aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authortg(x) <*@tg-x.net>2017-03-22 10:08:01 +0100
committertg(x) <*@tg-x.net>2017-03-22 10:08:01 +0100
commitaa98f144e6db0da5a0a4cad83fe64a80bbab6692 (patch)
tree5a072b4e1b689bf4330b2a412bdadc705d33ff75 /src
parentcaeeec6cacaa5354883494cb64b0a38e5c75da5d (diff)
parentb424335cc632a11bd76bad5791cef10e8c985720 (diff)
downloadgnunet-aa98f144e6db0da5a0a4cad83fe64a80bbab6692.tar.gz
gnunet-aa98f144e6db0da5a0a4cad83fe64a80bbab6692.zip
Merge branch 'master' of gnunet.org:gnunet
Diffstat (limited to 'src')
-rw-r--r--src/arm/arm_api.c2
-rw-r--r--src/arm/gnunet-arm.c141
-rw-r--r--src/arm/gnunet-service-arm.c3
-rw-r--r--src/ats-tests/gnunet-ats-sim.c14
-rw-r--r--src/ats-tests/gnunet-solver-eval.c47
-rw-r--r--src/ats-tool/gnunet-ats.c84
-rw-r--r--src/ats/ats_api_scheduling.c6
-rw-r--r--src/ats/gnunet-ats-solver-eval.c45
-rw-r--r--src/ats/gnunet-service-ats_addresses.c2
-rw-r--r--src/ats/gnunet-service-ats_performance.c2
-rw-r--r--src/ats/perf_ats_solver.c57
-rw-r--r--src/auction/gnunet-auction-create.c67
-rw-r--r--src/block/bg_bf.c1
-rw-r--r--src/cadet/Makefile.am222
-rw-r--r--src/cadet/TODO10
-rw-r--r--src/cadet/cadet.conf.in2
-rw-r--r--src/cadet/cadet.h2
-rw-r--r--src/cadet/cadet_api.c1757
-rw-r--r--src/cadet/cadet_api_new.c1720
-rw-r--r--src/cadet/cadet_common.c370
-rw-r--r--src/cadet/cadet_path.c363
-rw-r--r--src/cadet/cadet_path.h226
-rw-r--r--src/cadet/cadet_protocol.h150
-rw-r--r--src/cadet/cadet_test_lib.c133
-rw-r--r--src/cadet/cadet_test_lib.h40
-rw-r--r--src/cadet/cadet_test_lib_new.c362
-rw-r--r--src/cadet/cadet_test_lib_new.h106
-rw-r--r--src/cadet/gnunet-cadet.c89
-rw-r--r--src/cadet/gnunet-service-cadet-new.c1490
-rw-r--r--src/cadet/gnunet-service-cadet-new_channel.c2037
-rw-r--r--src/cadet/gnunet-service-cadet-new_channel.h262
-rw-r--r--src/cadet/gnunet-service-cadet-new_connection.c1093
-rw-r--r--src/cadet/gnunet-service-cadet-new_connection.h339
-rw-r--r--src/cadet/gnunet-service-cadet-new_dht.c351
-rw-r--r--src/cadet/gnunet-service-cadet-new_dht.h100
-rw-r--r--src/cadet/gnunet-service-cadet-new_hello.c152
-rw-r--r--src/cadet/gnunet-service-cadet-new_hello.h80
-rw-r--r--src/cadet/gnunet-service-cadet-new_peer.c1477
-rw-r--r--src/cadet/gnunet-service-cadet-new_peer.h394
-rw-r--r--src/cadet/gnunet-service-cadet.c1470
-rw-r--r--src/cadet/gnunet-service-cadet.h (renamed from src/cadet/gnunet-service-cadet-new.h)2
-rw-r--r--src/cadet/gnunet-service-cadet_channel.c3461
-rw-r--r--src/cadet/gnunet-service-cadet_channel.h387
-rw-r--r--src/cadet/gnunet-service-cadet_connection.c4010
-rw-r--r--src/cadet/gnunet-service-cadet_connection.h605
-rw-r--r--src/cadet/gnunet-service-cadet_core.c (renamed from src/cadet/gnunet-service-cadet-new_core.c)10
-rw-r--r--src/cadet/gnunet-service-cadet_core.h (renamed from src/cadet/gnunet-service-cadet-new_core.h)0
-rw-r--r--src/cadet/gnunet-service-cadet_dht.c373
-rw-r--r--src/cadet/gnunet-service-cadet_dht.h49
-rw-r--r--src/cadet/gnunet-service-cadet_hello.c140
-rw-r--r--src/cadet/gnunet-service-cadet_hello.h5
-rw-r--r--src/cadet/gnunet-service-cadet_local.c1553
-rw-r--r--src/cadet/gnunet-service-cadet_local.h234
-rw-r--r--src/cadet/gnunet-service-cadet_paths.c (renamed from src/cadet/gnunet-service-cadet-new_paths.c)10
-rw-r--r--src/cadet/gnunet-service-cadet_paths.h (renamed from src/cadet/gnunet-service-cadet-new_paths.h)2
-rw-r--r--src/cadet/gnunet-service-cadet_peer.c2928
-rw-r--r--src/cadet/gnunet-service-cadet_peer.h519
-rw-r--r--src/cadet/gnunet-service-cadet_tunnel.c3501
-rw-r--r--src/cadet/gnunet-service-cadet_tunnel.h616
-rw-r--r--src/cadet/gnunet-service-cadet_tunnels.c (renamed from src/cadet/gnunet-service-cadet-new_tunnels.c)25
-rw-r--r--src/cadet/gnunet-service-cadet_tunnels.h (renamed from src/cadet/gnunet-service-cadet-new_tunnels.h)4
-rw-r--r--src/cadet/test_cadet.c801
-rw-r--r--src/cadet/test_cadet_local.c351
-rw-r--r--src/cadet/test_cadet_local_mq.c12
-rw-r--r--src/cadet/test_cadet_new.c1048
-rw-r--r--src/cadet/test_cadet_single.c354
-rw-r--r--src/consensus/Makefile.am5
-rw-r--r--src/consensus/consensus_protocol.h20
-rw-r--r--src/consensus/gnunet-consensus-profiler.c74
-rw-r--r--src/consensus/gnunet-service-consensus.c46
-rw-r--r--src/consensus/test_consensus.conf2
-rw-r--r--src/conversation/Makefile.am2
-rw-r--r--src/conversation/gnunet-conversation.c21
-rw-r--r--src/conversation/gnunet-helper-audio-playback.c15
-rw-r--r--src/conversation/gnunet-service-conversation.c7
-rw-r--r--src/conversation/microphone.c2
-rw-r--r--src/core/core_api.c4
-rw-r--r--src/core/gnunet-core.c9
-rw-r--r--src/core/gnunet-service-core.c2
-rw-r--r--src/core/gnunet-service-core_kx.c152
-rw-r--r--src/datacache/Makefile.am1
-rw-r--r--src/datacache/plugin_datacache_sqlite.c550
-rw-r--r--src/datastore/Makefile.am1
-rw-r--r--src/datastore/datastore.h22
-rw-r--r--src/datastore/datastore_api.c78
-rw-r--r--src/datastore/gnunet-datastore.c12
-rw-r--r--src/datastore/gnunet-service-datastore.c24
-rw-r--r--src/datastore/plugin_datastore_heap.c207
-rw-r--r--src/datastore/plugin_datastore_mysql.c201
-rw-r--r--src/datastore/plugin_datastore_postgres.c251
-rw-r--r--src/datastore/plugin_datastore_sqlite.c792
-rw-r--r--src/datastore/plugin_datastore_template.c17
-rw-r--r--src/datastore/test_datastore_api.c43
-rw-r--r--src/datastore/test_datastore_api_management.c20
-rw-r--r--src/datastore/test_plugin_datastore.c4
-rw-r--r--src/dht/dht_api.c14
-rw-r--r--src/dht/gnunet-dht-get.c68
-rw-r--r--src/dht/gnunet-dht-monitor.c50
-rw-r--r--src/dht/gnunet-dht-put.c89
-rw-r--r--src/dht/gnunet-service-dht_clients.c2
-rw-r--r--src/dht/gnunet-service-dht_datacache.c2
-rw-r--r--src/dht/gnunet-service-dht_neighbours.c16
-rw-r--r--src/dht/gnunet_dht_profiler.c73
-rw-r--r--src/dns/Makefile.am1
-rw-r--r--src/dns/dns_api.c2
-rw-r--r--src/dns/gnunet-dns-monitor.c21
-rw-r--r--src/dns/gnunet-dns-redirector.c22
-rw-r--r--src/dns/gnunet-helper-dns.c2
-rw-r--r--src/dns/gnunet-service-dns.c7
-rw-r--r--src/dv/dv_api.c2
-rw-r--r--src/dv/gnunet-dv.c10
-rw-r--r--src/dv/gnunet-service-dv.c8
-rw-r--r--src/exit/Makefile.am2
-rw-r--r--src/exit/gnunet-daemon-exit.c20
-rw-r--r--src/exit/gnunet-helper-exit-windows.c2
-rw-r--r--src/exit/gnunet-helper-exit.c2
-rw-r--r--src/fs/Makefile.am2
-rw-r--r--src/fs/fs_api.h10
-rw-r--r--src/fs/fs_directory.c78
-rw-r--r--src/fs/fs_dirmetascan.c2
-rw-r--r--src/fs/fs_download.c107
-rw-r--r--src/fs/fs_getopt.c79
-rw-r--r--src/fs/fs_publish.c4
-rw-r--r--src/fs/fs_search.c67
-rw-r--r--src/fs/fs_tree.c6
-rw-r--r--src/fs/fs_unindex.c61
-rw-r--r--src/fs/fs_uri.c22
-rw-r--r--src/fs/gnunet-auto-share.c54
-rw-r--r--src/fs/gnunet-download.c74
-rw-r--r--src/fs/gnunet-fs-profiler.c30
-rw-r--r--src/fs/gnunet-fs.c13
-rw-r--r--src/fs/gnunet-helper-fs-publish.c2
-rw-r--r--src/fs/gnunet-publish.c151
-rw-r--r--src/fs/gnunet-search.c58
-rw-r--r--src/fs/gnunet-service-fs.c1
-rw-r--r--src/fs/gnunet-service-fs_cadet_client.c4
-rw-r--r--src/fs/gnunet-service-fs_cadet_server.c19
-rw-r--r--src/fs/gnunet-service-fs_cp.c4
-rw-r--r--src/fs/gnunet-service-fs_indexing.c2
-rw-r--r--src/fs/gnunet-service-fs_lc.c33
-rw-r--r--src/fs/gnunet-service-fs_lc.h33
-rw-r--r--src/fs/gnunet-service-fs_pr.c403
-rw-r--r--src/fs/gnunet-service-fs_put.c44
-rw-r--r--src/fs/gnunet-unindex.c10
-rw-r--r--src/gns/gns_api.c2
-rw-r--r--src/gns/gnunet-bcd.c12
-rw-r--r--src/gns/gnunet-dns2gns.c48
-rw-r--r--src/gns/gnunet-gns-proxy.c39
-rw-r--r--src/gns/gnunet-gns.c56
-rw-r--r--src/gns/plugin_gnsrecord_gns.c18
-rw-r--r--src/hello/hello.c2
-rw-r--r--src/hostlist/gnunet-daemon-hostlist.c31
-rw-r--r--src/hostlist/gnunet-daemon-hostlist_client.c6
-rw-r--r--src/hostlist/gnunet-daemon-hostlist_server.c2
-rw-r--r--src/identity-provider/gnunet-identity-token.c19
-rw-r--r--src/identity-provider/identity_provider_api.c4
-rw-r--r--src/identity/gnunet-identity.c54
-rw-r--r--src/identity/identity_api.c14
-rw-r--r--src/include/Makefile.am2
-rw-r--r--src/include/gnunet_arm_service.h18
-rw-r--r--src/include/gnunet_bandwidth_lib.h14
-rw-r--r--src/include/gnunet_cadet_service.h523
-rw-r--r--src/include/gnunet_configuration_lib.h7
-rw-r--r--src/include/gnunet_connection_lib.h400
-rw-r--r--src/include/gnunet_constants.h2
-rw-r--r--src/include/gnunet_core_service.h53
-rw-r--r--src/include/gnunet_datastore_plugin.h41
-rw-r--r--src/include/gnunet_datastore_service.h47
-rw-r--r--src/include/gnunet_fs_service.h47
-rw-r--r--src/include/gnunet_getopt_lib.h349
-rw-r--r--src/include/gnunet_helper_lib.h8
-rw-r--r--src/include/gnunet_json_lib.h20
-rw-r--r--src/include/gnunet_mq_lib.h1
-rw-r--r--src/include/gnunet_multicast_service.h4
-rw-r--r--src/include/gnunet_peerstore_service.h4
-rw-r--r--src/include/gnunet_server_lib.h887
-rw-r--r--src/include/gnunet_service_lib.h107
-rw-r--r--src/include/gnunet_sq_lib.h35
-rw-r--r--src/include/gnunet_util_lib.h17
-rw-r--r--src/include/platform.h1
-rw-r--r--src/integration-tests/confs/test_defaults.conf4
-rw-r--r--src/json/json.c73
-rw-r--r--src/multicast/.gitignore1
-rw-r--r--src/multicast/Makefile.am17
-rw-r--r--src/multicast/gnunet-service-multicast.c6
-rw-r--r--src/multicast/test_multicast.conf10
-rw-r--r--src/multicast/test_multicast_2peers.c511
-rw-r--r--src/multicast/test_multicast_multipeer.c106
-rw-r--r--src/namecache/Makefile.am2
-rw-r--r--src/namecache/gnunet-namecache.c20
-rw-r--r--src/namecache/plugin_namecache_sqlite.c215
-rw-r--r--src/namestore/Makefile.am1
-rw-r--r--src/namestore/gnunet-namestore.c125
-rw-r--r--src/namestore/gnunet-service-namestore.c2
-rw-r--r--src/namestore/plugin_namestore_sqlite.c394
-rw-r--r--src/nat-auto/Makefile.am5
-rw-r--r--src/nat-auto/gnunet-nat-auto.c69
-rw-r--r--src/nat-auto/gnunet-nat-server.c212
-rw-r--r--src/nat-auto/nat_auto_api.c2
-rw-r--r--src/nat/gnunet-nat.c140
-rw-r--r--src/nat/gnunet-service-nat.c70
-rw-r--r--src/nat/gnunet-service-nat_externalip.c1
-rw-r--r--src/nat/gnunet-service-nat_helper.c29
-rw-r--r--src/nat/nat_api.c30
-rw-r--r--src/nat/nat_stun.h15
-rw-r--r--src/nse/gnunet-nse-profiler.c65
-rw-r--r--src/peerinfo-tool/gnunet-peerinfo.c67
-rw-r--r--src/peerinfo/gnunet-service-peerinfo.c8
-rw-r--r--src/peerstore/Makefile.am4
-rw-r--r--src/peerstore/gnunet-service-peerstore.c28
-rw-r--r--src/peerstore/peerstore.h2
-rw-r--r--src/peerstore/peerstore_api.c27
-rw-r--r--src/peerstore/peerstore_common.c20
-rw-r--r--src/peerstore/peerstore_common.h2
-rw-r--r--src/peerstore/plugin_peerstore_flat.c49
-rw-r--r--src/peerstore/plugin_peerstore_sqlite.c464
-rw-r--r--src/peerstore/test_peerstore_api_iterate.c73
-rw-r--r--src/peerstore/test_peerstore_api_store.c55
-rw-r--r--src/peerstore/test_plugin_peerstore.c127
-rw-r--r--src/pq/pq.c7
-rw-r--r--src/psyc/.gitignore1
-rw-r--r--src/psyc/psyc_api.c4
-rw-r--r--src/psycstore/.gitignore4
-rw-r--r--src/psycstore/gnunet-service-psycstore.c2
-rw-r--r--src/psycstore/psycstore_api.c4
-rw-r--r--src/psycutil/.gitignore1
-rw-r--r--src/pt/Makefile.am2
-rw-r--r--src/pt/gnunet-daemon-pt.c6
-rw-r--r--src/regex/gnunet-regex-profiler.c49
-rw-r--r--src/regex/gnunet-regex-simulation-profiler.c21
-rw-r--r--src/regex/gnunet-service-regex.c323
-rw-r--r--src/regex/regex_api_announce.c2
-rw-r--r--src/regex/regex_api_search.c2
-rw-r--r--src/rest/gnunet-rest-server.c14
-rw-r--r--src/revocation/gnunet-revocation.c38
-rw-r--r--src/revocation/test_revocation.c20
-rw-r--r--src/rps/Makefile.am34
-rw-r--r--src/rps/gnunet-rps.c57
-rw-r--r--src/rps/gnunet-service-rps.c222
-rw-r--r--src/rps/gnunet-service-rps_peers.c96
-rw-r--r--src/rps/gnunet-service-rps_peers.h37
-rw-r--r--src/rps/rps_api.c8
-rw-r--r--src/rps/test_rps.c6
-rw-r--r--src/rps/test_service_rps_peers.c8
-rw-r--r--src/scalarproduct/Makefile.am8
-rw-r--r--src/scalarproduct/gnunet-scalarproduct.c36
-rw-r--r--src/scalarproduct/gnunet-service-scalarproduct-ecc_alice.c4
-rw-r--r--src/scalarproduct/gnunet-service-scalarproduct-ecc_bob.c4
-rw-r--r--src/scalarproduct/gnunet-service-scalarproduct_alice.c4
-rw-r--r--src/scalarproduct/gnunet-service-scalarproduct_bob.c4
-rw-r--r--src/scalarproduct/scalarproduct_api.c8
-rw-r--r--src/secretsharing/Makefile.am6
-rw-r--r--src/secretsharing/gnunet-secretsharing-profiler.c59
-rw-r--r--src/secretsharing/gnunet-service-secretsharing.c538
-rw-r--r--src/set/Makefile.am4
-rw-r--r--src/set/gnunet-service-set.c1574
-rw-r--r--src/set/gnunet-service-set.h366
-rw-r--r--src/set/gnunet-service-set_intersection.c652
-rw-r--r--src/set/gnunet-service-set_intersection.h79
-rw-r--r--src/set/gnunet-service-set_union.c1033
-rw-r--r--src/set/gnunet-service-set_union.h239
-rw-r--r--src/set/gnunet-set-ibf-profiler.c49
-rw-r--r--src/set/gnunet-set-profiler.c128
-rw-r--r--src/set/set_api.c76
-rw-r--r--src/set/test_set_api.c76
-rw-r--r--src/set/test_set_union_copy.c4
-rw-r--r--src/social/.gitignore1
-rw-r--r--src/social/gnunet-social.c291
-rw-r--r--src/social/social_api.c10
-rw-r--r--src/sq/Makefile.am2
-rw-r--r--src/sq/sq.c34
-rw-r--r--src/sq/sq_query_helper.c52
-rw-r--r--src/sq/sq_result_helper.c74
-rw-r--r--src/sq/test_sq.c20
-rw-r--r--src/statistics/gnunet-service-statistics.c9
-rw-r--r--src/statistics/gnunet-statistics.c60
-rw-r--r--src/statistics/statistics_api.c6
-rw-r--r--src/testbed-logger/gnunet-service-testbed-logger.c179
-rw-r--r--src/testbed-logger/test_testbed_logger_api.c4
-rw-r--r--src/testbed-logger/testbed_logger_api.c2
-rw-r--r--src/testbed/Makefile.am4
-rw-r--r--src/testbed/generate-underlay-topology.c12
-rw-r--r--src/testbed/gnunet-helper-testbed.c2
-rw-r--r--src/testbed/gnunet-service-testbed_barriers.c4
-rw-r--r--src/testbed/gnunet-service-testbed_oc.c2
-rw-r--r--src/testbed/gnunet-service-testbed_peers.c6
-rw-r--r--src/testbed/gnunet-testbed-profiler.c43
-rw-r--r--src/testbed/test_gnunet_helper_testbed.c18
-rw-r--r--src/testbed/testbed_api_hosts.c5
-rw-r--r--src/testbed/testbed_api_peers.c2
-rw-r--r--src/testbed/testbed_api_topology.c8
-rw-r--r--src/testing/gnunet-testing.c40
-rw-r--r--src/testing/list-keys.c15
-rw-r--r--src/testing/testing.c1
-rw-r--r--src/topology/friends.c18
-rw-r--r--src/topology/gnunet-daemon-topology.c2
-rw-r--r--src/transport/Makefile.am4
-rw-r--r--src/transport/gnunet-helper-transport-wlan-dummy.c30
-rw-r--r--src/transport/gnunet-service-transport_validation.c2
-rw-r--r--src/transport/gnunet-transport-certificate-creation.c2
-rw-r--r--src/transport/gnunet-transport-profiler.c54
-rw-r--r--src/transport/gnunet-transport.c120
-rw-r--r--src/transport/plugin_transport_http_client.c25
-rw-r--r--src/transport/plugin_transport_http_server.c25
-rw-r--r--src/transport/plugin_transport_tcp.c587
-rw-r--r--src/transport/plugin_transport_udp.c43
-rw-r--r--src/transport/plugin_transport_udp.h12
-rw-r--r--src/transport/plugin_transport_udp_broadcasting.c30
-rw-r--r--src/transport/plugin_transport_wlan.c31
-rw-r--r--src/transport/tcp_connection_legacy.c (renamed from src/util/connection.c)24
-rw-r--r--src/transport/tcp_server_legacy.c (renamed from src/util/server.c)12
-rw-r--r--src/transport/tcp_server_mst_legacy.c (renamed from src/util/server_mst.c)6
-rw-r--r--src/transport/tcp_service_legacy.c1688
-rw-r--r--src/transport/test_plugin_transport.c2
-rw-r--r--src/transport/test_transport_api_reliability.c2
-rw-r--r--src/transport/transport-testing-loggers.c1
-rw-r--r--src/transport/transport-testing-main.c22
-rw-r--r--src/transport/transport-testing.c26
-rw-r--r--src/transport/transport_api_address_to_string.c6
-rw-r--r--src/transport/transport_api_core.c2
-rw-r--r--src/util/Makefile.am96
-rw-r--r--src/util/bandwidth.c20
-rw-r--r--src/util/client.c21
-rw-r--r--src/util/disk.c21
-rw-r--r--src/util/getopt.c72
-rw-r--r--src/util/getopt_helpers.c634
-rw-r--r--src/util/gnunet-config.c58
-rw-r--r--src/util/gnunet-ecc.c56
-rw-r--r--src/util/gnunet-resolver.c9
-rw-r--r--src/util/gnunet-scrypt.c41
-rw-r--r--src/util/helper.c25
-rw-r--r--src/util/mq.c128
-rw-r--r--src/util/mst.c4
-rw-r--r--src/util/resolver_api.c2
-rw-r--r--src/util/server_nc.c472
-rw-r--r--src/util/server_tc.c242
-rw-r--r--src/util/service.c2401
-rw-r--r--src/util/service_new.c2615
-rw-r--r--src/util/socks.c84
-rw-r--r--src/util/test_client.c2
-rw-r--r--src/util/test_common_allocation.c73
-rw-r--r--src/util/test_connection.c167
-rw-r--r--src/util/test_connection_addressing.c186
-rw-r--r--src/util/test_connection_receive_cancel.c160
-rw-r--r--src/util/test_connection_timeout.c129
-rw-r--r--src/util/test_connection_timeout_no_connect.c76
-rw-r--r--src/util/test_connection_transmit_cancel.c76
-rw-r--r--src/util/test_getopt.c43
-rw-r--r--src/util/test_program.c129
-rw-r--r--src/util/test_server.c302
-rw-r--r--src/util/test_server_disconnect.c166
-rw-r--r--src/util/test_server_mst_interrupt.c60
-rw-r--r--src/util/test_server_with_client.c198
-rw-r--r--src/util/test_server_with_client_unix.c176
-rw-r--r--src/util/test_service.c2
-rw-r--r--src/util/util.conf5
-rw-r--r--src/vpn/Makefile.am2
-rw-r--r--src/vpn/gnunet-helper-vpn-windows.c2
-rw-r--r--src/vpn/gnunet-helper-vpn.c2
-rw-r--r--src/vpn/gnunet-service-vpn.c25
-rw-r--r--src/vpn/gnunet-vpn.c72
361 files changed, 20859 insertions, 44381 deletions
diff --git a/src/arm/arm_api.c b/src/arm/arm_api.c
index a61343833..56af544b1 100644
--- a/src/arm/arm_api.c
+++ b/src/arm/arm_api.c
@@ -753,7 +753,7 @@ change_service (struct GNUNET_ARM_Handle *h,
753 753
754 slen = strlen (service_name) + 1; 754 slen = strlen (service_name) + 1;
755 if (slen + sizeof (struct GNUNET_ARM_Message) >= 755 if (slen + sizeof (struct GNUNET_ARM_Message) >=
756 GNUNET_SERVER_MAX_MESSAGE_SIZE) 756 GNUNET_MAX_MESSAGE_SIZE)
757 { 757 {
758 GNUNET_break (0); 758 GNUNET_break (0);
759 return NULL; 759 return NULL;
diff --git a/src/arm/gnunet-arm.c b/src/arm/gnunet-arm.c
index 65a6463cf..78c78738a 100644
--- a/src/arm/gnunet-arm.c
+++ b/src/arm/gnunet-arm.c
@@ -121,12 +121,12 @@ static struct GNUNET_SCHEDULER_Task *timeout_task;
121/** 121/**
122 * Do we want to give our stdout to gnunet-service-arm? 122 * Do we want to give our stdout to gnunet-service-arm?
123 */ 123 */
124static unsigned int no_stdout; 124static int no_stdout;
125 125
126/** 126/**
127 * Do we want to give our stderr to gnunet-service-arm? 127 * Do we want to give our stderr to gnunet-service-arm?
128 */ 128 */
129static unsigned int no_stderr; 129static int no_stderr;
130 130
131/** 131/**
132 * Handle for the task running the #action_loop(). 132 * Handle for the task running the #action_loop().
@@ -220,14 +220,8 @@ req_string (enum GNUNET_ARM_RequestStatus rs)
220 { 220 {
221 case GNUNET_ARM_REQUEST_SENT_OK: 221 case GNUNET_ARM_REQUEST_SENT_OK:
222 return _("Message was sent successfully"); 222 return _("Message was sent successfully");
223 case GNUNET_ARM_REQUEST_CONFIGURATION_ERROR:
224 return _("Misconfiguration (can not connect to the ARM service)");
225 case GNUNET_ARM_REQUEST_DISCONNECTED: 223 case GNUNET_ARM_REQUEST_DISCONNECTED:
226 return _("We disconnected from ARM before we could send a request"); 224 return _("We disconnected from ARM before we could send a request");
227 case GNUNET_ARM_REQUEST_BUSY:
228 return _("ARM API is busy");
229 case GNUNET_ARM_REQUEST_TIMEOUT:
230 return _("Request timed out");
231 } 225 }
232 return _("Unknown request status"); 226 return _("Unknown request status");
233} 227}
@@ -245,27 +239,27 @@ ret_string (enum GNUNET_ARM_Result result)
245 switch (result) 239 switch (result)
246 { 240 {
247 case GNUNET_ARM_RESULT_STOPPED: 241 case GNUNET_ARM_RESULT_STOPPED:
248 return _("%s is stopped"); 242 return _("is stopped");
249 case GNUNET_ARM_RESULT_STARTING: 243 case GNUNET_ARM_RESULT_STARTING:
250 return _("%s is starting"); 244 return _("is starting");
251 case GNUNET_ARM_RESULT_STOPPING: 245 case GNUNET_ARM_RESULT_STOPPING:
252 return _("%s is stopping"); 246 return _("is stopping");
253 case GNUNET_ARM_RESULT_IS_STARTING_ALREADY: 247 case GNUNET_ARM_RESULT_IS_STARTING_ALREADY:
254 return _("%s is starting already"); 248 return _("is starting already");
255 case GNUNET_ARM_RESULT_IS_STOPPING_ALREADY: 249 case GNUNET_ARM_RESULT_IS_STOPPING_ALREADY:
256 return _("%s is stopping already"); 250 return _("is stopping already");
257 case GNUNET_ARM_RESULT_IS_STARTED_ALREADY: 251 case GNUNET_ARM_RESULT_IS_STARTED_ALREADY:
258 return _("%s is started already"); 252 return _("is started already");
259 case GNUNET_ARM_RESULT_IS_STOPPED_ALREADY: 253 case GNUNET_ARM_RESULT_IS_STOPPED_ALREADY:
260 return _("%s is stopped already"); 254 return _("is stopped already");
261 case GNUNET_ARM_RESULT_IS_NOT_KNOWN: 255 case GNUNET_ARM_RESULT_IS_NOT_KNOWN:
262 return _("%s service is not known to ARM"); 256 return _("service is not known to ARM");
263 case GNUNET_ARM_RESULT_START_FAILED: 257 case GNUNET_ARM_RESULT_START_FAILED:
264 return _("%s service failed to start"); 258 return _("service failed to start");
265 case GNUNET_ARM_RESULT_IN_SHUTDOWN: 259 case GNUNET_ARM_RESULT_IN_SHUTDOWN:
266 return _("%s service cannot be started because ARM is shutting down"); 260 return _("service cannot be manipulated because ARM is shutting down");
267 } 261 }
268 return _("%.s Unknown result code."); 262 return _("Unknown result code.");
269} 263}
270 264
271 265
@@ -378,10 +372,9 @@ stop_callback (void *cls,
378 (GNUNET_ARM_RESULT_STOPPED != result) && 372 (GNUNET_ARM_RESULT_STOPPED != result) &&
379 (GNUNET_ARM_RESULT_IS_STOPPED_ALREADY != result)) 373 (GNUNET_ARM_RESULT_IS_STOPPED_ALREADY != result))
380 { 374 {
381 GNUNET_asprintf (&msg, "%s", 375 FPRINTF (stdout,
382 _("Failed to stop the ARM service: %s\n")); 376 _("Failed to stop the ARM service: %s\n"),
383 FPRINTF (stdout, msg, ret_string (result)); 377 ret_string (result));
384 GNUNET_free (msg);
385 GNUNET_SCHEDULER_shutdown (); 378 GNUNET_SCHEDULER_shutdown ();
386 return; 379 return;
387 } 380 }
@@ -476,11 +469,10 @@ term_callback (void *cls,
476 if ((GNUNET_ARM_RESULT_STOPPED != result) && 469 if ((GNUNET_ARM_RESULT_STOPPED != result) &&
477 (GNUNET_ARM_RESULT_IS_STOPPED_ALREADY != result)) 470 (GNUNET_ARM_RESULT_IS_STOPPED_ALREADY != result))
478 { 471 {
479 GNUNET_asprintf (&msg, 472 FPRINTF (stdout,
480 _("Failed to kill the `%s' service: %s\n"), 473 _("Failed to kill the `%s' service: %s\n"),
481 term, ret_string (result)); 474 term,
482 FPRINTF (stdout, "%s", msg); 475 ret_string (result));
483 GNUNET_free (msg);
484 GNUNET_SCHEDULER_shutdown (); 476 GNUNET_SCHEDULER_shutdown ();
485 return; 477 return;
486 } 478 }
@@ -770,35 +762,70 @@ run (void *cls,
770int 762int
771main (int argc, char *const *argv) 763main (int argc, char *const *argv)
772{ 764{
773 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 765 struct GNUNET_GETOPT_CommandLineOption options[] = {
774 {'e', "end", NULL, gettext_noop ("stop all GNUnet services"), 766
775 GNUNET_NO, &GNUNET_GETOPT_set_one, &end}, 767 GNUNET_GETOPT_OPTION_SET_ONE ('e',
776 {'i', "init", "SERVICE", gettext_noop ("start a particular service"), 768 "end",
777 GNUNET_YES, &GNUNET_GETOPT_set_string, &init}, 769 gettext_noop ("stop all GNUnet services"),
778 {'k', "kill", "SERVICE", gettext_noop ("stop a particular service"), 770 &end),
779 GNUNET_YES, &GNUNET_GETOPT_set_string, &term}, 771
780 {'s', "start", NULL, gettext_noop ("start all GNUnet default services"), 772 GNUNET_GETOPT_OPTION_STRING ('i',
781 GNUNET_NO, &GNUNET_GETOPT_set_one, &start}, 773 "init",
782 {'r', "restart", NULL, 774 "SERVICE",
783 gettext_noop ("stop and start all GNUnet default services"), 775 gettext_noop ("start a particular service"),
784 GNUNET_NO, &GNUNET_GETOPT_set_one, &restart}, 776 &init),
785 {'d', "delete", NULL, 777
786 gettext_noop ("delete config file and directory on exit"), 778 GNUNET_GETOPT_OPTION_STRING ('k',
787 GNUNET_NO, &GNUNET_GETOPT_set_one, &delete}, 779 "kill",
788 {'m', "monitor", NULL, 780 "SERVICE",
789 gettext_noop ("monitor ARM activities"), 781 gettext_noop ("stop a particular service"),
790 GNUNET_NO, &GNUNET_GETOPT_set_one, &monitor}, 782 &term),
791 {'q', "quiet", NULL, gettext_noop ("don't print status messages"), 783
792 GNUNET_NO, &GNUNET_GETOPT_set_one, &quiet}, 784 GNUNET_GETOPT_OPTION_SET_ONE ('s',
793 {'T', "timeout", "DELAY", 785 "start",
794 gettext_noop ("exit with error status if operation does not finish after DELAY"), 786 gettext_noop ("start all GNUnet default services"),
795 GNUNET_YES, &GNUNET_GETOPT_set_relative_time, &timeout}, 787 &start),
796 {'I', "info", NULL, gettext_noop ("list currently running services"), 788
797 GNUNET_NO, &GNUNET_GETOPT_set_one, &list}, 789 GNUNET_GETOPT_OPTION_SET_ONE ('r',
798 {'O', "no-stdout", NULL, gettext_noop ("don't let gnunet-service-arm inherit standard output"), 790 "restart",
799 GNUNET_NO, &GNUNET_GETOPT_set_one, &no_stdout}, 791 gettext_noop ("stop and start all GNUnet default services"),
800 {'E', "no-stderr", NULL, gettext_noop ("don't let gnunet-service-arm inherit standard error"), 792 &restart),
801 GNUNET_NO, &GNUNET_GETOPT_set_one, &no_stderr}, 793 GNUNET_GETOPT_OPTION_SET_ONE ('d',
794 "delete",
795 gettext_noop ("delete config file and directory on exit"),
796 &delete),
797
798 GNUNET_GETOPT_OPTION_SET_ONE ('m',
799 "monitor",
800 gettext_noop ("monitor ARM activities"),
801 &monitor),
802
803 GNUNET_GETOPT_OPTION_SET_ONE ('q',
804 "quiet",
805 gettext_noop ("don't print status messages"),
806 &quiet),
807
808 GNUNET_GETOPT_OPTION_SET_RELATIVE_TIME ('T',
809 "timeout",
810 "DELAY",
811 gettext_noop ("exit with error status if operation does not finish after DELAY"),
812 &timeout),
813
814 GNUNET_GETOPT_OPTION_SET_ONE ('I',
815 "info",
816 gettext_noop ("list currently running services"),
817 &list),
818
819 GNUNET_GETOPT_OPTION_SET_ONE ('O',
820 "no-stdout",
821 gettext_noop ("don't let gnunet-service-arm inherit standard output"),
822 &no_stdout),
823
824 GNUNET_GETOPT_OPTION_SET_ONE ('E',
825 "no-stderr",
826 gettext_noop ("don't let gnunet-service-arm inherit standard error"),
827 &no_stderr),
828
802 GNUNET_GETOPT_OPTION_END 829 GNUNET_GETOPT_OPTION_END
803 }; 830 };
804 831
diff --git a/src/arm/gnunet-service-arm.c b/src/arm/gnunet-service-arm.c
index 4f3e964e3..19088c5cb 100644
--- a/src/arm/gnunet-service-arm.c
+++ b/src/arm/gnunet-service-arm.c
@@ -812,6 +812,7 @@ start_process (struct ServiceList *sl,
812 "%s %s", 812 "%s %s",
813 fin_options, 813 fin_options,
814 optpos); 814 optpos);
815 GNUNET_free (fin_options);
815 GNUNET_free (optpos); 816 GNUNET_free (optpos);
816 } 817 }
817 else 818 else
@@ -2224,7 +2225,7 @@ main (int argc,
2224 shc_chld = 2225 shc_chld =
2225 GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD, 2226 GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD,
2226 &sighandler_child_death); 2227 &sighandler_child_death);
2227 ret = GNUNET_SERVICE_ruN_ (argc, 2228 ret = GNUNET_SERVICE_run_ (argc,
2228 argv, 2229 argv,
2229 "arm", 2230 "arm",
2230 GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN, 2231 GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN,
diff --git a/src/ats-tests/gnunet-ats-sim.c b/src/ats-tests/gnunet-ats-sim.c
index 56f8f2223..0f32df511 100644
--- a/src/ats-tests/gnunet-ats-sim.c
+++ b/src/ats-tests/gnunet-ats-sim.c
@@ -81,15 +81,19 @@ evaluate (struct GNUNET_TIME_Relative duration_total)
81 81
82 82
83 duration = (duration_total.rel_value_us / (1000 * 1000)); 83 duration = (duration_total.rel_value_us / (1000 * 1000));
84 if (0 == duration)
85 duration = 1;
84 for (c_m = 0; c_m < e->num_masters; c_m++) 86 for (c_m = 0; c_m < e->num_masters; c_m++)
85 { 87 {
86 mp = &masters_p[c_m]; 88 mp = &masters_p[c_m];
87 fprintf (stderr, 89 fprintf (stderr,
88 _("Master [%u]: sent: %u KiB in %u sec. = %u KiB/s, received: %u KiB in %u sec. = %u KiB/s\n"), 90 _("Master [%u]: sent: %u KiB in %u sec. = %u KiB/s, received: %u KiB in %u sec. = %u KiB/s\n"),
89 mp->no, mp->total_bytes_sent / 1024, duration, 91 mp->no, mp->total_bytes_sent / 1024,
90 (mp->total_bytes_sent / 1024) / duration, 92 duration,
91 mp->total_bytes_received / 1024, duration, 93 (mp->total_bytes_sent / 1024) / duration,
92 (mp->total_bytes_received / 1024) / duration); 94 mp->total_bytes_received / 1024,
95 duration,
96 (mp->total_bytes_received / 1024) / duration);
93 97
94 for (c_s = 0; c_s < e->num_slaves; c_s++) 98 for (c_s = 0; c_s < e->num_slaves; c_s++)
95 { 99 {
diff --git a/src/ats-tests/gnunet-solver-eval.c b/src/ats-tests/gnunet-solver-eval.c
index 0e49a3a32..1bb7fdee7 100644
--- a/src/ats-tests/gnunet-solver-eval.c
+++ b/src/ats-tests/gnunet-solver-eval.c
@@ -331,12 +331,14 @@ load_episode (struct Experiment *e,
331 o->pref_type = GNUNET_ATS_PREFERENCE_LATENCY; 331 o->pref_type = GNUNET_ATS_PREFERENCE_LATENCY;
332 else 332 else
333 { 333 {
334 fprintf (stderr, "Invalid preference in operation %u `%s' in episode %u\n", 334 fprintf (stderr,
335 op_counter, op, cur->id); 335 "Invalid preference in operation %u `%s' in episode %u\n",
336 op_counter,
337 op,
338 cur->id);
336 GNUNET_free (type); 339 GNUNET_free (type);
337 GNUNET_free (op_name); 340 GNUNET_free (op_name);
338 GNUNET_free (op); 341 GNUNET_free (op);
339 GNUNET_free (pref);
340 GNUNET_free (sec_name); 342 GNUNET_free (sec_name);
341 GNUNET_free_non_null (pref); 343 GNUNET_free_non_null (pref);
342 GNUNET_free (o); 344 GNUNET_free (o);
@@ -929,22 +931,35 @@ main (int argc, char *argv[])
929 opt_log = GNUNET_NO; 931 opt_log = GNUNET_NO;
930 opt_plot = GNUNET_NO; 932 opt_plot = GNUNET_NO;
931 933
932 static struct GNUNET_GETOPT_CommandLineOption options[] = 934 struct GNUNET_GETOPT_CommandLineOption options[] =
933 { 935 {
934 { 's', "solver", NULL, 936 GNUNET_GETOPT_OPTION_STRING ('s',
935 gettext_noop ("solver to use"), 937 "solver",
936 1, &GNUNET_GETOPT_set_string, &opt_solver}, 938 NULL,
937 { 'e', "experiment", NULL, 939 gettext_noop ("solver to use"),
938 gettext_noop ("experiment to use"), 940 &opt_solver),
939 1, &GNUNET_GETOPT_set_string, &opt_exp_file}, 941
940 { 'e', "experiment", NULL, 942 GNUNET_GETOPT_OPTION_STRING ('e',
941 gettext_noop ("experiment to use"), 943 "experiment",
942 1, &GNUNET_GETOPT_set_one, &opt_verbose}, 944 NULL,
945 gettext_noop ("experiment to use"),
946 &opt_exp_file),
947
948 GNUNET_GETOPT_OPTION_SET_ONE ('e',
949 "experiment",
950 gettext_noop ("experiment to use"),
951 &opt_verbose),
943 GNUNET_GETOPT_OPTION_END 952 GNUNET_GETOPT_OPTION_END
944 }; 953 };
945 954
946 GNUNET_PROGRAM_run (argc, argv, argv[0], NULL, options, &run, argv[0]); 955 if (GNUNET_OK !=
956 GNUNET_PROGRAM_run (argc,
957 argv, argv[0],
958 NULL,
959 options,
960 &run, argv[0]))
961 return 1;
947 962
948 return 0; 963 return 0;
949} 964}
950/* end of file ats-testing-experiment.c*/ 965/* end of file gnunet-solver-eval.c*/
diff --git a/src/ats-tool/gnunet-ats.c b/src/ats-tool/gnunet-ats.c
index 5fc1d6e92..f645ba56d 100644
--- a/src/ats-tool/gnunet-ats.c
+++ b/src/ats-tool/gnunet-ats.c
@@ -944,34 +944,62 @@ main (int argc,
944 stat_receive_done = GNUNET_NO; 944 stat_receive_done = GNUNET_NO;
945 opt_type_str = NULL; 945 opt_type_str = NULL;
946 946
947 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 947 struct GNUNET_GETOPT_CommandLineOption options[] = {
948 { 'u', "used", NULL, 948 GNUNET_GETOPT_OPTION_SET_ONE ('u',
949 gettext_noop ("get list of active addresses currently used"), 0, 949 "used",
950 &GNUNET_GETOPT_set_one, &opt_list_used }, 950 gettext_noop ("get list of active addresses currently used"),
951 { 'a', "all", NULL, gettext_noop ("get list of all active addresses"), 0, 951 &opt_list_used),
952 &GNUNET_GETOPT_set_one, &opt_list_all }, 952 GNUNET_GETOPT_OPTION_SET_ONE ('a',
953 { 'C', "connect", "PEER", 953 "all",
954 gettext_noop ("connect to PEER"), 1, 954 gettext_noop ("get list of all active addresses"),
955 &GNUNET_GETOPT_set_string, &cpid_str }, 955 &opt_list_all),
956 { 'n', "numeric", NULL, 956
957 gettext_noop ("do not resolve IP addresses to hostnames"), 0, 957 GNUNET_GETOPT_OPTION_STRING ('C',
958 &GNUNET_GETOPT_set_one, &opt_resolve_addresses_numeric }, 958 "connect",
959 { 'm', "monitor", NULL, gettext_noop ("monitor mode"), 0, 959 NULL,
960 &GNUNET_GETOPT_set_one, &opt_monitor }, 960 gettext_noop ("connect to PEER"),
961 { 'p', "preference", NULL, gettext_noop ("set preference for the given peer"), 961 &cpid_str),
962 0, &GNUNET_GETOPT_set_one, &opt_set_pref }, 962 GNUNET_GETOPT_OPTION_SET_ONE ('n',
963 { 'q', "quotas", NULL, gettext_noop ("print all configured quotas"), 0, 963 "numeric",
964 &GNUNET_GETOPT_set_one, &opt_print_quotas }, 964 gettext_noop ("do not resolve IP addresses to hostnames"),
965 { 'i', "id", "TYPE", gettext_noop ("peer id"), 1, &GNUNET_GETOPT_set_string, 965 &opt_resolve_addresses_numeric),
966 &opt_pid_str }, 966
967 { 't', "type", "TYPE", 967 GNUNET_GETOPT_OPTION_SET_ONE ('m',
968 gettext_noop ("preference type to set: latency | bandwidth"), 1, 968 "monitor",
969 &GNUNET_GETOPT_set_string, &opt_type_str }, 969 gettext_noop ("monitor mode"),
970 { 'k', "value", "VALUE", gettext_noop ("preference value"), 1, 970 &opt_monitor),
971 &GNUNET_GETOPT_set_uint, &opt_pref_value }, 971
972 { 'V', "verbose", NULL, 972 GNUNET_GETOPT_OPTION_SET_ONE ('p',
973 gettext_noop ("verbose output (include ATS address properties)"), 0, 973 "preference",
974 &GNUNET_GETOPT_set_one, &opt_verbose }, 974 gettext_noop ("set preference for the given peer"),
975 &opt_set_pref),
976
977 GNUNET_GETOPT_OPTION_SET_ONE ('q',
978 "quotas",
979 gettext_noop ("print all configured quotas"),
980 &opt_print_quotas),
981 GNUNET_GETOPT_OPTION_STRING ('i',
982 "id",
983 "TYPE",
984 gettext_noop ("peer id"),
985 &opt_pid_str),
986
987 GNUNET_GETOPT_OPTION_STRING ('t',
988 "type",
989 "TYPE",
990 gettext_noop ("preference type to set: latency | bandwidth"),
991 &opt_type_str),
992
993 GNUNET_GETOPT_OPTION_SET_UINT ('k',
994 "value",
995 "VALUE",
996 gettext_noop ("preference value"),
997 &opt_pref_value),
998
999 GNUNET_GETOPT_OPTION_SET_ONE ('V',
1000 "verbose",
1001 gettext_noop ("verbose output (include ATS address properties)"),
1002 &opt_verbose),
975 GNUNET_GETOPT_OPTION_END 1003 GNUNET_GETOPT_OPTION_END
976 }; 1004 };
977 1005
diff --git a/src/ats/ats_api_scheduling.c b/src/ats/ats_api_scheduling.c
index faeeb6081..81ae01b6a 100644
--- a/src/ats/ats_api_scheduling.c
+++ b/src/ats/ats_api_scheduling.c
@@ -657,9 +657,9 @@ GNUNET_ATS_address_add (struct GNUNET_ATS_SchedulingHandle *sh,
657 GNUNET_break (GNUNET_ATS_NET_UNSPECIFIED != prop->scope); 657 GNUNET_break (GNUNET_ATS_NET_UNSPECIFIED != prop->scope);
658 namelen = strlen (address->transport_name) + 1; 658 namelen = strlen (address->transport_name) + 1;
659 msize = address->address_length + namelen; 659 msize = address->address_length + namelen;
660 if ((msize + sizeof (struct AddressUpdateMessage) >= GNUNET_SERVER_MAX_MESSAGE_SIZE) || 660 if ((msize + sizeof (struct AddressUpdateMessage) >= GNUNET_MAX_MESSAGE_SIZE) ||
661 (address->address_length >= GNUNET_SERVER_MAX_MESSAGE_SIZE) || 661 (address->address_length >= GNUNET_MAX_MESSAGE_SIZE) ||
662 (namelen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ) 662 (namelen >= GNUNET_MAX_MESSAGE_SIZE) )
663 { 663 {
664 /* address too large for us, this should not happen */ 664 /* address too large for us, this should not happen */
665 GNUNET_break (0); 665 GNUNET_break (0);
diff --git a/src/ats/gnunet-ats-solver-eval.c b/src/ats/gnunet-ats-solver-eval.c
index e2e68562c..597285f5e 100644
--- a/src/ats/gnunet-ats-solver-eval.c
+++ b/src/ats/gnunet-ats-solver-eval.c
@@ -3289,24 +3289,33 @@ main (int argc, char *argv[])
3289 3289
3290 static struct GNUNET_GETOPT_CommandLineOption options[] = 3290 static struct GNUNET_GETOPT_CommandLineOption options[] =
3291 { 3291 {
3292 { 's', "solver", NULL, 3292 GNUNET_GETOPT_OPTION_STRING ('s',
3293 gettext_noop ("solver to use"), 3293 "solver",
3294 1, &GNUNET_GETOPT_set_string, &opt_solver}, 3294 gettext_noop ("solver to use"),
3295 { 'e', "experiment", NULL, 3295 &opt_solver),
3296 gettext_noop ("experiment to use"), 3296
3297 1, &GNUNET_GETOPT_set_string, &opt_exp_file}, 3297 GNUNET_GETOPT_OPTION_STRING ('e',
3298 { 'V', "verbose", NULL, 3298 "experiment"
3299 gettext_noop ("be verbose"), 3299 gettext_noop ("experiment to use"),
3300 0, &GNUNET_GETOPT_set_one, &opt_verbose}, 3300 &opt_exp_file),
3301 { 'p', "print", NULL, 3301
3302 gettext_noop ("print logging"), 3302 GNUNET_GETOPT_OPTION_VERBOSE (&opt_verbose),
3303 0, &GNUNET_GETOPT_set_one, &opt_print}, 3303
3304 { 'f', "file", NULL, 3304 GNUNET_GETOPT_OPTION_SET_ONE ('p',
3305 gettext_noop ("save logging to disk"), 3305 "print",
3306 0, &GNUNET_GETOPT_set_one, &opt_save}, 3306 gettext_noop ("print logging"),
3307 { 'd', "dn", NULL, 3307 &opt_print),
3308 gettext_noop ("disable normalization"), 3308
3309 0, &GNUNET_GETOPT_set_one, &opt_disable_normalization}, 3309 GNUNET_GETOPT_OPTION_SET_ONE ('f',
3310 "file",
3311 gettext_noop ("save logging to disk"),
3312 &opt_save),
3313
3314 GNUNET_GETOPT_OPTION_SET_ONE ('d',
3315 "dn",
3316 gettext_noop ("disable normalization"),
3317 &opt_disable_normalization),
3318
3310 GNUNET_GETOPT_OPTION_END 3319 GNUNET_GETOPT_OPTION_END
3311 }; 3320 };
3312 3321
diff --git a/src/ats/gnunet-service-ats_addresses.c b/src/ats/gnunet-service-ats_addresses.c
index 1a4a33206..ba34cbacb 100644
--- a/src/ats/gnunet-service-ats_addresses.c
+++ b/src/ats/gnunet-service-ats_addresses.c
@@ -571,7 +571,7 @@ transmit_req_addr (struct AddressIteration *ai,
571 msize = plugin_addr_len + plugin_name_length; 571 msize = plugin_addr_len + plugin_name_length;
572 572
573 GNUNET_assert (sizeof (struct PeerInformationMessage) + msize 573 GNUNET_assert (sizeof (struct PeerInformationMessage) + msize
574 < GNUNET_SERVER_MAX_MESSAGE_SIZE); 574 < GNUNET_MAX_MESSAGE_SIZE);
575 env = GNUNET_MQ_msg_extra (msg, 575 env = GNUNET_MQ_msg_extra (msg,
576 msize, 576 msize,
577 GNUNET_MESSAGE_TYPE_ATS_ADDRESSLIST_RESPONSE); 577 GNUNET_MESSAGE_TYPE_ATS_ADDRESSLIST_RESPONSE);
diff --git a/src/ats/gnunet-service-ats_performance.c b/src/ats/gnunet-service-ats_performance.c
index 5252a71bc..07ddf0531 100644
--- a/src/ats/gnunet-service-ats_performance.c
+++ b/src/ats/gnunet-service-ats_performance.c
@@ -85,7 +85,7 @@ notify_client (struct GNUNET_SERVICE_Client *client,
85 85
86 if (NULL != prop) 86 if (NULL != prop)
87 GNUNET_break (GNUNET_ATS_NET_UNSPECIFIED != prop->scope); 87 GNUNET_break (GNUNET_ATS_NET_UNSPECIFIED != prop->scope);
88 GNUNET_assert (msize < GNUNET_SERVER_MAX_MESSAGE_SIZE); 88 GNUNET_assert (msize < GNUNET_MAX_MESSAGE_SIZE);
89 msg = (struct PeerInformationMessage *) buf; 89 msg = (struct PeerInformationMessage *) buf;
90 msg->header.size = htons (msize); 90 msg->header.size = htons (msize);
91 msg->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_PEER_INFORMATION); 91 msg->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_PEER_INFORMATION);
diff --git a/src/ats/perf_ats_solver.c b/src/ats/perf_ats_solver.c
index f05668e9b..855899b36 100644
--- a/src/ats/perf_ats_solver.c
+++ b/src/ats/perf_ats_solver.c
@@ -1404,27 +1404,42 @@ main (int argc, char *argv[])
1404 ph.total_iterations = 1; 1404 ph.total_iterations = 1;
1405 1405
1406 static struct GNUNET_GETOPT_CommandLineOption options[] = { 1406 static struct GNUNET_GETOPT_CommandLineOption options[] = {
1407 { 'a', "addresses", NULL, 1407
1408 gettext_noop ("addresses to use"), 1408 GNUNET_GETOPT_OPTION_SET_UINT ('a',
1409 1, &GNUNET_GETOPT_set_uint, &ph.N_address }, 1409 "addresses",
1410 { 's', "start", NULL, 1410 gettext_noop ("addresses to use"),
1411 gettext_noop ("start with peer"), 1411 &ph.N_address),
1412 1, &GNUNET_GETOPT_set_uint, &ph.N_peers_start }, 1412
1413 { 'e', "end", NULL, 1413 GNUNET_GETOPT_OPTION_SET_UINT ('s',
1414 gettext_noop ("end with peer"), 1414 "start",
1415 1, &GNUNET_GETOPT_set_uint, &ph.N_peers_end }, 1415 gettext_noop ("start with peer"),
1416 { 'i', "iterations", NULL, 1416 &ph.N_peers_start),
1417 gettext_noop ("number of iterations used for averaging (default: 1)"), 1417
1418 1, &GNUNET_GETOPT_set_uint, &ph.total_iterations }, 1418 GNUNET_GETOPT_OPTION_SET_UINT ('e',
1419 { 'p', "percentage", NULL, 1419 "end",
1420 gettext_noop ("update a fix percentage of addresses"), 1420 gettext_noop ("end with peer"),
1421 1, &GNUNET_GETOPT_set_uint, &ph.opt_update_percent }, 1421 &ph.N_peers_end),
1422 { 'd', "data", NULL, 1422
1423 gettext_noop ("create data file"), 1423 GNUNET_GETOPT_OPTION_SET_UINT ('i',
1424 0, &GNUNET_GETOPT_set_one, &ph.create_datafile}, 1424 "iterations",
1425 { 'u', "update", NULL, 1425 gettext_noop ("number of iterations used for averaging (default: 1)"),
1426 gettext_noop ("measure updates"), 1426 &ph.total_iterations),
1427 0, &GNUNET_GETOPT_set_one, &ph.measure_updates}, 1427
1428 GNUNET_GETOPT_OPTION_SET_UINT ('p',
1429 "percentage",
1430 gettext_noop ("update a fix percentage of addresses"),
1431 &ph.opt_update_percent),
1432
1433 GNUNET_GETOPT_OPTION_SET_ONE ('d',
1434 "data",
1435 gettext_noop ("create data file"),
1436 &ph.create_datafile),
1437
1438 GNUNET_GETOPT_OPTION_SET_ONE ('u',
1439 "update",
1440 gettext_noop ("measure updates"),
1441 &ph.measure_updates),
1442
1428 GNUNET_GETOPT_OPTION_END 1443 GNUNET_GETOPT_OPTION_END
1429 }; 1444 };
1430 1445
diff --git a/src/auction/gnunet-auction-create.c b/src/auction/gnunet-auction-create.c
index a4c029572..e6fcab097 100644
--- a/src/auction/gnunet-auction-create.c
+++ b/src/auction/gnunet-auction-create.c
@@ -155,30 +155,49 @@ fail:
155int 155int
156main (int argc, char *const *argv) 156main (int argc, char *const *argv)
157{ 157{
158 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 158 struct GNUNET_GETOPT_CommandLineOption options[] = {
159 {'d', "description", "FILE", 159
160 gettext_noop ("description of the item to be sold"), 160 GNUNET_GETOPT_OPTION_FILENAME ('d',
161 1, &GNUNET_GETOPT_set_filename, &fndesc}, 161 "description",
162 {'p', "pricemap", "FILE", 162 "FILE",
163 gettext_noop ("mapping of possible prices"), 163 gettext_noop ("description of the item to be sold"),
164 1, &GNUNET_GETOPT_set_filename, &fnprices}, 164 &fndesc),
165 {'r', "roundtime", "DURATION", 165
166 gettext_noop ("max duration per round"), 166 GNUNET_GETOPT_OPTION_FILENAME ('p',
167 1, &GNUNET_GETOPT_set_relative_time, &dround}, 167 "pricemap",
168 {'s', "regtime", "DURATION", 168 "FILE",
169 gettext_noop ("duration until auction starts"), 169 gettext_noop ("mapping of possible prices"),
170 1, &GNUNET_GETOPT_set_relative_time, &dstart}, 170 &fnprices),
171 {'m', "m", "NUMBER", 171
172 gettext_noop ("number of items to sell\n" 172 GNUNET_GETOPT_OPTION_SET_RELATIVE_TIME ('r',
173 "0 for first price auction\n" 173 "roundtime",
174 ">0 for vickrey/M+1st price auction"), 174 "DURATION",
175 1, &GNUNET_GETOPT_set_uint, &m}, 175 gettext_noop ("max duration per round"),
176 {'u', "public", NULL, 176 &dround),
177 gettext_noop ("public auction outcome"), 177
178 0, &GNUNET_GETOPT_set_one, &outcome}, 178 GNUNET_GETOPT_OPTION_SET_RELATIVE_TIME ('s',
179 {'i', "interactive", NULL, 179 "regtime",
180 gettext_noop ("keep running in foreground until auction completes"), 180 "DURATION",
181 0, &GNUNET_GETOPT_set_one, &interactive}, 181 gettext_noop ("duration until auction starts"),
182 &dstart),
183 GNUNET_GETOPT_OPTION_SET_UINT ('m',
184 "m",
185 "NUMBER",
186 gettext_noop ("number of items to sell\n"
187 "0 for first price auction\n"
188 ">0 for vickrey/M+1st price auction"),
189 &m),
190
191 GNUNET_GETOPT_OPTION_SET_ONE ('u',
192 "public",
193 gettext_noop ("public auction outcome"),
194 &outcome),
195
196 GNUNET_GETOPT_OPTION_SET_ONE ('i',
197 "interactive",
198 gettext_noop ("keep running in foreground until auction completes"),
199 &interactive),
200
182 GNUNET_GETOPT_OPTION_END 201 GNUNET_GETOPT_OPTION_END
183 }; 202 };
184 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) 203 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
diff --git a/src/block/bg_bf.c b/src/block/bg_bf.c
index 1a17ec84e..3e7d38892 100644
--- a/src/block/bg_bf.c
+++ b/src/block/bg_bf.c
@@ -77,6 +77,7 @@ bf_group_serialize_cb (struct GNUNET_BLOCK_Group *bg,
77 raw, 77 raw,
78 gi->bf_size)) 78 gi->bf_size))
79 { 79 {
80 GNUNET_free (raw);
80 GNUNET_break (0); 81 GNUNET_break (0);
81 return GNUNET_SYSERR; 82 return GNUNET_SYSERR;
82 } 83 }
diff --git a/src/cadet/Makefile.am b/src/cadet/Makefile.am
index b52079b2e..ce30ebe46 100644
--- a/src/cadet/Makefile.am
+++ b/src/cadet/Makefile.am
@@ -23,84 +23,48 @@ AM_CLFAGS = -g
23 23
24libexec_PROGRAMS = \ 24libexec_PROGRAMS = \
25 gnunet-service-cadet \ 25 gnunet-service-cadet \
26 gnunet-service-cadet-new \
27 $(EXP_LIBEXEC) 26 $(EXP_LIBEXEC)
28 27
29bin_PROGRAMS = \ 28bin_PROGRAMS = \
30 gnunet-cadet 29 gnunet-cadet
31 30
32lib_LTLIBRARIES = \ 31lib_LTLIBRARIES = \
33 libgnunetcadetnew.la \
34 libgnunetcadet.la \ 32 libgnunetcadet.la \
35 $(EXP_LIB) 33 $(EXP_LIB)
36 34
37libgnunetcadet_la_SOURCES = \ 35libgnunetcadet_la_SOURCES = \
38 cadet_api.c cadet_common.c 36 cadet_api.c
39libgnunetcadet_la_LIBADD = \ 37libgnunetcadet_la_LIBADD = \
40 $(top_builddir)/src/util/libgnunetutil.la \ 38 $(top_builddir)/src/util/libgnunetutil.la \
41 $(XLIB) \ 39 $(XLIB) \
42 $(LTLIBINTL) 40 $(LTLIBINTL)
43libgnunetcadet_la_LDFLAGS = \ 41libgnunetcadet_la_LDFLAGS = \
44 $(GN_LIB_LDFLAGS) $(WINFLAGS) \ 42 $(GN_LIB_LDFLAGS) $(WINFLAGS) \
45 -version-info 5:0:0 43 -version-info 7:0:0
46
47
48libgnunetcadetnew_la_SOURCES = \
49 cadet_api_new.c
50libgnunetcadetnew_la_LIBADD = \
51 $(top_builddir)/src/util/libgnunetutil.la \
52 $(XLIB) \
53 $(LTLIBINTL)
54libgnunetcadetnew_la_LDFLAGS = \
55 $(GN_LIB_LDFLAGS) $(WINFLAGS) \
56 -version-info 6:0:0
57 44
58gnunet_cadet_SOURCES = \ 45gnunet_cadet_SOURCES = \
59 gnunet-cadet.c 46 gnunet-cadet.c
60gnunet_cadet_LDADD = \ 47gnunet_cadet_LDADD = \
61 libgnunetcadetnew.la \ 48 libgnunetcadet.la \
62 $(top_builddir)/src/util/libgnunetutil.la 49 $(top_builddir)/src/util/libgnunetutil.la
63 50
64gnunet_service_cadet_new_SOURCES = \
65 gnunet-service-cadet-new.c gnunet-service-cadet-new.h \
66 gnunet-service-cadet-new_channel.c gnunet-service-cadet-new_channel.h \
67 gnunet-service-cadet-new_connection.c gnunet-service-cadet-new_connection.h \
68 gnunet-service-cadet-new_core.c gnunet-service-cadet-new_core.h \
69 gnunet-service-cadet-new_dht.c gnunet-service-cadet-new_dht.h \
70 gnunet-service-cadet-new_hello.c gnunet-service-cadet-new_hello.h \
71 gnunet-service-cadet-new_tunnels.c gnunet-service-cadet-new_tunnels.h \
72 gnunet-service-cadet-new_paths.c gnunet-service-cadet-new_paths.h \
73 gnunet-service-cadet-new_peer.c gnunet-service-cadet-new_peer.h
74gnunet_service_cadet_new_LDADD = \
75 $(top_builddir)/src/util/libgnunetutil.la \
76 $(top_builddir)/src/ats/libgnunetats.la \
77 $(top_builddir)/src/core/libgnunetcore.la \
78 $(top_builddir)/src/dht/libgnunetdht.la \
79 $(top_builddir)/src/statistics/libgnunetstatistics.la \
80 $(top_builddir)/src/transport/libgnunettransport.la \
81 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
82 $(top_builddir)/src/hello/libgnunethello.la \
83 $(top_builddir)/src/block/libgnunetblock.la
84
85gnunet_service_cadet_SOURCES = \ 51gnunet_service_cadet_SOURCES = \
86 gnunet-service-cadet_tunnel.c gnunet-service-cadet_tunnel.h \ 52 gnunet-service-cadet.c gnunet-service-cadet.h \
87 gnunet-service-cadet_connection.c gnunet-service-cadet_connection.h \
88 gnunet-service-cadet_channel.c gnunet-service-cadet_channel.h \ 53 gnunet-service-cadet_channel.c gnunet-service-cadet_channel.h \
89 gnunet-service-cadet_local.c gnunet-service-cadet_local.h \ 54 gnunet-service-cadet_connection.c gnunet-service-cadet_connection.h \
90 gnunet-service-cadet_peer.c gnunet-service-cadet_peer.h \ 55 gnunet-service-cadet_core.c gnunet-service-cadet_core.h \
91 gnunet-service-cadet_dht.c gnunet-service-cadet_dht.h \ 56 gnunet-service-cadet_dht.c gnunet-service-cadet_dht.h \
92 gnunet-service-cadet_hello.c gnunet-service-cadet_hello.h \ 57 gnunet-service-cadet_hello.c gnunet-service-cadet_hello.h \
93 cadet_path.c cadet_path.h \ 58 gnunet-service-cadet_tunnels.c gnunet-service-cadet_tunnels.h \
94 cadet_common.c \ 59 gnunet-service-cadet_paths.c gnunet-service-cadet_paths.h \
95 gnunet-service-cadet.c 60 gnunet-service-cadet_peer.c gnunet-service-cadet_peer.h
96gnunet_service_cadet_CFLAGS = $(AM_CFLAGS)
97gnunet_service_cadet_LDADD = \ 61gnunet_service_cadet_LDADD = \
98 $(top_builddir)/src/util/libgnunetutil.la \ 62 $(top_builddir)/src/util/libgnunetutil.la \
99 $(top_builddir)/src/transport/libgnunettransport.la \
100 $(top_builddir)/src/core/libgnunetcore.la \
101 $(top_builddir)/src/ats/libgnunetats.la \ 63 $(top_builddir)/src/ats/libgnunetats.la \
64 $(top_builddir)/src/core/libgnunetcore.la \
102 $(top_builddir)/src/dht/libgnunetdht.la \ 65 $(top_builddir)/src/dht/libgnunetdht.la \
103 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 66 $(top_builddir)/src/statistics/libgnunetstatistics.la \
67 $(top_builddir)/src/transport/libgnunettransport.la \
104 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ 68 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
105 $(top_builddir)/src/hello/libgnunethello.la \ 69 $(top_builddir)/src/hello/libgnunethello.la \
106 $(top_builddir)/src/block/libgnunetblock.la 70 $(top_builddir)/src/block/libgnunetblock.la
@@ -110,39 +74,14 @@ endif
110 74
111 75
112if HAVE_TESTING 76if HAVE_TESTING
113 noinst_LTLIBRARIES = libgnunetcadettest.la libgnunetcadettestnew.la $(noinst_LIB_EXP) 77 noinst_LTLIBRARIES = libgnunetcadettest.la $(noinst_LIB_EXP)
114 noinst_PROGRAMS = gnunet-cadet-profiler 78# noinst_PROGRAMS = gnunet-cadet-profiler
115endif 79endif
116 80
117libgnunetcadettest_la_SOURCES = \
118 cadet_test_lib.c cadet_test_lib.h
119libgnunetcadettest_la_LIBADD = \
120 $(top_builddir)/src/util/libgnunetutil.la \
121 $(top_builddir)/src/testbed/libgnunettestbed.la \
122 libgnunetcadet.la
123
124if HAVE_TESTING 81if HAVE_TESTING
125check_PROGRAMS = \ 82check_PROGRAMS = \
126 test_cadet_local_mq \ 83 test_cadet_local_mq \
127 test_cadet_2_forward_new \ 84 test_cadet_2_forward \
128 test_cadet_2_forward_new \
129 test_cadet_2_signal_new \
130 test_cadet_2_keepalive_new \
131 test_cadet_2_speed_new \
132 test_cadet_2_speed_ack_new \
133 test_cadet_2_speed_backwards_new \
134 test_cadet_2_speed_reliable_new \
135 test_cadet_2_speed_reliable_backwards_new \
136 test_cadet_5_forward_new \
137 test_cadet_5_signal_new \
138 test_cadet_5_keepalive_new \
139 test_cadet_5_speed_new \
140 test_cadet_5_speed_ack_new \
141 test_cadet_5_speed_reliable_new \
142 test_cadet_5_speed_reliable_backwards_new \
143 test_cadet_5_speed_backwards_new \
144 test_cadet_single \
145 test_cadet_local \
146 test_cadet_2_forward \ 85 test_cadet_2_forward \
147 test_cadet_2_signal \ 86 test_cadet_2_signal \
148 test_cadet_2_keepalive \ 87 test_cadet_2_keepalive \
@@ -161,41 +100,39 @@ check_PROGRAMS = \
161 test_cadet_5_speed_backwards 100 test_cadet_5_speed_backwards
162endif 101endif
163 102
103
104#gnunet_cadet_profiler_SOURCES = \
105# gnunet-cadet-profiler.c
106#gnunet_cadet_profiler_LDADD = $(ld_cadet_test_lib)
107
108
109test_cadet_local_mq_SOURCES = \
110 test_cadet_local_mq.c
111test_cadet_local_mq_LDADD = \
112 libgnunetcadet.la \
113 $(top_builddir)/src/testing/libgnunettesting.la \
114 $(top_builddir)/src/util/libgnunetutil.la
115
116
117libgnunetcadettest_la_SOURCES = \
118 cadet_test_lib.c cadet_test_lib.h
119libgnunetcadettest_la_LIBADD = \
120 $(top_builddir)/src/util/libgnunetutil.la \
121 $(top_builddir)/src/testbed/libgnunettestbed.la \
122 libgnunetcadet.la
123
164ld_cadet_test_lib = \ 124ld_cadet_test_lib = \
165 $(top_builddir)/src/util/libgnunetutil.la \ 125 $(top_builddir)/src/util/libgnunetutil.la \
166 $(top_builddir)/src/testing/libgnunettesting.la \ 126 $(top_builddir)/src/testing/libgnunettesting.la \
167 libgnunetcadettest.la \
168 libgnunetcadet.la \ 127 libgnunetcadet.la \
128 libgnunetcadettest.la \
169 $(top_builddir)/src/testbed/libgnunettestbed.la \ 129 $(top_builddir)/src/testbed/libgnunettestbed.la \
170 $(top_builddir)/src/statistics/libgnunetstatistics.la 130 $(top_builddir)/src/statistics/libgnunetstatistics.la
171
172dep_cadet_test_lib = \ 131dep_cadet_test_lib = \
173 libgnunetcadet.la \ 132 libgnunetcadet.la \
174 libgnunetcadettest.la \ 133 libgnunetcadettest.la \
175 $(top_builddir)/src/statistics/libgnunetstatistics.la 134 $(top_builddir)/src/statistics/libgnunetstatistics.la
176 135
177
178gnunet_cadet_profiler_SOURCES = \
179 gnunet-cadet-profiler.c
180gnunet_cadet_profiler_LDADD = $(ld_cadet_test_lib)
181
182
183test_cadet_single_SOURCES = \
184 test_cadet_single.c
185test_cadet_single_LDADD = $(ld_cadet_test_lib)
186
187test_cadet_local_SOURCES = \
188 test_cadet_local.c
189test_cadet_local_LDADD = $(ld_cadet_test_lib)
190
191
192test_cadet_local_mq_SOURCES = \
193 test_cadet_local_mq.c
194test_cadet_local_mq_LDADD = \
195 libgnunetcadetnew.la \
196 $(top_builddir)/src/testing/libgnunettesting.la \
197 $(top_builddir)/src/util/libgnunetutil.la
198
199test_cadet_2_forward_SOURCES = \ 136test_cadet_2_forward_SOURCES = \
200 test_cadet.c 137 test_cadet.c
201test_cadet_2_forward_LDADD = $(ld_cadet_test_lib) 138test_cadet_2_forward_LDADD = $(ld_cadet_test_lib)
@@ -228,7 +165,6 @@ test_cadet_2_speed_reliable_backwards_SOURCES = \
228 test_cadet.c 165 test_cadet.c
229test_cadet_2_speed_reliable_backwards_LDADD = $(ld_cadet_test_lib) 166test_cadet_2_speed_reliable_backwards_LDADD = $(ld_cadet_test_lib)
230 167
231
232test_cadet_5_forward_SOURCES = \ 168test_cadet_5_forward_SOURCES = \
233 test_cadet.c 169 test_cadet.c
234test_cadet_5_forward_LDADD = $(ld_cadet_test_lib) 170test_cadet_5_forward_LDADD = $(ld_cadet_test_lib)
@@ -262,92 +198,6 @@ test_cadet_5_speed_reliable_backwards_SOURCES = \
262test_cadet_5_speed_reliable_backwards_LDADD = $(ld_cadet_test_lib) 198test_cadet_5_speed_reliable_backwards_LDADD = $(ld_cadet_test_lib)
263 199
264 200
265# NEW TESTS
266libgnunetcadettestnew_la_SOURCES = \
267 cadet_test_lib_new.c cadet_test_lib_new.h
268libgnunetcadettestnew_la_LIBADD = \
269 $(top_builddir)/src/util/libgnunetutil.la \
270 $(top_builddir)/src/testbed/libgnunettestbed.la \
271 libgnunetcadetnew.la
272
273ld_cadet_test_lib_new = \
274 $(top_builddir)/src/util/libgnunetutil.la \
275 $(top_builddir)/src/testing/libgnunettesting.la \
276 libgnunetcadetnew.la \
277 libgnunetcadettestnew.la \
278 $(top_builddir)/src/testbed/libgnunettestbed.la \
279 $(top_builddir)/src/statistics/libgnunetstatistics.la
280dep_cadet_test_lib_new = \
281 libgnunetcadetnew.la \
282 libgnunetcadettestnew.la \
283 $(top_builddir)/src/statistics/libgnunetstatistics.la
284
285test_cadet_2_forward_new_SOURCES = \
286 test_cadet_new.c
287test_cadet_2_forward_new_LDADD = $(ld_cadet_test_lib_new)
288
289test_cadet_2_signal_new_SOURCES = \
290 test_cadet_new.c
291test_cadet_2_signal_new_LDADD = $(ld_cadet_test_lib_new)
292
293test_cadet_2_keepalive_new_SOURCES = \
294 test_cadet_new.c
295test_cadet_2_keepalive_new_LDADD = $(ld_cadet_test_lib_new)
296
297test_cadet_2_speed_new_SOURCES = \
298 test_cadet_new.c
299test_cadet_2_speed_new_LDADD = $(ld_cadet_test_lib_new)
300
301test_cadet_2_speed_ack_new_SOURCES = \
302 test_cadet_new.c
303test_cadet_2_speed_ack_new_LDADD = $(ld_cadet_test_lib_new)
304
305test_cadet_2_speed_backwards_new_SOURCES = \
306 test_cadet_new.c
307test_cadet_2_speed_backwards_new_LDADD = $(ld_cadet_test_lib_new)
308
309test_cadet_2_speed_reliable_new_SOURCES = \
310 test_cadet_new.c
311test_cadet_2_speed_reliable_new_LDADD = $(ld_cadet_test_lib_new)
312
313test_cadet_2_speed_reliable_backwards_new_SOURCES = \
314 test_cadet_new.c
315test_cadet_2_speed_reliable_backwards_new_LDADD = $(ld_cadet_test_lib_new)
316
317
318test_cadet_5_forward_new_SOURCES = \
319 test_cadet_new.c
320test_cadet_5_forward_new_LDADD = $(ld_cadet_test_lib_new)
321
322test_cadet_5_signal_new_SOURCES = \
323 test_cadet_new.c
324test_cadet_5_signal_new_LDADD = $(ld_cadet_test_lib_new)
325
326test_cadet_5_keepalive_new_SOURCES = \
327 test_cadet_new.c
328test_cadet_5_keepalive_new_LDADD = $(ld_cadet_test_lib_new)
329
330test_cadet_5_speed_new_SOURCES = \
331 test_cadet_new.c
332test_cadet_5_speed_new_LDADD = $(ld_cadet_test_lib_new)
333
334test_cadet_5_speed_ack_new_SOURCES = \
335 test_cadet_new.c
336test_cadet_5_speed_ack_new_LDADD = $(ld_cadet_test_lib_new)
337
338test_cadet_5_speed_backwards_new_SOURCES = \
339 test_cadet_new.c
340test_cadet_5_speed_backwards_new_LDADD = $(ld_cadet_test_lib_new)
341
342test_cadet_5_speed_reliable_new_SOURCES = \
343 test_cadet_new.c
344test_cadet_5_speed_reliable_new_LDADD = $(ld_cadet_test_lib_new)
345
346test_cadet_5_speed_reliable_backwards_new_SOURCES = \
347 test_cadet_new.c
348test_cadet_5_speed_reliable_backwards_new_LDADD = $(ld_cadet_test_lib_new)
349
350
351if ENABLE_TEST_RUN 201if ENABLE_TEST_RUN
352AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME; 202AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
353TESTS = \ 203TESTS = \
diff --git a/src/cadet/TODO b/src/cadet/TODO
index 820efab7a..06567b0ad 100644
--- a/src/cadet/TODO
+++ b/src/cadet/TODO
@@ -1,6 +1,10 @@
1- URGENT: Congestion/flow control (CHANNEL): 1- URGENT:
2 + estimate max bandwidth using bursts and use to for CONGESTION CONTROL! 2 + if 'client-not-ready', we do not ACK at all, and sender keeps
3 (and figure out how/where to use this!) 3 retransmitting again and again; would be good to do flow-control notification instead
4 of not ACKing that we got the data but are simply not ready for more!
5 + Congestion/flow control (CHANNEL):
6 estimate max bandwidth using bursts and use to for CONGESTION CONTROL!
7 (and figure out how/where to use this!)
4 8
5- HIGH: revisit handling of 'unbuffered' traffic! (CHANNEL/TUNNEL) 9- HIGH: revisit handling of 'unbuffered' traffic! (CHANNEL/TUNNEL)
6 (need to push down through tunnel into connection selection); 10 (need to push down through tunnel into connection selection);
diff --git a/src/cadet/cadet.conf.in b/src/cadet/cadet.conf.in
index 86ba2e535..d50e168f0 100644
--- a/src/cadet/cadet.conf.in
+++ b/src/cadet/cadet.conf.in
@@ -3,7 +3,7 @@ FORCESTART = YES
3AUTOSTART = @AUTOSTART@ 3AUTOSTART = @AUTOSTART@
4@JAVAPORT@PORT = 2096 4@JAVAPORT@PORT = 2096
5HOSTNAME = localhost 5HOSTNAME = localhost
6BINARY = gnunet-service-cadet-new 6BINARY = gnunet-service-cadet
7# PREFIX = valgrind --leak-check=yes 7# PREFIX = valgrind --leak-check=yes
8ACCEPT_FROM = 127.0.0.1; 8ACCEPT_FROM = 127.0.0.1;
9ACCEPT_FROM6 = ::1; 9ACCEPT_FROM6 = ::1;
diff --git a/src/cadet/cadet.h b/src/cadet/cadet.h
index 451d1f354..99f9f2653 100644
--- a/src/cadet/cadet.h
+++ b/src/cadet/cadet.h
@@ -59,7 +59,7 @@ extern "C"
59#include "gnunet_core_service.h" 59#include "gnunet_core_service.h"
60#include "gnunet_cadet_service.h" 60#include "gnunet_cadet_service.h"
61#include "gnunet_protocols.h" 61#include "gnunet_protocols.h"
62#include <gnunet_cadet_service.h> 62#include "gnunet_cadet_service.h"
63 63
64/******************************************************************************/ 64/******************************************************************************/
65/************************** CONSTANTS ******************************/ 65/************************** CONSTANTS ******************************/
diff --git a/src/cadet/cadet_api.c b/src/cadet/cadet_api.c
index 7b9ac62b3..decf473a9 100644
--- a/src/cadet/cadet_api.c
+++ b/src/cadet/cadet_api.c
@@ -21,8 +21,8 @@
21 * @file cadet/cadet_api.c 21 * @file cadet/cadet_api.c
22 * @brief cadet api: client implementation of cadet service 22 * @brief cadet api: client implementation of cadet service
23 * @author Bartlomiej Polot 23 * @author Bartlomiej Polot
24 * @author Christian Grothoff
24 */ 25 */
25
26#include "platform.h" 26#include "platform.h"
27#include "gnunet_util_lib.h" 27#include "gnunet_util_lib.h"
28#include "gnunet_constants.h" 28#include "gnunet_constants.h"
@@ -32,57 +32,9 @@
32 32
33#define LOG(kind,...) GNUNET_log_from (kind, "cadet-api",__VA_ARGS__) 33#define LOG(kind,...) GNUNET_log_from (kind, "cadet-api",__VA_ARGS__)
34 34
35/******************************************************************************/
36/************************ DATA STRUCTURES ****************************/
37/******************************************************************************/
38
39/** 35/**
40 * Transmission queue to the service 36 * Ugly legacy hack.
41 *
42 * @deprecated
43 */ 37 */
44struct GNUNET_CADET_TransmitHandle
45{
46 /**
47 * Double Linked list
48 */
49 struct GNUNET_CADET_TransmitHandle *next;
50
51 /**
52 * Double Linked list
53 */
54 struct GNUNET_CADET_TransmitHandle *prev;
55
56 /**
57 * Channel this message is sent on / for (may be NULL for control messages).
58 */
59 struct GNUNET_CADET_Channel *channel;
60
61 /**
62 * Request data task.
63 */
64 struct GNUNET_SCHEDULER_Task *request_data_task;
65
66 /**
67 * Callback to obtain the message to transmit, or NULL if we
68 * got the message in 'data'. Notice that messages built
69 * by 'notify' need to be encapsulated with information about
70 * the 'target'.
71 */
72 GNUNET_CONNECTION_TransmitReadyNotify notify;
73
74 /**
75 * Closure for 'notify'
76 */
77 void *notify_cls;
78
79 /**
80 * Size of the payload.
81 */
82 size_t size;
83};
84
85
86union CadetInfoCB 38union CadetInfoCB
87{ 39{
88 40
@@ -119,69 +71,19 @@ union CadetInfoCB
119struct GNUNET_CADET_Handle 71struct GNUNET_CADET_Handle
120{ 72{
121 /** 73 /**
122 * Flag to indicate old or MQ API. 74 * Message queue.
123 */
124 int mq_api;
125
126 /**
127 * Message queue (if available).
128 */ 75 */
129 struct GNUNET_MQ_Handle *mq; 76 struct GNUNET_MQ_Handle *mq;
130 77
131 /** 78 /**
132 * Set of handlers used for processing incoming messages in the channels
133 *
134 * @deprecated
135 */
136 const struct GNUNET_CADET_MessageHandler *message_handlers;
137
138 /**
139 * Number of handlers in the handlers array.
140 *
141 * @deprecated
142 */
143 unsigned int n_handlers;
144
145 /**
146 * Ports open. 79 * Ports open.
147 */ 80 */
148 struct GNUNET_CONTAINER_MultiHashMap *ports; 81 struct GNUNET_CONTAINER_MultiHashMap *ports;
149 82
150 /** 83 /**
151 * Double linked list of the channels this client is connected to, head. 84 * Channels open.
152 */ 85 */
153 struct GNUNET_CADET_Channel *channels_head; 86 struct GNUNET_CONTAINER_MultiHashMap32 *channels;
154
155 /**
156 * Double linked list of the channels this client is connected to, tail.
157 */
158 struct GNUNET_CADET_Channel *channels_tail;
159
160 /**
161 * Callback for inbound channel disconnection
162 */
163 GNUNET_CADET_ChannelEndHandler *cleaner;
164
165 /**
166 * Closure for all the handlers given by the client
167 *
168 * @deprecated
169 */
170 void *cls;
171
172 /**
173 * Messages to send to the service, head.
174 *
175 * @deprecated
176 */
177 struct GNUNET_CADET_TransmitHandle *th_head;
178
179 /**
180 * Messages to send to the service, tail.
181 *
182 * @deprecated
183 */
184 struct GNUNET_CADET_TransmitHandle *th_tail;
185 87
186 /** 88 /**
187 * child of the next channel to create (to avoid reusing IDs often) 89 * child of the next channel to create (to avoid reusing IDs often)
@@ -194,14 +96,9 @@ struct GNUNET_CADET_Handle
194 const struct GNUNET_CONFIGURATION_Handle *cfg; 96 const struct GNUNET_CONFIGURATION_Handle *cfg;
195 97
196 /** 98 /**
197 * Time to the next reconnect in case one reconnect fails
198 */
199 struct GNUNET_TIME_Relative reconnect_time;
200
201 /**
202 * Task for trying to reconnect. 99 * Task for trying to reconnect.
203 */ 100 */
204 struct GNUNET_SCHEDULER_Task * reconnect_task; 101 struct GNUNET_SCHEDULER_Task *reconnect_task;
205 102
206 /** 103 /**
207 * Callback for an info task (only one active at a time). 104 * Callback for an info task (only one active at a time).
@@ -212,23 +109,12 @@ struct GNUNET_CADET_Handle
212 * Info callback closure for @c info_cb. 109 * Info callback closure for @c info_cb.
213 */ 110 */
214 void *info_cls; 111 void *info_cls;
215};
216
217 112
218/**
219 * Description of a peer
220 */
221struct GNUNET_CADET_Peer
222{
223 /** 113 /**
224 * ID of the peer in short form 114 * Time to the next reconnect in case one reconnect fails
225 */ 115 */
226 GNUNET_PEER_Id id; 116 struct GNUNET_TIME_Relative reconnect_time;
227 117
228 /**
229 * Channel this peer belongs to
230 */
231 struct GNUNET_CADET_Channel *t;
232}; 118};
233 119
234 120
@@ -237,15 +123,11 @@ struct GNUNET_CADET_Peer
237 */ 123 */
238struct GNUNET_CADET_Channel 124struct GNUNET_CADET_Channel
239{ 125{
240 /**
241 * DLL next
242 */
243 struct GNUNET_CADET_Channel *next;
244 126
245 /** 127 /**
246 * DLL prev 128 * Other end of the channel.
247 */ 129 */
248 struct GNUNET_CADET_Channel *prev; 130 struct GNUNET_PeerIdentity peer;
249 131
250 /** 132 /**
251 * Handle to the cadet this channel belongs to 133 * Handle to the cadet this channel belongs to
@@ -253,40 +135,18 @@ struct GNUNET_CADET_Channel
253 struct GNUNET_CADET_Handle *cadet; 135 struct GNUNET_CADET_Handle *cadet;
254 136
255 /** 137 /**
256 * Local ID of the channel
257 */
258 struct GNUNET_CADET_ClientChannelNumber ccn;
259
260 /**
261 * Channel's port, if incoming. 138 * Channel's port, if incoming.
262 */ 139 */
263 struct GNUNET_CADET_Port *incoming_port; 140 struct GNUNET_CADET_Port *incoming_port;
264 141
265 /** 142 /**
266 * Other end of the channel. 143 * Any data the caller wants to put in here, used for the
267 */ 144 * various callbacks (@e disconnects, @e window_changes, handlers).
268 GNUNET_PEER_Id peer;
269
270 /**
271 * Any data the caller wants to put in here
272 */ 145 */
273 void *ctx; 146 void *ctx;
274 147
275 /** 148 /**
276 * Channel options: reliability, etc. 149 * Message Queue for the channel (which we are implementing).
277 */
278 enum GNUNET_CADET_ChannelOption options;
279
280 /**
281 * Are we allowed to send to the service?
282 *
283 * @deprecated?
284 */
285 unsigned int allow_send;
286
287 /***************************** MQ ************************************/
288 /**
289 * Message Queue for the channel.
290 */ 150 */
291 struct GNUNET_MQ_Handle *mq; 151 struct GNUNET_MQ_Handle *mq;
292 152
@@ -296,7 +156,9 @@ struct GNUNET_CADET_Channel
296 struct GNUNET_SCHEDULER_Task *mq_cont; 156 struct GNUNET_SCHEDULER_Task *mq_cont;
297 157
298 /** 158 /**
299 * Pending envelope in case we don't have an ACK from the service. 159 * Pending envelope with a message to be transmitted to the
160 * service as soon as we are allowed to. Should only be
161 * non-NULL if @e allow_send is 0.
300 */ 162 */
301 struct GNUNET_MQ_Envelope *pending_env; 163 struct GNUNET_MQ_Envelope *pending_env;
302 164
@@ -310,6 +172,21 @@ struct GNUNET_CADET_Channel
310 */ 172 */
311 GNUNET_CADET_DisconnectEventHandler disconnects; 173 GNUNET_CADET_DisconnectEventHandler disconnects;
312 174
175 /**
176 * Local ID of the channel, #GNUNET_CADET_LOCAL_CHANNEL_ID_CLI bit is set if outbound.
177 */
178 struct GNUNET_CADET_ClientChannelNumber ccn;
179
180 /**
181 * Channel options: reliability, etc.
182 */
183 enum GNUNET_CADET_ChannelOption options;
184
185 /**
186 * How many messages are we allowed to send to the service right now?
187 */
188 unsigned int allow_send;
189
313}; 190};
314 191
315 192
@@ -318,35 +195,22 @@ struct GNUNET_CADET_Channel
318 */ 195 */
319struct GNUNET_CADET_Port 196struct GNUNET_CADET_Port
320{ 197{
321 /**
322 * Handle to the CADET session this port belongs to.
323 */
324 struct GNUNET_CADET_Handle *cadet;
325 198
326 /** 199 /**
327 * Port ID. 200 * Port "number"
328 *
329 * @deprecated
330 */ 201 */
331 struct GNUNET_HashCode *hash; 202 struct GNUNET_HashCode id;
332 203
333 /** 204 /**
334 * Callback handler for incoming channels on this port. 205 * Handle to the CADET session this port belongs to.
335 */ 206 */
336 GNUNET_CADET_InboundChannelNotificationHandler *handler; 207 struct GNUNET_CADET_Handle *cadet;
337 208
338 /** 209 /**
339 * Closure for @a handler. 210 * Closure for @a handler.
340 */ 211 */
341 void *cls; 212 void *cls;
342 213
343 /***************************** MQ ************************************/
344
345 /**
346 * Port "number"
347 */
348 struct GNUNET_HashCode id;
349
350 /** 214 /**
351 * Handler for incoming channels on this port 215 * Handler for incoming channels on this port
352 */ 216 */
@@ -355,7 +219,7 @@ struct GNUNET_CADET_Port
355 /** 219 /**
356 * Closure for @ref connects 220 * Closure for @ref connects
357 */ 221 */
358 void * connects_cls; 222 void *connects_cls;
359 223
360 /** 224 /**
361 * Window size change handler. 225 * Window size change handler.
@@ -363,106 +227,30 @@ struct GNUNET_CADET_Port
363 GNUNET_CADET_WindowSizeEventHandler window_changes; 227 GNUNET_CADET_WindowSizeEventHandler window_changes;
364 228
365 /** 229 /**
366 * Handler called when an incoming channel is destroyed.. 230 * Handler called when an incoming channel is destroyed.
367 */ 231 */
368 GNUNET_CADET_DisconnectEventHandler disconnects; 232 GNUNET_CADET_DisconnectEventHandler disconnects;
369 233
370 /** 234 /**
371 * Payload handlers for incoming channels. 235 * Payload handlers for incoming channels.
372 */ 236 */
373 const struct GNUNET_MQ_MessageHandler *handlers; 237 struct GNUNET_MQ_MessageHandler *handlers;
374}; 238};
375 239
376 240
377/** 241/**
378 * Implementation state for cadet's message queue.
379 */
380struct CadetMQState
381{
382 /**
383 * The current transmit handle, or NULL
384 * if no transmit is active.
385 */
386 struct GNUNET_CADET_TransmitHandle *th;
387
388 /**
389 * Channel to send the data over.
390 */
391 struct GNUNET_CADET_Channel *channel;
392};
393
394
395
396/******************************************************************************/
397/********************* FUNCTION DECLARATIONS *************************/
398/******************************************************************************/
399
400/**
401 * Reconnect to the service, retransmit all infomation to try to restore the
402 * original state.
403 *
404 * @param h Handle to the CADET service.
405 */
406static void
407schedule_reconnect (struct GNUNET_CADET_Handle *h);
408
409
410/**
411 * Reconnect callback: tries to reconnect again after a failer previous
412 * reconnection.
413 *
414 * @param cls Closure (cadet handle).
415 */
416static void
417reconnect_cbk (void *cls);
418
419
420/**
421 * Reconnect to the service, retransmit all infomation to try to restore the
422 * original state.
423 *
424 * @param h handle to the cadet
425 */
426static void
427reconnect (struct GNUNET_CADET_Handle *h);
428
429
430/******************************************************************************/
431/*********************** AUXILIARY FUNCTIONS *************************/
432/******************************************************************************/
433
434/**
435 * Check if transmission is a payload packet.
436 *
437 * @param th Transmission handle.
438 *
439 * @return #GNUNET_YES if it is a payload packet,
440 * #GNUNET_NO if it is a cadet management packet.
441 */
442static int
443th_is_payload (struct GNUNET_CADET_TransmitHandle *th)
444{
445 return (th->notify != NULL) ? GNUNET_YES : GNUNET_NO;
446}
447
448
449/**
450 * Find the Port struct for a hash. 242 * Find the Port struct for a hash.
451 * 243 *
452 * @param h CADET handle. 244 * @param h CADET handle.
453 * @param hash HashCode for the port number. 245 * @param hash HashCode for the port number.
454 *
455 * @return The port handle if known, NULL otherwise. 246 * @return The port handle if known, NULL otherwise.
456 */ 247 */
457static struct GNUNET_CADET_Port * 248static struct GNUNET_CADET_Port *
458find_port (const struct GNUNET_CADET_Handle *h, 249find_port (const struct GNUNET_CADET_Handle *h,
459 const struct GNUNET_HashCode *hash) 250 const struct GNUNET_HashCode *hash)
460{ 251{
461 struct GNUNET_CADET_Port *p; 252 return GNUNET_CONTAINER_multihashmap_get (h->ports,
462 253 hash);
463 p = GNUNET_CONTAINER_multihashmap_get (h->ports, hash);
464
465 return p;
466} 254}
467 255
468 256
@@ -474,15 +262,11 @@ find_port (const struct GNUNET_CADET_Handle *h,
474 * @return handle to the required channel or NULL if not found 262 * @return handle to the required channel or NULL if not found
475 */ 263 */
476static struct GNUNET_CADET_Channel * 264static struct GNUNET_CADET_Channel *
477retrieve_channel (struct GNUNET_CADET_Handle *h, 265find_channel (struct GNUNET_CADET_Handle *h,
478 struct GNUNET_CADET_ClientChannelNumber ccn) 266 struct GNUNET_CADET_ClientChannelNumber ccn)
479{ 267{
480 struct GNUNET_CADET_Channel *ch; 268 return GNUNET_CONTAINER_multihashmap32_get (h->channels,
481 269 ntohl (ccn.channel_of_client));
482 for (ch = h->channels_head; NULL != ch; ch = ch->next)
483 if (ch->ccn.channel_of_client == ccn.channel_of_client)
484 return ch;
485 return NULL;
486} 270}
487 271
488 272
@@ -490,38 +274,37 @@ retrieve_channel (struct GNUNET_CADET_Handle *h,
490 * Create a new channel and insert it in the channel list of the cadet handle 274 * Create a new channel and insert it in the channel list of the cadet handle
491 * 275 *
492 * @param h Cadet handle 276 * @param h Cadet handle
493 * @param ccn Desired ccn of the channel, 0 to assign one automatically. 277 * @param ccnp pointer to desired ccn of the channel, NULL to assign one automatically.
494 *
495 * @return Handle to the created channel. 278 * @return Handle to the created channel.
496 */ 279 */
497static struct GNUNET_CADET_Channel * 280static struct GNUNET_CADET_Channel *
498create_channel (struct GNUNET_CADET_Handle *h, 281create_channel (struct GNUNET_CADET_Handle *h,
499 struct GNUNET_CADET_ClientChannelNumber ccn) 282 const struct GNUNET_CADET_ClientChannelNumber *ccnp)
500{ 283{
501 struct GNUNET_CADET_Channel *ch; 284 struct GNUNET_CADET_Channel *ch;
285 struct GNUNET_CADET_ClientChannelNumber ccn;
502 286
503 ch = GNUNET_new (struct GNUNET_CADET_Channel); 287 ch = GNUNET_new (struct GNUNET_CADET_Channel);
504 GNUNET_CONTAINER_DLL_insert (h->channels_head,
505 h->channels_tail,
506 ch);
507 ch->cadet = h; 288 ch->cadet = h;
508 if (0 == ccn.channel_of_client) 289 if (NULL == ccnp)
509 { 290 {
510 ch->ccn = h->next_ccn; 291 while (NULL !=
511 while (NULL != retrieve_channel (h, 292 find_channel (h,
512 h->next_ccn)) 293 h->next_ccn))
513 {
514 h->next_ccn.channel_of_client 294 h->next_ccn.channel_of_client
515 = htonl (1 + ntohl (h->next_ccn.channel_of_client)); 295 = htonl (GNUNET_CADET_LOCAL_CHANNEL_ID_CLI | (1 + ntohl (h->next_ccn.channel_of_client)));
516 if (0 == ntohl (h->next_ccn.channel_of_client)) 296 ccn = h->next_ccn;
517 h->next_ccn.channel_of_client
518 = htonl (GNUNET_CADET_LOCAL_CHANNEL_ID_CLI);
519 }
520 } 297 }
521 else 298 else
522 { 299 {
523 ch->ccn = ccn; 300 ccn = *ccnp;
524 } 301 }
302 ch->ccn = ccn;
303 GNUNET_assert (GNUNET_OK ==
304 GNUNET_CONTAINER_multihashmap32_put (h->channels,
305 ntohl (ch->ccn.channel_of_client),
306 ch,
307 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
525 return ch; 308 return ch;
526} 309}
527 310
@@ -535,114 +318,106 @@ create_channel (struct GNUNET_CADET_Handle *h,
535 * 318 *
536 * @param ch Pointer to the channel. 319 * @param ch Pointer to the channel.
537 * @param call_cleaner Whether to call the cleaner handler. 320 * @param call_cleaner Whether to call the cleaner handler.
538 *
539 * @return Handle to the required channel or NULL if not found.
540 */ 321 */
541static void 322static void
542destroy_channel (struct GNUNET_CADET_Channel *ch) 323destroy_channel (struct GNUNET_CADET_Channel *ch)
543{ 324{
544 struct GNUNET_CADET_Handle *h; 325 struct GNUNET_CADET_Handle *h = ch->cadet;
545 struct GNUNET_CADET_TransmitHandle *th;
546 struct GNUNET_CADET_TransmitHandle *next;
547 326
548 if (NULL == ch)
549 {
550 GNUNET_break (0);
551 return;
552 }
553 h = ch->cadet;
554 LOG (GNUNET_ERROR_TYPE_DEBUG, 327 LOG (GNUNET_ERROR_TYPE_DEBUG,
555 " destroy_channel %X of %p\n", 328 "Destroying channel %X of %p\n",
556 ch->ccn, 329 ch->ccn,
557 h); 330 h);
558 331 GNUNET_assert (GNUNET_YES ==
559 GNUNET_CONTAINER_DLL_remove (h->channels_head, 332 GNUNET_CONTAINER_multihashmap32_remove (h->channels,
560 h->channels_tail, 333 ntohl (ch->ccn.channel_of_client),
561 ch); 334 ch));
562 if (NULL != ch->mq_cont) 335 if (NULL != ch->mq_cont)
563 { 336 {
564 GNUNET_SCHEDULER_cancel (ch->mq_cont); 337 GNUNET_SCHEDULER_cancel (ch->mq_cont);
565 ch->mq_cont = NULL; 338 ch->mq_cont = NULL;
566 } 339 }
567 /* signal channel destruction */ 340 /* signal channel destruction */
568 if (0 != ch->peer) 341 if (NULL != ch->disconnects)
569 { 342 ch->disconnects (ch->ctx,
570 if (NULL != h->cleaner) 343 ch);
571 { 344 if (NULL != ch->pending_env)
572 /** @a deprecated */ 345 GNUNET_MQ_discard (ch->pending_env);
573 LOG (GNUNET_ERROR_TYPE_DEBUG, 346 GNUNET_MQ_destroy (ch->mq);
574 " calling cleaner\n");
575 h->cleaner (h->cls, ch, ch->ctx);
576 }
577 else if (NULL != ch->disconnects)
578 {
579 LOG (GNUNET_ERROR_TYPE_DEBUG,
580 " calling disconnect handler\n");
581 ch->disconnects (ch->ctx, ch);
582 }
583 else
584 {
585 /* Application won't be aware of the channel destruction and use
586 * a pointer to free'd memory.
587 */
588 GNUNET_assert (0);
589 }
590 }
591
592 /* check that clients did not leave messages behind in the queue */
593 for (th = h->th_head; NULL != th; th = next)
594 {
595 next = th->next;
596 if (th->channel != ch)
597 continue;
598 /* Clients should have aborted their requests already.
599 * Management traffic should be ok, as clients can't cancel that.
600 * If the service crashed and we are reconnecting, it's ok.
601 */
602 GNUNET_break (GNUNET_NO == th_is_payload (th));
603 GNUNET_CADET_notify_transmit_ready_cancel (th);
604 }
605
606 if (0 != ch->peer)
607 GNUNET_PEER_change_rc (ch->peer, -1);
608 GNUNET_free (ch); 347 GNUNET_free (ch);
609} 348}
610 349
611 350
612/** 351/**
613 * Add a transmit handle to the transmission queue and set the 352 * Reconnect to the service, retransmit all infomation to try to restore the
614 * timeout if needed. 353 * original state.
354 *
355 * @param h handle to the cadet
356 */
357static void
358reconnect (struct GNUNET_CADET_Handle *h);
359
360
361/**
362 * Reconnect callback: tries to reconnect again after a failer previous
363 * reconnecttion
615 * 364 *
616 * @param h cadet handle with the queue head and tail 365 * @param cls closure (cadet handle)
617 * @param th handle to the packet to be transmitted
618 */ 366 */
619static void 367static void
620add_to_queue (struct GNUNET_CADET_Handle *h, 368reconnect_cbk (void *cls)
621 struct GNUNET_CADET_TransmitHandle *th) 369{
370 struct GNUNET_CADET_Handle *h = cls;
371
372 h->reconnect_task = NULL;
373 reconnect (h);
374}
375
376
377/**
378 * Function called during #reconnect() to destroy
379 * all channels that are still open.
380 *
381 * @param cls the `struct GNUNET_CADET_Handle`
382 * @param cid chanenl ID
383 * @param value a `struct GNUNET_CADET_Channel` to destroy
384 * @return #GNUNET_OK (continue to iterate)
385 */
386static int
387destroy_channel_on_reconnect_cb (void *cls,
388 uint32_t cid,
389 void *value)
622{ 390{
623 GNUNET_CONTAINER_DLL_insert_tail (h->th_head, 391 /* struct GNUNET_CADET_Handle *handle = cls; */
624 h->th_tail, 392 struct GNUNET_CADET_Channel *ch = value;
625 th); 393
394 destroy_channel (ch);
395 return GNUNET_OK;
626} 396}
627 397
628 398
629/** 399/**
630 * Remove a transmit handle from the transmission queue, if present. 400 * Reconnect to the service, retransmit all infomation to try to restore the
401 * original state.
631 * 402 *
632 * Safe to call even if not queued. 403 * @param h handle to the cadet
633 * 404 *
634 * @param th handle to the packet to be unqueued. 405 * @return #GNUNET_YES in case of sucess, #GNUNET_NO otherwise (service down...)
635 */ 406 */
636static void 407static void
637remove_from_queue (struct GNUNET_CADET_TransmitHandle *th) 408schedule_reconnect (struct GNUNET_CADET_Handle *h)
638{ 409{
639 struct GNUNET_CADET_Handle *h = th->channel->cadet; 410 if (NULL != h->reconnect_task)
640 411 return;
641 /* It might or might not have been queued (rarely not), but check anyway. */ 412 GNUNET_CONTAINER_multihashmap32_iterate (h->channels,
642 if (NULL != th->next || h->th_tail == th) 413 &destroy_channel_on_reconnect_cb,
643 { 414 h);
644 GNUNET_CONTAINER_DLL_remove (h->th_head, h->th_tail, th); 415 h->reconnect_task
645 } 416 = GNUNET_SCHEDULER_add_delayed (h->reconnect_time,
417 &reconnect_cbk,
418 h);
419 h->reconnect_time
420 = GNUNET_TIME_STD_BACKOFF (h->reconnect_time);
646} 421}
647 422
648 423
@@ -655,29 +430,44 @@ static void
655notify_window_size (struct GNUNET_CADET_Channel *ch) 430notify_window_size (struct GNUNET_CADET_Channel *ch)
656{ 431{
657 if (NULL != ch->window_changes) 432 if (NULL != ch->window_changes)
658 { 433 ch->window_changes (ch->ctx,
659 ch->window_changes (ch->ctx, ch, ch->allow_send); 434 ch, /* FIXME: remove 'ch'? */
660 } 435 ch->allow_send);
661} 436}
662 437
663/******************************************************************************/
664/*********************** MQ API CALLBACKS ****************************/
665/******************************************************************************/
666 438
667/** 439/**
668 * Allow the MQ implementation to send the next message. 440 * Transmit the next message from our queue.
669 * 441 *
670 * @param cls Closure (channel whose mq to activate). 442 * @param cls Closure (channel whose mq to activate).
671 */ 443 */
672static void 444static void
673cadet_mq_send_continue (void *cls) 445cadet_mq_send_now (void *cls)
674{ 446{
675 struct GNUNET_CADET_Channel *ch = cls; 447 struct GNUNET_CADET_Channel *ch = cls;
448 struct GNUNET_MQ_Envelope *env = ch->pending_env;
676 449
677 ch->mq_cont = NULL; 450 ch->mq_cont = NULL;
451 if (0 == ch->allow_send)
452 {
453 /* how did we get here? */
454 GNUNET_break (0);
455 return;
456 }
457 if (NULL == env)
458 {
459 /* how did we get here? */
460 GNUNET_break (0);
461 return;
462 }
463 ch->allow_send--;
464 ch->pending_env = NULL;
465 GNUNET_MQ_send (ch->cadet->mq,
466 env);
678 GNUNET_MQ_impl_send_continue (ch->mq); 467 GNUNET_MQ_impl_send_continue (ch->mq);
679} 468}
680 469
470
681/** 471/**
682 * Implement sending functionality of a message queue for 472 * Implement sending functionality of a message queue for
683 * us sending messages to a peer. 473 * us sending messages to a peer.
@@ -701,7 +491,6 @@ cadet_mq_send_impl (struct GNUNET_MQ_Handle *mq,
701 struct GNUNET_MQ_Envelope *env; 491 struct GNUNET_MQ_Envelope *env;
702 struct GNUNET_CADET_LocalData *cadet_msg; 492 struct GNUNET_CADET_LocalData *cadet_msg;
703 493
704
705 if (NULL == h->mq) 494 if (NULL == h->mq)
706 { 495 {
707 /* We're currently reconnecting, pretend this worked */ 496 /* We're currently reconnecting, pretend this worked */
@@ -717,26 +506,16 @@ cadet_mq_send_impl (struct GNUNET_MQ_Handle *mq,
717 GNUNET_MQ_impl_send_continue (mq); 506 GNUNET_MQ_impl_send_continue (mq);
718 return; 507 return;
719 } 508 }
720
721 env = GNUNET_MQ_msg_nested_mh (cadet_msg, 509 env = GNUNET_MQ_msg_nested_mh (cadet_msg,
722 GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA, 510 GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA,
723 msg); 511 msg);
724 cadet_msg->ccn = ch->ccn; 512 cadet_msg->ccn = ch->ccn;
725 513 GNUNET_assert (NULL == ch->pending_env);
514 ch->pending_env = env;
726 if (0 < ch->allow_send) 515 if (0 < ch->allow_send)
727 { 516 ch->mq_cont
728 /* Service has allowed this message, just send it and continue accepting */ 517 = GNUNET_SCHEDULER_add_now (&cadet_mq_send_now,
729 GNUNET_MQ_send (h->mq, env); 518 ch);
730 ch->allow_send--;
731 ch->mq_cont = GNUNET_SCHEDULER_add_now (&cadet_mq_send_continue, ch);
732 // notify_window_size (ch); /* FIXME add "verbose" setting? */
733 }
734 else
735 {
736 /* Service has NOT allowed this message, queue it and wait for an ACK */
737 GNUNET_assert (NULL == ch->pending_env);
738 ch->pending_env = env;
739 }
740} 519}
741 520
742 521
@@ -763,14 +542,25 @@ cadet_mq_destroy_impl (struct GNUNET_MQ_Handle *mq,
763 * the CADET service. We should just complain about it but otherwise 542 * the CADET service. We should just complain about it but otherwise
764 * continue processing. 543 * continue processing.
765 * 544 *
766 * @param cls closure 545 * @param cls closure with our `struct GNUNET_CADET_Channel`
767 * @param error error code 546 * @param error error code
768 */ 547 */
769static void 548static void
770cadet_mq_error_handler (void *cls, 549cadet_mq_error_handler (void *cls,
771 enum GNUNET_MQ_Error error) 550 enum GNUNET_MQ_Error error)
772{ 551{
773 GNUNET_break_op (0); 552 struct GNUNET_CADET_Channel *ch = cls;
553
554 GNUNET_break (0);
555 if (GNUNET_MQ_ERROR_NO_MATCH == error)
556 {
557 /* Got a message we did not understand, still try to continue! */
558 GNUNET_CADET_receive_done (ch);
559 }
560 else
561 {
562 schedule_reconnect (ch->cadet);
563 }
774} 564}
775 565
776 566
@@ -781,65 +571,20 @@ cadet_mq_error_handler (void *cls,
781 * @param mq message queue 571 * @param mq message queue
782 * @param impl_state state specific to the implementation 572 * @param impl_state state specific to the implementation
783 */ 573 */
784
785static void 574static void
786cadet_mq_cancel_impl (struct GNUNET_MQ_Handle *mq, 575cadet_mq_cancel_impl (struct GNUNET_MQ_Handle *mq,
787 void *impl_state) 576 void *impl_state)
788{ 577{
789 struct GNUNET_CADET_Channel *ch = impl_state; 578 struct GNUNET_CADET_Channel *ch = impl_state;
790 579
791 LOG (GNUNET_ERROR_TYPE_WARNING, 580 GNUNET_assert (NULL != ch->pending_env);
792 "Cannot cancel mq message on channel %X of %p\n", 581 GNUNET_MQ_discard (ch->pending_env);
793 ch->ccn.channel_of_client, ch->cadet); 582 ch->pending_env = NULL;
794 583 if (NULL != ch->mq_cont)
795 GNUNET_break (0); 584 {
796} 585 GNUNET_SCHEDULER_cancel (ch->mq_cont);
797 586 ch->mq_cont = NULL;
798 587 }
799/******************************************************************************/
800/*********************** RECEIVE HANDLERS ****************************/
801/******************************************************************************/
802
803
804/**
805 * Call the @a notify callback given to #GNUNET_CADET_notify_transmit_ready to
806 * request the data to send over MQ. Since MQ manages the queue, this function
807 * is scheduled immediatly after a transmit ready notification.
808 *
809 * @param cls Closure (transmit handle).
810 */
811static void
812request_data (void *cls)
813{
814 struct GNUNET_CADET_TransmitHandle *th = cls;
815 struct GNUNET_CADET_LocalData *msg;
816 struct GNUNET_MQ_Envelope *env;
817 size_t osize;
818
819 LOG (GNUNET_ERROR_TYPE_DEBUG,
820 "Requesting Data: %u bytes (allow send is %u)\n",
821 th->size,
822 th->channel->allow_send);
823
824 GNUNET_assert (0 < th->channel->allow_send);
825 th->channel->allow_send--;
826 /* NOTE: we may be allowed to send another packet immediately,
827 albeit the current logic waits for the ACK. */
828 th->request_data_task = NULL;
829 remove_from_queue (th);
830
831 env = GNUNET_MQ_msg_extra (msg,
832 th->size,
833 GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA);
834 msg->ccn = th->channel->ccn;
835 osize = th->notify (th->notify_cls,
836 th->size,
837 &msg[1]);
838 GNUNET_assert (osize == th->size);
839
840 GNUNET_MQ_send (th->channel->cadet->mq,
841 env);
842 GNUNET_free (th);
843} 588}
844 589
845 590
@@ -866,7 +611,8 @@ handle_channel_created (void *cls,
866 GNUNET_break (0); 611 GNUNET_break (0);
867 return; 612 return;
868 } 613 }
869 port = find_port (h, port_number); 614 port = find_port (h,
615 port_number);
870 if (NULL == port) 616 if (NULL == port)
871 { 617 {
872 /* We could have closed the port but the service didn't know about it yet 618 /* We could have closed the port but the service didn't know about it yet
@@ -875,7 +621,6 @@ handle_channel_created (void *cls,
875 struct GNUNET_CADET_LocalChannelDestroyMessage *d_msg; 621 struct GNUNET_CADET_LocalChannelDestroyMessage *d_msg;
876 struct GNUNET_MQ_Envelope *env; 622 struct GNUNET_MQ_Envelope *env;
877 623
878 GNUNET_break (0);
879 LOG (GNUNET_ERROR_TYPE_DEBUG, 624 LOG (GNUNET_ERROR_TYPE_DEBUG,
880 "No handler for incoming channel %X (on port %s, recently closed?)\n", 625 "No handler for incoming channel %X (on port %s, recently closed?)\n",
881 ntohl (ccn.channel_of_client), 626 ntohl (ccn.channel_of_client),
@@ -889,10 +634,9 @@ handle_channel_created (void *cls,
889 } 634 }
890 635
891 ch = create_channel (h, 636 ch = create_channel (h,
892 ccn); 637 &ccn);
893 ch->peer = GNUNET_PEER_intern (&msg->peer); 638 ch->peer = msg->peer;
894 ch->cadet = h; 639 ch->cadet = h;
895 ch->ccn = ccn;
896 ch->incoming_port = port; 640 ch->incoming_port = port;
897 ch->options = ntohl (msg->opt); 641 ch->options = ntohl (msg->opt);
898 LOG (GNUNET_ERROR_TYPE_DEBUG, 642 LOG (GNUNET_ERROR_TYPE_DEBUG,
@@ -901,34 +645,21 @@ handle_channel_created (void *cls,
901 GNUNET_h2s (port_number), 645 GNUNET_h2s (port_number),
902 ch); 646 ch);
903 647
904 if (NULL != port->handler) 648 GNUNET_assert (NULL != port->connects);
905 { 649 ch->window_changes = port->window_changes;
906 /** @deprecated */ 650 ch->disconnects = port->disconnects;
907 /* Old style API */ 651 ch->mq = GNUNET_MQ_queue_for_callbacks (&cadet_mq_send_impl,
908 ch->ctx = port->handler (port->cls, 652 &cadet_mq_destroy_impl,
909 ch, 653 &cadet_mq_cancel_impl,
910 &msg->peer, 654 ch,
911 port->hash, 655 port->handlers,
912 ch->options); 656 &cadet_mq_error_handler,
913 } 657 ch);
914 else 658 ch->ctx = port->connects (port->cls,
915 { 659 ch,
916 /* MQ API */ 660 &msg->peer);
917 GNUNET_assert (NULL != port->connects); 661 GNUNET_MQ_set_handlers_closure (ch->mq,
918 ch->window_changes = port->window_changes; 662 ch->ctx);
919 ch->disconnects = port->disconnects;
920 ch->mq = GNUNET_MQ_queue_for_callbacks (&cadet_mq_send_impl,
921 &cadet_mq_destroy_impl,
922 &cadet_mq_cancel_impl,
923 ch,
924 port->handlers,
925 &cadet_mq_error_handler,
926 ch);
927 ch->ctx = port->connects (port->cls,
928 ch,
929 &msg->peer);
930 GNUNET_MQ_set_handlers_closure (ch->mq, ch->ctx);
931 }
932} 663}
933 664
934 665
@@ -944,22 +675,19 @@ handle_channel_destroy (void *cls,
944{ 675{
945 struct GNUNET_CADET_Handle *h = cls; 676 struct GNUNET_CADET_Handle *h = cls;
946 struct GNUNET_CADET_Channel *ch; 677 struct GNUNET_CADET_Channel *ch;
947 struct GNUNET_CADET_ClientChannelNumber ccn;
948
949 ccn = msg->ccn;
950 LOG (GNUNET_ERROR_TYPE_DEBUG,
951 "Channel %X Destroy from service\n",
952 ntohl (ccn.channel_of_client));
953 ch = retrieve_channel (h,
954 ccn);
955 678
679 ch = find_channel (h,
680 msg->ccn);
956 if (NULL == ch) 681 if (NULL == ch)
957 { 682 {
958 LOG (GNUNET_ERROR_TYPE_DEBUG, 683 LOG (GNUNET_ERROR_TYPE_DEBUG,
959 "channel %X unknown\n", 684 "Received channel destroy for unknown channel %X from CADET service (recently close?)\n",
960 ntohl (ccn.channel_of_client)); 685 ntohl (msg->ccn.channel_of_client));
961 return; 686 return;
962 } 687 }
688 LOG (GNUNET_ERROR_TYPE_DEBUG,
689 "Received channel destroy for channel %X from CADET service\n",
690 ntohl (msg->ccn.channel_of_client));
963 destroy_channel (ch); 691 destroy_channel (ch);
964} 692}
965 693
@@ -976,25 +704,14 @@ static int
976check_local_data (void *cls, 704check_local_data (void *cls,
977 const struct GNUNET_CADET_LocalData *message) 705 const struct GNUNET_CADET_LocalData *message)
978{ 706{
979 struct GNUNET_CADET_Handle *h = cls;
980 struct GNUNET_CADET_Channel *ch;
981 uint16_t size; 707 uint16_t size;
982 708
983 size = ntohs (message->header.size); 709 size = ntohs (message->header.size);
984 if (sizeof (*message) + sizeof (struct GNUNET_MessageHeader) > size) 710 if (sizeof (*message) + sizeof (struct GNUNET_MessageHeader) > size)
985 { 711 {
986 GNUNET_break_op (0); 712 GNUNET_break (0);
987 return GNUNET_SYSERR;
988 }
989
990 ch = retrieve_channel (h,
991 message->ccn);
992 if (NULL == ch)
993 {
994 GNUNET_break_op (0);
995 return GNUNET_SYSERR; 713 return GNUNET_SYSERR;
996 } 714 }
997
998 return GNUNET_OK; 715 return GNUNET_OK;
999} 716}
1000 717
@@ -1011,62 +728,31 @@ handle_local_data (void *cls,
1011{ 728{
1012 struct GNUNET_CADET_Handle *h = cls; 729 struct GNUNET_CADET_Handle *h = cls;
1013 const struct GNUNET_MessageHeader *payload; 730 const struct GNUNET_MessageHeader *payload;
1014 const struct GNUNET_CADET_MessageHandler *handler;
1015 struct GNUNET_CADET_Channel *ch; 731 struct GNUNET_CADET_Channel *ch;
1016 uint16_t type; 732 uint16_t type;
1017 int fwd; 733 int fwd;
1018 734
1019 ch = retrieve_channel (h, 735 ch = find_channel (h,
1020 message->ccn); 736 message->ccn);
1021 if (NULL == ch) 737 if (NULL == ch)
1022 { 738 {
1023 GNUNET_break_op (0); 739 LOG (GNUNET_ERROR_TYPE_DEBUG,
1024 reconnect (h); 740 "Unknown channel %X for incoming data (recently closed?)\n",
741 ntohl (message->ccn.channel_of_client));
1025 return; 742 return;
1026 } 743 }
1027 744
1028 payload = (struct GNUNET_MessageHeader *) &message[1]; 745 payload = (const struct GNUNET_MessageHeader *) &message[1];
1029 type = ntohs (payload->type); 746 type = ntohs (payload->type);
1030 fwd = ntohl (ch->ccn.channel_of_client) <= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI; 747 fwd = ntohl (ch->ccn.channel_of_client) <= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI;
1031 LOG (GNUNET_ERROR_TYPE_DEBUG, 748 LOG (GNUNET_ERROR_TYPE_DEBUG,
1032 "Got a %s data on channel %s [%X] of type %s (%u)\n", 749 "Got a %s data on channel %s [%X] of type %u\n",
1033 GC_f2s (fwd), 750 fwd ? "FWD" : "BWD",
1034 GNUNET_i2s (GNUNET_PEER_resolve2 (ch->peer)), 751 GNUNET_i2s (&ch->peer),
1035 ntohl (message->ccn.channel_of_client), 752 ntohl (message->ccn.channel_of_client),
1036 GC_m2s (type),
1037 type); 753 type);
1038 if (NULL != ch->mq) 754 GNUNET_MQ_inject_message (ch->mq,
1039 { 755 payload);
1040 LOG (GNUNET_ERROR_TYPE_DEBUG,
1041 "injecting msg %s into mq %p\n",
1042 GC_m2s (ntohs (payload->type)),
1043 ch->mq);
1044 GNUNET_MQ_inject_message (ch->mq, payload);
1045 return;
1046 }
1047 /** @a deprecated */
1048 for (unsigned i=0;i<h->n_handlers;i++)
1049 {
1050 handler = &h->message_handlers[i];
1051 if (handler->type == type)
1052 {
1053 if (GNUNET_OK !=
1054 handler->callback (h->cls,
1055 ch,
1056 &ch->ctx,
1057 payload))
1058 {
1059 LOG (GNUNET_ERROR_TYPE_DEBUG,
1060 "callback caused disconnection\n");
1061 GNUNET_CADET_channel_destroy (ch);
1062 return;
1063 }
1064 return;
1065 }
1066 }
1067 /* Other peer sent message we do not comprehend. */
1068 GNUNET_break_op (0);
1069 GNUNET_CADET_receive_done (ch);
1070} 756}
1071 757
1072 758
@@ -1083,55 +769,34 @@ handle_local_ack (void *cls,
1083{ 769{
1084 struct GNUNET_CADET_Handle *h = cls; 770 struct GNUNET_CADET_Handle *h = cls;
1085 struct GNUNET_CADET_Channel *ch; 771 struct GNUNET_CADET_Channel *ch;
1086 struct GNUNET_CADET_ClientChannelNumber ccn;
1087 struct GNUNET_CADET_TransmitHandle *th;
1088 772
1089 ccn = message->ccn; 773 ch = find_channel (h,
1090 ch = retrieve_channel (h, ccn); 774 message->ccn);
1091 if (NULL == ch) 775 if (NULL == ch)
1092 { 776 {
1093 LOG (GNUNET_ERROR_TYPE_DEBUG, 777 LOG (GNUNET_ERROR_TYPE_DEBUG,
1094 "ACK on unknown channel %X\n", 778 "ACK on unknown channel %X\n",
1095 ntohl (ccn.channel_of_client)); 779 ntohl (message->ccn.channel_of_client));
1096 return; 780 return;
1097 } 781 }
1098 ch->allow_send++; 782 ch->allow_send++;
1099 if (NULL != ch->mq) 783 if (NULL == ch->pending_env)
1100 { 784 {
1101 if (NULL == ch->pending_env) 785 LOG (GNUNET_ERROR_TYPE_DEBUG,
1102 { 786 "Got an ACK on mq channel %X, allow send now %u!\n",
1103 LOG (GNUNET_ERROR_TYPE_DEBUG, 787 ntohl (ch->ccn.channel_of_client),
1104 "Got an ACK on mq channel %X, allow send now %u!\n", 788 ch->allow_send);
1105 ntohl (ch->ccn.channel_of_client), 789 notify_window_size (ch);
1106 ch->allow_send);
1107 notify_window_size (ch);
1108 }
1109 else
1110 {
1111 LOG (GNUNET_ERROR_TYPE_DEBUG,
1112 "Got an ACK on mq channel %X, sending pending message!\n",
1113 ntohl (ch->ccn.channel_of_client));
1114 GNUNET_MQ_send (h->mq, ch->pending_env);
1115 ch->allow_send--;
1116 ch->pending_env = NULL;
1117 ch->mq_cont = GNUNET_SCHEDULER_add_now (&cadet_mq_send_continue, ch);
1118 }
1119 return; 790 return;
1120 } 791 }
1121 792 if (NULL != ch->mq_cont)
1122 /** @deprecated */ 793 return; /* already working on it! */
1123 /* Old style API */ 794 LOG (GNUNET_ERROR_TYPE_DEBUG,
1124 for (th = h->th_head; NULL != th; th = th->next) 795 "Got an ACK on mq channel %X, sending pending message!\n",
1125 { 796 ntohl (ch->ccn.channel_of_client));
1126 if ( (th->channel == ch) && 797 ch->mq_cont
1127 (NULL == th->request_data_task) ) 798 = GNUNET_SCHEDULER_add_now (&cadet_mq_send_now,
1128 { 799 ch);
1129 th->request_data_task
1130 = GNUNET_SCHEDULER_add_now (&request_data,
1131 th);
1132 break;
1133 }
1134 }
1135} 800}
1136 801
1137 802
@@ -1149,134 +814,15 @@ handle_mq_error (void *cls,
1149{ 814{
1150 struct GNUNET_CADET_Handle *h = cls; 815 struct GNUNET_CADET_Handle *h = cls;
1151 816
1152 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MQ ERROR: %u\n", error); 817 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
818 "MQ ERROR: %u\n",
819 error);
1153 GNUNET_MQ_destroy (h->mq); 820 GNUNET_MQ_destroy (h->mq);
1154 h->mq = NULL; 821 h->mq = NULL;
1155 reconnect (h); 822 reconnect (h);
1156} 823}
1157 824
1158 825
1159/*
1160 * Process a local reply about info on all channels, pass info to the user.
1161 *
1162 * @param h Cadet handle.
1163 * @param message Message itself.
1164 */
1165// static void
1166// process_get_channels (struct GNUNET_CADET_Handle *h,
1167// const struct GNUNET_MessageHeader *message)
1168// {
1169// struct GNUNET_CADET_LocalInfo *msg;
1170//
1171// GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Get Channels messasge received\n");
1172//
1173// if (NULL == h->channels_cb)
1174// {
1175// GNUNET_log (GNUNET_ERROR_TYPE_ERROR, " ignored\n");
1176// return;
1177// }
1178//
1179// msg = (struct GNUNET_CADET_LocalInfo *) message;
1180// if (ntohs (message->size) !=
1181// (sizeof (struct GNUNET_CADET_LocalInfo) +
1182// sizeof (struct GNUNET_PeerIdentity)))
1183// {
1184// GNUNET_break_op (0);
1185// GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1186// "Get channels message: size %hu - expected %u\n",
1187// ntohs (message->size),
1188// sizeof (struct GNUNET_CADET_LocalInfo));
1189// return;
1190// }
1191// h->channels_cb (h->channels_cls,
1192// ntohl (msg->channel_id),
1193// &msg->owner,
1194// &msg->destination);
1195// }
1196
1197
1198
1199/*
1200 * Process a local monitor_channel reply, pass info to the user.
1201 *
1202 * @param h Cadet handle.
1203 * @param message Message itself.
1204 */
1205// static void
1206// process_show_channel (struct GNUNET_CADET_Handle *h,
1207// const struct GNUNET_MessageHeader *message)
1208// {
1209// struct GNUNET_CADET_LocalInfo *msg;
1210// size_t esize;
1211//
1212// GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Show Channel messasge received\n");
1213//
1214// if (NULL == h->channel_cb)
1215// {
1216// GNUNET_log (GNUNET_ERROR_TYPE_ERROR, " ignored\n");
1217// return;
1218// }
1219//
1220// /* Verify message sanity */
1221// msg = (struct GNUNET_CADET_LocalInfo *) message;
1222// esize = sizeof (struct GNUNET_CADET_LocalInfo);
1223// if (ntohs (message->size) != esize)
1224// {
1225// GNUNET_break_op (0);
1226// GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1227// "Show channel message: size %hu - expected %u\n",
1228// ntohs (message->size),
1229// esize);
1230//
1231// h->channel_cb (h->channel_cls, NULL, NULL);
1232// h->channel_cb = NULL;
1233// h->channel_cls = NULL;
1234//
1235// return;
1236// }
1237//
1238// h->channel_cb (h->channel_cls,
1239// &msg->destination,
1240// &msg->owner);
1241// }
1242
1243
1244
1245/**
1246 * Check that message received from CADET service is well-formed.
1247 *
1248 * @param cls the `struct GNUNET_CADET_Handle`
1249 * @param message the message we got
1250 * @return #GNUNET_OK if the message is well-formed,
1251 * #GNUNET_SYSERR otherwise
1252 */
1253static int
1254check_get_peers (void *cls,
1255 const struct GNUNET_CADET_LocalInfoPeer *message)
1256{
1257 struct GNUNET_CADET_Handle *h = cls;
1258 uint16_t size;
1259
1260 if (NULL == h->info_cb.peers_cb)
1261 {
1262 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1263 " no handler for peesr monitor message!\n");
1264 return GNUNET_SYSERR;
1265 }
1266
1267 size = ntohs (message->header.size);
1268 if (sizeof (struct GNUNET_CADET_LocalInfoPeer) > size)
1269 {
1270 h->info_cb.peers_cb (h->info_cls, NULL, -1, 0, 0);
1271 h->info_cb.peers_cb = NULL;
1272 h->info_cls = NULL;
1273 return GNUNET_SYSERR;
1274 }
1275
1276 return GNUNET_OK;
1277}
1278
1279
1280/** 826/**
1281 * Process a local reply about info on all tunnels, pass info to the user. 827 * Process a local reply about info on all tunnels, pass info to the user.
1282 * 828 *
@@ -1288,9 +834,13 @@ handle_get_peers (void *cls,
1288 const struct GNUNET_CADET_LocalInfoPeer *msg) 834 const struct GNUNET_CADET_LocalInfoPeer *msg)
1289{ 835{
1290 struct GNUNET_CADET_Handle *h = cls; 836 struct GNUNET_CADET_Handle *h = cls;
1291 h->info_cb.peers_cb (h->info_cls, &msg->destination, 837
838 if (NULL == h->info_cb.peers_cb)
839 return;
840 h->info_cb.peers_cb (h->info_cls,
841 &msg->destination,
1292 (int) ntohs (msg->tunnel), 842 (int) ntohs (msg->tunnel),
1293 (unsigned int ) ntohs (msg->paths), 843 (unsigned int) ntohs (msg->paths),
1294 0); 844 0);
1295} 845}
1296 846
@@ -1307,62 +857,39 @@ static int
1307check_get_peer (void *cls, 857check_get_peer (void *cls,
1308 const struct GNUNET_CADET_LocalInfoPeer *message) 858 const struct GNUNET_CADET_LocalInfoPeer *message)
1309{ 859{
1310 struct GNUNET_CADET_Handle *h = cls; 860 size_t msize = sizeof (struct GNUNET_CADET_LocalInfoPeer);
1311 const size_t msize = sizeof (struct GNUNET_CADET_LocalInfoPeer); 861 const struct GNUNET_PeerIdentity *paths_array;
1312 struct GNUNET_PeerIdentity *paths_array;
1313 size_t esize; 862 size_t esize;
1314 unsigned int epaths; 863 unsigned int epaths;
1315 unsigned int paths; 864 unsigned int paths;
1316 unsigned int peers; 865 unsigned int peers;
1317 866
1318 if (NULL == h->info_cb.peer_cb)
1319 {
1320 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1321 " no handler for peer monitor message!\n");
1322 goto clean_cls;
1323 }
1324
1325 /* Verify message sanity */
1326 esize = ntohs (message->header.size); 867 esize = ntohs (message->header.size);
1327 if (esize < msize) 868 if (esize < msize)
1328 { 869 {
1329 GNUNET_break_op (0); 870 GNUNET_break (0);
1330 h->info_cb.peer_cb (h->info_cls, NULL, 0, 0, 0, NULL); 871 return GNUNET_SYSERR;
1331 goto clean_cls;
1332 } 872 }
1333 if (0 != ((esize - msize) % sizeof (struct GNUNET_PeerIdentity))) 873 if (0 != ((esize - msize) % sizeof (struct GNUNET_PeerIdentity)))
1334 { 874 {
1335 GNUNET_break_op (0); 875 GNUNET_break (0);
1336 h->info_cb.peer_cb (h->info_cls, NULL, 0, 0, 0, NULL); 876 return GNUNET_SYSERR;
1337 goto clean_cls;
1338
1339 } 877 }
1340 peers = (esize - msize) / sizeof (struct GNUNET_PeerIdentity); 878 peers = (esize - msize) / sizeof (struct GNUNET_PeerIdentity);
1341 epaths = (unsigned int) ntohs (message->paths); 879 epaths = ntohs (message->paths);
1342 paths_array = (struct GNUNET_PeerIdentity *) &message[1]; 880 paths_array = (const struct GNUNET_PeerIdentity *) &message[1];
1343 paths = 0; 881 paths = 0;
1344 for (int i = 0; i < peers; i++) 882 for (unsigned int i = 0; i < peers; i++)
1345 { 883 if (0 == memcmp (&paths_array[i],
1346 if (0 == memcmp (&paths_array[i], &message->destination, 884 &message->destination,
1347 sizeof (struct GNUNET_PeerIdentity))) 885 sizeof (struct GNUNET_PeerIdentity)))
1348 {
1349 paths++; 886 paths++;
1350 }
1351 }
1352 if (paths != epaths) 887 if (paths != epaths)
1353 { 888 {
1354 GNUNET_break_op (0); 889 GNUNET_break (0);
1355 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "p:%u, e: %u\n", paths, epaths); 890 return GNUNET_SYSERR;
1356 h->info_cb.peer_cb (h->info_cls, NULL, 0, 0, 0, NULL);
1357 goto clean_cls;
1358 } 891 }
1359
1360 return GNUNET_OK; 892 return GNUNET_OK;
1361
1362clean_cls:
1363 h->info_cb.peer_cb = NULL;
1364 h->info_cls = NULL;
1365 return GNUNET_SYSERR;
1366} 893}
1367 894
1368 895
@@ -1377,22 +904,26 @@ handle_get_peer (void *cls,
1377 const struct GNUNET_CADET_LocalInfoPeer *message) 904 const struct GNUNET_CADET_LocalInfoPeer *message)
1378{ 905{
1379 struct GNUNET_CADET_Handle *h = cls; 906 struct GNUNET_CADET_Handle *h = cls;
1380 struct GNUNET_PeerIdentity *paths_array; 907 const struct GNUNET_PeerIdentity *paths_array;
1381 unsigned int paths; 908 unsigned int paths;
1382 unsigned int path_length; 909 unsigned int path_length;
1383 int neighbor; 910 int neighbor;
1384 unsigned int peers; 911 unsigned int peers;
1385 912
1386 paths = (unsigned int) ntohs (message->paths); 913 if (NULL == h->info_cb.peer_cb)
1387 paths_array = (struct GNUNET_PeerIdentity *) &message[1]; 914 return;
915 paths = ntohs (message->paths);
916 paths_array = (const struct GNUNET_PeerIdentity *) &message[1];
1388 peers = (ntohs (message->header.size) - sizeof (*message)) 917 peers = (ntohs (message->header.size) - sizeof (*message))
1389 / sizeof (struct GNUNET_PeerIdentity); 918 / sizeof (struct GNUNET_PeerIdentity);
1390 path_length = 0; 919 path_length = 0;
1391 neighbor = GNUNET_NO; 920 neighbor = GNUNET_NO;
1392 921
1393 for (int i = 0; i < peers; i++) 922 for (unsigned int i = 0; i < peers; i++)
1394 { 923 {
1395 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " %s\n", GNUNET_i2s (&paths_array[i])); 924 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
925 " %s\n",
926 GNUNET_i2s (&paths_array[i]));
1396 path_length++; 927 path_length++;
1397 if (0 == memcmp (&paths_array[i], &message->destination, 928 if (0 == memcmp (&paths_array[i], &message->destination,
1398 sizeof (struct GNUNET_PeerIdentity))) 929 sizeof (struct GNUNET_PeerIdentity)))
@@ -1404,7 +935,7 @@ handle_get_peer (void *cls,
1404 } 935 }
1405 936
1406 /* Call Callback with tunnel info. */ 937 /* Call Callback with tunnel info. */
1407 paths_array = (struct GNUNET_PeerIdentity *) &message[1]; 938 paths_array = (const struct GNUNET_PeerIdentity *) &message[1];
1408 h->info_cb.peer_cb (h->info_cls, 939 h->info_cb.peer_cb (h->info_cls,
1409 &message->destination, 940 &message->destination,
1410 (int) ntohs (message->tunnel), 941 (int) ntohs (message->tunnel),
@@ -1415,40 +946,6 @@ handle_get_peer (void *cls,
1415 946
1416 947
1417/** 948/**
1418 * Check that message received from CADET service is well-formed.
1419 *
1420 * @param cls the `struct GNUNET_CADET_Handle`
1421 * @param msg the message we got
1422 * @return #GNUNET_OK if the message is well-formed,
1423 * #GNUNET_SYSERR otherwise
1424 */
1425static int
1426check_get_tunnels (void *cls,
1427 const struct GNUNET_CADET_LocalInfoTunnel *msg)
1428{
1429 struct GNUNET_CADET_Handle *h = cls;
1430 uint16_t size;
1431
1432 if (NULL == h->info_cb.tunnels_cb)
1433 {
1434 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1435 " no handler for tunnels monitor message!\n");
1436 return GNUNET_SYSERR;
1437 }
1438
1439 size = ntohs (msg->header.size);
1440 if (sizeof (struct GNUNET_CADET_LocalInfoTunnel) > size)
1441 {
1442 h->info_cb.tunnels_cb (h->info_cls, NULL, 0, 0, 0, 0);
1443 h->info_cb.tunnels_cb = NULL;
1444 h->info_cls = NULL;
1445 return GNUNET_SYSERR;
1446 }
1447 return GNUNET_OK;
1448}
1449
1450
1451/**
1452 * Process a local reply about info on all tunnels, pass info to the user. 949 * Process a local reply about info on all tunnels, pass info to the user.
1453 * 950 *
1454 * @param cls Closure (Cadet handle). 951 * @param cls Closure (Cadet handle).
@@ -1460,6 +957,8 @@ handle_get_tunnels (void *cls,
1460{ 957{
1461 struct GNUNET_CADET_Handle *h = cls; 958 struct GNUNET_CADET_Handle *h = cls;
1462 959
960 if (NULL == h->info_cb.tunnels_cb)
961 return;
1463 h->info_cb.tunnels_cb (h->info_cls, 962 h->info_cb.tunnels_cb (h->info_cls,
1464 &msg->destination, 963 &msg->destination,
1465 ntohl (msg->channels), 964 ntohl (msg->channels),
@@ -1482,28 +981,18 @@ static int
1482check_get_tunnel (void *cls, 981check_get_tunnel (void *cls,
1483 const struct GNUNET_CADET_LocalInfoTunnel *msg) 982 const struct GNUNET_CADET_LocalInfoTunnel *msg)
1484{ 983{
1485 struct GNUNET_CADET_Handle *h = cls;
1486 unsigned int ch_n; 984 unsigned int ch_n;
1487 unsigned int c_n; 985 unsigned int c_n;
1488 size_t esize; 986 size_t esize;
1489 size_t msize; 987 size_t msize;
1490 988
1491 if (NULL == h->info_cb.tunnel_cb)
1492 {
1493 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1494 " no handler for tunnel monitor message!\n");
1495 goto clean_cls;
1496 }
1497
1498 /* Verify message sanity */ 989 /* Verify message sanity */
1499 msize = ntohs (msg->header.size); 990 msize = ntohs (msg->header.size);
1500 esize = sizeof (struct GNUNET_CADET_LocalInfoTunnel); 991 esize = sizeof (struct GNUNET_CADET_LocalInfoTunnel);
1501 if (esize > msize) 992 if (esize > msize)
1502 { 993 {
1503 GNUNET_break_op (0); 994 GNUNET_break (0);
1504 h->info_cb.tunnel_cb (h->info_cls, 995 return GNUNET_SYSERR;
1505 NULL, 0, 0, NULL, NULL, 0, 0);
1506 goto clean_cls;
1507 } 996 }
1508 ch_n = ntohl (msg->channels); 997 ch_n = ntohl (msg->channels);
1509 c_n = ntohl (msg->connections); 998 c_n = ntohl (msg->connections);
@@ -1518,17 +1007,9 @@ check_get_tunnel (void *cls,
1518 (unsigned int) esize, 1007 (unsigned int) esize,
1519 ch_n, 1008 ch_n,
1520 c_n); 1009 c_n);
1521 h->info_cb.tunnel_cb (h->info_cls, 1010 return GNUNET_SYSERR;
1522 NULL, 0, 0, NULL, NULL, 0, 0);
1523 goto clean_cls;
1524 } 1011 }
1525
1526 return GNUNET_OK; 1012 return GNUNET_OK;
1527
1528clean_cls:
1529 h->info_cb.tunnel_cb = NULL;
1530 h->info_cls = NULL;
1531 return GNUNET_SYSERR;
1532} 1013}
1533 1014
1534 1015
@@ -1548,6 +1029,9 @@ handle_get_tunnel (void *cls,
1548 const struct GNUNET_CADET_ConnectionTunnelIdentifier *conns; 1029 const struct GNUNET_CADET_ConnectionTunnelIdentifier *conns;
1549 const struct GNUNET_CADET_ChannelTunnelNumber *chns; 1030 const struct GNUNET_CADET_ChannelTunnelNumber *chns;
1550 1031
1032 if (NULL == h->info_cb.tunnel_cb)
1033 return;
1034
1551 ch_n = ntohl (msg->channels); 1035 ch_n = ntohl (msg->channels);
1552 c_n = ntohl (msg->connections); 1036 c_n = ntohl (msg->connections);
1553 1037
@@ -1591,44 +1075,25 @@ reconnect (struct GNUNET_CADET_Handle *h)
1591 GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK, 1075 GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK,
1592 struct GNUNET_CADET_LocalAck, 1076 struct GNUNET_CADET_LocalAck,
1593 h), 1077 h),
1594 GNUNET_MQ_hd_var_size (get_peers, 1078 GNUNET_MQ_hd_fixed_size (get_peers,
1595 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS, 1079 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS,
1596 struct GNUNET_CADET_LocalInfoPeer, 1080 struct GNUNET_CADET_LocalInfoPeer,
1597 h), 1081 h),
1598 GNUNET_MQ_hd_var_size (get_peer, 1082 GNUNET_MQ_hd_var_size (get_peer,
1599 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER, 1083 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER,
1600 struct GNUNET_CADET_LocalInfoPeer, 1084 struct GNUNET_CADET_LocalInfoPeer,
1601 h), 1085 h),
1602 GNUNET_MQ_hd_var_size (get_tunnels, 1086 GNUNET_MQ_hd_fixed_size (get_tunnels,
1603 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS, 1087 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS,
1604 struct GNUNET_CADET_LocalInfoTunnel, 1088 struct GNUNET_CADET_LocalInfoTunnel,
1605 h), 1089 h),
1606 GNUNET_MQ_hd_var_size (get_tunnel, 1090 GNUNET_MQ_hd_var_size (get_tunnel,
1607 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL, 1091 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL,
1608 struct GNUNET_CADET_LocalInfoTunnel, 1092 struct GNUNET_CADET_LocalInfoTunnel,
1609 h), 1093 h),
1610// FIXME
1611// GNUNET_MQ_hd_fixed_Y size (channel_destroyed,
1612// GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_NACK_DEPRECATED,
1613// struct GNUNET_CADET_ChannelDestroyMessage);
1614 GNUNET_MQ_handler_end () 1094 GNUNET_MQ_handler_end ()
1615 }; 1095 };
1616 struct GNUNET_CADET_Channel *ch;
1617
1618 while (NULL != (ch = h->channels_head))
1619 {
1620 LOG (GNUNET_ERROR_TYPE_DEBUG,
1621 "Destroying channel due to a reconnect\n");
1622 destroy_channel (ch);
1623 }
1624
1625 LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to CADET\n");
1626 1096
1627 if (NULL != h->mq)
1628 {
1629 GNUNET_MQ_destroy (h->mq);
1630 h->mq = NULL;
1631 }
1632 h->mq = GNUNET_CLIENT_connect (h->cfg, 1097 h->mq = GNUNET_CLIENT_connect (h->cfg,
1633 "cadet", 1098 "cadet",
1634 handlers, 1099 handlers,
@@ -1639,85 +1104,60 @@ reconnect (struct GNUNET_CADET_Handle *h)
1639 schedule_reconnect (h); 1104 schedule_reconnect (h);
1640 return; 1105 return;
1641 } 1106 }
1642 else 1107 h->reconnect_time = GNUNET_TIME_UNIT_MILLISECONDS;
1643 {
1644 h->reconnect_time = GNUNET_TIME_UNIT_MILLISECONDS;
1645 }
1646} 1108}
1647 1109
1110
1648/** 1111/**
1649 * Reconnect callback: tries to reconnect again after a failer previous 1112 * Function called during #GNUNET_CADET_disconnect() to destroy
1650 * reconnecttion 1113 * all channels that are still open.
1651 * 1114 *
1652 * @param cls closure (cadet handle) 1115 * @param cls the `struct GNUNET_CADET_Handle`
1116 * @param cid chanenl ID
1117 * @param value a `struct GNUNET_CADET_Channel` to destroy
1118 * @return #GNUNET_OK (continue to iterate)
1653 */ 1119 */
1654static void 1120static int
1655reconnect_cbk (void *cls) 1121destroy_channel_cb (void *cls,
1122 uint32_t cid,
1123 void *value)
1656{ 1124{
1657 struct GNUNET_CADET_Handle *h = cls; 1125 /* struct GNUNET_CADET_Handle *handle = cls; */
1126 struct GNUNET_CADET_Channel *ch = value;
1658 1127
1659 h->reconnect_task = NULL; 1128 if (ntohl (ch->ccn.channel_of_client) >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
1660 reconnect (h); 1129 {
1130 GNUNET_break (0);
1131 LOG (GNUNET_ERROR_TYPE_DEBUG,
1132 "channel %X not destroyed\n",
1133 ntohl (ch->ccn.channel_of_client));
1134 }
1135 destroy_channel (ch);
1136 return GNUNET_OK;
1661} 1137}
1662 1138
1663 1139
1664/** 1140/**
1665 * Reconnect to the service, retransmit all infomation to try to restore the 1141 * Function called during #GNUNET_CADET_disconnect() to destroy
1666 * original state. 1142 * all ports that are still open.
1667 * 1143 *
1668 * @param h handle to the cadet 1144 * @param cls the `struct GNUNET_CADET_Handle`
1669 * 1145 * @param id port ID
1670 * @return #GNUNET_YES in case of sucess, #GNUNET_NO otherwise (service down...) 1146 * @param value a `struct GNUNET_CADET_Channel` to destroy
1147 * @return #GNUNET_OK (continue to iterate)
1671 */ 1148 */
1672static void 1149static int
1673schedule_reconnect (struct GNUNET_CADET_Handle *h) 1150destroy_port_cb (void *cls,
1674{ 1151 const struct GNUNET_HashCode *id,
1675 if (NULL == h->reconnect_task) 1152 void *value)
1676 {
1677 h->reconnect_task = GNUNET_SCHEDULER_add_delayed (h->reconnect_time,
1678 &reconnect_cbk, h);
1679 h->reconnect_time = GNUNET_TIME_STD_BACKOFF (h->reconnect_time);
1680 }
1681}
1682
1683
1684/******************************************************************************/
1685/********************** API CALL DEFINITIONS *************************/
1686/******************************************************************************/
1687
1688struct GNUNET_CADET_Handle *
1689GNUNET_CADET_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
1690 void *cls,
1691 GNUNET_CADET_ChannelEndHandler cleaner,
1692 const struct GNUNET_CADET_MessageHandler *handlers)
1693{ 1153{
1694 struct GNUNET_CADET_Handle *h; 1154 /* struct GNUNET_CADET_Handle *handle = cls; */
1695 1155 struct GNUNET_CADET_Port *port = value;
1696 h = GNUNET_new (struct GNUNET_CADET_Handle);
1697 LOG (GNUNET_ERROR_TYPE_DEBUG,
1698 "GNUNET_CADET_connect() %p\n",
1699 h);
1700 h->cfg = cfg;
1701 h->cleaner = cleaner;
1702 h->ports = GNUNET_CONTAINER_multihashmap_create (4, GNUNET_YES);
1703 reconnect (h);
1704 if (h->mq == NULL)
1705 {
1706 GNUNET_break (0);
1707 GNUNET_CADET_disconnect (h);
1708 return NULL;
1709 }
1710 h->cls = cls;
1711 h->message_handlers = handlers;
1712 h->next_ccn.channel_of_client = htonl (GNUNET_CADET_LOCAL_CHANNEL_ID_CLI);
1713 h->reconnect_time = GNUNET_TIME_UNIT_MILLISECONDS;
1714 h->reconnect_task = NULL;
1715 1156
1716 /* count handlers */ 1157 /* This is a warning, the app should have cleanly closed all open ports */
1717 for (h->n_handlers = 0; 1158 GNUNET_break (0);
1718 handlers && handlers[h->n_handlers].type; 1159 GNUNET_CADET_close_port (port);
1719 h->n_handlers++) ; 1160 return GNUNET_OK;
1720 return h;
1721} 1161}
1722 1162
1723 1163
@@ -1732,57 +1172,16 @@ GNUNET_CADET_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
1732void 1172void
1733GNUNET_CADET_disconnect (struct GNUNET_CADET_Handle *handle) 1173GNUNET_CADET_disconnect (struct GNUNET_CADET_Handle *handle)
1734{ 1174{
1735 struct GNUNET_CADET_Channel *ch; 1175 GNUNET_CONTAINER_multihashmap_iterate (handle->ports,
1736 struct GNUNET_CADET_Channel *aux; 1176 &destroy_port_cb,
1737 struct GNUNET_CADET_TransmitHandle *th; 1177 handle);
1738 1178 GNUNET_CONTAINER_multihashmap_destroy (handle->ports);
1739 LOG (GNUNET_ERROR_TYPE_DEBUG, 1179 handle->ports = NULL;
1740 "CADET DISCONNECT\n"); 1180 GNUNET_CONTAINER_multihashmap32_iterate (handle->channels,
1741 ch = handle->channels_head; 1181 &destroy_channel_cb,
1742 while (NULL != ch) 1182 handle);
1743 { 1183 GNUNET_CONTAINER_multihashmap32_destroy (handle->channels);
1744 aux = ch->next; 1184 handle->channels = NULL;
1745 if (ntohl (ch->ccn.channel_of_client) >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
1746 {
1747 GNUNET_break (0);
1748 LOG (GNUNET_ERROR_TYPE_DEBUG,
1749 "channel %X not destroyed\n",
1750 ntohl (ch->ccn.channel_of_client));
1751 }
1752 destroy_channel (ch);
1753 ch = aux;
1754 }
1755 while (NULL != (th = handle->th_head))
1756 {
1757 struct GNUNET_MessageHeader *msg;
1758
1759 /* Make sure it is an allowed packet (everything else should have been
1760 * already canceled).
1761 */
1762 GNUNET_break (GNUNET_NO == th_is_payload (th));
1763 msg = (struct GNUNET_MessageHeader *) &th[1];
1764 switch (ntohs(msg->type))
1765 {
1766 case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN:
1767 case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY:
1768 case GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_OPEN:
1769 case GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_CLOSE:
1770 case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CHANNELS:
1771 case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CHANNEL:
1772 case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER:
1773 case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS:
1774 case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL:
1775 case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS:
1776 break;
1777 default:
1778 GNUNET_break (0);
1779 LOG (GNUNET_ERROR_TYPE_ERROR, "unexpected unsent msg %s\n",
1780 GC_m2s (ntohs(msg->type)));
1781 }
1782
1783 GNUNET_CADET_notify_transmit_ready_cancel (th);
1784 }
1785
1786 if (NULL != handle->mq) 1185 if (NULL != handle->mq)
1787 { 1186 {
1788 GNUNET_MQ_destroy (handle->mq); 1187 GNUNET_MQ_destroy (handle->mq);
@@ -1790,58 +1189,15 @@ GNUNET_CADET_disconnect (struct GNUNET_CADET_Handle *handle)
1790 } 1189 }
1791 if (NULL != handle->reconnect_task) 1190 if (NULL != handle->reconnect_task)
1792 { 1191 {
1793 GNUNET_SCHEDULER_cancel(handle->reconnect_task); 1192 GNUNET_SCHEDULER_cancel (handle->reconnect_task);
1794 handle->reconnect_task = NULL; 1193 handle->reconnect_task = NULL;
1795 } 1194 }
1796
1797 GNUNET_CONTAINER_multihashmap_destroy (handle->ports);
1798 handle->ports = NULL;
1799 GNUNET_free (handle); 1195 GNUNET_free (handle);
1800} 1196}
1801 1197
1802 1198
1803/** 1199/**
1804 * Open a port to receive incomming channels. 1200 * Close a port opened with @a GNUNET_CADET_open_port().
1805 *
1806 * @param h CADET handle.
1807 * @param port Hash representing the port number.
1808 * @param new_channel Function called when an channel is received.
1809 * @param new_channel_cls Closure for @a new_channel.
1810 * @return Port handle.
1811 */
1812struct GNUNET_CADET_Port *
1813GNUNET_CADET_open_port (struct GNUNET_CADET_Handle *h,
1814 const struct GNUNET_HashCode *port,
1815 GNUNET_CADET_InboundChannelNotificationHandler
1816 new_channel,
1817 void *new_channel_cls)
1818{
1819 struct GNUNET_CADET_PortMessage *msg;
1820 struct GNUNET_MQ_Envelope *env;
1821 struct GNUNET_CADET_Port *p;
1822
1823 GNUNET_assert (NULL != new_channel);
1824 p = GNUNET_new (struct GNUNET_CADET_Port);
1825 p->cadet = h;
1826 p->hash = GNUNET_new (struct GNUNET_HashCode);
1827 *p->hash = *port;
1828 p->handler = new_channel;
1829 p->cls = new_channel_cls;
1830 GNUNET_assert (GNUNET_OK ==
1831 GNUNET_CONTAINER_multihashmap_put (h->ports,
1832 p->hash,
1833 p,
1834 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1835
1836 env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_OPEN);
1837 msg->port = *p->hash;
1838 GNUNET_MQ_send (h->mq, env);
1839
1840 return p;
1841}
1842
1843/**
1844 * Close a port opened with @a GNUNET_CADET_open_port.
1845 * The @a new_channel callback will no longer be called. 1201 * The @a new_channel callback will no longer be called.
1846 * 1202 *
1847 * @param p Port handle. 1203 * @param p Port handle.
@@ -1851,111 +1207,45 @@ GNUNET_CADET_close_port (struct GNUNET_CADET_Port *p)
1851{ 1207{
1852 struct GNUNET_CADET_PortMessage *msg; 1208 struct GNUNET_CADET_PortMessage *msg;
1853 struct GNUNET_MQ_Envelope *env; 1209 struct GNUNET_MQ_Envelope *env;
1854 struct GNUNET_HashCode *id;
1855
1856 env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_CLOSE);
1857 1210
1858 id = NULL != p->hash ? p->hash : &p->id; 1211 env = GNUNET_MQ_msg (msg,
1859 msg->port = *id; 1212 GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_CLOSE);
1860 GNUNET_MQ_send (p->cadet->mq, env); 1213 msg->port = p->id;
1861 GNUNET_CONTAINER_multihashmap_remove (p->cadet->ports, id, p); 1214 GNUNET_MQ_send (p->cadet->mq,
1862 GNUNET_free_non_null (p->hash); 1215 env);
1216 GNUNET_assert (GNUNET_YES ==
1217 GNUNET_CONTAINER_multihashmap_remove (p->cadet->ports,
1218 &p->id,
1219 p));
1220 GNUNET_free_non_null (p->handlers);
1863 GNUNET_free (p); 1221 GNUNET_free (p);
1864} 1222}
1865 1223
1866 1224
1867/** 1225/**
1868 * Create a new channel towards a remote peer. 1226 * Destroy an existing channel.
1869 * 1227 *
1870 * If the destination port is not open by any peer or the destination peer 1228 * The existing end callback for the channel will be called immediately.
1871 * does not accept the channel, #GNUNET_CADET_ChannelEndHandler will be called 1229 * Any pending outgoing messages will be sent but no incoming messages will be
1872 * for this channel. 1230 * accepted and no data callbacks will be called.
1873 * 1231 *
1874 * @param h cadet handle 1232 * @param channel Channel handle, becomes invalid after this call.
1875 * @param channel_ctx client's channel context to associate with the channel
1876 * @param peer peer identity the channel should go to
1877 * @param port Port hash (port number).
1878 * @param options CadetOption flag field, with all desired option bits set to 1.
1879 * @return handle to the channel
1880 */ 1233 */
1881struct GNUNET_CADET_Channel *
1882GNUNET_CADET_channel_create (struct GNUNET_CADET_Handle *h,
1883 void *channel_ctx,
1884 const struct GNUNET_PeerIdentity *peer,
1885 const struct GNUNET_HashCode *port,
1886 enum GNUNET_CADET_ChannelOption options)
1887{
1888 struct GNUNET_CADET_LocalChannelCreateMessage *msg;
1889 struct GNUNET_MQ_Envelope *env;
1890 struct GNUNET_CADET_Channel *ch;
1891 struct GNUNET_CADET_ClientChannelNumber ccn;
1892
1893 ccn.channel_of_client = htonl (0);
1894 ch = create_channel (h, ccn);
1895 ch->ctx = channel_ctx;
1896 ch->peer = GNUNET_PEER_intern (peer);
1897
1898 LOG (GNUNET_ERROR_TYPE_DEBUG,
1899 "Creating new channel to %s:%u at %p number %X\n",
1900 GNUNET_i2s (peer),
1901 port,
1902 ch,
1903 ntohl (ch->ccn.channel_of_client));
1904 env = GNUNET_MQ_msg (msg,
1905 GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_CREATE);
1906 msg->ccn = ch->ccn;
1907 msg->port = *port;
1908 msg->peer = *peer;
1909 msg->opt = htonl (options);
1910 GNUNET_MQ_send (h->mq,
1911 env);
1912 return ch;
1913}
1914
1915
1916void 1234void
1917GNUNET_CADET_channel_destroy (struct GNUNET_CADET_Channel *channel) 1235GNUNET_CADET_channel_destroy (struct GNUNET_CADET_Channel *channel)
1918{ 1236{
1919 struct GNUNET_CADET_Handle *h; 1237 struct GNUNET_CADET_Handle *h = channel->cadet;
1920 struct GNUNET_CADET_LocalChannelDestroyMessage *msg; 1238 struct GNUNET_CADET_LocalChannelDestroyMessage *msg;
1921 struct GNUNET_MQ_Envelope *env; 1239 struct GNUNET_MQ_Envelope *env;
1922 struct GNUNET_CADET_TransmitHandle *th;
1923 struct GNUNET_CADET_TransmitHandle *next;
1924 1240
1925 LOG (GNUNET_ERROR_TYPE_DEBUG, 1241 if (NULL != h->mq)
1926 "Destroying channel\n");
1927 h = channel->cadet;
1928 for (th = h->th_head; th != NULL; th = next)
1929 { 1242 {
1930 next = th->next; 1243 env = GNUNET_MQ_msg (msg,
1931 if (th->channel == channel) 1244 GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY);
1932 { 1245 msg->ccn = channel->ccn;
1933 GNUNET_break (0); 1246 GNUNET_MQ_send (h->mq,
1934 if (GNUNET_YES == th_is_payload (th)) 1247 env);
1935 {
1936 /* applications should cancel before destroying channel */
1937 LOG (GNUNET_ERROR_TYPE_WARNING,
1938 "Channel destroyed without cancelling transmission requests\n");
1939 th->notify (th->notify_cls, 0, NULL);
1940 }
1941 else
1942 {
1943 LOG (GNUNET_ERROR_TYPE_WARNING,
1944 "no meta-traffic should be queued\n");
1945 }
1946 GNUNET_CONTAINER_DLL_remove (h->th_head,
1947 h->th_tail,
1948 th);
1949 GNUNET_CADET_notify_transmit_ready_cancel (th);
1950 }
1951 } 1248 }
1952
1953 env = GNUNET_MQ_msg (msg,
1954 GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY);
1955 msg->ccn = channel->ccn;
1956 GNUNET_MQ_send (h->mq,
1957 env);
1958
1959 destroy_channel (channel); 1249 destroy_channel (channel);
1960} 1250}
1961 1251
@@ -1971,10 +1261,10 @@ GNUNET_CADET_channel_destroy (struct GNUNET_CADET_Channel *channel)
1971 */ 1261 */
1972const union GNUNET_CADET_ChannelInfo * 1262const union GNUNET_CADET_ChannelInfo *
1973GNUNET_CADET_channel_get_info (struct GNUNET_CADET_Channel *channel, 1263GNUNET_CADET_channel_get_info (struct GNUNET_CADET_Channel *channel,
1974 enum GNUNET_CADET_ChannelOption option, ...) 1264 enum GNUNET_CADET_ChannelOption option,
1265 ...)
1975{ 1266{
1976 static int bool_flag; 1267 static int bool_flag;
1977 const union GNUNET_CADET_ChannelInfo *ret;
1978 1268
1979 switch (option) 1269 switch (option)
1980 { 1270 {
@@ -1985,74 +1275,15 @@ GNUNET_CADET_channel_get_info (struct GNUNET_CADET_Channel *channel,
1985 bool_flag = GNUNET_YES; 1275 bool_flag = GNUNET_YES;
1986 else 1276 else
1987 bool_flag = GNUNET_NO; 1277 bool_flag = GNUNET_NO;
1988 ret = (const union GNUNET_CADET_ChannelInfo *) &bool_flag; 1278 return (const union GNUNET_CADET_ChannelInfo *) &bool_flag;
1989 break; 1279 break;
1990 case GNUNET_CADET_OPTION_PEER: 1280 case GNUNET_CADET_OPTION_PEER:
1991 ret = (const union GNUNET_CADET_ChannelInfo *) GNUNET_PEER_resolve2 (channel->peer); 1281 return (const union GNUNET_CADET_ChannelInfo *) &channel->peer;
1992 break; 1282 break;
1993 default: 1283 default:
1994 GNUNET_break (0); 1284 GNUNET_break (0);
1995 return NULL; 1285 return NULL;
1996 } 1286 }
1997
1998 return ret;
1999}
2000
2001
2002struct GNUNET_CADET_TransmitHandle *
2003GNUNET_CADET_notify_transmit_ready (struct GNUNET_CADET_Channel *channel,
2004 int cork,
2005 struct GNUNET_TIME_Relative maxdelay,
2006 size_t notify_size,
2007 GNUNET_CONNECTION_TransmitReadyNotify notify,
2008 void *notify_cls)
2009{
2010 struct GNUNET_CADET_TransmitHandle *th;
2011
2012 GNUNET_assert (NULL != channel);
2013 GNUNET_assert (NULL != notify);
2014 GNUNET_assert (GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE >= notify_size);
2015 LOG (GNUNET_ERROR_TYPE_DEBUG,
2016 "CADET NOTIFY TRANSMIT READY on channel %X allow_send is %u to %s with %u bytes\n",
2017 ntohl (channel->ccn.channel_of_client),
2018 channel->allow_send,
2019 (ntohl (channel->ccn.channel_of_client) >=
2020 GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
2021 ? "origin"
2022 : "destination",
2023 (unsigned int) notify_size);
2024 if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us != maxdelay.rel_value_us)
2025 {
2026 LOG (GNUNET_ERROR_TYPE_WARNING,
2027 "CADET transmit ready timeout is deprected (has no effect)\n");
2028 }
2029
2030 th = GNUNET_new (struct GNUNET_CADET_TransmitHandle);
2031 th->channel = channel;
2032 th->size = notify_size;
2033 th->notify = notify;
2034 th->notify_cls = notify_cls;
2035 if (0 != channel->allow_send)
2036 th->request_data_task
2037 = GNUNET_SCHEDULER_add_now (&request_data,
2038 th);
2039 else
2040 add_to_queue (channel->cadet,
2041 th);
2042 return th;
2043}
2044
2045
2046void
2047GNUNET_CADET_notify_transmit_ready_cancel (struct GNUNET_CADET_TransmitHandle *th)
2048{
2049 if (NULL != th->request_data_task)
2050 {
2051 GNUNET_SCHEDULER_cancel (th->request_data_task);
2052 th->request_data_task = NULL;
2053 }
2054 remove_from_queue (th);
2055 GNUNET_free (th);
2056} 1287}
2057 1288
2058 1289
@@ -2078,18 +1309,23 @@ GNUNET_CADET_receive_done (struct GNUNET_CADET_Channel *channel)
2078} 1309}
2079 1310
2080 1311
1312/**
1313 * Send message of @a type to CADET service of @a h
1314 *
1315 * @param h handle to CADET service
1316 * @param type message type of trivial information request to send
1317 */
2081static void 1318static void
2082send_info_request (struct GNUNET_CADET_Handle *h, uint16_t type) 1319send_info_request (struct GNUNET_CADET_Handle *h,
1320 uint16_t type)
2083{ 1321{
2084 struct GNUNET_MessageHeader *msg; 1322 struct GNUNET_MessageHeader *msg;
2085 struct GNUNET_MQ_Envelope *env; 1323 struct GNUNET_MQ_Envelope *env;
2086 1324
2087 LOG (GNUNET_ERROR_TYPE_DEBUG, 1325 env = GNUNET_MQ_msg (msg,
2088 " Sending %s monitor message to service\n", 1326 type);
2089 GC_m2s(type)); 1327 GNUNET_MQ_send (h->mq,
2090 1328 env);
2091 env = GNUNET_MQ_msg (msg, type);
2092 GNUNET_MQ_send (h->mq, env);
2093} 1329}
2094 1330
2095 1331
@@ -2103,8 +1339,8 @@ send_info_request (struct GNUNET_CADET_Handle *h, uint16_t type)
2103void 1339void
2104GNUNET_CADET_request_dump (struct GNUNET_CADET_Handle *h) 1340GNUNET_CADET_request_dump (struct GNUNET_CADET_Handle *h)
2105{ 1341{
2106 LOG (GNUNET_ERROR_TYPE_DEBUG, "requesting dump\n"); 1342 send_info_request (h,
2107 send_info_request (h, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_DUMP); 1343 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_DUMP);
2108} 1344}
2109 1345
2110 1346
@@ -2113,13 +1349,11 @@ GNUNET_CADET_request_dump (struct GNUNET_CADET_Handle *h)
2113 * The callback will be called for every peer known to the service. 1349 * The callback will be called for every peer known to the service.
2114 * Only one info request (of any kind) can be active at once. 1350 * Only one info request (of any kind) can be active at once.
2115 * 1351 *
2116 *
2117 * WARNING: unstable API, likely to change in the future! 1352 * WARNING: unstable API, likely to change in the future!
2118 * 1353 *
2119 * @param h Handle to the cadet peer. 1354 * @param h Handle to the cadet peer.
2120 * @param callback Function to call with the requested data. 1355 * @param callback Function to call with the requested data.
2121 * @param callback_cls Closure for @c callback. 1356 * @param callback_cls Closure for @c callback.
2122 *
2123 * @return #GNUNET_OK / #GNUNET_SYSERR 1357 * @return #GNUNET_OK / #GNUNET_SYSERR
2124 */ 1358 */
2125int 1359int
@@ -2132,7 +1366,8 @@ GNUNET_CADET_get_peers (struct GNUNET_CADET_Handle *h,
2132 GNUNET_break (0); 1366 GNUNET_break (0);
2133 return GNUNET_SYSERR; 1367 return GNUNET_SYSERR;
2134 } 1368 }
2135 send_info_request (h, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS); 1369 send_info_request (h,
1370 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS);
2136 h->info_cb.peers_cb = callback; 1371 h->info_cb.peers_cb = callback;
2137 h->info_cls = callback_cls; 1372 h->info_cls = callback_cls;
2138 return GNUNET_OK; 1373 return GNUNET_OK;
@@ -2145,15 +1380,13 @@ GNUNET_CADET_get_peers (struct GNUNET_CADET_Handle *h,
2145 * WARNING: unstable API, likely to change in the future! 1380 * WARNING: unstable API, likely to change in the future!
2146 * 1381 *
2147 * @param h Cadet handle. 1382 * @param h Cadet handle.
2148 * 1383 * @return Closure given to GNUNET_CADET_get_peers().
2149 * @return Closure given to GNUNET_CADET_get_peers.
2150 */ 1384 */
2151void * 1385void *
2152GNUNET_CADET_get_peers_cancel (struct GNUNET_CADET_Handle *h) 1386GNUNET_CADET_get_peers_cancel (struct GNUNET_CADET_Handle *h)
2153{ 1387{
2154 void *cls; 1388 void *cls = h->info_cls;
2155 1389
2156 cls = h->info_cls;
2157 h->info_cb.peers_cb = NULL; 1390 h->info_cb.peers_cb = NULL;
2158 h->info_cls = NULL; 1391 h->info_cls = NULL;
2159 return cls; 1392 return cls;
@@ -2171,7 +1404,6 @@ GNUNET_CADET_get_peers_cancel (struct GNUNET_CADET_Handle *h)
2171 * @param id Peer whose tunnel to examine. 1404 * @param id Peer whose tunnel to examine.
2172 * @param callback Function to call with the requested data. 1405 * @param callback Function to call with the requested data.
2173 * @param callback_cls Closure for @c callback. 1406 * @param callback_cls Closure for @c callback.
2174 *
2175 * @return #GNUNET_OK / #GNUNET_SYSERR 1407 * @return #GNUNET_OK / #GNUNET_SYSERR
2176 */ 1408 */
2177int 1409int
@@ -2188,11 +1420,11 @@ GNUNET_CADET_get_peer (struct GNUNET_CADET_Handle *h,
2188 GNUNET_break (0); 1420 GNUNET_break (0);
2189 return GNUNET_SYSERR; 1421 return GNUNET_SYSERR;
2190 } 1422 }
2191 1423 env = GNUNET_MQ_msg (msg,
2192 env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER); 1424 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER);
2193 msg->peer = *id; 1425 msg->peer = *id;
2194 GNUNET_MQ_send (h->mq, env); 1426 GNUNET_MQ_send (h->mq,
2195 1427 env);
2196 h->info_cb.peer_cb = callback; 1428 h->info_cb.peer_cb = callback;
2197 h->info_cls = callback_cls; 1429 h->info_cls = callback_cls;
2198 return GNUNET_OK; 1430 return GNUNET_OK;
@@ -2209,7 +1441,6 @@ GNUNET_CADET_get_peer (struct GNUNET_CADET_Handle *h,
2209 * @param h Handle to the cadet peer. 1441 * @param h Handle to the cadet peer.
2210 * @param callback Function to call with the requested data. 1442 * @param callback Function to call with the requested data.
2211 * @param callback_cls Closure for @c callback. 1443 * @param callback_cls Closure for @c callback.
2212 *
2213 * @return #GNUNET_OK / #GNUNET_SYSERR 1444 * @return #GNUNET_OK / #GNUNET_SYSERR
2214 */ 1445 */
2215int 1446int
@@ -2222,7 +1453,8 @@ GNUNET_CADET_get_tunnels (struct GNUNET_CADET_Handle *h,
2222 GNUNET_break (0); 1453 GNUNET_break (0);
2223 return GNUNET_SYSERR; 1454 return GNUNET_SYSERR;
2224 } 1455 }
2225 send_info_request (h, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS); 1456 send_info_request (h,
1457 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS);
2226 h->info_cb.tunnels_cb = callback; 1458 h->info_cb.tunnels_cb = callback;
2227 h->info_cls = callback_cls; 1459 h->info_cls = callback_cls;
2228 return GNUNET_OK; 1460 return GNUNET_OK;
@@ -2233,23 +1465,19 @@ GNUNET_CADET_get_tunnels (struct GNUNET_CADET_Handle *h,
2233 * Cancel a monitor request. The monitor callback will not be called. 1465 * Cancel a monitor request. The monitor callback will not be called.
2234 * 1466 *
2235 * @param h Cadet handle. 1467 * @param h Cadet handle.
2236 * 1468 * @return Closure given to GNUNET_CADET_get_tunnels().
2237 * @return Closure given to GNUNET_CADET_get_tunnels.
2238 */ 1469 */
2239void * 1470void *
2240GNUNET_CADET_get_tunnels_cancel (struct GNUNET_CADET_Handle *h) 1471GNUNET_CADET_get_tunnels_cancel (struct GNUNET_CADET_Handle *h)
2241{ 1472{
2242 void *cls; 1473 void *cls = h->info_cls;
2243 1474
2244 h->info_cb.tunnels_cb = NULL; 1475 h->info_cb.tunnels_cb = NULL;
2245 cls = h->info_cls;
2246 h->info_cls = NULL; 1476 h->info_cls = NULL;
2247
2248 return cls; 1477 return cls;
2249} 1478}
2250 1479
2251 1480
2252
2253/** 1481/**
2254 * Request information about a tunnel of the running cadet peer. 1482 * Request information about a tunnel of the running cadet peer.
2255 * The callback will be called for the tunnel once. 1483 * The callback will be called for the tunnel once.
@@ -2261,7 +1489,6 @@ GNUNET_CADET_get_tunnels_cancel (struct GNUNET_CADET_Handle *h)
2261 * @param id Peer whose tunnel to examine. 1489 * @param id Peer whose tunnel to examine.
2262 * @param callback Function to call with the requested data. 1490 * @param callback Function to call with the requested data.
2263 * @param callback_cls Closure for @c callback. 1491 * @param callback_cls Closure for @c callback.
2264 *
2265 * @return #GNUNET_OK / #GNUNET_SYSERR 1492 * @return #GNUNET_OK / #GNUNET_SYSERR
2266 */ 1493 */
2267int 1494int
@@ -2278,11 +1505,11 @@ GNUNET_CADET_get_tunnel (struct GNUNET_CADET_Handle *h,
2278 GNUNET_break (0); 1505 GNUNET_break (0);
2279 return GNUNET_SYSERR; 1506 return GNUNET_SYSERR;
2280 } 1507 }
2281 1508 env = GNUNET_MQ_msg (msg,
2282 env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL); 1509 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL);
2283 msg->peer = *id; 1510 msg->peer = *id;
2284 GNUNET_MQ_send (h->mq, env); 1511 GNUNET_MQ_send (h->mq,
2285 1512 env);
2286 h->info_cb.tunnel_cb = callback; 1513 h->info_cb.tunnel_cb = callback;
2287 h->info_cls = callback_cls; 1514 h->info_cls = callback_cls;
2288 return GNUNET_OK; 1515 return GNUNET_OK;
@@ -2290,158 +1517,6 @@ GNUNET_CADET_get_tunnel (struct GNUNET_CADET_Handle *h,
2290 1517
2291 1518
2292/** 1519/**
2293 * Request information about a specific channel of the running cadet peer.
2294 *
2295 * WARNING: unstable API, likely to change in the future!
2296 * FIXME Add destination option.
2297 *
2298 * @param h Handle to the cadet peer.
2299 * @param initiator ID of the owner of the channel.
2300 * @param channel_number Channel number.
2301 * @param callback Function to call with the requested data.
2302 * @param callback_cls Closure for @c callback.
2303 *
2304 * @return #GNUNET_OK / #GNUNET_SYSERR
2305 */
2306int
2307GNUNET_CADET_show_channel (struct GNUNET_CADET_Handle *h,
2308 struct GNUNET_PeerIdentity *initiator,
2309 unsigned int channel_number,
2310 GNUNET_CADET_ChannelCB callback,
2311 void *callback_cls)
2312{
2313 struct GNUNET_CADET_LocalInfo *msg;
2314 struct GNUNET_MQ_Envelope *env;
2315
2316 if (NULL != h->info_cb.channel_cb)
2317 {
2318 GNUNET_break (0);
2319 return GNUNET_SYSERR;
2320 }
2321
2322 env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CHANNEL);
2323 msg->peer = *initiator;
2324 msg->ccn.channel_of_client = htonl (channel_number);
2325 GNUNET_MQ_send (h->mq, env);
2326
2327 h->info_cb.channel_cb = callback;
2328 h->info_cls = callback_cls;
2329 return GNUNET_OK;
2330}
2331
2332
2333/**
2334 * Function called to notify a client about the connection
2335 * begin ready to queue more data. "buf" will be
2336 * NULL and "size" zero if the connection was closed for
2337 * writing in the meantime.
2338 *
2339 * @param cls closure
2340 * @param size number of bytes available in buf
2341 * @param buf where the callee should write the message
2342 * @return number of bytes written to buf
2343 */
2344static size_t
2345cadet_mq_ntr (void *cls, size_t size,
2346 void *buf)
2347{
2348 struct GNUNET_MQ_Handle *mq = cls;
2349 struct CadetMQState *state = GNUNET_MQ_impl_state (mq);
2350 const struct GNUNET_MessageHeader *msg = GNUNET_MQ_impl_current (mq);
2351 uint16_t msize;
2352
2353 state->th = NULL;
2354 if (NULL == buf)
2355 {
2356 GNUNET_MQ_inject_error (mq, GNUNET_MQ_ERROR_WRITE);
2357 return 0;
2358 }
2359 msize = ntohs (msg->size);
2360 GNUNET_assert (msize <= size);
2361 GNUNET_memcpy (buf, msg, msize);
2362 GNUNET_MQ_impl_send_continue (mq);
2363 return msize;
2364}
2365
2366
2367/**
2368 * Signature of functions implementing the
2369 * sending functionality of a message queue.
2370 *
2371 * @param mq the message queue
2372 * @param msg the message to send
2373 * @param impl_state state of the implementation
2374 */
2375static void
2376cadet_mq_send_impl_old (struct GNUNET_MQ_Handle *mq,
2377 const struct GNUNET_MessageHeader *msg,
2378 void *impl_state)
2379{
2380 struct CadetMQState *state = impl_state;
2381
2382 GNUNET_assert (NULL == state->th);
2383 state->th =
2384 GNUNET_CADET_notify_transmit_ready (state->channel,
2385 /* FIXME: add option for corking */
2386 GNUNET_NO,
2387 GNUNET_TIME_UNIT_FOREVER_REL,
2388 ntohs (msg->size),
2389 &cadet_mq_ntr, mq);
2390
2391}
2392
2393
2394/**
2395 * Signature of functions implementing the
2396 * destruction of a message queue.
2397 * Implementations must not free 'mq', but should
2398 * take care of 'impl_state'.
2399 *
2400 * @param mq the message queue to destroy
2401 * @param impl_state state of the implementation
2402 */
2403static void
2404cadet_mq_destroy_impl_old (struct GNUNET_MQ_Handle *mq,
2405 void *impl_state)
2406{
2407 struct CadetMQState *state = impl_state;
2408
2409 if (NULL != state->th)
2410 GNUNET_CADET_notify_transmit_ready_cancel (state->th);
2411
2412 GNUNET_free (state);
2413}
2414
2415
2416/**
2417 * Create a message queue for a cadet channel.
2418 * The message queue can only be used to transmit messages,
2419 * not to receive them.
2420 *
2421 * @param channel the channel to create the message qeue for
2422 * @return a message queue to messages over the channel
2423 */
2424struct GNUNET_MQ_Handle *
2425GNUNET_CADET_mq_create (struct GNUNET_CADET_Channel *channel)
2426{
2427 struct GNUNET_MQ_Handle *mq;
2428 struct CadetMQState *state;
2429
2430 state = GNUNET_new (struct CadetMQState);
2431 state->channel = channel;
2432
2433 mq = GNUNET_MQ_queue_for_callbacks (&cadet_mq_send_impl_old,
2434 &cadet_mq_destroy_impl_old,
2435 NULL, /* FIXME: cancel impl. */
2436 state,
2437 NULL, /* no msg handlers */
2438 NULL, /* no err handlers */
2439 NULL); /* no handler cls */
2440 return mq;
2441}
2442
2443
2444/**
2445 * Transitional function to convert an unsigned int port to a hash value. 1520 * Transitional function to convert an unsigned int port to a hash value.
2446 * WARNING: local static value returned, NOT reentrant! 1521 * WARNING: local static value returned, NOT reentrant!
2447 * WARNING: do not use this function for new code! 1522 * WARNING: do not use this function for new code!
@@ -2456,19 +1531,14 @@ GC_u2h (uint32_t port)
2456 static struct GNUNET_HashCode hash; 1531 static struct GNUNET_HashCode hash;
2457 1532
2458 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1533 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2459 "This is a transitional function, " 1534 "This is a transitional function, use proper crypto hashes as CADET ports\n");
2460 "use proper crypto hashes as CADET ports\n"); 1535 GNUNET_CRYPTO_hash (&port,
2461 GNUNET_CRYPTO_hash (&port, sizeof (port), &hash); 1536 sizeof (port),
2462 1537 &hash);
2463 return &hash; 1538 return &hash;
2464} 1539}
2465 1540
2466 1541
2467
2468/******************************************************************************/
2469/******************************* MQ-BASED API *********************************/
2470/******************************************************************************/
2471
2472/** 1542/**
2473 * Connect to the MQ-based cadet service. 1543 * Connect to the MQ-based cadet service.
2474 * 1544 *
@@ -2477,16 +1547,17 @@ GC_u2h (uint32_t port)
2477 * @return Handle to the cadet service NULL on error. 1547 * @return Handle to the cadet service NULL on error.
2478 */ 1548 */
2479struct GNUNET_CADET_Handle * 1549struct GNUNET_CADET_Handle *
2480GNUNET_CADET_connecT (const struct GNUNET_CONFIGURATION_Handle *cfg) 1550GNUNET_CADET_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
2481{ 1551{
2482 struct GNUNET_CADET_Handle *h; 1552 struct GNUNET_CADET_Handle *h;
2483 1553
2484 LOG (GNUNET_ERROR_TYPE_DEBUG, 1554 LOG (GNUNET_ERROR_TYPE_DEBUG,
2485 "GNUNET_CADET_connecT()\n"); 1555 "GNUNET_CADET_connect()\n");
2486 h = GNUNET_new (struct GNUNET_CADET_Handle); 1556 h = GNUNET_new (struct GNUNET_CADET_Handle);
2487 h->cfg = cfg; 1557 h->cfg = cfg;
2488 h->mq_api = GNUNET_YES; 1558 h->ports = GNUNET_CONTAINER_multihashmap_create (4,
2489 h->ports = GNUNET_CONTAINER_multihashmap_create (4, GNUNET_YES); 1559 GNUNET_YES);
1560 h->channels = GNUNET_CONTAINER_multihashmap32_create (4);
2490 reconnect (h); 1561 reconnect (h);
2491 if (NULL == h->mq) 1562 if (NULL == h->mq)
2492 { 1563 {
@@ -2512,11 +1583,10 @@ GNUNET_CADET_connecT (const struct GNUNET_CONFIGURATION_Handle *cfg)
2512 * @param window_changes Function called when the transmit window size changes. 1583 * @param window_changes Function called when the transmit window size changes.
2513 * @param disconnects Function called when a channel is disconnected. 1584 * @param disconnects Function called when a channel is disconnected.
2514 * @param handlers Callbacks for messages we care about, NULL-terminated. 1585 * @param handlers Callbacks for messages we care about, NULL-terminated.
2515 *
2516 * @return Port handle. 1586 * @return Port handle.
2517 */ 1587 */
2518struct GNUNET_CADET_Port * 1588struct GNUNET_CADET_Port *
2519GNUNET_CADET_open_porT (struct GNUNET_CADET_Handle *h, 1589GNUNET_CADET_open_port (struct GNUNET_CADET_Handle *h,
2520 const struct GNUNET_HashCode *port, 1590 const struct GNUNET_HashCode *port,
2521 GNUNET_CADET_ConnectEventHandler connects, 1591 GNUNET_CADET_ConnectEventHandler connects,
2522 void * connects_cls, 1592 void * connects_cls,
@@ -2538,16 +1608,7 @@ GNUNET_CADET_open_porT (struct GNUNET_CADET_Handle *h,
2538 p->cls = connects_cls; 1608 p->cls = connects_cls;
2539 p->window_changes = window_changes; 1609 p->window_changes = window_changes;
2540 p->disconnects = disconnects; 1610 p->disconnects = disconnects;
2541 if (NULL != handlers) 1611 p->handlers = GNUNET_MQ_copy_handlers (handlers);
2542 {
2543 unsigned int i;
2544 for (i=0;NULL != handlers[i].cb; i++) ;
2545 p->handlers = GNUNET_new_array (i + 1,
2546 struct GNUNET_MQ_MessageHandler);
2547 GNUNET_memcpy ((struct GNUNET_MQ_MessageHandler *) p->handlers,
2548 handlers,
2549 i * sizeof (struct GNUNET_MQ_MessageHandler));
2550 }
2551 1612
2552 GNUNET_assert (GNUNET_OK == 1613 GNUNET_assert (GNUNET_OK ==
2553 GNUNET_CONTAINER_multihashmap_put (h->ports, 1614 GNUNET_CONTAINER_multihashmap_put (h->ports,
@@ -2555,10 +1616,11 @@ GNUNET_CADET_open_porT (struct GNUNET_CADET_Handle *h,
2555 p, 1616 p,
2556 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); 1617 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2557 1618
2558 env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_OPEN); 1619 env = GNUNET_MQ_msg (msg,
1620 GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_OPEN);
2559 msg->port = p->id; 1621 msg->port = p->id;
2560 GNUNET_MQ_send (h->mq, env); 1622 GNUNET_MQ_send (h->mq,
2561 1623 env);
2562 return p; 1624 return p;
2563} 1625}
2564 1626
@@ -2580,11 +1642,10 @@ GNUNET_CADET_open_porT (struct GNUNET_CADET_Handle *h,
2580 * @param window_changes Function called when the transmit window size changes. 1642 * @param window_changes Function called when the transmit window size changes.
2581 * @param disconnects Function called when the channel is disconnected. 1643 * @param disconnects Function called when the channel is disconnected.
2582 * @param handlers Callbacks for messages we care about, NULL-terminated. 1644 * @param handlers Callbacks for messages we care about, NULL-terminated.
2583 *
2584 * @return Handle to the channel. 1645 * @return Handle to the channel.
2585 */ 1646 */
2586struct GNUNET_CADET_Channel * 1647struct GNUNET_CADET_Channel *
2587GNUNET_CADET_channel_creatE (struct GNUNET_CADET_Handle *h, 1648GNUNET_CADET_channel_create (struct GNUNET_CADET_Handle *h,
2588 void *channel_cls, 1649 void *channel_cls,
2589 const struct GNUNET_PeerIdentity *destination, 1650 const struct GNUNET_PeerIdentity *destination,
2590 const struct GNUNET_HashCode *port, 1651 const struct GNUNET_HashCode *port,
@@ -2594,17 +1655,14 @@ GNUNET_CADET_channel_creatE (struct GNUNET_CADET_Handle *h,
2594 const struct GNUNET_MQ_MessageHandler *handlers) 1655 const struct GNUNET_MQ_MessageHandler *handlers)
2595{ 1656{
2596 struct GNUNET_CADET_Channel *ch; 1657 struct GNUNET_CADET_Channel *ch;
2597 struct GNUNET_CADET_ClientChannelNumber ccn;
2598 struct GNUNET_CADET_LocalChannelCreateMessage *msg; 1658 struct GNUNET_CADET_LocalChannelCreateMessage *msg;
2599 struct GNUNET_MQ_Envelope *env; 1659 struct GNUNET_MQ_Envelope *env;
2600 1660
2601 GNUNET_assert (NULL != disconnects); 1661 GNUNET_assert (NULL != disconnects);
2602 1662 ch = create_channel (h,
2603 /* Save parameters */ 1663 NULL);
2604 ccn.channel_of_client = htonl (0);
2605 ch = create_channel (h, ccn);
2606 ch->ctx = channel_cls; 1664 ch->ctx = channel_cls;
2607 ch->peer = GNUNET_PEER_intern (destination); 1665 ch->peer = *destination;
2608 ch->options = options; 1666 ch->options = options;
2609 ch->window_changes = window_changes; 1667 ch->window_changes = window_changes;
2610 ch->disconnects = disconnects; 1668 ch->disconnects = disconnects;
@@ -2628,7 +1686,6 @@ GNUNET_CADET_channel_creatE (struct GNUNET_CADET_Handle *h,
2628 msg->opt = htonl (options); 1686 msg->opt = htonl (options);
2629 GNUNET_MQ_send (h->mq, 1687 GNUNET_MQ_send (h->mq,
2630 env); 1688 env);
2631
2632 return ch; 1689 return ch;
2633} 1690}
2634 1691
@@ -2645,3 +1702,5 @@ GNUNET_CADET_get_mq (const struct GNUNET_CADET_Channel *channel)
2645{ 1702{
2646 return channel->mq; 1703 return channel->mq;
2647} 1704}
1705
1706/* end of cadet_api.c */
diff --git a/src/cadet/cadet_api_new.c b/src/cadet/cadet_api_new.c
deleted file mode 100644
index a62de0a47..000000000
--- a/src/cadet/cadet_api_new.c
+++ /dev/null
@@ -1,1720 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011, 2017 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20/**
21 * @file cadet/cadet_api.c
22 * @brief cadet api: client implementation of cadet service
23 * @author Bartlomiej Polot
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_constants.h"
29#include "gnunet_cadet_service.h"
30#include "cadet.h"
31#include "cadet_protocol.h"
32
33#define LOG(kind,...) GNUNET_log_from (kind, "cadet-api",__VA_ARGS__)
34
35/**
36 * Ugly legacy hack.
37 */
38union CadetInfoCB
39{
40
41 /**
42 * Channel callback.
43 */
44 GNUNET_CADET_ChannelCB channel_cb;
45
46 /**
47 * Monitor callback
48 */
49 GNUNET_CADET_PeersCB peers_cb;
50
51 /**
52 * Monitor callback
53 */
54 GNUNET_CADET_PeerCB peer_cb;
55
56 /**
57 * Monitor callback
58 */
59 GNUNET_CADET_TunnelsCB tunnels_cb;
60
61 /**
62 * Tunnel callback.
63 */
64 GNUNET_CADET_TunnelCB tunnel_cb;
65};
66
67
68/**
69 * Opaque handle to the service.
70 */
71struct GNUNET_CADET_Handle
72{
73 /**
74 * Message queue.
75 */
76 struct GNUNET_MQ_Handle *mq;
77
78 /**
79 * Ports open.
80 */
81 struct GNUNET_CONTAINER_MultiHashMap *ports;
82
83 /**
84 * Channels open.
85 */
86 struct GNUNET_CONTAINER_MultiHashMap32 *channels;
87
88 /**
89 * child of the next channel to create (to avoid reusing IDs often)
90 */
91 struct GNUNET_CADET_ClientChannelNumber next_ccn;
92
93 /**
94 * Configuration given by the client, in case of reconnection
95 */
96 const struct GNUNET_CONFIGURATION_Handle *cfg;
97
98 /**
99 * Task for trying to reconnect.
100 */
101 struct GNUNET_SCHEDULER_Task *reconnect_task;
102
103 /**
104 * Callback for an info task (only one active at a time).
105 */
106 union CadetInfoCB info_cb;
107
108 /**
109 * Info callback closure for @c info_cb.
110 */
111 void *info_cls;
112
113 /**
114 * Time to the next reconnect in case one reconnect fails
115 */
116 struct GNUNET_TIME_Relative reconnect_time;
117
118};
119
120
121/**
122 * Opaque handle to a channel.
123 */
124struct GNUNET_CADET_Channel
125{
126
127 /**
128 * Other end of the channel.
129 */
130 struct GNUNET_PeerIdentity peer;
131
132 /**
133 * Handle to the cadet this channel belongs to
134 */
135 struct GNUNET_CADET_Handle *cadet;
136
137 /**
138 * Channel's port, if incoming.
139 */
140 struct GNUNET_CADET_Port *incoming_port;
141
142 /**
143 * Any data the caller wants to put in here, used for the
144 * various callbacks (@e disconnects, @e window_changes, handlers).
145 */
146 void *ctx;
147
148 /**
149 * Message Queue for the channel (which we are implementing).
150 */
151 struct GNUNET_MQ_Handle *mq;
152
153 /**
154 * Task to allow mq to send more traffic.
155 */
156 struct GNUNET_SCHEDULER_Task *mq_cont;
157
158 /**
159 * Pending envelope with a message to be transmitted to the
160 * service as soon as we are allowed to. Should only be
161 * non-NULL if @e allow_send is 0.
162 */
163 struct GNUNET_MQ_Envelope *pending_env;
164
165 /**
166 * Window change handler.
167 */
168 GNUNET_CADET_WindowSizeEventHandler window_changes;
169
170 /**
171 * Disconnect handler.
172 */
173 GNUNET_CADET_DisconnectEventHandler disconnects;
174
175 /**
176 * Local ID of the channel, #GNUNET_CADET_LOCAL_CHANNEL_ID_CLI bit is set if outbound.
177 */
178 struct GNUNET_CADET_ClientChannelNumber ccn;
179
180 /**
181 * Channel options: reliability, etc.
182 */
183 enum GNUNET_CADET_ChannelOption options;
184
185 /**
186 * How many messages are we allowed to send to the service right now?
187 */
188 unsigned int allow_send;
189
190};
191
192
193/**
194 * Opaque handle to a port.
195 */
196struct GNUNET_CADET_Port
197{
198
199 /**
200 * Port "number"
201 */
202 struct GNUNET_HashCode id;
203
204 /**
205 * Handle to the CADET session this port belongs to.
206 */
207 struct GNUNET_CADET_Handle *cadet;
208
209 /**
210 * Callback handler for incoming channels on this port.
211 */
212 GNUNET_CADET_InboundChannelNotificationHandler *handler;
213
214 /**
215 * Closure for @a handler.
216 */
217 void *cls;
218
219 /**
220 * Handler for incoming channels on this port
221 */
222 GNUNET_CADET_ConnectEventHandler connects;
223
224 /**
225 * Closure for @ref connects
226 */
227 void *connects_cls;
228
229 /**
230 * Window size change handler.
231 */
232 GNUNET_CADET_WindowSizeEventHandler window_changes;
233
234 /**
235 * Handler called when an incoming channel is destroyed.
236 */
237 GNUNET_CADET_DisconnectEventHandler disconnects;
238
239 /**
240 * Payload handlers for incoming channels.
241 */
242 struct GNUNET_MQ_MessageHandler *handlers;
243};
244
245
246/**
247 * Find the Port struct for a hash.
248 *
249 * @param h CADET handle.
250 * @param hash HashCode for the port number.
251 * @return The port handle if known, NULL otherwise.
252 */
253static struct GNUNET_CADET_Port *
254find_port (const struct GNUNET_CADET_Handle *h,
255 const struct GNUNET_HashCode *hash)
256{
257 return GNUNET_CONTAINER_multihashmap_get (h->ports,
258 hash);
259}
260
261
262/**
263 * Get the channel handler for the channel specified by id from the given handle
264 *
265 * @param h Cadet handle
266 * @param ccn ID of the wanted channel
267 * @return handle to the required channel or NULL if not found
268 */
269static struct GNUNET_CADET_Channel *
270find_channel (struct GNUNET_CADET_Handle *h,
271 struct GNUNET_CADET_ClientChannelNumber ccn)
272{
273 return GNUNET_CONTAINER_multihashmap32_get (h->channels,
274 ntohl (ccn.channel_of_client));
275}
276
277
278/**
279 * Create a new channel and insert it in the channel list of the cadet handle
280 *
281 * @param h Cadet handle
282 * @param ccnp pointer to desired ccn of the channel, NULL to assign one automatically.
283 * @return Handle to the created channel.
284 */
285static struct GNUNET_CADET_Channel *
286create_channel (struct GNUNET_CADET_Handle *h,
287 const struct GNUNET_CADET_ClientChannelNumber *ccnp)
288{
289 struct GNUNET_CADET_Channel *ch;
290 struct GNUNET_CADET_ClientChannelNumber ccn;
291
292 ch = GNUNET_new (struct GNUNET_CADET_Channel);
293 ch->cadet = h;
294 if (NULL == ccnp)
295 {
296 while (NULL !=
297 find_channel (h,
298 h->next_ccn))
299 h->next_ccn.channel_of_client
300 = htonl (GNUNET_CADET_LOCAL_CHANNEL_ID_CLI | (1 + ntohl (h->next_ccn.channel_of_client)));
301 ccn = h->next_ccn;
302 }
303 else
304 {
305 ccn = *ccnp;
306 }
307 ch->ccn = ccn;
308 GNUNET_assert (GNUNET_OK ==
309 GNUNET_CONTAINER_multihashmap32_put (h->channels,
310 ntohl (ch->ccn.channel_of_client),
311 ch,
312 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
313 return ch;
314}
315
316
317/**
318 * Destroy the specified channel.
319 * - Destroys all peers, calling the disconnect callback on each if needed
320 * - Cancels all outgoing traffic for that channel, calling respective notifys
321 * - Calls cleaner if channel was inbound
322 * - Frees all memory used
323 *
324 * @param ch Pointer to the channel.
325 * @param call_cleaner Whether to call the cleaner handler.
326 */
327static void
328destroy_channel (struct GNUNET_CADET_Channel *ch)
329{
330 struct GNUNET_CADET_Handle *h = ch->cadet;
331
332 LOG (GNUNET_ERROR_TYPE_DEBUG,
333 "Destroying channel %X of %p\n",
334 ch->ccn,
335 h);
336 GNUNET_assert (GNUNET_YES ==
337 GNUNET_CONTAINER_multihashmap32_remove (h->channels,
338 ntohl (ch->ccn.channel_of_client),
339 ch));
340 if (NULL != ch->mq_cont)
341 {
342 GNUNET_SCHEDULER_cancel (ch->mq_cont);
343 ch->mq_cont = NULL;
344 }
345 /* signal channel destruction */
346 if (NULL != ch->disconnects)
347 ch->disconnects (ch->ctx,
348 ch);
349 if (NULL != ch->pending_env)
350 GNUNET_MQ_discard (ch->pending_env);
351 GNUNET_MQ_destroy (ch->mq);
352 GNUNET_free (ch);
353}
354
355
356/**
357 * Reconnect to the service, retransmit all infomation to try to restore the
358 * original state.
359 *
360 * @param h handle to the cadet
361 */
362static void
363reconnect (struct GNUNET_CADET_Handle *h);
364
365
366/**
367 * Reconnect callback: tries to reconnect again after a failer previous
368 * reconnecttion
369 *
370 * @param cls closure (cadet handle)
371 */
372static void
373reconnect_cbk (void *cls)
374{
375 struct GNUNET_CADET_Handle *h = cls;
376
377 h->reconnect_task = NULL;
378 reconnect (h);
379}
380
381
382/**
383 * Function called during #reconnect() to destroy
384 * all channels that are still open.
385 *
386 * @param cls the `struct GNUNET_CADET_Handle`
387 * @param cid chanenl ID
388 * @param value a `struct GNUNET_CADET_Channel` to destroy
389 * @return #GNUNET_OK (continue to iterate)
390 */
391static int
392destroy_channel_on_reconnect_cb (void *cls,
393 uint32_t cid,
394 void *value)
395{
396 /* struct GNUNET_CADET_Handle *handle = cls; */
397 struct GNUNET_CADET_Channel *ch = value;
398
399 destroy_channel (ch);
400 return GNUNET_OK;
401}
402
403
404/**
405 * Reconnect to the service, retransmit all infomation to try to restore the
406 * original state.
407 *
408 * @param h handle to the cadet
409 *
410 * @return #GNUNET_YES in case of sucess, #GNUNET_NO otherwise (service down...)
411 */
412static void
413schedule_reconnect (struct GNUNET_CADET_Handle *h)
414{
415 if (NULL != h->reconnect_task)
416 return;
417 GNUNET_CONTAINER_multihashmap32_iterate (h->channels,
418 &destroy_channel_on_reconnect_cb,
419 h);
420 h->reconnect_task
421 = GNUNET_SCHEDULER_add_delayed (h->reconnect_time,
422 &reconnect_cbk,
423 h);
424 h->reconnect_time
425 = GNUNET_TIME_STD_BACKOFF (h->reconnect_time);
426}
427
428
429/**
430 * Notify the application about a change in the window size (if needed).
431 *
432 * @param ch Channel to notify about.
433 */
434static void
435notify_window_size (struct GNUNET_CADET_Channel *ch)
436{
437 if (NULL != ch->window_changes)
438 ch->window_changes (ch->ctx,
439 ch, /* FIXME: remove 'ch'? */
440 ch->allow_send);
441}
442
443
444/**
445 * Transmit the next message from our queue.
446 *
447 * @param cls Closure (channel whose mq to activate).
448 */
449static void
450cadet_mq_send_now (void *cls)
451{
452 struct GNUNET_CADET_Channel *ch = cls;
453 struct GNUNET_MQ_Envelope *env = ch->pending_env;
454
455 ch->mq_cont = NULL;
456 if (0 == ch->allow_send)
457 {
458 /* how did we get here? */
459 GNUNET_break (0);
460 return;
461 }
462 if (NULL == env)
463 {
464 /* how did we get here? */
465 GNUNET_break (0);
466 return;
467 }
468 ch->allow_send--;
469 ch->pending_env = NULL;
470 GNUNET_MQ_send (ch->cadet->mq,
471 env);
472 GNUNET_MQ_impl_send_continue (ch->mq);
473}
474
475
476/**
477 * Implement sending functionality of a message queue for
478 * us sending messages to a peer.
479 *
480 * Encapsulates the payload message in a #GNUNET_CADET_LocalData message
481 * in order to label the message with the channel ID and send the
482 * encapsulated message to the service.
483 *
484 * @param mq the message queue
485 * @param msg the message to send
486 * @param impl_state state of the implementation
487 */
488static void
489cadet_mq_send_impl (struct GNUNET_MQ_Handle *mq,
490 const struct GNUNET_MessageHeader *msg,
491 void *impl_state)
492{
493 struct GNUNET_CADET_Channel *ch = impl_state;
494 struct GNUNET_CADET_Handle *h = ch->cadet;
495 uint16_t msize;
496 struct GNUNET_MQ_Envelope *env;
497 struct GNUNET_CADET_LocalData *cadet_msg;
498
499 if (NULL == h->mq)
500 {
501 /* We're currently reconnecting, pretend this worked */
502 GNUNET_MQ_impl_send_continue (mq);
503 return;
504 }
505
506 /* check message size for sanity */
507 msize = ntohs (msg->size);
508 if (msize > GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE)
509 {
510 GNUNET_break (0);
511 GNUNET_MQ_impl_send_continue (mq);
512 return;
513 }
514 env = GNUNET_MQ_msg_nested_mh (cadet_msg,
515 GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA,
516 msg);
517 cadet_msg->ccn = ch->ccn;
518 GNUNET_assert (NULL == ch->pending_env);
519 ch->pending_env = env;
520 if (0 < ch->allow_send)
521 ch->mq_cont
522 = GNUNET_SCHEDULER_add_now (&cadet_mq_send_now,
523 ch);
524}
525
526
527/**
528 * Handle destruction of a message queue. Implementations must not
529 * free @a mq, but should take care of @a impl_state.
530 *
531 * @param mq the message queue to destroy
532 * @param impl_state state of the implementation
533 */
534static void
535cadet_mq_destroy_impl (struct GNUNET_MQ_Handle *mq,
536 void *impl_state)
537{
538 struct GNUNET_CADET_Channel *ch = impl_state;
539
540 GNUNET_assert (mq == ch->mq);
541 ch->mq = NULL;
542}
543
544
545/**
546 * We had an error processing a message we forwarded from a peer to
547 * the CADET service. We should just complain about it but otherwise
548 * continue processing.
549 *
550 * @param cls closure with our `struct GNUNET_CADET_Channel`
551 * @param error error code
552 */
553static void
554cadet_mq_error_handler (void *cls,
555 enum GNUNET_MQ_Error error)
556{
557 struct GNUNET_CADET_Channel *ch = cls;
558
559 GNUNET_break (0);
560 if (GNUNET_MQ_ERROR_NO_MATCH == error)
561 {
562 /* Got a message we did not understand, still try to continue! */
563 GNUNET_CADET_receive_done (ch);
564 }
565 else
566 {
567 schedule_reconnect (ch->cadet);
568 }
569}
570
571
572/**
573 * Implementation function that cancels the currently sent message.
574 * Should basically undo whatever #mq_send_impl() did.
575 *
576 * @param mq message queue
577 * @param impl_state state specific to the implementation
578 */
579static void
580cadet_mq_cancel_impl (struct GNUNET_MQ_Handle *mq,
581 void *impl_state)
582{
583 struct GNUNET_CADET_Channel *ch = impl_state;
584
585 GNUNET_assert (NULL != ch->pending_env);
586 GNUNET_MQ_discard (ch->pending_env);
587 ch->pending_env = NULL;
588 if (NULL != ch->mq_cont)
589 {
590 GNUNET_SCHEDULER_cancel (ch->mq_cont);
591 ch->mq_cont = NULL;
592 }
593}
594
595
596/**
597 * Process the new channel notification and add it to the channels in the handle
598 *
599 * @param h The cadet handle
600 * @param msg A message with the details of the new incoming channel
601 */
602static void
603handle_channel_created (void *cls,
604 const struct GNUNET_CADET_LocalChannelCreateMessage *msg)
605{
606 struct GNUNET_CADET_Handle *h = cls;
607 struct GNUNET_CADET_Channel *ch;
608 struct GNUNET_CADET_Port *port;
609 const struct GNUNET_HashCode *port_number;
610 struct GNUNET_CADET_ClientChannelNumber ccn;
611
612 ccn = msg->ccn;
613 port_number = &msg->port;
614 if (ntohl (ccn.channel_of_client) >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
615 {
616 GNUNET_break (0);
617 return;
618 }
619 port = find_port (h,
620 port_number);
621 if (NULL == port)
622 {
623 /* We could have closed the port but the service didn't know about it yet
624 * This is not an error.
625 */
626 struct GNUNET_CADET_LocalChannelDestroyMessage *d_msg;
627 struct GNUNET_MQ_Envelope *env;
628
629 GNUNET_break (0);
630 LOG (GNUNET_ERROR_TYPE_DEBUG,
631 "No handler for incoming channel %X (on port %s, recently closed?)\n",
632 ntohl (ccn.channel_of_client),
633 GNUNET_h2s (port_number));
634 env = GNUNET_MQ_msg (d_msg,
635 GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY);
636 d_msg->ccn = msg->ccn;
637 GNUNET_MQ_send (h->mq,
638 env);
639 return;
640 }
641
642 ch = create_channel (h,
643 &ccn);
644 ch->peer = msg->peer;
645 ch->cadet = h;
646 ch->incoming_port = port;
647 ch->options = ntohl (msg->opt);
648 LOG (GNUNET_ERROR_TYPE_DEBUG,
649 "Creating incoming channel %X [%s] %p\n",
650 ntohl (ccn.channel_of_client),
651 GNUNET_h2s (port_number),
652 ch);
653
654 GNUNET_assert (NULL != port->connects);
655 ch->window_changes = port->window_changes;
656 ch->disconnects = port->disconnects;
657 ch->mq = GNUNET_MQ_queue_for_callbacks (&cadet_mq_send_impl,
658 &cadet_mq_destroy_impl,
659 &cadet_mq_cancel_impl,
660 ch,
661 port->handlers,
662 &cadet_mq_error_handler,
663 ch);
664 ch->ctx = port->connects (port->cls,
665 ch,
666 &msg->peer);
667 GNUNET_MQ_set_handlers_closure (ch->mq,
668 ch->ctx);
669}
670
671
672/**
673 * Process the channel destroy notification and free associated resources
674 *
675 * @param h The cadet handle
676 * @param msg A message with the details of the channel being destroyed
677 */
678static void
679handle_channel_destroy (void *cls,
680 const struct GNUNET_CADET_LocalChannelDestroyMessage *msg)
681{
682 struct GNUNET_CADET_Handle *h = cls;
683 struct GNUNET_CADET_Channel *ch;
684
685 LOG (GNUNET_ERROR_TYPE_DEBUG,
686 "Received channel destroy for channel %X from CADET service\n",
687 ntohl (msg->ccn.channel_of_client));
688 ch = find_channel (h,
689 msg->ccn);
690 if (NULL == ch)
691 {
692 GNUNET_break (0);
693 return;
694 }
695 destroy_channel (ch);
696}
697
698
699/**
700 * Check that message received from CADET service is well-formed.
701 *
702 * @param cls the `struct GNUNET_CADET_Handle`
703 * @param message the message we got
704 * @return #GNUNET_OK if the message is well-formed,
705 * #GNUNET_SYSERR otherwise
706 */
707static int
708check_local_data (void *cls,
709 const struct GNUNET_CADET_LocalData *message)
710{
711 struct GNUNET_CADET_Handle *h = cls;
712 struct GNUNET_CADET_Channel *ch;
713 uint16_t size;
714
715 size = ntohs (message->header.size);
716 if (sizeof (*message) + sizeof (struct GNUNET_MessageHeader) > size)
717 {
718 GNUNET_break (0);
719 return GNUNET_SYSERR;
720 }
721
722 ch = find_channel (h,
723 message->ccn);
724 if (NULL == ch)
725 {
726 GNUNET_break (0);
727 return GNUNET_SYSERR;
728 }
729
730 return GNUNET_OK;
731}
732
733
734/**
735 * Process the incoming data packets, call appropriate handlers.
736 *
737 * @param h The cadet handle
738 * @param message A message encapsulating the data
739 */
740static void
741handle_local_data (void *cls,
742 const struct GNUNET_CADET_LocalData *message)
743{
744 struct GNUNET_CADET_Handle *h = cls;
745 const struct GNUNET_MessageHeader *payload;
746 struct GNUNET_CADET_Channel *ch;
747 uint16_t type;
748 int fwd;
749
750 ch = find_channel (h,
751 message->ccn);
752 if (NULL == ch)
753 {
754 GNUNET_break (0);
755 reconnect (h);
756 return;
757 }
758
759 payload = (const struct GNUNET_MessageHeader *) &message[1];
760 type = ntohs (payload->type);
761 fwd = ntohl (ch->ccn.channel_of_client) <= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI;
762 LOG (GNUNET_ERROR_TYPE_DEBUG,
763 "Got a %s data on channel %s [%X] of type %u\n",
764 fwd ? "FWD" : "BWD",
765 GNUNET_i2s (&ch->peer),
766 ntohl (message->ccn.channel_of_client),
767 type);
768 GNUNET_MQ_inject_message (ch->mq,
769 payload);
770}
771
772
773/**
774 * Process a local ACK message, enabling the client to send
775 * more data to the service.
776 *
777 * @param h Cadet handle.
778 * @param message Message itself.
779 */
780static void
781handle_local_ack (void *cls,
782 const struct GNUNET_CADET_LocalAck *message)
783{
784 struct GNUNET_CADET_Handle *h = cls;
785 struct GNUNET_CADET_Channel *ch;
786
787 ch = find_channel (h,
788 message->ccn);
789 if (NULL == ch)
790 {
791 LOG (GNUNET_ERROR_TYPE_DEBUG,
792 "ACK on unknown channel %X\n",
793 ntohl (message->ccn.channel_of_client));
794 return;
795 }
796 ch->allow_send++;
797 if (NULL == ch->pending_env)
798 {
799 LOG (GNUNET_ERROR_TYPE_DEBUG,
800 "Got an ACK on mq channel %X, allow send now %u!\n",
801 ntohl (ch->ccn.channel_of_client),
802 ch->allow_send);
803 notify_window_size (ch);
804 return;
805 }
806 if (NULL != ch->mq_cont)
807 return; /* already working on it! */
808 LOG (GNUNET_ERROR_TYPE_DEBUG,
809 "Got an ACK on mq channel %X, sending pending message!\n",
810 ntohl (ch->ccn.channel_of_client));
811 ch->mq_cont
812 = GNUNET_SCHEDULER_add_now (&cadet_mq_send_now,
813 ch);
814}
815
816
817/**
818 * Generic error handler, called with the appropriate error code and
819 * the same closure specified at the creation of the message queue.
820 * Not every message queue implementation supports an error handler.
821 *
822 * @param cls closure, a `struct GNUNET_CORE_Handle *`
823 * @param error error code
824 */
825static void
826handle_mq_error (void *cls,
827 enum GNUNET_MQ_Error error)
828{
829 struct GNUNET_CADET_Handle *h = cls;
830
831 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
832 "MQ ERROR: %u\n",
833 error);
834 GNUNET_MQ_destroy (h->mq);
835 h->mq = NULL;
836 reconnect (h);
837}
838
839
840/**
841 * Process a local reply about info on all tunnels, pass info to the user.
842 *
843 * @param cls Closure (Cadet handle).
844 * @param msg Message itself.
845 */
846static void
847handle_get_peers (void *cls,
848 const struct GNUNET_CADET_LocalInfoPeer *msg)
849{
850 struct GNUNET_CADET_Handle *h = cls;
851
852 if (NULL == h->info_cb.peers_cb)
853 return;
854 h->info_cb.peers_cb (h->info_cls,
855 &msg->destination,
856 (int) ntohs (msg->tunnel),
857 (unsigned int) ntohs (msg->paths),
858 0);
859}
860
861
862/**
863 * Check that message received from CADET service is well-formed.
864 *
865 * @param cls the `struct GNUNET_CADET_Handle`
866 * @param message the message we got
867 * @return #GNUNET_OK if the message is well-formed,
868 * #GNUNET_SYSERR otherwise
869 */
870static int
871check_get_peer (void *cls,
872 const struct GNUNET_CADET_LocalInfoPeer *message)
873{
874 size_t msize = sizeof (struct GNUNET_CADET_LocalInfoPeer);
875 const struct GNUNET_PeerIdentity *paths_array;
876 size_t esize;
877 unsigned int epaths;
878 unsigned int paths;
879 unsigned int peers;
880
881 esize = ntohs (message->header.size);
882 if (esize < msize)
883 {
884 GNUNET_break (0);
885 return GNUNET_SYSERR;
886 }
887 if (0 != ((esize - msize) % sizeof (struct GNUNET_PeerIdentity)))
888 {
889 GNUNET_break (0);
890 return GNUNET_SYSERR;
891 }
892 peers = (esize - msize) / sizeof (struct GNUNET_PeerIdentity);
893 epaths = ntohs (message->paths);
894 paths_array = (const struct GNUNET_PeerIdentity *) &message[1];
895 paths = 0;
896 for (unsigned int i = 0; i < peers; i++)
897 if (0 == memcmp (&paths_array[i],
898 &message->destination,
899 sizeof (struct GNUNET_PeerIdentity)))
900 paths++;
901 if (paths != epaths)
902 {
903 GNUNET_break (0);
904 return GNUNET_SYSERR;
905 }
906 return GNUNET_OK;
907}
908
909
910/**
911 * Process a local peer info reply, pass info to the user.
912 *
913 * @param cls Closure (Cadet handle).
914 * @param message Message itself.
915 */
916static void
917handle_get_peer (void *cls,
918 const struct GNUNET_CADET_LocalInfoPeer *message)
919{
920 struct GNUNET_CADET_Handle *h = cls;
921 const struct GNUNET_PeerIdentity *paths_array;
922 unsigned int paths;
923 unsigned int path_length;
924 int neighbor;
925 unsigned int peers;
926
927 if (NULL == h->info_cb.peer_cb)
928 return;
929 paths = ntohs (message->paths);
930 paths_array = (const struct GNUNET_PeerIdentity *) &message[1];
931 peers = (ntohs (message->header.size) - sizeof (*message))
932 / sizeof (struct GNUNET_PeerIdentity);
933 path_length = 0;
934 neighbor = GNUNET_NO;
935
936 for (unsigned int i = 0; i < peers; i++)
937 {
938 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
939 " %s\n",
940 GNUNET_i2s (&paths_array[i]));
941 path_length++;
942 if (0 == memcmp (&paths_array[i], &message->destination,
943 sizeof (struct GNUNET_PeerIdentity)))
944 {
945 if (1 == path_length)
946 neighbor = GNUNET_YES;
947 path_length = 0;
948 }
949 }
950
951 /* Call Callback with tunnel info. */
952 paths_array = (const struct GNUNET_PeerIdentity *) &message[1];
953 h->info_cb.peer_cb (h->info_cls,
954 &message->destination,
955 (int) ntohs (message->tunnel),
956 neighbor,
957 paths,
958 paths_array);
959}
960
961
962/**
963 * Process a local reply about info on all tunnels, pass info to the user.
964 *
965 * @param cls Closure (Cadet handle).
966 * @param message Message itself.
967 */
968static void
969handle_get_tunnels (void *cls,
970 const struct GNUNET_CADET_LocalInfoTunnel *msg)
971{
972 struct GNUNET_CADET_Handle *h = cls;
973
974 if (NULL == h->info_cb.tunnels_cb)
975 return;
976 h->info_cb.tunnels_cb (h->info_cls,
977 &msg->destination,
978 ntohl (msg->channels),
979 ntohl (msg->connections),
980 ntohs (msg->estate),
981 ntohs (msg->cstate));
982
983}
984
985
986/**
987 * Check that message received from CADET service is well-formed.
988 *
989 * @param cls the `struct GNUNET_CADET_Handle`
990 * @param msg the message we got
991 * @return #GNUNET_OK if the message is well-formed,
992 * #GNUNET_SYSERR otherwise
993 */
994static int
995check_get_tunnel (void *cls,
996 const struct GNUNET_CADET_LocalInfoTunnel *msg)
997{
998 unsigned int ch_n;
999 unsigned int c_n;
1000 size_t esize;
1001 size_t msize;
1002
1003 /* Verify message sanity */
1004 msize = ntohs (msg->header.size);
1005 esize = sizeof (struct GNUNET_CADET_LocalInfoTunnel);
1006 if (esize > msize)
1007 {
1008 GNUNET_break (0);
1009 return GNUNET_SYSERR;
1010 }
1011 ch_n = ntohl (msg->channels);
1012 c_n = ntohl (msg->connections);
1013 esize += ch_n * sizeof (struct GNUNET_CADET_ChannelTunnelNumber);
1014 esize += c_n * sizeof (struct GNUNET_CADET_ConnectionTunnelIdentifier);
1015 if (msize != esize)
1016 {
1017 GNUNET_break_op (0);
1018 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1019 "m:%u, e: %u (%u ch, %u conn)\n",
1020 (unsigned int) msize,
1021 (unsigned int) esize,
1022 ch_n,
1023 c_n);
1024 return GNUNET_SYSERR;
1025 }
1026 return GNUNET_OK;
1027}
1028
1029
1030/**
1031 * Process a local tunnel info reply, pass info to the user.
1032 *
1033 * @param cls Closure (Cadet handle).
1034 * @param msg Message itself.
1035 */
1036static void
1037handle_get_tunnel (void *cls,
1038 const struct GNUNET_CADET_LocalInfoTunnel *msg)
1039{
1040 struct GNUNET_CADET_Handle *h = cls;
1041 unsigned int ch_n;
1042 unsigned int c_n;
1043 const struct GNUNET_CADET_ConnectionTunnelIdentifier *conns;
1044 const struct GNUNET_CADET_ChannelTunnelNumber *chns;
1045
1046 if (NULL == h->info_cb.tunnel_cb)
1047 return;
1048
1049 ch_n = ntohl (msg->channels);
1050 c_n = ntohl (msg->connections);
1051
1052 /* Call Callback with tunnel info. */
1053 conns = (const struct GNUNET_CADET_ConnectionTunnelIdentifier *) &msg[1];
1054 chns = (const struct GNUNET_CADET_ChannelTunnelNumber *) &conns[c_n];
1055 h->info_cb.tunnel_cb (h->info_cls,
1056 &msg->destination,
1057 ch_n,
1058 c_n,
1059 chns,
1060 conns,
1061 ntohs (msg->estate),
1062 ntohs (msg->cstate));
1063}
1064
1065
1066/**
1067 * Reconnect to the service, retransmit all infomation to try to restore the
1068 * original state.
1069 *
1070 * @param h handle to the cadet
1071 */
1072static void
1073reconnect (struct GNUNET_CADET_Handle *h)
1074{
1075 struct GNUNET_MQ_MessageHandler handlers[] = {
1076 GNUNET_MQ_hd_fixed_size (channel_created,
1077 GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_CREATE,
1078 struct GNUNET_CADET_LocalChannelCreateMessage,
1079 h),
1080 GNUNET_MQ_hd_fixed_size (channel_destroy,
1081 GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY,
1082 struct GNUNET_CADET_LocalChannelDestroyMessage,
1083 h),
1084 GNUNET_MQ_hd_var_size (local_data,
1085 GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA,
1086 struct GNUNET_CADET_LocalData,
1087 h),
1088 GNUNET_MQ_hd_fixed_size (local_ack,
1089 GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK,
1090 struct GNUNET_CADET_LocalAck,
1091 h),
1092 GNUNET_MQ_hd_fixed_size (get_peers,
1093 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS,
1094 struct GNUNET_CADET_LocalInfoPeer,
1095 h),
1096 GNUNET_MQ_hd_var_size (get_peer,
1097 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER,
1098 struct GNUNET_CADET_LocalInfoPeer,
1099 h),
1100 GNUNET_MQ_hd_fixed_size (get_tunnels,
1101 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS,
1102 struct GNUNET_CADET_LocalInfoTunnel,
1103 h),
1104 GNUNET_MQ_hd_var_size (get_tunnel,
1105 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL,
1106 struct GNUNET_CADET_LocalInfoTunnel,
1107 h),
1108 GNUNET_MQ_handler_end ()
1109 };
1110
1111 h->mq = GNUNET_CLIENT_connect (h->cfg,
1112 "cadet",
1113 handlers,
1114 &handle_mq_error,
1115 h);
1116 if (NULL == h->mq)
1117 {
1118 schedule_reconnect (h);
1119 return;
1120 }
1121 h->reconnect_time = GNUNET_TIME_UNIT_MILLISECONDS;
1122}
1123
1124
1125/**
1126 * Function called during #GNUNET_CADET_disconnect() to destroy
1127 * all channels that are still open.
1128 *
1129 * @param cls the `struct GNUNET_CADET_Handle`
1130 * @param cid chanenl ID
1131 * @param value a `struct GNUNET_CADET_Channel` to destroy
1132 * @return #GNUNET_OK (continue to iterate)
1133 */
1134static int
1135destroy_channel_cb (void *cls,
1136 uint32_t cid,
1137 void *value)
1138{
1139 /* struct GNUNET_CADET_Handle *handle = cls; */
1140 struct GNUNET_CADET_Channel *ch = value;
1141
1142 if (ntohl (ch->ccn.channel_of_client) >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
1143 {
1144 GNUNET_break (0);
1145 LOG (GNUNET_ERROR_TYPE_DEBUG,
1146 "channel %X not destroyed\n",
1147 ntohl (ch->ccn.channel_of_client));
1148 }
1149 destroy_channel (ch);
1150 return GNUNET_OK;
1151}
1152
1153
1154/**
1155 * Function called during #GNUNET_CADET_disconnect() to destroy
1156 * all ports that are still open.
1157 *
1158 * @param cls the `struct GNUNET_CADET_Handle`
1159 * @param id port ID
1160 * @param value a `struct GNUNET_CADET_Channel` to destroy
1161 * @return #GNUNET_OK (continue to iterate)
1162 */
1163static int
1164destroy_port_cb (void *cls,
1165 const struct GNUNET_HashCode *id,
1166 void *value)
1167{
1168 /* struct GNUNET_CADET_Handle *handle = cls; */
1169 struct GNUNET_CADET_Port *port = value;
1170
1171 /* This is a warning, the app should have cleanly closed all open ports */
1172 GNUNET_break (0);
1173 GNUNET_CADET_close_port (port);
1174 return GNUNET_OK;
1175}
1176
1177
1178/**
1179 * Disconnect from the cadet service. All channels will be destroyed. All channel
1180 * disconnect callbacks will be called on any still connected peers, notifying
1181 * about their disconnection. The registered inbound channel cleaner will be
1182 * called should any inbound channels still exist.
1183 *
1184 * @param handle connection to cadet to disconnect
1185 */
1186void
1187GNUNET_CADET_disconnect (struct GNUNET_CADET_Handle *handle)
1188{
1189 GNUNET_CONTAINER_multihashmap_iterate (handle->ports,
1190 &destroy_port_cb,
1191 handle);
1192 GNUNET_CONTAINER_multihashmap_destroy (handle->ports);
1193 handle->ports = NULL;
1194 GNUNET_CONTAINER_multihashmap32_iterate (handle->channels,
1195 &destroy_channel_cb,
1196 handle);
1197 GNUNET_CONTAINER_multihashmap32_destroy (handle->channels);
1198 handle->channels = NULL;
1199 if (NULL != handle->mq)
1200 {
1201 GNUNET_MQ_destroy (handle->mq);
1202 handle->mq = NULL;
1203 }
1204 if (NULL != handle->reconnect_task)
1205 {
1206 GNUNET_SCHEDULER_cancel (handle->reconnect_task);
1207 handle->reconnect_task = NULL;
1208 }
1209 GNUNET_free (handle);
1210}
1211
1212
1213/**
1214 * Close a port opened with @a GNUNET_CADET_open_port().
1215 * The @a new_channel callback will no longer be called.
1216 *
1217 * @param p Port handle.
1218 */
1219void
1220GNUNET_CADET_close_port (struct GNUNET_CADET_Port *p)
1221{
1222 struct GNUNET_CADET_PortMessage *msg;
1223 struct GNUNET_MQ_Envelope *env;
1224
1225 env = GNUNET_MQ_msg (msg,
1226 GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_CLOSE);
1227 msg->port = p->id;
1228 GNUNET_MQ_send (p->cadet->mq,
1229 env);
1230 GNUNET_assert (GNUNET_YES ==
1231 GNUNET_CONTAINER_multihashmap_remove (p->cadet->ports,
1232 &p->id,
1233 p));
1234 GNUNET_free_non_null (p->handlers);
1235 GNUNET_free (p);
1236}
1237
1238
1239/**
1240 * Destroy an existing channel.
1241 *
1242 * The existing end callback for the channel will be called immediately.
1243 * Any pending outgoing messages will be sent but no incoming messages will be
1244 * accepted and no data callbacks will be called.
1245 *
1246 * @param channel Channel handle, becomes invalid after this call.
1247 */
1248void
1249GNUNET_CADET_channel_destroy (struct GNUNET_CADET_Channel *channel)
1250{
1251 struct GNUNET_CADET_Handle *h = channel->cadet;
1252 struct GNUNET_CADET_LocalChannelDestroyMessage *msg;
1253 struct GNUNET_MQ_Envelope *env;
1254
1255 if (NULL != h->mq)
1256 {
1257 env = GNUNET_MQ_msg (msg,
1258 GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY);
1259 msg->ccn = channel->ccn;
1260 GNUNET_MQ_send (h->mq,
1261 env);
1262 }
1263 destroy_channel (channel);
1264}
1265
1266
1267/**
1268 * Get information about a channel.
1269 *
1270 * @param channel Channel handle.
1271 * @param option Query (GNUNET_CADET_OPTION_*).
1272 * @param ... dependant on option, currently not used
1273 *
1274 * @return Union with an answer to the query.
1275 */
1276const union GNUNET_CADET_ChannelInfo *
1277GNUNET_CADET_channel_get_info (struct GNUNET_CADET_Channel *channel,
1278 enum GNUNET_CADET_ChannelOption option,
1279 ...)
1280{
1281 static int bool_flag;
1282
1283 switch (option)
1284 {
1285 case GNUNET_CADET_OPTION_NOBUFFER:
1286 case GNUNET_CADET_OPTION_RELIABLE:
1287 case GNUNET_CADET_OPTION_OUT_OF_ORDER:
1288 if (0 != (option & channel->options))
1289 bool_flag = GNUNET_YES;
1290 else
1291 bool_flag = GNUNET_NO;
1292 return (const union GNUNET_CADET_ChannelInfo *) &bool_flag;
1293 break;
1294 case GNUNET_CADET_OPTION_PEER:
1295 return (const union GNUNET_CADET_ChannelInfo *) &channel->peer;
1296 break;
1297 default:
1298 GNUNET_break (0);
1299 return NULL;
1300 }
1301}
1302
1303
1304/**
1305 * Send an ack on the channel to confirm the processing of a message.
1306 *
1307 * @param ch Channel on which to send the ACK.
1308 */
1309void
1310GNUNET_CADET_receive_done (struct GNUNET_CADET_Channel *channel)
1311{
1312 struct GNUNET_CADET_LocalAck *msg;
1313 struct GNUNET_MQ_Envelope *env;
1314
1315 env = GNUNET_MQ_msg (msg,
1316 GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK);
1317 LOG (GNUNET_ERROR_TYPE_DEBUG,
1318 "Sending ACK on channel %X\n",
1319 ntohl (channel->ccn.channel_of_client));
1320 msg->ccn = channel->ccn;
1321 GNUNET_MQ_send (channel->cadet->mq,
1322 env);
1323}
1324
1325
1326/**
1327 * Send message of @a type to CADET service of @a h
1328 *
1329 * @param h handle to CADET service
1330 * @param type message type of trivial information request to send
1331 */
1332static void
1333send_info_request (struct GNUNET_CADET_Handle *h,
1334 uint16_t type)
1335{
1336 struct GNUNET_MessageHeader *msg;
1337 struct GNUNET_MQ_Envelope *env;
1338
1339 env = GNUNET_MQ_msg (msg,
1340 type);
1341 GNUNET_MQ_send (h->mq,
1342 env);
1343}
1344
1345
1346/**
1347 * Request a debug dump on the service's STDERR.
1348 *
1349 * WARNING: unstable API, likely to change in the future!
1350 *
1351 * @param h cadet handle
1352 */
1353void
1354GNUNET_CADET_request_dump (struct GNUNET_CADET_Handle *h)
1355{
1356 send_info_request (h,
1357 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_DUMP);
1358}
1359
1360
1361/**
1362 * Request information about peers known to the running cadet service.
1363 * The callback will be called for every peer known to the service.
1364 * Only one info request (of any kind) can be active at once.
1365 *
1366 * WARNING: unstable API, likely to change in the future!
1367 *
1368 * @param h Handle to the cadet peer.
1369 * @param callback Function to call with the requested data.
1370 * @param callback_cls Closure for @c callback.
1371 * @return #GNUNET_OK / #GNUNET_SYSERR
1372 */
1373int
1374GNUNET_CADET_get_peers (struct GNUNET_CADET_Handle *h,
1375 GNUNET_CADET_PeersCB callback,
1376 void *callback_cls)
1377{
1378 if (NULL != h->info_cb.peers_cb)
1379 {
1380 GNUNET_break (0);
1381 return GNUNET_SYSERR;
1382 }
1383 send_info_request (h,
1384 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS);
1385 h->info_cb.peers_cb = callback;
1386 h->info_cls = callback_cls;
1387 return GNUNET_OK;
1388}
1389
1390
1391/**
1392 * Cancel a peer info request. The callback will not be called (anymore).
1393 *
1394 * WARNING: unstable API, likely to change in the future!
1395 *
1396 * @param h Cadet handle.
1397 * @return Closure given to GNUNET_CADET_get_peers().
1398 */
1399void *
1400GNUNET_CADET_get_peers_cancel (struct GNUNET_CADET_Handle *h)
1401{
1402 void *cls = h->info_cls;
1403
1404 h->info_cb.peers_cb = NULL;
1405 h->info_cls = NULL;
1406 return cls;
1407}
1408
1409
1410/**
1411 * Request information about a peer known to the running cadet peer.
1412 * The callback will be called for the tunnel once.
1413 * Only one info request (of any kind) can be active at once.
1414 *
1415 * WARNING: unstable API, likely to change in the future!
1416 *
1417 * @param h Handle to the cadet peer.
1418 * @param id Peer whose tunnel to examine.
1419 * @param callback Function to call with the requested data.
1420 * @param callback_cls Closure for @c callback.
1421 * @return #GNUNET_OK / #GNUNET_SYSERR
1422 */
1423int
1424GNUNET_CADET_get_peer (struct GNUNET_CADET_Handle *h,
1425 const struct GNUNET_PeerIdentity *id,
1426 GNUNET_CADET_PeerCB callback,
1427 void *callback_cls)
1428{
1429 struct GNUNET_CADET_LocalInfo *msg;
1430 struct GNUNET_MQ_Envelope *env;
1431
1432 if (NULL != h->info_cb.peer_cb)
1433 {
1434 GNUNET_break (0);
1435 return GNUNET_SYSERR;
1436 }
1437 env = GNUNET_MQ_msg (msg,
1438 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER);
1439 msg->peer = *id;
1440 GNUNET_MQ_send (h->mq,
1441 env);
1442 h->info_cb.peer_cb = callback;
1443 h->info_cls = callback_cls;
1444 return GNUNET_OK;
1445}
1446
1447
1448/**
1449 * Request information about tunnels of the running cadet peer.
1450 * The callback will be called for every tunnel of the service.
1451 * Only one info request (of any kind) can be active at once.
1452 *
1453 * WARNING: unstable API, likely to change in the future!
1454 *
1455 * @param h Handle to the cadet peer.
1456 * @param callback Function to call with the requested data.
1457 * @param callback_cls Closure for @c callback.
1458 * @return #GNUNET_OK / #GNUNET_SYSERR
1459 */
1460int
1461GNUNET_CADET_get_tunnels (struct GNUNET_CADET_Handle *h,
1462 GNUNET_CADET_TunnelsCB callback,
1463 void *callback_cls)
1464{
1465 if (NULL != h->info_cb.tunnels_cb)
1466 {
1467 GNUNET_break (0);
1468 return GNUNET_SYSERR;
1469 }
1470 send_info_request (h,
1471 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS);
1472 h->info_cb.tunnels_cb = callback;
1473 h->info_cls = callback_cls;
1474 return GNUNET_OK;
1475}
1476
1477
1478/**
1479 * Cancel a monitor request. The monitor callback will not be called.
1480 *
1481 * @param h Cadet handle.
1482 * @return Closure given to GNUNET_CADET_get_tunnels().
1483 */
1484void *
1485GNUNET_CADET_get_tunnels_cancel (struct GNUNET_CADET_Handle *h)
1486{
1487 void *cls = h->info_cls;
1488
1489 h->info_cb.tunnels_cb = NULL;
1490 h->info_cls = NULL;
1491 return cls;
1492}
1493
1494
1495/**
1496 * Request information about a tunnel of the running cadet peer.
1497 * The callback will be called for the tunnel once.
1498 * Only one info request (of any kind) can be active at once.
1499 *
1500 * WARNING: unstable API, likely to change in the future!
1501 *
1502 * @param h Handle to the cadet peer.
1503 * @param id Peer whose tunnel to examine.
1504 * @param callback Function to call with the requested data.
1505 * @param callback_cls Closure for @c callback.
1506 * @return #GNUNET_OK / #GNUNET_SYSERR
1507 */
1508int
1509GNUNET_CADET_get_tunnel (struct GNUNET_CADET_Handle *h,
1510 const struct GNUNET_PeerIdentity *id,
1511 GNUNET_CADET_TunnelCB callback,
1512 void *callback_cls)
1513{
1514 struct GNUNET_CADET_LocalInfo *msg;
1515 struct GNUNET_MQ_Envelope *env;
1516
1517 if (NULL != h->info_cb.tunnel_cb)
1518 {
1519 GNUNET_break (0);
1520 return GNUNET_SYSERR;
1521 }
1522 env = GNUNET_MQ_msg (msg,
1523 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL);
1524 msg->peer = *id;
1525 GNUNET_MQ_send (h->mq,
1526 env);
1527 h->info_cb.tunnel_cb = callback;
1528 h->info_cls = callback_cls;
1529 return GNUNET_OK;
1530}
1531
1532
1533/**
1534 * Transitional function to convert an unsigned int port to a hash value.
1535 * WARNING: local static value returned, NOT reentrant!
1536 * WARNING: do not use this function for new code!
1537 *
1538 * @param port Numerical port (unsigned int format).
1539 *
1540 * @return A GNUNET_HashCode usable for the new CADET API.
1541 */
1542const struct GNUNET_HashCode *
1543GC_u2h (uint32_t port)
1544{
1545 static struct GNUNET_HashCode hash;
1546
1547 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1548 "This is a transitional function, use proper crypto hashes as CADET ports\n");
1549 GNUNET_CRYPTO_hash (&port,
1550 sizeof (port),
1551 &hash);
1552 return &hash;
1553}
1554
1555
1556/**
1557 * Connect to the MQ-based cadet service.
1558 *
1559 * @param cfg Configuration to use.
1560 *
1561 * @return Handle to the cadet service NULL on error.
1562 */
1563struct GNUNET_CADET_Handle *
1564GNUNET_CADET_connecT (const struct GNUNET_CONFIGURATION_Handle *cfg)
1565{
1566 struct GNUNET_CADET_Handle *h;
1567
1568 LOG (GNUNET_ERROR_TYPE_DEBUG,
1569 "GNUNET_CADET_connecT()\n");
1570 h = GNUNET_new (struct GNUNET_CADET_Handle);
1571 h->cfg = cfg;
1572 h->ports = GNUNET_CONTAINER_multihashmap_create (4,
1573 GNUNET_YES);
1574 h->channels = GNUNET_CONTAINER_multihashmap32_create (4);
1575 reconnect (h);
1576 if (NULL == h->mq)
1577 {
1578 GNUNET_break (0);
1579 GNUNET_CADET_disconnect (h);
1580 return NULL;
1581 }
1582 h->next_ccn.channel_of_client = htonl (GNUNET_CADET_LOCAL_CHANNEL_ID_CLI);
1583 h->reconnect_time = GNUNET_TIME_UNIT_MILLISECONDS;
1584 h->reconnect_task = NULL;
1585
1586 return h;
1587}
1588
1589
1590/**
1591 * Open a port to receive incomming MQ-based channels.
1592 *
1593 * @param h CADET handle.
1594 * @param port Hash identifying the port.
1595 * @param connects Function called when an incoming channel is connected.
1596 * @param connects_cls Closure for the @a connects handler.
1597 * @param window_changes Function called when the transmit window size changes.
1598 * @param disconnects Function called when a channel is disconnected.
1599 * @param handlers Callbacks for messages we care about, NULL-terminated.
1600 * @return Port handle.
1601 */
1602struct GNUNET_CADET_Port *
1603GNUNET_CADET_open_porT (struct GNUNET_CADET_Handle *h,
1604 const struct GNUNET_HashCode *port,
1605 GNUNET_CADET_ConnectEventHandler connects,
1606 void * connects_cls,
1607 GNUNET_CADET_WindowSizeEventHandler window_changes,
1608 GNUNET_CADET_DisconnectEventHandler disconnects,
1609 const struct GNUNET_MQ_MessageHandler *handlers)
1610{
1611 struct GNUNET_CADET_PortMessage *msg;
1612 struct GNUNET_MQ_Envelope *env;
1613 struct GNUNET_CADET_Port *p;
1614
1615 GNUNET_assert (NULL != connects);
1616 GNUNET_assert (NULL != disconnects);
1617
1618 p = GNUNET_new (struct GNUNET_CADET_Port);
1619 p->cadet = h;
1620 p->id = *port;
1621 p->connects = connects;
1622 p->cls = connects_cls;
1623 p->window_changes = window_changes;
1624 p->disconnects = disconnects;
1625 p->handlers = GNUNET_MQ_copy_handlers (handlers);
1626
1627 GNUNET_assert (GNUNET_OK ==
1628 GNUNET_CONTAINER_multihashmap_put (h->ports,
1629 &p->id,
1630 p,
1631 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1632
1633 env = GNUNET_MQ_msg (msg,
1634 GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_OPEN);
1635 msg->port = p->id;
1636 GNUNET_MQ_send (h->mq,
1637 env);
1638 return p;
1639}
1640
1641
1642/**
1643 * Create a new channel towards a remote peer.
1644 *
1645 * If the destination port is not open by any peer or the destination peer
1646 * does not accept the channel, #GNUNET_CADET_ChannelEndHandler will be called
1647 * for this channel.
1648 *
1649 * @param h CADET handle.
1650 * @param channel_cls Closure for the channel. It's given to:
1651 * - The disconnect handler @a disconnects
1652 * - Each message type callback in @a handlers
1653 * @param destination Peer identity the channel should go to.
1654 * @param port Identification of the destination port.
1655 * @param options CadetOption flag field, with all desired option bits set to 1.
1656 * @param window_changes Function called when the transmit window size changes.
1657 * @param disconnects Function called when the channel is disconnected.
1658 * @param handlers Callbacks for messages we care about, NULL-terminated.
1659 * @return Handle to the channel.
1660 */
1661struct GNUNET_CADET_Channel *
1662GNUNET_CADET_channel_creatE (struct GNUNET_CADET_Handle *h,
1663 void *channel_cls,
1664 const struct GNUNET_PeerIdentity *destination,
1665 const struct GNUNET_HashCode *port,
1666 enum GNUNET_CADET_ChannelOption options,
1667 GNUNET_CADET_WindowSizeEventHandler window_changes,
1668 GNUNET_CADET_DisconnectEventHandler disconnects,
1669 const struct GNUNET_MQ_MessageHandler *handlers)
1670{
1671 struct GNUNET_CADET_Channel *ch;
1672 struct GNUNET_CADET_LocalChannelCreateMessage *msg;
1673 struct GNUNET_MQ_Envelope *env;
1674
1675 GNUNET_assert (NULL != disconnects);
1676 ch = create_channel (h,
1677 NULL);
1678 ch->ctx = channel_cls;
1679 ch->peer = *destination;
1680 ch->options = options;
1681 ch->window_changes = window_changes;
1682 ch->disconnects = disconnects;
1683
1684 /* Create MQ for channel */
1685 ch->mq = GNUNET_MQ_queue_for_callbacks (&cadet_mq_send_impl,
1686 &cadet_mq_destroy_impl,
1687 &cadet_mq_cancel_impl,
1688 ch,
1689 handlers,
1690 &cadet_mq_error_handler,
1691 ch);
1692 GNUNET_MQ_set_handlers_closure (ch->mq, channel_cls);
1693
1694 /* Request channel creation to service */
1695 env = GNUNET_MQ_msg (msg,
1696 GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_CREATE);
1697 msg->ccn = ch->ccn;
1698 msg->port = *port;
1699 msg->peer = *destination;
1700 msg->opt = htonl (options);
1701 GNUNET_MQ_send (h->mq,
1702 env);
1703 return ch;
1704}
1705
1706
1707/**
1708 * Obtain the message queue for a connected peer.
1709 *
1710 * @param channel The channel handle from which to get the MQ.
1711 *
1712 * @return NULL if @a channel is not yet connected.
1713 */
1714struct GNUNET_MQ_Handle *
1715GNUNET_CADET_get_mq (const struct GNUNET_CADET_Channel *channel)
1716{
1717 return channel->mq;
1718}
1719
1720/* end of cadet_api.c */
diff --git a/src/cadet/cadet_common.c b/src/cadet/cadet_common.c
deleted file mode 100644
index 95a3144e4..000000000
--- a/src/cadet/cadet_common.c
+++ /dev/null
@@ -1,370 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21/**
22 * @file cadet/cadet_common.c
23 * @brief CADET helper functions
24 * @author Bartlomiej Polot
25 */
26
27#include "cadet.h"
28
29/**
30 * @brief Translate a fwd variable into a string representation, for logging.
31 *
32 * @param fwd Is FWD? (#GNUNET_YES or #GNUNET_NO)
33 *
34 * @return String representing FWD or BCK.
35 */
36char *
37GC_f2s (int fwd)
38{
39 if (GNUNET_YES == fwd)
40 {
41 return "FWD";
42 }
43 else if (GNUNET_NO == fwd)
44 {
45 return "BCK";
46 }
47 else
48 {
49 /* Not an error, can happen with CONNECTION_BROKEN messages. */
50 return "\???";
51 }
52}
53
54
55/**
56 * Test if @a bigger is larger than @a smaller.
57 * Considers the case that @a bigger just overflowed
58 * and is thus tiny while @a smaller is still below
59 * `UINT32_MAX`.
60 */
61int
62GC_is_pid_bigger (uint32_t bigger,
63 uint32_t smaller)
64{
65 return (PID_OVERFLOW (smaller, bigger) ||
66 ( (bigger > smaller) &&
67 (! PID_OVERFLOW (bigger, smaller))) );
68}
69
70
71uint32_t
72GC_max_pid (uint32_t a, uint32_t b)
73{
74 if (GC_is_pid_bigger(a, b))
75 return a;
76 return b;
77}
78
79
80uint32_t
81GC_min_pid (uint32_t a, uint32_t b)
82{
83 if (GC_is_pid_bigger(a, b))
84 return b;
85 return a;
86}
87
88
89/**
90 * Allocate a string with a hexdump of any binary data.
91 *
92 * @param bin Arbitrary binary data.
93 * @param len Length of @a bin in bytes.
94 * @param output Where to write the output (if *output be NULL it's allocated).
95 *
96 * @return The size of the output.
97 */
98size_t
99GC_bin2s (void *bin, unsigned int len, char **output)
100{
101 char *data = bin;
102 char *buf;
103 unsigned int s_len;
104 unsigned int i;
105
106 s_len = 2 * len + 1;
107 if (NULL == *output)
108 *output = GNUNET_malloc (s_len);
109 buf = *output;
110
111 for (i = 0; i < len; i++)
112 {
113 SPRINTF (&buf[2 * i], "%2X", data[i]);
114 }
115 buf[s_len - 1] = '\0';
116
117 return s_len;
118}
119
120
121#if !defined(GNUNET_CULL_LOGGING)
122const char *
123GC_m2s (uint16_t m)
124{
125 static char buf[2][16];
126 static int idx;
127 const char *s;
128
129 idx = (idx + 1) % 2;
130 switch (m)
131 {
132 /**
133 * Used to mark the "payload" of a non-payload message.
134 */
135 case 0:
136 s = "retransmit";
137 break;
138
139 /**
140 * Request the creation of a path
141 */
142 case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE:
143 s = "CONN_CREAT";
144 break;
145
146 /**
147 * Request the modification of an existing path
148 */
149 case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK:
150 s = "CONN_ACK";
151 break;
152
153 /**
154 * Notify that a connection of a path is no longer valid
155 */
156 case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN:
157 s = "CONN_BRKN";
158 break;
159
160 /**
161 * At some point, the route will spontaneously change
162 */
163 case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_PATH_CHANGED_UNIMPLEMENTED:
164 s = "PATH_CHNGD";
165 break;
166
167 /**
168 * Transport payload data.
169 */
170 case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA:
171 s = "DATA";
172 break;
173
174 /**
175 * Confirm receipt of payload data.
176 */
177 case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK:
178 s = "DATA_ACK";
179 break;
180
181 /**
182 * Key exchange message.
183 */
184 case GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX:
185 s = "KX";
186 break;
187
188 /**
189 * Encrypted.
190 */
191 case GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED:
192 s = "ENCRYPTED";
193 break;
194
195 /**
196 * Request the destuction of a path
197 */
198 case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY:
199 s = "CONN_DSTRY";
200 break;
201
202 /**
203 * ACK for a data packet.
204 */
205 case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_HOP_BY_HOP_ENCRYPTED_ACK:
206 s = "ACK";
207 break;
208
209 /**
210 * POLL for ACK.
211 */
212 case GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED_POLL:
213 s = "POLL";
214 break;
215
216 /**
217 * Announce origin is still alive.
218 */
219 case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE:
220 s = "KEEPALIVE";
221 break;
222
223 /**
224 * Open port
225 */
226 case GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_OPEN:
227 s = "OPEN_PORT";
228 break;
229
230 /**
231 * Close port
232 */
233 case GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_CLOSE:
234 s = "CLOSE_PORT";
235 break;
236
237 /**
238 * Ask the cadet service to create a new tunnel
239 */
240 case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN:
241 s = "CHAN_CREAT";
242 break;
243
244 /**
245 * Ask the cadet service to destroy a tunnel
246 */
247 case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY:
248 s = "CHAN_DSTRY";
249 break;
250
251 /**
252 * Confirm the creation of a channel.
253 */
254 case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK:
255 s = "CHAN_ACK";
256 break;
257
258 /**
259 * Confirm the creation of a channel.
260 */
261 case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_NACK_DEPRECATED:
262 s = "CHAN_NACK";
263 break;
264
265 /**
266 * Local payload traffic
267 */
268 case GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA:
269 s = "LOC_DATA";
270 break;
271
272 /**
273 * Local ACK for data.
274 */
275 case GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK:
276 s = "LOC_ACK";
277 break;
278
279 /**
280 * Local monitoring of channels.
281 */
282 case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CHANNELS:
283 s = "INFO_CHANS";
284 break;
285
286 /**
287 * Local monitoring of a channel.
288 */
289 case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CHANNEL:
290 s = "INFO_CHAN";
291 break;
292
293 /**
294 * Local monitoring of service.
295 */
296 case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS:
297 s = "INFO_TUNS";
298 break;
299
300 /**
301 * Local monitoring of service.
302 */
303 case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL:
304 s = "INFO_TUN";
305 break;
306
307 /**
308 * Local information about all connections of service.
309 */
310 case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CONNECTIONS:
311 s = "INFO_CONNS";
312 break;
313
314 /**
315 * Local information of service about a specific connection.
316 */
317 case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CONNECTION:
318 s = "INFO_CONN";
319 break;
320
321 /**
322 * Local information about all peers known to the service.
323 */
324 case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS:
325 s = "INFO_PEERS";
326 break;
327
328 /**
329 * Local information of service about a specific peer.
330 */
331 case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER:
332 s = "INFO_PEER";
333 break;
334
335 /**
336 * Traffic (net-cat style) used by the Command Line Interface.
337 */
338 case GNUNET_MESSAGE_TYPE_CADET_CLI:
339 s = "CLI";
340 break;
341
342 /**
343 * Debug request.
344 */
345 case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_DUMP:
346 s = "INFO_DUMP";
347 break;
348
349 /**
350 * Used to mark the "payload" of a non-payload message.
351 */
352 case UINT16_MAX:
353 s = " N/A";
354 break;
355
356
357 default:
358 SPRINTF (buf[idx], "{UNK: %5u}", m);
359 return buf[idx];
360 }
361 SPRINTF (buf[idx], "{%10s}", s);
362 return buf[idx];
363}
364#else
365const char *
366GC_m2s (uint16_t m)
367{
368 return "";
369}
370#endif
diff --git a/src/cadet/cadet_path.c b/src/cadet/cadet_path.c
deleted file mode 100644
index 79a498805..000000000
--- a/src/cadet/cadet_path.c
+++ /dev/null
@@ -1,363 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2001 - 2013 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21/**
22 * @file cadet/cadet_path.c
23 * @brief Path handling functions
24 * @author Bartlomiej Polot
25 */
26
27#include "cadet.h"
28#include "cadet_path.h"
29#include "gnunet-service-cadet_peer.h"
30
31#define LOG(level, ...) GNUNET_log_from (level,"cadet-pth",__VA_ARGS__)
32
33
34/**
35 * @brief Destroy a path after some time has past.
36 * Removes the path from the peer (must not be used for direct paths).
37 *
38 * @param cls Closure (path to destroy).
39 */
40static void
41path_destroy_delayed (void *cls)
42{
43 struct CadetPeerPath *path = cls;
44 struct CadetPeer *peer;
45
46 path->path_delete = NULL;
47 LOG (GNUNET_ERROR_TYPE_DEBUG,
48 "Destroy delayed %p (%u)\n",
49 path,
50 path->length);
51 GNUNET_assert (2 < path->length);
52 peer = GCP_get_short (path->peers[path->length - 1],
53 GNUNET_NO);
54 GNUNET_assert (NULL != peer);
55 GCP_remove_path (peer, path);
56}
57
58
59/**
60 * Create a new path
61 *
62 * @param length How many hops will the path have.
63 * @return A newly allocated path with a peer array of the specified length.
64 */
65struct CadetPeerPath *
66path_new (unsigned int length)
67{
68 struct CadetPeerPath *p;
69
70 p = GNUNET_new (struct CadetPeerPath);
71 if (length > 0)
72 {
73 p->length = length;
74 p->peers = GNUNET_malloc (length * sizeof (GNUNET_PEER_Id));
75 }
76 LOG (GNUNET_ERROR_TYPE_DEBUG, "New path %p (%u)\n", p, p->length);
77 return p;
78}
79
80
81/**
82 * Invert the path
83 *
84 * @param path the path to invert
85 */
86void
87path_invert (struct CadetPeerPath *path)
88{
89 GNUNET_PEER_Id aux;
90 unsigned int i;
91
92 for (i = 0; i < path->length / 2; i++)
93 {
94 aux = path->peers[i];
95 path->peers[i] = path->peers[path->length - i - 1];
96 path->peers[path->length - i - 1] = aux;
97 }
98}
99
100
101/**
102 * Duplicate a path, incrementing short peer's rc.
103 *
104 * @param path The path to duplicate.
105 */
106struct CadetPeerPath *
107path_duplicate (const struct CadetPeerPath *path)
108{
109 struct CadetPeerPath *aux;
110 unsigned int i;
111
112 aux = path_new (path->length);
113 GNUNET_memcpy (aux->peers,
114 path->peers,
115 path->length * sizeof (GNUNET_PEER_Id));
116 for (i = 0; i < aux->length; i++)
117 GNUNET_PEER_change_rc (aux->peers[i], 1);
118 return aux;
119}
120
121
122/**
123 * Get the length of a path.
124 *
125 * @param path The path to measure, with the local peer at any point of it.
126 *
127 * @return Number of hops to reach destination.
128 * UINT_MAX in case the peer is not in the path.
129 */
130unsigned int
131path_get_length (struct CadetPeerPath *path)
132{
133 if (NULL == path)
134 return UINT_MAX;
135 return path->length;
136}
137
138
139
140/**
141 * Mark path as invalid: keep it aroud for a while to avoid trying it in a loop.
142 *
143 * Never invalidates a two-hop (direct) path, only a core handler can do that.
144 *
145 * Rationale: DHT_get sometimes returns bad cached results, for instance,
146 * on a locally cached result where the PUT followed a path that is no longer
147 * current. The path must remain "known and marked as invalid" for a while.
148 *
149 * @param p Path to invalidate.
150 */
151void
152path_invalidate (struct CadetPeerPath *p)
153{
154 if (NULL != p->path_delete)
155 return;
156
157 LOG (GNUNET_ERROR_TYPE_DEBUG,
158 "Invalidating path %p (%u)\n",
159 p,
160 p->length);
161 p->path_delete
162 = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
163 &path_destroy_delayed, p);
164}
165
166
167/**
168 * Builds a path from a PeerIdentity array.
169 *
170 * @param peers PeerIdentity array.
171 * @param size Size of the @c peers array.
172 * @param myid ID of local peer, to find @c own_pos.
173 * @param own_pos Output parameter: own position in the path.
174 *
175 * @return Fixed and shortened path.
176 */
177struct CadetPeerPath *
178path_build_from_peer_ids (struct GNUNET_PeerIdentity *peers,
179 unsigned int size,
180 GNUNET_PEER_Id myid,
181 unsigned int *own_pos)
182{
183 struct CadetPeerPath *path;
184 GNUNET_PEER_Id shortid;
185 unsigned int i;
186 unsigned int j;
187 unsigned int offset;
188
189 /* Create path */
190 LOG (GNUNET_ERROR_TYPE_DEBUG, " Creating path...\n");
191 path = path_new (size);
192 *own_pos = 0;
193 offset = 0;
194 for (i = 0; i < size; i++)
195 {
196 LOG (GNUNET_ERROR_TYPE_DEBUG, " - %u: taking %s\n",
197 i, GNUNET_i2s (&peers[i]));
198 shortid = GNUNET_PEER_intern (&peers[i]);
199
200 /* Check for loops / duplicates */
201 for (j = 0; j < i - offset; j++)
202 {
203 if (path->peers[j] == shortid)
204 {
205 LOG (GNUNET_ERROR_TYPE_DEBUG, " already exists at pos %u\n", j);
206 offset = i - j;
207 LOG (GNUNET_ERROR_TYPE_DEBUG, " offset now %u\n", offset);
208 GNUNET_PEER_change_rc (shortid, -1);
209 }
210 }
211 LOG (GNUNET_ERROR_TYPE_DEBUG, " storing at %u\n", i - offset);
212 path->peers[i - offset] = shortid;
213 if (path->peers[i - offset] == myid)
214 *own_pos = i - offset;
215 }
216 path->length -= offset;
217
218 if (path->peers[*own_pos] != myid)
219 {
220 /* create path: self not found in path through self */
221 GNUNET_break_op (0);
222 path_destroy (path);
223 return NULL;
224 }
225
226 return path;
227}
228
229
230/**
231 * Test if two paths are equivalent (equal or revese of each other).
232 *
233 * @param p1 First path
234 * @param p2 Second path
235 *
236 * @return #GNUNET_YES if both paths are equivalent
237 * #GNUNET_NO otherwise
238 */
239int
240path_equivalent (const struct CadetPeerPath *p1,
241 const struct CadetPeerPath *p2)
242{
243 unsigned int i;
244 unsigned int l;
245 unsigned int half;
246
247 if (NULL == p1 || NULL == p2)
248 return GNUNET_NO;
249
250 if (p1->length != p2->length)
251 return GNUNET_NO;
252
253 l = p1->length;
254 if (0 == memcmp (p1->peers, p2->peers, sizeof (p1->peers[0]) * l))
255 return GNUNET_YES;
256
257 half = l / 2;
258 l = l - 1;
259 for (i = 0; i <= half; i++)
260 if (p1->peers[i] != p2->peers[l - i])
261 return GNUNET_NO;
262
263 return GNUNET_YES;
264}
265
266
267/**
268 * Test if a path is valid (or at least not known to be invalid).
269 *
270 * @param path Path to test.
271 *
272 * @return #GNUNET_YES If the path is valid or unknown,
273 * #GNUNET_NO If the path is known to be invalid.
274 */
275int
276path_is_valid (const struct CadetPeerPath *path)
277{
278 return (NULL == path->path_delete);
279}
280
281
282/**
283 * Destroy the path and free any allocated resources linked to it
284 *
285 * @param p the path to destroy
286 *
287 * @return #GNUNET_OK on success
288 */
289int
290path_destroy (struct CadetPeerPath *p)
291{
292 if (NULL == p)
293 return GNUNET_OK;
294
295 LOG (GNUNET_ERROR_TYPE_DEBUG,
296 "destroying path %p (%u)\n",
297 p,
298 p->length);
299 GNUNET_PEER_decrement_rcs (p->peers, p->length);
300 GNUNET_free_non_null (p->peers);
301 if (NULL != p->path_delete)
302 GNUNET_SCHEDULER_cancel (p->path_delete);
303 GNUNET_free (p);
304 return GNUNET_OK;
305}
306
307
308/**
309 * Compare two paths.
310 *
311 * @param p1 First path.
312 * @param p2 Second path.
313 *
314 * @return > 0 if p1 is longer, or the first differing PEER_Id is higher on p1.
315 * < 0 if p2 is longer, or the first differing PEER_Id is higher on p2.
316 * 0 if they are identical.
317 */
318int
319path_cmp (const struct CadetPeerPath *p1,
320 const struct CadetPeerPath *p2)
321{
322 if (p1->length > p2->length)
323 return 1;
324
325 if (p1->length < p2->length)
326 return -1;
327
328 return memcmp (p1->peers,
329 p2->peers,
330 sizeof (GNUNET_PEER_Id) * p1->length);
331}
332
333
334char *
335path_2s (struct CadetPeerPath *p)
336{
337 char *s;
338 char *old;
339 unsigned int i;
340
341 old = GNUNET_strdup ("");
342 for (i = 0; i < p->length; i++)
343 {
344 GNUNET_asprintf (&s, "%s %s",
345 old, GNUNET_i2s (GNUNET_PEER_resolve2 (p->peers[i])));
346 GNUNET_free_non_null (old);
347 old = s;
348 }
349 return old;
350}
351
352
353void
354path_debug (struct CadetPeerPath *p)
355{
356 unsigned int i;
357
358 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "PATH:\n");
359 for (i = 0; i < p->length; i++)
360 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " %s\n",
361 GNUNET_i2s (GNUNET_PEER_resolve2 (p->peers[i])));
362 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "END\n");
363}
diff --git a/src/cadet/cadet_path.h b/src/cadet/cadet_path.h
deleted file mode 100644
index bb68eec42..000000000
--- a/src/cadet/cadet_path.h
+++ /dev/null
@@ -1,226 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2001 - 2013 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21/**
22 * @file cadet/cadet_path.h
23 * @brief Path handling functions
24 * @author Bartlomiej Polot
25 */
26
27#ifndef CADET_PATH_H_
28#define CADET_PATH_H_
29
30#ifdef __cplusplus
31extern "C"
32{
33 #if 0 /* keep Emacsens' auto-indent happy */
34}
35#endif
36#endif
37
38
39/******************************************************************************/
40/************************ DATA STRUCTURES ****************************/
41/******************************************************************************/
42
43/**
44 * Information regarding a possible path to reach a single peer
45 */
46struct CadetPeerPath
47{
48
49 /**
50 * Linked list
51 */
52 struct CadetPeerPath *next;
53 struct CadetPeerPath *prev;
54
55 /**
56 * List of all the peers that form the path from origin to target.
57 */
58 GNUNET_PEER_Id *peers;
59
60 /**
61 * Number of peers (hops) in the path
62 */
63 unsigned int length;
64
65 /**
66 * User defined data store.
67 */
68 struct CadetConnection *c;
69
70 /**
71 * Path's score, how reliable is the path.
72 */
73// int score;
74
75 /**
76 * Task to delete the path.
77 * We tried it, it didn't work, don't try again in a while.
78 */
79 struct GNUNET_SCHEDULER_Task * path_delete;
80
81};
82
83/******************************************************************************/
84/************************* FUNCTIONS *****************************/
85/******************************************************************************/
86
87/**
88 * Create a new path.
89 *
90 * @param length How many hops will the path have.
91 *
92 * @return A newly allocated path with a peer array of the specified length.
93 */
94struct CadetPeerPath *
95path_new (unsigned int length);
96
97
98/**
99 * Invert the path.
100 *
101 * @param path The path to invert.
102 */
103void
104path_invert (struct CadetPeerPath *path);
105
106
107/**
108 * Duplicate a path, incrementing short peer's rc.
109 *
110 * @param path The path to duplicate.
111 */
112struct CadetPeerPath *
113path_duplicate (const struct CadetPeerPath *path);
114
115
116/**
117 * Get the length of a path.
118 *
119 * @param path The path to measure, with the local peer at any point of it.
120 *
121 * @return Number of hops to reach destination.
122 * UINT_MAX in case the peer is not in the path.
123 */
124unsigned int
125path_get_length (struct CadetPeerPath *path);
126
127/**
128 * Mark path as invalid: keep it aroud for a while to avoid trying it in a loop.
129 *
130 * DHT_get sometimes returns bad cached results, for instance, on a locally
131 * cached result where the PUT followed a path that is no longer current.
132 *
133 * @param p Path to invalidate.
134 */
135void
136path_invalidate (struct CadetPeerPath *p);
137
138/**
139 * Test if two paths are equivalent (equal or revese of each other).
140 *
141 * @param p1 First path
142 * @param p2 Second path
143 *
144 * @return GNUNET_YES if both paths are equivalent
145 * GNUNET_NO otherwise
146 */
147int
148path_equivalent (const struct CadetPeerPath *p1,
149 const struct CadetPeerPath *p2);
150
151/**
152 * Test if a path is valid (or at least not known to be invalid).
153 *
154 * @param path Path to test.
155 *
156 * @return #GNUNET_YES If the path is valid or unknown,
157 * #GNUNET_NO If the path is known to be invalid.
158 */
159int
160path_is_valid (const struct CadetPeerPath *path);
161
162/**
163 * Destroy the path and free any allocated resources linked to it
164 *
165 * @param p the path to destroy
166 *
167 * @return GNUNET_OK on success
168 */
169int
170path_destroy (struct CadetPeerPath *p);
171
172/**
173 * Compare two paths.
174 *
175 * @param p1 First path.
176 * @param p2 Second path.
177 *
178 * @return > 0 if p1 is longer, or the first differing PEER_Id is higher on p1.
179 * < 0 if p2 is longer, or the first differing PEER_Id is higher on p2.
180 * 0 if they are identical.
181 */
182int
183path_cmp (const struct CadetPeerPath *p1, const struct CadetPeerPath *p2);
184
185/**
186 * Builds a path from a PeerIdentity array.
187 *
188 * @param peers PeerIdentity array.
189 * @param size Size of the @c peers array.
190 * @param myid ID of local peer, to find @c own_pos.
191 * @param own_pos Output parameter: own position in the path.
192 *
193 * @return Fixed and shortened path.
194 */
195struct CadetPeerPath *
196path_build_from_peer_ids (struct GNUNET_PeerIdentity *peers,
197 unsigned int size,
198 GNUNET_PEER_Id myid,
199 unsigned int *own_pos);
200
201/**
202 * Path -> allocated one line string. Caller must free.
203 *
204 * @param p Path.
205 */
206char *
207path_2s (struct CadetPeerPath *p);
208
209/**
210 * Print info about the path for debug.
211 *
212 * @param p Path to debug.
213 */
214void
215path_debug (struct CadetPeerPath *p);
216
217#if 0 /* keep Emacsens' auto-indent happy */
218{
219 #endif
220 #ifdef __cplusplus
221}
222#endif
223
224
225/* ifndef CADET_PATH_H */
226#endif
diff --git a/src/cadet/cadet_protocol.h b/src/cadet/cadet_protocol.h
index d2426addb..560c186cd 100644
--- a/src/cadet/cadet_protocol.h
+++ b/src/cadet/cadet_protocol.h
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 Copyright (C) 2001 - 2011 GNUnet e.V. 3 Copyright (C) 2007 - 2017 GNUnet e.V.
4 4
5 GNUnet is free software; you can redistribute it and/or modify 5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published 6 it under the terms of the GNU General Public License as published
@@ -19,8 +19,10 @@
19*/ 19*/
20 20
21/** 21/**
22 * @author Bartlomiej Polot
23 * @file cadet/cadet_protocol.h 22 * @file cadet/cadet_protocol.h
23 * @brief P2P messages used by CADET
24 * @author Bartlomiej Polot
25 * @author Christian Grothoff
24 */ 26 */
25 27
26#ifndef CADET_PROTOCOL_H_ 28#ifndef CADET_PROTOCOL_H_
@@ -298,17 +300,10 @@ struct GNUNET_CADET_TunnelEncryptedMessage
298 */ 300 */
299 struct GNUNET_MessageHeader header; 301 struct GNUNET_MessageHeader header;
300 302
301#if NEW_CADET
302 /** 303 /**
303 * Reserved, for alignment. 304 * Reserved, for alignment.
304 */ 305 */
305 uint32_t reserved GNUNET_PACKED; 306 uint32_t reserved GNUNET_PACKED;
306#else
307 /**
308 * Maximum packet ID authorized.
309 */
310 struct CadetEncryptedMessageIdentifier cemi;
311#endif
312 307
313 /** 308 /**
314 * ID of the connection. 309 * ID of the connection.
@@ -322,89 +317,18 @@ struct GNUNET_CADET_TunnelEncryptedMessage
322 */ 317 */
323 struct GNUNET_ShortHashCode hmac; 318 struct GNUNET_ShortHashCode hmac;
324 319
325 #if NEW_CADET
326 /** 320 /**
327 * Axolotl-header that specifies which keys to use in which ratchet 321 * Axolotl-header that specifies which keys to use in which ratchet
328 * to decrypt the body that follows. 322 * to decrypt the body that follows.
329 */ 323 */
330 struct GNUNET_CADET_AxHeader ax_header; 324 struct GNUNET_CADET_AxHeader ax_header;
331#else
332 /**
333 * Number of messages sent with the current ratchet key.
334 */
335 uint32_t Ns GNUNET_PACKED;
336
337 /**
338 * Number of messages sent with the previous ratchet key.
339 */
340 uint32_t PNs GNUNET_PACKED;
341 325
342 /** 326 /**
343 * Current ratchet key.
344 */
345 struct GNUNET_CRYPTO_EcdhePublicKey DHRs;
346#endif
347 /**
348 * Encrypted content follows. 327 * Encrypted content follows.
349 */ 328 */
350}; 329};
351 330
352 331
353#ifndef NEW_CADET
354
355/**
356 * Message to query a peer about its Flow Control status regarding a tunnel.
357 *
358 * It is NOT yet clear if we need this.
359 */
360struct GNUNET_CADET_ConnectionHopByHopPollMessage
361{
362 /**
363 * Type: #GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED_POLL
364 */
365 struct GNUNET_MessageHeader header;
366
367 /**
368 * Last packet sent.
369 */
370 struct CadetEncryptedMessageIdentifier cemi;
371
372 /**
373 * ID of the connection.
374 */
375 struct GNUNET_CADET_ConnectionTunnelIdentifier cid;
376
377};
378
379
380/**
381 * Message to acknowledge cadet encrypted traffic, used for
382 * flow-control on a hop-by-hop basis on the connection-level. Note
383 * that we do use the @e cemi from the tunnel layer as the connection
384 * layer's header is included/shared with the tunnel layer messages,
385 * and we only do flow control for the payload.
386 */
387struct GNUNET_CADET_ConnectionEncryptedAckMessage
388{
389 /**
390 * Type: #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_HOP_BY_HOP_ENCRYPTED_ACK
391 */
392 struct GNUNET_MessageHeader header;
393
394 /**
395 * Maximum packet ID authorized.
396 */
397 struct CadetEncryptedMessageIdentifier cemi_max;
398
399 /**
400 * ID of the connection.
401 */
402 struct GNUNET_CADET_ConnectionTunnelIdentifier cid;
403};
404
405#endif
406
407
408/******************************************************************************/ 332/******************************************************************************/
409/******************************* CHANNEL ***********************************/ 333/******************************* CHANNEL ***********************************/
410/******************************************************************************/ 334/******************************************************************************/
@@ -450,83 +374,19 @@ struct GNUNET_CADET_ChannelManageMessage
450 */ 374 */
451 struct GNUNET_MessageHeader header; 375 struct GNUNET_MessageHeader header;
452 376
453#ifdef NEW_CADET
454 /** 377 /**
455 * For alignment. 378 * For alignment.
456 */ 379 */
457 uint32_t reserved GNUNET_PACKED; 380 uint32_t reserved GNUNET_PACKED;
458#endif
459
460 /**
461 * ID of the channel
462 */
463 struct GNUNET_CADET_ChannelTunnelNumber ctn;
464};
465
466
467#ifndef NEW_CADET
468
469/**
470 * Message for cadet data traffic.
471 */
472struct GNUNET_CADET_ChannelAppDataMessage
473{
474 /**
475 * Type: #GNUNET_MESSAGE_TYPE_CADET_UNICAST,
476 * #GNUNET_MESSAGE_TYPE_CADET_TO_ORIGIN
477 */
478 struct GNUNET_MessageHeader header;
479
480 /**
481 * Unique ID of the payload message
482 */
483 /* NEW: struct ChannelMessageIdentifier */
484 uint32_t mid GNUNET_PACKED;
485 381
486 /** 382 /**
487 * ID of the channel 383 * ID of the channel
488 */ 384 */
489 struct GNUNET_CADET_ChannelTunnelNumber ctn; 385 struct GNUNET_CADET_ChannelTunnelNumber ctn;
490
491 /**
492 * Payload follows
493 */
494}; 386};
495 387
496 388
497/** 389/**
498 * Message to acknowledge end-to-end data.
499 */
500struct GNUNET_CADET_ChannelDataAckMessage
501{
502 /**
503 * Type: #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK
504 */
505 struct GNUNET_MessageHeader header;
506
507 /**
508 * ID of the channel
509 */
510 struct GNUNET_CADET_ChannelTunnelNumber ctn;
511
512 /**
513 * Bitfield of already-received messages past @e mid.
514 * pid + 1 @ LSB
515 * pid + 64 @ MSB
516 */
517 uint64_t futures GNUNET_PACKED;
518
519 /**
520 * Last message ID received.
521 */
522 /* NEW: struct ChannelMessageIdentifier */
523 uint32_t mid GNUNET_PACKED;
524};
525
526#else
527
528
529/**
530 * Number used to uniquely identify messages in a CADET Channel. 390 * Number used to uniquely identify messages in a CADET Channel.
531 */ 391 */
532struct ChannelMessageIdentifier 392struct ChannelMessageIdentifier
@@ -595,8 +455,6 @@ struct GNUNET_CADET_ChannelDataAckMessage
595}; 455};
596 456
597 457
598#endif
599
600GNUNET_NETWORK_STRUCT_END 458GNUNET_NETWORK_STRUCT_END
601 459
602#if 0 /* keep Emacsens' auto-indent happy */ 460#if 0 /* keep Emacsens' auto-indent happy */
diff --git a/src/cadet/cadet_test_lib.c b/src/cadet/cadet_test_lib.c
index 9a70dad49..1df6bff0d 100644
--- a/src/cadet/cadet_test_lib.c
+++ b/src/cadet/cadet_test_lib.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 Copyright (C) 2012 GNUnet e.V. 3 Copyright (C) 2012, 2017 GNUnet e.V.
4 4
5 GNUnet is free software; you can redistribute it and/or modify 5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published 6 it under the terms of the GNU General Public License as published
@@ -27,6 +27,7 @@
27#include "cadet_test_lib.h" 27#include "cadet_test_lib.h"
28#include "gnunet_cadet_service.h" 28#include "gnunet_cadet_service.h"
29 29
30
30/** 31/**
31 * Test context for a CADET Test. 32 * Test context for a CADET Test.
32 */ 33 */
@@ -40,7 +41,7 @@ struct GNUNET_CADET_TEST_Context
40 /** 41 /**
41 * Array of handles to the CADET for each peer. 42 * Array of handles to the CADET for each peer.
42 */ 43 */
43 struct GNUNET_CADET_Handle **cadetes; 44 struct GNUNET_CADET_Handle **cadets;
44 45
45 /** 46 /**
46 * Operation associated with the connection to the CADET. 47 * Operation associated with the connection to the CADET.
@@ -48,6 +49,11 @@ struct GNUNET_CADET_TEST_Context
48 struct GNUNET_TESTBED_Operation **ops; 49 struct GNUNET_TESTBED_Operation **ops;
49 50
50 /** 51 /**
52 * Number of peers running, size of the arrays above.
53 */
54 unsigned int num_peers;
55
56 /**
51 * Main function of the test to run once all CADETs are available. 57 * Main function of the test to run once all CADETs are available.
52 */ 58 */
53 GNUNET_CADET_TEST_AppMain app_main; 59 GNUNET_CADET_TEST_AppMain app_main;
@@ -58,30 +64,35 @@ struct GNUNET_CADET_TEST_Context
58 void *app_main_cls; 64 void *app_main_cls;
59 65
60 /** 66 /**
61 * Number of peers running, size of the arrays above. 67 * Handler for incoming tunnels.
62 */ 68 */
63 unsigned int num_peers; 69 GNUNET_CADET_ConnectEventHandler connects;
64 70
65 /** 71 /**
66 * Handler for incoming tunnels. 72 * Function called when the transmit window size changes.
67 */ 73 */
68 GNUNET_CADET_InboundChannelNotificationHandler *new_channel; 74 GNUNET_CADET_WindowSizeEventHandler window_changes;
69 75
70 /** 76 /**
71 * Cleaner for destroyed incoming tunnels. 77 * Cleaner for destroyed incoming tunnels.
72 */ 78 */
73 GNUNET_CADET_ChannelEndHandler *cleaner; 79 GNUNET_CADET_DisconnectEventHandler disconnects;
74 80
75 /** 81 /**
76 * Message handlers. 82 * Message handlers.
77 */ 83 */
78 struct GNUNET_CADET_MessageHandler* handlers; 84 struct GNUNET_MQ_MessageHandler *handlers;
79 85
80 /** 86 /**
81 * Application ports. 87 * Application ports.
82 */ 88 */
83 const struct GNUNET_HashCode **ports; 89 const struct GNUNET_HashCode **ports;
84 90
91 /**
92 * Number of ports in #ports.
93 */
94 unsigned int port_count;
95
85}; 96};
86 97
87 98
@@ -94,6 +105,11 @@ struct GNUNET_CADET_TEST_AdapterContext
94 * Peer number for the particular peer. 105 * Peer number for the particular peer.
95 */ 106 */
96 unsigned int peer; 107 unsigned int peer;
108
109 /**
110 * Port handlers for open ports.
111 */
112 struct GNUNET_CADET_Port **ports;
97 113
98 /** 114 /**
99 * General context. 115 * General context.
@@ -114,26 +130,28 @@ struct GNUNET_CADET_TEST_AdapterContext
114 */ 130 */
115static void * 131static void *
116cadet_connect_adapter (void *cls, 132cadet_connect_adapter (void *cls,
117 const struct GNUNET_CONFIGURATION_Handle *cfg) 133 const struct GNUNET_CONFIGURATION_Handle *cfg)
118{ 134{
119 struct GNUNET_CADET_TEST_AdapterContext *actx = cls; 135 struct GNUNET_CADET_TEST_AdapterContext *actx = cls;
120 struct GNUNET_CADET_TEST_Context *ctx = actx->ctx; 136 struct GNUNET_CADET_TEST_Context *ctx = actx->ctx;
121 struct GNUNET_CADET_Handle *h; 137 struct GNUNET_CADET_Handle *h;
138 unsigned int i;
122 139
123 h = GNUNET_CADET_connect (cfg, 140 h = GNUNET_CADET_connect (cfg);
124 (void *) (long) actx->peer,
125 ctx->cleaner,
126 ctx->handlers);
127 if (NULL == ctx->ports) 141 if (NULL == ctx->ports)
128 return h; 142 return h;
129 143
130 for (int i = 0; NULL != ctx->ports[i]; i++) 144 actx->ports = GNUNET_new_array (ctx->port_count, struct GNUNET_CADET_Port *);
145 for (i = 0; i < ctx->port_count; i++)
131 { 146 {
132 (void ) GNUNET_CADET_open_port (h, ctx->ports[i], 147 actx->ports[i] = GNUNET_CADET_open_port (h,
133 ctx->new_channel, 148 ctx->ports[i],
134 (void *) (long) actx->peer); 149 ctx->connects,
150 (void *) (long) actx->peer,
151 ctx->window_changes,
152 ctx->disconnects,
153 ctx->handlers);
135 } 154 }
136
137 return h; 155 return h;
138} 156}
139 157
@@ -152,6 +170,15 @@ cadet_disconnect_adapter (void *cls,
152 struct GNUNET_CADET_Handle *cadet = op_result; 170 struct GNUNET_CADET_Handle *cadet = op_result;
153 struct GNUNET_CADET_TEST_AdapterContext *actx = cls; 171 struct GNUNET_CADET_TEST_AdapterContext *actx = cls;
154 172
173 if (NULL != actx->ports)
174 {
175 for (int i = 0; i < actx->ctx->port_count; i++)
176 {
177 GNUNET_CADET_close_port (actx->ports[i]);
178 actx->ports[i] = NULL;
179 }
180 GNUNET_free (actx->ports);
181 }
155 GNUNET_free (actx); 182 GNUNET_free (actx);
156 GNUNET_CADET_disconnect (cadet); 183 GNUNET_CADET_disconnect (cadet);
157} 184}
@@ -186,18 +213,18 @@ cadet_connect_cb (void *cls,
186 for (i = 0; i < ctx->num_peers; i++) 213 for (i = 0; i < ctx->num_peers; i++)
187 if (op == ctx->ops[i]) 214 if (op == ctx->ops[i])
188 { 215 {
189 ctx->cadetes[i] = ca_result; 216 ctx->cadets[i] = ca_result;
190 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "...cadet %u connected\n", i); 217 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "...cadet %u connected\n", i);
191 } 218 }
192 for (i = 0; i < ctx->num_peers; i++) 219 for (i = 0; i < ctx->num_peers; i++)
193 if (NULL == ctx->cadetes[i]) 220 if (NULL == ctx->cadets[i])
194 return; /* still some CADET connections missing */ 221 return; /* still some CADET connections missing */
195 /* all CADET connections ready! */ 222 /* all CADET connections ready! */
196 ctx->app_main (ctx->app_main_cls, 223 ctx->app_main (ctx->app_main_cls,
197 ctx, 224 ctx,
198 ctx->num_peers, 225 ctx->num_peers,
199 ctx->peers, 226 ctx->peers,
200 ctx->cadetes); 227 ctx->cadets);
201} 228}
202 229
203 230
@@ -213,7 +240,7 @@ GNUNET_CADET_TEST_cleanup (struct GNUNET_CADET_TEST_Context *ctx)
213 ctx->ops[i] = NULL; 240 ctx->ops[i] = NULL;
214 } 241 }
215 GNUNET_free (ctx->ops); 242 GNUNET_free (ctx->ops);
216 GNUNET_free (ctx->cadetes); 243 GNUNET_free (ctx->cadets);
217 GNUNET_free (ctx); 244 GNUNET_free (ctx);
218 GNUNET_SCHEDULER_shutdown (); 245 GNUNET_SCHEDULER_shutdown ();
219} 246}
@@ -243,12 +270,23 @@ cadet_test_run (void *cls,
243 struct GNUNET_CADET_TEST_Context *ctx = cls; 270 struct GNUNET_CADET_TEST_Context *ctx = cls;
244 unsigned int i; 271 unsigned int i;
245 272
273 if (0 != links_failed)
274 {
275 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Some links failed (%u), ending\n",
276 links_failed);
277 exit (2);
278 }
279
246 if (num_peers != ctx->num_peers) 280 if (num_peers != ctx->num_peers)
247 { 281 {
248 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peers started %u/%u, ending\n", 282 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peers started %u/%u, ending\n",
249 num_peers, ctx->num_peers); 283 num_peers, ctx->num_peers);
250 exit (1); 284 exit (1);
251 } 285 }
286
287 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
288 "Testbed up, %u peers and %u links\n",
289 num_peers, links_succeeded);
252 ctx->peers = peers; 290 ctx->peers = peers;
253 for (i = 0; i < num_peers; i++) 291 for (i = 0; i < num_peers; i++)
254 { 292 {
@@ -270,31 +308,52 @@ cadet_test_run (void *cls,
270} 308}
271 309
272 310
311/**
312 * Run a test using the given name, configuration file and number of peers.
313 * All cadet callbacks will receive the peer number (long) as the closure.
314 *
315 * @param testname Name of the test (for logging).
316 * @param cfgfile Name of the configuration file.
317 * @param num_peers Number of peers to start.
318 * @param tmain Main function to run once the testbed is ready.
319 * @param tmain_cls Closure for @a tmain.
320 * @param connects Handler for incoming channels.
321 * @param window_changes Handler for the window size change notification.
322 * @param disconnects Cleaner for destroyed incoming channels.
323 * @param handlers Message handlers.
324 * @param ports Ports the peers offer, NULL-terminated.
325 */
273void 326void
274GNUNET_CADET_TEST_run (const char *testname, 327GNUNET_CADET_TEST_ruN (const char *testname,
275 const char *cfgname, 328 const char *cfgfile,
276 unsigned int num_peers, 329 unsigned int num_peers,
277 GNUNET_CADET_TEST_AppMain tmain, 330 GNUNET_CADET_TEST_AppMain tmain,
278 void *tmain_cls, 331 void *tmain_cls,
279 GNUNET_CADET_InboundChannelNotificationHandler new_channel, 332 GNUNET_CADET_ConnectEventHandler connects,
280 GNUNET_CADET_ChannelEndHandler cleaner, 333 GNUNET_CADET_WindowSizeEventHandler window_changes,
281 struct GNUNET_CADET_MessageHandler* handlers, 334 GNUNET_CADET_DisconnectEventHandler disconnects,
282 const struct GNUNET_HashCode **ports) 335 struct GNUNET_MQ_MessageHandler *handlers,
336 const struct GNUNET_HashCode **ports)
283{ 337{
284 struct GNUNET_CADET_TEST_Context *ctx; 338 struct GNUNET_CADET_TEST_Context *ctx;
285 339
286 ctx = GNUNET_new (struct GNUNET_CADET_TEST_Context); 340 ctx = GNUNET_new (struct GNUNET_CADET_TEST_Context);
287 ctx->num_peers = num_peers; 341 ctx->num_peers = num_peers;
288 ctx->ops = GNUNET_malloc (num_peers * sizeof (struct GNUNET_TESTBED_Operation *)); 342 ctx->ops = GNUNET_new_array (num_peers, struct GNUNET_TESTBED_Operation *);
289 ctx->cadetes = GNUNET_malloc (num_peers * sizeof (struct GNUNET_CADET_Handle *)); 343 ctx->cadets = GNUNET_new_array (num_peers, struct GNUNET_CADET_Handle *);
290 ctx->app_main = tmain; 344 ctx->app_main = tmain;
291 ctx->app_main_cls = tmain_cls; 345 ctx->app_main_cls = tmain_cls;
292 ctx->new_channel = new_channel; 346 ctx->connects = connects;
293 ctx->cleaner = cleaner; 347 ctx->window_changes = window_changes;
294 ctx->handlers = handlers; 348 ctx->disconnects = disconnects;
349 ctx->handlers = GNUNET_MQ_copy_handlers (handlers);
295 ctx->ports = ports; 350 ctx->ports = ports;
351 ctx->port_count = 0;
352 while (NULL != ctx->ports[ctx->port_count])
353 ctx->port_count++;
354
296 GNUNET_TESTBED_test_run (testname, 355 GNUNET_TESTBED_test_run (testname,
297 cfgname, 356 cfgfile,
298 num_peers, 357 num_peers,
299 0LL, NULL, NULL, 358 0LL, NULL, NULL,
300 &cadet_test_run, ctx); 359 &cadet_test_run, ctx);
diff --git a/src/cadet/cadet_test_lib.h b/src/cadet/cadet_test_lib.h
index 464977d42..4b3a6b18d 100644
--- a/src/cadet/cadet_test_lib.h
+++ b/src/cadet/cadet_test_lib.h
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 Copyright (C) 2012 GNUnet e.V. 3 Copyright (C) 2012,2017 GNUnet e.V.
4 4
5 GNUnet is free software; you can redistribute it and/or modify 5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published 6 it under the terms of the GNU General Public License as published
@@ -49,41 +49,41 @@ struct GNUNET_CADET_TEST_Context;
49 * @param ctx Argument to give to GNUNET_CADET_TEST_cleanup on test end. 49 * @param ctx Argument to give to GNUNET_CADET_TEST_cleanup on test end.
50 * @param num_peers Number of peers that are running. 50 * @param num_peers Number of peers that are running.
51 * @param peers Array of peers. 51 * @param peers Array of peers.
52 * @param cadetes Handle to each of the CADETs of the peers. 52 * @param cadets Handle to each of the CADETs of the peers.
53 */ 53 */
54typedef void (*GNUNET_CADET_TEST_AppMain) (void *cls, 54typedef void (*GNUNET_CADET_TEST_AppMain) (void *cls,
55 struct GNUNET_CADET_TEST_Context *ctx, 55 struct GNUNET_CADET_TEST_Context *ctx,
56 unsigned int num_peers, 56 unsigned int num_peers,
57 struct GNUNET_TESTBED_Peer **peers, 57 struct GNUNET_TESTBED_Peer **peers,
58 struct GNUNET_CADET_Handle **cadetes); 58 struct GNUNET_CADET_Handle **cadets);
59 59
60 60
61/** 61/**
62 * Run a test using the given name, configuration file and number of 62 * Run a test using the given name, configuration file and number of peers.
63 * peers. 63 * All cadet callbacks will receive the peer number (long) as the closure.
64 * All cadet callbacks will receive the peer number as the closure.
65 * 64 *
66 * @param testname Name of the test (for logging). 65 * @param testname Name of the test (for logging).
67 * @param cfgname Name of the configuration file. 66 * @param cfgfile Name of the configuration file.
68 * @param num_peers Number of peers to start. 67 * @param num_peers Number of peers to start.
69 * @param tmain Main function to run once the testbed is ready. 68 * @param tmain Main function to run once the testbed is ready.
70 * @param tmain_cls Closure for 'tmain'. 69 * @param tmain_cls Closure for @a tmain.
71 * @param new_channel Handler for incoming tunnels. 70 * @param connects Handler for incoming channels.
72 * @param cleaner Cleaner for destroyed incoming tunnels. 71 * @param window_changes Handler for the window size change notification.
72 * @param disconnects Cleaner for destroyed incoming channels.
73 * @param handlers Message handlers. 73 * @param handlers Message handlers.
74 * @param ports Ports the peers offer, NULL-terminated. 74 * @param ports Ports the peers offer, NULL-terminated.
75 */ 75 */
76void 76void
77GNUNET_CADET_TEST_run (const char *testname, 77GNUNET_CADET_TEST_ruN (const char *testname,
78 const char *cfgname, 78 const char *cfgfile,
79 unsigned int num_peers, 79 unsigned int num_peers,
80 GNUNET_CADET_TEST_AppMain tmain, 80 GNUNET_CADET_TEST_AppMain tmain,
81 void *tmain_cls, 81 void *tmain_cls,
82 GNUNET_CADET_InboundChannelNotificationHandler new_channel, 82 GNUNET_CADET_ConnectEventHandler connects,
83 GNUNET_CADET_ChannelEndHandler cleaner, 83 GNUNET_CADET_WindowSizeEventHandler window_changes,
84 struct GNUNET_CADET_MessageHandler* handlers, 84 GNUNET_CADET_DisconnectEventHandler disconnects,
85 const struct GNUNET_HashCode **ports); 85 struct GNUNET_MQ_MessageHandler *handlers,
86 86 const struct GNUNET_HashCode **ports);
87 87
88/** 88/**
89 * Clean up the testbed. 89 * Clean up the testbed.
diff --git a/src/cadet/cadet_test_lib_new.c b/src/cadet/cadet_test_lib_new.c
deleted file mode 100644
index c3a1540f4..000000000
--- a/src/cadet/cadet_test_lib_new.c
+++ /dev/null
@@ -1,362 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012, 2017 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20/**
21 * @file cadet/cadet_test_lib.c
22 * @author Bartlomiej Polot
23 * @brief library for writing CADET tests
24 */
25#include "platform.h"
26#include "gnunet_util_lib.h"
27#include "cadet_test_lib_new.h"
28#include "gnunet_cadet_service.h"
29
30
31/**
32 * Test context for a CADET Test.
33 */
34struct GNUNET_CADET_TEST_Context
35{
36 /**
37 * Array of running peers.
38 */
39 struct GNUNET_TESTBED_Peer **peers;
40
41 /**
42 * Array of handles to the CADET for each peer.
43 */
44 struct GNUNET_CADET_Handle **cadets;
45
46 /**
47 * Operation associated with the connection to the CADET.
48 */
49 struct GNUNET_TESTBED_Operation **ops;
50
51 /**
52 * Number of peers running, size of the arrays above.
53 */
54 unsigned int num_peers;
55
56 /**
57 * Main function of the test to run once all CADETs are available.
58 */
59 GNUNET_CADET_TEST_AppMain app_main;
60
61 /**
62 * Closure for 'app_main'.
63 */
64 void *app_main_cls;
65
66 /**
67 * Handler for incoming tunnels.
68 */
69 GNUNET_CADET_ConnectEventHandler connects;
70
71 /**
72 * Function called when the transmit window size changes.
73 */
74 GNUNET_CADET_WindowSizeEventHandler window_changes;
75
76 /**
77 * Cleaner for destroyed incoming tunnels.
78 */
79 GNUNET_CADET_DisconnectEventHandler disconnects;
80
81 /**
82 * Message handlers.
83 */
84 struct GNUNET_MQ_MessageHandler *handlers;
85
86 /**
87 * Application ports.
88 */
89 const struct GNUNET_HashCode **ports;
90
91 /**
92 * Number of ports in #ports.
93 */
94 unsigned int port_count;
95
96};
97
98
99/**
100 * Context for a cadet adapter callback.
101 */
102struct GNUNET_CADET_TEST_AdapterContext
103{
104 /**
105 * Peer number for the particular peer.
106 */
107 unsigned int peer;
108
109 /**
110 * Port handlers for open ports.
111 */
112 struct GNUNET_CADET_Port **ports;
113
114 /**
115 * General context.
116 */
117 struct GNUNET_CADET_TEST_Context *ctx;
118};
119
120
121/**
122 * Adapter function called to establish a connection to
123 * the CADET service.
124 *
125 * @param cls closure
126 * @param cfg configuration of the peer to connect to; will be available until
127 * GNUNET_TESTBED_operation_done() is called on the operation returned
128 * from GNUNET_TESTBED_service_connect()
129 * @return service handle to return in 'op_result', NULL on error
130 */
131static void *
132cadet_connect_adapter (void *cls,
133 const struct GNUNET_CONFIGURATION_Handle *cfg)
134{
135 struct GNUNET_CADET_TEST_AdapterContext *actx = cls;
136 struct GNUNET_CADET_TEST_Context *ctx = actx->ctx;
137 struct GNUNET_CADET_Handle *h;
138 unsigned int i;
139
140 h = GNUNET_CADET_connecT (cfg);
141 if (NULL == ctx->ports)
142 return h;
143
144 actx->ports = GNUNET_new_array (ctx->port_count, struct GNUNET_CADET_Port *);
145 for (i = 0; i < ctx->port_count; i++)
146 {
147 actx->ports[i] = GNUNET_CADET_open_porT (h,
148 ctx->ports[i],
149 ctx->connects,
150 (void *) (long) actx->peer,
151 ctx->window_changes,
152 ctx->disconnects,
153 ctx->handlers);
154 }
155 return h;
156}
157
158
159/**
160 * Adapter function called to destroy a connection to
161 * the CADET service.
162 *
163 * @param cls closure
164 * @param op_result service handle returned from the connect adapter
165 */
166static void
167cadet_disconnect_adapter (void *cls,
168 void *op_result)
169{
170 struct GNUNET_CADET_Handle *cadet = op_result;
171 struct GNUNET_CADET_TEST_AdapterContext *actx = cls;
172
173 if (NULL != actx->ports)
174 {
175 for (int i = 0; i < actx->ctx->port_count; i++)
176 {
177 GNUNET_CADET_close_port (actx->ports[i]);
178 actx->ports[i] = NULL;
179 }
180 GNUNET_free (actx->ports);
181 }
182 GNUNET_free (actx);
183 GNUNET_CADET_disconnect (cadet);
184}
185
186
187/**
188 * Callback to be called when a service connect operation is completed.
189 *
190 * @param cls The callback closure from functions generating an operation.
191 * @param op The operation that has been finished.
192 * @param ca_result The service handle returned from
193 * GNUNET_TESTBED_ConnectAdapter() (cadet handle).
194 * @param emsg Error message in case the operation has failed.
195 * NULL if operation has executed successfully.
196 */
197static void
198cadet_connect_cb (void *cls,
199 struct GNUNET_TESTBED_Operation *op,
200 void *ca_result,
201 const char *emsg)
202{
203 struct GNUNET_CADET_TEST_Context *ctx = cls;
204 unsigned int i;
205
206 if (NULL != emsg)
207 {
208 fprintf (stderr, "Failed to connect to CADET service: %s\n",
209 emsg);
210 GNUNET_SCHEDULER_shutdown ();
211 return;
212 }
213 for (i = 0; i < ctx->num_peers; i++)
214 if (op == ctx->ops[i])
215 {
216 ctx->cadets[i] = ca_result;
217 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "...cadet %u connected\n", i);
218 }
219 for (i = 0; i < ctx->num_peers; i++)
220 if (NULL == ctx->cadets[i])
221 return; /* still some CADET connections missing */
222 /* all CADET connections ready! */
223 ctx->app_main (ctx->app_main_cls,
224 ctx,
225 ctx->num_peers,
226 ctx->peers,
227 ctx->cadets);
228}
229
230
231void
232GNUNET_CADET_TEST_cleanup (struct GNUNET_CADET_TEST_Context *ctx)
233{
234 unsigned int i;
235
236 for (i = 0; i < ctx->num_peers; i++)
237 {
238 GNUNET_assert (NULL != ctx->ops[i]);
239 GNUNET_TESTBED_operation_done (ctx->ops[i]);
240 ctx->ops[i] = NULL;
241 }
242 GNUNET_free (ctx->ops);
243 GNUNET_free (ctx->cadets);
244 GNUNET_free (ctx);
245 GNUNET_SCHEDULER_shutdown ();
246}
247
248
249/**
250 * Callback run when the testbed is ready (peers running and connected to
251 * each other)
252 *
253 * @param cls Closure (context).
254 * @param h the run handle
255 * @param num_peers Number of peers that are running.
256 * @param peers Handles to each one of the @c num_peers peers.
257 * @param links_succeeded the number of overlay link connection attempts that
258 * succeeded
259 * @param links_failed the number of overlay link connection attempts that
260 * failed
261 */
262static void
263cadet_test_run (void *cls,
264 struct GNUNET_TESTBED_RunHandle *h,
265 unsigned int num_peers,
266 struct GNUNET_TESTBED_Peer **peers,
267 unsigned int links_succeeded,
268 unsigned int links_failed)
269{
270 struct GNUNET_CADET_TEST_Context *ctx = cls;
271 unsigned int i;
272
273 if (0 != links_failed)
274 {
275 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Some links failed (%u), ending\n",
276 links_failed);
277 exit (2);
278 }
279
280 if (num_peers != ctx->num_peers)
281 {
282 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peers started %u/%u, ending\n",
283 num_peers, ctx->num_peers);
284 exit (1);
285 }
286
287 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
288 "Testbed up, %u peers and %u links\n",
289 num_peers, links_succeeded);
290 ctx->peers = peers;
291 for (i = 0; i < num_peers; i++)
292 {
293 struct GNUNET_CADET_TEST_AdapterContext *newctx;
294 newctx = GNUNET_new (struct GNUNET_CADET_TEST_AdapterContext);
295 newctx->peer = i;
296 newctx->ctx = ctx;
297 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connecting to cadet %u\n", i);
298 ctx->ops[i] = GNUNET_TESTBED_service_connect (ctx,
299 peers[i],
300 "cadet",
301 &cadet_connect_cb,
302 ctx,
303 &cadet_connect_adapter,
304 &cadet_disconnect_adapter,
305 newctx);
306 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "op handle %p\n", ctx->ops[i]);
307 }
308}
309
310
311/**
312 * Run a test using the given name, configuration file and number of peers.
313 * All cadet callbacks will receive the peer number (long) as the closure.
314 *
315 * @param testname Name of the test (for logging).
316 * @param cfgfile Name of the configuration file.
317 * @param num_peers Number of peers to start.
318 * @param tmain Main function to run once the testbed is ready.
319 * @param tmain_cls Closure for @a tmain.
320 * @param connects Handler for incoming channels.
321 * @param window_changes Handler for the window size change notification.
322 * @param disconnects Cleaner for destroyed incoming channels.
323 * @param handlers Message handlers.
324 * @param ports Ports the peers offer, NULL-terminated.
325 */
326void
327GNUNET_CADET_TEST_ruN (const char *testname,
328 const char *cfgfile,
329 unsigned int num_peers,
330 GNUNET_CADET_TEST_AppMain tmain,
331 void *tmain_cls,
332 GNUNET_CADET_ConnectEventHandler connects,
333 GNUNET_CADET_WindowSizeEventHandler window_changes,
334 GNUNET_CADET_DisconnectEventHandler disconnects,
335 struct GNUNET_MQ_MessageHandler *handlers,
336 const struct GNUNET_HashCode **ports)
337{
338 struct GNUNET_CADET_TEST_Context *ctx;
339
340 ctx = GNUNET_new (struct GNUNET_CADET_TEST_Context);
341 ctx->num_peers = num_peers;
342 ctx->ops = GNUNET_new_array (num_peers, struct GNUNET_TESTBED_Operation *);
343 ctx->cadets = GNUNET_new_array (num_peers, struct GNUNET_CADET_Handle *);
344 ctx->app_main = tmain;
345 ctx->app_main_cls = tmain_cls;
346 ctx->connects = connects;
347 ctx->window_changes = window_changes;
348 ctx->disconnects = disconnects;
349 ctx->handlers = GNUNET_MQ_copy_handlers (handlers);
350 ctx->ports = ports;
351 ctx->port_count = 0;
352 while (NULL != ctx->ports[ctx->port_count])
353 ctx->port_count++;
354
355 GNUNET_TESTBED_test_run (testname,
356 cfgfile,
357 num_peers,
358 0LL, NULL, NULL,
359 &cadet_test_run, ctx);
360}
361
362/* end of cadet_test_lib.c */
diff --git a/src/cadet/cadet_test_lib_new.h b/src/cadet/cadet_test_lib_new.h
deleted file mode 100644
index 4b3a6b18d..000000000
--- a/src/cadet/cadet_test_lib_new.h
+++ /dev/null
@@ -1,106 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012,2017 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20/**
21 * @file cadet/cadet_test_lib.h
22 * @author Bartlomiej Polot
23 * @brief library for writing CADET tests
24 */
25#ifndef CADET_TEST_LIB_H
26#define CADET_TEST_LIB_H
27
28#ifdef __cplusplus
29extern "C"
30{
31#if 0 /* keep Emacsens' auto-indent happy */
32}
33#endif
34#endif
35
36#include "gnunet_testbed_service.h"
37#include "gnunet_cadet_service.h"
38
39/**
40 * Test context for a CADET Test.
41 */
42struct GNUNET_CADET_TEST_Context;
43
44
45/**
46 * Main function of a CADET test.
47 *
48 * @param cls Closure.
49 * @param ctx Argument to give to GNUNET_CADET_TEST_cleanup on test end.
50 * @param num_peers Number of peers that are running.
51 * @param peers Array of peers.
52 * @param cadets Handle to each of the CADETs of the peers.
53 */
54typedef void (*GNUNET_CADET_TEST_AppMain) (void *cls,
55 struct GNUNET_CADET_TEST_Context *ctx,
56 unsigned int num_peers,
57 struct GNUNET_TESTBED_Peer **peers,
58 struct GNUNET_CADET_Handle **cadets);
59
60
61/**
62 * Run a test using the given name, configuration file and number of peers.
63 * All cadet callbacks will receive the peer number (long) as the closure.
64 *
65 * @param testname Name of the test (for logging).
66 * @param cfgfile Name of the configuration file.
67 * @param num_peers Number of peers to start.
68 * @param tmain Main function to run once the testbed is ready.
69 * @param tmain_cls Closure for @a tmain.
70 * @param connects Handler for incoming channels.
71 * @param window_changes Handler for the window size change notification.
72 * @param disconnects Cleaner for destroyed incoming channels.
73 * @param handlers Message handlers.
74 * @param ports Ports the peers offer, NULL-terminated.
75 */
76void
77GNUNET_CADET_TEST_ruN (const char *testname,
78 const char *cfgfile,
79 unsigned int num_peers,
80 GNUNET_CADET_TEST_AppMain tmain,
81 void *tmain_cls,
82 GNUNET_CADET_ConnectEventHandler connects,
83 GNUNET_CADET_WindowSizeEventHandler window_changes,
84 GNUNET_CADET_DisconnectEventHandler disconnects,
85 struct GNUNET_MQ_MessageHandler *handlers,
86 const struct GNUNET_HashCode **ports);
87
88/**
89 * Clean up the testbed.
90 *
91 * @param ctx handle for the testbed
92 */
93void
94GNUNET_CADET_TEST_cleanup (struct GNUNET_CADET_TEST_Context *ctx);
95
96
97#if 0 /* keep Emacsens' auto-indent happy */
98{
99#endif
100#ifdef __cplusplus
101}
102#endif
103
104
105/* ifndef CADET_TEST_LIB_H */
106#endif
diff --git a/src/cadet/gnunet-cadet.c b/src/cadet/gnunet-cadet.c
index c194a5bc1..57eeac735 100644
--- a/src/cadet/gnunet-cadet.c
+++ b/src/cadet/gnunet-cadet.c
@@ -772,15 +772,15 @@ run (void *cls,
772 && target_id != NULL) 772 && target_id != NULL)
773 { 773 {
774 FPRINTF (stderr, 774 FPRINTF (stderr,
775 _("You must NOT give a TARGET " 775 _("Extra arguments are not applicable "
776 "when using 'request all' options\n")); 776 "in combination with this option.\n"));
777 return; 777 return;
778 } 778 }
779 779
780 if (GNUNET_YES == dump) 780 if (GNUNET_YES == dump)
781 { 781 {
782 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 782 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
783 "requesting debug dump\n"); 783 "Requesting debug dump\n");
784 job = GNUNET_SCHEDULER_add_now (&request_dump, 784 job = GNUNET_SCHEDULER_add_now (&request_dump,
785 NULL); 785 NULL);
786 } 786 }
@@ -829,7 +829,7 @@ run (void *cls,
829 829
830 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 830 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
831 "Connecting to CADET service\n"); 831 "Connecting to CADET service\n");
832 mh = GNUNET_CADET_connecT (cfg); 832 mh = GNUNET_CADET_connect (cfg);
833 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, 833 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
834 NULL); 834 NULL);
835 if (NULL == mh) 835 if (NULL == mh)
@@ -844,7 +844,7 @@ run (void *cls,
844 GNUNET_CRYPTO_hash (listen_port, 844 GNUNET_CRYPTO_hash (listen_port,
845 strlen (listen_port), 845 strlen (listen_port),
846 &porthash); 846 &porthash);
847 lp = GNUNET_CADET_open_porT (mh, 847 lp = GNUNET_CADET_open_port (mh,
848 &porthash, 848 &porthash,
849 &channel_incoming, 849 &channel_incoming,
850 NULL, 850 NULL,
@@ -876,7 +876,7 @@ run (void *cls,
876 GNUNET_CRYPTO_hash (target_port, 876 GNUNET_CRYPTO_hash (target_port,
877 strlen(target_port), 877 strlen(target_port),
878 &porthash); 878 &porthash);
879 ch = GNUNET_CADET_channel_creatE (mh, 879 ch = GNUNET_CADET_channel_create (mh,
880 NULL, 880 NULL,
881 &pid, 881 &pid,
882 &porthash, 882 &porthash,
@@ -919,32 +919,55 @@ main (int argc,
919 char *const *argv) 919 char *const *argv)
920{ 920{
921 int res; 921 int res;
922 const char helpstr[] = "Create channels and retreive info about cadets status."; 922 const char helpstr[] = "Create tunnels and retrieve info about CADET's status.";
923 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 923 struct GNUNET_GETOPT_CommandLineOption options[] = {
924 {'C', "connection", "CONNECTION_ID", 924 /* I would use the terminology 'circuit' here... --lynX */
925 gettext_noop ("provide information about a particular connection"), 925 GNUNET_GETOPT_OPTION_STRING ('C',
926 GNUNET_YES, &GNUNET_GETOPT_set_string, &conn_id}, 926 "connection",
927 {'e', "echo", NULL, 927 "CONNECTION_ID",
928 gettext_noop ("activate echo mode"), 928 gettext_noop ("Provide information about a particular connection"),
929 GNUNET_NO, &GNUNET_GETOPT_set_one, &echo}, 929 &conn_id),
930 {'d', "dump", NULL, 930
931 gettext_noop ("dump debug information to STDERR"), 931 GNUNET_GETOPT_OPTION_SET_ONE ('e',
932 GNUNET_NO, &GNUNET_GETOPT_set_one, &dump}, 932 "echo",
933 {'o', "open-port", "PORT", 933 gettext_noop ("Activate echo mode"),
934 gettext_noop ("port to listen to"), 934 &echo),
935 GNUNET_YES, &GNUNET_GETOPT_set_string, &listen_port}, 935
936 {'p', "peer", "PEER_ID", 936 GNUNET_GETOPT_OPTION_SET_ONE ('d',
937 gettext_noop ("provide information about a patricular peer"), 937 "dump",
938 GNUNET_YES, &GNUNET_GETOPT_set_string, &peer_id}, 938 gettext_noop ("Dump debug information to STDERR"),
939 {'P', "peers", NULL, 939 &dump),
940 gettext_noop ("provide information about all peers"), 940
941 GNUNET_NO, &GNUNET_GETOPT_set_one, &request_peers}, 941 GNUNET_GETOPT_OPTION_STRING ('o',
942 {'t', "tunnel", "TUNNEL_ID", 942 "open-port",
943 gettext_noop ("provide information about a particular tunnel"), 943 "SHARED_SECRET",
944 GNUNET_YES, &GNUNET_GETOPT_set_string, &tunnel_id}, 944 gettext_noop ("Listen for connections using a shared secret among sender and recipient"),
945 {'T', "tunnels", NULL, 945 &listen_port),
946 gettext_noop ("provide information about all tunnels"), 946
947 GNUNET_NO, &GNUNET_GETOPT_set_one, &request_tunnels}, 947
948 GNUNET_GETOPT_OPTION_STRING ('p',
949 "peer",
950 "PEER_ID",
951 gettext_noop ("Provide information about a patricular peer"),
952 &peer_id),
953
954
955 GNUNET_GETOPT_OPTION_SET_ONE ('P',
956 "peers",
957 gettext_noop ("Provide information about all peers"),
958 &request_peers),
959
960 GNUNET_GETOPT_OPTION_STRING ('t',
961 "tunnel",
962 "TUNNEL_ID",
963 gettext_noop ("Provide information about a particular tunnel"),
964 &tunnel_id),
965
966
967 GNUNET_GETOPT_OPTION_SET_ONE ('T',
968 "tunnels",
969 gettext_noop ("Provide information about all tunnels"),
970 &request_tunnels),
948 971
949 GNUNET_GETOPT_OPTION_END 972 GNUNET_GETOPT_OPTION_END
950 }; 973 };
@@ -955,7 +978,7 @@ main (int argc,
955 return 2; 978 return 2;
956 979
957 res = GNUNET_PROGRAM_run (argc, argv, 980 res = GNUNET_PROGRAM_run (argc, argv,
958 "gnunet-cadet (OPTIONS | TARGET PORT)", 981 "gnunet-cadet (OPTIONS | PEER_ID SHARED_SECRET)",
959 gettext_noop (helpstr), 982 gettext_noop (helpstr),
960 options, &run, NULL); 983 options, &run, NULL);
961 984
diff --git a/src/cadet/gnunet-service-cadet-new.c b/src/cadet/gnunet-service-cadet-new.c
deleted file mode 100644
index de85db5b6..000000000
--- a/src/cadet/gnunet-service-cadet-new.c
+++ /dev/null
@@ -1,1490 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2001-2013, 2017 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21/**
22 * @file cadet/gnunet-service-cadet-new.c
23 * @brief GNUnet CADET service with encryption
24 * @author Bartlomiej Polot
25 * @author Christian Grothoff
26 *
27 * Dictionary:
28 * - peer: other cadet instance. If there is direct connection it's a neighbor.
29 * - path: series of directly connected peer from one peer to another.
30 * - connection: path which is being used in a tunnel.
31 * - tunnel: encrypted connection to a peer, neighbor or not.
32 * - channel: logical link between two clients, on the same or different peers.
33 * have properties like reliability.
34 */
35
36#include "platform.h"
37#include "gnunet_util_lib.h"
38#include "cadet.h"
39#include "gnunet_statistics_service.h"
40#include "gnunet-service-cadet-new.h"
41#include "gnunet-service-cadet-new_channel.h"
42#include "gnunet-service-cadet-new_connection.h"
43#include "gnunet-service-cadet-new_core.h"
44#include "gnunet-service-cadet-new_dht.h"
45#include "gnunet-service-cadet-new_hello.h"
46#include "gnunet-service-cadet-new_tunnels.h"
47#include "gnunet-service-cadet-new_peer.h"
48#include "gnunet-service-cadet-new_paths.h"
49
50#define LOG(level, ...) GNUNET_log (level,__VA_ARGS__)
51
52
53/**
54 * Struct containing information about a client of the service
55 */
56struct CadetClient
57{
58 /**
59 * Linked list next
60 */
61 struct CadetClient *next;
62
63 /**
64 * Linked list prev
65 */
66 struct CadetClient *prev;
67
68 /**
69 * Tunnels that belong to this client, indexed by local id,
70 * value is a `struct CadetChannel`.
71 */
72 struct GNUNET_CONTAINER_MultiHashMap32 *channels;
73
74 /**
75 * Handle to communicate with the client
76 */
77 struct GNUNET_MQ_Handle *mq;
78
79 /**
80 * Client handle.
81 */
82 struct GNUNET_SERVICE_Client *client;
83
84 /**
85 * Ports that this client has declared interest in.
86 * Indexed by port, contains *Client.
87 */
88 struct GNUNET_CONTAINER_MultiHashMap *ports;
89
90 /**
91 * Channel ID to use for the next incoming channel for this client.
92 * Wraps around (in theory).
93 */
94 struct GNUNET_CADET_ClientChannelNumber next_ccn;
95
96 /**
97 * ID of the client, mainly for debug messages. Purely internal to this file.
98 */
99 unsigned int id;
100};
101
102/******************************************************************************/
103/*********************** GLOBAL VARIABLES ****************************/
104/******************************************************************************/
105
106/****************************** Global variables ******************************/
107
108/**
109 * Handle to our configuration.
110 */
111const struct GNUNET_CONFIGURATION_Handle *cfg;
112
113/**
114 * Handle to the statistics service.
115 */
116struct GNUNET_STATISTICS_Handle *stats;
117
118/**
119 * Handle to communicate with ATS.
120 */
121struct GNUNET_ATS_ConnectivityHandle *ats_ch;
122
123/**
124 * Local peer own ID.
125 */
126struct GNUNET_PeerIdentity my_full_id;
127
128/**
129 * Own private key.
130 */
131struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
132
133/**
134 * Signal that shutdown is happening: prevent recovery measures.
135 */
136int shutting_down;
137
138/**
139 * DLL with all the clients, head.
140 */
141static struct CadetClient *clients_head;
142
143/**
144 * DLL with all the clients, tail.
145 */
146static struct CadetClient *clients_tail;
147
148/**
149 * Next ID to assign to a client.
150 */
151static unsigned int next_client_id;
152
153/**
154 * All ports clients of this peer have opened.
155 */
156struct GNUNET_CONTAINER_MultiHashMap *open_ports;
157
158/**
159 * Map from ports to channels where the ports were closed at the
160 * time we got the inbound connection.
161 * Indexed by port, contains `struct CadetChannel`.
162 */
163struct GNUNET_CONTAINER_MultiHashMap *loose_channels;
164
165/**
166 * Map from PIDs to `struct CadetPeer` entries.
167 */
168struct GNUNET_CONTAINER_MultiPeerMap *peers;
169
170/**
171 * Map from `struct GNUNET_CADET_ConnectionTunnelIdentifier`
172 * hash codes to `struct CadetConnection` objects.
173 */
174struct GNUNET_CONTAINER_MultiShortmap *connections;
175
176/**
177 * How many messages are needed to trigger an AXOLOTL ratchet advance.
178 */
179unsigned long long ratchet_messages;
180
181/**
182 * How long until we trigger a ratched advance due to time.
183 */
184struct GNUNET_TIME_Relative ratchet_time;
185
186/**
187 * How frequently do we send KEEPALIVE messages on idle connections?
188 */
189struct GNUNET_TIME_Relative keepalive_period;
190
191/**
192 * Set to non-zero values to create random drops to test retransmissions.
193 */
194unsigned long long drop_percent;
195
196
197/**
198 * Send a message to a client.
199 *
200 * @param c client to get the message
201 * @param env envelope with the message
202 */
203void
204GSC_send_to_client (struct CadetClient *c,
205 struct GNUNET_MQ_Envelope *env)
206{
207 GNUNET_MQ_send (c->mq,
208 env);
209}
210
211
212/**
213 * Return identifier for a client as a string.
214 *
215 * @param c client to identify
216 * @return string for debugging
217 */
218const char *
219GSC_2s (struct CadetClient *c)
220{
221 static char buf[32];
222
223 GNUNET_snprintf (buf,
224 sizeof (buf),
225 "Client(%u)",
226 c->id);
227 return buf;
228}
229
230
231/**
232 * Lookup channel of client @a c by @a ccn.
233 *
234 * @param c client to look in
235 * @param ccn channel ID to look up
236 * @return NULL if no such channel exists
237 */
238static struct CadetChannel *
239lookup_channel (struct CadetClient *c,
240 struct GNUNET_CADET_ClientChannelNumber ccn)
241{
242 return GNUNET_CONTAINER_multihashmap32_get (c->channels,
243 ntohl (ccn.channel_of_client));
244}
245
246
247/**
248 * Obtain the next LID to use for incoming connections to
249 * the given client.
250 *
251 * @param c client handle
252 */
253static struct GNUNET_CADET_ClientChannelNumber
254client_get_next_ccn (struct CadetClient *c)
255{
256 struct GNUNET_CADET_ClientChannelNumber ccn = c->next_ccn;
257
258 /* increment until we have a free one... */
259 while (NULL !=
260 lookup_channel (c,
261 ccn))
262 {
263 ccn.channel_of_client
264 = htonl (1 + (ntohl (ccn.channel_of_client)));
265 if (ntohl (ccn.channel_of_client) >=
266 GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
267 ccn.channel_of_client = htonl (0);
268 }
269 c->next_ccn.channel_of_client
270 = htonl (1 + (ntohl (ccn.channel_of_client)));
271 return ccn;
272}
273
274
275/**
276 * Bind incoming channel to this client, and notify client about
277 * incoming connection. Caller is responsible for notifying the other
278 * peer about our acceptance of the channel.
279 *
280 * @param c client to bind to
281 * @param ch channel to be bound
282 * @param dest peer that establishes the connection
283 * @param port port number
284 * @param options options
285 * @return local channel number assigned to the new client
286 */
287struct GNUNET_CADET_ClientChannelNumber
288GSC_bind (struct CadetClient *c,
289 struct CadetChannel *ch,
290 struct CadetPeer *dest,
291 const struct GNUNET_HashCode *port,
292 uint32_t options)
293{
294 struct GNUNET_MQ_Envelope *env;
295 struct GNUNET_CADET_LocalChannelCreateMessage *cm;
296 struct GNUNET_CADET_ClientChannelNumber ccn;
297
298 ccn = client_get_next_ccn (c);
299 GNUNET_assert (GNUNET_YES ==
300 GNUNET_CONTAINER_multihashmap32_put (c->channels,
301 ntohl (ccn.channel_of_client),
302 ch,
303 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
304 LOG (GNUNET_ERROR_TYPE_DEBUG,
305 "Accepting incoming %s from %s on open port %s (%u), assigning ccn %X\n",
306 GCCH_2s (ch),
307 GCP_2s (dest),
308 GNUNET_h2s (port),
309 (uint32_t) ntohl (options),
310 (uint32_t) ntohl (ccn.channel_of_client));
311 /* notify local client about incoming connection! */
312 env = GNUNET_MQ_msg (cm,
313 GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_CREATE);
314 cm->ccn = ccn;
315 cm->port = *port;
316 cm->opt = htonl (options);
317 cm->peer = *GCP_get_id (dest);
318 GSC_send_to_client (c,
319 env);
320 return ccn;
321}
322
323
324/**
325 * Callback invoked on all peers to destroy all tunnels
326 * that may still exist.
327 *
328 * @param cls NULL
329 * @param pid identify of a peer
330 * @param value a `struct CadetPeer` that may still have a tunnel
331 * @return #GNUNET_OK (iterate over all entries)
332 */
333static int
334destroy_tunnels_now (void *cls,
335 const struct GNUNET_PeerIdentity *pid,
336 void *value)
337{
338 struct CadetPeer *cp = value;
339 struct CadetTunnel *t = GCP_get_tunnel (cp,
340 GNUNET_NO);
341
342 if (NULL != t)
343 GCT_destroy_tunnel_now (t);
344 return GNUNET_OK;
345}
346
347
348/**
349 * Callback invoked on all peers to destroy all tunnels
350 * that may still exist.
351 *
352 * @param cls NULL
353 * @param pid identify of a peer
354 * @param value a `struct CadetPeer` that may still have a tunnel
355 * @return #GNUNET_OK (iterate over all entries)
356 */
357static int
358destroy_paths_now (void *cls,
359 const struct GNUNET_PeerIdentity *pid,
360 void *value)
361{
362 struct CadetPeer *cp = value;
363
364 GCP_drop_owned_paths (cp);
365 return GNUNET_OK;
366}
367
368
369/**
370 * Shutdown everything once the clients have disconnected.
371 */
372static void
373shutdown_rest ()
374{
375 if (NULL != stats)
376 {
377 GNUNET_STATISTICS_destroy (stats,
378 GNUNET_NO);
379 stats = NULL;
380 }
381 if (NULL != open_ports)
382 {
383 GNUNET_CONTAINER_multihashmap_destroy (open_ports);
384 open_ports = NULL;
385 }
386 if (NULL != loose_channels)
387 {
388 GNUNET_CONTAINER_multihashmap_destroy (loose_channels);
389 loose_channels = NULL;
390 }
391 /* Destroy tunnels. Note that all channels must be destroyed first! */
392 GCP_iterate_all (&destroy_tunnels_now,
393 NULL);
394 /* All tunnels, channels, connections and CORE must be down before this point. */
395 GCP_iterate_all (&destroy_paths_now,
396 NULL);
397 /* All paths, tunnels, channels, connections and CORE must be down before this point. */
398 GCP_destroy_all_peers ();
399 if (NULL != peers)
400 {
401 GNUNET_CONTAINER_multipeermap_destroy (peers);
402 peers = NULL;
403 }
404 if (NULL != connections)
405 {
406 GNUNET_CONTAINER_multishortmap_destroy (connections);
407 connections = NULL;
408 }
409 if (NULL != ats_ch)
410 {
411 GNUNET_ATS_connectivity_done (ats_ch);
412 ats_ch = NULL;
413 }
414 GCD_shutdown ();
415 GCH_shutdown ();
416 GNUNET_free_non_null (my_private_key);
417 my_private_key = NULL;
418}
419
420
421/**
422 * Task run during shutdown.
423 *
424 * @param cls unused
425 */
426static void
427shutdown_task (void *cls)
428{
429 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
430 "Shutting down\n");
431 shutting_down = GNUNET_YES;
432 GCO_shutdown ();
433 if (NULL == clients_head)
434 shutdown_rest ();
435}
436
437
438/**
439 * We had a remote connection @a value to port @a port before
440 * client @a cls opened port @a port. Bind them now.
441 *
442 * @param cls the `struct CadetClient`
443 * @param port the port
444 * @param value the `struct CadetChannel`
445 * @return #GNUNET_YES (iterate over all such channels)
446 */
447static int
448bind_loose_channel (void *cls,
449 const struct GNUNET_HashCode *port,
450 void *value)
451{
452 struct CadetClient *c = cls;
453 struct CadetChannel *ch = value;
454
455 GCCH_bind (ch,
456 c);
457 GNUNET_assert (GNUNET_YES ==
458 GNUNET_CONTAINER_multihashmap_remove (loose_channels,
459 port,
460 value));
461 return GNUNET_YES;
462}
463
464
465/**
466 * Handle port open request. Creates a mapping from the
467 * port to the respective client and checks whether we have
468 * loose channels trying to bind to the port. If so, those
469 * are bound.
470 *
471 * @param cls Identification of the client.
472 * @param pmsg The actual message.
473 */
474static void
475handle_port_open (void *cls,
476 const struct GNUNET_CADET_PortMessage *pmsg)
477{
478 struct CadetClient *c = cls;
479
480 LOG (GNUNET_ERROR_TYPE_DEBUG,
481 "Open port %s requested by %s\n",
482 GNUNET_h2s (&pmsg->port),
483 GSC_2s (c));
484 if (NULL == c->ports)
485 c->ports = GNUNET_CONTAINER_multihashmap_create (4,
486 GNUNET_NO);
487 if (GNUNET_OK !=
488 GNUNET_CONTAINER_multihashmap_put (c->ports,
489 &pmsg->port,
490 c,
491 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
492 {
493 GNUNET_break (0);
494 GNUNET_SERVICE_client_drop (c->client);
495 return;
496 }
497 (void) GNUNET_CONTAINER_multihashmap_put (open_ports,
498 &pmsg->port,
499 c,
500 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
501 GNUNET_CONTAINER_multihashmap_get_multiple (loose_channels,
502 &pmsg->port,
503 &bind_loose_channel,
504 c);
505 GNUNET_SERVICE_client_continue (c->client);
506}
507
508
509/**
510 * Handler for port close requests. Marks this port as closed
511 * (unless of course we have another client with the same port
512 * open). Note that existing channels accepted on the port are
513 * not affected.
514 *
515 * @param cls Identification of the client.
516 * @param pmsg The actual message.
517 */
518static void
519handle_port_close (void *cls,
520 const struct GNUNET_CADET_PortMessage *pmsg)
521{
522 struct CadetClient *c = cls;
523
524 LOG (GNUNET_ERROR_TYPE_DEBUG,
525 "Closing port %s as requested by %s\n",
526 GNUNET_h2s (&pmsg->port),
527 GSC_2s (c));
528 if (GNUNET_YES !=
529 GNUNET_CONTAINER_multihashmap_remove (c->ports,
530 &pmsg->port,
531 c))
532 {
533 GNUNET_break (0);
534 GNUNET_SERVICE_client_drop (c->client);
535 return;
536 }
537 GNUNET_assert (GNUNET_YES ==
538 GNUNET_CONTAINER_multihashmap_remove (open_ports,
539 &pmsg->port,
540 c));
541 GNUNET_SERVICE_client_continue (c->client);
542}
543
544
545/**
546 * Handler for requests for us creating a new channel to another peer and port.
547 *
548 * @param cls Identification of the client.
549 * @param tcm The actual message.
550 */
551static void
552handle_channel_create (void *cls,
553 const struct GNUNET_CADET_LocalChannelCreateMessage *tcm)
554{
555 struct CadetClient *c = cls;
556 struct CadetChannel *ch;
557
558 if (ntohl (tcm->ccn.channel_of_client) < GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
559 {
560 /* Channel ID not in allowed range. */
561 GNUNET_break (0);
562 GNUNET_SERVICE_client_drop (c->client);
563 return;
564 }
565 ch = lookup_channel (c,
566 tcm->ccn);
567 if (NULL != ch)
568 {
569 /* Channel ID already in use. Not allowed. */
570 GNUNET_break (0);
571 GNUNET_SERVICE_client_drop (c->client);
572 return;
573 }
574 LOG (GNUNET_ERROR_TYPE_DEBUG,
575 "New channel to %s at port %s requested by %s\n",
576 GNUNET_i2s (&tcm->peer),
577 GNUNET_h2s (&tcm->port),
578 GSC_2s (c));
579
580 /* Create channel */
581 ch = GCCH_channel_local_new (c,
582 tcm->ccn,
583 GCP_get (&tcm->peer,
584 GNUNET_YES),
585 &tcm->port,
586 ntohl (tcm->opt));
587 if (NULL == ch)
588 {
589 GNUNET_break (0);
590 GNUNET_SERVICE_client_drop (c->client);
591 return;
592 }
593 GNUNET_assert (GNUNET_YES ==
594 GNUNET_CONTAINER_multihashmap32_put (c->channels,
595 ntohl (tcm->ccn.channel_of_client),
596 ch,
597 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
598
599 GNUNET_SERVICE_client_continue (c->client);
600}
601
602
603/**
604 * Handler for requests of destroying an existing channel.
605 *
606 * @param cls client identification of the client
607 * @param msg the actual message
608 */
609static void
610handle_channel_destroy (void *cls,
611 const struct GNUNET_CADET_LocalChannelDestroyMessage *msg)
612{
613 struct CadetClient *c = cls;
614 struct CadetChannel *ch;
615
616 ch = lookup_channel (c,
617 msg->ccn);
618 if (NULL == ch)
619 {
620 /* Client attempted to destroy unknown channel.
621 Can happen if the other side went down at the same time.*/
622 LOG (GNUNET_ERROR_TYPE_DEBUG,
623 "%s tried to destroy unknown channel %X\n",
624 GSC_2s(c),
625 (uint32_t) ntohl (msg->ccn.channel_of_client));
626 return;
627 }
628 LOG (GNUNET_ERROR_TYPE_DEBUG,
629 "%s is destroying %s\n",
630 GSC_2s(c),
631 GCCH_2s (ch));
632 GNUNET_assert (GNUNET_YES ==
633 GNUNET_CONTAINER_multihashmap32_remove (c->channels,
634 ntohl (msg->ccn.channel_of_client),
635 ch));
636 GCCH_channel_local_destroy (ch,
637 c,
638 msg->ccn);
639 GNUNET_SERVICE_client_continue (c->client);
640}
641
642
643/**
644 * Check for client traffic data message is well-formed.
645 *
646 * @param cls identification of the client
647 * @param msg the actual message
648 * @return #GNUNET_OK if @a msg is OK, #GNUNET_SYSERR if not
649 */
650static int
651check_local_data (void *cls,
652 const struct GNUNET_CADET_LocalData *msg)
653{
654 size_t payload_size;
655 size_t payload_claimed_size;
656 const char *buf;
657 struct GNUNET_MessageHeader pa;
658
659 /* FIXME: what is the format we shall allow for @a msg?
660 ONE payload item or multiple? Seems current cadet_api
661 at least in theory allows more than one. Next-gen
662 cadet_api will likely no more, so we could then
663 simplify this mess again. */
664 /* Sanity check for message size */
665 payload_size = ntohs (msg->header.size) - sizeof (*msg);
666 buf = (const char *) &msg[1];
667 while (payload_size >= sizeof (struct GNUNET_MessageHeader))
668 {
669 /* need to memcpy() for alignment */
670 GNUNET_memcpy (&pa,
671 buf,
672 sizeof (pa));
673 payload_claimed_size = ntohs (pa.size);
674 if ( (payload_size < payload_claimed_size) ||
675 (payload_claimed_size < sizeof (struct GNUNET_MessageHeader)) ||
676 (GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE < payload_claimed_size) )
677 {
678 GNUNET_break (0);
679 LOG (GNUNET_ERROR_TYPE_DEBUG,
680 "Local data of %u total size had sub-message %u at %u with %u bytes\n",
681 ntohs (msg->header.size),
682 ntohs (pa.type),
683 (unsigned int) (buf - (const char *) &msg[1]),
684 (unsigned int) payload_claimed_size);
685 return GNUNET_SYSERR;
686 }
687 payload_size -= payload_claimed_size;
688 buf += payload_claimed_size;
689 }
690 if (0 != payload_size)
691 {
692 GNUNET_break_op (0);
693 return GNUNET_SYSERR;
694 }
695 return GNUNET_OK;
696}
697
698
699/**
700 * Handler for client payload traffic to be send on a channel to
701 * another peer.
702 *
703 * @param cls identification of the client
704 * @param msg the actual message
705 */
706static void
707handle_local_data (void *cls,
708 const struct GNUNET_CADET_LocalData *msg)
709{
710 struct CadetClient *c = cls;
711 struct CadetChannel *ch;
712 size_t payload_size;
713 const char *buf;
714
715 ch = lookup_channel (c,
716 msg->ccn);
717 if (NULL == ch)
718 {
719 /* Channel does not exist (anymore) */
720 LOG (GNUNET_ERROR_TYPE_WARNING,
721 "Dropping payload for channel %u from client (channel unknown, other endpoint may have disconnected)\n",
722 (unsigned int) ntohl (msg->ccn.channel_of_client));
723 GNUNET_SERVICE_client_continue (c->client);
724 return;
725 }
726 payload_size = ntohs (msg->header.size) - sizeof (*msg);
727 buf = (const char *) &msg[1];
728 LOG (GNUNET_ERROR_TYPE_DEBUG,
729 "Received %u bytes payload from %s for %s\n",
730 (unsigned int) payload_size,
731 GSC_2s (c),
732 GCCH_2s (ch));
733 if (GNUNET_OK !=
734 GCCH_handle_local_data (ch,
735 msg->ccn,
736 buf,
737 payload_size))
738 {
739 GNUNET_SERVICE_client_drop (c->client);
740 return;
741 }
742 GNUNET_SERVICE_client_continue (c->client);
743}
744
745
746/**
747 * Handler for client's ACKs for payload traffic.
748 *
749 * @param cls identification of the client.
750 * @param msg The actual message.
751 */
752static void
753handle_local_ack (void *cls,
754 const struct GNUNET_CADET_LocalAck *msg)
755{
756 struct CadetClient *c = cls;
757 struct CadetChannel *ch;
758
759 ch = lookup_channel (c,
760 msg->ccn);
761 if (NULL == ch)
762 {
763 /* Channel does not exist! */
764 GNUNET_break (0);
765 GNUNET_SERVICE_client_drop (c->client);
766 return;
767 }
768 LOG (GNUNET_ERROR_TYPE_DEBUG,
769 "Got a local ACK from %s for %s\n",
770 GSC_2s(c),
771 GCCH_2s (ch));
772 GCCH_handle_local_ack (ch,
773 msg->ccn);
774 GNUNET_SERVICE_client_continue (c->client);
775}
776
777
778/**
779 * Iterator over all peers to send a monitoring client info about each peer.
780 *
781 * @param cls Closure ().
782 * @param peer Peer ID (tunnel remote peer).
783 * @param value Peer info.
784 * @return #GNUNET_YES, to keep iterating.
785 */
786static int
787get_all_peers_iterator (void *cls,
788 const struct GNUNET_PeerIdentity *peer,
789 void *value)
790{
791 struct CadetClient *c = cls;
792 struct CadetPeer *p = value;
793 struct GNUNET_MQ_Envelope *env;
794 struct GNUNET_CADET_LocalInfoPeer *msg;
795
796 env = GNUNET_MQ_msg (msg,
797 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS);
798 msg->destination = *peer;
799 msg->paths = htons (GCP_count_paths (p));
800 msg->tunnel = htons (NULL != GCP_get_tunnel (p,
801 GNUNET_NO));
802 GNUNET_MQ_send (c->mq,
803 env);
804 return GNUNET_YES;
805}
806
807
808/**
809 * Handler for client's INFO PEERS request.
810 *
811 * @param cls Identification of the client.
812 * @param message The actual message.
813 */
814static void
815handle_get_peers (void *cls,
816 const struct GNUNET_MessageHeader *message)
817{
818 struct CadetClient *c = cls;
819 struct GNUNET_MQ_Envelope *env;
820 struct GNUNET_MessageHeader *reply;
821
822 GCP_iterate_all (&get_all_peers_iterator,
823 c);
824 env = GNUNET_MQ_msg (reply,
825 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS);
826 GNUNET_MQ_send (c->mq,
827 env);
828 GNUNET_SERVICE_client_continue (c->client);
829}
830
831
832/**
833 * Iterator over all paths of a peer to build an InfoPeer message.
834 * Message contains blocks of peers, first not included.
835 *
836 * @param cls message queue for transmission
837 * @param path Path itself
838 * @param off offset of the peer on @a path
839 * @return #GNUNET_YES if should keep iterating.
840 * #GNUNET_NO otherwise.
841 */
842static int
843path_info_iterator (void *cls,
844 struct CadetPeerPath *path,
845 unsigned int off)
846{
847 struct GNUNET_MQ_Handle *mq = cls;
848 struct GNUNET_MQ_Envelope *env;
849 struct GNUNET_MessageHeader *resp;
850 struct GNUNET_PeerIdentity *id;
851 uint16_t path_size;
852 unsigned int i;
853 unsigned int path_length;
854
855 path_length = GCPP_get_length (path);
856 path_size = sizeof (struct GNUNET_PeerIdentity) * (path_length - 1);
857 if (sizeof (*resp) + path_size > UINT16_MAX)
858 {
859 LOG (GNUNET_ERROR_TYPE_WARNING,
860 "Path of %u entries is too long for info message\n",
861 path_length);
862 return GNUNET_YES;
863 }
864 env = GNUNET_MQ_msg_extra (resp,
865 path_size,
866 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER);
867 id = (struct GNUNET_PeerIdentity *) &resp[1];
868
869 /* Don't copy first peer. First peer is always the local one. Last
870 * peer is always the destination (leave as 0, EOL).
871 */
872 for (i = 0; i < off; i++)
873 id[i] = *GCP_get_id (GCPP_get_peer_at_offset (path,
874 i + 1));
875 GNUNET_MQ_send (mq,
876 env);
877 return GNUNET_YES;
878}
879
880
881/**
882 * Handler for client's SHOW_PEER request.
883 *
884 * @param cls Identification of the client.
885 * @param msg The actual message.
886 */
887static void
888handle_show_peer (void *cls,
889 const struct GNUNET_CADET_LocalInfo *msg)
890{
891 struct CadetClient *c = cls;
892 struct CadetPeer *p;
893 struct GNUNET_MQ_Envelope *env;
894 struct GNUNET_MessageHeader *resp;
895
896 p = GCP_get (&msg->peer,
897 GNUNET_NO);
898 if (NULL != p)
899 GCP_iterate_paths (p,
900 &path_info_iterator,
901 c->mq);
902 /* Send message with 0/0 to indicate the end */
903 env = GNUNET_MQ_msg (resp,
904 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER_END);
905 GNUNET_MQ_send (c->mq,
906 env);
907 GNUNET_SERVICE_client_continue (c->client);
908}
909
910
911/**
912 * Iterator over all tunnels to send a monitoring client info about each tunnel.
913 *
914 * @param cls Closure ().
915 * @param peer Peer ID (tunnel remote peer).
916 * @param value a `struct CadetPeer`
917 * @return #GNUNET_YES, to keep iterating.
918 */
919static int
920get_all_tunnels_iterator (void *cls,
921 const struct GNUNET_PeerIdentity *peer,
922 void *value)
923{
924 struct CadetClient *c = cls;
925 struct CadetPeer *p = value;
926 struct GNUNET_MQ_Envelope *env;
927 struct GNUNET_CADET_LocalInfoTunnel *msg;
928 struct CadetTunnel *t;
929
930 t = GCP_get_tunnel (p,
931 GNUNET_NO);
932 if (NULL == t)
933 return GNUNET_YES;
934 env = GNUNET_MQ_msg (msg,
935 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS);
936 msg->destination = *peer;
937 msg->channels = htonl (GCT_count_channels (t));
938 msg->connections = htonl (GCT_count_any_connections (t));
939 msg->cstate = htons (0);
940 msg->estate = htons ((uint16_t) GCT_get_estate (t));
941 GNUNET_MQ_send (c->mq,
942 env);
943 return GNUNET_YES;
944}
945
946
947/**
948 * Handler for client's #GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS request.
949 *
950 * @param cls client Identification of the client.
951 * @param message The actual message.
952 */
953static void
954handle_info_tunnels (void *cls,
955 const struct GNUNET_MessageHeader *message)
956{
957 struct CadetClient *c = cls;
958 struct GNUNET_MQ_Envelope *env;
959 struct GNUNET_MessageHeader *reply;
960
961 GCP_iterate_all (&get_all_tunnels_iterator,
962 c);
963 env = GNUNET_MQ_msg (reply,
964 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS);
965 GNUNET_MQ_send (c->mq,
966 env);
967 GNUNET_SERVICE_client_continue (c->client);
968}
969
970
971/**
972 * Update the message with information about the connection.
973 *
974 * @param cls a `struct GNUNET_CADET_LocalInfoTunnel` message to update
975 * @param ct a connection about which we should store information in @a cls
976 */
977static void
978iter_connection (void *cls,
979 struct CadetTConnection *ct)
980{
981 struct GNUNET_CADET_LocalInfoTunnel *msg = cls;
982 struct CadetConnection *cc = ct->cc;
983 struct GNUNET_CADET_ConnectionTunnelIdentifier *h;
984
985 h = (struct GNUNET_CADET_ConnectionTunnelIdentifier *) &msg[1];
986 h[msg->connections++] = *(GCC_get_id (cc));
987}
988
989
990/**
991 * Update the message with information about the channel.
992 *
993 * @param cls a `struct GNUNET_CADET_LocalInfoTunnel` message to update
994 * @param ch a channel about which we should store information in @a cls
995 */
996static void
997iter_channel (void *cls,
998 struct CadetChannel *ch)
999{
1000 struct GNUNET_CADET_LocalInfoTunnel *msg = cls;
1001 struct GNUNET_CADET_ConnectionTunnelIdentifier *h = (struct GNUNET_CADET_ConnectionTunnelIdentifier *) &msg[1];
1002 struct GNUNET_CADET_ChannelTunnelNumber *chn
1003 = (struct GNUNET_CADET_ChannelTunnelNumber *) &h[msg->connections];
1004
1005 chn[msg->channels++] = GCCH_get_id (ch);
1006}
1007
1008
1009/**
1010 * Handler for client's #GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL request.
1011 *
1012 * @param cls Identification of the client.
1013 * @param msg The actual message.
1014 */
1015static void
1016handle_info_tunnel (void *cls,
1017 const struct GNUNET_CADET_LocalInfo *msg)
1018{
1019 struct CadetClient *c = cls;
1020 struct GNUNET_MQ_Envelope *env;
1021 struct GNUNET_CADET_LocalInfoTunnel *resp;
1022 struct CadetTunnel *t;
1023 struct CadetPeer *p;
1024 unsigned int ch_n;
1025 unsigned int c_n;
1026
1027 p = GCP_get (&msg->peer,
1028 GNUNET_NO);
1029 t = GCP_get_tunnel (p,
1030 GNUNET_NO);
1031 if (NULL == t)
1032 {
1033 /* We don't know the tunnel */
1034 struct GNUNET_MQ_Envelope *env;
1035 struct GNUNET_CADET_LocalInfoTunnel *warn;
1036
1037 LOG (GNUNET_ERROR_TYPE_INFO,
1038 "Tunnel to %s unknown\n",
1039 GNUNET_i2s_full (&msg->peer));
1040 env = GNUNET_MQ_msg (warn,
1041 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL);
1042 warn->destination = msg->peer;
1043 GNUNET_MQ_send (c->mq,
1044 env);
1045 GNUNET_SERVICE_client_continue (c->client);
1046 return;
1047 }
1048
1049 /* Initialize context */
1050 ch_n = GCT_count_channels (t);
1051 c_n = GCT_count_any_connections (t);
1052 env = GNUNET_MQ_msg_extra (resp,
1053 c_n * sizeof (struct GNUNET_CADET_ConnectionTunnelIdentifier) +
1054 ch_n * sizeof (struct GNUNET_CADET_ChannelTunnelNumber),
1055 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL);
1056 resp->destination = msg->peer;
1057 /* Do not reorder! #iter_channel needs counters in HBO! */
1058 GCT_iterate_connections (t,
1059 &iter_connection,
1060 resp);
1061 GCT_iterate_channels (t,
1062 &iter_channel,
1063 resp);
1064 resp->connections = htonl (resp->connections);
1065 resp->channels = htonl (resp->channels);
1066 resp->cstate = htons (0);
1067 resp->estate = htons (GCT_get_estate (t));
1068 GNUNET_MQ_send (c->mq,
1069 env);
1070 GNUNET_SERVICE_client_continue (c->client);
1071}
1072
1073
1074/**
1075 * Iterator over all peers to dump info for each peer.
1076 *
1077 * @param cls Closure (unused).
1078 * @param peer Peer ID (tunnel remote peer).
1079 * @param value Peer info.
1080 *
1081 * @return #GNUNET_YES, to keep iterating.
1082 */
1083static int
1084show_peer_iterator (void *cls,
1085 const struct GNUNET_PeerIdentity *peer,
1086 void *value)
1087{
1088 struct CadetPeer *p = value;
1089 struct CadetTunnel *t;
1090
1091 t = GCP_get_tunnel (p,
1092 GNUNET_NO);
1093 if (NULL != t)
1094 GCT_debug (t,
1095 GNUNET_ERROR_TYPE_ERROR);
1096 LOG (GNUNET_ERROR_TYPE_ERROR, "\n");
1097 return GNUNET_YES;
1098}
1099
1100
1101/**
1102 * Handler for client's INFO_DUMP request.
1103 *
1104 * @param cls Identification of the client.
1105 * @param message The actual message.
1106 */
1107static void
1108handle_info_dump (void *cls,
1109 const struct GNUNET_MessageHeader *message)
1110{
1111 struct CadetClient *c = cls;
1112
1113 LOG (GNUNET_ERROR_TYPE_INFO,
1114 "Received dump info request from client %u\n",
1115 c->id);
1116
1117 LOG (GNUNET_ERROR_TYPE_ERROR,
1118 "*************************** DUMP START ***************************\n");
1119 for (struct CadetClient *ci = clients_head;
1120 NULL != ci;
1121 ci = ci->next)
1122 {
1123 LOG (GNUNET_ERROR_TYPE_ERROR,
1124 "Client %u (%p), handle: %p, ports: %u, channels: %u\n",
1125 ci->id,
1126 ci,
1127 ci->client,
1128 (NULL != c->ports)
1129 ? GNUNET_CONTAINER_multihashmap_size (ci->ports)
1130 : 0,
1131 GNUNET_CONTAINER_multihashmap32_size (ci->channels));
1132 }
1133 LOG (GNUNET_ERROR_TYPE_ERROR, "***************************\n");
1134 GCP_iterate_all (&show_peer_iterator,
1135 NULL);
1136
1137 LOG (GNUNET_ERROR_TYPE_ERROR,
1138 "**************************** DUMP END ****************************\n");
1139
1140 GNUNET_SERVICE_client_continue (c->client);
1141}
1142
1143
1144
1145/**
1146 * Callback called when a client connects to the service.
1147 *
1148 * @param cls closure for the service
1149 * @param client the new client that connected to the service
1150 * @param mq the message queue used to send messages to the client
1151 * @return @a c
1152 */
1153static void *
1154client_connect_cb (void *cls,
1155 struct GNUNET_SERVICE_Client *client,
1156 struct GNUNET_MQ_Handle *mq)
1157{
1158 struct CadetClient *c;
1159
1160 c = GNUNET_new (struct CadetClient);
1161 c->client = client;
1162 c->mq = mq;
1163 c->id = next_client_id++; /* overflow not important: just for debug */
1164 c->channels
1165 = GNUNET_CONTAINER_multihashmap32_create (32);
1166 GNUNET_CONTAINER_DLL_insert (clients_head,
1167 clients_tail,
1168 c);
1169 GNUNET_STATISTICS_update (stats,
1170 "# clients",
1171 +1,
1172 GNUNET_NO);
1173 LOG (GNUNET_ERROR_TYPE_DEBUG,
1174 "%s connected\n",
1175 GSC_2s (c));
1176 return c;
1177}
1178
1179
1180/**
1181 * A channel was destroyed by the other peer. Tell our client.
1182 *
1183 * @param c client that lost a channel
1184 * @param ccn channel identification number for the client
1185 * @param ch the channel object
1186 */
1187void
1188GSC_handle_remote_channel_destroy (struct CadetClient *c,
1189 struct GNUNET_CADET_ClientChannelNumber ccn,
1190 struct CadetChannel *ch)
1191{
1192 struct GNUNET_MQ_Envelope *env;
1193 struct GNUNET_CADET_LocalChannelDestroyMessage *tdm;
1194
1195 env = GNUNET_MQ_msg (tdm,
1196 GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY);
1197 tdm->ccn = ccn;
1198 GSC_send_to_client (c,
1199 env);
1200 GNUNET_assert (GNUNET_YES ==
1201 GNUNET_CONTAINER_multihashmap32_remove (c->channels,
1202 ntohl (ccn.channel_of_client),
1203 ch));
1204}
1205
1206
1207/**
1208 * A client that created a loose channel that was not bound to a port
1209 * disconnected, drop it from the #loose_channels list.
1210 *
1211 * @param port the port the channel was trying to bind to
1212 * @param ch the channel that was lost
1213 */
1214void
1215GSC_drop_loose_channel (const struct GNUNET_HashCode *port,
1216 struct CadetChannel *ch)
1217{
1218 GNUNET_assert (GNUNET_YES ==
1219 GNUNET_CONTAINER_multihashmap_remove (loose_channels,
1220 port,
1221 ch));
1222}
1223
1224
1225/**
1226 * Iterator for deleting each channel whose client endpoint disconnected.
1227 *
1228 * @param cls Closure (client that has disconnected).
1229 * @param key The local channel id in host byte order
1230 * @param value The value stored at the key (channel to destroy).
1231 * @return #GNUNET_OK, keep iterating.
1232 */
1233static int
1234channel_destroy_iterator (void *cls,
1235 uint32_t key,
1236 void *value)
1237{
1238 struct CadetClient *c = cls;
1239 struct GNUNET_CADET_ClientChannelNumber ccn;
1240 struct CadetChannel *ch = value;
1241
1242 LOG (GNUNET_ERROR_TYPE_DEBUG,
1243 "Destroying %s, due to %s disconnecting.\n",
1244 GCCH_2s (ch),
1245 GSC_2s (c));
1246 ccn.channel_of_client = htonl (key);
1247 GCCH_channel_local_destroy (ch,
1248 c,
1249 ccn);
1250 GNUNET_assert (GNUNET_YES ==
1251 GNUNET_CONTAINER_multihashmap32_remove (c->channels,
1252 key,
1253 ch));
1254 return GNUNET_OK;
1255}
1256
1257
1258/**
1259 * Remove client's ports from the global hashmap on disconnect.
1260 *
1261 * @param cls Closure (unused).
1262 * @param key the port.
1263 * @param value the `struct CadetClient` to remove
1264 * @return #GNUNET_OK, keep iterating.
1265 */
1266static int
1267client_release_ports (void *cls,
1268 const struct GNUNET_HashCode *key,
1269 void *value)
1270{
1271 struct CadetClient *c = value;
1272
1273 LOG (GNUNET_ERROR_TYPE_DEBUG,
1274 "Closing port %s due to %s disconnect.\n",
1275 GNUNET_h2s (key),
1276 GSC_2s (c));
1277 GNUNET_assert (GNUNET_YES ==
1278 GNUNET_CONTAINER_multihashmap_remove (open_ports,
1279 key,
1280 value));
1281 GNUNET_assert (GNUNET_YES ==
1282 GNUNET_CONTAINER_multihashmap_remove (c->ports,
1283 key,
1284 value));
1285 return GNUNET_OK;
1286}
1287
1288
1289/**
1290 * Callback called when a client disconnected from the service
1291 *
1292 * @param cls closure for the service
1293 * @param client the client that disconnected
1294 * @param internal_cls should be equal to @a c
1295 */
1296static void
1297client_disconnect_cb (void *cls,
1298 struct GNUNET_SERVICE_Client *client,
1299 void *internal_cls)
1300{
1301 struct CadetClient *c = internal_cls;
1302
1303 GNUNET_assert (c->client == client);
1304 LOG (GNUNET_ERROR_TYPE_DEBUG,
1305 "%s is disconnecting.\n",
1306 GSC_2s (c));
1307 if (NULL != c->channels)
1308 {
1309 GNUNET_CONTAINER_multihashmap32_iterate (c->channels,
1310 &channel_destroy_iterator,
1311 c);
1312 GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap32_size (c->channels));
1313 GNUNET_CONTAINER_multihashmap32_destroy (c->channels);
1314 }
1315 if (NULL != c->ports)
1316 {
1317 GNUNET_CONTAINER_multihashmap_iterate (c->ports,
1318 &client_release_ports,
1319 c);
1320 GNUNET_CONTAINER_multihashmap_destroy (c->ports);
1321 }
1322 GNUNET_CONTAINER_DLL_remove (clients_head,
1323 clients_tail,
1324 c);
1325 GNUNET_STATISTICS_update (stats,
1326 "# clients",
1327 -1,
1328 GNUNET_NO);
1329 GNUNET_free (c);
1330 if ( (NULL == clients_head) &&
1331 (GNUNET_YES == shutting_down) )
1332 shutdown_rest ();
1333}
1334
1335
1336/**
1337 * Setup CADET internals.
1338 *
1339 * @param cls closure
1340 * @param server the initialized server
1341 * @param c configuration to use
1342 */
1343static void
1344run (void *cls,
1345 const struct GNUNET_CONFIGURATION_Handle *c,
1346 struct GNUNET_SERVICE_Handle *service)
1347{
1348 cfg = c;
1349 if (GNUNET_OK !=
1350 GNUNET_CONFIGURATION_get_value_number (c,
1351 "CADET",
1352 "RATCHET_MESSAGES",
1353 &ratchet_messages))
1354 {
1355 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
1356 "CADET",
1357 "RATCHET_MESSAGES",
1358 "needs to be a number");
1359 ratchet_messages = 64;
1360 }
1361 if (GNUNET_OK !=
1362 GNUNET_CONFIGURATION_get_value_time (c,
1363 "CADET",
1364 "RATCHET_TIME",
1365 &ratchet_time))
1366 {
1367 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
1368 "CADET",
1369 "RATCHET_TIME",
1370 "need delay value");
1371 ratchet_time = GNUNET_TIME_UNIT_HOURS;
1372 }
1373 if (GNUNET_OK !=
1374 GNUNET_CONFIGURATION_get_value_time (c,
1375 "CADET",
1376 "REFRESH_CONNECTION_TIME",
1377 &keepalive_period))
1378 {
1379 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
1380 "CADET",
1381 "REFRESH_CONNECTION_TIME",
1382 "need delay value");
1383 keepalive_period = GNUNET_TIME_UNIT_MINUTES;
1384 }
1385 if (GNUNET_OK !=
1386 GNUNET_CONFIGURATION_get_value_number (c,
1387 "CADET",
1388 "DROP_PERCENT",
1389 &drop_percent))
1390 {
1391 drop_percent = 0;
1392 }
1393 else
1394 {
1395 LOG (GNUNET_ERROR_TYPE_WARNING, "**************************************\n");
1396 LOG (GNUNET_ERROR_TYPE_WARNING, "Cadet is running with DROP enabled.\n");
1397 LOG (GNUNET_ERROR_TYPE_WARNING, "This is NOT a good idea!\n");
1398 LOG (GNUNET_ERROR_TYPE_WARNING, "Remove DROP_PERCENT from config file.\n");
1399 LOG (GNUNET_ERROR_TYPE_WARNING, "**************************************\n");
1400 }
1401 my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (c);
1402 if (NULL == my_private_key)
1403 {
1404 GNUNET_break (0);
1405 GNUNET_SCHEDULER_shutdown ();
1406 return;
1407 }
1408 GNUNET_CRYPTO_eddsa_key_get_public (my_private_key,
1409 &my_full_id.public_key);
1410 stats = GNUNET_STATISTICS_create ("cadet",
1411 c);
1412 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1413 NULL);
1414 ats_ch = GNUNET_ATS_connectivity_init (c);
1415 /* FIXME: optimize code to allow GNUNET_YES here! */
1416 open_ports = GNUNET_CONTAINER_multihashmap_create (16,
1417 GNUNET_NO);
1418 loose_channels = GNUNET_CONTAINER_multihashmap_create (16,
1419 GNUNET_NO);
1420 peers = GNUNET_CONTAINER_multipeermap_create (16,
1421 GNUNET_YES);
1422 connections = GNUNET_CONTAINER_multishortmap_create (256,
1423 GNUNET_YES);
1424 GCH_init (c);
1425 GCD_init (c);
1426 GCO_init (c);
1427 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1428 "CADET started for peer %s\n",
1429 GNUNET_i2s (&my_full_id));
1430
1431}
1432
1433
1434/**
1435 * Define "main" method using service macro.
1436 */
1437GNUNET_SERVICE_MAIN
1438("cadet",
1439 GNUNET_SERVICE_OPTION_NONE,
1440 &run,
1441 &client_connect_cb,
1442 &client_disconnect_cb,
1443 NULL,
1444 GNUNET_MQ_hd_fixed_size (port_open,
1445 GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_OPEN,
1446 struct GNUNET_CADET_PortMessage,
1447 NULL),
1448 GNUNET_MQ_hd_fixed_size (port_close,
1449 GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_CLOSE,
1450 struct GNUNET_CADET_PortMessage,
1451 NULL),
1452 GNUNET_MQ_hd_fixed_size (channel_create,
1453 GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_CREATE,
1454 struct GNUNET_CADET_LocalChannelCreateMessage,
1455 NULL),
1456 GNUNET_MQ_hd_fixed_size (channel_destroy,
1457 GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY,
1458 struct GNUNET_CADET_LocalChannelDestroyMessage,
1459 NULL),
1460 GNUNET_MQ_hd_var_size (local_data,
1461 GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA,
1462 struct GNUNET_CADET_LocalData,
1463 NULL),
1464 GNUNET_MQ_hd_fixed_size (local_ack,
1465 GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK,
1466 struct GNUNET_CADET_LocalAck,
1467 NULL),
1468 GNUNET_MQ_hd_fixed_size (get_peers,
1469 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS,
1470 struct GNUNET_MessageHeader,
1471 NULL),
1472 GNUNET_MQ_hd_fixed_size (show_peer,
1473 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER,
1474 struct GNUNET_CADET_LocalInfo,
1475 NULL),
1476 GNUNET_MQ_hd_fixed_size (info_tunnels,
1477 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS,
1478 struct GNUNET_MessageHeader,
1479 NULL),
1480 GNUNET_MQ_hd_fixed_size (info_tunnel,
1481 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL,
1482 struct GNUNET_CADET_LocalInfo,
1483 NULL),
1484 GNUNET_MQ_hd_fixed_size (info_dump,
1485 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_DUMP,
1486 struct GNUNET_MessageHeader,
1487 NULL),
1488 GNUNET_MQ_handler_end ());
1489
1490/* end of gnunet-service-cadet-new.c */
diff --git a/src/cadet/gnunet-service-cadet-new_channel.c b/src/cadet/gnunet-service-cadet-new_channel.c
deleted file mode 100644
index 8769601c2..000000000
--- a/src/cadet/gnunet-service-cadet-new_channel.c
+++ /dev/null
@@ -1,2037 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2001-2017 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20/**
21 * @file cadet/gnunet-service-cadet-new_channel.c
22 * @brief logical links between CADET clients
23 * @author Bartlomiej Polot
24 * @author Christian Grothoff
25 *
26 * TODO:
27 * - Congestion/flow control:
28 * + estimate max bandwidth using bursts and use to for CONGESTION CONTROL!
29 * (and figure out how/where to use this!)
30 * + figure out flow control without ACKs (unreliable traffic!)
31 * - revisit handling of 'unbuffered' traffic!
32 * (need to push down through tunnel into connection selection)
33 * - revisit handling of 'buffered' traffic: 4 is a rather small buffer; maybe
34 * reserve more bits in 'options' to allow for buffer size control?
35 */
36#include "platform.h"
37#include "gnunet_util_lib.h"
38#include "cadet.h"
39#include "gnunet_statistics_service.h"
40#include "gnunet-service-cadet-new.h"
41#include "gnunet-service-cadet-new_channel.h"
42#include "gnunet-service-cadet-new_connection.h"
43#include "gnunet-service-cadet-new_tunnels.h"
44#include "gnunet-service-cadet-new_peer.h"
45#include "gnunet-service-cadet-new_paths.h"
46
47#define LOG(level,...) GNUNET_log_from (level,"cadet-chn",__VA_ARGS__)
48
49/**
50 * How long do we initially wait before retransmitting?
51 */
52#define CADET_INITIAL_RETRANSMIT_TIME GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 250)
53
54/**
55 * How long do we wait before dropping state about incoming
56 * connection to closed port?
57 */
58#define TIMEOUT_CLOSED_PORT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30)
59
60/**
61 * How long do we wait at least before retransmitting ever?
62 */
63#define MIN_RTT_DELAY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 75)
64
65/**
66 * Maximum message ID into the future we accept for out-of-order messages.
67 * If the message is more than this into the future, we drop it. This is
68 * important both to detect values that are actually in the past, as well
69 * as to limit adversarially triggerable memory consumption.
70 *
71 * Note that right now we have "max_pending_messages = 4" hard-coded in
72 * the logic below, so a value of 4 would suffice here. But we plan to
73 * allow larger windows in the future...
74 */
75#define MAX_OUT_OF_ORDER_DISTANCE 1024
76
77
78/**
79 * All the states a channel can be in.
80 */
81enum CadetChannelState
82{
83 /**
84 * Uninitialized status, should never appear in operation.
85 */
86 CADET_CHANNEL_NEW,
87
88 /**
89 * Channel is to a port that is not open, we're waiting for the
90 * port to be opened.
91 */
92 CADET_CHANNEL_LOOSE,
93
94 /**
95 * CHANNEL_OPEN message sent, waiting for CHANNEL_OPEN_ACK.
96 */
97 CADET_CHANNEL_OPEN_SENT,
98
99 /**
100 * Connection confirmed, ready to carry traffic.
101 */
102 CADET_CHANNEL_READY
103};
104
105
106/**
107 * Info needed to retry a message in case it gets lost.
108 * Note that we DO use this structure also for unreliable
109 * messages.
110 */
111struct CadetReliableMessage
112{
113 /**
114 * Double linked list, FIFO style
115 */
116 struct CadetReliableMessage *next;
117
118 /**
119 * Double linked list, FIFO style
120 */
121 struct CadetReliableMessage *prev;
122
123 /**
124 * Which channel is this message in?
125 */
126 struct CadetChannel *ch;
127
128 /**
129 * Entry in the tunnels queue for this message, NULL if it has left
130 * the tunnel. Used to cancel transmission in case we receive an
131 * ACK in time.
132 */
133 struct CadetTunnelQueueEntry *qe;
134
135 /**
136 * Data message we are trying to send.
137 */
138 struct GNUNET_CADET_ChannelAppDataMessage *data_message;
139
140 /**
141 * How soon should we retry if we fail to get an ACK?
142 * Messages in the queue are sorted by this value.
143 */
144 struct GNUNET_TIME_Absolute next_retry;
145
146 /**
147 * How long do we wait for an ACK after transmission?
148 * Use for the back-off calculation.
149 */
150 struct GNUNET_TIME_Relative retry_delay;
151
152 /**
153 * Time when we first successfully transmitted the message
154 * (that is, set @e num_transmissions to 1).
155 */
156 struct GNUNET_TIME_Absolute first_transmission_time;
157
158 /**
159 * Identifier of the connection that this message took when it
160 * was first transmitted. Only useful if @e num_transmissions is 1.
161 */
162 struct GNUNET_CADET_ConnectionTunnelIdentifier connection_taken;
163
164 /**
165 * How often was this message transmitted? #GNUNET_SYSERR if there
166 * was an error transmitting the message, #GNUNET_NO if it was not
167 * yet transmitted ever, otherwise the number of (re) transmissions.
168 */
169 int num_transmissions;
170
171};
172
173
174/**
175 * List of received out-of-order data messages.
176 */
177struct CadetOutOfOrderMessage
178{
179 /**
180 * Double linked list, FIFO style
181 */
182 struct CadetOutOfOrderMessage *next;
183
184 /**
185 * Double linked list, FIFO style
186 */
187 struct CadetOutOfOrderMessage *prev;
188
189 /**
190 * ID of the message (messages up to this point needed
191 * before we give this one to the client).
192 */
193 struct ChannelMessageIdentifier mid;
194
195 /**
196 * The envelope with the payload of the out-of-order message
197 */
198 struct GNUNET_MQ_Envelope *env;
199
200};
201
202
203/**
204 * Client endpoint of a `struct CadetChannel`. A channel may be a
205 * loopback channel, in which case it has two of these endpoints.
206 * Note that flow control also is required in both directions.
207 */
208struct CadetChannelClient
209{
210 /**
211 * Client handle. Not by itself sufficient to designate
212 * the client endpoint, as the same client handle may
213 * be used for both the owner and the destination, and
214 * we thus also need the channel ID to identify the client.
215 */
216 struct CadetClient *c;
217
218 /**
219 * Head of DLL of messages received out of order or while client was unready.
220 */
221 struct CadetOutOfOrderMessage *head_recv;
222
223 /**
224 * Tail DLL of messages received out of order or while client was unready.
225 */
226 struct CadetOutOfOrderMessage *tail_recv;
227
228 /**
229 * Local tunnel number for this client.
230 * (if owner >= #GNUNET_CADET_LOCAL_CHANNEL_ID_CLI,
231 * otherwise < #GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
232 */
233 struct GNUNET_CADET_ClientChannelNumber ccn;
234
235 /**
236 * Number of entries currently in @a head_recv DLL.
237 */
238 unsigned int num_recv;
239
240 /**
241 * Can we send data to the client?
242 */
243 int client_ready;
244
245};
246
247
248/**
249 * Struct containing all information regarding a channel to a remote client.
250 */
251struct CadetChannel
252{
253 /**
254 * Tunnel this channel is in.
255 */
256 struct CadetTunnel *t;
257
258 /**
259 * Client owner of the tunnel, if any.
260 * (Used if this channel represends the initiating end of the tunnel.)
261 */
262 struct CadetChannelClient *owner;
263
264 /**
265 * Client destination of the tunnel, if any.
266 * (Used if this channel represents the listening end of the tunnel.)
267 */
268 struct CadetChannelClient *dest;
269
270 /**
271 * Last entry in the tunnel's queue relating to control messages
272 * (#GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN or
273 * #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK). Used to cancel
274 * transmission in case we receive updated information.
275 */
276 struct CadetTunnelQueueEntry *last_control_qe;
277
278 /**
279 * Head of DLL of messages sent and not yet ACK'd.
280 */
281 struct CadetReliableMessage *head_sent;
282
283 /**
284 * Tail of DLL of messages sent and not yet ACK'd.
285 */
286 struct CadetReliableMessage *tail_sent;
287
288 /**
289 * Task to resend/poll in case no ACK is received.
290 */
291 struct GNUNET_SCHEDULER_Task *retry_control_task;
292
293 /**
294 * Task to resend/poll in case no ACK is received.
295 */
296 struct GNUNET_SCHEDULER_Task *retry_data_task;
297
298 /**
299 * Last time the channel was used
300 */
301 struct GNUNET_TIME_Absolute timestamp;
302
303 /**
304 * Destination port of the channel.
305 */
306 struct GNUNET_HashCode port;
307
308 /**
309 * Counter for exponential backoff.
310 */
311 struct GNUNET_TIME_Relative retry_time;
312
313 /**
314 * Bitfield of already-received messages past @e mid_recv.
315 */
316 uint64_t mid_futures;
317
318 /**
319 * Next MID expected for incoming traffic.
320 */
321 struct ChannelMessageIdentifier mid_recv;
322
323 /**
324 * Next MID to use for outgoing traffic.
325 */
326 struct ChannelMessageIdentifier mid_send;
327
328 /**
329 * Total (reliable) messages pending ACK for this channel.
330 */
331 unsigned int pending_messages;
332
333 /**
334 * Maximum (reliable) messages pending ACK for this channel
335 * before we throttle the client.
336 */
337 unsigned int max_pending_messages;
338
339 /**
340 * Number identifying this channel in its tunnel.
341 */
342 struct GNUNET_CADET_ChannelTunnelNumber ctn;
343
344 /**
345 * Channel state.
346 */
347 enum CadetChannelState state;
348
349 /**
350 * Count how many ACKs we skipped, used to prevent long
351 * sequences of ACK skipping.
352 */
353 unsigned int skip_ack_series;
354
355 /**
356 * Is the tunnel bufferless (minimum latency)?
357 */
358 int nobuffer;
359
360 /**
361 * Is the tunnel reliable?
362 */
363 int reliable;
364
365 /**
366 * Is the tunnel out-of-order?
367 */
368 int out_of_order;
369
370 /**
371 * Is this channel a loopback channel, where the destination is us again?
372 */
373 int is_loopback;
374
375 /**
376 * Flag to signal the destruction of the channel. If this is set to
377 * #GNUNET_YES the channel will be destroyed once the queue is
378 * empty.
379 */
380 int destroy;
381
382};
383
384
385/**
386 * Get the static string for identification of the channel.
387 *
388 * @param ch Channel.
389 *
390 * @return Static string with the channel IDs.
391 */
392const char *
393GCCH_2s (const struct CadetChannel *ch)
394{
395 static char buf[128];
396
397 GNUNET_snprintf (buf,
398 sizeof (buf),
399 "Channel %s:%s ctn:%X(%X/%X)",
400 (GNUNET_YES == ch->is_loopback)
401 ? "loopback"
402 : GNUNET_i2s (GCP_get_id (GCT_get_destination (ch->t))),
403 GNUNET_h2s (&ch->port),
404 ch->ctn,
405 (NULL == ch->owner) ? 0 : ntohl (ch->owner->ccn.channel_of_client),
406 (NULL == ch->dest) ? 0 : ntohl (ch->dest->ccn.channel_of_client));
407 return buf;
408}
409
410
411/**
412 * Get the channel's public ID.
413 *
414 * @param ch Channel.
415 *
416 * @return ID used to identify the channel with the remote peer.
417 */
418struct GNUNET_CADET_ChannelTunnelNumber
419GCCH_get_id (const struct CadetChannel *ch)
420{
421 return ch->ctn;
422}
423
424
425/**
426 * Release memory associated with @a ccc
427 *
428 * @param ccc data structure to clean up
429 */
430static void
431free_channel_client (struct CadetChannelClient *ccc)
432{
433 struct CadetOutOfOrderMessage *com;
434
435 while (NULL != (com = ccc->head_recv))
436 {
437 GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
438 ccc->tail_recv,
439 com);
440 ccc->num_recv--;
441 GNUNET_MQ_discard (com->env);
442 GNUNET_free (com);
443 }
444 GNUNET_free (ccc);
445}
446
447
448/**
449 * Destroy the given channel.
450 *
451 * @param ch channel to destroy
452 */
453static void
454channel_destroy (struct CadetChannel *ch)
455{
456 struct CadetReliableMessage *crm;
457
458 while (NULL != (crm = ch->head_sent))
459 {
460 GNUNET_assert (ch == crm->ch);
461 if (NULL != crm->qe)
462 {
463 GCT_send_cancel (crm->qe);
464 crm->qe = NULL;
465 }
466 GNUNET_CONTAINER_DLL_remove (ch->head_sent,
467 ch->tail_sent,
468 crm);
469 GNUNET_free (crm->data_message);
470 GNUNET_free (crm);
471 }
472 if (NULL != ch->owner)
473 {
474 free_channel_client (ch->owner);
475 ch->owner = NULL;
476 }
477 if (NULL != ch->dest)
478 {
479 free_channel_client (ch->dest);
480 ch->dest = NULL;
481 }
482 if (NULL != ch->last_control_qe)
483 {
484 GCT_send_cancel (ch->last_control_qe);
485 ch->last_control_qe = NULL;
486 }
487 if (NULL != ch->retry_data_task)
488 {
489 GNUNET_SCHEDULER_cancel (ch->retry_data_task);
490 ch->retry_data_task = NULL;
491 }
492 if (NULL != ch->retry_control_task)
493 {
494 GNUNET_SCHEDULER_cancel (ch->retry_control_task);
495 ch->retry_control_task = NULL;
496 }
497 if (GNUNET_NO == ch->is_loopback)
498 {
499 GCT_remove_channel (ch->t,
500 ch,
501 ch->ctn);
502 ch->t = NULL;
503 }
504 GNUNET_free (ch);
505}
506
507
508/**
509 * Send a channel create message.
510 *
511 * @param cls Channel for which to send.
512 */
513static void
514send_channel_open (void *cls);
515
516
517/**
518 * Function called once the tunnel confirms that we sent the
519 * create message. Delays for a bit until we retry.
520 *
521 * @param cls our `struct CadetChannel`.
522 * @param cid identifier of the connection within the tunnel, NULL
523 * if transmission failed
524 */
525static void
526channel_open_sent_cb (void *cls,
527 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
528{
529 struct CadetChannel *ch = cls;
530
531 GNUNET_assert (NULL != ch->last_control_qe);
532 ch->last_control_qe = NULL;
533 ch->retry_time = GNUNET_TIME_STD_BACKOFF (ch->retry_time);
534 LOG (GNUNET_ERROR_TYPE_DEBUG,
535 "Sent CADET_CHANNEL_OPEN on %s, retrying in %s\n",
536 GCCH_2s (ch),
537 GNUNET_STRINGS_relative_time_to_string (ch->retry_time,
538 GNUNET_YES));
539 ch->retry_control_task
540 = GNUNET_SCHEDULER_add_delayed (ch->retry_time,
541 &send_channel_open,
542 ch);
543}
544
545
546/**
547 * Send a channel open message.
548 *
549 * @param cls Channel for which to send.
550 */
551static void
552send_channel_open (void *cls)
553{
554 struct CadetChannel *ch = cls;
555 struct GNUNET_CADET_ChannelOpenMessage msgcc;
556 uint32_t options;
557
558 ch->retry_control_task = NULL;
559 LOG (GNUNET_ERROR_TYPE_DEBUG,
560 "Sending CHANNEL_OPEN message for %s\n",
561 GCCH_2s (ch));
562 options = 0;
563 if (ch->nobuffer)
564 options |= GNUNET_CADET_OPTION_NOBUFFER;
565 if (ch->reliable)
566 options |= GNUNET_CADET_OPTION_RELIABLE;
567 if (ch->out_of_order)
568 options |= GNUNET_CADET_OPTION_OUT_OF_ORDER;
569 msgcc.header.size = htons (sizeof (msgcc));
570 msgcc.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN);
571 msgcc.opt = htonl (options);
572 msgcc.port = ch->port;
573 msgcc.ctn = ch->ctn;
574 ch->state = CADET_CHANNEL_OPEN_SENT;
575 if (NULL != ch->last_control_qe)
576 GCT_send_cancel (ch->last_control_qe);
577 ch->last_control_qe = GCT_send (ch->t,
578 &msgcc.header,
579 &channel_open_sent_cb,
580 ch);
581 GNUNET_assert (NULL == ch->retry_control_task);
582}
583
584
585/**
586 * Function called once and only once after a channel was bound
587 * to its tunnel via #GCT_add_channel() is ready for transmission.
588 * Note that this is only the case for channels that this peer
589 * initiates, as for incoming channels we assume that they are
590 * ready for transmission immediately upon receiving the open
591 * message. Used to bootstrap the #GCT_send() process.
592 *
593 * @param ch the channel for which the tunnel is now ready
594 */
595void
596GCCH_tunnel_up (struct CadetChannel *ch)
597{
598 GNUNET_assert (NULL == ch->retry_control_task);
599 LOG (GNUNET_ERROR_TYPE_DEBUG,
600 "Tunnel up, sending CHANNEL_OPEN on %s now\n",
601 GCCH_2s (ch));
602 ch->retry_control_task
603 = GNUNET_SCHEDULER_add_now (&send_channel_open,
604 ch);
605}
606
607
608/**
609 * Create a new channel.
610 *
611 * @param owner local client owning the channel
612 * @param ccn local number of this channel at the @a owner
613 * @param destination peer to which we should build the channel
614 * @param port desired port at @a destination
615 * @param options options for the channel
616 * @return handle to the new channel
617 */
618struct CadetChannel *
619GCCH_channel_local_new (struct CadetClient *owner,
620 struct GNUNET_CADET_ClientChannelNumber ccn,
621 struct CadetPeer *destination,
622 const struct GNUNET_HashCode *port,
623 uint32_t options)
624{
625 struct CadetChannel *ch;
626 struct CadetChannelClient *ccco;
627
628 ccco = GNUNET_new (struct CadetChannelClient);
629 ccco->c = owner;
630 ccco->ccn = ccn;
631 ccco->client_ready = GNUNET_YES;
632
633 ch = GNUNET_new (struct CadetChannel);
634 ch->mid_recv.mid = htonl (1); /* The OPEN_ACK counts as message 0! */
635 ch->nobuffer = (0 != (options & GNUNET_CADET_OPTION_NOBUFFER));
636 ch->reliable = (0 != (options & GNUNET_CADET_OPTION_RELIABLE));
637 ch->out_of_order = (0 != (options & GNUNET_CADET_OPTION_OUT_OF_ORDER));
638 ch->max_pending_messages = (ch->nobuffer) ? 1 : 4; /* FIXME: 4!? Do not hardcode! */
639 ch->owner = ccco;
640 ch->port = *port;
641 if (0 == memcmp (&my_full_id,
642 GCP_get_id (destination),
643 sizeof (struct GNUNET_PeerIdentity)))
644 {
645 struct CadetClient *c;
646
647 ch->is_loopback = GNUNET_YES;
648 c = GNUNET_CONTAINER_multihashmap_get (open_ports,
649 port);
650 if (NULL == c)
651 {
652 /* port closed, wait for it to possibly open */
653 ch->state = CADET_CHANNEL_LOOSE;
654 (void) GNUNET_CONTAINER_multihashmap_put (loose_channels,
655 port,
656 ch,
657 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
658 LOG (GNUNET_ERROR_TYPE_DEBUG,
659 "Created loose incoming loopback channel to port %s\n",
660 GNUNET_h2s (&ch->port));
661 }
662 else
663 {
664 GCCH_bind (ch,
665 c);
666 }
667 }
668 else
669 {
670 ch->t = GCP_get_tunnel (destination,
671 GNUNET_YES);
672 ch->retry_time = CADET_INITIAL_RETRANSMIT_TIME;
673 ch->ctn = GCT_add_channel (ch->t,
674 ch);
675 }
676 GNUNET_STATISTICS_update (stats,
677 "# channels",
678 1,
679 GNUNET_NO);
680 LOG (GNUNET_ERROR_TYPE_DEBUG,
681 "Created channel to port %s at peer %s for %s using %s\n",
682 GNUNET_h2s (port),
683 GCP_2s (destination),
684 GSC_2s (owner),
685 (GNUNET_YES == ch->is_loopback) ? "loopback" : GCT_2s (ch->t));
686 return ch;
687}
688
689
690/**
691 * We had an incoming channel to a port that is closed.
692 * It has not been opened for a while, drop it.
693 *
694 * @param cls the channel to drop
695 */
696static void
697timeout_closed_cb (void *cls)
698{
699 struct CadetChannel *ch = cls;
700
701 ch->retry_control_task = NULL;
702 LOG (GNUNET_ERROR_TYPE_DEBUG,
703 "Closing incoming channel to port %s from peer %s due to timeout\n",
704 GNUNET_h2s (&ch->port),
705 GCP_2s (GCT_get_destination (ch->t)));
706 channel_destroy (ch);
707}
708
709
710/**
711 * Create a new channel based on a request coming in over the network.
712 *
713 * @param t tunnel to the remote peer
714 * @param ctn identifier of this channel in the tunnel
715 * @param port desired local port
716 * @param options options for the channel
717 * @return handle to the new channel
718 */
719struct CadetChannel *
720GCCH_channel_incoming_new (struct CadetTunnel *t,
721 struct GNUNET_CADET_ChannelTunnelNumber ctn,
722 const struct GNUNET_HashCode *port,
723 uint32_t options)
724{
725 struct CadetChannel *ch;
726 struct CadetClient *c;
727
728 ch = GNUNET_new (struct CadetChannel);
729 ch->port = *port;
730 ch->t = t;
731 ch->ctn = ctn;
732 ch->retry_time = CADET_INITIAL_RETRANSMIT_TIME;
733 ch->nobuffer = (0 != (options & GNUNET_CADET_OPTION_NOBUFFER));
734 ch->reliable = (0 != (options & GNUNET_CADET_OPTION_RELIABLE));
735 ch->out_of_order = (0 != (options & GNUNET_CADET_OPTION_OUT_OF_ORDER));
736 ch->max_pending_messages = (ch->nobuffer) ? 1 : 4; /* FIXME: 4!? Do not hardcode! */
737 GNUNET_STATISTICS_update (stats,
738 "# channels",
739 1,
740 GNUNET_NO);
741
742 c = GNUNET_CONTAINER_multihashmap_get (open_ports,
743 port);
744 if (NULL == c)
745 {
746 /* port closed, wait for it to possibly open */
747 ch->state = CADET_CHANNEL_LOOSE;
748 (void) GNUNET_CONTAINER_multihashmap_put (loose_channels,
749 port,
750 ch,
751 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
752 GNUNET_assert (NULL == ch->retry_control_task);
753 ch->retry_control_task
754 = GNUNET_SCHEDULER_add_delayed (TIMEOUT_CLOSED_PORT,
755 &timeout_closed_cb,
756 ch);
757 LOG (GNUNET_ERROR_TYPE_DEBUG,
758 "Created loose incoming channel to port %s from peer %s\n",
759 GNUNET_h2s (&ch->port),
760 GCP_2s (GCT_get_destination (ch->t)));
761 }
762 else
763 {
764 GCCH_bind (ch,
765 c);
766 }
767 GNUNET_STATISTICS_update (stats,
768 "# channels",
769 1,
770 GNUNET_NO);
771 return ch;
772}
773
774
775/**
776 * Function called once the tunnel confirms that we sent the
777 * ACK message. Just remembers it was sent, we do not expect
778 * ACKs for ACKs ;-).
779 *
780 * @param cls our `struct CadetChannel`.
781 * @param cid identifier of the connection within the tunnel, NULL
782 * if transmission failed
783 */
784static void
785send_ack_cb (void *cls,
786 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
787{
788 struct CadetChannel *ch = cls;
789
790 GNUNET_assert (NULL != ch->last_control_qe);
791 ch->last_control_qe = NULL;
792}
793
794
795/**
796 * Compute and send the current #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK to the other peer.
797 *
798 * @param ch channel to send the #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK for
799 */
800static void
801send_channel_data_ack (struct CadetChannel *ch)
802{
803 struct GNUNET_CADET_ChannelDataAckMessage msg;
804
805 if (GNUNET_NO == ch->reliable)
806 return; /* no ACKs */
807 msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK);
808 msg.header.size = htons (sizeof (msg));
809 msg.ctn = ch->ctn;
810 msg.mid.mid = htonl (ntohl (ch->mid_recv.mid));
811 msg.futures = GNUNET_htonll (ch->mid_futures);
812 LOG (GNUNET_ERROR_TYPE_DEBUG,
813 "Sending DATA_ACK %u:%llX via %s\n",
814 (unsigned int) ntohl (msg.mid.mid),
815 (unsigned long long) ch->mid_futures,
816 GCCH_2s (ch));
817 if (NULL != ch->last_control_qe)
818 GCT_send_cancel (ch->last_control_qe);
819 ch->last_control_qe = GCT_send (ch->t,
820 &msg.header,
821 &send_ack_cb,
822 ch);
823}
824
825
826/**
827 * Send our initial #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK to the client confirming that the
828 * connection is up.
829 *
830 * @param cls the `struct CadetChannel`
831 */
832static void
833send_open_ack (void *cls)
834{
835 struct CadetChannel *ch = cls;
836 struct GNUNET_CADET_ChannelManageMessage msg;
837
838 ch->retry_control_task = NULL;
839 LOG (GNUNET_ERROR_TYPE_DEBUG,
840 "Sending CHANNEL_OPEN_ACK on %s\n",
841 GCCH_2s (ch));
842 msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK);
843 msg.header.size = htons (sizeof (msg));
844 msg.reserved = htonl (0);
845 msg.ctn = ch->ctn;
846 if (NULL != ch->last_control_qe)
847 GCT_send_cancel (ch->last_control_qe);
848 ch->last_control_qe = GCT_send (ch->t,
849 &msg.header,
850 &send_ack_cb,
851 ch);
852}
853
854
855/**
856 * We got a #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN message again for
857 * this channel. If the binding was successful, (re)transmit the
858 * #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK.
859 *
860 * @param ch channel that got the duplicate open
861 * @param cti identifier of the connection that delivered the message
862 */
863void
864GCCH_handle_duplicate_open (struct CadetChannel *ch,
865 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti)
866{
867 if (NULL == ch->dest)
868 {
869 LOG (GNUNET_ERROR_TYPE_DEBUG,
870 "Ignoring duplicate CHANNEL_OPEN on %s: port is closed\n",
871 GCCH_2s (ch));
872 return;
873 }
874 if (NULL != ch->retry_control_task)
875 {
876 LOG (GNUNET_ERROR_TYPE_DEBUG,
877 "Ignoring duplicate CHANNEL_OPEN on %s: control message is pending\n",
878 GCCH_2s (ch));
879 return;
880 }
881 LOG (GNUNET_ERROR_TYPE_DEBUG,
882 "Retransmitting CHANNEL_OPEN_ACK on %s\n",
883 GCCH_2s (ch));
884 ch->retry_control_task
885 = GNUNET_SCHEDULER_add_now (&send_open_ack,
886 ch);
887}
888
889
890/**
891 * Send a #GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK to the client to solicit more messages.
892 *
893 * @param ch channel the ack is for
894 * @param to_owner #GNUNET_YES to send to owner,
895 * #GNUNET_NO to send to dest
896 */
897static void
898send_ack_to_client (struct CadetChannel *ch,
899 int to_owner)
900{
901 struct GNUNET_MQ_Envelope *env;
902 struct GNUNET_CADET_LocalAck *ack;
903 struct CadetChannelClient *ccc;
904
905 ccc = (GNUNET_YES == to_owner) ? ch->owner : ch->dest;
906 if (NULL == ccc)
907 {
908 /* This can happen if we are just getting ACKs after
909 our local client already disconnected. */
910 GNUNET_assert (GNUNET_YES == ch->destroy);
911 return;
912 }
913 env = GNUNET_MQ_msg (ack,
914 GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK);
915 ack->ccn = ccc->ccn;
916 LOG (GNUNET_ERROR_TYPE_DEBUG,
917 "Sending CADET_LOCAL_ACK to %s (%s) at ccn %X (%u/%u pending)\n",
918 GSC_2s (ccc->c),
919 (GNUNET_YES == to_owner) ? "owner" : "dest",
920 ntohl (ack->ccn.channel_of_client),
921 ch->pending_messages,
922 ch->max_pending_messages);
923 GSC_send_to_client (ccc->c,
924 env);
925}
926
927
928/**
929 * A client is bound to the port that we have a channel
930 * open to. Send the acknowledgement for the connection
931 * request and establish the link with the client.
932 *
933 * @param ch open incoming channel
934 * @param c client listening on the respective port
935 */
936void
937GCCH_bind (struct CadetChannel *ch,
938 struct CadetClient *c)
939{
940 uint32_t options;
941 struct CadetChannelClient *cccd;
942
943 LOG (GNUNET_ERROR_TYPE_DEBUG,
944 "Binding %s from %s to port %s of %s\n",
945 GCCH_2s (ch),
946 GCT_2s (ch->t),
947 GNUNET_h2s (&ch->port),
948 GSC_2s (c));
949 if (NULL != ch->retry_control_task)
950 {
951 /* there might be a timeout task here */
952 GNUNET_SCHEDULER_cancel (ch->retry_control_task);
953 ch->retry_control_task = NULL;
954 }
955 options = 0;
956 if (ch->nobuffer)
957 options |= GNUNET_CADET_OPTION_NOBUFFER;
958 if (ch->reliable)
959 options |= GNUNET_CADET_OPTION_RELIABLE;
960 if (ch->out_of_order)
961 options |= GNUNET_CADET_OPTION_OUT_OF_ORDER;
962 cccd = GNUNET_new (struct CadetChannelClient);
963 GNUNET_assert (NULL == ch->dest);
964 ch->dest = cccd;
965 cccd->c = c;
966 cccd->client_ready = GNUNET_YES;
967 cccd->ccn = GSC_bind (c,
968 ch,
969 (GNUNET_YES == ch->is_loopback)
970 ? GCP_get (&my_full_id,
971 GNUNET_YES)
972 : GCT_get_destination (ch->t),
973 &ch->port,
974 options);
975 GNUNET_assert (ntohl (cccd->ccn.channel_of_client) <
976 GNUNET_CADET_LOCAL_CHANNEL_ID_CLI);
977 ch->mid_recv.mid = htonl (1); /* The OPEN counts as message 0! */
978 if (GNUNET_YES == ch->is_loopback)
979 {
980 ch->state = CADET_CHANNEL_OPEN_SENT;
981 GCCH_handle_channel_open_ack (ch,
982 NULL);
983 }
984 else
985 {
986 /* notify other peer that we accepted the connection */
987 ch->state = CADET_CHANNEL_READY;
988 ch->retry_control_task
989 = GNUNET_SCHEDULER_add_now (&send_open_ack,
990 ch);
991 }
992 /* give client it's initial supply of ACKs */
993 GNUNET_assert (ntohl (cccd->ccn.channel_of_client) <
994 GNUNET_CADET_LOCAL_CHANNEL_ID_CLI);
995 for (unsigned int i=0;i<ch->max_pending_messages;i++)
996 send_ack_to_client (ch,
997 GNUNET_NO);
998}
999
1000
1001/**
1002 * One of our clients has disconnected, tell the other one that we
1003 * are finished. Done asynchronously to avoid concurrent modification
1004 * issues if this is the same client.
1005 *
1006 * @param cls the `struct CadetChannel` where one of the ends is now dead
1007 */
1008static void
1009signal_remote_destroy_cb (void *cls)
1010{
1011 struct CadetChannel *ch = cls;
1012 struct CadetChannelClient *ccc;
1013
1014 /* Find which end is left... */
1015 ch->retry_control_task = NULL;
1016 ccc = (NULL != ch->owner) ? ch->owner : ch->dest;
1017 GSC_handle_remote_channel_destroy (ccc->c,
1018 ccc->ccn,
1019 ch);
1020 channel_destroy (ch);
1021}
1022
1023
1024/**
1025 * Destroy locally created channel. Called by the local client, so no
1026 * need to tell the client.
1027 *
1028 * @param ch channel to destroy
1029 * @param c client that caused the destruction
1030 * @param ccn client number of the client @a c
1031 */
1032void
1033GCCH_channel_local_destroy (struct CadetChannel *ch,
1034 struct CadetClient *c,
1035 struct GNUNET_CADET_ClientChannelNumber ccn)
1036{
1037 LOG (GNUNET_ERROR_TYPE_DEBUG,
1038 "%s asks for destruction of %s\n",
1039 GSC_2s (c),
1040 GCCH_2s (ch));
1041 GNUNET_assert (NULL != c);
1042 if ( (NULL != ch->owner) &&
1043 (c == ch->owner->c) &&
1044 (ccn.channel_of_client == ch->owner->ccn.channel_of_client) )
1045 {
1046 free_channel_client (ch->owner);
1047 ch->owner = NULL;
1048 }
1049 else if ( (NULL != ch->dest) &&
1050 (c == ch->dest->c) &&
1051 (ccn.channel_of_client == ch->dest->ccn.channel_of_client) )
1052 {
1053 free_channel_client (ch->dest);
1054 ch->dest = NULL;
1055 }
1056 else
1057 {
1058 GNUNET_assert (0);
1059 }
1060
1061 if (GNUNET_YES == ch->destroy)
1062 {
1063 /* other end already destroyed, with the local client gone, no need
1064 to finish transmissions, just destroy immediately. */
1065 channel_destroy (ch);
1066 return;
1067 }
1068 if ( (NULL != ch->head_sent) &&
1069 ( (NULL != ch->owner) ||
1070 (NULL != ch->dest) ) )
1071 {
1072 /* Wait for other end to destroy us as well,
1073 and otherwise allow send queue to be transmitted first */
1074 ch->destroy = GNUNET_YES;
1075 return;
1076 }
1077 if ( (GNUNET_YES == ch->is_loopback) &&
1078 ( (NULL != ch->owner) ||
1079 (NULL != ch->dest) ) )
1080 {
1081 if (NULL != ch->retry_control_task)
1082 GNUNET_SCHEDULER_cancel (ch->retry_control_task);
1083 ch->retry_control_task
1084 = GNUNET_SCHEDULER_add_now (&signal_remote_destroy_cb,
1085 ch);
1086 return;
1087 }
1088 if (GNUNET_NO == ch->is_loopback)
1089 {
1090 /* If the we ever sent the CHANNEL_CREATE, we need to send a destroy message. */
1091 switch (ch->state)
1092 {
1093 case CADET_CHANNEL_NEW:
1094 /* We gave up on a channel that we created as a client to a remote
1095 target, but that never went anywhere. Nothing to do here. */
1096 break;
1097 case CADET_CHANNEL_LOOSE:
1098 GSC_drop_loose_channel (&ch->port,
1099 ch);
1100 break;
1101 default:
1102 GCT_send_channel_destroy (ch->t,
1103 ch->ctn);
1104 }
1105 }
1106 /* Nothing left to do, just finish destruction */
1107 channel_destroy (ch);
1108}
1109
1110
1111/**
1112 * We got an acknowledgement for the creation of the channel
1113 * (the port is open on the other side). Begin transmissions.
1114 *
1115 * @param ch channel to destroy
1116 * @param cti identifier of the connection that delivered the message
1117 */
1118void
1119GCCH_handle_channel_open_ack (struct CadetChannel *ch,
1120 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti)
1121{
1122 switch (ch->state)
1123 {
1124 case CADET_CHANNEL_NEW:
1125 /* this should be impossible */
1126 GNUNET_break (0);
1127 break;
1128 case CADET_CHANNEL_LOOSE:
1129 /* This makes no sense. */
1130 GNUNET_break_op (0);
1131 break;
1132 case CADET_CHANNEL_OPEN_SENT:
1133 if (NULL == ch->owner)
1134 {
1135 /* We're not the owner, wrong direction! */
1136 GNUNET_break_op (0);
1137 return;
1138 }
1139 LOG (GNUNET_ERROR_TYPE_DEBUG,
1140 "Received CHANNEL_OPEN_ACK for waiting %s, entering READY state\n",
1141 GCCH_2s (ch));
1142 if (NULL != ch->retry_control_task) /* can be NULL if ch->is_loopback */
1143 {
1144 GNUNET_SCHEDULER_cancel (ch->retry_control_task);
1145 ch->retry_control_task = NULL;
1146 }
1147 ch->state = CADET_CHANNEL_READY;
1148 /* On first connect, send client as many ACKs as we allow messages
1149 to be buffered! */
1150 for (unsigned int i=0;i<ch->max_pending_messages;i++)
1151 send_ack_to_client (ch,
1152 GNUNET_YES);
1153 break;
1154 case CADET_CHANNEL_READY:
1155 /* duplicate ACK, maybe we retried the CREATE. Ignore. */
1156 LOG (GNUNET_ERROR_TYPE_DEBUG,
1157 "Received duplicate channel OPEN_ACK for %s\n",
1158 GCCH_2s (ch));
1159 GNUNET_STATISTICS_update (stats,
1160 "# duplicate CREATE_ACKs",
1161 1,
1162 GNUNET_NO);
1163 break;
1164 }
1165}
1166
1167
1168/**
1169 * Test if element @a e1 comes before element @a e2.
1170 *
1171 * @param cls closure, to a flag where we indicate duplicate packets
1172 * @param m1 a message of to sort
1173 * @param m2 another message to sort
1174 * @return #GNUNET_YES if @e1 < @e2, otherwise #GNUNET_NO
1175 */
1176static int
1177is_before (void *cls,
1178 struct CadetOutOfOrderMessage *m1,
1179 struct CadetOutOfOrderMessage *m2)
1180{
1181 int *duplicate = cls;
1182 uint32_t v1 = ntohl (m1->mid.mid);
1183 uint32_t v2 = ntohl (m2->mid.mid);
1184 uint32_t delta;
1185
1186 delta = v2 - v1;
1187 if (0 == delta)
1188 *duplicate = GNUNET_YES;
1189 if (delta > (uint32_t) INT_MAX)
1190 {
1191 /* in overflow range, we can safely assume we wrapped around */
1192 return GNUNET_NO;
1193 }
1194 else
1195 {
1196 /* result is small, thus v2 > v1, thus m1 < m2 */
1197 return GNUNET_YES;
1198 }
1199}
1200
1201
1202/**
1203 * We got payload data for a channel. Pass it on to the client
1204 * and send an ACK to the other end (once flow control allows it!)
1205 *
1206 * @param ch channel that got data
1207 * @param cti identifier of the connection that delivered the message
1208 * @param msg message that was received
1209 */
1210void
1211GCCH_handle_channel_plaintext_data (struct CadetChannel *ch,
1212 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
1213 const struct GNUNET_CADET_ChannelAppDataMessage *msg)
1214{
1215 struct GNUNET_MQ_Envelope *env;
1216 struct GNUNET_CADET_LocalData *ld;
1217 struct CadetChannelClient *ccc;
1218 size_t payload_size;
1219 struct CadetOutOfOrderMessage *com;
1220 int duplicate;
1221 uint32_t mid_min;
1222 uint32_t mid_max;
1223 uint32_t mid_msg;
1224 uint32_t delta;
1225
1226 GNUNET_assert (GNUNET_NO == ch->is_loopback);
1227 if ( (GNUNET_YES == ch->destroy) &&
1228 (NULL == ch->owner) &&
1229 (NULL == ch->dest) )
1230 {
1231 /* This client is gone, but we still have messages to send to
1232 the other end (which is why @a ch is not yet dead). However,
1233 we cannot pass messages to our client anymore. */
1234 LOG (GNUNET_ERROR_TYPE_DEBUG,
1235 "Dropping incoming payload on %s as this end is already closed\n",
1236 GCCH_2s (ch));
1237 /* send back DESTROY notification to stop further retransmissions! */
1238 GCT_send_channel_destroy (ch->t,
1239 ch->ctn);
1240 return;
1241 }
1242 payload_size = ntohs (msg->header.size) - sizeof (*msg);
1243 env = GNUNET_MQ_msg_extra (ld,
1244 payload_size,
1245 GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA);
1246 ld->ccn = (NULL == ch->dest) ? ch->owner->ccn : ch->dest->ccn;
1247 GNUNET_memcpy (&ld[1],
1248 &msg[1],
1249 payload_size);
1250 ccc = (NULL != ch->owner) ? ch->owner : ch->dest;
1251 if ( (GNUNET_YES == ccc->client_ready) &&
1252 ( (GNUNET_YES == ch->out_of_order) ||
1253 (msg->mid.mid == ch->mid_recv.mid) ) )
1254 {
1255 LOG (GNUNET_ERROR_TYPE_DEBUG,
1256 "Giving %u bytes of payload with MID %u from %s to client %s\n",
1257 (unsigned int) payload_size,
1258 ntohl (msg->mid.mid),
1259 GCCH_2s (ch),
1260 GSC_2s (ccc->c));
1261 ccc->client_ready = GNUNET_NO;
1262 GSC_send_to_client (ccc->c,
1263 env);
1264 ch->mid_recv.mid = htonl (1 + ntohl (ch->mid_recv.mid));
1265 ch->mid_futures >>= 1;
1266 send_channel_data_ack (ch);
1267 return;
1268 }
1269
1270 if (GNUNET_YES == ch->reliable)
1271 {
1272 /* check if message ought to be dropped because it is ancient/too distant/duplicate */
1273 mid_min = ntohl (ch->mid_recv.mid);
1274 mid_max = mid_min + ch->max_pending_messages;
1275 mid_msg = ntohl (msg->mid.mid);
1276 if ( ( (uint32_t) (mid_msg - mid_min) > ch->max_pending_messages) ||
1277 ( (uint32_t) (mid_max - mid_msg) > ch->max_pending_messages) )
1278 {
1279 LOG (GNUNET_ERROR_TYPE_DEBUG,
1280 "%s at %u drops ancient or far-future message %u\n",
1281 GCCH_2s (ch),
1282 (unsigned int) mid_min,
1283 ntohl (msg->mid.mid));
1284
1285 GNUNET_STATISTICS_update (stats,
1286 "# duplicate DATA (ancient or future)",
1287 1,
1288 GNUNET_NO);
1289 GNUNET_MQ_discard (env);
1290 send_channel_data_ack (ch);
1291 return;
1292 }
1293 /* mark bit for future ACKs */
1294 delta = mid_msg - mid_min - 1; /* overflow/underflow are OK here */
1295 if (delta < 64)
1296 {
1297 if (0 != (ch->mid_futures & (1LLU << delta)))
1298 {
1299 /* Duplicate within the queue, drop also */
1300 LOG (GNUNET_ERROR_TYPE_DEBUG,
1301 "Duplicate payload of %u bytes on %s (mid %u) dropped\n",
1302 (unsigned int) payload_size,
1303 GCCH_2s (ch),
1304 ntohl (msg->mid.mid));
1305 GNUNET_STATISTICS_update (stats,
1306 "# duplicate DATA",
1307 1,
1308 GNUNET_NO);
1309 GNUNET_MQ_discard (env);
1310 send_channel_data_ack (ch);
1311 return;
1312 }
1313 ch->mid_futures |= (1LLU << delta);
1314 LOG (GNUNET_ERROR_TYPE_DEBUG,
1315 "Marked bit %llX for mid %u (base: %u); now: %llX\n",
1316 (1LLU << delta),
1317 mid_msg,
1318 mid_min,
1319 ch->mid_futures);
1320 }
1321 }
1322 else /* ! ch->reliable */
1323 {
1324 /* Channel is unreliable, so we do not ACK. But we also cannot
1325 allow buffering everything, so check if we have space... */
1326 if (ccc->num_recv >= ch->max_pending_messages)
1327 {
1328 struct CadetOutOfOrderMessage *drop;
1329
1330 /* Yep, need to drop. Drop the oldest message in
1331 the buffer. */
1332 LOG (GNUNET_ERROR_TYPE_DEBUG,
1333 "Queue full due slow client on %s, dropping oldest message\n",
1334 GCCH_2s (ch));
1335 GNUNET_STATISTICS_update (stats,
1336 "# messages dropped due to slow client",
1337 1,
1338 GNUNET_NO);
1339 drop = ccc->head_recv;
1340 GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
1341 ccc->tail_recv,
1342 drop);
1343 ccc->num_recv--;
1344 GNUNET_MQ_discard (drop->env);
1345 GNUNET_free (drop);
1346 }
1347 }
1348
1349 /* Insert message into sorted out-of-order queue */
1350 com = GNUNET_new (struct CadetOutOfOrderMessage);
1351 com->mid = msg->mid;
1352 com->env = env;
1353 duplicate = GNUNET_NO;
1354 GNUNET_CONTAINER_DLL_insert_sorted (struct CadetOutOfOrderMessage,
1355 is_before,
1356 &duplicate,
1357 ccc->head_recv,
1358 ccc->tail_recv,
1359 com);
1360 ccc->num_recv++;
1361 if (GNUNET_YES == duplicate)
1362 {
1363 /* Duplicate within the queue, drop also (this is not covered by
1364 the case above if "delta" >= 64, which could be the case if
1365 max_pending_messages is also >= 64 or if our client is unready
1366 and we are seeing retransmissions of the message our client is
1367 blocked on. */
1368 LOG (GNUNET_ERROR_TYPE_DEBUG,
1369 "Duplicate payload of %u bytes on %s (mid %u) dropped\n",
1370 (unsigned int) payload_size,
1371 GCCH_2s (ch),
1372 ntohl (msg->mid.mid));
1373 GNUNET_STATISTICS_update (stats,
1374 "# duplicate DATA",
1375 1,
1376 GNUNET_NO);
1377 GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
1378 ccc->tail_recv,
1379 com);
1380 ccc->num_recv--;
1381 GNUNET_MQ_discard (com->env);
1382 GNUNET_free (com);
1383 send_channel_data_ack (ch);
1384 return;
1385 }
1386 LOG (GNUNET_ERROR_TYPE_DEBUG,
1387 "Queued %s payload of %u bytes on %s-%X(%p) (mid %u, need %u first)\n",
1388 (GNUNET_YES == ccc->client_ready)
1389 ? "out-of-order"
1390 : "client-not-ready",
1391 (unsigned int) payload_size,
1392 GCCH_2s (ch),
1393 ntohl (ccc->ccn.channel_of_client),
1394 ccc,
1395 ntohl (msg->mid.mid),
1396 ntohl (ch->mid_recv.mid));
1397 /* NOTE: this ACK we _could_ skip, as the packet is out-of-order and
1398 the sender may already be transmitting the previous one. Needs
1399 experimental evaluation to see if/when this ACK helps or
1400 hurts. (We might even want another option.) */
1401 send_channel_data_ack (ch);
1402}
1403
1404
1405/**
1406 * Function called once the tunnel has sent one of our messages.
1407 * If the message is unreliable, simply frees the `crm`. If the
1408 * message was reliable, calculate retransmission time and
1409 * wait for ACK (or retransmit).
1410 *
1411 * @param cls the `struct CadetReliableMessage` that was sent
1412 * @param cid identifier of the connection within the tunnel, NULL
1413 * if transmission failed
1414 */
1415static void
1416data_sent_cb (void *cls,
1417 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid);
1418
1419
1420/**
1421 * We need to retry a transmission, the last one took too long to
1422 * be acknowledged.
1423 *
1424 * @param cls the `struct CadetChannel` where we need to retransmit
1425 */
1426static void
1427retry_transmission (void *cls)
1428{
1429 struct CadetChannel *ch = cls;
1430 struct CadetReliableMessage *crm = ch->head_sent;
1431
1432 ch->retry_data_task = NULL;
1433 GNUNET_assert (NULL == crm->qe);
1434 LOG (GNUNET_ERROR_TYPE_DEBUG,
1435 "Retrying transmission on %s of message %u\n",
1436 GCCH_2s (ch),
1437 (unsigned int) ntohl (crm->data_message->mid.mid));
1438 crm->qe = GCT_send (ch->t,
1439 &crm->data_message->header,
1440 &data_sent_cb,
1441 crm);
1442 GNUNET_assert (NULL == ch->retry_data_task);
1443}
1444
1445
1446/**
1447 * We got an PLAINTEXT_DATA_ACK for a message in our queue, remove it from
1448 * the queue and tell our client that it can send more.
1449 *
1450 * @param ch the channel that got the PLAINTEXT_DATA_ACK
1451 * @param cti identifier of the connection that delivered the message
1452 * @param crm the message that got acknowledged
1453 */
1454static void
1455handle_matching_ack (struct CadetChannel *ch,
1456 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
1457 struct CadetReliableMessage *crm)
1458{
1459 GNUNET_CONTAINER_DLL_remove (ch->head_sent,
1460 ch->tail_sent,
1461 crm);
1462 ch->pending_messages--;
1463 GNUNET_assert (ch->pending_messages < ch->max_pending_messages);
1464 LOG (GNUNET_ERROR_TYPE_DEBUG,
1465 "Received DATA_ACK on %s for message %u (%u ACKs pending)\n",
1466 GCCH_2s (ch),
1467 (unsigned int) ntohl (crm->data_message->mid.mid),
1468 ch->pending_messages);
1469 if (NULL != crm->qe)
1470 {
1471 GCT_send_cancel (crm->qe);
1472 crm->qe = NULL;
1473 }
1474 if ( (1 == crm->num_transmissions) &&
1475 (NULL != cti) )
1476 {
1477 GCC_ack_observed (cti);
1478 if (0 == memcmp (cti,
1479 &crm->connection_taken,
1480 sizeof (struct GNUNET_CADET_ConnectionTunnelIdentifier)))
1481 {
1482 GCC_latency_observed (cti,
1483 GNUNET_TIME_absolute_get_duration (crm->first_transmission_time));
1484 }
1485 }
1486 GNUNET_free (crm->data_message);
1487 GNUNET_free (crm);
1488 send_ack_to_client (ch,
1489 (NULL == ch->owner)
1490 ? GNUNET_NO
1491 : GNUNET_YES);
1492}
1493
1494
1495/**
1496 * We got an acknowledgement for payload data for a channel.
1497 * Possibly resume transmissions.
1498 *
1499 * @param ch channel that got the ack
1500 * @param cti identifier of the connection that delivered the message
1501 * @param ack details about what was received
1502 */
1503void
1504GCCH_handle_channel_plaintext_data_ack (struct CadetChannel *ch,
1505 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
1506 const struct GNUNET_CADET_ChannelDataAckMessage *ack)
1507{
1508 struct CadetReliableMessage *crm;
1509 struct CadetReliableMessage *crmn;
1510 int found;
1511 uint32_t mid_base;
1512 uint64_t mid_mask;
1513 unsigned int delta;
1514
1515 GNUNET_break (GNUNET_NO == ch->is_loopback);
1516 if (GNUNET_NO == ch->reliable)
1517 {
1518 /* not expecting ACKs on unreliable channel, odd */
1519 GNUNET_break_op (0);
1520 return;
1521 }
1522 /* mid_base is the MID of the next message that the
1523 other peer expects (i.e. that is missing!), everything
1524 LOWER (but excluding mid_base itself) was received. */
1525 mid_base = ntohl (ack->mid.mid);
1526 mid_mask = GNUNET_htonll (ack->futures);
1527 found = GNUNET_NO;
1528 for (crm = ch->head_sent;
1529 NULL != crm;
1530 crm = crmn)
1531 {
1532 crmn = crm->next;
1533 delta = (unsigned int) (ntohl (crm->data_message->mid.mid) - mid_base);
1534 if (delta >= UINT_MAX - ch->max_pending_messages)
1535 {
1536 /* overflow, means crm was a bit in the past, so this ACK counts for it. */
1537 LOG (GNUNET_ERROR_TYPE_DEBUG,
1538 "Got DATA_ACK with base %u satisfying past message %u on %s\n",
1539 (unsigned int) mid_base,
1540 ntohl (crm->data_message->mid.mid),
1541 GCCH_2s (ch));
1542 handle_matching_ack (ch,
1543 cti,
1544 crm);
1545 found = GNUNET_YES;
1546 continue;
1547 }
1548 delta--;
1549 if (delta >= 64)
1550 continue;
1551 LOG (GNUNET_ERROR_TYPE_DEBUG,
1552 "Testing bit %llX for mid %u (base: %u)\n",
1553 (1LLU << delta),
1554 ntohl (crm->data_message->mid.mid),
1555 mid_base);
1556 if (0 != (mid_mask & (1LLU << delta)))
1557 {
1558 LOG (GNUNET_ERROR_TYPE_DEBUG,
1559 "Got DATA_ACK with mask for %u on %s\n",
1560 ntohl (crm->data_message->mid.mid),
1561 GCCH_2s (ch));
1562 handle_matching_ack (ch,
1563 cti,
1564 crm);
1565 found = GNUNET_YES;
1566 }
1567 }
1568 if (GNUNET_NO == found)
1569 {
1570 /* ACK for message we already dropped, might have been a
1571 duplicate ACK? Ignore. */
1572 LOG (GNUNET_ERROR_TYPE_DEBUG,
1573 "Duplicate DATA_ACK on %s, ignoring\n",
1574 GCCH_2s (ch));
1575 GNUNET_STATISTICS_update (stats,
1576 "# duplicate DATA_ACKs",
1577 1,
1578 GNUNET_NO);
1579 return;
1580 }
1581 if (NULL != ch->retry_data_task)
1582 {
1583 GNUNET_SCHEDULER_cancel (ch->retry_data_task);
1584 ch->retry_data_task = NULL;
1585 }
1586 if ( (NULL != ch->head_sent) &&
1587 (NULL == ch->head_sent->qe) )
1588 ch->retry_data_task
1589 = GNUNET_SCHEDULER_add_at (ch->head_sent->next_retry,
1590 &retry_transmission,
1591 ch);
1592}
1593
1594
1595/**
1596 * Destroy channel, based on the other peer closing the
1597 * connection. Also needs to remove this channel from
1598 * the tunnel.
1599 *
1600 * @param ch channel to destroy
1601 * @param cti identifier of the connection that delivered the message,
1602 * NULL if we are simulating receiving a destroy due to shutdown
1603 */
1604void
1605GCCH_handle_remote_destroy (struct CadetChannel *ch,
1606 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti)
1607{
1608 struct CadetChannelClient *ccc;
1609
1610 GNUNET_assert (GNUNET_NO == ch->is_loopback);
1611 LOG (GNUNET_ERROR_TYPE_DEBUG,
1612 "Received remote channel DESTROY for %s\n",
1613 GCCH_2s (ch));
1614 if (GNUNET_YES == ch->destroy)
1615 {
1616 /* Local client already gone, this is instant-death. */
1617 channel_destroy (ch);
1618 return;
1619 }
1620 ccc = (NULL != ch->owner) ? ch->owner : ch->dest;
1621 if ( (NULL != ccc) &&
1622 (NULL != ccc->head_recv) )
1623 {
1624 LOG (GNUNET_ERROR_TYPE_WARNING,
1625 "Lost end of transmission due to remote shutdown on %s\n",
1626 GCCH_2s (ch));
1627 /* FIXME: change API to notify client about truncated transmission! */
1628 }
1629 ch->destroy = GNUNET_YES;
1630 if (NULL != ccc)
1631 GSC_handle_remote_channel_destroy (ccc->c,
1632 ccc->ccn,
1633 ch);
1634 channel_destroy (ch);
1635}
1636
1637
1638/**
1639 * Test if element @a e1 comes before element @a e2.
1640 *
1641 * @param cls closure, to a flag where we indicate duplicate packets
1642 * @param crm1 an element of to sort
1643 * @param crm2 another element to sort
1644 * @return #GNUNET_YES if @e1 < @e2, otherwise #GNUNET_NO
1645 */
1646static int
1647cmp_crm_by_next_retry (void *cls,
1648 struct CadetReliableMessage *crm1,
1649 struct CadetReliableMessage *crm2)
1650{
1651 if (crm1->next_retry.abs_value_us <
1652 crm2->next_retry.abs_value_us)
1653 return GNUNET_YES;
1654 return GNUNET_NO;
1655}
1656
1657
1658/**
1659 * Function called once the tunnel has sent one of our messages.
1660 * If the message is unreliable, simply frees the `crm`. If the
1661 * message was reliable, calculate retransmission time and
1662 * wait for ACK (or retransmit).
1663 *
1664 * @param cls the `struct CadetReliableMessage` that was sent
1665 * @param cid identifier of the connection within the tunnel, NULL
1666 * if transmission failed
1667 */
1668static void
1669data_sent_cb (void *cls,
1670 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
1671{
1672 struct CadetReliableMessage *crm = cls;
1673 struct CadetChannel *ch = crm->ch;
1674
1675 GNUNET_assert (GNUNET_NO == ch->is_loopback);
1676 GNUNET_assert (NULL != crm->qe);
1677 crm->qe = NULL;
1678 GNUNET_CONTAINER_DLL_remove (ch->head_sent,
1679 ch->tail_sent,
1680 crm);
1681 if (GNUNET_NO == ch->reliable)
1682 {
1683 GNUNET_free (crm->data_message);
1684 GNUNET_free (crm);
1685 ch->pending_messages--;
1686 send_ack_to_client (ch,
1687 (NULL == ch->owner)
1688 ? GNUNET_NO
1689 : GNUNET_YES);
1690 return;
1691 }
1692 if (NULL == cid)
1693 {
1694 /* There was an error sending. */
1695 crm->num_transmissions = GNUNET_SYSERR;
1696 }
1697 else if (GNUNET_SYSERR != crm->num_transmissions)
1698 {
1699 /* Increment transmission counter, and possibly store @a cid
1700 if this was the first transmission. */
1701 crm->num_transmissions++;
1702 if (1 == crm->num_transmissions)
1703 {
1704 crm->first_transmission_time = GNUNET_TIME_absolute_get ();
1705 crm->connection_taken = *cid;
1706 GCC_ack_expected (cid);
1707 }
1708 }
1709 if ( (0 == crm->retry_delay.rel_value_us) &&
1710 (NULL != cid) )
1711 {
1712 struct CadetConnection *cc = GCC_lookup (cid);
1713
1714 if (NULL != cc)
1715 crm->retry_delay = GCC_get_metrics (cc)->aged_latency;
1716 else
1717 crm->retry_delay = ch->retry_time;
1718 }
1719 crm->retry_delay = GNUNET_TIME_STD_BACKOFF (crm->retry_delay);
1720 crm->retry_delay = GNUNET_TIME_relative_max (crm->retry_delay,
1721 MIN_RTT_DELAY);
1722 crm->next_retry = GNUNET_TIME_relative_to_absolute (crm->retry_delay);
1723
1724 GNUNET_CONTAINER_DLL_insert_sorted (struct CadetReliableMessage,
1725 cmp_crm_by_next_retry,
1726 NULL,
1727 ch->head_sent,
1728 ch->tail_sent,
1729 crm);
1730 LOG (GNUNET_ERROR_TYPE_DEBUG,
1731 "Message %u sent, next transmission on %s in %s\n",
1732 (unsigned int) ntohl (crm->data_message->mid.mid),
1733 GCCH_2s (ch),
1734 GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (ch->head_sent->next_retry),
1735 GNUNET_YES));
1736 if (NULL == ch->head_sent->qe)
1737 {
1738 if (NULL != ch->retry_data_task)
1739 GNUNET_SCHEDULER_cancel (ch->retry_data_task);
1740 ch->retry_data_task
1741 = GNUNET_SCHEDULER_add_at (ch->head_sent->next_retry,
1742 &retry_transmission,
1743 ch);
1744 }
1745}
1746
1747
1748/**
1749 * Handle data given by a client.
1750 *
1751 * Check whether the client is allowed to send in this tunnel, save if
1752 * channel is reliable and send an ACK to the client if there is still
1753 * buffer space in the tunnel.
1754 *
1755 * @param ch Channel.
1756 * @param sender_ccn ccn of the sender
1757 * @param buf payload to transmit.
1758 * @param buf_len number of bytes in @a buf
1759 * @return #GNUNET_OK if everything goes well,
1760 * #GNUNET_SYSERR in case of an error.
1761 */
1762int
1763GCCH_handle_local_data (struct CadetChannel *ch,
1764 struct GNUNET_CADET_ClientChannelNumber sender_ccn,
1765 const char *buf,
1766 size_t buf_len)
1767{
1768 struct CadetReliableMessage *crm;
1769
1770 if (ch->pending_messages > ch->max_pending_messages)
1771 {
1772 GNUNET_break (0);
1773 return GNUNET_SYSERR;
1774 }
1775 if (GNUNET_YES == ch->destroy)
1776 {
1777 /* we are going down, drop messages */
1778 return GNUNET_OK;
1779 }
1780 ch->pending_messages++;
1781
1782 if (GNUNET_YES == ch->is_loopback)
1783 {
1784 struct CadetChannelClient *receiver;
1785 struct GNUNET_MQ_Envelope *env;
1786 struct GNUNET_CADET_LocalData *ld;
1787 int ack_to_owner;
1788
1789 env = GNUNET_MQ_msg_extra (ld,
1790 buf_len,
1791 GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA);
1792 if ( (NULL != ch->owner) &&
1793 (sender_ccn.channel_of_client ==
1794 ch->owner->ccn.channel_of_client) )
1795 {
1796 receiver = ch->dest;
1797 ack_to_owner = GNUNET_YES;
1798 }
1799 else if ( (NULL != ch->dest) &&
1800 (sender_ccn.channel_of_client ==
1801 ch->dest->ccn.channel_of_client) )
1802 {
1803 receiver = ch->owner;
1804 ack_to_owner = GNUNET_NO;
1805 }
1806 else
1807 {
1808 GNUNET_break (0);
1809 return GNUNET_SYSERR;
1810 }
1811 ld->ccn = receiver->ccn;
1812 GNUNET_memcpy (&ld[1],
1813 buf,
1814 buf_len);
1815 if (GNUNET_YES == receiver->client_ready)
1816 {
1817 ch->pending_messages--;
1818 GSC_send_to_client (receiver->c,
1819 env);
1820 send_ack_to_client (ch,
1821 ack_to_owner);
1822 }
1823 else
1824 {
1825 struct CadetOutOfOrderMessage *oom;
1826
1827 oom = GNUNET_new (struct CadetOutOfOrderMessage);
1828 oom->env = env;
1829 GNUNET_CONTAINER_DLL_insert_tail (receiver->head_recv,
1830 receiver->tail_recv,
1831 oom);
1832 receiver->num_recv++;
1833 }
1834 return GNUNET_OK;
1835 }
1836
1837 /* Everything is correct, send the message. */
1838 crm = GNUNET_malloc (sizeof (*crm));
1839 crm->ch = ch;
1840 crm->data_message = GNUNET_malloc (sizeof (struct GNUNET_CADET_ChannelAppDataMessage)
1841 + buf_len);
1842 crm->data_message->header.size = htons (sizeof (struct GNUNET_CADET_ChannelAppDataMessage) + buf_len);
1843 crm->data_message->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA);
1844 ch->mid_send.mid = htonl (ntohl (ch->mid_send.mid) + 1);
1845 crm->data_message->mid = ch->mid_send;
1846 crm->data_message->ctn = ch->ctn;
1847 GNUNET_memcpy (&crm->data_message[1],
1848 buf,
1849 buf_len);
1850 GNUNET_CONTAINER_DLL_insert_tail (ch->head_sent,
1851 ch->tail_sent,
1852 crm);
1853 LOG (GNUNET_ERROR_TYPE_DEBUG,
1854 "Sending message %u from local client to %s with %u bytes\n",
1855 ntohl (crm->data_message->mid.mid),
1856 GCCH_2s (ch),
1857 buf_len);
1858 if (NULL != ch->retry_data_task)
1859 {
1860 GNUNET_SCHEDULER_cancel (ch->retry_data_task);
1861 ch->retry_data_task = NULL;
1862 }
1863 crm->qe = GCT_send (ch->t,
1864 &crm->data_message->header,
1865 &data_sent_cb,
1866 crm);
1867 GNUNET_assert (NULL == ch->retry_data_task);
1868 return GNUNET_OK;
1869}
1870
1871
1872/**
1873 * Handle ACK from client on local channel. Means the client is ready
1874 * for more data, see if we have any for it.
1875 *
1876 * @param ch channel to destroy
1877 * @param client_ccn ccn of the client sending the ack
1878 */
1879void
1880GCCH_handle_local_ack (struct CadetChannel *ch,
1881 struct GNUNET_CADET_ClientChannelNumber client_ccn)
1882{
1883 struct CadetChannelClient *ccc;
1884 struct CadetOutOfOrderMessage *com;
1885
1886 if ( (NULL != ch->owner) &&
1887 (ch->owner->ccn.channel_of_client == client_ccn.channel_of_client) )
1888 ccc = ch->owner;
1889 else if ( (NULL != ch->dest) &&
1890 (ch->dest->ccn.channel_of_client == client_ccn.channel_of_client) )
1891 ccc = ch->dest;
1892 else
1893 GNUNET_assert (0);
1894 ccc->client_ready = GNUNET_YES;
1895 com = ccc->head_recv;
1896 if (NULL == com)
1897 {
1898 LOG (GNUNET_ERROR_TYPE_DEBUG,
1899 "Got LOCAL_ACK, %s-%X ready to receive more data, but none pending on %s-%X(%p)!\n",
1900 GSC_2s (ccc->c),
1901 ntohl (client_ccn.channel_of_client),
1902 GCCH_2s (ch),
1903 ntohl (ccc->ccn.channel_of_client),
1904 ccc);
1905 return; /* none pending */
1906 }
1907 if (GNUNET_YES == ch->is_loopback)
1908 {
1909 int to_owner;
1910
1911 /* Messages are always in-order, just send */
1912 GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
1913 ccc->tail_recv,
1914 com);
1915 ccc->num_recv--;
1916 GSC_send_to_client (ccc->c,
1917 com->env);
1918 /* Notify sender that we can receive more */
1919 if (ccc->ccn.channel_of_client ==
1920 ch->owner->ccn.channel_of_client)
1921 {
1922 to_owner = GNUNET_NO;
1923 }
1924 else
1925 {
1926 GNUNET_assert (ccc->ccn.channel_of_client ==
1927 ch->dest->ccn.channel_of_client);
1928 to_owner = GNUNET_YES;
1929 }
1930 send_ack_to_client (ch,
1931 to_owner);
1932 GNUNET_free (com);
1933 return;
1934 }
1935
1936 if ( (com->mid.mid != ch->mid_recv.mid) &&
1937 (GNUNET_NO == ch->out_of_order) &&
1938 (GNUNET_YES == ch->reliable) )
1939 {
1940 LOG (GNUNET_ERROR_TYPE_DEBUG,
1941 "Got LOCAL_ACK, %s-%X ready to receive more data (but next one is out-of-order %u vs. %u)!\n",
1942 GSC_2s (ccc->c),
1943 ntohl (ccc->ccn.channel_of_client),
1944 ntohl (com->mid.mid),
1945 ntohl (ch->mid_recv.mid));
1946 return; /* missing next one in-order */
1947 }
1948
1949 LOG (GNUNET_ERROR_TYPE_DEBUG,
1950 "Got LOCAL_ACK, giving payload message %u to %s-%X on %s\n",
1951 ntohl (com->mid.mid),
1952 GSC_2s (ccc->c),
1953 ntohl (ccc->ccn.channel_of_client),
1954 GCCH_2s (ch));
1955
1956 /* all good, pass next message to client */
1957 GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
1958 ccc->tail_recv,
1959 com);
1960 ccc->num_recv--;
1961 /* FIXME: if unreliable, this is not aggressive
1962 enough, as it would be OK to have lost some! */
1963
1964 ch->mid_recv.mid = htonl (1 + ntohl (com->mid.mid));
1965 ch->mid_futures >>= 1; /* equivalent to division by 2 */
1966 ccc->client_ready = GNUNET_NO;
1967 GSC_send_to_client (ccc->c,
1968 com->env);
1969 GNUNET_free (com);
1970 send_channel_data_ack (ch);
1971 if (NULL != ccc->head_recv)
1972 return;
1973 if (GNUNET_NO == ch->destroy)
1974 return;
1975 GCT_send_channel_destroy (ch->t,
1976 ch->ctn);
1977 channel_destroy (ch);
1978}
1979
1980
1981#define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-chn",__VA_ARGS__)
1982
1983
1984/**
1985 * Log channel info.
1986 *
1987 * @param ch Channel.
1988 * @param level Debug level to use.
1989 */
1990void
1991GCCH_debug (struct CadetChannel *ch,
1992 enum GNUNET_ErrorType level)
1993{
1994 int do_log;
1995
1996 do_log = GNUNET_get_log_call_status (level & (~GNUNET_ERROR_TYPE_BULK),
1997 "cadet-chn",
1998 __FILE__, __FUNCTION__, __LINE__);
1999 if (0 == do_log)
2000 return;
2001
2002 if (NULL == ch)
2003 {
2004 LOG2 (level, "CHN *** DEBUG NULL CHANNEL ***\n");
2005 return;
2006 }
2007 LOG2 (level,
2008 "CHN %s:%X (%p)\n",
2009 GCT_2s (ch->t),
2010 ch->ctn,
2011 ch);
2012 if (NULL != ch->owner)
2013 {
2014 LOG2 (level,
2015 "CHN origin %s ready %s local-id: %u\n",
2016 GSC_2s (ch->owner->c),
2017 ch->owner->client_ready ? "YES" : "NO",
2018 ntohl (ch->owner->ccn.channel_of_client));
2019 }
2020 if (NULL != ch->dest)
2021 {
2022 LOG2 (level,
2023 "CHN destination %s ready %s local-id: %u\n",
2024 GSC_2s (ch->dest->c),
2025 ch->dest->client_ready ? "YES" : "NO",
2026 ntohl (ch->dest->ccn.channel_of_client));
2027 }
2028 LOG2 (level,
2029 "CHN Message IDs recv: %d (%LLX), send: %d\n",
2030 ntohl (ch->mid_recv.mid),
2031 (unsigned long long) ch->mid_futures,
2032 ntohl (ch->mid_send.mid));
2033}
2034
2035
2036
2037/* end of gnunet-service-cadet-new_channel.c */
diff --git a/src/cadet/gnunet-service-cadet-new_channel.h b/src/cadet/gnunet-service-cadet-new_channel.h
deleted file mode 100644
index 5167305a6..000000000
--- a/src/cadet/gnunet-service-cadet-new_channel.h
+++ /dev/null
@@ -1,262 +0,0 @@
1
2/*
3 This file is part of GNUnet.
4 Copyright (C) 2001-2017 GNUnet e.V.
5
6 GNUnet is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published
8 by the Free Software Foundation; either version 3, or (at your
9 option) any later version.
10
11 GNUnet is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNUnet; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA.
20*/
21
22/**
23 * @file cadet/gnunet-service-cadet-new_channel.h
24 * @brief GNUnet CADET service with encryption
25 * @author Bartlomiej Polot
26 * @author Christian Grothoff
27 */
28#ifndef GNUNET_SERVICE_CADET_CHANNEL_H
29#define GNUNET_SERVICE_CADET_CHANNEL_H
30
31#include "gnunet-service-cadet-new.h"
32#include "gnunet-service-cadet-new_peer.h"
33#include "cadet_protocol.h"
34
35
36/**
37 * A channel is a bidirectional connection between two CADET
38 * clients. Communiation can be reliable, unreliable, in-order
39 * or out-of-order. One client is the "local" client, this
40 * one initiated the connection. The other client is the
41 * "incoming" client, this one listened on a port to accept
42 * the connection from the "local" client.
43 */
44struct CadetChannel;
45
46
47/**
48 * Get the static string for identification of the channel.
49 *
50 * @param ch Channel.
51 *
52 * @return Static string with the channel IDs.
53 */
54const char *
55GCCH_2s (const struct CadetChannel *ch);
56
57
58/**
59 * Log channel info.
60 *
61 * @param ch Channel.
62 * @param level Debug level to use.
63 */
64void
65GCCH_debug (struct CadetChannel *ch,
66 enum GNUNET_ErrorType level);
67
68
69/**
70 * Get the channel's public ID.
71 *
72 * @param ch Channel.
73 *
74 * @return ID used to identify the channel with the remote peer.
75 */
76struct GNUNET_CADET_ChannelTunnelNumber
77GCCH_get_id (const struct CadetChannel *ch);
78
79
80/**
81 * Create a new channel.
82 *
83 * @param owner local client owning the channel
84 * @param owner_id local chid of this channel at the @a owner
85 * @param destination peer to which we should build the channel
86 * @param port desired port at @a destination
87 * @param options options for the channel
88 * @return handle to the new channel
89 */
90struct CadetChannel *
91GCCH_channel_local_new (struct CadetClient *owner,
92 struct GNUNET_CADET_ClientChannelNumber owner_id,
93 struct CadetPeer *destination,
94 const struct GNUNET_HashCode *port,
95 uint32_t options);
96
97
98/**
99 * A client is bound to the port that we have a channel
100 * open to. Send the acknowledgement for the connection
101 * request and establish the link with the client.
102 *
103 * @param ch open incoming channel
104 * @param c client listening on the respective port
105 */
106void
107GCCH_bind (struct CadetChannel *ch,
108 struct CadetClient *c);
109
110
111/**
112 * Destroy locally created channel. Called by the
113 * local client, so no need to tell the client.
114 *
115 * @param ch channel to destroy
116 * @param c client that caused the destruction
117 * @param ccn client number of the client @a c
118 */
119void
120GCCH_channel_local_destroy (struct CadetChannel *ch,
121 struct CadetClient *c,
122 struct GNUNET_CADET_ClientChannelNumber ccn);
123
124
125/**
126 * Function called once and only once after a channel was bound
127 * to its tunnel via #GCT_add_channel() is ready for transmission.
128 * Note that this is only the case for channels that this peer
129 * initiates, as for incoming channels we assume that they are
130 * ready for transmission immediately upon receiving the open
131 * message. Used to bootstrap the #GCT_send() process.
132 *
133 * @param ch the channel for which the tunnel is now ready
134 */
135void
136GCCH_tunnel_up (struct CadetChannel *ch);
137
138
139/**
140 * Create a new channel based on a request coming in over the network.
141 *
142 * @param t tunnel to the remote peer
143 * @param chid identifier of this channel in the tunnel
144 * @param origin peer to who initiated the channel
145 * @param port desired local port
146 * @param options options for the channel
147 * @return handle to the new channel
148 */
149struct CadetChannel *
150GCCH_channel_incoming_new (struct CadetTunnel *t,
151 struct GNUNET_CADET_ChannelTunnelNumber chid,
152 const struct GNUNET_HashCode *port,
153 uint32_t options);
154
155
156/**
157 * We got a #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN message again for
158 * this channel. If the binding was successful, (re)transmit the
159 * #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK.
160 *
161 * @param ch channel that got the duplicate open
162 * @param cti identifier of the connection that delivered the message
163 */
164void
165GCCH_handle_duplicate_open (struct CadetChannel *ch,
166 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti);
167
168
169
170/**
171 * We got payload data for a channel. Pass it on to the client.
172 *
173 * @param ch channel that got data
174 * @param cti identifier of the connection that delivered the message
175 * @param msg message that was received
176 */
177void
178GCCH_handle_channel_plaintext_data (struct CadetChannel *ch,
179 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
180 const struct GNUNET_CADET_ChannelAppDataMessage *msg);
181
182
183/**
184 * We got an acknowledgement for payload data for a channel.
185 * Possibly resume transmissions.
186 *
187 * @param ch channel that got the ack
188 * @param cti identifier of the connection that delivered the message
189 * @param ack details about what was received
190 */
191void
192GCCH_handle_channel_plaintext_data_ack (struct CadetChannel *ch,
193 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
194 const struct GNUNET_CADET_ChannelDataAckMessage *ack);
195
196
197/**
198 * We got an acknowledgement for the creation of the channel
199 * (the port is open on the other side). Begin transmissions.
200 *
201 * @param ch channel to destroy
202 * @param cti identifier of the connection that delivered the message,
203 * NULL if the ACK was inferred because we got payload or are on loopback
204 */
205void
206GCCH_handle_channel_open_ack (struct CadetChannel *ch,
207 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti);
208
209
210/**
211 * Destroy channel, based on the other peer closing the
212 * connection. Also needs to remove this channel from
213 * the tunnel.
214 *
215 * FIXME: need to make it possible to defer destruction until we have
216 * received all messages up to the destroy, and right now the destroy
217 * message (and this API) fails to give is the information we need!
218 *
219 * FIXME: also need to know if the other peer got a destroy from
220 * us before!
221 *
222 * @param ch channel to destroy
223 * @param cti identifier of the connection that delivered the message,
224 * NULL during shutdown
225 */
226void
227GCCH_handle_remote_destroy (struct CadetChannel *ch,
228 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti);
229
230
231/**
232 * Handle data given by a client.
233 *
234 * Check whether the client is allowed to send in this tunnel, save if
235 * channel is reliable and send an ACK to the client if there is still
236 * buffer space in the tunnel.
237 *
238 * @param ch Channel.
239 * @param sender_ccn ccn of the sender
240 * @param buf payload to transmit.
241 * @param buf_len number of bytes in @a buf
242 * @return #GNUNET_OK if everything goes well,
243 * #GNUNET_SYSERR in case of an error.
244 */
245int
246GCCH_handle_local_data (struct CadetChannel *ch,
247 struct GNUNET_CADET_ClientChannelNumber sender_ccn,
248 const char *buf,
249 size_t buf_len);
250
251
252/**
253 * Handle ACK from client on local channel.
254 *
255 * @param ch channel to destroy
256 * @param client_ccn ccn of the client sending the ack
257 */
258void
259GCCH_handle_local_ack (struct CadetChannel *ch,
260 struct GNUNET_CADET_ClientChannelNumber client_ccn);
261
262#endif
diff --git a/src/cadet/gnunet-service-cadet-new_connection.c b/src/cadet/gnunet-service-cadet-new_connection.c
deleted file mode 100644
index 6976e66e4..000000000
--- a/src/cadet/gnunet-service-cadet-new_connection.c
+++ /dev/null
@@ -1,1093 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2001-2017 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21/**
22 * @file cadet/gnunet-service-cadet-new_connection.c
23 * @brief management of CORE-level end-to-end connections; establishes
24 * end-to-end routes and transmits messages along the route
25 * @author Bartlomiej Polot
26 * @author Christian Grothoff
27 */
28#include "platform.h"
29#include "gnunet-service-cadet-new.h"
30#include "gnunet-service-cadet-new_channel.h"
31#include "gnunet-service-cadet-new_connection.h"
32#include "gnunet-service-cadet-new_paths.h"
33#include "gnunet-service-cadet-new_peer.h"
34#include "gnunet-service-cadet-new_tunnels.h"
35#include "gnunet_cadet_service.h"
36#include "gnunet_statistics_service.h"
37#include "cadet_protocol.h"
38
39
40#define LOG(level, ...) GNUNET_log_from(level,"cadet-con",__VA_ARGS__)
41
42
43/**
44 * All the states a connection can be in.
45 */
46enum CadetConnectionState
47{
48 /**
49 * Uninitialized status, we have not yet even gotten the message queue.
50 */
51 CADET_CONNECTION_NEW,
52
53 /**
54 * Connection create message in queue, awaiting transmission by CORE.
55 */
56 CADET_CONNECTION_SENDING_CREATE,
57
58 /**
59 * Connection create message sent, waiting for ACK.
60 */
61 CADET_CONNECTION_SENT,
62
63 /**
64 * We are an inbound connection, and received a CREATE. Need to
65 * send an CREATE_ACK back.
66 */
67 CADET_CONNECTION_CREATE_RECEIVED,
68
69 /**
70 * Connection confirmed, ready to carry traffic.
71 */
72 CADET_CONNECTION_READY
73
74};
75
76
77/**
78 * Low-level connection to a destination.
79 */
80struct CadetConnection
81{
82
83 /**
84 * ID of the connection.
85 */
86 struct GNUNET_CADET_ConnectionTunnelIdentifier cid;
87
88 /**
89 * To which peer does this connection go?
90 */
91 struct CadetPeer *destination;
92
93 /**
94 * Which tunnel is using this connection?
95 */
96 struct CadetTConnection *ct;
97
98 /**
99 * Path we are using to our destination.
100 */
101 struct CadetPeerPath *path;
102
103 /**
104 * Pending message, NULL if we are ready to transmit.
105 */
106 struct GNUNET_MQ_Envelope *env;
107
108 /**
109 * Handle for calling #GCP_request_mq_cancel() once we are finished.
110 */
111 struct GCP_MessageQueueManager *mq_man;
112
113 /**
114 * Task for connection maintenance.
115 */
116 struct GNUNET_SCHEDULER_Task *task;
117
118 /**
119 * Queue entry for keepalive messages.
120 */
121 struct CadetTunnelQueueEntry *keepalive_qe;
122
123 /**
124 * Function to call once we are ready to transmit.
125 */
126 GCC_ReadyCallback ready_cb;
127
128 /**
129 * Closure for @e ready_cb.
130 */
131 void *ready_cb_cls;
132
133 /**
134 * How long do we wait before we try again with a CREATE message?
135 */
136 struct GNUNET_TIME_Relative retry_delay;
137
138 /**
139 * Performance metrics for this connection.
140 */
141 struct CadetConnectionMetrics metrics;
142
143 /**
144 * State of the connection.
145 */
146 enum CadetConnectionState state;
147
148 /**
149 * Options for the route, control buffering.
150 */
151 enum GNUNET_CADET_ChannelOption options;
152
153 /**
154 * How many latency observations did we make for this connection?
155 */
156 unsigned int latency_datapoints;
157
158 /**
159 * Offset of our @e destination in @e path.
160 */
161 unsigned int off;
162
163 /**
164 * Are we ready to transmit via @e mq_man right now?
165 */
166 int mqm_ready;
167
168};
169
170
171/**
172 * Lookup a connection by its identifier.
173 *
174 * @param cid identifier to resolve
175 * @return NULL if connection was not found
176 */
177struct CadetConnection *
178GCC_lookup (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
179{
180 return GNUNET_CONTAINER_multishortmap_get (connections,
181 &cid->connection_of_tunnel);
182}
183
184
185/**
186 * Update the connection state. Also triggers the necessary
187 * MQM notifications.
188 *
189 * @param cc connection to update the state for
190 * @param new_state new state for @a cc
191 * @param new_mqm_ready new `mqm_ready` state for @a cc
192 */
193static void
194update_state (struct CadetConnection *cc,
195 enum CadetConnectionState new_state,
196 int new_mqm_ready)
197{
198 int old_ready;
199 int new_ready;
200
201 if ( (new_state == cc->state) &&
202 (new_mqm_ready == cc->mqm_ready) )
203 return; /* no change, nothing to do */
204 old_ready = ( (CADET_CONNECTION_READY == cc->state) &&
205 (GNUNET_YES == cc->mqm_ready) );
206 new_ready = ( (CADET_CONNECTION_READY == new_state) &&
207 (GNUNET_YES == new_mqm_ready) );
208 cc->state = new_state;
209 cc->mqm_ready = new_mqm_ready;
210 if (old_ready != new_ready)
211 cc->ready_cb (cc->ready_cb_cls,
212 new_ready);
213}
214
215
216/**
217 * Destroy a connection, part of the internal implementation. Called
218 * only from #GCC_destroy_from_core() or #GCC_destroy_from_tunnel().
219 *
220 * @param cc connection to destroy
221 */
222static void
223GCC_destroy (struct CadetConnection *cc)
224{
225 LOG (GNUNET_ERROR_TYPE_DEBUG,
226 "Destroying %s\n",
227 GCC_2s (cc));
228 if (NULL != cc->mq_man)
229 {
230 GCP_request_mq_cancel (cc->mq_man,
231 NULL);
232 cc->mq_man = NULL;
233 }
234 if (NULL != cc->task)
235 {
236 GNUNET_SCHEDULER_cancel (cc->task);
237 cc->task = NULL;
238 }
239 if (NULL != cc->keepalive_qe)
240 {
241 GCT_send_cancel (cc->keepalive_qe);
242 cc->keepalive_qe = NULL;
243 }
244 GCPP_del_connection (cc->path,
245 cc->off,
246 cc);
247 for (unsigned int i=0;i<cc->off;i++)
248 GCP_remove_connection (GCPP_get_peer_at_offset (cc->path,
249 i),
250 cc);
251 GNUNET_assert (GNUNET_YES ==
252 GNUNET_CONTAINER_multishortmap_remove (connections,
253 &GCC_get_id (cc)->connection_of_tunnel,
254 cc));
255 GNUNET_free (cc);
256}
257
258
259
260/**
261 * Destroy a connection, called when the CORE layer is already done
262 * (i.e. has received a BROKEN message), but if we still have to
263 * communicate the destruction of the connection to the tunnel (if one
264 * exists).
265 *
266 * @param cc connection to destroy
267 */
268void
269GCC_destroy_without_core (struct CadetConnection *cc)
270{
271 if (NULL != cc->ct)
272 {
273 GCT_connection_lost (cc->ct);
274 cc->ct = NULL;
275 }
276 GCC_destroy (cc);
277}
278
279
280/**
281 * Destroy a connection, called if the tunnel association with the
282 * connection was already broken, but we still need to notify the CORE
283 * layer about the breakage.
284 *
285 * @param cc connection to destroy
286 */
287void
288GCC_destroy_without_tunnel (struct CadetConnection *cc)
289{
290 cc->ct = NULL;
291 if ( (CADET_CONNECTION_SENDING_CREATE != cc->state) &&
292 (NULL != cc->mq_man) )
293 {
294 struct GNUNET_MQ_Envelope *env;
295 struct GNUNET_CADET_ConnectionDestroyMessage *destroy_msg;
296
297 /* Need to notify next hop that we are down. */
298 env = GNUNET_MQ_msg (destroy_msg,
299 GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY);
300 destroy_msg->cid = cc->cid;
301 GCP_request_mq_cancel (cc->mq_man,
302 env);
303 cc->mq_man = NULL;
304 }
305 GCC_destroy (cc);
306}
307
308
309/**
310 * Return the tunnel associated with this connection.
311 *
312 * @param cc connection to query
313 * @return corresponding entry in the tunnel's connection list
314 */
315struct CadetTConnection *
316GCC_get_ct (struct CadetConnection *cc)
317{
318 return cc->ct;
319}
320
321
322/**
323 * Obtain performance @a metrics from @a cc.
324 *
325 * @param cc connection to query
326 * @return the metrics
327 */
328const struct CadetConnectionMetrics *
329GCC_get_metrics (struct CadetConnection *cc)
330{
331 return &cc->metrics;
332}
333
334
335/**
336 * Send a #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE through the
337 * tunnel to prevent it from timing out.
338 *
339 * @param cls the `struct CadetConnection` to keep alive.
340 */
341static void
342send_keepalive (void *cls);
343
344
345/**
346 * Keepalive was transmitted. Remember this, and possibly
347 * schedule the next one.
348 *
349 * @param cls the `struct CadetConnection` to keep alive.
350 * @param cid identifier of the connection within the tunnel, NULL
351 * if transmission failed
352 */
353static void
354keepalive_done (void *cls,
355 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
356{
357 struct CadetConnection *cc = cls;
358
359 cc->keepalive_qe = NULL;
360 if ( (GNUNET_YES == cc->mqm_ready) &&
361 (NULL == cc->task) )
362 cc->task = GNUNET_SCHEDULER_add_delayed (keepalive_period,
363 &send_keepalive,
364 cc);
365}
366
367
368/**
369 * Send a #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE through the
370 * tunnel to prevent it from timing out.
371 *
372 * @param cls the `struct CadetConnection` to keep alive.
373 */
374static void
375send_keepalive (void *cls)
376{
377 struct CadetConnection *cc = cls;
378 struct GNUNET_MessageHeader msg;
379
380 cc->task = NULL;
381 if (CADET_TUNNEL_KEY_OK != GCT_get_estate (cc->ct->t))
382 {
383 /* Tunnel not yet ready, wait with keepalives... */
384 cc->task = GNUNET_SCHEDULER_add_delayed (keepalive_period,
385 &send_keepalive,
386 cc);
387 return;
388 }
389 GNUNET_assert (NULL != cc->ct);
390 GNUNET_assert (GNUNET_YES == cc->mqm_ready);
391 GNUNET_assert (NULL == cc->keepalive_qe);
392 LOG (GNUNET_ERROR_TYPE_INFO,
393 "Sending KEEPALIVE on behalf of %s via %s\n",
394 GCC_2s (cc),
395 GCT_2s (cc->ct->t));
396 GNUNET_STATISTICS_update (stats,
397 "# keepalives sent",
398 1,
399 GNUNET_NO);
400 msg.size = htons (sizeof (msg));
401 msg.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE);
402
403 cc->keepalive_qe
404 = GCT_send (cc->ct->t,
405 &msg,
406 &keepalive_done,
407 cc);
408}
409
410
411/**
412 * We sent a message for which we expect to receive an ACK via
413 * the connection identified by @a cti.
414 *
415 * @param cid connection identifier where we expect an ACK
416 */
417void
418GCC_ack_expected (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
419{
420 struct CadetConnection *cc;
421
422 cc = GCC_lookup (cid);
423 if (NULL == cc)
424 return; /* whopise, connection alredy down? */
425 cc->metrics.num_acked_transmissions++;
426}
427
428
429/**
430 * We observed an ACK for a message that was originally sent via
431 * the connection identified by @a cti.
432 *
433 * @param cti connection identifier where we got an ACK for a message
434 * that was originally sent via this connection (the ACK
435 * may have gotten back to us via a different connection).
436 */
437void
438GCC_ack_observed (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
439{
440 struct CadetConnection *cc;
441
442 cc = GCC_lookup (cid);
443 if (NULL == cc)
444 return; /* whopise, connection alredy down? */
445 cc->metrics.num_successes++;
446}
447
448
449/**
450 * We observed some the given @a latency on the connection
451 * identified by @a cti. (The same connection was taken
452 * in both directions.)
453 *
454 * @param cid connection identifier where we measured latency
455 * @param latency the observed latency
456 */
457void
458GCC_latency_observed (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
459 struct GNUNET_TIME_Relative latency)
460{
461 struct CadetConnection *cc;
462 double weight;
463 double result;
464
465 cc = GCC_lookup (cid);
466 if (NULL == cc)
467 return; /* whopise, connection alredy down? */
468 GNUNET_STATISTICS_update (stats,
469 "# latencies observed",
470 1,
471 GNUNET_NO);
472 cc->latency_datapoints++;
473 if (cc->latency_datapoints >= 7)
474 weight = 7.0;
475 else
476 weight = cc->latency_datapoints;
477 /* Compute weighted average, giving at MOST weight 7 to the
478 existing values, or less if that value is based on fewer than 7
479 measurements. */
480 result = (weight * cc->metrics.aged_latency.rel_value_us) + 1.0 * latency.rel_value_us;
481 result /= (weight + 1.0);
482 cc->metrics.aged_latency.rel_value_us = (uint64_t) result;
483}
484
485
486/**
487 * A #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK was received for this connection, implying
488 * that the end-to-end connection is up. Process it.
489 *
490 * @param cc the connection that got the ACK.
491 */
492void
493GCC_handle_connection_create_ack (struct CadetConnection *cc)
494{
495 LOG (GNUNET_ERROR_TYPE_DEBUG,
496 "Received CADET_CONNECTION_CREATE_ACK for %s in state %d (%s)\n",
497 GCC_2s (cc),
498 cc->state,
499 (GNUNET_YES == cc->mqm_ready) ? "MQM ready" : "MQM busy");
500 if (CADET_CONNECTION_READY == cc->state)
501 return; /* Duplicate ACK, ignore */
502 if (NULL != cc->task)
503 {
504 GNUNET_SCHEDULER_cancel (cc->task);
505 cc->task = NULL;
506 }
507 cc->metrics.age = GNUNET_TIME_absolute_get ();
508 update_state (cc,
509 CADET_CONNECTION_READY,
510 cc->mqm_ready);
511 if ( (NULL == cc->keepalive_qe) &&
512 (GNUNET_YES == cc->mqm_ready) &&
513 (NULL == cc->task) )
514 cc->task = GNUNET_SCHEDULER_add_delayed (keepalive_period,
515 &send_keepalive,
516 cc);
517}
518
519
520/**
521 * Handle KX message.
522 *
523 * @param cc connection that received encrypted message
524 * @param msg the key exchange message
525 */
526void
527GCC_handle_kx (struct CadetConnection *cc,
528 const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg)
529{
530 if (CADET_CONNECTION_SENT == cc->state)
531 {
532 /* We didn't get the CADET_CONNECTION_CREATE_ACK, but instead got payload. That's fine,
533 clearly something is working, so pretend we got an ACK. */
534 LOG (GNUNET_ERROR_TYPE_DEBUG,
535 "Faking connection CADET_CONNECTION_CREATE_ACK for %s due to KX\n",
536 GCC_2s (cc));
537 GCC_handle_connection_create_ack (cc);
538 }
539 GCT_handle_kx (cc->ct,
540 msg);
541}
542
543
544/**
545 * Handle KX_AUTH message.
546 *
547 * @param cc connection that received encrypted message
548 * @param msg the key exchange message
549 */
550void
551GCC_handle_kx_auth (struct CadetConnection *cc,
552 const struct GNUNET_CADET_TunnelKeyExchangeAuthMessage *msg)
553{
554 if (CADET_CONNECTION_SENT == cc->state)
555 {
556 /* We didn't get the CADET_CONNECTION_CREATE_ACK, but instead got payload. That's fine,
557 clearly something is working, so pretend we got an ACK. */
558 LOG (GNUNET_ERROR_TYPE_DEBUG,
559 "Faking connection CADET_CONNECTION_CREATE_ACK for %s due to KX\n",
560 GCC_2s (cc));
561 GCC_handle_connection_create_ack (cc);
562 }
563 GCT_handle_kx_auth (cc->ct,
564 msg);
565}
566
567
568/**
569 * Handle encrypted message.
570 *
571 * @param cc connection that received encrypted message
572 * @param msg the encrypted message to decrypt
573 */
574void
575GCC_handle_encrypted (struct CadetConnection *cc,
576 const struct GNUNET_CADET_TunnelEncryptedMessage *msg)
577{
578 if (CADET_CONNECTION_SENT == cc->state)
579 {
580 /* We didn't get the CREATE_ACK, but instead got payload. That's fine,
581 clearly something is working, so pretend we got an ACK. */
582 LOG (GNUNET_ERROR_TYPE_DEBUG,
583 "Faking connection ACK for %s due to ENCRYPTED payload\n",
584 GCC_2s (cc));
585 GCC_handle_connection_create_ack (cc);
586 }
587 cc->metrics.last_use = GNUNET_TIME_absolute_get ();
588 GCT_handle_encrypted (cc->ct,
589 msg);
590}
591
592
593/**
594 * Send a #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE message to the
595 * first hop.
596 *
597 * @param cls the `struct CadetConnection` to initiate
598 */
599static void
600send_create (void *cls)
601{
602 struct CadetConnection *cc = cls;
603 struct GNUNET_CADET_ConnectionCreateMessage *create_msg;
604 struct GNUNET_PeerIdentity *pids;
605 struct GNUNET_MQ_Envelope *env;
606 unsigned int path_length;
607
608 cc->task = NULL;
609 GNUNET_assert (GNUNET_YES == cc->mqm_ready);
610 path_length = GCPP_get_length (cc->path);
611 env = GNUNET_MQ_msg_extra (create_msg,
612 (1 + path_length) * sizeof (struct GNUNET_PeerIdentity),
613 GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE);
614 create_msg->options = htonl ((uint32_t) cc->options);
615 create_msg->cid = cc->cid;
616 pids = (struct GNUNET_PeerIdentity *) &create_msg[1];
617 pids[0] = my_full_id;
618 for (unsigned int i=0;i<path_length;i++)
619 pids[i + 1] = *GCP_get_id (GCPP_get_peer_at_offset (cc->path,
620 i));
621 LOG (GNUNET_ERROR_TYPE_DEBUG,
622 "Sending CADET_CONNECTION_CREATE message for %s\n",
623 GCC_2s (cc));
624 cc->env = env;
625 update_state (cc,
626 CADET_CONNECTION_SENT,
627 GNUNET_NO);
628 GCP_send (cc->mq_man,
629 env);
630}
631
632
633/**
634 * Send a CREATE_ACK message towards the origin.
635 *
636 * @param cls the `struct CadetConnection` to initiate
637 */
638static void
639send_create_ack (void *cls)
640{
641 struct CadetConnection *cc = cls;
642 struct GNUNET_CADET_ConnectionCreateAckMessage *ack_msg;
643 struct GNUNET_MQ_Envelope *env;
644
645 cc->task = NULL;
646 GNUNET_assert (CADET_CONNECTION_CREATE_RECEIVED == cc->state);
647 LOG (GNUNET_ERROR_TYPE_DEBUG,
648 "Sending CONNECTION_CREATE_ACK message for %s\n",
649 GCC_2s (cc));
650 GNUNET_assert (GNUNET_YES == cc->mqm_ready);
651 env = GNUNET_MQ_msg (ack_msg,
652 GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK);
653 ack_msg->cid = cc->cid;
654 cc->env = env;
655 update_state (cc,
656 CADET_CONNECTION_READY,
657 GNUNET_NO);
658 GCP_send (cc->mq_man,
659 env);
660}
661
662
663/**
664 * We got a #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE for a
665 * connection that we already have. Either our ACK got lost
666 * or something is fishy. Consider retransmitting the ACK.
667 *
668 * @param cc connection that got the duplicate CREATE
669 */
670void
671GCC_handle_duplicate_create (struct CadetConnection *cc)
672{
673 if (GNUNET_YES == cc->mqm_ready)
674 {
675 LOG (GNUNET_ERROR_TYPE_DEBUG,
676 "Got duplicate CREATE for %s, scheduling another ACK (%s)\n",
677 GCC_2s (cc),
678 (GNUNET_YES == cc->mqm_ready) ? "MQM ready" : "MQM busy");
679 /* Revert back to the state of having only received the 'CREATE',
680 and immediately proceed to send the CREATE_ACK. */
681 update_state (cc,
682 CADET_CONNECTION_CREATE_RECEIVED,
683 cc->mqm_ready);
684 if (NULL != cc->task)
685 GNUNET_SCHEDULER_cancel (cc->task);
686 cc->task = GNUNET_SCHEDULER_add_now (&send_create_ack,
687 cc);
688 }
689 else
690 {
691 /* We are currently sending something else back, which
692 can only be an ACK or payload, either of which would
693 do. So actually no need to do anything. */
694 LOG (GNUNET_ERROR_TYPE_DEBUG,
695 "Got duplicate CREATE for %s. MQ is busy, not queueing another ACK\n",
696 GCC_2s (cc));
697 }
698}
699
700
701/**
702 * There has been a change in the message queue existence for our
703 * peer at the first hop. Adjust accordingly.
704 *
705 * @param cls the `struct CadetConnection`
706 * @param available #GNUNET_YES if sending is now possible,
707 * #GNUNET_NO if sending is no longer possible
708 * #GNUNET_SYSERR if sending is no longer possible
709 * and the last envelope was discarded
710 */
711static void
712manage_first_hop_mq (void *cls,
713 int available)
714{
715 struct CadetConnection *cc = cls;
716
717 if (GNUNET_YES != available)
718 {
719 /* Connection is down, for now... */
720 LOG (GNUNET_ERROR_TYPE_DEBUG,
721 "Core MQ for %s went down\n",
722 GCC_2s (cc));
723 update_state (cc,
724 CADET_CONNECTION_NEW,
725 GNUNET_NO);
726 cc->retry_delay = GNUNET_TIME_UNIT_ZERO;
727 if (NULL != cc->task)
728 {
729 GNUNET_SCHEDULER_cancel (cc->task);
730 cc->task = NULL;
731 }
732 return;
733 }
734
735 update_state (cc,
736 cc->state,
737 GNUNET_YES);
738 LOG (GNUNET_ERROR_TYPE_DEBUG,
739 "Core MQ for %s became available in state %d\n",
740 GCC_2s (cc),
741 cc->state);
742 switch (cc->state)
743 {
744 case CADET_CONNECTION_NEW:
745 /* Transmit immediately */
746 cc->task = GNUNET_SCHEDULER_add_now (&send_create,
747 cc);
748 break;
749 case CADET_CONNECTION_SENDING_CREATE:
750 /* Should not be possible to be called in this state. */
751 GNUNET_assert (0);
752 break;
753 case CADET_CONNECTION_SENT:
754 /* Retry a bit later... */
755 cc->retry_delay = GNUNET_TIME_STD_BACKOFF (cc->retry_delay);
756 cc->task = GNUNET_SCHEDULER_add_delayed (cc->retry_delay,
757 &send_create,
758 cc);
759 break;
760 case CADET_CONNECTION_CREATE_RECEIVED:
761 /* We got the 'CREATE' (incoming connection), should send the CREATE_ACK */
762 cc->metrics.age = GNUNET_TIME_absolute_get ();
763 cc->task = GNUNET_SCHEDULER_add_now (&send_create_ack,
764 cc);
765 break;
766 case CADET_CONNECTION_READY:
767 if ( (NULL == cc->keepalive_qe) &&
768 (GNUNET_YES == cc->mqm_ready) &&
769 (NULL == cc->task) )
770 {
771 LOG (GNUNET_ERROR_TYPE_DEBUG,
772 "Scheduling keepalive for %s in %s\n",
773 GCC_2s (cc),
774 GNUNET_STRINGS_relative_time_to_string (keepalive_period,
775 GNUNET_YES));
776 cc->task = GNUNET_SCHEDULER_add_delayed (keepalive_period,
777 &send_keepalive,
778 cc);
779 }
780 break;
781 }
782}
783
784
785/**
786 * Create a connection to @a destination via @a path and notify @a cb
787 * whenever we are ready for more data. Shared logic independent of
788 * who is initiating the connection.
789 *
790 * @param destination where to go
791 * @param path which path to take (may not be the full path)
792 * @param off offset of @a destination on @a path
793 * @param options options for the connection
794 * @param ct which tunnel uses this connection
795 * @param init_state initial state for the connection
796 * @param ready_cb function to call when ready to transmit
797 * @param ready_cb_cls closure for @a cb
798 * @return handle to the connection
799 */
800static struct CadetConnection *
801connection_create (struct CadetPeer *destination,
802 struct CadetPeerPath *path,
803 unsigned int off,
804 enum GNUNET_CADET_ChannelOption options,
805 struct CadetTConnection *ct,
806 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
807 enum CadetConnectionState init_state,
808 GCC_ReadyCallback ready_cb,
809 void *ready_cb_cls)
810{
811 struct CadetConnection *cc;
812 struct CadetPeer *first_hop;
813
814 cc = GNUNET_new (struct CadetConnection);
815 cc->options = options;
816 cc->state = init_state;
817 cc->ct = ct;
818 cc->cid = *cid;
819 GNUNET_assert (GNUNET_OK ==
820 GNUNET_CONTAINER_multishortmap_put (connections,
821 &GCC_get_id (cc)->connection_of_tunnel,
822 cc,
823 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
824 cc->ready_cb = ready_cb;
825 cc->ready_cb_cls = ready_cb_cls;
826 cc->path = path;
827 cc->off = off;
828 LOG (GNUNET_ERROR_TYPE_DEBUG,
829 "Creating %s using path %s\n",
830 GCC_2s (cc),
831 GCPP_2s (path));
832 GCPP_add_connection (path,
833 off,
834 cc);
835 for (unsigned int i=0;i<off;i++)
836 GCP_add_connection (GCPP_get_peer_at_offset (path,
837 i),
838 cc);
839
840 first_hop = GCPP_get_peer_at_offset (path,
841 0);
842 cc->mq_man = GCP_request_mq (first_hop,
843 &manage_first_hop_mq,
844 cc);
845 return cc;
846}
847
848
849/**
850 * Create a connection to @a destination via @a path and
851 * notify @a cb whenever we are ready for more data. This
852 * is an inbound tunnel, so we must use the existing @a cid
853 *
854 * @param destination where to go
855 * @param path which path to take (may not be the full path)
856 * @param options options for the connection
857 * @param ct which tunnel uses this connection
858 * @param ready_cb function to call when ready to transmit
859 * @param ready_cb_cls closure for @a cb
860 * @return handle to the connection, NULL if we already have
861 * a connection that takes precedence on @a path
862 */
863struct CadetConnection *
864GCC_create_inbound (struct CadetPeer *destination,
865 struct CadetPeerPath *path,
866 enum GNUNET_CADET_ChannelOption options,
867 struct CadetTConnection *ct,
868 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
869 GCC_ReadyCallback ready_cb,
870 void *ready_cb_cls)
871{
872 struct CadetConnection *cc;
873 unsigned int off;
874
875 off = GCPP_find_peer (path,
876 destination);
877 GNUNET_assert (UINT_MAX != off);
878 cc = GCPP_get_connection (path,
879 destination,
880 off);
881 if (NULL != cc)
882 {
883 int cmp;
884
885 cmp = memcmp (cid,
886 &cc->cid,
887 sizeof (*cid));
888 if (0 == cmp)
889 {
890 /* Two peers picked the SAME random connection identifier at the
891 same time for the same path? Must be malicious. Drop
892 connection (existing and inbound), even if it is the only
893 one. */
894 GNUNET_break_op (0);
895 GCT_connection_lost (cc->ct);
896 GCC_destroy_without_tunnel (cc);
897 return NULL;
898 }
899 if (0 < cmp)
900 {
901 /* drop existing */
902 LOG (GNUNET_ERROR_TYPE_DEBUG,
903 "Got two connections on %s, dropping my existing %s\n",
904 GCPP_2s (path),
905 GCC_2s (cc));
906 GCT_connection_lost (cc->ct);
907 GCC_destroy_without_tunnel (cc);
908 }
909 else
910 {
911 /* keep existing */
912 LOG (GNUNET_ERROR_TYPE_DEBUG,
913 "Got two connections on %s, keeping my existing %s\n",
914 GCPP_2s (path),
915 GCC_2s (cc));
916 return NULL;
917 }
918 }
919
920 return connection_create (destination,
921 path,
922 off,
923 options,
924 ct,
925 cid,
926 CADET_CONNECTION_CREATE_RECEIVED,
927 ready_cb,
928 ready_cb_cls);
929}
930
931
932/**
933 * Create a connection to @a destination via @a path and
934 * notify @a cb whenever we are ready for more data.
935 *
936 * @param destination where to go
937 * @param path which path to take (may not be the full path)
938 * @param off offset of @a destination on @a path
939 * @param options options for the connection
940 * @param ct tunnel that uses the connection
941 * @param ready_cb function to call when ready to transmit
942 * @param ready_cb_cls closure for @a cb
943 * @return handle to the connection
944 */
945struct CadetConnection *
946GCC_create (struct CadetPeer *destination,
947 struct CadetPeerPath *path,
948 unsigned int off,
949 enum GNUNET_CADET_ChannelOption options,
950 struct CadetTConnection *ct,
951 GCC_ReadyCallback ready_cb,
952 void *ready_cb_cls)
953{
954 struct GNUNET_CADET_ConnectionTunnelIdentifier cid;
955
956 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
957 &cid,
958 sizeof (cid));
959 return connection_create (destination,
960 path,
961 off,
962 options,
963 ct,
964 &cid,
965 CADET_CONNECTION_NEW,
966 ready_cb,
967 ready_cb_cls);
968}
969
970
971/**
972 * Transmit message @a msg via connection @a cc. Must only be called
973 * (once) after the connection has signalled that it is ready via the
974 * `ready_cb`. Clients can also use #GCC_is_ready() to check if the
975 * connection is right now ready for transmission.
976 *
977 * @param cc connection identification
978 * @param env envelope with message to transmit; must NOT
979 * yet have a #GNUNET_MQ_notify_sent() callback attached to it
980 */
981void
982GCC_transmit (struct CadetConnection *cc,
983 struct GNUNET_MQ_Envelope *env)
984{
985 LOG (GNUNET_ERROR_TYPE_DEBUG,
986 "Scheduling message for transmission on %s\n",
987 GCC_2s (cc));
988 GNUNET_assert (GNUNET_YES == cc->mqm_ready);
989 GNUNET_assert (CADET_CONNECTION_READY == cc->state);
990 cc->metrics.last_use = GNUNET_TIME_absolute_get ();
991 cc->mqm_ready = GNUNET_NO;
992 if (NULL != cc->task)
993 {
994 GNUNET_SCHEDULER_cancel (cc->task);
995 cc->task = NULL;
996 }
997 GCP_send (cc->mq_man,
998 env);
999}
1000
1001
1002/**
1003 * Obtain the path used by this connection.
1004 *
1005 * @param cc connection
1006 * @return path to @a cc
1007 */
1008struct CadetPeerPath *
1009GCC_get_path (struct CadetConnection *cc)
1010{
1011 return cc->path;
1012}
1013
1014
1015/**
1016 * Obtain unique ID for the connection.
1017 *
1018 * @param cc connection.
1019 * @return unique number of the connection
1020 */
1021const struct GNUNET_CADET_ConnectionTunnelIdentifier *
1022GCC_get_id (struct CadetConnection *cc)
1023{
1024 return &cc->cid;
1025}
1026
1027
1028/**
1029 * Get a (static) string for a connection.
1030 *
1031 * @param cc Connection.
1032 */
1033const char *
1034GCC_2s (const struct CadetConnection *cc)
1035{
1036 static char buf[128];
1037
1038 if (NULL == cc)
1039 return "Connection(NULL)";
1040
1041 if (NULL != cc->ct)
1042 {
1043 GNUNET_snprintf (buf,
1044 sizeof (buf),
1045 "Connection %s (%s)",
1046 GNUNET_sh2s (&cc->cid.connection_of_tunnel),
1047 GCT_2s (cc->ct->t));
1048 return buf;
1049 }
1050 GNUNET_snprintf (buf,
1051 sizeof (buf),
1052 "Connection %s",
1053 GNUNET_sh2s (&cc->cid.connection_of_tunnel));
1054 return buf;
1055}
1056
1057
1058#define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-con",__VA_ARGS__)
1059
1060
1061/**
1062 * Log connection info.
1063 *
1064 * @param cc connection
1065 * @param level Debug level to use.
1066 */
1067void
1068GCC_debug (struct CadetConnection *cc,
1069 enum GNUNET_ErrorType level)
1070{
1071 int do_log;
1072
1073 do_log = GNUNET_get_log_call_status (level & (~GNUNET_ERROR_TYPE_BULK),
1074 "cadet-con",
1075 __FILE__, __FUNCTION__, __LINE__);
1076 if (0 == do_log)
1077 return;
1078 if (NULL == cc)
1079 {
1080 LOG2 (level,
1081 "Connection (NULL)\n");
1082 return;
1083 }
1084 LOG2 (level,
1085 "%s to %s via path %s in state %d is %s\n",
1086 GCC_2s (cc),
1087 GCP_2s (cc->destination),
1088 GCPP_2s (cc->path),
1089 cc->state,
1090 (GNUNET_YES == cc->mqm_ready) ? "ready" : "busy");
1091}
1092
1093/* end of gnunet-service-cadet-new_connection.c */
diff --git a/src/cadet/gnunet-service-cadet-new_connection.h b/src/cadet/gnunet-service-cadet-new_connection.h
deleted file mode 100644
index e48b208fd..000000000
--- a/src/cadet/gnunet-service-cadet-new_connection.h
+++ /dev/null
@@ -1,339 +0,0 @@
1
2/*
3 This file is part of GNUnet.
4 Copyright (C) 2001-2017 GNUnet e.V.
5
6 GNUnet is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published
8 by the Free Software Foundation; either version 3, or (at your
9 option) any later version.
10
11 GNUnet is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNUnet; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA.
20*/
21
22/**
23 * @file cadet/gnunet-service-cadet-new_connection.h
24 * @brief A connection is a live end-to-end messaging mechanism
25 * where the peers are identified by a path and know how
26 * to forward along the route using a connection identifier
27 * for routing the data.
28 * @author Bartlomiej Polot
29 * @author Christian Grothoff
30 */
31#ifndef GNUNET_SERVICE_CADET_CONNECTION_H
32#define GNUNET_SERVICE_CADET_CONNECTION_H
33
34#include "gnunet_util_lib.h"
35#include "gnunet-service-cadet-new.h"
36#include "gnunet-service-cadet-new_peer.h"
37#include "cadet_protocol.h"
38
39
40/**
41 * Function called to notify tunnel about change in our readyness.
42 *
43 * @param cls closure
44 * @param is_ready #GNUNET_YES if the connection is now ready for transmission,
45 * #GNUNET_NO if the connection is no longer ready for transmission
46 */
47typedef void
48(*GCC_ReadyCallback)(void *cls,
49 int is_ready);
50
51
52/**
53 * Destroy a connection, called when the CORE layer is already done
54 * (i.e. has received a BROKEN message), but if we still have to
55 * communicate the destruction of the connection to the tunnel (if one
56 * exists).
57 *
58 * @param cc connection to destroy
59 */
60void
61GCC_destroy_without_core (struct CadetConnection *cc);
62
63
64/**
65 * Destroy a connection, called if the tunnel association with the
66 * connection was already broken, but we still need to notify the CORE
67 * layer about the breakage.
68 *
69 * @param cc connection to destroy
70 */
71void
72GCC_destroy_without_tunnel (struct CadetConnection *cc);
73
74
75/**
76 * Lookup a connection by its identifier.
77 *
78 * @param cid identifier to resolve
79 * @return NULL if connection was not found
80 */
81struct CadetConnection *
82GCC_lookup (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid);
83
84
85/**
86 * Create a connection to @a destination via @a path and
87 * notify @a cb whenever we are ready for more data.
88 *
89 * @param destination where to go
90 * @param path which path to take (may not be the full path)
91 * @param off offset of @a destination on @a path
92 * @param options options for the connection
93 * @param ct which tunnel uses this connection
94 * @param ready_cb function to call when ready to transmit
95 * @param ready_cb_cls closure for @a cb
96 * @return handle to the connection
97 */
98struct CadetConnection *
99GCC_create (struct CadetPeer *destination,
100 struct CadetPeerPath *path,
101 unsigned int off,
102 enum GNUNET_CADET_ChannelOption options,
103 struct CadetTConnection *ct,
104 GCC_ReadyCallback ready_cb,
105 void *ready_cb_cls);
106
107
108/**
109 * Create a connection to @a destination via @a path and
110 * notify @a cb whenever we are ready for more data. This
111 * is an inbound tunnel, so we must use the existing @a cid
112 *
113 * @param destination where to go
114 * @param path which path to take (may not be the full path)
115 * @param options options for the connection
116 * @param ct which tunnel uses this connection
117 * @param ready_cb function to call when ready to transmit
118 * @param ready_cb_cls closure for @a cb
119 * @return handle to the connection, NULL if we already have
120 * a connection that takes precedence on @a path
121 */
122struct CadetConnection *
123GCC_create_inbound (struct CadetPeer *destination,
124 struct CadetPeerPath *path,
125 enum GNUNET_CADET_ChannelOption options,
126 struct CadetTConnection *ct,
127 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
128 GCC_ReadyCallback ready_cb,
129 void *ready_cb_cls);
130
131
132/**
133 * Transmit message @a msg via connection @a cc. Must only be called
134 * (once) after the connection has signalled that it is ready via the
135 * `ready_cb`. Clients can also use #GCC_is_ready() to check if the
136 * connection is right now ready for transmission.
137 *
138 * @param cc connection identification
139 * @param env envelope with message to transmit;
140 * the #GNUNET_MQ_notify_send() must not have yet been used
141 * for the envelope. Also, the message better match the
142 * connection identifier of this connection...
143 */
144void
145GCC_transmit (struct CadetConnection *cc,
146 struct GNUNET_MQ_Envelope *env);
147
148
149/**
150 * A CREATE_ACK was received for this connection, process it.
151 *
152 * @param cc the connection that got the ACK.
153 */
154void
155GCC_handle_connection_create_ack (struct CadetConnection *cc);
156
157
158/**
159 * We got a #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE for a
160 * connection that we already have. Either our ACK got lost
161 * or something is fishy. Consider retransmitting the ACK.
162 *
163 * @param cc connection that got the duplicate CREATE
164 */
165void
166GCC_handle_duplicate_create (struct CadetConnection *cc);
167
168
169/**
170 * Handle KX message.
171 *
172 * @param cc connection that received encrypted message
173 * @param msg the key exchange message
174 */
175void
176GCC_handle_kx (struct CadetConnection *cc,
177 const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg);
178
179
180/**
181 * Handle KX_AUTH message.
182 *
183 * @param cc connection that received encrypted message
184 * @param msg the key exchange message
185 */
186void
187GCC_handle_kx_auth (struct CadetConnection *cc,
188 const struct GNUNET_CADET_TunnelKeyExchangeAuthMessage *msg);
189
190
191/**
192 * Performance metrics for a connection.
193 */
194struct CadetConnectionMetrics
195{
196
197 /**
198 * Our current best estimate of the latency, based on a weighted
199 * average of at least @a latency_datapoints values.
200 */
201 struct GNUNET_TIME_Relative aged_latency;
202
203 /**
204 * When was this connection first established? (by us sending or
205 * receiving the CREATE_ACK for the first time)
206 */
207 struct GNUNET_TIME_Absolute age;
208
209 /**
210 * When was this connection last used? (by us sending or
211 * receiving a PAYLOAD message on it)
212 */
213 struct GNUNET_TIME_Absolute last_use;
214
215 /**
216 * How many packets that ought to generate an ACK did we send via
217 * this connection?
218 */
219 unsigned long long num_acked_transmissions;
220
221 /**
222 * Number of packets that were sent via this connection did actually
223 * receive an ACK? (Note: ACKs may be transmitted and lost via
224 * other connections, so this value should only be interpreted
225 * relative to @e num_acked_transmissions and in relation to other
226 * connections.)
227 */
228 unsigned long long num_successes;
229
230};
231
232
233/**
234 * Obtain performance @a metrics from @a cc.
235 *
236 * @param cc connection to query
237 * @return the metrics
238 */
239const struct CadetConnectionMetrics *
240GCC_get_metrics (struct CadetConnection *cc);
241
242
243/**
244 * Handle encrypted message.
245 *
246 * @param cc connection that received encrypted message
247 * @param msg the encrypted message to decrypt
248 */
249void
250GCC_handle_encrypted (struct CadetConnection *cc,
251 const struct GNUNET_CADET_TunnelEncryptedMessage *msg);
252
253
254/**
255 * We sent a message for which we expect to receive an ACK via
256 * the connection identified by @a cti.
257 *
258 * @param cid connection identifier where we expect an ACK
259 */
260void
261GCC_ack_expected (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid);
262
263
264/**
265 * We observed an ACK for a message that was originally sent via
266 * the connection identified by @a cti.
267 *
268 * @param cid connection identifier where we got an ACK for a message
269 * that was originally sent via this connection (the ACK
270 * may have gotten back to us via a different connection).
271 */
272void
273GCC_ack_observed (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid);
274
275
276/**
277 * We observed some the given @a latency on the connection
278 * identified by @a cti. (The same connection was taken
279 * in both directions.)
280 *
281 * @param cti connection identifier where we measured latency
282 * @param latency the observed latency
283 */
284void
285GCC_latency_observed (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
286 struct GNUNET_TIME_Relative latency);
287
288
289/**
290 * Return the tunnel associated with this connection.
291 *
292 * @param cc connection to query
293 * @return corresponding entry in the tunnel's connection list
294 */
295struct CadetTConnection *
296GCC_get_ct (struct CadetConnection *cc);
297
298
299/**
300 * Obtain the path used by this connection.
301 *
302 * @param cc connection
303 * @return path to @a cc
304 */
305struct CadetPeerPath *
306GCC_get_path (struct CadetConnection *cc);
307
308
309/**
310 * Obtain unique ID for the connection.
311 *
312 * @param cc connection.
313 * @return unique number of the connection
314 */
315const struct GNUNET_CADET_ConnectionTunnelIdentifier *
316GCC_get_id (struct CadetConnection *cc);
317
318
319/**
320 * Get a (static) string for a connection.
321 *
322 * @param cc Connection.
323 */
324const char *
325GCC_2s (const struct CadetConnection *cc);
326
327
328/**
329 * Log connection info.
330 *
331 * @param cc connection
332 * @param level Debug level to use.
333 */
334void
335GCC_debug (struct CadetConnection *cc,
336 enum GNUNET_ErrorType level);
337
338
339#endif
diff --git a/src/cadet/gnunet-service-cadet-new_dht.c b/src/cadet/gnunet-service-cadet-new_dht.c
deleted file mode 100644
index 849562f23..000000000
--- a/src/cadet/gnunet-service-cadet-new_dht.c
+++ /dev/null
@@ -1,351 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2013, 2017 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20/**
21 * @file cadet/gnunet-service-cadet-new_dht.c
22 * @brief Information we track per peer.
23 * @author Bartlomiej Polot
24 * @author Christian Grothoff
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_dht_service.h"
30#include "gnunet_statistics_service.h"
31#include "gnunet-service-cadet-new.h"
32#include "gnunet-service-cadet-new_dht.h"
33#include "gnunet-service-cadet-new_hello.h"
34#include "gnunet-service-cadet-new_peer.h"
35#include "gnunet-service-cadet-new_paths.h"
36
37/**
38 * How long do we wait before first announcing our presence to the DHT.
39 * Used to wait for our HELLO to be available. Note that we also get
40 * notifications when our HELLO is ready, so this is just the maximum
41 * we wait for the first notification.
42 */
43#define STARTUP_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 500)
44
45/**
46 * How long do we wait after we get an updated HELLO before publishing?
47 * Allows for the HELLO to be updated again quickly, for example in
48 * case multiple addresses changed and we got a partial update.
49 */
50#define CHANGE_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100)
51
52
53#define LOG(level, ...) GNUNET_log_from (level,"cadet-dht",__VA_ARGS__)
54
55
56/**
57 * Handle for DHT searches.
58 */
59struct GCD_search_handle
60{
61 /**
62 * DHT_GET handle.
63 */
64 struct GNUNET_DHT_GetHandle *dhtget;
65
66};
67
68
69/**
70 * Handle to use DHT.
71 */
72static struct GNUNET_DHT_Handle *dht_handle;
73
74/**
75 * How often to PUT own ID in the DHT.
76 */
77static struct GNUNET_TIME_Relative id_announce_time;
78
79/**
80 * DHT replication level, see DHT API: #GNUNET_DHT_get_start(), #GNUNET_DHT_put().
81 */
82static unsigned long long dht_replication_level;
83
84/**
85 * Task to periodically announce itself in the network.
86 */
87static struct GNUNET_SCHEDULER_Task *announce_id_task;
88
89/**
90 * Delay for the next ID announce.
91 */
92static struct GNUNET_TIME_Relative announce_delay;
93
94
95/**
96 * Function to process paths received for a new peer addition. The recorded
97 * paths form the initial tunnel, which can be optimized later.
98 * Called on each result obtained for the DHT search.
99 *
100 * @param cls closure
101 * @param exp when will this value expire
102 * @param key key of the result
103 * @param get_path path of the get request
104 * @param get_path_length lenght of @a get_path
105 * @param put_path path of the put request
106 * @param put_path_length length of the @a put_path
107 * @param type type of the result
108 * @param size number of bytes in data
109 * @param data pointer to the result data
110 */
111static void
112dht_get_id_handler (void *cls, struct GNUNET_TIME_Absolute exp,
113 const struct GNUNET_HashCode *key,
114 const struct GNUNET_PeerIdentity *get_path,
115 unsigned int get_path_length,
116 const struct GNUNET_PeerIdentity *put_path,
117 unsigned int put_path_length,
118 enum GNUNET_BLOCK_Type type,
119 size_t size,
120 const void *data)
121{
122 const struct GNUNET_HELLO_Message *hello = data;
123 struct CadetPeer *peer;
124
125 GCPP_try_path_from_dht (get_path,
126 get_path_length,
127 put_path,
128 put_path_length);
129 if ( (size >= sizeof (struct GNUNET_HELLO_Message)) &&
130 (ntohs (hello->header.size) == size) &&
131 (size == GNUNET_HELLO_size (hello)) )
132 {
133 peer = GCP_get (&put_path[0],
134 GNUNET_YES);
135 LOG (GNUNET_ERROR_TYPE_DEBUG,
136 "Got HELLO for %s\n",
137 GCP_2s (peer));
138 GCP_set_hello (peer,
139 hello);
140 }
141}
142
143
144/**
145 * Periodically announce self id in the DHT
146 *
147 * @param cls closure
148 */
149static void
150announce_id (void *cls)
151{
152 struct GNUNET_HashCode phash;
153 const struct GNUNET_HELLO_Message *hello;
154 size_t size;
155 struct GNUNET_TIME_Absolute expiration;
156 struct GNUNET_TIME_Relative next_put;
157
158 hello = GCH_get_mine ();
159 size = (NULL != hello) ? GNUNET_HELLO_size (hello) : 0;
160 if (0 == size)
161 {
162 expiration = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (),
163 announce_delay);
164 announce_delay = GNUNET_TIME_STD_BACKOFF (announce_delay);
165 }
166 else
167 {
168 expiration = GNUNET_HELLO_get_last_expiration (hello);
169 announce_delay = GNUNET_TIME_UNIT_SECONDS;
170 }
171
172 /* Call again in id_announce_time, unless HELLO expires first,
173 * but wait at least 1s. */
174 next_put
175 = GNUNET_TIME_absolute_get_remaining (expiration);
176 next_put
177 = GNUNET_TIME_relative_min (next_put,
178 id_announce_time);
179 next_put
180 = GNUNET_TIME_relative_max (next_put,
181 GNUNET_TIME_UNIT_SECONDS);
182 announce_id_task
183 = GNUNET_SCHEDULER_add_delayed (next_put,
184 &announce_id,
185 cls);
186 GNUNET_STATISTICS_update (stats,
187 "# DHT announce",
188 1,
189 GNUNET_NO);
190 memset (&phash,
191 0,
192 sizeof (phash));
193 GNUNET_memcpy (&phash,
194 &my_full_id,
195 sizeof (my_full_id));
196 LOG (GNUNET_ERROR_TYPE_DEBUG,
197 "Announcing my HELLO (%u bytes) in the DHT\n",
198 size);
199 GNUNET_DHT_put (dht_handle, /* DHT handle */
200 &phash, /* Key to use */
201 dht_replication_level, /* Replication level */
202 GNUNET_DHT_RO_RECORD_ROUTE
203 | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, /* DHT options */
204 GNUNET_BLOCK_TYPE_DHT_HELLO, /* Block type */
205 size, /* Size of the data */
206 (const char *) hello, /* Data itself */
207 expiration, /* Data expiration */
208 NULL, /* Continuation */
209 NULL); /* Continuation closure */
210}
211
212
213/**
214 * Function called by the HELLO subsystem whenever OUR hello
215 * changes. Re-triggers the DHT PUT immediately.
216 */
217void
218GCD_hello_update ()
219{
220 if (NULL == announce_id_task)
221 return; /* too early */
222 GNUNET_SCHEDULER_cancel (announce_id_task);
223 announce_id_task
224 = GNUNET_SCHEDULER_add_delayed (CHANGE_DELAY,
225 &announce_id,
226 NULL);
227}
228
229
230/**
231 * Initialize the DHT subsystem.
232 *
233 * @param c Configuration.
234 */
235void
236GCD_init (const struct GNUNET_CONFIGURATION_Handle *c)
237{
238 if (GNUNET_OK !=
239 GNUNET_CONFIGURATION_get_value_number (c,
240 "CADET",
241 "DHT_REPLICATION_LEVEL",
242 &dht_replication_level))
243 {
244 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
245 "CADET",
246 "DHT_REPLICATION_LEVEL",
247 "USING DEFAULT");
248 dht_replication_level = 3;
249 }
250
251 if (GNUNET_OK !=
252 GNUNET_CONFIGURATION_get_value_time (c,
253 "CADET",
254 "ID_ANNOUNCE_TIME",
255 &id_announce_time))
256 {
257 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
258 "CADET",
259 "ID_ANNOUNCE_TIME",
260 "MISSING");
261 GNUNET_SCHEDULER_shutdown ();
262 return;
263 }
264
265 dht_handle = GNUNET_DHT_connect (c,
266 64);
267 GNUNET_break (NULL != dht_handle);
268 announce_delay = GNUNET_TIME_UNIT_SECONDS;
269 announce_id_task = GNUNET_SCHEDULER_add_delayed (STARTUP_DELAY,
270 &announce_id,
271 NULL);
272}
273
274
275/**
276 * Shut down the DHT subsystem.
277 */
278void
279GCD_shutdown (void)
280{
281 if (NULL != dht_handle)
282 {
283 GNUNET_DHT_disconnect (dht_handle);
284 dht_handle = NULL;
285 }
286 if (NULL != announce_id_task)
287 {
288 GNUNET_SCHEDULER_cancel (announce_id_task);
289 announce_id_task = NULL;
290 }
291}
292
293
294/**
295 * Search DHT for paths to @a peeR_id
296 *
297 * @param peer_id peer to search for
298 * @return handle to abort search
299 */
300struct GCD_search_handle *
301GCD_search (const struct GNUNET_PeerIdentity *peer_id)
302{
303 struct GNUNET_HashCode phash;
304 struct GCD_search_handle *h;
305
306 GNUNET_STATISTICS_update (stats,
307 "# DHT search",
308 1,
309 GNUNET_NO);
310 memset (&phash,
311 0,
312 sizeof (phash));
313 GNUNET_memcpy (&phash,
314 peer_id,
315 sizeof (*peer_id));
316
317 h = GNUNET_new (struct GCD_search_handle);
318 h->dhtget = GNUNET_DHT_get_start (dht_handle, /* handle */
319 GNUNET_BLOCK_TYPE_DHT_HELLO, /* type */
320 &phash, /* key to search */
321 dht_replication_level, /* replication level */
322 GNUNET_DHT_RO_RECORD_ROUTE |
323 GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
324 NULL, /* xquery */
325 0, /* xquery bits */
326 &dht_get_id_handler,
327 h);
328 LOG (GNUNET_ERROR_TYPE_DEBUG,
329 "Starting DHT GET for peer %s (%p)\n",
330 GNUNET_i2s (peer_id),
331 h);
332 return h;
333}
334
335
336/**
337 * Stop DHT search started with #GCD_search().
338 *
339 * @param h handle to search to stop
340 */
341void
342GCD_search_stop (struct GCD_search_handle *h)
343{
344 LOG (GNUNET_ERROR_TYPE_DEBUG,
345 "Stopping DHT GET %p\n",
346 h);
347 GNUNET_DHT_get_stop (h->dhtget);
348 GNUNET_free (h);
349}
350
351/* end of gnunet-service-cadet_dht.c */
diff --git a/src/cadet/gnunet-service-cadet-new_dht.h b/src/cadet/gnunet-service-cadet-new_dht.h
deleted file mode 100644
index 5d7ab29a0..000000000
--- a/src/cadet/gnunet-service-cadet-new_dht.h
+++ /dev/null
@@ -1,100 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2013, 2017 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21/**
22 * @file cadet/gnunet-service-cadet_dht.h
23 * @brief cadet service; dealing with DHT requests and results
24 * @author Bartlomiej Polot
25 * @author Christian Grothoff
26 *
27 * All functions in this file should use the prefix GCD (Gnunet Cadet Dht)
28 */
29#ifndef GNUNET_SERVICE_CADET_DHT_H
30#define GNUNET_SERVICE_CADET_DHT_H
31
32#ifdef __cplusplus
33extern "C"
34{
35#if 0 /* keep Emacsens' auto-indent happy */
36}
37#endif
38#endif
39
40#include "platform.h"
41#include "gnunet_util_lib.h"
42
43/**
44 * Handle for DHT search operation.
45 */
46struct GCD_search_handle;
47
48
49/**
50 * Initialize the DHT subsystem.
51 *
52 * @param c Configuration.
53 */
54void
55GCD_init (const struct GNUNET_CONFIGURATION_Handle *c);
56
57
58/**
59 * Shut down the DHT subsystem.
60 */
61void
62GCD_shutdown (void);
63
64
65/**
66 * Function called by the HELLO subsystem whenever OUR hello
67 * changes. Re-triggers the DHT PUT immediately.
68 */
69void
70GCD_hello_update (void);
71
72/**
73 * Search DHT for paths to @a peeR_id
74 *
75 * @param peer_id peer to search for
76 * @return handle to abort search
77 */
78struct GCD_search_handle *
79GCD_search (const struct GNUNET_PeerIdentity *peer_id);
80
81
82/**
83 * Stop DHT search started with #GCD_search().
84 *
85 * @param h handle to search to stop
86 */
87void
88GCD_search_stop (struct GCD_search_handle *h);
89
90
91#if 0 /* keep Emacsens' auto-indent happy */
92{
93#endif
94#ifdef __cplusplus
95}
96#endif
97
98/* ifndef GNUNET_CADET_SERVICE_DHT_H */
99#endif
100/* end of gnunet-service-cadet_dht.h */
diff --git a/src/cadet/gnunet-service-cadet-new_hello.c b/src/cadet/gnunet-service-cadet-new_hello.c
deleted file mode 100644
index a24325ada..000000000
--- a/src/cadet/gnunet-service-cadet-new_hello.c
+++ /dev/null
@@ -1,152 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2014, 2017 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20/**
21 * @file cadet/gnunet-service-cadet-new_hello.c
22 * @brief spread knowledge about how to contact other peers from PEERINFO
23 * @author Bartlomiej Polot
24 * @author Christian Grothoff
25 *
26 * TODO:
27 * - is most of this necessary/helpful?
28 * - should we not simply restrict this to OUR hello?
29 */
30#include "platform.h"
31#include "gnunet_util_lib.h"
32
33#include "gnunet_statistics_service.h"
34#include "gnunet_peerinfo_service.h"
35#include "cadet_protocol.h"
36#include "gnunet-service-cadet-new.h"
37#include "gnunet-service-cadet-new_dht.h"
38#include "gnunet-service-cadet-new_hello.h"
39#include "gnunet-service-cadet-new_peer.h"
40
41#define LOG(level, ...) GNUNET_log_from(level,"cadet-hll",__VA_ARGS__)
42
43/**
44 * Hello message of local peer.
45 */
46static struct GNUNET_HELLO_Message *mine;
47
48/**
49 * Handle to peerinfo service.
50 */
51static struct GNUNET_PEERINFO_Handle *peerinfo;
52
53/**
54 * Iterator context.
55 */
56static struct GNUNET_PEERINFO_NotifyContext *nc;
57
58
59/**
60 * Process each hello message received from peerinfo.
61 *
62 * @param cls Closure (unused).
63 * @param peer Identity of the peer.
64 * @param hello Hello of the peer.
65 * @param err_msg Error message.
66 */
67static void
68got_hello (void *cls,
69 const struct GNUNET_PeerIdentity *id,
70 const struct GNUNET_HELLO_Message *hello,
71 const char *err_msg)
72{
73 struct CadetPeer *peer;
74
75 if ( (NULL == id) ||
76 (NULL == hello) )
77 return;
78 if (0 == memcmp (id,
79 &my_full_id,
80 sizeof (struct GNUNET_PeerIdentity)))
81 {
82 GNUNET_free_non_null (mine);
83 mine = (struct GNUNET_HELLO_Message *) GNUNET_copy_message (&hello->header);
84 GCD_hello_update ();
85 return;
86 }
87
88 LOG (GNUNET_ERROR_TYPE_DEBUG,
89 "Hello for %s (%d bytes), expires on %s\n",
90 GNUNET_i2s (id),
91 GNUNET_HELLO_size (hello),
92 GNUNET_STRINGS_absolute_time_to_string (GNUNET_HELLO_get_last_expiration (hello)));
93 peer = GCP_get (id,
94 GNUNET_YES);
95 GCP_set_hello (peer,
96 hello);
97}
98
99
100/**
101 * Initialize the hello subsystem.
102 *
103 * @param c Configuration.
104 */
105void
106GCH_init (const struct GNUNET_CONFIGURATION_Handle *c)
107{
108 GNUNET_assert (NULL == nc);
109 peerinfo = GNUNET_PEERINFO_connect (c);
110 nc = GNUNET_PEERINFO_notify (c,
111 GNUNET_NO,
112 &got_hello,
113 NULL);
114}
115
116
117/**
118 * Shut down the hello subsystem.
119 */
120void
121GCH_shutdown ()
122{
123 if (NULL != nc)
124 {
125 GNUNET_PEERINFO_notify_cancel (nc);
126 nc = NULL;
127 }
128 if (NULL != peerinfo)
129 {
130 GNUNET_PEERINFO_disconnect (peerinfo);
131 peerinfo = NULL;
132 }
133 if (NULL != mine)
134 {
135 GNUNET_free (mine);
136 mine = NULL;
137 }
138}
139
140
141/**
142 * Get own hello message.
143 *
144 * @return Own hello message.
145 */
146const struct GNUNET_HELLO_Message *
147GCH_get_mine (void)
148{
149 return mine;
150}
151
152/* end of gnunet-service-cadet-new_hello.c */
diff --git a/src/cadet/gnunet-service-cadet-new_hello.h b/src/cadet/gnunet-service-cadet-new_hello.h
deleted file mode 100644
index 4291ae985..000000000
--- a/src/cadet/gnunet-service-cadet-new_hello.h
+++ /dev/null
@@ -1,80 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2014, 2017 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21/**
22 * @file cadet/gnunet-service-cadet_hello.h
23 * @brief cadet service; dealing with hello messages
24 * @author Bartlomiej Polot
25 * @author Christian Grothoff
26 *
27 * All functions in this file should use the prefix GCH (Gnunet Cadet Hello)
28 */
29
30#ifndef GNUNET_SERVICE_CADET_HELLO_H
31#define GNUNET_SERVICE_CADET_HELLO_H
32
33#ifdef __cplusplus
34extern "C"
35{
36#if 0 /* keep Emacsens' auto-indent happy */
37}
38#endif
39#endif
40
41#include "platform.h"
42#include "gnunet_util_lib.h"
43#include "gnunet_hello_lib.h"
44
45
46/**
47 * Initialize the hello subsystem.
48 *
49 * @param c Configuration.
50 */
51void
52GCH_init (const struct GNUNET_CONFIGURATION_Handle *c);
53
54
55/**
56 * Shut down the hello subsystem.
57 */
58void
59GCH_shutdown (void);
60
61
62/**
63 * Get own hello message.
64 *
65 * @return Own hello message.
66 */
67const struct GNUNET_HELLO_Message *
68GCH_get_mine (void);
69
70
71#if 0 /* keep Emacsens' auto-indent happy */
72{
73#endif
74#ifdef __cplusplus
75}
76#endif
77
78/* ifndef GNUNET_CADET_SERVICE_HELLO_H */
79#endif
80/* end of gnunet-cadet-service_hello.h */
diff --git a/src/cadet/gnunet-service-cadet-new_peer.c b/src/cadet/gnunet-service-cadet-new_peer.c
deleted file mode 100644
index 350c8efae..000000000
--- a/src/cadet/gnunet-service-cadet-new_peer.c
+++ /dev/null
@@ -1,1477 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2001-2017 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21/**
22 * @file cadet/gnunet-service-cadet-new_peer.c
23 * @brief Information we track per peer.
24 * @author Bartlomiej Polot
25 * @author Christian Grothoff
26 *
27 * TODO:
28 * - optimize stopping/restarting DHT search to situations
29 * where we actually need it (i.e. not if we have a direct connection,
30 * or if we already have plenty of good short ones, or maybe even
31 * to take a break if we have some connections and have searched a lot (?))
32 */
33#include "platform.h"
34#include "gnunet_util_lib.h"
35#include "gnunet_hello_lib.h"
36#include "gnunet_signatures.h"
37#include "gnunet_transport_service.h"
38#include "gnunet_ats_service.h"
39#include "gnunet_core_service.h"
40#include "gnunet_statistics_service.h"
41#include "cadet_protocol.h"
42#include "gnunet-service-cadet-new.h"
43#include "gnunet-service-cadet-new_connection.h"
44#include "gnunet-service-cadet-new_dht.h"
45#include "gnunet-service-cadet-new_peer.h"
46#include "gnunet-service-cadet-new_paths.h"
47#include "gnunet-service-cadet-new_tunnels.h"
48
49
50#define LOG(level, ...) GNUNET_log_from(level,"cadet-per",__VA_ARGS__)
51
52
53/**
54 * How long do we wait until tearing down an idle peer?
55 */
56#define IDLE_PEER_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5)
57
58/**
59 * How long do we keep paths around if we no longer care about the peer?
60 */
61#define IDLE_PATH_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 2)
62
63
64
65
66/**
67 * Data structure used to track whom we have to notify about changes
68 * to our message queue.
69 */
70struct GCP_MessageQueueManager
71{
72
73 /**
74 * Kept in a DLL.
75 */
76 struct GCP_MessageQueueManager *next;
77
78 /**
79 * Kept in a DLL.
80 */
81 struct GCP_MessageQueueManager *prev;
82
83 /**
84 * Function to call with updated message queue object.
85 */
86 GCP_MessageQueueNotificationCallback cb;
87
88 /**
89 * Closure for @e cb.
90 */
91 void *cb_cls;
92
93 /**
94 * The peer this is for.
95 */
96 struct CadetPeer *cp;
97
98 /**
99 * Envelope this manager would like to transmit once it is its turn.
100 */
101 struct GNUNET_MQ_Envelope *env;
102
103};
104
105
106/**
107 * Struct containing all information regarding a given peer
108 */
109struct CadetPeer
110{
111 /**
112 * ID of the peer
113 */
114 struct GNUNET_PeerIdentity pid;
115
116 /**
117 * Last time we heard from this peer (currently not used!)
118 */
119 struct GNUNET_TIME_Absolute last_contactXXX;
120
121 /**
122 * Array of DLLs of paths traversing the peer, organized by the
123 * offset of the peer on the larger path.
124 */
125 struct CadetPeerPathEntry **path_heads;
126
127 /**
128 * Array of DLL of paths traversing the peer, organized by the
129 * offset of the peer on the larger path.
130 */
131 struct CadetPeerPathEntry **path_tails;
132
133 /**
134 * Notifications to call when @e core_mq changes.
135 */
136 struct GCP_MessageQueueManager *mqm_head;
137
138 /**
139 * Notifications to call when @e core_mq changes.
140 */
141 struct GCP_MessageQueueManager *mqm_tail;
142
143 /**
144 * Pointer to first "ready" entry in @e mqm_head.
145 */
146 struct GCP_MessageQueueManager *mqm_ready_ptr;
147
148 /**
149 * MIN-heap of paths owned by this peer (they also end at this
150 * peer). Ordered by desirability.
151 */
152 struct GNUNET_CONTAINER_Heap *path_heap;
153
154 /**
155 * Handle to stop the DHT search for paths to this peer
156 */
157 struct GCD_search_handle *search_h;
158
159 /**
160 * Task to clean up @e path_heap asynchronously.
161 */
162 struct GNUNET_SCHEDULER_Task *heap_cleanup_task;
163
164 /**
165 * Task to destroy this entry.
166 */
167 struct GNUNET_SCHEDULER_Task *destroy_task;
168
169 /**
170 * Tunnel to this peer, if any.
171 */
172 struct CadetTunnel *t;
173
174 /**
175 * Connections that go through this peer; indexed by tid.
176 */
177 struct GNUNET_CONTAINER_MultiShortmap *connections;
178
179 /**
180 * Handle for core transmissions.
181 */
182 struct GNUNET_MQ_Handle *core_mq;
183
184 /**
185 * Hello message of the peer.
186 */
187 struct GNUNET_HELLO_Message *hello;
188
189 /**
190 * Handle to us offering the HELLO to the transport.
191 */
192 struct GNUNET_TRANSPORT_OfferHelloHandle *hello_offer;
193
194 /**
195 * Handle to our ATS request asking ATS to suggest an address
196 * to TRANSPORT for this peer (to establish a direct link).
197 */
198 struct GNUNET_ATS_ConnectivitySuggestHandle *connectivity_suggestion;
199
200 /**
201 * How many messages are in the queue to this peer.
202 */
203 unsigned int queue_n;
204
205 /**
206 * How many paths do we have to this peer (in all @e path_heads DLLs combined).
207 */
208 unsigned int num_paths;
209
210 /**
211 * Sum over all of the offsets of all of the paths in the @a path_heads DLLs.
212 * Used to speed-up @GCP_get_desirability_of_path() calculation.
213 */
214 unsigned int off_sum;
215
216 /**
217 * Number of message queue managers of this peer that have a message in waiting.
218 *
219 * Used to quickly see if we need to bother scanning the @e msm_head DLL.
220 * TODO: could be replaced by another DLL that would then allow us to avoid
221 * the O(n)-scan of the DLL for ready entries!
222 */
223 unsigned int mqm_ready_counter;
224
225 /**
226 * Current length of the @e path_heads and @path_tails arrays.
227 * The arrays should be grown as needed.
228 */
229 unsigned int path_dll_length;
230
231};
232
233
234/**
235 * Get the static string for a peer ID.
236 *
237 * @param cp Peer.
238 * @return Static string for it's ID.
239 */
240const char *
241GCP_2s (const struct CadetPeer *cp)
242{
243 static char buf[32];
244
245 GNUNET_snprintf (buf,
246 sizeof (buf),
247 "P(%s)",
248 GNUNET_i2s (&cp->pid));
249 return buf;
250}
251
252
253/**
254 * Calculate how desirable a path is for @a cp if @a cp
255 * is at offset @a off.
256 *
257 * The 'desirability_table.c' program can be used to compute a list of
258 * sample outputs for different scenarios. Basically, we score paths
259 * lower if there are many alternatives, and higher if they are
260 * shorter than average, and very high if they are much shorter than
261 * average and without many alternatives.
262 *
263 * @param cp a peer reachable via a path
264 * @param off offset of @a cp in the path
265 * @return score how useful a path is to reach @a cp,
266 * positive scores mean path is more desirable
267 */
268double
269GCP_get_desirability_of_path (struct CadetPeer *cp,
270 unsigned int off)
271{
272 unsigned int num_alts = cp->num_paths;
273 unsigned int off_sum;
274 double avg_sum;
275 double path_delta;
276 double weight_alts;
277
278 GNUNET_assert (num_alts >= 1); /* 'path' should be in there! */
279 GNUNET_assert (0 != cp->path_dll_length);
280
281 /* We maintain 'off_sum' in 'peer' and thereby
282 avoid the SLOW recalculation each time. Kept here
283 just to document what is going on. */
284#if SLOW
285 off_sum = 0;
286 for (unsigned int j=0;j<cp->path_dll_length;j++)
287 for (struct CadetPeerPathEntry *pe = cp->path_heads[j];
288 NULL != pe;
289 pe = pe->next)
290 off_sum += j;
291 GNUNET_assert (off_sum == cp->off_sum);
292#else
293 off_sum = cp->off_sum;
294#endif
295 avg_sum = off_sum * 1.0 / cp->path_dll_length;
296 path_delta = off - avg_sum;
297 /* path_delta positiv: path off of peer above average (bad path for peer),
298 path_delta negativ: path off of peer below average (good path for peer) */
299 if (path_delta <= - 1.0)
300 weight_alts = - num_alts / path_delta; /* discount alternative paths */
301 else if (path_delta >= 1.0)
302 weight_alts = num_alts * path_delta; /* overcount alternative paths */
303 else
304 weight_alts = num_alts; /* count alternative paths normally */
305
306
307 /* off+1: long paths are generally harder to find and thus count
308 a bit more as they get longer. However, above-average paths
309 still need to count less, hence the squaring of that factor. */
310 return (off + 1.0) / (weight_alts * weight_alts);
311}
312
313
314/**
315 * This peer is no longer be needed, clean it up now.
316 *
317 * @param cls peer to clean up
318 */
319static void
320destroy_peer (void *cls)
321{
322 struct CadetPeer *cp = cls;
323
324 LOG (GNUNET_ERROR_TYPE_DEBUG,
325 "Destroying state about peer %s\n",
326 GCP_2s (cp));
327 cp->destroy_task = NULL;
328 GNUNET_assert (NULL == cp->t);
329 GNUNET_assert (NULL == cp->core_mq);
330 GNUNET_assert (0 == cp->num_paths);
331 for (unsigned int i=0;i<cp->path_dll_length;i++)
332 GNUNET_assert (NULL == cp->path_heads[i]);
333 GNUNET_assert (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections));
334 GNUNET_assert (GNUNET_YES ==
335 GNUNET_CONTAINER_multipeermap_remove (peers,
336 &cp->pid,
337 cp));
338 GNUNET_free_non_null (cp->path_heads);
339 GNUNET_free_non_null (cp->path_tails);
340 cp->path_dll_length = 0;
341 if (NULL != cp->search_h)
342 {
343 GCD_search_stop (cp->search_h);
344 cp->search_h = NULL;
345 }
346 /* FIXME: clean up search_delayedXXX! */
347
348 if (NULL != cp->hello_offer)
349 {
350 GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer);
351 cp->hello_offer = NULL;
352 }
353 if (NULL != cp->connectivity_suggestion)
354 {
355 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
356 cp->connectivity_suggestion = NULL;
357 }
358 GNUNET_CONTAINER_multishortmap_destroy (cp->connections);
359 if (NULL != cp->path_heap)
360 {
361 GNUNET_CONTAINER_heap_destroy (cp->path_heap);
362 cp->path_heap = NULL;
363 }
364 if (NULL != cp->heap_cleanup_task)
365 {
366 GNUNET_SCHEDULER_cancel (cp->heap_cleanup_task);
367 cp->heap_cleanup_task = NULL;
368 }
369 GNUNET_free_non_null (cp->hello);
370 /* Peer should not be freed if paths exist; if there are no paths,
371 there ought to be no connections, and without connections, no
372 notifications. Thus we can assert that mqm_head is empty at this
373 point. */
374 GNUNET_assert (NULL == cp->mqm_head);
375 GNUNET_assert (NULL == cp->mqm_ready_ptr);
376 GNUNET_free (cp);
377}
378
379
380/**
381 * This peer is now on more "active" duty, activate processes related to it.
382 *
383 * @param cp the more-active peer
384 */
385static void
386consider_peer_activate (struct CadetPeer *cp)
387{
388 uint32_t strength;
389
390 LOG (GNUNET_ERROR_TYPE_DEBUG,
391 "Updating peer %s activation state (%u connections)%s%s\n",
392 GCP_2s (cp),
393 GNUNET_CONTAINER_multishortmap_size (cp->connections),
394 (NULL == cp->t) ? "" : " with tunnel",
395 (NULL == cp->core_mq) ? "" : " with CORE link");
396 if (NULL != cp->destroy_task)
397 {
398 /* It's active, do not destory! */
399 GNUNET_SCHEDULER_cancel (cp->destroy_task);
400 cp->destroy_task = NULL;
401 }
402 if ( (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections)) &&
403 (NULL == cp->t) )
404 {
405 /* We're just on a path or directly connected; don't bother too much */
406 if (NULL != cp->connectivity_suggestion)
407 {
408 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
409 cp->connectivity_suggestion = NULL;
410 }
411 if (NULL != cp->search_h)
412 {
413 GCD_search_stop (cp->search_h);
414 cp->search_h = NULL;
415 }
416 return;
417 }
418 if (NULL == cp->core_mq)
419 {
420 /* Lacks direct connection, try to create one by querying the DHT */
421 if ( (NULL == cp->search_h) &&
422 (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) )
423 cp->search_h
424 = GCD_search (&cp->pid);
425 }
426 else
427 {
428 /* Have direct connection, stop DHT search if active */
429 if (NULL != cp->search_h)
430 {
431 GCD_search_stop (cp->search_h);
432 cp->search_h = NULL;
433 }
434 }
435
436 /* If we have a tunnel, our urge for connections is much bigger */
437 strength = (NULL != cp->t) ? 32 : 1;
438 if (NULL != cp->connectivity_suggestion)
439 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
440 cp->connectivity_suggestion
441 = GNUNET_ATS_connectivity_suggest (ats_ch,
442 &cp->pid,
443 strength);
444}
445
446
447/**
448 * This peer may no longer be needed, consider cleaning it up.
449 *
450 * @param cp peer to clean up
451 */
452static void
453consider_peer_destroy (struct CadetPeer *cp);
454
455
456/**
457 * We really no longere care about a peer, stop hogging memory with paths to it.
458 * Afterwards, see if there is more to be cleaned up about this peer.
459 *
460 * @param cls a `struct CadetPeer`.
461 */
462static void
463drop_paths (void *cls)
464{
465 struct CadetPeer *cp = cls;
466 struct CadetPeerPath *path;
467
468 cp->destroy_task = NULL;
469 while (NULL != (path = GNUNET_CONTAINER_heap_remove_root (cp->path_heap)))
470 GCPP_release (path);
471 consider_peer_destroy (cp);
472}
473
474
475/**
476 * This peer may no longer be needed, consider cleaning it up.
477 *
478 * @param cp peer to clean up
479 */
480static void
481consider_peer_destroy (struct CadetPeer *cp)
482{
483 struct GNUNET_TIME_Relative exp;
484
485 if (NULL != cp->destroy_task)
486 {
487 GNUNET_SCHEDULER_cancel (cp->destroy_task);
488 cp->destroy_task = NULL;
489 }
490 if (NULL != cp->t)
491 return; /* still relevant! */
492 if (NULL != cp->core_mq)
493 return; /* still relevant! */
494 if (0 != GNUNET_CONTAINER_multishortmap_size (cp->connections))
495 return; /* still relevant! */
496 if ( (NULL != cp->path_heap) &&
497 (0 < GNUNET_CONTAINER_heap_get_size (cp->path_heap)) )
498 {
499 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PATH_TIMEOUT,
500 &drop_paths,
501 cp);
502 return;
503 }
504 if (0 != cp->num_paths)
505 return; /* still relevant! */
506 if (NULL != cp->hello)
507 {
508 /* relevant only until HELLO expires */
509 exp = GNUNET_TIME_absolute_get_remaining (GNUNET_HELLO_get_last_expiration (cp->hello));
510 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (exp,
511 &destroy_peer,
512 cp);
513 return;
514 }
515 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PEER_TIMEOUT,
516 &destroy_peer,
517 cp);
518}
519
520
521/**
522 * Set the message queue to @a mq for peer @a cp and notify watchers.
523 *
524 * @param cp peer to modify
525 * @param mq message queue to set (can be NULL)
526 */
527void
528GCP_set_mq (struct CadetPeer *cp,
529 struct GNUNET_MQ_Handle *mq)
530{
531 LOG (GNUNET_ERROR_TYPE_DEBUG,
532 "Message queue for peer %s is now %p\n",
533 GCP_2s (cp),
534 mq);
535 cp->core_mq = mq;
536 for (struct GCP_MessageQueueManager *mqm = cp->mqm_head, *next;
537 NULL != mqm;
538 mqm = next)
539 {
540 /* Save next pointer in case mqm gets freed by the callback */
541 next = mqm->next;
542 if (NULL == mq)
543 {
544 if (NULL != mqm->env)
545 {
546 GNUNET_MQ_discard (mqm->env);
547 mqm->env = NULL;
548 mqm->cb (mqm->cb_cls,
549 GNUNET_SYSERR);
550 }
551 else
552 {
553 mqm->cb (mqm->cb_cls,
554 GNUNET_NO);
555 }
556 }
557 else
558 {
559 GNUNET_assert (NULL == mqm->env);
560 mqm->cb (mqm->cb_cls,
561 GNUNET_YES);
562 }
563 }
564 if ( (NULL != mq) ||
565 (NULL != cp->t) )
566 consider_peer_activate (cp);
567 else
568 consider_peer_destroy (cp);
569
570 if ( (NULL != mq) &&
571 (NULL != cp->t) )
572 {
573 /* have a new, direct path to the target, notify tunnel */
574 struct CadetPeerPath *path;
575
576 path = GCPP_get_path_from_route (1,
577 &cp->pid);
578 GCT_consider_path (cp->t,
579 path,
580 0);
581 }
582}
583
584
585/**
586 * Debug function should NEVER return true in production code, useful to
587 * simulate losses for testcases.
588 *
589 * @return #GNUNET_YES or #GNUNET_NO with the decision to drop.
590 */
591static int
592should_I_drop (void)
593{
594 if (0 == drop_percent)
595 return GNUNET_NO;
596 if (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
597 101) < drop_percent)
598 return GNUNET_YES;
599 return GNUNET_NO;
600}
601
602
603/**
604 * Function called when CORE took one of the messages from
605 * a message queue manager and transmitted it.
606 *
607 * @param cls the `struct CadetPeeer` where we made progress
608 */
609static void
610mqm_send_done (void *cls);
611
612
613/**
614 * Transmit current envelope from this @a mqm.
615 *
616 * @param mqm mqm to transmit message for now
617 */
618static void
619mqm_execute (struct GCP_MessageQueueManager *mqm)
620{
621 struct CadetPeer *cp = mqm->cp;
622
623 /* Move ready pointer to the next entry that might be ready. */
624 if ( (mqm == cp->mqm_ready_ptr) &&
625 (NULL != mqm->next) )
626 cp->mqm_ready_ptr = mqm->next;
627 /* Move entry to the end of the DLL, to be fair. */
628 if (mqm != cp->mqm_tail)
629 {
630 GNUNET_CONTAINER_DLL_remove (cp->mqm_head,
631 cp->mqm_tail,
632 mqm);
633 GNUNET_CONTAINER_DLL_insert_tail (cp->mqm_head,
634 cp->mqm_tail,
635 mqm);
636 }
637 cp->mqm_ready_counter--;
638 if (GNUNET_YES == should_I_drop ())
639 {
640 LOG (GNUNET_ERROR_TYPE_DEBUG,
641 "DROPPING message to peer %s from MQM %p\n",
642 GCP_2s (cp),
643 mqm);
644 GNUNET_MQ_discard (mqm->env);
645 mqm->env = NULL;
646 mqm_send_done (cp);
647 }
648 else
649 {
650 LOG (GNUNET_ERROR_TYPE_DEBUG,
651 "Sending to peer %s from MQM %p\n",
652 GCP_2s (cp),
653 mqm);
654 GNUNET_MQ_send (cp->core_mq,
655 mqm->env);
656 mqm->env = NULL;
657 }
658 mqm->cb (mqm->cb_cls,
659 GNUNET_YES);
660}
661
662
663/**
664 * Find the next ready message in the queue (starting
665 * the search from the `cp->mqm_ready_ptr`) and if possible
666 * execute the transmission.
667 *
668 * @param cp peer to try to send the next ready message to
669 */
670static void
671send_next_ready (struct CadetPeer *cp)
672{
673 struct GCP_MessageQueueManager *mqm;
674
675 if (0 == cp->mqm_ready_counter)
676 return;
677 while ( (NULL != (mqm = cp->mqm_ready_ptr)) &&
678 (NULL == mqm->env) )
679 cp->mqm_ready_ptr = mqm->next;
680 if (NULL == mqm)
681 return; /* nothing to do */
682 mqm_execute (mqm);
683}
684
685
686/**
687 * Function called when CORE took one of the messages from
688 * a message queue manager and transmitted it.
689 *
690 * @param cls the `struct CadetPeeer` where we made progress
691 */
692static void
693mqm_send_done (void *cls)
694{
695 struct CadetPeer *cp = cls;
696
697 LOG (GNUNET_ERROR_TYPE_DEBUG,
698 "Sending to peer %s completed\n",
699 GCP_2s (cp));
700 send_next_ready (cp);
701}
702
703
704/**
705 * Send the message in @a env to @a cp.
706 *
707 * @param mqm the message queue manager to use for transmission
708 * @param env envelope with the message to send; must NOT
709 * yet have a #GNUNET_MQ_notify_sent() callback attached to it
710 */
711void
712GCP_send (struct GCP_MessageQueueManager *mqm,
713 struct GNUNET_MQ_Envelope *env)
714{
715 struct CadetPeer *cp = mqm->cp;
716
717 GNUNET_assert (NULL != env);
718 LOG (GNUNET_ERROR_TYPE_DEBUG,
719 "Queueing message to peer %s in MQM %p\n",
720 GCP_2s (cp),
721 mqm);
722 GNUNET_assert (NULL != cp->core_mq);
723 GNUNET_assert (NULL == mqm->env);
724 GNUNET_MQ_notify_sent (env,
725 &mqm_send_done,
726 cp);
727 mqm->env = env;
728 cp->mqm_ready_counter++;
729 if (mqm != cp->mqm_ready_ptr)
730 cp->mqm_ready_ptr = cp->mqm_head;
731 if (1 == cp->mqm_ready_counter)
732 cp->mqm_ready_ptr = mqm;
733 if (0 != GNUNET_MQ_get_length (cp->core_mq))
734 return;
735 send_next_ready (cp);
736}
737
738
739/**
740 * Function called to destroy a peer now.
741 *
742 * @param cls NULL
743 * @param pid identity of the peer (unused)
744 * @param value the `struct CadetPeer` to clean up
745 * @return #GNUNET_OK (continue to iterate)
746 */
747static int
748destroy_iterator_cb (void *cls,
749 const struct GNUNET_PeerIdentity *pid,
750 void *value)
751{
752 struct CadetPeer *cp = value;
753
754 if (NULL != cp->destroy_task)
755 {
756 GNUNET_SCHEDULER_cancel (cp->destroy_task);
757 cp->destroy_task = NULL;
758 }
759 destroy_peer (cp);
760 return GNUNET_OK;
761}
762
763
764/**
765 * Clean up all entries about all peers.
766 * Must only be called after all tunnels, CORE-connections and
767 * connections are down.
768 */
769void
770GCP_destroy_all_peers ()
771{
772 LOG (GNUNET_ERROR_TYPE_DEBUG,
773 "Destroying all peers now\n");
774 GNUNET_CONTAINER_multipeermap_iterate (peers,
775 &destroy_iterator_cb,
776 NULL);
777}
778
779
780/**
781 * Drop all paths owned by this peer, and do not
782 * allow new ones to be added: We are shutting down.
783 *
784 * @param cp peer to drop paths to
785 */
786void
787GCP_drop_owned_paths (struct CadetPeer *cp)
788{
789 struct CadetPeerPath *path;
790
791 LOG (GNUNET_ERROR_TYPE_DEBUG,
792 "Destroying all paths to %s\n",
793 GCP_2s (cp));
794 while (NULL != (path =
795 GNUNET_CONTAINER_heap_remove_root (cp->path_heap)))
796 GCPP_release (path);
797 GNUNET_CONTAINER_heap_destroy (cp->path_heap);
798 cp->path_heap = NULL;
799}
800
801
802/**
803 * Add an entry to the DLL of all of the paths that this peer is on.
804 *
805 * @param cp peer to modify
806 * @param entry an entry on a path
807 * @param off offset of this peer on the path
808 */
809void
810GCP_path_entry_add (struct CadetPeer *cp,
811 struct CadetPeerPathEntry *entry,
812 unsigned int off)
813{
814 GNUNET_assert (cp == GCPP_get_peer_at_offset (entry->path,
815 off));
816 LOG (GNUNET_ERROR_TYPE_DEBUG,
817 "Discovered that peer %s is on path %s at offset %u\n",
818 GCP_2s (cp),
819 GCPP_2s (entry->path),
820 off);
821 if (off >= cp->path_dll_length)
822 {
823 unsigned int len = cp->path_dll_length;
824
825 GNUNET_array_grow (cp->path_heads,
826 len,
827 off + 4);
828 GNUNET_array_grow (cp->path_tails,
829 cp->path_dll_length,
830 off + 4);
831 }
832 GNUNET_CONTAINER_DLL_insert (cp->path_heads[off],
833 cp->path_tails[off],
834 entry);
835 cp->off_sum += off;
836 cp->num_paths++;
837
838 /* If we have a tunnel to this peer, tell the tunnel that there is a
839 new path available. */
840 if (NULL != cp->t)
841 GCT_consider_path (cp->t,
842 entry->path,
843 off);
844
845 if ( (NULL != cp->search_h) &&
846 (DESIRED_CONNECTIONS_PER_TUNNEL <= cp->num_paths) )
847 {
848 /* Now I have enough paths, stop search */
849 GCD_search_stop (cp->search_h);
850 cp->search_h = NULL;
851 }
852 if (NULL != cp->destroy_task)
853 {
854 /* paths changed, this resets the destroy timeout counter
855 and aborts a destroy task that may no longer be valid
856 to have (as we now have more paths via this peer). */
857 consider_peer_destroy (cp);
858 }
859}
860
861
862/**
863 * Remove an entry from the DLL of all of the paths that this peer is on.
864 *
865 * @param cp peer to modify
866 * @param entry an entry on a path
867 * @param off offset of this peer on the path
868 */
869void
870GCP_path_entry_remove (struct CadetPeer *cp,
871 struct CadetPeerPathEntry *entry,
872 unsigned int off)
873{
874 LOG (GNUNET_ERROR_TYPE_DEBUG,
875 "Removing knowledge about peer %s beging on path %s at offset %u\n",
876 GCP_2s (cp),
877 GCPP_2s (entry->path),
878 off);
879 GNUNET_CONTAINER_DLL_remove (cp->path_heads[off],
880 cp->path_tails[off],
881 entry);
882 GNUNET_assert (0 < cp->num_paths);
883 cp->off_sum -= off;
884 cp->num_paths--;
885 if ( (NULL == cp->core_mq) &&
886 (NULL != cp->t) &&
887 (NULL == cp->search_h) &&
888 (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) )
889 cp->search_h
890 = GCD_search (&cp->pid);
891 if (NULL == cp->destroy_task)
892 {
893 /* paths changed, we might now be ready for destruction, check again */
894 consider_peer_destroy (cp);
895 }
896}
897
898
899/**
900 * Prune down the number of paths to this peer, we seem to
901 * have way too many.
902 *
903 * @param cls the `struct CadetPeer` to maintain the path heap for
904 */
905static void
906path_heap_cleanup (void *cls)
907{
908 struct CadetPeer *cp = cls;
909 struct CadetPeerPath *root;
910
911 cp->heap_cleanup_task = NULL;
912 while (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >=
913 2 * DESIRED_CONNECTIONS_PER_TUNNEL)
914 {
915 /* Now we have way too many, drop least desirable UNLESS it is in use!
916 (Note that this intentionally keeps highly desireable, but currently
917 unused paths around in the hope that we might be able to switch, even
918 if the number of paths exceeds the threshold.) */
919 root = GNUNET_CONTAINER_heap_peek (cp->path_heap);
920 if (NULL !=
921 GCPP_get_connection (root,
922 cp,
923 GCPP_get_length (root) - 1))
924 break; /* can't fix */
925 /* Got plenty of paths to this destination, and this is a low-quality
926 one that we don't care about. Allow it to die. */
927 GNUNET_assert (root ==
928 GNUNET_CONTAINER_heap_remove_root (cp->path_heap));
929 GCPP_release (root);
930 }
931}
932
933
934/**
935 * Try adding a @a path to this @a peer. If the peer already
936 * has plenty of paths, return NULL.
937 *
938 * @param cp peer to which the @a path leads to
939 * @param path a path looking for an owner; may not be fully initialized yet!
940 * @param off offset of @a cp in @a path
941 * @param force force attaching the path
942 * @return NULL if this peer does not care to become a new owner,
943 * otherwise the node in the peer's path heap for the @a path.
944 */
945struct GNUNET_CONTAINER_HeapNode *
946GCP_attach_path (struct CadetPeer *cp,
947 struct CadetPeerPath *path,
948 unsigned int off,
949 int force)
950{
951 GNUNET_CONTAINER_HeapCostType desirability;
952 struct CadetPeerPath *root;
953 GNUNET_CONTAINER_HeapCostType root_desirability;
954 struct GNUNET_CONTAINER_HeapNode *hn;
955
956 GNUNET_assert (off == GCPP_get_length (path) - 1);
957 GNUNET_assert (cp == GCPP_get_peer_at_offset (path,
958 off));
959 if (NULL == cp->path_heap)
960 {
961 /* #GCP_drop_owned_paths() was already called, we cannot take new ones! */
962 GNUNET_assert (GNUNET_NO == force);
963 return NULL;
964 }
965 desirability = GCPP_get_desirability (path);
966 if (GNUNET_NO == force)
967 {
968 /* FIXME: desirability is not yet initialized; tricky! */
969 if (GNUNET_NO ==
970 GNUNET_CONTAINER_heap_peek2 (cp->path_heap,
971 (void **) &root,
972 &root_desirability))
973 {
974 root = NULL;
975 root_desirability = 0;
976 }
977
978 if ( (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) &&
979 (desirability < root_desirability) )
980 {
981 LOG (GNUNET_ERROR_TYPE_DEBUG,
982 "Decided to not attach path %p to peer %s due to undesirability\n",
983 GCPP_2s (path),
984 GCP_2s (cp));
985 return NULL;
986 }
987 }
988
989 LOG (GNUNET_ERROR_TYPE_DEBUG,
990 "Attaching path %s to peer %s (%s)\n",
991 GCPP_2s (path),
992 GCP_2s (cp),
993 (GNUNET_NO == force) ? "desirable" : "forced");
994
995 /* Yes, we'd like to add this path, add to our heap */
996 hn = GNUNET_CONTAINER_heap_insert (cp->path_heap,
997 path,
998 desirability);
999
1000 /* Consider maybe dropping other paths because of the new one */
1001 if ( (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >=
1002 2 * DESIRED_CONNECTIONS_PER_TUNNEL) &&
1003 (NULL != cp->heap_cleanup_task) )
1004 cp->heap_cleanup_task = GNUNET_SCHEDULER_add_now (&path_heap_cleanup,
1005 cp);
1006 return hn;
1007}
1008
1009
1010/**
1011 * This peer can no longer own @a path as the path
1012 * has been extended and a peer further down the line
1013 * is now the new owner.
1014 *
1015 * @param cp old owner of the @a path
1016 * @param path path where the ownership is lost
1017 * @param hn note in @a cp's path heap that must be deleted
1018 */
1019void
1020GCP_detach_path (struct CadetPeer *cp,
1021 struct CadetPeerPath *path,
1022 struct GNUNET_CONTAINER_HeapNode *hn)
1023{
1024 LOG (GNUNET_ERROR_TYPE_DEBUG,
1025 "Detatching path %s from peer %s\n",
1026 GCPP_2s (path),
1027 GCP_2s (cp));
1028 GNUNET_assert (path ==
1029 GNUNET_CONTAINER_heap_remove_node (hn));
1030}
1031
1032
1033/**
1034 * Add a @a connection to this @a cp.
1035 *
1036 * @param cp peer via which the @a connection goes
1037 * @param cc the connection to add
1038 */
1039void
1040GCP_add_connection (struct CadetPeer *cp,
1041 struct CadetConnection *cc)
1042{
1043 LOG (GNUNET_ERROR_TYPE_DEBUG,
1044 "Adding connection %s to peer %s\n",
1045 GCC_2s (cc),
1046 GCP_2s (cp));
1047 GNUNET_assert (GNUNET_OK ==
1048 GNUNET_CONTAINER_multishortmap_put (cp->connections,
1049 &GCC_get_id (cc)->connection_of_tunnel,
1050 cc,
1051 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1052 if (NULL != cp->destroy_task)
1053 {
1054 GNUNET_SCHEDULER_cancel (cp->destroy_task);
1055 cp->destroy_task = NULL;
1056 }
1057}
1058
1059
1060/**
1061 * Remove a @a connection that went via this @a cp.
1062 *
1063 * @param cp peer via which the @a connection went
1064 * @param cc the connection to remove
1065 */
1066void
1067GCP_remove_connection (struct CadetPeer *cp,
1068 struct CadetConnection *cc)
1069{
1070 LOG (GNUNET_ERROR_TYPE_DEBUG,
1071 "Removing connection %s from peer %s\n",
1072 GCC_2s (cc),
1073 GCP_2s (cp));
1074 GNUNET_assert (GNUNET_YES ==
1075 GNUNET_CONTAINER_multishortmap_remove (cp->connections,
1076 &GCC_get_id (cc)->connection_of_tunnel,
1077 cc));
1078 consider_peer_destroy (cp);
1079}
1080
1081
1082/**
1083 * Retrieve the CadetPeer stucture associated with the
1084 * peer. Optionally create one and insert it in the appropriate
1085 * structures if the peer is not known yet.
1086 *
1087 * @param peer_id Full identity of the peer.
1088 * @param create #GNUNET_YES if a new peer should be created if unknown.
1089 * #GNUNET_NO to return NULL if peer is unknown.
1090 * @return Existing or newly created peer structure.
1091 * NULL if unknown and not requested @a create
1092 */
1093struct CadetPeer *
1094GCP_get (const struct GNUNET_PeerIdentity *peer_id,
1095 int create)
1096{
1097 struct CadetPeer *cp;
1098
1099 cp = GNUNET_CONTAINER_multipeermap_get (peers,
1100 peer_id);
1101 if (NULL != cp)
1102 return cp;
1103 if (GNUNET_NO == create)
1104 return NULL;
1105 cp = GNUNET_new (struct CadetPeer);
1106 cp->pid = *peer_id;
1107 cp->connections = GNUNET_CONTAINER_multishortmap_create (32,
1108 GNUNET_YES);
1109 cp->path_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
1110 GNUNET_assert (GNUNET_YES ==
1111 GNUNET_CONTAINER_multipeermap_put (peers,
1112 &cp->pid,
1113 cp,
1114 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1115 LOG (GNUNET_ERROR_TYPE_DEBUG,
1116 "Creating peer %s\n",
1117 GCP_2s (cp));
1118 return cp;
1119}
1120
1121
1122/**
1123 * Obtain the peer identity for a `struct CadetPeer`.
1124 *
1125 * @param cp our peer handle
1126 * @return the peer identity
1127 */
1128const struct GNUNET_PeerIdentity *
1129GCP_get_id (struct CadetPeer *cp)
1130{
1131 return &cp->pid;
1132}
1133
1134
1135/**
1136 * Iterate over all known peers.
1137 *
1138 * @param iter Iterator.
1139 * @param cls Closure for @c iter.
1140 */
1141void
1142GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter,
1143 void *cls)
1144{
1145 GNUNET_CONTAINER_multipeermap_iterate (peers,
1146 iter,
1147 cls);
1148}
1149
1150
1151/**
1152 * Count the number of known paths toward the peer.
1153 *
1154 * @param cp Peer to get path info.
1155 * @return Number of known paths.
1156 */
1157unsigned int
1158GCP_count_paths (const struct CadetPeer *cp)
1159{
1160 return cp->num_paths;
1161}
1162
1163
1164/**
1165 * Iterate over the paths to a peer.
1166 *
1167 * @param cp Peer to get path info.
1168 * @param callback Function to call for every path.
1169 * @param callback_cls Closure for @a callback.
1170 * @return Number of iterated paths.
1171 */
1172unsigned int
1173GCP_iterate_paths (struct CadetPeer *cp,
1174 GCP_PathIterator callback,
1175 void *callback_cls)
1176{
1177 unsigned int ret = 0;
1178
1179 LOG (GNUNET_ERROR_TYPE_DEBUG,
1180 "Iterating over paths to peer %s%s\n",
1181 GCP_2s (cp),
1182 (NULL == cp->core_mq) ? "" : " including direct link");
1183 if (NULL != cp->core_mq)
1184 {
1185 struct CadetPeerPath *path;
1186
1187 path = GCPP_get_path_from_route (1,
1188 &cp->pid);
1189 ret++;
1190 if (GNUNET_NO ==
1191 callback (callback_cls,
1192 path,
1193 0))
1194 return ret;
1195 }
1196 for (unsigned int i=0;i<cp->path_dll_length;i++)
1197 {
1198 for (struct CadetPeerPathEntry *pe = cp->path_heads[i];
1199 NULL != pe;
1200 pe = pe->next)
1201 {
1202 ret++;
1203 if (GNUNET_NO ==
1204 callback (callback_cls,
1205 pe->path,
1206 i))
1207 return ret;
1208 }
1209 }
1210 return ret;
1211}
1212
1213
1214/**
1215 * Iterate over the paths to @a cp where
1216 * @a cp is at distance @a dist from us.
1217 *
1218 * @param cp Peer to get path info.
1219 * @param dist desired distance of @a cp to us on the path
1220 * @param callback Function to call for every path.
1221 * @param callback_cls Closure for @a callback.
1222 * @return Number of iterated paths.
1223 */
1224unsigned int
1225GCP_iterate_paths_at (struct CadetPeer *cp,
1226 unsigned int dist,
1227 GCP_PathIterator callback,
1228 void *callback_cls)
1229{
1230 unsigned int ret = 0;
1231
1232 if (dist >= cp->path_dll_length)
1233 {
1234 LOG (GNUNET_ERROR_TYPE_DEBUG,
1235 "Asked to look for paths at distance %u, but maximum for me is < %u\n",
1236 dist,
1237 cp->path_dll_length);
1238 return 0;
1239 }
1240 for (struct CadetPeerPathEntry *pe = cp->path_heads[dist];
1241 NULL != pe;
1242 pe = pe->next)
1243 {
1244 if (GNUNET_NO ==
1245 callback (callback_cls,
1246 pe->path,
1247 dist))
1248 return ret;
1249 ret++;
1250 }
1251 return ret;
1252}
1253
1254
1255/**
1256 * Get the tunnel towards a peer.
1257 *
1258 * @param cp Peer to get from.
1259 * @param create #GNUNET_YES to create a tunnel if we do not have one
1260 * @return Tunnel towards peer.
1261 */
1262struct CadetTunnel *
1263GCP_get_tunnel (struct CadetPeer *cp,
1264 int create)
1265{
1266 if (NULL == cp)
1267 return NULL;
1268 if ( (NULL != cp->t) ||
1269 (GNUNET_NO == create) )
1270 return cp->t;
1271 cp->t = GCT_create_tunnel (cp);
1272 consider_peer_activate (cp);
1273 return cp->t;
1274}
1275
1276
1277/**
1278 * Hello offer was passed to the transport service. Mark it
1279 * as done.
1280 *
1281 * @param cls the `struct CadetPeer` where the offer completed
1282 */
1283static void
1284hello_offer_done (void *cls)
1285{
1286 struct CadetPeer *cp = cls;
1287
1288 cp->hello_offer = NULL;
1289}
1290
1291
1292/**
1293 * We got a HELLO for a @a peer, remember it, and possibly
1294 * trigger adequate actions (like trying to connect).
1295 *
1296 * @param cp the peer we got a HELLO for
1297 * @param hello the HELLO to remember
1298 */
1299void
1300GCP_set_hello (struct CadetPeer *cp,
1301 const struct GNUNET_HELLO_Message *hello)
1302{
1303 struct GNUNET_HELLO_Message *mrg;
1304
1305 LOG (GNUNET_ERROR_TYPE_DEBUG,
1306 "Got %u byte HELLO for peer %s\n",
1307 (unsigned int) GNUNET_HELLO_size (hello),
1308 GCP_2s (cp));
1309 if (NULL != cp->hello_offer)
1310 {
1311 GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer);
1312 cp->hello_offer = NULL;
1313 }
1314 if (NULL != cp->hello)
1315 {
1316 mrg = GNUNET_HELLO_merge (hello,
1317 cp->hello);
1318 GNUNET_free (cp->hello);
1319 cp->hello = mrg;
1320 }
1321 else
1322 {
1323 cp->hello = GNUNET_memdup (hello,
1324 GNUNET_HELLO_size (hello));
1325 }
1326 cp->hello_offer
1327 = GNUNET_TRANSPORT_offer_hello (cfg,
1328 GNUNET_HELLO_get_header (cp->hello) ,
1329 &hello_offer_done,
1330 cp);
1331 /* New HELLO means cp's destruction time may change... */
1332 consider_peer_destroy (cp);
1333}
1334
1335
1336/**
1337 * The tunnel to the given peer no longer exists, remove it from our
1338 * data structures, and possibly clean up the peer itself.
1339 *
1340 * @param cp the peer affected
1341 * @param t the dead tunnel
1342 */
1343void
1344GCP_drop_tunnel (struct CadetPeer *cp,
1345 struct CadetTunnel *t)
1346{
1347 LOG (GNUNET_ERROR_TYPE_DEBUG,
1348 "Dropping tunnel %s to peer %s\n",
1349 GCT_2s (t),
1350 GCP_2s (cp));
1351 GNUNET_assert (cp->t == t);
1352 cp->t = NULL;
1353 consider_peer_destroy (cp);
1354}
1355
1356
1357/**
1358 * Test if @a cp has a core-level connection
1359 *
1360 * @param cp peer to test
1361 * @return #GNUNET_YES if @a cp has a core-level connection
1362 */
1363int
1364GCP_has_core_connection (struct CadetPeer *cp)
1365{
1366 return (NULL != cp->core_mq) ? GNUNET_YES : GNUNET_NO;
1367}
1368
1369
1370/**
1371 * Start message queue change notifications.
1372 *
1373 * @param cp peer to notify for
1374 * @param cb function to call if mq becomes available or unavailable
1375 * @param cb_cls closure for @a cb
1376 * @return handle to cancel request
1377 */
1378struct GCP_MessageQueueManager *
1379GCP_request_mq (struct CadetPeer *cp,
1380 GCP_MessageQueueNotificationCallback cb,
1381 void *cb_cls)
1382{
1383 struct GCP_MessageQueueManager *mqm;
1384
1385 mqm = GNUNET_new (struct GCP_MessageQueueManager);
1386 mqm->cb = cb;
1387 mqm->cb_cls = cb_cls;
1388 mqm->cp = cp;
1389 GNUNET_CONTAINER_DLL_insert (cp->mqm_head,
1390 cp->mqm_tail,
1391 mqm);
1392 LOG (GNUNET_ERROR_TYPE_DEBUG,
1393 "Creating MQM %p for peer %s\n",
1394 mqm,
1395 GCP_2s (cp));
1396 if (NULL != cp->core_mq)
1397 cb (cb_cls,
1398 GNUNET_YES);
1399 return mqm;
1400}
1401
1402
1403/**
1404 * Stops message queue change notifications.
1405 *
1406 * @param mqm handle matching request to cancel
1407 * @param last_env final message to transmit, or NULL
1408 */
1409void
1410GCP_request_mq_cancel (struct GCP_MessageQueueManager *mqm,
1411 struct GNUNET_MQ_Envelope *last_env)
1412{
1413 struct CadetPeer *cp = mqm->cp;
1414
1415 LOG (GNUNET_ERROR_TYPE_DEBUG,
1416 "Destroying MQM %p for peer %s%s\n",
1417 mqm,
1418 GCP_2s (cp),
1419 (NULL == last_env) ? "" : " with last ditch transmission");
1420 if (NULL != mqm->env)
1421 GNUNET_MQ_discard (mqm->env);
1422 if (NULL != last_env)
1423 {
1424 if (NULL != cp->core_mq)
1425 {
1426 GNUNET_MQ_notify_sent (last_env,
1427 &mqm_send_done,
1428 cp);
1429 GNUNET_MQ_send (cp->core_mq,
1430 last_env);
1431 }
1432 else
1433 {
1434 GNUNET_MQ_discard (last_env);
1435 }
1436 }
1437 if (cp->mqm_ready_ptr == mqm)
1438 cp->mqm_ready_ptr = mqm->next;
1439 GNUNET_CONTAINER_DLL_remove (cp->mqm_head,
1440 cp->mqm_tail,
1441 mqm);
1442 GNUNET_free (mqm);
1443}
1444
1445
1446/**
1447 * Send the message in @a env to @a cp, overriding queueing logic.
1448 * This function should only be used to send error messages outside
1449 * of flow and congestion control, similar to ICMP. Note that
1450 * the envelope may be silently discarded as well.
1451 *
1452 * @param cp peer to send the message to
1453 * @param env envelope with the message to send
1454 */
1455void
1456GCP_send_ooo (struct CadetPeer *cp,
1457 struct GNUNET_MQ_Envelope *env)
1458{
1459 LOG (GNUNET_ERROR_TYPE_DEBUG,
1460 "Sending message to %s out of management\n",
1461 GCP_2s (cp));
1462 if (NULL == cp->core_mq)
1463 {
1464 GNUNET_MQ_discard (env);
1465 return;
1466 }
1467 GNUNET_MQ_notify_sent (env,
1468 &mqm_send_done,
1469 cp);
1470 GNUNET_MQ_send (cp->core_mq,
1471 env);
1472}
1473
1474
1475
1476
1477/* end of gnunet-service-cadet-new_peer.c */
diff --git a/src/cadet/gnunet-service-cadet-new_peer.h b/src/cadet/gnunet-service-cadet-new_peer.h
deleted file mode 100644
index e1d6fc33a..000000000
--- a/src/cadet/gnunet-service-cadet-new_peer.h
+++ /dev/null
@@ -1,394 +0,0 @@
1
2/*
3 This file is part of GNUnet.
4 Copyright (C) 2001-2017 GNUnet e.V.
5
6 GNUnet is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published
8 by the Free Software Foundation; either version 3, or (at your
9 option) any later version.
10
11 GNUnet is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNUnet; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA.
20*/
21
22/**
23 * @file cadet/gnunet-service-cadet-new_peer.h
24 * @brief Information we track per peer.
25 * @author Bartlomiej Polot
26 * @author Christian Grothoff
27 */
28#ifndef GNUNET_SERVICE_CADET_PEER_H
29#define GNUNET_SERVICE_CADET_PEER_H
30
31#include "gnunet-service-cadet-new.h"
32#include "gnunet_hello_lib.h"
33
34
35/**
36 * Get the static string for a peer ID.
37 *
38 * @param peer Peer.
39 *
40 * @return Static string for it's ID.
41 */
42const char *
43GCP_2s (const struct CadetPeer *peer);
44
45
46/**
47 * Retrieve the CadetPeer stucture associated with the
48 * peer. Optionally create one and insert it in the appropriate
49 * structures if the peer is not known yet.
50 *
51 * @param peer_id Full identity of the peer.
52 * @param create #GNUNET_YES if a new peer should be created if unknown.
53 * #GNUNET_NO to return NULL if peer is unknown.
54 * @return Existing or newly created peer structure.
55 * NULL if unknown and not requested @a create
56 */
57struct CadetPeer *
58GCP_get (const struct GNUNET_PeerIdentity *peer_id,
59 int create);
60
61
62/**
63 * Calculate how desirable a path is for @a cp if
64 * @a cp is at offset @a off in the path.
65 *
66 * @param cp a peer reachable via a path
67 * @param off offset of @a cp in a path
68 * @return score how useful a path is to reach @a cp,
69 * positive scores mean path is more desirable
70 */
71double
72GCP_get_desirability_of_path (struct CadetPeer *cp,
73 unsigned int off);
74
75
76/**
77 * Obtain the peer identity for a `struct CadetPeer`.
78 *
79 * @param cp our peer handle
80 * @return the peer identity
81 */
82const struct GNUNET_PeerIdentity *
83GCP_get_id (struct CadetPeer *cp);
84
85
86/**
87 * Iterate over all known peers.
88 *
89 * @param iter Iterator.
90 * @param cls Closure for @c iter.
91 */
92void
93GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter,
94 void *cls);
95
96
97/**
98 * Count the number of known paths toward the peer.
99 *
100 * @param cp Peer to get path info.
101 * @return Number of known paths.
102 */
103unsigned int
104GCP_count_paths (const struct CadetPeer *cp);
105
106
107/**
108 * Drop all paths owned by this peer, and do not
109 * allow new ones to be added: We are shutting down.
110 *
111 * @param cp peer to drop paths to
112 */
113void
114GCP_drop_owned_paths (struct CadetPeer *cp);
115
116
117/**
118 * Peer path iterator.
119 *
120 * @param cls Closure.
121 * @param path Path itself
122 * @param off offset of the target peer in @a path
123 * @return #GNUNET_YES if should keep iterating.
124 * #GNUNET_NO otherwise.
125 */
126typedef int
127(*GCP_PathIterator) (void *cls,
128 struct CadetPeerPath *path,
129 unsigned int off);
130
131
132/**
133 * Iterate over the paths to a peer.
134 *
135 * @param cp Peer to get path info.
136 * @param callback Function to call for every path.
137 * @param callback_cls Closure for @a callback.
138 * @return Number of iterated paths.
139 */
140unsigned int
141GCP_iterate_paths (struct CadetPeer *cp,
142 GCP_PathIterator callback,
143 void *callback_cls);
144
145
146/**
147 * Iterate over the paths to @a peer where
148 * @a peer is at distance @a dist from us.
149 *
150 * @param cp Peer to get path info.
151 * @param dist desired distance of @a peer to us on the path
152 * @param callback Function to call for every path.
153 * @param callback_cls Closure for @a callback.
154 * @return Number of iterated paths.
155 */
156unsigned int
157GCP_iterate_paths_at (struct CadetPeer *cp,
158 unsigned int dist,
159 GCP_PathIterator callback,
160 void *callback_cls);
161
162
163/**
164 * Remove an entry from the DLL of all of the paths that this peer is on.
165 *
166 * @param cp peer to modify
167 * @param entry an entry on a path
168 * @param off offset of this peer on the path
169 */
170void
171GCP_path_entry_remove (struct CadetPeer *cp,
172 struct CadetPeerPathEntry *entry,
173 unsigned int off);
174
175
176/**
177 * Add an entry to the DLL of all of the paths that this peer is on.
178 *
179 * @param cp peer to modify
180 * @param entry an entry on a path
181 * @param off offset of this peer on the path
182 */
183void
184GCP_path_entry_add (struct CadetPeer *cp,
185 struct CadetPeerPathEntry *entry,
186 unsigned int off);
187
188
189/**
190 * Get the tunnel towards a peer.
191 *
192 * @param cp Peer to get from.
193 * @param create #GNUNET_YES to create a tunnel if we do not have one
194 * @return Tunnel towards peer.
195 */
196struct CadetTunnel *
197GCP_get_tunnel (struct CadetPeer *cp,
198 int create);
199
200
201/**
202 * The tunnel to the given peer no longer exists, remove it from our
203 * data structures, and possibly clean up the peer itself.
204 *
205 * @param cp the peer affected
206 * @param t the dead tunnel
207 */
208void
209GCP_drop_tunnel (struct CadetPeer *cp,
210 struct CadetTunnel *t);
211
212
213/**
214 * Try adding a @a path to this @a cp. If the peer already
215 * has plenty of paths, return NULL.
216 *
217 * @param cp peer to which the @a path leads to
218 * @param path a path looking for an owner; may not be fully initialized yet!
219 * @param off offset of @a cp in @a path
220 * @param force for attaching the path
221 * @return NULL if this peer does not care to become a new owner,
222 * otherwise the node in the peer's path heap for the @a path.
223 */
224struct GNUNET_CONTAINER_HeapNode *
225GCP_attach_path (struct CadetPeer *cp,
226 struct CadetPeerPath *path,
227 unsigned int off,
228 int force);
229
230
231/**
232 * This peer can no longer own @a path as the path
233 * has been extended and a peer further down the line
234 * is now the new owner.
235 *
236 * @param cp old owner of the @a path
237 * @param path path where the ownership is lost
238 * @param hn note in @a cp's path heap that must be deleted
239 */
240void
241GCP_detach_path (struct CadetPeer *cp,
242 struct CadetPeerPath *path,
243 struct GNUNET_CONTAINER_HeapNode *hn);
244
245
246/**
247 * Add a @a connection to this @a cp.
248 *
249 * @param cp peer via which the @a connection goes
250 * @param cc the connection to add
251 */
252void
253GCP_add_connection (struct CadetPeer *cp,
254 struct CadetConnection *cc);
255
256
257/**
258 * Remove a @a connection that went via this @a cp.
259 *
260 * @param cp peer via which the @a connection went
261 * @param cc the connection to remove
262 */
263void
264GCP_remove_connection (struct CadetPeer *cp,
265 struct CadetConnection *cc);
266
267
268/**
269 * We got a HELLO for a @a cp, remember it, and possibly
270 * trigger adequate actions (like trying to connect).
271 *
272 * @param cp the peer we got a HELLO for
273 * @param hello the HELLO to remember
274 */
275void
276GCP_set_hello (struct CadetPeer *cp,
277 const struct GNUNET_HELLO_Message *hello);
278
279
280/**
281 * Clean up all entries about all peers.
282 * Must only be called after all tunnels, CORE-connections and
283 * connections are down.
284 */
285void
286GCP_destroy_all_peers (void);
287
288
289/**
290 * Data structure used to track whom we have to notify about changes
291 * in our ability to transmit to a given peer.
292 *
293 * All queue managers will be given equal chance for sending messages
294 * to @a cp. This construct this guarantees fairness for access to @a
295 * cp among the different message queues. Each connection or route
296 * will have its respective message queue managers for each direction.
297 */
298struct GCP_MessageQueueManager;
299
300
301/**
302 * Function to call with updated message queue object.
303 *
304 * @param cls closure
305 * @param available #GNUNET_YES if sending is now possible,
306 * #GNUNET_NO if sending is no longer possible
307 * #GNUNET_SYSERR if sending is no longer possible
308 * and the last envelope was discarded
309 */
310typedef void
311(*GCP_MessageQueueNotificationCallback)(void *cls,
312 int available);
313
314
315/**
316 * Start message queue change notifications. Will create a new slot
317 * to manage the message queue to the given @a cp.
318 *
319 * @param cp peer to notify for
320 * @param cb function to call if mq becomes available or unavailable
321 * @param cb_cls closure for @a cb
322 * @return handle to cancel request
323 */
324struct GCP_MessageQueueManager *
325GCP_request_mq (struct CadetPeer *cp,
326 GCP_MessageQueueNotificationCallback cb,
327 void *cb_cls);
328
329
330/**
331 * Test if @a cp has a core-level connection
332 *
333 * @param cp peer to test
334 * @return #GNUNET_YES if @a cp has a core-level connection
335 */
336int
337GCP_has_core_connection (struct CadetPeer *cp);
338
339
340/**
341 * Send the message in @a env via a @a mqm. Must only be called at
342 * most once after the respective
343 * #GCP_MessageQueueNotificationCallback was called with `available`
344 * set to #GNUNET_YES, and not after the callback was called with
345 * `available` set to #GNUNET_NO or #GNUNET_SYSERR.
346 *
347 * @param mqm message queue manager for the transmission
348 * @param env envelope with the message to send; must NOT
349 * yet have a #GNUNET_MQ_notify_sent() callback attached to it
350 */
351void
352GCP_send (struct GCP_MessageQueueManager *mqm,
353 struct GNUNET_MQ_Envelope *env);
354
355
356/**
357 * Send the message in @a env to @a cp, overriding queueing logic.
358 * This function should only be used to send error messages outside
359 * of flow and congestion control, similar to ICMP. Note that
360 * the envelope may be silently discarded as well.
361 *
362 * @param cp peer to send the message to
363 * @param env envelope with the message to send
364 */
365void
366GCP_send_ooo (struct CadetPeer *cp,
367 struct GNUNET_MQ_Envelope *env);
368
369
370/**
371 * Stops message queue change notifications and sends a last message.
372 * In practice, this is implemented by sending that @a last_env
373 * message immediately (if any), ignoring queue order.
374 *
375 * @param mqm handle matching request to cancel
376 * @param last_env final message to transmit, or NULL
377 */
378void
379GCP_request_mq_cancel (struct GCP_MessageQueueManager *mqm,
380 struct GNUNET_MQ_Envelope *last_env);
381
382
383/**
384 * Set the message queue to @a mq for peer @a cp and notify watchers.
385 *
386 * @param cp peer to modify
387 * @param mq message queue to set (can be NULL)
388 */
389void
390GCP_set_mq (struct CadetPeer *cp,
391 struct GNUNET_MQ_Handle *mq);
392
393
394#endif
diff --git a/src/cadet/gnunet-service-cadet.c b/src/cadet/gnunet-service-cadet.c
index 3a07f0ee5..a7e1fca47 100644
--- a/src/cadet/gnunet-service-cadet.c
+++ b/src/cadet/gnunet-service-cadet.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 Copyright (C) 2001-2013 GNUnet e.V. 3 Copyright (C) 2001-2013, 2017 GNUnet e.V.
4 4
5 GNUnet is free software; you can redistribute it and/or modify 5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published 6 it under the terms of the GNU General Public License as published
@@ -22,38 +22,82 @@
22 * @file cadet/gnunet-service-cadet.c 22 * @file cadet/gnunet-service-cadet.c
23 * @brief GNUnet CADET service with encryption 23 * @brief GNUnet CADET service with encryption
24 * @author Bartlomiej Polot 24 * @author Bartlomiej Polot
25 * 25 * @author Christian Grothoff
26 * FIXME in progress:
27 * - rekey - reliability interaction
28 * - channel retransmit timing
29 *
30 * TODO:
31 * - relay corking down to core
32 * - set ttl relative to path length
33 * TODO END
34 * 26 *
35 * Dictionary: 27 * Dictionary:
36 * - peer: other cadet instance. If there is direct connection it's a neighbor. 28 * - peer: other cadet instance. If there is direct connection it's a neighbor.
37 * - tunnel: encrypted connection to a peer, neighbor or not.
38 * - channel: connection between two clients, on the same or different peers.
39 * have properties like reliability.
40 * - path: series of directly connected peer from one peer to another. 29 * - path: series of directly connected peer from one peer to another.
41 * - connection: path which is being used in a tunnel. 30 * - connection: path which is being used in a tunnel.
31 * - tunnel: encrypted connection to a peer, neighbor or not.
32 * - channel: logical link between two clients, on the same or different peers.
33 * have properties like reliability.
42 */ 34 */
43 35
44#include "platform.h" 36#include "platform.h"
45#include "gnunet_util_lib.h" 37#include "gnunet_util_lib.h"
46#include "cadet.h" 38#include "cadet.h"
47#include "gnunet_statistics_service.h" 39#include "gnunet_statistics_service.h"
48 40#include "gnunet-service-cadet.h"
49#include "gnunet-service-cadet_local.h"
50#include "gnunet-service-cadet_channel.h" 41#include "gnunet-service-cadet_channel.h"
51#include "gnunet-service-cadet_connection.h" 42#include "gnunet-service-cadet_connection.h"
52#include "gnunet-service-cadet_tunnel.h" 43#include "gnunet-service-cadet_core.h"
53#include "gnunet-service-cadet_dht.h" 44#include "gnunet-service-cadet_dht.h"
54#include "gnunet-service-cadet_peer.h"
55#include "gnunet-service-cadet_hello.h" 45#include "gnunet-service-cadet_hello.h"
46#include "gnunet-service-cadet_tunnels.h"
47#include "gnunet-service-cadet_peer.h"
48#include "gnunet-service-cadet_paths.h"
49
50#define LOG(level, ...) GNUNET_log (level,__VA_ARGS__)
51
52
53/**
54 * Struct containing information about a client of the service
55 */
56struct CadetClient
57{
58 /**
59 * Linked list next
60 */
61 struct CadetClient *next;
62
63 /**
64 * Linked list prev
65 */
66 struct CadetClient *prev;
67
68 /**
69 * Tunnels that belong to this client, indexed by local id,
70 * value is a `struct CadetChannel`.
71 */
72 struct GNUNET_CONTAINER_MultiHashMap32 *channels;
73
74 /**
75 * Handle to communicate with the client
76 */
77 struct GNUNET_MQ_Handle *mq;
78
79 /**
80 * Client handle.
81 */
82 struct GNUNET_SERVICE_Client *client;
83
84 /**
85 * Ports that this client has declared interest in.
86 * Indexed by port, contains *Client.
87 */
88 struct GNUNET_CONTAINER_MultiHashMap *ports;
56 89
90 /**
91 * Channel ID to use for the next incoming channel for this client.
92 * Wraps around (in theory).
93 */
94 struct GNUNET_CADET_ClientChannelNumber next_ccn;
95
96 /**
97 * ID of the client, mainly for debug messages. Purely internal to this file.
98 */
99 unsigned int id;
100};
57 101
58/******************************************************************************/ 102/******************************************************************************/
59/*********************** GLOBAL VARIABLES ****************************/ 103/*********************** GLOBAL VARIABLES ****************************/
@@ -62,37 +106,317 @@
62/****************************** Global variables ******************************/ 106/****************************** Global variables ******************************/
63 107
64/** 108/**
109 * Handle to our configuration.
110 */
111const struct GNUNET_CONFIGURATION_Handle *cfg;
112
113/**
65 * Handle to the statistics service. 114 * Handle to the statistics service.
66 */ 115 */
67struct GNUNET_STATISTICS_Handle *stats; 116struct GNUNET_STATISTICS_Handle *stats;
68 117
69/** 118/**
70 * Local peer own ID (memory efficient handle). 119 * Handle to communicate with ATS.
71 */ 120 */
72GNUNET_PEER_Id myid; 121struct GNUNET_ATS_ConnectivityHandle *ats_ch;
73 122
74/** 123/**
75 * Local peer own ID (full value). 124 * Local peer own ID.
76 */ 125 */
77struct GNUNET_PeerIdentity my_full_id; 126struct GNUNET_PeerIdentity my_full_id;
78 127
128/**
129 * Own private key.
130 */
131struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
79 132
80/** 133/**
81 * Signal that shutdown is happening: prevent recover measures. 134 * Signal that shutdown is happening: prevent recovery measures.
82 */ 135 */
83int shutting_down; 136int shutting_down;
84 137
85/*************************** Static global variables **************************/ 138/**
139 * DLL with all the clients, head.
140 */
141static struct CadetClient *clients_head;
86 142
87/** 143/**
88 * Own private key. 144 * DLL with all the clients, tail.
89 */ 145 */
90static struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key; 146static struct CadetClient *clients_tail;
91 147
148/**
149 * Next ID to assign to a client.
150 */
151static unsigned int next_client_id;
152
153/**
154 * All ports clients of this peer have opened.
155 */
156struct GNUNET_CONTAINER_MultiHashMap *open_ports;
157
158/**
159 * Map from ports to channels where the ports were closed at the
160 * time we got the inbound connection.
161 * Indexed by port, contains `struct CadetChannel`.
162 */
163struct GNUNET_CONTAINER_MultiHashMap *loose_channels;
164
165/**
166 * Map from PIDs to `struct CadetPeer` entries.
167 */
168struct GNUNET_CONTAINER_MultiPeerMap *peers;
169
170/**
171 * Map from `struct GNUNET_CADET_ConnectionTunnelIdentifier`
172 * hash codes to `struct CadetConnection` objects.
173 */
174struct GNUNET_CONTAINER_MultiShortmap *connections;
175
176/**
177 * How many messages are needed to trigger an AXOLOTL ratchet advance.
178 */
179unsigned long long ratchet_messages;
180
181/**
182 * How long until we trigger a ratched advance due to time.
183 */
184struct GNUNET_TIME_Relative ratchet_time;
185
186/**
187 * How frequently do we send KEEPALIVE messages on idle connections?
188 */
189struct GNUNET_TIME_Relative keepalive_period;
190
191/**
192 * Set to non-zero values to create random drops to test retransmissions.
193 */
194unsigned long long drop_percent;
195
196
197/**
198 * Send a message to a client.
199 *
200 * @param c client to get the message
201 * @param env envelope with the message
202 */
203void
204GSC_send_to_client (struct CadetClient *c,
205 struct GNUNET_MQ_Envelope *env)
206{
207 GNUNET_MQ_send (c->mq,
208 env);
209}
210
211
212/**
213 * Return identifier for a client as a string.
214 *
215 * @param c client to identify
216 * @return string for debugging
217 */
218const char *
219GSC_2s (struct CadetClient *c)
220{
221 static char buf[32];
222
223 GNUNET_snprintf (buf,
224 sizeof (buf),
225 "Client(%u)",
226 c->id);
227 return buf;
228}
229
230
231/**
232 * Lookup channel of client @a c by @a ccn.
233 *
234 * @param c client to look in
235 * @param ccn channel ID to look up
236 * @return NULL if no such channel exists
237 */
238static struct CadetChannel *
239lookup_channel (struct CadetClient *c,
240 struct GNUNET_CADET_ClientChannelNumber ccn)
241{
242 return GNUNET_CONTAINER_multihashmap32_get (c->channels,
243 ntohl (ccn.channel_of_client));
244}
245
246
247/**
248 * Obtain the next LID to use for incoming connections to
249 * the given client.
250 *
251 * @param c client handle
252 */
253static struct GNUNET_CADET_ClientChannelNumber
254client_get_next_ccn (struct CadetClient *c)
255{
256 struct GNUNET_CADET_ClientChannelNumber ccn = c->next_ccn;
257
258 /* increment until we have a free one... */
259 while (NULL !=
260 lookup_channel (c,
261 ccn))
262 {
263 ccn.channel_of_client
264 = htonl (1 + (ntohl (ccn.channel_of_client)));
265 if (ntohl (ccn.channel_of_client) >=
266 GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
267 ccn.channel_of_client = htonl (0);
268 }
269 c->next_ccn.channel_of_client
270 = htonl (1 + (ntohl (ccn.channel_of_client)));
271 return ccn;
272}
273
274
275/**
276 * Bind incoming channel to this client, and notify client about
277 * incoming connection. Caller is responsible for notifying the other
278 * peer about our acceptance of the channel.
279 *
280 * @param c client to bind to
281 * @param ch channel to be bound
282 * @param dest peer that establishes the connection
283 * @param port port number
284 * @param options options
285 * @return local channel number assigned to the new client
286 */
287struct GNUNET_CADET_ClientChannelNumber
288GSC_bind (struct CadetClient *c,
289 struct CadetChannel *ch,
290 struct CadetPeer *dest,
291 const struct GNUNET_HashCode *port,
292 uint32_t options)
293{
294 struct GNUNET_MQ_Envelope *env;
295 struct GNUNET_CADET_LocalChannelCreateMessage *cm;
296 struct GNUNET_CADET_ClientChannelNumber ccn;
297
298 ccn = client_get_next_ccn (c);
299 GNUNET_assert (GNUNET_YES ==
300 GNUNET_CONTAINER_multihashmap32_put (c->channels,
301 ntohl (ccn.channel_of_client),
302 ch,
303 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
304 LOG (GNUNET_ERROR_TYPE_DEBUG,
305 "Accepting incoming %s from %s on open port %s (%u), assigning ccn %X\n",
306 GCCH_2s (ch),
307 GCP_2s (dest),
308 GNUNET_h2s (port),
309 (uint32_t) ntohl (options),
310 (uint32_t) ntohl (ccn.channel_of_client));
311 /* notify local client about incoming connection! */
312 env = GNUNET_MQ_msg (cm,
313 GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_CREATE);
314 cm->ccn = ccn;
315 cm->port = *port;
316 cm->opt = htonl (options);
317 cm->peer = *GCP_get_id (dest);
318 GSC_send_to_client (c,
319 env);
320 return ccn;
321}
322
323
324/**
325 * Callback invoked on all peers to destroy all tunnels
326 * that may still exist.
327 *
328 * @param cls NULL
329 * @param pid identify of a peer
330 * @param value a `struct CadetPeer` that may still have a tunnel
331 * @return #GNUNET_OK (iterate over all entries)
332 */
333static int
334destroy_tunnels_now (void *cls,
335 const struct GNUNET_PeerIdentity *pid,
336 void *value)
337{
338 struct CadetPeer *cp = value;
339 struct CadetTunnel *t = GCP_get_tunnel (cp,
340 GNUNET_NO);
341
342 if (NULL != t)
343 GCT_destroy_tunnel_now (t);
344 return GNUNET_OK;
345}
346
347
348/**
349 * Callback invoked on all peers to destroy all tunnels
350 * that may still exist.
351 *
352 * @param cls NULL
353 * @param pid identify of a peer
354 * @param value a `struct CadetPeer` that may still have a tunnel
355 * @return #GNUNET_OK (iterate over all entries)
356 */
357static int
358destroy_paths_now (void *cls,
359 const struct GNUNET_PeerIdentity *pid,
360 void *value)
361{
362 struct CadetPeer *cp = value;
363
364 GCP_drop_owned_paths (cp);
365 return GNUNET_OK;
366}
367
368
369/**
370 * Shutdown everything once the clients have disconnected.
371 */
372static void
373shutdown_rest ()
374{
375 if (NULL != stats)
376 {
377 GNUNET_STATISTICS_destroy (stats,
378 GNUNET_NO);
379 stats = NULL;
380 }
381 if (NULL != open_ports)
382 {
383 GNUNET_CONTAINER_multihashmap_destroy (open_ports);
384 open_ports = NULL;
385 }
386 if (NULL != loose_channels)
387 {
388 GNUNET_CONTAINER_multihashmap_destroy (loose_channels);
389 loose_channels = NULL;
390 }
391 /* Destroy tunnels. Note that all channels must be destroyed first! */
392 GCP_iterate_all (&destroy_tunnels_now,
393 NULL);
394 /* All tunnels, channels, connections and CORE must be down before this point. */
395 GCP_iterate_all (&destroy_paths_now,
396 NULL);
397 /* All paths, tunnels, channels, connections and CORE must be down before this point. */
398 GCP_destroy_all_peers ();
399 if (NULL != peers)
400 {
401 GNUNET_CONTAINER_multipeermap_destroy (peers);
402 peers = NULL;
403 }
404 if (NULL != connections)
405 {
406 GNUNET_CONTAINER_multishortmap_destroy (connections);
407 connections = NULL;
408 }
409 if (NULL != ats_ch)
410 {
411 GNUNET_ATS_connectivity_done (ats_ch);
412 ats_ch = NULL;
413 }
414 GCD_shutdown ();
415 GCH_shutdown ();
416 GNUNET_free_non_null (my_private_key);
417 my_private_key = NULL;
418}
92 419
93/******************************************************************************/
94/************************ MAIN FUNCTIONS ****************************/
95/******************************************************************************/
96 420
97/** 421/**
98 * Task run during shutdown. 422 * Task run during shutdown.
@@ -102,83 +426,1071 @@ static struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
102static void 426static void
103shutdown_task (void *cls) 427shutdown_task (void *cls)
104{ 428{
105 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "shutting down\n"); 429 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
106 430 "Shutting down\n");
107 shutting_down = GNUNET_YES; 431 shutting_down = GNUNET_YES;
432 GCO_shutdown ();
433 if (NULL == clients_head)
434 shutdown_rest ();
435}
108 436
109 GML_shutdown ();
110 GCH_shutdown ();
111 GCC_shutdown ();
112 GCT_shutdown ();
113 GCD_shutdown ();
114 GCP_shutdown ();
115 437
116 GNUNET_STATISTICS_destroy (stats, GNUNET_NO); 438/**
117 stats = NULL; 439 * We had a remote connection @a value to port @a port before
118 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "shut down\n"); 440 * client @a cls opened port @a port. Bind them now.
441 *
442 * @param cls the `struct CadetClient`
443 * @param port the port
444 * @param value the `struct CadetChannel`
445 * @return #GNUNET_YES (iterate over all such channels)
446 */
447static int
448bind_loose_channel (void *cls,
449 const struct GNUNET_HashCode *port,
450 void *value)
451{
452 struct CadetClient *c = cls;
453 struct CadetChannel *ch = value;
454
455 GCCH_bind (ch,
456 c);
457 GNUNET_assert (GNUNET_YES ==
458 GNUNET_CONTAINER_multihashmap_remove (loose_channels,
459 port,
460 value));
461 return GNUNET_YES;
119} 462}
120 463
121 464
122/** 465/**
123 * Process cadet requests. 466 * Handle port open request. Creates a mapping from the
467 * port to the respective client and checks whether we have
468 * loose channels trying to bind to the port. If so, those
469 * are bound.
124 * 470 *
125 * @param cls closure 471 * @param cls Identification of the client.
126 * @param server the initialized server 472 * @param pmsg The actual message.
127 * @param c configuration to use
128 */ 473 */
129static void 474static void
130run (void *cls, struct GNUNET_SERVER_Handle *server, 475handle_port_open (void *cls,
131 const struct GNUNET_CONFIGURATION_Handle *c) 476 const struct GNUNET_CADET_PortMessage *pmsg)
132{ 477{
133 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "starting to run\n"); 478 struct CadetClient *c = cls;
134 479
135 stats = GNUNET_STATISTICS_create ("cadet", c); 480 LOG (GNUNET_ERROR_TYPE_DEBUG,
481 "Open port %s requested by %s\n",
482 GNUNET_h2s (&pmsg->port),
483 GSC_2s (c));
484 if (NULL == c->ports)
485 c->ports = GNUNET_CONTAINER_multihashmap_create (4,
486 GNUNET_NO);
487 if (GNUNET_OK !=
488 GNUNET_CONTAINER_multihashmap_put (c->ports,
489 &pmsg->port,
490 c,
491 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
492 {
493 GNUNET_break (0);
494 GNUNET_SERVICE_client_drop (c->client);
495 return;
496 }
497 (void) GNUNET_CONTAINER_multihashmap_put (open_ports,
498 &pmsg->port,
499 c,
500 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
501 GNUNET_CONTAINER_multihashmap_get_multiple (loose_channels,
502 &pmsg->port,
503 &bind_loose_channel,
504 c);
505 GNUNET_SERVICE_client_continue (c->client);
506}
136 507
137 /* Scheduled the task to clean up when shutdown is called */
138 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
139 NULL);
140 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "reading key\n");
141 my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (c);
142 GNUNET_assert (NULL != my_private_key);
143 GNUNET_CRYPTO_eddsa_key_get_public (my_private_key, &my_full_id.public_key);
144 myid = GNUNET_PEER_intern (&my_full_id);
145 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
146 "STARTING SERVICE (cadet) for peer [%s]\n",
147 GNUNET_i2s (&my_full_id));
148 508
149 GML_init (server); /* Local clients */ 509/**
150 GCH_init (c); /* Hellos */ 510 * Handler for port close requests. Marks this port as closed
151 GCC_init (c); /* Connections */ 511 * (unless of course we have another client with the same port
152 GCP_init (c); /* Peers */ 512 * open). Note that existing channels accepted on the port are
153 GCD_init (c); /* DHT */ 513 * not affected.
154 GCT_init (c, my_private_key); /* Tunnels */ 514 *
515 * @param cls Identification of the client.
516 * @param pmsg The actual message.
517 */
518static void
519handle_port_close (void *cls,
520 const struct GNUNET_CADET_PortMessage *pmsg)
521{
522 struct CadetClient *c = cls;
155 523
156 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cadet service running\n"); 524 LOG (GNUNET_ERROR_TYPE_DEBUG,
525 "Closing port %s as requested by %s\n",
526 GNUNET_h2s (&pmsg->port),
527 GSC_2s (c));
528 if (GNUNET_YES !=
529 GNUNET_CONTAINER_multihashmap_remove (c->ports,
530 &pmsg->port,
531 c))
532 {
533 GNUNET_break (0);
534 GNUNET_SERVICE_client_drop (c->client);
535 return;
536 }
537 GNUNET_assert (GNUNET_YES ==
538 GNUNET_CONTAINER_multihashmap_remove (open_ports,
539 &pmsg->port,
540 c));
541 GNUNET_SERVICE_client_continue (c->client);
157} 542}
158 543
159 544
160/** 545/**
161 * The main function for the cadet service. 546 * Handler for requests for us creating a new channel to another peer and port.
162 * 547 *
163 * @param argc number of arguments from the command line 548 * @param cls Identification of the client.
164 * @param argv command line arguments 549 * @param tcm The actual message.
165 * @return 0 ok, 1 on error
166 */ 550 */
167int 551static void
168main (int argc, char *const *argv) 552handle_channel_create (void *cls,
553 const struct GNUNET_CADET_LocalChannelCreateMessage *tcm)
169{ 554{
170 int r; 555 struct CadetClient *c = cls;
556 struct CadetChannel *ch;
171 557
172 shutting_down = GNUNET_NO; 558 if (ntohl (tcm->ccn.channel_of_client) < GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
173 r = GNUNET_SERVICE_run (argc, argv, "cadet", GNUNET_SERVICE_OPTION_NONE, &run, 559 {
174 NULL); 560 /* Channel ID not in allowed range. */
175 GNUNET_free (my_private_key); 561 GNUNET_break (0);
562 GNUNET_SERVICE_client_drop (c->client);
563 return;
564 }
565 ch = lookup_channel (c,
566 tcm->ccn);
567 if (NULL != ch)
568 {
569 /* Channel ID already in use. Not allowed. */
570 GNUNET_break (0);
571 GNUNET_SERVICE_client_drop (c->client);
572 return;
573 }
574 LOG (GNUNET_ERROR_TYPE_DEBUG,
575 "New channel to %s at port %s requested by %s\n",
576 GNUNET_i2s (&tcm->peer),
577 GNUNET_h2s (&tcm->port),
578 GSC_2s (c));
176 579
177 if (GNUNET_OK != r) 580 /* Create channel */
581 ch = GCCH_channel_local_new (c,
582 tcm->ccn,
583 GCP_get (&tcm->peer,
584 GNUNET_YES),
585 &tcm->port,
586 ntohl (tcm->opt));
587 if (NULL == ch)
178 { 588 {
179 FPRINTF (stderr, "GNUNET_SERVICE_run for CADET has failed!\n"); 589 GNUNET_break (0);
180 return 1; 590 GNUNET_SERVICE_client_drop (c->client);
591 return;
181 } 592 }
593 GNUNET_assert (GNUNET_YES ==
594 GNUNET_CONTAINER_multihashmap32_put (c->channels,
595 ntohl (tcm->ccn.channel_of_client),
596 ch,
597 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
182 598
183 return 0; 599 GNUNET_SERVICE_client_continue (c->client);
184} 600}
601
602
603/**
604 * Handler for requests of destroying an existing channel.
605 *
606 * @param cls client identification of the client
607 * @param msg the actual message
608 */
609static void
610handle_channel_destroy (void *cls,
611 const struct GNUNET_CADET_LocalChannelDestroyMessage *msg)
612{
613 struct CadetClient *c = cls;
614 struct CadetChannel *ch;
615
616 ch = lookup_channel (c,
617 msg->ccn);
618 if (NULL == ch)
619 {
620 /* Client attempted to destroy unknown channel.
621 Can happen if the other side went down at the same time.*/
622 LOG (GNUNET_ERROR_TYPE_DEBUG,
623 "%s tried to destroy unknown channel %X\n",
624 GSC_2s(c),
625 (uint32_t) ntohl (msg->ccn.channel_of_client));
626 return;
627 }
628 LOG (GNUNET_ERROR_TYPE_DEBUG,
629 "%s is destroying %s\n",
630 GSC_2s(c),
631 GCCH_2s (ch));
632 GNUNET_assert (GNUNET_YES ==
633 GNUNET_CONTAINER_multihashmap32_remove (c->channels,
634 ntohl (msg->ccn.channel_of_client),
635 ch));
636 GCCH_channel_local_destroy (ch,
637 c,
638 msg->ccn);
639 GNUNET_SERVICE_client_continue (c->client);
640}
641
642
643/**
644 * Check for client traffic data message is well-formed.
645 *
646 * @param cls identification of the client
647 * @param msg the actual message
648 * @return #GNUNET_OK if @a msg is OK, #GNUNET_SYSERR if not
649 */
650static int
651check_local_data (void *cls,
652 const struct GNUNET_CADET_LocalData *msg)
653{
654 size_t payload_size;
655 size_t payload_claimed_size;
656 const char *buf;
657 struct GNUNET_MessageHeader pa;
658
659 /* FIXME: what is the format we shall allow for @a msg?
660 ONE payload item or multiple? Seems current cadet_api
661 at least in theory allows more than one. Next-gen
662 cadet_api will likely no more, so we could then
663 simplify this mess again. */
664 /* Sanity check for message size */
665 payload_size = ntohs (msg->header.size) - sizeof (*msg);
666 buf = (const char *) &msg[1];
667 while (payload_size >= sizeof (struct GNUNET_MessageHeader))
668 {
669 /* need to memcpy() for alignment */
670 GNUNET_memcpy (&pa,
671 buf,
672 sizeof (pa));
673 payload_claimed_size = ntohs (pa.size);
674 if ( (payload_size < payload_claimed_size) ||
675 (payload_claimed_size < sizeof (struct GNUNET_MessageHeader)) ||
676 (GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE < payload_claimed_size) )
677 {
678 GNUNET_break (0);
679 LOG (GNUNET_ERROR_TYPE_DEBUG,
680 "Local data of %u total size had sub-message %u at %u with %u bytes\n",
681 ntohs (msg->header.size),
682 ntohs (pa.type),
683 (unsigned int) (buf - (const char *) &msg[1]),
684 (unsigned int) payload_claimed_size);
685 return GNUNET_SYSERR;
686 }
687 payload_size -= payload_claimed_size;
688 buf += payload_claimed_size;
689 }
690 if (0 != payload_size)
691 {
692 GNUNET_break_op (0);
693 return GNUNET_SYSERR;
694 }
695 return GNUNET_OK;
696}
697
698
699/**
700 * Handler for client payload traffic to be send on a channel to
701 * another peer.
702 *
703 * @param cls identification of the client
704 * @param msg the actual message
705 */
706static void
707handle_local_data (void *cls,
708 const struct GNUNET_CADET_LocalData *msg)
709{
710 struct CadetClient *c = cls;
711 struct CadetChannel *ch;
712 size_t payload_size;
713 const char *buf;
714
715 ch = lookup_channel (c,
716 msg->ccn);
717 if (NULL == ch)
718 {
719 /* Channel does not exist (anymore) */
720 LOG (GNUNET_ERROR_TYPE_WARNING,
721 "Dropping payload for channel %u from client (channel unknown, other endpoint may have disconnected)\n",
722 (unsigned int) ntohl (msg->ccn.channel_of_client));
723 GNUNET_SERVICE_client_continue (c->client);
724 return;
725 }
726 payload_size = ntohs (msg->header.size) - sizeof (*msg);
727 GNUNET_STATISTICS_update (stats,
728 "# payload received from clients",
729 payload_size,
730 GNUNET_NO);
731 buf = (const char *) &msg[1];
732 LOG (GNUNET_ERROR_TYPE_DEBUG,
733 "Received %u bytes payload from %s for %s\n",
734 (unsigned int) payload_size,
735 GSC_2s (c),
736 GCCH_2s (ch));
737 if (GNUNET_OK !=
738 GCCH_handle_local_data (ch,
739 msg->ccn,
740 buf,
741 payload_size))
742 {
743 GNUNET_SERVICE_client_drop (c->client);
744 return;
745 }
746 GNUNET_SERVICE_client_continue (c->client);
747}
748
749
750/**
751 * Handler for client's ACKs for payload traffic.
752 *
753 * @param cls identification of the client.
754 * @param msg The actual message.
755 */
756static void
757handle_local_ack (void *cls,
758 const struct GNUNET_CADET_LocalAck *msg)
759{
760 struct CadetClient *c = cls;
761 struct CadetChannel *ch;
762
763 ch = lookup_channel (c,
764 msg->ccn);
765 if (NULL == ch)
766 {
767 /* Channel does not exist (anymore) */
768 LOG (GNUNET_ERROR_TYPE_WARNING,
769 "Ignoring local ACK for channel %u from client (channel unknown, other endpoint may have disconnected)\n",
770 (unsigned int) ntohl (msg->ccn.channel_of_client));
771 GNUNET_SERVICE_client_continue (c->client);
772 return;
773 }
774 LOG (GNUNET_ERROR_TYPE_DEBUG,
775 "Got a local ACK from %s for %s\n",
776 GSC_2s(c),
777 GCCH_2s (ch));
778 GCCH_handle_local_ack (ch,
779 msg->ccn);
780 GNUNET_SERVICE_client_continue (c->client);
781}
782
783
784/**
785 * Iterator over all peers to send a monitoring client info about each peer.
786 *
787 * @param cls Closure ().
788 * @param peer Peer ID (tunnel remote peer).
789 * @param value Peer info.
790 * @return #GNUNET_YES, to keep iterating.
791 */
792static int
793get_all_peers_iterator (void *cls,
794 const struct GNUNET_PeerIdentity *peer,
795 void *value)
796{
797 struct CadetClient *c = cls;
798 struct CadetPeer *p = value;
799 struct GNUNET_MQ_Envelope *env;
800 struct GNUNET_CADET_LocalInfoPeer *msg;
801
802 env = GNUNET_MQ_msg (msg,
803 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS);
804 msg->destination = *peer;
805 msg->paths = htons (GCP_count_paths (p));
806 msg->tunnel = htons (NULL != GCP_get_tunnel (p,
807 GNUNET_NO));
808 GNUNET_MQ_send (c->mq,
809 env);
810 return GNUNET_YES;
811}
812
813
814/**
815 * Handler for client's INFO PEERS request.
816 *
817 * @param cls Identification of the client.
818 * @param message The actual message.
819 */
820static void
821handle_get_peers (void *cls,
822 const struct GNUNET_MessageHeader *message)
823{
824 struct CadetClient *c = cls;
825 struct GNUNET_MQ_Envelope *env;
826 struct GNUNET_MessageHeader *reply;
827
828 GCP_iterate_all (&get_all_peers_iterator,
829 c);
830 env = GNUNET_MQ_msg (reply,
831 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS);
832 GNUNET_MQ_send (c->mq,
833 env);
834 GNUNET_SERVICE_client_continue (c->client);
835}
836
837
838/**
839 * Iterator over all paths of a peer to build an InfoPeer message.
840 * Message contains blocks of peers, first not included.
841 *
842 * @param cls message queue for transmission
843 * @param path Path itself
844 * @param off offset of the peer on @a path
845 * @return #GNUNET_YES if should keep iterating.
846 * #GNUNET_NO otherwise.
847 */
848static int
849path_info_iterator (void *cls,
850 struct CadetPeerPath *path,
851 unsigned int off)
852{
853 struct GNUNET_MQ_Handle *mq = cls;
854 struct GNUNET_MQ_Envelope *env;
855 struct GNUNET_MessageHeader *resp;
856 struct GNUNET_PeerIdentity *id;
857 uint16_t path_size;
858 unsigned int i;
859 unsigned int path_length;
860
861 path_length = GCPP_get_length (path);
862 path_size = sizeof (struct GNUNET_PeerIdentity) * (path_length - 1);
863 if (sizeof (*resp) + path_size > UINT16_MAX)
864 {
865 LOG (GNUNET_ERROR_TYPE_WARNING,
866 "Path of %u entries is too long for info message\n",
867 path_length);
868 return GNUNET_YES;
869 }
870 env = GNUNET_MQ_msg_extra (resp,
871 path_size,
872 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER);
873 id = (struct GNUNET_PeerIdentity *) &resp[1];
874
875 /* Don't copy first peer. First peer is always the local one. Last
876 * peer is always the destination (leave as 0, EOL).
877 */
878 for (i = 0; i < off; i++)
879 id[i] = *GCP_get_id (GCPP_get_peer_at_offset (path,
880 i + 1));
881 GNUNET_MQ_send (mq,
882 env);
883 return GNUNET_YES;
884}
885
886
887/**
888 * Handler for client's SHOW_PEER request.
889 *
890 * @param cls Identification of the client.
891 * @param msg The actual message.
892 */
893static void
894handle_show_peer (void *cls,
895 const struct GNUNET_CADET_LocalInfo *msg)
896{
897 struct CadetClient *c = cls;
898 struct CadetPeer *p;
899 struct GNUNET_MQ_Envelope *env;
900 struct GNUNET_MessageHeader *resp;
901
902 p = GCP_get (&msg->peer,
903 GNUNET_NO);
904 if (NULL != p)
905 GCP_iterate_paths (p,
906 &path_info_iterator,
907 c->mq);
908 /* Send message with 0/0 to indicate the end */
909 env = GNUNET_MQ_msg (resp,
910 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER_END);
911 GNUNET_MQ_send (c->mq,
912 env);
913 GNUNET_SERVICE_client_continue (c->client);
914}
915
916
917/**
918 * Iterator over all tunnels to send a monitoring client info about each tunnel.
919 *
920 * @param cls Closure ().
921 * @param peer Peer ID (tunnel remote peer).
922 * @param value a `struct CadetPeer`
923 * @return #GNUNET_YES, to keep iterating.
924 */
925static int
926get_all_tunnels_iterator (void *cls,
927 const struct GNUNET_PeerIdentity *peer,
928 void *value)
929{
930 struct CadetClient *c = cls;
931 struct CadetPeer *p = value;
932 struct GNUNET_MQ_Envelope *env;
933 struct GNUNET_CADET_LocalInfoTunnel *msg;
934 struct CadetTunnel *t;
935
936 t = GCP_get_tunnel (p,
937 GNUNET_NO);
938 if (NULL == t)
939 return GNUNET_YES;
940 env = GNUNET_MQ_msg (msg,
941 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS);
942 msg->destination = *peer;
943 msg->channels = htonl (GCT_count_channels (t));
944 msg->connections = htonl (GCT_count_any_connections (t));
945 msg->cstate = htons (0);
946 msg->estate = htons ((uint16_t) GCT_get_estate (t));
947 GNUNET_MQ_send (c->mq,
948 env);
949 return GNUNET_YES;
950}
951
952
953/**
954 * Handler for client's #GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS request.
955 *
956 * @param cls client Identification of the client.
957 * @param message The actual message.
958 */
959static void
960handle_info_tunnels (void *cls,
961 const struct GNUNET_MessageHeader *message)
962{
963 struct CadetClient *c = cls;
964 struct GNUNET_MQ_Envelope *env;
965 struct GNUNET_MessageHeader *reply;
966
967 GCP_iterate_all (&get_all_tunnels_iterator,
968 c);
969 env = GNUNET_MQ_msg (reply,
970 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS);
971 GNUNET_MQ_send (c->mq,
972 env);
973 GNUNET_SERVICE_client_continue (c->client);
974}
975
976
977/**
978 * Update the message with information about the connection.
979 *
980 * @param cls a `struct GNUNET_CADET_LocalInfoTunnel` message to update
981 * @param ct a connection about which we should store information in @a cls
982 */
983static void
984iter_connection (void *cls,
985 struct CadetTConnection *ct)
986{
987 struct GNUNET_CADET_LocalInfoTunnel *msg = cls;
988 struct CadetConnection *cc = ct->cc;
989 struct GNUNET_CADET_ConnectionTunnelIdentifier *h;
990
991 h = (struct GNUNET_CADET_ConnectionTunnelIdentifier *) &msg[1];
992 h[msg->connections++] = *(GCC_get_id (cc));
993}
994
995
996/**
997 * Update the message with information about the channel.
998 *
999 * @param cls a `struct GNUNET_CADET_LocalInfoTunnel` message to update
1000 * @param ch a channel about which we should store information in @a cls
1001 */
1002static void
1003iter_channel (void *cls,
1004 struct CadetChannel *ch)
1005{
1006 struct GNUNET_CADET_LocalInfoTunnel *msg = cls;
1007 struct GNUNET_CADET_ConnectionTunnelIdentifier *h = (struct GNUNET_CADET_ConnectionTunnelIdentifier *) &msg[1];
1008 struct GNUNET_CADET_ChannelTunnelNumber *chn
1009 = (struct GNUNET_CADET_ChannelTunnelNumber *) &h[msg->connections];
1010
1011 chn[msg->channels++] = GCCH_get_id (ch);
1012}
1013
1014
1015/**
1016 * Handler for client's #GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL request.
1017 *
1018 * @param cls Identification of the client.
1019 * @param msg The actual message.
1020 */
1021static void
1022handle_info_tunnel (void *cls,
1023 const struct GNUNET_CADET_LocalInfo *msg)
1024{
1025 struct CadetClient *c = cls;
1026 struct GNUNET_MQ_Envelope *env;
1027 struct GNUNET_CADET_LocalInfoTunnel *resp;
1028 struct CadetTunnel *t;
1029 struct CadetPeer *p;
1030 unsigned int ch_n;
1031 unsigned int c_n;
1032
1033 p = GCP_get (&msg->peer,
1034 GNUNET_NO);
1035 t = GCP_get_tunnel (p,
1036 GNUNET_NO);
1037 if (NULL == t)
1038 {
1039 /* We don't know the tunnel */
1040 struct GNUNET_MQ_Envelope *env;
1041 struct GNUNET_CADET_LocalInfoTunnel *warn;
1042
1043 LOG (GNUNET_ERROR_TYPE_INFO,
1044 "Tunnel to %s unknown\n",
1045 GNUNET_i2s_full (&msg->peer));
1046 env = GNUNET_MQ_msg (warn,
1047 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL);
1048 warn->destination = msg->peer;
1049 GNUNET_MQ_send (c->mq,
1050 env);
1051 GNUNET_SERVICE_client_continue (c->client);
1052 return;
1053 }
1054
1055 /* Initialize context */
1056 ch_n = GCT_count_channels (t);
1057 c_n = GCT_count_any_connections (t);
1058 env = GNUNET_MQ_msg_extra (resp,
1059 c_n * sizeof (struct GNUNET_CADET_ConnectionTunnelIdentifier) +
1060 ch_n * sizeof (struct GNUNET_CADET_ChannelTunnelNumber),
1061 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL);
1062 resp->destination = msg->peer;
1063 /* Do not reorder! #iter_channel needs counters in HBO! */
1064 GCT_iterate_connections (t,
1065 &iter_connection,
1066 resp);
1067 GCT_iterate_channels (t,
1068 &iter_channel,
1069 resp);
1070 resp->connections = htonl (resp->connections);
1071 resp->channels = htonl (resp->channels);
1072 resp->cstate = htons (0);
1073 resp->estate = htons (GCT_get_estate (t));
1074 GNUNET_MQ_send (c->mq,
1075 env);
1076 GNUNET_SERVICE_client_continue (c->client);
1077}
1078
1079
1080/**
1081 * Iterator over all peers to dump info for each peer.
1082 *
1083 * @param cls Closure (unused).
1084 * @param peer Peer ID (tunnel remote peer).
1085 * @param value Peer info.
1086 *
1087 * @return #GNUNET_YES, to keep iterating.
1088 */
1089static int
1090show_peer_iterator (void *cls,
1091 const struct GNUNET_PeerIdentity *peer,
1092 void *value)
1093{
1094 struct CadetPeer *p = value;
1095 struct CadetTunnel *t;
1096
1097 t = GCP_get_tunnel (p,
1098 GNUNET_NO);
1099 if (NULL != t)
1100 GCT_debug (t,
1101 GNUNET_ERROR_TYPE_ERROR);
1102 LOG (GNUNET_ERROR_TYPE_ERROR, "\n");
1103 return GNUNET_YES;
1104}
1105
1106
1107/**
1108 * Handler for client's INFO_DUMP request.
1109 *
1110 * @param cls Identification of the client.
1111 * @param message The actual message.
1112 */
1113static void
1114handle_info_dump (void *cls,
1115 const struct GNUNET_MessageHeader *message)
1116{
1117 struct CadetClient *c = cls;
1118
1119 LOG (GNUNET_ERROR_TYPE_INFO,
1120 "Received dump info request from client %u\n",
1121 c->id);
1122
1123 LOG (GNUNET_ERROR_TYPE_ERROR,
1124 "*************************** DUMP START ***************************\n");
1125 for (struct CadetClient *ci = clients_head;
1126 NULL != ci;
1127 ci = ci->next)
1128 {
1129 LOG (GNUNET_ERROR_TYPE_ERROR,
1130 "Client %u (%p), handle: %p, ports: %u, channels: %u\n",
1131 ci->id,
1132 ci,
1133 ci->client,
1134 (NULL != c->ports)
1135 ? GNUNET_CONTAINER_multihashmap_size (ci->ports)
1136 : 0,
1137 GNUNET_CONTAINER_multihashmap32_size (ci->channels));
1138 }
1139 LOG (GNUNET_ERROR_TYPE_ERROR, "***************************\n");
1140 GCP_iterate_all (&show_peer_iterator,
1141 NULL);
1142
1143 LOG (GNUNET_ERROR_TYPE_ERROR,
1144 "**************************** DUMP END ****************************\n");
1145
1146 GNUNET_SERVICE_client_continue (c->client);
1147}
1148
1149
1150
1151/**
1152 * Callback called when a client connects to the service.
1153 *
1154 * @param cls closure for the service
1155 * @param client the new client that connected to the service
1156 * @param mq the message queue used to send messages to the client
1157 * @return @a c
1158 */
1159static void *
1160client_connect_cb (void *cls,
1161 struct GNUNET_SERVICE_Client *client,
1162 struct GNUNET_MQ_Handle *mq)
1163{
1164 struct CadetClient *c;
1165
1166 c = GNUNET_new (struct CadetClient);
1167 c->client = client;
1168 c->mq = mq;
1169 c->id = next_client_id++; /* overflow not important: just for debug */
1170 c->channels
1171 = GNUNET_CONTAINER_multihashmap32_create (32);
1172 GNUNET_CONTAINER_DLL_insert (clients_head,
1173 clients_tail,
1174 c);
1175 GNUNET_STATISTICS_update (stats,
1176 "# clients",
1177 +1,
1178 GNUNET_NO);
1179 LOG (GNUNET_ERROR_TYPE_DEBUG,
1180 "%s connected\n",
1181 GSC_2s (c));
1182 return c;
1183}
1184
1185
1186/**
1187 * A channel was destroyed by the other peer. Tell our client.
1188 *
1189 * @param c client that lost a channel
1190 * @param ccn channel identification number for the client
1191 * @param ch the channel object
1192 */
1193void
1194GSC_handle_remote_channel_destroy (struct CadetClient *c,
1195 struct GNUNET_CADET_ClientChannelNumber ccn,
1196 struct CadetChannel *ch)
1197{
1198 struct GNUNET_MQ_Envelope *env;
1199 struct GNUNET_CADET_LocalChannelDestroyMessage *tdm;
1200
1201 env = GNUNET_MQ_msg (tdm,
1202 GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY);
1203 tdm->ccn = ccn;
1204 GSC_send_to_client (c,
1205 env);
1206 GNUNET_assert (GNUNET_YES ==
1207 GNUNET_CONTAINER_multihashmap32_remove (c->channels,
1208 ntohl (ccn.channel_of_client),
1209 ch));
1210}
1211
1212
1213/**
1214 * A client that created a loose channel that was not bound to a port
1215 * disconnected, drop it from the #loose_channels list.
1216 *
1217 * @param port the port the channel was trying to bind to
1218 * @param ch the channel that was lost
1219 */
1220void
1221GSC_drop_loose_channel (const struct GNUNET_HashCode *port,
1222 struct CadetChannel *ch)
1223{
1224 GNUNET_assert (GNUNET_YES ==
1225 GNUNET_CONTAINER_multihashmap_remove (loose_channels,
1226 port,
1227 ch));
1228}
1229
1230
1231/**
1232 * Iterator for deleting each channel whose client endpoint disconnected.
1233 *
1234 * @param cls Closure (client that has disconnected).
1235 * @param key The local channel id in host byte order
1236 * @param value The value stored at the key (channel to destroy).
1237 * @return #GNUNET_OK, keep iterating.
1238 */
1239static int
1240channel_destroy_iterator (void *cls,
1241 uint32_t key,
1242 void *value)
1243{
1244 struct CadetClient *c = cls;
1245 struct GNUNET_CADET_ClientChannelNumber ccn;
1246 struct CadetChannel *ch = value;
1247
1248 LOG (GNUNET_ERROR_TYPE_DEBUG,
1249 "Destroying %s, due to %s disconnecting.\n",
1250 GCCH_2s (ch),
1251 GSC_2s (c));
1252 ccn.channel_of_client = htonl (key);
1253 GCCH_channel_local_destroy (ch,
1254 c,
1255 ccn);
1256 GNUNET_assert (GNUNET_YES ==
1257 GNUNET_CONTAINER_multihashmap32_remove (c->channels,
1258 key,
1259 ch));
1260 return GNUNET_OK;
1261}
1262
1263
1264/**
1265 * Remove client's ports from the global hashmap on disconnect.
1266 *
1267 * @param cls Closure (unused).
1268 * @param key the port.
1269 * @param value the `struct CadetClient` to remove
1270 * @return #GNUNET_OK, keep iterating.
1271 */
1272static int
1273client_release_ports (void *cls,
1274 const struct GNUNET_HashCode *key,
1275 void *value)
1276{
1277 struct CadetClient *c = value;
1278
1279 LOG (GNUNET_ERROR_TYPE_DEBUG,
1280 "Closing port %s due to %s disconnect.\n",
1281 GNUNET_h2s (key),
1282 GSC_2s (c));
1283 GNUNET_assert (GNUNET_YES ==
1284 GNUNET_CONTAINER_multihashmap_remove (open_ports,
1285 key,
1286 value));
1287 GNUNET_assert (GNUNET_YES ==
1288 GNUNET_CONTAINER_multihashmap_remove (c->ports,
1289 key,
1290 value));
1291 return GNUNET_OK;
1292}
1293
1294
1295/**
1296 * Callback called when a client disconnected from the service
1297 *
1298 * @param cls closure for the service
1299 * @param client the client that disconnected
1300 * @param internal_cls should be equal to @a c
1301 */
1302static void
1303client_disconnect_cb (void *cls,
1304 struct GNUNET_SERVICE_Client *client,
1305 void *internal_cls)
1306{
1307 struct CadetClient *c = internal_cls;
1308
1309 GNUNET_assert (c->client == client);
1310 LOG (GNUNET_ERROR_TYPE_DEBUG,
1311 "%s is disconnecting.\n",
1312 GSC_2s (c));
1313 if (NULL != c->channels)
1314 {
1315 GNUNET_CONTAINER_multihashmap32_iterate (c->channels,
1316 &channel_destroy_iterator,
1317 c);
1318 GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap32_size (c->channels));
1319 GNUNET_CONTAINER_multihashmap32_destroy (c->channels);
1320 }
1321 if (NULL != c->ports)
1322 {
1323 GNUNET_CONTAINER_multihashmap_iterate (c->ports,
1324 &client_release_ports,
1325 c);
1326 GNUNET_CONTAINER_multihashmap_destroy (c->ports);
1327 }
1328 GNUNET_CONTAINER_DLL_remove (clients_head,
1329 clients_tail,
1330 c);
1331 GNUNET_STATISTICS_update (stats,
1332 "# clients",
1333 -1,
1334 GNUNET_NO);
1335 GNUNET_free (c);
1336 if ( (NULL == clients_head) &&
1337 (GNUNET_YES == shutting_down) )
1338 shutdown_rest ();
1339}
1340
1341
1342/**
1343 * Setup CADET internals.
1344 *
1345 * @param cls closure
1346 * @param server the initialized server
1347 * @param c configuration to use
1348 */
1349static void
1350run (void *cls,
1351 const struct GNUNET_CONFIGURATION_Handle *c,
1352 struct GNUNET_SERVICE_Handle *service)
1353{
1354 cfg = c;
1355 if (GNUNET_OK !=
1356 GNUNET_CONFIGURATION_get_value_number (c,
1357 "CADET",
1358 "RATCHET_MESSAGES",
1359 &ratchet_messages))
1360 {
1361 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
1362 "CADET",
1363 "RATCHET_MESSAGES",
1364 "needs to be a number");
1365 ratchet_messages = 64;
1366 }
1367 if (GNUNET_OK !=
1368 GNUNET_CONFIGURATION_get_value_time (c,
1369 "CADET",
1370 "RATCHET_TIME",
1371 &ratchet_time))
1372 {
1373 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
1374 "CADET",
1375 "RATCHET_TIME",
1376 "need delay value");
1377 ratchet_time = GNUNET_TIME_UNIT_HOURS;
1378 }
1379 if (GNUNET_OK !=
1380 GNUNET_CONFIGURATION_get_value_time (c,
1381 "CADET",
1382 "REFRESH_CONNECTION_TIME",
1383 &keepalive_period))
1384 {
1385 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
1386 "CADET",
1387 "REFRESH_CONNECTION_TIME",
1388 "need delay value");
1389 keepalive_period = GNUNET_TIME_UNIT_MINUTES;
1390 }
1391 if (GNUNET_OK !=
1392 GNUNET_CONFIGURATION_get_value_number (c,
1393 "CADET",
1394 "DROP_PERCENT",
1395 &drop_percent))
1396 {
1397 drop_percent = 0;
1398 }
1399 else
1400 {
1401 LOG (GNUNET_ERROR_TYPE_WARNING, "**************************************\n");
1402 LOG (GNUNET_ERROR_TYPE_WARNING, "Cadet is running with DROP enabled.\n");
1403 LOG (GNUNET_ERROR_TYPE_WARNING, "This is NOT a good idea!\n");
1404 LOG (GNUNET_ERROR_TYPE_WARNING, "Remove DROP_PERCENT from config file.\n");
1405 LOG (GNUNET_ERROR_TYPE_WARNING, "**************************************\n");
1406 }
1407 my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (c);
1408 if (NULL == my_private_key)
1409 {
1410 GNUNET_break (0);
1411 GNUNET_SCHEDULER_shutdown ();
1412 return;
1413 }
1414 GNUNET_CRYPTO_eddsa_key_get_public (my_private_key,
1415 &my_full_id.public_key);
1416 stats = GNUNET_STATISTICS_create ("cadet",
1417 c);
1418 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1419 NULL);
1420 ats_ch = GNUNET_ATS_connectivity_init (c);
1421 /* FIXME: optimize code to allow GNUNET_YES here! */
1422 open_ports = GNUNET_CONTAINER_multihashmap_create (16,
1423 GNUNET_NO);
1424 loose_channels = GNUNET_CONTAINER_multihashmap_create (16,
1425 GNUNET_NO);
1426 peers = GNUNET_CONTAINER_multipeermap_create (16,
1427 GNUNET_YES);
1428 connections = GNUNET_CONTAINER_multishortmap_create (256,
1429 GNUNET_YES);
1430 GCH_init (c);
1431 GCD_init (c);
1432 GCO_init (c);
1433 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1434 "CADET started for peer %s\n",
1435 GNUNET_i2s (&my_full_id));
1436
1437}
1438
1439
1440/**
1441 * Define "main" method using service macro.
1442 */
1443GNUNET_SERVICE_MAIN
1444("cadet",
1445 GNUNET_SERVICE_OPTION_NONE,
1446 &run,
1447 &client_connect_cb,
1448 &client_disconnect_cb,
1449 NULL,
1450 GNUNET_MQ_hd_fixed_size (port_open,
1451 GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_OPEN,
1452 struct GNUNET_CADET_PortMessage,
1453 NULL),
1454 GNUNET_MQ_hd_fixed_size (port_close,
1455 GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_CLOSE,
1456 struct GNUNET_CADET_PortMessage,
1457 NULL),
1458 GNUNET_MQ_hd_fixed_size (channel_create,
1459 GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_CREATE,
1460 struct GNUNET_CADET_LocalChannelCreateMessage,
1461 NULL),
1462 GNUNET_MQ_hd_fixed_size (channel_destroy,
1463 GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY,
1464 struct GNUNET_CADET_LocalChannelDestroyMessage,
1465 NULL),
1466 GNUNET_MQ_hd_var_size (local_data,
1467 GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA,
1468 struct GNUNET_CADET_LocalData,
1469 NULL),
1470 GNUNET_MQ_hd_fixed_size (local_ack,
1471 GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK,
1472 struct GNUNET_CADET_LocalAck,
1473 NULL),
1474 GNUNET_MQ_hd_fixed_size (get_peers,
1475 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS,
1476 struct GNUNET_MessageHeader,
1477 NULL),
1478 GNUNET_MQ_hd_fixed_size (show_peer,
1479 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER,
1480 struct GNUNET_CADET_LocalInfo,
1481 NULL),
1482 GNUNET_MQ_hd_fixed_size (info_tunnels,
1483 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS,
1484 struct GNUNET_MessageHeader,
1485 NULL),
1486 GNUNET_MQ_hd_fixed_size (info_tunnel,
1487 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL,
1488 struct GNUNET_CADET_LocalInfo,
1489 NULL),
1490 GNUNET_MQ_hd_fixed_size (info_dump,
1491 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_DUMP,
1492 struct GNUNET_MessageHeader,
1493 NULL),
1494 GNUNET_MQ_handler_end ());
1495
1496/* end of gnunet-service-cadet-new.c */
diff --git a/src/cadet/gnunet-service-cadet-new.h b/src/cadet/gnunet-service-cadet.h
index bee5c67cc..2f2d7baf3 100644
--- a/src/cadet/gnunet-service-cadet-new.h
+++ b/src/cadet/gnunet-service-cadet.h
@@ -20,7 +20,7 @@
20*/ 20*/
21 21
22/** 22/**
23 * @file cadet/gnunet-service-cadet-new.h 23 * @file cadet/gnunet-service-cadet.h
24 * @brief Information we track per peer. 24 * @brief Information we track per peer.
25 * @author Bartlomiej Polot 25 * @author Bartlomiej Polot
26 * @author Christian Grothoff 26 * @author Christian Grothoff
diff --git a/src/cadet/gnunet-service-cadet_channel.c b/src/cadet/gnunet-service-cadet_channel.c
index 7b7c6e57c..68e29b66b 100644
--- a/src/cadet/gnunet-service-cadet_channel.c
+++ b/src/cadet/gnunet-service-cadet_channel.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 Copyright (C) 2013 GNUnet e.V. 3 Copyright (C) 2001-2017 GNUnet e.V.
4 4
5 GNUnet is free software; you can redistribute it and/or modify 5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published 6 it under the terms of the GNU General Public License as published
@@ -17,31 +17,63 @@
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA. 18 Boston, MA 02110-1301, USA.
19*/ 19*/
20 20/**
21 21 * @file cadet/gnunet-service-cadet_channel.c
22 * @brief logical links between CADET clients
23 * @author Bartlomiej Polot
24 * @author Christian Grothoff
25 *
26 * TODO:
27 * - Congestion/flow control:
28 * + estimate max bandwidth using bursts and use to for CONGESTION CONTROL!
29 * (and figure out how/where to use this!)
30 * + figure out flow control without ACKs (unreliable traffic!)
31 * - revisit handling of 'unbuffered' traffic!
32 * (need to push down through tunnel into connection selection)
33 * - revisit handling of 'buffered' traffic: 4 is a rather small buffer; maybe
34 * reserve more bits in 'options' to allow for buffer size control?
35 */
22#include "platform.h" 36#include "platform.h"
23#include "gnunet_util_lib.h" 37#include "cadet.h"
24
25#include "gnunet_statistics_service.h" 38#include "gnunet_statistics_service.h"
39#include "gnunet-service-cadet_channel.h"
40#include "gnunet-service-cadet_connection.h"
41#include "gnunet-service-cadet_tunnels.h"
42#include "gnunet-service-cadet_paths.h"
26 43
27#include "cadet.h" 44#define LOG(level,...) GNUNET_log_from (level,"cadet-chn",__VA_ARGS__)
28#include "cadet_protocol.h"
29 45
30#include "gnunet-service-cadet_channel.h" 46/**
31#include "gnunet-service-cadet_local.h" 47 * How long do we initially wait before retransmitting?
32#include "gnunet-service-cadet_tunnel.h" 48 */
33#include "gnunet-service-cadet_peer.h" 49#define CADET_INITIAL_RETRANSMIT_TIME GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 250)
34 50
35#define LOG(level, ...) GNUNET_log_from(level,"cadet-chn",__VA_ARGS__) 51/**
36#define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-chn",__VA_ARGS__) 52 * How long do we wait before dropping state about incoming
53 * connection to closed port?
54 */
55#define TIMEOUT_CLOSED_PORT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30)
37 56
38#define CADET_RETRANSMIT_TIME GNUNET_TIME_relative_multiply(\ 57/**
39 GNUNET_TIME_UNIT_MILLISECONDS, 250) 58 * How long do we wait at least before retransmitting ever?
40#define CADET_RETRANSMIT_MARGIN 4 59 */
60#define MIN_RTT_DELAY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 75)
61
62/**
63 * Maximum message ID into the future we accept for out-of-order messages.
64 * If the message is more than this into the future, we drop it. This is
65 * important both to detect values that are actually in the past, as well
66 * as to limit adversarially triggerable memory consumption.
67 *
68 * Note that right now we have "max_pending_messages = 4" hard-coded in
69 * the logic below, so a value of 4 would suffice here. But we plan to
70 * allow larger windows in the future...
71 */
72#define MAX_OUT_OF_ORDER_DISTANCE 1024
41 73
42 74
43/** 75/**
44 * All the states a connection can be in. 76 * All the states a channel can be in.
45 */ 77 */
46enum CadetChannelState 78enum CadetChannelState
47{ 79{
@@ -51,9 +83,15 @@ enum CadetChannelState
51 CADET_CHANNEL_NEW, 83 CADET_CHANNEL_NEW,
52 84
53 /** 85 /**
54 * Connection create message sent, waiting for ACK. 86 * Channel is to a port that is not open, we're waiting for the
87 * port to be opened.
88 */
89 CADET_CHANNEL_LOOSE,
90
91 /**
92 * CHANNEL_OPEN message sent, waiting for CHANNEL_OPEN_ACK.
55 */ 93 */
56 CADET_CHANNEL_SENT, 94 CADET_CHANNEL_OPEN_SENT,
57 95
58 /** 96 /**
59 * Connection confirmed, ready to carry traffic. 97 * Connection confirmed, ready to carry traffic.
@@ -63,138 +101,144 @@ enum CadetChannelState
63 101
64 102
65/** 103/**
66 * Info holder for channel messages in queues. 104 * Info needed to retry a message in case it gets lost.
105 * Note that we DO use this structure also for unreliable
106 * messages.
67 */ 107 */
68struct CadetChannelQueue 108struct CadetReliableMessage
69{ 109{
70 /** 110 /**
71 * Tunnel Queue. 111 * Double linked list, FIFO style
72 */ 112 */
73 struct CadetTunnelQueue *tq; 113 struct CadetReliableMessage *next;
74 114
75 /** 115 /**
76 * Message type (DATA/DATA_ACK) 116 * Double linked list, FIFO style
77 */ 117 */
78 uint16_t type; 118 struct CadetReliableMessage *prev;
79 119
80 /** 120 /**
81 * Message copy (for DATAs, to start retransmission timer) 121 * Which channel is this message in?
82 */ 122 */
83 struct CadetReliableMessage *copy; 123 struct CadetChannel *ch;
84 124
85 /** 125 /**
86 * Reliability (for DATA_ACKs, to access rel->ack_q) 126 * Entry in the tunnels queue for this message, NULL if it has left
127 * the tunnel. Used to cancel transmission in case we receive an
128 * ACK in time.
87 */ 129 */
88 struct CadetChannelReliability *rel; 130 struct CadetTunnelQueueEntry *qe;
89};
90
91 131
92/**
93 * Info needed to retry a message in case it gets lost.
94 */
95struct CadetReliableMessage
96{
97 /** 132 /**
98 * Double linked list, FIFO style 133 * Data message we are trying to send.
99 */ 134 */
100 struct CadetReliableMessage *next; 135 struct GNUNET_CADET_ChannelAppDataMessage *data_message;
101 struct CadetReliableMessage *prev;
102 136
103 /** 137 /**
104 * Type of message (payload, channel management). 138 * How soon should we retry if we fail to get an ACK?
139 * Messages in the queue are sorted by this value.
105 */ 140 */
106 int16_t type; 141 struct GNUNET_TIME_Absolute next_retry;
107 142
108 /** 143 /**
109 * Tunnel Reliability queue this message is in. 144 * How long do we wait for an ACK after transmission?
145 * Use for the back-off calculation.
110 */ 146 */
111 struct CadetChannelReliability *rel; 147 struct GNUNET_TIME_Relative retry_delay;
112 148
113 /** 149 /**
114 * ID of the message (ACK needed to free) 150 * Time when we first successfully transmitted the message
151 * (that is, set @e num_transmissions to 1).
115 */ 152 */
116 uint32_t mid; 153 struct GNUNET_TIME_Absolute first_transmission_time;
117 154
118 /** 155 /**
119 * Tunnel Queue. 156 * Identifier of the connection that this message took when it
157 * was first transmitted. Only useful if @e num_transmissions is 1.
120 */ 158 */
121 struct CadetChannelQueue *chq; 159 struct GNUNET_CADET_ConnectionTunnelIdentifier connection_taken;
122 160
123 /** 161 /**
124 * When was this message issued (to calculate ACK delay) 162 * How often was this message transmitted? #GNUNET_SYSERR if there
163 * was an error transmitting the message, #GNUNET_NO if it was not
164 * yet transmitted ever, otherwise the number of (re) transmissions.
125 */ 165 */
126 struct GNUNET_TIME_Absolute timestamp; 166 int num_transmissions;
127 167
128 /* struct GNUNET_CADET_ChannelAppDataMessage with payload */
129}; 168};
130 169
131 170
132/** 171/**
133 * Info about the traffic state for a client in a channel. 172 * List of received out-of-order data messages.
134 */ 173 */
135struct CadetChannelReliability 174struct CadetOutOfOrderMessage
136{ 175{
137 /** 176 /**
138 * Channel this is about. 177 * Double linked list, FIFO style
139 */ 178 */
140 struct CadetChannel *ch; 179 struct CadetOutOfOrderMessage *next;
141 180
142 /** 181 /**
143 * DLL of messages sent and not yet ACK'd. 182 * Double linked list, FIFO style
144 */ 183 */
145 struct CadetReliableMessage *head_sent; 184 struct CadetOutOfOrderMessage *prev;
146 struct CadetReliableMessage *tail_sent;
147 185
148 /** 186 /**
149 * DLL of messages received out of order. 187 * ID of the message (messages up to this point needed
188 * before we give this one to the client).
150 */ 189 */
151 struct CadetReliableMessage *head_recv; 190 struct ChannelMessageIdentifier mid;
152 struct CadetReliableMessage *tail_recv;
153 191
154 /** 192 /**
155 * Messages received. 193 * The envelope with the payload of the out-of-order message
156 */ 194 */
157 unsigned int n_recv; 195 struct GNUNET_MQ_Envelope *env;
158 196
159 /** 197};
160 * Next MID to use for outgoing traffic.
161 */
162 uint32_t mid_send;
163 198
164 /**
165 * Next MID expected for incoming traffic.
166 */
167 uint32_t mid_recv;
168 199
200/**
201 * Client endpoint of a `struct CadetChannel`. A channel may be a
202 * loopback channel, in which case it has two of these endpoints.
203 * Note that flow control also is required in both directions.
204 */
205struct CadetChannelClient
206{
169 /** 207 /**
170 * Handle for queued unique data CREATE, DATA_ACK. 208 * Client handle. Not by itself sufficient to designate
209 * the client endpoint, as the same client handle may
210 * be used for both the owner and the destination, and
211 * we thus also need the channel ID to identify the client.
171 */ 212 */
172 struct CadetChannelQueue *uniq; 213 struct CadetClient *c;
173 214
174 /** 215 /**
175 * Can we send data to the client? 216 * Head of DLL of messages received out of order or while client was unready.
176 */ 217 */
177 int client_ready; 218 struct CadetOutOfOrderMessage *head_recv;
178 219
179 /** 220 /**
180 * Can the client send data to us? 221 * Tail DLL of messages received out of order or while client was unready.
181 */ 222 */
182 int client_allowed; 223 struct CadetOutOfOrderMessage *tail_recv;
183 224
184 /** 225 /**
185 * Task to resend/poll in case no ACK is received. 226 * Local tunnel number for this client.
227 * (if owner >= #GNUNET_CADET_LOCAL_CHANNEL_ID_CLI,
228 * otherwise < #GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
186 */ 229 */
187 struct GNUNET_SCHEDULER_Task * retry_task; 230 struct GNUNET_CADET_ClientChannelNumber ccn;
188 231
189 /** 232 /**
190 * Counter for exponential backoff. 233 * Number of entries currently in @a head_recv DLL.
191 */ 234 */
192 struct GNUNET_TIME_Relative retry_timer; 235 unsigned int num_recv;
193 236
194 /** 237 /**
195 * How long does it usually take to get an ACK. 238 * Can we send data to the client?
196 */ 239 */
197 struct GNUNET_TIME_Relative expected_delay; 240 int client_ready;
241
198}; 242};
199 243
200 244
@@ -209,41 +253,44 @@ struct CadetChannel
209 struct CadetTunnel *t; 253 struct CadetTunnel *t;
210 254
211 /** 255 /**
212 * Destination port of the channel. 256 * Client owner of the tunnel, if any.
257 * (Used if this channel represends the initiating end of the tunnel.)
213 */ 258 */
214 struct GNUNET_HashCode port; 259 struct CadetChannelClient *owner;
215 260
216 /** 261 /**
217 * Global channel number ( < GNUNET_CADET_LOCAL_CHANNEL_ID_CLI) 262 * Client destination of the tunnel, if any.
263 * (Used if this channel represents the listening end of the tunnel.)
218 */ 264 */
219 struct GNUNET_CADET_ChannelTunnelNumber gid; 265 struct CadetChannelClient *dest;
220 266
221 /** 267 /**
222 * Local tunnel number for root (owner) client. 268 * Last entry in the tunnel's queue relating to control messages
223 * ( >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI or 0 ) 269 * (#GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN or
270 * #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK). Used to cancel
271 * transmission in case we receive updated information.
224 */ 272 */
225 struct GNUNET_CADET_ClientChannelNumber lid_root; 273 struct CadetTunnelQueueEntry *last_control_qe;
226 274
227 /** 275 /**
228 * Local tunnel number for local destination clients (incoming number) 276 * Head of DLL of messages sent and not yet ACK'd.
229 * ( >= GNUNET_CADET_LOCAL_CHANNEL_ID_SERV or 0).
230 */ 277 */
231 struct GNUNET_CADET_ClientChannelNumber lid_dest; 278 struct CadetReliableMessage *head_sent;
232 279
233 /** 280 /**
234 * Channel state. 281 * Tail of DLL of messages sent and not yet ACK'd.
235 */ 282 */
236 enum CadetChannelState state; 283 struct CadetReliableMessage *tail_sent;
237 284
238 /** 285 /**
239 * Is the tunnel bufferless (minimum latency)? 286 * Task to resend/poll in case no ACK is received.
240 */ 287 */
241 int nobuffer; 288 struct GNUNET_SCHEDULER_Task *retry_control_task;
242 289
243 /** 290 /**
244 * Is the tunnel reliable? 291 * Task to resend/poll in case no ACK is received.
245 */ 292 */
246 int reliable; 293 struct GNUNET_SCHEDULER_Task *retry_data_task;
247 294
248 /** 295 /**
249 * Last time the channel was used 296 * Last time the channel was used
@@ -251,21 +298,29 @@ struct CadetChannel
251 struct GNUNET_TIME_Absolute timestamp; 298 struct GNUNET_TIME_Absolute timestamp;
252 299
253 /** 300 /**
254 * Client owner of the tunnel, if any 301 * Destination port of the channel.
255 */ 302 */
256 struct CadetClient *root; 303 struct GNUNET_HashCode port;
257 304
258 /** 305 /**
259 * Client destination of the tunnel, if any. 306 * Counter for exponential backoff.
260 */ 307 */
261 struct CadetClient *dest; 308 struct GNUNET_TIME_Relative retry_time;
262 309
263 /** 310 /**
264 * Flag to signal the destruction of the channel. 311 * Bitfield of already-received messages past @e mid_recv.
265 * If this is set to #GNUNET_YES the channel will be destroyed
266 * when the queue is empty.
267 */ 312 */
268 int destroy; 313 uint64_t mid_futures;
314
315 /**
316 * Next MID expected for incoming traffic.
317 */
318 struct ChannelMessageIdentifier mid_recv;
319
320 /**
321 * Next MID to use for outgoing traffic.
322 */
323 struct ChannelMessageIdentifier mid_send;
269 324
270 /** 325 /**
271 * Total (reliable) messages pending ACK for this channel. 326 * Total (reliable) messages pending ACK for this channel.
@@ -273,2290 +328,1710 @@ struct CadetChannel
273 unsigned int pending_messages; 328 unsigned int pending_messages;
274 329
275 /** 330 /**
276 * Reliability data. 331 * Maximum (reliable) messages pending ACK for this channel
277 * Only present (non-NULL) at the owner of a tunnel. 332 * before we throttle the client.
278 */ 333 */
279 struct CadetChannelReliability *root_rel; 334 unsigned int max_pending_messages;
280 335
281 /** 336 /**
282 * Reliability data. 337 * Number identifying this channel in its tunnel.
283 * Only present (non-NULL) at the destination of a tunnel.
284 */ 338 */
285 struct CadetChannelReliability *dest_rel; 339 struct GNUNET_CADET_ChannelTunnelNumber ctn;
286 340
287}; 341 /**
342 * Channel state.
343 */
344 enum CadetChannelState state;
288 345
346 /**
347 * Count how many ACKs we skipped, used to prevent long
348 * sequences of ACK skipping.
349 */
350 unsigned int skip_ack_series;
289 351
290/******************************************************************************/ 352 /**
291/******************************* GLOBALS ***********************************/ 353 * Is the tunnel bufferless (minimum latency)?
292/******************************************************************************/ 354 */
355 int nobuffer;
293 356
294/** 357 /**
295 * Global handle to the statistics service. 358 * Is the tunnel reliable?
296 */ 359 */
297extern struct GNUNET_STATISTICS_Handle *stats; 360 int reliable;
298 361
299/** 362 /**
300 * Local peer own ID (memory efficient handle). 363 * Is the tunnel out-of-order?
301 */ 364 */
302extern GNUNET_PEER_Id myid; 365 int out_of_order;
303 366
367 /**
368 * Is this channel a loopback channel, where the destination is us again?
369 */
370 int is_loopback;
304 371
305/******************************************************************************/ 372 /**
306/******************************** STATIC ***********************************/ 373 * Flag to signal the destruction of the channel. If this is set to
307/******************************************************************************/ 374 * #GNUNET_YES the channel will be destroyed once the queue is
375 * empty.
376 */
377 int destroy;
308 378
379};
309 380
310/**
311 * Destroy a reliable message after it has been acknowledged, either by
312 * direct mid ACK or bitfield. Updates the appropriate data structures and
313 * timers and frees all memory.
314 *
315 * @param copy Message that is no longer needed: remote peer got it.
316 * @param update_time Is the timing information relevant?
317 * If this message is ACK in a batch the timing information
318 * is skewed by the retransmission, count only for the
319 * retransmitted message.
320 *
321 * @return #GNUNET_YES if channel was destroyed as a result of the call,
322 * #GNUNET_NO otherwise.
323 */
324static int
325rel_message_free (struct CadetReliableMessage *copy, int update_time);
326 381
327/** 382/**
328 * send a channel create message. 383 * Get the static string for identification of the channel.
329 * 384 *
330 * @param ch Channel for which to send. 385 * @param ch Channel.
331 */
332static void
333send_create (struct CadetChannel *ch);
334
335/**
336 * Confirm we got a channel create, FWD ack.
337 * 386 *
338 * @param ch The channel to confirm. 387 * @return Static string with the channel IDs.
339 * @param fwd Should we send a FWD ACK? (going dest->root)
340 */ 388 */
341static void 389const char *
342send_ack (struct CadetChannel *ch, int fwd); 390GCCH_2s (const struct CadetChannel *ch)
343 391{
392 static char buf[128];
393
394 GNUNET_snprintf (buf,
395 sizeof (buf),
396 "Channel %s:%s ctn:%X(%X/%X)",
397 (GNUNET_YES == ch->is_loopback)
398 ? "loopback"
399 : GNUNET_i2s (GCP_get_id (GCT_get_destination (ch->t))),
400 GNUNET_h2s (&ch->port),
401 ch->ctn,
402 (NULL == ch->owner) ? 0 : ntohl (ch->owner->ccn.channel_of_client),
403 (NULL == ch->dest) ? 0 : ntohl (ch->dest->ccn.channel_of_client));
404 return buf;
405}
344 406
345 407
346/** 408/**
347 * Test if the channel is loopback: both root and dest are on the local peer. 409 * Get the channel's public ID.
348 * 410 *
349 * @param ch Channel to test. 411 * @param ch Channel.
350 * 412 *
351 * @return #GNUNET_YES if channel is loopback, #GNUNET_NO otherwise. 413 * @return ID used to identify the channel with the remote peer.
352 */ 414 */
353static int 415struct GNUNET_CADET_ChannelTunnelNumber
354is_loopback (const struct CadetChannel *ch) 416GCCH_get_id (const struct CadetChannel *ch)
355{ 417{
356 if (NULL != ch->t) 418 return ch->ctn;
357 return GCT_is_loopback (ch->t);
358
359 return (NULL != ch->root && NULL != ch->dest);
360} 419}
361 420
362 421
363/** 422/**
364 * Save a copy of the data message for later retransmission. 423 * Release memory associated with @a ccc
365 * 424 *
366 * @param msg Message to copy. 425 * @param ccc data structure to clean up
367 * @param mid Message ID.
368 * @param rel Reliability data for retransmission.
369 */ 426 */
370static struct CadetReliableMessage * 427static void
371copy_message (const struct GNUNET_CADET_ChannelAppDataMessage *msg, uint32_t mid, 428free_channel_client (struct CadetChannelClient *ccc)
372 struct CadetChannelReliability *rel)
373{ 429{
374 struct CadetReliableMessage *copy; 430 struct CadetOutOfOrderMessage *com;
375 uint16_t size;
376 431
377 size = ntohs (msg->header.size); 432 while (NULL != (com = ccc->head_recv))
378 copy = GNUNET_malloc (sizeof (*copy) + size); 433 {
379 copy->mid = mid; 434 GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
380 copy->rel = rel; 435 ccc->tail_recv,
381 copy->type = GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA; 436 com);
382 GNUNET_memcpy (&copy[1], msg, size); 437 ccc->num_recv--;
383 438 GNUNET_MQ_discard (com->env);
384 return copy; 439 GNUNET_free (com);
440 }
441 GNUNET_free (ccc);
385} 442}
386 443
444
387/** 445/**
388 * We have received a message out of order, or the client is not ready. 446 * Destroy the given channel.
389 * Buffer it until we receive an ACK from the client or the missing
390 * message from the channel.
391 * 447 *
392 * @param msg Message to buffer (MUST be of type CADET_DATA). 448 * @param ch channel to destroy
393 * @param rel Reliability data to the corresponding direction.
394 */ 449 */
395static void 450static void
396add_buffered_data (const struct GNUNET_CADET_ChannelAppDataMessage *msg, 451channel_destroy (struct CadetChannel *ch)
397 struct CadetChannelReliability *rel)
398{ 452{
399 struct CadetReliableMessage *copy; 453 struct CadetReliableMessage *crm;
400 struct CadetReliableMessage *prev;
401 uint32_t mid;
402
403 mid = ntohl (msg->mid);
404 454
405 LOG (GNUNET_ERROR_TYPE_DEBUG, "add_buffered_data MID %u (%u)\n", 455 while (NULL != (crm = ch->head_sent))
406 mid, rel->n_recv);
407
408 rel->n_recv++;
409
410 // FIXME do something better than O(n), although n < 64...
411 // FIXME start from the end (most messages are the latest ones)
412 for (prev = rel->head_recv; NULL != prev; prev = prev->next)
413 { 456 {
414 LOG (GNUNET_ERROR_TYPE_DEBUG, " prev %u\n", prev->mid); 457 GNUNET_assert (ch == crm->ch);
415 if (prev->mid == mid) 458 if (NULL != crm->qe)
416 { 459 {
417 LOG (GNUNET_ERROR_TYPE_DEBUG, " already there!\n"); 460 GCT_send_cancel (crm->qe);
418 rel->n_recv--; 461 crm->qe = NULL;
419 return;
420 }
421 else if (GC_is_pid_bigger (prev->mid, mid))
422 {
423 LOG (GNUNET_ERROR_TYPE_DEBUG, " bingo!\n");
424 copy = copy_message (msg, mid, rel);
425 GNUNET_CONTAINER_DLL_insert_before (rel->head_recv, rel->tail_recv,
426 prev, copy);
427 return;
428 } 462 }
463 GNUNET_CONTAINER_DLL_remove (ch->head_sent,
464 ch->tail_sent,
465 crm);
466 GNUNET_free (crm->data_message);
467 GNUNET_free (crm);
468 }
469 if (NULL != ch->owner)
470 {
471 free_channel_client (ch->owner);
472 ch->owner = NULL;
429 } 473 }
430 copy = copy_message (msg, mid, rel); 474 if (NULL != ch->dest)
431 LOG (GNUNET_ERROR_TYPE_DEBUG, " insert at tail! (now: %u)\n", rel->n_recv); 475 {
432 GNUNET_CONTAINER_DLL_insert_tail (rel->head_recv, rel->tail_recv, copy); 476 free_channel_client (ch->dest);
433 LOG (GNUNET_ERROR_TYPE_DEBUG, "add_buffered_data END\n"); 477 ch->dest = NULL;
478 }
479 if (NULL != ch->last_control_qe)
480 {
481 GCT_send_cancel (ch->last_control_qe);
482 ch->last_control_qe = NULL;
483 }
484 if (NULL != ch->retry_data_task)
485 {
486 GNUNET_SCHEDULER_cancel (ch->retry_data_task);
487 ch->retry_data_task = NULL;
488 }
489 if (NULL != ch->retry_control_task)
490 {
491 GNUNET_SCHEDULER_cancel (ch->retry_control_task);
492 ch->retry_control_task = NULL;
493 }
494 if (GNUNET_NO == ch->is_loopback)
495 {
496 GCT_remove_channel (ch->t,
497 ch,
498 ch->ctn);
499 ch->t = NULL;
500 }
501 GNUNET_free (ch);
434} 502}
435 503
436 504
437/** 505/**
438 * Add a destination client to a channel, initializing all data structures 506 * Send a channel create message.
439 * in the channel and the client.
440 * 507 *
441 * @param ch Channel to which add the destination. 508 * @param cls Channel for which to send.
442 * @param c Client which to add to the channel.
443 */ 509 */
444static void 510static void
445add_destination (struct CadetChannel *ch, struct CadetClient *c) 511send_channel_open (void *cls);
446{
447 if (NULL != ch->dest)
448 {
449 GNUNET_break (0);
450 return;
451 }
452
453 /* Assign local id as destination */
454 ch->lid_dest = GML_get_next_ccn (c);
455
456 /* Store in client's hashmap */
457 GML_channel_add (c, ch->lid_dest, ch);
458
459 GNUNET_break (NULL == ch->dest_rel);
460 ch->dest_rel = GNUNET_new (struct CadetChannelReliability);
461 ch->dest_rel->ch = ch;
462 ch->dest_rel->expected_delay.rel_value_us = 0;
463 ch->dest_rel->retry_timer = CADET_RETRANSMIT_TIME;
464
465 ch->dest = c;
466}
467 512
468 513
469/** 514/**
470 * Set options in a channel, extracted from a bit flag field. 515 * Function called once the tunnel confirms that we sent the
516 * create message. Delays for a bit until we retry.
471 * 517 *
472 * @param ch Channel to set options to. 518 * @param cls our `struct CadetChannel`.
473 * @param options Bit array in host byte order. 519 * @param cid identifier of the connection within the tunnel, NULL
520 * if transmission failed
474 */ 521 */
475static void 522static void
476channel_set_options (struct CadetChannel *ch, uint32_t options) 523channel_open_sent_cb (void *cls,
524 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
477{ 525{
478 ch->nobuffer = (options & GNUNET_CADET_OPTION_NOBUFFER) != 0 ? 526 struct CadetChannel *ch = cls;
479 GNUNET_YES : GNUNET_NO; 527
480 ch->reliable = (options & GNUNET_CADET_OPTION_RELIABLE) != 0 ? 528 GNUNET_assert (NULL != ch->last_control_qe);
481 GNUNET_YES : GNUNET_NO; 529 ch->last_control_qe = NULL;
530 ch->retry_time = GNUNET_TIME_STD_BACKOFF (ch->retry_time);
531 LOG (GNUNET_ERROR_TYPE_DEBUG,
532 "Sent CADET_CHANNEL_OPEN on %s, retrying in %s\n",
533 GCCH_2s (ch),
534 GNUNET_STRINGS_relative_time_to_string (ch->retry_time,
535 GNUNET_YES));
536 ch->retry_control_task
537 = GNUNET_SCHEDULER_add_delayed (ch->retry_time,
538 &send_channel_open,
539 ch);
482} 540}
483 541
484 542
485/** 543/**
486 * Get a bit flag field with the options of a channel. 544 * Send a channel open message.
487 * 545 *
488 * @param ch Channel to get options from. 546 * @param cls Channel for which to send.
489 *
490 * @return Bit array in host byte order.
491 */ 547 */
492static uint32_t 548static void
493channel_get_options (struct CadetChannel *ch) 549send_channel_open (void *cls)
494{ 550{
551 struct CadetChannel *ch = cls;
552 struct GNUNET_CADET_ChannelOpenMessage msgcc;
495 uint32_t options; 553 uint32_t options;
496 554
555 ch->retry_control_task = NULL;
556 LOG (GNUNET_ERROR_TYPE_DEBUG,
557 "Sending CHANNEL_OPEN message for %s\n",
558 GCCH_2s (ch));
497 options = 0; 559 options = 0;
498 if (ch->nobuffer) 560 if (ch->nobuffer)
499 options |= GNUNET_CADET_OPTION_NOBUFFER; 561 options |= GNUNET_CADET_OPTION_NOBUFFER;
500 if (ch->reliable) 562 if (ch->reliable)
501 options |= GNUNET_CADET_OPTION_RELIABLE; 563 options |= GNUNET_CADET_OPTION_RELIABLE;
502 564 if (ch->out_of_order)
503 return options; 565 options |= GNUNET_CADET_OPTION_OUT_OF_ORDER;
566 msgcc.header.size = htons (sizeof (msgcc));
567 msgcc.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN);
568 msgcc.opt = htonl (options);
569 msgcc.port = ch->port;
570 msgcc.ctn = ch->ctn;
571 ch->state = CADET_CHANNEL_OPEN_SENT;
572 if (NULL != ch->last_control_qe)
573 GCT_send_cancel (ch->last_control_qe);
574 ch->last_control_qe = GCT_send (ch->t,
575 &msgcc.header,
576 &channel_open_sent_cb,
577 ch);
578 GNUNET_assert (NULL == ch->retry_control_task);
504} 579}
505 580
506 581
507/** 582/**
508 * Notify a client that the channel is no longer valid. 583 * Function called once and only once after a channel was bound
509 * 584 * to its tunnel via #GCT_add_channel() is ready for transmission.
510 * @param ch Channel that is destroyed. 585 * Note that this is only the case for channels that this peer
511 * @param local_only Should we avoid sending it to other peers? 586 * initiates, as for incoming channels we assume that they are
587 * ready for transmission immediately upon receiving the open
588 * message. Used to bootstrap the #GCT_send() process.
589 *
590 * @param ch the channel for which the tunnel is now ready
512 */ 591 */
513static void 592void
514send_destroy (struct CadetChannel *ch, int local_only) 593GCCH_tunnel_up (struct CadetChannel *ch)
515{ 594{
516 struct GNUNET_CADET_ChannelManageMessage msg; 595 GNUNET_assert (NULL == ch->retry_control_task);
517 596 LOG (GNUNET_ERROR_TYPE_DEBUG,
518 msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY); 597 "Tunnel up, sending CHANNEL_OPEN on %s now\n",
519 msg.header.size = htons (sizeof (msg)); 598 GCCH_2s (ch));
520 msg.ctn = ch->gid; 599 ch->retry_control_task
521 600 = GNUNET_SCHEDULER_add_now (&send_channel_open,
522 /* If root is not NULL, notify. 601 ch);
523 * If it's NULL, check lid_root. When a local destroy comes in, root
524 * is set to NULL but lid_root is left untouched. In this case, do nothing,
525 * the client is the one who requested the channel to be destroyed.
526 */
527 if (NULL != ch->root)
528 GML_send_channel_destroy (ch->root, ch->lid_root);
529 else if (0 == ch->lid_root.channel_of_client && GNUNET_NO == local_only)
530 GCCH_send_prebuilt_message (&msg.header, ch, GNUNET_NO, NULL);
531
532 if (NULL != ch->dest)
533 GML_send_channel_destroy (ch->dest, ch->lid_dest);
534 else if (0 == ch->lid_dest.channel_of_client && GNUNET_NO == local_only)
535 GCCH_send_prebuilt_message (&msg.header, ch, GNUNET_YES, NULL);
536} 602}
537 603
538 604
539/** 605/**
540 * Notify the destination client that a new incoming channel was created. 606 * Create a new channel.
541 * 607 *
542 * @param ch Channel that was created. 608 * @param owner local client owning the channel
609 * @param ccn local number of this channel at the @a owner
610 * @param destination peer to which we should build the channel
611 * @param port desired port at @a destination
612 * @param options options for the channel
613 * @return handle to the new channel
543 */ 614 */
544static void 615struct CadetChannel *
545send_client_create (struct CadetChannel *ch) 616GCCH_channel_local_new (struct CadetClient *owner,
617 struct GNUNET_CADET_ClientChannelNumber ccn,
618 struct CadetPeer *destination,
619 const struct GNUNET_HashCode *port,
620 uint32_t options)
546{ 621{
547 uint32_t opt; 622 struct CadetChannel *ch;
548 623 struct CadetChannelClient *ccco;
549 if (NULL == ch->dest)
550 return;
551
552 opt = 0;
553 opt |= GNUNET_YES == ch->reliable ? GNUNET_CADET_OPTION_RELIABLE : 0;
554 opt |= GNUNET_YES == ch->nobuffer ? GNUNET_CADET_OPTION_NOBUFFER : 0;
555 GML_send_channel_create (ch->dest,
556 ch->lid_dest,
557 &ch->port,
558 opt,
559 GCT_get_destination (ch->t));
560
561}
562 624
625 ccco = GNUNET_new (struct CadetChannelClient);
626 ccco->c = owner;
627 ccco->ccn = ccn;
628 ccco->client_ready = GNUNET_YES;
563 629
564/** 630 ch = GNUNET_new (struct CadetChannel);
565 * Send data to a client. 631 ch->mid_recv.mid = htonl (1); /* The OPEN_ACK counts as message 0! */
566 * 632 ch->nobuffer = (0 != (options & GNUNET_CADET_OPTION_NOBUFFER));
567 * If the client is ready, send directly, otherwise buffer while listening 633 ch->reliable = (0 != (options & GNUNET_CADET_OPTION_RELIABLE));
568 * for a local ACK. 634 ch->out_of_order = (0 != (options & GNUNET_CADET_OPTION_OUT_OF_ORDER));
569 * 635 ch->max_pending_messages = (ch->nobuffer) ? 1 : 4; /* FIXME: 4!? Do not hardcode! */
570 * @param ch Channel 636 ch->owner = ccco;
571 * @param msg Message. 637 ch->port = *port;
572 * @param fwd Is this a fwd (root->dest) message? 638 if (0 == memcmp (&my_full_id,
573 */ 639 GCP_get_id (destination),
574static void 640 sizeof (struct GNUNET_PeerIdentity)))
575send_client_data (struct CadetChannel *ch, 641 {
576 const struct GNUNET_CADET_ChannelAppDataMessage *msg, 642 struct CadetClient *c;
577 int fwd) 643
578{ 644 ch->is_loopback = GNUNET_YES;
579 if (fwd) 645 c = GNUNET_CONTAINER_multihashmap_get (open_ports,
580 { 646 port);
581 if (ch->dest_rel->client_ready) 647 if (NULL == c)
582 { 648 {
583 GML_send_data (ch->dest, msg, ch->lid_dest); 649 /* port closed, wait for it to possibly open */
584 ch->dest_rel->client_ready = GNUNET_NO; 650 ch->state = CADET_CHANNEL_LOOSE;
585 ch->dest_rel->mid_recv++; 651 (void) GNUNET_CONTAINER_multihashmap_put (loose_channels,
652 port,
653 ch,
654 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
655 LOG (GNUNET_ERROR_TYPE_DEBUG,
656 "Created loose incoming loopback channel to port %s\n",
657 GNUNET_h2s (&ch->port));
586 } 658 }
587 else 659 else
588 add_buffered_data (msg, ch->dest_rel); 660 {
661 GCCH_bind (ch,
662 c);
663 }
589 } 664 }
590 else 665 else
591 { 666 {
592 if (ch->root_rel->client_ready) 667 ch->t = GCP_get_tunnel (destination,
593 { 668 GNUNET_YES);
594 GML_send_data (ch->root, msg, ch->lid_root); 669 ch->retry_time = CADET_INITIAL_RETRANSMIT_TIME;
595 ch->root_rel->client_ready = GNUNET_NO; 670 ch->ctn = GCT_add_channel (ch->t,
596 ch->root_rel->mid_recv++; 671 ch);
597 }
598 else
599 add_buffered_data (msg, ch->root_rel);
600 } 672 }
673 GNUNET_STATISTICS_update (stats,
674 "# channels",
675 1,
676 GNUNET_NO);
677 LOG (GNUNET_ERROR_TYPE_DEBUG,
678 "Created channel to port %s at peer %s for %s using %s\n",
679 GNUNET_h2s (port),
680 GCP_2s (destination),
681 GSC_2s (owner),
682 (GNUNET_YES == ch->is_loopback) ? "loopback" : GCT_2s (ch->t));
683 return ch;
601} 684}
602 685
603 686
604/** 687/**
605 * Send a buffered message to the client, for in order delivery or 688 * We had an incoming channel to a port that is closed.
606 * as result of client ACK. 689 * It has not been opened for a while, drop it.
607 * 690 *
608 * @param ch Channel on which to empty the message buffer. 691 * @param cls the channel to drop
609 * @param c Client to send to.
610 * @param fwd Is this to send FWD data?.
611 */ 692 */
612static void 693static void
613send_client_buffered_data (struct CadetChannel *ch, 694timeout_closed_cb (void *cls)
614 struct CadetClient *c,
615 int fwd)
616{ 695{
617 struct CadetReliableMessage *copy; 696 struct CadetChannel *ch = cls;
618 struct CadetChannelReliability *rel;
619
620 LOG (GNUNET_ERROR_TYPE_DEBUG, "send_buffered_data\n");
621 rel = fwd ? ch->dest_rel : ch->root_rel;
622 if (GNUNET_NO == rel->client_ready)
623 {
624 LOG (GNUNET_ERROR_TYPE_DEBUG, "client not ready\n");
625 return;
626 }
627 697
628 copy = rel->head_recv; 698 ch->retry_control_task = NULL;
629 /* We never buffer channel management messages */ 699 LOG (GNUNET_ERROR_TYPE_DEBUG,
630 if (NULL != copy) 700 "Closing incoming channel to port %s from peer %s due to timeout\n",
631 { 701 GNUNET_h2s (&ch->port),
632 if (copy->mid == rel->mid_recv || GNUNET_NO == ch->reliable) 702 GCP_2s (GCT_get_destination (ch->t)));
633 { 703 channel_destroy (ch);
634 struct GNUNET_CADET_ChannelAppDataMessage *msg = (struct GNUNET_CADET_ChannelAppDataMessage *) &copy[1];
635
636 LOG (GNUNET_ERROR_TYPE_DEBUG, " have %u! now expecting %u\n",
637 copy->mid, rel->mid_recv + 1);
638 send_client_data (ch, msg, fwd);
639 rel->n_recv--;
640 GNUNET_CONTAINER_DLL_remove (rel->head_recv, rel->tail_recv, copy);
641 LOG (GNUNET_ERROR_TYPE_DEBUG, " free copy recv MID %u (%p), %u left\n",
642 copy->mid, copy, rel->n_recv);
643 GNUNET_free (copy);
644 GCCH_send_data_ack (ch, fwd);
645 }
646 else
647 {
648 LOG (GNUNET_ERROR_TYPE_DEBUG, " reliable && don't have %u, next is %u\n",
649 rel->mid_recv, copy->mid);
650 if (GNUNET_YES == ch->destroy)
651 {
652 /* We don't have the next data piece and the remote peer has closed the
653 * channel. We won't receive it anymore, so just destroy the channel.
654 * FIXME: wait some time to allow other connections to
655 * deliver missing messages
656 */
657 send_destroy (ch, GNUNET_YES);
658 GCCH_destroy (ch);
659 }
660 }
661 }
662 LOG (GNUNET_ERROR_TYPE_DEBUG, "send_buffered_data END\n");
663} 704}
664 705
665 706
666/** 707/**
667 * Allow a client to send more data. 708 * Create a new channel based on a request coming in over the network.
668 *
669 * In case the client was already allowed to send data, do nothing.
670 * 709 *
671 * @param ch Channel. 710 * @param t tunnel to the remote peer
672 * @param fwd Is this a FWD ACK? (FWD ACKs are sent to root) 711 * @param ctn identifier of this channel in the tunnel
712 * @param port desired local port
713 * @param options options for the channel
714 * @return handle to the new channel
673 */ 715 */
674static void 716struct CadetChannel *
675send_client_ack (struct CadetChannel *ch, int fwd) 717GCCH_channel_incoming_new (struct CadetTunnel *t,
718 struct GNUNET_CADET_ChannelTunnelNumber ctn,
719 const struct GNUNET_HashCode *port,
720 uint32_t options)
676{ 721{
677 struct CadetChannelReliability *rel = fwd ? ch->root_rel : ch->dest_rel; 722 struct CadetChannel *ch;
678 struct CadetClient *c = fwd ? ch->root : ch->dest; 723 struct CadetClient *c;
724
725 ch = GNUNET_new (struct CadetChannel);
726 ch->port = *port;
727 ch->t = t;
728 ch->ctn = ctn;
729 ch->retry_time = CADET_INITIAL_RETRANSMIT_TIME;
730 ch->nobuffer = (0 != (options & GNUNET_CADET_OPTION_NOBUFFER));
731 ch->reliable = (0 != (options & GNUNET_CADET_OPTION_RELIABLE));
732 ch->out_of_order = (0 != (options & GNUNET_CADET_OPTION_OUT_OF_ORDER));
733 ch->max_pending_messages = (ch->nobuffer) ? 1 : 4; /* FIXME: 4!? Do not hardcode! */
734 GNUNET_STATISTICS_update (stats,
735 "# channels",
736 1,
737 GNUNET_NO);
679 738
739 c = GNUNET_CONTAINER_multihashmap_get (open_ports,
740 port);
680 if (NULL == c) 741 if (NULL == c)
681 { 742 {
682 GNUNET_break (GNUNET_NO != ch->destroy); 743 /* port closed, wait for it to possibly open */
683 return; 744 ch->state = CADET_CHANNEL_LOOSE;
745 (void) GNUNET_CONTAINER_multihashmap_put (loose_channels,
746 port,
747 ch,
748 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
749 GNUNET_assert (NULL == ch->retry_control_task);
750 ch->retry_control_task
751 = GNUNET_SCHEDULER_add_delayed (TIMEOUT_CLOSED_PORT,
752 &timeout_closed_cb,
753 ch);
754 LOG (GNUNET_ERROR_TYPE_DEBUG,
755 "Created loose incoming channel to port %s from peer %s\n",
756 GNUNET_h2s (&ch->port),
757 GCP_2s (GCT_get_destination (ch->t)));
684 } 758 }
685 LOG (GNUNET_ERROR_TYPE_DEBUG, 759 else
686 " sending %s ack to client on channel %s\n",
687 GC_f2s (fwd), GCCH_2s (ch));
688
689 if (NULL == rel)
690 { 760 {
691 GNUNET_break (0); 761 GCCH_bind (ch,
692 return; 762 c);
693 } 763 }
694 764 GNUNET_STATISTICS_update (stats,
695 if (GNUNET_YES == rel->client_allowed) 765 "# channels",
696 { 766 1,
697 LOG (GNUNET_ERROR_TYPE_DEBUG, " already allowed\n"); 767 GNUNET_NO);
698 return; 768 return ch;
699 }
700 rel->client_allowed = GNUNET_YES;
701
702 GML_send_ack (c, fwd ? ch->lid_root : ch->lid_dest);
703} 769}
704 770
705 771
706/** 772/**
707 * Notify the root that the destination rejected the channel. 773 * Function called once the tunnel confirms that we sent the
774 * ACK message. Just remembers it was sent, we do not expect
775 * ACKs for ACKs ;-).
708 * 776 *
709 * @param ch Rejected channel. 777 * @param cls our `struct CadetChannel`.
778 * @param cid identifier of the connection within the tunnel, NULL
779 * if transmission failed
710 */ 780 */
711static void 781static void
712send_client_nack (struct CadetChannel *ch) 782send_ack_cb (void *cls,
783 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
713{ 784{
714 if (NULL == ch->root) 785 struct CadetChannel *ch = cls;
715 { 786
716 GNUNET_break (0); 787 GNUNET_assert (NULL != ch->last_control_qe);
717 return; 788 ch->last_control_qe = NULL;
718 }
719 GML_send_channel_nack (ch->root, ch->lid_root);
720} 789}
721 790
722 791
723/** 792/**
724 * We haven't received an ACK after a certain time: restransmit the message. 793 * Compute and send the current #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK to the other peer.
725 * 794 *
726 * @param cls Closure (CadetChannelReliability with the message to restransmit) 795 * @param ch channel to send the #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK for
727 */ 796 */
728static void 797static void
729channel_retransmit_message (void *cls) 798send_channel_data_ack (struct CadetChannel *ch)
730{ 799{
731 struct CadetChannelReliability *rel = cls; 800 struct GNUNET_CADET_ChannelDataAckMessage msg;
732 struct CadetReliableMessage *copy;
733 struct CadetChannel *ch;
734 struct GNUNET_CADET_ChannelAppDataMessage *payload;
735 int fwd;
736
737 rel->retry_task = NULL;
738 ch = rel->ch;
739 copy = rel->head_sent;
740 if (NULL == copy)
741 {
742 GNUNET_break (0); // FIXME tripped in rps testcase
743 return;
744 }
745
746 payload = (struct GNUNET_CADET_ChannelAppDataMessage *) &copy[1];
747 fwd = (rel == ch->root_rel);
748
749 /* Message not found in the queue that we are going to use. */
750 LOG (GNUNET_ERROR_TYPE_DEBUG, "RETRANSMIT MID %u\n", copy->mid);
751 801
752 GCCH_send_prebuilt_message (&payload->header, ch, fwd, copy); 802 if (GNUNET_NO == ch->reliable)
753 GNUNET_STATISTICS_update (stats, "# data retransmitted", 1, GNUNET_NO); 803 return; /* no ACKs */
804 msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK);
805 msg.header.size = htons (sizeof (msg));
806 msg.ctn = ch->ctn;
807 msg.mid.mid = htonl (ntohl (ch->mid_recv.mid));
808 msg.futures = GNUNET_htonll (ch->mid_futures);
809 LOG (GNUNET_ERROR_TYPE_DEBUG,
810 "Sending DATA_ACK %u:%llX via %s\n",
811 (unsigned int) ntohl (msg.mid.mid),
812 (unsigned long long) ch->mid_futures,
813 GCCH_2s (ch));
814 if (NULL != ch->last_control_qe)
815 GCT_send_cancel (ch->last_control_qe);
816 ch->last_control_qe = GCT_send (ch->t,
817 &msg.header,
818 &send_ack_cb,
819 ch);
754} 820}
755 821
756 822
757/** 823/**
758 * We haven't received an Channel ACK after a certain time: resend the CREATE. 824 * Send our initial #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK to the client confirming that the
825 * connection is up.
759 * 826 *
760 * @param cls Closure (CadetChannelReliability of the channel to recreate) 827 * @param cls the `struct CadetChannel`
761 */ 828 */
762static void 829static void
763channel_recreate (void *cls) 830send_open_ack (void *cls)
764{ 831{
765 struct CadetChannelReliability *rel = cls; 832 struct CadetChannel *ch = cls;
766 833 struct GNUNET_CADET_ChannelManageMessage msg;
767 rel->retry_task = NULL;
768 LOG (GNUNET_ERROR_TYPE_DEBUG, "RE-CREATE\n");
769 GNUNET_STATISTICS_update (stats,
770 "# data retransmitted", 1, GNUNET_NO);
771 834
772 if (rel == rel->ch->root_rel) 835 ch->retry_control_task = NULL;
773 { 836 LOG (GNUNET_ERROR_TYPE_DEBUG,
774 send_create (rel->ch); 837 "Sending CHANNEL_OPEN_ACK on %s\n",
775 } 838 GCCH_2s (ch));
776 else if (rel == rel->ch->dest_rel) 839 msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK);
777 { 840 msg.header.size = htons (sizeof (msg));
778 send_ack (rel->ch, GNUNET_YES); 841 msg.reserved = htonl (0);
779 } 842 msg.ctn = ch->ctn;
780 else 843 if (NULL != ch->last_control_qe)
781 { 844 GCT_send_cancel (ch->last_control_qe);
782 GNUNET_break (0); 845 ch->last_control_qe = GCT_send (ch->t,
783 } 846 &msg.header,
847 &send_ack_cb,
848 ch);
784} 849}
785 850
786 851
787/** 852/**
788 * Message has been sent: start retransmission timer. 853 * We got a #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN message again for
854 * this channel. If the binding was successful, (re)transmit the
855 * #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK.
789 * 856 *
790 * @param cls Closure (queue structure). 857 * @param ch channel that got the duplicate open
791 * @param t Tunnel. 858 * @param cti identifier of the connection that delivered the message
792 * @param q Queue handler (no longer valid).
793 * @param type Type of message.
794 * @param size Size of the message.
795 */ 859 */
796static void 860void
797ch_message_sent (void *cls, 861GCCH_handle_duplicate_open (struct CadetChannel *ch,
798 struct CadetTunnel *t, 862 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti)
799 struct CadetTunnelQueue *q,
800 uint16_t type, size_t size)
801{ 863{
802 struct CadetChannelQueue *chq = cls; 864 if (NULL == ch->dest)
803 struct CadetReliableMessage *copy = chq->copy;
804 struct CadetChannelReliability *rel;
805
806 LOG (GNUNET_ERROR_TYPE_DEBUG, "channel_message_sent callback %s\n",
807 GC_m2s (chq->type));
808
809 switch (chq->type)
810 { 865 {
811 case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA: 866 LOG (GNUNET_ERROR_TYPE_DEBUG,
812 LOG (GNUNET_ERROR_TYPE_DEBUG, "data MID %u sent\n", copy->mid); 867 "Ignoring duplicate CHANNEL_OPEN on %s: port is closed\n",
813 GNUNET_assert (chq == copy->chq); 868 GCCH_2s (ch));
814 copy->timestamp = GNUNET_TIME_absolute_get (); 869 return;
815 rel = copy->rel;
816 if (NULL == rel->retry_task)
817 {
818 LOG (GNUNET_ERROR_TYPE_DEBUG, " scheduling retry in %d * %s\n",
819 CADET_RETRANSMIT_MARGIN,
820 GNUNET_STRINGS_relative_time_to_string (rel->expected_delay,
821 GNUNET_YES));
822 if (0 != rel->expected_delay.rel_value_us)
823 {
824 rel->retry_timer =
825 GNUNET_TIME_relative_saturating_multiply (rel->expected_delay,
826 CADET_RETRANSMIT_MARGIN);
827 }
828 else
829 {
830 rel->retry_timer = CADET_RETRANSMIT_TIME;
831 }
832 LOG (GNUNET_ERROR_TYPE_DEBUG, " using delay %s\n",
833 GNUNET_STRINGS_relative_time_to_string (rel->retry_timer,
834 GNUNET_NO));
835 rel->retry_task =
836 GNUNET_SCHEDULER_add_delayed (rel->retry_timer,
837 &channel_retransmit_message, rel);
838 }
839 else
840 {
841 LOG (GNUNET_ERROR_TYPE_DEBUG, "retry running %p\n", rel->retry_task);
842 }
843 copy->chq = NULL;
844 break;
845
846
847 case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK:
848 case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN:
849 case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK:
850 LOG (GNUNET_ERROR_TYPE_DEBUG, "sent %s\n", GC_m2s (chq->type));
851 rel = chq->rel;
852 GNUNET_assert (rel->uniq == chq);
853 rel->uniq = NULL;
854
855 if (CADET_CHANNEL_READY != rel->ch->state
856 && GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK != type
857 && GNUNET_NO == rel->ch->destroy)
858 {
859 GNUNET_assert (NULL == rel->retry_task);
860 LOG (GNUNET_ERROR_TYPE_DEBUG, "STD BACKOFF %s\n",
861 GNUNET_STRINGS_relative_time_to_string (rel->retry_timer,
862 GNUNET_NO));
863 rel->retry_timer = GNUNET_TIME_STD_BACKOFF (rel->retry_timer);
864 rel->retry_task = GNUNET_SCHEDULER_add_delayed (rel->retry_timer,
865 &channel_recreate, rel);
866 }
867 break;
868
869 default:
870 GNUNET_break (0);
871 } 870 }
872 871 if (NULL != ch->retry_control_task)
873 GNUNET_free (chq); 872 {
873 LOG (GNUNET_ERROR_TYPE_DEBUG,
874 "Ignoring duplicate CHANNEL_OPEN on %s: control message is pending\n",
875 GCCH_2s (ch));
876 return;
877 }
878 LOG (GNUNET_ERROR_TYPE_DEBUG,
879 "Retransmitting CHANNEL_OPEN_ACK on %s\n",
880 GCCH_2s (ch));
881 ch->retry_control_task
882 = GNUNET_SCHEDULER_add_now (&send_open_ack,
883 ch);
874} 884}
875 885
876 886
877/** 887/**
878 * send a channel create message. 888 * Send a #GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK to the client to solicit more messages.
879 * 889 *
880 * @param ch Channel for which to send. 890 * @param ch channel the ack is for
891 * @param to_owner #GNUNET_YES to send to owner,
892 * #GNUNET_NO to send to dest
881 */ 893 */
882static void 894static void
883send_create (struct CadetChannel *ch) 895send_ack_to_client (struct CadetChannel *ch,
896 int to_owner)
884{ 897{
885 struct GNUNET_CADET_ChannelOpenMessage msgcc; 898 struct GNUNET_MQ_Envelope *env;
899 struct GNUNET_CADET_LocalAck *ack;
900 struct CadetChannelClient *ccc;
886 901
887 msgcc.header.size = htons (sizeof (msgcc)); 902 ccc = (GNUNET_YES == to_owner) ? ch->owner : ch->dest;
888 msgcc.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN); 903 if (NULL == ccc)
889 msgcc.ctn = ch->gid; 904 {
890 msgcc.port = ch->port; 905 /* This can happen if we are just getting ACKs after
891 msgcc.opt = htonl (channel_get_options (ch)); 906 our local client already disconnected. */
892 907 GNUNET_assert (GNUNET_YES == ch->destroy);
893 GCCH_send_prebuilt_message (&msgcc.header, ch, GNUNET_YES, NULL); 908 return;
909 }
910 env = GNUNET_MQ_msg (ack,
911 GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK);
912 ack->ccn = ccc->ccn;
913 LOG (GNUNET_ERROR_TYPE_DEBUG,
914 "Sending CADET_LOCAL_ACK to %s (%s) at ccn %X (%u/%u pending)\n",
915 GSC_2s (ccc->c),
916 (GNUNET_YES == to_owner) ? "owner" : "dest",
917 ntohl (ack->ccn.channel_of_client),
918 ch->pending_messages,
919 ch->max_pending_messages);
920 GSC_send_to_client (ccc->c,
921 env);
894} 922}
895 923
896 924
897/** 925/**
898 * Confirm we got a channel create or FWD ack. 926 * A client is bound to the port that we have a channel
927 * open to. Send the acknowledgement for the connection
928 * request and establish the link with the client.
899 * 929 *
900 * @param ch The channel to confirm. 930 * @param ch open incoming channel
901 * @param fwd Should we send a FWD ACK? (going dest->root) 931 * @param c client listening on the respective port
902 */ 932 */
903static void 933void
904send_ack (struct CadetChannel *ch, int fwd) 934GCCH_bind (struct CadetChannel *ch,
935 struct CadetClient *c)
905{ 936{
906 struct GNUNET_CADET_ChannelManageMessage msg; 937 uint32_t options;
938 struct CadetChannelClient *cccd;
907 939
908 msg.header.size = htons (sizeof (msg));
909 msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK);
910 LOG (GNUNET_ERROR_TYPE_DEBUG, 940 LOG (GNUNET_ERROR_TYPE_DEBUG,
911 " sending channel %s ack for channel %s\n", 941 "Binding %s from %s to port %s of %s\n",
912 GC_f2s (fwd), GCCH_2s (ch)); 942 GCCH_2s (ch),
913 943 GCT_2s (ch->t),
914 msg.ctn =ch->gid; 944 GNUNET_h2s (&ch->port),
915 GCCH_send_prebuilt_message (&msg.header, ch, !fwd, NULL); 945 GSC_2s (c));
946 if (NULL != ch->retry_control_task)
947 {
948 /* there might be a timeout task here */
949 GNUNET_SCHEDULER_cancel (ch->retry_control_task);
950 ch->retry_control_task = NULL;
951 }
952 options = 0;
953 if (ch->nobuffer)
954 options |= GNUNET_CADET_OPTION_NOBUFFER;
955 if (ch->reliable)
956 options |= GNUNET_CADET_OPTION_RELIABLE;
957 if (ch->out_of_order)
958 options |= GNUNET_CADET_OPTION_OUT_OF_ORDER;
959 cccd = GNUNET_new (struct CadetChannelClient);
960 GNUNET_assert (NULL == ch->dest);
961 ch->dest = cccd;
962 cccd->c = c;
963 cccd->client_ready = GNUNET_YES;
964 cccd->ccn = GSC_bind (c,
965 ch,
966 (GNUNET_YES == ch->is_loopback)
967 ? GCP_get (&my_full_id,
968 GNUNET_YES)
969 : GCT_get_destination (ch->t),
970 &ch->port,
971 options);
972 GNUNET_assert (ntohl (cccd->ccn.channel_of_client) <
973 GNUNET_CADET_LOCAL_CHANNEL_ID_CLI);
974 ch->mid_recv.mid = htonl (1); /* The OPEN counts as message 0! */
975 if (GNUNET_YES == ch->is_loopback)
976 {
977 ch->state = CADET_CHANNEL_OPEN_SENT;
978 GCCH_handle_channel_open_ack (ch,
979 NULL);
980 }
981 else
982 {
983 /* notify other peer that we accepted the connection */
984 ch->state = CADET_CHANNEL_READY;
985 ch->retry_control_task
986 = GNUNET_SCHEDULER_add_now (&send_open_ack,
987 ch);
988 }
989 /* give client it's initial supply of ACKs */
990 GNUNET_assert (ntohl (cccd->ccn.channel_of_client) <
991 GNUNET_CADET_LOCAL_CHANNEL_ID_CLI);
992 for (unsigned int i=0;i<ch->max_pending_messages;i++)
993 send_ack_to_client (ch,
994 GNUNET_NO);
916} 995}
917 996
918 997
919/** 998/**
920 * Send a message and don't keep any info about it: we won't need to cancel it 999 * One of our clients has disconnected, tell the other one that we
921 * or resend it. 1000 * are finished. Done asynchronously to avoid concurrent modification
1001 * issues if this is the same client.
922 * 1002 *
923 * @param msg Header of the message to fire away. 1003 * @param cls the `struct CadetChannel` where one of the ends is now dead
924 * @param ch Channel on which the message should go.
925 * @param force Is this a forced (undroppable) message?
926 */ 1004 */
927static void 1005static void
928fire_and_forget (const struct GNUNET_MessageHeader *msg, 1006signal_remote_destroy_cb (void *cls)
929 struct CadetChannel *ch,
930 int force)
931{ 1007{
932 GNUNET_break (NULL == 1008 struct CadetChannel *ch = cls;
933 GCT_send_prebuilt_message (msg, ch->t, NULL, 1009 struct CadetChannelClient *ccc;
934 force, NULL, NULL)); 1010
1011 /* Find which end is left... */
1012 ch->retry_control_task = NULL;
1013 ccc = (NULL != ch->owner) ? ch->owner : ch->dest;
1014 GSC_handle_remote_channel_destroy (ccc->c,
1015 ccc->ccn,
1016 ch);
1017 channel_destroy (ch);
935} 1018}
936 1019
937 1020
938/** 1021/**
939 * Notify that a channel create didn't succeed. 1022 * Destroy locally created channel. Called by the local client, so no
1023 * need to tell the client.
940 * 1024 *
941 * @param ch The channel to reject. 1025 * @param ch channel to destroy
1026 * @param c client that caused the destruction
1027 * @param ccn client number of the client @a c
942 */ 1028 */
943static void 1029void
944send_nack (struct CadetChannel *ch) 1030GCCH_channel_local_destroy (struct CadetChannel *ch,
1031 struct CadetClient *c,
1032 struct GNUNET_CADET_ClientChannelNumber ccn)
945{ 1033{
946 struct GNUNET_CADET_ChannelManageMessage msg;
947
948 msg.header.size = htons (sizeof (msg));
949 msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_NACK_DEPRECATED);
950 LOG (GNUNET_ERROR_TYPE_DEBUG, 1034 LOG (GNUNET_ERROR_TYPE_DEBUG,
951 " sending channel NACK for channel %s\n", 1035 "%s asks for destruction of %s\n",
1036 GSC_2s (c),
952 GCCH_2s (ch)); 1037 GCCH_2s (ch));
1038 GNUNET_assert (NULL != c);
1039 if ( (NULL != ch->owner) &&
1040 (c == ch->owner->c) &&
1041 (ccn.channel_of_client == ch->owner->ccn.channel_of_client) )
1042 {
1043 free_channel_client (ch->owner);
1044 ch->owner = NULL;
1045 }
1046 else if ( (NULL != ch->dest) &&
1047 (c == ch->dest->c) &&
1048 (ccn.channel_of_client == ch->dest->ccn.channel_of_client) )
1049 {
1050 free_channel_client (ch->dest);
1051 ch->dest = NULL;
1052 }
1053 else
1054 {
1055 GNUNET_assert (0);
1056 }
953 1057
954 msg.ctn = ch->gid; 1058 if (GNUNET_YES == ch->destroy)
955 GCCH_send_prebuilt_message (&msg.header, ch, GNUNET_NO, NULL);
956}
957
958
959/**
960 * Destroy all reliable messages queued for a channel,
961 * during a channel destruction.
962 * Frees the reliability structure itself.
963 *
964 * @param rel Reliability data for a channel.
965 */
966static void
967channel_rel_free_all (struct CadetChannelReliability *rel)
968{
969 struct CadetReliableMessage *copy;
970 struct CadetReliableMessage *next;
971
972 if (NULL == rel)
973 return;
974
975 for (copy = rel->head_recv; NULL != copy; copy = next)
976 { 1059 {
977 next = copy->next; 1060 /* other end already destroyed, with the local client gone, no need
978 GNUNET_CONTAINER_DLL_remove (rel->head_recv, rel->tail_recv, copy); 1061 to finish transmissions, just destroy immediately. */
979 LOG (GNUNET_ERROR_TYPE_DEBUG, " COPYFREE ALL RECV %p\n", copy); 1062 channel_destroy (ch);
980 GNUNET_break (NULL == copy->chq); 1063 return;
981 GNUNET_free (copy);
982 } 1064 }
983 for (copy = rel->head_sent; NULL != copy; copy = next) 1065 if ( (NULL != ch->head_sent) &&
1066 ( (NULL != ch->owner) ||
1067 (NULL != ch->dest) ) )
984 { 1068 {
985 next = copy->next; 1069 /* Wait for other end to destroy us as well,
986 GNUNET_CONTAINER_DLL_remove (rel->head_sent, rel->tail_sent, copy); 1070 and otherwise allow send queue to be transmitted first */
987 LOG (GNUNET_ERROR_TYPE_DEBUG, " COPYFREE ALL SEND %p\n", copy); 1071 ch->destroy = GNUNET_YES;
988 if (NULL != copy->chq) 1072 return;
989 {
990 if (NULL != copy->chq->tq)
991 {
992 GCT_cancel (copy->chq->tq);
993 /* ch_message_sent will free copy->q */
994 }
995 else
996 {
997 GNUNET_free (copy->chq);
998 GNUNET_break (0);
999 }
1000 }
1001 GNUNET_free (copy);
1002 } 1073 }
1003 if (NULL != rel->uniq && NULL != rel->uniq->tq) 1074 if ( (GNUNET_YES == ch->is_loopback) &&
1075 ( (NULL != ch->owner) ||
1076 (NULL != ch->dest) ) )
1004 { 1077 {
1005 GCT_cancel (rel->uniq->tq); 1078 if (NULL != ch->retry_control_task)
1006 /* ch_message_sent is called freeing uniq */ 1079 GNUNET_SCHEDULER_cancel (ch->retry_control_task);
1080 ch->retry_control_task
1081 = GNUNET_SCHEDULER_add_now (&signal_remote_destroy_cb,
1082 ch);
1083 return;
1007 } 1084 }
1008 if (NULL != rel->retry_task) 1085 if (GNUNET_NO == ch->is_loopback)
1009 { 1086 {
1010 GNUNET_SCHEDULER_cancel (rel->retry_task); 1087 /* If the we ever sent the CHANNEL_CREATE, we need to send a destroy message. */
1011 rel->retry_task = NULL; 1088 switch (ch->state)
1089 {
1090 case CADET_CHANNEL_NEW:
1091 /* We gave up on a channel that we created as a client to a remote
1092 target, but that never went anywhere. Nothing to do here. */
1093 break;
1094 case CADET_CHANNEL_LOOSE:
1095 GSC_drop_loose_channel (&ch->port,
1096 ch);
1097 break;
1098 default:
1099 GCT_send_channel_destroy (ch->t,
1100 ch->ctn);
1101 }
1012 } 1102 }
1013 GNUNET_free (rel); 1103 /* Nothing left to do, just finish destruction */
1104 channel_destroy (ch);
1014} 1105}
1015 1106
1016 1107
1017/** 1108/**
1018 * Mark future messages as ACK'd. 1109 * We got an acknowledgement for the creation of the channel
1019 * 1110 * (the port is open on the other side). Begin transmissions.
1020 * @param rel Reliability data.
1021 * @param msg DataACK message with a bitfield of future ACK'd messages.
1022 * 1111 *
1023 * @return How many messages have been freed. 1112 * @param ch channel to destroy
1113 * @param cti identifier of the connection that delivered the message
1024 */ 1114 */
1025static unsigned int 1115void
1026channel_rel_free_sent (struct CadetChannelReliability *rel, 1116GCCH_handle_channel_open_ack (struct CadetChannel *ch,
1027 const struct GNUNET_CADET_ChannelDataAckMessage *msg) 1117 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti)
1028{ 1118{
1029 struct CadetReliableMessage *copy; 1119 switch (ch->state)
1030 struct CadetReliableMessage *next;
1031 uint64_t bitfield;
1032 uint64_t mask;
1033 uint32_t mid;
1034 uint32_t target;
1035 unsigned int i;
1036 unsigned int r;
1037
1038 bitfield = msg->futures;
1039 mid = ntohl (msg->mid);
1040 LOG (GNUNET_ERROR_TYPE_DEBUG, "free_sent_reliable %u %lX\n", mid, bitfield);
1041 LOG (GNUNET_ERROR_TYPE_DEBUG, " rel %p, head %p\n", rel, rel->head_sent);
1042 for (i = 0, r = 0, copy = rel->head_sent;
1043 i < 64 && NULL != copy && 0 != bitfield;
1044 i++)
1045 { 1120 {
1046 LOG (GNUNET_ERROR_TYPE_DEBUG, " trying bit %u (mid %u)\n", i, mid + i + 1); 1121 case CADET_CHANNEL_NEW:
1047 mask = 0x1LL << i; 1122 /* this should be impossible */
1048 if (0 == (bitfield & mask)) 1123 GNUNET_break (0);
1049 continue; 1124 break;
1050 1125 case CADET_CHANNEL_LOOSE:
1051 LOG (GNUNET_ERROR_TYPE_DEBUG, " set!\n"); 1126 /* This makes no sense. */
1052 /* Bit was set, clear the bit from the bitfield */ 1127 GNUNET_break_op (0);
1053 bitfield &= ~mask; 1128 break;
1054 1129 case CADET_CHANNEL_OPEN_SENT:
1055 /* The i-th bit was set. Do we have that copy? */ 1130 if (NULL == ch->owner)
1056 /* Skip copies with mid < target */
1057 target = mid + i + 1;
1058 LOG (GNUNET_ERROR_TYPE_DEBUG, " target %u\n", target);
1059 while (NULL != copy && GC_is_pid_bigger (target, copy->mid))
1060 copy = copy->next;
1061
1062 /* Did we run out of copies? (previously freed, it's ok) */
1063 if (NULL == copy)
1064 { 1131 {
1065 LOG (GNUNET_ERROR_TYPE_DEBUG, "run out of copies...\n"); 1132 /* We're not the owner, wrong direction! */
1066 return r; 1133 GNUNET_break_op (0);
1134 return;
1067 } 1135 }
1068 1136 LOG (GNUNET_ERROR_TYPE_DEBUG,
1069 /* Did we overshoot the target? (previously freed, it's ok) */ 1137 "Received CHANNEL_OPEN_ACK for waiting %s, entering READY state\n",
1070 if (GC_is_pid_bigger (copy->mid, target)) 1138 GCCH_2s (ch));
1139 if (NULL != ch->retry_control_task) /* can be NULL if ch->is_loopback */
1071 { 1140 {
1072 LOG (GNUNET_ERROR_TYPE_DEBUG, " next copy %u\n", copy->mid); 1141 GNUNET_SCHEDULER_cancel (ch->retry_control_task);
1073 i += copy->mid - target - 1; /* MID: 90, t = 85, i += 4 (i++ later) */ 1142 ch->retry_control_task = NULL;
1074 mask = (0x1LL << (i + 1)) - 1; /* Mask = i-th bit and all before */
1075 bitfield &= ~mask; /* Clear all bits up to MID - 1 */
1076 continue;
1077 } 1143 }
1078 1144 ch->state = CADET_CHANNEL_READY;
1079 /* Now copy->mid == target, free it */ 1145 /* On first connect, send client as many ACKs as we allow messages
1080 next = copy->next; 1146 to be buffered! */
1081 GNUNET_break (GNUNET_YES != rel_message_free (copy, GNUNET_YES)); 1147 for (unsigned int i=0;i<ch->max_pending_messages;i++)
1082 r++; 1148 send_ack_to_client (ch,
1083 copy = next; 1149 GNUNET_YES);
1150 break;
1151 case CADET_CHANNEL_READY:
1152 /* duplicate ACK, maybe we retried the CREATE. Ignore. */
1153 LOG (GNUNET_ERROR_TYPE_DEBUG,
1154 "Received duplicate channel OPEN_ACK for %s\n",
1155 GCCH_2s (ch));
1156 GNUNET_STATISTICS_update (stats,
1157 "# duplicate CREATE_ACKs",
1158 1,
1159 GNUNET_NO);
1160 break;
1084 } 1161 }
1085 LOG (GNUNET_ERROR_TYPE_DEBUG, "free_sent_reliable END\n");
1086 return r;
1087} 1162}
1088 1163
1089 1164
1090/** 1165/**
1091 * Destroy a reliable message after it has been acknowledged, either by 1166 * Test if element @a e1 comes before element @a e2.
1092 * direct mid ACK or bitfield. Updates the appropriate data structures and
1093 * timers and frees all memory.
1094 * 1167 *
1095 * @param copy Message that is no longer needed: remote peer got it. 1168 * @param cls closure, to a flag where we indicate duplicate packets
1096 * @param update_time Is the timing information relevant? 1169 * @param m1 a message of to sort
1097 * If this message is ACK in a batch the timing information 1170 * @param m2 another message to sort
1098 * is skewed by the retransmission, count only for the 1171 * @return #GNUNET_YES if @e1 < @e2, otherwise #GNUNET_NO
1099 * retransmitted message.
1100 *
1101 * @return #GNUNET_YES if channel was destroyed as a result of the call,
1102 * #GNUNET_NO otherwise.
1103 */ 1172 */
1104static int 1173static int
1105rel_message_free (struct CadetReliableMessage *copy, int update_time) 1174is_before (void *cls,
1175 struct CadetOutOfOrderMessage *m1,
1176 struct CadetOutOfOrderMessage *m2)
1106{ 1177{
1107 struct CadetChannelReliability *rel; 1178 int *duplicate = cls;
1108 struct GNUNET_TIME_Relative time; 1179 uint32_t v1 = ntohl (m1->mid.mid);
1180 uint32_t v2 = ntohl (m2->mid.mid);
1181 uint32_t delta;
1109 1182
1110 rel = copy->rel; 1183 delta = v2 - v1;
1111 LOG (GNUNET_ERROR_TYPE_DEBUG, "Freeing %u\n", copy->mid); 1184 if (0 == delta)
1112 if (GNUNET_YES == update_time) 1185 *duplicate = GNUNET_YES;
1186 if (delta > (uint32_t) INT_MAX)
1113 { 1187 {
1114 time = GNUNET_TIME_absolute_get_duration (copy->timestamp); 1188 /* in overflow range, we can safely assume we wrapped around */
1115 if (0 == rel->expected_delay.rel_value_us) 1189 return GNUNET_NO;
1116 rel->expected_delay = time;
1117 else
1118 {
1119 rel->expected_delay.rel_value_us *= 7;
1120 rel->expected_delay.rel_value_us += time.rel_value_us;
1121 rel->expected_delay.rel_value_us /= 8;
1122 }
1123 LOG (GNUNET_ERROR_TYPE_DEBUG, " message time %12s\n",
1124 GNUNET_STRINGS_relative_time_to_string (time, GNUNET_NO));
1125 LOG (GNUNET_ERROR_TYPE_DEBUG, " new delay %12s\n",
1126 GNUNET_STRINGS_relative_time_to_string (rel->expected_delay,
1127 GNUNET_NO));
1128 rel->retry_timer = rel->expected_delay;
1129 } 1190 }
1130 else 1191 else
1131 { 1192 {
1132 LOG (GNUNET_ERROR_TYPE_DEBUG, "batch free, ignoring timing\n"); 1193 /* result is small, thus v2 > v1, thus m1 < m2 */
1133 }
1134 rel->ch->pending_messages--;
1135 if (NULL != copy->chq)
1136 {
1137 GCT_cancel (copy->chq->tq);
1138 /* copy->q is set to NULL by ch_message_sent */
1139 }
1140 GNUNET_CONTAINER_DLL_remove (rel->head_sent, rel->tail_sent, copy);
1141 LOG (GNUNET_ERROR_TYPE_DEBUG, " free send copy MID %u at %p\n",
1142 copy->mid, copy);
1143 GNUNET_free (copy);
1144
1145 if (GNUNET_NO != rel->ch->destroy && 0 == rel->ch->pending_messages)
1146 {
1147 GCCH_destroy (rel->ch);
1148 return GNUNET_YES; 1194 return GNUNET_YES;
1149 } 1195 }
1150 return GNUNET_NO;
1151} 1196}
1152 1197
1153 1198
1154/** 1199/**
1155 * Channel was ACK'd by remote peer, mark as ready and cancel retransmission. 1200 * We got payload data for a channel. Pass it on to the client
1201 * and send an ACK to the other end (once flow control allows it!)
1156 * 1202 *
1157 * @param ch Channel to mark as ready. 1203 * @param ch channel that got data
1158 * @param fwd Was the ACK message a FWD ACK? (dest->root, SYNACK) 1204 * @param cti identifier of the connection that delivered the message
1205 * @param msg message that was received
1159 */ 1206 */
1160static void 1207void
1161channel_confirm (struct CadetChannel *ch, int fwd) 1208GCCH_handle_channel_plaintext_data (struct CadetChannel *ch,
1209 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
1210 const struct GNUNET_CADET_ChannelAppDataMessage *msg)
1162{ 1211{
1163 struct CadetChannelReliability *rel; 1212 struct GNUNET_MQ_Envelope *env;
1164 enum CadetChannelState oldstate; 1213 struct GNUNET_CADET_LocalData *ld;
1165 1214 struct CadetChannelClient *ccc;
1166 rel = fwd ? ch->root_rel : ch->dest_rel; 1215 size_t payload_size;
1167 if (NULL == rel) 1216 struct CadetOutOfOrderMessage *com;
1217 int duplicate;
1218 uint32_t mid_min;
1219 uint32_t mid_max;
1220 uint32_t mid_msg;
1221 uint32_t delta;
1222
1223 GNUNET_assert (GNUNET_NO == ch->is_loopback);
1224 if ( (GNUNET_YES == ch->destroy) &&
1225 (NULL == ch->owner) &&
1226 (NULL == ch->dest) )
1227 {
1228 /* This client is gone, but we still have messages to send to
1229 the other end (which is why @a ch is not yet dead). However,
1230 we cannot pass messages to our client anymore. */
1231 LOG (GNUNET_ERROR_TYPE_DEBUG,
1232 "Dropping incoming payload on %s as this end is already closed\n",
1233 GCCH_2s (ch));
1234 /* send back DESTROY notification to stop further retransmissions! */
1235 GCT_send_channel_destroy (ch->t,
1236 ch->ctn);
1237 return;
1238 }
1239 payload_size = ntohs (msg->header.size) - sizeof (*msg);
1240 env = GNUNET_MQ_msg_extra (ld,
1241 payload_size,
1242 GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA);
1243 ld->ccn = (NULL == ch->dest) ? ch->owner->ccn : ch->dest->ccn;
1244 GNUNET_memcpy (&ld[1],
1245 &msg[1],
1246 payload_size);
1247 ccc = (NULL != ch->owner) ? ch->owner : ch->dest;
1248 if ( (GNUNET_YES == ccc->client_ready) &&
1249 ( (GNUNET_YES == ch->out_of_order) ||
1250 (msg->mid.mid == ch->mid_recv.mid) ) )
1168 { 1251 {
1169 GNUNET_break (GNUNET_NO != ch->destroy); 1252 LOG (GNUNET_ERROR_TYPE_DEBUG,
1253 "Giving %u bytes of payload with MID %u from %s to client %s\n",
1254 (unsigned int) payload_size,
1255 ntohl (msg->mid.mid),
1256 GCCH_2s (ch),
1257 GSC_2s (ccc->c));
1258 ccc->client_ready = GNUNET_NO;
1259 GSC_send_to_client (ccc->c,
1260 env);
1261 ch->mid_recv.mid = htonl (1 + ntohl (ch->mid_recv.mid));
1262 ch->mid_futures >>= 1;
1263 send_channel_data_ack (ch);
1170 return; 1264 return;
1171 } 1265 }
1172 LOG (GNUNET_ERROR_TYPE_DEBUG, " channel confirm %s %s\n",
1173 GC_f2s (fwd), GCCH_2s (ch));
1174 oldstate = ch->state;
1175 ch->state = CADET_CHANNEL_READY;
1176 1266
1177 if (CADET_CHANNEL_READY != oldstate || GNUNET_YES == is_loopback (ch)) 1267 if (GNUNET_YES == ch->reliable)
1178 { 1268 {
1179 rel->client_ready = GNUNET_YES; 1269 /* check if message ought to be dropped because it is ancient/too distant/duplicate */
1180 rel->expected_delay = rel->retry_timer; 1270 mid_min = ntohl (ch->mid_recv.mid);
1181 LOG (GNUNET_ERROR_TYPE_DEBUG, " confirm retry timer %s\n", 1271 mid_max = mid_min + ch->max_pending_messages;
1182 GNUNET_STRINGS_relative_time_to_string (rel->retry_timer, GNUNET_NO)); 1272 mid_msg = ntohl (msg->mid.mid);
1183 if (GCT_get_connections_buffer (ch->t) > 0 || GCT_is_loopback (ch->t)) 1273 if ( ( (uint32_t) (mid_msg - mid_min) > ch->max_pending_messages) ||
1184 send_client_ack (ch, fwd); 1274 ( (uint32_t) (mid_max - mid_msg) > ch->max_pending_messages) )
1185
1186 if (NULL != rel->retry_task)
1187 { 1275 {
1188 GNUNET_SCHEDULER_cancel (rel->retry_task); 1276 LOG (GNUNET_ERROR_TYPE_DEBUG,
1189 rel->retry_task = NULL; 1277 "%s at %u drops ancient or far-future message %u\n",
1190 } 1278 GCCH_2s (ch),
1191 else if (NULL != rel->uniq) 1279 (unsigned int) mid_min,
1192 { 1280 ntohl (msg->mid.mid));
1193 GCT_cancel (rel->uniq->tq); 1281
1194 /* ch_message_sent will free and NULL uniq */ 1282 GNUNET_STATISTICS_update (stats,
1283 "# duplicate DATA (ancient or future)",
1284 1,
1285 GNUNET_NO);
1286 GNUNET_MQ_discard (env);
1287 send_channel_data_ack (ch);
1288 return;
1195 } 1289 }
1196 else if (GNUNET_NO == is_loopback (ch)) 1290 /* mark bit for future ACKs */
1291 delta = mid_msg - mid_min - 1; /* overflow/underflow are OK here */
1292 if (delta < 64)
1197 { 1293 {
1198 /* We SHOULD have been trying to retransmit this! */ 1294 if (0 != (ch->mid_futures & (1LLU << delta)))
1199 GNUNET_break (0); 1295 {
1296 /* Duplicate within the queue, drop also */
1297 LOG (GNUNET_ERROR_TYPE_DEBUG,
1298 "Duplicate payload of %u bytes on %s (mid %u) dropped\n",
1299 (unsigned int) payload_size,
1300 GCCH_2s (ch),
1301 ntohl (msg->mid.mid));
1302 GNUNET_STATISTICS_update (stats,
1303 "# duplicate DATA",
1304 1,
1305 GNUNET_NO);
1306 GNUNET_MQ_discard (env);
1307 send_channel_data_ack (ch);
1308 return;
1309 }
1310 ch->mid_futures |= (1LLU << delta);
1311 LOG (GNUNET_ERROR_TYPE_DEBUG,
1312 "Marked bit %llX for mid %u (base: %u); now: %llX\n",
1313 (1LLU << delta),
1314 mid_msg,
1315 mid_min,
1316 ch->mid_futures);
1200 } 1317 }
1201 } 1318 }
1202 1319 else /* ! ch->reliable */
1203 /* In case of a FWD ACK (SYNACK) send a BCK ACK (ACK). */
1204 if (GNUNET_YES == fwd)
1205 send_ack (ch, GNUNET_NO);
1206}
1207
1208
1209/**
1210 * Save a copy to retransmit in case it gets lost.
1211 *
1212 * Initializes all needed callbacks and timers.
1213 *
1214 * @param ch Channel this message goes on.
1215 * @param msg Message to copy.
1216 * @param fwd Is this fwd traffic?
1217 */
1218static struct CadetReliableMessage *
1219channel_save_copy (struct CadetChannel *ch,
1220 const struct GNUNET_MessageHeader *msg,
1221 int fwd)
1222{
1223 struct CadetChannelReliability *rel;
1224 struct CadetReliableMessage *copy;
1225 uint32_t mid;
1226 uint16_t type;
1227 uint16_t size;
1228
1229 rel = fwd ? ch->root_rel : ch->dest_rel;
1230 mid = rel->mid_send - 1;
1231 type = ntohs (msg->type);
1232 size = ntohs (msg->size);
1233
1234 LOG (GNUNET_ERROR_TYPE_DEBUG, "save MID %u %s\n", mid, GC_m2s (type));
1235 copy = GNUNET_malloc (sizeof (struct CadetReliableMessage) + size);
1236 LOG (GNUNET_ERROR_TYPE_DEBUG, " at %p\n", copy);
1237 copy->mid = mid;
1238 copy->rel = rel;
1239 copy->type = type;
1240 GNUNET_memcpy (&copy[1], msg, size);
1241 GNUNET_CONTAINER_DLL_insert_tail (rel->head_sent, rel->tail_sent, copy);
1242 ch->pending_messages++;
1243
1244 return copy;
1245}
1246
1247
1248/**
1249 * Create a new channel.
1250 *
1251 * @param t Tunnel this channel is in.
1252 * @param owner Client that owns the channel, NULL for foreign channels.
1253 * @param lid_root Local ID for root client.
1254 *
1255 * @return A new initialized channel. NULL on error.
1256 */
1257static struct CadetChannel *
1258channel_new (struct CadetTunnel *t,
1259 struct CadetClient *owner,
1260 struct GNUNET_CADET_ClientChannelNumber lid_root)
1261{
1262 struct CadetChannel *ch;
1263
1264 ch = GNUNET_new (struct CadetChannel);
1265 ch->root = owner;
1266 ch->lid_root = lid_root;
1267 ch->t = t;
1268
1269 GNUNET_STATISTICS_update (stats, "# channels", 1, GNUNET_NO);
1270
1271 if (NULL != owner)
1272 {
1273 ch->gid = GCT_get_next_ctn (t);
1274 GML_channel_add (owner, lid_root, ch);
1275 }
1276 GCT_add_channel (t, ch);
1277
1278 return ch;
1279}
1280
1281
1282/**
1283 * Handle a loopback message: call the appropriate handler for the message type.
1284 *
1285 * @param ch Channel this message is on.
1286 * @param msgh Message header.
1287 * @param fwd Is this FWD traffic?
1288 */
1289void
1290handle_loopback (struct CadetChannel *ch,
1291 const struct GNUNET_MessageHeader *msgh,
1292 int fwd)
1293{
1294 uint16_t type;
1295
1296 type = ntohs (msgh->type);
1297 LOG (GNUNET_ERROR_TYPE_DEBUG,
1298 "Loopback %s %s message!\n",
1299 GC_f2s (fwd), GC_m2s (type));
1300
1301 switch (type)
1302 { 1320 {
1303 case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA: 1321 /* Channel is unreliable, so we do not ACK. But we also cannot
1304 /* Don't send hop ACK, wait for client to ACK */ 1322 allow buffering everything, so check if we have space... */
1305 LOG (GNUNET_ERROR_TYPE_DEBUG, "SEND loopback %u (%u)\n", 1323 if (ccc->num_recv >= ch->max_pending_messages)
1306 ntohl (((struct GNUNET_CADET_ChannelAppDataMessage *) msgh)->mid), ntohs (msgh->size)); 1324 {
1307 GCCH_handle_data (ch, (struct GNUNET_CADET_ChannelAppDataMessage *) msgh, fwd); 1325 struct CadetOutOfOrderMessage *drop;
1308 break;
1309
1310 case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK:
1311 GCCH_handle_data_ack (ch,
1312 (const struct GNUNET_CADET_ChannelDataAckMessage *) msgh, fwd);
1313 break;
1314
1315 case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN:
1316 GCCH_handle_create (ch->t,
1317 (const struct GNUNET_CADET_ChannelOpenMessage *) msgh);
1318 break;
1319
1320 case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK:
1321 GCCH_handle_ack (ch,
1322 (const struct GNUNET_CADET_ChannelManageMessage *) msgh,
1323 fwd);
1324 break;
1325
1326 case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_NACK_DEPRECATED:
1327 GCCH_handle_nack (ch);
1328 break;
1329
1330 case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY:
1331 GCCH_handle_destroy (ch,
1332 (const struct GNUNET_CADET_ChannelManageMessage *) msgh,
1333 fwd);
1334 break;
1335 1326
1336 default: 1327 /* Yep, need to drop. Drop the oldest message in
1337 GNUNET_break_op (0); 1328 the buffer. */
1338 LOG (GNUNET_ERROR_TYPE_DEBUG, 1329 LOG (GNUNET_ERROR_TYPE_DEBUG,
1339 "end-to-end message not known (%u)\n", 1330 "Queue full due slow client on %s, dropping oldest message\n",
1340 ntohs (msgh->type)); 1331 GCCH_2s (ch));
1332 GNUNET_STATISTICS_update (stats,
1333 "# messages dropped due to slow client",
1334 1,
1335 GNUNET_NO);
1336 drop = ccc->head_recv;
1337 GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
1338 ccc->tail_recv,
1339 drop);
1340 ccc->num_recv--;
1341 GNUNET_MQ_discard (drop->env);
1342 GNUNET_free (drop);
1343 }
1341 } 1344 }
1342}
1343
1344
1345
1346/******************************************************************************/
1347/******************************** API ***********************************/
1348/******************************************************************************/
1349
1350/**
1351 * Destroy a channel and free all resources.
1352 *
1353 * @param ch Channel to destroy.
1354 */
1355void
1356GCCH_destroy (struct CadetChannel *ch)
1357{
1358 struct CadetClient *c;
1359 struct CadetTunnel *t;
1360 1345
1361 if (NULL == ch) 1346 /* Insert message into sorted out-of-order queue */
1347 com = GNUNET_new (struct CadetOutOfOrderMessage);
1348 com->mid = msg->mid;
1349 com->env = env;
1350 duplicate = GNUNET_NO;
1351 GNUNET_CONTAINER_DLL_insert_sorted (struct CadetOutOfOrderMessage,
1352 is_before,
1353 &duplicate,
1354 ccc->head_recv,
1355 ccc->tail_recv,
1356 com);
1357 ccc->num_recv++;
1358 if (GNUNET_YES == duplicate)
1359 {
1360 /* Duplicate within the queue, drop also (this is not covered by
1361 the case above if "delta" >= 64, which could be the case if
1362 max_pending_messages is also >= 64 or if our client is unready
1363 and we are seeing retransmissions of the message our client is
1364 blocked on. */
1365 LOG (GNUNET_ERROR_TYPE_DEBUG,
1366 "Duplicate payload of %u bytes on %s (mid %u) dropped\n",
1367 (unsigned int) payload_size,
1368 GCCH_2s (ch),
1369 ntohl (msg->mid.mid));
1370 GNUNET_STATISTICS_update (stats,
1371 "# duplicate DATA",
1372 1,
1373 GNUNET_NO);
1374 GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
1375 ccc->tail_recv,
1376 com);
1377 ccc->num_recv--;
1378 GNUNET_MQ_discard (com->env);
1379 GNUNET_free (com);
1380 send_channel_data_ack (ch);
1362 return; 1381 return;
1363 if (2 == ch->destroy)
1364 return; /* recursive call */
1365 ch->destroy = 2;
1366
1367 LOG (GNUNET_ERROR_TYPE_DEBUG, "destroying channel %s:%u\n",
1368 GCT_2s (ch->t), ch->gid);
1369 GCCH_debug (ch, GNUNET_ERROR_TYPE_DEBUG);
1370
1371 c = ch->root;
1372 if (NULL != c)
1373 {
1374 GML_channel_remove (c, ch->lid_root, ch);
1375 }
1376
1377 c = ch->dest;
1378 if (NULL != c)
1379 {
1380 GML_channel_remove (c, ch->lid_dest, ch);
1381 } 1382 }
1382 1383 LOG (GNUNET_ERROR_TYPE_DEBUG,
1383 channel_rel_free_all (ch->root_rel); 1384 "Queued %s payload of %u bytes on %s-%X(%p) (mid %u, need %u first)\n",
1384 channel_rel_free_all (ch->dest_rel); 1385 (GNUNET_YES == ccc->client_ready)
1385 1386 ? "out-of-order"
1386 t = ch->t; 1387 : "client-not-ready",
1387 GCT_remove_channel (t, ch); 1388 (unsigned int) payload_size,
1388 GNUNET_STATISTICS_update (stats, "# channels", -1, GNUNET_NO); 1389 GCCH_2s (ch),
1389 1390 ntohl (ccc->ccn.channel_of_client),
1390 GNUNET_free (ch); 1391 ccc,
1391 GCT_destroy_if_empty (t); 1392 ntohl (msg->mid.mid),
1392} 1393 ntohl (ch->mid_recv.mid));
1393 1394 /* NOTE: this ACK we _could_ skip, as the packet is out-of-order and
1394 1395 the sender may already be transmitting the previous one. Needs
1395/** 1396 experimental evaluation to see if/when this ACK helps or
1396 * Get the channel's public ID. 1397 hurts. (We might even want another option.) */
1397 * 1398 send_channel_data_ack (ch);
1398 * @param ch Channel.
1399 *
1400 * @return ID used to identify the channel with the remote peer.
1401 */
1402struct GNUNET_CADET_ChannelTunnelNumber
1403GCCH_get_id (const struct CadetChannel *ch)
1404{
1405 return ch->gid;
1406}
1407
1408
1409/**
1410 * Get the channel tunnel.
1411 *
1412 * @param ch Channel to get the tunnel from.
1413 *
1414 * @return tunnel of the channel.
1415 */
1416struct CadetTunnel *
1417GCCH_get_tunnel (const struct CadetChannel *ch)
1418{
1419 return ch->t;
1420}
1421
1422
1423/**
1424 * Get free buffer space towards the client on a specific channel.
1425 *
1426 * @param ch Channel.
1427 * @param fwd Is query about FWD traffic?
1428 *
1429 * @return Free buffer space [0 - 64]
1430 */
1431unsigned int
1432GCCH_get_buffer (struct CadetChannel *ch, int fwd)
1433{
1434 struct CadetChannelReliability *rel;
1435
1436 rel = fwd ? ch->dest_rel : ch->root_rel;
1437 LOG (GNUNET_ERROR_TYPE_DEBUG, " get buffer, channel %s\n", GCCH_2s (ch));
1438 GCCH_debug (ch, GNUNET_ERROR_TYPE_DEBUG);
1439 /* If rel is NULL it means that the end is not yet created,
1440 * most probably is a loopback channel at the point of sending
1441 * the ChannelCreate to itself.
1442 */
1443 if (NULL == rel)
1444 {
1445 LOG (GNUNET_ERROR_TYPE_DEBUG, " rel is NULL: max\n");
1446 return 64;
1447 }
1448
1449 LOG (GNUNET_ERROR_TYPE_DEBUG, " n_recv %d\n", rel->n_recv);
1450 return (64 - rel->n_recv);
1451}
1452
1453
1454/**
1455 * Get flow control status of end point: is client allow to send?
1456 *
1457 * @param ch Channel.
1458 * @param fwd Is query about FWD traffic? (Request root status).
1459 *
1460 * @return #GNUNET_YES if client is allowed to send us data.
1461 */
1462int
1463GCCH_get_allowed (struct CadetChannel *ch, int fwd)
1464{
1465 struct CadetChannelReliability *rel;
1466
1467 rel = fwd ? ch->root_rel : ch->dest_rel;
1468
1469 if (NULL == rel)
1470 {
1471 /* Probably shutting down: root/dest NULL'ed to mark disconnection */
1472 GNUNET_break (GNUNET_NO != ch->destroy);
1473 return 0;
1474 }
1475
1476 return rel->client_allowed;
1477} 1399}
1478 1400
1479 1401
1480/** 1402/**
1481 * Is the root client for this channel on this peer? 1403 * Function called once the tunnel has sent one of our messages.
1482 * 1404 * If the message is unreliable, simply frees the `crm`. If the
1483 * @param ch Channel. 1405 * message was reliable, calculate retransmission time and
1484 * @param fwd Is this for fwd traffic? 1406 * wait for ACK (or retransmit).
1485 * 1407 *
1486 * @return #GNUNET_YES in case it is. 1408 * @param cls the `struct CadetReliableMessage` that was sent
1409 * @param cid identifier of the connection within the tunnel, NULL
1410 * if transmission failed
1487 */ 1411 */
1488int 1412static void
1489GCCH_is_origin (struct CadetChannel *ch, int fwd) 1413data_sent_cb (void *cls,
1490{ 1414 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid);
1491 struct CadetClient *c;
1492
1493 c = fwd ? ch->root : ch->dest;
1494 return NULL != c;
1495}
1496 1415
1497 1416
1498/** 1417/**
1499 * Is the destination client for this channel on this peer? 1418 * We need to retry a transmission, the last one took too long to
1500 * 1419 * be acknowledged.
1501 * @param ch Channel.
1502 * @param fwd Is this for fwd traffic?
1503 * 1420 *
1504 * @return #GNUNET_YES in case it is. 1421 * @param cls the `struct CadetChannel` where we need to retransmit
1505 */ 1422 */
1506int 1423static void
1507GCCH_is_terminal (struct CadetChannel *ch, int fwd) 1424retry_transmission (void *cls)
1508{ 1425{
1509 struct CadetClient *c; 1426 struct CadetChannel *ch = cls;
1427 struct CadetReliableMessage *crm = ch->head_sent;
1510 1428
1511 c = fwd ? ch->dest : ch->root; 1429 ch->retry_data_task = NULL;
1512 return NULL != c; 1430 GNUNET_assert (NULL == crm->qe);
1431 LOG (GNUNET_ERROR_TYPE_DEBUG,
1432 "Retrying transmission on %s of message %u\n",
1433 GCCH_2s (ch),
1434 (unsigned int) ntohl (crm->data_message->mid.mid));
1435 crm->qe = GCT_send (ch->t,
1436 &crm->data_message->header,
1437 &data_sent_cb,
1438 crm);
1439 GNUNET_assert (NULL == ch->retry_data_task);
1513} 1440}
1514 1441
1515 1442
1516/** 1443/**
1517 * Send an end-to-end ACK message for the most recent in-sequence payload. 1444 * We got an PLAINTEXT_DATA_ACK for a message in our queue, remove it from
1445 * the queue and tell our client that it can send more.
1518 * 1446 *
1519 * If channel is not reliable, do nothing. 1447 * @param ch the channel that got the PLAINTEXT_DATA_ACK
1520 * 1448 * @param cti identifier of the connection that delivered the message
1521 * @param ch Channel this is about. 1449 * @param crm the message that got acknowledged
1522 * @param fwd Is for FWD traffic? (ACK dest->owner)
1523 */ 1450 */
1524void 1451static void
1525GCCH_send_data_ack (struct CadetChannel *ch, int fwd) 1452handle_matching_ack (struct CadetChannel *ch,
1453 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
1454 struct CadetReliableMessage *crm)
1526{ 1455{
1527 struct GNUNET_CADET_ChannelDataAckMessage msg; 1456 GNUNET_CONTAINER_DLL_remove (ch->head_sent,
1528 struct CadetChannelReliability *rel; 1457 ch->tail_sent,
1529 struct CadetReliableMessage *copy; 1458 crm);
1530 unsigned int delta; 1459 ch->pending_messages--;
1531 uint64_t mask; 1460 GNUNET_assert (ch->pending_messages < ch->max_pending_messages);
1532 uint32_t ack; 1461 LOG (GNUNET_ERROR_TYPE_DEBUG,
1533 1462 "Received DATA_ACK on %s for message %u (%u ACKs pending)\n",
1534 if (GNUNET_NO == ch->reliable) 1463 GCCH_2s (ch),
1535 return; 1464 (unsigned int) ntohl (crm->data_message->mid.mid),
1536 1465 ch->pending_messages);
1537 rel = fwd ? ch->dest_rel : ch->root_rel; 1466 if (NULL != crm->qe)
1538 ack = rel->mid_recv - 1; 1467 {
1539 1468 GCT_send_cancel (crm->qe);
1540 msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK); 1469 crm->qe = NULL;
1541 msg.header.size = htons (sizeof (msg)); 1470 }
1542 msg.ctn = ch->gid; 1471 if ( (1 == crm->num_transmissions) &&
1543 msg.mid = htonl (ack); 1472 (NULL != cti) )
1544 1473 {
1545 msg.futures = 0LL; 1474 GCC_ack_observed (cti);
1546 for (copy = rel->head_recv; NULL != copy; copy = copy->next) 1475 if (0 == memcmp (cti,
1547 { 1476 &crm->connection_taken,
1548 if (copy->type != GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA) 1477 sizeof (struct GNUNET_CADET_ConnectionTunnelIdentifier)))
1549 { 1478 {
1550 LOG (GNUNET_ERROR_TYPE_DEBUG, " Type %s, expected DATA\n", 1479 GCC_latency_observed (cti,
1551 GC_m2s (copy->type)); 1480 GNUNET_TIME_absolute_get_duration (crm->first_transmission_time));
1552 continue;
1553 } 1481 }
1554 GNUNET_assert (GC_is_pid_bigger(copy->mid, ack));
1555 delta = copy->mid - (ack + 1);
1556 if (63 < delta)
1557 break;
1558 mask = 0x1LL << delta;
1559 msg.futures |= mask;
1560 LOG (GNUNET_ERROR_TYPE_DEBUG,
1561 " setting bit for %u (delta %u) (%lX) -> %lX\n",
1562 copy->mid, delta, mask, msg.futures);
1563 } 1482 }
1564 1483 GNUNET_free (crm->data_message);
1565 GCCH_send_prebuilt_message (&msg.header, ch, !fwd, NULL); 1484 GNUNET_free (crm);
1566 LOG (GNUNET_ERROR_TYPE_DEBUG, "send_data_ack END\n"); 1485 send_ack_to_client (ch,
1486 (NULL == ch->owner)
1487 ? GNUNET_NO
1488 : GNUNET_YES);
1567} 1489}
1568 1490
1569 1491
1570/** 1492/**
1571 * Allow a client to send us more data, in case it was choked. 1493 * We got an acknowledgement for payload data for a channel.
1494 * Possibly resume transmissions.
1572 * 1495 *
1573 * @param ch Channel. 1496 * @param ch channel that got the ack
1574 * @param fwd Is this about FWD traffic? (Root client). 1497 * @param cti identifier of the connection that delivered the message
1498 * @param ack details about what was received
1575 */ 1499 */
1576void 1500void
1577GCCH_allow_client (struct CadetChannel *ch, int fwd) 1501GCCH_handle_channel_plaintext_data_ack (struct CadetChannel *ch,
1502 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
1503 const struct GNUNET_CADET_ChannelDataAckMessage *ack)
1578{ 1504{
1579 struct CadetChannelReliability *rel; 1505 struct CadetReliableMessage *crm;
1580 unsigned int buffer; 1506 struct CadetReliableMessage *crmn;
1581 1507 int found;
1582 LOG (GNUNET_ERROR_TYPE_DEBUG, "GMCH allow\n"); 1508 uint32_t mid_base;
1509 uint64_t mid_mask;
1510 unsigned int delta;
1583 1511
1584 if (CADET_CHANNEL_READY != ch->state) 1512 GNUNET_break (GNUNET_NO == ch->is_loopback);
1513 if (GNUNET_NO == ch->reliable)
1585 { 1514 {
1586 LOG (GNUNET_ERROR_TYPE_DEBUG, " channel not ready yet!\n"); 1515 /* not expecting ACKs on unreliable channel, odd */
1516 GNUNET_break_op (0);
1587 return; 1517 return;
1588 } 1518 }
1589 1519 /* mid_base is the MID of the next message that the
1590 if (GNUNET_YES == ch->reliable) 1520 other peer expects (i.e. that is missing!), everything
1591 { 1521 LOWER (but excluding mid_base itself) was received. */
1592 rel = fwd ? ch->root_rel : ch->dest_rel; 1522 mid_base = ntohl (ack->mid.mid);
1593 if (NULL == rel) 1523 mid_mask = GNUNET_htonll (ack->futures);
1594 { 1524 found = GNUNET_NO;
1595 GNUNET_break (GNUNET_NO != ch->destroy); 1525 for (crm = ch->head_sent;
1596 return; 1526 NULL != crm;
1597 } 1527 crm = crmn)
1598 if (NULL != rel->head_sent) 1528 {
1529 crmn = crm->next;
1530 delta = (unsigned int) (ntohl (crm->data_message->mid.mid) - mid_base);
1531 if (delta >= UINT_MAX - ch->max_pending_messages)
1599 { 1532 {
1600 if (64 <= rel->mid_send - rel->head_sent->mid) 1533 /* overflow, means crm was a bit in the past, so this ACK counts for it. */
1601 { 1534 LOG (GNUNET_ERROR_TYPE_DEBUG,
1602 LOG (GNUNET_ERROR_TYPE_DEBUG, " too big MID gap! Wait for ACK.\n"); 1535 "Got DATA_ACK with base %u satisfying past message %u on %s\n",
1603 return; 1536 (unsigned int) mid_base,
1604 } 1537 ntohl (crm->data_message->mid.mid),
1605 else 1538 GCCH_2s (ch));
1606 { 1539 handle_matching_ack (ch,
1607 LOG (GNUNET_ERROR_TYPE_DEBUG, " gap ok: %u - %u\n", 1540 cti,
1608 rel->head_sent->mid, rel->mid_send); 1541 crm);
1609 struct CadetReliableMessage *aux; 1542 found = GNUNET_YES;
1610 for (aux = rel->head_sent; NULL != aux; aux = aux->next) 1543 continue;
1611 {
1612 LOG (GNUNET_ERROR_TYPE_DEBUG, " - sent mid %u\n", aux->mid);
1613 }
1614 }
1615 } 1544 }
1616 else 1545 delta--;
1546 if (delta >= 64)
1547 continue;
1548 LOG (GNUNET_ERROR_TYPE_DEBUG,
1549 "Testing bit %llX for mid %u (base: %u)\n",
1550 (1LLU << delta),
1551 ntohl (crm->data_message->mid.mid),
1552 mid_base);
1553 if (0 != (mid_mask & (1LLU << delta)))
1617 { 1554 {
1618 LOG (GNUNET_ERROR_TYPE_DEBUG, " head sent is NULL\n"); 1555 LOG (GNUNET_ERROR_TYPE_DEBUG,
1556 "Got DATA_ACK with mask for %u on %s\n",
1557 ntohl (crm->data_message->mid.mid),
1558 GCCH_2s (ch));
1559 handle_matching_ack (ch,
1560 cti,
1561 crm);
1562 found = GNUNET_YES;
1619 } 1563 }
1620 } 1564 }
1621 1565 if (GNUNET_NO == found)
1622 if (is_loopback (ch))
1623 buffer = GCCH_get_buffer (ch, fwd);
1624 else
1625 buffer = GCT_get_connections_buffer (ch->t);
1626
1627 if (0 == buffer)
1628 { 1566 {
1629 LOG (GNUNET_ERROR_TYPE_DEBUG, " no buffer space.\n"); 1567 /* ACK for message we already dropped, might have been a
1568 duplicate ACK? Ignore. */
1569 LOG (GNUNET_ERROR_TYPE_DEBUG,
1570 "Duplicate DATA_ACK on %s, ignoring\n",
1571 GCCH_2s (ch));
1572 GNUNET_STATISTICS_update (stats,
1573 "# duplicate DATA_ACKs",
1574 1,
1575 GNUNET_NO);
1630 return; 1576 return;
1631 } 1577 }
1632 1578 if (NULL != ch->retry_data_task)
1633 LOG (GNUNET_ERROR_TYPE_DEBUG, " buffer space %u, allowing\n", buffer); 1579 {
1634 send_client_ack (ch, fwd); 1580 GNUNET_SCHEDULER_cancel (ch->retry_data_task);
1581 ch->retry_data_task = NULL;
1582 }
1583 if ( (NULL != ch->head_sent) &&
1584 (NULL == ch->head_sent->qe) )
1585 ch->retry_data_task
1586 = GNUNET_SCHEDULER_add_at (ch->head_sent->next_retry,
1587 &retry_transmission,
1588 ch);
1635} 1589}
1636 1590
1637 1591
1638/** 1592/**
1639 * Log channel info. 1593 * Destroy channel, based on the other peer closing the
1594 * connection. Also needs to remove this channel from
1595 * the tunnel.
1640 * 1596 *
1641 * @param ch Channel. 1597 * @param ch channel to destroy
1642 * @param level Debug level to use. 1598 * @param cti identifier of the connection that delivered the message,
1599 * NULL if we are simulating receiving a destroy due to shutdown
1643 */ 1600 */
1644void 1601void
1645GCCH_debug (struct CadetChannel *ch, enum GNUNET_ErrorType level) 1602GCCH_handle_remote_destroy (struct CadetChannel *ch,
1603 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti)
1646{ 1604{
1647 int do_log; 1605 struct CadetChannelClient *ccc;
1648 1606
1649 do_log = GNUNET_get_log_call_status (level & (~GNUNET_ERROR_TYPE_BULK), 1607 GNUNET_assert (GNUNET_NO == ch->is_loopback);
1650 "cadet-chn", 1608 LOG (GNUNET_ERROR_TYPE_DEBUG,
1651 __FILE__, __FUNCTION__, __LINE__); 1609 "Received remote channel DESTROY for %s\n",
1652 if (0 == do_log) 1610 GCCH_2s (ch));
1653 return; 1611 if (GNUNET_YES == ch->destroy)
1654
1655 if (NULL == ch)
1656 { 1612 {
1657 LOG2 (level, "CHN *** DEBUG NULL CHANNEL ***\n"); 1613 /* Local client already gone, this is instant-death. */
1614 channel_destroy (ch);
1658 return; 1615 return;
1659 } 1616 }
1660 LOG2 (level, "CHN Channel %s:%X (%p)\n", GCT_2s (ch->t), ch->gid, ch); 1617 ccc = (NULL != ch->owner) ? ch->owner : ch->dest;
1661 LOG2 (level, "CHN root %p/%p\n", ch->root, ch->root_rel); 1618 if ( (NULL != ccc) &&
1662 if (NULL != ch->root) 1619 (NULL != ccc->head_recv) )
1663 {
1664 LOG2 (level, "CHN cli %s\n", GML_2s (ch->root));
1665 LOG2 (level, "CHN ready %s\n", ch->root_rel->client_ready ? "YES" : "NO");
1666 LOG2 (level, "CHN id %X\n", ch->lid_root.channel_of_client);
1667 LOG2 (level, "CHN recv %d\n", ch->root_rel->n_recv);
1668 LOG2 (level, "CHN MID r: %d, s: %d\n",
1669 ch->root_rel->mid_recv, ch->root_rel->mid_send);
1670 }
1671 LOG2 (level, "CHN dest %p/%p\n",
1672 ch->dest, ch->dest_rel);
1673 if (NULL != ch->dest)
1674 { 1620 {
1675 LOG2 (level, "CHN cli %s\n", GML_2s (ch->dest)); 1621 LOG (GNUNET_ERROR_TYPE_WARNING,
1676 LOG2 (level, "CHN ready %s\n", ch->dest_rel->client_ready ? "YES" : "NO"); 1622 "Lost end of transmission due to remote shutdown on %s\n",
1677 LOG2 (level, "CHN id %X\n", ch->lid_dest); 1623 GCCH_2s (ch));
1678 LOG2 (level, "CHN recv %d\n", ch->dest_rel->n_recv); 1624 /* FIXME: change API to notify client about truncated transmission! */
1679 LOG2 (level, "CHN MID r: %d, s: %d\n",
1680 ch->dest_rel->mid_recv, ch->dest_rel->mid_send);
1681
1682 } 1625 }
1626 ch->destroy = GNUNET_YES;
1627 if (NULL != ccc)
1628 GSC_handle_remote_channel_destroy (ccc->c,
1629 ccc->ccn,
1630 ch);
1631 channel_destroy (ch);
1683} 1632}
1684 1633
1685 1634
1686/** 1635/**
1687 * Handle an ACK given by a client. 1636 * Test if element @a e1 comes before element @a e2.
1688 *
1689 * Mark client as ready and send him any buffered data we could have for him.
1690 * 1637 *
1691 * @param ch Channel. 1638 * @param cls closure, to a flag where we indicate duplicate packets
1692 * @param fwd Is this a "FWD ACK"? (FWD ACKs are sent by dest and go BCK) 1639 * @param crm1 an element of to sort
1640 * @param crm2 another element to sort
1641 * @return #GNUNET_YES if @e1 < @e2, otherwise #GNUNET_NO
1693 */ 1642 */
1694void 1643static int
1695GCCH_handle_local_ack (struct CadetChannel *ch, int fwd) 1644cmp_crm_by_next_retry (void *cls,
1645 struct CadetReliableMessage *crm1,
1646 struct CadetReliableMessage *crm2)
1696{ 1647{
1697 struct CadetChannelReliability *rel; 1648 if (crm1->next_retry.abs_value_us <
1698 struct CadetClient *c; 1649 crm2->next_retry.abs_value_us)
1699 1650 return GNUNET_YES;
1700 rel = fwd ? ch->dest_rel : ch->root_rel; 1651 return GNUNET_NO;
1701 c = fwd ? ch->dest : ch->root;
1702
1703 rel->client_ready = GNUNET_YES;
1704 send_client_buffered_data (ch, c, fwd);
1705
1706 if (GNUNET_YES == ch->destroy && 0 == rel->n_recv)
1707 {
1708 send_destroy (ch, GNUNET_YES);
1709 GCCH_destroy (ch);
1710 return;
1711 }
1712 /* if loopback is marked for destruction, no need to ACK to the other peer,
1713 * it requested the destruction and is already gone, therefore, else if.
1714 */
1715 else if (is_loopback (ch))
1716 {
1717 unsigned int buffer;
1718
1719 buffer = GCCH_get_buffer (ch, fwd);
1720 if (0 < buffer)
1721 GCCH_allow_client (ch, fwd);
1722
1723 return;
1724 }
1725 GCT_send_connection_acks (ch->t);
1726} 1652}
1727 1653
1728 1654
1729/** 1655/**
1730 * Handle data given by a client. 1656 * Function called once the tunnel has sent one of our messages.
1731 * 1657 * If the message is unreliable, simply frees the `crm`. If the
1732 * Check whether the client is allowed to send in this tunnel, save if channel 1658 * message was reliable, calculate retransmission time and
1733 * is reliable and send an ACK to the client if there is still buffer space 1659 * wait for ACK (or retransmit).
1734 * in the tunnel. 1660 *
1735 * 1661 * @param cls the `struct CadetReliableMessage` that was sent
1736 * @param ch Channel. 1662 * @param cid identifier of the connection within the tunnel, NULL
1737 * @param c Client which sent the data. 1663 * if transmission failed
1738 * @param fwd Is this a FWD data?
1739 * @param message Data message.
1740 * @param size Size of data.
1741 *
1742 * @return #GNUNET_OK if everything goes well, #GNUNET_SYSERR in case of en error.
1743 */ 1664 */
1744int 1665static void
1745GCCH_handle_local_data (struct CadetChannel *ch, 1666data_sent_cb (void *cls,
1746 struct CadetClient *c, 1667 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
1747 int fwd,
1748 const struct GNUNET_MessageHeader *message,
1749 size_t size)
1750{ 1668{
1751 struct CadetChannelReliability *rel; 1669 struct CadetReliableMessage *crm = cls;
1752 struct GNUNET_CADET_ChannelAppDataMessage *payload; 1670 struct CadetChannel *ch = crm->ch;
1753 uint16_t p2p_size = sizeof(struct GNUNET_CADET_ChannelAppDataMessage) + size; 1671
1754 unsigned char cbuf[p2p_size]; 1672 GNUNET_assert (GNUNET_NO == ch->is_loopback);
1755 unsigned char buffer; 1673 GNUNET_assert (NULL != crm->qe);
1756 1674 crm->qe = NULL;
1757 /* Is the client in the channel? */ 1675 GNUNET_CONTAINER_DLL_remove (ch->head_sent,
1758 if ( !( (fwd && 1676 ch->tail_sent,
1759 ch->root == c) 1677 crm);
1760 || 1678 if (GNUNET_NO == ch->reliable)
1761 (!fwd &&
1762 ch->dest == c) ) )
1763 { 1679 {
1764 GNUNET_break_op (0); 1680 GNUNET_free (crm->data_message);
1765 return GNUNET_SYSERR; 1681 GNUNET_free (crm);
1682 ch->pending_messages--;
1683 send_ack_to_client (ch,
1684 (NULL == ch->owner)
1685 ? GNUNET_NO
1686 : GNUNET_YES);
1687 return;
1766 } 1688 }
1767 1689 if (NULL == cid)
1768 rel = fwd ? ch->root_rel : ch->dest_rel;
1769
1770 if (GNUNET_NO == rel->client_allowed)
1771 { 1690 {
1772 GNUNET_break_op (0); 1691 /* There was an error sending. */
1773 return GNUNET_SYSERR; 1692 crm->num_transmissions = GNUNET_SYSERR;
1774 } 1693 }
1775 1694 else if (GNUNET_SYSERR != crm->num_transmissions)
1776 rel->client_allowed = GNUNET_NO;
1777
1778 /* Ok, everything is correct, send the message. */
1779 payload = (struct GNUNET_CADET_ChannelAppDataMessage *) cbuf;
1780 payload->mid = htonl (rel->mid_send);
1781 rel->mid_send++;
1782 GNUNET_memcpy (&payload[1], message, size);
1783 payload->header.size = htons (p2p_size);
1784 payload->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA);
1785 payload->ctn = ch->gid;
1786 LOG (GNUNET_ERROR_TYPE_DEBUG, " sending on channel...\n");
1787 GCCH_send_prebuilt_message (&payload->header, ch, fwd, NULL);
1788
1789 if (is_loopback (ch))
1790 buffer = GCCH_get_buffer (ch, fwd);
1791 else
1792 buffer = GCT_get_connections_buffer (ch->t);
1793
1794 if (0 < buffer)
1795 GCCH_allow_client (ch, fwd);
1796
1797 return GNUNET_OK;
1798}
1799
1800
1801/**
1802 * Handle a channel destroy requested by a client.
1803 *
1804 * TODO: add "reason" field
1805 *
1806 * Destroy the channel and the tunnel in case this was the last channel.
1807 *
1808 * @param ch Channel.
1809 * @param c Client that requested the destruction (to avoid notifying him).
1810 * @param is_root Is the request coming from root?
1811 */
1812void
1813GCCH_handle_local_destroy (struct CadetChannel *ch,
1814 struct CadetClient *c,
1815 int is_root)
1816{
1817 ch->destroy = GNUNET_YES;
1818 /* Cleanup after the tunnel */
1819 if (GNUNET_NO == is_root && c == ch->dest)
1820 { 1695 {
1821 LOG (GNUNET_ERROR_TYPE_DEBUG, " Client %s is destination.\n", GML_2s (c)); 1696 /* Increment transmission counter, and possibly store @a cid
1822 GML_client_delete_channel (c, ch, ch->lid_dest); 1697 if this was the first transmission. */
1823 ch->dest = NULL; 1698 crm->num_transmissions++;
1699 if (1 == crm->num_transmissions)
1700 {
1701 crm->first_transmission_time = GNUNET_TIME_absolute_get ();
1702 crm->connection_taken = *cid;
1703 GCC_ack_expected (cid);
1704 }
1824 } 1705 }
1825 if (GNUNET_YES == is_root && c == ch->root) 1706 if ( (0 == crm->retry_delay.rel_value_us) &&
1707 (NULL != cid) )
1826 { 1708 {
1827 LOG (GNUNET_ERROR_TYPE_DEBUG, " Client %s is owner.\n", GML_2s (c)); 1709 struct CadetConnection *cc = GCC_lookup (cid);
1828 GML_client_delete_channel (c, ch, ch->lid_root);
1829 ch->root = NULL;
1830 }
1831 1710
1832 send_destroy (ch, GNUNET_NO); 1711 if (NULL != cc)
1833 if (0 == ch->pending_messages) 1712 crm->retry_delay = GCC_get_metrics (cc)->aged_latency;
1834 GCCH_destroy (ch); 1713 else
1714 crm->retry_delay = ch->retry_time;
1715 }
1716 crm->retry_delay = GNUNET_TIME_STD_BACKOFF (crm->retry_delay);
1717 crm->retry_delay = GNUNET_TIME_relative_max (crm->retry_delay,
1718 MIN_RTT_DELAY);
1719 crm->next_retry = GNUNET_TIME_relative_to_absolute (crm->retry_delay);
1720
1721 GNUNET_CONTAINER_DLL_insert_sorted (struct CadetReliableMessage,
1722 cmp_crm_by_next_retry,
1723 NULL,
1724 ch->head_sent,
1725 ch->tail_sent,
1726 crm);
1727 LOG (GNUNET_ERROR_TYPE_DEBUG,
1728 "Message %u sent, next transmission on %s in %s\n",
1729 (unsigned int) ntohl (crm->data_message->mid.mid),
1730 GCCH_2s (ch),
1731 GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (ch->head_sent->next_retry),
1732 GNUNET_YES));
1733 if (NULL == ch->head_sent->qe)
1734 {
1735 if (NULL != ch->retry_data_task)
1736 GNUNET_SCHEDULER_cancel (ch->retry_data_task);
1737 ch->retry_data_task
1738 = GNUNET_SCHEDULER_add_at (ch->head_sent->next_retry,
1739 &retry_transmission,
1740 ch);
1741 }
1835} 1742}
1836 1743
1837 1744
1838/** 1745/**
1839 * Handle a channel create requested by a client. 1746 * Handle data given by a client.
1840 *
1841 * Create the channel and the tunnel in case this was the first0 channel.
1842 * 1747 *
1843 * @param c Client that requested the creation (will be the root). 1748 * Check whether the client is allowed to send in this tunnel, save if
1844 * @param msg Create Channel message. 1749 * channel is reliable and send an ACK to the client if there is still
1750 * buffer space in the tunnel.
1845 * 1751 *
1846 * @return #GNUNET_OK if everything went fine, #GNUNET_SYSERR otherwise. 1752 * @param ch Channel.
1753 * @param sender_ccn ccn of the sender
1754 * @param buf payload to transmit.
1755 * @param buf_len number of bytes in @a buf
1756 * @return #GNUNET_OK if everything goes well,
1757 * #GNUNET_SYSERR in case of an error.
1847 */ 1758 */
1848int 1759int
1849GCCH_handle_local_create (struct CadetClient *c, 1760GCCH_handle_local_data (struct CadetChannel *ch,
1850 struct GNUNET_CADET_LocalChannelCreateMessage *msg) 1761 struct GNUNET_CADET_ClientChannelNumber sender_ccn,
1762 const char *buf,
1763 size_t buf_len)
1851{ 1764{
1852 struct CadetChannel *ch; 1765 struct CadetReliableMessage *crm;
1853 struct CadetTunnel *t;
1854 struct CadetPeer *peer;
1855 struct GNUNET_CADET_ClientChannelNumber ccn;
1856
1857 LOG (GNUNET_ERROR_TYPE_DEBUG, " towards %s:%u\n",
1858 GNUNET_i2s (&msg->peer), GNUNET_h2s (&msg->port));
1859 ccn = msg->ccn;
1860
1861 /* Sanity check for duplicate channel IDs */
1862 if (NULL != GML_channel_get (c, ccn))
1863 {
1864 GNUNET_break (0);
1865 return GNUNET_SYSERR;
1866 }
1867 1766
1868 peer = GCP_get (&msg->peer, GNUNET_YES); 1767 if (ch->pending_messages > ch->max_pending_messages)
1869 GCP_add_tunnel (peer);
1870 t = GCP_get_tunnel (peer);
1871
1872 if (GCP_get_short_id (peer) == myid)
1873 {
1874 GCT_change_cstate (t, CADET_TUNNEL_READY);
1875 }
1876 else
1877 {
1878 /* FIXME change to a tunnel API, eliminate ch <-> peer connection */
1879 GCP_connect (peer);
1880 }
1881
1882 /* Create channel */
1883 ch = channel_new (t, c, ccn);
1884 if (NULL == ch)
1885 { 1768 {
1886 GNUNET_break (0); 1769 GNUNET_break (0);
1887 return GNUNET_SYSERR; 1770 return GNUNET_SYSERR;
1888 } 1771 }
1889 ch->port = msg->port; 1772 if (GNUNET_YES == ch->destroy)
1890 channel_set_options (ch, ntohl (msg->opt));
1891
1892 /* In unreliable channels, we'll use the DLL to buffer BCK data */
1893 ch->root_rel = GNUNET_new (struct CadetChannelReliability);
1894 ch->root_rel->ch = ch;
1895 ch->root_rel->retry_timer = CADET_RETRANSMIT_TIME;
1896 ch->root_rel->expected_delay.rel_value_us = 0;
1897
1898 LOG (GNUNET_ERROR_TYPE_DEBUG, "CREATED CHANNEL %s\n", GCCH_2s (ch));
1899
1900 send_create (ch);
1901
1902 return GNUNET_OK;
1903}
1904
1905
1906/**
1907 * Handler for cadet network payload traffic.
1908 *
1909 * @param ch Channel for the message.
1910 * @param msg Unencryted data message.
1911 * @param fwd Is this message fwd? This only is meaningful in loopback channels.
1912 * #GNUNET_YES if message is FWD on the respective channel (loopback)
1913 * #GNUNET_NO if message is BCK on the respective channel (loopback)
1914 * #GNUNET_SYSERR if message on a one-ended channel (remote)
1915 */
1916void
1917GCCH_handle_data (struct CadetChannel *ch,
1918 const struct GNUNET_CADET_ChannelAppDataMessage *msg,
1919 int fwd)
1920{
1921 struct CadetChannelReliability *rel;
1922 struct CadetClient *c;
1923 struct GNUNET_MessageHeader *payload_msg;
1924 uint32_t mid;
1925 uint16_t payload_type;
1926 uint16_t payload_size;
1927
1928 /* If this is a remote (non-loopback) channel, find 'fwd'. */
1929 if (GNUNET_SYSERR == fwd)
1930 { 1773 {
1931 if (is_loopback (ch)) 1774 /* we are going down, drop messages */
1932 { 1775 return GNUNET_OK;
1933 /* It is a loopback channel after all... */
1934 GNUNET_break (0);
1935 return;
1936 }
1937 fwd = (NULL != ch->dest) ? GNUNET_YES : GNUNET_NO;
1938 } 1776 }
1777 ch->pending_messages++;
1939 1778
1940 /* Initialize FWD/BCK data */ 1779 if (GNUNET_YES == ch->is_loopback)
1941 c = fwd ? ch->dest : ch->root;
1942 rel = fwd ? ch->dest_rel : ch->root_rel;
1943
1944 if (NULL == c)
1945 { 1780 {
1946 GNUNET_break (GNUNET_NO != ch->destroy); 1781 struct CadetChannelClient *receiver;
1947 return; 1782 struct GNUNET_MQ_Envelope *env;
1948 } 1783 struct GNUNET_CADET_LocalData *ld;
1784 int ack_to_owner;
1949 1785
1950 if (CADET_CHANNEL_READY != ch->state) 1786 env = GNUNET_MQ_msg_extra (ld,
1951 { 1787 buf_len,
1952 if (GNUNET_NO == fwd) 1788 GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA);
1789 if ( (NULL != ch->owner) &&
1790 (sender_ccn.channel_of_client ==
1791 ch->owner->ccn.channel_of_client) )
1953 { 1792 {
1954 /* If we are the root, this means the other peer has sent traffic before 1793 receiver = ch->dest;
1955 * receiving our ACK. Even if the SYNACK goes missing, no traffic should 1794 ack_to_owner = GNUNET_YES;
1956 * be sent before the ACK.
1957 */
1958 GNUNET_break_op (0);
1959 return;
1960 } 1795 }
1961 /* If we are the dest, this means that the SYNACK got to the root but 1796 else if ( (NULL != ch->dest) &&
1962 * the ACK went missing. Treat this as an ACK. 1797 (sender_ccn.channel_of_client ==
1963 */ 1798 ch->dest->ccn.channel_of_client) )
1964 channel_confirm (ch, GNUNET_NO);
1965 }
1966
1967 payload_msg = (struct GNUNET_MessageHeader *) &msg[1];
1968 payload_type = ntohs (payload_msg->type);
1969 payload_size = ntohs (payload_msg->size);
1970
1971 GNUNET_STATISTICS_update (stats, "# messages received", 1, GNUNET_NO);
1972 GNUNET_STATISTICS_update (stats, "# bytes received", payload_size, GNUNET_NO);
1973
1974 mid = ntohl (msg->mid);
1975 LOG (GNUNET_ERROR_TYPE_INFO, "<== %s (%s %4u) on chan %s (%p) %s [%5u]\n",
1976 GC_m2s (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA), GC_m2s (payload_type), mid,
1977 GCCH_2s (ch), ch, GC_f2s (fwd), ntohs (msg->header.size));
1978
1979 if ( (GNUNET_NO == ch->reliable) ||
1980 ( (! GC_is_pid_bigger (rel->mid_recv, mid)) &&
1981 GC_is_pid_bigger (rel->mid_recv + 64, mid) ) )
1982 {
1983 if (GNUNET_YES == ch->reliable)
1984 { 1799 {
1985 /* Is this the exact next expected messasge? */ 1800 receiver = ch->owner;
1986 if (mid == rel->mid_recv) 1801 ack_to_owner = GNUNET_NO;
1987 {
1988 LOG (GNUNET_ERROR_TYPE_DEBUG,
1989 "as expected, sending to client\n");
1990 send_client_data (ch, msg, fwd);
1991 }
1992 else
1993 {
1994 LOG (GNUNET_ERROR_TYPE_DEBUG,
1995 "save for later\n");
1996 add_buffered_data (msg, rel);
1997 }
1998 } 1802 }
1999 else 1803 else
2000 { 1804 {
2001 /* Tunnel is unreliable: send to clients directly */ 1805 GNUNET_break (0);
2002 /* FIXME: accept Out Of Order traffic */ 1806 return GNUNET_SYSERR;
2003 rel->mid_recv = mid + 1;
2004 send_client_data (ch, msg, fwd);
2005 } 1807 }
2006 } 1808 GNUNET_assert (NULL != receiver);
2007 else 1809 ld->ccn = receiver->ccn;
2008 { 1810 GNUNET_memcpy (&ld[1],
2009 GNUNET_STATISTICS_update (stats, "# duplicate MID", 1, GNUNET_NO); 1811 buf,
2010 if (GC_is_pid_bigger (rel->mid_recv, mid)) 1812 buf_len);
1813 if (GNUNET_YES == receiver->client_ready)
2011 { 1814 {
2012 GNUNET_break_op (0); 1815 ch->pending_messages--;
2013 LOG (GNUNET_ERROR_TYPE_WARNING, 1816 GSC_send_to_client (receiver->c,
2014 "MID %u on channel %s not expected (window: %u - %u). Dropping!\n", 1817 env);
2015 mid, GCCH_2s (ch), rel->mid_recv, rel->mid_recv + 63); 1818 send_ack_to_client (ch,
1819 ack_to_owner);
2016 } 1820 }
2017 else 1821 else
2018 { 1822 {
2019 LOG (GNUNET_ERROR_TYPE_INFO, 1823 struct CadetOutOfOrderMessage *oom;
2020 "Duplicate MID %u, channel %s (expecting MID %u). Re-sending ACK!\n", 1824
2021 mid, GCCH_2s (ch), rel->mid_recv); 1825 oom = GNUNET_new (struct CadetOutOfOrderMessage);
2022 if (NULL != rel->uniq) 1826 oom->env = env;
2023 { 1827 GNUNET_CONTAINER_DLL_insert_tail (receiver->head_recv,
2024 LOG (GNUNET_ERROR_TYPE_WARNING, 1828 receiver->tail_recv,
2025 "We are trying to send an ACK, but don't seem have the " 1829 oom);
2026 "bandwidth. Have you set enough [ats] QUOTA in your config?\n"); 1830 receiver->num_recv++;
2027 }
2028
2029 } 1831 }
2030 } 1832 return GNUNET_OK;
2031 1833 }
2032 GCCH_send_data_ack (ch, fwd); 1834
1835 /* Everything is correct, send the message. */
1836 crm = GNUNET_malloc (sizeof (*crm));
1837 crm->ch = ch;
1838 crm->data_message = GNUNET_malloc (sizeof (struct GNUNET_CADET_ChannelAppDataMessage)
1839 + buf_len);
1840 crm->data_message->header.size = htons (sizeof (struct GNUNET_CADET_ChannelAppDataMessage) + buf_len);
1841 crm->data_message->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA);
1842 ch->mid_send.mid = htonl (ntohl (ch->mid_send.mid) + 1);
1843 crm->data_message->mid = ch->mid_send;
1844 crm->data_message->ctn = ch->ctn;
1845 GNUNET_memcpy (&crm->data_message[1],
1846 buf,
1847 buf_len);
1848 GNUNET_CONTAINER_DLL_insert_tail (ch->head_sent,
1849 ch->tail_sent,
1850 crm);
1851 LOG (GNUNET_ERROR_TYPE_DEBUG,
1852 "Sending message %u from local client to %s with %u bytes\n",
1853 ntohl (crm->data_message->mid.mid),
1854 GCCH_2s (ch),
1855 buf_len);
1856 if (NULL != ch->retry_data_task)
1857 {
1858 GNUNET_SCHEDULER_cancel (ch->retry_data_task);
1859 ch->retry_data_task = NULL;
1860 }
1861 crm->qe = GCT_send (ch->t,
1862 &crm->data_message->header,
1863 &data_sent_cb,
1864 crm);
1865 GNUNET_assert (NULL == ch->retry_data_task);
1866 return GNUNET_OK;
2033} 1867}
2034 1868
2035 1869
2036/** 1870/**
2037 * Handler for cadet network traffic end-to-end ACKs. 1871 * Handle ACK from client on local channel. Means the client is ready
1872 * for more data, see if we have any for it.
2038 * 1873 *
2039 * @param ch Channel on which we got this message. 1874 * @param ch channel to destroy
2040 * @param msg Data message. 1875 * @param client_ccn ccn of the client sending the ack
2041 * @param fwd Is this message fwd? This only is meaningful in loopback channels.
2042 * #GNUNET_YES if message is FWD on the respective channel (loopback)
2043 * #GNUNET_NO if message is BCK on the respective channel (loopback)
2044 * #GNUNET_SYSERR if message on a one-ended channel (remote)
2045 */ 1876 */
2046void 1877void
2047GCCH_handle_data_ack (struct CadetChannel *ch, 1878GCCH_handle_local_ack (struct CadetChannel *ch,
2048 const struct GNUNET_CADET_ChannelDataAckMessage *msg, 1879 struct GNUNET_CADET_ClientChannelNumber client_ccn)
2049 int fwd)
2050{ 1880{
2051 struct CadetChannelReliability *rel; 1881 struct CadetChannelClient *ccc;
2052 struct CadetReliableMessage *copy; 1882 struct CadetOutOfOrderMessage *com;
2053 struct CadetReliableMessage *next; 1883
2054 uint32_t ack; 1884 if ( (NULL != ch->owner) &&
2055 int work; 1885 (ch->owner->ccn.channel_of_client == client_ccn.channel_of_client) )
2056 1886 ccc = ch->owner;
2057 /* If this is a remote (non-loopback) channel, find 'fwd'. */ 1887 else if ( (NULL != ch->dest) &&
2058 if (GNUNET_SYSERR == fwd) 1888 (ch->dest->ccn.channel_of_client == client_ccn.channel_of_client) )
2059 { 1889 ccc = ch->dest;
2060 if (is_loopback (ch))
2061 {
2062 /* It is a loopback channel after all... */
2063 GNUNET_break (0);
2064 return;
2065 }
2066 /* Inverted: if message came 'FWD' is a 'BCK ACK'. */
2067 fwd = (NULL != ch->dest) ? GNUNET_NO : GNUNET_YES;
2068 }
2069
2070 ack = ntohl (msg->mid);
2071 LOG (GNUNET_ERROR_TYPE_INFO,
2072 "<== %s (0x%010lX %4u) on chan %s (%p) %s [%5u]\n",
2073 GC_m2s (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK), msg->futures, ack,
2074 GCCH_2s (ch), ch, GC_f2s (fwd), ntohs (msg->header.size));
2075
2076 if (GNUNET_YES == fwd)
2077 rel = ch->root_rel;
2078 else 1890 else
2079 rel = ch->dest_rel; 1891 GNUNET_assert (0);
2080 1892 ccc->client_ready = GNUNET_YES;
2081 if (NULL == rel) 1893 com = ccc->head_recv;
1894 if (NULL == com)
2082 { 1895 {
2083 GNUNET_break (GNUNET_NO != ch->destroy); 1896 LOG (GNUNET_ERROR_TYPE_DEBUG,
2084 return; 1897 "Got LOCAL_ACK, %s-%X ready to receive more data, but none pending on %s-%X(%p)!\n",
2085 } 1898 GSC_2s (ccc->c),
2086 1899 ntohl (client_ccn.channel_of_client),
2087 /* Free ACK'd copies: no need to retransmit those anymore FIXME refactor */ 1900 GCCH_2s (ch),
2088 for (work = GNUNET_NO, copy = rel->head_sent; copy != NULL; copy = next) 1901 ntohl (ccc->ccn.channel_of_client),
2089 { 1902 ccc);
2090 if (GC_is_pid_bigger (copy->mid, ack)) 1903 return; /* none pending */
2091 { 1904 }
2092 LOG (GNUNET_ERROR_TYPE_DEBUG, " head %u, out!\n", copy->mid); 1905 if (GNUNET_YES == ch->is_loopback)
2093 if (0 < channel_rel_free_sent (rel, msg)) 1906 {
2094 work = GNUNET_YES; 1907 int to_owner;
2095 break; 1908
2096 } 1909 /* Messages are always in-order, just send */
2097 work = GNUNET_YES; 1910 GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
2098 LOG (GNUNET_ERROR_TYPE_DEBUG, " id %u\n", copy->mid); 1911 ccc->tail_recv,
2099 next = copy->next; 1912 com);
2100 if (GNUNET_YES == rel_message_free (copy, GNUNET_YES)) 1913 ccc->num_recv--;
2101 { 1914 GSC_send_to_client (ccc->c,
2102 LOG (GNUNET_ERROR_TYPE_DEBUG, " channel destoyed\n"); 1915 com->env);
2103 return; 1916 /* Notify sender that we can receive more */
2104 } 1917 if ( (NULL != ch->owner) &&
2105 } 1918 (ccc->ccn.channel_of_client ==
2106 1919 ch->owner->ccn.channel_of_client) )
2107 /* ACK client if needed and possible */
2108 GCCH_allow_client (ch, fwd);
2109
2110 /* If some message was free'd, update the retransmission delay */
2111 if (GNUNET_YES == work)
2112 {
2113 if (NULL != rel->retry_task)
2114 { 1920 {
2115 GNUNET_SCHEDULER_cancel (rel->retry_task); 1921 to_owner = GNUNET_NO;
2116 rel->retry_task = NULL;
2117 if (NULL != rel->head_sent && NULL == rel->head_sent->chq)
2118 {
2119 struct GNUNET_TIME_Absolute new_target;
2120 struct GNUNET_TIME_Relative delay;
2121
2122 delay = GNUNET_TIME_relative_saturating_multiply (rel->retry_timer,
2123 CADET_RETRANSMIT_MARGIN);
2124 new_target = GNUNET_TIME_absolute_add (rel->head_sent->timestamp,
2125 delay);
2126 delay = GNUNET_TIME_absolute_get_remaining (new_target);
2127 rel->retry_task =
2128 GNUNET_SCHEDULER_add_delayed (delay,
2129 &channel_retransmit_message,
2130 rel);
2131 }
2132 } 1922 }
2133 else 1923 else
2134 { 1924 {
2135 /* Work was done but no task was pending. 1925 GNUNET_assert ( (NULL != ch->dest) &&
2136 * Task was cancelled by a retransmission that is sitting in the queue. 1926 (ccc->ccn.channel_of_client ==
2137 */ 1927 ch->dest->ccn.channel_of_client) );
2138 // FIXME add test to make sure this is the case, probably add return 1928 to_owner = GNUNET_YES;
2139 // value to GCCH_send_prebuilt_message
2140 } 1929 }
1930 send_ack_to_client (ch,
1931 to_owner);
1932 GNUNET_free (com);
1933 return;
2141 } 1934 }
2142}
2143 1935
2144 1936 if ( (com->mid.mid != ch->mid_recv.mid) &&
2145/** 1937 (GNUNET_NO == ch->out_of_order) &&
2146 * Handler for channel create messages. 1938 (GNUNET_YES == ch->reliable) )
2147 *
2148 * Does not have fwd parameter because it's always 'FWD': channel is incoming.
2149 *
2150 * @param t Tunnel this channel will be in.
2151 * @param msg Channel crate message.
2152 */
2153struct CadetChannel *
2154GCCH_handle_create (struct CadetTunnel *t,
2155 const struct GNUNET_CADET_ChannelOpenMessage *msg)
2156{
2157 struct GNUNET_CADET_ClientChannelNumber ccn;
2158 struct GNUNET_CADET_ChannelTunnelNumber gid;
2159 struct CadetChannel *ch;
2160 struct CadetClient *c;
2161 int new_channel;
2162 const struct GNUNET_HashCode *port;
2163
2164 gid = msg->ctn;
2165 ch = GCT_get_channel (t, gid);
2166 if (NULL == ch)
2167 {
2168 /* Create channel */
2169 ccn.channel_of_client = htonl (0);
2170 ch = channel_new (t, NULL, ccn);
2171 ch->gid = gid;
2172 channel_set_options (ch, ntohl (msg->opt));
2173 new_channel = GNUNET_YES;
2174 }
2175 else
2176 { 1939 {
2177 new_channel = GNUNET_NO; 1940 LOG (GNUNET_ERROR_TYPE_DEBUG,
1941 "Got LOCAL_ACK, %s-%X ready to receive more data (but next one is out-of-order %u vs. %u)!\n",
1942 GSC_2s (ccc->c),
1943 ntohl (ccc->ccn.channel_of_client),
1944 ntohl (com->mid.mid),
1945 ntohl (ch->mid_recv.mid));
1946 return; /* missing next one in-order */
2178 } 1947 }
2179 port = &msg->port;
2180
2181 LOG (GNUNET_ERROR_TYPE_INFO,
2182 "<== %s ( 0x%08X %4u) on chan %s (%p) %s [%5u]\n",
2183 GC_m2s (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN), ccn, port,
2184 GCCH_2s (ch), ch, GC_f2s (GNUNET_YES), ntohs (msg->header.size));
2185
2186 if (GNUNET_YES == new_channel || GCT_is_loopback (t))
2187 {
2188 /* Find a destination client */
2189 ch->port = *port;
2190 LOG (GNUNET_ERROR_TYPE_DEBUG, " port %s\n", GNUNET_h2s (port));
2191 c = GML_client_get_by_port (port);
2192 if (NULL == c)
2193 {
2194 LOG (GNUNET_ERROR_TYPE_DEBUG, " no client has port registered\n");
2195 if (is_loopback (ch))
2196 {
2197 LOG (GNUNET_ERROR_TYPE_DEBUG, " loopback: destroy on handler\n");
2198 send_nack (ch);
2199 }
2200 else
2201 {
2202 LOG (GNUNET_ERROR_TYPE_DEBUG, " not loopback: destroy now\n");
2203 send_nack (ch);
2204 GCCH_destroy (ch);
2205 }
2206 return NULL;
2207 }
2208 else
2209 {
2210 LOG (GNUNET_ERROR_TYPE_DEBUG, " client %p has port registered\n", c);
2211 }
2212
2213 add_destination (ch, c);
2214 if (GNUNET_YES == ch->reliable)
2215 LOG (GNUNET_ERROR_TYPE_DEBUG, "Reliable\n");
2216 else
2217 LOG (GNUNET_ERROR_TYPE_DEBUG, "Not Reliable\n");
2218 1948
2219 send_client_create (ch); 1949 LOG (GNUNET_ERROR_TYPE_DEBUG,
2220 ch->state = CADET_CHANNEL_SENT; 1950 "Got LOCAL_ACK, giving payload message %u to %s-%X on %s\n",
2221 } 1951 ntohl (com->mid.mid),
2222 else 1952 GSC_2s (ccc->c),
2223 { 1953 ntohl (ccc->ccn.channel_of_client),
2224 LOG (GNUNET_ERROR_TYPE_DEBUG, " duplicate create channel\n"); 1954 GCCH_2s (ch));
2225 if (NULL != ch->dest_rel->retry_task)
2226 {
2227 LOG (GNUNET_ERROR_TYPE_DEBUG, " clearing retry task\n");
2228 /* we were waiting to re-send our 'SYNACK', wait no more! */
2229 GNUNET_SCHEDULER_cancel (ch->dest_rel->retry_task);
2230 ch->dest_rel->retry_task = NULL;
2231 }
2232 else if (NULL != ch->dest_rel->uniq)
2233 {
2234 /* we are waiting to for our 'SYNACK' to leave the queue, all done! */
2235 return ch;
2236 }
2237 }
2238 send_ack (ch, GNUNET_YES);
2239 1955
2240 return ch; 1956 /* all good, pass next message to client */
1957 GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
1958 ccc->tail_recv,
1959 com);
1960 ccc->num_recv--;
1961 /* FIXME: if unreliable, this is not aggressive
1962 enough, as it would be OK to have lost some! */
1963
1964 ch->mid_recv.mid = htonl (1 + ntohl (com->mid.mid));
1965 ch->mid_futures >>= 1; /* equivalent to division by 2 */
1966 ccc->client_ready = GNUNET_NO;
1967 GSC_send_to_client (ccc->c,
1968 com->env);
1969 GNUNET_free (com);
1970 send_channel_data_ack (ch);
1971 if (NULL != ccc->head_recv)
1972 return;
1973 if (GNUNET_NO == ch->destroy)
1974 return;
1975 GCT_send_channel_destroy (ch->t,
1976 ch->ctn);
1977 channel_destroy (ch);
2241} 1978}
2242 1979
2243 1980
2244/** 1981#define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-chn",__VA_ARGS__)
2245 * Handler for channel NACK messages.
2246 *
2247 * NACK messages always go dest -> root, no need for 'fwd' or 'msg' parameter.
2248 *
2249 * @param ch Channel.
2250 */
2251void
2252GCCH_handle_nack (struct CadetChannel *ch)
2253{
2254 LOG (GNUNET_ERROR_TYPE_INFO,
2255 "<== %s ( 0x%08X %4u) on chan %s (%p) %s [%5u]\n",
2256 GC_m2s (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_NACK_DEPRECATED), ch->gid, 0,
2257 GCCH_2s (ch), ch, "---", 0);
2258
2259 send_client_nack (ch);
2260 GCCH_destroy (ch);
2261}
2262 1982
2263 1983
2264/** 1984/**
2265 * Handler for channel ack messages. 1985 * Log channel info.
2266 * 1986 *
2267 * @param ch Channel. 1987 * @param ch Channel.
2268 * @param msg Message. 1988 * @param level Debug level to use.
2269 * @param fwd Is this message fwd? This only is meaningful in loopback channels.
2270 * #GNUNET_YES if message is FWD on the respective channel (loopback)
2271 * #GNUNET_NO if message is BCK on the respective channel (loopback)
2272 * #GNUNET_SYSERR if message on a one-ended channel (remote)
2273 */
2274void
2275GCCH_handle_ack (struct CadetChannel *ch,
2276 const struct GNUNET_CADET_ChannelManageMessage *msg,
2277 int fwd)
2278{
2279 LOG (GNUNET_ERROR_TYPE_INFO,
2280 "<== %s ( 0x%08X %4u) on chan %s (%p) %s [%5u]\n",
2281 GC_m2s (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK), ch->gid, 0,
2282 GCCH_2s (ch), ch, GC_f2s (fwd), ntohs (msg->header.size));
2283
2284 /* If this is a remote (non-loopback) channel, find 'fwd'. */
2285 if (GNUNET_SYSERR == fwd)
2286 {
2287 if (is_loopback (ch))
2288 {
2289 /* It is a loopback channel after all... */
2290 GNUNET_break (0);
2291 return;
2292 }
2293 fwd = (NULL != ch->dest) ? GNUNET_YES : GNUNET_NO;
2294 }
2295
2296 channel_confirm (ch, !fwd);
2297}
2298
2299
2300/**
2301 * Handler for channel destroy messages.
2302 *
2303 * @param ch Channel to be destroyed of.
2304 * @param msg Message.
2305 * @param fwd Is this message fwd? This only is meaningful in loopback channels.
2306 * #GNUNET_YES if message is FWD on the respective channel (loopback)
2307 * #GNUNET_NO if message is BCK on the respective channel (loopback)
2308 * #GNUNET_SYSERR if message on a one-ended channel (remote)
2309 */ 1989 */
2310void 1990void
2311GCCH_handle_destroy (struct CadetChannel *ch, 1991GCCH_debug (struct CadetChannel *ch,
2312 const struct GNUNET_CADET_ChannelManageMessage *msg, 1992 enum GNUNET_ErrorType level)
2313 int fwd)
2314{ 1993{
2315 struct CadetChannelReliability *rel; 1994 int do_log;
2316
2317 LOG (GNUNET_ERROR_TYPE_INFO,
2318 "<== %s ( 0x%08X %4u) on chan %s (%p) %s [%5u]\n",
2319 GC_m2s (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY), ch->gid, 0,
2320 GCCH_2s (ch), ch, GC_f2s (fwd), ntohs (msg->header.size));
2321
2322 /* If this is a remote (non-loopback) channel, find 'fwd'. */
2323 if (GNUNET_SYSERR == fwd)
2324 {
2325 if (is_loopback (ch))
2326 {
2327 /* It is a loopback channel after all... */
2328 GNUNET_break (0);
2329 return;
2330 }
2331 fwd = (NULL != ch->dest) ? GNUNET_YES : GNUNET_NO;
2332 }
2333 1995
2334 GCCH_debug (ch, GNUNET_ERROR_TYPE_DEBUG); 1996 do_log = GNUNET_get_log_call_status (level & (~GNUNET_ERROR_TYPE_BULK),
2335 if ( (fwd && NULL == ch->dest) || (!fwd && NULL == ch->root) ) 1997 "cadet-chn",
2336 { 1998 __FILE__, __FUNCTION__, __LINE__);
2337 /* Not for us (don't destroy twice a half-open loopback channel) */ 1999 if (0 == do_log)
2338 return; 2000 return;
2339 }
2340
2341 rel = fwd ? ch->dest_rel : ch->root_rel;
2342 if (0 == rel->n_recv)
2343 {
2344 send_destroy (ch, GNUNET_YES);
2345 GCCH_destroy (ch);
2346 }
2347 else
2348 {
2349 ch->destroy = GNUNET_YES;
2350 }
2351}
2352
2353
2354/**
2355 * Sends an already built message on a channel.
2356 *
2357 * If the channel is on a loopback tunnel, notifies the appropriate destination
2358 * client locally.
2359 *
2360 * On a normal channel passes the message to the tunnel for encryption and
2361 * sending on a connection.
2362 *
2363 * This function DOES NOT save the message for retransmission.
2364 *
2365 * @param message Message to send. Function makes a copy of it.
2366 * @param ch Channel on which this message is transmitted.
2367 * @param fwd Is this a fwd message?
2368 * @param existing_copy This is a retransmission, don't save a copy.
2369 */
2370void
2371GCCH_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
2372 struct CadetChannel *ch, int fwd,
2373 void *existing_copy)
2374{
2375 struct CadetChannelQueue *chq;
2376 uint32_t data_id;
2377 uint16_t type;
2378 uint16_t size;
2379 char info[32];
2380
2381 type = ntohs (message->type);
2382 size = ntohs (message->size);
2383
2384 data_id = 0;
2385 switch (type)
2386 {
2387 case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA:
2388 {
2389 struct GNUNET_CADET_ChannelAppDataMessage *data_msg;
2390 struct GNUNET_MessageHeader *payload_msg;
2391 uint16_t payload_type;
2392
2393 data_msg = (struct GNUNET_CADET_ChannelAppDataMessage *) message;
2394 data_id = ntohl (data_msg->mid);
2395 payload_msg = (struct GNUNET_MessageHeader *) &data_msg[1];
2396 payload_type = ntohs (payload_msg->type);
2397 strncpy (info, GC_m2s (payload_type), 31);
2398 info[31] = '\0';
2399 break;
2400 }
2401 case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK:
2402 {
2403 struct GNUNET_CADET_ChannelDataAckMessage *ack_msg;
2404 ack_msg = (struct GNUNET_CADET_ChannelDataAckMessage *) message;
2405 data_id = ntohl (ack_msg->mid);
2406 SPRINTF (info, "0x%010lX",
2407 (unsigned long int) ack_msg->futures);
2408 break;
2409 }
2410 case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN:
2411 {
2412 struct GNUNET_CADET_ChannelOpenMessage *cc_msg;
2413 cc_msg = (struct GNUNET_CADET_ChannelOpenMessage *) message;
2414 SPRINTF (info, " 0x%08X", ntohl (cc_msg->ctn.cn));
2415 break;
2416 }
2417 case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK:
2418 case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_NACK_DEPRECATED:
2419 case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY:
2420 {
2421 struct GNUNET_CADET_ChannelManageMessage *m_msg;
2422 m_msg = (struct GNUNET_CADET_ChannelManageMessage *) message;
2423 SPRINTF (info, " 0x%08X", ntohl (m_msg->ctn.cn));
2424 break;
2425 }
2426 default:
2427 info[0] = '\0';
2428 }
2429 LOG (GNUNET_ERROR_TYPE_INFO,
2430 "==> %s (%12s %4u) on chan %s (%p) %s [%5u]\n",
2431 GC_m2s (type), info, data_id,
2432 GCCH_2s (ch), ch, GC_f2s (fwd), size);
2433 2001
2434 if (GCT_is_loopback (ch->t)) 2002 if (NULL == ch)
2435 { 2003 {
2436 handle_loopback (ch, message, fwd); 2004 LOG2 (level, "CHN *** DEBUG NULL CHANNEL ***\n");
2437 return; 2005 return;
2438 } 2006 }
2439 2007 LOG2 (level,
2440 switch (type) 2008 "CHN %s:%X (%p)\n",
2009 GCT_2s (ch->t),
2010 ch->ctn,
2011 ch);
2012 if (NULL != ch->owner)
2441 { 2013 {
2442 case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA: 2014 LOG2 (level,
2443 if (GNUNET_YES == ch->reliable) 2015 "CHN origin %s ready %s local-id: %u\n",
2444 { 2016 GSC_2s (ch->owner->c),
2445 chq = GNUNET_new (struct CadetChannelQueue); 2017 ch->owner->client_ready ? "YES" : "NO",
2446 chq->type = type; 2018 ntohl (ch->owner->ccn.channel_of_client));
2447 if (NULL == existing_copy)
2448 chq->copy = channel_save_copy (ch, message, fwd);
2449 else
2450 {
2451 chq->copy = (struct CadetReliableMessage *) existing_copy;
2452 if (NULL != chq->copy->chq)
2453 {
2454 /* Last retransmission was queued but not yet sent!
2455 * This retransmission was scheduled by a ch_message_sent which
2456 * followed a very fast RTT, so the tiny delay made the
2457 * retransmission function to execute before the previous
2458 * retransmitted message even had a chance to leave the peer.
2459 * Cancel this message and wait until the pending
2460 * retransmission leaves the peer and ch_message_sent starts
2461 * the timer for the next one.
2462 */
2463 GNUNET_free (chq);
2464 LOG (GNUNET_ERROR_TYPE_DEBUG,
2465 " exisitng copy not yet transmitted!\n");
2466 return;
2467 }
2468 LOG (GNUNET_ERROR_TYPE_DEBUG,
2469 " using existing copy: %p {r:%p q:%p t:%u}\n",
2470 existing_copy,
2471 chq->copy->rel, chq->copy->chq, chq->copy->type);
2472 }
2473 LOG (GNUNET_ERROR_TYPE_DEBUG, " new chq: %p\n", chq);
2474 chq->copy->chq = chq;
2475 chq->tq = GCT_send_prebuilt_message (message, ch->t, NULL,
2476 GNUNET_YES,
2477 &ch_message_sent, chq);
2478 /* q itself is stored in copy */
2479 GNUNET_assert (NULL != chq->tq || GNUNET_NO != ch->destroy);
2480 }
2481 else
2482 {
2483 fire_and_forget (message, ch, GNUNET_NO);
2484 }
2485 break;
2486
2487
2488 case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK:
2489 case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN:
2490 case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK:
2491 chq = GNUNET_new (struct CadetChannelQueue);
2492 chq->type = type;
2493 chq->rel = fwd ? ch->root_rel : ch->dest_rel;
2494 if (NULL != chq->rel->uniq)
2495 {
2496 if (NULL != chq->rel->uniq->tq)
2497 {
2498 GCT_cancel (chq->rel->uniq->tq);
2499 /* ch_message_sent is called, freeing and NULLing uniq */
2500 GNUNET_break (NULL == chq->rel->uniq);
2501 }
2502 else
2503 {
2504 GNUNET_break (0);
2505 GNUNET_free (chq->rel->uniq);
2506 }
2507 }
2508
2509 chq->rel->uniq = chq;
2510 chq->tq = GCT_send_prebuilt_message (message, ch->t, NULL, GNUNET_YES,
2511 &ch_message_sent, chq);
2512 if (NULL == chq->tq)
2513 {
2514 GNUNET_break (0);
2515 chq->rel->uniq = NULL;
2516 GCT_debug (ch->t, GNUNET_ERROR_TYPE_ERROR);
2517 GNUNET_free (chq);
2518 chq = NULL;
2519 return;
2520 }
2521 break;
2522
2523
2524 case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY:
2525 case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_NACK_DEPRECATED:
2526 fire_and_forget (message, ch, GNUNET_YES);
2527 break;
2528
2529
2530 default:
2531 GNUNET_break (0);
2532 LOG (GNUNET_ERROR_TYPE_WARNING, "type %s unknown!\n", GC_m2s (type));
2533 fire_and_forget (message, ch, GNUNET_YES);
2534 } 2019 }
2020 if (NULL != ch->dest)
2021 {
2022 LOG2 (level,
2023 "CHN destination %s ready %s local-id: %u\n",
2024 GSC_2s (ch->dest->c),
2025 ch->dest->client_ready ? "YES" : "NO",
2026 ntohl (ch->dest->ccn.channel_of_client));
2027 }
2028 LOG2 (level,
2029 "CHN Message IDs recv: %d (%LLX), send: %d\n",
2030 ntohl (ch->mid_recv.mid),
2031 (unsigned long long) ch->mid_futures,
2032 ntohl (ch->mid_send.mid));
2535} 2033}
2536 2034
2537 2035
2538/**
2539 * Get the static string for identification of the channel.
2540 *
2541 * @param ch Channel.
2542 *
2543 * @return Static string with the channel IDs.
2544 */
2545const char *
2546GCCH_2s (const struct CadetChannel *ch)
2547{
2548 static char buf[64];
2549
2550 if (NULL == ch)
2551 return "(NULL Channel)";
2552 2036
2553 SPRINTF (buf, 2037/* end of gnunet-service-cadet-new_channel.c */
2554 "%s:%s gid:%X (%X / %X)",
2555 GCT_2s (ch->t),
2556 GNUNET_h2s (&ch->port),
2557 ntohl (ch->gid.cn),
2558 ntohl (ch->lid_root.channel_of_client),
2559 ntohl (ch->lid_dest.channel_of_client));
2560
2561 return buf;
2562}
diff --git a/src/cadet/gnunet-service-cadet_channel.h b/src/cadet/gnunet-service-cadet_channel.h
index 9d4893269..a3ef9a06d 100644
--- a/src/cadet/gnunet-service-cadet_channel.h
+++ b/src/cadet/gnunet-service-cadet_channel.h
@@ -1,6 +1,7 @@
1
1/* 2/*
2 This file is part of GNUnet. 3 This file is part of GNUnet.
3 Copyright (C) 2013 GNUnet e.V. 4 Copyright (C) 2001-2017 GNUnet e.V.
4 5
5 GNUnet is free software; you can redistribute it and/or modify 6 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published 7 it under the terms of the GNU General Public License as published
@@ -20,344 +21,242 @@
20 21
21/** 22/**
22 * @file cadet/gnunet-service-cadet_channel.h 23 * @file cadet/gnunet-service-cadet_channel.h
23 * @brief cadet service; dealing with end-to-end channels 24 * @brief GNUnet CADET service with encryption
24 * @author Bartlomiej Polot 25 * @author Bartlomiej Polot
25 * 26 * @author Christian Grothoff
26 * All functions in this file should use the prefix GMCH (Gnunet Cadet CHannel)
27 */ 27 */
28
29#ifndef GNUNET_SERVICE_CADET_CHANNEL_H 28#ifndef GNUNET_SERVICE_CADET_CHANNEL_H
30#define GNUNET_SERVICE_CADET_CHANNEL_H 29#define GNUNET_SERVICE_CADET_CHANNEL_H
31 30
32#ifdef __cplusplus 31#include "gnunet-service-cadet.h"
33extern "C" 32#include "gnunet-service-cadet_peer.h"
34{
35#if 0 /* keep Emacsens' auto-indent happy */
36}
37#endif
38#endif
39
40#include "platform.h"
41#include "gnunet_util_lib.h"
42
43#include "cadet_protocol.h" 33#include "cadet_protocol.h"
44#include "cadet.h"
45
46/**
47 * Struct containing all information regarding a channel to a remote client.
48 */
49struct CadetChannel;
50
51
52#include "gnunet-service-cadet_tunnel.h"
53#include "gnunet-service-cadet_local.h"
54
55
56/**
57 * Destroy a channel and free all resources.
58 *
59 * @param ch Channel to destroy.
60 */
61void
62GCCH_destroy (struct CadetChannel *ch);
63 34
64 35
65/** 36/**
66 * Get the channel's public ID. 37 * A channel is a bidirectional connection between two CADET
67 * 38 * clients. Communiation can be reliable, unreliable, in-order
68 * @param ch Channel. 39 * or out-of-order. One client is the "local" client, this
69 * 40 * one initiated the connection. The other client is the
70 * @return ID used to identify the channel with the remote peer. 41 * "incoming" client, this one listened on a port to accept
42 * the connection from the "local" client.
71 */ 43 */
72struct GNUNET_CADET_ChannelTunnelNumber 44struct CadetChannel;
73GCCH_get_id (const struct CadetChannel *ch);
74
75
76/**
77 * Get the channel tunnel.
78 *
79 * @param ch Channel to get the tunnel from.
80 *
81 * @return tunnel of the channel.
82 */
83struct CadetTunnel *
84GCCH_get_tunnel (const struct CadetChannel *ch);
85 45
86 46
87/** 47/**
88 * Get free buffer space towards the client on a specific channel. 48 * Get the static string for identification of the channel.
89 * 49 *
90 * @param ch Channel. 50 * @param ch Channel.
91 * @param fwd Is query about FWD traffic?
92 * 51 *
93 * @return Free buffer space [0 - 64] 52 * @return Static string with the channel IDs.
94 */ 53 */
95unsigned int 54const char *
96GCCH_get_buffer (struct CadetChannel *ch, int fwd); 55GCCH_2s (const struct CadetChannel *ch);
97 56
98 57
99/** 58/**
100 * Get flow control status of end point: is client allow to send? 59 * Log channel info.
101 * 60 *
102 * @param ch Channel. 61 * @param ch Channel.
103 * @param fwd Is query about FWD traffic? (Request root status). 62 * @param level Debug level to use.
104 *
105 * @return #GNUNET_YES if client is allowed to send us data.
106 */ 63 */
107int 64void
108GCCH_get_allowed (struct CadetChannel *ch, int fwd); 65GCCH_debug (struct CadetChannel *ch,
66 enum GNUNET_ErrorType level);
109 67
110 68
111/** 69/**
112 * Is the root client for this channel on this peer? 70 * Get the channel's public ID.
113 * 71 *
114 * @param ch Channel. 72 * @param ch Channel.
115 * @param fwd Is this for fwd traffic?
116 * 73 *
117 * @return #GNUNET_YES in case it is. 74 * @return ID used to identify the channel with the remote peer.
118 */ 75 */
119int 76struct GNUNET_CADET_ChannelTunnelNumber
120GCCH_is_origin (struct CadetChannel *ch, int fwd); 77GCCH_get_id (const struct CadetChannel *ch);
121 78
122/**
123 * Is the destination client for this channel on this peer?
124 *
125 * @param ch Channel.
126 * @param fwd Is this for fwd traffic?
127 *
128 * @return #GNUNET_YES in case it is.
129 */
130int
131GCCH_is_terminal (struct CadetChannel *ch, int fwd);
132 79
133/** 80/**
134 * Send an end-to-end ACK message for the most recent in-sequence payload. 81 * Create a new channel.
135 * 82 *
136 * If channel is not reliable, do nothing. 83 * @param owner local client owning the channel
137 * 84 * @param owner_id local chid of this channel at the @a owner
138 * @param ch Channel this is about. 85 * @param destination peer to which we should build the channel
139 * @param fwd Is for FWD traffic? (ACK dest->owner) 86 * @param port desired port at @a destination
87 * @param options options for the channel
88 * @return handle to the new channel
140 */ 89 */
141void 90struct CadetChannel *
142GCCH_send_data_ack (struct CadetChannel *ch, int fwd); 91GCCH_channel_local_new (struct CadetClient *owner,
92 struct GNUNET_CADET_ClientChannelNumber owner_id,
93 struct CadetPeer *destination,
94 const struct GNUNET_HashCode *port,
95 uint32_t options);
143 96
144/**
145 * Notify the destination client that a new incoming channel was created.
146 *
147 * @param ch Channel that was created.
148 */
149void
150GCCH_send_create (struct CadetChannel *ch);
151 97
152/** 98/**
153 * Allow a client to send us more data, in case it was choked. 99 * A client is bound to the port that we have a channel
100 * open to. Send the acknowledgement for the connection
101 * request and establish the link with the client.
154 * 102 *
155 * @param ch Channel. 103 * @param ch open incoming channel
156 * @param fwd Is this about FWD traffic? (Root client). 104 * @param c client listening on the respective port
157 */ 105 */
158void 106void
159GCCH_allow_client (struct CadetChannel *ch, int fwd); 107GCCH_bind (struct CadetChannel *ch,
108 struct CadetClient *c);
160 109
161/**
162 * Log channel info.
163 *
164 * @param ch Channel.
165 * @param level Debug level to use.
166 */
167void
168GCCH_debug (struct CadetChannel *ch, enum GNUNET_ErrorType level);
169 110
170/** 111/**
171 * Handle an ACK given by a client. 112 * Destroy locally created channel. Called by the
113 * local client, so no need to tell the client.
172 * 114 *
173 * Mark client as ready and send him any buffered data we could have for him. 115 * @param ch channel to destroy
174 * 116 * @param c client that caused the destruction
175 * @param ch Channel. 117 * @param ccn client number of the client @a c
176 * @param fwd Is this a "FWD ACK"? (FWD ACKs are sent by root and go BCK)
177 */ 118 */
178void 119void
179GCCH_handle_local_ack (struct CadetChannel *ch, int fwd); 120GCCH_channel_local_destroy (struct CadetChannel *ch,
121 struct CadetClient *c,
122 struct GNUNET_CADET_ClientChannelNumber ccn);
180 123
181/**
182 * Handle data given by a client.
183 *
184 * Check whether the client is allowed to send in this tunnel, save if channel
185 * is reliable and send an ACK to the client if there is still buffer space
186 * in the tunnel.
187 *
188 * @param ch Channel.
189 * @param c Client which sent the data.
190 * @param fwd Is this a FWD data?
191 * @param message Data message.
192 * @param size Size of data.
193 *
194 * @return GNUNET_OK if everything goes well, GNUNET_SYSERR in case of en error.
195 */
196int
197GCCH_handle_local_data (struct CadetChannel *ch,
198 struct CadetClient *c, int fwd,
199 const struct GNUNET_MessageHeader *message,
200 size_t size);
201 124
202/** 125/**
203 * Handle a channel destroy requested by a client. 126 * Function called once and only once after a channel was bound
204 * 127 * to its tunnel via #GCT_add_channel() is ready for transmission.
205 * Destroy the channel and the tunnel in case this was the last channel. 128 * Note that this is only the case for channels that this peer
206 * 129 * initiates, as for incoming channels we assume that they are
207 * @param ch Channel. 130 * ready for transmission immediately upon receiving the open
208 * @param c Client that requested the destruction (to avoid notifying him). 131 * message. Used to bootstrap the #GCT_send() process.
209 * @param is_root Is the request coming from root? 132 *
133 * @param ch the channel for which the tunnel is now ready
210 */ 134 */
211void 135void
212GCCH_handle_local_destroy (struct CadetChannel *ch, 136GCCH_tunnel_up (struct CadetChannel *ch);
213 struct CadetClient *c,
214 int is_root);
215 137
216 138
217/** 139/**
218 * Handle a channel create requested by a client. 140 * Create a new channel based on a request coming in over the network.
219 * 141 *
220 * Create the channel and the tunnel in case this was the first0 channel. 142 * @param t tunnel to the remote peer
221 * 143 * @param chid identifier of this channel in the tunnel
222 * @param c Client that requested the creation (will be the root). 144 * @param origin peer to who initiated the channel
223 * @param msg Create Channel message. 145 * @param port desired local port
224 * 146 * @param options options for the channel
225 * @return #GNUNET_OK if everything went fine, #GNUNET_SYSERR otherwise. 147 * @return handle to the new channel
226 */ 148 */
227int 149struct CadetChannel *
228GCCH_handle_local_create (struct CadetClient *c, 150GCCH_channel_incoming_new (struct CadetTunnel *t,
229 struct GNUNET_CADET_LocalChannelCreateMessage *msg); 151 struct GNUNET_CADET_ChannelTunnelNumber chid,
230 152 const struct GNUNET_HashCode *port,
231/** 153 uint32_t options);
232 * Handler for cadet network payload traffic.
233 *
234 * @param ch Channel for the message.
235 * @param msg Unencryted data message.
236 * @param fwd Is this message fwd? This only is meaningful in loopback channels.
237 * #GNUNET_YES if message is FWD on the respective channel (loopback)
238 * #GNUNET_NO if message is BCK on the respective channel (loopback)
239 * #GNUNET_SYSERR if message on a one-ended channel (remote)
240 */
241void
242GCCH_handle_data (struct CadetChannel *ch,
243 const struct GNUNET_CADET_ChannelAppDataMessage *msg,
244 int fwd);
245 154
246 155
247/** 156/**
248 * Handler for cadet network traffic end-to-end ACKs. 157 * We got a #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN message again for
158 * this channel. If the binding was successful, (re)transmit the
159 * #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK.
249 * 160 *
250 * @param ch Channel on which we got this message. 161 * @param ch channel that got the duplicate open
251 * @param msg Data message. 162 * @param cti identifier of the connection that delivered the message
252 * @param fwd Is this message fwd? This only is meaningful in loopback channels.
253 * #GNUNET_YES if message is FWD on the respective channel (loopback)
254 * #GNUNET_NO if message is BCK on the respective channel (loopback)
255 * #GNUNET_SYSERR if message on a one-ended channel (remote)
256 */ 163 */
257void 164void
258GCCH_handle_data_ack (struct CadetChannel *ch, 165GCCH_handle_duplicate_open (struct CadetChannel *ch,
259 const struct GNUNET_CADET_ChannelDataAckMessage *msg, 166 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti);
260 int fwd);
261 167
262 168
263/**
264 * Handler for channel create messages.
265 *
266 * Does not have fwd parameter because it's always 'FWD': channel is incoming.
267 *
268 * @param t Tunnel this channel will be in.
269 * @param msg Channel crate message.
270 */
271struct CadetChannel *
272GCCH_handle_create (struct CadetTunnel *t,
273 const struct GNUNET_CADET_ChannelOpenMessage *msg);
274
275 169
276/** 170/**
277 * Handler for channel NACK messages. 171 * We got payload data for a channel. Pass it on to the client.
278 * 172 *
279 * NACK messages always go dest -> root, no need for 'fwd' or 'msg' parameter. 173 * @param ch channel that got data
280 * 174 * @param cti identifier of the connection that delivered the message
281 * @param ch Channel. 175 * @param msg message that was received
282 */ 176 */
283void 177void
284GCCH_handle_nack (struct CadetChannel *ch); 178GCCH_handle_channel_plaintext_data (struct CadetChannel *ch,
179 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
180 const struct GNUNET_CADET_ChannelAppDataMessage *msg);
285 181
286 182
287/** 183/**
288 * Handler for channel ack messages. 184 * We got an acknowledgement for payload data for a channel.
185 * Possibly resume transmissions.
289 * 186 *
290 * @param ch Channel this channel is to be created in. 187 * @param ch channel that got the ack
291 * @param msg Message. 188 * @param cti identifier of the connection that delivered the message
292 * @param fwd Is this message fwd? This only is meaningful in loopback channels. 189 * @param ack details about what was received
293 * #GNUNET_YES if message is FWD on the respective channel (loopback)
294 * #GNUNET_NO if message is BCK on the respective channel (loopback)
295 * #GNUNET_SYSERR if message on a one-ended channel (remote)
296 */ 190 */
297void 191void
298GCCH_handle_ack (struct CadetChannel *ch, 192GCCH_handle_channel_plaintext_data_ack (struct CadetChannel *ch,
299 const struct GNUNET_CADET_ChannelManageMessage *msg, 193 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
300 int fwd); 194 const struct GNUNET_CADET_ChannelDataAckMessage *ack);
301 195
302 196
303/** 197/**
304 * Handler for channel destroy messages. 198 * We got an acknowledgement for the creation of the channel
199 * (the port is open on the other side). Begin transmissions.
305 * 200 *
306 * @param ch Channel this channel is to be destroyed of. 201 * @param ch channel to destroy
307 * @param msg Message. 202 * @param cti identifier of the connection that delivered the message,
308 * @param fwd Is this message fwd? This only is meaningful in loopback channels. 203 * NULL if the ACK was inferred because we got payload or are on loopback
309 * #GNUNET_YES if message is FWD on the respective channel (loopback)
310 * #GNUNET_NO if message is BCK on the respective channel (loopback)
311 * #GNUNET_SYSERR if message on a one-ended channel (remote)
312 */ 204 */
313void 205void
314GCCH_handle_destroy (struct CadetChannel *ch, 206GCCH_handle_channel_open_ack (struct CadetChannel *ch,
315 const struct GNUNET_CADET_ChannelManageMessage *msg, 207 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti);
316 int fwd);
317 208
318 209
319/** 210/**
320 * Sends an already built message on a channel. 211 * Destroy channel, based on the other peer closing the
212 * connection. Also needs to remove this channel from
213 * the tunnel.
321 * 214 *
322 * If the channel is on a loopback tunnel, notifies the appropriate destination 215 * FIXME: need to make it possible to defer destruction until we have
323 * client locally. 216 * received all messages up to the destroy, and right now the destroy
217 * message (and this API) fails to give is the information we need!
324 * 218 *
325 * On a normal channel passes the message to the tunnel for encryption and 219 * FIXME: also need to know if the other peer got a destroy from
326 * sending on a connection. 220 * us before!
327 * 221 *
328 * This function DOES NOT save the message for retransmission. 222 * @param ch channel to destroy
329 * 223 * @param cti identifier of the connection that delivered the message,
330 * @param message Message to send. Function makes a copy of it. 224 * NULL during shutdown
331 * @param ch Channel on which this message is transmitted.
332 * @param fwd Is this a fwd message?
333 * @param existing_copy This is a retransmission, don't save a copy.
334 */ 225 */
335void 226void
336GCCH_send_prebuilt_message (const struct GNUNET_MessageHeader *message, 227GCCH_handle_remote_destroy (struct CadetChannel *ch,
337 struct CadetChannel *ch, int fwd, 228 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti);
338 void *existing_copy);
339 229
340 230
341/** 231/**
342 * Get the static string for identification of the channel. 232 * Handle data given by a client.
343 * 233 *
344 * @param ch Channel.i 234 * Check whether the client is allowed to send in this tunnel, save if
235 * channel is reliable and send an ACK to the client if there is still
236 * buffer space in the tunnel.
345 * 237 *
346 * @return Static string with the channel IDs. 238 * @param ch Channel.
239 * @param sender_ccn ccn of the sender
240 * @param buf payload to transmit.
241 * @param buf_len number of bytes in @a buf
242 * @return #GNUNET_OK if everything goes well,
243 * #GNUNET_SYSERR in case of an error.
347 */ 244 */
348const char * 245int
349GCCH_2s (const struct CadetChannel *ch); 246GCCH_handle_local_data (struct CadetChannel *ch,
350 247 struct GNUNET_CADET_ClientChannelNumber sender_ccn,
351 248 const char *buf,
249 size_t buf_len);
352 250
353 251
354#if 0 /* keep Emacsens' auto-indent happy */ 252/**
355{ 253 * Handle ACK from client on local channel.
356#endif 254 *
357#ifdef __cplusplus 255 * @param ch channel to destroy
358} 256 * @param client_ccn ccn of the client sending the ack
359#endif 257 */
258void
259GCCH_handle_local_ack (struct CadetChannel *ch,
260 struct GNUNET_CADET_ClientChannelNumber client_ccn);
360 261
361/* ifndef GNUNET_SERVICE_CADET_CHANNEL_H */
362#endif 262#endif
363/* end of gnunet-service-cadet_channel.h */
diff --git a/src/cadet/gnunet-service-cadet_connection.c b/src/cadet/gnunet-service-cadet_connection.c
index 2d5087f81..7b66f61a2 100644
--- a/src/cadet/gnunet-service-cadet_connection.c
+++ b/src/cadet/gnunet-service-cadet_connection.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 Copyright (C) 2001-2015 GNUnet e.V. 3 Copyright (C) 2001-2017 GNUnet e.V.
4 4
5 GNUnet is free software; you can redistribute it and/or modify 5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published 6 it under the terms of the GNU General Public License as published
@@ -17,242 +17,126 @@
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA. 18 Boston, MA 02110-1301, USA.
19*/ 19*/
20
20/** 21/**
21 * @file cadet/gnunet-service-cadet_connection.c 22 * @file cadet/gnunet-service-cadet_connection.c
22 * @brief GNUnet CADET service connection handling 23 * @brief management of CORE-level end-to-end connections; establishes
24 * end-to-end routes and transmits messages along the route
23 * @author Bartlomiej Polot 25 * @author Bartlomiej Polot
26 * @author Christian Grothoff
24 */ 27 */
25#include "platform.h" 28#include "platform.h"
26#include "gnunet_util_lib.h" 29#include "gnunet-service-cadet_connection.h"
30#include "gnunet-service-cadet_channel.h"
31#include "gnunet-service-cadet_paths.h"
32#include "gnunet-service-cadet_tunnels.h"
33#include "gnunet_cadet_service.h"
27#include "gnunet_statistics_service.h" 34#include "gnunet_statistics_service.h"
28#include "cadet_path.h"
29#include "cadet_protocol.h" 35#include "cadet_protocol.h"
30#include "cadet.h"
31#include "gnunet-service-cadet_connection.h"
32#include "gnunet-service-cadet_peer.h"
33#include "gnunet-service-cadet_tunnel.h"
34
35
36/**
37 * Should we run somewhat expensive checks on our invariants?
38 */
39#define CHECK_INVARIANTS 0
40
41
42#define LOG(level, ...) GNUNET_log_from (level,"cadet-con",__VA_ARGS__)
43#define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-con",__VA_ARGS__)
44
45
46#define CADET_MAX_POLL_TIME GNUNET_TIME_relative_multiply (\
47 GNUNET_TIME_UNIT_MINUTES,\
48 10)
49#define AVG_MSGS 32
50
51
52/******************************************************************************/
53/******************************** STRUCTS **********************************/
54/******************************************************************************/
55
56/**
57 * Handle for messages queued but not yet sent.
58 */
59struct CadetConnectionQueue
60{
61 36
62 struct CadetConnectionQueue *next;
63 struct CadetConnectionQueue *prev;
64 37
65 /** 38#define LOG(level, ...) GNUNET_log_from(level,"cadet-con",__VA_ARGS__)
66 * Peer queue handle, to cancel if necessary.
67 */
68 struct CadetPeerQueue *peer_q;
69
70 /**
71 * Continuation to call once sent.
72 */
73 GCC_sent cont;
74
75 /**
76 * Closure for @e cont.
77 */
78 void *cont_cls;
79
80 /**
81 * Was this a forced message? (Do not account for it)
82 */
83 int forced;
84};
85 39
86 40
87/** 41/**
88 * Struct to encapsulate all the Flow Control information to a peer to which 42 * All the states a connection can be in.
89 * we are directly connected (on a core level).
90 */ 43 */
91struct CadetFlowControl 44enum CadetConnectionState
92{ 45{
93 /** 46 /**
94 * Connection this controls. 47 * Uninitialized status, we have not yet even gotten the message queue.
95 */
96 struct CadetConnection *c;
97
98 struct CadetConnectionQueue *q_head;
99 struct CadetConnectionQueue *q_tail;
100
101 /**
102 * How many messages are in the queue on this connection.
103 */
104 unsigned int queue_n;
105
106 /**
107 * How many messages do we accept in the queue.
108 * If 0, the connection is broken in this direction (next hop disconnected).
109 */
110 unsigned int queue_max;
111
112 /**
113 * ID of the next packet to send.
114 */
115 struct CadetEncryptedMessageIdentifier next_pid;
116
117 /**
118 * ID of the last packet sent towards the peer.
119 */
120 struct CadetEncryptedMessageIdentifier last_pid_sent;
121
122 /**
123 * ID of the last packet received from the peer.
124 */
125 struct CadetEncryptedMessageIdentifier last_pid_recv;
126
127 /**
128 * Bitmap of past 32 messages received:
129 * - LSB being @c last_pid_recv.
130 * - MSB being @c last_pid_recv - 31 (mod UINTMAX).
131 */
132 uint32_t recv_bitmap;
133
134 /**
135 * Last ACK sent to the peer (peer is not allowed to send
136 * messages with PIDs higher than this value).
137 */ 48 */
138 struct CadetEncryptedMessageIdentifier last_ack_sent; 49 CADET_CONNECTION_NEW,
139 50
140 /** 51 /**
141 * Last ACK sent towards the origin (for traffic towards leaf node). 52 * Connection create message in queue, awaiting transmission by CORE.
142 */ 53 */
143 struct CadetEncryptedMessageIdentifier last_ack_recv; 54 CADET_CONNECTION_SENDING_CREATE,
144 55
145 /** 56 /**
146 * Task to poll the peer in case of a lost ACK causes stall. 57 * Connection create message sent, waiting for ACK.
147 */ 58 */
148 struct GNUNET_SCHEDULER_Task *poll_task; 59 CADET_CONNECTION_SENT,
149 60
150 /** 61 /**
151 * How frequently to poll for ACKs. 62 * We are an inbound connection, and received a CREATE. Need to
63 * send an CREATE_ACK back.
152 */ 64 */
153 struct GNUNET_TIME_Relative poll_time; 65 CADET_CONNECTION_CREATE_RECEIVED,
154 66
155 /** 67 /**
156 * Queued poll message, to cancel if not necessary anymore (got ACK). 68 * Connection confirmed, ready to carry traffic.
157 */ 69 */
158 struct CadetConnectionQueue *poll_msg; 70 CADET_CONNECTION_READY
159 71
160 /**
161 * Queued poll message, to cancel if not necessary anymore (got ACK).
162 */
163 struct CadetConnectionQueue *ack_msg;
164}; 72};
165 73
74
166/** 75/**
167 * Keep a record of the last messages sent on this connection. 76 * Low-level connection to a destination.
168 */ 77 */
169struct CadetConnectionPerformance 78struct CadetConnection
170{ 79{
171 /**
172 * Circular buffer for storing measurements.
173 */
174 double usecsperbyte[AVG_MSGS];
175 80
176 /** 81 /**
177 * Running average of @c usecsperbyte. 82 * ID of the connection.
178 */
179 double avg;
180
181 /**
182 * How many values of @c usecsperbyte are valid.
183 */
184 uint16_t size;
185
186 /**
187 * Index of the next "free" position in @c usecsperbyte.
188 */ 83 */
189 uint16_t idx; 84 struct GNUNET_CADET_ConnectionTunnelIdentifier cid;
190};
191
192 85
193/**
194 * Struct containing all information regarding a connection to a peer.
195 */
196struct CadetConnection
197{
198 /** 86 /**
199 * Tunnel this connection is part of. 87 * To which peer does this connection go?
200 */ 88 */
201 struct CadetTunnel *t; 89 struct CadetPeer *destination;
202 90
203 /** 91 /**
204 * Flow control information for traffic fwd. 92 * Which tunnel is using this connection?
205 */ 93 */
206 struct CadetFlowControl fwd_fc; 94 struct CadetTConnection *ct;
207 95
208 /** 96 /**
209 * Flow control information for traffic bck. 97 * Path we are using to our destination.
210 */ 98 */
211 struct CadetFlowControl bck_fc; 99 struct CadetPeerPath *path;
212 100
213 /** 101 /**
214 * Measure connection performance on the endpoint. 102 * Pending message, NULL if we are ready to transmit.
215 */ 103 */
216 struct CadetConnectionPerformance *perf; 104 struct GNUNET_MQ_Envelope *env;
217 105
218 /** 106 /**
219 * ID of the connection. 107 * Handle for calling #GCP_request_mq_cancel() once we are finished.
220 */ 108 */
221 struct GNUNET_CADET_ConnectionTunnelIdentifier id; 109 struct GCP_MessageQueueManager *mq_man;
222 110
223 /** 111 /**
224 * Path being used for the tunnel. At the origin of the connection 112 * Task for connection maintenance.
225 * it's a pointer to the destination's path pool, otherwise just a copy.
226 */ 113 */
227 struct CadetPeerPath *path; 114 struct GNUNET_SCHEDULER_Task *task;
228 115
229 /** 116 /**
230 * Task to keep the used paths alive at the owner, 117 * Queue entry for keepalive messages.
231 * time tunnel out on all the other peers.
232 */ 118 */
233 struct GNUNET_SCHEDULER_Task *fwd_maintenance_task; 119 struct CadetTunnelQueueEntry *keepalive_qe;
234 120
235 /** 121 /**
236 * Task to keep the used paths alive at the destination, 122 * Function to call once we are ready to transmit.
237 * time tunnel out on all the other peers.
238 */ 123 */
239 struct GNUNET_SCHEDULER_Task *bck_maintenance_task; 124 GCC_ReadyCallback ready_cb;
240 125
241 /** 126 /**
242 * Queue handle for maintainance traffic. One handle for FWD and BCK since 127 * Closure for @e ready_cb.
243 * one peer never needs to maintain both directions (no loopback connections).
244 */ 128 */
245 struct CadetPeerQueue *maintenance_q; 129 void *ready_cb_cls;
246 130
247 /** 131 /**
248 * Should equal #get_next_hop(), or NULL if that peer disconnected. 132 * How long do we wait before we try again with a CREATE message?
249 */ 133 */
250 struct CadetPeer *next_peer; 134 struct GNUNET_TIME_Relative retry_delay;
251 135
252 /** 136 /**
253 * Should equal #get_prev_hop(), or NULL if that peer disconnected. 137 * Performance metrics for this connection.
254 */ 138 */
255 struct CadetPeer *prev_peer; 139 struct CadetConnectionMetrics metrics;
256 140
257 /** 141 /**
258 * State of the connection. 142 * State of the connection.
@@ -260,221 +144,36 @@ struct CadetConnection
260 enum CadetConnectionState state; 144 enum CadetConnectionState state;
261 145
262 /** 146 /**
263 * Position of the local peer in the path. 147 * Options for the route, control buffering.
264 */ 148 */
265 unsigned int own_pos; 149 enum GNUNET_CADET_ChannelOption options;
266 150
267 /** 151 /**
268 * Pending message count. 152 * How many latency observations did we make for this connection?
269 */ 153 */
270 unsigned int pending_messages; 154 unsigned int latency_datapoints;
271 155
272 /** 156 /**
273 * Destroy flag: 157 * Offset of our @e destination in @e path.
274 * - if 0, connection in use.
275 * - if 1, destroy on last message.
276 * - if 2, connection is being destroyed don't re-enter.
277 */ 158 */
278 int destroy; 159 unsigned int off;
279 160
280 /** 161 /**
281 * In-connection-map flag. Sometimes, when @e destroy is set but 162 * Are we ready to transmit via @e mq_man right now?
282 * actual destruction is delayed to enable us to finish processing
283 * queues (i.e. in the direction that is still working), we remove
284 * the connection from the map to prevent it from still being
285 * found (and used) by accident. This flag is set to #GNUNET_YES
286 * for a connection that is not in the #connections map. Should
287 * only be #GNUNET_YES if #destroy is also non-zero.
288 */ 163 */
289 int was_removed; 164 int mqm_ready;
290 165
291 /**
292 * Counter to do exponential backoff when creating a connection (max 64).
293 */
294 unsigned short create_retry;
295
296 /**
297 * Task to check if connection has duplicates.
298 */
299 struct GNUNET_SCHEDULER_Task *check_duplicates_task;
300}; 166};
301 167
302 168
303/******************************************************************************/
304/******************************* GLOBALS ***********************************/
305/******************************************************************************/
306
307/**
308 * Global handle to the statistics service.
309 */
310extern struct GNUNET_STATISTICS_Handle *stats;
311
312/**
313 * Local peer own ID (memory efficient handle).
314 */
315extern GNUNET_PEER_Id myid;
316
317/**
318 * Local peer own ID (full value).
319 */
320extern struct GNUNET_PeerIdentity my_full_id;
321
322/**
323 * Connections known, indexed by cid (CadetConnection).
324 */
325static struct GNUNET_CONTAINER_MultiShortmap *connections;
326
327/**
328 * How many connections are we willing to maintain.
329 * Local connections are always allowed,
330 * even if there are more connections than max.
331 */
332static unsigned long long max_connections;
333
334/**
335 * How many messages *in total* are we willing to queue, divide by number of
336 * connections to get connection queue size.
337 */
338static unsigned long long max_msgs_queue;
339
340/**
341 * How often to send path keepalives. Paths timeout after 4 missed.
342 */
343static struct GNUNET_TIME_Relative refresh_connection_time;
344
345/**
346 * How often to send path create / ACKs.
347 */
348static struct GNUNET_TIME_Relative create_connection_time;
349
350
351/******************************************************************************/
352/******************************** STATIC ***********************************/
353/******************************************************************************/
354
355
356
357#if 0 // avoid compiler warning for unused static function
358static void
359fc_debug (struct CadetFlowControl *fc)
360{
361 LOG (GNUNET_ERROR_TYPE_DEBUG, " IN: %u/%u\n",
362 ntohl (fc->last_pid_recv.pid),
363 ntohl (fc->last_ack_sent.pid));
364 LOG (GNUNET_ERROR_TYPE_DEBUG, " OUT: %u/%u\n",
365 fc->last_pid_sent, fc->last_ack_recv);
366 LOG (GNUNET_ERROR_TYPE_DEBUG, " QUEUE: %u/%u\n",
367 fc->queue_n, fc->queue_max);
368}
369
370static void
371connection_debug (struct CadetConnection *c)
372{
373 if (NULL == c)
374 {
375 LOG (GNUNET_ERROR_TYPE_INFO, "DEBUG NULL CONNECTION\n");
376 return;
377 }
378 LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection %s:%X\n",
379 peer2s (c->t->peer), GCC_2s (c));
380 LOG (GNUNET_ERROR_TYPE_DEBUG, " state: %u, pending msgs: %u\n",
381 c->state, c->pending_messages);
382 LOG (GNUNET_ERROR_TYPE_DEBUG, " FWD FC\n");
383 fc_debug (&c->fwd_fc);
384 LOG (GNUNET_ERROR_TYPE_DEBUG, " BCK FC\n");
385 fc_debug (&c->bck_fc);
386}
387#endif
388
389
390/**
391 * Schedule next keepalive task, taking in consideration
392 * the connection state and number of retries.
393 *
394 * @param c Connection for which to schedule the next keepalive.
395 * @param fwd Direction for the next keepalive.
396 */
397static void
398schedule_next_keepalive (struct CadetConnection *c, int fwd);
399
400
401/**
402 * Resets the connection timeout task, some other message has done the
403 * task's job.
404 * - For the first peer on the direction this means to send
405 * a keepalive or a path confirmation message (either create or ACK).
406 * - For all other peers, this means to destroy the connection,
407 * due to lack of activity.
408 * Starts the timeout if no timeout was running (connection just created).
409 *
410 * @param c Connection whose timeout to reset.
411 * @param fwd Is this forward?
412 */
413static void
414connection_reset_timeout (struct CadetConnection *c, int fwd);
415
416
417/**
418 * Get string description for tunnel state. Reentrant.
419 *
420 * @param s Tunnel state.
421 *
422 * @return String representation.
423 */
424static const char *
425GCC_state2s (enum CadetConnectionState s)
426{
427 switch (s)
428 {
429 case CADET_CONNECTION_NEW:
430 return "CADET_CONNECTION_NEW";
431 case CADET_CONNECTION_SENT:
432 return "CADET_CONNECTION_SENT";
433 case CADET_CONNECTION_ACK:
434 return "CADET_CONNECTION_ACK";
435 case CADET_CONNECTION_READY:
436 return "CADET_CONNECTION_READY";
437 case CADET_CONNECTION_DESTROYED:
438 return "CADET_CONNECTION_DESTROYED";
439 case CADET_CONNECTION_BROKEN:
440 return "CADET_CONNECTION_BROKEN";
441 default:
442 GNUNET_break (0);
443 LOG (GNUNET_ERROR_TYPE_ERROR, " conn state %u unknown!\n", s);
444 return "CADET_CONNECTION_STATE_ERROR";
445 }
446}
447
448
449/** 169/**
450 * Initialize a Flow Control structure to the initial state. 170 * Lookup a connection by its identifier.
451 * 171 *
452 * @param fc Flow Control structure to initialize. 172 * @param cid identifier to resolve
173 * @return NULL if connection was not found
453 */ 174 */
454static void 175struct CadetConnection *
455fc_init (struct CadetFlowControl *fc) 176GCC_lookup (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
456{
457 fc->next_pid.pid = 0;
458 fc->last_pid_sent.pid = htonl (UINT32_MAX);
459 fc->last_pid_recv.pid = htonl (UINT32_MAX);
460 fc->last_ack_sent.pid = (uint32_t) 0;
461 fc->last_ack_recv.pid = (uint32_t) 0;
462 fc->poll_task = NULL;
463 fc->poll_time = GNUNET_TIME_UNIT_SECONDS;
464 fc->queue_n = 0;
465 fc->queue_max = (max_msgs_queue / max_connections) + 1;
466}
467
468
469/**
470 * Find a connection.
471 *
472 * @param cid Connection ID.
473 *
474 * @return conntection with the given ID @cid or NULL if not found.
475 */
476static struct CadetConnection *
477connection_get (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
478{ 177{
479 return GNUNET_CONTAINER_multishortmap_get (connections, 178 return GNUNET_CONTAINER_multishortmap_get (connections,
480 &cid->connection_of_tunnel); 179 &cid->connection_of_tunnel);
@@ -482,3232 +181,911 @@ connection_get (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
482 181
483 182
484/** 183/**
485 * Change the connection state. Cannot change a connection marked as destroyed. 184 * Update the connection state. Also triggers the necessary
185 * MQM notifications.
486 * 186 *
487 * @param c Connection to change. 187 * @param cc connection to update the state for
488 * @param state New state to set. 188 * @param new_state new state for @a cc
189 * @param new_mqm_ready new `mqm_ready` state for @a cc
489 */ 190 */
490static void 191static void
491connection_change_state (struct CadetConnection* c, 192update_state (struct CadetConnection *cc,
492 enum CadetConnectionState state) 193 enum CadetConnectionState new_state,
194 int new_mqm_ready)
493{ 195{
494 LOG (GNUNET_ERROR_TYPE_DEBUG, 196 int old_ready;
495 "Connection %s state %s -> %s\n", 197 int new_ready;
496 GCC_2s (c), GCC_state2s (c->state), GCC_state2s (state));
497 if (CADET_CONNECTION_DESTROYED <= c->state) /* Destroyed or broken. */
498 {
499 LOG (GNUNET_ERROR_TYPE_DEBUG, "state not changing anymore\n");
500 return;
501 }
502 c->state = state;
503 if (CADET_CONNECTION_READY == state)
504 c->create_retry = 1;
505}
506
507 198
508/** 199 if ( (new_state == cc->state) &&
509 * Mark a connection as "destroyed", to send all pending traffic and freeing 200 (new_mqm_ready == cc->mqm_ready) )
510 * all associated resources, without accepting new status changes on it. 201 return; /* no change, nothing to do */
511 * 202 old_ready = ( (CADET_CONNECTION_READY == cc->state) &&
512 * @param c Connection to mark as destroyed. 203 (GNUNET_YES == cc->mqm_ready) );
513 */ 204 new_ready = ( (CADET_CONNECTION_READY == new_state) &&
514static void 205 (GNUNET_YES == new_mqm_ready) );
515mark_destroyed (struct CadetConnection *c) 206 cc->state = new_state;
516{ 207 cc->mqm_ready = new_mqm_ready;
517 c->destroy = GNUNET_YES; 208 if (old_ready != new_ready)
518 connection_change_state (c, CADET_CONNECTION_DESTROYED); 209 cc->ready_cb (cc->ready_cb_cls,
210 new_ready);
519} 211}
520 212
521 213
522/** 214/**
523 * Function called if a connection has been stalled for a while, 215 * Destroy a connection, part of the internal implementation. Called
524 * possibly due to a missed ACK. Poll the neighbor about its ACK status. 216 * only from #GCC_destroy_from_core() or #GCC_destroy_from_tunnel().
525 *
526 * @param cls Closure (poll ctx).
527 */
528static void
529send_poll (void *cls);
530
531
532/**
533 * Send an ACK on the connection, informing the predecessor about
534 * the available buffer space. Should not be called in case the peer
535 * is origin (no predecessor) in the @c fwd direction.
536 *
537 * Note that for fwd ack, the FWD mean forward *traffic* (root->dest),
538 * the ACK itself goes "back" (dest->root).
539 * 217 *
540 * @param c Connection on which to send the ACK. 218 * @param cc connection to destroy
541 * @param buffer How much space free to advertise?
542 * @param fwd Is this FWD ACK? (Going dest -> root)
543 * @param force Don't optimize out.
544 */ 219 */
545static void 220static void
546send_ack (struct CadetConnection *c, 221GCC_destroy (struct CadetConnection *cc)
547 unsigned int buffer,
548 int fwd,
549 int force)
550{ 222{
551 static struct CadetEncryptedMessageIdentifier zero;
552 struct CadetFlowControl *next_fc;
553 struct CadetFlowControl *prev_fc;
554 struct GNUNET_CADET_ConnectionEncryptedAckMessage msg;
555 struct CadetEncryptedMessageIdentifier ack_cemi;
556 int delta;
557
558 GCC_check_connections ();
559 GNUNET_assert (GNUNET_NO == GCC_is_origin (c, fwd));
560
561 next_fc = fwd ? &c->fwd_fc : &c->bck_fc;
562 prev_fc = fwd ? &c->bck_fc : &c->fwd_fc;
563
564 LOG (GNUNET_ERROR_TYPE_DEBUG, "send %s ack on %s\n",
565 GC_f2s (fwd), GCC_2s (c));
566
567 /* Check if we need to transmit the ACK. */
568 delta = ntohl (prev_fc->last_ack_sent.pid) - ntohl (prev_fc->last_pid_recv.pid);
569 if (3 < delta && buffer < delta && GNUNET_NO == force)
570 {
571 LOG (GNUNET_ERROR_TYPE_DEBUG, "Not sending ACK, delta > 3\n");
572 LOG (GNUNET_ERROR_TYPE_DEBUG,
573 " last pid recv: %u, last ack sent: %u\n",
574 ntohl (prev_fc->last_pid_recv.pid),
575 ntohl (prev_fc->last_ack_sent.pid));
576 GCC_check_connections ();
577 return;
578 }
579
580 /* Ok, ACK might be necessary, what PID to ACK? */
581 ack_cemi.pid = htonl (ntohl (prev_fc->last_pid_recv.pid) + buffer);
582 LOG (GNUNET_ERROR_TYPE_DEBUG, 223 LOG (GNUNET_ERROR_TYPE_DEBUG,
583 " ACK %u, last PID %u, last ACK %u, qmax %u, q %u\n", 224 "Destroying %s\n",
584 ntohl (ack_cemi.pid), 225 GCC_2s (cc));
585 ntohl (prev_fc->last_pid_recv.pid), 226 if (NULL != cc->mq_man)
586 ntohl (prev_fc->last_ack_sent.pid),
587 next_fc->queue_max, next_fc->queue_n);
588 if ( (ack_cemi.pid == prev_fc->last_ack_sent.pid) &&
589 (GNUNET_NO == force) )
590 {
591 LOG (GNUNET_ERROR_TYPE_DEBUG, "Not sending FWD ACK, not needed\n");
592 GCC_check_connections ();
593 return;
594 }
595
596 /* Check if message is already in queue */
597 if (NULL != prev_fc->ack_msg)
598 {
599 if (GC_is_pid_bigger (ntohl (ack_cemi.pid),
600 ntohl (prev_fc->last_ack_sent.pid)))
601 {
602 LOG (GNUNET_ERROR_TYPE_DEBUG, " canceling old ACK\n");
603 GCC_cancel (prev_fc->ack_msg);
604 /* GCC_cancel triggers ack_sent(), which clears fc->ack_msg */
605 }
606 else
607 {
608 LOG (GNUNET_ERROR_TYPE_DEBUG, " same ACK already in queue\n");
609 GCC_check_connections ();
610 return;
611 }
612 }
613 GNUNET_break (GC_is_pid_bigger (ntohl (ack_cemi.pid),
614 ntohl (prev_fc->last_ack_sent.pid)));
615 prev_fc->last_ack_sent = ack_cemi;
616
617 /* Build ACK message and send on conn */
618 msg.header.size = htons (sizeof (msg));
619 msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_HOP_BY_HOP_ENCRYPTED_ACK);
620 msg.cemi_max = ack_cemi;
621 msg.cid = c->id;
622
623 prev_fc->ack_msg = GCC_send_prebuilt_message (&msg.header,
624 UINT16_MAX,
625 zero,
626 c,
627 !fwd,
628 GNUNET_YES,
629 NULL, NULL);
630 GNUNET_assert (NULL != prev_fc->ack_msg);
631 GCC_check_connections ();
632}
633
634
635/**
636 * Update performance information if we are a connection's endpoint.
637 *
638 * @param c Connection to update.
639 * @param wait How much time did we wait to send the last message.
640 * @param size Size of the last message.
641 */
642static void
643update_perf (struct CadetConnection *c,
644 struct GNUNET_TIME_Relative wait,
645 uint16_t size)
646{
647 struct CadetConnectionPerformance *p;
648 double usecsperbyte;
649
650 if (NULL == c->perf)
651 return; /* Only endpoints are interested in timing. */
652
653 p = c->perf;
654 usecsperbyte = ((double) wait.rel_value_us) / size;
655 if (p->size == AVG_MSGS)
656 {
657 /* Array is full. Substract oldest value, add new one and store. */
658 p->avg -= (p->usecsperbyte[p->idx] / AVG_MSGS);
659 p->usecsperbyte[p->idx] = usecsperbyte;
660 p->avg += (p->usecsperbyte[p->idx] / AVG_MSGS);
661 }
662 else
663 {
664 /* Array not yet full. Add current value to avg and store. */
665 p->usecsperbyte[p->idx] = usecsperbyte;
666 p->avg *= p->size;
667 p->avg += p->usecsperbyte[p->idx];
668 p->size++;
669 p->avg /= p->size;
670 }
671 p->idx = (p->idx + 1) % AVG_MSGS;
672}
673
674
675/**
676 * Callback called when a connection queued message is sent.
677 *
678 * Calculates the average time and connection packet tracking.
679 *
680 * @param cls Closure (ConnectionQueue Handle), can be NULL.
681 * @param c Connection this message was on.
682 * @param fwd Was this a FWD going message?
683 * @param sent Was it really sent? (Could have been canceled)
684 * @param type Type of message sent.
685 * @param payload_type Type of payload, if applicable.
686 * @param pid Message ID, or 0 if not applicable (create, destroy, etc).
687 * @param size Size of the message.
688 * @param wait Time spent waiting for core (only the time for THIS message)
689 */
690static void
691conn_message_sent (void *cls,
692 struct CadetConnection *c,
693 int fwd,
694 int sent,
695 uint16_t type,
696 uint16_t payload_type,
697 struct CadetEncryptedMessageIdentifier pid,
698 size_t size,
699 struct GNUNET_TIME_Relative wait)
700{
701 struct CadetConnectionQueue *q = cls;
702 struct CadetFlowControl *fc;
703 int forced;
704
705 GCC_check_connections ();
706 LOG (GNUNET_ERROR_TYPE_INFO,
707 ">>> %s (%s %4u) on conn %s (%p) %s [%5u] in queue %s\n",
708 GC_m2s (type), GC_m2s (payload_type),
709 ntohl (pid.pid),
710 GCC_2s (c),
711 c,
712 GC_f2s (fwd), size,
713 GNUNET_STRINGS_relative_time_to_string (wait, GNUNET_YES));
714
715 /* If c is NULL, nothing to update. */
716 if (NULL == c)
717 {
718 if (type != GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN
719 && type != GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY)
720 {
721 LOG (GNUNET_ERROR_TYPE_ERROR, "Message %s sent on NULL connection!\n",
722 GC_m2s (type));
723 }
724 GCC_check_connections ();
725 return;
726 }
727
728 LOG (GNUNET_ERROR_TYPE_DEBUG, " %ssent %s %s pid %u\n",
729 sent ? "" : "not ", GC_f2s (fwd),
730 GC_m2s (type), GC_m2s (payload_type),
731 ntohl (pid.pid));
732 GCC_debug (c, GNUNET_ERROR_TYPE_DEBUG);
733
734 /* Update flow control info. */
735 fc = fwd ? &c->fwd_fc : &c->bck_fc;
736
737 if (NULL != q)
738 { 227 {
739 GNUNET_CONTAINER_DLL_remove (fc->q_head, fc->q_tail, q); 228 GCP_request_mq_cancel (cc->mq_man,
740 forced = q->forced; 229 NULL);
741 if (NULL != q->cont) 230 cc->mq_man = NULL;
742 {
743 LOG (GNUNET_ERROR_TYPE_DEBUG, " calling cont\n");
744 q->cont (q->cont_cls, c, q, type, fwd, size);
745 }
746 GNUNET_free (q);
747 } 231 }
748 else /* CONN_CREATE or CONN_ACK */ 232 if (NULL != cc->task)
749 { 233 {
750 GNUNET_assert (GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED != type); 234 GNUNET_SCHEDULER_cancel (cc->task);
751 forced = GNUNET_YES; 235 cc->task = NULL;
752 } 236 }
753 237 if (NULL != cc->keepalive_qe)
754 LOG (GNUNET_ERROR_TYPE_DEBUG, " C_P- %p %u\n", c, c->pending_messages);
755 c->pending_messages--;
756 if ( (GNUNET_YES == c->destroy) &&
757 (0 == c->pending_messages) )
758 { 238 {
759 LOG (GNUNET_ERROR_TYPE_DEBUG, 239 GCT_send_cancel (cc->keepalive_qe);
760 "! destroying connection!\n"); 240 cc->keepalive_qe = NULL;
761 GCC_destroy (c);
762 GCC_check_connections ();
763 return;
764 } 241 }
765 242 GCPP_del_connection (cc->path,
766 /* Send ACK if needed, after accounting for sent ID in fc->queue_n */ 243 cc->off,
767 switch (type) 244 cc);
768 { 245 for (unsigned int i=0;i<cc->off;i++)
769 case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE: 246 GCP_remove_connection (GCPP_get_peer_at_offset (cc->path,
770 case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK: 247 i),
771 c->maintenance_q = NULL; 248 cc);
772 /* Don't trigger a keepalive for sent ACKs, only SYN and SYNACKs */ 249 GNUNET_assert (GNUNET_YES ==
773 if (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE == type || !fwd) 250 GNUNET_CONTAINER_multishortmap_remove (connections,
774 schedule_next_keepalive (c, fwd); 251 &GCC_get_id (cc)->connection_of_tunnel,
775 break; 252 cc));
776 253 GNUNET_free (cc);
777 case GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED:
778 if (GNUNET_YES == sent)
779 {
780 fc->last_pid_sent = pid;
781 if (GC_is_pid_bigger (ntohl (fc->last_pid_sent.pid) + 1,
782 ntohl (fc->last_ack_recv.pid)) )
783 GCC_start_poll (c, fwd);
784 GCC_send_ack (c, fwd, GNUNET_NO);
785 connection_reset_timeout (c, fwd);
786 }
787
788 LOG (GNUNET_ERROR_TYPE_DEBUG, "! Q_N- %p %u\n", fc, fc->queue_n);
789 if (GNUNET_NO == forced)
790 {
791 fc->queue_n--;
792 LOG (GNUNET_ERROR_TYPE_DEBUG,
793 "! accounting pid %u\n",
794 ntohl (fc->last_pid_sent.pid));
795 }
796 else
797 {
798 LOG (GNUNET_ERROR_TYPE_DEBUG,
799 "! forced, Q_N not accounting pid %u\n",
800 ntohl (fc->last_pid_sent.pid));
801 }
802 break;
803
804 case GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX:
805 if (GNUNET_YES == sent)
806 connection_reset_timeout (c, fwd);
807 break;
808
809 case GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED_POLL:
810 fc->poll_msg = NULL;
811 if (2 == c->destroy)
812 {
813 LOG (GNUNET_ERROR_TYPE_DEBUG, "POLL canceled on shutdown\n");
814 return;
815 }
816 if (0 == fc->queue_max)
817 {
818 LOG (GNUNET_ERROR_TYPE_DEBUG, "POLL cancelled: neighbor disconnected\n");
819 return;
820 }
821 LOG (GNUNET_ERROR_TYPE_DEBUG, "POLL sent for %s, scheduling new one!\n",
822 GCC_2s (c));
823 GNUNET_assert (NULL == fc->poll_task);
824 fc->poll_time = GNUNET_TIME_STD_BACKOFF (fc->poll_time);
825 fc->poll_task = GNUNET_SCHEDULER_add_delayed (fc->poll_time,
826 &send_poll, fc);
827 LOG (GNUNET_ERROR_TYPE_DEBUG, " task %u\n", fc->poll_task);
828 break;
829
830 case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_HOP_BY_HOP_ENCRYPTED_ACK:
831 fc->ack_msg = NULL;
832 break;
833
834 case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN:
835 case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY:
836 break;
837
838 default:
839 LOG (GNUNET_ERROR_TYPE_ERROR, "%s unknown\n", GC_m2s (type));
840 GNUNET_break (0);
841 break;
842 }
843 LOG (GNUNET_ERROR_TYPE_DEBUG, "! message sent!\n");
844
845 update_perf (c, wait, size);
846 GCC_check_connections ();
847}
848
849
850/**
851 * Get the previous hop in a connection
852 *
853 * @param c Connection.
854 *
855 * @return Previous peer in the connection.
856 */
857static struct CadetPeer *
858get_prev_hop (const struct CadetConnection *c)
859{
860 GNUNET_PEER_Id id;
861
862 if (NULL == c->path)
863 return NULL;
864 LOG (GNUNET_ERROR_TYPE_DEBUG,
865 " get prev hop %s [%u/%u]\n",
866 GCC_2s (c), c->own_pos, c->path->length);
867 if (0 == c->own_pos || c->path->length < 2)
868 id = c->path->peers[0];
869 else
870 id = c->path->peers[c->own_pos - 1];
871
872 LOG (GNUNET_ERROR_TYPE_DEBUG, " ID: %s (%u)\n",
873 GNUNET_i2s (GNUNET_PEER_resolve2 (id)), id);
874
875 return GCP_get_short (id, GNUNET_YES);
876}
877
878
879/**
880 * Get the next hop in a connection
881 *
882 * @param c Connection.
883 *
884 * @return Next peer in the connection.
885 */
886static struct CadetPeer *
887get_next_hop (const struct CadetConnection *c)
888{
889 GNUNET_PEER_Id id;
890
891 if (NULL == c->path)
892 return NULL;
893
894 LOG (GNUNET_ERROR_TYPE_DEBUG, " get next hop %s [%u/%u]\n",
895 GCC_2s (c), c->own_pos, c->path->length);
896 if ((c->path->length - 1) == c->own_pos || c->path->length < 2)
897 id = c->path->peers[c->path->length - 1];
898 else
899 id = c->path->peers[c->own_pos + 1];
900
901 LOG (GNUNET_ERROR_TYPE_DEBUG, " ID: %s (%u)\n",
902 GNUNET_i2s (GNUNET_PEER_resolve2 (id)), id);
903
904 return GCP_get_short (id, GNUNET_YES);
905} 254}
906 255
907 256
908/**
909 * Check that the direct neighbours (previous and next hop)
910 * are properly associated with this connection.
911 *
912 * @param c connection to check
913 */
914static void
915check_neighbours (const struct CadetConnection *c)
916{
917 if (NULL == c->path)
918 return; /* nothing to check */
919 GCP_check_connection (get_next_hop (c), c);
920 GCP_check_connection (get_prev_hop (c), c);
921}
922
923 257
924/** 258/**
925 * Helper for #GCC_check_connections(). Calls #check_neighbours(). 259 * Destroy a connection, called when the CORE layer is already done
260 * (i.e. has received a BROKEN message), but if we still have to
261 * communicate the destruction of the connection to the tunnel (if one
262 * exists).
926 * 263 *
927 * @param cls NULL 264 * @param cc connection to destroy
928 * @param key ignored
929 * @param value the `struct CadetConnection` to check
930 * @return #GNUNET_OK (continue to iterate)
931 */
932static int
933check_connection (void *cls,
934 const struct GNUNET_ShortHashCode *key,
935 void *value)
936{
937 struct CadetConnection *c = value;
938
939 check_neighbours (c);
940 return GNUNET_OK;
941}
942
943
944/**
945 * Check invariants for all connections using #check_neighbours().
946 */ 265 */
947void 266void
948GCC_check_connections () 267GCC_destroy_without_core (struct CadetConnection *cc)
949{
950 if (0 == CHECK_INVARIANTS)
951 return;
952 if (NULL == connections)
953 return;
954 GNUNET_CONTAINER_multishortmap_iterate (connections,
955 &check_connection,
956 NULL);
957}
958
959
960/**
961 * Get the hop in a connection.
962 *
963 * @param c Connection.
964 * @param fwd Next in the FWD direction?
965 *
966 * @return Next peer in the connection.
967 */
968static struct CadetPeer *
969get_hop (struct CadetConnection *c, int fwd)
970{
971 return (fwd) ? get_next_hop (c) : get_prev_hop (c);
972}
973
974
975/**
976 * Get a bit mask for a message received out-of-order.
977 *
978 * @param last_pid_recv Last PID we received prior to the out-of-order.
979 * @param ooo_pid PID of the out-of-order message.
980 */
981static uint32_t
982get_recv_bitmask (struct CadetEncryptedMessageIdentifier last_pid_recv,
983 struct CadetEncryptedMessageIdentifier ooo_pid)
984{
985 // FIXME: should assert that the delta is in range...
986 return 1 << (ntohl (last_pid_recv.pid) - ntohl (ooo_pid.pid));
987}
988
989
990/**
991 * Check is an out-of-order message is ok:
992 * - at most 31 messages behind.
993 * - not duplicate.
994 *
995 * @param last_pid_recv Last in-order PID received.
996 */
997static int
998is_ooo_ok (struct CadetEncryptedMessageIdentifier last_pid_recv,
999 struct CadetEncryptedMessageIdentifier ooo_pid,
1000 uint32_t ooo_bitmap)
1001{
1002 uint32_t mask;
1003
1004 if (GC_is_pid_bigger (ntohl (last_pid_recv.pid) - 31,
1005 ntohl (ooo_pid.pid)))
1006 return GNUNET_NO;
1007
1008 mask = get_recv_bitmask (last_pid_recv,
1009 ooo_pid);
1010 if (0 != (ooo_bitmap & mask))
1011 return GNUNET_NO;
1012
1013 return GNUNET_YES;
1014}
1015
1016
1017/**
1018 * Is traffic coming from this sender 'FWD' traffic?
1019 *
1020 * @param c Connection to check.
1021 * @param sender Short peer identity of neighbor.
1022 *
1023 * @return #GNUNET_YES in case the sender is the 'prev' hop and therefore
1024 * the traffic is 'FWD'.
1025 * #GNUNET_NO for BCK.
1026 * #GNUNET_SYSERR for errors (sender isn't a hop in the connection).
1027 */
1028static int
1029is_fwd (const struct CadetConnection *c,
1030 const struct CadetPeer *sender)
1031{
1032 GNUNET_PEER_Id id;
1033
1034 id = GCP_get_short_id (sender);
1035 if (GCP_get_short_id (get_prev_hop (c)) == id)
1036 return GNUNET_YES;
1037
1038 if (GCP_get_short_id (get_next_hop (c)) == id)
1039 return GNUNET_NO;
1040
1041 return GNUNET_SYSERR;
1042}
1043
1044
1045/**
1046 * Sends a CONNECTION ACK message in reponse to a received CONNECTION_CREATE
1047 * or a first CONNECTION_ACK directed to us.
1048 *
1049 * @param c Connection to confirm.
1050 * @param fwd Should we send it FWD? (root->dest)
1051 * (First (~SYNACK) goes BCK, second (~ACK) goes FWD)
1052 */
1053static void
1054send_connection_ack (struct CadetConnection *c, int fwd)
1055{
1056 static struct CadetEncryptedMessageIdentifier zero;
1057 struct GNUNET_CADET_ConnectionCreateAckMessage msg;
1058 struct CadetTunnel *t;
1059 const uint16_t size = sizeof (struct GNUNET_CADET_ConnectionCreateAckMessage);
1060 const uint16_t type = GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK;
1061
1062 GCC_check_connections ();
1063 t = c->t;
1064 LOG (GNUNET_ERROR_TYPE_INFO,
1065 "==> %s ({ C %s ACK} 0) on conn %s (%p) %s [%5u]\n",
1066 GC_m2s (type), GC_f2s (!fwd), GCC_2s (c), c, GC_f2s (fwd), size);
1067
1068 msg.header.size = htons (size);
1069 msg.header.type = htons (type);
1070 msg.reserved = htonl (0);
1071 msg.cid = c->id;
1072
1073 GNUNET_assert (NULL == c->maintenance_q);
1074 c->maintenance_q = GCP_send (get_hop (c, fwd),
1075 &msg.header,
1076 GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK,
1077 zero,
1078 c,
1079 fwd,
1080 &conn_message_sent, NULL);
1081 LOG (GNUNET_ERROR_TYPE_DEBUG, " C_P+ %p %u (conn`ACK)\n",
1082 c, c->pending_messages);
1083 c->pending_messages++;
1084
1085 if (CADET_TUNNEL_NEW == GCT_get_cstate (t))
1086 GCT_change_cstate (t, CADET_TUNNEL_WAITING);
1087 if (CADET_CONNECTION_READY != c->state)
1088 connection_change_state (c, CADET_CONNECTION_SENT);
1089 GCC_check_connections ();
1090}
1091
1092
1093/**
1094 * Send a notification that a connection is broken.
1095 *
1096 * @param c Connection that is broken.
1097 * @param id1 Peer that has disconnected.
1098 * @param id2 Peer that has disconnected.
1099 * @param fwd Direction towards which to send it.
1100 */
1101static void
1102send_broken (struct CadetConnection *c,
1103 const struct GNUNET_PeerIdentity *id1,
1104 const struct GNUNET_PeerIdentity *id2,
1105 int fwd)
1106{
1107 static struct CadetEncryptedMessageIdentifier zero;
1108 struct GNUNET_CADET_ConnectionBrokenMessage msg;
1109
1110 GCC_check_connections ();
1111 msg.header.size = htons (sizeof (struct GNUNET_CADET_ConnectionBrokenMessage));
1112 msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN);
1113 msg.cid = c->id;
1114 msg.reserved = htonl (0);
1115 msg.peer1 = *id1;
1116 msg.peer2 = *id2;
1117 (void) GCC_send_prebuilt_message (&msg.header,
1118 UINT16_MAX,
1119 zero,
1120 c,
1121 fwd,
1122 GNUNET_YES,
1123 NULL, NULL);
1124 GCC_check_connections ();
1125}
1126
1127
1128/**
1129 * Send a notification that a connection is broken, when a connection
1130 * isn't even known to the local peer or soon to be destroyed.
1131 *
1132 * @param connection_id Connection ID.
1133 * @param id1 Peer that has disconnected, probably local peer.
1134 * @param id2 Peer that has disconnected can be NULL if unknown.
1135 * @param neighbor Peer to notify (neighbor who sent the connection).
1136 */
1137static void
1138send_broken_unknown (const struct GNUNET_CADET_ConnectionTunnelIdentifier *connection_id,
1139 const struct GNUNET_PeerIdentity *id1,
1140 const struct GNUNET_PeerIdentity *id2,
1141 struct CadetPeer *neighbor)
1142{
1143 static struct CadetEncryptedMessageIdentifier zero;
1144 struct GNUNET_CADET_ConnectionBrokenMessage msg;
1145
1146 GCC_check_connections ();
1147 LOG (GNUNET_ERROR_TYPE_INFO, "--> BROKEN on unknown connection %s\n",
1148 GNUNET_sh2s (&connection_id->connection_of_tunnel));
1149
1150 msg.header.size = htons (sizeof (struct GNUNET_CADET_ConnectionBrokenMessage));
1151 msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN);
1152 msg.cid = *connection_id;
1153 msg.reserved = htonl (0);
1154 msg.peer1 = *id1;
1155 if (NULL != id2)
1156 msg.peer2 = *id2;
1157 else
1158 memset (&msg.peer2, 0, sizeof (msg.peer2));
1159 GNUNET_assert (NULL != GCP_send (neighbor,
1160 &msg.header,
1161 UINT16_MAX,
1162 zero,
1163 NULL,
1164 GNUNET_SYSERR, /* connection, fwd */
1165 NULL, NULL)); /* continuation */
1166 GCC_check_connections ();
1167}
1168
1169
1170/**
1171 * Send keepalive packets for a connection.
1172 *
1173 * @param c Connection to keep alive..
1174 * @param fwd Is this a FWD keepalive? (owner -> dest).
1175 */
1176static void
1177send_connection_keepalive (struct CadetConnection *c, int fwd)
1178{ 268{
1179 struct GNUNET_MessageHeader msg; 269 if (NULL != cc->ct)
1180 struct CadetFlowControl *fc;
1181 int tunnel_ready;
1182
1183 GCC_check_connections ();
1184 LOG (GNUNET_ERROR_TYPE_INFO,
1185 "keepalive %s for connection %s\n",
1186 GC_f2s (fwd), GCC_2s (c));
1187
1188 GNUNET_assert (NULL != c->t);
1189 fc = fwd ? &c->fwd_fc : &c->bck_fc;
1190 tunnel_ready = GNUNET_YES == GCT_has_queued_traffic (c->t)
1191 && CADET_TUNNEL_KEY_OK <= GCT_get_estate (c->t);
1192 if (0 < fc->queue_n || tunnel_ready)
1193 { 270 {
1194 LOG (GNUNET_ERROR_TYPE_INFO, "not sending keepalive, traffic in queue\n"); 271 GCT_connection_lost (cc->ct);
1195 return; 272 cc->ct = NULL;
1196 } 273 }
1197 274 GCC_destroy (cc);
1198 GNUNET_STATISTICS_update (stats, "# keepalives sent", 1, GNUNET_NO);
1199
1200 GNUNET_assert (NULL != c->t);
1201 msg.size = htons (sizeof (msg));
1202 msg.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE);
1203
1204 GNUNET_assert (NULL ==
1205 GCT_send_prebuilt_message (&msg, c->t, c,
1206 GNUNET_NO, NULL, NULL));
1207 GCC_check_connections ();
1208}
1209
1210
1211/**
1212 * Send CONNECTION_{CREATE/ACK} packets for a connection.
1213 *
1214 * @param c Connection for which to send the message.
1215 * @param fwd If #GNUNET_YES, send CREATE, otherwise send ACK.
1216 */
1217static void
1218connection_recreate (struct CadetConnection *c, int fwd)
1219{
1220 LOG (GNUNET_ERROR_TYPE_DEBUG,
1221 "sending connection recreate\n");
1222 if (fwd)
1223 GCC_send_create (c);
1224 else
1225 send_connection_ack (c, GNUNET_NO);
1226} 275}
1227 276
1228 277
1229/** 278/**
1230 * Generic connection timer management. 279 * Destroy a connection, called if the tunnel association with the
1231 * Depending on the role of the peer in the connection will send the 280 * connection was already broken, but we still need to notify the CORE
1232 * appropriate message (build or keepalive) 281 * layer about the breakage.
1233 * 282 *
1234 * @param c Conncetion to maintain. 283 * @param cc connection to destroy
1235 * @param fwd Is FWD?
1236 */ 284 */
1237static void 285void
1238connection_maintain (struct CadetConnection *c, int fwd) 286GCC_destroy_without_tunnel (struct CadetConnection *cc)
1239{ 287{
1240 if (GNUNET_NO != c->destroy) 288 cc->ct = NULL;
289 if ( (CADET_CONNECTION_SENDING_CREATE != cc->state) &&
290 (NULL != cc->mq_man) )
1241 { 291 {
1242 LOG (GNUNET_ERROR_TYPE_INFO, "not sending keepalive, being destroyed\n"); 292 struct GNUNET_MQ_Envelope *env;
1243 return; 293 struct GNUNET_CADET_ConnectionDestroyMessage *destroy_msg;
1244 }
1245
1246 if (NULL == c->t)
1247 {
1248 GNUNET_break (0);
1249 GCC_debug (c, GNUNET_ERROR_TYPE_ERROR);
1250 return;
1251 }
1252 294
1253 if (CADET_TUNNEL_SEARCHING == GCT_get_cstate (c->t)) 295 /* Need to notify next hop that we are down. */
1254 { 296 env = GNUNET_MQ_msg (destroy_msg,
1255 /* If status is SEARCHING, why is there a connection? Should be WAITING */ 297 GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY);
1256 GNUNET_break (0); 298 destroy_msg->cid = cc->cid;
1257 GCT_debug (c->t, GNUNET_ERROR_TYPE_ERROR); 299 GCP_request_mq_cancel (cc->mq_man,
1258 LOG (GNUNET_ERROR_TYPE_INFO, "not sending keepalive, tunnel SEARCHING\n"); 300 env);
1259 schedule_next_keepalive (c, fwd); 301 cc->mq_man = NULL;
1260 return;
1261 }
1262 switch (c->state)
1263 {
1264 case CADET_CONNECTION_NEW:
1265 GNUNET_break (0);
1266 /* fall-through */
1267 case CADET_CONNECTION_SENT:
1268 connection_recreate (c, fwd);
1269 break;
1270 case CADET_CONNECTION_READY:
1271 send_connection_keepalive (c, fwd);
1272 break;
1273 default:
1274 break;
1275 } 302 }
303 GCC_destroy (cc);
1276} 304}
1277 305
1278 306
1279/** 307/**
1280 * Keep the connection alive. 308 * Return the tunnel associated with this connection.
1281 * 309 *
1282 * @param c Connection to keep alive. 310 * @param cc connection to query
1283 * @param fwd Direction. 311 * @return corresponding entry in the tunnel's connection list
1284 */ 312 */
1285static void 313struct CadetTConnection *
1286connection_keepalive (struct CadetConnection *c, 314GCC_get_ct (struct CadetConnection *cc)
1287 int fwd)
1288{ 315{
1289 GCC_check_connections (); 316 return cc->ct;
1290 LOG (GNUNET_ERROR_TYPE_DEBUG,
1291 "%s keepalive for %s\n",
1292 GC_f2s (fwd), GCC_2s (c));
1293
1294 if (fwd)
1295 c->fwd_maintenance_task = NULL;
1296 else
1297 c->bck_maintenance_task = NULL;
1298 connection_maintain (c, fwd);
1299 GCC_check_connections ();
1300 /* Next execution will be scheduled by message_sent or _maintain*/
1301} 317}
1302 318
1303 319
1304/** 320/**
1305 * Keep the connection alive in the FWD direction. 321 * Obtain performance @a metrics from @a cc.
1306 * 322 *
1307 * @param cls Closure (connection to keepalive). 323 * @param cc connection to query
324 * @return the metrics
1308 */ 325 */
1309static void 326const struct CadetConnectionMetrics *
1310connection_fwd_keepalive (void *cls) 327GCC_get_metrics (struct CadetConnection *cc)
1311{ 328{
1312 struct CadetConnection *c = cls; 329 return &cc->metrics;
1313
1314 GCC_check_connections ();
1315 connection_keepalive (c,
1316 GNUNET_YES);
1317 GCC_check_connections ();
1318} 330}
1319 331
1320 332
1321/** 333/**
1322 * Keep the connection alive in the BCK direction. 334 * Send a #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE through the
335 * tunnel to prevent it from timing out.
1323 * 336 *
1324 * @param cls Closure (connection to keepalive). 337 * @param cls the `struct CadetConnection` to keep alive.
1325 */ 338 */
1326static void 339static void
1327connection_bck_keepalive (void *cls) 340send_keepalive (void *cls);
1328{
1329 struct CadetConnection *c = cls;
1330
1331 GCC_check_connections ();
1332 connection_keepalive (c,
1333 GNUNET_NO);
1334 GCC_check_connections ();
1335}
1336 341
1337 342
1338/** 343/**
1339 * Schedule next keepalive task, taking in consideration 344 * Keepalive was transmitted. Remember this, and possibly
1340 * the connection state and number of retries. 345 * schedule the next one.
1341 * 346 *
1342 * If the peer is not the origin, do nothing. 347 * @param cls the `struct CadetConnection` to keep alive.
1343 * 348 * @param cid identifier of the connection within the tunnel, NULL
1344 * @param c Connection for which to schedule the next keepalive. 349 * if transmission failed
1345 * @param fwd Direction for the next keepalive.
1346 */ 350 */
1347static void 351static void
1348schedule_next_keepalive (struct CadetConnection *c, int fwd) 352keepalive_done (void *cls,
353 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
1349{ 354{
1350 struct GNUNET_TIME_Relative delay; 355 struct CadetConnection *cc = cls;
1351 struct GNUNET_SCHEDULER_Task * *task_id;
1352 GNUNET_SCHEDULER_TaskCallback keepalive_task;
1353
1354 GCC_check_connections ();
1355 if (GNUNET_NO == GCC_is_origin (c, fwd))
1356 return;
1357
1358 /* Calculate delay to use, depending on the state of the connection */
1359 if (CADET_CONNECTION_READY == c->state)
1360 {
1361 delay = refresh_connection_time;
1362 }
1363 else
1364 {
1365 if (1 > c->create_retry)
1366 c->create_retry = 1;
1367 delay = GNUNET_TIME_relative_saturating_multiply (create_connection_time,
1368 c->create_retry);
1369 if (c->create_retry < 64) // TODO make configurable
1370 c->create_retry *= 2;
1371 }
1372
1373 /* Select direction-dependent parameters */
1374 if (GNUNET_YES == fwd)
1375 {
1376 task_id = &c->fwd_maintenance_task;
1377 keepalive_task = &connection_fwd_keepalive;
1378 }
1379 else
1380 {
1381 task_id = &c->bck_maintenance_task;
1382 keepalive_task = &connection_bck_keepalive;
1383 }
1384 356
1385 /* Check that no one scheduled it before us */ 357 cc->keepalive_qe = NULL;
1386 if (NULL != *task_id) 358 if ( (GNUNET_YES == cc->mqm_ready) &&
1387 { 359 (NULL == cc->task) )
1388 /* No need for a _break. It can happen for instance when sending a SYNACK 360 cc->task = GNUNET_SCHEDULER_add_delayed (keepalive_period,
1389 * for a duplicate SYN: the first SYNACK scheduled the task. */ 361 &send_keepalive,
1390 GNUNET_SCHEDULER_cancel (*task_id); 362 cc);
1391 }
1392
1393 /* Schedule the task */
1394 *task_id = GNUNET_SCHEDULER_add_delayed (delay,
1395 keepalive_task,
1396 c);
1397 LOG (GNUNET_ERROR_TYPE_INFO,
1398 "next keepalive for %s in in %s\n",
1399 GCC_2s (c), GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
1400 GCC_check_connections ();
1401} 363}
1402 364
1403 365
1404/** 366/**
1405 * Cancel all transmissions that belong to a certain connection. 367 * Send a #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE through the
368 * tunnel to prevent it from timing out.
1406 * 369 *
1407 * If the connection is scheduled for destruction and no more messages are left, 370 * @param cls the `struct CadetConnection` to keep alive.
1408 * the connection will be destroyed by the continuation call.
1409 *
1410 * @param c Connection which to cancel. Might be destroyed during this call.
1411 * @param fwd Cancel fwd traffic?
1412 */ 371 */
1413static void 372static void
1414connection_cancel_queues (struct CadetConnection *c, 373send_keepalive (void *cls)
1415 int fwd)
1416{ 374{
1417 struct CadetFlowControl *fc; 375 struct CadetConnection *cc = cls;
376 struct GNUNET_MessageHeader msg;
1418 377
1419 GCC_check_connections (); 378 cc->task = NULL;
1420 LOG (GNUNET_ERROR_TYPE_DEBUG, 379 if (CADET_TUNNEL_KEY_OK != GCT_get_estate (cc->ct->t))
1421 "Cancel %s queues for connection %s\n",
1422 GC_f2s (fwd), GCC_2s (c));
1423 if (NULL == c)
1424 { 380 {
1425 GNUNET_break (0); 381 /* Tunnel not yet ready, wait with keepalives... */
382 cc->task = GNUNET_SCHEDULER_add_delayed (keepalive_period,
383 &send_keepalive,
384 cc);
1426 return; 385 return;
1427 } 386 }
1428 387 GNUNET_assert (NULL != cc->ct);
1429 fc = fwd ? &c->fwd_fc : &c->bck_fc; 388 GNUNET_assert (GNUNET_YES == cc->mqm_ready);
1430 if (NULL != fc->poll_task) 389 GNUNET_assert (NULL == cc->keepalive_qe);
1431 {
1432 GNUNET_SCHEDULER_cancel (fc->poll_task);
1433 fc->poll_task = NULL;
1434 LOG (GNUNET_ERROR_TYPE_DEBUG, " cancelled POLL task for fc %p\n", fc);
1435 }
1436 if (NULL != fc->poll_msg)
1437 {
1438 GCC_cancel (fc->poll_msg);
1439 LOG (GNUNET_ERROR_TYPE_DEBUG, " cancelled POLL msg for fc %p\n", fc);
1440 }
1441
1442 while (NULL != fc->q_head)
1443 {
1444 GCC_cancel (fc->q_head);
1445 }
1446 GCC_check_connections ();
1447}
1448
1449
1450/**
1451 * Function called if a connection has been stalled for a while,
1452 * possibly due to a missed ACK. Poll the neighbor about its ACK status.
1453 *
1454 * @param cls Closure (poll ctx).
1455 */
1456static void
1457send_poll (void *cls)
1458{
1459 static struct CadetEncryptedMessageIdentifier zero;
1460 struct CadetFlowControl *fc = cls;
1461 struct GNUNET_CADET_ConnectionHopByHopPollMessage msg;
1462 struct CadetConnection *c;
1463 int fwd;
1464
1465 fc->poll_task = NULL;
1466 GCC_check_connections ();
1467 c = fc->c;
1468 fwd = fc == &c->fwd_fc;
1469 LOG (GNUNET_ERROR_TYPE_DEBUG, "Polling connection %s %s\n",
1470 GCC_2s (c), GC_f2s (fwd));
1471
1472 msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED_POLL);
1473 msg.header.size = htons (sizeof (msg));
1474 msg.cid = c->id;
1475 msg.cemi = fc->last_pid_sent;
1476 LOG (GNUNET_ERROR_TYPE_DEBUG, " last pid sent: %u\n", ntohl (fc->last_pid_sent.pid));
1477 fc->poll_msg
1478 = GCC_send_prebuilt_message (&msg.header,
1479 UINT16_MAX,
1480 zero,
1481 c,
1482 fc == &c->fwd_fc,
1483 GNUNET_YES,
1484 NULL,
1485 NULL);
1486 GNUNET_assert (NULL != fc->poll_msg);
1487 GCC_check_connections ();
1488}
1489
1490
1491/**
1492 * Generic connection timeout implementation.
1493 *
1494 * Timeout function due to lack of keepalive/traffic from an endpoint.
1495 * Destroys connection if called.
1496 *
1497 * @param c Connection to destroy.
1498 * @param fwd Was the timeout from the origin? (FWD timeout)
1499 */
1500static void
1501connection_timeout (struct CadetConnection *c, int fwd)
1502{
1503 GCC_check_connections ();
1504
1505 LOG (GNUNET_ERROR_TYPE_INFO, 390 LOG (GNUNET_ERROR_TYPE_INFO,
1506 "Connection %s %s timed out. Destroying.\n", 391 "Sending KEEPALIVE on behalf of %s via %s\n",
1507 GCC_2s (c), 392 GCC_2s (cc),
1508 GC_f2s (fwd)); 393 GCT_2s (cc->ct->t));
1509 GCC_debug (c, GNUNET_ERROR_TYPE_DEBUG); 394 GNUNET_STATISTICS_update (stats,
1510 395 "# keepalives sent",
1511 if (GCC_is_origin (c, fwd)) /* Loopback? Something is wrong! */ 396 1,
1512 { 397 GNUNET_NO);
1513 GNUNET_break (0); 398 msg.size = htons (sizeof (msg));
1514 return; 399 msg.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE);
1515 }
1516
1517 /* If dest, send "broken" notification. */
1518 if (GCC_is_terminal (c, fwd))
1519 {
1520 struct CadetPeer *next_hop;
1521
1522 next_hop = fwd ? get_prev_hop (c) : get_next_hop (c);
1523 send_broken_unknown (&c->id, &my_full_id, NULL, next_hop);
1524 }
1525
1526 GCC_destroy (c);
1527 GCC_check_connections ();
1528}
1529
1530
1531/**
1532 * Timeout function due to lack of keepalive/traffic from the owner.
1533 * Destroys connection if called.
1534 *
1535 * @param cls Closure (connection to destroy).
1536 */
1537static void
1538connection_fwd_timeout (void *cls)
1539{
1540 struct CadetConnection *c = cls;
1541
1542 c->fwd_maintenance_task = NULL;
1543 GCC_check_connections ();
1544 connection_timeout (c, GNUNET_YES);
1545 GCC_check_connections ();
1546}
1547
1548
1549/**
1550 * Timeout function due to lack of keepalive/traffic from the destination.
1551 * Destroys connection if called.
1552 *
1553 * @param cls Closure (connection to destroy).
1554 */
1555static void
1556connection_bck_timeout (void *cls)
1557{
1558 struct CadetConnection *c = cls;
1559 400
1560 c->bck_maintenance_task = NULL; 401 cc->keepalive_qe
1561 GCC_check_connections (); 402 = GCT_send (cc->ct->t,
1562 connection_timeout (c, GNUNET_NO); 403 &msg,
1563 GCC_check_connections (); 404 &keepalive_done,
405 cc);
1564} 406}
1565 407
1566 408
1567/** 409/**
1568 * Resets the connection timeout task, some other message has done the 410 * We sent a message for which we expect to receive an ACK via
1569 * task's job. 411 * the connection identified by @a cti.
1570 * - For the first peer on the direction this means to send
1571 * a keepalive or a path confirmation message (either create or ACK).
1572 * - For all other peers, this means to destroy the connection,
1573 * due to lack of activity.
1574 * Starts the timeout if no timeout was running (connection just created).
1575 *
1576 * @param c Connection whose timeout to reset.
1577 * @param fwd Is this forward?
1578 * 412 *
1579 * TODO use heap to improve efficiency of scheduler. 413 * @param cid connection identifier where we expect an ACK
1580 */ 414 */
1581static void 415void
1582connection_reset_timeout (struct CadetConnection *c, int fwd) 416GCC_ack_expected (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
1583{ 417{
1584 LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection %s reset timeout\n", GC_f2s (fwd)); 418 struct CadetConnection *cc;
1585 if (GCC_is_origin (c, fwd)) /* Startpoint */
1586 {
1587 schedule_next_keepalive (c, fwd);
1588 if (NULL != c->maintenance_q)
1589 {
1590 GCP_send_cancel (c->maintenance_q);
1591 c->maintenance_q = NULL; /* Is set to NULL by conn_message_sent anyway */
1592 }
1593 }
1594 else /* Relay, endpoint. */
1595 {
1596 struct GNUNET_TIME_Relative delay;
1597 struct GNUNET_SCHEDULER_Task * *ti;
1598 GNUNET_SCHEDULER_TaskCallback f;
1599
1600 ti = fwd ? &c->fwd_maintenance_task : &c->bck_maintenance_task;
1601 419
1602 if (NULL != *ti) 420 cc = GCC_lookup (cid);
1603 GNUNET_SCHEDULER_cancel (*ti); 421 if (NULL == cc)
1604 delay = GNUNET_TIME_relative_saturating_multiply (refresh_connection_time, 4); 422 return; /* whopise, connection alredy down? */
1605 LOG (GNUNET_ERROR_TYPE_DEBUG, 423 cc->metrics.num_acked_transmissions++;
1606 " timing out in %s\n",
1607 GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_NO));
1608 f = fwd ? &connection_fwd_timeout : &connection_bck_timeout;
1609 *ti = GNUNET_SCHEDULER_add_delayed (delay, f, c);
1610 }
1611} 424}
1612 425
1613 426
1614/** 427/**
1615 * Iterator to compare each connection's path with the path of a new connection. 428 * We observed an ACK for a message that was originally sent via
429 * the connection identified by @a cti.
1616 * 430 *
1617 * If the connection coincides, the c member of path is set to the connection 431 * @param cti connection identifier where we got an ACK for a message
1618 * and the destroy flag of the connection is set. 432 * that was originally sent via this connection (the ACK
1619 * 433 * may have gotten back to us via a different connection).
1620 * @param cls Closure (new path).
1621 * @param c Connection in the tunnel to check.
1622 */ 434 */
1623static void 435void
1624check_path (void *cls, struct CadetConnection *c) 436GCC_ack_observed (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
1625{ 437{
1626 struct CadetConnection *new_conn = cls; 438 struct CadetConnection *cc;
1627 struct CadetPeerPath *path = new_conn->path;
1628
1629 LOG (GNUNET_ERROR_TYPE_DEBUG, " checking %s (%p), length %u\n",
1630 GCC_2s (c), c, c->path->length);
1631 439
1632 if (c != new_conn 440 cc = GCC_lookup (cid);
1633 && GNUNET_NO == c->destroy 441 if (NULL == cc)
1634 && CADET_CONNECTION_BROKEN != c->state 442 return; /* whopise, connection alredy down? */
1635 && CADET_CONNECTION_DESTROYED != c->state 443 cc->metrics.num_successes++;
1636 && path_equivalent (path, c->path))
1637 {
1638 new_conn->destroy = GNUNET_YES; /* Do not mark_destroyed, */
1639 new_conn->path->c = c; /* this is only a flag for the Iterator. */
1640 LOG (GNUNET_ERROR_TYPE_DEBUG, " MATCH!\n");
1641 }
1642} 444}
1643 445
1644 446
1645/** 447/**
1646 * Finds out if this path is already being used by an existing connection. 448 * We observed some the given @a latency on the connection
1647 * 449 * identified by @a cti. (The same connection was taken
1648 * Checks the tunnel towards the destination to see if it contains 450 * in both directions.)
1649 * any connection with the same path.
1650 * 451 *
1651 * If the existing connection is ready, it is kept. 452 * @param cid connection identifier where we measured latency
1652 * Otherwise if the sender has a smaller ID that ours, we accept it (and 453 * @param latency the observed latency
1653 * the peer will eventually reject our attempt).
1654 *
1655 * @param path Path to check.
1656 * @return #GNUNET_YES if the tunnel has a connection with the same path,
1657 * #GNUNET_NO otherwise.
1658 */ 454 */
1659static int 455void
1660does_connection_exist (struct CadetConnection *conn) 456GCC_latency_observed (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
457 struct GNUNET_TIME_Relative latency)
1661{ 458{
1662 struct CadetPeer *p; 459 struct CadetConnection *cc;
1663 struct CadetTunnel *t; 460 double weight;
1664 struct CadetConnection *c; 461 double result;
1665
1666 p = GCP_get_short (conn->path->peers[0], GNUNET_NO);
1667 if (NULL == p)
1668 return GNUNET_NO;
1669 t = GCP_get_tunnel (p);
1670 if (NULL == t)
1671 return GNUNET_NO;
1672
1673 LOG (GNUNET_ERROR_TYPE_DEBUG, "Checking for duplicates\n");
1674 462
1675 GCT_iterate_connections (t, &check_path, conn); 463 cc = GCC_lookup (cid);
1676 464 if (NULL == cc)
1677 if (GNUNET_YES == conn->destroy) 465 return; /* whopise, connection alredy down? */
1678 { 466 GNUNET_STATISTICS_update (stats,
1679 c = conn->path->c; 467 "# latencies observed",
1680 conn->destroy = GNUNET_NO; 468 1,
1681 conn->path->c = conn; 469 GNUNET_NO);
1682 LOG (GNUNET_ERROR_TYPE_DEBUG, " found duplicate of %s\n", GCC_2s (conn)); 470 cc->latency_datapoints++;
1683 LOG (GNUNET_ERROR_TYPE_DEBUG, " duplicate: %s\n", GCC_2s (c)); 471 if (cc->latency_datapoints >= 7)
1684 GCC_debug (c, GNUNET_ERROR_TYPE_DEBUG); 472 weight = 7.0;
1685 if (CADET_CONNECTION_READY == c->state)
1686 {
1687 /* The other peer confirmed a live connection with this path,
1688 * why are they trying to duplicate it? */
1689 GNUNET_STATISTICS_update (stats, "# duplicate connections", 1, GNUNET_NO);
1690 return GNUNET_YES;
1691 }
1692 LOG (GNUNET_ERROR_TYPE_DEBUG, " duplicate not ready, connection unique\n");
1693 return GNUNET_NO;
1694 }
1695 else 473 else
1696 { 474 weight = cc->latency_datapoints;
1697 LOG (GNUNET_ERROR_TYPE_DEBUG, " %s has no duplicates\n", GCC_2s (conn)); 475 /* Compute weighted average, giving at MOST weight 7 to the
1698 return GNUNET_NO; 476 existing values, or less if that value is based on fewer than 7
1699 } 477 measurements. */
478 result = (weight * cc->metrics.aged_latency.rel_value_us) + 1.0 * latency.rel_value_us;
479 result /= (weight + 1.0);
480 cc->metrics.aged_latency.rel_value_us = (uint64_t) result;
1700} 481}
1701 482
1702 483
1703/** 484/**
1704 * @brief Check if the tunnel this connection belongs to has any other 485 * A #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK was received for this connection, implying
1705 * connection with the same path, and destroy one if so. 486 * that the end-to-end connection is up. Process it.
1706 * 487 *
1707 * @param cls Closure (connection to check). 488 * @param cc the connection that got the ACK.
1708 */
1709static void
1710check_duplicates (void *cls)
1711{
1712 struct CadetConnection *c = cls;
1713
1714 c->check_duplicates_task = NULL;
1715 if (GNUNET_YES == does_connection_exist (c))
1716 {
1717 GCT_debug (c->t, GNUNET_ERROR_TYPE_DEBUG);
1718 send_broken (c, &my_full_id, &my_full_id, GCC_is_origin (c, GNUNET_YES));
1719 GCC_destroy (c);
1720 }
1721}
1722
1723
1724/**
1725 * Wait for enough time to let any dead connections time out and check for
1726 * any remaining duplicates.
1727 *
1728 * @param c Connection that is a potential duplicate.
1729 */
1730static void
1731schedule_check_duplicates (struct CadetConnection *c)
1732{
1733 struct GNUNET_TIME_Relative delay;
1734
1735 if (NULL != c->check_duplicates_task)
1736 return;
1737 delay = GNUNET_TIME_relative_saturating_multiply (refresh_connection_time, 5);
1738 c->check_duplicates_task = GNUNET_SCHEDULER_add_delayed (delay,
1739 &check_duplicates,
1740 c);
1741}
1742
1743
1744/**
1745 * Add the connection to the list of both neighbors.
1746 *
1747 * @param c Connection.
1748 *
1749 * @return #GNUNET_OK if everything went fine
1750 * #GNUNET_SYSERR if the was an error and @c c is malformed.
1751 */
1752static int
1753register_neighbors (struct CadetConnection *c)
1754{
1755 c->next_peer = get_next_hop (c);
1756 c->prev_peer = get_prev_hop (c);
1757 GNUNET_assert (c->next_peer != c->prev_peer);
1758 LOG (GNUNET_ERROR_TYPE_DEBUG,
1759 "register neighbors for connection %s\n",
1760 GCC_2s (c));
1761 path_debug (c->path);
1762 LOG (GNUNET_ERROR_TYPE_DEBUG,
1763 "own pos %u\n", c->own_pos);
1764 LOG (GNUNET_ERROR_TYPE_DEBUG,
1765 "putting connection %s to next peer %p\n",
1766 GCC_2s (c),
1767 c->next_peer);
1768 LOG (GNUNET_ERROR_TYPE_DEBUG, "next peer %p %s\n",
1769 c->next_peer,
1770 GCP_2s (c->next_peer));
1771 LOG (GNUNET_ERROR_TYPE_DEBUG,
1772 "putting connection %s to prev peer %p\n",
1773 GCC_2s (c),
1774 c->prev_peer);
1775 LOG (GNUNET_ERROR_TYPE_DEBUG,
1776 "prev peer %p %s\n",
1777 c->prev_peer,
1778 GCP_2s (c->prev_peer));
1779
1780 if ( (GNUNET_NO == GCP_is_neighbor (c->next_peer)) ||
1781 (GNUNET_NO == GCP_is_neighbor (c->prev_peer)) )
1782 {
1783 if (GCC_is_origin (c, GNUNET_YES))
1784 GNUNET_STATISTICS_update (stats, "# local bad paths", 1, GNUNET_NO);
1785 GNUNET_STATISTICS_update (stats, "# bad paths", 1, GNUNET_NO);
1786
1787 LOG (GNUNET_ERROR_TYPE_DEBUG,
1788 " register neighbors failed\n");
1789 LOG (GNUNET_ERROR_TYPE_DEBUG,
1790 " prev: %s, neighbor?: %d\n",
1791 GCP_2s (c->prev_peer),
1792 GCP_is_neighbor (c->prev_peer));
1793 LOG (GNUNET_ERROR_TYPE_DEBUG,
1794 " next: %s, neighbor?: %d\n",
1795 GCP_2s (c->next_peer),
1796 GCP_is_neighbor (c->next_peer));
1797 return GNUNET_SYSERR;
1798 }
1799 GCP_add_connection (c->next_peer, c, GNUNET_NO);
1800 GCP_add_connection (c->prev_peer, c, GNUNET_YES);
1801
1802 return GNUNET_OK;
1803}
1804
1805
1806/**
1807 * Remove the connection from the list of both neighbors.
1808 *
1809 * @param c Connection.
1810 */
1811static void
1812unregister_neighbors (struct CadetConnection *c)
1813{
1814// struct CadetPeer *peer; FIXME dont use next_peer, prev_peer
1815 /* Either already unregistered or never got registered, it's ok either way. */
1816 if (NULL == c->path)
1817 return;
1818 if (NULL != c->next_peer)
1819 {
1820 GCP_remove_connection (c->next_peer, c);
1821 c->next_peer = NULL;
1822 }
1823 if (NULL != c->prev_peer)
1824 {
1825 GCP_remove_connection (c->prev_peer, c);
1826 c->prev_peer = NULL;
1827 }
1828}
1829
1830
1831/**
1832 * Invalidates all paths towards all peers that comprise the connection which
1833 * rely on the disconnected peer.
1834 *
1835 * ~O(n^3) (peers in connection * paths/peer * links/path)
1836 *
1837 * @param c Connection whose peers' paths to clean.
1838 * @param disconnected Peer that disconnected.
1839 */
1840static void
1841invalidate_paths (struct CadetConnection *c,
1842 struct CadetPeer *disconnected)
1843{
1844 struct CadetPeer *peer;
1845 unsigned int i;
1846
1847 for (i = 0; i < c->path->length; i++)
1848 {
1849 peer = GCP_get_short (c->path->peers[i], GNUNET_NO);
1850 if (NULL != peer)
1851 GCP_notify_broken_link (peer, &my_full_id, GCP_get_id (disconnected));
1852 }
1853}
1854
1855
1856/**
1857 * Bind the connection to the peer and the tunnel to that peer.
1858 *
1859 * If the peer has no tunnel, create one. Update tunnel and connection
1860 * data structres to reflect new status.
1861 *
1862 * @param c Connection.
1863 * @param peer Peer.
1864 */
1865static void
1866add_to_peer (struct CadetConnection *c,
1867 struct CadetPeer *peer)
1868{
1869 GCP_add_tunnel (peer);
1870 c->t = GCP_get_tunnel (peer);
1871 GCT_add_connection (c->t, c);
1872}
1873
1874
1875/**
1876 * Log receipt of message on stderr (INFO level).
1877 *
1878 * @param message Message received.
1879 * @param peer Peer who sent the message.
1880 * @param conn_id Connection ID of the message.
1881 */
1882static void
1883log_message (const struct GNUNET_MessageHeader *message,
1884 const struct CadetPeer *peer,
1885 const struct GNUNET_CADET_ConnectionTunnelIdentifier *conn_id)
1886{
1887 uint16_t size;
1888 uint16_t type;
1889 char *arrow;
1890
1891 size = ntohs (message->size);
1892 type = ntohs (message->type);
1893 switch (type)
1894 {
1895 case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE:
1896 case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK:
1897 case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN:
1898 case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY:
1899 arrow = "==";
1900 break;
1901 default:
1902 arrow = "--";
1903 }
1904 LOG (GNUNET_ERROR_TYPE_INFO,
1905 "<%s %s on conn %s from %s, %6u bytes\n",
1906 arrow,
1907 GC_m2s (type),
1908 GNUNET_sh2s (&conn_id->connection_of_tunnel),
1909 GCP_2s(peer),
1910 (unsigned int) size);
1911}
1912
1913/******************************************************************************/
1914/******************************** API ***********************************/
1915/******************************************************************************/
1916
1917/**
1918 * Handler for connection creation.
1919 *
1920 * @param peer Message sender (neighbor).
1921 * @param msg Message itself.
1922 */ 489 */
1923void 490void
1924GCC_handle_create (struct CadetPeer *peer, 491GCC_handle_connection_create_ack (struct CadetConnection *cc)
1925 const struct GNUNET_CADET_ConnectionCreateMessage *msg)
1926{ 492{
1927 static struct CadetEncryptedMessageIdentifier zero; 493 LOG (GNUNET_ERROR_TYPE_DEBUG,
1928 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid; 494 "Received CADET_CONNECTION_CREATE_ACK for %s in state %d (%s)\n",
1929 struct GNUNET_PeerIdentity *id; 495 GCC_2s (cc),
1930 struct CadetPeerPath *path; 496 cc->state,
1931 struct CadetPeer *dest_peer; 497 (GNUNET_YES == cc->mqm_ready) ? "MQM ready" : "MQM busy");
1932 struct CadetPeer *orig_peer; 498 if (CADET_CONNECTION_READY == cc->state)
1933 struct CadetConnection *c; 499 return; /* Duplicate ACK, ignore */
1934 unsigned int own_pos; 500 if (NULL != cc->task)
1935 uint16_t size;
1936
1937 GCC_check_connections ();
1938 size = ntohs (msg->header.size);
1939
1940 /* Calculate hops */
1941 size -= sizeof (struct GNUNET_CADET_ConnectionCreateMessage);
1942 if (0 != size % sizeof (struct GNUNET_PeerIdentity))
1943 {
1944 GNUNET_break_op (0);
1945 return;
1946 }
1947 size /= sizeof (struct GNUNET_PeerIdentity);
1948 if (1 > size)
1949 {
1950 GNUNET_break_op (0);
1951 return;
1952 }
1953 LOG (GNUNET_ERROR_TYPE_DEBUG, " path has %u hops.\n", size);
1954
1955 /* Get parameters */
1956 cid = &msg->cid;
1957 log_message (&msg->header, peer, cid);
1958 id = (struct GNUNET_PeerIdentity *) &msg[1];
1959 LOG (GNUNET_ERROR_TYPE_DEBUG, " origin: %s\n", GNUNET_i2s (id));
1960
1961 /* Create connection */
1962 c = connection_get (cid);
1963 if (NULL == c)
1964 {
1965 path = path_build_from_peer_ids ((struct GNUNET_PeerIdentity *) &msg[1],
1966 size, myid, &own_pos);
1967 if (NULL == path)
1968 {
1969 /* Path was malformed, probably our own ID was not in it. */
1970 GNUNET_STATISTICS_update (stats, "# malformed paths", 1, GNUNET_NO);
1971 GNUNET_break_op (0);
1972 return;
1973 }
1974 if (0 == own_pos)
1975 {
1976 /* We received this request from a neighbor, we cannot be origin */
1977 GNUNET_STATISTICS_update (stats, "# fake paths", 1, GNUNET_NO);
1978 GNUNET_break_op (0);
1979 path_destroy (path);
1980 return;
1981 }
1982
1983 LOG (GNUNET_ERROR_TYPE_DEBUG, " Own position: %u\n", own_pos);
1984 LOG (GNUNET_ERROR_TYPE_DEBUG, " Creating connection\n");
1985 c = GCC_new (cid, NULL, path, own_pos);
1986 if (NULL == c)
1987 {
1988 if (path->length - 1 == own_pos)
1989 {
1990 /* If we are destination, why did the creation fail? */
1991 GNUNET_break (0);
1992 path_destroy (path);
1993 GCC_check_connections ();
1994 return;
1995 }
1996 send_broken_unknown (cid, &my_full_id,
1997 GNUNET_PEER_resolve2 (path->peers[own_pos + 1]),
1998 peer);
1999 path_destroy (path);
2000 GCC_check_connections ();
2001 return;
2002 }
2003 GCP_add_path_to_all (path, GNUNET_NO);
2004 connection_reset_timeout (c, GNUNET_YES);
2005 }
2006 else
2007 {
2008 path = path_duplicate (c->path);
2009 }
2010 if (CADET_CONNECTION_NEW == c->state)
2011 connection_change_state (c, CADET_CONNECTION_SENT);
2012
2013 /* Remember peers */
2014 dest_peer = GCP_get (&id[size - 1], GNUNET_YES);
2015 orig_peer = GCP_get (&id[0], GNUNET_YES);
2016
2017 /* Is it a connection to us? */
2018 if (c->own_pos == path->length - 1)
2019 {
2020 LOG (GNUNET_ERROR_TYPE_DEBUG, " It's for us!\n");
2021 GCP_add_path_to_origin (orig_peer, path_duplicate (path), GNUNET_YES);
2022
2023 add_to_peer (c, orig_peer);
2024 if (GNUNET_YES == does_connection_exist (c))
2025 {
2026 /* Peer created a connection equal to one we think exists
2027 * and is fine.
2028 * Solution: Keep both and postpone disambiguation. In the meantime
2029 * the connection will time out or peer will inform us it is broken.
2030 *
2031 * Other options:
2032 * - Use explicit duplicate.
2033 * - Accept new conn and destroy the old. (interruption in higher level)
2034 * - Keep the one with higher ID / created by peer with higher ID. */
2035 schedule_check_duplicates (c);
2036 }
2037
2038 if (CADET_TUNNEL_NEW == GCT_get_cstate (c->t))
2039 GCT_change_cstate (c->t, CADET_TUNNEL_WAITING);
2040 if (NULL == c->maintenance_q)
2041 send_connection_ack (c, GNUNET_NO);
2042 if (CADET_CONNECTION_SENT == c->state)
2043 connection_change_state (c, CADET_CONNECTION_ACK);
2044 }
2045 else
2046 { 501 {
2047 LOG (GNUNET_ERROR_TYPE_DEBUG, " not for us, retransmitting...\n"); 502 GNUNET_SCHEDULER_cancel (cc->task);
2048 GCP_add_path (dest_peer, path_duplicate (path), GNUNET_NO); 503 cc->task = NULL;
2049 GCP_add_path_to_origin (orig_peer, path_duplicate (path), GNUNET_NO);
2050 (void) GCC_send_prebuilt_message (&msg->header,
2051 0,
2052 zero,
2053 c,
2054 GNUNET_YES, GNUNET_YES,
2055 NULL, NULL);
2056 } 504 }
2057 path_destroy (path); 505 cc->metrics.age = GNUNET_TIME_absolute_get ();
2058 GCC_check_connections (); 506 update_state (cc,
507 CADET_CONNECTION_READY,
508 cc->mqm_ready);
509 if ( (NULL == cc->keepalive_qe) &&
510 (GNUNET_YES == cc->mqm_ready) &&
511 (NULL == cc->task) )
512 cc->task = GNUNET_SCHEDULER_add_delayed (keepalive_period,
513 &send_keepalive,
514 cc);
2059} 515}
2060 516
2061 517
2062/** 518/**
2063 * Handler for connection confirmations. 519 * Handle KX message.
2064 * 520 *
2065 * @param peer Message sender (neighbor). 521 * @param cc connection that received encrypted message
2066 * @param msg Message itself. 522 * @param msg the key exchange message
2067 */ 523 */
2068void 524void
2069GCC_handle_confirm (struct CadetPeer *peer, 525GCC_handle_kx (struct CadetConnection *cc,
2070 const struct GNUNET_CADET_ConnectionCreateAckMessage *msg) 526 const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg)
2071{ 527{
2072 static struct CadetEncryptedMessageIdentifier zero; 528 if (CADET_CONNECTION_SENT == cc->state)
2073 struct CadetConnection *c;
2074 enum CadetConnectionState oldstate;
2075 int fwd;
2076
2077 GCC_check_connections ();
2078 log_message (&msg->header, peer, &msg->cid);
2079 c = connection_get (&msg->cid);
2080 if (NULL == c)
2081 {
2082 GNUNET_STATISTICS_update (stats, "# control on unknown connection",
2083 1, GNUNET_NO);
2084 LOG (GNUNET_ERROR_TYPE_DEBUG,
2085 " don't know the connection!\n");
2086 send_broken_unknown (&msg->cid, &my_full_id, NULL, peer);
2087 GCC_check_connections ();
2088 return;
2089 }
2090 if (GNUNET_NO != c->destroy)
2091 { 529 {
2092 GNUNET_assert (CADET_CONNECTION_DESTROYED == c->state); 530 /* We didn't get the CADET_CONNECTION_CREATE_ACK, but instead got payload. That's fine,
2093 GNUNET_STATISTICS_update (stats, "# control on dying connection", 531 clearly something is working, so pretend we got an ACK. */
2094 1, GNUNET_NO);
2095 LOG (GNUNET_ERROR_TYPE_DEBUG, 532 LOG (GNUNET_ERROR_TYPE_DEBUG,
2096 "connection %s being destroyed, ignoring confirm\n", 533 "Faking connection CADET_CONNECTION_CREATE_ACK for %s due to KX\n",
2097 GCC_2s (c)); 534 GCC_2s (cc));
2098 GCC_check_connections (); 535 GCC_handle_connection_create_ack (cc);
2099 return;
2100 }
2101
2102 oldstate = c->state;
2103 LOG (GNUNET_ERROR_TYPE_DEBUG, " via peer %s\n", GCP_2s (peer));
2104 if (get_next_hop (c) == peer)
2105 {
2106 LOG (GNUNET_ERROR_TYPE_DEBUG, " SYNACK\n");
2107 fwd = GNUNET_NO;
2108 if (CADET_CONNECTION_SENT == oldstate)
2109 connection_change_state (c, CADET_CONNECTION_ACK);
2110 }
2111 else if (get_prev_hop (c) == peer)
2112 {
2113 LOG (GNUNET_ERROR_TYPE_DEBUG, " FINAL ACK\n");
2114 fwd = GNUNET_YES;
2115 connection_change_state (c, CADET_CONNECTION_READY);
2116 }
2117 else
2118 {
2119 GNUNET_STATISTICS_update (stats, "# control on connection from wrong peer",
2120 1, GNUNET_NO);
2121 GNUNET_break_op (0);
2122 return;
2123 }
2124
2125 connection_reset_timeout (c, fwd);
2126
2127 GNUNET_assert (NULL != c->path);
2128 GCP_add_path_to_all (c->path, GNUNET_YES);
2129
2130 /* Message for us as creator? */
2131 if (GNUNET_YES == GCC_is_origin (c, GNUNET_YES))
2132 {
2133 if (GNUNET_NO != fwd)
2134 {
2135 GNUNET_break (0);
2136 return;
2137 }
2138 LOG (GNUNET_ERROR_TYPE_DEBUG, " Connection (SYN)ACK for us!\n");
2139
2140 /* If just created, cancel the short timeout and start a long one */
2141 if (CADET_CONNECTION_SENT == oldstate)
2142 {
2143 c->create_retry = 1;
2144 connection_reset_timeout (c, GNUNET_YES);
2145 }
2146
2147 /* Change connection state, send ACK */
2148 connection_change_state (c, CADET_CONNECTION_READY);
2149 send_connection_ack (c, GNUNET_YES);
2150
2151 /* Change tunnel state, trigger KX */
2152 if (CADET_TUNNEL_WAITING == GCT_get_cstate (c->t))
2153 GCT_change_cstate (c->t, CADET_TUNNEL_READY);
2154 GCC_check_connections ();
2155 return;
2156 }
2157
2158 /* Message for us as destination? */
2159 if (GCC_is_terminal (c, GNUNET_YES))
2160 {
2161 if (GNUNET_YES != fwd)
2162 {
2163 GNUNET_break (0);
2164 return;
2165 }
2166 LOG (GNUNET_ERROR_TYPE_DEBUG, " Connection ACK for us!\n");
2167
2168 /* If just created, cancel the short timeout and start a long one */
2169 if (CADET_CONNECTION_ACK == oldstate)
2170 connection_reset_timeout (c, GNUNET_NO);
2171
2172 /* Change tunnel state */
2173 if (CADET_TUNNEL_WAITING == GCT_get_cstate (c->t))
2174 GCT_change_cstate (c->t, CADET_TUNNEL_READY);
2175 GCC_check_connections ();
2176 } 536 }
2177 else 537 GCT_handle_kx (cc->ct,
2178 { 538 msg);
2179 LOG (GNUNET_ERROR_TYPE_DEBUG, " not for us, retransmitting...\n");
2180 (void) GCC_send_prebuilt_message (&msg->header, 0,
2181 zero,
2182 c,
2183 fwd,
2184 GNUNET_YES, NULL, NULL);
2185 }
2186 GCC_check_connections ();
2187} 539}
2188 540
2189 541
2190/** 542/**
2191 * Handler for notifications of broken connections. 543 * Handle KX_AUTH message.
2192 * 544 *
2193 * @param peer Message sender (neighbor). 545 * @param cc connection that received encrypted message
2194 * @param msg Message itself. 546 * @param msg the key exchange message
2195 */ 547 */
2196void 548void
2197GCC_handle_broken (struct CadetPeer *peer, 549GCC_handle_kx_auth (struct CadetConnection *cc,
2198 const struct GNUNET_CADET_ConnectionBrokenMessage *msg) 550 const struct GNUNET_CADET_TunnelKeyExchangeAuthMessage *msg)
2199{ 551{
2200 static struct CadetEncryptedMessageIdentifier zero; 552 if (CADET_CONNECTION_SENT == cc->state)
2201 struct CadetConnection *c;
2202 struct CadetTunnel *t;
2203 int fwd;
2204
2205 GCC_check_connections ();
2206 log_message (&msg->header, peer, &msg->cid);
2207 LOG (GNUNET_ERROR_TYPE_DEBUG, " regarding %s\n", GNUNET_i2s (&msg->peer1));
2208 LOG (GNUNET_ERROR_TYPE_DEBUG, " regarding %s\n", GNUNET_i2s (&msg->peer2));
2209 c = connection_get (&msg->cid);
2210 if (NULL == c)
2211 {
2212 LOG (GNUNET_ERROR_TYPE_DEBUG, " duplicate CONNECTION_BROKEN\n");
2213 GNUNET_STATISTICS_update (stats, "# duplicate CONNECTION_BROKEN",
2214 1, GNUNET_NO);
2215 GCC_check_connections ();
2216 return;
2217 }
2218
2219 t = c->t;
2220
2221 fwd = is_fwd (c, peer);
2222 if (GNUNET_SYSERR == fwd)
2223 {
2224 GNUNET_break_op (0);
2225 GCC_check_connections ();
2226 return;
2227 }
2228 mark_destroyed (c);
2229 if (GCC_is_terminal (c, fwd))
2230 {
2231 struct CadetPeer *endpoint;
2232
2233 if (NULL == t)
2234 {
2235 /* A terminal connection should not have 't' set to NULL. */
2236 GNUNET_break (0);
2237 GCC_debug (c, GNUNET_ERROR_TYPE_ERROR);
2238 return;
2239 }
2240 endpoint = GCP_get_short (c->path->peers[c->path->length - 1], GNUNET_YES);
2241 if (2 < c->path->length)
2242 path_invalidate (c->path);
2243 GCP_notify_broken_link (endpoint, &msg->peer1, &msg->peer2);
2244
2245 connection_change_state (c, CADET_CONNECTION_BROKEN);
2246 GCT_remove_connection (t, c);
2247 c->t = NULL;
2248
2249 GCC_destroy (c);
2250 }
2251 else
2252 { 553 {
2253 (void) GCC_send_prebuilt_message (&msg->header, 0, 554 /* We didn't get the CADET_CONNECTION_CREATE_ACK, but instead got payload. That's fine,
2254 zero, c, fwd, 555 clearly something is working, so pretend we got an ACK. */
2255 GNUNET_YES, NULL, NULL); 556 LOG (GNUNET_ERROR_TYPE_DEBUG,
2256 connection_cancel_queues (c, !fwd); 557 "Faking connection CADET_CONNECTION_CREATE_ACK for %s due to KX\n",
558 GCC_2s (cc));
559 GCC_handle_connection_create_ack (cc);
2257 } 560 }
2258 GCC_check_connections (); 561 GCT_handle_kx_auth (cc->ct,
2259 return; 562 msg);
2260} 563}
2261 564
2262 565
2263/** 566/**
2264 * Handler for notifications of destroyed connections. 567 * Handle encrypted message.
2265 * 568 *
2266 * @param peer Message sender (neighbor). 569 * @param cc connection that received encrypted message
2267 * @param msg Message itself. 570 * @param msg the encrypted message to decrypt
2268 */ 571 */
2269void 572void
2270GCC_handle_destroy (struct CadetPeer *peer, 573GCC_handle_encrypted (struct CadetConnection *cc,
2271 const struct GNUNET_CADET_ConnectionDestroyMessage *msg) 574 const struct GNUNET_CADET_TunnelEncryptedMessage *msg)
2272{ 575{
2273 static struct CadetEncryptedMessageIdentifier zero; 576 if (CADET_CONNECTION_SENT == cc->state)
2274 struct CadetConnection *c;
2275 int fwd;
2276
2277 GCC_check_connections ();
2278 log_message (&msg->header, peer, &msg->cid);
2279 c = connection_get (&msg->cid);
2280 if (NULL == c)
2281 { 577 {
2282 /* Probably already got the message from another path, 578 /* We didn't get the CREATE_ACK, but instead got payload. That's fine,
2283 * destroyed the tunnel and retransmitted to children. 579 clearly something is working, so pretend we got an ACK. */
2284 * Safe to ignore.
2285 */
2286 GNUNET_STATISTICS_update (stats,
2287 "# control on unknown connection",
2288 1, GNUNET_NO);
2289 LOG (GNUNET_ERROR_TYPE_DEBUG, 580 LOG (GNUNET_ERROR_TYPE_DEBUG,
2290 " connection unknown destroyed: previously destroyed?\n"); 581 "Faking connection ACK for %s due to ENCRYPTED payload\n",
2291 GCC_check_connections (); 582 GCC_2s (cc));
2292 return; 583 GCC_handle_connection_create_ack (cc);
2293 }
2294
2295 fwd = is_fwd (c, peer);
2296 if (GNUNET_SYSERR == fwd)
2297 {
2298 GNUNET_break_op (0);
2299 GCC_check_connections ();
2300 return;
2301 }
2302
2303 if (GNUNET_NO == GCC_is_terminal (c, fwd))
2304 {
2305 (void) GCC_send_prebuilt_message (&msg->header, 0,
2306 zero, c, fwd,
2307 GNUNET_YES, NULL, NULL);
2308 } 584 }
2309 else if (0 == c->pending_messages) 585 cc->metrics.last_use = GNUNET_TIME_absolute_get ();
2310 { 586 GCT_handle_encrypted (cc->ct,
2311 LOG (GNUNET_ERROR_TYPE_DEBUG, " directly destroying connection!\n"); 587 msg);
2312 GCC_destroy (c);
2313 GCC_check_connections ();
2314 return;
2315 }
2316 mark_destroyed (c);
2317 if (NULL != c->t)
2318 {
2319 GCT_remove_connection (c->t, c);
2320 c->t = NULL;
2321 }
2322 GCC_check_connections ();
2323 return;
2324} 588}
2325 589
2326 590
2327/** 591/**
2328 * Handler for cadet network traffic hop-by-hop acks. 592 * Send a #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE message to the
593 * first hop.
2329 * 594 *
2330 * @param peer Message sender (neighbor). 595 * @param cls the `struct CadetConnection` to initiate
2331 * @param msg Message itself.
2332 */ 596 */
2333void 597static void
2334GCC_handle_ack (struct CadetPeer *peer, 598send_create (void *cls)
2335 const struct GNUNET_CADET_ConnectionEncryptedAckMessage *msg) 599{
2336{ 600 struct CadetConnection *cc = cls;
2337 struct CadetConnection *c; 601 struct GNUNET_CADET_ConnectionCreateMessage *create_msg;
2338 struct CadetFlowControl *fc; 602 struct GNUNET_PeerIdentity *pids;
2339 struct CadetEncryptedMessageIdentifier ack; 603 struct GNUNET_MQ_Envelope *env;
2340 int fwd; 604 unsigned int path_length;
2341 605
2342 GCC_check_connections (); 606 cc->task = NULL;
2343 log_message (&msg->header, peer, &msg->cid); 607 GNUNET_assert (GNUNET_YES == cc->mqm_ready);
2344 c = connection_get (&msg->cid); 608 path_length = GCPP_get_length (cc->path);
2345 if (NULL == c) 609 env = GNUNET_MQ_msg_extra (create_msg,
2346 { 610 (1 + path_length) * sizeof (struct GNUNET_PeerIdentity),
2347 GNUNET_STATISTICS_update (stats, 611 GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE);
2348 "# ack on unknown connection", 612 create_msg->options = htonl ((uint32_t) cc->options);
2349 1, 613 create_msg->cid = cc->cid;
2350 GNUNET_NO); 614 pids = (struct GNUNET_PeerIdentity *) &create_msg[1];
2351 send_broken_unknown (&msg->cid, 615 pids[0] = my_full_id;
2352 &my_full_id, 616 for (unsigned int i=0;i<path_length;i++)
2353 NULL, 617 pids[i + 1] = *GCP_get_id (GCPP_get_peer_at_offset (cc->path,
2354 peer); 618 i));
2355 GCC_check_connections (); 619 LOG (GNUNET_ERROR_TYPE_DEBUG,
2356 return; 620 "Sending CADET_CONNECTION_CREATE message for %s\n",
2357 } 621 GCC_2s (cc));
2358 622 cc->env = env;
2359 /* Is this a forward or backward ACK? */ 623 update_state (cc,
2360 if (get_next_hop (c) == peer) 624 CADET_CONNECTION_SENT,
2361 { 625 GNUNET_NO);
2362 fc = &c->fwd_fc; 626 GCP_send (cc->mq_man,
2363 fwd = GNUNET_YES; 627 env);
2364 }
2365 else if (get_prev_hop (c) == peer)
2366 {
2367 fc = &c->bck_fc;
2368 fwd = GNUNET_NO;
2369 }
2370 else
2371 {
2372 GNUNET_break_op (0);
2373 return;
2374 }
2375
2376 ack = msg->cemi_max;
2377 LOG (GNUNET_ERROR_TYPE_DEBUG, " %s ACK %u (was %u)\n",
2378 GC_f2s (fwd),
2379 ntohl (ack.pid),
2380 ntohl (fc->last_ack_recv.pid));
2381 if (GC_is_pid_bigger (ntohl (ack.pid),
2382 ntohl (fc->last_ack_recv.pid)))
2383 fc->last_ack_recv = ack;
2384
2385 /* Cancel polling if the ACK is big enough. */
2386 if ( (NULL != fc->poll_task) &
2387 GC_is_pid_bigger (ntohl (fc->last_ack_recv.pid),
2388 ntohl (fc->last_pid_sent.pid)))
2389 {
2390 LOG (GNUNET_ERROR_TYPE_DEBUG, " Cancel poll\n");
2391 GNUNET_SCHEDULER_cancel (fc->poll_task);
2392 fc->poll_task = NULL;
2393 fc->poll_time = GNUNET_TIME_UNIT_SECONDS;
2394 }
2395
2396 GCC_check_connections ();
2397} 628}
2398 629
2399 630
2400/** 631/**
2401 * Handler for cadet network traffic hop-by-hop data counter polls. 632 * Send a CREATE_ACK message towards the origin.
2402 * 633 *
2403 * @param peer Message sender (neighbor). 634 * @param cls the `struct CadetConnection` to initiate
2404 * @param msg Message itself.
2405 */ 635 */
2406void 636static void
2407GCC_handle_poll (struct CadetPeer *peer, 637send_create_ack (void *cls)
2408 const struct GNUNET_CADET_ConnectionHopByHopPollMessage *msg)
2409{ 638{
2410 struct CadetConnection *c; 639 struct CadetConnection *cc = cls;
2411 struct CadetFlowControl *fc; 640 struct GNUNET_CADET_ConnectionCreateAckMessage *ack_msg;
2412 struct CadetEncryptedMessageIdentifier pid; 641 struct GNUNET_MQ_Envelope *env;
2413 int fwd;
2414
2415 GCC_check_connections ();
2416 log_message (&msg->header, peer, &msg->cid);
2417 c = connection_get (&msg->cid);
2418 if (NULL == c)
2419 {
2420 GNUNET_STATISTICS_update (stats, "# poll on unknown connection", 1,
2421 GNUNET_NO);
2422 LOG (GNUNET_ERROR_TYPE_DEBUG,
2423 "POLL message on unknown connection %s!\n",
2424 GNUNET_sh2s (&msg->cid.connection_of_tunnel));
2425 send_broken_unknown (&msg->cid,
2426 &my_full_id,
2427 NULL,
2428 peer);
2429 GCC_check_connections ();
2430 return;
2431 }
2432
2433 /* Is this a forward or backward ACK?
2434 * Note: a poll should never be needed in a loopback case,
2435 * since there is no possiblility of packet loss there, so
2436 * this way of discerining FWD/BCK should not be a problem.
2437 */
2438 if (get_next_hop (c) == peer)
2439 {
2440 LOG (GNUNET_ERROR_TYPE_DEBUG, " FWD FC\n");
2441 fc = &c->fwd_fc;
2442 }
2443 else if (get_prev_hop (c) == peer)
2444 {
2445 LOG (GNUNET_ERROR_TYPE_DEBUG, " BCK FC\n");
2446 fc = &c->bck_fc;
2447 }
2448 else
2449 {
2450 GNUNET_break_op (0);
2451 return;
2452 }
2453 642
2454 pid = msg->cemi; 643 cc->task = NULL;
644 GNUNET_assert (CADET_CONNECTION_CREATE_RECEIVED == cc->state);
2455 LOG (GNUNET_ERROR_TYPE_DEBUG, 645 LOG (GNUNET_ERROR_TYPE_DEBUG,
2456 " PID %u, OLD %u\n", 646 "Sending CONNECTION_CREATE_ACK message for %s\n",
2457 ntohl (pid.pid), 647 GCC_2s (cc));
2458 ntohl (fc->last_pid_recv.pid)); 648 GNUNET_assert (GNUNET_YES == cc->mqm_ready);
2459 fc->last_pid_recv = pid; 649 env = GNUNET_MQ_msg (ack_msg,
2460 fwd = fc == &c->bck_fc; 650 GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK);
2461 GCC_send_ack (c, fwd, GNUNET_YES); 651 ack_msg->cid = cc->cid;
2462 GCC_check_connections (); 652 cc->env = env;
653 update_state (cc,
654 CADET_CONNECTION_READY,
655 GNUNET_NO);
656 GCP_send (cc->mq_man,
657 env);
2463} 658}
2464 659
2465 660
2466/** 661/**
2467 * Check the message against internal state and test if it goes FWD or BCK. 662 * We got a #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE for a
2468 * 663 * connection that we already have. Either our ACK got lost
2469 * Updates the PID, state and timeout values for the connection. 664 * or something is fishy. Consider retransmitting the ACK.
2470 *
2471 * @param message Message to check. It must belong to an existing connection.
2472 * @param cid Connection ID (even if @a c is NULL, the ID is still needed).
2473 * @param c Connection this message should belong. If NULL, check fails.
2474 * @param sender Neighbor that sent the message.
2475 * 665 *
2476 * @return #GNUNET_YES if the message goes FWD. 666 * @param cc connection that got the duplicate CREATE
2477 * #GNUNET_NO if it goes BCK.
2478 * #GNUNET_SYSERR if there is an error (unauthorized sender, ...).
2479 */ 667 */
2480static int 668void
2481check_message (const struct GNUNET_MessageHeader *message, 669GCC_handle_duplicate_create (struct CadetConnection *cc)
2482 const struct GNUNET_CADET_ConnectionTunnelIdentifier* cid,
2483 struct CadetConnection *c,
2484 struct CadetPeer *sender,
2485 struct CadetEncryptedMessageIdentifier pid)
2486{ 670{
2487 struct CadetFlowControl *fc; 671 if (GNUNET_YES == cc->mqm_ready)
2488 struct CadetPeer *hop;
2489 int fwd;
2490 uint16_t type;
2491
2492 /* Check connection */
2493 if (NULL == c)
2494 { 672 {
2495 GNUNET_STATISTICS_update (stats,
2496 "# unknown connection",
2497 1, GNUNET_NO);
2498 LOG (GNUNET_ERROR_TYPE_DEBUG, 673 LOG (GNUNET_ERROR_TYPE_DEBUG,
2499 "%s on unknown connection %s\n", 674 "Got duplicate CREATE for %s, scheduling another ACK (%s)\n",
2500 GC_m2s (ntohs (message->type)), 675 GCC_2s (cc),
2501 GNUNET_sh2s (&cid->connection_of_tunnel)); 676 (GNUNET_YES == cc->mqm_ready) ? "MQM ready" : "MQM busy");
2502 GNUNET_break_op (0); 677 /* Revert back to the state of having only received the 'CREATE',
2503 send_broken_unknown (cid, 678 and immediately proceed to send the CREATE_ACK. */
2504 &my_full_id, 679 update_state (cc,
2505 NULL, 680 CADET_CONNECTION_CREATE_RECEIVED,
2506 sender); 681 cc->mqm_ready);
2507 return GNUNET_SYSERR; 682 if (NULL != cc->task)
2508 } 683 GNUNET_SCHEDULER_cancel (cc->task);
2509 684 cc->task = GNUNET_SCHEDULER_add_now (&send_create_ack,
2510 /* Check if origin is as expected */ 685 cc);
2511 hop = get_prev_hop (c);
2512 if (sender == hop)
2513 {
2514 fwd = GNUNET_YES;
2515 } 686 }
2516 else 687 else
2517 { 688 {
2518 hop = get_next_hop (c); 689 /* We are currently sending something else back, which
2519 GNUNET_break (hop == c->next_peer); 690 can only be an ACK or payload, either of which would
2520 if (sender == hop) 691 do. So actually no need to do anything. */
2521 { 692 LOG (GNUNET_ERROR_TYPE_DEBUG,
2522 fwd = GNUNET_NO; 693 "Got duplicate CREATE for %s. MQ is busy, not queueing another ACK\n",
2523 } 694 GCC_2s (cc));
2524 else
2525 {
2526 /* Unexpected peer sending traffic on a connection. */
2527 GNUNET_break_op (0);
2528 return GNUNET_SYSERR;
2529 }
2530 }
2531
2532 /* Check PID for payload messages */
2533 type = ntohs (message->type);
2534 if (GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED == type)
2535 {
2536 fc = fwd ? &c->bck_fc : &c->fwd_fc;
2537 LOG (GNUNET_ERROR_TYPE_DEBUG, " PID %u (expected in interval [%u,%u])\n",
2538 ntohl (pid.pid),
2539 ntohl (fc->last_pid_recv.pid) + 1,
2540 ntohl (fc->last_ack_sent.pid));
2541 if (GC_is_pid_bigger (ntohl (pid.pid),
2542 ntohl (fc->last_ack_sent.pid)))
2543 {
2544 GNUNET_STATISTICS_update (stats,
2545 "# unsolicited message",
2546 1,
2547 GNUNET_NO);
2548 LOG (GNUNET_ERROR_TYPE_WARNING,
2549 "Received PID %u, (prev %u), ACK %u\n",
2550 pid, fc->last_pid_recv, fc->last_ack_sent);
2551 return GNUNET_SYSERR;
2552 }
2553 if (GC_is_pid_bigger (ntohl (pid.pid),
2554 ntohl (fc->last_pid_recv.pid)))
2555 {
2556 unsigned int delta;
2557
2558 delta = ntohl (pid.pid) - ntohl (fc->last_pid_recv.pid);
2559 fc->last_pid_recv = pid;
2560 fc->recv_bitmap <<= delta;
2561 fc->recv_bitmap |= 1;
2562 }
2563 else
2564 {
2565 GNUNET_STATISTICS_update (stats,
2566 "# out of order PID",
2567 1,
2568 GNUNET_NO);
2569 if (GNUNET_NO == is_ooo_ok (fc->last_pid_recv,
2570 pid,
2571 fc->recv_bitmap))
2572 {
2573 LOG (GNUNET_ERROR_TYPE_WARNING,
2574 "PID %u unexpected (%u+), dropping!\n",
2575 ntohl (pid.pid),
2576 ntohl (fc->last_pid_recv.pid) - 31);
2577 return GNUNET_SYSERR;
2578 }
2579 fc->recv_bitmap |= get_recv_bitmask (fc->last_pid_recv,
2580 pid);
2581 }
2582 }
2583
2584 /* Count as connection confirmation. */
2585 if ( (CADET_CONNECTION_SENT == c->state) ||
2586 (CADET_CONNECTION_ACK == c->state) )
2587 {
2588 connection_change_state (c, CADET_CONNECTION_READY);
2589 if (NULL != c->t)
2590 {
2591 if (CADET_TUNNEL_WAITING == GCT_get_cstate (c->t))
2592 GCT_change_cstate (c->t, CADET_TUNNEL_READY);
2593 }
2594 } 695 }
2595 connection_reset_timeout (c, fwd);
2596
2597 return fwd;
2598} 696}
2599 697
2600 698
2601/** 699/**
2602 * Handler for key exchange traffic (Axolotl KX). 700 * There has been a change in the message queue existence for our
701 * peer at the first hop. Adjust accordingly.
2603 * 702 *
2604 * @param peer Message sender (neighbor). 703 * @param cls the `struct CadetConnection`
2605 * @param msg Message itself. 704 * @param available #GNUNET_YES if sending is now possible,
705 * #GNUNET_NO if sending is no longer possible
706 * #GNUNET_SYSERR if sending is no longer possible
707 * and the last envelope was discarded
2606 */ 708 */
2607void 709static void
2608GCC_handle_kx (struct CadetPeer *peer, 710manage_first_hop_mq (void *cls,
2609 const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg) 711 int available)
2610{ 712{
2611 static struct CadetEncryptedMessageIdentifier zero; 713 struct CadetConnection *cc = cls;
2612 const struct GNUNET_CADET_ConnectionTunnelIdentifier* cid;
2613 struct CadetConnection *c;
2614 int fwd;
2615
2616 GCC_check_connections ();
2617 cid = &msg->cid;
2618 log_message (&msg->header, peer, cid);
2619
2620 c = connection_get (cid);
2621 fwd = check_message (&msg->header,
2622 cid,
2623 c,
2624 peer,
2625 zero);
2626
2627 /* If something went wrong, discard message. */
2628 if (GNUNET_SYSERR == fwd)
2629 {
2630 GNUNET_break_op (0);
2631 GCC_check_connections ();
2632 return;
2633 }
2634 714
2635 /* Is this message for us? */ 715 if (GNUNET_YES != available)
2636 if (GCC_is_terminal (c, fwd))
2637 { 716 {
2638 LOG (GNUNET_ERROR_TYPE_DEBUG, " message for us!\n"); 717 /* Connection is down, for now... */
2639 GNUNET_STATISTICS_update (stats, "# received KX", 1, GNUNET_NO); 718 LOG (GNUNET_ERROR_TYPE_DEBUG,
2640 if (NULL == c->t) 719 "Core MQ for %s went down\n",
720 GCC_2s (cc));
721 update_state (cc,
722 CADET_CONNECTION_NEW,
723 GNUNET_NO);
724 cc->retry_delay = GNUNET_TIME_UNIT_ZERO;
725 if (NULL != cc->task)
2641 { 726 {
2642 GNUNET_break (0); 727 GNUNET_SCHEDULER_cancel (cc->task);
2643 return; 728 cc->task = NULL;
2644 } 729 }
2645 GCT_handle_kx (c->t, msg);
2646 GCC_check_connections ();
2647 return;
2648 }
2649
2650 /* Message not for us: forward to next hop */
2651 LOG (GNUNET_ERROR_TYPE_DEBUG, " not for us, retransmitting...\n");
2652 GNUNET_STATISTICS_update (stats, "# messages forwarded", 1, GNUNET_NO);
2653 (void) GCC_send_prebuilt_message (&msg->header, 0,
2654 zero, c, fwd,
2655 GNUNET_NO, NULL, NULL);
2656 GCC_check_connections ();
2657}
2658
2659
2660/**
2661 * Handler for encrypted cadet network traffic (channel mgmt, data).
2662 *
2663 * @param peer Message sender (neighbor).
2664 * @param msg Message itself.
2665 */
2666void
2667GCC_handle_encrypted (struct CadetPeer *peer,
2668 const struct GNUNET_CADET_TunnelEncryptedMessage *msg)
2669{
2670 static struct CadetEncryptedMessageIdentifier zero;
2671 const struct GNUNET_CADET_ConnectionTunnelIdentifier* cid;
2672 struct CadetConnection *c;
2673 struct CadetEncryptedMessageIdentifier pid;
2674 int fwd;
2675
2676 GCC_check_connections ();
2677 cid = &msg->cid;
2678 pid = msg->cemi;
2679 log_message (&msg->header, peer, cid);
2680
2681 c = connection_get (cid);
2682 fwd = check_message (&msg->header,
2683 cid,
2684 c,
2685 peer,
2686 pid);
2687
2688 /* If something went wrong, discard message. */
2689 if (GNUNET_SYSERR == fwd)
2690 {
2691 GCC_check_connections ();
2692 return; 730 return;
2693 } 731 }
2694 732
2695 /* Is this message for us? */ 733 update_state (cc,
2696 if (GCC_is_terminal (c, fwd)) 734 cc->state,
2697 { 735 GNUNET_YES);
2698 GNUNET_STATISTICS_update (stats, "# received encrypted", 1, GNUNET_NO); 736 LOG (GNUNET_ERROR_TYPE_DEBUG,
2699 737 "Core MQ for %s became available in state %d\n",
2700 if (NULL == c->t) 738 GCC_2s (cc),
739 cc->state);
740 switch (cc->state)
741 {
742 case CADET_CONNECTION_NEW:
743 /* Transmit immediately */
744 cc->task = GNUNET_SCHEDULER_add_now (&send_create,
745 cc);
746 break;
747 case CADET_CONNECTION_SENDING_CREATE:
748 /* Should not be possible to be called in this state. */
749 GNUNET_assert (0);
750 break;
751 case CADET_CONNECTION_SENT:
752 /* Retry a bit later... */
753 cc->retry_delay = GNUNET_TIME_STD_BACKOFF (cc->retry_delay);
754 cc->task = GNUNET_SCHEDULER_add_delayed (cc->retry_delay,
755 &send_create,
756 cc);
757 break;
758 case CADET_CONNECTION_CREATE_RECEIVED:
759 /* We got the 'CREATE' (incoming connection), should send the CREATE_ACK */
760 cc->metrics.age = GNUNET_TIME_absolute_get ();
761 cc->task = GNUNET_SCHEDULER_add_now (&send_create_ack,
762 cc);
763 break;
764 case CADET_CONNECTION_READY:
765 if ( (NULL == cc->keepalive_qe) &&
766 (GNUNET_YES == cc->mqm_ready) &&
767 (NULL == cc->task) )
2701 { 768 {
2702 GNUNET_break (GNUNET_NO != c->destroy); 769 LOG (GNUNET_ERROR_TYPE_DEBUG,
2703 return; 770 "Scheduling keepalive for %s in %s\n",
771 GCC_2s (cc),
772 GNUNET_STRINGS_relative_time_to_string (keepalive_period,
773 GNUNET_YES));
774 cc->task = GNUNET_SCHEDULER_add_delayed (keepalive_period,
775 &send_keepalive,
776 cc);
2704 } 777 }
2705 GCT_handle_encrypted (c->t, msg); 778 break;
2706 GCC_send_ack (c, fwd, GNUNET_NO);
2707 GCC_check_connections ();
2708 return;
2709 } 779 }
2710
2711 /* Message not for us: forward to next hop */
2712 LOG (GNUNET_ERROR_TYPE_DEBUG, " not for us, retransmitting...\n");
2713 GNUNET_STATISTICS_update (stats, "# messages forwarded", 1, GNUNET_NO);
2714 (void) GCC_send_prebuilt_message (&msg->header, 0,
2715 zero, c, fwd,
2716 GNUNET_NO, NULL, NULL);
2717 GCC_check_connections ();
2718} 780}
2719 781
2720 782
2721/** 783/**
2722 * Initialize the connections subsystem 784 * Create a connection to @a destination via @a path and notify @a cb
785 * whenever we are ready for more data. Shared logic independent of
786 * who is initiating the connection.
2723 * 787 *
2724 * @param c Configuration handle. 788 * @param destination where to go
789 * @param path which path to take (may not be the full path)
790 * @param off offset of @a destination on @a path
791 * @param options options for the connection
792 * @param ct which tunnel uses this connection
793 * @param init_state initial state for the connection
794 * @param ready_cb function to call when ready to transmit
795 * @param ready_cb_cls closure for @a cb
796 * @return handle to the connection
2725 */ 797 */
2726void 798static struct CadetConnection *
2727GCC_init (const struct GNUNET_CONFIGURATION_Handle *c) 799connection_create (struct CadetPeer *destination,
2728{ 800 struct CadetPeerPath *path,
2729 LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n"); 801 unsigned int off,
2730 if (GNUNET_OK != 802 enum GNUNET_CADET_ChannelOption options,
2731 GNUNET_CONFIGURATION_get_value_number (c, "CADET", "MAX_MSGS_QUEUE", 803 struct CadetTConnection *ct,
2732 &max_msgs_queue)) 804 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
2733 { 805 enum CadetConnectionState init_state,
2734 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 806 GCC_ReadyCallback ready_cb,
2735 "CADET", "MAX_MSGS_QUEUE", "MISSING"); 807 void *ready_cb_cls)
2736 GNUNET_SCHEDULER_shutdown (); 808{
2737 return; 809 struct CadetConnection *cc;
2738 } 810 struct CadetPeer *first_hop;
2739 811
2740 if (GNUNET_OK != 812 cc = GNUNET_new (struct CadetConnection);
2741 GNUNET_CONFIGURATION_get_value_number (c, "CADET", "MAX_CONNECTIONS", 813 cc->options = options;
2742 &max_connections)) 814 cc->state = init_state;
2743 { 815 cc->ct = ct;
2744 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 816 cc->cid = *cid;
2745 "CADET", "MAX_CONNECTIONS", "MISSING");
2746 GNUNET_SCHEDULER_shutdown ();
2747 return;
2748 }
2749
2750 if (GNUNET_OK !=
2751 GNUNET_CONFIGURATION_get_value_time (c, "CADET", "REFRESH_CONNECTION_TIME",
2752 &refresh_connection_time))
2753 {
2754 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
2755 "CADET", "REFRESH_CONNECTION_TIME", "MISSING");
2756 GNUNET_SCHEDULER_shutdown ();
2757 return;
2758 }
2759 create_connection_time = GNUNET_TIME_relative_min (GNUNET_TIME_UNIT_SECONDS,
2760 refresh_connection_time);
2761 connections = GNUNET_CONTAINER_multishortmap_create (1024,
2762 GNUNET_YES);
2763}
2764
2765
2766/**
2767 * Destroy each connection on shutdown.
2768 *
2769 * @param cls Closure (unused).
2770 * @param key Current key code (CID, unused).
2771 * @param value Value in the hash map (`struct CadetConnection`)
2772 *
2773 * @return #GNUNET_YES, because we should continue to iterate
2774 */
2775static int
2776shutdown_iterator (void *cls,
2777 const struct GNUNET_ShortHashCode *key,
2778 void *value)
2779{
2780 struct CadetConnection *c = value;
2781
2782 c->state = CADET_CONNECTION_DESTROYED;
2783 GCC_destroy (c);
2784 return GNUNET_YES;
2785}
2786
2787
2788/**
2789 * Shut down the connections subsystem.
2790 */
2791void
2792GCC_shutdown (void)
2793{
2794 LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down connections\n");
2795 GCC_check_connections ();
2796 GNUNET_CONTAINER_multishortmap_iterate (connections,
2797 &shutdown_iterator,
2798 NULL);
2799 GNUNET_CONTAINER_multishortmap_destroy (connections);
2800 connections = NULL;
2801}
2802
2803
2804/**
2805 * Create a connection.
2806 *
2807 * @param cid Connection ID (either created locally or imposed remotely).
2808 * @param t Tunnel this connection belongs to (or NULL for transit connections);
2809 * @param path Path this connection has to use (copy is made).
2810 * @param own_pos Own position in the @c path path.
2811 *
2812 * @return Newly created connection.
2813 * NULL in case of error: own id not in path, wrong neighbors, ...
2814*/
2815struct CadetConnection *
2816GCC_new (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
2817 struct CadetTunnel *t,
2818 struct CadetPeerPath *path,
2819 unsigned int own_pos)
2820{
2821 struct CadetConnection *c;
2822 struct CadetPeerPath *cpath;
2823
2824 GCC_check_connections ();
2825 cpath = path_duplicate (path);
2826 GNUNET_assert (NULL != cpath);
2827 c = GNUNET_new (struct CadetConnection);
2828 c->id = *cid;
2829 GNUNET_assert (GNUNET_OK == 817 GNUNET_assert (GNUNET_OK ==
2830 GNUNET_CONTAINER_multishortmap_put (connections, 818 GNUNET_CONTAINER_multishortmap_put (connections,
2831 &c->id.connection_of_tunnel, 819 &GCC_get_id (cc)->connection_of_tunnel,
2832 c, 820 cc,
2833 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); 821 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2834 fc_init (&c->fwd_fc); 822 cc->ready_cb = ready_cb;
2835 fc_init (&c->bck_fc); 823 cc->ready_cb_cls = ready_cb_cls;
2836 c->fwd_fc.c = c; 824 cc->path = path;
2837 c->bck_fc.c = c; 825 cc->off = off;
2838
2839 c->t = t;
2840 GNUNET_assert (own_pos <= cpath->length - 1);
2841 c->own_pos = own_pos;
2842 c->path = cpath;
2843 cpath->c = c;
2844 if (GNUNET_OK != register_neighbors (c))
2845 {
2846 if (0 == own_pos)
2847 {
2848 /* We were the origin of this request, this means we have invalid
2849 * info about the paths to reach the destination. We must invalidate
2850 * the *original* path to avoid trying it again in the next minute.
2851 */
2852 if (2 < path->length)
2853 path_invalidate (path);
2854 else
2855 {
2856 GNUNET_break (0);
2857 GCT_debug(t, GNUNET_ERROR_TYPE_WARNING);
2858 }
2859 c->t = NULL;
2860 }
2861 path_destroy (c->path);
2862 c->path = NULL;
2863 GCC_destroy (c);
2864 return NULL;
2865 }
2866 LOG (GNUNET_ERROR_TYPE_INFO, "New connection %s\n", GCC_2s (c));
2867 GCC_check_connections ();
2868 return c;
2869}
2870
2871
2872/**
2873 * Connection is no longer needed: destroy it.
2874 *
2875 * Cancels all pending traffic (including possible DESTROY messages), all
2876 * maintenance tasks and removes the connection from neighbor peers and tunnel.
2877 *
2878 * @param c Connection to destroy.
2879 */
2880void
2881GCC_destroy (struct CadetConnection *c)
2882{
2883 GCC_check_connections ();
2884 if (NULL == c)
2885 {
2886 GNUNET_break (0);
2887 return;
2888 }
2889
2890 if (2 == c->destroy) /* cancel queues -> GCP_queue_cancel -> q_destroy -> */
2891 return; /* -> message_sent -> GCC_destroy. Don't loop. */
2892 c->destroy = 2;
2893
2894 LOG (GNUNET_ERROR_TYPE_DEBUG,
2895 "destroying connection %s\n",
2896 GCC_2s (c));
2897 LOG (GNUNET_ERROR_TYPE_DEBUG,
2898 " fc's f: %p, b: %p\n",
2899 &c->fwd_fc, &c->bck_fc);
2900 LOG (GNUNET_ERROR_TYPE_DEBUG,
2901 " fc tasks f: %u, b: %u\n",
2902 c->fwd_fc.poll_task,
2903 c->bck_fc.poll_task);
2904
2905 /* Cancel all traffic */
2906 if (NULL != c->path)
2907 {
2908 connection_cancel_queues (c, GNUNET_YES);
2909 connection_cancel_queues (c, GNUNET_NO);
2910 if (NULL != c->maintenance_q)
2911 {
2912 GCP_send_cancel (c->maintenance_q);
2913 c->maintenance_q = NULL;
2914 }
2915 }
2916 unregister_neighbors (c);
2917 path_destroy (c->path);
2918 c->path = NULL;
2919
2920 /* Delete from tunnel */
2921 if (NULL != c->t)
2922 GCT_remove_connection (c->t, c);
2923
2924 if (NULL != c->check_duplicates_task)
2925 GNUNET_SCHEDULER_cancel (c->check_duplicates_task);
2926 if (NULL != c->fwd_maintenance_task)
2927 GNUNET_SCHEDULER_cancel (c->fwd_maintenance_task);
2928 if (NULL != c->bck_maintenance_task)
2929 GNUNET_SCHEDULER_cancel (c->bck_maintenance_task);
2930
2931 if (GNUNET_NO == c->was_removed)
2932 {
2933 GNUNET_break (GNUNET_YES ==
2934 GNUNET_CONTAINER_multishortmap_remove (connections,
2935 &c->id.connection_of_tunnel,
2936 c));
2937 }
2938 GNUNET_STATISTICS_update (stats,
2939 "# connections",
2940 -1,
2941 GNUNET_NO);
2942 GNUNET_free (c);
2943 GCC_check_connections ();
2944}
2945
2946
2947/**
2948 * Get the connection ID.
2949 *
2950 * @param c Connection to get the ID from.
2951 *
2952 * @return ID of the connection.
2953 */
2954const struct GNUNET_CADET_ConnectionTunnelIdentifier *
2955GCC_get_id (const struct CadetConnection *c)
2956{
2957 return &c->id;
2958}
2959
2960
2961/**
2962 * Get the connection path.
2963 *
2964 * @param c Connection to get the path from.
2965 *
2966 * @return path used by the connection.
2967 */
2968const struct CadetPeerPath *
2969GCC_get_path (const struct CadetConnection *c)
2970{
2971 if (GNUNET_NO == c->destroy)
2972 return c->path;
2973 return NULL;
2974}
2975
2976
2977/**
2978 * Get the connection state.
2979 *
2980 * @param c Connection to get the state from.
2981 *
2982 * @return state of the connection.
2983 */
2984enum CadetConnectionState
2985GCC_get_state (const struct CadetConnection *c)
2986{
2987 return c->state;
2988}
2989
2990/**
2991 * Get the connection tunnel.
2992 *
2993 * @param c Connection to get the tunnel from.
2994 *
2995 * @return tunnel of the connection.
2996 */
2997struct CadetTunnel *
2998GCC_get_tunnel (const struct CadetConnection *c)
2999{
3000 return c->t;
3001}
3002
3003
3004/**
3005 * Get free buffer space in a connection.
3006 *
3007 * @param c Connection.
3008 * @param fwd Is query about FWD traffic?
3009 *
3010 * @return Free buffer space [0 - max_msgs_queue/max_connections]
3011 */
3012unsigned int
3013GCC_get_buffer (struct CadetConnection *c, int fwd)
3014{
3015 struct CadetFlowControl *fc;
3016
3017 fc = fwd ? &c->fwd_fc : &c->bck_fc;
3018
3019 LOG (GNUNET_ERROR_TYPE_DEBUG, " Get %s buffer on %s: %u - %u\n",
3020 GC_f2s (fwd), GCC_2s (c), fc->queue_max, fc->queue_n);
3021 GCC_debug (c, GNUNET_ERROR_TYPE_DEBUG);
3022
3023 return (fc->queue_max - fc->queue_n);
3024}
3025
3026
3027/**
3028 * Get how many messages have we allowed to send to us from a direction.
3029 *
3030 * @param c Connection.
3031 * @param fwd Are we asking about traffic from FWD (BCK messages)?
3032 *
3033 * @return last_ack_sent - last_pid_recv
3034 */
3035unsigned int
3036GCC_get_allowed (struct CadetConnection *c, int fwd)
3037{
3038 struct CadetFlowControl *fc;
3039
3040 fc = fwd ? &c->fwd_fc : &c->bck_fc;
3041 if ( (CADET_CONNECTION_READY != c->state) ||
3042 GC_is_pid_bigger (ntohl (fc->last_pid_recv.pid),
3043 ntohl (fc->last_ack_sent.pid)) )
3044 {
3045 return 0;
3046 }
3047 return (ntohl (fc->last_ack_sent.pid) - ntohl (fc->last_pid_recv.pid));
3048}
3049
3050
3051/**
3052 * Get messages queued in a connection.
3053 *
3054 * @param c Connection.
3055 * @param fwd Is query about FWD traffic?
3056 *
3057 * @return Number of messages queued.
3058 */
3059unsigned int
3060GCC_get_qn (struct CadetConnection *c, int fwd)
3061{
3062 struct CadetFlowControl *fc;
3063
3064 fc = fwd ? &c->fwd_fc : &c->bck_fc;
3065
3066 return fc->queue_n;
3067}
3068
3069
3070/**
3071 * Get next PID to use.
3072 *
3073 * @param c Connection.
3074 * @param fwd Is query about FWD traffic?
3075 * @return Next PID to use.
3076 */
3077struct CadetEncryptedMessageIdentifier
3078GCC_get_pid (struct CadetConnection *c, int fwd)
3079{
3080 struct CadetFlowControl *fc;
3081 struct CadetEncryptedMessageIdentifier pid;
3082
3083 fc = fwd ? &c->fwd_fc : &c->bck_fc;
3084 pid = fc->next_pid;
3085 fc->next_pid.pid = htonl (1 + ntohl (pid.pid));
3086 return pid;
3087}
3088
3089
3090/**
3091 * Allow the connection to advertise a buffer of the given size.
3092 *
3093 * The connection will send an @c fwd ACK message (so: in direction !fwd)
3094 * allowing up to last_pid_recv + buffer.
3095 *
3096 * @param c Connection.
3097 * @param buffer How many more messages the connection can accept.
3098 * @param fwd Is this about FWD traffic? (The ack will go dest->root).
3099 */
3100void
3101GCC_allow (struct CadetConnection *c, unsigned int buffer, int fwd)
3102{
3103 LOG (GNUNET_ERROR_TYPE_DEBUG, " allowing %s %u messages %s\n",
3104 GCC_2s (c), buffer, GC_f2s (fwd));
3105 send_ack (c, buffer, fwd, GNUNET_NO);
3106}
3107
3108
3109/**
3110 * Notify other peers on a connection of a broken link. Mark connections
3111 * to destroy after all traffic has been sent.
3112 *
3113 * @param c Connection on which there has been a disconnection.
3114 * @param peer Peer that disconnected.
3115 */
3116void
3117GCC_neighbor_disconnected (struct CadetConnection *c, struct CadetPeer *peer)
3118{
3119 struct CadetFlowControl *fc;
3120 char peer_name[16];
3121 int fwd;
3122
3123 GCC_check_connections ();
3124 strncpy (peer_name, GCP_2s (peer), 16);
3125 peer_name[15] = '\0';
3126 LOG (GNUNET_ERROR_TYPE_DEBUG, 826 LOG (GNUNET_ERROR_TYPE_DEBUG,
3127 "shutting down %s, %s disconnected\n", 827 "Creating %s using path %s\n",
3128 GCC_2s (c), peer_name); 828 GCC_2s (cc),
3129 829 GCPP_2s (path));
3130 invalidate_paths (c, peer); 830 GCPP_add_connection (path,
3131 831 off,
3132 fwd = is_fwd (c, peer); 832 cc);
3133 if (GNUNET_SYSERR == fwd) 833 for (unsigned int i=0;i<off;i++)
3134 { 834 GCP_add_connection (GCPP_get_peer_at_offset (path,
3135 GNUNET_break (0); 835 i),
3136 return; 836 cc);
3137 } 837
3138 if ( (GNUNET_YES == GCC_is_terminal (c, fwd)) || 838 first_hop = GCPP_get_peer_at_offset (path,
3139 (GNUNET_NO != c->destroy) ) 839 0);
3140 { 840 cc->mq_man = GCP_request_mq (first_hop,
3141 /* Local shutdown, or other peer already down (hence 'c->destroy'); 841 &manage_first_hop_mq,
3142 so there is no one to notify about this, just clean up. */ 842 cc);
3143 GCC_destroy (c); 843 return cc;
3144 GCC_check_connections (); 844}
3145 return; 845
3146 } 846
3147 /* Mark FlowControl towards the peer as unavaliable. */ 847/**
3148 fc = fwd ? &c->bck_fc : &c->fwd_fc; 848 * Create a connection to @a destination via @a path and
3149 fc->queue_max = 0; 849 * notify @a cb whenever we are ready for more data. This
3150 850 * is an inbound tunnel, so we must use the existing @a cid
3151 send_broken (c, &my_full_id, GCP_get_id (peer), fwd); 851 *
3152 852 * @param destination where to go
3153 /* Connection will have at least one pending message 853 * @param path which path to take (may not be the full path)
3154 * (the one we just scheduled), so delay destruction 854 * @param options options for the connection
3155 * and remove from map so we don't use accidentally. */ 855 * @param ct which tunnel uses this connection
3156 mark_destroyed (c); 856 * @param ready_cb function to call when ready to transmit
3157 GNUNET_assert (GNUNET_NO == c->was_removed); 857 * @param ready_cb_cls closure for @a cb
3158 c->was_removed = GNUNET_YES; 858 * @return handle to the connection, NULL if we already have
3159 GNUNET_break (GNUNET_YES == 859 * a connection that takes precedence on @a path
3160 GNUNET_CONTAINER_multishortmap_remove (connections,
3161 &c->id.connection_of_tunnel,
3162 c));
3163 /* Cancel queue in the direction that just died. */
3164 connection_cancel_queues (c, ! fwd);
3165 GCC_stop_poll (c, ! fwd);
3166 unregister_neighbors (c);
3167 GCC_check_connections ();
3168}
3169
3170
3171/**
3172 * Is this peer the first one on the connection?
3173 *
3174 * @param c Connection.
3175 * @param fwd Is this about fwd traffic?
3176 *
3177 * @return #GNUNET_YES if origin, #GNUNET_NO if relay/terminal.
3178 */ 860 */
3179int 861struct CadetConnection *
3180GCC_is_origin (struct CadetConnection *c, int fwd) 862GCC_create_inbound (struct CadetPeer *destination,
3181{ 863 struct CadetPeerPath *path,
3182 if (!fwd && c->path->length - 1 == c->own_pos ) 864 enum GNUNET_CADET_ChannelOption options,
3183 return GNUNET_YES; 865 struct CadetTConnection *ct,
3184 if (fwd && 0 == c->own_pos) 866 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
3185 return GNUNET_YES; 867 GCC_ReadyCallback ready_cb,
3186 return GNUNET_NO; 868 void *ready_cb_cls)
3187} 869{
3188 870 struct CadetConnection *cc;
3189 871 unsigned int off;
3190/** 872
3191 * Is this peer the last one on the connection? 873 off = GCPP_find_peer (path,
3192 * 874 destination);
3193 * @param c Connection. 875 GNUNET_assert (UINT_MAX != off);
3194 * @param fwd Is this about fwd traffic? 876 cc = GCPP_get_connection (path,
3195 * Note that the ROOT is the terminal for BCK traffic! 877 destination,
3196 * 878 off);
3197 * @return #GNUNET_YES if terminal, #GNUNET_NO if relay/origin. 879 if (NULL != cc)
3198 */ 880 {
3199int 881 int cmp;
3200GCC_is_terminal (struct CadetConnection *c, int fwd) 882
3201{ 883 cmp = memcmp (cid,
3202 return GCC_is_origin (c, ! fwd); 884 &cc->cid,
3203} 885 sizeof (*cid));
3204 886 if (0 == cmp)
3205 887 {
3206/** 888 /* Two peers picked the SAME random connection identifier at the
3207 * See if we are allowed to send by the next hop in the given direction. 889 same time for the same path? Must be malicious. Drop
3208 * 890 connection (existing and inbound), even if it is the only
3209 * @param c Connection. 891 one. */
3210 * @param fwd Is this about fwd traffic? 892 GNUNET_break_op (0);
3211 * 893 GCT_connection_lost (cc->ct);
3212 * @return #GNUNET_YES in case it's OK to send. 894 GCC_destroy_without_tunnel (cc);
3213 */
3214int
3215GCC_is_sendable (struct CadetConnection *c, int fwd)
3216{
3217 struct CadetFlowControl *fc;
3218
3219 LOG (GNUNET_ERROR_TYPE_DEBUG,
3220 " checking sendability of %s traffic on %s\n",
3221 GC_f2s (fwd), GCC_2s (c));
3222 if (NULL == c)
3223 {
3224 GNUNET_break (0);
3225 return GNUNET_YES;
3226 }
3227 fc = fwd ? &c->fwd_fc : &c->bck_fc;
3228 LOG (GNUNET_ERROR_TYPE_DEBUG,
3229 " last ack recv: %u, last pid sent: %u\n",
3230 ntohl (fc->last_ack_recv.pid),
3231 ntohl (fc->last_pid_sent.pid));
3232 if (GC_is_pid_bigger (ntohl (fc->last_ack_recv.pid),
3233 ntohl (fc->last_pid_sent.pid)))
3234 {
3235 LOG (GNUNET_ERROR_TYPE_DEBUG, " sendable\n");
3236 return GNUNET_YES;
3237 }
3238 LOG (GNUNET_ERROR_TYPE_DEBUG, " not sendable\n");
3239 return GNUNET_NO;
3240}
3241
3242
3243/**
3244 * Check if this connection is a direct one (never trim a direct connection).
3245 *
3246 * @param c Connection.
3247 *
3248 * @return #GNUNET_YES in case it's a direct connection, #GNUNET_NO otherwise.
3249 */
3250int
3251GCC_is_direct (struct CadetConnection *c)
3252{
3253 return (c->path->length == 2) ? GNUNET_YES : GNUNET_NO;
3254}
3255
3256
3257/**
3258 * Sends a completely built message on a connection, properly registering
3259 * all used resources.
3260 *
3261 * @param message Message to send.
3262 * @param payload_type Type of payload, in case the message is encrypted.
3263 * 0 for restransmissions (when type is no longer known)
3264 * UINT16_MAX when not applicable.
3265 * @param payload_id ID of the payload (PID, ACK, ...).
3266 * @param c Connection on which this message is transmitted.
3267 * @param fwd Is this a fwd message?
3268 * @param force Force the connection to accept the message (buffer overfill).
3269 * @param cont Continuation called once message is sent. Can be NULL.
3270 * @param cont_cls Closure for @c cont.
3271 *
3272 * @return Handle to cancel the message before it's sent.
3273 * NULL on error.
3274 * Invalid on @c cont call.
3275 */
3276struct CadetConnectionQueue *
3277GCC_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
3278 uint16_t payload_type,
3279 struct CadetEncryptedMessageIdentifier payload_id,
3280 struct CadetConnection *c, int fwd, int force,
3281 GCC_sent cont, void *cont_cls)
3282{
3283 struct CadetFlowControl *fc;
3284 struct CadetConnectionQueue *q;
3285 uint16_t size;
3286 uint16_t type;
3287
3288 size = ntohs (message->size);
3289 type = ntohs (message->type);
3290
3291 GCC_check_connections ();
3292 fc = fwd ? &c->fwd_fc : &c->bck_fc;
3293 if (0 == fc->queue_max)
3294 {
3295 GNUNET_break (0);
3296 return NULL;
3297 }
3298
3299 LOG (GNUNET_ERROR_TYPE_INFO,
3300 "--> %s (%s %4u) on conn %s (%p) %s [%5u]\n",
3301 GC_m2s (type), GC_m2s (payload_type), payload_id, GCC_2s (c), c,
3302 GC_f2s(fwd), size);
3303 switch (type)
3304 {
3305 case GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED:
3306 LOG (GNUNET_ERROR_TYPE_DEBUG, " Q_N+ %p %u, PIDsnt: %u, ACKrcv: %u\n",
3307 fc,
3308 fc->queue_n,
3309 ntohl (fc->last_pid_sent.pid),
3310 ntohl (fc->last_ack_recv.pid));
3311 if (GNUNET_NO == force)
3312 {
3313 fc->queue_n++;
3314 }
3315 break;
3316
3317 case GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX:
3318 /* nothing to do here */
3319 break;
3320
3321 case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE:
3322 case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK:
3323 /* Should've only be used for restransmissions. */
3324 GNUNET_break (0 == payload_type);
3325 break;
3326
3327 case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_HOP_BY_HOP_ENCRYPTED_ACK:
3328 case GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED_POLL:
3329 case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY:
3330 case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN:
3331 GNUNET_assert (GNUNET_YES == force);
3332 break;
3333
3334 default:
3335 GNUNET_break (0);
3336 return NULL; 895 return NULL;
3337 } 896 }
3338 897 if (0 < cmp)
3339 if (fc->queue_n > fc->queue_max && GNUNET_NO == force)
3340 {
3341 GNUNET_STATISTICS_update (stats, "# messages dropped (buffer full)",
3342 1, GNUNET_NO);
3343 GNUNET_break (0);
3344 LOG (GNUNET_ERROR_TYPE_DEBUG, "queue full: %u/%u\n",
3345 fc->queue_n, fc->queue_max);
3346 if (GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED == type)
3347 { 898 {
3348 fc->queue_n--; 899 /* drop existing */
900 LOG (GNUNET_ERROR_TYPE_DEBUG,
901 "Got two connections on %s, dropping my existing %s\n",
902 GCPP_2s (path),
903 GCC_2s (cc));
904 GCT_connection_lost (cc->ct);
905 GCC_destroy_without_tunnel (cc);
3349 } 906 }
3350 return NULL; /* Drop this message */ 907 else
3351 }
3352
3353 LOG (GNUNET_ERROR_TYPE_DEBUG, " C_P+ %s %u\n",
3354 GCC_2s (c), c->pending_messages);
3355 c->pending_messages++;
3356
3357 q = GNUNET_new (struct CadetConnectionQueue);
3358 q->cont = cont;
3359 q->cont_cls = cont_cls;
3360 q->forced = force;
3361 GNUNET_CONTAINER_DLL_insert (fc->q_head, fc->q_tail, q);
3362 q->peer_q = GCP_send (get_hop (c, fwd),
3363 message,
3364 payload_type,
3365 payload_id,
3366 c,
3367 fwd,
3368 &conn_message_sent, q);
3369 if (NULL == q->peer_q)
3370 {
3371 LOG (GNUNET_ERROR_TYPE_DEBUG, "dropping msg on %s, NULL q\n", GCC_2s (c));
3372 GNUNET_CONTAINER_DLL_remove (fc->q_head, fc->q_tail, q);
3373 GNUNET_free (q);
3374 GCC_check_connections ();
3375 return NULL;
3376 }
3377 GCC_check_connections ();
3378 return q;
3379}
3380
3381
3382/**
3383 * Cancel a previously sent message while it's in the queue.
3384 *
3385 * ONLY can be called before the continuation given to the send function
3386 * is called. Once the continuation is called, the message is no longer in the
3387 * queue.
3388 *
3389 * @param q Handle to the queue.
3390 */
3391void
3392GCC_cancel (struct CadetConnectionQueue *q)
3393{
3394 LOG (GNUNET_ERROR_TYPE_DEBUG, "! GCC cancel message\n");
3395
3396 /* send_cancel calls message_sent, which calls q->cont and frees q */
3397 GCP_send_cancel (q->peer_q);
3398 GCC_check_connections ();
3399}
3400
3401
3402/**
3403 * Sends a CREATE CONNECTION message for a path to a peer.
3404 * Changes the connection and tunnel states if necessary.
3405 *
3406 * @param c Connection to create.
3407 */
3408void
3409GCC_send_create (struct CadetConnection *c)
3410{
3411 static struct CadetEncryptedMessageIdentifier zero;
3412 enum CadetTunnelCState state;
3413 size_t size;
3414
3415 GCC_check_connections ();
3416 size = sizeof (struct GNUNET_CADET_ConnectionCreateMessage);
3417 size += c->path->length * sizeof (struct GNUNET_PeerIdentity);
3418 {
3419 /* Allocate message on the stack */
3420 unsigned char cbuf[size];
3421 struct GNUNET_CADET_ConnectionCreateMessage *msg;
3422 struct GNUNET_PeerIdentity *peers;
3423
3424
3425 msg = (struct GNUNET_CADET_ConnectionCreateMessage *) cbuf;
3426 msg->header.size = htons (size);
3427 msg->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE);
3428 msg->options = htonl (0);
3429 msg->cid = *GCC_get_id (c);
3430 peers = (struct GNUNET_PeerIdentity *) &msg[1];
3431 for (int i = 0; i < c->path->length; i++)
3432 { 908 {
3433 GNUNET_PEER_resolve (c->path->peers[i], peers++); 909 /* keep existing */
910 LOG (GNUNET_ERROR_TYPE_DEBUG,
911 "Got two connections on %s, keeping my existing %s\n",
912 GCPP_2s (path),
913 GCC_2s (cc));
914 return NULL;
3434 } 915 }
3435 GNUNET_assert (NULL == c->maintenance_q);
3436 c->maintenance_q = GCP_send (get_next_hop (c),
3437 &msg->header,
3438 GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE,
3439 zero,
3440 c, GNUNET_YES,
3441 &conn_message_sent, NULL);
3442 } 916 }
3443 917
3444 LOG (GNUNET_ERROR_TYPE_INFO, "==> %s %19s on conn %s (%p) FWD [%5u]\n", 918 return connection_create (destination,
3445 GC_m2s (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE), "", 919 path,
3446 GCC_2s (c), c, size); 920 off,
3447 LOG (GNUNET_ERROR_TYPE_DEBUG, " C_P+ %p %u (create)\n", 921 options,
3448 c, c->pending_messages); 922 ct,
3449 c->pending_messages++; 923 cid,
3450 924 CADET_CONNECTION_CREATE_RECEIVED,
3451 state = GCT_get_cstate (c->t); 925 ready_cb,
3452 if (CADET_TUNNEL_SEARCHING == state || CADET_TUNNEL_NEW == state) 926 ready_cb_cls);
3453 GCT_change_cstate (c->t, CADET_TUNNEL_WAITING);
3454 if (CADET_CONNECTION_NEW == c->state)
3455 connection_change_state (c, CADET_CONNECTION_SENT);
3456 GCC_check_connections ();
3457} 927}
3458 928
3459 929
3460/** 930/**
3461 * Send an ACK on the appropriate connection/channel, depending on 931 * Create a connection to @a destination via @a path and
3462 * the direction and the position of the peer. 932 * notify @a cb whenever we are ready for more data.
3463 * 933 *
3464 * @param c Which connection to send the hop-by-hop ACK. 934 * @param destination where to go
3465 * @param fwd Is this a fwd ACK? (will go dest->root). 935 * @param path which path to take (may not be the full path)
3466 * @param force Send the ACK even if suboptimal (e.g. requested by POLL). 936 * @param off offset of @a destination on @a path
937 * @param options options for the connection
938 * @param ct tunnel that uses the connection
939 * @param ready_cb function to call when ready to transmit
940 * @param ready_cb_cls closure for @a cb
941 * @return handle to the connection
3467 */ 942 */
3468void 943struct CadetConnection *
3469GCC_send_ack (struct CadetConnection *c, int fwd, int force) 944GCC_create (struct CadetPeer *destination,
945 struct CadetPeerPath *path,
946 unsigned int off,
947 enum GNUNET_CADET_ChannelOption options,
948 struct CadetTConnection *ct,
949 GCC_ReadyCallback ready_cb,
950 void *ready_cb_cls)
3470{ 951{
3471 unsigned int buffer; 952 struct GNUNET_CADET_ConnectionTunnelIdentifier cid;
3472
3473 GCC_check_connections ();
3474 LOG (GNUNET_ERROR_TYPE_DEBUG, "GCC send %s ACK on %s\n",
3475 GC_f2s (fwd), GCC_2s (c));
3476
3477 if (NULL == c)
3478 {
3479 GNUNET_break (0);
3480 return;
3481 }
3482 953
3483 if (GNUNET_NO != c->destroy) 954 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
3484 { 955 &cid,
3485 LOG (GNUNET_ERROR_TYPE_DEBUG, " being destroyed, why bother...\n"); 956 sizeof (cid));
3486 GCC_check_connections (); 957 return connection_create (destination,
3487 return; 958 path,
3488 } 959 off,
3489 960 options,
3490 /* Get available buffer space */ 961 ct,
3491 if (GCC_is_terminal (c, fwd)) 962 &cid,
3492 { 963 CADET_CONNECTION_NEW,
3493 LOG (GNUNET_ERROR_TYPE_DEBUG, " getting from all channels\n"); 964 ready_cb,
3494 buffer = GCT_get_channels_buffer (c->t); 965 ready_cb_cls);
3495 }
3496 else
3497 {
3498 LOG (GNUNET_ERROR_TYPE_DEBUG, " getting from one connection\n");
3499 buffer = GCC_get_buffer (c, fwd);
3500 }
3501 LOG (GNUNET_ERROR_TYPE_DEBUG, " buffer available: %u\n", buffer);
3502 if (0 == buffer && GNUNET_NO == force)
3503 {
3504 GCC_check_connections ();
3505 return;
3506 }
3507
3508 /* Send available buffer space */
3509 if (GNUNET_YES == GCC_is_origin (c, fwd))
3510 {
3511 GNUNET_assert (NULL != c->t);
3512 LOG (GNUNET_ERROR_TYPE_DEBUG, " sending on channels...\n");
3513 GCT_unchoke_channels (c->t);
3514 }
3515 else
3516 {
3517 LOG (GNUNET_ERROR_TYPE_DEBUG, " sending on connection\n");
3518 send_ack (c, buffer, fwd, force);
3519 }
3520 GCC_check_connections ();
3521} 966}
3522 967
3523 968
3524/** 969/**
3525 * Send a message to all peers in this connection that the connection 970 * Transmit message @a msg via connection @a cc. Must only be called
3526 * is no longer valid. 971 * (once) after the connection has signalled that it is ready via the
972 * `ready_cb`. Clients can also use #GCC_is_ready() to check if the
973 * connection is right now ready for transmission.
3527 * 974 *
3528 * If some peer should not receive the message, it should be zero'ed out 975 * @param cc connection identification
3529 * before calling this function. 976 * @param env envelope with message to transmit; must NOT
3530 * 977 * yet have a #GNUNET_MQ_notify_sent() callback attached to it
3531 * @param c The connection whose peers to notify.
3532 */ 978 */
3533void 979void
3534GCC_send_destroy (struct CadetConnection *c) 980GCC_transmit (struct CadetConnection *cc,
981 struct GNUNET_MQ_Envelope *env)
3535{ 982{
3536 static struct CadetEncryptedMessageIdentifier zero;
3537 struct GNUNET_CADET_ConnectionDestroyMessage msg;
3538
3539 if (GNUNET_YES == c->destroy)
3540 return;
3541 GCC_check_connections ();
3542 msg.header.size = htons (sizeof (msg));
3543 msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY);
3544 msg.cid = c->id;
3545 msg.reserved = htonl (0);
3546 LOG (GNUNET_ERROR_TYPE_DEBUG, 983 LOG (GNUNET_ERROR_TYPE_DEBUG,
3547 " sending connection destroy for connection %s\n", 984 "Scheduling message for transmission on %s\n",
3548 GCC_2s (c)); 985 GCC_2s (cc));
3549 986 GNUNET_assert (GNUNET_YES == cc->mqm_ready);
3550 if (GNUNET_NO == GCC_is_terminal (c, GNUNET_YES)) 987 GNUNET_assert (CADET_CONNECTION_READY == cc->state);
3551 (void) GCC_send_prebuilt_message (&msg.header, 988 cc->metrics.last_use = GNUNET_TIME_absolute_get ();
3552 UINT16_MAX, 989 cc->mqm_ready = GNUNET_NO;
3553 zero, 990 if (NULL != cc->task)
3554 c, 991 {
3555 GNUNET_YES, GNUNET_YES, NULL, NULL); 992 GNUNET_SCHEDULER_cancel (cc->task);
3556 if (GNUNET_NO == GCC_is_terminal (c, GNUNET_NO)) 993 cc->task = NULL;
3557 (void) GCC_send_prebuilt_message (&msg.header, 994 }
3558 UINT16_MAX, 995 GCP_send (cc->mq_man,
3559 zero, 996 env);
3560 c,
3561 GNUNET_NO, GNUNET_YES, NULL, NULL);
3562 mark_destroyed (c);
3563 GCC_check_connections ();
3564} 997}
3565 998
3566 999
3567/** 1000/**
3568 * @brief Start a polling timer for the connection. 1001 * Obtain the path used by this connection.
3569 *
3570 * When a neighbor does not accept more traffic on the connection it could be
3571 * caused by a simple congestion or by a lost ACK. Polling enables to check
3572 * for the lastest ACK status for a connection.
3573 * 1002 *
3574 * @param c Connection. 1003 * @param cc connection
3575 * @param fwd Should we poll in the FWD direction? 1004 * @return path to @a cc
3576 */ 1005 */
3577void 1006struct CadetPeerPath *
3578GCC_start_poll (struct CadetConnection *c, int fwd) 1007GCC_get_path (struct CadetConnection *cc)
3579{ 1008{
3580 struct CadetFlowControl *fc; 1009 return cc->path;
3581
3582 fc = fwd ? &c->fwd_fc : &c->bck_fc;
3583 LOG (GNUNET_ERROR_TYPE_DEBUG, "POLL %s requested\n",
3584 GC_f2s (fwd));
3585 if (NULL != fc->poll_task || NULL != fc->poll_msg)
3586 {
3587 LOG (GNUNET_ERROR_TYPE_DEBUG, " POLL already in progress (t: %p, m: %p)\n",
3588 fc->poll_task, fc->poll_msg);
3589 return;
3590 }
3591 if (0 == fc->queue_max)
3592 {
3593 /* Should not be needed, traffic should've been cancelled. */
3594 GNUNET_break (0);
3595 LOG (GNUNET_ERROR_TYPE_DEBUG, " POLL not possible, peer disconnected\n");
3596 return;
3597 }
3598 LOG (GNUNET_ERROR_TYPE_DEBUG, "POLL started on request\n");
3599 fc->poll_task = GNUNET_SCHEDULER_add_delayed (fc->poll_time, &send_poll, fc);
3600} 1010}
3601 1011
3602 1012
3603/** 1013/**
3604 * @brief Stop polling a connection for ACKs. 1014 * Obtain unique ID for the connection.
3605 * 1015 *
3606 * Once we have enough ACKs for future traffic, polls are no longer necessary. 1016 * @param cc connection.
3607 * 1017 * @return unique number of the connection
3608 * @param c Connection.
3609 * @param fwd Should we stop the poll in the FWD direction?
3610 */ 1018 */
3611void 1019const struct GNUNET_CADET_ConnectionTunnelIdentifier *
3612GCC_stop_poll (struct CadetConnection *c, int fwd) 1020GCC_get_id (struct CadetConnection *cc)
3613{ 1021{
3614 struct CadetFlowControl *fc; 1022 return &cc->cid;
3615
3616 fc = fwd ? &c->fwd_fc : &c->bck_fc;
3617 if (NULL != fc->poll_task)
3618 {
3619 GNUNET_SCHEDULER_cancel (fc->poll_task);
3620 fc->poll_task = NULL;
3621 }
3622 if (NULL != fc->poll_msg)
3623 {
3624 GCC_cancel (fc->poll_msg);
3625 fc->poll_msg = NULL;
3626 }
3627} 1023}
3628 1024
3629 1025
3630/** 1026/**
3631 * Get a (static) string for a connection. 1027 * Get a (static) string for a connection.
3632 * 1028 *
3633 * @param c Connection. 1029 * @param cc Connection.
3634 */ 1030 */
3635const char * 1031const char *
3636GCC_2s (const struct CadetConnection *c) 1032GCC_2s (const struct CadetConnection *cc)
3637{ 1033{
3638 if (NULL == c) 1034 static char buf[128];
3639 return "NULL";
3640 1035
3641 if (NULL != c->t) 1036 if (NULL == cc)
3642 { 1037 return "Connection(NULL)";
3643 static char buf[128];
3644 1038
3645 SPRINTF (buf, "%s (->%s)", 1039 if (NULL != cc->ct)
3646 GNUNET_sh2s (&GCC_get_id (c)->connection_of_tunnel), 1040 {
3647 GCT_2s (c->t)); 1041 GNUNET_snprintf (buf,
1042 sizeof (buf),
1043 "Connection %s (%s)",
1044 GNUNET_sh2s (&cc->cid.connection_of_tunnel),
1045 GCT_2s (cc->ct->t));
3648 return buf; 1046 return buf;
3649 } 1047 }
3650 return GNUNET_sh2s (&c->id.connection_of_tunnel); 1048 GNUNET_snprintf (buf,
1049 sizeof (buf),
1050 "Connection %s",
1051 GNUNET_sh2s (&cc->cid.connection_of_tunnel));
1052 return buf;
3651} 1053}
3652 1054
3653 1055
1056#define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-con",__VA_ARGS__)
1057
1058
3654/** 1059/**
3655 * Log all possible info about the connection state. 1060 * Log connection info.
3656 * 1061 *
3657 * @param c Connection to debug. 1062 * @param cc connection
3658 * @param level Debug level to use. 1063 * @param level Debug level to use.
3659 */ 1064 */
3660void 1065void
3661GCC_debug (const struct CadetConnection *c, enum GNUNET_ErrorType level) 1066GCC_debug (struct CadetConnection *cc,
1067 enum GNUNET_ErrorType level)
3662{ 1068{
3663 int do_log; 1069 int do_log;
3664 char *s;
3665 1070
3666 do_log = GNUNET_get_log_call_status (level & (~GNUNET_ERROR_TYPE_BULK), 1071 do_log = GNUNET_get_log_call_status (level & (~GNUNET_ERROR_TYPE_BULK),
3667 "cadet-con", 1072 "cadet-con",
3668 __FILE__, __FUNCTION__, __LINE__); 1073 __FILE__, __FUNCTION__, __LINE__);
3669 if (0 == do_log) 1074 if (0 == do_log)
3670 return; 1075 return;
3671 1076 if (NULL == cc)
3672 if (NULL == c)
3673 { 1077 {
3674 LOG2 (level, "CCC DEBUG NULL CONNECTION\n"); 1078 LOG2 (level,
1079 "Connection (NULL)\n");
3675 return; 1080 return;
3676 } 1081 }
3677 1082 LOG2 (level,
3678 LOG2 (level, "CCC DEBUG CONNECTION %s\n", GCC_2s (c)); 1083 "%s to %s via path %s in state %d is %s\n",
3679 s = path_2s (c->path); 1084 GCC_2s (cc),
3680 LOG2 (level, "CCC path %s, own pos: %u\n", s, c->own_pos); 1085 GCP_2s (cc->destination),
3681 GNUNET_free (s); 1086 GCPP_2s (cc->path),
3682 LOG2 (level, "CCC state: %s, destroy: %u\n", 1087 cc->state,
3683 GCC_state2s (c->state), c->destroy); 1088 (GNUNET_YES == cc->mqm_ready) ? "ready" : "busy");
3684 LOG2 (level, "CCC pending messages: %u\n", c->pending_messages);
3685 if (NULL != c->perf)
3686 LOG2 (level, "CCC us/byte: %f\n", c->perf->avg);
3687
3688 LOG2 (level, "CCC FWD flow control:\n");
3689 LOG2 (level, "CCC queue: %u/%u\n", c->fwd_fc.queue_n, c->fwd_fc.queue_max);
3690 LOG2 (level, "CCC last PID sent: %5u, recv: %5u\n",
3691 ntohl (c->fwd_fc.last_pid_sent.pid),
3692 ntohl (c->fwd_fc.last_pid_recv.pid));
3693 LOG2 (level, "CCC last ACK sent: %5u, recv: %5u\n",
3694 ntohl (c->fwd_fc.last_ack_sent.pid),
3695 ntohl (c->fwd_fc.last_ack_recv.pid));
3696 LOG2 (level, "CCC recv PID bitmap: %X\n", c->fwd_fc.recv_bitmap);
3697 LOG2 (level, "CCC poll: task %d, msg %p, msg_ack %p)\n",
3698 c->fwd_fc.poll_task, c->fwd_fc.poll_msg, c->fwd_fc.ack_msg);
3699
3700 LOG2 (level, "CCC BCK flow control:\n");
3701 LOG2 (level, "CCC queue: %u/%u\n", c->bck_fc.queue_n, c->bck_fc.queue_max);
3702 LOG2 (level, "CCC last PID sent: %5u, recv: %5u\n",
3703 ntohl (c->bck_fc.last_pid_sent.pid),
3704 ntohl (c->bck_fc.last_pid_recv.pid));
3705 LOG2 (level, "CCC last ACK sent: %5u, recv: %5u\n",
3706 ntohl (c->bck_fc.last_ack_sent.pid),
3707 ntohl (c->bck_fc.last_ack_recv.pid));
3708 LOG2 (level, "CCC recv PID bitmap: %X\n", c->bck_fc.recv_bitmap);
3709 LOG2 (level, "CCC poll: task %d, msg %p, msg_ack %p)\n",
3710 c->bck_fc.poll_task, c->bck_fc.poll_msg, c->bck_fc.ack_msg);
3711
3712 LOG2 (level, "CCC DEBUG CONNECTION END\n");
3713} 1089}
1090
1091/* end of gnunet-service-cadet-new_connection.c */
diff --git a/src/cadet/gnunet-service-cadet_connection.h b/src/cadet/gnunet-service-cadet_connection.h
index 307cb42c2..fdb184366 100644
--- a/src/cadet/gnunet-service-cadet_connection.h
+++ b/src/cadet/gnunet-service-cadet_connection.h
@@ -1,6 +1,7 @@
1
1/* 2/*
2 This file is part of GNUnet. 3 This file is part of GNUnet.
3 Copyright (C) 2013 GNUnet e.V. 4 Copyright (C) 2001-2017 GNUnet e.V.
4 5
5 GNUnet is free software; you can redistribute it and/or modify 6 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published 7 it under the terms of the GNU General Public License as published
@@ -20,557 +21,319 @@
20 21
21/** 22/**
22 * @file cadet/gnunet-service-cadet_connection.h 23 * @file cadet/gnunet-service-cadet_connection.h
23 * @brief cadet service; dealing with connections 24 * @brief A connection is a live end-to-end messaging mechanism
25 * where the peers are identified by a path and know how
26 * to forward along the route using a connection identifier
27 * for routing the data.
24 * @author Bartlomiej Polot 28 * @author Bartlomiej Polot
25 * 29 * @author Christian Grothoff
26 * All functions in this file use the prefix GCC (GNUnet Cadet Connection)
27 */ 30 */
28
29#ifndef GNUNET_SERVICE_CADET_CONNECTION_H 31#ifndef GNUNET_SERVICE_CADET_CONNECTION_H
30#define GNUNET_SERVICE_CADET_CONNECTION_H 32#define GNUNET_SERVICE_CADET_CONNECTION_H
31 33
32#ifdef __cplusplus
33extern "C"
34{
35#if 0 /* keep Emacsens' auto-indent happy */
36}
37#endif
38#endif
39
40#include "gnunet_util_lib.h" 34#include "gnunet_util_lib.h"
41 35#include "gnunet-service-cadet.h"
42
43/**
44 * All the states a connection can be in.
45 */
46enum CadetConnectionState
47{
48 /**
49 * Uninitialized status, should never appear in operation.
50 */
51 CADET_CONNECTION_NEW,
52
53 /**
54 * Connection create message sent, waiting for ACK.
55 */
56 CADET_CONNECTION_SENT,
57
58 /**
59 * Connection ACK sent, waiting for ACK.
60 */
61 CADET_CONNECTION_ACK,
62
63 /**
64 * Connection confirmed, ready to carry traffic.
65 */
66 CADET_CONNECTION_READY,
67
68 /**
69 * Connection to be destroyed, just waiting to empty queues.
70 */
71 CADET_CONNECTION_DESTROYED,
72
73 /**
74 * Connection to be destroyed because of a distant peer, same as DESTROYED.
75 */
76 CADET_CONNECTION_BROKEN,
77};
78
79
80/**
81 * Struct containing all information regarding a connection to a peer.
82 */
83struct CadetConnection;
84
85/**
86 * Handle for messages queued but not yet sent.
87 */
88struct CadetConnectionQueue;
89
90#include "cadet_path.h"
91#include "gnunet-service-cadet_channel.h"
92#include "gnunet-service-cadet_peer.h" 36#include "gnunet-service-cadet_peer.h"
37#include "cadet_protocol.h"
93 38
94 39
95/** 40/**
96 * Check invariants for all connections using #check_neighbours(). 41 * Function called to notify tunnel about change in our readyness.
97 */
98void
99GCC_check_connections (void);
100
101
102/**
103 * Callback called when a queued message is sent.
104 * 42 *
105 * @param cls Closure. 43 * @param cls closure
106 * @param c Connection this message was on. 44 * @param is_ready #GNUNET_YES if the connection is now ready for transmission,
107 * @param type Type of message sent. 45 * #GNUNET_NO if the connection is no longer ready for transmission
108 * @param fwd Was this a FWD going message?
109 * @param size Size of the message.
110 */ 46 */
111typedef void 47typedef void
112(*GCC_sent) (void *cls, 48(*GCC_ReadyCallback)(void *cls,
113 struct CadetConnection *c, 49 int is_ready);
114 struct CadetConnectionQueue *q,
115 uint16_t type,
116 int fwd,
117 size_t size);
118 50
119 51
120/** 52/**
121 * Handler for connection creation. 53 * Destroy a connection, called when the CORE layer is already done
54 * (i.e. has received a BROKEN message), but if we still have to
55 * communicate the destruction of the connection to the tunnel (if one
56 * exists).
122 * 57 *
123 * @param peer Message sender (neighbor). 58 * @param cc connection to destroy
124 * @param msg Message itself.
125 */ 59 */
126void 60void
127GCC_handle_create (struct CadetPeer *peer, 61GCC_destroy_without_core (struct CadetConnection *cc);
128 const struct GNUNET_CADET_ConnectionCreateMessage *msg);
129 62
130 63
131/** 64/**
132 * Handler for connection confirmations. 65 * Destroy a connection, called if the tunnel association with the
66 * connection was already broken, but we still need to notify the CORE
67 * layer about the breakage.
133 * 68 *
134 * @param peer Message sender (neighbor). 69 * @param cc connection to destroy
135 * @param msg Message itself.
136 */ 70 */
137void 71void
138GCC_handle_confirm (struct CadetPeer *peer, 72GCC_destroy_without_tunnel (struct CadetConnection *cc);
139 const struct GNUNET_CADET_ConnectionCreateAckMessage *msg);
140 73
141 74
142/** 75/**
143 * Handler for notifications of broken connections. 76 * Lookup a connection by its identifier.
144 * 77 *
145 * @param peer Message sender (neighbor). 78 * @param cid identifier to resolve
146 * @param msg Message itself. 79 * @return NULL if connection was not found
147 */ 80 */
148void 81struct CadetConnection *
149GCC_handle_broken (struct CadetPeer *peer, 82GCC_lookup (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid);
150 const struct GNUNET_CADET_ConnectionBrokenMessage *msg);
151 83
152/**
153 * Handler for notifications of destroyed connections.
154 *
155 * @param peer Message sender (neighbor).
156 * @param msg Message itself.
157 */
158void
159GCC_handle_destroy (struct CadetPeer *peer,
160 const struct GNUNET_CADET_ConnectionDestroyMessage *msg);
161 84
162/** 85/**
163 * Handler for cadet network traffic hop-by-hop acks. 86 * Create a connection to @a destination via @a path and
87 * notify @a cb whenever we are ready for more data.
164 * 88 *
165 * @param peer Message sender (neighbor). 89 * @param destination where to go
166 * @param msg Message itself. 90 * @param path which path to take (may not be the full path)
91 * @param off offset of @a destination on @a path
92 * @param options options for the connection
93 * @param ct which tunnel uses this connection
94 * @param ready_cb function to call when ready to transmit
95 * @param ready_cb_cls closure for @a cb
96 * @return handle to the connection
167 */ 97 */
168void 98struct CadetConnection *
169GCC_handle_ack (struct CadetPeer *peer, 99GCC_create (struct CadetPeer *destination,
170 const struct GNUNET_CADET_ConnectionEncryptedAckMessage *msg); 100 struct CadetPeerPath *path,
101 unsigned int off,
102 enum GNUNET_CADET_ChannelOption options,
103 struct CadetTConnection *ct,
104 GCC_ReadyCallback ready_cb,
105 void *ready_cb_cls);
171 106
172/**
173 * Handler for cadet network traffic hop-by-hop data counter polls.
174 *
175 * @param peer Message sender (neighbor).
176 * @param msg Message itself.
177 */
178void
179GCC_handle_poll (struct CadetPeer *peer,
180 const struct GNUNET_CADET_ConnectionHopByHopPollMessage *msg);
181 107
182/** 108/**
183 * Handler for key exchange traffic (Axolotl KX). 109 * Create a connection to @a destination via @a path and
110 * notify @a cb whenever we are ready for more data. This
111 * is an inbound tunnel, so we must use the existing @a cid
184 * 112 *
185 * @param peer Message sender (neighbor). 113 * @param destination where to go
186 * @param msg Message itself. 114 * @param path which path to take (may not be the full path)
115 * @param options options for the connection
116 * @param ct which tunnel uses this connection
117 * @param ready_cb function to call when ready to transmit
118 * @param ready_cb_cls closure for @a cb
119 * @return handle to the connection, NULL if we already have
120 * a connection that takes precedence on @a path
187 */ 121 */
188void 122struct CadetConnection *
189GCC_handle_kx (struct CadetPeer *peer, 123GCC_create_inbound (struct CadetPeer *destination,
190 const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg); 124 struct CadetPeerPath *path,
125 enum GNUNET_CADET_ChannelOption options,
126 struct CadetTConnection *ct,
127 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
128 GCC_ReadyCallback ready_cb,
129 void *ready_cb_cls);
130
191 131
192/** 132/**
193 * Handler for encrypted cadet network traffic (channel mgmt, data). 133 * Transmit message @a msg via connection @a cc. Must only be called
134 * (once) after the connection has signalled that it is ready via the
135 * `ready_cb`. Clients can also use #GCC_is_ready() to check if the
136 * connection is right now ready for transmission.
194 * 137 *
195 * @param peer Message sender (neighbor). 138 * @param cc connection identification
196 * @param msg Message itself. 139 * @param env envelope with message to transmit;
140 * the #GNUNET_MQ_notify_send() must not have yet been used
141 * for the envelope. Also, the message better match the
142 * connection identifier of this connection...
197 */ 143 */
198void 144void
199GCC_handle_encrypted (struct CadetPeer *peer, 145GCC_transmit (struct CadetConnection *cc,
200 const struct GNUNET_CADET_TunnelEncryptedMessage *msg); 146 struct GNUNET_MQ_Envelope *env);
201 147
202/**
203 * Core handler for axolotl key exchange traffic.
204 *
205 * @param cls Closure (unused).
206 * @param message Message received.
207 * @param peer Neighbor who sent the message.
208 *
209 * @return GNUNET_OK, to keep the connection open.
210 */
211int
212GCC_handle_ax_kx (void *cls, const struct GNUNET_PeerIdentity *peer,
213 const struct GNUNET_MessageHeader *message);
214 148
215/** 149/**
216 * Core handler for axolotl encrypted cadet network traffic. 150 * A CREATE_ACK was received for this connection, process it.
217 * 151 *
218 * @param cls Closure (unused). 152 * @param cc the connection that got the ACK.
219 * @param message Message received.
220 * @param peer Neighbor who sent the message.
221 *
222 * @return GNUNET_OK, to keep the connection open.
223 */ 153 */
224int 154void
225GCC_handle_ax (void *cls, const struct GNUNET_PeerIdentity *peer, 155GCC_handle_connection_create_ack (struct CadetConnection *cc);
226 struct GNUNET_MessageHeader *message);
227 156
228/**
229 * Core handler for cadet keepalives.
230 *
231 * @param cls closure
232 * @param message message
233 * @param peer peer identity this notification is about
234 * @return GNUNET_OK to keep the connection open,
235 * GNUNET_SYSERR to close it (signal serious error)
236 *
237 * TODO: Check who we got this from, to validate route.
238 */
239int
240GCC_handle_keepalive (void *cls, const struct GNUNET_PeerIdentity *peer,
241 const struct GNUNET_MessageHeader *message);
242 157
243/** 158/**
244 * Send an ACK on the appropriate connection/channel, depending on 159 * We got a #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE for a
245 * the direction and the position of the peer. 160 * connection that we already have. Either our ACK got lost
161 * or something is fishy. Consider retransmitting the ACK.
246 * 162 *
247 * @param c Which connection to send the hop-by-hop ACK. 163 * @param cc connection that got the duplicate CREATE
248 * @param fwd Is this a fwd ACK? (will go dest->root).
249 * @param force Send the ACK even if suboptimal (e.g. requested by POLL).
250 */ 164 */
251void 165void
252GCC_send_ack (struct CadetConnection *c, int fwd, int force); 166GCC_handle_duplicate_create (struct CadetConnection *cc);
253 167
254/**
255 * Initialize the connections subsystem
256 *
257 * @param c Configuration handle.
258 */
259void
260GCC_init (const struct GNUNET_CONFIGURATION_Handle *c);
261 168
262/** 169/**
263 * Shut down the connections subsystem. 170 * Handle KX message.
171 *
172 * @param cc connection that received encrypted message
173 * @param msg the key exchange message
264 */ 174 */
265void 175void
266GCC_shutdown (void); 176GCC_handle_kx (struct CadetConnection *cc,
177 const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg);
267 178
268/**
269 * Create a connection.
270 *
271 * @param cid Connection ID (either created locally or imposed remotely).
272 * @param t Tunnel this connection belongs to (or NULL for transit connections);
273 * @param path Path this connection has to use (copy is made).
274 * @param own_pos Own position in the @c path path.
275 *
276 * @return Newly created connection.
277 * NULL in case of error: own id not in path, wrong neighbors, ...
278 */
279struct CadetConnection *
280GCC_new (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
281 struct CadetTunnel *t,
282 struct CadetPeerPath *path,
283 unsigned int own_pos);
284 179
285/** 180/**
286 * Connection is no longer needed: destroy it. 181 * Handle KX_AUTH message.
287 *
288 * Cancels all pending traffic (including possible DESTROY messages), all
289 * maintenance tasks and removes the connection from neighbor peers and tunnel.
290 * 182 *
291 * @param c Connection to destroy. 183 * @param cc connection that received encrypted message
184 * @param msg the key exchange message
292 */ 185 */
293void 186void
294GCC_destroy (struct CadetConnection *c); 187GCC_handle_kx_auth (struct CadetConnection *cc,
295 188 const struct GNUNET_CADET_TunnelKeyExchangeAuthMessage *msg);
296/**
297 * Get the connection ID.
298 *
299 * @param c Connection to get the ID from.
300 *
301 * @return ID of the connection.
302 */
303const struct GNUNET_CADET_ConnectionTunnelIdentifier *
304GCC_get_id (const struct CadetConnection *c);
305 189
306 190
307/** 191/**
308 * Get the connection path. 192 * Performance metrics for a connection.
309 *
310 * @param c Connection to get the path from.
311 *
312 * @return path used by the connection.
313 */ 193 */
314const struct CadetPeerPath * 194struct CadetConnectionMetrics
315GCC_get_path (const struct CadetConnection *c); 195{
316 196
317/** 197 /**
318 * Get the connection state. 198 * Our current best estimate of the latency, based on a weighted
319 * 199 * average of at least @a latency_datapoints values.
320 * @param c Connection to get the state from. 200 */
321 * 201 struct GNUNET_TIME_Relative aged_latency;
322 * @return state of the connection.
323 */
324enum CadetConnectionState
325GCC_get_state (const struct CadetConnection *c);
326 202
327/** 203 /**
328 * Get the connection tunnel. 204 * When was this connection first established? (by us sending or
329 * 205 * receiving the CREATE_ACK for the first time)
330 * @param c Connection to get the tunnel from. 206 */
331 * 207 struct GNUNET_TIME_Absolute age;
332 * @return tunnel of the connection.
333 */
334struct CadetTunnel *
335GCC_get_tunnel (const struct CadetConnection *c);
336 208
337/** 209 /**
338 * Get free buffer space in a connection. 210 * When was this connection last used? (by us sending or
339 * 211 * receiving a PAYLOAD message on it)
340 * @param c Connection. 212 */
341 * @param fwd Is query about FWD traffic? 213 struct GNUNET_TIME_Absolute last_use;
342 *
343 * @return Free buffer space [0 - max_msgs_queue/max_connections]
344 */
345unsigned int
346GCC_get_buffer (struct CadetConnection *c, int fwd);
347 214
348/** 215 /**
349 * Get how many messages have we allowed to send to us from a direction. 216 * How many packets that ought to generate an ACK did we send via
350 * 217 * this connection?
351 * @param c Connection. 218 */
352 * @param fwd Are we asking about traffic from FWD (BCK messages)? 219 unsigned long long num_acked_transmissions;
353 *
354 * @return last_ack_sent - last_pid_recv
355 */
356unsigned int
357GCC_get_allowed (struct CadetConnection *c, int fwd);
358 220
359/** 221 /**
360 * Get messages queued in a connection. 222 * Number of packets that were sent via this connection did actually
361 * 223 * receive an ACK? (Note: ACKs may be transmitted and lost via
362 * @param c Connection. 224 * other connections, so this value should only be interpreted
363 * @param fwd Is query about FWD traffic? 225 * relative to @e num_acked_transmissions and in relation to other
364 * 226 * connections.)
365 * @return Number of messages queued. 227 */
366 */ 228 unsigned long long num_successes;
367unsigned int
368GCC_get_qn (struct CadetConnection *c, int fwd);
369 229
370/** 230};
371 * Get next PID to use.
372 *
373 * @param c Connection.
374 * @param fwd Is query about FWD traffic?
375 * @return Next PID to use.
376 */
377struct CadetEncryptedMessageIdentifier
378GCC_get_pid (struct CadetConnection *c, int fwd);
379 231
380/**
381 * Allow the connection to advertise a buffer of the given size.
382 *
383 * The connection will send an @c fwd ACK message (so: in direction !fwd)
384 * allowing up to last_pid_recv + buffer.
385 *
386 * @param c Connection.
387 * @param buffer How many more messages the connection can accept.
388 * @param fwd Is this about FWD traffic? (The ack will go dest->root).
389 */
390void
391GCC_allow (struct CadetConnection *c, unsigned int buffer, int fwd);
392 232
393/** 233/**
394 * Send FWD keepalive packets for a connection. 234 * Obtain performance @a metrics from @a cc.
395 * 235 *
396 * @param cls Closure (connection for which to send the keepalive). 236 * @param cc connection to query
397 * @param tc Notification context. 237 * @return the metrics
398 */ 238 */
399void 239const struct CadetConnectionMetrics *
400GCC_fwd_keepalive (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); 240GCC_get_metrics (struct CadetConnection *cc);
241
401 242
402/** 243/**
403 * Send BCK keepalive packets for a connection. 244 * Handle encrypted message.
404 * 245 *
405 * @param cls Closure (connection for which to send the keepalive). 246 * @param cc connection that received encrypted message
406 * @param tc Notification context. 247 * @param msg the encrypted message to decrypt
407 */ 248 */
408void 249void
409GCC_bck_keepalive (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); 250GCC_handle_encrypted (struct CadetConnection *cc,
251 const struct GNUNET_CADET_TunnelEncryptedMessage *msg);
410 252
411 253
412/** 254/**
413 * Notify other peers on a connection of a broken link. Mark connections 255 * We sent a message for which we expect to receive an ACK via
414 * to destroy after all traffic has been sent. 256 * the connection identified by @a cti.
415 * 257 *
416 * @param c Connection on which there has been a disconnection. 258 * @param cid connection identifier where we expect an ACK
417 * @param peer Peer that disconnected.
418 */ 259 */
419void 260void
420GCC_neighbor_disconnected (struct CadetConnection *c, struct CadetPeer *peer); 261GCC_ack_expected (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid);
421 262
422/**
423 * Is this peer the first one on the connection?
424 *
425 * @param c Connection.
426 * @param fwd Is this about fwd traffic?
427 *
428 * @return #GNUNET_YES if origin, #GNUNET_NO if relay/terminal.
429 */
430int
431GCC_is_origin (struct CadetConnection *c, int fwd);
432 263
433/** 264/**
434 * Is this peer the last one on the connection? 265 * We observed an ACK for a message that was originally sent via
435 * 266 * the connection identified by @a cti.
436 * @param c Connection.
437 * @param fwd Is this about fwd traffic?
438 * Note that the ROOT is the terminal for BCK traffic!
439 * 267 *
440 * @return #GNUNET_YES if terminal, #GNUNET_NO if relay/origin. 268 * @param cid connection identifier where we got an ACK for a message
269 * that was originally sent via this connection (the ACK
270 * may have gotten back to us via a different connection).
441 */ 271 */
442int 272void
443GCC_is_terminal (struct CadetConnection *c, int fwd); 273GCC_ack_observed (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid);
444
445/**
446 * See if we are allowed to send by the next hop in the given direction.
447 *
448 * @param c Connection.
449 * @param fwd Is this about fwd traffic?
450 *
451 * @return #GNUNET_YES in case it's OK to send.
452 */
453int
454GCC_is_sendable (struct CadetConnection *c, int fwd);
455 274
456/**
457 * Check if this connection is a direct one (never trim a direct connection).
458 *
459 * @param c Connection.
460 *
461 * @return #GNUNET_YES in case it's a direct connection, #GNUNET_NO otherwise.
462 */
463int
464GCC_is_direct (struct CadetConnection *c);
465 275
466/** 276/**
467 * Cancel a previously sent message while it's in the queue. 277 * We observed some the given @a latency on the connection
278 * identified by @a cti. (The same connection was taken
279 * in both directions.)
468 * 280 *
469 * ONLY can be called before the continuation given to the send function 281 * @param cti connection identifier where we measured latency
470 * is called. Once the continuation is called, the message is no longer in the 282 * @param latency the observed latency
471 * queue.
472 *
473 * @param q Handle to the queue.
474 */ 283 */
475void 284void
476GCC_cancel (struct CadetConnectionQueue *q); 285GCC_latency_observed (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
286 struct GNUNET_TIME_Relative latency);
477 287
478/**
479 * Sends an already built message on a connection, properly registering
480 * all used resources.
481 *
482 * @param message Message to send.
483 * @param payload_type Type of payload, in case the message is encrypted.
484 * 0 for restransmissions (when type is no longer known)
485 * UINT16_MAX when not applicable.
486 * @param payload_id ID of the payload (PID, ACK, ...).
487 * @param c Connection on which this message is transmitted.
488 * @param fwd Is this a fwd message?
489 * @param force Force the connection to accept the message (buffer overfill).
490 * @param cont Continuation called once message is sent. Can be NULL.
491 * @param cont_cls Closure for @c cont.
492 *
493 * @return Handle to cancel the message before it's sent.
494 * NULL on error.
495 * Invalid on @c cont call.
496 */
497struct CadetConnectionQueue *
498GCC_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
499 uint16_t payload_type,
500 struct CadetEncryptedMessageIdentifier payload_id,
501 struct CadetConnection *c, int fwd, int force,
502 GCC_sent cont, void *cont_cls);
503 288
504/** 289/**
505 * Sends a CREATE CONNECTION message for a path to a peer. 290 * Return the tunnel associated with this connection.
506 * Changes the connection and tunnel states if necessary.
507 * 291 *
508 * @param connection Connection to create. 292 * @param cc connection to query
293 * @return corresponding entry in the tunnel's connection list
509 */ 294 */
510void 295struct CadetTConnection *
511GCC_send_create (struct CadetConnection *connection); 296GCC_get_ct (struct CadetConnection *cc);
512 297
513/**
514 * Send a message to all peers in this connection that the connection
515 * is no longer valid.
516 *
517 * If some peer should not receive the message, it should be zero'ed out
518 * before calling this function.
519 *
520 * @param c The connection whose peers to notify.
521 */
522void
523GCC_send_destroy (struct CadetConnection *c);
524 298
525/** 299/**
526 * @brief Start a polling timer for the connection. 300 * Obtain the path used by this connection.
527 * 301 *
528 * When a neighbor does not accept more traffic on the connection it could be 302 * @param cc connection
529 * caused by a simple congestion or by a lost ACK. Polling enables to check 303 * @return path to @a cc
530 * for the lastest ACK status for a connection.
531 *
532 * @param c Connection.
533 * @param fwd Should we poll in the FWD direction?
534 */ 304 */
535void 305struct CadetPeerPath *
536GCC_start_poll (struct CadetConnection *c, int fwd); 306GCC_get_path (struct CadetConnection *cc);
537 307
538 308
539/** 309/**
540 * @brief Stop polling a connection for ACKs. 310 * Obtain unique ID for the connection.
541 *
542 * Once we have enough ACKs for future traffic, polls are no longer necessary.
543 * 311 *
544 * @param c Connection. 312 * @param cc connection.
545 * @param fwd Should we stop the poll in the FWD direction? 313 * @return unique number of the connection
546 */ 314 */
547void 315const struct GNUNET_CADET_ConnectionTunnelIdentifier *
548GCC_stop_poll (struct CadetConnection *c, int fwd); 316GCC_get_id (struct CadetConnection *cc);
317
549 318
550/** 319/**
551 * Get a (static) string for a connection. 320 * Get a (static) string for a connection.
552 * 321 *
553 * @param c Connection. 322 * @param cc Connection.
554 */ 323 */
555const char * 324const char *
556GCC_2s (const struct CadetConnection *c); 325GCC_2s (const struct CadetConnection *cc);
326
557 327
558/** 328/**
559 * Log all possible info about the connection state. 329 * Log connection info.
560 * 330 *
561 * @param c Connection to debug. 331 * @param cc connection
562 * @param level Debug level to use. 332 * @param level Debug level to use.
563 */ 333 */
564void 334void
565GCC_debug (const struct CadetConnection *c, enum GNUNET_ErrorType level); 335GCC_debug (struct CadetConnection *cc,
336 enum GNUNET_ErrorType level);
566 337
567#if 0 /* keep Emacsens' auto-indent happy */
568{
569#endif
570#ifdef __cplusplus
571}
572#endif
573 338
574/* ifndef GNUNET_SERVICE_CADET_CONNECTION_H */
575#endif 339#endif
576/* end of gnunet-service-cadet_connection.h */
diff --git a/src/cadet/gnunet-service-cadet-new_core.c b/src/cadet/gnunet-service-cadet_core.c
index 3768c36a5..ae03b4f35 100644
--- a/src/cadet/gnunet-service-cadet-new_core.c
+++ b/src/cadet/gnunet-service-cadet_core.c
@@ -30,11 +30,11 @@
30 * - Optimization: given BROKEN messages, destroy paths (?) 30 * - Optimization: given BROKEN messages, destroy paths (?)
31 */ 31 */
32#include "platform.h" 32#include "platform.h"
33#include "gnunet-service-cadet-new_core.h" 33#include "gnunet-service-cadet_core.h"
34#include "gnunet-service-cadet-new_paths.h" 34#include "gnunet-service-cadet_paths.h"
35#include "gnunet-service-cadet-new_peer.h" 35#include "gnunet-service-cadet_peer.h"
36#include "gnunet-service-cadet-new_connection.h" 36#include "gnunet-service-cadet_connection.h"
37#include "gnunet-service-cadet-new_tunnels.h" 37#include "gnunet-service-cadet_tunnels.h"
38#include "gnunet_core_service.h" 38#include "gnunet_core_service.h"
39#include "gnunet_statistics_service.h" 39#include "gnunet_statistics_service.h"
40#include "cadet_protocol.h" 40#include "cadet_protocol.h"
diff --git a/src/cadet/gnunet-service-cadet-new_core.h b/src/cadet/gnunet-service-cadet_core.h
index 65b0a6ba5..65b0a6ba5 100644
--- a/src/cadet/gnunet-service-cadet-new_core.h
+++ b/src/cadet/gnunet-service-cadet_core.h
diff --git a/src/cadet/gnunet-service-cadet_dht.c b/src/cadet/gnunet-service-cadet_dht.c
index 22673b167..f00c0caf3 100644
--- a/src/cadet/gnunet-service-cadet_dht.c
+++ b/src/cadet/gnunet-service-cadet_dht.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 Copyright (C) 2013 GNUnet e.V. 3 Copyright (C) 2013, 2017 GNUnet e.V.
4 4
5 GNUnet is free software; you can redistribute it and/or modify 5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published 6 it under the terms of the GNU General Public License as published
@@ -17,25 +17,41 @@
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA. 18 Boston, MA 02110-1301, USA.
19*/ 19*/
20 20/**
21 * @file cadet/gnunet-service-cadet_dht.c
22 * @brief Information we track per peer.
23 * @author Bartlomiej Polot
24 * @author Christian Grothoff
25 */
21 26
22#include "platform.h" 27#include "platform.h"
23#include "gnunet_util_lib.h" 28#include "gnunet_util_lib.h"
24
25#include "gnunet_dht_service.h" 29#include "gnunet_dht_service.h"
26#include "gnunet_statistics_service.h" 30#include "gnunet_statistics_service.h"
27 31#include "gnunet-service-cadet.h"
28#include "cadet_path.h"
29#include "gnunet-service-cadet_dht.h" 32#include "gnunet-service-cadet_dht.h"
30#include "gnunet-service-cadet_peer.h"
31#include "gnunet-service-cadet_hello.h" 33#include "gnunet-service-cadet_hello.h"
34#include "gnunet-service-cadet_peer.h"
35#include "gnunet-service-cadet_paths.h"
32 36
33#define LOG(level, ...) GNUNET_log_from (level,"cadet-dht",__VA_ARGS__) 37/**
38 * How long do we wait before first announcing our presence to the DHT.
39 * Used to wait for our HELLO to be available. Note that we also get
40 * notifications when our HELLO is ready, so this is just the maximum
41 * we wait for the first notification.
42 */
43#define STARTUP_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 500)
34 44
45/**
46 * How long do we wait after we get an updated HELLO before publishing?
47 * Allows for the HELLO to be updated again quickly, for example in
48 * case multiple addresses changed and we got a partial update.
49 */
50#define CHANGE_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100)
51
52
53#define LOG(level, ...) GNUNET_log_from (level,"cadet-dht",__VA_ARGS__)
35 54
36/******************************************************************************/
37/******************************** STRUCTS **********************************/
38/******************************************************************************/
39 55
40/** 56/**
41 * Handle for DHT searches. 57 * Handle for DHT searches.
@@ -47,42 +63,9 @@ struct GCD_search_handle
47 */ 63 */
48 struct GNUNET_DHT_GetHandle *dhtget; 64 struct GNUNET_DHT_GetHandle *dhtget;
49 65
50 /**
51 * Provided callback to call when a path is found.
52 */
53 GCD_search_callback callback;
54
55 /**
56 * Provided closure.
57 */
58 void *cls;
59
60 /**
61 * Peer ID searched for
62 */
63 GNUNET_PEER_Id peer_id;
64}; 66};
65 67
66 68
67/******************************************************************************/
68/******************************* GLOBALS ***********************************/
69/******************************************************************************/
70
71/**
72 * Global handle to the statistics service.
73 */
74extern struct GNUNET_STATISTICS_Handle *stats;
75
76/**
77 * Own ID (short value).
78 */
79extern GNUNET_PEER_Id myid;
80
81/**
82 * Own ID (full value).
83 */
84extern struct GNUNET_PeerIdentity my_full_id;
85
86/** 69/**
87 * Handle to use DHT. 70 * Handle to use DHT.
88 */ 71 */
@@ -94,69 +77,20 @@ static struct GNUNET_DHT_Handle *dht_handle;
94static struct GNUNET_TIME_Relative id_announce_time; 77static struct GNUNET_TIME_Relative id_announce_time;
95 78
96/** 79/**
97 * DHT replication level, see DHT API: GNUNET_DHT_get_start, GNUNET_DHT_put. 80 * DHT replication level, see DHT API: #GNUNET_DHT_get_start(), #GNUNET_DHT_put().
98 */ 81 */
99static unsigned long long dht_replication_level; 82static unsigned long long dht_replication_level;
100 83
101/** 84/**
102 * Task to periodically announce itself in the network. 85 * Task to periodically announce itself in the network.
103 */ 86 */
104static struct GNUNET_SCHEDULER_Task * announce_id_task; 87static struct GNUNET_SCHEDULER_Task *announce_id_task;
105 88
106/** 89/**
107 * Delay for the next ID announce. 90 * Delay for the next ID announce.
108 */ 91 */
109static struct GNUNET_TIME_Relative announce_delay; 92static struct GNUNET_TIME_Relative announce_delay;
110 93
111/**
112 * GET requests to stop on shutdown.
113 */
114static struct GNUNET_CONTAINER_MultiHashMap32 *get_requests;
115
116/******************************************************************************/
117/******************************** STATIC ***********************************/
118/******************************************************************************/
119
120
121/**
122 * Build a PeerPath from the paths returned from the DHT, reversing the paths
123 * to obtain a local peer -> destination path and interning the peer ids.
124 *
125 * @return Newly allocated and created path
126 *
127 * FIXME refactor and use build_path_from_peer_ids
128 */
129static struct CadetPeerPath *
130path_build_from_dht (const struct GNUNET_PeerIdentity *get_path,
131 unsigned int get_path_length,
132 const struct GNUNET_PeerIdentity *put_path,
133 unsigned int put_path_length)
134{
135 size_t size = get_path_length + put_path_length + 1;
136 struct GNUNET_PeerIdentity peers[size];
137 const struct GNUNET_PeerIdentity *peer;
138 struct CadetPeerPath *p;
139 unsigned int own_pos;
140 int i;
141
142 peers[0] = my_full_id;
143 LOG (GNUNET_ERROR_TYPE_DEBUG, " GET has %d hops.\n", get_path_length);
144 for (i = 0 ; i < get_path_length; i++)
145 {
146 peer = &get_path[get_path_length - i - 1];
147 LOG (GNUNET_ERROR_TYPE_DEBUG, " From GET: %s\n", GNUNET_i2s (peer));
148 peers[i + 1] = *peer;
149 }
150 for (i = 0 ; i < put_path_length; i++)
151 {
152 peer = &put_path[put_path_length - i - 1];
153 LOG (GNUNET_ERROR_TYPE_DEBUG, " From PUT: %s\n", GNUNET_i2s (peer));
154 peers[i + get_path_length + 1] = *peer;
155 }
156 p = path_build_from_peer_ids (peers, size, myid, &own_pos);
157 return p;
158}
159
160 94
161/** 95/**
162 * Function to process paths received for a new peer addition. The recorded 96 * Function to process paths received for a new peer addition. The recorded
@@ -176,42 +110,34 @@ path_build_from_dht (const struct GNUNET_PeerIdentity *get_path,
176 */ 110 */
177static void 111static void
178dht_get_id_handler (void *cls, struct GNUNET_TIME_Absolute exp, 112dht_get_id_handler (void *cls, struct GNUNET_TIME_Absolute exp,
179 const struct GNUNET_HashCode * key, 113 const struct GNUNET_HashCode *key,
180 const struct GNUNET_PeerIdentity *get_path, 114 const struct GNUNET_PeerIdentity *get_path,
181 unsigned int get_path_length, 115 unsigned int get_path_length,
182 const struct GNUNET_PeerIdentity *put_path, 116 const struct GNUNET_PeerIdentity *put_path,
183 unsigned int put_path_length, enum GNUNET_BLOCK_Type type, 117 unsigned int put_path_length,
184 size_t size, const void *data) 118 enum GNUNET_BLOCK_Type type,
119 size_t size,
120 const void *data)
185{ 121{
186 struct GCD_search_handle *h = cls; 122 const struct GNUNET_HELLO_Message *hello = data;
187 struct GNUNET_HELLO_Message *hello;
188 struct CadetPeerPath *p;
189 struct CadetPeer *peer; 123 struct CadetPeer *peer;
190 char *s;
191 124
192 p = path_build_from_dht (get_path, get_path_length, 125 GCPP_try_path_from_dht (get_path,
193 put_path, put_path_length); 126 get_path_length,
194 if (NULL == p) 127 put_path,
128 put_path_length);
129 if ( (size >= sizeof (struct GNUNET_HELLO_Message)) &&
130 (ntohs (hello->header.size) == size) &&
131 (size == GNUNET_HELLO_size (hello)) )
195 { 132 {
196 GNUNET_break_op (0); 133 peer = GCP_get (&put_path[0],
197 return; 134 GNUNET_YES);
135 LOG (GNUNET_ERROR_TYPE_DEBUG,
136 "Got HELLO for %s\n",
137 GCP_2s (peer));
138 GCP_set_hello (peer,
139 hello);
198 } 140 }
199
200 s = path_2s (p);
201 LOG (GNUNET_ERROR_TYPE_INFO,
202 "Got path from DHT: %s\n",
203 s);
204 GNUNET_free_non_null (s);
205
206 peer = GCP_get_short (p->peers[p->length - 1], GNUNET_YES);
207 LOG (GNUNET_ERROR_TYPE_DEBUG,
208 "Got HELLO for %s\n",
209 GCP_2s (peer));
210 h->callback (h->cls, p);
211 path_destroy (p);
212 hello = (struct GNUNET_HELLO_Message *) data;
213 GCP_set_hello (peer, hello);
214 GCP_try_connect (peer);
215} 141}
216 142
217 143
@@ -229,19 +155,10 @@ announce_id (void *cls)
229 struct GNUNET_TIME_Absolute expiration; 155 struct GNUNET_TIME_Absolute expiration;
230 struct GNUNET_TIME_Relative next_put; 156 struct GNUNET_TIME_Relative next_put;
231 157
232 announce_id_task = NULL;
233 LOG (GNUNET_ERROR_TYPE_DEBUG, "Announce ID\n");
234 hello = GCH_get_mine (); 158 hello = GCH_get_mine ();
235 size = (NULL != hello) ? GNUNET_HELLO_size (hello) : 0; 159 size = (NULL != hello) ? GNUNET_HELLO_size (hello) : 0;
236 if ( (NULL == hello) || (0 == size) ) 160 if (0 == size)
237 { 161 {
238 /* Peerinfo gave us no hello yet, try again soon. */
239 LOG (GNUNET_ERROR_TYPE_INFO,
240 " no hello, waiting!\n");
241 GNUNET_STATISTICS_update (stats,
242 "# DHT announce skipped (no hello)",
243 1,
244 GNUNET_NO);
245 expiration = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), 162 expiration = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (),
246 announce_delay); 163 announce_delay);
247 announce_delay = GNUNET_TIME_STD_BACKOFF (announce_delay); 164 announce_delay = GNUNET_TIME_STD_BACKOFF (announce_delay);
@@ -252,71 +169,64 @@ announce_id (void *cls)
252 announce_delay = GNUNET_TIME_UNIT_SECONDS; 169 announce_delay = GNUNET_TIME_UNIT_SECONDS;
253 } 170 }
254 171
255 LOG (GNUNET_ERROR_TYPE_DEBUG,
256 "Hello %p size: %u\n",
257 hello,
258 size);
259 if (NULL != hello)
260 {
261 GNUNET_STATISTICS_update (stats,
262 "# DHT announce",
263 1, GNUNET_NO);
264 memset (&phash,
265 0,
266 sizeof (phash));
267 GNUNET_memcpy (&phash,
268 &my_full_id,
269 sizeof (my_full_id));
270 GNUNET_DHT_put (dht_handle, /* DHT handle */
271 &phash, /* Key to use */
272 dht_replication_level, /* Replication level */
273 GNUNET_DHT_RO_RECORD_ROUTE
274 | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, /* DHT options */
275 GNUNET_BLOCK_TYPE_DHT_HELLO, /* Block type */
276 size, /* Size of the data */
277 (const char *) hello, /* Data itself */
278 expiration, /* Data expiration */
279 NULL, /* Continuation */
280 NULL); /* Continuation closure */
281 }
282 /* Call again in id_announce_time, unless HELLO expires first, 172 /* Call again in id_announce_time, unless HELLO expires first,
283 * but wait at least 1s. */ 173 * but wait at least 1s. */
284 next_put = GNUNET_TIME_absolute_get_remaining (expiration); 174 next_put
285 next_put = GNUNET_TIME_relative_min (next_put, 175 = GNUNET_TIME_absolute_get_remaining (expiration);
286 id_announce_time); 176 next_put
287 next_put = GNUNET_TIME_relative_max (next_put, 177 = GNUNET_TIME_relative_min (next_put,
288 GNUNET_TIME_UNIT_SECONDS); 178 id_announce_time);
289 announce_id_task = GNUNET_SCHEDULER_add_delayed (next_put, 179 next_put
290 &announce_id, 180 = GNUNET_TIME_relative_max (next_put,
291 cls); 181 GNUNET_TIME_UNIT_SECONDS);
182 announce_id_task
183 = GNUNET_SCHEDULER_add_delayed (next_put,
184 &announce_id,
185 cls);
186 GNUNET_STATISTICS_update (stats,
187 "# DHT announce",
188 1,
189 GNUNET_NO);
190 memset (&phash,
191 0,
192 sizeof (phash));
193 GNUNET_memcpy (&phash,
194 &my_full_id,
195 sizeof (my_full_id));
196 LOG (GNUNET_ERROR_TYPE_DEBUG,
197 "Announcing my HELLO (%u bytes) in the DHT\n",
198 size);
199 GNUNET_DHT_put (dht_handle, /* DHT handle */
200 &phash, /* Key to use */
201 dht_replication_level, /* Replication level */
202 GNUNET_DHT_RO_RECORD_ROUTE
203 | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, /* DHT options */
204 GNUNET_BLOCK_TYPE_DHT_HELLO, /* Block type */
205 size, /* Size of the data */
206 (const char *) hello, /* Data itself */
207 expiration, /* Data expiration */
208 NULL, /* Continuation */
209 NULL); /* Continuation closure */
292} 210}
293 211
212
294/** 213/**
295 * Iterator over hash map entries and stop GET requests before disconnecting 214 * Function called by the HELLO subsystem whenever OUR hello
296 * from the DHT. 215 * changes. Re-triggers the DHT PUT immediately.
297 *
298 * @param cls Closure (unused)
299 * @param key Current peer ID.
300 * @param value Value in the hash map (GCD_search_handle).
301 *
302 * @return #GNUNET_YES, we should continue to iterate,
303 */ 216 */
304int 217void
305stop_get (void *cls, 218GCD_hello_update ()
306 uint32_t key,
307 void *value)
308{ 219{
309 struct GCD_search_handle *h = value; 220 if (NULL == announce_id_task)
310 221 return; /* too early */
311 GCD_search_stop (h); 222 GNUNET_SCHEDULER_cancel (announce_id_task);
312 return GNUNET_YES; 223 announce_id_task
224 = GNUNET_SCHEDULER_add_delayed (CHANGE_DELAY,
225 &announce_id,
226 NULL);
313} 227}
314 228
315 229
316/******************************************************************************/
317/******************************** API ***********************************/
318/******************************************************************************/
319
320/** 230/**
321 * Initialize the DHT subsystem. 231 * Initialize the DHT subsystem.
322 * 232 *
@@ -325,36 +235,40 @@ stop_get (void *cls,
325void 235void
326GCD_init (const struct GNUNET_CONFIGURATION_Handle *c) 236GCD_init (const struct GNUNET_CONFIGURATION_Handle *c)
327{ 237{
328 LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n");
329 if (GNUNET_OK != 238 if (GNUNET_OK !=
330 GNUNET_CONFIGURATION_get_value_number (c, "CADET", 239 GNUNET_CONFIGURATION_get_value_number (c,
240 "CADET",
331 "DHT_REPLICATION_LEVEL", 241 "DHT_REPLICATION_LEVEL",
332 &dht_replication_level)) 242 &dht_replication_level))
333 { 243 {
334 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING, "CADET", 244 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
335 "DHT_REPLICATION_LEVEL", "USING DEFAULT"); 245 "CADET",
246 "DHT_REPLICATION_LEVEL",
247 "USING DEFAULT");
336 dht_replication_level = 3; 248 dht_replication_level = 3;
337 } 249 }
338 250
339 if (GNUNET_OK != 251 if (GNUNET_OK !=
340 GNUNET_CONFIGURATION_get_value_time (c, "CADET", "ID_ANNOUNCE_TIME", 252 GNUNET_CONFIGURATION_get_value_time (c,
253 "CADET",
254 "ID_ANNOUNCE_TIME",
341 &id_announce_time)) 255 &id_announce_time))
342 { 256 {
343 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, "CADET", 257 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
344 "ID_ANNOUNCE_TIME", "MISSING"); 258 "CADET",
259 "ID_ANNOUNCE_TIME",
260 "MISSING");
345 GNUNET_SCHEDULER_shutdown (); 261 GNUNET_SCHEDULER_shutdown ();
346 return; 262 return;
347 } 263 }
348 264
349 dht_handle = GNUNET_DHT_connect (c, 64); 265 dht_handle = GNUNET_DHT_connect (c,
350 if (NULL == dht_handle) 266 64);
351 { 267 GNUNET_break (NULL != dht_handle);
352 GNUNET_break (0);
353 }
354
355 announce_delay = GNUNET_TIME_UNIT_SECONDS; 268 announce_delay = GNUNET_TIME_UNIT_SECONDS;
356 announce_id_task = GNUNET_SCHEDULER_add_now (&announce_id, NULL); 269 announce_id_task = GNUNET_SCHEDULER_add_delayed (STARTUP_DELAY,
357 get_requests = GNUNET_CONTAINER_multihashmap32_create (32); 270 &announce_id,
271 NULL);
358} 272}
359 273
360 274
@@ -364,10 +278,7 @@ GCD_init (const struct GNUNET_CONFIGURATION_Handle *c)
364void 278void
365GCD_shutdown (void) 279GCD_shutdown (void)
366{ 280{
367 LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down DHT\n"); 281 if (NULL != dht_handle)
368 GNUNET_CONTAINER_multihashmap32_iterate (get_requests, &stop_get, NULL);
369 GNUNET_CONTAINER_multihashmap32_destroy (get_requests);
370 if (dht_handle != NULL)
371 { 282 {
372 GNUNET_DHT_disconnect (dht_handle); 283 GNUNET_DHT_disconnect (dht_handle);
373 dht_handle = NULL; 284 dht_handle = NULL;
@@ -379,22 +290,31 @@ GCD_shutdown (void)
379 } 290 }
380} 291}
381 292
293
294/**
295 * Search DHT for paths to @a peeR_id
296 *
297 * @param peer_id peer to search for
298 * @return handle to abort search
299 */
382struct GCD_search_handle * 300struct GCD_search_handle *
383GCD_search (const struct GNUNET_PeerIdentity *peer_id, 301GCD_search (const struct GNUNET_PeerIdentity *peer_id)
384 GCD_search_callback callback, void *cls)
385{ 302{
386 struct GNUNET_HashCode phash; 303 struct GNUNET_HashCode phash;
387 struct GCD_search_handle *h; 304 struct GCD_search_handle *h;
388 305
389 LOG (GNUNET_ERROR_TYPE_DEBUG, "Starting DHT GET for peer %s\n", 306 GNUNET_STATISTICS_update (stats,
390 GNUNET_i2s (peer_id)); 307 "# DHT search",
391 GNUNET_STATISTICS_update (stats, "# DHT search", 1, GNUNET_NO); 308 1,
392 memset (&phash, 0, sizeof (phash)); 309 GNUNET_NO);
393 GNUNET_memcpy (&phash, peer_id, sizeof (*peer_id)); 310 memset (&phash,
311 0,
312 sizeof (phash));
313 GNUNET_memcpy (&phash,
314 peer_id,
315 sizeof (*peer_id));
316
394 h = GNUNET_new (struct GCD_search_handle); 317 h = GNUNET_new (struct GCD_search_handle);
395 h->peer_id = GNUNET_PEER_intern (peer_id);
396 h->callback = callback;
397 h->cls = cls;
398 h->dhtget = GNUNET_DHT_get_start (dht_handle, /* handle */ 318 h->dhtget = GNUNET_DHT_get_start (dht_handle, /* handle */
399 GNUNET_BLOCK_TYPE_DHT_HELLO, /* type */ 319 GNUNET_BLOCK_TYPE_DHT_HELLO, /* type */
400 &phash, /* key to search */ 320 &phash, /* key to search */
@@ -405,20 +325,27 @@ GCD_search (const struct GNUNET_PeerIdentity *peer_id,
405 0, /* xquery bits */ 325 0, /* xquery bits */
406 &dht_get_id_handler, 326 &dht_get_id_handler,
407 h); 327 h);
408 GNUNET_CONTAINER_multihashmap32_put (get_requests, 328 LOG (GNUNET_ERROR_TYPE_DEBUG,
409 h->peer_id, 329 "Starting DHT GET for peer %s (%p)\n",
410 h, 330 GNUNET_i2s (peer_id),
411 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); 331 h);
412 return h; 332 return h;
413} 333}
414 334
415 335
336/**
337 * Stop DHT search started with #GCD_search().
338 *
339 * @param h handle to search to stop
340 */
416void 341void
417GCD_search_stop (struct GCD_search_handle *h) 342GCD_search_stop (struct GCD_search_handle *h)
418{ 343{
419 GNUNET_break (GNUNET_OK == 344 LOG (GNUNET_ERROR_TYPE_DEBUG,
420 GNUNET_CONTAINER_multihashmap32_remove (get_requests, 345 "Stopping DHT GET %p\n",
421 h->peer_id, h)); 346 h);
422 GNUNET_DHT_get_stop (h->dhtget); 347 GNUNET_DHT_get_stop (h->dhtget);
423 GNUNET_free (h); 348 GNUNET_free (h);
424} 349}
350
351/* end of gnunet-service-cadet_dht.c */
diff --git a/src/cadet/gnunet-service-cadet_dht.h b/src/cadet/gnunet-service-cadet_dht.h
index b70dfe975..5d7ab29a0 100644
--- a/src/cadet/gnunet-service-cadet_dht.h
+++ b/src/cadet/gnunet-service-cadet_dht.h
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 Copyright (C) 2013 GNUnet e.V. 3 Copyright (C) 2013, 2017 GNUnet e.V.
4 4
5 GNUnet is free software; you can redistribute it and/or modify 5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published 6 it under the terms of the GNU General Public License as published
@@ -22,10 +22,10 @@
22 * @file cadet/gnunet-service-cadet_dht.h 22 * @file cadet/gnunet-service-cadet_dht.h
23 * @brief cadet service; dealing with DHT requests and results 23 * @brief cadet service; dealing with DHT requests and results
24 * @author Bartlomiej Polot 24 * @author Bartlomiej Polot
25 * @author Christian Grothoff
25 * 26 *
26 * All functions in this file should use the prefix GMD (Gnunet Cadet Dht) 27 * All functions in this file should use the prefix GCD (Gnunet Cadet Dht)
27 */ 28 */
28
29#ifndef GNUNET_SERVICE_CADET_DHT_H 29#ifndef GNUNET_SERVICE_CADET_DHT_H
30#define GNUNET_SERVICE_CADET_DHT_H 30#define GNUNET_SERVICE_CADET_DHT_H
31 31
@@ -40,23 +40,11 @@ extern "C"
40#include "platform.h" 40#include "platform.h"
41#include "gnunet_util_lib.h" 41#include "gnunet_util_lib.h"
42 42
43struct GCD_search_handle;
44
45
46/** 43/**
47 * Callback called on each path found over the DHT. 44 * Handle for DHT search operation.
48 *
49 * @param cls Closure.
50 * @param path An unchecked, unoptimized path to the target node.
51 * After callback will no longer be valid!
52 */ 45 */
53typedef void 46struct GCD_search_handle;
54(*GCD_search_callback) (void *cls,
55 const struct CadetPeerPath *path);
56 47
57/******************************************************************************/
58/******************************** API ***********************************/
59/******************************************************************************/
60 48
61/** 49/**
62 * Initialize the DHT subsystem. 50 * Initialize the DHT subsystem.
@@ -66,6 +54,7 @@ typedef void
66void 54void
67GCD_init (const struct GNUNET_CONFIGURATION_Handle *c); 55GCD_init (const struct GNUNET_CONFIGURATION_Handle *c);
68 56
57
69/** 58/**
70 * Shut down the DHT subsystem. 59 * Shut down the DHT subsystem.
71 */ 60 */
@@ -73,14 +62,32 @@ void
73GCD_shutdown (void); 62GCD_shutdown (void);
74 63
75 64
65/**
66 * Function called by the HELLO subsystem whenever OUR hello
67 * changes. Re-triggers the DHT PUT immediately.
68 */
69void
70GCD_hello_update (void);
71
72/**
73 * Search DHT for paths to @a peeR_id
74 *
75 * @param peer_id peer to search for
76 * @return handle to abort search
77 */
76struct GCD_search_handle * 78struct GCD_search_handle *
77GCD_search (const struct GNUNET_PeerIdentity *peer_id, 79GCD_search (const struct GNUNET_PeerIdentity *peer_id);
78 GCD_search_callback callback, void *cls);
79 80
80 81
82/**
83 * Stop DHT search started with #GCD_search().
84 *
85 * @param h handle to search to stop
86 */
81void 87void
82GCD_search_stop (struct GCD_search_handle *h); 88GCD_search_stop (struct GCD_search_handle *h);
83 89
90
84#if 0 /* keep Emacsens' auto-indent happy */ 91#if 0 /* keep Emacsens' auto-indent happy */
85{ 92{
86#endif 93#endif
@@ -88,6 +95,6 @@ GCD_search_stop (struct GCD_search_handle *h);
88} 95}
89#endif 96#endif
90 97
91/* ifndef GNUNET_CADET_SERVICE_LOCAL_H */ 98/* ifndef GNUNET_CADET_SERVICE_DHT_H */
92#endif 99#endif
93/* end of gnunet-cadet-service_LOCAL.h */ 100/* end of gnunet-service-cadet_dht.h */
diff --git a/src/cadet/gnunet-service-cadet_hello.c b/src/cadet/gnunet-service-cadet_hello.c
index 3c63f3551..6d85de39f 100644
--- a/src/cadet/gnunet-service-cadet_hello.c
+++ b/src/cadet/gnunet-service-cadet_hello.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 Copyright (C) 2014 GNUnet e.V. 3 Copyright (C) 2014, 2017 GNUnet e.V.
4 4
5 GNUnet is free software; you can redistribute it and/or modify 5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published 6 it under the terms of the GNU General Public License as published
@@ -17,58 +17,33 @@
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA. 18 Boston, MA 02110-1301, USA.
19*/ 19*/
20 20/**
21 * @file cadet/gnunet-service-cadet_hello.c
22 * @brief spread knowledge about how to contact other peers from PEERINFO
23 * @author Bartlomiej Polot
24 * @author Christian Grothoff
25 *
26 * TODO:
27 * - is most of this necessary/helpful?
28 * - should we not simply restrict this to OUR hello?
29 */
21#include "platform.h" 30#include "platform.h"
22#include "gnunet_util_lib.h" 31#include "gnunet_util_lib.h"
23 32
24#include "gnunet_statistics_service.h" 33#include "gnunet_statistics_service.h"
25#include "gnunet_peerinfo_service.h" 34#include "gnunet_peerinfo_service.h"
26
27#include "cadet_protocol.h" 35#include "cadet_protocol.h"
28#include "cadet_path.h" 36#include "gnunet-service-cadet.h"
29 37#include "gnunet-service-cadet_dht.h"
30#include "gnunet-service-cadet_hello.h" 38#include "gnunet-service-cadet_hello.h"
31#include "gnunet-service-cadet_peer.h" 39#include "gnunet-service-cadet_peer.h"
32 40
33#define LOG(level, ...) GNUNET_log_from(level,"cadet-hll",__VA_ARGS__) 41#define LOG(level, ...) GNUNET_log_from(level,"cadet-hll",__VA_ARGS__)
34 42
35
36/******************************************************************************/
37/******************************** STRUCTS **********************************/
38/******************************************************************************/
39
40
41
42/******************************************************************************/
43/******************************* GLOBALS ***********************************/
44/******************************************************************************/
45
46/**
47 * Global handle to the statistics service.
48 */
49extern struct GNUNET_STATISTICS_Handle *stats;
50
51/**
52 * Local peer own ID (memory efficient handle).
53 */
54extern GNUNET_PEER_Id myid;
55
56/**
57 * Local peer own ID (full value).
58 */
59extern struct GNUNET_PeerIdentity my_full_id;
60
61
62/**
63 * Don't try to recover tunnels if shutting down.
64 */
65extern int shutting_down;
66
67
68/** 43/**
69 * Hello message of local peer. 44 * Hello message of local peer.
70 */ 45 */
71const struct GNUNET_HELLO_Message *mine; 46static struct GNUNET_HELLO_Message *mine;
72 47
73/** 48/**
74 * Handle to peerinfo service. 49 * Handle to peerinfo service.
@@ -78,13 +53,9 @@ static struct GNUNET_PEERINFO_Handle *peerinfo;
78/** 53/**
79 * Iterator context. 54 * Iterator context.
80 */ 55 */
81struct GNUNET_PEERINFO_NotifyContext* nc; 56static struct GNUNET_PEERINFO_NotifyContext *nc;
82 57
83 58
84/******************************************************************************/
85/******************************** STATIC ***********************************/
86/******************************************************************************/
87
88/** 59/**
89 * Process each hello message received from peerinfo. 60 * Process each hello message received from peerinfo.
90 * 61 *
@@ -94,31 +65,37 @@ struct GNUNET_PEERINFO_NotifyContext* nc;
94 * @param err_msg Error message. 65 * @param err_msg Error message.
95 */ 66 */
96static void 67static void
97got_hello (void *cls, const struct GNUNET_PeerIdentity *id, 68got_hello (void *cls,
69 const struct GNUNET_PeerIdentity *id,
98 const struct GNUNET_HELLO_Message *hello, 70 const struct GNUNET_HELLO_Message *hello,
99 const char *err_msg) 71 const char *err_msg)
100{ 72{
101 struct CadetPeer *peer; 73 struct CadetPeer *peer;
102 74
103 if (NULL == id || NULL == hello) 75 if ( (NULL == id) ||
76 (NULL == hello) )
77 return;
78 if (0 == memcmp (id,
79 &my_full_id,
80 sizeof (struct GNUNET_PeerIdentity)))
104 { 81 {
105 LOG (GNUNET_ERROR_TYPE_DEBUG, " hello with id %p and msg %p\n", id, hello); 82 GNUNET_free_non_null (mine);
83 mine = (struct GNUNET_HELLO_Message *) GNUNET_copy_message (&hello->header);
84 GCD_hello_update ();
106 return; 85 return;
107 } 86 }
108 LOG (GNUNET_ERROR_TYPE_DEBUG, " hello for %s (%d bytes), expires on %s\n",
109 GNUNET_i2s (id), GNUNET_HELLO_size (hello),
110 GNUNET_STRINGS_absolute_time_to_string (GNUNET_HELLO_get_last_expiration(hello)));
111 peer = GCP_get (id, GNUNET_YES);
112 GCP_set_hello (peer, hello);
113
114 if (GCP_get_short_id (peer) == myid)
115 mine = GCP_get_hello (peer);
116}
117 87
88 LOG (GNUNET_ERROR_TYPE_DEBUG,
89 "Hello for %s (%d bytes), expires on %s\n",
90 GNUNET_i2s (id),
91 GNUNET_HELLO_size (hello),
92 GNUNET_STRINGS_absolute_time_to_string (GNUNET_HELLO_get_last_expiration (hello)));
93 peer = GCP_get (id,
94 GNUNET_YES);
95 GCP_set_hello (peer,
96 hello);
97}
118 98
119/******************************************************************************/
120/******************************** API ***********************************/
121/******************************************************************************/
122 99
123/** 100/**
124 * Initialize the hello subsystem. 101 * Initialize the hello subsystem.
@@ -128,10 +105,12 @@ got_hello (void *cls, const struct GNUNET_PeerIdentity *id,
128void 105void
129GCH_init (const struct GNUNET_CONFIGURATION_Handle *c) 106GCH_init (const struct GNUNET_CONFIGURATION_Handle *c)
130{ 107{
131 LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n");
132 GNUNET_assert (NULL == nc); 108 GNUNET_assert (NULL == nc);
133 peerinfo = GNUNET_PEERINFO_connect (c); 109 peerinfo = GNUNET_PEERINFO_connect (c);
134 nc = GNUNET_PEERINFO_notify (c, GNUNET_NO, &got_hello, NULL); 110 nc = GNUNET_PEERINFO_notify (c,
111 GNUNET_NO,
112 &got_hello,
113 NULL);
135} 114}
136 115
137 116
@@ -141,7 +120,6 @@ GCH_init (const struct GNUNET_CONFIGURATION_Handle *c)
141void 120void
142GCH_shutdown () 121GCH_shutdown ()
143{ 122{
144 LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down channels\n");
145 if (NULL != nc) 123 if (NULL != nc)
146 { 124 {
147 GNUNET_PEERINFO_notify_cancel (nc); 125 GNUNET_PEERINFO_notify_cancel (nc);
@@ -152,6 +130,11 @@ GCH_shutdown ()
152 GNUNET_PEERINFO_disconnect (peerinfo); 130 GNUNET_PEERINFO_disconnect (peerinfo);
153 peerinfo = NULL; 131 peerinfo = NULL;
154 } 132 }
133 if (NULL != mine)
134 {
135 GNUNET_free (mine);
136 mine = NULL;
137 }
155} 138}
156 139
157 140
@@ -166,35 +149,4 @@ GCH_get_mine (void)
166 return mine; 149 return mine;
167} 150}
168 151
169 152/* end of gnunet-service-cadet-new_hello.c */
170/**
171 * Get another peer's hello message.
172 *
173 * @param id ID of the peer whose hello message is requested.
174 *
175 * @return Hello message, if any (NULL possible).
176 */
177const struct GNUNET_HELLO_Message *
178GCH_get (const struct GNUNET_PeerIdentity *id)
179{
180 struct CadetPeer *p;
181
182 p = GCP_get (id, GNUNET_NO);
183 if (NULL == p)
184 return NULL;
185 return GCP_get_hello (p);
186}
187
188
189/**
190 * Convert a hello message to a string.
191 *
192 * @param h Hello message.
193 */
194char *
195GCH_2s (const struct GNUNET_HELLO_Message *h)
196{
197 return "hello (TODO)";
198}
199
200
diff --git a/src/cadet/gnunet-service-cadet_hello.h b/src/cadet/gnunet-service-cadet_hello.h
index 34121e1e0..4291ae985 100644
--- a/src/cadet/gnunet-service-cadet_hello.h
+++ b/src/cadet/gnunet-service-cadet_hello.h
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 Copyright (C) 2014 GNUnet e.V. 3 Copyright (C) 2014, 2017 GNUnet e.V.
4 4
5 GNUnet is free software; you can redistribute it and/or modify 5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published 6 it under the terms of the GNU General Public License as published
@@ -22,8 +22,9 @@
22 * @file cadet/gnunet-service-cadet_hello.h 22 * @file cadet/gnunet-service-cadet_hello.h
23 * @brief cadet service; dealing with hello messages 23 * @brief cadet service; dealing with hello messages
24 * @author Bartlomiej Polot 24 * @author Bartlomiej Polot
25 * @author Christian Grothoff
25 * 26 *
26 * All functions in this file should use the prefix GMH (Gnunet Cadet Hello) 27 * All functions in this file should use the prefix GCH (Gnunet Cadet Hello)
27 */ 28 */
28 29
29#ifndef GNUNET_SERVICE_CADET_HELLO_H 30#ifndef GNUNET_SERVICE_CADET_HELLO_H
diff --git a/src/cadet/gnunet-service-cadet_local.c b/src/cadet/gnunet-service-cadet_local.c
deleted file mode 100644
index dea6681df..000000000
--- a/src/cadet/gnunet-service-cadet_local.c
+++ /dev/null
@@ -1,1553 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2013 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21
22#include "platform.h"
23#include "gnunet_util_lib.h"
24
25#include "gnunet_statistics_service.h"
26
27#include "cadet.h"
28#include "cadet_protocol.h" /* GNUNET_CADET_Data is shared */
29
30#include "gnunet-service-cadet_local.h"
31#include "gnunet-service-cadet_channel.h"
32
33/* INFO DEBUG */
34#include "gnunet-service-cadet_tunnel.h"
35#include "gnunet-service-cadet_peer.h"
36
37#define LOG(level, ...) GNUNET_log_from(level,"cadet-loc",__VA_ARGS__)
38
39/******************************************************************************/
40/******************************** STRUCTS **********************************/
41/******************************************************************************/
42
43/**
44 * Struct containing information about a client of the service
45 *
46 * TODO: add a list of 'waiting' ports
47 */
48struct CadetClient
49{
50 /**
51 * Linked list next
52 */
53 struct CadetClient *next;
54
55 /**
56 * Linked list prev
57 */
58 struct CadetClient *prev;
59
60 /**
61 * Tunnels that belong to this client, indexed by local id
62 */
63 struct GNUNET_CONTAINER_MultiHashMap32 *own_channels;
64
65 /**
66 * Tunnels this client has accepted, indexed by incoming local id
67 */
68 struct GNUNET_CONTAINER_MultiHashMap32 *incoming_channels;
69
70 /**
71 * Channel ID for the next incoming channel.
72 */
73 struct GNUNET_CADET_ClientChannelNumber next_ccn;
74
75 /**
76 * Handle to communicate with the client
77 */
78 struct GNUNET_SERVER_Client *handle;
79
80 /**
81 * Ports that this client has declared interest in.
82 * Indexed by port, contains *Client.
83 */
84 struct GNUNET_CONTAINER_MultiHashMap *ports;
85
86 /**
87 * Whether the client is active or shutting down (don't send confirmations
88 * to a client that is shutting down.
89 */
90 int shutting_down;
91
92 /**
93 * ID of the client, mainly for debug messages
94 */
95 unsigned int id;
96};
97
98/******************************************************************************/
99/******************************* GLOBALS ***********************************/
100/******************************************************************************/
101
102/**
103 * Global handle to the statistics service.
104 */
105extern struct GNUNET_STATISTICS_Handle *stats;
106
107/**
108 * Handle to server lib.
109 */
110static struct GNUNET_SERVER_Handle *server_handle;
111
112/**
113 * DLL with all the clients, head.
114 */
115static struct CadetClient *clients_head;
116
117/**
118 * DLL with all the clients, tail.
119 */
120static struct CadetClient *clients_tail;
121
122/**
123 * Next ID to assign to a client.
124 */
125unsigned int next_client_id;
126
127/**
128 * All ports clients of this peer have opened.
129 */
130static struct GNUNET_CONTAINER_MultiHashMap *ports;
131
132/**
133 * Notification context, to send messages to local clients.
134 */
135static struct GNUNET_SERVER_NotificationContext *nc;
136
137
138/******************************************************************************/
139/******************************** STATIC ***********************************/
140/******************************************************************************/
141
142/**
143 * Remove client's ports from the global hashmap on disconnect.
144 *
145 * @param cls Closure (unused).
146 * @param key Port.
147 * @param value Client structure.
148 *
149 * @return #GNUNET_OK, keep iterating.
150 */
151static int
152client_release_ports (void *cls,
153 const struct GNUNET_HashCode *key,
154 void *value)
155{
156 int res;
157
158 res = GNUNET_CONTAINER_multihashmap_remove (ports, key, value);
159 if (GNUNET_YES != res)
160 {
161 GNUNET_break (0);
162 LOG (GNUNET_ERROR_TYPE_WARNING,
163 "Port %s by client %p was not registered.\n",
164 GNUNET_h2s (key), value);
165 }
166 return GNUNET_OK;
167}
168
169
170/**
171 * Iterator for deleting each channel whose client endpoint disconnected.
172 *
173 * @param cls Closure (client that has disconnected).
174 * @param key The local channel id (used to access the hashmap).
175 * @param value The value stored at the key (channel to destroy).
176 *
177 * @return #GNUNET_OK, keep iterating.
178 */
179static int
180channel_destroy_iterator (void *cls,
181 uint32_t key,
182 void *value)
183{
184 struct CadetChannel *ch = value;
185 struct CadetClient *c = cls;
186
187 LOG (GNUNET_ERROR_TYPE_DEBUG,
188 " Channel %s destroy, due to client %s shutdown.\n",
189 GCCH_2s (ch), GML_2s (c));
190
191 GCCH_handle_local_destroy (ch,
192 c,
193 key < GNUNET_CADET_LOCAL_CHANNEL_ID_CLI);
194 return GNUNET_OK;
195}
196
197
198/**
199 * Unregister data and free memory for a client.
200 *
201 * @param c Client to destroy. No longer valid after call.
202 */
203static void
204client_destroy (struct CadetClient *c)
205{
206 LOG (GNUNET_ERROR_TYPE_DEBUG, " client destroy: %p/%u\n", c, c->id);
207 GNUNET_SERVER_client_drop (c->handle);
208 c->shutting_down = GNUNET_YES;
209
210 if (NULL != c->own_channels)
211 {
212 GNUNET_CONTAINER_multihashmap32_iterate (c->own_channels,
213 &channel_destroy_iterator, c);
214 GNUNET_CONTAINER_multihashmap32_destroy (c->own_channels);
215 }
216 if (NULL != c->incoming_channels)
217 {
218 GNUNET_CONTAINER_multihashmap32_iterate (c->incoming_channels,
219 &channel_destroy_iterator, c);
220 GNUNET_CONTAINER_multihashmap32_destroy (c->incoming_channels);
221 }
222 if (NULL != c->ports)
223 {
224 GNUNET_CONTAINER_multihashmap_iterate (c->ports,
225 &client_release_ports, c);
226 GNUNET_CONTAINER_multihashmap_destroy (c->ports);
227 }
228
229 GNUNET_CONTAINER_DLL_remove (clients_head, clients_tail, c);
230 GNUNET_STATISTICS_update (stats, "# clients", -1, GNUNET_NO);
231 GNUNET_SERVER_client_set_user_context (c->handle, NULL);
232 GNUNET_free (c);
233}
234
235
236/**
237 * Create a client record, register data and initialize memory.
238 *
239 * @param client Client's handle.
240 */
241static struct CadetClient *
242client_new (struct GNUNET_SERVER_Client *client)
243{
244 struct CadetClient *c;
245
246 GNUNET_SERVER_client_keep (client);
247 GNUNET_SERVER_notification_context_add (nc, client);
248
249 c = GNUNET_new (struct CadetClient);
250 c->handle = client;
251 c->id = next_client_id++; /* overflow not important: just for debug */
252
253 c->own_channels = GNUNET_CONTAINER_multihashmap32_create (32);
254 c->incoming_channels = GNUNET_CONTAINER_multihashmap32_create (32);
255
256 GNUNET_SERVER_client_set_user_context (client, c);
257 GNUNET_CONTAINER_DLL_insert (clients_head, clients_tail, c);
258 GNUNET_STATISTICS_update (stats, "# clients", +1, GNUNET_NO);
259
260 LOG (GNUNET_ERROR_TYPE_DEBUG, " client created: %p/%u\n", c, c->id);
261
262 return c;
263}
264
265
266/******************************************************************************/
267/******************************** HANDLES ***********************************/
268/******************************************************************************/
269
270/**
271 * Handler for client connection.
272 *
273 * @param cls Closure (unused).
274 * @param client Client handler.
275 */
276static void
277handle_client_connect (void *cls, struct GNUNET_SERVER_Client *client)
278{
279 LOG (GNUNET_ERROR_TYPE_DEBUG, "Client connected: %p\n", client);
280 if (NULL == client)
281 return;
282
283 (void) client_new (client);
284}
285
286
287/**
288 * Handler for client disconnection
289 *
290 * @param cls closure
291 * @param client identification of the client; NULL
292 * for the last call when the server is destroyed
293 */
294static void
295handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
296{
297 struct CadetClient *c;
298
299 LOG (GNUNET_ERROR_TYPE_DEBUG, "Client disconnected: %p\n", client);
300
301 c = GML_client_get (client);
302 if (NULL != c)
303 {
304 LOG (GNUNET_ERROR_TYPE_DEBUG, "matching client found (%u, %p)\n",
305 c->id, c);
306 client_destroy (c);
307 }
308 else
309 {
310 LOG (GNUNET_ERROR_TYPE_DEBUG, " disconnecting client's context NULL\n");
311 }
312 return;
313}
314
315
316/**
317 * Handler for port open requests.
318 *
319 * @param cls Closure.
320 * @param client Identification of the client.
321 * @param message The actual message.
322 */
323static void
324handle_port_open (void *cls, struct GNUNET_SERVER_Client *client,
325 const struct GNUNET_MessageHeader *message)
326{
327 struct CadetClient *c;
328 struct GNUNET_CADET_PortMessage *pmsg;
329
330 LOG (GNUNET_ERROR_TYPE_DEBUG, "open port requested\n");
331
332 /* Sanity check for client registration */
333 if (NULL == (c = GML_client_get (client)))
334 {
335 GNUNET_break (0);
336 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
337 return;
338 }
339 LOG (GNUNET_ERROR_TYPE_DEBUG, " by client %u\n", c->id);
340
341 /* Message size sanity check */
342 if (sizeof (struct GNUNET_CADET_PortMessage) != ntohs (message->size))
343 {
344 GNUNET_break (0);
345 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
346 return;
347 }
348
349 pmsg = (struct GNUNET_CADET_PortMessage *) message;
350 if (NULL == c->ports)
351 {
352 c->ports = GNUNET_CONTAINER_multihashmap_create (4, GNUNET_NO);
353 }
354 /* store in client's hashmap */
355 if (GNUNET_OK !=
356 GNUNET_CONTAINER_multihashmap_put (c->ports, &pmsg->port, c,
357 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
358 {
359 GNUNET_break (0);
360 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
361 return;
362 }
363 /* store in global hashmap */
364 /* FIXME only allow one client to have the port open,
365 * have a backup hashmap with waiting clients */
366 GNUNET_CONTAINER_multihashmap_put (ports, &pmsg->port, c,
367 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
368
369 GNUNET_SERVER_receive_done (client, GNUNET_OK);
370}
371
372
373/**
374 * Handler for port close requests.
375 *
376 * @param cls Closure.
377 * @param client Identification of the client.
378 * @param message The actual message.
379 */
380static void
381handle_port_close (void *cls, struct GNUNET_SERVER_Client *client,
382 const struct GNUNET_MessageHeader *message)
383{
384 struct CadetClient *c;
385 struct GNUNET_CADET_PortMessage *pmsg;
386 int removed;
387
388 LOG (GNUNET_ERROR_TYPE_DEBUG, "close port requested\n");
389
390 /* Sanity check for client registration */
391 if (NULL == (c = GML_client_get (client)))
392 {
393 GNUNET_break (0);
394 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
395 return;
396 }
397 LOG (GNUNET_ERROR_TYPE_DEBUG, " by client %u\n", c->id);
398
399 /* Message size sanity check */
400 if (sizeof (struct GNUNET_CADET_PortMessage) != ntohs (message->size))
401 {
402 GNUNET_break (0);
403 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
404 return;
405 }
406
407 pmsg = (struct GNUNET_CADET_PortMessage *) message;
408 removed = GNUNET_CONTAINER_multihashmap_remove (c->ports, &pmsg->port, c);
409 GNUNET_break_op (GNUNET_YES == removed);
410 removed = GNUNET_CONTAINER_multihashmap_remove (ports, &pmsg->port, c);
411 GNUNET_break_op (GNUNET_YES == removed);
412
413 GNUNET_SERVER_receive_done (client, GNUNET_OK);
414}
415
416
417/**
418 * Handler for requests of new channels.
419 *
420 * @param cls Closure.
421 * @param client Identification of the client.
422 * @param message The actual message.
423 */
424static void
425handle_channel_create (void *cls, struct GNUNET_SERVER_Client *client,
426 const struct GNUNET_MessageHeader *message)
427{
428 struct CadetClient *c;
429
430 LOG (GNUNET_ERROR_TYPE_DEBUG, "\n");
431 LOG (GNUNET_ERROR_TYPE_DEBUG, "new channel requested\n");
432
433 /* Sanity check for client registration */
434 if (NULL == (c = GML_client_get (client)))
435 {
436 GNUNET_break (0);
437 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
438 return;
439 }
440 LOG (GNUNET_ERROR_TYPE_DEBUG, " by client %u\n", c->id);
441
442 /* Message size sanity check */
443 if (sizeof (struct GNUNET_CADET_LocalChannelCreateMessage)
444 != ntohs (message->size))
445 {
446 GNUNET_break (0);
447 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
448 return;
449 }
450
451 if (GNUNET_OK !=
452 GCCH_handle_local_create (c,
453 (struct GNUNET_CADET_LocalChannelCreateMessage *)
454 message))
455 {
456 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
457 return;
458 }
459
460 GNUNET_SERVER_receive_done (client, GNUNET_OK);
461}
462
463
464/**
465 * Handler for requests of deleting tunnels
466 *
467 * @param cls closure
468 * @param client identification of the client
469 * @param message the actual message
470 */
471static void
472handle_channel_destroy (void *cls, struct GNUNET_SERVER_Client *client,
473 const struct GNUNET_MessageHeader *message)
474{
475 const struct GNUNET_CADET_LocalChannelDestroyMessage *msg;
476 struct CadetClient *c;
477 struct CadetChannel *ch;
478 struct GNUNET_CADET_ClientChannelNumber ccn;
479
480 LOG (GNUNET_ERROR_TYPE_DEBUG, "Got a DESTROY CHANNEL from client!\n");
481
482 /* Sanity check for client registration */
483 if (NULL == (c = GML_client_get (client)))
484 {
485 GNUNET_break (0);
486 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
487 return;
488 }
489 LOG (GNUNET_ERROR_TYPE_DEBUG, " by client %u\n", c->id);
490
491 /* Message sanity check */
492 if (sizeof (struct GNUNET_CADET_LocalChannelDestroyMessage)
493 != ntohs (message->size))
494 {
495 GNUNET_break (0);
496 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
497 return;
498 }
499
500 msg = (const struct GNUNET_CADET_LocalChannelDestroyMessage *) message;
501
502 /* Retrieve tunnel */
503 ccn = msg->ccn;
504 ch = GML_channel_get (c, ccn);
505
506 LOG (GNUNET_ERROR_TYPE_INFO, "Client %u is destroying channel %X\n",
507 c->id, ccn);
508
509 if (NULL == ch)
510 {
511 LOG (GNUNET_ERROR_TYPE_WARNING, " channel %X not found\n", ccn);
512 GNUNET_STATISTICS_update (stats,
513 "# client destroy messages on unknown channel",
514 1, GNUNET_NO);
515 GNUNET_SERVER_receive_done (client, GNUNET_OK);
516 return;
517 }
518
519 GCCH_handle_local_destroy (ch,
520 c,
521 ntohl (ccn.channel_of_client) < GNUNET_CADET_LOCAL_CHANNEL_ID_CLI);
522
523 GNUNET_SERVER_receive_done (client, GNUNET_OK);
524}
525
526
527/**
528 * Handler for client traffic
529 *
530 * @param cls closure
531 * @param client identification of the client
532 * @param message the actual message
533 */
534static void
535handle_data (void *cls, struct GNUNET_SERVER_Client *client,
536 const struct GNUNET_MessageHeader *message)
537{
538 const struct GNUNET_MessageHeader *payload;
539 struct GNUNET_CADET_LocalData *msg;
540 struct CadetClient *c;
541 struct CadetChannel *ch;
542 struct GNUNET_CADET_ClientChannelNumber ccn;
543 size_t message_size;
544 size_t payload_size;
545 size_t payload_claimed_size;
546 int fwd;
547
548 LOG (GNUNET_ERROR_TYPE_DEBUG, "\n");
549 LOG (GNUNET_ERROR_TYPE_DEBUG, "\n");
550 LOG (GNUNET_ERROR_TYPE_DEBUG, "Got data from a client\n");
551
552 /* Sanity check for client registration */
553 if (NULL == (c = GML_client_get (client)))
554 {
555 GNUNET_break (0);
556 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
557 return;
558 }
559
560 /* Sanity check for message size */
561 message_size = ntohs (message->size);
562 if (sizeof (struct GNUNET_CADET_LocalData)
563 + sizeof (struct GNUNET_MessageHeader) > message_size
564 || GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE < message_size)
565 {
566 GNUNET_break (0);
567 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
568 return;
569 }
570
571 /* Sanity check for payload size */
572 payload_size = message_size - sizeof (struct GNUNET_CADET_LocalData);
573 msg = (struct GNUNET_CADET_LocalData *) message;
574 payload = (struct GNUNET_MessageHeader *) &msg[1];
575 payload_claimed_size = ntohs (payload->size);
576 if (sizeof (struct GNUNET_MessageHeader) > payload_claimed_size
577 || GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE < payload_claimed_size
578 || payload_claimed_size > payload_size)
579 {
580 LOG (GNUNET_ERROR_TYPE_WARNING,
581 "client claims to send %u bytes in %u payload\n",
582 payload_claimed_size, payload_size);
583 GNUNET_break (0);
584 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
585 return;
586 }
587
588 ccn = msg->ccn;
589 LOG (GNUNET_ERROR_TYPE_DEBUG, " %u bytes (%u payload) by client %u\n",
590 payload_size, payload_claimed_size, c->id);
591
592 /* Channel exists? */
593 fwd = ntohl (ccn.channel_of_client) >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI;
594 ch = GML_channel_get (c, ccn);
595 if (NULL == ch)
596 {
597 GNUNET_STATISTICS_update (stats,
598 "# client data messages on unknown channel",
599 1, GNUNET_NO);
600 GNUNET_SERVER_receive_done (client, GNUNET_OK);
601 return;
602 }
603
604 if (GNUNET_OK != GCCH_handle_local_data (ch, c, fwd, payload, payload_size))
605 {
606 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
607 return;
608 }
609
610 LOG (GNUNET_ERROR_TYPE_DEBUG, "receive done OK\n");
611 GNUNET_SERVER_receive_done (client, GNUNET_OK);
612
613 return;
614}
615
616
617/**
618 * Handler for client's ACKs for payload traffic.
619 *
620 * @param cls Closure (unused).
621 * @param client Identification of the client.
622 * @param message The actual message.
623 */
624static void
625handle_ack (void *cls, struct GNUNET_SERVER_Client *client,
626 const struct GNUNET_MessageHeader *message)
627{
628 struct GNUNET_CADET_LocalAck *msg;
629 struct CadetChannel *ch;
630 struct CadetClient *c;
631 struct GNUNET_CADET_ClientChannelNumber ccn;
632 int fwd;
633
634 LOG (GNUNET_ERROR_TYPE_DEBUG, "\n");
635 LOG (GNUNET_ERROR_TYPE_DEBUG, "Got a local ACK\n");
636
637 /* Sanity check for client registration */
638 if (NULL == (c = GML_client_get (client)))
639 {
640 GNUNET_break (0);
641 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
642 return;
643 }
644 LOG (GNUNET_ERROR_TYPE_DEBUG, " by client %u\n", c->id);
645
646 msg = (struct GNUNET_CADET_LocalAck *) message;
647
648 /* Channel exists? */
649 ccn = msg->ccn;
650 LOG (GNUNET_ERROR_TYPE_DEBUG, " on channel %X\n",
651 ntohl (ccn.channel_of_client));
652 ch = GML_channel_get (c, ccn);
653 LOG (GNUNET_ERROR_TYPE_DEBUG, " -- ch %p\n", ch);
654 if (NULL == ch)
655 {
656 LOG (GNUNET_ERROR_TYPE_DEBUG,
657 "Channel %X unknown.\n",
658 ntohl (ccn.channel_of_client));
659 LOG (GNUNET_ERROR_TYPE_DEBUG, " for client %u.\n", c->id);
660 GNUNET_STATISTICS_update (stats,
661 "# client ack messages on unknown channel",
662 1, GNUNET_NO);
663 GNUNET_SERVER_receive_done (client, GNUNET_OK);
664 return;
665 }
666
667 /* If client is root, the ACK is going FWD, therefore this is "BCK ACK". */
668 /* If client is dest, the ACK is going BCK, therefore this is "FWD ACK" */
669 fwd = ntohl (ccn.channel_of_client) < GNUNET_CADET_LOCAL_CHANNEL_ID_CLI;
670
671 GCCH_handle_local_ack (ch, fwd);
672 GNUNET_SERVER_receive_done (client, GNUNET_OK);
673}
674
675
676/**
677 * Iterator over all peers to send a monitoring client info about each peer.
678 *
679 * @param cls Closure ().
680 * @param peer Peer ID (tunnel remote peer).
681 * @param value Peer info.
682 *
683 * @return #GNUNET_YES, to keep iterating.
684 */
685static int
686get_all_peers_iterator (void *cls,
687 const struct GNUNET_PeerIdentity * peer,
688 void *value)
689{
690 struct GNUNET_SERVER_Client *client = cls;
691 struct CadetPeer *p = value;
692 struct GNUNET_CADET_LocalInfoPeer msg;
693
694 msg.header.size = htons (sizeof (msg));
695 msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS);
696 msg.destination = *peer;
697 msg.paths = htons (GCP_count_paths (p));
698 msg.tunnel = htons (NULL != GCP_get_tunnel (p));
699
700 LOG (GNUNET_ERROR_TYPE_DEBUG, "sending info about peer %s\n",
701 GNUNET_i2s (peer));
702
703 GNUNET_SERVER_notification_context_unicast (nc, client,
704 &msg.header, GNUNET_NO);
705 return GNUNET_YES;
706}
707
708
709/**
710 * Iterator over all peers to dump info for each peer.
711 *
712 * @param cls Closure (unused).
713 * @param peer Peer ID (tunnel remote peer).
714 * @param value Peer info.
715 *
716 * @return #GNUNET_YES, to keep iterating.
717 */
718static int
719show_peer_iterator (void *cls,
720 const struct GNUNET_PeerIdentity * peer,
721 void *value)
722{
723 struct CadetPeer *p = value;
724 struct CadetTunnel *t;
725
726 t = GCP_get_tunnel (p);
727 if (NULL != t)
728 GCT_debug (t, GNUNET_ERROR_TYPE_ERROR);
729
730 LOG (GNUNET_ERROR_TYPE_ERROR, "\n");
731
732 return GNUNET_YES;
733}
734
735
736/**
737 * Iterator over all paths of a peer to build an InfoPeer message.
738 *
739 * Message contains blocks of peers, first not included.
740 *
741 * @param cls Closure (message to build).
742 * @param peer Peer this path is towards.
743 * @param path Path itself
744 * @return #GNUNET_YES if should keep iterating.
745 * #GNUNET_NO otherwise.
746 */
747static int
748path_info_iterator (void *cls,
749 struct CadetPeer *peer,
750 struct CadetPeerPath *path)
751{
752 struct GNUNET_CADET_LocalInfoPeer *resp = cls;
753 struct GNUNET_PeerIdentity *id;
754 uint16_t msg_size;
755 uint16_t path_size;
756 unsigned int i;
757
758 msg_size = ntohs (resp->header.size);
759 path_size = sizeof (struct GNUNET_PeerIdentity) * (path->length - 1);
760
761 LOG (GNUNET_ERROR_TYPE_DEBUG, "Info Path %u\n", path->length);
762 if (msg_size + path_size > UINT16_MAX)
763 {
764 LOG (GNUNET_ERROR_TYPE_WARNING, "path too long for info message\n");
765 return GNUNET_NO;
766 }
767
768 i = msg_size - sizeof (struct GNUNET_CADET_LocalInfoPeer);
769 i = i / sizeof (struct GNUNET_PeerIdentity);
770
771 /* Set id to the address of the first free peer slot. */
772 id = (struct GNUNET_PeerIdentity *) &resp[1];
773 id = &id[i];
774
775 /* Don't copy first peers.
776 * First peer is always the local one.
777 * Last peer is always the destination (leave as 0, EOL).
778 */
779 for (i = 0; i < path->length - 1; i++)
780 {
781 GNUNET_PEER_resolve (path->peers[i + 1], &id[i]);
782 LOG (GNUNET_ERROR_TYPE_DEBUG, " %s\n", GNUNET_i2s (&id[i]));
783 }
784
785 resp->header.size = htons (msg_size + path_size);
786
787 return GNUNET_YES;
788}
789
790
791/**
792 * Handler for client's INFO PEERS request.
793 *
794 * @param cls Closure (unused).
795 * @param client Identification of the client.
796 * @param message The actual message.
797 */
798static void
799handle_get_peers (void *cls, struct GNUNET_SERVER_Client *client,
800 const struct GNUNET_MessageHeader *message)
801{
802 struct CadetClient *c;
803 struct GNUNET_MessageHeader reply;
804
805 /* Sanity check for client registration */
806 if (NULL == (c = GML_client_get (client)))
807 {
808 GNUNET_break (0);
809 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
810 return;
811 }
812
813 LOG (GNUNET_ERROR_TYPE_DEBUG,
814 "Received get peers request from client %u (%p)\n",
815 c->id, client);
816
817 GCP_iterate_all (get_all_peers_iterator, client);
818 reply.size = htons (sizeof (reply));
819 reply.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS);
820 GNUNET_SERVER_notification_context_unicast (nc, client, &reply, GNUNET_NO);
821
822 LOG (GNUNET_ERROR_TYPE_DEBUG,
823 "Get peers request from client %u completed\n", c->id);
824 GNUNET_SERVER_receive_done (client, GNUNET_OK);
825}
826
827
828/**
829 * Handler for client's SHOW_PEER request.
830 *
831 * @param cls Closure (unused).
832 * @param client Identification of the client.
833 * @param message The actual message.
834 */
835void
836handle_show_peer (void *cls, struct GNUNET_SERVER_Client *client,
837 const struct GNUNET_MessageHeader *message)
838{
839 const struct GNUNET_CADET_LocalInfo *msg;
840 struct GNUNET_CADET_LocalInfoPeer *resp;
841 struct CadetPeer *p;
842 struct CadetClient *c;
843 unsigned char cbuf[64 * 1024];
844
845 /* Sanity check for client registration */
846 if (NULL == (c = GML_client_get (client)))
847 {
848 GNUNET_break (0);
849 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
850 return;
851 }
852
853 msg = (struct GNUNET_CADET_LocalInfo *) message;
854 resp = (struct GNUNET_CADET_LocalInfoPeer *) cbuf;
855 LOG (GNUNET_ERROR_TYPE_INFO,
856 "Received peer info request from client %u for peer %s\n",
857 c->id, GNUNET_i2s_full (&msg->peer));
858
859 resp->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER);
860 resp->header.size = htons (sizeof (struct GNUNET_CADET_LocalInfoPeer));
861 resp->destination = msg->peer;
862 p = GCP_get (&msg->peer, GNUNET_NO);
863 if (NULL == p)
864 {
865 /* We don't know the peer */
866
867 LOG (GNUNET_ERROR_TYPE_INFO, "Peer %s unknown\n",
868 GNUNET_i2s_full (&msg->peer));
869 resp->paths = htons (0);
870 resp->tunnel = htons (NULL != GCP_get_tunnel (p));
871
872 GNUNET_SERVER_notification_context_unicast (nc, client,
873 &resp->header,
874 GNUNET_NO);
875 GNUNET_SERVER_receive_done (client, GNUNET_OK);
876 return;
877 }
878
879 resp->paths = htons (GCP_count_paths (p));
880 resp->tunnel = htons (NULL != GCP_get_tunnel (p));
881 GCP_iterate_paths (p, &path_info_iterator, resp);
882
883 GNUNET_SERVER_notification_context_unicast (nc, c->handle,
884 &resp->header, GNUNET_NO);
885
886 LOG (GNUNET_ERROR_TYPE_INFO, "Show peer from client %u completed.\n", c->id);
887 GNUNET_SERVER_receive_done (client, GNUNET_OK);
888}
889
890
891/**
892 * Iterator over all tunnels to send a monitoring client info about each tunnel.
893 *
894 * @param cls Closure ().
895 * @param peer Peer ID (tunnel remote peer).
896 * @param value Tunnel info.
897 *
898 * @return #GNUNET_YES, to keep iterating.
899 */
900static int
901get_all_tunnels_iterator (void *cls,
902 const struct GNUNET_PeerIdentity * peer,
903 void *value)
904{
905 struct GNUNET_SERVER_Client *client = cls;
906 struct CadetTunnel *t = value;
907 struct GNUNET_CADET_LocalInfoTunnel msg;
908
909 msg.header.size = htons (sizeof (msg));
910 msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS);
911 msg.destination = *peer;
912 msg.channels = htonl (GCT_count_channels (t));
913 msg.connections = htonl (GCT_count_any_connections (t));
914 msg.cstate = htons ((uint16_t) GCT_get_cstate (t));
915 msg.estate = htons ((uint16_t) GCT_get_estate (t));
916
917 LOG (GNUNET_ERROR_TYPE_DEBUG, "sending info about tunnel ->%s\n",
918 GNUNET_i2s (peer));
919
920 GNUNET_SERVER_notification_context_unicast (nc, client,
921 &msg.header, GNUNET_NO);
922 return GNUNET_YES;
923}
924
925
926/**
927 * Handler for client's INFO TUNNELS request.
928 *
929 * @param cls Closure (unused).
930 * @param client Identification of the client.
931 * @param message The actual message.
932 */
933static void
934handle_get_tunnels (void *cls, struct GNUNET_SERVER_Client *client,
935 const struct GNUNET_MessageHeader *message)
936{
937 struct CadetClient *c;
938 struct GNUNET_MessageHeader reply;
939
940 /* Sanity check for client registration */
941 if (NULL == (c = GML_client_get (client)))
942 {
943 GNUNET_break (0);
944 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
945 return;
946 }
947
948 LOG (GNUNET_ERROR_TYPE_DEBUG,
949 "Received get tunnels request from client %u (%p)\n",
950 c->id, client);
951
952 GCT_iterate_all (get_all_tunnels_iterator, client);
953 reply.size = htons (sizeof (reply));
954 reply.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS);
955 GNUNET_SERVER_notification_context_unicast (nc, client, &reply, GNUNET_NO);
956
957 LOG (GNUNET_ERROR_TYPE_DEBUG,
958 "Get tunnels request from client %u completed\n", c->id);
959 GNUNET_SERVER_receive_done (client, GNUNET_OK);
960}
961
962
963static void
964iter_connection (void *cls, struct CadetConnection *c)
965{
966 struct GNUNET_CADET_LocalInfoTunnel *msg = cls;
967 struct GNUNET_CADET_ConnectionTunnelIdentifier *h;
968
969 h = (struct GNUNET_CADET_ConnectionTunnelIdentifier *) &msg[1];
970 h[msg->connections] = *(GCC_get_id (c));
971 msg->connections++;
972}
973
974static void
975iter_channel (void *cls, struct CadetChannel *ch)
976{
977 struct GNUNET_CADET_LocalInfoTunnel *msg = cls;
978 struct GNUNET_CADET_ConnectionTunnelIdentifier *h = (struct GNUNET_CADET_ConnectionTunnelIdentifier *) &msg[1];
979 struct GNUNET_CADET_ChannelTunnelNumber *chn = (struct GNUNET_CADET_ChannelTunnelNumber *) &h[msg->connections];
980
981 chn[msg->channels] = GCCH_get_id (ch);
982 msg->channels++;
983}
984
985
986/**
987 * Handler for client's SHOW_TUNNEL request.
988 *
989 * @param cls Closure (unused).
990 * @param client Identification of the client.
991 * @param message The actual message.
992 */
993void
994handle_show_tunnel (void *cls, struct GNUNET_SERVER_Client *client,
995 const struct GNUNET_MessageHeader *message)
996{
997 const struct GNUNET_CADET_LocalInfo *msg;
998 struct GNUNET_CADET_LocalInfoTunnel *resp;
999 struct CadetClient *c;
1000 struct CadetTunnel *t;
1001 unsigned int ch_n;
1002 unsigned int c_n;
1003 size_t size;
1004
1005 /* Sanity check for client registration */
1006 if (NULL == (c = GML_client_get (client)))
1007 {
1008 GNUNET_break (0);
1009 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1010 return;
1011 }
1012
1013 msg = (struct GNUNET_CADET_LocalInfo *) message;
1014 LOG (GNUNET_ERROR_TYPE_DEBUG,
1015 "Received tunnel info request from client %u for tunnel %s\n",
1016 c->id, GNUNET_i2s_full(&msg->peer));
1017
1018 t = GCP_get_tunnel (GCP_get (&msg->peer, GNUNET_NO));
1019 if (NULL == t)
1020 {
1021 /* We don't know the tunnel */
1022 struct GNUNET_CADET_LocalInfoTunnel warn;
1023
1024 LOG (GNUNET_ERROR_TYPE_INFO, "Tunnel %s unknown %u\n",
1025 GNUNET_i2s_full(&msg->peer), sizeof (warn));
1026 warn.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL);
1027 warn.header.size = htons (sizeof (warn));
1028 warn.destination = msg->peer;
1029 warn.channels = htonl (0);
1030 warn.connections = htonl (0);
1031 warn.cstate = htons (0);
1032 warn.estate = htons (0);
1033
1034 GNUNET_SERVER_notification_context_unicast (nc, client,
1035 &warn.header,
1036 GNUNET_NO);
1037 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1038 return;
1039 }
1040
1041 /* Initialize context */
1042 ch_n = GCT_count_channels (t);
1043 c_n = GCT_count_any_connections (t);
1044
1045 size = sizeof (struct GNUNET_CADET_LocalInfoTunnel);
1046 size += c_n * sizeof (struct GNUNET_CADET_ConnectionTunnelIdentifier);
1047 size += ch_n * sizeof (struct GNUNET_CADET_ChannelTunnelNumber);
1048
1049 resp = GNUNET_malloc (size);
1050 resp->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL);
1051 resp->header.size = htons (size);
1052 resp->destination = msg->peer;
1053 /* Do not interleave with iterators, iter_channel needs conn in HBO */
1054 GCT_iterate_connections (t, &iter_connection, resp);
1055 GCT_iterate_channels (t, &iter_channel, resp);
1056 resp->connections = htonl (resp->connections);
1057 resp->channels = htonl (resp->channels);
1058 /* Do not interleave end */
1059 resp->cstate = htons (GCT_get_cstate (t));
1060 resp->estate = htons (GCT_get_estate (t));
1061 GNUNET_SERVER_notification_context_unicast (nc, c->handle,
1062 &resp->header, GNUNET_NO);
1063 GNUNET_free (resp);
1064
1065 LOG (GNUNET_ERROR_TYPE_DEBUG,
1066 "Show tunnel request from client %u completed. %u conn, %u ch\n",
1067 c->id, c_n, ch_n);
1068 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1069}
1070
1071
1072/**
1073 * Handler for client's INFO_DUMP request.
1074 *
1075 * @param cls Closure (unused).
1076 * @param client Identification of the client.
1077 * @param message The actual message.
1078 */
1079void
1080handle_info_dump (void *cls, struct GNUNET_SERVER_Client *client,
1081 const struct GNUNET_MessageHeader *message)
1082{
1083 struct CadetClient *c;
1084
1085 /* Sanity check for client registration */
1086 if (NULL == (c = GML_client_get (client)))
1087 {
1088 GNUNET_break (0);
1089 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1090 return;
1091 }
1092
1093 LOG (GNUNET_ERROR_TYPE_INFO, "Received dump info request from client %u\n",
1094 c->id);
1095 LOG (GNUNET_ERROR_TYPE_ERROR,
1096 "*************************** DUMP START ***************************\n");
1097
1098 for (c = clients_head; NULL != c; c = c->next)
1099 {
1100 LOG (GNUNET_ERROR_TYPE_ERROR, "Client %u (%p), handle: %p\n",
1101 c->id, c, c->handle);
1102 if (NULL != c->ports)
1103 LOG (GNUNET_ERROR_TYPE_ERROR, "\t%3u ports registered\n",
1104 GNUNET_CONTAINER_multihashmap_size (c->ports));
1105 else
1106 LOG (GNUNET_ERROR_TYPE_ERROR, "\t no ports registered\n");
1107 LOG (GNUNET_ERROR_TYPE_ERROR, "\t%3u own channles\n",
1108 GNUNET_CONTAINER_multihashmap32_size (c->own_channels));
1109 LOG (GNUNET_ERROR_TYPE_ERROR, "\t%3u incoming channles\n",
1110 GNUNET_CONTAINER_multihashmap32_size (c->incoming_channels));
1111 }
1112 LOG (GNUNET_ERROR_TYPE_ERROR, "***************************\n");
1113 GCP_iterate_all (&show_peer_iterator, NULL);
1114
1115 LOG (GNUNET_ERROR_TYPE_ERROR,
1116 "**************************** DUMP END ****************************\n");
1117
1118 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1119}
1120
1121
1122/**
1123 * Functions to handle messages from clients
1124 */
1125static struct GNUNET_SERVER_MessageHandler client_handlers[] = {
1126 {&handle_port_open, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_OPEN,
1127 sizeof (struct GNUNET_CADET_PortMessage)},
1128 {&handle_port_close, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_CLOSE,
1129 sizeof (struct GNUNET_CADET_PortMessage)},
1130 {&handle_channel_create, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_CREATE,
1131 sizeof (struct GNUNET_CADET_LocalChannelCreateMessage)},
1132 {&handle_channel_destroy, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY,
1133 sizeof (struct GNUNET_CADET_LocalChannelDestroyMessage)},
1134 {&handle_data, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA, 0},
1135 {&handle_ack, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK,
1136 sizeof (struct GNUNET_CADET_LocalAck)},
1137 {&handle_get_peers, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS,
1138 sizeof (struct GNUNET_MessageHeader)},
1139 {&handle_show_peer, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER,
1140 sizeof (struct GNUNET_CADET_LocalInfo)},
1141 {&handle_get_tunnels, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS,
1142 sizeof (struct GNUNET_MessageHeader)},
1143 {&handle_show_tunnel, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL,
1144 sizeof (struct GNUNET_CADET_LocalInfo)},
1145 {&handle_info_dump, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_DUMP,
1146 sizeof (struct GNUNET_MessageHeader)},
1147 {NULL, NULL, 0, 0}
1148};
1149
1150
1151
1152/******************************************************************************/
1153/******************************** API ***********************************/
1154/******************************************************************************/
1155
1156/**
1157 * Initialize server subsystem.
1158 *
1159 * @param handle Server handle.
1160 */
1161void
1162GML_init (struct GNUNET_SERVER_Handle *handle)
1163{
1164 LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n");
1165 server_handle = handle;
1166 GNUNET_SERVER_suspend (server_handle);
1167 ports = GNUNET_CONTAINER_multihashmap_create (16, GNUNET_NO);
1168}
1169
1170
1171/**
1172 * Install server (service) handlers and start listening to clients.
1173 */
1174void
1175GML_start (void)
1176{
1177 GNUNET_SERVER_add_handlers (server_handle, client_handlers);
1178 GNUNET_SERVER_connect_notify (server_handle, &handle_client_connect, NULL);
1179 GNUNET_SERVER_disconnect_notify (server_handle, &handle_client_disconnect,
1180 NULL);
1181 nc = GNUNET_SERVER_notification_context_create (server_handle, 1);
1182
1183 clients_head = NULL;
1184 clients_tail = NULL;
1185 next_client_id = 0;
1186 GNUNET_SERVER_resume (server_handle);
1187}
1188
1189
1190/**
1191 * Shutdown server.
1192 */
1193void
1194GML_shutdown (void)
1195{
1196 struct CadetClient *c;
1197
1198 LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down local\n");
1199
1200 for (c = clients_head; NULL != clients_head; c = clients_head)
1201 client_destroy (c);
1202
1203 if (nc != NULL)
1204 {
1205 GNUNET_SERVER_notification_context_destroy (nc);
1206 nc = NULL;
1207 }
1208
1209}
1210
1211
1212/**
1213 * Get a channel from a client.
1214 *
1215 * @param c Client to check.
1216 * @param ccn Channel ID, must be local (> 0x800...).
1217 *
1218 * @return non-NULL if channel exists in the clients lists
1219 */
1220struct CadetChannel *
1221GML_channel_get (struct CadetClient *c,
1222 struct GNUNET_CADET_ClientChannelNumber ccn)
1223{
1224 struct GNUNET_CONTAINER_MultiHashMap32 *map;
1225
1226 if (ntohl (ccn.channel_of_client) >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
1227 map = c->own_channels;
1228 else
1229 map = c->incoming_channels;
1230
1231 if (NULL == map)
1232 {
1233 GNUNET_break (0);
1234 LOG (GNUNET_ERROR_TYPE_DEBUG,
1235 "Client %s does no t have a valid map for CCN %X\n",
1236 GML_2s (c), ccn);
1237 return NULL;
1238 }
1239 return GNUNET_CONTAINER_multihashmap32_get (map,
1240 ccn.channel_of_client);
1241}
1242
1243
1244/**
1245 * Add a channel to a client
1246 *
1247 * @param client Client.
1248 * @param ccn Channel ID.
1249 * @param ch Channel.
1250 */
1251void
1252GML_channel_add (struct CadetClient *client,
1253 struct GNUNET_CADET_ClientChannelNumber ccn,
1254 struct CadetChannel *ch)
1255{
1256 if (ntohl (ccn.channel_of_client) >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
1257 GNUNET_CONTAINER_multihashmap32_put (client->own_channels,
1258 ccn.channel_of_client,
1259 ch,
1260 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
1261 else
1262 GNUNET_CONTAINER_multihashmap32_put (client->incoming_channels,
1263 ccn.channel_of_client,
1264 ch,
1265 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
1266}
1267
1268
1269/**
1270 * Remove a channel from a client.
1271 *
1272 * @param client Client.
1273 * @param ccn Channel ID.
1274 * @param ch Channel.
1275 */
1276void
1277GML_channel_remove (struct CadetClient *client,
1278 struct GNUNET_CADET_ClientChannelNumber ccn,
1279 struct CadetChannel *ch)
1280{
1281 if (ntohl (ccn.channel_of_client) >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
1282 GNUNET_CONTAINER_multihashmap32_remove (client->own_channels,
1283 ccn.channel_of_client,
1284 ch);
1285 else
1286 GNUNET_CONTAINER_multihashmap32_remove (client->incoming_channels,
1287 ccn.channel_of_client,
1288 ch);
1289}
1290
1291
1292/**
1293 * Get the tunnel's next free local channel ID.
1294 *
1295 * @param c Client.
1296 *
1297 * @return LID of a channel free to use.
1298 */
1299struct GNUNET_CADET_ClientChannelNumber
1300GML_get_next_ccn (struct CadetClient *c)
1301{
1302 struct GNUNET_CADET_ClientChannelNumber ccn;
1303
1304 while (NULL != GML_channel_get (c,
1305 c->next_ccn))
1306 {
1307 LOG (GNUNET_ERROR_TYPE_DEBUG,
1308 "Channel %u exists...\n",
1309 c->next_ccn);
1310 c->next_ccn.channel_of_client
1311 = htonl (1 + (ntohl (c->next_ccn.channel_of_client)));
1312 if (ntohl (c->next_ccn.channel_of_client) >=
1313 GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
1314 c->next_ccn.channel_of_client = htonl (0);
1315 }
1316 ccn = c->next_ccn;
1317 c->next_ccn.channel_of_client
1318 = htonl (1 + (ntohl (c->next_ccn.channel_of_client)));
1319
1320 return ccn;
1321}
1322
1323
1324/**
1325 * Check if client has registered with the service and has not disconnected
1326 *
1327 * @param client the client to check
1328 *
1329 * @return non-NULL if client exists in the global DLL
1330 */
1331struct CadetClient *
1332GML_client_get (struct GNUNET_SERVER_Client *client)
1333{
1334 if (NULL == client)
1335 return NULL;
1336 return GNUNET_SERVER_client_get_user_context (client,
1337 struct CadetClient);
1338}
1339
1340
1341/**
1342 * Find a client that has opened a port
1343 *
1344 * @param port Port to check.
1345 *
1346 * @return non-NULL if a client has the port.
1347 */
1348struct CadetClient *
1349GML_client_get_by_port (const struct GNUNET_HashCode *port)
1350{
1351 return GNUNET_CONTAINER_multihashmap_get (ports, port);
1352}
1353
1354
1355/**
1356 * Deletes a channel from a client (either owner or destination).
1357 *
1358 * @param c Client whose tunnel to delete.
1359 * @param ch Channel which should be deleted.
1360 * @param id Channel ID.
1361 */
1362void
1363GML_client_delete_channel (struct CadetClient *c,
1364 struct CadetChannel *ch,
1365 struct GNUNET_CADET_ClientChannelNumber id)
1366{
1367 int res;
1368
1369 if (ntohl (id.channel_of_client) >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
1370 {
1371 res = GNUNET_CONTAINER_multihashmap32_remove (c->own_channels,
1372 id.channel_of_client,
1373 ch);
1374 if (GNUNET_YES != res)
1375 LOG (GNUNET_ERROR_TYPE_DEBUG, "client_delete_tunnel root KO\n");
1376 }
1377 else
1378 {
1379 res = GNUNET_CONTAINER_multihashmap32_remove (c->incoming_channels,
1380 id.channel_of_client,
1381 ch);
1382 if (GNUNET_YES != res)
1383 LOG (GNUNET_ERROR_TYPE_DEBUG, "client_delete_channel dest KO\n");
1384 }
1385}
1386
1387/**
1388 * Build a local ACK message and send it to a local client, if needed.
1389 *
1390 * If the client was already allowed to send data, do nothing.
1391 *
1392 * @param c Client to whom send the ACK.
1393 * @param ccn Channel ID to use
1394 */
1395void
1396GML_send_ack (struct CadetClient *c,
1397 struct GNUNET_CADET_ClientChannelNumber ccn)
1398{
1399 struct GNUNET_CADET_LocalAck msg;
1400
1401 LOG (GNUNET_ERROR_TYPE_DEBUG,
1402 "send local %s ack on %X towards %p\n",
1403 ntohl (ccn.channel_of_client) < GNUNET_CADET_LOCAL_CHANNEL_ID_CLI
1404 ? "FWD" : "BCK",
1405 ntohl (ccn.channel_of_client),
1406 c);
1407
1408 msg.header.size = htons (sizeof (msg));
1409 msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK);
1410 msg.ccn = ccn;
1411 GNUNET_SERVER_notification_context_unicast (nc,
1412 c->handle,
1413 &msg.header,
1414 GNUNET_NO);
1415
1416}
1417
1418
1419
1420/**
1421 * Notify the client that a new incoming channel was created.
1422 *
1423 * @param c Client to notify.
1424 * @param ccn Channel ID.
1425 * @param port Channel's destination port.
1426 * @param opt Options (bit array).
1427 * @param peer Origin peer.
1428 */
1429void
1430GML_send_channel_create (struct CadetClient *c,
1431 struct GNUNET_CADET_ClientChannelNumber ccn,
1432 const struct GNUNET_HashCode *port,
1433 uint32_t opt,
1434 const struct GNUNET_PeerIdentity *peer)
1435{
1436 struct GNUNET_CADET_LocalChannelCreateMessage msg;
1437
1438 msg.header.size = htons (sizeof (msg));
1439 msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_CREATE);
1440 msg.ccn = ccn;
1441 msg.port = *port;
1442 msg.opt = htonl (opt);
1443 msg.peer = *peer;
1444 GNUNET_SERVER_notification_context_unicast (nc, c->handle,
1445 &msg.header, GNUNET_NO);
1446}
1447
1448
1449/**
1450 * Build a local channel NACK message and send it to a local client.
1451 *
1452 * @param c Client to whom send the NACK.
1453 * @param ccn Channel ID to use
1454 */
1455void
1456GML_send_channel_nack (struct CadetClient *c,
1457 struct GNUNET_CADET_ClientChannelNumber ccn)
1458{
1459 struct GNUNET_CADET_LocalAck msg;
1460
1461 LOG (GNUNET_ERROR_TYPE_DEBUG,
1462 "send local nack on %X towards %p\n",
1463 ntohl (ccn.channel_of_client),
1464 c);
1465
1466 msg.header.size = htons (sizeof (msg));
1467 msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_NACK_DEPRECATED);
1468 msg.ccn = ccn;
1469 GNUNET_SERVER_notification_context_unicast (nc,
1470 c->handle,
1471 &msg.header,
1472 GNUNET_NO);
1473
1474}
1475
1476/**
1477 * Notify a client that a channel is no longer valid.
1478 *
1479 * @param c Client.
1480 * @param ccn ID of the channel that is destroyed.
1481 */
1482void
1483GML_send_channel_destroy (struct CadetClient *c,
1484 struct GNUNET_CADET_ClientChannelNumber ccn)
1485{
1486 struct GNUNET_CADET_LocalChannelDestroyMessage msg;
1487
1488 if (NULL == c)
1489 {
1490 GNUNET_break (0);
1491 return;
1492 }
1493 if (GNUNET_YES == c->shutting_down)
1494 return;
1495 msg.header.size = htons (sizeof (msg));
1496 msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY);
1497 msg.ccn = ccn;
1498 GNUNET_SERVER_notification_context_unicast (nc, c->handle,
1499 &msg.header, GNUNET_NO);
1500}
1501
1502
1503/**
1504 * Modify the cadet message ID from global to local and send to client.
1505 *
1506 * @param c Client to send to.
1507 * @param msg Message to modify and send.
1508 * @param ccn Channel ID to use (c can be both owner and client).
1509 */
1510void
1511GML_send_data (struct CadetClient *c,
1512 const struct GNUNET_CADET_ChannelAppDataMessage *msg,
1513 struct GNUNET_CADET_ClientChannelNumber ccn)
1514{
1515 struct GNUNET_CADET_LocalData *copy;
1516 uint16_t size = ntohs (msg->header.size) - sizeof (struct GNUNET_CADET_ChannelAppDataMessage);
1517 char cbuf[size + sizeof (struct GNUNET_CADET_LocalData)];
1518
1519 if (size < sizeof (struct GNUNET_MessageHeader))
1520 {
1521 GNUNET_break_op (0);
1522 return;
1523 }
1524 if (NULL == c)
1525 {
1526 GNUNET_break (0);
1527 return;
1528 }
1529 copy = (struct GNUNET_CADET_LocalData *) cbuf;
1530 GNUNET_memcpy (&copy[1], &msg[1], size);
1531 copy->header.size = htons (sizeof (struct GNUNET_CADET_LocalData) + size);
1532 copy->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA);
1533 copy->ccn = ccn;
1534 GNUNET_SERVER_notification_context_unicast (nc, c->handle,
1535 &copy->header, GNUNET_NO);
1536}
1537
1538
1539/**
1540 * Get the static string to represent a client.
1541 *
1542 * @param c Client.
1543 *
1544 * @return Static string for the client.
1545 */
1546const char *
1547GML_2s (const struct CadetClient *c)
1548{
1549 static char buf[32];
1550
1551 SPRINTF (buf, "%u", c->id);
1552 return buf;
1553}
diff --git a/src/cadet/gnunet-service-cadet_local.h b/src/cadet/gnunet-service-cadet_local.h
deleted file mode 100644
index 113c2f489..000000000
--- a/src/cadet/gnunet-service-cadet_local.h
+++ /dev/null
@@ -1,234 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2013 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21/**
22 * @file cadet/gnunet-service-cadet_local.h
23 * @brief cadet service; dealing with local clients
24 * @author Bartlomiej Polot
25 *
26 * All functions in this file should use the prefix GML (Gnunet Cadet Local)
27 */
28
29#ifndef GNUNET_SERVICE_CADET_LOCAL_H
30#define GNUNET_SERVICE_CADET_LOCAL_H
31
32#ifdef __cplusplus
33extern "C"
34{
35#if 0 /* keep Emacsens' auto-indent happy */
36}
37#endif
38#endif
39
40#include "platform.h"
41#include "gnunet_util_lib.h"
42
43/**
44 * Struct containing information about a client of the service
45 */
46struct CadetClient;
47
48#include "gnunet-service-cadet_channel.h"
49
50/******************************************************************************/
51/******************************** API ***********************************/
52/******************************************************************************/
53
54/**
55 * Initialize server subsystem.
56 *
57 * @param handle Server handle.
58 */
59void
60GML_init (struct GNUNET_SERVER_Handle *handle);
61
62/**
63 * Install server (service) handlers and start listening to clients.
64 */
65void
66GML_start (void);
67
68/**
69 * Shutdown server.
70 */
71void
72GML_shutdown (void);
73
74/**
75 * Get a channel from a client.
76 *
77 * @param c Client to check.
78 * @param ccn Channel ID, must be local (> 0x800...).
79 *
80 * @return non-NULL if channel exists in the clients lists
81 */
82struct CadetChannel *
83GML_channel_get (struct CadetClient *c,
84 struct GNUNET_CADET_ClientChannelNumber ccn);
85
86/**
87 * Add a channel to a client
88 *
89 * @param client Client.
90 * @param ccn Channel ID.
91 * @param ch Channel.
92 */
93void
94GML_channel_add (struct CadetClient *client,
95 struct GNUNET_CADET_ClientChannelNumber ccn,
96 struct CadetChannel *ch);
97
98/**
99 * Remove a channel from a client
100 *
101 * @param client Client.
102 * @param ccn Channel ID.
103 * @param ch Channel.
104 */
105void
106GML_channel_remove (struct CadetClient *client,
107 struct GNUNET_CADET_ClientChannelNumber ccn,
108 struct CadetChannel *ch);
109
110/**
111 * Get the tunnel's next free local channel ID.
112 *
113 * @param c Client.
114 *
115 * @return LID of a channel free to use.
116 */
117struct GNUNET_CADET_ClientChannelNumber
118GML_get_next_ccn (struct CadetClient *c);
119
120/**
121 * Check if client has registered with the service and has not disconnected
122 *
123 * @param client the client to check
124 *
125 * @return non-NULL if client exists in the global DLL
126 */
127struct CadetClient *
128GML_client_get (struct GNUNET_SERVER_Client *client);
129
130/**
131 * Find a client that has opened a port
132 *
133 * @param port Port to check.
134 *
135 * @return non-NULL if a client has the port.
136 */
137struct CadetClient *
138GML_client_get_by_port (const struct GNUNET_HashCode *port);
139
140/**
141 * Deletes a tunnel from a client (either owner or destination).
142 *
143 * @param c Client whose tunnel to delete.
144 * @param ch Channel which should be deleted.
145 * @param id Channel ID.
146 */
147void
148GML_client_delete_channel (struct CadetClient *c,
149 struct CadetChannel *ch,
150 struct GNUNET_CADET_ClientChannelNumber id);
151
152/**
153 * Build a local ACK message and send it to a local client, if needed.
154 *
155 * If the client was already allowed to send data, do nothing.
156 *
157 * @param c Client to whom send the ACK.
158 * @param id Channel ID to use
159 */
160void
161GML_send_ack (struct CadetClient *c,
162 struct GNUNET_CADET_ClientChannelNumber id);
163
164/**
165 * Notify the appropriate client that a new incoming channel was created.
166 *
167 * @param c Client to notify.
168 * @param id Channel ID.
169 * @param port Channel's destination port.
170 * @param opt Options (bit array).
171 * @param peer Origin peer.
172 */
173void
174GML_send_channel_create (struct CadetClient *c,
175 struct GNUNET_CADET_ClientChannelNumber id,
176 const struct GNUNET_HashCode *port,
177 uint32_t opt,
178 const struct GNUNET_PeerIdentity *peer);
179
180/**
181 * Build a local channel NACK message and send it to a local client.
182 *
183 * @param c Client to whom send the NACK.
184 * @param id Channel ID to use
185 */
186void
187GML_send_channel_nack (struct CadetClient *c,
188 struct GNUNET_CADET_ClientChannelNumber id);
189
190
191/**
192 * Notify a client that a channel is no longer valid.
193 *
194 * @param c Client.
195 * @param id ID of the channel that is destroyed.
196 */
197void
198GML_send_channel_destroy (struct CadetClient *c,
199 struct GNUNET_CADET_ClientChannelNumber id);
200
201
202/**
203 * Modify the cadet message ID from global to local and send to client.
204 *
205 * @param c Client to send to.
206 * @param msg Message to modify and send.
207 * @param id Channel ID to use (c can be both owner and client).
208 */
209void
210GML_send_data (struct CadetClient *c,
211 const struct GNUNET_CADET_ChannelAppDataMessage *msg,
212 struct GNUNET_CADET_ClientChannelNumber id);
213
214/**
215 * Get the static string to represent a client.
216 *
217 * @param c Client.
218 *
219 * @return Static string for the client.
220 */
221const char *
222GML_2s (const struct CadetClient *c);
223
224
225#if 0 /* keep Emacsens' auto-indent happy */
226{
227#endif
228#ifdef __cplusplus
229}
230#endif
231
232/* ifndef GNUNET_CADET_SERVICE_LOCAL_H */
233#endif
234/* end of gnunet-cadet-service_LOCAL.h */
diff --git a/src/cadet/gnunet-service-cadet-new_paths.c b/src/cadet/gnunet-service-cadet_paths.c
index c6121a133..13752643c 100644
--- a/src/cadet/gnunet-service-cadet-new_paths.c
+++ b/src/cadet/gnunet-service-cadet_paths.c
@@ -18,16 +18,16 @@
18 Boston, MA 02110-1301, USA. 18 Boston, MA 02110-1301, USA.
19*/ 19*/
20/** 20/**
21 * @file cadet/gnunet-service-cadet-new_paths.c 21 * @file cadet/gnunet-service-cadet_paths.c
22 * @brief Information we track per path. 22 * @brief Information we track per path.
23 * @author Bartlomiej Polot 23 * @author Bartlomiej Polot
24 * @author Christian Grothoff 24 * @author Christian Grothoff
25 */ 25 */
26#include "platform.h" 26#include "platform.h"
27#include "gnunet-service-cadet-new_connection.h" 27#include "gnunet-service-cadet_connection.h"
28#include "gnunet-service-cadet-new_tunnels.h" 28#include "gnunet-service-cadet_tunnels.h"
29#include "gnunet-service-cadet-new_peer.h" 29#include "gnunet-service-cadet_peer.h"
30#include "gnunet-service-cadet-new_paths.h" 30#include "gnunet-service-cadet_paths.h"
31 31
32 32
33#define LOG(level, ...) GNUNET_log_from(level,"cadet-pat",__VA_ARGS__) 33#define LOG(level, ...) GNUNET_log_from(level,"cadet-pat",__VA_ARGS__)
diff --git a/src/cadet/gnunet-service-cadet-new_paths.h b/src/cadet/gnunet-service-cadet_paths.h
index 7310d75e6..6b7bef640 100644
--- a/src/cadet/gnunet-service-cadet-new_paths.h
+++ b/src/cadet/gnunet-service-cadet_paths.h
@@ -29,7 +29,7 @@
29#define GNUNET_SERVICE_CADET_PATHS_H 29#define GNUNET_SERVICE_CADET_PATHS_H
30 30
31#include "gnunet_util_lib.h" 31#include "gnunet_util_lib.h"
32#include "gnunet-service-cadet-new.h" 32#include "gnunet-service-cadet.h"
33 33
34/** 34/**
35 * Create a peer path based on the result of a DHT lookup. If we 35 * Create a peer path based on the result of a DHT lookup. If we
diff --git a/src/cadet/gnunet-service-cadet_peer.c b/src/cadet/gnunet-service-cadet_peer.c
index fa3f2be80..71c7c67d0 100644
--- a/src/cadet/gnunet-service-cadet_peer.c
+++ b/src/cadet/gnunet-service-cadet_peer.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 Copyright (C) 2013, 2015 GNUnet e.V. 3 Copyright (C) 2001-2017 GNUnet e.V.
4 4
5 GNUnet is free software; you can redistribute it and/or modify 5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published 6 it under the terms of the GNU General Public License as published
@@ -17,2193 +17,1461 @@
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA. 18 Boston, MA 02110-1301, USA.
19*/ 19*/
20
20/** 21/**
21 * @file cadet/gnunet-service-cadet_peer.c 22 * @file cadet/gnunet-service-cadet_peer.c
22 * @brief GNUnet CADET service connection handling 23 * @brief Information we track per peer.
23 * @author Bartlomiej Polot 24 * @author Bartlomiej Polot
25 * @author Christian Grothoff
26 *
27 * TODO:
28 * - optimize stopping/restarting DHT search to situations
29 * where we actually need it (i.e. not if we have a direct connection,
30 * or if we already have plenty of good short ones, or maybe even
31 * to take a break if we have some connections and have searched a lot (?))
24 */ 32 */
25#include "platform.h" 33#include "platform.h"
26#include "gnunet_util_lib.h" 34#include "gnunet_util_lib.h"
35#include "gnunet_hello_lib.h"
27#include "gnunet_signatures.h" 36#include "gnunet_signatures.h"
28#include "gnunet_transport_service.h" 37#include "gnunet_transport_service.h"
29#include "gnunet_ats_service.h" 38#include "gnunet_ats_service.h"
30#include "gnunet_core_service.h" 39#include "gnunet_core_service.h"
31#include "gnunet_statistics_service.h" 40#include "gnunet_statistics_service.h"
32#include "cadet_protocol.h" 41#include "cadet_protocol.h"
33#include "gnunet-service-cadet_peer.h"
34#include "gnunet-service-cadet_dht.h"
35#include "gnunet-service-cadet_connection.h" 42#include "gnunet-service-cadet_connection.h"
36#include "gnunet-service-cadet_tunnel.h" 43#include "gnunet-service-cadet_dht.h"
37#include "cadet_path.h" 44#include "gnunet-service-cadet_peer.h"
45#include "gnunet-service-cadet_paths.h"
46#include "gnunet-service-cadet_tunnels.h"
38 47
39#define LOG(level, ...) GNUNET_log_from (level,"cadet-p2p",__VA_ARGS__)
40#define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-p2p",__VA_ARGS__)
41 48
49#define LOG(level, ...) GNUNET_log_from(level,"cadet-per",__VA_ARGS__)
42 50
43/******************************************************************************/
44/******************************** STRUCTS **********************************/
45/******************************************************************************/
46 51
47/** 52/**
48 * Information about a queued message on the peer level. 53 * How long do we wait until tearing down an idle peer?
49 */ 54 */
50struct CadetPeerQueue { 55#define IDLE_PEER_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5)
51
52 struct CadetPeerQueue *next;
53 struct CadetPeerQueue *prev;
54
55 /**
56 * Envelope to cancel message before MQ sends it.
57 */
58 struct GNUNET_MQ_Envelope *env;
59
60 /**
61 * Peer (neighbor) this message is being sent to.
62 */
63 struct CadetPeer *peer;
64
65 /**
66 * Continuation to call to notify higher layers about message sent.
67 */
68 GCP_sent cont;
69
70 /**
71 * Closure for @a cont.
72 */
73 void *cont_cls;
74
75 /**
76 * Task to asynchronously run the drop continuation.
77 */
78 struct GNUNET_SCHEDULER_Task *drop_task;
79
80 /**
81 * Time when message was queued for sending.
82 */
83 struct GNUNET_TIME_Absolute queue_timestamp;
84
85 /**
86 * #GNUNET_YES if message was management traffic (POLL, ACK, ...).
87 */
88 int management_traffic;
89
90 /**
91 * Message type.
92 */
93 uint16_t type;
94
95 /**
96 * Message size.
97 */
98 uint16_t size;
99
100 /**
101 * Type of the message's payload, if it was encrypted data.
102 */
103 uint16_t payload_type;
104
105 /**
106 * ID of the payload (PID, ACK #, ...).
107 */
108 struct CadetEncryptedMessageIdentifier payload_id;
109
110 /**
111 * Connection this message was sent on.
112 */
113 struct CadetConnection *c;
114
115 /**
116 * Direction in @a c this message was send on (#GNUNET_YES = FWD).
117 */
118 int c_fwd;
119};
120
121 56
122/** 57/**
123 * Struct containing all information regarding a given peer 58 * How long do we keep paths around if we no longer care about the peer?
124 */ 59 */
125struct CadetPeer 60#define IDLE_PATH_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 2)
126{
127 /**
128 * ID of the peer
129 */
130 GNUNET_PEER_Id id;
131
132 struct CadetPeerQueue *q_head;
133 struct CadetPeerQueue *q_tail;
134
135 /**
136 * Last time we heard from this peer
137 */
138 struct GNUNET_TIME_Absolute last_contact;
139
140 /**
141 * Paths to reach the peer, ordered by ascending hop count
142 */
143 struct CadetPeerPath *path_head;
144
145 /**
146 * Paths to reach the peer, ordered by ascending hop count
147 */
148 struct CadetPeerPath *path_tail;
149
150 /**
151 * Handle to stop the DHT search for paths to this peer
152 */
153 struct GCD_search_handle *search_h;
154
155 /**
156 * Handle to stop the DHT search for paths to this peer
157 */
158 struct GNUNET_SCHEDULER_Task *search_delayed;
159
160 /**
161 * Tunnel to this peer, if any.
162 */
163 struct CadetTunnel *tunnel;
164
165 /**
166 * Connections that go through this peer; indexed by tid.
167 */
168 struct GNUNET_CONTAINER_MultiShortmap *connections;
169
170 /**
171 * Handle for core transmissions.
172 */
173 struct GNUNET_MQ_Handle *core_mq;
174
175 /**
176 * How many messages are in the queue to this peer.
177 */
178 unsigned int queue_n;
179
180 /**
181 * Hello message.
182 */
183 struct GNUNET_HELLO_Message* hello;
184
185 /**
186 * Handle to us offering the HELLO to the transport.
187 */
188 struct GNUNET_TRANSPORT_OfferHelloHandle *hello_offer;
189
190 /**
191 * Handle to our ATS request asking ATS to suggest an address
192 * to TRANSPORT for this peer (to establish a direct link).
193 */
194 struct GNUNET_ATS_ConnectivitySuggestHandle *connectivity_suggestion;
195 61
196};
197
198
199/******************************************************************************/
200/******************************* GLOBALS ***********************************/
201/******************************************************************************/
202
203/**
204 * Global handle to the statistics service.
205 */
206extern struct GNUNET_STATISTICS_Handle *stats;
207 62
208/**
209 * Local peer own ID (full value).
210 */
211extern struct GNUNET_PeerIdentity my_full_id;
212 63
213/**
214 * Local peer own ID (short)
215 */
216extern GNUNET_PEER_Id myid;
217 64
218/** 65/**
219 * Peers known, indexed by PeerIdentity, values of type `struct CadetPeer`. 66 * Data structure used to track whom we have to notify about changes
67 * to our message queue.
220 */ 68 */
221static struct GNUNET_CONTAINER_MultiPeerMap *peers; 69struct GCP_MessageQueueManager
222 70{
223/**
224 * How many peers do we want to remember?
225 */
226static unsigned long long max_peers;
227 71
228/** 72 /**
229 * Percentage of messages that will be dropped (for test purposes only). 73 * Kept in a DLL.
230 */ 74 */
231static unsigned long long drop_percent; 75 struct GCP_MessageQueueManager *next;
232 76
233/** 77 /**
234 * Handle to communicate with CORE. 78 * Kept in a DLL.
235 */ 79 */
236static struct GNUNET_CORE_Handle *core_handle; 80 struct GCP_MessageQueueManager *prev;
237 81
238/** 82 /**
239 * Our configuration; 83 * Function to call with updated message queue object.
240 */ 84 */
241static const struct GNUNET_CONFIGURATION_Handle *cfg; 85 GCP_MessageQueueNotificationCallback cb;
242 86
243/** 87 /**
244 * Handle to communicate with ATS. 88 * Closure for @e cb.
245 */ 89 */
246static struct GNUNET_ATS_ConnectivityHandle *ats_ch; 90 void *cb_cls;
247 91
248/** 92 /**
249 * Shutdown falg. 93 * The peer this is for.
250 */ 94 */
251static int in_shutdown; 95 struct CadetPeer *cp;
252 96
97 /**
98 * Envelope this manager would like to transmit once it is its turn.
99 */
100 struct GNUNET_MQ_Envelope *env;
253 101
254/******************************************************************************/ 102};
255/***************************** CORE HELPERS *********************************/
256/******************************************************************************/
257 103
258 104
259/** 105/**
260 * Iterator to notify all connections of a broken link. Mark connections 106 * Struct containing all information regarding a given peer
261 * to destroy after all traffic has been sent.
262 *
263 * @param cls Closure (disconnected peer).
264 * @param key Current key code (peer id).
265 * @param value Value in the hash map (connection).
266 *
267 * @return #GNUNET_YES to continue to iterate.
268 */ 107 */
269static int 108struct CadetPeer
270notify_broken (void *cls,
271 const struct GNUNET_ShortHashCode *key,
272 void *value)
273{ 109{
274 struct CadetPeer *peer = cls; 110 /**
275 struct CadetConnection *c = value; 111 * ID of the peer
112 */
113 struct GNUNET_PeerIdentity pid;
114
115 /**
116 * Last time we heard from this peer (currently not used!)
117 */
118 struct GNUNET_TIME_Absolute last_contactXXX;
119
120 /**
121 * Array of DLLs of paths traversing the peer, organized by the
122 * offset of the peer on the larger path.
123 */
124 struct CadetPeerPathEntry **path_heads;
125
126 /**
127 * Array of DLL of paths traversing the peer, organized by the
128 * offset of the peer on the larger path.
129 */
130 struct CadetPeerPathEntry **path_tails;
131
132 /**
133 * Notifications to call when @e core_mq changes.
134 */
135 struct GCP_MessageQueueManager *mqm_head;
136
137 /**
138 * Notifications to call when @e core_mq changes.
139 */
140 struct GCP_MessageQueueManager *mqm_tail;
141
142 /**
143 * Pointer to first "ready" entry in @e mqm_head.
144 */
145 struct GCP_MessageQueueManager *mqm_ready_ptr;
146
147 /**
148 * MIN-heap of paths owned by this peer (they also end at this
149 * peer). Ordered by desirability.
150 */
151 struct GNUNET_CONTAINER_Heap *path_heap;
152
153 /**
154 * Handle to stop the DHT search for paths to this peer
155 */
156 struct GCD_search_handle *search_h;
157
158 /**
159 * Task to clean up @e path_heap asynchronously.
160 */
161 struct GNUNET_SCHEDULER_Task *heap_cleanup_task;
162
163 /**
164 * Task to destroy this entry.
165 */
166 struct GNUNET_SCHEDULER_Task *destroy_task;
167
168 /**
169 * Tunnel to this peer, if any.
170 */
171 struct CadetTunnel *t;
172
173 /**
174 * Connections that go through this peer; indexed by tid.
175 */
176 struct GNUNET_CONTAINER_MultiShortmap *connections;
177
178 /**
179 * Handle for core transmissions.
180 */
181 struct GNUNET_MQ_Handle *core_mq;
182
183 /**
184 * Hello message of the peer.
185 */
186 struct GNUNET_HELLO_Message *hello;
187
188 /**
189 * Handle to us offering the HELLO to the transport.
190 */
191 struct GNUNET_TRANSPORT_OfferHelloHandle *hello_offer;
192
193 /**
194 * Handle to our ATS request asking ATS to suggest an address
195 * to TRANSPORT for this peer (to establish a direct link).
196 */
197 struct GNUNET_ATS_ConnectivitySuggestHandle *connectivity_suggestion;
198
199 /**
200 * How many messages are in the queue to this peer.
201 */
202 unsigned int queue_n;
203
204 /**
205 * How many paths do we have to this peer (in all @e path_heads DLLs combined).
206 */
207 unsigned int num_paths;
208
209 /**
210 * Sum over all of the offsets of all of the paths in the @a path_heads DLLs.
211 * Used to speed-up @GCP_get_desirability_of_path() calculation.
212 */
213 unsigned int off_sum;
214
215 /**
216 * Number of message queue managers of this peer that have a message in waiting.
217 *
218 * Used to quickly see if we need to bother scanning the @e msm_head DLL.
219 * TODO: could be replaced by another DLL that would then allow us to avoid
220 * the O(n)-scan of the DLL for ready entries!
221 */
222 unsigned int mqm_ready_counter;
223
224 /**
225 * Current length of the @e path_heads and @path_tails arrays.
226 * The arrays should be grown as needed.
227 */
228 unsigned int path_dll_length;
276 229
277 LOG (GNUNET_ERROR_TYPE_DEBUG, 230};
278 "Notifying %s due to %s disconnect\n",
279 GCC_2s (c), GCP_2s (peer));
280 GCC_neighbor_disconnected (c, peer);
281 return GNUNET_YES;
282}
283 231
284 232
285/** 233/**
286 * Remove the direct path to the peer. 234 * Get the static string for a peer ID.
287 *
288 * @param peer Peer to remove the direct path from.
289 */
290static struct CadetPeerPath *
291pop_direct_path (struct CadetPeer *peer)
292{
293 struct CadetPeerPath *iter;
294
295 for (iter = peer->path_head; NULL != iter; iter = iter->next)
296 {
297 if (2 >= iter->length)
298 {
299 GNUNET_CONTAINER_DLL_remove (peer->path_head,
300 peer->path_tail,
301 iter);
302 return iter;
303 }
304 }
305 return NULL;
306}
307
308/**
309 * Call the continuation after a message has been sent or dropped.
310 *
311 * This funcion removes the message from the queue.
312 * 235 *
313 * @param q Queue handle. 236 * @param cp Peer.
314 * @param sent #GNUNET_YES if was sent to CORE, #GNUNET_NO if dropped. 237 * @return Static string for it's ID.
315 */ 238 */
316static void 239const char *
317call_peer_cont (struct CadetPeerQueue *q, int sent); 240GCP_2s (const struct CadetPeer *cp)
241{
242 static char buf[32];
243
244 GNUNET_snprintf (buf,
245 sizeof (buf),
246 "P(%s)",
247 GNUNET_i2s (&cp->pid));
248 return buf;
249}
250
251
252/**
253 * Calculate how desirable a path is for @a cp if @a cp
254 * is at offset @a off.
255 *
256 * The 'desirability_table.c' program can be used to compute a list of
257 * sample outputs for different scenarios. Basically, we score paths
258 * lower if there are many alternatives, and higher if they are
259 * shorter than average, and very high if they are much shorter than
260 * average and without many alternatives.
261 *
262 * @param cp a peer reachable via a path
263 * @param off offset of @a cp in the path
264 * @return score how useful a path is to reach @a cp,
265 * positive scores mean path is more desirable
266 */
267double
268GCP_get_desirability_of_path (struct CadetPeer *cp,
269 unsigned int off)
270{
271 unsigned int num_alts = cp->num_paths;
272 unsigned int off_sum;
273 double avg_sum;
274 double path_delta;
275 double weight_alts;
276
277 GNUNET_assert (num_alts >= 1); /* 'path' should be in there! */
278 GNUNET_assert (0 != cp->path_dll_length);
279
280 /* We maintain 'off_sum' in 'peer' and thereby
281 avoid the SLOW recalculation each time. Kept here
282 just to document what is going on. */
283#if SLOW
284 off_sum = 0;
285 for (unsigned int j=0;j<cp->path_dll_length;j++)
286 for (struct CadetPeerPathEntry *pe = cp->path_heads[j];
287 NULL != pe;
288 pe = pe->next)
289 off_sum += j;
290 GNUNET_assert (off_sum == cp->off_sum);
291#else
292 off_sum = cp->off_sum;
293#endif
294 avg_sum = off_sum * 1.0 / cp->path_dll_length;
295 path_delta = off - avg_sum;
296 /* path_delta positiv: path off of peer above average (bad path for peer),
297 path_delta negativ: path off of peer below average (good path for peer) */
298 if (path_delta <= - 1.0)
299 weight_alts = - num_alts / path_delta; /* discount alternative paths */
300 else if (path_delta >= 1.0)
301 weight_alts = num_alts * path_delta; /* overcount alternative paths */
302 else
303 weight_alts = num_alts; /* count alternative paths normally */
318 304
319 305
320/******************************************************************************/ 306 /* off+1: long paths are generally harder to find and thus count
321/***************************** CORE CALLBACKS *********************************/ 307 a bit more as they get longer. However, above-average paths
322/******************************************************************************/ 308 still need to count less, hence the squaring of that factor. */
309 return (off + 1.0) / (weight_alts * weight_alts);
310}
323 311
324 312
325/** 313/**
326 * Method called whenever a given peer connects. 314 * This peer is no longer be needed, clean it up now.
327 * 315 *
328 * @param cls Core closure (unused). 316 * @param cls peer to clean up
329 * @param peer Peer identity this notification is about
330 * @param mq Message Queue to this peer.
331 *
332 * @return Internal closure for handlers (CadetPeer struct).
333 */ 317 */
334static void * 318static void
335core_connect_handler (void *cls, 319destroy_peer (void *cls)
336 const struct GNUNET_PeerIdentity *peer, 320{
337 struct GNUNET_MQ_Handle *mq) 321 struct CadetPeer *cp = cls;
338{ 322
339 struct CadetPeer *neighbor; 323 LOG (GNUNET_ERROR_TYPE_DEBUG,
340 struct CadetPeerPath *path; 324 "Destroying state about peer %s\n",
341 char own_id[16]; 325 GCP_2s (cp));
342 326 cp->destroy_task = NULL;
343 GCC_check_connections (); 327 GNUNET_assert (NULL == cp->t);
344 GNUNET_snprintf (own_id, 328 GNUNET_assert (NULL == cp->core_mq);
345 sizeof (own_id), 329 GNUNET_assert (0 == cp->num_paths);
346 "%s", 330 for (unsigned int i=0;i<cp->path_dll_length;i++)
347 GNUNET_i2s (&my_full_id)); 331 GNUNET_assert (NULL == cp->path_heads[i]);
348 332 GNUNET_assert (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections));
349 /* Save a path to the neighbor */ 333 GNUNET_assert (GNUNET_YES ==
350 neighbor = GCP_get (peer, GNUNET_YES); 334 GNUNET_CONTAINER_multipeermap_remove (peers,
351 if (myid == neighbor->id) 335 &cp->pid,
352 { 336 cp));
353 LOG (GNUNET_ERROR_TYPE_INFO, 337 GNUNET_free_non_null (cp->path_heads);
354 "CONNECTED %s (self)\n", 338 GNUNET_free_non_null (cp->path_tails);
355 own_id); 339 cp->path_dll_length = 0;
356 path = path_new (1); 340 if (NULL != cp->search_h)
357 } 341 {
358 else 342 GCD_search_stop (cp->search_h);
359 { 343 cp->search_h = NULL;
360 LOG (GNUNET_ERROR_TYPE_INFO, 344 }
361 "CONNECTED %s <= %s\n", 345 /* FIXME: clean up search_delayedXXX! */
362 own_id,
363 GNUNET_i2s (peer));
364 path = path_new (2);
365 path->peers[1] = neighbor->id;
366 GNUNET_PEER_change_rc (neighbor->id, 1);
367 GNUNET_assert (NULL == neighbor->core_mq);
368 neighbor->core_mq = mq;
369 }
370 path->peers[0] = myid;
371 GNUNET_PEER_change_rc (myid, 1);
372 GCP_add_path (neighbor, path, GNUNET_YES);
373
374 /* Create the connections hashmap */
375 GNUNET_assert (NULL == neighbor->connections);
376 neighbor->connections = GNUNET_CONTAINER_multishortmap_create (16,
377 GNUNET_YES);
378 GNUNET_STATISTICS_update (stats,
379 "# peers",
380 1,
381 GNUNET_NO);
382
383 if ( (NULL != GCP_get_tunnel (neighbor)) &&
384 (0 > GNUNET_CRYPTO_cmp_peer_identity (&my_full_id, peer)) )
385 {
386 GCP_connect (neighbor);
387 }
388 GCC_check_connections ();
389 346
390 return neighbor; 347 if (NULL != cp->hello_offer)
348 {
349 GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer);
350 cp->hello_offer = NULL;
351 }
352 if (NULL != cp->connectivity_suggestion)
353 {
354 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
355 cp->connectivity_suggestion = NULL;
356 }
357 GNUNET_CONTAINER_multishortmap_destroy (cp->connections);
358 if (NULL != cp->path_heap)
359 {
360 GNUNET_CONTAINER_heap_destroy (cp->path_heap);
361 cp->path_heap = NULL;
362 }
363 if (NULL != cp->heap_cleanup_task)
364 {
365 GNUNET_SCHEDULER_cancel (cp->heap_cleanup_task);
366 cp->heap_cleanup_task = NULL;
367 }
368 GNUNET_free_non_null (cp->hello);
369 /* Peer should not be freed if paths exist; if there are no paths,
370 there ought to be no connections, and without connections, no
371 notifications. Thus we can assert that mqm_head is empty at this
372 point. */
373 GNUNET_assert (NULL == cp->mqm_head);
374 GNUNET_assert (NULL == cp->mqm_ready_ptr);
375 GNUNET_free (cp);
391} 376}
392 377
393 378
394/** 379/**
395 * Method called whenever a peer disconnects. 380 * This peer is now on more "active" duty, activate processes related to it.
396 * 381 *
397 * @param cls Core closure (unused). 382 * @param cp the more-active peer
398 * @param peer Peer identity this notification is about.
399 * @param internal_cls Internal closure (CadetPeer struct).
400 */ 383 */
401static void 384static void
402core_disconnect_handler (void *cls, 385consider_peer_activate (struct CadetPeer *cp)
403 const struct GNUNET_PeerIdentity *peer,
404 void *internal_cls)
405{ 386{
406 struct CadetPeer *p = internal_cls; 387 uint32_t strength;
407 struct CadetPeerPath *direct_path; 388
408 char own_id[16]; 389 LOG (GNUNET_ERROR_TYPE_DEBUG,
409 390 "Updating peer %s activation state (%u connections)%s%s\n",
410 GCC_check_connections (); 391 GCP_2s (cp),
411 strncpy (own_id, GNUNET_i2s (&my_full_id), 16); 392 GNUNET_CONTAINER_multishortmap_size (cp->connections),
412 own_id[15] = '\0'; 393 (NULL == cp->t) ? "" : " with tunnel",
413 if (myid == p->id) 394 (NULL == cp->core_mq) ? "" : " with CORE link");
414 { 395 if (NULL != cp->destroy_task)
415 LOG (GNUNET_ERROR_TYPE_INFO, 396 {
416 "DISCONNECTED %s (self)\n", 397 /* It's active, do not destory! */
417 own_id); 398 GNUNET_SCHEDULER_cancel (cp->destroy_task);
418 } 399 cp->destroy_task = NULL;
419 else 400 }
401 if ( (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections)) &&
402 (NULL == cp->t) )
403 {
404 /* We're just on a path or directly connected; don't bother too much */
405 if (NULL != cp->connectivity_suggestion)
420 { 406 {
421 LOG (GNUNET_ERROR_TYPE_INFO, 407 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
422 "DISCONNECTED %s <= %s\n", 408 cp->connectivity_suggestion = NULL;
423 own_id, GNUNET_i2s (peer));
424 p->core_mq = NULL;
425 } 409 }
426 direct_path = pop_direct_path (p); 410 if (NULL != cp->search_h)
427 if (NULL != p->connections)
428 { 411 {
429 GNUNET_CONTAINER_multishortmap_iterate (p->connections, 412 GCD_search_stop (cp->search_h);
430 &notify_broken, 413 cp->search_h = NULL;
431 p);
432 GNUNET_CONTAINER_multishortmap_destroy (p->connections);
433 p->connections = NULL;
434 } 414 }
435 GNUNET_STATISTICS_update (stats, 415 return;
436 "# peers", 416 }
437 -1, 417 if (NULL == cp->core_mq)
438 GNUNET_NO); 418 {
439 path_destroy (direct_path); 419 /* Lacks direct connection, try to create one by querying the DHT */
440 GCC_check_connections (); 420 if ( (NULL == cp->search_h) &&
441} 421 (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) )
442 422 cp->search_h
443 423 = GCD_search (&cp->pid);
444/******************************************************************************/ 424 }
445/******************************************************************************/ 425 else
446/******************************************************************************/ 426 {
447/******************************************************************************/ 427 /* Have direct connection, stop DHT search if active */
448/******************************************************************************/ 428 if (NULL != cp->search_h)
449
450/**
451 * Check if the create_connection message has the appropriate size.
452 *
453 * @param cls Closure (unused).
454 * @param msg Message to check.
455 *
456 * @return #GNUNET_YES if size is correct, #GNUNET_NO otherwise.
457 */
458static int
459check_create (void *cls, const struct GNUNET_CADET_ConnectionCreateMessage *msg)
460{
461 uint16_t size;
462
463 size = ntohs (msg->header.size);
464 if (size < sizeof (*msg))
465 { 429 {
466 GNUNET_break_op (0); 430 GCD_search_stop (cp->search_h);
467 return GNUNET_NO; 431 cp->search_h = NULL;
468 } 432 }
469 return GNUNET_YES; 433 }
470}
471
472/**
473 * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE
474 *
475 * @param cls Closure (CadetPeer for neighbor that sent the message).
476 * @param msg Message itself.
477 */
478static void
479handle_create (void *cls, const struct GNUNET_CADET_ConnectionCreateMessage *msg)
480{
481 struct CadetPeer *peer = cls;
482 GCC_handle_create (peer, msg);
483}
484
485
486/**
487 * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK
488 *
489 * @param cls Closure (CadetPeer for neighbor that sent the message).
490 * @param msg Message itself.
491 */
492static void
493handle_confirm (void *cls, const struct GNUNET_CADET_ConnectionCreateAckMessage *msg)
494{
495 struct CadetPeer *peer = cls;
496 GCC_handle_confirm (peer, msg);
497}
498
499 434
500/** 435 /* If we have a tunnel, our urge for connections is much bigger */
501 * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN 436 strength = (NULL != cp->t) ? 32 : 1;
502 * 437 if (NULL != cp->connectivity_suggestion)
503 * @param cls Closure (CadetPeer for neighbor that sent the message). 438 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
504 * @param msg Message itself. 439 cp->connectivity_suggestion
505 */ 440 = GNUNET_ATS_connectivity_suggest (ats_ch,
506static void 441 &cp->pid,
507handle_broken (void *cls, const struct GNUNET_CADET_ConnectionBrokenMessage *msg) 442 strength);
508{
509 struct CadetPeer *peer = cls;
510 GCC_handle_broken (peer, msg);
511} 443}
512 444
513 445
514/** 446/**
515 * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY 447 * This peer may no longer be needed, consider cleaning it up.
516 * 448 *
517 * @param cls Closure (CadetPeer for neighbor that sent the message). 449 * @param cp peer to clean up
518 * @param msg Message itself.
519 */ 450 */
520static void 451static void
521handle_destroy (void *cls, const struct GNUNET_CADET_ConnectionDestroyMessage *msg) 452consider_peer_destroy (struct CadetPeer *cp);
522{
523 struct CadetPeer *peer = cls;
524 GCC_handle_destroy (peer, msg);
525}
526 453
527 454
528/** 455/**
529 * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_HOP_BY_HOP_ENCRYPTED_ACK 456 * We really no longere care about a peer, stop hogging memory with paths to it.
457 * Afterwards, see if there is more to be cleaned up about this peer.
530 * 458 *
531 * @param cls Closure (CadetPeer for neighbor that sent the message). 459 * @param cls a `struct CadetPeer`.
532 * @param msg Message itself.
533 */ 460 */
534static void 461static void
535handle_ack (void *cls, const struct GNUNET_CADET_ConnectionEncryptedAckMessage *msg) 462drop_paths (void *cls)
536{ 463{
537 struct CadetPeer *peer = cls; 464 struct CadetPeer *cp = cls;
538 GCC_handle_ack (peer, msg); 465 struct CadetPeerPath *path;
539}
540 466
541 467 cp->destroy_task = NULL;
542/** 468 while (NULL != (path = GNUNET_CONTAINER_heap_remove_root (cp->path_heap)))
543 * Handle for #GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED_POLL 469 GCPP_release (path);
544 * 470 consider_peer_destroy (cp);
545 * @param cls Closure (CadetPeer for neighbor that sent the message).
546 * @param msg Message itself.
547 */
548static void
549handle_poll (void *cls, const struct GNUNET_CADET_ConnectionHopByHopPollMessage *msg)
550{
551 struct CadetPeer *peer = cls;
552 GCC_handle_poll (peer, msg);
553} 471}
554 472
555 473
556/** 474/**
557 * Handle for #GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX 475 * This peer may no longer be needed, consider cleaning it up.
558 * 476 *
559 * @param cls Closure (CadetPeer for neighbor that sent the message). 477 * @param cp peer to clean up
560 * @param msg Message itself.
561 */ 478 */
562static void 479static void
563handle_kx (void *cls, const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg) 480consider_peer_destroy (struct CadetPeer *cp)
564{
565 struct CadetPeer *peer = cls;
566 GCC_handle_kx (peer, msg);
567}
568
569
570/**
571 * Check if the encrypted message has the appropriate size.
572 *
573 * @param cls Closure (unused).
574 * @param msg Message to check.
575 *
576 * @return #GNUNET_YES if size is correct, #GNUNET_NO otherwise.
577 */
578static int
579check_encrypted (void *cls, const struct GNUNET_CADET_TunnelEncryptedMessage *msg)
580{ 481{
581 uint16_t size; 482 struct GNUNET_TIME_Relative exp;
582 uint16_t minimum_size;
583
584 size = ntohs (msg->header.size);
585 minimum_size = sizeof (struct GNUNET_CADET_TunnelEncryptedMessage)
586 + sizeof (struct GNUNET_MessageHeader);
587
588 if (size < minimum_size)
589 {
590 GNUNET_break_op (0);
591 return GNUNET_NO;
592 }
593 return GNUNET_YES;
594}
595 483
596/** 484 if (NULL != cp->destroy_task)
597 * Handle for #GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED. 485 {
598 * 486 GNUNET_SCHEDULER_cancel (cp->destroy_task);
599 * @param cls Closure (CadetPeer for neighbor that sent the message). 487 cp->destroy_task = NULL;
600 * @param msg Message itself. 488 }
601 */ 489 if (NULL != cp->t)
602static void 490 return; /* still relevant! */
603handle_encrypted (void *cls, const struct GNUNET_CADET_TunnelEncryptedMessage *msg) 491 if (NULL != cp->core_mq)
604{ 492 return; /* still relevant! */
605 struct CadetPeer *peer = cls; 493 if (0 != GNUNET_CONTAINER_multishortmap_size (cp->connections))
606 GCC_handle_encrypted (peer, msg); 494 return; /* still relevant! */
607} 495 if ( (NULL != cp->path_heap) &&
608 496 (0 < GNUNET_CONTAINER_heap_get_size (cp->path_heap)) )
609 497 {
610/** 498 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PATH_TIMEOUT,
611 * To be called on core init/fail. 499 &drop_paths,
612 * 500 cp);
613 * @param cls Closure (config) 501 return;
614 * @param identity The public identity of this peer. 502 }
615 */ 503 if (0 != cp->num_paths)
616static void 504 return; /* still relevant! */
617core_init_notify (void *cls, 505 if (NULL != cp->hello)
618 const struct GNUNET_PeerIdentity *identity); 506 {
619 507 /* relevant only until HELLO expires */
620 508 exp = GNUNET_TIME_absolute_get_remaining (GNUNET_HELLO_get_last_expiration (cp->hello));
621static void 509 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (exp,
622connect_to_core (const struct GNUNET_CONFIGURATION_Handle *c) 510 &destroy_peer,
623{ 511 cp);
624 struct GNUNET_MQ_MessageHandler core_handlers[] = { 512 return;
625 GNUNET_MQ_hd_var_size (create, 513 }
626 GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE, 514 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PEER_TIMEOUT,
627 struct GNUNET_CADET_ConnectionCreateMessage, 515 &destroy_peer,
628 NULL), 516 cp);
629 GNUNET_MQ_hd_fixed_size (confirm,
630 GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK,
631 struct GNUNET_CADET_ConnectionCreateAckMessage,
632 NULL),
633 GNUNET_MQ_hd_fixed_size (broken,
634 GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN,
635 struct GNUNET_CADET_ConnectionBrokenMessage,
636 NULL),
637 GNUNET_MQ_hd_fixed_size (destroy,
638 GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY,
639 struct GNUNET_CADET_ConnectionDestroyMessage,
640 NULL),
641 GNUNET_MQ_hd_fixed_size (ack,
642 GNUNET_MESSAGE_TYPE_CADET_CONNECTION_HOP_BY_HOP_ENCRYPTED_ACK,
643 struct GNUNET_CADET_ConnectionEncryptedAckMessage,
644 NULL),
645 GNUNET_MQ_hd_fixed_size (poll,
646 GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED_POLL,
647 struct GNUNET_CADET_ConnectionHopByHopPollMessage,
648 NULL),
649 GNUNET_MQ_hd_fixed_size (kx,
650 GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX,
651 struct GNUNET_CADET_TunnelKeyExchangeMessage,
652 NULL),
653 GNUNET_MQ_hd_var_size (encrypted,
654 GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED,
655 struct GNUNET_CADET_TunnelEncryptedMessage,
656 NULL),
657 GNUNET_MQ_handler_end ()
658 };
659 core_handle = GNUNET_CORE_connect (c, NULL,
660 &core_init_notify,
661 &core_connect_handler,
662 &core_disconnect_handler,
663 core_handlers);
664}
665
666/******************************************************************************/
667/******************************************************************************/
668/******************************************************************************/
669/******************************************************************************/
670/******************************************************************************/
671
672/**
673 * To be called on core init/fail.
674 *
675 * @param cls Closure (config)
676 * @param identity The public identity of this peer.
677 */
678static void
679core_init_notify (void *cls,
680 const struct GNUNET_PeerIdentity *core_identity)
681{
682 const struct GNUNET_CONFIGURATION_Handle *c = cls;
683
684 LOG (GNUNET_ERROR_TYPE_DEBUG, "Core init\n");
685 if (0 != memcmp (core_identity, &my_full_id, sizeof (my_full_id)))
686 {
687 LOG (GNUNET_ERROR_TYPE_ERROR, _("Wrong CORE service\n"));
688 LOG (GNUNET_ERROR_TYPE_ERROR, " core id %s\n", GNUNET_i2s (core_identity));
689 LOG (GNUNET_ERROR_TYPE_ERROR, " my id %s\n", GNUNET_i2s (&my_full_id));
690 GNUNET_CORE_disconnect (core_handle);
691 connect_to_core (c);
692 return;
693 }
694 GML_start ();
695} 517}
696 518
697 519
698/******************************************************************************/
699/******************************** STATIC ***********************************/
700/******************************************************************************/
701
702
703/** 520/**
704 * Get priority for a queued message. 521 * Set the message queue to @a mq for peer @a cp and notify watchers.
705 *
706 * @param q Queued message
707 *
708 * @return CORE priority to use.
709 * 522 *
710 * FIXME make static 523 * @param cp peer to modify
711 * FIXME use when sending 524 * @param mq message queue to set (can be NULL)
712 */ 525 */
713enum GNUNET_CORE_Priority 526void
714get_priority (struct CadetPeerQueue *q) 527GCP_set_mq (struct CadetPeer *cp,
715{ 528 struct GNUNET_MQ_Handle *mq)
716 enum GNUNET_CORE_Priority low; 529{
717 enum GNUNET_CORE_Priority high; 530 LOG (GNUNET_ERROR_TYPE_DEBUG,
718 531 "Message queue for peer %s is now %p\n",
719 if (NULL == q) 532 GCP_2s (cp),
720 { 533 mq);
721 GNUNET_break (0); 534 cp->core_mq = mq;
722 return GNUNET_CORE_PRIO_BACKGROUND; 535 for (struct GCP_MessageQueueManager *mqm = cp->mqm_head, *next;
723 } 536 NULL != mqm;
724 537 mqm = next)
725 /* Relayed traffic has lower priority, our own traffic has higher */ 538 {
726 if (NULL == q->c || GNUNET_NO == GCC_is_origin (q->c, q->c_fwd)) 539 /* Save next pointer in case mqm gets freed by the callback */
540 next = mqm->next;
541 if (NULL == mq)
727 { 542 {
728 low = GNUNET_CORE_PRIO_BEST_EFFORT; 543 if (NULL != mqm->env)
729 high = GNUNET_CORE_PRIO_URGENT; 544 {
545 GNUNET_MQ_discard (mqm->env);
546 mqm->env = NULL;
547 mqm->cb (mqm->cb_cls,
548 GNUNET_SYSERR);
549 }
550 else
551 {
552 mqm->cb (mqm->cb_cls,
553 GNUNET_NO);
554 }
730 } 555 }
731 else 556 else
732 { 557 {
733 low = GNUNET_CORE_PRIO_URGENT; 558 GNUNET_assert (NULL == mqm->env);
734 high = GNUNET_CORE_PRIO_CRITICAL_CONTROL; 559 mqm->cb (mqm->cb_cls,
560 GNUNET_YES);
735 } 561 }
562 }
563 if ( (NULL != mq) ||
564 (NULL != cp->t) )
565 consider_peer_activate (cp);
566 else
567 consider_peer_destroy (cp);
736 568
737 /* Bulky payload has lower priority, control traffic has higher. */ 569 if ( (NULL != mq) &&
738 if (GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED == q->type) 570 (NULL != cp->t) )
739 return low; 571 {
740 return high; 572 /* have a new, direct path to the target, notify tunnel */
741} 573 struct CadetPeerPath *path;
742
743
744/**
745 * Cancel all messages queued to CORE MQ towards this peer.
746 *
747 * @param peer Peer towards which to cancel all messages.
748 */
749static void
750cancel_queued_messages (struct CadetPeer *peer)
751{
752 while (NULL != peer->q_head)
753 {
754 struct CadetPeerQueue *q;
755
756 q = peer->q_head;
757 call_peer_cont (q, GNUNET_NO);
758 GNUNET_free (q);
759 }
760}
761
762
763/**
764 * Destroy the peer_info and free any allocated resources linked to it
765 *
766 * @param peer The peer_info to destroy.
767 * @return #GNUNET_OK on success
768 */
769static int
770peer_destroy (struct CadetPeer *peer)
771{
772 struct GNUNET_PeerIdentity id;
773 struct CadetPeerPath *p;
774 struct CadetPeerPath *nextp;
775
776 GNUNET_PEER_resolve (peer->id, &id);
777 GNUNET_PEER_change_rc (peer->id, -1);
778
779 LOG (GNUNET_ERROR_TYPE_INFO,
780 "destroying peer %s\n",
781 GNUNET_i2s (&id));
782
783 if (GNUNET_YES !=
784 GNUNET_CONTAINER_multipeermap_remove (peers, &id, peer))
785 {
786 GNUNET_break (0);
787 LOG (GNUNET_ERROR_TYPE_WARNING, " peer not in peermap!!\n");
788 }
789 GCP_stop_search (peer);
790 p = peer->path_head;
791 while (NULL != p)
792 {
793 nextp = p->next;
794 GNUNET_CONTAINER_DLL_remove (peer->path_head,
795 peer->path_tail,
796 p);
797 path_destroy (p);
798 p = nextp;
799 }
800 if (NULL != peer->tunnel)
801 GCT_destroy_empty (peer->tunnel);
802 if (NULL != peer->connections)
803 {
804 GNUNET_assert (0 == GNUNET_CONTAINER_multishortmap_size (peer->connections));
805 GNUNET_CONTAINER_multishortmap_destroy (peer->connections);
806 peer->connections = NULL;
807 }
808 if (NULL != peer->hello_offer)
809 {
810 GNUNET_TRANSPORT_offer_hello_cancel (peer->hello_offer);
811 peer->hello_offer = NULL;
812 }
813 if (NULL != peer->connectivity_suggestion)
814 {
815 GNUNET_ATS_connectivity_suggest_cancel (peer->connectivity_suggestion);
816 peer->connectivity_suggestion = NULL;
817 }
818 cancel_queued_messages (peer);
819 574
820 GNUNET_free_non_null (peer->hello); 575 path = GCPP_get_path_from_route (1,
821 GNUNET_free (peer); 576 &cp->pid);
822 return GNUNET_OK; 577 GCT_consider_path (cp->t,
578 path,
579 0);
580 }
823} 581}
824 582
825 583
826/** 584/**
827 * Iterator over peer hash map entries to destroy the peer during in_shutdown. 585 * Debug function should NEVER return true in production code, useful to
586 * simulate losses for testcases.
828 * 587 *
829 * @param cls closure 588 * @return #GNUNET_YES or #GNUNET_NO with the decision to drop.
830 * @param key current key code
831 * @param value value in the hash map
832 * @return #GNUNET_YES if we should continue to iterate,
833 * #GNUNET_NO if not.
834 */ 589 */
835static int 590static int
836shutdown_peer (void *cls, 591should_I_drop (void)
837 const struct GNUNET_PeerIdentity *key,
838 void *value)
839{ 592{
840 struct CadetPeer *p = value; 593 if (0 == drop_percent)
841 struct CadetTunnel *t = p->tunnel; 594 return GNUNET_NO;
842 595 if (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
843 LOG (GNUNET_ERROR_TYPE_DEBUG, " shutting down %s\n", GCP_2s (p)); 596 101) < drop_percent)
844 if (NULL != t)
845 GCT_destroy (t);
846 p->tunnel = NULL;
847 peer_destroy (p);
848 return GNUNET_YES; 597 return GNUNET_YES;
598 return GNUNET_NO;
849} 599}
850 600
851 601
852/** 602/**
853 * Check if peer is searching for a path (either active or delayed search). 603 * Function called when CORE took one of the messages from
854 * 604 * a message queue manager and transmitted it.
855 * @param peer Peer to check
856 * @return #GNUNET_YES if there is a search active.
857 * #GNUNET_NO otherwise.
858 */
859static int
860is_searching (const struct CadetPeer *peer)
861{
862 return ( (NULL == peer->search_h) &&
863 (NULL == peer->search_delayed) ) ?
864 GNUNET_NO : GNUNET_YES;
865}
866
867
868/**
869 * @brief Start a search for a peer.
870 * 605 *
871 * @param cls Closure (Peer to search for). 606 * @param cls the `struct CadetPeeer` where we made progress
872 */ 607 */
873static void 608static void
874delayed_search (void *cls) 609mqm_send_done (void *cls);
875{
876 struct CadetPeer *peer = cls;
877
878 peer->search_delayed = NULL;
879 GCC_check_connections ();
880 GCP_start_search (peer);
881 GCC_check_connections ();
882}
883 610
884 611
885/** 612/**
886 * Returns if peer is used (has a tunnel or is neighbor). 613 * Transmit current envelope from this @a mqm.
887 * 614 *
888 * @param peer Peer to check. 615 * @param mqm mqm to transmit message for now
889 * @return #GNUNET_YES if peer is in use.
890 */ 616 */
891static int 617static void
892peer_is_used (struct CadetPeer *peer) 618mqm_execute (struct GCP_MessageQueueManager *mqm)
893{
894 struct CadetPeerPath *p;
895
896 if (NULL != peer->tunnel)
897 return GNUNET_YES;
898
899 for (p = peer->path_head; NULL != p; p = p->next)
900 {
901 if (p->length < 3)
902 return GNUNET_YES;
903 }
904 return GNUNET_NO;
905}
906
907
908/**
909 * Iterator over all the peers to get the oldest timestamp.
910 *
911 * @param cls Closure (unsued).
912 * @param key ID of the peer.
913 * @param value Peer_Info of the peer.
914 */
915static int
916peer_get_oldest (void *cls,
917 const struct GNUNET_PeerIdentity *key,
918 void *value)
919{ 619{
920 struct CadetPeer *p = value; 620 struct CadetPeer *cp = mqm->cp;
921 struct GNUNET_TIME_Absolute *abs = cls;
922
923 /* Don't count active peers */
924 if (GNUNET_YES == peer_is_used (p))
925 return GNUNET_YES;
926 621
927 if (abs->abs_value_us < p->last_contact.abs_value_us) 622 /* Move ready pointer to the next entry that might be ready. */
928 abs->abs_value_us = p->last_contact.abs_value_us; 623 if ( (mqm == cp->mqm_ready_ptr) &&
929 624 (NULL != mqm->next) )
930 return GNUNET_YES; 625 cp->mqm_ready_ptr = mqm->next;
626 /* Move entry to the end of the DLL, to be fair. */
627 if (mqm != cp->mqm_tail)
628 {
629 GNUNET_CONTAINER_DLL_remove (cp->mqm_head,
630 cp->mqm_tail,
631 mqm);
632 GNUNET_CONTAINER_DLL_insert_tail (cp->mqm_head,
633 cp->mqm_tail,
634 mqm);
635 }
636 cp->mqm_ready_counter--;
637 if (GNUNET_YES == should_I_drop ())
638 {
639 LOG (GNUNET_ERROR_TYPE_DEBUG,
640 "DROPPING message to peer %s from MQM %p\n",
641 GCP_2s (cp),
642 mqm);
643 GNUNET_MQ_discard (mqm->env);
644 mqm->env = NULL;
645 mqm_send_done (cp);
646 }
647 else
648 {
649 LOG (GNUNET_ERROR_TYPE_DEBUG,
650 "Sending to peer %s from MQM %p\n",
651 GCP_2s (cp),
652 mqm);
653 GNUNET_MQ_send (cp->core_mq,
654 mqm->env);
655 mqm->env = NULL;
656 }
657 mqm->cb (mqm->cb_cls,
658 GNUNET_YES);
931} 659}
932 660
933 661
934/** 662/**
935 * Iterator over all the peers to remove the oldest entry. 663 * Find the next ready message in the queue (starting
664 * the search from the `cp->mqm_ready_ptr`) and if possible
665 * execute the transmission.
936 * 666 *
937 * @param cls Closure (unsued). 667 * @param cp peer to try to send the next ready message to
938 * @param key ID of the peer.
939 * @param value Peer_Info of the peer.
940 */
941static int
942peer_timeout (void *cls,
943 const struct GNUNET_PeerIdentity *key,
944 void *value)
945{
946 struct CadetPeer *p = value;
947 struct GNUNET_TIME_Absolute *abs = cls;
948
949 LOG (GNUNET_ERROR_TYPE_WARNING,
950 "peer %s timeout\n", GNUNET_i2s (key));
951
952 if (p->last_contact.abs_value_us == abs->abs_value_us &&
953 GNUNET_NO == peer_is_used (p))
954 {
955 peer_destroy (p);
956 return GNUNET_NO;
957 }
958 return GNUNET_YES;
959}
960
961
962/**
963 * Delete oldest unused peer.
964 */ 668 */
965static void 669static void
966peer_delete_oldest (void) 670send_next_ready (struct CadetPeer *cp)
967{ 671{
968 struct GNUNET_TIME_Absolute abs; 672 struct GCP_MessageQueueManager *mqm;
969
970 abs = GNUNET_TIME_UNIT_FOREVER_ABS;
971
972 GNUNET_CONTAINER_multipeermap_iterate (peers,
973 &peer_get_oldest,
974 &abs);
975 GNUNET_CONTAINER_multipeermap_iterate (peers,
976 &peer_timeout,
977 &abs);
978}
979
980 673
981/** 674 if (0 == cp->mqm_ready_counter)
982 * Choose the best (yet unused) path towards a peer, 675 return;
983 * considering the tunnel properties. 676 while ( (NULL != (mqm = cp->mqm_ready_ptr)) &&
984 * 677 (NULL == mqm->env) )
985 * @param peer The destination peer. 678 cp->mqm_ready_ptr = mqm->next;
986 * @return Best current known path towards the peer, if any. 679 if (NULL == mqm)
987 */ 680 return; /* nothing to do */
988static struct CadetPeerPath * 681 mqm_execute (mqm);
989peer_get_best_path (const struct CadetPeer *peer)
990{
991 struct CadetPeerPath *best_p;
992 struct CadetPeerPath *p;
993 unsigned int best_cost;
994 unsigned int cost;
995
996 best_cost = UINT_MAX;
997 best_p = NULL;
998 for (p = peer->path_head; NULL != p; p = p->next)
999 {
1000 if (GNUNET_NO == path_is_valid (p))
1001 continue; /* Don't use invalid paths. */
1002 if (GNUNET_YES == GCT_is_path_used (peer->tunnel, p))
1003 continue; /* If path is already in use, skip it. */
1004
1005 if ((cost = GCT_get_path_cost (peer->tunnel, p)) < best_cost)
1006 {
1007 best_cost = cost;
1008 best_p = p;
1009 }
1010 }
1011 return best_p;
1012} 682}
1013 683
1014 684
1015/** 685/**
1016 * Function to process paths received for a new peer addition. The recorded 686 * Function called when CORE took one of the messages from
1017 * paths form the initial tunnel, which can be optimized later. 687 * a message queue manager and transmitted it.
1018 * Called on each result obtained for the DHT search.
1019 * 688 *
1020 * @param cls Closure (peer towards a path has been found). 689 * @param cls the `struct CadetPeeer` where we made progress
1021 * @param path Path created from the DHT query. Will be freed afterwards.
1022 */ 690 */
1023static void 691static void
1024search_handler (void *cls, const struct CadetPeerPath *path) 692mqm_send_done (void *cls)
1025{ 693{
1026 struct CadetPeer *peer = cls; 694 struct CadetPeer *cp = cls;
1027 unsigned int connection_count;
1028
1029 GCC_check_connections ();
1030 GCP_add_path_to_all (path, GNUNET_NO);
1031
1032 /* Count connections */
1033 connection_count = GCT_count_connections (peer->tunnel);
1034 695
1035 /* If we already have our minimum (or more) connections, it's enough */ 696 LOG (GNUNET_ERROR_TYPE_DEBUG,
1036 if (CONNECTIONS_PER_TUNNEL <= connection_count) 697 "Sending to peer %s completed\n",
1037 { 698 GCP_2s (cp));
1038 GCC_check_connections (); 699 send_next_ready (cp);
1039 return;
1040 }
1041
1042 if (CADET_TUNNEL_SEARCHING == GCT_get_cstate (peer->tunnel))
1043 {
1044 LOG (GNUNET_ERROR_TYPE_DEBUG, " ... connect!\n");
1045 GCP_connect (peer);
1046 }
1047 GCC_check_connections ();
1048}
1049
1050
1051/**
1052 * Test if a message type is connection management traffic
1053 * or regular payload traffic.
1054 *
1055 * @param type Message type.
1056 *
1057 * @return #GNUNET_YES if connection management, #GNUNET_NO otherwise.
1058 */
1059static int
1060is_connection_management (uint16_t type)
1061{
1062 return type == GNUNET_MESSAGE_TYPE_CADET_CONNECTION_HOP_BY_HOP_ENCRYPTED_ACK ||
1063 type == GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED_POLL;
1064} 700}
1065 701
1066 702
1067/** 703/**
1068 * Debug function should NEVER return true in production code, useful to 704 * Send the message in @a env to @a cp.
1069 * simulate losses for testcases.
1070 * 705 *
1071 * @return #GNUNET_YES or #GNUNET_NO with the decision to drop. 706 * @param mqm the message queue manager to use for transmission
707 * @param env envelope with the message to send; must NOT
708 * yet have a #GNUNET_MQ_notify_sent() callback attached to it
1072 */ 709 */
1073static int 710void
1074should_I_drop (void) 711GCP_send (struct GCP_MessageQueueManager *mqm,
712 struct GNUNET_MQ_Envelope *env)
1075{ 713{
1076 if (0 == drop_percent) 714 struct CadetPeer *cp = mqm->cp;
1077 return GNUNET_NO;
1078 715
1079 if (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 101) < drop_percent) 716 GNUNET_assert (NULL != env);
1080 return GNUNET_YES; 717 LOG (GNUNET_ERROR_TYPE_DEBUG,
1081 718 "Queueing message to peer %s in MQM %p\n",
1082 return GNUNET_NO; 719 GCP_2s (cp),
720 mqm);
721 GNUNET_assert (NULL != cp->core_mq);
722 GNUNET_assert (NULL == mqm->env);
723 GNUNET_MQ_notify_sent (env,
724 &mqm_send_done,
725 cp);
726 mqm->env = env;
727 cp->mqm_ready_counter++;
728 if (mqm != cp->mqm_ready_ptr)
729 cp->mqm_ready_ptr = cp->mqm_head;
730 if (1 == cp->mqm_ready_counter)
731 cp->mqm_ready_ptr = mqm;
732 if (0 != GNUNET_MQ_get_length (cp->core_mq))
733 return;
734 send_next_ready (cp);
1083} 735}
1084 736
1085 737
1086/******************************************************************************/
1087/******************************** API ***********************************/
1088/******************************************************************************/
1089
1090/** 738/**
1091 * Call the continuation after a message has been sent or dropped. 739 * Function called to destroy a peer now.
1092 * 740 *
1093 * This funcion removes the message from the queue. 741 * @param cls NULL
1094 * 742 * @param pid identity of the peer (unused)
1095 * @param q Queue handle. 743 * @param value the `struct CadetPeer` to clean up
1096 * @param sent #GNUNET_YES if was sent to CORE, #GNUNET_NO if dropped. 744 * @return #GNUNET_OK (continue to iterate)
1097 */ 745 */
1098static void 746static int
1099call_peer_cont (struct CadetPeerQueue *q, int sent) 747destroy_iterator_cb (void *cls,
1100{ 748 const struct GNUNET_PeerIdentity *pid,
1101 LOG (GNUNET_ERROR_TYPE_DEBUG, " core mq just sent %s\n", GC_m2s (q->type)); 749 void *value)
1102 if (NULL != q->cont)
1103 {
1104 struct GNUNET_TIME_Relative wait_time;
1105
1106 wait_time = GNUNET_TIME_absolute_get_duration (q->queue_timestamp);
1107 LOG (GNUNET_ERROR_TYPE_DEBUG,
1108 " calling callback on %s after %s\n",
1109 GCC_2s (q->c),
1110 GNUNET_STRINGS_relative_time_to_string (wait_time, GNUNET_NO));
1111 q->cont (q->cont_cls,
1112 q->c, q->c_fwd, sent,
1113 q->type,
1114 q->payload_type,
1115 q->payload_id,
1116 q->size, wait_time);
1117 q->cont = NULL;
1118 }
1119 GNUNET_CONTAINER_DLL_remove (q->peer->q_head, q->peer->q_tail, q);
1120}
1121
1122
1123/**
1124 * Function called by MQ when a message is sent to CORE.
1125 *
1126 * @param cls Closure (queue handle).
1127 */
1128static void
1129mq_sent (void *cls)
1130{ 750{
1131 struct CadetPeerQueue *q = cls; 751 struct CadetPeer *cp = value;
1132 752
1133 if (GNUNET_NO == q->management_traffic) 753 if (NULL != cp->destroy_task)
1134 { 754 {
1135 q->peer->queue_n--; 755 GNUNET_SCHEDULER_cancel (cp->destroy_task);
1136 } 756 cp->destroy_task = NULL;
1137 call_peer_cont (q, GNUNET_YES); 757 }
1138 GNUNET_free (q); 758 destroy_peer (cp);
759 return GNUNET_OK;
1139} 760}
1140 761
1141 762
1142/** 763/**
1143 * Finish the drop operation. 764 * Clean up all entries about all peers.
1144 * 765 * Must only be called after all tunnels, CORE-connections and
1145 * @param cls queue entry to finish drop for 766 * connections are down.
1146 */ 767 */
1147static void 768void
1148drop_cb (void *cls) 769GCP_destroy_all_peers ()
1149{ 770{
1150 struct CadetPeerQueue *q = cls; 771 LOG (GNUNET_ERROR_TYPE_DEBUG,
1151 772 "Destroying all peers now\n");
1152 GNUNET_MQ_discard (q->env); 773 GNUNET_CONTAINER_multipeermap_iterate (peers,
1153 call_peer_cont (q, GNUNET_YES); 774 &destroy_iterator_cb,
1154 GNUNET_free (q); 775 NULL);
1155} 776}
1156 777
1157 778
1158/** 779/**
1159 * @brief Send a message to another peer (using CORE). 780 * Drop all paths owned by this peer, and do not
781 * allow new ones to be added: We are shutting down.
1160 * 782 *
1161 * @param peer Peer towards which to queue the message. 783 * @param cp peer to drop paths to
1162 * @param message Message to send.
1163 * @param payload_type Type of the message's payload, for debug messages.
1164 * 0 if the message is a retransmission (unknown payload).
1165 * UINT16_MAX if the message does not have payload.
1166 * @param payload_id ID of the payload (MID, ACK #, etc)
1167 * @param c Connection this message belongs to (can be NULL).
1168 * @param fwd Is this a message going root->dest? (FWD ACK are NOT FWD!)
1169 * @param cont Continuation to be called once CORE has sent the message.
1170 * @param cont_cls Closure for @c cont.
1171 *
1172 * @return A handle to the message in the queue or NULL (if dropped).
1173 */ 784 */
1174struct CadetPeerQueue * 785void
1175GCP_send (struct CadetPeer *peer, 786GCP_drop_owned_paths (struct CadetPeer *cp)
1176 const struct GNUNET_MessageHeader *message,
1177 uint16_t payload_type,
1178 struct CadetEncryptedMessageIdentifier payload_id,
1179 struct CadetConnection *c,
1180 int fwd,
1181 GCP_sent cont,
1182 void *cont_cls)
1183{ 787{
1184 struct CadetPeerQueue *q; 788 struct CadetPeerPath *path;
1185 uint16_t type;
1186 uint16_t size;
1187
1188 GCC_check_connections ();
1189 type = ntohs (message->type);
1190 size = ntohs (message->size);
1191 LOG (GNUNET_ERROR_TYPE_DEBUG,
1192 "que %s (%s %4u) on conn %s (%p) %s towards %s (size %u)\n",
1193 GC_m2s (type), GC_m2s (payload_type),
1194 ntohl (payload_id.pid),
1195 GCC_2s (c), c, GC_f2s (fwd), GCP_2s (peer), size);
1196
1197 if (NULL == peer->connections)
1198 {
1199 /* We are not connected to this peer, ignore request. */
1200 GNUNET_break (0);
1201 LOG (GNUNET_ERROR_TYPE_INFO, "%s not a neighbor\n", GCP_2s (peer));
1202 GNUNET_STATISTICS_update (stats, "# messages dropped due to wrong hop", 1,
1203 GNUNET_NO);
1204 return NULL;
1205 }
1206 789
1207 q = GNUNET_new (struct CadetPeerQueue); 790 LOG (GNUNET_ERROR_TYPE_DEBUG,
1208 q->env = GNUNET_MQ_msg_copy (message); 791 "Destroying all paths to %s\n",
1209 q->peer = peer; 792 GCP_2s (cp));
1210 q->cont = cont; 793 while (NULL != (path =
1211 q->cont_cls = cont_cls; 794 GNUNET_CONTAINER_heap_remove_root (cp->path_heap)))
1212 q->queue_timestamp = GNUNET_TIME_absolute_get (); 795 GCPP_release (path);
1213 q->management_traffic = is_connection_management (type); 796 GNUNET_CONTAINER_heap_destroy (cp->path_heap);
1214 q->type = type; 797 cp->path_heap = NULL;
1215 q->size = size;
1216 q->payload_type = payload_type;
1217 q->payload_id = payload_id;
1218 q->c = c;
1219 q->c_fwd = fwd;
1220 GNUNET_MQ_notify_sent (q->env, &mq_sent, q);
1221 GNUNET_CONTAINER_DLL_insert (peer->q_head, peer->q_tail, q);
1222
1223 if (GNUNET_YES == q->management_traffic)
1224 {
1225 GNUNET_MQ_send (peer->core_mq, q->env); // FIXME implement "_urgent", use
1226 }
1227 else
1228 {
1229 if (GNUNET_YES == should_I_drop ())
1230 {
1231 LOG (GNUNET_ERROR_TYPE_WARNING,
1232 "DD %s (%s %u) on conn %s %s (random drop for testing)\n",
1233 GC_m2s (q->type),
1234 GC_m2s (q->payload_type),
1235 ntohl (q->payload_id.pid),
1236 GCC_2s (c),
1237 GC_f2s (q->c_fwd));
1238 q->drop_task = GNUNET_SCHEDULER_add_now (&drop_cb,
1239 q);
1240 return q;
1241 }
1242 GNUNET_MQ_send (peer->core_mq, q->env);
1243 peer->queue_n++;
1244 }
1245
1246 GCC_check_connections ();
1247 return q;
1248} 798}
1249 799
1250 800
1251/** 801/**
1252 * Cancel sending a message. Message must have been sent with 802 * Add an entry to the DLL of all of the paths that this peer is on.
1253 * #GCP_send before. May not be called after the notify sent
1254 * callback has been called.
1255 *
1256 * It DOES call the continuation given to #GCP_send.
1257 * 803 *
1258 * @param q Queue handle to cancel 804 * @param cp peer to modify
805 * @param entry an entry on a path
806 * @param off offset of this peer on the path
1259 */ 807 */
1260void 808void
1261GCP_send_cancel (struct CadetPeerQueue *q) 809GCP_path_entry_add (struct CadetPeer *cp,
1262{ 810 struct CadetPeerPathEntry *entry,
1263 if (NULL != q->drop_task) 811 unsigned int off)
812{
813 GNUNET_assert (cp == GCPP_get_peer_at_offset (entry->path,
814 off));
815 LOG (GNUNET_ERROR_TYPE_DEBUG,
816 "Discovered that peer %s is on path %s at offset %u\n",
817 GCP_2s (cp),
818 GCPP_2s (entry->path),
819 off);
820 if (off >= cp->path_dll_length)
1264 { 821 {
1265 GNUNET_SCHEDULER_cancel (q->drop_task); 822 unsigned int len = cp->path_dll_length;
1266 q->drop_task = NULL; 823
1267 GNUNET_MQ_discard (q->env); 824 GNUNET_array_grow (cp->path_heads,
825 len,
826 off + 4);
827 GNUNET_array_grow (cp->path_tails,
828 cp->path_dll_length,
829 off + 4);
1268 } 830 }
1269 else 831 GNUNET_CONTAINER_DLL_insert (cp->path_heads[off],
832 cp->path_tails[off],
833 entry);
834 cp->off_sum += off;
835 cp->num_paths++;
836
837 /* If we have a tunnel to this peer, tell the tunnel that there is a
838 new path available. */
839 if (NULL != cp->t)
840 GCT_consider_path (cp->t,
841 entry->path,
842 off);
843
844 if ( (NULL != cp->search_h) &&
845 (DESIRED_CONNECTIONS_PER_TUNNEL <= cp->num_paths) )
1270 { 846 {
1271 GNUNET_MQ_send_cancel (q->env); 847 /* Now I have enough paths, stop search */
848 GCD_search_stop (cp->search_h);
849 cp->search_h = NULL;
850 }
851 if (NULL != cp->destroy_task)
852 {
853 /* paths changed, this resets the destroy timeout counter
854 and aborts a destroy task that may no longer be valid
855 to have (as we now have more paths via this peer). */
856 consider_peer_destroy (cp);
1272 } 857 }
1273 call_peer_cont (q, GNUNET_NO);
1274 GNUNET_free (q);
1275} 858}
1276 859
1277 860
1278/** 861/**
1279 * Initialize the peer subsystem. 862 * Remove an entry from the DLL of all of the paths that this peer is on.
1280 * 863 *
1281 * @param c Configuration. 864 * @param cp peer to modify
1282 */ 865 * @param entry an entry on a path
1283void 866 * @param off offset of this peer on the path
1284GCP_init (const struct GNUNET_CONFIGURATION_Handle *c)
1285{
1286 cfg = c;
1287 LOG (GNUNET_ERROR_TYPE_DEBUG,
1288 "GCP_init\n");
1289 in_shutdown = GNUNET_NO;
1290 peers = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_NO);
1291 if (GNUNET_OK !=
1292 GNUNET_CONFIGURATION_get_value_number (c, "CADET", "MAX_PEERS",
1293 &max_peers))
1294 {
1295 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
1296 "CADET", "MAX_PEERS", "USING DEFAULT");
1297 max_peers = 1000;
1298 }
1299
1300 if (GNUNET_OK !=
1301 GNUNET_CONFIGURATION_get_value_number (c, "CADET", "DROP_PERCENT",
1302 &drop_percent))
1303 {
1304 drop_percent = 0;
1305 }
1306 else
1307 {
1308 LOG (GNUNET_ERROR_TYPE_WARNING, "**************************************\n");
1309 LOG (GNUNET_ERROR_TYPE_WARNING, "Cadet is running with DROP enabled.\n");
1310 LOG (GNUNET_ERROR_TYPE_WARNING, "This is NOT a good idea!\n");
1311 LOG (GNUNET_ERROR_TYPE_WARNING, "Remove DROP_PERCENT from config file.\n");
1312 LOG (GNUNET_ERROR_TYPE_WARNING, "**************************************\n");
1313 }
1314 ats_ch = GNUNET_ATS_connectivity_init (c);
1315 connect_to_core (c);
1316 if (NULL == core_handle)
1317 {
1318 GNUNET_break (0);
1319 GNUNET_SCHEDULER_shutdown ();
1320 }
1321}
1322
1323
1324/**
1325 * Shut down the peer subsystem.
1326 */ 867 */
1327void 868void
1328GCP_shutdown (void) 869GCP_path_entry_remove (struct CadetPeer *cp,
1329{ 870 struct CadetPeerPathEntry *entry,
1330 LOG (GNUNET_ERROR_TYPE_DEBUG, 871 unsigned int off)
1331 "Shutting down peer subsystem\n"); 872{
1332 in_shutdown = GNUNET_YES; 873 LOG (GNUNET_ERROR_TYPE_DEBUG,
1333 if (NULL != core_handle) 874 "Removing knowledge about peer %s beging on path %s at offset %u\n",
1334 { 875 GCP_2s (cp),
1335 GNUNET_CORE_disconnect (core_handle); 876 GCPP_2s (entry->path),
1336 core_handle = NULL; 877 off);
1337 } 878 GNUNET_CONTAINER_DLL_remove (cp->path_heads[off],
1338 GNUNET_PEER_change_rc (myid, -1); 879 cp->path_tails[off],
1339 /* With MQ API, CORE calls the disconnect handler for every peer 880 entry);
1340 * after calling GNUNET_CORE_disconnect, shutdown must occur *after* that. 881 GNUNET_assert (0 < cp->num_paths);
1341 */ 882 cp->off_sum -= off;
1342 GNUNET_CONTAINER_multipeermap_iterate (peers, 883 cp->num_paths--;
1343 &shutdown_peer, 884 if ( (NULL == cp->core_mq) &&
1344 NULL); 885 (NULL != cp->t) &&
1345 if (NULL != ats_ch) 886 (NULL == cp->search_h) &&
1346 { 887 (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) )
1347 GNUNET_ATS_connectivity_done (ats_ch); 888 cp->search_h
1348 ats_ch = NULL; 889 = GCD_search (&cp->pid);
1349 } 890 if (NULL == cp->destroy_task)
1350 GNUNET_CONTAINER_multipeermap_destroy (peers); 891 {
1351 peers = NULL; 892 /* paths changed, we might now be ready for destruction, check again */
1352} 893 consider_peer_destroy (cp);
1353 894 }
1354
1355/**
1356 * Retrieve the CadetPeer stucture associated with the peer. Optionally create
1357 * one and insert it in the appropriate structures if the peer is not known yet.
1358 *
1359 * @param peer_id Full identity of the peer.
1360 * @param create #GNUNET_YES if a new peer should be created if unknown.
1361 * #GNUNET_NO otherwise.
1362 *
1363 * @return Existing or newly created peer structure.
1364 * NULL if unknown and not requested @a create
1365 */
1366struct CadetPeer *
1367GCP_get (const struct GNUNET_PeerIdentity *peer_id, int create)
1368{
1369 struct CadetPeer *peer;
1370
1371 peer = GNUNET_CONTAINER_multipeermap_get (peers, peer_id);
1372 if (NULL == peer)
1373 {
1374 peer = GNUNET_new (struct CadetPeer);
1375 if (GNUNET_CONTAINER_multipeermap_size (peers) > max_peers)
1376 {
1377 peer_delete_oldest ();
1378 }
1379 GNUNET_assert (GNUNET_OK ==
1380 GNUNET_CONTAINER_multipeermap_put (peers,
1381 peer_id,
1382 peer,
1383 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1384 peer->id = GNUNET_PEER_intern (peer_id);
1385 }
1386 peer->last_contact = GNUNET_TIME_absolute_get ();
1387
1388 return peer;
1389}
1390
1391
1392/**
1393 * Retrieve the CadetPeer stucture associated with the
1394 * peer. Optionally create one and insert it in the appropriate
1395 * structures if the peer is not known yet.
1396 *
1397 * @param peer Short identity of the peer.
1398 * @param create #GNUNET_YES if a new peer should be created if unknown.
1399 * #GNUNET_NO otherwise.
1400 *
1401 * @return Existing or newly created peer structure.
1402 * NULL if unknown and not requested @a create
1403 */
1404struct CadetPeer *
1405GCP_get_short (const GNUNET_PEER_Id peer, int create)
1406{
1407 return GCP_get (GNUNET_PEER_resolve2 (peer), create);
1408} 895}
1409 896
1410 897
1411/** 898/**
1412 * Function called once #GNUNET_TRANSPORT_offer_hello() is done. 899 * Prune down the number of paths to this peer, we seem to
1413 * Marks the operation as finished. 900 * have way too many.
1414 * 901 *
1415 * @param cls Closure (our `struct CadetPeer`). 902 * @param cls the `struct CadetPeer` to maintain the path heap for
1416 */ 903 */
1417static void 904static void
1418hello_offer_done (void *cls) 905path_heap_cleanup (void *cls)
1419{ 906{
1420 struct CadetPeer *peer = cls; 907 struct CadetPeer *cp = cls;
908 struct CadetPeerPath *root;
1421 909
1422 peer->hello_offer = NULL; 910 cp->heap_cleanup_task = NULL;
911 while (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >=
912 2 * DESIRED_CONNECTIONS_PER_TUNNEL)
913 {
914 /* Now we have way too many, drop least desirable UNLESS it is in use!
915 (Note that this intentionally keeps highly desireable, but currently
916 unused paths around in the hope that we might be able to switch, even
917 if the number of paths exceeds the threshold.) */
918 root = GNUNET_CONTAINER_heap_peek (cp->path_heap);
919 GNUNET_assert (NULL != root);
920 if (NULL !=
921 GCPP_get_connection (root,
922 cp,
923 GCPP_get_length (root) - 1))
924 break; /* can't fix */
925 /* Got plenty of paths to this destination, and this is a low-quality
926 one that we don't care about. Allow it to die. */
927 GNUNET_assert (root ==
928 GNUNET_CONTAINER_heap_remove_root (cp->path_heap));
929 GCPP_release (root);
930 }
1423} 931}
1424 932
1425 933
1426/** 934/**
1427 * Try to establish a new connection to this peer (in its tunnel). 935 * Try adding a @a path to this @a peer. If the peer already
1428 * If the peer doesn't have any path to it yet, try to get one. 936 * has plenty of paths, return NULL.
1429 * If the peer already has some path, send a CREATE CONNECTION towards it.
1430 * 937 *
1431 * @param peer Peer to connect to. 938 * @param cp peer to which the @a path leads to
939 * @param path a path looking for an owner; may not be fully initialized yet!
940 * @param off offset of @a cp in @a path
941 * @param force force attaching the path
942 * @return NULL if this peer does not care to become a new owner,
943 * otherwise the node in the peer's path heap for the @a path.
1432 */ 944 */
1433void 945struct GNUNET_CONTAINER_HeapNode *
1434GCP_connect (struct CadetPeer *peer) 946GCP_attach_path (struct CadetPeer *cp,
947 struct CadetPeerPath *path,
948 unsigned int off,
949 int force)
1435{ 950{
1436 struct CadetTunnel *t; 951 GNUNET_CONTAINER_HeapCostType desirability;
1437 struct CadetPeerPath *path; 952 struct CadetPeerPath *root;
1438 struct CadetConnection *c; 953 GNUNET_CONTAINER_HeapCostType root_desirability;
1439 int rerun_search; 954 struct GNUNET_CONTAINER_HeapNode *hn;
1440
1441 GCC_check_connections ();
1442 LOG (GNUNET_ERROR_TYPE_DEBUG,
1443 "peer_connect towards %s\n",
1444 GCP_2s (peer));
1445 /* If we have a current hello, try to connect using it. */
1446 GCP_try_connect (peer);
1447 955
1448 t = peer->tunnel; 956 GNUNET_assert (off == GCPP_get_length (path) - 1);
1449 c = NULL; 957 GNUNET_assert (cp == GCPP_get_peer_at_offset (path,
1450 rerun_search = GNUNET_NO; 958 off));
1451 959 if (NULL == cp->path_heap)
1452 if (NULL != peer->path_head) 960 {
961 /* #GCP_drop_owned_paths() was already called, we cannot take new ones! */
962 GNUNET_assert (GNUNET_NO == force);
963 return NULL;
964 }
965 desirability = GCPP_get_desirability (path);
966 if (GNUNET_NO == force)
967 {
968 /* FIXME: desirability is not yet initialized; tricky! */
969 if (GNUNET_NO ==
970 GNUNET_CONTAINER_heap_peek2 (cp->path_heap,
971 (void **) &root,
972 &root_desirability))
1453 { 973 {
1454 LOG (GNUNET_ERROR_TYPE_DEBUG, " some path exists\n"); 974 root = NULL;
1455 path = peer_get_best_path (peer); 975 root_desirability = 0;
1456 if (NULL != path)
1457 {
1458 char *s;
1459
1460 s = path_2s (path);
1461 LOG (GNUNET_ERROR_TYPE_DEBUG, " path to use: %s\n", s);
1462 GNUNET_free (s);
1463
1464 c = GCT_use_path (t, path);
1465 if (NULL == c)
1466 {
1467 /* This case can happen when the path includes a first hop that is
1468 * not yet known to be connected.
1469 *
1470 * This happens quite often during testing when running cadet
1471 * under valgrind: core connect notifications come very late
1472 * and the DHT result has already come and created a valid
1473 * path. In this case, the peer->connections
1474 * hashmaps will be NULL and tunnel_use_path will not be able
1475 * to create a connection from that path.
1476 *
1477 * Re-running the DHT GET should give core time to callback.
1478 *
1479 * GCT_use_path -> GCC_new -> register_neighbors takes care of
1480 * updating statistics about this issue.
1481 */
1482 rerun_search = GNUNET_YES;
1483 }
1484 else
1485 {
1486 GCC_send_create (c);
1487 return;
1488 }
1489 }
1490 else
1491 {
1492 LOG (GNUNET_ERROR_TYPE_DEBUG, " but is NULL, all paths are in use\n");
1493 }
1494 } 976 }
1495 977
1496 if (GNUNET_YES == rerun_search) 978 if ( (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) &&
979 (desirability < root_desirability) )
1497 { 980 {
1498 struct GNUNET_TIME_Relative delay; 981 LOG (GNUNET_ERROR_TYPE_DEBUG,
1499 982 "Decided to not attach path %p to peer %s due to undesirability\n",
1500 GCP_stop_search (peer); 983 GCPP_2s (path),
1501 delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100); 984 GCP_2s (cp));
1502 peer->search_delayed = GNUNET_SCHEDULER_add_delayed (delay, 985 return NULL;
1503 &delayed_search,
1504 peer);
1505 GCC_check_connections ();
1506 return;
1507 } 986 }
987 }
1508 988
1509 if (GNUNET_NO == is_searching (peer)) 989 LOG (GNUNET_ERROR_TYPE_DEBUG,
1510 GCP_start_search (peer); 990 "Attaching path %s to peer %s (%s)\n",
1511 GCC_check_connections (); 991 GCPP_2s (path),
1512} 992 GCP_2s (cp),
1513 993 (GNUNET_NO == force) ? "desirable" : "forced");
1514
1515/**
1516 * Chech whether there is a direct (core level) connection to peer.
1517 *
1518 * @param peer Peer to check.
1519 *
1520 * @return #GNUNET_YES if there is a direct connection.
1521 */
1522int
1523GCP_is_neighbor (const struct CadetPeer *peer)
1524{
1525 struct CadetPeerPath *path;
1526
1527 if (NULL == peer->connections)
1528 return GNUNET_NO;
1529 994
1530 for (path = peer->path_head; NULL != path; path = path->next) 995 /* Yes, we'd like to add this path, add to our heap */
1531 { 996 hn = GNUNET_CONTAINER_heap_insert (cp->path_heap,
1532 if (3 > path->length) 997 path,
1533 return GNUNET_YES; 998 desirability);
1534 }
1535 999
1536 /* Is not a neighbor but connections is not NULL, probably disconnecting */ 1000 /* Consider maybe dropping other paths because of the new one */
1537 return GNUNET_NO; 1001 if ( (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >=
1002 2 * DESIRED_CONNECTIONS_PER_TUNNEL) &&
1003 (NULL != cp->heap_cleanup_task) )
1004 cp->heap_cleanup_task = GNUNET_SCHEDULER_add_now (&path_heap_cleanup,
1005 cp);
1006 return hn;
1538} 1007}
1539 1008
1540 1009
1541/** 1010/**
1542 * Create and initialize a new tunnel towards a peer, in case it has none. 1011 * This peer can no longer own @a path as the path
1543 * In case the peer already has a tunnel, nothing is done. 1012 * has been extended and a peer further down the line
1013 * is now the new owner.
1544 * 1014 *
1545 * Does not generate any traffic, just creates the local data structures. 1015 * @param cp old owner of the @a path
1546 * 1016 * @param path path where the ownership is lost
1547 * @param peer Peer towards which to create the tunnel. 1017 * @param hn note in @a cp's path heap that must be deleted
1548 */ 1018 */
1549void 1019void
1550GCP_add_tunnel (struct CadetPeer *peer) 1020GCP_detach_path (struct CadetPeer *cp,
1021 struct CadetPeerPath *path,
1022 struct GNUNET_CONTAINER_HeapNode *hn)
1551{ 1023{
1552 GCC_check_connections (); 1024 LOG (GNUNET_ERROR_TYPE_DEBUG,
1553 if (NULL != peer->tunnel) 1025 "Detatching path %s from peer %s\n",
1554 return; 1026 GCPP_2s (path),
1555 peer->tunnel = GCT_new (peer); 1027 GCP_2s (cp));
1556 GCC_check_connections (); 1028 GNUNET_assert (path ==
1029 GNUNET_CONTAINER_heap_remove_node (hn));
1557} 1030}
1558 1031
1559 1032
1560/** 1033/**
1561 * Add a connection to a neighboring peer. 1034 * Add a @a connection to this @a cp.
1562 *
1563 * Store that the peer is the first hop of the connection in one
1564 * direction and that on peer disconnect the connection must be
1565 * notified and destroyed, for it will no longer be valid.
1566 * 1035 *
1567 * @param peer Peer to add connection to. 1036 * @param cp peer via which the @a connection goes
1568 * @param c Connection to add. 1037 * @param cc the connection to add
1569 * @param pred #GNUNET_YES if we are predecessor, #GNUNET_NO if we are successor
1570 */ 1038 */
1571void 1039void
1572GCP_add_connection (struct CadetPeer *peer, 1040GCP_add_connection (struct CadetPeer *cp,
1573 struct CadetConnection *c, 1041 struct CadetConnection *cc)
1574 int pred) 1042{
1575{ 1043 LOG (GNUNET_ERROR_TYPE_DEBUG,
1576 LOG (GNUNET_ERROR_TYPE_DEBUG, 1044 "Adding connection %s to peer %s\n",
1577 "adding connection %s\n", 1045 GCC_2s (cc),
1578 GCC_2s (c)); 1046 GCP_2s (cp));
1579 LOG (GNUNET_ERROR_TYPE_DEBUG, 1047 GNUNET_assert (GNUNET_OK ==
1580 "to peer %s\n", 1048 GNUNET_CONTAINER_multishortmap_put (cp->connections,
1581 GCP_2s (peer)); 1049 &GCC_get_id (cc)->connection_of_tunnel,
1582 GNUNET_assert (NULL != peer->connections); 1050 cc,
1583 GNUNET_assert (GNUNET_OK == 1051 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1584 GNUNET_CONTAINER_multishortmap_put (peer->connections, 1052 if (NULL != cp->destroy_task)
1585 &GCC_get_id (c)->connection_of_tunnel, 1053 {
1586 c, 1054 GNUNET_SCHEDULER_cancel (cp->destroy_task);
1587 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); 1055 cp->destroy_task = NULL;
1588 LOG (GNUNET_ERROR_TYPE_DEBUG, 1056 }
1589 "Peer %s has now %u connections.\n",
1590 GCP_2s (peer),
1591 GNUNET_CONTAINER_multishortmap_size (peer->connections));
1592}
1593
1594
1595/**
1596 * Add the path to the peer and update the path used to reach it in case this
1597 * is the shortest.
1598 *
1599 * @param peer Destination peer to add the path to.
1600 * @param path New path to add. Last peer must be @c peer.
1601 * Path will be either used of freed if already known.
1602 * @param trusted Do we trust that this path is real?
1603 *
1604 * @return path if path was taken, pointer to existing duplicate if exists
1605 * NULL on error.
1606 */
1607struct CadetPeerPath *
1608GCP_add_path (struct CadetPeer *peer,
1609 struct CadetPeerPath *path,
1610 int trusted)
1611{
1612 struct CadetPeerPath *aux;
1613 unsigned int l;
1614 unsigned int l2;
1615
1616 GCC_check_connections ();
1617 LOG (GNUNET_ERROR_TYPE_DEBUG,
1618 "adding path [%u] to peer %s\n",
1619 path->length, GCP_2s (peer));
1620
1621 if (NULL == peer || NULL == path
1622 || path->peers[path->length - 1] != peer->id)
1623 {
1624 GNUNET_break (0);
1625 path_destroy (path);
1626 return NULL;
1627 }
1628
1629 for (l = 1; l < path->length; l++)
1630 {
1631 if (path->peers[l] == myid)
1632 {
1633 LOG (GNUNET_ERROR_TYPE_DEBUG, " shortening path by %u\n", l);
1634 for (l2 = 0; l2 < path->length - l; l2++)
1635 {
1636 path->peers[l2] = path->peers[l + l2];
1637 }
1638 path->length -= l;
1639 l = 1;
1640 path->peers = GNUNET_realloc (path->peers,
1641 path->length * sizeof (GNUNET_PEER_Id));
1642 }
1643 }
1644
1645 LOG (GNUNET_ERROR_TYPE_DEBUG, " final length: %u\n", path->length);
1646
1647 if (2 >= path->length && GNUNET_NO == trusted)
1648 {
1649 /* Only allow CORE to tell us about direct paths */
1650 path_destroy (path);
1651 return NULL;
1652 }
1653
1654 l = path_get_length (path);
1655 if (0 == l)
1656 {
1657 path_destroy (path);
1658 return NULL;
1659 }
1660
1661 GNUNET_assert (peer->id == path->peers[path->length - 1]);
1662 for (aux = peer->path_head; aux != NULL; aux = aux->next)
1663 {
1664 l2 = path_get_length (aux);
1665 if (l2 > l)
1666 {
1667 LOG (GNUNET_ERROR_TYPE_DEBUG, " added\n");
1668 GNUNET_CONTAINER_DLL_insert_before (peer->path_head,
1669 peer->path_tail, aux, path);
1670 goto finish;
1671 }
1672 else
1673 {
1674 if (l2 == l && memcmp (path->peers, aux->peers, l) == 0)
1675 {
1676 LOG (GNUNET_ERROR_TYPE_DEBUG, " already known\n");
1677 path_destroy (path);
1678 return aux;
1679 }
1680 }
1681 }
1682 GNUNET_CONTAINER_DLL_insert_tail (peer->path_head,
1683 peer->path_tail,
1684 path);
1685 LOG (GNUNET_ERROR_TYPE_DEBUG, " added last\n");
1686
1687finish:
1688 if (NULL != peer->tunnel
1689 && CONNECTIONS_PER_TUNNEL > GCT_count_connections (peer->tunnel)
1690 && 2 < path->length) /* Direct paths are handled by core_connect */
1691 {
1692 GCP_connect (peer);
1693 }
1694 GCC_check_connections ();
1695 return path;
1696} 1057}
1697 1058
1698 1059
1699/** 1060/**
1700 * Add the path to the origin peer and update the path used to reach it in case 1061 * Remove a @a connection that went via this @a cp.
1701 * this is the shortest.
1702 * The path is given in peer_info -> destination, therefore we turn the path
1703 * upside down first.
1704 *
1705 * @param peer Peer to add the path to, being the origin of the path.
1706 * @param path New path to add after being inversed.
1707 * Path will be either used or freed.
1708 * @param trusted Do we trust that this path is real?
1709 * 1062 *
1710 * @return path if path was taken, pointer to existing duplicate if exists 1063 * @param cp peer via which the @a connection went
1711 * NULL on error. 1064 * @param cc the connection to remove
1712 */ 1065 */
1713struct CadetPeerPath * 1066void
1714GCP_add_path_to_origin (struct CadetPeer *peer, 1067GCP_remove_connection (struct CadetPeer *cp,
1715 struct CadetPeerPath *path, 1068 struct CadetConnection *cc)
1716 int trusted)
1717{ 1069{
1718 if (NULL == path) 1070 LOG (GNUNET_ERROR_TYPE_DEBUG,
1719 return NULL; 1071 "Removing connection %s from peer %s\n",
1720 path_invert (path); 1072 GCC_2s (cc),
1721 return GCP_add_path (peer, path, trusted); 1073 GCP_2s (cp));
1074 GNUNET_assert (GNUNET_YES ==
1075 GNUNET_CONTAINER_multishortmap_remove (cp->connections,
1076 &GCC_get_id (cc)->connection_of_tunnel,
1077 cc));
1078 consider_peer_destroy (cp);
1722} 1079}
1723 1080
1724 1081
1725/** 1082/**
1726 * Adds a path to the info of all the peers in the path 1083 * Retrieve the CadetPeer stucture associated with the
1084 * peer. Optionally create one and insert it in the appropriate
1085 * structures if the peer is not known yet.
1727 * 1086 *
1728 * @param p Path to process. 1087 * @param peer_id Full identity of the peer.
1729 * @param confirmed Whether we know if the path works or not. 1088 * @param create #GNUNET_YES if a new peer should be created if unknown.
1089 * #GNUNET_NO to return NULL if peer is unknown.
1090 * @return Existing or newly created peer structure.
1091 * NULL if unknown and not requested @a create
1730 */ 1092 */
1731void 1093struct CadetPeer *
1732GCP_add_path_to_all (const struct CadetPeerPath *p, int confirmed) 1094GCP_get (const struct GNUNET_PeerIdentity *peer_id,
1095 int create)
1733{ 1096{
1734 unsigned int i; 1097 struct CadetPeer *cp;
1735 1098
1736 /* TODO: invert and add to origin */ 1099 cp = GNUNET_CONTAINER_multipeermap_get (peers,
1737 /* TODO: replace all "GCP_add_path" with this, make the other one static */ 1100 peer_id);
1738 GCC_check_connections (); 1101 if (NULL != cp)
1739 for (i = 0; i < p->length && p->peers[i] != myid; i++) /* skip'em */ ; 1102 return cp;
1740 for (i++; i < p->length; i++) 1103 if (GNUNET_NO == create)
1741 { 1104 return NULL;
1742 struct CadetPeer *peer; 1105 cp = GNUNET_new (struct CadetPeer);
1743 struct CadetPeerPath *copy; 1106 cp->pid = *peer_id;
1744 1107 cp->connections = GNUNET_CONTAINER_multishortmap_create (32,
1745 peer = GCP_get_short (p->peers[i], GNUNET_YES); 1108 GNUNET_YES);
1746 copy = path_duplicate (p); 1109 cp->path_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
1747 copy->length = i + 1; 1110 GNUNET_assert (GNUNET_YES ==
1748 GCP_add_path (peer, copy, 3 > p->length ? GNUNET_NO : confirmed); 1111 GNUNET_CONTAINER_multipeermap_put (peers,
1749 } 1112 &cp->pid,
1750 GCC_check_connections (); 1113 cp,
1114 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1115 LOG (GNUNET_ERROR_TYPE_DEBUG,
1116 "Creating peer %s\n",
1117 GCP_2s (cp));
1118 return cp;
1751} 1119}
1752 1120
1753 1121
1754/** 1122/**
1755 * Remove any path to the peer that has the exact same peers as the one given. 1123 * Obtain the peer identity for a `struct CadetPeer`.
1756 * 1124 *
1757 * @param peer Peer to remove the path from. 1125 * @param cp our peer handle
1758 * @param path Path to remove. Is always destroyed . 1126 * @return the peer identity
1759 */ 1127 */
1760void 1128const struct GNUNET_PeerIdentity *
1761GCP_remove_path (struct CadetPeer *peer, 1129GCP_get_id (struct CadetPeer *cp)
1762 struct CadetPeerPath *path)
1763{ 1130{
1764 struct CadetPeerPath *iter; 1131 return &cp->pid;
1765 struct CadetPeerPath *next;
1766
1767 GCC_check_connections ();
1768 GNUNET_assert (myid == path->peers[0]);
1769 GNUNET_assert (peer->id == path->peers[path->length - 1]);
1770
1771 LOG (GNUNET_ERROR_TYPE_INFO,
1772 "Removing path %p (%u) from %s\n",
1773 path, path->length, GCP_2s (peer));
1774
1775 for (iter = peer->path_head; NULL != iter; iter = next)
1776 {
1777 next = iter->next;
1778 if (0 == path_cmp (path, iter))
1779 {
1780 GNUNET_CONTAINER_DLL_remove (peer->path_head,
1781 peer->path_tail,
1782 iter);
1783 if (iter != path)
1784 path_destroy (iter);
1785 }
1786 }
1787 path_destroy (path);
1788 GCC_check_connections ();
1789} 1132}
1790 1133
1791 1134
1792/** 1135/**
1793 * Check that we are aware of a connection from a neighboring peer. 1136 * Iterate over all known peers.
1794 * 1137 *
1795 * @param peer Peer to the connection is with 1138 * @param iter Iterator.
1796 * @param c Connection that should be in the map with this peer. 1139 * @param cls Closure for @c iter.
1797 */ 1140 */
1798void 1141void
1799GCP_check_connection (const struct CadetPeer *peer, 1142GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter,
1800 const struct CadetConnection *c) 1143 void *cls)
1801{ 1144{
1802 GNUNET_assert (NULL != peer); 1145 GNUNET_CONTAINER_multipeermap_iterate (peers,
1803 GNUNET_assert (NULL != peer->connections); 1146 iter,
1804 return; // ???? 1147 cls);
1805 GNUNET_assert (GNUNET_YES ==
1806 GNUNET_CONTAINER_multishortmap_contains_value (peer->connections,
1807 &GCC_get_id (c)->connection_of_tunnel,
1808 c));
1809} 1148}
1810 1149
1811 1150
1812/** 1151/**
1813 * Remove a connection from a neighboring peer. 1152 * Count the number of known paths toward the peer.
1814 * 1153 *
1815 * @param peer Peer to remove connection from. 1154 * @param cp Peer to get path info.
1816 * @param c Connection to remove. 1155 * @return Number of known paths.
1817 */ 1156 */
1818void 1157unsigned int
1819GCP_remove_connection (struct CadetPeer *peer, 1158GCP_count_paths (const struct CadetPeer *cp)
1820 const struct CadetConnection *c)
1821{ 1159{
1822 LOG (GNUNET_ERROR_TYPE_DEBUG, 1160 return cp->num_paths;
1823 "Removing connection %s\n",
1824 GCC_2s (c));
1825 LOG (GNUNET_ERROR_TYPE_DEBUG,
1826 "from peer %s\n",
1827 GCP_2s (peer));
1828 if ( (NULL == peer) ||
1829 (NULL == peer->connections) )
1830 return;
1831 GNUNET_assert (GNUNET_YES ==
1832 GNUNET_CONTAINER_multishortmap_remove (peer->connections,
1833 &GCC_get_id (c)->connection_of_tunnel,
1834 c));
1835 LOG (GNUNET_ERROR_TYPE_DEBUG,
1836 "Peer %s remains with %u connections.\n",
1837 GCP_2s (peer),
1838 GNUNET_CONTAINER_multishortmap_size (peer->connections));
1839} 1161}
1840 1162
1841 1163
1842/** 1164/**
1843 * Start the DHT search for new paths towards the peer: we don't have 1165 * Iterate over the paths to a peer.
1844 * enough good connections.
1845 * 1166 *
1846 * @param peer Destination peer. 1167 * @param cp Peer to get path info.
1168 * @param callback Function to call for every path.
1169 * @param callback_cls Closure for @a callback.
1170 * @return Number of iterated paths.
1847 */ 1171 */
1848void 1172unsigned int
1849GCP_start_search (struct CadetPeer *peer) 1173GCP_iterate_paths (struct CadetPeer *cp,
1174 GCP_PathIterator callback,
1175 void *callback_cls)
1850{ 1176{
1851 const struct GNUNET_PeerIdentity *id; 1177 unsigned int ret = 0;
1852 struct CadetTunnel *t = peer->tunnel;
1853
1854 GCC_check_connections ();
1855 if (NULL != peer->search_h)
1856 {
1857 GNUNET_break (0);
1858 return;
1859 }
1860
1861 if (NULL != peer->search_delayed)
1862 GCP_stop_search (peer);
1863
1864 id = GNUNET_PEER_resolve2 (peer->id);
1865 peer->search_h = GCD_search (id, &search_handler, peer);
1866
1867 if (NULL == t)
1868 {
1869 /* Why would we search for a peer with no tunnel towards it? */
1870 GNUNET_break (0);
1871 return;
1872 }
1873
1874 if (CADET_TUNNEL_NEW == GCT_get_cstate (t)
1875 || 0 == GCT_count_any_connections (t))
1876 {
1877 GCT_change_cstate (t, CADET_TUNNEL_SEARCHING);
1878 }
1879 GCC_check_connections ();
1880}
1881 1178
1179 LOG (GNUNET_ERROR_TYPE_DEBUG,
1180 "Iterating over paths to peer %s%s\n",
1181 GCP_2s (cp),
1182 (NULL == cp->core_mq) ? "" : " including direct link");
1183 if (NULL != cp->core_mq)
1184 {
1185 struct CadetPeerPath *path;
1882 1186
1883/** 1187 path = GCPP_get_path_from_route (1,
1884 * Stop the DHT search for new paths towards the peer: we already have 1188 &cp->pid);
1885 * enough good connections. 1189 ret++;
1886 * 1190 if (GNUNET_NO ==
1887 * @param peer Destination peer. 1191 callback (callback_cls,
1888 */ 1192 path,
1889void 1193 0))
1890GCP_stop_search (struct CadetPeer *peer) 1194 return ret;
1891{ 1195 }
1892 GCC_check_connections (); 1196 for (unsigned int i=0;i<cp->path_dll_length;i++)
1893 if (NULL != peer->search_h) 1197 {
1894 { 1198 for (struct CadetPeerPathEntry *pe = cp->path_heads[i];
1895 GCD_search_stop (peer->search_h); 1199 NULL != pe;
1896 peer->search_h = NULL; 1200 pe = pe->next)
1897 }
1898 if (NULL != peer->search_delayed)
1899 { 1201 {
1900 GNUNET_SCHEDULER_cancel (peer->search_delayed); 1202 ret++;
1901 peer->search_delayed = NULL; 1203 if (GNUNET_NO ==
1204 callback (callback_cls,
1205 pe->path,
1206 i))
1207 return ret;
1902 } 1208 }
1903 GCC_check_connections (); 1209 }
1904} 1210 return ret;
1905
1906
1907/**
1908 * Get the Full ID of a peer.
1909 *
1910 * @param peer Peer to get from.
1911 *
1912 * @return Full ID of peer.
1913 */
1914const struct GNUNET_PeerIdentity *
1915GCP_get_id (const struct CadetPeer *peer)
1916{
1917 return GNUNET_PEER_resolve2 (peer->id);
1918} 1211}
1919 1212
1920 1213
1921/** 1214/**
1922 * Get the Short ID of a peer. 1215 * Iterate over the paths to @a cp where
1923 * 1216 * @a cp is at distance @a dist from us.
1924 * @param peer Peer to get from.
1925 * 1217 *
1926 * @return Short ID of peer. 1218 * @param cp Peer to get path info.
1219 * @param dist desired distance of @a cp to us on the path
1220 * @param callback Function to call for every path.
1221 * @param callback_cls Closure for @a callback.
1222 * @return Number of iterated paths.
1927 */ 1223 */
1928GNUNET_PEER_Id 1224unsigned int
1929GCP_get_short_id (const struct CadetPeer *peer) 1225GCP_iterate_paths_at (struct CadetPeer *cp,
1226 unsigned int dist,
1227 GCP_PathIterator callback,
1228 void *callback_cls)
1930{ 1229{
1931 return peer->id; 1230 unsigned int ret = 0;
1932}
1933
1934 1231
1935/** 1232 if (dist >= cp->path_dll_length)
1936 * Set tunnel. 1233 {
1937 * 1234 LOG (GNUNET_ERROR_TYPE_DEBUG,
1938 * If tunnel is NULL and there was a search active, stop it, as it's useless. 1235 "Asked to look for paths at distance %u, but maximum for me is < %u\n",
1939 * 1236 dist,
1940 * @param peer Peer. 1237 cp->path_dll_length);
1941 * @param t Tunnel. 1238 return 0;
1942 */ 1239 }
1943void 1240 for (struct CadetPeerPathEntry *pe = cp->path_heads[dist];
1944GCP_set_tunnel (struct CadetPeer *peer, struct CadetTunnel *t) 1241 NULL != pe;
1945{ 1242 pe = pe->next)
1946 peer->tunnel = t; 1243 {
1947 if (NULL == t && GNUNET_YES == is_searching (peer)) 1244 if (GNUNET_NO ==
1948 { 1245 callback (callback_cls,
1949 GCP_stop_search (peer); 1246 pe->path,
1950 } 1247 dist))
1248 return ret;
1249 ret++;
1250 }
1251 return ret;
1951} 1252}
1952 1253
1953 1254
1954/** 1255/**
1955 * Get the tunnel towards a peer. 1256 * Get the tunnel towards a peer.
1956 * 1257 *
1957 * @param peer Peer to get from. 1258 * @param cp Peer to get from.
1958 * 1259 * @param create #GNUNET_YES to create a tunnel if we do not have one
1959 * @return Tunnel towards peer. 1260 * @return Tunnel towards peer.
1960 */ 1261 */
1961struct CadetTunnel * 1262struct CadetTunnel *
1962GCP_get_tunnel (const struct CadetPeer *peer) 1263GCP_get_tunnel (struct CadetPeer *cp,
1264 int create)
1963{ 1265{
1964 if (NULL == peer) 1266 if (NULL == cp)
1965 return NULL; 1267 return NULL;
1966 return peer->tunnel; 1268 if ( (NULL != cp->t) ||
1269 (GNUNET_NO == create) )
1270 return cp->t;
1271 cp->t = GCT_create_tunnel (cp);
1272 consider_peer_activate (cp);
1273 return cp->t;
1967} 1274}
1968 1275
1969 1276
1970/** 1277/**
1971 * Set the hello message. 1278 * Hello offer was passed to the transport service. Mark it
1279 * as done.
1972 * 1280 *
1973 * @param peer Peer whose message to set. 1281 * @param cls the `struct CadetPeer` where the offer completed
1974 * @param hello Hello message.
1975 */ 1282 */
1976void 1283static void
1977GCP_set_hello (struct CadetPeer *peer, 1284hello_offer_done (void *cls)
1978 const struct GNUNET_HELLO_Message *hello)
1979{ 1285{
1980 struct GNUNET_HELLO_Message *old; 1286 struct CadetPeer *cp = cls;
1981 size_t size;
1982 1287
1983 GCC_check_connections (); 1288 cp->hello_offer = NULL;
1984 LOG (GNUNET_ERROR_TYPE_DEBUG, "set hello for %s\n", GCP_2s (peer));
1985 if (NULL == hello)
1986 return;
1987
1988 old = GCP_get_hello (peer);
1989 if (NULL == old)
1990 {
1991 size = GNUNET_HELLO_size (hello);
1992 peer->hello = GNUNET_malloc (size);
1993 GNUNET_memcpy (peer->hello, hello, size);
1994 }
1995 else
1996 {
1997 peer->hello = GNUNET_HELLO_merge (old, hello);
1998 GNUNET_free (old);
1999 }
2000 GCC_check_connections ();
2001} 1289}
2002 1290
2003 1291
2004/** 1292/**
2005 * Get the hello message. 1293 * We got a HELLO for a @a peer, remember it, and possibly
2006 * 1294 * trigger adequate actions (like trying to connect).
2007 * @param peer Peer whose message to get.
2008 * 1295 *
2009 * @return Hello message. 1296 * @param cp the peer we got a HELLO for
1297 * @param hello the HELLO to remember
2010 */ 1298 */
2011struct GNUNET_HELLO_Message * 1299void
2012GCP_get_hello (struct CadetPeer *peer) 1300GCP_set_hello (struct CadetPeer *cp,
1301 const struct GNUNET_HELLO_Message *hello)
2013{ 1302{
2014 struct GNUNET_TIME_Absolute expiration; 1303 struct GNUNET_HELLO_Message *mrg;
2015 struct GNUNET_TIME_Relative remaining;
2016
2017 if (NULL == peer->hello)
2018 return NULL;
2019 1304
2020 expiration = GNUNET_HELLO_get_last_expiration (peer->hello); 1305 LOG (GNUNET_ERROR_TYPE_DEBUG,
2021 remaining = GNUNET_TIME_absolute_get_remaining (expiration); 1306 "Got %u byte HELLO for peer %s\n",
2022 if (0 == remaining.rel_value_us) 1307 (unsigned int) GNUNET_HELLO_size (hello),
2023 { 1308 GCP_2s (cp));
2024 LOG (GNUNET_ERROR_TYPE_DEBUG, " get - hello expired on %s\n", 1309 if (NULL != cp->hello_offer)
2025 GNUNET_STRINGS_absolute_time_to_string (expiration)); 1310 {
2026 GNUNET_free (peer->hello); 1311 GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer);
2027 peer->hello = NULL; 1312 cp->hello_offer = NULL;
2028 } 1313 }
2029 return peer->hello; 1314 if (NULL != cp->hello)
1315 {
1316 mrg = GNUNET_HELLO_merge (hello,
1317 cp->hello);
1318 GNUNET_free (cp->hello);
1319 cp->hello = mrg;
1320 }
1321 else
1322 {
1323 cp->hello = GNUNET_memdup (hello,
1324 GNUNET_HELLO_size (hello));
1325 }
1326 cp->hello_offer
1327 = GNUNET_TRANSPORT_offer_hello (cfg,
1328 GNUNET_HELLO_get_header (cp->hello) ,
1329 &hello_offer_done,
1330 cp);
1331 /* New HELLO means cp's destruction time may change... */
1332 consider_peer_destroy (cp);
2030} 1333}
2031 1334
2032 1335
2033/** 1336/**
2034 * Try to connect to a peer on TRANSPORT level. 1337 * The tunnel to the given peer no longer exists, remove it from our
1338 * data structures, and possibly clean up the peer itself.
2035 * 1339 *
2036 * @param peer Peer to whom to connect. 1340 * @param cp the peer affected
1341 * @param t the dead tunnel
2037 */ 1342 */
2038void 1343void
2039GCP_try_connect (struct CadetPeer *peer) 1344GCP_drop_tunnel (struct CadetPeer *cp,
1345 struct CadetTunnel *t)
2040{ 1346{
2041 struct GNUNET_HELLO_Message *hello; 1347 LOG (GNUNET_ERROR_TYPE_DEBUG,
2042 struct GNUNET_MessageHeader *mh; 1348 "Dropping tunnel %s to peer %s\n",
2043 1349 GCT_2s (t),
2044 if (GNUNET_YES != 1350 GCP_2s (cp));
2045 GNUNET_CONFIGURATION_get_value_yesno (cfg, 1351 GNUNET_assert (cp->t == t);
2046 "CADET", 1352 cp->t = NULL;
2047 "DISABLE_TRY_CONNECT")) 1353 consider_peer_destroy (cp);
2048 return;
2049 GCC_check_connections ();
2050 if (GNUNET_YES == GCP_is_neighbor (peer))
2051 return;
2052 hello = GCP_get_hello (peer);
2053 if (NULL == hello)
2054 return;
2055
2056 mh = GNUNET_HELLO_get_header (hello);
2057 if (NULL != peer->hello_offer)
2058 {
2059 GNUNET_TRANSPORT_offer_hello_cancel (peer->hello_offer);
2060 peer->hello_offer = NULL;
2061 }
2062 peer->hello_offer = GNUNET_TRANSPORT_offer_hello (cfg,
2063 mh,
2064 &hello_offer_done,
2065 peer);
2066 if (NULL == peer->connectivity_suggestion)
2067 peer->connectivity_suggestion
2068 = GNUNET_ATS_connectivity_suggest (ats_ch,
2069 GCP_get_id (peer),
2070 1); /* strength */
2071 GCC_check_connections ();
2072} 1354}
2073 1355
2074 1356
2075/** 1357/**
2076 * Notify a peer that a link between two other peers is broken. If any path 1358 * Test if @a cp has a core-level connection
2077 * used that link, eliminate it.
2078 * 1359 *
2079 * @param peer Peer affected by the change. 1360 * @param cp peer to test
2080 * @param peer1 Peer whose link is broken. 1361 * @return #GNUNET_YES if @a cp has a core-level connection
2081 * @param peer2 Peer whose link is broken.
2082 */ 1362 */
2083void 1363int
2084GCP_notify_broken_link (struct CadetPeer *peer, 1364GCP_has_core_connection (struct CadetPeer *cp)
2085 const struct GNUNET_PeerIdentity *peer1,
2086 const struct GNUNET_PeerIdentity *peer2)
2087{ 1365{
2088 struct CadetPeerPath *iter; 1366 return (NULL != cp->core_mq) ? GNUNET_YES : GNUNET_NO;
2089 struct CadetPeerPath *next;
2090 unsigned int i;
2091 GNUNET_PEER_Id p1;
2092 GNUNET_PEER_Id p2;
2093
2094 GCC_check_connections ();
2095 p1 = GNUNET_PEER_search (peer1);
2096 p2 = GNUNET_PEER_search (peer2);
2097
2098 LOG (GNUNET_ERROR_TYPE_DEBUG, "Link %u-%u broken\n", p1, p2);
2099 if (0 == p1 || 0 == p2)
2100 {
2101 /* We don't even know them */
2102 return;
2103 }
2104
2105 for (iter = peer->path_head; NULL != iter; iter = next)
2106 {
2107 next = iter->next;
2108 for (i = 0; i < iter->length - 1; i++)
2109 {
2110 if ((iter->peers[i] == p1 && iter->peers[i + 1] == p2)
2111 || (iter->peers[i] == p2 && iter->peers[i + 1] == p1))
2112 {
2113 char *s;
2114
2115 s = path_2s (iter);
2116 LOG (GNUNET_ERROR_TYPE_DEBUG, " - invalidating %s\n", s);
2117 GNUNET_free (s);
2118
2119 path_invalidate (iter);
2120 }
2121 }
2122 }
2123 GCC_check_connections ();
2124} 1367}
2125 1368
2126 1369
2127/** 1370/**
2128 * Count the number of known paths toward the peer. 1371 * Start message queue change notifications.
2129 *
2130 * @param peer Peer to get path info.
2131 * 1372 *
2132 * @return Number of known paths. 1373 * @param cp peer to notify for
1374 * @param cb function to call if mq becomes available or unavailable
1375 * @param cb_cls closure for @a cb
1376 * @return handle to cancel request
2133 */ 1377 */
2134unsigned int 1378struct GCP_MessageQueueManager *
2135GCP_count_paths (const struct CadetPeer *peer) 1379GCP_request_mq (struct CadetPeer *cp,
1380 GCP_MessageQueueNotificationCallback cb,
1381 void *cb_cls)
2136{ 1382{
2137 struct CadetPeerPath *iter; 1383 struct GCP_MessageQueueManager *mqm;
2138 unsigned int i;
2139 1384
2140 for (iter = peer->path_head, i = 0; NULL != iter; iter = iter->next) 1385 mqm = GNUNET_new (struct GCP_MessageQueueManager);
2141 i++; 1386 mqm->cb = cb;
2142 1387 mqm->cb_cls = cb_cls;
2143 return i; 1388 mqm->cp = cp;
1389 GNUNET_CONTAINER_DLL_insert (cp->mqm_head,
1390 cp->mqm_tail,
1391 mqm);
1392 LOG (GNUNET_ERROR_TYPE_DEBUG,
1393 "Creating MQM %p for peer %s\n",
1394 mqm,
1395 GCP_2s (cp));
1396 if (NULL != cp->core_mq)
1397 cb (cb_cls,
1398 GNUNET_YES);
1399 return mqm;
2144} 1400}
2145 1401
2146 1402
2147/** 1403/**
2148 * Iterate over the paths to a peer. 1404 * Stops message queue change notifications.
2149 * 1405 *
2150 * @param peer Peer to get path info. 1406 * @param mqm handle matching request to cancel
2151 * @param callback Function to call for every path. 1407 * @param last_env final message to transmit, or NULL
2152 * @param cls Closure for @a callback.
2153 *
2154 * @return Number of iterated paths.
2155 */ 1408 */
2156unsigned int 1409void
2157GCP_iterate_paths (struct CadetPeer *peer, 1410GCP_request_mq_cancel (struct GCP_MessageQueueManager *mqm,
2158 GCP_path_iterator callback, 1411 struct GNUNET_MQ_Envelope *last_env)
2159 void *cls) 1412{
2160{ 1413 struct CadetPeer *cp = mqm->cp;
2161 struct CadetPeerPath *iter; 1414
2162 unsigned int i; 1415 LOG (GNUNET_ERROR_TYPE_DEBUG,
2163 1416 "Destroying MQM %p for peer %s%s\n",
2164 for (iter = peer->path_head, i = 0; NULL != iter; iter = iter->next) 1417 mqm,
1418 GCP_2s (cp),
1419 (NULL == last_env) ? "" : " with last ditch transmission");
1420 if (NULL != mqm->env)
1421 GNUNET_MQ_discard (mqm->env);
1422 if (NULL != last_env)
1423 {
1424 if (NULL != cp->core_mq)
2165 { 1425 {
2166 i++; 1426 GNUNET_MQ_notify_sent (last_env,
2167 if (GNUNET_YES != callback (cls, peer, iter)) 1427 &mqm_send_done,
2168 break; 1428 cp);
1429 GNUNET_MQ_send (cp->core_mq,
1430 last_env);
2169 } 1431 }
2170 1432 else
2171 return i; 1433 {
1434 GNUNET_MQ_discard (last_env);
1435 }
1436 }
1437 if (cp->mqm_ready_ptr == mqm)
1438 cp->mqm_ready_ptr = mqm->next;
1439 GNUNET_CONTAINER_DLL_remove (cp->mqm_head,
1440 cp->mqm_tail,
1441 mqm);
1442 GNUNET_free (mqm);
2172} 1443}
2173 1444
2174 1445
2175/** 1446/**
2176 * Iterate all known peers. 1447 * Send the message in @a env to @a cp, overriding queueing logic.
1448 * This function should only be used to send error messages outside
1449 * of flow and congestion control, similar to ICMP. Note that
1450 * the envelope may be silently discarded as well.
2177 * 1451 *
2178 * @param iter Iterator. 1452 * @param cp peer to send the message to
2179 * @param cls Closure for @c iter. 1453 * @param env envelope with the message to send
2180 */ 1454 */
2181void 1455void
2182GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter, 1456GCP_send_ooo (struct CadetPeer *cp,
2183 void *cls) 1457 struct GNUNET_MQ_Envelope *env)
2184{ 1458{
2185 GCC_check_connections (); 1459 LOG (GNUNET_ERROR_TYPE_DEBUG,
2186 GNUNET_CONTAINER_multipeermap_iterate (peers, 1460 "Sending message to %s out of management\n",
2187 iter, 1461 GCP_2s (cp));
2188 cls); 1462 if (NULL == cp->core_mq)
2189 GCC_check_connections (); 1463 {
1464 GNUNET_MQ_discard (env);
1465 return;
1466 }
1467 GNUNET_MQ_notify_sent (env,
1468 &mqm_send_done,
1469 cp);
1470 GNUNET_MQ_send (cp->core_mq,
1471 env);
2190} 1472}
2191 1473
2192 1474
2193/**
2194 * Get the static string for a peer ID.
2195 *
2196 * @param peer Peer.
2197 *
2198 * @return Static string for it's ID.
2199 */
2200const char *
2201GCP_2s (const struct CadetPeer *peer)
2202{
2203 if (NULL == peer)
2204 return "(NULL)";
2205 return GNUNET_i2s (GNUNET_PEER_resolve2 (peer->id));
2206}
2207 1475
2208 1476
2209/* end of gnunet-service-cadet_peer.c */ 1477/* end of gnunet-service-cadet-new_peer.c */
diff --git a/src/cadet/gnunet-service-cadet_peer.h b/src/cadet/gnunet-service-cadet_peer.h
index 1e206e10f..a2a6c6a92 100644
--- a/src/cadet/gnunet-service-cadet_peer.h
+++ b/src/cadet/gnunet-service-cadet_peer.h
@@ -1,6 +1,7 @@
1
1/* 2/*
2 This file is part of GNUnet. 3 This file is part of GNUnet.
3 Copyright (C) 2013 GNUnet e.V. 4 Copyright (C) 2001-2017 GNUnet e.V.
4 5
5 GNUnet is free software; you can redistribute it and/or modify 6 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published 7 it under the terms of the GNU General Public License as published
@@ -19,465 +20,375 @@
19*/ 20*/
20 21
21/** 22/**
22 * @file cadet/gnunet-service-cadet_peer.h 23 * @file cadet/gnunet-service-cadet-new_peer.h
23 * @brief cadet service; dealing with remote peers 24 * @brief Information we track per peer.
24 * @author Bartlomiej Polot 25 * @author Bartlomiej Polot
25 * 26 * @author Christian Grothoff
26 * All functions in this file should use the prefix GMP (Gnunet Cadet Peer)
27 */ 27 */
28
29#ifndef GNUNET_SERVICE_CADET_PEER_H 28#ifndef GNUNET_SERVICE_CADET_PEER_H
30#define GNUNET_SERVICE_CADET_PEER_H 29#define GNUNET_SERVICE_CADET_PEER_H
31 30
32#ifdef __cplusplus 31#include "gnunet-service-cadet.h"
33extern "C" 32#include "gnunet_hello_lib.h"
34{
35#if 0 /* keep Emacsens' auto-indent happy */
36}
37#endif
38#endif
39
40#include "platform.h"
41#include "gnunet_util_lib.h"
42#include "cadet_path.h"
43
44/**
45 * Struct containing all information regarding a given peer
46 */
47struct CadetPeer;
48 33
49/**
50 * Handle to queued messages on a peer level.
51 */
52struct CadetPeerQueue;
53
54#include "gnunet-service-cadet_connection.h"
55
56
57/**
58 * Callback called when a queued message is sent.
59 *
60 * @param cls Closure.
61 * @param c Connection this message was on.
62 * @param fwd Was this a FWD going message?
63 * @param sent Was it really sent? (Could have been canceled)
64 * @param type Type of message sent.
65 * @param payload_type Type of payload, if applicable.
66 * @param pid Message ID, or 0 if not applicable (create, destroy, etc).
67 * @param size Size of the message.
68 * @param wait Time spent waiting for core (only the time for THIS message)
69 */
70typedef void
71(*GCP_sent) (void *cls,
72 struct CadetConnection *c,
73 int fwd,
74 int sent,
75 uint16_t type,
76 uint16_t payload_type,
77 struct CadetEncryptedMessageIdentifier pid,
78 size_t size,
79 struct GNUNET_TIME_Relative wait);
80 34
81/** 35/**
82 * Peer path iterator. 36 * Get the static string for a peer ID.
83 * 37 *
84 * @param cls Closure. 38 * @param peer Peer.
85 * @param peer Peer this path is towards.
86 * @param path Path itself
87 * @return #GNUNET_YES if should keep iterating.
88 * #GNUNET_NO otherwise.
89 */
90typedef int
91(*GCP_path_iterator) (void *cls,
92 struct CadetPeer *peer,
93 struct CadetPeerPath *path);
94
95
96/******************************************************************************/
97/******************************** API ***********************************/
98/******************************************************************************/
99
100/**
101 * Initialize peer subsystem.
102 * 39 *
103 * @param c Configuration. 40 * @return Static string for it's ID.
104 */
105void
106GCP_init (const struct GNUNET_CONFIGURATION_Handle *c);
107
108/**
109 * Shut down the peer subsystem.
110 */ 41 */
111void 42const char *
112GCP_shutdown (void); 43GCP_2s (const struct CadetPeer *peer);
113 44
114 45
115/** 46/**
116 * Retrieve the CadetPeer stucture associated with the peer. Optionally create 47 * Retrieve the CadetPeer stucture associated with the
117 * one and insert it in the appropriate structures if the peer is not known yet. 48 * peer. Optionally create one and insert it in the appropriate
49 * structures if the peer is not known yet.
118 * 50 *
119 * @param peer_id Full identity of the peer. 51 * @param peer_id Full identity of the peer.
120 * @param create #GNUNET_YES if a new peer should be created if unknown. 52 * @param create #GNUNET_YES if a new peer should be created if unknown.
121 * #GNUNET_NO otherwise. 53 * #GNUNET_NO to return NULL if peer is unknown.
122 *
123 * @return Existing or newly created peer structure. 54 * @return Existing or newly created peer structure.
124 * NULL if unknown and not requested @a create 55 * NULL if unknown and not requested @a create
125 */ 56 */
126struct CadetPeer * 57struct CadetPeer *
127GCP_get (const struct GNUNET_PeerIdentity *peer_id, int create); 58GCP_get (const struct GNUNET_PeerIdentity *peer_id,
59 int create);
128 60
129 61
130/** 62/**
131 * Retrieve the CadetPeer stucture associated with the peer. Optionally create 63 * Calculate how desirable a path is for @a cp if
132 * one and insert it in the appropriate structures if the peer is not known yet. 64 * @a cp is at offset @a off in the path.
133 *
134 * @param peer Short identity of the peer.
135 * @param create #GNUNET_YES if a new peer should be created if unknown.
136 * #GNUNET_NO otherwise.
137 * 65 *
138 * @return Existing or newly created peer structure. 66 * @param cp a peer reachable via a path
139 * NULL if unknown and not requested @a create 67 * @param off offset of @a cp in a path
68 * @return score how useful a path is to reach @a cp,
69 * positive scores mean path is more desirable
140 */ 70 */
141struct CadetPeer * 71double
142GCP_get_short (const GNUNET_PEER_Id peer, int create); 72GCP_get_desirability_of_path (struct CadetPeer *cp,
143 73 unsigned int off);
144 74
145/**
146 * Try to establish a new connection to this peer (in its tunnel).
147 * If the peer doesn't have any path to it yet, try to get one.
148 * If the peer already has some path, send a CREATE CONNECTION towards it.
149 *
150 * @param peer Peer to connect to.
151 */
152void
153GCP_connect (struct CadetPeer *peer);
154 75
155/** 76/**
156 * @brief Send a message to another peer (using CORE). 77 * Obtain the peer identity for a `struct CadetPeer`.
157 * 78 *
158 * @param peer Peer towards which to queue the message. 79 * @param cp our peer handle
159 * @param message Message to send. 80 * @return the peer identity
160 * @param payload_type Type of the message's payload, for debug messages.
161 * 0 if the message is a retransmission (unknown payload).
162 * UINT16_MAX if the message does not have payload.
163 * @param payload_id ID of the payload (MID, ACK #, etc)
164 * @param c Connection this message belongs to (can be NULL).
165 * @param fwd Is this a message going root->dest? (FWD ACK are NOT FWD!)
166 * @param cont Continuation to be called once CORE has sent the message.
167 * @param cont_cls Closure for @c cont.
168 */ 81 */
169struct CadetPeerQueue * 82const struct GNUNET_PeerIdentity *
170GCP_send (struct CadetPeer *peer, 83GCP_get_id (struct CadetPeer *cp);
171 const struct GNUNET_MessageHeader *message,
172 uint16_t payload_type,
173 struct CadetEncryptedMessageIdentifier payload_id,
174 struct CadetConnection *c,
175 int fwd,
176 GCP_sent cont,
177 void *cont_cls);
178 84
179/**
180 * Cancel sending a message. Message must have been sent with
181 * #GCP_send before. May not be called after the notify sent
182 * callback has been called.
183 *
184 * It does NOT call the continuation given to #GCP_send.
185 *
186 * @param q Queue handle to cancel
187 */
188void
189GCP_send_cancel (struct CadetPeerQueue *q);
190 85
191/** 86/**
192 * Set tunnel. 87 * Iterate over all known peers.
193 * 88 *
194 * @param peer Peer. 89 * @param iter Iterator.
195 * @param t Tunnel. 90 * @param cls Closure for @c iter.
196 */ 91 */
197void 92void
198GCP_set_tunnel (struct CadetPeer *peer, struct CadetTunnel *t); 93GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter,
94 void *cls);
199 95
200 96
201/** 97/**
202 * Check whether there is a direct (core level) connection to peer. 98 * Count the number of known paths toward the peer.
203 *
204 * @param peer Peer to check.
205 * 99 *
206 * @return #GNUNET_YES if there is a direct connection. 100 * @param cp Peer to get path info.
101 * @return Number of known paths.
207 */ 102 */
208int 103unsigned int
209GCP_is_neighbor (const struct CadetPeer *peer); 104GCP_count_paths (const struct CadetPeer *cp);
210 105
211 106
212/** 107/**
213 * Create and initialize a new tunnel towards a peer, in case it has none. 108 * Drop all paths owned by this peer, and do not
214 * 109 * allow new ones to be added: We are shutting down.
215 * Does not generate any traffic, just creates the local data structures.
216 * 110 *
217 * @param peer Peer towards which to create the tunnel. 111 * @param cp peer to drop paths to
218 */ 112 */
219void 113void
220GCP_add_tunnel (struct CadetPeer *peer); 114GCP_drop_owned_paths (struct CadetPeer *cp);
221 115
222 116
223/** 117/**
224 * Add a connection to a neighboring peer. 118 * Peer path iterator.
225 *
226 * Store that the peer is the first hop of the connection in one
227 * direction and that on peer disconnect the connection must be
228 * notified and destroyed, for it will no longer be valid.
229 * 119 *
230 * @param peer Peer to add connection to. 120 * @param cls Closure.
231 * @param c Connection to add. 121 * @param path Path itself
232 * @param pred #GNUNET_YES if we are predecessor, #GNUNET_NO if we are successor 122 * @param off offset of the target peer in @a path
123 * @return #GNUNET_YES if should keep iterating.
124 * #GNUNET_NO otherwise.
233 */ 125 */
234void 126typedef int
235GCP_add_connection (struct CadetPeer *peer, 127(*GCP_PathIterator) (void *cls,
236 struct CadetConnection *c, 128 struct CadetPeerPath *path,
237 int pred); 129 unsigned int off);
238 130
239 131
240/** 132/**
241 * Add the path to the peer and update the path used to reach it in case this 133 * Iterate over the paths to a peer.
242 * is the shortest.
243 *
244 * @param peer Destination peer to add the path to.
245 * @param path New path to add. Last peer must be the peer in arg 1.
246 * Path will be either used of freed if already known.
247 * @param trusted Do we trust that this path is real?
248 * 134 *
249 * @return path if path was taken, pointer to existing duplicate if exists 135 * @param cp Peer to get path info.
250 * NULL on error. 136 * @param callback Function to call for every path.
137 * @param callback_cls Closure for @a callback.
138 * @return Number of iterated paths.
251 */ 139 */
252struct CadetPeerPath * 140unsigned int
253GCP_add_path (struct CadetPeer *peer, 141GCP_iterate_paths (struct CadetPeer *cp,
254 struct CadetPeerPath *p, 142 GCP_PathIterator callback,
255 int trusted); 143 void *callback_cls);
256 144
257 145
258/** 146/**
259 * Add the path to the origin peer and update the path used to reach it in case 147 * Iterate over the paths to @a peer where
260 * this is the shortest. 148 * @a peer is at distance @a dist from us.
261 * The path is given in peer_info -> destination, therefore we turn the path
262 * upside down first.
263 * 149 *
264 * @param peer Peer to add the path to, being the origin of the path. 150 * @param cp Peer to get path info.
265 * @param path New path to add after being inversed. 151 * @param dist desired distance of @a peer to us on the path
266 * Path will be either used or freed. 152 * @param callback Function to call for every path.
267 * @param trusted Do we trust that this path is real? 153 * @param callback_cls Closure for @a callback.
268 * 154 * @return Number of iterated paths.
269 * @return path if path was taken, pointer to existing duplicate if exists
270 * NULL on error.
271 */ 155 */
272struct CadetPeerPath * 156unsigned int
273GCP_add_path_to_origin (struct CadetPeer *peer, 157GCP_iterate_paths_at (struct CadetPeer *cp,
274 struct CadetPeerPath *path, 158 unsigned int dist,
275 int trusted); 159 GCP_PathIterator callback,
160 void *callback_cls);
161
276 162
277/** 163/**
278 * Adds a path to the info of all the peers in the path 164 * Remove an entry from the DLL of all of the paths that this peer is on.
279 * 165 *
280 * @param p Path to process. 166 * @param cp peer to modify
281 * @param confirmed Whether we know if the path works or not. 167 * @param entry an entry on a path
168 * @param off offset of this peer on the path
282 */ 169 */
283void 170void
284GCP_add_path_to_all (const struct CadetPeerPath *p, int confirmed); 171GCP_path_entry_remove (struct CadetPeer *cp,
172 struct CadetPeerPathEntry *entry,
173 unsigned int off);
285 174
286 175
287/** 176/**
288 * Remove any path to the peer that has the extact same peers as the one given. 177 * Add an entry to the DLL of all of the paths that this peer is on.
289 * 178 *
290 * @param peer Peer to remove the path from. 179 * @param cp peer to modify
291 * @param path Path to remove. Is always destroyed . 180 * @param entry an entry on a path
181 * @param off offset of this peer on the path
292 */ 182 */
293void 183void
294GCP_remove_path (struct CadetPeer *peer, 184GCP_path_entry_add (struct CadetPeer *cp,
295 struct CadetPeerPath *path); 185 struct CadetPeerPathEntry *entry,
186 unsigned int off);
296 187
297 188
298/** 189/**
299 * Check that we are aware of a connection from a neighboring peer. 190 * Get the tunnel towards a peer.
300 * 191 *
301 * @param peer Peer to the connection is with 192 * @param cp Peer to get from.
302 * @param c Connection that should be in the map with this peer. 193 * @param create #GNUNET_YES to create a tunnel if we do not have one
194 * @return Tunnel towards peer.
303 */ 195 */
304void 196struct CadetTunnel *
305GCP_check_connection (const struct CadetPeer *peer, 197GCP_get_tunnel (struct CadetPeer *cp,
306 const struct CadetConnection *c); 198 int create);
307 199
308 200
309/** 201/**
310 * Remove a connection from a neighboring peer. 202 * The tunnel to the given peer no longer exists, remove it from our
203 * data structures, and possibly clean up the peer itself.
311 * 204 *
312 * @param peer Peer to remove connection from. 205 * @param cp the peer affected
313 * @param c Connection to remove. 206 * @param t the dead tunnel
314 */ 207 */
315void 208void
316GCP_remove_connection (struct CadetPeer *peer, 209GCP_drop_tunnel (struct CadetPeer *cp,
317 const struct CadetConnection *c); 210 struct CadetTunnel *t);
318 211
319 212
320/** 213/**
321 * Start the DHT search for new paths towards the peer: we don't have 214 * Try adding a @a path to this @a cp. If the peer already
322 * enough good connections. 215 * has plenty of paths, return NULL.
323 * 216 *
324 * @param peer Destination peer. 217 * @param cp peer to which the @a path leads to
218 * @param path a path looking for an owner; may not be fully initialized yet!
219 * @param off offset of @a cp in @a path
220 * @param force for attaching the path
221 * @return NULL if this peer does not care to become a new owner,
222 * otherwise the node in the peer's path heap for the @a path.
325 */ 223 */
326void 224struct GNUNET_CONTAINER_HeapNode *
327GCP_start_search (struct CadetPeer *peer); 225GCP_attach_path (struct CadetPeer *cp,
226 struct CadetPeerPath *path,
227 unsigned int off,
228 int force);
328 229
329 230
330/** 231/**
331 * Stop the DHT search for new paths towards the peer: we already have 232 * This peer can no longer own @a path as the path
332 * enough good connections. 233 * has been extended and a peer further down the line
234 * is now the new owner.
333 * 235 *
334 * @param peer Destination peer. 236 * @param cp old owner of the @a path
237 * @param path path where the ownership is lost
238 * @param hn note in @a cp's path heap that must be deleted
335 */ 239 */
336void 240void
337GCP_stop_search (struct CadetPeer *peer); 241GCP_detach_path (struct CadetPeer *cp,
242 struct CadetPeerPath *path,
243 struct GNUNET_CONTAINER_HeapNode *hn);
338 244
339 245
340/** 246/**
341 * Get the Full ID of a peer. 247 * Add a @a connection to this @a cp.
342 *
343 * @param peer Peer to get from.
344 * 248 *
345 * @return Full ID of peer. 249 * @param cp peer via which the @a connection goes
250 * @param cc the connection to add
346 */ 251 */
347const struct GNUNET_PeerIdentity * 252void
348GCP_get_id (const struct CadetPeer *peer); 253GCP_add_connection (struct CadetPeer *cp,
254 struct CadetConnection *cc);
349 255
350 256
351/** 257/**
352 * Get the Short ID of a peer. 258 * Remove a @a connection that went via this @a cp.
353 * 259 *
354 * @param peer Peer to get from. 260 * @param cp peer via which the @a connection went
355 * 261 * @param cc the connection to remove
356 * @return Short ID of peer.
357 */ 262 */
358GNUNET_PEER_Id 263void
359GCP_get_short_id (const struct CadetPeer *peer); 264GCP_remove_connection (struct CadetPeer *cp,
265 struct CadetConnection *cc);
360 266
361 267
362/** 268/**
363 * Get the tunnel towards a peer. 269 * We got a HELLO for a @a cp, remember it, and possibly
364 * 270 * trigger adequate actions (like trying to connect).
365 * @param peer Peer to get from.
366 * 271 *
367 * @return Tunnel towards peer. 272 * @param cp the peer we got a HELLO for
273 * @param hello the HELLO to remember
368 */ 274 */
369struct CadetTunnel * 275void
370GCP_get_tunnel (const struct CadetPeer *peer); 276GCP_set_hello (struct CadetPeer *cp,
277 const struct GNUNET_HELLO_Message *hello);
371 278
372 279
373/** 280/**
374 * Set the hello message. 281 * Clean up all entries about all peers.
375 * 282 * Must only be called after all tunnels, CORE-connections and
376 * @param peer Peer whose message to set. 283 * connections are down.
377 * @param hello Hello message.
378 */ 284 */
379void 285void
380GCP_set_hello (struct CadetPeer *peer, 286GCP_destroy_all_peers (void);
381 const struct GNUNET_HELLO_Message *hello);
382 287
383 288
384/** 289/**
385 * Get the hello message. 290 * Data structure used to track whom we have to notify about changes
386 * 291 * in our ability to transmit to a given peer.
387 * @param peer Peer whose message to get.
388 * 292 *
389 * @return Hello message. 293 * All queue managers will be given equal chance for sending messages
294 * to @a cp. This construct this guarantees fairness for access to @a
295 * cp among the different message queues. Each connection or route
296 * will have its respective message queue managers for each direction.
390 */ 297 */
391struct GNUNET_HELLO_Message * 298struct GCP_MessageQueueManager;
392GCP_get_hello (struct CadetPeer *peer);
393 299
394 300
395/** 301/**
396 * Try to connect to a peer on TRANSPORT level. 302 * Function to call with updated message queue object.
397 * 303 *
398 * @param peer Peer to whom to connect. 304 * @param cls closure
305 * @param available #GNUNET_YES if sending is now possible,
306 * #GNUNET_NO if sending is no longer possible
307 * #GNUNET_SYSERR if sending is no longer possible
308 * and the last envelope was discarded
399 */ 309 */
400void 310typedef void
401GCP_try_connect (struct CadetPeer *peer); 311(*GCP_MessageQueueNotificationCallback)(void *cls,
312 int available);
313
402 314
403/** 315/**
404 * Notify a peer that a link between two other peers is broken. If any path 316 * Start message queue change notifications. Will create a new slot
405 * used that link, eliminate it. 317 * to manage the message queue to the given @a cp.
406 * 318 *
407 * @param peer Peer affected by the change. 319 * @param cp peer to notify for
408 * @param peer1 Peer whose link is broken. 320 * @param cb function to call if mq becomes available or unavailable
409 * @param peer2 Peer whose link is broken. 321 * @param cb_cls closure for @a cb
322 * @return handle to cancel request
410 */ 323 */
411void 324struct GCP_MessageQueueManager *
412GCP_notify_broken_link (struct CadetPeer *peer, 325GCP_request_mq (struct CadetPeer *cp,
413 const struct GNUNET_PeerIdentity *peer1, 326 GCP_MessageQueueNotificationCallback cb,
414 const struct GNUNET_PeerIdentity *peer2); 327 void *cb_cls);
415 328
416 329
417/** 330/**
418 * Count the number of known paths toward the peer. 331 * Test if @a cp has a core-level connection
419 *
420 * @param peer Peer to get path info.
421 * 332 *
422 * @return Number of known paths. 333 * @param cp peer to test
334 * @return #GNUNET_YES if @a cp has a core-level connection
423 */ 335 */
424unsigned int 336int
425GCP_count_paths (const struct CadetPeer *peer); 337GCP_has_core_connection (struct CadetPeer *cp);
338
426 339
427/** 340/**
428 * Iterate over the paths to a peer. 341 * Send the message in @a env via a @a mqm. Must only be called at
429 * 342 * most once after the respective
430 * @param peer Peer to get path info. 343 * #GCP_MessageQueueNotificationCallback was called with `available`
431 * @param callback Function to call for every path. 344 * set to #GNUNET_YES, and not after the callback was called with
432 * @param cls Closure for @a callback. 345 * `available` set to #GNUNET_NO or #GNUNET_SYSERR.
433 * 346 *
434 * @return Number of iterated paths. 347 * @param mqm message queue manager for the transmission
348 * @param env envelope with the message to send; must NOT
349 * yet have a #GNUNET_MQ_notify_sent() callback attached to it
435 */ 350 */
436unsigned int 351void
437GCP_iterate_paths (struct CadetPeer *peer, 352GCP_send (struct GCP_MessageQueueManager *mqm,
438 GCP_path_iterator callback, 353 struct GNUNET_MQ_Envelope *env);
439 void *cls);
440 354
441 355
442/** 356/**
443 * Iterate all known peers. 357 * Send the message in @a env to @a cp, overriding queueing logic.
358 * This function should only be used to send error messages outside
359 * of flow and congestion control, similar to ICMP. Note that
360 * the envelope may be silently discarded as well.
444 * 361 *
445 * @param iter Iterator. 362 * @param cp peer to send the message to
446 * @param cls Closure for @c iter. 363 * @param env envelope with the message to send
447 */ 364 */
448void 365void
449GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter, 366GCP_send_ooo (struct CadetPeer *cp,
450 void *cls); 367 struct GNUNET_MQ_Envelope *env);
451 368
452 369
453/** 370/**
454 * Get the static string for a peer ID. 371 * Stops message queue change notifications and sends a last message.
455 * 372 * In practice, this is implemented by sending that @a last_env
456 * @param peer Peer. 373 * message immediately (if any), ignoring queue order.
457 * 374 *
458 * @return Static string for it's ID. 375 * @param mqm handle matching request to cancel
376 * @param last_env final message to transmit, or NULL
459 */ 377 */
460const char * 378void
461GCP_2s (const struct CadetPeer *peer); 379GCP_request_mq_cancel (struct GCP_MessageQueueManager *mqm,
380 struct GNUNET_MQ_Envelope *last_env);
462 381
463 382
464/** 383/**
465 * Log all kinds of info about a peer. 384 * Set the message queue to @a mq for peer @a cp and notify watchers.
466 * 385 *
467 * @param peer Peer. 386 * @param cp peer to modify
387 * @param mq message queue to set (can be NULL)
468 */ 388 */
469void 389void
470GCP_debug (const struct CadetPeer *p, 390GCP_set_mq (struct CadetPeer *cp,
471 enum GNUNET_ErrorType level); 391 struct GNUNET_MQ_Handle *mq);
472
473 392
474#if 0 /* keep Emacsens' auto-indent happy */
475{
476#endif
477#ifdef __cplusplus
478}
479#endif
480 393
481/* ifndef GNUNET_CADET_SERVICE_PEER_H */
482#endif 394#endif
483/* end of gnunet-cadet-service_peer.h */
diff --git a/src/cadet/gnunet-service-cadet_tunnel.c b/src/cadet/gnunet-service-cadet_tunnel.c
deleted file mode 100644
index a94e8f4ff..000000000
--- a/src/cadet/gnunet-service-cadet_tunnel.c
+++ /dev/null
@@ -1,3501 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2013, 2017 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20/**
21 * @file cadet/gnunet-service-cadet_tunnel.c
22 * @brief logical links between CADET clients
23 * @author Bartlomiej Polot
24 */
25#include "platform.h"
26#include "gnunet_util_lib.h"
27#include "gnunet_signatures.h"
28#include "gnunet_statistics_service.h"
29#include "cadet_protocol.h"
30#include "cadet_path.h"
31#include "gnunet-service-cadet_tunnel.h"
32#include "gnunet-service-cadet_connection.h"
33#include "gnunet-service-cadet_channel.h"
34#include "gnunet-service-cadet_peer.h"
35
36#define LOG(level, ...) GNUNET_log_from(level,"cadet-tun",__VA_ARGS__)
37#define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-tun",__VA_ARGS__)
38
39#define REKEY_WAIT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5)
40
41#if !defined(GNUNET_CULL_LOGGING)
42 #define DUMP_KEYS_TO_STDERR GNUNET_YES
43#else
44 #define DUMP_KEYS_TO_STDERR GNUNET_NO
45#endif
46
47#define MIN_TUNNEL_BUFFER 8
48#define MAX_TUNNEL_BUFFER 64
49#define MAX_SKIPPED_KEYS 64
50#define MAX_KEY_GAP 256
51#define AX_HEADER_SIZE (sizeof (uint32_t) * 2\
52 + sizeof (struct GNUNET_CRYPTO_EcdhePublicKey))
53
54/******************************************************************************/
55/******************************** STRUCTS **********************************/
56/******************************************************************************/
57
58struct CadetTChannel
59{
60 struct CadetTChannel *next;
61 struct CadetTChannel *prev;
62 struct CadetChannel *ch;
63};
64
65
66/**
67 * Entry in list of connections used by tunnel, with metadata.
68 */
69struct CadetTConnection
70{
71 /**
72 * Next in DLL.
73 */
74 struct CadetTConnection *next;
75
76 /**
77 * Prev in DLL.
78 */
79 struct CadetTConnection *prev;
80
81 /**
82 * Connection handle.
83 */
84 struct CadetConnection *c;
85
86 /**
87 * Creation time, to keep oldest connection alive.
88 */
89 struct GNUNET_TIME_Absolute created;
90
91 /**
92 * Connection throughput, to keep fastest connection alive.
93 */
94 uint32_t throughput;
95};
96
97
98/**
99 * Struct to old keys for skipped messages while advancing the Axolotl ratchet.
100 */
101struct CadetTunnelSkippedKey
102{
103 /**
104 * DLL next.
105 */
106 struct CadetTunnelSkippedKey *next;
107
108 /**
109 * DLL prev.
110 */
111 struct CadetTunnelSkippedKey *prev;
112
113 /**
114 * When was this key stored (for timeout).
115 */
116 struct GNUNET_TIME_Absolute timestamp;
117
118 /**
119 * Header key.
120 */
121 struct GNUNET_CRYPTO_SymmetricSessionKey HK;
122
123 /**
124 * Message key.
125 */
126 struct GNUNET_CRYPTO_SymmetricSessionKey MK;
127
128 /**
129 * Key number for a given HK.
130 */
131 unsigned int Kn;
132};
133
134
135/**
136 * Axolotl data, according to https://github.com/trevp/axolotl/wiki .
137 */
138struct CadetTunnelAxolotl
139{
140 /**
141 * A (double linked) list of stored message keys and associated header keys
142 * for "skipped" messages, i.e. messages that have not been
143 * received despite the reception of more recent messages, (head).
144 */
145 struct CadetTunnelSkippedKey *skipped_head;
146
147 /**
148 * Skipped messages' keys DLL, tail.
149 */
150 struct CadetTunnelSkippedKey *skipped_tail;
151
152 /**
153 * Elements in @a skipped_head <-> @a skipped_tail.
154 */
155 unsigned int skipped;
156
157 /**
158 * 32-byte root key which gets updated by DH ratchet.
159 */
160 struct GNUNET_CRYPTO_SymmetricSessionKey RK;
161
162 /**
163 * 32-byte header key (send).
164 */
165 struct GNUNET_CRYPTO_SymmetricSessionKey HKs;
166
167 /**
168 * 32-byte header key (recv)
169 */
170 struct GNUNET_CRYPTO_SymmetricSessionKey HKr;
171
172 /**
173 * 32-byte next header key (send).
174 */
175 struct GNUNET_CRYPTO_SymmetricSessionKey NHKs;
176
177 /**
178 * 32-byte next header key (recv).
179 */
180 struct GNUNET_CRYPTO_SymmetricSessionKey NHKr;
181
182 /**
183 * 32-byte chain keys (used for forward-secrecy updating, send).
184 */
185 struct GNUNET_CRYPTO_SymmetricSessionKey CKs;
186
187 /**
188 * 32-byte chain keys (used for forward-secrecy updating, recv).
189 */
190 struct GNUNET_CRYPTO_SymmetricSessionKey CKr;
191
192 /**
193 * ECDH for key exchange (A0 / B0).
194 */
195 struct GNUNET_CRYPTO_EcdhePrivateKey *kx_0;
196
197 /**
198 * ECDH Ratchet key (send).
199 */
200 struct GNUNET_CRYPTO_EcdhePrivateKey *DHRs;
201
202 /**
203 * ECDH Ratchet key (recv).
204 */
205 struct GNUNET_CRYPTO_EcdhePublicKey DHRr;
206
207 /**
208 * Message number (reset to 0 with each new ratchet, next message to send).
209 */
210 uint32_t Ns;
211
212 /**
213 * Message number (reset to 0 with each new ratchet, next message to recv).
214 */
215 uint32_t Nr;
216
217 /**
218 * Previous message numbers (# of msgs sent under prev ratchet)
219 */
220 uint32_t PNs;
221
222 /**
223 * True (#GNUNET_YES) if we have to send a new ratchet key in next msg.
224 */
225 int ratchet_flag;
226
227 /**
228 * Number of messages recieved since our last ratchet advance.
229 * - If this counter = 0, we cannot send a new ratchet key in next msg.
230 * - If this counter > 0, we can (but don't yet have to) send a new key.
231 */
232 unsigned int ratchet_allowed;
233
234 /**
235 * Number of messages recieved since our last ratchet advance.
236 * - If this counter = 0, we cannot send a new ratchet key in next msg.
237 * - If this counter > 0, we can (but don't yet have to) send a new key.
238 */
239 unsigned int ratchet_counter;
240
241 /**
242 * When does this ratchet expire and a new one is triggered.
243 */
244 struct GNUNET_TIME_Absolute ratchet_expiration;
245};
246
247
248/**
249 * Struct containing all information regarding a tunnel to a peer.
250 */
251struct CadetTunnel
252{
253 /**
254 * Endpoint of the tunnel.
255 */
256 struct CadetPeer *peer;
257
258 /**
259 * Axolotl info.
260 */
261 struct CadetTunnelAxolotl *ax;
262
263 /**
264 * State of the tunnel connectivity.
265 */
266 enum CadetTunnelCState cstate;
267
268 /**
269 * State of the tunnel encryption.
270 */
271 enum CadetTunnelEState estate;
272
273 /**
274 * Peer's ephemeral key, to recreate @c e_key and @c d_key when own ephemeral
275 * key changes.
276 */
277 struct GNUNET_CRYPTO_EcdhePublicKey peers_ephemeral_key;
278
279 /**
280 * Encryption ("our") key. It is only "confirmed" if kx_ctx is NULL.
281 */
282 struct GNUNET_CRYPTO_SymmetricSessionKey e_key;
283
284 /**
285 * Decryption ("their") key. It is only "confirmed" if kx_ctx is NULL.
286 */
287 struct GNUNET_CRYPTO_SymmetricSessionKey d_key;
288
289 /**
290 * Task to start the rekey process.
291 */
292 struct GNUNET_SCHEDULER_Task *rekey_task;
293
294 /**
295 * Paths that are actively used to reach the destination peer.
296 */
297 struct CadetTConnection *connection_head;
298 struct CadetTConnection *connection_tail;
299
300 /**
301 * Next connection number.
302 */
303 uint32_t next_cid;
304
305 /**
306 * Channels inside this tunnel.
307 */
308 struct CadetTChannel *channel_head;
309 struct CadetTChannel *channel_tail;
310
311 /**
312 * Channel ID for the next created channel.
313 */
314 struct GNUNET_CADET_ChannelTunnelNumber next_ctn;
315
316 /**
317 * Destroy flag: if true, destroy on last message.
318 */
319 struct GNUNET_SCHEDULER_Task * destroy_task;
320
321 /**
322 * Queued messages, to transmit once tunnel gets connected.
323 */
324 struct CadetTunnelDelayed *tq_head;
325 struct CadetTunnelDelayed *tq_tail;
326
327 /**
328 * Task to trim connections if too many are present.
329 */
330 struct GNUNET_SCHEDULER_Task * trim_connections_task;
331
332 /**
333 * Ephemeral message in the queue (to avoid queueing more than one).
334 */
335 struct CadetConnectionQueue *ephm_h;
336
337 /**
338 * Pong message in the queue.
339 */
340 struct CadetConnectionQueue *pong_h;
341};
342
343
344/**
345 * Struct used to save messages in a non-ready tunnel to send once connected.
346 */
347struct CadetTunnelDelayed
348{
349 /**
350 * DLL
351 */
352 struct CadetTunnelDelayed *next;
353 struct CadetTunnelDelayed *prev;
354
355 /**
356 * Tunnel.
357 */
358 struct CadetTunnel *t;
359
360 /**
361 * Tunnel queue given to the channel to cancel request. Update on send_queued.
362 */
363 struct CadetTunnelQueue *tq;
364
365 /**
366 * Message to send.
367 */
368 /* struct GNUNET_MessageHeader *msg; */
369};
370
371
372/**
373 * Handle for messages queued but not yet sent.
374 */
375struct CadetTunnelQueue
376{
377 /**
378 * Connection queue handle, to cancel if necessary.
379 */
380 struct CadetConnectionQueue *cq;
381
382 /**
383 * Handle in case message hasn't been given to a connection yet.
384 */
385 struct CadetTunnelDelayed *tqd;
386
387 /**
388 * Continuation to call once sent.
389 */
390 GCT_sent cont;
391
392 /**
393 * Closure for @c cont.
394 */
395 void *cont_cls;
396};
397
398
399/******************************************************************************/
400/******************************* GLOBALS ***********************************/
401/******************************************************************************/
402
403/**
404 * Global handle to the statistics service.
405 */
406extern struct GNUNET_STATISTICS_Handle *stats;
407
408/**
409 * Local peer own ID (memory efficient handle).
410 */
411extern GNUNET_PEER_Id myid;
412
413/**
414 * Local peer own ID (full value).
415 */
416extern struct GNUNET_PeerIdentity my_full_id;
417
418
419/**
420 * Don't try to recover tunnels if shutting down.
421 */
422extern int shutting_down;
423
424
425/**
426 * Set of all tunnels, in order to trigger a new exchange on rekey.
427 * Indexed by peer's ID.
428 */
429static struct GNUNET_CONTAINER_MultiPeerMap *tunnels;
430
431/**
432 * Own Peer ID private key.
433 */
434const static struct GNUNET_CRYPTO_EddsaPrivateKey *id_key;
435
436
437/******************************** AXOLOTL ************************************/
438
439/**
440 * How many messages are needed to trigger a ratchet advance.
441 */
442static unsigned long long ratchet_messages;
443
444/**
445 * How long until we trigger a ratched advance.
446 */
447static struct GNUNET_TIME_Relative ratchet_time;
448
449
450/******************************************************************************/
451/******************************** STATIC ***********************************/
452/******************************************************************************/
453
454/**
455 * Get string description for tunnel connectivity state.
456 *
457 * @param cs Tunnel state.
458 *
459 * @return String representation.
460 */
461static const char *
462cstate2s (enum CadetTunnelCState cs)
463{
464 static char buf[32];
465
466 switch (cs)
467 {
468 case CADET_TUNNEL_NEW:
469 return "CADET_TUNNEL_NEW";
470 case CADET_TUNNEL_SEARCHING:
471 return "CADET_TUNNEL_SEARCHING";
472 case CADET_TUNNEL_WAITING:
473 return "CADET_TUNNEL_WAITING";
474 case CADET_TUNNEL_READY:
475 return "CADET_TUNNEL_READY";
476 case CADET_TUNNEL_SHUTDOWN:
477 return "CADET_TUNNEL_SHUTDOWN";
478 default:
479 SPRINTF (buf, "%u (UNKNOWN STATE)", cs);
480 return buf;
481 }
482 return "";
483}
484
485
486/**
487 * Get string description for tunnel encryption state.
488 *
489 * @param es Tunnel state.
490 *
491 * @return String representation.
492 */
493static const char *
494estate2s (enum CadetTunnelEState es)
495{
496 static char buf[32];
497
498 switch (es)
499 {
500 case CADET_TUNNEL_KEY_UNINITIALIZED:
501 return "CADET_TUNNEL_KEY_UNINITIALIZED";
502 case CADET_TUNNEL_KEY_AX_SENT:
503 return "CADET_TUNNEL_KEY_AX_SENT";
504 case CADET_TUNNEL_KEY_AX_AUTH_SENT:
505 return "CADET_TUNNEL_KEY_AX_AUTH_SENT";
506 case CADET_TUNNEL_KEY_OK:
507 return "CADET_TUNNEL_KEY_OK";
508 case CADET_TUNNEL_KEY_REKEY:
509 return "CADET_TUNNEL_KEY_REKEY";
510 default:
511 SPRINTF (buf, "%u (UNKNOWN STATE)", es);
512 return buf;
513 }
514 return "";
515}
516
517
518/**
519 * @brief Check if tunnel is ready to send traffic.
520 *
521 * Tunnel must be connected and with encryption correctly set up.
522 *
523 * @param t Tunnel to check.
524 *
525 * @return #GNUNET_YES if ready, #GNUNET_NO otherwise
526 */
527static int
528is_ready (struct CadetTunnel *t)
529{
530 int ready;
531 int conn_ok;
532 int enc_ok;
533
534 conn_ok = CADET_TUNNEL_READY == t->cstate;
535 enc_ok = CADET_TUNNEL_KEY_OK == t->estate
536 || CADET_TUNNEL_KEY_REKEY == t->estate
537 || CADET_TUNNEL_KEY_AX_AUTH_SENT == t->estate;
538 ready = conn_ok && enc_ok;
539 ready = ready || GCT_is_loopback (t);
540 return ready;
541}
542
543
544/**
545 * Get the channel's buffer. ONLY FOR NON-LOOPBACK CHANNELS!!
546 *
547 * @param tch Tunnel's channel handle.
548 *
549 * @return Amount of messages the channel can still buffer towards the client.
550 */
551static unsigned int
552get_channel_buffer (const struct CadetTChannel *tch)
553{
554 int fwd;
555
556 /* If channel is incoming, is terminal in the FWD direction and fwd is YES */
557 fwd = GCCH_is_terminal (tch->ch, GNUNET_YES);
558
559 return GCCH_get_buffer (tch->ch, fwd);
560}
561
562
563/**
564 * Get the channel's allowance status.
565 *
566 * @param tch Tunnel's channel handle.
567 *
568 * @return #GNUNET_YES if we allowed the client to send data to us.
569 */
570static int
571get_channel_allowed (const struct CadetTChannel *tch)
572{
573 int fwd;
574
575 /* If channel is outgoing, is origin in the FWD direction and fwd is YES */
576 fwd = GCCH_is_origin (tch->ch, GNUNET_YES);
577
578 return GCCH_get_allowed (tch->ch, fwd);
579}
580
581
582/**
583 * Get the connection's buffer.
584 *
585 * @param tc Tunnel's connection handle.
586 *
587 * @return Amount of messages the connection can still buffer.
588 */
589static unsigned int
590get_connection_buffer (const struct CadetTConnection *tc)
591{
592 int fwd;
593
594 /* If connection is outgoing, is origin in the FWD direction and fwd is YES */
595 fwd = GCC_is_origin (tc->c, GNUNET_YES);
596
597 return GCC_get_buffer (tc->c, fwd);
598}
599
600
601/**
602 * Get the connection's allowance.
603 *
604 * @param tc Tunnel's connection handle.
605 *
606 * @return Amount of messages we have allowed the next peer to send us.
607 */
608static unsigned int
609get_connection_allowed (const struct CadetTConnection *tc)
610{
611 int fwd;
612
613 /* If connection is outgoing, is origin in the FWD direction and fwd is YES */
614 fwd = GCC_is_origin (tc->c, GNUNET_YES);
615
616 return GCC_get_allowed (tc->c, fwd);
617}
618
619
620/**
621 * Create a new Axolotl ephemeral (ratchet) key.
622 *
623 * @param t Tunnel.
624 */
625static void
626new_ephemeral (struct CadetTunnel *t)
627{
628 GNUNET_free_non_null (t->ax->DHRs);
629 t->ax->DHRs = GNUNET_CRYPTO_ecdhe_key_create();
630 #if DUMP_KEYS_TO_STDERR
631 {
632 struct GNUNET_CRYPTO_EcdhePublicKey pub;
633 GNUNET_CRYPTO_ecdhe_key_get_public (t->ax->DHRs, &pub);
634 LOG (GNUNET_ERROR_TYPE_DEBUG, " new DHRs generated: pub %s\n",
635 GNUNET_i2s ((struct GNUNET_PeerIdentity *) &pub));
636 }
637 #endif
638}
639
640
641/**
642 * Calculate HMAC.
643 *
644 * @param plaintext Content to HMAC.
645 * @param size Size of @c plaintext.
646 * @param iv Initialization vector for the message.
647 * @param key Key to use.
648 * @param hmac[out] Destination to store the HMAC.
649 */
650static void
651t_hmac (const void *plaintext, size_t size,
652 uint32_t iv, const struct GNUNET_CRYPTO_SymmetricSessionKey *key,
653 struct GNUNET_ShortHashCode *hmac)
654{
655 static const char ctx[] = "cadet authentication key";
656 struct GNUNET_CRYPTO_AuthKey auth_key;
657 struct GNUNET_HashCode hash;
658
659#if DUMP_KEYS_TO_STDERR
660 LOG (GNUNET_ERROR_TYPE_INFO, " HMAC %u bytes with key %s\n", size,
661 GNUNET_i2s ((struct GNUNET_PeerIdentity *) key));
662#endif
663 GNUNET_CRYPTO_hmac_derive_key (&auth_key, key,
664 &iv, sizeof (iv),
665 key, sizeof (*key),
666 ctx, sizeof (ctx),
667 NULL);
668 /* Two step: CADET_Hash is only 256 bits, HashCode is 512. */
669 GNUNET_CRYPTO_hmac (&auth_key, plaintext, size, &hash);
670 GNUNET_memcpy (hmac, &hash, sizeof (*hmac));
671}
672
673
674/**
675 * Perform a HMAC.
676 *
677 * @param key Key to use.
678 * @param hash[out] Resulting HMAC.
679 * @param source Source key material (data to HMAC).
680 * @param len Length of @a source.
681 */
682static void
683t_ax_hmac_hash (struct GNUNET_CRYPTO_SymmetricSessionKey *key,
684 struct GNUNET_HashCode *hash,
685 void *source, unsigned int len)
686{
687 static const char ctx[] = "axolotl HMAC-HASH";
688 struct GNUNET_CRYPTO_AuthKey auth_key;
689
690 GNUNET_CRYPTO_hmac_derive_key (&auth_key, key,
691 ctx, sizeof (ctx),
692 NULL);
693 GNUNET_CRYPTO_hmac (&auth_key, source, len, hash);
694}
695
696
697/**
698 * Derive a key from a HMAC-HASH.
699 *
700 * @param key Key to use for the HMAC.
701 * @param out Key to generate.
702 * @param source Source key material (data to HMAC).
703 * @param len Length of @a source.
704 */
705static void
706t_hmac_derive_key (struct GNUNET_CRYPTO_SymmetricSessionKey *key,
707 struct GNUNET_CRYPTO_SymmetricSessionKey *out,
708 void *source, unsigned int len)
709{
710 static const char ctx[] = "axolotl derive key";
711 struct GNUNET_HashCode h;
712
713 t_ax_hmac_hash (key, &h, source, len);
714 GNUNET_CRYPTO_kdf (out, sizeof (*out), ctx, sizeof (ctx),
715 &h, sizeof (h), NULL);
716}
717
718
719/**
720 * Encrypt data with the axolotl tunnel key.
721 *
722 * @param t Tunnel whose key to use.
723 * @param dst Destination for the encrypted data.
724 * @param src Source of the plaintext. Can overlap with @c dst.
725 * @param size Size of the plaintext.
726 *
727 * @return Size of the encrypted data.
728 */
729static int
730t_ax_encrypt (struct CadetTunnel *t, void *dst, const void *src, size_t size)
731{
732 struct GNUNET_CRYPTO_SymmetricSessionKey MK;
733 struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
734 struct CadetTunnelAxolotl *ax;
735 size_t out_size;
736
737 CADET_TIMING_START;
738
739 ax = t->ax;
740 ax->ratchet_counter++;
741 if (GNUNET_YES == ax->ratchet_allowed
742 && (ratchet_messages <= ax->ratchet_counter
743 || 0 == GNUNET_TIME_absolute_get_remaining (ax->ratchet_expiration).rel_value_us))
744 {
745 ax->ratchet_flag = GNUNET_YES;
746 }
747
748 if (GNUNET_YES == ax->ratchet_flag)
749 {
750 /* Advance ratchet */
751 struct GNUNET_CRYPTO_SymmetricSessionKey keys[3];
752 struct GNUNET_HashCode dh;
753 struct GNUNET_HashCode hmac;
754 static const char ctx[] = "axolotl ratchet";
755
756 new_ephemeral (t);
757 ax->HKs = ax->NHKs;
758
759 /* RK, NHKs, CKs = KDF( HMAC-HASH(RK, DH(DHRs, DHRr)) ) */
760 GNUNET_CRYPTO_ecc_ecdh (ax->DHRs, &ax->DHRr, &dh);
761 t_ax_hmac_hash (&ax->RK, &hmac, &dh, sizeof (dh));
762 GNUNET_CRYPTO_kdf (keys, sizeof (keys), ctx, sizeof (ctx),
763 &hmac, sizeof (hmac), NULL);
764 ax->RK = keys[0];
765 ax->NHKs = keys[1];
766 ax->CKs = keys[2];
767
768 ax->PNs = ax->Ns;
769 ax->Ns = 0;
770 ax->ratchet_flag = GNUNET_NO;
771 ax->ratchet_allowed = GNUNET_NO;
772 ax->ratchet_counter = 0;
773 ax->ratchet_expiration =
774 GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get(), ratchet_time);
775 }
776
777 t_hmac_derive_key (&ax->CKs, &MK, "0", 1);
778 GNUNET_CRYPTO_symmetric_derive_iv (&iv, &MK, NULL, 0, NULL);
779
780 #if DUMP_KEYS_TO_STDERR
781 LOG (GNUNET_ERROR_TYPE_DEBUG, " CKs: %s\n",
782 GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->CKs));
783 LOG (GNUNET_ERROR_TYPE_INFO, " AX_ENC with key %u: %s\n", ax->Ns,
784 GNUNET_i2s ((struct GNUNET_PeerIdentity *) &MK));
785 #endif
786
787 out_size = GNUNET_CRYPTO_symmetric_encrypt (src, size, &MK, &iv, dst);
788 t_hmac_derive_key (&ax->CKs, &ax->CKs, "1", 1);
789
790 CADET_TIMING_END;
791
792 return out_size;
793}
794
795
796/**
797 * Decrypt data with the axolotl tunnel key.
798 *
799 * @param t Tunnel whose key to use.
800 * @param dst Destination for the decrypted data.
801 * @param src Source of the ciphertext. Can overlap with @c dst.
802 * @param size Size of the ciphertext.
803 *
804 * @return Size of the decrypted data.
805 */
806static int
807t_ax_decrypt (struct CadetTunnel *t, void *dst, const void *src, size_t size)
808{
809 struct GNUNET_CRYPTO_SymmetricSessionKey MK;
810 struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
811 struct CadetTunnelAxolotl *ax;
812 size_t out_size;
813
814 CADET_TIMING_START;
815
816 ax = t->ax;
817
818 t_hmac_derive_key (&ax->CKr, &MK, "0", 1);
819 GNUNET_CRYPTO_symmetric_derive_iv (&iv, &MK, NULL, 0, NULL);
820
821 #if DUMP_KEYS_TO_STDERR
822 LOG (GNUNET_ERROR_TYPE_DEBUG, " CKr: %s\n",
823 GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->CKr));
824 LOG (GNUNET_ERROR_TYPE_INFO, " AX_DEC with key %u: %s\n", ax->Nr,
825 GNUNET_i2s ((struct GNUNET_PeerIdentity *) &MK));
826 #endif
827
828 GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader));
829 out_size = GNUNET_CRYPTO_symmetric_decrypt (src, size, &MK, &iv, dst);
830 GNUNET_assert (out_size == size);
831
832 t_hmac_derive_key (&ax->CKr, &ax->CKr, "1", 1);
833
834 CADET_TIMING_END;
835
836 return out_size;
837}
838
839
840/**
841 * Encrypt header with the axolotl header key.
842 *
843 * @param t Tunnel whose key to use.
844 * @param msg Message whose header to encrypt.
845 */
846static void
847t_h_encrypt (struct CadetTunnel *t, struct GNUNET_CADET_TunnelEncryptedMessage *msg)
848{
849 struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
850 struct CadetTunnelAxolotl *ax;
851 size_t out_size;
852
853 CADET_TIMING_START;
854 ax = t->ax;
855 GNUNET_CRYPTO_symmetric_derive_iv (&iv, &ax->HKs, NULL, 0, NULL);
856
857 #if DUMP_KEYS_TO_STDERR
858 LOG (GNUNET_ERROR_TYPE_INFO, " AX_ENC_H with key %s\n",
859 GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->HKs));
860 #endif
861
862 out_size = GNUNET_CRYPTO_symmetric_encrypt (&msg->Ns, AX_HEADER_SIZE,
863 &ax->HKs, &iv, &msg->Ns);
864
865 GNUNET_assert (AX_HEADER_SIZE == out_size);
866 CADET_TIMING_END;
867}
868
869
870/**
871 * Decrypt header with the current axolotl header key.
872 *
873 * @param t Tunnel whose current ax HK to use.
874 * @param src Message whose header to decrypt.
875 * @param dst Where to decrypt header to.
876 */
877static void
878t_h_decrypt (struct CadetTunnel *t, const struct GNUNET_CADET_TunnelEncryptedMessage *src,
879 struct GNUNET_CADET_TunnelEncryptedMessage *dst)
880{
881 struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
882 struct CadetTunnelAxolotl *ax;
883 size_t out_size;
884
885 CADET_TIMING_START;
886
887 ax = t->ax;
888 GNUNET_CRYPTO_symmetric_derive_iv (&iv, &ax->HKr, NULL, 0, NULL);
889
890 #if DUMP_KEYS_TO_STDERR
891 LOG (GNUNET_ERROR_TYPE_INFO, " AX_DEC_H with key %s\n",
892 GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->HKr));
893 #endif
894
895 out_size = GNUNET_CRYPTO_symmetric_decrypt (&src->Ns, AX_HEADER_SIZE,
896 &ax->HKr, &iv, &dst->Ns);
897
898 GNUNET_assert (AX_HEADER_SIZE == out_size);
899
900 CADET_TIMING_END;
901}
902
903
904/**
905 * Decrypt and verify data with the appropriate tunnel key and verify that the
906 * data has not been altered since it was sent by the remote peer.
907 *
908 * @param t Tunnel whose key to use.
909 * @param dst Destination for the plaintext.
910 * @param src Source of the message. Can overlap with @c dst.
911 * @param size Size of the message.
912 *
913 * @return Size of the decrypted data, -1 if an error was encountered.
914 */
915static int
916try_old_ax_keys (struct CadetTunnel *t, void *dst,
917 const struct GNUNET_CADET_TunnelEncryptedMessage *src, size_t size)
918{
919 struct CadetTunnelSkippedKey *key;
920 struct GNUNET_ShortHashCode *hmac;
921 struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
922 struct GNUNET_CADET_TunnelEncryptedMessage plaintext_header;
923 struct GNUNET_CRYPTO_SymmetricSessionKey *valid_HK;
924 size_t esize;
925 size_t res;
926 size_t len;
927 unsigned int N;
928
929 LOG (GNUNET_ERROR_TYPE_DEBUG, "Trying old keys\n");
930 hmac = &plaintext_header.hmac;
931 esize = size - sizeof (struct GNUNET_CADET_TunnelEncryptedMessage);
932
933 /* Find a correct Header Key */
934 for (key = t->ax->skipped_head; NULL != key; key = key->next)
935 {
936 #if DUMP_KEYS_TO_STDERR
937 LOG (GNUNET_ERROR_TYPE_DEBUG, " Trying hmac with key %s\n",
938 GNUNET_i2s ((struct GNUNET_PeerIdentity *) &key->HK));
939 #endif
940 t_hmac (&src->Ns, AX_HEADER_SIZE + esize, 0, &key->HK, hmac);
941 if (0 == memcmp (hmac, &src->hmac, sizeof (*hmac)))
942 {
943 LOG (GNUNET_ERROR_TYPE_DEBUG, " hmac correct\n");
944 valid_HK = &key->HK;
945 break;
946 }
947 }
948 if (NULL == key)
949 return -1;
950
951 /* Should've been checked in -cadet_connection.c handle_cadet_encrypted. */
952 GNUNET_assert (size > sizeof (struct GNUNET_CADET_TunnelEncryptedMessage));
953 len = size - sizeof (struct GNUNET_CADET_TunnelEncryptedMessage);
954 GNUNET_assert (len >= sizeof (struct GNUNET_MessageHeader));
955
956 /* Decrypt header */
957 GNUNET_CRYPTO_symmetric_derive_iv (&iv, &key->HK, NULL, 0, NULL);
958 res = GNUNET_CRYPTO_symmetric_decrypt (&src->Ns, AX_HEADER_SIZE,
959 &key->HK, &iv, &plaintext_header.Ns);
960 GNUNET_assert (AX_HEADER_SIZE == res);
961 LOG (GNUNET_ERROR_TYPE_DEBUG, " Message %u, previous: %u\n",
962 ntohl (plaintext_header.Ns), ntohl (plaintext_header.PNs));
963
964 /* Find the correct Message Key */
965 N = ntohl (plaintext_header.Ns);
966 while (NULL != key && N != key->Kn)
967 key = key->next;
968 if (NULL == key || 0 != memcmp (&key->HK, valid_HK, sizeof (*valid_HK)))
969 return -1;
970
971 #if DUMP_KEYS_TO_STDERR
972 LOG (GNUNET_ERROR_TYPE_INFO, " AX_DEC_H with skipped key %s\n",
973 GNUNET_i2s ((struct GNUNET_PeerIdentity *) &key->HK));
974 LOG (GNUNET_ERROR_TYPE_INFO, " AX_DEC with skipped key %u: %s\n",
975 key->Kn, GNUNET_i2s ((struct GNUNET_PeerIdentity *) &key->MK));
976 #endif
977
978 /* Decrypt payload */
979 GNUNET_CRYPTO_symmetric_derive_iv (&iv, &key->MK, NULL, 0, NULL);
980 res = GNUNET_CRYPTO_symmetric_decrypt (&src[1], len, &key->MK, &iv, dst);
981
982 /* Remove key */
983 GNUNET_CONTAINER_DLL_remove (t->ax->skipped_head, t->ax->skipped_tail, key);
984 t->ax->skipped--;
985 GNUNET_free (key); /* GNUNET_free overwrites memory with 0xbaadf00d */
986
987 return res;
988}
989
990
991/**
992 * Delete a key from the list of skipped keys.
993 *
994 * @param t Tunnel to delete from.
995 * @param HKr Header Key to use.
996 */
997static void
998store_skipped_key (struct CadetTunnel *t,
999 const struct GNUNET_CRYPTO_SymmetricSessionKey *HKr)
1000{
1001 struct CadetTunnelSkippedKey *key;
1002
1003 key = GNUNET_new (struct CadetTunnelSkippedKey);
1004 key->timestamp = GNUNET_TIME_absolute_get ();
1005 key->Kn = t->ax->Nr;
1006 key->HK = t->ax->HKr;
1007 t_hmac_derive_key (&t->ax->CKr, &key->MK, "0", 1);
1008 #if DUMP_KEYS_TO_STDERR
1009 LOG (GNUNET_ERROR_TYPE_DEBUG, " storing MK for Nr %u: %s\n",
1010 key->Kn, GNUNET_i2s ((struct GNUNET_PeerIdentity *) &key->MK));
1011 LOG (GNUNET_ERROR_TYPE_DEBUG, " for CKr: %s\n",
1012 GNUNET_i2s ((struct GNUNET_PeerIdentity *) &t->ax->CKr));
1013 #endif
1014 t_hmac_derive_key (&t->ax->CKr, &t->ax->CKr, "1", 1);
1015 GNUNET_CONTAINER_DLL_insert (t->ax->skipped_head, t->ax->skipped_tail, key);
1016 t->ax->Nr++;
1017 t->ax->skipped++;
1018}
1019
1020
1021/**
1022 * Delete a key from the list of skipped keys.
1023 *
1024 * @param t Tunnel to delete from.
1025 * @param key Key to delete.
1026 */
1027static void
1028delete_skipped_key (struct CadetTunnel *t, struct CadetTunnelSkippedKey *key)
1029{
1030 GNUNET_CONTAINER_DLL_remove (t->ax->skipped_head, t->ax->skipped_tail, key);
1031 GNUNET_free (key);
1032 t->ax->skipped--;
1033}
1034
1035
1036/**
1037 * Stage skipped AX keys and calculate the message key.
1038 *
1039 * Stores each HK and MK for skipped messages.
1040 *
1041 * @param t Tunnel where to stage the keys.
1042 * @param HKr Header key.
1043 * @param Np Received meesage number.
1044 *
1045 * @return GNUNET_OK if keys were stored.
1046 * GNUNET_SYSERR if an error ocurred (Np not expected).
1047 */
1048static int
1049store_ax_keys (struct CadetTunnel *t,
1050 const struct GNUNET_CRYPTO_SymmetricSessionKey *HKr,
1051 uint32_t Np)
1052{
1053 int gap;
1054
1055
1056 gap = Np - t->ax->Nr;
1057 LOG (GNUNET_ERROR_TYPE_INFO, "Storing keys [%u, %u)\n", t->ax->Nr, Np);
1058 if (MAX_KEY_GAP < gap)
1059 {
1060 /* Avoid DoS (forcing peer to do 2*33 chain HMAC operations) */
1061 /* TODO: start new key exchange on return */
1062 GNUNET_break_op (0);
1063 LOG (GNUNET_ERROR_TYPE_WARNING, "Got message %u, expected %u+\n",
1064 Np, t->ax->Nr);
1065 return GNUNET_SYSERR;
1066 }
1067 if (0 > gap)
1068 {
1069 /* Delayed message: don't store keys, flag to try old keys. */
1070 return GNUNET_SYSERR;
1071 }
1072
1073 while (t->ax->Nr < Np)
1074 store_skipped_key (t, HKr);
1075
1076 while (t->ax->skipped > MAX_SKIPPED_KEYS)
1077 delete_skipped_key (t, t->ax->skipped_tail);
1078
1079 return GNUNET_OK;
1080}
1081
1082
1083/**
1084 * Decrypt and verify data with the appropriate tunnel key and verify that the
1085 * data has not been altered since it was sent by the remote peer.
1086 *
1087 * @param t Tunnel whose key to use.
1088 * @param dst Destination for the plaintext.
1089 * @param src Source of the message. Can overlap with @c dst.
1090 * @param size Size of the message.
1091 *
1092 * @return Size of the decrypted data, -1 if an error was encountered.
1093 */
1094static int
1095t_ax_decrypt_and_validate (struct CadetTunnel *t, void *dst,
1096 const struct GNUNET_CADET_TunnelEncryptedMessage *src,
1097 size_t size)
1098{
1099 struct CadetTunnelAxolotl *ax;
1100 struct GNUNET_ShortHashCode msg_hmac;
1101 struct GNUNET_HashCode hmac;
1102 struct GNUNET_CADET_TunnelEncryptedMessage plaintext_header;
1103 uint32_t Np;
1104 uint32_t PNp;
1105 size_t esize; /* Size of encryped payload */
1106 size_t osize; /* Size of output (decrypted payload) */
1107
1108 esize = size - sizeof (struct GNUNET_CADET_TunnelEncryptedMessage);
1109 ax = t->ax;
1110 if (NULL == ax)
1111 return -1;
1112
1113 /* Try current HK */
1114 t_hmac (&src->Ns, AX_HEADER_SIZE + esize, 0, &ax->HKr, &msg_hmac);
1115 if (0 != memcmp (&msg_hmac, &src->hmac, sizeof (msg_hmac)))
1116 {
1117 static const char ctx[] = "axolotl ratchet";
1118 struct GNUNET_CRYPTO_SymmetricSessionKey keys[3]; /* RKp, NHKp, CKp */
1119 struct GNUNET_CRYPTO_SymmetricSessionKey HK;
1120 struct GNUNET_HashCode dh;
1121 struct GNUNET_CRYPTO_EcdhePublicKey *DHRp;
1122
1123 /* Try Next HK */
1124 LOG (GNUNET_ERROR_TYPE_DEBUG, " trying next HK\n");
1125 t_hmac (&src->Ns, AX_HEADER_SIZE + esize, 0, &ax->NHKr, &msg_hmac);
1126 if (0 != memcmp (&msg_hmac, &src->hmac, sizeof (msg_hmac)))
1127 {
1128 /* Try the skipped keys, if that fails, we're out of luck. */
1129 return try_old_ax_keys (t, dst, src, size);
1130 }
1131 LOG (GNUNET_ERROR_TYPE_INFO, "next HK worked\n");
1132
1133 HK = ax->HKr;
1134 ax->HKr = ax->NHKr;
1135 t_h_decrypt (t, src, &plaintext_header);
1136 Np = ntohl (plaintext_header.Ns);
1137 PNp = ntohl (plaintext_header.PNs);
1138 DHRp = &plaintext_header.DHRs;
1139 store_ax_keys (t, &HK, PNp);
1140
1141 /* RKp, NHKp, CKp = KDF (HMAC-HASH (RK, DH (DHRp, DHRs))) */
1142 GNUNET_CRYPTO_ecc_ecdh (ax->DHRs, DHRp, &dh);
1143 t_ax_hmac_hash (&ax->RK, &hmac, &dh, sizeof (dh));
1144 GNUNET_CRYPTO_kdf (keys, sizeof (keys), ctx, sizeof (ctx),
1145 &hmac, sizeof (hmac), NULL);
1146
1147 /* Commit "purported" keys */
1148 ax->RK = keys[0];
1149 ax->NHKr = keys[1];
1150 ax->CKr = keys[2];
1151 ax->DHRr = *DHRp;
1152 ax->Nr = 0;
1153 ax->ratchet_allowed = GNUNET_YES;
1154 }
1155 else
1156 {
1157 LOG (GNUNET_ERROR_TYPE_DEBUG, "current HK\n");
1158 t_h_decrypt (t, src, &plaintext_header);
1159 Np = ntohl (plaintext_header.Ns);
1160 PNp = ntohl (plaintext_header.PNs);
1161 }
1162 LOG (GNUNET_ERROR_TYPE_INFO, " got AX Nr %u\n", Np);
1163 if (Np != ax->Nr)
1164 if (GNUNET_OK != store_ax_keys (t, &ax->HKr, Np))
1165 /* Try the skipped keys, if that fails, we're out of luck. */
1166 return try_old_ax_keys (t, dst, src, size);
1167
1168 osize = t_ax_decrypt (t, dst, &src[1], esize);
1169 ax->Nr = Np + 1;
1170
1171 if (osize != esize)
1172 {
1173 GNUNET_break_op (0);
1174 return -1;
1175 }
1176
1177 return osize;
1178}
1179
1180
1181/**
1182 * Pick a connection on which send the next data message.
1183 *
1184 * @param t Tunnel on which to send the message.
1185 *
1186 * @return The connection on which to send the next message.
1187 */
1188static struct CadetConnection *
1189tunnel_get_connection (struct CadetTunnel *t)
1190{
1191 struct CadetTConnection *iter;
1192 struct CadetConnection *best;
1193 unsigned int qn;
1194 unsigned int lowest_q;
1195
1196 LOG (GNUNET_ERROR_TYPE_DEBUG, "tunnel_get_connection %s\n", GCT_2s (t));
1197 best = NULL;
1198 lowest_q = UINT_MAX;
1199 for (iter = t->connection_head; NULL != iter; iter = iter->next)
1200 {
1201 LOG (GNUNET_ERROR_TYPE_DEBUG, " connection %s: %u\n",
1202 GCC_2s (iter->c), GCC_get_state (iter->c));
1203 if (CADET_CONNECTION_READY == GCC_get_state (iter->c))
1204 {
1205 qn = GCC_get_qn (iter->c, GCC_is_origin (iter->c, GNUNET_YES));
1206 LOG (GNUNET_ERROR_TYPE_DEBUG, " q_n %u, \n", qn);
1207 if (qn < lowest_q)
1208 {
1209 best = iter->c;
1210 lowest_q = qn;
1211 }
1212 }
1213 }
1214 LOG (GNUNET_ERROR_TYPE_DEBUG, " selected: connection %s\n", GCC_2s (best));
1215 return best;
1216}
1217
1218
1219/**
1220 * Callback called when a queued message is sent.
1221 *
1222 * Calculates the average time and connection packet tracking.
1223 *
1224 * @param cls Closure (TunnelQueue handle).
1225 * @param c Connection this message was on.
1226 * @param q Connection queue handle (unused).
1227 * @param type Type of message sent.
1228 * @param fwd Was this a FWD going message?
1229 * @param size Size of the message.
1230 */
1231static void
1232tun_message_sent (void *cls,
1233 struct CadetConnection *c,
1234 struct CadetConnectionQueue *q,
1235 uint16_t type, int fwd, size_t size)
1236{
1237 struct CadetTunnelQueue *qt = cls;
1238 struct CadetTunnel *t;
1239
1240 LOG (GNUNET_ERROR_TYPE_DEBUG, "tun_message_sent\n");
1241
1242 GNUNET_assert (NULL != qt->cont);
1243 t = NULL == c ? NULL : GCC_get_tunnel (c);
1244 qt->cont (qt->cont_cls, t, qt, type, size);
1245 GNUNET_free (qt);
1246}
1247
1248
1249static unsigned int
1250count_queued_data (const struct CadetTunnel *t)
1251{
1252 struct CadetTunnelDelayed *iter;
1253 unsigned int count;
1254
1255 for (count = 0, iter = t->tq_head; iter != NULL; iter = iter->next)
1256 count++;
1257
1258 return count;
1259}
1260
1261/**
1262 * Delete a queued message: either was sent or the channel was destroyed
1263 * before the tunnel's key exchange had a chance to finish.
1264 *
1265 * @param tqd Delayed queue handle.
1266 */
1267static void
1268unqueue_data (struct CadetTunnelDelayed *tqd)
1269{
1270 GNUNET_CONTAINER_DLL_remove (tqd->t->tq_head, tqd->t->tq_tail, tqd);
1271 GNUNET_free (tqd);
1272}
1273
1274
1275/**
1276 * Cache a message to be sent once tunnel is online.
1277 *
1278 * @param t Tunnel to hold the message.
1279 * @param msg Message itself (copy will be made).
1280 */
1281static struct CadetTunnelDelayed *
1282queue_data (struct CadetTunnel *t, const struct GNUNET_MessageHeader *msg)
1283{
1284 struct CadetTunnelDelayed *tqd;
1285 uint16_t size = ntohs (msg->size);
1286
1287 LOG (GNUNET_ERROR_TYPE_DEBUG, "queue data on Tunnel %s\n", GCT_2s (t));
1288
1289 GNUNET_assert (GNUNET_NO == is_ready (t));
1290
1291 tqd = GNUNET_malloc (sizeof (struct CadetTunnelDelayed) + size);
1292
1293 tqd->t = t;
1294 GNUNET_memcpy (&tqd[1], msg, size);
1295 GNUNET_CONTAINER_DLL_insert_tail (t->tq_head, t->tq_tail, tqd);
1296 return tqd;
1297}
1298
1299
1300/**
1301 * Sends an already built message on a tunnel, encrypting it and
1302 * choosing the best connection.
1303 *
1304 * @param message Message to send. Function modifies it.
1305 * @param t Tunnel on which this message is transmitted.
1306 * @param c Connection to use (autoselect if NULL).
1307 * @param force Force the tunnel to take the message (buffer overfill).
1308 * @param cont Continuation to call once message is really sent.
1309 * @param cont_cls Closure for @c cont.
1310 * @param existing_q In case this a transmission of previously queued data,
1311 * this should be TunnelQueue given to the client.
1312 * Otherwise, NULL.
1313 * @return Handle to cancel message.
1314 * NULL if @c cont is NULL or an error happens and message is dropped.
1315 */
1316static struct CadetTunnelQueue *
1317send_prebuilt_message (const struct GNUNET_MessageHeader *message,
1318 struct CadetTunnel *t,
1319 struct CadetConnection *c,
1320 int force,
1321 GCT_sent cont,
1322 void *cont_cls,
1323 struct CadetTunnelQueue *existing_q)
1324{
1325 struct GNUNET_MessageHeader *msg;
1326 struct GNUNET_CADET_TunnelEncryptedMessage *ax_msg;
1327 struct CadetTunnelQueue *tq;
1328 size_t size = ntohs (message->size);
1329 char cbuf[sizeof (struct GNUNET_CADET_TunnelEncryptedMessage) + size] GNUNET_ALIGN;
1330 size_t esize;
1331 uint16_t type;
1332 int fwd;
1333
1334 LOG (GNUNET_ERROR_TYPE_DEBUG, "GMT Send on Tunnel %s\n", GCT_2s (t));
1335
1336 if (GNUNET_NO == is_ready (t))
1337 {
1338 struct CadetTunnelDelayed *tqd;
1339 /* A non null existing_q indicates sending of queued data.
1340 * Should only happen after tunnel becomes ready.
1341 */
1342 GNUNET_assert (NULL == existing_q);
1343 tqd = queue_data (t, message);
1344 if (NULL == cont)
1345 return NULL;
1346 tq = GNUNET_new (struct CadetTunnelQueue);
1347 tq->tqd = tqd;
1348 tqd->tq = tq;
1349 tq->cont = cont;
1350 tq->cont_cls = cont_cls;
1351 return tq;
1352 }
1353
1354 GNUNET_assert (GNUNET_NO == GCT_is_loopback (t));
1355
1356 ax_msg = (struct GNUNET_CADET_TunnelEncryptedMessage *) cbuf;
1357 msg = &ax_msg->header;
1358 msg->size = htons (sizeof (struct GNUNET_CADET_TunnelEncryptedMessage) + size);
1359 msg->type = htons (GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED);
1360 esize = t_ax_encrypt (t, &ax_msg[1], message, size);
1361 ax_msg->Ns = htonl (t->ax->Ns++);
1362 ax_msg->PNs = htonl (t->ax->PNs);
1363 GNUNET_CRYPTO_ecdhe_key_get_public (t->ax->DHRs, &ax_msg->DHRs);
1364 t_h_encrypt (t, ax_msg);
1365 t_hmac (&ax_msg->Ns, AX_HEADER_SIZE + esize, 0, &t->ax->HKs, &ax_msg->hmac);
1366 GNUNET_assert (esize == size);
1367
1368 if (NULL == c)
1369 c = tunnel_get_connection (t);
1370 if (NULL == c)
1371 {
1372 /* Why is tunnel 'ready'? Should have been queued! */
1373 if (NULL != t->destroy_task)
1374 {
1375 GNUNET_break (0);
1376 GCT_debug (t, GNUNET_ERROR_TYPE_WARNING);
1377 }
1378 return NULL; /* Drop... */
1379 }
1380 fwd = GCC_is_origin (c, GNUNET_YES);
1381 ax_msg->cid = *GCC_get_id (c);
1382 ax_msg->cemi = GCC_get_pid (c, fwd);
1383
1384 type = htons (message->type);
1385 LOG (GNUNET_ERROR_TYPE_DEBUG,
1386 "Sending message of type %s with CEMI %u and CID %s\n",
1387 GC_m2s (type),
1388 htonl (ax_msg->cemi.pid),
1389 GNUNET_sh2s (&ax_msg->cid.connection_of_tunnel));
1390
1391 if (NULL == cont)
1392 {
1393 (void) GCC_send_prebuilt_message (msg,
1394 type,
1395 ax_msg->cemi,
1396 c,
1397 fwd,
1398 force, NULL, NULL);
1399 return NULL;
1400 }
1401 if (NULL == existing_q)
1402 {
1403 tq = GNUNET_new (struct CadetTunnelQueue); /* FIXME valgrind: leak*/
1404 }
1405 else
1406 {
1407 tq = existing_q;
1408 tq->tqd = NULL;
1409 }
1410 tq->cont = cont;
1411 tq->cont_cls = cont_cls;
1412 tq->cq = GCC_send_prebuilt_message (msg,
1413 type,
1414 ax_msg->cemi,
1415 c,
1416 fwd,
1417 force,
1418 &tun_message_sent, tq);
1419 GNUNET_assert (NULL != tq->cq);
1420
1421 return tq;
1422}
1423
1424
1425/**
1426 * Send all cached messages that we can, tunnel is online.
1427 *
1428 * @param t Tunnel that holds the messages. Cannot be loopback.
1429 */
1430static void
1431send_queued_data (struct CadetTunnel *t)
1432{
1433 struct CadetTunnelDelayed *tqd;
1434 struct CadetTunnelDelayed *next;
1435 unsigned int room;
1436
1437 LOG (GNUNET_ERROR_TYPE_INFO, "Send queued data, tunnel %s\n", GCT_2s (t));
1438
1439 if (GCT_is_loopback (t))
1440 {
1441 GNUNET_break (0);
1442 return;
1443 }
1444
1445 if (GNUNET_NO == is_ready (t))
1446 {
1447 LOG (GNUNET_ERROR_TYPE_WARNING, " not ready yet: %s/%s\n",
1448 estate2s (t->estate), cstate2s (t->cstate));
1449 return;
1450 }
1451
1452 room = GCT_get_connections_buffer (t);
1453 LOG (GNUNET_ERROR_TYPE_DEBUG, " buffer space: %u\n", room);
1454 LOG (GNUNET_ERROR_TYPE_DEBUG, " tq head: %p\n", t->tq_head);
1455 for (tqd = t->tq_head; NULL != tqd && room > 0; tqd = next)
1456 {
1457 LOG (GNUNET_ERROR_TYPE_DEBUG, " sending queued data\n");
1458 next = tqd->next;
1459 room--;
1460 send_prebuilt_message ((struct GNUNET_MessageHeader *) &tqd[1],
1461 tqd->t, NULL, GNUNET_YES,
1462 NULL != tqd->tq ? tqd->tq->cont : NULL,
1463 NULL != tqd->tq ? tqd->tq->cont_cls : NULL,
1464 tqd->tq);
1465 unqueue_data (tqd);
1466 }
1467 LOG (GNUNET_ERROR_TYPE_DEBUG, "GCT_send_queued_data end\n", GCP_2s (t->peer));
1468}
1469
1470
1471/**
1472 * @brief Resend the KX until we complete the handshake.
1473 *
1474 * @param cls Closure (tunnel).
1475 */
1476static void
1477kx_resend (void *cls)
1478{
1479 struct CadetTunnel *t = cls;
1480
1481 t->rekey_task = NULL;
1482 if (CADET_TUNNEL_KEY_OK == t->estate)
1483 {
1484 /* Should have been canceled on estate change */
1485 GNUNET_break (0);
1486 return;
1487 }
1488
1489 GCT_send_kx (t, CADET_TUNNEL_KEY_AX_SENT >= t->estate);
1490}
1491
1492
1493/**
1494 * Callback called when a queued message is sent.
1495 *
1496 * @param cls Closure.
1497 * @param c Connection this message was on.
1498 * @param type Type of message sent.
1499 * @param fwd Was this a FWD going message?
1500 * @param size Size of the message.
1501 */
1502static void
1503ephm_sent (void *cls,
1504 struct CadetConnection *c,
1505 struct CadetConnectionQueue *q,
1506 uint16_t type, int fwd, size_t size)
1507{
1508 struct CadetTunnel *t = cls;
1509 LOG (GNUNET_ERROR_TYPE_DEBUG, "ephemeral sent %s\n", GC_m2s (type));
1510
1511 t->ephm_h = NULL;
1512
1513 if (CADET_TUNNEL_KEY_OK == t->estate)
1514 return;
1515
1516 if (NULL != t->rekey_task)
1517 {
1518 GNUNET_break (0);
1519 GCT_debug (t, GNUNET_ERROR_TYPE_WARNING);
1520 GNUNET_SCHEDULER_cancel (t->rekey_task);
1521 }
1522 t->rekey_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
1523 &kx_resend, t);
1524
1525}
1526
1527
1528/**
1529 * Called only on shutdown, destroy every tunnel.
1530 *
1531 * @param cls Closure (unused).
1532 * @param key Current public key.
1533 * @param value Value in the hash map (tunnel).
1534 *
1535 * @return #GNUNET_YES, so we should continue to iterate,
1536 */
1537static int
1538destroy_iterator (void *cls,
1539 const struct GNUNET_PeerIdentity *key,
1540 void *value)
1541{
1542 struct CadetTunnel *t = value;
1543
1544 LOG (GNUNET_ERROR_TYPE_DEBUG,
1545 "GCT_shutdown destroying tunnel at %p\n", t);
1546 GCT_destroy (t);
1547 return GNUNET_YES;
1548}
1549
1550
1551/**
1552 * Notify remote peer that we don't know a channel he is talking about,
1553 * probably CHANNEL_DESTROY was missed.
1554 *
1555 * @param t Tunnel on which to notify.
1556 * @param gid ID of the channel.
1557 */
1558static void
1559send_channel_destroy (struct CadetTunnel *t,
1560 struct GNUNET_CADET_ChannelTunnelNumber gid)
1561{
1562 struct GNUNET_CADET_ChannelManageMessage msg;
1563
1564 msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY);
1565 msg.header.size = htons (sizeof (msg));
1566 msg.ctn = gid;
1567
1568 LOG (GNUNET_ERROR_TYPE_DEBUG,
1569 "WARNING destroying unknown channel %u on tunnel %s\n",
1570 ntohl (gid.cn),
1571 GCT_2s (t));
1572 send_prebuilt_message (&msg.header, t, NULL, GNUNET_YES, NULL, NULL, NULL);
1573}
1574
1575
1576/**
1577 * Demultiplex data per channel and call appropriate channel handler.
1578 *
1579 * @param t Tunnel on which the data came.
1580 * @param msg Data message.
1581 * @param fwd Is this message fwd? This only is meaningful in loopback channels.
1582 * #GNUNET_YES if message is FWD on the respective channel (loopback)
1583 * #GNUNET_NO if message is BCK on the respective channel (loopback)
1584 * #GNUNET_SYSERR if message on a one-ended channel (remote)
1585 */
1586static void
1587handle_data (struct CadetTunnel *t,
1588 const struct GNUNET_CADET_ChannelAppDataMessage *msg,
1589 int fwd)
1590{
1591 struct CadetChannel *ch;
1592 char buf[128];
1593 size_t size;
1594 uint16_t type;
1595
1596 /* Check size */
1597 size = ntohs (msg->header.size);
1598 if (size <
1599 sizeof (struct GNUNET_CADET_ChannelAppDataMessage) +
1600 sizeof (struct GNUNET_MessageHeader))
1601 {
1602 GNUNET_break (0);
1603 return;
1604 }
1605 type = ntohs (msg[1].header.type);
1606 LOG (GNUNET_ERROR_TYPE_DEBUG, " payload of type %s\n", GC_m2s (type));
1607 SPRINTF (buf, "# received payload of type %hu", type);
1608 GNUNET_STATISTICS_update (stats, buf, 1, GNUNET_NO);
1609
1610
1611 /* Check channel */
1612 ch = GCT_get_channel (t, msg->ctn);
1613 if (NULL == ch)
1614 {
1615 GNUNET_STATISTICS_update (stats,
1616 "# data on unknown channel",
1617 1,
1618 GNUNET_NO);
1619 LOG (GNUNET_ERROR_TYPE_DEBUG,
1620 "channel 0x%X unknown\n",
1621 ntohl (msg->ctn.cn));
1622 send_channel_destroy (t, msg->ctn);
1623 return;
1624 }
1625
1626 GCCH_handle_data (ch, msg, fwd);
1627}
1628
1629
1630/**
1631 * Demultiplex data ACKs per channel and update appropriate channel buffer info.
1632 *
1633 * @param t Tunnel on which the DATA ACK came.
1634 * @param msg DATA ACK message.
1635 * @param fwd Is this message fwd? This only is meaningful in loopback channels.
1636 * #GNUNET_YES if message is FWD on the respective channel (loopback)
1637 * #GNUNET_NO if message is BCK on the respective channel (loopback)
1638 * #GNUNET_SYSERR if message on a one-ended channel (remote)
1639 */
1640static void
1641handle_data_ack (struct CadetTunnel *t,
1642 const struct GNUNET_CADET_ChannelDataAckMessage *msg,
1643 int fwd)
1644{
1645 struct CadetChannel *ch;
1646 size_t size;
1647
1648 /* Check size */
1649 size = ntohs (msg->header.size);
1650 if (size != sizeof (struct GNUNET_CADET_ChannelDataAckMessage))
1651 {
1652 GNUNET_break (0);
1653 return;
1654 }
1655
1656 /* Check channel */
1657 ch = GCT_get_channel (t, msg->ctn);
1658 if (NULL == ch)
1659 {
1660 GNUNET_STATISTICS_update (stats, "# data ack on unknown channel",
1661 1, GNUNET_NO);
1662 LOG (GNUNET_ERROR_TYPE_DEBUG, "WARNING channel %u unknown\n",
1663 ntohl (msg->ctn.cn));
1664 return;
1665 }
1666
1667 GCCH_handle_data_ack (ch, msg, fwd);
1668}
1669
1670
1671/**
1672 * Handle channel create.
1673 *
1674 * @param t Tunnel on which the message came.
1675 * @param msg ChannelCreate message.
1676 */
1677static void
1678handle_ch_create (struct CadetTunnel *t,
1679 const struct GNUNET_CADET_ChannelOpenMessage *msg)
1680{
1681 struct CadetChannel *ch;
1682 size_t size;
1683
1684 /* Check size */
1685 size = ntohs (msg->header.size);
1686 if (size != sizeof (struct GNUNET_CADET_ChannelOpenMessage))
1687 {
1688 GNUNET_break_op (0);
1689 return;
1690 }
1691
1692 /* Check channel */
1693 ch = GCT_get_channel (t, msg->ctn);
1694 if (NULL != ch && ! GCT_is_loopback (t))
1695 {
1696 /* Probably a retransmission, safe to ignore */
1697 LOG (GNUNET_ERROR_TYPE_DEBUG, " already exists...\n");
1698 }
1699 ch = GCCH_handle_create (t, msg);
1700 if (NULL != ch)
1701 GCT_add_channel (t, ch);
1702}
1703
1704
1705
1706/**
1707 * Handle channel NACK: check correctness and call channel handler for NACKs.
1708 *
1709 * @param t Tunnel on which the NACK came.
1710 * @param msg NACK message.
1711 */
1712static void
1713handle_ch_nack (struct CadetTunnel *t,
1714 const struct GNUNET_CADET_ChannelManageMessage *msg)
1715{
1716 struct CadetChannel *ch;
1717 size_t size;
1718
1719 /* Check size */
1720 size = ntohs (msg->header.size);
1721 if (size != sizeof (struct GNUNET_CADET_ChannelManageMessage))
1722 {
1723 GNUNET_break (0);
1724 return;
1725 }
1726
1727 /* Check channel */
1728 ch = GCT_get_channel (t, msg->ctn);
1729 if (NULL == ch)
1730 {
1731 GNUNET_STATISTICS_update (stats, "# channel NACK on unknown channel",
1732 1, GNUNET_NO);
1733 LOG (GNUNET_ERROR_TYPE_DEBUG,
1734 "WARNING channel %u unknown\n",
1735 ntohl (msg->ctn.cn));
1736 return;
1737 }
1738
1739 GCCH_handle_nack (ch);
1740}
1741
1742
1743/**
1744 * Handle a CHANNEL ACK (SYNACK/ACK).
1745 *
1746 * @param t Tunnel on which the CHANNEL ACK came.
1747 * @param msg CHANNEL ACK message.
1748 * @param fwd Is this message fwd? This only is meaningful in loopback channels.
1749 * #GNUNET_YES if message is FWD on the respective channel (loopback)
1750 * #GNUNET_NO if message is BCK on the respective channel (loopback)
1751 * #GNUNET_SYSERR if message on a one-ended channel (remote)
1752 */
1753static void
1754handle_ch_ack (struct CadetTunnel *t,
1755 const struct GNUNET_CADET_ChannelManageMessage *msg,
1756 int fwd)
1757{
1758 struct CadetChannel *ch;
1759 size_t size;
1760
1761 /* Check size */
1762 size = ntohs (msg->header.size);
1763 if (size != sizeof (struct GNUNET_CADET_ChannelManageMessage))
1764 {
1765 GNUNET_break (0);
1766 return;
1767 }
1768
1769 /* Check channel */
1770 ch = GCT_get_channel (t, msg->ctn);
1771 if (NULL == ch)
1772 {
1773 GNUNET_STATISTICS_update (stats,
1774 "# channel ack on unknown channel",
1775 1,
1776 GNUNET_NO);
1777 LOG (GNUNET_ERROR_TYPE_DEBUG,
1778 "WARNING channel %u unknown\n",
1779 ntohl (msg->ctn.cn));
1780 return;
1781 }
1782
1783 GCCH_handle_ack (ch, msg, fwd);
1784}
1785
1786
1787/**
1788 * Handle a channel destruction message.
1789 *
1790 * @param t Tunnel on which the message came.
1791 * @param msg Channel destroy message.
1792 * @param fwd Is this message fwd? This only is meaningful in loopback channels.
1793 * #GNUNET_YES if message is FWD on the respective channel (loopback)
1794 * #GNUNET_NO if message is BCK on the respective channel (loopback)
1795 * #GNUNET_SYSERR if message on a one-ended channel (remote)
1796 */
1797static void
1798handle_ch_destroy (struct CadetTunnel *t,
1799 const struct GNUNET_CADET_ChannelManageMessage *msg,
1800 int fwd)
1801{
1802 struct CadetChannel *ch;
1803 size_t size;
1804
1805 /* Check size */
1806 size = ntohs (msg->header.size);
1807 if (size != sizeof (struct GNUNET_CADET_ChannelManageMessage))
1808 {
1809 GNUNET_break (0);
1810 return;
1811 }
1812
1813 /* Check channel */
1814 ch = GCT_get_channel (t, msg->ctn);
1815 if (NULL == ch)
1816 {
1817 /* Probably a retransmission, safe to ignore */
1818 return;
1819 }
1820
1821 GCCH_handle_destroy (ch, msg, fwd);
1822}
1823
1824
1825/**
1826 * Free Axolotl data.
1827 *
1828 * @param t Tunnel.
1829 */
1830static void
1831destroy_ax (struct CadetTunnel *t)
1832{
1833 if (NULL == t->ax)
1834 return;
1835
1836 GNUNET_free_non_null (t->ax->DHRs);
1837 GNUNET_free_non_null (t->ax->kx_0);
1838 while (NULL != t->ax->skipped_head)
1839 delete_skipped_key (t, t->ax->skipped_head);
1840 GNUNET_assert (0 == t->ax->skipped);
1841
1842 GNUNET_free (t->ax);
1843 t->ax = NULL;
1844
1845 if (NULL != t->rekey_task)
1846 {
1847 GNUNET_SCHEDULER_cancel (t->rekey_task);
1848 t->rekey_task = NULL;
1849 }
1850 if (NULL != t->ephm_h)
1851 {
1852 GCC_cancel (t->ephm_h);
1853 t->ephm_h = NULL;
1854 }
1855}
1856
1857
1858/**
1859 * Demultiplex by message type and call appropriate handler for a message
1860 * towards a channel of a local tunnel.
1861 *
1862 * @param t Tunnel this message came on.
1863 * @param msgh Message header.
1864 * @param fwd Is this message fwd? This only is meaningful in loopback channels.
1865 * #GNUNET_YES if message is FWD on the respective channel (loopback)
1866 * #GNUNET_NO if message is BCK on the respective channel (loopback)
1867 * #GNUNET_SYSERR if message on a one-ended channel (remote)
1868 */
1869static void
1870handle_decrypted (struct CadetTunnel *t,
1871 const struct GNUNET_MessageHeader *msgh,
1872 int fwd)
1873{
1874 uint16_t type;
1875 char buf[256];
1876
1877 type = ntohs (msgh->type);
1878 LOG (GNUNET_ERROR_TYPE_DEBUG, "<-- %s on %s\n", GC_m2s (type), GCT_2s (t));
1879 SPRINTF (buf, "# received encrypted of type %hu (%s)", type, GC_m2s (type));
1880 GNUNET_STATISTICS_update (stats, buf, 1, GNUNET_NO);
1881
1882 switch (type)
1883 {
1884 case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE:
1885 /* Do nothing, connection aleady got updated. */
1886 GNUNET_STATISTICS_update (stats, "# keepalives received", 1, GNUNET_NO);
1887 break;
1888
1889 case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA:
1890 /* Don't send hop ACK, wait for client to ACK */
1891 handle_data (t, (struct GNUNET_CADET_ChannelAppDataMessage *) msgh, fwd);
1892 break;
1893
1894 case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK:
1895 handle_data_ack (t, (struct GNUNET_CADET_ChannelDataAckMessage *) msgh, fwd);
1896 break;
1897
1898 case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN:
1899 handle_ch_create (t, (struct GNUNET_CADET_ChannelOpenMessage *) msgh);
1900 break;
1901
1902 case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_NACK_DEPRECATED:
1903 handle_ch_nack (t, (struct GNUNET_CADET_ChannelManageMessage *) msgh);
1904 break;
1905
1906 case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK:
1907 handle_ch_ack (t, (struct GNUNET_CADET_ChannelManageMessage *) msgh, fwd);
1908 break;
1909
1910 case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY:
1911 handle_ch_destroy (t, (struct GNUNET_CADET_ChannelManageMessage *) msgh, fwd);
1912 break;
1913
1914 default:
1915 GNUNET_break_op (0);
1916 LOG (GNUNET_ERROR_TYPE_WARNING,
1917 "end-to-end message not known (%u)\n",
1918 ntohs (msgh->type));
1919 GCT_debug (t, GNUNET_ERROR_TYPE_WARNING);
1920 }
1921}
1922
1923
1924/******************************************************************************/
1925/******************************** API ***********************************/
1926/******************************************************************************/
1927
1928/**
1929 * Decrypt and process an encrypted message.
1930 *
1931 * Calls the appropriate handler for a message in a channel of a local tunnel.
1932 *
1933 * @param t Tunnel this message came on.
1934 * @param msg Message header.
1935 */
1936void
1937GCT_handle_encrypted (struct CadetTunnel *t,
1938 const struct GNUNET_CADET_TunnelEncryptedMessage *msg)
1939{
1940 uint16_t size = ntohs (msg->header.size);
1941 char cbuf [size];
1942 int decrypted_size;
1943 const struct GNUNET_MessageHeader *msgh;
1944 unsigned int off;
1945
1946 GNUNET_STATISTICS_update (stats, "# received encrypted", 1, GNUNET_NO);
1947
1948 decrypted_size = t_ax_decrypt_and_validate (t, cbuf, msg, size);
1949
1950 if (-1 == decrypted_size)
1951 {
1952 GNUNET_STATISTICS_update (stats, "# unable to decrypt", 1, GNUNET_NO);
1953 if (CADET_TUNNEL_KEY_AX_AUTH_SENT <= t->estate)
1954 {
1955 GNUNET_break_op (0);
1956 LOG (GNUNET_ERROR_TYPE_WARNING, "Wrong crypto, tunnel %s\n", GCT_2s (t));
1957 GCT_debug (t, GNUNET_ERROR_TYPE_WARNING);
1958 }
1959 return;
1960 }
1961 GCT_change_estate (t, CADET_TUNNEL_KEY_OK);
1962
1963 /* FIXME: this is bad, as the structs returned from
1964 this loop may be unaligned, see util's MST for
1965 how to do this right. */
1966 off = 0;
1967 while (off + sizeof (struct GNUNET_MessageHeader) <= decrypted_size)
1968 {
1969 uint16_t msize;
1970
1971 msgh = (const struct GNUNET_MessageHeader *) &cbuf[off];
1972 msize = ntohs (msgh->size);
1973 if (msize < sizeof (struct GNUNET_MessageHeader))
1974 {
1975 GNUNET_break_op (0);
1976 return;
1977 }
1978 if (off + msize < decrypted_size)
1979 {
1980 GNUNET_break_op (0);
1981 return;
1982 }
1983 handle_decrypted (t, msgh, GNUNET_SYSERR);
1984 off += msize;
1985 }
1986}
1987
1988
1989/**
1990 * Handle a Key eXchange message.
1991 *
1992 * @param t Tunnel on which the message came.
1993 * @param msg KX message itself.
1994 */
1995void
1996GCT_handle_kx (struct CadetTunnel *t,
1997 const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg)
1998{
1999 struct CadetTunnelAxolotl *ax;
2000 struct GNUNET_HashCode key_material[3];
2001 struct GNUNET_CRYPTO_SymmetricSessionKey keys[5];
2002 const char salt[] = "CADET Axolotl salt";
2003 const struct GNUNET_PeerIdentity *pid;
2004 int am_I_alice;
2005
2006 CADET_TIMING_START;
2007
2008 LOG (GNUNET_ERROR_TYPE_INFO, "<== { KX} on %s\n", GCT_2s (t));
2009
2010 if (NULL == t->ax)
2011 {
2012 /* Something is wrong if ax is NULL. Whose fault it is? */
2013 return;
2014 }
2015 ax = t->ax;
2016
2017 pid = GCT_get_destination (t);
2018 if (0 > GNUNET_CRYPTO_cmp_peer_identity (&my_full_id, pid))
2019 am_I_alice = GNUNET_YES;
2020 else if (0 < GNUNET_CRYPTO_cmp_peer_identity (&my_full_id, pid))
2021 am_I_alice = GNUNET_NO;
2022 else
2023 {
2024 GNUNET_break_op (0);
2025 return;
2026 }
2027
2028 if (0 != (GNUNET_CADET_KX_FLAG_FORCE_REPLY & ntohl (msg->flags)))
2029 {
2030 if (NULL != t->rekey_task)
2031 {
2032 GNUNET_SCHEDULER_cancel (t->rekey_task);
2033 t->rekey_task = NULL;
2034 }
2035 GCT_send_kx (t, GNUNET_NO);
2036 }
2037
2038 if (0 == memcmp (&ax->DHRr, &msg->ratchet_key, sizeof(msg->ratchet_key)))
2039 {
2040 LOG (GNUNET_ERROR_TYPE_INFO, " known ratchet key, exit\n");
2041 return;
2042 }
2043
2044 LOG (GNUNET_ERROR_TYPE_INFO, " is Alice? %s\n", am_I_alice ? "YES" : "NO");
2045
2046 ax->DHRr = msg->ratchet_key;
2047
2048 /* ECDH A B0 */
2049 if (GNUNET_YES == am_I_alice)
2050 {
2051 GNUNET_CRYPTO_eddsa_ecdh (id_key, /* A */
2052 &msg->ephemeral_key, /* B0 */
2053 &key_material[0]);
2054 }
2055 else
2056 {
2057 GNUNET_CRYPTO_ecdh_eddsa (ax->kx_0, /* B0 */
2058 &pid->public_key, /* A */
2059 &key_material[0]);
2060 }
2061
2062 /* ECDH A0 B */
2063 if (GNUNET_YES == am_I_alice)
2064 {
2065 GNUNET_CRYPTO_ecdh_eddsa (ax->kx_0, /* A0 */
2066 &pid->public_key, /* B */
2067 &key_material[1]);
2068 }
2069 else
2070 {
2071 GNUNET_CRYPTO_eddsa_ecdh (id_key, /* A */
2072 &msg->ephemeral_key, /* B0 */
2073 &key_material[1]);
2074
2075
2076 }
2077
2078 /* ECDH A0 B0 */
2079 /* (This is the triple-DH, we could probably safely skip this,
2080 as A0/B0 are already in the key material.) */
2081 GNUNET_CRYPTO_ecc_ecdh (ax->kx_0, /* A0 or B0 */
2082 &msg->ephemeral_key, /* B0 or A0 */
2083 &key_material[2]);
2084
2085 #if DUMP_KEYS_TO_STDERR
2086 {
2087 unsigned int i;
2088 for (i = 0; i < 3; i++)
2089 LOG (GNUNET_ERROR_TYPE_INFO, "km[%u]: %s\n",
2090 i, GNUNET_h2s (&key_material[i]));
2091 }
2092 #endif
2093
2094 /* KDF */
2095 GNUNET_CRYPTO_kdf (keys, sizeof (keys),
2096 salt, sizeof (salt),
2097 &key_material, sizeof (key_material), NULL);
2098
2099 if (0 == memcmp (&ax->RK, &keys[0], sizeof(ax->RK)))
2100 {
2101 LOG (GNUNET_ERROR_TYPE_INFO, " known handshake key, exit\n");
2102 return;
2103 }
2104 ax->RK = keys[0];
2105 if (GNUNET_YES == am_I_alice)
2106 {
2107 ax->HKr = keys[1];
2108 ax->NHKs = keys[2];
2109 ax->NHKr = keys[3];
2110 ax->CKr = keys[4];
2111 ax->ratchet_flag = GNUNET_YES;
2112 }
2113 else
2114 {
2115 ax->HKs = keys[1];
2116 ax->NHKr = keys[2];
2117 ax->NHKs = keys[3];
2118 ax->CKs = keys[4];
2119 ax->ratchet_flag = GNUNET_NO;
2120 ax->ratchet_allowed = GNUNET_NO;
2121 ax->ratchet_counter = 0;
2122 ax->ratchet_expiration =
2123 GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get(), ratchet_time);
2124 }
2125 ax->PNs = 0;
2126 ax->Nr = 0;
2127 ax->Ns = 0;
2128
2129 GCT_change_estate (t, CADET_TUNNEL_KEY_AX_AUTH_SENT);
2130 send_queued_data (t);
2131
2132 CADET_TIMING_END;
2133}
2134
2135/**
2136 * Initialize the tunnel subsystem.
2137 *
2138 * @param c Configuration handle.
2139 * @param key ECC private key, to derive all other keys and do crypto.
2140 */
2141void
2142GCT_init (const struct GNUNET_CONFIGURATION_Handle *c,
2143 const struct GNUNET_CRYPTO_EddsaPrivateKey *key)
2144{
2145 unsigned int expected_overhead;
2146
2147 LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n");
2148
2149 expected_overhead = 0;
2150 expected_overhead += sizeof (struct GNUNET_CADET_TunnelEncryptedMessage);
2151 expected_overhead += sizeof (struct GNUNET_CADET_ChannelAppDataMessage);
2152 expected_overhead += sizeof (struct GNUNET_CADET_ConnectionEncryptedAckMessage);
2153 GNUNET_assert (GNUNET_CONSTANTS_CADET_P2P_OVERHEAD == expected_overhead);
2154
2155 if (GNUNET_OK !=
2156 GNUNET_CONFIGURATION_get_value_number (c,
2157 "CADET",
2158 "RATCHET_MESSAGES",
2159 &ratchet_messages))
2160 {
2161 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
2162 "CADET",
2163 "RATCHET_MESSAGES",
2164 "USING DEFAULT");
2165 ratchet_messages = 64;
2166 }
2167 if (GNUNET_OK !=
2168 GNUNET_CONFIGURATION_get_value_time (c,
2169 "CADET",
2170 "RATCHET_TIME",
2171 &ratchet_time))
2172 {
2173 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
2174 "CADET", "RATCHET_TIME", "USING DEFAULT");
2175 ratchet_time = GNUNET_TIME_UNIT_HOURS;
2176 }
2177
2178
2179 id_key = key;
2180 tunnels = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_YES);
2181}
2182
2183
2184/**
2185 * Shut down the tunnel subsystem.
2186 */
2187void
2188GCT_shutdown (void)
2189{
2190 LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down tunnels\n");
2191 GNUNET_CONTAINER_multipeermap_iterate (tunnels, &destroy_iterator, NULL);
2192 GNUNET_CONTAINER_multipeermap_destroy (tunnels);
2193}
2194
2195
2196/**
2197 * Create a tunnel.
2198 *
2199 * @param destination Peer this tunnel is towards.
2200 */
2201struct CadetTunnel *
2202GCT_new (struct CadetPeer *destination)
2203{
2204 struct CadetTunnel *t;
2205
2206 t = GNUNET_new (struct CadetTunnel);
2207 t->next_ctn.cn = 0;
2208 t->peer = destination;
2209
2210 if (GNUNET_OK !=
2211 GNUNET_CONTAINER_multipeermap_put (tunnels, GCP_get_id (destination), t,
2212 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
2213 {
2214 GNUNET_break (0);
2215 GNUNET_free (t);
2216 return NULL;
2217 }
2218 t->ax = GNUNET_new (struct CadetTunnelAxolotl);
2219 new_ephemeral (t);
2220 t->ax->kx_0 = GNUNET_CRYPTO_ecdhe_key_create ();
2221 return t;
2222}
2223
2224
2225/**
2226 * Change the tunnel's connection state.
2227 *
2228 * @param t Tunnel whose connection state to change.
2229 * @param cstate New connection state.
2230 */
2231void
2232GCT_change_cstate (struct CadetTunnel* t, enum CadetTunnelCState cstate)
2233{
2234 if (NULL == t)
2235 return;
2236 LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel %s cstate %s => %s\n",
2237 GCP_2s (t->peer), cstate2s (t->cstate), cstate2s (cstate));
2238 if (myid != GCP_get_short_id (t->peer) &&
2239 CADET_TUNNEL_READY != t->cstate &&
2240 CADET_TUNNEL_READY == cstate)
2241 {
2242 t->cstate = cstate;
2243 if (CADET_TUNNEL_KEY_OK == t->estate)
2244 {
2245 LOG (GNUNET_ERROR_TYPE_DEBUG, " cstate triggered send queued data\n");
2246 send_queued_data (t);
2247 }
2248 else if (CADET_TUNNEL_KEY_UNINITIALIZED == t->estate)
2249 {
2250 LOG (GNUNET_ERROR_TYPE_DEBUG, " cstate triggered KX\n");
2251 GCT_send_kx (t, GNUNET_NO);
2252 }
2253 else
2254 {
2255 LOG (GNUNET_ERROR_TYPE_DEBUG, "estate %s\n", estate2s (t->estate));
2256 }
2257 }
2258 t->cstate = cstate;
2259
2260 if (CADET_TUNNEL_READY == cstate
2261 && CONNECTIONS_PER_TUNNEL <= GCT_count_connections (t))
2262 {
2263 LOG (GNUNET_ERROR_TYPE_DEBUG, " cstate triggered stop dht\n");
2264 GCP_stop_search (t->peer);
2265 }
2266}
2267
2268
2269/**
2270 * Change the tunnel encryption state.
2271 *
2272 * If the encryption state changes to OK, stop the rekey task.
2273 *
2274 * @param t Tunnel whose encryption state to change, or NULL.
2275 * @param state New encryption state.
2276 */
2277void
2278GCT_change_estate (struct CadetTunnel* t, enum CadetTunnelEState state)
2279{
2280 enum CadetTunnelEState old;
2281
2282 if (NULL == t)
2283 return;
2284
2285 old = t->estate;
2286 t->estate = state;
2287 LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel %s estate was %s\n",
2288 GCP_2s (t->peer), estate2s (old));
2289 LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel %s estate is now %s\n",
2290 GCP_2s (t->peer), estate2s (t->estate));
2291
2292 if (CADET_TUNNEL_KEY_OK != old && CADET_TUNNEL_KEY_OK == t->estate)
2293 {
2294 if (NULL != t->rekey_task)
2295 {
2296 GNUNET_SCHEDULER_cancel (t->rekey_task);
2297 t->rekey_task = NULL;
2298 }
2299 /* Send queued data if tunnel is not loopback */
2300 if (myid != GCP_get_short_id (t->peer))
2301 send_queued_data (t);
2302 }
2303}
2304
2305
2306/**
2307 * @brief Check if tunnel has too many connections, and remove one if necessary.
2308 *
2309 * Currently this means the newest connection, unless it is a direct one.
2310 * Implemented as a task to avoid freeing a connection that is in the middle
2311 * of being created/processed.
2312 *
2313 * @param cls Closure (Tunnel to check).
2314 */
2315static void
2316trim_connections (void *cls)
2317{
2318 struct CadetTunnel *t = cls;
2319
2320 t->trim_connections_task = NULL;
2321 if (GCT_count_connections (t) > 2 * CONNECTIONS_PER_TUNNEL)
2322 {
2323 struct CadetTConnection *iter;
2324 struct CadetTConnection *c;
2325
2326 for (c = iter = t->connection_head; NULL != iter; iter = iter->next)
2327 {
2328 if ((iter->created.abs_value_us > c->created.abs_value_us)
2329 && GNUNET_NO == GCC_is_direct (iter->c))
2330 {
2331 c = iter;
2332 }
2333 }
2334 if (NULL != c)
2335 {
2336 LOG (GNUNET_ERROR_TYPE_DEBUG, "Too many connections on tunnel %s\n",
2337 GCT_2s (t));
2338 LOG (GNUNET_ERROR_TYPE_DEBUG, "Destroying connection %s\n",
2339 GCC_2s (c->c));
2340 GCC_destroy (c->c);
2341 }
2342 else
2343 {
2344 GNUNET_break (0);
2345 }
2346 }
2347}
2348
2349
2350/**
2351 * Add a connection to a tunnel.
2352 *
2353 * @param t Tunnel.
2354 * @param c Connection.
2355 */
2356void
2357GCT_add_connection (struct CadetTunnel *t, struct CadetConnection *c)
2358{
2359 struct CadetTConnection *aux;
2360
2361 GNUNET_assert (NULL != c);
2362
2363 LOG (GNUNET_ERROR_TYPE_DEBUG, "add connection %s\n", GCC_2s (c));
2364 LOG (GNUNET_ERROR_TYPE_DEBUG, " to tunnel %s\n", GCT_2s (t));
2365 for (aux = t->connection_head; aux != NULL; aux = aux->next)
2366 if (aux->c == c)
2367 return;
2368
2369 aux = GNUNET_new (struct CadetTConnection);
2370 aux->c = c;
2371 aux->created = GNUNET_TIME_absolute_get ();
2372
2373 GNUNET_CONTAINER_DLL_insert (t->connection_head, t->connection_tail, aux);
2374
2375 if (CADET_TUNNEL_SEARCHING == t->cstate)
2376 GCT_change_cstate (t, CADET_TUNNEL_WAITING);
2377
2378 if (NULL != t->trim_connections_task)
2379 t->trim_connections_task = GNUNET_SCHEDULER_add_now (&trim_connections, t);
2380}
2381
2382
2383/**
2384 * Remove a connection from a tunnel.
2385 *
2386 * @param t Tunnel.
2387 * @param c Connection.
2388 */
2389void
2390GCT_remove_connection (struct CadetTunnel *t,
2391 struct CadetConnection *c)
2392{
2393 struct CadetTConnection *aux;
2394 struct CadetTConnection *next;
2395 unsigned int conns;
2396
2397 LOG (GNUNET_ERROR_TYPE_DEBUG, "Removing connection %s from tunnel %s\n",
2398 GCC_2s (c), GCT_2s (t));
2399 for (aux = t->connection_head; aux != NULL; aux = next)
2400 {
2401 next = aux->next;
2402 if (aux->c == c)
2403 {
2404 GNUNET_CONTAINER_DLL_remove (t->connection_head, t->connection_tail, aux);
2405 GNUNET_free (aux);
2406 }
2407 }
2408
2409 conns = GCT_count_connections (t);
2410 if (0 == conns
2411 && NULL == t->destroy_task
2412 && CADET_TUNNEL_SHUTDOWN != t->cstate
2413 && GNUNET_NO == shutting_down)
2414 {
2415 if (0 == GCT_count_any_connections (t))
2416 GCT_change_cstate (t, CADET_TUNNEL_SEARCHING);
2417 else
2418 GCT_change_cstate (t, CADET_TUNNEL_WAITING);
2419 }
2420
2421 /* Start new connections if needed */
2422 if (CONNECTIONS_PER_TUNNEL > conns
2423 && CADET_TUNNEL_SHUTDOWN != t->cstate
2424 && GNUNET_NO == shutting_down)
2425 {
2426 LOG (GNUNET_ERROR_TYPE_DEBUG, " too few connections, getting new ones\n");
2427 GCP_connect (t->peer); /* Will change cstate to WAITING when possible */
2428 return;
2429 }
2430
2431 /* If not marked as ready, no change is needed */
2432 if (CADET_TUNNEL_READY != t->cstate)
2433 return;
2434
2435 /* Check if any connection is ready to maintain cstate */
2436 for (aux = t->connection_head; aux != NULL; aux = aux->next)
2437 if (CADET_CONNECTION_READY == GCC_get_state (aux->c))
2438 return;
2439}
2440
2441
2442/**
2443 * Add a channel to a tunnel.
2444 *
2445 * @param t Tunnel.
2446 * @param ch Channel.
2447 */
2448void
2449GCT_add_channel (struct CadetTunnel *t,
2450 struct CadetChannel *ch)
2451{
2452 struct CadetTChannel *aux;
2453
2454 GNUNET_assert (NULL != ch);
2455
2456 LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding channel %p to tunnel %p\n", ch, t);
2457
2458 for (aux = t->channel_head; aux != NULL; aux = aux->next)
2459 {
2460 LOG (GNUNET_ERROR_TYPE_DEBUG, " already there %p\n", aux->ch);
2461 if (aux->ch == ch)
2462 return;
2463 }
2464
2465 aux = GNUNET_new (struct CadetTChannel);
2466 aux->ch = ch;
2467 LOG (GNUNET_ERROR_TYPE_DEBUG,
2468 " adding %p to %p\n", aux, t->channel_head);
2469 GNUNET_CONTAINER_DLL_insert_tail (t->channel_head,
2470 t->channel_tail,
2471 aux);
2472
2473 if (NULL != t->destroy_task)
2474 {
2475 GNUNET_SCHEDULER_cancel (t->destroy_task);
2476 t->destroy_task = NULL;
2477 LOG (GNUNET_ERROR_TYPE_DEBUG, " undo destroy!\n");
2478 }
2479}
2480
2481
2482/**
2483 * Remove a channel from a tunnel.
2484 *
2485 * @param t Tunnel.
2486 * @param ch Channel.
2487 */
2488void
2489GCT_remove_channel (struct CadetTunnel *t, struct CadetChannel *ch)
2490{
2491 struct CadetTChannel *aux;
2492
2493 LOG (GNUNET_ERROR_TYPE_DEBUG, "Removing channel %p from tunnel %p\n", ch, t);
2494 for (aux = t->channel_head; aux != NULL; aux = aux->next)
2495 {
2496 if (aux->ch == ch)
2497 {
2498 LOG (GNUNET_ERROR_TYPE_DEBUG, " found! %s\n", GCCH_2s (ch));
2499 GNUNET_CONTAINER_DLL_remove (t->channel_head,
2500 t->channel_tail,
2501 aux);
2502 GNUNET_free (aux);
2503 return;
2504 }
2505 }
2506}
2507
2508
2509/**
2510 * Search for a channel by global ID.
2511 *
2512 * @param t Tunnel containing the channel.
2513 * @param ctn Public channel number.
2514 *
2515 * @return channel handler, NULL if doesn't exist
2516 */
2517struct CadetChannel *
2518GCT_get_channel (struct CadetTunnel *t,
2519 struct GNUNET_CADET_ChannelTunnelNumber ctn)
2520{
2521 struct CadetTChannel *iter;
2522
2523 if (NULL == t)
2524 return NULL;
2525
2526 for (iter = t->channel_head; NULL != iter; iter = iter->next)
2527 {
2528 if (GCCH_get_id (iter->ch).cn == ctn.cn)
2529 break;
2530 }
2531
2532 return NULL == iter ? NULL : iter->ch;
2533}
2534
2535
2536/**
2537 * @brief Destroy a tunnel and free all resources.
2538 *
2539 * Should only be called a while after the tunnel has been marked as destroyed,
2540 * in case there is a new channel added to the same peer shortly after marking
2541 * the tunnel. This way we avoid a new public key handshake.
2542 *
2543 * @param cls Closure (tunnel to destroy).
2544 */
2545static void
2546delayed_destroy (void *cls)
2547{
2548 struct CadetTunnel *t = cls;
2549 struct CadetTConnection *iter;
2550
2551 t->destroy_task = NULL;
2552 LOG (GNUNET_ERROR_TYPE_DEBUG,
2553 "delayed destroying tunnel %p\n",
2554 t);
2555 t->cstate = CADET_TUNNEL_SHUTDOWN;
2556 for (iter = t->connection_head; NULL != iter; iter = iter->next)
2557 {
2558 GCC_send_destroy (iter->c);
2559 }
2560 GCT_destroy (t);
2561}
2562
2563
2564/**
2565 * Tunnel is empty: destroy it.
2566 *
2567 * Notifies all connections about the destruction.
2568 *
2569 * @param t Tunnel to destroy.
2570 */
2571void
2572GCT_destroy_empty (struct CadetTunnel *t)
2573{
2574 if (GNUNET_YES == shutting_down)
2575 return; /* Will be destroyed immediately anyway */
2576
2577 if (NULL != t->destroy_task)
2578 {
2579 LOG (GNUNET_ERROR_TYPE_WARNING,
2580 "Tunnel %s is already scheduled for destruction. Tunnel debug dump:\n",
2581 GCT_2s (t));
2582 GCT_debug (t, GNUNET_ERROR_TYPE_WARNING);
2583 GNUNET_break (0);
2584 /* should never happen, tunnel can only become empty once, and the
2585 * task identifier should be NO_TASK (cleaned when the tunnel was created
2586 * or became un-empty)
2587 */
2588 return;
2589 }
2590
2591 LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel %s empty: scheduling destruction\n",
2592 GCT_2s (t));
2593
2594 // FIXME make delay a config option
2595 t->destroy_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
2596 &delayed_destroy, t);
2597 LOG (GNUNET_ERROR_TYPE_DEBUG, "Scheduled destroy of %p as %p\n",
2598 t, t->destroy_task);
2599}
2600
2601
2602/**
2603 * Destroy tunnel if empty (no more channels).
2604 *
2605 * @param t Tunnel to destroy if empty.
2606 */
2607void
2608GCT_destroy_if_empty (struct CadetTunnel *t)
2609{
2610 LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel %s destroy if empty\n", GCT_2s (t));
2611 if (0 < GCT_count_channels (t))
2612 return;
2613
2614 GCT_destroy_empty (t);
2615}
2616
2617
2618/**
2619 * Destroy the tunnel.
2620 *
2621 * This function does not generate any warning traffic to clients or peers.
2622 *
2623 * Tasks:
2624 * Cancel messages belonging to this tunnel queued to neighbors.
2625 * Free any allocated resources linked to the tunnel.
2626 *
2627 * @param t The tunnel to destroy.
2628 */
2629void
2630GCT_destroy (struct CadetTunnel *t)
2631{
2632 struct CadetTConnection *iter_c;
2633 struct CadetTConnection *next_c;
2634 struct CadetTChannel *iter_ch;
2635 struct CadetTChannel *next_ch;
2636 unsigned int keepalives_queued;
2637
2638 if (NULL == t)
2639 return;
2640
2641 LOG (GNUNET_ERROR_TYPE_DEBUG,
2642 "destroying tunnel %s\n",
2643 GCP_2s (t->peer));
2644 GNUNET_break (GNUNET_YES ==
2645 GNUNET_CONTAINER_multipeermap_remove (tunnels,
2646 GCP_get_id (t->peer), t));
2647
2648 for (iter_c = t->connection_head; NULL != iter_c; iter_c = next_c)
2649 {
2650 next_c = iter_c->next;
2651 GCC_destroy (iter_c->c);
2652 }
2653 for (iter_ch = t->channel_head; NULL != iter_ch; iter_ch = next_ch)
2654 {
2655 next_ch = iter_ch->next;
2656 GCCH_destroy (iter_ch->ch);
2657 /* Should only happen on shutdown, but it's ok. */
2658 }
2659 keepalives_queued = 0;
2660 while (NULL != t->tq_head)
2661 {
2662 /* Should have been cleaned by destuction of channel. */
2663 struct GNUNET_MessageHeader *mh;
2664 uint16_t type;
2665
2666 mh = (struct GNUNET_MessageHeader *) &t->tq_head[1];
2667 type = ntohs (mh->type);
2668 if (0 == keepalives_queued && GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE == type)
2669 {
2670 keepalives_queued = 1;
2671 LOG (GNUNET_ERROR_TYPE_DEBUG,
2672 "one keepalive left behind on tunnel shutdown\n");
2673 }
2674 else if (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY == type)
2675 {
2676 LOG (GNUNET_ERROR_TYPE_WARNING,
2677 "tunnel destroyed before a CHANNEL_DESTROY was sent to peer\n");
2678 }
2679 else
2680 {
2681 GNUNET_break (0);
2682 LOG (GNUNET_ERROR_TYPE_ERROR,
2683 "message left behind on tunnel shutdown: %s\n",
2684 GC_m2s (type));
2685 }
2686 unqueue_data (t->tq_head);
2687 }
2688
2689
2690 if (NULL != t->destroy_task)
2691 {
2692 LOG (GNUNET_ERROR_TYPE_DEBUG,
2693 "cancelling dest: %p\n",
2694 t->destroy_task);
2695 GNUNET_SCHEDULER_cancel (t->destroy_task);
2696 t->destroy_task = NULL;
2697 }
2698
2699 if (NULL != t->trim_connections_task)
2700 {
2701 LOG (GNUNET_ERROR_TYPE_DEBUG, "cancelling trim: %p\n",
2702 t->trim_connections_task);
2703 GNUNET_SCHEDULER_cancel (t->trim_connections_task);
2704 t->trim_connections_task = NULL;
2705 }
2706
2707 GNUNET_STATISTICS_update (stats, "# tunnels", -1, GNUNET_NO);
2708 GCP_set_tunnel (t->peer, NULL);
2709
2710 if (NULL != t->rekey_task)
2711 {
2712 GNUNET_SCHEDULER_cancel (t->rekey_task);
2713 t->rekey_task = NULL;
2714 }
2715 if (NULL != t->ax)
2716 destroy_ax (t);
2717
2718 GNUNET_free (t);
2719}
2720
2721
2722/**
2723 * @brief Use the given path for the tunnel.
2724 * Update the next and prev hops (and RCs).
2725 * (Re)start the path refresh in case the tunnel is locally owned.
2726 *
2727 * @param t Tunnel to update.
2728 * @param p Path to use.
2729 *
2730 * @return Connection created.
2731 */
2732struct CadetConnection *
2733GCT_use_path (struct CadetTunnel *t, struct CadetPeerPath *path)
2734{
2735 struct CadetConnection *c;
2736 struct GNUNET_CADET_ConnectionTunnelIdentifier cid;
2737 unsigned int own_pos;
2738
2739 if (NULL == t || NULL == path)
2740 {
2741 GNUNET_break (0);
2742 return NULL;
2743 }
2744
2745 if (CADET_TUNNEL_SHUTDOWN == t->cstate)
2746 {
2747 GNUNET_break (0);
2748 return NULL;
2749 }
2750
2751 for (own_pos = 0; own_pos < path->length; own_pos++)
2752 {
2753 if (path->peers[own_pos] == myid)
2754 break;
2755 }
2756 if (own_pos >= path->length)
2757 {
2758 GNUNET_break_op (0);
2759 return NULL;
2760 }
2761
2762 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, &cid, sizeof (cid));
2763 c = GCC_new (&cid, t, path, own_pos);
2764 if (NULL == c)
2765 {
2766 /* Path was flawed */
2767 return NULL;
2768 }
2769 GCT_add_connection (t, c);
2770 return c;
2771}
2772
2773
2774/**
2775 * Count all created connections of a tunnel. Not necessarily ready connections!
2776 *
2777 * @param t Tunnel on which to count.
2778 *
2779 * @return Number of connections created, either being established or ready.
2780 */
2781unsigned int
2782GCT_count_any_connections (struct CadetTunnel *t)
2783{
2784 struct CadetTConnection *iter;
2785 unsigned int count;
2786
2787 if (NULL == t)
2788 return 0;
2789
2790 for (count = 0, iter = t->connection_head; NULL != iter; iter = iter->next)
2791 count++;
2792
2793 return count;
2794}
2795
2796
2797/**
2798 * Count established (ready) connections of a tunnel.
2799 *
2800 * @param t Tunnel on which to count.
2801 *
2802 * @return Number of connections.
2803 */
2804unsigned int
2805GCT_count_connections (struct CadetTunnel *t)
2806{
2807 struct CadetTConnection *iter;
2808 unsigned int count;
2809
2810 if (NULL == t)
2811 return 0;
2812
2813 for (count = 0, iter = t->connection_head; NULL != iter; iter = iter->next)
2814 if (CADET_CONNECTION_READY == GCC_get_state (iter->c))
2815 count++;
2816
2817 return count;
2818}
2819
2820
2821/**
2822 * Count channels of a tunnel.
2823 *
2824 * @param t Tunnel on which to count.
2825 *
2826 * @return Number of channels.
2827 */
2828unsigned int
2829GCT_count_channels (struct CadetTunnel *t)
2830{
2831 struct CadetTChannel *iter;
2832 unsigned int count;
2833
2834 for (count = 0, iter = t->channel_head;
2835 NULL != iter;
2836 iter = iter->next, count++) /* skip */;
2837
2838 return count;
2839}
2840
2841
2842/**
2843 * Get the connectivity state of a tunnel.
2844 *
2845 * @param t Tunnel.
2846 *
2847 * @return Tunnel's connectivity state.
2848 */
2849enum CadetTunnelCState
2850GCT_get_cstate (struct CadetTunnel *t)
2851{
2852 if (NULL == t)
2853 {
2854 GNUNET_assert (0);
2855 return (enum CadetTunnelCState) -1;
2856 }
2857 return t->cstate;
2858}
2859
2860
2861/**
2862 * Get the encryption state of a tunnel.
2863 *
2864 * @param t Tunnel.
2865 *
2866 * @return Tunnel's encryption state.
2867 */
2868enum CadetTunnelEState
2869GCT_get_estate (struct CadetTunnel *t)
2870{
2871 if (NULL == t)
2872 {
2873 GNUNET_break (0);
2874 return (enum CadetTunnelEState) -1;
2875 }
2876 return t->estate;
2877}
2878
2879/**
2880 * Get the maximum buffer space for a tunnel towards a local client.
2881 *
2882 * @param t Tunnel.
2883 *
2884 * @return Biggest buffer space offered by any channel in the tunnel.
2885 */
2886unsigned int
2887GCT_get_channels_buffer (struct CadetTunnel *t)
2888{
2889 struct CadetTChannel *iter;
2890 unsigned int buffer;
2891 unsigned int ch_buf;
2892
2893 if (NULL == t->channel_head)
2894 {
2895 /* Probably getting buffer for a channel create/handshake. */
2896 LOG (GNUNET_ERROR_TYPE_DEBUG, " no channels, allow max\n");
2897 return MIN_TUNNEL_BUFFER;
2898 }
2899
2900 buffer = 0;
2901 for (iter = t->channel_head; NULL != iter; iter = iter->next)
2902 {
2903 ch_buf = get_channel_buffer (iter);
2904 if (ch_buf > buffer)
2905 buffer = ch_buf;
2906 }
2907 if (MIN_TUNNEL_BUFFER > buffer)
2908 return MIN_TUNNEL_BUFFER;
2909
2910 if (MAX_TUNNEL_BUFFER < buffer)
2911 {
2912 GNUNET_break (0);
2913 return MAX_TUNNEL_BUFFER;
2914 }
2915 return buffer;
2916}
2917
2918
2919/**
2920 * Get the total buffer space for a tunnel for P2P traffic.
2921 *
2922 * @param t Tunnel.
2923 *
2924 * @return Buffer space offered by all connections in the tunnel.
2925 */
2926unsigned int
2927GCT_get_connections_buffer (struct CadetTunnel *t)
2928{
2929 struct CadetTConnection *iter;
2930 unsigned int buffer;
2931
2932 if (GNUNET_NO == is_ready (t))
2933 {
2934 if (count_queued_data (t) >= 3)
2935 return 0;
2936 else
2937 return 1;
2938 }
2939
2940 buffer = 0;
2941 for (iter = t->connection_head; NULL != iter; iter = iter->next)
2942 {
2943 if (GCC_get_state (iter->c) != CADET_CONNECTION_READY)
2944 {
2945 continue;
2946 }
2947 buffer += get_connection_buffer (iter);
2948 }
2949
2950 return buffer;
2951}
2952
2953
2954/**
2955 * Get the tunnel's destination.
2956 *
2957 * @param t Tunnel.
2958 *
2959 * @return ID of the destination peer.
2960 */
2961const struct GNUNET_PeerIdentity *
2962GCT_get_destination (struct CadetTunnel *t)
2963{
2964 return GCP_get_id (t->peer);
2965}
2966
2967
2968/**
2969 * Get the tunnel's next free global channel ID.
2970 *
2971 * @param t Tunnel.
2972 *
2973 * @return GID of a channel free to use.
2974 */
2975struct GNUNET_CADET_ChannelTunnelNumber
2976GCT_get_next_ctn (struct CadetTunnel *t)
2977{
2978 struct GNUNET_CADET_ChannelTunnelNumber ctn;
2979 struct GNUNET_CADET_ChannelTunnelNumber mask;
2980 int result;
2981
2982 /* Set bit 30 depending on the ID relationship. Bit 31 is always 0 for GID.
2983 * If our ID is bigger or loopback tunnel, start at 0, bit 30 = 0
2984 * If peer's ID is bigger, start at 0x4... bit 30 = 1
2985 */
2986 result = GNUNET_CRYPTO_cmp_peer_identity (&my_full_id, GCP_get_id (t->peer));
2987 if (0 > result)
2988 mask.cn = htonl (0x40000000);
2989 else
2990 mask.cn = 0x0;
2991 t->next_ctn.cn |= mask.cn;
2992
2993 while (NULL != GCT_get_channel (t, t->next_ctn))
2994 {
2995 LOG (GNUNET_ERROR_TYPE_DEBUG,
2996 "Channel %u exists...\n",
2997 t->next_ctn.cn);
2998 t->next_ctn.cn = htonl ((ntohl (t->next_ctn.cn) + 1) & ~GNUNET_CADET_LOCAL_CHANNEL_ID_CLI);
2999 t->next_ctn.cn |= mask.cn;
3000 }
3001 ctn = t->next_ctn;
3002 t->next_ctn.cn = (t->next_ctn.cn + 1) & ~GNUNET_CADET_LOCAL_CHANNEL_ID_CLI;
3003 t->next_ctn.cn |= mask.cn;
3004
3005 return ctn;
3006}
3007
3008
3009/**
3010 * Send ACK on one or more channels due to buffer in connections.
3011 *
3012 * @param t Channel which has some free buffer space.
3013 */
3014void
3015GCT_unchoke_channels (struct CadetTunnel *t)
3016{
3017 struct CadetTChannel *iter;
3018 unsigned int buffer;
3019 unsigned int channels = GCT_count_channels (t);
3020 unsigned int choked_n;
3021 struct CadetChannel *choked[channels];
3022
3023 LOG (GNUNET_ERROR_TYPE_DEBUG, "GCT_unchoke_channels on %s\n", GCT_2s (t));
3024 LOG (GNUNET_ERROR_TYPE_DEBUG, " head: %p\n", t->channel_head);
3025 if (NULL != t->channel_head)
3026 LOG (GNUNET_ERROR_TYPE_DEBUG, " head ch: %p\n", t->channel_head->ch);
3027
3028 if (NULL != t->tq_head)
3029 send_queued_data (t);
3030
3031 /* Get buffer space */
3032 buffer = GCT_get_connections_buffer (t);
3033 if (0 == buffer)
3034 {
3035 return;
3036 }
3037
3038 /* Count and remember choked channels */
3039 choked_n = 0;
3040 for (iter = t->channel_head; NULL != iter; iter = iter->next)
3041 {
3042 if (GNUNET_NO == get_channel_allowed (iter))
3043 {
3044 choked[choked_n++] = iter->ch;
3045 }
3046 }
3047
3048 /* Unchoke random channels */
3049 while (0 < buffer && 0 < choked_n)
3050 {
3051 unsigned int r = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
3052 choked_n);
3053 GCCH_allow_client (choked[r], GCCH_is_origin (choked[r], GNUNET_YES));
3054 choked_n--;
3055 buffer--;
3056 choked[r] = choked[choked_n];
3057 }
3058}
3059
3060
3061/**
3062 * Send ACK on one or more connections due to buffer space to the client.
3063 *
3064 * Iterates all connections of the tunnel and sends ACKs appropriately.
3065 *
3066 * @param t Tunnel.
3067 */
3068void
3069GCT_send_connection_acks (struct CadetTunnel *t)
3070{
3071 struct CadetTConnection *iter;
3072 uint32_t allowed;
3073 uint32_t to_allow;
3074 uint32_t allow_per_connection;
3075 unsigned int cs;
3076 unsigned int buffer;
3077
3078 LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel send connection ACKs on %s\n",
3079 GCT_2s (t));
3080
3081 if (NULL == t)
3082 {
3083 GNUNET_break (0);
3084 return;
3085 }
3086
3087 if (CADET_TUNNEL_READY != t->cstate)
3088 return;
3089
3090 buffer = GCT_get_channels_buffer (t);
3091 LOG (GNUNET_ERROR_TYPE_DEBUG, " buffer %u\n", buffer);
3092
3093 /* Count connections, how many messages are already allowed */
3094 cs = GCT_count_connections (t);
3095 for (allowed = 0, iter = t->connection_head; NULL != iter; iter = iter->next)
3096 {
3097 allowed += get_connection_allowed (iter);
3098 }
3099 LOG (GNUNET_ERROR_TYPE_DEBUG, " allowed %u\n", allowed);
3100
3101 /* Make sure there is no overflow */
3102 if (allowed > buffer)
3103 return;
3104
3105 /* Authorize connections to send more data */
3106 to_allow = buffer - allowed;
3107
3108 for (iter = t->connection_head;
3109 NULL != iter && to_allow > 0;
3110 iter = iter->next)
3111 {
3112 if (CADET_CONNECTION_READY != GCC_get_state (iter->c)
3113 || get_connection_allowed (iter) > 64 / 3)
3114 {
3115 continue;
3116 }
3117 GNUNET_assert(cs != 0);
3118 allow_per_connection = to_allow/cs;
3119 to_allow -= allow_per_connection;
3120 cs--;
3121 GCC_allow (iter->c, allow_per_connection,
3122 GCC_is_origin (iter->c, GNUNET_NO));
3123 }
3124
3125 if (0 != to_allow)
3126 {
3127 /* Since we don't allow if it's allowed to send 64/3, this can happen. */
3128 LOG (GNUNET_ERROR_TYPE_DEBUG, " reminding to_allow: %u\n", to_allow);
3129 }
3130}
3131
3132
3133/**
3134 * Cancel a previously sent message while it's in the queue.
3135 *
3136 * ONLY can be called before the continuation given to the send function
3137 * is called. Once the continuation is called, the message is no longer in the
3138 * queue.
3139 *
3140 * @param q Handle to the queue.
3141 */
3142void
3143GCT_cancel (struct CadetTunnelQueue *q)
3144{
3145 if (NULL != q->cq)
3146 {
3147 GNUNET_assert (NULL == q->tqd);
3148 GCC_cancel (q->cq);
3149 /* tun_message_sent() will be called and free q */
3150 }
3151 else if (NULL != q->tqd)
3152 {
3153 unqueue_data (q->tqd);
3154 q->tqd = NULL;
3155 if (NULL != q->cont)
3156 q->cont (q->cont_cls, NULL, q, 0, 0);
3157 GNUNET_free (q);
3158 }
3159 else
3160 {
3161 GNUNET_break (0);
3162 }
3163}
3164
3165
3166/**
3167 * Check if the tunnel has queued traffic.
3168 *
3169 * @param t Tunnel to check.
3170 *
3171 * @return #GNUNET_YES if there is queued traffic
3172 * #GNUNET_NO otherwise
3173 */
3174int
3175GCT_has_queued_traffic (struct CadetTunnel *t)
3176{
3177 return (NULL != t->tq_head) ? GNUNET_YES : GNUNET_NO;
3178}
3179
3180
3181/**
3182 * Sends an already built message on a tunnel, encrypting it and
3183 * choosing the best connection if not provided.
3184 *
3185 * @param message Message to send. Function modifies it.
3186 * @param t Tunnel on which this message is transmitted.
3187 * @param c Connection to use (autoselect if NULL).
3188 * @param force Force the tunnel to take the message (buffer overfill).
3189 * @param cont Continuation to call once message is really sent.
3190 * @param cont_cls Closure for @c cont.
3191 *
3192 * @return Handle to cancel message. NULL if @c cont is NULL.
3193 */
3194struct CadetTunnelQueue *
3195GCT_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
3196 struct CadetTunnel *t,
3197 struct CadetConnection *c,
3198 int force, GCT_sent cont, void *cont_cls)
3199{
3200 return send_prebuilt_message (message, t, c, force, cont, cont_cls, NULL);
3201}
3202
3203
3204/**
3205 * Send a KX message.
3206 *
3207 * @param t Tunnel on which to send it.
3208 * @param force_reply Force the other peer to reply with a KX message.
3209 */
3210void
3211GCT_send_kx (struct CadetTunnel *t, int force_reply)
3212{
3213 static struct CadetEncryptedMessageIdentifier zero;
3214 struct CadetConnection *c;
3215 struct GNUNET_CADET_TunnelKeyExchangeMessage msg;
3216 enum GNUNET_CADET_KX_Flags flags;
3217
3218 LOG (GNUNET_ERROR_TYPE_INFO, "==> { KX} on %s\n", GCT_2s (t));
3219 if (NULL != t->ephm_h)
3220 {
3221 LOG (GNUNET_ERROR_TYPE_INFO, " already queued, nop\n");
3222 return;
3223 }
3224 GNUNET_assert (GNUNET_NO == GCT_is_loopback (t));
3225
3226 c = tunnel_get_connection (t);
3227 if (NULL == c)
3228 {
3229 if (NULL == t->destroy_task && CADET_TUNNEL_READY == t->cstate)
3230 {
3231 GNUNET_break (0);
3232 GCT_debug (t, GNUNET_ERROR_TYPE_ERROR);
3233 }
3234 return;
3235 }
3236
3237 msg.header.size = htons (sizeof (msg));
3238 msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX);
3239 flags = GNUNET_CADET_KX_FLAG_NONE;
3240 if (GNUNET_YES == force_reply)
3241 flags |= GNUNET_CADET_KX_FLAG_FORCE_REPLY;
3242 msg.flags = htonl (flags);
3243 msg.cid = *GCC_get_id (c);
3244 GNUNET_CRYPTO_ecdhe_key_get_public (t->ax->kx_0, &msg.ephemeral_key);
3245 GNUNET_CRYPTO_ecdhe_key_get_public (t->ax->DHRs, &msg.ratchet_key);
3246
3247 t->ephm_h = GCC_send_prebuilt_message (&msg.header,
3248 UINT16_MAX,
3249 zero,
3250 c,
3251 GCC_is_origin (c, GNUNET_YES),
3252 GNUNET_YES, &ephm_sent, t);
3253 if (CADET_TUNNEL_KEY_UNINITIALIZED == t->estate)
3254 GCT_change_estate (t, CADET_TUNNEL_KEY_AX_SENT);
3255}
3256
3257
3258/**
3259 * Is the tunnel directed towards the local peer?
3260 *
3261 * @param t Tunnel.
3262 *
3263 * @return #GNUNET_YES if it is loopback.
3264 */
3265int
3266GCT_is_loopback (const struct CadetTunnel *t)
3267{
3268 return (myid == GCP_get_short_id (t->peer));
3269}
3270
3271
3272/**
3273 * Is the tunnel this path already?
3274 *
3275 * @param t Tunnel.
3276 * @param p Path.
3277 *
3278 * @return #GNUNET_YES a connection uses this path.
3279 */
3280int
3281GCT_is_path_used (const struct CadetTunnel *t, const struct CadetPeerPath *p)
3282{
3283 struct CadetTConnection *iter;
3284
3285 for (iter = t->connection_head; NULL != iter; iter = iter->next)
3286 if (path_equivalent (GCC_get_path (iter->c), p))
3287 return GNUNET_YES;
3288
3289 return GNUNET_NO;
3290}
3291
3292
3293/**
3294 * Get a cost of a path for a tunnel considering existing connections.
3295 *
3296 * @param t Tunnel.
3297 * @param path Candidate path.
3298 *
3299 * @return Cost of the path (path length + number of overlapping nodes)
3300 */
3301unsigned int
3302GCT_get_path_cost (const struct CadetTunnel *t,
3303 const struct CadetPeerPath *path)
3304{
3305 struct CadetTConnection *iter;
3306 const struct CadetPeerPath *aux;
3307 unsigned int overlap;
3308 unsigned int i;
3309 unsigned int j;
3310
3311 if (NULL == path)
3312 return 0;
3313
3314 overlap = 0;
3315 GNUNET_assert (NULL != t);
3316
3317 for (i = 0; i < path->length; i++)
3318 {
3319 for (iter = t->connection_head; NULL != iter; iter = iter->next)
3320 {
3321 aux = GCC_get_path (iter->c);
3322 if (NULL == aux)
3323 continue;
3324
3325 for (j = 0; j < aux->length; j++)
3326 {
3327 if (path->peers[i] == aux->peers[j])
3328 {
3329 overlap++;
3330 break;
3331 }
3332 }
3333 }
3334 }
3335 return path->length + overlap;
3336}
3337
3338
3339/**
3340 * Get the static string for the peer this tunnel is directed.
3341 *
3342 * @param t Tunnel.
3343 *
3344 * @return Static string the destination peer's ID.
3345 */
3346const char *
3347GCT_2s (const struct CadetTunnel *t)
3348{
3349 if (NULL == t)
3350 return "(NULL)";
3351
3352 return GCP_2s (t->peer);
3353}
3354
3355
3356/******************************************************************************/
3357/***************************** INFO/DEBUG *******************************/
3358/******************************************************************************/
3359
3360static void
3361ax_debug (const struct CadetTunnelAxolotl *ax, enum GNUNET_ErrorType level)
3362{
3363 struct GNUNET_CRYPTO_EcdhePublicKey pub;
3364 struct CadetTunnelSkippedKey *iter;
3365
3366 LOG2 (level, "TTT RK \t %s\n",
3367 GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->RK));
3368
3369 LOG2 (level, "TTT HKs \t %s\n",
3370 GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->HKs));
3371 LOG2 (level, "TTT HKr \t %s\n",
3372 GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->HKr));
3373 LOG2 (level, "TTT NHKs\t %s\n",
3374 GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->NHKs));
3375 LOG2 (level, "TTT NHKr\t %s\n",
3376 GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->NHKr));
3377
3378 LOG2 (level, "TTT CKs \t %s\n",
3379 GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->CKs));
3380 LOG2 (level, "TTT CKr \t %s\n",
3381 GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->CKr));
3382
3383 GNUNET_CRYPTO_ecdhe_key_get_public (ax->DHRs, &pub);
3384 LOG2 (level, "TTT DHRs\t %s\n",
3385 GNUNET_i2s ((struct GNUNET_PeerIdentity *) &pub));
3386 LOG2 (level, "TTT DHRr\t %s\n",
3387 GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->DHRr));
3388
3389 LOG2 (level, "TTT Nr\t %u\tNs\t%u\n", ax->Nr, ax->Ns);
3390 LOG2 (level, "TTT PNs\t %u\tSkipped\t%u\n", ax->PNs, ax->skipped);
3391 LOG2 (level, "TTT Ratchet\t%u\n", ax->ratchet_flag);
3392
3393 for (iter = ax->skipped_head; NULL != iter; iter = iter->next)
3394 {
3395 LOG2 (level, "TTT HK\t %s\n",
3396 GNUNET_i2s ((struct GNUNET_PeerIdentity *) &iter->HK));
3397 LOG2 (level, "TTT MK\t %s\n",
3398 GNUNET_i2s ((struct GNUNET_PeerIdentity *) &iter->MK));
3399 }
3400}
3401
3402/**
3403 * Log all possible info about the tunnel state.
3404 *
3405 * @param t Tunnel to debug.
3406 * @param level Debug level to use.
3407 */
3408void
3409GCT_debug (const struct CadetTunnel *t, enum GNUNET_ErrorType level)
3410{
3411 struct CadetTChannel *iter_ch;
3412 struct CadetTConnection *iter_c;
3413 int do_log;
3414
3415 do_log = GNUNET_get_log_call_status (level & (~GNUNET_ERROR_TYPE_BULK),
3416 "cadet-tun",
3417 __FILE__, __FUNCTION__, __LINE__);
3418 if (0 == do_log)
3419 return;
3420
3421 LOG2 (level, "TTT DEBUG TUNNEL TOWARDS %s\n", GCT_2s (t));
3422 LOG2 (level, "TTT cstate %s, estate %s\n",
3423 cstate2s (t->cstate), estate2s (t->estate));
3424#if DUMP_KEYS_TO_STDERR
3425 ax_debug (t->ax, level);
3426#endif
3427 LOG2 (level, "TTT tq_head %p, tq_tail %p\n", t->tq_head, t->tq_tail);
3428 LOG2 (level, "TTT destroy %p\n", t->destroy_task);
3429 LOG2 (level, "TTT channels:\n");
3430 for (iter_ch = t->channel_head; NULL != iter_ch; iter_ch = iter_ch->next)
3431 {
3432 GCCH_debug (iter_ch->ch, level);
3433 }
3434
3435 LOG2 (level, "TTT connections:\n");
3436 for (iter_c = t->connection_head; NULL != iter_c; iter_c = iter_c->next)
3437 {
3438 GCC_debug (iter_c->c, level);
3439 }
3440
3441 LOG2 (level, "TTT DEBUG TUNNEL END\n");
3442}
3443
3444
3445/**
3446 * Iterate all tunnels.
3447 *
3448 * @param iter Iterator.
3449 * @param cls Closure for @c iter.
3450 */
3451void
3452GCT_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter, void *cls)
3453{
3454 GNUNET_CONTAINER_multipeermap_iterate (tunnels, iter, cls);
3455}
3456
3457
3458/**
3459 * Count all tunnels.
3460 *
3461 * @return Number of tunnels to remote peers kept by this peer.
3462 */
3463unsigned int
3464GCT_count_all (void)
3465{
3466 return GNUNET_CONTAINER_multipeermap_size (tunnels);
3467}
3468
3469
3470/**
3471 * Iterate all connections of a tunnel.
3472 *
3473 * @param t Tunnel whose connections to iterate.
3474 * @param iter Iterator.
3475 * @param cls Closure for @c iter.
3476 */
3477void
3478GCT_iterate_connections (struct CadetTunnel *t, GCT_conn_iter iter, void *cls)
3479{
3480 struct CadetTConnection *ct;
3481
3482 for (ct = t->connection_head; NULL != ct; ct = ct->next)
3483 iter (cls, ct->c);
3484}
3485
3486
3487/**
3488 * Iterate all channels of a tunnel.
3489 *
3490 * @param t Tunnel whose channels to iterate.
3491 * @param iter Iterator.
3492 * @param cls Closure for @c iter.
3493 */
3494void
3495GCT_iterate_channels (struct CadetTunnel *t, GCT_chan_iter iter, void *cls)
3496{
3497 struct CadetTChannel *cht;
3498
3499 for (cht = t->channel_head; NULL != cht; cht = cht->next)
3500 iter (cls, cht->ch);
3501}
diff --git a/src/cadet/gnunet-service-cadet_tunnel.h b/src/cadet/gnunet-service-cadet_tunnel.h
deleted file mode 100644
index 1b56a0632..000000000
--- a/src/cadet/gnunet-service-cadet_tunnel.h
+++ /dev/null
@@ -1,616 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2013 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21/**
22 * @file cadet/gnunet-service-cadet_tunnel.h
23 * @brief cadet service; dealing with tunnels and crypto
24 * @author Bartlomiej Polot
25 *
26 * All functions in this file should use the prefix GMT (Gnunet Cadet Tunnel)
27 */
28
29#ifndef GNUNET_SERVICE_CADET_TUNNEL_H
30#define GNUNET_SERVICE_CADET_TUNNEL_H
31
32#ifdef __cplusplus
33extern "C"
34{
35#if 0 /* keep Emacsens' auto-indent happy */
36}
37#endif
38#endif
39
40#include "platform.h"
41#include "gnunet_util_lib.h"
42
43#define CONNECTIONS_PER_TUNNEL 3
44
45/**
46 * All the connectivity states a tunnel can be in.
47 */
48enum CadetTunnelCState
49{
50 /**
51 * Uninitialized status, should never appear in operation.
52 */
53 CADET_TUNNEL_NEW,
54
55 /**
56 * No path to the peer known yet.
57 */
58 CADET_TUNNEL_SEARCHING,
59
60 /**
61 * Request sent, not yet answered.
62 */
63 CADET_TUNNEL_WAITING,
64
65 /**
66 * Peer connected and ready to accept data.
67 */
68 CADET_TUNNEL_READY,
69
70 /**
71 * Tunnel being shut down, don't try to keep it alive.
72 */
73 CADET_TUNNEL_SHUTDOWN
74};
75
76
77/**
78 * All the encryption states a tunnel can be in.
79 */
80enum CadetTunnelEState
81{
82 /**
83 * Uninitialized status, should never appear in operation.
84 */
85 CADET_TUNNEL_KEY_UNINITIALIZED,
86
87 /**
88 * Ephemeral key sent, waiting for peer's key.
89 */
90 CADET_TUNNEL_KEY_AX_SENT,
91
92 /**
93 * In OTR: New ephemeral key and ping sent, waiting for pong.
94 *
95 * This means that we DO have the peer's ephemeral key, otherwise the
96 * state would be KEY_SENT. We DO NOT have a valid session key (either no
97 * previous key or previous key expired).
98 *
99 *
100 * In Axolotl: Key sent and received but no deciphered traffic yet.
101 *
102 * This means that we can send traffic (otherwise we would never complete
103 * the handshake), but we don't have complete confirmation. Since the first
104 * traffic MUST be a complete channel creation 3-way handshake, no payload
105 * will be sent before confirmation.
106 */
107 CADET_TUNNEL_KEY_AX_AUTH_SENT,
108
109 /**
110 * Handshake completed: session key available.
111 */
112 CADET_TUNNEL_KEY_OK,
113
114 /**
115 * New ephemeral key and ping sent, waiting for pong. Unlike KEY_PING,
116 * we still have a valid session key and therefore we *can* still send
117 * traffic on the tunnel.
118 */
119 CADET_TUNNEL_KEY_REKEY
120};
121
122/**
123 * Struct containing all information regarding a given peer
124 */
125struct CadetTunnel;
126
127
128#include "gnunet-service-cadet_channel.h"
129#include "gnunet-service-cadet_connection.h"
130#include "gnunet-service-cadet_peer.h"
131
132/**
133 * Handle for messages queued but not yet sent.
134 */
135struct CadetTunnelQueue;
136
137/**
138 * Callback called when a queued message is sent.
139 *
140 * @param cls Closure.
141 * @param t Tunnel this message was on.
142 * @param type Type of message sent.
143 * @param size Size of the message.
144 */
145typedef void
146(*GCT_sent) (void *cls,
147 struct CadetTunnel *t,
148 struct CadetTunnelQueue *q,
149 uint16_t type, size_t size);
150
151typedef void
152(*GCT_conn_iter) (void *cls, struct CadetConnection *c);
153
154
155typedef void
156(*GCT_chan_iter) (void *cls, struct CadetChannel *ch);
157
158
159/******************************************************************************/
160/******************************** API ***********************************/
161/******************************************************************************/
162
163/**
164 * Initialize tunnel subsystem.
165 *
166 * @param c Configuration handle.
167 * @param key ECC private key, to derive all other keys and do crypto.
168 */
169void
170GCT_init (const struct GNUNET_CONFIGURATION_Handle *c,
171 const struct GNUNET_CRYPTO_EddsaPrivateKey *key);
172
173
174/**
175 * Shut down the tunnel subsystem.
176 */
177void
178GCT_shutdown (void);
179
180
181/**
182 * Create a tunnel.
183 *
184 * @param destination Peer this tunnel is towards.
185 */
186struct CadetTunnel *
187GCT_new (struct CadetPeer *destination);
188
189
190/**
191 * Tunnel is empty: destroy it.
192 *
193 * Notifies all connections about the destruction.
194 *
195 * @param t Tunnel to destroy.
196 */
197void
198GCT_destroy_empty (struct CadetTunnel *t);
199
200
201/**
202 * Destroy tunnel if empty (no more channels).
203 *
204 * @param t Tunnel to destroy if empty.
205 */
206void
207GCT_destroy_if_empty (struct CadetTunnel *t);
208
209
210/**
211 * Destroy the tunnel.
212 *
213 * This function does not generate any warning traffic to clients or peers.
214 *
215 * Tasks:
216 * Cancel messages belonging to this tunnel queued to neighbors.
217 * Free any allocated resources linked to the tunnel.
218 *
219 * @param t The tunnel to destroy.
220 */
221void
222GCT_destroy (struct CadetTunnel *t);
223
224
225/**
226 * Change the tunnel's connection state.
227 *
228 * @param t Tunnel whose connection state to change.
229 * @param cstate New connection state.
230 */
231void
232GCT_change_cstate (struct CadetTunnel* t, enum CadetTunnelCState cstate);
233
234
235/**
236 * Change the tunnel encryption state.
237 *
238 * @param t Tunnel whose encryption state to change.
239 * @param state New encryption state.
240 */
241void
242GCT_change_estate (struct CadetTunnel* t, enum CadetTunnelEState state);
243
244
245/**
246 * Add a connection to a tunnel.
247 *
248 * @param t Tunnel.
249 * @param c Connection.
250 */
251void
252GCT_add_connection (struct CadetTunnel *t, struct CadetConnection *c);
253
254
255/**
256 * Remove a connection from a tunnel.
257 *
258 * @param t Tunnel.
259 * @param c Connection.
260 */
261void
262GCT_remove_connection (struct CadetTunnel *t, struct CadetConnection *c);
263
264
265/**
266 * Add a channel to a tunnel.
267 *
268 * @param t Tunnel.
269 * @param ch Channel.
270 */
271void
272GCT_add_channel (struct CadetTunnel *t, struct CadetChannel *ch);
273
274
275/**
276 * Remove a channel from a tunnel.
277 *
278 * @param t Tunnel.
279 * @param ch Channel.
280 */
281void
282GCT_remove_channel (struct CadetTunnel *t, struct CadetChannel *ch);
283
284
285/**
286 * Search for a channel by global ID.
287 *
288 * @param t Tunnel containing the channel.
289 * @param ctn Public channel number.
290 *
291 * @return channel handler, NULL if doesn't exist
292 */
293struct CadetChannel *
294GCT_get_channel (struct CadetTunnel *t, struct GNUNET_CADET_ChannelTunnelNumber ctn);
295
296
297/**
298 * Decrypt and process an encrypted message.
299 *
300 * Calls the appropriate handler for a message in a channel of a local tunnel.
301 *
302 * @param t Tunnel this message came on.
303 * @param msg Message header.
304 */
305void
306GCT_handle_encrypted (struct CadetTunnel *t,
307 const struct GNUNET_CADET_TunnelEncryptedMessage *msg);
308
309
310/**
311 * Handle a Key eXchange message.
312 *
313 * @param t Tunnel on which the message came.
314 * @param msg KX message itself.
315 */
316void
317GCT_handle_kx (struct CadetTunnel *t,
318 const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg);
319
320
321/**
322 * @brief Use the given path for the tunnel.
323 * Update the next and prev hops (and RCs).
324 * (Re)start the path refresh in case the tunnel is locally owned.
325 *
326 * @param t Tunnel to update.
327 * @param p Path to use.
328 *
329 * @return Connection created.
330 */
331struct CadetConnection *
332GCT_use_path (struct CadetTunnel *t, struct CadetPeerPath *p);
333
334
335/**
336 * Count all created connections of a tunnel. Not necessarily ready connections!
337 *
338 * @param t Tunnel on which to count.
339 *
340 * @return Number of connections created, either being established or ready.
341 */
342unsigned int
343GCT_count_any_connections (struct CadetTunnel *t);
344
345
346/**
347 * Count established (ready) connections of a tunnel.
348 *
349 * @param t Tunnel on which to count.
350 *
351 * @return Number of connections.
352 */
353unsigned int
354GCT_count_connections (struct CadetTunnel *t);
355
356
357/**
358 * Count channels of a tunnel.
359 *
360 * @param t Tunnel on which to count.
361 *
362 * @return Number of channels.
363 */
364unsigned int
365GCT_count_channels (struct CadetTunnel *t);
366
367
368/**
369 * Get the connectivity state of a tunnel.
370 *
371 * @param t Tunnel.
372 *
373 * @return Tunnel's connectivity state.
374 */
375enum CadetTunnelCState
376GCT_get_cstate (struct CadetTunnel *t);
377
378
379/**
380 * Get the encryption state of a tunnel.
381 *
382 * @param t Tunnel.
383 *
384 * @return Tunnel's encryption state.
385 */
386enum CadetTunnelEState
387GCT_get_estate (struct CadetTunnel *t);
388
389
390/**
391 * Get the maximum buffer space for a tunnel towards a local client.
392 *
393 * @param t Tunnel.
394 *
395 * @return Biggest buffer space offered by any channel in the tunnel.
396 */
397unsigned int
398GCT_get_channels_buffer (struct CadetTunnel *t);
399
400
401/**
402 * Get the total buffer space for a tunnel for P2P traffic.
403 *
404 * @param t Tunnel.
405 *
406 * @return Buffer space offered by all connections in the tunnel.
407 */
408unsigned int
409GCT_get_connections_buffer (struct CadetTunnel *t);
410
411
412/**
413 * Get the tunnel's destination.
414 *
415 * @param t Tunnel.
416 *
417 * @return ID of the destination peer.
418 */
419const struct GNUNET_PeerIdentity *
420GCT_get_destination (struct CadetTunnel *t);
421
422
423/**
424 * Get the tunnel's next free Channel ID.
425 *
426 * @param t Tunnel.
427 *
428 * @return ID of a channel free to use.
429 */
430struct GNUNET_CADET_ChannelTunnelNumber
431GCT_get_next_ctn (struct CadetTunnel *t);
432
433
434/**
435 * Send ACK on one or more channels due to buffer in connections.
436 *
437 * @param t Channel which has some free buffer space.
438 */
439void
440GCT_unchoke_channels (struct CadetTunnel *t);
441
442
443/**
444 * Send ACK on one or more connections due to buffer space to the client.
445 *
446 * Iterates all connections of the tunnel and sends ACKs appropriately.
447 *
448 * @param t Tunnel which has some free buffer space.
449 */
450void
451GCT_send_connection_acks (struct CadetTunnel *t);
452
453
454/**
455 * Cancel a previously sent message while it's in the queue.
456 *
457 * ONLY can be called before the continuation given to the send function
458 * is called. Once the continuation is called, the message is no longer in the
459 * queue.
460 *
461 * @param q Handle to the queue.
462 */
463void
464GCT_cancel (struct CadetTunnelQueue *q);
465
466
467/**
468 * Check if the tunnel has queued traffic.
469 *
470 * @param t Tunnel to check.
471 *
472 * @return #GNUNET_YES if there is queued traffic
473 * #GNUNET_NO otherwise
474 */
475int
476GCT_has_queued_traffic (struct CadetTunnel *t);
477
478/**
479 * Sends an already built message on a tunnel, encrypting it and
480 * choosing the best connection.
481 *
482 * @param message Message to send. Function modifies it.
483 * @param t Tunnel on which this message is transmitted.
484 * @param c Connection to use (autoselect if NULL).
485 * @param force Force the tunnel to take the message (buffer overfill).
486 * @param cont Continuation to call once message is really sent.
487 * @param cont_cls Closure for @c cont.
488 *
489 * @return Handle to cancel message. NULL if @c cont is NULL.
490 */
491struct CadetTunnelQueue *
492GCT_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
493 struct CadetTunnel *t, struct CadetConnection *c,
494 int force, GCT_sent cont, void *cont_cls);
495
496
497/**
498 * Send a KX message.
499 *
500 * @param t Tunnel on which to send it.
501 * @param force_reply Force the other peer to reply with a KX message.
502 */
503void
504GCT_send_kx (struct CadetTunnel *t, int force_reply);
505
506
507/**
508 * Is the tunnel directed towards the local peer?
509 *
510 * @param t Tunnel.
511 *
512 * @return #GNUNET_YES if it is loopback.
513 */
514int
515GCT_is_loopback (const struct CadetTunnel *t);
516
517
518/**
519 * Is the tunnel using this path already?
520 *
521 * @param t Tunnel.
522 * @param p Path.
523 *
524 * @return #GNUNET_YES a connection uses this path.
525 */
526int
527GCT_is_path_used (const struct CadetTunnel *t, const struct CadetPeerPath *p);
528
529
530/**
531 * Get a cost of a path for a tunnel considering existing connections.
532 *
533 * @param t Tunnel.
534 * @param path Candidate path.
535 *
536 * @return Cost of the path (path length + number of overlapping nodes)
537 */
538unsigned int
539GCT_get_path_cost (const struct CadetTunnel *t,
540 const struct CadetPeerPath *path);
541
542
543/**
544 * Get the static string for the peer this tunnel is directed.
545 *
546 * @param t Tunnel.
547 *
548 * @return Static string the destination peer's ID.
549 */
550const char *
551GCT_2s (const struct CadetTunnel *t);
552
553
554/**
555 * Log all possible info about the tunnel state.
556 *
557 * @param t Tunnel to debug.
558 * @param level Debug level to use.
559 */
560void
561GCT_debug (const struct CadetTunnel *t, enum GNUNET_ErrorType level);
562
563
564/**
565 * Iterate all tunnels.
566 *
567 * @param iter Iterator.
568 * @param cls Closure for @c iter.
569 */
570void
571GCT_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter, void *cls);
572
573
574/**
575 * Count all tunnels.
576 *
577 * @return Number of tunnels to remote peers kept by this peer.
578 */
579unsigned int
580GCT_count_all (void);
581
582
583/**
584 * Iterate all connections of a tunnel.
585 *
586 * @param t Tunnel whose connections to iterate.
587 * @param iter Iterator.
588 * @param cls Closure for @c iter.
589 */
590void
591GCT_iterate_connections (struct CadetTunnel *t, GCT_conn_iter iter, void *cls);
592
593
594/**
595 * Iterate all channels of a tunnel.
596 *
597 * @param t Tunnel whose channels to iterate.
598 * @param iter Iterator.
599 * @param cls Closure for @c iter.
600 */
601void
602GCT_iterate_channels (struct CadetTunnel *t,
603 GCT_chan_iter iter,
604 void *cls);
605
606
607#if 0 /* keep Emacsens' auto-indent happy */
608{
609#endif
610#ifdef __cplusplus
611}
612#endif
613
614/* ifndef GNUNET_CADET_SERVICE_TUNNEL_H */
615#endif
616/* end of gnunet-cadet-service_tunnel.h */
diff --git a/src/cadet/gnunet-service-cadet-new_tunnels.c b/src/cadet/gnunet-service-cadet_tunnels.c
index bf05fae6b..bcdeeb4da 100644
--- a/src/cadet/gnunet-service-cadet-new_tunnels.c
+++ b/src/cadet/gnunet-service-cadet_tunnels.c
@@ -18,7 +18,7 @@
18 Boston, MA 02110-1301, USA. 18 Boston, MA 02110-1301, USA.
19*/ 19*/
20/** 20/**
21 * @file cadet/gnunet-service-cadet-new_tunnels.c 21 * @file cadet/gnunet-service-cadet_tunnels.c
22 * @brief Information we track per tunnel. 22 * @brief Information we track per tunnel.
23 * @author Bartlomiej Polot 23 * @author Bartlomiej Polot
24 * @author Christian Grothoff 24 * @author Christian Grothoff
@@ -34,13 +34,12 @@
34#include "gnunet_util_lib.h" 34#include "gnunet_util_lib.h"
35#include "gnunet_statistics_service.h" 35#include "gnunet_statistics_service.h"
36#include "gnunet_signatures.h" 36#include "gnunet_signatures.h"
37#include "gnunet-service-cadet-new.h"
38#include "cadet_protocol.h" 37#include "cadet_protocol.h"
39#include "gnunet-service-cadet-new_channel.h" 38#include "gnunet-service-cadet_channel.h"
40#include "gnunet-service-cadet-new_connection.h" 39#include "gnunet-service-cadet_connection.h"
41#include "gnunet-service-cadet-new_tunnels.h" 40#include "gnunet-service-cadet_tunnels.h"
42#include "gnunet-service-cadet-new_peer.h" 41#include "gnunet-service-cadet_peer.h"
43#include "gnunet-service-cadet-new_paths.h" 42#include "gnunet-service-cadet_paths.h"
44 43
45 44
46#define LOG(level, ...) GNUNET_log_from(level,"cadet-tun",__VA_ARGS__) 45#define LOG(level, ...) GNUNET_log_from(level,"cadet-tun",__VA_ARGS__)
@@ -3082,10 +3081,6 @@ GCT_handle_encrypted (struct CadetTConnection *ct,
3082 break; 3081 break;
3083 } 3082 }
3084 3083
3085 GNUNET_STATISTICS_update (stats,
3086 "# received encrypted",
3087 1,
3088 GNUNET_NO);
3089 decrypted_size = -1; 3084 decrypted_size = -1;
3090 if (CADET_TUNNEL_KEY_OK == t->estate) 3085 if (CADET_TUNNEL_KEY_OK == t->estate)
3091 { 3086 {
@@ -3166,6 +3161,10 @@ GCT_handle_encrypted (struct CadetTConnection *ct,
3166 &t->ax); 3161 &t->ax);
3167 return; 3162 return;
3168 } 3163 }
3164 GNUNET_STATISTICS_update (stats,
3165 "# decrypted bytes",
3166 decrypted_size,
3167 GNUNET_NO);
3169 3168
3170 /* The MST will ultimately call #handle_decrypted() on each message. */ 3169 /* The MST will ultimately call #handle_decrypted() on each message. */
3171 t->current_ct = ct; 3170 t->current_ct = ct;
@@ -3217,6 +3216,10 @@ GCT_send (struct CadetTunnel *t,
3217 &ax_msg[1], 3216 &ax_msg[1],
3218 message, 3217 message,
3219 payload_size); 3218 payload_size);
3219 GNUNET_STATISTICS_update (stats,
3220 "# encrypted bytes",
3221 payload_size,
3222 GNUNET_NO);
3220 ax_msg->ax_header.Ns = htonl (t->ax.Ns++); 3223 ax_msg->ax_header.Ns = htonl (t->ax.Ns++);
3221 ax_msg->ax_header.PNs = htonl (t->ax.PNs); 3224 ax_msg->ax_header.PNs = htonl (t->ax.PNs);
3222 /* FIXME: we should do this once, not once per message; 3225 /* FIXME: we should do this once, not once per message;
diff --git a/src/cadet/gnunet-service-cadet-new_tunnels.h b/src/cadet/gnunet-service-cadet_tunnels.h
index a81bc2341..4a3619ab6 100644
--- a/src/cadet/gnunet-service-cadet-new_tunnels.h
+++ b/src/cadet/gnunet-service-cadet_tunnels.h
@@ -20,7 +20,7 @@
20*/ 20*/
21 21
22/** 22/**
23 * @file cadet/gnunet-service-cadet-new_tunnels.h 23 * @file cadet/gnunet-service-cadet_tunnels.h
24 * @brief Information we track per tunnel. 24 * @brief Information we track per tunnel.
25 * @author Bartlomiej Polot 25 * @author Bartlomiej Polot
26 * @author Christian Grothoff 26 * @author Christian Grothoff
@@ -28,7 +28,7 @@
28#ifndef GNUNET_SERVICE_CADET_TUNNELS_H 28#ifndef GNUNET_SERVICE_CADET_TUNNELS_H
29#define GNUNET_SERVICE_CADET_TUNNELS_H 29#define GNUNET_SERVICE_CADET_TUNNELS_H
30 30
31#include "gnunet-service-cadet-new.h" 31#include "gnunet-service-cadet.h"
32#include "cadet_protocol.h" 32#include "cadet_protocol.h"
33 33
34 34
diff --git a/src/cadet/test_cadet.c b/src/cadet/test_cadet.c
index e57c01be2..8963d97c9 100644
--- a/src/cadet/test_cadet.c
+++ b/src/cadet/test_cadet.c
@@ -21,7 +21,7 @@
21 * @file cadet/test_cadet.c 21 * @file cadet/test_cadet.c
22 * @author Bart Polot 22 * @author Bart Polot
23 * @author Christian Grothoff 23 * @author Christian Grothoff
24 * @brief Test for the cadet service: retransmission of traffic. 24 * @brief Test for the cadet service using mq API.
25 */ 25 */
26#include <stdio.h> 26#include <stdio.h>
27#include "platform.h" 27#include "platform.h"
@@ -32,9 +32,20 @@
32 32
33 33
34/** 34/**
35 * How many messages to send 35 * Ugly workaround to unify data handlers on incoming and outgoing channels.
36 */ 36 */
37#define TOTAL_PACKETS 500 /* Cannot exceed 64k! */ 37struct CadetTestChannelWrapper
38{
39 /**
40 * Channel pointer.
41 */
42 struct GNUNET_CADET_Channel *ch;
43};
44
45/**
46 * How many messages to send by default.
47 */
48#define TOTAL_PACKETS 500 /* Cannot exceed 64k! */
38 49
39/** 50/**
40 * How long until we give up on connecting the peers? 51 * How long until we give up on connecting the peers?
@@ -42,7 +53,7 @@
42#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120) 53#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120)
43 54
44/** 55/**
45 * Time to wait for stuff that should be rather fast 56 * Time to wait by default for stuff that should be rather fast.
46 */ 57 */
47#define SHORT_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 20) 58#define SHORT_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 20)
48 59
@@ -73,6 +84,16 @@ static char *test_name;
73static int test_backwards = GNUNET_NO; 84static int test_backwards = GNUNET_NO;
74 85
75/** 86/**
87 * How many packets to send.
88 */
89static unsigned int total_packets;
90
91/**
92 * Time to wait for fast operations.
93 */
94static struct GNUNET_TIME_Relative short_time;
95
96/**
76 * How many events have happened 97 * How many events have happened
77 */ 98 */
78static int ok; 99static int ok;
@@ -83,9 +104,9 @@ static int ok;
83static int ok_goal; 104static int ok_goal;
84 105
85/** 106/**
86 * Size of each test packet 107 * Size of each test packet's payload
87 */ 108 */
88static size_t size_payload = sizeof (struct GNUNET_MessageHeader) + sizeof (uint32_t); 109static size_t size_payload = sizeof (uint32_t);
89 110
90/** 111/**
91 * Operation to get peer ids. 112 * Operation to get peer ids.
@@ -158,9 +179,9 @@ static struct GNUNET_SCHEDULER_Task *disconnect_task;
158static struct GNUNET_SCHEDULER_Task *test_task; 179static struct GNUNET_SCHEDULER_Task *test_task;
159 180
160/** 181/**
161 * Task runnining #data_task(). 182 * Task runnining #send_next_msg().
162 */ 183 */
163static struct GNUNET_SCHEDULER_Task *data_job; 184static struct GNUNET_SCHEDULER_Task *send_next_msg_task;
164 185
165/** 186/**
166 * Cadet handle for the root peer 187 * Cadet handle for the root peer
@@ -175,7 +196,7 @@ static struct GNUNET_CADET_Handle *h2;
175/** 196/**
176 * Channel handle for the root peer 197 * Channel handle for the root peer
177 */ 198 */
178static struct GNUNET_CADET_Channel *ch; 199static struct GNUNET_CADET_Channel *outgoing_ch;
179 200
180/** 201/**
181 * Channel handle for the dest peer 202 * Channel handle for the dest peer
@@ -183,17 +204,6 @@ static struct GNUNET_CADET_Channel *ch;
183static struct GNUNET_CADET_Channel *incoming_ch; 204static struct GNUNET_CADET_Channel *incoming_ch;
184 205
185/** 206/**
186 * Transmit handle for root data calls
187 */
188static struct GNUNET_CADET_TransmitHandle *th;
189
190/**
191 * Transmit handle for root data calls
192 */
193static struct GNUNET_CADET_TransmitHandle *incoming_th;
194
195
196/**
197 * Time we started the data transmission (after channel has been established 207 * Time we started the data transmission (after channel has been established
198 * and initilized). 208 * and initilized).
199 */ 209 */
@@ -225,20 +235,26 @@ static unsigned int ka_received;
225static unsigned int msg_dropped; 235static unsigned int msg_dropped;
226 236
227 237
238/******************************************************************************/
239
240
241/******************************************************************************/
242
243
228/** 244/**
229 * Get the client number considered as the "target" or "receiver", depending on 245 * Get the channel considered as the "target" or "receiver", depending on
230 * the test type and size. 246 * the test type and size.
231 * 247 *
232 * @return Peer # of the target client, either 0 (for backward tests) or 248 * @return Channel handle of the target client, either 0 (for backward tests)
233 * the last peer in the line (for other tests). 249 * or the last peer in the line (for other tests).
234 */ 250 */
235static unsigned int 251static struct GNUNET_CADET_Channel *
236get_expected_target () 252get_target_channel ()
237{ 253{
238 if (SPEED == test && GNUNET_YES == test_backwards) 254 if (SPEED == test && GNUNET_YES == test_backwards)
239 return 0; 255 return outgoing_ch;
240 else 256 else
241 return peers_requested - 1; 257 return incoming_ch;
242} 258}
243 259
244 260
@@ -251,18 +267,15 @@ show_end_data (void)
251 static struct GNUNET_TIME_Absolute end_time; 267 static struct GNUNET_TIME_Absolute end_time;
252 static struct GNUNET_TIME_Relative total_time; 268 static struct GNUNET_TIME_Relative total_time;
253 269
254 end_time = GNUNET_TIME_absolute_get(); 270 end_time = GNUNET_TIME_absolute_get ();
255 total_time = GNUNET_TIME_absolute_get_difference(start_time, end_time); 271 total_time = GNUNET_TIME_absolute_get_difference (start_time, end_time);
256 FPRINTF (stderr, "\nResults of test \"%s\"\n", test_name); 272 FPRINTF (stderr, "\nResults of test \"%s\"\n", test_name);
257 FPRINTF (stderr, "Test time %s\n", 273 FPRINTF (stderr, "Test time %s\n",
258 GNUNET_STRINGS_relative_time_to_string (total_time, 274 GNUNET_STRINGS_relative_time_to_string (total_time, GNUNET_YES));
259 GNUNET_YES)); 275 FPRINTF (stderr, "Test bandwidth: %f kb/s\n", 4 * total_packets * 1.0 / (total_time.rel_value_us / 1000)); // 4bytes * ms
260 FPRINTF (stderr, "Test bandwidth: %f kb/s\n", 276 FPRINTF (stderr, "Test throughput: %f packets/s\n\n", total_packets * 1000.0 / (total_time.rel_value_us / 1000)); // packets * ms
261 4 * TOTAL_PACKETS * 1.0 / (total_time.rel_value_us / 1000)); // 4bytes * ms
262 FPRINTF (stderr, "Test throughput: %f packets/s\n\n",
263 TOTAL_PACKETS * 1000.0 / (total_time.rel_value_us / 1000)); // packets * ms
264 GAUGER ("CADET", test_name, 277 GAUGER ("CADET", test_name,
265 TOTAL_PACKETS * 1000.0 / (total_time.rel_value_us / 1000), 278 total_packets * 1000.0 / (total_time.rel_value_us / 1000),
266 "packets/s"); 279 "packets/s");
267} 280}
268 281
@@ -281,29 +294,19 @@ disconnect_cadet_peers (void *cls)
281 294
282 disconnect_task = NULL; 295 disconnect_task = NULL;
283 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 296 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
284 "disconnecting cadet service of peers, called from line %ld\n", 297 "disconnecting cadet service of peers, called from line %ld\n",
285 line); 298 line);
286 for (i = 0; i < 2; i++) 299 for (i = 0; i < 2; i++)
287 { 300 {
288 GNUNET_TESTBED_operation_done (t_op[i]); 301 GNUNET_TESTBED_operation_done (t_op[i]);
289 } 302 }
290 if (NULL != ch) 303 if (NULL != outgoing_ch)
291 { 304 {
292 if (NULL != th) 305 GNUNET_CADET_channel_destroy (outgoing_ch);
293 { 306 outgoing_ch = NULL;
294 GNUNET_CADET_notify_transmit_ready_cancel (th);
295 th = NULL;
296 }
297 GNUNET_CADET_channel_destroy (ch);
298 ch = NULL;
299 } 307 }
300 if (NULL != incoming_ch) 308 if (NULL != incoming_ch)
301 { 309 {
302 if (NULL != incoming_th)
303 {
304 GNUNET_CADET_notify_transmit_ready_cancel (incoming_th);
305 incoming_th = NULL;
306 }
307 GNUNET_CADET_channel_destroy (incoming_ch); 310 GNUNET_CADET_channel_destroy (incoming_ch);
308 incoming_ch = NULL; 311 incoming_ch = NULL;
309 } 312 }
@@ -322,10 +325,10 @@ static void
322shutdown_task (void *cls) 325shutdown_task (void *cls)
323{ 326{
324 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ending test.\n"); 327 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ending test.\n");
325 if (NULL != data_job) 328 if (NULL != send_next_msg_task)
326 { 329 {
327 GNUNET_SCHEDULER_cancel (data_job); 330 GNUNET_SCHEDULER_cancel (send_next_msg_task);
328 data_job = NULL; 331 send_next_msg_task = NULL;
329 } 332 }
330 if (NULL != test_task) 333 if (NULL != test_task)
331 { 334 {
@@ -335,8 +338,8 @@ shutdown_task (void *cls)
335 if (NULL != disconnect_task) 338 if (NULL != disconnect_task)
336 { 339 {
337 GNUNET_SCHEDULER_cancel (disconnect_task); 340 GNUNET_SCHEDULER_cancel (disconnect_task);
338 disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, 341 disconnect_task =
339 (void *) __LINE__); 342 GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, (void *) __LINE__);
340 } 343 }
341} 344}
342 345
@@ -351,17 +354,11 @@ shutdown_task (void *cls)
351 * operation has executed successfully. 354 * operation has executed successfully.
352 */ 355 */
353static void 356static void
354stats_cont (void *cls, 357stats_cont (void *cls, struct GNUNET_TESTBED_Operation *op, const char *emsg)
355 struct GNUNET_TESTBED_Operation *op,
356 const char *emsg)
357{ 358{
358 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 359 GNUNET_log (GNUNET_ERROR_TYPE_INFO, " KA sent: %u, KA received: %u\n",
359 " KA sent: %u, KA received: %u\n", 360 ka_sent, ka_received);
360 ka_sent, 361 if ((KEEPALIVE == test) && ((ka_sent < 2) || (ka_sent > ka_received + 1)))
361 ka_received);
362 if ( (KEEPALIVE == test) &&
363 ( (ka_sent < 2) ||
364 (ka_sent > ka_received + 1)) )
365 { 362 {
366 GNUNET_break (0); 363 GNUNET_break (0);
367 ok--; 364 ok--;
@@ -370,8 +367,7 @@ stats_cont (void *cls,
370 367
371 if (NULL != disconnect_task) 368 if (NULL != disconnect_task)
372 GNUNET_SCHEDULER_cancel (disconnect_task); 369 GNUNET_SCHEDULER_cancel (disconnect_task);
373 disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, 370 disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, cls);
374 cls);
375} 371}
376 372
377 373
@@ -387,11 +383,8 @@ stats_cont (void *cls,
387 * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration 383 * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
388 */ 384 */
389static int 385static int
390stats_iterator (void *cls, 386stats_iterator (void *cls, const struct GNUNET_TESTBED_Peer *peer,
391 const struct GNUNET_TESTBED_Peer *peer, 387 const char *subsystem, const char *name, uint64_t value,
392 const char *subsystem,
393 const char *name,
394 uint64_t value,
395 int is_persistent) 388 int is_persistent)
396{ 389{
397 static const char *s_sent = "# keepalives sent"; 390 static const char *s_sent = "# keepalives sent";
@@ -401,19 +394,15 @@ stats_iterator (void *cls,
401 uint32_t i; 394 uint32_t i;
402 395
403 i = GNUNET_TESTBED_get_index (peer); 396 i = GNUNET_TESTBED_get_index (peer);
404 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 397 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "STATS PEER %u - %s [%s]: %llu\n", i,
405 "STATS PEER %u - %s [%s]: %llu\n", 398 subsystem, name, (unsigned long long) value);
406 i,
407 subsystem,
408 name,
409 (unsigned long long) value);
410 if (0 == strncmp (s_sent, name, strlen (s_sent)) && 0 == i) 399 if (0 == strncmp (s_sent, name, strlen (s_sent)) && 0 == i)
411 ka_sent = value; 400 ka_sent = value;
412 if (0 == strncmp(s_recv, name, strlen (s_recv)) && peers_requested - 1 == i) 401 if (0 == strncmp (s_recv, name, strlen (s_recv)) && peers_requested - 1 == i)
413 ka_received = value; 402 ka_received = value;
414 if (0 == strncmp(rdrops, name, strlen (rdrops))) 403 if (0 == strncmp (rdrops, name, strlen (rdrops)))
415 msg_dropped += value; 404 msg_dropped += value;
416 if (0 == strncmp(cdrops, name, strlen (cdrops))) 405 if (0 == strncmp (cdrops, name, strlen (cdrops)))
417 msg_dropped += value; 406 msg_dropped += value;
418 407
419 return GNUNET_OK; 408 return GNUNET_OK;
@@ -423,7 +412,7 @@ stats_iterator (void *cls,
423/** 412/**
424 * Task to gather all statistics. 413 * Task to gather all statistics.
425 * 414 *
426 * @param cls Closure (NULL). 415 * @param cls Closure (line from which the task was scheduled).
427 */ 416 */
428static void 417static void
429gather_stats_and_exit (void *cls) 418gather_stats_and_exit (void *cls)
@@ -432,21 +421,20 @@ gather_stats_and_exit (void *cls)
432 421
433 disconnect_task = NULL; 422 disconnect_task = NULL;
434 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 423 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
435 "gathering statistics from line %d\n", 424 "gathering statistics from line %ld\n",
436 (int) l); 425 l);
437 if (NULL != ch) 426 if (NULL != outgoing_ch)
438 { 427 {
439 if (NULL != th) 428 GNUNET_CADET_channel_destroy (outgoing_ch);
440 { 429 outgoing_ch = NULL;
441 GNUNET_CADET_notify_transmit_ready_cancel (th);
442 th = NULL;
443 }
444 GNUNET_CADET_channel_destroy (ch);
445 ch = NULL;
446 } 430 }
447 stats_op = GNUNET_TESTBED_get_statistics (peers_running, testbed_peers, 431 stats_op = GNUNET_TESTBED_get_statistics (peers_running,
448 "cadet", NULL, 432 testbed_peers,
449 &stats_iterator, stats_cont, cls); 433 "cadet",
434 NULL,
435 &stats_iterator,
436 stats_cont,
437 cls);
450} 438}
451 439
452 440
@@ -462,163 +450,151 @@ abort_test (long line)
462 if (NULL != disconnect_task) 450 if (NULL != disconnect_task)
463 { 451 {
464 GNUNET_SCHEDULER_cancel (disconnect_task); 452 GNUNET_SCHEDULER_cancel (disconnect_task);
465 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 453 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Aborting test from %ld\n", line);
466 "Aborting test from %ld\n", line); 454 disconnect_task =
467 disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, 455 GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, (void *) line);
468 (void *) line);
469 } 456 }
470} 457}
471 458
472/**
473 * Transmit ready callback.
474 *
475 * @param cls Closure (message type).
476 * @param size Size of the tranmist buffer.
477 * @param buf Pointer to the beginning of the buffer.
478 *
479 * @return Number of bytes written to buf.
480 */
481static size_t
482tmt_rdy (void *cls, size_t size, void *buf);
483
484 459
485/** 460/**
486 * Task to request a new data transmission. 461 * Send a message on the channel with the appropriate size and payload.
462 *
463 * Update the appropriate *_sent counter.
487 * 464 *
488 * @param cls Closure (peer #). 465 * @param channel Channel to send the message on.
489 */ 466 */
490static void 467static void
491data_task (void *cls) 468send_test_message (struct GNUNET_CADET_Channel *channel)
492{ 469{
493 struct GNUNET_CADET_Channel *channel; 470 struct GNUNET_MQ_Envelope *env;
494 static struct GNUNET_CADET_TransmitHandle **pth; 471 struct GNUNET_MessageHeader *msg;
495 long src; 472 uint32_t *data;
473 int payload;
474 int size;
496 475
497 data_job = NULL; 476 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
498 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Data task\n"); 477 "Sending test message on channel %p\n",
499 if (GNUNET_YES == test_backwards) 478 channel);
500 { 479 size = size_payload;
501 channel = incoming_ch; 480 if (GNUNET_NO == initialized)
502 pth = &incoming_th;
503 src = peers_requested - 1;
504 }
505 else
506 { 481 {
507 channel = ch; 482 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending INITIALIZER\n");
508 pth = &th; 483 size += 1000;
509 src = 0; 484 payload = data_sent;
485 if (SPEED_ACK == test) // FIXME unify SPEED_ACK with an initializer
486 data_sent++;
510 } 487 }
511 488 else if (SPEED == test || SPEED_ACK == test)
512 GNUNET_assert (NULL != channel);
513 GNUNET_assert (NULL == *pth);
514
515 *pth = GNUNET_CADET_notify_transmit_ready (channel, GNUNET_NO,
516 GNUNET_TIME_UNIT_FOREVER_REL,
517 size_payload + data_sent,
518 &tmt_rdy, (void *) src);
519 if (NULL == *pth)
520 { 489 {
521 unsigned long i = (unsigned long) cls; 490 if (get_target_channel() == channel)
522
523 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Retransmission\n");
524 if (0 == i)
525 { 491 {
526 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, " in 1 ms\n"); 492 payload = ack_sent;
527 data_job = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS, 493 size += ack_sent;
528 &data_task, (void *) 1L); 494 ack_sent++;
495 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
496 "Sending ACK %u [%d bytes]\n",
497 payload, size);
529 } 498 }
530 else 499 else
531 { 500 {
532 i++; 501 payload = data_sent;
533 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 502 size += data_sent;
534 "in %llu ms\n", 503 data_sent++;
535 (unsigned long long) i); 504 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
536 data_job = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 505 "Sending DATA %u [%d bytes]\n",
537 i), 506 data_sent, size);
538 &data_task, (void *) i);
539 } 507 }
540 } 508 }
541} 509 else if (FORWARD == test)
510 {
511 payload = ack_sent;
512 }
513 else if (P2P_SIGNAL == test)
514 {
515 payload = data_sent;
516 }
517 else
518 {
519 GNUNET_assert (0);
520 }
521 env = GNUNET_MQ_msg_extra (msg, size, GNUNET_MESSAGE_TYPE_DUMMY);
542 522
523 data = (uint32_t *) &msg[1];
524 *data = htonl (payload);
525 GNUNET_MQ_send (GNUNET_CADET_get_mq (channel), env);
526}
543 527
544/** 528/**
545 * Transmit ready callback 529 * Task to request a new data transmission in a SPEED test, without waiting
530 * for previous messages to be sent/arrrive.
546 * 531 *
547 * @param cls Closure (peer # which is sending the data). 532 * @param cls Closure (unused).
548 * @param size Size of the buffer we have.
549 * @param buf Buffer to copy data to.
550 */ 533 */
551static size_t 534static void
552tmt_rdy (void *cls, size_t size, void *buf) 535send_next_msg (void *cls)
553{ 536{
554 struct GNUNET_MessageHeader *msg = buf; 537 struct GNUNET_CADET_Channel *channel;
555 size_t msg_size;
556 uint32_t *data;
557 long id = (long) cls;
558 unsigned int counter;
559 538
560 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 539 send_next_msg_task = NULL;
561 "tmt_rdy on %ld, filling buffer\n", 540 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending next message: %d\n", data_sent);
562 id); 541
563 if (0 == id) 542 channel = GNUNET_YES == test_backwards ? incoming_ch : outgoing_ch;
564 th = NULL; 543 GNUNET_assert (NULL != channel);
565 else if ((peers_requested - 1) == id) 544 GNUNET_assert (SPEED == test);
566 incoming_th = NULL; 545 send_test_message (channel);
567 else 546 if (data_sent < total_packets)
568 GNUNET_assert (0);
569 counter = get_expected_target () == id ? ack_sent : data_sent;
570 msg_size = size_payload + counter;
571 GNUNET_assert (msg_size > sizeof (struct GNUNET_MessageHeader));
572 if ( (size < msg_size) ||
573 (NULL == buf) )
574 {
575 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
576 "size %u, buf %p, data_sent %u, ack_received %u\n",
577 (unsigned int) size,
578 buf,
579 data_sent,
580 ack_received);
581 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ok %u, ok goal %u\n", ok, ok_goal);
582 GNUNET_break (ok >= ok_goal - 2);
583
584 return 0;
585 }
586 msg->size = htons (msg_size);
587 msg->type = htons (GNUNET_MESSAGE_TYPE_DUMMY);
588 data = (uint32_t *) &msg[1];
589 *data = htonl (counter);
590 if (GNUNET_NO == initialized)
591 { 547 {
548 /* SPEED test: Send all messages as soon as possible */
592 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 549 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
593 "sending initializer\n"); 550 "Scheduling message %d\n",
594 msg_size = size_payload + 1000; 551 data_sent + 1);
595 msg->size = htons (msg_size); 552 send_next_msg_task =
596 if (SPEED_ACK == test) 553 GNUNET_SCHEDULER_add_delayed(GNUNET_TIME_UNIT_SECONDS,
597 data_sent++; 554 &send_next_msg,
555 NULL);
598 } 556 }
599 else if ( (SPEED == test) || 557}
600 (SPEED_ACK == test) ) 558
559
560/**
561 * Every few messages cancel the timeout task and re-schedule it again, to
562 * avoid timing out when traffic keeps coming.
563 *
564 * @param line Code line number to log if a timeout occurs.
565 */
566static void
567reschedule_timeout_task (long line)
568{
569 if ((ok % 10) == 0)
601 { 570 {
602 if (get_expected_target() == id) 571 if (NULL != disconnect_task)
603 ack_sent++;
604 else
605 data_sent++;
606 counter++;
607 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
608 " Sent message %u size %u\n",
609 counter,
610 (unsigned int) msg_size);
611 if ( (data_sent < TOTAL_PACKETS) &&
612 (SPEED == test) )
613 { 572 {
614 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 573 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
615 " Scheduling message %d\n", 574 " reschedule timeout every 10 messages\n");
616 counter + 1); 575 GNUNET_SCHEDULER_cancel (disconnect_task);
617 data_job = GNUNET_SCHEDULER_add_now (&data_task, NULL); 576 disconnect_task = GNUNET_SCHEDULER_add_delayed (short_time,
577 &gather_stats_and_exit,
578 (void *) line);
618 } 579 }
619 } 580 }
581}
582
620 583
621 return msg_size; 584/**
585 * Check if payload is sane (size contains payload).
586 *
587 * @param cls should match #ch
588 * @param message The actual message.
589 * @return #GNUNET_OK to keep the channel open,
590 * #GNUNET_SYSERR to close it (signal serious error).
591 */
592static int
593check_data (void *cls, const struct GNUNET_MessageHeader *message)
594{
595 if (sizeof (struct GNUNET_MessageHeader) >= ntohs (message->size))
596 return GNUNET_SYSERR;
597 return GNUNET_OK; /* all is well-formed */
622} 598}
623 599
624 600
@@ -626,75 +602,50 @@ tmt_rdy (void *cls, size_t size, void *buf)
626 * Function is called whenever a message is received. 602 * Function is called whenever a message is received.
627 * 603 *
628 * @param cls closure (set from GNUNET_CADET_connect(), peer number) 604 * @param cls closure (set from GNUNET_CADET_connect(), peer number)
629 * @param channel connection to the other end
630 * @param channel_ctx place to store local state associated with the channel
631 * @param message the actual message 605 * @param message the actual message
632 * @return #GNUNET_OK to keep the connection open,
633 * #GNUNET_SYSERR to close it (signal serious error)
634 */ 606 */
635static int 607static void
636data_callback (void *cls, 608handle_data (void *cls, const struct GNUNET_MessageHeader *message)
637 struct GNUNET_CADET_Channel *channel,
638 void **channel_ctx,
639 const struct GNUNET_MessageHeader *message)
640{ 609{
641 struct GNUNET_CADET_TransmitHandle **pth; 610 struct CadetTestChannelWrapper *ch = cls;
642 long client = (long) cls; 611 struct GNUNET_CADET_Channel *channel = ch->ch;
643 long expected_target_client;
644 uint32_t *data; 612 uint32_t *data;
645 uint32_t payload; 613 uint32_t payload;
646 unsigned int counter; 614 int *counter;
647 615
648 ok++; 616 ok++;
649 counter = get_expected_target () == client ? data_received : ack_received;
650
651 GNUNET_CADET_receive_done (channel); 617 GNUNET_CADET_receive_done (channel);
618 counter = get_target_channel () == channel ? &data_received : &ack_received;
652 619
653 if ((ok % 10) == 0) 620 reschedule_timeout_task ((long) __LINE__);
621
622 if (channel == outgoing_ch)
654 { 623 {
655 if (NULL != disconnect_task) 624 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Root client got a message.\n");
656 {
657 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
658 " reschedule timeout\n");
659 GNUNET_SCHEDULER_cancel (disconnect_task);
660 disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME,
661 &gather_stats_and_exit,
662 (void *) __LINE__);
663 }
664 } 625 }
665 626 else if (channel == incoming_ch)
666 switch (client)
667 { 627 {
668 case 0L: 628 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Leaf client got a message.\n");
669 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Root client got a message!\n"); 629 }
670 GNUNET_assert (channel == ch); 630 else
671 pth = &th; 631 {
672 break; 632 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unknown channel %p.\n", channel);
673 case 1L:
674 case 4L:
675 GNUNET_assert (client == peers_requested - 1);
676 GNUNET_assert (channel == incoming_ch);
677 pth = &incoming_th;
678 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Leaf client %ld got a message.\n",
679 client);
680 break;
681 default:
682 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Client %ld not valid.\n", client);
683 GNUNET_assert (0); 633 GNUNET_assert (0);
684 } 634 }
635
685 GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: (%d/%d)\n", ok, ok_goal); 636 GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: (%d/%d)\n", ok, ok_goal);
686 data = (uint32_t *) &message[1]; 637 data = (uint32_t *) &message[1];
687 payload = ntohl (*data); 638 payload = ntohl (*data);
688 if (payload == counter) 639 if (payload == *counter)
689 { 640 {
690 GNUNET_log (GNUNET_ERROR_TYPE_INFO, " payload as expected: %u\n", payload); 641 GNUNET_log (GNUNET_ERROR_TYPE_INFO, " payload as expected: %u\n", payload);
691 } 642 }
692 else 643 else
693 { 644 {
694 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, " payload %u, expected: %u\n", 645 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
695 payload, counter); 646 " payload %u, expected: %u\n",
647 payload, *counter);
696 } 648 }
697 expected_target_client = get_expected_target ();
698 649
699 if (GNUNET_NO == initialized) 650 if (GNUNET_NO == initialized)
700 { 651 {
@@ -702,189 +653,152 @@ data_callback (void *cls,
702 start_time = GNUNET_TIME_absolute_get (); 653 start_time = GNUNET_TIME_absolute_get ();
703 if (SPEED == test) 654 if (SPEED == test)
704 { 655 {
705 GNUNET_assert (peers_requested - 1 == client); 656 GNUNET_assert (incoming_ch == channel);
706 data_job = GNUNET_SCHEDULER_add_now (&data_task, NULL); 657 send_next_msg_task = GNUNET_SCHEDULER_add_now (&send_next_msg, NULL);
707 return GNUNET_OK; 658 return;
708 } 659 }
709 } 660 }
710 661
711 counter++; 662 (*counter)++;
712 if (client == expected_target_client) /* Normally 4 */ 663 if (get_target_channel () == channel) /* Got "data" */
713 { 664 {
714 data_received++;
715 GNUNET_log (GNUNET_ERROR_TYPE_INFO, " received data %u\n", data_received); 665 GNUNET_log (GNUNET_ERROR_TYPE_INFO, " received data %u\n", data_received);
716 if (SPEED != test || (ok_goal - 2) == ok) 666 if (SPEED != test || (ok_goal - 2) == ok)
717 { 667 {
718 /* Send ACK */ 668 /* Send ACK */
719 GNUNET_assert (NULL == *pth); 669 send_test_message (channel);
720 *pth = GNUNET_CADET_notify_transmit_ready (channel, GNUNET_NO, 670 return;
721 GNUNET_TIME_UNIT_FOREVER_REL,
722 size_payload + ack_sent,
723 &tmt_rdy, (void *) client);
724 return GNUNET_OK;
725 } 671 }
726 else 672 else
727 { 673 {
728 if (data_received < TOTAL_PACKETS) 674 if (data_received < total_packets)
729 return GNUNET_OK; 675 return;
730 } 676 }
731 } 677 }
732 else /* Normally 0 */ 678 else /* Got "ack" */
733 { 679 {
734 if (SPEED_ACK == test || SPEED == test) 680 if (SPEED_ACK == test || SPEED == test)
735 { 681 {
736 ack_received++;
737 GNUNET_log (GNUNET_ERROR_TYPE_INFO, " received ack %u\n", ack_received); 682 GNUNET_log (GNUNET_ERROR_TYPE_INFO, " received ack %u\n", ack_received);
738 /* send more data */ 683 /* Send more data */
739 GNUNET_assert (NULL == *pth); 684 send_test_message (channel);
740 *pth = GNUNET_CADET_notify_transmit_ready (channel, GNUNET_NO, 685 if (ack_received < total_packets && SPEED != test)
741 GNUNET_TIME_UNIT_FOREVER_REL, 686 return;
742 size_payload + data_sent,
743 &tmt_rdy, (void *) client);
744 if (ack_received < TOTAL_PACKETS && SPEED != test)
745 return GNUNET_OK;
746 if (ok == 2 && SPEED == test) 687 if (ok == 2 && SPEED == test)
747 return GNUNET_OK; 688 return;
748 show_end_data(); 689 show_end_data ();
749 } 690 }
750 if (test == P2P_SIGNAL) 691 if (test == P2P_SIGNAL)
751 { 692 {
752 if (NULL != incoming_th)
753 {
754 GNUNET_CADET_notify_transmit_ready_cancel (incoming_th);
755 incoming_th = NULL;
756 }
757 GNUNET_CADET_channel_destroy (incoming_ch); 693 GNUNET_CADET_channel_destroy (incoming_ch);
758 incoming_ch = NULL; 694 incoming_ch = NULL;
759 } 695 }
760 else 696 else
761 { 697 {
762 if (NULL != th) 698 GNUNET_CADET_channel_destroy (outgoing_ch);
763 { 699 outgoing_ch = NULL;
764 GNUNET_CADET_notify_transmit_ready_cancel (th);
765 th = NULL;
766 }
767 GNUNET_CADET_channel_destroy (ch);
768 ch = NULL;
769 } 700 }
770 } 701 }
771
772 return GNUNET_OK;
773} 702}
774 703
775 704
776/** 705/**
777 * Data handlers for every message type of CADET's payload. 706 * Method called whenever a peer connects to a port in MQ-based CADET.
778 * {callback_function, message_type, size_expected}
779 */
780static struct GNUNET_CADET_MessageHandler handlers[] = {
781 {&data_callback,
782 GNUNET_MESSAGE_TYPE_DUMMY,
783 sizeof (struct GNUNET_MessageHeader)},
784 {NULL, 0, 0}
785};
786
787
788/**
789 * Method called whenever another peer has added us to a channel
790 * the other peer initiated.
791 * 707 *
792 * @param cls Closure. 708 * @param cls Closure from #GNUNET_CADET_open_port (peer # as long).
793 * @param channel New handle to the channel. 709 * @param channel New handle to the channel.
794 * @param initiator Peer that started the channel. 710 * @param source Peer that started this channel.
795 * @param port Port this channel is connected to. 711 * @return Closure for the incoming @a channel. It's given to:
796 * @param options channel option flags 712 * - The #GNUNET_CADET_DisconnectEventHandler (given to
797 * @return Initial channel context for the channel 713 * #GNUNET_CADET_open_port) when the channel dies.
798 * (can be NULL -- that's not an error). 714 * - Each the #GNUNET_MQ_MessageCallback handlers for each message
715 * received on the @a channel.
799 */ 716 */
800static void * 717static void *
801incoming_channel (void *cls, 718connect_handler (void *cls, struct GNUNET_CADET_Channel *channel,
802 struct GNUNET_CADET_Channel *channel, 719 const struct GNUNET_PeerIdentity *source)
803 const struct GNUNET_PeerIdentity *initiator,
804 const struct GNUNET_HashCode *port,
805 enum GNUNET_CADET_ChannelOption options)
806{ 720{
721 struct CadetTestChannelWrapper *ch;
722 long peer = (long) cls;
723
807 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 724 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
808 "Incoming channel from %s to peer %d:%s\n", 725 "Incoming channel from %s to %ld: %p\n",
809 GNUNET_i2s (initiator), 726 GNUNET_i2s (source), peer, channel);
810 (int) (long) cls, GNUNET_h2s (port));
811 ok++; 727 ok++;
812 GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok); 728 GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok);
813 if ((long) cls == peers_requested - 1) 729 if (peer == peers_requested - 1)
814 { 730 {
815 if (NULL != incoming_ch) 731 if (NULL != incoming_ch)
816 { 732 {
817 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 733 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
818 "Duplicate incoming channel for client %lu\n", 734 "Duplicate incoming channel for client %lu\n", (long) cls);
819 (long) cls); 735 GNUNET_assert (0);
820 GNUNET_break(0);
821 } 736 }
822 incoming_ch = channel; 737 incoming_ch = channel;
823 } 738 }
824 else 739 else
825 { 740 {
826 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 741 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
827 "Incoming channel for unexpected peer #%lu\n", 742 "Incoming channel for unexpected peer #%lu\n", (long) cls);
828 (long) cls); 743 GNUNET_assert (0);
829 GNUNET_break (0);
830 } 744 }
831 if (NULL != disconnect_task) 745 if (NULL != disconnect_task)
832 { 746 {
833 GNUNET_SCHEDULER_cancel (disconnect_task); 747 GNUNET_SCHEDULER_cancel (disconnect_task);
834 disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME, 748 disconnect_task = GNUNET_SCHEDULER_add_delayed (short_time,
835 &gather_stats_and_exit, 749 &gather_stats_and_exit,
836 (void *) __LINE__); 750 (void *) __LINE__);
837 } 751 }
838 752
839 return NULL; 753 /* TODO: cannot return channel as-is, in order to unify the data handlers */
754 ch = GNUNET_new (struct CadetTestChannelWrapper);
755 ch->ch = channel;
756
757 return ch;
840} 758}
841 759
842 760
843/** 761/**
844 * Function called whenever an inbound channel is destroyed. Should clean up 762 * Function called whenever an MQ-channel is destroyed, even if the destruction
845 * any associated state. 763 * was requested by #GNUNET_CADET_channel_destroy.
764 * It must NOT call #GNUNET_CADET_channel_destroy on the channel.
765 *
766 * It should clean up any associated state, including cancelling any pending
767 * transmission on this channel.
846 * 768 *
847 * @param cls closure (set from GNUNET_CADET_connect, peer number) 769 * @param cls Channel closure (channel wrapper).
848 * @param channel connection to the other end (henceforth invalid) 770 * @param channel Connection to the other end (henceforth invalid).
849 * @param channel_ctx place where local state associated
850 * with the channel is stored
851 */ 771 */
852static void 772static void
853channel_cleaner (void *cls, 773disconnect_handler (void *cls, const struct GNUNET_CADET_Channel *channel)
854 const struct GNUNET_CADET_Channel *channel,
855 void *channel_ctx)
856{ 774{
857 long i = (long) cls; 775 struct CadetTestChannelWrapper *ch_w = cls;
858 776
859 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 777 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Channel disconnected\n");
860 "Incoming channel disconnected at peer %ld\n", 778 GNUNET_assert (ch_w->ch == channel);
861 i); 779 if (channel == incoming_ch)
862 if (peers_running - 1 == i)
863 { 780 {
864 ok++; 781 ok++;
865 GNUNET_break (channel == incoming_ch);
866 incoming_ch = NULL; 782 incoming_ch = NULL;
867 } 783 }
868 else if (0L == i) 784 else if (outgoing_ch == channel
785 )
869 { 786 {
870 if (P2P_SIGNAL == test) 787 if (P2P_SIGNAL == test)
871 { 788 {
872 ok++; 789 ok++;
873 } 790 }
874 GNUNET_break (channel == ch); 791 outgoing_ch = NULL;
875 ch = NULL;
876 } 792 }
877 else 793 else
878 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 794 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Unknown channel! %p\n", channel);
879 "Unknown peer! %d\n",
880 (int) i);
881 GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok); 795 GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok);
882 796
883 if (NULL != disconnect_task) 797 if (NULL != disconnect_task)
884 { 798 {
885 GNUNET_SCHEDULER_cancel (disconnect_task); 799 GNUNET_SCHEDULER_cancel (disconnect_task);
886 disconnect_task = GNUNET_SCHEDULER_add_now (&gather_stats_and_exit, 800 disconnect_task =
887 (void *) __LINE__); 801 GNUNET_SCHEDULER_add_now (&gather_stats_and_exit, (void *) __LINE__);
888 } 802 }
889} 803}
890 804
@@ -898,13 +812,20 @@ channel_cleaner (void *cls,
898 * @param cls Closure (unused). 812 * @param cls Closure (unused).
899 */ 813 */
900static void 814static void
901do_test (void *cls) 815start_test (void *cls)
902{ 816{
817 struct GNUNET_MQ_MessageHandler handlers[] = {
818 GNUNET_MQ_hd_var_size (data,
819 GNUNET_MESSAGE_TYPE_DUMMY,
820 struct GNUNET_MessageHeader,
821 NULL),
822 GNUNET_MQ_handler_end ()
823 };
824 struct CadetTestChannelWrapper *ch;
903 enum GNUNET_CADET_ChannelOption flags; 825 enum GNUNET_CADET_ChannelOption flags;
904 826
905 test_task = NULL; 827 test_task = NULL;
906 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 828 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "start_test\n");
907 "do_test\n");
908 if (NULL != disconnect_task) 829 if (NULL != disconnect_task)
909 { 830 {
910 GNUNET_SCHEDULER_cancel (disconnect_task); 831 GNUNET_SCHEDULER_cancel (disconnect_task);
@@ -918,30 +839,33 @@ do_test (void *cls)
918 flags |= GNUNET_CADET_OPTION_RELIABLE; 839 flags |= GNUNET_CADET_OPTION_RELIABLE;
919 } 840 }
920 841
921 ch = GNUNET_CADET_channel_create (h1, 842 ch = GNUNET_new (struct CadetTestChannelWrapper);
922 NULL, 843 outgoing_ch = GNUNET_CADET_channel_create (h1,
923 p_id[1], 844 ch,
924 &port, 845 p_id[1],
925 flags); 846 &port,
847 flags,
848 NULL,
849 &disconnect_handler,
850 handlers);
851
852 ch->ch = outgoing_ch;
926 853
927 disconnect_task 854 disconnect_task = GNUNET_SCHEDULER_add_delayed (short_time,
928 = GNUNET_SCHEDULER_add_delayed (SHORT_TIME, 855 &gather_stats_and_exit,
929 &gather_stats_and_exit, 856 (void *) __LINE__);
930 (void *) __LINE__);
931 if (KEEPALIVE == test) 857 if (KEEPALIVE == test)
932 return; /* Don't send any data. */ 858 return; /* Don't send any data. */
859
933 860
934 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
935 "Sending data initializer...\n");
936 data_received = 0; 861 data_received = 0;
937 data_sent = 0; 862 data_sent = 0;
938 ack_received = 0; 863 ack_received = 0;
939 ack_sent = 0; 864 ack_sent = 0;
940 th = GNUNET_CADET_notify_transmit_ready (ch, 865 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
941 GNUNET_NO, 866 "Sending data initializer on channel %p...\n",
942 GNUNET_TIME_UNIT_FOREVER_REL, 867 outgoing_ch);
943 size_payload + 1000, 868 send_test_message (outgoing_ch);
944 &tmt_rdy, (void *) 0L);
945} 869}
946 870
947 871
@@ -955,35 +879,26 @@ do_test (void *cls)
955 * NULL if the operation is successfull 879 * NULL if the operation is successfull
956 */ 880 */
957static void 881static void
958pi_cb (void *cls, 882pi_cb (void *cls, struct GNUNET_TESTBED_Operation *op,
959 struct GNUNET_TESTBED_Operation *op, 883 const struct GNUNET_TESTBED_PeerInformation *pinfo, const char *emsg)
960 const struct GNUNET_TESTBED_PeerInformation *pinfo,
961 const char *emsg)
962{ 884{
963 long i = (long) cls; 885 long i = (long) cls;
964 886
965 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 887 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ID callback for %ld\n", i);
966 "id callback for %ld\n", i);
967 888
968 if ( (NULL == pinfo) || 889 if ((NULL == pinfo) || (NULL != emsg))
969 (NULL != emsg) )
970 { 890 {
971 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 891 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "pi_cb: %s\n", emsg);
972 "pi_cb: %s\n", emsg);
973 abort_test (__LINE__); 892 abort_test (__LINE__);
974 return; 893 return;
975 } 894 }
976 p_id[i] = pinfo->result.id; 895 p_id[i] = pinfo->result.id;
977 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 896 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " id: %s\n", GNUNET_i2s (p_id[i]));
978 " id: %s\n", GNUNET_i2s (p_id[i]));
979 p_ids++; 897 p_ids++;
980 if (p_ids < 2) 898 if (p_ids < 2)
981 return; 899 return;
982 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 900 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got all IDs, starting test\n");
983 "Got all IDs, starting test\n"); 901 test_task = GNUNET_SCHEDULER_add_now (&start_test, NULL);
984 test_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
985 &do_test,
986 NULL);
987} 902}
988 903
989 904
@@ -994,7 +909,7 @@ pi_cb (void *cls,
994 * @param ctx Argument to give to GNUNET_CADET_TEST_cleanup on test end. 909 * @param ctx Argument to give to GNUNET_CADET_TEST_cleanup on test end.
995 * @param num_peers Number of peers that are running. 910 * @param num_peers Number of peers that are running.
996 * @param peers Array of peers. 911 * @param peers Array of peers.
997 * @param cadetes Handle to each of the CADETs of the peers. 912 * @param cadets Handle to each of the CADETs of the peers.
998 */ 913 */
999static void 914static void
1000tmain (void *cls, 915tmain (void *cls,
@@ -1011,16 +926,18 @@ tmain (void *cls,
1011 testbed_peers = peers; 926 testbed_peers = peers;
1012 h1 = cadets[0]; 927 h1 = cadets[0];
1013 h2 = cadets[num_peers - 1]; 928 h2 = cadets[num_peers - 1];
1014 disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME, 929 disconnect_task = GNUNET_SCHEDULER_add_delayed (short_time,
1015 &disconnect_cadet_peers, 930 &disconnect_cadet_peers,
1016 (void *) __LINE__); 931 (void *) __LINE__);
1017 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); 932 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
1018 t_op[0] = GNUNET_TESTBED_peer_get_information (peers[0], 933 t_op[0] = GNUNET_TESTBED_peer_get_information (peers[0],
1019 GNUNET_TESTBED_PIT_IDENTITY, 934 GNUNET_TESTBED_PIT_IDENTITY,
1020 &pi_cb, (void *) 0L); 935 &pi_cb,
936 (void *) 0L);
1021 t_op[1] = GNUNET_TESTBED_peer_get_information (peers[num_peers - 1], 937 t_op[1] = GNUNET_TESTBED_peer_get_information (peers[num_peers - 1],
1022 GNUNET_TESTBED_PIT_IDENTITY, 938 GNUNET_TESTBED_PIT_IDENTITY,
1023 &pi_cb, (void *) 1L); 939 &pi_cb,
940 (void *) 1L);
1024 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "requested peer ids\n"); 941 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "requested peer ids\n");
1025} 942}
1026 943
@@ -1031,16 +948,46 @@ tmain (void *cls,
1031int 948int
1032main (int argc, char *argv[]) 949main (int argc, char *argv[])
1033{ 950{
1034 initialized = GNUNET_NO;
1035 static const struct GNUNET_HashCode *ports[2]; 951 static const struct GNUNET_HashCode *ports[2];
952 struct GNUNET_MQ_MessageHandler handlers[] = {
953 GNUNET_MQ_hd_var_size (data,
954 GNUNET_MESSAGE_TYPE_DUMMY,
955 struct GNUNET_MessageHeader,
956 NULL),
957 GNUNET_MQ_handler_end ()
958 };
1036 const char *config_file; 959 const char *config_file;
1037 char port_id[] = "test port"; 960 char port_id[] = "test port";
1038 GNUNET_CRYPTO_hash (port_id, sizeof (port_id), &port); 961 struct GNUNET_GETOPT_CommandLineOption options[] = {
962 GNUNET_GETOPT_OPTION_SET_RELATIVE_TIME ('t',
963 "time",
964 "short_time",
965 gettext_noop ("set short timeout"),
966 &short_time),
967
968 GNUNET_GETOPT_OPTION_SET_UINT ('m',
969 "messages",
970 "NUM_MESSAGES",
971 gettext_noop ("set number of messages to send"),
972 &total_packets),
973
974 GNUNET_GETOPT_OPTION_END
975 };
1039 976
977
978 initialized = GNUNET_NO;
1040 GNUNET_log_setup ("test", "DEBUG", NULL); 979 GNUNET_log_setup ("test", "DEBUG", NULL);
1041 config_file = "test_cadet.conf";
1042 980
1043 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Start\n"); 981 total_packets = TOTAL_PACKETS;
982 short_time = SHORT_TIME;
983 if (-1 == GNUNET_GETOPT_run (argv[0], options, argc, argv))
984 {
985 FPRINTF (stderr, "test failed: problem with CLI parameters\n");
986 exit (1);
987 }
988
989 config_file = "test_cadet.conf";
990 GNUNET_CRYPTO_hash (port_id, sizeof (port_id), &port);
1044 991
1045 /* Find out requested size */ 992 /* Find out requested size */
1046 if (strstr (argv[0], "_2_") != NULL) 993 if (strstr (argv[0], "_2_") != NULL)
@@ -1078,11 +1025,11 @@ main (int argc, char *argv[])
1078 { 1025 {
1079 /* Test is supposed to generate the following callbacks: 1026 /* Test is supposed to generate the following callbacks:
1080 * 1 incoming channel (@dest) 1027 * 1 incoming channel (@dest)
1081 * TOTAL_PACKETS received data packet (@dest) 1028 * total_packets received data packet (@dest)
1082 * TOTAL_PACKETS received data packet (@orig) 1029 * total_packets received data packet (@orig)
1083 * 1 received channel destroy (@dest) 1030 * 1 received channel destroy (@dest)
1084 */ 1031 */
1085 ok_goal = TOTAL_PACKETS * 2 + 2; 1032 ok_goal = total_packets * 2 + 2;
1086 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SPEED_ACK\n"); 1033 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SPEED_ACK\n");
1087 test = SPEED_ACK; 1034 test = SPEED_ACK;
1088 test_name = "speed ack"; 1035 test_name = "speed ack";
@@ -1092,11 +1039,11 @@ main (int argc, char *argv[])
1092 /* Test is supposed to generate the following callbacks: 1039 /* Test is supposed to generate the following callbacks:
1093 * 1 incoming channel (@dest) 1040 * 1 incoming channel (@dest)
1094 * 1 initial packet (@dest) 1041 * 1 initial packet (@dest)
1095 * TOTAL_PACKETS received data packet (@dest) 1042 * total_packets received data packet (@dest)
1096 * 1 received data packet (@orig) 1043 * 1 received data packet (@orig)
1097 * 1 received channel destroy (@dest) 1044 * 1 received channel destroy (@dest)
1098 */ 1045 */
1099 ok_goal = TOTAL_PACKETS + 4; 1046 ok_goal = total_packets + 4;
1100 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SPEED\n"); 1047 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SPEED\n");
1101 if (strstr (argv[0], "_reliable") != NULL) 1048 if (strstr (argv[0], "_reliable") != NULL)
1102 { 1049 {
@@ -1137,22 +1084,22 @@ main (int argc, char *argv[])
1137 p_ids = 0; 1084 p_ids = 0;
1138 ports[0] = &port; 1085 ports[0] = &port;
1139 ports[1] = NULL; 1086 ports[1] = NULL;
1140 GNUNET_CADET_TEST_run ("test_cadet_small", 1087 GNUNET_CADET_TEST_ruN ("test_cadet_small",
1141 config_file, 1088 config_file,
1142 peers_requested, 1089 peers_requested,
1143 &tmain, 1090 &tmain,
1144 NULL, /* tmain cls */ 1091 NULL, /* tmain cls */
1145 &incoming_channel, 1092 &connect_handler,
1146 &channel_cleaner, 1093 NULL,
1147 handlers, 1094 &disconnect_handler,
1148 ports); 1095 handlers,
1096 ports);
1149 if (NULL != strstr (argv[0], "_reliable")) 1097 if (NULL != strstr (argv[0], "_reliable"))
1150 msg_dropped = 0; /* dropped should be retransmitted */ 1098 msg_dropped = 0; /* dropped should be retransmitted */
1151 1099
1152 if (ok_goal > ok - msg_dropped) 1100 if (ok_goal > ok - msg_dropped)
1153 { 1101 {
1154 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1102 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "FAILED! (%d/%d)\n", ok, ok_goal);
1155 "FAILED! (%d/%d)\n", ok, ok_goal);
1156 return 1; 1103 return 1;
1157 } 1104 }
1158 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "success\n"); 1105 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "success\n");
diff --git a/src/cadet/test_cadet_local.c b/src/cadet/test_cadet_local.c
deleted file mode 100644
index 2b915ab81..000000000
--- a/src/cadet/test_cadet_local.c
+++ /dev/null
@@ -1,351 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21/**
22 * @file cadet/test_cadet_local.c
23 * @brief test cadet local: test of cadet channels with just one peer
24 * @author Bartlomiej Polot
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_dht_service.h"
30#include "gnunet_testing_lib.h"
31#include "gnunet_cadet_service.h"
32
33struct GNUNET_TESTING_Peer *me;
34
35static struct GNUNET_CADET_Handle *cadet_peer_1;
36
37static struct GNUNET_CADET_Handle *cadet_peer_2;
38
39static struct GNUNET_CADET_Channel *ch;
40
41static int result = GNUNET_OK;
42
43static int got_data = GNUNET_NO;
44
45static struct GNUNET_SCHEDULER_Task *abort_task;
46
47static struct GNUNET_SCHEDULER_Task *connect_task;
48
49static struct GNUNET_CADET_TransmitHandle *mth;
50
51
52/**
53 * Connect to other client and send data
54 *
55 * @param cls Closue (unused).
56 */
57static void
58do_connect (void *cls);
59
60
61/**
62 * Shutdown nicely
63 */
64static void
65do_shutdown (void *cls)
66{
67 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
68 "shutdown\n");
69 if (NULL != abort_task)
70 {
71 GNUNET_SCHEDULER_cancel (abort_task);
72 abort_task = NULL;
73 }
74 if (NULL != ch)
75 {
76 GNUNET_CADET_channel_destroy (ch);
77 ch = NULL;
78 }
79 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
80 "Disconnect client 1\n");
81 if (NULL != cadet_peer_1)
82 {
83 GNUNET_CADET_disconnect (cadet_peer_1);
84 cadet_peer_1 = NULL;
85 }
86 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
87 "Disconnect client 2\n");
88 if (NULL != cadet_peer_2)
89 {
90 GNUNET_CADET_disconnect (cadet_peer_2);
91 cadet_peer_2 = NULL;
92 }
93 if (NULL != connect_task)
94 {
95 GNUNET_SCHEDULER_cancel (connect_task);
96 connect_task = NULL;
97 }
98}
99
100
101/**
102 * Something went wrong and timed out. Kill everything and set error flag
103 */
104static void
105do_abort (void *cls)
106{
107 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ABORT\n");
108 result = GNUNET_SYSERR;
109 abort_task = NULL;
110 GNUNET_SCHEDULER_shutdown ();
111}
112
113
114/**
115 * Function is called whenever a message is received.
116 *
117 * @param cls closure (set from GNUNET_CADET_connect)
118 * @param channel connection to the other end
119 * @param channel_ctx place to store local state associated with the channel
120 * @param message the actual message
121 * @return #GNUNET_OK to keep the connection open,
122 * #GNUNET_SYSERR to close it (signal serious error)
123 */
124static int
125data_callback (void *cls,
126 struct GNUNET_CADET_Channel *channel,
127 void **channel_ctx,
128 const struct GNUNET_MessageHeader *message)
129{
130 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
131 "Data callback! Shutting down.\n");
132 got_data = GNUNET_YES;
133 GNUNET_SCHEDULER_shutdown ();
134 GNUNET_CADET_receive_done (channel);
135 return GNUNET_OK;
136}
137
138
139/**
140 * Method called whenever another peer has added us to a channel
141 * the other peer initiated.
142 *
143 * @param cls closure
144 * @param channel new handle to the channel
145 * @param initiator peer that started the channel
146 * @param port port number
147 * @param options channel options
148 * @return initial channel context for the channel
149 * (can be NULL -- that's not an error)
150 */
151static void *
152inbound_channel (void *cls,
153 struct GNUNET_CADET_Channel *channel,
154 const struct GNUNET_PeerIdentity *initiator,
155 const struct GNUNET_HashCode *port,
156 enum GNUNET_CADET_ChannelOption options)
157{
158 long id = (long) cls;
159
160 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
161 "received incoming channel on peer %d, port %s\n",
162 (int) id,
163 GNUNET_h2s (port));
164 if (id != 2L)
165 {
166 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
167 "wrong peer\n");
168 result = GNUNET_SYSERR;
169 }
170 return NULL;
171}
172
173
174/**
175 * Function called whenever an channel is destroyed. Should clean up
176 * any associated state.
177 *
178 * @param cls closure (set from GNUNET_CADET_connect)
179 * @param channel connection to the other end (henceforth invalid)
180 * @param channel_ctx place where local state associated
181 * with the channel is stored
182 */
183static void
184channel_end (void *cls,
185 const struct GNUNET_CADET_Channel *channel,
186 void *channel_ctx)
187{
188 long id = (long) cls;
189
190 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
191 "incoming channel closed at peer %ld\n",
192 id);
193 if (NULL != mth)
194 {
195 GNUNET_CADET_notify_transmit_ready_cancel (mth);
196 mth = NULL;
197 }
198 if (channel == ch)
199 ch = NULL;
200 if (GNUNET_NO == got_data)
201 {
202 if (NULL == connect_task)
203 connect_task
204 = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
205 2),
206 &do_connect,
207 NULL);
208 }
209}
210
211
212/**
213 * Handler array for traffic received on peer1
214 */
215static struct GNUNET_CADET_MessageHandler handlers1[] = {
216 {&data_callback, 1, 0},
217 {NULL, 0, 0}
218};
219
220
221/**
222 * Handler array for traffic received on peer2 (none expected)
223 */
224static struct GNUNET_CADET_MessageHandler handlers2[] = {
225 {&data_callback, 1, 0},
226 {NULL, 0, 0}
227};
228
229
230/**
231 * Data send callback: fillbuffer with test packet.
232 *
233 * @param cls Closure (unused).
234 * @param size Buffer size.
235 * @param buf Buffer to fill.
236 *
237 * @return size of test packet.
238 */
239static size_t
240do_send (void *cls, size_t size, void *buf)
241{
242 struct GNUNET_MessageHeader *m = buf;
243
244 mth = NULL;
245 if (NULL == buf)
246 {
247 GNUNET_break (0);
248 result = GNUNET_SYSERR;
249 return 0;
250 }
251 m->size = htons (sizeof (struct GNUNET_MessageHeader));
252 m->type = htons (1);
253 GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader));
254 return sizeof (struct GNUNET_MessageHeader);
255}
256
257
258/**
259 * Connect to other client and send data
260 *
261 * @param cls Closue (unused).
262 */
263static void
264do_connect (void *cls)
265{
266 struct GNUNET_PeerIdentity id;
267
268 connect_task = NULL;
269 GNUNET_TESTING_peer_get_identity (me, &id);
270 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
271 "CONNECT BY PORT\n");
272 ch = GNUNET_CADET_channel_create (cadet_peer_1,
273 NULL,
274 &id, GC_u2h (1),
275 GNUNET_CADET_OPTION_DEFAULT);
276 mth = GNUNET_CADET_notify_transmit_ready (ch, GNUNET_NO,
277 GNUNET_TIME_UNIT_FOREVER_REL,
278 sizeof (struct GNUNET_MessageHeader),
279 &do_send, NULL);
280}
281
282
283/**
284 * Initialize framework and start test
285 *
286 * @param cls Closure (unused).
287 * @param cfg Configuration handle.
288 * @param peer Testing peer handle.
289 */
290static void
291run (void *cls,
292 const struct GNUNET_CONFIGURATION_Handle *cfg,
293 struct GNUNET_TESTING_Peer *peer)
294{
295 me = peer;
296 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
297 NULL);
298 abort_task =
299 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
300 (GNUNET_TIME_UNIT_SECONDS, 15),
301 &do_abort,
302 NULL);
303 cadet_peer_1 = GNUNET_CADET_connect (cfg, /* configuration */
304 (void *) 1L, /* cls */
305 &channel_end, /* channel end hndlr */
306 handlers1); /* traffic handlers */
307 cadet_peer_2 = GNUNET_CADET_connect (cfg, /* configuration */
308 (void *) 2L, /* cls */
309 &channel_end, /* channel end hndlr */
310 handlers2); /* traffic handlers */
311
312 if ( (NULL == cadet_peer_1) ||
313 (NULL == cadet_peer_2) )
314 {
315 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
316 "Couldn't connect to cadet :(\n");
317 result = GNUNET_SYSERR;
318 GNUNET_SCHEDULER_shutdown ();
319 return;
320 }
321 GNUNET_CADET_open_port (cadet_peer_2,
322 GC_u2h (1),
323 &inbound_channel,
324 (void *) 2L);
325 if (NULL == connect_task)
326 connect_task
327 = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
328 2),
329 &do_connect,
330 NULL);
331}
332
333
334/**
335 * Main
336 */
337int
338main (int argc, char *argv[])
339{
340 if (0 != GNUNET_TESTING_peer_run ("test-cadet-local",
341 "test_cadet.conf",
342 &run, NULL))
343 {
344 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "run failed\n");
345 return 2;
346 }
347 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Final result: %d\n", result);
348 return (result == GNUNET_OK) ? 0 : 1;
349}
350
351/* end of test_cadet_local_1.c */
diff --git a/src/cadet/test_cadet_local_mq.c b/src/cadet/test_cadet_local_mq.c
index 19bafbed1..3089c7fbb 100644
--- a/src/cadet/test_cadet_local_mq.c
+++ b/src/cadet/test_cadet_local_mq.c
@@ -132,12 +132,12 @@ do_abort (void *cls)
132/** 132/**
133 * Method called whenever a peer connects to a port in MQ-based CADET. 133 * Method called whenever a peer connects to a port in MQ-based CADET.
134 * 134 *
135 * @param cls Closure from #GNUNET_CADET_open_porT. 135 * @param cls Closure from #GNUNET_CADET_open_port.
136 * @param channel New handle to the channel. 136 * @param channel New handle to the channel.
137 * @param source Peer that started this channel. 137 * @param source Peer that started this channel.
138 * @return Closure for the incoming @a channel. It's given to: 138 * @return Closure for the incoming @a channel. It's given to:
139 * - The #GNUNET_CADET_DisconnectEventHandler (given to 139 * - The #GNUNET_CADET_DisconnectEventHandler (given to
140 * #GNUNET_CADET_open_porT) when the channel dies. 140 * #GNUNET_CADET_open_port) when the channel dies.
141 * - Each the #GNUNET_MQ_MessageCallback handlers for each message 141 * - Each the #GNUNET_MQ_MessageCallback handlers for each message
142 * received on the @a channel. 142 * received on the @a channel.
143 */ 143 */
@@ -235,7 +235,7 @@ do_connect (void *cls)
235 GNUNET_TESTING_peer_get_identity (me, &id); 235 GNUNET_TESTING_peer_get_identity (me, &id);
236 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 236 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
237 "creating channel\n"); 237 "creating channel\n");
238 ch = GNUNET_CADET_channel_creatE (cadet_peer_1, /* cadet handle */ 238 ch = GNUNET_CADET_channel_create (cadet_peer_1, /* cadet handle */
239 NULL, /* channel cls */ 239 NULL, /* channel cls */
240 &id, /* destination */ 240 &id, /* destination */
241 GC_u2h (TEST_MESSAGE_TYPE), /* port */ 241 GC_u2h (TEST_MESSAGE_TYPE), /* port */
@@ -282,8 +282,8 @@ run (void *cls,
282 abort_task = GNUNET_SCHEDULER_add_delayed (delay, 282 abort_task = GNUNET_SCHEDULER_add_delayed (delay,
283 &do_abort, 283 &do_abort,
284 (void *) (long) __LINE__); 284 (void *) (long) __LINE__);
285 cadet_peer_1 = GNUNET_CADET_connecT (cfg); 285 cadet_peer_1 = GNUNET_CADET_connect (cfg);
286 cadet_peer_2 = GNUNET_CADET_connecT (cfg); 286 cadet_peer_2 = GNUNET_CADET_connect (cfg);
287 287
288 if ( (NULL == cadet_peer_1) || 288 if ( (NULL == cadet_peer_1) ||
289 (NULL == cadet_peer_2) ) 289 (NULL == cadet_peer_2) )
@@ -297,7 +297,7 @@ run (void *cls,
297 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CADET 1: %p\n", cadet_peer_1); 297 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CADET 1: %p\n", cadet_peer_1);
298 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CADET 2: %p\n", cadet_peer_2); 298 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CADET 2: %p\n", cadet_peer_2);
299 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "handlers 2: %p\n", handlers); 299 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "handlers 2: %p\n", handlers);
300 GNUNET_CADET_open_porT (cadet_peer_2, /* cadet handle */ 300 GNUNET_CADET_open_port (cadet_peer_2, /* cadet handle */
301 GC_u2h (TEST_PORT_ID), /* port id */ 301 GC_u2h (TEST_PORT_ID), /* port id */
302 &connected, /* connect handler */ 302 &connected, /* connect handler */
303 (void *) 2L, /* handle for #connected */ 303 (void *) 2L, /* handle for #connected */
diff --git a/src/cadet/test_cadet_new.c b/src/cadet/test_cadet_new.c
deleted file mode 100644
index d32404815..000000000
--- a/src/cadet/test_cadet_new.c
+++ /dev/null
@@ -1,1048 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011, 2017 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20/**
21 * @file cadet/test_cadet_mq.c
22 * @author Bart Polot
23 * @author Christian Grothoff
24 * @brief Test for the cadet service using mq API.
25 */
26#include <stdio.h>
27#include "platform.h"
28#include "cadet_test_lib_new.h"
29#include "gnunet_cadet_service.h"
30#include "gnunet_statistics_service.h"
31#include <gauger.h>
32
33
34/**
35 * Ugly workaround to unify data handlers on incoming and outgoing channels.
36 */
37struct CadetTestChannelWrapper
38{
39 /**
40 * Channel pointer.
41 */
42 struct GNUNET_CADET_Channel *ch;
43};
44
45/**
46 * How many messages to send
47 */
48#define TOTAL_PACKETS 500 /* Cannot exceed 64k! */
49
50/**
51 * How long until we give up on connecting the peers?
52 */
53#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120)
54
55/**
56 * Time to wait for stuff that should be rather fast
57 */
58#define SHORT_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 20)
59
60/**
61 * DIFFERENT TESTS TO RUN
62 */
63#define SETUP 0
64#define FORWARD 1
65#define KEEPALIVE 2
66#define SPEED 3
67#define SPEED_ACK 4
68#define SPEED_REL 8
69#define P2P_SIGNAL 10
70
71/**
72 * Which test are we running?
73 */
74static int test;
75
76/**
77 * String with test name
78 */
79static char *test_name;
80
81/**
82 * Flag to send traffic leaf->root in speed tests to test BCK_ACK logic.
83 */
84static int test_backwards = GNUNET_NO;
85
86/**
87 * How many events have happened
88 */
89static int ok;
90
91/**
92 * Number of events expected to conclude the test successfully.
93 */
94static int ok_goal;
95
96/**
97 * Size of each test packet's payload
98 */
99static size_t size_payload = sizeof (uint32_t);
100
101/**
102 * Operation to get peer ids.
103 */
104static struct GNUNET_TESTBED_Operation *t_op[2];
105
106/**
107 * Peer ids.
108 */
109static struct GNUNET_PeerIdentity *p_id[2];
110
111/**
112 * Port ID
113 */
114static struct GNUNET_HashCode port;
115
116/**
117 * Peer ids counter.
118 */
119static unsigned int p_ids;
120
121/**
122 * Is the setup initialized?
123 */
124static int initialized;
125
126/**
127 * Number of payload packes sent.
128 */
129static int data_sent;
130
131/**
132 * Number of payload packets received.
133 */
134static int data_received;
135
136/**
137 * Number of payload packed acknowledgements sent.
138 */
139static int ack_sent;
140
141/**
142 * Number of payload packed explicitly (app level) acknowledged.
143 */
144static int ack_received;
145
146/**
147 * Total number of peers asked to run.
148 */
149static unsigned long long peers_requested;
150
151/**
152 * Number of currently running peers (should be same as @c peers_requested).
153 */
154static unsigned long long peers_running;
155
156/**
157 * Test context (to shut down).
158 */
159struct GNUNET_CADET_TEST_Context *test_ctx;
160
161/**
162 * Task called to disconnect peers.
163 */
164static struct GNUNET_SCHEDULER_Task *disconnect_task;
165
166/**
167 * Task To perform tests
168 */
169static struct GNUNET_SCHEDULER_Task *test_task;
170
171/**
172 * Task runnining #send_next_msg().
173 */
174static struct GNUNET_SCHEDULER_Task *send_next_msg_task;
175
176/**
177 * Cadet handle for the root peer
178 */
179static struct GNUNET_CADET_Handle *h1;
180
181/**
182 * Cadet handle for the first leaf peer
183 */
184static struct GNUNET_CADET_Handle *h2;
185
186/**
187 * Channel handle for the root peer
188 */
189static struct GNUNET_CADET_Channel *outgoing_ch;
190
191/**
192 * Channel handle for the dest peer
193 */
194static struct GNUNET_CADET_Channel *incoming_ch;
195
196/**
197 * Time we started the data transmission (after channel has been established
198 * and initilized).
199 */
200static struct GNUNET_TIME_Absolute start_time;
201
202/**
203 * Peers handle.
204 */
205static struct GNUNET_TESTBED_Peer **testbed_peers;
206
207/**
208 * Statistics operation handle.
209 */
210static struct GNUNET_TESTBED_Operation *stats_op;
211
212/**
213 * Keepalives sent.
214 */
215static unsigned int ka_sent;
216
217/**
218 * Keepalives received.
219 */
220static unsigned int ka_received;
221
222/**
223 * How many messages were dropped by CADET because of full buffers?
224 */
225static unsigned int msg_dropped;
226
227
228/******************************************************************************/
229
230
231/******************************************************************************/
232
233
234/**
235 * Get the channel considered as the "target" or "receiver", depending on
236 * the test type and size.
237 *
238 * @return Channel handle of the target client, either 0 (for backward tests)
239 * or the last peer in the line (for other tests).
240 */
241static struct GNUNET_CADET_Channel *
242get_target_channel ()
243{
244 if (SPEED == test && GNUNET_YES == test_backwards)
245 return outgoing_ch;
246 else
247 return incoming_ch;
248}
249
250
251/**
252 * Show the results of the test (banwidth acheived) and log them to GAUGER
253 */
254static void
255show_end_data (void)
256{
257 static struct GNUNET_TIME_Absolute end_time;
258 static struct GNUNET_TIME_Relative total_time;
259
260 end_time = GNUNET_TIME_absolute_get ();
261 total_time = GNUNET_TIME_absolute_get_difference (start_time, end_time);
262 FPRINTF (stderr, "\nResults of test \"%s\"\n", test_name);
263 FPRINTF (stderr, "Test time %s\n",
264 GNUNET_STRINGS_relative_time_to_string (total_time, GNUNET_YES));
265 FPRINTF (stderr, "Test bandwidth: %f kb/s\n", 4 * TOTAL_PACKETS * 1.0 / (total_time.rel_value_us / 1000)); // 4bytes * ms
266 FPRINTF (stderr, "Test throughput: %f packets/s\n\n", TOTAL_PACKETS * 1000.0 / (total_time.rel_value_us / 1000)); // packets * ms
267 GAUGER ("CADET", test_name,
268 TOTAL_PACKETS * 1000.0 / (total_time.rel_value_us / 1000),
269 "packets/s");
270}
271
272
273/**
274 * Disconnect from cadet services af all peers, call shutdown.
275 *
276 * @param cls Closure (line number from which termination was requested).
277 * @param tc Task Context.
278 */
279static void
280disconnect_cadet_peers (void *cls)
281{
282 long line = (long) cls;
283 unsigned int i;
284
285 disconnect_task = NULL;
286 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
287 "disconnecting cadet service of peers, called from line %ld\n",
288 line);
289 for (i = 0; i < 2; i++)
290 {
291 GNUNET_TESTBED_operation_done (t_op[i]);
292 }
293 if (NULL != outgoing_ch)
294 {
295 GNUNET_CADET_channel_destroy (outgoing_ch);
296 outgoing_ch = NULL;
297 }
298 if (NULL != incoming_ch)
299 {
300 GNUNET_CADET_channel_destroy (incoming_ch);
301 incoming_ch = NULL;
302 }
303 GNUNET_CADET_TEST_cleanup (test_ctx);
304 GNUNET_SCHEDULER_shutdown ();
305}
306
307
308/**
309 * Shut down peergroup, clean up.
310 *
311 * @param cls Closure (unused).
312 * @param tc Task Context.
313 */
314static void
315shutdown_task (void *cls)
316{
317 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ending test.\n");
318 if (NULL != send_next_msg_task)
319 {
320 GNUNET_SCHEDULER_cancel (send_next_msg_task);
321 send_next_msg_task = NULL;
322 }
323 if (NULL != test_task)
324 {
325 GNUNET_SCHEDULER_cancel (test_task);
326 test_task = NULL;
327 }
328 if (NULL != disconnect_task)
329 {
330 GNUNET_SCHEDULER_cancel (disconnect_task);
331 disconnect_task =
332 GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, (void *) __LINE__);
333 }
334}
335
336
337/**
338 * Stats callback. Finish the stats testbed operation and when all stats have
339 * been iterated, shutdown the test.
340 *
341 * @param cls Closure (line number from which termination was requested).
342 * @param op the operation that has been finished
343 * @param emsg error message in case the operation has failed; will be NULL if
344 * operation has executed successfully.
345 */
346static void
347stats_cont (void *cls, struct GNUNET_TESTBED_Operation *op, const char *emsg)
348{
349 GNUNET_log (GNUNET_ERROR_TYPE_INFO, " KA sent: %u, KA received: %u\n",
350 ka_sent, ka_received);
351 if ((KEEPALIVE == test) && ((ka_sent < 2) || (ka_sent > ka_received + 1)))
352 {
353 GNUNET_break (0);
354 ok--;
355 }
356 GNUNET_TESTBED_operation_done (stats_op);
357
358 if (NULL != disconnect_task)
359 GNUNET_SCHEDULER_cancel (disconnect_task);
360 disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, cls);
361}
362
363
364/**
365 * Process statistic values.
366 *
367 * @param cls closure (line number, unused)
368 * @param peer the peer the statistic belong to
369 * @param subsystem name of subsystem that created the statistic
370 * @param name the name of the datum
371 * @param value the current value
372 * @param is_persistent #GNUNET_YES if the value is persistent, #GNUNET_NO if not
373 * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
374 */
375static int
376stats_iterator (void *cls, const struct GNUNET_TESTBED_Peer *peer,
377 const char *subsystem, const char *name, uint64_t value,
378 int is_persistent)
379{
380 static const char *s_sent = "# keepalives sent";
381 static const char *s_recv = "# keepalives received";
382 static const char *rdrops = "# messages dropped due to full buffer";
383 static const char *cdrops = "# messages dropped due to slow client";
384 uint32_t i;
385
386 i = GNUNET_TESTBED_get_index (peer);
387 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "STATS PEER %u - %s [%s]: %llu\n", i,
388 subsystem, name, (unsigned long long) value);
389 if (0 == strncmp (s_sent, name, strlen (s_sent)) && 0 == i)
390 ka_sent = value;
391 if (0 == strncmp (s_recv, name, strlen (s_recv)) && peers_requested - 1 == i)
392 ka_received = value;
393 if (0 == strncmp (rdrops, name, strlen (rdrops)))
394 msg_dropped += value;
395 if (0 == strncmp (cdrops, name, strlen (cdrops)))
396 msg_dropped += value;
397
398 return GNUNET_OK;
399}
400
401
402/**
403 * Task to gather all statistics.
404 *
405 * @param cls Closure (line from which the task was scheduled).
406 */
407static void
408gather_stats_and_exit (void *cls)
409{
410 long l = (long) cls;
411
412 disconnect_task = NULL;
413 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
414 "gathering statistics from line %ld\n",
415 l);
416 if (NULL != outgoing_ch)
417 {
418 GNUNET_CADET_channel_destroy (outgoing_ch);
419 outgoing_ch = NULL;
420 }
421 stats_op = GNUNET_TESTBED_get_statistics (peers_running,
422 testbed_peers,
423 "cadet",
424 NULL,
425 &stats_iterator,
426 stats_cont,
427 cls);
428}
429
430
431
432/**
433 * Abort test: schedule disconnect and shutdown immediately
434 *
435 * @param line Line in the code the abort is requested from (__LINE__).
436 */
437static void
438abort_test (long line)
439{
440 if (NULL != disconnect_task)
441 {
442 GNUNET_SCHEDULER_cancel (disconnect_task);
443 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Aborting test from %ld\n", line);
444 disconnect_task =
445 GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, (void *) line);
446 }
447}
448
449
450/**
451 * Send a message on the channel with the appropriate size and payload.
452 *
453 * Update the appropriate *_sent counter.
454 *
455 * @param channel Channel to send the message on.
456 */
457static void
458send_test_message (struct GNUNET_CADET_Channel *channel)
459{
460 struct GNUNET_MQ_Envelope *env;
461 struct GNUNET_MessageHeader *msg;
462 uint32_t *data;
463 int *counter;
464 int size;
465
466 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
467 "Sending test message on channel %p\n",
468 channel);
469 size = size_payload;
470 if (GNUNET_NO == initialized)
471 {
472 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending INITIALIZER\n");
473 size += 1000;
474 counter = &data_sent;
475 if (SPEED_ACK == test) // FIXME unify SPEED_ACK with an initializer
476 data_sent++;
477 }
478 else if (SPEED == test || SPEED_ACK == test)
479 {
480 counter = get_target_channel() == channel ? &ack_sent : &data_sent;
481 size += *counter;
482 *counter = *counter + 1;
483 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Sending message %u\n", *counter);
484 }
485 else
486 {
487 counter = &ack_sent;
488 }
489 env = GNUNET_MQ_msg_extra (msg, size, GNUNET_MESSAGE_TYPE_DUMMY);
490
491 data = (uint32_t *) &msg[1];
492 *data = htonl (*counter);
493 GNUNET_MQ_send (GNUNET_CADET_get_mq (channel), env);
494}
495
496/**
497 * Task to request a new data transmission in a SPEED test, without waiting
498 * for previous messages to be sent/arrrive.
499 *
500 * @param cls Closure (unused).
501 */
502static void
503send_next_msg (void *cls)
504{
505 struct GNUNET_CADET_Channel *channel;
506
507 send_next_msg_task = NULL;
508 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending next message: %d\n", data_sent);
509
510 channel = GNUNET_YES == test_backwards ? incoming_ch : outgoing_ch;
511 GNUNET_assert (NULL != channel);
512 GNUNET_assert (SPEED == test);
513 send_test_message (channel);
514 if (data_sent < TOTAL_PACKETS)
515 {
516 /* SPEED test: Send all messages as soon as possible */
517 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
518 "Scheduling message %d\n",
519 data_sent + 1);
520 send_next_msg_task = GNUNET_SCHEDULER_add_now (&send_next_msg, NULL);
521 }
522}
523
524
525/**
526 * Every few messages cancel the timeout task and re-schedule it again, to
527 * avoid timing out when traffic keeps coming.
528 *
529 * @param line Code line number to log if a timeout occurs.
530 */
531static void
532reschedule_timeout_task (long line)
533{
534 if ((ok % 10) == 0)
535 {
536 if (NULL != disconnect_task)
537 {
538 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
539 " reschedule timeout every 10 messages\n");
540 GNUNET_SCHEDULER_cancel (disconnect_task);
541 disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME,
542 &gather_stats_and_exit,
543 (void *) line);
544 }
545 }
546}
547
548
549/**
550 * Check if payload is sane (size contains payload).
551 *
552 * @param cls should match #ch
553 * @param message The actual message.
554 * @return #GNUNET_OK to keep the channel open,
555 * #GNUNET_SYSERR to close it (signal serious error).
556 */
557static int
558check_data (void *cls, const struct GNUNET_MessageHeader *message)
559{
560 if (sizeof (struct GNUNET_MessageHeader) >= ntohs (message->size))
561 return GNUNET_SYSERR;
562 return GNUNET_OK; /* all is well-formed */
563}
564
565
566/**
567 * Function is called whenever a message is received.
568 *
569 * @param cls closure (set from GNUNET_CADET_connect(), peer number)
570 * @param message the actual message
571 */
572static void
573handle_data (void *cls, const struct GNUNET_MessageHeader *message)
574{
575 struct CadetTestChannelWrapper *ch = cls;
576 struct GNUNET_CADET_Channel *channel = ch->ch;
577 uint32_t *data;
578 uint32_t payload;
579 int *counter;
580
581 ok++;
582 counter = get_target_channel () == channel ? &data_received : &ack_received;
583
584 reschedule_timeout_task ((long) __LINE__);
585
586 if (channel == outgoing_ch)
587 {
588 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Root client got a message!\n");
589 }
590 else if (channel == incoming_ch)
591 {
592 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Leaf client got a message.\n");
593 }
594 else
595 {
596 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unknown channel %p.\n", channel);
597 GNUNET_assert (0);
598 }
599
600 GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: (%d/%d)\n", ok, ok_goal);
601 data = (uint32_t *) &message[1];
602 payload = ntohl (*data);
603 if (payload == *counter)
604 {
605 GNUNET_log (GNUNET_ERROR_TYPE_INFO, " payload as expected: %u\n", payload);
606 }
607 else
608 {
609 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
610 " payload %u, expected: %u\n",
611 payload, *counter);
612 }
613
614 if (GNUNET_NO == initialized)
615 {
616 initialized = GNUNET_YES;
617 start_time = GNUNET_TIME_absolute_get ();
618 if (SPEED == test)
619 {
620 GNUNET_assert (incoming_ch == channel);
621 send_next_msg_task = GNUNET_SCHEDULER_add_now (&send_next_msg, NULL);
622 return;
623 }
624 }
625
626 (*counter)++;
627 if (get_target_channel () == channel) /* Got "data" */
628 {
629 GNUNET_log (GNUNET_ERROR_TYPE_INFO, " received data %u\n", data_received);
630 if (SPEED != test || (ok_goal - 2) == ok)
631 {
632 /* Send ACK */
633 send_test_message (channel);
634 return;
635 }
636 else
637 {
638 if (data_received < TOTAL_PACKETS)
639 return;
640 }
641 }
642 else /* Got "ack" */
643 {
644 if (SPEED_ACK == test || SPEED == test)
645 {
646 GNUNET_log (GNUNET_ERROR_TYPE_INFO, " received ack %u\n", ack_received);
647 /* Send more data */
648 send_test_message (channel);
649 if (ack_received < TOTAL_PACKETS && SPEED != test)
650 return;
651 if (ok == 2 && SPEED == test)
652 return;
653 show_end_data ();
654 }
655 if (test == P2P_SIGNAL)
656 {
657 GNUNET_CADET_channel_destroy (incoming_ch);
658 incoming_ch = NULL;
659 }
660 else
661 {
662 GNUNET_CADET_channel_destroy (outgoing_ch);
663 outgoing_ch = NULL;
664 }
665 }
666}
667
668
669/**
670 * Method called whenever a peer connects to a port in MQ-based CADET.
671 *
672 * @param cls Closure from #GNUNET_CADET_open_porT (peer # as long).
673 * @param channel New handle to the channel.
674 * @param source Peer that started this channel.
675 * @return Closure for the incoming @a channel. It's given to:
676 * - The #GNUNET_CADET_DisconnectEventHandler (given to
677 * #GNUNET_CADET_open_porT) when the channel dies.
678 * - Each the #GNUNET_MQ_MessageCallback handlers for each message
679 * received on the @a channel.
680 */
681static void *
682connect_handler (void *cls, struct GNUNET_CADET_Channel *channel,
683 const struct GNUNET_PeerIdentity *source)
684{
685 struct CadetTestChannelWrapper *ch;
686 long peer = (long) cls;
687
688 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Incoming channel from %s to peer %ld\n",
689 GNUNET_i2s (source), peer);
690 ok++;
691 GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok);
692 if (peer == peers_requested - 1)
693 {
694 if (NULL != incoming_ch)
695 {
696 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
697 "Duplicate incoming channel for client %lu\n", (long) cls);
698 GNUNET_assert (0);
699 }
700 incoming_ch = channel;
701 }
702 else
703 {
704 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
705 "Incoming channel for unexpected peer #%lu\n", (long) cls);
706 GNUNET_assert (0);
707 }
708 if (NULL != disconnect_task)
709 {
710 GNUNET_SCHEDULER_cancel (disconnect_task);
711 disconnect_task =
712 GNUNET_SCHEDULER_add_delayed (SHORT_TIME, &gather_stats_and_exit,
713 (void *) __LINE__);
714 }
715
716 /* TODO: cannot return channel as-is, in order to unify the data handlers */
717 ch = GNUNET_new (struct CadetTestChannelWrapper);
718 ch->ch = channel;
719
720 return ch;
721}
722
723
724/**
725 * Function called whenever an MQ-channel is destroyed, even if the destruction
726 * was requested by #GNUNET_CADET_channel_destroy.
727 * It must NOT call #GNUNET_CADET_channel_destroy on the channel.
728 *
729 * It should clean up any associated state, including cancelling any pending
730 * transmission on this channel.
731 *
732 * @param cls Channel closure (channel wrapper).
733 * @param channel Connection to the other end (henceforth invalid).
734 */
735static void
736disconnect_handler (void *cls, const struct GNUNET_CADET_Channel *channel)
737{
738 struct CadetTestChannelWrapper *ch_w = cls;
739
740 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Channel disconnected\n");
741 GNUNET_assert (ch_w->ch == channel);
742 if (channel == incoming_ch)
743 {
744 ok++;
745 incoming_ch = NULL;
746 }
747 else if (outgoing_ch == channel
748 )
749 {
750 if (P2P_SIGNAL == test)
751 {
752 ok++;
753 }
754 outgoing_ch = NULL;
755 }
756 else
757 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Unknown channel! %p\n", channel);
758 GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok);
759
760 if (NULL != disconnect_task)
761 {
762 GNUNET_SCHEDULER_cancel (disconnect_task);
763 disconnect_task =
764 GNUNET_SCHEDULER_add_now (&gather_stats_and_exit, (void *) __LINE__);
765 }
766}
767
768
769/**
770 * START THE TESTCASE ITSELF, AS WE ARE CONNECTED TO THE CADET SERVICES.
771 *
772 * Testcase continues when the root receives confirmation of connected peers,
773 * on callback function ch.
774 *
775 * @param cls Closure (unused).
776 */
777static void
778start_test (void *cls)
779{
780 struct GNUNET_MQ_MessageHandler handlers[] = {
781 GNUNET_MQ_hd_var_size (data,
782 GNUNET_MESSAGE_TYPE_DUMMY,
783 struct GNUNET_MessageHeader,
784 NULL),
785 GNUNET_MQ_handler_end ()
786 };
787 struct CadetTestChannelWrapper *ch;
788 enum GNUNET_CADET_ChannelOption flags;
789
790 test_task = NULL;
791 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "start_test\n");
792 if (NULL != disconnect_task)
793 {
794 GNUNET_SCHEDULER_cancel (disconnect_task);
795 disconnect_task = NULL;
796 }
797
798 flags = GNUNET_CADET_OPTION_DEFAULT;
799 if (SPEED_REL == test)
800 {
801 test = SPEED;
802 flags |= GNUNET_CADET_OPTION_RELIABLE;
803 }
804
805 ch = GNUNET_new (struct CadetTestChannelWrapper);
806 outgoing_ch = GNUNET_CADET_channel_creatE (h1,
807 ch,
808 p_id[1],
809 &port,
810 flags,
811 NULL,
812 &disconnect_handler,
813 handlers);
814 ch->ch = outgoing_ch;
815
816 disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME,
817 &gather_stats_and_exit,
818 (void *) __LINE__);
819 if (KEEPALIVE == test)
820 return; /* Don't send any data. */
821
822
823 data_received = 0;
824 data_sent = 0;
825 ack_received = 0;
826 ack_sent = 0;
827 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending data initializer...\n");
828 send_test_message (outgoing_ch);
829}
830
831
832/**
833 * Callback to be called when the requested peer information is available
834 *
835 * @param cls the closure from GNUNET_TESTBED_peer_get_information()
836 * @param op the operation this callback corresponds to
837 * @param pinfo the result; will be NULL if the operation has failed
838 * @param emsg error message if the operation has failed;
839 * NULL if the operation is successfull
840 */
841static void
842pi_cb (void *cls, struct GNUNET_TESTBED_Operation *op,
843 const struct GNUNET_TESTBED_PeerInformation *pinfo, const char *emsg)
844{
845 long i = (long) cls;
846
847 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ID callback for %ld\n", i);
848
849 if ((NULL == pinfo) || (NULL != emsg))
850 {
851 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "pi_cb: %s\n", emsg);
852 abort_test (__LINE__);
853 return;
854 }
855 p_id[i] = pinfo->result.id;
856 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " id: %s\n", GNUNET_i2s (p_id[i]));
857 p_ids++;
858 if (p_ids < 2)
859 return;
860 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got all IDs, starting test\n");
861 test_task = GNUNET_SCHEDULER_add_now (&start_test, NULL);
862}
863
864
865/**
866 * test main: start test when all peers are connected
867 *
868 * @param cls Closure.
869 * @param ctx Argument to give to GNUNET_CADET_TEST_cleanup on test end.
870 * @param num_peers Number of peers that are running.
871 * @param peers Array of peers.
872 * @param cadets Handle to each of the CADETs of the peers.
873 */
874static void
875tmain (void *cls,
876 struct GNUNET_CADET_TEST_Context *ctx,
877 unsigned int num_peers,
878 struct GNUNET_TESTBED_Peer **peers,
879 struct GNUNET_CADET_Handle **cadets)
880{
881 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test main\n");
882 ok = 0;
883 test_ctx = ctx;
884 peers_running = num_peers;
885 GNUNET_assert (peers_running == peers_requested);
886 testbed_peers = peers;
887 h1 = cadets[0];
888 h2 = cadets[num_peers - 1];
889 disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME,
890 &disconnect_cadet_peers,
891 (void *) __LINE__);
892 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
893 t_op[0] = GNUNET_TESTBED_peer_get_information (peers[0],
894 GNUNET_TESTBED_PIT_IDENTITY,
895 &pi_cb,
896 (void *) 0L);
897 t_op[1] = GNUNET_TESTBED_peer_get_information (peers[num_peers - 1],
898 GNUNET_TESTBED_PIT_IDENTITY,
899 &pi_cb,
900 (void *) 1L);
901 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "requested peer ids\n");
902}
903
904
905/**
906 * Main: start test
907 */
908int
909main (int argc, char *argv[])
910{
911 struct GNUNET_MQ_MessageHandler handlers[] = {
912 GNUNET_MQ_hd_var_size (data,
913 GNUNET_MESSAGE_TYPE_DUMMY,
914 struct GNUNET_MessageHeader,
915 NULL),
916 GNUNET_MQ_handler_end ()
917 };
918
919 initialized = GNUNET_NO;
920 static const struct GNUNET_HashCode *ports[2];
921 const char *config_file;
922 char port_id[] = "test port";
923
924 GNUNET_CRYPTO_hash (port_id, sizeof (port_id), &port);
925
926 GNUNET_log_setup ("test", "DEBUG", NULL);
927 config_file = "test_cadet.conf";
928
929 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Start\n");
930
931 /* Find out requested size */
932 if (strstr (argv[0], "_2_") != NULL)
933 {
934 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "DIRECT CONNECTIONs\n");
935 peers_requested = 2;
936 }
937 else if (strstr (argv[0], "_5_") != NULL)
938 {
939 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "5 PEER LINE\n");
940 peers_requested = 5;
941 }
942 else
943 {
944 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "SIZE UNKNOWN, USING 2\n");
945 peers_requested = 2;
946 }
947
948 /* Find out requested test */
949 if (strstr (argv[0], "_forward") != NULL)
950 {
951 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "FORWARD\n");
952 test = FORWARD;
953 test_name = "unicast";
954 ok_goal = 4;
955 }
956 else if (strstr (argv[0], "_signal") != NULL)
957 {
958 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SIGNAL\n");
959 test = P2P_SIGNAL;
960 test_name = "signal";
961 ok_goal = 4;
962 }
963 else if (strstr (argv[0], "_speed_ack") != NULL)
964 {
965 /* Test is supposed to generate the following callbacks:
966 * 1 incoming channel (@dest)
967 * TOTAL_PACKETS received data packet (@dest)
968 * TOTAL_PACKETS received data packet (@orig)
969 * 1 received channel destroy (@dest)
970 */
971 ok_goal = TOTAL_PACKETS * 2 + 2;
972 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SPEED_ACK\n");
973 test = SPEED_ACK;
974 test_name = "speed ack";
975 }
976 else if (strstr (argv[0], "_speed") != NULL)
977 {
978 /* Test is supposed to generate the following callbacks:
979 * 1 incoming channel (@dest)
980 * 1 initial packet (@dest)
981 * TOTAL_PACKETS received data packet (@dest)
982 * 1 received data packet (@orig)
983 * 1 received channel destroy (@dest)
984 */
985 ok_goal = TOTAL_PACKETS + 4;
986 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SPEED\n");
987 if (strstr (argv[0], "_reliable") != NULL)
988 {
989 test = SPEED_REL;
990 test_name = "speed reliable";
991 config_file = "test_cadet_drop.conf";
992 }
993 else
994 {
995 test = SPEED;
996 test_name = "speed";
997 }
998 }
999 else if (strstr (argv[0], "_keepalive") != NULL)
1000 {
1001 test = KEEPALIVE;
1002 /* Test is supposed to generate the following callbacks:
1003 * 1 incoming channel (@dest)
1004 * [wait]
1005 * 1 received channel destroy (@dest)
1006 */
1007 ok_goal = 2;
1008 }
1009 else
1010 {
1011 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "UNKNOWN\n");
1012 test = SETUP;
1013 ok_goal = 0;
1014 }
1015
1016 if (strstr (argv[0], "backwards") != NULL)
1017 {
1018 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "BACKWARDS (LEAF TO ROOT)\n");
1019 test_backwards = GNUNET_YES;
1020 GNUNET_asprintf (&test_name, "backwards %s", test_name);
1021 }
1022
1023 p_ids = 0;
1024 ports[0] = &port;
1025 ports[1] = NULL;
1026 GNUNET_CADET_TEST_ruN ("test_cadet_small",
1027 config_file,
1028 peers_requested,
1029 &tmain,
1030 NULL, /* tmain cls */
1031 &connect_handler,
1032 NULL,
1033 &disconnect_handler,
1034 handlers,
1035 ports);
1036 if (NULL != strstr (argv[0], "_reliable"))
1037 msg_dropped = 0; /* dropped should be retransmitted */
1038
1039 if (ok_goal > ok - msg_dropped)
1040 {
1041 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "FAILED! (%d/%d)\n", ok, ok_goal);
1042 return 1;
1043 }
1044 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "success\n");
1045 return 0;
1046}
1047
1048/* end of test_cadet.c */
diff --git a/src/cadet/test_cadet_single.c b/src/cadet/test_cadet_single.c
deleted file mode 100644
index b45b0af5d..000000000
--- a/src/cadet/test_cadet_single.c
+++ /dev/null
@@ -1,354 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21/**
22 * @file cadet/test_cadet_single.c
23 * @brief test cadet single: test of cadet channels with just one client
24 * @author Bartlomiej Polot
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_dht_service.h"
30#include "gnunet_testing_lib.h"
31#include "gnunet_cadet_service.h"
32
33#define REPETITIONS 5
34#define DATA_SIZE 35000
35
36struct GNUNET_TESTING_Peer *me;
37
38static struct GNUNET_CADET_Handle *cadet;
39
40static struct GNUNET_CADET_Channel *ch1;
41
42static struct GNUNET_CADET_Channel *ch2;
43
44static int result;
45
46static struct GNUNET_SCHEDULER_Task *abort_task;
47
48static struct GNUNET_SCHEDULER_Task *connect_task;
49
50static unsigned int repetition;
51
52static struct GNUNET_CADET_TransmitHandle *nth;
53
54static struct GNUNET_CADET_Port *port;
55
56
57/* forward declaration */
58static size_t
59do_send (void *cls, size_t size, void *buf);
60
61
62/**
63 * Shutdown nicely
64 */
65static void
66do_shutdown (void *cls)
67{
68 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
69 "shutdown\n");
70 if (NULL != port)
71 {
72 GNUNET_CADET_close_port (port);
73 port = NULL;
74 }
75 if (NULL != nth)
76 {
77 GNUNET_CADET_notify_transmit_ready_cancel (nth);
78 nth = NULL;
79 }
80 if (NULL != abort_task)
81 {
82 GNUNET_SCHEDULER_cancel (abort_task);
83 abort_task = NULL;
84 }
85 if (NULL != connect_task)
86 {
87 GNUNET_SCHEDULER_cancel (connect_task);
88 connect_task = NULL;
89 }
90 if (NULL != ch1)
91 {
92 GNUNET_CADET_channel_destroy (ch1);
93 ch1 = NULL;
94 }
95 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
96 "Disconnect clients\n");
97 if (NULL != cadet)
98 {
99 GNUNET_CADET_disconnect (cadet);
100 cadet = NULL;
101 }
102 else
103 {
104 GNUNET_break (0);
105 }
106}
107
108
109/**
110 * Something went wrong and timed out. Kill everything and set error flag
111 */
112static void
113do_abort (void *cls)
114{
115 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ABORT\n");
116 result = GNUNET_SYSERR;
117 abort_task = NULL;
118 GNUNET_SCHEDULER_shutdown ();
119}
120
121
122/**
123 * Function is called whenever a message is received.
124 *
125 * @param cls closure (set from GNUNET_CADET_connect)
126 * @param channel connection to the other end
127 * @param channel_ctx place to store local state associated with the channel
128 * @param message the actual message
129 * @return #GNUNET_OK to keep the connection open,
130 * #GNUNET_SYSERR to close it (signal serious error)
131 */
132static int
133data_callback (void *cls,
134 struct GNUNET_CADET_Channel *channel,
135 void **channel_ctx,
136 const struct GNUNET_MessageHeader *message)
137{
138 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
139 "Data callback! Repetition %u/%u\n",
140 repetition, REPETITIONS);
141 repetition++;
142 if (repetition < REPETITIONS)
143 {
144 struct GNUNET_CADET_Channel *my_channel;
145 if (0 == repetition % 2)
146 my_channel = ch1;
147 else
148 my_channel = ch2;
149 nth = GNUNET_CADET_notify_transmit_ready (my_channel,
150 GNUNET_NO,
151 GNUNET_TIME_UNIT_FOREVER_REL,
152 sizeof (struct GNUNET_MessageHeader)
153 + DATA_SIZE,
154 &do_send, NULL);
155 GNUNET_CADET_receive_done (channel);
156 return GNUNET_OK;
157 }
158 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
159 "All data OK. Destroying channel.\n");
160 GNUNET_assert (NULL == nth);
161 GNUNET_CADET_channel_destroy (ch1);
162 ch1 = NULL;
163 return GNUNET_OK;
164}
165
166
167/**
168 * Method called whenever another peer has added us to a channel
169 * the other peer initiated.
170 *
171 * @param cls closure
172 * @param channel new handle to the channel
173 * @param initiator peer that started the channel
174 * @param port port number
175 * @param options channel option flags
176 * @return initial channel context for the channel
177 * (can be NULL -- that's not an error)
178 */
179static void *
180inbound_channel (void *cls,
181 struct GNUNET_CADET_Channel *channel,
182 const struct GNUNET_PeerIdentity *initiator,
183 const struct GNUNET_HashCode *port,
184 enum GNUNET_CADET_ChannelOption options)
185{
186 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
187 "received incoming channel on port %s\n",
188 GNUNET_h2s (port));
189 ch2 = channel;
190 return NULL;
191}
192
193
194/**
195 * Function called whenever an inbound channel is destroyed. Should clean up
196 * any associated state.
197 *
198 * @param cls closure (set from GNUNET_CADET_connect)
199 * @param channel connection to the other end (henceforth invalid)
200 * @param channel_ctx place where local state associated
201 * with the channel is stored
202 */
203static void
204channel_end (void *cls,
205 const struct GNUNET_CADET_Channel *channel,
206 void *channel_ctx)
207{
208 long id = (long) cls;
209
210 nth = NULL;
211 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
212 "incoming channel closed at peer %ld\n",
213 id);
214 if ( (REPETITIONS == repetition) &&
215 (channel == ch2) )
216 {
217 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
218 "everything fine! finishing!\n");
219 result = GNUNET_OK;
220 GNUNET_SCHEDULER_shutdown ();
221 }
222 if (channel == ch2)
223 ch2 = NULL;
224 if (channel == ch1)
225 ch1 = NULL;
226}
227
228
229/**
230 * Handler array for traffic received on peer1
231 */
232static struct GNUNET_CADET_MessageHandler handlers1[] = {
233 {&data_callback, 1, 0},
234 {NULL, 0, 0}
235};
236
237
238/**
239 * Data send callback: fillbuffer with test packet.
240 *
241 * @param cls Closure (unused).
242 * @param size Buffer size.
243 * @param buf Buffer to fill.
244 * @return size of test packet.
245 */
246static size_t
247do_send (void *cls, size_t size, void *buf)
248{
249 struct GNUNET_MessageHeader *m = buf;
250
251 nth = NULL;
252 if (NULL == buf)
253 {
254 GNUNET_break (0);
255 result = GNUNET_SYSERR;
256 return 0;
257 }
258 m->size = htons (sizeof (struct GNUNET_MessageHeader) + DATA_SIZE);
259 m->type = htons (1);
260 memset (&m[1], 0, DATA_SIZE);
261 GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader) + DATA_SIZE);
262 return sizeof (struct GNUNET_MessageHeader) + DATA_SIZE;
263}
264
265/**
266 * Connect to other client and send data
267 *
268 * @param cls Closue (unused).
269 */
270static void
271do_connect (void *cls)
272{
273 struct GNUNET_PeerIdentity id;
274 size_t size = sizeof (struct GNUNET_MessageHeader) + DATA_SIZE;
275
276 connect_task = NULL;
277 GNUNET_TESTING_peer_get_identity (me, &id);
278 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CONNECT BY PORT\n");
279 ch1 = GNUNET_CADET_channel_create (cadet, NULL, &id, GC_u2h (1),
280 GNUNET_CADET_OPTION_DEFAULT);
281 nth = GNUNET_CADET_notify_transmit_ready (ch1,
282 GNUNET_NO,
283 GNUNET_TIME_UNIT_FOREVER_REL,
284 size,
285 &do_send,
286 NULL);
287}
288
289
290/**
291 * Initialize framework and start test
292 *
293 * @param cls Closure (unused).
294 * @param cfg Configuration handle.
295 * @param peer Testing peer handle.
296 */
297static void
298run (void *cls,
299 const struct GNUNET_CONFIGURATION_Handle *cfg,
300 struct GNUNET_TESTING_Peer *peer)
301{
302 me = peer;
303 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
304 abort_task =
305 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
306 (GNUNET_TIME_UNIT_SECONDS, 15), &do_abort,
307 NULL);
308 cadet = GNUNET_CADET_connect (cfg, /* configuration */
309 (void *) 1L, /* cls */
310 &channel_end, /* inbound end hndlr */
311 handlers1); /* traffic handlers */
312 port = GNUNET_CADET_open_port (cadet,
313 GC_u2h (1),
314 &inbound_channel,
315 (void *) 1L);
316
317
318 if (NULL == cadet)
319 {
320 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
321 "Couldn't connect to cadet :(\n");
322 result = GNUNET_SYSERR;
323 return;
324 }
325 connect_task
326 = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
327 &do_connect,
328 NULL);
329}
330
331
332/**
333 * Main
334 */
335int
336main (int argc,
337 char *argv[])
338{
339 result = GNUNET_NO;
340 if (0 != GNUNET_TESTING_peer_run ("test-cadet-local",
341 "test_cadet.conf",
342 &run, NULL))
343 {
344 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
345 "run failed\n");
346 return 2;
347 }
348 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
349 "Final result: %d\n",
350 result);
351 return (result == GNUNET_OK) ? 0 : 1;
352}
353
354/* end of test_cadet_single.c */
diff --git a/src/consensus/Makefile.am b/src/consensus/Makefile.am
index 2b1987fbc..c0205ee5d 100644
--- a/src/consensus/Makefile.am
+++ b/src/consensus/Makefile.am
@@ -18,8 +18,6 @@ if USE_COVERAGE
18 AM_CFLAGS = -fprofile-arcs -ftest-coverage 18 AM_CFLAGS = -fprofile-arcs -ftest-coverage
19endif 19endif
20 20
21bin_PROGRAMS = \
22 gnunet-consensus-profiler
23 21
24libexec_PROGRAMS = \ 22libexec_PROGRAMS = \
25 gnunet-service-consensus 23 gnunet-service-consensus
@@ -86,6 +84,9 @@ libgnunet_plugin_block_consensus_la_LDFLAGS = \
86 84
87 85
88if HAVE_TESTING 86if HAVE_TESTING
87bin_PROGRAMS = \
88 gnunet-consensus-profiler
89
89check_PROGRAMS = \ 90check_PROGRAMS = \
90 test_consensus_api 91 test_consensus_api
91 92
diff --git a/src/consensus/consensus_protocol.h b/src/consensus/consensus_protocol.h
index e0002de56..f2933ed6f 100644
--- a/src/consensus/consensus_protocol.h
+++ b/src/consensus/consensus_protocol.h
@@ -45,37 +45,37 @@ GNUNET_NETWORK_STRUCT_BEGIN
45struct GNUNET_CONSENSUS_RoundContextMessage 45struct GNUNET_CONSENSUS_RoundContextMessage
46{ 46{
47 /** 47 /**
48 * Type: GNUNET_MESSAGE_TYPE_CONSENSUS_P2P_ROUND_CONTEXT 48 * Type: #GNUNET_MESSAGE_TYPE_CONSENSUS_P2P_ROUND_CONTEXT
49 */ 49 */
50 struct GNUNET_MessageHeader header; 50 struct GNUNET_MessageHeader header;
51 51
52 /** 52 /**
53 * A value from 'enum PhaseKind'. 53 * A value from 'enum PhaseKind'.
54 */ 54 */
55 uint16_t kind; 55 uint16_t kind GNUNET_PACKED;
56 56
57 /** 57 /**
58 * Number of the first peer 58 * Number of the first peer
59 * in canonical order. 59 * in canonical order.
60 */ 60 */
61 int16_t peer1; 61 int16_t peer1 GNUNET_PACKED;
62 62
63 /** 63 /**
64 * Number of the second peer in canonical order. 64 * Number of the second peer in canonical order.
65 */ 65 */
66 int16_t peer2; 66 int16_t peer2 GNUNET_PACKED;
67 67
68 /** 68 /**
69 * Repetition of the gradecast phase. 69 * Repetition of the gradecast phase.
70 */ 70 */
71 int16_t repetition; 71 int16_t repetition GNUNET_PACKED;
72 72
73 /** 73 /**
74 * Leader in the gradecast phase. 74 * Leader in the gradecast phase.
75 * 75 *
76 * Can be different from both peer1 and peer2. 76 * Can be different from both peer1 and peer2.
77 */ 77 */
78 int16_t leader; 78 int16_t leader GNUNET_PACKED;
79 79
80 /** 80 /**
81 * Non-zero if this set reconciliation 81 * Non-zero if this set reconciliation
@@ -85,7 +85,7 @@ struct GNUNET_CONSENSUS_RoundContextMessage
85 * 85 *
86 * Ignored for set operations that are not within gradecasts. 86 * Ignored for set operations that are not within gradecasts.
87 */ 87 */
88 uint16_t is_contested; 88 uint16_t is_contested GNUNET_PACKED;
89}; 89};
90 90
91 91
@@ -104,7 +104,7 @@ struct ConsensusElement
104 * Payload element_type, only valid 104 * Payload element_type, only valid
105 * if this is not a marker element. 105 * if this is not a marker element.
106 */ 106 */
107 uint16_t payload_type; 107 uint16_t payload_type GNUNET_PACKED;
108 108
109 /** 109 /**
110 * Is this a marker element? 110 * Is this a marker element?
@@ -117,7 +117,7 @@ struct ConsensusElement
117 117
118struct ConsensusSizeElement 118struct ConsensusSizeElement
119{ 119{
120 struct ConsensusElement ce GNUNET_PACKED; 120 struct ConsensusElement ce;
121 121
122 uint64_t size GNUNET_PACKED; 122 uint64_t size GNUNET_PACKED;
123 uint8_t sender_index; 123 uint8_t sender_index;
@@ -125,7 +125,7 @@ struct ConsensusSizeElement
125 125
126struct ConsensusStuffedElement 126struct ConsensusStuffedElement
127{ 127{
128 struct ConsensusElement ce GNUNET_PACKED; 128 struct ConsensusElement ce;
129 struct GNUNET_HashCode rand GNUNET_PACKED; 129 struct GNUNET_HashCode rand GNUNET_PACKED;
130}; 130};
131 131
diff --git a/src/consensus/gnunet-consensus-profiler.c b/src/consensus/gnunet-consensus-profiler.c
index 65542f4cd..8cc1b3512 100644
--- a/src/consensus/gnunet-consensus-profiler.c
+++ b/src/consensus/gnunet-consensus-profiler.c
@@ -515,31 +515,55 @@ run (void *cls, char *const *args, const char *cfgfile,
515int 515int
516main (int argc, char **argv) 516main (int argc, char **argv)
517{ 517{
518 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 518 struct GNUNET_GETOPT_CommandLineOption options[] = {
519 { 'n', "num-peers", NULL, 519
520 gettext_noop ("number of peers in consensus"), 520 GNUNET_GETOPT_OPTION_SET_UINT ('n',
521 GNUNET_YES, &GNUNET_GETOPT_set_uint, &num_peers }, 521 "num-peers",
522 { 'k', "value-replication", NULL, 522 NULL,
523 gettext_noop ("how many peers (random selection without replacement) receive one value?"), 523 gettext_noop ("number of peers in consensus"),
524 GNUNET_YES, &GNUNET_GETOPT_set_uint, &replication }, 524 &num_peers),
525 { 'x', "num-values", NULL, 525
526 gettext_noop ("number of values"), 526 GNUNET_GETOPT_OPTION_SET_UINT ('k',
527 GNUNET_YES, &GNUNET_GETOPT_set_uint, &num_values }, 527 "value-replication",
528 { 't', "timeout", NULL, 528 NULL,
529 gettext_noop ("consensus timeout"), 529 gettext_noop ("how many peers (random selection without replacement) receive one value?"),
530 GNUNET_YES, &GNUNET_GETOPT_set_relative_time, &conclude_timeout }, 530 &replication),
531 { 'd', "delay", NULL, 531
532 gettext_noop ("delay until consensus starts"), 532 GNUNET_GETOPT_OPTION_SET_UINT ('x',
533 GNUNET_YES, &GNUNET_GETOPT_set_relative_time, &consensus_delay }, 533 "num-values",
534 { 's', "statistics", NULL, 534 NULL,
535 gettext_noop ("write statistics to file"), 535 gettext_noop ("number of values"),
536 GNUNET_YES, &GNUNET_GETOPT_set_filename, &statistics_filename }, 536 &num_values),
537 { 'S', "dist-static", NULL, 537
538 gettext_noop ("distribute elements to a static subset of good peers"), 538 GNUNET_GETOPT_OPTION_SET_RELATIVE_TIME ('t',
539 GNUNET_YES, &GNUNET_GETOPT_set_one, &dist_static }, 539 "timeout",
540 { 'V', "verbose", NULL, 540 NULL,
541 gettext_noop ("be more verbose (print received values)"), 541 gettext_noop ("consensus timeout"),
542 GNUNET_NO, &GNUNET_GETOPT_set_one, &verbose }, 542 &conclude_timeout),
543
544
545 GNUNET_GETOPT_OPTION_SET_RELATIVE_TIME ('d',
546 "delay",
547 NULL,
548 gettext_noop ("delay until consensus starts"),
549 &consensus_delay),
550
551 GNUNET_GETOPT_OPTION_FILENAME ('s',
552 "statistics",
553 "FILENAME",
554 gettext_noop ("write statistics to file"),
555 &statistics_filename),
556
557 GNUNET_GETOPT_OPTION_SET_ONE ('S',
558 "dist-static",
559 gettext_noop ("distribute elements to a static subset of good peers"),
560 &dist_static),
561
562 GNUNET_GETOPT_OPTION_SET_ONE ('V',
563 "verbose",
564 gettext_noop ("be more verbose (print received values)"),
565 &verbose),
566
543 GNUNET_GETOPT_OPTION_END 567 GNUNET_GETOPT_OPTION_END
544 }; 568 };
545 conclude_timeout = GNUNET_TIME_UNIT_SECONDS; 569 conclude_timeout = GNUNET_TIME_UNIT_SECONDS;
diff --git a/src/consensus/gnunet-service-consensus.c b/src/consensus/gnunet-service-consensus.c
index b934f468f..4af7199aa 100644
--- a/src/consensus/gnunet-service-consensus.c
+++ b/src/consensus/gnunet-service-consensus.c
@@ -393,6 +393,14 @@ struct DiffEntry
393 struct GNUNET_CONTAINER_MultiHashMap *changes; 393 struct GNUNET_CONTAINER_MultiHashMap *changes;
394}; 394};
395 395
396struct SetHandle
397{
398 struct SetHandle *prev;
399 struct SetHandle *next;
400
401 struct GNUNET_SET_Handle *h;
402};
403
396 404
397 405
398/** 406/**
@@ -499,6 +507,9 @@ struct ConsensusSession
499 * Bounded Eppstein lower bound. 507 * Bounded Eppstein lower bound.
500 */ 508 */
501 uint64_t lower_bound; 509 uint64_t lower_bound;
510
511 struct SetHandle *set_handles_head;
512 struct SetHandle *set_handles_tail;
502}; 513};
503 514
504/** 515/**
@@ -894,7 +905,7 @@ cmp_uint64_t (const void *pa, const void *pb)
894 * in the result set. 905 * in the result set.
895 * 906 *
896 * @param cls closure 907 * @param cls closure
897 * @param element a result element, only valid if status is GNUNET_SET_STATUS_OK 908 * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
898 * @param current_size current set size 909 * @param current_size current set size
899 * @param status see enum GNUNET_SET_Status 910 * @param status see enum GNUNET_SET_Status
900 */ 911 */
@@ -1011,6 +1022,7 @@ set_result_cb (void *cls,
1011 "P%u: lower bound %llu\n", 1022 "P%u: lower bound %llu\n",
1012 session->local_peer_idx, 1023 session->local_peer_idx,
1013 (long long) session->lower_bound); 1024 (long long) session->lower_bound);
1025 GNUNET_free (copy);
1014 } 1026 }
1015 return; 1027 return;
1016 } 1028 }
@@ -1329,7 +1341,10 @@ commit_set (struct ConsensusSession *session,
1329 if (PHASE_KIND_ALL_TO_ALL_2 == task->key.kind) 1341 if (PHASE_KIND_ALL_TO_ALL_2 == task->key.kind)
1330 { 1342 {
1331 struct GNUNET_SET_Element element; 1343 struct GNUNET_SET_Element element;
1332 struct ConsensusSizeElement cse = { 0 }; 1344 struct ConsensusSizeElement cse = {
1345 .size = 0,
1346 .sender_index = 0
1347 };
1333 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "inserting size marker\n"); 1348 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "inserting size marker\n");
1334 cse.ce.marker = CONSENSUS_MARKER_SIZE; 1349 cse.ce.marker = CONSENSUS_MARKER_SIZE;
1335 cse.size = GNUNET_htonll (session->first_size); 1350 cse.size = GNUNET_htonll (session->first_size);
@@ -1382,7 +1397,10 @@ commit_set (struct ConsensusSession *session,
1382 for (i = 0; i < evil.num; i++) 1397 for (i = 0; i < evil.num; i++)
1383 { 1398 {
1384 struct GNUNET_SET_Element element; 1399 struct GNUNET_SET_Element element;
1385 struct ConsensusStuffedElement se = { 0 }; 1400 struct ConsensusStuffedElement se = {
1401 .ce.payload_type = 0,
1402 .ce.marker = 0,
1403 };
1386 element.data = &se; 1404 element.data = &se;
1387 element.size = sizeof (struct ConsensusStuffedElement); 1405 element.size = sizeof (struct ConsensusStuffedElement);
1388 element.element_type = GNUNET_BLOCK_TYPE_CONSENSUS_ELEMENT; 1406 element.element_type = GNUNET_BLOCK_TYPE_CONSENSUS_ELEMENT;
@@ -1663,6 +1681,12 @@ set_copy_cb (void *cls, struct GNUNET_SET_Handle *copy)
1663 struct TaskEntry *task = scc->task; 1681 struct TaskEntry *task = scc->task;
1664 struct SetKey dst_set_key = scc->dst_set_key; 1682 struct SetKey dst_set_key = scc->dst_set_key;
1665 struct SetEntry *set; 1683 struct SetEntry *set;
1684 struct SetHandle *sh = GNUNET_new (struct SetHandle);
1685
1686 sh->h = copy;
1687 GNUNET_CONTAINER_DLL_insert (task->step->session->set_handles_head,
1688 task->step->session->set_handles_tail,
1689 sh);
1666 1690
1667 GNUNET_free (scc); 1691 GNUNET_free (scc);
1668 set = GNUNET_new (struct SetEntry); 1692 set = GNUNET_new (struct SetEntry);
@@ -2105,7 +2129,7 @@ task_start_reconcile (struct TaskEntry *task)
2105 2129
2106 if (task->key.peer1 == session->local_peer_idx) 2130 if (task->key.peer1 == session->local_peer_idx)
2107 { 2131 {
2108 struct GNUNET_CONSENSUS_RoundContextMessage rcm = { 0 }; 2132 struct GNUNET_CONSENSUS_RoundContextMessage rcm;
2109 2133
2110 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 2134 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2111 "P%u: Looking up set {%s} to run remote union\n", 2135 "P%u: Looking up set {%s} to run remote union\n",
@@ -2120,6 +2144,7 @@ task_start_reconcile (struct TaskEntry *task)
2120 rcm.peer2 = htons (task->key.peer2); 2144 rcm.peer2 = htons (task->key.peer2);
2121 rcm.leader = htons (task->key.leader); 2145 rcm.leader = htons (task->key.leader);
2122 rcm.repetition = htons (task->key.repetition); 2146 rcm.repetition = htons (task->key.repetition);
2147 rcm.is_contested = htons (0);
2123 2148
2124 GNUNET_assert (NULL == setop->op); 2149 GNUNET_assert (NULL == setop->op);
2125 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: initiating set op with P%u, our set is %s\n", 2150 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: initiating set op with P%u, our set is %s\n",
@@ -3152,6 +3177,11 @@ handle_client_join (void *cls,
3152 client_set = GNUNET_new (struct SetEntry); 3177 client_set = GNUNET_new (struct SetEntry);
3153 client_set->h = GNUNET_SET_create (cfg, 3178 client_set->h = GNUNET_SET_create (cfg,
3154 GNUNET_SET_OPERATION_UNION); 3179 GNUNET_SET_OPERATION_UNION);
3180 struct SetHandle *sh = GNUNET_new (struct SetHandle);
3181 sh->h = client_set->h;
3182 GNUNET_CONTAINER_DLL_insert (session->set_handles_head,
3183 session->set_handles_tail,
3184 sh);
3155 client_set->key = ((struct SetKey) { SET_KIND_CURRENT, 0, 0 }); 3185 client_set->key = ((struct SetKey) { SET_KIND_CURRENT, 0, 0 });
3156 put_set (session, 3186 put_set (session,
3157 client_set); 3187 client_set);
@@ -3370,6 +3400,14 @@ client_disconnect_cb (void *cls,
3370 GNUNET_CONTAINER_DLL_remove (sessions_head, 3400 GNUNET_CONTAINER_DLL_remove (sessions_head,
3371 sessions_tail, 3401 sessions_tail,
3372 session); 3402 session);
3403
3404 while (session->set_handles_head)
3405 {
3406 struct SetHandle *sh = session->set_handles_head;
3407 session->set_handles_head = sh->next;
3408 GNUNET_SET_destroy (sh->h);
3409 GNUNET_free (sh);
3410 }
3373 GNUNET_free (session); 3411 GNUNET_free (session);
3374} 3412}
3375 3413
diff --git a/src/consensus/test_consensus.conf b/src/consensus/test_consensus.conf
index f78b77d09..881251a66 100644
--- a/src/consensus/test_consensus.conf
+++ b/src/consensus/test_consensus.conf
@@ -5,7 +5,7 @@ GNUNET_TEST_HOME = /tmp/test-consensus/
5#OPTIONS = -L INFO 5#OPTIONS = -L INFO
6BINARY = gnunet-service-evil-consensus 6BINARY = gnunet-service-evil-consensus
7 7
8#PREFIX = valgrind 8PREFIX = valgrind
9 9
10#EVIL_SPEC = 0;cram-all;noreplace;5 10#EVIL_SPEC = 0;cram-all;noreplace;5
11#EVIL_SPEC = 0;cram;5/1;cram;5 11#EVIL_SPEC = 0;cram;5/1;cram;5
diff --git a/src/conversation/Makefile.am b/src/conversation/Makefile.am
index 83313e7f8..cc2938144 100644
--- a/src/conversation/Makefile.am
+++ b/src/conversation/Makefile.am
@@ -180,7 +180,7 @@ gnunet_service_conversation_LDADD = \
180 libgnunetconversation.la \ 180 libgnunetconversation.la \
181 libgnunetspeaker.la \ 181 libgnunetspeaker.la \
182 libgnunetmicrophone.la \ 182 libgnunetmicrophone.la \
183 $(top_builddir)/src/cadet/libgnunetcadetnew.la \ 183 $(top_builddir)/src/cadet/libgnunetcadet.la \
184 $(top_builddir)/src/util/libgnunetutil.la \ 184 $(top_builddir)/src/util/libgnunetutil.la \
185 $(INTLLIBS) 185 $(INTLLIBS)
186gnunet_service_conversation_LDFLAGS = \ 186gnunet_service_conversation_LDFLAGS = \
diff --git a/src/conversation/gnunet-conversation.c b/src/conversation/gnunet-conversation.c
index 925db4665..c5275c0de 100644
--- a/src/conversation/gnunet-conversation.c
+++ b/src/conversation/gnunet-conversation.c
@@ -1265,13 +1265,20 @@ run (void *cls,
1265int 1265int
1266main (int argc, char *const *argv) 1266main (int argc, char *const *argv)
1267{ 1267{
1268 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 1268 struct GNUNET_GETOPT_CommandLineOption options[] = {
1269 {'e', "ego", "NAME", 1269
1270 gettext_noop ("sets the NAME of the ego to use for the phone (and name resolution)"), 1270 GNUNET_GETOPT_OPTION_STRING ('e',
1271 1, &GNUNET_GETOPT_set_string, &ego_name}, 1271 "ego",
1272 {'p', "phone", "LINE", 1272 "NAME",
1273 gettext_noop ("sets the LINE to use for the phone"), 1273 gettext_noop ("sets the NAME of the ego to use for the phone (and name resolution)"),
1274 1, &GNUNET_GETOPT_set_string, &line}, 1274 &ego_name),
1275
1276 GNUNET_GETOPT_OPTION_STRING ('p',
1277 "phone",
1278 "LINE",
1279 gettext_noop ("sets the LINE to use for the phone"),
1280 &line),
1281
1275 GNUNET_GETOPT_OPTION_END 1282 GNUNET_GETOPT_OPTION_END
1276 }; 1283 };
1277 int ret; 1284 int ret;
diff --git a/src/conversation/gnunet-helper-audio-playback.c b/src/conversation/gnunet-helper-audio-playback.c
index e965cb2aa..4344e1d41 100644
--- a/src/conversation/gnunet-helper-audio-playback.c
+++ b/src/conversation/gnunet-helper-audio-playback.c
@@ -549,7 +549,6 @@ ogg_demux_and_decode ()
549 */ 549 */
550static int 550static int
551stdin_receiver (void *cls, 551stdin_receiver (void *cls,
552 void *client,
553 const struct GNUNET_MessageHeader *msg) 552 const struct GNUNET_MessageHeader *msg)
554{ 553{
555 struct AudioMessage *audio; 554 struct AudioMessage *audio;
@@ -727,12 +726,14 @@ ogg_init ()
727 ogg_sync_init (&oy); 726 ogg_sync_init (&oy);
728} 727}
729 728
729
730static void 730static void
731drain_callback (pa_stream*s, int success, void *userdata) 731drain_callback (pa_stream*s, int success, void *userdata)
732{ 732{
733 pa_threaded_mainloop_signal (m, 0); 733 pa_threaded_mainloop_signal (m, 0);
734} 734}
735 735
736
736/** 737/**
737 * The main function for the playback helper. 738 * The main function for the playback helper.
738 * 739 *
@@ -746,7 +747,7 @@ main (int argc, char *argv[])
746 static unsigned long long toff; 747 static unsigned long long toff;
747 748
748 char readbuf[MAXLINE]; 749 char readbuf[MAXLINE];
749 struct GNUNET_SERVER_MessageStreamTokenizer *stdin_mst; 750 struct GNUNET_MessageStreamTokenizer *stdin_mst;
750 char c; 751 char c;
751 ssize_t ret; 752 ssize_t ret;
752#ifdef DEBUG_READ_PURE_OGG 753#ifdef DEBUG_READ_PURE_OGG
@@ -762,7 +763,7 @@ main (int argc, char *argv[])
762 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "pipe"); 763 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "pipe");
763 return 1; 764 return 1;
764 } 765 }
765 stdin_mst = GNUNET_SERVER_mst_create (&stdin_receiver, NULL); 766 stdin_mst = GNUNET_MST_create (&stdin_receiver, NULL);
766 ogg_init (); 767 ogg_init ();
767 pa_init (); 768 pa_init ();
768 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 769 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -802,11 +803,11 @@ main (int argc, char *argv[])
802 } 803 }
803 else 804 else
804#endif 805#endif
805 GNUNET_SERVER_mst_receive (stdin_mst, NULL, 806 GNUNET_MST_from_buffer (stdin_mst,
806 readbuf, ret, 807 readbuf, ret,
807 GNUNET_NO, GNUNET_NO); 808 GNUNET_NO, GNUNET_NO);
808 } 809 }
809 GNUNET_SERVER_mst_destroy (stdin_mst); 810 GNUNET_MST_destroy (stdin_mst);
810 if (stream_out) 811 if (stream_out)
811 { 812 {
812 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 813 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
diff --git a/src/conversation/gnunet-service-conversation.c b/src/conversation/gnunet-service-conversation.c
index f80cc1d11..5f43bfe80 100644
--- a/src/conversation/gnunet-service-conversation.c
+++ b/src/conversation/gnunet-service-conversation.c
@@ -779,7 +779,6 @@ handle_cadet_hangup_message (void *cls,
779 { 779 {
780 case CS_CALLEE_INIT: 780 case CS_CALLEE_INIT:
781 GNUNET_break_op (0); 781 GNUNET_break_op (0);
782 destroy_line_cadet_channels (ch);
783 return; 782 return;
784 case CS_CALLEE_RINGING: 783 case CS_CALLEE_RINGING:
785 case CS_CALLEE_CONNECTED: 784 case CS_CALLEE_CONNECTED:
@@ -1110,7 +1109,7 @@ handle_client_call_message (void *cls,
1110 line->channel_tail, 1109 line->channel_tail,
1111 ch); 1110 ch);
1112 ch->status = CS_CALLER_CALLING; 1111 ch->status = CS_CALLER_CALLING;
1113 ch->channel = GNUNET_CADET_channel_creatE (cadet, 1112 ch->channel = GNUNET_CADET_channel_create (cadet,
1114 ch, 1113 ch,
1115 &msg->target, 1114 &msg->target,
1116 &msg->line_port, 1115 &msg->line_port,
@@ -1264,7 +1263,7 @@ handle_client_register_message (void *cls,
1264 }; 1263 };
1265 1264
1266 line->line_port = msg->line_port; 1265 line->line_port = msg->line_port;
1267 line->port = GNUNET_CADET_open_porT (cadet, 1266 line->port = GNUNET_CADET_open_port (cadet,
1268 &msg->line_port, 1267 &msg->line_port,
1269 &inbound_channel, 1268 &inbound_channel,
1270 line, 1269 line,
@@ -1307,7 +1306,7 @@ run (void *cls,
1307 GNUNET_assert (GNUNET_OK == 1306 GNUNET_assert (GNUNET_OK ==
1308 GNUNET_CRYPTO_get_peer_identity (cfg, 1307 GNUNET_CRYPTO_get_peer_identity (cfg,
1309 &my_identity)); 1308 &my_identity));
1310 cadet = GNUNET_CADET_connecT (cfg); 1309 cadet = GNUNET_CADET_connect (cfg);
1311 if (NULL == cadet) 1310 if (NULL == cadet)
1312 { 1311 {
1313 GNUNET_break (0); 1312 GNUNET_break (0);
diff --git a/src/conversation/microphone.c b/src/conversation/microphone.c
index 94f52f8dc..7871433a3 100644
--- a/src/conversation/microphone.c
+++ b/src/conversation/microphone.c
@@ -64,13 +64,11 @@ struct Microphone
64 * Function to process the audio from the record helper 64 * Function to process the audio from the record helper
65 * 65 *
66 * @param cls clsoure with our `struct Microphone` 66 * @param cls clsoure with our `struct Microphone`
67 * @param client NULL
68 * @param msg the message from the helper 67 * @param msg the message from the helper
69 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error 68 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
70 */ 69 */
71static int 70static int
72process_record_messages (void *cls, 71process_record_messages (void *cls,
73 void *client,
74 const struct GNUNET_MessageHeader *msg) 72 const struct GNUNET_MessageHeader *msg)
75{ 73{
76 struct Microphone *mic = cls; 74 struct Microphone *mic = cls;
diff --git a/src/core/core_api.c b/src/core/core_api.c
index fd789295d..ed8ce364d 100644
--- a/src/core/core_api.c
+++ b/src/core/core_api.c
@@ -321,7 +321,7 @@ core_mq_send_impl (struct GNUNET_MQ_Handle *mq,
321 321
322 /* check message size for sanity */ 322 /* check message size for sanity */
323 msize = ntohs (msg->size); 323 msize = ntohs (msg->size);
324 if (msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct SendMessage)) 324 if (msize >= GNUNET_MAX_MESSAGE_SIZE - sizeof (struct SendMessage))
325 { 325 {
326 GNUNET_break (0); 326 GNUNET_break (0);
327 GNUNET_MQ_impl_send_continue (mq); 327 GNUNET_MQ_impl_send_continue (mq);
@@ -796,7 +796,7 @@ GNUNET_CORE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
796 h->handlers = GNUNET_MQ_copy_handlers (handlers); 796 h->handlers = GNUNET_MQ_copy_handlers (handlers);
797 h->hcnt = GNUNET_MQ_count_handlers (handlers); 797 h->hcnt = GNUNET_MQ_count_handlers (handlers);
798 GNUNET_assert (h->hcnt < 798 GNUNET_assert (h->hcnt <
799 (GNUNET_SERVER_MAX_MESSAGE_SIZE - 799 (GNUNET_MAX_MESSAGE_SIZE -
800 sizeof (struct InitMessage)) / sizeof (uint16_t)); 800 sizeof (struct InitMessage)) / sizeof (uint16_t));
801 LOG (GNUNET_ERROR_TYPE_DEBUG, 801 LOG (GNUNET_ERROR_TYPE_DEBUG,
802 "Connecting to CORE service\n"); 802 "Connecting to CORE service\n");
diff --git a/src/core/gnunet-core.c b/src/core/gnunet-core.c
index d91dc304d..ed89b1946 100644
--- a/src/core/gnunet-core.c
+++ b/src/core/gnunet-core.c
@@ -171,10 +171,11 @@ main (int argc,
171 char *const *argv) 171 char *const *argv)
172{ 172{
173 int res; 173 int res;
174 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 174 struct GNUNET_GETOPT_CommandLineOption options[] = {
175 {'m', "monitor", NULL, 175 GNUNET_GETOPT_OPTION_SET_ONE ('m',
176 gettext_noop ("provide information about all current connections (continuously)"), 176 "monitor",
177 0, &GNUNET_GETOPT_set_one, &monitor_connections}, 177 gettext_noop ("provide information about all current connections (continuously)"),
178 &monitor_connections),
178 GNUNET_GETOPT_OPTION_END 179 GNUNET_GETOPT_OPTION_END
179 }; 180 };
180 181
diff --git a/src/core/gnunet-service-core.c b/src/core/gnunet-service-core.c
index 31b91f12f..625bf9655 100644
--- a/src/core/gnunet-service-core.c
+++ b/src/core/gnunet-service-core.c
@@ -807,7 +807,7 @@ GSC_CLIENTS_deliver_message (const struct GNUNET_PeerIdentity *sender,
807{ 807{
808 size_t size = msize + sizeof (struct NotifyTrafficMessage); 808 size_t size = msize + sizeof (struct NotifyTrafficMessage);
809 809
810 if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE) 810 if (size >= GNUNET_MAX_MESSAGE_SIZE)
811 { 811 {
812 GNUNET_break (0); 812 GNUNET_break (0);
813 return; 813 return;
diff --git a/src/core/gnunet-service-core_kx.c b/src/core/gnunet-service-core_kx.c
index 906898512..8a7cada5c 100644
--- a/src/core/gnunet-service-core_kx.c
+++ b/src/core/gnunet-service-core_kx.c
@@ -263,6 +263,11 @@ struct GSC_KeyExchangeInfo
263 struct GNUNET_MQ_Handle *mq; 263 struct GNUNET_MQ_Handle *mq;
264 264
265 /** 265 /**
266 * Our message stream tokenizer (for encrypted payload).
267 */
268 struct GNUNET_MessageStreamTokenizer *mst;
269
270 /**
266 * PING message we transmit to the other peer. 271 * PING message we transmit to the other peer.
267 */ 272 */
268 struct PingMessage ping; 273 struct PingMessage ping;
@@ -370,11 +375,6 @@ static struct GNUNET_CRYPTO_EcdhePrivateKey *my_ephemeral_key;
370static struct EphemeralKeyMessage current_ekm; 375static struct EphemeralKeyMessage current_ekm;
371 376
372/** 377/**
373 * Our message stream tokenizer (for encrypted payload).
374 */
375static struct GNUNET_SERVER_MessageStreamTokenizer *mst;
376
377/**
378 * DLL head. 378 * DLL head.
379 */ 379 */
380static struct GSC_KeyExchangeInfo *kx_head; 380static struct GSC_KeyExchangeInfo *kx_head;
@@ -702,6 +702,55 @@ setup_fresh_ping (struct GSC_KeyExchangeInfo *kx)
702 702
703 703
704/** 704/**
705 * Deliver P2P message to interested clients. Invokes send twice,
706 * once for clients that want the full message, and once for clients
707 * that only want the header
708 *
709 * @param cls the `struct GSC_KeyExchangeInfo`
710 * @param m the message
711 */
712static int
713deliver_message (void *cls,
714 const struct GNUNET_MessageHeader *m)
715{
716 struct GSC_KeyExchangeInfo *kx = cls;
717
718 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
719 "Decrypted message of type %d from %s\n",
720 ntohs (m->type),
721 GNUNET_i2s (kx->peer));
722 if (GNUNET_CORE_KX_STATE_UP != kx->status)
723 {
724 GNUNET_STATISTICS_update (GSC_stats,
725 gettext_noop ("# PAYLOAD dropped (out of order)"),
726 1,
727 GNUNET_NO);
728 return GNUNET_OK;
729 }
730 switch (ntohs (m->type))
731 {
732 case GNUNET_MESSAGE_TYPE_CORE_BINARY_TYPE_MAP:
733 case GNUNET_MESSAGE_TYPE_CORE_COMPRESSED_TYPE_MAP:
734 GSC_SESSIONS_set_typemap (kx->peer, m);
735 return GNUNET_OK;
736 case GNUNET_MESSAGE_TYPE_CORE_CONFIRM_TYPE_MAP:
737 GSC_SESSIONS_confirm_typemap (kx->peer, m);
738 return GNUNET_OK;
739 default:
740 GSC_CLIENTS_deliver_message (kx->peer,
741 m,
742 ntohs (m->size),
743 GNUNET_CORE_OPTION_SEND_FULL_INBOUND);
744 GSC_CLIENTS_deliver_message (kx->peer,
745 m,
746 sizeof (struct GNUNET_MessageHeader),
747 GNUNET_CORE_OPTION_SEND_HDR_INBOUND);
748 }
749 return GNUNET_OK;
750}
751
752
753/**
705 * Function called by transport to notify us that 754 * Function called by transport to notify us that
706 * a peer connected to us (on the network level). 755 * a peer connected to us (on the network level).
707 * Starts the key exchange with the given peer. 756 * Starts the key exchange with the given peer.
@@ -727,6 +776,8 @@ handle_transport_notify_connect (void *cls,
727 1, 776 1,
728 GNUNET_NO); 777 GNUNET_NO);
729 kx = GNUNET_new (struct GSC_KeyExchangeInfo); 778 kx = GNUNET_new (struct GSC_KeyExchangeInfo);
779 kx->mst = GNUNET_MST_create (&deliver_message,
780 kx);
730 kx->mq = mq; 781 kx->mq = mq;
731 kx->peer = pid; 782 kx->peer = pid;
732 kx->set_key_retry_frequency = INITIAL_SET_KEY_RETRY_FREQUENCY; 783 kx->set_key_retry_frequency = INITIAL_SET_KEY_RETRY_FREQUENCY;
@@ -801,6 +852,7 @@ handle_transport_notify_disconnect (void *cls,
801 GNUNET_CONTAINER_DLL_remove (kx_head, 852 GNUNET_CONTAINER_DLL_remove (kx_head,
802 kx_tail, 853 kx_tail,
803 kx); 854 kx);
855 GNUNET_MST_destroy (kx->mst);
804 GNUNET_free (kx); 856 GNUNET_free (kx);
805} 857}
806 858
@@ -1417,24 +1469,6 @@ GSC_KX_encrypt_and_transmit (struct GSC_KeyExchangeInfo *kx,
1417 1469
1418 1470
1419/** 1471/**
1420 * Closure for #deliver_message()
1421 */
1422struct DeliverMessageContext
1423{
1424
1425 /**
1426 * Key exchange context.
1427 */
1428 struct GSC_KeyExchangeInfo *kx;
1429
1430 /**
1431 * Sender of the message.
1432 */
1433 const struct GNUNET_PeerIdentity *peer;
1434};
1435
1436
1437/**
1438 * We received an encrypted message. Check that it is 1472 * We received an encrypted message. Check that it is
1439 * well-formed (size-wise). 1473 * well-formed (size-wise).
1440 * 1474 *
@@ -1475,7 +1509,6 @@ handle_encrypted (void *cls,
1475 struct GNUNET_TIME_Absolute t; 1509 struct GNUNET_TIME_Absolute t;
1476 struct GNUNET_CRYPTO_SymmetricInitializationVector iv; 1510 struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
1477 struct GNUNET_CRYPTO_AuthKey auth_key; 1511 struct GNUNET_CRYPTO_AuthKey auth_key;
1478 struct DeliverMessageContext dmc;
1479 uint16_t size = ntohs (m->header.size); 1512 uint16_t size = ntohs (m->header.size);
1480 char buf[size] GNUNET_ALIGN; 1513 char buf[size] GNUNET_ALIGN;
1481 1514
@@ -1620,15 +1653,12 @@ handle_encrypted (void *cls,
1620 gettext_noop ("# bytes of payload decrypted"), 1653 gettext_noop ("# bytes of payload decrypted"),
1621 size - sizeof (struct EncryptedMessage), 1654 size - sizeof (struct EncryptedMessage),
1622 GNUNET_NO); 1655 GNUNET_NO);
1623 dmc.kx = kx;
1624 dmc.peer = kx->peer;
1625 if (GNUNET_OK != 1656 if (GNUNET_OK !=
1626 GNUNET_SERVER_mst_receive (mst, 1657 GNUNET_MST_from_buffer (kx->mst,
1627 &dmc, 1658 &buf[sizeof (struct EncryptedMessage)],
1628 &buf[sizeof (struct EncryptedMessage)], 1659 size - sizeof (struct EncryptedMessage),
1629 size - sizeof (struct EncryptedMessage), 1660 GNUNET_YES,
1630 GNUNET_YES, 1661 GNUNET_NO))
1631 GNUNET_NO))
1632 GNUNET_break_op (0); 1662 GNUNET_break_op (0);
1633} 1663}
1634 1664
@@ -1656,57 +1686,6 @@ handle_transport_notify_excess_bw (void *cls,
1656 1686
1657 1687
1658/** 1688/**
1659 * Deliver P2P message to interested clients. Invokes send twice,
1660 * once for clients that want the full message, and once for clients
1661 * that only want the header
1662 *
1663 * @param cls always NULL
1664 * @param client who sent us the message (struct GSC_KeyExchangeInfo)
1665 * @param m the message
1666 */
1667static int
1668deliver_message (void *cls,
1669 void *client,
1670 const struct GNUNET_MessageHeader *m)
1671{
1672 struct DeliverMessageContext *dmc = client;
1673
1674 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1675 "Decrypted message of type %d from %s\n",
1676 ntohs (m->type),
1677 GNUNET_i2s (dmc->peer));
1678 if (GNUNET_CORE_KX_STATE_UP != dmc->kx->status)
1679 {
1680 GNUNET_STATISTICS_update (GSC_stats,
1681 gettext_noop ("# PAYLOAD dropped (out of order)"),
1682 1,
1683 GNUNET_NO);
1684 return GNUNET_OK;
1685 }
1686 switch (ntohs (m->type))
1687 {
1688 case GNUNET_MESSAGE_TYPE_CORE_BINARY_TYPE_MAP:
1689 case GNUNET_MESSAGE_TYPE_CORE_COMPRESSED_TYPE_MAP:
1690 GSC_SESSIONS_set_typemap (dmc->peer, m);
1691 return GNUNET_OK;
1692 case GNUNET_MESSAGE_TYPE_CORE_CONFIRM_TYPE_MAP:
1693 GSC_SESSIONS_confirm_typemap (dmc->peer, m);
1694 return GNUNET_OK;
1695 default:
1696 GSC_CLIENTS_deliver_message (dmc->peer,
1697 m,
1698 ntohs (m->size),
1699 GNUNET_CORE_OPTION_SEND_FULL_INBOUND);
1700 GSC_CLIENTS_deliver_message (dmc->peer,
1701 m,
1702 sizeof (struct GNUNET_MessageHeader),
1703 GNUNET_CORE_OPTION_SEND_HDR_INBOUND);
1704 }
1705 return GNUNET_OK;
1706}
1707
1708
1709/**
1710 * Setup the message that links the ephemeral key to our persistent 1689 * Setup the message that links the ephemeral key to our persistent
1711 * public key and generate the appropriate signature. 1690 * public key and generate the appropriate signature.
1712 */ 1691 */
@@ -1829,8 +1808,6 @@ GSC_KX_init (struct GNUNET_CRYPTO_EddsaPrivateKey *pk)
1829 rekey_task = GNUNET_SCHEDULER_add_delayed (REKEY_FREQUENCY, 1808 rekey_task = GNUNET_SCHEDULER_add_delayed (REKEY_FREQUENCY,
1830 &do_rekey, 1809 &do_rekey,
1831 NULL); 1810 NULL);
1832 mst = GNUNET_SERVER_mst_create (&deliver_message,
1833 NULL);
1834 transport 1811 transport
1835 = GNUNET_TRANSPORT_core_connect (GSC_cfg, 1812 = GNUNET_TRANSPORT_core_connect (GSC_cfg,
1836 &GSC_my_identity, 1813 &GSC_my_identity,
@@ -1874,11 +1851,6 @@ GSC_KX_done ()
1874 GNUNET_free (my_private_key); 1851 GNUNET_free (my_private_key);
1875 my_private_key = NULL; 1852 my_private_key = NULL;
1876 } 1853 }
1877 if (NULL != mst)
1878 {
1879 GNUNET_SERVER_mst_destroy (mst);
1880 mst = NULL;
1881 }
1882 if (NULL != nc) 1854 if (NULL != nc)
1883 { 1855 {
1884 GNUNET_notification_context_destroy (nc); 1856 GNUNET_notification_context_destroy (nc);
diff --git a/src/datacache/Makefile.am b/src/datacache/Makefile.am
index 431b3179e..670a64926 100644
--- a/src/datacache/Makefile.am
+++ b/src/datacache/Makefile.am
@@ -53,6 +53,7 @@ libgnunet_plugin_datacache_sqlite_la_SOURCES = \
53 plugin_datacache_sqlite.c 53 plugin_datacache_sqlite.c
54libgnunet_plugin_datacache_sqlite_la_LIBADD = \ 54libgnunet_plugin_datacache_sqlite_la_LIBADD = \
55 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 55 $(top_builddir)/src/statistics/libgnunetstatistics.la \
56 $(top_builddir)/src/sq/libgnunetsq.la \
56 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lsqlite3 \ 57 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lsqlite3 \
57 $(LTLIBINTL) 58 $(LTLIBINTL)
58libgnunet_plugin_datacache_sqlite_la_LDFLAGS = \ 59libgnunet_plugin_datacache_sqlite_la_LDFLAGS = \
diff --git a/src/datacache/plugin_datacache_sqlite.c b/src/datacache/plugin_datacache_sqlite.c
index 5567077d3..dd79d0125 100644
--- a/src/datacache/plugin_datacache_sqlite.c
+++ b/src/datacache/plugin_datacache_sqlite.c
@@ -26,6 +26,7 @@
26#include "platform.h" 26#include "platform.h"
27#include "gnunet_util_lib.h" 27#include "gnunet_util_lib.h"
28#include "gnunet_datacache_plugin.h" 28#include "gnunet_datacache_plugin.h"
29#include "gnunet_sq_lib.h"
29#include <sqlite3.h> 30#include <sqlite3.h>
30 31
31#define LOG(kind,...) GNUNET_log_from (kind, "datacache-sqlite", __VA_ARGS__) 32#define LOG(kind,...) GNUNET_log_from (kind, "datacache-sqlite", __VA_ARGS__)
@@ -60,6 +61,41 @@ struct Plugin
60 char *fn; 61 char *fn;
61 62
62 /** 63 /**
64 * Prepared statement for #sqlite_plugin_put.
65 */
66 sqlite3_stmt *insert_stmt;
67
68 /**
69 * Prepared statement for #sqlite_plugin_get.
70 */
71 sqlite3_stmt *get_count_stmt;
72
73 /**
74 * Prepared statement for #sqlite_plugin_get.
75 */
76 sqlite3_stmt *get_stmt;
77
78 /**
79 * Prepared statement for #sqlite_plugin_del.
80 */
81 sqlite3_stmt *del_select_stmt;
82
83 /**
84 * Prepared statement for #sqlite_plugin_del.
85 */
86 sqlite3_stmt *del_stmt;
87
88 /**
89 * Prepared statement for #sqlite_plugin_get_random.
90 */
91 sqlite3_stmt *get_random_stmt;
92
93 /**
94 * Prepared statement for #sqlite_plugin_get_closest.
95 */
96 sqlite3_stmt *get_closest_stmt;
97
98 /**
63 * Number of key-value pairs in the database. 99 * Number of key-value pairs in the database.
64 */ 100 */
65 unsigned int num_items; 101 unsigned int num_items;
@@ -132,60 +168,47 @@ sqlite_plugin_put (void *cls,
132 const struct GNUNET_PeerIdentity *path_info) 168 const struct GNUNET_PeerIdentity *path_info)
133{ 169{
134 struct Plugin *plugin = cls; 170 struct Plugin *plugin = cls;
135 sqlite3_stmt *stmt; 171 uint32_t type32 = type;
136 int64_t dval; 172 struct GNUNET_SQ_QueryParam params[] = {
173 GNUNET_SQ_query_param_uint32 (&type32),
174 GNUNET_SQ_query_param_absolute_time (&discard_time),
175 GNUNET_SQ_query_param_auto_from_type (key),
176 GNUNET_SQ_query_param_fixed_size (data, size),
177 GNUNET_SQ_query_param_fixed_size (path_info,
178 path_info_len * sizeof (struct GNUNET_PeerIdentity)),
179 GNUNET_SQ_query_param_end
180 };
137 181
138 LOG (GNUNET_ERROR_TYPE_DEBUG, 182 LOG (GNUNET_ERROR_TYPE_DEBUG,
139 "Processing PUT of %u bytes with key `%4s' and expiration %s\n", 183 "Processing PUT of %u bytes with key `%s' and expiration %s\n",
140 (unsigned int) size, 184 (unsigned int) size,
141 GNUNET_h2s (key), 185 GNUNET_h2s (key),
142 GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (discard_time), GNUNET_YES)); 186 GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (discard_time),
143 dval = (int64_t) discard_time.abs_value_us; 187 GNUNET_YES));
144 if (dval < 0) 188 if (GNUNET_OK !=
145 dval = INT64_MAX; 189 GNUNET_SQ_bind (plugin->insert_stmt,
146 if (sq_prepare 190 params))
147 (plugin->dbh,
148 "INSERT INTO ds090 (type, expire, key, value, path) VALUES (?, ?, ?, ?, ?)",
149 &stmt) != SQLITE_OK)
150 {
151 LOG_SQLITE (plugin->dbh,
152 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
153 "sq_prepare");
154 return -1;
155 }
156 if ((SQLITE_OK != sqlite3_bind_int (stmt, 1, type)) ||
157 (SQLITE_OK != sqlite3_bind_int64 (stmt, 2, dval)) ||
158 (SQLITE_OK !=
159 sqlite3_bind_blob (stmt, 3,
160 key, sizeof (struct GNUNET_HashCode),
161 SQLITE_TRANSIENT)) ||
162 (SQLITE_OK != sqlite3_bind_blob (stmt, 4,
163 data, size,
164 SQLITE_TRANSIENT)) ||
165 (SQLITE_OK != sqlite3_bind_blob (stmt, 5,
166 path_info,
167 path_info_len * sizeof (struct GNUNET_PeerIdentity),
168 SQLITE_TRANSIENT)))
169 { 191 {
170 LOG_SQLITE (plugin->dbh, 192 LOG_SQLITE (plugin->dbh,
171 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 193 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
172 "sqlite3_bind_xxx"); 194 "sqlite3_bind_xxx");
173 sqlite3_finalize (stmt); 195 GNUNET_SQ_reset (plugin->dbh,
196 plugin->insert_stmt);
174 return -1; 197 return -1;
175 } 198 }
176 if (SQLITE_DONE != sqlite3_step (stmt)) 199 if (SQLITE_DONE !=
200 sqlite3_step (plugin->insert_stmt))
177 { 201 {
178 LOG_SQLITE (plugin->dbh, 202 LOG_SQLITE (plugin->dbh,
179 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 203 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
180 "sqlite3_step"); 204 "sqlite3_step");
181 sqlite3_finalize (stmt); 205 GNUNET_SQ_reset (plugin->dbh,
206 plugin->insert_stmt);
182 return -1; 207 return -1;
183 } 208 }
184 plugin->num_items++; 209 plugin->num_items++;
185 if (SQLITE_OK != sqlite3_finalize (stmt)) 210 GNUNET_SQ_reset (plugin->dbh,
186 LOG_SQLITE (plugin->dbh, 211 plugin->insert_stmt);
187 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
188 "sqlite3_finalize");
189 return size + OVERHEAD; 212 return size + OVERHEAD;
190} 213}
191 214
@@ -209,120 +232,119 @@ sqlite_plugin_get (void *cls,
209 void *iter_cls) 232 void *iter_cls)
210{ 233{
211 struct Plugin *plugin = cls; 234 struct Plugin *plugin = cls;
212 sqlite3_stmt *stmt; 235 uint32_t type32 = type;
213 struct GNUNET_TIME_Absolute now; 236 struct GNUNET_TIME_Absolute now;
214 struct GNUNET_TIME_Absolute exp; 237 struct GNUNET_TIME_Absolute exp;
215 unsigned int size; 238 size_t size;
216 const char *dat; 239 void *dat;
217 unsigned int cnt; 240 unsigned int cnt;
218 unsigned int off; 241 uint32_t off;
219 unsigned int total; 242 unsigned int total;
220 unsigned int psize; 243 size_t psize;
221 char scratch[256]; 244 struct GNUNET_PeerIdentity *path;
222 int64_t ntime; 245 struct GNUNET_SQ_QueryParam params_count[] = {
223 const struct GNUNET_PeerIdentity *path; 246 GNUNET_SQ_query_param_auto_from_type (key),
247 GNUNET_SQ_query_param_uint32 (&type32),
248 GNUNET_SQ_query_param_absolute_time (&now),
249 GNUNET_SQ_query_param_end
250 };
251 struct GNUNET_SQ_QueryParam params_select[] = {
252 GNUNET_SQ_query_param_auto_from_type (key),
253 GNUNET_SQ_query_param_uint32 (&type32),
254 GNUNET_SQ_query_param_absolute_time (&now),
255 GNUNET_SQ_query_param_uint32 (&off),
256 GNUNET_SQ_query_param_end
257 };
258 struct GNUNET_SQ_ResultSpec rs[] = {
259 GNUNET_SQ_result_spec_variable_size (&dat,
260 &size),
261 GNUNET_SQ_result_spec_absolute_time (&exp),
262 GNUNET_SQ_result_spec_variable_size ((void **) &path,
263 &psize),
264 GNUNET_SQ_result_spec_end
265 };
224 266
225 now = GNUNET_TIME_absolute_get (); 267 now = GNUNET_TIME_absolute_get ();
226 LOG (GNUNET_ERROR_TYPE_DEBUG, 268 LOG (GNUNET_ERROR_TYPE_DEBUG,
227 "Processing GET for key `%4s'\n", 269 "Processing GET for key `%s'\n",
228 GNUNET_h2s (key)); 270 GNUNET_h2s (key));
229 if (sq_prepare 271
230 (plugin->dbh, 272 if (GNUNET_OK !=
231 "SELECT count(*) FROM ds090 WHERE key=? AND type=? AND expire >= ?", 273 GNUNET_SQ_bind (plugin->get_count_stmt,
232 &stmt) != SQLITE_OK) 274 params_count))
233 {
234 LOG_SQLITE (plugin->dbh,
235 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
236 "sq_prepare");
237 return 0;
238 }
239 ntime = (int64_t) now.abs_value_us;
240 GNUNET_assert (ntime >= 0);
241 if ((SQLITE_OK !=
242 sqlite3_bind_blob (stmt, 1, key, sizeof (struct GNUNET_HashCode),
243 SQLITE_TRANSIENT)) ||
244 (SQLITE_OK != sqlite3_bind_int (stmt, 2, type)) ||
245 (SQLITE_OK != sqlite3_bind_int64 (stmt, 3, now.abs_value_us)))
246 { 275 {
247 LOG_SQLITE (plugin->dbh, 276 LOG_SQLITE (plugin->dbh,
248 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 277 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
249 "sqlite3_bind_xxx"); 278 "sqlite3_bind_xxx");
250 sqlite3_finalize (stmt); 279 GNUNET_SQ_reset (plugin->dbh,
280 plugin->get_count_stmt);
251 return 0; 281 return 0;
252 } 282 }
253 283 if (SQLITE_ROW !=
254 if (SQLITE_ROW != sqlite3_step (stmt)) 284 sqlite3_step (plugin->get_count_stmt))
255 { 285 {
256 LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 286 LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
257 "sqlite_step"); 287 "sqlite_step");
258 sqlite3_finalize (stmt); 288 GNUNET_SQ_reset (plugin->dbh,
289 plugin->get_count_stmt);
259 LOG (GNUNET_ERROR_TYPE_DEBUG, 290 LOG (GNUNET_ERROR_TYPE_DEBUG,
260 "No content found when processing GET for key `%4s'\n", 291 "No content found when processing GET for key `%s'\n",
261 GNUNET_h2s (key)); 292 GNUNET_h2s (key));
262 return 0; 293 return 0;
263 } 294 }
264 total = sqlite3_column_int (stmt, 0); 295 total = sqlite3_column_int (plugin->get_count_stmt,
265 sqlite3_finalize (stmt); 296 0);
266 if ((0 == total) || (NULL == iter)) 297 GNUNET_SQ_reset (plugin->dbh,
298 plugin->get_count_stmt);
299 if ( (0 == total) ||
300 (NULL == iter) )
267 { 301 {
268 if (0 == total) 302 if (0 == total)
269 LOG (GNUNET_ERROR_TYPE_DEBUG, 303 LOG (GNUNET_ERROR_TYPE_DEBUG,
270 "No content found when processing GET for key `%4s'\n", 304 "No content found when processing GET for key `%s'\n",
271 GNUNET_h2s (key)); 305 GNUNET_h2s (key));
272 return total; 306 return total;
273 } 307 }
274 308
275 cnt = 0; 309 cnt = 0;
276 off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, total); 310 off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
311 total);
277 while (cnt < total) 312 while (cnt < total)
278 { 313 {
279 off = (off + 1) % total; 314 off = (off + 1) % total;
280 GNUNET_snprintf (scratch, sizeof (scratch), 315 if (GNUNET_OK !=
281 "SELECT value,expire,path FROM ds090 WHERE key=? AND type=? AND expire >= ? LIMIT 1 OFFSET %u", 316 GNUNET_SQ_bind (plugin->get_stmt,
282 off); 317 params_select))
283 if (sq_prepare (plugin->dbh, scratch, &stmt) != SQLITE_OK)
284 {
285 LOG_SQLITE (plugin->dbh,
286 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
287 "sq_prepare");
288 return cnt;
289 }
290 if ((SQLITE_OK !=
291 sqlite3_bind_blob (stmt, 1,
292 key,
293 sizeof (struct GNUNET_HashCode),
294 SQLITE_TRANSIENT)) ||
295 (SQLITE_OK != sqlite3_bind_int (stmt, 2, type)) ||
296 (SQLITE_OK != sqlite3_bind_int64 (stmt, 3, now.abs_value_us)))
297 { 318 {
298 LOG_SQLITE (plugin->dbh, 319 LOG_SQLITE (plugin->dbh,
299 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 320 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
300 "sqlite3_bind_xxx"); 321 "sqlite3_bind_xxx");
301 sqlite3_finalize (stmt); 322 GNUNET_SQ_reset (plugin->dbh,
323 plugin->get_stmt);
302 return cnt; 324 return cnt;
303 } 325 }
304 if (sqlite3_step (stmt) != SQLITE_ROW) 326 if (SQLITE_ROW !=
327 sqlite3_step (plugin->get_stmt))
305 break; 328 break;
306 size = sqlite3_column_bytes (stmt, 0); 329 if (GNUNET_OK !=
307 dat = sqlite3_column_blob (stmt, 0); 330 GNUNET_SQ_extract_result (plugin->get_stmt,
308 exp.abs_value_us = sqlite3_column_int64 (stmt, 1); 331 rs))
309 psize = sqlite3_column_bytes (stmt, 2); 332 {
333 GNUNET_break (0);
334 GNUNET_SQ_reset (plugin->dbh,
335 plugin->get_stmt);
336 break;
337 }
310 if (0 != psize % sizeof (struct GNUNET_PeerIdentity)) 338 if (0 != psize % sizeof (struct GNUNET_PeerIdentity))
311 { 339 {
312 GNUNET_break (0); 340 GNUNET_break (0);
313 psize = 0; 341 psize = 0;
342 path = NULL;
314 } 343 }
315 psize /= sizeof (struct GNUNET_PeerIdentity); 344 psize /= sizeof (struct GNUNET_PeerIdentity);
316 if (0 != psize)
317 path = sqlite3_column_blob (stmt, 2);
318 else
319 path = NULL;
320 ntime = (int64_t) exp.abs_value_us;
321 if (ntime == INT64_MAX)
322 exp = GNUNET_TIME_UNIT_FOREVER_ABS;
323 cnt++; 345 cnt++;
324 LOG (GNUNET_ERROR_TYPE_DEBUG, 346 LOG (GNUNET_ERROR_TYPE_DEBUG,
325 "Found %u-byte result when processing GET for key `%4s'\n", 347 "Found %u-byte result when processing GET for key `%s'\n",
326 (unsigned int) size, 348 (unsigned int) size,
327 GNUNET_h2s (key)); 349 GNUNET_h2s (key));
328 if (GNUNET_OK != iter (iter_cls, 350 if (GNUNET_OK != iter (iter_cls,
@@ -334,11 +356,17 @@ sqlite_plugin_get (void *cls,
334 psize, 356 psize,
335 path)) 357 path))
336 { 358 {
337 sqlite3_finalize (stmt); 359 GNUNET_SQ_cleanup_result (rs);
360 GNUNET_SQ_reset (plugin->dbh,
361 plugin->get_stmt);
338 break; 362 break;
339 } 363 }
340 sqlite3_finalize (stmt); 364 GNUNET_SQ_cleanup_result (rs);
365 GNUNET_SQ_reset (plugin->dbh,
366 plugin->get_stmt);
341 } 367 }
368 GNUNET_SQ_reset (plugin->dbh,
369 plugin->get_stmt);
342 return cnt; 370 return cnt;
343} 371}
344 372
@@ -354,79 +382,73 @@ static int
354sqlite_plugin_del (void *cls) 382sqlite_plugin_del (void *cls)
355{ 383{
356 struct Plugin *plugin = cls; 384 struct Plugin *plugin = cls;
357 unsigned long long rowid; 385 uint64_t rowid;
358 unsigned int dsize; 386 void *data;
359 sqlite3_stmt *stmt; 387 size_t dsize;
360 sqlite3_stmt *dstmt;
361 struct GNUNET_HashCode hc; 388 struct GNUNET_HashCode hc;
389 struct GNUNET_SQ_ResultSpec rs[] = {
390 GNUNET_SQ_result_spec_uint64 (&rowid),
391 GNUNET_SQ_result_spec_auto_from_type (&hc),
392 GNUNET_SQ_result_spec_variable_size ((void **) &data,
393 &dsize),
394 GNUNET_SQ_result_spec_end
395 };
396 struct GNUNET_SQ_QueryParam params[] = {
397 GNUNET_SQ_query_param_uint64 (&rowid),
398 GNUNET_SQ_query_param_end
399 };
362 400
363 LOG (GNUNET_ERROR_TYPE_DEBUG, 401 LOG (GNUNET_ERROR_TYPE_DEBUG,
364 "Processing DEL\n"); 402 "Processing DEL\n");
365 stmt = NULL; 403 if (SQLITE_ROW !=
366 dstmt = NULL; 404 sqlite3_step (plugin->del_select_stmt))
367 if (SQLITE_OK !=
368 sq_prepare (plugin->dbh,
369 "SELECT _ROWID_,key,value FROM ds090 ORDER BY expire ASC LIMIT 1",
370 &stmt))
371 {
372 LOG_SQLITE (plugin->dbh,
373 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
374 "sq_prepare");
375 if (stmt != NULL)
376 (void) sqlite3_finalize (stmt);
377 return GNUNET_SYSERR;
378 }
379 if (SQLITE_ROW != sqlite3_step (stmt))
380 { 405 {
381 LOG_SQLITE (plugin->dbh, 406 LOG_SQLITE (plugin->dbh,
382 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 407 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
383 "sqlite3_step"); 408 "sqlite3_step");
384 (void) sqlite3_finalize (stmt); 409 GNUNET_SQ_reset (plugin->dbh,
410 plugin->del_select_stmt);
385 return GNUNET_SYSERR; 411 return GNUNET_SYSERR;
386 } 412 }
387 rowid = sqlite3_column_int64 (stmt, 0); 413 if (GNUNET_OK !=
388 GNUNET_assert (sqlite3_column_bytes (stmt, 1) == sizeof (struct GNUNET_HashCode)); 414 GNUNET_SQ_extract_result (plugin->del_select_stmt,
389 GNUNET_memcpy (&hc, sqlite3_column_blob (stmt, 1), sizeof (struct GNUNET_HashCode)); 415 rs))
390 dsize = sqlite3_column_bytes (stmt, 2);
391 if (SQLITE_OK != sqlite3_finalize (stmt))
392 LOG_SQLITE (plugin->dbh,
393 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
394 "sqlite3_step");
395 if (SQLITE_OK !=
396 sq_prepare (plugin->dbh,
397 "DELETE FROM ds090 WHERE _ROWID_=?", &dstmt))
398 { 416 {
399 LOG_SQLITE (plugin->dbh, 417 GNUNET_break (0);
400 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 418 GNUNET_SQ_reset (plugin->dbh,
401 "sq_prepare"); 419 plugin->del_select_stmt);
402 if (stmt != NULL)
403 (void) sqlite3_finalize (stmt);
404 return GNUNET_SYSERR; 420 return GNUNET_SYSERR;
405 } 421 }
406 if (SQLITE_OK != sqlite3_bind_int64 (dstmt, 1, rowid)) 422 GNUNET_SQ_cleanup_result (rs);
423 GNUNET_SQ_reset (plugin->dbh,
424 plugin->del_select_stmt);
425 if (GNUNET_OK !=
426 GNUNET_SQ_bind (plugin->del_stmt,
427 params))
407 { 428 {
408 LOG_SQLITE (plugin->dbh, 429 LOG_SQLITE (plugin->dbh,
409 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 430 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
410 "sqlite3_bind"); 431 "sqlite3_bind");
411 (void) sqlite3_finalize (dstmt); 432 GNUNET_SQ_reset (plugin->dbh,
433 plugin->del_stmt);
412 return GNUNET_SYSERR; 434 return GNUNET_SYSERR;
413 } 435 }
414 if (SQLITE_DONE != sqlite3_step (dstmt)) 436 if (SQLITE_DONE !=
437 sqlite3_step (plugin->del_stmt))
415 { 438 {
416 LOG_SQLITE (plugin->dbh, 439 LOG_SQLITE (plugin->dbh,
417 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 440 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
418 "sqlite3_step"); 441 "sqlite3_step");
419 (void) sqlite3_finalize (dstmt); 442 GNUNET_SQ_reset (plugin->dbh,
443 plugin->del_stmt);
420 return GNUNET_SYSERR; 444 return GNUNET_SYSERR;
421 } 445 }
422 plugin->num_items--; 446 plugin->num_items--;
423 plugin->env->delete_notify (plugin->env->cls, 447 plugin->env->delete_notify (plugin->env->cls,
424 &hc, 448 &hc,
425 dsize + OVERHEAD); 449 dsize + OVERHEAD);
426 if (SQLITE_OK != sqlite3_finalize (dstmt)) 450 GNUNET_SQ_reset (plugin->dbh,
427 LOG_SQLITE (plugin->dbh, 451 plugin->del_stmt);
428 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
429 "sqlite3_finalize");
430 return GNUNET_OK; 452 return GNUNET_OK;
431} 453}
432 454
@@ -445,17 +467,28 @@ sqlite_plugin_get_random (void *cls,
445 void *iter_cls) 467 void *iter_cls)
446{ 468{
447 struct Plugin *plugin = cls; 469 struct Plugin *plugin = cls;
448 sqlite3_stmt *stmt;
449 struct GNUNET_TIME_Absolute exp; 470 struct GNUNET_TIME_Absolute exp;
450 unsigned int size; 471 size_t size;
451 const char *dat; 472 void *dat;
452 unsigned int off; 473 uint32_t off;
453 unsigned int psize; 474 size_t psize;
454 unsigned int type; 475 uint32_t type;
455 char scratch[256]; 476 struct GNUNET_PeerIdentity *path;
456 int64_t ntime; 477 struct GNUNET_HashCode key;
457 const struct GNUNET_PeerIdentity *path; 478 struct GNUNET_SQ_QueryParam params[] = {
458 const struct GNUNET_HashCode *key; 479 GNUNET_SQ_query_param_uint32 (&off),
480 GNUNET_SQ_query_param_end
481 };
482 struct GNUNET_SQ_ResultSpec rs[] = {
483 GNUNET_SQ_result_spec_variable_size (&dat,
484 &size),
485 GNUNET_SQ_result_spec_absolute_time (&exp),
486 GNUNET_SQ_result_spec_variable_size ((void **) &path,
487 &psize),
488 GNUNET_SQ_result_spec_auto_from_type (&key),
489 GNUNET_SQ_result_spec_uint32 (&type),
490 GNUNET_SQ_result_spec_end
491 };
459 492
460 if (0 == plugin->num_items) 493 if (0 == plugin->num_items)
461 return 0; 494 return 0;
@@ -463,60 +496,51 @@ sqlite_plugin_get_random (void *cls,
463 return 1; 496 return 1;
464 off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, 497 off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
465 plugin->num_items); 498 plugin->num_items);
466 GNUNET_snprintf (scratch, 499 if (GNUNET_OK !=
467 sizeof (scratch), 500 GNUNET_SQ_bind (plugin->get_random_stmt,
468 "SELECT value,expire,path,key,type FROM ds090 ORDER BY key LIMIT 1 OFFSET %u", 501 params))
469 off);
470 if (SQLITE_OK !=
471 sq_prepare (plugin->dbh, scratch, &stmt))
472 { 502 {
473 LOG_SQLITE (plugin->dbh,
474 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
475 "sq_prepare");
476 return 0; 503 return 0;
477 } 504 }
478 if (SQLITE_ROW != sqlite3_step (stmt)) 505 if (SQLITE_ROW !=
506 sqlite3_step (plugin->get_random_stmt))
507 {
508 GNUNET_break (0);
509 GNUNET_SQ_reset (plugin->dbh,
510 plugin->get_random_stmt);
511 return 0;
512 }
513 if (GNUNET_OK !=
514 GNUNET_SQ_extract_result (plugin->get_random_stmt,
515 rs))
479 { 516 {
480 GNUNET_break (0); 517 GNUNET_break (0);
481 sqlite3_finalize (stmt); 518 GNUNET_SQ_reset (plugin->dbh,
519 plugin->get_random_stmt);
482 return 0; 520 return 0;
483 } 521 }
484 size = sqlite3_column_bytes (stmt, 0);
485 dat = sqlite3_column_blob (stmt, 0);
486 exp.abs_value_us = sqlite3_column_int64 (stmt, 1);
487 psize = sqlite3_column_bytes (stmt, 2);
488 if (0 != psize % sizeof (struct GNUNET_PeerIdentity)) 522 if (0 != psize % sizeof (struct GNUNET_PeerIdentity))
489 { 523 {
490 GNUNET_break (0); 524 GNUNET_break (0);
491 psize = 0; 525 psize = 0;
526 path = NULL;
492 } 527 }
493 psize /= sizeof (struct GNUNET_PeerIdentity); 528 psize /= sizeof (struct GNUNET_PeerIdentity);
494 if (0 != psize)
495 path = sqlite3_column_blob (stmt, 2);
496 else
497 path = NULL;
498
499 GNUNET_assert (sizeof (struct GNUNET_HashCode) ==
500 sqlite3_column_bytes (stmt, 3));
501 key = sqlite3_column_blob (stmt, 3);
502 type = sqlite3_column_int (stmt, 4);
503
504 ntime = (int64_t) exp.abs_value_us;
505 if (ntime == INT64_MAX)
506 exp = GNUNET_TIME_UNIT_FOREVER_ABS;
507 LOG (GNUNET_ERROR_TYPE_DEBUG, 529 LOG (GNUNET_ERROR_TYPE_DEBUG,
508 "Found %u-byte result with key %s when processing GET-RANDOM\n", 530 "Found %u-byte result with key %s when processing GET-RANDOM\n",
509 (unsigned int) size, 531 (unsigned int) size,
510 GNUNET_h2s (key)); 532 GNUNET_h2s (&key));
511 (void) iter (iter_cls, 533 (void) iter (iter_cls,
512 key, 534 &key,
513 size, 535 size,
514 dat, 536 dat,
515 type, 537 (enum GNUNET_BLOCK_Type) type,
516 exp, 538 exp,
517 psize, 539 psize,
518 path); 540 path);
519 sqlite3_finalize (stmt); 541 GNUNET_SQ_cleanup_result (rs);
542 GNUNET_SQ_reset (plugin->dbh,
543 plugin->get_random_stmt);
520 return 1; 544 return 1;
521} 545}
522 546
@@ -542,83 +566,73 @@ sqlite_plugin_get_closest (void *cls,
542 void *iter_cls) 566 void *iter_cls)
543{ 567{
544 struct Plugin *plugin = cls; 568 struct Plugin *plugin = cls;
545 sqlite3_stmt *stmt; 569 uint32_t num_results32 = num_results;
546 struct GNUNET_TIME_Absolute now; 570 struct GNUNET_TIME_Absolute now;
547 struct GNUNET_TIME_Absolute exp; 571 struct GNUNET_TIME_Absolute exp;
548 unsigned int size; 572 size_t size;
549 const char *dat; 573 void *dat;
550 unsigned int cnt; 574 unsigned int cnt;
551 unsigned int psize; 575 size_t psize;
552 unsigned int type; 576 uint32_t type;
553 int64_t ntime; 577 struct GNUNET_HashCode hc;
554 const struct GNUNET_PeerIdentity *path; 578 struct GNUNET_PeerIdentity *path;
579 struct GNUNET_SQ_QueryParam params[] = {
580 GNUNET_SQ_query_param_auto_from_type (key),
581 GNUNET_SQ_query_param_absolute_time (&now),
582 GNUNET_SQ_query_param_uint32 (&num_results32),
583 GNUNET_SQ_query_param_end
584 };
585 struct GNUNET_SQ_ResultSpec rs[] = {
586 GNUNET_SQ_result_spec_variable_size (&dat,
587 &size),
588 GNUNET_SQ_result_spec_absolute_time (&exp),
589 GNUNET_SQ_result_spec_variable_size ((void **) &path,
590 &psize),
591 GNUNET_SQ_result_spec_uint32 (&type),
592 GNUNET_SQ_result_spec_auto_from_type (&hc),
593 GNUNET_SQ_result_spec_end
594 };
555 595
556 now = GNUNET_TIME_absolute_get (); 596 now = GNUNET_TIME_absolute_get ();
557 LOG (GNUNET_ERROR_TYPE_DEBUG, 597 LOG (GNUNET_ERROR_TYPE_DEBUG,
558 "Processing GET_CLOSEST for key `%4s'\n", 598 "Processing GET_CLOSEST for key `%s'\n",
559 GNUNET_h2s (key)); 599 GNUNET_h2s (key));
560 if (SQLITE_OK != 600 if (GNUNET_OK !=
561 sq_prepare (plugin->dbh, 601 GNUNET_SQ_bind (plugin->get_closest_stmt,
562 "SELECT value,expire,path,type,key FROM ds090 WHERE key>=? AND expire >= ? ORDER BY KEY ASC LIMIT ?", 602 params))
563 &stmt))
564 {
565 LOG_SQLITE (plugin->dbh,
566 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
567 "sq_prepare");
568 return 0;
569 }
570 ntime = (int64_t) now.abs_value_us;
571 GNUNET_assert (ntime >= 0);
572 if ((SQLITE_OK !=
573 sqlite3_bind_blob (stmt,
574 1,
575 key,
576 sizeof (struct GNUNET_HashCode),
577 SQLITE_TRANSIENT)) ||
578 (SQLITE_OK != sqlite3_bind_int64 (stmt, 2, now.abs_value_us)) ||
579 (SQLITE_OK != sqlite3_bind_int (stmt, 3, num_results)) )
580 { 603 {
581 LOG_SQLITE (plugin->dbh, 604 LOG_SQLITE (plugin->dbh,
582 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 605 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
583 "sqlite3_bind_xxx"); 606 "sqlite3_bind_xxx");
584 sqlite3_finalize (stmt); 607 GNUNET_SQ_reset (plugin->dbh,
608 plugin->get_closest_stmt);
585 return 0; 609 return 0;
586 } 610 }
587 cnt = 0; 611 cnt = 0;
588 while (SQLITE_ROW == sqlite3_step (stmt)) 612 while (SQLITE_ROW ==
613 sqlite3_step (plugin->get_closest_stmt))
589 { 614 {
590 if (sizeof (struct GNUNET_HashCode) != 615 if (GNUNET_OK !=
591 sqlite3_column_bytes (stmt, 4)) 616 GNUNET_SQ_extract_result (plugin->get_closest_stmt,
617 rs))
592 { 618 {
593 GNUNET_break (0); 619 GNUNET_break (0);
594 break; 620 break;
595 } 621 }
596 size = sqlite3_column_bytes (stmt, 0);
597 dat = sqlite3_column_blob (stmt, 0);
598 exp.abs_value_us = sqlite3_column_int64 (stmt, 1);
599 psize = sqlite3_column_bytes (stmt, 2);
600 type = sqlite3_column_int (stmt, 3);
601 key = sqlite3_column_blob (stmt, 4);
602 if (0 != psize % sizeof (struct GNUNET_PeerIdentity)) 622 if (0 != psize % sizeof (struct GNUNET_PeerIdentity))
603 { 623 {
604 GNUNET_break (0); 624 GNUNET_break (0);
605 psize = 0; 625 psize = 0;
626 path = NULL;
606 } 627 }
607 psize /= sizeof (struct GNUNET_PeerIdentity); 628 psize /= sizeof (struct GNUNET_PeerIdentity);
608 if (0 != psize)
609 path = sqlite3_column_blob (stmt, 2);
610 else
611 path = NULL;
612 ntime = (int64_t) exp.abs_value_us;
613 if (ntime == INT64_MAX)
614 exp = GNUNET_TIME_UNIT_FOREVER_ABS;
615 cnt++; 629 cnt++;
616 LOG (GNUNET_ERROR_TYPE_DEBUG, 630 LOG (GNUNET_ERROR_TYPE_DEBUG,
617 "Found %u-byte result at %s when processing GET_CLOSE\n", 631 "Found %u-byte result at %s when processing GET_CLOSE\n",
618 (unsigned int) size, 632 (unsigned int) size,
619 GNUNET_h2s (key)); 633 GNUNET_h2s (&hc));
620 if (GNUNET_OK != iter (iter_cls, 634 if (GNUNET_OK != iter (iter_cls,
621 key, 635 &hc,
622 size, 636 size,
623 dat, 637 dat,
624 type, 638 type,
@@ -626,11 +640,13 @@ sqlite_plugin_get_closest (void *cls,
626 psize, 640 psize,
627 path)) 641 path))
628 { 642 {
629 sqlite3_finalize (stmt); 643 GNUNET_SQ_cleanup_result (rs);
630 break; 644 break;
631 } 645 }
646 GNUNET_SQ_cleanup_result (rs);
632 } 647 }
633 sqlite3_finalize (stmt); 648 GNUNET_SQ_reset (plugin->dbh,
649 plugin->get_closest_stmt);
634 return cnt; 650 return cnt;
635} 651}
636 652
@@ -703,6 +719,51 @@ libgnunet_plugin_datacache_sqlite_init (void *cls)
703 plugin->env = env; 719 plugin->env = env;
704 plugin->dbh = dbh; 720 plugin->dbh = dbh;
705 plugin->fn = fn_utf8; 721 plugin->fn = fn_utf8;
722
723 if ( (SQLITE_OK !=
724 sq_prepare (plugin->dbh,
725 "INSERT INTO ds090 (type, expire, key, value, path) "
726 "VALUES (?, ?, ?, ?, ?)",
727 &plugin->insert_stmt)) ||
728 (SQLITE_OK !=
729 sq_prepare (plugin->dbh,
730 "SELECT count(*) FROM ds090 "
731 "WHERE key=? AND type=? AND expire >= ?",
732 &plugin->get_count_stmt)) ||
733 (SQLITE_OK !=
734 sq_prepare (plugin->dbh,
735 "SELECT value,expire,path FROM ds090 "
736 "WHERE key=? AND type=? AND expire >= ? LIMIT 1 OFFSET ?",
737 &plugin->get_stmt)) ||
738 (SQLITE_OK !=
739 sq_prepare (plugin->dbh,
740 "SELECT _ROWID_,key,value FROM ds090 ORDER BY expire ASC LIMIT 1",
741 &plugin->del_select_stmt)) ||
742 (SQLITE_OK !=
743 sq_prepare (plugin->dbh,
744 "DELETE FROM ds090 WHERE _ROWID_=?",
745 &plugin->del_stmt)) ||
746 (SQLITE_OK !=
747 sq_prepare (plugin->dbh,
748 "SELECT value,expire,path,key,type FROM ds090 "
749 "ORDER BY key LIMIT 1 OFFSET ?",
750 &plugin->get_random_stmt)) ||
751 (SQLITE_OK !=
752 sq_prepare (plugin->dbh,
753 "SELECT value,expire,path,type,key FROM ds090 "
754 "WHERE key>=? AND expire >= ? ORDER BY KEY ASC LIMIT ?",
755 &plugin->get_closest_stmt))
756 )
757 {
758 LOG_SQLITE (plugin->dbh,
759 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
760 "sq_prepare");
761 GNUNET_break (SQLITE_OK ==
762 sqlite3_close (plugin->dbh));
763 GNUNET_free (plugin);
764 return NULL;
765 }
766
706 api = GNUNET_new (struct GNUNET_DATACACHE_PluginFunctions); 767 api = GNUNET_new (struct GNUNET_DATACACHE_PluginFunctions);
707 api->cls = plugin; 768 api->cls = plugin;
708 api->get = &sqlite_plugin_get; 769 api->get = &sqlite_plugin_get;
@@ -741,6 +802,13 @@ libgnunet_plugin_datacache_sqlite_done (void *cls)
741 plugin->fn); 802 plugin->fn);
742 GNUNET_free_non_null (plugin->fn); 803 GNUNET_free_non_null (plugin->fn);
743#endif 804#endif
805 sqlite3_finalize (plugin->insert_stmt);
806 sqlite3_finalize (plugin->get_count_stmt);
807 sqlite3_finalize (plugin->get_stmt);
808 sqlite3_finalize (plugin->del_select_stmt);
809 sqlite3_finalize (plugin->del_stmt);
810 sqlite3_finalize (plugin->get_random_stmt);
811 sqlite3_finalize (plugin->get_closest_stmt);
744 result = sqlite3_close (plugin->dbh); 812 result = sqlite3_close (plugin->dbh);
745#if SQLITE_VERSION_NUMBER >= 3007000 813#if SQLITE_VERSION_NUMBER >= 3007000
746 if (SQLITE_BUSY == result) 814 if (SQLITE_BUSY == result)
diff --git a/src/datastore/Makefile.am b/src/datastore/Makefile.am
index 1285020de..9b8cf365f 100644
--- a/src/datastore/Makefile.am
+++ b/src/datastore/Makefile.am
@@ -115,6 +115,7 @@ noinst_LTLIBRARIES = \
115libgnunet_plugin_datastore_sqlite_la_SOURCES = \ 115libgnunet_plugin_datastore_sqlite_la_SOURCES = \
116 plugin_datastore_sqlite.c 116 plugin_datastore_sqlite.c
117libgnunet_plugin_datastore_sqlite_la_LIBADD = \ 117libgnunet_plugin_datastore_sqlite_la_LIBADD = \
118 $(top_builddir)/src/sq/libgnunetsq.la \
118 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 119 $(top_builddir)/src/statistics/libgnunetstatistics.la \
119 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lsqlite3 \ 120 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lsqlite3 \
120 $(LTLIBINTL) 121 $(LTLIBINTL)
diff --git a/src/datastore/datastore.h b/src/datastore/datastore.h
index 9de72f064..5fd360161 100644
--- a/src/datastore/datastore.h
+++ b/src/datastore/datastore.h
@@ -119,9 +119,14 @@ struct GetKeyMessage
119 uint32_t type GNUNET_PACKED; 119 uint32_t type GNUNET_PACKED;
120 120
121 /** 121 /**
122 * Offset of the result. 122 * UID at which to start the search
123 */ 123 */
124 uint64_t offset GNUNET_PACKED; 124 uint64_t next_uid GNUNET_PACKED;
125
126 /**
127 * If true return a random result
128 */
129 uint32_t random GNUNET_PACKED;
125 130
126 /** 131 /**
127 * Desired key. 132 * Desired key.
@@ -148,9 +153,14 @@ struct GetMessage
148 uint32_t type GNUNET_PACKED; 153 uint32_t type GNUNET_PACKED;
149 154
150 /** 155 /**
151 * Offset of the result. 156 * UID at which to start the search
157 */
158 uint64_t next_uid GNUNET_PACKED;
159
160 /**
161 * If true return a random result
152 */ 162 */
153 uint64_t offset GNUNET_PACKED; 163 uint32_t random GNUNET_PACKED;
154 164
155}; 165};
156 166
@@ -172,9 +182,9 @@ struct GetZeroAnonymityMessage
172 uint32_t type GNUNET_PACKED; 182 uint32_t type GNUNET_PACKED;
173 183
174 /** 184 /**
175 * Offset of the result. 185 * UID at which to start the search
176 */ 186 */
177 uint64_t offset GNUNET_PACKED; 187 uint64_t next_uid GNUNET_PACKED;
178 188
179}; 189};
180 190
diff --git a/src/datastore/datastore_api.c b/src/datastore/datastore_api.c
index 916e6acae..26e1e501d 100644
--- a/src/datastore/datastore_api.c
+++ b/src/datastore/datastore_api.c
@@ -33,6 +33,8 @@
33 33
34#define LOG(kind,...) GNUNET_log_from (kind, "datastore-api",__VA_ARGS__) 34#define LOG(kind,...) GNUNET_log_from (kind, "datastore-api",__VA_ARGS__)
35 35
36#define DELAY_WARN_TIMEOUT GNUNET_TIME_UNIT_MINUTES
37
36/** 38/**
37 * Collect an instane number of statistics? May cause excessive IPC. 39 * Collect an instane number of statistics? May cause excessive IPC.
38 */ 40 */
@@ -138,6 +140,12 @@ struct GNUNET_DATASTORE_QueueEntry
138 struct GNUNET_MQ_Envelope *env; 140 struct GNUNET_MQ_Envelope *env;
139 141
140 /** 142 /**
143 * Task we run if this entry stalls the queue and we
144 * need to warn the user.
145 */
146 struct GNUNET_SCHEDULER_Task *delay_warn_task;
147
148 /**
141 * Priority in the queue. 149 * Priority in the queue.
142 */ 150 */
143 unsigned int priority; 151 unsigned int priority;
@@ -269,11 +277,36 @@ free_queue_entry (struct GNUNET_DATASTORE_QueueEntry *qe)
269 h->queue_size--; 277 h->queue_size--;
270 if (NULL != qe->env) 278 if (NULL != qe->env)
271 GNUNET_MQ_discard (qe->env); 279 GNUNET_MQ_discard (qe->env);
280 if (NULL != qe->delay_warn_task)
281 GNUNET_SCHEDULER_cancel (qe->delay_warn_task);
272 GNUNET_free (qe); 282 GNUNET_free (qe);
273} 283}
274 284
275 285
276/** 286/**
287 * Task that logs an error after some time.
288 *
289 * @param qe `struct GNUNET_DATASTORE_QueueEntry` about which the error is
290 */
291static void
292delay_warning (void *cls)
293{
294 struct GNUNET_DATASTORE_QueueEntry *qe = cls;
295
296 qe->delay_warn_task = NULL;
297 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
298 "Request %p of type %u at head of datastore queue for more than %s\n",
299 qe,
300 (unsigned int) qe->response_type,
301 GNUNET_STRINGS_relative_time_to_string (DELAY_WARN_TIMEOUT,
302 GNUNET_YES));
303 qe->delay_warn_task = GNUNET_SCHEDULER_add_delayed (DELAY_WARN_TIMEOUT,
304 &delay_warning,
305 qe);
306}
307
308
309/**
277 * Handle error in sending drop request to datastore. 310 * Handle error in sending drop request to datastore.
278 * 311 *
279 * @param cls closure with the datastore handle 312 * @param cls closure with the datastore handle
@@ -290,8 +323,14 @@ mq_error_handler (void *cls,
290 "MQ error, reconnecting to DATASTORE\n"); 323 "MQ error, reconnecting to DATASTORE\n");
291 do_disconnect (h); 324 do_disconnect (h);
292 qe = h->queue_head; 325 qe = h->queue_head;
293 if ( (NULL != qe) && 326 if (NULL == qe)
294 (NULL == qe->env) ) 327 return;
328 if (NULL != qe->delay_warn_task)
329 {
330 GNUNET_SCHEDULER_cancel (qe->delay_warn_task);
331 qe->delay_warn_task = NULL;
332 }
333 if (NULL == qe->env)
295 { 334 {
296 union QueueContext qc = qe->qc; 335 union QueueContext qc = qe->qc;
297 uint16_t rt = qe->response_type; 336 uint16_t rt = qe->response_type;
@@ -594,6 +633,10 @@ process_queue (struct GNUNET_DATASTORE_Handle *h)
594 "Not connected\n"); 633 "Not connected\n");
595 return; 634 return;
596 } 635 }
636 GNUNET_assert (NULL == qe->delay_warn_task);
637 qe->delay_warn_task = GNUNET_SCHEDULER_add_delayed (DELAY_WARN_TIMEOUT,
638 &delay_warning,
639 qe);
597 GNUNET_MQ_send (h->mq, 640 GNUNET_MQ_send (h->mq,
598 qe->env); 641 qe->env);
599 qe->env = NULL; 642 qe->env = NULL;
@@ -958,7 +1001,7 @@ GNUNET_DATASTORE_put (struct GNUNET_DATASTORE_Handle *h,
958 struct DataMessage *dm; 1001 struct DataMessage *dm;
959 union QueueContext qc; 1002 union QueueContext qc;
960 1003
961 if (size + sizeof (*dm) >= GNUNET_SERVER_MAX_MESSAGE_SIZE) 1004 if (size + sizeof (*dm) >= GNUNET_MAX_MESSAGE_SIZE)
962 { 1005 {
963 GNUNET_break (0); 1006 GNUNET_break (0);
964 return NULL; 1007 return NULL;
@@ -1169,7 +1212,7 @@ GNUNET_DATASTORE_remove (struct GNUNET_DATASTORE_Handle *h,
1169 struct GNUNET_MQ_Envelope *env; 1212 struct GNUNET_MQ_Envelope *env;
1170 union QueueContext qc; 1213 union QueueContext qc;
1171 1214
1172 if (sizeof (*dm) + size >= GNUNET_SERVER_MAX_MESSAGE_SIZE) 1215 if (sizeof (*dm) + size >= GNUNET_MAX_MESSAGE_SIZE)
1173 { 1216 {
1174 GNUNET_break (0); 1217 GNUNET_break (0);
1175 return NULL; 1218 return NULL;
@@ -1282,10 +1325,7 @@ GNUNET_DATASTORE_get_for_replication (struct GNUNET_DATASTORE_Handle *h,
1282 * Get a single zero-anonymity value from the datastore. 1325 * Get a single zero-anonymity value from the datastore.
1283 * 1326 *
1284 * @param h handle to the datastore 1327 * @param h handle to the datastore
1285 * @param offset offset of the result (modulo num-results); set to 1328 * @param next_uid return the result with lowest uid >= next_uid
1286 * a random 64-bit value initially; then increment by
1287 * one each time; detect that all results have been found by uid
1288 * being again the first uid ever returned.
1289 * @param queue_priority ranking of this request in the priority queue 1329 * @param queue_priority ranking of this request in the priority queue
1290 * @param max_queue_size at what queue size should this request be dropped 1330 * @param max_queue_size at what queue size should this request be dropped
1291 * (if other requests of higher priority are in the queue) 1331 * (if other requests of higher priority are in the queue)
@@ -1299,7 +1339,7 @@ GNUNET_DATASTORE_get_for_replication (struct GNUNET_DATASTORE_Handle *h,
1299 */ 1339 */
1300struct GNUNET_DATASTORE_QueueEntry * 1340struct GNUNET_DATASTORE_QueueEntry *
1301GNUNET_DATASTORE_get_zero_anonymity (struct GNUNET_DATASTORE_Handle *h, 1341GNUNET_DATASTORE_get_zero_anonymity (struct GNUNET_DATASTORE_Handle *h,
1302 uint64_t offset, 1342 uint64_t next_uid,
1303 unsigned int queue_priority, 1343 unsigned int queue_priority,
1304 unsigned int max_queue_size, 1344 unsigned int max_queue_size,
1305 enum GNUNET_BLOCK_Type type, 1345 enum GNUNET_BLOCK_Type type,
@@ -1314,13 +1354,12 @@ GNUNET_DATASTORE_get_zero_anonymity (struct GNUNET_DATASTORE_Handle *h,
1314 GNUNET_assert (NULL != proc); 1354 GNUNET_assert (NULL != proc);
1315 GNUNET_assert (type != GNUNET_BLOCK_TYPE_ANY); 1355 GNUNET_assert (type != GNUNET_BLOCK_TYPE_ANY);
1316 LOG (GNUNET_ERROR_TYPE_DEBUG, 1356 LOG (GNUNET_ERROR_TYPE_DEBUG,
1317 "Asked to get %llu-th zero-anonymity entry of type %d\n", 1357 "Asked to get a zero-anonymity entry of type %d\n",
1318 (unsigned long long) offset,
1319 type); 1358 type);
1320 env = GNUNET_MQ_msg (m, 1359 env = GNUNET_MQ_msg (m,
1321 GNUNET_MESSAGE_TYPE_DATASTORE_GET_ZERO_ANONYMITY); 1360 GNUNET_MESSAGE_TYPE_DATASTORE_GET_ZERO_ANONYMITY);
1322 m->type = htonl ((uint32_t) type); 1361 m->type = htonl ((uint32_t) type);
1323 m->offset = GNUNET_htonll (offset); 1362 m->next_uid = GNUNET_htonll (next_uid);
1324 qc.rc.proc = proc; 1363 qc.rc.proc = proc;
1325 qc.rc.proc_cls = proc_cls; 1364 qc.rc.proc_cls = proc_cls;
1326 qe = make_queue_entry (h, 1365 qe = make_queue_entry (h,
@@ -1349,10 +1388,8 @@ GNUNET_DATASTORE_get_zero_anonymity (struct GNUNET_DATASTORE_Handle *h,
1349 * will only be called once. 1388 * will only be called once.
1350 * 1389 *
1351 * @param h handle to the datastore 1390 * @param h handle to the datastore
1352 * @param offset offset of the result (modulo num-results); set to 1391 * @param next_uid return the result with lowest uid >= next_uid
1353 * a random 64-bit value initially; then increment by 1392 * @param random if true, return a random result instead of using next_uid
1354 * one each time; detect that all results have been found by uid
1355 * being again the first uid ever returned.
1356 * @param key maybe NULL (to match all entries) 1393 * @param key maybe NULL (to match all entries)
1357 * @param type desired type, 0 for any 1394 * @param type desired type, 0 for any
1358 * @param queue_priority ranking of this request in the priority queue 1395 * @param queue_priority ranking of this request in the priority queue
@@ -1366,7 +1403,8 @@ GNUNET_DATASTORE_get_zero_anonymity (struct GNUNET_DATASTORE_Handle *h,
1366 */ 1403 */
1367struct GNUNET_DATASTORE_QueueEntry * 1404struct GNUNET_DATASTORE_QueueEntry *
1368GNUNET_DATASTORE_get_key (struct GNUNET_DATASTORE_Handle *h, 1405GNUNET_DATASTORE_get_key (struct GNUNET_DATASTORE_Handle *h,
1369 uint64_t offset, 1406 uint64_t next_uid,
1407 bool random,
1370 const struct GNUNET_HashCode *key, 1408 const struct GNUNET_HashCode *key,
1371 enum GNUNET_BLOCK_Type type, 1409 enum GNUNET_BLOCK_Type type,
1372 unsigned int queue_priority, 1410 unsigned int queue_priority,
@@ -1390,14 +1428,16 @@ GNUNET_DATASTORE_get_key (struct GNUNET_DATASTORE_Handle *h,
1390 env = GNUNET_MQ_msg (gm, 1428 env = GNUNET_MQ_msg (gm,
1391 GNUNET_MESSAGE_TYPE_DATASTORE_GET); 1429 GNUNET_MESSAGE_TYPE_DATASTORE_GET);
1392 gm->type = htonl (type); 1430 gm->type = htonl (type);
1393 gm->offset = GNUNET_htonll (offset); 1431 gm->next_uid = GNUNET_htonll (next_uid);
1432 gm->random = random;
1394 } 1433 }
1395 else 1434 else
1396 { 1435 {
1397 env = GNUNET_MQ_msg (gkm, 1436 env = GNUNET_MQ_msg (gkm,
1398 GNUNET_MESSAGE_TYPE_DATASTORE_GET_KEY); 1437 GNUNET_MESSAGE_TYPE_DATASTORE_GET_KEY);
1399 gkm->type = htonl (type); 1438 gkm->type = htonl (type);
1400 gkm->offset = GNUNET_htonll (offset); 1439 gkm->next_uid = GNUNET_htonll (next_uid);
1440 gkm->random = random;
1401 gkm->key = *key; 1441 gkm->key = *key;
1402 } 1442 }
1403 qc.rc.proc = proc; 1443 qc.rc.proc = proc;
diff --git a/src/datastore/gnunet-datastore.c b/src/datastore/gnunet-datastore.c
index b3d14c43c..c93bc8dd3 100644
--- a/src/datastore/gnunet-datastore.c
+++ b/src/datastore/gnunet-datastore.c
@@ -171,7 +171,7 @@ static void
171do_get () 171do_get ()
172{ 172{
173 qe = GNUNET_DATASTORE_get_key (db_src, 173 qe = GNUNET_DATASTORE_get_key (db_src,
174 offset, 174 0, false,
175 NULL, GNUNET_BLOCK_TYPE_ANY, 175 NULL, GNUNET_BLOCK_TYPE_ANY,
176 0, 1, 176 0, 1,
177 &do_put, NULL); 177 &do_put, NULL);
@@ -239,10 +239,12 @@ run (void *cls, char *const *args, const char *cfgfile,
239int 239int
240main (int argc, char *const *argv) 240main (int argc, char *const *argv)
241{ 241{
242 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 242 struct GNUNET_GETOPT_CommandLineOption options[] = {
243 { 's', "sourcecfg", "FILENAME", 243 GNUNET_GETOPT_OPTION_FILENAME ('s',
244 gettext_noop ("specifies the configuration to use to access an alternative datastore; will merge that datastore into our current datastore"), 244 "sourcecfg",
245 1, &GNUNET_GETOPT_set_filename, &alternative_cfg }, 245 "FILENAME",
246 gettext_noop ("specifies the configuration to use to access an alternative datastore; will merge that datastore into our current datastore"),
247 &alternative_cfg),
246 GNUNET_GETOPT_OPTION_END 248 GNUNET_GETOPT_OPTION_END
247 }; 249 };
248 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) 250 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
diff --git a/src/datastore/gnunet-service-datastore.c b/src/datastore/gnunet-service-datastore.c
index 1e699fea3..af33c4412 100644
--- a/src/datastore/gnunet-service-datastore.c
+++ b/src/datastore/gnunet-service-datastore.c
@@ -307,7 +307,7 @@ expired_processor (void *cls,
307{ 307{
308 struct GNUNET_TIME_Absolute now; 308 struct GNUNET_TIME_Absolute now;
309 309
310 if (key == NULL) 310 if (NULL == key)
311 { 311 {
312 expired_kill_task = 312 expired_kill_task =
313 GNUNET_SCHEDULER_add_delayed_with_priority (MAX_EXPIRE_DELAY, 313 GNUNET_SCHEDULER_add_delayed_with_priority (MAX_EXPIRE_DELAY,
@@ -529,7 +529,7 @@ transmit_item (void *cls,
529 return GNUNET_OK; 529 return GNUNET_OK;
530 } 530 }
531 GNUNET_assert (sizeof (struct DataMessage) + size < 531 GNUNET_assert (sizeof (struct DataMessage) + size <
532 GNUNET_SERVER_MAX_MESSAGE_SIZE); 532 GNUNET_MAX_MESSAGE_SIZE);
533 env = GNUNET_MQ_msg_extra (dm, 533 env = GNUNET_MQ_msg_extra (dm,
534 size, 534 size,
535 GNUNET_MESSAGE_TYPE_DATASTORE_DATA); 535 GNUNET_MESSAGE_TYPE_DATASTORE_DATA);
@@ -984,12 +984,13 @@ handle_put (void *cls,
984 size, 984 size,
985 &vhash); 985 &vhash);
986 plugin->api->get_key (plugin->api->cls, 986 plugin->api->get_key (plugin->api->cls,
987 0, 987 0,
988 &dm->key, 988 false,
989 &vhash, 989 &dm->key,
990 &vhash,
990 ntohl (dm->type), 991 ntohl (dm->type),
991 &check_present, 992 &check_present,
992 pc); 993 pc);
993 GNUNET_SERVICE_client_continue (client); 994 GNUNET_SERVICE_client_continue (client);
994 return; 995 return;
995 } 996 }
@@ -1018,7 +1019,8 @@ handle_get (void *cls,
1018 1, 1019 1,
1019 GNUNET_NO); 1020 GNUNET_NO);
1020 plugin->api->get_key (plugin->api->cls, 1021 plugin->api->get_key (plugin->api->cls,
1021 GNUNET_ntohll (msg->offset), 1022 GNUNET_ntohll (msg->next_uid),
1023 msg->random,
1022 NULL, 1024 NULL,
1023 NULL, 1025 NULL,
1024 ntohl (msg->type), 1026 ntohl (msg->type),
@@ -1069,7 +1071,8 @@ handle_get_key (void *cls,
1069 return; 1071 return;
1070 } 1072 }
1071 plugin->api->get_key (plugin->api->cls, 1073 plugin->api->get_key (plugin->api->cls,
1072 GNUNET_ntohll (msg->offset), 1074 GNUNET_ntohll (msg->next_uid),
1075 msg->random,
1073 &msg->key, 1076 &msg->key,
1074 NULL, 1077 NULL,
1075 ntohl (msg->type), 1078 ntohl (msg->type),
@@ -1131,7 +1134,7 @@ handle_get_zero_anonymity (void *cls,
1131 1, 1134 1,
1132 GNUNET_NO); 1135 GNUNET_NO);
1133 plugin->api->get_zero_anonymity (plugin->api->cls, 1136 plugin->api->get_zero_anonymity (plugin->api->cls,
1134 GNUNET_ntohll (msg->offset), 1137 GNUNET_ntohll (msg->next_uid),
1135 type, 1138 type,
1136 &transmit_item, 1139 &transmit_item,
1137 client); 1140 client);
@@ -1241,6 +1244,7 @@ handle_remove (void *cls,
1241 (uint32_t) ntohl (dm->type)); 1244 (uint32_t) ntohl (dm->type));
1242 plugin->api->get_key (plugin->api->cls, 1245 plugin->api->get_key (plugin->api->cls,
1243 0, 1246 0,
1247 false,
1244 &dm->key, 1248 &dm->key,
1245 &vhash, 1249 &vhash,
1246 (enum GNUNET_BLOCK_Type) ntohl (dm->type), 1250 (enum GNUNET_BLOCK_Type) ntohl (dm->type),
diff --git a/src/datastore/plugin_datastore_heap.c b/src/datastore/plugin_datastore_heap.c
index 199c03a50..e15cacb5b 100644
--- a/src/datastore/plugin_datastore_heap.c
+++ b/src/datastore/plugin_datastore_heap.c
@@ -323,19 +323,19 @@ struct GetContext
323{ 323{
324 324
325 /** 325 /**
326 * Desired result offset / number of results. 326 * Lowest uid to consider.
327 */ 327 */
328 uint64_t offset; 328 uint64_t next_uid;
329 329
330 /** 330 /**
331 * The plugin. 331 * Value with lowest uid >= next_uid found so far.
332 */ 332 */
333 struct Plugin *plugin; 333 struct Value *value;
334 334
335 /** 335 /**
336 * Requested value hash. 336 * Requested value hash.
337 */ 337 */
338 const struct GNUNET_HashCode * vhash; 338 const struct GNUNET_HashCode *vhash;
339 339
340 /** 340 /**
341 * Requested type. 341 * Requested type.
@@ -343,68 +343,15 @@ struct GetContext
343 enum GNUNET_BLOCK_Type type; 343 enum GNUNET_BLOCK_Type type;
344 344
345 /** 345 /**
346 * Function to call with the result. 346 * If true, return a random value
347 */ 347 */
348 PluginDatumProcessor proc; 348 bool random;
349 349
350 /**
351 * Closure for 'proc'.
352 */
353 void *proc_cls;
354}; 350};
355 351
356 352
357/** 353/**
358 * Test if a value matches the specification from the 'get' context 354 * Obtain the matching value with the lowest uid >= next_uid.
359 *
360 * @param gc query
361 * @param value the value to check against the query
362 * @return GNUNET_YES if the value matches
363 */
364static int
365match (const struct GetContext *gc,
366 struct Value *value)
367{
368 struct GNUNET_HashCode vh;
369
370 if ( (gc->type != GNUNET_BLOCK_TYPE_ANY) &&
371 (gc->type != value->type) )
372 return GNUNET_NO;
373 if (NULL != gc->vhash)
374 {
375 GNUNET_CRYPTO_hash (&value[1], value->size, &vh);
376 if (0 != memcmp (&vh, gc->vhash, sizeof (struct GNUNET_HashCode)))
377 return GNUNET_NO;
378 }
379 return GNUNET_YES;
380}
381
382
383/**
384 * Count number of matching values.
385 *
386 * @param cls the 'struct GetContext'
387 * @param key unused
388 * @param val the 'struct Value'
389 * @return GNUNET_YES (continue iteration)
390 */
391static int
392count_iterator (void *cls,
393 const struct GNUNET_HashCode *key,
394 void *val)
395{
396 struct GetContext *gc = cls;
397 struct Value *value = val;
398
399 if (GNUNET_NO == match (gc, value))
400 return GNUNET_OK;
401 gc->offset++;
402 return GNUNET_OK;
403}
404
405
406/**
407 * Obtain matching value at 'offset'.
408 * 355 *
409 * @param cls the 'struct GetContext' 356 * @param cls the 'struct GetContext'
410 * @param key unused 357 * @param key unused
@@ -418,23 +365,29 @@ get_iterator (void *cls,
418{ 365{
419 struct GetContext *gc = cls; 366 struct GetContext *gc = cls;
420 struct Value *value = val; 367 struct Value *value = val;
368 struct GNUNET_HashCode vh;
421 369
422 if (GNUNET_NO == match (gc, value)) 370 if ( (gc->type != GNUNET_BLOCK_TYPE_ANY) &&
371 (gc->type != value->type) )
423 return GNUNET_OK; 372 return GNUNET_OK;
424 if (0 != gc->offset--) 373 if (NULL != gc->vhash)
374 {
375 GNUNET_CRYPTO_hash (&value[1], value->size, &vh);
376 if (0 != memcmp (&vh, gc->vhash, sizeof (struct GNUNET_HashCode)))
377 return GNUNET_OK;
378 }
379 if (gc->random)
380 {
381 gc->value = value;
382 return GNUNET_NO;
383 }
384 if ( (uint64_t) (intptr_t) value < gc->next_uid)
425 return GNUNET_OK; 385 return GNUNET_OK;
426 if (GNUNET_NO == 386 if ( (NULL != gc->value) &&
427 gc->proc (gc->proc_cls, 387 (value > gc->value) )
428 key, 388 return GNUNET_OK;
429 value->size, 389 gc->value = value;
430 &value[1], 390 return GNUNET_OK;
431 value->type,
432 value->priority,
433 value->anonymity,
434 value->expiration,
435 (uint64_t) (long) value))
436 delete_value (gc->plugin, value);
437 return GNUNET_NO;
438} 391}
439 392
440 393
@@ -442,8 +395,8 @@ get_iterator (void *cls,
442 * Get one of the results for a particular key in the datastore. 395 * Get one of the results for a particular key in the datastore.
443 * 396 *
444 * @param cls closure 397 * @param cls closure
445 * @param offset offset of the result (modulo num-results); 398 * @param next_uid return the result with lowest uid >= next_uid
446 * specific ordering does not matter for the offset 399 * @param random if true, return a random result instead of using next_uid
447 * @param key maybe NULL (to match all entries) 400 * @param key maybe NULL (to match all entries)
448 * @param vhash hash of the value, maybe NULL (to 401 * @param vhash hash of the value, maybe NULL (to
449 * match all values that have the right key). 402 * match all values that have the right key).
@@ -457,7 +410,7 @@ get_iterator (void *cls,
457 * @param proc_cls closure for proc 410 * @param proc_cls closure for proc
458 */ 411 */
459static void 412static void
460heap_plugin_get_key (void *cls, uint64_t offset, 413heap_plugin_get_key (void *cls, uint64_t next_uid, bool random,
461 const struct GNUNET_HashCode *key, 414 const struct GNUNET_HashCode *key,
462 const struct GNUNET_HashCode *vhash, 415 const struct GNUNET_HashCode *vhash,
463 enum GNUNET_BLOCK_Type type, PluginDatumProcessor proc, 416 enum GNUNET_BLOCK_Type type, PluginDatumProcessor proc,
@@ -466,25 +419,14 @@ heap_plugin_get_key (void *cls, uint64_t offset,
466 struct Plugin *plugin = cls; 419 struct Plugin *plugin = cls;
467 struct GetContext gc; 420 struct GetContext gc;
468 421
469 gc.plugin = plugin; 422 gc.value = NULL;
470 gc.offset = 0; 423 gc.next_uid = next_uid;
424 gc.random = random;
471 gc.vhash = vhash; 425 gc.vhash = vhash;
472 gc.type = type; 426 gc.type = type;
473 gc.proc = proc;
474 gc.proc_cls = proc_cls;
475 if (NULL == key) 427 if (NULL == key)
476 { 428 {
477 GNUNET_CONTAINER_multihashmap_iterate (plugin->keyvalue, 429 GNUNET_CONTAINER_multihashmap_iterate (plugin->keyvalue,
478 &count_iterator,
479 &gc);
480 if (0 == gc.offset)
481 {
482 proc (proc_cls,
483 NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
484 return;
485 }
486 gc.offset = offset % gc.offset;
487 GNUNET_CONTAINER_multihashmap_iterate (plugin->keyvalue,
488 &get_iterator, 430 &get_iterator,
489 &gc); 431 &gc);
490 } 432 }
@@ -492,20 +434,27 @@ heap_plugin_get_key (void *cls, uint64_t offset,
492 { 434 {
493 GNUNET_CONTAINER_multihashmap_get_multiple (plugin->keyvalue, 435 GNUNET_CONTAINER_multihashmap_get_multiple (plugin->keyvalue,
494 key, 436 key,
495 &count_iterator,
496 &gc);
497 if (0 == gc.offset)
498 {
499 proc (proc_cls,
500 NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
501 return;
502 }
503 gc.offset = offset % gc.offset;
504 GNUNET_CONTAINER_multihashmap_get_multiple (plugin->keyvalue,
505 key,
506 &get_iterator, 437 &get_iterator,
507 &gc); 438 &gc);
508 } 439 }
440 if (NULL == gc.value)
441 {
442 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
443 return;
444 }
445 if (GNUNET_NO ==
446 proc (proc_cls,
447 &gc.value->key,
448 gc.value->size,
449 &gc.value[1],
450 gc.value->type,
451 gc.value->priority,
452 gc.value->anonymity,
453 gc.value->expiration,
454 (uint64_t) (intptr_t) gc.value))
455 {
456 delete_value (plugin, gc.value);
457 }
509} 458}
510 459
511 460
@@ -559,7 +508,7 @@ heap_plugin_get_replication (void *cls,
559 value->priority, 508 value->priority,
560 value->anonymity, 509 value->anonymity,
561 value->expiration, 510 value->expiration,
562 (uint64_t) (long) value)) 511 (uint64_t) (intptr_t) value))
563 delete_value (plugin, value); 512 delete_value (plugin, value);
564} 513}
565 514
@@ -595,7 +544,7 @@ heap_plugin_get_expiration (void *cls, PluginDatumProcessor proc,
595 value->priority, 544 value->priority,
596 value->anonymity, 545 value->anonymity,
597 value->expiration, 546 value->expiration,
598 (uint64_t) (long) value)) 547 (uint64_t) (intptr_t) value))
599 delete_value (plugin, value); 548 delete_value (plugin, value);
600} 549}
601 550
@@ -628,7 +577,7 @@ heap_plugin_update (void *cls,
628{ 577{
629 struct Value *value; 578 struct Value *value;
630 579
631 value = (struct Value*) (long) uid; 580 value = (struct Value*) (intptr_t) uid;
632 GNUNET_assert (NULL != value); 581 GNUNET_assert (NULL != value);
633 if (value->expiration.abs_value_us != expire.abs_value_us) 582 if (value->expiration.abs_value_us != expire.abs_value_us)
634 { 583 {
@@ -649,53 +598,43 @@ heap_plugin_update (void *cls,
649 * Call the given processor on an item with zero anonymity. 598 * Call the given processor on an item with zero anonymity.
650 * 599 *
651 * @param cls our "struct Plugin*" 600 * @param cls our "struct Plugin*"
652 * @param offset offset of the result (modulo num-results); 601 * @param next_uid return the result with lowest uid >= next_uid
653 * specific ordering does not matter for the offset
654 * @param type entries of which type should be considered? 602 * @param type entries of which type should be considered?
655 * Use 0 for any type. 603 * Must not be zero (ANY).
656 * @param proc function to call on each matching value; 604 * @param proc function to call on each matching value;
657 * will be called with NULL if no value matches 605 * will be called with NULL if no value matches
658 * @param proc_cls closure for proc 606 * @param proc_cls closure for proc
659 */ 607 */
660static void 608static void
661heap_plugin_get_zero_anonymity (void *cls, uint64_t offset, 609heap_plugin_get_zero_anonymity (void *cls, uint64_t next_uid,
662 enum GNUNET_BLOCK_Type type, 610 enum GNUNET_BLOCK_Type type,
663 PluginDatumProcessor proc, void *proc_cls) 611 PluginDatumProcessor proc, void *proc_cls)
664{ 612{
665 struct Plugin *plugin = cls; 613 struct Plugin *plugin = cls;
666 struct ZeroAnonByType *zabt; 614 struct ZeroAnonByType *zabt;
667 struct Value *value; 615 struct Value *value = NULL;
668 uint64_t count;
669 616
670 count = 0;
671 for (zabt = plugin->zero_head; NULL != zabt; zabt = zabt->next) 617 for (zabt = plugin->zero_head; NULL != zabt; zabt = zabt->next)
672 { 618 {
673 if ( (type != GNUNET_BLOCK_TYPE_ANY) && 619 if ( (type != GNUNET_BLOCK_TYPE_ANY) &&
674 (type != zabt->type) ) 620 (type != zabt->type) )
675 continue; 621 continue;
676 count += zabt->array_pos; 622 for (int i = 0; i < zabt->array_pos; ++i)
623 {
624 if ( (uint64_t) (intptr_t) zabt->array[i] < next_uid)
625 continue;
626 if ( (NULL != value) &&
627 (zabt->array[i] > value) )
628 continue;
629 value = zabt->array[i];
630 }
677 } 631 }
678 if (0 == count) 632 if (NULL == value)
679 { 633 {
680 proc (proc_cls, 634 proc (proc_cls,
681 NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); 635 NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
682 return; 636 return;
683 } 637 }
684 offset = offset % count;
685 for (zabt = plugin->zero_head; NULL != zabt; zabt = zabt->next)
686 {
687 if ( (type != GNUNET_BLOCK_TYPE_ANY) &&
688 (type != zabt->type) )
689 continue;
690 if (offset >= zabt->array_pos)
691 {
692 offset -= zabt->array_pos;
693 continue;
694 }
695 break;
696 }
697 GNUNET_assert (NULL != zabt);
698 value = zabt->array[offset];
699 if (GNUNET_NO == 638 if (GNUNET_NO ==
700 proc (proc_cls, 639 proc (proc_cls,
701 &value->key, 640 &value->key,
@@ -705,7 +644,7 @@ heap_plugin_get_zero_anonymity (void *cls, uint64_t offset,
705 value->priority, 644 value->priority,
706 value->anonymity, 645 value->anonymity,
707 value->expiration, 646 value->expiration,
708 (uint64_t) (long) value)) 647 (uint64_t) (intptr_t) value))
709 delete_value (plugin, value); 648 delete_value (plugin, value);
710} 649}
711 650
diff --git a/src/datastore/plugin_datastore_mysql.c b/src/datastore/plugin_datastore_mysql.c
index 1067064aa..5ae4485cb 100644
--- a/src/datastore/plugin_datastore_mysql.c
+++ b/src/datastore/plugin_datastore_mysql.c
@@ -150,28 +150,19 @@ struct Plugin
150#define DELETE_ENTRY_BY_UID "DELETE FROM gn090 WHERE uid=?" 150#define DELETE_ENTRY_BY_UID "DELETE FROM gn090 WHERE uid=?"
151 struct GNUNET_MYSQL_StatementHandle *delete_entry_by_uid; 151 struct GNUNET_MYSQL_StatementHandle *delete_entry_by_uid;
152 152
153#define COUNT_ENTRY_BY_HASH "SELECT count(*) FROM gn090 FORCE INDEX (idx_hash) WHERE hash=?" 153#define SELECT_ENTRY "SELECT type,prio,anonLevel,expire,hash,value,uid FROM gn090 WHERE uid >= ? AND (rvalue >= ? OR 0 = ?) ORDER BY uid LIMIT 1"
154 struct GNUNET_MYSQL_StatementHandle *count_entry_by_hash; 154 struct GNUNET_MYSQL_StatementHandle *select_entry;
155 155
156#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 ?" 156#define SELECT_ENTRY_BY_HASH "SELECT type,prio,anonLevel,expire,hash,value,uid FROM gn090 FORCE INDEX (idx_hash) WHERE hash=? AND uid >= ? AND (rvalue >= ? OR 0 = ?) ORDER BY uid LIMIT 1"
157 struct GNUNET_MYSQL_StatementHandle *select_entry_by_hash; 157 struct GNUNET_MYSQL_StatementHandle *select_entry_by_hash;
158 158
159#define COUNT_ENTRY_BY_HASH_AND_VHASH "SELECT count(*) FROM gn090 FORCE INDEX (idx_hash_vhash) WHERE hash=? AND vhash=?" 159#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=? AND uid >= ? AND (rvalue >= ? OR 0 = ?) ORDER BY uid LIMIT 1"
160 struct GNUNET_MYSQL_StatementHandle *count_entry_by_hash_and_vhash;
161
162#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 ?"
163 struct GNUNET_MYSQL_StatementHandle *select_entry_by_hash_and_vhash; 160 struct GNUNET_MYSQL_StatementHandle *select_entry_by_hash_and_vhash;
164 161
165#define COUNT_ENTRY_BY_HASH_AND_TYPE "SELECT count(*) FROM gn090 FORCE INDEX (idx_hash_type_uid) WHERE hash=? AND type=?" 162#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=? AND uid >= ? AND (rvalue >= ? OR 0 = ?) ORDER BY uid LIMIT 1"
166 struct GNUNET_MYSQL_StatementHandle *count_entry_by_hash_and_type;
167
168#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 ?"
169 struct GNUNET_MYSQL_StatementHandle *select_entry_by_hash_and_type; 163 struct GNUNET_MYSQL_StatementHandle *select_entry_by_hash_and_type;
170 164
171#define COUNT_ENTRY_BY_HASH_VHASH_AND_TYPE "SELECT count(*) FROM gn090 FORCE INDEX (idx_hash_vhash) WHERE hash=? AND vhash=? AND type=?" 165#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=? AND uid >= ? AND (rvalue >= ? OR 0 = ?) ORDER BY uid LIMIT 1"
172 struct GNUNET_MYSQL_StatementHandle *count_entry_by_hash_vhash_and_type;
173
174#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 ?"
175 struct GNUNET_MYSQL_StatementHandle *select_entry_by_hash_vhash_and_type; 166 struct GNUNET_MYSQL_StatementHandle *select_entry_by_hash_vhash_and_type;
176 167
177#define UPDATE_ENTRY "UPDATE gn090 SET prio=prio+?,expire=IF(expire>=?,expire,?) WHERE uid=?" 168#define UPDATE_ENTRY "UPDATE gn090 SET prio=prio+?,expire=IF(expire>=?,expire,?) WHERE uid=?"
@@ -185,10 +176,8 @@ struct Plugin
185 176
186#define SELECT_IT_NON_ANONYMOUS "SELECT type,prio,anonLevel,expire,hash,value,uid "\ 177#define SELECT_IT_NON_ANONYMOUS "SELECT type,prio,anonLevel,expire,hash,value,uid "\
187 "FROM gn090 FORCE INDEX (idx_anonLevel_type_rvalue) "\ 178 "FROM gn090 FORCE INDEX (idx_anonLevel_type_rvalue) "\
188 "WHERE anonLevel=0 AND type=? AND "\ 179 "WHERE anonLevel=0 AND type=? AND uid >= ? "\
189 "(rvalue >= ? OR"\ 180 "ORDER BY uid LIMIT 1"
190 " NOT EXISTS (SELECT 1 FROM gn090 FORCE INDEX (idx_anonLevel_type_rvalue) WHERE anonLevel=0 AND type=? AND rvalue>=?)) "\
191 "ORDER BY rvalue ASC LIMIT 1"
192 struct GNUNET_MYSQL_StatementHandle *zero_iter; 181 struct GNUNET_MYSQL_StatementHandle *zero_iter;
193 182
194#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" 183#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"
@@ -541,8 +530,8 @@ execute_select (struct Plugin *plugin,
541 * Get one of the results for a particular key in the datastore. 530 * Get one of the results for a particular key in the datastore.
542 * 531 *
543 * @param cls closure 532 * @param cls closure
544 * @param offset offset of the result (modulo num-results); 533 * @param next_uid return the result with lowest uid >= next_uid
545 * specific ordering does not matter for the offset 534 * @param random if true, return a random result instead of using next_uid
546 * @param key key to match, never NULL 535 * @param key key to match, never NULL
547 * @param vhash hash of the value, maybe NULL (to 536 * @param vhash hash of the value, maybe NULL (to
548 * match all values that have the right key). 537 * match all values that have the right key).
@@ -557,7 +546,8 @@ execute_select (struct Plugin *plugin,
557 */ 546 */
558static void 547static void
559mysql_plugin_get_key (void *cls, 548mysql_plugin_get_key (void *cls,
560 uint64_t offset, 549 uint64_t next_uid,
550 bool random,
561 const struct GNUNET_HashCode *key, 551 const struct GNUNET_HashCode *key,
562 const struct GNUNET_HashCode *vhash, 552 const struct GNUNET_HashCode *vhash,
563 enum GNUNET_BLOCK_Type type, 553 enum GNUNET_BLOCK_Type type,
@@ -565,121 +555,33 @@ mysql_plugin_get_key (void *cls,
565 void *proc_cls) 555 void *proc_cls)
566{ 556{
567 struct Plugin *plugin = cls; 557 struct Plugin *plugin = cls;
568 int ret; 558 uint64_t rvalue;
569 uint64_t total;
570 struct GNUNET_MY_ResultSpec results_get[] = {
571 GNUNET_MY_result_spec_uint64 (&total),
572 GNUNET_MY_result_spec_end
573 };
574 559
575 total = UINT64_MAX; 560 if (random)
576 if (0 != type)
577 { 561 {
578 if (NULL != vhash) 562 rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
579 { 563 UINT64_MAX);
580 struct GNUNET_MY_QueryParam params_get[] = { 564 next_uid = 0;
581 GNUNET_MY_query_param_auto_from_type (key),
582 GNUNET_MY_query_param_auto_from_type (vhash),
583 GNUNET_MY_query_param_uint32 (&type),
584 GNUNET_MY_query_param_end
585 };
586
587 ret =
588 GNUNET_MY_exec_prepared (plugin->mc,
589 plugin->count_entry_by_hash_vhash_and_type,
590 params_get);
591 GNUNET_break (GNUNET_OK == ret);
592 if (GNUNET_OK == ret)
593 ret =
594 GNUNET_MY_extract_result (plugin->count_entry_by_hash_vhash_and_type,
595 results_get);
596 if (GNUNET_OK == ret)
597 GNUNET_break (GNUNET_NO ==
598 GNUNET_MY_extract_result (plugin->count_entry_by_hash_vhash_and_type,
599 NULL));
600 }
601 else
602 {
603 struct GNUNET_MY_QueryParam params_get[] = {
604 GNUNET_MY_query_param_auto_from_type (key),
605 GNUNET_MY_query_param_uint32 (&type),
606 GNUNET_MY_query_param_end
607 };
608
609 ret =
610 GNUNET_MY_exec_prepared (plugin->mc,
611 plugin->count_entry_by_hash_and_type,
612 params_get);
613 GNUNET_break (GNUNET_OK == ret);
614 if (GNUNET_OK == ret)
615 ret =
616 GNUNET_MY_extract_result (plugin->count_entry_by_hash_and_type,
617 results_get);
618 if (GNUNET_OK == ret)
619 GNUNET_break (GNUNET_NO ==
620 GNUNET_MY_extract_result (plugin->count_entry_by_hash_and_type,
621 NULL));
622 }
623 } 565 }
624 else 566 else
625 { 567 rvalue = 0;
626 if (NULL != vhash)
627 {
628 struct GNUNET_MY_QueryParam params_get[] = {
629 GNUNET_MY_query_param_auto_from_type (key),
630 GNUNET_MY_query_param_auto_from_type (vhash),
631 GNUNET_MY_query_param_end
632 };
633 568
634 ret = 569 if (NULL == key)
635 GNUNET_MY_exec_prepared (plugin->mc,
636 plugin->count_entry_by_hash_and_vhash,
637 params_get);
638 GNUNET_break (GNUNET_OK == ret);
639 if (GNUNET_OK == ret)
640 ret =
641 GNUNET_MY_extract_result (plugin->count_entry_by_hash_and_vhash,
642 results_get);
643 if (GNUNET_OK == ret)
644 GNUNET_break (GNUNET_NO ==
645 GNUNET_MY_extract_result (plugin->count_entry_by_hash_and_vhash,
646 NULL));
647 }
648 else
649 {
650 struct GNUNET_MY_QueryParam params_get[] = {
651 GNUNET_MY_query_param_auto_from_type (key),
652 GNUNET_MY_query_param_end
653 };
654
655 ret =
656 GNUNET_MY_exec_prepared (plugin->mc,
657 plugin->count_entry_by_hash,
658 params_get);
659 GNUNET_break (GNUNET_OK == ret);
660 if (GNUNET_OK == ret)
661 ret =
662 GNUNET_MY_extract_result (plugin->count_entry_by_hash,
663 results_get);
664 if (GNUNET_OK == ret)
665 GNUNET_break (GNUNET_NO ==
666 GNUNET_MY_extract_result (plugin->count_entry_by_hash,
667 NULL));
668 }
669 }
670 if ( (GNUNET_OK != ret) ||
671 (0 >= total) )
672 { 570 {
673 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); 571 struct GNUNET_MY_QueryParam params_select[] = {
674 return; 572 GNUNET_MY_query_param_uint64 (&next_uid),
573 GNUNET_MY_query_param_uint64 (&rvalue),
574 GNUNET_MY_query_param_uint64 (&rvalue),
575 GNUNET_MY_query_param_end
576 };
577
578 execute_select (plugin,
579 plugin->select_entry,
580 proc,
581 proc_cls,
582 params_select);
675 } 583 }
676 offset = offset % total; 584 else if (type != GNUNET_BLOCK_TYPE_ANY)
677 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
678 "Obtaining %llu/%lld result for GET `%s'\n",
679 (unsigned long long) offset,
680 (unsigned long long) total,
681 GNUNET_h2s (key));
682 if (type != GNUNET_BLOCK_TYPE_ANY)
683 { 585 {
684 if (NULL != vhash) 586 if (NULL != vhash)
685 { 587 {
@@ -687,7 +589,9 @@ mysql_plugin_get_key (void *cls,
687 GNUNET_MY_query_param_auto_from_type (key), 589 GNUNET_MY_query_param_auto_from_type (key),
688 GNUNET_MY_query_param_auto_from_type (vhash), 590 GNUNET_MY_query_param_auto_from_type (vhash),
689 GNUNET_MY_query_param_uint32 (&type), 591 GNUNET_MY_query_param_uint32 (&type),
690 GNUNET_MY_query_param_uint64 (&offset), 592 GNUNET_MY_query_param_uint64 (&next_uid),
593 GNUNET_MY_query_param_uint64 (&rvalue),
594 GNUNET_MY_query_param_uint64 (&rvalue),
691 GNUNET_MY_query_param_end 595 GNUNET_MY_query_param_end
692 }; 596 };
693 597
@@ -702,7 +606,9 @@ mysql_plugin_get_key (void *cls,
702 struct GNUNET_MY_QueryParam params_select[] = { 606 struct GNUNET_MY_QueryParam params_select[] = {
703 GNUNET_MY_query_param_auto_from_type (key), 607 GNUNET_MY_query_param_auto_from_type (key),
704 GNUNET_MY_query_param_uint32 (&type), 608 GNUNET_MY_query_param_uint32 (&type),
705 GNUNET_MY_query_param_uint64 (&offset), 609 GNUNET_MY_query_param_uint64 (&next_uid),
610 GNUNET_MY_query_param_uint64 (&rvalue),
611 GNUNET_MY_query_param_uint64 (&rvalue),
706 GNUNET_MY_query_param_end 612 GNUNET_MY_query_param_end
707 }; 613 };
708 614
@@ -720,7 +626,9 @@ mysql_plugin_get_key (void *cls,
720 struct GNUNET_MY_QueryParam params_select[] = { 626 struct GNUNET_MY_QueryParam params_select[] = {
721 GNUNET_MY_query_param_auto_from_type (key), 627 GNUNET_MY_query_param_auto_from_type (key),
722 GNUNET_MY_query_param_auto_from_type (vhash), 628 GNUNET_MY_query_param_auto_from_type (vhash),
723 GNUNET_MY_query_param_uint64 (&offset), 629 GNUNET_MY_query_param_uint64 (&next_uid),
630 GNUNET_MY_query_param_uint64 (&rvalue),
631 GNUNET_MY_query_param_uint64 (&rvalue),
724 GNUNET_MY_query_param_end 632 GNUNET_MY_query_param_end
725 }; 633 };
726 634
@@ -734,7 +642,9 @@ mysql_plugin_get_key (void *cls,
734 { 642 {
735 struct GNUNET_MY_QueryParam params_select[] = { 643 struct GNUNET_MY_QueryParam params_select[] = {
736 GNUNET_MY_query_param_auto_from_type (key), 644 GNUNET_MY_query_param_auto_from_type (key),
737 GNUNET_MY_query_param_uint64 (&offset), 645 GNUNET_MY_query_param_uint64 (&next_uid),
646 GNUNET_MY_query_param_uint64 (&rvalue),
647 GNUNET_MY_query_param_uint64 (&rvalue),
738 GNUNET_MY_query_param_end 648 GNUNET_MY_query_param_end
739 }; 649 };
740 650
@@ -753,28 +663,26 @@ mysql_plugin_get_key (void *cls,
753 * Get a zero-anonymity datum from the datastore. 663 * Get a zero-anonymity datum from the datastore.
754 * 664 *
755 * @param cls our `struct Plugin *` 665 * @param cls our `struct Plugin *`
756 * @param offset offset of the result 666 * @param next_uid return the result with lowest uid >= next_uid
757 * @param type entries of which type should be considered? 667 * @param type entries of which type should be considered?
758 * Use 0 for any type. 668 * Must not be zero (ANY).
759 * @param proc function to call on a matching value or NULL 669 * @param proc function to call on a matching value;
670 * will be called with NULL if no value matches
760 * @param proc_cls closure for @a proc 671 * @param proc_cls closure for @a proc
761 */ 672 */
762static void 673static void
763mysql_plugin_get_zero_anonymity (void *cls, 674mysql_plugin_get_zero_anonymity (void *cls,
764 uint64_t offset, 675 uint64_t next_uid,
765 enum GNUNET_BLOCK_Type type, 676 enum GNUNET_BLOCK_Type type,
766 PluginDatumProcessor proc, 677 PluginDatumProcessor proc,
767 void *proc_cls) 678 void *proc_cls)
768{ 679{
769 struct Plugin *plugin = cls; 680 struct Plugin *plugin = cls;
770 uint32_t typei = (uint32_t) type; 681 uint32_t typei = (uint32_t) type;
771 uint64_t rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, 682
772 UINT64_MAX);
773 struct GNUNET_MY_QueryParam params_zero_iter[] = { 683 struct GNUNET_MY_QueryParam params_zero_iter[] = {
774 GNUNET_MY_query_param_uint32 (&typei), 684 GNUNET_MY_query_param_uint32 (&typei),
775 GNUNET_MY_query_param_uint64 (&rvalue), 685 GNUNET_MY_query_param_uint64 (&next_uid),
776 GNUNET_MY_query_param_uint32 (&typei),
777 GNUNET_MY_query_param_uint64 (&rvalue),
778 GNUNET_MY_query_param_end 686 GNUNET_MY_query_param_end
779 }; 687 };
780 688
@@ -1209,6 +1117,7 @@ libgnunet_plugin_datastore_mysql_init (void *cls)
1209 ") ENGINE=InnoDB") || MRUNS ("SET AUTOCOMMIT = 1") || 1117 ") ENGINE=InnoDB") || MRUNS ("SET AUTOCOMMIT = 1") ||
1210 PINIT (plugin->insert_entry, INSERT_ENTRY) || 1118 PINIT (plugin->insert_entry, INSERT_ENTRY) ||
1211 PINIT (plugin->delete_entry_by_uid, DELETE_ENTRY_BY_UID) || 1119 PINIT (plugin->delete_entry_by_uid, DELETE_ENTRY_BY_UID) ||
1120 PINIT (plugin->select_entry, SELECT_ENTRY) ||
1212 PINIT (plugin->select_entry_by_hash, SELECT_ENTRY_BY_HASH) || 1121 PINIT (plugin->select_entry_by_hash, SELECT_ENTRY_BY_HASH) ||
1213 PINIT (plugin->select_entry_by_hash_and_vhash, 1122 PINIT (plugin->select_entry_by_hash_and_vhash,
1214 SELECT_ENTRY_BY_HASH_AND_VHASH) || 1123 SELECT_ENTRY_BY_HASH_AND_VHASH) ||
@@ -1216,13 +1125,7 @@ libgnunet_plugin_datastore_mysql_init (void *cls)
1216 SELECT_ENTRY_BY_HASH_AND_TYPE) || 1125 SELECT_ENTRY_BY_HASH_AND_TYPE) ||
1217 PINIT (plugin->select_entry_by_hash_vhash_and_type, 1126 PINIT (plugin->select_entry_by_hash_vhash_and_type,
1218 SELECT_ENTRY_BY_HASH_VHASH_AND_TYPE) || 1127 SELECT_ENTRY_BY_HASH_VHASH_AND_TYPE) ||
1219 PINIT (plugin->count_entry_by_hash, COUNT_ENTRY_BY_HASH) ||
1220 PINIT (plugin->get_size, SELECT_SIZE) || 1128 PINIT (plugin->get_size, SELECT_SIZE) ||
1221 PINIT (plugin->count_entry_by_hash_and_vhash,
1222 COUNT_ENTRY_BY_HASH_AND_VHASH) ||
1223 PINIT (plugin->count_entry_by_hash_and_type, COUNT_ENTRY_BY_HASH_AND_TYPE)
1224 || PINIT (plugin->count_entry_by_hash_vhash_and_type,
1225 COUNT_ENTRY_BY_HASH_VHASH_AND_TYPE) ||
1226 PINIT (plugin->update_entry, UPDATE_ENTRY) || 1129 PINIT (plugin->update_entry, UPDATE_ENTRY) ||
1227 PINIT (plugin->dec_repl, DEC_REPL) || 1130 PINIT (plugin->dec_repl, DEC_REPL) ||
1228 PINIT (plugin->zero_iter, SELECT_IT_NON_ANONYMOUS) || 1131 PINIT (plugin->zero_iter, SELECT_IT_NON_ANONYMOUS) ||
diff --git a/src/datastore/plugin_datastore_postgres.c b/src/datastore/plugin_datastore_postgres.c
index 7b04cc68a..0376ebb6c 100644
--- a/src/datastore/plugin_datastore_postgres.c
+++ b/src/datastore/plugin_datastore_postgres.c
@@ -80,6 +80,7 @@ init_connection (struct Plugin *plugin)
80 * we only test equality on it and can cast it to/from uint32_t. For repl, prio, and anonLevel 80 * we only test equality on it and can cast it to/from uint32_t. For repl, prio, and anonLevel
81 * we do math or inequality tests, so we can't handle the entire range of uint32_t. 81 * we do math or inequality tests, so we can't handle the entire range of uint32_t.
82 * This will also cause problems for expiration times after 294247-01-10-04:00:54 UTC. 82 * This will also cause problems for expiration times after 294247-01-10-04:00:54 UTC.
83 * PostgreSQL also recommends against using WITH OIDS.
83 */ 84 */
84 ret = 85 ret =
85 PQexec (plugin->dbh, 86 PQexec (plugin->dbh,
@@ -114,13 +115,17 @@ init_connection (struct Plugin *plugin)
114 if (PQresultStatus (ret) == PGRES_COMMAND_OK) 115 if (PQresultStatus (ret) == PGRES_COMMAND_OK)
115 { 116 {
116 if ((GNUNET_OK != 117 if ((GNUNET_OK !=
117 GNUNET_POSTGRES_exec (plugin->dbh, "CREATE INDEX IF NOT EXISTS idx_hash ON gn090 (hash)")) || 118 GNUNET_POSTGRES_exec (plugin->dbh,
119 "CREATE INDEX IF NOT EXISTS idx_hash ON gn090 (hash)")) ||
118 (GNUNET_OK != 120 (GNUNET_OK !=
119 GNUNET_POSTGRES_exec (plugin->dbh, "CREATE INDEX IF NOT EXISTS idx_hash_vhash ON gn090 (hash,vhash)")) || 121 GNUNET_POSTGRES_exec (plugin->dbh,
122 "CREATE INDEX IF NOT EXISTS idx_hash_vhash ON gn090 (hash,vhash)")) ||
120 (GNUNET_OK != 123 (GNUNET_OK !=
121 GNUNET_POSTGRES_exec (plugin->dbh, "CREATE INDEX IF NOT EXISTS idx_prio ON gn090 (prio)")) || 124 GNUNET_POSTGRES_exec (plugin->dbh,
125 "CREATE INDEX IF NOT EXISTS idx_prio ON gn090 (prio)")) ||
122 (GNUNET_OK != 126 (GNUNET_OK !=
123 GNUNET_POSTGRES_exec (plugin->dbh, "CREATE INDEX IF NOT EXISTS idx_expire ON gn090 (expire)")) || 127 GNUNET_POSTGRES_exec (plugin->dbh,
128 "CREATE INDEX IF NOT EXISTS idx_expire ON gn090 (expire)")) ||
124 (GNUNET_OK != 129 (GNUNET_OK !=
125 GNUNET_POSTGRES_exec (plugin->dbh, 130 GNUNET_POSTGRES_exec (plugin->dbh,
126 "CREATE INDEX IF NOT EXISTS idx_prio_anon ON gn090 (prio,anonLevel)")) || 131 "CREATE INDEX IF NOT EXISTS idx_prio_anon ON gn090 (prio,anonLevel)")) ||
@@ -128,9 +133,11 @@ init_connection (struct Plugin *plugin)
128 GNUNET_POSTGRES_exec (plugin->dbh, 133 GNUNET_POSTGRES_exec (plugin->dbh,
129 "CREATE INDEX IF NOT EXISTS idx_prio_hash_anon ON gn090 (prio,hash,anonLevel)")) || 134 "CREATE INDEX IF NOT EXISTS idx_prio_hash_anon ON gn090 (prio,hash,anonLevel)")) ||
130 (GNUNET_OK != 135 (GNUNET_OK !=
131 GNUNET_POSTGRES_exec (plugin->dbh, "CREATE INDEX IF NOT EXISTS idx_repl_rvalue ON gn090 (repl,rvalue)")) || 136 GNUNET_POSTGRES_exec (plugin->dbh,
137 "CREATE INDEX IF NOT EXISTS idx_repl_rvalue ON gn090 (repl,rvalue)")) ||
132 (GNUNET_OK != 138 (GNUNET_OK !=
133 GNUNET_POSTGRES_exec (plugin->dbh, "CREATE INDEX IF NOT EXISTS idx_expire_hash ON gn090 (expire,hash)"))) 139 GNUNET_POSTGRES_exec (plugin->dbh,
140 "CREATE INDEX IF NOT EXISTS idx_expire_hash ON gn090 (expire,hash)")))
134 { 141 {
135 PQclear (ret); 142 PQclear (ret);
136 PQfinish (plugin->dbh); 143 PQfinish (plugin->dbh);
@@ -170,40 +177,18 @@ init_connection (struct Plugin *plugin)
170 } 177 }
171 PQclear (ret); 178 PQclear (ret);
172 if ((GNUNET_OK != 179 if ((GNUNET_OK !=
173 GNUNET_POSTGRES_prepare (plugin->dbh, "getvt",
174 "SELECT type, prio, anonLevel, expire, hash, value, oid FROM gn090 "
175 "WHERE hash=$1 AND vhash=$2 AND type=$3 "
176 "ORDER BY oid ASC LIMIT 1 OFFSET $4", 4)) ||
177 (GNUNET_OK !=
178 GNUNET_POSTGRES_prepare (plugin->dbh, "gett",
179 "SELECT type, prio, anonLevel, expire, hash, value, oid FROM gn090 "
180 "WHERE hash=$1 AND type=$2 "
181 "ORDER BY oid ASC LIMIT 1 OFFSET $3", 3)) ||
182 (GNUNET_OK !=
183 GNUNET_POSTGRES_prepare (plugin->dbh, "getv",
184 "SELECT type, prio, anonLevel, expire, hash, value, oid FROM gn090 "
185 "WHERE hash=$1 AND vhash=$2 "
186 "ORDER BY oid ASC LIMIT 1 OFFSET $3", 3)) ||
187 (GNUNET_OK !=
188 GNUNET_POSTGRES_prepare (plugin->dbh, "get", 180 GNUNET_POSTGRES_prepare (plugin->dbh, "get",
189 "SELECT type, prio, anonLevel, expire, hash, value, oid FROM gn090 " 181 "SELECT type, prio, anonLevel, expire, hash, value, oid FROM gn090 "
190 "WHERE hash=$1 " "ORDER BY oid ASC LIMIT 1 OFFSET $2", 2)) || 182 "WHERE oid >= $1::bigint AND "
191 (GNUNET_OK != 183 "(rvalue >= $2 OR 0 = $3::smallint) AND "
192 GNUNET_POSTGRES_prepare (plugin->dbh, "count_getvt", 184 "(hash = $4 OR 0 = $5::smallint) AND "
193 "SELECT count(*) FROM gn090 WHERE hash=$1 AND vhash=$2 AND type=$3", 3)) || 185 "(vhash = $6 OR 0 = $7::smallint) AND "
194 (GNUNET_OK != 186 "(type = $8 OR 0 = $9::smallint) "
195 GNUNET_POSTGRES_prepare (plugin->dbh, "count_gett", 187 "ORDER BY oid ASC LIMIT 1", 9)) ||
196 "SELECT count(*) FROM gn090 WHERE hash=$1 AND type=$2", 2)) ||
197 (GNUNET_OK !=
198 GNUNET_POSTGRES_prepare (plugin->dbh, "count_getv",
199 "SELECT count(*) FROM gn090 WHERE hash=$1 AND vhash=$2", 2)) ||
200 (GNUNET_OK !=
201 GNUNET_POSTGRES_prepare (plugin->dbh, "count_get",
202 "SELECT count(*) FROM gn090 WHERE hash=$1", 1)) ||
203 (GNUNET_OK != 188 (GNUNET_OK !=
204 GNUNET_POSTGRES_prepare (plugin->dbh, "put", 189 GNUNET_POSTGRES_prepare (plugin->dbh, "put",
205 "INSERT INTO gn090 (repl, type, prio, anonLevel, expire, rvalue, hash, vhash, value) " 190 "INSERT INTO gn090 (repl, type, prio, anonLevel, expire, rvalue, hash, vhash, value) "
206 "VALUES ($1, $2, $3, $4, $5, RANDOM(), $6, $7, $8)", 9)) || 191 "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)", 9)) ||
207 (GNUNET_OK != 192 (GNUNET_OK !=
208 GNUNET_POSTGRES_prepare (plugin->dbh, "update", 193 GNUNET_POSTGRES_prepare (plugin->dbh, "update",
209 "UPDATE gn090 SET prio = prio + $1, expire = CASE WHEN expire < $2 THEN $2 ELSE expire END " 194 "UPDATE gn090 SET prio = prio + $1, expire = CASE WHEN expire < $2 THEN $2 ELSE expire END "
@@ -215,8 +200,9 @@ init_connection (struct Plugin *plugin)
215 (GNUNET_OK != 200 (GNUNET_OK !=
216 GNUNET_POSTGRES_prepare (plugin->dbh, "select_non_anonymous", 201 GNUNET_POSTGRES_prepare (plugin->dbh, "select_non_anonymous",
217 "SELECT type, prio, anonLevel, expire, hash, value, oid FROM gn090 " 202 "SELECT type, prio, anonLevel, expire, hash, value, oid FROM gn090 "
218 "WHERE anonLevel = 0 AND type = $1 ORDER BY oid DESC LIMIT 1 OFFSET $2", 203 "WHERE anonLevel = 0 AND type = $1 AND oid >= $2::bigint "
219 1)) || 204 "ORDER BY oid ASC LIMIT 1",
205 2)) ||
220 (GNUNET_OK != 206 (GNUNET_OK !=
221 GNUNET_POSTGRES_prepare (plugin->dbh, "select_expiration_order", 207 GNUNET_POSTGRES_prepare (plugin->dbh, "select_expiration_order",
222 "(SELECT type, prio, anonLevel, expire, hash, value, oid FROM gn090 " 208 "(SELECT type, prio, anonLevel, expire, hash, value, oid FROM gn090 "
@@ -322,6 +308,8 @@ postgres_plugin_put (void *cls,
322 struct Plugin *plugin = cls; 308 struct Plugin *plugin = cls;
323 uint32_t utype = type; 309 uint32_t utype = type;
324 struct GNUNET_HashCode vhash; 310 struct GNUNET_HashCode vhash;
311 uint64_t rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
312 UINT64_MAX);
325 PGresult *ret; 313 PGresult *ret;
326 struct GNUNET_PQ_QueryParam params[] = { 314 struct GNUNET_PQ_QueryParam params[] = {
327 GNUNET_PQ_query_param_uint32 (&replication), 315 GNUNET_PQ_query_param_uint32 (&replication),
@@ -329,6 +317,7 @@ postgres_plugin_put (void *cls,
329 GNUNET_PQ_query_param_uint32 (&priority), 317 GNUNET_PQ_query_param_uint32 (&priority),
330 GNUNET_PQ_query_param_uint32 (&anonymity), 318 GNUNET_PQ_query_param_uint32 (&anonymity),
331 GNUNET_PQ_query_param_absolute_time (&expiration), 319 GNUNET_PQ_query_param_absolute_time (&expiration),
320 GNUNET_PQ_query_param_uint64 (&rvalue),
332 GNUNET_PQ_query_param_auto_from_type (key), 321 GNUNET_PQ_query_param_auto_from_type (key),
333 GNUNET_PQ_query_param_auto_from_type (&vhash), 322 GNUNET_PQ_query_param_auto_from_type (&vhash),
334 GNUNET_PQ_query_param_fixed_size (data, size), 323 GNUNET_PQ_query_param_fixed_size (data, size),
@@ -489,12 +478,11 @@ process_result (struct Plugin *plugin,
489 478
490 479
491/** 480/**
492 * Iterate over the results for a particular key 481 * Get one of the results for a particular key in the datastore.
493 * in the datastore.
494 * 482 *
495 * @param cls closure with the 'struct Plugin' 483 * @param cls closure with the 'struct Plugin'
496 * @param offset offset of the result (modulo num-results); 484 * @param next_uid return the result with lowest uid >= next_uid
497 * specific ordering does not matter for the offset 485 * @param random if true, return a random result instead of using next_uid
498 * @param key maybe NULL (to match all entries) 486 * @param key maybe NULL (to match all entries)
499 * @param vhash hash of the value, maybe NULL (to 487 * @param vhash hash of the value, maybe NULL (to
500 * match all values that have the right key). 488 * match all values that have the right key).
@@ -504,160 +492,52 @@ process_result (struct Plugin *plugin,
504 * @param type entries of which type are relevant? 492 * @param type entries of which type are relevant?
505 * Use 0 for any type. 493 * Use 0 for any type.
506 * @param proc function to call on the matching value; 494 * @param proc function to call on the matching value;
507 * will be called once with a NULL if no value matches 495 * will be called with NULL if nothing matches
508 * @param proc_cls closure for iter 496 * @param proc_cls closure for @a proc
509 */ 497 */
510static void 498static void
511postgres_plugin_get_key (void *cls, 499postgres_plugin_get_key (void *cls,
512 uint64_t offset, 500 uint64_t next_uid,
501 bool random,
513 const struct GNUNET_HashCode *key, 502 const struct GNUNET_HashCode *key,
514 const struct GNUNET_HashCode *vhash, 503 const struct GNUNET_HashCode *vhash,
515 enum GNUNET_BLOCK_Type type, 504 enum GNUNET_BLOCK_Type type,
516 PluginDatumProcessor proc, 505 PluginDatumProcessor proc,
517 void *proc_cls) 506 void *proc_cls)
518{ 507{
519 struct Plugin *plugin = cls; 508 struct Plugin *plugin = cls;
520 uint32_t utype = type; 509 uint32_t utype = type;
510 uint16_t use_rvalue = random;
511 uint16_t use_key = NULL != key;
512 uint16_t use_vhash = NULL != vhash;
513 uint16_t use_type = GNUNET_BLOCK_TYPE_ANY != type;
514 uint64_t rvalue;
515 struct GNUNET_PQ_QueryParam params[] = {
516 GNUNET_PQ_query_param_uint64 (&next_uid),
517 GNUNET_PQ_query_param_uint64 (&rvalue),
518 GNUNET_PQ_query_param_uint16 (&use_rvalue),
519 GNUNET_PQ_query_param_auto_from_type (key),
520 GNUNET_PQ_query_param_uint16 (&use_key),
521 GNUNET_PQ_query_param_auto_from_type (vhash),
522 GNUNET_PQ_query_param_uint16 (&use_vhash),
523 GNUNET_PQ_query_param_uint32 (&utype),
524 GNUNET_PQ_query_param_uint16 (&use_type),
525 GNUNET_PQ_query_param_end
526 };
521 PGresult *ret; 527 PGresult *ret;
522 uint64_t total;
523 uint64_t limit_off;
524 528
525 if (0 != type) 529 if (random)
526 { 530 {
527 if (NULL != vhash) 531 rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
528 { 532 UINT64_MAX);
529 struct GNUNET_PQ_QueryParam params[] = { 533 next_uid = 0;
530 GNUNET_PQ_query_param_auto_from_type (key),
531 GNUNET_PQ_query_param_auto_from_type (vhash),
532 GNUNET_PQ_query_param_uint32 (&utype),
533 GNUNET_PQ_query_param_end
534 };
535 ret = GNUNET_PQ_exec_prepared (plugin->dbh,
536 "count_getvt",
537 params);
538 }
539 else
540 {
541 struct GNUNET_PQ_QueryParam params[] = {
542 GNUNET_PQ_query_param_auto_from_type (key),
543 GNUNET_PQ_query_param_uint32 (&utype),
544 GNUNET_PQ_query_param_end
545 };
546 ret = GNUNET_PQ_exec_prepared (plugin->dbh,
547 "count_gett",
548 params);
549 }
550 } 534 }
551 else 535 else
552 { 536 rvalue = 0;
553 if (NULL != vhash)
554 {
555 struct GNUNET_PQ_QueryParam params[] = {
556 GNUNET_PQ_query_param_auto_from_type (key),
557 GNUNET_PQ_query_param_auto_from_type (vhash),
558 GNUNET_PQ_query_param_end
559 };
560 ret = GNUNET_PQ_exec_prepared (plugin->dbh,
561 "count_getv",
562 params);
563 }
564 else
565 {
566 struct GNUNET_PQ_QueryParam params[] = {
567 GNUNET_PQ_query_param_auto_from_type (key),
568 GNUNET_PQ_query_param_end
569 };
570 ret = GNUNET_PQ_exec_prepared (plugin->dbh,
571 "count_get",
572 params);
573 }
574 }
575 537
576 if (GNUNET_OK != 538 ret = GNUNET_PQ_exec_prepared (plugin->dbh,
577 GNUNET_POSTGRES_check_result (plugin->dbh, 539 "get",
578 ret, 540 params);
579 PGRES_TUPLES_OK,
580 "PQexecParams",
581 "count"))
582 {
583 proc (proc_cls, NULL, 0, NULL, 0, 0, 0,
584 GNUNET_TIME_UNIT_ZERO_ABS, 0);
585 return;
586 }
587 if ( (PQntuples (ret) != 1) ||
588 (PQnfields (ret) != 1) ||
589 (PQgetlength (ret, 0, 0) != sizeof (uint64_t)))
590 {
591 GNUNET_break (0);
592 PQclear (ret);
593 proc (proc_cls, NULL, 0, NULL, 0, 0, 0,
594 GNUNET_TIME_UNIT_ZERO_ABS, 0);
595 return;
596 }
597 total = GNUNET_ntohll (*(const uint64_t *) PQgetvalue (ret, 0, 0));
598 PQclear (ret);
599 if (0 == total)
600 {
601 proc (proc_cls, NULL, 0, NULL, 0, 0, 0,
602 GNUNET_TIME_UNIT_ZERO_ABS, 0);
603 return;
604 }
605 limit_off = offset % total;
606
607 if (0 != type)
608 {
609 if (NULL != vhash)
610 {
611 struct GNUNET_PQ_QueryParam params[] = {
612 GNUNET_PQ_query_param_auto_from_type (key),
613 GNUNET_PQ_query_param_auto_from_type (vhash),
614 GNUNET_PQ_query_param_uint32 (&utype),
615 GNUNET_PQ_query_param_uint64 (&limit_off),
616 GNUNET_PQ_query_param_end
617 };
618 ret = GNUNET_PQ_exec_prepared (plugin->dbh,
619 "getvt",
620 params);
621 }
622 else
623 {
624 struct GNUNET_PQ_QueryParam params[] = {
625 GNUNET_PQ_query_param_auto_from_type (key),
626 GNUNET_PQ_query_param_uint32 (&utype),
627 GNUNET_PQ_query_param_uint64 (&limit_off),
628 GNUNET_PQ_query_param_end
629 };
630 ret = GNUNET_PQ_exec_prepared (plugin->dbh,
631 "gett",
632 params);
633 }
634 }
635 else
636 {
637 if (NULL != vhash)
638 {
639 struct GNUNET_PQ_QueryParam params[] = {
640 GNUNET_PQ_query_param_auto_from_type (key),
641 GNUNET_PQ_query_param_auto_from_type (vhash),
642 GNUNET_PQ_query_param_uint64 (&limit_off),
643 GNUNET_PQ_query_param_end
644 };
645 ret = GNUNET_PQ_exec_prepared (plugin->dbh,
646 "getv",
647 params);
648 }
649 else
650 {
651 struct GNUNET_PQ_QueryParam params[] = {
652 GNUNET_PQ_query_param_auto_from_type (key),
653 GNUNET_PQ_query_param_uint64 (&limit_off),
654 GNUNET_PQ_query_param_end
655 };
656 ret = GNUNET_PQ_exec_prepared (plugin->dbh,
657 "get",
658 params);
659 }
660 }
661 process_result (plugin, 541 process_result (plugin,
662 proc, 542 proc,
663 proc_cls, 543 proc_cls,
@@ -671,26 +551,25 @@ postgres_plugin_get_key (void *cls,
671 * the given iterator for each of them. 551 * the given iterator for each of them.
672 * 552 *
673 * @param cls our `struct Plugin *` 553 * @param cls our `struct Plugin *`
674 * @param offset offset of the result (modulo num-results); 554 * @param next_uid return the result with lowest uid >= next_uid
675 * specific ordering does not matter for the offset
676 * @param type entries of which type should be considered? 555 * @param type entries of which type should be considered?
677 * Use 0 for any type. 556 * Must not be zero (ANY).
678 * @param proc function to call on the matching value; 557 * @param proc function to call on the matching value;
679 * will be called with a NULL if no value matches 558 * will be called with NULL if no value matches
680 * @param proc_cls closure for @a proc 559 * @param proc_cls closure for @a proc
681 */ 560 */
682static void 561static void
683postgres_plugin_get_zero_anonymity (void *cls, 562postgres_plugin_get_zero_anonymity (void *cls,
684 uint64_t offset, 563 uint64_t next_uid,
685 enum GNUNET_BLOCK_Type type, 564 enum GNUNET_BLOCK_Type type,
686 PluginDatumProcessor proc, 565 PluginDatumProcessor proc,
687 void *proc_cls) 566 void *proc_cls)
688{ 567{
689 struct Plugin *plugin = cls; 568 struct Plugin *plugin = cls;
690 uint32_t utype = type; 569 uint32_t utype = type;
691 struct GNUNET_PQ_QueryParam params[] = { 570 struct GNUNET_PQ_QueryParam params[] = {
692 GNUNET_PQ_query_param_uint32 (&utype), 571 GNUNET_PQ_query_param_uint32 (&utype),
693 GNUNET_PQ_query_param_uint64 (&offset), 572 GNUNET_PQ_query_param_uint64 (&next_uid),
694 GNUNET_PQ_query_param_end 573 GNUNET_PQ_query_param_end
695 }; 574 };
696 PGresult *ret; 575 PGresult *ret;
diff --git a/src/datastore/plugin_datastore_sqlite.c b/src/datastore/plugin_datastore_sqlite.c
index 9ab50714f..76f791ad4 100644
--- a/src/datastore/plugin_datastore_sqlite.c
+++ b/src/datastore/plugin_datastore_sqlite.c
@@ -1,6 +1,6 @@
1 /* 1 /*
2 * This file is part of GNUnet 2 * This file is part of GNUnet
3 * Copyright (C) 2009, 2011 GNUnet e.V. 3 * Copyright (C) 2009, 2011, 2017 GNUnet e.V.
4 * 4 *
5 * GNUnet is free software; you can redistribute it and/or modify 5 * GNUnet is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published 6 * it under the terms of the GNU General Public License as published
@@ -26,6 +26,7 @@
26 26
27#include "platform.h" 27#include "platform.h"
28#include "gnunet_datastore_plugin.h" 28#include "gnunet_datastore_plugin.h"
29#include "gnunet_sq_lib.h"
29#include <sqlite3.h> 30#include <sqlite3.h>
30 31
31 32
@@ -127,6 +128,11 @@ struct Plugin
127 sqlite3_stmt *insertContent; 128 sqlite3_stmt *insertContent;
128 129
129 /** 130 /**
131 * Precompiled SQL for selection
132 */
133 sqlite3_stmt *get;
134
135 /**
130 * Should the database be dropped on shutdown? 136 * Should the database be dropped on shutdown?
131 */ 137 */
132 int drop_on_shutdown; 138 int drop_on_shutdown;
@@ -150,11 +156,17 @@ sq_prepare (sqlite3 *dbh,
150 char *dummy; 156 char *dummy;
151 int result; 157 int result;
152 158
153 result = 159 result = sqlite3_prepare_v2 (dbh,
154 sqlite3_prepare_v2 (dbh, zSql, strlen (zSql), ppStmt, 160 zSql,
155 (const char **) &dummy); 161 strlen (zSql),
156 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", 162 ppStmt,
157 "Prepared `%s' / %p: %d\n", zSql, *ppStmt, result); 163 (const char **) &dummy);
164 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
165 "sqlite",
166 "Prepared `%s' / %p: %d\n",
167 zSql,
168 *ppStmt,
169 result);
158 return result; 170 return result;
159} 171}
160 172
@@ -310,80 +322,110 @@ database_setup (const struct GNUNET_CONFIGURATION_Handle *cfg,
310 * we do math or inequality tests, so we can't handle the entire range of uint32_t. 322 * we do math or inequality tests, so we can't handle the entire range of uint32_t.
311 * This will also cause problems for expiration times after 294247-01-10-04:00:54 UTC. 323 * This will also cause problems for expiration times after 294247-01-10-04:00:54 UTC.
312 */ 324 */
313 if ((sqlite3_step (stmt) == SQLITE_DONE) && 325 if ( (SQLITE_DONE ==
314 (sqlite3_exec 326 sqlite3_step (stmt)) &&
315 (plugin->dbh, 327 (SQLITE_OK !=
316 "CREATE TABLE gn090 (" " repl INT4 NOT NULL DEFAULT 0," 328 sqlite3_exec (plugin->dbh,
317 " type INT4 NOT NULL DEFAULT 0," " prio INT4 NOT NULL DEFAULT 0," 329 "CREATE TABLE gn090 ("
318 " anonLevel INT4 NOT NULL DEFAULT 0," 330 " repl INT4 NOT NULL DEFAULT 0,"
319 " expire INT8 NOT NULL DEFAULT 0," " rvalue INT8 NOT NULL," 331 " type INT4 NOT NULL DEFAULT 0,"
320 " hash TEXT NOT NULL DEFAULT ''," " vhash TEXT NOT NULL DEFAULT ''," 332 " prio INT4 NOT NULL DEFAULT 0,"
321 " value BLOB NOT NULL DEFAULT '')", NULL, NULL, NULL) != SQLITE_OK)) 333 " anonLevel INT4 NOT NULL DEFAULT 0,"
334 " expire INT8 NOT NULL DEFAULT 0,"
335 " rvalue INT8 NOT NULL,"
336 " hash TEXT NOT NULL DEFAULT '',"
337 " vhash TEXT NOT NULL DEFAULT '',"
338 " value BLOB NOT NULL DEFAULT '')",
339 NULL,
340 NULL,
341 NULL)) )
322 { 342 {
323 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite3_exec"); 343 LOG_SQLITE (plugin,
344 GNUNET_ERROR_TYPE_ERROR,
345 "sqlite3_exec");
324 sqlite3_finalize (stmt); 346 sqlite3_finalize (stmt);
325 return GNUNET_SYSERR; 347 return GNUNET_SYSERR;
326 } 348 }
327 sqlite3_finalize (stmt); 349 sqlite3_finalize (stmt);
328 create_indices (plugin->dbh); 350 create_indices (plugin->dbh);
329 351
330 if ((sq_prepare 352 if ( (SQLITE_OK !=
331 (plugin->dbh, 353 sq_prepare (plugin->dbh,
332 "UPDATE gn090 " 354 "UPDATE gn090 "
333 "SET prio = prio + ?, expire = MAX(expire,?) WHERE _ROWID_ = ?", 355 "SET prio = prio + ?, expire = MAX(expire,?) WHERE _ROWID_ = ?",
334 &plugin->updPrio) != SQLITE_OK) || 356 &plugin->updPrio)) ||
335 (sq_prepare 357 (SQLITE_OK !=
336 (plugin->dbh, 358 sq_prepare (plugin->dbh,
337 "UPDATE gn090 " "SET repl = MAX (0, repl - 1) WHERE _ROWID_ = ?", 359 "UPDATE gn090 " "SET repl = MAX (0, repl - 1) WHERE _ROWID_ = ?",
338 &plugin->updRepl) != SQLITE_OK) || 360 &plugin->updRepl)) ||
339 (sq_prepare 361 (SQLITE_OK !=
340 (plugin->dbh, 362 sq_prepare (plugin->dbh,
341 "SELECT type,prio,anonLevel,expire,hash,value,_ROWID_ " "FROM gn090 " 363 "SELECT type,prio,anonLevel,expire,hash,value,_ROWID_ " "FROM gn090 "
342#if SQLITE_VERSION_NUMBER >= 3007000 364#if SQLITE_VERSION_NUMBER >= 3007000
343 "INDEXED BY idx_repl_rvalue " 365 "INDEXED BY idx_repl_rvalue "
344#endif 366#endif
345 "WHERE repl=?2 AND " " (rvalue>=?1 OR " 367 "WHERE repl=?2 AND " " (rvalue>=?1 OR "
346 " NOT EXISTS (SELECT 1 FROM gn090 " 368 " NOT EXISTS (SELECT 1 FROM gn090 "
347#if SQLITE_VERSION_NUMBER >= 3007000 369#if SQLITE_VERSION_NUMBER >= 3007000
348 "INDEXED BY idx_repl_rvalue " 370 "INDEXED BY idx_repl_rvalue "
349#endif 371#endif
350 "WHERE repl=?2 AND rvalue>=?1 LIMIT 1) ) " 372 "WHERE repl=?2 AND rvalue>=?1 LIMIT 1) ) "
351 "ORDER BY rvalue ASC LIMIT 1", &plugin->selRepl) != SQLITE_OK) || 373 "ORDER BY rvalue ASC LIMIT 1",
352 (sq_prepare (plugin->dbh, "SELECT MAX(repl) FROM gn090" 374 &plugin->selRepl)) ||
375 (SQLITE_OK !=
376 sq_prepare (plugin->dbh,
377 "SELECT MAX(repl) FROM gn090"
353#if SQLITE_VERSION_NUMBER >= 3007000 378#if SQLITE_VERSION_NUMBER >= 3007000
354 " INDEXED BY idx_repl_rvalue" 379 " INDEXED BY idx_repl_rvalue"
355#endif 380#endif
356 "", &plugin->maxRepl) != SQLITE_OK) || 381 "",
357 (sq_prepare 382 &plugin->maxRepl)) ||
358 (plugin->dbh, 383 (SQLITE_OK !=
359 "SELECT type,prio,anonLevel,expire,hash,value,_ROWID_ " "FROM gn090 " 384 sq_prepare (plugin->dbh,
385 "SELECT type,prio,anonLevel,expire,hash,value,_ROWID_ " "FROM gn090 "
360#if SQLITE_VERSION_NUMBER >= 3007000 386#if SQLITE_VERSION_NUMBER >= 3007000
361 "INDEXED BY idx_expire " 387 "INDEXED BY idx_expire "
362#endif 388#endif
363 "WHERE NOT EXISTS (SELECT 1 FROM gn090 WHERE expire < ?1 LIMIT 1) OR (expire < ?1) " 389 "WHERE NOT EXISTS (SELECT 1 FROM gn090 WHERE expire < ?1 LIMIT 1) OR (expire < ?1) "
364 "ORDER BY expire ASC LIMIT 1", &plugin->selExpi) != SQLITE_OK) || 390 "ORDER BY expire ASC LIMIT 1",
365 (sq_prepare 391 &plugin->selExpi)) ||
366 (plugin->dbh, 392 (SQLITE_OK !=
367 "SELECT type,prio,anonLevel,expire,hash,value,_ROWID_ " "FROM gn090 " 393 sq_prepare (plugin->dbh,
394 "SELECT type,prio,anonLevel,expire,hash,value,_ROWID_ " "FROM gn090 "
368#if SQLITE_VERSION_NUMBER >= 3007000 395#if SQLITE_VERSION_NUMBER >= 3007000
369 "INDEXED BY idx_anon_type_hash " 396 "INDEXED BY idx_anon_type_hash "
370#endif 397#endif
371 "WHERE (anonLevel = 0 AND type=?1) " 398 "WHERE _ROWID_ >= ? AND "
372 "ORDER BY hash DESC LIMIT 1 OFFSET ?2", 399 "anonLevel = 0 AND "
373 &plugin->selZeroAnon) != SQLITE_OK) || 400 "type = ? "
374 (sq_prepare 401 "ORDER BY _ROWID_ ASC LIMIT 1",
375 (plugin->dbh, 402 &plugin->selZeroAnon)) ||
376 "INSERT INTO gn090 (repl, type, prio, anonLevel, expire, rvalue, hash, vhash, value) " 403 (SQLITE_OK !=
377 "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", 404 sq_prepare (plugin->dbh,
378 &plugin->insertContent) != SQLITE_OK) || 405 "INSERT INTO gn090 (repl, type, prio, anonLevel, expire, rvalue, hash, vhash, value) "
379 (sq_prepare 406 "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
380 (plugin->dbh, "DELETE FROM gn090 WHERE _ROWID_ = ?", 407 &plugin->insertContent)) ||
381 &plugin->delRow) != SQLITE_OK)) 408 (SQLITE_OK !=
409 sq_prepare (plugin->dbh,
410 "SELECT type, prio, anonLevel, expire, hash, value, _ROWID_ FROM gn090 "
411 "WHERE _ROWID_ >= ? AND "
412 "(rvalue >= ? OR 0 = ?) AND "
413 "(hash = ? OR 0 = ?) AND "
414 "(vhash = ? OR 0 = ?) AND "
415 "(type = ? OR 0 = ?) "
416 "ORDER BY _ROWID_ ASC LIMIT 1",
417 &plugin->get)) ||
418 (SQLITE_OK !=
419 sq_prepare (plugin->dbh,
420 "DELETE FROM gn090 WHERE _ROWID_ = ?",
421 &plugin->delRow))
422 )
382 { 423 {
383 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "precompiling"); 424 LOG_SQLITE (plugin,
425 GNUNET_ERROR_TYPE_ERROR,
426 "precompiling");
384 return GNUNET_SYSERR; 427 return GNUNET_SYSERR;
385 } 428 }
386
387 return GNUNET_OK; 429 return GNUNET_OK;
388} 430}
389 431
@@ -398,51 +440,60 @@ static void
398database_shutdown (struct Plugin *plugin) 440database_shutdown (struct Plugin *plugin)
399{ 441{
400 int result; 442 int result;
401
402#if SQLITE_VERSION_NUMBER >= 3007000 443#if SQLITE_VERSION_NUMBER >= 3007000
403 sqlite3_stmt *stmt; 444 sqlite3_stmt *stmt;
404#endif 445#endif
405 446
406 if (plugin->delRow != NULL) 447 if (NULL != plugin->delRow)
407 sqlite3_finalize (plugin->delRow); 448 sqlite3_finalize (plugin->delRow);
408 if (plugin->updPrio != NULL) 449 if (NULL != plugin->updPrio)
409 sqlite3_finalize (plugin->updPrio); 450 sqlite3_finalize (plugin->updPrio);
410 if (plugin->updRepl != NULL) 451 if (NULL != plugin->updRepl)
411 sqlite3_finalize (plugin->updRepl); 452 sqlite3_finalize (plugin->updRepl);
412 if (plugin->selRepl != NULL) 453 if (NULL != plugin->selRepl)
413 sqlite3_finalize (plugin->selRepl); 454 sqlite3_finalize (plugin->selRepl);
414 if (plugin->maxRepl != NULL) 455 if (NULL != plugin->maxRepl)
415 sqlite3_finalize (plugin->maxRepl); 456 sqlite3_finalize (plugin->maxRepl);
416 if (plugin->selExpi != NULL) 457 if (NULL != plugin->selExpi)
417 sqlite3_finalize (plugin->selExpi); 458 sqlite3_finalize (plugin->selExpi);
418 if (plugin->selZeroAnon != NULL) 459 if (NULL != plugin->selZeroAnon)
419 sqlite3_finalize (plugin->selZeroAnon); 460 sqlite3_finalize (plugin->selZeroAnon);
420 if (plugin->insertContent != NULL) 461 if (NULL != plugin->insertContent)
421 sqlite3_finalize (plugin->insertContent); 462 sqlite3_finalize (plugin->insertContent);
463 if (NULL != plugin->get)
464 sqlite3_finalize (plugin->get);
422 result = sqlite3_close (plugin->dbh); 465 result = sqlite3_close (plugin->dbh);
423#if SQLITE_VERSION_NUMBER >= 3007000 466#if SQLITE_VERSION_NUMBER >= 3007000
424 if (result == SQLITE_BUSY) 467 if (result == SQLITE_BUSY)
425 { 468 {
426 GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "sqlite", 469 GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
427 _ 470 "sqlite",
428 ("Tried to close sqlite without finalizing all prepared statements.\n")); 471 _("Tried to close sqlite without finalizing all prepared statements.\n"));
429 stmt = sqlite3_next_stmt (plugin->dbh, NULL); 472 stmt = sqlite3_next_stmt (plugin->dbh,
430 while (stmt != NULL) 473 NULL);
474 while (NULL != stmt)
431 { 475 {
432 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", 476 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
433 "Closing statement %p\n", stmt); 477 "sqlite",
478 "Closing statement %p\n",
479 stmt);
434 result = sqlite3_finalize (stmt); 480 result = sqlite3_finalize (stmt);
435 if (result != SQLITE_OK) 481 if (result != SQLITE_OK)
436 GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "sqlite", 482 GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
437 "Failed to close statement %p: %d\n", stmt, result); 483 "sqlite",
438 stmt = sqlite3_next_stmt (plugin->dbh, NULL); 484 "Failed to close statement %p: %d\n",
485 stmt,
486 result);
487 stmt = sqlite3_next_stmt (plugin->dbh,
488 NULL);
439 } 489 }
440 result = sqlite3_close (plugin->dbh); 490 result = sqlite3_close (plugin->dbh);
441 } 491 }
442#endif 492#endif
443 if (SQLITE_OK != result) 493 if (SQLITE_OK != result)
444 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite3_close"); 494 LOG_SQLITE (plugin,
445 495 GNUNET_ERROR_TYPE_ERROR,
496 "sqlite3_close");
446 GNUNET_free_non_null (plugin->fn); 497 GNUNET_free_non_null (plugin->fn);
447} 498}
448 499
@@ -456,31 +507,27 @@ database_shutdown (struct Plugin *plugin)
456 */ 507 */
457static int 508static int
458delete_by_rowid (struct Plugin *plugin, 509delete_by_rowid (struct Plugin *plugin,
459 unsigned long long rid) 510 uint64_t rid)
460{ 511{
461 if (SQLITE_OK != sqlite3_bind_int64 (plugin->delRow, 1, rid)) 512 struct GNUNET_SQ_QueryParam params[] = {
462 { 513 GNUNET_SQ_query_param_uint64 (&rid),
463 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 514 GNUNET_SQ_query_param_end
464 "sqlite3_bind_XXXX"); 515 };
465 if (SQLITE_OK != sqlite3_reset (plugin->delRow)) 516
466 LOG_SQLITE (plugin, 517 if (GNUNET_OK !=
467 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 518 GNUNET_SQ_bind (plugin->delRow,
468 "sqlite3_reset"); 519 params))
469 return GNUNET_SYSERR; 520 return GNUNET_SYSERR;
470 }
471 if (SQLITE_DONE != sqlite3_step (plugin->delRow)) 521 if (SQLITE_DONE != sqlite3_step (plugin->delRow))
472 { 522 {
473 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 523 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
474 "sqlite3_step"); 524 "sqlite3_step");
475 if (SQLITE_OK != sqlite3_reset (plugin->delRow)) 525 GNUNET_SQ_reset (plugin->dbh,
476 LOG_SQLITE (plugin, 526 plugin->delRow);
477 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
478 "sqlite3_reset");
479 return GNUNET_SYSERR; 527 return GNUNET_SYSERR;
480 } 528 }
481 if (SQLITE_OK != sqlite3_reset (plugin->delRow)) 529 GNUNET_SQ_reset (plugin->dbh,
482 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 530 plugin->delRow);
483 "sqlite3_reset");
484 return GNUNET_OK; 531 return GNUNET_OK;
485} 532}
486 533
@@ -513,12 +560,25 @@ sqlite_plugin_put (void *cls,
513 PluginPutCont cont, 560 PluginPutCont cont,
514 void *cont_cls) 561 void *cont_cls)
515{ 562{
563 uint64_t rvalue;
564 struct GNUNET_HashCode vhash;
565 uint32_t type32 = (uint32_t) type;
566 struct GNUNET_SQ_QueryParam params[] = {
567 GNUNET_SQ_query_param_uint32 (&replication),
568 GNUNET_SQ_query_param_uint32 (&type32),
569 GNUNET_SQ_query_param_uint32 (&priority),
570 GNUNET_SQ_query_param_uint32 (&anonymity),
571 GNUNET_SQ_query_param_absolute_time (&expiration),
572 GNUNET_SQ_query_param_uint64 (&rvalue),
573 GNUNET_SQ_query_param_auto_from_type (key),
574 GNUNET_SQ_query_param_auto_from_type (&vhash),
575 GNUNET_SQ_query_param_fixed_size (data, size),
576 GNUNET_SQ_query_param_end
577 };
516 struct Plugin *plugin = cls; 578 struct Plugin *plugin = cls;
517 int n; 579 int n;
518 int ret; 580 int ret;
519 sqlite3_stmt *stmt; 581 sqlite3_stmt *stmt;
520 struct GNUNET_HashCode vhash;
521 uint64_t rvalue;
522 char *msg = NULL; 582 char *msg = NULL;
523 583
524 if (size > MAX_ITEM_SIZE) 584 if (size > MAX_ITEM_SIZE)
@@ -537,26 +597,10 @@ sqlite_plugin_put (void *cls,
537 GNUNET_CRYPTO_hash (data, size, &vhash); 597 GNUNET_CRYPTO_hash (data, size, &vhash);
538 stmt = plugin->insertContent; 598 stmt = plugin->insertContent;
539 rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX); 599 rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
540 if ((SQLITE_OK != sqlite3_bind_int (stmt, 1, replication)) || 600 if (GNUNET_OK !=
541 (SQLITE_OK != sqlite3_bind_int (stmt, 2, type)) || 601 GNUNET_SQ_bind (stmt,
542 (SQLITE_OK != sqlite3_bind_int (stmt, 3, priority)) || 602 params))
543 (SQLITE_OK != sqlite3_bind_int (stmt, 4, anonymity)) ||
544 (SQLITE_OK != sqlite3_bind_int64 (stmt, 5, expiration.abs_value_us)) ||
545 (SQLITE_OK != sqlite3_bind_int64 (stmt, 6, rvalue)) ||
546 (SQLITE_OK !=
547 sqlite3_bind_blob (stmt, 7, key, sizeof (struct GNUNET_HashCode),
548 SQLITE_TRANSIENT)) ||
549 (SQLITE_OK !=
550 sqlite3_bind_blob (stmt, 8, &vhash, sizeof (struct GNUNET_HashCode),
551 SQLITE_TRANSIENT)) ||
552 (SQLITE_OK != sqlite3_bind_blob (stmt, 9, data, size, SQLITE_TRANSIENT)))
553 { 603 {
554 LOG_SQLITE_MSG (plugin, &msg, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
555 "sqlite3_bind_XXXX");
556 if (SQLITE_OK != sqlite3_reset (stmt))
557 LOG_SQLITE (plugin,
558 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
559 "sqlite3_reset");
560 cont (cont_cls, key, size, GNUNET_SYSERR, msg); 604 cont (cont_cls, key, size, GNUNET_SYSERR, msg);
561 GNUNET_free_non_null(msg); 605 GNUNET_free_non_null(msg);
562 return; 606 return;
@@ -582,19 +626,16 @@ sqlite_plugin_put (void *cls,
582 default: 626 default:
583 LOG_SQLITE_MSG (plugin, &msg, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 627 LOG_SQLITE_MSG (plugin, &msg, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
584 "sqlite3_step"); 628 "sqlite3_step");
585 if (SQLITE_OK != sqlite3_reset (stmt)) 629 GNUNET_SQ_reset (plugin->dbh,
586 LOG_SQLITE (plugin, 630 stmt);
587 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
588 "sqlite3_reset");
589 database_shutdown (plugin); 631 database_shutdown (plugin);
590 database_setup (plugin->env->cfg, plugin); 632 database_setup (plugin->env->cfg, plugin);
591 cont (cont_cls, key, size, GNUNET_SYSERR, msg); 633 cont (cont_cls, key, size, GNUNET_SYSERR, msg);
592 GNUNET_free_non_null(msg); 634 GNUNET_free_non_null(msg);
593 return; 635 return;
594 } 636 }
595 if (SQLITE_OK != sqlite3_reset (stmt)) 637 GNUNET_SQ_reset (plugin->dbh,
596 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 638 stmt);
597 "sqlite3_reset");
598 cont (cont_cls, key, size, ret, msg); 639 cont (cont_cls, key, size, ret, msg);
599 GNUNET_free_non_null(msg); 640 GNUNET_free_non_null(msg);
600} 641}
@@ -619,7 +660,7 @@ sqlite_plugin_put (void *cls,
619 * MAX of any existing expiration time and 660 * MAX of any existing expiration time and
620 * this value 661 * this value
621 * @param cont continuation called with success or failure status 662 * @param cont continuation called with success or failure status
622 * @param cons_cls continuation closure 663 * @param cons_cls closure for @a cont
623 */ 664 */
624static void 665static void
625sqlite_plugin_update (void *cls, 666sqlite_plugin_update (void *cls,
@@ -630,27 +671,26 @@ sqlite_plugin_update (void *cls,
630 void *cont_cls) 671 void *cont_cls)
631{ 672{
632 struct Plugin *plugin = cls; 673 struct Plugin *plugin = cls;
674 struct GNUNET_SQ_QueryParam params[] = {
675 GNUNET_SQ_query_param_uint32 (&delta),
676 GNUNET_SQ_query_param_absolute_time (&expire),
677 GNUNET_SQ_query_param_uint64 (&uid),
678 GNUNET_SQ_query_param_end
679 };
633 int n; 680 int n;
634 char *msg = NULL; 681 char *msg = NULL;
635 682
636 if ((SQLITE_OK != sqlite3_bind_int (plugin->updPrio, 1, delta)) || 683 if (GNUNET_OK !=
637 (SQLITE_OK != sqlite3_bind_int64 (plugin->updPrio, 2, expire.abs_value_us)) 684 GNUNET_SQ_bind (plugin->updPrio,
638 || (SQLITE_OK != sqlite3_bind_int64 (plugin->updPrio, 3, uid))) 685 params))
639 { 686 {
640 LOG_SQLITE_MSG (plugin, &msg, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
641 "sqlite3_bind_XXXX");
642 if (SQLITE_OK != sqlite3_reset (plugin->updPrio))
643 LOG_SQLITE (plugin,
644 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
645 "sqlite3_reset");
646 cont (cont_cls, GNUNET_SYSERR, msg); 687 cont (cont_cls, GNUNET_SYSERR, msg);
647 GNUNET_free_non_null(msg); 688 GNUNET_free_non_null(msg);
648 return; 689 return;
649 } 690 }
650 n = sqlite3_step (plugin->updPrio); 691 n = sqlite3_step (plugin->updPrio);
651 if (SQLITE_OK != sqlite3_reset (plugin->updPrio)) 692 GNUNET_SQ_reset (plugin->dbh,
652 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 693 plugin->updPrio);
653 "sqlite3_reset");
654 switch (n) 694 switch (n)
655 { 695 {
656 case SQLITE_DONE: 696 case SQLITE_DONE:
@@ -691,75 +731,84 @@ execute_get (struct Plugin *plugin,
691{ 731{
692 int n; 732 int n;
693 struct GNUNET_TIME_Absolute expiration; 733 struct GNUNET_TIME_Absolute expiration;
694 unsigned long long rowid; 734 uint32_t type;
695 unsigned int size; 735 uint32_t priority;
736 uint32_t anonymity;
737 uint64_t rowid;
738 void *value;
739 size_t value_size;
740 struct GNUNET_HashCode key;
696 int ret; 741 int ret;
742 struct GNUNET_SQ_ResultSpec rs[] = {
743 GNUNET_SQ_result_spec_uint32 (&type),
744 GNUNET_SQ_result_spec_uint32 (&priority),
745 GNUNET_SQ_result_spec_uint32 (&anonymity),
746 GNUNET_SQ_result_spec_absolute_time (&expiration),
747 GNUNET_SQ_result_spec_auto_from_type (&key),
748 GNUNET_SQ_result_spec_variable_size (&value,
749 &value_size),
750 GNUNET_SQ_result_spec_uint64 (&rowid),
751 GNUNET_SQ_result_spec_end
752 };
697 753
698 n = sqlite3_step (stmt); 754 n = sqlite3_step (stmt);
699 switch (n) 755 switch (n)
700 { 756 {
701 case SQLITE_ROW: 757 case SQLITE_ROW:
702 size = sqlite3_column_bytes (stmt, 5); 758 if (GNUNET_OK !=
703 rowid = sqlite3_column_int64 (stmt, 6); 759 GNUNET_SQ_extract_result (stmt,
704 if (sqlite3_column_bytes (stmt, 4) != sizeof (struct GNUNET_HashCode)) 760 rs))
705 { 761 {
706 GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "sqlite", 762 GNUNET_break (0);
707 _("Invalid data in database. Trying to fix (by deletion).\n"));
708 if (SQLITE_OK != sqlite3_reset (stmt))
709 LOG_SQLITE (plugin,
710 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
711 "sqlite3_reset");
712 if ( (GNUNET_OK == delete_by_rowid (plugin, rowid)) &&
713 (NULL != plugin->env->duc) )
714 plugin->env->duc (plugin->env->cls,
715 -(size + GNUNET_DATASTORE_ENTRY_OVERHEAD));
716 break; 763 break;
717 } 764 }
718 expiration.abs_value_us = sqlite3_column_int64 (stmt, 3); 765 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
719 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", 766 "sqlite",
720 "Found reply in database with expiration %s\n", 767 "Found reply in database with expiration %s\n",
721 GNUNET_STRINGS_absolute_time_to_string (expiration)); 768 GNUNET_STRINGS_absolute_time_to_string (expiration));
722 ret = proc (proc_cls, sqlite3_column_blob (stmt, 4) /* key */ , 769 ret = proc (proc_cls,
723 size, sqlite3_column_blob (stmt, 5) /* data */ , 770 &key,
724 sqlite3_column_int (stmt, 0) /* type */ , 771 value_size,
725 sqlite3_column_int (stmt, 1) /* priority */ , 772 value,
726 sqlite3_column_int (stmt, 2) /* anonymity */ , 773 type,
727 expiration, rowid); 774 priority,
728 if (SQLITE_OK != sqlite3_reset (stmt)) 775 anonymity,
729 LOG_SQLITE (plugin, 776 expiration,
730 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 777 rowid);
731 "sqlite3_reset"); 778 GNUNET_SQ_cleanup_result (rs);
779 GNUNET_SQ_reset (plugin->dbh,
780 stmt);
732 if ( (GNUNET_NO == ret) && 781 if ( (GNUNET_NO == ret) &&
733 (GNUNET_OK == delete_by_rowid (plugin, rowid)) && 782 (GNUNET_OK == delete_by_rowid (plugin,
783 rowid)) &&
734 (NULL != plugin->env->duc) ) 784 (NULL != plugin->env->duc) )
735 plugin->env->duc (plugin->env->cls, 785 plugin->env->duc (plugin->env->cls,
736 -(size + GNUNET_DATASTORE_ENTRY_OVERHEAD)); 786 -(value_size + GNUNET_DATASTORE_ENTRY_OVERHEAD));
737 return; 787 return;
738 case SQLITE_DONE: 788 case SQLITE_DONE:
739 /* database must be empty */ 789 /* database must be empty */
740 if (SQLITE_OK != sqlite3_reset (stmt))
741 LOG_SQLITE (plugin,
742 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
743 "sqlite3_reset");
744 break; 790 break;
745 case SQLITE_BUSY: 791 case SQLITE_BUSY:
746 case SQLITE_ERROR: 792 case SQLITE_ERROR:
747 case SQLITE_MISUSE: 793 case SQLITE_MISUSE:
748 default: 794 default:
749 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 795 LOG_SQLITE (plugin,
796 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
750 "sqlite3_step"); 797 "sqlite3_step");
751 if (SQLITE_OK != sqlite3_reset (stmt)) 798 if (SQLITE_OK !=
799 sqlite3_reset (stmt))
752 LOG_SQLITE (plugin, 800 LOG_SQLITE (plugin,
753 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 801 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
754 "sqlite3_reset"); 802 "sqlite3_reset");
755 GNUNET_break (0); 803 GNUNET_break (0);
804 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
756 database_shutdown (plugin); 805 database_shutdown (plugin);
757 database_setup (plugin->env->cfg, plugin); 806 database_setup (plugin->env->cfg,
758 break; 807 plugin);
808 return;
759 } 809 }
760 if (SQLITE_OK != sqlite3_reset (stmt)) 810 GNUNET_SQ_reset (plugin->dbh,
761 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 811 stmt);
762 "sqlite3_reset");
763 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); 812 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
764} 813}
765 814
@@ -769,37 +818,36 @@ execute_get (struct Plugin *plugin,
769 * the given processor for the item. 818 * the given processor for the item.
770 * 819 *
771 * @param cls our plugin context 820 * @param cls our plugin context
772 * @param offset offset of the result (modulo num-results); 821 * @param next_uid return the result with lowest uid >= next_uid
773 * specific ordering does not matter for the offset
774 * @param type entries of which type should be considered? 822 * @param type entries of which type should be considered?
775 * Use 0 for any type. 823 * Must not be zero (ANY).
776 * @param proc function to call on each matching value; 824 * @param proc function to call on the matching value;
777 * will be called once with a NULL value at the end 825 * will be called with NULL if no value matches
778 * @param proc_cls closure for @a proc 826 * @param proc_cls closure for @a proc
779 */ 827 */
780static void 828static void
781sqlite_plugin_get_zero_anonymity (void *cls, uint64_t offset, 829sqlite_plugin_get_zero_anonymity (void *cls,
830 uint64_t next_uid,
782 enum GNUNET_BLOCK_Type type, 831 enum GNUNET_BLOCK_Type type,
783 PluginDatumProcessor proc, void *proc_cls) 832 PluginDatumProcessor proc,
833 void *proc_cls)
784{ 834{
785 struct Plugin *plugin = cls; 835 struct Plugin *plugin = cls;
786 sqlite3_stmt *stmt; 836 struct GNUNET_SQ_QueryParam params[] = {
837 GNUNET_SQ_query_param_uint64 (&next_uid),
838 GNUNET_SQ_query_param_uint32 (&type),
839 GNUNET_SQ_query_param_end
840 };
787 841
788 GNUNET_assert (type != GNUNET_BLOCK_TYPE_ANY); 842 GNUNET_assert (type != GNUNET_BLOCK_TYPE_ANY);
789 stmt = plugin->selZeroAnon; 843 if (GNUNET_OK !=
790 if ((SQLITE_OK != sqlite3_bind_int (stmt, 1, type)) || 844 GNUNET_SQ_bind (plugin->selZeroAnon,
791 (SQLITE_OK != sqlite3_bind_int64 (stmt, 2, offset))) 845 params))
792 { 846 {
793 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
794 "sqlite3_bind_XXXX");
795 if (SQLITE_OK != sqlite3_reset (stmt))
796 LOG_SQLITE (plugin,
797 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
798 "sqlite3_reset");
799 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); 847 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
800 return; 848 return;
801 } 849 }
802 execute_get (plugin, stmt, proc, proc_cls); 850 execute_get (plugin, plugin->selZeroAnon, proc, proc_cls);
803} 851}
804 852
805 853
@@ -807,8 +855,9 @@ sqlite_plugin_get_zero_anonymity (void *cls, uint64_t offset,
807 * Get results for a particular key in the datastore. 855 * Get results for a particular key in the datastore.
808 * 856 *
809 * @param cls closure 857 * @param cls closure
810 * @param offset offset (mod count). 858 * @param next_uid return the result with lowest uid >= next_uid
811 * @param key key to match, never NULL 859 * @param random if true, return a random result instead of using next_uid
860 * @param key maybe NULL (to match all entries)
812 * @param vhash hash of the value, maybe NULL (to 861 * @param vhash hash of the value, maybe NULL (to
813 * match all values that have the right key). 862 * match all values that have the right key).
814 * Note that for DBlocks there is no difference 863 * Note that for DBlocks there is no difference
@@ -822,7 +871,8 @@ sqlite_plugin_get_zero_anonymity (void *cls, uint64_t offset,
822 */ 871 */
823static void 872static void
824sqlite_plugin_get_key (void *cls, 873sqlite_plugin_get_key (void *cls,
825 uint64_t offset, 874 uint64_t next_uid,
875 bool random,
826 const struct GNUNET_HashCode *key, 876 const struct GNUNET_HashCode *key,
827 const struct GNUNET_HashCode *vhash, 877 const struct GNUNET_HashCode *vhash,
828 enum GNUNET_BLOCK_Type type, 878 enum GNUNET_BLOCK_Type type,
@@ -830,97 +880,45 @@ sqlite_plugin_get_key (void *cls,
830 void *proc_cls) 880 void *proc_cls)
831{ 881{
832 struct Plugin *plugin = cls; 882 struct Plugin *plugin = cls;
833 int ret; 883 uint64_t rvalue;
834 int total; 884 uint16_t use_rvalue = random;
835 int limit_off; 885 uint32_t type32 = (uint32_t) type;
836 unsigned int sqoff; 886 uint16_t use_type = GNUNET_BLOCK_TYPE_ANY != type;
837 sqlite3_stmt *stmt; 887 uint16_t use_key = NULL != key;
838 char scratch[256]; 888 uint16_t use_vhash = NULL != vhash;
839 889 struct GNUNET_SQ_QueryParam params[] = {
840 GNUNET_assert (proc != NULL); 890 GNUNET_SQ_query_param_uint64 (&next_uid),
841 GNUNET_assert (key != NULL); 891 GNUNET_SQ_query_param_uint64 (&rvalue),
842 GNUNET_snprintf (scratch, sizeof (scratch), 892 GNUNET_SQ_query_param_uint16 (&use_rvalue),
843 "SELECT count(*) FROM gn090 WHERE hash=?%s%s", 893 GNUNET_SQ_query_param_auto_from_type (key),
844 vhash == NULL ? "" : " AND vhash=?", 894 GNUNET_SQ_query_param_uint16 (&use_key),
845 type == 0 ? "" : " AND type=?"); 895 GNUNET_SQ_query_param_auto_from_type (vhash),
846 if (sq_prepare (plugin->dbh, scratch, &stmt) != SQLITE_OK) 896 GNUNET_SQ_query_param_uint16 (&use_vhash),
847 { 897 GNUNET_SQ_query_param_uint32 (&type32),
848 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 898 GNUNET_SQ_query_param_uint16 (&use_type),
849 "sqlite_prepare"); 899 GNUNET_SQ_query_param_end
850 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); 900 };
851 return; 901
852 } 902 if (random)
853 sqoff = 1;
854 ret =
855 sqlite3_bind_blob (stmt, sqoff++, key, sizeof (struct GNUNET_HashCode),
856 SQLITE_TRANSIENT);
857 if ((vhash != NULL) && (ret == SQLITE_OK))
858 ret =
859 sqlite3_bind_blob (stmt, sqoff++, vhash, sizeof (struct GNUNET_HashCode),
860 SQLITE_TRANSIENT);
861 if ((type != 0) && (ret == SQLITE_OK))
862 ret = sqlite3_bind_int (stmt, sqoff++, type);
863 if (SQLITE_OK != ret)
864 {
865 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite_bind");
866 sqlite3_finalize (stmt);
867 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
868 return;
869 }
870 ret = sqlite3_step (stmt);
871 if (ret != SQLITE_ROW)
872 {
873 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
874 "sqlite_step");
875 sqlite3_finalize (stmt);
876 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
877 return;
878 }
879 total = sqlite3_column_int (stmt, 0);
880 sqlite3_finalize (stmt);
881 if (0 == total)
882 {
883 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
884 return;
885 }
886 limit_off = (int) (offset % total);
887 if (limit_off < 0)
888 limit_off += total;
889 GNUNET_snprintf (scratch, sizeof (scratch),
890 "SELECT type, prio, anonLevel, expire, hash, value, _ROWID_ "
891 "FROM gn090 WHERE hash=?%s%s "
892 "ORDER BY _ROWID_ ASC LIMIT 1 OFFSET ?",
893 vhash == NULL ? "" : " AND vhash=?",
894 type == 0 ? "" : " AND type=?");
895 if (sq_prepare (plugin->dbh, scratch, &stmt) != SQLITE_OK)
896 { 903 {
897 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 904 rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
898 "sqlite_prepare"); 905 UINT64_MAX);
899 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); 906 next_uid = 0;
900 return;
901 } 907 }
902 sqoff = 1; 908 else
903 ret = sqlite3_bind_blob (stmt, sqoff++, key, 909 rvalue = 0;
904 sizeof (struct GNUNET_HashCode), 910
905 SQLITE_TRANSIENT); 911 if (GNUNET_OK !=
906 if ((vhash != NULL) && (ret == SQLITE_OK)) 912 GNUNET_SQ_bind (plugin->get,
907 ret = sqlite3_bind_blob (stmt, sqoff++, vhash, 913 params))
908 sizeof (struct GNUNET_HashCode),
909 SQLITE_TRANSIENT);
910 if ((type != 0) && (ret == SQLITE_OK))
911 ret = sqlite3_bind_int (stmt, sqoff++, type);
912 if (ret == SQLITE_OK)
913 ret = sqlite3_bind_int64 (stmt, sqoff++, limit_off);
914 if (ret != SQLITE_OK)
915 { 914 {
916 LOG_SQLITE (plugin,
917 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
918 "sqlite_bind");
919 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); 915 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
920 return; 916 return;
921 } 917 }
922 execute_get (plugin, stmt, proc, proc_cls); 918 execute_get (plugin,
923 sqlite3_finalize (stmt); 919 plugin->get,
920 proc,
921 proc_cls);
924} 922}
925 923
926 924
@@ -984,13 +982,17 @@ repl_proc (void *cls,
984 struct ReplCtx *rc = cls; 982 struct ReplCtx *rc = cls;
985 int ret; 983 int ret;
986 984
985 if (GNUNET_SYSERR == rc->have_uid)
986 rc->have_uid = GNUNET_NO;
987 ret = rc->proc (rc->proc_cls, 987 ret = rc->proc (rc->proc_cls,
988 key, 988 key,
989 size, data, 989 size,
990 data,
990 type, 991 type,
991 priority, 992 priority,
992 anonymity, 993 anonymity,
993 expiration, uid); 994 expiration,
995 uid);
994 if (NULL != key) 996 if (NULL != key)
995 { 997 {
996 rc->uid = uid; 998 rc->uid = uid;
@@ -1011,81 +1013,77 @@ repl_proc (void *cls,
1011 * @param proc_cls closure for @a proc 1013 * @param proc_cls closure for @a proc
1012 */ 1014 */
1013static void 1015static void
1014sqlite_plugin_get_replication (void *cls, PluginDatumProcessor proc, 1016sqlite_plugin_get_replication (void *cls,
1017 PluginDatumProcessor proc,
1015 void *proc_cls) 1018 void *proc_cls)
1016{ 1019{
1017 struct Plugin *plugin = cls; 1020 struct Plugin *plugin = cls;
1018 struct ReplCtx rc; 1021 struct ReplCtx rc;
1019 uint64_t rvalue; 1022 uint64_t rvalue;
1020 uint32_t repl; 1023 uint32_t repl;
1021 sqlite3_stmt *stmt; 1024 struct GNUNET_SQ_QueryParam params_sel_repl[] = {
1022 1025 GNUNET_SQ_query_param_uint64 (&rvalue),
1023 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", 1026 GNUNET_SQ_query_param_uint32 (&repl),
1027 GNUNET_SQ_query_param_end
1028 };
1029 struct GNUNET_SQ_QueryParam params_upd_repl[] = {
1030 GNUNET_SQ_query_param_uint64 (&rc.uid),
1031 GNUNET_SQ_query_param_end
1032 };
1033
1034 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1035 "datastore-sqlite",
1024 "Getting random block based on replication order.\n"); 1036 "Getting random block based on replication order.\n");
1025 rc.have_uid = GNUNET_NO; 1037 if (SQLITE_ROW !=
1026 rc.proc = proc; 1038 sqlite3_step (plugin->maxRepl))
1027 rc.proc_cls = proc_cls;
1028 stmt = plugin->maxRepl;
1029 if (SQLITE_ROW != sqlite3_step (stmt))
1030 { 1039 {
1031 if (SQLITE_OK != sqlite3_reset (stmt)) 1040 GNUNET_SQ_reset (plugin->dbh,
1032 LOG_SQLITE (plugin, 1041 plugin->maxRepl);
1033 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1034 "sqlite3_reset");
1035 /* DB empty */ 1042 /* DB empty */
1036 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); 1043 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
1037 return; 1044 return;
1038 } 1045 }
1039 repl = sqlite3_column_int (stmt, 0); 1046 repl = sqlite3_column_int (plugin->maxRepl,
1040 if (SQLITE_OK != sqlite3_reset (stmt)) 1047 0);
1041 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 1048 GNUNET_SQ_reset (plugin->dbh,
1042 "sqlite3_reset"); 1049 plugin->maxRepl);
1043 stmt = plugin->selRepl; 1050 rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
1044 rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX); 1051 UINT64_MAX);
1045 if (SQLITE_OK != sqlite3_bind_int64 (stmt, 1, rvalue)) 1052 if (GNUNET_OK !=
1053 GNUNET_SQ_bind (plugin->selRepl,
1054 params_sel_repl))
1046 { 1055 {
1047 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1048 "sqlite3_bind_XXXX");
1049 if (SQLITE_OK != sqlite3_reset (stmt))
1050 LOG_SQLITE (plugin,
1051 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1052 "sqlite3_reset");
1053 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); 1056 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
1054 return; 1057 return;
1055 } 1058 }
1056 if (SQLITE_OK != sqlite3_bind_int (stmt, 2, repl)) 1059 rc.have_uid = GNUNET_SYSERR;
1057 { 1060 rc.proc = proc;
1058 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 1061 rc.proc_cls = proc_cls;
1059 "sqlite3_bind_XXXX"); 1062 execute_get (plugin,
1060 if (SQLITE_OK != sqlite3_reset (stmt)) 1063 plugin->selRepl,
1061 LOG_SQLITE (plugin, 1064 &repl_proc,
1062 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 1065 &rc);
1063 "sqlite3_reset");
1064 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
1065 return;
1066 }
1067 execute_get (plugin, stmt, &repl_proc, &rc);
1068 if (GNUNET_YES == rc.have_uid) 1066 if (GNUNET_YES == rc.have_uid)
1069 { 1067 {
1070 if (SQLITE_OK != sqlite3_bind_int64 (plugin->updRepl, 1, rc.uid)) 1068 if (GNUNET_OK !=
1069 GNUNET_SQ_bind (plugin->updRepl,
1070 params_upd_repl))
1071 { 1071 {
1072 LOG_SQLITE (plugin, 1072 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
1073 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1074 "sqlite3_bind_XXXX");
1075 if (SQLITE_OK != sqlite3_reset (plugin->updRepl))
1076 LOG_SQLITE (plugin,
1077 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1078 "sqlite3_reset");
1079 return; 1073 return;
1080 } 1074 }
1081 if (SQLITE_DONE != sqlite3_step (plugin->updRepl)) 1075 if (SQLITE_DONE !=
1076 sqlite3_step (plugin->updRepl))
1082 LOG_SQLITE (plugin, 1077 LOG_SQLITE (plugin,
1083 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 1078 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1084 "sqlite3_step"); 1079 "sqlite3_step");
1085 if (SQLITE_OK != sqlite3_reset (plugin->updRepl)) 1080 GNUNET_SQ_reset (plugin->dbh,
1086 LOG_SQLITE (plugin, 1081 plugin->updRepl);
1087 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 1082 }
1088 "sqlite3_reset"); 1083 if (GNUNET_SYSERR == rc.have_uid)
1084 {
1085 /* proc was not called at all so far, do it now. */
1086 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
1089 } 1087 }
1090} 1088}
1091 1089
@@ -1105,19 +1103,20 @@ sqlite_plugin_get_expiration (void *cls, PluginDatumProcessor proc,
1105 struct Plugin *plugin = cls; 1103 struct Plugin *plugin = cls;
1106 sqlite3_stmt *stmt; 1104 sqlite3_stmt *stmt;
1107 struct GNUNET_TIME_Absolute now; 1105 struct GNUNET_TIME_Absolute now;
1106 struct GNUNET_SQ_QueryParam params[] = {
1107 GNUNET_SQ_query_param_absolute_time (&now),
1108 GNUNET_SQ_query_param_end
1109 };
1108 1110
1109 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", 1111 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1112 "sqlite",
1110 "Getting random block based on expiration and priority order.\n"); 1113 "Getting random block based on expiration and priority order.\n");
1111 now = GNUNET_TIME_absolute_get (); 1114 now = GNUNET_TIME_absolute_get ();
1112 stmt = plugin->selExpi; 1115 stmt = plugin->selExpi;
1113 if (SQLITE_OK != sqlite3_bind_int64 (stmt, 1, now.abs_value_us)) 1116 if (GNUNET_OK !=
1117 GNUNET_SQ_bind (stmt,
1118 params))
1114 { 1119 {
1115 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1116 "sqlite3_bind_XXXX");
1117 if (SQLITE_OK != sqlite3_reset (stmt))
1118 LOG_SQLITE (plugin,
1119 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1120 "sqlite3_reset");
1121 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); 1120 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
1122 return; 1121 return;
1123 } 1122 }
@@ -1138,30 +1137,47 @@ sqlite_plugin_get_keys (void *cls,
1138 void *proc_cls) 1137 void *proc_cls)
1139{ 1138{
1140 struct Plugin *plugin = cls; 1139 struct Plugin *plugin = cls;
1141 const struct GNUNET_HashCode *key; 1140 struct GNUNET_HashCode key;
1141 struct GNUNET_SQ_ResultSpec results[] = {
1142 GNUNET_SQ_result_spec_auto_from_type (&key),
1143 GNUNET_SQ_result_spec_end
1144 };
1142 sqlite3_stmt *stmt; 1145 sqlite3_stmt *stmt;
1143 int ret; 1146 int ret;
1144 1147
1145 GNUNET_assert (proc != NULL); 1148 GNUNET_assert (NULL != proc);
1146 if (sq_prepare (plugin->dbh, "SELECT hash FROM gn090", &stmt) != SQLITE_OK) 1149 if (SQLITE_OK !=
1150 sq_prepare (plugin->dbh,
1151 "SELECT hash FROM gn090",
1152 &stmt))
1147 { 1153 {
1148 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 1154 LOG_SQLITE (plugin,
1155 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1149 "sqlite_prepare"); 1156 "sqlite_prepare");
1150 proc (proc_cls, NULL, 0); 1157 proc (proc_cls,
1158 NULL,
1159 0);
1151 return; 1160 return;
1152 } 1161 }
1153 while (SQLITE_ROW == (ret = sqlite3_step (stmt))) 1162 while (SQLITE_ROW == (ret = sqlite3_step (stmt)))
1154 { 1163 {
1155 key = sqlite3_column_blob (stmt, 0); 1164 if (GNUNET_OK ==
1156 if (sizeof (struct GNUNET_HashCode) == sqlite3_column_bytes (stmt, 0)) 1165 GNUNET_SQ_extract_result (stmt,
1157 proc (proc_cls, key, 1); 1166 results))
1167 proc (proc_cls,
1168 &key,
1169 1);
1158 else 1170 else
1159 GNUNET_break (0); 1171 GNUNET_break (0);
1160 } 1172 }
1161 if (SQLITE_DONE != ret) 1173 if (SQLITE_DONE != ret)
1162 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite_step"); 1174 LOG_SQLITE (plugin,
1175 GNUNET_ERROR_TYPE_ERROR,
1176 "sqlite_step");
1163 sqlite3_finalize (stmt); 1177 sqlite3_finalize (stmt);
1164 proc (proc_cls, NULL, 0); 1178 proc (proc_cls,
1179 NULL,
1180 0);
1165} 1181}
1166 1182
1167 1183
@@ -1187,7 +1203,8 @@ sqlite_plugin_drop (void *cls)
1187 * @return the size of the database on disk (estimate) 1203 * @return the size of the database on disk (estimate)
1188 */ 1204 */
1189static void 1205static void
1190sqlite_plugin_estimate_size (void *cls, unsigned long long *estimate) 1206sqlite_plugin_estimate_size (void *cls,
1207 unsigned long long *estimate)
1191{ 1208{
1192 struct Plugin *plugin = cls; 1209 struct Plugin *plugin = cls;
1193 sqlite3_stmt *stmt; 1210 sqlite3_stmt *stmt;
@@ -1202,30 +1219,45 @@ sqlite_plugin_estimate_size (void *cls, unsigned long long *estimate)
1202 return; 1219 return;
1203 if (SQLITE_VERSION_NUMBER < 3006000) 1220 if (SQLITE_VERSION_NUMBER < 3006000)
1204 { 1221 {
1205 GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "datastore-sqlite", 1222 GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
1206 _ 1223 "datastore-sqlite",
1207 ("sqlite version to old to determine size, assuming zero\n")); 1224 _("sqlite version to old to determine size, assuming zero\n"));
1208 *estimate = 0; 1225 *estimate = 0;
1209 return; 1226 return;
1210 } 1227 }
1211 CHECK (SQLITE_OK == sqlite3_exec (plugin->dbh, "VACUUM", NULL, NULL, ENULL));
1212 CHECK (SQLITE_OK == 1228 CHECK (SQLITE_OK ==
1213 sqlite3_exec (plugin->dbh, "PRAGMA auto_vacuum=INCREMENTAL", NULL, 1229 sqlite3_exec (plugin->dbh,
1230 "VACUUM",
1231 NULL,
1232 NULL,
1233 ENULL));
1234 CHECK (SQLITE_OK ==
1235 sqlite3_exec (plugin->dbh,
1236 "PRAGMA auto_vacuum=INCREMENTAL",
1237 NULL,
1214 NULL, ENULL)); 1238 NULL, ENULL));
1215 CHECK (SQLITE_OK == sq_prepare (plugin->dbh, "PRAGMA page_count", &stmt)); 1239 CHECK (SQLITE_OK ==
1240 sq_prepare (plugin->dbh,
1241 "PRAGMA page_count",
1242 &stmt));
1216 if (SQLITE_ROW == sqlite3_step (stmt)) 1243 if (SQLITE_ROW == sqlite3_step (stmt))
1217 pages = sqlite3_column_int64 (stmt, 0); 1244 pages = sqlite3_column_int64 (stmt,
1245 0);
1218 else 1246 else
1219 pages = 0; 1247 pages = 0;
1220 sqlite3_finalize (stmt); 1248 sqlite3_finalize (stmt);
1221 CHECK (SQLITE_OK == sq_prepare (plugin->dbh, "PRAGMA page_size", &stmt)); 1249 CHECK (SQLITE_OK ==
1222 CHECK (SQLITE_ROW == sqlite3_step (stmt)); 1250 sq_prepare (plugin->dbh,
1251 "PRAGMA page_size",
1252 &stmt));
1253 CHECK (SQLITE_ROW ==
1254 sqlite3_step (stmt));
1223 page_size = sqlite3_column_int64 (stmt, 0); 1255 page_size = sqlite3_column_int64 (stmt, 0);
1224 sqlite3_finalize (stmt); 1256 sqlite3_finalize (stmt);
1225 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1257 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1226 _ 1258 _("Using sqlite page utilization to estimate payload (%llu pages of size %llu bytes)\n"),
1227 ("Using sqlite page utilization to estimate payload (%llu pages of size %llu bytes)\n"), 1259 (unsigned long long) pages,
1228 (unsigned long long) pages, (unsigned long long) page_size); 1260 (unsigned long long) page_size);
1229 *estimate = pages * page_size; 1261 *estimate = pages * page_size;
1230} 1262}
1231 1263
@@ -1243,9 +1275,11 @@ libgnunet_plugin_datastore_sqlite_init (void *cls)
1243 struct GNUNET_DATASTORE_PluginEnvironment *env = cls; 1275 struct GNUNET_DATASTORE_PluginEnvironment *env = cls;
1244 struct GNUNET_DATASTORE_PluginFunctions *api; 1276 struct GNUNET_DATASTORE_PluginFunctions *api;
1245 1277
1246 if (plugin.env != NULL) 1278 if (NULL != plugin.env)
1247 return NULL; /* can only initialize once! */ 1279 return NULL; /* can only initialize once! */
1248 memset (&plugin, 0, sizeof (struct Plugin)); 1280 memset (&plugin,
1281 0,
1282 sizeof (struct Plugin));
1249 plugin.env = env; 1283 plugin.env = env;
1250 if (GNUNET_OK != database_setup (env->cfg, &plugin)) 1284 if (GNUNET_OK != database_setup (env->cfg, &plugin))
1251 { 1285 {
@@ -1263,7 +1297,8 @@ libgnunet_plugin_datastore_sqlite_init (void *cls)
1263 api->get_zero_anonymity = &sqlite_plugin_get_zero_anonymity; 1297 api->get_zero_anonymity = &sqlite_plugin_get_zero_anonymity;
1264 api->get_keys = &sqlite_plugin_get_keys; 1298 api->get_keys = &sqlite_plugin_get_keys;
1265 api->drop = &sqlite_plugin_drop; 1299 api->drop = &sqlite_plugin_drop;
1266 GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "sqlite", 1300 GNUNET_log_from (GNUNET_ERROR_TYPE_INFO,
1301 "sqlite",
1267 _("Sqlite database running\n")); 1302 _("Sqlite database running\n"));
1268 return api; 1303 return api;
1269} 1304}
@@ -1282,24 +1317,23 @@ libgnunet_plugin_datastore_sqlite_done (void *cls)
1282 struct GNUNET_DATASTORE_PluginFunctions *api = cls; 1317 struct GNUNET_DATASTORE_PluginFunctions *api = cls;
1283 struct Plugin *plugin = api->cls; 1318 struct Plugin *plugin = api->cls;
1284 1319
1285 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", 1320 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1321 "sqlite",
1286 "sqlite plugin is done\n"); 1322 "sqlite plugin is done\n");
1287 fn = NULL; 1323 fn = NULL;
1288 if (plugin->drop_on_shutdown) 1324 if (plugin->drop_on_shutdown)
1289 fn = GNUNET_strdup (plugin->fn); 1325 fn = GNUNET_strdup (plugin->fn);
1290 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite",
1291 "Shutting down database\n");
1292 database_shutdown (plugin); 1326 database_shutdown (plugin);
1293 plugin->env = NULL; 1327 plugin->env = NULL;
1294 GNUNET_free (api); 1328 GNUNET_free (api);
1295 if (fn != NULL) 1329 if (NULL != fn)
1296 { 1330 {
1297 if (0 != UNLINK (fn)) 1331 if (0 != UNLINK (fn))
1298 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", fn); 1332 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
1333 "unlink",
1334 fn);
1299 GNUNET_free (fn); 1335 GNUNET_free (fn);
1300 } 1336 }
1301 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite",
1302 "sqlite plugin is finished\n");
1303 return NULL; 1337 return NULL;
1304} 1338}
1305 1339
diff --git a/src/datastore/plugin_datastore_template.c b/src/datastore/plugin_datastore_template.c
index a1e03e8ee..187221798 100644
--- a/src/datastore/plugin_datastore_template.c
+++ b/src/datastore/plugin_datastore_template.c
@@ -89,8 +89,8 @@ template_plugin_put (void *cls, const struct GNUNET_HashCode * key, uint32_t siz
89 * Get one of the results for a particular key in the datastore. 89 * Get one of the results for a particular key in the datastore.
90 * 90 *
91 * @param cls closure 91 * @param cls closure
92 * @param offset offset of the result (modulo num-results); 92 * @param next_uid return the result with lowest uid >= next_uid
93 * specific ordering does not matter for the offset 93 * @param random if true, return a random result instead of using next_uid
94 * @param key maybe NULL (to match all entries) 94 * @param key maybe NULL (to match all entries)
95 * @param vhash hash of the value, maybe NULL (to 95 * @param vhash hash of the value, maybe NULL (to
96 * match all values that have the right key). 96 * match all values that have the right key).
@@ -104,7 +104,7 @@ template_plugin_put (void *cls, const struct GNUNET_HashCode * key, uint32_t siz
104 * @param proc_cls closure for proc 104 * @param proc_cls closure for proc
105 */ 105 */
106static void 106static void
107template_plugin_get_key (void *cls, uint64_t offset, 107template_plugin_get_key (void *cls, uint64_t next_uid, bool random,
108 const struct GNUNET_HashCode * key, 108 const struct GNUNET_HashCode * key,
109 const struct GNUNET_HashCode * vhash, 109 const struct GNUNET_HashCode * vhash,
110 enum GNUNET_BLOCK_Type type, PluginDatumProcessor proc, 110 enum GNUNET_BLOCK_Type type, PluginDatumProcessor proc,
@@ -185,16 +185,15 @@ template_plugin_update (void *cls, uint64_t uid, uint32_t delta,
185 * Call the given processor on an item with zero anonymity. 185 * Call the given processor on an item with zero anonymity.
186 * 186 *
187 * @param cls our "struct Plugin*" 187 * @param cls our "struct Plugin*"
188 * @param offset offset of the result (modulo num-results); 188 * @param next_uid return the result with lowest uid >= next_uid
189 * specific ordering does not matter for the offset
190 * @param type entries of which type should be considered? 189 * @param type entries of which type should be considered?
191 * Use 0 for any type. 190 * Must not be zero (ANY).
192 * @param proc function to call on each matching value; 191 * @param proc function to call on the matching value;
193 * will be called with NULL if no value matches 192 * will be called with NULL if no value matches
194 * @param proc_cls closure for proc 193 * @param proc_cls closure for proc
195 */ 194 */
196static void 195static void
197template_plugin_get_zero_anonymity (void *cls, uint64_t offset, 196template_plugin_get_zero_anonymity (void *cls, uint64_t next_uid,
198 enum GNUNET_BLOCK_Type type, 197 enum GNUNET_BLOCK_Type type,
199 PluginDatumProcessor proc, void *proc_cls) 198 PluginDatumProcessor proc, void *proc_cls)
200{ 199{
diff --git a/src/datastore/test_datastore_api.c b/src/datastore/test_datastore_api.c
index a99668240..0da68b266 100644
--- a/src/datastore/test_datastore_api.c
+++ b/src/datastore/test_datastore_api.c
@@ -156,8 +156,6 @@ struct CpsRunContext
156 void *data; 156 void *data;
157 size_t size; 157 size_t size;
158 158
159 uint64_t uid;
160 uint64_t offset;
161 uint64_t first_uid; 159 uint64_t first_uid;
162}; 160};
163 161
@@ -267,7 +265,6 @@ check_value (void *cls,
267 GNUNET_assert (priority == get_priority (i)); 265 GNUNET_assert (priority == get_priority (i));
268 GNUNET_assert (anonymity == get_anonymity (i)); 266 GNUNET_assert (anonymity == get_anonymity (i));
269 GNUNET_assert (expiration.abs_value_us == get_expiration (i).abs_value_us); 267 GNUNET_assert (expiration.abs_value_us == get_expiration (i).abs_value_us);
270 crc->offset++;
271 if (crc->i == 0) 268 if (crc->i == 0)
272 { 269 {
273 crc->phase = RP_DEL; 270 crc->phase = RP_DEL;
@@ -343,7 +340,6 @@ check_multiple (void *cls,
343 case RP_GET_MULTIPLE: 340 case RP_GET_MULTIPLE:
344 crc->phase = RP_GET_MULTIPLE_NEXT; 341 crc->phase = RP_GET_MULTIPLE_NEXT;
345 crc->first_uid = uid; 342 crc->first_uid = uid;
346 crc->offset++;
347 break; 343 break;
348 case RP_GET_MULTIPLE_NEXT: 344 case RP_GET_MULTIPLE_NEXT:
349 GNUNET_assert (uid != crc->first_uid); 345 GNUNET_assert (uid != crc->first_uid);
@@ -354,8 +350,6 @@ check_multiple (void *cls,
354 crc->phase = RP_ERROR; 350 crc->phase = RP_ERROR;
355 break; 351 break;
356 } 352 }
357 if (priority == get_priority (42))
358 crc->uid = uid;
359 GNUNET_SCHEDULER_add_now (&run_continuation, crc); 353 GNUNET_SCHEDULER_add_now (&run_continuation, crc);
360} 354}
361 355
@@ -400,7 +394,8 @@ run_continuation (void *cls)
400 sizeof (int), 394 sizeof (int),
401 &crc->key); 395 &crc->key);
402 GNUNET_DATASTORE_get_key (datastore, 396 GNUNET_DATASTORE_get_key (datastore,
403 crc->offset, 397 0,
398 false,
404 &crc->key, 399 &crc->key,
405 get_type (crc->i), 400 get_type (crc->i),
406 1, 401 1,
@@ -417,7 +412,8 @@ run_continuation (void *cls)
417 GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key); 412 GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
418 GNUNET_assert (NULL != 413 GNUNET_assert (NULL !=
419 GNUNET_DATASTORE_get_key (datastore, 414 GNUNET_DATASTORE_get_key (datastore,
420 crc->offset, 415 0,
416 false,
421 &crc->key, 417 &crc->key,
422 get_type (crc->i), 418 get_type (crc->i),
423 1, 419 1,
@@ -450,9 +446,15 @@ run_continuation (void *cls)
450 crc->i); 446 crc->i);
451 GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key); 447 GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
452 GNUNET_assert (NULL != 448 GNUNET_assert (NULL !=
453 GNUNET_DATASTORE_get_key (datastore, crc->offset, &crc->key, 449 GNUNET_DATASTORE_get_key (datastore,
454 get_type (crc->i), 1, 1, 450 0,
455 &check_nothing, crc)); 451 false,
452 &crc->key,
453 get_type (crc->i),
454 1,
455 1,
456 &check_nothing,
457 crc));
456 break; 458 break;
457 case RP_RESERVE: 459 case RP_RESERVE:
458 crc->phase = RP_PUT_MULTIPLE; 460 crc->phase = RP_PUT_MULTIPLE;
@@ -483,19 +485,26 @@ run_continuation (void *cls)
483 case RP_GET_MULTIPLE: 485 case RP_GET_MULTIPLE:
484 GNUNET_assert (NULL != 486 GNUNET_assert (NULL !=
485 GNUNET_DATASTORE_get_key (datastore, 487 GNUNET_DATASTORE_get_key (datastore,
486 crc->offset, 488 0,
489 false,
487 &crc->key, 490 &crc->key,
488 get_type (42), 1, 1, 491 get_type (42),
489 &check_multiple, crc)); 492 1,
493 1,
494 &check_multiple,
495 crc));
490 break; 496 break;
491 case RP_GET_MULTIPLE_NEXT: 497 case RP_GET_MULTIPLE_NEXT:
492 GNUNET_assert (NULL != 498 GNUNET_assert (NULL !=
493 GNUNET_DATASTORE_get_key (datastore, 499 GNUNET_DATASTORE_get_key (datastore,
494 crc->offset, 500 crc->first_uid + 1,
501 false,
495 &crc->key, 502 &crc->key,
496 get_type (42), 503 get_type (42),
497 1, 1, 504 1,
498 &check_multiple, crc)); 505 1,
506 &check_multiple,
507 crc));
499 break; 508 break;
500 case RP_DONE: 509 case RP_DONE:
501 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 510 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
diff --git a/src/datastore/test_datastore_api_management.c b/src/datastore/test_datastore_api_management.c
index 9a3e5446b..de4dc657f 100644
--- a/src/datastore/test_datastore_api_management.c
+++ b/src/datastore/test_datastore_api_management.c
@@ -58,7 +58,6 @@ struct CpsRunContext
58 const struct GNUNET_CONFIGURATION_Handle *cfg; 58 const struct GNUNET_CONFIGURATION_Handle *cfg;
59 void *data; 59 void *data;
60 enum RunPhase phase; 60 enum RunPhase phase;
61 uint64_t offset;
62}; 61};
63 62
64 63
@@ -159,7 +158,6 @@ check_value (void *cls, const struct GNUNET_HashCode * key, size_t size,
159 GNUNET_assert (priority == get_priority (i)); 158 GNUNET_assert (priority == get_priority (i));
160 GNUNET_assert (anonymity == get_anonymity (i)); 159 GNUNET_assert (anonymity == get_anonymity (i));
161 GNUNET_assert (expiration.abs_value_us == get_expiration (i).abs_value_us); 160 GNUNET_assert (expiration.abs_value_us == get_expiration (i).abs_value_us);
162 crc->offset++;
163 crc->i--; 161 crc->i--;
164 if (crc->i == 0) 162 if (crc->i == 0)
165 crc->phase = RP_DONE; 163 crc->phase = RP_DONE;
@@ -221,8 +219,13 @@ run_continuation (void *cls)
221 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing `%s' number %u\n", "GET", 219 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing `%s' number %u\n", "GET",
222 crc->i); 220 crc->i);
223 GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key); 221 GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
224 GNUNET_DATASTORE_get_key (datastore, crc->offset++, &crc->key, 222 GNUNET_DATASTORE_get_key (datastore,
225 get_type (crc->i), 1, 1, 223 0,
224 false,
225 &crc->key,
226 get_type (crc->i),
227 1,
228 1,
226 &check_value, 229 &check_value,
227 crc); 230 crc);
228 break; 231 break;
@@ -230,8 +233,13 @@ run_continuation (void *cls)
230 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing `%s' number %u\n", "GET(f)", 233 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing `%s' number %u\n", "GET(f)",
231 crc->i); 234 crc->i);
232 GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key); 235 GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
233 GNUNET_DATASTORE_get_key (datastore, crc->offset++, &crc->key, 236 GNUNET_DATASTORE_get_key (datastore,
234 get_type (crc->i), 1, 1, 237 0,
238 false,
239 &crc->key,
240 get_type (crc->i),
241 1,
242 1,
235 &check_nothing, 243 &check_nothing,
236 crc); 244 crc);
237 break; 245 break;
diff --git a/src/datastore/test_plugin_datastore.c b/src/datastore/test_plugin_datastore.c
index 9b85d57da..94d93aac6 100644
--- a/src/datastore/test_plugin_datastore.c
+++ b/src/datastore/test_plugin_datastore.c
@@ -64,7 +64,6 @@ struct CpsRunContext
64 enum RunPhase phase; 64 enum RunPhase phase;
65 unsigned int cnt; 65 unsigned int cnt;
66 unsigned int i; 66 unsigned int i;
67 uint64_t offset;
68}; 67};
69 68
70 69
@@ -308,7 +307,8 @@ test (void *cls)
308 "Looking for %s\n", 307 "Looking for %s\n",
309 GNUNET_h2s (&key)); 308 GNUNET_h2s (&key));
310 crc->api->get_key (crc->api->cls, 309 crc->api->get_key (crc->api->cls,
311 crc->offset++, 310 0,
311 false,
312 &key, 312 &key,
313 NULL, 313 NULL,
314 GNUNET_BLOCK_TYPE_ANY, 314 GNUNET_BLOCK_TYPE_ANY,
diff --git a/src/dht/dht_api.c b/src/dht/dht_api.c
index ee208b50e..42ddc7b60 100644
--- a/src/dht/dht_api.c
+++ b/src/dht/dht_api.c
@@ -319,7 +319,7 @@ send_get_known_results (struct GNUNET_DHT_GetHandle *gh,
319 unsigned int max; 319 unsigned int max;
320 unsigned int transmission_offset; 320 unsigned int transmission_offset;
321 321
322 max = (GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (*msg)) 322 max = (GNUNET_MAX_MESSAGE_SIZE - sizeof (*msg))
323 / sizeof (struct GNUNET_HashCode); 323 / sizeof (struct GNUNET_HashCode);
324 transmission_offset = transmission_offset_start; 324 transmission_offset = transmission_offset_start;
325 while (transmission_offset < gh->seen_results_end) 325 while (transmission_offset < gh->seen_results_end)
@@ -704,9 +704,9 @@ check_client_result (void *cls,
704 sizeof (struct GNUNET_PeerIdentity) * (get_path_length + put_path_length); 704 sizeof (struct GNUNET_PeerIdentity) * (get_path_length + put_path_length);
705 if ( (msize < meta_length) || 705 if ( (msize < meta_length) ||
706 (get_path_length > 706 (get_path_length >
707 GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)) || 707 GNUNET_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)) ||
708 (put_path_length > 708 (put_path_length >
709 GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)) ) 709 GNUNET_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)) )
710 { 710 {
711 GNUNET_break (0); 711 GNUNET_break (0);
712 return GNUNET_SYSERR; 712 return GNUNET_SYSERR;
@@ -998,8 +998,8 @@ GNUNET_DHT_put (struct GNUNET_DHT_Handle *handle,
998 struct GNUNET_DHT_PutHandle *ph; 998 struct GNUNET_DHT_PutHandle *ph;
999 999
1000 msize = sizeof (struct GNUNET_DHT_ClientPutMessage) + size; 1000 msize = sizeof (struct GNUNET_DHT_ClientPutMessage) + size;
1001 if ((msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) || 1001 if ((msize >= GNUNET_MAX_MESSAGE_SIZE) ||
1002 (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)) 1002 (size >= GNUNET_MAX_MESSAGE_SIZE))
1003 { 1003 {
1004 GNUNET_break (0); 1004 GNUNET_break (0);
1005 return NULL; 1005 return NULL;
@@ -1090,8 +1090,8 @@ GNUNET_DHT_get_start (struct GNUNET_DHT_Handle *handle,
1090 size_t msize; 1090 size_t msize;
1091 1091
1092 msize = sizeof (struct GNUNET_DHT_ClientGetMessage) + xquery_size; 1092 msize = sizeof (struct GNUNET_DHT_ClientGetMessage) + xquery_size;
1093 if ((msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) || 1093 if ((msize >= GNUNET_MAX_MESSAGE_SIZE) ||
1094 (xquery_size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)) 1094 (xquery_size >= GNUNET_MAX_MESSAGE_SIZE))
1095 { 1095 {
1096 GNUNET_break (0); 1096 GNUNET_break (0);
1097 return NULL; 1097 return NULL;
diff --git a/src/dht/gnunet-dht-get.c b/src/dht/gnunet-dht-get.c
index ce479dc3e..67f0ce76d 100644
--- a/src/dht/gnunet-dht-get.c
+++ b/src/dht/gnunet-dht-get.c
@@ -50,7 +50,7 @@ static struct GNUNET_TIME_Relative timeout_request = { 60000 };
50/** 50/**
51 * Be verbose 51 * Be verbose
52 */ 52 */
53static int verbose; 53static unsigned int verbose;
54 54
55/** 55/**
56 * Use DHT demultixplex_everywhere 56 * Use DHT demultixplex_everywhere
@@ -226,33 +226,6 @@ run (void *cls, char *const *args, const char *cfgfile,
226 226
227} 227}
228 228
229
230/**
231 * gnunet-dht-get command line options
232 */
233static struct GNUNET_GETOPT_CommandLineOption options[] = {
234 {'k', "key", "KEY",
235 gettext_noop ("the query key"),
236 1, &GNUNET_GETOPT_set_string, &query_key},
237 {'r', "replication", "LEVEL",
238 gettext_noop ("how many parallel requests (replicas) to create"),
239 1, &GNUNET_GETOPT_set_uint, &replication},
240 {'t', "type", "TYPE",
241 gettext_noop ("the type of data to look for"),
242 1, &GNUNET_GETOPT_set_uint, &query_type},
243 {'T', "timeout", "TIMEOUT",
244 gettext_noop ("how long to execute this query before giving up?"),
245 1, &GNUNET_GETOPT_set_relative_time, &timeout_request},
246 {'x', "demultiplex", NULL,
247 gettext_noop ("use DHT's demultiplex everywhere option"),
248 0, &GNUNET_GETOPT_set_one, &demultixplex_everywhere},
249 {'V', "verbose", NULL,
250 gettext_noop ("be verbose (print progress information)"),
251 0, &GNUNET_GETOPT_set_one, &verbose},
252 GNUNET_GETOPT_OPTION_END
253};
254
255
256/** 229/**
257 * Entry point for gnunet-dht-get 230 * Entry point for gnunet-dht-get
258 * 231 *
@@ -263,6 +236,45 @@ static struct GNUNET_GETOPT_CommandLineOption options[] = {
263int 236int
264main (int argc, char *const *argv) 237main (int argc, char *const *argv)
265{ 238{
239
240 struct GNUNET_GETOPT_CommandLineOption options[] = {
241
242 GNUNET_GETOPT_OPTION_STRING ('k',
243 "key",
244 "KEY",
245 gettext_noop ("the query key"),
246 &query_key),
247
248 GNUNET_GETOPT_OPTION_SET_UINT ('r',
249 "replication",
250 "LEVEL",
251 gettext_noop ("how many parallel requests (replicas) to create"),
252 &replication),
253
254
255 GNUNET_GETOPT_OPTION_SET_UINT ('t',
256 "type",
257 "TYPE",
258 gettext_noop ("the type of data to look for"),
259 &query_type),
260
261 GNUNET_GETOPT_OPTION_SET_RELATIVE_TIME ('T',
262 "timeout",
263 "TIMEOUT",
264 gettext_noop ("how long to execute this query before giving up?"),
265 &timeout_request),
266
267 GNUNET_GETOPT_OPTION_SET_ONE ('x',
268 "demultiplex",
269 gettext_noop ("use DHT's demultiplex everywhere option"),
270 &demultixplex_everywhere),
271
272 GNUNET_GETOPT_OPTION_VERBOSE (&verbose),
273 GNUNET_GETOPT_OPTION_END
274 };
275
276
277
266 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) 278 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
267 return 2; 279 return 2;
268 return (GNUNET_OK == 280 return (GNUNET_OK ==
diff --git a/src/dht/gnunet-dht-monitor.c b/src/dht/gnunet-dht-monitor.c
index 7f14255d3..e4e8c46a1 100644
--- a/src/dht/gnunet-dht-monitor.c
+++ b/src/dht/gnunet-dht-monitor.c
@@ -280,27 +280,6 @@ run (void *cls, char *const *args, const char *cfgfile,
280 NULL); 280 NULL);
281} 281}
282 282
283
284/**
285 * gnunet-dht-monitor command line options
286 */
287static struct GNUNET_GETOPT_CommandLineOption options[] = {
288 {'k', "key", "KEY",
289 gettext_noop ("the query key"),
290 1, &GNUNET_GETOPT_set_string, &query_key},
291 {'t', "type", "TYPE",
292 gettext_noop ("the type of data to look for"),
293 1, &GNUNET_GETOPT_set_uint, &block_type},
294 {'T', "timeout", "TIMEOUT",
295 gettext_noop ("how long should the monitor command run"),
296 1, &GNUNET_GETOPT_set_relative_time, &timeout_request},
297 {'V', "verbose", NULL,
298 gettext_noop ("be verbose (print progress information)"),
299 0, &GNUNET_GETOPT_set_one, &verbose},
300 GNUNET_GETOPT_OPTION_END
301};
302
303
304/** 283/**
305 * Entry point for gnunet-dht-monitor 284 * Entry point for gnunet-dht-monitor
306 * 285 *
@@ -311,6 +290,35 @@ static struct GNUNET_GETOPT_CommandLineOption options[] = {
311int 290int
312main (int argc, char *const *argv) 291main (int argc, char *const *argv)
313{ 292{
293 struct GNUNET_GETOPT_CommandLineOption options[] = {
294
295 GNUNET_GETOPT_OPTION_STRING ('k',
296 "key",
297 "KEY",
298 gettext_noop ("the query key"),
299 &query_key),
300
301 GNUNET_GETOPT_OPTION_SET_UINT ('t',
302 "type",
303 "TYPE",
304 gettext_noop ("the type of data to look for"),
305 &block_type),
306
307 GNUNET_GETOPT_OPTION_SET_RELATIVE_TIME ('T',
308 "timeout",
309 "TIMEOUT",
310 gettext_noop ("how long should the monitor command run"),
311 &timeout_request),
312
313 GNUNET_GETOPT_OPTION_SET_ONE ('V',
314 "verbose",
315 gettext_noop ("be verbose (print progress information)"),
316 &verbose),
317
318 GNUNET_GETOPT_OPTION_END
319 };
320
321
314 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) 322 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
315 return 2; 323 return 2;
316 324
diff --git a/src/dht/gnunet-dht-put.c b/src/dht/gnunet-dht-put.c
index 64764cb65..bf88e5ded 100644
--- a/src/dht/gnunet-dht-put.c
+++ b/src/dht/gnunet-dht-put.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 Copyright (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009 GNUnet e.V. 3 Copyright (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009, 2017 GNUnet e.V.
4 4
5 GNUnet is free software; you can redistribute it and/or modify 5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published 6 it under the terms of the GNU General Public License as published
@@ -54,7 +54,7 @@ static unsigned int replication = 5;
54/** 54/**
55 * Be verbose 55 * Be verbose
56 */ 56 */
57static int verbose; 57static unsigned int verbose;
58 58
59/** 59/**
60 * Use #GNUNET_DHT_DEMULTIPLEX_EVERYWHERE. 60 * Use #GNUNET_DHT_DEMULTIPLEX_EVERYWHERE.
@@ -148,7 +148,6 @@ run (void *cls,
148 const char *cfgfile, 148 const char *cfgfile,
149 const struct GNUNET_CONFIGURATION_Handle *c) 149 const struct GNUNET_CONFIGURATION_Handle *c)
150{ 150{
151 struct GNUNET_TIME_Absolute expiration;
152 enum GNUNET_DHT_RouteOption ro; 151 enum GNUNET_DHT_RouteOption ro;
153 152
154 cfg = c; 153 cfg = c;
@@ -187,44 +186,11 @@ run (void *cls,
187 query_type, 186 query_type,
188 strlen (data), 187 strlen (data),
189 data, 188 data,
190 expiration, 189 GNUNET_TIME_relative_to_absolute (expiration),
191 &message_sent_cont, 190 &message_sent_cont,
192 NULL); 191 NULL);
193} 192}
194 193
195
196/**
197 * gnunet-dht-put command line options
198 */
199static struct GNUNET_GETOPT_CommandLineOption options[] = {
200 {'d', "data", "DATA",
201 gettext_noop ("the data to insert under the key"),
202 1, &GNUNET_GETOPT_set_string, &data},
203 {'e', "expiration", "EXPIRATION",
204 gettext_noop ("how long to store this entry in the dht (in seconds)"),
205 1, &GNUNET_GETOPT_set_relative_time, &expiration},
206 {'k', "key", "KEY",
207 gettext_noop ("the query key"),
208 1, &GNUNET_GETOPT_set_string, &query_key},
209 {'x', "demultiplex", NULL,
210 gettext_noop ("use DHT's demultiplex everywhere option"),
211 0, &GNUNET_GETOPT_set_one, &demultixplex_everywhere},
212 {'r', "replication", "LEVEL",
213 gettext_noop ("how many replicas to create"),
214 1, &GNUNET_GETOPT_set_uint, &replication},
215 {'R', "record", NULL,
216 gettext_noop ("use DHT's record route option"),
217 0, &GNUNET_GETOPT_set_one, &record_route},
218 {'t', "type", "TYPE",
219 gettext_noop ("the type to insert data as"),
220 1, &GNUNET_GETOPT_set_uint, &query_type},
221 {'V', "verbose", NULL,
222 gettext_noop ("be verbose (print progress information)"),
223 0, &GNUNET_GETOPT_set_one, &verbose},
224 GNUNET_GETOPT_OPTION_END
225};
226
227
228/** 194/**
229 * Entry point for gnunet-dht-put 195 * Entry point for gnunet-dht-put
230 * 196 *
@@ -235,6 +201,55 @@ static struct GNUNET_GETOPT_CommandLineOption options[] = {
235int 201int
236main (int argc, char *const *argv) 202main (int argc, char *const *argv)
237{ 203{
204
205 struct GNUNET_GETOPT_CommandLineOption options[] = {
206
207 GNUNET_GETOPT_OPTION_STRING ('d',
208 "data",
209 "DATA",
210 gettext_noop ("the data to insert under the key"),
211 &data),
212
213 GNUNET_GETOPT_OPTION_SET_RELATIVE_TIME ('e',
214 "expiration",
215 "EXPIRATION",
216 gettext_noop ("how long to store this entry in the dht (in seconds)"),
217 &expiration),
218
219 GNUNET_GETOPT_OPTION_STRING ('k',
220 "key",
221 "KEY",
222 gettext_noop ("the query key"),
223 &query_key),
224
225 GNUNET_GETOPT_OPTION_SET_ONE ('x',
226 "demultiplex",
227 gettext_noop ("use DHT's demultiplex everywhere option"),
228 &demultixplex_everywhere),
229
230 GNUNET_GETOPT_OPTION_SET_UINT ('r',
231 "replication",
232 "LEVEL",
233 gettext_noop ("how many replicas to create"),
234 &replication),
235
236 GNUNET_GETOPT_OPTION_SET_ONE ('R',
237 "record",
238 gettext_noop ("use DHT's record route option"),
239 &record_route),
240
241 GNUNET_GETOPT_OPTION_SET_UINT ('t',
242 "type",
243 "TYPE",
244 gettext_noop ("the type to insert data as"),
245 &query_type),
246
247 GNUNET_GETOPT_OPTION_VERBOSE (&verbose),
248
249 GNUNET_GETOPT_OPTION_END
250 };
251
252
238 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, 253 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv,
239 &argc, &argv)) 254 &argc, &argv))
240 return 2; 255 return 2;
diff --git a/src/dht/gnunet-service-dht_clients.c b/src/dht/gnunet-service-dht_clients.c
index 0f521a401..cb155c484 100644
--- a/src/dht/gnunet-service-dht_clients.c
+++ b/src/dht/gnunet-service-dht_clients.c
@@ -1166,7 +1166,7 @@ GDS_CLIENTS_handle_reply (struct GNUNET_TIME_Absolute expiration,
1166 1166
1167 msize = sizeof (struct GNUNET_DHT_ClientResultMessage) + data_size + 1167 msize = sizeof (struct GNUNET_DHT_ClientResultMessage) + data_size +
1168 (get_path_length + put_path_length) * sizeof (struct GNUNET_PeerIdentity); 1168 (get_path_length + put_path_length) * sizeof (struct GNUNET_PeerIdentity);
1169 if (msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) 1169 if (msize >= GNUNET_MAX_MESSAGE_SIZE)
1170 { 1170 {
1171 GNUNET_break (0); 1171 GNUNET_break (0);
1172 return; 1172 return;
diff --git a/src/dht/gnunet-service-dht_datacache.c b/src/dht/gnunet-service-dht_datacache.c
index fef637cad..36047d561 100644
--- a/src/dht/gnunet-service-dht_datacache.c
+++ b/src/dht/gnunet-service-dht_datacache.c
@@ -72,7 +72,7 @@ GDS_DATACACHE_handle_put (struct GNUNET_TIME_Absolute expiration,
72 _("%s request received, but have no datacache!\n"), "PUT"); 72 _("%s request received, but have no datacache!\n"), "PUT");
73 return; 73 return;
74 } 74 }
75 if (data_size >= GNUNET_SERVER_MAX_MESSAGE_SIZE) 75 if (data_size >= GNUNET_MAX_MESSAGE_SIZE)
76 { 76 {
77 GNUNET_break (0); 77 GNUNET_break (0);
78 return; 78 return;
diff --git a/src/dht/gnunet-service-dht_neighbours.c b/src/dht/gnunet-service-dht_neighbours.c
index 15071edca..0309bea88 100644
--- a/src/dht/gnunet-service-dht_neighbours.c
+++ b/src/dht/gnunet-service-dht_neighbours.c
@@ -1423,7 +1423,7 @@ GDS_NEIGHBOURS_handle_get (enum GNUNET_BLOCK_Type type,
1423 UINT32_MAX); 1423 UINT32_MAX);
1424 } 1424 }
1425 msize = xquery_size + reply_bf_size; 1425 msize = xquery_size + reply_bf_size;
1426 if (msize + sizeof (struct PeerGetMessage) >= GNUNET_SERVER_MAX_MESSAGE_SIZE) 1426 if (msize + sizeof (struct PeerGetMessage) >= GNUNET_MAX_MESSAGE_SIZE)
1427 { 1427 {
1428 GNUNET_break (0); 1428 GNUNET_break (0);
1429 GNUNET_free_non_null (reply_bf); 1429 GNUNET_free_non_null (reply_bf);
@@ -1522,12 +1522,12 @@ GDS_NEIGHBOURS_handle_reply (const struct GNUNET_PeerIdentity *target,
1522 1522
1523 msize = data_size + (get_path_length + put_path_length) * 1523 msize = data_size + (get_path_length + put_path_length) *
1524 sizeof (struct GNUNET_PeerIdentity); 1524 sizeof (struct GNUNET_PeerIdentity);
1525 if ((msize + sizeof (struct PeerResultMessage) >= GNUNET_SERVER_MAX_MESSAGE_SIZE) || 1525 if ((msize + sizeof (struct PeerResultMessage) >= GNUNET_MAX_MESSAGE_SIZE) ||
1526 (get_path_length > 1526 (get_path_length >
1527 GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)) || 1527 GNUNET_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)) ||
1528 (put_path_length > 1528 (put_path_length >
1529 GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)) || 1529 GNUNET_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)) ||
1530 (data_size > GNUNET_SERVER_MAX_MESSAGE_SIZE)) 1530 (data_size > GNUNET_MAX_MESSAGE_SIZE))
1531 { 1531 {
1532 GNUNET_break (0); 1532 GNUNET_break (0);
1533 return; 1533 return;
@@ -1627,7 +1627,7 @@ check_dht_p2p_put (void *cls,
1627 sizeof (struct PeerPutMessage) + 1627 sizeof (struct PeerPutMessage) +
1628 putlen * sizeof (struct GNUNET_PeerIdentity)) || 1628 putlen * sizeof (struct GNUNET_PeerIdentity)) ||
1629 (putlen > 1629 (putlen >
1630 GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity))) 1630 GNUNET_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)))
1631 { 1631 {
1632 GNUNET_break_op (0); 1632 GNUNET_break_op (0);
1633 return GNUNET_SYSERR; 1633 return GNUNET_SYSERR;
@@ -2213,9 +2213,9 @@ check_dht_p2p_result (void *cls,
2213 put_path_length) * 2213 put_path_length) *
2214 sizeof (struct GNUNET_PeerIdentity)) || 2214 sizeof (struct GNUNET_PeerIdentity)) ||
2215 (get_path_length > 2215 (get_path_length >
2216 GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)) || 2216 GNUNET_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)) ||
2217 (put_path_length > 2217 (put_path_length >
2218 GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity))) 2218 GNUNET_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)))
2219 { 2219 {
2220 GNUNET_break_op (0); 2220 GNUNET_break_op (0);
2221 return GNUNET_SYSERR; 2221 return GNUNET_SYSERR;
diff --git a/src/dht/gnunet_dht_profiler.c b/src/dht/gnunet_dht_profiler.c
index 460eaa572..f65141640 100644
--- a/src/dht/gnunet_dht_profiler.c
+++ b/src/dht/gnunet_dht_profiler.c
@@ -1181,31 +1181,54 @@ main (int argc, char *const *argv)
1181{ 1181{
1182 int rc; 1182 int rc;
1183 1183
1184 static struct GNUNET_GETOPT_CommandLineOption options[] = { 1184 struct GNUNET_GETOPT_CommandLineOption options[] = {
1185 {'n', "peers", "COUNT", 1185 GNUNET_GETOPT_OPTION_SET_UINT ('n',
1186 gettext_noop ("number of peers to start"), 1186 "peers",
1187 1, &GNUNET_GETOPT_set_uint, &num_peers}, 1187 "COUNT",
1188 {'s', "searches", "COUNT", 1188 gettext_noop ("number of peers to start"),
1189 gettext_noop ("maximum number of times we try to search for successor circle formation (0 for R5N)"), 1189 &num_peers),
1190 1, &GNUNET_GETOPT_set_uint, &max_searches}, 1190
1191 {'H', "hosts", "FILENAME", 1191 GNUNET_GETOPT_OPTION_SET_UINT ('s',
1192 gettext_noop ("name of the file with the login information for the testbed"), 1192 "searches",
1193 1, &GNUNET_GETOPT_set_string, &hosts_file}, 1193 "COUNT",
1194 {'D', "delay", "DELAY", 1194 gettext_noop ("maximum number of times we try to search for successor circle formation (0 for R5N)"),
1195 gettext_noop ("delay between rounds for collecting statistics (default: 30 sec)"), 1195 &max_searches),
1196 1, &GNUNET_GETOPT_set_relative_time, &delay_stats}, 1196
1197 {'P', "PUT-delay", "DELAY", 1197 GNUNET_GETOPT_OPTION_STRING ('H',
1198 gettext_noop ("delay to start doing PUTs (default: 1 sec)"), 1198 "hosts",
1199 1, &GNUNET_GETOPT_set_relative_time, &delay_put}, 1199 "FILENAME",
1200 {'G', "GET-delay", "DELAY", 1200 gettext_noop ("name of the file with the login information for the testbed"),
1201 gettext_noop ("delay to start doing GETs (default: 5 min)"), 1201 &hosts_file),
1202 1, &GNUNET_GETOPT_set_relative_time, &delay_get}, 1202
1203 {'r', "replication", "DEGREE", 1203 GNUNET_GETOPT_OPTION_SET_RELATIVE_TIME ('D',
1204 gettext_noop ("replication degree for DHT PUTs"), 1204 "delay",
1205 1, &GNUNET_GETOPT_set_uint, &replication}, 1205 "DELAY",
1206 {'t', "timeout", "TIMEOUT", 1206 gettext_noop ("delay between rounds for collecting statistics (default: 30 sec)"),
1207 gettext_noop ("timeout for DHT PUT and GET requests (default: 1 min)"), 1207 &delay_stats),
1208 1, &GNUNET_GETOPT_set_relative_time, &timeout}, 1208
1209 GNUNET_GETOPT_OPTION_SET_RELATIVE_TIME ('P',
1210 "PUT-delay",
1211 "DELAY",
1212 gettext_noop ("delay to start doing PUTs (default: 1 sec)"),
1213 &delay_put),
1214
1215 GNUNET_GETOPT_OPTION_SET_RELATIVE_TIME ('G',
1216 "GET-delay",
1217 "DELAY",
1218 gettext_noop ("delay to start doing GETs (default: 5 min)"),
1219 &delay_get),
1220 GNUNET_GETOPT_OPTION_SET_UINT ('r',
1221 "replication",
1222 "DEGREE",
1223 gettext_noop ("replication degree for DHT PUTs"),
1224 &replication),
1225
1226
1227 GNUNET_GETOPT_OPTION_SET_RELATIVE_TIME ('t',
1228 "timeout",
1229 "TIMEOUT",
1230 gettext_noop ("timeout for DHT PUT and GET requests (default: 1 min)"),
1231 &timeout),
1209 GNUNET_GETOPT_OPTION_END 1232 GNUNET_GETOPT_OPTION_END
1210 }; 1233 };
1211 1234
diff --git a/src/dns/Makefile.am b/src/dns/Makefile.am
index f74c41fc5..5af228121 100644
--- a/src/dns/Makefile.am
+++ b/src/dns/Makefile.am
@@ -106,6 +106,7 @@ libgnunetdns_la_LDFLAGS = \
106libgnunet_plugin_block_dns_la_SOURCES = \ 106libgnunet_plugin_block_dns_la_SOURCES = \
107 plugin_block_dns.c 107 plugin_block_dns.c
108libgnunet_plugin_block_dns_la_LIBADD = \ 108libgnunet_plugin_block_dns_la_LIBADD = \
109 $(top_builddir)/src/block/libgnunetblockgroup.la \
109 $(top_builddir)/src/util/libgnunetutil.la 110 $(top_builddir)/src/util/libgnunetutil.la
110libgnunet_plugin_block_dns_la_LDFLAGS = \ 111libgnunet_plugin_block_dns_la_LDFLAGS = \
111 $(top_builddir)/src/block/$(GN_PLUGIN_LDFLAGS) 112 $(top_builddir)/src/block/$(GN_PLUGIN_LDFLAGS)
diff --git a/src/dns/dns_api.c b/src/dns/dns_api.c
index e7450a1d4..9f0dee9a9 100644
--- a/src/dns/dns_api.c
+++ b/src/dns/dns_api.c
@@ -317,7 +317,7 @@ GNUNET_DNS_request_answer (struct GNUNET_DNS_RequestHandle *rh,
317 return; 317 return;
318 } 318 }
319 if (reply_length + sizeof (struct GNUNET_DNS_Response) 319 if (reply_length + sizeof (struct GNUNET_DNS_Response)
320 >= GNUNET_SERVER_MAX_MESSAGE_SIZE) 320 >= GNUNET_MAX_MESSAGE_SIZE)
321 { 321 {
322 GNUNET_break (0); 322 GNUNET_break (0);
323 GNUNET_free (rh); 323 GNUNET_free (rh);
diff --git a/src/dns/gnunet-dns-monitor.c b/src/dns/gnunet-dns-monitor.c
index 5e6f90555..2436931fb 100644
--- a/src/dns/gnunet-dns-monitor.c
+++ b/src/dns/gnunet-dns-monitor.c
@@ -52,7 +52,7 @@ static int ret;
52/** 52/**
53 * Selected level of verbosity. 53 * Selected level of verbosity.
54 */ 54 */
55static int verbosity; 55static unsigned int verbosity;
56 56
57 57
58/** 58/**
@@ -346,13 +346,18 @@ run (void *cls, char *const *args, const char *cfgfile,
346int 346int
347main (int argc, char *const *argv) 347main (int argc, char *const *argv)
348{ 348{
349 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 349 struct GNUNET_GETOPT_CommandLineOption options[] = {
350 {'i', "inbound-only", NULL, 350
351 gettext_noop ("only monitor DNS queries"), 351 GNUNET_GETOPT_OPTION_SET_ONE ('i',
352 0, &GNUNET_GETOPT_set_one, &inbound_only}, 352 "inbound-only",
353 {'o', "outbound-only", NULL, 353 gettext_noop ("only monitor DNS queries"),
354 gettext_noop ("only monitor DNS replies"), 354 &inbound_only),
355 0, &GNUNET_GETOPT_set_one, &outbound_only}, 355
356 GNUNET_GETOPT_OPTION_SET_ONE ('o',
357 "outbound-only",
358 gettext_noop ("only monitor DNS queries"),
359 &outbound_only),
360
356 GNUNET_GETOPT_OPTION_VERBOSE (&verbosity), 361 GNUNET_GETOPT_OPTION_VERBOSE (&verbosity),
357 GNUNET_GETOPT_OPTION_END 362 GNUNET_GETOPT_OPTION_END
358 }; 363 };
diff --git a/src/dns/gnunet-dns-redirector.c b/src/dns/gnunet-dns-redirector.c
index 89929815a..0469af732 100644
--- a/src/dns/gnunet-dns-redirector.c
+++ b/src/dns/gnunet-dns-redirector.c
@@ -52,7 +52,7 @@ static int ret;
52/** 52/**
53 * Selected level of verbosity. 53 * Selected level of verbosity.
54 */ 54 */
55static int verbosity; 55static unsigned int verbosity;
56 56
57 57
58/** 58/**
@@ -230,13 +230,19 @@ run (void *cls, char *const *args, const char *cfgfile,
230int 230int
231main (int argc, char *const *argv) 231main (int argc, char *const *argv)
232{ 232{
233 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 233 struct GNUNET_GETOPT_CommandLineOption options[] = {
234 {'4', "ipv4", "IPV4", 234 GNUNET_GETOPT_OPTION_STRING ('4',
235 gettext_noop ("set A records"), 235 "ipv4",
236 1, &GNUNET_GETOPT_set_string, &n4}, 236 "IPV4",
237 {'6', "ipv4", "IPV6", 237 gettext_noop ("set A records"),
238 gettext_noop ("set AAAA records"), 238 &n4),
239 1, &GNUNET_GETOPT_set_string, &n6}, 239
240 GNUNET_GETOPT_OPTION_STRING ('6',
241 "ipv4",
242 "IPV6",
243 gettext_noop ("set AAAA records"),
244 &n6),
245
240 GNUNET_GETOPT_OPTION_VERBOSE (&verbosity), 246 GNUNET_GETOPT_OPTION_VERBOSE (&verbosity),
241 GNUNET_GETOPT_OPTION_END 247 GNUNET_GETOPT_OPTION_END
242 }; 248 };
diff --git a/src/dns/gnunet-helper-dns.c b/src/dns/gnunet-helper-dns.c
index d083a9df2..5cf1967f5 100644
--- a/src/dns/gnunet-helper-dns.c
+++ b/src/dns/gnunet-helper-dns.c
@@ -79,7 +79,7 @@
79#include "gnunet_protocols.h" 79#include "gnunet_protocols.h"
80 80
81/** 81/**
82 * Maximum size of a GNUnet message (GNUNET_SERVER_MAX_MESSAGE_SIZE) 82 * Maximum size of a GNUnet message (GNUNET_MAX_MESSAGE_SIZE)
83 */ 83 */
84#define MAX_SIZE 65536 84#define MAX_SIZE 65536
85 85
diff --git a/src/dns/gnunet-service-dns.c b/src/dns/gnunet-service-dns.c
index 74f595c5e..ffc94afb7 100644
--- a/src/dns/gnunet-service-dns.c
+++ b/src/dns/gnunet-service-dns.c
@@ -347,7 +347,7 @@ request_done (struct RequestRecord *rr)
347 } 347 }
348 reply_len += sizeof (struct GNUNET_TUN_UdpHeader); 348 reply_len += sizeof (struct GNUNET_TUN_UdpHeader);
349 reply_len += rr->payload_length; 349 reply_len += rr->payload_length;
350 if (reply_len >= GNUNET_SERVER_MAX_MESSAGE_SIZE) 350 if (reply_len >= GNUNET_MAX_MESSAGE_SIZE)
351 { 351 {
352 /* response too big, drop */ 352 /* response too big, drop */
353 GNUNET_break (0); /* how can this be? */ 353 GNUNET_break (0); /* how can this be? */
@@ -481,7 +481,7 @@ send_request_to_client (struct RequestRecord *rr,
481 struct GNUNET_MQ_Envelope *env; 481 struct GNUNET_MQ_Envelope *env;
482 struct GNUNET_DNS_Request *req; 482 struct GNUNET_DNS_Request *req;
483 483
484 if (sizeof (struct GNUNET_DNS_Request) + rr->payload_length >= GNUNET_SERVER_MAX_MESSAGE_SIZE) 484 if (sizeof (struct GNUNET_DNS_Request) + rr->payload_length >= GNUNET_MAX_MESSAGE_SIZE)
485 { 485 {
486 GNUNET_break (0); 486 GNUNET_break (0);
487 cleanup_rr (rr); 487 cleanup_rr (rr);
@@ -882,11 +882,10 @@ handle_client_response (void *cls,
882 * message is received by the tokenizer from the DNS hijack process. 882 * message is received by the tokenizer from the DNS hijack process.
883 * 883 *
884 * @param cls closure 884 * @param cls closure
885 * @param client identification of the client
886 * @param message the actual message, a DNS request we should handle 885 * @param message the actual message, a DNS request we should handle
887 */ 886 */
888static int 887static int
889process_helper_messages (void *cls GNUNET_UNUSED, void *client, 888process_helper_messages (void *cls,
890 const struct GNUNET_MessageHeader *message) 889 const struct GNUNET_MessageHeader *message)
891{ 890{
892 uint16_t msize; 891 uint16_t msize;
diff --git a/src/dv/dv_api.c b/src/dv/dv_api.c
index 062f9a95f..ab521ec1f 100644
--- a/src/dv/dv_api.c
+++ b/src/dv/dv_api.c
@@ -437,7 +437,7 @@ GNUNET_DV_send (struct GNUNET_DV_ServiceHandle *sh,
437 struct ConnectedPeer *peer; 437 struct ConnectedPeer *peer;
438 struct GNUNET_MQ_Envelope *env; 438 struct GNUNET_MQ_Envelope *env;
439 439
440 if (ntohs (msg->size) + sizeof (*sm) >= GNUNET_SERVER_MAX_MESSAGE_SIZE) 440 if (ntohs (msg->size) + sizeof (*sm) >= GNUNET_MAX_MESSAGE_SIZE)
441 { 441 {
442 GNUNET_break (0); 442 GNUNET_break (0);
443 return; 443 return;
diff --git a/src/dv/gnunet-dv.c b/src/dv/gnunet-dv.c
index d0917d363..cb40bb6d2 100644
--- a/src/dv/gnunet-dv.c
+++ b/src/dv/gnunet-dv.c
@@ -34,7 +34,7 @@ static struct GNUNET_DV_ServiceHandle *sh;
34/** 34/**
35 * Was verbose specified? 35 * Was verbose specified?
36 */ 36 */
37static int verbose; 37static unsigned int verbose;
38 38
39 39
40/** 40/**
@@ -161,10 +161,10 @@ main (int argc, char *const *argv)
161{ 161{
162 int res; 162 int res;
163 163
164 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 164 struct GNUNET_GETOPT_CommandLineOption options[] = {
165 {'V', "verbose", NULL, 165
166 gettext_noop ("verbose output"), 166 GNUNET_GETOPT_OPTION_VERBOSE (&verbose),
167 0, &GNUNET_GETOPT_set_one, &verbose}, 167
168 GNUNET_GETOPT_OPTION_END 168 GNUNET_GETOPT_OPTION_END
169 }; 169 };
170 170
diff --git a/src/dv/gnunet-service-dv.c b/src/dv/gnunet-service-dv.c
index 7d101c8ae..fa1c16be8 100644
--- a/src/dv/gnunet-service-dv.c
+++ b/src/dv/gnunet-service-dv.c
@@ -399,7 +399,7 @@ send_data_to_plugin (const struct GNUNET_MessageHeader *message,
399 (unsigned int) distance); 399 (unsigned int) distance);
400 size = sizeof (struct GNUNET_DV_ReceivedMessage) + 400 size = sizeof (struct GNUNET_DV_ReceivedMessage) +
401 ntohs (message->size); 401 ntohs (message->size);
402 if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE) 402 if (size >= GNUNET_MAX_MESSAGE_SIZE)
403 { 403 {
404 GNUNET_break (0); /* too big */ 404 GNUNET_break (0); /* too big */
405 return; 405 return;
@@ -537,7 +537,7 @@ forward_payload (struct DirectNeighbor *target,
537 return; 537 return;
538 } 538 }
539 if (sizeof (struct RouteMessage) + ntohs (payload->size) 539 if (sizeof (struct RouteMessage) + ntohs (payload->size)
540 >= GNUNET_SERVER_MAX_MESSAGE_SIZE) 540 >= GNUNET_MAX_MESSAGE_SIZE)
541 { 541 {
542 GNUNET_break (0); 542 GNUNET_break (0);
543 return; 543 return;
@@ -1530,7 +1530,7 @@ listen_set_union (void *cls,
1530 GNUNET_SET_OPERATION_UNION); 1530 GNUNET_SET_OPERATION_UNION);
1531 neighbor->set_op = GNUNET_SET_accept (request, 1531 neighbor->set_op = GNUNET_SET_accept (request,
1532 GNUNET_SET_RESULT_ADDED, 1532 GNUNET_SET_RESULT_ADDED,
1533 (struct GNUNET_SET_Option[]) { 0 }, 1533 (struct GNUNET_SET_Option[]) {{ 0 }},
1534 &handle_set_union_result, 1534 &handle_set_union_result,
1535 neighbor); 1535 neighbor);
1536 neighbor->consensus_insertion_offset = 0; 1536 neighbor->consensus_insertion_offset = 0;
@@ -1561,7 +1561,7 @@ initiate_set_union (void *cls)
1561 &neighbor->real_session_id, 1561 &neighbor->real_session_id,
1562 NULL, 1562 NULL,
1563 GNUNET_SET_RESULT_ADDED, 1563 GNUNET_SET_RESULT_ADDED,
1564 (struct GNUNET_SET_Option[]) { 0 }, 1564 (struct GNUNET_SET_Option[]) {{ 0 }},
1565 &handle_set_union_result, 1565 &handle_set_union_result,
1566 neighbor); 1566 neighbor);
1567 neighbor->consensus_insertion_offset = 0; 1567 neighbor->consensus_insertion_offset = 0;
diff --git a/src/exit/Makefile.am b/src/exit/Makefile.am
index 271b4ebd7..aa1210269 100644
--- a/src/exit/Makefile.am
+++ b/src/exit/Makefile.am
@@ -54,6 +54,6 @@ gnunet_daemon_exit_LDADD = \
54 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 54 $(top_builddir)/src/statistics/libgnunetstatistics.la \
55 $(top_builddir)/src/tun/libgnunettun.la \ 55 $(top_builddir)/src/tun/libgnunettun.la \
56 $(top_builddir)/src/util/libgnunetutil.la \ 56 $(top_builddir)/src/util/libgnunetutil.la \
57 $(top_builddir)/src/cadet/libgnunetcadetnew.la \ 57 $(top_builddir)/src/cadet/libgnunetcadet.la \
58 $(top_builddir)/src/regex/libgnunetregex.la \ 58 $(top_builddir)/src/regex/libgnunetregex.la \
59 $(GN_LIBINTL) 59 $(GN_LIBINTL)
diff --git a/src/exit/gnunet-daemon-exit.c b/src/exit/gnunet-daemon-exit.c
index 09576e393..2cd3441a1 100644
--- a/src/exit/gnunet-daemon-exit.c
+++ b/src/exit/gnunet-daemon-exit.c
@@ -979,7 +979,7 @@ send_tcp_packet_via_tun (const struct SocketAddress *destination_address,
979 } 979 }
980 len += sizeof (struct GNUNET_TUN_TcpHeader); 980 len += sizeof (struct GNUNET_TUN_TcpHeader);
981 len += payload_length; 981 len += payload_length;
982 if (len >= GNUNET_SERVER_MAX_MESSAGE_SIZE) 982 if (len >= GNUNET_MAX_MESSAGE_SIZE)
983 { 983 {
984 GNUNET_break (0); 984 GNUNET_break (0);
985 return; 985 return;
@@ -1079,7 +1079,7 @@ send_icmp_packet_via_tun (const struct SocketAddress *destination_address,
1079 } 1079 }
1080 len += sizeof (struct GNUNET_TUN_IcmpHeader); 1080 len += sizeof (struct GNUNET_TUN_IcmpHeader);
1081 len += payload_length; 1081 len += payload_length;
1082 if (len >= GNUNET_SERVER_MAX_MESSAGE_SIZE) 1082 if (len >= GNUNET_MAX_MESSAGE_SIZE)
1083 { 1083 {
1084 GNUNET_break (0); 1084 GNUNET_break (0);
1085 return; 1085 return;
@@ -1358,7 +1358,7 @@ send_udp_packet_via_tun (const struct SocketAddress *destination_address,
1358 } 1358 }
1359 len += sizeof (struct GNUNET_TUN_UdpHeader); 1359 len += sizeof (struct GNUNET_TUN_UdpHeader);
1360 len += payload_length; 1360 len += payload_length;
1361 if (len >= GNUNET_SERVER_MAX_MESSAGE_SIZE) 1361 if (len >= GNUNET_MAX_MESSAGE_SIZE)
1362 { 1362 {
1363 GNUNET_break (0); 1363 GNUNET_break (0);
1364 return; 1364 return;
@@ -2502,7 +2502,7 @@ store_service (int proto,
2502 GNUNET_h2s (&cadet_port), 2502 GNUNET_h2s (&cadet_port),
2503 name, 2503 name,
2504 (unsigned int) destination_port); 2504 (unsigned int) destination_port);
2505 service->port = GNUNET_CADET_open_porT (cadet_handle, 2505 service->port = GNUNET_CADET_open_port (cadet_handle,
2506 &cadet_port, 2506 &cadet_port,
2507 &new_service_channel, 2507 &new_service_channel,
2508 service, 2508 service,
@@ -2884,7 +2884,7 @@ tcp_from_helper (const struct GNUNET_TUN_TcpHeader *tcp,
2884 mtcp->crc = 0; 2884 mtcp->crc = 0;
2885 2885
2886 mlen = sizeof (struct GNUNET_EXIT_TcpDataMessage) + (pktlen - sizeof (struct GNUNET_TUN_TcpHeader)); 2886 mlen = sizeof (struct GNUNET_EXIT_TcpDataMessage) + (pktlen - sizeof (struct GNUNET_TUN_TcpHeader));
2887 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) 2887 if (mlen >= GNUNET_MAX_MESSAGE_SIZE)
2888 { 2888 {
2889 GNUNET_break (0); 2889 GNUNET_break (0);
2890 return; 2890 return;
@@ -2905,12 +2905,10 @@ tcp_from_helper (const struct GNUNET_TUN_TcpHeader *tcp,
2905 * Receive packets from the helper-process 2905 * Receive packets from the helper-process
2906 * 2906 *
2907 * @param cls unused 2907 * @param cls unused
2908 * @param client unsued
2909 * @param message message received from helper 2908 * @param message message received from helper
2910 */ 2909 */
2911static int 2910static int
2912message_token (void *cls GNUNET_UNUSED, 2911message_token (void *cls GNUNET_UNUSED,
2913 void *client GNUNET_UNUSED,
2914 const struct GNUNET_MessageHeader *message) 2912 const struct GNUNET_MessageHeader *message)
2915{ 2913{
2916 const struct GNUNET_TUN_Layer2PacketHeader *pkt_tun; 2914 const struct GNUNET_TUN_Layer2PacketHeader *pkt_tun;
@@ -3579,7 +3577,7 @@ advertise_dns_exit ()
3579 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 3577 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3580 "Opening CADET port %s for DNS exit service\n", 3578 "Opening CADET port %s for DNS exit service\n",
3581 GNUNET_h2s (&port)); 3579 GNUNET_h2s (&port));
3582 dns_port = GNUNET_CADET_open_porT (cadet_handle, 3580 dns_port = GNUNET_CADET_open_port (cadet_handle,
3583 &port, 3581 &port,
3584 &new_channel, 3582 &new_channel,
3585 NULL, 3583 NULL,
@@ -3829,7 +3827,7 @@ run (void *cls,
3829 NULL); 3827 NULL);
3830 stats = GNUNET_STATISTICS_create ("exit", 3828 stats = GNUNET_STATISTICS_create ("exit",
3831 cfg); 3829 cfg);
3832 cadet_handle = GNUNET_CADET_connecT (cfg); 3830 cadet_handle = GNUNET_CADET_connect (cfg);
3833 if (NULL == cadet_handle) 3831 if (NULL == cadet_handle)
3834 { 3832 {
3835 GNUNET_SCHEDULER_shutdown (); 3833 GNUNET_SCHEDULER_shutdown ();
@@ -3862,7 +3860,7 @@ run (void *cls,
3862 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 3860 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3863 "Opening CADET port %s for IPv4 gateway service\n", 3861 "Opening CADET port %s for IPv4 gateway service\n",
3864 GNUNET_h2s (&port)); 3862 GNUNET_h2s (&port));
3865 cadet_port4 = GNUNET_CADET_open_porT (cadet_handle, 3863 cadet_port4 = GNUNET_CADET_open_port (cadet_handle,
3866 &port, 3864 &port,
3867 &new_channel, 3865 &new_channel,
3868 NULL, 3866 NULL,
@@ -3902,7 +3900,7 @@ run (void *cls,
3902 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 3900 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3903 "Opening CADET port %s for IPv6 gateway service\n", 3901 "Opening CADET port %s for IPv6 gateway service\n",
3904 GNUNET_h2s (&port)); 3902 GNUNET_h2s (&port));
3905 cadet_port6 = GNUNET_CADET_open_porT (cadet_handle, 3903 cadet_port6 = GNUNET_CADET_open_port (cadet_handle,
3906 &port, 3904 &port,
3907 &new_channel, 3905 &new_channel,
3908 NULL, 3906 NULL,
diff --git a/src/exit/gnunet-helper-exit-windows.c b/src/exit/gnunet-helper-exit-windows.c
index 6be65ccd5..aa7a7a4a3 100644
--- a/src/exit/gnunet-helper-exit-windows.c
+++ b/src/exit/gnunet-helper-exit-windows.c
@@ -77,7 +77,7 @@
77static boolean privilege_testing = FALSE; 77static boolean privilege_testing = FALSE;
78 78
79/** 79/**
80 * Maximum size of a GNUnet message (GNUNET_SERVER_MAX_MESSAGE_SIZE) 80 * Maximum size of a GNUnet message (GNUNET_MAX_MESSAGE_SIZE)
81 */ 81 */
82#define MAX_SIZE 65536 82#define MAX_SIZE 65536
83 83
diff --git a/src/exit/gnunet-helper-exit.c b/src/exit/gnunet-helper-exit.c
index e14c6ca43..3c6f97557 100644
--- a/src/exit/gnunet-helper-exit.c
+++ b/src/exit/gnunet-helper-exit.c
@@ -62,7 +62,7 @@
62#define DEBUG GNUNET_NO 62#define DEBUG GNUNET_NO
63 63
64/** 64/**
65 * Maximum size of a GNUnet message (GNUNET_SERVER_MAX_MESSAGE_SIZE) 65 * Maximum size of a GNUnet message (GNUNET_MAX_MESSAGE_SIZE)
66 */ 66 */
67#define MAX_SIZE 65536 67#define MAX_SIZE 65536
68 68
diff --git a/src/fs/Makefile.am b/src/fs/Makefile.am
index 4374d45ea..33260a794 100644
--- a/src/fs/Makefile.am
+++ b/src/fs/Makefile.am
@@ -202,7 +202,7 @@ gnunet_service_fs_LDADD = \
202 $(top_builddir)/src/block/libgnunetblock.la \ 202 $(top_builddir)/src/block/libgnunetblock.la \
203 $(top_builddir)/src/datastore/libgnunetdatastore.la \ 203 $(top_builddir)/src/datastore/libgnunetdatastore.la \
204 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 204 $(top_builddir)/src/statistics/libgnunetstatistics.la \
205 $(top_builddir)/src/cadet/libgnunetcadetnew.la \ 205 $(top_builddir)/src/cadet/libgnunetcadet.la \
206 $(top_builddir)/src/ats/libgnunetats.la \ 206 $(top_builddir)/src/ats/libgnunetats.la \
207 $(top_builddir)/src/core/libgnunetcore.la \ 207 $(top_builddir)/src/core/libgnunetcore.la \
208 $(top_builddir)/src/util/libgnunetutil.la \ 208 $(top_builddir)/src/util/libgnunetutil.la \
diff --git a/src/fs/fs_api.h b/src/fs/fs_api.h
index e85de94a7..be22ea73e 100644
--- a/src/fs/fs_api.h
+++ b/src/fs/fs_api.h
@@ -1464,21 +1464,11 @@ struct GNUNET_FS_UnindexContext
1464 struct GNUNET_CRYPTO_FileHashContext *fhc; 1464 struct GNUNET_CRYPTO_FileHashContext *fhc;
1465 1465
1466 /** 1466 /**
1467 * Which values have we seen already?
1468 */
1469 struct GNUNET_CONTAINER_MultiHashMap *seen_dh;
1470
1471 /**
1472 * Overall size of the file. 1467 * Overall size of the file.
1473 */ 1468 */
1474 uint64_t file_size; 1469 uint64_t file_size;
1475 1470
1476 /** 1471 /**
1477 * Random offset given to #GNUNET_DATASTORE_get_key.
1478 */
1479 uint64_t roff;
1480
1481 /**
1482 * When did we start? 1472 * When did we start?
1483 */ 1473 */
1484 struct GNUNET_TIME_Absolute start_time; 1474 struct GNUNET_TIME_Absolute start_time;
diff --git a/src/fs/fs_directory.c b/src/fs/fs_directory.c
index a18a903be..514eb64b3 100644
--- a/src/fs/fs_directory.c
+++ b/src/fs/fs_directory.c
@@ -170,13 +170,14 @@ find_full_data (void *cls, const char *plugin_name,
170 * @param data pointer to the beginning of the directory 170 * @param data pointer to the beginning of the directory
171 * @param offset offset of data in the directory 171 * @param offset offset of data in the directory
172 * @param dep function to call on each entry 172 * @param dep function to call on each entry
173 * @param dep_cls closure for dep 173 * @param dep_cls closure for @a dep
174 * @return GNUNET_OK if this could be a block in a directory, 174 * @return #GNUNET_OK if this could be a block in a directory,
175 * GNUNET_NO if this could be part of a directory (but not 100% OK) 175 * #GNUNET_NO if this could be part of a directory (but not 100% OK)
176 * GNUNET_SYSERR if 'data' does not represent a directory 176 * #GNUNET_SYSERR if @a data does not represent a directory
177 */ 177 */
178int 178int
179GNUNET_FS_directory_list_contents (size_t size, const void *data, 179GNUNET_FS_directory_list_contents (size_t size,
180 const void *data,
180 uint64_t offset, 181 uint64_t offset,
181 GNUNET_FS_DirectoryEntryProcessor dep, 182 GNUNET_FS_DirectoryEntryProcessor dep,
182 void *dep_cls) 183 void *dep_cls)
@@ -194,12 +195,16 @@ GNUNET_FS_directory_list_contents (size_t size, const void *data,
194 195
195 if ((offset == 0) && 196 if ((offset == 0) &&
196 ((size < 8 + sizeof (uint32_t)) || 197 ((size < 8 + sizeof (uint32_t)) ||
197 (0 != memcmp (cdata, GNUNET_FS_DIRECTORY_MAGIC, 8)))) 198 (0 != memcmp (cdata,
199 GNUNET_FS_DIRECTORY_MAGIC,
200 8))))
198 return GNUNET_SYSERR; 201 return GNUNET_SYSERR;
199 pos = offset; 202 pos = offset;
200 if (offset == 0) 203 if (offset == 0)
201 { 204 {
202 GNUNET_memcpy (&mdSize, &cdata[8], sizeof (uint32_t)); 205 GNUNET_memcpy (&mdSize,
206 &cdata[8],
207 sizeof (uint32_t));
203 mdSize = ntohl (mdSize); 208 mdSize = ntohl (mdSize);
204 if (mdSize > size - 8 - sizeof (uint32_t)) 209 if (mdSize > size - 8 - sizeof (uint32_t))
205 { 210 {
@@ -215,7 +220,12 @@ GNUNET_FS_directory_list_contents (size_t size, const void *data,
215 GNUNET_break (0); 220 GNUNET_break (0);
216 return GNUNET_SYSERR; /* malformed ! */ 221 return GNUNET_SYSERR; /* malformed ! */
217 } 222 }
218 dep (dep_cls, NULL, NULL, md, 0, NULL); 223 dep (dep_cls,
224 NULL,
225 NULL,
226 md,
227 0,
228 NULL);
219 GNUNET_CONTAINER_meta_data_destroy (md); 229 GNUNET_CONTAINER_meta_data_destroy (md);
220 pos = 8 + sizeof (uint32_t) + mdSize; 230 pos = 8 + sizeof (uint32_t) + mdSize;
221 } 231 }
@@ -247,7 +257,7 @@ GNUNET_FS_directory_list_contents (size_t size, const void *data,
247 257
248 uri = GNUNET_FS_uri_parse (&cdata[pos], &emsg); 258 uri = GNUNET_FS_uri_parse (&cdata[pos], &emsg);
249 pos = epos + 1; 259 pos = epos + 1;
250 if (uri == NULL) 260 if (NULL == uri)
251 { 261 {
252 GNUNET_free (emsg); 262 GNUNET_free (emsg);
253 pos--; /* go back to '\0' to force going to next alignment */ 263 pos--; /* go back to '\0' to force going to next alignment */
@@ -260,7 +270,9 @@ GNUNET_FS_directory_list_contents (size_t size, const void *data,
260 return GNUNET_NO; /* illegal in directory! */ 270 return GNUNET_NO; /* illegal in directory! */
261 } 271 }
262 272
263 GNUNET_memcpy (&mdSize, &cdata[pos], sizeof (uint32_t)); 273 GNUNET_memcpy (&mdSize,
274 &cdata[pos],
275 sizeof (uint32_t));
264 mdSize = ntohl (mdSize); 276 mdSize = ntohl (mdSize);
265 pos += sizeof (uint32_t); 277 pos += sizeof (uint32_t);
266 if (pos + mdSize > size) 278 if (pos + mdSize > size)
@@ -269,8 +281,9 @@ GNUNET_FS_directory_list_contents (size_t size, const void *data,
269 return GNUNET_NO; /* malformed - or partial download */ 281 return GNUNET_NO; /* malformed - or partial download */
270 } 282 }
271 283
272 md = GNUNET_CONTAINER_meta_data_deserialize (&cdata[pos], mdSize); 284 md = GNUNET_CONTAINER_meta_data_deserialize (&cdata[pos],
273 if (md == NULL) 285 mdSize);
286 if (NULL == md)
274 { 287 {
275 GNUNET_FS_uri_destroy (uri); 288 GNUNET_FS_uri_destroy (uri);
276 GNUNET_break (0); 289 GNUNET_break (0);
@@ -282,10 +295,17 @@ GNUNET_FS_directory_list_contents (size_t size, const void *data,
282 EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME); 295 EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME);
283 full_data.size = 0; 296 full_data.size = 0;
284 full_data.data = NULL; 297 full_data.data = NULL;
285 GNUNET_CONTAINER_meta_data_iterate (md, &find_full_data, &full_data); 298 GNUNET_CONTAINER_meta_data_iterate (md,
286 if (dep != NULL) 299 &find_full_data,
300 &full_data);
301 if (NULL != dep)
287 { 302 {
288 dep (dep_cls, filename, uri, md, full_data.size, full_data.data); 303 dep (dep_cls,
304 filename,
305 uri,
306 md,
307 full_data.size,
308 full_data.data);
289 } 309 }
290 GNUNET_free_non_null (full_data.data); 310 GNUNET_free_non_null (full_data.data);
291 GNUNET_free_non_null (filename); 311 GNUNET_free_non_null (filename);
@@ -548,11 +568,12 @@ block_align (size_t start, unsigned int count, const size_t * sizes,
548 * @param bld directory to finish 568 * @param bld directory to finish
549 * @param rsize set to the number of bytes needed 569 * @param rsize set to the number of bytes needed
550 * @param rdata set to the encoded directory 570 * @param rdata set to the encoded directory
551 * @return GNUNET_OK on success 571 * @return #GNUNET_OK on success
552 */ 572 */
553int 573int
554GNUNET_FS_directory_builder_finish (struct GNUNET_FS_DirectoryBuilder *bld, 574GNUNET_FS_directory_builder_finish (struct GNUNET_FS_DirectoryBuilder *bld,
555 size_t * rsize, void **rdata) 575 size_t * rsize,
576 void **rdata)
556{ 577{
557 char *data; 578 char *data;
558 char *sptr; 579 char *sptr;
@@ -575,9 +596,12 @@ GNUNET_FS_directory_builder_finish (struct GNUNET_FS_DirectoryBuilder *bld,
575 bes = NULL; 596 bes = NULL;
576 if (0 < bld->count) 597 if (0 < bld->count)
577 { 598 {
578 sizes = GNUNET_malloc (bld->count * sizeof (size_t)); 599 sizes = GNUNET_new_array (bld->count,
579 perm = GNUNET_malloc (bld->count * sizeof (unsigned int)); 600 size_t);
580 bes = GNUNET_malloc (bld->count * sizeof (struct BuilderEntry *)); 601 perm = GNUNET_new_array (bld->count,
602 unsigned int);
603 bes = GNUNET_new_array (bld->count,
604 struct BuilderEntry *);
581 pos = bld->head; 605 pos = bld->head;
582 for (i = 0; i < bld->count; i++) 606 for (i = 0; i < bld->count; i++)
583 { 607 {
@@ -599,7 +623,8 @@ GNUNET_FS_directory_builder_finish (struct GNUNET_FS_DirectoryBuilder *bld,
599 data = GNUNET_malloc_large (size); 623 data = GNUNET_malloc_large (size);
600 if (data == NULL) 624 if (data == NULL)
601 { 625 {
602 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "malloc"); 626 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
627 "malloc");
603 *rsize = 0; 628 *rsize = 0;
604 *rdata = NULL; 629 *rdata = NULL;
605 GNUNET_free_non_null (sizes); 630 GNUNET_free_non_null (sizes);
@@ -608,17 +633,22 @@ GNUNET_FS_directory_builder_finish (struct GNUNET_FS_DirectoryBuilder *bld,
608 return GNUNET_SYSERR; 633 return GNUNET_SYSERR;
609 } 634 }
610 *rdata = data; 635 *rdata = data;
611 GNUNET_memcpy (data, GNUNET_DIRECTORY_MAGIC, strlen (GNUNET_DIRECTORY_MAGIC)); 636 GNUNET_memcpy (data,
637 GNUNET_DIRECTORY_MAGIC,
638 strlen (GNUNET_DIRECTORY_MAGIC));
612 off = strlen (GNUNET_DIRECTORY_MAGIC); 639 off = strlen (GNUNET_DIRECTORY_MAGIC);
613 640
614 sptr = &data[off + sizeof (uint32_t)]; 641 sptr = &data[off + sizeof (uint32_t)];
615 ret = 642 ret =
616 GNUNET_CONTAINER_meta_data_serialize (bld->meta, &sptr, 643 GNUNET_CONTAINER_meta_data_serialize (bld->meta,
644 &sptr,
617 size - off - sizeof (uint32_t), 645 size - off - sizeof (uint32_t),
618 GNUNET_CONTAINER_META_DATA_SERIALIZE_FULL); 646 GNUNET_CONTAINER_META_DATA_SERIALIZE_FULL);
619 GNUNET_assert (ret != -1); 647 GNUNET_assert (ret != -1);
620 big = htonl (ret); 648 big = htonl (ret);
621 GNUNET_memcpy (&data[off], &big, sizeof (uint32_t)); 649 GNUNET_memcpy (&data[off],
650 &big,
651 sizeof (uint32_t));
622 off += sizeof (uint32_t) + ret; 652 off += sizeof (uint32_t) + ret;
623 for (j = 0; j < bld->count; j++) 653 for (j = 0; j < bld->count; j++)
624 { 654 {
diff --git a/src/fs/fs_dirmetascan.c b/src/fs/fs_dirmetascan.c
index 2f79c7c05..7b9f178fd 100644
--- a/src/fs/fs_dirmetascan.c
+++ b/src/fs/fs_dirmetascan.c
@@ -245,12 +245,10 @@ finish_scan (void *cls)
245 * Calls the scanner progress handler. 245 * Calls the scanner progress handler.
246 * 246 *
247 * @param cls the closure (directory scanner object) 247 * @param cls the closure (directory scanner object)
248 * @param client always NULL
249 * @param msg message from the helper process 248 * @param msg message from the helper process
250 */ 249 */
251static int 250static int
252process_helper_msgs (void *cls, 251process_helper_msgs (void *cls,
253 void *client,
254 const struct GNUNET_MessageHeader *msg) 252 const struct GNUNET_MessageHeader *msg)
255{ 253{
256 struct GNUNET_FS_DirScanner *ds = cls; 254 struct GNUNET_FS_DirScanner *ds = cls;
diff --git a/src/fs/fs_download.c b/src/fs/fs_download.c
index 0789162bf..ce852f2d0 100644
--- a/src/fs/fs_download.c
+++ b/src/fs/fs_download.c
@@ -37,14 +37,14 @@ static int
37is_recursive_download (struct GNUNET_FS_DownloadContext *dc) 37is_recursive_download (struct GNUNET_FS_DownloadContext *dc)
38{ 38{
39 return (0 != (dc->options & GNUNET_FS_DOWNLOAD_OPTION_RECURSIVE)) && 39 return (0 != (dc->options & GNUNET_FS_DOWNLOAD_OPTION_RECURSIVE)) &&
40 ((GNUNET_YES == GNUNET_FS_meta_data_test_for_directory (dc->meta)) || 40 ( (GNUNET_YES == GNUNET_FS_meta_data_test_for_directory (dc->meta)) ||
41 ((NULL == dc->meta) && 41 ( (NULL == dc->meta) &&
42 ((NULL == dc->filename) || 42 ( (NULL == dc->filename) ||
43 ((strlen (dc->filename) >= strlen (GNUNET_FS_DIRECTORY_EXT)) && 43 ( (strlen (dc->filename) >= strlen (GNUNET_FS_DIRECTORY_EXT)) &&
44 (NULL != 44 (NULL !=
45 strstr (dc->filename + strlen (dc->filename) - 45 strstr (dc->filename + strlen (dc->filename) -
46 strlen (GNUNET_FS_DIRECTORY_EXT), 46 strlen (GNUNET_FS_DIRECTORY_EXT),
47 GNUNET_FS_DIRECTORY_EXT)))))); 47 GNUNET_FS_DIRECTORY_EXT)) ) ) ) );
48} 48}
49 49
50 50
@@ -278,10 +278,12 @@ try_reconnect (struct GNUNET_FS_DownloadContext *dc);
278 * @param data contents of the file (or NULL if they were not inlined) 278 * @param data contents of the file (or NULL if they were not inlined)
279 */ 279 */
280static void 280static void
281trigger_recursive_download (void *cls, const char *filename, 281trigger_recursive_download (void *cls,
282 const char *filename,
282 const struct GNUNET_FS_Uri *uri, 283 const struct GNUNET_FS_Uri *uri,
283 const struct GNUNET_CONTAINER_MetaData *meta, 284 const struct GNUNET_CONTAINER_MetaData *meta,
284 size_t length, const void *data); 285 size_t length,
286 const void *data);
285 287
286 288
287/** 289/**
@@ -304,24 +306,28 @@ full_recursive_download (struct GNUNET_FS_DownloadContext *dc)
304 if (size64 != (uint64_t) size) 306 if (size64 != (uint64_t) size)
305 { 307 {
306 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 308 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
307 _ 309 _("Recursive downloads of directories larger than 4 GB are not supported on 32-bit systems\n"));
308 ("Recursive downloads of directories larger than 4 GB are not supported on 32-bit systems\n"));
309 return; 310 return;
310 } 311 }
311 if (NULL != dc->filename) 312 if (NULL != dc->filename)
312 { 313 {
313 h = GNUNET_DISK_file_open (dc->filename, GNUNET_DISK_OPEN_READ, 314 h = GNUNET_DISK_file_open (dc->filename,
315 GNUNET_DISK_OPEN_READ,
314 GNUNET_DISK_PERM_NONE); 316 GNUNET_DISK_PERM_NONE);
315 } 317 }
316 else 318 else
317 { 319 {
318 GNUNET_assert (NULL != dc->temp_filename); 320 GNUNET_assert (NULL != dc->temp_filename);
319 h = GNUNET_DISK_file_open (dc->temp_filename, GNUNET_DISK_OPEN_READ, 321 h = GNUNET_DISK_file_open (dc->temp_filename,
322 GNUNET_DISK_OPEN_READ,
320 GNUNET_DISK_PERM_NONE); 323 GNUNET_DISK_PERM_NONE);
321 } 324 }
322 if (NULL == h) 325 if (NULL == h)
323 return; /* oops */ 326 return; /* oops */
324 data = GNUNET_DISK_file_map (h, &m, GNUNET_DISK_MAP_TYPE_READ, size); 327 data = GNUNET_DISK_file_map (h,
328 &m,
329 GNUNET_DISK_MAP_TYPE_READ,
330 size);
325 if (NULL == data) 331 if (NULL == data)
326 { 332 {
327 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 333 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@@ -329,15 +335,25 @@ full_recursive_download (struct GNUNET_FS_DownloadContext *dc)
329 } 335 }
330 else 336 else
331 { 337 {
332 GNUNET_FS_directory_list_contents (size, data, 0, 338 if (GNUNET_OK !=
333 &trigger_recursive_download, dc); 339 GNUNET_FS_directory_list_contents (size,
340 data,
341 0,
342 &trigger_recursive_download,
343 dc))
344 {
345 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
346 _("Failed to access full directroy contents of `%s' for recursive download\n"),
347 dc->filename);
348 }
334 GNUNET_DISK_file_unmap (m); 349 GNUNET_DISK_file_unmap (m);
335 } 350 }
336 GNUNET_DISK_file_close (h); 351 GNUNET_DISK_file_close (h);
337 if (NULL == dc->filename) 352 if (NULL == dc->filename)
338 { 353 {
339 if (0 != UNLINK (dc->temp_filename)) 354 if (0 != UNLINK (dc->temp_filename))
340 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", 355 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
356 "unlink",
341 dc->temp_filename); 357 dc->temp_filename);
342 GNUNET_free (dc->temp_filename); 358 GNUNET_free (dc->temp_filename);
343 dc->temp_filename = NULL; 359 dc->temp_filename = NULL;
@@ -362,14 +378,16 @@ check_completed (struct GNUNET_FS_DownloadContext *dc)
362 struct GNUNET_FS_DownloadContext *pos; 378 struct GNUNET_FS_DownloadContext *pos;
363 379
364 /* first, check if we need to download children */ 380 /* first, check if we need to download children */
365 if ((NULL == dc->child_head) && (is_recursive_download (dc))) 381 if (is_recursive_download (dc))
366 full_recursive_download (dc); 382 full_recursive_download (dc);
367 /* then, check if children are done already */ 383 /* then, check if children are done already */
368 for (pos = dc->child_head; NULL != pos; pos = pos->next) 384 for (pos = dc->child_head; NULL != pos; pos = pos->next)
369 { 385 {
370 if ((pos->emsg == NULL) && (pos->completed < pos->length)) 386 if ( (NULL == pos->emsg) &&
387 (pos->completed < pos->length) )
371 return; /* not done yet */ 388 return; /* not done yet */
372 if ((pos->child_head != NULL) && (pos->has_finished != GNUNET_YES)) 389 if ( (NULL != pos->child_head) &&
390 (pos->has_finished != GNUNET_YES) )
373 return; /* not transitively done yet */ 391 return; /* not transitively done yet */
374 } 392 }
375 /* All of our children are done, so mark this download done */ 393 /* All of our children are done, so mark this download done */
@@ -471,7 +489,11 @@ try_match_block (struct GNUNET_FS_DownloadContext *dc,
471 } 489 }
472 GNUNET_CRYPTO_hash (&data[dr->offset], dlen, &in_chk.key); 490 GNUNET_CRYPTO_hash (&data[dr->offset], dlen, &in_chk.key);
473 GNUNET_CRYPTO_hash_to_aes_key (&in_chk.key, &sk, &iv); 491 GNUNET_CRYPTO_hash_to_aes_key (&in_chk.key, &sk, &iv);
474 if (-1 == GNUNET_CRYPTO_symmetric_encrypt (&data[dr->offset], dlen, &sk, &iv, enc)) 492 if (-1 == GNUNET_CRYPTO_symmetric_encrypt (&data[dr->offset],
493 dlen,
494 &sk,
495 &iv,
496 enc))
475 { 497 {
476 GNUNET_break (0); 498 GNUNET_break (0);
477 return; 499 return;
@@ -484,7 +506,9 @@ try_match_block (struct GNUNET_FS_DownloadContext *dc,
484 dr->state = BRS_RECONSTRUCT_META_UP; 506 dr->state = BRS_RECONSTRUCT_META_UP;
485 break; 507 break;
486 case BRS_CHK_SET: 508 case BRS_CHK_SET:
487 if (0 != memcmp (&in_chk, &dr->chk, sizeof (struct ContentHashKey))) 509 if (0 != memcmp (&in_chk,
510 &dr->chk,
511 sizeof (struct ContentHashKey)))
488 { 512 {
489 /* other peer provided bogus meta data */ 513 /* other peer provided bogus meta data */
490 GNUNET_break_op (0); 514 GNUNET_break_op (0);
@@ -591,7 +615,10 @@ match_full_data (void *cls, const char *plugin_name,
591 GNUNET_break_op (0); 615 GNUNET_break_op (0);
592 return 1; /* bogus meta data */ 616 return 1; /* bogus meta data */
593 } 617 }
594 try_match_block (dc, dc->top_request, data, data_len); 618 try_match_block (dc,
619 dc->top_request,
620 data,
621 data_len);
595 return 1; 622 return 1;
596} 623}
597 624
@@ -820,10 +847,12 @@ schedule_block_download (struct GNUNET_FS_DownloadContext *dc,
820 * @param data contents of the file (or NULL if they were not inlined) 847 * @param data contents of the file (or NULL if they were not inlined)
821 */ 848 */
822static void 849static void
823trigger_recursive_download (void *cls, const char *filename, 850trigger_recursive_download (void *cls,
851 const char *filename,
824 const struct GNUNET_FS_Uri *uri, 852 const struct GNUNET_FS_Uri *uri,
825 const struct GNUNET_CONTAINER_MetaData *meta, 853 const struct GNUNET_CONTAINER_MetaData *meta,
826 size_t length, const void *data) 854 size_t length,
855 const void *data)
827{ 856{
828 struct GNUNET_FS_DownloadContext *dc = cls; 857 struct GNUNET_FS_DownloadContext *dc = cls;
829 struct GNUNET_FS_DownloadContext *cpos; 858 struct GNUNET_FS_DownloadContext *cpos;
@@ -936,9 +965,17 @@ trigger_recursive_download (void *cls, const char *filename,
936 (unsigned long long) GNUNET_FS_uri_chk_get_file_size (uri), 965 (unsigned long long) GNUNET_FS_uri_chk_get_file_size (uri),
937 (unsigned int) 966 (unsigned int)
938 GNUNET_CONTAINER_meta_data_get_serialized_size (meta)); 967 GNUNET_CONTAINER_meta_data_get_serialized_size (meta));
939 GNUNET_FS_download_start (dc->h, uri, meta, full_name, temp_name, 0, 968 GNUNET_FS_download_start (dc->h,
969 uri,
970 meta,
971 full_name,
972 temp_name,
973 0,
940 GNUNET_FS_uri_chk_get_file_size (uri), 974 GNUNET_FS_uri_chk_get_file_size (uri),
941 dc->anonymity, dc->options, NULL, dc); 975 dc->anonymity,
976 dc->options,
977 NULL,
978 dc);
942 GNUNET_free_non_null (full_name); 979 GNUNET_free_non_null (full_name);
943 GNUNET_free_non_null (temp_name); 980 GNUNET_free_non_null (temp_name);
944 GNUNET_free_non_null (fn); 981 GNUNET_free_non_null (fn);
@@ -953,11 +990,9 @@ trigger_recursive_download (void *cls, const char *filename,
953void 990void
954GNUNET_FS_free_download_request_ (struct DownloadRequest *dr) 991GNUNET_FS_free_download_request_ (struct DownloadRequest *dr)
955{ 992{
956 unsigned int i;
957
958 if (NULL == dr) 993 if (NULL == dr)
959 return; 994 return;
960 for (i = 0; i < dr->num_children; i++) 995 for (unsigned int i = 0; i < dr->num_children; i++)
961 GNUNET_FS_free_download_request_ (dr->children[i]); 996 GNUNET_FS_free_download_request_ (dr->children[i]);
962 GNUNET_free_non_null (dr->children); 997 GNUNET_free_non_null (dr->children);
963 GNUNET_free (dr); 998 GNUNET_free (dr);
@@ -1509,13 +1544,17 @@ create_download_request (struct DownloadRequest *parent,
1509 GNUNET_assert (dr->num_children > 0); 1544 GNUNET_assert (dr->num_children > 0);
1510 1545
1511 dr->children = 1546 dr->children =
1512 GNUNET_malloc (dr->num_children * sizeof (struct DownloadRequest *)); 1547 GNUNET_new_array (dr->num_children,
1548 struct DownloadRequest *);
1513 for (i = 0; i < dr->num_children; i++) 1549 for (i = 0; i < dr->num_children; i++)
1514 { 1550 {
1515 dr->children[i] = 1551 dr->children[i] =
1516 create_download_request (dr, i + head_skip, depth - 1, 1552 create_download_request (dr,
1553 i + head_skip,
1554 depth - 1,
1517 dr_offset + (i + head_skip) * child_block_size, 1555 dr_offset + (i + head_skip) * child_block_size,
1518 file_start_offset, desired_length); 1556 file_start_offset,
1557 desired_length);
1519 } 1558 }
1520 return dr; 1559 return dr;
1521} 1560}
diff --git a/src/fs/fs_getopt.c b/src/fs/fs_getopt.c
index f78e311d3..bfe45957e 100644
--- a/src/fs/fs_getopt.c
+++ b/src/fs/fs_getopt.c
@@ -25,6 +25,7 @@
25 */ 25 */
26#include "platform.h" 26#include "platform.h"
27#include "gnunet_fs_service.h" 27#include "gnunet_fs_service.h"
28#include "gnunet_getopt_lib.h"
28#include "fs_api.h" 29#include "fs_api.h"
29 30
30/* ******************** command-line option parsing API ******************** */ 31/* ******************** command-line option parsing API ******************** */
@@ -41,10 +42,10 @@
41 * @param value command line argument given 42 * @param value command line argument given
42 * @return GNUNET_OK on success 43 * @return GNUNET_OK on success
43 */ 44 */
44int 45static int
45GNUNET_FS_getopt_set_keywords (struct GNUNET_GETOPT_CommandLineProcessorContext 46getopt_set_keywords (struct GNUNET_GETOPT_CommandLineProcessorContext
46 *ctx, void *scls, const char *option, 47 *ctx, void *scls, const char *option,
47 const char *value) 48 const char *value)
48{ 49{
49 struct GNUNET_FS_Uri **uri = scls; 50 struct GNUNET_FS_Uri **uri = scls;
50 struct GNUNET_FS_Uri *u = *uri; 51 struct GNUNET_FS_Uri *u = *uri;
@@ -107,6 +108,34 @@ GNUNET_FS_getopt_set_keywords (struct GNUNET_GETOPT_CommandLineProcessorContext
107 return GNUNET_OK; 108 return GNUNET_OK;
108} 109}
109 110
111/**
112 * Allow user to specify keywords.
113 *
114 * @param shortName short name of the option
115 * @param name long name of the option
116 * @param argumentHelp help text for the option argument
117 * @param description long help text for the option
118 * @param[out] topKeywords set to the desired value
119 */
120struct GNUNET_GETOPT_CommandLineOption
121GNUNET_FS_GETOPT_KEYWORDS (char shortName,
122 const char *name,
123 const char *argumentHelp,
124 const char *description,
125 struct GNUNET_FS_Uri **topKeywords)
126{
127 struct GNUNET_GETOPT_CommandLineOption clo = {
128 .shortName = shortName,
129 .name = name,
130 .argumentHelp = argumentHelp,
131 .description = description,
132 .require_argument = 1,
133 .processor = &getopt_set_keywords,
134 .scls = (void *) topKeywords
135 };
136
137 return clo;
138}
110 139
111/** 140/**
112 * Command-line option parser function that allows the user to specify 141 * Command-line option parser function that allows the user to specify
@@ -120,11 +149,11 @@ GNUNET_FS_getopt_set_keywords (struct GNUNET_GETOPT_CommandLineProcessorContext
120 * @param value command line argument given 149 * @param value command line argument given
121 * @return #GNUNET_OK on success 150 * @return #GNUNET_OK on success
122 */ 151 */
123int 152static int
124GNUNET_FS_getopt_set_metadata (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, 153getopt_set_metadata (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
125 void *scls, 154 void *scls,
126 const char *option, 155 const char *option,
127 const char *value) 156 const char *value)
128{ 157{
129 struct GNUNET_CONTAINER_MetaData **mm = scls; 158 struct GNUNET_CONTAINER_MetaData **mm = scls;
130#if HAVE_EXTRACTOR_H && HAVE_LIBEXTRACTOR 159#if HAVE_EXTRACTOR_H && HAVE_LIBEXTRACTOR
@@ -200,4 +229,36 @@ GNUNET_FS_getopt_set_metadata (struct GNUNET_GETOPT_CommandLineProcessorContext
200 return GNUNET_OK; 229 return GNUNET_OK;
201} 230}
202 231
232/**
233 * Allow user to specify metadata.
234 *
235 * @param shortName short name of the option
236 * @param name long name of the option
237 * @param argumentHelp help text for the option argument
238 * @param description long help text for the option
239 * @param[out] metadata set to the desired value
240 */
241struct GNUNET_GETOPT_CommandLineOption
242GNUNET_FS_GETOPT_METADATA (char shortName,
243 const char *name,
244 const char *argumentHelp,
245 const char *description,
246 struct GNUNET_CONTAINER_MetaData **meta)
247{
248 struct GNUNET_GETOPT_CommandLineOption clo = {
249 .shortName = shortName,
250 .name = name,
251 .argumentHelp = argumentHelp,
252 .description = description,
253 .require_argument = 1,
254 .processor = &getopt_set_metadata,
255 .scls = (void *) meta
256 };
257
258 return clo;
259}
260
261
262
263
203/* end of fs_getopt.c */ 264/* end of fs_getopt.c */
diff --git a/src/fs/fs_publish.c b/src/fs/fs_publish.c
index 86a58a58b..759467ba4 100644
--- a/src/fs/fs_publish.c
+++ b/src/fs/fs_publish.c
@@ -837,7 +837,7 @@ hash_for_index_cb (void *cls,
837 GNUNET_assert (fn != NULL); 837 GNUNET_assert (fn != NULL);
838 slen = strlen (fn) + 1; 838 slen = strlen (fn) + 1;
839 if (slen >= 839 if (slen >=
840 GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct IndexStartMessage)) 840 GNUNET_MAX_MESSAGE_SIZE - sizeof (struct IndexStartMessage))
841 { 841 {
842 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 842 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
843 _ 843 _
@@ -1226,7 +1226,7 @@ fip_signal_start (void *cls,
1226 { 1226 {
1227 kc = GNUNET_FS_uri_ksk_get_keyword_count (*uri); 1227 kc = GNUNET_FS_uri_ksk_get_keyword_count (*uri);
1228 pc->reserve_entries += kc; 1228 pc->reserve_entries += kc;
1229 pc->reserve_space += GNUNET_SERVER_MAX_MESSAGE_SIZE * kc; 1229 pc->reserve_space += GNUNET_MAX_MESSAGE_SIZE * kc;
1230 } 1230 }
1231 pi.status = GNUNET_FS_STATUS_PUBLISH_START; 1231 pi.status = GNUNET_FS_STATUS_PUBLISH_START;
1232 *client_info = GNUNET_FS_publish_make_status_ (&pi, pc, fi, 0); 1232 *client_info = GNUNET_FS_publish_make_status_ (&pi, pc, fi, 0);
diff --git a/src/fs/fs_search.c b/src/fs/fs_search.c
index 3cbf2afef..8c6f5edcf 100644
--- a/src/fs/fs_search.c
+++ b/src/fs/fs_search.c
@@ -1088,15 +1088,17 @@ schedule_transmit_search_request (struct GNUNET_FS_SearchContext *sc)
1088 unsigned int left; 1088 unsigned int left;
1089 unsigned int todo; 1089 unsigned int todo;
1090 unsigned int fit; 1090 unsigned int fit;
1091 int first_call;
1092 unsigned int search_request_map_offset; 1091 unsigned int search_request_map_offset;
1093 unsigned int keyword_offset; 1092 unsigned int keyword_offset;
1093 int first_call;
1094 1094
1095 memset (&mbc, 0, sizeof (mbc)); 1095 memset (&mbc, 0, sizeof (mbc));
1096 mbc.sc = sc; 1096 mbc.sc = sc;
1097 if (GNUNET_FS_uri_test_ksk (sc->uri)) 1097 if (GNUNET_FS_uri_test_ksk (sc->uri))
1098 { 1098 {
1099 mbc.put_cnt = 0; 1099 /* This will calculate the result set size ONLY for
1100 "keyword_offset == 0", so we will have to recalculate
1101 it for the other keywords later! */
1100 GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map, 1102 GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map,
1101 &find_result_set, 1103 &find_result_set,
1102 &mbc); 1104 &mbc);
@@ -1109,7 +1111,6 @@ schedule_transmit_search_request (struct GNUNET_FS_SearchContext *sc)
1109 } 1111 }
1110 search_request_map_offset = 0; 1112 search_request_map_offset = 0;
1111 keyword_offset = 0; 1113 keyword_offset = 0;
1112
1113 first_call = GNUNET_YES; 1114 first_call = GNUNET_YES;
1114 while ( (0 != (left = 1115 while ( (0 != (left =
1115 (total_seen_results - search_request_map_offset))) || 1116 (total_seen_results - search_request_map_offset))) ||
@@ -1120,7 +1121,7 @@ schedule_transmit_search_request (struct GNUNET_FS_SearchContext *sc)
1120 if (0 != (sc->options & GNUNET_FS_SEARCH_OPTION_LOOPBACK_ONLY)) 1121 if (0 != (sc->options & GNUNET_FS_SEARCH_OPTION_LOOPBACK_ONLY))
1121 options |= SEARCH_MESSAGE_OPTION_LOOPBACK_ONLY; 1122 options |= SEARCH_MESSAGE_OPTION_LOOPBACK_ONLY;
1122 1123
1123 fit = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - sizeof (*sm)) / sizeof (struct GNUNET_HashCode); 1124 fit = (GNUNET_MAX_MESSAGE_SIZE - 1 - sizeof (*sm)) / sizeof (struct GNUNET_HashCode);
1124 todo = GNUNET_MIN (fit, 1125 todo = GNUNET_MIN (fit,
1125 left); 1126 left);
1126 env = GNUNET_MQ_msg_extra (sm, 1127 env = GNUNET_MQ_msg_extra (sm,
@@ -1128,6 +1129,11 @@ schedule_transmit_search_request (struct GNUNET_FS_SearchContext *sc)
1128 GNUNET_MESSAGE_TYPE_FS_START_SEARCH); 1129 GNUNET_MESSAGE_TYPE_FS_START_SEARCH);
1129 mbc.skip_cnt = search_request_map_offset; 1130 mbc.skip_cnt = search_request_map_offset;
1130 mbc.xoff = (struct GNUNET_HashCode *) &sm[1]; 1131 mbc.xoff = (struct GNUNET_HashCode *) &sm[1];
1132 sm->type = htonl (GNUNET_BLOCK_TYPE_FS_UBLOCK);
1133 sm->anonymity_level = htonl (sc->anonymity);
1134 memset (&sm->target,
1135 0,
1136 sizeof (struct GNUNET_PeerIdentity));
1131 1137
1132 if (GNUNET_FS_uri_test_ksk (sc->uri)) 1138 if (GNUNET_FS_uri_test_ksk (sc->uri))
1133 { 1139 {
@@ -1135,17 +1141,12 @@ schedule_transmit_search_request (struct GNUNET_FS_SearchContext *sc)
1135 /* calculate how many results we can send in this message */ 1141 /* calculate how many results we can send in this message */
1136 mbc.put_cnt = todo; 1142 mbc.put_cnt = todo;
1137 /* now build message */ 1143 /* now build message */
1138 sm->type = htonl (GNUNET_BLOCK_TYPE_FS_UBLOCK);
1139 sm->anonymity_level = htonl (sc->anonymity);
1140 memset (&sm->target,
1141 0,
1142 sizeof (struct GNUNET_PeerIdentity));
1143 sm->query = sc->requests[keyword_offset].uquery; 1144 sm->query = sc->requests[keyword_offset].uquery;
1144 GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map, 1145 GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map,
1145 &build_result_set, 1146 &build_result_set,
1146 &mbc); 1147 &mbc);
1147 search_request_map_offset += todo; 1148 search_request_map_offset += todo;
1148 GNUNET_assert (0 == mbc.put_cnt); /* #4608 reports this fails? */ 1149 GNUNET_assert (0 == mbc.put_cnt);
1149 GNUNET_assert (total_seen_results >= search_request_map_offset); 1150 GNUNET_assert (total_seen_results >= search_request_map_offset);
1150 if (total_seen_results != search_request_map_offset) 1151 if (total_seen_results != search_request_map_offset)
1151 { 1152 {
@@ -1156,11 +1157,17 @@ schedule_transmit_search_request (struct GNUNET_FS_SearchContext *sc)
1156 { 1157 {
1157 sm->options = htonl (options); 1158 sm->options = htonl (options);
1158 keyword_offset++; 1159 keyword_offset++;
1159 search_request_map_offset = 0;
1160 if (sc->uri->data.ksk.keywordCount != keyword_offset) 1160 if (sc->uri->data.ksk.keywordCount != keyword_offset)
1161 { 1161 {
1162 /* more keywords => more requesting to be done... */ 1162 /* more keywords => more requesting to be done... */
1163 first_call = GNUNET_YES; 1163 first_call = GNUNET_YES;
1164 search_request_map_offset = 0;
1165 mbc.put_cnt = 0;
1166 mbc.keyword_offset = keyword_offset;
1167 GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map,
1168 &find_result_set,
1169 &mbc);
1170 total_seen_results = mbc.put_cnt;
1164 } 1171 }
1165 } 1172 }
1166 } 1173 }
@@ -1168,11 +1175,6 @@ schedule_transmit_search_request (struct GNUNET_FS_SearchContext *sc)
1168 { 1175 {
1169 GNUNET_assert (GNUNET_FS_uri_test_sks (sc->uri)); 1176 GNUNET_assert (GNUNET_FS_uri_test_sks (sc->uri));
1170 1177
1171 sm->type = htonl (GNUNET_BLOCK_TYPE_FS_UBLOCK);
1172 sm->anonymity_level = htonl (sc->anonymity);
1173 memset (&sm->target,
1174 0,
1175 sizeof (struct GNUNET_PeerIdentity));
1176 GNUNET_CRYPTO_ecdsa_public_key_derive (&sc->uri->data.sks.ns, 1178 GNUNET_CRYPTO_ecdsa_public_key_derive (&sc->uri->data.sks.ns,
1177 sc->uri->data.sks.identifier, 1179 sc->uri->data.sks.identifier,
1178 "fs-ublock", 1180 "fs-ublock",
@@ -1383,9 +1385,10 @@ GNUNET_FS_search_start_searching_ (struct GNUNET_FS_SearchContext *sc)
1383 GNUNET_assert (0 != sc->uri->data.ksk.keywordCount); 1385 GNUNET_assert (0 != sc->uri->data.ksk.keywordCount);
1384 anon = GNUNET_CRYPTO_ecdsa_key_get_anonymous (); 1386 anon = GNUNET_CRYPTO_ecdsa_key_get_anonymous ();
1385 GNUNET_CRYPTO_ecdsa_key_get_public (anon, &anon_pub); 1387 GNUNET_CRYPTO_ecdsa_key_get_public (anon, &anon_pub);
1386 sc->requests = 1388 sc->requests
1387 GNUNET_malloc (sizeof (struct SearchRequestEntry) * 1389 = GNUNET_new_array (sc->uri->data.ksk.keywordCount,
1388 sc->uri->data.ksk.keywordCount); 1390 struct SearchRequestEntry);
1391
1389 for (i = 0; i < sc->uri->data.ksk.keywordCount; i++) 1392 for (i = 0; i < sc->uri->data.ksk.keywordCount; i++)
1390 { 1393 {
1391 keyword = &sc->uri->data.ksk.keywords[i][1]; 1394 keyword = &sc->uri->data.ksk.keywords[i][1];
@@ -1666,8 +1669,8 @@ search_result_stop (void *cls,
1666 if (NULL != sr->download) 1669 if (NULL != sr->download)
1667 { 1670 {
1668 sr->download->search = NULL; 1671 sr->download->search = NULL;
1669 sr->download->top = 1672 sr->download->top
1670 GNUNET_FS_make_top (sr->download->h, 1673 = GNUNET_FS_make_top (sr->download->h,
1671 &GNUNET_FS_download_signal_suspend_, 1674 &GNUNET_FS_download_signal_suspend_,
1672 sr->download); 1675 sr->download);
1673 if (NULL != sr->download->serialization) 1676 if (NULL != sr->download->serialization)
@@ -1679,7 +1682,8 @@ search_result_stop (void *cls,
1679 sr->download->serialization = NULL; 1682 sr->download->serialization = NULL;
1680 } 1683 }
1681 pi.status = GNUNET_FS_STATUS_DOWNLOAD_LOST_PARENT; 1684 pi.status = GNUNET_FS_STATUS_DOWNLOAD_LOST_PARENT;
1682 GNUNET_FS_download_make_status_ (&pi, sr->download); 1685 GNUNET_FS_download_make_status_ (&pi,
1686 sr->download);
1683 GNUNET_FS_download_sync_ (sr->download); 1687 GNUNET_FS_download_sync_ (sr->download);
1684 sr->download = NULL; 1688 sr->download = NULL;
1685 } 1689 }
@@ -1745,25 +1749,28 @@ GNUNET_FS_search_stop (struct GNUNET_FS_SearchContext *sc)
1745 if (NULL != sc->top) 1749 if (NULL != sc->top)
1746 GNUNET_FS_end_top (sc->h, sc->top); 1750 GNUNET_FS_end_top (sc->h, sc->top);
1747 GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map, 1751 GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map,
1748 &search_result_stop, sc); 1752 &search_result_stop,
1753 sc);
1749 if (NULL != sc->psearch_result) 1754 if (NULL != sc->psearch_result)
1750 sc->psearch_result->update_search = NULL; 1755 sc->psearch_result->update_search = NULL;
1751 if (NULL != sc->serialization) 1756 if (NULL != sc->serialization)
1752 { 1757 {
1753 GNUNET_FS_remove_sync_file_ (sc->h, 1758 GNUNET_FS_remove_sync_file_ (sc->h,
1754 (sc->psearch_result != 1759 (NULL != sc->psearch_result)
1755 NULL) ? GNUNET_FS_SYNC_PATH_CHILD_SEARCH : 1760 ? GNUNET_FS_SYNC_PATH_CHILD_SEARCH
1756 GNUNET_FS_SYNC_PATH_MASTER_SEARCH, 1761 : GNUNET_FS_SYNC_PATH_MASTER_SEARCH,
1757 sc->serialization); 1762 sc->serialization);
1758 GNUNET_FS_remove_sync_dir_ (sc->h, 1763 GNUNET_FS_remove_sync_dir_ (sc->h,
1759 (sc->psearch_result != 1764 (NULL != sc->psearch_result)
1760 NULL) ? GNUNET_FS_SYNC_PATH_CHILD_SEARCH : 1765 ? GNUNET_FS_SYNC_PATH_CHILD_SEARCH
1761 GNUNET_FS_SYNC_PATH_MASTER_SEARCH, 1766 : GNUNET_FS_SYNC_PATH_MASTER_SEARCH,
1762 sc->serialization); 1767 sc->serialization);
1763 GNUNET_free (sc->serialization); 1768 GNUNET_free (sc->serialization);
1764 } 1769 }
1765 pi.status = GNUNET_FS_STATUS_SEARCH_STOPPED; 1770 pi.status = GNUNET_FS_STATUS_SEARCH_STOPPED;
1766 sc->client_info = GNUNET_FS_search_make_status_ (&pi, sc->h, sc); 1771 sc->client_info = GNUNET_FS_search_make_status_ (&pi,
1772 sc->h,
1773 sc);
1767 GNUNET_break (NULL == sc->client_info); 1774 GNUNET_break (NULL == sc->client_info);
1768 if (NULL != sc->task) 1775 if (NULL != sc->task)
1769 { 1776 {
diff --git a/src/fs/fs_tree.c b/src/fs/fs_tree.c
index b3c632203..e57e4e494 100644
--- a/src/fs/fs_tree.c
+++ b/src/fs/fs_tree.c
@@ -285,9 +285,9 @@ GNUNET_FS_tree_encoder_create (struct GNUNET_FS_Handle *h, uint64_t size,
285 te->progress = progress; 285 te->progress = progress;
286 te->cont = cont; 286 te->cont = cont;
287 te->chk_tree_depth = GNUNET_FS_compute_depth (size); 287 te->chk_tree_depth = GNUNET_FS_compute_depth (size);
288 te->chk_tree = 288 te->chk_tree
289 GNUNET_malloc (te->chk_tree_depth * CHK_PER_INODE * 289 = GNUNET_new_array (te->chk_tree_depth * CHK_PER_INODE,
290 sizeof (struct ContentHashKey)); 290 struct ContentHashKey);
291 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 291 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
292 "Created tree encoder for file with %llu bytes and depth %u\n", 292 "Created tree encoder for file with %llu bytes and depth %u\n",
293 (unsigned long long) size, 293 (unsigned long long) size,
diff --git a/src/fs/fs_unindex.c b/src/fs/fs_unindex.c
index a672b84d5..e1c7ea535 100644
--- a/src/fs/fs_unindex.c
+++ b/src/fs/fs_unindex.c
@@ -312,8 +312,6 @@ unindex_finish (struct GNUNET_FS_UnindexContext *uc)
312 uc->fh = NULL; 312 uc->fh = NULL;
313 GNUNET_DATASTORE_disconnect (uc->dsh, GNUNET_NO); 313 GNUNET_DATASTORE_disconnect (uc->dsh, GNUNET_NO);
314 uc->dsh = NULL; 314 uc->dsh = NULL;
315 GNUNET_CONTAINER_multihashmap_destroy (uc->seen_dh);
316 uc->seen_dh = NULL;
317 uc->state = UNINDEX_STATE_FS_NOTIFY; 315 uc->state = UNINDEX_STATE_FS_NOTIFY;
318 GNUNET_FS_unindex_sync_ (uc); 316 GNUNET_FS_unindex_sync_ (uc);
319 uc->mq = GNUNET_CLIENT_connect (uc->h->cfg, 317 uc->mq = GNUNET_CLIENT_connect (uc->h->cfg,
@@ -444,7 +442,6 @@ continue_after_remove (void *cls,
444 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 442 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
445 _("Failed to remove UBlock: %s\n"), 443 _("Failed to remove UBlock: %s\n"),
446 msg); 444 msg);
447 GNUNET_CONTAINER_multihashmap_clear (uc->seen_dh);
448 uc->ksk_offset++; 445 uc->ksk_offset++;
449 GNUNET_FS_unindex_do_remove_kblocks_ (uc); 446 GNUNET_FS_unindex_do_remove_kblocks_ (uc);
450} 447}
@@ -454,7 +451,8 @@ continue_after_remove (void *cls,
454 * Function called from datastore with result from us looking for 451 * Function called from datastore with result from us looking for
455 * a UBlock. There are four cases: 452 * a UBlock. There are four cases:
456 * 1) no result, means we move on to the next keyword 453 * 1) no result, means we move on to the next keyword
457 * 2) UID is the same as the first UID, means we move on to next keyword 454 * 2) data hash is the same as an already seen data hash, means we move on to
455 * next keyword
458 * 3) UBlock for a different CHK, means we keep looking for more 456 * 3) UBlock for a different CHK, means we keep looking for more
459 * 4) UBlock is for our CHK, means we remove the block and then move 457 * 4) UBlock is for our CHK, means we remove the block and then move
460 * on to the next keyword 458 * on to the next keyword
@@ -485,34 +483,15 @@ process_kblock_for_unindex (void *cls,
485 const struct UBlock *ub; 483 const struct UBlock *ub;
486 struct GNUNET_FS_Uri *chk_uri; 484 struct GNUNET_FS_Uri *chk_uri;
487 struct GNUNET_HashCode query; 485 struct GNUNET_HashCode query;
488 struct GNUNET_HashCode dh;
489 486
490 uc->dqe = NULL; 487 uc->dqe = NULL;
491 if (NULL == data) 488 if (NULL == data)
492 { 489 {
493 /* no result */ 490 /* no result */
494 GNUNET_CONTAINER_multihashmap_clear (uc->seen_dh);
495 uc->ksk_offset++; 491 uc->ksk_offset++;
496 GNUNET_FS_unindex_do_remove_kblocks_ (uc); 492 GNUNET_FS_unindex_do_remove_kblocks_ (uc);
497 return; 493 return;
498 } 494 }
499 GNUNET_CRYPTO_hash (data,
500 size,
501 &dh);
502 if (GNUNET_YES ==
503 GNUNET_CONTAINER_multihashmap_contains (uc->seen_dh,
504 &dh))
505 {
506 GNUNET_CONTAINER_multihashmap_clear (uc->seen_dh);
507 uc->ksk_offset++;
508 GNUNET_FS_unindex_do_remove_kblocks_ (uc);
509 return;
510 }
511 GNUNET_assert (GNUNET_OK ==
512 GNUNET_CONTAINER_multihashmap_put (uc->seen_dh,
513 &dh,
514 uc,
515 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
516 GNUNET_assert (GNUNET_BLOCK_TYPE_FS_UBLOCK == type); 495 GNUNET_assert (GNUNET_BLOCK_TYPE_FS_UBLOCK == type);
517 if (size < sizeof (struct UBlock)) 496 if (size < sizeof (struct UBlock))
518 { 497 {
@@ -565,23 +544,24 @@ process_kblock_for_unindex (void *cls,
565 GNUNET_FS_uri_destroy (chk_uri); 544 GNUNET_FS_uri_destroy (chk_uri);
566 /* matches! */ 545 /* matches! */
567 uc->dqe = GNUNET_DATASTORE_remove (uc->dsh, 546 uc->dqe = GNUNET_DATASTORE_remove (uc->dsh,
568 key, 547 key,
569 size, 548 size,
570 data, 549 data,
571 0 /* priority */, 550 0 /* priority */,
572 1 /* queue size */, 551 1 /* queue size */,
573 &continue_after_remove, 552 &continue_after_remove,
574 uc); 553 uc);
575 return; 554 return;
576 get_next: 555 get_next:
577 uc->dqe = GNUNET_DATASTORE_get_key (uc->dsh, 556 uc->dqe = GNUNET_DATASTORE_get_key (uc->dsh,
578 uc->roff++, 557 uid + 1 /* next_uid */,
579 &uc->uquery, 558 false /* random */,
580 GNUNET_BLOCK_TYPE_FS_UBLOCK, 559 &uc->uquery,
581 0 /* priority */, 560 GNUNET_BLOCK_TYPE_FS_UBLOCK,
561 0 /* priority */,
582 1 /* queue size */, 562 1 /* queue size */,
583 &process_kblock_for_unindex, 563 &process_kblock_for_unindex,
584 uc); 564 uc);
585} 565}
586 566
587 567
@@ -626,13 +606,14 @@ GNUNET_FS_unindex_do_remove_kblocks_ (struct GNUNET_FS_UnindexContext *uc)
626 sizeof (dpub), 606 sizeof (dpub),
627 &uc->uquery); 607 &uc->uquery);
628 uc->dqe = GNUNET_DATASTORE_get_key (uc->dsh, 608 uc->dqe = GNUNET_DATASTORE_get_key (uc->dsh,
629 uc->roff++, 609 0 /* next_uid */,
630 &uc->uquery, 610 false /* random */,
631 GNUNET_BLOCK_TYPE_FS_UBLOCK, 611 &uc->uquery,
632 0 /* priority */, 612 GNUNET_BLOCK_TYPE_FS_UBLOCK,
613 0 /* priority */,
633 1 /* queue size */, 614 1 /* queue size */,
634 &process_kblock_for_unindex, 615 &process_kblock_for_unindex,
635 uc); 616 uc);
636} 617}
637 618
638 619
@@ -825,8 +806,6 @@ GNUNET_FS_unindex_start (struct GNUNET_FS_Handle *h,
825 uc->start_time = GNUNET_TIME_absolute_get (); 806 uc->start_time = GNUNET_TIME_absolute_get ();
826 uc->file_size = size; 807 uc->file_size = size;
827 uc->client_info = cctx; 808 uc->client_info = cctx;
828 uc->seen_dh = GNUNET_CONTAINER_multihashmap_create (4,
829 GNUNET_NO);
830 GNUNET_FS_unindex_sync_ (uc); 809 GNUNET_FS_unindex_sync_ (uc);
831 pi.status = GNUNET_FS_STATUS_UNINDEX_START; 810 pi.status = GNUNET_FS_STATUS_UNINDEX_START;
832 pi.value.unindex.eta = GNUNET_TIME_UNIT_FOREVER_REL; 811 pi.value.unindex.eta = GNUNET_TIME_UNIT_FOREVER_REL;
diff --git a/src/fs/fs_uri.c b/src/fs/fs_uri.c
index fa27e6e9b..11968b750 100644
--- a/src/fs/fs_uri.c
+++ b/src/fs/fs_uri.c
@@ -309,7 +309,8 @@ uri_ksk_parse (const char *s,
309 } 309 }
310 iret = max; 310 iret = max;
311 dup = GNUNET_strdup (s); 311 dup = GNUNET_strdup (s);
312 keywords = GNUNET_malloc (max * sizeof (char *)); 312 keywords = GNUNET_new_array (max,
313 char *);
313 for (i = slen - 1; i >= (int) pos; i--) 314 for (i = slen - 1; i >= (int) pos; i--)
314 { 315 {
315 if ((s[i] == '%') && (&s[i] == strstr (&s[i], "%22"))) 316 if ((s[i] == '%') && (&s[i] == strstr (&s[i], "%22")))
@@ -937,7 +938,8 @@ GNUNET_FS_uri_ksk_merge (const struct GNUNET_FS_Uri *u1,
937 return NULL; 938 return NULL;
938 } 939 }
939 kc = u1->data.ksk.keywordCount; 940 kc = u1->data.ksk.keywordCount;
940 kl = GNUNET_malloc ((kc + u2->data.ksk.keywordCount) * sizeof (char *)); 941 kl = GNUNET_new_array (kc + u2->data.ksk.keywordCount,
942 char *);
941 for (i = 0; i < u1->data.ksk.keywordCount; i++) 943 for (i = 0; i < u1->data.ksk.keywordCount; i++)
942 kl[i] = GNUNET_strdup (u1->data.ksk.keywords[i]); 944 kl[i] = GNUNET_strdup (u1->data.ksk.keywords[i]);
943 for (i = 0; i < u2->data.ksk.keywordCount; i++) 945 for (i = 0; i < u2->data.ksk.keywordCount; i++)
@@ -991,8 +993,9 @@ GNUNET_FS_uri_dup (const struct GNUNET_FS_Uri *uri)
991 } 993 }
992 if (ret->data.ksk.keywordCount > 0) 994 if (ret->data.ksk.keywordCount > 0)
993 { 995 {
994 ret->data.ksk.keywords = 996 ret->data.ksk.keywords
995 GNUNET_malloc (ret->data.ksk.keywordCount * sizeof (char *)); 997 = GNUNET_new_array (ret->data.ksk.keywordCount,
998 char *);
996 for (i = 0; i < ret->data.ksk.keywordCount; i++) 999 for (i = 0; i < ret->data.ksk.keywordCount; i++)
997 ret->data.ksk.keywords[i] = GNUNET_strdup (uri->data.ksk.keywords[i]); 1000 ret->data.ksk.keywords[i] = GNUNET_strdup (uri->data.ksk.keywords[i]);
998 } 1001 }
@@ -1078,7 +1081,8 @@ GNUNET_FS_uri_ksk_create (const char *keywords,
1078 *emsg = GNUNET_strdup (_("Number of double-quotes not balanced!\n")); 1081 *emsg = GNUNET_strdup (_("Number of double-quotes not balanced!\n"));
1079 return NULL; 1082 return NULL;
1080 } 1083 }
1081 keywordarr = GNUNET_malloc (num_Words * sizeof (char *)); 1084 keywordarr = GNUNET_new_array (num_Words,
1085 char *);
1082 num_Words = 0; 1086 num_Words = 0;
1083 inWord = 0; 1087 inWord = 0;
1084 pos = searchString; 1088 pos = searchString;
@@ -1151,7 +1155,8 @@ GNUNET_FS_uri_ksk_create_from_args (unsigned int argc,
1151 uri = GNUNET_new (struct GNUNET_FS_Uri); 1155 uri = GNUNET_new (struct GNUNET_FS_Uri);
1152 uri->type = GNUNET_FS_URI_KSK; 1156 uri->type = GNUNET_FS_URI_KSK;
1153 uri->data.ksk.keywordCount = argc; 1157 uri->data.ksk.keywordCount = argc;
1154 uri->data.ksk.keywords = GNUNET_malloc (argc * sizeof (char *)); 1158 uri->data.ksk.keywords = GNUNET_new_array (argc,
1159 char *);
1155 for (i = 0; i < argc; i++) 1160 for (i = 0; i < argc; i++)
1156 { 1161 {
1157 keyword = argv[i]; 1162 keyword = argv[i];
@@ -1766,8 +1771,9 @@ GNUNET_FS_uri_ksk_create_from_meta_data (const struct GNUNET_CONTAINER_MetaData
1766 } 1771 }
1767 /* x3 because there might be a normalized variant of every keyword, 1772 /* x3 because there might be a normalized variant of every keyword,
1768 plus theoretically one more for mime... */ 1773 plus theoretically one more for mime... */
1769 ret->data.ksk.keywords = GNUNET_malloc 1774 ret->data.ksk.keywords
1770 (sizeof (char *) * (ent + tok_keywords + paren_keywords) * 3); 1775 = GNUNET_new_array ((ent + tok_keywords + paren_keywords) * 3,
1776 char *);
1771 GNUNET_CONTAINER_meta_data_iterate (md, &gather_uri_data, ret); 1777 GNUNET_CONTAINER_meta_data_iterate (md, &gather_uri_data, ret);
1772 } 1778 }
1773 if (tok_keywords > 0) 1779 if (tok_keywords > 0)
diff --git a/src/fs/gnunet-auto-share.c b/src/fs/gnunet-auto-share.c
index cc0111111..2f980520a 100644
--- a/src/fs/gnunet-auto-share.c
+++ b/src/fs/gnunet-auto-share.c
@@ -72,7 +72,7 @@ static int ret;
72/** 72/**
73 * Are we running 'verbosely'? 73 * Are we running 'verbosely'?
74 */ 74 */
75static int verbose; 75static unsigned int verbose;
76 76
77/** 77/**
78 * Configuration to use. 78 * Configuration to use.
@@ -759,26 +759,38 @@ free_item (void *cls,
759int 759int
760main (int argc, char *const *argv) 760main (int argc, char *const *argv)
761{ 761{
762 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 762 struct GNUNET_GETOPT_CommandLineOption options[] = {
763 {'a', "anonymity", "LEVEL", 763
764 gettext_noop ("set the desired LEVEL of sender-anonymity"), 764 GNUNET_GETOPT_OPTION_SET_UINT ('a',
765 1, &GNUNET_GETOPT_set_uint, &anonymity_level}, 765 "anonymity",
766 {'d', "disable-creation-time", NULL, 766 "LEVEL",
767 gettext_noop 767 gettext_noop ("set the desired LEVEL of sender-anonymity"),
768 ("disable adding the creation time to the metadata of the uploaded file"), 768 &anonymity_level),
769 0, &GNUNET_GETOPT_set_one, &do_disable_creation_time}, 769
770 {'D', "disable-extractor", NULL, 770 GNUNET_GETOPT_OPTION_SET_ONE ('d',
771 gettext_noop ("do not use libextractor to add keywords or metadata"), 771 "disable-creation-time",
772 0, &GNUNET_GETOPT_set_one, &disable_extractor}, 772 gettext_noop ("disable adding the creation time to the metadata of the uploaded file"),
773 {'p', "priority", "PRIORITY", 773 &do_disable_creation_time),
774 gettext_noop ("specify the priority of the content"), 774
775 1, &GNUNET_GETOPT_set_uint, &content_priority}, 775 GNUNET_GETOPT_OPTION_SET_ONE ('D',
776 {'r', "replication", "LEVEL", 776 "disable-extractor",
777 gettext_noop ("set the desired replication LEVEL"), 777 gettext_noop ("do not use libextractor to add keywords or metadata"),
778 1, &GNUNET_GETOPT_set_uint, &replication_level}, 778 &disable_extractor),
779 {'V', "verbose", NULL, 779
780 gettext_noop ("be verbose (print progress information)"), 780 GNUNET_GETOPT_OPTION_SET_UINT ('p',
781 0, &GNUNET_GETOPT_set_one, &verbose}, 781 "priority",
782 "PRIORITY",
783 gettext_noop ("specify the priority of the content"),
784 &content_priority),
785
786 GNUNET_GETOPT_OPTION_SET_UINT ('r',
787 "replication",
788 "LEVEL",
789 gettext_noop ("set the desired replication LEVEL"),
790 &replication_level),
791
792 GNUNET_GETOPT_OPTION_VERBOSE (&verbose),
793
782 GNUNET_GETOPT_OPTION_END 794 GNUNET_GETOPT_OPTION_END
783 }; 795 };
784 struct WorkItem *wi; 796 struct WorkItem *wi;
diff --git a/src/fs/gnunet-download.c b/src/fs/gnunet-download.c
index 6d9adb8ab..4d6f30587 100644
--- a/src/fs/gnunet-download.c
+++ b/src/fs/gnunet-download.c
@@ -30,7 +30,7 @@
30 30
31static int ret; 31static int ret;
32 32
33static int verbose; 33static unsigned int verbose;
34 34
35static int delete_incomplete; 35static int delete_incomplete;
36 36
@@ -299,33 +299,51 @@ run (void *cls, char *const *args, const char *cfgfile,
299int 299int
300main (int argc, char *const *argv) 300main (int argc, char *const *argv)
301{ 301{
302 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 302 struct GNUNET_GETOPT_CommandLineOption options[] = {
303 {'a', "anonymity", "LEVEL", 303 GNUNET_GETOPT_OPTION_SET_UINT ('a',
304 gettext_noop ("set the desired LEVEL of receiver-anonymity"), 304 "anonymity",
305 1, &GNUNET_GETOPT_set_uint, &anonymity}, 305 "LEVEL",
306 {'D', "delete-incomplete", NULL, 306 gettext_noop ("set the desired LEVEL of receiver-anonymity"),
307 gettext_noop ("delete incomplete downloads (when aborted with CTRL-C)"), 307 &anonymity),
308 0, &GNUNET_GETOPT_set_one, &delete_incomplete}, 308
309 {'n', "no-network", NULL, 309 GNUNET_GETOPT_OPTION_SET_ONE ('D',
310 gettext_noop ("only search the local peer (no P2P network search)"), 310 "delete-incomplete",
311 0, &GNUNET_GETOPT_set_one, &local_only}, 311 gettext_noop ("delete incomplete downloads (when aborted with CTRL-C)"),
312 {'o', "output", "FILENAME", 312 &delete_incomplete),
313 gettext_noop ("write the file to FILENAME"), 313
314 1, &GNUNET_GETOPT_set_string, &filename}, 314 GNUNET_GETOPT_OPTION_SET_ONE ('n',
315 {'p', "parallelism", "DOWNLOADS", 315 "no-network",
316 gettext_noop 316 gettext_noop ("only search the local peer (no P2P network search)"),
317 ("set the maximum number of parallel downloads that is allowed"), 317 &local_only),
318 1, &GNUNET_GETOPT_set_uint, &parallelism}, 318
319 {'r', "request-parallelism", "REQUESTS", 319 GNUNET_GETOPT_OPTION_STRING ('o',
320 gettext_noop 320 "output",
321 ("set the maximum number of parallel requests for blocks that is allowed"), 321 "FILENAME",
322 1, &GNUNET_GETOPT_set_uint, &request_parallelism}, 322 gettext_noop ("write the file to FILENAME"),
323 {'R', "recursive", NULL, 323 &filename),
324 gettext_noop ("download a GNUnet directory recursively"), 324
325 0, &GNUNET_GETOPT_set_one, &do_recursive}, 325 GNUNET_GETOPT_OPTION_SET_UINT ('p',
326 {'V', "verbose", NULL, 326 "parallelism",
327 gettext_noop ("be verbose (print progress information)"), 327 "DOWNLOADS",
328 0, &GNUNET_GETOPT_increment_value, &verbose}, 328 gettext_noop ("set the maximum number of parallel downloads that is allowed"),
329 &parallelism),
330
331 GNUNET_GETOPT_OPTION_SET_UINT ('r',
332 "request-parallelism",
333 "REQUESTS",
334 gettext_noop ("set the maximum number of parallel requests for blocks that is allowed"),
335 &request_parallelism),
336
337 GNUNET_GETOPT_OPTION_SET_ONE ('R',
338 "recursive",
339 gettext_noop ("download a GNUnet directory recursively"),
340 &do_recursive),
341
342 GNUNET_GETOPT_OPTION_INCREMENT_VALUE ('V',
343 "verbose",
344 gettext_noop ("be verbose (print progress information)"),
345 &verbose),
346
329 GNUNET_GETOPT_OPTION_END 347 GNUNET_GETOPT_OPTION_END
330 }; 348 };
331 349
diff --git a/src/fs/gnunet-fs-profiler.c b/src/fs/gnunet-fs-profiler.c
index cfbe57bbd..fb99d8f90 100644
--- a/src/fs/gnunet-fs-profiler.c
+++ b/src/fs/gnunet-fs-profiler.c
@@ -203,16 +203,26 @@ run (void *cls, char *const *args, const char *cfgfile,
203int 203int
204main (int argc, char *const *argv) 204main (int argc, char *const *argv)
205{ 205{
206 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 206 struct GNUNET_GETOPT_CommandLineOption options[] = {
207 {'n', "num-peers", "COUNT", 207
208 gettext_noop ("run the experiment with COUNT peers"), 208 GNUNET_GETOPT_OPTION_SET_UINT ('n',
209 1, &GNUNET_GETOPT_set_uint, &num_peers}, 209 "num-peers",
210 {'H', "hosts", "HOSTFILE", 210 "COUNT",
211 gettext_noop ("specifies name of a file with the HOSTS the testbed should use"), 211 gettext_noop ("run the experiment with COUNT peers"),
212 1, &GNUNET_GETOPT_set_string, &host_filename}, 212 &num_peers),
213 {'t', "timeout", "DELAY", 213
214 gettext_noop ("automatically terminate experiment after DELAY"), 214 GNUNET_GETOPT_OPTION_STRING ('H',
215 1, &GNUNET_GETOPT_set_relative_time, &timeout}, 215 "hosts",
216 "HOSTFILE",
217 gettext_noop ("specifies name of a file with the HOSTS the testbed should use"),
218 &host_filename),
219
220 GNUNET_GETOPT_OPTION_SET_RELATIVE_TIME ('t',
221 "timeout",
222 "DELAY",
223 gettext_noop ("automatically terminate experiment after DELAY"),
224 &timeout),
225
216 GNUNET_GETOPT_OPTION_END 226 GNUNET_GETOPT_OPTION_END
217 }; 227 };
218 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) 228 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
diff --git a/src/fs/gnunet-fs.c b/src/fs/gnunet-fs.c
index 7c20e025f..2b24b7124 100644
--- a/src/fs/gnunet-fs.c
+++ b/src/fs/gnunet-fs.c
@@ -43,7 +43,7 @@ static int list_indexed_files;
43/** 43/**
44 * Option -v given? 44 * Option -v given?
45 */ 45 */
46static int verbose; 46static unsigned int verbose;
47 47
48 48
49/** 49/**
@@ -112,10 +112,13 @@ run (void *cls, char *const *args, const char *cfgfile,
112int 112int
113main (int argc, char *const *argv) 113main (int argc, char *const *argv)
114{ 114{
115 static struct GNUNET_GETOPT_CommandLineOption options[] = { 115 struct GNUNET_GETOPT_CommandLineOption options[] = {
116 {'i', "list-indexed", NULL, 116
117 gettext_noop ("print a list of all indexed files"), 0, 117 GNUNET_GETOPT_OPTION_SET_ONE ('i',
118 &GNUNET_GETOPT_set_one, &list_indexed_files}, 118 "list-indexed",
119 gettext_noop ("print a list of all indexed files"),
120 &list_indexed_files),
121
119 GNUNET_GETOPT_OPTION_VERBOSE (&verbose), 122 GNUNET_GETOPT_OPTION_VERBOSE (&verbose),
120 GNUNET_GETOPT_OPTION_END 123 GNUNET_GETOPT_OPTION_END
121 }; 124 };
diff --git a/src/fs/gnunet-helper-fs-publish.c b/src/fs/gnunet-helper-fs-publish.c
index 55836e772..72a656de1 100644
--- a/src/fs/gnunet-helper-fs-publish.c
+++ b/src/fs/gnunet-helper-fs-publish.c
@@ -480,7 +480,7 @@ make_dev_zero (int fd,
480 GNUNET_assert (-1 != z); 480 GNUNET_assert (-1 != z);
481 if (z == fd) 481 if (z == fd)
482 return; 482 return;
483 dup2 (z, fd); 483 GNUNET_break (fd == dup2 (z, fd));
484 GNUNET_assert (0 == close (z)); 484 GNUNET_assert (0 == close (z));
485} 485}
486 486
diff --git a/src/fs/gnunet-publish.c b/src/fs/gnunet-publish.c
index a563d7b7a..2229e45e7 100644
--- a/src/fs/gnunet-publish.c
+++ b/src/fs/gnunet-publish.c
@@ -37,7 +37,7 @@ static int ret;
37/** 37/**
38 * Command line option 'verbose' set 38 * Command line option 'verbose' set
39 */ 39 */
40static int verbose; 40static unsigned int verbose;
41 41
42/** 42/**
43 * Handle to our configuration. 43 * Handle to our configuration.
@@ -893,63 +893,98 @@ run (void *cls,
893int 893int
894main (int argc, char *const *argv) 894main (int argc, char *const *argv)
895{ 895{
896 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 896 struct GNUNET_GETOPT_CommandLineOption options[] = {
897 {'a', "anonymity", "LEVEL", 897 GNUNET_GETOPT_OPTION_SET_UINT ('a',
898 gettext_noop ("set the desired LEVEL of sender-anonymity"), 898 "anonymity",
899 1, &GNUNET_GETOPT_set_uint, &bo.anonymity_level}, 899 "LEVEL",
900 {'d', "disable-creation-time", NULL, 900 gettext_noop ("set the desired LEVEL of sender-anonymity"),
901 gettext_noop 901 &bo.anonymity_level),
902 ("disable adding the creation time to the metadata of the uploaded file"), 902
903 0, &GNUNET_GETOPT_set_one, &do_disable_creation_time}, 903 GNUNET_GETOPT_OPTION_SET_ONE ('d',
904 {'D', "disable-extractor", NULL, 904 "disable-creation-time",
905 gettext_noop ("do not use libextractor to add keywords or metadata"), 905 gettext_noop ("disable adding the creation time to the "
906 0, &GNUNET_GETOPT_set_one, &disable_extractor}, 906 "metadata of the uploaded file"),
907 {'e', "extract", NULL, 907 &do_disable_creation_time),
908 gettext_noop 908
909 ("print list of extracted keywords that would be used, but do not perform upload"), 909 GNUNET_GETOPT_OPTION_SET_ONE ('D',
910 0, &GNUNET_GETOPT_set_one, &extract_only}, 910 "disable-extractor",
911 {'k', "key", "KEYWORD", 911 gettext_noop ("do not use libextractor to add keywords or metadata"),
912 gettext_noop 912 &disable_extractor),
913 ("add an additional keyword for the top-level file or directory" 913
914 " (this option can be specified multiple times)"), 914 GNUNET_GETOPT_OPTION_SET_ONE ('e',
915 1, &GNUNET_FS_getopt_set_keywords, &topKeywords}, 915 "extract",
916 {'m', "meta", "TYPE:VALUE", 916 gettext_noop ("print list of extracted keywords that would "
917 gettext_noop ("set the meta-data for the given TYPE to the given VALUE"), 917 "be used, but do not perform upload"),
918 1, &GNUNET_FS_getopt_set_metadata, &meta}, 918 &extract_only),
919 {'n', "noindex", NULL, 919
920 gettext_noop ("do not index, perform full insertion (stores entire " 920 GNUNET_FS_GETOPT_KEYWORDS ('k',
921 "file in encrypted form in GNUnet database)"), 921 "key",
922 0, &GNUNET_GETOPT_set_one, &do_insert}, 922 "KEYWORD",
923 {'N', "next", "ID", 923 gettext_noop ("add an additional keyword for the top-level "
924 gettext_noop 924 "file or directory (this option can be specified multiple times)"),
925 ("specify ID of an updated version to be published in the future" 925 &topKeywords),
926 " (for namespace insertions only)"), 926
927 1, &GNUNET_GETOPT_set_string, &next_id}, 927 GNUNET_FS_GETOPT_METADATA ('m',
928 {'p', "priority", "PRIORITY", 928 "meta",
929 gettext_noop ("specify the priority of the content"), 929 "TYPE:VALUE",
930 1, &GNUNET_GETOPT_set_uint, &bo.content_priority}, 930 gettext_noop ("set the meta-data for the given TYPE to the given VALUE"),
931 {'P', "pseudonym", "NAME", 931 &meta),
932 gettext_noop 932
933 ("publish the files under the pseudonym NAME (place file into namespace)"), 933 GNUNET_GETOPT_OPTION_SET_ONE ('n',
934 1, &GNUNET_GETOPT_set_string, &pseudonym}, 934 "noindex",
935 {'r', "replication", "LEVEL", 935 gettext_noop ("do not index, perform full insertion (stores "
936 gettext_noop ("set the desired replication LEVEL"), 936 "entire file in encrypted form in GNUnet database)"),
937 1, &GNUNET_GETOPT_set_uint, &bo.replication_level}, 937 &do_insert),
938 {'s', "simulate-only", NULL, 938
939 gettext_noop ("only simulate the process but do not do any " 939 GNUNET_GETOPT_OPTION_STRING ('N',
940 "actual publishing (useful to compute URIs)"), 940 "next",
941 0, &GNUNET_GETOPT_set_one, &do_simulate}, 941 "ID",
942 {'t', "this", "ID", 942 gettext_noop ("specify ID of an updated version to be "
943 gettext_noop ("set the ID of this version of the publication" 943 "published in the future (for namespace insertions only)"),
944 " (for namespace insertions only)"), 944 &next_id),
945 1, &GNUNET_GETOPT_set_string, &this_id}, 945
946 {'u', "uri", "URI", 946 GNUNET_GETOPT_OPTION_SET_UINT ('p',
947 gettext_noop ("URI to be published (can be used instead of passing a " 947 "priority",
948 "file to add keywords to the file with the respective URI)"), 948 "PRIORITY",
949 1, &GNUNET_GETOPT_set_string, &uri_string}, 949 gettext_noop ("specify the priority of the content"),
950 {'V', "verbose", NULL, 950 &bo.content_priority),
951 gettext_noop ("be verbose (print progress information)"), 951
952 0, &GNUNET_GETOPT_set_one, &verbose}, 952 GNUNET_GETOPT_OPTION_STRING ('P',
953 "pseudonym",
954 "NAME",
955 gettext_noop ("publish the files under the pseudonym "
956 "NAME (place file into namespace)"),
957 &pseudonym),
958
959 GNUNET_GETOPT_OPTION_SET_UINT ('r',
960 "replication",
961 "LEVEL",
962 gettext_noop ("set the desired replication LEVEL"),
963 &bo.replication_level),
964
965
966 GNUNET_GETOPT_OPTION_SET_ONE ('s',
967 "simulate-only",
968 gettext_noop ("only simulate the process but do not do "
969 "any actual publishing (useful to compute URIs)"),
970 &do_simulate),
971
972 GNUNET_GETOPT_OPTION_STRING ('t',
973 "this",
974 "ID",
975 gettext_noop ("set the ID of this version of the publication "
976 "(for namespace insertions only)"),
977 &this_id),
978
979 GNUNET_GETOPT_OPTION_STRING ('u',
980 "uri",
981 "URI",
982 gettext_noop ("URI to be published (can be used instead of passing a "
983 "file to add keywords to the file with the respective URI)"),
984 &uri_string),
985
986 GNUNET_GETOPT_OPTION_VERBOSE (&verbose),
987
953 GNUNET_GETOPT_OPTION_END 988 GNUNET_GETOPT_OPTION_END
954 }; 989 };
955 bo.expiration_time = 990 bo.expiration_time =
diff --git a/src/fs/gnunet-search.c b/src/fs/gnunet-search.c
index dfe6d0e75..22e790cf3 100644
--- a/src/fs/gnunet-search.c
+++ b/src/fs/gnunet-search.c
@@ -51,7 +51,7 @@ static unsigned int results_limit;
51 51
52static unsigned int results; 52static unsigned int results;
53 53
54static int verbose; 54static unsigned int verbose;
55 55
56static int local_only; 56static int local_only;
57 57
@@ -305,26 +305,42 @@ run (void *cls, char *const *args, const char *cfgfile,
305int 305int
306main (int argc, char *const *argv) 306main (int argc, char *const *argv)
307{ 307{
308 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 308 struct GNUNET_GETOPT_CommandLineOption options[] = {
309 {'a', "anonymity", "LEVEL", 309
310 gettext_noop ("set the desired LEVEL of receiver-anonymity"), 310 GNUNET_GETOPT_OPTION_SET_UINT ('a',
311 1, &GNUNET_GETOPT_set_uint, &anonymity}, 311 "anonymity",
312 {'n', "no-network", NULL, 312 "LEVEL",
313 gettext_noop ("only search the local peer (no P2P network search)"), 313 gettext_noop ("set the desired LEVEL of receiver-anonymity"),
314 0, &GNUNET_GETOPT_set_one, &local_only}, 314 &anonymity),
315 {'o', "output", "PREFIX", 315
316 gettext_noop ("write search results to file starting with PREFIX"), 316
317 1, &GNUNET_GETOPT_set_string, &output_filename}, 317 GNUNET_GETOPT_OPTION_SET_ONE ('n',
318 {'t', "timeout", "DELAY", 318 "no-network",
319 gettext_noop ("automatically terminate search after DELAY"), 319 gettext_noop ("only search the local peer (no P2P network search)"),
320 1, &GNUNET_GETOPT_set_relative_time, &timeout}, 320 &local_only),
321 {'V', "verbose", NULL, 321
322 gettext_noop ("be verbose (print progress information)"), 322 GNUNET_GETOPT_OPTION_STRING ('o',
323 0, &GNUNET_GETOPT_set_one, &verbose}, 323 "output",
324 {'N', "results", "VALUE", 324 "PREFIX",
325 gettext_noop 325 gettext_noop ("write search results to file starting with PREFIX"),
326 ("automatically terminate search after VALUE results are found"), 326 &output_filename),
327 1, &GNUNET_GETOPT_set_uint, &results_limit}, 327
328 GNUNET_GETOPT_OPTION_SET_RELATIVE_TIME ('t',
329 "timeout",
330 "DELAY",
331 gettext_noop ("automatically terminate search after DELAY"),
332 &timeout),
333
334
335 GNUNET_GETOPT_OPTION_VERBOSE (&verbose),
336
337 GNUNET_GETOPT_OPTION_SET_UINT ('N',
338 "results",
339 "VALUE",
340 gettext_noop ("automatically terminate search "
341 "after VALUE results are found"),
342 &results_limit),
343
328 GNUNET_GETOPT_OPTION_END 344 GNUNET_GETOPT_OPTION_END
329 }; 345 };
330 346
diff --git a/src/fs/gnunet-service-fs.c b/src/fs/gnunet-service-fs.c
index 256d0c2b8..09b1e05d8 100644
--- a/src/fs/gnunet-service-fs.c
+++ b/src/fs/gnunet-service-fs.c
@@ -38,7 +38,6 @@
38#include "gnunet_util_lib.h" 38#include "gnunet_util_lib.h"
39#include "gnunet-service-fs_cp.h" 39#include "gnunet-service-fs_cp.h"
40#include "gnunet-service-fs_indexing.h" 40#include "gnunet-service-fs_indexing.h"
41#include "gnunet-service-fs_lc.h"
42#include "gnunet-service-fs_pe.h" 41#include "gnunet-service-fs_pe.h"
43#include "gnunet-service-fs_pr.h" 42#include "gnunet-service-fs_pr.h"
44#include "gnunet-service-fs_push.h" 43#include "gnunet-service-fs_push.h"
diff --git a/src/fs/gnunet-service-fs_cadet_client.c b/src/fs/gnunet-service-fs_cadet_client.c
index 55e0cbc24..c729ebe41 100644
--- a/src/fs/gnunet-service-fs_cadet_client.c
+++ b/src/fs/gnunet-service-fs_cadet_client.c
@@ -487,7 +487,7 @@ reset_cadet (struct CadetHandle *mh)
487 GNUNET_CRYPTO_hash (GNUNET_APPLICATION_PORT_FS_BLOCK_TRANSFER, 487 GNUNET_CRYPTO_hash (GNUNET_APPLICATION_PORT_FS_BLOCK_TRANSFER,
488 strlen (GNUNET_APPLICATION_PORT_FS_BLOCK_TRANSFER), 488 strlen (GNUNET_APPLICATION_PORT_FS_BLOCK_TRANSFER),
489 &port); 489 &port);
490 mh->channel = GNUNET_CADET_channel_creatE (cadet_handle, 490 mh->channel = GNUNET_CADET_channel_create (cadet_handle,
491 mh, 491 mh,
492 &mh->target, 492 &mh->target,
493 &port, 493 &port,
@@ -627,7 +627,7 @@ get_cadet (const struct GNUNET_PeerIdentity *target)
627 GNUNET_CRYPTO_hash (GNUNET_APPLICATION_PORT_FS_BLOCK_TRANSFER, 627 GNUNET_CRYPTO_hash (GNUNET_APPLICATION_PORT_FS_BLOCK_TRANSFER,
628 strlen (GNUNET_APPLICATION_PORT_FS_BLOCK_TRANSFER), 628 strlen (GNUNET_APPLICATION_PORT_FS_BLOCK_TRANSFER),
629 &port); 629 &port);
630 mh->channel = GNUNET_CADET_channel_creatE (cadet_handle, 630 mh->channel = GNUNET_CADET_channel_create (cadet_handle,
631 mh, 631 mh,
632 &mh->target, 632 &mh->target,
633 &port, 633 &port,
diff --git a/src/fs/gnunet-service-fs_cadet_server.c b/src/fs/gnunet-service-fs_cadet_server.c
index adbce1154..f8619b812 100644
--- a/src/fs/gnunet-service-fs_cadet_server.c
+++ b/src/fs/gnunet-service-fs_cadet_server.c
@@ -289,7 +289,7 @@ handle_datastore_reply (void *cls,
289 } 289 }
290 return; 290 return;
291 } 291 }
292 if (msize > GNUNET_SERVER_MAX_MESSAGE_SIZE) 292 if (msize > GNUNET_MAX_MESSAGE_SIZE)
293 { 293 {
294 GNUNET_break (0); 294 GNUNET_break (0);
295 continue_writing (sc); 295 continue_writing (sc);
@@ -345,12 +345,13 @@ handle_request (void *cls,
345 GNUNET_NO); 345 GNUNET_NO);
346 refresh_timeout_task (sc); 346 refresh_timeout_task (sc);
347 sc->qe = GNUNET_DATASTORE_get_key (GSF_dsh, 347 sc->qe = GNUNET_DATASTORE_get_key (GSF_dsh,
348 0, 348 0 /* next_uid */,
349 &sqm->query, 349 false /* random */,
350 ntohl (sqm->type), 350 &sqm->query,
351 0 /* priority */, 351 ntohl (sqm->type),
352 GSF_datastore_queue_size, 352 0 /* priority */,
353 &handle_datastore_reply, 353 GSF_datastore_queue_size,
354 &handle_datastore_reply,
354 sc); 355 sc);
355 if (NULL == sc->qe) 356 if (NULL == sc->qe)
356 { 357 {
@@ -499,12 +500,12 @@ GSF_cadet_start_server ()
499 "Initializing cadet FS server with a limit of %llu connections\n", 500 "Initializing cadet FS server with a limit of %llu connections\n",
500 sc_count_max); 501 sc_count_max);
501 cadet_map = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES); 502 cadet_map = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
502 cadet_handle = GNUNET_CADET_connecT (GSF_cfg); 503 cadet_handle = GNUNET_CADET_connect (GSF_cfg);
503 GNUNET_assert (NULL != cadet_handle); 504 GNUNET_assert (NULL != cadet_handle);
504 GNUNET_CRYPTO_hash (GNUNET_APPLICATION_PORT_FS_BLOCK_TRANSFER, 505 GNUNET_CRYPTO_hash (GNUNET_APPLICATION_PORT_FS_BLOCK_TRANSFER,
505 strlen (GNUNET_APPLICATION_PORT_FS_BLOCK_TRANSFER), 506 strlen (GNUNET_APPLICATION_PORT_FS_BLOCK_TRANSFER),
506 &port); 507 &port);
507 cadet_port = GNUNET_CADET_open_porT (cadet_handle, 508 cadet_port = GNUNET_CADET_open_port (cadet_handle,
508 &port, 509 &port,
509 &connect_cb, 510 &connect_cb,
510 NULL, 511 NULL,
diff --git a/src/fs/gnunet-service-fs_cp.c b/src/fs/gnunet-service-fs_cp.c
index 3f7783ded..817aed257 100644
--- a/src/fs/gnunet-service-fs_cp.c
+++ b/src/fs/gnunet-service-fs_cp.c
@@ -859,7 +859,7 @@ handle_p2p_reply (void *cls,
859 size_t msize; 859 size_t msize;
860 860
861 GNUNET_assert (data_len + sizeof (struct PutMessage) < 861 GNUNET_assert (data_len + sizeof (struct PutMessage) <
862 GNUNET_SERVER_MAX_MESSAGE_SIZE); 862 GNUNET_MAX_MESSAGE_SIZE);
863 GNUNET_assert (peerreq->pr == pr); 863 GNUNET_assert (peerreq->pr == pr);
864 prd = GSF_pending_request_get_data_ (pr); 864 prd = GSF_pending_request_get_data_ (pr);
865 if (NULL == data) 865 if (NULL == data)
@@ -883,7 +883,7 @@ handle_p2p_reply (void *cls,
883 gettext_noop ("# replies received for other peers"), 883 gettext_noop ("# replies received for other peers"),
884 1, GNUNET_NO); 884 1, GNUNET_NO);
885 msize = sizeof (struct PutMessage) + data_len; 885 msize = sizeof (struct PutMessage) + data_len;
886 if (msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) 886 if (msize >= GNUNET_MAX_MESSAGE_SIZE)
887 { 887 {
888 GNUNET_break (0); 888 GNUNET_break (0);
889 return; 889 return;
diff --git a/src/fs/gnunet-service-fs_indexing.c b/src/fs/gnunet-service-fs_indexing.c
index 3ce68f487..ce6bcec41 100644
--- a/src/fs/gnunet-service-fs_indexing.c
+++ b/src/fs/gnunet-service-fs_indexing.c
@@ -438,7 +438,7 @@ GNUNET_FS_indexing_send_list (struct GNUNET_MQ_Handle *mq)
438 fn = pos->filename; 438 fn = pos->filename;
439 slen = strlen (fn) + 1; 439 slen = strlen (fn) + 1;
440 if (slen + sizeof (struct IndexInfoMessage) >= 440 if (slen + sizeof (struct IndexInfoMessage) >=
441 GNUNET_SERVER_MAX_MESSAGE_SIZE) 441 GNUNET_MAX_MESSAGE_SIZE)
442 { 442 {
443 GNUNET_break (0); 443 GNUNET_break (0);
444 break; 444 break;
diff --git a/src/fs/gnunet-service-fs_lc.c b/src/fs/gnunet-service-fs_lc.c
deleted file mode 100644
index 9ffd6cadd..000000000
--- a/src/fs/gnunet-service-fs_lc.c
+++ /dev/null
@@ -1,33 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20/**
21 * @file fs/gnunet-service-fs_lc.c
22 * @brief API to handle 'local clients'
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "gnunet-service-fs.h"
27#include "gnunet-service-fs_lc.h"
28#include "gnunet-service-fs_cp.h"
29#include "gnunet-service-fs_pr.h"
30
31
32
33/* 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
deleted file mode 100644
index 6671ed33c..000000000
--- a/src/fs/gnunet-service-fs_lc.h
+++ /dev/null
@@ -1,33 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21/**
22 * @file fs/gnunet-service-fs_lc.h
23 * @brief API to handle 'local clients'
24 * @author Christian Grothoff
25 */
26#ifndef GNUNET_SERVICE_FS_LC_H
27#define GNUNET_SERVICE_FS_LC_H
28
29#include "gnunet-service-fs.h"
30
31
32#endif
33/* end of gnunet-service-fs_lc.h */
diff --git a/src/fs/gnunet-service-fs_pr.c b/src/fs/gnunet-service-fs_pr.c
index b0fda24b5..b736b49c2 100644
--- a/src/fs/gnunet-service-fs_pr.c
+++ b/src/fs/gnunet-service-fs_pr.c
@@ -160,20 +160,27 @@ struct GSF_PendingRequest
160 struct GNUNET_SCHEDULER_Task * warn_task; 160 struct GNUNET_SCHEDULER_Task * warn_task;
161 161
162 /** 162 /**
163 * Current offset for querying our local datastore for results. 163 * Do we have a first UID yet?
164 * Starts at a random value, incremented until we get the same 164 */
165 * UID again (detected using 'first_uid'), which is then used 165 bool have_first_uid;
166 * to termiante the iteration. 166
167 /**
168 * Have we seen a NULL result yet?
167 */ 169 */
168 uint64_t local_result_offset; 170 bool seen_null;
169 171
170 /** 172 /**
171 * Unique ID of the first result from the local datastore; 173 * Unique ID of the first result from the local datastore;
172 * used to detect wrap-around of the offset. 174 * used to terminate the loop.
173 */ 175 */
174 uint64_t first_uid; 176 uint64_t first_uid;
175 177
176 /** 178 /**
179 * Result count.
180 */
181 size_t result_count;
182
183 /**
177 * How often have we retried this request via 'cadet'? 184 * How often have we retried this request via 'cadet'?
178 * (used to bound overall retries). 185 * (used to bound overall retries).
179 */ 186 */
@@ -189,11 +196,6 @@ struct GSF_PendingRequest
189 */ 196 */
190 unsigned int replies_seen_size; 197 unsigned int replies_seen_size;
191 198
192 /**
193 * Do we have a first UID yet?
194 */
195 unsigned int have_first_uid;
196
197}; 199};
198 200
199 201
@@ -332,8 +334,6 @@ GSF_pending_request_create_ (enum GSF_PendingRequestOptions options,
332 if (NULL != target) 334 if (NULL != target)
333 extra += sizeof (struct GNUNET_PeerIdentity); 335 extra += sizeof (struct GNUNET_PeerIdentity);
334 pr = GNUNET_malloc (sizeof (struct GSF_PendingRequest) + extra); 336 pr = GNUNET_malloc (sizeof (struct GSF_PendingRequest) + extra);
335 pr->local_result_offset =
336 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
337 pr->public_data.query = *query; 337 pr->public_data.query = *query;
338 eptr = (struct GNUNET_HashCode *) &pr[1]; 338 eptr = (struct GNUNET_HashCode *) &pr[1];
339 if (NULL != target) 339 if (NULL != target)
@@ -1340,6 +1340,123 @@ odc_warn_delay_task (void *cls)
1340} 1340}
1341 1341
1342 1342
1343/* Call our continuation (if we have any) */
1344static void
1345call_continuation (struct GSF_PendingRequest *pr)
1346{
1347 GSF_LocalLookupContinuation cont = pr->llc_cont;
1348
1349 GNUNET_assert (NULL == pr->qe);
1350 if (NULL != pr->warn_task)
1351 {
1352 GNUNET_SCHEDULER_cancel (pr->warn_task);
1353 pr->warn_task = NULL;
1354 }
1355 if (NULL == cont)
1356 return; /* no continuation */
1357 pr->llc_cont = NULL;
1358 if (0 != (GSF_PRO_LOCAL_ONLY & pr->public_data.options))
1359 {
1360 if (GNUNET_BLOCK_EVALUATION_OK_LAST != pr->local_result)
1361 {
1362 /* Signal that we are done and that there won't be any
1363 additional results to allow client to clean up state. */
1364 pr->rh (pr->rh_cls,
1365 GNUNET_BLOCK_EVALUATION_OK_LAST,
1366 pr,
1367 UINT32_MAX,
1368 GNUNET_TIME_UNIT_ZERO_ABS,
1369 GNUNET_TIME_UNIT_FOREVER_ABS,
1370 GNUNET_BLOCK_TYPE_ANY,
1371 NULL,
1372 0);
1373 }
1374 /* Finally, call our continuation to signal that we are
1375 done with local processing of this request; i.e. to
1376 start reading again from the client. */
1377 cont (pr->llc_cont_cls, NULL, GNUNET_BLOCK_EVALUATION_OK_LAST);
1378 return;
1379 }
1380
1381 cont (pr->llc_cont_cls, pr, pr->local_result);
1382}
1383
1384
1385/* Update stats and call continuation */
1386static void
1387no_more_local_results (struct GSF_PendingRequest *pr)
1388{
1389 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1390 "No further local responses available.\n");
1391#if INSANE_STATISTICS
1392 if ( (GNUNET_BLOCK_TYPE_FS_DBLOCK == pr->public_data.type) ||
1393 (GNUNET_BLOCK_TYPE_FS_IBLOCK == pr->public_data.type) )
1394 GNUNET_STATISTICS_update (GSF_stats,
1395 gettext_noop ("# requested DBLOCK or IBLOCK not found"),
1396 1,
1397 GNUNET_NO);
1398#endif
1399 call_continuation (pr);
1400}
1401
1402
1403/* forward declaration */
1404static void
1405process_local_reply (void *cls,
1406 const struct GNUNET_HashCode *key,
1407 size_t size,
1408 const void *data,
1409 enum GNUNET_BLOCK_Type type,
1410 uint32_t priority,
1411 uint32_t anonymity,
1412 struct GNUNET_TIME_Absolute expiration,
1413 uint64_t uid);
1414
1415
1416/* Start a local query */
1417static void
1418start_local_query (struct GSF_PendingRequest *pr,
1419 uint64_t next_uid,
1420 bool random)
1421{
1422 pr->qe_start = GNUNET_TIME_absolute_get ();
1423 pr->warn_task =
1424 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
1425 &warn_delay_task,
1426 pr);
1427 pr->qe =
1428 GNUNET_DATASTORE_get_key (GSF_dsh,
1429 next_uid,
1430 random,
1431 &pr->public_data.query,
1432 pr->public_data.type ==
1433 GNUNET_BLOCK_TYPE_FS_DBLOCK ?
1434 GNUNET_BLOCK_TYPE_ANY : pr->public_data.type,
1435 (0 !=
1436 (GSF_PRO_PRIORITY_UNLIMITED & pr->
1437 public_data.options)) ? UINT_MAX : 1
1438 /* queue priority */ ,
1439 (0 !=
1440 (GSF_PRO_PRIORITY_UNLIMITED & pr->
1441 public_data.options)) ? UINT_MAX :
1442 GSF_datastore_queue_size
1443 /* max queue size */ ,
1444 &process_local_reply, pr);
1445 if (NULL != pr->qe)
1446 return;
1447 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1448 "ERROR Requesting `%s' of type %d with next_uid %llu from datastore.\n",
1449 GNUNET_h2s (&pr->public_data.query),
1450 pr->public_data.type,
1451 (unsigned long long) next_uid);
1452 GNUNET_STATISTICS_update (GSF_stats,
1453 gettext_noop ("# Datastore lookups concluded (error queueing)"),
1454 1,
1455 GNUNET_NO);
1456 call_continuation (pr);
1457}
1458
1459
1343/** 1460/**
1344 * We're processing (local) results for a search request 1461 * We're processing (local) results for a search request
1345 * from another peer. Pass applicable results to the 1462 * from another peer. Pass applicable results to the
@@ -1369,69 +1486,71 @@ process_local_reply (void *cls,
1369 uint64_t uid) 1486 uint64_t uid)
1370{ 1487{
1371 struct GSF_PendingRequest *pr = cls; 1488 struct GSF_PendingRequest *pr = cls;
1372 GSF_LocalLookupContinuation cont;
1373 struct ProcessReplyClosure prq; 1489 struct ProcessReplyClosure prq;
1374 struct GNUNET_HashCode query; 1490 struct GNUNET_HashCode query;
1375 unsigned int old_rf; 1491 unsigned int old_rf;
1376 1492
1377 GNUNET_SCHEDULER_cancel (pr->warn_task); 1493 GNUNET_SCHEDULER_cancel (pr->warn_task);
1378 pr->warn_task = NULL; 1494 pr->warn_task = NULL;
1379 if (NULL != pr->qe) 1495 if (NULL == pr->qe)
1496 goto called_from_on_demand;
1497 pr->qe = NULL;
1498 if ( (NULL == key) &&
1499 pr->seen_null &&
1500 !pr->have_first_uid) /* We have hit the end for the 2nd time with no results */
1380 { 1501 {
1381 pr->qe = NULL; 1502 /* No results */
1382 if (NULL == key)
1383 {
1384#if INSANE_STATISTICS 1503#if INSANE_STATISTICS
1385 GNUNET_STATISTICS_update (GSF_stats, 1504 GNUNET_STATISTICS_update (GSF_stats,
1386 gettext_noop 1505 gettext_noop
1387 ("# Datastore lookups concluded (no results)"), 1506 ("# Datastore lookups concluded (no results)"),
1388 1, GNUNET_NO); 1507 1, GNUNET_NO);
1389#endif 1508#endif
1390 } 1509 no_more_local_results (pr);
1391 if (GNUNET_NO == pr->have_first_uid) 1510 return;
1392 { 1511 }
1393 pr->first_uid = uid; 1512 if ( ( (NULL == key) &&
1394 pr->have_first_uid = 1; 1513 pr->seen_null ) || /* We have hit the end for the 2nd time OR */
1395 } 1514 ( pr->seen_null &&
1396 else 1515 pr->have_first_uid &&
1397 { 1516 (uid >= pr->first_uid) ) ) /* We have hit the end and past first UID */
1398 if ((uid == pr->first_uid) && (key != NULL)) 1517 {
1399 { 1518 /* Seen all results */
1400 GNUNET_STATISTICS_update (GSF_stats, 1519 GNUNET_STATISTICS_update (GSF_stats,
1401 gettext_noop 1520 gettext_noop
1402 ("# Datastore lookups concluded (seen all)"), 1521 ("# Datastore lookups concluded (seen all)"),
1403 1, GNUNET_NO); 1522 1, GNUNET_NO);
1404 key = NULL; /* all replies seen! */ 1523 no_more_local_results (pr);
1405 } 1524 return;
1406 pr->have_first_uid++;
1407 if ((pr->have_first_uid > MAX_RESULTS) && (key != NULL))
1408 {
1409 GNUNET_STATISTICS_update (GSF_stats,
1410 gettext_noop
1411 ("# Datastore lookups aborted (more than MAX_RESULTS)"),
1412 1, GNUNET_NO);
1413 key = NULL; /* all replies seen! */
1414 }
1415 }
1416 } 1525 }
1417 if (NULL == key) 1526 if (NULL == key)
1418 { 1527 {
1419 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, 1528 GNUNET_assert (!pr->seen_null);
1420 "No further local responses available.\n"); 1529 pr->seen_null = true;
1421#if INSANE_STATISTICS 1530 start_local_query (pr,
1422 if ((pr->public_data.type == GNUNET_BLOCK_TYPE_FS_DBLOCK) || 1531 0 /* next_uid */,
1423 (pr->public_data.type == GNUNET_BLOCK_TYPE_FS_IBLOCK)) 1532 false /* random */);
1424 GNUNET_STATISTICS_update (GSF_stats, 1533 return;
1425 gettext_noop 1534 }
1426 ("# requested DBLOCK or IBLOCK not found"), 1, 1535 if (!pr->have_first_uid)
1427 GNUNET_NO); 1536 {
1428#endif 1537 pr->first_uid = uid;
1429 goto check_error_and_continue; 1538 pr->have_first_uid = true;
1539 }
1540 pr->result_count++;
1541 if (pr->result_count > MAX_RESULTS)
1542 {
1543 GNUNET_STATISTICS_update (GSF_stats,
1544 gettext_noop
1545 ("# Datastore lookups aborted (more than MAX_RESULTS)"),
1546 1, GNUNET_NO);
1547 no_more_local_results (pr);
1548 return;
1430 } 1549 }
1431 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1550 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1432 "Received reply for `%s' of type %d with UID %llu from datastore.\n", 1551 "Received reply for `%s' of type %d with UID %llu from datastore.\n",
1433 GNUNET_h2s (key), type, (unsigned long long) uid); 1552 GNUNET_h2s (key), type, (unsigned long long) uid);
1434 if (type == GNUNET_BLOCK_TYPE_FS_ONDEMAND) 1553 if (GNUNET_BLOCK_TYPE_FS_ONDEMAND == type)
1435 { 1554 {
1436 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1555 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1437 "Found ONDEMAND block, performing on-demand encoding\n"); 1556 "Found ONDEMAND block, performing on-demand encoding\n");
@@ -1458,33 +1577,12 @@ process_local_reply (void *cls,
1458 gettext_noop ("# on-demand lookups failed"), 1, 1577 gettext_noop ("# on-demand lookups failed"), 1,
1459 GNUNET_NO); 1578 GNUNET_NO);
1460 GNUNET_SCHEDULER_cancel (pr->warn_task); 1579 GNUNET_SCHEDULER_cancel (pr->warn_task);
1461 pr->warn_task = 1580 start_local_query (pr,
1462 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, 1581 uid + 1 /* next_uid */,
1463 &warn_delay_task, pr); 1582 false /* random */);
1464 pr->qe = 1583 return;
1465 GNUNET_DATASTORE_get_key (GSF_dsh, pr->local_result_offset - 1,
1466 &pr->public_data.query,
1467 pr->public_data.type ==
1468 GNUNET_BLOCK_TYPE_FS_DBLOCK ?
1469 GNUNET_BLOCK_TYPE_ANY : pr->public_data.type,
1470 (0 !=
1471 (GSF_PRO_PRIORITY_UNLIMITED &
1472 pr->public_data.options)) ? UINT_MAX : 1
1473 /* queue priority */ ,
1474 (0 !=
1475 (GSF_PRO_PRIORITY_UNLIMITED &
1476 pr->public_data.options)) ? UINT_MAX :
1477 GSF_datastore_queue_size
1478 /* max queue size */ ,
1479 &process_local_reply, pr);
1480 if (NULL != pr->qe)
1481 return; /* we're done */
1482 GNUNET_STATISTICS_update (GSF_stats,
1483 gettext_noop
1484 ("# Datastore lookups concluded (error queueing)"),
1485 1, GNUNET_NO);
1486 goto check_error_and_continue;
1487 } 1584 }
1585called_from_on_demand:
1488 old_rf = pr->public_data.results_found; 1586 old_rf = pr->public_data.results_found;
1489 memset (&prq, 0, sizeof (prq)); 1587 memset (&prq, 0, sizeof (prq));
1490 prq.data = data; 1588 prq.data = data;
@@ -1496,34 +1594,9 @@ process_local_reply (void *cls,
1496 GNUNET_break (0); 1594 GNUNET_break (0);
1497 GNUNET_DATASTORE_remove (GSF_dsh, key, size, data, -1, -1, 1595 GNUNET_DATASTORE_remove (GSF_dsh, key, size, data, -1, -1,
1498 NULL, NULL); 1596 NULL, NULL);
1499 pr->qe_start = GNUNET_TIME_absolute_get (); 1597 start_local_query (pr,
1500 pr->warn_task = 1598 uid + 1 /* next_uid */,
1501 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, 1599 false /* random */);
1502 &warn_delay_task, pr);
1503 pr->qe =
1504 GNUNET_DATASTORE_get_key (GSF_dsh, pr->local_result_offset - 1,
1505 &pr->public_data.query,
1506 pr->public_data.type ==
1507 GNUNET_BLOCK_TYPE_FS_DBLOCK ?
1508 GNUNET_BLOCK_TYPE_ANY : pr->public_data.type,
1509 (0 !=
1510 (GSF_PRO_PRIORITY_UNLIMITED &
1511 pr->public_data.options)) ? UINT_MAX : 1
1512 /* queue priority */ ,
1513 (0 !=
1514 (GSF_PRO_PRIORITY_UNLIMITED &
1515 pr->public_data.options)) ? UINT_MAX :
1516 GSF_datastore_queue_size
1517 /* max queue size */ ,
1518 &process_local_reply, pr);
1519 if (NULL == pr->qe)
1520 {
1521 GNUNET_STATISTICS_update (GSF_stats,
1522 gettext_noop
1523 ("# Datastore lookups concluded (error queueing)"),
1524 1, GNUNET_NO);
1525 goto check_error_and_continue;
1526 }
1527 return; 1600 return;
1528 } 1601 }
1529 prq.type = type; 1602 prq.type = type;
@@ -1535,14 +1608,15 @@ process_local_reply (void *cls,
1535 prq.eo = GNUNET_BLOCK_EO_LOCAL_SKIP_CRYPTO; 1608 prq.eo = GNUNET_BLOCK_EO_LOCAL_SKIP_CRYPTO;
1536 process_reply (&prq, key, pr); 1609 process_reply (&prq, key, pr);
1537 pr->local_result = prq.eval; 1610 pr->local_result = prq.eval;
1538 if (prq.eval == GNUNET_BLOCK_EVALUATION_OK_LAST) 1611 if (GNUNET_BLOCK_EVALUATION_OK_LAST == prq.eval)
1539 { 1612 {
1540 GNUNET_STATISTICS_update (GSF_stats, 1613 GNUNET_STATISTICS_update (GSF_stats,
1541 gettext_noop 1614 gettext_noop
1542 ("# Datastore lookups concluded (found last result)"), 1615 ("# Datastore lookups concluded (found last result)"),
1543 1, 1616 1,
1544 GNUNET_NO); 1617 GNUNET_NO);
1545 goto check_error_and_continue; 1618 call_continuation (pr);
1619 return;
1546 } 1620 }
1547 if ((0 == (GSF_PRO_PRIORITY_UNLIMITED & pr->public_data.options)) && 1621 if ((0 == (GSF_PRO_PRIORITY_UNLIMITED & pr->public_data.options)) &&
1548 ((GNUNET_YES == GSF_test_get_load_too_high_ (0)) || 1622 ((GNUNET_YES == GSF_test_get_load_too_high_ (0)) ||
@@ -1554,66 +1628,12 @@ process_local_reply (void *cls,
1554 gettext_noop ("# Datastore lookups concluded (load too high)"), 1628 gettext_noop ("# Datastore lookups concluded (load too high)"),
1555 1, 1629 1,
1556 GNUNET_NO); 1630 GNUNET_NO);
1557 goto check_error_and_continue; 1631 call_continuation (pr);
1558 }
1559 pr->qe_start = GNUNET_TIME_absolute_get ();
1560 pr->warn_task =
1561 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
1562 &warn_delay_task,
1563 pr);
1564 pr->qe =
1565 GNUNET_DATASTORE_get_key (GSF_dsh, pr->local_result_offset++,
1566 &pr->public_data.query,
1567 pr->public_data.type ==
1568 GNUNET_BLOCK_TYPE_FS_DBLOCK ?
1569 GNUNET_BLOCK_TYPE_ANY : pr->public_data.type,
1570 (0 !=
1571 (GSF_PRO_PRIORITY_UNLIMITED & pr->
1572 public_data.options)) ? UINT_MAX : 1
1573 /* queue priority */ ,
1574 (0 !=
1575 (GSF_PRO_PRIORITY_UNLIMITED & pr->
1576 public_data.options)) ? UINT_MAX :
1577 GSF_datastore_queue_size
1578 /* max queue size */ ,
1579 &process_local_reply, pr);
1580 /* check if we successfully queued another datastore request;
1581 * if so, return, otherwise call our continuation (if we have
1582 * any) */
1583check_error_and_continue:
1584 if (NULL != pr->qe)
1585 return; 1632 return;
1586 if (NULL != pr->warn_task)
1587 {
1588 GNUNET_SCHEDULER_cancel (pr->warn_task);
1589 pr->warn_task = NULL;
1590 } 1633 }
1591 if (NULL == (cont = pr->llc_cont)) 1634 start_local_query (pr,
1592 return; /* no continuation */ 1635 uid + 1 /* next_uid */,
1593 pr->llc_cont = NULL; 1636 false /* random */);
1594 if (0 != (GSF_PRO_LOCAL_ONLY & pr->public_data.options))
1595 {
1596 if (GNUNET_BLOCK_EVALUATION_OK_LAST != pr->local_result)
1597 {
1598 /* Signal that we are done and that there won't be any
1599 additional results to allow client to clean up state. */
1600 pr->rh (pr->rh_cls,
1601 GNUNET_BLOCK_EVALUATION_OK_LAST,
1602 pr,
1603 UINT32_MAX,
1604 GNUNET_TIME_UNIT_ZERO_ABS,
1605 GNUNET_TIME_UNIT_FOREVER_ABS,
1606 GNUNET_BLOCK_TYPE_ANY,
1607 NULL, 0);
1608 }
1609 /* Finally, call our continuation to signal that we are
1610 done with local processing of this request; i.e. to
1611 start reading again from the client. */
1612 cont (pr->llc_cont_cls, NULL, GNUNET_BLOCK_EVALUATION_OK_LAST);
1613 return;
1614 }
1615
1616 cont (pr->llc_cont_cls, pr, pr->local_result);
1617} 1637}
1618 1638
1619 1639
@@ -1657,43 +1677,14 @@ GSF_local_lookup_ (struct GSF_PendingRequest *pr,
1657 GNUNET_assert (NULL == pr->llc_cont); 1677 GNUNET_assert (NULL == pr->llc_cont);
1658 pr->llc_cont = cont; 1678 pr->llc_cont = cont;
1659 pr->llc_cont_cls = cont_cls; 1679 pr->llc_cont_cls = cont_cls;
1660 pr->qe_start = GNUNET_TIME_absolute_get ();
1661 pr->warn_task =
1662 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
1663 &warn_delay_task,
1664 pr);
1665#if INSANE_STATISTICS 1680#if INSANE_STATISTICS
1666 GNUNET_STATISTICS_update (GSF_stats, 1681 GNUNET_STATISTICS_update (GSF_stats,
1667 gettext_noop ("# Datastore lookups initiated"), 1, 1682 gettext_noop ("# Datastore lookups initiated"), 1,
1668 GNUNET_NO); 1683 GNUNET_NO);
1669#endif 1684#endif
1670 pr->qe = 1685 start_local_query(pr,
1671 GNUNET_DATASTORE_get_key (GSF_dsh, pr->local_result_offset++, 1686 0 /* next_uid */,
1672 &pr->public_data.query, 1687 true /* random */);
1673 pr->public_data.type ==
1674 GNUNET_BLOCK_TYPE_FS_DBLOCK ?
1675 GNUNET_BLOCK_TYPE_ANY : pr->public_data.type,
1676 (0 !=
1677 (GSF_PRO_PRIORITY_UNLIMITED & pr->
1678 public_data.options)) ? UINT_MAX : 1
1679 /* queue priority */ ,
1680 (0 !=
1681 (GSF_PRO_PRIORITY_UNLIMITED & pr->
1682 public_data.options)) ? UINT_MAX :
1683 GSF_datastore_queue_size
1684 /* max queue size */ ,
1685 &process_local_reply, pr);
1686 if (NULL != pr->qe)
1687 return;
1688 GNUNET_STATISTICS_update (GSF_stats,
1689 gettext_noop
1690 ("# Datastore lookups concluded (error queueing)"),
1691 1, GNUNET_NO);
1692 GNUNET_SCHEDULER_cancel (pr->warn_task);
1693 pr->warn_task = NULL;
1694 pr->llc_cont = NULL;
1695 if (NULL != cont)
1696 cont (cont_cls, pr, pr->local_result);
1697} 1688}
1698 1689
1699 1690
diff --git a/src/fs/gnunet-service-fs_put.c b/src/fs/gnunet-service-fs_put.c
index bb4cb4ecb..cd062bf2b 100644
--- a/src/fs/gnunet-service-fs_put.c
+++ b/src/fs/gnunet-service-fs_put.c
@@ -72,9 +72,14 @@ struct PutOperator
72 uint64_t zero_anonymity_count_estimate; 72 uint64_t zero_anonymity_count_estimate;
73 73
74 /** 74 /**
75 * Current offset when iterating the database. 75 * Count of results received from the database.
76 */ 76 */
77 uint64_t current_offset; 77 uint64_t result_count;
78
79 /**
80 * Next UID to request when iterating the database.
81 */
82 uint64_t next_uid;
78}; 83};
79 84
80 85
@@ -177,37 +182,43 @@ delay_dht_put_task (void *cls)
177 */ 182 */
178static void 183static void
179process_dht_put_content (void *cls, 184process_dht_put_content (void *cls,
180 const struct GNUNET_HashCode * key, 185 const struct GNUNET_HashCode * key,
181 size_t size, 186 size_t size,
182 const void *data, 187 const void *data,
183 enum GNUNET_BLOCK_Type type, 188 enum GNUNET_BLOCK_Type type,
184 uint32_t priority, uint32_t anonymity, 189 uint32_t priority,
185 struct GNUNET_TIME_Absolute expiration, uint64_t uid) 190 uint32_t anonymity,
191 struct GNUNET_TIME_Absolute expiration,
192 uint64_t uid)
186{ 193{
187 struct PutOperator *po = cls; 194 struct PutOperator *po = cls;
188 195
189 po->dht_qe = NULL; 196 po->dht_qe = NULL;
190 if (key == NULL) 197 if (key == NULL)
191 { 198 {
192 po->zero_anonymity_count_estimate = po->current_offset - 1; 199 po->zero_anonymity_count_estimate = po->result_count;
193 po->current_offset = 0; 200 po->result_count = 0;
201 po->next_uid = 0;
194 po->dht_task = GNUNET_SCHEDULER_add_now (&delay_dht_put_task, po); 202 po->dht_task = GNUNET_SCHEDULER_add_now (&delay_dht_put_task, po);
195 return; 203 return;
196 } 204 }
205 po->result_count++;
206 po->next_uid = uid + 1;
197 po->zero_anonymity_count_estimate = 207 po->zero_anonymity_count_estimate =
198 GNUNET_MAX (po->current_offset, po->zero_anonymity_count_estimate); 208 GNUNET_MAX (po->result_count, po->zero_anonymity_count_estimate);
199 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 209 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
200 "Retrieved block `%s' of type %u for DHT PUT\n", GNUNET_h2s (key), 210 "Retrieved block `%s' of type %u for DHT PUT\n", GNUNET_h2s (key),
201 type); 211 type);
202 po->dht_put = GNUNET_DHT_put (GSF_dht, 212 po->dht_put = GNUNET_DHT_put (GSF_dht,
203 key, 213 key,
204 DEFAULT_PUT_REPLICATION, 214 DEFAULT_PUT_REPLICATION,
205 GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, 215 GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
206 type, 216 type,
207 size, 217 size,
208 data, 218 data,
209 expiration, 219 expiration,
210 &delay_dht_put_blocks, po); 220 &delay_dht_put_blocks,
221 po);
211} 222}
212 223
213 224
@@ -223,10 +234,13 @@ gather_dht_put_blocks (void *cls)
223 234
224 po->dht_task = NULL; 235 po->dht_task = NULL;
225 po->dht_qe = 236 po->dht_qe =
226 GNUNET_DATASTORE_get_zero_anonymity (GSF_dsh, po->current_offset++, 0, 237 GNUNET_DATASTORE_get_zero_anonymity (GSF_dsh,
238 po->next_uid,
239 0,
227 UINT_MAX, 240 UINT_MAX,
228 po->dht_put_type, 241 po->dht_put_type,
229 &process_dht_put_content, po); 242 &process_dht_put_content,
243 po);
230 if (NULL == po->dht_qe) 244 if (NULL == po->dht_qe)
231 po->dht_task = GNUNET_SCHEDULER_add_now (&delay_dht_put_task, po); 245 po->dht_task = GNUNET_SCHEDULER_add_now (&delay_dht_put_task, po);
232} 246}
diff --git a/src/fs/gnunet-unindex.c b/src/fs/gnunet-unindex.c
index 40fa13b62..c53a85fb4 100644
--- a/src/fs/gnunet-unindex.c
+++ b/src/fs/gnunet-unindex.c
@@ -30,7 +30,7 @@
30 30
31static int ret; 31static int ret;
32 32
33static int verbose; 33static unsigned int verbose;
34 34
35static const struct GNUNET_CONFIGURATION_Handle *cfg; 35static const struct GNUNET_CONFIGURATION_Handle *cfg;
36 36
@@ -162,10 +162,10 @@ run (void *cls, char *const *args, const char *cfgfile,
162int 162int
163main (int argc, char *const *argv) 163main (int argc, char *const *argv)
164{ 164{
165 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 165 struct GNUNET_GETOPT_CommandLineOption options[] = {
166 {'V', "verbose", NULL, 166
167 gettext_noop ("be verbose (print progress information)"), 167 GNUNET_GETOPT_OPTION_VERBOSE (&verbose),
168 0, &GNUNET_GETOPT_set_one, &verbose}, 168
169 GNUNET_GETOPT_OPTION_END 169 GNUNET_GETOPT_OPTION_END
170 }; 170 };
171 171
diff --git a/src/gns/gns_api.c b/src/gns/gns_api.c
index 15a59a4bc..26293f4df 100644
--- a/src/gns/gns_api.c
+++ b/src/gns/gns_api.c
@@ -391,7 +391,7 @@ GNUNET_GNS_lookup (struct GNUNET_GNS_Handle *handle,
391 "Trying to lookup `%s' in GNS\n", 391 "Trying to lookup `%s' in GNS\n",
392 name); 392 name);
393 nlen = strlen (name) + 1; 393 nlen = strlen (name) + 1;
394 if (nlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (*lr)) 394 if (nlen >= GNUNET_MAX_MESSAGE_SIZE - sizeof (*lr))
395 { 395 {
396 GNUNET_break (0); 396 GNUNET_break (0);
397 return NULL; 397 return NULL;
diff --git a/src/gns/gnunet-bcd.c b/src/gns/gnunet-bcd.c
index 21471350d..fb7ac10c1 100644
--- a/src/gns/gnunet-bcd.c
+++ b/src/gns/gnunet-bcd.c
@@ -514,10 +514,14 @@ run (void *cls,
514int 514int
515main (int argc, char *const *argv) 515main (int argc, char *const *argv)
516{ 516{
517 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 517 struct GNUNET_GETOPT_CommandLineOption options[] = {
518 {'p', "port", "PORT", 518
519 gettext_noop ("Run HTTP serve on port PORT (default is 8888)"), 1, 519 GNUNET_GETOPT_OPTION_SET_UINT ('p',
520 &GNUNET_GETOPT_set_uint, &port}, 520 "port",
521 "PORT",
522 gettext_noop ("Run HTTP serve on port PORT (default is 8888)"),
523 &port),
524
521 GNUNET_GETOPT_OPTION_END 525 GNUNET_GETOPT_OPTION_END
522 }; 526 };
523 int ret; 527 int ret;
diff --git a/src/gns/gnunet-dns2gns.c b/src/gns/gnunet-dns2gns.c
index 813ecdf8e..c9b4bde9c 100644
--- a/src/gns/gnunet-dns2gns.c
+++ b/src/gns/gnunet-dns2gns.c
@@ -776,22 +776,38 @@ int
776main (int argc, 776main (int argc,
777 char *const *argv) 777 char *const *argv)
778{ 778{
779 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 779 struct GNUNET_GETOPT_CommandLineOption options[] = {
780 {'d', "dns", "IP", 780
781 gettext_noop ("IP of recursive DNS resolver to use (required)"), 1, 781 GNUNET_GETOPT_OPTION_STRING ('d',
782 &GNUNET_GETOPT_set_string, &dns_ip}, 782 "dns",
783 {'f', "fcfs", "NAME", 783 "IP",
784 gettext_noop ("Authoritative FCFS suffix to use (optional); default: fcfs.zkey.eu"), 1, 784 gettext_noop ("IP of recursive DNS resolver to use (required)"),
785 &GNUNET_GETOPT_set_string, &fcfs_suffix}, 785 &dns_ip),
786 {'s', "suffix", "SUFFIX", 786
787 gettext_noop ("Authoritative DNS suffix to use (optional); default: zkey.eu"), 1, 787 GNUNET_GETOPT_OPTION_STRING ('f',
788 &GNUNET_GETOPT_set_string, &dns_suffix}, 788 "fcfs",
789 {'p', "port", "UDPPORT", 789 "NAME",
790 gettext_noop ("UDP port to listen on for inbound DNS requests; default: 2853"), 1, 790 gettext_noop ("Authoritative FCFS suffix to use (optional); default: fcfs.zkey.eu"),
791 &GNUNET_GETOPT_set_uint, &listen_port}, 791 &fcfs_suffix),
792 {'z', "zone", "PUBLICKEY", 792
793 gettext_noop ("Public key of the GNS zone to use (overrides default)"), 1, 793 GNUNET_GETOPT_OPTION_STRING ('s',
794 &GNUNET_GETOPT_set_string, &gns_zone_str}, 794 "suffix",
795 "SUFFIX",
796 gettext_noop ("Authoritative DNS suffix to use (optional); default: zkey.eu"),
797 &dns_suffix),
798
799 GNUNET_GETOPT_OPTION_SET_UINT ('p',
800 "port",
801 "UDPPORT",
802 gettext_noop ("UDP port to listen on for inbound DNS requests; default: 2853"),
803 &listen_port),
804
805 GNUNET_GETOPT_OPTION_STRING ('z',
806 "zone",
807 "PUBLICKEY",
808 gettext_noop ("Public key of the GNS zone to use (overrides default)"),
809 &gns_zone_str),
810
795 GNUNET_GETOPT_OPTION_END 811 GNUNET_GETOPT_OPTION_END
796 }; 812 };
797 int ret; 813 int ret;
diff --git a/src/gns/gnunet-gns-proxy.c b/src/gns/gnunet-gns-proxy.c
index 6eb87a95e..35f42cdec 100644
--- a/src/gns/gnunet-gns-proxy.c
+++ b/src/gns/gnunet-gns-proxy.c
@@ -621,7 +621,7 @@ struct Socks5Request
621/** 621/**
622 * The port the proxy is running on (default 7777) 622 * The port the proxy is running on (default 7777)
623 */ 623 */
624static unsigned long port = GNUNET_GNS_PROXY_PORT; 624static unsigned long long port = GNUNET_GNS_PROXY_PORT;
625 625
626/** 626/**
627 * The CA file (pem) to use for the proxy CA 627 * The CA file (pem) to use for the proxy CA
@@ -865,7 +865,8 @@ check_ssl_certificate (struct Socks5Request *s5r)
865 const char *name; 865 const char *name;
866 866
867 s5r->ssl_checked = GNUNET_YES; 867 s5r->ssl_checked = GNUNET_YES;
868 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "XXXXXX\n"); 868 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
869 "Checking SSL certificate\n");
869 if (CURLE_OK != 870 if (CURLE_OK !=
870 curl_easy_getinfo (s5r->curl, 871 curl_easy_getinfo (s5r->curl,
871 CURLINFO_TLS_SESSION, 872 CURLINFO_TLS_SESSION,
@@ -1882,19 +1883,22 @@ mhd_connection_cb (void *cls,
1882 { 1883 {
1883 if (GNUNET_NETWORK_get_fd (s5r->sock) == sock) 1884 if (GNUNET_NETWORK_get_fd (s5r->sock) == sock)
1884 { 1885 {
1885 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Context set...\n"); 1886 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1887 "Context set...\n");
1888 s5r->ssl_checked = GNUNET_NO;
1886 *con_cls = s5r; 1889 *con_cls = s5r;
1887 break; 1890 break;
1888 } 1891 }
1889 } 1892 }
1890 s5r->ssl_checked = GNUNET_NO;
1891 break; 1893 break;
1892 case MHD_CONNECTION_NOTIFY_CLOSED: 1894 case MHD_CONNECTION_NOTIFY_CLOSED:
1893 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connection closed... cleaning up\n"); 1895 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1896 "Connection closed... cleaning up\n");
1894 s5r = *con_cls; 1897 s5r = *con_cls;
1895 if (NULL == s5r) 1898 if (NULL == s5r)
1896 { 1899 {
1897 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Connection stale!\n"); 1900 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1901 "Connection stale!\n");
1898 return; 1902 return;
1899 } 1903 }
1900 cleanup_s5r (s5r); 1904 cleanup_s5r (s5r);
@@ -3104,7 +3108,7 @@ run_cont ()
3104 return; 3108 return;
3105 } 3109 }
3106 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 3110 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3107 "Proxy listens on port %lu\n", 3111 "Proxy listens on port %llu\n",
3108 port); 3112 port);
3109 3113
3110 /* start MHD daemon for HTTP */ 3114 /* start MHD daemon for HTTP */
@@ -3257,13 +3261,20 @@ run (void *cls,
3257int 3261int
3258main (int argc, char *const *argv) 3262main (int argc, char *const *argv)
3259{ 3263{
3260 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 3264 struct GNUNET_GETOPT_CommandLineOption options[] = {
3261 {'p', "port", NULL, 3265
3262 gettext_noop ("listen on specified port (default: 7777)"), 1, 3266 GNUNET_GETOPT_OPTION_SET_ULONG ('p',
3263 &GNUNET_GETOPT_set_ulong, &port}, 3267 "port",
3264 {'a', "authority", NULL, 3268 NULL,
3265 gettext_noop ("pem file to use as CA"), 1, 3269 gettext_noop ("listen on specified port (default: 7777)"),
3266 &GNUNET_GETOPT_set_string, &cafile_opt}, 3270 &port),
3271
3272 GNUNET_GETOPT_OPTION_STRING ('a',
3273 "authority",
3274 NULL,
3275 gettext_noop ("pem file to use as CA"),
3276 &cafile_opt),
3277
3267 GNUNET_GETOPT_OPTION_END 3278 GNUNET_GETOPT_OPTION_END
3268 }; 3279 };
3269 static const char* page = 3280 static const char* page =
diff --git a/src/gns/gnunet-gns.c b/src/gns/gnunet-gns.c
index a261e008b..c85ddfe81 100644
--- a/src/gns/gnunet-gns.c
+++ b/src/gns/gnunet-gns.c
@@ -420,25 +420,43 @@ int
420main (int argc, 420main (int argc,
421 char *const *argv) 421 char *const *argv)
422{ 422{
423 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 423 struct GNUNET_GETOPT_CommandLineOption options[] = {
424 {'u', "lookup", "NAME", 424
425 gettext_noop ("Lookup a record for the given name"), 1, 425 GNUNET_GETOPT_OPTION_STRING ('u',
426 &GNUNET_GETOPT_set_string, &lookup_name}, 426 "lookup",
427 {'t', "type", "TYPE", 427 "NAME",
428 gettext_noop ("Specify the type of the record to lookup"), 1, 428 gettext_noop ("Lookup a record for the given name"),
429 &GNUNET_GETOPT_set_string, &lookup_type}, 429 &lookup_name),
430 { 'T', "timeout", "DELAY", 430
431 gettext_noop ("Specify timeout for the lookup"), 1, 431 GNUNET_GETOPT_OPTION_STRING ('t',
432 &GNUNET_GETOPT_set_relative_time, &timeout }, 432 "type",
433 {'r', "raw", NULL, 433 "TYPE",
434 gettext_noop ("No unneeded output"), 0, 434 gettext_noop ("Specify the type of the record to lookup"),
435 &GNUNET_GETOPT_set_one, &raw}, 435 &lookup_type),
436 {'p', "public-key", "PKEY", 436
437 gettext_noop ("Specify the public key of the zone to lookup the record in"), 1, 437 GNUNET_GETOPT_OPTION_SET_RELATIVE_TIME ('T',
438 &GNUNET_GETOPT_set_string, &public_key}, 438 "timeout",
439 {'z', "zone", "NAME", 439 "DELAY",
440 gettext_noop ("Specify the name of the ego of the zone to lookup the record in"), 1, 440 gettext_noop ("Specify timeout for the lookup"),
441 &GNUNET_GETOPT_set_string, &zone_ego_name}, 441 &timeout),
442
443 GNUNET_GETOPT_OPTION_SET_ONE ('r',
444 "raw",
445 gettext_noop ("No unneeded output"),
446 &raw),
447
448 GNUNET_GETOPT_OPTION_STRING ('p',
449 "public-key",
450 "PKEY",
451 gettext_noop ("Specify the public key of the zone to lookup the record in"),
452 &public_key),
453
454 GNUNET_GETOPT_OPTION_STRING ('z',
455 "zone",
456 "NAME",
457 gettext_noop ("Specify the name of the ego of the zone to lookup the record in"),
458 &zone_ego_name),
459
442 GNUNET_GETOPT_OPTION_END 460 GNUNET_GETOPT_OPTION_END
443 }; 461 };
444 int ret; 462 int ret;
diff --git a/src/gns/plugin_gnsrecord_gns.c b/src/gns/plugin_gnsrecord_gns.c
index 5faca4578..5d611e19e 100644
--- a/src/gns/plugin_gnsrecord_gns.c
+++ b/src/gns/plugin_gnsrecord_gns.c
@@ -279,9 +279,10 @@ gns_string_to_value (void *cls,
279 } 279 }
280 *data_size = sizeof (struct GNUNET_TUN_GnsVpnRecord) + strlen (s_serv) + 1; 280 *data_size = sizeof (struct GNUNET_TUN_GnsVpnRecord) + strlen (s_serv) + 1;
281 *data = vpn = GNUNET_malloc (*data_size); 281 *data = vpn = GNUNET_malloc (*data_size);
282 if (GNUNET_OK != GNUNET_CRYPTO_eddsa_public_key_from_string ((char*) s_peer, 282 if (GNUNET_OK !=
283 strlen (s_peer), 283 GNUNET_CRYPTO_eddsa_public_key_from_string ((char*) s_peer,
284 &vpn->peer.public_key)) 284 strlen (s_peer),
285 &vpn->peer.public_key))
285 { 286 {
286 GNUNET_free (vpn); 287 GNUNET_free (vpn);
287 *data_size = 0; 288 *data_size = 0;
@@ -362,9 +363,14 @@ gns_string_to_value (void *cls,
362 } 363 }
363 *data_size = sizeof (struct GNUNET_GNSRECORD_ReverseRecord) + strlen (known_by) + 1; 364 *data_size = sizeof (struct GNUNET_GNSRECORD_ReverseRecord) + strlen (known_by) + 1;
364 *data = rev = GNUNET_malloc (*data_size); 365 *data = rev = GNUNET_malloc (*data_size);
365 GNUNET_CRYPTO_ecdsa_public_key_from_string (pkey_str, 366 if (GNUNET_OK !=
366 strlen (pkey_str), 367 GNUNET_CRYPTO_ecdsa_public_key_from_string (pkey_str,
367 &rev->pkey); 368 strlen (pkey_str),
369 &rev->pkey))
370 {
371 GNUNET_free (rev);
372 return GNUNET_SYSERR;
373 }
368 rev->expiration = expiration; 374 rev->expiration = expiration;
369 GNUNET_memcpy (&rev[1], 375 GNUNET_memcpy (&rev[1],
370 known_by, 376 known_by,
diff --git a/src/hello/hello.c b/src/hello/hello.c
index f9b21aa4f..27580275f 100644
--- a/src/hello/hello.c
+++ b/src/hello/hello.c
@@ -206,7 +206,7 @@ GNUNET_HELLO_create (const struct GNUNET_CRYPTO_EddsaPublicKey *public_key,
206 void *addrgen_cls, 206 void *addrgen_cls,
207 int friend_only) 207 int friend_only)
208{ 208{
209 char buffer[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - 256 - 209 char buffer[GNUNET_MAX_MESSAGE_SIZE - 1 - 256 -
210 sizeof (struct GNUNET_HELLO_Message)]; 210 sizeof (struct GNUNET_HELLO_Message)];
211 size_t max; 211 size_t max;
212 size_t used; 212 size_t used;
diff --git a/src/hostlist/gnunet-daemon-hostlist.c b/src/hostlist/gnunet-daemon-hostlist.c
index a83d46e07..9b4790c32 100644
--- a/src/hostlist/gnunet-daemon-hostlist.c
+++ b/src/hostlist/gnunet-daemon-hostlist.c
@@ -369,23 +369,26 @@ run (void *cls,
369int 369int
370main (int argc, char *const *argv) 370main (int argc, char *const *argv)
371{ 371{
372 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 372 struct GNUNET_GETOPT_CommandLineOption options[] = {
373#if HAVE_MHD 373#if HAVE_MHD
374 {'a', "advertise", NULL, 374 GNUNET_GETOPT_OPTION_SET_ONE ('a',
375 gettext_noop ("advertise our hostlist to other peers"), 375 "advertise",
376 GNUNET_NO, &GNUNET_GETOPT_set_one, &advertising}, 376 gettext_noop ("advertise our hostlist to other peers"),
377 &advertising),
377#endif 378#endif
378 {'b', "bootstrap", NULL, 379 GNUNET_GETOPT_OPTION_SET_ONE ('b',
379 gettext_noop 380 "bootstrap",
380 ("bootstrap using hostlists (it is highly recommended that you always use this option)"), 381 gettext_noop ("bootstrap using hostlists (it is highly recommended that you always use this option)"),
381 GNUNET_NO, &GNUNET_GETOPT_set_one, &bootstrapping}, 382 &bootstrapping),
382 {'e', "enable-learning", NULL, 383 GNUNET_GETOPT_OPTION_SET_ONE ('e',
383 gettext_noop ("enable learning about hostlist servers from other peers"), 384 "enable-learning",
384 GNUNET_NO, &GNUNET_GETOPT_set_one, &learning}, 385 gettext_noop ("enable learning about hostlist servers from other peers"),
386 &learning),
385#if HAVE_MHD 387#if HAVE_MHD
386 {'p', "provide-hostlist", NULL, 388 GNUNET_GETOPT_OPTION_SET_ONE ('p',
387 gettext_noop ("provide a hostlist server"), 389 "provide-hostlist",
388 GNUNET_NO, &GNUNET_GETOPT_set_one, &provide_hostlist}, 390 gettext_noop ("provide a hostlist server"),
391 &provide_hostlist),
389#endif 392#endif
390 GNUNET_GETOPT_OPTION_END 393 GNUNET_GETOPT_OPTION_END
391 }; 394 };
diff --git a/src/hostlist/gnunet-daemon-hostlist_client.c b/src/hostlist/gnunet-daemon-hostlist_client.c
index a973fcc28..207cc4a81 100644
--- a/src/hostlist/gnunet-daemon-hostlist_client.c
+++ b/src/hostlist/gnunet-daemon-hostlist_client.c
@@ -350,7 +350,7 @@ callback_download (void *ptr,
350 size_t nmemb, 350 size_t nmemb,
351 void *ctx) 351 void *ctx)
352{ 352{
353 static char download_buffer[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1]; 353 static char download_buffer[GNUNET_MAX_MESSAGE_SIZE - 1];
354 const char *cbuf = ptr; 354 const char *cbuf = ptr;
355 const struct GNUNET_MessageHeader *msg; 355 const struct GNUNET_MessageHeader *msg;
356 struct HelloOffer *ho; 356 struct HelloOffer *ho;
@@ -373,7 +373,7 @@ callback_download (void *ptr,
373 left = total; 373 left = total;
374 while ((left > 0) || (download_pos > 0)) 374 while ((left > 0) || (download_pos > 0))
375 { 375 {
376 cpy = GNUNET_MIN (left, GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - download_pos); 376 cpy = GNUNET_MIN (left, GNUNET_MAX_MESSAGE_SIZE - 1 - download_pos);
377 GNUNET_memcpy (&download_buffer[download_pos], cbuf, cpy); 377 GNUNET_memcpy (&download_buffer[download_pos], cbuf, cpy);
378 cbuf += cpy; 378 cbuf += cpy;
379 download_pos += cpy; 379 download_pos += cpy;
@@ -1042,7 +1042,7 @@ download_hostlist ()
1042#if 0 1042#if 0
1043 CURL_EASY_SETOPT (curl, CURLOPT_VERBOSE, 1); 1043 CURL_EASY_SETOPT (curl, CURLOPT_VERBOSE, 1);
1044#endif 1044#endif
1045 CURL_EASY_SETOPT (curl, CURLOPT_BUFFERSIZE, GNUNET_SERVER_MAX_MESSAGE_SIZE); 1045 CURL_EASY_SETOPT (curl, CURLOPT_BUFFERSIZE, GNUNET_MAX_MESSAGE_SIZE);
1046 if (0 == strncmp (current_url, "http", 4)) 1046 if (0 == strncmp (current_url, "http", 4))
1047 CURL_EASY_SETOPT (curl, CURLOPT_USERAGENT, "GNUnet"); 1047 CURL_EASY_SETOPT (curl, CURLOPT_USERAGENT, "GNUnet");
1048 CURL_EASY_SETOPT (curl, CURLOPT_CONNECTTIMEOUT, 60L); 1048 CURL_EASY_SETOPT (curl, CURLOPT_CONNECTTIMEOUT, 60L);
diff --git a/src/hostlist/gnunet-daemon-hostlist_server.c b/src/hostlist/gnunet-daemon-hostlist_server.c
index 48c1a5622..3df6f1ef8 100644
--- a/src/hostlist/gnunet-daemon-hostlist_server.c
+++ b/src/hostlist/gnunet-daemon-hostlist_server.c
@@ -489,7 +489,7 @@ connect_handler (void *cls,
489 return NULL; 489 return NULL;
490 size = strlen (hostlist_uri) + 1; 490 size = strlen (hostlist_uri) + 1;
491 if (size + sizeof (struct GNUNET_MessageHeader) >= 491 if (size + sizeof (struct GNUNET_MessageHeader) >=
492 GNUNET_SERVER_MAX_MESSAGE_SIZE) 492 GNUNET_MAX_MESSAGE_SIZE)
493 { 493 {
494 GNUNET_break (0); 494 GNUNET_break (0);
495 return NULL; 495 return NULL;
diff --git a/src/identity-provider/gnunet-identity-token.c b/src/identity-provider/gnunet-identity-token.c
index 4bb3292be..906899ea7 100644
--- a/src/identity-provider/gnunet-identity-token.c
+++ b/src/identity-provider/gnunet-identity-token.c
@@ -158,13 +158,18 @@ run (void *cls,
158int 158int
159main(int argc, char *const argv[]) 159main(int argc, char *const argv[])
160{ 160{
161 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 161 struct GNUNET_GETOPT_CommandLineOption options[] = {
162 {'t', "token", NULL, 162
163 gettext_noop ("GNUid token"), 1, 163 GNUNET_GETOPT_OPTION_STRING ('t',
164 &GNUNET_GETOPT_set_string, &token}, 164 "token",
165 {'p', "print", NULL, 165 NULL,
166 gettext_noop ("Print token contents"), 0, 166 gettext_noop ("GNUid token"),
167 &GNUNET_GETOPT_set_one, &print_token}, 167 &token),
168
169 GNUNET_GETOPT_OPTION_SET_ONE ('p',
170 "print",
171 gettext_noop ("Print token contents"),
172 &print_token),
168 173
169 GNUNET_GETOPT_OPTION_END 174 GNUNET_GETOPT_OPTION_END
170 }; 175 };
diff --git a/src/identity-provider/identity_provider_api.c b/src/identity-provider/identity_provider_api.c
index 32c3cb703..845d1f753 100644
--- a/src/identity-provider/identity_provider_api.c
+++ b/src/identity-provider/identity_provider_api.c
@@ -440,7 +440,7 @@ GNUNET_IDENTITY_PROVIDER_issue_token (struct GNUNET_IDENTITY_PROVIDER_Handle *id
440 size_t slen; 440 size_t slen;
441 441
442 slen = strlen (scopes) + 1; 442 slen = strlen (scopes) + 1;
443 if (slen >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct IssueMessage)) 443 if (slen >= GNUNET_MAX_MESSAGE_SIZE - sizeof (struct IssueMessage))
444 { 444 {
445 GNUNET_break (0); 445 GNUNET_break (0);
446 return NULL; 446 return NULL;
@@ -493,7 +493,7 @@ GNUNET_IDENTITY_PROVIDER_exchange_ticket (struct GNUNET_IDENTITY_PROVIDER_Handle
493 ticket_str = GNUNET_IDENTITY_PROVIDER_ticket_to_string (ticket); 493 ticket_str = GNUNET_IDENTITY_PROVIDER_ticket_to_string (ticket);
494 494
495 slen = strlen (ticket_str) + 1; 495 slen = strlen (ticket_str) + 1;
496 if (slen >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct ExchangeMessage)) 496 if (slen >= GNUNET_MAX_MESSAGE_SIZE - sizeof (struct ExchangeMessage))
497 { 497 {
498 GNUNET_free (ticket_str); 498 GNUNET_free (ticket_str);
499 GNUNET_break (0); 499 GNUNET_break (0);
diff --git a/src/identity/gnunet-identity.c b/src/identity/gnunet-identity.c
index 8c8485249..5c457ef5d 100644
--- a/src/identity/gnunet-identity.c
+++ b/src/identity/gnunet-identity.c
@@ -349,25 +349,41 @@ run (void *cls,
349int 349int
350main (int argc, char *const *argv) 350main (int argc, char *const *argv)
351{ 351{
352 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 352 struct GNUNET_GETOPT_CommandLineOption options[] = {
353 {'C', "create", "NAME", 353 GNUNET_GETOPT_OPTION_STRING ('C',
354 gettext_noop ("create ego NAME"), 354 "create",
355 1, &GNUNET_GETOPT_set_string, &create_ego}, 355 "NAME",
356 {'D', "delete", "NAME", 356 gettext_noop ("create ego NAME"),
357 gettext_noop ("delete ego NAME "), 357 &create_ego),
358 1, &GNUNET_GETOPT_set_string, &delete_ego}, 358
359 {'d', "display", NULL, 359 GNUNET_GETOPT_OPTION_STRING ('D',
360 gettext_noop ("display all egos"), 360 "delete",
361 0, &GNUNET_GETOPT_set_one, &list}, 361 "NAME",
362 {'e', "ego", "NAME", 362 gettext_noop ("delete ego NAME "),
363 gettext_noop ("set default identity to EGO for a subsystem SUBSYSTEM (use together with -s)"), 363 &delete_ego),
364 1, &GNUNET_GETOPT_set_string, &set_ego}, 364
365 {'m', "monitor", NULL, 365 GNUNET_GETOPT_OPTION_SET_ONE ('d',
366 gettext_noop ("run in monitor mode egos"), 366 "display",
367 0, &GNUNET_GETOPT_set_one, &monitor}, 367 gettext_noop ("display all egos"),
368 {'s', "set", "SUBSYSTEM", 368 &list),
369 gettext_noop ("set default identity to EGO for a subsystem SUBSYSTEM (use together with -e)"), 369
370 1, &GNUNET_GETOPT_set_string, &set_subsystem}, 370 GNUNET_GETOPT_OPTION_STRING ('e',
371 "ego",
372 "NAME",
373 gettext_noop ("set default identity to EGO for a subsystem SUBSYSTEM (use together with -s)"),
374 &set_ego),
375
376 GNUNET_GETOPT_OPTION_SET_ONE ('m',
377 "monitor",
378 gettext_noop ("run in monitor mode egos"),
379 &monitor),
380
381 GNUNET_GETOPT_OPTION_STRING ('s',
382 "set",
383 "SUBSYSTEM",
384 gettext_noop ("set default identity to EGO for a subsystem SUBSYSTEM (use together with -e)"),
385 &set_subsystem),
386
371 GNUNET_GETOPT_OPTION_END 387 GNUNET_GETOPT_OPTION_END
372 }; 388 };
373 int res; 389 int res;
diff --git a/src/identity/identity_api.c b/src/identity/identity_api.c
index 905b3fd8b..1601ae2fd 100644
--- a/src/identity/identity_api.c
+++ b/src/identity/identity_api.c
@@ -671,7 +671,7 @@ GNUNET_IDENTITY_get (struct GNUNET_IDENTITY_Handle *h,
671 if (NULL == h->mq) 671 if (NULL == h->mq)
672 return NULL; 672 return NULL;
673 slen = strlen (service_name) + 1; 673 slen = strlen (service_name) + 1;
674 if (slen >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct GetDefaultMessage)) 674 if (slen >= GNUNET_MAX_MESSAGE_SIZE - sizeof (struct GetDefaultMessage))
675 { 675 {
676 GNUNET_break (0); 676 GNUNET_break (0);
677 return NULL; 677 return NULL;
@@ -722,7 +722,7 @@ GNUNET_IDENTITY_set (struct GNUNET_IDENTITY_Handle *h,
722 if (NULL == h->mq) 722 if (NULL == h->mq)
723 return NULL; 723 return NULL;
724 slen = strlen (service_name) + 1; 724 slen = strlen (service_name) + 1;
725 if (slen >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct SetDefaultMessage)) 725 if (slen >= GNUNET_MAX_MESSAGE_SIZE - sizeof (struct SetDefaultMessage))
726 { 726 {
727 GNUNET_break (0); 727 GNUNET_break (0);
728 return NULL; 728 return NULL;
@@ -773,7 +773,7 @@ GNUNET_IDENTITY_create (struct GNUNET_IDENTITY_Handle *h,
773 if (NULL == h->mq) 773 if (NULL == h->mq)
774 return NULL; 774 return NULL;
775 slen = strlen (name) + 1; 775 slen = strlen (name) + 1;
776 if (slen >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct CreateRequestMessage)) 776 if (slen >= GNUNET_MAX_MESSAGE_SIZE - sizeof (struct CreateRequestMessage))
777 { 777 {
778 GNUNET_break (0); 778 GNUNET_break (0);
779 return NULL; 779 return NULL;
@@ -830,9 +830,9 @@ GNUNET_IDENTITY_rename (struct GNUNET_IDENTITY_Handle *h,
830 return NULL; 830 return NULL;
831 slen_old = strlen (old_name) + 1; 831 slen_old = strlen (old_name) + 1;
832 slen_new = strlen (new_name) + 1; 832 slen_new = strlen (new_name) + 1;
833 if ( (slen_old >= GNUNET_SERVER_MAX_MESSAGE_SIZE) || 833 if ( (slen_old >= GNUNET_MAX_MESSAGE_SIZE) ||
834 (slen_new >= GNUNET_SERVER_MAX_MESSAGE_SIZE) || 834 (slen_new >= GNUNET_MAX_MESSAGE_SIZE) ||
835 (slen_old + slen_new >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct RenameMessage)) ) 835 (slen_old + slen_new >= GNUNET_MAX_MESSAGE_SIZE - sizeof (struct RenameMessage)) )
836 { 836 {
837 GNUNET_break (0); 837 GNUNET_break (0);
838 return NULL; 838 return NULL;
@@ -885,7 +885,7 @@ GNUNET_IDENTITY_delete (struct GNUNET_IDENTITY_Handle *h,
885 if (NULL == h->mq) 885 if (NULL == h->mq)
886 return NULL; 886 return NULL;
887 slen = strlen (name) + 1; 887 slen = strlen (name) + 1;
888 if (slen >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct DeleteMessage)) 888 if (slen >= GNUNET_MAX_MESSAGE_SIZE - sizeof (struct DeleteMessage))
889 { 889 {
890 GNUNET_break (0); 890 GNUNET_break (0);
891 return NULL; 891 return NULL;
diff --git a/src/include/Makefile.am b/src/include/Makefile.am
index 4fb2577fd..b745da125 100644
--- a/src/include/Makefile.am
+++ b/src/include/Makefile.am
@@ -38,7 +38,6 @@ gnunetinclude_HEADERS = \
38 gnunet_common.h \ 38 gnunet_common.h \
39 gnunet_constants.h \ 39 gnunet_constants.h \
40 gnunet_configuration_lib.h \ 40 gnunet_configuration_lib.h \
41 gnunet_connection_lib.h \
42 gnunet_consensus_service.h \ 41 gnunet_consensus_service.h \
43 gnunet_container_lib.h \ 42 gnunet_container_lib.h \
44 gnunet_conversation_service.h \ 43 gnunet_conversation_service.h \
@@ -107,7 +106,6 @@ gnunetinclude_HEADERS = \
107 gnunet_scalarproduct_service.h \ 106 gnunet_scalarproduct_service.h \
108 gnunet_scheduler_lib.h \ 107 gnunet_scheduler_lib.h \
109 gnunet_secretsharing_service.h \ 108 gnunet_secretsharing_service.h \
110 gnunet_server_lib.h \
111 gnunet_service_lib.h \ 109 gnunet_service_lib.h \
112 gnunet_set_service.h \ 110 gnunet_set_service.h \
113 gnunet_signal_lib.h \ 111 gnunet_signal_lib.h \
diff --git a/src/include/gnunet_arm_service.h b/src/include/gnunet_arm_service.h
index 7fb14d3ac..f8d71bd8b 100644
--- a/src/include/gnunet_arm_service.h
+++ b/src/include/gnunet_arm_service.h
@@ -62,25 +62,9 @@ enum GNUNET_ARM_RequestStatus
62 GNUNET_ARM_REQUEST_SENT_OK = 0, 62 GNUNET_ARM_REQUEST_SENT_OK = 0,
63 63
64 /** 64 /**
65 * Misconfiguration (can't connect to the ARM service).
66 */
67 GNUNET_ARM_REQUEST_CONFIGURATION_ERROR = 1,
68
69 /**
70 * We disconnected from ARM, and request was not sent. 65 * We disconnected from ARM, and request was not sent.
71 */ 66 */
72 GNUNET_ARM_REQUEST_DISCONNECTED = 2, 67 GNUNET_ARM_REQUEST_DISCONNECTED = 2
73
74 /**
75 * ARM API is busy (probably trying to connect to ARM),
76 * and request was not sent. Try again later.
77 */
78 GNUNET_ARM_REQUEST_BUSY = 3,
79
80 /**
81 * Request time ran out before we had a chance to send it.
82 */
83 GNUNET_ARM_REQUEST_TIMEOUT = 5
84 68
85}; 69};
86 70
diff --git a/src/include/gnunet_bandwidth_lib.h b/src/include/gnunet_bandwidth_lib.h
index 178ddaaac..967d50dea 100644
--- a/src/include/gnunet_bandwidth_lib.h
+++ b/src/include/gnunet_bandwidth_lib.h
@@ -133,7 +133,7 @@ struct GNUNET_BANDWIDTH_Tracker
133 /** 133 /**
134 * Maximum number of seconds over which bandwidth may "accumulate". 134 * Maximum number of seconds over which bandwidth may "accumulate".
135 * Note that additionally, we also always allow at least 135 * Note that additionally, we also always allow at least
136 * #GNUNET_SERVER_MAX_MESSAGE_SIZE to accumulate. 136 * #GNUNET_MAX_MESSAGE_SIZE to accumulate.
137 */ 137 */
138 uint32_t max_carry_s__; 138 uint32_t max_carry_s__;
139}; 139};
@@ -214,10 +214,10 @@ GNUNET_BANDWIDTH_value_max (struct GNUNET_BANDWIDTH_Value32NBO b1,
214/** 214/**
215 * Initialize bandwidth tracker. Note that in addition to the 215 * Initialize bandwidth tracker. Note that in addition to the
216 * 'max_carry_s' limit, we also always allow at least 216 * 'max_carry_s' limit, we also always allow at least
217 * #GNUNET_SERVER_MAX_MESSAGE_SIZE to accumulate. So if the 217 * #GNUNET_MAX_MESSAGE_SIZE to accumulate. So if the
218 * bytes-per-second limit is so small that within 'max_carry_s' not 218 * bytes-per-second limit is so small that within 'max_carry_s' not
219 * even #GNUNET_SERVER_MAX_MESSAGE_SIZE is allowed to accumulate, it is 219 * even #GNUNET_MAX_MESSAGE_SIZE is allowed to accumulate, it is
220 * ignored and replaced by #GNUNET_SERVER_MAX_MESSAGE_SIZE (which is in 220 * ignored and replaced by #GNUNET_MAX_MESSAGE_SIZE (which is in
221 * bytes). 221 * bytes).
222 * 222 *
223 * @param av tracker to initialize 223 * @param av tracker to initialize
@@ -238,10 +238,10 @@ GNUNET_BANDWIDTH_tracker_init (struct GNUNET_BANDWIDTH_Tracker *av,
238/** 238/**
239 * Initialize bandwidth tracker. Note that in addition to the 239 * Initialize bandwidth tracker. Note that in addition to the
240 * 'max_carry_s' limit, we also always allow at least 240 * 'max_carry_s' limit, we also always allow at least
241 * GNUNET_SERVER_MAX_MESSAGE_SIZE to accumulate. So if the 241 * GNUNET_MAX_MESSAGE_SIZE to accumulate. So if the
242 * bytes-per-second limit is so small that within 'max_carry_s' not 242 * bytes-per-second limit is so small that within 'max_carry_s' not
243 * even GNUNET_SERVER_MAX_MESSAGE_SIZE is allowed to accumulate, it is 243 * even GNUNET_MAX_MESSAGE_SIZE is allowed to accumulate, it is
244 * ignored and replaced by GNUNET_SERVER_MAX_MESSAGE_SIZE (which is in 244 * ignored and replaced by GNUNET_MAX_MESSAGE_SIZE (which is in
245 * bytes). 245 * bytes).
246 * 246 *
247 * @param av tracker to initialize 247 * @param av tracker to initialize
diff --git a/src/include/gnunet_cadet_service.h b/src/include/gnunet_cadet_service.h
index fd838df8d..f76f17a51 100644
--- a/src/include/gnunet_cadet_service.h
+++ b/src/include/gnunet_cadet_service.h
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 Copyright (C) 2009-2014 GNUnet e.V. 3 Copyright (C) 2009-2017 GNUnet e.V.
4 4
5 GNUnet is free software; you can redistribute it and/or modify 5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published 6 it under the terms of the GNU General Public License as published
@@ -49,7 +49,7 @@ extern "C"
49/** 49/**
50 * Version number of GNUnet-cadet API. 50 * Version number of GNUnet-cadet API.
51 */ 51 */
52#define GNUNET_CADET_VERSION 0x00000004 52#define GNUNET_CADET_VERSION 0x00000005
53 53
54 54
55/** 55/**
@@ -69,6 +69,33 @@ struct GNUNET_CADET_Port;
69 69
70 70
71/** 71/**
72 * Hash uniquely identifying a connection below a tunnel.
73 */
74struct GNUNET_CADET_ConnectionTunnelIdentifier
75{
76 struct GNUNET_ShortHashCode connection_of_tunnel;
77};
78
79
80/**
81 * Number identifying a CADET channel within a tunnel.
82 */
83struct GNUNET_CADET_ChannelTunnelNumber
84{
85 /**
86 * Which number does this channel have that uniquely identfies
87 * it within its tunnel, in network byte order.
88 *
89 * Given two peers, both may initiate channels over the same tunnel.
90 * The @e cn must be greater or equal to 0x80000000 (high-bit set)
91 * for tunnels initiated with the peer that has the larger peer
92 * identity as compared using #GNUNET_CRYPTO_cmp_peer_identity().
93 */
94 uint32_t cn GNUNET_PACKED;
95};
96
97
98/**
72 * Channel options. Second line indicates filed in the 99 * Channel options. Second line indicates filed in the
73 * CadetChannelInfo union carrying the answer. 100 * CadetChannelInfo union carrying the answer.
74 */ 101 */
@@ -108,118 +135,67 @@ enum GNUNET_CADET_ChannelOption
108 135
109 136
110/** 137/**
111 * Functions with this signature are called whenever a message is 138 * Method called whenever a peer connects to a port in MQ-based CADET.
112 * received.
113 *
114 * Each time the function must call #GNUNET_CADET_receive_done on the channel
115 * in order to receive the next message. This doesn't need to be immediate:
116 * can be delayed if some processing is done on the message.
117 * 139 *
118 * @param cls Closure (set from #GNUNET_CADET_connect). 140 * @param cls Closure from #GNUNET_CADET_open_port.
119 * @param channel Connection to the other end. 141 * @param channel New handle to the channel.
120 * @param channel_ctx Place to store local state associated with the channel. 142 * @param source Peer that started this channel.
121 * @param message The actual message. 143 * @return Closure for the incoming @a channel. It's given to:
122 * @return #GNUNET_OK to keep the channel open, 144 * - The #GNUNET_CADET_DisconnectEventHandler (given to
123 * #GNUNET_SYSERR to close it (signal serious error). 145 * #GNUNET_CADET_open_port) when the channel dies.
124 */ 146 * - Each the #GNUNET_MQ_MessageCallback handlers for each message
125typedef int 147 * received on the @a channel.
126(*GNUNET_CADET_MessageCallback) (void *cls,
127 struct GNUNET_CADET_Channel *channel,
128 void **channel_ctx,
129 const struct GNUNET_MessageHeader *message);
130
131
132/**
133 * Message handler. Each struct specifies how to handle on particular
134 * type of message received.
135 */ 148 */
136struct GNUNET_CADET_MessageHandler 149typedef void *
137{ 150(*GNUNET_CADET_ConnectEventHandler) (void *cls,
138 /** 151 struct GNUNET_CADET_Channel *channel,
139 * Function to call for messages of type @e type. 152 const struct GNUNET_PeerIdentity *source);
140 */
141 GNUNET_CADET_MessageCallback callback;
142
143 /**
144 * Type of the message this handler covers.
145 */
146 uint16_t type;
147
148 /**
149 * Expected size of messages of this type. Use 0 for variable-size.
150 * If non-zero, messages of the given type will be discarded if they
151 * do not have the right size.
152 */
153 uint16_t expected_size;
154};
155 153
156 154
157/** 155/**
158 * Method called whenever another peer has added us to a channel 156 * Function called whenever an MQ-channel is destroyed, even if the destruction
159 * the other peer initiated. 157 * was requested by #GNUNET_CADET_channel_destroy.
160 * Only called (once) upon reception of data with a message type which was 158 * It must NOT call #GNUNET_CADET_channel_destroy on the channel.
161 * subscribed to in #GNUNET_CADET_connect.
162 *
163 * A call to #GNUNET_CADET_channel_destroy causes te channel to be ignored. In
164 * this case the handler MUST return NULL.
165 * 159 *
166 * @param cls closure 160 * It should clean up any associated state, including cancelling any pending
167 * @param channel new handle to the channel 161 * transmission on this channel.
168 * @param initiator peer that started the channel
169 * @param port Port this channel is for.
170 * @param options CadetOption flag field, with all active option bits set to 1.
171 * 162 *
172 * @return initial channel context for the channel 163 * @param cls Channel closure.
173 * (can be NULL -- that's not an error) 164 * @param channel Connection to the other end (henceforth invalid).
174 */ 165 */
175typedef void * 166typedef void
176(GNUNET_CADET_InboundChannelNotificationHandler) (void *cls, 167(*GNUNET_CADET_DisconnectEventHandler) (void *cls,
177 struct GNUNET_CADET_Channel *channel, 168 const struct GNUNET_CADET_Channel *channel);
178 const struct GNUNET_PeerIdentity *initiator,
179 const struct GNUNET_HashCode *port,
180 enum GNUNET_CADET_ChannelOption options);
181 169
182 170
183/** 171/**
184 * Function called whenever a channel is destroyed. Should clean up 172 * Function called whenever an MQ-channel's transmission window size changes.
185 * any associated state, including cancelling any pending transmission on this
186 * channel.
187 * 173 *
188 * It must NOT call #GNUNET_CADET_channel_destroy on the channel. 174 * The first callback in an outgoing channel will be with a non-zero value
175 * and will mean the channel is connected to the destination.
176 *
177 * For an incoming channel it will be called immediately after the
178 * #GNUNET_CADET_ConnectEventHandler, also with a non-zero value.
189 * 179 *
190 * @param cls closure (set from #GNUNET_CADET_connect) 180 * @param cls Channel closure.
191 * @param channel connection to the other end (henceforth invalid) 181 * @param channel Connection to the other end --- FIXME: drop?
192 * @param channel_ctx place where local state associated 182 * @param window_size New window size. If the is more messages than buffer size
193 * with the channel is stored 183 * this value will be negative. -- FIXME: make unsigned, we never call negative?
194 */ 184 */
195typedef void 185typedef void
196(GNUNET_CADET_ChannelEndHandler) (void *cls, 186(*GNUNET_CADET_WindowSizeEventHandler) (void *cls,
197 const struct GNUNET_CADET_Channel *channel, 187 const struct GNUNET_CADET_Channel *channel,
198 void *channel_ctx); 188 int window_size);
199 189
200 190
201/** 191/**
202 * Connect to the cadet service. 192 * Connect to the MQ-based cadet service.
203 * 193 *
204 * @param cfg Configuration to use. 194 * @param cfg Configuration to use.
205 * @param cls Closure for the various callbacks that follow (including 195 * @return Handle to the cadet service NULL on error.
206 * handlers in the handlers array).
207 * @param cleaner Function called when a channel is destroyed.
208 * It is called immediately if #GNUNET_CADET_channel_destroy
209 * is called on the channel.
210 * @param handlers Callbacks for messages we care about, NULL-terminated. Each
211 * one must call #GNUNET_CADET_receive_done on the channel to
212 * receive the next message. Messages of a type that is not
213 * in the handlers array are ignored if received.
214 *
215 * @return handle to the cadet service NULL on error
216 * (in this case, init is never called)
217 */ 196 */
218struct GNUNET_CADET_Handle * 197struct GNUNET_CADET_Handle *
219GNUNET_CADET_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, 198GNUNET_CADET_connect (const struct GNUNET_CONFIGURATION_Handle *cfg);
220 void *cls,
221 GNUNET_CADET_ChannelEndHandler cleaner,
222 const struct GNUNET_CADET_MessageHandler *handlers);
223 199
224 200
225/** 201/**
@@ -233,21 +209,29 @@ GNUNET_CADET_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
233void 209void
234GNUNET_CADET_disconnect (struct GNUNET_CADET_Handle *handle); 210GNUNET_CADET_disconnect (struct GNUNET_CADET_Handle *handle);
235 211
212
236/** 213/**
237 * Open a port to receive incomming channels. 214 * Open a port to receive incomming MQ-based channels.
238 * 215 *
239 * @param h CADET handle. 216 * @param h CADET handle.
240 * @param port Hash representing the port number. 217 * @param port Hash identifying the port.
241 * @param new_channel Function called when an channel is received. 218 * @param connects Function called when an incoming channel is connected.
242 * @param new_channel_cls Closure for @a new_channel. 219 * @param connects_cls Closure for the @a connects handler.
243 * 220 * @param window_changes Function called when the transmit window size changes.
221 * Can be NULL.
222 * @param disconnects Function called when a channel is disconnected.
223 * @param handlers Callbacks for messages we care about, NULL-terminated.
244 * @return Port handle. 224 * @return Port handle.
245 */ 225 */
246struct GNUNET_CADET_Port * 226struct GNUNET_CADET_Port *
247GNUNET_CADET_open_port (struct GNUNET_CADET_Handle *h, 227GNUNET_CADET_open_port (struct GNUNET_CADET_Handle *h,
248 const struct GNUNET_HashCode *port, 228 const struct GNUNET_HashCode *port,
249 GNUNET_CADET_InboundChannelNotificationHandler new_channel, 229 GNUNET_CADET_ConnectEventHandler connects,
250 void *new_channel_cls); 230 void *connects_cls,
231 GNUNET_CADET_WindowSizeEventHandler window_changes,
232 GNUNET_CADET_DisconnectEventHandler disconnects,
233 const struct GNUNET_MQ_MessageHandler *handlers);
234
251 235
252/** 236/**
253 * Close a port opened with @a GNUNET_CADET_open_port. 237 * Close a port opened with @a GNUNET_CADET_open_port.
@@ -258,27 +242,38 @@ GNUNET_CADET_open_port (struct GNUNET_CADET_Handle *h,
258void 242void
259GNUNET_CADET_close_port (struct GNUNET_CADET_Port *p); 243GNUNET_CADET_close_port (struct GNUNET_CADET_Port *p);
260 244
245
261/** 246/**
262 * Create a new channel towards a remote peer. 247 * Create a new channel towards a remote peer.
263 * 248 *
264 * If the destination port is not open by any peer or the destination peer 249 * If the destination port is not open by any peer or the destination peer
265 * does not accept the channel, #GNUNET_CADET_ChannelEndHandler will be called 250 * does not accept the channel, @a disconnects will be called
266 * for this channel. 251 * for this channel.
267 * 252 *
268 * @param h cadet handle 253 * @param h CADET handle.
269 * @param channel_ctx client's channel context to associate with the channel 254 * @param channel_cls Closure for the channel. It's given to:
270 * @param peer peer identity the channel should go to 255 * - The management handler @a window_changes.
271 * @param port Port hash (port number). 256 * - The disconnect handler @a disconnects
257 * - Each message type callback in @a handlers
258 * @param destination Peer identity the channel should go to.
259 * @param port Identification of the destination port.
272 * @param options CadetOption flag field, with all desired option bits set to 1. 260 * @param options CadetOption flag field, with all desired option bits set to 1.
273 * 261 * @param window_changes Function called when the transmit window size changes.
274 * @return handle to the channel 262 * Can be NULL if this data is of no interest.
263 * TODO Not yet implemented.
264 * @param disconnects Function called when the channel is disconnected.
265 * @param handlers Callbacks for messages we care about, NULL-terminated.
266 * @return Handle to the channel.
275 */ 267 */
276struct GNUNET_CADET_Channel * 268struct GNUNET_CADET_Channel *
277GNUNET_CADET_channel_create (struct GNUNET_CADET_Handle *h, 269GNUNET_CADET_channel_create (struct GNUNET_CADET_Handle *h,
278 void *channel_ctx, 270 void *channel_cls,
279 const struct GNUNET_PeerIdentity *peer, 271 const struct GNUNET_PeerIdentity *destination,
280 const struct GNUNET_HashCode *port, 272 const struct GNUNET_HashCode *port,
281 enum GNUNET_CADET_ChannelOption options); 273 enum GNUNET_CADET_ChannelOption options,
274 GNUNET_CADET_WindowSizeEventHandler window_changes,
275 GNUNET_CADET_DisconnectEventHandler disconnects,
276 const struct GNUNET_MQ_MessageHandler *handlers);
282 277
283 278
284/** 279/**
@@ -295,6 +290,52 @@ GNUNET_CADET_channel_destroy (struct GNUNET_CADET_Channel *channel);
295 290
296 291
297/** 292/**
293 * Obtain the message queue for a connected channel.
294 *
295 * @param channel The channel handle from which to get the MQ.
296 * @return The message queue of the channel.
297 */
298struct GNUNET_MQ_Handle *
299GNUNET_CADET_get_mq (const struct GNUNET_CADET_Channel *channel);
300
301
302/**
303 * Indicate readiness to receive the next message on a channel.
304 *
305 * Should only be called once per handler called.
306 *
307 * @param channel Channel that will be allowed to call another handler.
308 */
309void
310GNUNET_CADET_receive_done (struct GNUNET_CADET_Channel *channel);
311
312
313/******************************************************************************/
314/******************** MONITORING /DEBUG API *************************/
315/******************************************************************************/
316/* The following calls are not useful for normal CADET operation, but for */
317/* debug and monitoring of the cadet state. They can be safely ignored. */
318/* The API can change at any point without notice. */
319/* Please contact the developer if you consider any of this calls useful for */
320/* normal cadet applications. */
321/******************************************************************************/
322
323
324/**
325 * Transitional function to convert an unsigned int port to a hash value.
326 * WARNING: local static value returned, NOT reentrant!
327 * WARNING: do not use this function for new code!
328 *
329 * @param port Numerical port (unsigned int format).
330 *
331 * @return A GNUNET_HashCode usable for the new CADET API.
332 */
333const struct GNUNET_HashCode *
334GC_u2h (uint32_t port);
335
336
337
338/**
298 * Struct to retrieve info about a channel. 339 * Struct to retrieve info about a channel.
299 */ 340 */
300union GNUNET_CADET_ChannelInfo 341union GNUNET_CADET_ChannelInfo
@@ -327,76 +368,6 @@ GNUNET_CADET_channel_get_info (struct GNUNET_CADET_Channel *channel,
327 368
328 369
329/** 370/**
330 * Handle for a transmission request.
331 */
332struct GNUNET_CADET_TransmitHandle;
333
334
335/**
336 * Ask the cadet to call @a notify once it is ready to transmit the
337 * given number of bytes to the specified channel.
338 * Only one call can be active at any time, to issue another request,
339 * wait for the callback or cancel the current request.
340 *
341 * @param channel channel to use for transmission
342 * @param cork is corking allowed for this transmission?
343 * @param maxdelay how long can the message wait?
344 * @param notify_size how many bytes of buffer space does notify want?
345 * @param notify function to call when buffer space is available;
346 * will be called with NULL on timeout or if the overall queue
347 * for this peer is larger than queue_size and this is currently
348 * the message with the lowest priority
349 * @param notify_cls closure for @a notify
350 * @return non-NULL if the notify callback was queued,
351 * NULL if we can not even queue the request (insufficient
352 * memory); if NULL is returned, @a notify will NOT be called.
353 */
354struct GNUNET_CADET_TransmitHandle *
355GNUNET_CADET_notify_transmit_ready (struct GNUNET_CADET_Channel *channel,
356 int cork,
357 struct GNUNET_TIME_Relative maxdelay,
358 size_t notify_size,
359 GNUNET_CONNECTION_TransmitReadyNotify notify,
360 void *notify_cls);
361
362
363/**
364 * Cancel the specified transmission-ready notification.
365 *
366 * #DEPRECATED
367 * Since soon we will send immediately with mq (via request_data),
368 * there will be time or need to cancel a "pending" transmission.
369 *
370 * @param th handle that was returned by "notify_transmit_ready".
371 */
372void
373GNUNET_CADET_notify_transmit_ready_cancel (struct GNUNET_CADET_TransmitHandle *th);
374
375
376/**
377 * Indicate readiness to receive the next message on a channel.
378 *
379 * Should only be called once per handler called.
380 *
381 * @param channel Channel that will be allowed to call another handler.
382 */
383void
384GNUNET_CADET_receive_done (struct GNUNET_CADET_Channel *channel);
385
386
387
388/******************************************************************************/
389/******************** MONITORING /DEBUG API *************************/
390/******************************************************************************/
391/* The following calls are not useful for normal CADET operation, but for */
392/* debug and monitoring of the cadet state. They can be safely ignored. */
393/* The API can change at any point without notice. */
394/* Please contact the developer if you consider any of this calls useful for */
395/* normal cadet applications. */
396/******************************************************************************/
397
398
399/**
400 * Method called to retrieve information about a specific channel the cadet peer 371 * Method called to retrieve information about a specific channel the cadet peer
401 * is aware of, including all transit nodes. 372 * is aware of, including all transit nodes.
402 * 373 *
@@ -482,33 +453,6 @@ typedef void
482 453
483 454
484/** 455/**
485 * Hash uniquely identifying a connection below a tunnel.
486 */
487struct GNUNET_CADET_ConnectionTunnelIdentifier
488{
489 struct GNUNET_ShortHashCode connection_of_tunnel;
490};
491
492
493/**
494 * Number identifying a CADET channel within a tunnel.
495 */
496struct GNUNET_CADET_ChannelTunnelNumber
497{
498 /**
499 * Which number does this channel have that uniquely identfies
500 * it within its tunnel, in network byte order.
501 *
502 * Given two peers, both may initiate channels over the same tunnel.
503 * The @e cn must be greater or equal to 0x80000000 (high-bit set)
504 * for tunnels initiated with the peer that has the larger peer
505 * identity as compared using #GNUNET_CRYPTO_cmp_peer_identity().
506 */
507 uint32_t cn GNUNET_PACKED;
508};
509
510
511/**
512 * Method called to retrieve information about a specific tunnel the cadet peer 456 * Method called to retrieve information about a specific tunnel the cadet peer
513 * has established, o`r is trying to establish. 457 * has established, o`r is trying to establish.
514 * 458 *
@@ -667,169 +611,6 @@ GNUNET_CADET_get_tunnel (struct GNUNET_CADET_Handle *h,
667 void *callback_cls); 611 void *callback_cls);
668 612
669 613
670/**
671 * Create a message queue for a cadet channel.
672 * The message queue can only be used to transmit messages,
673 * not to receive them.
674 *
675 * @param channel the channel to create the message qeue for
676 * @return a message queue to messages over the channel
677 */
678struct GNUNET_MQ_Handle *
679GNUNET_CADET_mq_create (struct GNUNET_CADET_Channel *channel);
680
681
682/**
683 * Transitional function to convert an unsigned int port to a hash value.
684 * WARNING: local static value returned, NOT reentrant!
685 * WARNING: do not use this function for new code!
686 *
687 * @param port Numerical port (unsigned int format).
688 *
689 * @return A GNUNET_HashCode usable for the new CADET API.
690 */
691const struct GNUNET_HashCode *
692GC_u2h (uint32_t port);
693
694
695/******************************************************************************/
696/******************************* MQ-BASED API *********************************/
697/******************************************************************************/
698
699/**
700 * Method called whenever a peer connects to a port in MQ-based CADET.
701 *
702 * @param cls Closure from #GNUNET_CADET_open_porT.
703 * @param channel New handle to the channel.
704 * @param source Peer that started this channel.
705 * @return Closure for the incoming @a channel. It's given to:
706 * - The #GNUNET_CADET_DisconnectEventHandler (given to
707 * #GNUNET_CADET_open_porT) when the channel dies.
708 * - Each the #GNUNET_MQ_MessageCallback handlers for each message
709 * received on the @a channel.
710 */
711typedef void *
712(*GNUNET_CADET_ConnectEventHandler) (void *cls,
713 struct GNUNET_CADET_Channel *channel,
714 const struct GNUNET_PeerIdentity *source);
715
716
717/**
718 * Function called whenever an MQ-channel is destroyed, even if the destruction
719 * was requested by #GNUNET_CADET_channel_destroy.
720 * It must NOT call #GNUNET_CADET_channel_destroy on the channel.
721 *
722 * It should clean up any associated state, including cancelling any pending
723 * transmission on this channel.
724 *
725 * @param cls Channel closure.
726 * @param channel Connection to the other end (henceforth invalid).
727 */
728typedef void
729(*GNUNET_CADET_DisconnectEventHandler) (void *cls,
730 const struct GNUNET_CADET_Channel *channel);
731
732
733/**
734 * Function called whenever an MQ-channel's transmission window size changes.
735 *
736 * The first callback in an outgoing channel will be with a non-zero value
737 * and will mean the channel is connected to the destination.
738 *
739 * For an incoming channel it will be called immediately after the
740 * #GNUNET_CADET_ConnectEventHandler, also with a non-zero value.
741 *
742 * @param cls Channel closure.
743 * @param channel Connection to the other end --- FIXME: drop?
744 * @param window_size New window size. If the is more messages than buffer size
745 * this value will be negative. -- FIXME: make unsigned, we never call negative?
746 */
747typedef void
748(*GNUNET_CADET_WindowSizeEventHandler) (void *cls,
749 const struct GNUNET_CADET_Channel *channel,
750 int window_size);
751
752
753/**
754 * Connect to the MQ-based cadet service.
755 *
756 * @param cfg Configuration to use.
757 * @return Handle to the cadet service NULL on error.
758 */
759struct GNUNET_CADET_Handle *
760GNUNET_CADET_connecT (const struct GNUNET_CONFIGURATION_Handle *cfg);
761
762
763/**
764 * Open a port to receive incomming MQ-based channels.
765 *
766 * @param h CADET handle.
767 * @param port Hash identifying the port.
768 * @param connects Function called when an incoming channel is connected.
769 * @param connects_cls Closure for the @a connects handler.
770 * @param window_changes Function called when the transmit window size changes.
771 * Can be NULL.
772 * @param disconnects Function called when a channel is disconnected.
773 * @param handlers Callbacks for messages we care about, NULL-terminated.
774 * @return Port handle.
775 */
776struct GNUNET_CADET_Port *
777GNUNET_CADET_open_porT (struct GNUNET_CADET_Handle *h,
778 const struct GNUNET_HashCode *port,
779 GNUNET_CADET_ConnectEventHandler connects,
780 void *connects_cls,
781 GNUNET_CADET_WindowSizeEventHandler window_changes,
782 GNUNET_CADET_DisconnectEventHandler disconnects,
783 const struct GNUNET_MQ_MessageHandler *handlers);
784
785/**
786 * Create a new channel towards a remote peer.
787 *
788 * If the destination port is not open by any peer or the destination peer
789 * does not accept the channel, #GNUNET_CADET_ChannelEndHandler will be called
790 * for this channel.
791 *
792 * @param h CADET handle.
793 * @param channel_cls Closure for the channel. It's given to:
794 * - The management handler @a window_changes.
795 * - The disconnect handler @a disconnects
796 * - Each message type callback in @a handlers
797 * @param destination Peer identity the channel should go to.
798 * @param port Identification of the destination port.
799 * @param options CadetOption flag field, with all desired option bits set to 1.
800 * @param window_changes Function called when the transmit window size changes.
801 * Can be NULL if this data is of no interest.
802 * TODO Not yet implemented.
803 * @param disconnects Function called when the channel is disconnected.
804 * @param handlers Callbacks for messages we care about, NULL-terminated.
805 * @return Handle to the channel.
806 */
807struct GNUNET_CADET_Channel *
808GNUNET_CADET_channel_creatE (struct GNUNET_CADET_Handle *h,
809 void *channel_cls,
810 const struct GNUNET_PeerIdentity *destination,
811 const struct GNUNET_HashCode *port,
812 enum GNUNET_CADET_ChannelOption options,
813 GNUNET_CADET_WindowSizeEventHandler window_changes,
814 GNUNET_CADET_DisconnectEventHandler disconnects,
815 const struct GNUNET_MQ_MessageHandler *handlers);
816
817
818/**
819 * Obtain the message queue for a connected channel.
820 *
821 * @param channel The channel handle from which to get the MQ.
822 * @return The message queue of the channel.
823 */
824struct GNUNET_MQ_Handle *
825GNUNET_CADET_get_mq (const struct GNUNET_CADET_Channel *channel);
826
827
828/******************************************************************************/
829/******************************* MQ-BASED API *********************************/
830/******************************************************************************/
831
832
833 614
834#if 0 /* keep Emacsens' auto-indent happy */ 615#if 0 /* keep Emacsens' auto-indent happy */
835{ 616{
diff --git a/src/include/gnunet_configuration_lib.h b/src/include/gnunet_configuration_lib.h
index 746dea61f..c1537e4f8 100644
--- a/src/include/gnunet_configuration_lib.h
+++ b/src/include/gnunet_configuration_lib.h
@@ -281,8 +281,8 @@ GNUNET_CONFIGURATION_get_value_number (const struct GNUNET_CONFIGURATION_Handle
281 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error 281 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
282 */ 282 */
283int 283int
284GNUNET_CONFIGURATION_get_value_float (const struct GNUNET_CONFIGURATION_Handle 284GNUNET_CONFIGURATION_get_value_float (const struct GNUNET_CONFIGURATION_Handle *cfg,
285 *cfg, const char *section, 285 const char *section,
286 const char *option, 286 const char *option,
287 float *number); 287 float *number);
288 288
@@ -454,9 +454,6 @@ GNUNET_CONFIGURATION_get_data (const struct GNUNET_CONFIGURATION_Handle *cfg,
454 size_t buf_size); 454 size_t buf_size);
455 455
456 456
457
458
459
460/** 457/**
461 * Expand an expression of the form "$FOO/BAR" to "DIRECTORY/BAR" 458 * Expand an expression of the form "$FOO/BAR" to "DIRECTORY/BAR"
462 * where either in the "PATHS" section or the environtment "FOO" is 459 * where either in the "PATHS" section or the environtment "FOO" is
diff --git a/src/include/gnunet_connection_lib.h b/src/include/gnunet_connection_lib.h
deleted file mode 100644
index e9dd95d1b..000000000
--- a/src/include/gnunet_connection_lib.h
+++ /dev/null
@@ -1,400 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21/**
22 * @author Christian Grothoff
23 *
24 * @file include/gnunet_connection_lib.h
25 * Basic, low-level TCP networking interface
26 *
27 * @defgroup connection Connection library
28 * Basic, low-level TCP networking interface
29 * @{
30 */
31#ifndef GNUNET_CONNECTION_LIB_H
32#define GNUNET_CONNECTION_LIB_H
33
34#ifdef __cplusplus
35extern "C"
36{
37#if 0 /* keep Emacsens' auto-indent happy */
38}
39#endif
40#endif
41
42#include "gnunet_network_lib.h"
43#include "gnunet_scheduler_lib.h"
44#include "gnunet_time_lib.h"
45
46/**
47 * Timeout we use on TCP connect before trying another
48 * result from the DNS resolver. Actual value used
49 * is this value divided by the number of address families.
50 * Default is 5s.
51 */
52#define GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
53
54/**
55 * @brief handle for a network connection
56 */
57struct GNUNET_CONNECTION_Handle;
58
59
60/**
61 * Credentials for UNIX domain sockets.
62 */
63struct GNUNET_CONNECTION_Credentials
64{
65 /**
66 * UID of the other end of the connection.
67 */
68 uid_t uid;
69
70 /**
71 * GID of the other end of the connection.
72 */
73 gid_t gid;
74};
75
76
77/**
78 * Function to call for access control checks.
79 *
80 * @param cls closure
81 * @param ucred credentials, if available, otherwise NULL
82 * @param addr address
83 * @param addrlen length of address
84 * @return GNUNET_YES to allow, GNUNET_NO to deny, GNUNET_SYSERR
85 * for unknown address family (will be denied).
86 */
87typedef int (*GNUNET_CONNECTION_AccessCheck) (void *cls,
88 const struct
89 GNUNET_CONNECTION_Credentials *
90 ucred,
91 const struct sockaddr * addr,
92 socklen_t addrlen);
93
94
95/**
96 * Callback function for data received from the network. Note that
97 * both "available" and "err" would be 0 if the read simply timed out.
98 *
99 * @param cls closure
100 * @param buf pointer to received data
101 * @param available number of bytes availabe in "buf",
102 * possibly 0 (on errors)
103 * @param addr address of the sender
104 * @param addrlen size of addr
105 * @param errCode value of errno (on errors receiving)
106 */
107typedef void (*GNUNET_CONNECTION_Receiver) (void *cls, const void *buf,
108 size_t available,
109 const struct sockaddr * addr,
110 socklen_t addrlen, int errCode);
111
112/**
113 * Set the persist option on this connection handle. Indicates
114 * that the underlying socket or fd should never really be closed.
115 * Used for indicating process death.
116 *
117 * @param connection the connection to set persistent
118 */
119void
120GNUNET_CONNECTION_persist_ (struct GNUNET_CONNECTION_Handle *connection);
121
122/**
123 * Disable the "CORK" feature for communication with the given socket,
124 * forcing the OS to immediately flush the buffer on transmission
125 * instead of potentially buffering multiple messages. Essentially
126 * reduces the OS send buffers to zero.
127 * Used to make sure that the last messages sent through the connection
128 * reach the other side before the process is terminated.
129 *
130 * @param connection the connection to make flushing and blocking
131 * @return #GNUNET_OK on success
132 */
133int
134GNUNET_CONNECTION_disable_corking (struct GNUNET_CONNECTION_Handle *connection);
135
136
137/**
138 * Create a connection handle by (asynchronously) connecting to a host.
139 * This function returns immediately, even if the connection has not
140 * yet been established. This function only creates TCP connections.
141 *
142 * @param s socket to connect
143 * @param serv_addr server address
144 * @param addrlen length of server address
145 * @return the connection handle
146 */
147struct GNUNET_CONNECTION_Handle *
148GNUNET_CONNECTION_connect_socket (struct GNUNET_NETWORK_Handle *s,
149 const struct sockaddr *serv_addr,
150 socklen_t addrlen);
151
152
153/**
154 * Create a connection handle by boxing an existing OS socket. The OS
155 * socket should henceforth be no longer used directly.
156 * #GNUNET_CONNECTION_destroy() will close it.
157 *
158 * @param osSocket existing socket to box
159 * @return the boxed socket handle
160 */
161struct GNUNET_CONNECTION_Handle *
162GNUNET_CONNECTION_create_from_existing (struct GNUNET_NETWORK_Handle *osSocket);
163
164
165/**
166 * Create a connection handle by accepting on a listen socket. This
167 * function may block if the listen socket has no connection ready.
168 *
169 * @param access_cb function to use to check if access is allowed
170 * @param access_cb_cls closure for @a access_cb
171 * @param lsock listen socket
172 * @return the connection handle, NULL on error (for example, access refused)
173 */
174struct GNUNET_CONNECTION_Handle *
175GNUNET_CONNECTION_create_from_accept (GNUNET_CONNECTION_AccessCheck access_cb,
176 void *access_cb_cls,
177 struct GNUNET_NETWORK_Handle *lsock);
178
179
180/**
181 * Create a connection handle by (asynchronously) connecting to a host.
182 * This function returns immediately, even if the connection has not
183 * yet been established. This function only creates TCP connections.
184 *
185 * @param cfg configuration to use
186 * @param hostname name of the host to connect to
187 * @param port port to connect to
188 * @return the connection handle
189 */
190struct GNUNET_CONNECTION_Handle *
191GNUNET_CONNECTION_create_from_connect (const struct GNUNET_CONFIGURATION_Handle
192 *cfg, const char *hostname,
193 uint16_t port);
194
195
196/**
197 * Create a connection handle by connecting to a UNIX domain service.
198 * This function returns immediately, even if the connection has not
199 * yet been established. This function only creates UNIX connections.
200 *
201 * @param cfg configuration to use
202 * @param unixpath path to connect to)
203 * @return the connection handle, NULL on systems without UNIX support
204 */
205struct GNUNET_CONNECTION_Handle *
206GNUNET_CONNECTION_create_from_connect_to_unixpath (const struct
207 GNUNET_CONFIGURATION_Handle
208 *cfg, const char *unixpath);
209
210
211
212
213/**
214 * Create a connection handle by (asynchronously) connecting to a host.
215 * This function returns immediately, even if the connection has not
216 * yet been established. This function only creates TCP connections.
217 *
218 * @param af_family address family to use
219 * @param serv_addr server address
220 * @param addrlen length of server address
221 * @return the connection handle
222 */
223struct GNUNET_CONNECTION_Handle *
224GNUNET_CONNECTION_create_from_sockaddr (int af_family,
225 const struct sockaddr *serv_addr,
226 socklen_t addrlen);
227
228/**
229 * Check if connection is valid (no fatal errors have happened so far).
230 * Note that a connection that is still trying to connect is considered
231 * valid.
232 *
233 * @param connection handle to check
234 * @return GNUNET_YES if valid, GNUNET_NO otherwise
235 */
236int
237GNUNET_CONNECTION_check (struct GNUNET_CONNECTION_Handle *connection);
238
239
240/**
241 * Obtain the network address of the other party.
242 *
243 * @param connection the client to get the address for
244 * @param addr where to store the address
245 * @param addrlen where to store the length of the address
246 * @return GNUNET_OK on success
247 */
248int
249GNUNET_CONNECTION_get_address (struct GNUNET_CONNECTION_Handle *connection,
250 void **addr, size_t * addrlen);
251
252
253/**
254 * Close the connection and free associated resources. There must
255 * not be any pending requests for reading or writing to the
256 * connection at this time.
257 *
258 * @param connection connection to destroy
259 */
260void
261GNUNET_CONNECTION_destroy (struct GNUNET_CONNECTION_Handle *connection);
262
263
264/**
265 * Receive data from the given connection. Note that this function will
266 * call "receiver" asynchronously using the scheduler. It will
267 * "immediately" return. Note that there MUST only be one active
268 * receive call per connection at any given point in time (so do not
269 * call receive again until the receiver callback has been invoked).
270 *
271 * @param connection connection handle
272 * @param max maximum number of bytes to read
273 * @param timeout maximum amount of time to wait
274 * @param receiver function to call with received data
275 * @param receiver_cls closure for receiver
276 */
277void
278GNUNET_CONNECTION_receive (struct GNUNET_CONNECTION_Handle *connection, size_t max,
279 struct GNUNET_TIME_Relative timeout,
280 GNUNET_CONNECTION_Receiver receiver,
281 void *receiver_cls);
282
283
284/**
285 * Cancel receive job on the given connection. Note that the
286 * receiver callback must not have been called yet in order
287 * for the cancellation to be valid.
288 *
289 * @param connection connection handle
290 * @return closure of the original receiver callback closure
291 */
292void *
293GNUNET_CONNECTION_receive_cancel (struct GNUNET_CONNECTION_Handle *connection);
294
295
296/**
297 * Function called to notify a client about the connection begin ready
298 * to queue more data. @a buf will be NULL and @a size zero if the
299 * connection was closed for writing in the meantime.
300 *
301 * @param cls closure
302 * @param size number of bytes available in @a buf
303 * @param buf where the callee should write the message
304 * @return number of bytes written to @a buf
305 */
306typedef size_t
307(*GNUNET_CONNECTION_TransmitReadyNotify) (void *cls,
308 size_t size,
309 void *buf);
310
311
312/**
313 * Opaque handle that can be used to cancel
314 * a transmit-ready notification.
315 */
316struct GNUNET_CONNECTION_TransmitHandle;
317
318/**
319 * Ask the connection to call us once the specified number of bytes
320 * are free in the transmission buffer. Will never call the @a notify
321 * callback in this task, but always first go into the scheduler. Note that
322 * this function will abort if "size" is greater than
323 * #GNUNET_SERVER_MAX_MESSAGE_SIZE.
324 *
325 * Note that "notify" will be called either when enough
326 * buffer space is available OR when the connection is destroyed.
327 * The size parameter given to notify is guaranteed to be
328 * larger or equal to size if the buffer is ready, or zero
329 * if the connection was destroyed (or at least closed for
330 * writing). Finally, any time before 'notify' is called, a
331 * client may call "notify_transmit_ready_cancel" to cancel
332 * the transmission request.
333 *
334 * Only one transmission request can be scheduled at the same
335 * time. Notify will be run with the same scheduler priority
336 * as that of the caller.
337 *
338 * @param connection connection
339 * @param size number of bytes to send
340 * @param timeout after how long should we give up (and call
341 * notify with buf NULL and size 0)?
342 * @param notify function to call when buffer space is available
343 * @param notify_cls closure for notify
344 * @return non-NULL if the notify callback was queued,
345 * NULL if we are already going to notify someone else (busy)
346 */
347struct GNUNET_CONNECTION_TransmitHandle *
348GNUNET_CONNECTION_notify_transmit_ready (struct GNUNET_CONNECTION_Handle *connection,
349 size_t size,
350 struct GNUNET_TIME_Relative timeout,
351 GNUNET_CONNECTION_TransmitReadyNotify
352 notify, void *notify_cls);
353
354
355/**
356 * Cancel the specified transmission-ready
357 * notification.
358 *
359 * @param th handle for notification to cancel
360 */
361void
362GNUNET_CONNECTION_notify_transmit_ready_cancel (struct
363 GNUNET_CONNECTION_TransmitHandle
364 *th);
365
366
367/**
368 * Create a connection to be proxied using a given connection.
369 *
370 * @param cph connection to proxy server
371 * @return connection to be proxied
372 */
373struct GNUNET_CONNECTION_Handle *
374GNUNET_CONNECTION_create_proxied_from_handshake (struct GNUNET_CONNECTION_Handle *cph);
375
376
377/**
378 * Activate proxied connection and destroy initial proxy handshake connection.
379 * There must not be any pending requests for reading or writing to the
380 * proxy hadshake connection at this time.
381 *
382 * @param proxied connection connection to proxy server
383 */
384void
385GNUNET_CONNECTION_acivate_proxied (struct GNUNET_CONNECTION_Handle *proxied);
386
387
388#if 0 /* keep Emacsens' auto-indent happy */
389{
390#endif
391#ifdef __cplusplus
392}
393#endif
394
395/* ifndef GNUNET_CONNECTION_LIB_H */
396#endif
397
398/** @} */ /* end of group */
399
400/* end of gnunet_connection_lib.h */
diff --git a/src/include/gnunet_constants.h b/src/include/gnunet_constants.h
index 1d0232cea..1c48298a0 100644
--- a/src/include/gnunet_constants.h
+++ b/src/include/gnunet_constants.h
@@ -40,6 +40,8 @@ extern "C"
40#endif 40#endif
41#endif 41#endif
42 42
43
44
43/** 45/**
44 * Bandwidth (in/out) to assume initially (before either peer has 46 * Bandwidth (in/out) to assume initially (before either peer has
45 * communicated any particular preference). Should be rather low; set 47 * communicated any particular preference). Should be rather low; set
diff --git a/src/include/gnunet_core_service.h b/src/include/gnunet_core_service.h
index 8136770b7..ace223c11 100644
--- a/src/include/gnunet_core_service.h
+++ b/src/include/gnunet_core_service.h
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 Copyright (C) 2009-2014, 2016 GNUnet e.V. 3 Copyright (C) 2009-2017 GNUnet e.V.
4 4
5 GNUnet is free software; you can redistribute it and/or modify 5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published 6 it under the terms of the GNU General Public License as published
@@ -197,57 +197,6 @@ GNUNET_CORE_get_mq (const struct GNUNET_CORE_Handle *h,
197 197
198 198
199/** 199/**
200 * Handle for a transmission request.
201 */
202struct GNUNET_CORE_TransmitHandle;
203
204
205/**
206 * Ask the core to call @a notify once it is ready to transmit the
207 * given number of bytes to the specified @a target. Must only be
208 * called after a connection to the respective peer has been
209 * established (and the client has been informed about this). You may
210 * have one request of this type pending for each connected peer at
211 * any time. If a peer disconnects, the application MUST call
212 * #GNUNET_CORE_notify_transmit_ready_cancel() on the respective
213 * transmission request, if one such request is pending.
214 *
215 * @param handle connection to core service
216 * @param cork is corking allowed for this transmission?
217 * @param priority how important is the message?
218 * @param maxdelay how long can the message wait? Only effective if @a cork is #GNUNET_YES
219 * @param target who should receive the message, never NULL (can be this peer's identity for loopback)
220 * @param notify_size how many bytes of buffer space does @a notify want?
221 * @param notify function to call when buffer space is available;
222 * will be called with NULL on timeout; clients MUST cancel
223 * all pending transmission requests DURING the disconnect
224 * handler
225 * @param notify_cls closure for @a notify
226 * @return non-NULL if the notify callback was queued,
227 * NULL if we can not even queue the request (request already pending);
228 * if NULL is returned, @a notify will NOT be called.
229 */
230struct GNUNET_CORE_TransmitHandle *
231GNUNET_CORE_notify_transmit_ready (struct GNUNET_CORE_Handle *handle,
232 int cork,
233 enum GNUNET_CORE_Priority priority,
234 struct GNUNET_TIME_Relative maxdelay,
235 const struct GNUNET_PeerIdentity *target,
236 size_t notify_size,
237 GNUNET_CONNECTION_TransmitReadyNotify notify,
238 void *notify_cls);
239
240
241/**
242 * Cancel the specified transmission-ready notification.
243 *
244 * @param th handle that was returned by #GNUNET_CORE_notify_transmit_ready().
245 */
246void
247GNUNET_CORE_notify_transmit_ready_cancel (struct GNUNET_CORE_TransmitHandle *th);
248
249
250/**
251 * Handle to a CORE monitoring operation. 200 * Handle to a CORE monitoring operation.
252 */ 201 */
253struct GNUNET_CORE_MonitorHandle; 202struct GNUNET_CORE_MonitorHandle;
diff --git a/src/include/gnunet_datastore_plugin.h b/src/include/gnunet_datastore_plugin.h
index 2295d4e72..b1c9cb7c3 100644
--- a/src/include/gnunet_datastore_plugin.h
+++ b/src/include/gnunet_datastore_plugin.h
@@ -204,9 +204,9 @@ typedef void
204 * Get one of the results for a particular key in the datastore. 204 * Get one of the results for a particular key in the datastore.
205 * 205 *
206 * @param cls closure 206 * @param cls closure
207 * @param offset offset of the result (modulo num-results); 207 * @param next_uid return the result with lowest uid >= next_uid
208 * specific ordering does not matter for the offset 208 * @param random if true, return a random result instead of using next_uid
209 * @param key key to match, never NULL 209 * @param key maybe NULL (to match all entries)
210 * @param vhash hash of the value, maybe NULL (to 210 * @param vhash hash of the value, maybe NULL (to
211 * match all values that have the right key). 211 * match all values that have the right key).
212 * Note that for DBlocks there is no difference 212 * Note that for DBlocks there is no difference
@@ -215,17 +215,18 @@ typedef void
215 * @param type entries of which type are relevant? 215 * @param type entries of which type are relevant?
216 * Use 0 for any type. 216 * Use 0 for any type.
217 * @param proc function to call on the matching value; 217 * @param proc function to call on the matching value;
218 * proc should be called with NULL if there is no result 218 * will be called with NULL if nothing matches
219 * @param proc_cls closure for @a proc 219 * @param proc_cls closure for @a proc
220 */ 220 */
221typedef void 221typedef void
222(*PluginGetKey) (void *cls, 222(*PluginGetKey) (void *cls,
223 uint64_t offset, 223 uint64_t next_uid,
224 const struct GNUNET_HashCode *key, 224 bool random,
225 const struct GNUNET_HashCode *vhash, 225 const struct GNUNET_HashCode *key,
226 enum GNUNET_BLOCK_Type type, 226 const struct GNUNET_HashCode *vhash,
227 PluginDatumProcessor proc, 227 enum GNUNET_BLOCK_Type type,
228 void *proc_cls); 228 PluginDatumProcessor proc,
229 void *proc_cls);
229 230
230 231
231/** 232/**
@@ -285,23 +286,22 @@ typedef void
285 286
286 287
287/** 288/**
288 * Select a single item from the datastore at the specified offset 289 * Select a single item from the datastore (among those applicable).
289 * (among those applicable).
290 * 290 *
291 * @param cls closure 291 * @param cls closure
292 * @param offset offset of the result (modulo num-results); 292 * @param next_uid return the result with lowest uid >= next_uid
293 * specific ordering does not matter for the offset
294 * @param type entries of which type should be considered? 293 * @param type entries of which type should be considered?
295 * Must not be zero (ANY). 294 * Must not be zero (ANY).
296 * @param proc function to call on the matching value 295 * @param proc function to call on the matching value;
296 * will be called with NULL if no value matches
297 * @param proc_cls closure for @a proc 297 * @param proc_cls closure for @a proc
298 */ 298 */
299typedef void 299typedef void
300(*PluginGetType) (void *cls, 300(*PluginGetType) (void *cls,
301 uint64_t offset, 301 uint64_t next_uid,
302 enum GNUNET_BLOCK_Type type, 302 enum GNUNET_BLOCK_Type type,
303 PluginDatumProcessor proc, 303 PluginDatumProcessor proc,
304 void *proc_cls); 304 void *proc_cls);
305 305
306 306
307/** 307/**
@@ -354,9 +354,6 @@ struct GNUNET_DATASTORE_PluginFunctions
354 354
355 /** 355 /**
356 * Get datum (of the specified type) with anonymity level zero. 356 * Get datum (of the specified type) with anonymity level zero.
357 * This function is allowed to ignore the 'offset' argument
358 * and instead return a random result (with zero anonymity of
359 * the correct type) if implementing an offset is expensive.
360 */ 357 */
361 PluginGetType get_zero_anonymity; 358 PluginGetType get_zero_anonymity;
362 359
diff --git a/src/include/gnunet_datastore_service.h b/src/include/gnunet_datastore_service.h
index f594d8fa6..830e7da86 100644
--- a/src/include/gnunet_datastore_service.h
+++ b/src/include/gnunet_datastore_service.h
@@ -201,33 +201,6 @@ GNUNET_DATASTORE_release_reserve (struct GNUNET_DATASTORE_Handle *h,
201 201
202 202
203/** 203/**
204 * Update a value in the datastore.
205 *
206 * @param h handle to the datastore
207 * @param uid identifier for the value
208 * @param priority how much to increase the priority of the value
209 * @param expiration new expiration value should be MAX of existing and this argument
210 * @param queue_priority ranking of this request in the priority queue
211 * @param max_queue_size at what queue size should this request be dropped
212 * (if other requests of higher priority are in the queue)
213 * @param cont continuation to call when done
214 * @param cont_cls closure for @a cont
215 * @return NULL if the entry was not queued, otherwise a handle that can be used to
216 * cancel; note that even if NULL is returned, the callback will be invoked
217 * (or rather, will already have been invoked)
218 */
219struct GNUNET_DATASTORE_QueueEntry *
220GNUNET_DATASTORE_update (struct GNUNET_DATASTORE_Handle *h,
221 uint64_t uid,
222 uint32_t priority,
223 struct GNUNET_TIME_Absolute expiration,
224 unsigned int queue_priority,
225 unsigned int max_queue_size,
226 GNUNET_DATASTORE_ContinuationWithStatus cont,
227 void *cont_cls);
228
229
230/**
231 * Explicitly remove some content from the database. @a cont will be 204 * Explicitly remove some content from the database. @a cont will be
232 * called with status #GNUNET_OK if content was removed, #GNUNET_NO if 205 * called with status #GNUNET_OK if content was removed, #GNUNET_NO if
233 * no matching entry was found and #GNUNET_SYSERR on all other types 206 * no matching entry was found and #GNUNET_SYSERR on all other types
@@ -288,10 +261,8 @@ typedef void
288 * will only be called once. 261 * will only be called once.
289 * 262 *
290 * @param h handle to the datastore 263 * @param h handle to the datastore
291 * @param offset offset of the result (modulo num-results); set to 264 * @param next_uid return the result with lowest uid >= next_uid
292 * a random 64-bit value initially; then increment by 265 * @param random if true, return a random result instead of using next_uid
293 * one each time; detect that all results have been found by uid
294 * being again the first uid ever returned.
295 * @param key maybe NULL (to match all entries) 266 * @param key maybe NULL (to match all entries)
296 * @param type desired type, 0 for any 267 * @param type desired type, 0 for any
297 * @param queue_priority ranking of this request in the priority queue 268 * @param queue_priority ranking of this request in the priority queue
@@ -305,7 +276,8 @@ typedef void
305 */ 276 */
306struct GNUNET_DATASTORE_QueueEntry * 277struct GNUNET_DATASTORE_QueueEntry *
307GNUNET_DATASTORE_get_key (struct GNUNET_DATASTORE_Handle *h, 278GNUNET_DATASTORE_get_key (struct GNUNET_DATASTORE_Handle *h,
308 uint64_t offset, 279 uint64_t next_uid,
280 bool random,
309 const struct GNUNET_HashCode *key, 281 const struct GNUNET_HashCode *key,
310 enum GNUNET_BLOCK_Type type, 282 enum GNUNET_BLOCK_Type type,
311 unsigned int queue_priority, 283 unsigned int queue_priority,
@@ -316,16 +288,9 @@ GNUNET_DATASTORE_get_key (struct GNUNET_DATASTORE_Handle *h,
316 288
317/** 289/**
318 * Get a single zero-anonymity value from the datastore. 290 * Get a single zero-anonymity value from the datastore.
319 * Note that some implementations can ignore the 'offset' and
320 * instead return a random zero-anonymity value. In that case,
321 * detecting the wrap-around based on a repeating UID is at best
322 * probabilistic.
323 * 291 *
324 * @param h handle to the datastore 292 * @param h handle to the datastore
325 * @param offset offset of the result (modulo num-results); set to 293 * @param next_uid return the result with lowest uid >= next_uid
326 * a random 64-bit value initially; then increment by
327 * one each time; detect that all results have been found by uid
328 * being again the first uid ever returned.
329 * @param queue_priority ranking of this request in the priority queue 294 * @param queue_priority ranking of this request in the priority queue
330 * @param max_queue_size at what queue size should this request be dropped 295 * @param max_queue_size at what queue size should this request be dropped
331 * (if other requests of higher priority are in the queue) 296 * (if other requests of higher priority are in the queue)
@@ -339,7 +304,7 @@ GNUNET_DATASTORE_get_key (struct GNUNET_DATASTORE_Handle *h,
339 */ 304 */
340struct GNUNET_DATASTORE_QueueEntry * 305struct GNUNET_DATASTORE_QueueEntry *
341GNUNET_DATASTORE_get_zero_anonymity (struct GNUNET_DATASTORE_Handle *h, 306GNUNET_DATASTORE_get_zero_anonymity (struct GNUNET_DATASTORE_Handle *h,
342 uint64_t offset, 307 uint64_t next_uid,
343 unsigned int queue_priority, 308 unsigned int queue_priority,
344 unsigned int max_queue_size, 309 unsigned int max_queue_size,
345 enum GNUNET_BLOCK_Type type, 310 enum GNUNET_BLOCK_Type type,
diff --git a/src/include/gnunet_fs_service.h b/src/include/gnunet_fs_service.h
index a9c7e8944..ac418072e 100644
--- a/src/include/gnunet_fs_service.h
+++ b/src/include/gnunet_fs_service.h
@@ -438,23 +438,36 @@ GNUNET_FS_uri_ksk_create_from_meta_data (const struct GNUNET_CONTAINER_MetaData
438/* ******************** command-line option parsing API *********************** */ 438/* ******************** command-line option parsing API *********************** */
439 439
440/** 440/**
441 * Command-line option parser function that allows the user 441 * Allow user to specify keywords.
442 * to specify one or more '-k' options with keywords. Each 442 *
443 * specified keyword will be added to the URI. A pointer to 443 * @param shortName short name of the option
444 * the URI must be passed as the "scls" argument. 444 * @param name long name of the option
445 * 445 * @param argumentHelp help text for the option argument
446 * @param ctx command line processor context 446 * @param description long help text for the option
447 * @param scls must be of type "struct GNUNET_FS_Uri **" 447 * @param[out] topKeywords set to the desired value
448 * @param option name of the option (typically 'k') 448 */
449 * @param value command line argument given 449struct GNUNET_GETOPT_CommandLineOption
450 * @return #GNUNET_OK on success 450GNUNET_FS_GETOPT_KEYWORDS (char shortName,
451 */ 451 const char *name,
452int 452 const char *argumentHelp,
453GNUNET_FS_getopt_set_keywords (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, 453 const char *description,
454 void *scls, 454 struct GNUNET_FS_Uri **topKeywords);
455 const char *option, 455
456 const char *value); 456/**
457 457 * Allow user to specify metadata.
458 *
459 * @param shortName short name of the option
460 * @param name long name of the option
461 * @param argumentHelp help text for the option argument
462 * @param description long help text for the option
463 * @param[out] metadata set to the desired value
464 */
465struct GNUNET_GETOPT_CommandLineOption
466GNUNET_FS_GETOPT_METADATA (char shortName,
467 const char *name,
468 const char *argumentHelp,
469 const char *description,
470 struct GNUNET_CONTAINER_MetaData **meta);
458 471
459/** 472/**
460 * Command-line option parser function that allows the user to specify 473 * Command-line option parser function that allows the user to specify
diff --git a/src/include/gnunet_getopt_lib.h b/src/include/gnunet_getopt_lib.h
index b04020a70..c2bd72340 100644
--- a/src/include/gnunet_getopt_lib.h
+++ b/src/include/gnunet_getopt_lib.h
@@ -97,6 +97,7 @@ typedef int
97 const char *option, 97 const char *option,
98 const char *value); 98 const char *value);
99 99
100
100/** 101/**
101 * @brief Definition of a command line option. 102 * @brief Definition of a command line option.
102 */ 103 */
@@ -130,255 +131,301 @@ struct GNUNET_GETOPT_CommandLineOption
130 int require_argument; 131 int require_argument;
131 132
132 /** 133 /**
134 * Is the presence of this option mandatory?
135 */
136 int option_mandatory;
137
138 /**
133 * Handler for the option. 139 * Handler for the option.
134 */ 140 */
135 GNUNET_GETOPT_CommandLineOptionProcessor processor; 141 GNUNET_GETOPT_CommandLineOptionProcessor processor;
136 142
137 /** 143 /**
144 * Function to call on @e scls to clean up after processing all
145 * the arguments. Can be NULL.
146 */
147 void (*cleaner)(void *cls);
148
149 /**
138 * Specific closure to pass to the processor. 150 * Specific closure to pass to the processor.
139 */ 151 */
140 void *scls; 152 void *scls;
141 153
142}; 154};
143 155
156
144/** 157/**
145 * Macro defining the option to print the command line 158 * Defining the option to print the command line
146 * help text (-h option). 159 * help text (-h option).
147 * 160 *
148 * @param about string with brief description of the application 161 * @param about string with brief description of the application
149 */ 162 */
150#define GNUNET_GETOPT_OPTION_HELP(about) \ 163struct GNUNET_GETOPT_CommandLineOption
151 { 'h', "help", (const char *) NULL, gettext_noop("print this help"), 0, &GNUNET_GETOPT_format_help_, (void *) about } 164GNUNET_GETOPT_OPTION_HELP (const char *about);
152 165
153 166
154/** 167/**
155 * Macro defining the option to print the version of 168 * Define the option to print the version of
156 * the application (-v option) 169 * the application (-v option)
157 * 170 *
158 * @param version string with the version number 171 * @param version string with the version number
159 */ 172 */
160#define GNUNET_GETOPT_OPTION_VERSION(version) \ 173struct GNUNET_GETOPT_CommandLineOption
161 { 'v', "version", (const char *) NULL, gettext_noop("print the version number"), 0, &GNUNET_GETOPT_print_version_, (void *) version } 174GNUNET_GETOPT_OPTION_VERSION (const char *version);
175
162 176
163 177
164/** 178/**
165 * Allow user to specify log file name (-l option) 179 * Allow user to specify log file name (-l option)
166 * 180 *
167 * @param logfn set to the name of the logfile 181 * @param[out] logfn set to the name of the logfile
168 */ 182 */
169#define GNUNET_GETOPT_OPTION_LOGFILE(logfn) \ 183struct GNUNET_GETOPT_CommandLineOption
170 { 'l', "logfile", "LOGFILE", gettext_noop("configure logging to write logs to LOGFILE"), 1, &GNUNET_GETOPT_set_string, (void *) logfn } 184GNUNET_GETOPT_OPTION_LOGFILE (char **logfn);
171 185
172 186
173/** 187/**
174 * Allow user to specify log level (-L option) 188 * Allow user to specify a string.
175 * 189 *
176 * @param loglev set to the log level 190 * @param shortName short name of the option
191 * @param name long name of the option
192 * @param argumentHelp help text for the option argument
193 * @param description long help text for the option
194 * @param[out] str set to the string
177 */ 195 */
178#define GNUNET_GETOPT_OPTION_LOGLEVEL(loglev) \ 196struct GNUNET_GETOPT_CommandLineOption
179 { 'L', "log", "LOGLEVEL", gettext_noop("configure logging to use LOGLEVEL"), 1, &GNUNET_GETOPT_set_string, (void *) loglev } 197GNUNET_GETOPT_OPTION_STRING (char shortName,
198 const char *name,
199 const char *argumentHelp,
200 const char *description,
201 char **str);
202
203/**
204 * Allow user to specify a filename (automatically path expanded).
205 *
206 * @param shortName short name of the option
207 * @param name long name of the option
208 * @param argumentHelp help text for the option argument
209 * @param description long help text for the option
210 * @param[out] str set to the string
211 */
212struct GNUNET_GETOPT_CommandLineOption
213GNUNET_GETOPT_OPTION_FILENAME (char shortName,
214 const char *name,
215 const char *argumentHelp,
216 const char *description,
217 char **str);
180 218
181 219
182/** 220/**
183 * Get number of verbose (-V) flags 221 * Allow user to specify a binary value using Crockford
222 * Base32 encoding.
184 * 223 *
185 * @param level where to store the verbosity level (should be an 'int') 224 * @param shortName short name of the option
225 * @param name long name of the option
226 * @param argumentHelp help text for the option argument
227 * @param description long help text for the option
228 * @param[out] val binary value decoded from Crockford Base32-encoded argument
229 * @param val_size size of @a val in bytes
186 */ 230 */
187#define GNUNET_GETOPT_OPTION_VERBOSE(level) \ 231struct GNUNET_GETOPT_CommandLineOption
188 { 'V', "verbose", (const char *) NULL, gettext_noop("be verbose"), 0, &GNUNET_GETOPT_increment_value, (void *) level } 232GNUNET_GETOPT_OPTION_SET_BASE32_FIXED_SIZE (char shortName,
233 const char *name,
234 const char *argumentHelp,
235 const char *description,
236 void *val,
237 size_t val_size);
189 238
190 239
191/** 240/**
192 * Get configuration file name (-c option) 241 * Allow user to specify a binary value using Crockford
242 * Base32 encoding where the size of the binary value is
243 * automatically determined from its type.
193 * 244 *
194 * @param fn set to the configuration file name 245 * @param shortName short name of the option
246 * @param name long name of the option
247 * @param argumentHelp help text for the option argument
248 * @param description long help text for the option
249 * @param[out] val binary value decoded from Crockford Base32-encoded argument;
250 * size is determined by type (sizeof (*val)).
195 */ 251 */
196#define GNUNET_GETOPT_OPTION_CFG_FILE(fn) \ 252#define GNUNET_GETOPT_OPTION_SET_BASE32_AUTO(shortName,name,argumentHelp,description,val) \
197 { 'c', "config", "FILENAME", gettext_noop("use configuration file FILENAME"), 1, &GNUNET_GETOPT_set_string, (void *) fn } 253 GNUNET_GETOPT_OPTION_SET_BASE32_FIXED_SIZE(shortName,name,argumentHelp,description,val,sizeof(*val))
198 254
199 255
200/** 256/**
201 * Marker for the end of the list of options. 257 * Allow user to specify a flag (which internally means setting
258 * an integer to 1/#GNUNET_YES/#GNUNET_OK.
259 *
260 * @param shortName short name of the option
261 * @param name long name of the option
262 * @param description long help text for the option
263 * @param[out] val set to 1 if the option is present
202 */ 264 */
203#define GNUNET_GETOPT_OPTION_END \ 265struct GNUNET_GETOPT_CommandLineOption
204 { '\0', NULL, NULL, NULL, 0, NULL, NULL } 266GNUNET_GETOPT_OPTION_SET_ONE (char shortName,
267 const char *name,
268 const char *description,
269 int *val);
205 270
206 271
207/** 272/**
208 * Parse the command line. 273 * Allow user to specify an `unsigned int`.
209 * 274 *
210 * @param binaryOptions Name of application with option summary 275 * @param shortName short name of the option
211 * @param allOptions defined options and handlers 276 * @param name long name of the option
212 * @param argc number of arguments in @a argv 277 * @param argumentHelp help text for the option argument
213 * @param argv actual arguments 278 * @param description long help text for the option
214 * @return index into argv with first non-option 279 * @param[out] val set to the value specified at the command line
215 * argument, or #GNUNET_SYSERR on error
216 */ 280 */
217int 281struct GNUNET_GETOPT_CommandLineOption
218GNUNET_GETOPT_run (const char *binaryOptions, 282GNUNET_GETOPT_OPTION_SET_UINT (char shortName,
219 const struct GNUNET_GETOPT_CommandLineOption *allOptions, 283 const char *name,
220 unsigned int argc, char *const *argv); 284 const char *argumentHelp,
285 const char *description,
286 unsigned int *val);
221 287
222 288
223/** 289/**
224 * Set an option of type 'unsigned long long' from the command line. 290 * Allow user to specify an `unsigned long long`.
225 * A pointer to this function should be passed as part of the
226 * `struct GNUNET_GETOPT_CommandLineOption` array to initialize options
227 * of this type. It should be followed by a pointer to a value of
228 * type `unsigned long long`.
229 * 291 *
230 * @param ctx command line processing context 292 * @param shortName short name of the option
231 * @param scls additional closure (will point to the 'unsigned long long') 293 * @param name long name of the option
232 * @param option name of the option 294 * @param argumentHelp help text for the option argument
233 * @param value actual value of the option as a string. 295 * @param description long help text for the option
234 * @return #GNUNET_OK if parsing the value worked 296 * @param[out] val set to the value specified at the command line
235 */ 297 */
236int 298struct GNUNET_GETOPT_CommandLineOption
237GNUNET_GETOPT_set_ulong (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, 299GNUNET_GETOPT_OPTION_SET_ULONG (char shortName,
238 void *scls, const char *option, const char *value); 300 const char *name,
301 const char *argumentHelp,
302 const char *description,
303 unsigned long long *val);
239 304
240 305
241/** 306/**
242 * Set an option of type 'struct GNUNET_TIME_Relative' from the command line. 307 * Allow user to specify a `struct GNUNET_TIME_Relative`
243 * A pointer to this function should be passed as part of the 308 * (using human-readable "fancy" time).
244 * `struct GNUNET_GETOPT_CommandLineOption` array to initialize options
245 * of this type. It should be followed by a pointer to a value of
246 * type `struct GNUNET_TIME_Relative`.
247 * 309 *
248 * @param ctx command line processing context 310 * @param shortName short name of the option
249 * @param scls additional closure (will point to the 'struct GNUNET_TIME_Relative') 311 * @param name long name of the option
250 * @param option name of the option 312 * @param argumentHelp help text for the option argument
251 * @param value actual value of the option as a string. 313 * @param description long help text for the option
252 * @return #GNUNET_OK if parsing the value worked 314 * @param[out] val set to the time specified at the command line
253 */ 315 */
254int 316struct GNUNET_GETOPT_CommandLineOption
255GNUNET_GETOPT_set_relative_time (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, 317GNUNET_GETOPT_OPTION_SET_RELATIVE_TIME (char shortName,
256 void *scls, const char *option, const char *value); 318 const char *name,
319 const char *argumentHelp,
320 const char *description,
321 struct GNUNET_TIME_Relative *val);
257 322
258 323
259/** 324/**
260 * Set an option of type 'unsigned int' from the command line. 325 * Allow user to specify a `struct GNUNET_TIME_Absolute`
261 * A pointer to this function should be passed as part of the 326 * (using human-readable "fancy" time).
262 * `struct GNUNET_GETOPT_CommandLineOption` array to initialize options
263 * of this type. It should be followed by a pointer to a value of
264 * type `unsigned int`.
265 * 327 *
266 * @param ctx command line processing context 328 * @param shortName short name of the option
267 * @param scls additional closure (will point to the 'unsigned int') 329 * @param name long name of the option
268 * @param option name of the option 330 * @param argumentHelp help text for the option argument
269 * @param value actual value of the option as a string. 331 * @param description long help text for the option
270 * @return #GNUNET_OK if parsing the value worked 332 * @param[out] val set to the time specified at the command line
271 */ 333 */
272int 334struct GNUNET_GETOPT_CommandLineOption
273GNUNET_GETOPT_set_uint (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, 335GNUNET_GETOPT_OPTION_SET_ABSOLUTE_TIME (char shortName,
274 void *scls, const char *option, const char *value); 336 const char *name,
337 const char *argumentHelp,
338 const char *description,
339 struct GNUNET_TIME_Absolute *val);
275 340
276 341
277/** 342/**
278 * Set an option of type 'int' from the command line to 1 if the 343 * Increment @a val each time the option flag is given by one.
279 * given option is present.
280 * A pointer to this function should be passed as part of the
281 * `struct GNUNET_GETOPT_CommandLineOption` array to initialize options
282 * of this type. It should be followed by a pointer to a value of
283 * type `int`.
284 * 344 *
285 * @param ctx command line processing context 345 * @param shortName short name of the option
286 * @param scls additional closure (will point to the `int`) 346 * @param name long name of the option
287 * @param option name of the option 347 * @param argumentHelp help text for the option argument
288 * @param value not used (NULL) 348 * @param description long help text for the option
289 * @return #GNUNET_OK (always) 349 * @param[out] val set to 1 if the option is present
290 */ 350 */
291int 351struct GNUNET_GETOPT_CommandLineOption
292GNUNET_GETOPT_set_one (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, 352GNUNET_GETOPT_OPTION_INCREMENT_VALUE (char shortName,
293 void *scls, const char *option, const char *value); 353 const char *name,
354 const char *description,
355 unsigned int *val);
294 356
295 357
296/** 358/**
297 * Set an option of type 'char *' from the command line. 359 * Define the '-L' log level option. Note that we do not check
298 * A pointer to this function should be passed as part of the 360 * that the log level is valid here.
299 * `struct GNUNET_GETOPT_CommandLineOption` array to initialize options
300 * of this type. It should be followed by a pointer to a value of
301 * type `char *`, which will be allocated with the requested string.
302 * 361 *
303 * @param ctx command line processing context 362 * @param[out] level set to the log level
304 * @param scls additional closure (will point to the `char *`,
305 * which will be allocated)
306 * @param option name of the option
307 * @param value actual value of the option (a string)
308 * @return #GNUNET_OK (always)
309 */ 363 */
310int 364struct GNUNET_GETOPT_CommandLineOption
311GNUNET_GETOPT_set_string (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, 365GNUNET_GETOPT_OPTION_LOGLEVEL (char **level);
312 void *scls, const char *option, const char *value);
313 366
314 367
315/** 368/**
316 * Set an option of type 'char *' from the command line doing fs expansion. 369 * Define the '-V' verbosity option. Using the option more
317 * A pointer to this function should be passed as part of the 370 * than once increments @a level each time.
318 * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options
319 * of this type. It should be followed by a pointer to a value of
320 * type 'char *', which will be allocated with the requested string.
321 * 371 *
322 * @param ctx command line processing context 372 * @param[out] level set to the verbosity level
323 * @param scls additional closure (will point to the 'char *',
324 * which will be allocated)
325 * @param option name of the option
326 * @param value actual value of the option (a string)
327 * @return #GNUNET_OK (always)
328 */ 373 */
329int 374struct GNUNET_GETOPT_CommandLineOption
330GNUNET_GETOPT_set_filename (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, 375GNUNET_GETOPT_OPTION_VERBOSE (unsigned int *level);
331 void *scls, const char *option, const char *value); 376
332 377
333/** 378/**
334 * Set an option of type 'unsigned int' from the command line. Each 379 * Allow user to specify log file name (-l option)
335 * time the option flag is given, the value is incremented by one.
336 * A pointer to this function should be passed as part of the
337 * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options
338 * of this type. It should be followed by a pointer to a value of
339 * type 'int'.
340 * 380 *
341 * @param ctx command line processing context 381 * @param[out] logfn set to the name of the logfile
342 * @param scls additional closure (will point to the 'int')
343 * @param option name of the option
344 * @param value not used (NULL)
345 * @return #GNUNET_OK (always)
346 */ 382 */
347int 383struct GNUNET_GETOPT_CommandLineOption
348GNUNET_GETOPT_increment_value (struct GNUNET_GETOPT_CommandLineProcessorContext 384GNUNET_GETOPT_OPTION_LOGFILE (char **logfn);
349 *ctx, void *scls, const char *option,
350 const char *value);
351 385
352 386
353/* *************** internal prototypes - use macros above! ************* */ 387/**
388 * Allow user to specify configuration file name (-c option)
389 *
390 * @param[out] fn set to the name of the configuration file
391 */
392struct GNUNET_GETOPT_CommandLineOption
393GNUNET_GETOPT_OPTION_CFG_FILE (char **fn);
394
354 395
355/** 396/**
356 * Print out details on command line options (implements --help). 397 * Make the given option mandatory.
357 * 398 *
358 * @param ctx command line processing context 399 * @param opt option to modify
359 * @param scls additional closure (points to about text) 400 * @return @a opt with the mandatory flag set.
360 * @param option name of the option
361 * @param value not used (NULL)
362 * @return #GNUNET_NO (do not continue, not an error)
363 */ 401 */
364int 402struct GNUNET_GETOPT_CommandLineOption
365GNUNET_GETOPT_format_help_ (struct GNUNET_GETOPT_CommandLineProcessorContext 403GNUNET_GETOPT_OPTION_MANDATORY (struct GNUNET_GETOPT_CommandLineOption opt);
366 *ctx, void *scls, const char *option, 404
367 const char *value);
368 405
369/** 406/**
370 * Print out program version (implements --version). 407 * Marker for the end of the list of options.
408 */
409#define GNUNET_GETOPT_OPTION_END \
410 { '\0', NULL, NULL, NULL, 0, 0, NULL, NULL, NULL }
411
412
413/**
414 * Parse the command line.
371 * 415 *
372 * @param ctx command line processing context 416 * @param binaryOptions Name of application with option summary
373 * @param scls additional closure (points to version string) 417 * @param allOptions defined options and handlers
374 * @param option name of the option 418 * @param argc number of arguments in @a argv
375 * @param value not used (NULL) 419 * @param argv actual arguments
376 * @return #GNUNET_NO (do not continue, not an error) 420 * @return index into argv with first non-option
421 * argument, or #GNUNET_SYSERR on error
377 */ 422 */
378int 423int
379GNUNET_GETOPT_print_version_ (struct GNUNET_GETOPT_CommandLineProcessorContext 424GNUNET_GETOPT_run (const char *binaryOptions,
380 *ctx, void *scls, const char *option, 425 const struct GNUNET_GETOPT_CommandLineOption *allOptions,
381 const char *value); 426 unsigned int argc,
427 char *const *argv);
428
382 429
383#if 0 /* keep Emacsens' auto-indent happy */ 430#if 0 /* keep Emacsens' auto-indent happy */
384{ 431{
diff --git a/src/include/gnunet_helper_lib.h b/src/include/gnunet_helper_lib.h
index db0ca98aa..60b3ff681 100644
--- a/src/include/gnunet_helper_lib.h
+++ b/src/include/gnunet_helper_lib.h
@@ -38,7 +38,8 @@
38#define GNUNET_HELPER_LIB_H 38#define GNUNET_HELPER_LIB_H
39 39
40#include "gnunet_scheduler_lib.h" 40#include "gnunet_scheduler_lib.h"
41#include "gnunet_server_lib.h" 41#include "gnunet_mst_lib.h"
42
42 43
43/** 44/**
44 * The handle to a helper process. 45 * The handle to a helper process.
@@ -52,7 +53,8 @@ struct GNUNET_HELPER_Handle;
52 * 53 *
53 * @param cls the closure from GNUNET_HELPER_start() 54 * @param cls the closure from GNUNET_HELPER_start()
54 */ 55 */
55typedef void (*GNUNET_HELPER_ExceptionCallback) (void *cls); 56typedef void
57(*GNUNET_HELPER_ExceptionCallback) (void *cls);
56 58
57 59
58/** 60/**
@@ -75,7 +77,7 @@ struct GNUNET_HELPER_Handle *
75GNUNET_HELPER_start (int with_control_pipe, 77GNUNET_HELPER_start (int with_control_pipe,
76 const char *binary_name, 78 const char *binary_name,
77 char *const binary_argv[], 79 char *const binary_argv[],
78 GNUNET_SERVER_MessageTokenizerCallback cb, 80 GNUNET_MessageTokenizerCallback cb,
79 GNUNET_HELPER_ExceptionCallback exp_cb, 81 GNUNET_HELPER_ExceptionCallback exp_cb,
80 void *cb_cls); 82 void *cb_cls);
81 83
diff --git a/src/include/gnunet_json_lib.h b/src/include/gnunet_json_lib.h
index 9e5f9e284..ce721d8d8 100644
--- a/src/include/gnunet_json_lib.h
+++ b/src/include/gnunet_json_lib.h
@@ -427,6 +427,26 @@ void
427GNUNET_JSON_post_parser_cleanup (void *con_cls); 427GNUNET_JSON_post_parser_cleanup (void *con_cls);
428 428
429 429
430/* ****************** GETOPT JSON helper ******************* */
431
432
433/**
434 * Allow user to specify a JSON input value.
435 *
436 * @param shortName short name of the option
437 * @param name long name of the option
438 * @param argumentHelp help text for the option argument
439 * @param description long help text for the option
440 * @param[out] val set to the JSON specified at the command line
441 */
442struct GNUNET_GETOPT_CommandLineOption
443GNUNET_JSON_getopt (char shortName,
444 const char *name,
445 const char *argumentHelp,
446 const char *description,
447 json_t **json);
448
449
430#endif 450#endif
431 451
432/* end of gnunet_json_lib.h */ 452/* end of gnunet_json_lib.h */
diff --git a/src/include/gnunet_mq_lib.h b/src/include/gnunet_mq_lib.h
index b05128ccc..ecee1b223 100644
--- a/src/include/gnunet_mq_lib.h
+++ b/src/include/gnunet_mq_lib.h
@@ -35,6 +35,7 @@
35#ifndef GNUNET_MQ_LIB_H 35#ifndef GNUNET_MQ_LIB_H
36#define GNUNET_MQ_LIB_H 36#define GNUNET_MQ_LIB_H
37 37
38#include "gnunet_scheduler_lib.h"
38 39
39/** 40/**
40 * Allocate an envelope, with extra space allocated after the space needed 41 * Allocate an envelope, with extra space allocated after the space needed
diff --git a/src/include/gnunet_multicast_service.h b/src/include/gnunet_multicast_service.h
index 3829a7040..5645207dd 100644
--- a/src/include/gnunet_multicast_service.h
+++ b/src/include/gnunet_multicast_service.h
@@ -617,6 +617,7 @@ GNUNET_MULTICAST_origin_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
617 * data. If 0 is returned in @a data_size the transmission is paused, 617 * data. If 0 is returned in @a data_size the transmission is paused,
618 * and can be resumed with GNUNET_MULTICAST_origin_to_all_resume(). 618 * and can be resumed with GNUNET_MULTICAST_origin_to_all_resume().
619 * #GNUNET_YES if this completes the transmission (all data supplied) 619 * #GNUNET_YES if this completes the transmission (all data supplied)
620 * @deprecated should move to MQ-style API!
620 */ 621 */
621typedef int 622typedef int
622(*GNUNET_MULTICAST_OriginTransmitNotify) (void *cls, 623(*GNUNET_MULTICAST_OriginTransmitNotify) (void *cls,
@@ -647,6 +648,7 @@ struct GNUNET_MULTICAST_OriginTransmitHandle;
647 * Closure for @a notify. 648 * Closure for @a notify.
648 * 649 *
649 * @return NULL on error (i.e. request already pending). 650 * @return NULL on error (i.e. request already pending).
651 * @deprecated should move to MQ-style API!
650 */ 652 */
651struct GNUNET_MULTICAST_OriginTransmitHandle * 653struct GNUNET_MULTICAST_OriginTransmitHandle *
652GNUNET_MULTICAST_origin_to_all (struct GNUNET_MULTICAST_Origin *origin, 654GNUNET_MULTICAST_origin_to_all (struct GNUNET_MULTICAST_Origin *origin,
@@ -854,6 +856,7 @@ GNUNET_MULTICAST_member_part (struct GNUNET_MULTICAST_Member *member,
854 * data. If 0 is returned in @a data_size the transmission is paused, 856 * data. If 0 is returned in @a data_size the transmission is paused,
855 * and can be resumed with GNUNET_MULTICAST_member_to_origin_resume(). 857 * and can be resumed with GNUNET_MULTICAST_member_to_origin_resume().
856 * #GNUNET_YES if this completes the transmission (all data supplied) 858 * #GNUNET_YES if this completes the transmission (all data supplied)
859 * @deprecated should move to MQ-style API!
857 */ 860 */
858typedef int 861typedef int
859(*GNUNET_MULTICAST_MemberTransmitNotify) (void *cls, 862(*GNUNET_MULTICAST_MemberTransmitNotify) (void *cls,
@@ -880,6 +883,7 @@ struct GNUNET_MULTICAST_MemberTransmitHandle;
880 * Closure for @a notify. 883 * Closure for @a notify.
881 * 884 *
882 * @return Handle to cancel request, NULL on error (i.e. request already pending). 885 * @return Handle to cancel request, NULL on error (i.e. request already pending).
886 * @deprecated should move to MQ-style API!
883 */ 887 */
884struct GNUNET_MULTICAST_MemberTransmitHandle * 888struct GNUNET_MULTICAST_MemberTransmitHandle *
885GNUNET_MULTICAST_member_to_origin (struct GNUNET_MULTICAST_Member *member, 889GNUNET_MULTICAST_member_to_origin (struct GNUNET_MULTICAST_Member *member,
diff --git a/src/include/gnunet_peerstore_service.h b/src/include/gnunet_peerstore_service.h
index 3cafe70b8..c636447c2 100644
--- a/src/include/gnunet_peerstore_service.h
+++ b/src/include/gnunet_peerstore_service.h
@@ -86,7 +86,7 @@ struct GNUNET_PEERSTORE_Record
86 /** 86 /**
87 * Peer Identity 87 * Peer Identity
88 */ 88 */
89 struct GNUNET_PeerIdentity *peer; 89 struct GNUNET_PeerIdentity peer;
90 90
91 /** 91 /**
92 * Record key string 92 * Record key string
@@ -106,7 +106,7 @@ struct GNUNET_PEERSTORE_Record
106 /** 106 /**
107 * Expiry time of entry 107 * Expiry time of entry
108 */ 108 */
109 struct GNUNET_TIME_Absolute *expiry; 109 struct GNUNET_TIME_Absolute expiry;
110 110
111 /** 111 /**
112 * Client from which this record originated. 112 * Client from which this record originated.
diff --git a/src/include/gnunet_server_lib.h b/src/include/gnunet_server_lib.h
deleted file mode 100644
index 5da31bcd7..000000000
--- a/src/include/gnunet_server_lib.h
+++ /dev/null
@@ -1,887 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-2013 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21/**
22 * @author Christian Grothoff
23 *
24 * @file
25 * Library for building GNUnet network servers
26
27 * @defgroup server Server library
28 * Library for building GNUnet network servers
29 *
30 * Provides functions for a server that communicates with clients.
31 *
32 * @see [Documentation](https://gnunet.org/ipc)
33 *
34 * @{
35 */
36
37#ifndef GNUNET_SERVER_LIB_H
38#define GNUNET_SERVER_LIB_H
39
40#ifdef __cplusplus
41extern "C"
42{
43#if 0 /* keep Emacsens' auto-indent happy */
44}
45#endif
46#endif
47
48#include "gnunet_common.h"
49#include "gnunet_connection_lib.h"
50
51
52/**
53 * Largest supported message (to be precise, one byte more
54 * than the largest possible message, so tests involving
55 * this value should check for messages being smaller than
56 * this value).
57 */
58#define GNUNET_SERVER_MAX_MESSAGE_SIZE 65536
59
60/**
61 * Smallest supported message.
62 */
63#define GNUNET_SERVER_MIN_BUFFER_SIZE sizeof (struct GNUNET_MessageHeader)
64
65/**
66 * @brief handle for a server
67 */
68struct GNUNET_SERVER_Handle;
69
70/**
71 * @brief opaque handle for a client of the server
72 */
73struct GNUNET_SERVER_Client;
74
75/**
76 * @brief opaque handle server returns for aborting transmission to a client.
77 */
78struct GNUNET_SERVER_TransmitHandle;
79
80
81/**
82 * Functions with this signature are called whenever a message is
83 * received.
84 *
85 * @param cls closure
86 * @param client identification of the client
87 * @param message the actual message
88 */
89typedef void
90(*GNUNET_SERVER_MessageCallback) (void *cls,
91 struct GNUNET_SERVER_Client *client,
92 const struct GNUNET_MessageHeader *message);
93
94
95/**
96 * Message handler. Each struct specifies how to handle on particular
97 * type of message received.
98 */
99struct GNUNET_SERVER_MessageHandler
100{
101 /**
102 * Function to call for messages of "type".
103 */
104 GNUNET_SERVER_MessageCallback callback;
105
106 /**
107 * Closure argument for @e callback.
108 */
109 void *callback_cls;
110
111 /**
112 * Type of the message this handler covers.
113 */
114 uint16_t type;
115
116 /**
117 * Expected size of messages of this type. Use 0 for
118 * variable-size. If non-zero, messages of the given
119 * type will be discarded (and the connection closed)
120 * if they do not have the right size.
121 */
122 uint16_t expected_size;
123
124};
125
126
127/**
128 * Create a new server.
129 *
130 * @param access_cb function for access control
131 * @param access_cb_cls closure for @a access_cb
132 * @param lsocks NULL-terminated array of listen sockets
133 * @param idle_timeout after how long should we timeout idle connections?
134 * @param require_found if #GNUNET_YES, connections sending messages of unknown type
135 * will be closed
136 * @return handle for the new server, NULL on error
137 * (typically, "port" already in use)
138 */
139struct GNUNET_SERVER_Handle *
140GNUNET_SERVER_create_with_sockets (GNUNET_CONNECTION_AccessCheck access_cb,
141 void *access_cb_cls,
142 struct GNUNET_NETWORK_Handle **lsocks,
143 struct GNUNET_TIME_Relative idle_timeout,
144 int require_found);
145
146/**
147 * Create a new server.
148 *
149 * @param access_cb function for access control
150 * @param access_cb_cls closure for @a access_cb
151 * @param server_addr address toes listen on (including port), NULL terminated array
152 * @param socklen lengths of respective @a server_addr
153 * @param idle_timeout after how long should we timeout idle connections?
154 * @param require_found if #GNUNET_YES, connections sending messages of unknown type
155 * will be closed
156 * @return handle for the new server, NULL on error
157 * (typically, "port" already in use)
158 */
159struct GNUNET_SERVER_Handle *
160GNUNET_SERVER_create (GNUNET_CONNECTION_AccessCheck access_cb,
161 void *access_cb_cls,
162 struct sockaddr *const *server_addr,
163 const socklen_t *socklen,
164 struct GNUNET_TIME_Relative idle_timeout,
165 int require_found);
166
167
168/**
169 * Suspend accepting connections from the listen socket temporarily.
170 * Resume activity using #GNUNET_SERVER_resume.
171 *
172 * @param server server to stop accepting connections.
173 */
174void
175GNUNET_SERVER_suspend (struct GNUNET_SERVER_Handle *server);
176
177
178/**
179 * Resume accepting connections from the listen socket.
180 *
181 * @param server server to resume accepting connections.
182 */
183void
184GNUNET_SERVER_resume (struct GNUNET_SERVER_Handle *server);
185
186
187/**
188 * Stop the listen socket and get ready to shutdown the server once
189 * only clients marked using #GNUNET_SERVER_client_mark_monitor are
190 * left.
191 *
192 * @param server server to stop listening on
193 */
194void
195GNUNET_SERVER_stop_listening (struct GNUNET_SERVER_Handle *server);
196
197
198/**
199 * Free resources held by this server.
200 *
201 * @param server server to destroy
202 */
203void
204GNUNET_SERVER_destroy (struct GNUNET_SERVER_Handle *server);
205
206
207/**
208 * Add additional handlers to an existing server.
209 *
210 * @param server the server to add handlers to
211 * @param handlers array of message handlers for
212 * incoming messages; the last entry must
213 * have "NULL" for the "callback"; multiple
214 * entries for the same type are allowed,
215 * they will be called in order of occurence.
216 * These handlers can be removed later;
217 * the handlers array must exist until removed
218 * (or server is destroyed).
219 */
220void
221GNUNET_SERVER_add_handlers (struct GNUNET_SERVER_Handle *server,
222 const struct GNUNET_SERVER_MessageHandler *handlers);
223
224
225/**
226 * Notify us when the server has enough space to transmit
227 * a message of the given size to the given client.
228 *
229 * @param client client to transmit message to
230 * @param size requested amount of buffer space
231 * @param timeout after how long should we give up (and call
232 * notify with buf NULL and size 0)?
233 * @param callback function to call when space is available
234 * @param callback_cls closure for @a callback
235 * @return non-NULL if the notify callback was queued; can be used
236 * to cancel the request using
237 * #GNUNET_SERVER_notify_transmit_ready_cancel.
238 * NULL if we are already going to notify someone else (busy)
239 */
240struct GNUNET_SERVER_TransmitHandle *
241GNUNET_SERVER_notify_transmit_ready (struct GNUNET_SERVER_Client *client,
242 size_t size,
243 struct GNUNET_TIME_Relative timeout,
244 GNUNET_CONNECTION_TransmitReadyNotify callback,
245 void *callback_cls);
246
247
248/**
249 * Abort transmission request.
250 *
251 * @param th request to abort
252 */
253void
254GNUNET_SERVER_notify_transmit_ready_cancel (struct GNUNET_SERVER_TransmitHandle *th);
255
256
257/**
258 * Set the 'monitor' flag on this client. Clients which have been
259 * marked as 'monitors' won't prevent the server from shutting down
260 * once #GNUNET_SERVER_stop_listening has been invoked. The idea is
261 * that for "normal" clients we likely want to allow them to process
262 * their requests; however, monitor-clients are likely to 'never'
263 * disconnect during shutdown and thus will not be considered when
264 * determining if the server should continue to exist after
265 * #GNUNET_SERVER_destroy has been called.
266 *
267 * @param client the client to set the 'monitor' flag on
268 */
269void
270GNUNET_SERVER_client_mark_monitor (struct GNUNET_SERVER_Client *client);
271
272
273/**
274 * Set the persistent flag on this client, used to setup client
275 * connection to only be killed when the process of the service it's
276 * connected to is actually dead. This API is used during shutdown
277 * signalling within ARM, and it is not expected that typical users
278 * of the API would need this function.
279 *
280 * @param client the client to set the persistent flag on
281 */
282void
283GNUNET_SERVER_client_persist_ (struct GNUNET_SERVER_Client *client);
284
285
286/**
287 * Resume receiving from this client, we are done processing the
288 * current request. This function must be called from within each
289 * #GNUNET_SERVER_MessageCallback (or its respective continuations).
290 *
291 * @param client client we were processing a message of
292 * @param success #GNUNET_OK to keep the connection open and
293 * continue to receive
294 * #GNUNET_NO to close the connection (normal behavior)
295 * #GNUNET_SYSERR to close the connection (signal
296 * serious error)
297 */
298void
299GNUNET_SERVER_receive_done (struct GNUNET_SERVER_Client *client,
300 int success);
301
302
303/**
304 * Change the timeout for a particular client. Decreasing the timeout
305 * may not go into effect immediately (only after the previous timeout
306 * times out or activity happens on the socket).
307 *
308 * @param client the client to update
309 * @param timeout new timeout for activities on the socket
310 */
311void
312GNUNET_SERVER_client_set_timeout (struct GNUNET_SERVER_Client *client,
313 struct GNUNET_TIME_Relative timeout);
314
315
316/**
317 * Return user context associated with the given client.
318 * Note: you should probably use the macro (call without the underscore).
319 *
320 * @param client client to query
321 * @param size number of bytes in user context struct (for verification only)
322 * @return pointer to user context
323 */
324void *
325GNUNET_SERVER_client_get_user_context_ (struct GNUNET_SERVER_Client *client,
326 size_t size);
327
328
329/**
330 * Set user context to be associated with the given client.
331 * Note: you should probably use the macro (call without the underscore).
332 *
333 * @param client client to query
334 * @param ptr pointer to user context
335 * @param size number of bytes in user context struct (for verification only)
336 */
337void
338GNUNET_SERVER_client_set_user_context_ (struct GNUNET_SERVER_Client *client,
339 void *ptr,
340 size_t size);
341
342
343/**
344 * Return user context associated with the given client.
345 *
346 * @param client client to query
347 * @param type expected return type (i.e. 'struct Foo')
348 * @return pointer to user context of type 'type *'.
349 */
350#define GNUNET_SERVER_client_get_user_context(client,type) \
351 (type *) GNUNET_SERVER_client_get_user_context_ (client, sizeof (type))
352
353/**
354 * Set user context to be associated with the given client.
355 *
356 * @param client client to query
357 * @param value pointer to user context
358 */
359#define GNUNET_SERVER_client_set_user_context(client,value) \
360 GNUNET_SERVER_client_set_user_context_ (client, value, sizeof (*value))
361
362
363/**
364 * Disable the warning the server issues if a message is not acknowledged
365 * in a timely fashion. Use this call if a client is intentionally delayed
366 * for a while. Only applies to the current message.
367 *
368 * @param client client for which to disable the warning
369 */
370void
371GNUNET_SERVER_disable_receive_done_warning (struct GNUNET_SERVER_Client
372 *client);
373
374
375/**
376 * Inject a message into the server, pretend it came
377 * from the specified client. Delivery of the message
378 * will happen instantly (if a handler is installed;
379 * otherwise the call does nothing).
380 *
381 * @param server the server receiving the message
382 * @param sender the "pretended" sender of the message
383 * can be NULL!
384 * @param message message to transmit
385 * @return #GNUNET_OK if the message was OK and the
386 * connection can stay open
387 * #GNUNET_SYSERR if the connection to the
388 * client should be shut down
389 */
390int
391GNUNET_SERVER_inject (struct GNUNET_SERVER_Handle *server,
392 struct GNUNET_SERVER_Client *sender,
393 const struct GNUNET_MessageHeader *message);
394
395
396/**
397 * Add a TCP socket-based connection to the set of handles managed by
398 * this server. Use this function for outgoing (P2P) connections that
399 * we initiated (and where this server should process incoming
400 * messages).
401 *
402 * @param server the server to use
403 * @param connection the connection to manage (client must
404 * stop using this connection from now on)
405 * @return the client handle
406 */
407struct GNUNET_SERVER_Client *
408GNUNET_SERVER_connect_socket (struct GNUNET_SERVER_Handle *server,
409 struct GNUNET_CONNECTION_Handle *connection);
410
411
412/**
413 * Notify the server that the given client handle should
414 * be kept (keeps the connection up if possible, increments
415 * the internal reference counter).
416 *
417 * @param client the client to keep
418 */
419void
420GNUNET_SERVER_client_keep (struct GNUNET_SERVER_Client *client);
421
422
423/**
424 * Notify the server that the given client handle is no
425 * longer required. Decrements the reference counter. If
426 * that counter reaches zero an inactive connection maybe
427 * closed.
428 *
429 * @param client the client to drop
430 */
431void
432GNUNET_SERVER_client_drop (struct GNUNET_SERVER_Client *client);
433
434
435/**
436 * Obtain the network address of the other party.
437 *
438 * @param client the client to get the address for
439 * @param addr where to store the address
440 * @param addrlen where to store the length of @a addr
441 * @return #GNUNET_OK on success
442 */
443int
444GNUNET_SERVER_client_get_address (struct GNUNET_SERVER_Client *client,
445 void **addr, size_t *addrlen);
446
447
448/**
449 * Functions with this signature are called whenever a client
450 * is disconnected on the network level.
451 *
452 * @param cls closure
453 * @param client identification of the client; NULL
454 * for the last call when the server is destroyed
455 */
456typedef void
457(*GNUNET_SERVER_DisconnectCallback) (void *cls,
458 struct GNUNET_SERVER_Client *client);
459
460
461/**
462 * Functions with this signature are called whenever a client
463 * is connected on the network level.
464 *
465 * @param cls closure
466 * @param client identification of the client
467 */
468typedef void
469(*GNUNET_SERVER_ConnectCallback) (void *cls,
470 struct GNUNET_SERVER_Client *client);
471
472
473/**
474 * Ask the server to notify us whenever a client disconnects.
475 * This function is called whenever the actual network connection
476 * is closed; the reference count may be zero or larger than zero
477 * at this point. If the server is destroyed before this
478 * notification is explicitly cancelled, the 'callback' will
479 * once be called with a 'client' argument of NULL to indicate
480 * that the server itself is now gone (and that the callback
481 * won't be called anymore and also can no longer be cancelled).
482 *
483 * @param server the server manageing the clients
484 * @param callback function to call on disconnect
485 * @param callback_cls closure for @a callback
486 */
487void
488GNUNET_SERVER_disconnect_notify (struct GNUNET_SERVER_Handle *server,
489 GNUNET_SERVER_DisconnectCallback callback,
490 void *callback_cls);
491
492
493/**
494 * Ask the server to notify us whenever a client connects.
495 * This function is called whenever the actual network connection
496 * is opened. If the server is destroyed before this
497 * notification is explicitly cancelled, the @a callback will
498 * once be called with a 'client' argument of NULL to indicate
499 * that the server itself is now gone (and that the callback
500 * won't be called anymore and also can no longer be cancelled).
501 *
502 * @param server the server manageing the clients
503 * @param callback function to call on sconnect
504 * @param callback_cls closure for @a callback
505 */
506void
507GNUNET_SERVER_connect_notify (struct GNUNET_SERVER_Handle *server,
508 GNUNET_SERVER_ConnectCallback callback,
509 void *callback_cls);
510
511
512/**
513 * Ask the server to stop notifying us whenever a client disconnects.
514 * Arguments must match exactly those given to
515 * #GNUNET_SERVER_disconnect_notify. It is not necessary to call this
516 * function during shutdown of the server; in fact, most applications
517 * will never use this function.
518 *
519 * @param server the server manageing the clients
520 * @param callback function to call on disconnect
521 * @param callback_cls closure for @a callback
522 */
523void
524GNUNET_SERVER_disconnect_notify_cancel (struct GNUNET_SERVER_Handle *server,
525 GNUNET_SERVER_DisconnectCallback callback,
526 void *callback_cls);
527
528
529/**
530 * Ask the server to stop notifying us whenever a client connects.
531 * Arguments must match exactly those given to
532 * #GNUNET_SERVER_connect_notify. It is not necessary to call this
533 * function during shutdown of the server; in fact, most applications
534 * will never use this function.
535 *
536 * @param server the server manageing the clients
537 * @param callback function to call on connect
538 * @param callback_cls closure for @a callback
539 */
540void
541GNUNET_SERVER_connect_notify_cancel (struct GNUNET_SERVER_Handle *server,
542 GNUNET_SERVER_ConnectCallback callback,
543 void *callback_cls);
544
545
546/**
547 * Ask the server to disconnect from the given client. This is the
548 * same as passing #GNUNET_SYSERR to #GNUNET_SERVER_receive_done,
549 * except that it allows dropping of a client even when not handling a
550 * message from that client.
551 *
552 * @param client the client to disconnect from
553 */
554void
555GNUNET_SERVER_client_disconnect (struct GNUNET_SERVER_Client *client);
556
557
558/**
559 * Disable the "CORK" feature for communication with the given client,
560 * forcing the OS to immediately flush the buffer on transmission
561 * instead of potentially buffering multiple messages.
562 *
563 * @param client handle to the client
564 * @return #GNUNET_OK on success
565 */
566int
567GNUNET_SERVER_client_disable_corking (struct GNUNET_SERVER_Client *client);
568
569
570/**
571 * The tansmit context is the key datastructure for a conveniance API
572 * used for transmission of complex results to the client followed
573 * ONLY by signaling receive_done with success or error
574 */
575struct GNUNET_SERVER_TransmitContext;
576
577
578/**
579 * Create a new transmission context for the given client.
580 *
581 * @param client client to create the context for.
582 * @return NULL on error
583 */
584struct GNUNET_SERVER_TransmitContext *
585GNUNET_SERVER_transmit_context_create (struct GNUNET_SERVER_Client *client);
586
587
588/**
589 * Append a message to the transmission context.
590 * All messages in the context will be sent by
591 * the #GNUNET_SERVER_transmit_context_run method.
592 *
593 * @param tc context to use
594 * @param data what to append to the result message
595 * @param length length of @a data
596 * @param type type of the message
597 */
598void
599GNUNET_SERVER_transmit_context_append_data (struct GNUNET_SERVER_TransmitContext *tc,
600 const void *data,
601 size_t length, uint16_t type);
602
603
604/**
605 * Append a message to the transmission context.
606 * All messages in the context will be sent by
607 * the transmit_context_run method.
608 *
609 * @param tc context to use
610 * @param msg message to append
611 */
612void
613GNUNET_SERVER_transmit_context_append_message (struct GNUNET_SERVER_TransmitContext *tc,
614 const struct GNUNET_MessageHeader *msg);
615
616
617/**
618 * Execute a transmission context. If there is an error in the
619 * transmission, the receive_done method will be called with an error
620 * code (#GNUNET_SYSERR), otherwise with #GNUNET_OK.
621 *
622 * @param tc transmission context to use
623 * @param timeout when to time out and abort the transmission
624 */
625void
626GNUNET_SERVER_transmit_context_run (struct GNUNET_SERVER_TransmitContext *tc,
627 struct GNUNET_TIME_Relative timeout);
628
629
630/**
631 * Destroy a transmission context. This function must not be called
632 * after #GNUNET_SERVER_transmit_context_run.
633 *
634 * @param tc transmission context to destroy
635 * @param success code to give to #GNUNET_SERVER_receive_done for
636 * the client: #GNUNET_OK to keep the connection open and
637 * continue to receive
638 * #GNUNET_NO to close the connection (normal behavior)
639 * #GNUNET_SYSERR to close the connection (signal
640 * serious error)
641 */
642void
643GNUNET_SERVER_transmit_context_destroy (struct GNUNET_SERVER_TransmitContext *tc,
644 int success);
645
646
647/**
648 * The notification context is the key datastructure for a conveniance
649 * API used for transmission of notifications to the client until the
650 * client disconnects or is disconnected (or the notification context
651 * is destroyed, in which case we disconnect these clients).
652 * Essentially, all (notification) messages are queued up until the
653 * client is able to read them.
654 */
655struct GNUNET_SERVER_NotificationContext;
656
657
658/**
659 * Create a new notification context.
660 *
661 * @param server server for which this function creates the context
662 * @param queue_length maximum number of messages to keep in
663 * the notification queue; optional messages are dropped
664 * if the queue gets longer than this number of messages
665 * @return handle to the notification context
666 */
667struct GNUNET_SERVER_NotificationContext *
668GNUNET_SERVER_notification_context_create (struct GNUNET_SERVER_Handle *server,
669 unsigned int queue_length);
670
671
672/**
673 * Destroy the context, force disconnect for all clients.
674 *
675 * @param nc context to destroy.
676 */
677void
678GNUNET_SERVER_notification_context_destroy (struct GNUNET_SERVER_NotificationContext *nc);
679
680
681/**
682 * Add a client to the notification context.
683 *
684 * @param nc context to modify
685 * @param client client to add
686 */
687void
688GNUNET_SERVER_notification_context_add (struct GNUNET_SERVER_NotificationContext *nc,
689 struct GNUNET_SERVER_Client *client);
690
691
692/**
693 * Send a message to a particular client; must have
694 * already been added to the notification context.
695 *
696 * @param nc context to modify
697 * @param client client to transmit to
698 * @param msg message to send
699 * @param can_drop can this message be dropped due to queue length limitations
700 */
701void
702GNUNET_SERVER_notification_context_unicast (struct GNUNET_SERVER_NotificationContext *nc,
703 struct GNUNET_SERVER_Client *client,
704 const struct GNUNET_MessageHeader *msg,
705 int can_drop);
706
707
708/**
709 * Send a message to all clients of this context.
710 *
711 * @param nc context to modify
712 * @param msg message to send
713 * @param can_drop can this message be dropped due to queue length limitations
714 */
715void
716GNUNET_SERVER_notification_context_broadcast (struct GNUNET_SERVER_NotificationContext *nc,
717 const struct GNUNET_MessageHeader *msg,
718 int can_drop);
719
720
721/**
722 * Return active number of subscribers in this context.
723 *
724 * @param nc context to query
725 * @return number of current subscribers
726 */
727unsigned int
728GNUNET_SERVER_notification_context_get_size (struct GNUNET_SERVER_NotificationContext *nc);
729
730
731/**
732 * Create a message queue for a server's client.
733 *
734 * @param client the client
735 * @return the message queue
736 */
737struct GNUNET_MQ_Handle *
738GNUNET_MQ_queue_for_server_client (struct GNUNET_SERVER_Client *client);
739
740
741/**
742 * Handle to a message stream tokenizer.
743 */
744struct GNUNET_SERVER_MessageStreamTokenizer;
745
746
747/**
748 * Functions with this signature are called whenever a
749 * complete message is received by the tokenizer.
750 *
751 * Do not call #GNUNET_SERVER_mst_destroy from within
752 * the scope of this callback.
753 *
754 * @param cls closure
755 * @param client identification of the client
756 * @param message the actual message
757 * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing
758 */
759typedef int
760(*GNUNET_SERVER_MessageTokenizerCallback) (void *cls,
761 void *client,
762 const struct GNUNET_MessageHeader *message);
763
764
765/**
766 * Create a message stream tokenizer.
767 *
768 * @param cb function to call on completed messages
769 * @param cb_cls closure for @a cb
770 * @return handle to tokenizer
771 */
772struct GNUNET_SERVER_MessageStreamTokenizer *
773GNUNET_SERVER_mst_create (GNUNET_SERVER_MessageTokenizerCallback cb,
774 void *cb_cls);
775
776
777/**
778 * Add incoming data to the receive buffer and call the
779 * callback for all complete messages.
780 *
781 * @param mst tokenizer to use
782 * @param client_identity ID of client for which this is a buffer,
783 * can be NULL (will be passed back to 'cb')
784 * @param buf input data to add
785 * @param size number of bytes in @a buf
786 * @param purge should any excess bytes in the buffer be discarded
787 * (i.e. for packet-based services like UDP)
788 * @param one_shot only call callback once, keep rest of message in buffer
789 * @return #GNUNET_OK if we are done processing (need more data)
790 * #GNUNET_NO if one_shot was set and we have another message ready
791 * #GNUNET_SYSERR if the data stream is corrupt
792 */
793int
794GNUNET_SERVER_mst_receive (struct GNUNET_SERVER_MessageStreamTokenizer *mst,
795 void *client_identity,
796 const char *buf, size_t size,
797 int purge, int one_shot);
798
799
800/**
801 * Destroys a tokenizer.
802 *
803 * @param mst tokenizer to destroy
804 */
805void
806GNUNET_SERVER_mst_destroy (struct GNUNET_SERVER_MessageStreamTokenizer *mst);
807
808
809/**
810 * Signature of a function to create a custom tokenizer.
811 *
812 * @param cls closure from #GNUNET_SERVER_set_callbacks
813 * @param client handle to client the tokenzier will be used for
814 * @return handle to custom tokenizer ('mst')
815 */
816typedef void*
817(*GNUNET_SERVER_MstCreateCallback) (void *cls,
818 struct GNUNET_SERVER_Client *client);
819
820
821/**
822 * Signature of a function to destroy a custom tokenizer.
823 *
824 * @param cls closure from #GNUNET_SERVER_set_callbacks
825 * @param mst custom tokenizer handle
826 */
827typedef void
828(*GNUNET_SERVER_MstDestroyCallback) (void *cls,
829 void *mst);
830
831
832/**
833 * Signature of a function to receive data for a custom tokenizer.
834 *
835 * @param cls closure from #GNUNET_SERVER_set_callbacks
836 * @param mst custom tokenizer handle
837 * @param client_identity ID of client for which this is a buffer,
838 * can be NULL (will be passed back to 'cb')
839 * @param buf input data to add
840 * @param size number of bytes in @a buf
841 * @param purge should any excess bytes in the buffer be discarded
842 * (i.e. for packet-based services like UDP)
843 * @param one_shot only call callback once, keep rest of message in buffer
844 * @return #GNUNET_OK if we are done processing (need more data)
845 * #GNUNET_NO if one_shot was set and we have another message ready
846 * #GNUNET_SYSERR if the data stream is corrupt
847 */
848typedef int
849(*GNUNET_SERVER_MstReceiveCallback) (void *cls, void *mst,
850 struct GNUNET_SERVER_Client *client,
851 const char *buf,
852 size_t size,
853 int purge,
854 int one_shot);
855
856
857/**
858 * Change functions used by the server to tokenize the message stream.
859 * (very rarely used).
860 *
861 * @param server server to modify
862 * @param create new tokenizer initialization function
863 * @param destroy new tokenizer destruction function
864 * @param receive new tokenizer receive function
865 * @param cls closure for @a create, @a receive and @a destroy
866 */
867void
868GNUNET_SERVER_set_callbacks (struct GNUNET_SERVER_Handle *server,
869 GNUNET_SERVER_MstCreateCallback create,
870 GNUNET_SERVER_MstDestroyCallback destroy,
871 GNUNET_SERVER_MstReceiveCallback receive,
872 void *cls);
873
874
875#if 0 /* keep Emacsens' auto-indent happy */
876{
877#endif
878#ifdef __cplusplus
879}
880#endif
881
882/* ifndef GNUNET_SERVER_LIB_H */
883#endif
884
885/** @} */ /* end of group server */
886
887/* end of gnunet_server_lib.h */
diff --git a/src/include/gnunet_service_lib.h b/src/include/gnunet_service_lib.h
index 75b880530..aacafe956 100644
--- a/src/include/gnunet_service_lib.h
+++ b/src/include/gnunet_service_lib.h
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 Copyright (C) 2009-2013, 2016 GNUnet e.V. 3 Copyright (C) 2009-2013, 2016, 2017 GNUnet e.V.
4 4
5 GNUnet is free software; you can redistribute it and/or modify 5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published 6 it under the terms of the GNU General Public License as published
@@ -44,25 +44,10 @@ extern "C"
44#endif 44#endif
45 45
46#include "gnunet_configuration_lib.h" 46#include "gnunet_configuration_lib.h"
47#include "gnunet_server_lib.h"
48#include "gnunet_mq_lib.h" 47#include "gnunet_mq_lib.h"
49 48
50 49
51/** 50/**
52 * Function called by the service's run
53 * method to run service-specific setup code.
54 *
55 * @param cls closure
56 * @param server the initialized server
57 * @param cfg configuration to use
58 */
59typedef void
60(*GNUNET_SERVICE_Main) (void *cls,
61 struct GNUNET_SERVER_Handle *server,
62 const struct GNUNET_CONFIGURATION_Handle *cfg);
63
64
65/**
66 * Options for the service (bitmask). 51 * Options for the service (bitmask).
67 */ 52 */
68enum GNUNET_SERVICE_Options 53enum GNUNET_SERVICE_Options
@@ -88,84 +73,6 @@ enum GNUNET_SERVICE_Options
88}; 73};
89 74
90 75
91/**
92 * Run a standard GNUnet service startup sequence (initialize loggers
93 * and configuration, parse options).
94 *
95 * @param argc number of command line arguments in @a argv
96 * @param argv command line arguments
97 * @param service_name our service name
98 * @param options service options
99 * @param task main task of the service
100 * @param task_cls closure for @a task
101 * @return #GNUNET_SYSERR on error, #GNUNET_OK
102 * if we shutdown nicely
103 * @deprecated
104 */
105int
106GNUNET_SERVICE_run (int argc,
107 char *const *argv,
108 const char *service_name,
109 enum GNUNET_SERVICE_Options options,
110 GNUNET_SERVICE_Main task,
111 void *task_cls);
112
113
114/**
115 * Opaque handle for a service.
116 */
117struct GNUNET_SERVICE_Context;
118
119
120/**
121 * Run a service startup sequence within an existing
122 * initialized system.
123 *
124 * @param service_name our service name
125 * @param cfg configuration to use
126 * @param options service options
127 * @return NULL on error, service handle
128 * @deprecated
129 */
130struct GNUNET_SERVICE_Context *
131GNUNET_SERVICE_start (const char *service_name,
132 const struct GNUNET_CONFIGURATION_Handle *cfg,
133 enum GNUNET_SERVICE_Options options);
134
135
136/**
137 * Obtain the server used by a service. Note that the server must NOT
138 * be destroyed by the caller.
139 *
140 * @param ctx the service context returned from the start function
141 * @return handle to the server for this service, NULL if there is none
142 * @deprecated
143 */
144struct GNUNET_SERVER_Handle *
145GNUNET_SERVICE_get_server (struct GNUNET_SERVICE_Context *ctx);
146
147
148/**
149 * Get the NULL-terminated array of listen sockets for this service.
150 *
151 * @param ctx service context to query
152 * @return NULL if there are no listen sockets, otherwise NULL-terminated
153 * array of listen sockets.
154 * @deprecated
155 */
156struct GNUNET_NETWORK_Handle *const *
157GNUNET_SERVICE_get_listen_sockets (struct GNUNET_SERVICE_Context *ctx);
158
159
160/**
161 * Stop a service that was started with #GNUNET_SERVICE_start.
162 *
163 * @param sctx the service context returned from the start function
164 * @deprecated
165 */
166void
167GNUNET_SERVICE_stop (struct GNUNET_SERVICE_Context *sctx);
168
169 76
170/* **************** NEW SERVICE API ********************** */ 77/* **************** NEW SERVICE API ********************** */
171 78
@@ -245,7 +152,7 @@ typedef void
245 * dropped. Additionally, clients can be dropped at any time using 152 * dropped. Additionally, clients can be dropped at any time using
246 * #GNUNET_SERVICE_client_drop(). 153 * #GNUNET_SERVICE_client_drop().
247 * 154 *
248 * The service must be stopped using #GNUNET_SERVICE_stoP(). 155 * The service must be stopped using #GNUNET_SERVICE_stop().
249 * 156 *
250 * @param service_name name of the service to run 157 * @param service_name name of the service to run
251 * @param cfg configuration to use 158 * @param cfg configuration to use
@@ -258,7 +165,7 @@ typedef void
258 * @return NULL on error 165 * @return NULL on error
259 */ 166 */
260struct GNUNET_SERVICE_Handle * 167struct GNUNET_SERVICE_Handle *
261GNUNET_SERVICE_starT (const char *service_name, 168GNUNET_SERVICE_start (const char *service_name,
262 const struct GNUNET_CONFIGURATION_Handle *cfg, 169 const struct GNUNET_CONFIGURATION_Handle *cfg,
263 GNUNET_SERVICE_ConnectHandler connect_cb, 170 GNUNET_SERVICE_ConnectHandler connect_cb,
264 GNUNET_SERVICE_DisconnectHandler disconnect_cb, 171 GNUNET_SERVICE_DisconnectHandler disconnect_cb,
@@ -267,12 +174,12 @@ GNUNET_SERVICE_starT (const char *service_name,
267 174
268 175
269/** 176/**
270 * Stops a service that was started with #GNUNET_SERVICE_starT(). 177 * Stops a service that was started with #GNUNET_SERVICE_start().
271 * 178 *
272 * @param srv service to stop 179 * @param srv service to stop
273 */ 180 */
274void 181void
275GNUNET_SERVICE_stoP (struct GNUNET_SERVICE_Handle *srv); 182GNUNET_SERVICE_stop (struct GNUNET_SERVICE_Handle *srv);
276 183
277 184
278/** 185/**
@@ -317,7 +224,7 @@ GNUNET_SERVICE_stoP (struct GNUNET_SERVICE_Handle *srv);
317 * @return 0 on success, non-zero on error 224 * @return 0 on success, non-zero on error
318 */ 225 */
319int 226int
320GNUNET_SERVICE_ruN_ (int argc, 227GNUNET_SERVICE_run_ (int argc,
321 char *const *argv, 228 char *const *argv,
322 const char *service_name, 229 const char *service_name,
323 enum GNUNET_SERVICE_Options options, 230 enum GNUNET_SERVICE_Options options,
@@ -393,7 +300,7 @@ GNUNET_SERVICE_ruN_ (int argc,
393 struct GNUNET_MQ_MessageHandler mh[] = { \ 300 struct GNUNET_MQ_MessageHandler mh[] = { \
394 __VA_ARGS__ \ 301 __VA_ARGS__ \
395 }; \ 302 }; \
396 return GNUNET_SERVICE_ruN_ (argc, \ 303 return GNUNET_SERVICE_run_ (argc, \
397 argv, \ 304 argv, \
398 service_name, \ 305 service_name, \
399 service_options, \ 306 service_options, \
diff --git a/src/include/gnunet_sq_lib.h b/src/include/gnunet_sq_lib.h
index c03f83e07..c196d7767 100644
--- a/src/include/gnunet_sq_lib.h
+++ b/src/include/gnunet_sq_lib.h
@@ -182,6 +182,29 @@ GNUNET_SQ_query_param_uint64 (const uint64_t *x);
182 182
183 183
184/** 184/**
185 * Execute binding operations for a prepared statement.
186 *
187 * @param db_conn database connection
188 * @param params parameters to the statement
189 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
190 */
191int
192GNUNET_SQ_bind (sqlite3_stmt *stmt,
193 const struct GNUNET_SQ_QueryParam *params);
194
195
196/**
197 * Reset @a stmt and log error.
198 *
199 * @param dbh database handle
200 * @param stmt statement to reset
201 */
202void
203GNUNET_SQ_reset (sqlite3 *dbh,
204 sqlite3_stmt *stmt);
205
206
207/**
185 * Extract data from a Postgres database @a result at row @a row. 208 * Extract data from a Postgres database @a result at row @a row.
186 * 209 *
187 * @param cls closure 210 * @param cls closure
@@ -400,18 +423,6 @@ GNUNET_SQ_result_spec_uint64 (uint64_t *u64);
400 423
401 424
402/** 425/**
403 * Execute a prepared statement.
404 *
405 * @param db_conn database connection
406 * @param params parameters to the statement
407 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
408 */
409int
410GNUNET_SQ_bind (sqlite3_stmt *stmt,
411 const struct GNUNET_SQ_QueryParam *params);
412
413
414/**
415 * Extract results from a query result according to the given specification. 426 * Extract results from a query result according to the given specification.
416 * 427 *
417 * @param result result to process 428 * @param result result to process
diff --git a/src/include/gnunet_util_lib.h b/src/include/gnunet_util_lib.h
index 52f5d8ab2..a9bd6c33f 100644
--- a/src/include/gnunet_util_lib.h
+++ b/src/include/gnunet_util_lib.h
@@ -38,10 +38,24 @@ extern "C"
38#endif 38#endif
39#endif 39#endif
40 40
41
42/**
43 * Largest supported message (to be precise, one byte more
44 * than the largest possible message, so tests involving
45 * this value should check for messages being smaller than
46 * this value).
47 */
48#define GNUNET_MAX_MESSAGE_SIZE 65536
49
50/**
51 * Smallest supported message.
52 */
53#define GNUNET_MIN_MESSAGE_SIZE sizeof (struct GNUNET_MessageHeader)
54
55
41#include "gnunet_crypto_lib.h" 56#include "gnunet_crypto_lib.h"
42#include "gnunet_bandwidth_lib.h" 57#include "gnunet_bandwidth_lib.h"
43#include "gnunet_bio_lib.h" 58#include "gnunet_bio_lib.h"
44#include "gnunet_connection_lib.h"
45#include "gnunet_client_lib.h" 59#include "gnunet_client_lib.h"
46#include "gnunet_container_lib.h" 60#include "gnunet_container_lib.h"
47#include "gnunet_getopt_lib.h" 61#include "gnunet_getopt_lib.h"
@@ -55,7 +69,6 @@ extern "C"
55#include "gnunet_plugin_lib.h" 69#include "gnunet_plugin_lib.h"
56#include "gnunet_program_lib.h" 70#include "gnunet_program_lib.h"
57#include "gnunet_protocols.h" 71#include "gnunet_protocols.h"
58#include "gnunet_server_lib.h"
59#include "gnunet_service_lib.h" 72#include "gnunet_service_lib.h"
60#include "gnunet_signal_lib.h" 73#include "gnunet_signal_lib.h"
61#include "gnunet_strings_lib.h" 74#include "gnunet_strings_lib.h"
diff --git a/src/include/platform.h b/src/include/platform.h
index add58821f..6095d0258 100644
--- a/src/include/platform.h
+++ b/src/include/platform.h
@@ -110,6 +110,7 @@
110#include <stdlib.h> 110#include <stdlib.h>
111#include <stdint.h> 111#include <stdint.h>
112#include <stdarg.h> 112#include <stdarg.h>
113#include <stdbool.h>
113#include <errno.h> 114#include <errno.h>
114#include <signal.h> 115#include <signal.h>
115#include <libgen.h> 116#include <libgen.h>
diff --git a/src/integration-tests/confs/test_defaults.conf b/src/integration-tests/confs/test_defaults.conf
index 8d3356cbc..1be582650 100644
--- a/src/integration-tests/confs/test_defaults.conf
+++ b/src/integration-tests/confs/test_defaults.conf
@@ -1,5 +1,5 @@
1@INLINE@ ../../contrib/no_forcestart.conf 1@INLINE@ ../../../contrib/no_forcestart.conf
2@INLINE@ ../../contrib/no_autostart_above_core.conf 2@INLINE@ ../../../contrib/no_autostart_above_core.conf
3 3
4[fs] 4[fs]
5FORCESTART = YES 5FORCESTART = YES
diff --git a/src/json/json.c b/src/json/json.c
index a2d1a9608..c182a02f4 100644
--- a/src/json/json.c
+++ b/src/json/json.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet 2 This file is part of GNUnet
3 Copyright (C) 2014, 2015, 2016 GNUnet e.V. 3 Copyright (C) 2014-2017 GNUnet e.V.
4 4
5 GNUnet is free software; you can redistribute it and/or modify it under the 5 GNUnet is free software; you can redistribute it and/or modify it under the
6 terms of the GNU General Public License as published by the Free Software 6 terms of the GNU General Public License as published by the Free Software
@@ -82,13 +82,78 @@ GNUNET_JSON_parse (const json_t *root,
82void 82void
83GNUNET_JSON_parse_free (struct GNUNET_JSON_Specification *spec) 83GNUNET_JSON_parse_free (struct GNUNET_JSON_Specification *spec)
84{ 84{
85 unsigned int i; 85 for (unsigned int i=0;NULL != spec[i].parser;i++)
86
87 for (i=0;NULL != spec[i].parser;i++)
88 if (NULL != spec[i].cleaner) 86 if (NULL != spec[i].cleaner)
89 spec[i].cleaner (spec[i].cls, 87 spec[i].cleaner (spec[i].cls,
90 &spec[i]); 88 &spec[i]);
91} 89}
92 90
93 91
92/**
93 * Set an option with a JSON value from the command line.
94 * A pointer to this function should be passed as part of the
95 * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options
96 * of this type.
97 *
98 * @param ctx command line processing context
99 * @param scls additional closure (will point to the 'json_t *')
100 * @param option name of the option
101 * @param value actual value of the option as a string.
102 * @return #GNUNET_OK if parsing the value worked
103 */
104static int
105set_json (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
106 void *scls,
107 const char *option,
108 const char *value)
109{
110 json_t **json = scls;
111 json_error_t error;
112
113 *json = json_loads (value,
114 JSON_REJECT_DUPLICATES,
115 &error);
116 if (NULL == *json)
117 {
118 FPRINTF (stderr,
119 _("Failed to parse JSON in option `%s': %s (%s)\n"),
120 option,
121 error.text,
122 error.source);
123 return GNUNET_SYSERR;
124 }
125 return GNUNET_OK;
126}
127
128
129/**
130 * Allow user to specify a JSON input value.
131 *
132 * @param shortName short name of the option
133 * @param name long name of the option
134 * @param argumentHelp help text for the option argument
135 * @param description long help text for the option
136 * @param[out] val set to the JSON specified at the command line
137 */
138struct GNUNET_GETOPT_CommandLineOption
139GNUNET_JSON_getopt (char shortName,
140 const char *name,
141 const char *argumentHelp,
142 const char *description,
143 json_t **json)
144{
145 struct GNUNET_GETOPT_CommandLineOption clo = {
146 .shortName = shortName,
147 .name = name,
148 .argumentHelp = argumentHelp,
149 .description = description,
150 .require_argument = 1,
151 .processor = &set_json,
152 .scls = (void *) json
153 };
154
155 return clo;
156}
157
158
94/* end of json.c */ 159/* end of json.c */
diff --git a/src/multicast/.gitignore b/src/multicast/.gitignore
index d38ca9c02..43752ec4b 100644
--- a/src/multicast/.gitignore
+++ b/src/multicast/.gitignore
@@ -2,3 +2,4 @@ gnunet-service-multicast
2gnunet-multicast 2gnunet-multicast
3test_multicast 3test_multicast
4test_multicast_multipeer 4test_multicast_multipeer
5test_multicast_2peers
diff --git a/src/multicast/Makefile.am b/src/multicast/Makefile.am
index 61821d973..1a61abb09 100644
--- a/src/multicast/Makefile.am
+++ b/src/multicast/Makefile.am
@@ -33,7 +33,8 @@ bin_PROGRAMS = \
33 gnunet-multicast 33 gnunet-multicast
34 34
35libexec_PROGRAMS = \ 35libexec_PROGRAMS = \
36 gnunet-service-multicast 36 gnunet-service-multicast \
37 $(EXP_LIBEXEC)
37 38
38gnunet_multicast_SOURCES = \ 39gnunet_multicast_SOURCES = \
39 gnunet-multicast.c 40 gnunet-multicast.c
@@ -45,17 +46,17 @@ gnunet_service_multicast_SOURCES = \
45 gnunet-service-multicast.c 46 gnunet-service-multicast.c
46gnunet_service_multicast_LDADD = \ 47gnunet_service_multicast_LDADD = \
47 $(top_builddir)/src/util/libgnunetutil.la \ 48 $(top_builddir)/src/util/libgnunetutil.la \
48 $(top_builddir)/src/cadet/libgnunetcadetnew.la \ 49 $(top_builddir)/src/cadet/libgnunetcadet.la \
49 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 50 $(top_builddir)/src/statistics/libgnunetstatistics.la \
50 $(GN_LIBINTL) 51 $(GN_LIBINTL)
51 52
52
53check_PROGRAMS = \ 53check_PROGRAMS = \
54 test_multicast \ 54 test_multicast \
55 test_multicast_multipeer 55 test_multicast_2peers
56# test_multicast_multipeer
56 57
57if ENABLE_TEST_RUN 58if ENABLE_TEST_RUN
58AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@}; export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; unset XDG_DATA_HOME; unset XDG_CONFIG_HOME; export GNUNET_FORCE_LOG=';;;;INFO' 59AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@}; export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; unset XDG_DATA_HOME; unset XDG_CONFIG_HOME; export GNUNET_FORCE_LOG=';;;;INFO';
59TESTS = $(check_PROGRAMS) 60TESTS = $(check_PROGRAMS)
60endif 61endif
61 62
@@ -66,9 +67,9 @@ test_multicast_LDADD = \
66 $(top_builddir)/src/testing/libgnunettesting.la \ 67 $(top_builddir)/src/testing/libgnunettesting.la \
67 $(top_builddir)/src/util/libgnunetutil.la 68 $(top_builddir)/src/util/libgnunetutil.la
68 69
69test_multicast_multipeer_SOURCE = \ 70test_multicast_2peers_SOURCE = \
70 test_multicast_multipeer.c 71 test_multicast_2peers.c
71test_multicast_multipeer_LDADD = \ 72test_multicast_2peers_LDADD = \
72 libgnunetmulticast.la \ 73 libgnunetmulticast.la \
73 $(top_builddir)/src/testbed/libgnunettestbed.la \ 74 $(top_builddir)/src/testbed/libgnunettestbed.la \
74 $(top_builddir)/src/util/libgnunetutil.la 75 $(top_builddir)/src/util/libgnunetutil.la
diff --git a/src/multicast/gnunet-service-multicast.c b/src/multicast/gnunet-service-multicast.c
index 3f356af83..9683efcff 100644
--- a/src/multicast/gnunet-service-multicast.c
+++ b/src/multicast/gnunet-service-multicast.c
@@ -1302,7 +1302,7 @@ cadet_channel_create (struct Group *grp, struct GNUNET_PeerIdentity *peer)
1302 GNUNET_MQ_handler_end () 1302 GNUNET_MQ_handler_end ()
1303 }; 1303 };
1304 1304
1305 chn->channel = GNUNET_CADET_channel_creatE (cadet, chn, &chn->peer, 1305 chn->channel = GNUNET_CADET_channel_create (cadet, chn, &chn->peer,
1306 &grp->cadet_port_hash, 1306 &grp->cadet_port_hash,
1307 GNUNET_CADET_OPTION_RELIABLE, 1307 GNUNET_CADET_OPTION_RELIABLE,
1308 cadet_notify_window_change, 1308 cadet_notify_window_change,
@@ -1392,7 +1392,7 @@ handle_client_origin_start (void *cls,
1392 }; 1392 };
1393 1393
1394 1394
1395 orig->cadet_port = GNUNET_CADET_open_porT (cadet, 1395 orig->cadet_port = GNUNET_CADET_open_port (cadet,
1396 &grp->cadet_port_hash, 1396 &grp->cadet_port_hash,
1397 cadet_notify_connect, 1397 cadet_notify_connect,
1398 NULL, 1398 NULL,
@@ -2085,7 +2085,7 @@ run (void *cls,
2085 replay_req_cadet = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); 2085 replay_req_cadet = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
2086 replay_req_client = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); 2086 replay_req_client = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
2087 2087
2088 cadet = GNUNET_CADET_connecT (cfg); 2088 cadet = GNUNET_CADET_connect (cfg);
2089 2089
2090 GNUNET_assert (NULL != cadet); 2090 GNUNET_assert (NULL != cadet);
2091 2091
diff --git a/src/multicast/test_multicast.conf b/src/multicast/test_multicast.conf
index 675776bbc..3081aeecc 100644
--- a/src/multicast/test_multicast.conf
+++ b/src/multicast/test_multicast.conf
@@ -1,4 +1,12 @@
1[testbed]
2HOSTNAME = localhost
3
1[arm] 4[arm]
2GLOBAL_POSTFIX=-L ERROR 5GLOBAL_POSTFIX=-L ERROR
3 6
4#PREFIX = sakura -t test-multicast -e cgdb --args 7[multicast]
8#PREFIX = xterm -T peer -e gdb --args
9UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-multicast.sock
10
11[vpn]
12AUTOSTART = NO
diff --git a/src/multicast/test_multicast_2peers.c b/src/multicast/test_multicast_2peers.c
new file mode 100644
index 000000000..058533e50
--- /dev/null
+++ b/src/multicast/test_multicast_2peers.c
@@ -0,0 +1,511 @@
1/*
2 * This file is part of GNUnet
3 * Copyright (C) 2013 GNUnet e.V.
4 *
5 * GNUnet is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published
7 * by the Free Software Foundation; either version 3, or (at your
8 * option) any later version.
9 *
10 * GNUnet is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with GNUnet; see the file COPYING. If not, write to the
17 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21/**
22 * @file multicast/test_multicast_2peers.c
23 * @brief Tests for the Multicast API with two peers doing the ping
24 * pong test.
25 * @author xrs
26 */
27
28#include <inttypes.h>
29
30#include "platform.h"
31#include "gnunet_crypto_lib.h"
32#include "gnunet_common.h"
33#include "gnunet_util_lib.h"
34#include "gnunet_testbed_service.h"
35#include "gnunet_multicast_service.h"
36
37#define NUM_PEERS 2
38
39static struct GNUNET_TESTBED_Operation *op0;
40static struct GNUNET_TESTBED_Operation *op1;
41static struct GNUNET_TESTBED_Operation *pi_op0;
42static struct GNUNET_TESTBED_Operation *pi_op1;
43
44static struct GNUNET_TESTBED_Peer **peers;
45const struct GNUNET_PeerIdentity *peer_id[2];
46
47static struct GNUNET_SCHEDULER_Task *timeout_tid;
48
49static struct GNUNET_MULTICAST_Origin *origin;
50static struct GNUNET_MULTICAST_Member *member;
51
52struct GNUNET_CRYPTO_EddsaPrivateKey *group_key;
53struct GNUNET_CRYPTO_EddsaPublicKey group_pub_key;
54
55struct GNUNET_CRYPTO_EcdsaPrivateKey *member_key;
56struct GNUNET_CRYPTO_EcdsaPublicKey member_pub_key;
57
58/**
59 * Global result for testcase.
60 */
61static int result;
62
63
64/**
65 * Function run on CTRL-C or shutdown (i.e. success/timeout/etc.).
66 * Cleans up.
67 */
68static void
69shutdown_task (void *cls)
70{
71 if (NULL != op0)
72 {
73 GNUNET_TESTBED_operation_done (op0);
74 op0 = NULL;
75 }
76 if (NULL != op1)
77 {
78 GNUNET_TESTBED_operation_done (op1);
79 op1 = NULL;
80 }
81 if (NULL != pi_op0)
82 {
83 GNUNET_TESTBED_operation_done (pi_op0);
84 pi_op0 = NULL;
85 }
86 if (NULL != pi_op1)
87 {
88 GNUNET_TESTBED_operation_done (pi_op1);
89 pi_op1 = NULL;
90 }
91 if (NULL != timeout_tid)
92 {
93 GNUNET_SCHEDULER_cancel (timeout_tid);
94 timeout_tid = NULL;
95 }
96}
97
98
99static void
100timeout_task (void *cls)
101{
102 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
103 "Timeout!\n");
104 result = GNUNET_SYSERR;
105 GNUNET_SCHEDULER_shutdown ();
106}
107
108
109static void
110member_join_request (void *cls,
111 const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key,
112 const struct GNUNET_MessageHeader *join_msg,
113 struct GNUNET_MULTICAST_JoinHandle *jh)
114{
115 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
116 "Member sent a join request.\n");
117
118}
119
120
121static int
122notify (void *cls,
123 size_t *data_size,
124 void *data)
125{
126
127 char text[] = "ping";
128 *data_size = strlen(text)+1;
129 GNUNET_memcpy(data, text, *data_size);
130
131 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
132 "Member sents message to origin: %s\n", text);
133
134 return GNUNET_YES;
135}
136
137
138static void
139member_join_decision (void *cls,
140 int is_admitted,
141 const struct GNUNET_PeerIdentity *peer,
142 uint16_t relay_count,
143 const struct GNUNET_PeerIdentity *relays,
144 const struct GNUNET_MessageHeader *join_msg)
145{
146 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
147 "Member received a decision from origin: %s\n",
148 (GNUNET_YES == is_admitted)
149 ? "accepted"
150 : "rejected");
151
152 if (GNUNET_YES == is_admitted)
153 {
154 struct GNUNET_MULTICAST_MemberTransmitHandle *req;
155
156 // FIXME: move to MQ-style API!
157 req = GNUNET_MULTICAST_member_to_origin (member,
158 0,
159 &notify,
160 NULL);
161 }
162}
163
164
165static void
166member_message (void *cls,
167 const struct GNUNET_MULTICAST_MessageHeader *msg)
168{
169 if (0 != strncmp ("pong", (char *)&msg[1], 4))
170 {
171 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "member did not receive pong\n");
172 result = GNUNET_SYSERR;
173 GNUNET_SCHEDULER_shutdown ();
174 }
175
176 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
177 "member receives: %s\n", (char *)&msg[1]);
178
179 // Testcase ends here.
180 result = GNUNET_YES;
181 GNUNET_SCHEDULER_shutdown ();
182}
183
184static void
185origin_join_request (void *cls,
186 const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key,
187 const struct GNUNET_MessageHeader *join_msg,
188 struct GNUNET_MULTICAST_JoinHandle *jh)
189{
190 struct GNUNET_MessageHeader *join_resp;
191
192 uint8_t data_size = ntohs (join_msg->size);
193
194 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
195 "origin got a join request...\n");
196 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
197 "origin receives: '%s'\n", (char *)&join_msg[1]);
198
199 const char data[] = "Come in!";
200 data_size = strlen (data) + 1;
201 join_resp = GNUNET_malloc (sizeof (join_resp) + data_size);
202 join_resp->size = htons (sizeof (join_resp) + data_size);
203 join_resp->type = htons (123);
204 GNUNET_memcpy (&join_resp[1], data, data_size);
205
206 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
207 "origin sends: '%s'\n", data);
208
209 GNUNET_MULTICAST_join_decision (jh,
210 GNUNET_YES,
211 0,
212 NULL,
213 join_resp);
214 GNUNET_free (join_resp);
215 result = GNUNET_OK;
216}
217
218int
219origin_notify (void *cls,
220 size_t *data_size,
221 void *data)
222{
223 char text[] = "pong";
224 *data_size = strlen(text)+1;
225 memcpy(data, text, *data_size);
226
227 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin sends (to all): %s\n", text);
228
229 return GNUNET_YES;
230}
231
232
233static void
234origin_request (void *cls,
235 const struct GNUNET_MULTICAST_RequestHeader *req)
236{
237 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin receives: %s\n", (char *)&req[1]);
238
239 if (0 != strncmp ("ping", (char *)&req[1], 4))
240 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "origin didn't reveice a correct request");
241
242 GNUNET_MULTICAST_origin_to_all (origin,
243 0,
244 0,
245 origin_notify,
246 NULL);
247}
248
249static void
250origin_message (void *cls,
251 const struct GNUNET_MULTICAST_MessageHeader *msg)
252{
253 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin message msg\n");
254}
255
256
257static void
258service_connect1 (void *cls,
259 struct GNUNET_TESTBED_Operation *op,
260 void *ca_result,
261 const char *emsg)
262{
263 member = ca_result;
264
265 if (NULL != member)
266 {
267 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connected to multicast service of member\n");
268 }
269 else
270 {
271 result = GNUNET_SYSERR;
272 GNUNET_SCHEDULER_shutdown ();
273 }
274}
275
276static void
277multicast_da1 (void *cls,
278 void * op_result)
279{
280 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
281 "Member parting from multicast group\n");
282
283 GNUNET_MULTICAST_member_part (member, NULL, NULL);
284}
285
286
287static void *
288multicast_ca1 (void *cls,
289 const struct GNUNET_CONFIGURATION_Handle *cfg)
290{
291 struct GNUNET_MessageHeader *join_msg;
292 void *ret;
293
294 // Get members keys
295 member_key = GNUNET_CRYPTO_ecdsa_key_create ();
296 GNUNET_CRYPTO_ecdsa_key_get_public (member_key, &member_pub_key);
297
298 char data[] = "Hi, can I enter?";
299 uint8_t data_size = strlen (data) + 1;
300 join_msg = GNUNET_malloc (sizeof (join_msg) + data_size);
301 join_msg->size = htons (sizeof (join_msg) + data_size);
302 join_msg->type = htons (123);
303 GNUNET_memcpy (&join_msg[1], data, data_size);
304
305 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
306 "Members tries to join multicast group\n");
307
308 ret = GNUNET_MULTICAST_member_join (cfg,
309 &group_pub_key,
310 member_key,
311 peer_id[0],
312 0,
313 NULL,
314 join_msg, /* join message */
315 member_join_request,
316 member_join_decision,
317 NULL, /* no test for member_replay_frag */
318 NULL, /* no test for member_replay_msg */
319 member_message,
320 NULL);
321 GNUNET_free (join_msg);
322 return ret;
323}
324
325
326static void
327peer_information_cb (void *cls,
328 struct GNUNET_TESTBED_Operation *op,
329 const struct GNUNET_TESTBED_PeerInformation *pinfo,
330 const char *emsg)
331{
332 int i = (int) (long) cls;
333
334 if (NULL == pinfo)
335 {
336 result = GNUNET_SYSERR;
337 GNUNET_SCHEDULER_shutdown ();
338 }
339
340 peer_id[i] = pinfo->result.id;
341
342 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
343 "Got peer information of %s (%s)\n", (0==i)?"origin":"member" ,GNUNET_i2s(pinfo->result.id));
344
345 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
346 "Create member peer\n");
347
348 if (0 == i)
349 {
350 /* connect to multicast service of member */
351 op1 = GNUNET_TESTBED_service_connect (NULL, /* Closure for operation */
352 peers[1], /* The peer whose service to connect to */
353 "multicast", /* The name of the service */
354 service_connect1, /* callback to call after a handle to service
355 is opened */
356 NULL, /* closure for the above callback */
357 multicast_ca1, /* callback to call with peer's configuration;
358 this should open the needed service connection */
359 multicast_da1, /* callback to be called when closing the
360 opened service connection */
361 NULL); /* closure for the above two callbacks */
362 }
363}
364
365/**
366 * Test logic of peer "0" being origin starts here.
367 *
368 * @param cls closure, for the example: NULL
369 * @param op should be equal to "dht_op"
370 * @param ca_result result of the connect operation, the
371 * connection to the DHT service
372 * @param emsg error message, if testbed somehow failed to
373 * connect to the DHT.
374 */
375static void
376service_connect0 (void *cls,
377 struct GNUNET_TESTBED_Operation *op,
378 void *ca_result,
379 const char *emsg)
380{
381 origin = ca_result;
382
383 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
384 "Connected to multicast service of origin\n");
385
386 // Get GNUnet identity of origin
387 pi_op0 = GNUNET_TESTBED_peer_get_information (peers[0],
388 GNUNET_TESTBED_PIT_IDENTITY,
389 peer_information_cb,
390 (void *) 0);
391 // Get GNUnet identity of member
392 pi_op1 = GNUNET_TESTBED_peer_get_information (peers[1],
393 GNUNET_TESTBED_PIT_IDENTITY,
394 peer_information_cb,
395 (void *) 1);
396
397 /* Connection to service successful. Here we'd usually do something with
398 * the service. */
399 result = GNUNET_OK;
400 //GNUNET_SCHEDULER_shutdown (); /* Also kills the testbed */
401}
402
403
404
405/**
406 * Function run when service multicast has started and is providing us
407 * with a configuration file.
408 */
409static void *
410multicast_ca0 (void *cls,
411 const struct GNUNET_CONFIGURATION_Handle *cfg)
412{
413 group_key = GNUNET_CRYPTO_eddsa_key_create ();
414 GNUNET_CRYPTO_eddsa_key_get_public (group_key, &group_pub_key);
415
416 return GNUNET_MULTICAST_origin_start (cfg,
417 group_key,
418 0,
419 origin_join_request,
420 NULL, /* no test for origin_replay_frag */
421 NULL, /* no test for origin_replay_msg */
422 origin_request,
423 origin_message,
424 NULL);
425}
426
427static void
428multicast_da0 (void *cls,
429 void *op_result)
430{
431 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
432 "Origin closes multicast group\n");
433
434 GNUNET_MULTICAST_origin_stop (origin, NULL, NULL);
435}
436
437
438/**
439 * Main function inovked from TESTBED once all of the
440 * peers are up and running. This one then connects
441 * just to the multicast service of peer 0 and 1.
442 * Peer 0 is going to be origin.
443 * Peer 1 is going to be one member.
444 * Origin will start a multicast group and the member will try to join it.
445 * After that we execute some multicast test.
446 *
447 * @param cls closure
448 * @param h the run handle
449 * @param peers started peers for the test
450 * @param num_peers size of the 'peers' array
451 * @param links_succeeded number of links between peers that were created
452 * @param links_failed number of links testbed was unable to establish
453 */
454static void
455testbed_master (void *cls,
456 struct GNUNET_TESTBED_RunHandle *h,
457 unsigned int num_peers,
458 struct GNUNET_TESTBED_Peer **p,
459 unsigned int links_succeeded,
460 unsigned int links_failed)
461{
462 /* Testbed is ready with peers running and connected in a pre-defined overlay
463 topology (FIXME) */
464 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
465 "Connected to testbed_master()\n");
466
467 peers = p;
468
469 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
470 "Create origin peer\n");
471 op0 = GNUNET_TESTBED_service_connect (NULL, /* Closure for operation */
472 peers[0], /* The peer whose service to connect to */
473 "multicast", /* The name of the service */
474 service_connect0, /* callback to call after a handle to service
475 is opened */
476 NULL, /* closure for the above callback */
477 multicast_ca0, /* callback to call with peer's configuration;
478 this should open the needed service connection */
479 multicast_da0, /* callback to be called when closing the
480 opened service connection */
481 NULL); /* closure for the above two callbacks */
482
483 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); /* Schedule a new task on shutdown */
484
485 /* Schedule the shutdown task with a delay of a few Seconds */
486 timeout_tid = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 50),
487 &timeout_task, NULL);
488}
489
490
491int
492main (int argc, char *argv[])
493{
494 int ret;
495
496 result = GNUNET_SYSERR;
497 ret = GNUNET_TESTBED_test_run
498 ("test-multicast-multipeer", /* test case name */
499 "test_multicast.conf", /* template configuration */
500 NUM_PEERS, /* number of peers to start */
501 0LL, /* Event mask - set to 0 for no event notifications */
502 NULL, /* Controller event callback */
503 NULL, /* Closure for controller event callback */
504 testbed_master, /* continuation callback to be called when testbed setup is complete */
505 NULL); /* Closure for the test_master callback */
506 if ( (GNUNET_OK != ret) || (GNUNET_OK != result) )
507 return 1;
508 return 0;
509}
510
511/* end of test_multicast_multipeer.c */
diff --git a/src/multicast/test_multicast_multipeer.c b/src/multicast/test_multicast_multipeer.c
index 1b76737f4..58e43d4ba 100644
--- a/src/multicast/test_multicast_multipeer.c
+++ b/src/multicast/test_multicast_multipeer.c
@@ -107,7 +107,6 @@ shutdown_task (void *cls)
107static void 107static void
108timeout_task (void *cls) 108timeout_task (void *cls)
109{ 109{
110 timeout_tid = NULL;
111 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 110 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
112 "Timeout!\n"); 111 "Timeout!\n");
113 result = GNUNET_SYSERR; 112 result = GNUNET_SYSERR;
@@ -126,6 +125,21 @@ member_join_request (void *cls,
126 125
127} 126}
128 127
128int notify (void *cls,
129 size_t *data_size,
130 void *data)
131{
132
133 char text[] = "ping";
134 *data_size = strlen(text)+1;
135 GNUNET_memcpy(data, text, *data_size);
136
137 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
138 "Member sents message to origin: %s\n", text);
139
140 return GNUNET_YES;
141}
142
129 143
130static void 144static void
131member_join_decision (void *cls, 145member_join_decision (void *cls,
@@ -135,11 +149,19 @@ member_join_decision (void *cls,
135 const struct GNUNET_PeerIdentity *relays, 149 const struct GNUNET_PeerIdentity *relays,
136 const struct GNUNET_MessageHeader *join_msg) 150 const struct GNUNET_MessageHeader *join_msg)
137{ 151{
138 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 152 struct GNUNET_MULTICAST_MemberTransmitHandle *req;
153
154 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
139 "Member received a decision from origin: %s\n", (GNUNET_YES == is_admitted)?"accepted":"rejected"); 155 "Member received a decision from origin: %s\n", (GNUNET_YES == is_admitted)?"accepted":"rejected");
140 156
141 result = GNUNET_OK; 157 if (GNUNET_YES == is_admitted)
142 GNUNET_SCHEDULER_shutdown (); 158 {
159 req = GNUNET_MULTICAST_member_to_origin (member,
160 0,
161 notify,
162 NULL);
163
164 }
143} 165}
144 166
145static void 167static void
@@ -161,6 +183,10 @@ member_message ()
161{ 183{
162 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 184 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
163 "member message...\n"); 185 "member message...\n");
186
187 // FIXME: not finished here
188 result = GNUNET_YES;
189 GNUNET_SCHEDULER_shutdown ();
164} 190}
165 191
166static void 192static void
@@ -173,20 +199,21 @@ origin_join_request (void *cls,
173 199
174 uint8_t data_size = ntohs (join_msg->size); 200 uint8_t data_size = ntohs (join_msg->size);
175 201
176 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 202 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
177 "Dizzy: Mh, got a join request...\n"); 203 "origin got a join request...\n");
178 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 204 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
179 "'%s'\n", (char *)&join_msg[1]); 205 "origin receives: '%s'\n", (char *)&join_msg[1]);
180 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
181 "Dizzy: Oh, it's Bird! Let's get him in.\n");
182 206
183 char data[] = "Hi, Bird. Come in!"; 207 char data[] = "Come in!";
184 data_size = strlen (data) + 1; 208 data_size = strlen (data) + 1;
185 join_resp = GNUNET_malloc (sizeof (join_resp) + data_size); 209 join_resp = GNUNET_malloc (sizeof (join_resp) + data_size);
186 join_resp->size = htons (sizeof (join_resp) + data_size); 210 join_resp->size = htons (sizeof (join_resp) + data_size);
187 join_resp->type = htons (123); 211 join_resp->type = htons (123);
188 GNUNET_memcpy (&join_resp[1], data, data_size); 212 GNUNET_memcpy (&join_resp[1], data, data_size);
189 213
214 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
215 "origin sends: '%s'\n", data);
216
190 GNUNET_MULTICAST_join_decision (jh, 217 GNUNET_MULTICAST_join_decision (jh,
191 GNUNET_YES, 218 GNUNET_YES,
192 0, 219 0,
@@ -198,37 +225,62 @@ origin_join_request (void *cls,
198 225
199static void 226static void
200origin_replay_frag (void *cls, 227origin_replay_frag (void *cls,
201 const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key, 228 const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key,
202 uint64_t fragment_id, 229 uint64_t fragment_id,
203 uint64_t flags, 230 uint64_t flags,
204 struct GNUNET_MULTICAST_ReplayHandle *rh) 231 struct GNUNET_MULTICAST_ReplayHandle *rh)
205{ 232{
206 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin replay fraq msg\n"); 233 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin replay fraq msg\n");
207} 234}
208 235
209static void 236static void
210origin_replay_msg (void *cls, 237origin_replay_msg (void *cls,
211 const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key, 238 const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key,
212 uint64_t message_id, 239 uint64_t message_id,
213 uint64_t fragment_offset, 240 uint64_t fragment_offset,
214 uint64_t flags, 241 uint64_t flags,
215 struct GNUNET_MULTICAST_ReplayHandle *rh) 242 struct GNUNET_MULTICAST_ReplayHandle *rh)
216{ 243{
217 244
218 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin replay msg\n"); 245 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin replay msg\n");
219} 246}
220 247
248
249int
250origin_notify (void *cls,
251 size_t *data_size,
252 void *data)
253{
254 char text[] = "pong";
255 *data_size = strlen(text)+1;
256 memcpy(data, text, *data_size);
257
258 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin sends (to all): %s\n", text);
259
260 return GNUNET_YES;
261}
262
263
221static void 264static void
222origin_request (void *cls, 265origin_request (void *cls,
223 const struct GNUNET_MULTICAST_RequestHeader *req) 266 const struct GNUNET_MULTICAST_RequestHeader *req)
224{ 267{
225 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin request msg\n"); 268 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin receives: %s\n", (char *)&req[1]);
269
270 if (0 != strncmp ("ping", (char *)&req[1], 4)) {
271 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "origin didn't reveice a correct request");
272 }
226 273
274 GNUNET_MULTICAST_origin_to_all (origin,
275 0,
276 0,
277 origin_notify,
278 NULL);
227} 279}
228 280
229static void 281static void
230origin_message (void *cls, 282origin_message (void *cls,
231 const struct GNUNET_MULTICAST_MessageHeader *msg) 283 const struct GNUNET_MULTICAST_MessageHeader *msg)
232{ 284{
233 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin message msg\n"); 285 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin message msg\n");
234} 286}
@@ -268,8 +320,8 @@ multicast_ca1 (void *cls,
268 // Get members keys 320 // Get members keys
269 member_key = GNUNET_CRYPTO_ecdsa_key_create (); 321 member_key = GNUNET_CRYPTO_ecdsa_key_create ();
270 GNUNET_CRYPTO_ecdsa_key_get_public (member_key, &member_pub_key); 322 GNUNET_CRYPTO_ecdsa_key_get_public (member_key, &member_pub_key);
271 323
272 char data[] = "Whut's up, Dizzy!"; 324 char data[] = "Hi, can I enter?";
273 uint8_t data_size = strlen (data) + 1; 325 uint8_t data_size = strlen (data) + 1;
274 join_msg = GNUNET_malloc (sizeof (join_msg) + data_size); 326 join_msg = GNUNET_malloc (sizeof (join_msg) + data_size);
275 join_msg->size = htons (sizeof (join_msg) + data_size); 327 join_msg->size = htons (sizeof (join_msg) + data_size);
@@ -453,7 +505,7 @@ testbed_master (void *cls,
453 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); /* Schedule a new task on shutdown */ 505 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); /* Schedule a new task on shutdown */
454 506
455 /* Schedule the shutdown task with a delay of a few Seconds */ 507 /* Schedule the shutdown task with a delay of a few Seconds */
456 timeout_tid = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 40), 508 timeout_tid = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 48),
457 &timeout_task, NULL); 509 &timeout_task, NULL);
458} 510}
459 511
diff --git a/src/namecache/Makefile.am b/src/namecache/Makefile.am
index 89d7bffee..d379b2602 100644
--- a/src/namecache/Makefile.am
+++ b/src/namecache/Makefile.am
@@ -121,6 +121,7 @@ libgnunet_plugin_namecache_sqlite_la_SOURCES = \
121 plugin_namecache_sqlite.c 121 plugin_namecache_sqlite.c
122libgnunet_plugin_namecache_sqlite_la_LIBADD = \ 122libgnunet_plugin_namecache_sqlite_la_LIBADD = \
123 libgnunetnamecache.la \ 123 libgnunetnamecache.la \
124 $(top_builddir)/src/sq/libgnunetsq.la \
124 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 125 $(top_builddir)/src/statistics/libgnunetstatistics.la \
125 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lsqlite3 \ 126 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lsqlite3 \
126 $(LTLIBINTL) 127 $(LTLIBINTL)
@@ -172,4 +173,3 @@ EXTRA_DIST = \
172 test_plugin_namecache_sqlite.conf \ 173 test_plugin_namecache_sqlite.conf \
173 test_plugin_namecache_postgres.conf \ 174 test_plugin_namecache_postgres.conf \
174 test_plugin_namecache_flat.conf 175 test_plugin_namecache_flat.conf
175
diff --git a/src/namecache/gnunet-namecache.c b/src/namecache/gnunet-namecache.c
index 490197b1e..2410c9b3c 100644
--- a/src/namecache/gnunet-namecache.c
+++ b/src/namecache/gnunet-namecache.c
@@ -225,13 +225,19 @@ run (void *cls, char *const *args, const char *cfgfile,
225int 225int
226main (int argc, char *const *argv) 226main (int argc, char *const *argv)
227{ 227{
228 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 228 struct GNUNET_GETOPT_CommandLineOption options[] = {
229 {'n', "name", "NAME", 229 GNUNET_GETOPT_OPTION_STRING ('n',
230 gettext_noop ("name of the record to add/delete/display"), 1, 230 "name",
231 &GNUNET_GETOPT_set_string, &name}, 231 "NAME",
232 {'z', "zone", "PKEY", 232 gettext_noop ("name of the record to add/delete/display"),
233 gettext_noop ("spezifies the public key of the zone to look in"), 1, 233 &name),
234 &GNUNET_GETOPT_set_string, &pkey}, 234
235 GNUNET_GETOPT_OPTION_STRING ('z',
236 "zone",
237 "PKEY",
238 gettext_noop ("spezifies the public key of the zone to look in"),
239 &pkey),
240
235 GNUNET_GETOPT_OPTION_END 241 GNUNET_GETOPT_OPTION_END
236 }; 242 };
237 243
diff --git a/src/namecache/plugin_namecache_sqlite.c b/src/namecache/plugin_namecache_sqlite.c
index fdce899fa..2f7b2a981 100644
--- a/src/namecache/plugin_namecache_sqlite.c
+++ b/src/namecache/plugin_namecache_sqlite.c
@@ -25,6 +25,7 @@
25 */ 25 */
26 26
27#include "platform.h" 27#include "platform.h"
28#include "gnunet_sq_lib.h"
28#include "gnunet_namecache_plugin.h" 29#include "gnunet_namecache_plugin.h"
29#include "gnunet_namecache_service.h" 30#include "gnunet_namecache_service.h"
30#include "gnunet_gnsrecord_lib.h" 31#include "gnunet_gnsrecord_lib.h"
@@ -241,25 +242,28 @@ database_setup (struct Plugin *plugin)
241 sqlite3_finalize (stmt); 242 sqlite3_finalize (stmt);
242 create_indices (plugin->dbh); 243 create_indices (plugin->dbh);
243 244
244 if ((sq_prepare 245 if ( (SQLITE_OK !=
245 (plugin->dbh, 246 sq_prepare (plugin->dbh,
246 "INSERT INTO ns096blocks (query,block,expiration_time) VALUES (?, ?, ?)", 247 "INSERT INTO ns096blocks (query,block,expiration_time) VALUES (?, ?, ?)",
247 &plugin->cache_block) != SQLITE_OK) || 248 &plugin->cache_block)) ||
248 (sq_prepare 249 (SQLITE_OK !=
249 (plugin->dbh, 250 sq_prepare (plugin->dbh,
250 "DELETE FROM ns096blocks WHERE expiration_time<?", 251 "DELETE FROM ns096blocks WHERE expiration_time<?",
251 &plugin->expire_blocks) != SQLITE_OK) || 252 &plugin->expire_blocks)) ||
252 (sq_prepare 253 (SQLITE_OK !=
253 (plugin->dbh, 254 sq_prepare (plugin->dbh,
254 "DELETE FROM ns096blocks WHERE query=? AND expiration_time<=?", 255 "DELETE FROM ns096blocks WHERE query=? AND expiration_time<=?",
255 &plugin->delete_block) != SQLITE_OK) || 256 &plugin->delete_block)) ||
256 (sq_prepare 257 (SQLITE_OK !=
257 (plugin->dbh, 258 sq_prepare (plugin->dbh,
258 "SELECT block FROM ns096blocks WHERE query=? ORDER BY expiration_time DESC LIMIT 1", 259 "SELECT block FROM ns096blocks WHERE query=? "
259 &plugin->lookup_block) != SQLITE_OK) 260 "ORDER BY expiration_time DESC LIMIT 1",
261 &plugin->lookup_block) )
260 ) 262 )
261 { 263 {
262 LOG_SQLITE (plugin,GNUNET_ERROR_TYPE_ERROR, "precompiling"); 264 LOG_SQLITE (plugin,
265 GNUNET_ERROR_TYPE_ERROR,
266 "precompiling");
263 return GNUNET_SYSERR; 267 return GNUNET_SYSERR;
264 } 268 }
265 return GNUNET_OK; 269 return GNUNET_OK;
@@ -319,35 +323,41 @@ static void
319namecache_sqlite_expire_blocks (struct Plugin *plugin) 323namecache_sqlite_expire_blocks (struct Plugin *plugin)
320{ 324{
321 struct GNUNET_TIME_Absolute now; 325 struct GNUNET_TIME_Absolute now;
326 struct GNUNET_SQ_QueryParam params[] = {
327 GNUNET_SQ_query_param_absolute_time (&now),
328 GNUNET_SQ_query_param_end
329 };
322 int n; 330 int n;
323 331
324 now = GNUNET_TIME_absolute_get (); 332 now = GNUNET_TIME_absolute_get ();
325 if (SQLITE_OK != sqlite3_bind_int64 (plugin->expire_blocks, 333 if (GNUNET_OK !=
326 1, now.abs_value_us)) 334 GNUNET_SQ_bind (plugin->expire_blocks,
335 params))
327 { 336 {
328 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 337 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
329 "sqlite3_bind_XXXX"); 338 "sqlite3_bind_XXXX");
330 if (SQLITE_OK != sqlite3_reset (plugin->expire_blocks)) 339 GNUNET_SQ_reset (plugin->dbh,
331 LOG_SQLITE (plugin, 340 plugin->expire_blocks);
332 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
333 "sqlite3_reset");
334 return; 341 return;
335 } 342 }
336 n = sqlite3_step (plugin->expire_blocks); 343 n = sqlite3_step (plugin->expire_blocks);
337 if (SQLITE_OK != sqlite3_reset (plugin->expire_blocks)) 344 GNUNET_SQ_reset (plugin->dbh,
338 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 345 plugin->expire_blocks);
339 "sqlite3_reset");
340 switch (n) 346 switch (n)
341 { 347 {
342 case SQLITE_DONE: 348 case SQLITE_DONE:
343 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", "Records expired\n"); 349 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
350 "sqlite",
351 "Records expired\n");
344 return; 352 return;
345 case SQLITE_BUSY: 353 case SQLITE_BUSY:
346 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, 354 LOG_SQLITE (plugin,
355 GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
347 "sqlite3_step"); 356 "sqlite3_step");
348 return; 357 return;
349 default: 358 default:
350 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 359 LOG_SQLITE (plugin,
360 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
351 "sqlite3_step"); 361 "sqlite3_step");
352 return; 362 return;
353 } 363 }
@@ -368,8 +378,21 @@ namecache_sqlite_cache_block (void *cls,
368 struct Plugin *plugin = cls; 378 struct Plugin *plugin = cls;
369 struct GNUNET_HashCode query; 379 struct GNUNET_HashCode query;
370 struct GNUNET_TIME_Absolute expiration; 380 struct GNUNET_TIME_Absolute expiration;
371 int64_t dval; 381 size_t block_size = ntohl (block->purpose.size) +
372 size_t block_size; 382 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) +
383 sizeof (struct GNUNET_CRYPTO_EcdsaSignature);
384 struct GNUNET_SQ_QueryParam del_params[] = {
385 GNUNET_SQ_query_param_auto_from_type (&query),
386 GNUNET_SQ_query_param_absolute_time (&expiration),
387 GNUNET_SQ_query_param_end
388 };
389 struct GNUNET_SQ_QueryParam ins_params[] = {
390 GNUNET_SQ_query_param_auto_from_type (&query),
391 GNUNET_SQ_query_param_fixed_size (block,
392 block_size),
393 GNUNET_SQ_query_param_absolute_time (&expiration),
394 GNUNET_SQ_query_param_end
395 };
373 int n; 396 int n;
374 397
375 namecache_sqlite_expire_blocks (plugin); 398 namecache_sqlite_expire_blocks (plugin);
@@ -377,12 +400,6 @@ namecache_sqlite_cache_block (void *cls,
377 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey), 400 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
378 &query); 401 &query);
379 expiration = GNUNET_TIME_absolute_ntoh (block->expiration_time); 402 expiration = GNUNET_TIME_absolute_ntoh (block->expiration_time);
380 dval = (int64_t) expiration.abs_value_us;
381 if (dval < 0)
382 dval = INT64_MAX;
383 block_size = ntohl (block->purpose.size) +
384 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) +
385 sizeof (struct GNUNET_CRYPTO_EcdsaSignature);
386 if (block_size > 64 * 65536) 403 if (block_size > 64 * 65536)
387 { 404 {
388 GNUNET_break (0); 405 GNUNET_break (0);
@@ -390,61 +407,48 @@ namecache_sqlite_cache_block (void *cls,
390 } 407 }
391 408
392 /* delete old version of the block */ 409 /* delete old version of the block */
393 if ( (SQLITE_OK != 410 if (GNUNET_OK !=
394 sqlite3_bind_blob (plugin->delete_block, 1, 411 GNUNET_SQ_bind (plugin->delete_block,
395 &query, sizeof (struct GNUNET_HashCode), 412 del_params))
396 SQLITE_STATIC)) ||
397 (SQLITE_OK !=
398 sqlite3_bind_int64 (plugin->delete_block,
399 2, dval)) )
400 { 413 {
401 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 414 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
402 "sqlite3_bind_XXXX"); 415 "sqlite3_bind_XXXX");
403 if (SQLITE_OK != sqlite3_reset (plugin->delete_block)) 416 GNUNET_SQ_reset (plugin->dbh,
404 LOG_SQLITE (plugin, 417 plugin->delete_block);
405 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
406 "sqlite3_reset");
407 return GNUNET_SYSERR; 418 return GNUNET_SYSERR;
408 } 419 }
409 n = sqlite3_step (plugin->delete_block); 420 n = sqlite3_step (plugin->delete_block);
410 switch (n) 421 switch (n)
411 { 422 {
412 case SQLITE_DONE: 423 case SQLITE_DONE:
413 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", "Old block deleted\n"); 424 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
425 "sqlite",
426 "Old block deleted\n");
414 break; 427 break;
415 case SQLITE_BUSY: 428 case SQLITE_BUSY:
416 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, 429 LOG_SQLITE (plugin,
430 GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
417 "sqlite3_step"); 431 "sqlite3_step");
418 break; 432 break;
419 default: 433 default:
420 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 434 LOG_SQLITE (plugin,
435 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
421 "sqlite3_step"); 436 "sqlite3_step");
422 break; 437 break;
423 } 438 }
424 if (SQLITE_OK != sqlite3_reset (plugin->delete_block)) 439 GNUNET_SQ_reset (plugin->dbh,
425 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 440 plugin->delete_block);
426 "sqlite3_reset");
427 441
428 /* insert new version of the block */ 442 /* insert new version of the block */
429 if ((SQLITE_OK != 443 if (GNUNET_OK !=
430 sqlite3_bind_blob (plugin->cache_block, 1, 444 GNUNET_SQ_bind (plugin->cache_block,
431 &query, sizeof (struct GNUNET_HashCode), 445 ins_params))
432 SQLITE_STATIC)) ||
433 (SQLITE_OK !=
434 sqlite3_bind_blob (plugin->cache_block, 2,
435 block, block_size,
436 SQLITE_STATIC)) ||
437 (SQLITE_OK !=
438 sqlite3_bind_int64 (plugin->cache_block, 3,
439 dval)))
440 { 446 {
441 LOG_SQLITE (plugin, 447 LOG_SQLITE (plugin,
442 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 448 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
443 "sqlite3_bind_XXXX"); 449 "sqlite3_bind_XXXX");
444 if (SQLITE_OK != sqlite3_reset (plugin->cache_block)) 450 GNUNET_SQ_reset (plugin->dbh,
445 LOG_SQLITE (plugin, 451 plugin->cache_block);
446 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
447 "sqlite3_reset");
448 return GNUNET_SYSERR; 452 return GNUNET_SYSERR;
449 453
450 } 454 }
@@ -452,9 +456,8 @@ namecache_sqlite_cache_block (void *cls,
452 "Caching block under derived key `%s'\n", 456 "Caching block under derived key `%s'\n",
453 GNUNET_h2s_full (&query)); 457 GNUNET_h2s_full (&query));
454 n = sqlite3_step (plugin->cache_block); 458 n = sqlite3_step (plugin->cache_block);
455 if (SQLITE_OK != sqlite3_reset (plugin->cache_block)) 459 GNUNET_SQ_reset (plugin->dbh,
456 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 460 plugin->cache_block);
457 "sqlite3_reset");
458 switch (n) 461 switch (n)
459 { 462 {
460 case SQLITE_DONE: 463 case SQLITE_DONE:
@@ -462,11 +465,13 @@ namecache_sqlite_cache_block (void *cls,
462 "Record stored\n"); 465 "Record stored\n");
463 return GNUNET_OK; 466 return GNUNET_OK;
464 case SQLITE_BUSY: 467 case SQLITE_BUSY:
465 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, 468 LOG_SQLITE (plugin,
469 GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
466 "sqlite3_step"); 470 "sqlite3_step");
467 return GNUNET_NO; 471 return GNUNET_NO;
468 default: 472 default:
469 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 473 LOG_SQLITE (plugin,
474 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
470 "sqlite3_step"); 475 "sqlite3_step");
471 return GNUNET_SYSERR; 476 return GNUNET_SYSERR;
472 } 477 }
@@ -486,45 +491,63 @@ namecache_sqlite_cache_block (void *cls,
486static int 491static int
487namecache_sqlite_lookup_block (void *cls, 492namecache_sqlite_lookup_block (void *cls,
488 const struct GNUNET_HashCode *query, 493 const struct GNUNET_HashCode *query,
489 GNUNET_NAMECACHE_BlockCallback iter, void *iter_cls) 494 GNUNET_NAMECACHE_BlockCallback iter,
495 void *iter_cls)
490{ 496{
491 struct Plugin *plugin = cls; 497 struct Plugin *plugin = cls;
492 int ret; 498 int ret;
493 int sret; 499 int sret;
494 size_t block_size; 500 size_t block_size;
495 const struct GNUNET_GNSRECORD_Block *block; 501 const struct GNUNET_GNSRECORD_Block *block;
502 struct GNUNET_SQ_QueryParam params[] = {
503 GNUNET_SQ_query_param_auto_from_type (query),
504 GNUNET_SQ_query_param_end
505 };
506 struct GNUNET_SQ_ResultSpec rs[] = {
507 GNUNET_SQ_result_spec_variable_size ((void **) &block,
508 &block_size),
509 GNUNET_SQ_result_spec_end
510 };
496 511
497 if (SQLITE_OK != sqlite3_bind_blob (plugin->lookup_block, 1, 512 if (GNUNET_OK !=
498 query, sizeof (struct GNUNET_HashCode), 513 GNUNET_SQ_bind (plugin->lookup_block,
499 SQLITE_STATIC)) 514 params))
500 { 515 {
501 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 516 LOG_SQLITE (plugin,
517 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
502 "sqlite3_bind_XXXX"); 518 "sqlite3_bind_XXXX");
503 if (SQLITE_OK != sqlite3_reset (plugin->lookup_block)) 519 GNUNET_SQ_reset (plugin->dbh,
504 LOG_SQLITE (plugin, 520 plugin->lookup_block);
505 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
506 "sqlite3_reset");
507 return GNUNET_SYSERR; 521 return GNUNET_SYSERR;
508 } 522 }
509 ret = GNUNET_NO; 523 ret = GNUNET_NO;
510 if (SQLITE_ROW == (sret = sqlite3_step (plugin->lookup_block))) 524 if (SQLITE_ROW ==
525 (sret = sqlite3_step (plugin->lookup_block)))
511 { 526 {
512 block = sqlite3_column_blob (plugin->lookup_block, 0); 527 if (GNUNET_OK !=
513 block_size = sqlite3_column_bytes (plugin->lookup_block, 0); 528 GNUNET_SQ_extract_result (plugin->lookup_block,
514 if ( (block_size < sizeof (struct GNUNET_GNSRECORD_Block)) || 529 rs))
515 (ntohl (block->purpose.size) +
516 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) +
517 sizeof (struct GNUNET_CRYPTO_EcdsaSignature) != block_size) )
518 { 530 {
519 GNUNET_break (0); 531 GNUNET_break (0);
520 ret = GNUNET_SYSERR; 532 ret = GNUNET_SYSERR;
521 } 533 }
534 else if ( (block_size < sizeof (struct GNUNET_GNSRECORD_Block)) ||
535 (ntohl (block->purpose.size) +
536 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) +
537 sizeof (struct GNUNET_CRYPTO_EcdsaSignature) != block_size) )
538 {
539 GNUNET_break (0);
540 GNUNET_SQ_cleanup_result (rs);
541 ret = GNUNET_SYSERR;
542 }
522 else 543 else
523 { 544 {
524 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 545 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
525 "Found block under derived key `%s'\n", 546 "Found block under derived key `%s'\n",
526 GNUNET_h2s_full (query)); 547 GNUNET_h2s_full (query));
527 iter (iter_cls, block); 548 iter (iter_cls,
549 block);
550 GNUNET_SQ_cleanup_result (rs);
528 ret = GNUNET_YES; 551 ret = GNUNET_YES;
529 } 552 }
530 } 553 }
@@ -532,7 +555,9 @@ namecache_sqlite_lookup_block (void *cls,
532 { 555 {
533 if (SQLITE_DONE != sret) 556 if (SQLITE_DONE != sret)
534 { 557 {
535 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite_step"); 558 LOG_SQLITE (plugin,
559 GNUNET_ERROR_TYPE_ERROR,
560 "sqlite_step");
536 ret = GNUNET_SYSERR; 561 ret = GNUNET_SYSERR;
537 } 562 }
538 else 563 else
@@ -542,10 +567,8 @@ namecache_sqlite_lookup_block (void *cls,
542 GNUNET_h2s_full (query)); 567 GNUNET_h2s_full (query));
543 } 568 }
544 } 569 }
545 if (SQLITE_OK != sqlite3_reset (plugin->lookup_block)) 570 GNUNET_SQ_reset (plugin->dbh,
546 LOG_SQLITE (plugin, 571 plugin->lookup_block);
547 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
548 "sqlite3_reset");
549 return ret; 572 return ret;
550} 573}
551 574
diff --git a/src/namestore/Makefile.am b/src/namestore/Makefile.am
index e9b0f179a..de46e9c89 100644
--- a/src/namestore/Makefile.am
+++ b/src/namestore/Makefile.am
@@ -189,6 +189,7 @@ libgnunet_plugin_namestore_sqlite_la_SOURCES = \
189 plugin_namestore_sqlite.c 189 plugin_namestore_sqlite.c
190libgnunet_plugin_namestore_sqlite_la_LIBADD = \ 190libgnunet_plugin_namestore_sqlite_la_LIBADD = \
191 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ 191 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
192 $(top_builddir)/src/sq/libgnunetsq.la \
192 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 193 $(top_builddir)/src/statistics/libgnunetstatistics.la \
193 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lsqlite3 \ 194 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lsqlite3 \
194 $(LTLIBINTL) 195 $(LTLIBINTL)
diff --git a/src/namestore/gnunet-namestore.c b/src/namestore/gnunet-namestore.c
index 457e77022..2ce3741f8 100644
--- a/src/namestore/gnunet-namestore.c
+++ b/src/namestore/gnunet-namestore.c
@@ -1130,49 +1130,88 @@ main (int argc,
1130 is_public = -1; 1130 is_public = -1;
1131 is_shadow = -1; 1131 is_shadow = -1;
1132 1132
1133 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 1133 struct GNUNET_GETOPT_CommandLineOption options[] = {
1134 {'a', "add", NULL, 1134
1135 gettext_noop ("add record"), 0, 1135 GNUNET_GETOPT_OPTION_SET_ONE ('a',
1136 &GNUNET_GETOPT_set_one, &add}, 1136 "add",
1137 {'d', "delete", NULL, 1137 gettext_noop ("add record"),
1138 gettext_noop ("delete record"), 0, 1138 &add),
1139 &GNUNET_GETOPT_set_one, &del}, 1139
1140 {'D', "display", NULL, 1140 GNUNET_GETOPT_OPTION_SET_ONE ('d',
1141 gettext_noop ("display records"), 0, 1141 "delete",
1142 &GNUNET_GETOPT_set_one, &list}, 1142 gettext_noop ("delete record"),
1143 {'e', "expiration", "TIME", 1143 &del),
1144 gettext_noop ("expiration time for record to use (for adding only), \"never\" is possible"), 1, 1144
1145 &GNUNET_GETOPT_set_string, &expirationstring}, 1145 GNUNET_GETOPT_OPTION_SET_ONE ('D',
1146 {'i', "nick", "NICKNAME", 1146 "display",
1147 gettext_noop ("set the desired nick name for the zone"), 1, 1147 gettext_noop ("display records"),
1148 &GNUNET_GETOPT_set_string, &nickstring}, 1148 &list),
1149 {'m', "monitor", NULL, 1149
1150 gettext_noop ("monitor changes in the namestore"), 0, 1150 GNUNET_GETOPT_OPTION_STRING ('e',
1151 &GNUNET_GETOPT_set_one, &monitor}, 1151 "expiration",
1152 {'n', "name", "NAME", 1152 "TIME",
1153 gettext_noop ("name of the record to add/delete/display"), 1, 1153 gettext_noop ("expiration time for record to use (for adding only), \"never\" is possible"),
1154 &GNUNET_GETOPT_set_string, &name}, 1154 &expirationstring),
1155 {'r', "reverse", "PKEY", 1155
1156 gettext_noop ("determine our name for the given PKEY"), 1, 1156 GNUNET_GETOPT_OPTION_STRING ('i',
1157 &GNUNET_GETOPT_set_string, &reverse_pkey}, 1157 "nick",
1158 {'t', "type", "TYPE", 1158 "NICKNAME",
1159 gettext_noop ("type of the record to add/delete/display"), 1, 1159 gettext_noop ("set the desired nick name for the zone"),
1160 &GNUNET_GETOPT_set_string, &typestring}, 1160 &nickstring),
1161 {'u', "uri", "URI", 1161
1162 gettext_noop ("URI to import into our zone"), 1, 1162 GNUNET_GETOPT_OPTION_SET_ONE ('m',
1163 &GNUNET_GETOPT_set_string, &uri}, 1163 "monitor",
1164 {'V', "value", "VALUE", 1164 gettext_noop ("monitor changes in the namestore"),
1165 gettext_noop ("value of the record to add/delete"), 1, 1165 &monitor),
1166 &GNUNET_GETOPT_set_string, &value}, 1166
1167 {'p', "public", NULL, 1167 GNUNET_GETOPT_OPTION_STRING ('n',
1168 gettext_noop ("create or list public record"), 0, 1168 "name",
1169 &GNUNET_GETOPT_set_one, &is_public}, 1169 "NAME",
1170 {'s', "shadow", NULL, 1170 gettext_noop ("name of the record to add/delete/display"),
1171 gettext_noop ("create shadow record (only valid if all other records of the same type have expired"), 0, 1171 &name),
1172 &GNUNET_GETOPT_set_one, &is_shadow}, 1172
1173 {'z', "zone", "EGO", 1173 GNUNET_GETOPT_OPTION_STRING ('r',
1174 gettext_noop ("name of the ego controlling the zone"), 1, 1174 "reverse",
1175 &GNUNET_GETOPT_set_string, &ego_name}, 1175 "PKEY",
1176 gettext_noop ("determine our name for the given PKEY"),
1177 &reverse_pkey),
1178
1179
1180
1181 GNUNET_GETOPT_OPTION_STRING ('t',
1182 "type",
1183 "TYPE",
1184 gettext_noop ("type of the record to add/delete/display"),
1185 &typestring),
1186
1187 GNUNET_GETOPT_OPTION_STRING ('u',
1188 "uri",
1189 "URI",
1190 gettext_noop ("URI to import into our zone"),
1191 &uri),
1192
1193 GNUNET_GETOPT_OPTION_STRING ('V',
1194 "value",
1195 "VALUE",
1196 gettext_noop ("value of the record to add/delete"),
1197 &value),
1198
1199 GNUNET_GETOPT_OPTION_SET_ONE ('p',
1200 "public",
1201 gettext_noop ("create or list public record"),
1202 &is_public),
1203
1204 GNUNET_GETOPT_OPTION_SET_ONE ('s',
1205 "shadow",
1206 gettext_noop ("create shadow record (only valid if all other records of the same type have expired"),
1207 &is_shadow),
1208
1209 GNUNET_GETOPT_OPTION_STRING ('z',
1210 "zone",
1211 "EGO",
1212 gettext_noop ("name of the ego controlling the zone"),
1213 &ego_name),
1214
1176 GNUNET_GETOPT_OPTION_END 1215 GNUNET_GETOPT_OPTION_END
1177 }; 1216 };
1178 1217
diff --git a/src/namestore/gnunet-service-namestore.c b/src/namestore/gnunet-service-namestore.c
index ae65802b0..6cb4290a0 100644
--- a/src/namestore/gnunet-service-namestore.c
+++ b/src/namestore/gnunet-service-namestore.c
@@ -1136,7 +1136,7 @@ handle_zone_to_name_it (void *cls,
1136 name_len = (NULL == name) ? 0 : strlen (name) + 1; 1136 name_len = (NULL == name) ? 0 : strlen (name) + 1;
1137 rd_ser_len = GNUNET_GNSRECORD_records_get_size (rd_count, rd); 1137 rd_ser_len = GNUNET_GNSRECORD_records_get_size (rd_count, rd);
1138 msg_size = sizeof (struct ZoneToNameResponseMessage) + name_len + rd_ser_len; 1138 msg_size = sizeof (struct ZoneToNameResponseMessage) + name_len + rd_ser_len;
1139 if (msg_size >= GNUNET_SERVER_MAX_MESSAGE_SIZE) 1139 if (msg_size >= GNUNET_MAX_MESSAGE_SIZE)
1140 { 1140 {
1141 GNUNET_break (0); 1141 GNUNET_break (0);
1142 ztn_ctx->success = GNUNET_SYSERR; 1142 ztn_ctx->success = GNUNET_SYSERR;
diff --git a/src/namestore/plugin_namestore_sqlite.c b/src/namestore/plugin_namestore_sqlite.c
index d64ce10a8..5c3533506 100644
--- a/src/namestore/plugin_namestore_sqlite.c
+++ b/src/namestore/plugin_namestore_sqlite.c
@@ -1,6 +1,6 @@
1 /* 1 /*
2 * This file is part of GNUnet 2 * This file is part of GNUnet
3 * Copyright (C) 2009-2013 GNUnet e.V. 3 * Copyright (C) 2009-2017 GNUnet e.V.
4 * 4 *
5 * GNUnet is free software; you can redistribute it and/or modify 5 * GNUnet is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published 6 * it under the terms of the GNU General Public License as published
@@ -28,6 +28,7 @@
28#include "gnunet_namestore_plugin.h" 28#include "gnunet_namestore_plugin.h"
29#include "gnunet_namestore_service.h" 29#include "gnunet_namestore_service.h"
30#include "gnunet_gnsrecord_lib.h" 30#include "gnunet_gnsrecord_lib.h"
31#include "gnunet_sq_lib.h"
31#include "namestore.h" 32#include "namestore.h"
32#include <sqlite3.h> 33#include <sqlite3.h>
33 34
@@ -113,16 +114,24 @@ struct Plugin
113 * @return 0 on success 114 * @return 0 on success
114 */ 115 */
115static int 116static int
116sq_prepare (sqlite3 * dbh, const char *zSql, sqlite3_stmt ** ppStmt) 117sq_prepare (sqlite3 *dbh,
118 const char *zSql,
119 sqlite3_stmt **ppStmt)
117{ 120{
118 char *dummy; 121 char *dummy;
119 int result; 122 int result;
120 123
121 result = 124 result =
122 sqlite3_prepare_v2 (dbh, zSql, strlen (zSql), ppStmt, 125 sqlite3_prepare_v2 (dbh,
126 zSql,
127 strlen (zSql),
128 ppStmt,
123 (const char **) &dummy); 129 (const char **) &dummy);
124 LOG (GNUNET_ERROR_TYPE_DEBUG, 130 LOG (GNUNET_ERROR_TYPE_DEBUG,
125 "Prepared `%s' / %p: %d\n", zSql, *ppStmt, result); 131 "Prepared `%s' / %p: %d\n",
132 zSql,
133 *ppStmt,
134 result);
126 return result; 135 return result;
127} 136}
128 137
@@ -275,38 +284,41 @@ database_setup (struct Plugin *plugin)
275 284
276 create_indices (plugin->dbh); 285 create_indices (plugin->dbh);
277 286
278 if ((sq_prepare 287 if ( (SQLITE_OK !=
279 (plugin->dbh, 288 sq_prepare (plugin->dbh,
280 "INSERT INTO ns097records (zone_private_key, pkey, rvalue, record_count, record_data, label)" 289 "INSERT INTO ns097records (zone_private_key, pkey, rvalue, record_count, record_data, label)"
281 " VALUES (?, ?, ?, ?, ?, ?)", 290 " VALUES (?, ?, ?, ?, ?, ?)",
282 &plugin->store_records) != SQLITE_OK) || 291 &plugin->store_records)) ||
283 (sq_prepare 292 (SQLITE_OK !=
284 (plugin->dbh, 293 sq_prepare (plugin->dbh,
285 "DELETE FROM ns097records WHERE zone_private_key=? AND label=?", 294 "DELETE FROM ns097records WHERE zone_private_key=? AND label=?",
286 &plugin->delete_records) != SQLITE_OK) || 295 &plugin->delete_records)) ||
287 (sq_prepare 296 (SQLITE_OK !=
288 (plugin->dbh, 297 sq_prepare (plugin->dbh,
289 "SELECT record_count,record_data,label" 298 "SELECT record_count,record_data,label"
290 " FROM ns097records WHERE zone_private_key=? AND pkey=?", 299 " FROM ns097records WHERE zone_private_key=? AND pkey=?",
291 &plugin->zone_to_name) != SQLITE_OK) || 300 &plugin->zone_to_name)) ||
292 (sq_prepare 301 (SQLITE_OK !=
293 (plugin->dbh, 302 sq_prepare (plugin->dbh,
294 "SELECT record_count,record_data,label" 303 "SELECT record_count,record_data,label"
295 " FROM ns097records WHERE zone_private_key=? ORDER BY rvalue LIMIT 1 OFFSET ?", 304 " FROM ns097records WHERE zone_private_key=?"
296 &plugin->iterate_zone) != SQLITE_OK) || 305 " ORDER BY rvalue LIMIT 1 OFFSET ?",
297 (sq_prepare 306 &plugin->iterate_zone)) ||
298 (plugin->dbh, 307 (SQLITE_OK !=
299 "SELECT record_count,record_data,label,zone_private_key" 308 sq_prepare (plugin->dbh,
300 " FROM ns097records ORDER BY rvalue LIMIT 1 OFFSET ?", 309 "SELECT record_count,record_data,label,zone_private_key"
301 &plugin->iterate_all_zones) != SQLITE_OK) || 310 " FROM ns097records ORDER BY rvalue LIMIT 1 OFFSET ?",
302 (sq_prepare 311 &plugin->iterate_all_zones)) ||
303 (plugin->dbh, 312 (SQLITE_OK !=
304 "SELECT record_count,record_data,label,zone_private_key" 313 sq_prepare (plugin->dbh,
305 " FROM ns097records WHERE zone_private_key=? AND label=?", 314 "SELECT record_count,record_data,label,zone_private_key"
306 &plugin->lookup_label) != SQLITE_OK) 315 " FROM ns097records WHERE zone_private_key=? AND label=?",
307 ) 316 &plugin->lookup_label))
317 )
308 { 318 {
309 LOG_SQLITE (plugin,GNUNET_ERROR_TYPE_ERROR, "precompiling"); 319 LOG_SQLITE (plugin,
320 GNUNET_ERROR_TYPE_ERROR,
321 "precompiling");
310 return GNUNET_SYSERR; 322 return GNUNET_SYSERR;
311 } 323 }
312 return GNUNET_OK; 324 return GNUNET_OK;
@@ -341,21 +353,30 @@ database_shutdown (struct Plugin *plugin)
341 { 353 {
342 LOG (GNUNET_ERROR_TYPE_WARNING, 354 LOG (GNUNET_ERROR_TYPE_WARNING,
343 _("Tried to close sqlite without finalizing all prepared statements.\n")); 355 _("Tried to close sqlite without finalizing all prepared statements.\n"));
344 stmt = sqlite3_next_stmt (plugin->dbh, NULL); 356 stmt = sqlite3_next_stmt (plugin->dbh,
345 while (stmt != NULL) 357 NULL);
358 while (NULL != stmt)
346 { 359 {
347 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", 360 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
348 "Closing statement %p\n", stmt); 361 "sqlite",
362 "Closing statement %p\n",
363 stmt);
349 result = sqlite3_finalize (stmt); 364 result = sqlite3_finalize (stmt);
350 if (result != SQLITE_OK) 365 if (result != SQLITE_OK)
351 GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "sqlite", 366 GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
352 "Failed to close statement %p: %d\n", stmt, result); 367 "sqlite",
353 stmt = sqlite3_next_stmt (plugin->dbh, NULL); 368 "Failed to close statement %p: %d\n",
369 stmt,
370 result);
371 stmt = sqlite3_next_stmt (plugin->dbh,
372 NULL);
354 } 373 }
355 result = sqlite3_close (plugin->dbh); 374 result = sqlite3_close (plugin->dbh);
356 } 375 }
357 if (SQLITE_OK != result) 376 if (SQLITE_OK != result)
358 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite3_close"); 377 LOG_SQLITE (plugin,
378 GNUNET_ERROR_TYPE_ERROR,
379 "sqlite3_close");
359 380
360 GNUNET_free_non_null (plugin->fn); 381 GNUNET_free_non_null (plugin->fn);
361} 382}
@@ -407,7 +428,13 @@ namestore_sqlite_store_records (void *cls,
407 return GNUNET_SYSERR; 428 return GNUNET_SYSERR;
408 } 429 }
409 { 430 {
431 /* First delete 'old' records */
410 char data[data_size]; 432 char data[data_size];
433 struct GNUNET_SQ_QueryParam dparams[] = {
434 GNUNET_SQ_query_param_auto_from_type (zone_key),
435 GNUNET_SQ_query_param_string (label),
436 GNUNET_SQ_query_param_end
437 };
411 438
412 if (data_size != 439 if (data_size !=
413 GNUNET_GNSRECORD_records_serialize (rd_count, 440 GNUNET_GNSRECORD_records_serialize (rd_count,
@@ -418,92 +445,71 @@ namestore_sqlite_store_records (void *cls,
418 GNUNET_break (0); 445 GNUNET_break (0);
419 return GNUNET_SYSERR; 446 return GNUNET_SYSERR;
420 } 447 }
421 448 if (GNUNET_OK !=
422 /* First delete 'old' records */ 449 GNUNET_SQ_bind (plugin->delete_records,
423 if ((SQLITE_OK != 450 dparams))
424 sqlite3_bind_blob (plugin->delete_records,
425 1,
426 zone_key,
427 sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey),
428 SQLITE_STATIC)) ||
429 (SQLITE_OK !=
430 sqlite3_bind_text (plugin->delete_records,
431 2,
432 label,
433 -1,
434 SQLITE_STATIC)))
435 { 451 {
436 LOG_SQLITE (plugin, 452 LOG_SQLITE (plugin,
437 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 453 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
438 "sqlite3_bind_XXXX"); 454 "sqlite3_bind_XXXX");
439 if (SQLITE_OK != sqlite3_reset (plugin->delete_records)) 455 GNUNET_SQ_reset (plugin->dbh,
440 LOG_SQLITE (plugin, 456 plugin->delete_records);
441 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
442 "sqlite3_reset");
443 return GNUNET_SYSERR; 457 return GNUNET_SYSERR;
444 458
445 } 459 }
446 n = sqlite3_step (plugin->delete_records); 460 n = sqlite3_step (plugin->delete_records);
447 if (SQLITE_OK != sqlite3_reset (plugin->delete_records)) 461 GNUNET_SQ_reset (plugin->dbh,
448 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 462 plugin->delete_records);
449 "sqlite3_reset");
450 463
451 if (0 != rd_count) 464 if (0 != rd_count)
452 { 465 {
453 if ((SQLITE_OK != 466 uint32_t rd_count32 = (uint32_t) rd_count;
454 sqlite3_bind_blob (plugin->store_records, 467 struct GNUNET_SQ_QueryParam sparams[] = {
455 1, 468 GNUNET_SQ_query_param_auto_from_type (zone_key),
456 zone_key, 469 GNUNET_SQ_query_param_auto_from_type (&rvalue),
457 sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey), 470 GNUNET_SQ_query_param_uint64 (&rvalue),
458 SQLITE_STATIC)) || 471 GNUNET_SQ_query_param_uint32 (&rd_count32),
459 (SQLITE_OK != 472 GNUNET_SQ_query_param_fixed_size (data, data_size),
460 sqlite3_bind_blob (plugin->store_records, 473 GNUNET_SQ_query_param_string (label),
461 2, 474 GNUNET_SQ_query_param_end
462 &pkey, 475 };
463 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey), 476
464 SQLITE_STATIC)) || 477 if (GNUNET_OK !=
465 (SQLITE_OK != 478 GNUNET_SQ_bind (plugin->store_records,
466 sqlite3_bind_int64 (plugin->store_records, 3, rvalue)) || 479 sparams))
467 (SQLITE_OK !=
468 sqlite3_bind_int (plugin->store_records, 4, rd_count)) ||
469 (SQLITE_OK !=
470 sqlite3_bind_blob (plugin->store_records, 5,
471 data, data_size,
472 SQLITE_STATIC)) ||
473 (SQLITE_OK !=
474 sqlite3_bind_text (plugin->store_records, 6,
475 label, -1,
476 SQLITE_STATIC)))
477 { 480 {
478 LOG_SQLITE (plugin, 481 LOG_SQLITE (plugin,
479 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 482 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
480 "sqlite3_bind_XXXX"); 483 "sqlite3_bind_XXXX");
481 if (SQLITE_OK != sqlite3_reset (plugin->store_records)) 484 GNUNET_SQ_reset (plugin->dbh,
482 LOG_SQLITE (plugin, 485 plugin->store_records);
483 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
484 "sqlite3_reset");
485 return GNUNET_SYSERR; 486 return GNUNET_SYSERR;
486 } 487 }
487 n = sqlite3_step (plugin->store_records); 488 n = sqlite3_step (plugin->store_records);
488 if (SQLITE_OK != sqlite3_reset (plugin->store_records)) 489 GNUNET_SQ_reset (plugin->dbh,
489 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 490 plugin->store_records);
490 "sqlite3_reset");
491 } 491 }
492 } 492 }
493 switch (n) 493 switch (n)
494 { 494 {
495 case SQLITE_DONE: 495 case SQLITE_DONE:
496 if (0 != rd_count) 496 if (0 != rd_count)
497 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", "Record stored\n"); 497 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
498 "sqlite",
499 "Record stored\n");
498 else 500 else
499 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", "Record deleted\n"); 501 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
502 "sqlite",
503 "Record deleted\n");
500 return GNUNET_OK; 504 return GNUNET_OK;
501 case SQLITE_BUSY: 505 case SQLITE_BUSY:
502 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, 506 LOG_SQLITE (plugin,
507 GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
503 "sqlite3_step"); 508 "sqlite3_step");
504 return GNUNET_NO; 509 return GNUNET_NO;
505 default: 510 default:
506 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 511 LOG_SQLITE (plugin,
512 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
507 "sqlite3_step"); 513 "sqlite3_step");
508 return GNUNET_SYSERR; 514 return GNUNET_SYSERR;
509 } 515 }
@@ -526,37 +532,47 @@ static int
526get_record_and_call_iterator (struct Plugin *plugin, 532get_record_and_call_iterator (struct Plugin *plugin,
527 sqlite3_stmt *stmt, 533 sqlite3_stmt *stmt,
528 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key, 534 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
529 GNUNET_NAMESTORE_RecordIterator iter, void *iter_cls) 535 GNUNET_NAMESTORE_RecordIterator iter,
536 void *iter_cls)
530{ 537{
531 unsigned int record_count; 538 uint32_t record_count;
532 size_t data_size; 539 size_t data_size;
533 const char *data; 540 void *data;
534 const char *label; 541 char *label;
542 struct GNUNET_CRYPTO_EcdsaPrivateKey zk;
535 int ret; 543 int ret;
536 int sret; 544 int sret;
537 545
538 ret = GNUNET_NO; 546 ret = GNUNET_NO;
539 if (SQLITE_ROW == (sret = sqlite3_step (stmt))) 547 if (SQLITE_ROW == (sret = sqlite3_step (stmt)))
540 { 548 {
541 record_count = sqlite3_column_int (stmt, 0); 549 struct GNUNET_SQ_ResultSpec rs[] = {
542 data_size = sqlite3_column_bytes (stmt, 1); 550 GNUNET_SQ_result_spec_uint32 (&record_count),
543 data = sqlite3_column_blob (stmt, 1); 551 GNUNET_SQ_result_spec_variable_size (&data, &data_size),
544 label = (const char*) sqlite3_column_text (stmt, 2); 552 GNUNET_SQ_result_spec_string (&label),
553 GNUNET_SQ_result_spec_end
554 };
555 struct GNUNET_SQ_ResultSpec rsx[] = {
556 GNUNET_SQ_result_spec_uint32 (&record_count),
557 GNUNET_SQ_result_spec_variable_size (&data, &data_size),
558 GNUNET_SQ_result_spec_string (&label),
559 GNUNET_SQ_result_spec_auto_from_type (&zk),
560 GNUNET_SQ_result_spec_end
561 };
562
545 if (NULL == zone_key) 563 if (NULL == zone_key)
546 { 564 {
547 /* must be "iterate_all_zones", got one extra return value */ 565 zone_key = &zk;
548 if (sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey) != 566 ret = GNUNET_SQ_extract_result (stmt,
549 sqlite3_column_bytes (stmt, 3)) 567 rsx);
550 { 568 }
551 GNUNET_break (0); 569 else
552 ret = GNUNET_SYSERR; 570 {
553 } 571 ret = GNUNET_SQ_extract_result (stmt,
554 else 572 rs);
555 {
556 zone_key = sqlite3_column_blob (stmt, 3);
557 }
558 } 573 }
559 if (record_count > 64 * 1024) 574 if ( (GNUNET_OK != ret) ||
575 (record_count > 64 * 1024) )
560 { 576 {
561 /* sanity check, don't stack allocate far too much just 577 /* sanity check, don't stack allocate far too much just
562 because database might contain a large value here */ 578 because database might contain a large value here */
@@ -568,32 +584,40 @@ get_record_and_call_iterator (struct Plugin *plugin,
568 struct GNUNET_GNSRECORD_Data rd[record_count]; 584 struct GNUNET_GNSRECORD_Data rd[record_count];
569 585
570 if (GNUNET_OK != 586 if (GNUNET_OK !=
571 GNUNET_GNSRECORD_records_deserialize (data_size, data, 587 GNUNET_GNSRECORD_records_deserialize (data_size,
572 record_count, rd)) 588 data,
589 record_count,
590 rd))
573 { 591 {
574 GNUNET_break (0); 592 GNUNET_break (0);
575 ret = GNUNET_SYSERR; 593 ret = GNUNET_SYSERR;
576 } 594 }
577 else if (NULL != zone_key) 595 else
578 { 596 {
579 if (NULL != iter) 597 if (NULL != iter)
580 iter (iter_cls, zone_key, label, record_count, rd); 598 iter (iter_cls,
599 zone_key,
600 label,
601 record_count,
602 rd);
581 ret = GNUNET_YES; 603 ret = GNUNET_YES;
582 } 604 }
583 } 605 }
606 GNUNET_SQ_cleanup_result (rs);
584 } 607 }
585 else 608 else
586 { 609 {
587 if (SQLITE_DONE != sret) 610 if (SQLITE_DONE != sret)
588 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite_step"); 611 LOG_SQLITE (plugin,
612 GNUNET_ERROR_TYPE_ERROR,
613 "sqlite_step");
589 } 614 }
590 if (SQLITE_OK != sqlite3_reset (stmt)) 615 GNUNET_SQ_reset (plugin->dbh,
591 LOG_SQLITE (plugin, 616 stmt);
592 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
593 "sqlite3_reset");
594 return ret; 617 return ret;
595} 618}
596 619
620
597/** 621/**
598 * Lookup records in the datastore for which we are the authority. 622 * Lookup records in the datastore for which we are the authority.
599 * 623 *
@@ -606,37 +630,35 @@ get_record_and_call_iterator (struct Plugin *plugin,
606 */ 630 */
607static int 631static int
608namestore_sqlite_lookup_records (void *cls, 632namestore_sqlite_lookup_records (void *cls,
609 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone, const char *label, 633 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
610 GNUNET_NAMESTORE_RecordIterator iter, void *iter_cls) 634 const char *label,
635 GNUNET_NAMESTORE_RecordIterator iter,
636 void *iter_cls)
611{ 637{
612 struct Plugin *plugin = cls; 638 struct Plugin *plugin = cls;
613 sqlite3_stmt *stmt; 639 struct GNUNET_SQ_QueryParam params[] = {
614 int err; 640 GNUNET_SQ_query_param_auto_from_type (zone),
641 GNUNET_SQ_query_param_string (label),
642 GNUNET_SQ_query_param_end
643 };
615 644
616 if (NULL == zone) 645 if (NULL == zone)
617 {
618 return GNUNET_SYSERR; 646 return GNUNET_SYSERR;
619 } 647 if (GNUNET_OK !=
620 else 648 GNUNET_SQ_bind (plugin->lookup_label,
621 { 649 params))
622 stmt = plugin->lookup_label;
623 err = ( (SQLITE_OK != sqlite3_bind_blob (stmt, 1,
624 zone, sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey),
625 SQLITE_STATIC)) ||
626 (SQLITE_OK != sqlite3_bind_text (stmt, 2,
627 label, -1, SQLITE_STATIC)) );
628 }
629 if (err)
630 { 650 {
631 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 651 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
632 "sqlite3_bind_XXXX"); 652 "sqlite3_bind_XXXX");
633 if (SQLITE_OK != sqlite3_reset (stmt)) 653 GNUNET_SQ_reset (plugin->dbh,
634 LOG_SQLITE (plugin, 654 plugin->lookup_label);
635 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
636 "sqlite3_reset");
637 return GNUNET_SYSERR; 655 return GNUNET_SYSERR;
638 } 656 }
639 return get_record_and_call_iterator (plugin, stmt, zone, iter, iter_cls); 657 return get_record_and_call_iterator (plugin,
658 plugin->lookup_label,
659 zone,
660 iter,
661 iter_cls);
640} 662}
641 663
642 664
@@ -655,7 +677,8 @@ static int
655namestore_sqlite_iterate_records (void *cls, 677namestore_sqlite_iterate_records (void *cls,
656 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone, 678 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
657 uint64_t offset, 679 uint64_t offset,
658 GNUNET_NAMESTORE_RecordIterator iter, void *iter_cls) 680 GNUNET_NAMESTORE_RecordIterator iter,
681 void *iter_cls)
659{ 682{
660 struct Plugin *plugin = cls; 683 struct Plugin *plugin = cls;
661 sqlite3_stmt *stmt; 684 sqlite3_stmt *stmt;
@@ -663,30 +686,41 @@ namestore_sqlite_iterate_records (void *cls,
663 686
664 if (NULL == zone) 687 if (NULL == zone)
665 { 688 {
689 struct GNUNET_SQ_QueryParam params[] = {
690 GNUNET_SQ_query_param_uint64 (&offset),
691 GNUNET_SQ_query_param_end
692 };
693
666 stmt = plugin->iterate_all_zones; 694 stmt = plugin->iterate_all_zones;
667 err = (SQLITE_OK != sqlite3_bind_int64 (stmt, 1, 695 err = GNUNET_SQ_bind (stmt,
668 offset)); 696 params);
669 } 697 }
670 else 698 else
671 { 699 {
700 struct GNUNET_SQ_QueryParam params[] = {
701 GNUNET_SQ_query_param_auto_from_type (zone),
702 GNUNET_SQ_query_param_uint64 (&offset),
703 GNUNET_SQ_query_param_end
704 };
705
672 stmt = plugin->iterate_zone; 706 stmt = plugin->iterate_zone;
673 err = ( (SQLITE_OK != sqlite3_bind_blob (stmt, 1, 707 err = GNUNET_SQ_bind (stmt,
674 zone, sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey), 708 params);
675 SQLITE_STATIC)) ||
676 (SQLITE_OK != sqlite3_bind_int64 (stmt, 2,
677 offset)) );
678 } 709 }
679 if (err) 710 if (GNUNET_OK != err)
680 { 711 {
681 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 712 LOG_SQLITE (plugin,
713 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
682 "sqlite3_bind_XXXX"); 714 "sqlite3_bind_XXXX");
683 if (SQLITE_OK != sqlite3_reset (stmt)) 715 GNUNET_SQ_reset (plugin->dbh,
684 LOG_SQLITE (plugin, 716 stmt);
685 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
686 "sqlite3_reset");
687 return GNUNET_SYSERR; 717 return GNUNET_SYSERR;
688 } 718 }
689 return get_record_and_call_iterator (plugin, stmt, zone, iter, iter_cls); 719 return get_record_and_call_iterator (plugin,
720 stmt,
721 zone,
722 iter,
723 iter_cls);
690} 724}
691 725
692 726
@@ -708,29 +742,31 @@ namestore_sqlite_zone_to_name (void *cls,
708 GNUNET_NAMESTORE_RecordIterator iter, void *iter_cls) 742 GNUNET_NAMESTORE_RecordIterator iter, void *iter_cls)
709{ 743{
710 struct Plugin *plugin = cls; 744 struct Plugin *plugin = cls;
711 sqlite3_stmt *stmt; 745 struct GNUNET_SQ_QueryParam params[] = {
746 GNUNET_SQ_query_param_auto_from_type (zone),
747 GNUNET_SQ_query_param_auto_from_type (value_zone),
748 GNUNET_SQ_query_param_end
749 };
712 750
713 stmt = plugin->zone_to_name; 751 if (GNUNET_OK !=
714 if ( (SQLITE_OK != sqlite3_bind_blob (stmt, 1, 752 GNUNET_SQ_bind (plugin->zone_to_name,
715 zone, sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey), 753 params))
716 SQLITE_STATIC)) ||
717 (SQLITE_OK != sqlite3_bind_blob (stmt, 2,
718 value_zone, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
719 SQLITE_STATIC)) )
720 { 754 {
721 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 755 LOG_SQLITE (plugin,
756 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
722 "sqlite3_bind_XXXX"); 757 "sqlite3_bind_XXXX");
723 if (SQLITE_OK != sqlite3_reset (stmt)) 758 GNUNET_SQ_reset (plugin->dbh,
724 LOG_SQLITE (plugin, 759 plugin->zone_to_name);
725 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
726 "sqlite3_reset");
727 return GNUNET_SYSERR; 760 return GNUNET_SYSERR;
728 } 761 }
729 LOG (GNUNET_ERROR_TYPE_DEBUG, 762 LOG (GNUNET_ERROR_TYPE_DEBUG,
730 "Performing reverse lookup for `%s'\n", 763 "Performing reverse lookup for `%s'\n",
731 GNUNET_GNSRECORD_z2s (value_zone)); 764 GNUNET_GNSRECORD_z2s (value_zone));
732 765 return get_record_and_call_iterator (plugin,
733 return get_record_and_call_iterator (plugin, stmt, zone, iter, iter_cls); 766 plugin->zone_to_name,
767 zone,
768 iter,
769 iter_cls);
734} 770}
735 771
736 772
diff --git a/src/nat-auto/Makefile.am b/src/nat-auto/Makefile.am
index 19695fabd..14f3f2330 100644
--- a/src/nat-auto/Makefile.am
+++ b/src/nat-auto/Makefile.am
@@ -37,11 +37,11 @@ lib_LTLIBRARIES = \
37 37
38libgnunetnatauto_la_SOURCES = \ 38libgnunetnatauto_la_SOURCES = \
39 nat_auto_api.c \ 39 nat_auto_api.c \
40 nat_auto_api_test.c 40 nat_auto_api_test.c
41libgnunetnatauto_la_LIBADD = \ 41libgnunetnatauto_la_LIBADD = \
42 $(top_builddir)/src/nat/libgnunetnatnew.la \ 42 $(top_builddir)/src/nat/libgnunetnatnew.la \
43 $(top_builddir)/src/util/libgnunetutil.la \ 43 $(top_builddir)/src/util/libgnunetutil.la \
44 $(GN_LIBINTL) @EXT_LIBS@ 44 $(GN_LIBINTL) @EXT_LIBS@
45libgnunetnatauto_la_LDFLAGS = \ 45libgnunetnatauto_la_LDFLAGS = \
46 $(GN_LIB_LDFLAGS) $(WINFLAGS) \ 46 $(GN_LIB_LDFLAGS) $(WINFLAGS) \
47 -version-info 0:0:0 47 -version-info 0:0:0
@@ -55,4 +55,3 @@ gnunet_service_nat_auto_LDADD = \
55 $(LIBGCRYPT_LIBS) \ 55 $(LIBGCRYPT_LIBS) \
56 -lgcrypt \ 56 -lgcrypt \
57 $(GN_LIBINTL) 57 $(GN_LIBINTL)
58
diff --git a/src/nat-auto/gnunet-nat-auto.c b/src/nat-auto/gnunet-nat-auto.c
index 9ba81eb5f..8b281d1ab 100644
--- a/src/nat-auto/gnunet-nat-auto.c
+++ b/src/nat-auto/gnunet-nat-auto.c
@@ -63,7 +63,7 @@ static char *section_name;
63/** 63/**
64 * Should we run autoconfiguration? 64 * Should we run autoconfiguration?
65 */ 65 */
66static unsigned int do_auto; 66static int do_auto;
67 67
68/** 68/**
69 * Handle to a NAT test operation. 69 * Handle to a NAT test operation.
@@ -174,6 +174,9 @@ auto_config_cb (void *cls,
174 GNUNET_NAT_AUTO_status2string (result), 174 GNUNET_NAT_AUTO_status2string (result),
175 nat_type); 175 nat_type);
176 176
177 if (NULL == diff)
178 return;
179
177 /* Shortcut: if there are no changes suggested, bail out early. */ 180 /* Shortcut: if there are no changes suggested, bail out early. */
178 if (GNUNET_NO == 181 if (GNUNET_NO ==
179 GNUNET_CONFIGURATION_is_dirty (diff)) 182 GNUNET_CONFIGURATION_is_dirty (diff))
@@ -186,20 +189,16 @@ auto_config_cb (void *cls,
186 to the user */ 189 to the user */
187 new_cfg = write_cfg ? GNUNET_CONFIGURATION_dup (cfg) : NULL; 190 new_cfg = write_cfg ? GNUNET_CONFIGURATION_dup (cfg) : NULL;
188 191
189 if (NULL != diff) 192 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
190 { 193 _("Suggested configuration changes:\n"));
191 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, 194 GNUNET_CONFIGURATION_iterate_section_values (diff,
192 _("Suggested configuration changes:\n")); 195 "nat",
193 GNUNET_CONFIGURATION_iterate_section_values (diff, 196 &auto_conf_iter,
194 "nat", 197 new_cfg);
195 &auto_conf_iter,
196 new_cfg);
197 }
198 198
199 /* If desired, write configuration to file; we write only the 199 /* If desired, write configuration to file; we write only the
200 changes to the defaults to keep things compact. */ 200 changes to the defaults to keep things compact. */
201 if ( (write_cfg) && 201 if (write_cfg)
202 (NULL != diff) )
203 { 202 {
204 struct GNUNET_CONFIGURATION_Handle *def_cfg; 203 struct GNUNET_CONFIGURATION_Handle *def_cfg;
205 204
@@ -298,8 +297,8 @@ run (void *cls,
298 if (do_auto) 297 if (do_auto)
299 { 298 {
300 ah = GNUNET_NAT_AUTO_autoconfig_start (c, 299 ah = GNUNET_NAT_AUTO_autoconfig_start (c,
301 &auto_config_cb, 300 &auto_config_cb,
302 NULL); 301 NULL);
303 } 302 }
304 303
305 if (use_tcp && use_udp) 304 if (use_tcp && use_udp)
@@ -340,22 +339,32 @@ int
340main (int argc, 339main (int argc,
341 char *const argv[]) 340 char *const argv[])
342{ 341{
343 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 342 struct GNUNET_GETOPT_CommandLineOption options[] = {
344 {'a', "auto", NULL, 343 GNUNET_GETOPT_OPTION_SET_ONE ('a',
345 gettext_noop ("run autoconfiguration"), 344 "auto",
346 GNUNET_NO, &GNUNET_GETOPT_set_one, &do_auto }, 345 gettext_noop ("run autoconfiguration"),
347 {'S', "section", "NAME", 346 &do_auto),
348 gettext_noop ("section name providing the configuration for the adapter"), 347
349 GNUNET_YES, &GNUNET_GETOPT_set_string, &section_name }, 348 GNUNET_GETOPT_OPTION_STRING ('S',
350 {'t', "tcp", NULL, 349 "section",
351 gettext_noop ("use TCP"), 350 "NAME",
352 GNUNET_NO, &GNUNET_GETOPT_set_one, &use_tcp }, 351 gettext_noop ("section name providing the configuration for the adapter"),
353 {'u', "udp", NULL, 352 &section_name),
354 gettext_noop ("use UDP"), 353
355 GNUNET_NO, &GNUNET_GETOPT_set_one, &use_udp }, 354 GNUNET_GETOPT_OPTION_SET_ONE ('t',
356 {'w', "write", NULL, 355 "tcp",
357 gettext_noop ("write configuration file (for autoconfiguration)"), 356 gettext_noop ("use TCP"),
358 GNUNET_NO, &GNUNET_GETOPT_set_one, &write_cfg }, 357 &use_tcp),
358
359 GNUNET_GETOPT_OPTION_SET_ONE ('u',
360 "udp",
361 gettext_noop ("use UDP"),
362 &use_udp),
363
364 GNUNET_GETOPT_OPTION_SET_ONE ('w',
365 "write",
366 gettext_noop ("write configuration file (for autoconfiguration)"),
367 &write_cfg),
359 GNUNET_GETOPT_OPTION_END 368 GNUNET_GETOPT_OPTION_END
360 }; 369 };
361 370
diff --git a/src/nat-auto/gnunet-nat-server.c b/src/nat-auto/gnunet-nat-server.c
index 371e4b27e..590fad4d6 100644
--- a/src/nat-auto/gnunet-nat-server.c
+++ b/src/nat-auto/gnunet-nat-server.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 Copyright (C) 2011 GNUnet e.V. 3 Copyright (C) 2011, 2017 GNUnet e.V.
4 4
5 GNUnet is free software; you can redistribute it and/or modify 5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published 6 it under the terms of the GNU General Public License as published
@@ -31,9 +31,21 @@
31 31
32 32
33/** 33/**
34 * Our server. 34 * Information we track per client.
35 */ 35 */
36static struct GNUNET_SERVER_Handle *server; 36struct ClientData
37{
38 /**
39 * Timeout task.
40 */
41 struct GNUNET_SCHEDULER_Task *tt;
42
43 /**
44 * Client handle.
45 */
46 struct GNUNET_SERVICE_Client *client;
47};
48
37 49
38/** 50/**
39 * Our configuration. 51 * Our configuration.
@@ -248,21 +260,18 @@ try_send_udp (uint32_t dst_ipv4,
248 * We've received a request to probe a NAT 260 * We've received a request to probe a NAT
249 * traversal. Do it. 261 * traversal. Do it.
250 * 262 *
251 * @param cls unused 263 * @param cls handle to client (we always close)
252 * @param client handle to client (we always close)
253 * @param msg message with details about what to test 264 * @param msg message with details about what to test
254 */ 265 */
255static void 266static void
256test (void *cls, 267handle_test (void *cls,
257 struct GNUNET_SERVER_Client *client, 268 const struct GNUNET_NAT_AUTO_TestMessage *tm)
258 const struct GNUNET_MessageHeader *msg)
259{ 269{
260 const struct GNUNET_NAT_AUTO_TestMessage *tm; 270 struct ClientData *cd = cls;
261 uint16_t dport; 271 uint16_t dport;
262 272
263 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 273 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
264 "Received test request\n"); 274 "Received test request\n");
265 tm = (const struct GNUNET_NAT_AUTO_TestMessage *) msg;
266 dport = ntohs (tm->dport); 275 dport = ntohs (tm->dport);
267 if (0 == dport) 276 if (0 == dport)
268 try_anat (tm->dst_ipv4, 277 try_anat (tm->dst_ipv4,
@@ -276,126 +285,119 @@ test (void *cls,
276 try_send_udp (tm->dst_ipv4, 285 try_send_udp (tm->dst_ipv4,
277 dport, 286 dport,
278 tm->data); 287 tm->data);
279 GNUNET_SERVER_receive_done (client, 288 GNUNET_SERVICE_client_drop (cd->client);
280 GNUNET_NO);
281} 289}
282 290
283 291
284/** 292/**
285 * Task run during shutdown. 293 * Main function that will be run.
286 * 294 *
287 * @param cls unused 295 * @param cls closure
296 * @param c configuration
297 * @param srv service handle
288 */ 298 */
289static void 299static void
290shutdown_task (void *cls) 300run (void *cls,
301 const struct GNUNET_CONFIGURATION_Handle *c,
302 struct GNUNET_SERVICE_Handle *srv)
291{ 303{
292 GNUNET_SERVER_destroy (server); 304 cfg = c;
293 server = NULL;
294} 305}
295 306
296 307
297/** 308/**
298 * Main function that will be run. 309 * Forcefully drops client after 1s.
299 * 310 *
300 * @param cls closure 311 * @param cls our `struct ClientData` of a client to drop
301 * @param args remaining command-line arguments
302 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
303 * @param c configuration
304 */ 312 */
305static void 313static void
306run (void *cls, 314force_timeout (void *cls)
307 char *const *args,
308 const char *cfgfile,
309 const struct GNUNET_CONFIGURATION_Handle *c)
310{ 315{
311 static const struct GNUNET_SERVER_MessageHandler handlers[] = { 316 struct ClientData *cd = cls;
312 {&test, NULL, GNUNET_MESSAGE_TYPE_NAT_TEST,
313 sizeof (struct GNUNET_NAT_AUTO_TestMessage)},
314 {NULL, NULL, 0, 0}
315 };
316 unsigned int port;
317 struct sockaddr_in in4;
318 struct sockaddr_in6 in6;
319
320 socklen_t slen[] = {
321 sizeof (in4),
322 sizeof (in6),
323 0
324 };
325 struct sockaddr *sa[] = {
326 (struct sockaddr *) &in4,
327 (struct sockaddr *) &in6,
328 NULL
329 };
330 317
331 cfg = c; 318 cd->tt = NULL;
332 if ( (NULL == args[0]) || 319 GNUNET_SERVICE_client_drop (cd->client);
333 (1 != SSCANF (args[0], "%u", &port)) ||
334 (0 == port) ||
335 (65536 <= port) )
336 {
337 FPRINTF (stderr,
338 _("Please pass valid port number as the first argument! (got `%s')\n"),
339 args[0]);
340 return;
341 }
342 memset (&in4, 0, sizeof (in4));
343 memset (&in6, 0, sizeof (in6));
344 in4.sin_family = AF_INET;
345 in4.sin_port = htons ((uint16_t) port);
346 in6.sin6_family = AF_INET6;
347 in6.sin6_port = htons ((uint16_t) port);
348#if HAVE_SOCKADDR_IN_SIN_LEN
349 in4.sin_len = sizeof (in4);
350 in6.sin6_len = sizeof (in6);
351#endif
352 server = GNUNET_SERVER_create (NULL,
353 NULL,
354 (struct sockaddr * const *) sa,
355 slen,
356 GNUNET_TIME_UNIT_SECONDS,
357 GNUNET_YES);
358 GNUNET_SERVER_add_handlers (server,
359 handlers);
360 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
361 NULL);
362} 320}
363 321
364 322
323
365/** 324/**
366 * Main function of gnunet-nat-server. 325 * Callback called when a client connects to the service.
367 * 326 *
368 * @param argc number of command-line arguments 327 * @param cls closure for the service
369 * @param argv command line 328 * @param c the new client that connected to the service
370 * @return 0 on success, -1 on error 329 * @param mq the message queue used to send messages to the client
330 * @return our `struct ClientData`
371 */ 331 */
372int 332static void *
373main (int argc, char *const argv[]) 333client_connect_cb (void *cls,
334 struct GNUNET_SERVICE_Client *c,
335 struct GNUNET_MQ_Handle *mq)
374{ 336{
375 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 337 struct ClientData *cd;
376 GNUNET_GETOPT_OPTION_END 338
377 }; 339 cd = GNUNET_new (struct ClientData);
378 340 cd->client = c;
379 if (GNUNET_OK != 341 cd->tt = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
380 GNUNET_STRINGS_get_utf8_args (argc, argv, 342 &force_timeout,
381 &argc, &argv)) 343 cd);
382 return 2; 344 return cd;
383 345}
384 if (GNUNET_OK != 346
385 GNUNET_PROGRAM_run (argc, 347
386 argv, 348/**
387 "gnunet-nat-server [options] PORT", 349 * Callback called when a client disconnected from the service
388 _("GNUnet NAT traversal test helper daemon"), 350 *
389 options, 351 * @param cls closure for the service
390 &run, 352 * @param c the client that disconnected
391 NULL)) 353 * @param internal_cls our `struct ClientData`
392 { 354 */
393 GNUNET_free ((void*) argv); 355static void
394 return 1; 356client_disconnect_cb (void *cls,
395 } 357 struct GNUNET_SERVICE_Client *c,
396 GNUNET_free ((void*) argv); 358 void *internal_cls)
397 return 0; 359{
360 struct ClientData *cd = internal_cls;
361
362 if (NULL != cd->tt)
363 GNUNET_SCHEDULER_cancel (cd->tt);
364 GNUNET_free (cd);
398} 365}
399 366
400 367
368/**
369 * Define "main" method using service macro.
370 */
371GNUNET_SERVICE_MAIN
372("nat-server",
373 GNUNET_SERVICE_OPTION_NONE,
374 &run,
375 &client_connect_cb,
376 &client_disconnect_cb,
377 NULL,
378 GNUNET_MQ_hd_fixed_size (test,
379 GNUNET_MESSAGE_TYPE_NAT_TEST,
380 struct GNUNET_NAT_AUTO_TestMessage,
381 NULL),
382 GNUNET_MQ_handler_end ());
383
384
385#if defined(LINUX) && defined(__GLIBC__)
386#include <malloc.h>
387
388/**
389 * MINIMIZE heap size (way below 128k) since this process doesn't need much.
390 */
391void __attribute__ ((constructor))
392GNUNET_ARM_memory_init ()
393{
394 mallopt (M_TRIM_THRESHOLD, 4 * 1024);
395 mallopt (M_TOP_PAD, 1 * 1024);
396 malloc_trim (0);
397}
398#endif
399
400
401
402
401/* end of gnunet-nat-server.c */ 403/* end of gnunet-nat-server.c */
diff --git a/src/nat-auto/nat_auto_api.c b/src/nat-auto/nat_auto_api.c
index 6660239c3..8a7eaf264 100644
--- a/src/nat-auto/nat_auto_api.c
+++ b/src/nat-auto/nat_auto_api.c
@@ -224,7 +224,7 @@ GNUNET_NAT_AUTO_autoconfig_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
224 224
225 buf = GNUNET_CONFIGURATION_serialize (cfg, 225 buf = GNUNET_CONFIGURATION_serialize (cfg,
226 &size); 226 &size);
227 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (*req)) 227 if (size > GNUNET_MAX_MESSAGE_SIZE - sizeof (*req))
228 { 228 {
229 GNUNET_break (0); 229 GNUNET_break (0);
230 GNUNET_free (buf); 230 GNUNET_free (buf);
diff --git a/src/nat/gnunet-nat.c b/src/nat/gnunet-nat.c
index 80bfb5726..50e0dff0f 100644
--- a/src/nat/gnunet-nat.c
+++ b/src/nat/gnunet-nat.c
@@ -34,9 +34,9 @@
34static int global_ret; 34static int global_ret;
35 35
36/** 36/**
37 * Name of section in configuration file to use for 37 * Name of section in configuration file to use for
38 * additional options. 38 * additional options.
39 */ 39 */
40static char *section_name; 40static char *section_name;
41 41
42/** 42/**
@@ -72,7 +72,7 @@ static char *remote_addr;
72/** 72/**
73 * Should we actually bind to #bind_addr and receive and process STUN requests? 73 * Should we actually bind to #bind_addr and receive and process STUN requests?
74 */ 74 */
75static unsigned int do_stun; 75static int do_stun;
76 76
77/** 77/**
78 * Handle to NAT operation. 78 * Handle to NAT operation.
@@ -81,7 +81,7 @@ static struct GNUNET_NAT_Handle *nh;
81 81
82/** 82/**
83 * Listen socket for STUN processing. 83 * Listen socket for STUN processing.
84 */ 84 */
85static struct GNUNET_NETWORK_Handle *ls; 85static struct GNUNET_NETWORK_Handle *ls;
86 86
87/** 87/**
@@ -110,7 +110,7 @@ test_finished ()
110 * a function to call whenever our set of 'valid' addresses changes. 110 * a function to call whenever our set of 'valid' addresses changes.
111 * 111 *
112 * @param cls closure, NULL 112 * @param cls closure, NULL
113 * @param add_remove #GNUNET_YES to add a new public IP address, 113 * @param add_remove #GNUNET_YES to add a new public IP address,
114 * #GNUNET_NO to remove a previous (now invalid) one 114 * #GNUNET_NO to remove a previous (now invalid) one
115 * @param ac address class the address belongs to 115 * @param ac address class the address belongs to
116 * @param addr either the previous or the new public IP address 116 * @param addr either the previous or the new public IP address
@@ -123,12 +123,12 @@ address_cb (void *cls,
123 const struct sockaddr *addr, 123 const struct sockaddr *addr,
124 socklen_t addrlen) 124 socklen_t addrlen)
125{ 125{
126 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, 126 fprintf (stdout,
127 "%s %s (%d)\n", 127 "%s %s (%d)\n",
128 add_remove ? "+" : "-", 128 add_remove ? "+" : "-",
129 GNUNET_a2s (addr, 129 GNUNET_a2s (addr,
130 addrlen), 130 addrlen),
131 (int) ac); 131 (int) ac);
132} 132}
133 133
134 134
@@ -186,7 +186,7 @@ static void
186stun_read_task (void *cls) 186stun_read_task (void *cls)
187{ 187{
188 ssize_t size; 188 ssize_t size;
189 189
190 rtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, 190 rtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
191 ls, 191 ls,
192 &stun_read_task, 192 &stun_read_task,
@@ -204,7 +204,7 @@ stun_read_task (void *cls)
204 struct sockaddr_storage sa; 204 struct sockaddr_storage sa;
205 socklen_t salen = sizeof (sa); 205 socklen_t salen = sizeof (sa);
206 ssize_t ret; 206 ssize_t ret;
207 207
208 ret = GNUNET_NETWORK_socket_recvfrom (ls, 208 ret = GNUNET_NETWORK_socket_recvfrom (ls,
209 buf, 209 buf,
210 size + 1, 210 size + 1,
@@ -269,6 +269,10 @@ run (void *cls,
269 global_ret = 1; 269 global_ret = 1;
270 return; 270 return;
271 } 271 }
272 local_len = 0;
273 local_sa = NULL;
274 remote_len = 0;
275 remote_sa = NULL;
272 if (NULL != local_addr) 276 if (NULL != local_addr)
273 { 277 {
274 local_len = (socklen_t) GNUNET_STRINGS_parse_socket_addr (local_addr, 278 local_len = (socklen_t) GNUNET_STRINGS_parse_socket_addr (local_addr,
@@ -279,13 +283,10 @@ run (void *cls,
279 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, 283 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
280 "Invalid socket address `%s'\n", 284 "Invalid socket address `%s'\n",
281 local_addr); 285 local_addr);
282 global_ret = 1; 286 goto fail_and_shutdown;
283 return;
284 } 287 }
285 } 288 }
286 289
287 remote_len = 0;
288
289 if (NULL != remote_addr) 290 if (NULL != remote_addr)
290 { 291 {
291 remote_len = GNUNET_STRINGS_parse_socket_addr (remote_addr, 292 remote_len = GNUNET_STRINGS_parse_socket_addr (remote_addr,
@@ -296,8 +297,7 @@ run (void *cls,
296 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, 297 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
297 "Invalid socket address `%s'\n", 298 "Invalid socket address `%s'\n",
298 remote_addr); 299 remote_addr);
299 global_ret = 1; 300 goto fail_and_shutdown;
300 return;
301 } 301 }
302 } 302 }
303 303
@@ -318,32 +318,26 @@ run (void *cls,
318 else if (listen_reversal) 318 else if (listen_reversal)
319 { 319 {
320 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, 320 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
321 "Use of `-W` only effective in combination with `-i`\n"); 321 "Use of `-W` only effective in combination with `-i`\n");
322 global_ret = 1; 322 goto fail_and_shutdown;
323 GNUNET_SCHEDULER_shutdown ();
324 return;
325 } 323 }
326 324
327 if (NULL != remote_addr) 325 if (NULL != remote_addr)
328 { 326 {
329 int ret; 327 int ret;
330 328
331 if ( (NULL == nh) || 329 if ( (NULL == nh) ||
332 (sizeof (struct sockaddr_in) != local_len) ) 330 (sizeof (struct sockaddr_in) != local_len) )
333 { 331 {
334 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, 332 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
335 "Require IPv4 local address to initiate connection reversal\n"); 333 "Require IPv4 local address to initiate connection reversal\n");
336 global_ret = 1; 334 goto fail_and_shutdown;
337 GNUNET_SCHEDULER_shutdown ();
338 return;
339 } 335 }
340 if (sizeof (struct sockaddr_in) != remote_len) 336 if (sizeof (struct sockaddr_in) != remote_len)
341 { 337 {
342 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, 338 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
343 "Require IPv4 reversal target address\n"); 339 "Require IPv4 reversal target address\n");
344 global_ret = 1; 340 goto fail_and_shutdown;
345 GNUNET_SCHEDULER_shutdown ();
346 return;
347 } 341 }
348 GNUNET_assert (AF_INET == local_sa->sa_family); 342 GNUNET_assert (AF_INET == local_sa->sa_family);
349 GNUNET_assert (AF_INET == remote_sa->sa_family); 343 GNUNET_assert (AF_INET == remote_sa->sa_family);
@@ -365,24 +359,20 @@ run (void *cls,
365 break; 359 break;
366 } 360 }
367 } 361 }
368 362
369 if (do_stun) 363 if (do_stun)
370 { 364 {
371 if (NULL == local_addr) 365 if (NULL == local_addr)
372 { 366 {
373 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, 367 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
374 "Require local address to support STUN requests\n"); 368 "Require local address to support STUN requests\n");
375 global_ret = 1; 369 goto fail_and_shutdown;
376 GNUNET_SCHEDULER_shutdown ();
377 return;
378 } 370 }
379 if (IPPROTO_UDP != proto) 371 if (IPPROTO_UDP != proto)
380 { 372 {
381 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, 373 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
382 "STUN only supported over UDP\n"); 374 "STUN only supported over UDP\n");
383 global_ret = 1; 375 goto fail_and_shutdown;
384 GNUNET_SCHEDULER_shutdown ();
385 return;
386 } 376 }
387 ls = GNUNET_NETWORK_socket_create (af, 377 ls = GNUNET_NETWORK_socket_create (af,
388 SOCK_DGRAM, 378 SOCK_DGRAM,
@@ -397,17 +387,22 @@ run (void *cls,
397 GNUNET_a2s (local_sa, 387 GNUNET_a2s (local_sa,
398 local_len), 388 local_len),
399 STRERROR (errno)); 389 STRERROR (errno));
400 global_ret = 1; 390 goto fail_and_shutdown;
401 GNUNET_SCHEDULER_shutdown ();
402 return;
403 } 391 }
404 rtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, 392 rtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
405 ls, 393 ls,
406 &stun_read_task, 394 &stun_read_task,
407 NULL); 395 NULL);
408 } 396 }
409 397 GNUNET_free_non_null (remote_sa);
398 GNUNET_free_non_null (local_sa);
410 test_finished (); 399 test_finished ();
400 return;
401 fail_and_shutdown:
402 global_ret = 1;
403 GNUNET_SCHEDULER_shutdown ();
404 GNUNET_free_non_null (remote_sa);
405 GNUNET_free_non_null (local_sa);
411} 406}
412 407
413 408
@@ -422,29 +417,46 @@ int
422main (int argc, 417main (int argc,
423 char *const argv[]) 418 char *const argv[])
424{ 419{
425 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 420 struct GNUNET_GETOPT_CommandLineOption options[] = {
426 {'i', "in", "ADDRESS", 421
427 gettext_noop ("which IP and port are we locally using to bind/listen to"), 422 GNUNET_GETOPT_OPTION_STRING ('i',
428 GNUNET_YES, &GNUNET_GETOPT_set_string, &local_addr }, 423 "in",
429 {'r', "remote", "ADDRESS", 424 "ADDRESS",
430 gettext_noop ("which remote IP and port should be asked for connection reversal"), 425 gettext_noop ("which IP and port are we locally using to bind/listen to"),
431 GNUNET_YES, &GNUNET_GETOPT_set_string, &remote_addr }, 426 &local_addr),
432 {'S', "section", NULL, 427
433 gettext_noop ("name of configuration section to find additional options, such as manual host punching data"), 428 GNUNET_GETOPT_OPTION_STRING ('r',
434 GNUNET_YES, &GNUNET_GETOPT_set_string, &section_name }, 429 "remote",
435 {'s', "stun", NULL, 430 "ADDRESS",
436 gettext_noop ("enable STUN processing"), 431 gettext_noop ("which remote IP and port should be asked for connection reversal"),
437 GNUNET_NO, &GNUNET_GETOPT_set_one, &do_stun }, 432 &remote_addr),
438 {'t', "tcp", NULL, 433
439 gettext_noop ("use TCP"), 434 GNUNET_GETOPT_OPTION_STRING ('S',
440 GNUNET_NO, &GNUNET_GETOPT_set_one, &use_tcp }, 435 "section",
441 {'u', "udp", NULL, 436 NULL,
442 gettext_noop ("use UDP"), 437 gettext_noop ("name of configuration section to find additional options, such as manual host punching data"),
443 GNUNET_NO, &GNUNET_GETOPT_set_one, &use_udp }, 438 &section_name),
444 {'W', "watch", NULL, 439
445 gettext_noop ("watch for connection reversal requests"), 440 GNUNET_GETOPT_OPTION_SET_ONE ('s',
446 GNUNET_NO, &GNUNET_GETOPT_set_one, &listen_reversal }, 441 "stun",
447 GNUNET_GETOPT_OPTION_END 442 gettext_noop ("enable STUN processing"),
443 &do_stun),
444
445 GNUNET_GETOPT_OPTION_SET_ONE ('t',
446 "tcp",
447 gettext_noop ("use TCP"),
448 &use_tcp),
449
450 GNUNET_GETOPT_OPTION_SET_ONE ('u',
451 "udp",
452 gettext_noop ("use UDP"),
453 &use_udp),
454
455 GNUNET_GETOPT_OPTION_SET_ONE ('W',
456 "watch",
457 gettext_noop ("watch for connection reversal requests"),
458 &listen_reversal),
459 GNUNET_GETOPT_OPTION_END
448 }; 460 };
449 461
450 if (GNUNET_OK != 462 if (GNUNET_OK !=
diff --git a/src/nat/gnunet-service-nat.c b/src/nat/gnunet-service-nat.c
index bfe212308..0695c7ac7 100644
--- a/src/nat/gnunet-service-nat.c
+++ b/src/nat/gnunet-service-nat.c
@@ -662,6 +662,11 @@ notify_client (enum GNUNET_NAT_AddressClass ac,
662 struct GNUNET_MQ_Envelope *env; 662 struct GNUNET_MQ_Envelope *env;
663 struct GNUNET_NAT_AddressChangeNotificationMessage *msg; 663 struct GNUNET_NAT_AddressChangeNotificationMessage *msg;
664 664
665 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
666 "Notifying client about %s of IP %s\n",
667 add ? "addition" : "removal",
668 GNUNET_a2s (addr,
669 addr_len));
665 env = GNUNET_MQ_msg_extra (msg, 670 env = GNUNET_MQ_msg_extra (msg,
666 addr_len, 671 addr_len,
667 GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE); 672 GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE);
@@ -693,7 +698,11 @@ check_notify_client (struct LocalAddressList *delta,
693 struct sockaddr_in6 v6; 698 struct sockaddr_in6 v6;
694 699
695 if (0 == (ch->flags & GNUNET_NAT_RF_ADDRESSES)) 700 if (0 == (ch->flags & GNUNET_NAT_RF_ADDRESSES))
701 {
702 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
703 "Not notifying client as it does not care about addresses\n");
696 return; 704 return;
705 }
697 switch (delta->af) 706 switch (delta->af)
698 { 707 {
699 case AF_INET: 708 case AF_INET:
@@ -715,25 +724,24 @@ check_notify_client (struct LocalAddressList *delta,
715 (! match_ipv4 ("127.0.0.1", &v4.sin_addr, 8)) ) 724 (! match_ipv4 ("127.0.0.1", &v4.sin_addr, 8)) )
716 continue; /* bound to loopback, but this is not loopback */ 725 continue; /* bound to loopback, but this is not loopback */
717 if ( (! match_ipv4 ("127.0.0.1", &c4->sin_addr, 8) ) && 726 if ( (! match_ipv4 ("127.0.0.1", &c4->sin_addr, 8) ) &&
718 (0 != c4->sin_addr.s_addr) &&
719 match_ipv4 ("127.0.0.1", &v4.sin_addr, 8) ) 727 match_ipv4 ("127.0.0.1", &v4.sin_addr, 8) )
720 continue; /* bound to non-loopback, but this is loopback */ 728 continue; /* bound to non-loopback, but this is loopback */
721 if ( (0 != (ch->flags & GNUNET_NAT_AC_EXTERN)) && 729 if ( (0 != (delta->ac & GNUNET_NAT_AC_EXTERN)) &&
722 (0 != c4->sin_addr.s_addr) && 730 (0 != c4->sin_addr.s_addr) &&
723 (! is_nat_v4 (&v4.sin_addr)) ) 731 (! is_nat_v4 (&v4.sin_addr)) )
724 continue; /* based on external-IP, but this IP is not 732 continue; /* based on external-IP, but this IP is not
725 from private address range. */ 733 from private address range. */
726 if ( (0 != memcmp (&v4.sin_addr, 734 if ( (0 != memcmp (&v4.sin_addr,
727 &c4->sin_addr, 735 &c4->sin_addr,
728 sizeof (struct in_addr))) && 736 sizeof (struct in_addr))) &&
729 (0 != c4->sin_addr.s_addr) && 737 (0 != c4->sin_addr.s_addr) &&
730 ( (! is_nat_v4 (&c4->sin_addr)) || 738 (! is_nat_v4 (&c4->sin_addr)) )
731 (0 == (ch->flags & GNUNET_NAT_AC_EXTERN))) )
732 continue; /* this IP is not from private address range, 739 continue; /* this IP is not from private address range,
733 and IP does not match. */ 740 and IP does not match. */
734 741
735 /* OK, IP seems relevant, notify client */ 742 /* OK, IP seems relevant, notify client */
736 v4.sin_port = c4->sin_port; 743 if (0 == htons (v4.sin_port))
744 v4.sin_port = c4->sin_port;
737 notify_client (delta->ac, 745 notify_client (delta->ac,
738 ch, 746 ch,
739 add, 747 add,
@@ -760,13 +768,10 @@ check_notify_client (struct LocalAddressList *delta,
760 (! match_ipv6 ("::1", &v6.sin6_addr, 128)) ) 768 (! match_ipv6 ("::1", &v6.sin6_addr, 128)) )
761 continue; /* bound to loopback, but this is not loopback */ 769 continue; /* bound to loopback, but this is not loopback */
762 if ( (! match_ipv6 ("::1", &c6->sin6_addr, 128) ) && 770 if ( (! match_ipv6 ("::1", &c6->sin6_addr, 128) ) &&
763 (0 != memcmp (&c6->sin6_addr,
764 &in6addr_any,
765 sizeof (struct in6_addr))) &&
766 match_ipv6 ("::1", &v6.sin6_addr, 128) ) 771 match_ipv6 ("::1", &v6.sin6_addr, 128) )
767 continue; /* bound to non-loopback, but this is loopback */ 772 continue; /* bound to non-loopback, but this is loopback */
768 if ( (0 != (ch->flags & GNUNET_NAT_AC_EXTERN)) && 773 if ( (0 != (delta->ac & GNUNET_NAT_AC_EXTERN)) &&
769 (0 != memcmp (&c6->sin6_addr, 774 (0 != memcmp (&c6->sin6_addr,
770 &in6addr_any, 775 &in6addr_any,
771 sizeof (struct in6_addr))) && 776 sizeof (struct in6_addr))) &&
772 (! is_nat_v6 (&v6.sin6_addr)) ) 777 (! is_nat_v6 (&v6.sin6_addr)) )
@@ -793,7 +798,8 @@ check_notify_client (struct LocalAddressList *delta,
793 does not match and is not an external IP */ 798 does not match and is not an external IP */
794 799
795 /* OK, IP seems relevant, notify client */ 800 /* OK, IP seems relevant, notify client */
796 v6.sin6_port = c6->sin6_port; 801 if (0 == htons (v6.sin6_port))
802 v6.sin6_port = c6->sin6_port;
797 notify_client (delta->ac, 803 notify_client (delta->ac,
798 ch, 804 ch,
799 add, 805 add,
@@ -853,6 +859,10 @@ notify_client_external_ipv4_change (void *cls,
853 struct LocalAddressList lal; 859 struct LocalAddressList lal;
854 struct sockaddr_in *s4; 860 struct sockaddr_in *s4;
855 861
862 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
863 "Detected eternal IP, can now back-fill AUTO:%u in hole punching specification of `%s'\n",
864 (unsigned int) ch->ext_dns_port,
865 ch->section_name);
856 memset (&lal, 0, sizeof (lal)); 866 memset (&lal, 0, sizeof (lal));
857 s4 = (struct sockaddr_in *) &lal.addr; 867 s4 = (struct sockaddr_in *) &lal.addr;
858 s4->sin_family = AF_INET; 868 s4->sin_family = AF_INET;
@@ -868,8 +878,6 @@ notify_client_external_ipv4_change (void *cls,
868 /* (1) check if client cares. */ 878 /* (1) check if client cares. */
869 if (! ch->natted_address) 879 if (! ch->natted_address)
870 return; 880 return;
871 if (0 == (GNUNET_NAT_RF_ADDRESSES & ch->flags))
872 return;
873 have_v4 = GNUNET_NO; 881 have_v4 = GNUNET_NO;
874 for (unsigned int i=0;i<ch->num_caddrs;i++) 882 for (unsigned int i=0;i<ch->num_caddrs;i++)
875 { 883 {
@@ -891,6 +899,10 @@ notify_client_external_ipv4_change (void *cls,
891 sa.sin_addr = *v4; 899 sa.sin_addr = *v4;
892 sa.sin_port = htons (0); 900 sa.sin_port = htons (0);
893 901
902 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
903 "Detected eternal IP %s, notifying client of external IP (without port)\n",
904 GNUNET_a2s ((const struct sockaddr *) &sa,
905 sizeof (sa)));
894 /* (3) notify client of change */ 906 /* (3) notify client of change */
895 notify_client (is_nat_v4 (v4) 907 notify_client (is_nat_v4 (v4)
896 ? GNUNET_NAT_AC_EXTERN | GNUNET_NAT_AC_LAN 908 ? GNUNET_NAT_AC_EXTERN | GNUNET_NAT_AC_LAN
@@ -1055,7 +1067,8 @@ run_scan (void *cls)
1055 1067
1056 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1068 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1057 "Found NATed local address %s, starting NAT server\n", 1069 "Found NATed local address %s, starting NAT server\n",
1058 GNUNET_a2s ((void *) &pos->addr, sizeof (*s4))); 1070 GNUNET_a2s ((const struct sockaddr *) &pos->addr,
1071 sizeof (*s4)));
1059 pos->hc = GN_start_gnunet_nat_server_ (&s4->sin_addr, 1072 pos->hc = GN_start_gnunet_nat_server_ (&s4->sin_addr,
1060 &reversal_callback, 1073 &reversal_callback,
1061 pos); 1074 pos);
@@ -1280,6 +1293,11 @@ dyndns_lookup (void *cls)
1280 struct ClientHandle *ch = cls; 1293 struct ClientHandle *ch = cls;
1281 struct LocalAddressList *lal; 1294 struct LocalAddressList *lal;
1282 1295
1296 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1297 "Performing DNS lookup for punched hole given for `%s' as `%s:%u'\n",
1298 ch->section_name,
1299 ch->hole_external,
1300 (unsigned int) ch->ext_dns_port);
1283 for (lal = ch->ext_addr_head; NULL != lal; lal = lal->next) 1301 for (lal = ch->ext_addr_head; NULL != lal; lal = lal->next)
1284 lal->old = GNUNET_YES; 1302 lal->old = GNUNET_YES;
1285 ch->ext_dns_task = NULL; 1303 ch->ext_dns_task = NULL;
@@ -1374,6 +1392,11 @@ lookup_hole_external (struct ClientHandle *ch)
1374 ch->hole_external, 1392 ch->hole_external,
1375 &s4->sin_addr)) 1393 &s4->sin_addr))
1376 { 1394 {
1395 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1396 "IPv4 punched hole given for `%s' via `%s:%u'\n",
1397 ch->section_name,
1398 ch->hole_external,
1399 (unsigned int) ch->ext_dns_port);
1377 s4->sin_port = htons (ch->ext_dns_port); 1400 s4->sin_port = htons (ch->ext_dns_port);
1378 lal->af = AF_INET; 1401 lal->af = AF_INET;
1379 lal->ac = GNUNET_NAT_AC_GLOBAL | GNUNET_NAT_AC_MANUAL; 1402 lal->ac = GNUNET_NAT_AC_GLOBAL | GNUNET_NAT_AC_MANUAL;
@@ -1423,8 +1446,6 @@ handle_register (void *cls,
1423 GNUNET_SERVICE_client_drop (ch->client); 1446 GNUNET_SERVICE_client_drop (ch->client);
1424 return; 1447 return;
1425 } 1448 }
1426 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1427 "Received REGISTER message from client\n");
1428 ch->flags = message->flags; 1449 ch->flags = message->flags;
1429 ch->proto = message->proto; 1450 ch->proto = message->proto;
1430 ch->num_caddrs = ntohs (message->num_addrs); 1451 ch->num_caddrs = ntohs (message->num_addrs);
@@ -1512,6 +1533,9 @@ handle_register (void *cls,
1512 ch->section_name 1533 ch->section_name
1513 = GNUNET_strndup (off, 1534 = GNUNET_strndup (off,
1514 ntohs (message->str_len)); 1535 ntohs (message->str_len));
1536 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1537 "Received REGISTER message from client for subsystem `%s'\n",
1538 ch->section_name);
1515 if (GNUNET_OK == 1539 if (GNUNET_OK ==
1516 GNUNET_CONFIGURATION_get_value_string (cfg, 1540 GNUNET_CONFIGURATION_get_value_string (cfg,
1517 ch->section_name, 1541 ch->section_name,
diff --git a/src/nat/gnunet-service-nat_externalip.c b/src/nat/gnunet-service-nat_externalip.c
index 8df6f48a5..f79ff4070 100644
--- a/src/nat/gnunet-service-nat_externalip.c
+++ b/src/nat/gnunet-service-nat_externalip.c
@@ -182,6 +182,7 @@ handle_external_ip (void *cls,
182 switch (result) 182 switch (result)
183 { 183 {
184 case GNUNET_NAT_ERROR_SUCCESS: 184 case GNUNET_NAT_ERROR_SUCCESS:
185 GNUNET_assert (NULL != addr);
185 if (addr->s_addr == mini_external_ipv4.s_addr) 186 if (addr->s_addr == mini_external_ipv4.s_addr)
186 return; /* not change */ 187 return; /* not change */
187 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 188 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
diff --git a/src/nat/gnunet-service-nat_helper.c b/src/nat/gnunet-service-nat_helper.c
index e91f63beb..de6531fa8 100644
--- a/src/nat/gnunet-service-nat_helper.c
+++ b/src/nat/gnunet-service-nat_helper.c
@@ -221,6 +221,26 @@ restart_nat_server (void *cls)
221 char ia[INET_ADDRSTRLEN]; 221 char ia[INET_ADDRSTRLEN];
222 222
223 h->server_read_task = NULL; 223 h->server_read_task = NULL;
224 GNUNET_assert (NULL !=
225 inet_ntop (AF_INET,
226 &h->internal_address,
227 ia,
228 sizeof (ia)));
229 /* Start the server process */
230 binary
231 = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-nat-server");
232 if (GNUNET_YES !=
233 GNUNET_OS_check_helper_binary (binary,
234 GNUNET_YES,
235 ia))
236 {
237 /* move instantly to max delay, as this is unlikely to be fixed */
238 h->server_retry_delay
239 = GNUNET_TIME_STD_EXPONENTIAL_BACKOFF_THRESHOLD;
240 GNUNET_free (binary);
241 try_again (h);
242 return;
243 }
224 h->server_stdout 244 h->server_stdout
225 = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, 245 = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES,
226 GNUNET_NO, GNUNET_YES); 246 GNUNET_NO, GNUNET_YES);
@@ -228,21 +248,14 @@ restart_nat_server (void *cls)
228 { 248 {
229 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, 249 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
230 "pipe"); 250 "pipe");
251 GNUNET_free (binary);
231 try_again (h); 252 try_again (h);
232 return; 253 return;
233 } 254 }
234 GNUNET_assert (NULL !=
235 inet_ntop (AF_INET,
236 &h->internal_address,
237 ia,
238 sizeof (ia)));
239 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 255 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
240 "Starting `%s' at `%s'\n", 256 "Starting `%s' at `%s'\n",
241 "gnunet-helper-nat-server", 257 "gnunet-helper-nat-server",
242 ia); 258 ia);
243 /* Start the server process */
244 binary
245 = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-nat-server");
246 h->server_proc 259 h->server_proc
247 = GNUNET_OS_start_process (GNUNET_NO, 260 = GNUNET_OS_start_process (GNUNET_NO,
248 0, 261 0,
diff --git a/src/nat/nat_api.c b/src/nat/nat_api.c
index eec5d3968..69612584e 100644
--- a/src/nat/nat_api.c
+++ b/src/nat/nat_api.c
@@ -52,7 +52,7 @@ struct AddrEntry
52 * Address class of the address. 52 * Address class of the address.
53 */ 53 */
54 enum GNUNET_NAT_AddressClass ac; 54 enum GNUNET_NAT_AddressClass ac;
55 55
56 /** 56 /**
57 * Number of bytes that follow. 57 * Number of bytes that follow.
58 */ 58 */
@@ -70,7 +70,7 @@ struct GNUNET_NAT_Handle
70 * Configuration we use. 70 * Configuration we use.
71 */ 71 */
72 const struct GNUNET_CONFIGURATION_Handle *cfg; 72 const struct GNUNET_CONFIGURATION_Handle *cfg;
73 73
74 /** 74 /**
75 * Message queue for communicating with the NAT service. 75 * Message queue for communicating with the NAT service.
76 */ 76 */
@@ -80,7 +80,7 @@ struct GNUNET_NAT_Handle
80 * Our registration message. 80 * Our registration message.
81 */ 81 */
82 struct GNUNET_MessageHeader *reg; 82 struct GNUNET_MessageHeader *reg;
83 83
84 /** 84 /**
85 * Head of address DLL. 85 * Head of address DLL.
86 */ 86 */
@@ -95,12 +95,12 @@ struct GNUNET_NAT_Handle
95 * Function to call when our addresses change. 95 * Function to call when our addresses change.
96 */ 96 */
97 GNUNET_NAT_AddressCallback address_callback; 97 GNUNET_NAT_AddressCallback address_callback;
98 98
99 /** 99 /**
100 * Function to call when another peer requests connection reversal. 100 * Function to call when another peer requests connection reversal.
101 */ 101 */
102 GNUNET_NAT_ReversalCallback reversal_callback; 102 GNUNET_NAT_ReversalCallback reversal_callback;
103 103
104 /** 104 /**
105 * Closure for the various callbacks. 105 * Closure for the various callbacks.
106 */ 106 */
@@ -136,7 +136,7 @@ static void
136reconnect (struct GNUNET_NAT_Handle *nh) 136reconnect (struct GNUNET_NAT_Handle *nh)
137{ 137{
138 struct AddrEntry *ae; 138 struct AddrEntry *ae;
139 139
140 if (NULL != nh->mq) 140 if (NULL != nh->mq)
141 { 141 {
142 GNUNET_MQ_destroy (nh->mq); 142 GNUNET_MQ_destroy (nh->mq);
@@ -184,7 +184,7 @@ check_connection_reversal_request (void *cls,
184 return GNUNET_OK; 184 return GNUNET_OK;
185} 185}
186 186
187 187
188/** 188/**
189 * Handle connection reversal request. 189 * Handle connection reversal request.
190 * 190 *
@@ -247,7 +247,7 @@ check_address_change_notification (void *cls,
247 return GNUNET_OK; 247 return GNUNET_OK;
248} 248}
249 249
250 250
251/** 251/**
252 * Handle connection reversal request. 252 * Handle connection reversal request.
253 * 253 *
@@ -264,6 +264,8 @@ handle_address_change_notification (void *cls,
264 enum GNUNET_NAT_AddressClass ac; 264 enum GNUNET_NAT_AddressClass ac;
265 struct AddrEntry *ae; 265 struct AddrEntry *ae;
266 266
267 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
268 "Received address change notification\n");
267 ac = (enum GNUNET_NAT_AddressClass) ntohl (acn->addr_class); 269 ac = (enum GNUNET_NAT_AddressClass) ntohl (acn->addr_class);
268 if (GNUNET_YES == ntohl (acn->add_remove)) 270 if (GNUNET_YES == ntohl (acn->add_remove))
269 { 271 {
@@ -395,13 +397,13 @@ GNUNET_NAT_register (const struct GNUNET_CONFIGURATION_Handle *cfg,
395 size_t len; 397 size_t len;
396 size_t str_len; 398 size_t str_len;
397 char *off; 399 char *off;
398 400
399 len = 0; 401 len = 0;
400 for (unsigned int i=0;i<num_addrs;i++) 402 for (unsigned int i=0;i<num_addrs;i++)
401 len += addrlens[i]; 403 len += addrlens[i];
402 str_len = strlen (config_section) + 1; 404 str_len = strlen (config_section) + 1;
403 len += str_len; 405 len += str_len;
404 if ( (len > GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (*rm)) || 406 if ( (len > GNUNET_MAX_MESSAGE_SIZE - sizeof (*rm)) ||
405 (num_addrs > UINT16_MAX) ) 407 (num_addrs > UINT16_MAX) )
406 { 408 {
407 GNUNET_break (0); 409 GNUNET_break (0);
@@ -427,6 +429,7 @@ GNUNET_NAT_register (const struct GNUNET_CONFIGURATION_Handle *cfg,
427 if (sizeof (struct sockaddr_in) != addrlens[i]) 429 if (sizeof (struct sockaddr_in) != addrlens[i])
428 { 430 {
429 GNUNET_break (0); 431 GNUNET_break (0);
432 GNUNET_free (rm);
430 return NULL; 433 return NULL;
431 } 434 }
432 break; 435 break;
@@ -434,6 +437,7 @@ GNUNET_NAT_register (const struct GNUNET_CONFIGURATION_Handle *cfg,
434 if (sizeof (struct sockaddr_in6) != addrlens[i]) 437 if (sizeof (struct sockaddr_in6) != addrlens[i])
435 { 438 {
436 GNUNET_break (0); 439 GNUNET_break (0);
440 GNUNET_free (rm);
437 return NULL; 441 return NULL;
438 } 442 }
439 break; 443 break;
@@ -442,12 +446,14 @@ GNUNET_NAT_register (const struct GNUNET_CONFIGURATION_Handle *cfg,
442 if (sizeof (struct sockaddr_un) != addrlens[i]) 446 if (sizeof (struct sockaddr_un) != addrlens[i])
443 { 447 {
444 GNUNET_break (0); 448 GNUNET_break (0);
449 GNUNET_free (rm);
445 return NULL; 450 return NULL;
446 } 451 }
447 break; 452 break;
448#endif 453#endif
449 default: 454 default:
450 GNUNET_break (0); 455 GNUNET_break (0);
456 GNUNET_free (rm);
451 return NULL; 457 return NULL;
452 } 458 }
453 GNUNET_memcpy (off, 459 GNUNET_memcpy (off,
@@ -569,7 +575,7 @@ test_stun_packet (const void *data,
569 * 575 *
570 * The function does some basic sanity checks on packet size and 576 * The function does some basic sanity checks on packet size and
571 * content, try to extract a bit of information. 577 * content, try to extract a bit of information.
572 * 578 *
573 * At the moment this only processes BIND requests, and returns the 579 * At the moment this only processes BIND requests, and returns the
574 * externally visible address of the request to the rest of the 580 * externally visible address of the request to the rest of the
575 * NAT logic. 581 * NAT logic.
@@ -663,7 +669,7 @@ GNUNET_NAT_test_address (struct GNUNET_NAT_Handle *nh,
663 * @param nh handle (used for configuration) 669 * @param nh handle (used for configuration)
664 * @param local_sa our local address of the peer (IPv4-only) 670 * @param local_sa our local address of the peer (IPv4-only)
665 * @param remote_sa the remote address of the peer (IPv4-only) 671 * @param remote_sa the remote address of the peer (IPv4-only)
666 * @return #GNUNET_SYSERR on error, 672 * @return #GNUNET_SYSERR on error,
667 * #GNUNET_NO if connection reversal is unavailable, 673 * #GNUNET_NO if connection reversal is unavailable,
668 * #GNUNET_OK otherwise (presumably in progress) 674 * #GNUNET_OK otherwise (presumably in progress)
669 */ 675 */
diff --git a/src/nat/nat_stun.h b/src/nat/nat_stun.h
index 3e4228875..8d1c2720f 100644
--- a/src/nat/nat_stun.h
+++ b/src/nat/nat_stun.h
@@ -70,7 +70,7 @@ struct stun_addr
70 * Port number. 70 * Port number.
71 */ 71 */
72 uint16_t port; 72 uint16_t port;
73 73
74 /** 74 /**
75 * IPv4 address. Should this be "struct in_addr"? 75 * IPv4 address. Should this be "struct in_addr"?
76 */ 76 */
@@ -79,7 +79,7 @@ struct stun_addr
79 79
80 80
81/** 81/**
82 * STUN message classes 82 * STUN message classes
83 */ 83 */
84enum StunClasses { 84enum StunClasses {
85 INVALID_CLASS = 0, 85 INVALID_CLASS = 0,
@@ -186,18 +186,19 @@ stun_msg2str (int msg)
186 static char result[64]; 186 static char result[64];
187 const char *msg_class = NULL; 187 const char *msg_class = NULL;
188 const char *method = NULL; 188 const char *method = NULL;
189 int value; 189 enum StunClasses cvalue;
190 enum StunMethods mvalue;
190 191
191 value = decode_class (msg); 192 cvalue = decode_class (msg);
192 for (unsigned int i = 0; classes[i].name; i++) 193 for (unsigned int i = 0; classes[i].name; i++)
193 if (classes[i].value == value) 194 if (classes[i].value == cvalue)
194 { 195 {
195 msg_class = classes[i].name; 196 msg_class = classes[i].name;
196 break; 197 break;
197 } 198 }
198 value = decode_method (msg); 199 mvalue = decode_method (msg);
199 for (unsigned int i = 0; methods[i].name; i++) 200 for (unsigned int i = 0; methods[i].name; i++)
200 if (methods[i].value == value) 201 if (methods[i].value == mvalue)
201 { 202 {
202 method = methods[i].name; 203 method = methods[i].name;
203 break; 204 break;
diff --git a/src/nse/gnunet-nse-profiler.c b/src/nse/gnunet-nse-profiler.c
index 48afd9298..ea28bf610 100644
--- a/src/nse/gnunet-nse-profiler.c
+++ b/src/nse/gnunet-nse-profiler.c
@@ -129,7 +129,7 @@ static int ok;
129/** 129/**
130 * Be verbose (configuration option) 130 * Be verbose (configuration option)
131 */ 131 */
132static int verbose; 132static unsigned int verbose;
133 133
134/** 134/**
135 * Name of the file with the hosts to run the test over (configuration option) 135 * Name of the file with the hosts to run the test over (configuration option)
@@ -835,28 +835,47 @@ run (void *cls, char *const *args, const char *cfgfile,
835int 835int
836main (int argc, char *const *argv) 836main (int argc, char *const *argv)
837{ 837{
838 static struct GNUNET_GETOPT_CommandLineOption options[] = { 838 struct GNUNET_GETOPT_CommandLineOption options[] = {
839 {'C', "connections", "COUNT", 839 GNUNET_GETOPT_OPTION_SET_UINT ('C',
840 gettext_noop ("limit to the number of connections to NSE services, 0 for none"), 840 "connections",
841 1, &GNUNET_GETOPT_set_uint, &connection_limit}, 841 "COUNT",
842 {'d', "details", "FILENAME", 842 gettext_noop ("limit to the number of connections to NSE services, 0 for none"),
843 gettext_noop ("name of the file for writing connection information and statistics"), 843 &connection_limit),
844 1, &GNUNET_GETOPT_set_string, &data_filename}, 844 GNUNET_GETOPT_OPTION_STRING ('d',
845 {'H', "hosts", "FILENAME", 845 "details",
846 gettext_noop ("name of the file with the login information for the testbed"), 846 "FILENAME",
847 1, &GNUNET_GETOPT_set_string, &hosts_file}, 847 gettext_noop ("name of the file for writing connection information and statistics"),
848 {'o', "output", "FILENAME", 848 &data_filename),
849 gettext_noop ("name of the file for writing the main results"), 849
850 1, &GNUNET_GETOPT_set_string, &output_filename}, 850 GNUNET_GETOPT_OPTION_STRING ('H',
851 {'p', "peers", "NETWORKSIZESPEC", 851 "hosts",
852 gettext_noop ("Number of peers to run in each round, separated by commas"), 852 "FILENAME",
853 1, &GNUNET_GETOPT_set_string, &num_peer_spec}, 853 gettext_noop ("name of the file with the login information for the testbed"),
854 {'V', "verbose", NULL, 854 &hosts_file),
855 gettext_noop ("be verbose (print progress information)"), 855
856 0, &GNUNET_GETOPT_increment_value, &verbose}, 856 GNUNET_GETOPT_OPTION_STRING ('o',
857 {'w', "wait", "DELAY", 857 "output",
858 gettext_noop ("delay between rounds"), 858 "FILENAME",
859 1, &GNUNET_GETOPT_set_relative_time, &wait_time}, 859 gettext_noop ("name of the file for writing the main results"),
860 &output_filename),
861
862
863 GNUNET_GETOPT_OPTION_STRING ('p',
864 "peers",
865 "NETWORKSIZESPEC",
866 gettext_noop ("Number of peers to run in each round, separated by commas"),
867 &num_peer_spec),
868
869 GNUNET_GETOPT_OPTION_INCREMENT_VALUE ('V',
870 "verbose",
871 gettext_noop ("be verbose (print progress information)"),
872 &verbose),
873
874 GNUNET_GETOPT_OPTION_SET_RELATIVE_TIME ('w',
875 "wait",
876 "DELAY",
877 gettext_noop ("delay between rounds"),
878 &wait_time),
860 GNUNET_GETOPT_OPTION_END 879 GNUNET_GETOPT_OPTION_END
861 }; 880 };
862 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) 881 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
diff --git a/src/peerinfo-tool/gnunet-peerinfo.c b/src/peerinfo-tool/gnunet-peerinfo.c
index a5907c63f..59ffe2efd 100644
--- a/src/peerinfo-tool/gnunet-peerinfo.c
+++ b/src/peerinfo-tool/gnunet-peerinfo.c
@@ -837,31 +837,48 @@ state_machine (void *cls)
837int 837int
838main (int argc, char *const *argv) 838main (int argc, char *const *argv)
839{ 839{
840 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 840 struct GNUNET_GETOPT_CommandLineOption options[] = {
841 {'n', "numeric", NULL, 841 GNUNET_GETOPT_OPTION_SET_ONE ('n',
842 gettext_noop ("don't resolve host names"), 842 "numeric",
843 0, &GNUNET_GETOPT_set_one, &no_resolve}, 843 gettext_noop ("don't resolve host names"),
844 {'q', "quiet", NULL, 844 &no_resolve),
845 gettext_noop ("output only the identity strings"), 845
846 0, &GNUNET_GETOPT_set_one, &be_quiet}, 846 GNUNET_GETOPT_OPTION_SET_ONE ('q',
847 {'f', "friends", NULL, 847 "quiet",
848 gettext_noop ("include friend-only information"), 848 gettext_noop ("output only the identity strings"),
849 0, &GNUNET_GETOPT_set_one, &include_friend_only}, 849 &be_quiet),
850 {'s', "self", NULL, 850 GNUNET_GETOPT_OPTION_SET_ONE ('f',
851 gettext_noop ("output our own identity only"), 851 "friends",
852 0, &GNUNET_GETOPT_set_one, &get_self}, 852 gettext_noop ("include friend-only information"),
853 {'i', "info", NULL, 853 &include_friend_only),
854 gettext_noop ("list all known peers"), 854
855 0, &GNUNET_GETOPT_set_one, &get_info}, 855 GNUNET_GETOPT_OPTION_SET_ONE ('s',
856 {'d', "dump-hello", NULL, 856 "self",
857 gettext_noop ("dump hello to file"), 857 gettext_noop ("output our own identity only"),
858 1, &GNUNET_GETOPT_set_string, &dump_hello}, 858 &get_self),
859 {'g', "get-hello", NULL, 859
860 gettext_noop ("also output HELLO uri(s)"), 860 GNUNET_GETOPT_OPTION_SET_ONE ('i',
861 0, &GNUNET_GETOPT_set_one, &get_uri}, 861 "info",
862 {'p', "put-hello", "HELLO", 862 gettext_noop ("list all known peers"),
863 gettext_noop ("add given HELLO uri to the database"), 863 &get_info),
864 1, &GNUNET_GETOPT_set_string, &put_uri}, 864
865 GNUNET_GETOPT_OPTION_STRING ('d',
866 "dump-hello",
867 NULL,
868 gettext_noop ("dump hello to file"),
869 &dump_hello),
870
871 GNUNET_GETOPT_OPTION_SET_ONE ('g',
872 "get-hello",
873 gettext_noop ("also output HELLO uri(s)"),
874 &get_uri),
875
876 GNUNET_GETOPT_OPTION_STRING ('p',
877 "put-hello",
878 "HELLO",
879 gettext_noop ("add given HELLO uri to the database"),
880 &put_uri),
881
865 GNUNET_GETOPT_OPTION_END 882 GNUNET_GETOPT_OPTION_END
866 }; 883 };
867 int ret; 884 int ret;
diff --git a/src/peerinfo/gnunet-service-peerinfo.c b/src/peerinfo/gnunet-service-peerinfo.c
index bc4a2a10d..731c24bf1 100644
--- a/src/peerinfo/gnunet-service-peerinfo.c
+++ b/src/peerinfo/gnunet-service-peerinfo.c
@@ -283,7 +283,7 @@ read_host_file (const char *fn,
283 int unlink_garbage, 283 int unlink_garbage,
284 struct ReadHostFileContext *r) 284 struct ReadHostFileContext *r)
285{ 285{
286 char buffer[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1] GNUNET_ALIGN; 286 char buffer[GNUNET_MAX_MESSAGE_SIZE - 1] GNUNET_ALIGN;
287 ssize_t size_total; 287 ssize_t size_total;
288 struct GNUNET_TIME_Absolute now; 288 struct GNUNET_TIME_Absolute now;
289 unsigned int left; 289 unsigned int left;
@@ -919,7 +919,7 @@ add_to_tc (void *cls,
919 { 919 {
920 /* Copy public HELLO */ 920 /* Copy public HELLO */
921 hs = GNUNET_HELLO_size (pos->hello); 921 hs = GNUNET_HELLO_size (pos->hello);
922 GNUNET_assert (hs < GNUNET_SERVER_MAX_MESSAGE_SIZE - 922 GNUNET_assert (hs < GNUNET_MAX_MESSAGE_SIZE -
923 sizeof (struct InfoMessage)); 923 sizeof (struct InfoMessage));
924 env = GNUNET_MQ_msg_extra (im, 924 env = GNUNET_MQ_msg_extra (im,
925 hs, 925 hs,
@@ -937,7 +937,7 @@ add_to_tc (void *cls,
937 { 937 {
938 /* Copy friend only HELLO */ 938 /* Copy friend only HELLO */
939 hs = GNUNET_HELLO_size (pos->friend_only_hello); 939 hs = GNUNET_HELLO_size (pos->friend_only_hello);
940 GNUNET_assert (hs < GNUNET_SERVER_MAX_MESSAGE_SIZE - 940 GNUNET_assert (hs < GNUNET_MAX_MESSAGE_SIZE -
941 sizeof (struct InfoMessage)); 941 sizeof (struct InfoMessage));
942 env = GNUNET_MQ_msg_extra (im, 942 env = GNUNET_MQ_msg_extra (im,
943 hs, 943 hs,
@@ -977,7 +977,7 @@ discard_hosts_helper (void *cls,
977 const char *fn) 977 const char *fn)
978{ 978{
979 struct GNUNET_TIME_Absolute *now = cls; 979 struct GNUNET_TIME_Absolute *now = cls;
980 char buffer[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1] GNUNET_ALIGN; 980 char buffer[GNUNET_MAX_MESSAGE_SIZE - 1] GNUNET_ALIGN;
981 const struct GNUNET_HELLO_Message *hello; 981 const struct GNUNET_HELLO_Message *hello;
982 struct GNUNET_HELLO_Message *new_hello; 982 struct GNUNET_HELLO_Message *new_hello;
983 int read_size; 983 int read_size;
diff --git a/src/peerstore/Makefile.am b/src/peerstore/Makefile.am
index 21db6ad17..3aef05769 100644
--- a/src/peerstore/Makefile.am
+++ b/src/peerstore/Makefile.am
@@ -73,7 +73,9 @@ libgnunet_plugin_peerstore_sqlite_la_SOURCES = \
73 plugin_peerstore_sqlite.c 73 plugin_peerstore_sqlite.c
74libgnunet_plugin_peerstore_sqlite_la_LIBADD = \ 74libgnunet_plugin_peerstore_sqlite_la_LIBADD = \
75 libgnunetpeerstore.la \ 75 libgnunetpeerstore.la \
76 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lsqlite3 \ 76 $(top_builddir)/src/sq/libgnunetsq.la \
77 $(top_builddir)/src/util/libgnunetutil.la \
78 $(XLIBS) -lsqlite3 \
77 $(LTLIBINTL) 79 $(LTLIBINTL)
78libgnunet_plugin_peerstore_sqlite_la_LDFLAGS = \ 80libgnunet_plugin_peerstore_sqlite_la_LDFLAGS = \
79 $(GN_PLUGIN_LDFLAGS) 81 $(GN_PLUGIN_LDFLAGS)
diff --git a/src/peerstore/gnunet-service-peerstore.c b/src/peerstore/gnunet-service-peerstore.c
index 8200c2366..92d020799 100644
--- a/src/peerstore/gnunet-service-peerstore.c
+++ b/src/peerstore/gnunet-service-peerstore.c
@@ -260,15 +260,23 @@ record_iterator (void *cls,
260 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (cls_record->client), 260 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (cls_record->client),
261 env); 261 env);
262 if (NULL == emsg) 262 if (NULL == emsg)
263 {
263 GNUNET_SERVICE_client_continue (cls_record->client); 264 GNUNET_SERVICE_client_continue (cls_record->client);
265 }
264 else 266 else
267 {
268 GNUNET_break (0);
269 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
270 "Failed to iterate: %s\n",
271 emsg);
265 GNUNET_SERVICE_client_drop (cls_record->client); 272 GNUNET_SERVICE_client_drop (cls_record->client);
273 }
266 PEERSTORE_destroy_record (cls_record); 274 PEERSTORE_destroy_record (cls_record);
267 return; 275 return;
268 } 276 }
269 277
270 env = PEERSTORE_create_record_mq_envelope (record->sub_system, 278 env = PEERSTORE_create_record_mq_envelope (record->sub_system,
271 record->peer, 279 &record->peer,
272 record->key, 280 record->key,
273 record->value, 281 record->value,
274 record->value_size, 282 record->value_size,
@@ -301,7 +309,7 @@ watch_notifier_it (void *cls,
301 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 309 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
302 "Found a watcher to update.\n"); 310 "Found a watcher to update.\n");
303 env = PEERSTORE_create_record_mq_envelope (record->sub_system, 311 env = PEERSTORE_create_record_mq_envelope (record->sub_system,
304 record->peer, 312 &record->peer,
305 record->key, 313 record->key,
306 record->value, 314 record->value,
307 record->value_size, 315 record->value_size,
@@ -325,7 +333,7 @@ watch_notifier (struct GNUNET_PEERSTORE_Record *record)
325 struct GNUNET_HashCode keyhash; 333 struct GNUNET_HashCode keyhash;
326 334
327 PEERSTORE_hash_key (record->sub_system, 335 PEERSTORE_hash_key (record->sub_system,
328 record->peer, 336 &record->peer,
329 record->key, 337 record->key,
330 &keyhash); 338 &keyhash);
331 GNUNET_CONTAINER_multihashmap_get_multiple (watchers, 339 GNUNET_CONTAINER_multihashmap_get_multiple (watchers,
@@ -434,17 +442,18 @@ handle_iterate (void *cls,
434 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 442 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
435 "Iterate request: ss `%s', peer `%s', key `%s'\n", 443 "Iterate request: ss `%s', peer `%s', key `%s'\n",
436 record->sub_system, 444 record->sub_system,
437 (NULL == record->peer) ? "NULL" : GNUNET_i2s (record->peer), 445 GNUNET_i2s (&record->peer),
438 (NULL == record->key) ? "NULL" : record->key); 446 (NULL == record->key) ? "NULL" : record->key);
439 record->client = client; 447 record->client = client;
440 if (GNUNET_OK != 448 if (GNUNET_OK !=
441 db->iterate_records (db->cls, 449 db->iterate_records (db->cls,
442 record->sub_system, 450 record->sub_system,
443 record->peer, 451 (ntohs (srm->peer_set)) ? &record->peer : NULL,
444 record->key, 452 record->key,
445 &record_iterator, 453 &record_iterator,
446 record)) 454 record))
447 { 455 {
456 GNUNET_break (0);
448 GNUNET_SERVICE_client_drop (client); 457 GNUNET_SERVICE_client_drop (client);
449 PEERSTORE_destroy_record (record); 458 PEERSTORE_destroy_record (record);
450 } 459 }
@@ -470,6 +479,7 @@ store_record_continuation (void *cls,
470 } 479 }
471 else 480 else
472 { 481 {
482 GNUNET_break (0);
473 GNUNET_SERVICE_client_drop (record->client); 483 GNUNET_SERVICE_client_drop (record->client);
474 } 484 }
475 PEERSTORE_destroy_record (record); 485 PEERSTORE_destroy_record (record);
@@ -496,7 +506,6 @@ check_store (void *cls,
496 return GNUNET_SYSERR; 506 return GNUNET_SYSERR;
497 } 507 }
498 if ( (NULL == record->sub_system) || 508 if ( (NULL == record->sub_system) ||
499 (NULL == record->peer) ||
500 (NULL == record->key) ) 509 (NULL == record->key) )
501 { 510 {
502 GNUNET_break (0); 511 GNUNET_break (0);
@@ -525,22 +534,23 @@ handle_store (void *cls,
525 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 534 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
526 "Received a store request. Sub system `%s' Peer `%s Key `%s' Options: %u.\n", 535 "Received a store request. Sub system `%s' Peer `%s Key `%s' Options: %u.\n",
527 record->sub_system, 536 record->sub_system,
528 GNUNET_i2s (record->peer), 537 GNUNET_i2s (&record->peer),
529 record->key, 538 record->key,
530 (uint32_t) ntohl (srm->options)); 539 (uint32_t) ntohl (srm->options));
531 record->client = client; 540 record->client = client;
532 if (GNUNET_OK != 541 if (GNUNET_OK !=
533 db->store_record (db->cls, 542 db->store_record (db->cls,
534 record->sub_system, 543 record->sub_system,
535 record->peer, 544 &record->peer,
536 record->key, 545 record->key,
537 record->value, 546 record->value,
538 record->value_size, 547 record->value_size,
539 *record->expiry, 548 record->expiry,
540 ntohl (srm->options), 549 ntohl (srm->options),
541 &store_record_continuation, 550 &store_record_continuation,
542 record)) 551 record))
543 { 552 {
553 GNUNET_break (0);
544 PEERSTORE_destroy_record (record); 554 PEERSTORE_destroy_record (record);
545 GNUNET_SERVICE_client_drop (client); 555 GNUNET_SERVICE_client_drop (client);
546 return; 556 return;
diff --git a/src/peerstore/peerstore.h b/src/peerstore/peerstore.h
index 8b3c4dd92..c6b954676 100644
--- a/src/peerstore/peerstore.h
+++ b/src/peerstore/peerstore.h
@@ -60,7 +60,7 @@ struct StoreRecordMessage
60 /** 60 /**
61 * Expiry time of entry 61 * Expiry time of entry
62 */ 62 */
63 struct GNUNET_TIME_Absolute expiry GNUNET_PACKED; 63 struct GNUNET_TIME_AbsoluteNBO expiry;
64 64
65 /** 65 /**
66 * Size of the key string 66 * Size of the key string
diff --git a/src/peerstore/peerstore_api.c b/src/peerstore/peerstore_api.c
index c9fcd17ab..df182fe10 100644
--- a/src/peerstore/peerstore_api.c
+++ b/src/peerstore/peerstore_api.c
@@ -286,6 +286,10 @@ store_request_sent (void *cls)
286/******************* CONNECTION FUNCTIONS *********************/ 286/******************* CONNECTION FUNCTIONS *********************/
287/******************************************************************************/ 287/******************************************************************************/
288 288
289
290/**
291 * Function called when we had trouble talking to the service.
292 */
289static void 293static void
290handle_client_error (void *cls, 294handle_client_error (void *cls,
291 enum GNUNET_MQ_Error error) 295 enum GNUNET_MQ_Error error)
@@ -293,7 +297,7 @@ handle_client_error (void *cls,
293 struct GNUNET_PEERSTORE_Handle *h = cls; 297 struct GNUNET_PEERSTORE_Handle *h = cls;
294 298
295 LOG (GNUNET_ERROR_TYPE_ERROR, 299 LOG (GNUNET_ERROR_TYPE_ERROR,
296 _("Received an error notification from MQ of type: %d\n"), 300 "Received an error notification from MQ of type: %d\n",
297 error); 301 error);
298 reconnect (h); 302 reconnect (h);
299} 303}
@@ -341,7 +345,9 @@ iterate_timeout (void *cls)
341 callback_cls = ic->callback_cls; 345 callback_cls = ic->callback_cls;
342 GNUNET_PEERSTORE_iterate_cancel (ic); 346 GNUNET_PEERSTORE_iterate_cancel (ic);
343 if (NULL != callback) 347 if (NULL != callback)
344 callback (callback_cls, NULL, _("timeout")); 348 callback (callback_cls,
349 NULL,
350 _("timeout"));
345} 351}
346 352
347 353
@@ -510,7 +516,7 @@ GNUNET_PEERSTORE_store (struct GNUNET_PEERSTORE_Handle *h,
510 "Storing value (size: %lu) for subsytem `%s', peer `%s', key `%s'\n", 516 "Storing value (size: %lu) for subsytem `%s', peer `%s', key `%s'\n",
511 size, sub_system, GNUNET_i2s (peer), key); 517 size, sub_system, GNUNET_i2s (peer), key);
512 ev = PEERSTORE_create_record_mq_envelope (sub_system, peer, key, value, size, 518 ev = PEERSTORE_create_record_mq_envelope (sub_system, peer, key, value, size,
513 &expiry, options, 519 expiry, options,
514 GNUNET_MESSAGE_TYPE_PEERSTORE_STORE); 520 GNUNET_MESSAGE_TYPE_PEERSTORE_STORE);
515 sc = GNUNET_new (struct GNUNET_PEERSTORE_StoreContext); 521 sc = GNUNET_new (struct GNUNET_PEERSTORE_StoreContext);
516 522
@@ -684,8 +690,12 @@ GNUNET_PEERSTORE_iterate (struct GNUNET_PEERSTORE_Handle *h,
684 struct GNUNET_MQ_Envelope *ev; 690 struct GNUNET_MQ_Envelope *ev;
685 struct GNUNET_PEERSTORE_IterateContext *ic; 691 struct GNUNET_PEERSTORE_IterateContext *ic;
686 692
687 ev = PEERSTORE_create_record_mq_envelope (sub_system, peer, key, NULL, 0, 693 ev = PEERSTORE_create_record_mq_envelope (sub_system,
694 peer,
695 key,
688 NULL, 0, 696 NULL, 0,
697 GNUNET_TIME_UNIT_FOREVER_ABS,
698 0,
689 GNUNET_MESSAGE_TYPE_PEERSTORE_ITERATE); 699 GNUNET_MESSAGE_TYPE_PEERSTORE_ITERATE);
690 ic = GNUNET_new (struct GNUNET_PEERSTORE_IterateContext); 700 ic = GNUNET_new (struct GNUNET_PEERSTORE_IterateContext);
691 701
@@ -756,7 +766,7 @@ handle_watch_record (void *cls,
756 return; 766 return;
757 } 767 }
758 PEERSTORE_hash_key (record->sub_system, 768 PEERSTORE_hash_key (record->sub_system,
759 record->peer, 769 &record->peer,
760 record->key, 770 record->key,
761 &keyhash); 771 &keyhash);
762 // FIXME: what if there are multiple watches for the same key? 772 // FIXME: what if there are multiple watches for the same key?
@@ -848,9 +858,12 @@ reconnect (struct GNUNET_PEERSTORE_Handle *h)
848 &ic->peer, 858 &ic->peer,
849 ic->key, 859 ic->key,
850 NULL, 0, 860 NULL, 0,
851 NULL, 0, 861 GNUNET_TIME_UNIT_FOREVER_ABS,
862 0,
852 GNUNET_MESSAGE_TYPE_PEERSTORE_ITERATE); 863 GNUNET_MESSAGE_TYPE_PEERSTORE_ITERATE);
853 GNUNET_MQ_send (h->mq, ev); 864 GNUNET_MQ_send (h->mq, ev);
865 if (NULL != ic->timeout_task)
866 GNUNET_SCHEDULER_cancel (ic->timeout_task);
854 ic->timeout_task 867 ic->timeout_task
855 = GNUNET_SCHEDULER_add_delayed (ic->timeout, 868 = GNUNET_SCHEDULER_add_delayed (ic->timeout,
856 &iterate_timeout, 869 &iterate_timeout,
@@ -863,7 +876,7 @@ reconnect (struct GNUNET_PEERSTORE_Handle *h)
863 sc->key, 876 sc->key,
864 sc->value, 877 sc->value,
865 sc->size, 878 sc->size,
866 &sc->expiry, 879 sc->expiry,
867 sc->options, 880 sc->options,
868 GNUNET_MESSAGE_TYPE_PEERSTORE_STORE); 881 GNUNET_MESSAGE_TYPE_PEERSTORE_STORE);
869 GNUNET_MQ_notify_sent (ev, 882 GNUNET_MQ_notify_sent (ev,
diff --git a/src/peerstore/peerstore_common.c b/src/peerstore/peerstore_common.c
index d12c4e21e..e0ab778fa 100644
--- a/src/peerstore/peerstore_common.c
+++ b/src/peerstore/peerstore_common.c
@@ -77,7 +77,7 @@ PEERSTORE_create_record_mq_envelope (const char *sub_system,
77 const char *key, 77 const char *key,
78 const void *value, 78 const void *value,
79 size_t value_size, 79 size_t value_size,
80 struct GNUNET_TIME_Absolute *expiry, 80 struct GNUNET_TIME_Absolute expiry,
81 enum GNUNET_PEERSTORE_StoreOption options, 81 enum GNUNET_PEERSTORE_StoreOption options,
82 uint16_t msg_type) 82 uint16_t msg_type)
83{ 83{
@@ -97,8 +97,7 @@ PEERSTORE_create_record_mq_envelope (const char *sub_system,
97 msg_size = ss_size + key_size + value_size; 97 msg_size = ss_size + key_size + value_size;
98 ev = GNUNET_MQ_msg_extra (srm, msg_size, msg_type); 98 ev = GNUNET_MQ_msg_extra (srm, msg_size, msg_type);
99 srm->key_size = htons (key_size); 99 srm->key_size = htons (key_size);
100 if (NULL != expiry) 100 srm->expiry = GNUNET_TIME_absolute_hton (expiry);
101 srm->expiry = *expiry;
102 if (NULL == peer) 101 if (NULL == peer)
103 srm->peer_set = htons (GNUNET_NO); 102 srm->peer_set = htons (GNUNET_NO);
104 else 103 else
@@ -147,12 +146,9 @@ PEERSTORE_parse_record_message (const struct StoreRecordMessage *srm)
147 record = GNUNET_new (struct GNUNET_PEERSTORE_Record); 146 record = GNUNET_new (struct GNUNET_PEERSTORE_Record);
148 if (GNUNET_YES == ntohs (srm->peer_set)) 147 if (GNUNET_YES == ntohs (srm->peer_set))
149 { 148 {
150 record->peer = GNUNET_new (struct GNUNET_PeerIdentity); 149 record->peer = srm->peer;
151 *record->peer = srm->peer;
152 } 150 }
153 record->expiry = GNUNET_new (struct GNUNET_TIME_Absolute); 151 record->expiry = GNUNET_TIME_absolute_ntoh (srm->expiry);
154
155 *(record->expiry) = srm->expiry;
156 dummy = (char *) &srm[1]; 152 dummy = (char *) &srm[1];
157 if (ss_size > 0) 153 if (ss_size > 0)
158 { 154 {
@@ -167,7 +163,9 @@ PEERSTORE_parse_record_message (const struct StoreRecordMessage *srm)
167 if (value_size > 0) 163 if (value_size > 0)
168 { 164 {
169 record->value = GNUNET_malloc (value_size); 165 record->value = GNUNET_malloc (value_size);
170 GNUNET_memcpy (record->value, dummy, value_size); 166 GNUNET_memcpy (record->value,
167 dummy,
168 value_size);
171 } 169 }
172 record->value_size = value_size; 170 record->value_size = value_size;
173 return record; 171 return record;
@@ -184,8 +182,6 @@ PEERSTORE_destroy_record (struct GNUNET_PEERSTORE_Record *record)
184{ 182{
185 if (NULL != record->sub_system) 183 if (NULL != record->sub_system)
186 GNUNET_free (record->sub_system); 184 GNUNET_free (record->sub_system);
187 if (NULL != record->peer)
188 GNUNET_free (record->peer);
189 if (NULL != record->key) 185 if (NULL != record->key)
190 GNUNET_free (record->key); 186 GNUNET_free (record->key);
191 if (NULL != record->value) 187 if (NULL != record->value)
@@ -193,7 +189,5 @@ PEERSTORE_destroy_record (struct GNUNET_PEERSTORE_Record *record)
193 GNUNET_free (record->value); 189 GNUNET_free (record->value);
194 record->value = 0; 190 record->value = 0;
195 } 191 }
196 if (NULL != record->expiry)
197 GNUNET_free (record->expiry);
198 GNUNET_free (record); 192 GNUNET_free (record);
199} 193}
diff --git a/src/peerstore/peerstore_common.h b/src/peerstore/peerstore_common.h
index 3d938b5da..0fc14d9b4 100644
--- a/src/peerstore/peerstore_common.h
+++ b/src/peerstore/peerstore_common.h
@@ -56,7 +56,7 @@ PEERSTORE_create_record_mq_envelope (const char *sub_system,
56 const char *key, 56 const char *key,
57 const void *value, 57 const void *value,
58 size_t value_size, 58 size_t value_size,
59 struct GNUNET_TIME_Absolute *expiry, 59 struct GNUNET_TIME_Absolute expiry,
60 enum GNUNET_PEERSTORE_StoreOption options, 60 enum GNUNET_PEERSTORE_StoreOption options,
61 uint16_t msg_type); 61 uint16_t msg_type);
62 62
diff --git a/src/peerstore/plugin_peerstore_flat.c b/src/peerstore/plugin_peerstore_flat.c
index 2b90719d9..c75b2b1e4 100644
--- a/src/peerstore/plugin_peerstore_flat.c
+++ b/src/peerstore/plugin_peerstore_flat.c
@@ -107,7 +107,9 @@ delete_entries (void *cls,
107 struct GNUNET_PEERSTORE_Record *entry = value; 107 struct GNUNET_PEERSTORE_Record *entry = value;
108 if (0 != strcmp (plugin->iter_key, entry->key)) 108 if (0 != strcmp (plugin->iter_key, entry->key))
109 return GNUNET_YES; 109 return GNUNET_YES;
110 if (0 != memcmp (plugin->iter_peer, entry->peer, sizeof (struct GNUNET_PeerIdentity))) 110 if (0 != memcmp (plugin->iter_peer,
111 &entry->peer,
112 sizeof (struct GNUNET_PeerIdentity)))
111 return GNUNET_YES; 113 return GNUNET_YES;
112 if (0 != strcmp (plugin->iter_sub_system, entry->sub_system)) 114 if (0 != strcmp (plugin->iter_sub_system, entry->sub_system))
113 return GNUNET_YES; 115 return GNUNET_YES;
@@ -153,7 +155,7 @@ expire_entries (void *cls,
153 struct Plugin *plugin = cls; 155 struct Plugin *plugin = cls;
154 struct GNUNET_PEERSTORE_Record *entry = value; 156 struct GNUNET_PEERSTORE_Record *entry = value;
155 157
156 if (entry->expiry->abs_value_us < plugin->iter_now.abs_value_us) 158 if (entry->expiry.abs_value_us < plugin->iter_now.abs_value_us)
157 { 159 {
158 GNUNET_CONTAINER_multihashmap_remove (plugin->hm, key, value); 160 GNUNET_CONTAINER_multihashmap_remove (plugin->hm, key, value);
159 plugin->exp_changes++; 161 plugin->exp_changes++;
@@ -204,7 +206,7 @@ iterate_entries (void *cls,
204 206
205 if ((NULL != plugin->iter_peer) && 207 if ((NULL != plugin->iter_peer) &&
206 (0 != memcmp (plugin->iter_peer, 208 (0 != memcmp (plugin->iter_peer,
207 entry->peer, 209 &entry->peer,
208 sizeof (struct GNUNET_PeerIdentity)))) 210 sizeof (struct GNUNET_PeerIdentity))))
209 { 211 {
210 return GNUNET_YES; 212 return GNUNET_YES;
@@ -296,10 +298,8 @@ peerstore_flat_store_record (void *cls, const char *sub_system,
296 entry->value = GNUNET_malloc (size); 298 entry->value = GNUNET_malloc (size);
297 GNUNET_memcpy (entry->value, value, size); 299 GNUNET_memcpy (entry->value, value, size);
298 entry->value_size = size; 300 entry->value_size = size;
299 entry->peer = GNUNET_new (struct GNUNET_PeerIdentity); 301 entry->peer = *peer;
300 GNUNET_memcpy (entry->peer, peer, sizeof (struct GNUNET_PeerIdentity)); 302 entry->expiry = expiry;
301 entry->expiry = GNUNET_new (struct GNUNET_TIME_Absolute);
302 entry->expiry->abs_value_us = expiry.abs_value_us;
303 303
304 peer_id = GNUNET_i2s (peer); 304 peer_id = GNUNET_i2s (peer);
305 GNUNET_CRYPTO_hash (peer_id, 305 GNUNET_CRYPTO_hash (peer_id,
@@ -409,7 +409,7 @@ database_setup (struct Plugin *plugin)
409 GNUNET_free (buffer); 409 GNUNET_free (buffer);
410 return GNUNET_SYSERR; 410 return GNUNET_SYSERR;
411 } 411 }
412 412
413 buffer[size] = '\0'; 413 buffer[size] = '\0';
414 GNUNET_DISK_file_close (fh); 414 GNUNET_DISK_file_close (fh);
415 if (0 < size) { 415 if (0 < size) {
@@ -433,22 +433,35 @@ database_setup (struct Plugin *plugin)
433 entry = GNUNET_new (struct GNUNET_PEERSTORE_Record); 433 entry = GNUNET_new (struct GNUNET_PEERSTORE_Record);
434 entry->sub_system = GNUNET_strdup (sub_system); 434 entry->sub_system = GNUNET_strdup (sub_system);
435 entry->key = GNUNET_strdup (key); 435 entry->key = GNUNET_strdup (key);
436 GNUNET_STRINGS_base64_decode (peer, 436 {
437 strlen (peer), 437 size_t s;
438 (char**)&entry->peer); 438 char *o;
439
440 o = NULL;
441 s = GNUNET_STRINGS_base64_decode (peer,
442 strlen (peer),
443 &o);
444 if (sizeof (struct GNUNET_PeerIdentity) == s)
445 GNUNET_memcpy (&entry->peer,
446 o,
447 s);
448 else
449 GNUNET_break (0);
450 GNUNET_free_non_null (o);
451 }
439 entry->value_size = GNUNET_STRINGS_base64_decode (value, 452 entry->value_size = GNUNET_STRINGS_base64_decode (value,
440 strlen (value), 453 strlen (value),
441 (char**)&entry->value); 454 (char**)&entry->value);
442 if (GNUNET_SYSERR == GNUNET_STRINGS_fancy_time_to_absolute (expiry, 455 if (GNUNET_SYSERR ==
443 entry->expiry)) 456 GNUNET_STRINGS_fancy_time_to_absolute (expiry,
457 &entry->expiry))
444 { 458 {
445 GNUNET_free (entry->sub_system); 459 GNUNET_free (entry->sub_system);
446 GNUNET_free (entry->key); 460 GNUNET_free (entry->key);
447 GNUNET_free (entry->peer);
448 GNUNET_free (entry); 461 GNUNET_free (entry);
449 break; 462 break;
450 } 463 }
451 peer_id = GNUNET_i2s (entry->peer); 464 peer_id = GNUNET_i2s (&entry->peer);
452 GNUNET_CRYPTO_hash (peer_id, 465 GNUNET_CRYPTO_hash (peer_id,
453 strlen (peer_id), 466 strlen (peer_id),
454 &hkey); 467 &hkey);
@@ -479,8 +492,8 @@ store_and_free_entries (void *cls,
479 GNUNET_STRINGS_base64_encode (entry->value, 492 GNUNET_STRINGS_base64_encode (entry->value,
480 entry->value_size, 493 entry->value_size,
481 &val); 494 &val);
482 expiry = GNUNET_STRINGS_absolute_time_to_string (*entry->expiry); 495 expiry = GNUNET_STRINGS_absolute_time_to_string (entry->expiry);
483 GNUNET_STRINGS_base64_encode ((char*)entry->peer, 496 GNUNET_STRINGS_base64_encode ((char*)&entry->peer,
484 sizeof (struct GNUNET_PeerIdentity), 497 sizeof (struct GNUNET_PeerIdentity),
485 &peer); 498 &peer);
486 GNUNET_asprintf (&line, 499 GNUNET_asprintf (&line,
@@ -496,10 +509,8 @@ store_and_free_entries (void *cls,
496 line, 509 line,
497 strlen (line)); 510 strlen (line));
498 GNUNET_free (entry->sub_system); 511 GNUNET_free (entry->sub_system);
499 GNUNET_free (entry->peer);
500 GNUNET_free (entry->key); 512 GNUNET_free (entry->key);
501 GNUNET_free (entry->value); 513 GNUNET_free (entry->value);
502 GNUNET_free (entry->expiry);
503 GNUNET_free (entry); 514 GNUNET_free (entry);
504 GNUNET_free (line); 515 GNUNET_free (line);
505 return GNUNET_YES; 516 return GNUNET_YES;
diff --git a/src/peerstore/plugin_peerstore_sqlite.c b/src/peerstore/plugin_peerstore_sqlite.c
index 2cd7e22cf..440263d44 100644
--- a/src/peerstore/plugin_peerstore_sqlite.c
+++ b/src/peerstore/plugin_peerstore_sqlite.c
@@ -1,6 +1,6 @@
1/* 1/*
2 * This file is part of GNUnet 2 * This file is part of GNUnet
3 * Copyright (C) 2013 GNUnet e.V. 3 * Copyright (C) 2013, 2017 GNUnet e.V.
4 * 4 *
5 * GNUnet is free software; you can redistribute it and/or modify 5 * GNUnet is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published 6 * it under the terms of the GNU General Public License as published
@@ -22,11 +22,13 @@
22 * @file peerstore/plugin_peerstore_sqlite.c 22 * @file peerstore/plugin_peerstore_sqlite.c
23 * @brief sqlite-based peerstore backend 23 * @brief sqlite-based peerstore backend
24 * @author Omar Tarabai 24 * @author Omar Tarabai
25 * @author Christian Grothoff
25 */ 26 */
26 27
27#include "platform.h" 28#include "platform.h"
28#include "gnunet_peerstore_plugin.h" 29#include "gnunet_peerstore_plugin.h"
29#include "gnunet_peerstore_service.h" 30#include "gnunet_peerstore_service.h"
31#include "gnunet_sq_lib.h"
30#include "peerstore.h" 32#include "peerstore.h"
31#include <sqlite3.h> 33#include <sqlite3.h>
32 34
@@ -111,6 +113,7 @@ struct Plugin
111 113
112}; 114};
113 115
116
114/** 117/**
115 * Delete records with the given key 118 * Delete records with the given key
116 * 119 *
@@ -118,40 +121,50 @@ struct Plugin
118 * @param sub_system name of sub system 121 * @param sub_system name of sub system
119 * @param peer Peer identity (can be NULL) 122 * @param peer Peer identity (can be NULL)
120 * @param key entry key string (can be NULL) 123 * @param key entry key string (can be NULL)
121 * @return number of deleted records 124 * @return number of deleted records, #GNUNE_SYSERR on error
122 */ 125 */
123static int 126static int
124peerstore_sqlite_delete_records (void *cls, const char *sub_system, 127peerstore_sqlite_delete_records (void *cls,
128 const char *sub_system,
125 const struct GNUNET_PeerIdentity *peer, 129 const struct GNUNET_PeerIdentity *peer,
126 const char *key) 130 const char *key)
127{ 131{
128 struct Plugin *plugin = cls; 132 struct Plugin *plugin = cls;
129 sqlite3_stmt *stmt = plugin->delete_peerstoredata; 133 sqlite3_stmt *stmt = plugin->delete_peerstoredata;
134 struct GNUNET_SQ_QueryParam params[] = {
135 GNUNET_SQ_query_param_string (sub_system),
136 GNUNET_SQ_query_param_auto_from_type (peer),
137 GNUNET_SQ_query_param_string (key),
138 GNUNET_SQ_query_param_end
139 };
140 int ret;
130 141
131 if ((SQLITE_OK != 142 if (GNUNET_OK !=
132 sqlite3_bind_text (stmt, 1, sub_system, strlen (sub_system) + 1, 143 GNUNET_SQ_bind (stmt,
133 SQLITE_STATIC)) || 144 params))
134 (SQLITE_OK !=
135 sqlite3_bind_blob (stmt, 2, peer, sizeof (struct GNUNET_PeerIdentity),
136 SQLITE_STATIC)) ||
137 (SQLITE_OK !=
138 sqlite3_bind_text (stmt, 3, key, strlen (key) + 1, SQLITE_STATIC)))
139 { 145 {
140 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 146 LOG_SQLITE (plugin,
147 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
141 "sqlite3_bind"); 148 "sqlite3_bind");
149 GNUNET_SQ_reset (plugin->dbh,
150 stmt);
151 return GNUNET_SYSERR;
142 } 152 }
143 else if (SQLITE_DONE != sqlite3_step (stmt)) 153 if (SQLITE_DONE !=
154 sqlite3_step (stmt))
144 { 155 {
145 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 156 LOG_SQLITE (plugin,
157 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
146 "sqlite3_step"); 158 "sqlite3_step");
159 ret = GNUNET_SYSERR;
147 } 160 }
148 if (SQLITE_OK != sqlite3_reset (stmt)) 161 else
149 { 162 {
150 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 163 ret = sqlite3_changes (plugin->dbh);
151 "sqlite3_reset");
152 return 0;
153 } 164 }
154 return sqlite3_changes (plugin->dbh); 165 GNUNET_SQ_reset (plugin->dbh,
166 stmt);
167 return ret;
155} 168}
156 169
157 170
@@ -172,28 +185,36 @@ peerstore_sqlite_expire_records (void *cls, struct GNUNET_TIME_Absolute now,
172{ 185{
173 struct Plugin *plugin = cls; 186 struct Plugin *plugin = cls;
174 sqlite3_stmt *stmt = plugin->expire_peerstoredata; 187 sqlite3_stmt *stmt = plugin->expire_peerstoredata;
188 struct GNUNET_SQ_QueryParam params[] = {
189 GNUNET_SQ_query_param_absolute_time (&now),
190 GNUNET_SQ_query_param_end
191 };
175 192
176 if (SQLITE_OK != 193 if (GNUNET_OK !=
177 sqlite3_bind_int64 (stmt, 1, (sqlite3_uint64) now.abs_value_us)) 194 GNUNET_SQ_bind (stmt,
195 params))
178 { 196 {
179 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 197 LOG_SQLITE (plugin,
198 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
180 "sqlite3_bind"); 199 "sqlite3_bind");
200 GNUNET_SQ_reset (plugin->dbh,
201 stmt);
202 return GNUNET_SYSERR;
181 } 203 }
182 else if (SQLITE_DONE != sqlite3_step (stmt)) 204 if (SQLITE_DONE != sqlite3_step (stmt))
183 { 205 {
184 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 206 LOG_SQLITE (plugin,
207 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
185 "sqlite3_step"); 208 "sqlite3_step");
186 } 209 GNUNET_SQ_reset (plugin->dbh,
187 if (SQLITE_OK != sqlite3_reset (stmt)) 210 stmt);
188 {
189 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
190 "sqlite3_reset");
191 return GNUNET_SYSERR; 211 return GNUNET_SYSERR;
192 } 212 }
193 if (NULL != cont) 213 if (NULL != cont)
194 { 214 cont (cont_cls,
195 cont (cont_cls, sqlite3_changes (plugin->dbh)); 215 sqlite3_changes (plugin->dbh));
196 } 216 GNUNET_SQ_reset (plugin->dbh,
217 stmt);
197 return GNUNET_OK; 218 return GNUNET_OK;
198} 219}
199 220
@@ -213,7 +234,8 @@ peerstore_sqlite_expire_records (void *cls, struct GNUNET_TIME_Absolute now,
213 * called 234 * called
214 */ 235 */
215static int 236static int
216peerstore_sqlite_iterate_records (void *cls, const char *sub_system, 237peerstore_sqlite_iterate_records (void *cls,
238 const char *sub_system,
217 const struct GNUNET_PeerIdentity *peer, 239 const struct GNUNET_PeerIdentity *peer,
218 const char *key, 240 const char *key,
219 GNUNET_PEERSTORE_Processor iter, 241 GNUNET_PEERSTORE_Processor iter,
@@ -223,94 +245,115 @@ peerstore_sqlite_iterate_records (void *cls, const char *sub_system,
223 sqlite3_stmt *stmt; 245 sqlite3_stmt *stmt;
224 int err = 0; 246 int err = 0;
225 int sret; 247 int sret;
226 struct GNUNET_PEERSTORE_Record *ret; 248 struct GNUNET_PEERSTORE_Record rec;
227 249
228 LOG (GNUNET_ERROR_TYPE_DEBUG, "Executing iterate request on sqlite db.\n"); 250 LOG (GNUNET_ERROR_TYPE_DEBUG,
229 if (NULL == peer && NULL == key) 251 "Executing iterate request on sqlite db.\n");
230 { 252 if (NULL == peer)
231 stmt = plugin->select_peerstoredata;
232 err =
233 (SQLITE_OK !=
234 sqlite3_bind_text (stmt, 1, sub_system, strlen (sub_system) + 1,
235 SQLITE_STATIC));
236 }
237 else if (NULL == key)
238 {
239 stmt = plugin->select_peerstoredata_by_pid;
240 err =
241 (SQLITE_OK !=
242 sqlite3_bind_text (stmt, 1, sub_system, strlen (sub_system) + 1,
243 SQLITE_STATIC)) ||
244 (SQLITE_OK !=
245 sqlite3_bind_blob (stmt, 2, peer, sizeof (struct GNUNET_PeerIdentity),
246 SQLITE_STATIC));
247 }
248 else if (NULL == peer)
249 { 253 {
250 stmt = plugin->select_peerstoredata_by_key; 254 if (NULL == key)
251 err = 255 {
252 (SQLITE_OK != 256 struct GNUNET_SQ_QueryParam params[] = {
253 sqlite3_bind_text (stmt, 1, sub_system, strlen (sub_system) + 1, 257 GNUNET_SQ_query_param_string (sub_system),
254 SQLITE_STATIC)) || 258 GNUNET_SQ_query_param_end
255 (SQLITE_OK != 259 };
256 sqlite3_bind_text (stmt, 2, key, strlen (key) + 1, SQLITE_STATIC)); 260
261 stmt = plugin->select_peerstoredata;
262 err = GNUNET_SQ_bind (stmt,
263 params);
264 }
265 else
266 {
267 struct GNUNET_SQ_QueryParam params[] = {
268 GNUNET_SQ_query_param_string (sub_system),
269 GNUNET_SQ_query_param_string (key),
270 GNUNET_SQ_query_param_end
271 };
272
273 stmt = plugin->select_peerstoredata_by_key;
274 err = GNUNET_SQ_bind (stmt,
275 params);
276 }
257 } 277 }
258 else 278 else
259 { 279 {
260 stmt = plugin->select_peerstoredata_by_all; 280 if (NULL == key)
261 err = 281 {
262 (SQLITE_OK != 282 struct GNUNET_SQ_QueryParam params[] = {
263 sqlite3_bind_text (stmt, 1, sub_system, strlen (sub_system) + 1, 283 GNUNET_SQ_query_param_string (sub_system),
264 SQLITE_STATIC)) || 284 GNUNET_SQ_query_param_auto_from_type (peer),
265 (SQLITE_OK != 285 GNUNET_SQ_query_param_end
266 sqlite3_bind_blob (stmt, 2, peer, sizeof (struct GNUNET_PeerIdentity), 286 };
267 SQLITE_STATIC)) || 287
268 (SQLITE_OK != 288 stmt = plugin->select_peerstoredata_by_pid;
269 sqlite3_bind_text (stmt, 3, key, strlen (key) + 1, SQLITE_STATIC)); 289 err = GNUNET_SQ_bind (stmt,
290 params);
291 }
292 else
293 {
294 struct GNUNET_SQ_QueryParam params[] = {
295 GNUNET_SQ_query_param_string (sub_system),
296 GNUNET_SQ_query_param_auto_from_type (peer),
297 GNUNET_SQ_query_param_string (key),
298 GNUNET_SQ_query_param_end
299 };
300
301 stmt = plugin->select_peerstoredata_by_all;
302 err = GNUNET_SQ_bind (stmt,
303 params);
304 }
270 } 305 }
271 306
272 if (err) 307 if (GNUNET_OK != err)
273 { 308 {
274 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 309 LOG_SQLITE (plugin,
310 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
275 "sqlite3_bind_XXXX"); 311 "sqlite3_bind_XXXX");
276 if (SQLITE_OK != sqlite3_reset (stmt)) 312 GNUNET_SQ_reset (plugin->dbh,
277 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 313 stmt);
278 "sqlite3_reset");
279 return GNUNET_SYSERR; 314 return GNUNET_SYSERR;
280 } 315 }
316
317 err = 0;
281 while (SQLITE_ROW == (sret = sqlite3_step (stmt))) 318 while (SQLITE_ROW == (sret = sqlite3_step (stmt)))
282 { 319 {
283 LOG (GNUNET_ERROR_TYPE_DEBUG, "Returning a matched record.\n"); 320 LOG (GNUNET_ERROR_TYPE_DEBUG,
284 ret = GNUNET_new (struct GNUNET_PEERSTORE_Record); 321 "Returning a matched record.\n");
285 322 struct GNUNET_SQ_ResultSpec rs[] = {
286 ret->sub_system = (char *) sqlite3_column_text (stmt, 0); 323 GNUNET_SQ_result_spec_string (&rec.sub_system),
287 ret->peer = (struct GNUNET_PeerIdentity *) sqlite3_column_blob (stmt, 1); 324 GNUNET_SQ_result_spec_auto_from_type (&rec.peer),
288 ret->key = (char *) sqlite3_column_text (stmt, 2); 325 GNUNET_SQ_result_spec_string (&rec.key),
289 ret->value = (void *) sqlite3_column_blob (stmt, 3); 326 GNUNET_SQ_result_spec_variable_size (&rec.value, &rec.value_size),
290 ret->value_size = sqlite3_column_bytes (stmt, 3); 327 GNUNET_SQ_result_spec_absolute_time (&rec.expiry),
291 ret->expiry = GNUNET_new (struct GNUNET_TIME_Absolute); 328 GNUNET_SQ_result_spec_end
292 329 };
293 ret->expiry->abs_value_us = (uint64_t) sqlite3_column_int64 (stmt, 4); 330
331 if (GNUNET_OK !=
332 GNUNET_SQ_extract_result (stmt,
333 rs))
334 {
335 GNUNET_break (0);
336 break;
337 }
294 if (NULL != iter) 338 if (NULL != iter)
295 iter (iter_cls, ret, NULL); 339 iter (iter_cls,
296 GNUNET_free (ret->expiry); 340 &rec,
297 GNUNET_free (ret); 341 NULL);
342 GNUNET_SQ_cleanup_result (rs);
298 } 343 }
299 if (SQLITE_DONE != sret) 344 if (SQLITE_DONE != sret)
300 { 345 {
301 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite_step"); 346 LOG_SQLITE (plugin,
302 err = 1; 347 GNUNET_ERROR_TYPE_ERROR,
303 } 348 "sqlite_step");
304 if (SQLITE_OK != sqlite3_reset (stmt))
305 {
306 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
307 "sqlite3_reset");
308 err = 1; 349 err = 1;
309 } 350 }
351 GNUNET_SQ_reset (plugin->dbh,
352 stmt);
310 if (NULL != iter) 353 if (NULL != iter)
311 { 354 iter (iter_cls,
312 iter (iter_cls, NULL, err ? "sqlite error" : NULL); 355 NULL,
313 } 356 err ? "sqlite error" : NULL);
314 return GNUNET_OK; 357 return GNUNET_OK;
315} 358}
316 359
@@ -333,9 +376,12 @@ peerstore_sqlite_iterate_records (void *cls, const char *sub_system,
333 * @return #GNUNET_OK on success, else #GNUNET_SYSERR and cont is not called 376 * @return #GNUNET_OK on success, else #GNUNET_SYSERR and cont is not called
334 */ 377 */
335static int 378static int
336peerstore_sqlite_store_record (void *cls, const char *sub_system, 379peerstore_sqlite_store_record (void *cls,
380 const char *sub_system,
337 const struct GNUNET_PeerIdentity *peer, 381 const struct GNUNET_PeerIdentity *peer,
338 const char *key, const void *value, size_t size, 382 const char *key,
383 const void *value,
384 size_t size,
339 struct GNUNET_TIME_Absolute expiry, 385 struct GNUNET_TIME_Absolute expiry,
340 enum GNUNET_PEERSTORE_StoreOption options, 386 enum GNUNET_PEERSTORE_StoreOption options,
341 GNUNET_PEERSTORE_Continuation cont, 387 GNUNET_PEERSTORE_Continuation cont,
@@ -343,39 +389,39 @@ peerstore_sqlite_store_record (void *cls, const char *sub_system,
343{ 389{
344 struct Plugin *plugin = cls; 390 struct Plugin *plugin = cls;
345 sqlite3_stmt *stmt = plugin->insert_peerstoredata; 391 sqlite3_stmt *stmt = plugin->insert_peerstoredata;
392 struct GNUNET_SQ_QueryParam params[] = {
393 GNUNET_SQ_query_param_string (sub_system),
394 GNUNET_SQ_query_param_auto_from_type (peer),
395 GNUNET_SQ_query_param_string (key),
396 GNUNET_SQ_query_param_fixed_size (value, size),
397 GNUNET_SQ_query_param_absolute_time (&expiry),
398 GNUNET_SQ_query_param_end
399 };
346 400
347 if (GNUNET_PEERSTORE_STOREOPTION_REPLACE == options) 401 if (GNUNET_PEERSTORE_STOREOPTION_REPLACE == options)
348 { 402 {
349 peerstore_sqlite_delete_records (cls, sub_system, peer, key); 403 peerstore_sqlite_delete_records (cls,
404 sub_system,
405 peer,
406 key);
350 } 407 }
351 if (SQLITE_OK != 408 if (GNUNET_OK !=
352 sqlite3_bind_text (stmt, 1, sub_system, strlen (sub_system) + 1, 409 GNUNET_SQ_bind (stmt,
353 SQLITE_STATIC) || 410 params))
354 SQLITE_OK != sqlite3_bind_blob (stmt, 2, peer, 411 LOG_SQLITE (plugin,
355 sizeof (struct GNUNET_PeerIdentity), 412 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
356 SQLITE_STATIC) ||
357 SQLITE_OK != sqlite3_bind_text (stmt, 3, key, strlen (key) + 1,
358 SQLITE_STATIC) ||
359 SQLITE_OK != sqlite3_bind_blob (stmt, 4, value, size, SQLITE_STATIC) ||
360 SQLITE_OK != sqlite3_bind_int64 (stmt, 5,
361 (sqlite3_uint64) expiry.abs_value_us))
362 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
363 "sqlite3_bind"); 413 "sqlite3_bind");
364 else if (SQLITE_DONE != sqlite3_step (stmt)) 414 else if (SQLITE_DONE != sqlite3_step (stmt))
365 { 415 {
366 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 416 LOG_SQLITE (plugin,
417 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
367 "sqlite3_step"); 418 "sqlite3_step");
368 } 419 }
369 if (SQLITE_OK != sqlite3_reset (stmt)) 420 GNUNET_SQ_reset (plugin->dbh,
370 { 421 stmt);
371 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
372 "sqlite3_reset");
373 return GNUNET_SYSERR;
374 }
375 if (NULL != cont) 422 if (NULL != cont)
376 { 423 cont (cont_cls,
377 cont (cont_cls, GNUNET_OK); 424 GNUNET_OK);
378 }
379 return GNUNET_OK; 425 return GNUNET_OK;
380} 426}
381 427
@@ -388,15 +434,25 @@ peerstore_sqlite_store_record (void *cls, const char *sub_system,
388 * @return 0 on success 434 * @return 0 on success
389 */ 435 */
390static int 436static int
391sql_exec (sqlite3 * dbh, const char *sql) 437sql_exec (sqlite3 *dbh,
438 const char *sql)
392{ 439{
393 int result; 440 int result;
394 441
395 result = sqlite3_exec (dbh, sql, NULL, NULL, NULL); 442 result = sqlite3_exec (dbh,
396 LOG (GNUNET_ERROR_TYPE_DEBUG, "Executed `%s' / %d\n", sql, result); 443 sql,
397 if (result != SQLITE_OK) 444 NULL,
398 LOG (GNUNET_ERROR_TYPE_ERROR, _("Error executing SQL query: %s\n %s\n"), 445 NULL,
399 sqlite3_errmsg (dbh), sql); 446 NULL);
447 LOG (GNUNET_ERROR_TYPE_DEBUG,
448 "Executed `%s' / %d\n",
449 sql,
450 result);
451 if (SQLITE_OK != result)
452 LOG (GNUNET_ERROR_TYPE_ERROR,
453 _("Error executing SQL query: %s\n %s\n"),
454 sqlite3_errmsg (dbh),
455 sql);
400 return result; 456 return result;
401} 457}
402 458
@@ -410,38 +466,33 @@ sql_exec (sqlite3 * dbh, const char *sql)
410 * @return 0 on success 466 * @return 0 on success
411 */ 467 */
412static int 468static int
413sql_prepare (sqlite3 * dbh, const char *sql, sqlite3_stmt ** stmt) 469sql_prepare (sqlite3 *dbh,
470 const char *sql,
471 sqlite3_stmt ** stmt)
414{ 472{
415 char *tail; 473 char *tail;
416 int result; 474 int result;
417 475
418 result = 476 result = sqlite3_prepare_v2 (dbh,
419 sqlite3_prepare_v2 (dbh, sql, strlen (sql), stmt, (const char **) &tail); 477 sql,
420 LOG (GNUNET_ERROR_TYPE_DEBUG, "Prepared `%s' / %p: %d\n", sql, *stmt, result); 478 strlen (sql),
421 if (result != SQLITE_OK) 479 stmt,
422 LOG (GNUNET_ERROR_TYPE_ERROR, _("Error preparing SQL query: %s\n %s\n"), 480 (const char **) &tail);
423 sqlite3_errmsg (dbh), sql); 481 LOG (GNUNET_ERROR_TYPE_DEBUG,
482 "Prepared `%s' / %p: %d\n",
483 sql,
484 *stmt,
485 result);
486 if (SQLITE_OK != result)
487 LOG (GNUNET_ERROR_TYPE_ERROR,
488 _("Error preparing SQL query: %s\n %s\n"),
489 sqlite3_errmsg (dbh),
490 sql);
424 return result; 491 return result;
425} 492}
426 493
427 494
428/** 495/**
429 * sqlite3 custom function for comparison of uint64_t values
430 * since it is not supported by default
431 */
432void
433sqlite3_lessthan (sqlite3_context * ctx, int dummy, sqlite3_value ** values)
434{
435 uint64_t v1;
436 uint64_t v2;
437
438 v1 = (uint64_t) sqlite3_value_int64 (values[0]);
439 v2 = (uint64_t) sqlite3_value_int64 (values[1]);
440 sqlite3_result_int (ctx, v1 < v2);
441}
442
443
444/**
445 * Initialize the database connections and associated 496 * Initialize the database connections and associated
446 * data structures (create tables and indices 497 * data structures (create tables and indices
447 * as needed as well). 498 * as needed as well).
@@ -455,10 +506,13 @@ database_setup (struct Plugin *plugin)
455 char *filename; 506 char *filename;
456 507
457 if (GNUNET_OK != 508 if (GNUNET_OK !=
458 GNUNET_CONFIGURATION_get_value_filename (plugin->cfg, "peerstore-sqlite", 509 GNUNET_CONFIGURATION_get_value_filename (plugin->cfg,
459 "FILENAME", &filename)) 510 "peerstore-sqlite",
511 "FILENAME",
512 &filename))
460 { 513 {
461 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "peerstore-sqlite", 514 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
515 "peerstore-sqlite",
462 "FILENAME"); 516 "FILENAME");
463 return GNUNET_SYSERR; 517 return GNUNET_SYSERR;
464 } 518 }
@@ -474,60 +528,81 @@ database_setup (struct Plugin *plugin)
474 /* filename should be UTF-8-encoded. If it isn't, it's a bug */ 528 /* filename should be UTF-8-encoded. If it isn't, it's a bug */
475 plugin->fn = filename; 529 plugin->fn = filename;
476 /* Open database and precompile statements */ 530 /* Open database and precompile statements */
477 if (SQLITE_OK != sqlite3_open (plugin->fn, &plugin->dbh)) 531 if (SQLITE_OK != sqlite3_open (plugin->fn,
532 &plugin->dbh))
478 { 533 {
479 LOG (GNUNET_ERROR_TYPE_ERROR, _("Unable to initialize SQLite: %s.\n"), 534 LOG (GNUNET_ERROR_TYPE_ERROR,
535 _("Unable to initialize SQLite: %s.\n"),
480 sqlite3_errmsg (plugin->dbh)); 536 sqlite3_errmsg (plugin->dbh));
481 return GNUNET_SYSERR; 537 return GNUNET_SYSERR;
482 } 538 }
483 sql_exec (plugin->dbh, "PRAGMA temp_store=MEMORY"); 539 sql_exec (plugin->dbh,
484 sql_exec (plugin->dbh, "PRAGMA synchronous=OFF"); 540 "PRAGMA temp_store=MEMORY");
485 sql_exec (plugin->dbh, "PRAGMA legacy_file_format=OFF"); 541 sql_exec (plugin->dbh,
486 sql_exec (plugin->dbh, "PRAGMA auto_vacuum=INCREMENTAL"); 542 "PRAGMA synchronous=OFF");
487 sql_exec (plugin->dbh, "PRAGMA encoding=\"UTF-8\""); 543 sql_exec (plugin->dbh,
488 sql_exec (plugin->dbh, "PRAGMA page_size=4096"); 544 "PRAGMA legacy_file_format=OFF");
489 sqlite3_busy_timeout (plugin->dbh, BUSY_TIMEOUT_MS); 545 sql_exec (plugin->dbh,
546 "PRAGMA auto_vacuum=INCREMENTAL");
547 sql_exec (plugin->dbh,
548 "PRAGMA encoding=\"UTF-8\"");
549 sql_exec (plugin->dbh,
550 "PRAGMA page_size=4096");
551 sqlite3_busy_timeout (plugin->dbh,
552 BUSY_TIMEOUT_MS);
490 /* Create tables */ 553 /* Create tables */
491 sql_exec (plugin->dbh, 554 sql_exec (plugin->dbh,
492 "CREATE TABLE IF NOT EXISTS peerstoredata (\n" 555 "CREATE TABLE IF NOT EXISTS peerstoredata (\n"
493 " sub_system TEXT NOT NULL,\n" " peer_id BLOB NOT NULL,\n" 556 " sub_system TEXT NOT NULL,\n"
494 " key TEXT NOT NULL,\n" " value BLOB NULL,\n" 557 " peer_id BLOB NOT NULL,\n"
495 " expiry sqlite3_uint64 NOT NULL" ");"); 558 " key TEXT NOT NULL,\n"
496 sqlite3_create_function (plugin->dbh, "UINT64_LT", 2, SQLITE_UTF8, NULL, 559 " value BLOB NULL,\n"
497 &sqlite3_lessthan, NULL, NULL); 560 " expiry INT8 NOT NULL" ");");
498 /* Create Indices */ 561 /* Create Indices */
499 if (SQLITE_OK != 562 if (SQLITE_OK !=
500 sqlite3_exec (plugin->dbh, 563 sqlite3_exec (plugin->dbh,
501 "CREATE INDEX IF NOT EXISTS peerstoredata_key_index ON peerstoredata (sub_system, peer_id, key)", 564 "CREATE INDEX IF NOT EXISTS peerstoredata_key_index ON peerstoredata (sub_system, peer_id, key)",
502 NULL, NULL, NULL)) 565 NULL,
566 NULL,
567 NULL))
503 { 568 {
504 LOG (GNUNET_ERROR_TYPE_ERROR, _("Unable to create indices: %s.\n"), 569 LOG (GNUNET_ERROR_TYPE_ERROR,
570 _("Unable to create indices: %s.\n"),
505 sqlite3_errmsg (plugin->dbh)); 571 sqlite3_errmsg (plugin->dbh));
506 return GNUNET_SYSERR; 572 return GNUNET_SYSERR;
507 } 573 }
508 /* Prepare statements */ 574 /* Prepare statements */
509 575
510 sql_prepare (plugin->dbh, 576 sql_prepare (plugin->dbh,
511 "INSERT INTO peerstoredata (sub_system, peer_id, key, value, expiry) VALUES (?,?,?,?,?);", 577 "INSERT INTO peerstoredata (sub_system, peer_id, key, value, expiry)"
578 " VALUES (?,?,?,?,?);",
512 &plugin->insert_peerstoredata); 579 &plugin->insert_peerstoredata);
513 sql_prepare (plugin->dbh, 580 sql_prepare (plugin->dbh,
514 "SELECT * FROM peerstoredata" " WHERE sub_system = ?", 581 "SELECT sub_system,peer_id,key,value,expiry FROM peerstoredata"
582 " WHERE sub_system = ?",
515 &plugin->select_peerstoredata); 583 &plugin->select_peerstoredata);
516 sql_prepare (plugin->dbh, 584 sql_prepare (plugin->dbh,
517 "SELECT * FROM peerstoredata" " WHERE sub_system = ?" 585 "SELECT sub_system,peer_id,key,value,expiry FROM peerstoredata"
518 " AND peer_id = ?", &plugin->select_peerstoredata_by_pid); 586 " WHERE sub_system = ?"
587 " AND peer_id = ?",
588 &plugin->select_peerstoredata_by_pid);
519 sql_prepare (plugin->dbh, 589 sql_prepare (plugin->dbh,
520 "SELECT * FROM peerstoredata" " WHERE sub_system = ?" 590 "SELECT sub_system,peer_id,key,value,expiry FROM peerstoredata"
521 " AND key = ?", &plugin->select_peerstoredata_by_key); 591 " WHERE sub_system = ?"
592 " AND key = ?",
593 &plugin->select_peerstoredata_by_key);
522 sql_prepare (plugin->dbh, 594 sql_prepare (plugin->dbh,
523 "SELECT * FROM peerstoredata" " WHERE sub_system = ?" 595 "SELECT sub_system,peer_id,key,value,expiry FROM peerstoredata"
596 " WHERE sub_system = ?"
524 " AND peer_id = ?" " AND key = ?", 597 " AND peer_id = ?" " AND key = ?",
525 &plugin->select_peerstoredata_by_all); 598 &plugin->select_peerstoredata_by_all);
526 sql_prepare (plugin->dbh, 599 sql_prepare (plugin->dbh,
527 "DELETE FROM peerstoredata" " WHERE UINT64_LT(expiry, ?)", 600 "DELETE FROM peerstoredata"
601 " WHERE expiry < ?",
528 &plugin->expire_peerstoredata); 602 &plugin->expire_peerstoredata);
529 sql_prepare (plugin->dbh, 603 sql_prepare (plugin->dbh,
530 "DELETE FROM peerstoredata" " WHERE sub_system = ?" 604 "DELETE FROM peerstoredata"
605 " WHERE sub_system = ?"
531 " AND peer_id = ?" " AND key = ?", 606 " AND peer_id = ?" " AND key = ?",
532 &plugin->delete_peerstoredata); 607 &plugin->delete_peerstoredata);
533 return GNUNET_OK; 608 return GNUNET_OK;
@@ -545,15 +620,20 @@ database_shutdown (struct Plugin *plugin)
545 int result; 620 int result;
546 sqlite3_stmt *stmt; 621 sqlite3_stmt *stmt;
547 622
548 while (NULL != (stmt = sqlite3_next_stmt (plugin->dbh, NULL))) 623 while (NULL != (stmt = sqlite3_next_stmt (plugin->dbh,
624 NULL)))
549 { 625 {
550 result = sqlite3_finalize (stmt); 626 result = sqlite3_finalize (stmt);
551 if (SQLITE_OK != result) 627 if (SQLITE_OK != result)
552 LOG (GNUNET_ERROR_TYPE_WARNING, "Failed to close statement %p: %d\n", 628 LOG (GNUNET_ERROR_TYPE_WARNING,
553 stmt, result); 629 "Failed to close statement %p: %d\n",
630 stmt,
631 result);
554 } 632 }
555 if (SQLITE_OK != sqlite3_close (plugin->dbh)) 633 if (SQLITE_OK != sqlite3_close (plugin->dbh))
556 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite3_close"); 634 LOG_SQLITE (plugin,
635 GNUNET_ERROR_TYPE_ERROR,
636 "sqlite3_close");
557 GNUNET_free_non_null (plugin->fn); 637 GNUNET_free_non_null (plugin->fn);
558} 638}
559 639
@@ -573,7 +653,9 @@ libgnunet_plugin_peerstore_sqlite_init (void *cls)
573 653
574 if (NULL != plugin.cfg) 654 if (NULL != plugin.cfg)
575 return NULL; /* can only initialize once! */ 655 return NULL; /* can only initialize once! */
576 memset (&plugin, 0, sizeof (struct Plugin)); 656 memset (&plugin,
657 0,
658 sizeof (struct Plugin));
577 plugin.cfg = cfg; 659 plugin.cfg = cfg;
578 if (GNUNET_OK != database_setup (&plugin)) 660 if (GNUNET_OK != database_setup (&plugin))
579 { 661 {
@@ -585,7 +667,8 @@ libgnunet_plugin_peerstore_sqlite_init (void *cls)
585 api->store_record = &peerstore_sqlite_store_record; 667 api->store_record = &peerstore_sqlite_store_record;
586 api->iterate_records = &peerstore_sqlite_iterate_records; 668 api->iterate_records = &peerstore_sqlite_iterate_records;
587 api->expire_records = &peerstore_sqlite_expire_records; 669 api->expire_records = &peerstore_sqlite_expire_records;
588 LOG (GNUNET_ERROR_TYPE_DEBUG, "Sqlite plugin is running\n"); 670 LOG (GNUNET_ERROR_TYPE_DEBUG,
671 "Sqlite plugin is running\n");
589 return api; 672 return api;
590} 673}
591 674
@@ -605,7 +688,8 @@ libgnunet_plugin_peerstore_sqlite_done (void *cls)
605 database_shutdown (plugin); 688 database_shutdown (plugin);
606 plugin->cfg = NULL; 689 plugin->cfg = NULL;
607 GNUNET_free (api); 690 GNUNET_free (api);
608 LOG (GNUNET_ERROR_TYPE_DEBUG, "Sqlite plugin is finished\n"); 691 LOG (GNUNET_ERROR_TYPE_DEBUG,
692 "Sqlite plugin is finished\n");
609 return NULL; 693 return NULL;
610} 694}
611 695
diff --git a/src/peerstore/test_peerstore_api_iterate.c b/src/peerstore/test_peerstore_api_iterate.c
index 83a6bf7b7..c607d9fb3 100644
--- a/src/peerstore/test_peerstore_api_iterate.c
+++ b/src/peerstore/test_peerstore_api_iterate.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 Copyright (C) 3 Copyright (C) 2013-2017 GNUnet e.V.
4 4
5 GNUnet is free software; you can redistribute it and/or modify 5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published 6 it under the terms of the GNU General Public License as published
@@ -42,7 +42,8 @@ static int count = 0;
42 42
43 43
44static void 44static void
45iter3_cb (void *cls, const struct GNUNET_PEERSTORE_Record *record, 45iter3_cb (void *cls,
46 const struct GNUNET_PEERSTORE_Record *record,
46 const char *emsg) 47 const char *emsg)
47{ 48{
48 if (NULL != emsg) 49 if (NULL != emsg)
@@ -63,7 +64,8 @@ iter3_cb (void *cls, const struct GNUNET_PEERSTORE_Record *record,
63 64
64 65
65static void 66static void
66iter2_cb (void *cls, const struct GNUNET_PEERSTORE_Record *record, 67iter2_cb (void *cls,
68 const struct GNUNET_PEERSTORE_Record *record,
67 const char *emsg) 69 const char *emsg)
68{ 70{
69 if (NULL != emsg) 71 if (NULL != emsg)
@@ -78,13 +80,19 @@ iter2_cb (void *cls, const struct GNUNET_PEERSTORE_Record *record,
78 } 80 }
79 GNUNET_assert (count == 2); 81 GNUNET_assert (count == 2);
80 count = 0; 82 count = 0;
81 ic = GNUNET_PEERSTORE_iterate (h, ss, NULL, NULL, GNUNET_TIME_UNIT_FOREVER_REL, 83 ic = GNUNET_PEERSTORE_iterate (h,
82 iter3_cb, NULL); 84 ss,
85 NULL,
86 NULL,
87 GNUNET_TIME_UNIT_FOREVER_REL,
88 &iter3_cb,
89 NULL);
83} 90}
84 91
85 92
86static void 93static void
87iter1_cb (void *cls, const struct GNUNET_PEERSTORE_Record *record, 94iter1_cb (void *cls,
95 const struct GNUNET_PEERSTORE_Record *record,
88 const char *emsg) 96 const char *emsg)
89{ 97{
90 if (NULL != emsg) 98 if (NULL != emsg)
@@ -99,30 +107,61 @@ iter1_cb (void *cls, const struct GNUNET_PEERSTORE_Record *record,
99 } 107 }
100 GNUNET_assert (count == 1); 108 GNUNET_assert (count == 1);
101 count = 0; 109 count = 0;
102 ic = GNUNET_PEERSTORE_iterate (h, ss, &p1, NULL, GNUNET_TIME_UNIT_FOREVER_REL, 110 ic = GNUNET_PEERSTORE_iterate (h,
103 iter2_cb, NULL); 111 ss,
112 &p1,
113 NULL,
114 GNUNET_TIME_UNIT_FOREVER_REL,
115 iter2_cb,
116 NULL);
104} 117}
105 118
106 119
107static void 120static void
108run (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg, 121run (void *cls,
122 const struct GNUNET_CONFIGURATION_Handle *cfg,
109 struct GNUNET_TESTING_Peer *peer) 123 struct GNUNET_TESTING_Peer *peer)
110{ 124{
111 h = GNUNET_PEERSTORE_connect (cfg); 125 h = GNUNET_PEERSTORE_connect (cfg);
112 GNUNET_assert (NULL != h); 126 GNUNET_assert (NULL != h);
113 memset (&p1, 1, sizeof (p1)); 127 memset (&p1, 1, sizeof (p1));
114 memset (&p2, 2, sizeof (p2)); 128 memset (&p2, 2, sizeof (p2));
115 GNUNET_PEERSTORE_store (h, ss, &p1, k1, val, strlen (val) + 1, 129 GNUNET_PEERSTORE_store (h,
130 ss,
131 &p1,
132 k1,
133 val,
134 strlen (val) + 1,
116 GNUNET_TIME_UNIT_FOREVER_ABS, 135 GNUNET_TIME_UNIT_FOREVER_ABS,
117 GNUNET_PEERSTORE_STOREOPTION_REPLACE, NULL, NULL); 136 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
118 GNUNET_PEERSTORE_store (h, ss, &p1, k2, val, strlen (val) + 1, 137 NULL,
138 NULL);
139 GNUNET_PEERSTORE_store (h,
140 ss,
141 &p1,
142 k2,
143 val,
144 strlen (val) + 1,
119 GNUNET_TIME_UNIT_FOREVER_ABS, 145 GNUNET_TIME_UNIT_FOREVER_ABS,
120 GNUNET_PEERSTORE_STOREOPTION_REPLACE, NULL, NULL); 146 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
121 GNUNET_PEERSTORE_store (h, ss, &p2, k3, val, strlen (val) + 1, 147 NULL,
148 NULL);
149 GNUNET_PEERSTORE_store (h,
150 ss,
151 &p2,
152 k3,
153 val,
154 strlen (val) + 1,
122 GNUNET_TIME_UNIT_FOREVER_ABS, 155 GNUNET_TIME_UNIT_FOREVER_ABS,
123 GNUNET_PEERSTORE_STOREOPTION_REPLACE, NULL, NULL); 156 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
124 ic = GNUNET_PEERSTORE_iterate (h, ss, &p1, k1, GNUNET_TIME_UNIT_FOREVER_REL, 157 NULL,
125 iter1_cb, NULL); 158 NULL);
159 ic = GNUNET_PEERSTORE_iterate (h,
160 ss,
161 &p1,
162 k1,
163 GNUNET_TIME_UNIT_FOREVER_REL,
164 &iter1_cb, NULL);
126} 165}
127 166
128 167
diff --git a/src/peerstore/test_peerstore_api_store.c b/src/peerstore/test_peerstore_api_store.c
index bfe1b5b55..978009dbb 100644
--- a/src/peerstore/test_peerstore_api_store.c
+++ b/src/peerstore/test_peerstore_api_store.c
@@ -39,6 +39,7 @@ static char *val3 = "test_peerstore_api_store_val3--";
39 39
40static int count = 0; 40static int count = 0;
41 41
42
42static void 43static void
43test3_cont2 (void *cls, 44test3_cont2 (void *cls,
44 const struct GNUNET_PEERSTORE_Record *record, 45 const struct GNUNET_PEERSTORE_Record *record,
@@ -49,7 +50,8 @@ test3_cont2 (void *cls,
49 if (NULL != record) 50 if (NULL != record)
50 { 51 {
51 GNUNET_assert ((strlen (val3) + 1) == record->value_size); 52 GNUNET_assert ((strlen (val3) + 1) == record->value_size);
52 GNUNET_assert (0 == strcmp ((char *) val3, (char *) record->value)); 53 GNUNET_assert (0 == strcmp ((char *) val3,
54 (char *) record->value));
53 count++; 55 count++;
54 return; 56 return;
55 } 57 }
@@ -61,7 +63,8 @@ test3_cont2 (void *cls,
61 63
62 64
63static void 65static void
64test3_cont (void *cls, int success) 66test3_cont (void *cls,
67 int success)
65{ 68{
66 if (GNUNET_YES != success) 69 if (GNUNET_YES != success)
67 return; 70 return;
@@ -71,7 +74,8 @@ test3_cont (void *cls, int success)
71 &pid, 74 &pid,
72 key, 75 key,
73 GNUNET_TIME_UNIT_SECONDS, 76 GNUNET_TIME_UNIT_SECONDS,
74 &test3_cont2, NULL); 77 &test3_cont2,
78 NULL);
75} 79}
76 80
77 81
@@ -81,9 +85,15 @@ test3_cont (void *cls, int success)
81static void 85static void
82test3 () 86test3 ()
83{ 87{
84 GNUNET_PEERSTORE_store (h, subsystem, &pid, key, val3, strlen (val3) + 1, 88 GNUNET_PEERSTORE_store (h,
89 subsystem,
90 &pid,
91 key,
92 val3,
93 strlen (val3) + 1,
85 GNUNET_TIME_UNIT_FOREVER_ABS, 94 GNUNET_TIME_UNIT_FOREVER_ABS,
86 GNUNET_PEERSTORE_STOREOPTION_REPLACE, &test3_cont, 95 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
96 &test3_cont,
87 NULL); 97 NULL);
88} 98}
89 99
@@ -130,9 +140,15 @@ test2_cont (void *cls, int success)
130void 140void
131test2 () 141test2 ()
132{ 142{
133 GNUNET_PEERSTORE_store (h, subsystem, &pid, key, val2, strlen (val2) + 1, 143 GNUNET_PEERSTORE_store (h,
144 subsystem,
145 &pid,
146 key,
147 val2,
148 strlen (val2) + 1,
134 GNUNET_TIME_UNIT_FOREVER_ABS, 149 GNUNET_TIME_UNIT_FOREVER_ABS,
135 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE, &test2_cont, 150 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
151 &test2_cont,
136 NULL); 152 NULL);
137} 153}
138 154
@@ -163,8 +179,13 @@ test1_cont (void *cls, int success)
163 if (GNUNET_YES != success) 179 if (GNUNET_YES != success)
164 return; 180 return;
165 count = 0; 181 count = 0;
166 GNUNET_PEERSTORE_iterate (h, subsystem, &pid, key, GNUNET_TIME_UNIT_SECONDS, 182 GNUNET_PEERSTORE_iterate (h,
167 &test1_cont2, NULL); 183 subsystem,
184 &pid,
185 key,
186 GNUNET_TIME_UNIT_SECONDS,
187 &test1_cont2,
188 NULL);
168} 189}
169 190
170 191
@@ -174,9 +195,15 @@ test1_cont (void *cls, int success)
174static void 195static void
175test1 () 196test1 ()
176{ 197{
177 GNUNET_PEERSTORE_store (h, subsystem, &pid, key, val1, strlen (val1) + 1, 198 GNUNET_PEERSTORE_store (h,
199 subsystem,
200 &pid,
201 key,
202 val1,
203 strlen (val1) + 1,
178 GNUNET_TIME_UNIT_FOREVER_ABS, 204 GNUNET_TIME_UNIT_FOREVER_ABS,
179 GNUNET_PEERSTORE_STOREOPTION_REPLACE, &test1_cont, 205 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
206 &test1_cont,
180 NULL); 207 NULL);
181} 208}
182 209
@@ -196,8 +223,10 @@ int
196main (int argc, char *argv[]) 223main (int argc, char *argv[])
197{ 224{
198 if (0 != 225 if (0 !=
199 GNUNET_TESTING_service_run ("test-gnunet-peerstore", "peerstore", 226 GNUNET_TESTING_service_run ("test-gnunet-peerstore",
200 "test_peerstore_api_data.conf", &run, NULL)) 227 "peerstore",
228 "test_peerstore_api_data.conf",
229 &run, NULL))
201 return 1; 230 return 1;
202 return ok; 231 return ok;
203} 232}
diff --git a/src/peerstore/test_plugin_peerstore.c b/src/peerstore/test_plugin_peerstore.c
index 179e32b52..62c06be8e 100644
--- a/src/peerstore/test_plugin_peerstore.c
+++ b/src/peerstore/test_plugin_peerstore.c
@@ -36,6 +36,11 @@ static int ok;
36static const char *plugin_name; 36static const char *plugin_name;
37 37
38 38
39static struct GNUNET_PEERSTORE_PluginFunctions *psp;
40
41static struct GNUNET_PeerIdentity p1;
42
43
39/** 44/**
40 * Function called when the service shuts down. Unloads our namestore 45 * Function called when the service shuts down. Unloads our namestore
41 * plugin. 46 * plugin.
@@ -47,8 +52,12 @@ unload_plugin (struct GNUNET_PEERSTORE_PluginFunctions *api)
47{ 52{
48 char *libname; 53 char *libname;
49 54
50 GNUNET_asprintf (&libname, "libgnunet_plugin_peer_%s", plugin_name); 55 GNUNET_asprintf (&libname,
51 GNUNET_break (NULL == GNUNET_PLUGIN_unload (libname, api)); 56 "libgnunet_plugin_peer_%s",
57 plugin_name);
58 GNUNET_break (NULL ==
59 GNUNET_PLUGIN_unload (libname,
60 api));
52 GNUNET_free (libname); 61 GNUNET_free (libname);
53} 62}
54 63
@@ -65,12 +74,18 @@ load_plugin (const struct GNUNET_CONFIGURATION_Handle *cfg)
65 struct GNUNET_PEERSTORE_PluginFunctions *ret; 74 struct GNUNET_PEERSTORE_PluginFunctions *ret;
66 char *libname; 75 char *libname;
67 76
68 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Loading `%s' peer plugin\n"), 77 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
78 _("Loading `%s' peer plugin\n"),
69 plugin_name); 79 plugin_name);
70 GNUNET_asprintf (&libname, "libgnunet_plugin_peerstore_%s", plugin_name); 80 GNUNET_asprintf (&libname,
71 if (NULL == (ret = GNUNET_PLUGIN_load (libname, (void*) cfg))) 81 "libgnunet_plugin_peerstore_%s",
82 plugin_name);
83 if (NULL == (ret = GNUNET_PLUGIN_load (libname,
84 (void*) cfg)))
72 { 85 {
73 FPRINTF (stderr, "Failed to load plugin `%s'!\n", plugin_name); 86 FPRINTF (stderr,
87 "Failed to load plugin `%s'!\n",
88 plugin_name);
74 GNUNET_free (libname); 89 GNUNET_free (libname);
75 return NULL; 90 return NULL;
76 } 91 }
@@ -81,19 +96,28 @@ load_plugin (const struct GNUNET_CONFIGURATION_Handle *cfg)
81 96
82static void 97static void
83test_record (void *cls, 98test_record (void *cls,
84 const struct GNUNET_PEERSTORE_Record *record, 99 const struct GNUNET_PEERSTORE_Record *record,
85 const char *error) 100 const char *error)
86{ 101{
87 struct GNUNET_PeerIdentity *id = cls; 102 const struct GNUNET_PeerIdentity *id = cls;
88 char* testval = "test_val"; 103 const char* testval = "test_val";
89 104
90 if (NULL == record) 105 if (NULL == record)
106 {
107 unload_plugin (psp);
91 return; 108 return;
92 109 }
93 GNUNET_assert (0 == memcmp (record->peer, id, sizeof (struct GNUNET_PeerIdentity))); 110 GNUNET_assert (0 == memcmp (&record->peer,
94 GNUNET_assert (0 == strcmp ("subsys", record->sub_system)); 111 id,
95 GNUNET_assert (0 == strcmp ("key", record->key)); 112 sizeof (struct GNUNET_PeerIdentity)));
96 GNUNET_assert (0 == memcmp (testval, record->value, strlen (testval))); 113 GNUNET_assert (0 == strcmp ("subsys",
114 record->sub_system));
115 GNUNET_assert (0 == strcmp ("key",
116 record->key));
117 GNUNET_assert (0 == memcmp (testval,
118 record->value,
119 strlen (testval)));
120 ok = 0;
97} 121}
98 122
99 123
@@ -101,38 +125,52 @@ static void
101get_record (struct GNUNET_PEERSTORE_PluginFunctions *psp, 125get_record (struct GNUNET_PEERSTORE_PluginFunctions *psp,
102 const struct GNUNET_PeerIdentity *identity) 126 const struct GNUNET_PeerIdentity *identity)
103{ 127{
104 GNUNET_assert (GNUNET_OK == psp->iterate_records (psp->cls, 128 GNUNET_assert (GNUNET_OK ==
105 "subsys", identity, "key", &test_record, (void*)identity)); 129 psp->iterate_records (psp->cls,
130 "subsys",
131 identity,
132 "key",
133 &test_record,
134 (void*)identity));
106} 135}
107 136
137
108static void 138static void
109store_cont (void *cls, int status) 139store_cont (void *cls,
140 int status)
110{ 141{
111 GNUNET_assert (GNUNET_OK == status); 142 GNUNET_assert (GNUNET_OK == status);
143 get_record (psp,
144 &p1);
112} 145}
113 146
147
114static void 148static void
115put_record (struct GNUNET_PEERSTORE_PluginFunctions *psp, struct GNUNET_PeerIdentity *identity) 149put_record (struct GNUNET_PEERSTORE_PluginFunctions *psp,
150 const struct GNUNET_PeerIdentity *identity)
116{ 151{
117 GNUNET_assert (GNUNET_OK == psp->store_record (psp->cls, 152 GNUNET_assert (GNUNET_OK ==
118 "subsys", 153 psp->store_record (psp->cls,
119 identity, 154 "subsys",
120 "key", "test_value", strlen ("test_value"), 155 identity,
121 GNUNET_TIME_absolute_get (), 156 "key",
122 GNUNET_PEERSTORE_STOREOPTION_REPLACE, 157 "test_value",
123 &store_cont, 158 strlen ("test_value"),
124 identity)); 159 GNUNET_TIME_absolute_get (),
160 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
161 &store_cont,
162 NULL));
125} 163}
126 164
127 165
128static void 166static void
129run (void *cls, char *const *args, const char *cfgfile, 167run (void *cls,
168 char *const *args,
169 const char *cfgfile,
130 const struct GNUNET_CONFIGURATION_Handle *cfg) 170 const struct GNUNET_CONFIGURATION_Handle *cfg)
131{ 171{
132 struct GNUNET_PEERSTORE_PluginFunctions *psp;
133 struct GNUNET_PeerIdentity p1;
134 172
135 ok = 0; 173 ok = 1;
136 psp = load_plugin (cfg); 174 psp = load_plugin (cfg);
137 if (NULL == psp) 175 if (NULL == psp)
138 { 176 {
@@ -142,10 +180,8 @@ run (void *cls, char *const *args, const char *cfgfile,
142 return; 180 return;
143 } 181 }
144 memset (&p1, 1, sizeof (p1)); 182 memset (&p1, 1, sizeof (p1));
145 put_record (psp, &p1); 183 put_record (psp,
146 get_record (psp, &p1); 184 &p1);
147
148 unload_plugin (psp);
149} 185}
150 186
151 187
@@ -163,19 +199,26 @@ main (int argc, char *argv[])
163 GNUNET_GETOPT_OPTION_END 199 GNUNET_GETOPT_OPTION_END
164 }; 200 };
165 201
166 //GNUNET_DISK_directory_remove ("/tmp/gnunet-test-plugin-namestore-sqlite");
167 GNUNET_log_setup ("test-plugin-peerstore", 202 GNUNET_log_setup ("test-plugin-peerstore",
168 "WARNING", 203 "WARNING",
169 NULL); 204 NULL);
170 plugin_name = GNUNET_TESTING_get_testname_from_underscore (argv[0]); 205 plugin_name = GNUNET_TESTING_get_testname_from_underscore (argv[0]);
171 GNUNET_snprintf (cfg_name, sizeof (cfg_name), "test_plugin_peerstore_%s.conf", 206 GNUNET_snprintf (cfg_name,
207 sizeof (cfg_name),
208 "test_plugin_peerstore_%s.conf",
172 plugin_name); 209 plugin_name);
173 GNUNET_PROGRAM_run ((sizeof (xargv) / sizeof (char *)) - 1, xargv, 210 GNUNET_PROGRAM_run ((sizeof (xargv) / sizeof (char *)) - 1,
174 "test-plugin-peerstore", "nohelp", options, &run, NULL); 211 xargv,
212 "test-plugin-peerstore",
213 "nohelp",
214 options,
215 &run,
216 NULL);
175 if (ok != 0) 217 if (ok != 0)
176 FPRINTF (stderr, "Missed some testcases: %d\n", ok); 218 FPRINTF (stderr,
177 //GNUNET_DISK_directory_remove ("/tmp/gnunet-test-plugin-namestore-sqlite"); 219 "Missed some testcases: %d\n",
220 ok);
178 return ok; 221 return ok;
179} 222}
180 223
181/* end of test_plugin_namestore.c */ 224/* end of test_plugin_peerstore.c */
diff --git a/src/pq/pq.c b/src/pq/pq.c
index f4bab4e00..4e24e1ef8 100644
--- a/src/pq/pq.c
+++ b/src/pq/pq.c
@@ -85,9 +85,10 @@ GNUNET_PQ_exec_prepared (PGconn *db_conn,
85 off += x->num_params; 85 off += x->num_params;
86 } 86 }
87 GNUNET_assert (off == len); 87 GNUNET_assert (off == len);
88 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 88 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
89 "Executing prepared SQL statement `%s'\n", 89 "pq",
90 name); 90 "Executing prepared SQL statement `%s'\n",
91 name);
91 res = PQexecPrepared (db_conn, 92 res = PQexecPrepared (db_conn,
92 name, 93 name,
93 len, 94 len,
diff --git a/src/psyc/.gitignore b/src/psyc/.gitignore
index e12b3210c..14a175367 100644
--- a/src/psyc/.gitignore
+++ b/src/psyc/.gitignore
@@ -1 +1,2 @@
1gnunet-service-psyc 1gnunet-service-psyc
2test_psyc
diff --git a/src/psyc/psyc_api.c b/src/psyc/psyc_api.c
index c6544df3a..c93d8b383 100644
--- a/src/psyc/psyc_api.c
+++ b/src/psyc/psyc_api.c
@@ -1309,7 +1309,7 @@ channel_history_replay (struct GNUNET_PSYC_Channel *chn,
1309 1309
1310 GNUNET_assert (NULL != method_prefix); 1310 GNUNET_assert (NULL != method_prefix);
1311 uint16_t method_size = strnlen (method_prefix, 1311 uint16_t method_size = strnlen (method_prefix,
1312 GNUNET_SERVER_MAX_MESSAGE_SIZE 1312 GNUNET_MAX_MESSAGE_SIZE
1313 - sizeof (*req)) + 1; 1313 - sizeof (*req)) + 1;
1314 GNUNET_assert ('\0' == method_prefix[method_size - 1]); 1314 GNUNET_assert ('\0' == method_prefix[method_size - 1]);
1315 1315
@@ -1454,7 +1454,7 @@ channel_state_get (struct GNUNET_PSYC_Channel *chn,
1454 sr->op_id = GNUNET_OP_add (chn->op, op_recv_state_result, sr, NULL); 1454 sr->op_id = GNUNET_OP_add (chn->op, op_recv_state_result, sr, NULL);
1455 1455
1456 GNUNET_assert (NULL != name); 1456 GNUNET_assert (NULL != name);
1457 size_t name_size = strnlen (name, GNUNET_SERVER_MAX_MESSAGE_SIZE 1457 size_t name_size = strnlen (name, GNUNET_MAX_MESSAGE_SIZE
1458 - sizeof (*req)) + 1; 1458 - sizeof (*req)) + 1;
1459 struct GNUNET_MQ_Envelope * 1459 struct GNUNET_MQ_Envelope *
1460 env = GNUNET_MQ_msg_extra (req, name_size, type); 1460 env = GNUNET_MQ_msg_extra (req, name_size, type);
diff --git a/src/psycstore/.gitignore b/src/psycstore/.gitignore
index fc2e4cf8e..5ec783202 100644
--- a/src/psycstore/.gitignore
+++ b/src/psycstore/.gitignore
@@ -1 +1,5 @@
1gnunet-service-psycstore 1gnunet-service-psycstore
2test_plugin_psycstore_mysql
3test_plugin_psycstore_sqlite
4test_plugin_psycstore_postgres
5test_psycstore
diff --git a/src/psycstore/gnunet-service-psycstore.c b/src/psycstore/gnunet-service-psycstore.c
index 10c92a878..1bee8da65 100644
--- a/src/psycstore/gnunet-service-psycstore.c
+++ b/src/psycstore/gnunet-service-psycstore.c
@@ -106,7 +106,7 @@ send_result_code (struct GNUNET_SERVICE_Client *client,
106 106
107 if (NULL != err_msg) 107 if (NULL != err_msg)
108 err_size = strnlen (err_msg, 108 err_size = strnlen (err_msg,
109 GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (*res) - 1) + 1; 109 GNUNET_MAX_MESSAGE_SIZE - sizeof (*res) - 1) + 1;
110 struct GNUNET_MQ_Envelope * 110 struct GNUNET_MQ_Envelope *
111 env = GNUNET_MQ_msg_extra (res, err_size, 111 env = GNUNET_MQ_msg_extra (res, err_size,
112 GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_CODE); 112 GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_CODE);
diff --git a/src/psycstore/psycstore_api.c b/src/psycstore/psycstore_api.c
index 40322662e..d79daa357 100644
--- a/src/psycstore/psycstore_api.c
+++ b/src/psycstore/psycstore_api.c
@@ -809,7 +809,7 @@ GNUNET_PSYCSTORE_message_get (struct GNUNET_PSYCSTORE_Handle *h,
809 if (NULL == method_prefix) 809 if (NULL == method_prefix)
810 method_prefix = ""; 810 method_prefix = "";
811 uint16_t method_size = strnlen (method_prefix, 811 uint16_t method_size = strnlen (method_prefix,
812 GNUNET_SERVER_MAX_MESSAGE_SIZE 812 GNUNET_MAX_MESSAGE_SIZE
813 - sizeof (*req)) + 1; 813 - sizeof (*req)) + 1;
814 814
815 struct GNUNET_MQ_Envelope * 815 struct GNUNET_MQ_Envelope *
@@ -875,7 +875,7 @@ GNUNET_PSYCSTORE_message_get_latest (struct GNUNET_PSYCSTORE_Handle *h,
875 if (NULL == method_prefix) 875 if (NULL == method_prefix)
876 method_prefix = ""; 876 method_prefix = "";
877 uint16_t method_size = strnlen (method_prefix, 877 uint16_t method_size = strnlen (method_prefix,
878 GNUNET_SERVER_MAX_MESSAGE_SIZE 878 GNUNET_MAX_MESSAGE_SIZE
879 - sizeof (*req)) + 1; 879 - sizeof (*req)) + 1;
880 GNUNET_assert ('\0' == method_prefix[method_size - 1]); 880 GNUNET_assert ('\0' == method_prefix[method_size - 1]);
881 881
diff --git a/src/psycutil/.gitignore b/src/psycutil/.gitignore
new file mode 100644
index 000000000..03d8197fb
--- /dev/null
+++ b/src/psycutil/.gitignore
@@ -0,0 +1 @@
test_psyc_env
diff --git a/src/pt/Makefile.am b/src/pt/Makefile.am
index 7ea8257d5..e36630ae4 100644
--- a/src/pt/Makefile.am
+++ b/src/pt/Makefile.am
@@ -25,7 +25,7 @@ gnunet_daemon_pt_SOURCES = \
25 gnunet-daemon-pt.c 25 gnunet-daemon-pt.c
26gnunet_daemon_pt_LDADD = \ 26gnunet_daemon_pt_LDADD = \
27 $(top_builddir)/src/vpn/libgnunetvpn.la \ 27 $(top_builddir)/src/vpn/libgnunetvpn.la \
28 $(top_builddir)/src/cadet/libgnunetcadetnew.la \ 28 $(top_builddir)/src/cadet/libgnunetcadet.la \
29 $(top_builddir)/src/dht/libgnunetdht.la \ 29 $(top_builddir)/src/dht/libgnunetdht.la \
30 $(top_builddir)/src/dns/libgnunetdns.la \ 30 $(top_builddir)/src/dns/libgnunetdns.la \
31 $(top_builddir)/src/dns/libgnunetdnsparser.la \ 31 $(top_builddir)/src/dns/libgnunetdnsparser.la \
diff --git a/src/pt/gnunet-daemon-pt.c b/src/pt/gnunet-daemon-pt.c
index 54556cc52..295082c0e 100644
--- a/src/pt/gnunet-daemon-pt.c
+++ b/src/pt/gnunet-daemon-pt.c
@@ -1015,7 +1015,7 @@ cadet_channel_end_cb (void *cls,
1015 GNUNET_CONTAINER_DLL_insert (alt->receive_queue_head, 1015 GNUNET_CONTAINER_DLL_insert (alt->receive_queue_head,
1016 alt->receive_queue_tail, 1016 alt->receive_queue_tail,
1017 rc); 1017 rc);
1018 GNUNET_MQ_send (GNUNET_CADET_get_mq (exit->cadet_channel), 1018 GNUNET_MQ_send (GNUNET_CADET_get_mq (alt->cadet_channel),
1019 GNUNET_MQ_env_copy (rc->env)); 1019 GNUNET_MQ_env_copy (rc->env));
1020 } 1020 }
1021 try_open_exit (); 1021 try_open_exit ();
@@ -1084,7 +1084,7 @@ try_open_exit ()
1084 1084
1085 /* move to the head of the DLL */ 1085 /* move to the head of the DLL */
1086 pos->cadet_channel 1086 pos->cadet_channel
1087 = GNUNET_CADET_channel_creatE (cadet_handle, 1087 = GNUNET_CADET_channel_create (cadet_handle,
1088 pos, 1088 pos,
1089 &pos->peer, 1089 &pos->peer,
1090 &port, 1090 &port,
@@ -1246,7 +1246,7 @@ run (void *cls, char *const *args GNUNET_UNUSED,
1246 GNUNET_SCHEDULER_shutdown (); 1246 GNUNET_SCHEDULER_shutdown ();
1247 return; 1247 return;
1248 } 1248 }
1249 cadet_handle = GNUNET_CADET_connecT (cfg); 1249 cadet_handle = GNUNET_CADET_connect (cfg);
1250 if (NULL == cadet_handle) 1250 if (NULL == cadet_handle)
1251 { 1251 {
1252 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1252 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
diff --git a/src/regex/gnunet-regex-profiler.c b/src/regex/gnunet-regex-profiler.c
index dfbcd388a..71f3580f8 100644
--- a/src/regex/gnunet-regex-profiler.c
+++ b/src/regex/gnunet-regex-profiler.c
@@ -1477,22 +1477,39 @@ run (void *cls,
1477int 1477int
1478main (int argc, char *const *argv) 1478main (int argc, char *const *argv)
1479{ 1479{
1480 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 1480 struct GNUNET_GETOPT_CommandLineOption options[] = {
1481 {'o', "output-file", "FILENAME", 1481
1482 gettext_noop ("name of the file for writing statistics"), 1482 GNUNET_GETOPT_OPTION_FILENAME ('o',
1483 GNUNET_YES, &GNUNET_GETOPT_set_string, &data_filename}, 1483 "output-file",
1484 {'t', "matching-timeout", "TIMEOUT", 1484 "FILENAME",
1485 gettext_noop ("wait TIMEOUT before ending the experiment"), 1485 gettext_noop ("name of the file for writing statistics"),
1486 GNUNET_YES, &GNUNET_GETOPT_set_relative_time, &search_timeout_time}, 1486 &data_filename),
1487 {'p', "policy-dir", "DIRECTORY", 1487
1488 gettext_noop ("directory with policy files"), 1488 GNUNET_GETOPT_OPTION_SET_RELATIVE_TIME ('t',
1489 GNUNET_YES, &GNUNET_GETOPT_set_filename, &policy_dir}, 1489 "matching-timeout",
1490 {'s', "strings-file", "FILENAME", 1490 "TIMEOUT",
1491 gettext_noop ("name of file with input strings"), 1491 gettext_noop ("wait TIMEOUT before ending the experiment"),
1492 GNUNET_YES, &GNUNET_GETOPT_set_filename, &strings_file}, 1492 &search_timeout_time),
1493 {'H', "hosts-file", "FILENAME", 1493
1494 gettext_noop ("name of file with hosts' names"), 1494 GNUNET_GETOPT_OPTION_FILENAME ('p',
1495 GNUNET_YES, &GNUNET_GETOPT_set_filename, &hosts_file}, 1495 "policy-dir",
1496 "DIRECTORY",
1497 gettext_noop ("directory with policy files"),
1498 &policy_dir),
1499
1500
1501 GNUNET_GETOPT_OPTION_FILENAME ('s',
1502 "strings-file",
1503 "FILENAME",
1504 gettext_noop ("name of file with input strings"),
1505 &strings_file),
1506
1507 GNUNET_GETOPT_OPTION_FILENAME ('H',
1508 "hosts-file",
1509 "FILENAME",
1510 gettext_noop ("name of file with hosts' names"),
1511 &hosts_file),
1512
1496 GNUNET_GETOPT_OPTION_END 1513 GNUNET_GETOPT_OPTION_END
1497 }; 1514 };
1498 int ret; 1515 int ret;
diff --git a/src/regex/gnunet-regex-simulation-profiler.c b/src/regex/gnunet-regex-simulation-profiler.c
index 025a70316..422e45565 100644
--- a/src/regex/gnunet-regex-simulation-profiler.c
+++ b/src/regex/gnunet-regex-simulation-profiler.c
@@ -691,13 +691,20 @@ run (void *cls,
691int 691int
692main (int argc, char *const *argv) 692main (int argc, char *const *argv)
693{ 693{
694 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 694 struct GNUNET_GETOPT_CommandLineOption options[] = {
695 {'t', "table", "TABLENAME", 695
696 gettext_noop ("name of the table to write DFAs"), 696 GNUNET_GETOPT_OPTION_STRING ('t',
697 1, &GNUNET_GETOPT_set_string, &table_name}, 697 "table",
698 {'p', "max-path-compression", "MAX_PATH_COMPRESSION", 698 "TABLENAME",
699 gettext_noop ("maximum path compression length"), 699 gettext_noop ("name of the table to write DFAs"),
700 1, &GNUNET_GETOPT_set_uint, &max_path_compression}, 700 &table_name),
701
702 GNUNET_GETOPT_OPTION_SET_UINT ('p',
703 "max-path-compression",
704 "MAX_PATH_COMPRESSION",
705 gettext_noop ("maximum path compression length"),
706 &max_path_compression),
707
701 GNUNET_GETOPT_OPTION_END 708 GNUNET_GETOPT_OPTION_END
702 }; 709 };
703 int ret; 710 int ret;
diff --git a/src/regex/gnunet-service-regex.c b/src/regex/gnunet-service-regex.c
index 294670be6..9a40a5264 100644
--- a/src/regex/gnunet-service-regex.c
+++ b/src/regex/gnunet-service-regex.c
@@ -37,19 +37,14 @@ struct ClientEntry
37{ 37{
38 38
39 /** 39 /**
40 * Kept in DLL. 40 * Queue for transmissions to @e client.
41 */ 41 */
42 struct ClientEntry *next; 42 struct GNUNET_MQ_Handle *mq;
43
44 /**
45 * Kept in DLL.
46 */
47 struct ClientEntry *prev;
48 43
49 /** 44 /**
50 * Handle identifying the client. 45 * Handle identifying the client.
51 */ 46 */
52 struct GNUNET_SERVER_Client *client; 47 struct GNUNET_SERVICE_Client *client;
53 48
54 /** 49 /**
55 * Search handle (if this client is searching). 50 * Search handle (if this client is searching).
@@ -69,7 +64,7 @@ struct ClientEntry
69 /** 64 /**
70 * Task for re-announcing. 65 * Task for re-announcing.
71 */ 66 */
72 struct GNUNET_SCHEDULER_Task * refresh_task; 67 struct GNUNET_SCHEDULER_Task *refresh_task;
73 68
74}; 69};
75 70
@@ -85,70 +80,12 @@ static struct GNUNET_DHT_Handle *dht;
85static struct GNUNET_STATISTICS_Handle *stats; 80static struct GNUNET_STATISTICS_Handle *stats;
86 81
87/** 82/**
88 * Head of list of clients.
89 */
90static struct ClientEntry *client_head;
91
92/**
93 * End of list of clients.
94 */
95static struct ClientEntry *client_tail;
96
97/**
98 * Our notification context, used to send back results to the client.
99 */
100static struct GNUNET_SERVER_NotificationContext *nc;
101
102/**
103 * Private key for this peer. 83 * Private key for this peer.
104 */ 84 */
105static struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key; 85static struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
106 86
107 87
108/** 88/**
109 * A client disconnected. Remove all of its data structure entries.
110 *
111 * @param cls closure, NULL
112 * @param client identification of the client
113 */
114static void
115handle_client_disconnect (void *cls,
116 struct GNUNET_SERVER_Client *client)
117{
118 struct ClientEntry *ce;
119 struct ClientEntry *nx;
120
121 nx = client_head;
122 for (ce = nx; NULL != ce; ce = nx)
123 {
124 nx = ce->next;
125 if (ce->client == client)
126 {
127 if (NULL != ce->refresh_task)
128 {
129 GNUNET_SCHEDULER_cancel (ce->refresh_task);
130 ce->refresh_task = NULL;
131 }
132 if (NULL != ce->ah)
133 {
134 REGEX_INTERNAL_announce_cancel (ce->ah);
135 ce->ah = NULL;
136 }
137 if (NULL != ce->sh)
138 {
139 REGEX_INTERNAL_search_cancel (ce->sh);
140 ce->sh = NULL;
141 }
142 GNUNET_CONTAINER_DLL_remove (client_head,
143 client_tail,
144 ce);
145 GNUNET_free (ce);
146 }
147 }
148}
149
150
151/**
152 * Task run during shutdown. 89 * Task run during shutdown.
153 * 90 *
154 * @param cls unused 91 * @param cls unused
@@ -156,17 +93,11 @@ handle_client_disconnect (void *cls,
156static void 93static void
157cleanup_task (void *cls) 94cleanup_task (void *cls)
158{ 95{
159 struct ClientEntry *ce;
160
161 while (NULL != (ce = client_head))
162 handle_client_disconnect (NULL,
163 ce->client);
164 GNUNET_DHT_disconnect (dht); 96 GNUNET_DHT_disconnect (dht);
165 dht = NULL; 97 dht = NULL;
166 GNUNET_STATISTICS_destroy (stats, GNUNET_NO); 98 GNUNET_STATISTICS_destroy (stats,
99 GNUNET_NO);
167 stats = NULL; 100 stats = NULL;
168 GNUNET_SERVER_notification_context_destroy (nc);
169 nc = NULL;
170 GNUNET_free (my_private_key); 101 GNUNET_free (my_private_key);
171 my_private_key = NULL; 102 my_private_key = NULL;
172} 103}
@@ -191,35 +122,51 @@ reannounce (void *cls)
191 122
192 123
193/** 124/**
194 * Handle ANNOUNCE message. 125 * Check ANNOUNCE message.
195 * 126 *
196 * @param cls closure 127 * @param cls identification of the client
197 * @param client identification of the client 128 * @param am the actual message
198 * @param message the actual message 129 * @return #GNUNET_OK if @am is well-formed
199 */ 130 */
200static void 131static int
201handle_announce (void *cls, 132check_announce (void *cls,
202 struct GNUNET_SERVER_Client *client, 133 const struct AnnounceMessage *am)
203 const struct GNUNET_MessageHeader *message)
204{ 134{
205 const struct AnnounceMessage *am; 135 struct ClientEntry *ce = cls;
206 const char *regex; 136 const char *regex;
207 struct ClientEntry *ce;
208 uint16_t size; 137 uint16_t size;
209 138
210 size = ntohs (message->size); 139 size = ntohs (am->header.size) - sizeof (*am);
211 am = (const struct AnnounceMessage *) message;
212 regex = (const char *) &am[1]; 140 regex = (const char *) &am[1];
213 if ( (size <= sizeof (struct AnnounceMessage)) || 141 if ('\0' != regex[size - 1])
214 ('\0' != regex[size - sizeof (struct AnnounceMessage) - 1]) )
215 { 142 {
216 GNUNET_break (0); 143 GNUNET_break (0);
217 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); 144 return GNUNET_SYSERR;
218 return; 145 }
146 if (NULL != ce->ah)
147 {
148 /* only one announcement per client allowed */
149 GNUNET_break (0);
150 return GNUNET_SYSERR;
219 } 151 }
152 return GNUNET_OK;
153}
220 154
221 ce = GNUNET_new (struct ClientEntry); 155
222 ce->client = client; 156/**
157 * Handle ANNOUNCE message.
158 *
159 * @param cls identification of the client
160 * @param am the actual message
161 */
162static void
163handle_announce (void *cls,
164 const struct AnnounceMessage *am)
165{
166 struct ClientEntry *ce = cls;
167 const char *regex;
168
169 regex = (const char *) &am[1];
223 ce->frequency = GNUNET_TIME_relative_ntoh (am->refresh_delay); 170 ce->frequency = GNUNET_TIME_relative_ntoh (am->refresh_delay);
224 ce->refresh_task = GNUNET_SCHEDULER_add_delayed (ce->frequency, 171 ce->refresh_task = GNUNET_SCHEDULER_add_delayed (ce->frequency,
225 &reannounce, 172 &reannounce,
@@ -238,14 +185,11 @@ handle_announce (void *cls,
238 { 185 {
239 GNUNET_break (0); 186 GNUNET_break (0);
240 GNUNET_SCHEDULER_cancel (ce->refresh_task); 187 GNUNET_SCHEDULER_cancel (ce->refresh_task);
241 GNUNET_free (ce); 188 ce->refresh_task = NULL;
242 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); 189 GNUNET_SERVICE_client_drop (ce->client);
243 return; 190 return;
244 } 191 }
245 GNUNET_CONTAINER_DLL_insert (client_head, 192 GNUNET_SERVICE_client_continue (ce->client);
246 client_tail,
247 ce);
248 GNUNET_SERVER_receive_done (client, GNUNET_OK);
249} 193}
250 194
251 195
@@ -268,6 +212,7 @@ handle_search_result (void *cls,
268 unsigned int put_path_length) 212 unsigned int put_path_length)
269{ 213{
270 struct ClientEntry *ce = cls; 214 struct ClientEntry *ce = cls;
215 struct GNUNET_MQ_Envelope *env;
271 struct ResultMessage *result; 216 struct ResultMessage *result;
272 struct GNUNET_PeerIdentity *gp; 217 struct GNUNET_PeerIdentity *gp;
273 uint16_t size; 218 uint16_t size;
@@ -275,64 +220,78 @@ handle_search_result (void *cls,
275 if ( (get_path_length >= 65536) || 220 if ( (get_path_length >= 65536) ||
276 (put_path_length >= 65536) || 221 (put_path_length >= 65536) ||
277 ( (get_path_length + put_path_length) * sizeof (struct GNUNET_PeerIdentity)) 222 ( (get_path_length + put_path_length) * sizeof (struct GNUNET_PeerIdentity))
278 + sizeof (struct ResultMessage) >= GNUNET_SERVER_MAX_MESSAGE_SIZE) 223 + sizeof (struct ResultMessage) >= GNUNET_MAX_MESSAGE_SIZE)
279 { 224 {
280 GNUNET_break (0); 225 GNUNET_break (0);
281 return; 226 return;
282 } 227 }
283 size = (get_path_length + put_path_length) * sizeof (struct GNUNET_PeerIdentity) + sizeof (struct ResultMessage); 228 size = (get_path_length + put_path_length) * sizeof (struct GNUNET_PeerIdentity);
284 result = GNUNET_malloc (size); 229 env = GNUNET_MQ_msg_extra (result,
285 result->header.size = htons (size); 230 size,
286 result->header.type = htons (GNUNET_MESSAGE_TYPE_REGEX_RESULT); 231 GNUNET_MESSAGE_TYPE_REGEX_RESULT);
287 result->get_path_length = htons ((uint16_t) get_path_length); 232 result->get_path_length = htons ((uint16_t) get_path_length);
288 result->put_path_length = htons ((uint16_t) put_path_length); 233 result->put_path_length = htons ((uint16_t) put_path_length);
289 result->id = *id; 234 result->id = *id;
290 gp = &result->id; 235 gp = &result->id;
291 GNUNET_memcpy (&gp[1], 236 GNUNET_memcpy (&gp[1],
292 get_path, 237 get_path,
293 get_path_length * sizeof (struct GNUNET_PeerIdentity)); 238 get_path_length * sizeof (struct GNUNET_PeerIdentity));
294 GNUNET_memcpy (&gp[1 + get_path_length], 239 GNUNET_memcpy (&gp[1 + get_path_length],
295 put_path, 240 put_path,
296 put_path_length * sizeof (struct GNUNET_PeerIdentity)); 241 put_path_length * sizeof (struct GNUNET_PeerIdentity));
297 GNUNET_SERVER_notification_context_unicast (nc, 242 GNUNET_MQ_send (ce->mq,
298 ce->client, 243 env);
299 &result->header, GNUNET_NO);
300 GNUNET_free (result);
301} 244}
302 245
303 246
304/** 247/**
305 * Handle SEARCH message. 248 * Check SEARCH message.
306 * 249 *
307 * @param cls closure 250 * @param cls identification of the client
308 * @param client identification of the client
309 * @param message the actual message 251 * @param message the actual message
310 */ 252 */
311static void 253static int
312handle_search (void *cls, 254check_search (void *cls,
313 struct GNUNET_SERVER_Client *client, 255 const struct RegexSearchMessage *sm)
314 const struct GNUNET_MessageHeader *message)
315{ 256{
316 const struct RegexSearchMessage *sm; 257 struct ClientEntry *ce = cls;
317 const char *string; 258 const char *string;
318 struct ClientEntry *ce;
319 uint16_t size; 259 uint16_t size;
320 260
321 size = ntohs (message->size); 261 size = ntohs (sm->header.size) - sizeof (*sm);
322 sm = (const struct RegexSearchMessage *) message;
323 string = (const char *) &sm[1]; 262 string = (const char *) &sm[1];
324 if ( (size <= sizeof (struct RegexSearchMessage)) || 263 if ('\0' != string[size - 1])
325 ('\0' != string[size - sizeof (struct RegexSearchMessage) - 1]) )
326 { 264 {
327 GNUNET_break (0); 265 GNUNET_break (0);
328 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); 266 return GNUNET_SYSERR;
329 return;
330 } 267 }
268 if (NULL != ce->sh)
269 {
270 /* only one search allowed per client */
271 GNUNET_break (0);
272 return GNUNET_SYSERR;
273 }
274 return GNUNET_OK;
275}
276
277
278/**
279 * Handle SEARCH message.
280 *
281 * @param cls identification of the client
282 * @param message the actual message
283 */
284static void
285handle_search (void *cls,
286 const struct RegexSearchMessage *sm)
287{
288 struct ClientEntry *ce = cls;
289 const char *string;
290
291 string = (const char *) &sm[1];
331 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 292 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
332 "Starting to search for `%s'\n", 293 "Starting to search for `%s'\n",
333 string); 294 string);
334 ce = GNUNET_new (struct ClientEntry);
335 ce->client = client;
336 ce->sh = REGEX_INTERNAL_search (dht, 295 ce->sh = REGEX_INTERNAL_search (dht,
337 string, 296 string,
338 &handle_search_result, 297 &handle_search_result,
@@ -341,15 +300,10 @@ handle_search (void *cls,
341 if (NULL == ce->sh) 300 if (NULL == ce->sh)
342 { 301 {
343 GNUNET_break (0); 302 GNUNET_break (0);
344 GNUNET_free (ce); 303 GNUNET_SERVICE_client_drop (ce->client);
345 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
346 return; 304 return;
347 } 305 }
348 GNUNET_CONTAINER_DLL_insert (client_head, 306 GNUNET_SERVICE_client_continue (ce->client);
349 client_tail,
350 ce);
351 GNUNET_SERVER_notification_context_add (nc, client);
352 GNUNET_SERVER_receive_done (client, GNUNET_OK);
353} 307}
354 308
355 309
@@ -357,19 +311,14 @@ handle_search (void *cls,
357 * Process regex requests. 311 * Process regex requests.
358 * 312 *
359 * @param cls closure 313 * @param cls closure
360 * @param server the initialized server
361 * @param cfg configuration to use 314 * @param cfg configuration to use
315 * @param service the initialized service
362 */ 316 */
363static void 317static void
364run (void *cls, struct GNUNET_SERVER_Handle *server, 318run (void *cls,
365 const struct GNUNET_CONFIGURATION_Handle *cfg) 319 const struct GNUNET_CONFIGURATION_Handle *cfg,
320 struct GNUNET_SERVICE_Handle *service)
366{ 321{
367 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
368 {&handle_announce, NULL, GNUNET_MESSAGE_TYPE_REGEX_ANNOUNCE, 0},
369 {&handle_search, NULL, GNUNET_MESSAGE_TYPE_REGEX_SEARCH, 0},
370 {NULL, NULL, 0, 0}
371 };
372
373 my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg); 322 my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg);
374 if (NULL == my_private_key) 323 if (NULL == my_private_key)
375 { 324 {
@@ -386,28 +335,84 @@ run (void *cls, struct GNUNET_SERVER_Handle *server,
386 } 335 }
387 GNUNET_SCHEDULER_add_shutdown (&cleanup_task, 336 GNUNET_SCHEDULER_add_shutdown (&cleanup_task,
388 NULL); 337 NULL);
389 nc = GNUNET_SERVER_notification_context_create (server, 1);
390 stats = GNUNET_STATISTICS_create ("regex", cfg); 338 stats = GNUNET_STATISTICS_create ("regex", cfg);
391 GNUNET_SERVER_add_handlers (server, handlers);
392 GNUNET_SERVER_disconnect_notify (server,
393 &handle_client_disconnect,
394 NULL);
395} 339}
396 340
397 341
398/** 342/**
399 * The main function for the regex service. 343 * Callback called when a client connects to the service.
400 * 344 *
401 * @param argc number of arguments from the command line 345 * @param cls closure for the service
402 * @param argv command line arguments 346 * @param c the new client that connected to the service
403 * @return 0 ok, 1 on error 347 * @param mq the message queue used to send messages to the client
348 * @return @a c
404 */ 349 */
405int 350static void *
406main (int argc, char *const *argv) 351client_connect_cb (void *cls,
352 struct GNUNET_SERVICE_Client *c,
353 struct GNUNET_MQ_Handle *mq)
407{ 354{
408 return (GNUNET_OK == 355 struct ClientEntry *ce;
409 GNUNET_SERVICE_run (argc, argv, "regex", 356
410 GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1; 357 ce = GNUNET_new (struct ClientEntry);
358 ce->client = c;
359 ce->mq = mq;
360 return ce;
411} 361}
412 362
363
364/**
365 * Callback called when a client disconnected from the service
366 *
367 * @param cls closure for the service
368 * @param c the client that disconnected
369 * @param internal_cls should be equal to @a c
370 */
371static void
372client_disconnect_cb (void *cls,
373 struct GNUNET_SERVICE_Client *c,
374 void *internal_cls)
375{
376 struct ClientEntry *ce = internal_cls;
377
378 if (NULL != ce->refresh_task)
379 {
380 GNUNET_SCHEDULER_cancel (ce->refresh_task);
381 ce->refresh_task = NULL;
382 }
383 if (NULL != ce->ah)
384 {
385 REGEX_INTERNAL_announce_cancel (ce->ah);
386 ce->ah = NULL;
387 }
388 if (NULL != ce->sh)
389 {
390 REGEX_INTERNAL_search_cancel (ce->sh);
391 ce->sh = NULL;
392 }
393 GNUNET_free (ce);
394}
395
396
397/**
398 * Define "main" method using service macro.
399 */
400GNUNET_SERVICE_MAIN
401("regex",
402 GNUNET_SERVICE_OPTION_NONE,
403 &run,
404 &client_connect_cb,
405 &client_disconnect_cb,
406 NULL,
407 GNUNET_MQ_hd_var_size (announce,
408 GNUNET_MESSAGE_TYPE_REGEX_ANNOUNCE,
409 struct AnnounceMessage,
410 NULL),
411 GNUNET_MQ_hd_var_size (search,
412 GNUNET_MESSAGE_TYPE_REGEX_SEARCH,
413 struct RegexSearchMessage,
414 NULL),
415 GNUNET_MQ_handler_end ());
416
417
413/* end of gnunet-service-regex.c */ 418/* end of gnunet-service-regex.c */
diff --git a/src/regex/regex_api_announce.c b/src/regex/regex_api_announce.c
index 70bf34bc8..8e018f26c 100644
--- a/src/regex/regex_api_announce.c
+++ b/src/regex/regex_api_announce.c
@@ -146,7 +146,7 @@ GNUNET_REGEX_announce (const struct GNUNET_CONFIGURATION_Handle *cfg,
146 size_t slen; 146 size_t slen;
147 147
148 slen = strlen (regex) + 1; 148 slen = strlen (regex) + 1;
149 if (slen + sizeof (struct AnnounceMessage) >= GNUNET_SERVER_MAX_MESSAGE_SIZE) 149 if (slen + sizeof (struct AnnounceMessage) >= GNUNET_MAX_MESSAGE_SIZE)
150 { 150 {
151 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 151 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
152 _("Regex `%s' is too long!\n"), 152 _("Regex `%s' is too long!\n"),
diff --git a/src/regex/regex_api_search.c b/src/regex/regex_api_search.c
index b7a015f87..a5480ac7a 100644
--- a/src/regex/regex_api_search.c
+++ b/src/regex/regex_api_search.c
@@ -206,7 +206,7 @@ GNUNET_REGEX_search (const struct GNUNET_CONFIGURATION_Handle *cfg,
206 struct GNUNET_REGEX_Search *s; 206 struct GNUNET_REGEX_Search *s;
207 size_t slen = strlen (string) + 1; 207 size_t slen = strlen (string) + 1;
208 208
209 if (slen + sizeof (struct RegexSearchMessage) >= GNUNET_SERVER_MAX_MESSAGE_SIZE) 209 if (slen + sizeof (struct RegexSearchMessage) >= GNUNET_MAX_MESSAGE_SIZE)
210 { 210 {
211 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 211 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
212 _("Search string `%s' is too long!\n"), 212 _("Search string `%s' is too long!\n"),
diff --git a/src/rest/gnunet-rest-server.c b/src/rest/gnunet-rest-server.c
index b115deb20..0b6c18267 100644
--- a/src/rest/gnunet-rest-server.c
+++ b/src/rest/gnunet-rest-server.c
@@ -66,7 +66,7 @@ static struct GNUNET_SCHEDULER_Task *httpd_task;
66/** 66/**
67 * The port the service is running on (default 7776) 67 * The port the service is running on (default 7776)
68 */ 68 */
69static unsigned long port = GNUNET_REST_SERVICE_PORT; 69static unsigned long long port = GNUNET_REST_SERVICE_PORT;
70 70
71/** 71/**
72 * The listen socket of the service for IPv4 72 * The listen socket of the service for IPv4
@@ -748,7 +748,7 @@ run (void *cls,
748 return; 748 return;
749 } 749 }
750 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 750 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
751 "Service listens on port %lu\n", 751 "Service listens on port %llu\n",
752 port); 752 port);
753 httpd = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_NO_LISTEN_SOCKET, 753 httpd = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_NO_LISTEN_SOCKET,
754 0, 754 0,
@@ -783,10 +783,12 @@ run (void *cls,
783int 783int
784main (int argc, char *const *argv) 784main (int argc, char *const *argv)
785{ 785{
786 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 786 struct GNUNET_GETOPT_CommandLineOption options[] = {
787 {'p', "port", NULL, 787 GNUNET_GETOPT_OPTION_SET_ULONG ('p',
788 gettext_noop ("listen on specified port (default: 7776)"), 1, 788 "port",
789 &GNUNET_GETOPT_set_ulong, &port}, 789 "PORT",
790 gettext_noop ("listen on specified port (default: 7776)"),
791 &port),
790 GNUNET_GETOPT_OPTION_END 792 GNUNET_GETOPT_OPTION_END
791 }; 793 };
792 static const char* err_page = 794 static const char* err_page =
diff --git a/src/revocation/gnunet-revocation.c b/src/revocation/gnunet-revocation.c
index 133468789..7b40c83d7 100644
--- a/src/revocation/gnunet-revocation.c
+++ b/src/revocation/gnunet-revocation.c
@@ -527,19 +527,31 @@ run (void *cls,
527int 527int
528main (int argc, char *const *argv) 528main (int argc, char *const *argv)
529{ 529{
530 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 530 struct GNUNET_GETOPT_CommandLineOption options[] = {
531 {'f', "filename", "NAME", 531
532 gettext_noop ("use NAME for the name of the revocation file"), 532 GNUNET_GETOPT_OPTION_STRING ('f',
533 1, &GNUNET_GETOPT_set_string, &filename}, 533 "filename",
534 {'R', "revoke", "NAME", 534 "NAME",
535 gettext_noop ("revoke the private key associated for the the private key associated with the ego NAME "), 535 gettext_noop ("use NAME for the name of the revocation file"),
536 1, &GNUNET_GETOPT_set_string, &revoke_ego}, 536 &filename),
537 {'p', "perform", NULL, 537
538 gettext_noop ("actually perform revocation, otherwise we just do the precomputation"), 538 GNUNET_GETOPT_OPTION_STRING ('R',
539 0, &GNUNET_GETOPT_set_one, &perform}, 539 "revoke",
540 {'t', "test", "KEY", 540 "NAME",
541 gettext_noop ("test if the public key KEY has been revoked"), 541 gettext_noop ("revoke the private key associated for the the private key associated with the ego NAME "),
542 1, &GNUNET_GETOPT_set_string, &test_ego}, 542 &revoke_ego),
543
544 GNUNET_GETOPT_OPTION_SET_ONE ('p',
545 "perform",
546 gettext_noop ("actually perform revocation, otherwise we just do the precomputation"),
547 &perform),
548
549 GNUNET_GETOPT_OPTION_STRING ('t',
550 "test",
551 "KEY",
552 gettext_noop ("test if the public key KEY has been revoked"),
553 &test_ego),
554
543 GNUNET_GETOPT_OPTION_END 555 GNUNET_GETOPT_OPTION_END
544 }; 556 };
545 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) 557 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
diff --git a/src/revocation/test_revocation.c b/src/revocation/test_revocation.c
index d3bbb879a..8d5593694 100644
--- a/src/revocation/test_revocation.c
+++ b/src/revocation/test_revocation.c
@@ -104,8 +104,8 @@ revocation_remote_cb (void *cls,
104 104
105 if (GNUNET_NO == is_valid) 105 if (GNUNET_NO == is_valid)
106 { 106 {
107 fprintf (stderr, 107 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
108 "Local revocation successful\n"); 108 "Local revocation successful\n");
109 ok = 0; 109 ok = 0;
110 GNUNET_SCHEDULER_shutdown (); 110 GNUNET_SCHEDULER_shutdown ();
111 return; 111 return;
@@ -118,8 +118,8 @@ revocation_remote_cb (void *cls,
118 NULL); 118 NULL);
119 return; 119 return;
120 } 120 }
121 fprintf (stderr, 121 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
122 "Flooding of revocation failed\n"); 122 "Flooding of revocation failed\n");
123 ok = 2; 123 ok = 2;
124 GNUNET_SCHEDULER_shutdown (); 124 GNUNET_SCHEDULER_shutdown ();
125} 125}
@@ -141,8 +141,8 @@ revocation_cb (void *cls,
141 testpeers[1].revok_handle = NULL; 141 testpeers[1].revok_handle = NULL;
142 if (GNUNET_NO == is_valid) 142 if (GNUNET_NO == is_valid)
143 { 143 {
144 fprintf (stderr, 144 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
145 "Revocation successful\n"); 145 "Revocation successful\n");
146 check_revocation (NULL); 146 check_revocation (NULL);
147 } 147 }
148} 148}
@@ -386,8 +386,8 @@ test_connection (void *cls,
386 /* We are generating a CLIQUE */ 386 /* We are generating a CLIQUE */
387 if (NUM_TEST_PEERS * (NUM_TEST_PEERS -1) == links_succeeded) 387 if (NUM_TEST_PEERS * (NUM_TEST_PEERS -1) == links_succeeded)
388 { 388 {
389 fprintf (stderr, 389 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
390 "Testbed connected peers, initializing test\n"); 390 "Testbed connected peers, initializing test\n");
391 for (c = 0; c < num_peers; c++) 391 for (c = 0; c < num_peers; c++)
392 { 392 {
393 testpeers[c].p = peers[c]; 393 testpeers[c].p = peers[c];
@@ -403,8 +403,8 @@ test_connection (void *cls,
403 } 403 }
404 else 404 else
405 { 405 {
406 fprintf (stderr, 406 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
407 "Testbed failed to connect peers\n"); 407 "Testbed failed to connect peers\n");
408 ok = 5; 408 ok = 5;
409 GNUNET_SCHEDULER_shutdown (); 409 GNUNET_SCHEDULER_shutdown ();
410 return; 410 return;
diff --git a/src/rps/Makefile.am b/src/rps/Makefile.am
index de7f853c1..e6c8cd929 100644
--- a/src/rps/Makefile.am
+++ b/src/rps/Makefile.am
@@ -100,22 +100,28 @@ AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PAT
100TESTS = $(check_PROGRAMS) 100TESTS = $(check_PROGRAMS)
101endif 101endif
102 102
103test_service_rps_view_SOURCES = gnunet-service-rps_view.h gnunet-service-rps_view.c \ 103test_service_rps_view_SOURCES = \
104 test_service_rps_view.c 104 gnunet-service-rps_view.h gnunet-service-rps_view.c \
105 test_service_rps_view.c
105test_service_rps_view_LDADD = $(top_builddir)/src/util/libgnunetutil.la 106test_service_rps_view_LDADD = $(top_builddir)/src/util/libgnunetutil.la
106 107
107test_service_rps_peers_SOURCES = gnunet-service-rps_peers.h gnunet-service-rps_peers.c \ 108test_service_rps_peers_SOURCES = \
108 test_service_rps_peers.c 109 gnunet-service-rps_peers.h gnunet-service-rps_peers.c \
109test_service_rps_peers_LDADD = $(top_builddir)/src/util/libgnunetutil.la \ 110 test_service_rps_peers.c
110 $(top_builddir)/src/cadet/libgnunetcadet.la 111test_service_rps_peers_LDADD = \
111 112 $(top_builddir)/src/util/libgnunetutil.la \
112test_service_rps_custommap_SOURCES = gnunet-service-rps_custommap.h gnunet-service-rps_custommap.c \ 113 $(top_builddir)/src/cadet/libgnunetcadet.la
113 test_service_rps_custommap.c 114
114test_service_rps_custommap_LDADD = $(top_builddir)/src/util/libgnunetutil.la 115test_service_rps_custommap_SOURCES = \
115 116 gnunet-service-rps_custommap.h gnunet-service-rps_custommap.c \
116test_service_rps_sampler_elem_SOURCES = gnunet-service-rps_sampler_elem.h gnunet-service-rps_sampler_elem.c \ 117 test_service_rps_custommap.c
117 rps-test_util.h rps-test_util.c \ 118test_service_rps_custommap_LDADD = \
118 test_service_rps_sampler_elem.c 119 $(top_builddir)/src/util/libgnunetutil.la
120
121test_service_rps_sampler_elem_SOURCES = \
122 gnunet-service-rps_sampler_elem.h gnunet-service-rps_sampler_elem.c \
123 rps-test_util.h rps-test_util.c \
124 test_service_rps_sampler_elem.c
119test_service_rps_sampler_elem_LDADD = $(top_builddir)/src/util/libgnunetutil.la 125test_service_rps_sampler_elem_LDADD = $(top_builddir)/src/util/libgnunetutil.la
120 126
121test_rps_malicious_1_SOURCES = $(rps_test_src) 127test_rps_malicious_1_SOURCES = $(rps_test_src)
diff --git a/src/rps/gnunet-rps.c b/src/rps/gnunet-rps.c
index 3dbb8053e..e36e547fa 100644
--- a/src/rps/gnunet-rps.c
+++ b/src/rps/gnunet-rps.c
@@ -43,43 +43,7 @@ static struct GNUNET_RPS_Request_Handle *req_handle;
43/** 43/**
44 * PeerID (Option --seed) 44 * PeerID (Option --seed)
45 */ 45 */
46static struct GNUNET_PeerIdentity *peer_id; 46static struct GNUNET_PeerIdentity peer_id;
47
48
49/**
50 * Set an option of type 'struct GNUNET_PeerIdentity *' from the command line.
51 * A pointer to this function should be passed as part of the
52 * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options
53 * of this type. It should be followed by a pointer to a value of
54 * type 'struct GNUNET_PeerIdentity *', which will be allocated with the requested string.
55 *
56 * @param ctx command line processing context
57 * @param scls additional closure (will point to the 'char *',
58 * which will be allocated)
59 * @param option name of the option
60 * @param value actual value of the option (a PeerID)
61 * @return #GNUNET_OK
62 */
63static int
64GNUNET_GETOPT_set_peerid (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
65 void *scls, const char *option, const char *value)
66{
67 struct GNUNET_PeerIdentity **val = (struct GNUNET_PeerIdentity **) scls;
68
69 GNUNET_assert (NULL != value);
70 GNUNET_free_non_null (*val);
71 /* Not quite sure whether that is a sane way */
72 *val = GNUNET_new (struct GNUNET_PeerIdentity);
73 if (GNUNET_OK !=
74 GNUNET_CRYPTO_eddsa_public_key_from_string (value,
75 strlen (value),
76 &((*val)->public_key)))
77 {
78 FPRINTF (stderr, "Invalid peer ID %s\n", value);
79 return GNUNET_SYSERR;
80 }
81 return GNUNET_OK;
82}
83 47
84 48
85/** 49/**
@@ -139,10 +103,13 @@ run (void *cls,
139 const struct GNUNET_CONFIGURATION_Handle *cfg) 103 const struct GNUNET_CONFIGURATION_Handle *cfg)
140{ 104{
141 static uint64_t num_peers; 105 static uint64_t num_peers;
106 static struct GNUNET_PeerIdentity zero_pid;
142 107
143 rps_handle = GNUNET_RPS_connect (cfg); 108 rps_handle = GNUNET_RPS_connect (cfg);
144 109
145 if (NULL == peer_id) 110 if (0 == memcmp (&zero_pid,
111 &peer_id,
112 sizeof (peer_id)))
146 { /* Request n PeerIDs */ 113 { /* Request n PeerIDs */
147 /* If number was specified use it, else request single peer. */ 114 /* If number was specified use it, else request single peer. */
148 num_peers = (NULL == args[0]) ? 1 : atoi (args[0]); 115 num_peers = (NULL == args[0]) ? 1 : atoi (args[0]);
@@ -153,8 +120,8 @@ run (void *cls,
153 } 120 }
154 else 121 else
155 { /* Seed PeerID */ 122 { /* Seed PeerID */
156 GNUNET_RPS_seed_ids (rps_handle, 1, peer_id); 123 GNUNET_RPS_seed_ids (rps_handle, 1, &peer_id);
157 FPRINTF (stdout, "Seeded PeerID %s\n", GNUNET_i2s_full (peer_id)); 124 FPRINTF (stdout, "Seeded PeerID %s\n", GNUNET_i2s_full (&peer_id));
158 ret = 0; 125 ret = 0;
159 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); 126 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
160 } 127 }
@@ -172,10 +139,12 @@ main (int argc, char *const *argv)
172{ 139{
173 const char helpstr[] = 140 const char helpstr[] =
174 "Get random GNUnet peers. If none is specified a single is requested."; 141 "Get random GNUnet peers. If none is specified a single is requested.";
175 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 142 struct GNUNET_GETOPT_CommandLineOption options[] = {
176 {'s', "seed", "PEER_ID", 143 GNUNET_GETOPT_OPTION_SET_BASE32_AUTO ('s',
177 gettext_noop ("Seed a PeerID"), 144 "seed",
178 GNUNET_YES, &GNUNET_GETOPT_set_peerid, &peer_id}, 145 "PEER_ID",
146 gettext_noop ("Seed a PeerID"),
147 &peer_id),
179 GNUNET_GETOPT_OPTION_END 148 GNUNET_GETOPT_OPTION_END
180 }; 149 };
181 return (GNUNET_OK == 150 return (GNUNET_OK ==
diff --git a/src/rps/gnunet-service-rps.c b/src/rps/gnunet-service-rps.c
index adcfe7d02..0a4543b30 100644
--- a/src/rps/gnunet-service-rps.c
+++ b/src/rps/gnunet-service-rps.c
@@ -217,6 +217,11 @@ static struct GNUNET_NSE_Handle *nse;
217static struct GNUNET_CADET_Handle *cadet_handle; 217static struct GNUNET_CADET_Handle *cadet_handle;
218 218
219/** 219/**
220 * @brief Port to communicate to other peers.
221 */
222static struct GNUNET_CADET_Port *cadet_port;
223
224/**
220 * Handler to PEERINFO. 225 * Handler to PEERINFO.
221 */ 226 */
222static struct GNUNET_PEERINFO_Handle *peerinfo_handle; 227static struct GNUNET_PEERINFO_Handle *peerinfo_handle;
@@ -838,14 +843,10 @@ clean_peer (const struct GNUNET_PeerIdentity *peer)
838 */ 843 */
839static void 844static void
840cleanup_destroyed_channel (void *cls, 845cleanup_destroyed_channel (void *cls,
841 const struct GNUNET_CADET_Channel *channel, 846 const struct GNUNET_CADET_Channel *channel)
842 void *channel_ctx)
843{ 847{
844 struct GNUNET_PeerIdentity *peer; 848 struct GNUNET_PeerIdentity *peer = cls;
845 849 uint32_t *channel_flag;
846 peer = (struct GNUNET_PeerIdentity *) GNUNET_CADET_channel_get_info (
847 (struct GNUNET_CADET_Channel *) channel, GNUNET_CADET_OPTION_PEER);
848 // FIXME wait for cadet to change this function
849 850
850 if (GNUNET_NO == Peers_check_peer_known (peer)) 851 if (GNUNET_NO == Peers_check_peer_known (peer))
851 { /* We don't know a context to that peer */ 852 { /* We don't know a context to that peer */
@@ -858,7 +859,7 @@ cleanup_destroyed_channel (void *cls,
858 if (GNUNET_YES == Peers_check_peer_flag (peer, Peers_TO_DESTROY)) 859 if (GNUNET_YES == Peers_check_peer_flag (peer, Peers_TO_DESTROY))
859 { /* We are in the middle of removing that peer from our knowledge. In this 860 { /* We are in the middle of removing that peer from our knowledge. In this
860 case simply make sure that the channels are cleaned. */ 861 case simply make sure that the channels are cleaned. */
861 Peers_cleanup_destroyed_channel (cls, channel, channel_ctx); 862 Peers_cleanup_destroyed_channel (cls, channel);
862 to_file (file_name_view_log, 863 to_file (file_name_view_log,
863 "-%s\t(cleanup channel, ourself)", 864 "-%s\t(cleanup channel, ourself)",
864 GNUNET_i2s_full (peer)); 865 GNUNET_i2s_full (peer));
@@ -872,16 +873,17 @@ cleanup_destroyed_channel (void *cls,
872 * - ourselves -> cleaning send channel -> clean context 873 * - ourselves -> cleaning send channel -> clean context
873 * - other peer -> peer probably went down -> remove 874 * - other peer -> peer probably went down -> remove
874 */ 875 */
875 if (GNUNET_YES == Peers_check_channel_flag (channel_ctx, Peers_CHANNEL_CLEAN)) 876 channel_flag = Peers_get_channel_flag (peer, Peers_CHANNEL_ROLE_SENDING);
877 if (GNUNET_YES == Peers_check_channel_flag (channel_flag, Peers_CHANNEL_CLEAN))
876 { /* We are about to clean the sending channel. Clean the respective 878 { /* We are about to clean the sending channel. Clean the respective
877 * context */ 879 * context */
878 Peers_cleanup_destroyed_channel (cls, channel, channel_ctx); 880 Peers_cleanup_destroyed_channel (cls, channel);
879 return; 881 return;
880 } 882 }
881 else 883 else
882 { /* Other peer destroyed our sending channel that he is supposed to keep 884 { /* Other peer destroyed our sending channel that he is supposed to keep
883 * open. It probably went down. Remove it from our knowledge. */ 885 * open. It probably went down. Remove it from our knowledge. */
884 Peers_cleanup_destroyed_channel (cls, channel, channel_ctx); 886 Peers_cleanup_destroyed_channel (cls, channel);
885 remove_peer (peer); 887 remove_peer (peer);
886 return; 888 return;
887 } 889 }
@@ -893,17 +895,18 @@ cleanup_destroyed_channel (void *cls,
893 * - ourselves -> peer tried to establish channel twice -> clean context 895 * - ourselves -> peer tried to establish channel twice -> clean context
894 * - other peer -> peer doesn't want to send us data -> clean 896 * - other peer -> peer doesn't want to send us data -> clean
895 */ 897 */
898 channel_flag = Peers_get_channel_flag (peer, Peers_CHANNEL_ROLE_RECEIVING);
896 if (GNUNET_YES == 899 if (GNUNET_YES ==
897 Peers_check_channel_flag (channel_ctx, Peers_CHANNEL_ESTABLISHED_TWICE)) 900 Peers_check_channel_flag (channel_flag, Peers_CHANNEL_ESTABLISHED_TWICE))
898 { /* Other peer tried to establish a channel to us twice. We do not accept 901 { /* Other peer tried to establish a channel to us twice. We do not accept
899 * that. Clean the context. */ 902 * that. Clean the context. */
900 Peers_cleanup_destroyed_channel (cls, channel, channel_ctx); 903 Peers_cleanup_destroyed_channel (cls, channel);
901 return; 904 return;
902 } 905 }
903 else 906 else
904 { /* Other peer doesn't want to send us data anymore. We are free to clean 907 { /* Other peer doesn't want to send us data anymore. We are free to clean
905 * it. */ 908 * it. */
906 Peers_cleanup_destroyed_channel (cls, channel, channel_ctx); 909 Peers_cleanup_destroyed_channel (cls, channel);
907 clean_peer (peer); 910 clean_peer (peer);
908 return; 911 return;
909 } 912 }
@@ -1023,7 +1026,7 @@ client_respond (void *cls,
1023 size_needed = sizeof (struct GNUNET_RPS_CS_ReplyMessage) + 1026 size_needed = sizeof (struct GNUNET_RPS_CS_ReplyMessage) +
1024 num_peers * sizeof (struct GNUNET_PeerIdentity); 1027 num_peers * sizeof (struct GNUNET_PeerIdentity);
1025 1028
1026 GNUNET_assert (GNUNET_SERVER_MAX_MESSAGE_SIZE >= size_needed); 1029 GNUNET_assert (GNUNET_MAX_MESSAGE_SIZE >= size_needed);
1027 1030
1028 ev = GNUNET_MQ_msg_extra (out_msg, 1031 ev = GNUNET_MQ_msg_extra (out_msg,
1029 num_peers * sizeof (struct GNUNET_PeerIdentity), 1032 num_peers * sizeof (struct GNUNET_PeerIdentity),
@@ -1048,7 +1051,6 @@ client_respond (void *cls,
1048 * Handle RPS request from the client. 1051 * Handle RPS request from the client.
1049 * 1052 *
1050 * @param cls closure 1053 * @param cls closure
1051 * @param client identification of the client
1052 * @param message the actual message 1054 * @param message the actual message
1053 */ 1055 */
1054static void 1056static void
@@ -1065,7 +1067,7 @@ handle_client_request (void *cls,
1065 size_needed = sizeof (struct GNUNET_RPS_CS_RequestMessage) + 1067 size_needed = sizeof (struct GNUNET_RPS_CS_RequestMessage) +
1066 num_peers * sizeof (struct GNUNET_PeerIdentity); 1068 num_peers * sizeof (struct GNUNET_PeerIdentity);
1067 1069
1068 if (GNUNET_SERVER_MAX_MESSAGE_SIZE < size_needed) 1070 if (GNUNET_MAX_MESSAGE_SIZE < size_needed)
1069 { 1071 {
1070 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1072 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1071 "Message received from client has size larger than expected\n"); 1073 "Message received from client has size larger than expected\n");
@@ -1100,12 +1102,11 @@ handle_client_request (void *cls,
1100 * @brief Handle a message that requests the cancellation of a request 1102 * @brief Handle a message that requests the cancellation of a request
1101 * 1103 *
1102 * @param cls unused 1104 * @param cls unused
1103 * @param client the client that requests the cancellation
1104 * @param message the message containing the id of the request 1105 * @param message the message containing the id of the request
1105 */ 1106 */
1106static void 1107static void
1107handle_client_request_cancel (void *cls, 1108handle_client_request_cancel (void *cls,
1108 const struct GNUNET_RPS_CS_RequestCancelMessage *msg) 1109 const struct GNUNET_RPS_CS_RequestCancelMessage *msg)
1109{ 1110{
1110 struct ClientContext *cli_ctx = cls; 1111 struct ClientContext *cli_ctx = cls;
1111 struct ReplyCls *rep_cls; 1112 struct ReplyCls *rep_cls;
@@ -1157,7 +1158,6 @@ check_client_seed (void *cls, const struct GNUNET_RPS_CS_SeedMessage *msg)
1157 * Handle seed from the client. 1158 * Handle seed from the client.
1158 * 1159 *
1159 * @param cls closure 1160 * @param cls closure
1160 * @param client identification of the client
1161 * @param message the actual message 1161 * @param message the actual message
1162 */ 1162 */
1163static void 1163static void
@@ -1172,7 +1172,7 @@ handle_client_seed (void *cls,
1172 num_peers = ntohl (msg->num_peers); 1172 num_peers = ntohl (msg->num_peers);
1173 peers = (struct GNUNET_PeerIdentity *) &msg[1]; 1173 peers = (struct GNUNET_PeerIdentity *) &msg[1];
1174 //peers = GNUNET_new_array (num_peers, struct GNUNET_PeerIdentity); 1174 //peers = GNUNET_new_array (num_peers, struct GNUNET_PeerIdentity);
1175 //GNUNET_memcpy (peers, &in_msg[1], num_peers * sizeof (struct GNUNET_PeerIdentity)); 1175 //GNUNET_memcpy (peers, &msg[1], num_peers * sizeof (struct GNUNET_PeerIdentity));
1176 1176
1177 LOG (GNUNET_ERROR_TYPE_DEBUG, 1177 LOG (GNUNET_ERROR_TYPE_DEBUG,
1178 "Client seeded peers:\n"); 1178 "Client seeded peers:\n");
@@ -1200,18 +1200,15 @@ handle_client_seed (void *cls,
1200 * the channel is blocked for all other communication. 1200 * the channel is blocked for all other communication.
1201 * 1201 *
1202 * @param cls Closure 1202 * @param cls Closure
1203 * @param channel The channel the CHECK was received over
1204 * @param channel_ctx The context associated with this channel
1205 * @param msg The message header 1203 * @param msg The message header
1206 */ 1204 */
1207static int 1205static void
1208handle_peer_check (void *cls, 1206handle_peer_check (void *cls,
1209 struct GNUNET_CADET_Channel *channel, 1207 const struct GNUNET_MessageHeader *msg)
1210 void **channel_ctx,
1211 const struct GNUNET_MessageHeader *msg)
1212{ 1208{
1213 GNUNET_CADET_receive_done (channel); 1209 const struct GNUNET_PeerIdentity *peer = cls;
1214 return GNUNET_OK; 1210
1211 GNUNET_CADET_receive_done (Peers_get_recv_channel (peer));
1215} 1212}
1216 1213
1217/** 1214/**
@@ -1221,24 +1218,16 @@ handle_peer_check (void *cls,
1221 * in the temporary list for pushed PeerIDs. 1218 * in the temporary list for pushed PeerIDs.
1222 * 1219 *
1223 * @param cls Closure 1220 * @param cls Closure
1224 * @param channel The channel the PUSH was received over
1225 * @param channel_ctx The context associated with this channel
1226 * @param msg The message header 1221 * @param msg The message header
1227 */ 1222 */
1228static int 1223static void
1229handle_peer_push (void *cls, 1224handle_peer_push (void *cls,
1230 struct GNUNET_CADET_Channel *channel, 1225 const struct GNUNET_MessageHeader *msg)
1231 void **channel_ctx,
1232 const struct GNUNET_MessageHeader *msg)
1233{ 1226{
1234 const struct GNUNET_PeerIdentity *peer; 1227 const struct GNUNET_PeerIdentity *peer = cls;
1235 1228
1236 // (check the proof of work (?)) 1229 // (check the proof of work (?))
1237 1230
1238 peer = (const struct GNUNET_PeerIdentity *)
1239 GNUNET_CADET_channel_get_info (channel, GNUNET_CADET_OPTION_PEER);
1240 // FIXME wait for cadet to change this function
1241
1242 LOG (GNUNET_ERROR_TYPE_DEBUG, 1231 LOG (GNUNET_ERROR_TYPE_DEBUG,
1243 "Received PUSH (%s)\n", 1232 "Received PUSH (%s)\n",
1244 GNUNET_i2s (peer)); 1233 GNUNET_i2s (peer));
@@ -1261,23 +1250,20 @@ handle_peer_push (void *cls,
1261 tmp_att_peer); 1250 tmp_att_peer);
1262 add_peer_array_to_set (peer, 1, att_peer_set); 1251 add_peer_array_to_set (peer, 1, att_peer_set);
1263 } 1252 }
1264 GNUNET_CADET_receive_done (channel); 1253 GNUNET_CADET_receive_done (Peers_get_recv_channel (peer));
1265 return GNUNET_OK;
1266 } 1254 }
1267 1255
1268 1256
1269 else if (2 == mal_type) 1257 else if (2 == mal_type)
1270 { /* We attack one single well-known peer - simply ignore */ 1258 { /* We attack one single well-known peer - simply ignore */
1271 GNUNET_CADET_receive_done (channel); 1259 GNUNET_CADET_receive_done (Peers_get_recv_channel (peer));
1272 return GNUNET_OK;
1273 } 1260 }
1274 #endif /* ENABLE_MALICIOUS */ 1261 #endif /* ENABLE_MALICIOUS */
1275 1262
1276 /* Add the sending peer to the push_map */ 1263 /* Add the sending peer to the push_map */
1277 CustomPeerMap_put (push_map, peer); 1264 CustomPeerMap_put (push_map, peer);
1278 1265
1279 GNUNET_CADET_receive_done (channel); 1266 GNUNET_CADET_receive_done (Peers_get_recv_channel (peer));
1280 return GNUNET_OK;
1281} 1267}
1282 1268
1283 1269
@@ -1287,24 +1273,15 @@ handle_peer_push (void *cls,
1287 * Reply with the view of PeerIDs. 1273 * Reply with the view of PeerIDs.
1288 * 1274 *
1289 * @param cls Closure 1275 * @param cls Closure
1290 * @param channel The channel the PULL REQUEST was received over
1291 * @param channel_ctx The context associated with this channel
1292 * @param msg The message header 1276 * @param msg The message header
1293 */ 1277 */
1294static int 1278static void
1295handle_peer_pull_request (void *cls, 1279handle_peer_pull_request (void *cls,
1296 struct GNUNET_CADET_Channel *channel, 1280 const struct GNUNET_MessageHeader *msg)
1297 void **channel_ctx,
1298 const struct GNUNET_MessageHeader *msg)
1299{ 1281{
1300 struct GNUNET_PeerIdentity *peer; 1282 struct GNUNET_PeerIdentity *peer = cls;
1301 const struct GNUNET_PeerIdentity *view_array; 1283 const struct GNUNET_PeerIdentity *view_array;
1302 1284
1303 peer = (struct GNUNET_PeerIdentity *)
1304 GNUNET_CADET_channel_get_info (channel,
1305 GNUNET_CADET_OPTION_PEER);
1306 // FIXME wait for cadet to change this function
1307
1308 LOG (GNUNET_ERROR_TYPE_DEBUG, "Received PULL REQUEST (%s)\n", GNUNET_i2s (peer)); 1285 LOG (GNUNET_ERROR_TYPE_DEBUG, "Received PULL REQUEST (%s)\n", GNUNET_i2s (peer));
1309 1286
1310 #ifdef ENABLE_MALICIOUS 1287 #ifdef ENABLE_MALICIOUS
@@ -1312,8 +1289,7 @@ handle_peer_pull_request (void *cls,
1312 || 3 == mal_type) 1289 || 3 == mal_type)
1313 { /* Try to maximise representation */ 1290 { /* Try to maximise representation */
1314 send_pull_reply (peer, mal_peers, num_mal_peers); 1291 send_pull_reply (peer, mal_peers, num_mal_peers);
1315 GNUNET_CADET_receive_done (channel); 1292 GNUNET_CADET_receive_done (Peers_get_recv_channel (peer));
1316 return GNUNET_OK;
1317 } 1293 }
1318 1294
1319 else if (2 == mal_type) 1295 else if (2 == mal_type)
@@ -1322,101 +1298,93 @@ handle_peer_pull_request (void *cls,
1322 { 1298 {
1323 send_pull_reply (peer, mal_peers, num_mal_peers); 1299 send_pull_reply (peer, mal_peers, num_mal_peers);
1324 } 1300 }
1325 GNUNET_CADET_receive_done (channel); 1301 GNUNET_CADET_receive_done (Peers_get_recv_channel (peer));
1326 return GNUNET_OK;
1327 } 1302 }
1328 #endif /* ENABLE_MALICIOUS */ 1303 #endif /* ENABLE_MALICIOUS */
1329 1304
1330 view_array = View_get_as_array (); 1305 view_array = View_get_as_array ();
1331
1332 send_pull_reply (peer, view_array, View_size ()); 1306 send_pull_reply (peer, view_array, View_size ());
1333 1307
1334 GNUNET_CADET_receive_done (channel); 1308 GNUNET_CADET_receive_done (Peers_get_recv_channel (peer));
1335 return GNUNET_OK;
1336} 1309}
1337 1310
1338 1311
1339/** 1312/**
1340 * Handle PULL REPLY message from another peer.
1341 *
1342 * Check whether we sent a corresponding request and 1313 * Check whether we sent a corresponding request and
1343 * whether this reply is the first one. 1314 * whether this reply is the first one.
1344 * 1315 *
1345 * @param cls Closure 1316 * @param cls Closure
1346 * @param channel The channel the PUSH was received over
1347 * @param channel_ctx The context associated with this channel
1348 * @param msg The message header 1317 * @param msg The message header
1349 */ 1318 */
1350static int 1319static int
1351handle_peer_pull_reply (void *cls, 1320check_peer_pull_reply (void *cls,
1352 struct GNUNET_CADET_Channel *channel, 1321 const struct GNUNET_RPS_P2P_PullReplyMessage *msg)
1353 void **channel_ctx,
1354 const struct GNUNET_MessageHeader *msg)
1355{ 1322{
1356 struct GNUNET_RPS_P2P_PullReplyMessage *in_msg; 1323 struct GNUNET_PeerIdentity *sender = cls;
1357 struct GNUNET_PeerIdentity *peers;
1358 struct GNUNET_PeerIdentity *sender;
1359 uint32_t i;
1360#ifdef ENABLE_MALICIOUS
1361 struct AttackedPeer *tmp_att_peer;
1362#endif /* ENABLE_MALICIOUS */
1363 1324
1364 /* Check for protocol violation */ 1325 if (sizeof (struct GNUNET_RPS_P2P_PullReplyMessage) > ntohs (msg->header.size))
1365 if (sizeof (struct GNUNET_RPS_P2P_PullReplyMessage) > ntohs (msg->size))
1366 { 1326 {
1367 GNUNET_break_op (0); 1327 GNUNET_break_op (0);
1368 GNUNET_CADET_receive_done (channel);
1369 return GNUNET_SYSERR; 1328 return GNUNET_SYSERR;
1370 } 1329 }
1371 1330
1372 in_msg = (struct GNUNET_RPS_P2P_PullReplyMessage *) msg; 1331 if ((ntohs (msg->header.size) - sizeof (struct GNUNET_RPS_P2P_PullReplyMessage)) /
1373 if ((ntohs (msg->size) - sizeof (struct GNUNET_RPS_P2P_PullReplyMessage)) / 1332 sizeof (struct GNUNET_PeerIdentity) != ntohl (msg->num_peers))
1374 sizeof (struct GNUNET_PeerIdentity) != ntohl (in_msg->num_peers))
1375 { 1333 {
1376 LOG (GNUNET_ERROR_TYPE_ERROR, 1334 LOG (GNUNET_ERROR_TYPE_ERROR,
1377 "message says it sends %" PRIu32 " peers, have space for %lu peers\n", 1335 "message says it sends %" PRIu32 " peers, have space for %lu peers\n",
1378 ntohl (in_msg->num_peers), 1336 ntohl (msg->num_peers),
1379 (ntohs (msg->size) - sizeof (struct GNUNET_RPS_P2P_PullReplyMessage)) / 1337 (ntohs (msg->header.size) - sizeof (struct GNUNET_RPS_P2P_PullReplyMessage)) /
1380 sizeof (struct GNUNET_PeerIdentity)); 1338 sizeof (struct GNUNET_PeerIdentity));
1381 GNUNET_break_op (0); 1339 GNUNET_break_op (0);
1382 GNUNET_CADET_receive_done (channel);
1383 return GNUNET_SYSERR; 1340 return GNUNET_SYSERR;
1384 } 1341 }
1385 1342
1386 // Guess simply casting isn't the nicest way...
1387 // FIXME wait for cadet to change this function
1388 sender = (struct GNUNET_PeerIdentity *)
1389 GNUNET_CADET_channel_get_info (channel, GNUNET_CADET_OPTION_PEER);
1390
1391 LOG (GNUNET_ERROR_TYPE_DEBUG, "Received PULL REPLY (%s)\n", GNUNET_i2s (sender));
1392
1393 if (GNUNET_YES != Peers_check_peer_flag (sender, Peers_PULL_REPLY_PENDING)) 1343 if (GNUNET_YES != Peers_check_peer_flag (sender, Peers_PULL_REPLY_PENDING))
1394 { 1344 {
1395 LOG (GNUNET_ERROR_TYPE_WARNING, 1345 LOG (GNUNET_ERROR_TYPE_WARNING,
1396 "Received a pull reply from a peer we didn't request one from!\n"); 1346 "Received a pull reply from a peer we didn't request one from!\n");
1397 GNUNET_CADET_receive_done (channel);
1398 GNUNET_break_op (0); 1347 GNUNET_break_op (0);
1399 return GNUNET_OK; 1348 return GNUNET_SYSERR;
1400 } 1349 }
1350 return GNUNET_OK;
1351}
1352
1353/**
1354 * Handle PULL REPLY message from another peer.
1355 *
1356 * @param cls Closure
1357 * @param msg The message header
1358 */
1359static void
1360handle_peer_pull_reply (void *cls,
1361 const struct GNUNET_RPS_P2P_PullReplyMessage *msg)
1362{
1363 struct GNUNET_PeerIdentity *peers;
1364 struct GNUNET_PeerIdentity *sender = cls;
1365 uint32_t i;
1366#ifdef ENABLE_MALICIOUS
1367 struct AttackedPeer *tmp_att_peer;
1368#endif /* ENABLE_MALICIOUS */
1401 1369
1370 LOG (GNUNET_ERROR_TYPE_DEBUG, "Received PULL REPLY (%s)\n", GNUNET_i2s (sender));
1402 1371
1403 #ifdef ENABLE_MALICIOUS 1372 #ifdef ENABLE_MALICIOUS
1404 // We shouldn't even receive pull replies as we're not sending 1373 // We shouldn't even receive pull replies as we're not sending
1405 if (2 == mal_type) 1374 if (2 == mal_type)
1406 { 1375 {
1407 GNUNET_CADET_receive_done (channel); 1376 GNUNET_CADET_receive_done (Peers_get_recv_channel (sender));
1408 return GNUNET_OK;
1409 } 1377 }
1410 #endif /* ENABLE_MALICIOUS */ 1378 #endif /* ENABLE_MALICIOUS */
1411 1379
1412 /* Do actual logic */ 1380 /* Do actual logic */
1413 peers = (struct GNUNET_PeerIdentity *) &in_msg[1]; 1381 peers = (struct GNUNET_PeerIdentity *) &msg[1];
1414 1382
1415 LOG (GNUNET_ERROR_TYPE_DEBUG, 1383 LOG (GNUNET_ERROR_TYPE_DEBUG,
1416 "PULL REPLY received, got following %u peers:\n", 1384 "PULL REPLY received, got following %u peers:\n",
1417 ntohl (in_msg->num_peers)); 1385 ntohl (msg->num_peers));
1418 1386
1419 for (i = 0 ; i < ntohl (in_msg->num_peers) ; i++) 1387 for (i = 0; i < ntohl (msg->num_peers); i++)
1420 { 1388 {
1421 LOG (GNUNET_ERROR_TYPE_DEBUG, 1389 LOG (GNUNET_ERROR_TYPE_DEBUG,
1422 "%u. %s\n", 1390 "%u. %s\n",
@@ -1466,8 +1434,7 @@ handle_peer_pull_reply (void *cls,
1466 Peers_unset_peer_flag (sender, Peers_PULL_REPLY_PENDING); 1434 Peers_unset_peer_flag (sender, Peers_PULL_REPLY_PENDING);
1467 clean_peer (sender); 1435 clean_peer (sender);
1468 1436
1469 GNUNET_CADET_receive_done (channel); 1437 GNUNET_CADET_receive_done (Peers_get_recv_channel (sender));
1470 return GNUNET_OK;
1471} 1438}
1472 1439
1473 1440
@@ -2273,15 +2240,24 @@ run (void *cls,
2273 const struct GNUNET_CONFIGURATION_Handle *c, 2240 const struct GNUNET_CONFIGURATION_Handle *c,
2274 struct GNUNET_SERVICE_Handle *service) 2241 struct GNUNET_SERVICE_Handle *service)
2275{ 2242{
2276 static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = { 2243 struct GNUNET_MQ_MessageHandler cadet_handlers[] = {
2277 {&handle_peer_check , GNUNET_MESSAGE_TYPE_RPS_PP_CHECK_LIVE, 2244 GNUNET_MQ_hd_fixed_size (peer_check,
2278 sizeof (struct GNUNET_MessageHeader)}, 2245 GNUNET_MESSAGE_TYPE_RPS_PP_CHECK_LIVE,
2279 {&handle_peer_push , GNUNET_MESSAGE_TYPE_RPS_PP_PUSH, 2246 struct GNUNET_MessageHeader,
2280 sizeof (struct GNUNET_MessageHeader)}, 2247 NULL),
2281 {&handle_peer_pull_request, GNUNET_MESSAGE_TYPE_RPS_PP_PULL_REQUEST, 2248 GNUNET_MQ_hd_fixed_size (peer_push,
2282 sizeof (struct GNUNET_MessageHeader)}, 2249 GNUNET_MESSAGE_TYPE_RPS_PP_PUSH,
2283 {&handle_peer_pull_reply , GNUNET_MESSAGE_TYPE_RPS_PP_PULL_REPLY, 0}, 2250 struct GNUNET_MessageHeader,
2284 {NULL, 0, 0} 2251 NULL),
2252 GNUNET_MQ_hd_fixed_size (peer_pull_request,
2253 GNUNET_MESSAGE_TYPE_RPS_PP_PULL_REQUEST,
2254 struct GNUNET_MessageHeader,
2255 NULL),
2256 GNUNET_MQ_hd_var_size (peer_pull_reply,
2257 GNUNET_MESSAGE_TYPE_RPS_PP_PULL_REPLY,
2258 struct GNUNET_RPS_P2P_PullReplyMessage,
2259 NULL),
2260 GNUNET_MQ_handler_end ()
2285 }; 2261 };
2286 2262
2287 int size; 2263 int size;
@@ -2373,21 +2349,23 @@ run (void *cls,
2373 2349
2374 2350
2375 /* Initialise cadet */ 2351 /* Initialise cadet */
2376 cadet_handle = GNUNET_CADET_connect (cfg, 2352 cadet_handle = GNUNET_CADET_connect (cfg);
2377 cls,
2378 &cleanup_destroyed_channel,
2379 cadet_handlers);
2380 GNUNET_assert (NULL != cadet_handle); 2353 GNUNET_assert (NULL != cadet_handle);
2381 GNUNET_CRYPTO_hash (GNUNET_APPLICATION_PORT_RPS, 2354 GNUNET_CRYPTO_hash (GNUNET_APPLICATION_PORT_RPS,
2382 strlen (GNUNET_APPLICATION_PORT_RPS), 2355 strlen (GNUNET_APPLICATION_PORT_RPS),
2383 &port); 2356 &port);
2384 GNUNET_CADET_open_port (cadet_handle, 2357 cadet_port = GNUNET_CADET_open_port (cadet_handle,
2385 &port, 2358 &port,
2386 &Peers_handle_inbound_channel, cls); 2359 &Peers_handle_inbound_channel, /* Connect handler */
2360 NULL, /* cls */
2361 NULL, /* WindowSize handler */
2362 cleanup_destroyed_channel, /* Disconnect handler */
2363 cadet_handlers);
2387 2364
2388 2365
2389 peerinfo_handle = GNUNET_PEERINFO_connect (cfg); 2366 peerinfo_handle = GNUNET_PEERINFO_connect (cfg);
2390 Peers_initialise (fn_valid_peers, cadet_handle, &own_identity); 2367 Peers_initialise (fn_valid_peers, cadet_handle, cleanup_destroyed_channel,
2368 cadet_handlers, &own_identity);
2391 GNUNET_free (fn_valid_peers); 2369 GNUNET_free (fn_valid_peers);
2392 2370
2393 /* Initialise sampler */ 2371 /* Initialise sampler */
diff --git a/src/rps/gnunet-service-rps_peers.c b/src/rps/gnunet-service-rps_peers.c
index e0b278bd0..58aa84ccf 100644
--- a/src/rps/gnunet-service-rps_peers.c
+++ b/src/rps/gnunet-service-rps_peers.c
@@ -251,6 +251,17 @@ static const struct GNUNET_PeerIdentity *own_identity;
251 */ 251 */
252static struct GNUNET_CADET_Handle *cadet_handle; 252static struct GNUNET_CADET_Handle *cadet_handle;
253 253
254/**
255 * @brief Disconnect handler
256 */
257static GNUNET_CADET_DisconnectEventHandler cleanup_destroyed_channel;
258
259/**
260 * @brief cadet handlers
261 */
262static const struct GNUNET_MQ_MessageHandler *cadet_handlers;
263
264
254 265
255/** 266/**
256 * @brief Get the #PeerContext associated with a peer 267 * @brief Get the #PeerContext associated with a peer
@@ -523,10 +534,13 @@ get_channel (const struct GNUNET_PeerIdentity *peer)
523 &port); 534 &port);
524 peer_ctx->send_channel = 535 peer_ctx->send_channel =
525 GNUNET_CADET_channel_create (cadet_handle, 536 GNUNET_CADET_channel_create (cadet_handle,
526 peer_ctx->send_channel_flags, /* context */ 537 (struct GNUNET_PeerIdentity *) peer, /* context */
527 peer, 538 peer,
528 &port, 539 &port,
529 GNUNET_CADET_OPTION_RELIABLE); 540 GNUNET_CADET_OPTION_RELIABLE,
541 NULL, /* WindowSize handler */
542 cleanup_destroyed_channel, /* Disconnect handler */
543 cadet_handlers);
530 } 544 }
531 GNUNET_assert (NULL != peer_ctx->send_channel); 545 GNUNET_assert (NULL != peer_ctx->send_channel);
532 return peer_ctx->send_channel; 546 return peer_ctx->send_channel;
@@ -552,7 +566,7 @@ get_mq (const struct GNUNET_PeerIdentity *peer)
552 if (NULL == peer_ctx->mq) 566 if (NULL == peer_ctx->mq)
553 { 567 {
554 (void) get_channel (peer); 568 (void) get_channel (peer);
555 peer_ctx->mq = GNUNET_CADET_mq_create (peer_ctx->send_channel); 569 peer_ctx->mq = GNUNET_CADET_get_mq (peer_ctx->send_channel);
556 } 570 }
557 return peer_ctx->mq; 571 return peer_ctx->mq;
558} 572}
@@ -649,9 +663,7 @@ remove_pending_message (struct PendingMessage *pending_msg)
649 GNUNET_CONTAINER_DLL_remove (peer_ctx->pending_messages_head, 663 GNUNET_CONTAINER_DLL_remove (peer_ctx->pending_messages_head,
650 peer_ctx->pending_messages_tail, 664 peer_ctx->pending_messages_tail,
651 pending_msg); 665 pending_msg);
652 /* FIXME We are not able to cancel messages as #GNUNET_CADET_mq_create () does 666 GNUNET_MQ_send_cancel (peer_ctx->pending_messages_head->ev);
653 * not set a #GNUNET_MQ_CancelImpl */
654 /* GNUNET_MQ_send_cancel (peer_ctx->pending_messages_head->ev); */
655 GNUNET_free (pending_msg); 667 GNUNET_free (pending_msg);
656} 668}
657 669
@@ -932,15 +944,21 @@ restore_valid_peers ()
932 * 944 *
933 * @param fn_valid_peers filename of the file used to store valid peer ids 945 * @param fn_valid_peers filename of the file used to store valid peer ids
934 * @param cadet_h cadet handle 946 * @param cadet_h cadet handle
947 * @param disconnect_handler Disconnect handler
948 * @param c_handlers cadet handlers
935 * @param own_id own peer identity 949 * @param own_id own peer identity
936 */ 950 */
937void 951void
938Peers_initialise (char* fn_valid_peers, 952Peers_initialise (char* fn_valid_peers,
939 struct GNUNET_CADET_Handle *cadet_h, 953 struct GNUNET_CADET_Handle *cadet_h,
954 GNUNET_CADET_DisconnectEventHandler disconnect_handler,
955 const struct GNUNET_MQ_MessageHandler *c_handlers,
940 const struct GNUNET_PeerIdentity *own_id) 956 const struct GNUNET_PeerIdentity *own_id)
941{ 957{
942 filename_valid_peers = GNUNET_strdup (fn_valid_peers); 958 filename_valid_peers = GNUNET_strdup (fn_valid_peers);
943 cadet_handle = cadet_h; 959 cadet_handle = cadet_h;
960 cleanup_destroyed_channel = disconnect_handler;
961 cadet_handlers = c_handlers;
944 own_identity = own_id; 962 own_identity = own_id;
945 peer_map = GNUNET_CONTAINER_multipeermap_create (4, GNUNET_NO); 963 peer_map = GNUNET_CONTAINER_multipeermap_create (4, GNUNET_NO);
946 valid_peers = GNUNET_CONTAINER_multipeermap_create (4, GNUNET_NO); 964 valid_peers = GNUNET_CONTAINER_multipeermap_create (4, GNUNET_NO);
@@ -1279,6 +1297,34 @@ Peers_check_channel_flag (uint32_t *channel_flags, enum Peers_ChannelFlags flags
1279 return check_channel_flag_set (channel_flags, flags); 1297 return check_channel_flag_set (channel_flags, flags);
1280} 1298}
1281 1299
1300/**
1301 * @brief Get the flags for the channel in @a role for @a peer.
1302 *
1303 * @param peer Peer to get the channel flags for.
1304 * @param role Role of channel to get flags for
1305 *
1306 * @return The flags.
1307 */
1308uint32_t *
1309Peers_get_channel_flag (const struct GNUNET_PeerIdentity *peer,
1310 enum Peers_ChannelRole role)
1311{
1312 const struct PeerContext *peer_ctx;
1313
1314 peer_ctx = get_peer_ctx (peer);
1315 if (Peers_CHANNEL_ROLE_SENDING == role)
1316 {
1317 return peer_ctx->send_channel_flags;
1318 }
1319 else if (Peers_CHANNEL_ROLE_RECEIVING == role)
1320 {
1321 return peer_ctx->recv_channel_flags;
1322 }
1323 else
1324 {
1325 GNUNET_assert (0);
1326 }
1327}
1282 1328
1283/** 1329/**
1284 * @brief Check whether we have information about the given peer. 1330 * @brief Check whether we have information about the given peer.
@@ -1358,8 +1404,6 @@ Peers_check_peer_send_intention (const struct GNUNET_PeerIdentity *peer)
1358 * @param cls The closure 1404 * @param cls The closure
1359 * @param channel The channel the peer wants to establish 1405 * @param channel The channel the peer wants to establish
1360 * @param initiator The peer's peer ID 1406 * @param initiator The peer's peer ID
1361 * @param port The port the channel is being established over
1362 * @param options Further options
1363 * 1407 *
1364 * @return initial channel context for the channel 1408 * @return initial channel context for the channel
1365 * (can be NULL -- that's not an error) 1409 * (can be NULL -- that's not an error)
@@ -1367,9 +1411,7 @@ Peers_check_peer_send_intention (const struct GNUNET_PeerIdentity *peer)
1367void * 1411void *
1368Peers_handle_inbound_channel (void *cls, 1412Peers_handle_inbound_channel (void *cls,
1369 struct GNUNET_CADET_Channel *channel, 1413 struct GNUNET_CADET_Channel *channel,
1370 const struct GNUNET_PeerIdentity *initiator, 1414 const struct GNUNET_PeerIdentity *initiator)
1371 const struct GNUNET_HashCode *port,
1372 enum GNUNET_CADET_ChannelOption options)
1373{ 1415{
1374 struct PeerContext *peer_ctx; 1416 struct PeerContext *peer_ctx;
1375 1417
@@ -1387,10 +1429,10 @@ Peers_handle_inbound_channel (void *cls,
1387 Peers_CHANNEL_ESTABLISHED_TWICE); 1429 Peers_CHANNEL_ESTABLISHED_TWICE);
1388 GNUNET_CADET_channel_destroy (channel); 1430 GNUNET_CADET_channel_destroy (channel);
1389 /* return the channel context */ 1431 /* return the channel context */
1390 return peer_ctx->recv_channel_flags; 1432 return &peer_ctx->peer_id;
1391 } 1433 }
1392 peer_ctx->recv_channel = channel; 1434 peer_ctx->recv_channel = channel;
1393 return peer_ctx->recv_channel_flags; 1435 return &peer_ctx->peer_id;
1394} 1436}
1395 1437
1396 1438
@@ -1500,16 +1542,11 @@ Peers_destroy_sending_channel (const struct GNUNET_PeerIdentity *peer)
1500 */ 1542 */
1501void 1543void
1502Peers_cleanup_destroyed_channel (void *cls, 1544Peers_cleanup_destroyed_channel (void *cls,
1503 const struct GNUNET_CADET_Channel *channel, 1545 const struct GNUNET_CADET_Channel *channel)
1504 void *channel_ctx)
1505{ 1546{
1506 struct GNUNET_PeerIdentity *peer; 1547 struct GNUNET_PeerIdentity *peer = cls;
1507 struct PeerContext *peer_ctx; 1548 struct PeerContext *peer_ctx;
1508 1549
1509 peer = (struct GNUNET_PeerIdentity *) GNUNET_CADET_channel_get_info (
1510 (struct GNUNET_CADET_Channel *) channel, GNUNET_CADET_OPTION_PEER);
1511 // FIXME wait for cadet to change this function
1512
1513 if (GNUNET_NO == Peers_check_peer_known (peer)) 1550 if (GNUNET_NO == Peers_check_peer_known (peer))
1514 {/* We don't want to implicitly create a context that we're about to kill */ 1551 {/* We don't want to implicitly create a context that we're about to kill */
1515 LOG (GNUNET_ERROR_TYPE_DEBUG, 1552 LOG (GNUNET_ERROR_TYPE_DEBUG,
@@ -1635,4 +1672,23 @@ Peers_schedule_operation (const struct GNUNET_PeerIdentity *peer,
1635 return GNUNET_NO; 1672 return GNUNET_NO;
1636} 1673}
1637 1674
1675/**
1676 * @brief Get the recv_channel of @a peer.
1677 * Needed to correctly handle (call #GNUNET_CADET_receive_done()) incoming
1678 * messages.
1679 *
1680 * @param peer The peer to get the recv_channel from.
1681 *
1682 * @return The recv_channel.
1683 */
1684struct GNUNET_CADET_Channel *
1685Peers_get_recv_channel (const struct GNUNET_PeerIdentity *peer)
1686{
1687 struct PeerContext *peer_ctx;
1688
1689 GNUNET_assert (GNUNET_YES == Peers_check_peer_known (peer));
1690 peer_ctx = get_peer_ctx (peer);
1691 return peer_ctx->recv_channel;
1692}
1693
1638/* end of gnunet-service-rps_peers.c */ 1694/* end of gnunet-service-rps_peers.c */
diff --git a/src/rps/gnunet-service-rps_peers.h b/src/rps/gnunet-service-rps_peers.h
index bbac86003..15970a7ce 100644
--- a/src/rps/gnunet-service-rps_peers.h
+++ b/src/rps/gnunet-service-rps_peers.h
@@ -117,11 +117,15 @@ typedef int
117 * 117 *
118 * @param fn_valid_peers filename of the file used to store valid peer ids 118 * @param fn_valid_peers filename of the file used to store valid peer ids
119 * @param cadet_h cadet handle 119 * @param cadet_h cadet handle
120 * @param disconnect_handler Disconnect handler
121 * @param c_handlers cadet handlers
120 * @param own_id own peer identity 122 * @param own_id own peer identity
121 */ 123 */
122void 124void
123Peers_initialise (char* fn_valid_peers, 125Peers_initialise (char* fn_valid_peers,
124 struct GNUNET_CADET_Handle *cadet_h, 126 struct GNUNET_CADET_Handle *cadet_h,
127 GNUNET_CADET_DisconnectEventHandler disconnect_handler,
128 const struct GNUNET_MQ_MessageHandler *c_handlers,
125 const struct GNUNET_PeerIdentity *own_id); 129 const struct GNUNET_PeerIdentity *own_id);
126 130
127/** 131/**
@@ -259,6 +263,18 @@ int
259Peers_check_channel_flag (uint32_t *channel_flags, enum Peers_ChannelFlags flags); 263Peers_check_channel_flag (uint32_t *channel_flags, enum Peers_ChannelFlags flags);
260 264
261/** 265/**
266 * @brief Get the flags for the channel in @a role for @a peer.
267 *
268 * @param peer Peer to get the channel flags for.
269 * @param role Role of channel to get flags for
270 *
271 * @return The flags.
272 */
273uint32_t *
274Peers_get_channel_flag (const struct GNUNET_PeerIdentity *peer,
275 enum Peers_ChannelRole role);
276
277/**
262 * @brief Check whether we have information about the given peer. 278 * @brief Check whether we have information about the given peer.
263 * 279 *
264 * FIXME probably deprecated. Make this the new _online. 280 * FIXME probably deprecated. Make this the new _online.
@@ -312,8 +328,6 @@ Peers_check_peer_send_intention (const struct GNUNET_PeerIdentity *peer);
312 * @param cls The closure 328 * @param cls The closure
313 * @param channel The channel the peer wants to establish 329 * @param channel The channel the peer wants to establish
314 * @param initiator The peer's peer ID 330 * @param initiator The peer's peer ID
315 * @param port The port the channel is being established over
316 * @param options Further options
317 * 331 *
318 * @return initial channel context for the channel 332 * @return initial channel context for the channel
319 * (can be NULL -- that's not an error) 333 * (can be NULL -- that's not an error)
@@ -321,9 +335,7 @@ Peers_check_peer_send_intention (const struct GNUNET_PeerIdentity *peer);
321void * 335void *
322Peers_handle_inbound_channel (void *cls, 336Peers_handle_inbound_channel (void *cls,
323 struct GNUNET_CADET_Channel *channel, 337 struct GNUNET_CADET_Channel *channel,
324 const struct GNUNET_PeerIdentity *initiator, 338 const struct GNUNET_PeerIdentity *initiator);
325 const struct GNUNET_HashCode *port,
326 enum GNUNET_CADET_ChannelOption options);
327 339
328/** 340/**
329 * @brief Check whether a sending channel towards the given peer exists 341 * @brief Check whether a sending channel towards the given peer exists
@@ -379,8 +391,7 @@ Peers_destroy_sending_channel (const struct GNUNET_PeerIdentity *peer);
379 */ 391 */
380void 392void
381Peers_cleanup_destroyed_channel (void *cls, 393Peers_cleanup_destroyed_channel (void *cls,
382 const struct GNUNET_CADET_Channel *channel, 394 const struct GNUNET_CADET_Channel *channel);
383 void *channel_ctx);
384 395
385/** 396/**
386 * @brief Send a message to another peer. 397 * @brief Send a message to another peer.
@@ -411,4 +422,16 @@ int
411Peers_schedule_operation (const struct GNUNET_PeerIdentity *peer, 422Peers_schedule_operation (const struct GNUNET_PeerIdentity *peer,
412 const PeerOp peer_op); 423 const PeerOp peer_op);
413 424
425/**
426 * @brief Get the recv_channel of @a peer.
427 * Needed to correctly handle (call #GNUNET_CADET_receive_done()) incoming
428 * messages.
429 *
430 * @param peer The peer to get the recv_channel from.
431 *
432 * @return The recv_channel.
433 */
434struct GNUNET_CADET_Channel *
435Peers_get_recv_channel (const struct GNUNET_PeerIdentity *peer);
436
414/* end of gnunet-service-rps_peers.h */ 437/* end of gnunet-service-rps_peers.h */
diff --git a/src/rps/rps_api.c b/src/rps/rps_api.c
index 504f28b92..ccd480086 100644
--- a/src/rps/rps_api.c
+++ b/src/rps/rps_api.c
@@ -389,12 +389,12 @@ GNUNET_RPS_seed_ids (struct GNUNET_RPS_Handle *h,
389 n * sizeof (struct GNUNET_PeerIdentity); 389 n * sizeof (struct GNUNET_PeerIdentity);
390 /* The number of peers that fits in one message together with 390 /* The number of peers that fits in one message together with
391 * the respective header */ 391 * the respective header */
392 num_peers_max = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 392 num_peers_max = (GNUNET_MAX_MESSAGE_SIZE -
393 sizeof (struct GNUNET_RPS_CS_SeedMessage)) / 393 sizeof (struct GNUNET_RPS_CS_SeedMessage)) /
394 sizeof (struct GNUNET_PeerIdentity); 394 sizeof (struct GNUNET_PeerIdentity);
395 tmp_peer_pointer = ids; 395 tmp_peer_pointer = ids;
396 396
397 while (GNUNET_SERVER_MAX_MESSAGE_SIZE < size_needed) 397 while (GNUNET_MAX_MESSAGE_SIZE < size_needed)
398 { 398 {
399 ev = GNUNET_MQ_msg_extra (msg, num_peers_max * sizeof (struct GNUNET_PeerIdentity), 399 ev = GNUNET_MQ_msg_extra (msg, num_peers_max * sizeof (struct GNUNET_PeerIdentity),
400 GNUNET_MESSAGE_TYPE_RPS_CS_SEED); 400 GNUNET_MESSAGE_TYPE_RPS_CS_SEED);
@@ -463,12 +463,12 @@ GNUNET_RPS_act_malicious (struct GNUNET_RPS_Handle *h,
463 num_peers * sizeof (struct GNUNET_PeerIdentity); 463 num_peers * sizeof (struct GNUNET_PeerIdentity);
464 /* The number of peers that fit in one message together with 464 /* The number of peers that fit in one message together with
465 * the respective header */ 465 * the respective header */
466 num_peers_max = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 466 num_peers_max = (GNUNET_MAX_MESSAGE_SIZE -
467 sizeof (struct GNUNET_RPS_CS_SeedMessage)) / 467 sizeof (struct GNUNET_RPS_CS_SeedMessage)) /
468 sizeof (struct GNUNET_PeerIdentity); 468 sizeof (struct GNUNET_PeerIdentity);
469 tmp_peer_pointer = peer_ids; 469 tmp_peer_pointer = peer_ids;
470 470
471 while (GNUNET_SERVER_MAX_MESSAGE_SIZE < size_needed) 471 while (GNUNET_MAX_MESSAGE_SIZE < size_needed)
472 { 472 {
473 LOG (GNUNET_ERROR_TYPE_DEBUG, 473 LOG (GNUNET_ERROR_TYPE_DEBUG,
474 "Too many peers to send at once, sending %" PRIu32 " (all we can so far)\n", 474 "Too many peers to send at once, sending %" PRIu32 " (all we can so far)\n",
diff --git a/src/rps/test_rps.c b/src/rps/test_rps.c
index 1ce174454..acd3a165d 100644
--- a/src/rps/test_rps.c
+++ b/src/rps/test_rps.c
@@ -546,7 +546,7 @@ seed_peers_big (void *cls)
546 unsigned int i; 546 unsigned int i;
547 547
548 seed_msg_size = 8; /* sizeof (struct GNUNET_RPS_CS_SeedMessage) */ 548 seed_msg_size = 8; /* sizeof (struct GNUNET_RPS_CS_SeedMessage) */
549 num_peers_max = (GNUNET_SERVER_MAX_MESSAGE_SIZE - seed_msg_size) / 549 num_peers_max = (GNUNET_MAX_MESSAGE_SIZE - seed_msg_size) /
550 sizeof (struct GNUNET_PeerIdentity); 550 sizeof (struct GNUNET_PeerIdentity);
551 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 551 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
552 "Peers that fit in one seed msg; %u\n", 552 "Peers that fit in one seed msg; %u\n",
@@ -980,7 +980,7 @@ seed_cb (struct RPSPeer *rps_peer)
980static void 980static void
981seed_big_cb (struct RPSPeer *rps_peer) 981seed_big_cb (struct RPSPeer *rps_peer)
982{ 982{
983 // TODO test seeding > GNUNET_SERVER_MAX_MESSAGE_SIZE peers 983 // TODO test seeding > GNUNET_MAX_MESSAGE_SIZE peers
984 GNUNET_SCHEDULER_add_delayed ( 984 GNUNET_SCHEDULER_add_delayed (
985 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2), 985 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2),
986 seed_peers_big, rps_peer); 986 seed_peers_big, rps_peer);
@@ -1457,7 +1457,7 @@ main (int argc, char *argv[])
1457 1457
1458 else if (strstr (argv[0], "_seed_big") != NULL) 1458 else if (strstr (argv[0], "_seed_big") != NULL)
1459 { 1459 {
1460 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test seeding (num_peers > GNUNET_SERVER_MAX_MESSAGE_SIZE)\n"); 1460 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test seeding (num_peers > GNUNET_MAX_MESSAGE_SIZE)\n");
1461 num_peers = 1; 1461 num_peers = 1;
1462 cur_test_run.name = "test-rps-seed-big"; 1462 cur_test_run.name = "test-rps-seed-big";
1463 cur_test_run.main_test = seed_big_cb; 1463 cur_test_run.main_test = seed_big_cb;
diff --git a/src/rps/test_service_rps_peers.c b/src/rps/test_service_rps_peers.c
index 37ed1974c..9cd677fef 100644
--- a/src/rps/test_service_rps_peers.c
+++ b/src/rps/test_service_rps_peers.c
@@ -59,25 +59,25 @@ check ()
59 memset (&own_id, 1, sizeof (own_id)); 59 memset (&own_id, 1, sizeof (own_id));
60 60
61 /* Do nothing */ 61 /* Do nothing */
62 Peers_initialise (FN_VALID_PEERS, NULL, &own_id); 62 Peers_initialise (FN_VALID_PEERS, NULL, NULL, NULL, &own_id);
63 Peers_terminate (); 63 Peers_terminate ();
64 64
65 65
66 /* Create peer */ 66 /* Create peer */
67 Peers_initialise (FN_VALID_PEERS, NULL, &own_id); 67 Peers_initialise (FN_VALID_PEERS, NULL, NULL, NULL, &own_id);
68 CHECK (GNUNET_YES == Peers_insert_peer (&k1)); 68 CHECK (GNUNET_YES == Peers_insert_peer (&k1));
69 Peers_terminate (); 69 Peers_terminate ();
70 70
71 71
72 /* Create peer */ 72 /* Create peer */
73 Peers_initialise (FN_VALID_PEERS, NULL, &own_id); 73 Peers_initialise (FN_VALID_PEERS, NULL, NULL, NULL, &own_id);
74 CHECK (GNUNET_YES == Peers_insert_peer (&k1)); 74 CHECK (GNUNET_YES == Peers_insert_peer (&k1));
75 CHECK (GNUNET_YES == Peers_remove_peer (&k1)); 75 CHECK (GNUNET_YES == Peers_remove_peer (&k1));
76 Peers_terminate (); 76 Peers_terminate ();
77 77
78 78
79 /* Insertion and Removal */ 79 /* Insertion and Removal */
80 Peers_initialise (FN_VALID_PEERS, NULL, &own_id); 80 Peers_initialise (FN_VALID_PEERS, NULL, NULL, NULL, &own_id);
81 CHECK (GNUNET_NO == Peers_check_peer_known (&k1)); 81 CHECK (GNUNET_NO == Peers_check_peer_known (&k1));
82 82
83 CHECK (GNUNET_YES == Peers_insert_peer (&k1)); 83 CHECK (GNUNET_YES == Peers_insert_peer (&k1));
diff --git a/src/scalarproduct/Makefile.am b/src/scalarproduct/Makefile.am
index 98829408a..10e04284f 100644
--- a/src/scalarproduct/Makefile.am
+++ b/src/scalarproduct/Makefile.am
@@ -42,7 +42,7 @@ gnunet_service_scalarproduct_alice_SOURCES = \
42 gnunet-service-scalarproduct_alice.c 42 gnunet-service-scalarproduct_alice.c
43gnunet_service_scalarproduct_alice_LDADD = \ 43gnunet_service_scalarproduct_alice_LDADD = \
44 $(top_builddir)/src/util/libgnunetutil.la \ 44 $(top_builddir)/src/util/libgnunetutil.la \
45 $(top_builddir)/src/cadet/libgnunetcadetnew.la \ 45 $(top_builddir)/src/cadet/libgnunetcadet.la \
46 $(top_builddir)/src/set/libgnunetset.la \ 46 $(top_builddir)/src/set/libgnunetset.la \
47 $(LIBGCRYPT_LIBS) \ 47 $(LIBGCRYPT_LIBS) \
48 -lgcrypt \ 48 -lgcrypt \
@@ -53,7 +53,7 @@ gnunet_service_scalarproduct_bob_SOURCES = \
53 gnunet-service-scalarproduct_bob.c 53 gnunet-service-scalarproduct_bob.c
54gnunet_service_scalarproduct_bob_LDADD = \ 54gnunet_service_scalarproduct_bob_LDADD = \
55 $(top_builddir)/src/util/libgnunetutil.la \ 55 $(top_builddir)/src/util/libgnunetutil.la \
56 $(top_builddir)/src/cadet/libgnunetcadetnew.la \ 56 $(top_builddir)/src/cadet/libgnunetcadet.la \
57 $(top_builddir)/src/set/libgnunetset.la \ 57 $(top_builddir)/src/set/libgnunetset.la \
58 $(LIBGCRYPT_LIBS) \ 58 $(LIBGCRYPT_LIBS) \
59 -lgcrypt \ 59 -lgcrypt \
@@ -64,7 +64,7 @@ gnunet_service_scalarproduct_ecc_alice_SOURCES = \
64 gnunet-service-scalarproduct-ecc_alice.c 64 gnunet-service-scalarproduct-ecc_alice.c
65gnunet_service_scalarproduct_ecc_alice_LDADD = \ 65gnunet_service_scalarproduct_ecc_alice_LDADD = \
66 $(top_builddir)/src/util/libgnunetutil.la \ 66 $(top_builddir)/src/util/libgnunetutil.la \
67 $(top_builddir)/src/cadet/libgnunetcadetnew.la \ 67 $(top_builddir)/src/cadet/libgnunetcadet.la \
68 $(top_builddir)/src/set/libgnunetset.la \ 68 $(top_builddir)/src/set/libgnunetset.la \
69 $(LIBGCRYPT_LIBS) \ 69 $(LIBGCRYPT_LIBS) \
70 -lgcrypt \ 70 -lgcrypt \
@@ -75,7 +75,7 @@ gnunet_service_scalarproduct_ecc_bob_SOURCES = \
75 gnunet-service-scalarproduct-ecc_bob.c 75 gnunet-service-scalarproduct-ecc_bob.c
76gnunet_service_scalarproduct_ecc_bob_LDADD = \ 76gnunet_service_scalarproduct_ecc_bob_LDADD = \
77 $(top_builddir)/src/util/libgnunetutil.la \ 77 $(top_builddir)/src/util/libgnunetutil.la \
78 $(top_builddir)/src/cadet/libgnunetcadetnew.la \ 78 $(top_builddir)/src/cadet/libgnunetcadet.la \
79 $(top_builddir)/src/set/libgnunetset.la \ 79 $(top_builddir)/src/set/libgnunetset.la \
80 $(LIBGCRYPT_LIBS) \ 80 $(LIBGCRYPT_LIBS) \
81 -lgcrypt \ 81 -lgcrypt \
diff --git a/src/scalarproduct/gnunet-scalarproduct.c b/src/scalarproduct/gnunet-scalarproduct.c
index aa894b61d..5d0fce2b1 100644
--- a/src/scalarproduct/gnunet-scalarproduct.c
+++ b/src/scalarproduct/gnunet-scalarproduct.c
@@ -343,16 +343,32 @@ run (void *cls,
343int 343int
344main (int argc, char *const *argv) 344main (int argc, char *const *argv)
345{ 345{
346 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 346 struct GNUNET_GETOPT_CommandLineOption options[] = {
347 {'e', "elements", "\"key1,val1;key2,val2;...,keyn,valn;\"", 347
348 gettext_noop ("A comma separated list of elements to compare as vector with our remote peer."), 348 GNUNET_GETOPT_OPTION_STRING ('e',
349 1, &GNUNET_GETOPT_set_string, &input_elements}, 349 "elements",
350 {'p', "peer", "PEERID", 350 "\"key1,val1;key2,val2;...,keyn,valn;\"",
351 gettext_noop ("[Optional] peer to calculate our scalarproduct with. If this parameter is not given, the service will wait for a remote peer to compute the request."), 351 gettext_noop ("A comma separated list of elements to compare as vector with our remote peer."),
352 1, &GNUNET_GETOPT_set_string, &input_peer_id}, 352 &input_elements),
353 {'k', "key", "TRANSACTION_ID", 353
354 gettext_noop ("Transaction ID shared with peer."), 354 GNUNET_GETOPT_OPTION_STRING ('e',
355 1, &GNUNET_GETOPT_set_string, &input_session_key}, 355 "elements",
356 "\"key1,val1;key2,val2;...,keyn,valn;\"",
357 gettext_noop ("A comma separated list of elements to compare as vector with our remote peer."),
358 &input_elements),
359
360 GNUNET_GETOPT_OPTION_STRING ('p',
361 "peer",
362 "PEERID",
363 gettext_noop ("[Optional] peer to calculate our scalarproduct with. If this parameter is not given, the service will wait for a remote peer to compute the request."),
364 &input_peer_id),
365
366 GNUNET_GETOPT_OPTION_STRING ('k',
367 "key",
368 "TRANSACTION_ID",
369 gettext_noop ("Transaction ID shared with peer."),
370 &input_session_key),
371
356 GNUNET_GETOPT_OPTION_END 372 GNUNET_GETOPT_OPTION_END
357 }; 373 };
358 374
diff --git a/src/scalarproduct/gnunet-service-scalarproduct-ecc_alice.c b/src/scalarproduct/gnunet-service-scalarproduct-ecc_alice.c
index ca92fb9ea..c0b33f8ef 100644
--- a/src/scalarproduct/gnunet-service-scalarproduct-ecc_alice.c
+++ b/src/scalarproduct/gnunet-service-scalarproduct-ecc_alice.c
@@ -842,7 +842,7 @@ client_request_complete_alice (struct AliceServiceSession *s)
842 "Creating new channel for session with key %s.\n", 842 "Creating new channel for session with key %s.\n",
843 GNUNET_h2s (&s->session_id)); 843 GNUNET_h2s (&s->session_id));
844 s->channel 844 s->channel
845 = GNUNET_CADET_channel_creatE (my_cadet, 845 = GNUNET_CADET_channel_create (my_cadet,
846 s, 846 s,
847 &s->peer, 847 &s->peer,
848 &s->session_id, 848 &s->session_id,
@@ -1173,7 +1173,7 @@ run (void *cls,
1173 GNUNET_CRYPTO_ecc_rnd_mpi (edc, 1173 GNUNET_CRYPTO_ecc_rnd_mpi (edc,
1174 &my_privkey, 1174 &my_privkey,
1175 &my_privkey_inv); 1175 &my_privkey_inv);
1176 my_cadet = GNUNET_CADET_connecT (cfg); 1176 my_cadet = GNUNET_CADET_connect (cfg);
1177 if (NULL == my_cadet) 1177 if (NULL == my_cadet)
1178 { 1178 {
1179 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1179 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
diff --git a/src/scalarproduct/gnunet-service-scalarproduct-ecc_bob.c b/src/scalarproduct/gnunet-service-scalarproduct-ecc_bob.c
index 3851ca763..0b0333332 100644
--- a/src/scalarproduct/gnunet-service-scalarproduct-ecc_bob.c
+++ b/src/scalarproduct/gnunet-service-scalarproduct-ecc_bob.c
@@ -950,7 +950,7 @@ handle_bob_client_message (void *cls,
950 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 950 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
951 "Received client request, opening port %s!\n", 951 "Received client request, opening port %s!\n",
952 GNUNET_h2s (&msg->session_key)); 952 GNUNET_h2s (&msg->session_key));
953 s->port = GNUNET_CADET_open_porT (my_cadet, 953 s->port = GNUNET_CADET_open_port (my_cadet,
954 &msg->session_key, 954 &msg->session_key,
955 &cb_channel_incoming, 955 &cb_channel_incoming,
956 s, 956 s,
@@ -1054,7 +1054,7 @@ run (void *cls,
1054 /* We don't really do DLOG, so we can setup with very minimal resources */ 1054 /* We don't really do DLOG, so we can setup with very minimal resources */
1055 edc = GNUNET_CRYPTO_ecc_dlog_prepare (4 /* max value */, 1055 edc = GNUNET_CRYPTO_ecc_dlog_prepare (4 /* max value */,
1056 2 /* RAM */); 1056 2 /* RAM */);
1057 my_cadet = GNUNET_CADET_connecT (cfg); 1057 my_cadet = GNUNET_CADET_connect (cfg);
1058 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, 1058 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1059 NULL); 1059 NULL);
1060 if (NULL == my_cadet) 1060 if (NULL == my_cadet)
diff --git a/src/scalarproduct/gnunet-service-scalarproduct_alice.c b/src/scalarproduct/gnunet-service-scalarproduct_alice.c
index 6d7a0a3b8..a55d03900 100644
--- a/src/scalarproduct/gnunet-service-scalarproduct_alice.c
+++ b/src/scalarproduct/gnunet-service-scalarproduct_alice.c
@@ -1076,7 +1076,7 @@ client_request_complete_alice (struct AliceServiceSession *s)
1076 "Creating new channel for session with key %s.\n", 1076 "Creating new channel for session with key %s.\n",
1077 GNUNET_h2s (&s->session_id)); 1077 GNUNET_h2s (&s->session_id));
1078 s->channel 1078 s->channel
1079 = GNUNET_CADET_channel_creatE (my_cadet, 1079 = GNUNET_CADET_channel_create (my_cadet,
1080 s, 1080 s,
1081 &s->peer, 1081 &s->peer,
1082 &s->session_id, 1082 &s->session_id,
@@ -1398,7 +1398,7 @@ run (void *cls,
1398 GNUNET_CRYPTO_PAILLIER_BITS / 3); 1398 GNUNET_CRYPTO_PAILLIER_BITS / 3);
1399 GNUNET_CRYPTO_paillier_create (&my_pubkey, 1399 GNUNET_CRYPTO_paillier_create (&my_pubkey,
1400 &my_privkey); 1400 &my_privkey);
1401 my_cadet = GNUNET_CADET_connecT (cfg); 1401 my_cadet = GNUNET_CADET_connect (cfg);
1402 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, 1402 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1403 NULL); 1403 NULL);
1404 if (NULL == my_cadet) 1404 if (NULL == my_cadet)
diff --git a/src/scalarproduct/gnunet-service-scalarproduct_bob.c b/src/scalarproduct/gnunet-service-scalarproduct_bob.c
index f3b5327f1..0c38cb426 100644
--- a/src/scalarproduct/gnunet-service-scalarproduct_bob.c
+++ b/src/scalarproduct/gnunet-service-scalarproduct_bob.c
@@ -1230,7 +1230,7 @@ handle_bob_client_message (void *cls,
1230 } 1230 }
1231 GNUNET_SERVICE_client_continue (s->client); 1231 GNUNET_SERVICE_client_continue (s->client);
1232 /* We're ready, open the port */ 1232 /* We're ready, open the port */
1233 s->port = GNUNET_CADET_open_porT (my_cadet, 1233 s->port = GNUNET_CADET_open_port (my_cadet,
1234 &msg->session_key, 1234 &msg->session_key,
1235 &cb_channel_incoming, 1235 &cb_channel_incoming,
1236 s, 1236 s,
@@ -1336,7 +1336,7 @@ run (void *cls,
1336 1336
1337 GNUNET_CRYPTO_paillier_create (&my_pubkey, 1337 GNUNET_CRYPTO_paillier_create (&my_pubkey,
1338 &my_privkey); 1338 &my_privkey);
1339 my_cadet = GNUNET_CADET_connecT (cfg); 1339 my_cadet = GNUNET_CADET_connect (cfg);
1340 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, 1340 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1341 NULL); 1341 NULL);
1342 if (NULL == my_cadet) 1342 if (NULL == my_cadet)
diff --git a/src/scalarproduct/scalarproduct_api.c b/src/scalarproduct/scalarproduct_api.c
index df9f8d196..05c122e74 100644
--- a/src/scalarproduct/scalarproduct_api.c
+++ b/src/scalarproduct/scalarproduct_api.c
@@ -268,7 +268,7 @@ GNUNET_SCALARPRODUCT_accept_computation (const struct GNUNET_CONFIGURATION_Handl
268 GNUNET_free (h); 268 GNUNET_free (h);
269 return NULL; 269 return NULL;
270 } 270 }
271 possible = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - sizeof (struct BobComputationMessage)) 271 possible = (GNUNET_MAX_MESSAGE_SIZE - 1 - sizeof (struct BobComputationMessage))
272 / sizeof (struct GNUNET_SCALARPRODUCT_Element); 272 / sizeof (struct GNUNET_SCALARPRODUCT_Element);
273 todo = GNUNET_MIN (possible, 273 todo = GNUNET_MIN (possible,
274 element_count); 274 element_count);
@@ -285,7 +285,7 @@ GNUNET_SCALARPRODUCT_accept_computation (const struct GNUNET_CONFIGURATION_Handl
285 element_count_transfered = todo; 285 element_count_transfered = todo;
286 GNUNET_MQ_send (h->mq, 286 GNUNET_MQ_send (h->mq,
287 env); 287 env);
288 possible = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - sizeof (*mmsg)) 288 possible = (GNUNET_MAX_MESSAGE_SIZE - 1 - sizeof (*mmsg))
289 / sizeof (struct GNUNET_SCALARPRODUCT_Element); 289 / sizeof (struct GNUNET_SCALARPRODUCT_Element);
290 while (element_count_transfered < element_count) 290 while (element_count_transfered < element_count)
291 { 291 {
@@ -426,7 +426,7 @@ GNUNET_SCALARPRODUCT_start_computation (const struct GNUNET_CONFIGURATION_Handle
426 h->cfg = cfg; 426 h->cfg = cfg;
427 h->key = *session_key; 427 h->key = *session_key;
428 428
429 possible = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - sizeof (struct AliceComputationMessage)) 429 possible = (GNUNET_MAX_MESSAGE_SIZE - 1 - sizeof (struct AliceComputationMessage))
430 / sizeof (struct GNUNET_SCALARPRODUCT_Element); 430 / sizeof (struct GNUNET_SCALARPRODUCT_Element);
431 todo = GNUNET_MIN (possible, 431 todo = GNUNET_MIN (possible,
432 element_count); 432 element_count);
@@ -445,7 +445,7 @@ GNUNET_SCALARPRODUCT_start_computation (const struct GNUNET_CONFIGURATION_Handle
445 GNUNET_MQ_send (h->mq, 445 GNUNET_MQ_send (h->mq,
446 env); 446 env);
447 element_count_transfered = todo; 447 element_count_transfered = todo;
448 possible = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - sizeof (*mmsg)) 448 possible = (GNUNET_MAX_MESSAGE_SIZE - 1 - sizeof (*mmsg))
449 / sizeof (struct GNUNET_SCALARPRODUCT_Element); 449 / sizeof (struct GNUNET_SCALARPRODUCT_Element);
450 while (element_count_transfered < element_count) 450 while (element_count_transfered < element_count)
451 { 451 {
diff --git a/src/secretsharing/Makefile.am b/src/secretsharing/Makefile.am
index 485183e36..4b9a06c40 100644
--- a/src/secretsharing/Makefile.am
+++ b/src/secretsharing/Makefile.am
@@ -17,9 +17,6 @@ if USE_COVERAGE
17endif 17endif
18 18
19 19
20bin_PROGRAMS = \
21 gnunet-secretsharing-profiler
22
23libexec_PROGRAMS = \ 20libexec_PROGRAMS = \
24 gnunet-service-secretsharing 21 gnunet-service-secretsharing
25 22
@@ -57,6 +54,9 @@ libgnunetsecretsharing_la_LDFLAGS = \
57 $(GN_LIB_LDFLAGS) 54 $(GN_LIB_LDFLAGS)
58 55
59if HAVE_TESTING 56if HAVE_TESTING
57bin_PROGRAMS = \
58 gnunet-secretsharing-profiler
59
60check_PROGRAMS = \ 60check_PROGRAMS = \
61 test_secretsharing_api 61 test_secretsharing_api
62 62
diff --git a/src/secretsharing/gnunet-secretsharing-profiler.c b/src/secretsharing/gnunet-secretsharing-profiler.c
index 3ff5d7fdd..e66019dc6 100644
--- a/src/secretsharing/gnunet-secretsharing-profiler.c
+++ b/src/secretsharing/gnunet-secretsharing-profiler.c
@@ -41,7 +41,7 @@ static unsigned int threshold = 2;
41/** 41/**
42 * Should we try to decrypt a value after the key generation? 42 * Should we try to decrypt a value after the key generation?
43 */ 43 */
44static unsigned int decrypt = GNUNET_NO; 44static int decrypt = GNUNET_NO;
45 45
46/** 46/**
47 * When would we like to see the operation finished? 47 * When would we like to see the operation finished?
@@ -88,7 +88,7 @@ static unsigned int num_decrypted;
88 88
89static struct GNUNET_HashCode session_id; 89static struct GNUNET_HashCode session_id;
90 90
91static int verbose; 91static unsigned int verbose;
92 92
93static struct GNUNET_SECRETSHARING_Plaintext reference_plaintext; 93static struct GNUNET_SECRETSHARING_Plaintext reference_plaintext;
94 94
@@ -602,26 +602,41 @@ run (void *cls, char *const *args, const char *cfgfile,
602int 602int
603main (int argc, char **argv) 603main (int argc, char **argv)
604{ 604{
605 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 605 struct GNUNET_GETOPT_CommandLineOption options[] = {
606 { 'n', "num-peers", NULL, 606
607 gettext_noop ("number of peers in consensus"), 607 GNUNET_GETOPT_OPTION_SET_UINT ('n',
608 GNUNET_YES, &GNUNET_GETOPT_set_uint, &num_peers }, 608 "num-peers",
609 { 'D', "delay", NULL, 609 NULL,
610 gettext_noop ("dkg start delay"), 610 gettext_noop ("number of peers in consensus"),
611 GNUNET_YES, &GNUNET_GETOPT_set_relative_time, &delay }, 611 &num_peers),
612 { 't', "timeout", NULL, 612
613 gettext_noop ("dkg timeout"), 613 GNUNET_GETOPT_OPTION_SET_RELATIVE_TIME ('D',
614 GNUNET_YES, &GNUNET_GETOPT_set_relative_time, &timeout }, 614 "delay",
615 { 'k', "threshold", NULL, 615 NULL,
616 gettext_noop ("threshold"), 616 gettext_noop ("dkg start delay"),
617 GNUNET_YES, &GNUNET_GETOPT_set_uint, &threshold }, 617 &delay),
618 { 'd', "decrypt", NULL, 618
619 gettext_noop ("also profile decryption"), 619 GNUNET_GETOPT_OPTION_SET_RELATIVE_TIME ('t',
620 GNUNET_NO, &GNUNET_GETOPT_set_one, &decrypt }, 620 "timeout",
621 { 'V', "verbose", NULL, 621 NULL,
622 gettext_noop ("be more verbose (print received values)"), 622 gettext_noop ("dkg timeout"),
623 GNUNET_NO, &GNUNET_GETOPT_set_one, &verbose }, 623 &timeout),
624 GNUNET_GETOPT_OPTION_END 624
625 GNUNET_GETOPT_OPTION_SET_UINT ('k',
626 "threshold",
627 NULL,
628 gettext_noop ("threshold"),
629 &threshold),
630
631 GNUNET_GETOPT_OPTION_SET_ONE ('d',
632 "descrypt",
633 gettext_noop ("also profile decryption"),
634 &decrypt),
635
636
637 GNUNET_GETOPT_OPTION_VERBOSE (&verbose),
638
639 GNUNET_GETOPT_OPTION_END
625 }; 640 };
626 delay = GNUNET_TIME_UNIT_ZERO; 641 delay = GNUNET_TIME_UNIT_ZERO;
627 timeout = GNUNET_TIME_UNIT_MINUTES; 642 timeout = GNUNET_TIME_UNIT_MINUTES;
diff --git a/src/secretsharing/gnunet-service-secretsharing.c b/src/secretsharing/gnunet-service-secretsharing.c
index ddbe81576..ccdba12c2 100644
--- a/src/secretsharing/gnunet-service-secretsharing.c
+++ b/src/secretsharing/gnunet-service-secretsharing.c
@@ -109,19 +109,16 @@ struct DecryptPeerInfo
109 109
110 110
111/** 111/**
112 * State we keep per client.
113 */
114struct ClientState;
115
116
117/**
112 * Session to establish a threshold-shared secret. 118 * Session to establish a threshold-shared secret.
113 */ 119 */
114struct KeygenSession 120struct KeygenSession
115{ 121{
116 /**
117 * Keygen sessions are held in a linked list.
118 */
119 struct KeygenSession *next;
120
121 /**
122 * Keygen sessions are held in a linked list.
123 */
124 struct KeygenSession *prev;
125 122
126 /** 123 /**
127 * Current consensus, used for both DKG rounds. 124 * Current consensus, used for both DKG rounds.
@@ -129,15 +126,9 @@ struct KeygenSession
129 struct GNUNET_CONSENSUS_Handle *consensus; 126 struct GNUNET_CONSENSUS_Handle *consensus;
130 127
131 /** 128 /**
132 * Client that is interested in the result 129 * Which client is this for?
133 * of this key generation session.
134 */
135 struct GNUNET_SERVER_Client *client;
136
137 /**
138 * Message queue for 'client'
139 */ 130 */
140 struct GNUNET_MQ_Handle *client_mq; 131 struct ClientState *cs;
141 132
142 /** 133 /**
143 * Randomly generated coefficients of the polynomial for sharing our 134 * Randomly generated coefficients of the polynomial for sharing our
@@ -223,15 +214,6 @@ struct KeygenSession
223 */ 214 */
224struct DecryptSession 215struct DecryptSession
225{ 216{
226 /**
227 * Decrypt sessions are stored in a linked list.
228 */
229 struct DecryptSession *next;
230
231 /**
232 * Decrypt sessions are stored in a linked list.
233 */
234 struct DecryptSession *prev;
235 217
236 /** 218 /**
237 * Handle to the consensus over partial decryptions. 219 * Handle to the consensus over partial decryptions.
@@ -239,14 +221,9 @@ struct DecryptSession
239 struct GNUNET_CONSENSUS_Handle *consensus; 221 struct GNUNET_CONSENSUS_Handle *consensus;
240 222
241 /** 223 /**
242 * Client connected to us. 224 * Which client is this for?
243 */ 225 */
244 struct GNUNET_SERVER_Client *client; 226 struct ClientState *cs;
245
246 /**
247 * Message queue for 'client'.
248 */
249 struct GNUNET_MQ_Handle *client_mq;
250 227
251 /** 228 /**
252 * When should we start communicating for decryption? 229 * When should we start communicating for decryption?
@@ -279,24 +256,32 @@ struct DecryptSession
279 256
280 257
281/** 258/**
282 * Decrypt sessions are held in a linked list. 259 * State we keep per client.
283 */ 260 */
284static struct DecryptSession *decrypt_sessions_head; 261struct ClientState
262{
263 /**
264 * Decrypt session of the client, if any.
265 */
266 struct DecryptSession *decrypt_session;
285 267
286/** 268 /**
287 * Decrypt sessions are held in a linked list. 269 * Keygen session of the client, if any.
288 */ 270 */
289static struct DecryptSession *decrypt_sessions_tail; 271 struct KeygenSession *keygen_session;
290 272
291/** 273 /**
292 * Decrypt sessions are held in a linked list. 274 * Client this is about.
293 */ 275 */
294static struct KeygenSession *keygen_sessions_head; 276 struct GNUNET_SERVICE_Client *client;
277
278 /**
279 * MQ to talk to @a client.
280 */
281 struct GNUNET_MQ_Handle *mq;
282
283};
295 284
296/**
297 * Decrypt sessions are held in a linked list.
298 */
299static struct KeygenSession *keygen_sessions_tail;
300 285
301/** 286/**
302 * The ElGamal prime field order as libgcrypt mpi. 287 * The ElGamal prime field order as libgcrypt mpi.
@@ -331,11 +316,6 @@ static struct GNUNET_CRYPTO_EddsaPrivateKey *my_peer_private_key;
331 */ 316 */
332static const struct GNUNET_CONFIGURATION_Handle *cfg; 317static const struct GNUNET_CONFIGURATION_Handle *cfg;
333 318
334/**
335 * Server for this service.
336 */
337static struct GNUNET_SERVER_Handle *srv;
338
339 319
340/** 320/**
341 * Get the peer info belonging to a peer identity in a keygen session. 321 * Get the peer info belonging to a peer identity in a keygen session.
@@ -468,7 +448,8 @@ normalize_peers (struct GNUNET_PeerIdentity *listed,
468 n += 1; 448 n += 1;
469 } 449 }
470 450
471 normalized = GNUNET_new_array (n, struct GNUNET_PeerIdentity); 451 normalized = GNUNET_new_array (n,
452 struct GNUNET_PeerIdentity);
472 453
473 if (GNUNET_NO == local_peer_in_list) 454 if (GNUNET_NO == local_peer_in_list)
474 normalized[n - 1] = my_peer; 455 normalized[n - 1] = my_peer;
@@ -558,10 +539,13 @@ compute_lagrange_coefficient (gcry_mpi_t coeff, unsigned int j,
558static void 539static void
559decrypt_session_destroy (struct DecryptSession *ds) 540decrypt_session_destroy (struct DecryptSession *ds)
560{ 541{
561 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "destroying decrypt session\n"); 542 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
562 543 "destroying decrypt session\n");
563 GNUNET_CONTAINER_DLL_remove (decrypt_sessions_head, decrypt_sessions_tail, ds); 544 if (NULL != ds->cs)
564 545 {
546 ds->cs->decrypt_session = NULL;
547 ds->cs = NULL;
548 }
565 if (NULL != ds->consensus) 549 if (NULL != ds->consensus)
566 { 550 {
567 GNUNET_CONSENSUS_destroy (ds->consensus); 551 GNUNET_CONSENSUS_destroy (ds->consensus);
@@ -570,8 +554,7 @@ decrypt_session_destroy (struct DecryptSession *ds)
570 554
571 if (NULL != ds->info) 555 if (NULL != ds->info)
572 { 556 {
573 unsigned int i; 557 for (unsigned int i = 0; i < ds->share->num_peers; i++)
574 for (i = 0; i < ds->share->num_peers; i++)
575 { 558 {
576 if (NULL != ds->info[i].partial_decryption) 559 if (NULL != ds->info[i].partial_decryption)
577 { 560 {
@@ -582,26 +565,12 @@ decrypt_session_destroy (struct DecryptSession *ds)
582 GNUNET_free (ds->info); 565 GNUNET_free (ds->info);
583 ds->info = NULL; 566 ds->info = NULL;
584 } 567 }
585
586 if (NULL != ds->share) 568 if (NULL != ds->share)
587 { 569 {
588 GNUNET_SECRETSHARING_share_destroy (ds->share); 570 GNUNET_SECRETSHARING_share_destroy (ds->share);
589 ds->share = NULL; 571 ds->share = NULL;
590 } 572 }
591 573
592 if (NULL != ds->client_mq)
593 {
594 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "destroying decrypt MQ\n");
595 GNUNET_MQ_destroy (ds->client_mq);
596 ds->client_mq = NULL;
597 }
598
599 if (NULL != ds->client)
600 {
601 GNUNET_SERVER_client_disconnect (ds->client);
602 ds->client = NULL;
603 }
604
605 GNUNET_free (ds); 574 GNUNET_free (ds);
606} 575}
607 576
@@ -630,14 +599,17 @@ keygen_info_destroy (struct KeygenPeerInfo *info)
630static void 599static void
631keygen_session_destroy (struct KeygenSession *ks) 600keygen_session_destroy (struct KeygenSession *ks)
632{ 601{
633 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "destroying keygen session\n"); 602 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
634 603 "destroying keygen session\n");
635 GNUNET_CONTAINER_DLL_remove (keygen_sessions_head, keygen_sessions_tail, ks);
636 604
605 if (NULL != ks->cs)
606 {
607 ks->cs->keygen_session = NULL;
608 ks->cs = NULL;
609 }
637 if (NULL != ks->info) 610 if (NULL != ks->info)
638 { 611 {
639 unsigned int i; 612 for (unsigned int i = 0; i < ks->num_peers; i++)
640 for (i = 0; i < ks->num_peers; i++)
641 keygen_info_destroy (&ks->info[i]); 613 keygen_info_destroy (&ks->info[i]);
642 GNUNET_free (ks->info); 614 GNUNET_free (ks->info);
643 ks->info = NULL; 615 ks->info = NULL;
@@ -651,8 +623,7 @@ keygen_session_destroy (struct KeygenSession *ks)
651 623
652 if (NULL != ks->presecret_polynomial) 624 if (NULL != ks->presecret_polynomial)
653 { 625 {
654 unsigned int i; 626 for (unsigned int i = 0; i < ks->threshold; i++)
655 for (i = 0; i < ks->threshold; i++)
656 { 627 {
657 GNUNET_assert (NULL != ks->presecret_polynomial[i]); 628 GNUNET_assert (NULL != ks->presecret_polynomial[i]);
658 gcry_mpi_release (ks->presecret_polynomial[i]); 629 gcry_mpi_release (ks->presecret_polynomial[i]);
@@ -661,38 +632,21 @@ keygen_session_destroy (struct KeygenSession *ks)
661 GNUNET_free (ks->presecret_polynomial); 632 GNUNET_free (ks->presecret_polynomial);
662 ks->presecret_polynomial = NULL; 633 ks->presecret_polynomial = NULL;
663 } 634 }
664
665 if (NULL != ks->client_mq)
666 {
667 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "destroying keygen MQ\n");
668 GNUNET_MQ_destroy (ks->client_mq);
669 ks->client_mq = NULL;
670 }
671
672 if (NULL != ks->my_share) 635 if (NULL != ks->my_share)
673 { 636 {
674 gcry_mpi_release (ks->my_share); 637 gcry_mpi_release (ks->my_share);
675 ks->my_share = NULL; 638 ks->my_share = NULL;
676 } 639 }
677
678 if (NULL != ks->public_key) 640 if (NULL != ks->public_key)
679 { 641 {
680 gcry_mpi_release (ks->public_key); 642 gcry_mpi_release (ks->public_key);
681 ks->public_key = NULL; 643 ks->public_key = NULL;
682 } 644 }
683
684 if (NULL != ks->peers) 645 if (NULL != ks->peers)
685 { 646 {
686 GNUNET_free (ks->peers); 647 GNUNET_free (ks->peers);
687 ks->peers = NULL; 648 ks->peers = NULL;
688 } 649 }
689
690 if (NULL != ks->client)
691 {
692 GNUNET_SERVER_client_disconnect (ks->client);
693 ks->client = NULL;
694 }
695
696 GNUNET_free (ks); 650 GNUNET_free (ks);
697} 651}
698 652
@@ -706,11 +660,7 @@ keygen_session_destroy (struct KeygenSession *ks)
706static void 660static void
707cleanup_task (void *cls) 661cleanup_task (void *cls)
708{ 662{
709 while (NULL != decrypt_sessions_head) 663 /* Nothing to do! */
710 decrypt_session_destroy (decrypt_sessions_head);
711
712 while (NULL != keygen_sessions_head)
713 keygen_session_destroy (keygen_sessions_head);
714} 664}
715 665
716 666
@@ -727,7 +677,8 @@ generate_presecret_polynomial (struct KeygenSession *ks)
727 gcry_mpi_t v; 677 gcry_mpi_t v;
728 678
729 GNUNET_assert (NULL == ks->presecret_polynomial); 679 GNUNET_assert (NULL == ks->presecret_polynomial);
730 ks->presecret_polynomial = GNUNET_new_array (ks->threshold, gcry_mpi_t); 680 ks->presecret_polynomial = GNUNET_new_array (ks->threshold,
681 gcry_mpi_t);
731 for (i = 0; i < ks->threshold; i++) 682 for (i = 0; i < ks->threshold; i++)
732 { 683 {
733 v = ks->presecret_polynomial[i] = gcry_mpi_new (GNUNET_SECRETSHARING_ELGAMAL_BITS); 684 v = ks->presecret_polynomial[i] = gcry_mpi_new (GNUNET_SECRETSHARING_ELGAMAL_BITS);
@@ -768,9 +719,9 @@ keygen_round1_new_element (void *cls,
768 if (element->size != sizeof (struct GNUNET_SECRETSHARING_KeygenCommitData)) 719 if (element->size != sizeof (struct GNUNET_SECRETSHARING_KeygenCommitData))
769 { 720 {
770 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 721 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
771 "keygen commit data with wrong size (%u) in consensus, " 722 "keygen commit data with wrong size (%u) in consensus, %u expected\n",
772 " %lu expected\n", 723 (unsigned int) element->size,
773 element->size, sizeof (struct GNUNET_SECRETSHARING_KeygenCommitData)); 724 (unsigned int) sizeof (struct GNUNET_SECRETSHARING_KeygenCommitData));
774 return; 725 return;
775 } 726 }
776 727
@@ -855,10 +806,13 @@ keygen_round2_conclude (void *cls)
855 if (GNUNET_YES == ks->info[i].round2_valid) 806 if (GNUNET_YES == ks->info[i].round2_valid)
856 share->num_peers++; 807 share->num_peers++;
857 808
858 share->peers = GNUNET_new_array (share->num_peers, struct GNUNET_PeerIdentity); 809 share->peers = GNUNET_new_array (share->num_peers,
810 struct GNUNET_PeerIdentity);
859 share->sigmas = 811 share->sigmas =
860 GNUNET_new_array (share->num_peers, struct GNUNET_SECRETSHARING_FieldElement); 812 GNUNET_new_array (share->num_peers,
861 share->original_indices = GNUNET_new_array (share->num_peers, uint16_t); 813 struct GNUNET_SECRETSHARING_FieldElement);
814 share->original_indices = GNUNET_new_array (share->num_peers,
815 uint16_t);
862 816
863 /* maybe we're not even in the list of peers? */ 817 /* maybe we're not even in the list of peers? */
864 share->my_peer = share->num_peers; 818 share->my_peer = share->num_peers;
@@ -907,7 +861,8 @@ keygen_round2_conclude (void *cls)
907 GNUNET_SECRETSHARING_share_destroy (share); 861 GNUNET_SECRETSHARING_share_destroy (share);
908 share = NULL; 862 share = NULL;
909 863
910 GNUNET_MQ_send (ks->client_mq, ev); 864 GNUNET_MQ_send (ks->cs->mq,
865 ev);
911} 866}
912 867
913 868
@@ -1429,9 +1384,9 @@ keygen_round2_new_element (void *cls,
1429 if (element->size != expected_element_size) 1384 if (element->size != expected_element_size)
1430 { 1385 {
1431 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1386 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1432 "keygen round2 data with wrong size (%u) in consensus, " 1387 "keygen round2 data with wrong size (%u) in consensus, %u expected\n",
1433 " %lu expected\n", 1388 (unsigned int) element->size,
1434 element->size, expected_element_size); 1389 (unsigned int) expected_element_size);
1435 return; 1390 return;
1436 } 1391 }
1437 1392
@@ -1669,73 +1624,102 @@ insert_round1_element (struct KeygenSession *ks)
1669 1624
1670 1625
1671/** 1626/**
1627 * Check that @a msg is well-formed.
1628 *
1629 * @param cls identification of the client
1630 * @param msg the actual message
1631 * @return #GNUNET_OK if @a msg is well-formed
1632 */
1633static int
1634check_client_keygen (void *cls,
1635 const struct GNUNET_SECRETSHARING_CreateMessage *msg)
1636{
1637 unsigned int num_peers = ntohs (msg->num_peers);
1638
1639 if (ntohs (msg->header.size) - sizeof (*msg) !=
1640 num_peers * sizeof (struct GNUNET_PeerIdentity))
1641 {
1642 GNUNET_break (0);
1643 return GNUNET_SYSERR;
1644 }
1645 return GNUNET_OK;
1646}
1647
1648
1649/**
1672 * Functions with this signature are called whenever a message is 1650 * Functions with this signature are called whenever a message is
1673 * received. 1651 * received.
1674 * 1652 *
1675 * @param cls closure 1653 * @param cls identification of the client
1676 * @param client identification of the client 1654 * @param msg the actual message
1677 * @param message the actual message
1678 */ 1655 */
1679static void handle_client_keygen (void *cls, 1656static void
1680 struct GNUNET_SERVER_Client *client, 1657handle_client_keygen (void *cls,
1681 const struct GNUNET_MessageHeader 1658 const struct GNUNET_SECRETSHARING_CreateMessage *msg)
1682 *message)
1683{ 1659{
1684 const struct GNUNET_SECRETSHARING_CreateMessage *msg = 1660 struct ClientState *cs = cls;
1685 (const struct GNUNET_SECRETSHARING_CreateMessage *) message;
1686 struct KeygenSession *ks; 1661 struct KeygenSession *ks;
1687 unsigned int i;
1688
1689 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "client requested key generation\n");
1690 1662
1663 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1664 "client requested key generation\n");
1665 if (NULL != cs->keygen_session)
1666 {
1667 GNUNET_break (0);
1668 GNUNET_SERVICE_client_drop (cs->client);
1669 return;
1670 }
1691 ks = GNUNET_new (struct KeygenSession); 1671 ks = GNUNET_new (struct KeygenSession);
1692 1672 ks->cs = cs;
1693 /* FIXME: check if client already has some session */ 1673 cs->keygen_session = ks;
1694
1695 GNUNET_CONTAINER_DLL_insert (keygen_sessions_head, keygen_sessions_tail, ks);
1696
1697 ks->client = client;
1698 ks->client_mq = GNUNET_MQ_queue_for_server_client (client);
1699
1700 ks->deadline = GNUNET_TIME_absolute_ntoh (msg->deadline); 1674 ks->deadline = GNUNET_TIME_absolute_ntoh (msg->deadline);
1701 ks->threshold = ntohs (msg->threshold); 1675 ks->threshold = ntohs (msg->threshold);
1702 ks->num_peers = ntohs (msg->num_peers); 1676 ks->num_peers = ntohs (msg->num_peers);
1703 1677
1704 ks->peers = normalize_peers ((struct GNUNET_PeerIdentity *) &msg[1], ks->num_peers, 1678 ks->peers = normalize_peers ((struct GNUNET_PeerIdentity *) &msg[1],
1705 &ks->num_peers, &ks->local_peer_idx); 1679 ks->num_peers,
1680 &ks->num_peers,
1681 &ks->local_peer_idx);
1706 1682
1707 1683
1708 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "first round of consensus with %u peers\n", ks->num_peers); 1684 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1709 ks->consensus = GNUNET_CONSENSUS_create (cfg, ks->num_peers, ks->peers, &msg->session_id, 1685 "first round of consensus with %u peers\n",
1686 ks->num_peers);
1687 ks->consensus = GNUNET_CONSENSUS_create (cfg,
1688 ks->num_peers,
1689 ks->peers,
1690 &msg->session_id,
1710 GNUNET_TIME_absolute_ntoh (msg->start), 1691 GNUNET_TIME_absolute_ntoh (msg->start),
1711 GNUNET_TIME_absolute_ntoh (msg->deadline), 1692 GNUNET_TIME_absolute_ntoh (msg->deadline),
1712 keygen_round1_new_element, ks); 1693 keygen_round1_new_element,
1694 ks);
1713 1695
1714 ks->info = GNUNET_new_array (ks->num_peers, struct KeygenPeerInfo); 1696 ks->info = GNUNET_new_array (ks->num_peers,
1697 struct KeygenPeerInfo);
1715 1698
1716 for (i = 0; i < ks->num_peers; i++) 1699 for (unsigned int i = 0; i < ks->num_peers; i++)
1717 ks->info[i].peer = ks->peers[i]; 1700 ks->info[i].peer = ks->peers[i];
1718 1701
1719 GNUNET_CRYPTO_paillier_create (&ks->info[ks->local_peer_idx].paillier_public_key, 1702 GNUNET_CRYPTO_paillier_create (&ks->info[ks->local_peer_idx].paillier_public_key,
1720 &ks->paillier_private_key); 1703 &ks->paillier_private_key);
1721 1704
1722 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: Generated paillier key pair\n", ks->local_peer_idx); 1705 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1723 1706 "P%u: Generated paillier key pair\n",
1707 ks->local_peer_idx);
1724 generate_presecret_polynomial (ks); 1708 generate_presecret_polynomial (ks);
1725 1709 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1726 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: Generated presecret polynomial\n", ks->local_peer_idx); 1710 "P%u: Generated presecret polynomial\n",
1727 1711 ks->local_peer_idx);
1728 insert_round1_element (ks); 1712 insert_round1_element (ks);
1729 1713 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1730 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: Concluding for round 1\n", ks->local_peer_idx); 1714 "P%u: Concluding for round 1\n",
1731 1715 ks->local_peer_idx);
1732 GNUNET_CONSENSUS_conclude (ks->consensus, 1716 GNUNET_CONSENSUS_conclude (ks->consensus,
1733 keygen_round1_conclude, 1717 keygen_round1_conclude,
1734 ks); 1718 ks);
1735 1719 GNUNET_SERVICE_client_continue (cs->client);
1736 GNUNET_SERVER_receive_done (client, GNUNET_OK); 1720 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1737 1721 "P%u: Waiting for round 1 elements ...\n",
1738 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: Waiting for round 1 elements ...\n", ks->local_peer_idx); 1722 ks->local_peer_idx);
1739} 1723}
1740 1724
1741 1725
@@ -1771,20 +1755,24 @@ decrypt_conclude (void *cls)
1771 if (NULL != ds->info[i].partial_decryption) 1755 if (NULL != ds->info[i].partial_decryption)
1772 num++; 1756 num++;
1773 1757
1774 indices = GNUNET_malloc (num * sizeof (unsigned int)); 1758 indices = GNUNET_new_array (num,
1759 unsigned int);
1775 j = 0; 1760 j = 0;
1776 for (i = 0; i < ds->share->num_peers; i++) 1761 for (i = 0; i < ds->share->num_peers; i++)
1777 if (NULL != ds->info[i].partial_decryption) 1762 if (NULL != ds->info[i].partial_decryption)
1778 indices[j++] = ds->info[i].original_index; 1763 indices[j++] = ds->info[i].original_index;
1779 1764
1780 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "P%u: decrypt conclude, with %u peers\n", 1765 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1781 ds->share->my_peer, num); 1766 "P%u: decrypt conclude, with %u peers\n",
1767 ds->share->my_peer,
1768 num);
1782 1769
1783 gcry_mpi_set_ui (prod, 1); 1770 gcry_mpi_set_ui (prod, 1);
1784 for (i = 0; i < num; i++) 1771 for (i = 0; i < num; i++)
1785 { 1772 {
1786 1773
1787 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "P%u: index of %u: %u\n", 1774 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1775 "P%u: index of %u: %u\n",
1788 ds->share->my_peer, i, indices[i]); 1776 ds->share->my_peer, i, indices[i]);
1789 compute_lagrange_coefficient (lagrange, indices[i], indices, num); 1777 compute_lagrange_coefficient (lagrange, indices[i], indices, num);
1790 // w_i^{\lambda_i} 1778 // w_i^{\lambda_i}
@@ -1801,7 +1789,8 @@ decrypt_conclude (void *cls)
1801 ev = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_DECRYPT_DONE); 1789 ev = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_DECRYPT_DONE);
1802 GNUNET_CRYPTO_mpi_print_unsigned (&msg->plaintext, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, m); 1790 GNUNET_CRYPTO_mpi_print_unsigned (&msg->plaintext, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, m);
1803 msg->success = htonl (1); 1791 msg->success = htonl (1);
1804 GNUNET_MQ_send (ds->client_mq, ev); 1792 GNUNET_MQ_send (ds->cs->mq,
1793 ev);
1805 1794
1806 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "sent decrypt done to client\n"); 1795 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "sent decrypt done to client\n");
1807 1796
@@ -1945,10 +1934,15 @@ decrypt_new_element (void *cls,
1945 { 1934 {
1946 char *tmp1_str; 1935 char *tmp1_str;
1947 char *tmp2_str; 1936 char *tmp2_str;
1937
1948 tmp1_str = mpi_to_str (tmp1); 1938 tmp1_str = mpi_to_str (tmp1);
1949 tmp2_str = mpi_to_str (tmp2); 1939 tmp2_str = mpi_to_str (tmp2);
1950 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "P%u: Received invalid partial decryption from P%ld (eqn 1), expected %s got %s\n", 1940 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1951 session->share->my_peer, info - session->info, tmp1_str, tmp2_str); 1941 "P%u: Received invalid partial decryption from P%u (eqn 1), expected %s got %s\n",
1942 session->share->my_peer,
1943 (unsigned int) (info - session->info),
1944 tmp1_str,
1945 tmp2_str);
1952 GNUNET_free (tmp1_str); 1946 GNUNET_free (tmp1_str);
1953 GNUNET_free (tmp2_str); 1947 GNUNET_free (tmp2_str);
1954 goto cleanup; 1948 goto cleanup;
@@ -1963,8 +1957,10 @@ decrypt_new_element (void *cls,
1963 1957
1964 if (0 != gcry_mpi_cmp (tmp1, tmp2)) 1958 if (0 != gcry_mpi_cmp (tmp1, tmp2))
1965 { 1959 {
1966 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "P%u: Received invalid partial decryption from P%ld (eqn 2)\n", 1960 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1967 session->share->my_peer, info - session->info); 1961 "P%u: Received invalid partial decryption from P%u (eqn 2)\n",
1962 session->share->my_peer,
1963 (unsigned int) (info - session->info));
1968 goto cleanup; 1964 goto cleanup;
1969 } 1965 }
1970 1966
@@ -2100,40 +2096,63 @@ insert_decrypt_element (struct DecryptSession *ds)
2100 2096
2101 2097
2102/** 2098/**
2099 * Check that @a msg is well-formed.
2100 *
2101 * @param cls identification of the client
2102 * @param msg the actual message
2103 * @return #GNUNET_OK (check deferred a bit)
2104 */
2105static int
2106check_client_decrypt (void *cls,
2107 const struct GNUNET_SECRETSHARING_DecryptRequestMessage *msg)
2108{
2109 /* we check later, it's complicated */
2110 return GNUNET_OK;
2111}
2112
2113
2114/**
2103 * Functions with this signature are called whenever a message is 2115 * Functions with this signature are called whenever a message is
2104 * received. 2116 * received.
2105 * 2117 *
2106 * @param cls closure 2118 * @param cls identification of the client
2107 * @param client identification of the client 2119 * @param msg the actual message
2108 * @param message the actual message
2109 */ 2120 */
2110static void handle_client_decrypt (void *cls, 2121static void
2111 struct GNUNET_SERVER_Client *client, 2122handle_client_decrypt (void *cls,
2112 const struct GNUNET_MessageHeader 2123 const struct GNUNET_SECRETSHARING_DecryptRequestMessage *msg)
2113 *message)
2114{ 2124{
2115 const struct GNUNET_SECRETSHARING_DecryptRequestMessage *msg = 2125 struct ClientState *cs = cls;
2116 (const void *) message;
2117 struct DecryptSession *ds; 2126 struct DecryptSession *ds;
2118 struct GNUNET_HashCode session_id; 2127 struct GNUNET_HashCode session_id;
2119 unsigned int i;
2120 2128
2129 if (NULL != cs->decrypt_session)
2130 {
2131 GNUNET_break (0);
2132 GNUNET_SERVICE_client_drop (cs->client);
2133 return;
2134 }
2121 ds = GNUNET_new (struct DecryptSession); 2135 ds = GNUNET_new (struct DecryptSession);
2122 // FIXME: check if session already exists 2136 cs->decrypt_session = ds;
2123 GNUNET_CONTAINER_DLL_insert (decrypt_sessions_head, decrypt_sessions_tail, ds); 2137 ds->cs = cs;
2124 ds->client = client;
2125 ds->client_mq = GNUNET_MQ_queue_for_server_client (client);
2126 ds->start = GNUNET_TIME_absolute_ntoh (msg->start); 2138 ds->start = GNUNET_TIME_absolute_ntoh (msg->start);
2127 ds->deadline = GNUNET_TIME_absolute_ntoh (msg->deadline); 2139 ds->deadline = GNUNET_TIME_absolute_ntoh (msg->deadline);
2128 ds->ciphertext = msg->ciphertext; 2140 ds->ciphertext = msg->ciphertext;
2129 2141
2130 ds->share = GNUNET_SECRETSHARING_share_read (&msg[1], ntohs (msg->header.size) - sizeof *msg, NULL); 2142 ds->share = GNUNET_SECRETSHARING_share_read (&msg[1],
2131 // FIXME: probably should be break rather than assert 2143 ntohs (msg->header.size) - sizeof (*msg),
2132 GNUNET_assert (NULL != ds->share); 2144 NULL);
2133 2145 if (NULL == ds->share)
2134 // FIXME: this is probably sufficient, but kdf/hash with all values would be nicer ... 2146 {
2135 GNUNET_CRYPTO_hash (&msg->ciphertext, sizeof (struct GNUNET_SECRETSHARING_Ciphertext), &session_id); 2147 GNUNET_break (0);
2148 GNUNET_SERVICE_client_drop (cs->client);
2149 return;
2150 }
2136 2151
2152 /* FIXME: this is probably sufficient, but kdf/hash with all values would be nicer ... */
2153 GNUNET_CRYPTO_hash (&msg->ciphertext,
2154 sizeof (struct GNUNET_SECRETSHARING_Ciphertext),
2155 &session_id);
2137 ds->consensus = GNUNET_CONSENSUS_create (cfg, 2156 ds->consensus = GNUNET_CONSENSUS_create (cfg,
2138 ds->share->num_peers, 2157 ds->share->num_peers,
2139 ds->share->peers, 2158 ds->share->peers,
@@ -2144,20 +2163,20 @@ static void handle_client_decrypt (void *cls,
2144 ds); 2163 ds);
2145 2164
2146 2165
2147 ds->info = GNUNET_new_array (ds->share->num_peers, struct DecryptPeerInfo); 2166 ds->info = GNUNET_new_array (ds->share->num_peers,
2148 for (i = 0; i < ds->share->num_peers; i++) 2167 struct DecryptPeerInfo);
2168 for (unsigned int i = 0; i < ds->share->num_peers; i++)
2149 { 2169 {
2150 ds->info[i].peer = ds->share->peers[i]; 2170 ds->info[i].peer = ds->share->peers[i];
2151 ds->info[i].original_index = ds->share->original_indices[i]; 2171 ds->info[i].original_index = ds->share->original_indices[i];
2152 } 2172 }
2153
2154 insert_decrypt_element (ds); 2173 insert_decrypt_element (ds);
2155 2174 GNUNET_CONSENSUS_conclude (ds->consensus,
2156 GNUNET_CONSENSUS_conclude (ds->consensus, decrypt_conclude, ds); 2175 decrypt_conclude,
2157 2176 ds);
2158 GNUNET_SERVER_receive_done (client, GNUNET_OK); 2177 GNUNET_SERVICE_client_continue (cs->client);
2159 2178 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2160 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "decrypting with %u peers\n", 2179 "decrypting with %u peers\n",
2161 ds->share->num_peers); 2180 ds->share->num_peers);
2162} 2181}
2163 2182
@@ -2174,103 +2193,104 @@ init_crypto_constants (void)
2174} 2193}
2175 2194
2176 2195
2177static struct KeygenSession *
2178keygen_session_get (struct GNUNET_SERVER_Client *client)
2179{
2180 struct KeygenSession *ks;
2181 for (ks = keygen_sessions_head; NULL != ks; ks = ks->next)
2182 if (ks->client == client)
2183 return ks;
2184 return NULL;
2185}
2186
2187static struct DecryptSession *
2188decrypt_session_get (struct GNUNET_SERVER_Client *client)
2189{
2190 struct DecryptSession *ds;
2191 for (ds = decrypt_sessions_head; NULL != ds; ds = ds->next)
2192 if (ds->client == client)
2193 return ds;
2194 return NULL;
2195}
2196
2197
2198/**
2199 * Clean up after a client has disconnected
2200 *
2201 * @param cls closure, unused
2202 * @param client the client to clean up after
2203 */
2204static void
2205handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
2206{
2207 struct KeygenSession *ks;
2208 struct DecryptSession *ds;
2209
2210 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "handling client disconnect\n");
2211
2212 ks = keygen_session_get (client);
2213 if (NULL != ks)
2214 keygen_session_destroy (ks);
2215
2216 ds = decrypt_session_get (client);
2217 if (NULL != ds)
2218 decrypt_session_destroy (ds);
2219}
2220
2221
2222/** 2196/**
2223 * Process template requests. 2197 * Initialize secretsharing service.
2224 * 2198 *
2225 * @param cls closure 2199 * @param cls closure
2226 * @param server the initialized server
2227 * @param c configuration to use 2200 * @param c configuration to use
2201 * @param service the initialized service
2228 */ 2202 */
2229static void 2203static void
2230run (void *cls, struct GNUNET_SERVER_Handle *server, 2204run (void *cls,
2231 const struct GNUNET_CONFIGURATION_Handle *c) 2205 const struct GNUNET_CONFIGURATION_Handle *c,
2206 struct GNUNET_SERVICE_Handle *service)
2232{ 2207{
2233 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
2234 {handle_client_keygen, NULL, GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_GENERATE, 0},
2235 {handle_client_decrypt, NULL, GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_DECRYPT, 0},
2236 {NULL, NULL, 0, 0}
2237 };
2238 cfg = c; 2208 cfg = c;
2239 srv = server;
2240 my_peer_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (c); 2209 my_peer_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (c);
2241 if (NULL == my_peer_private_key) 2210 if (NULL == my_peer_private_key)
2242 { 2211 {
2243 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "could not access host private key\n"); 2212 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2213 "could not access host private key\n");
2244 GNUNET_break (0); 2214 GNUNET_break (0);
2245 GNUNET_SCHEDULER_shutdown (); 2215 GNUNET_SCHEDULER_shutdown ();
2246 return; 2216 return;
2247 } 2217 }
2248 init_crypto_constants (); 2218 init_crypto_constants ();
2249 if (GNUNET_OK != GNUNET_CRYPTO_get_peer_identity (cfg, &my_peer)) 2219 if (GNUNET_OK !=
2220 GNUNET_CRYPTO_get_peer_identity (cfg,
2221 &my_peer))
2250 { 2222 {
2251 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "could not retrieve host identity\n"); 2223 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2224 "could not retrieve host identity\n");
2252 GNUNET_break (0); 2225 GNUNET_break (0);
2253 GNUNET_SCHEDULER_shutdown (); 2226 GNUNET_SCHEDULER_shutdown ();
2254 return; 2227 return;
2255 } 2228 }
2256 GNUNET_SERVER_add_handlers (server, handlers);
2257 GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL);
2258 GNUNET_SCHEDULER_add_shutdown (&cleanup_task, 2229 GNUNET_SCHEDULER_add_shutdown (&cleanup_task,
2259 NULL); 2230 NULL);
2260} 2231}
2261 2232
2262 2233
2263/** 2234/**
2264 * The main function for the template service. 2235 * Callback called when a client connects to the service.
2236 *
2237 * @param cls closure for the service
2238 * @param c the new client that connected to the service
2239 * @param mq the message queue used to send messages to the client
2240 * @return @a c
2241 */
2242static void *
2243client_connect_cb (void *cls,
2244 struct GNUNET_SERVICE_Client *c,
2245 struct GNUNET_MQ_Handle *mq)
2246{
2247 struct ClientState *cs = GNUNET_new (struct ClientState);;
2248
2249 cs->client = c;
2250 cs->mq = mq;
2251 return cs;
2252}
2253
2254
2255/**
2256 * Callback called when a client disconnected from the service
2265 * 2257 *
2266 * @param argc number of arguments from the command line 2258 * @param cls closure for the service
2267 * @param argv command line arguments 2259 * @param c the client that disconnected
2268 * @return 0 ok, 1 on error 2260 * @param internal_cls should be equal to @a c
2269 */ 2261 */
2270int 2262static void
2271main (int argc, char *const *argv) 2263client_disconnect_cb (void *cls,
2264 struct GNUNET_SERVICE_Client *c,
2265 void *internal_cls)
2272{ 2266{
2273 return (GNUNET_OK == 2267 struct ClientState *cs = internal_cls;
2274 GNUNET_SERVICE_run (argc, argv, "secretsharing", 2268
2275 GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1; 2269 if (NULL != cs->keygen_session)
2270 keygen_session_destroy (cs->keygen_session);
2271
2272 if (NULL != cs->decrypt_session)
2273 decrypt_session_destroy (cs->decrypt_session);
2274 GNUNET_free (cs);
2276} 2275}
2276
2277
2278/**
2279 * Define "main" method using service macro.
2280 */
2281GNUNET_SERVICE_MAIN
2282("secretsharing",
2283 GNUNET_SERVICE_OPTION_NONE,
2284 &run,
2285 &client_connect_cb,
2286 &client_disconnect_cb,
2287 NULL,
2288 GNUNET_MQ_hd_var_size (client_keygen,
2289 GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_GENERATE,
2290 struct GNUNET_SECRETSHARING_CreateMessage,
2291 NULL),
2292 GNUNET_MQ_hd_var_size (client_decrypt,
2293 GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_DECRYPT,
2294 struct GNUNET_SECRETSHARING_DecryptRequestMessage,
2295 NULL),
2296 GNUNET_MQ_handler_end ());
diff --git a/src/set/Makefile.am b/src/set/Makefile.am
index cfe95bc1a..14667d0ef 100644
--- a/src/set/Makefile.am
+++ b/src/set/Makefile.am
@@ -51,7 +51,7 @@ gnunet_set_ibf_profiler_LDADD = \
51 51
52gnunet_service_set_SOURCES = \ 52gnunet_service_set_SOURCES = \
53 gnunet-service-set.c gnunet-service-set.h \ 53 gnunet-service-set.c gnunet-service-set.h \
54 gnunet-service-set_union.c \ 54 gnunet-service-set_union.c gnunet-service-set_union.h \
55 gnunet-service-set_intersection.c \ 55 gnunet-service-set_intersection.c \
56 ibf.c ibf.h \ 56 ibf.c ibf.h \
57 gnunet-service-set_union_strata_estimator.c gnunet-service-set_union_strata_estimator.h \ 57 gnunet-service-set_union_strata_estimator.c gnunet-service-set_union_strata_estimator.h \
@@ -60,7 +60,7 @@ gnunet_service_set_LDADD = \
60 $(top_builddir)/src/util/libgnunetutil.la \ 60 $(top_builddir)/src/util/libgnunetutil.la \
61 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 61 $(top_builddir)/src/statistics/libgnunetstatistics.la \
62 $(top_builddir)/src/core/libgnunetcore.la \ 62 $(top_builddir)/src/core/libgnunetcore.la \
63 $(top_builddir)/src/cadet/libgnunetcadetnew.la \ 63 $(top_builddir)/src/cadet/libgnunetcadet.la \
64 $(top_builddir)/src/block/libgnunetblock.la \ 64 $(top_builddir)/src/block/libgnunetblock.la \
65 libgnunetset.la \ 65 libgnunetset.la \
66 $(GN_LIBINTL) 66 $(GN_LIBINTL)
diff --git a/src/set/gnunet-service-set.c b/src/set/gnunet-service-set.c
index 30d43e8a1..12af653c1 100644
--- a/src/set/gnunet-service-set.c
+++ b/src/set/gnunet-service-set.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet 2 This file is part of GNUnet
3 Copyright (C) 2013, 2014, 2017 GNUnet e.V. 3 Copyright (C) 2013-2017 GNUnet e.V.
4 4
5 GNUnet is free software; you can redistribute it and/or modify 5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published 6 it under the terms of the GNU General Public License as published
@@ -24,6 +24,8 @@
24 * @author Christian Grothoff 24 * @author Christian Grothoff
25 */ 25 */
26#include "gnunet-service-set.h" 26#include "gnunet-service-set.h"
27#include "gnunet-service-set_union.h"
28#include "gnunet-service-set_intersection.h"
27#include "gnunet-service-set_protocol.h" 29#include "gnunet-service-set_protocol.h"
28#include "gnunet_statistics_service.h" 30#include "gnunet_statistics_service.h"
29 31
@@ -33,6 +35,35 @@
33 */ 35 */
34#define INCOMING_CHANNEL_TIMEOUT GNUNET_TIME_UNIT_MINUTES 36#define INCOMING_CHANNEL_TIMEOUT GNUNET_TIME_UNIT_MINUTES
35 37
38
39/**
40 * Lazy copy requests made by a client.
41 */
42struct LazyCopyRequest
43{
44 /**
45 * Kept in a DLL.
46 */
47 struct LazyCopyRequest *prev;
48
49 /**
50 * Kept in a DLL.
51 */
52 struct LazyCopyRequest *next;
53
54 /**
55 * Which set are we supposed to copy?
56 */
57 struct Set *source_set;
58
59 /**
60 * Cookie identifying the request.
61 */
62 uint32_t cookie;
63
64};
65
66
36/** 67/**
37 * A listener is inhabited by a client, and waits for evaluation 68 * A listener is inhabited by a client, and waits for evaluation
38 * requests from remote peers. 69 * requests from remote peers.
@@ -50,21 +81,24 @@ struct Listener
50 struct Listener *prev; 81 struct Listener *prev;
51 82
52 /** 83 /**
53 * Client that owns the listener. 84 * Head of DLL of operations this listener is responsible for.
54 * Only one client may own a listener. 85 * Once the client has accepted/declined the operation, the
86 * operation is moved to the respective set's operation DLLS.
55 */ 87 */
56 struct GNUNET_SERVICE_Client *client; 88 struct Operation *op_head;
57 89
58 /** 90 /**
59 * Message queue for the client 91 * Tail of DLL of operations this listener is responsible for.
92 * Once the client has accepted/declined the operation, the
93 * operation is moved to the respective set's operation DLLS.
60 */ 94 */
61 struct GNUNET_MQ_Handle *client_mq; 95 struct Operation *op_tail;
62 96
63 /** 97 /**
64 * Application ID for the operation, used to distinguish 98 * Client that owns the listener.
65 * multiple operations of the same type with the same peer. 99 * Only one client may own a listener.
66 */ 100 */
67 struct GNUNET_HashCode app_id; 101 struct ClientState *cs;
68 102
69 /** 103 /**
70 * The port we are listening on with CADET. 104 * The port we are listening on with CADET.
@@ -72,27 +106,18 @@ struct Listener
72 struct GNUNET_CADET_Port *open_port; 106 struct GNUNET_CADET_Port *open_port;
73 107
74 /** 108 /**
109 * Application ID for the operation, used to distinguish
110 * multiple operations of the same type with the same peer.
111 */
112 struct GNUNET_HashCode app_id;
113
114 /**
75 * The type of the operation. 115 * The type of the operation.
76 */ 116 */
77 enum GNUNET_SET_OperationType operation; 117 enum GNUNET_SET_OperationType operation;
78}; 118};
79 119
80 120
81struct LazyCopyRequest
82{
83 struct Set *source_set;
84 uint32_t cookie;
85
86 struct LazyCopyRequest *prev;
87 struct LazyCopyRequest *next;
88};
89
90
91/**
92 * Configuration of our local peer.
93 */
94static const struct GNUNET_CONFIGURATION_Handle *configuration;
95
96/** 121/**
97 * Handle to the cadet service, used to listen for and connect to 122 * Handle to the cadet service, used to listen for and connect to
98 * remote peers. 123 * remote peers.
@@ -100,96 +125,48 @@ static const struct GNUNET_CONFIGURATION_Handle *configuration;
100static struct GNUNET_CADET_Handle *cadet; 125static struct GNUNET_CADET_Handle *cadet;
101 126
102/** 127/**
103 * Sets are held in a doubly linked list. 128 * DLL of lazy copy requests by this client.
104 */ 129 */
105static struct Set *sets_head; 130static struct LazyCopyRequest *lazy_copy_head;
106 131
107/** 132/**
108 * Sets are held in a doubly linked list. 133 * DLL of lazy copy requests by this client.
109 */ 134 */
110static struct Set *sets_tail; 135static struct LazyCopyRequest *lazy_copy_tail;
111 136
112/** 137/**
113 * Listeners are held in a doubly linked list. 138 * Generator for unique cookie we set per lazy copy request.
114 */ 139 */
115static struct Listener *listeners_head; 140static uint32_t lazy_copy_cookie;
116 141
117/** 142/**
118 * Listeners are held in a doubly linked list. 143 * Statistics handle.
119 */ 144 */
120static struct Listener *listeners_tail; 145struct GNUNET_STATISTICS_Handle *_GSS_statistics;
121 146
122/** 147/**
123 * Incoming sockets from remote peers are held in a doubly linked 148 * Listeners are held in a doubly linked list.
124 * list.
125 */ 149 */
126static struct Operation *incoming_head; 150static struct Listener *listener_head;
127 151
128/** 152/**
129 * Incoming sockets from remote peers are held in a doubly linked 153 * Listeners are held in a doubly linked list.
130 * list.
131 */ 154 */
132static struct Operation *incoming_tail; 155static struct Listener *listener_tail;
133
134static struct LazyCopyRequest *lazy_copy_head;
135static struct LazyCopyRequest *lazy_copy_tail;
136
137static uint32_t lazy_copy_cookie = 1;
138 156
139/** 157/**
140 * Counter for allocating unique IDs for clients, used to identify 158 * Counter for allocating unique IDs for clients, used to identify
141 * incoming operation requests from remote peers, that the client can 159 * incoming operation requests from remote peers, that the client can
142 * choose to accept or refuse. 160 * choose to accept or refuse. 0 must not be used (reserved for
161 * uninitialized).
143 */ 162 */
144static uint32_t suggest_id = 1; 163static uint32_t suggest_id;
145
146/**
147 * Statistics handle.
148 */
149struct GNUNET_STATISTICS_Handle *_GSS_statistics;
150
151
152/**
153 * Get set that is owned by the given client, if any.
154 *
155 * @param client client to look for
156 * @return set that the client owns, NULL if the client
157 * does not own a set
158 */
159static struct Set *
160set_get (struct GNUNET_SERVICE_Client *client)
161{
162 struct Set *set;
163
164 for (set = sets_head; NULL != set; set = set->next)
165 if (set->client == client)
166 return set;
167 return NULL;
168}
169
170
171/**
172 * Get the listener associated with the given client, if any.
173 *
174 * @param client the client
175 * @return listener associated with the client, NULL
176 * if there isn't any
177 */
178static struct Listener *
179listener_get (struct GNUNET_SERVICE_Client *client)
180{
181 struct Listener *listener;
182
183 for (listener = listeners_head; NULL != listener; listener = listener->next)
184 if (listener->client == client)
185 return listener;
186 return NULL;
187}
188 164
189 165
190/** 166/**
191 * Get the incoming socket associated with the given id. 167 * Get the incoming socket associated with the given id.
192 * 168 *
169 * @param listener the listener to look in
193 * @param id id to look for 170 * @param id id to look for
194 * @return the incoming socket associated with the id, 171 * @return the incoming socket associated with the id,
195 * or NULL if there is none 172 * or NULL if there is none
@@ -197,43 +174,49 @@ listener_get (struct GNUNET_SERVICE_Client *client)
197static struct Operation * 174static struct Operation *
198get_incoming (uint32_t id) 175get_incoming (uint32_t id)
199{ 176{
200 struct Operation *op; 177 for (struct Listener *listener = listener_head;
201 178 NULL != listener;
202 for (op = incoming_head; NULL != op; op = op->next) 179 listener = listener->next)
203 if (op->suggest_id == id) 180 {
204 { 181 for (struct Operation *op = listener->op_head; NULL != op; op = op->next)
205 GNUNET_assert (GNUNET_YES == op->is_incoming); 182 if (op->suggest_id == id)
206 return op; 183 return op;
207 } 184 }
208 return NULL; 185 return NULL;
209} 186}
210 187
211 188
212/** 189/**
213 * Destroy a listener, free all resources associated with it. 190 * Destroy an incoming request from a remote peer
214 * 191 *
215 * @param listener listener to destroy 192 * @param op remote request to destroy
216 */ 193 */
217static void 194static void
218listener_destroy (struct Listener *listener) 195incoming_destroy (struct Operation *op)
219{ 196{
220 /* If the client is not dead yet, destroy it. 197 struct Listener *listener;
221 * The client's destroy callback will destroy the listener again. */ 198 struct GNUNET_CADET_Channel *channel;
222 if (NULL != listener->client)
223 {
224 struct GNUNET_SERVICE_Client *client = listener->client;
225 199
226 listener->client = NULL; 200 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
227 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 201 "Destroying incoming operation %p\n",
228 "Disconnecting listener client\n"); 202 op);
229 GNUNET_SERVICE_client_drop (client); 203 if (NULL != (listener = op->listener))
230 return; 204 {
205 GNUNET_CONTAINER_DLL_remove (listener->op_head,
206 listener->op_tail,
207 op);
208 op->listener = NULL;
209 }
210 if (NULL != op->timeout_task)
211 {
212 GNUNET_SCHEDULER_cancel (op->timeout_task);
213 op->timeout_task = NULL;
214 }
215 if (NULL != (channel = op->channel))
216 {
217 op->channel = NULL;
218 GNUNET_CADET_channel_destroy (channel);
231 } 219 }
232 GNUNET_CADET_close_port (listener->open_port);
233 GNUNET_CONTAINER_DLL_remove (listeners_head,
234 listeners_tail,
235 listener);
236 GNUNET_free (listener);
237} 220}
238 221
239 222
@@ -303,12 +286,11 @@ garbage_collect_cb (void *cls,
303static void 286static void
304collect_generation_garbage (struct Set *set) 287collect_generation_garbage (struct Set *set)
305{ 288{
306 struct Operation *op;
307 struct GarbageContext gc; 289 struct GarbageContext gc;
308 290
309 gc.min_op_generation = UINT_MAX; 291 gc.min_op_generation = UINT_MAX;
310 gc.max_op_generation = 0; 292 gc.max_op_generation = 0;
311 for (op = set->ops_head; NULL != op; op = op->next) 293 for (struct Operation *op = set->ops_head; NULL != op; op = op->next)
312 { 294 {
313 gc.min_op_generation = GNUNET_MIN (gc.min_op_generation, 295 gc.min_op_generation = GNUNET_MIN (gc.min_op_generation,
314 op->generation_created); 296 op->generation_created);
@@ -322,23 +304,36 @@ collect_generation_garbage (struct Set *set)
322} 304}
323 305
324 306
307/**
308 * Is @a generation in the range of exclusions?
309 *
310 * @param generation generation to query
311 * @param excluded array of generations where the element is excluded
312 * @param excluded_size length of the @a excluded array
313 * @return #GNUNET_YES if @a generation is in any of the ranges
314 */
325static int 315static int
326is_excluded_generation (unsigned int generation, 316is_excluded_generation (unsigned int generation,
327 struct GenerationRange *excluded, 317 struct GenerationRange *excluded,
328 unsigned int excluded_size) 318 unsigned int excluded_size)
329{ 319{
330 unsigned int i; 320 for (unsigned int i = 0; i < excluded_size; i++)
331 321 if ( (generation >= excluded[i].start) &&
332 for (i = 0; i < excluded_size; i++) 322 (generation < excluded[i].end) )
333 {
334 if ( (generation >= excluded[i].start) && (generation < excluded[i].end) )
335 return GNUNET_YES; 323 return GNUNET_YES;
336 }
337
338 return GNUNET_NO; 324 return GNUNET_NO;
339} 325}
340 326
341 327
328/**
329 * Is element @a ee part of the set during @a query_generation?
330 *
331 * @param ee element to test
332 * @param query_generation generation to query
333 * @param excluded array of generations where the element is excluded
334 * @param excluded_size length of the @a excluded array
335 * @return #GNUNET_YES if the element is in the set, #GNUNET_NO if not
336 */
342static int 337static int
343is_element_of_generation (struct ElementEntry *ee, 338is_element_of_generation (struct ElementEntry *ee,
344 unsigned int query_generation, 339 unsigned int query_generation,
@@ -347,11 +342,12 @@ is_element_of_generation (struct ElementEntry *ee,
347{ 342{
348 struct MutationEvent *mut; 343 struct MutationEvent *mut;
349 int is_present; 344 int is_present;
350 unsigned int i;
351 345
352 GNUNET_assert (NULL != ee->mutations); 346 GNUNET_assert (NULL != ee->mutations);
353 347 if (GNUNET_YES ==
354 if (GNUNET_YES == is_excluded_generation (query_generation, excluded, excluded_size)) 348 is_excluded_generation (query_generation,
349 excluded,
350 excluded_size))
355 { 351 {
356 GNUNET_break (0); 352 GNUNET_break (0);
357 return GNUNET_NO; 353 return GNUNET_NO;
@@ -361,7 +357,7 @@ is_element_of_generation (struct ElementEntry *ee,
361 357
362 /* Could be made faster with binary search, but lists 358 /* Could be made faster with binary search, but lists
363 are small, so why bother. */ 359 are small, so why bother. */
364 for (i = 0; i < ee->mutations_size; i++) 360 for (unsigned int i = 0; i < ee->mutations_size; i++)
365 { 361 {
366 mut = &ee->mutations[i]; 362 mut = &ee->mutations[i];
367 363
@@ -373,7 +369,10 @@ is_element_of_generation (struct ElementEntry *ee,
373 continue; 369 continue;
374 } 370 }
375 371
376 if (GNUNET_YES == is_excluded_generation (mut->generation, excluded, excluded_size)) 372 if (GNUNET_YES ==
373 is_excluded_generation (mut->generation,
374 excluded,
375 excluded_size))
377 { 376 {
378 /* The generation is excluded (because it belongs to another 377 /* The generation is excluded (because it belongs to another
379 fork via a lazy copy) and thus mutations aren't considered 378 fork via a lazy copy) and thus mutations aren't considered
@@ -382,11 +381,12 @@ is_element_of_generation (struct ElementEntry *ee,
382 } 381 }
383 382
384 /* This would be an inconsistency in how we manage mutations. */ 383 /* This would be an inconsistency in how we manage mutations. */
385 if ( (GNUNET_YES == is_present) && (GNUNET_YES == mut->added) ) 384 if ( (GNUNET_YES == is_present) &&
385 (GNUNET_YES == mut->added) )
386 GNUNET_assert (0); 386 GNUNET_assert (0);
387
388 /* Likewise. */ 387 /* Likewise. */
389 if ( (GNUNET_NO == is_present) && (GNUNET_NO == mut->added) ) 388 if ( (GNUNET_NO == is_present) &&
389 (GNUNET_NO == mut->added) )
390 GNUNET_assert (0); 390 GNUNET_assert (0);
391 391
392 is_present = mut->added; 392 is_present = mut->added;
@@ -396,44 +396,33 @@ is_element_of_generation (struct ElementEntry *ee,
396} 396}
397 397
398 398
399int 399/**
400_GSS_is_element_of_set (struct ElementEntry *ee, 400 * Is element @a ee part of the set used by @a op?
401 struct Set *set) 401 *
402{ 402 * @param ee element to test
403 return is_element_of_generation (ee, 403 * @param op operation the defines the set and its generation
404 set->current_generation, 404 * @return #GNUNET_YES if the element is in the set, #GNUNET_NO if not
405 set->excluded_generations, 405 */
406 set->excluded_generations_size);
407}
408
409
410static int
411is_element_of_iteration (struct ElementEntry *ee,
412 struct Set *set)
413{
414 return is_element_of_generation (ee,
415 set->iter_generation,
416 set->excluded_generations,
417 set->excluded_generations_size);
418}
419
420
421int 406int
422_GSS_is_element_of_operation (struct ElementEntry *ee, 407_GSS_is_element_of_operation (struct ElementEntry *ee,
423 struct Operation *op) 408 struct Operation *op)
424{ 409{
425 return is_element_of_generation (ee, 410 return is_element_of_generation (ee,
426 op->generation_created, 411 op->generation_created,
427 op->spec->set->excluded_generations, 412 op->set->excluded_generations,
428 op->spec->set->excluded_generations_size); 413 op->set->excluded_generations_size);
429} 414}
430 415
431 416
432/** 417/**
433 * Destroy the given operation. Call the implementation-specific 418 * Destroy the given operation. Used for any operation where both
434 * cancel function of the operation. Disconnects from the remote 419 * peers were known and that thus actually had a vt and channel. Must
435 * peer. Does not disconnect the client, as there may be multiple 420 * not be used for operations where 'listener' is still set and we do
436 * operations per set. 421 * not know the other peer.
422 *
423 * Call the implementation-specific cancel function of the operation.
424 * Disconnects from the remote peer. Does not disconnect the client,
425 * as there may be multiple operations per set.
437 * 426 *
438 * @param op operation to destroy 427 * @param op operation to destroy
439 * @param gc #GNUNET_YES to perform garbage collection on the set 428 * @param gc #GNUNET_YES to perform garbage collection on the set
@@ -442,38 +431,39 @@ void
442_GSS_operation_destroy (struct Operation *op, 431_GSS_operation_destroy (struct Operation *op,
443 int gc) 432 int gc)
444{ 433{
445 struct Set *set; 434 struct Set *set = op->set;
446 struct GNUNET_CADET_Channel *channel; 435 struct GNUNET_CADET_Channel *channel;
447 436
448 if (NULL == op->vt) 437 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
438 "Destroying operation %p\n",
439 op);
440 GNUNET_assert (NULL == op->listener);
441 if (NULL != op->state)
449 { 442 {
450 /* already in #_GSS_operation_destroy() */ 443 set->vt->cancel (op);
451 return; 444 op->state = NULL;
452 } 445 }
453 GNUNET_assert (GNUNET_NO == op->is_incoming); 446 if (NULL != set)
454 GNUNET_assert (NULL != op->spec);
455 set = op->spec->set;
456 GNUNET_CONTAINER_DLL_remove (set->ops_head,
457 set->ops_tail,
458 op);
459 op->vt->cancel (op);
460 op->vt = NULL;
461 if (NULL != op->spec)
462 { 447 {
463 if (NULL != op->spec->context_msg) 448 GNUNET_CONTAINER_DLL_remove (set->ops_head,
464 { 449 set->ops_tail,
465 GNUNET_free (op->spec->context_msg); 450 op);
466 op->spec->context_msg = NULL; 451 op->set = NULL;
467 } 452 }
468 GNUNET_free (op->spec); 453 if (NULL != op->context_msg)
469 op->spec = NULL; 454 {
455 GNUNET_free (op->context_msg);
456 op->context_msg = NULL;
470 } 457 }
471 if (NULL != (channel = op->channel)) 458 if (NULL != (channel = op->channel))
472 { 459 {
460 /* This will free op; called conditionally as this helper function
461 is also called from within the channel disconnect handler. */
473 op->channel = NULL; 462 op->channel = NULL;
474 GNUNET_CADET_channel_destroy (channel); 463 GNUNET_CADET_channel_destroy (channel);
475 } 464 }
476 if (GNUNET_YES == gc) 465 if ( (NULL != set) &&
466 (GNUNET_YES == gc) )
477 collect_generation_garbage (set); 467 collect_generation_garbage (set);
478 /* We rely on the channel end handler to free 'op'. When 'op->channel' was NULL, 468 /* We rely on the channel end handler to free 'op'. When 'op->channel' was NULL,
479 * there was a channel end handler that will free 'op' on the call stack. */ 469 * there was a channel end handler that will free 'op' on the call stack. */
@@ -481,6 +471,28 @@ _GSS_operation_destroy (struct Operation *op,
481 471
482 472
483/** 473/**
474 * Callback called when a client connects to the service.
475 *
476 * @param cls closure for the service
477 * @param c the new client that connected to the service
478 * @param mq the message queue used to send messages to the client
479 * @return @a `struct ClientState`
480 */
481static void *
482client_connect_cb (void *cls,
483 struct GNUNET_SERVICE_Client *c,
484 struct GNUNET_MQ_Handle *mq)
485{
486 struct ClientState *cs;
487
488 cs = GNUNET_new (struct ClientState);
489 cs->client = c;
490 cs->mq = mq;
491 return cs;
492}
493
494
495/**
484 * Iterator over hash map entries to free element entries. 496 * Iterator over hash map entries to free element entries.
485 * 497 *
486 * @param cls closure 498 * @param cls closure
@@ -496,66 +508,76 @@ destroy_elements_iterator (void *cls,
496 struct ElementEntry *ee = value; 508 struct ElementEntry *ee = value;
497 509
498 GNUNET_free_non_null (ee->mutations); 510 GNUNET_free_non_null (ee->mutations);
499
500 GNUNET_free (ee); 511 GNUNET_free (ee);
501 return GNUNET_YES; 512 return GNUNET_YES;
502} 513}
503 514
504 515
505/** 516/**
506 * Destroy a set, and free all resources and operations associated with it. 517 * Clean up after a client has disconnected
507 * 518 *
508 * @param set the set to destroy 519 * @param cls closure, unused
520 * @param client the client to clean up after
521 * @param internal_cls the `struct ClientState`
509 */ 522 */
510static void 523static void
511set_destroy (struct Set *set) 524client_disconnect_cb (void *cls,
525 struct GNUNET_SERVICE_Client *client,
526 void *internal_cls)
512{ 527{
513 if (NULL != set->client) 528 struct ClientState *cs = internal_cls;
514 { 529 struct Operation *op;
515 /* If the client is not dead yet, destroy it. The client's destroy 530 struct Listener *listener;
516 * callback will call `set_destroy()` again in this case. We do 531 struct Set *set;
517 * this so that the channel end handler still has a valid set handle 532
518 * to destroy. */ 533 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
519 struct GNUNET_SERVICE_Client *client = set->client; 534 "Client disconnected, cleaning up\n");
520 535 if (NULL != (set = cs->set))
521 set->client = NULL;
522 GNUNET_SERVICE_client_drop (client);
523 return;
524 }
525 GNUNET_assert (NULL != set->state);
526 while (NULL != set->ops_head)
527 _GSS_operation_destroy (set->ops_head, GNUNET_NO);
528 set->vt->destroy_set (set->state);
529 set->state = NULL;
530 if (NULL != set->iter)
531 {
532 GNUNET_CONTAINER_multihashmap_iterator_destroy (set->iter);
533 set->iter = NULL;
534 set->iteration_id++;
535 }
536 { 536 {
537 struct SetContent *content; 537 struct SetContent *content = set->content;
538 struct PendingMutation *pm; 538 struct PendingMutation *pm;
539 struct PendingMutation *pm_current; 539 struct PendingMutation *pm_current;
540 struct LazyCopyRequest *lcr;
540 541
541 content = set->content; 542 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
543 "Destroying client's set\n");
544 /* Destroy pending set operations */
545 while (NULL != set->ops_head)
546 _GSS_operation_destroy (set->ops_head,
547 GNUNET_NO);
548
549 /* Destroy operation-specific state */
550 GNUNET_assert (NULL != set->state);
551 set->vt->destroy_set (set->state);
552 set->state = NULL;
553
554 /* Clean up ongoing iterations */
555 if (NULL != set->iter)
556 {
557 GNUNET_CONTAINER_multihashmap_iterator_destroy (set->iter);
558 set->iter = NULL;
559 set->iteration_id++;
560 }
542 561
543 // discard any pending mutations that reference this set 562 /* discard any pending mutations that reference this set */
544 pm = content->pending_mutations_head; 563 pm = content->pending_mutations_head;
545 while (NULL != pm) 564 while (NULL != pm)
546 { 565 {
547 pm_current = pm; 566 pm_current = pm;
548 pm = pm->next; 567 pm = pm->next;
549 if (pm_current-> set == set) 568 if (pm_current->set == set)
569 {
550 GNUNET_CONTAINER_DLL_remove (content->pending_mutations_head, 570 GNUNET_CONTAINER_DLL_remove (content->pending_mutations_head,
551 content->pending_mutations_tail, 571 content->pending_mutations_tail,
552 pm_current); 572 pm_current);
553 573 GNUNET_free (pm_current);
574 }
554 } 575 }
555 576
577 /* free set content (or at least decrement RC) */
556 set->content = NULL; 578 set->content = NULL;
557 GNUNET_assert (0 != content->refcount); 579 GNUNET_assert (0 != content->refcount);
558 content->refcount -= 1; 580 content->refcount--;
559 if (0 == content->refcount) 581 if (0 == content->refcount)
560 { 582 {
561 GNUNET_assert (NULL != content->elements); 583 GNUNET_assert (NULL != content->elements);
@@ -566,154 +588,85 @@ set_destroy (struct Set *set)
566 content->elements = NULL; 588 content->elements = NULL;
567 GNUNET_free (content); 589 GNUNET_free (content);
568 } 590 }
569 } 591 GNUNET_free_non_null (set->excluded_generations);
570 GNUNET_free_non_null (set->excluded_generations); 592 set->excluded_generations = NULL;
571 set->excluded_generations = NULL;
572 GNUNET_CONTAINER_DLL_remove (sets_head,
573 sets_tail,
574 set);
575 593
576 // remove set from pending copy requests 594 /* remove set from pending copy requests */
577 {
578 struct LazyCopyRequest *lcr;
579 lcr = lazy_copy_head; 595 lcr = lazy_copy_head;
580 while (NULL != lcr) 596 while (NULL != lcr)
581 { 597 {
582 struct LazyCopyRequest *lcr_current; 598 struct LazyCopyRequest *lcr_current = lcr;
583 lcr_current = lcr; 599
584 lcr = lcr->next; 600 lcr = lcr->next;
585 if (lcr_current->source_set == set) 601 if (lcr_current->source_set == set)
602 {
586 GNUNET_CONTAINER_DLL_remove (lazy_copy_head, 603 GNUNET_CONTAINER_DLL_remove (lazy_copy_head,
587 lazy_copy_tail, 604 lazy_copy_tail,
588 lcr_current); 605 lcr_current);
606 GNUNET_free (lcr_current);
607 }
589 } 608 }
609 GNUNET_free (set);
590 } 610 }
591 611
592 GNUNET_free (set); 612 if (NULL != (listener = cs->listener))
593}
594
595
596/**
597 * Callback called when a client connects to the service.
598 *
599 * @param cls closure for the service
600 * @param c the new client that connected to the service
601 * @param mq the message queue used to send messages to the client
602 * @return @a c
603 */
604static void *
605client_connect_cb (void *cls,
606 struct GNUNET_SERVICE_Client *c,
607 struct GNUNET_MQ_Handle *mq)
608{
609 return c;
610}
611
612
613/**
614 * Clean up after a client has disconnected
615 *
616 * @param cls closure, unused
617 * @param client the client to clean up after
618 * @param internal_cls our client-specific internal data structure
619 */
620static void
621client_disconnect_cb (void *cls,
622 struct GNUNET_SERVICE_Client *client,
623 void *internal_cls)
624{
625 struct Listener *listener;
626 struct Set *set;
627
628 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
629 "client disconnected, cleaning up\n");
630 set = set_get (client);
631 if (NULL != set)
632 { 613 {
633 set->client = NULL;
634 set_destroy (set);
635 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 614 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
636 "Client's set destroyed\n"); 615 "Destroying client's listener\n");
637 } 616 GNUNET_CADET_close_port (listener->open_port);
638 listener = listener_get (client); 617 listener->open_port = NULL;
639 if (NULL != listener) 618 while (NULL != (op = listener->op_head))
640 { 619 incoming_destroy (op);
641 listener->client = NULL; 620 GNUNET_CONTAINER_DLL_remove (listener_head,
642 listener_destroy (listener); 621 listener_tail,
643 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 622 listener);
644 "Client's listener destroyed\n"); 623 GNUNET_free (listener);
645 } 624 }
625 GNUNET_free (cs);
646} 626}
647 627
648 628
649/** 629/**
650 * Destroy an incoming request from a remote peer 630 * Check a request for a set operation from another peer.
651 * 631 *
652 * @param incoming remote request to destroy 632 * @param cls the operation state
633 * @param msg the received message
634 * @return #GNUNET_OK if the channel should be kept alive,
635 * #GNUNET_SYSERR to destroy the channel
653 */ 636 */
654static void 637static int
655incoming_destroy (struct Operation *incoming) 638check_incoming_msg (void *cls,
639 const struct OperationRequestMessage *msg)
656{ 640{
657 struct GNUNET_CADET_Channel *channel; 641 struct Operation *op = cls;
642 struct Listener *listener = op->listener;
643 const struct GNUNET_MessageHeader *nested_context;
658 644
659 GNUNET_assert (GNUNET_YES == incoming->is_incoming); 645 /* double operation request */
660 GNUNET_CONTAINER_DLL_remove (incoming_head, 646 if (0 != op->suggest_id)
661 incoming_tail,
662 incoming);
663 if (NULL != incoming->timeout_task)
664 { 647 {
665 GNUNET_SCHEDULER_cancel (incoming->timeout_task); 648 GNUNET_break_op (0);
666 incoming->timeout_task = NULL; 649 return GNUNET_SYSERR;
667 } 650 }
668 /* make sure that the tunnel end handler will not destroy us again */ 651 /* This should be equivalent to the previous condition, but can't hurt to check twice */
669 incoming->vt = NULL; 652 if (NULL == op->listener)
670 if (NULL != incoming->spec)
671 { 653 {
672 GNUNET_free (incoming->spec); 654 GNUNET_break (0);
673 incoming->spec = NULL; 655 return GNUNET_SYSERR;
674 } 656 }
675 if (NULL != (channel = incoming->channel)) 657 if (listener->operation != (enum GNUNET_SET_OperationType) ntohl (msg->operation))
676 { 658 {
677 incoming->channel = NULL; 659 GNUNET_break_op (0);
678 GNUNET_CADET_channel_destroy (channel); 660 return GNUNET_SYSERR;
679 } 661 }
680} 662 nested_context = GNUNET_MQ_extract_nested_mh (msg);
681 663 if ( (NULL != nested_context) &&
682 664 (ntohs (nested_context->size) > GNUNET_SET_CONTEXT_MESSAGE_MAX_SIZE) )
683/** 665 {
684 * Suggest the given request to the listener. The listening client can 666 GNUNET_break_op (0);
685 * then accept or reject the remote request. 667 return GNUNET_SYSERR;
686 * 668 }
687 * @param incoming the incoming peer with the request to suggest 669 return GNUNET_OK;
688 * @param listener the listener to suggest the request to
689 */
690static void
691incoming_suggest (struct Operation *incoming,
692 struct Listener *listener)
693{
694 struct GNUNET_MQ_Envelope *mqm;
695 struct GNUNET_SET_RequestMessage *cmsg;
696
697 GNUNET_assert (GNUNET_YES == incoming->is_incoming);
698 GNUNET_assert (NULL != incoming->spec);
699 GNUNET_assert (0 == incoming->suggest_id);
700 incoming->suggest_id = suggest_id++;
701 if (0 == suggest_id)
702 suggest_id++;
703 GNUNET_assert (NULL != incoming->timeout_task);
704 GNUNET_SCHEDULER_cancel (incoming->timeout_task);
705 incoming->timeout_task = NULL;
706 mqm = GNUNET_MQ_msg_nested_mh (cmsg,
707 GNUNET_MESSAGE_TYPE_SET_REQUEST,
708 incoming->spec->context_msg);
709 GNUNET_assert (NULL != mqm);
710 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
711 "Suggesting incoming request with accept id %u to listener\n",
712 incoming->suggest_id);
713 cmsg->accept_id = htonl (incoming->suggest_id);
714 cmsg->peer_id = incoming->spec->peer;
715 GNUNET_MQ_send (listener->client_mq,
716 mqm);
717} 670}
718 671
719 672
@@ -729,93 +682,85 @@ incoming_suggest (struct Operation *incoming,
729 * our virtual table and subsequent msgs would be routed differently (as 682 * our virtual table and subsequent msgs would be routed differently (as
730 * we then know what type of operation this is). 683 * we then know what type of operation this is).
731 * 684 *
732 * @param op the operation state 685 * @param cls the operation state
733 * @param mh the received message 686 * @param msg the received message
734 * @return #GNUNET_OK if the channel should be kept alive, 687 * @return #GNUNET_OK if the channel should be kept alive,
735 * #GNUNET_SYSERR to destroy the channel 688 * #GNUNET_SYSERR to destroy the channel
736 */ 689 */
737static int 690static void
738handle_incoming_msg (struct Operation *op, 691handle_incoming_msg (void *cls,
739 const struct GNUNET_MessageHeader *mh) 692 const struct OperationRequestMessage *msg)
740{ 693{
741 const struct OperationRequestMessage *msg; 694 struct Operation *op = cls;
742 struct Listener *listener = op->listener; 695 struct Listener *listener = op->listener;
743 struct OperationSpecification *spec;
744 const struct GNUNET_MessageHeader *nested_context; 696 const struct GNUNET_MessageHeader *nested_context;
697 struct GNUNET_MQ_Envelope *env;
698 struct GNUNET_SET_RequestMessage *cmsg;
745 699
746 msg = (const struct OperationRequestMessage *) mh;
747 GNUNET_assert (GNUNET_YES == op->is_incoming);
748 if (GNUNET_MESSAGE_TYPE_SET_P2P_OPERATION_REQUEST != ntohs (mh->type))
749 {
750 GNUNET_break_op (0);
751 return GNUNET_SYSERR;
752 }
753 /* double operation request */
754 if (NULL != op->spec)
755 {
756 GNUNET_break_op (0);
757 return GNUNET_SYSERR;
758 }
759 spec = GNUNET_new (struct OperationSpecification);
760 nested_context = GNUNET_MQ_extract_nested_mh (msg); 700 nested_context = GNUNET_MQ_extract_nested_mh (msg);
761 if ( (NULL != nested_context) &&
762 (ntohs (nested_context->size) > GNUNET_SET_CONTEXT_MESSAGE_MAX_SIZE) )
763 {
764 GNUNET_break_op (0);
765 GNUNET_free (spec);
766 return GNUNET_SYSERR;
767 }
768 /* Make a copy of the nested_context (application-specific context 701 /* Make a copy of the nested_context (application-specific context
769 information that is opaque to set) so we can pass it to the 702 information that is opaque to set) so we can pass it to the
770 listener later on */ 703 listener later on */
771 if (NULL != nested_context) 704 if (NULL != nested_context)
772 spec->context_msg = GNUNET_copy_message (nested_context); 705 op->context_msg = GNUNET_copy_message (nested_context);
773 spec->operation = ntohl (msg->operation); 706 op->remote_element_count = ntohl (msg->element_count);
774 spec->app_id = listener->app_id;
775 spec->salt = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
776 UINT32_MAX);
777 spec->peer = op->peer;
778 spec->remote_element_count = ntohl (msg->element_count);
779 op->spec = spec;
780
781 listener = op->listener;
782 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 707 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
783 "Received P2P operation request (op %u, port %s) for active listener\n", 708 "Received P2P operation request (op %u, port %s) for active listener\n",
784 (uint32_t) ntohl (msg->operation), 709 (uint32_t) ntohl (msg->operation),
785 GNUNET_h2s (&listener->app_id)); 710 GNUNET_h2s (&op->listener->app_id));
786 incoming_suggest (op, 711 GNUNET_assert (0 == op->suggest_id);
787 listener); 712 if (0 == suggest_id)
788 return GNUNET_OK; 713 suggest_id++;
714 op->suggest_id = suggest_id++;
715 GNUNET_assert (NULL != op->timeout_task);
716 GNUNET_SCHEDULER_cancel (op->timeout_task);
717 op->timeout_task = NULL;
718 env = GNUNET_MQ_msg_nested_mh (cmsg,
719 GNUNET_MESSAGE_TYPE_SET_REQUEST,
720 op->context_msg);
721 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
722 "Suggesting incoming request with accept id %u to listener %p of client %p\n",
723 op->suggest_id,
724 listener,
725 listener->cs);
726 cmsg->accept_id = htonl (op->suggest_id);
727 cmsg->peer_id = op->peer;
728 GNUNET_MQ_send (listener->cs->mq,
729 env);
730 /* NOTE: GNUNET_CADET_receive_done() will be called in
731 #handle_client_accept() */
789} 732}
790 733
791 734
735/**
736 * Add an element to @a set as specified by @a msg
737 *
738 * @param set set to manipulate
739 * @param msg message specifying the change
740 */
792static void 741static void
793execute_add (struct Set *set, 742execute_add (struct Set *set,
794 const struct GNUNET_MessageHeader *m) 743 const struct GNUNET_SET_ElementMessage *msg)
795{ 744{
796 const struct GNUNET_SET_ElementMessage *msg;
797 struct GNUNET_SET_Element el; 745 struct GNUNET_SET_Element el;
798 struct ElementEntry *ee; 746 struct ElementEntry *ee;
799 struct GNUNET_HashCode hash; 747 struct GNUNET_HashCode hash;
800 748
801 GNUNET_assert (GNUNET_MESSAGE_TYPE_SET_ADD == ntohs (m->type)); 749 GNUNET_assert (GNUNET_MESSAGE_TYPE_SET_ADD == ntohs (msg->header.type));
802 750 el.size = ntohs (msg->header.size) - sizeof (*msg);
803 msg = (const struct GNUNET_SET_ElementMessage *) m;
804 el.size = ntohs (m->size) - sizeof *msg;
805 el.data = &msg[1]; 751 el.data = &msg[1];
806 el.element_type = ntohs (msg->element_type); 752 el.element_type = ntohs (msg->element_type);
807 GNUNET_SET_element_hash (&el, &hash); 753 GNUNET_SET_element_hash (&el,
808 754 &hash);
809 ee = GNUNET_CONTAINER_multihashmap_get (set->content->elements, 755 ee = GNUNET_CONTAINER_multihashmap_get (set->content->elements,
810 &hash); 756 &hash);
811
812 if (NULL == ee) 757 if (NULL == ee)
813 { 758 {
814 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 759 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
815 "Client inserts element %s of size %u\n", 760 "Client inserts element %s of size %u\n",
816 GNUNET_h2s (&hash), 761 GNUNET_h2s (&hash),
817 el.size); 762 el.size);
818 ee = GNUNET_malloc (el.size + sizeof *ee); 763 ee = GNUNET_malloc (el.size + sizeof (*ee));
819 ee->element.size = el.size; 764 ee->element.size = el.size;
820 GNUNET_memcpy (&ee[1], 765 GNUNET_memcpy (&ee[1],
821 el.data, 766 el.data,
@@ -832,7 +777,11 @@ execute_add (struct Set *set,
832 ee, 777 ee,
833 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); 778 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
834 } 779 }
835 else if (GNUNET_YES == _GSS_is_element_of_set (ee, set)) 780 else if (GNUNET_YES ==
781 is_element_of_generation (ee,
782 set->current_generation,
783 set->excluded_generations,
784 set->excluded_generations_size))
836 { 785 {
837 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 786 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
838 "Client inserted element %s of size %u twice (ignored)\n", 787 "Client inserted element %s of size %u twice (ignored)\n",
@@ -852,24 +801,27 @@ execute_add (struct Set *set,
852 ee->mutations_size, 801 ee->mutations_size,
853 mut); 802 mut);
854 } 803 }
855 804 set->vt->add (set->state,
856 set->vt->add (set->state, ee); 805 ee);
857} 806}
858 807
859 808
809/**
810 * Remove an element from @a set as specified by @a msg
811 *
812 * @param set set to manipulate
813 * @param msg message specifying the change
814 */
860static void 815static void
861execute_remove (struct Set *set, 816execute_remove (struct Set *set,
862 const struct GNUNET_MessageHeader *m) 817 const struct GNUNET_SET_ElementMessage *msg)
863{ 818{
864 const struct GNUNET_SET_ElementMessage *msg;
865 struct GNUNET_SET_Element el; 819 struct GNUNET_SET_Element el;
866 struct ElementEntry *ee; 820 struct ElementEntry *ee;
867 struct GNUNET_HashCode hash; 821 struct GNUNET_HashCode hash;
868 822
869 GNUNET_assert (GNUNET_MESSAGE_TYPE_SET_REMOVE == ntohs (m->type)); 823 GNUNET_assert (GNUNET_MESSAGE_TYPE_SET_REMOVE == ntohs (msg->header.type));
870 824 el.size = ntohs (msg->header.size) - sizeof (*msg);
871 msg = (const struct GNUNET_SET_ElementMessage *) m;
872 el.size = ntohs (m->size) - sizeof *msg;
873 el.data = &msg[1]; 825 el.data = &msg[1];
874 el.element_type = ntohs (msg->element_type); 826 el.element_type = ntohs (msg->element_type);
875 GNUNET_SET_element_hash (&el, &hash); 827 GNUNET_SET_element_hash (&el, &hash);
@@ -883,7 +835,11 @@ execute_remove (struct Set *set,
883 el.size); 835 el.size);
884 return; 836 return;
885 } 837 }
886 if (GNUNET_NO == _GSS_is_element_of_set (ee, set)) 838 if (GNUNET_NO ==
839 is_element_of_generation (ee,
840 set->current_generation,
841 set->excluded_generations,
842 set->excluded_generations_size))
887 { 843 {
888 /* Client tried to remove element twice */ 844 /* Client tried to remove element twice */
889 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 845 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -906,22 +862,28 @@ execute_remove (struct Set *set,
906 ee->mutations_size, 862 ee->mutations_size,
907 mut); 863 mut);
908 } 864 }
909 set->vt->remove (set->state, ee); 865 set->vt->remove (set->state,
866 ee);
910} 867}
911 868
912 869
913 870/**
871 * Perform a mutation on a set as specified by the @a msg
872 *
873 * @param set the set to mutate
874 * @param msg specification of what to change
875 */
914static void 876static void
915execute_mutation (struct Set *set, 877execute_mutation (struct Set *set,
916 const struct GNUNET_MessageHeader *m) 878 const struct GNUNET_SET_ElementMessage *msg)
917{ 879{
918 switch (ntohs (m->type)) 880 switch (ntohs (msg->header.type))
919 { 881 {
920 case GNUNET_MESSAGE_TYPE_SET_ADD: 882 case GNUNET_MESSAGE_TYPE_SET_ADD:
921 execute_add (set, m); 883 execute_add (set, msg);
922 break; 884 break;
923 case GNUNET_MESSAGE_TYPE_SET_REMOVE: 885 case GNUNET_MESSAGE_TYPE_SET_REMOVE:
924 execute_remove (set, m); 886 execute_remove (set, msg);
925 break; 887 break;
926 default: 888 default:
927 GNUNET_break (0); 889 GNUNET_break (0);
@@ -929,6 +891,34 @@ execute_mutation (struct Set *set,
929} 891}
930 892
931 893
894/**
895 * Execute mutations that were delayed on a set because of
896 * pending operations.
897 *
898 * @param set the set to execute mutations on
899 */
900static void
901execute_delayed_mutations (struct Set *set)
902{
903 struct PendingMutation *pm;
904
905 if (0 != set->content->iterator_count)
906 return; /* still cannot do this */
907 while (NULL != (pm = set->content->pending_mutations_head))
908 {
909 GNUNET_CONTAINER_DLL_remove (set->content->pending_mutations_head,
910 set->content->pending_mutations_tail,
911 pm);
912 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
913 "Executing pending mutation on %p.\n",
914 pm->set);
915 execute_mutation (pm->set,
916 pm->msg);
917 GNUNET_free (pm->msg);
918 GNUNET_free (pm);
919 }
920}
921
932 922
933/** 923/**
934 * Send the next element of a set to the set's client. The next element is given by 924 * Send the next element of a set to the set's client. The next element is given by
@@ -952,65 +942,45 @@ send_client_element (struct Set *set)
952 struct GNUNET_SET_IterResponseMessage *msg; 942 struct GNUNET_SET_IterResponseMessage *msg;
953 943
954 GNUNET_assert (NULL != set->iter); 944 GNUNET_assert (NULL != set->iter);
955 945 do {
956again: 946 ret = GNUNET_CONTAINER_multihashmap_iterator_next (set->iter,
957 947 NULL,
958 ret = GNUNET_CONTAINER_multihashmap_iterator_next (set->iter, 948 (const void **) &ee);
959 NULL, 949 if (GNUNET_NO == ret)
960 (const void **) &ee);
961 if (GNUNET_NO == ret)
962 {
963 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
964 "Iteration on %p done.\n",
965 (void *) set);
966 ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_ITER_DONE);
967 GNUNET_CONTAINER_multihashmap_iterator_destroy (set->iter);
968 set->iter = NULL;
969 set->iteration_id++;
970
971 GNUNET_assert (set->content->iterator_count > 0);
972 set->content->iterator_count -= 1;
973
974 if (0 == set->content->iterator_count)
975 { 950 {
976 while (NULL != set->content->pending_mutations_head) 951 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
977 { 952 "Iteration on %p done.\n",
978 struct PendingMutation *pm; 953 set);
979 954 ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_ITER_DONE);
980 pm = set->content->pending_mutations_head; 955 GNUNET_CONTAINER_multihashmap_iterator_destroy (set->iter);
981 GNUNET_CONTAINER_DLL_remove (set->content->pending_mutations_head, 956 set->iter = NULL;
982 set->content->pending_mutations_tail, 957 set->iteration_id++;
983 pm); 958 GNUNET_assert (set->content->iterator_count > 0);
984 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 959 set->content->iterator_count--;
985 "Executing pending mutation on %p.\n", 960 execute_delayed_mutations (set);
986 (void *) pm->set); 961 GNUNET_MQ_send (set->cs->mq,
987 execute_mutation (pm->set, pm->mutation_message); 962 ev);
988 GNUNET_free (pm->mutation_message); 963 return;
989 GNUNET_free (pm);
990 }
991 } 964 }
992
993 }
994 else
995 {
996 GNUNET_assert (NULL != ee); 965 GNUNET_assert (NULL != ee);
997 966 } while (GNUNET_NO ==
998 if (GNUNET_NO == is_element_of_iteration (ee, set)) 967 is_element_of_generation (ee,
999 goto again; 968 set->iter_generation,
1000 969 set->excluded_generations,
1001 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 970 set->excluded_generations_size));
1002 "Sending iteration element on %p.\n", 971 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1003 (void *) set); 972 "Sending iteration element on %p.\n",
1004 ev = GNUNET_MQ_msg_extra (msg, 973 set);
1005 ee->element.size, 974 ev = GNUNET_MQ_msg_extra (msg,
1006 GNUNET_MESSAGE_TYPE_SET_ITER_ELEMENT); 975 ee->element.size,
1007 GNUNET_memcpy (&msg[1], 976 GNUNET_MESSAGE_TYPE_SET_ITER_ELEMENT);
1008 ee->element.data, 977 GNUNET_memcpy (&msg[1],
1009 ee->element.size); 978 ee->element.data,
1010 msg->element_type = htons (ee->element.element_type); 979 ee->element.size);
1011 msg->iteration_id = htons (set->iteration_id); 980 msg->element_type = htons (ee->element.element_type);
1012 } 981 msg->iteration_id = htons (set->iteration_id);
1013 GNUNET_MQ_send (set->client_mq, ev); 982 GNUNET_MQ_send (set->cs->mq,
983 ev);
1014} 984}
1015 985
1016 986
@@ -1027,22 +997,21 @@ static void
1027handle_client_iterate (void *cls, 997handle_client_iterate (void *cls,
1028 const struct GNUNET_MessageHeader *m) 998 const struct GNUNET_MessageHeader *m)
1029{ 999{
1030 struct GNUNET_SERVICE_Client *client = cls; 1000 struct ClientState *cs = cls;
1031 struct Set *set; 1001 struct Set *set;
1032 1002
1033 set = set_get (client); 1003 if (NULL == (set = cs->set))
1034 if (NULL == set)
1035 { 1004 {
1036 /* attempt to iterate over a non existing set */ 1005 /* attempt to iterate over a non existing set */
1037 GNUNET_break (0); 1006 GNUNET_break (0);
1038 GNUNET_SERVICE_client_drop (client); 1007 GNUNET_SERVICE_client_drop (cs->client);
1039 return; 1008 return;
1040 } 1009 }
1041 if (NULL != set->iter) 1010 if (NULL != set->iter)
1042 { 1011 {
1043 /* Only one concurrent iterate-action allowed per set */ 1012 /* Only one concurrent iterate-action allowed per set */
1044 GNUNET_break (0); 1013 GNUNET_break (0);
1045 GNUNET_SERVICE_client_drop (client); 1014 GNUNET_SERVICE_client_drop (cs->client);
1046 return; 1015 return;
1047 } 1016 }
1048 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1017 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -1050,8 +1019,8 @@ handle_client_iterate (void *cls,
1050 (void *) set, 1019 (void *) set,
1051 set->current_generation, 1020 set->current_generation,
1052 GNUNET_CONTAINER_multihashmap_size (set->content->elements)); 1021 GNUNET_CONTAINER_multihashmap_size (set->content->elements));
1053 GNUNET_SERVICE_client_continue (client); 1022 GNUNET_SERVICE_client_continue (cs->client);
1054 set->content->iterator_count += 1; 1023 set->content->iterator_count++;
1055 set->iter = GNUNET_CONTAINER_multihashmap_iterator_create (set->content->elements); 1024 set->iter = GNUNET_CONTAINER_multihashmap_iterator_create (set->content->elements);
1056 set->iter_generation = set->current_generation; 1025 set->iter_generation = set->current_generation;
1057 send_client_element (set); 1026 send_client_element (set);
@@ -1070,17 +1039,17 @@ static void
1070handle_client_create_set (void *cls, 1039handle_client_create_set (void *cls,
1071 const struct GNUNET_SET_CreateMessage *msg) 1040 const struct GNUNET_SET_CreateMessage *msg)
1072{ 1041{
1073 struct GNUNET_SERVICE_Client *client = cls; 1042 struct ClientState *cs = cls;
1074 struct Set *set; 1043 struct Set *set;
1075 1044
1076 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1045 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1077 "Client created new set (operation %u)\n", 1046 "Client created new set (operation %u)\n",
1078 (uint32_t) ntohl (msg->operation)); 1047 (uint32_t) ntohl (msg->operation));
1079 if (NULL != set_get (client)) 1048 if (NULL != cs->set)
1080 { 1049 {
1081 /* There can only be one set per client */ 1050 /* There can only be one set per client */
1082 GNUNET_break (0); 1051 GNUNET_break (0);
1083 GNUNET_SERVICE_client_drop (client); 1052 GNUNET_SERVICE_client_drop (cs->client);
1084 return; 1053 return;
1085 } 1054 }
1086 set = GNUNET_new (struct Set); 1055 set = GNUNET_new (struct Set);
@@ -1095,27 +1064,25 @@ handle_client_create_set (void *cls,
1095 default: 1064 default:
1096 GNUNET_free (set); 1065 GNUNET_free (set);
1097 GNUNET_break (0); 1066 GNUNET_break (0);
1098 GNUNET_SERVICE_client_drop (client); 1067 GNUNET_SERVICE_client_drop (cs->client);
1099 return; 1068 return;
1100 } 1069 }
1101 set->operation = ntohl (msg->operation); 1070 set->operation = (enum GNUNET_SET_OperationType) ntohl (msg->operation);
1102 set->state = set->vt->create (); 1071 set->state = set->vt->create ();
1103 if (NULL == set->state) 1072 if (NULL == set->state)
1104 { 1073 {
1105 /* initialization failed (i.e. out of memory) */ 1074 /* initialization failed (i.e. out of memory) */
1106 GNUNET_free (set); 1075 GNUNET_free (set);
1107 GNUNET_SERVICE_client_drop (client); 1076 GNUNET_SERVICE_client_drop (cs->client);
1108 return; 1077 return;
1109 } 1078 }
1110 set->content = GNUNET_new (struct SetContent); 1079 set->content = GNUNET_new (struct SetContent);
1111 set->content->refcount = 1; 1080 set->content->refcount = 1;
1112 set->content->elements = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES); 1081 set->content->elements = GNUNET_CONTAINER_multihashmap_create (1,
1113 set->client = client; 1082 GNUNET_YES);
1114 set->client_mq = GNUNET_SERVICE_client_get_mq (client); 1083 set->cs = cs;
1115 GNUNET_CONTAINER_DLL_insert (sets_head, 1084 cs->set = set;
1116 sets_tail, 1085 GNUNET_SERVICE_client_continue (cs->client);
1117 set);
1118 GNUNET_SERVICE_client_continue (client);
1119} 1086}
1120 1087
1121 1088
@@ -1131,31 +1098,12 @@ handle_client_create_set (void *cls,
1131static void 1098static void
1132incoming_timeout_cb (void *cls) 1099incoming_timeout_cb (void *cls)
1133{ 1100{
1134 struct Operation *incoming = cls; 1101 struct Operation *op = cls;
1135 1102
1136 incoming->timeout_task = NULL; 1103 op->timeout_task = NULL;
1137 GNUNET_assert (GNUNET_YES == incoming->is_incoming);
1138 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1104 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1139 "Remote peer's incoming request timed out\n"); 1105 "Remote peer's incoming request timed out\n");
1140 incoming_destroy (incoming);
1141}
1142
1143
1144/**
1145 * Terminates an incoming operation in case we have not yet received an
1146 * operation request. Called by the channel destruction handler.
1147 *
1148 * @param op the channel context
1149 */
1150static void
1151handle_incoming_disconnect (struct Operation *op)
1152{
1153 GNUNET_assert (GNUNET_YES == op->is_incoming);
1154 /* channel is already dead, incoming_destroy must not
1155 * destroy it ... */
1156 op->channel = NULL;
1157 incoming_destroy (op); 1106 incoming_destroy (op);
1158 op->vt = NULL;
1159} 1107}
1160 1108
1161 1109
@@ -1180,32 +1128,26 @@ channel_new_cb (void *cls,
1180 struct GNUNET_CADET_Channel *channel, 1128 struct GNUNET_CADET_Channel *channel,
1181 const struct GNUNET_PeerIdentity *source) 1129 const struct GNUNET_PeerIdentity *source)
1182{ 1130{
1183 static const struct SetVT incoming_vt = {
1184 .msg_handler = &handle_incoming_msg,
1185 .peer_disconnect = &handle_incoming_disconnect
1186 };
1187 struct Listener *listener = cls; 1131 struct Listener *listener = cls;
1188 struct Operation *incoming; 1132 struct Operation *op;
1189 1133
1190 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1134 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1191 "New incoming channel\n"); 1135 "New incoming channel\n");
1192 incoming = GNUNET_new (struct Operation); 1136 op = GNUNET_new (struct Operation);
1193 incoming->listener = listener; 1137 op->listener = listener;
1194 incoming->is_incoming = GNUNET_YES; 1138 op->peer = *source;
1195 incoming->peer = *source; 1139 op->channel = channel;
1196 incoming->channel = channel; 1140 op->mq = GNUNET_CADET_get_mq (op->channel);
1197 incoming->mq = GNUNET_CADET_get_mq (incoming->channel); 1141 op->salt = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
1198 incoming->vt = &incoming_vt; 1142 UINT32_MAX);
1199 incoming->timeout_task 1143 op->timeout_task
1200 = GNUNET_SCHEDULER_add_delayed (INCOMING_CHANNEL_TIMEOUT, 1144 = GNUNET_SCHEDULER_add_delayed (INCOMING_CHANNEL_TIMEOUT,
1201 &incoming_timeout_cb, 1145 &incoming_timeout_cb,
1202 incoming); 1146 op);
1203 GNUNET_CONTAINER_DLL_insert_tail (incoming_head, 1147 GNUNET_CONTAINER_DLL_insert (listener->op_head,
1204 incoming_tail, 1148 listener->op_tail,
1205 incoming); 1149 op);
1206 // incoming_suggest (incoming, 1150 return op;
1207 // listener);
1208 return incoming;
1209} 1151}
1210 1152
1211 1153
@@ -1234,22 +1176,14 @@ channel_end_cb (void *channel_ctx,
1234 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1176 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1235 "channel_end_cb called\n"); 1177 "channel_end_cb called\n");
1236 op->channel = NULL; 1178 op->channel = NULL;
1237 op->keep++; 1179 if (NULL != op->listener)
1238 /* the vt can be null if a client already requested canceling op. */ 1180 incoming_destroy (op);
1239 if (NULL != op->vt) 1181 else if (NULL != op->set)
1240 { 1182 op->set->vt->channel_death (op);
1241 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1183 else
1242 "calling peer disconnect due to channel end\n"); 1184 _GSS_operation_destroy (op,
1243 op->vt->peer_disconnect (op); 1185 GNUNET_YES);
1244 } 1186 GNUNET_free (op);
1245 op->keep--;
1246 if (0 == op->keep)
1247 {
1248 /* cadet will never call us with the context again! */
1249 GNUNET_free (op);
1250 }
1251 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1252 "channel_end_cb finished\n");
1253} 1187}
1254 1188
1255 1189
@@ -1275,60 +1209,6 @@ channel_window_cb (void *cls,
1275 /* FIXME: not implemented, we could do flow control here... */ 1209 /* FIXME: not implemented, we could do flow control here... */
1276} 1210}
1277 1211
1278/**
1279 * FIXME: hack-job. Migrate to proper handler array use!
1280 *
1281 * @param cls local state associated with the channel.
1282 * @param message The actual message.
1283 */
1284static int
1285check_p2p_message (void *cls,
1286 const struct GNUNET_MessageHeader *message)
1287{
1288 return GNUNET_OK;
1289}
1290
1291
1292/**
1293 * FIXME: hack-job. Migrate to proper handler array use!
1294 *
1295 * Functions with this signature are called whenever a message is
1296 * received via a cadet channel.
1297 *
1298 * The msg_handler is a virtual table set in initially either when a peer
1299 * creates a new channel with us, or once we create a new channel
1300 * ourselves (evaluate).
1301 *
1302 * Once we know the exact type of operation (union/intersection), the vt is
1303 * replaced with an operation specific instance (_GSS_[op]_vt).
1304 *
1305 * @param cls local state associated with the channel.
1306 * @param message The actual message.
1307 */
1308static void
1309handle_p2p_message (void *cls,
1310 const struct GNUNET_MessageHeader *message)
1311{
1312 struct Operation *op = cls;
1313 int ret;
1314
1315 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1316 "Dispatching cadet message (type: %u)\n",
1317 ntohs (message->type));
1318 /* do this before the handler, as the handler might kill the channel */
1319 GNUNET_CADET_receive_done (op->channel);
1320 if (NULL != op->vt)
1321 ret = op->vt->msg_handler (op,
1322 message);
1323 else
1324 ret = GNUNET_SYSERR;
1325 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1326 "Handled cadet message (type: %u)\n",
1327 ntohs (message->type));
1328 if (GNUNET_OK != ret)
1329 GNUNET_CADET_channel_destroy (op->channel);
1330}
1331
1332 1212
1333/** 1213/**
1334 * Called when a client wants to create a new listener. 1214 * Called when a client wants to create a new listener.
@@ -1340,116 +1220,99 @@ static void
1340handle_client_listen (void *cls, 1220handle_client_listen (void *cls,
1341 const struct GNUNET_SET_ListenMessage *msg) 1221 const struct GNUNET_SET_ListenMessage *msg)
1342{ 1222{
1343 struct GNUNET_SERVICE_Client *client = cls; 1223 struct ClientState *cs = cls;
1344 struct GNUNET_MQ_MessageHandler cadet_handlers[] = { 1224 struct GNUNET_MQ_MessageHandler cadet_handlers[] = {
1345 GNUNET_MQ_hd_var_size (p2p_message, 1225 GNUNET_MQ_hd_var_size (incoming_msg,
1346 GNUNET_MESSAGE_TYPE_SET_P2P_OPERATION_REQUEST, 1226 GNUNET_MESSAGE_TYPE_SET_P2P_OPERATION_REQUEST,
1347 struct GNUNET_MessageHeader, 1227 struct OperationRequestMessage,
1348 NULL), 1228 NULL),
1349 GNUNET_MQ_hd_var_size (p2p_message, 1229 GNUNET_MQ_hd_var_size (union_p2p_ibf,
1350 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_IBF, 1230 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_IBF,
1351 struct GNUNET_MessageHeader, 1231 struct IBFMessage,
1352 NULL), 1232 NULL),
1353 GNUNET_MQ_hd_var_size (p2p_message, 1233 GNUNET_MQ_hd_var_size (union_p2p_elements,
1354 GNUNET_MESSAGE_TYPE_SET_P2P_ELEMENTS, 1234 GNUNET_MESSAGE_TYPE_SET_P2P_ELEMENTS,
1355 struct GNUNET_MessageHeader, 1235 struct GNUNET_SET_ElementMessage,
1356 NULL), 1236 NULL),
1357 GNUNET_MQ_hd_var_size (p2p_message, 1237 GNUNET_MQ_hd_var_size (union_p2p_offer,
1358 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_OFFER, 1238 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_OFFER,
1359 struct GNUNET_MessageHeader, 1239 struct GNUNET_MessageHeader,
1360 NULL), 1240 NULL),
1361 GNUNET_MQ_hd_var_size (p2p_message, 1241 GNUNET_MQ_hd_var_size (union_p2p_inquiry,
1362 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_INQUIRY, 1242 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_INQUIRY,
1363 struct GNUNET_MessageHeader, 1243 struct InquiryMessage,
1364 NULL), 1244 NULL),
1365 GNUNET_MQ_hd_var_size (p2p_message, 1245 GNUNET_MQ_hd_var_size (union_p2p_demand,
1366 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DEMAND, 1246 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DEMAND,
1367 struct GNUNET_MessageHeader, 1247 struct GNUNET_MessageHeader,
1368 NULL), 1248 NULL),
1369 GNUNET_MQ_hd_var_size (p2p_message, 1249 GNUNET_MQ_hd_fixed_size (union_p2p_done,
1370 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DONE, 1250 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DONE,
1371 struct GNUNET_MessageHeader, 1251 struct GNUNET_MessageHeader,
1372 NULL), 1252 NULL),
1373 GNUNET_MQ_hd_var_size (p2p_message, 1253 GNUNET_MQ_hd_fixed_size (union_p2p_full_done,
1374 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_DONE, 1254 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_DONE,
1375 struct GNUNET_MessageHeader, 1255 struct GNUNET_MessageHeader,
1376 NULL), 1256 NULL),
1377 GNUNET_MQ_hd_var_size (p2p_message, 1257 GNUNET_MQ_hd_fixed_size (union_p2p_request_full,
1378 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_REQUEST_FULL, 1258 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_REQUEST_FULL,
1379 struct GNUNET_MessageHeader, 1259 struct GNUNET_MessageHeader,
1380 NULL), 1260 NULL),
1381 GNUNET_MQ_hd_var_size (p2p_message, 1261 GNUNET_MQ_hd_var_size (union_p2p_strata_estimator,
1382 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SE, 1262 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SE,
1383 struct GNUNET_MessageHeader, 1263 struct StrataEstimatorMessage,
1384 NULL), 1264 NULL),
1385 GNUNET_MQ_hd_var_size (p2p_message, 1265 GNUNET_MQ_hd_var_size (union_p2p_strata_estimator,
1386 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SEC, 1266 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SEC,
1387 struct GNUNET_MessageHeader, 1267 struct StrataEstimatorMessage,
1388 NULL), 1268 NULL),
1389 GNUNET_MQ_hd_var_size (p2p_message, 1269 GNUNET_MQ_hd_var_size (union_p2p_full_element,
1390 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_ELEMENT, 1270 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_ELEMENT,
1391 struct GNUNET_MessageHeader, 1271 struct GNUNET_SET_ElementMessage,
1392 NULL),
1393 GNUNET_MQ_hd_var_size (p2p_message,
1394 GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_ELEMENT_INFO,
1395 struct GNUNET_MessageHeader,
1396 NULL), 1272 NULL),
1397 GNUNET_MQ_hd_var_size (p2p_message, 1273 GNUNET_MQ_hd_fixed_size (intersection_p2p_element_info,
1274 GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_ELEMENT_INFO,
1275 struct IntersectionElementInfoMessage,
1276 NULL),
1277 GNUNET_MQ_hd_var_size (intersection_p2p_bf,
1398 GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_BF, 1278 GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_BF,
1399 struct GNUNET_MessageHeader, 1279 struct BFMessage,
1400 NULL),
1401 GNUNET_MQ_hd_var_size (p2p_message,
1402 GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_DONE,
1403 struct GNUNET_MessageHeader,
1404 NULL), 1280 NULL),
1281 GNUNET_MQ_hd_fixed_size (intersection_p2p_done,
1282 GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_DONE,
1283 struct IntersectionDoneMessage,
1284 NULL),
1405 GNUNET_MQ_handler_end () 1285 GNUNET_MQ_handler_end ()
1406 }; 1286 };
1407 struct Listener *listener; 1287 struct Listener *listener;
1408 1288
1409 if (NULL != listener_get (client)) 1289 if (NULL != cs->listener)
1410 { 1290 {
1411 /* max. one active listener per client! */ 1291 /* max. one active listener per client! */
1412 GNUNET_break (0); 1292 GNUNET_break (0);
1413 GNUNET_SERVICE_client_drop (client); 1293 GNUNET_SERVICE_client_drop (cs->client);
1414 return; 1294 return;
1415 } 1295 }
1416 listener = GNUNET_new (struct Listener); 1296 listener = GNUNET_new (struct Listener);
1417 listener->client = client; 1297 listener->cs = cs;
1418 listener->client_mq = GNUNET_SERVICE_client_get_mq (client);
1419 listener->app_id = msg->app_id; 1298 listener->app_id = msg->app_id;
1420 listener->operation = ntohl (msg->operation); 1299 listener->operation = (enum GNUNET_SET_OperationType) ntohl (msg->operation);
1421 GNUNET_CONTAINER_DLL_insert_tail (listeners_head, 1300 GNUNET_CONTAINER_DLL_insert (listener_head,
1422 listeners_tail, 1301 listener_tail,
1423 listener); 1302 listener);
1424 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1303 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1425 "New listener created (op %u, port %s)\n", 1304 "New listener created (op %u, port %s)\n",
1426 listener->operation, 1305 listener->operation,
1427 GNUNET_h2s (&listener->app_id)); 1306 GNUNET_h2s (&listener->app_id));
1428 listener->open_port = GNUNET_CADET_open_porT (cadet, 1307 listener->open_port
1429 &msg->app_id, 1308 = GNUNET_CADET_open_port (cadet,
1430 &channel_new_cb, 1309 &msg->app_id,
1431 listener, 1310 &channel_new_cb,
1432 &channel_window_cb, 1311 listener,
1433 &channel_end_cb, 1312 &channel_window_cb,
1434 cadet_handlers); 1313 &channel_end_cb,
1435 /* check for existing incoming requests the listener might be interested in */ 1314 cadet_handlers);
1436 for (struct Operation *op = incoming_head; NULL != op; op = op->next) 1315 GNUNET_SERVICE_client_continue (cs->client);
1437 {
1438 if (NULL == op->spec)
1439 continue; /* no details available yet */
1440 if (0 != op->suggest_id)
1441 continue; /* this one has been already suggested to a listener */
1442 if (listener->operation != op->spec->operation)
1443 continue; /* incompatible operation */
1444 if (0 != GNUNET_CRYPTO_hash_cmp (&listener->app_id,
1445 &op->spec->app_id))
1446 continue; /* incompatible appliation */
1447 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1448 "Found matching existing request\n");
1449 incoming_suggest (op,
1450 listener);
1451 }
1452 GNUNET_SERVICE_client_continue (client);
1453} 1316}
1454 1317
1455 1318
@@ -1464,23 +1327,26 @@ static void
1464handle_client_reject (void *cls, 1327handle_client_reject (void *cls,
1465 const struct GNUNET_SET_RejectMessage *msg) 1328 const struct GNUNET_SET_RejectMessage *msg)
1466{ 1329{
1467 struct GNUNET_SERVICE_Client *client = cls; 1330 struct ClientState *cs = cls;
1468 struct Operation *incoming; 1331 struct Operation *op;
1469 1332
1470 incoming = get_incoming (ntohl (msg->accept_reject_id)); 1333 op = get_incoming (ntohl (msg->accept_reject_id));
1471 if (NULL == incoming) 1334 if (NULL == op)
1472 { 1335 {
1473 /* no matching incoming operation for this reject */ 1336 /* no matching incoming operation for this reject;
1474 GNUNET_break (0); 1337 could be that the other peer already disconnected... */
1475 GNUNET_SERVICE_client_drop (client); 1338 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1339 "Client rejected unknown operation %u\n",
1340 (unsigned int) ntohl (msg->accept_reject_id));
1341 GNUNET_SERVICE_client_continue (cs->client);
1476 return; 1342 return;
1477 } 1343 }
1478 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1344 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1479 "Peer request (op %u, app %s) rejected by client\n", 1345 "Peer request (op %u, app %s) rejected by client\n",
1480 incoming->spec->operation, 1346 op->listener->operation,
1481 GNUNET_h2s (&incoming->spec->app_id)); 1347 GNUNET_h2s (&cs->listener->app_id));
1482 GNUNET_CADET_channel_destroy (incoming->channel); 1348 GNUNET_CADET_channel_destroy (op->channel);
1483 GNUNET_SERVICE_client_continue (client); 1349 GNUNET_SERVICE_client_continue (cs->client);
1484} 1350}
1485 1351
1486 1352
@@ -1488,13 +1354,14 @@ handle_client_reject (void *cls,
1488 * Called when a client wants to add or remove an element to a set it inhabits. 1354 * Called when a client wants to add or remove an element to a set it inhabits.
1489 * 1355 *
1490 * @param cls client that sent the message 1356 * @param cls client that sent the message
1491 * @param m message sent by the client 1357 * @param msg message sent by the client
1492 */ 1358 */
1493static int 1359static int
1494check_client_mutation (void *cls, 1360check_client_mutation (void *cls,
1495 const struct GNUNET_MessageHeader *m) 1361 const struct GNUNET_SET_ElementMessage *msg)
1496{ 1362{
1497 /* FIXME: any check we might want to do here? */ 1363 /* NOTE: Technically, we should probably check with the
1364 block library whether the element we are given is well-formed */
1498 return GNUNET_OK; 1365 return GNUNET_OK;
1499} 1366}
1500 1367
@@ -1503,25 +1370,23 @@ check_client_mutation (void *cls,
1503 * Called when a client wants to add or remove an element to a set it inhabits. 1370 * Called when a client wants to add or remove an element to a set it inhabits.
1504 * 1371 *
1505 * @param cls client that sent the message 1372 * @param cls client that sent the message
1506 * @param m message sent by the client 1373 * @param msg message sent by the client
1507 */ 1374 */
1508static void 1375static void
1509handle_client_mutation (void *cls, 1376handle_client_mutation (void *cls,
1510 const struct GNUNET_MessageHeader *m) 1377 const struct GNUNET_SET_ElementMessage *msg)
1511{ 1378{
1512 struct GNUNET_SERVICE_Client *client = cls; 1379 struct ClientState *cs = cls;
1513 struct Set *set; 1380 struct Set *set;
1514 1381
1515 set = set_get (client); 1382 if (NULL == (set = cs->set))
1516 if (NULL == set)
1517 { 1383 {
1518 /* client without a set requested an operation */ 1384 /* client without a set requested an operation */
1519 GNUNET_break (0); 1385 GNUNET_break (0);
1520 GNUNET_SERVICE_client_drop (client); 1386 GNUNET_SERVICE_client_drop (cs->client);
1521 return; 1387 return;
1522 } 1388 }
1523 1389 GNUNET_SERVICE_client_continue (cs->client);
1524 GNUNET_SERVICE_client_continue (client);
1525 1390
1526 if (0 != set->content->iterator_count) 1391 if (0 != set->content->iterator_count)
1527 { 1392 {
@@ -1529,16 +1394,18 @@ handle_client_mutation (void *cls,
1529 1394
1530 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1395 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1531 "Scheduling mutation on set\n"); 1396 "Scheduling mutation on set\n");
1532
1533 pm = GNUNET_new (struct PendingMutation); 1397 pm = GNUNET_new (struct PendingMutation);
1534 pm->mutation_message = GNUNET_copy_message (m); 1398 pm->msg = (struct GNUNET_SET_ElementMessage *) GNUNET_copy_message (&msg->header);
1535 pm->set = set; 1399 pm->set = set;
1536 GNUNET_CONTAINER_DLL_insert_tail (set->content->pending_mutations_head, 1400 GNUNET_CONTAINER_DLL_insert_tail (set->content->pending_mutations_head,
1537 set->content->pending_mutations_tail, 1401 set->content->pending_mutations_tail,
1538 pm); 1402 pm);
1539 return; 1403 return;
1540 } 1404 }
1541 execute_mutation (set, m); 1405 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1406 "Executing mutation on set\n");
1407 execute_mutation (set,
1408 msg);
1542} 1409}
1543 1410
1544 1411
@@ -1555,8 +1422,8 @@ advance_generation (struct Set *set)
1555 1422
1556 if (set->current_generation == set->content->latest_generation) 1423 if (set->current_generation == set->content->latest_generation)
1557 { 1424 {
1558 set->content->latest_generation += 1; 1425 set->content->latest_generation++;
1559 set->current_generation += 1; 1426 set->current_generation++;
1560 return; 1427 return;
1561 } 1428 }
1562 1429
@@ -1564,10 +1431,8 @@ advance_generation (struct Set *set)
1564 1431
1565 r.start = set->current_generation + 1; 1432 r.start = set->current_generation + 1;
1566 r.end = set->content->latest_generation + 1; 1433 r.end = set->content->latest_generation + 1;
1567
1568 set->content->latest_generation = r.end; 1434 set->content->latest_generation = r.end;
1569 set->current_generation = r.end; 1435 set->current_generation = r.end;
1570
1571 GNUNET_array_append (set->excluded_generations, 1436 GNUNET_array_append (set->excluded_generations,
1572 set->excluded_generations_size, 1437 set->excluded_generations_size,
1573 r); 1438 r);
@@ -1605,112 +1470,105 @@ static void
1605handle_client_evaluate (void *cls, 1470handle_client_evaluate (void *cls,
1606 const struct GNUNET_SET_EvaluateMessage *msg) 1471 const struct GNUNET_SET_EvaluateMessage *msg)
1607{ 1472{
1608 struct GNUNET_SERVICE_Client *client = cls; 1473 struct ClientState *cs = cls;
1609 struct Operation *op = GNUNET_new (struct Operation); 1474 struct Operation *op = GNUNET_new (struct Operation);
1610 const struct GNUNET_MQ_MessageHandler cadet_handlers[] = { 1475 const struct GNUNET_MQ_MessageHandler cadet_handlers[] = {
1611 GNUNET_MQ_hd_var_size (p2p_message, 1476 GNUNET_MQ_hd_var_size (incoming_msg,
1612 GNUNET_MESSAGE_TYPE_SET_P2P_OPERATION_REQUEST, 1477 GNUNET_MESSAGE_TYPE_SET_P2P_OPERATION_REQUEST,
1613 struct GNUNET_MessageHeader, 1478 struct OperationRequestMessage,
1614 op), 1479 op),
1615 GNUNET_MQ_hd_var_size (p2p_message, 1480 GNUNET_MQ_hd_var_size (union_p2p_ibf,
1616 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_IBF, 1481 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_IBF,
1617 struct GNUNET_MessageHeader, 1482 struct IBFMessage,
1618 op), 1483 op),
1619 GNUNET_MQ_hd_var_size (p2p_message, 1484 GNUNET_MQ_hd_var_size (union_p2p_elements,
1620 GNUNET_MESSAGE_TYPE_SET_P2P_ELEMENTS, 1485 GNUNET_MESSAGE_TYPE_SET_P2P_ELEMENTS,
1621 struct GNUNET_MessageHeader, 1486 struct GNUNET_SET_ElementMessage,
1622 op), 1487 op),
1623 GNUNET_MQ_hd_var_size (p2p_message, 1488 GNUNET_MQ_hd_var_size (union_p2p_offer,
1624 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_OFFER, 1489 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_OFFER,
1625 struct GNUNET_MessageHeader, 1490 struct GNUNET_MessageHeader,
1626 op), 1491 op),
1627 GNUNET_MQ_hd_var_size (p2p_message, 1492 GNUNET_MQ_hd_var_size (union_p2p_inquiry,
1628 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_INQUIRY, 1493 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_INQUIRY,
1629 struct GNUNET_MessageHeader, 1494 struct InquiryMessage,
1630 op), 1495 op),
1631 GNUNET_MQ_hd_var_size (p2p_message, 1496 GNUNET_MQ_hd_var_size (union_p2p_demand,
1632 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DEMAND, 1497 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DEMAND,
1633 struct GNUNET_MessageHeader, 1498 struct GNUNET_MessageHeader,
1634 op), 1499 op),
1635 GNUNET_MQ_hd_var_size (p2p_message, 1500 GNUNET_MQ_hd_fixed_size (union_p2p_done,
1636 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DONE, 1501 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DONE,
1637 struct GNUNET_MessageHeader, 1502 struct GNUNET_MessageHeader,
1638 op), 1503 op),
1639 GNUNET_MQ_hd_var_size (p2p_message, 1504 GNUNET_MQ_hd_fixed_size (union_p2p_full_done,
1505 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_DONE,
1506 struct GNUNET_MessageHeader,
1507 op),
1508 GNUNET_MQ_hd_fixed_size (union_p2p_request_full,
1509 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_REQUEST_FULL,
1510 struct GNUNET_MessageHeader,
1511 op),
1512 GNUNET_MQ_hd_var_size (union_p2p_strata_estimator,
1640 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SE, 1513 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SE,
1641 struct GNUNET_MessageHeader, 1514 struct StrataEstimatorMessage,
1642 op), 1515 op),
1643 GNUNET_MQ_hd_var_size (p2p_message, 1516 GNUNET_MQ_hd_var_size (union_p2p_strata_estimator,
1644 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SEC, 1517 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SEC,
1645 struct GNUNET_MessageHeader, 1518 struct StrataEstimatorMessage,
1646 op),
1647 GNUNET_MQ_hd_var_size (p2p_message,
1648 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_DONE,
1649 struct GNUNET_MessageHeader,
1650 op), 1519 op),
1651 GNUNET_MQ_hd_var_size (p2p_message, 1520 GNUNET_MQ_hd_var_size (union_p2p_full_element,
1652 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_REQUEST_FULL,
1653 struct GNUNET_MessageHeader,
1654 op),
1655 GNUNET_MQ_hd_var_size (p2p_message,
1656 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_ELEMENT, 1521 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_ELEMENT,
1657 struct GNUNET_MessageHeader, 1522 struct GNUNET_SET_ElementMessage,
1658 op), 1523 op),
1659 GNUNET_MQ_hd_var_size (p2p_message, 1524 GNUNET_MQ_hd_fixed_size (intersection_p2p_element_info,
1660 GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_ELEMENT_INFO, 1525 GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_ELEMENT_INFO,
1661 struct GNUNET_MessageHeader, 1526 struct IntersectionElementInfoMessage,
1662 op), 1527 op),
1663 GNUNET_MQ_hd_var_size (p2p_message, 1528 GNUNET_MQ_hd_var_size (intersection_p2p_bf,
1664 GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_BF, 1529 GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_BF,
1665 struct GNUNET_MessageHeader, 1530 struct BFMessage,
1666 op),
1667 GNUNET_MQ_hd_var_size (p2p_message,
1668 GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_DONE,
1669 struct GNUNET_MessageHeader,
1670 op), 1531 op),
1532 GNUNET_MQ_hd_fixed_size (intersection_p2p_done,
1533 GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_DONE,
1534 struct IntersectionDoneMessage,
1535 op),
1671 GNUNET_MQ_handler_end () 1536 GNUNET_MQ_handler_end ()
1672 }; 1537 };
1673 struct Set *set; 1538 struct Set *set;
1674 struct OperationSpecification *spec;
1675 const struct GNUNET_MessageHeader *context; 1539 const struct GNUNET_MessageHeader *context;
1676 1540
1677 set = set_get (client); 1541 if (NULL == (set = cs->set))
1678 if (NULL == set)
1679 { 1542 {
1680 GNUNET_break (0); 1543 GNUNET_break (0);
1681 GNUNET_free (op); 1544 GNUNET_free (op);
1682 GNUNET_SERVICE_client_drop (client); 1545 GNUNET_SERVICE_client_drop (cs->client);
1683 return; 1546 return;
1684 } 1547 }
1685 spec = GNUNET_new (struct OperationSpecification); 1548 op->salt = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
1686 spec->operation = set->operation; 1549 UINT32_MAX);
1687 spec->app_id = msg->app_id; 1550 op->peer = msg->target_peer;
1688 spec->salt = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, 1551 op->result_mode = ntohl (msg->result_mode);
1689 UINT32_MAX); 1552 op->client_request_id = ntohl (msg->request_id);
1690 spec->peer = msg->target_peer; 1553 op->byzantine = msg->byzantine;
1691 spec->set = set; 1554 op->byzantine_lower_bound = msg->byzantine_lower_bound;
1692 spec->result_mode = ntohl (msg->result_mode); 1555 op->force_full = msg->force_full;
1693 spec->client_request_id = ntohl (msg->request_id); 1556 op->force_delta = msg->force_delta;
1694 spec->byzantine = msg->byzantine;
1695 spec->byzantine_lower_bound = msg->byzantine_lower_bound;
1696 spec->force_full = msg->force_full;
1697 spec->force_delta = msg->force_delta;
1698 context = GNUNET_MQ_extract_nested_mh (msg); 1557 context = GNUNET_MQ_extract_nested_mh (msg);
1699 op->spec = spec;
1700 1558
1701 // Advance generation values, so that 1559 /* Advance generation values, so that
1702 // mutations won't interfer with the running operation. 1560 mutations won't interfer with the running operation. */
1561 op->set = set;
1703 op->generation_created = set->current_generation; 1562 op->generation_created = set->current_generation;
1704 advance_generation (set); 1563 advance_generation (set);
1705
1706 op->vt = set->vt;
1707 GNUNET_CONTAINER_DLL_insert (set->ops_head, 1564 GNUNET_CONTAINER_DLL_insert (set->ops_head,
1708 set->ops_tail, 1565 set->ops_tail,
1709 op); 1566 op);
1710 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1567 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1711 "Creating new CADET channel to port %s\n", 1568 "Creating new CADET channel to port %s for set operation type %u\n",
1712 GNUNET_h2s (&msg->app_id)); 1569 GNUNET_h2s (&msg->app_id),
1713 op->channel = GNUNET_CADET_channel_creatE (cadet, 1570 set->operation);
1571 op->channel = GNUNET_CADET_channel_create (cadet,
1714 op, 1572 op,
1715 &msg->target_peer, 1573 &msg->target_peer,
1716 &msg->app_id, 1574 &msg->app_id,
@@ -1719,9 +1577,15 @@ handle_client_evaluate (void *cls,
1719 &channel_end_cb, 1577 &channel_end_cb,
1720 cadet_handlers); 1578 cadet_handlers);
1721 op->mq = GNUNET_CADET_get_mq (op->channel); 1579 op->mq = GNUNET_CADET_get_mq (op->channel);
1722 set->vt->evaluate (op, 1580 op->state = set->vt->evaluate (op,
1723 context); 1581 context);
1724 GNUNET_SERVICE_client_continue (client); 1582 if (NULL == op->state)
1583 {
1584 GNUNET_break (0);
1585 GNUNET_SERVICE_client_drop (cs->client);
1586 return;
1587 }
1588 GNUNET_SERVICE_client_continue (cs->client);
1725} 1589}
1726 1590
1727 1591
@@ -1737,15 +1601,14 @@ static void
1737handle_client_iter_ack (void *cls, 1601handle_client_iter_ack (void *cls,
1738 const struct GNUNET_SET_IterAckMessage *ack) 1602 const struct GNUNET_SET_IterAckMessage *ack)
1739{ 1603{
1740 struct GNUNET_SERVICE_Client *client = cls; 1604 struct ClientState *cs = cls;
1741 struct Set *set; 1605 struct Set *set;
1742 1606
1743 set = set_get (client); 1607 if (NULL == (set = cs->set))
1744 if (NULL == set)
1745 { 1608 {
1746 /* client without a set acknowledged receiving a value */ 1609 /* client without a set acknowledged receiving a value */
1747 GNUNET_break (0); 1610 GNUNET_break (0);
1748 GNUNET_SERVICE_client_drop (client); 1611 GNUNET_SERVICE_client_drop (cs->client);
1749 return; 1612 return;
1750 } 1613 }
1751 if (NULL == set->iter) 1614 if (NULL == set->iter)
@@ -1753,10 +1616,10 @@ handle_client_iter_ack (void *cls,
1753 /* client sent an ack, but we were not expecting one (as 1616 /* client sent an ack, but we were not expecting one (as
1754 set iteration has finished) */ 1617 set iteration has finished) */
1755 GNUNET_break (0); 1618 GNUNET_break (0);
1756 GNUNET_SERVICE_client_drop (client); 1619 GNUNET_SERVICE_client_drop (cs->client);
1757 return; 1620 return;
1758 } 1621 }
1759 GNUNET_SERVICE_client_continue (client); 1622 GNUNET_SERVICE_client_continue (cs->client);
1760 if (ntohl (ack->send_more)) 1623 if (ntohl (ack->send_more))
1761 { 1624 {
1762 send_client_element (set); 1625 send_client_element (set);
@@ -1780,42 +1643,33 @@ static void
1780handle_client_copy_lazy_prepare (void *cls, 1643handle_client_copy_lazy_prepare (void *cls,
1781 const struct GNUNET_MessageHeader *mh) 1644 const struct GNUNET_MessageHeader *mh)
1782{ 1645{
1783 struct GNUNET_SERVICE_Client *client = cls; 1646 struct ClientState *cs = cls;
1784 struct Set *set; 1647 struct Set *set;
1785 struct LazyCopyRequest *cr; 1648 struct LazyCopyRequest *cr;
1786 struct GNUNET_MQ_Envelope *ev; 1649 struct GNUNET_MQ_Envelope *ev;
1787 struct GNUNET_SET_CopyLazyResponseMessage *resp_msg; 1650 struct GNUNET_SET_CopyLazyResponseMessage *resp_msg;
1788 1651
1789 set = set_get (client); 1652 if (NULL == (set = cs->set))
1790 if (NULL == set)
1791 { 1653 {
1792 /* client without a set requested an operation */ 1654 /* client without a set requested an operation */
1793 GNUNET_break (0); 1655 GNUNET_break (0);
1794 GNUNET_SERVICE_client_drop (client); 1656 GNUNET_SERVICE_client_drop (cs->client);
1795 return; 1657 return;
1796 } 1658 }
1797 1659 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1660 "Client requested creation of lazy copy\n");
1798 cr = GNUNET_new (struct LazyCopyRequest); 1661 cr = GNUNET_new (struct LazyCopyRequest);
1799 1662 cr->cookie = ++lazy_copy_cookie;
1800 cr->cookie = lazy_copy_cookie;
1801 lazy_copy_cookie += 1;
1802 cr->source_set = set; 1663 cr->source_set = set;
1803
1804 GNUNET_CONTAINER_DLL_insert (lazy_copy_head, 1664 GNUNET_CONTAINER_DLL_insert (lazy_copy_head,
1805 lazy_copy_tail, 1665 lazy_copy_tail,
1806 cr); 1666 cr);
1807
1808
1809 ev = GNUNET_MQ_msg (resp_msg, 1667 ev = GNUNET_MQ_msg (resp_msg,
1810 GNUNET_MESSAGE_TYPE_SET_COPY_LAZY_RESPONSE); 1668 GNUNET_MESSAGE_TYPE_SET_COPY_LAZY_RESPONSE);
1811 resp_msg->cookie = cr->cookie; 1669 resp_msg->cookie = cr->cookie;
1812 GNUNET_MQ_send (set->client_mq, ev); 1670 GNUNET_MQ_send (set->cs->mq,
1813 1671 ev);
1814 1672 GNUNET_SERVICE_client_continue (cs->client);
1815 GNUNET_SERVICE_client_continue (client);
1816
1817 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1818 "Client requested lazy copy\n");
1819} 1673}
1820 1674
1821 1675
@@ -1829,21 +1683,19 @@ static void
1829handle_client_copy_lazy_connect (void *cls, 1683handle_client_copy_lazy_connect (void *cls,
1830 const struct GNUNET_SET_CopyLazyConnectMessage *msg) 1684 const struct GNUNET_SET_CopyLazyConnectMessage *msg)
1831{ 1685{
1832 struct GNUNET_SERVICE_Client *client = cls; 1686 struct ClientState *cs = cls;
1833 struct LazyCopyRequest *cr; 1687 struct LazyCopyRequest *cr;
1834 struct Set *set; 1688 struct Set *set;
1835 int found; 1689 int found;
1836 1690
1837 if (NULL != set_get (client)) 1691 if (NULL != cs->set)
1838 { 1692 {
1839 /* There can only be one set per client */ 1693 /* There can only be one set per client */
1840 GNUNET_break (0); 1694 GNUNET_break (0);
1841 GNUNET_SERVICE_client_drop (client); 1695 GNUNET_SERVICE_client_drop (cs->client);
1842 return; 1696 return;
1843 } 1697 }
1844
1845 found = GNUNET_NO; 1698 found = GNUNET_NO;
1846
1847 for (cr = lazy_copy_head; NULL != cr; cr = cr->next) 1699 for (cr = lazy_copy_head; NULL != cr; cr = cr->next)
1848 { 1700 {
1849 if (cr->cookie == msg->cookie) 1701 if (cr->cookie == msg->cookie)
@@ -1852,21 +1704,20 @@ handle_client_copy_lazy_connect (void *cls,
1852 break; 1704 break;
1853 } 1705 }
1854 } 1706 }
1855
1856 if (GNUNET_NO == found) 1707 if (GNUNET_NO == found)
1857 { 1708 {
1858 /* client asked for copy with cookie we don't know */ 1709 /* client asked for copy with cookie we don't know */
1859 GNUNET_break (0); 1710 GNUNET_break (0);
1860 GNUNET_SERVICE_client_drop (client); 1711 GNUNET_SERVICE_client_drop (cs->client);
1861 return; 1712 return;
1862 } 1713 }
1863
1864 GNUNET_CONTAINER_DLL_remove (lazy_copy_head, 1714 GNUNET_CONTAINER_DLL_remove (lazy_copy_head,
1865 lazy_copy_tail, 1715 lazy_copy_tail,
1866 cr); 1716 cr);
1867 1717 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1718 "Client %p requested use of lazy copy\n",
1719 cs);
1868 set = GNUNET_new (struct Set); 1720 set = GNUNET_new (struct Set);
1869
1870 switch (cr->source_set->operation) 1721 switch (cr->source_set->operation)
1871 { 1722 {
1872 case GNUNET_SET_OPERATION_INTERSECTION: 1723 case GNUNET_SET_OPERATION_INTERSECTION:
@@ -1886,37 +1737,28 @@ handle_client_copy_lazy_connect (void *cls,
1886 GNUNET_break (0); 1737 GNUNET_break (0);
1887 GNUNET_free (set); 1738 GNUNET_free (set);
1888 GNUNET_free (cr); 1739 GNUNET_free (cr);
1889 GNUNET_SERVICE_client_drop (client); 1740 GNUNET_SERVICE_client_drop (cs->client);
1890 return; 1741 return;
1891 } 1742 }
1892 1743
1893 set->operation = cr->source_set->operation; 1744 set->operation = cr->source_set->operation;
1894 set->state = set->vt->copy_state (cr->source_set); 1745 set->state = set->vt->copy_state (cr->source_set->state);
1895 set->content = cr->source_set->content; 1746 set->content = cr->source_set->content;
1896 set->content->refcount += 1; 1747 set->content->refcount++;
1897 1748
1898 set->current_generation = cr->source_set->current_generation; 1749 set->current_generation = cr->source_set->current_generation;
1899 set->excluded_generations_size = cr->source_set->excluded_generations_size; 1750 set->excluded_generations_size = cr->source_set->excluded_generations_size;
1900 set->excluded_generations = GNUNET_memdup (cr->source_set->excluded_generations, 1751 set->excluded_generations
1901 set->excluded_generations_size * sizeof (struct GenerationRange)); 1752 = GNUNET_memdup (cr->source_set->excluded_generations,
1753 set->excluded_generations_size * sizeof (struct GenerationRange));
1902 1754
1903 /* Advance the generation of the new set, so that mutations to the 1755 /* Advance the generation of the new set, so that mutations to the
1904 of the cloned set and the source set are independent. */ 1756 of the cloned set and the source set are independent. */
1905 advance_generation (set); 1757 advance_generation (set);
1906 1758 set->cs = cs;
1907 1759 cs->set = set;
1908 set->client = client;
1909 set->client_mq = GNUNET_SERVICE_client_get_mq (client);
1910 GNUNET_CONTAINER_DLL_insert (sets_head,
1911 sets_tail,
1912 set);
1913
1914 GNUNET_free (cr); 1760 GNUNET_free (cr);
1915 1761 GNUNET_SERVICE_client_continue (cs->client);
1916 GNUNET_SERVICE_client_continue (client);
1917
1918 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1919 "Client connected to lazy set\n");
1920} 1762}
1921 1763
1922 1764
@@ -1930,26 +1772,22 @@ static void
1930handle_client_cancel (void *cls, 1772handle_client_cancel (void *cls,
1931 const struct GNUNET_SET_CancelMessage *msg) 1773 const struct GNUNET_SET_CancelMessage *msg)
1932{ 1774{
1933 struct GNUNET_SERVICE_Client *client = cls; 1775 struct ClientState *cs = cls;
1934 struct Set *set; 1776 struct Set *set;
1935 struct Operation *op; 1777 struct Operation *op;
1936 int found; 1778 int found;
1937 1779
1938 set = set_get (client); 1780 if (NULL == (set = cs->set))
1939 if (NULL == set)
1940 { 1781 {
1941 /* client without a set requested an operation */ 1782 /* client without a set requested an operation */
1942 GNUNET_break (0); 1783 GNUNET_break (0);
1943 GNUNET_SERVICE_client_drop (client); 1784 GNUNET_SERVICE_client_drop (cs->client);
1944 return; 1785 return;
1945 } 1786 }
1946 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1947 "Client requested cancel for op %u\n",
1948 (uint32_t) ntohl (msg->request_id));
1949 found = GNUNET_NO; 1787 found = GNUNET_NO;
1950 for (op = set->ops_head; NULL != op; op = op->next) 1788 for (op = set->ops_head; NULL != op; op = op->next)
1951 { 1789 {
1952 if (op->spec->client_request_id == ntohl (msg->request_id)) 1790 if (op->client_request_id == ntohl (msg->request_id))
1953 { 1791 {
1954 found = GNUNET_YES; 1792 found = GNUNET_YES;
1955 break; 1793 break;
@@ -1962,15 +1800,19 @@ handle_client_cancel (void *cls,
1962 * yet and try to cancel the (just barely non-existent) operation. 1800 * yet and try to cancel the (just barely non-existent) operation.
1963 * So this is not a hard error. 1801 * So this is not a hard error.
1964 */ 1802 */
1965 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1803 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1966 "Client canceled non-existent op\n"); 1804 "Client canceled non-existent op %u\n",
1805 (uint32_t) ntohl (msg->request_id));
1967 } 1806 }
1968 else 1807 else
1969 { 1808 {
1809 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1810 "Client requested cancel for op %u\n",
1811 (uint32_t) ntohl (msg->request_id));
1970 _GSS_operation_destroy (op, 1812 _GSS_operation_destroy (op,
1971 GNUNET_YES); 1813 GNUNET_YES);
1972 } 1814 }
1973 GNUNET_SERVICE_client_continue (client); 1815 GNUNET_SERVICE_client_continue (cs->client);
1974} 1816}
1975 1817
1976 1818
@@ -1986,18 +1828,18 @@ static void
1986handle_client_accept (void *cls, 1828handle_client_accept (void *cls,
1987 const struct GNUNET_SET_AcceptMessage *msg) 1829 const struct GNUNET_SET_AcceptMessage *msg)
1988{ 1830{
1989 struct GNUNET_SERVICE_Client *client = cls; 1831 struct ClientState *cs = cls;
1990 struct Set *set; 1832 struct Set *set;
1991 struct Operation *op; 1833 struct Operation *op;
1992 struct GNUNET_SET_ResultMessage *result_message; 1834 struct GNUNET_SET_ResultMessage *result_message;
1993 struct GNUNET_MQ_Envelope *ev; 1835 struct GNUNET_MQ_Envelope *ev;
1836 struct Listener *listener;
1994 1837
1995 set = set_get (client); 1838 if (NULL == (set = cs->set))
1996 if (NULL == set)
1997 { 1839 {
1998 /* client without a set requested to accept */ 1840 /* client without a set requested to accept */
1999 GNUNET_break (0); 1841 GNUNET_break (0);
2000 GNUNET_SERVICE_client_drop (client); 1842 GNUNET_SERVICE_client_drop (cs->client);
2001 return; 1843 return;
2002 } 1844 }
2003 op = get_incoming (ntohl (msg->accept_reject_id)); 1845 op = get_incoming (ntohl (msg->accept_reject_id));
@@ -2005,71 +1847,75 @@ handle_client_accept (void *cls,
2005 { 1847 {
2006 /* It is not an error if the set op does not exist -- it may 1848 /* It is not an error if the set op does not exist -- it may
2007 * have been destroyed when the partner peer disconnected. */ 1849 * have been destroyed when the partner peer disconnected. */
2008 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1850 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2009 "Client accepted request that is no longer active\n"); 1851 "Client %p accepted request %u of listener %p that is no longer active\n",
1852 cs,
1853 ntohl (msg->accept_reject_id),
1854 cs->listener);
2010 ev = GNUNET_MQ_msg (result_message, 1855 ev = GNUNET_MQ_msg (result_message,
2011 GNUNET_MESSAGE_TYPE_SET_RESULT); 1856 GNUNET_MESSAGE_TYPE_SET_RESULT);
2012 result_message->request_id = msg->request_id; 1857 result_message->request_id = msg->request_id;
2013 result_message->element_type = 0;
2014 result_message->result_status = htons (GNUNET_SET_STATUS_FAILURE); 1858 result_message->result_status = htons (GNUNET_SET_STATUS_FAILURE);
2015 GNUNET_MQ_send (set->client_mq, ev); 1859 GNUNET_MQ_send (set->cs->mq,
2016 GNUNET_SERVICE_client_continue (client); 1860 ev);
1861 GNUNET_SERVICE_client_continue (cs->client);
2017 return; 1862 return;
2018 } 1863 }
2019
2020 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1864 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2021 "Client accepting request %u\n", 1865 "Client accepting request %u\n",
2022 (uint32_t) ntohl (msg->accept_reject_id)); 1866 (uint32_t) ntohl (msg->accept_reject_id));
2023 GNUNET_assert (GNUNET_YES == op->is_incoming); 1867 listener = op->listener;
2024 op->is_incoming = GNUNET_NO; 1868 op->listener = NULL;
2025 GNUNET_CONTAINER_DLL_remove (incoming_head, 1869 GNUNET_CONTAINER_DLL_remove (listener->op_head,
2026 incoming_tail, 1870 listener->op_tail,
2027 op); 1871 op);
2028 op->spec->set = set; 1872 op->set = set;
2029 GNUNET_CONTAINER_DLL_insert (set->ops_head, 1873 GNUNET_CONTAINER_DLL_insert (set->ops_head,
2030 set->ops_tail, 1874 set->ops_tail,
2031 op); 1875 op);
2032 op->spec->client_request_id = ntohl (msg->request_id); 1876 op->client_request_id = ntohl (msg->request_id);
2033 op->spec->result_mode = ntohl (msg->result_mode); 1877 op->result_mode = ntohl (msg->result_mode);
2034 op->spec->byzantine = msg->byzantine; 1878 op->byzantine = msg->byzantine;
2035 op->spec->byzantine_lower_bound = msg->byzantine_lower_bound; 1879 op->byzantine_lower_bound = msg->byzantine_lower_bound;
2036 op->spec->force_full = msg->force_full; 1880 op->force_full = msg->force_full;
2037 op->spec->force_delta = msg->force_delta; 1881 op->force_delta = msg->force_delta;
2038 1882
2039 // Advance generation values, so that 1883 /* Advance generation values, so that future mutations do not
2040 // mutations won't interfer with the running operation. 1884 interfer with the running operation. */
2041 op->generation_created = set->current_generation; 1885 op->generation_created = set->current_generation;
2042 advance_generation (set); 1886 advance_generation (set);
2043 1887 GNUNET_assert (NULL == op->state);
2044 op->vt = set->vt; 1888 op->state = set->vt->accept (op);
2045 op->vt->accept (op); 1889 if (NULL == op->state)
2046 GNUNET_SERVICE_client_continue (client); 1890 {
1891 GNUNET_break (0);
1892 GNUNET_SERVICE_client_drop (cs->client);
1893 return;
1894 }
1895 /* Now allow CADET to continue, as we did not do this in
1896 #handle_incoming_msg (as we wanted to first see if the
1897 local client would accept the request). */
1898 GNUNET_CADET_receive_done (op->channel);
1899 GNUNET_SERVICE_client_continue (cs->client);
2047} 1900}
2048 1901
2049 1902
2050/** 1903/**
2051 * Called to clean up, after a shutdown has been requested. 1904 * Called to clean up, after a shutdown has been requested.
2052 * 1905 *
2053 * @param cls closure 1906 * @param cls closure, NULL
2054 */ 1907 */
2055static void 1908static void
2056shutdown_task (void *cls) 1909shutdown_task (void *cls)
2057{ 1910{
2058 while (NULL != incoming_head) 1911 /* Delay actual shutdown to allow service to disconnect clients */
2059 incoming_destroy (incoming_head);
2060 while (NULL != listeners_head)
2061 listener_destroy (listeners_head);
2062 while (NULL != sets_head)
2063 set_destroy (sets_head);
2064
2065 /* it's important to destroy cadet at the end, as all channels
2066 * must be destroyed before the cadet handle! */
2067 if (NULL != cadet) 1912 if (NULL != cadet)
2068 { 1913 {
2069 GNUNET_CADET_disconnect (cadet); 1914 GNUNET_CADET_disconnect (cadet);
2070 cadet = NULL; 1915 cadet = NULL;
2071 } 1916 }
2072 GNUNET_STATISTICS_destroy (_GSS_statistics, GNUNET_YES); 1917 GNUNET_STATISTICS_destroy (_GSS_statistics,
1918 GNUNET_YES);
2073 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1919 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2074 "handled shutdown request\n"); 1920 "handled shutdown request\n");
2075} 1921}
@@ -2088,15 +1934,19 @@ run (void *cls,
2088 const struct GNUNET_CONFIGURATION_Handle *cfg, 1934 const struct GNUNET_CONFIGURATION_Handle *cfg,
2089 struct GNUNET_SERVICE_Handle *service) 1935 struct GNUNET_SERVICE_Handle *service)
2090{ 1936{
2091 configuration = cfg; 1937 /* FIXME: need to modify SERVICE (!) API to allow
1938 us to run a shutdown task *after* clients were
1939 forcefully disconnected! */
2092 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, 1940 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
2093 NULL); 1941 NULL);
2094 _GSS_statistics = GNUNET_STATISTICS_create ("set", cfg); 1942 _GSS_statistics = GNUNET_STATISTICS_create ("set",
2095 cadet = GNUNET_CADET_connecT (cfg); 1943 cfg);
1944 cadet = GNUNET_CADET_connect (cfg);
2096 if (NULL == cadet) 1945 if (NULL == cadet)
2097 { 1946 {
2098 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1947 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2099 _("Could not connect to CADET service\n")); 1948 _("Could not connect to CADET service\n"));
1949 GNUNET_SCHEDULER_shutdown ();
2100 return; 1950 return;
2101 } 1951 }
2102} 1952}
@@ -2122,7 +1972,7 @@ GNUNET_SERVICE_MAIN
2122 NULL), 1972 NULL),
2123 GNUNET_MQ_hd_var_size (client_mutation, 1973 GNUNET_MQ_hd_var_size (client_mutation,
2124 GNUNET_MESSAGE_TYPE_SET_ADD, 1974 GNUNET_MESSAGE_TYPE_SET_ADD,
2125 struct GNUNET_MessageHeader, 1975 struct GNUNET_SET_ElementMessage,
2126 NULL), 1976 NULL),
2127 GNUNET_MQ_hd_fixed_size (client_create_set, 1977 GNUNET_MQ_hd_fixed_size (client_create_set,
2128 GNUNET_MESSAGE_TYPE_SET_CREATE, 1978 GNUNET_MESSAGE_TYPE_SET_CREATE,
@@ -2146,7 +1996,7 @@ GNUNET_SERVICE_MAIN
2146 NULL), 1996 NULL),
2147 GNUNET_MQ_hd_var_size (client_mutation, 1997 GNUNET_MQ_hd_var_size (client_mutation,
2148 GNUNET_MESSAGE_TYPE_SET_REMOVE, 1998 GNUNET_MESSAGE_TYPE_SET_REMOVE,
2149 struct GNUNET_MessageHeader, 1999 struct GNUNET_SET_ElementMessage,
2150 NULL), 2000 NULL),
2151 GNUNET_MQ_hd_fixed_size (client_cancel, 2001 GNUNET_MQ_hd_fixed_size (client_cancel,
2152 GNUNET_MESSAGE_TYPE_SET_CANCEL, 2002 GNUNET_MESSAGE_TYPE_SET_CANCEL,
diff --git a/src/set/gnunet-service-set.h b/src/set/gnunet-service-set.h
index 68d8fe81f..19413fd30 100644
--- a/src/set/gnunet-service-set.h
+++ b/src/set/gnunet-service-set.h
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet 2 This file is part of GNUnet
3 Copyright (C) 2013, 2014 GNUnet e.V. 3 Copyright (C) 2013-2017 GNUnet e.V.
4 4
5 GNUnet is free software; you can redistribute it and/or modify 5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published 6 it under the terms of the GNU General Public License as published
@@ -68,92 +68,13 @@ struct Operation;
68 68
69 69
70/** 70/**
71 * Detail information about an operation.
72 */
73struct OperationSpecification
74{
75
76 /**
77 * The remove peer we evaluate the operation with.
78 */
79 struct GNUNET_PeerIdentity peer;
80
81 /**
82 * Application ID for the operation, used to distinguish
83 * multiple operations of the same type with the same peer.
84 */
85 struct GNUNET_HashCode app_id;
86
87 /**
88 * Context message, may be NULL.
89 */
90 struct GNUNET_MessageHeader *context_msg;
91
92 /**
93 * Set associated with the operation, NULL until the spec has been
94 * associated with a set.
95 */
96 struct Set *set;
97
98 /**
99 * Salt to use for the operation.
100 */
101 uint32_t salt;
102
103 /**
104 * Remote peers element count
105 */
106 uint32_t remote_element_count;
107
108 /**
109 * ID used to identify an operation between service and client
110 */
111 uint32_t client_request_id;
112
113 /**
114 * The type of the operation.
115 */
116 enum GNUNET_SET_OperationType operation;
117
118 /**
119 * When are elements sent to the client, and which elements are sent?
120 */
121 enum GNUNET_SET_ResultMode result_mode;
122
123 /**
124 * Always use delta operation instead of sending full sets,
125 * even it it's less efficient.
126 */
127 int force_delta;
128
129 /**
130 * Always send full sets, even if delta operations would
131 * be more efficient.
132 */
133 int force_full;
134
135 /**
136 * #GNUNET_YES to fail operations where Byzantine faults
137 * are suspected
138 */
139 int byzantine;
140
141 /**
142 * Lower bound for the set size, used only when
143 * byzantine mode is enabled.
144 */
145 int byzantine_lower_bound;
146};
147
148
149/**
150 * Signature of functions that create the implementation-specific 71 * Signature of functions that create the implementation-specific
151 * state for a set supporting a specific operation. 72 * state for a set supporting a specific operation.
152 * 73 *
153 * @return a set state specific to the supported operation, NULL on error 74 * @return a set state specific to the supported operation, NULL on error
154 */ 75 */
155typedef struct SetState * 76typedef struct SetState *
156(*CreateImpl) (void); 77(*SetCreateImpl) (void);
157 78
158 79
159/** 80/**
@@ -164,18 +85,18 @@ typedef struct SetState *
164 * @param ee element message from the client 85 * @param ee element message from the client
165 */ 86 */
166typedef void 87typedef void
167(*AddRemoveImpl) (struct SetState *state, 88(*SetAddRemoveImpl) (struct SetState *state,
168 struct ElementEntry *ee); 89 struct ElementEntry *ee);
169 90
170 91
171/** 92/**
172 * Signature of functions that handle disconnection of the remote 93 * Make a copy of a set's internal state.
173 * peer.
174 * 94 *
175 * @param op the set operation, contains implementation-specific data 95 * @param state set state to copy
96 * @return copy of the internal state
176 */ 97 */
177typedef void 98typedef struct SetState *
178(*PeerDisconnectImpl) (struct Operation *op); 99(*SetCopyStateImpl) (struct SetState *state);
179 100
180 101
181/** 102/**
@@ -185,7 +106,7 @@ typedef void
185 * @param state the set state, contains implementation-specific data 106 * @param state the set state, contains implementation-specific data
186 */ 107 */
187typedef void 108typedef void
188(*DestroySetImpl) (struct SetState *state); 109(*SetDestroyImpl) (struct SetState *state);
189 110
190 111
191/** 112/**
@@ -193,8 +114,9 @@ typedef void
193 * 114 *
194 * @param op operation that is created by accepting the operation, 115 * @param op operation that is created by accepting the operation,
195 * should be initialized by the implementation 116 * should be initialized by the implementation
117 * @return operation-specific state to keep in @a op
196 */ 118 */
197typedef void 119typedef struct OperationState *
198(*OpAcceptImpl) (struct Operation *op); 120(*OpAcceptImpl) (struct Operation *op);
199 121
200 122
@@ -206,38 +128,32 @@ typedef void
206 * begin the evaluation 128 * begin the evaluation
207 * @param opaque_context message to be transmitted to the listener 129 * @param opaque_context message to be transmitted to the listener
208 * to convince him to accept, may be NULL 130 * to convince him to accept, may be NULL
131 * @return operation-specific state to keep in @a op
209 */ 132 */
210typedef void 133typedef struct OperationState *
211(*OpEvaluateImpl) (struct Operation *op, 134(*OpEvaluateImpl) (struct Operation *op,
212 const struct GNUNET_MessageHeader *opaque_context); 135 const struct GNUNET_MessageHeader *opaque_context);
213 136
214
215/** 137/**
216 * Signature of functions that implement the message handling for 138 * Signature of functions that implement operation cancelation.
217 * the different set operations. 139 * This includes notifying the client about the operation's final
140 * state.
218 * 141 *
219 * @param op operation state 142 * @param op operation state
220 * @param msg received message
221 * @return #GNUNET_OK on success, #GNUNET_SYSERR to
222 * destroy the operation and the tunnel
223 */ 143 */
224typedef int 144typedef void
225(*MsgHandlerImpl) (struct Operation *op, 145(*OpCancelImpl) (struct Operation *op);
226 const struct GNUNET_MessageHeader *msg);
227 146
228 147
229/** 148/**
230 * Signature of functions that implement operation cancellation 149 * Signature of functions called when the CADET channel died.
231 * 150 *
232 * @param op operation state 151 * @param op operation state
233 */ 152 */
234typedef void 153typedef void
235(*CancelImpl) (struct Operation *op); 154(*OpChannelDeathImpl) (struct Operation *op);
236 155
237 156
238typedef struct SetState *
239(*CopyStateImpl) (struct Set *op);
240
241 157
242/** 158/**
243 * Dispatch table for a specific set operation. Every set operation 159 * Dispatch table for a specific set operation. Every set operation
@@ -248,49 +164,48 @@ struct SetVT
248 /** 164 /**
249 * Callback for the set creation. 165 * Callback for the set creation.
250 */ 166 */
251 CreateImpl create; 167 SetCreateImpl create;
252 168
253 /** 169 /**
254 * Callback for element insertion 170 * Callback for element insertion
255 */ 171 */
256 AddRemoveImpl add; 172 SetAddRemoveImpl add;
257 173
258 /** 174 /**
259 * Callback for element removal. 175 * Callback for element removal.
260 */ 176 */
261 AddRemoveImpl remove; 177 SetAddRemoveImpl remove;
262 178
263 /** 179 /**
264 * Callback for accepting a set operation request 180 * Callback for making a copy of a set's internal state.
265 */ 181 */
266 OpAcceptImpl accept; 182 SetCopyStateImpl copy_state;
267 183
268 /** 184 /**
269 * Callback for starting evaluation with a remote peer. 185 * Callback for destruction of the set state.
270 */ 186 */
271 OpEvaluateImpl evaluate; 187 SetDestroyImpl destroy_set;
272 188
273 /** 189 /**
274 * Callback for destruction of the set state. 190 * Callback for accepting a set operation request
275 */ 191 */
276 DestroySetImpl destroy_set; 192 OpAcceptImpl accept;
277 193
278 /** 194 /**
279 * Callback for handling operation-specific messages. 195 * Callback for starting evaluation with a remote peer.
280 */ 196 */
281 MsgHandlerImpl msg_handler; 197 OpEvaluateImpl evaluate;
282 198
283 /** 199 /**
284 * Callback for handling the remote peer's disconnect. 200 * Callback for canceling an operation.
285 */ 201 */
286 PeerDisconnectImpl peer_disconnect; 202 OpCancelImpl cancel;
287 203
288 /** 204 /**
289 * Callback for canceling an operation by its ID. 205 * Callback called in case the CADET channel died.
290 */ 206 */
291 CancelImpl cancel; 207 OpChannelDeathImpl channel_death;
292 208
293 CopyStateImpl copy_state;
294}; 209};
295 210
296 211
@@ -360,20 +275,56 @@ struct ElementEntry
360}; 275};
361 276
362 277
278/**
279 * A listener is inhabited by a client, and waits for evaluation
280 * requests from remote peers.
281 */
363struct Listener; 282struct Listener;
364 283
365 284
366/** 285/**
286 * State we keep per client.
287 */
288struct ClientState
289{
290 /**
291 * Set, if associated with the client, otherwise NULL.
292 */
293 struct Set *set;
294
295 /**
296 * Listener, if associated with the client, otherwise NULL.
297 */
298 struct Listener *listener;
299
300 /**
301 * Client handle.
302 */
303 struct GNUNET_SERVICE_Client *client;
304
305 /**
306 * Message queue.
307 */
308 struct GNUNET_MQ_Handle *mq;
309
310};
311
312
313/**
367 * Operation context used to execute a set operation. 314 * Operation context used to execute a set operation.
368 */ 315 */
369struct Operation 316struct Operation
370{ 317{
318
371 /** 319 /**
372 * V-Table for the operation belonging to the tunnel contest. 320 * Kept in a DLL of the listener, if @e listener is non-NULL.
373 *
374 * Used for all operation specific operations after receiving the ops request
375 */ 321 */
376 const struct SetVT *vt; 322 struct Operation *next;
323
324 /**
325 * Kept in a DLL of the listener, if @e listener is non-NULL.
326 */
327 struct Operation *prev;
377 328
378 /** 329 /**
379 * Channel to the peer. 330 * Channel to the peer.
@@ -391,11 +342,15 @@ struct Operation
391 struct GNUNET_MQ_Handle *mq; 342 struct GNUNET_MQ_Handle *mq;
392 343
393 /** 344 /**
394 * Detail information about the set operation, including the set to 345 * Context message, may be NULL.
395 * use. When 'spec' is NULL, the operation is not yet entirely 346 */
396 * initialized. 347 struct GNUNET_MessageHeader *context_msg;
348
349 /**
350 * Set associated with the operation, NULL until the spec has been
351 * associated with a set.
397 */ 352 */
398 struct OperationSpecification *spec; 353 struct Set *set;
399 354
400 /** 355 /**
401 * Operation-specific operation state. Note that the exact 356 * Operation-specific operation state. Note that the exact
@@ -405,16 +360,6 @@ struct Operation
405 struct OperationState *state; 360 struct OperationState *state;
406 361
407 /** 362 /**
408 * Evaluate operations are held in a linked list.
409 */
410 struct Operation *next;
411
412 /**
413 * Evaluate operations are held in a linked list.
414 */
415 struct Operation *prev;
416
417 /**
418 * The identity of the requesting peer. Needs to 363 * The identity of the requesting peer. Needs to
419 * be stored here as the op spec might not have been created yet. 364 * be stored here as the op spec might not have been created yet.
420 */ 365 */
@@ -427,6 +372,50 @@ struct Operation
427 struct GNUNET_SCHEDULER_Task *timeout_task; 372 struct GNUNET_SCHEDULER_Task *timeout_task;
428 373
429 /** 374 /**
375 * Salt to use for the operation.
376 */
377 uint32_t salt;
378
379 /**
380 * Remote peers element count
381 */
382 uint32_t remote_element_count;
383
384 /**
385 * ID used to identify an operation between service and client
386 */
387 uint32_t client_request_id;
388
389 /**
390 * When are elements sent to the client, and which elements are sent?
391 */
392 enum GNUNET_SET_ResultMode result_mode;
393
394 /**
395 * Always use delta operation instead of sending full sets,
396 * even it it's less efficient.
397 */
398 int force_delta;
399
400 /**
401 * Always send full sets, even if delta operations would
402 * be more efficient.
403 */
404 int force_full;
405
406 /**
407 * #GNUNET_YES to fail operations where Byzantine faults
408 * are suspected
409 */
410 int byzantine;
411
412 /**
413 * Lower bound for the set size, used only when
414 * byzantine mode is enabled.
415 */
416 int byzantine_lower_bound;
417
418 /**
430 * Unique request id for the request from a remote peer, sent to the 419 * Unique request id for the request from a remote peer, sent to the
431 * client, which will accept or reject the request. Set to '0' iff 420 * client, which will accept or reject the request. Set to '0' iff
432 * the request has not been suggested yet. 421 * the request has not been suggested yet.
@@ -434,45 +423,26 @@ struct Operation
434 uint32_t suggest_id; 423 uint32_t suggest_id;
435 424
436 /** 425 /**
437 * #GNUNET_YES if this is not a "real" set operation yet, and we still
438 * need to wait for the other peer to give us more details.
439 */
440 int is_incoming;
441
442 /**
443 * Generation in which the operation handle 426 * Generation in which the operation handle
444 * was created. 427 * was created.
445 */ 428 */
446 unsigned int generation_created; 429 unsigned int generation_created;
447 430
448 /**
449 * Incremented whenever (during shutdown) some component still
450 * needs to do something with this before the operation is freed.
451 * (Used as a reference counter, but only during termination.)
452 */
453 unsigned int keep;
454}; 431};
455 432
456 433
457/** 434/**
458 * SetContent stores the actual set elements, 435 * SetContent stores the actual set elements, which may be shared by
459 * which may be shared by multiple generations derived 436 * multiple generations derived from one set.
460 * from one set.
461 */ 437 */
462struct SetContent 438struct SetContent
463{ 439{
464 /**
465 * Number of references to the content.
466 */
467 unsigned int refcount;
468 440
469 /** 441 /**
470 * Maps `struct GNUNET_HashCode *` to `struct ElementEntry *`. 442 * Maps `struct GNUNET_HashCode *` to `struct ElementEntry *`.
471 */ 443 */
472 struct GNUNET_CONTAINER_MultiHashMap *elements; 444 struct GNUNET_CONTAINER_MultiHashMap *elements;
473 445
474 unsigned int latest_generation;
475
476 /** 446 /**
477 * Mutations requested by the client that we're 447 * Mutations requested by the client that we're
478 * unable to execute right now because we're iterating 448 * unable to execute right now because we're iterating
@@ -488,6 +458,16 @@ struct SetContent
488 struct PendingMutation *pending_mutations_tail; 458 struct PendingMutation *pending_mutations_tail;
489 459
490 /** 460 /**
461 * Number of references to the content.
462 */
463 unsigned int refcount;
464
465 /**
466 * FIXME: document!
467 */
468 unsigned int latest_generation;
469
470 /**
491 * Number of concurrently active iterators. 471 * Number of concurrently active iterators.
492 */ 472 */
493 int iterator_count; 473 int iterator_count;
@@ -508,11 +488,24 @@ struct GenerationRange
508}; 488};
509 489
510 490
491/**
492 * Information about a mutation to apply to a set.
493 */
511struct PendingMutation 494struct PendingMutation
512{ 495{
496 /**
497 * Mutations are kept in a DLL.
498 */
513 struct PendingMutation *prev; 499 struct PendingMutation *prev;
500
501 /**
502 * Mutations are kept in a DLL.
503 */
514 struct PendingMutation *next; 504 struct PendingMutation *next;
515 505
506 /**
507 * Set this mutation is about.
508 */
516 struct Set *set; 509 struct Set *set;
517 510
518 /** 511 /**
@@ -520,7 +513,7 @@ struct PendingMutation
520 * May only be a #GNUNET_MESSAGE_TYPE_SET_ADD or 513 * May only be a #GNUNET_MESSAGE_TYPE_SET_ADD or
521 * #GNUNET_MESSAGE_TYPE_SET_REMOVE. 514 * #GNUNET_MESSAGE_TYPE_SET_REMOVE.
522 */ 515 */
523 struct GNUNET_MessageHeader *mutation_message; 516 struct GNUNET_SET_ElementMessage *msg;
524}; 517};
525 518
526 519
@@ -544,12 +537,13 @@ struct Set
544 * Client that owns the set. Only one client may own a set, 537 * Client that owns the set. Only one client may own a set,
545 * and there can only be one set per client. 538 * and there can only be one set per client.
546 */ 539 */
547 struct GNUNET_SERVICE_Client *client; 540 struct ClientState *cs;
548 541
549 /** 542 /**
550 * Message queue for the client. 543 * Content, possibly shared by multiple sets,
544 * and thus reference counted.
551 */ 545 */
552 struct GNUNET_MQ_Handle *client_mq; 546 struct SetContent *content;
553 547
554 /** 548 /**
555 * Virtual table for this set. Determined by the operation type of 549 * Virtual table for this set. Determined by the operation type of
@@ -582,15 +576,15 @@ struct Set
582 struct Operation *ops_tail; 576 struct Operation *ops_tail;
583 577
584 /** 578 /**
585 * Current generation, that is, number of previously executed 579 * List of generations we have to exclude, due to lazy copies.
586 * operations and lazy copies on the underlying set content.
587 */ 580 */
588 unsigned int current_generation; 581 struct GenerationRange *excluded_generations;
589 582
590 /** 583 /**
591 * List of generations we have to exclude, due to lazy copies. 584 * Current generation, that is, number of previously executed
585 * operations and lazy copies on the underlying set content.
592 */ 586 */
593 struct GenerationRange *excluded_generations; 587 unsigned int current_generation;
594 588
595 /** 589 /**
596 * Number of elements in array @a excluded_generations. 590 * Number of elements in array @a excluded_generations.
@@ -603,21 +597,16 @@ struct Set
603 enum GNUNET_SET_OperationType operation; 597 enum GNUNET_SET_OperationType operation;
604 598
605 /** 599 /**
606 * Each @e iter is assigned a unique number, so that the client
607 * can distinguish iterations.
608 */
609 uint16_t iteration_id;
610
611 /**
612 * Generation we're currently iteration over. 600 * Generation we're currently iteration over.
613 */ 601 */
614 unsigned int iter_generation; 602 unsigned int iter_generation;
615 603
616 /** 604 /**
617 * Content, possibly shared by multiple sets, 605 * Each @e iter is assigned a unique number, so that the client
618 * and thus reference counted. 606 * can distinguish iterations.
619 */ 607 */
620 struct SetContent *content; 608 uint16_t iteration_id;
609
621}; 610};
622 611
623 612
@@ -625,10 +614,14 @@ extern struct GNUNET_STATISTICS_Handle *_GSS_statistics;
625 614
626 615
627/** 616/**
628 * Destroy the given operation. Call the implementation-specific 617 * Destroy the given operation. Used for any operation where both
629 * cancel function of the operation. Disconnects from the remote 618 * peers were known and that thus actually had a vt and channel. Must
630 * peer. Does not disconnect the client, as there may be multiple 619 * not be used for operations where 'listener' is still set and we do
631 * operations per set. 620 * not know the other peer.
621 *
622 * Call the implementation-specific cancel function of the operation.
623 * Disconnects from the remote peer. Does not disconnect the client,
624 * as there may be multiple operations per set.
632 * 625 *
633 * @param op operation to destroy 626 * @param op operation to destroy
634 * @param gc #GNUNET_YES to perform garbage collection on the set 627 * @param gc #GNUNET_YES to perform garbage collection on the set
@@ -656,10 +649,13 @@ const struct SetVT *
656_GSS_intersection_vt (void); 649_GSS_intersection_vt (void);
657 650
658 651
659int 652/**
660_GSS_is_element_of_set (struct ElementEntry *ee, 653 * Is element @a ee part of the set used by @a op?
661 struct Set *set); 654 *
662 655 * @param ee element to test
656 * @param op operation the defines the set and its generation
657 * @return #GNUNET_YES if the element is in the set, #GNUNET_NO if not
658 */
663int 659int
664_GSS_is_element_of_operation (struct ElementEntry *ee, 660_GSS_is_element_of_operation (struct ElementEntry *ee,
665 struct Operation *op); 661 struct Operation *op);
diff --git a/src/set/gnunet-service-set_intersection.c b/src/set/gnunet-service-set_intersection.c
index 9fe1eabe6..9dc421792 100644
--- a/src/set/gnunet-service-set_intersection.c
+++ b/src/set/gnunet-service-set_intersection.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet 2 This file is part of GNUnet
3 Copyright (C) 2013, 2014 GNUnet e.V. 3 Copyright (C) 2013-2017 GNUnet e.V.
4 4
5 GNUnet is free software; you can redistribute it and/or modify 5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published 6 it under the terms of the GNU General Public License as published
@@ -28,6 +28,7 @@
28#include "gnunet-service-set.h" 28#include "gnunet-service-set.h"
29#include "gnunet_block_lib.h" 29#include "gnunet_block_lib.h"
30#include "gnunet-service-set_protocol.h" 30#include "gnunet-service-set_protocol.h"
31#include "gnunet-service-set_intersection.h"
31#include <gcrypt.h> 32#include <gcrypt.h>
32 33
33 34
@@ -55,6 +56,18 @@ enum IntersectionOperationPhase
55 PHASE_BF_EXCHANGE, 56 PHASE_BF_EXCHANGE,
56 57
57 /** 58 /**
59 * We must next send the P2P DONE message (after finishing mostly
60 * with the local client). Then we will wait for the channel to close.
61 */
62 PHASE_MUST_SEND_DONE,
63
64 /**
65 * We have received the P2P DONE message, and must finish with the
66 * local client before terminating the channel.
67 */
68 PHASE_DONE_RECEIVED,
69
70 /**
58 * The protocol is over. Results may still have to be sent to the 71 * The protocol is over. Results may still have to be sent to the
59 * client. 72 * client.
60 */ 73 */
@@ -161,6 +174,13 @@ struct OperationState
161 * Did we send the client that we are done? 174 * Did we send the client that we are done?
162 */ 175 */
163 int client_done_sent; 176 int client_done_sent;
177
178 /**
179 * Set whenever we reach the state where the death of the
180 * channel is perfectly find and should NOT result in the
181 * operation being cancelled.
182 */
183 int channel_death_expected;
164}; 184};
165 185
166 186
@@ -192,12 +212,12 @@ send_client_removed_element (struct Operation *op,
192 struct GNUNET_MQ_Envelope *ev; 212 struct GNUNET_MQ_Envelope *ev;
193 struct GNUNET_SET_ResultMessage *rm; 213 struct GNUNET_SET_ResultMessage *rm;
194 214
195 if (GNUNET_SET_RESULT_REMOVED != op->spec->result_mode) 215 if (GNUNET_SET_RESULT_REMOVED != op->result_mode)
196 return; /* Wrong mode for transmitting removed elements */ 216 return; /* Wrong mode for transmitting removed elements */
197 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 217 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
198 "Sending removed element (size %u) to client\n", 218 "Sending removed element (size %u) to client\n",
199 element->size); 219 element->size);
200 GNUNET_assert (0 != op->spec->client_request_id); 220 GNUNET_assert (0 != op->client_request_id);
201 ev = GNUNET_MQ_msg_extra (rm, 221 ev = GNUNET_MQ_msg_extra (rm,
202 element->size, 222 element->size,
203 GNUNET_MESSAGE_TYPE_SET_RESULT); 223 GNUNET_MESSAGE_TYPE_SET_RESULT);
@@ -207,12 +227,12 @@ send_client_removed_element (struct Operation *op,
207 return; 227 return;
208 } 228 }
209 rm->result_status = htons (GNUNET_SET_STATUS_OK); 229 rm->result_status = htons (GNUNET_SET_STATUS_OK);
210 rm->request_id = htonl (op->spec->client_request_id); 230 rm->request_id = htonl (op->client_request_id);
211 rm->element_type = element->element_type; 231 rm->element_type = element->element_type;
212 GNUNET_memcpy (&rm[1], 232 GNUNET_memcpy (&rm[1],
213 element->data, 233 element->data,
214 element->size); 234 element->size);
215 GNUNET_MQ_send (op->spec->set->client_mq, 235 GNUNET_MQ_send (op->set->cs->mq,
216 ev); 236 ev);
217} 237}
218 238
@@ -396,9 +416,9 @@ fail_intersection_operation (struct Operation *op)
396 ev = GNUNET_MQ_msg (msg, 416 ev = GNUNET_MQ_msg (msg,
397 GNUNET_MESSAGE_TYPE_SET_RESULT); 417 GNUNET_MESSAGE_TYPE_SET_RESULT);
398 msg->result_status = htons (GNUNET_SET_STATUS_FAILURE); 418 msg->result_status = htons (GNUNET_SET_STATUS_FAILURE);
399 msg->request_id = htonl (op->spec->client_request_id); 419 msg->request_id = htonl (op->client_request_id);
400 msg->element_type = htons (0); 420 msg->element_type = htons (0);
401 GNUNET_MQ_send (op->spec->set->client_mq, 421 GNUNET_MQ_send (op->set->cs->mq,
402 ev); 422 ev);
403 _GSS_operation_destroy (op, 423 _GSS_operation_destroy (op,
404 GNUNET_YES); 424 GNUNET_YES);
@@ -427,8 +447,8 @@ send_bloomfilter (struct Operation *op)
427 should use more bits to maximize its set reduction 447 should use more bits to maximize its set reduction
428 potential and minimize overall bandwidth consumption. */ 448 potential and minimize overall bandwidth consumption. */
429 bf_elementbits = 2 + ceil (log2((double) 449 bf_elementbits = 2 + ceil (log2((double)
430 (op->spec->remote_element_count / 450 (op->remote_element_count /
431 (double) op->state->my_element_count))); 451 (double) op->state->my_element_count)));
432 if (bf_elementbits < 1) 452 if (bf_elementbits < 1)
433 bf_elementbits = 1; /* make sure k is not 0 */ 453 bf_elementbits = 1; /* make sure k is not 0 */
434 /* optimize BF-size to ~50% of bits set */ 454 /* optimize BF-size to ~50% of bits set */
@@ -514,12 +534,14 @@ send_client_done_and_destroy (void *cls)
514 struct GNUNET_MQ_Envelope *ev; 534 struct GNUNET_MQ_Envelope *ev;
515 struct GNUNET_SET_ResultMessage *rm; 535 struct GNUNET_SET_ResultMessage *rm;
516 536
537 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
538 "Intersection succeeded, sending DONE to local client\n");
517 ev = GNUNET_MQ_msg (rm, 539 ev = GNUNET_MQ_msg (rm,
518 GNUNET_MESSAGE_TYPE_SET_RESULT); 540 GNUNET_MESSAGE_TYPE_SET_RESULT);
519 rm->request_id = htonl (op->spec->client_request_id); 541 rm->request_id = htonl (op->client_request_id);
520 rm->result_status = htons (GNUNET_SET_STATUS_DONE); 542 rm->result_status = htons (GNUNET_SET_STATUS_DONE);
521 rm->element_type = htons (0); 543 rm->element_type = htons (0);
522 GNUNET_MQ_send (op->spec->set->client_mq, 544 GNUNET_MQ_send (op->set->cs->mq,
523 ev); 545 ev);
524 _GSS_operation_destroy (op, 546 _GSS_operation_destroy (op,
525 GNUNET_YES); 547 GNUNET_YES);
@@ -527,6 +549,53 @@ send_client_done_and_destroy (void *cls)
527 549
528 550
529/** 551/**
552 * Remember that we are done dealing with the local client
553 * AND have sent the other peer our message that we are done,
554 * so we are not just waiting for the channel to die before
555 * telling the local client that we are done as our last act.
556 *
557 * @param cls the `struct Operation`.
558 */
559static void
560finished_local_operations (void *cls)
561{
562 struct Operation *op = cls;
563
564 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
565 "DONE sent to other peer, now waiting for other end to close the channel\n");
566 op->state->phase = PHASE_FINISHED;
567 op->state->channel_death_expected = GNUNET_YES;
568}
569
570
571/**
572 * Notify the other peer that we are done. Once this message
573 * is out, we still need to notify the local client that we
574 * are done.
575 *
576 * @param op operation to notify for.
577 */
578static void
579send_p2p_done (struct Operation *op)
580{
581 struct GNUNET_MQ_Envelope *ev;
582 struct IntersectionDoneMessage *idm;
583
584 GNUNET_assert (PHASE_MUST_SEND_DONE == op->state->phase);
585 GNUNET_assert (GNUNET_NO == op->state->channel_death_expected);
586 ev = GNUNET_MQ_msg (idm,
587 GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_DONE);
588 idm->final_element_count = htonl (op->state->my_element_count);
589 idm->element_xor_hash = op->state->my_xor;
590 GNUNET_MQ_notify_sent (ev,
591 &finished_local_operations,
592 op);
593 GNUNET_MQ_send (op->mq,
594 ev);
595}
596
597
598/**
530 * Send all elements in the full result iterator. 599 * Send all elements in the full result iterator.
531 * 600 *
532 * @param cls the `struct Operation *` 601 * @param cls the `struct Operation *`
@@ -549,8 +618,21 @@ send_remaining_elements (void *cls)
549 { 618 {
550 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 619 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
551 "Sending done and destroy because iterator ran out\n"); 620 "Sending done and destroy because iterator ran out\n");
552 op->keep--; 621 GNUNET_CONTAINER_multihashmap_iterator_destroy (op->state->full_result_iter);
553 send_client_done_and_destroy (op); 622 op->state->full_result_iter = NULL;
623 if (PHASE_DONE_RECEIVED == op->state->phase)
624 {
625 op->state->phase = PHASE_FINISHED;
626 send_client_done_and_destroy (op);
627 }
628 else if (PHASE_MUST_SEND_DONE == op->state->phase)
629 {
630 send_p2p_done (op);
631 }
632 else
633 {
634 GNUNET_assert (0);
635 }
554 return; 636 return;
555 } 637 }
556 ee = nxt; 638 ee = nxt;
@@ -559,48 +641,136 @@ send_remaining_elements (void *cls)
559 "Sending element %s:%u to client (full set)\n", 641 "Sending element %s:%u to client (full set)\n",
560 GNUNET_h2s (&ee->element_hash), 642 GNUNET_h2s (&ee->element_hash),
561 element->size); 643 element->size);
562 GNUNET_assert (0 != op->spec->client_request_id); 644 GNUNET_assert (0 != op->client_request_id);
563 ev = GNUNET_MQ_msg_extra (rm, 645 ev = GNUNET_MQ_msg_extra (rm,
564 element->size, 646 element->size,
565 GNUNET_MESSAGE_TYPE_SET_RESULT); 647 GNUNET_MESSAGE_TYPE_SET_RESULT);
566 GNUNET_assert (NULL != ev); 648 GNUNET_assert (NULL != ev);
567 rm->result_status = htons (GNUNET_SET_STATUS_OK); 649 rm->result_status = htons (GNUNET_SET_STATUS_OK);
568 rm->request_id = htonl (op->spec->client_request_id); 650 rm->request_id = htonl (op->client_request_id);
569 rm->element_type = element->element_type; 651 rm->element_type = element->element_type;
570 GNUNET_memcpy (&rm[1], 652 GNUNET_memcpy (&rm[1],
571 element->data, 653 element->data,
572 element->size); 654 element->size);
573 GNUNET_MQ_notify_sent (ev, 655 GNUNET_MQ_notify_sent (ev,
574 &send_remaining_elements, 656 &send_remaining_elements,
575 op); 657 op);
576 GNUNET_MQ_send (op->spec->set->client_mq, 658 GNUNET_MQ_send (op->set->cs->mq,
577 ev); 659 ev);
578} 660}
579 661
580 662
581/** 663/**
582 * Inform the peer that this operation is complete. 664 * Fills the "my_elements" hashmap with the initial set of
665 * (non-deleted) elements from the set of the specification.
583 * 666 *
584 * @param op the intersection operation to fail 667 * @param cls closure with the `struct Operation *`
668 * @param key current key code for the element
669 * @param value value in the hash map with the `struct ElementEntry *`
670 * @return #GNUNET_YES (we should continue to iterate)
671 */
672static int
673initialize_map_unfiltered (void *cls,
674 const struct GNUNET_HashCode *key,
675 void *value)
676{
677 struct ElementEntry *ee = value;
678 struct Operation *op = cls;
679
680 if (GNUNET_NO == _GSS_is_element_of_operation (ee, op))
681 return GNUNET_YES; /* element not live in operation's generation */
682 GNUNET_CRYPTO_hash_xor (&op->state->my_xor,
683 &ee->element_hash,
684 &op->state->my_xor);
685 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
686 "Initial full initialization of my_elements, adding %s:%u\n",
687 GNUNET_h2s (&ee->element_hash),
688 ee->element.size);
689 GNUNET_break (GNUNET_YES ==
690 GNUNET_CONTAINER_multihashmap_put (op->state->my_elements,
691 &ee->element_hash,
692 ee,
693 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
694 return GNUNET_YES;
695}
696
697
698/**
699 * Send our element count to the peer, in case our element count is
700 * lower than his.
701 *
702 * @param op intersection operation
585 */ 703 */
586static void 704static void
587send_peer_done (struct Operation *op) 705send_element_count (struct Operation *op)
588{ 706{
589 struct GNUNET_MQ_Envelope *ev; 707 struct GNUNET_MQ_Envelope *ev;
590 struct IntersectionDoneMessage *idm; 708 struct IntersectionElementInfoMessage *msg;
591 709
592 op->state->phase = PHASE_FINISHED;
593 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 710 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
594 "Intersection succeeded, sending DONE\n"); 711 "Sending our element count (%u)\n",
595 GNUNET_CONTAINER_bloomfilter_free (op->state->local_bf); 712 op->state->my_element_count);
596 op->state->local_bf = NULL; 713 ev = GNUNET_MQ_msg (msg,
714 GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_ELEMENT_INFO);
715 msg->sender_element_count = htonl (op->state->my_element_count);
716 GNUNET_MQ_send (op->mq, ev);
717}
597 718
598 ev = GNUNET_MQ_msg (idm, 719
599 GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_DONE); 720/**
600 idm->final_element_count = htonl (op->state->my_element_count); 721 * We go first, initialize our map with all elements and
601 idm->element_xor_hash = op->state->my_xor; 722 * send the first Bloom filter.
602 GNUNET_MQ_send (op->mq, 723 *
603 ev); 724 * @param op operation to start exchange for
725 */
726static void
727begin_bf_exchange (struct Operation *op)
728{
729 op->state->phase = PHASE_BF_EXCHANGE;
730 GNUNET_CONTAINER_multihashmap_iterate (op->set->content->elements,
731 &initialize_map_unfiltered,
732 op);
733 send_bloomfilter (op);
734}
735
736
737/**
738 * Handle the initial `struct IntersectionElementInfoMessage` from a
739 * remote peer.
740 *
741 * @param cls the intersection operation
742 * @param mh the header of the message
743 */
744void
745handle_intersection_p2p_element_info (void *cls,
746 const struct IntersectionElementInfoMessage *msg)
747{
748 struct Operation *op = cls;
749
750 if (GNUNET_SET_OPERATION_INTERSECTION != op->set->operation)
751 {
752 GNUNET_break_op (0);
753 fail_intersection_operation(op);
754 return;
755 }
756 op->remote_element_count = ntohl (msg->sender_element_count);
757 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
758 "Received remote element count (%u), I have %u\n",
759 op->remote_element_count,
760 op->state->my_element_count);
761 if ( ( (PHASE_INITIAL != op->state->phase) &&
762 (PHASE_COUNT_SENT != op->state->phase) ) ||
763 (op->state->my_element_count > op->remote_element_count) ||
764 (0 == op->state->my_element_count) ||
765 (0 == op->remote_element_count) )
766 {
767 GNUNET_break_op (0);
768 fail_intersection_operation(op);
769 return;
770 }
771 GNUNET_break (NULL == op->state->remote_bf);
772 begin_bf_exchange (op);
773 GNUNET_CADET_receive_done (op->channel);
604} 774}
605 775
606 776
@@ -615,9 +785,9 @@ process_bf (struct Operation *op)
615 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 785 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
616 "Received BF in phase %u, foreign count is %u, my element count is %u/%u\n", 786 "Received BF in phase %u, foreign count is %u, my element count is %u/%u\n",
617 op->state->phase, 787 op->state->phase,
618 op->spec->remote_element_count, 788 op->remote_element_count,
619 op->state->my_element_count, 789 op->state->my_element_count,
620 GNUNET_CONTAINER_multihashmap_size (op->spec->set->content->elements)); 790 GNUNET_CONTAINER_multihashmap_size (op->set->content->elements));
621 switch (op->state->phase) 791 switch (op->state->phase)
622 { 792 {
623 case PHASE_INITIAL: 793 case PHASE_INITIAL:
@@ -627,11 +797,8 @@ process_bf (struct Operation *op)
627 case PHASE_COUNT_SENT: 797 case PHASE_COUNT_SENT:
628 /* This is the first BF being sent, build our initial map with 798 /* This is the first BF being sent, build our initial map with
629 filtering in place */ 799 filtering in place */
630 op->state->my_elements
631 = GNUNET_CONTAINER_multihashmap_create (op->spec->remote_element_count,
632 GNUNET_YES);
633 op->state->my_element_count = 0; 800 op->state->my_element_count = 0;
634 GNUNET_CONTAINER_multihashmap_iterate (op->spec->set->content->elements, 801 GNUNET_CONTAINER_multihashmap_iterate (op->set->content->elements,
635 &filtered_map_initialization, 802 &filtered_map_initialization,
636 op); 803 op);
637 break; 804 break;
@@ -641,6 +808,14 @@ process_bf (struct Operation *op)
641 &iterator_bf_reduce, 808 &iterator_bf_reduce,
642 op); 809 op);
643 break; 810 break;
811 case PHASE_MUST_SEND_DONE:
812 GNUNET_break_op (0);
813 fail_intersection_operation(op);
814 return;
815 case PHASE_DONE_RECEIVED:
816 GNUNET_break_op (0);
817 fail_intersection_operation(op);
818 return;
644 case PHASE_FINISHED: 819 case PHASE_FINISHED:
645 GNUNET_break_op (0); 820 GNUNET_break_op (0);
646 fail_intersection_operation(op); 821 fail_intersection_operation(op);
@@ -650,13 +825,28 @@ process_bf (struct Operation *op)
650 op->state->remote_bf = NULL; 825 op->state->remote_bf = NULL;
651 826
652 if ( (0 == op->state->my_element_count) || /* fully disjoint */ 827 if ( (0 == op->state->my_element_count) || /* fully disjoint */
653 ( (op->state->my_element_count == op->spec->remote_element_count) && 828 ( (op->state->my_element_count == op->remote_element_count) &&
654 (0 == memcmp (&op->state->my_xor, 829 (0 == memcmp (&op->state->my_xor,
655 &op->state->other_xor, 830 &op->state->other_xor,
656 sizeof (struct GNUNET_HashCode))) ) ) 831 sizeof (struct GNUNET_HashCode))) ) )
657 { 832 {
658 /* we are done */ 833 /* we are done */
659 send_peer_done (op); 834 op->state->phase = PHASE_MUST_SEND_DONE;
835 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
836 "Intersection succeeded, sending DONE to other peer\n");
837 GNUNET_CONTAINER_bloomfilter_free (op->state->local_bf);
838 op->state->local_bf = NULL;
839 if (GNUNET_SET_RESULT_FULL == op->result_mode)
840 {
841 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
842 "Sending full result set (%u elements)\n",
843 GNUNET_CONTAINER_multihashmap_size (op->state->my_elements));
844 op->state->full_result_iter
845 = GNUNET_CONTAINER_multihashmap_iterator_create (op->state->my_elements);
846 send_remaining_elements (op);
847 return;
848 }
849 send_p2p_done (op);
660 return; 850 return;
661 } 851 }
662 op->state->phase = PHASE_BF_EXCHANGE; 852 op->state->phase = PHASE_BF_EXCHANGE;
@@ -665,41 +855,53 @@ process_bf (struct Operation *op)
665 855
666 856
667/** 857/**
858 * Check an BF message from a remote peer.
859 *
860 * @param cls the intersection operation
861 * @param msg the header of the message
862 * @return #GNUNET_OK if @a msg is well-formed
863 */
864int
865check_intersection_p2p_bf (void *cls,
866 const struct BFMessage *msg)
867{
868 struct Operation *op = cls;
869
870 if (GNUNET_SET_OPERATION_INTERSECTION != op->set->operation)
871 {
872 GNUNET_break_op (0);
873 return GNUNET_SYSERR;
874 }
875 return GNUNET_OK;
876}
877
878
879/**
668 * Handle an BF message from a remote peer. 880 * Handle an BF message from a remote peer.
669 * 881 *
670 * @param cls the intersection operation 882 * @param cls the intersection operation
671 * @param mh the header of the message 883 * @param msg the header of the message
672 */ 884 */
673static void 885void
674handle_p2p_bf (void *cls, 886handle_intersection_p2p_bf (void *cls,
675 const struct GNUNET_MessageHeader *mh) 887 const struct BFMessage *msg)
676{ 888{
677 struct Operation *op = cls; 889 struct Operation *op = cls;
678 const struct BFMessage *msg;
679 uint32_t bf_size; 890 uint32_t bf_size;
680 uint32_t chunk_size; 891 uint32_t chunk_size;
681 uint32_t bf_bits_per_element; 892 uint32_t bf_bits_per_element;
682 uint16_t msize;
683 893
684 msize = htons (mh->size);
685 if (msize < sizeof (struct BFMessage))
686 {
687 GNUNET_break_op (0);
688 fail_intersection_operation (op);
689 return;
690 }
691 msg = (const struct BFMessage *) mh;
692 switch (op->state->phase) 894 switch (op->state->phase)
693 { 895 {
694 case PHASE_INITIAL: 896 case PHASE_INITIAL:
695 GNUNET_break_op (0); 897 GNUNET_break_op (0);
696 fail_intersection_operation (op); 898 fail_intersection_operation (op);
697 break; 899 return;
698 case PHASE_COUNT_SENT: 900 case PHASE_COUNT_SENT:
699 case PHASE_BF_EXCHANGE: 901 case PHASE_BF_EXCHANGE:
700 bf_size = ntohl (msg->bloomfilter_total_length); 902 bf_size = ntohl (msg->bloomfilter_total_length);
701 bf_bits_per_element = ntohl (msg->bits_per_element); 903 bf_bits_per_element = ntohl (msg->bits_per_element);
702 chunk_size = msize - sizeof (struct BFMessage); 904 chunk_size = htons (msg->header.size) - sizeof (struct BFMessage);
703 op->state->other_xor = msg->element_xor_hash; 905 op->state->other_xor = msg->element_xor_hash;
704 if (bf_size == chunk_size) 906 if (bf_size == chunk_size)
705 { 907 {
@@ -715,9 +917,9 @@ handle_p2p_bf (void *cls,
715 bf_size, 917 bf_size,
716 bf_bits_per_element); 918 bf_bits_per_element);
717 op->state->salt = ntohl (msg->sender_mutator); 919 op->state->salt = ntohl (msg->sender_mutator);
718 op->spec->remote_element_count = ntohl (msg->sender_element_count); 920 op->remote_element_count = ntohl (msg->sender_element_count);
719 process_bf (op); 921 process_bf (op);
720 return; 922 break;
721 } 923 }
722 /* multipart chunk */ 924 /* multipart chunk */
723 if (NULL == op->state->bf_data) 925 if (NULL == op->state->bf_data)
@@ -728,7 +930,7 @@ handle_p2p_bf (void *cls,
728 op->state->bf_bits_per_element = bf_bits_per_element; 930 op->state->bf_bits_per_element = bf_bits_per_element;
729 op->state->bf_data_offset = 0; 931 op->state->bf_data_offset = 0;
730 op->state->salt = ntohl (msg->sender_mutator); 932 op->state->salt = ntohl (msg->sender_mutator);
731 op->spec->remote_element_count = ntohl (msg->sender_element_count); 933 op->remote_element_count = ntohl (msg->sender_element_count);
732 } 934 }
733 else 935 else
734 { 936 {
@@ -737,7 +939,7 @@ handle_p2p_bf (void *cls,
737 (op->state->bf_bits_per_element != bf_bits_per_element) || 939 (op->state->bf_bits_per_element != bf_bits_per_element) ||
738 (op->state->bf_data_offset + chunk_size > bf_size) || 940 (op->state->bf_data_offset + chunk_size > bf_size) ||
739 (op->state->salt != ntohl (msg->sender_mutator)) || 941 (op->state->salt != ntohl (msg->sender_mutator)) ||
740 (op->spec->remote_element_count != ntohl (msg->sender_element_count)) ) 942 (op->remote_element_count != ntohl (msg->sender_element_count)) )
741 { 943 {
742 GNUNET_break_op (0); 944 GNUNET_break_op (0);
743 fail_intersection_operation (op); 945 fail_intersection_operation (op);
@@ -764,153 +966,9 @@ handle_p2p_bf (void *cls,
764 default: 966 default:
765 GNUNET_break_op (0); 967 GNUNET_break_op (0);
766 fail_intersection_operation (op); 968 fail_intersection_operation (op);
767 break;
768 }
769}
770
771
772/**
773 * Fills the "my_elements" hashmap with the initial set of
774 * (non-deleted) elements from the set of the specification.
775 *
776 * @param cls closure with the `struct Operation *`
777 * @param key current key code for the element
778 * @param value value in the hash map with the `struct ElementEntry *`
779 * @return #GNUNET_YES (we should continue to iterate)
780 */
781static int
782initialize_map_unfiltered (void *cls,
783 const struct GNUNET_HashCode *key,
784 void *value)
785{
786 struct ElementEntry *ee = value;
787 struct Operation *op = cls;
788
789 if (GNUNET_NO == _GSS_is_element_of_operation (ee, op))
790 return GNUNET_YES; /* element not live in operation's generation */
791 GNUNET_CRYPTO_hash_xor (&op->state->my_xor,
792 &ee->element_hash,
793 &op->state->my_xor);
794 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
795 "Initial full initialization of my_elements, adding %s:%u\n",
796 GNUNET_h2s (&ee->element_hash),
797 ee->element.size);
798 GNUNET_break (GNUNET_YES ==
799 GNUNET_CONTAINER_multihashmap_put (op->state->my_elements,
800 &ee->element_hash,
801 ee,
802 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
803 return GNUNET_YES;
804}
805
806
807/**
808 * Send our element count to the peer, in case our element count is
809 * lower than his.
810 *
811 * @param op intersection operation
812 */
813static void
814send_element_count (struct Operation *op)
815{
816 struct GNUNET_MQ_Envelope *ev;
817 struct IntersectionElementInfoMessage *msg;
818
819 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
820 "Sending our element count (%u)\n",
821 op->state->my_element_count);
822 ev = GNUNET_MQ_msg (msg,
823 GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_ELEMENT_INFO);
824 msg->sender_element_count = htonl (op->state->my_element_count);
825 GNUNET_MQ_send (op->mq, ev);
826}
827
828
829/**
830 * We go first, initialize our map with all elements and
831 * send the first Bloom filter.
832 *
833 * @param op operation to start exchange for
834 */
835static void
836begin_bf_exchange (struct Operation *op)
837{
838 op->state->phase = PHASE_BF_EXCHANGE;
839 op->state->my_elements
840 = GNUNET_CONTAINER_multihashmap_create (op->state->my_element_count,
841 GNUNET_YES);
842 GNUNET_CONTAINER_multihashmap_iterate (op->spec->set->content->elements,
843 &initialize_map_unfiltered,
844 op);
845 send_bloomfilter (op);
846}
847
848
849/**
850 * Handle the initial `struct IntersectionElementInfoMessage` from a
851 * remote peer.
852 *
853 * @param cls the intersection operation
854 * @param mh the header of the message
855 */
856static void
857handle_p2p_element_info (void *cls,
858 const struct GNUNET_MessageHeader *mh)
859{
860 struct Operation *op = cls;
861 const struct IntersectionElementInfoMessage *msg;
862
863 if (ntohs (mh->size) != sizeof (struct IntersectionElementInfoMessage))
864 {
865 GNUNET_break_op (0);
866 fail_intersection_operation(op);
867 return;
868 }
869 msg = (const struct IntersectionElementInfoMessage *) mh;
870 op->spec->remote_element_count = ntohl (msg->sender_element_count);
871 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
872 "Received remote element count (%u), I have %u\n",
873 op->spec->remote_element_count,
874 op->state->my_element_count);
875 if ( ( (PHASE_INITIAL != op->state->phase) &&
876 (PHASE_COUNT_SENT != op->state->phase) ) ||
877 (op->state->my_element_count > op->spec->remote_element_count) ||
878 (0 == op->state->my_element_count) ||
879 (0 == op->spec->remote_element_count) )
880 {
881 GNUNET_break_op (0);
882 fail_intersection_operation(op);
883 return;
884 }
885 GNUNET_break (NULL == op->state->remote_bf);
886 begin_bf_exchange (op);
887}
888
889
890/**
891 * Send a result message to the client indicating that the operation
892 * is over. After the result done message has been sent to the
893 * client, destroy the evaluate operation.
894 *
895 * @param op intersection operation
896 */
897static void
898finish_and_destroy (struct Operation *op)
899{
900 GNUNET_assert (GNUNET_NO == op->state->client_done_sent);
901
902 if (GNUNET_SET_RESULT_FULL == op->spec->result_mode)
903 {
904 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
905 "Sending full result set (%u elements)\n",
906 GNUNET_CONTAINER_multihashmap_size (op->state->my_elements));
907 op->state->full_result_iter
908 = GNUNET_CONTAINER_multihashmap_iterator_create (op->state->my_elements);
909 op->keep++;
910 send_remaining_elements (op);
911 return; 969 return;
912 } 970 }
913 send_client_done_and_destroy (op); 971 GNUNET_CADET_receive_done (op->channel);
914} 972}
915 973
916 974
@@ -955,28 +1013,26 @@ filter_all (void *cls,
955 * @param cls the intersection operation 1013 * @param cls the intersection operation
956 * @param mh the message 1014 * @param mh the message
957 */ 1015 */
958static void 1016void
959handle_p2p_done (void *cls, 1017handle_intersection_p2p_done (void *cls,
960 const struct GNUNET_MessageHeader *mh) 1018 const struct IntersectionDoneMessage *idm)
961{ 1019{
962 struct Operation *op = cls; 1020 struct Operation *op = cls;
963 const struct IntersectionDoneMessage *idm;
964 1021
965 if (PHASE_BF_EXCHANGE != op->state->phase) 1022 if (GNUNET_SET_OPERATION_INTERSECTION != op->set->operation)
966 { 1023 {
967 /* wrong phase to conclude? FIXME: Or should we allow this
968 if the other peer has _initially_ already an empty set? */
969 GNUNET_break_op (0); 1024 GNUNET_break_op (0);
970 fail_intersection_operation (op); 1025 fail_intersection_operation (op);
971 return; 1026 return;
972 } 1027 }
973 if (ntohs (mh->size) != sizeof (struct IntersectionDoneMessage)) 1028 if (PHASE_BF_EXCHANGE != op->state->phase)
974 { 1029 {
1030 /* wrong phase to conclude? FIXME: Or should we allow this
1031 if the other peer has _initially_ already an empty set? */
975 GNUNET_break_op (0); 1032 GNUNET_break_op (0);
976 fail_intersection_operation (op); 1033 fail_intersection_operation (op);
977 return; 1034 return;
978 } 1035 }
979 idm = (const struct IntersectionDoneMessage *) mh;
980 if (0 == ntohl (idm->final_element_count)) 1036 if (0 == ntohl (idm->final_element_count))
981 { 1037 {
982 /* other peer determined empty set is the intersection, 1038 /* other peer determined empty set is the intersection,
@@ -998,8 +1054,22 @@ handle_p2p_done (void *cls,
998 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1054 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
999 "Got IntersectionDoneMessage, have %u elements in intersection\n", 1055 "Got IntersectionDoneMessage, have %u elements in intersection\n",
1000 op->state->my_element_count); 1056 op->state->my_element_count);
1057 op->state->phase = PHASE_DONE_RECEIVED;
1058 GNUNET_CADET_receive_done (op->channel);
1059
1060 GNUNET_assert (GNUNET_NO == op->state->client_done_sent);
1061 if (GNUNET_SET_RESULT_FULL == op->result_mode)
1062 {
1063 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1064 "Sending full result set to client (%u elements)\n",
1065 GNUNET_CONTAINER_multihashmap_size (op->state->my_elements));
1066 op->state->full_result_iter
1067 = GNUNET_CONTAINER_multihashmap_iterator_create (op->state->my_elements);
1068 send_remaining_elements (op);
1069 return;
1070 }
1001 op->state->phase = PHASE_FINISHED; 1071 op->state->phase = PHASE_FINISHED;
1002 finish_and_destroy (op); 1072 send_client_done_and_destroy (op);
1003} 1073}
1004 1074
1005 1075
@@ -1010,21 +1080,16 @@ handle_p2p_done (void *cls,
1010 * begin the evaluation 1080 * begin the evaluation
1011 * @param opaque_context message to be transmitted to the listener 1081 * @param opaque_context message to be transmitted to the listener
1012 * to convince him to accept, may be NULL 1082 * to convince him to accept, may be NULL
1083 * @return operation-specific state to keep in @a op
1013 */ 1084 */
1014static void 1085static struct OperationState *
1015intersection_evaluate (struct Operation *op, 1086intersection_evaluate (struct Operation *op,
1016 const struct GNUNET_MessageHeader *opaque_context) 1087 const struct GNUNET_MessageHeader *opaque_context)
1017{ 1088{
1089 struct OperationState *state;
1018 struct GNUNET_MQ_Envelope *ev; 1090 struct GNUNET_MQ_Envelope *ev;
1019 struct OperationRequestMessage *msg; 1091 struct OperationRequestMessage *msg;
1020 1092
1021 op->state = GNUNET_new (struct OperationState);
1022 /* we started the operation, thus we have to send the operation request */
1023 op->state->phase = PHASE_INITIAL;
1024 op->state->my_element_count = op->spec->set->state->current_set_element_count;
1025
1026 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1027 "Initiating intersection operation evaluation\n");
1028 ev = GNUNET_MQ_msg_nested_mh (msg, 1093 ev = GNUNET_MQ_msg_nested_mh (msg,
1029 GNUNET_MESSAGE_TYPE_SET_P2P_OPERATION_REQUEST, 1094 GNUNET_MESSAGE_TYPE_SET_P2P_OPERATION_REQUEST,
1030 opaque_context); 1095 opaque_context);
@@ -1032,20 +1097,30 @@ intersection_evaluate (struct Operation *op,
1032 { 1097 {
1033 /* the context message is too large!? */ 1098 /* the context message is too large!? */
1034 GNUNET_break (0); 1099 GNUNET_break (0);
1035 GNUNET_SERVICE_client_drop (op->spec->set->client); 1100 return NULL;
1036 return;
1037 } 1101 }
1102 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1103 "Initiating intersection operation evaluation\n");
1104 state = GNUNET_new (struct OperationState);
1105 /* we started the operation, thus we have to send the operation request */
1106 state->phase = PHASE_INITIAL;
1107 state->my_element_count = op->set->state->current_set_element_count;
1108 state->my_elements
1109 = GNUNET_CONTAINER_multihashmap_create (state->my_element_count,
1110 GNUNET_YES);
1111
1038 msg->operation = htonl (GNUNET_SET_OPERATION_INTERSECTION); 1112 msg->operation = htonl (GNUNET_SET_OPERATION_INTERSECTION);
1039 msg->element_count = htonl (op->state->my_element_count); 1113 msg->element_count = htonl (state->my_element_count);
1040 GNUNET_MQ_send (op->mq, 1114 GNUNET_MQ_send (op->mq,
1041 ev); 1115 ev);
1042 op->state->phase = PHASE_COUNT_SENT; 1116 state->phase = PHASE_COUNT_SENT;
1043 if (NULL != opaque_context) 1117 if (NULL != opaque_context)
1044 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1118 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1045 "Sent op request with context message\n"); 1119 "Sent op request with context message\n");
1046 else 1120 else
1047 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1121 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1048 "Sent op request without context message\n"); 1122 "Sent op request without context message\n");
1123 return state;
1049} 1124}
1050 1125
1051 1126
@@ -1055,90 +1130,33 @@ intersection_evaluate (struct Operation *op,
1055 * 1130 *
1056 * @param op operation that will be accepted as an intersection operation 1131 * @param op operation that will be accepted as an intersection operation
1057 */ 1132 */
1058static void 1133static struct OperationState *
1059intersection_accept (struct Operation *op) 1134intersection_accept (struct Operation *op)
1060{ 1135{
1136 struct OperationState *state;
1137
1061 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1138 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1062 "Accepting set intersection operation\n"); 1139 "Accepting set intersection operation\n");
1063 op->state = GNUNET_new (struct OperationState); 1140 state = GNUNET_new (struct OperationState);
1064 op->state->phase = PHASE_INITIAL; 1141 state->phase = PHASE_INITIAL;
1065 op->state->my_element_count 1142 state->my_element_count
1066 = op->spec->set->state->current_set_element_count; 1143 = op->set->state->current_set_element_count;
1067 op->state->my_elements 1144 state->my_elements
1068 = GNUNET_CONTAINER_multihashmap_create 1145 = GNUNET_CONTAINER_multihashmap_create (GNUNET_MIN (state->my_element_count,
1069 (GNUNET_MIN (op->state->my_element_count, 1146 op->remote_element_count),
1070 op->spec->remote_element_count), 1147 GNUNET_YES);
1071 GNUNET_YES); 1148 op->state = state;
1072 if (op->spec->remote_element_count < op->state->my_element_count) 1149 if (op->remote_element_count < state->my_element_count)
1073 { 1150 {
1074 /* If the other peer (Alice) has fewer elements than us (Bob), 1151 /* If the other peer (Alice) has fewer elements than us (Bob),
1075 we just send the count as Alice should send the first BF */ 1152 we just send the count as Alice should send the first BF */
1076 send_element_count (op); 1153 send_element_count (op);
1077 op->state->phase = PHASE_COUNT_SENT; 1154 state->phase = PHASE_COUNT_SENT;
1078 return; 1155 return state;
1079 } 1156 }
1080 /* We have fewer elements, so we start with the BF */ 1157 /* We have fewer elements, so we start with the BF */
1081 begin_bf_exchange (op); 1158 begin_bf_exchange (op);
1082} 1159 return state;
1083
1084
1085/**
1086 * Dispatch messages for a intersection operation.
1087 *
1088 * @param op the state of the intersection evaluate operation
1089 * @param mh the received message
1090 * @return #GNUNET_SYSERR if the tunnel should be disconnected,
1091 * #GNUNET_OK otherwise
1092 */
1093static int
1094intersection_handle_p2p_message (struct Operation *op,
1095 const struct GNUNET_MessageHeader *mh)
1096{
1097 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1098 "Received p2p message (t: %u, s: %u)\n",
1099 ntohs (mh->type), ntohs (mh->size));
1100 switch (ntohs (mh->type))
1101 {
1102 /* this message handler is not active until after we received an
1103 * operation request message, thus the ops request is not handled here
1104 */
1105 case GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_ELEMENT_INFO:
1106 handle_p2p_element_info (op, mh);
1107 break;
1108 case GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_BF:
1109 handle_p2p_bf (op, mh);
1110 break;
1111 case GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_DONE:
1112 handle_p2p_done (op, mh);
1113 break;
1114 default:
1115 /* something wrong with cadet's message handlers? */
1116 GNUNET_assert (0);
1117 }
1118 return GNUNET_OK;
1119}
1120
1121
1122/**
1123 * Handler for peer-disconnects, notifies the client about the aborted
1124 * operation. If we did not expect anything from the other peer, we
1125 * gracefully terminate the operation.
1126 *
1127 * @param op the destroyed operation
1128 */
1129static void
1130intersection_peer_disconnect (struct Operation *op)
1131{
1132 if (PHASE_FINISHED != op->state->phase)
1133 {
1134 fail_intersection_operation (op);
1135 return;
1136 }
1137 /* the session has already been concluded */
1138 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1139 "Other peer disconnected (finished)\n");
1140 if (GNUNET_NO == op->state->client_done_sent)
1141 finish_and_destroy (op);
1142} 1160}
1143 1161
1144 1162
@@ -1168,6 +1186,11 @@ intersection_op_cancel (struct Operation *op)
1168 GNUNET_CONTAINER_multihashmap_destroy (op->state->my_elements); 1186 GNUNET_CONTAINER_multihashmap_destroy (op->state->my_elements);
1169 op->state->my_elements = NULL; 1187 op->state->my_elements = NULL;
1170 } 1188 }
1189 if (NULL != op->state->full_result_iter)
1190 {
1191 GNUNET_CONTAINER_multihashmap_iterator_destroy (op->state->full_result_iter);
1192 op->state->full_result_iter = NULL;
1193 }
1171 GNUNET_free (op->state); 1194 GNUNET_free (op->state);
1172 op->state = NULL; 1195 op->state = NULL;
1173 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1196 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -1236,6 +1259,28 @@ intersection_remove (struct SetState *set_state,
1236 1259
1237 1260
1238/** 1261/**
1262 * Callback for channel death for the intersection operation.
1263 *
1264 * @param op operation that lost the channel
1265 */
1266static void
1267intersection_channel_death (struct Operation *op)
1268{
1269 if (GNUNET_YES == op->state->channel_death_expected)
1270 {
1271 /* oh goodie, we are done! */
1272 send_client_done_and_destroy (op);
1273 }
1274 else
1275 {
1276 /* sorry, channel went down early, too bad. */
1277 _GSS_operation_destroy (op,
1278 GNUNET_YES);
1279 }
1280}
1281
1282
1283/**
1239 * Get the table with implementing functions for set intersection. 1284 * Get the table with implementing functions for set intersection.
1240 * 1285 *
1241 * @return the operation specific VTable 1286 * @return the operation specific VTable
@@ -1245,14 +1290,13 @@ _GSS_intersection_vt ()
1245{ 1290{
1246 static const struct SetVT intersection_vt = { 1291 static const struct SetVT intersection_vt = {
1247 .create = &intersection_set_create, 1292 .create = &intersection_set_create,
1248 .msg_handler = &intersection_handle_p2p_message,
1249 .add = &intersection_add, 1293 .add = &intersection_add,
1250 .remove = &intersection_remove, 1294 .remove = &intersection_remove,
1251 .destroy_set = &intersection_set_destroy, 1295 .destroy_set = &intersection_set_destroy,
1252 .evaluate = &intersection_evaluate, 1296 .evaluate = &intersection_evaluate,
1253 .accept = &intersection_accept, 1297 .accept = &intersection_accept,
1254 .peer_disconnect = &intersection_peer_disconnect,
1255 .cancel = &intersection_op_cancel, 1298 .cancel = &intersection_op_cancel,
1299 .channel_death = &intersection_channel_death,
1256 }; 1300 };
1257 1301
1258 return &intersection_vt; 1302 return &intersection_vt;
diff --git a/src/set/gnunet-service-set_intersection.h b/src/set/gnunet-service-set_intersection.h
new file mode 100644
index 000000000..3bd255142
--- /dev/null
+++ b/src/set/gnunet-service-set_intersection.h
@@ -0,0 +1,79 @@
1
2/*
3 This file is part of GNUnet
4 Copyright (C) 2013-2017 GNUnet e.V.
5
6 GNUnet is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published
8 by the Free Software Foundation; either version 3, or (at your
9 option) any later version.
10
11 GNUnet is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNUnet; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA.
20*/
21/**
22 * @file set/gnunet-service-set_intersection.h
23 * @brief two-peer set operations
24 * @author Florian Dold
25 * @author Christian Grothoff
26 */
27#ifndef GNUNET_SERVICE_SET_INTERSECTION_H
28#define GNUNET_SERVICE_SET_INTERSECTION_H
29
30#include "gnunet-service-set.h"
31
32
33/**
34 * Check an BF message from a remote peer.
35 *
36 * @param cls the intersection operation
37 * @param msg the header of the message
38 * @return #GNUNET_OK if @a msg is well-formed
39 */
40int
41check_intersection_p2p_bf (void *cls,
42 const struct BFMessage *msg);
43
44
45/**
46 * Handle an BF message from a remote peer.
47 *
48 * @param cls the intersection operation
49 * @param msg the header of the message
50 */
51void
52handle_intersection_p2p_bf (void *cls,
53 const struct BFMessage *msg);
54
55
56/**
57 * Handle the initial `struct IntersectionElementInfoMessage` from a
58 * remote peer.
59 *
60 * @param cls the intersection operation
61 * @param mh the header of the message
62 */
63void
64handle_intersection_p2p_element_info (void *cls,
65 const struct IntersectionElementInfoMessage *msg);
66
67
68/**
69 * Handle a done message from a remote peer
70 *
71 * @param cls the intersection operation
72 * @param mh the message
73 */
74void
75handle_intersection_p2p_done (void *cls,
76 const struct IntersectionDoneMessage *idm);
77
78
79#endif
diff --git a/src/set/gnunet-service-set_union.c b/src/set/gnunet-service-set_union.c
index a19c36206..fc7e578e6 100644
--- a/src/set/gnunet-service-set_union.c
+++ b/src/set/gnunet-service-set_union.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet 2 This file is part of GNUnet
3 Copyright (C) 2013-2016 GNUnet e.V. 3 Copyright (C) 2013-2017 GNUnet e.V.
4 4
5 GNUnet is free software; you can redistribute it and/or modify 5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published 6 it under the terms of the GNU General Public License as published
@@ -19,15 +19,16 @@
19*/ 19*/
20/** 20/**
21 * @file set/gnunet-service-set_union.c 21 * @file set/gnunet-service-set_union.c
22
23 * @brief two-peer set operations 22 * @brief two-peer set operations
24 * @author Florian Dold 23 * @author Florian Dold
24 * @author Christian Grothoff
25 */ 25 */
26#include "platform.h" 26#include "platform.h"
27#include "gnunet_util_lib.h" 27#include "gnunet_util_lib.h"
28#include "gnunet_statistics_service.h" 28#include "gnunet_statistics_service.h"
29#include "gnunet-service-set.h" 29#include "gnunet-service-set.h"
30#include "ibf.h" 30#include "ibf.h"
31#include "gnunet-service-set_union.h"
31#include "gnunet-service-set_union_strata_estimator.h" 32#include "gnunet-service-set_union_strata_estimator.h"
32#include "gnunet-service-set_protocol.h" 33#include "gnunet-service-set_protocol.h"
33#include <gcrypt.h> 34#include <gcrypt.h>
@@ -367,9 +368,10 @@ fail_union_operation (struct Operation *op)
367 "union operation failed\n"); 368 "union operation failed\n");
368 ev = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SET_RESULT); 369 ev = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SET_RESULT);
369 msg->result_status = htons (GNUNET_SET_STATUS_FAILURE); 370 msg->result_status = htons (GNUNET_SET_STATUS_FAILURE);
370 msg->request_id = htonl (op->spec->client_request_id); 371 msg->request_id = htonl (op->client_request_id);
371 msg->element_type = htons (0); 372 msg->element_type = htons (0);
372 GNUNET_MQ_send (op->spec->set->client_mq, ev); 373 GNUNET_MQ_send (op->set->cs->mq,
374 ev);
373 _GSS_operation_destroy (op, GNUNET_YES); 375 _GSS_operation_destroy (op, GNUNET_YES);
374} 376}
375 377
@@ -400,7 +402,14 @@ get_ibf_key (const struct GNUNET_HashCode *src)
400 */ 402 */
401struct GetElementContext 403struct GetElementContext
402{ 404{
405 /**
406 * FIXME.
407 */
403 struct GNUNET_HashCode hash; 408 struct GNUNET_HashCode hash;
409
410 /**
411 * FIXME.
412 */
404 struct KeyEntry *k; 413 struct KeyEntry *k;
405}; 414};
406 415
@@ -503,6 +512,9 @@ op_register_element (struct Operation *op,
503} 512}
504 513
505 514
515/**
516 * FIXME.
517 */
506static void 518static void
507salt_key (const struct IBF_Key *k_in, 519salt_key (const struct IBF_Key *k_in,
508 uint32_t salt, 520 uint32_t salt,
@@ -516,6 +528,9 @@ salt_key (const struct IBF_Key *k_in,
516} 528}
517 529
518 530
531/**
532 * FIXME.
533 */
519static void 534static void
520unsalt_key (const struct IBF_Key *k_in, 535unsalt_key (const struct IBF_Key *k_in,
521 uint32_t salt, 536 uint32_t salt,
@@ -549,7 +564,9 @@ prepare_ibf_iterator (void *cls,
549 (void *) op, 564 (void *) op,
550 (unsigned long) ke->ibf_key.key_val, 565 (unsigned long) ke->ibf_key.key_val,
551 GNUNET_h2s (&ke->element->element_hash)); 566 GNUNET_h2s (&ke->element->element_hash));
552 salt_key (&ke->ibf_key, op->state->salt_send, &salted_key); 567 salt_key (&ke->ibf_key,
568 op->state->salt_send,
569 &salted_key);
553 ibf_insert (op->state->local_ibf, salted_key); 570 ibf_insert (op->state->local_ibf, salted_key);
554 return GNUNET_YES; 571 return GNUNET_YES;
555} 572}
@@ -575,12 +592,14 @@ init_key_to_element_iterator (void *cls,
575 592
576 /* make sure that the element belongs to the set at the time 593 /* make sure that the element belongs to the set at the time
577 * of creating the operation */ 594 * of creating the operation */
578 if (GNUNET_NO == _GSS_is_element_of_operation (ee, op)) 595 if (GNUNET_NO ==
596 _GSS_is_element_of_operation (ee,
597 op))
579 return GNUNET_YES; 598 return GNUNET_YES;
580
581 GNUNET_assert (GNUNET_NO == ee->remote); 599 GNUNET_assert (GNUNET_NO == ee->remote);
582 600 op_register_element (op,
583 op_register_element (op, ee, GNUNET_NO); 601 ee,
602 GNUNET_NO);
584 return GNUNET_YES; 603 return GNUNET_YES;
585} 604}
586 605
@@ -597,9 +616,11 @@ initialize_key_to_element (struct Operation *op)
597 unsigned int len; 616 unsigned int len;
598 617
599 GNUNET_assert (NULL == op->state->key_to_element); 618 GNUNET_assert (NULL == op->state->key_to_element);
600 len = GNUNET_CONTAINER_multihashmap_size (op->spec->set->content->elements); 619 len = GNUNET_CONTAINER_multihashmap_size (op->set->content->elements);
601 op->state->key_to_element = GNUNET_CONTAINER_multihashmap32_create (len + 1); 620 op->state->key_to_element = GNUNET_CONTAINER_multihashmap32_create (len + 1);
602 GNUNET_CONTAINER_multihashmap_iterate (op->spec->set->content->elements, init_key_to_element_iterator, op); 621 GNUNET_CONTAINER_multihashmap_iterate (op->set->content->elements,
622 &init_key_to_element_iterator,
623 op);
603} 624}
604 625
605 626
@@ -706,44 +727,6 @@ send_ibf (struct Operation *op,
706 727
707 728
708/** 729/**
709 * Send a strata estimator to the remote peer.
710 *
711 * @param op the union operation with the remote peer
712 */
713static void
714send_strata_estimator (struct Operation *op)
715{
716 const struct StrataEstimator *se = op->state->se;
717 struct GNUNET_MQ_Envelope *ev;
718 struct StrataEstimatorMessage *strata_msg;
719 char *buf;
720 size_t len;
721 uint16_t type;
722
723 buf = GNUNET_malloc (se->strata_count * IBF_BUCKET_SIZE * se->ibf_size);
724 len = strata_estimator_write (op->state->se,
725 buf);
726 if (len < se->strata_count * IBF_BUCKET_SIZE * se->ibf_size)
727 type = GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SEC;
728 else
729 type = GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SE;
730 ev = GNUNET_MQ_msg_extra (strata_msg,
731 len,
732 type);
733 GNUNET_memcpy (&strata_msg[1],
734 buf,
735 len);
736 GNUNET_free (buf);
737 strata_msg->set_size = GNUNET_htonll (GNUNET_CONTAINER_multihashmap_size (op->spec->set->content->elements));
738 GNUNET_MQ_send (op->mq,
739 ev);
740 op->state->phase = PHASE_EXPECT_IBF;
741 LOG (GNUNET_ERROR_TYPE_DEBUG,
742 "sent SE, expecting IBF\n");
743}
744
745
746/**
747 * Compute the necessary order of an ibf 730 * Compute the necessary order of an ibf
748 * from the size of the symmetric set difference. 731 * from the size of the symmetric set difference.
749 * 732 *
@@ -761,7 +744,8 @@ get_order_from_difference (unsigned int diff)
761 ibf_order++; 744 ibf_order++;
762 if (ibf_order > MAX_IBF_ORDER) 745 if (ibf_order > MAX_IBF_ORDER)
763 ibf_order = MAX_IBF_ORDER; 746 ibf_order = MAX_IBF_ORDER;
764 return ibf_order; 747 // add one for correction
748 return ibf_order + 1;
765} 749}
766 750
767 751
@@ -775,7 +759,7 @@ get_order_from_difference (unsigned int diff)
775 * @return #GNUNET_YES (to continue iterating) 759 * @return #GNUNET_YES (to continue iterating)
776 */ 760 */
777static int 761static int
778send_element_iterator (void *cls, 762send_full_element_iterator (void *cls,
779 const struct GNUNET_HashCode *key, 763 const struct GNUNET_HashCode *key,
780 void *value) 764 void *value)
781{ 765{
@@ -785,26 +769,43 @@ send_element_iterator (void *cls,
785 struct GNUNET_SET_Element *el = &ee->element; 769 struct GNUNET_SET_Element *el = &ee->element;
786 struct GNUNET_MQ_Envelope *ev; 770 struct GNUNET_MQ_Envelope *ev;
787 771
788 772 LOG (GNUNET_ERROR_TYPE_INFO,
789 ev = GNUNET_MQ_msg_extra (emsg, el->size, GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_ELEMENT); 773 "Sending element %s\n",
774 GNUNET_h2s (key));
775 ev = GNUNET_MQ_msg_extra (emsg,
776 el->size,
777 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_ELEMENT);
790 emsg->element_type = htons (el->element_type); 778 emsg->element_type = htons (el->element_type);
791 GNUNET_memcpy (&emsg[1], el->data, el->size); 779 GNUNET_memcpy (&emsg[1],
792 GNUNET_MQ_send (op->mq, ev); 780 el->data,
781 el->size);
782 GNUNET_MQ_send (op->mq,
783 ev);
793 return GNUNET_YES; 784 return GNUNET_YES;
794} 785}
795 786
796 787
788/**
789 * Switch to full set transmission for @a op.
790 *
791 * @param op operation to switch to full set transmission.
792 */
797static void 793static void
798send_full_set (struct Operation *op) 794send_full_set (struct Operation *op)
799{ 795{
800 struct GNUNET_MQ_Envelope *ev; 796 struct GNUNET_MQ_Envelope *ev;
801 797
802 op->state->phase = PHASE_FULL_SENDING; 798 op->state->phase = PHASE_FULL_SENDING;
803 799 LOG (GNUNET_ERROR_TYPE_INFO,
804 (void) GNUNET_CONTAINER_multihashmap_iterate (op->spec->set->content->elements, 800 "Dedicing to transmit the full set\n");
805 &send_element_iterator, op); 801 /* FIXME: use a more memory-friendly way of doing this with an
802 iterator, just as we do in the non-full case! */
803 (void) GNUNET_CONTAINER_multihashmap_iterate (op->set->content->elements,
804 &send_full_element_iterator,
805 op);
806 ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_DONE); 806 ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_DONE);
807 GNUNET_MQ_send (op->mq, ev); 807 GNUNET_MQ_send (op->mq,
808 ev);
808} 809}
809 810
810 811
@@ -812,42 +813,56 @@ send_full_set (struct Operation *op)
812 * Handle a strata estimator from a remote peer 813 * Handle a strata estimator from a remote peer
813 * 814 *
814 * @param cls the union operation 815 * @param cls the union operation
815 * @param mh the message 816 * @param msg the message
816 * @param is_compressed #GNUNET_YES if the estimator is compressed
817 * @return #GNUNET_SYSERR if the tunnel should be disconnected,
818 * #GNUNET_OK otherwise
819 */ 817 */
820static int 818int
821handle_p2p_strata_estimator (void *cls, 819check_union_p2p_strata_estimator (void *cls,
822 const struct GNUNET_MessageHeader *mh, 820 const struct StrataEstimatorMessage *msg)
823 int is_compressed)
824{ 821{
825 struct Operation *op = cls; 822 struct Operation *op = cls;
826 struct StrataEstimator *remote_se; 823 int is_compressed;
827 struct StrataEstimatorMessage *msg = (void *) mh;
828 unsigned int diff;
829 uint64_t other_size;
830 size_t len; 824 size_t len;
831 825
832 GNUNET_STATISTICS_update (_GSS_statistics,
833 "# bytes of SE received",
834 ntohs (mh->size),
835 GNUNET_NO);
836
837 if (op->state->phase != PHASE_EXPECT_SE) 826 if (op->state->phase != PHASE_EXPECT_SE)
838 { 827 {
839 GNUNET_break (0); 828 GNUNET_break (0);
840 fail_union_operation (op);
841 return GNUNET_SYSERR; 829 return GNUNET_SYSERR;
842 } 830 }
843 len = ntohs (mh->size) - sizeof (struct StrataEstimatorMessage); 831 is_compressed = (GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SEC == htons (msg->header.type));
832 len = ntohs (msg->header.size) - sizeof (struct StrataEstimatorMessage);
844 if ( (GNUNET_NO == is_compressed) && 833 if ( (GNUNET_NO == is_compressed) &&
845 (len != SE_STRATA_COUNT * SE_IBF_SIZE * IBF_BUCKET_SIZE) ) 834 (len != SE_STRATA_COUNT * SE_IBF_SIZE * IBF_BUCKET_SIZE) )
846 { 835 {
847 fail_union_operation (op);
848 GNUNET_break (0); 836 GNUNET_break (0);
849 return GNUNET_SYSERR; 837 return GNUNET_SYSERR;
850 } 838 }
839 return GNUNET_OK;
840}
841
842
843/**
844 * Handle a strata estimator from a remote peer
845 *
846 * @param cls the union operation
847 * @param msg the message
848 */
849void
850handle_union_p2p_strata_estimator (void *cls,
851 const struct StrataEstimatorMessage *msg)
852{
853 struct Operation *op = cls;
854 struct StrataEstimator *remote_se;
855 unsigned int diff;
856 uint64_t other_size;
857 size_t len;
858 int is_compressed;
859
860 is_compressed = (GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SEC == htons (msg->header.type));
861 GNUNET_STATISTICS_update (_GSS_statistics,
862 "# bytes of SE received",
863 ntohs (msg->header.size),
864 GNUNET_NO);
865 len = ntohs (msg->header.size) - sizeof (struct StrataEstimatorMessage);
851 other_size = GNUNET_ntohll (msg->set_size); 866 other_size = GNUNET_ntohll (msg->set_size);
852 remote_se = strata_estimator_create (SE_STRATA_COUNT, 867 remote_se = strata_estimator_create (SE_STRATA_COUNT,
853 SE_IBF_SIZE, 868 SE_IBF_SIZE,
@@ -856,7 +871,7 @@ handle_p2p_strata_estimator (void *cls,
856 { 871 {
857 /* insufficient resources, fail */ 872 /* insufficient resources, fail */
858 fail_union_operation (op); 873 fail_union_operation (op);
859 return GNUNET_SYSERR; 874 return;
860 } 875 }
861 if (GNUNET_OK != 876 if (GNUNET_OK !=
862 strata_estimator_read (&msg[1], 877 strata_estimator_read (&msg[1],
@@ -865,49 +880,81 @@ handle_p2p_strata_estimator (void *cls,
865 remote_se)) 880 remote_se))
866 { 881 {
867 /* decompression failed */ 882 /* decompression failed */
868 fail_union_operation (op);
869 strata_estimator_destroy (remote_se); 883 strata_estimator_destroy (remote_se);
870 return GNUNET_SYSERR; 884 fail_union_operation (op);
885 return;
871 } 886 }
872 GNUNET_assert (NULL != op->state->se); 887 GNUNET_assert (NULL != op->state->se);
873 diff = strata_estimator_difference (remote_se, 888 diff = strata_estimator_difference (remote_se,
874 op->state->se); 889 op->state->se);
890
891 if (diff > 200)
892 diff = diff * 3 / 2;
893
875 strata_estimator_destroy (remote_se); 894 strata_estimator_destroy (remote_se);
876 strata_estimator_destroy (op->state->se); 895 strata_estimator_destroy (op->state->se);
877 op->state->se = NULL; 896 op->state->se = NULL;
878 LOG (GNUNET_ERROR_TYPE_DEBUG, 897 LOG (GNUNET_ERROR_TYPE_DEBUG,
879 "got se diff=%d, using ibf size %d\n", 898 "got se diff=%d, using ibf size %d\n",
880 diff, 899 diff,
881 1<<get_order_from_difference (diff)); 900 1U << get_order_from_difference (diff));
901
902 {
903 char *set_debug;
882 904
883 if ((GNUNET_YES == op->spec->byzantine) && (other_size < op->spec->byzantine_lower_bound)) 905 set_debug = getenv ("GNUNET_SET_BENCHMARK");
906 if ( (NULL != set_debug) &&
907 (0 == strcmp (set_debug, "1")) )
908 {
909 FILE *f = fopen ("set.log", "a");
910 fprintf (f, "%llu\n", (unsigned long long) diff);
911 fclose (f);
912 }
913 }
914
915 if ( (GNUNET_YES == op->byzantine) &&
916 (other_size < op->byzantine_lower_bound) )
884 { 917 {
885 GNUNET_break (0); 918 GNUNET_break (0);
886 fail_union_operation (op); 919 fail_union_operation (op);
887 return GNUNET_SYSERR; 920 return;
888 } 921 }
889 922
890 923 if ( (GNUNET_YES == op->force_full) ||
891 if ( (GNUNET_YES == op->spec->force_full) || (diff > op->state->initial_size / 2)) 924 (diff > op->state->initial_size / 4) ||
925 (0 == other_size) )
892 { 926 {
893 LOG (GNUNET_ERROR_TYPE_INFO, 927 LOG (GNUNET_ERROR_TYPE_INFO,
894 "Sending full set (diff=%d, own set=%u)\n", 928 "Deciding to go for full set transmission (diff=%d, own set=%u)\n",
895 diff, 929 diff,
896 op->state->initial_size); 930 op->state->initial_size);
897 if (op->state->initial_size <= other_size) 931 GNUNET_STATISTICS_update (_GSS_statistics,
932 "# of full sends",
933 1,
934 GNUNET_NO);
935 if ( (op->state->initial_size <= other_size) ||
936 (0 == other_size) )
898 { 937 {
899 send_full_set (op); 938 send_full_set (op);
900 } 939 }
901 else 940 else
902 { 941 {
903 struct GNUNET_MQ_Envelope *ev; 942 struct GNUNET_MQ_Envelope *ev;
943
944 LOG (GNUNET_ERROR_TYPE_INFO,
945 "Telling other peer that we expect its full set\n");
904 op->state->phase = PHASE_EXPECT_IBF; 946 op->state->phase = PHASE_EXPECT_IBF;
905 ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_UNION_P2P_REQUEST_FULL); 947 ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_UNION_P2P_REQUEST_FULL);
906 GNUNET_MQ_send (op->mq, ev); 948 GNUNET_MQ_send (op->mq,
949 ev);
907 } 950 }
908 } 951 }
909 else 952 else
910 { 953 {
954 GNUNET_STATISTICS_update (_GSS_statistics,
955 "# of ibf sends",
956 1,
957 GNUNET_NO);
911 if (GNUNET_OK != 958 if (GNUNET_OK !=
912 send_ibf (op, 959 send_ibf (op,
913 get_order_from_difference (diff))) 960 get_order_from_difference (diff)))
@@ -916,11 +963,10 @@ handle_p2p_strata_estimator (void *cls,
916 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 963 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
917 "Failed to send IBF, closing connection\n"); 964 "Failed to send IBF, closing connection\n");
918 fail_union_operation (op); 965 fail_union_operation (op);
919 return GNUNET_SYSERR; 966 return;
920 } 967 }
921 } 968 }
922 969 GNUNET_CADET_receive_done (op->channel);
923 return GNUNET_OK;
924} 970}
925 971
926 972
@@ -1001,14 +1047,16 @@ decode_and_send (struct Operation *op)
1001 GNUNET_assert (PHASE_INVENTORY_ACTIVE == op->state->phase); 1047 GNUNET_assert (PHASE_INVENTORY_ACTIVE == op->state->phase);
1002 1048
1003 if (GNUNET_OK != 1049 if (GNUNET_OK !=
1004 prepare_ibf (op, op->state->remote_ibf->size)) 1050 prepare_ibf (op,
1051 op->state->remote_ibf->size))
1005 { 1052 {
1006 GNUNET_break (0); 1053 GNUNET_break (0);
1007 /* allocation failed */ 1054 /* allocation failed */
1008 return GNUNET_SYSERR; 1055 return GNUNET_SYSERR;
1009 } 1056 }
1010 diff_ibf = ibf_dup (op->state->local_ibf); 1057 diff_ibf = ibf_dup (op->state->local_ibf);
1011 ibf_subtract (diff_ibf, op->state->remote_ibf); 1058 ibf_subtract (diff_ibf,
1059 op->state->remote_ibf);
1012 1060
1013 ibf_destroy (op->state->remote_ibf); 1061 ibf_destroy (op->state->remote_ibf);
1014 op->state->remote_ibf = NULL; 1062 op->state->remote_ibf = NULL;
@@ -1105,8 +1153,12 @@ decode_and_send (struct Operation *op)
1105 if (1 == side) 1153 if (1 == side)
1106 { 1154 {
1107 struct IBF_Key unsalted_key; 1155 struct IBF_Key unsalted_key;
1108 unsalt_key (&key, op->state->salt_receive, &unsalted_key); 1156
1109 send_offers_for_key (op, unsalted_key); 1157 unsalt_key (&key,
1158 op->state->salt_receive,
1159 &unsalted_key);
1160 send_offers_for_key (op,
1161 unsalted_key);
1110 } 1162 }
1111 else if (-1 == side) 1163 else if (-1 == side)
1112 { 1164 {
@@ -1138,99 +1190,118 @@ decode_and_send (struct Operation *op)
1138 1190
1139 1191
1140/** 1192/**
1141 * Handle an IBF message from a remote peer. 1193 * Check an IBF message from a remote peer.
1142 * 1194 *
1143 * Reassemble the IBF from multiple pieces, and 1195 * Reassemble the IBF from multiple pieces, and
1144 * process the whole IBF once possible. 1196 * process the whole IBF once possible.
1145 * 1197 *
1146 * @param cls the union operation 1198 * @param cls the union operation
1147 * @param mh the header of the message 1199 * @param msg the header of the message
1148 * @return #GNUNET_SYSERR if the tunnel should be disconnected, 1200 * @return #GNUNET_OK if @a msg is well-formed
1149 * #GNUNET_OK otherwise
1150 */ 1201 */
1151static int 1202int
1152handle_p2p_ibf (void *cls, 1203check_union_p2p_ibf (void *cls,
1153 const struct GNUNET_MessageHeader *mh) 1204 const struct IBFMessage *msg)
1154{ 1205{
1155 struct Operation *op = cls; 1206 struct Operation *op = cls;
1156 const struct IBFMessage *msg;
1157 unsigned int buckets_in_message; 1207 unsigned int buckets_in_message;
1158 1208
1159 if (ntohs (mh->size) < sizeof (struct IBFMessage)) 1209 if (GNUNET_SET_OPERATION_UNION != op->set->operation)
1160 { 1210 {
1161 GNUNET_break_op (0); 1211 GNUNET_break_op (0);
1162 fail_union_operation (op);
1163 return GNUNET_SYSERR; 1212 return GNUNET_SYSERR;
1164 } 1213 }
1165 msg = (const struct IBFMessage *) mh; 1214 buckets_in_message = (ntohs (msg->header.size) - sizeof *msg) / IBF_BUCKET_SIZE;
1166 if ( (op->state->phase == PHASE_INVENTORY_PASSIVE) || 1215 if (0 == buckets_in_message)
1167 (op->state->phase == PHASE_EXPECT_IBF) )
1168 { 1216 {
1169 op->state->phase = PHASE_EXPECT_IBF_CONT; 1217 GNUNET_break_op (0);
1170 GNUNET_assert (NULL == op->state->remote_ibf); 1218 return GNUNET_SYSERR;
1171 LOG (GNUNET_ERROR_TYPE_DEBUG, 1219 }
1172 "Creating new ibf of size %u\n", 1220 if ((ntohs (msg->header.size) - sizeof *msg) != buckets_in_message * IBF_BUCKET_SIZE)
1173 1 << msg->order); 1221 {
1174 op->state->remote_ibf = ibf_create (1<<msg->order, SE_IBF_HASH_NUM); 1222 GNUNET_break_op (0);
1175 op->state->salt_receive = ntohl (msg->salt); 1223 return GNUNET_SYSERR;
1176 LOG (GNUNET_ERROR_TYPE_DEBUG, "Receiving new IBF with salt %u\n", op->state->salt_receive);
1177 if (NULL == op->state->remote_ibf)
1178 {
1179 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1180 "Failed to parse remote IBF, closing connection\n");
1181 fail_union_operation (op);
1182 return GNUNET_SYSERR;
1183 }
1184 op->state->ibf_buckets_received = 0;
1185 if (0 != ntohl (msg->offset))
1186 {
1187 GNUNET_break_op (0);
1188 fail_union_operation (op);
1189 return GNUNET_SYSERR;
1190 }
1191 } 1224 }
1192 else if (op->state->phase == PHASE_EXPECT_IBF_CONT) 1225 if (op->state->phase == PHASE_EXPECT_IBF_CONT)
1193 { 1226 {
1194 if (ntohl (msg->offset) != op->state->ibf_buckets_received) 1227 if (ntohl (msg->offset) != op->state->ibf_buckets_received)
1195 { 1228 {
1196 GNUNET_break_op (0); 1229 GNUNET_break_op (0);
1197 fail_union_operation (op);
1198 return GNUNET_SYSERR; 1230 return GNUNET_SYSERR;
1199 } 1231 }
1200 if (1<<msg->order != op->state->remote_ibf->size) 1232 if (1<<msg->order != op->state->remote_ibf->size)
1201 { 1233 {
1202 GNUNET_break_op (0); 1234 GNUNET_break_op (0);
1203 fail_union_operation (op);
1204 return GNUNET_SYSERR; 1235 return GNUNET_SYSERR;
1205 } 1236 }
1206 if (ntohl (msg->salt) != op->state->salt_receive) 1237 if (ntohl (msg->salt) != op->state->salt_receive)
1207 { 1238 {
1208 GNUNET_break_op (0); 1239 GNUNET_break_op (0);
1209 fail_union_operation (op);
1210 return GNUNET_SYSERR; 1240 return GNUNET_SYSERR;
1211 } 1241 }
1212 } 1242 }
1213 else 1243 else if ( (op->state->phase != PHASE_INVENTORY_PASSIVE) &&
1244 (op->state->phase != PHASE_EXPECT_IBF) )
1214 { 1245 {
1215 GNUNET_assert (0); 1246 GNUNET_break_op (0);
1247 return GNUNET_SYSERR;
1216 } 1248 }
1217 1249
1218 buckets_in_message = (ntohs (msg->header.size) - sizeof *msg) / IBF_BUCKET_SIZE; 1250 return GNUNET_OK;
1251}
1219 1252
1220 if (0 == buckets_in_message) 1253
1254/**
1255 * Handle an IBF message from a remote peer.
1256 *
1257 * Reassemble the IBF from multiple pieces, and
1258 * process the whole IBF once possible.
1259 *
1260 * @param cls the union operation
1261 * @param msg the header of the message
1262 */
1263void
1264handle_union_p2p_ibf (void *cls,
1265 const struct IBFMessage *msg)
1266{
1267 struct Operation *op = cls;
1268 unsigned int buckets_in_message;
1269
1270 buckets_in_message = (ntohs (msg->header.size) - sizeof *msg) / IBF_BUCKET_SIZE;
1271 if ( (op->state->phase == PHASE_INVENTORY_PASSIVE) ||
1272 (op->state->phase == PHASE_EXPECT_IBF) )
1221 { 1273 {
1222 GNUNET_break_op (0); 1274 op->state->phase = PHASE_EXPECT_IBF_CONT;
1223 fail_union_operation (op); 1275 GNUNET_assert (NULL == op->state->remote_ibf);
1224 return GNUNET_SYSERR; 1276 LOG (GNUNET_ERROR_TYPE_DEBUG,
1277 "Creating new ibf of size %u\n",
1278 1 << msg->order);
1279 op->state->remote_ibf = ibf_create (1<<msg->order, SE_IBF_HASH_NUM);
1280 op->state->salt_receive = ntohl (msg->salt);
1281 LOG (GNUNET_ERROR_TYPE_DEBUG,
1282 "Receiving new IBF with salt %u\n",
1283 op->state->salt_receive);
1284 if (NULL == op->state->remote_ibf)
1285 {
1286 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1287 "Failed to parse remote IBF, closing connection\n");
1288 fail_union_operation (op);
1289 return;
1290 }
1291 op->state->ibf_buckets_received = 0;
1292 if (0 != ntohl (msg->offset))
1293 {
1294 GNUNET_break_op (0);
1295 fail_union_operation (op);
1296 return;
1297 }
1225 } 1298 }
1226 1299 else
1227 if ((ntohs (msg->header.size) - sizeof *msg) != buckets_in_message * IBF_BUCKET_SIZE)
1228 { 1300 {
1229 GNUNET_break_op (0); 1301 GNUNET_assert (op->state->phase == PHASE_EXPECT_IBF_CONT);
1230 fail_union_operation (op); 1302 LOG (GNUNET_ERROR_TYPE_INFO,
1231 return GNUNET_SYSERR; 1303 "Received more of IBF\n");
1232 } 1304 }
1233
1234 GNUNET_assert (NULL != op->state->remote_ibf); 1305 GNUNET_assert (NULL != op->state->remote_ibf);
1235 1306
1236 ibf_read_slice (&msg[1], 1307 ibf_read_slice (&msg[1],
@@ -1250,10 +1321,11 @@ handle_p2p_ibf (void *cls,
1250 /* Internal error, best we can do is shut down */ 1321 /* Internal error, best we can do is shut down */
1251 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1322 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1252 "Failed to decode IBF, closing connection\n"); 1323 "Failed to decode IBF, closing connection\n");
1253 return GNUNET_SYSERR; 1324 fail_union_operation (op);
1325 return;
1254 } 1326 }
1255 } 1327 }
1256 return GNUNET_OK; 1328 GNUNET_CADET_receive_done (op->channel);
1257} 1329}
1258 1330
1259 1331
@@ -1276,7 +1348,7 @@ send_client_element (struct Operation *op,
1276 LOG (GNUNET_ERROR_TYPE_DEBUG, 1348 LOG (GNUNET_ERROR_TYPE_DEBUG,
1277 "sending element (size %u) to client\n", 1349 "sending element (size %u) to client\n",
1278 element->size); 1350 element->size);
1279 GNUNET_assert (0 != op->spec->client_request_id); 1351 GNUNET_assert (0 != op->client_request_id);
1280 ev = GNUNET_MQ_msg_extra (rm, element->size, GNUNET_MESSAGE_TYPE_SET_RESULT); 1352 ev = GNUNET_MQ_msg_extra (rm, element->size, GNUNET_MESSAGE_TYPE_SET_RESULT);
1281 if (NULL == ev) 1353 if (NULL == ev)
1282 { 1354 {
@@ -1285,11 +1357,14 @@ send_client_element (struct Operation *op,
1285 return; 1357 return;
1286 } 1358 }
1287 rm->result_status = htons (status); 1359 rm->result_status = htons (status);
1288 rm->request_id = htonl (op->spec->client_request_id); 1360 rm->request_id = htonl (op->client_request_id);
1289 rm->element_type = htons (element->element_type); 1361 rm->element_type = htons (element->element_type);
1290 rm->current_size = GNUNET_htonll (GNUNET_CONTAINER_multihashmap32_size (op->state->key_to_element)); 1362 rm->current_size = GNUNET_htonll (GNUNET_CONTAINER_multihashmap32_size (op->state->key_to_element));
1291 GNUNET_memcpy (&rm[1], element->data, element->size); 1363 GNUNET_memcpy (&rm[1],
1292 GNUNET_MQ_send (op->spec->set->client_mq, ev); 1364 element->data,
1365 element->size);
1366 GNUNET_MQ_send (op->set->cs->mq,
1367 ev);
1293} 1368}
1294 1369
1295 1370
@@ -1306,17 +1381,27 @@ send_done_and_destroy (void *cls)
1306 struct GNUNET_MQ_Envelope *ev; 1381 struct GNUNET_MQ_Envelope *ev;
1307 struct GNUNET_SET_ResultMessage *rm; 1382 struct GNUNET_SET_ResultMessage *rm;
1308 1383
1309 ev = GNUNET_MQ_msg (rm, GNUNET_MESSAGE_TYPE_SET_RESULT); 1384 LOG (GNUNET_ERROR_TYPE_INFO,
1310 rm->request_id = htonl (op->spec->client_request_id); 1385 "Signalling client that union operation is done\n");
1386 ev = GNUNET_MQ_msg (rm,
1387 GNUNET_MESSAGE_TYPE_SET_RESULT);
1388 rm->request_id = htonl (op->client_request_id);
1311 rm->result_status = htons (GNUNET_SET_STATUS_DONE); 1389 rm->result_status = htons (GNUNET_SET_STATUS_DONE);
1312 rm->element_type = htons (0); 1390 rm->element_type = htons (0);
1313 rm->current_size = GNUNET_htonll (GNUNET_CONTAINER_multihashmap32_size (op->state->key_to_element)); 1391 rm->current_size = GNUNET_htonll (GNUNET_CONTAINER_multihashmap32_size (op->state->key_to_element));
1314 GNUNET_MQ_send (op->spec->set->client_mq, ev); 1392 GNUNET_MQ_send (op->set->cs->mq,
1393 ev);
1315 /* Will also call the union-specific cancel function. */ 1394 /* Will also call the union-specific cancel function. */
1316 _GSS_operation_destroy (op, GNUNET_YES); 1395 _GSS_operation_destroy (op,
1396 GNUNET_YES);
1317} 1397}
1318 1398
1319 1399
1400/**
1401 * Tests if the operation is finished, and if so notify.
1402 *
1403 * @param op operation to check
1404 */
1320static void 1405static void
1321maybe_finish (struct Operation *op) 1406maybe_finish (struct Operation *op)
1322{ 1407{
@@ -1335,8 +1420,8 @@ maybe_finish (struct Operation *op)
1335 1420
1336 op->state->phase = PHASE_DONE; 1421 op->state->phase = PHASE_DONE;
1337 ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DONE); 1422 ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DONE);
1338 GNUNET_MQ_send (op->mq, ev); 1423 GNUNET_MQ_send (op->mq,
1339 1424 ev);
1340 /* We now wait until the other peer closes the channel 1425 /* We now wait until the other peer closes the channel
1341 * after it got all elements from us. */ 1426 * after it got all elements from us. */
1342 } 1427 }
@@ -1356,46 +1441,59 @@ maybe_finish (struct Operation *op)
1356 1441
1357 1442
1358/** 1443/**
1359 * Handle an element message from a remote peer. 1444 * Check an element message from a remote peer.
1360 * Sent by the other peer either because we decoded an IBF and placed a demand,
1361 * or because the other peer switched to full set transmission.
1362 * 1445 *
1363 * @param cls the union operation 1446 * @param cls the union operation
1364 * @param mh the message 1447 * @param emsg the message
1365 */ 1448 */
1366static void 1449int
1367handle_p2p_elements (void *cls, 1450check_union_p2p_elements (void *cls,
1368 const struct GNUNET_MessageHeader *mh) 1451 const struct GNUNET_SET_ElementMessage *emsg)
1369{ 1452{
1370 struct Operation *op = cls; 1453 struct Operation *op = cls;
1371 struct ElementEntry *ee;
1372 const struct GNUNET_SET_ElementMessage *emsg;
1373 uint16_t element_size;
1374 1454
1375 if (0 == GNUNET_CONTAINER_multihashmap_size (op->state->demanded_hashes)) 1455 if (GNUNET_SET_OPERATION_UNION != op->set->operation)
1376 { 1456 {
1377 GNUNET_break_op (0); 1457 GNUNET_break_op (0);
1378 fail_union_operation (op); 1458 return GNUNET_SYSERR;
1379 return;
1380 } 1459 }
1381 if (ntohs (mh->size) < sizeof (struct GNUNET_SET_ElementMessage)) 1460 if (0 == GNUNET_CONTAINER_multihashmap_size (op->state->demanded_hashes))
1382 { 1461 {
1383 GNUNET_break_op (0); 1462 GNUNET_break_op (0);
1384 fail_union_operation (op); 1463 return GNUNET_SYSERR;
1385 return;
1386 } 1464 }
1465 return GNUNET_OK;
1466}
1387 1467
1388 emsg = (const struct GNUNET_SET_ElementMessage *) mh;
1389 1468
1390 element_size = ntohs (mh->size) - sizeof (struct GNUNET_SET_ElementMessage); 1469/**
1470 * Handle an element message from a remote peer.
1471 * Sent by the other peer either because we decoded an IBF and placed a demand,
1472 * or because the other peer switched to full set transmission.
1473 *
1474 * @param cls the union operation
1475 * @param emsg the message
1476 */
1477void
1478handle_union_p2p_elements (void *cls,
1479 const struct GNUNET_SET_ElementMessage *emsg)
1480{
1481 struct Operation *op = cls;
1482 struct ElementEntry *ee;
1483 struct KeyEntry *ke;
1484 uint16_t element_size;
1485
1486 element_size = ntohs (emsg->header.size) - sizeof (struct GNUNET_SET_ElementMessage);
1391 ee = GNUNET_malloc (sizeof (struct ElementEntry) + element_size); 1487 ee = GNUNET_malloc (sizeof (struct ElementEntry) + element_size);
1392 GNUNET_memcpy (&ee[1], &emsg[1], element_size); 1488 GNUNET_memcpy (&ee[1],
1489 &emsg[1],
1490 element_size);
1393 ee->element.size = element_size; 1491 ee->element.size = element_size;
1394 ee->element.data = &ee[1]; 1492 ee->element.data = &ee[1];
1395 ee->element.element_type = ntohs (emsg->element_type); 1493 ee->element.element_type = ntohs (emsg->element_type);
1396 ee->remote = GNUNET_YES; 1494 ee->remote = GNUNET_YES;
1397 GNUNET_SET_element_hash (&ee->element, &ee->element_hash); 1495 GNUNET_SET_element_hash (&ee->element,
1398 1496 &ee->element_hash);
1399 if (GNUNET_NO == 1497 if (GNUNET_NO ==
1400 GNUNET_CONTAINER_multihashmap_remove (op->state->demanded_hashes, 1498 GNUNET_CONTAINER_multihashmap_remove (op->state->demanded_hashes,
1401 &ee->element_hash, 1499 &ee->element_hash,
@@ -1403,7 +1501,6 @@ handle_p2p_elements (void *cls,
1403 { 1501 {
1404 /* We got something we didn't demand, since it's not in our map. */ 1502 /* We got something we didn't demand, since it's not in our map. */
1405 GNUNET_break_op (0); 1503 GNUNET_break_op (0);
1406 GNUNET_free (ee);
1407 fail_union_operation (op); 1504 fail_union_operation (op);
1408 return; 1505 return;
1409 } 1506 }
@@ -1422,10 +1519,9 @@ handle_p2p_elements (void *cls,
1422 1, 1519 1,
1423 GNUNET_NO); 1520 GNUNET_NO);
1424 1521
1425 op->state->received_total += 1; 1522 op->state->received_total++;
1426
1427 struct KeyEntry *ke = op_get_element (op, &ee->element_hash);
1428 1523
1524 ke = op_get_element (op, &ee->element_hash);
1429 if (NULL != ke) 1525 if (NULL != ke)
1430 { 1526 {
1431 /* Got repeated element. Should not happen since 1527 /* Got repeated element. Should not happen since
@@ -1441,10 +1537,10 @@ handle_p2p_elements (void *cls,
1441 { 1537 {
1442 LOG (GNUNET_ERROR_TYPE_DEBUG, 1538 LOG (GNUNET_ERROR_TYPE_DEBUG,
1443 "Registering new element from remote peer\n"); 1539 "Registering new element from remote peer\n");
1444 op->state->received_fresh += 1; 1540 op->state->received_fresh++;
1445 op_register_element (op, ee, GNUNET_YES); 1541 op_register_element (op, ee, GNUNET_YES);
1446 /* only send results immediately if the client wants it */ 1542 /* only send results immediately if the client wants it */
1447 switch (op->spec->result_mode) 1543 switch (op->result_mode)
1448 { 1544 {
1449 case GNUNET_SET_RESULT_ADDED: 1545 case GNUNET_SET_RESULT_ADDED:
1450 send_client_element (op, &ee->element, GNUNET_SET_STATUS_OK); 1546 send_client_element (op, &ee->element, GNUNET_SET_STATUS_OK);
@@ -1459,43 +1555,57 @@ handle_p2p_elements (void *cls,
1459 } 1555 }
1460 } 1556 }
1461 1557
1462 if (op->state->received_total > 8 && op->state->received_fresh < op->state->received_total / 3) 1558 if ( (op->state->received_total > 8) &&
1559 (op->state->received_fresh < op->state->received_total / 3) )
1463 { 1560 {
1464 /* The other peer gave us lots of old elements, there's something wrong. */ 1561 /* The other peer gave us lots of old elements, there's something wrong. */
1465 GNUNET_break_op (0); 1562 GNUNET_break_op (0);
1466 fail_union_operation (op); 1563 fail_union_operation (op);
1467 return; 1564 return;
1468 } 1565 }
1469 1566 GNUNET_CADET_receive_done (op->channel);
1470 maybe_finish (op); 1567 maybe_finish (op);
1471} 1568}
1472 1569
1473 1570
1474/** 1571/**
1475 * Handle an element message from a remote peer. 1572 * Check a full element message from a remote peer.
1476 * 1573 *
1477 * @param cls the union operation 1574 * @param cls the union operation
1478 * @param mh the message 1575 * @param emsg the message
1479 */ 1576 */
1480static void 1577int
1481handle_p2p_full_element (void *cls, 1578check_union_p2p_full_element (void *cls,
1482 const struct GNUNET_MessageHeader *mh) 1579 const struct GNUNET_SET_ElementMessage *emsg)
1483{ 1580{
1484 struct Operation *op = cls; 1581 struct Operation *op = cls;
1485 struct ElementEntry *ee;
1486 const struct GNUNET_SET_ElementMessage *emsg;
1487 uint16_t element_size;
1488 1582
1489 if (ntohs (mh->size) < sizeof (struct GNUNET_SET_ElementMessage)) 1583 if (GNUNET_SET_OPERATION_UNION != op->set->operation)
1490 { 1584 {
1491 GNUNET_break_op (0); 1585 GNUNET_break_op (0);
1492 fail_union_operation (op); 1586 return GNUNET_SYSERR;
1493 return;
1494 } 1587 }
1588 // FIXME: check that we expect full elements here?
1589 return GNUNET_OK;
1590}
1495 1591
1496 emsg = (const struct GNUNET_SET_ElementMessage *) mh;
1497 1592
1498 element_size = ntohs (mh->size) - sizeof (struct GNUNET_SET_ElementMessage); 1593/**
1594 * Handle an element message from a remote peer.
1595 *
1596 * @param cls the union operation
1597 * @param emsg the message
1598 */
1599void
1600handle_union_p2p_full_element (void *cls,
1601 const struct GNUNET_SET_ElementMessage *emsg)
1602{
1603 struct Operation *op = cls;
1604 struct ElementEntry *ee;
1605 struct KeyEntry *ke;
1606 uint16_t element_size;
1607
1608 element_size = ntohs (emsg->header.size) - sizeof (struct GNUNET_SET_ElementMessage);
1499 ee = GNUNET_malloc (sizeof (struct ElementEntry) + element_size); 1609 ee = GNUNET_malloc (sizeof (struct ElementEntry) + element_size);
1500 GNUNET_memcpy (&ee[1], &emsg[1], element_size); 1610 GNUNET_memcpy (&ee[1], &emsg[1], element_size);
1501 ee->element.size = element_size; 1611 ee->element.size = element_size;
@@ -1518,10 +1628,9 @@ handle_p2p_full_element (void *cls,
1518 1, 1628 1,
1519 GNUNET_NO); 1629 GNUNET_NO);
1520 1630
1521 op->state->received_total += 1; 1631 op->state->received_total++;
1522
1523 struct KeyEntry *ke = op_get_element (op, &ee->element_hash);
1524 1632
1633 ke = op_get_element (op, &ee->element_hash);
1525 if (NULL != ke) 1634 if (NULL != ke)
1526 { 1635 {
1527 /* Got repeated element. Should not happen since 1636 /* Got repeated element. Should not happen since
@@ -1537,10 +1646,10 @@ handle_p2p_full_element (void *cls,
1537 { 1646 {
1538 LOG (GNUNET_ERROR_TYPE_DEBUG, 1647 LOG (GNUNET_ERROR_TYPE_DEBUG,
1539 "Registering new element from remote peer\n"); 1648 "Registering new element from remote peer\n");
1540 op->state->received_fresh += 1; 1649 op->state->received_fresh++;
1541 op_register_element (op, ee, GNUNET_YES); 1650 op_register_element (op, ee, GNUNET_YES);
1542 /* only send results immediately if the client wants it */ 1651 /* only send results immediately if the client wants it */
1543 switch (op->spec->result_mode) 1652 switch (op->result_mode)
1544 { 1653 {
1545 case GNUNET_SET_RESULT_ADDED: 1654 case GNUNET_SET_RESULT_ADDED:
1546 send_client_element (op, &ee->element, GNUNET_SET_STATUS_OK); 1655 send_client_element (op, &ee->element, GNUNET_SET_STATUS_OK);
@@ -1555,9 +1664,9 @@ handle_p2p_full_element (void *cls,
1555 } 1664 }
1556 } 1665 }
1557 1666
1558 if ( (GNUNET_YES == op->spec->byzantine) && 1667 if ( (GNUNET_YES == op->byzantine) &&
1559 (op->state->received_total > 150) && 1668 (op->state->received_total > 384 + op->state->received_fresh * 4) &&
1560 (op->state->received_fresh < op->state->received_total / 3) ) 1669 (op->state->received_fresh < op->state->received_total / 6) )
1561 { 1670 {
1562 /* The other peer gave us lots of old elements, there's something wrong. */ 1671 /* The other peer gave us lots of old elements, there's something wrong. */
1563 LOG (GNUNET_ERROR_TYPE_ERROR, 1672 LOG (GNUNET_ERROR_TYPE_ERROR,
@@ -1568,51 +1677,78 @@ handle_p2p_full_element (void *cls,
1568 fail_union_operation (op); 1677 fail_union_operation (op);
1569 return; 1678 return;
1570 } 1679 }
1680 GNUNET_CADET_receive_done (op->channel);
1571} 1681}
1572 1682
1683
1573/** 1684/**
1574 * Send offers (for GNUNET_Hash-es) in response 1685 * Send offers (for GNUNET_Hash-es) in response
1575 * to inquiries (for IBF_Key-s). 1686 * to inquiries (for IBF_Key-s).
1576 * 1687 *
1577 * @param cls the union operation 1688 * @param cls the union operation
1578 * @param mh the message 1689 * @param msg the message
1579 */ 1690 */
1580static void 1691int
1581handle_p2p_inquiry (void *cls, 1692check_union_p2p_inquiry (void *cls,
1582 const struct GNUNET_MessageHeader *mh) 1693 const struct InquiryMessage *msg)
1583{ 1694{
1584 struct Operation *op = cls; 1695 struct Operation *op = cls;
1585 const struct IBF_Key *ibf_key;
1586 unsigned int num_keys; 1696 unsigned int num_keys;
1587 struct InquiryMessage *msg;
1588 1697
1589 /* look up elements and send them */ 1698 if (GNUNET_SET_OPERATION_UNION != op->set->operation)
1699 {
1700 GNUNET_break_op (0);
1701 return GNUNET_SYSERR;
1702 }
1590 if (op->state->phase != PHASE_INVENTORY_PASSIVE) 1703 if (op->state->phase != PHASE_INVENTORY_PASSIVE)
1591 { 1704 {
1592 GNUNET_break_op (0); 1705 GNUNET_break_op (0);
1593 fail_union_operation (op); 1706 return GNUNET_SYSERR;
1594 return;
1595 } 1707 }
1596 num_keys = (ntohs (mh->size) - sizeof (struct InquiryMessage)) 1708 num_keys = (ntohs (msg->header.size) - sizeof (struct InquiryMessage))
1597 / sizeof (struct IBF_Key); 1709 / sizeof (struct IBF_Key);
1598 if ((ntohs (mh->size) - sizeof (struct InquiryMessage)) 1710 if ((ntohs (msg->header.size) - sizeof (struct InquiryMessage))
1599 != num_keys * sizeof (struct IBF_Key)) 1711 != num_keys * sizeof (struct IBF_Key))
1600 { 1712 {
1601 GNUNET_break_op (0); 1713 GNUNET_break_op (0);
1602 fail_union_operation (op); 1714 return GNUNET_SYSERR;
1603 return;
1604 } 1715 }
1716 return GNUNET_OK;
1717}
1605 1718
1606 msg = (struct InquiryMessage *) mh;
1607 1719
1720/**
1721 * Send offers (for GNUNET_Hash-es) in response
1722 * to inquiries (for IBF_Key-s).
1723 *
1724 * @param cls the union operation
1725 * @param msg the message
1726 */
1727void
1728handle_union_p2p_inquiry (void *cls,
1729 const struct InquiryMessage *msg)
1730{
1731 struct Operation *op = cls;
1732 const struct IBF_Key *ibf_key;
1733 unsigned int num_keys;
1734
1735 LOG (GNUNET_ERROR_TYPE_INFO,
1736 "Received union inquiry\n");
1737 num_keys = (ntohs (msg->header.size) - sizeof (struct InquiryMessage))
1738 / sizeof (struct IBF_Key);
1608 ibf_key = (const struct IBF_Key *) &msg[1]; 1739 ibf_key = (const struct IBF_Key *) &msg[1];
1609 while (0 != num_keys--) 1740 while (0 != num_keys--)
1610 { 1741 {
1611 struct IBF_Key unsalted_key; 1742 struct IBF_Key unsalted_key;
1612 unsalt_key (ibf_key, ntohl (msg->salt), &unsalted_key); 1743
1613 send_offers_for_key (op, unsalted_key); 1744 unsalt_key (ibf_key,
1745 ntohl (msg->salt),
1746 &unsalted_key);
1747 send_offers_for_key (op,
1748 unsalted_key);
1614 ibf_key++; 1749 ibf_key++;
1615 } 1750 }
1751 GNUNET_CADET_receive_done (op->channel);
1616} 1752}
1617 1753
1618 1754
@@ -1627,9 +1763,9 @@ handle_p2p_inquiry (void *cls,
1627 * #GNUNET_NO if not. 1763 * #GNUNET_NO if not.
1628 */ 1764 */
1629static int 1765static int
1630send_missing_elements_iter (void *cls, 1766send_missing_full_elements_iter (void *cls,
1631 uint32_t key, 1767 uint32_t key,
1632 void *value) 1768 void *value)
1633{ 1769{
1634 struct Operation *op = cls; 1770 struct Operation *op = cls;
1635 struct KeyEntry *ke = value; 1771 struct KeyEntry *ke = value;
@@ -1639,39 +1775,50 @@ send_missing_elements_iter (void *cls,
1639 1775
1640 if (GNUNET_YES == ke->received) 1776 if (GNUNET_YES == ke->received)
1641 return GNUNET_YES; 1777 return GNUNET_YES;
1642 1778 ev = GNUNET_MQ_msg_extra (emsg,
1643 ev = GNUNET_MQ_msg_extra (emsg, ee->element.size, GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_ELEMENT); 1779 ee->element.size,
1644 GNUNET_memcpy (&emsg[1], ee->element.data, ee->element.size); 1780 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_ELEMENT);
1645 emsg->reserved = htons (0); 1781 GNUNET_memcpy (&emsg[1],
1782 ee->element.data,
1783 ee->element.size);
1646 emsg->element_type = htons (ee->element.element_type); 1784 emsg->element_type = htons (ee->element.element_type);
1647 GNUNET_MQ_send (op->mq, ev); 1785 GNUNET_MQ_send (op->mq,
1648 1786 ev);
1649 return GNUNET_YES; 1787 return GNUNET_YES;
1650} 1788}
1651 1789
1652 1790
1653/** 1791/**
1654 * Handle a 1792 * Handle a request for full set transmission.
1655 * 1793 *
1656 * @parem cls closure, a set union operation 1794 * @parem cls closure, a set union operation
1657 * @param mh the demand message 1795 * @param mh the demand message
1658 */ 1796 */
1659static void 1797void
1660handle_p2p_request_full (void *cls, 1798handle_union_p2p_request_full (void *cls,
1661 const struct GNUNET_MessageHeader *mh) 1799 const struct GNUNET_MessageHeader *mh)
1662{ 1800{
1663 struct Operation *op = cls; 1801 struct Operation *op = cls;
1664 1802
1665 if (PHASE_EXPECT_IBF != op->state->phase) 1803 LOG (GNUNET_ERROR_TYPE_INFO,
1804 "Received request for full set transmission\n");
1805 if (GNUNET_SET_OPERATION_UNION != op->set->operation)
1666 { 1806 {
1807 GNUNET_break_op (0);
1667 fail_union_operation (op); 1808 fail_union_operation (op);
1809 return;
1810 }
1811 if (PHASE_EXPECT_IBF != op->state->phase)
1812 {
1668 GNUNET_break_op (0); 1813 GNUNET_break_op (0);
1814 fail_union_operation (op);
1669 return; 1815 return;
1670 } 1816 }
1671 1817
1672 // FIXME: we need to check that our set is larger than the 1818 // FIXME: we need to check that our set is larger than the
1673 // byzantine_lower_bound by some threshold 1819 // byzantine_lower_bound by some threshold
1674 send_full_set (op); 1820 send_full_set (op);
1821 GNUNET_CADET_receive_done (op->channel);
1675} 1822}
1676 1823
1677 1824
@@ -1681,56 +1828,101 @@ handle_p2p_request_full (void *cls,
1681 * @parem cls closure, a set union operation 1828 * @parem cls closure, a set union operation
1682 * @param mh the demand message 1829 * @param mh the demand message
1683 */ 1830 */
1684static void 1831void
1685handle_p2p_full_done (void *cls, 1832handle_union_p2p_full_done (void *cls,
1686 const struct GNUNET_MessageHeader *mh) 1833 const struct GNUNET_MessageHeader *mh)
1687{ 1834{
1688 struct Operation *op = cls; 1835 struct Operation *op = cls;
1689 1836
1690 if (PHASE_EXPECT_IBF == op->state->phase) 1837 switch (op->state->phase)
1691 { 1838 {
1692 struct GNUNET_MQ_Envelope *ev; 1839 case PHASE_EXPECT_IBF:
1840 {
1841 struct GNUNET_MQ_Envelope *ev;
1693 1842
1694 LOG (GNUNET_ERROR_TYPE_DEBUG, "got FULL DONE, sending elements that other peer is missing\n"); 1843 LOG (GNUNET_ERROR_TYPE_DEBUG,
1844 "got FULL DONE, sending elements that other peer is missing\n");
1845
1846 /* send all the elements that did not come from the remote peer */
1847 GNUNET_CONTAINER_multihashmap32_iterate (op->state->key_to_element,
1848 &send_missing_full_elements_iter,
1849 op);
1850
1851 ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_DONE);
1852 GNUNET_MQ_notify_sent (ev,
1853 &send_done_and_destroy,
1854 op);
1855 GNUNET_MQ_send (op->mq,
1856 ev);
1857 op->state->phase = PHASE_DONE;
1858 /* we now wait until the other peer shuts the tunnel down*/
1859 }
1860 break;
1861 case PHASE_FULL_SENDING:
1862 {
1863 LOG (GNUNET_ERROR_TYPE_DEBUG,
1864 "got FULL DONE, finishing\n");
1865 /* We sent the full set, and got the response for that. We're done. */
1866 op->state->phase = PHASE_DONE;
1867 GNUNET_CADET_receive_done (op->channel);
1868 send_done_and_destroy (op);
1869 return;
1870 }
1871 break;
1872 default:
1873 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1874 "Handle full done phase is %u\n",
1875 (unsigned) op->state->phase);
1876 GNUNET_break_op (0);
1877 fail_union_operation (op);
1878 return;
1879 }
1880 GNUNET_CADET_receive_done (op->channel);
1881}
1695 1882
1696 /* send all the elements that did not come from the remote peer */
1697 GNUNET_CONTAINER_multihashmap32_iterate (op->state->key_to_element,
1698 &send_missing_elements_iter,
1699 op);
1700 1883
1701 ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_DONE); 1884/**
1702 GNUNET_MQ_send (op->mq, ev); 1885 * Check a demand by the other peer for elements based on a list
1703 op->state->phase = PHASE_DONE; 1886 * of `struct GNUNET_HashCode`s.
1887 *
1888 * @parem cls closure, a set union operation
1889 * @param mh the demand message
1890 * @return #GNUNET_OK if @a mh is well-formed
1891 */
1892int
1893check_union_p2p_demand (void *cls,
1894 const struct GNUNET_MessageHeader *mh)
1895{
1896 struct Operation *op = cls;
1897 unsigned int num_hashes;
1704 1898
1705 /* we now wait until the other peer shuts the tunnel down*/ 1899 if (GNUNET_SET_OPERATION_UNION != op->set->operation)
1706 }
1707 else if (PHASE_FULL_SENDING == op->state->phase)
1708 { 1900 {
1709 LOG (GNUNET_ERROR_TYPE_DEBUG, "got FULL DONE, finishing\n"); 1901 GNUNET_break_op (0);
1710 /* We sent the full set, and got the response for that. We're done. */ 1902 return GNUNET_SYSERR;
1711 op->state->phase = PHASE_DONE;
1712 send_done_and_destroy (op);
1713 } 1903 }
1714 else 1904 num_hashes = (ntohs (mh->size) - sizeof (struct GNUNET_MessageHeader))
1905 / sizeof (struct GNUNET_HashCode);
1906 if ((ntohs (mh->size) - sizeof (struct GNUNET_MessageHeader))
1907 != num_hashes * sizeof (struct GNUNET_HashCode))
1715 { 1908 {
1716 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "handle full done phase is %u\n", (unsigned) op->state->phase);
1717 GNUNET_break_op (0); 1909 GNUNET_break_op (0);
1718 fail_union_operation (op); 1910 return GNUNET_SYSERR;
1719 return;
1720 } 1911 }
1912 return GNUNET_OK;
1721} 1913}
1722 1914
1723 1915
1724/** 1916/**
1725 * Handle a demand by the other peer for elements based on a list 1917 * Handle a demand by the other peer for elements based on a list
1726 * of GNUNET_HashCode-s. 1918 * of `struct GNUNET_HashCode`s.
1727 * 1919 *
1728 * @parem cls closure, a set union operation 1920 * @parem cls closure, a set union operation
1729 * @param mh the demand message 1921 * @param mh the demand message
1730 */ 1922 */
1731static void 1923void
1732handle_p2p_demand (void *cls, 1924handle_union_p2p_demand (void *cls,
1733 const struct GNUNET_MessageHeader *mh) 1925 const struct GNUNET_MessageHeader *mh)
1734{ 1926{
1735 struct Operation *op = cls; 1927 struct Operation *op = cls;
1736 struct ElementEntry *ee; 1928 struct ElementEntry *ee;
@@ -1741,19 +1933,12 @@ handle_p2p_demand (void *cls,
1741 1933
1742 num_hashes = (ntohs (mh->size) - sizeof (struct GNUNET_MessageHeader)) 1934 num_hashes = (ntohs (mh->size) - sizeof (struct GNUNET_MessageHeader))
1743 / sizeof (struct GNUNET_HashCode); 1935 / sizeof (struct GNUNET_HashCode);
1744 if ((ntohs (mh->size) - sizeof (struct GNUNET_MessageHeader))
1745 != num_hashes * sizeof (struct GNUNET_HashCode))
1746 {
1747 GNUNET_break_op (0);
1748 fail_union_operation (op);
1749 return;
1750 }
1751
1752 for (hash = (const struct GNUNET_HashCode *) &mh[1]; 1936 for (hash = (const struct GNUNET_HashCode *) &mh[1];
1753 num_hashes > 0; 1937 num_hashes > 0;
1754 hash++, num_hashes--) 1938 hash++, num_hashes--)
1755 { 1939 {
1756 ee = GNUNET_CONTAINER_multihashmap_get (op->spec->set->content->elements, hash); 1940 ee = GNUNET_CONTAINER_multihashmap_get (op->set->content->elements,
1941 hash);
1757 if (NULL == ee) 1942 if (NULL == ee)
1758 { 1943 {
1759 /* Demand for non-existing element. */ 1944 /* Demand for non-existing element. */
@@ -1783,7 +1968,7 @@ handle_p2p_demand (void *cls,
1783 1, 1968 1,
1784 GNUNET_NO); 1969 GNUNET_NO);
1785 1970
1786 switch (op->spec->result_mode) 1971 switch (op->result_mode)
1787 { 1972 {
1788 case GNUNET_SET_RESULT_ADDED: 1973 case GNUNET_SET_RESULT_ADDED:
1789 /* Nothing to do. */ 1974 /* Nothing to do. */
@@ -1797,42 +1982,65 @@ handle_p2p_demand (void *cls,
1797 break; 1982 break;
1798 } 1983 }
1799 } 1984 }
1985 GNUNET_CADET_receive_done (op->channel);
1800} 1986}
1801 1987
1802 1988
1803/** 1989/**
1804 * Handle offers (of GNUNET_HashCode-s) and 1990 * Check offer (of `struct GNUNET_HashCode`s).
1805 * respond with demands (of GNUNET_HashCode-s).
1806 * 1991 *
1807 * @param cls the union operation 1992 * @param cls the union operation
1808 * @param mh the message 1993 * @param mh the message
1994 * @return #GNUNET_OK if @a mh is well-formed
1809 */ 1995 */
1810static void 1996int
1811handle_p2p_offer (void *cls, 1997check_union_p2p_offer (void *cls,
1812 const struct GNUNET_MessageHeader *mh) 1998 const struct GNUNET_MessageHeader *mh)
1813{ 1999{
1814 struct Operation *op = cls; 2000 struct Operation *op = cls;
1815 const struct GNUNET_HashCode *hash;
1816 unsigned int num_hashes; 2001 unsigned int num_hashes;
1817 2002
2003 if (GNUNET_SET_OPERATION_UNION != op->set->operation)
2004 {
2005 GNUNET_break_op (0);
2006 return GNUNET_SYSERR;
2007 }
1818 /* look up elements and send them */ 2008 /* look up elements and send them */
1819 if ( (op->state->phase != PHASE_INVENTORY_PASSIVE) && 2009 if ( (op->state->phase != PHASE_INVENTORY_PASSIVE) &&
1820 (op->state->phase != PHASE_INVENTORY_ACTIVE)) 2010 (op->state->phase != PHASE_INVENTORY_ACTIVE))
1821 { 2011 {
1822 GNUNET_break_op (0); 2012 GNUNET_break_op (0);
1823 fail_union_operation (op); 2013 return GNUNET_SYSERR;
1824 return;
1825 } 2014 }
1826 num_hashes = (ntohs (mh->size) - sizeof (struct GNUNET_MessageHeader)) 2015 num_hashes = (ntohs (mh->size) - sizeof (struct GNUNET_MessageHeader))
1827 / sizeof (struct GNUNET_HashCode); 2016 / sizeof (struct GNUNET_HashCode);
1828 if ((ntohs (mh->size) - sizeof (struct GNUNET_MessageHeader)) 2017 if ((ntohs (mh->size) - sizeof (struct GNUNET_MessageHeader)) !=
1829 != num_hashes * sizeof (struct GNUNET_HashCode)) 2018 num_hashes * sizeof (struct GNUNET_HashCode))
1830 { 2019 {
1831 GNUNET_break_op (0); 2020 GNUNET_break_op (0);
1832 fail_union_operation (op); 2021 return GNUNET_SYSERR;
1833 return;
1834 } 2022 }
2023 return GNUNET_OK;
2024}
2025
2026
2027/**
2028 * Handle offers (of `struct GNUNET_HashCode`s) and
2029 * respond with demands (of `struct GNUNET_HashCode`s).
2030 *
2031 * @param cls the union operation
2032 * @param mh the message
2033 */
2034void
2035handle_union_p2p_offer (void *cls,
2036 const struct GNUNET_MessageHeader *mh)
2037{
2038 struct Operation *op = cls;
2039 const struct GNUNET_HashCode *hash;
2040 unsigned int num_hashes;
1835 2041
2042 num_hashes = (ntohs (mh->size) - sizeof (struct GNUNET_MessageHeader))
2043 / sizeof (struct GNUNET_HashCode);
1836 for (hash = (const struct GNUNET_HashCode *) &mh[1]; 2044 for (hash = (const struct GNUNET_HashCode *) &mh[1];
1837 num_hashes > 0; 2045 num_hashes > 0;
1838 hash++, num_hashes--) 2046 hash++, num_hashes--)
@@ -1841,7 +2049,7 @@ handle_p2p_offer (void *cls,
1841 struct GNUNET_MessageHeader *demands; 2049 struct GNUNET_MessageHeader *demands;
1842 struct GNUNET_MQ_Envelope *ev; 2050 struct GNUNET_MQ_Envelope *ev;
1843 2051
1844 ee = GNUNET_CONTAINER_multihashmap_get (op->spec->set->content->elements, 2052 ee = GNUNET_CONTAINER_multihashmap_get (op->set->content->elements,
1845 hash); 2053 hash);
1846 if (NULL != ee) 2054 if (NULL != ee)
1847 if (GNUNET_YES == _GSS_is_element_of_operation (ee, op)) 2055 if (GNUNET_YES == _GSS_is_element_of_operation (ee, op))
@@ -1868,9 +2076,12 @@ handle_p2p_offer (void *cls,
1868 ev = GNUNET_MQ_msg_header_extra (demands, 2076 ev = GNUNET_MQ_msg_header_extra (demands,
1869 sizeof (struct GNUNET_HashCode), 2077 sizeof (struct GNUNET_HashCode),
1870 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DEMAND); 2078 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DEMAND);
1871 *(struct GNUNET_HashCode *) &demands[1] = *hash; 2079 GNUNET_memcpy (&demands[1],
2080 hash,
2081 sizeof (struct GNUNET_HashCode));
1872 GNUNET_MQ_send (op->mq, ev); 2082 GNUNET_MQ_send (op->mq, ev);
1873 } 2083 }
2084 GNUNET_CADET_receive_done (op->channel);
1874} 2085}
1875 2086
1876 2087
@@ -1880,16 +2091,22 @@ handle_p2p_offer (void *cls,
1880 * @param cls the union operation 2091 * @param cls the union operation
1881 * @param mh the message 2092 * @param mh the message
1882 */ 2093 */
1883static void 2094void
1884handle_p2p_done (void *cls, 2095handle_union_p2p_done (void *cls,
1885 const struct GNUNET_MessageHeader *mh) 2096 const struct GNUNET_MessageHeader *mh)
1886{ 2097{
1887 struct Operation *op = cls; 2098 struct Operation *op = cls;
1888 2099
1889 if (op->state->phase == PHASE_INVENTORY_PASSIVE) 2100 if (GNUNET_SET_OPERATION_UNION != op->set->operation)
2101 {
2102 GNUNET_break_op (0);
2103 fail_union_operation (op);
2104 return;
2105 }
2106 switch (op->state->phase)
1890 { 2107 {
2108 case PHASE_INVENTORY_PASSIVE:
1891 /* We got all requests, but still have to send our elements in response. */ 2109 /* We got all requests, but still have to send our elements in response. */
1892
1893 op->state->phase = PHASE_FINISH_WAITING; 2110 op->state->phase = PHASE_FINISH_WAITING;
1894 2111
1895 LOG (GNUNET_ERROR_TYPE_DEBUG, 2112 LOG (GNUNET_ERROR_TYPE_DEBUG,
@@ -1903,11 +2120,10 @@ handle_p2p_done (void *cls,
1903 * all our demands are satisfied, so that the active 2120 * all our demands are satisfied, so that the active
1904 * peer can quit if we gave him everything. 2121 * peer can quit if we gave him everything.
1905 */ 2122 */
2123 GNUNET_CADET_receive_done (op->channel);
1906 maybe_finish (op); 2124 maybe_finish (op);
1907 return; 2125 return;
1908 } 2126 case PHASE_INVENTORY_ACTIVE:
1909 if (op->state->phase == PHASE_INVENTORY_ACTIVE)
1910 {
1911 LOG (GNUNET_ERROR_TYPE_DEBUG, 2127 LOG (GNUNET_ERROR_TYPE_DEBUG,
1912 "got DONE (as active partner), waiting to finish\n"); 2128 "got DONE (as active partner), waiting to finish\n");
1913 /* All demands of the other peer are satisfied, 2129 /* All demands of the other peer are satisfied,
@@ -1918,11 +2134,14 @@ handle_p2p_done (void *cls,
1918 * to the other peer once our demands are met. 2134 * to the other peer once our demands are met.
1919 */ 2135 */
1920 op->state->phase = PHASE_FINISH_CLOSING; 2136 op->state->phase = PHASE_FINISH_CLOSING;
2137 GNUNET_CADET_receive_done (op->channel);
1921 maybe_finish (op); 2138 maybe_finish (op);
1922 return; 2139 return;
2140 default:
2141 GNUNET_break_op (0);
2142 fail_union_operation (op);
2143 return;
1923 } 2144 }
1924 GNUNET_break_op (0);
1925 fail_union_operation (op);
1926} 2145}
1927 2146
1928 2147
@@ -1933,21 +2152,31 @@ handle_p2p_done (void *cls,
1933 * @param opaque_context message to be transmitted to the listener 2152 * @param opaque_context message to be transmitted to the listener
1934 * to convince him to accept, may be NULL 2153 * to convince him to accept, may be NULL
1935 */ 2154 */
1936static void 2155static struct OperationState *
1937union_evaluate (struct Operation *op, 2156union_evaluate (struct Operation *op,
1938 const struct GNUNET_MessageHeader *opaque_context) 2157 const struct GNUNET_MessageHeader *opaque_context)
1939{ 2158{
2159 struct OperationState *state;
1940 struct GNUNET_MQ_Envelope *ev; 2160 struct GNUNET_MQ_Envelope *ev;
1941 struct OperationRequestMessage *msg; 2161 struct OperationRequestMessage *msg;
1942 2162
1943 GNUNET_assert (NULL == op->state); 2163 ev = GNUNET_MQ_msg_nested_mh (msg,
1944 op->state = GNUNET_new (struct OperationState); 2164 GNUNET_MESSAGE_TYPE_SET_P2P_OPERATION_REQUEST,
1945 op->state->demanded_hashes = GNUNET_CONTAINER_multihashmap_create (32, GNUNET_NO); 2165 opaque_context);
2166 if (NULL == ev)
2167 {
2168 /* the context message is too large */
2169 GNUNET_break (0);
2170 return NULL;
2171 }
2172 state = GNUNET_new (struct OperationState);
2173 state->demanded_hashes = GNUNET_CONTAINER_multihashmap_create (32,
2174 GNUNET_NO);
1946 /* copy the current generation's strata estimator for this operation */ 2175 /* copy the current generation's strata estimator for this operation */
1947 op->state->se = strata_estimator_dup (op->spec->set->state->se); 2176 state->se = strata_estimator_dup (op->set->state->se);
1948 /* we started the operation, thus we have to send the operation request */ 2177 /* we started the operation, thus we have to send the operation request */
1949 op->state->phase = PHASE_EXPECT_SE; 2178 state->phase = PHASE_EXPECT_SE;
1950 op->state->salt_receive = op->state->salt_send = 42; 2179 state->salt_receive = state->salt_send = 42; // FIXME?????
1951 LOG (GNUNET_ERROR_TYPE_DEBUG, 2180 LOG (GNUNET_ERROR_TYPE_DEBUG,
1952 "Initiating union operation evaluation\n"); 2181 "Initiating union operation evaluation\n");
1953 GNUNET_STATISTICS_update (_GSS_statistics, 2182 GNUNET_STATISTICS_update (_GSS_statistics,
@@ -1958,16 +2187,6 @@ union_evaluate (struct Operation *op,
1958 "# of initiated union operations", 2187 "# of initiated union operations",
1959 1, 2188 1,
1960 GNUNET_NO); 2189 GNUNET_NO);
1961 ev = GNUNET_MQ_msg_nested_mh (msg,
1962 GNUNET_MESSAGE_TYPE_SET_P2P_OPERATION_REQUEST,
1963 opaque_context);
1964 if (NULL == ev)
1965 {
1966 /* the context message is too large */
1967 GNUNET_break (0);
1968 GNUNET_SERVICE_client_drop (op->spec->set->client);
1969 return;
1970 }
1971 msg->operation = htonl (GNUNET_SET_OPERATION_UNION); 2190 msg->operation = htonl (GNUNET_SET_OPERATION_UNION);
1972 GNUNET_MQ_send (op->mq, 2191 GNUNET_MQ_send (op->mq,
1973 ev); 2192 ev);
@@ -1979,8 +2198,10 @@ union_evaluate (struct Operation *op,
1979 LOG (GNUNET_ERROR_TYPE_DEBUG, 2198 LOG (GNUNET_ERROR_TYPE_DEBUG,
1980 "sent op request without context message\n"); 2199 "sent op request without context message\n");
1981 2200
2201 op->state = state;
1982 initialize_key_to_element (op); 2202 initialize_key_to_element (op);
1983 op->state->initial_size = GNUNET_CONTAINER_multihashmap32_size (op->state->key_to_element); 2203 state->initial_size = GNUNET_CONTAINER_multihashmap32_size (state->key_to_element);
2204 return state;
1984} 2205}
1985 2206
1986 2207
@@ -1990,13 +2211,19 @@ union_evaluate (struct Operation *op,
1990 * 2211 *
1991 * @param op operation that will be accepted as a union operation 2212 * @param op operation that will be accepted as a union operation
1992 */ 2213 */
1993static void 2214static struct OperationState *
1994union_accept (struct Operation *op) 2215union_accept (struct Operation *op)
1995{ 2216{
2217 struct OperationState *state;
2218 const struct StrataEstimator *se;
2219 struct GNUNET_MQ_Envelope *ev;
2220 struct StrataEstimatorMessage *strata_msg;
2221 char *buf;
2222 size_t len;
2223 uint16_t type;
2224
1996 LOG (GNUNET_ERROR_TYPE_DEBUG, 2225 LOG (GNUNET_ERROR_TYPE_DEBUG,
1997 "accepting set union operation\n"); 2226 "accepting set union operation\n");
1998 GNUNET_assert (NULL == op->state);
1999
2000 GNUNET_STATISTICS_update (_GSS_statistics, 2227 GNUNET_STATISTICS_update (_GSS_statistics,
2001 "# of accepted union operations", 2228 "# of accepted union operations",
2002 1, 2229 1,
@@ -2006,14 +2233,37 @@ union_accept (struct Operation *op)
2006 1, 2233 1,
2007 GNUNET_NO); 2234 GNUNET_NO);
2008 2235
2009 op->state = GNUNET_new (struct OperationState); 2236 state = GNUNET_new (struct OperationState);
2010 op->state->se = strata_estimator_dup (op->spec->set->state->se); 2237 state->se = strata_estimator_dup (op->set->state->se);
2011 op->state->demanded_hashes = GNUNET_CONTAINER_multihashmap_create (32, GNUNET_NO); 2238 state->demanded_hashes = GNUNET_CONTAINER_multihashmap_create (32,
2012 op->state->salt_receive = op->state->salt_send = 42; 2239 GNUNET_NO);
2240 state->salt_receive = state->salt_send = 42; // FIXME?????
2241 op->state = state;
2013 initialize_key_to_element (op); 2242 initialize_key_to_element (op);
2014 op->state->initial_size = GNUNET_CONTAINER_multihashmap32_size (op->state->key_to_element); 2243 state->initial_size = GNUNET_CONTAINER_multihashmap32_size (state->key_to_element);
2244
2015 /* kick off the operation */ 2245 /* kick off the operation */
2016 send_strata_estimator (op); 2246 se = state->se;
2247 buf = GNUNET_malloc (se->strata_count * IBF_BUCKET_SIZE * se->ibf_size);
2248 len = strata_estimator_write (se,
2249 buf);
2250 if (len < se->strata_count * IBF_BUCKET_SIZE * se->ibf_size)
2251 type = GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SEC;
2252 else
2253 type = GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SE;
2254 ev = GNUNET_MQ_msg_extra (strata_msg,
2255 len,
2256 type);
2257 GNUNET_memcpy (&strata_msg[1],
2258 buf,
2259 len);
2260 GNUNET_free (buf);
2261 strata_msg->set_size
2262 = GNUNET_htonll (GNUNET_CONTAINER_multihashmap_size (op->set->content->elements));
2263 GNUNET_MQ_send (op->mq,
2264 ev);
2265 state->phase = PHASE_EXPECT_IBF;
2266 return state;
2017} 2267}
2018 2268
2019 2269
@@ -2053,7 +2303,8 @@ union_set_create (void)
2053 * @param ee the element to add to the set 2303 * @param ee the element to add to the set
2054 */ 2304 */
2055static void 2305static void
2056union_add (struct SetState *set_state, struct ElementEntry *ee) 2306union_add (struct SetState *set_state,
2307 struct ElementEntry *ee)
2057{ 2308{
2058 strata_estimator_insert (set_state->se, 2309 strata_estimator_insert (set_state->se,
2059 get_ibf_key (&ee->element_hash)); 2310 get_ibf_key (&ee->element_hash));
@@ -2068,7 +2319,8 @@ union_add (struct SetState *set_state, struct ElementEntry *ee)
2068 * @param ee set element to remove 2319 * @param ee set element to remove
2069 */ 2320 */
2070static void 2321static void
2071union_remove (struct SetState *set_state, struct ElementEntry *ee) 2322union_remove (struct SetState *set_state,
2323 struct ElementEntry *ee)
2072{ 2324{
2073 strata_estimator_remove (set_state->se, 2325 strata_estimator_remove (set_state->se,
2074 get_ibf_key (&ee->element_hash)); 2326 get_ibf_key (&ee->element_hash));
@@ -2093,113 +2345,35 @@ union_set_destroy (struct SetState *set_state)
2093 2345
2094 2346
2095/** 2347/**
2096 * Dispatch messages for a union operation. 2348 * Copy union-specific set state.
2097 * 2349 *
2098 * @param op the state of the union evaluate operation 2350 * @param state source state for copying the union state
2099 * @param mh the received message 2351 * @return a copy of the union-specific set state
2100 * @return #GNUNET_SYSERR if the tunnel should be disconnected,
2101 * #GNUNET_OK otherwise
2102 */ 2352 */
2103int 2353static struct SetState *
2104union_handle_p2p_message (struct Operation *op, 2354union_copy_state (struct SetState *state)
2105 const struct GNUNET_MessageHeader *mh)
2106{ 2355{
2107 //LOG (GNUNET_ERROR_TYPE_DEBUG, 2356 struct SetState *new_state;
2108 // "received p2p message (t: %u, s: %u)\n",
2109 // ntohs (mh->type),
2110 // ntohs (mh->size));
2111 switch (ntohs (mh->type))
2112 {
2113 case GNUNET_MESSAGE_TYPE_SET_UNION_P2P_IBF:
2114 return handle_p2p_ibf (op, mh);
2115 case GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SE:
2116 return handle_p2p_strata_estimator (op, mh, GNUNET_NO);
2117 case GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SEC:
2118 return handle_p2p_strata_estimator (op, mh, GNUNET_YES);
2119 case GNUNET_MESSAGE_TYPE_SET_P2P_ELEMENTS:
2120 handle_p2p_elements (op, mh);
2121 break;
2122 case GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_ELEMENT:
2123 handle_p2p_full_element (op, mh);
2124 break;
2125 case GNUNET_MESSAGE_TYPE_SET_UNION_P2P_INQUIRY:
2126 handle_p2p_inquiry (op, mh);
2127 break;
2128 case GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DONE:
2129 handle_p2p_done (op, mh);
2130 break;
2131 case GNUNET_MESSAGE_TYPE_SET_UNION_P2P_OFFER:
2132 handle_p2p_offer (op, mh);
2133 break;
2134 case GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DEMAND:
2135 handle_p2p_demand (op, mh);
2136 break;
2137 case GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_DONE:
2138 handle_p2p_full_done (op, mh);
2139 break;
2140 case GNUNET_MESSAGE_TYPE_SET_UNION_P2P_REQUEST_FULL:
2141 handle_p2p_request_full (op, mh);
2142 break;
2143 default:
2144 /* Something wrong with cadet's message handlers? */
2145 GNUNET_assert (0);
2146 }
2147 return GNUNET_OK;
2148}
2149 2357
2358 GNUNET_assert ( (NULL != state) &&
2359 (NULL != state->se) );
2360 new_state = GNUNET_new (struct SetState);
2361 new_state->se = strata_estimator_dup (state->se);
2150 2362
2151/** 2363 return new_state;
2152 * Handler for peer-disconnects, notifies the client
2153 * about the aborted operation in case the op was not concluded.
2154 *
2155 * @param op the destroyed operation
2156 */
2157static void
2158union_peer_disconnect (struct Operation *op)
2159{
2160 if (PHASE_DONE != op->state->phase)
2161 {
2162 struct GNUNET_MQ_Envelope *ev;
2163 struct GNUNET_SET_ResultMessage *msg;
2164
2165 ev = GNUNET_MQ_msg (msg,
2166 GNUNET_MESSAGE_TYPE_SET_RESULT);
2167 msg->request_id = htonl (op->spec->client_request_id);
2168 msg->result_status = htons (GNUNET_SET_STATUS_FAILURE);
2169 msg->element_type = htons (0);
2170 GNUNET_MQ_send (op->spec->set->client_mq,
2171 ev);
2172 LOG (GNUNET_ERROR_TYPE_WARNING,
2173 "other peer disconnected prematurely, phase %u\n",
2174 op->state->phase);
2175 _GSS_operation_destroy (op,
2176 GNUNET_YES);
2177 return;
2178 }
2179 // else: the session has already been concluded
2180 LOG (GNUNET_ERROR_TYPE_DEBUG,
2181 "other peer disconnected (finished)\n");
2182 if (GNUNET_NO == op->state->client_done_sent)
2183 send_done_and_destroy (op);
2184} 2364}
2185 2365
2186 2366
2187/** 2367/**
2188 * Copy union-specific set state. 2368 * Handle case where channel went down for an operation.
2189 * 2369 *
2190 * @param set source set for copying the union state 2370 * @param op operation that lost the channel
2191 * @return a copy of the union-specific set state
2192 */ 2371 */
2193static struct SetState * 2372static void
2194union_copy_state (struct Set *set) 2373union_channel_death (struct Operation *op)
2195{ 2374{
2196 struct SetState *new_state; 2375 _GSS_operation_destroy (op,
2197 2376 GNUNET_YES);
2198 new_state = GNUNET_new (struct SetState);
2199 GNUNET_assert ( (NULL != set->state) && (NULL != set->state->se) );
2200 new_state->se = strata_estimator_dup (set->state->se);
2201
2202 return new_state;
2203} 2377}
2204 2378
2205 2379
@@ -2214,15 +2388,14 @@ _GSS_union_vt ()
2214{ 2388{
2215 static const struct SetVT union_vt = { 2389 static const struct SetVT union_vt = {
2216 .create = &union_set_create, 2390 .create = &union_set_create,
2217 .msg_handler = &union_handle_p2p_message,
2218 .add = &union_add, 2391 .add = &union_add,
2219 .remove = &union_remove, 2392 .remove = &union_remove,
2220 .destroy_set = &union_set_destroy, 2393 .destroy_set = &union_set_destroy,
2221 .evaluate = &union_evaluate, 2394 .evaluate = &union_evaluate,
2222 .accept = &union_accept, 2395 .accept = &union_accept,
2223 .peer_disconnect = &union_peer_disconnect,
2224 .cancel = &union_op_cancel, 2396 .cancel = &union_op_cancel,
2225 .copy_state = &union_copy_state, 2397 .copy_state = &union_copy_state,
2398 .channel_death = &union_channel_death
2226 }; 2399 };
2227 2400
2228 return &union_vt; 2401 return &union_vt;
diff --git a/src/set/gnunet-service-set_union.h b/src/set/gnunet-service-set_union.h
new file mode 100644
index 000000000..cbf60bcbc
--- /dev/null
+++ b/src/set/gnunet-service-set_union.h
@@ -0,0 +1,239 @@
1
2/*
3 This file is part of GNUnet
4 Copyright (C) 2013-2017 GNUnet e.V.
5
6 GNUnet is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published
8 by the Free Software Foundation; either version 3, or (at your
9 option) any later version.
10
11 GNUnet is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNUnet; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA.
20*/
21/**
22 * @file set/gnunet-service-set_union.h
23 * @brief two-peer set operations
24 * @author Florian Dold
25 * @author Christian Grothoff
26 */
27#ifndef GNUNET_SERVICE_SET_UNION_H
28#define GNUNET_SERVICE_SET_UNION_H
29
30#include "gnunet-service-set.h"
31#include "gnunet-service-set_protocol.h"
32
33
34/**
35 * Handle a strata estimator from a remote peer
36 *
37 * @param cls the union operation
38 * @param msg the message
39 */
40int
41check_union_p2p_strata_estimator (void *cls,
42 const struct StrataEstimatorMessage *msg);
43
44
45/**
46 * Handle a strata estimator from a remote peer
47 *
48 * @param cls the union operation
49 * @param msg the message
50 */
51void
52handle_union_p2p_strata_estimator (void *cls,
53 const struct StrataEstimatorMessage *msg);
54
55
56/**
57 * Check an IBF message from a remote peer.
58 *
59 * Reassemble the IBF from multiple pieces, and
60 * process the whole IBF once possible.
61 *
62 * @param cls the union operation
63 * @param msg the header of the message
64 * @return #GNUNET_OK if @a msg is well-formed
65 */
66int
67check_union_p2p_ibf (void *cls,
68 const struct IBFMessage *msg);
69
70
71/**
72 * Handle an IBF message from a remote peer.
73 *
74 * Reassemble the IBF from multiple pieces, and
75 * process the whole IBF once possible.
76 *
77 * @param cls the union operation
78 * @param msg the header of the message
79 */
80void
81handle_union_p2p_ibf (void *cls,
82 const struct IBFMessage *msg);
83
84
85/**
86 * Check an element message from a remote peer.
87 *
88 * @param cls the union operation
89 * @param emsg the message
90 */
91int
92check_union_p2p_elements (void *cls,
93 const struct GNUNET_SET_ElementMessage *emsg);
94
95
96/**
97 * Handle an element message from a remote peer.
98 * Sent by the other peer either because we decoded an IBF and placed a demand,
99 * or because the other peer switched to full set transmission.
100 *
101 * @param cls the union operation
102 * @param emsg the message
103 */
104void
105handle_union_p2p_elements (void *cls,
106 const struct GNUNET_SET_ElementMessage *emsg);
107
108
109/**
110 * Check a full element message from a remote peer.
111 *
112 * @param cls the union operation
113 * @param emsg the message
114 */
115int
116check_union_p2p_full_element (void *cls,
117 const struct GNUNET_SET_ElementMessage *emsg);
118
119
120/**
121 * Handle an element message from a remote peer.
122 *
123 * @param cls the union operation
124 * @param emsg the message
125 */
126void
127handle_union_p2p_full_element (void *cls,
128 const struct GNUNET_SET_ElementMessage *emsg);
129
130
131/**
132 * Send offers (for GNUNET_Hash-es) in response
133 * to inquiries (for IBF_Key-s).
134 *
135 * @param cls the union operation
136 * @param msg the message
137 */
138int
139check_union_p2p_inquiry (void *cls,
140 const struct InquiryMessage *msg);
141
142
143/**
144 * Send offers (for GNUNET_Hash-es) in response
145 * to inquiries (for IBF_Key-s).
146 *
147 * @param cls the union operation
148 * @param msg the message
149 */
150void
151handle_union_p2p_inquiry (void *cls,
152 const struct InquiryMessage *msg);
153
154
155
156/**
157 * Handle a request for full set transmission.
158 *
159 * @parem cls closure, a set union operation
160 * @param mh the demand message
161 */
162void
163handle_union_p2p_request_full (void *cls,
164 const struct GNUNET_MessageHeader *mh);
165
166
167
168/**
169 * Handle a "full done" message.
170 *
171 * @parem cls closure, a set union operation
172 * @param mh the demand message
173 */
174void
175handle_union_p2p_full_done (void *cls,
176 const struct GNUNET_MessageHeader *mh);
177
178
179/**
180 * Check a demand by the other peer for elements based on a list
181 * of `struct GNUNET_HashCode`s.
182 *
183 * @parem cls closure, a set union operation
184 * @param mh the demand message
185 * @return #GNUNET_OK if @a mh is well-formed
186 */
187int
188check_union_p2p_demand (void *cls,
189 const struct GNUNET_MessageHeader *mh);
190
191
192/**
193 * Handle a demand by the other peer for elements based on a list
194 * of `struct GNUNET_HashCode`s.
195 *
196 * @parem cls closure, a set union operation
197 * @param mh the demand message
198 */
199void
200handle_union_p2p_demand (void *cls,
201 const struct GNUNET_MessageHeader *mh);
202
203
204/**
205 * Check offer (of `struct GNUNET_HashCode`s).
206 *
207 * @param cls the union operation
208 * @param mh the message
209 * @return #GNUNET_OK if @a mh is well-formed
210 */
211int
212check_union_p2p_offer (void *cls,
213 const struct GNUNET_MessageHeader *mh);
214
215
216/**
217 * Handle offers (of `struct GNUNET_HashCode`s) and
218 * respond with demands (of `struct GNUNET_HashCode`s).
219 *
220 * @param cls the union operation
221 * @param mh the message
222 */
223void
224handle_union_p2p_offer (void *cls,
225 const struct GNUNET_MessageHeader *mh);
226
227
228/**
229 * Handle a done message from a remote peer
230 *
231 * @param cls the union operation
232 * @param mh the message
233 */
234void
235handle_union_p2p_done (void *cls,
236 const struct GNUNET_MessageHeader *mh);
237
238
239#endif
diff --git a/src/set/gnunet-set-ibf-profiler.c b/src/set/gnunet-set-ibf-profiler.c
index 8d832e358..ac86a900d 100644
--- a/src/set/gnunet-set-ibf-profiler.c
+++ b/src/set/gnunet-set-ibf-profiler.c
@@ -244,24 +244,41 @@ run (void *cls,
244int 244int
245main (int argc, char **argv) 245main (int argc, char **argv)
246{ 246{
247 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 247 struct GNUNET_GETOPT_CommandLineOption options[] = {
248 {'A', "asize", NULL, 248
249 gettext_noop ("number of element in set A-B"), 1, 249 GNUNET_GETOPT_OPTION_SET_UINT ('A',
250 &GNUNET_GETOPT_set_uint, &asize}, 250 "asize",
251 {'B', "bsize", NULL, 251 NULL,
252 gettext_noop ("number of element in set B-A"), 1, 252 gettext_noop ("number of element in set A-B"),
253 &GNUNET_GETOPT_set_uint, &bsize}, 253 &asize),
254 {'C', "csize", NULL, 254
255 gettext_noop ("number of common elements in A and B"), 1, 255 GNUNET_GETOPT_OPTION_SET_UINT ('B',
256 &GNUNET_GETOPT_set_uint, &csize}, 256 "bsize",
257 {'k', "hash-num", NULL, 257 NULL,
258 gettext_noop ("hash num"), 1, 258 gettext_noop ("number of element in set B-A"),
259 &GNUNET_GETOPT_set_uint, &hash_num}, 259 &bsize),
260 {'s', "ibf-size", NULL, 260
261 gettext_noop ("ibf size"), 1, 261 GNUNET_GETOPT_OPTION_SET_UINT ('C',
262 &GNUNET_GETOPT_set_uint, &ibf_size}, 262 "csize",
263 NULL,
264 gettext_noop ("number of common elements in A and B"),
265 &csize),
266
267 GNUNET_GETOPT_OPTION_SET_UINT ('k',
268 "hash-num",
269 NULL,
270 gettext_noop ("hash num"),
271 &hash_num),
272
273 GNUNET_GETOPT_OPTION_SET_UINT ('s',
274 "ibf-size",
275 NULL,
276 gettext_noop ("ibf size"),
277 &ibf_size),
278
263 GNUNET_GETOPT_OPTION_END 279 GNUNET_GETOPT_OPTION_END
264 }; 280 };
281
265 GNUNET_PROGRAM_run2 (argc, argv, "gnunet-consensus-ibf", 282 GNUNET_PROGRAM_run2 (argc, argv, "gnunet-consensus-ibf",
266 "help", 283 "help",
267 options, &run, NULL, GNUNET_YES); 284 options, &run, NULL, GNUNET_YES);
diff --git a/src/set/gnunet-set-profiler.c b/src/set/gnunet-set-profiler.c
index d83e034a6..349bce6ea 100644
--- a/src/set/gnunet-set-profiler.c
+++ b/src/set/gnunet-set-profiler.c
@@ -59,8 +59,9 @@ static struct GNUNET_PeerIdentity local_peer;
59static struct GNUNET_SET_ListenHandle *set_listener; 59static struct GNUNET_SET_ListenHandle *set_listener;
60 60
61static int byzantine; 61static int byzantine;
62static int force_delta; 62static unsigned int force_delta;
63static int force_full; 63static unsigned int force_full;
64static unsigned int element_size = 32;
64 65
65/** 66/**
66 * Handle to the statistics service. 67 * Handle to the statistics service.
@@ -90,7 +91,7 @@ map_remove_iterator (void *cls,
90 91
91 GNUNET_assert (NULL != key); 92 GNUNET_assert (NULL != key);
92 93
93 ret = GNUNET_CONTAINER_multihashmap_remove (m, key, NULL); 94 ret = GNUNET_CONTAINER_multihashmap_remove_all (m, key);
94 if (GNUNET_OK != ret) 95 if (GNUNET_OK != ret)
95 printf ("spurious element\n"); 96 printf ("spurious element\n");
96 return GNUNET_YES; 97 return GNUNET_YES;
@@ -196,7 +197,7 @@ set_result_cb (void *cls,
196 GNUNET_assert (0); 197 GNUNET_assert (0);
197 } 198 }
198 199
199 if (element->size != sizeof (struct GNUNET_HashCode)) 200 if (element->size != element_size)
200 { 201 {
201 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 202 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
202 "wrong element size: %u, expected %u\n", 203 "wrong element size: %u, expected %u\n",
@@ -208,8 +209,10 @@ set_result_cb (void *cls,
208 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "set %s: got element (%s)\n", 209 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "set %s: got element (%s)\n",
209 info->id, GNUNET_h2s (element->data)); 210 info->id, GNUNET_h2s (element->data));
210 GNUNET_assert (NULL != element->data); 211 GNUNET_assert (NULL != element->data);
212 struct GNUNET_HashCode data_hash;
213 GNUNET_CRYPTO_hash (element->data, element_size, &data_hash);
211 GNUNET_CONTAINER_multihashmap_put (info->received, 214 GNUNET_CONTAINER_multihashmap_put (info->received,
212 element->data, NULL, 215 &data_hash, NULL,
213 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE); 216 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
214} 217}
215 218
@@ -261,16 +264,12 @@ set_insert_iterator (void *cls,
261 void *value) 264 void *value)
262{ 265{
263 struct GNUNET_SET_Handle *set = cls; 266 struct GNUNET_SET_Handle *set = cls;
264 struct GNUNET_SET_Element *el; 267 struct GNUNET_SET_Element el;
265 268
266 el = GNUNET_malloc (sizeof (struct GNUNET_SET_Element) + 269 el.element_type = 0;
267 sizeof (struct GNUNET_HashCode)); 270 el.data = value;
268 el->element_type = 0; 271 el.size = element_size;
269 GNUNET_memcpy (&el[1], key, sizeof *key); 272 GNUNET_SET_add_element (set, &el, NULL, NULL);
270 el->data = &el[1];
271 el->size = sizeof *key;
272 GNUNET_SET_add_element (set, el, NULL, NULL);
273 GNUNET_free (el);
274 return GNUNET_YES; 273 return GNUNET_YES;
275} 274}
276 275
@@ -322,6 +321,8 @@ run (void *cls,
322 321
323 config = cfg; 322 config = cfg;
324 323
324 GNUNET_assert (element_size > 0);
325
325 if (GNUNET_OK != GNUNET_CRYPTO_get_peer_identity (cfg, &local_peer)) 326 if (GNUNET_OK != GNUNET_CRYPTO_get_peer_identity (cfg, &local_peer))
326 { 327 {
327 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "could not retrieve host identity\n"); 328 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "could not retrieve host identity\n");
@@ -345,22 +346,28 @@ run (void *cls,
345 346
346 for (i = 0; i < num_a; i++) 347 for (i = 0; i < num_a; i++)
347 { 348 {
348 GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_STRONG, &hash); 349 char *data = GNUNET_malloc (element_size);
349 GNUNET_CONTAINER_multihashmap_put (info1.sent, &hash, NULL, 350 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, data, element_size);
351 GNUNET_CRYPTO_hash (data, element_size, &hash);
352 GNUNET_CONTAINER_multihashmap_put (info1.sent, &hash, data,
350 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE); 353 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
351 } 354 }
352 355
353 for (i = 0; i < num_b; i++) 356 for (i = 0; i < num_b; i++)
354 { 357 {
355 GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_STRONG, &hash); 358 char *data = GNUNET_malloc (element_size);
356 GNUNET_CONTAINER_multihashmap_put (info2.sent, &hash, NULL, 359 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, data, element_size);
360 GNUNET_CRYPTO_hash (data, element_size, &hash);
361 GNUNET_CONTAINER_multihashmap_put (info2.sent, &hash, data,
357 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE); 362 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
358 } 363 }
359 364
360 for (i = 0; i < num_c; i++) 365 for (i = 0; i < num_c; i++)
361 { 366 {
362 GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_STRONG, &hash); 367 char *data = GNUNET_malloc (element_size);
363 GNUNET_CONTAINER_multihashmap_put (common_sent, &hash, NULL, 368 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, data, element_size);
369 GNUNET_CRYPTO_hash (data, element_size, &hash);
370 GNUNET_CONTAINER_multihashmap_put (common_sent, &hash, data,
364 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE); 371 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
365 } 372 }
366 373
@@ -419,31 +426,60 @@ pre_run (void *cls, char *const *args, const char *cfgfile,
419int 426int
420main (int argc, char **argv) 427main (int argc, char **argv)
421{ 428{
422 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 429 struct GNUNET_GETOPT_CommandLineOption options[] = {
423 { 'A', "num-first", NULL, 430 GNUNET_GETOPT_OPTION_SET_UINT ('A',
424 gettext_noop ("number of values"), 431 "num-first",
425 GNUNET_YES, &GNUNET_GETOPT_set_uint, &num_a }, 432 NULL,
426 { 'B', "num-second", NULL, 433 gettext_noop ("number of values"),
427 gettext_noop ("number of values"), 434 &num_a),
428 GNUNET_YES, &GNUNET_GETOPT_set_uint, &num_b }, 435
429 { 'b', "byzantine", NULL, 436 GNUNET_GETOPT_OPTION_SET_UINT ('B',
430 gettext_noop ("use byzantine mode"), 437 "num-second",
431 GNUNET_NO, &GNUNET_GETOPT_set_one, &byzantine }, 438 NULL,
432 { 'f', "force-full", NULL, 439 gettext_noop ("number of values"),
433 gettext_noop ("force sending full set"), 440 &num_b),
434 GNUNET_NO, &GNUNET_GETOPT_set_uint, &force_full }, 441
435 { 'd', "force-delta", NULL, 442 GNUNET_GETOPT_OPTION_SET_ONE ('b',
436 gettext_noop ("number delta operation"), 443 "byzantine",
437 GNUNET_NO, &GNUNET_GETOPT_set_uint, &force_delta }, 444 gettext_noop ("use byzantine mode"),
438 { 'C', "num-common", NULL, 445 &byzantine),
439 gettext_noop ("number of values"), 446
440 GNUNET_YES, &GNUNET_GETOPT_set_uint, &num_c }, 447 GNUNET_GETOPT_OPTION_SET_UINT ('f',
441 { 'x', "operation", NULL, 448 "force-full",
442 gettext_noop ("operation to execute"), 449 NULL,
443 GNUNET_YES, &GNUNET_GETOPT_set_string, &op_str }, 450 gettext_noop ("force sending full set"),
444 { 's', "statistics", NULL, 451 &force_full),
445 gettext_noop ("write statistics to file"), 452
446 GNUNET_YES, &GNUNET_GETOPT_set_filename, &statistics_filename }, 453 GNUNET_GETOPT_OPTION_SET_UINT ('d',
454 "force-delta",
455 NULL,
456 gettext_noop ("number delta operation"),
457 &force_delta),
458
459 GNUNET_GETOPT_OPTION_SET_UINT ('C',
460 "num-common",
461 NULL,
462 gettext_noop ("number of values"),
463 &num_c),
464
465 GNUNET_GETOPT_OPTION_STRING ('x',
466 "operation",
467 NULL,
468 gettext_noop ("operation to execute"),
469 &op_str),
470
471 GNUNET_GETOPT_OPTION_SET_UINT ('w',
472 "element-size",
473 NULL,
474 gettext_noop ("element size"),
475 &element_size),
476
477 GNUNET_GETOPT_OPTION_FILENAME ('s',
478 "statistics",
479 "FILENAME",
480 gettext_noop ("write statistics to file"),
481 &statistics_filename),
482
447 GNUNET_GETOPT_OPTION_END 483 GNUNET_GETOPT_OPTION_END
448 }; 484 };
449 GNUNET_PROGRAM_run2 (argc, argv, "gnunet-set-profiler", 485 GNUNET_PROGRAM_run2 (argc, argv, "gnunet-set-profiler",
diff --git a/src/set/set_api.c b/src/set/set_api.c
index 5b5b1b8ee..f5c43a9a7 100644
--- a/src/set/set_api.c
+++ b/src/set/set_api.c
@@ -76,6 +76,8 @@ struct GNUNET_SET_Handle
76 76
77 /** 77 /**
78 * Should the set be destroyed once all operations are gone? 78 * Should the set be destroyed once all operations are gone?
79 * #GNUNET_SYSERR if #GNUNET_SET_destroy() must raise this flag,
80 * #GNUNET_YES if #GNUNET_SET_destroy() did raise this flag.
79 */ 81 */
80 int destroy_requested; 82 int destroy_requested;
81 83
@@ -308,6 +310,8 @@ handle_iter_element (void *cls,
308 struct GNUNET_MQ_Envelope *ev; 310 struct GNUNET_MQ_Envelope *ev;
309 uint16_t msize; 311 uint16_t msize;
310 312
313 LOG (GNUNET_ERROR_TYPE_DEBUG,
314 "Received element in set iteration\n");
311 msize = ntohs (msg->header.size); 315 msize = ntohs (msg->header.size);
312 if (set->iteration_id != ntohs (msg->iteration_id)) 316 if (set->iteration_id != ntohs (msg->iteration_id))
313 { 317 {
@@ -344,11 +348,24 @@ handle_iter_done (void *cls,
344 GNUNET_SET_ElementIterator iter = set->iterator; 348 GNUNET_SET_ElementIterator iter = set->iterator;
345 349
346 if (NULL == iter) 350 if (NULL == iter)
351 {
352 /* FIXME: if this is true, could cancel+start a fresh one
353 cause elements to go to the wrong iteration? */
354 LOG (GNUNET_ERROR_TYPE_INFO,
355 "Service completed set iteration that was already cancelled\n");
347 return; 356 return;
357 }
358 LOG (GNUNET_ERROR_TYPE_DEBUG,
359 "Set iteration completed\n");
360 set->destroy_requested = GNUNET_SYSERR;
348 set->iterator = NULL; 361 set->iterator = NULL;
349 set->iteration_id++; 362 set->iteration_id++;
350 iter (set->iterator_cls, 363 iter (set->iterator_cls,
351 NULL); 364 NULL);
365 if (GNUNET_SYSERR == set->destroy_requested)
366 set->destroy_requested = GNUNET_NO;
367 if (GNUNET_YES == set->destroy_requested)
368 GNUNET_SET_destroy (set);
352} 369}
353 370
354 371
@@ -385,7 +402,7 @@ handle_result (void *cls,
385 int destroy_set; 402 int destroy_set;
386 403
387 GNUNET_assert (NULL != set->mq); 404 GNUNET_assert (NULL != set->mq);
388 result_status = ntohs (msg->result_status); 405 result_status = (enum GNUNET_SET_Status) ntohs (msg->result_status);
389 LOG (GNUNET_ERROR_TYPE_DEBUG, 406 LOG (GNUNET_ERROR_TYPE_DEBUG,
390 "Got result message with status %d\n", 407 "Got result message with status %d\n",
391 result_status); 408 result_status);
@@ -500,6 +517,8 @@ GNUNET_SET_operation_cancel (struct GNUNET_SET_OperationHandle *oh)
500 struct GNUNET_SET_CancelMessage *m; 517 struct GNUNET_SET_CancelMessage *m;
501 struct GNUNET_MQ_Envelope *mqm; 518 struct GNUNET_MQ_Envelope *mqm;
502 519
520 LOG (GNUNET_ERROR_TYPE_DEBUG,
521 "Cancelling SET operation\n");
503 if (NULL != set) 522 if (NULL != set)
504 { 523 {
505 mqm = GNUNET_MQ_msg (m, GNUNET_MESSAGE_TYPE_SET_CANCEL); 524 mqm = GNUNET_MQ_msg (m, GNUNET_MESSAGE_TYPE_SET_CANCEL);
@@ -553,6 +572,9 @@ handle_client_set_error (void *cls,
553} 572}
554 573
555 574
575/**
576 * FIXME.
577 */
556static struct GNUNET_SET_Handle * 578static struct GNUNET_SET_Handle *
557create_internal (const struct GNUNET_CONFIGURATION_Handle *cfg, 579create_internal (const struct GNUNET_CONFIGURATION_Handle *cfg,
558 enum GNUNET_SET_OperationType op, 580 enum GNUNET_SET_OperationType op,
@@ -611,7 +633,8 @@ create_internal (const struct GNUNET_CONFIGURATION_Handle *cfg,
611 GNUNET_MESSAGE_TYPE_SET_COPY_LAZY_CONNECT); 633 GNUNET_MESSAGE_TYPE_SET_COPY_LAZY_CONNECT);
612 copy_msg->cookie = *cookie; 634 copy_msg->cookie = *cookie;
613 } 635 }
614 GNUNET_MQ_send (set->mq, mqm); 636 GNUNET_MQ_send (set->mq,
637 mqm);
615 return set; 638 return set;
616} 639}
617 640
@@ -631,7 +654,16 @@ struct GNUNET_SET_Handle *
631GNUNET_SET_create (const struct GNUNET_CONFIGURATION_Handle *cfg, 654GNUNET_SET_create (const struct GNUNET_CONFIGURATION_Handle *cfg,
632 enum GNUNET_SET_OperationType op) 655 enum GNUNET_SET_OperationType op)
633{ 656{
634 return create_internal (cfg, op, NULL); 657 struct GNUNET_SET_Handle *set;
658
659 set = create_internal (cfg,
660 op,
661 NULL);
662 LOG (GNUNET_ERROR_TYPE_DEBUG,
663 "Creating set %p for operation %d\n",
664 set,
665 op);
666 return set;
635} 667}
636 668
637 669
@@ -657,8 +689,10 @@ GNUNET_SET_add_element (struct GNUNET_SET_Handle *set,
657 struct GNUNET_MQ_Envelope *mqm; 689 struct GNUNET_MQ_Envelope *mqm;
658 struct GNUNET_SET_ElementMessage *msg; 690 struct GNUNET_SET_ElementMessage *msg;
659 691
660 LOG (GNUNET_ERROR_TYPE_INFO, "adding element of type %u\n", (unsigned) element->element_type); 692 LOG (GNUNET_ERROR_TYPE_INFO,
661 693 "adding element of type %u to set %p\n",
694 (unsigned int) element->element_type,
695 set);
662 if (GNUNET_YES == set->invalid) 696 if (GNUNET_YES == set->invalid)
663 { 697 {
664 if (NULL != cont) 698 if (NULL != cont)
@@ -701,6 +735,9 @@ GNUNET_SET_remove_element (struct GNUNET_SET_Handle *set,
701 struct GNUNET_MQ_Envelope *mqm; 735 struct GNUNET_MQ_Envelope *mqm;
702 struct GNUNET_SET_ElementMessage *msg; 736 struct GNUNET_SET_ElementMessage *msg;
703 737
738 LOG (GNUNET_ERROR_TYPE_DEBUG,
739 "Removing element from set %p\n",
740 set);
704 if (GNUNET_YES == set->invalid) 741 if (GNUNET_YES == set->invalid)
705 { 742 {
706 if (NULL != cont) 743 if (NULL != cont)
@@ -733,8 +770,9 @@ GNUNET_SET_destroy (struct GNUNET_SET_Handle *set)
733 /* destroying set while iterator is active is currently 770 /* destroying set while iterator is active is currently
734 not supported; we should expand the API to allow 771 not supported; we should expand the API to allow
735 clients to explicitly cancel the iteration! */ 772 clients to explicitly cancel the iteration! */
736 GNUNET_assert (NULL == set->iterator); 773 if ( (NULL != set->ops_head) ||
737 if (NULL != set->ops_head) 774 (NULL != set->iterator) ||
775 (GNUNET_SYSERR == set->destroy_requested) )
738 { 776 {
739 LOG (GNUNET_ERROR_TYPE_DEBUG, 777 LOG (GNUNET_ERROR_TYPE_DEBUG,
740 "Set operations are pending, delaying set destruction\n"); 778 "Set operations are pending, delaying set destruction\n");
@@ -807,7 +845,7 @@ GNUNET_SET_prepare (const struct GNUNET_PeerIdentity *other_peer,
807 msg->force_delta = GNUNET_YES; 845 msg->force_delta = GNUNET_YES;
808 break; 846 break;
809 default: 847 default:
810 LOG (GNUNET_ERROR_TYPE_ERROR, 848 LOG (GNUNET_ERROR_TYPE_ERROR,
811 "Option with type %d not recognized\n", (int) opt->type); 849 "Option with type %d not recognized\n", (int) opt->type);
812 } 850 }
813 } 851 }
@@ -870,7 +908,8 @@ handle_request (void *cls,
870 struct GNUNET_SET_RejectMessage *rmsg; 908 struct GNUNET_SET_RejectMessage *rmsg;
871 909
872 LOG (GNUNET_ERROR_TYPE_DEBUG, 910 LOG (GNUNET_ERROR_TYPE_DEBUG,
873 "Processing incoming operation request\n"); 911 "Processing incoming operation request with id %u\n",
912 ntohl (msg->accept_id));
874 /* we got another valid request => reset the backoff */ 913 /* we got another valid request => reset the backoff */
875 lh->reconnect_backoff = GNUNET_TIME_UNIT_MILLISECONDS; 914 lh->reconnect_backoff = GNUNET_TIME_UNIT_MILLISECONDS;
876 req.accept_id = ntohl (msg->accept_id); 915 req.accept_id = ntohl (msg->accept_id);
@@ -884,7 +923,8 @@ handle_request (void *cls,
884 if (GNUNET_YES == req.accepted) 923 if (GNUNET_YES == req.accepted)
885 return; /* the accept-case is handled in #GNUNET_SET_accept() */ 924 return; /* the accept-case is handled in #GNUNET_SET_accept() */
886 LOG (GNUNET_ERROR_TYPE_DEBUG, 925 LOG (GNUNET_ERROR_TYPE_DEBUG,
887 "Rejecting request\n"); 926 "Rejected request %u\n",
927 ntohl (msg->accept_id));
888 mqm = GNUNET_MQ_msg (rmsg, 928 mqm = GNUNET_MQ_msg (rmsg,
889 GNUNET_MESSAGE_TYPE_SET_REJECT); 929 GNUNET_MESSAGE_TYPE_SET_REJECT);
890 rmsg->accept_reject_id = msg->accept_id; 930 rmsg->accept_reject_id = msg->accept_id;
@@ -974,6 +1014,9 @@ GNUNET_SET_listen (const struct GNUNET_CONFIGURATION_Handle *cfg,
974{ 1014{
975 struct GNUNET_SET_ListenHandle *lh; 1015 struct GNUNET_SET_ListenHandle *lh;
976 1016
1017 LOG (GNUNET_ERROR_TYPE_DEBUG,
1018 "Starting listener for app %s\n",
1019 GNUNET_h2s (app_id));
977 lh = GNUNET_new (struct GNUNET_SET_ListenHandle); 1020 lh = GNUNET_new (struct GNUNET_SET_ListenHandle);
978 lh->listen_cb = listen_cb; 1021 lh->listen_cb = listen_cb;
979 lh->listen_cls = listen_cls; 1022 lh->listen_cls = listen_cls;
@@ -1000,7 +1043,8 @@ void
1000GNUNET_SET_listen_cancel (struct GNUNET_SET_ListenHandle *lh) 1043GNUNET_SET_listen_cancel (struct GNUNET_SET_ListenHandle *lh)
1001{ 1044{
1002 LOG (GNUNET_ERROR_TYPE_DEBUG, 1045 LOG (GNUNET_ERROR_TYPE_DEBUG,
1003 "Canceling listener\n"); 1046 "Canceling listener %s\n",
1047 GNUNET_h2s (&lh->app_id));
1004 if (NULL != lh->mq) 1048 if (NULL != lh->mq)
1005 { 1049 {
1006 GNUNET_MQ_destroy (lh->mq); 1050 GNUNET_MQ_destroy (lh->mq);
@@ -1042,10 +1086,12 @@ GNUNET_SET_accept (struct GNUNET_SET_Request *request,
1042 1086
1043 GNUNET_assert (GNUNET_NO == request->accepted); 1087 GNUNET_assert (GNUNET_NO == request->accepted);
1044 LOG (GNUNET_ERROR_TYPE_DEBUG, 1088 LOG (GNUNET_ERROR_TYPE_DEBUG,
1045 "Client accepts set operation (%d)\n", 1089 "Client accepts set operation (%d) with id %u\n",
1046 result_mode); 1090 result_mode,
1091 request->accept_id);
1047 request->accepted = GNUNET_YES; 1092 request->accepted = GNUNET_YES;
1048 mqm = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SET_ACCEPT); 1093 mqm = GNUNET_MQ_msg (msg,
1094 GNUNET_MESSAGE_TYPE_SET_ACCEPT);
1049 msg->accept_reject_id = htonl (request->accept_id); 1095 msg->accept_reject_id = htonl (request->accept_id);
1050 msg->result_mode = htonl (result_mode); 1096 msg->result_mode = htonl (result_mode);
1051 oh = GNUNET_new (struct GNUNET_SET_OperationHandle); 1097 oh = GNUNET_new (struct GNUNET_SET_OperationHandle);
@@ -1143,6 +1189,8 @@ GNUNET_SET_copy_lazy (struct GNUNET_SET_Handle *set,
1143 struct GNUNET_MQ_Envelope *ev; 1189 struct GNUNET_MQ_Envelope *ev;
1144 struct SetCopyRequest *req; 1190 struct SetCopyRequest *req;
1145 1191
1192 LOG (GNUNET_ERROR_TYPE_DEBUG,
1193 "Creating lazy copy of set\n");
1146 ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_COPY_LAZY_PREPARE); 1194 ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_COPY_LAZY_PREPARE);
1147 GNUNET_MQ_send (set->mq, ev); 1195 GNUNET_MQ_send (set->mq, ev);
1148 1196
diff --git a/src/set/test_set_api.c b/src/set/test_set_api.c
index dd3f004f2..ca7d8a4e2 100644
--- a/src/set/test_set_api.c
+++ b/src/set/test_set_api.c
@@ -116,6 +116,7 @@ result_cb_set2 (void *cls,
116 oh2 = NULL; 116 oh2 = NULL;
117 fprintf (stderr, 117 fprintf (stderr,
118 "set 2: received failure status\n"); 118 "set 2: received failure status\n");
119 GNUNET_SCHEDULER_shutdown ();
119 ret = 1; 120 ret = 1;
120 break; 121 break;
121 case GNUNET_SET_STATUS_DONE: 122 case GNUNET_SET_STATUS_DONE:
@@ -147,8 +148,6 @@ listen_cb (void *cls,
147 GNUNET_assert (ntohs (context_msg->type) == GNUNET_MESSAGE_TYPE_DUMMY); 148 GNUNET_assert (ntohs (context_msg->type) == GNUNET_MESSAGE_TYPE_DUMMY);
148 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 149 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
149 "listen cb called\n"); 150 "listen cb called\n");
150 GNUNET_SET_listen_cancel (listen_handle);
151 listen_handle = NULL;
152 oh2 = GNUNET_SET_accept (request, 151 oh2 = GNUNET_SET_accept (request,
153 GNUNET_SET_RESULT_ADDED, 152 GNUNET_SET_RESULT_ADDED,
154 (struct GNUNET_SET_Option[]) { 0 }, 153 (struct GNUNET_SET_Option[]) { 0 },
@@ -200,19 +199,25 @@ init_set2 (void *cls)
200{ 199{
201 struct GNUNET_SET_Element element; 200 struct GNUNET_SET_Element element;
202 201
203 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "initializing set 2\n"); 202 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
203 "initializing set 2\n");
204 204
205 element.element_type = 0; 205 element.element_type = 0;
206
207 element.data = "hello"; 206 element.data = "hello";
208 element.size = strlen(element.data); 207 element.size = strlen(element.data);
209 GNUNET_SET_add_element (set2, &element, NULL, NULL); 208 GNUNET_SET_add_element (set2,
209 &element,
210 NULL, NULL);
210 element.data = "quux"; 211 element.data = "quux";
211 element.size = strlen(element.data); 212 element.size = strlen(element.data);
212 GNUNET_SET_add_element (set2, &element, NULL, NULL); 213 GNUNET_SET_add_element (set2,
214 &element,
215 NULL, NULL);
213 element.data = "baz"; 216 element.data = "baz";
214 element.size = strlen(element.data); 217 element.size = strlen(element.data);
215 GNUNET_SET_add_element (set2, &element, &start, NULL); 218 GNUNET_SET_add_element (set2,
219 &element,
220 &start, NULL);
216} 221}
217 222
218 223
@@ -225,14 +230,17 @@ init_set1 (void)
225 struct GNUNET_SET_Element element; 230 struct GNUNET_SET_Element element;
226 231
227 element.element_type = 0; 232 element.element_type = 0;
228
229 element.data = "hello"; 233 element.data = "hello";
230 element.size = strlen(element.data); 234 element.size = strlen(element.data);
231 GNUNET_SET_add_element (set1, &element, NULL, NULL); 235 GNUNET_SET_add_element (set1,
236 &element,
237 NULL, NULL);
232 element.data = "bar"; 238 element.data = "bar";
233 element.size = strlen(element.data); 239 element.size = strlen(element.data);
234 GNUNET_SET_add_element (set1, &element, init_set2, NULL); 240 GNUNET_SET_add_element (set1,
235 241 &element,
242 &init_set2,
243 NULL);
236 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 244 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
237 "initialized set 1\n"); 245 "initialized set 1\n");
238} 246}
@@ -242,10 +250,15 @@ static int
242iter_cb (void *cls, 250iter_cb (void *cls,
243 const struct GNUNET_SET_Element *element) 251 const struct GNUNET_SET_Element *element)
244{ 252{
253 struct GNUNET_SET_Handle *set = cls;
254
245 if (NULL == element) 255 if (NULL == element)
246 { 256 {
247 GNUNET_assert (3 == iter_count); 257 GNUNET_assert (3 == iter_count);
248 GNUNET_SET_destroy (cls); 258 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
259 "Iteration finished, destroying set %p\n",
260 set);
261 GNUNET_SET_destroy (set);
249 return GNUNET_YES; 262 return GNUNET_YES;
250 } 263 }
251 iter_count++; 264 iter_count++;
@@ -262,21 +275,31 @@ test_iter ()
262 struct GNUNET_SET_Element element; 275 struct GNUNET_SET_Element element;
263 struct GNUNET_SET_Handle *iter_set; 276 struct GNUNET_SET_Handle *iter_set;
264 277
265 iter_set = GNUNET_SET_create (config, GNUNET_SET_OPERATION_UNION); 278 iter_set = GNUNET_SET_create (config,
266 279 GNUNET_SET_OPERATION_UNION);
280 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
281 "Testing iteration over 3 elements on set %p\n",
282 iter_set);
267 element.element_type = 0; 283 element.element_type = 0;
268 284
269 element.data = "hello"; 285 element.data = "hello";
270 element.size = strlen(element.data); 286 element.size = strlen(element.data);
271 GNUNET_SET_add_element (iter_set, &element, NULL, NULL); 287 GNUNET_SET_add_element (iter_set,
288 &element,
289 NULL, NULL);
272 element.data = "bar"; 290 element.data = "bar";
273 element.size = strlen(element.data); 291 element.size = strlen(element.data);
274 GNUNET_SET_add_element (iter_set, &element, NULL, NULL); 292 GNUNET_SET_add_element (iter_set,
293 &element,
294 NULL, NULL);
275 element.data = "quux"; 295 element.data = "quux";
276 element.size = strlen(element.data); 296 element.size = strlen(element.data);
277 GNUNET_SET_add_element (iter_set, &element, NULL, NULL); 297 GNUNET_SET_add_element (iter_set,
278 298 &element,
279 GNUNET_SET_iterate (iter_set, iter_cb, iter_set); 299 NULL, NULL);
300 GNUNET_SET_iterate (iter_set,
301 &iter_cb,
302 iter_set);
280} 303}
281 304
282 305
@@ -372,12 +395,20 @@ run (void *cls,
372 GNUNET_i2s (&local_id)); 395 GNUNET_i2s (&local_id));
373 test_iter (); 396 test_iter ();
374 397
375 set1 = GNUNET_SET_create (cfg, GNUNET_SET_OPERATION_UNION); 398 set1 = GNUNET_SET_create (cfg,
376 set2 = GNUNET_SET_create (cfg, GNUNET_SET_OPERATION_UNION); 399 GNUNET_SET_OPERATION_UNION);
400 set2 = GNUNET_SET_create (cfg,
401 GNUNET_SET_OPERATION_UNION);
402 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
403 "Created sets %p and %p for union operation\n",
404 set1,
405 set2);
377 GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, 406 GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK,
378 &app_id); 407 &app_id);
379 408
380 ///* test if canceling an uncommited request works! */ 409 /* test if canceling an uncommited request works! */
410 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
411 "Launching and instantly stopping set operation\n");
381 my_oh = GNUNET_SET_prepare (&local_id, 412 my_oh = GNUNET_SET_prepare (&local_id,
382 &app_id, 413 &app_id,
383 NULL, 414 NULL,
@@ -385,7 +416,6 @@ run (void *cls,
385 (struct GNUNET_SET_Option[]) { 0 }, 416 (struct GNUNET_SET_Option[]) { 0 },
386 NULL, 417 NULL,
387 NULL); 418 NULL);
388
389 GNUNET_SET_operation_cancel (my_oh); 419 GNUNET_SET_operation_cancel (my_oh);
390 420
391 /* test the real set reconciliation */ 421 /* test the real set reconciliation */
diff --git a/src/set/test_set_union_copy.c b/src/set/test_set_union_copy.c
index c887a8958..242b9f2f2 100644
--- a/src/set/test_set_union_copy.c
+++ b/src/set/test_set_union_copy.c
@@ -122,6 +122,7 @@ check_count_iter (void *cls,
122 return GNUNET_NO; 122 return GNUNET_NO;
123 } 123 }
124 ci_cls->cont (ci_cls->cont_cls); 124 ci_cls->cont (ci_cls->cont_cls);
125 GNUNET_free (ci_cls);
125 return GNUNET_NO; 126 return GNUNET_NO;
126 } 127 }
127 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 128 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -264,7 +265,8 @@ run (void *cls,
264 GNUNET_TESTING_peer_get_identity (peer, 265 GNUNET_TESTING_peer_get_identity (peer,
265 &local_id); 266 &local_id);
266 267
267 set1 = GNUNET_SET_create (cfg, GNUNET_SET_OPERATION_UNION); 268 set1 = GNUNET_SET_create (cfg,
269 GNUNET_SET_OPERATION_UNION);
268 add_element_str (set1, 270 add_element_str (set1,
269 "333"); 271 "333");
270 add_element_str (set1, 272 add_element_str (set1,
diff --git a/src/social/.gitignore b/src/social/.gitignore
index 41954615f..875aa1105 100644
--- a/src/social/.gitignore
+++ b/src/social/.gitignore
@@ -1,2 +1,3 @@
1gnunet-social 1gnunet-social
2gnunet-service-social 2gnunet-service-social
3test_social
diff --git a/src/social/gnunet-social.c b/src/social/gnunet-social.c
index 1da51243e..4a46fdc99 100644
--- a/src/social/gnunet-social.c
+++ b/src/social/gnunet-social.c
@@ -67,10 +67,10 @@ static int op_guest_leave;
67static int op_guest_talk; 67static int op_guest_talk;
68 68
69/** --replay */ 69/** --replay */
70static char *op_replay; 70static int op_replay;
71 71
72/** --replay-latest */ 72/** --replay-latest */
73static char *op_replay_latest; 73static int op_replay_latest;
74 74
75/** --look-at */ 75/** --look-at */
76static int op_look_at; 76static int op_look_at;
@@ -116,13 +116,13 @@ static char *opt_data;
116static char *opt_name; 116static char *opt_name;
117 117
118/** --start */ 118/** --start */
119static uint64_t opt_start; 119static unsigned long long opt_start;
120 120
121/** --until */ 121/** --until */
122static uint64_t opt_until; 122static unsigned long long opt_until;
123 123
124/** --limit */ 124/** --limit */
125static int opt_limit; 125static unsigned long long opt_limit;
126 126
127 127
128/* global vars */ 128/* global vars */
@@ -563,7 +563,7 @@ slicer_recv_method (void *cls,
563 "%s (flags: %x)\n", 563 "%s (flags: %x)\n",
564 message_id, method_name, ntohl (meth->flags)); 564 message_id, method_name, ntohl (meth->flags));
565 /* routing header is missing, so we just print double newline */ 565 /* routing header is missing, so we just print double newline */
566 printf(".\n\n"); 566 printf("\n");
567 /* we output . instead of | to indicate that this is not proper PSYC syntax */ 567 /* we output . instead of | to indicate that this is not proper PSYC syntax */
568 /* FIXME: use libpsyc here */ 568 /* FIXME: use libpsyc here */
569} 569}
@@ -588,10 +588,11 @@ slicer_recv_modifier (void *cls,
588 "Received modifier for message ID %" PRIu64 ":\n" 588 "Received modifier for message ID %" PRIu64 ":\n"
589 "%c%s: %.*s (size: %u)\n", 589 "%c%s: %.*s (size: %u)\n",
590 message_id, oper, name, value_size, (const char *) value, value_size); 590 message_id, oper, name, value_size, (const char *) value, value_size);
591#endif 591#else
592 /* obviously not binary safe */ 592 /* obviously not binary safe */
593 printf("%c%s\t%.*s\n", 593 printf("%c%s\t%.*s\n",
594 oper, name, value_size, (const char *) value); 594 oper, name, value_size, (const char *) value);
595#endif
595} 596}
596 597
597 598
@@ -611,10 +612,11 @@ slicer_recv_data (void *cls,
611 "Received data for message ID %" PRIu64 ":\n" 612 "Received data for message ID %" PRIu64 ":\n"
612 "%.*s\n", 613 "%.*s\n",
613 message_id, data_size, (const char *) data); 614 message_id, data_size, (const char *) data);
614#endif 615#else
615 /* obviously not binary safe */ 616 /* obviously not binary safe */
616 printf("%s\n%.*s\n", 617 printf("%s\n%.*s\n",
617 method_received, data_size, (const char *) data); 618 method_received, data_size, (const char *) data);
619#endif
618} 620}
619 621
620 622
@@ -1016,6 +1018,7 @@ app_connected (void *cls)
1016 guest_enter (&place_pub_key, &peer); 1018 guest_enter (&place_pub_key, &peer);
1017 } 1019 }
1018 } 1020 }
1021 printf(".\n");
1019} 1022}
1020 1023
1021 1024
@@ -1161,6 +1164,7 @@ run (void *cls, char *const *args, const char *cfgfile,
1161 { 1164 {
1162 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1165 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1163 _("--place missing or invalid.\n")); 1166 _("--place missing or invalid.\n"));
1167 /* FIXME: why does it segfault here? */
1164 exit_fail (); 1168 exit_fail ();
1165 return; 1169 return;
1166 } 1170 }
@@ -1195,7 +1199,7 @@ int
1195main (int argc, char *const *argv) 1199main (int argc, char *const *argv)
1196{ 1200{
1197 int res; 1201 int res;
1198 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 1202 struct GNUNET_GETOPT_CommandLineOption options[] = {
1199 /* 1203 /*
1200 * gnunet program options in addition to the ones below: 1204 * gnunet program options in addition to the ones below:
1201 * 1205 *
@@ -1208,120 +1212,165 @@ main (int argc, char *const *argv)
1208 1212
1209 /* operations */ 1213 /* operations */
1210 1214
1211 { 'A', "host-assign", NULL, 1215 GNUNET_GETOPT_OPTION_SET_ONE ('A',
1212 gettext_noop ("assign --name in state to --data"), 1216 "host-assign",
1213 GNUNET_NO, &GNUNET_GETOPT_set_one, &op_host_assign }, 1217 gettext_noop ("assign --name in state to --data"),
1214 1218 &op_host_assign),
1215 { 'B', "guest-leave", NULL, 1219
1216 gettext_noop ("say good-bye and leave somebody else's place"), 1220 GNUNET_GETOPT_OPTION_SET_ONE ('B',
1217 GNUNET_NO, &GNUNET_GETOPT_set_one, &op_guest_leave }, 1221 "guest-leave",
1218 1222 gettext_noop ("say good-bye and leave somebody else's place"),
1219 { 'C', "host-enter", NULL, 1223 &op_guest_leave),
1220 gettext_noop ("create a place"), 1224
1221 GNUNET_NO, &GNUNET_GETOPT_set_one, &op_host_enter }, 1225 GNUNET_GETOPT_OPTION_SET_ONE ('C',
1222 1226 "host-enter",
1223 { 'D', "host-leave", NULL, 1227 gettext_noop ("create a place"),
1224 gettext_noop ("destroy a place we were hosting"), 1228 &op_host_enter),
1225 GNUNET_NO, &GNUNET_GETOPT_set_one, &op_host_leave }, 1229
1226 1230 GNUNET_GETOPT_OPTION_SET_ONE ('C',
1227 { 'E', "guest-enter", NULL, 1231 "host-enter",
1228 gettext_noop ("enter somebody else's place"), 1232 gettext_noop ("create a place"),
1229 GNUNET_NO, &GNUNET_GETOPT_set_one, &op_guest_enter }, 1233 &op_host_enter),
1230 1234
1231 { 'F', "look-for", NULL, 1235 GNUNET_GETOPT_OPTION_SET_ONE ('D',
1232 gettext_noop ("find state matching name prefix"), 1236 "host-leave",
1233 GNUNET_NO, &GNUNET_GETOPT_set_one, &op_look_for }, 1237 gettext_noop ("destroy a place we were hosting"),
1234 1238 &op_host_leave),
1235 { 'H', "replay-latest", NULL, 1239
1236 gettext_noop ("replay history of messages up to the given --limit"), 1240 GNUNET_GETOPT_OPTION_SET_ONE ('E',
1237 GNUNET_NO, &GNUNET_GETOPT_set_one, &op_replay_latest }, 1241 "guest-enter",
1238 1242 gettext_noop ("enter somebody else's place"),
1239 { 'N', "host-reconnect", NULL, 1243 &op_guest_enter),
1240 gettext_noop ("reconnect to a previously created place"), 1244
1241 GNUNET_NO, &GNUNET_GETOPT_set_one, &op_host_reconnect }, 1245
1242 1246 GNUNET_GETOPT_OPTION_SET_ONE ('F',
1243 { 'P', "host-announce", NULL, 1247 "look-for",
1244 gettext_noop ("publish something to a place we are hosting"), 1248 gettext_noop ("find state matching name prefix"),
1245 GNUNET_NO, &GNUNET_GETOPT_set_one, &op_host_announce }, 1249 &op_look_for),
1246 1250
1247 { 'R', "guest-reconnect", NULL, 1251 GNUNET_GETOPT_OPTION_SET_ONE ('H',
1248 gettext_noop ("reconnect to a previously entered place"), 1252 "replay-latest",
1249 GNUNET_NO, &GNUNET_GETOPT_set_one, &op_guest_reconnect }, 1253 gettext_noop ("replay history of messages up to the given --limit"),
1250 1254 &op_replay_latest),
1251 { 'S', "look-at", NULL, 1255
1252 gettext_noop ("search for state matching exact name"), 1256 GNUNET_GETOPT_OPTION_SET_ONE ('N',
1253 GNUNET_NO, &GNUNET_GETOPT_set_one, &op_look_at }, 1257 "host-reconnect",
1254 1258 gettext_noop ("reconnect to a previously created place"),
1255 { 'T', "guest-talk", NULL, 1259 &op_host_reconnect),
1256 gettext_noop ("submit something to somebody's place"), 1260
1257 GNUNET_NO, &GNUNET_GETOPT_set_one, &op_guest_talk }, 1261 GNUNET_GETOPT_OPTION_SET_ONE ('P',
1258 1262 "host-announce",
1259 { 'U', "status", NULL, 1263 gettext_noop ("publish something to a place we are hosting"),
1260 gettext_noop ("list of egos and subscribed places"), 1264 &op_host_announce),
1261 GNUNET_NO, &GNUNET_GETOPT_set_one, &op_status }, 1265
1262 1266 GNUNET_GETOPT_OPTION_SET_ONE ('R',
1263 { 'X', "replay", NULL, 1267 "guest-reconnect",
1264 gettext_noop ("extract and replay history between message IDs --start and --until"), 1268 gettext_noop ("reconnect to a previously entered place"),
1265 GNUNET_NO, &GNUNET_GETOPT_set_one, &op_replay }, 1269 &op_guest_reconnect),
1270
1271 GNUNET_GETOPT_OPTION_SET_ONE ('S',
1272 "look-at",
1273 gettext_noop ("search for state matching exact name"),
1274 &op_look_at),
1275
1276 GNUNET_GETOPT_OPTION_SET_ONE ('T',
1277 "guest-talk",
1278 gettext_noop ("submit something to somebody's place"),
1279 &op_guest_talk),
1280
1281 GNUNET_GETOPT_OPTION_SET_ONE ('U',
1282 "status",
1283 gettext_noop ("list of egos and subscribed places"),
1284 &op_status),
1285
1286 GNUNET_GETOPT_OPTION_SET_ONE ('X',
1287 "replay",
1288 gettext_noop ("extract and replay history between message IDs --start and --until"),
1289 &op_replay),
1266 1290
1267 1291
1268 /* options */ 1292 /* options */
1269 1293
1270 { 'a', "app", "APPLICATION_ID", 1294 GNUNET_GETOPT_OPTION_STRING ('a',
1271 gettext_noop ("application ID to use when connecting"), 1295 "app",
1272 GNUNET_YES, &GNUNET_GETOPT_set_string, &opt_app }, 1296 "APPLICATION_ID",
1273 1297 gettext_noop ("application ID to use when connecting"),
1274 { 'd', "data", "DATA", 1298 &opt_app),
1275 gettext_noop ("message body or state value"), 1299
1276 GNUNET_YES, &GNUNET_GETOPT_set_string, &opt_data }, 1300 GNUNET_GETOPT_OPTION_STRING ('d',
1277 1301 "data",
1278 { 'e', "ego", "NAME|PUBKEY", 1302 "DATA",
1279 gettext_noop ("name or public key of ego"), 1303 gettext_noop ("message body or state value"),
1280 GNUNET_YES, &GNUNET_GETOPT_set_string, &opt_ego }, 1304 &opt_data),
1281 1305
1282 { 'f', "follow", NULL, 1306 GNUNET_GETOPT_OPTION_STRING ('e',
1283 gettext_noop ("wait for incoming messages"), 1307 "ego",
1284 GNUNET_NO, &GNUNET_GETOPT_set_one, &opt_follow }, 1308 "NAME|PUBKEY",
1285 1309 gettext_noop ("name or public key of ego"),
1286 { 'g', "gns", "GNS_NAME", 1310 &opt_ego),
1287 gettext_noop ("GNS name"), 1311
1288 GNUNET_YES, &GNUNET_GETOPT_set_string, &opt_gns }, 1312 GNUNET_GETOPT_OPTION_SET_ONE ('f',
1289 1313 "follow",
1290 { 'i', "peer", "PEER_ID", 1314 gettext_noop ("wait for incoming messages"),
1291 gettext_noop ("peer ID for --guest-enter"), 1315 &opt_follow),
1292 GNUNET_YES, &GNUNET_GETOPT_set_string, &opt_peer }, 1316
1293 1317 GNUNET_GETOPT_OPTION_STRING ('g',
1294 { 'k', "name", "VAR_NAME", 1318 "gns",
1295 gettext_noop ("name (key) to query from state"), 1319 "GNS_NAME",
1296 GNUNET_YES, &GNUNET_GETOPT_set_string, &opt_name }, 1320 gettext_noop ("GNS name"),
1297 1321 &opt_gns),
1298 { 'm', "method", "METHOD_NAME", 1322
1299 gettext_noop ("method name"), 1323 GNUNET_GETOPT_OPTION_STRING ('i',
1300 GNUNET_YES, &GNUNET_GETOPT_set_string, &opt_method }, 1324 "peer",
1301 1325 "PEER_ID",
1302 { 'n', "limit", NULL, 1326 gettext_noop ("peer ID for --guest-enter"),
1303 gettext_noop ("number of messages to replay from history"), 1327 &opt_peer),
1304 GNUNET_YES, &GNUNET_GETOPT_set_ulong, &opt_limit }, 1328
1305 1329 GNUNET_GETOPT_OPTION_STRING ('k',
1306 { 'p', "place", "PUBKEY", 1330 "name",
1307 gettext_noop ("key address of place"), 1331 "VAR_NAME",
1308 GNUNET_YES, &GNUNET_GETOPT_set_string, &opt_place }, 1332 gettext_noop ("name (key) to query from state"),
1309 1333 &opt_name),
1310 { 's', "start", NULL, 1334
1311 gettext_noop ("start message ID for history replay"), 1335 GNUNET_GETOPT_OPTION_STRING ('m',
1312 GNUNET_YES, &GNUNET_GETOPT_set_ulong, &opt_start }, 1336 "method",
1313 1337 "METHOD_NAME",
1314 { 'w', "welcome", NULL, 1338 gettext_noop ("method name"),
1315 gettext_noop ("respond to entry requests by admitting all guests"), 1339 &opt_method),
1316 GNUNET_NO, &GNUNET_GETOPT_set_one, &opt_welcome }, 1340
1317 1341 GNUNET_GETOPT_OPTION_SET_ULONG ('n',
1318 { 'u', "until", NULL, 1342 "limit",
1319 gettext_noop ("end message ID for history replay"), 1343 NULL,
1320 GNUNET_YES, &GNUNET_GETOPT_set_ulong, &opt_until }, 1344 gettext_noop ("number of messages to replay from history"),
1321 1345 &opt_limit),
1322 { 'y', "deny", NULL, 1346
1323 gettext_noop ("respond to entry requests by refusing all guests"), 1347 GNUNET_GETOPT_OPTION_STRING ('p',
1324 GNUNET_NO, &GNUNET_GETOPT_set_one, &opt_deny }, 1348 "place",
1349 "PUBKEY",
1350 gettext_noop ("key address of place"),
1351 &opt_place),
1352
1353 GNUNET_GETOPT_OPTION_SET_ULONG ('s',
1354 "start",
1355 NULL,
1356 gettext_noop ("start message ID for history replay"),
1357 &opt_start),
1358
1359 GNUNET_GETOPT_OPTION_SET_ONE ('w',
1360 "welcome",
1361 gettext_noop ("respond to entry requests by admitting all guests"),
1362 &opt_welcome),
1363
1364 GNUNET_GETOPT_OPTION_SET_ULONG ('u',
1365 "until",
1366 NULL,
1367 gettext_noop ("end message ID for history replay"),
1368 &opt_until),
1369
1370 GNUNET_GETOPT_OPTION_SET_ONE ('y',
1371 "deny",
1372 gettext_noop ("respond to entry requests by refusing all guests"),
1373 &opt_deny),
1325 1374
1326 GNUNET_GETOPT_OPTION_END 1375 GNUNET_GETOPT_OPTION_END
1327 }; 1376 };
@@ -1350,8 +1399,8 @@ main (int argc, char *const *argv)
1350 "gnunet-social --guest-leave --place <PUBKEY>\n" 1399 "gnunet-social --guest-leave --place <PUBKEY>\n"
1351 "gnunet-social --guest-talk --place <PUBKEY> --method <METHOD_NAME> --data <MESSAGE_BODY>\n" 1400 "gnunet-social --guest-talk --place <PUBKEY> --method <METHOD_NAME> --data <MESSAGE_BODY>\n"
1352 "\n" 1401 "\n"
1353 "gnunet-social --history-replay --place <PUBKEY> --start <MSGID> --until <MSGID> [--method <METHOD_PREFIX>]\n" 1402 "gnunet-social --replay --place <PUBKEY> --start <MSGID> --until <MSGID> [--method <METHOD_PREFIX>]\n"
1354 "gnunet-social --history-replay-latest --place <PUBKEY> --limit <MSG_LIMIT> [--method <METHOD_PREFIX>]\n" 1403 "gnunet-social --replay-latest --place <PUBKEY> --limit <MSG_LIMIT> [--method <METHOD_PREFIX>]\n"
1355 "\n" 1404 "\n"
1356 "gnunet-social --look-at --place <PUBKEY> --name <FULL_NAME>\n" 1405 "gnunet-social --look-at --place <PUBKEY> --name <FULL_NAME>\n"
1357 "gnunet-social --look-for --place <PUBKEY> --name <NAME_PREFIX>\n"; 1406 "gnunet-social --look-for --place <PUBKEY> --name <NAME_PREFIX>\n";
diff --git a/src/social/social_api.c b/src/social/social_api.c
index a7fe0916f..af1d6e57e 100644
--- a/src/social/social_api.c
+++ b/src/social/social_api.c
@@ -2110,7 +2110,7 @@ GNUNET_SOCIAL_place_msg_proc_set (struct GNUNET_SOCIAL_Place *plc,
2110 GNUNET_assert (NULL != method_prefix); 2110 GNUNET_assert (NULL != method_prefix);
2111 struct MsgProcRequest *mpreq; 2111 struct MsgProcRequest *mpreq;
2112 uint16_t method_size = strnlen (method_prefix, 2112 uint16_t method_size = strnlen (method_prefix,
2113 GNUNET_SERVER_MAX_MESSAGE_SIZE 2113 GNUNET_MAX_MESSAGE_SIZE
2114 - sizeof (*mpreq)) + 1; 2114 - sizeof (*mpreq)) + 1;
2115 GNUNET_assert ('\0' == method_prefix[method_size - 1]); 2115 GNUNET_assert ('\0' == method_prefix[method_size - 1]);
2116 2116
@@ -2159,7 +2159,7 @@ place_history_replay (struct GNUNET_SOCIAL_Place *plc,
2159 2159
2160 GNUNET_assert (NULL != method_prefix); 2160 GNUNET_assert (NULL != method_prefix);
2161 uint16_t method_size = strnlen (method_prefix, 2161 uint16_t method_size = strnlen (method_prefix,
2162 GNUNET_SERVER_MAX_MESSAGE_SIZE 2162 GNUNET_MAX_MESSAGE_SIZE
2163 - sizeof (*req)) + 1; 2163 - sizeof (*req)) + 1;
2164 GNUNET_assert ('\0' == method_prefix[method_size - 1]); 2164 GNUNET_assert ('\0' == method_prefix[method_size - 1]);
2165 2165
@@ -2285,7 +2285,7 @@ place_state_get (struct GNUNET_SOCIAL_Place *plc,
2285 look->op_id = GNUNET_OP_add (plc->op, &op_recv_state_result, look, NULL); 2285 look->op_id = GNUNET_OP_add (plc->op, &op_recv_state_result, look, NULL);
2286 2286
2287 GNUNET_assert (NULL != name); 2287 GNUNET_assert (NULL != name);
2288 size_t name_size = strnlen (name, GNUNET_SERVER_MAX_MESSAGE_SIZE 2288 size_t name_size = strnlen (name, GNUNET_MAX_MESSAGE_SIZE
2289 - sizeof (*req)) + 1; 2289 - sizeof (*req)) + 1;
2290 struct GNUNET_MQ_Envelope * 2290 struct GNUNET_MQ_Envelope *
2291 env = GNUNET_MQ_msg_extra (req, name_size, type); 2291 env = GNUNET_MQ_msg_extra (req, name_size, type);
@@ -2426,7 +2426,7 @@ GNUNET_SOCIAL_zone_add_place (const struct GNUNET_SOCIAL_App *app,
2426 size_t relay_size = relay_count * sizeof (*relays); 2426 size_t relay_size = relay_count * sizeof (*relays);
2427 size_t payload_size = name_size + password_size + relay_size; 2427 size_t payload_size = name_size + password_size + relay_size;
2428 2428
2429 if (GNUNET_SERVER_MAX_MESSAGE_SIZE < sizeof (*preq) + payload_size) 2429 if (GNUNET_MAX_MESSAGE_SIZE < sizeof (*preq) + payload_size)
2430 return GNUNET_SYSERR; 2430 return GNUNET_SYSERR;
2431 2431
2432 struct GNUNET_MQ_Envelope * 2432 struct GNUNET_MQ_Envelope *
@@ -2506,7 +2506,7 @@ GNUNET_SOCIAL_zone_add_nym (const struct GNUNET_SOCIAL_App *app,
2506 struct ZoneAddNymRequest *nreq; 2506 struct ZoneAddNymRequest *nreq;
2507 2507
2508 size_t name_size = strlen (name) + 1; 2508 size_t name_size = strlen (name) + 1;
2509 if (GNUNET_SERVER_MAX_MESSAGE_SIZE < sizeof (*nreq) + name_size) 2509 if (GNUNET_MAX_MESSAGE_SIZE < sizeof (*nreq) + name_size)
2510 return GNUNET_SYSERR; 2510 return GNUNET_SYSERR;
2511 2511
2512 struct GNUNET_MQ_Envelope * 2512 struct GNUNET_MQ_Envelope *
diff --git a/src/sq/Makefile.am b/src/sq/Makefile.am
index c5f80bcf6..cfccd89f6 100644
--- a/src/sq/Makefile.am
+++ b/src/sq/Makefile.am
@@ -9,7 +9,7 @@ if USE_COVERAGE
9 AM_CFLAGS = --coverage 9 AM_CFLAGS = --coverage
10endif 10endif
11 11
12if HAVE_POSTGRESQL 12if HAVE_SQLITE
13lib_LTLIBRARIES = libgnunetsq.la 13lib_LTLIBRARIES = libgnunetsq.la
14endif 14endif
15 15
diff --git a/src/sq/sq.c b/src/sq/sq.c
index dc4416761..089ebf0ff 100644
--- a/src/sq/sq.c
+++ b/src/sq/sq.c
@@ -49,7 +49,14 @@ GNUNET_SQ_bind (sqlite3_stmt *stmt,
49 "sq", 49 "sq",
50 _("Failure to bind %u-th SQL parameter\n"), 50 _("Failure to bind %u-th SQL parameter\n"),
51 i); 51 i);
52 return GNUNET_SYSERR; 52 if (SQLITE_OK !=
53 sqlite3_reset (stmt))
54 {
55 GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
56 "sq",
57 _("Failure in sqlite3_reset (!)\n"));
58 return GNUNET_SYSERR;
59 }
53 } 60 }
54 GNUNET_assert (0 != params[i].num_params); 61 GNUNET_assert (0 != params[i].num_params);
55 j += params[i].num_params; 62 j += params[i].num_params;
@@ -83,7 +90,12 @@ GNUNET_SQ_extract_result (sqlite3_stmt *result,
83 j, 90 j,
84 rs[i].result_size, 91 rs[i].result_size,
85 rs[i].dst)) 92 rs[i].dst))
93 {
94 for (unsigned int k=0;k<i;k++)
95 if (NULL != rs[k].cleaner)
96 rs[k].cleaner (rs[k].cls);
86 return GNUNET_SYSERR; 97 return GNUNET_SYSERR;
98 }
87 GNUNET_assert (0 != rs[i].num_params); 99 GNUNET_assert (0 != rs[i].num_params);
88 j += rs[i].num_params; 100 j += rs[i].num_params;
89 } 101 }
@@ -105,4 +117,24 @@ GNUNET_SQ_cleanup_result (struct GNUNET_SQ_ResultSpec *rs)
105 rs[i].cleaner (rs[i].cls); 117 rs[i].cleaner (rs[i].cls);
106} 118}
107 119
120
121/**
122 * Reset @a stmt and log error.
123 *
124 * @param dbh database handle
125 * @param stmt statement to reset
126 */
127void
128GNUNET_SQ_reset (sqlite3 *dbh,
129 sqlite3_stmt *stmt)
130{
131 if (SQLITE_OK !=
132 sqlite3_reset (stmt))
133 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
134 "sqlite",
135 _("Failed to reset sqlite statement with error: %s\n"),
136 sqlite3_errmsg (dbh));
137}
138
139
108/* end of sq.c */ 140/* end of sq.c */
diff --git a/src/sq/sq_query_helper.c b/src/sq/sq_query_helper.c
index 5529c5e6c..94a3a3f1c 100644
--- a/src/sq/sq_query_helper.c
+++ b/src/sq/sq_query_helper.c
@@ -90,6 +90,14 @@ bind_string (void *cls,
90 sqlite3_stmt *stmt, 90 sqlite3_stmt *stmt,
91 unsigned int off) 91 unsigned int off)
92{ 92{
93 if (NULL == data)
94 {
95 if (SQLITE_OK !=
96 sqlite3_bind_null (stmt,
97 (int) off))
98 return GNUNET_SYSERR;
99 return GNUNET_OK;
100 }
93 if (SQLITE_OK != 101 if (SQLITE_OK !=
94 sqlite3_bind_text (stmt, 102 sqlite3_bind_text (stmt,
95 (int) off, 103 (int) off,
@@ -235,6 +243,40 @@ GNUNET_SQ_query_param_rsa_signature (const struct GNUNET_CRYPTO_RsaSignature *x)
235 243
236 244
237/** 245/**
246 * Function called to convert input argument into SQL parameters.
247 *
248 * @param cls closure
249 * @param data pointer to input argument
250 * @param data_len number of bytes in @a data (if applicable)
251 * @param stmt sqlite statement to bind parameters for
252 * @param off offset of the argument to bind in @a stmt, numbered from 1,
253 * so immediately suitable for passing to `sqlite3_bind`-functions.
254 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
255 */
256static int
257bind_abstime (void *cls,
258 const void *data,
259 size_t data_len,
260 sqlite3_stmt *stmt,
261 unsigned int off)
262{
263 const struct GNUNET_TIME_Absolute *u = data;
264 struct GNUNET_TIME_Absolute abs;
265
266 abs = *u;
267 if (abs.abs_value_us > INT64_MAX)
268 abs.abs_value_us = INT64_MAX;
269 GNUNET_assert (sizeof (uint64_t) == data_len);
270 if (SQLITE_OK !=
271 sqlite3_bind_int64 (stmt,
272 (int) off,
273 (sqlite3_int64) abs.abs_value_us))
274 return GNUNET_SYSERR;
275 return GNUNET_OK;
276}
277
278
279/**
238 * Generate query parameter for an absolute time value. 280 * Generate query parameter for an absolute time value.
239 * The database must store a 64-bit integer. 281 * The database must store a 64-bit integer.
240 * 282 *
@@ -243,7 +285,13 @@ GNUNET_SQ_query_param_rsa_signature (const struct GNUNET_CRYPTO_RsaSignature *x)
243struct GNUNET_SQ_QueryParam 285struct GNUNET_SQ_QueryParam
244GNUNET_SQ_query_param_absolute_time (const struct GNUNET_TIME_Absolute *x) 286GNUNET_SQ_query_param_absolute_time (const struct GNUNET_TIME_Absolute *x)
245{ 287{
246 return GNUNET_SQ_query_param_uint64 (&x->abs_value_us); 288 struct GNUNET_SQ_QueryParam qp = {
289 .conv = &bind_abstime,
290 .data = x,
291 .size = sizeof (struct GNUNET_TIME_Absolute),
292 .num_params = 1
293 };
294 return qp;
247} 295}
248 296
249 297
@@ -269,6 +317,8 @@ bind_nbotime (void *cls,
269 struct GNUNET_TIME_Absolute abs; 317 struct GNUNET_TIME_Absolute abs;
270 318
271 abs = GNUNET_TIME_absolute_ntoh (*u); 319 abs = GNUNET_TIME_absolute_ntoh (*u);
320 if (abs.abs_value_us > INT64_MAX)
321 abs.abs_value_us = INT64_MAX;
272 GNUNET_assert (sizeof (uint64_t) == data_len); 322 GNUNET_assert (sizeof (uint64_t) == data_len);
273 if (SQLITE_OK != 323 if (SQLITE_OK !=
274 sqlite3_bind_int64 (stmt, 324 sqlite3_bind_int64 (stmt,
diff --git a/src/sq/sq_result_helper.c b/src/sq/sq_result_helper.c
index eaf606aa4..9579863b2 100644
--- a/src/sq/sq_result_helper.c
+++ b/src/sq/sq_result_helper.c
@@ -46,6 +46,15 @@ extract_var_blob (void *cls,
46 const void *ret; 46 const void *ret;
47 void **rdst = (void **) dst; 47 void **rdst = (void **) dst;
48 48
49 if (SQLITE_NULL ==
50 sqlite3_column_type (result,
51 column))
52 {
53 *rdst = NULL;
54 *dst_size = 0;
55 return GNUNET_YES;
56 }
57
49 if (SQLITE_BLOB != 58 if (SQLITE_BLOB !=
50 sqlite3_column_type (result, 59 sqlite3_column_type (result,
51 column)) 60 column))
@@ -142,6 +151,14 @@ extract_fixed_blob (void *cls,
142 int have; 151 int have;
143 const void *ret; 152 const void *ret;
144 153
154 if ( (0 == *dst_size) &&
155 (SQLITE_NULL ==
156 sqlite3_column_type (result,
157 column)) )
158 {
159 return GNUNET_YES;
160 }
161
145 if (SQLITE_BLOB != 162 if (SQLITE_BLOB !=
146 sqlite3_column_type (result, 163 sqlite3_column_type (result,
147 column)) 164 column))
@@ -211,6 +228,13 @@ extract_utf8_string (void *cls,
211 const char *text; 228 const char *text;
212 char **rdst = dst; 229 char **rdst = dst;
213 230
231 if (SQLITE_NULL ==
232 sqlite3_column_type (result,
233 column))
234 {
235 *rdst = NULL;
236 return GNUNET_OK;
237 }
214 if (SQLITE_TEXT != 238 if (SQLITE_TEXT !=
215 sqlite3_column_type (result, 239 sqlite3_column_type (result,
216 column)) 240 column))
@@ -459,6 +483,45 @@ GNUNET_SQ_result_spec_rsa_signature (struct GNUNET_CRYPTO_RsaSignature **sig)
459 483
460 484
461/** 485/**
486 * Extract absolute time value from a Postgres database @a result at row @a row.
487 *
488 * @param cls closure
489 * @param result where to extract data from
490 * @param column column to extract data from
491 * @param[in,out] dst_size where to store size of result, may be NULL
492 * @param[out] dst where to store the result
493 * @return
494 * #GNUNET_YES if all results could be extracted
495 * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
496 */
497static int
498extract_abs_time (void *cls,
499 sqlite3_stmt *result,
500 unsigned int column,
501 size_t *dst_size,
502 void *dst)
503{
504 struct GNUNET_TIME_Absolute *u = dst;
505 struct GNUNET_TIME_Absolute t;
506
507 GNUNET_assert (sizeof (uint64_t) == *dst_size);
508 if (SQLITE_INTEGER !=
509 sqlite3_column_type (result,
510 column))
511 {
512 GNUNET_break (0);
513 return GNUNET_SYSERR;
514 }
515 t.abs_value_us = (uint64_t) sqlite3_column_int64 (result,
516 column);
517 if (INT64_MAX == t.abs_value_us)
518 t = GNUNET_TIME_UNIT_FOREVER_ABS;
519 *u = t;
520 return GNUNET_OK;
521}
522
523
524/**
462 * Absolute time expected. 525 * Absolute time expected.
463 * 526 *
464 * @param[out] at where to store the result 527 * @param[out] at where to store the result
@@ -467,7 +530,14 @@ GNUNET_SQ_result_spec_rsa_signature (struct GNUNET_CRYPTO_RsaSignature **sig)
467struct GNUNET_SQ_ResultSpec 530struct GNUNET_SQ_ResultSpec
468GNUNET_SQ_result_spec_absolute_time (struct GNUNET_TIME_Absolute *at) 531GNUNET_SQ_result_spec_absolute_time (struct GNUNET_TIME_Absolute *at)
469{ 532{
470 return GNUNET_SQ_result_spec_uint64 (&at->abs_value_us); 533 struct GNUNET_SQ_ResultSpec rs = {
534 .conv = &extract_abs_time,
535 .dst = at,
536 .dst_size = sizeof (struct GNUNET_TIME_Absolute),
537 .num_params = 1
538 };
539
540 return rs;
471} 541}
472 542
473 543
@@ -503,6 +573,8 @@ extract_abs_time_nbo (void *cls,
503 } 573 }
504 t.abs_value_us = (uint64_t) sqlite3_column_int64 (result, 574 t.abs_value_us = (uint64_t) sqlite3_column_int64 (result,
505 column); 575 column);
576 if (INT64_MAX == t.abs_value_us)
577 t = GNUNET_TIME_UNIT_FOREVER_ABS;
506 *u = GNUNET_TIME_absolute_hton (t); 578 *u = GNUNET_TIME_absolute_hton (t);
507 return GNUNET_OK; 579 return GNUNET_OK;
508} 580}
diff --git a/src/sq/test_sq.c b/src/sq/test_sq.c
index e6896861e..713809030 100644
--- a/src/sq/test_sq.c
+++ b/src/sq/test_sq.c
@@ -253,8 +253,12 @@ main(int argc,
253 { 253 {
254 fprintf (stderr, 254 fprintf (stderr,
255 "Failed to create table\n"); 255 "Failed to create table\n");
256 sqlite3_close (dbh); 256 GNUNET_break (SQLITE_OK ==
257 unlink ("test.db"); 257 sqlite3_close (dbh));
258 if (0 != unlink ("test.db"))
259 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
260 "unlink",
261 "test.db");
258 return 1; 262 return 1;
259 } 263 }
260 264
@@ -266,12 +270,14 @@ main(int argc,
266 { 270 {
267 fprintf (stderr, 271 fprintf (stderr,
268 "Failed to drop table\n"); 272 "Failed to drop table\n");
269 sqlite3_close (dbh); 273 ret = 1;
270 unlink ("test.db");
271 return 1;
272 } 274 }
273 sqlite3_close (dbh); 275 GNUNET_break (SQLITE_OK ==
274 unlink ("test.db"); 276 sqlite3_close (dbh));
277 if (0 != unlink ("test.db"))
278 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
279 "unlink",
280 "test.db");
275 return ret; 281 return ret;
276} 282}
277 283
diff --git a/src/statistics/gnunet-service-statistics.c b/src/statistics/gnunet-service-statistics.c
index 161327421..0cb136b99 100644
--- a/src/statistics/gnunet-service-statistics.c
+++ b/src/statistics/gnunet-service-statistics.c
@@ -359,7 +359,7 @@ transmit (struct ClientEntry *ce,
359 359
360 size = strlen (e->subsystem->service) + 1 + 360 size = strlen (e->subsystem->service) + 1 +
361 strlen (e->name) + 1; 361 strlen (e->name) + 1;
362 GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE); 362 GNUNET_assert (size < GNUNET_MAX_MESSAGE_SIZE);
363 env = GNUNET_MQ_msg_extra (m, 363 env = GNUNET_MQ_msg_extra (m,
364 size, 364 size,
365 GNUNET_MESSAGE_TYPE_STATISTICS_VALUE); 365 GNUNET_MESSAGE_TYPE_STATISTICS_VALUE);
@@ -776,7 +776,7 @@ check_watch (void *cls,
776 size_t size; 776 size_t size;
777 const char *service; 777 const char *service;
778 const char *name; 778 const char *name;
779 779
780 size = ntohs (message->size) - sizeof (struct GNUNET_MessageHeader); 780 size = ntohs (message->size) - sizeof (struct GNUNET_MessageHeader);
781 if (size != 781 if (size !=
782 GNUNET_STRINGS_buffer_tokenize ((const char *) &message[1], 782 GNUNET_STRINGS_buffer_tokenize ((const char *) &message[1],
@@ -870,7 +870,7 @@ handle_watch (void *cls,
870 870
871/** 871/**
872 * Handle DISCONNECT-message. Sync to disk and send 872 * Handle DISCONNECT-message. Sync to disk and send
873 * back a #GNUNET_MESSAGE_TYPE_STATISTICS_DISCONNECT_CONFIRM 873 * back a #GNUNET_MESSAGE_TYPE_STATISTICS_DISCONNECT_CONFIRM
874 * message. 874 * message.
875 * 875 *
876 * @param cls the `struct ClientEntry *` 876 * @param cls the `struct ClientEntry *`
@@ -984,6 +984,7 @@ client_disconnect_cb (void *cls,
984 } 984 }
985 } 985 }
986 } 986 }
987 GNUNET_free (ce);
987 if ( (0 == client_count) && 988 if ( (0 == client_count) &&
988 (GNUNET_YES == in_shutdown) ) 989 (GNUNET_YES == in_shutdown) )
989 do_shutdown (); 990 do_shutdown ();
@@ -992,7 +993,7 @@ client_disconnect_cb (void *cls,
992 993
993/** 994/**
994 * We've read a `struct GNUNET_STATISTICS_SetMessage *` from 995 * We've read a `struct GNUNET_STATISTICS_SetMessage *` from
995 * disk. Check that it is well-formed, and if so pass it to 996 * disk. Check that it is well-formed, and if so pass it to
996 * the handler for set messages. 997 * the handler for set messages.
997 * 998 *
998 * @param cls NULL 999 * @param cls NULL
diff --git a/src/statistics/gnunet-statistics.c b/src/statistics/gnunet-statistics.c
index ed0c3f27d..6cfc56171 100644
--- a/src/statistics/gnunet-statistics.c
+++ b/src/statistics/gnunet-statistics.c
@@ -378,28 +378,44 @@ run (void *cls,
378int 378int
379main (int argc, char *const *argv) 379main (int argc, char *const *argv)
380{ 380{
381 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 381 struct GNUNET_GETOPT_CommandLineOption options[] = {
382 {'n', "name", "NAME", 382 GNUNET_GETOPT_OPTION_STRING ('n',
383 gettext_noop ("limit output to statistics for the given NAME"), 1, 383 "name",
384 &GNUNET_GETOPT_set_string, &name}, 384 "NAME",
385 {'p', "persistent", NULL, 385 gettext_noop ("limit output to statistics for the given NAME"),
386 gettext_noop ("make the value being set persistent"), 0, 386 &name),
387 &GNUNET_GETOPT_set_one, &persistent}, 387
388 {'s', "subsystem", "SUBSYSTEM", 388 GNUNET_GETOPT_OPTION_SET_ONE ('p',
389 gettext_noop ("limit output to the given SUBSYSTEM"), 1, 389 "persistent",
390 &GNUNET_GETOPT_set_string, &subsystem}, 390 gettext_noop ("make the value being set persistent"),
391 {'q', "quiet", NULL, 391 &persistent),
392 gettext_noop ("just print the statistics value"), 0, 392
393 &GNUNET_GETOPT_set_one, &quiet}, 393 GNUNET_GETOPT_OPTION_STRING ('s',
394 {'w', "watch", NULL, 394 "subsystem",
395 gettext_noop ("watch value continuously"), 0, 395 "SUBSYSTEM",
396 &GNUNET_GETOPT_set_one, &watch}, 396 gettext_noop ("limit output to the given SUBSYSTEM"),
397 {'r', "remote", NULL, 397 &subsystem),
398 gettext_noop ("connect to remote host"), 1, 398
399 &GNUNET_GETOPT_set_string, &remote_host}, 399 GNUNET_GETOPT_OPTION_SET_ONE ('q',
400 {'o', "port", NULL, 400 "quiet",
401 gettext_noop ("port for remote host"), 1, 401 gettext_noop ("just print the statistics value"),
402 &GNUNET_GETOPT_set_uint, &remote_port}, 402 &quiet),
403
404 GNUNET_GETOPT_OPTION_SET_ONE ('w',
405 "watch",
406 gettext_noop ("watch value continuously"),
407 &watch),
408
409 GNUNET_GETOPT_OPTION_STRING ('r',
410 "remote",
411 "REMOTE",
412 gettext_noop ("connect to remote host"),
413 &remote_host),
414 GNUNET_GETOPT_OPTION_SET_ULONG ('o',
415 "port",
416 "PORT",
417 gettext_noop ("port for remote host"),
418 &remote_port),
403 GNUNET_GETOPT_OPTION_END 419 GNUNET_GETOPT_OPTION_END
404 }; 420 };
405 remote_port = 0; 421 remote_port = 0;
diff --git a/src/statistics/statistics_api.c b/src/statistics/statistics_api.c
index ad4453b2a..9d04e854f 100644
--- a/src/statistics/statistics_api.c
+++ b/src/statistics/statistics_api.c
@@ -349,7 +349,7 @@ schedule_watch_request (struct GNUNET_STATISTICS_Handle *h,
349 slen = strlen (watch->subsystem) + 1; 349 slen = strlen (watch->subsystem) + 1;
350 nlen = strlen (watch->name) + 1; 350 nlen = strlen (watch->name) + 1;
351 nsize = sizeof (struct GNUNET_MessageHeader) + slen + nlen; 351 nsize = sizeof (struct GNUNET_MessageHeader) + slen + nlen;
352 if (nsize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) 352 if (nsize >= GNUNET_MAX_MESSAGE_SIZE)
353 { 353 {
354 GNUNET_break (0); 354 GNUNET_break (0);
355 return; 355 return;
@@ -1098,7 +1098,7 @@ GNUNET_STATISTICS_get (struct GNUNET_STATISTICS_Handle *handle,
1098 slen1 = strlen (subsystem) + 1; 1098 slen1 = strlen (subsystem) + 1;
1099 slen2 = strlen (name) + 1; 1099 slen2 = strlen (name) + 1;
1100 GNUNET_assert (slen1 + slen2 + sizeof (struct GNUNET_MessageHeader) < 1100 GNUNET_assert (slen1 + slen2 + sizeof (struct GNUNET_MessageHeader) <
1101 GNUNET_SERVER_MAX_MESSAGE_SIZE); 1101 GNUNET_MAX_MESSAGE_SIZE);
1102 ai = GNUNET_new (struct GNUNET_STATISTICS_GetHandle); 1102 ai = GNUNET_new (struct GNUNET_STATISTICS_GetHandle);
1103 ai->sh = handle; 1103 ai->sh = handle;
1104 ai->subsystem = GNUNET_strdup (subsystem); 1104 ai->subsystem = GNUNET_strdup (subsystem);
@@ -1246,7 +1246,7 @@ add_setter_action (struct GNUNET_STATISTICS_Handle *h,
1246 slen = strlen (h->subsystem) + 1; 1246 slen = strlen (h->subsystem) + 1;
1247 nlen = strlen (name) + 1; 1247 nlen = strlen (name) + 1;
1248 nsize = sizeof (struct GNUNET_STATISTICS_SetMessage) + slen + nlen; 1248 nsize = sizeof (struct GNUNET_STATISTICS_SetMessage) + slen + nlen;
1249 if (nsize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) 1249 if (nsize >= GNUNET_MAX_MESSAGE_SIZE)
1250 { 1250 {
1251 GNUNET_break (0); 1251 GNUNET_break (0);
1252 return; 1252 return;
diff --git a/src/testbed-logger/gnunet-service-testbed-logger.c b/src/testbed-logger/gnunet-service-testbed-logger.c
index 1c250b306..f915e70af 100644
--- a/src/testbed-logger/gnunet-service-testbed-logger.c
+++ b/src/testbed-logger/gnunet-service-testbed-logger.c
@@ -40,42 +40,6 @@
40 LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__) 40 LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
41 41
42/** 42/**
43 * The message queue for sending messages to clients
44 */
45struct MessageQueue
46{
47 /**
48 * The message to be sent
49 */
50 struct GNUNET_MessageHeader *msg;
51
52 /**
53 * The client to send the message to
54 */
55 struct GNUNET_SERVER_Client *client;
56
57 /**
58 * next pointer for DLL
59 */
60 struct MessageQueue *next;
61
62 /**
63 * prev pointer for DLL
64 */
65 struct MessageQueue *prev;
66};
67
68/**
69 * The message queue head
70 */
71static struct MessageQueue *mq_head;
72
73/**
74 * The message queue tail
75 */
76static struct MessageQueue *mq_tail;
77
78/**
79 * Handle for buffered writing. 43 * Handle for buffered writing.
80 */ 44 */
81struct GNUNET_BIO_WriteHandle *bio; 45struct GNUNET_BIO_WriteHandle *bio;
@@ -92,23 +56,38 @@ static int in_shutdown;
92 56
93 57
94/** 58/**
95 * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages 59 * Check #GNUNET_MESSAGE_TYPE_TESTBED_LOGGER_MSG messages
96 * 60 *
97 * @param cls NULL 61 * @param cls client identification of the client
98 * @param client identification of the client 62 * @param msg the actual message
63 * @return #GNUNET_OK (they are all always OK)
64 */
65static int
66check_log_msg (void *cls,
67 const struct GNUNET_MessageHeader *msg)
68{
69 return GNUNET_OK;
70}
71
72
73/**
74 * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_LOGGER_MSG messages
75 *
76 * @param cls client identification of the client
99 * @param msg the actual message 77 * @param msg the actual message
100 */ 78 */
101static void 79static void
102handle_log_msg (void *cls, 80handle_log_msg (void *cls,
103 struct GNUNET_SERVER_Client *client,
104 const struct GNUNET_MessageHeader *msg) 81 const struct GNUNET_MessageHeader *msg)
105{ 82{
83 struct GNUNET_SERVICE_Client *client = cls;
106 uint16_t ms; 84 uint16_t ms;
107 85
108 ms = ntohs (msg->size); 86 ms = ntohs (msg->size) - sizeof (struct GNUNET_MessageHeader);
109 ms -= sizeof (struct GNUNET_MessageHeader); 87 GNUNET_BIO_write (bio,
110 GNUNET_BIO_write (bio, &msg[1], ms); 88 &msg[1],
111 GNUNET_SERVER_receive_done (client, GNUNET_OK); 89 ms);
90 GNUNET_SERVICE_client_continue (client);
112} 91}
113 92
114 93
@@ -120,69 +99,55 @@ handle_log_msg (void *cls,
120static void 99static void
121shutdown_task (void *cls) 100shutdown_task (void *cls)
122{ 101{
123 struct MessageQueue *mq_entry;
124
125 in_shutdown = GNUNET_YES; 102 in_shutdown = GNUNET_YES;
126 if (0 != nconn) 103 if (0 != nconn)
127 { 104 {
128 /* Delay shutdown if there are active connections */ 105 /* Delay shutdown if there are active connections */
129 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); 106 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
107 NULL);
130 return; 108 return;
131 } 109 }
132 while (NULL != (mq_entry = mq_head)) 110 GNUNET_break (GNUNET_OK ==
133 { 111 GNUNET_BIO_write_close (bio));
134 GNUNET_free (mq_entry->msg);
135 GNUNET_SERVER_client_drop (mq_entry->client);
136 GNUNET_CONTAINER_DLL_remove (mq_head,
137 mq_tail,
138 mq_entry);
139 GNUNET_free (mq_entry);
140 }
141 GNUNET_break (GNUNET_OK == GNUNET_BIO_write_close (bio));
142} 112}
143 113
144 114
145/** 115/**
146x * Functions with this signature are called whenever a client 116 * Callback called when a client connects to the service.
147 * is disconnected on the network level.
148 * 117 *
149 * @param cls closure 118 * @param cls closure for the service
150 * @param client identification of the client; NULL 119 * @param c the new client that connected to the service
151 * for the last call when the server is destroyed 120 * @param mq the message queue used to send messages to the client
121 * @return @a c
152 */ 122 */
153static void 123static void *
154client_disconnected (void *cls, 124client_connect_cb (void *cls,
155 struct GNUNET_SERVER_Client *client) 125 struct GNUNET_SERVICE_Client *c,
126 struct GNUNET_MQ_Handle *mq)
156{ 127{
157 if (NULL == client) 128 /* FIXME: is this really what we want here? */
158 { 129 GNUNET_SERVICE_client_persist (c);
159 GNUNET_break (0 == nconn); 130 nconn++;
160 return; 131 return c;
161 }
162 nconn--;
163 if (GNUNET_YES == in_shutdown)
164 GNUNET_SCHEDULER_shutdown ();
165} 132}
166 133
167 134
168/** 135/**
169 * Functions with this signature are called whenever a client 136 * Callback called when a client disconnected from the service
170 * is connected on the network level.
171 * 137 *
172 * @param cls closure 138 * @param cls closure for the service
173 * @param client identification of the client 139 * @param c the client that disconnected
140 * @param internal_cls should be equal to @a c
174 */ 141 */
175static void 142static void
176client_connected (void *cls, 143client_disconnect_cb (void *cls,
177 struct GNUNET_SERVER_Client *client) 144 struct GNUNET_SERVICE_Client *c,
145 void *internal_cls)
178{ 146{
179 if (NULL == client) 147 nconn--;
180 { 148 if (GNUNET_YES == in_shutdown)
181 GNUNET_break (0 == nconn); 149 GNUNET_SCHEDULER_shutdown ();
182 return; 150 GNUNET_assert (c == internal_cls);
183 }
184 GNUNET_SERVER_client_persist_ (client);
185 nconn++;
186} 151}
187 152
188 153
@@ -190,18 +155,14 @@ client_connected (void *cls,
190 * Testbed setup 155 * Testbed setup
191 * 156 *
192 * @param cls closure 157 * @param cls closure
193 * @param server the initialized server
194 * @param cfg configuration to use 158 * @param cfg configuration to use
159 * @param service the initialized service
195 */ 160 */
196static void 161static void
197logger_run (void *cls, 162logger_run (void *cls,
198 struct GNUNET_SERVER_Handle *server, 163 const struct GNUNET_CONFIGURATION_Handle *cfg,
199 const struct GNUNET_CONFIGURATION_Handle *cfg) 164 struct GNUNET_SERVICE_Handle *service)
200{ 165{
201 static const struct GNUNET_SERVER_MessageHandler message_handlers[] = {
202 {&handle_log_msg, NULL, GNUNET_MESSAGE_TYPE_TESTBED_LOGGER_MSG, 0},
203 {NULL, NULL, 0, 0}
204 };
205 char *dir; 166 char *dir;
206 char *fn; 167 char *fn;
207 char *hname; 168 char *hname;
@@ -223,7 +184,8 @@ logger_run (void *cls,
223 pid = getpid (); 184 pid = getpid ();
224 hname_len = GNUNET_OS_get_hostname_max_length (); 185 hname_len = GNUNET_OS_get_hostname_max_length ();
225 hname = GNUNET_malloc (hname_len); 186 hname = GNUNET_malloc (hname_len);
226 if (0 != gethostname (hname, hname_len)) 187 if (0 != gethostname (hname,
188 hname_len))
227 { 189 {
228 LOG (GNUNET_ERROR_TYPE_ERROR, 190 LOG (GNUNET_ERROR_TYPE_ERROR,
229 "Cannot get hostname. Exiting\n"); 191 "Cannot get hostname. Exiting\n");
@@ -247,24 +209,27 @@ logger_run (void *cls,
247 return; 209 return;
248 } 210 }
249 GNUNET_free (fn); 211 GNUNET_free (fn);
250 GNUNET_SERVER_add_handlers (server, message_handlers); 212 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
251 GNUNET_SERVER_connect_notify (server, &client_connected, NULL); 213 NULL);
252 GNUNET_SERVER_disconnect_notify (server, &client_disconnected, NULL);
253 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
254 LOG_DEBUG ("TESTBED-LOGGER startup complete\n"); 214 LOG_DEBUG ("TESTBED-LOGGER startup complete\n");
255} 215}
256 216
257 217
258/** 218/**
259 * The starting point of execution 219 * Define "main" method using service macro.
260 */ 220 */
261int 221GNUNET_SERVICE_MAIN
262main (int argc, char *const *argv) 222("testbed-logger",
263{ 223 GNUNET_SERVICE_OPTION_NONE,
264 return (GNUNET_OK == 224 &logger_run,
265 GNUNET_SERVICE_run (argc, argv, "testbed-logger", 225 &client_connect_cb,
266 GNUNET_SERVICE_OPTION_NONE, 226 &client_disconnect_cb,
267 &logger_run, NULL)) ? 0 : 1; 227 NULL,
268} 228 GNUNET_MQ_hd_var_size (log_msg,
229 GNUNET_MESSAGE_TYPE_TESTBED_LOGGER_MSG,
230 struct GNUNET_MessageHeader,
231 NULL),
232 GNUNET_MQ_handler_end ());
233
269 234
270/* end of gnunet-service-testbed-logger.c */ 235/* end of gnunet-service-testbed-logger.c */
diff --git a/src/testbed-logger/test_testbed_logger_api.c b/src/testbed-logger/test_testbed_logger_api.c
index 0ebe0c3f4..e627feeb4 100644
--- a/src/testbed-logger/test_testbed_logger_api.c
+++ b/src/testbed-logger/test_testbed_logger_api.c
@@ -258,11 +258,15 @@ main (int argc, char **argv)
258 GNUNET_log_setup ("test-testbed-logger-api", 258 GNUNET_log_setup ("test-testbed-logger-api",
259 "WARNING", 259 "WARNING",
260 NULL); 260 NULL);
261 GNUNET_break (GNUNET_OK ==
262 GNUNET_DISK_directory_remove ("/tmp/test-testbed"));
261 ret = GNUNET_TESTING_service_run ("test-testbed-logger", 263 ret = GNUNET_TESTING_service_run ("test-testbed-logger",
262 "testbed-logger", 264 "testbed-logger",
263 "test_testbed_logger_api.conf", 265 "test_testbed_logger_api.conf",
264 &test_main, 266 &test_main,
265 NULL); 267 NULL);
268 GNUNET_break (GNUNET_OK ==
269 GNUNET_DISK_directory_remove ("/tmp/test-testbed"));
266 if (0 != ret) 270 if (0 != ret)
267 return 1; 271 return 1;
268 if (GNUNET_OK != result) 272 if (GNUNET_OK != result)
diff --git a/src/testbed-logger/testbed_logger_api.c b/src/testbed-logger/testbed_logger_api.c
index 25494aed0..7aa4ade35 100644
--- a/src/testbed-logger/testbed_logger_api.c
+++ b/src/testbed-logger/testbed_logger_api.c
@@ -39,7 +39,7 @@
39/** 39/**
40 * The size of the buffer we fill before sending out the message 40 * The size of the buffer we fill before sending out the message
41 */ 41 */
42#define BUFFER_SIZE (GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct GNUNET_MessageHeader)) 42#define BUFFER_SIZE (GNUNET_MAX_MESSAGE_SIZE - sizeof (struct GNUNET_MessageHeader))
43 43
44/** 44/**
45 * Connection handle for the logger service 45 * Connection handle for the logger service
diff --git a/src/testbed/Makefile.am b/src/testbed/Makefile.am
index 94c908295..61cfba2ff 100644
--- a/src/testbed/Makefile.am
+++ b/src/testbed/Makefile.am
@@ -104,13 +104,13 @@ libgnunettestbed_la_SOURCES = \
104 testbed_api_test.c \ 104 testbed_api_test.c \
105 testbed_api_topology.c testbed_api_topology.h \ 105 testbed_api_topology.c testbed_api_topology.h \
106 testbed_api_sd.c testbed_api_sd.h \ 106 testbed_api_sd.c testbed_api_sd.h \
107 testbed_api_barriers.c 107 testbed_api_barriers.c
108libgnunettestbed_la_LIBADD = $(XLIB) \ 108libgnunettestbed_la_LIBADD = $(XLIB) \
109 $(top_builddir)/src/core/libgnunetcore.la \ 109 $(top_builddir)/src/core/libgnunetcore.la \
110 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 110 $(top_builddir)/src/statistics/libgnunetstatistics.la \
111 $(top_builddir)/src/transport/libgnunettransport.la \ 111 $(top_builddir)/src/transport/libgnunettransport.la \
112 $(top_builddir)/src/hello/libgnunethello.la \ 112 $(top_builddir)/src/hello/libgnunethello.la \
113 -lm \ 113 -lm $(Z_LIBS) \
114 $(top_builddir)/src/util/libgnunetutil.la \ 114 $(top_builddir)/src/util/libgnunetutil.la \
115 $(top_builddir)/src/testing/libgnunettesting.la \ 115 $(top_builddir)/src/testing/libgnunettesting.la \
116 $(LTLIBINTL) 116 $(LTLIBINTL)
diff --git a/src/testbed/generate-underlay-topology.c b/src/testbed/generate-underlay-topology.c
index 36580a2a3..ab7d81c8b 100644
--- a/src/testbed/generate-underlay-topology.c
+++ b/src/testbed/generate-underlay-topology.c
@@ -70,7 +70,7 @@ enum GNUNET_TESTBED_TopologyOption topology;
70/** 70/**
71 * The number of peers to include in the topology 71 * The number of peers to include in the topology
72 */ 72 */
73static int num_peers; 73static unsigned int num_peers;
74 74
75/** 75/**
76 * program result 76 * program result
@@ -335,11 +335,15 @@ int
335main (int argc, char *const argv[]) 335main (int argc, char *const argv[])
336{ 336{
337 struct GNUNET_GETOPT_CommandLineOption option[] = { 337 struct GNUNET_GETOPT_CommandLineOption option[] = {
338 {'p', "num-peers", "COUNT", 338
339 gettext_noop ("create COUNT number of peers"), 339 GNUNET_GETOPT_OPTION_SET_UINT ('p',
340 GNUNET_YES, &GNUNET_GETOPT_set_uint, &num_peers}, 340 "num-peers",
341 "COUNT",
342 gettext_noop ("create COUNT number of peers"),
343 &num_peers),
341 GNUNET_GETOPT_OPTION_END 344 GNUNET_GETOPT_OPTION_END
342 }; 345 };
346
343 int ret; 347 int ret;
344 348
345 exit_result = GNUNET_SYSERR; 349 exit_result = GNUNET_SYSERR;
diff --git a/src/testbed/gnunet-helper-testbed.c b/src/testbed/gnunet-helper-testbed.c
index 6368fb74b..d2a3a98b7 100644
--- a/src/testbed/gnunet-helper-testbed.c
+++ b/src/testbed/gnunet-helper-testbed.c
@@ -495,7 +495,7 @@ error:
495static void 495static void
496read_task (void *cls) 496read_task (void *cls)
497{ 497{
498 char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE]; 498 char buf[GNUNET_MAX_MESSAGE_SIZE];
499 ssize_t sread; 499 ssize_t sread;
500 500
501 read_task_id = NULL; 501 read_task_id = NULL;
diff --git a/src/testbed/gnunet-service-testbed_barriers.c b/src/testbed/gnunet-service-testbed_barriers.c
index a201d22bb..681ed6df2 100644
--- a/src/testbed/gnunet-service-testbed_barriers.c
+++ b/src/testbed/gnunet-service-testbed_barriers.c
@@ -478,7 +478,7 @@ GST_barriers_init (struct GNUNET_CONFIGURATION_Handle *cfg)
478 LOG_DEBUG ("Launching testbed-barrier service\n"); 478 LOG_DEBUG ("Launching testbed-barrier service\n");
479 barrier_map = GNUNET_CONTAINER_multihashmap_create (3, 479 barrier_map = GNUNET_CONTAINER_multihashmap_create (3,
480 GNUNET_YES); 480 GNUNET_YES);
481 ctx = GNUNET_SERVICE_starT ("testbed-barrier", 481 ctx = GNUNET_SERVICE_start ("testbed-barrier",
482 cfg, 482 cfg,
483 &connect_cb, 483 &connect_cb,
484 &disconnect_cb, 484 &disconnect_cb,
@@ -524,7 +524,7 @@ GST_barriers_destroy ()
524 NULL)); 524 NULL));
525 GNUNET_CONTAINER_multihashmap_destroy (barrier_map); 525 GNUNET_CONTAINER_multihashmap_destroy (barrier_map);
526 GNUNET_assert (NULL != ctx); 526 GNUNET_assert (NULL != ctx);
527 GNUNET_SERVICE_stoP (ctx); 527 GNUNET_SERVICE_stop (ctx);
528} 528}
529 529
530 530
diff --git a/src/testbed/gnunet-service-testbed_oc.c b/src/testbed/gnunet-service-testbed_oc.c
index b775f31bd..09849797c 100644
--- a/src/testbed/gnunet-service-testbed_oc.c
+++ b/src/testbed/gnunet-service-testbed_oc.c
@@ -371,7 +371,7 @@ GST_cleanup_focc (struct ForwardedOverlayConnectContext *focc)
371/** 371/**
372 * Timeout task for cancelling a forwarded overlay connect connect 372 * Timeout task for cancelling a forwarded overlay connect connect
373 * 373 *
374 * @param cls the ForwardedOverlayConnectContext 374 * @param cls the `struct ForwardedOperationContext`
375 */ 375 */
376static void 376static void
377forwarded_overlay_connect_timeout (void *cls) 377forwarded_overlay_connect_timeout (void *cls)
diff --git a/src/testbed/gnunet-service-testbed_peers.c b/src/testbed/gnunet-service-testbed_peers.c
index a977b2b9b..aacd62583 100644
--- a/src/testbed/gnunet-service-testbed_peers.c
+++ b/src/testbed/gnunet-service-testbed_peers.c
@@ -1137,14 +1137,8 @@ arm_req_string (enum GNUNET_ARM_RequestStatus rs)
1137 { 1137 {
1138 case GNUNET_ARM_REQUEST_SENT_OK: 1138 case GNUNET_ARM_REQUEST_SENT_OK:
1139 return _("Message was sent successfully"); 1139 return _("Message was sent successfully");
1140 case GNUNET_ARM_REQUEST_CONFIGURATION_ERROR:
1141 return _("Misconfiguration (can't connect to the ARM service)");
1142 case GNUNET_ARM_REQUEST_DISCONNECTED: 1140 case GNUNET_ARM_REQUEST_DISCONNECTED:
1143 return _("We disconnected from ARM before we could send a request"); 1141 return _("We disconnected from ARM before we could send a request");
1144 case GNUNET_ARM_REQUEST_BUSY:
1145 return _("ARM API is busy");
1146 case GNUNET_ARM_REQUEST_TIMEOUT:
1147 return _("Request timed out");
1148 } 1142 }
1149 return _("Unknown request status"); 1143 return _("Unknown request status");
1150} 1144}
diff --git a/src/testbed/gnunet-testbed-profiler.c b/src/testbed/gnunet-testbed-profiler.c
index 9468b3c91..29f77193d 100644
--- a/src/testbed/gnunet-testbed-profiler.c
+++ b/src/testbed/gnunet-testbed-profiler.c
@@ -276,23 +276,34 @@ run (void *cls, char *const *args, const char *cfgfile,
276int 276int
277main (int argc, char *const *argv) 277main (int argc, char *const *argv)
278{ 278{
279 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 279 struct GNUNET_GETOPT_CommandLineOption options[] = {
280 {'p', "num-peers", "COUNT", 280
281 gettext_noop ("create COUNT number of peers"), 281 GNUNET_GETOPT_OPTION_SET_UINT ('p',
282 GNUNET_YES, &GNUNET_GETOPT_set_uint, &num_peers}, 282 "num-peers",
283 {'e', "num-errors", "COUNT", 283 "COUNT",
284 gettext_noop ("tolerate COUNT number of continious timeout failures"), 284 gettext_noop ("create COUNT number of peers"),
285 GNUNET_YES, &GNUNET_GETOPT_set_uint, &num_cont_fails}, 285 &num_peers),
286 {'n', "non-interactive", NULL, 286
287 gettext_noop ("run profiler in non-interactive mode where upon " 287 GNUNET_GETOPT_OPTION_SET_UINT ('e',
288 "testbed setup the profiler does not wait for a " 288 "num-errors",
289 "keystroke but continues to run until a termination " 289 "COUNT",
290 "signal is received"), 290 gettext_noop ("tolerate COUNT number of continious timeout failures"),
291 GNUNET_NO, &GNUNET_GETOPT_set_one, &noninteractive}, 291 &num_cont_fails),
292
293 GNUNET_GETOPT_OPTION_SET_ONE ('n',
294 "non-interactive",
295 gettext_noop ("run profiler in non-interactive mode where upon "
296 "testbed setup the profiler does not wait for a "
297 "keystroke but continues to run until a termination "
298 "signal is received"),
299 &noninteractive),
300
292#if !ENABLE_SUPERMUC 301#if !ENABLE_SUPERMUC
293 {'H', "hosts", "FILENAME", 302 GNUNET_GETOPT_OPTION_STRING ('H',
294 gettext_noop ("name of the file with the login information for the testbed"), 303 "hosts",
295 GNUNET_YES, &GNUNET_GETOPT_set_string, &hosts_file}, 304 "FILENAME",
305 gettext_noop ("name of the file with the login information for the testbed"),
306 &hosts_file),
296#endif 307#endif
297 GNUNET_GETOPT_OPTION_END 308 GNUNET_GETOPT_OPTION_END
298 }; 309 };
diff --git a/src/testbed/test_gnunet_helper_testbed.c b/src/testbed/test_gnunet_helper_testbed.c
index 7a2dce8a5..7ba9e7c31 100644
--- a/src/testbed/test_gnunet_helper_testbed.c
+++ b/src/testbed/test_gnunet_helper_testbed.c
@@ -121,10 +121,12 @@ do_abort (void *cls)
121 * #GNUNET_SYSERR during GNUNET_HELPER_stop() 121 * #GNUNET_SYSERR during GNUNET_HELPER_stop()
122 */ 122 */
123static void 123static void
124cont_cb (void *cls, int result) 124cont_cb (void *cls,
125 int result)
125{ 126{
126 shandle = NULL; 127 shandle = NULL;
127 LOG (GNUNET_ERROR_TYPE_DEBUG, "Message sent\n"); 128 LOG (GNUNET_ERROR_TYPE_DEBUG,
129 "Message sent\n");
128 GNUNET_assert (GNUNET_OK == result); 130 GNUNET_assert (GNUNET_OK == result);
129} 131}
130 132
@@ -138,11 +140,11 @@ cont_cb (void *cls, int result)
138 * @param cls closure 140 * @param cls closure
139 * @param client identification of the client 141 * @param client identification of the client
140 * @param message the actual message 142 * @param message the actual message
141 *
142 * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing 143 * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing
143 */ 144 */
144static int 145static int
145mst_cb (void *cls, void *client, const struct GNUNET_MessageHeader *message) 146mst_cb (void *cls,
147 const struct GNUNET_MessageHeader *message)
146{ 148{
147 const struct GNUNET_TESTBED_HelperReply *msg; 149 const struct GNUNET_TESTBED_HelperReply *msg;
148 char *config; 150 char *config;
@@ -207,8 +209,12 @@ run (void *cls, char *const *args, const char *cfgfile,
207 const char *trusted_ip = "127.0.0.1"; 209 const char *trusted_ip = "127.0.0.1";
208 210
209 helper = 211 helper =
210 GNUNET_HELPER_start (GNUNET_YES, "gnunet-helper-testbed", binary_argv, 212 GNUNET_HELPER_start (GNUNET_YES,
211 &mst_cb, &exp_cb, NULL); 213 "gnunet-helper-testbed",
214 binary_argv,
215 &mst_cb,
216 &exp_cb,
217 NULL);
212 GNUNET_assert (NULL != helper); 218 GNUNET_assert (NULL != helper);
213 cfg = GNUNET_CONFIGURATION_dup (cfg2); 219 cfg = GNUNET_CONFIGURATION_dup (cfg2);
214 msg = GNUNET_TESTBED_create_helper_init_msg_ (trusted_ip, NULL, cfg); 220 msg = GNUNET_TESTBED_create_helper_init_msg_ (trusted_ip, NULL, cfg);
diff --git a/src/testbed/testbed_api_hosts.c b/src/testbed/testbed_api_hosts.c
index 731944bc4..5d2c1cc37 100644
--- a/src/testbed/testbed_api_hosts.c
+++ b/src/testbed/testbed_api_hosts.c
@@ -952,10 +952,11 @@ gen_rsh_suffix_args (const char * const *append_args)
952 * @param client identification of the client 952 * @param client identification of the client
953 * @param message the actual message 953 * @param message the actual message
954 * 954 *
955 * @return GNUNET_OK on success, GNUNET_SYSERR to stop further processing 955 * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing
956 */ 956 */
957static int 957static int
958helper_mst (void *cls, void *client, const struct GNUNET_MessageHeader *message) 958helper_mst (void *cls,
959 const struct GNUNET_MessageHeader *message)
959{ 960{
960 struct GNUNET_TESTBED_ControllerProc *cp = cls; 961 struct GNUNET_TESTBED_ControllerProc *cp = cls;
961 const struct GNUNET_TESTBED_HelperReply *msg; 962 const struct GNUNET_TESTBED_HelperReply *msg;
diff --git a/src/testbed/testbed_api_peers.c b/src/testbed/testbed_api_peers.c
index 2af62b44a..871e554a9 100644
--- a/src/testbed/testbed_api_peers.c
+++ b/src/testbed/testbed_api_peers.c
@@ -969,7 +969,7 @@ GNUNET_TESTBED_peer_manage_service (void *op_cls,
969 GNUNET_assert (TESTBED_PS_STARTED == peer->state); /* peer is not running? */ 969 GNUNET_assert (TESTBED_PS_STARTED == peer->state); /* peer is not running? */
970 msize = strlen (service_name) + 1; 970 msize = strlen (service_name) + 1;
971 msize += sizeof (struct GNUNET_TESTBED_ManagePeerServiceMessage); 971 msize += sizeof (struct GNUNET_TESTBED_ManagePeerServiceMessage);
972 if (GNUNET_SERVER_MAX_MESSAGE_SIZE < msize) 972 if (GNUNET_MAX_MESSAGE_SIZE < msize)
973 return NULL; 973 return NULL;
974 data = GNUNET_new (struct ManageServiceData); 974 data = GNUNET_new (struct ManageServiceData);
975 data->cb = cb; 975 data->cb = cb;
diff --git a/src/testbed/testbed_api_topology.c b/src/testbed/testbed_api_topology.c
index a21a7cf53..7bc36d1b4 100644
--- a/src/testbed/testbed_api_topology.c
+++ b/src/testbed/testbed_api_topology.c
@@ -1147,9 +1147,11 @@ gen_topo_from_file (struct TopologyContext *tc,
1147 other_peer_id); 1147 other_peer_id);
1148 while (('\n' != data[offset]) && ('|' != data[offset]) && (offset < fs)) 1148 while (('\n' != data[offset]) && ('|' != data[offset]) && (offset < fs))
1149 offset++; 1149 offset++;
1150 if ('\n' == data[offset]) 1150 if ( (offset < fs) &&
1151 ('\n' == data[offset]) )
1151 state = PEER_INDEX; 1152 state = PEER_INDEX;
1152 else if ('|' == data[offset]) 1153 else if ( (offset < fs) &&
1154 ('|' == data[offset]) )
1153 { 1155 {
1154 state = OTHER_PEER_INDEX; 1156 state = OTHER_PEER_INDEX;
1155 offset++; 1157 offset++;
@@ -1491,7 +1493,7 @@ GNUNET_TESTBED_topology_get_ (enum GNUNET_TESTBED_TopologyOption *topology,
1491 { 1493 {
1492 if (NULL != topology) 1494 if (NULL != topology)
1493 *topology = (enum GNUNET_TESTBED_TopologyOption) cnt; 1495 *topology = (enum GNUNET_TESTBED_TopologyOption) cnt;
1494 GNUNET_assert (GNUNET_TESTBED_TOPOLOGY_OPTION_END != *topology); 1496 GNUNET_assert (GNUNET_TESTBED_TOPOLOGY_OPTION_END != (enum GNUNET_TESTBED_TopologyOption) cnt);
1495 return GNUNET_YES; 1497 return GNUNET_YES;
1496 } 1498 }
1497 } 1499 }
diff --git a/src/testing/gnunet-testing.c b/src/testing/gnunet-testing.c
index 07f1560cb..686b38192 100644
--- a/src/testing/gnunet-testing.c
+++ b/src/testing/gnunet-testing.c
@@ -348,17 +348,35 @@ run_no_scheduler (void *cls, char *const *args, const char *cfgfile,
348int 348int
349main (int argc, char *const *argv) 349main (int argc, char *const *argv)
350{ 350{
351 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 351 struct GNUNET_GETOPT_CommandLineOption options[] = {
352 {'C', "cfg", NULL, gettext_noop ("create unique configuration files"), 352 GNUNET_GETOPT_OPTION_SET_ONE ('C',
353 GNUNET_NO, &GNUNET_GETOPT_set_one, &create_cfg}, 353 "cfg",
354 {'k', "key", "FILENAME", gettext_noop ("extract hostkey file from pre-computed hostkey list"), 354 gettext_noop ("create unique configuration files"),
355 GNUNET_YES, &GNUNET_GETOPT_set_string, &create_hostkey}, 355 &create_cfg),
356 {'n', "number", "NUMBER", gettext_noop ("number of unique configuration files to create, or number of the hostkey to extract"), 356 GNUNET_GETOPT_OPTION_STRING ('k',
357 GNUNET_YES, &GNUNET_GETOPT_set_uint, &create_no}, 357 "key",
358 {'t', "template", "FILENAME", gettext_noop ("configuration template"), 358 "FILENAME",
359 GNUNET_YES, &GNUNET_GETOPT_set_string, &create_cfg_template}, 359 gettext_noop ("extract hostkey file from pre-computed hostkey list"),
360 {'r', "run", "SERVICE", gettext_noop ("run the given service, wait on stdin for 'r' (restart) or 'q' (quit)"), 360 &create_hostkey),
361 GNUNET_YES, &GNUNET_GETOPT_set_string, &run_service_name}, 361
362 GNUNET_GETOPT_OPTION_SET_UINT ('n',
363 "number",
364 "NUMBER",
365 gettext_noop ("number of unique configuration files to create, or number of the hostkey to extract"),
366 &create_no),
367
368
369 GNUNET_GETOPT_OPTION_STRING ('t',
370 "template",
371 "FILENAME",
372 gettext_noop ("configuration template"),
373 &create_cfg_template),
374
375 GNUNET_GETOPT_OPTION_STRING ('r',
376 "run",
377 "SERVICE",
378 gettext_noop ("run the given service, wait on stdin for 'r' (restart) or 'q' (quit)"),
379 &run_service_name),
362 GNUNET_GETOPT_OPTION_END 380 GNUNET_GETOPT_OPTION_END
363 }; 381 };
364 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) 382 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
diff --git a/src/testing/list-keys.c b/src/testing/list-keys.c
index 1fd46ebf2..cfb49460a 100644
--- a/src/testing/list-keys.c
+++ b/src/testing/list-keys.c
@@ -6,10 +6,6 @@ static unsigned int nkeys;
6static unsigned int nskip; 6static unsigned int nskip;
7static int result; 7static int result;
8 8
9
10
11
12
13/** 9/**
14 * Main run function. 10 * Main run function.
15 * 11 *
@@ -87,12 +83,11 @@ run (void *cls, char *const *args, const char *cfgfile,
87int main (int argc, char *argv[]) 83int main (int argc, char *argv[])
88{ 84{
89 struct GNUNET_GETOPT_CommandLineOption option[] = { 85 struct GNUNET_GETOPT_CommandLineOption option[] = {
90 {'n', "num-keys", "COUNT", 86 GNUNET_GETOPT_OPTION_SET_UINT ('n',
91 gettext_noop ("list COUNT number of keys"), 87 "num-keys",
92 GNUNET_YES, &GNUNET_GETOPT_set_uint, &nkeys}, 88 "COUNT",
93 {'s', "skip", "COUNT", 89 gettext_noop ("list COUNT number of keys"),
94 gettext_noop ("skip COUNT number of keys in the beginning"), 90 &nkeys),
95 GNUNET_YES, &GNUNET_GETOPT_set_uint, &nskip},
96 GNUNET_GETOPT_OPTION_END 91 GNUNET_GETOPT_OPTION_END
97 }; 92 };
98 int ret; 93 int ret;
diff --git a/src/testing/testing.c b/src/testing/testing.c
index bab7976ea..ba7bf827e 100644
--- a/src/testing/testing.c
+++ b/src/testing/testing.c
@@ -907,6 +907,7 @@ update_config_sections (void *cls,
907 { 907 {
908 ikeys[key] = ptr; 908 ikeys[key] = ptr;
909 ptr = strstr (ptr, ";"); 909 ptr = strstr (ptr, ";");
910 GNUNET_assert (NULL != ptr); /* worked just before... */
910 *ptr = '\0'; 911 *ptr = '\0';
911 ptr++; 912 ptr++;
912 } 913 }
diff --git a/src/topology/friends.c b/src/topology/friends.c
index 59c70e4b0..a960fad17 100644
--- a/src/topology/friends.c
+++ b/src/topology/friends.c
@@ -58,14 +58,20 @@ GNUNET_FRIENDS_parse (const struct GNUNET_CONFIGURATION_Handle *cfg,
58 return GNUNET_SYSERR; 58 return GNUNET_SYSERR;
59 } 59 }
60 if ( (GNUNET_OK != GNUNET_DISK_file_test (fn)) && 60 if ( (GNUNET_OK != GNUNET_DISK_file_test (fn)) &&
61 (GNUNET_OK != GNUNET_DISK_fn_write (fn, NULL, 0, 61 (GNUNET_OK != GNUNET_DISK_fn_write (fn,
62 NULL,
63 0,
62 GNUNET_DISK_PERM_USER_READ | 64 GNUNET_DISK_PERM_USER_READ |
63 GNUNET_DISK_PERM_USER_WRITE)) ) 65 GNUNET_DISK_PERM_USER_WRITE |
64 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "write", fn); 66 GNUNET_DISK_OPEN_CREATE)) )
67 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
68 "write",
69 fn);
65 if ( (GNUNET_OK != 70 if ( (GNUNET_OK !=
66 GNUNET_DISK_file_size (fn, 71 GNUNET_DISK_file_size (fn,
67 &fsize, 72 &fsize,
68 GNUNET_NO, GNUNET_YES)) || 73 GNUNET_NO,
74 GNUNET_YES)) ||
69 (0 == fsize) ) 75 (0 == fsize) )
70 { 76 {
71 GNUNET_free (fn); 77 GNUNET_free (fn);
@@ -93,8 +99,8 @@ GNUNET_FRIENDS_parse (const struct GNUNET_CONFIGURATION_Handle *cfg,
93 pos++; 99 pos++;
94 if (GNUNET_OK != 100 if (GNUNET_OK !=
95 GNUNET_CRYPTO_eddsa_public_key_from_string (&data[start], 101 GNUNET_CRYPTO_eddsa_public_key_from_string (&data[start],
96 pos - start, 102 pos - start,
97 &pid.public_key)) 103 &pid.public_key))
98 { 104 {
99 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 105 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
100 _("Syntax error in FRIENDS file at offset %llu, skipping bytes `%.*s'.\n"), 106 _("Syntax error in FRIENDS file at offset %llu, skipping bytes `%.*s'.\n"),
diff --git a/src/topology/gnunet-daemon-topology.c b/src/topology/gnunet-daemon-topology.c
index 067ebce23..537ffe059 100644
--- a/src/topology/gnunet-daemon-topology.c
+++ b/src/topology/gnunet-daemon-topology.c
@@ -499,7 +499,7 @@ schedule_next_hello (void *cls)
499 /* find applicable HELLOs */ 499 /* find applicable HELLOs */
500 fah.peer = pl; 500 fah.peer = pl;
501 fah.result = NULL; 501 fah.result = NULL;
502 fah.max_size = GNUNET_SERVER_MAX_MESSAGE_SIZE - 1; 502 fah.max_size = GNUNET_MAX_MESSAGE_SIZE - 1;
503 fah.next_adv = GNUNET_TIME_UNIT_FOREVER_REL; 503 fah.next_adv = GNUNET_TIME_UNIT_FOREVER_REL;
504 GNUNET_CONTAINER_multipeermap_iterate (peers, 504 GNUNET_CONTAINER_multipeermap_iterate (peers,
505 &find_advertisable_hello, 505 &find_advertisable_hello,
diff --git a/src/transport/Makefile.am b/src/transport/Makefile.am
index acc2557c6..7687f2348 100644
--- a/src/transport/Makefile.am
+++ b/src/transport/Makefile.am
@@ -191,6 +191,8 @@ libexec_PROGRAMS = \
191 $(BT_BIN) \ 191 $(BT_BIN) \
192 gnunet-service-transport 192 gnunet-service-transport
193 193
194
195
194bin_PROGRAMS = \ 196bin_PROGRAMS = \
195 gnunet-transport \ 197 gnunet-transport \
196 gnunet-transport-certificate-creation 198 gnunet-transport-certificate-creation
@@ -561,7 +563,7 @@ TESTS = \
561 $(HTTP_API_TIMEOUT_TEST) \ 563 $(HTTP_API_TIMEOUT_TEST) \
562 $(HTTPS_API_TIMEOUT_TEST) \ 564 $(HTTPS_API_TIMEOUT_TEST) \
563 $(WLAN_TIMEOUT_TEST) \ 565 $(WLAN_TIMEOUT_TEST) \
564 $(BT_TIMEOUT_TEST) 566 $(BT_TIMEOUT_TEST)
565if HAVE_GETOPT_BINARY 567if HAVE_GETOPT_BINARY
566TESTS += \ 568TESTS += \
567test_transport_api_slow_ats 569test_transport_api_slow_ats
diff --git a/src/transport/gnunet-helper-transport-wlan-dummy.c b/src/transport/gnunet-helper-transport-wlan-dummy.c
index 684546314..63ed9c4b7 100644
--- a/src/transport/gnunet-helper-transport-wlan-dummy.c
+++ b/src/transport/gnunet-helper-transport-wlan-dummy.c
@@ -120,11 +120,11 @@ send_mac_to_plugin (char *buffer, struct GNUNET_TRANSPORT_WLAN_MacAddress *mac)
120 * type to the output forward and copy it to the buffer for stdout. 120 * type to the output forward and copy it to the buffer for stdout.
121 * 121 *
122 * @param cls the 'struct SendBuffer' to copy the converted message to 122 * @param cls the 'struct SendBuffer' to copy the converted message to
123 * @param client unused
124 * @param hdr inbound message from the FIFO 123 * @param hdr inbound message from the FIFO
125 */ 124 */
126static int 125static int
127stdin_send (void *cls, void *client, const struct GNUNET_MessageHeader *hdr) 126stdin_send (void *cls,
127 const struct GNUNET_MessageHeader *hdr)
128{ 128{
129 struct SendBuffer *write_pout = cls; 129 struct SendBuffer *write_pout = cls;
130 const struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *in; 130 const struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *in;
@@ -166,11 +166,11 @@ stdin_send (void *cls, void *client, const struct GNUNET_MessageHeader *hdr)
166 * We read a full message from stdin. Copy it to our send buffer. 166 * We read a full message from stdin. Copy it to our send buffer.
167 * 167 *
168 * @param cls the 'struct SendBuffer' to copy to 168 * @param cls the 'struct SendBuffer' to copy to
169 * @param client unused
170 * @param hdr the message we received to copy to the buffer 169 * @param hdr the message we received to copy to the buffer
171 */ 170 */
172static int 171static int
173file_in_send (void *cls, void *client, const struct GNUNET_MessageHeader *hdr) 172file_in_send (void *cls,
173 const struct GNUNET_MessageHeader *hdr)
174{ 174{
175 struct SendBuffer *write_std = cls; 175 struct SendBuffer *write_std = cls;
176 uint16_t sendsize; 176 uint16_t sendsize;
@@ -213,8 +213,8 @@ main (int argc, char *argv[])
213 fd_set wfds; 213 fd_set wfds;
214 struct timeval tv; 214 struct timeval tv;
215 int retval; 215 int retval;
216 struct GNUNET_SERVER_MessageStreamTokenizer *stdin_mst = NULL; 216 struct GNUNET_MessageStreamTokenizer *stdin_mst = NULL;
217 struct GNUNET_SERVER_MessageStreamTokenizer *file_in_mst = NULL; 217 struct GNUNET_MessageStreamTokenizer *file_in_mst = NULL;
218 struct GNUNET_TRANSPORT_WLAN_MacAddress macaddr; 218 struct GNUNET_TRANSPORT_WLAN_MacAddress macaddr;
219 int first; 219 int first;
220 220
@@ -340,8 +340,8 @@ main (int argc, char *argv[])
340 write_std.pos = 0; 340 write_std.pos = 0;
341 write_pout.size = 0; 341 write_pout.size = 0;
342 write_pout.pos = 0; 342 write_pout.pos = 0;
343 stdin_mst = GNUNET_SERVER_mst_create (&stdin_send, &write_pout); 343 stdin_mst = GNUNET_MST_create (&stdin_send, &write_pout);
344 file_in_mst = GNUNET_SERVER_mst_create (&file_in_send, &write_std); 344 file_in_mst = GNUNET_MST_create (&file_in_send, &write_std);
345 345
346 /* Send 'random' mac address */ 346 /* Send 'random' mac address */
347 macaddr.mac[0] = 0x13; 347 macaddr.mac[0] = 0x13;
@@ -453,8 +453,9 @@ main (int argc, char *argv[])
453 } 453 }
454 else if (0 < readsize) 454 else if (0 < readsize)
455 { 455 {
456 GNUNET_SERVER_mst_receive (stdin_mst, NULL, readbuf, readsize, 456 GNUNET_MST_from_buffer (stdin_mst,
457 GNUNET_NO, GNUNET_NO); 457 readbuf, readsize,
458 GNUNET_NO, GNUNET_NO);
458 459
459 } 460 }
460 else 461 else
@@ -475,8 +476,9 @@ main (int argc, char *argv[])
475 } 476 }
476 else if (0 < readsize) 477 else if (0 < readsize)
477 { 478 {
478 GNUNET_SERVER_mst_receive (file_in_mst, NULL, readbuf, readsize, 479 GNUNET_MST_from_buffer (file_in_mst,
479 GNUNET_NO, GNUNET_NO); 480 readbuf, readsize,
481 GNUNET_NO, GNUNET_NO);
480 } 482 }
481 else 483 else
482 { 484 {
@@ -489,9 +491,9 @@ main (int argc, char *argv[])
489end: 491end:
490 /* clean up */ 492 /* clean up */
491 if (NULL != stdin_mst) 493 if (NULL != stdin_mst)
492 GNUNET_SERVER_mst_destroy (stdin_mst); 494 GNUNET_MST_destroy (stdin_mst);
493 if (NULL != file_in_mst) 495 if (NULL != file_in_mst)
494 GNUNET_SERVER_mst_destroy (file_in_mst); 496 GNUNET_MST_destroy (file_in_mst);
495 497
496 if (NULL != fpout) 498 if (NULL != fpout)
497 fclose (fpout); 499 fclose (fpout);
diff --git a/src/transport/gnunet-service-transport_validation.c b/src/transport/gnunet-service-transport_validation.c
index 505626b59..4a6d427be 100644
--- a/src/transport/gnunet-service-transport_validation.c
+++ b/src/transport/gnunet-service-transport_validation.c
@@ -599,7 +599,7 @@ transmit_ping_if_allowed (void *cls,
599 ping.challenge = htonl (ve->challenge); 599 ping.challenge = htonl (ve->challenge);
600 ping.target = *pid; 600 ping.target = *pid;
601 601
602 if (tsize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) 602 if (tsize >= GNUNET_MAX_MESSAGE_SIZE)
603 { 603 {
604 GNUNET_break (0); 604 GNUNET_break (0);
605 hsize = 0; 605 hsize = 0;
diff --git a/src/transport/gnunet-transport-certificate-creation.c b/src/transport/gnunet-transport-certificate-creation.c
index 129df7b35..edaf4773a 100644
--- a/src/transport/gnunet-transport-certificate-creation.c
+++ b/src/transport/gnunet-transport-certificate-creation.c
@@ -44,7 +44,7 @@ make_dev_zero (int fd,
44 GNUNET_assert (-1 != z); 44 GNUNET_assert (-1 != z);
45 if (z == fd) 45 if (z == fd)
46 return; 46 return;
47 dup2 (z, fd); 47 GNUNET_break (fd == dup2 (z, fd));
48 GNUNET_assert (0 == close (z)); 48 GNUNET_assert (0 == close (z));
49} 49}
50#endif 50#endif
diff --git a/src/transport/gnunet-transport-profiler.c b/src/transport/gnunet-transport-profiler.c
index dceff7e3b..9292c42d4 100644
--- a/src/transport/gnunet-transport-profiler.c
+++ b/src/transport/gnunet-transport-profiler.c
@@ -151,7 +151,7 @@ static struct GNUNET_PeerIdentity pid;
151/** 151/**
152 * Selected level of verbosity. 152 * Selected level of verbosity.
153 */ 153 */
154static int verbosity; 154static unsigned int verbosity;
155 155
156 156
157/** 157/**
@@ -520,7 +520,7 @@ run (void *cls,
520 cfg = (struct GNUNET_CONFIGURATION_Handle *) mycfg; 520 cfg = (struct GNUNET_CONFIGURATION_Handle *) mycfg;
521 521
522 ret = 1; 522 ret = 1;
523 if (GNUNET_SERVER_MAX_MESSAGE_SIZE <= benchmark_size) 523 if (GNUNET_MAX_MESSAGE_SIZE <= benchmark_size)
524 { 524 {
525 FPRINTF (stderr, 525 FPRINTF (stderr,
526 "Message size too big!\n"); 526 "Message size too big!\n");
@@ -610,26 +610,36 @@ main (int argc, char * const *argv)
610 benchmark_iterations = DEFAULT_ITERATION_COUNT; 610 benchmark_iterations = DEFAULT_ITERATION_COUNT;
611 benchmark_running = GNUNET_NO; 611 benchmark_running = GNUNET_NO;
612 612
613 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 613 struct GNUNET_GETOPT_CommandLineOption options[] = {
614 614
615 { 's', "send", NULL, 615 GNUNET_GETOPT_OPTION_SET_ONE ('s',
616 gettext_noop ("send data to peer"), 616 "send",
617 0, &GNUNET_GETOPT_set_one, &benchmark_send}, 617 gettext_noop ("send data to peer"),
618 { 'r', "receive", NULL, gettext_noop 618 &benchmark_send),
619 ("receive data from peer"), 0, 619 GNUNET_GETOPT_OPTION_SET_ONE ('r',
620 &GNUNET_GETOPT_set_one, &benchmark_receive}, 620 "receive",
621 { 'i', "iterations", NULL, gettext_noop 621 gettext_noop ("receive data from peer"),
622 ("iterations"), 1, 622 &benchmark_receive),
623 &GNUNET_GETOPT_set_uint, &benchmark_iterations}, 623 GNUNET_GETOPT_OPTION_SET_UINT ('i',
624 { 'n', "number", NULL, gettext_noop 624 "iterations",
625 ("number of messages to send"), 1, 625 NULL,
626 &GNUNET_GETOPT_set_uint, &benchmark_count}, 626 gettext_noop ("iterations"),
627 { 'm', "messagesize", NULL, gettext_noop 627 &benchmark_iterations),
628 ("message size to use"), 1, 628 GNUNET_GETOPT_OPTION_SET_UINT ('n',
629 &GNUNET_GETOPT_set_uint, &benchmark_size}, 629 "number",
630 { 'p', "peer", "PEER", 630 NULL,
631 gettext_noop ("peer identity"), 1, &GNUNET_GETOPT_set_string, 631 gettext_noop ("number of messages to send"),
632 &cpid }, 632 &benchmark_count),
633 GNUNET_GETOPT_OPTION_SET_UINT ('m',
634 "messagesize",
635 NULL,
636 gettext_noop ("message size to use"),
637 &benchmark_size),
638 GNUNET_GETOPT_OPTION_STRING ('p',
639 "peer",
640 "PEER",
641 gettext_noop ("peer identity"),
642 &cpid),
633 GNUNET_GETOPT_OPTION_VERBOSE (&verbosity), 643 GNUNET_GETOPT_OPTION_VERBOSE (&verbosity),
634 GNUNET_GETOPT_OPTION_END 644 GNUNET_GETOPT_OPTION_END
635 }; 645 };
diff --git a/src/transport/gnunet-transport.c b/src/transport/gnunet-transport.c
index fcfc94ac8..8624b09b4 100644
--- a/src/transport/gnunet-transport.c
+++ b/src/transport/gnunet-transport.c
@@ -167,11 +167,6 @@ struct PeerResolutionContext
167#define BLOCKSIZE 4 167#define BLOCKSIZE 4
168 168
169/** 169/**
170 * Which peer should we connect to?
171 */
172static char *cpid;
173
174/**
175 * Handle to transport service. 170 * Handle to transport service.
176 */ 171 */
177static struct GNUNET_TRANSPORT_CoreHandle *handle; 172static struct GNUNET_TRANSPORT_CoreHandle *handle;
@@ -283,7 +278,7 @@ static struct GNUNET_TRANSPORT_PluginMonitor *pm;
283 278
284/** 279/**
285 * Identity of the peer we transmit to / connect to. 280 * Identity of the peer we transmit to / connect to.
286 * (equivalent to 'cpid' string). 281 * ('-p' command-line option).
287 */ 282 */
288static struct GNUNET_PeerIdentity pid; 283static struct GNUNET_PeerIdentity pid;
289 284
@@ -295,7 +290,7 @@ static struct GNUNET_SCHEDULER_Task *op_timeout;
295/** 290/**
296 * Selected level of verbosity. 291 * Selected level of verbosity.
297 */ 292 */
298static int verbosity; 293static unsigned int verbosity;
299 294
300/** 295/**
301 * Resolver process handle. 296 * Resolver process handle.
@@ -485,7 +480,7 @@ operation_timeout (void *cls)
485 _("Failed to resolve address for peer `%s'\n"), 480 _("Failed to resolve address for peer `%s'\n"),
486 GNUNET_i2s (&cur->addrcp->peer)); 481 GNUNET_i2s (&cur->addrcp->peer));
487 482
488 GNUNET_CONTAINER_DLL_remove(rc_head, 483 GNUNET_CONTAINER_DLL_remove(rc_head,
489 rc_tail, 484 rc_tail,
490 cur); 485 cur);
491 GNUNET_TRANSPORT_address_to_string_cancel (cur->asc); 486 GNUNET_TRANSPORT_address_to_string_cancel (cur->asc);
@@ -729,7 +724,7 @@ print_info (const struct GNUNET_PeerIdentity *id,
729 GNUNET_STRINGS_absolute_time_to_string (state_timeout)); 724 GNUNET_STRINGS_absolute_time_to_string (state_timeout));
730 } 725 }
731 else if ( (GNUNET_YES == iterate_connections) && 726 else if ( (GNUNET_YES == iterate_connections) &&
732 (GNUNET_TRANSPORT_is_connected(state)) ) 727 (GNUNET_TRANSPORT_is_connected(state)) )
733 { 728 {
734 /* Only connected peers, skip state */ 729 /* Only connected peers, skip state */
735 FPRINTF (stdout, 730 FPRINTF (stdout,
@@ -1089,10 +1084,9 @@ plugin_monitoring_cb (void *cls,
1089 } 1084 }
1090 return; /* shutdown */ 1085 return; /* shutdown */
1091 } 1086 }
1092 if ( (NULL != cpid) && 1087 if (0 != memcmp (&info->address->peer,
1093 (0 != memcmp (&info->address->peer, 1088 &pid,
1094 cpid, 1089 sizeof (struct GNUNET_PeerIdentity)))
1095 sizeof (struct GNUNET_PeerIdentity))) )
1096 return; /* filtered */ 1090 return; /* filtered */
1097 if (NULL == addr) 1091 if (NULL == addr)
1098 { 1092 {
@@ -1241,21 +1235,11 @@ run (void *cls,
1241 const char *cfgfile, 1235 const char *cfgfile,
1242 const struct GNUNET_CONFIGURATION_Handle *mycfg) 1236 const struct GNUNET_CONFIGURATION_Handle *mycfg)
1243{ 1237{
1238 static struct GNUNET_PeerIdentity zero_pid;
1244 int counter = 0; 1239 int counter = 0;
1245 ret = 1; 1240 ret = 1;
1246 1241
1247 cfg = (struct GNUNET_CONFIGURATION_Handle *) mycfg; 1242 cfg = (struct GNUNET_CONFIGURATION_Handle *) mycfg;
1248 if ( (NULL != cpid) &&
1249 (GNUNET_OK !=
1250 GNUNET_CRYPTO_eddsa_public_key_from_string (cpid,
1251 strlen (cpid),
1252 &pid.public_key)))
1253 {
1254 FPRINTF (stderr,
1255 _("Failed to parse peer identity `%s'\n"),
1256 cpid);
1257 return;
1258 }
1259 1243
1260 counter = benchmark_send + benchmark_receive + iterate_connections 1244 counter = benchmark_send + benchmark_receive + iterate_connections
1261 + monitor_connections + monitor_connects + do_disconnect + 1245 + monitor_connections + monitor_connects + do_disconnect +
@@ -1290,7 +1274,9 @@ run (void *cls,
1290 1274
1291 if (do_disconnect) /* -D: Disconnect from peer */ 1275 if (do_disconnect) /* -D: Disconnect from peer */
1292 { 1276 {
1293 if (NULL == cpid) 1277 if (0 == memcmp (&zero_pid,
1278 &pid,
1279 sizeof (pid)))
1294 { 1280 {
1295 FPRINTF (stderr, 1281 FPRINTF (stderr,
1296 _("Option `%s' makes no sense without option `%s'.\n"), 1282 _("Option `%s' makes no sense without option `%s'.\n"),
@@ -1315,7 +1301,9 @@ run (void *cls,
1315 } 1301 }
1316 else if (benchmark_send) /* -s: Benchmark sending */ 1302 else if (benchmark_send) /* -s: Benchmark sending */
1317 { 1303 {
1318 if (NULL == cpid) 1304 if (0 == memcmp (&zero_pid,
1305 &pid,
1306 sizeof (pid)))
1319 { 1307 {
1320 FPRINTF (stderr, 1308 FPRINTF (stderr,
1321 _("Option `%s' makes no sense without option `%s'.\n"), 1309 _("Option `%s' makes no sense without option `%s'.\n"),
@@ -1352,7 +1340,7 @@ run (void *cls,
1352 NULL), 1340 NULL),
1353 GNUNET_MQ_handler_end () 1341 GNUNET_MQ_handler_end ()
1354 }; 1342 };
1355 1343
1356 handle = GNUNET_TRANSPORT_core_connect (cfg, 1344 handle = GNUNET_TRANSPORT_core_connect (cfg,
1357 NULL, 1345 NULL,
1358 handlers, 1346 handlers,
@@ -1378,7 +1366,7 @@ run (void *cls,
1378 else if (iterate_connections) /* -i: List information about peers once */ 1366 else if (iterate_connections) /* -i: List information about peers once */
1379 { 1367 {
1380 pic = GNUNET_TRANSPORT_monitor_peers (cfg, 1368 pic = GNUNET_TRANSPORT_monitor_peers (cfg,
1381 (NULL == cpid) ? NULL : &pid, 1369 &pid,
1382 GNUNET_YES, 1370 GNUNET_YES,
1383 &process_peer_iteration_cb, 1371 &process_peer_iteration_cb,
1384 (void *) cfg); 1372 (void *) cfg);
@@ -1391,7 +1379,7 @@ run (void *cls,
1391 monitored_peers = GNUNET_CONTAINER_multipeermap_create (10, 1379 monitored_peers = GNUNET_CONTAINER_multipeermap_create (10,
1392 GNUNET_NO); 1380 GNUNET_NO);
1393 pic = GNUNET_TRANSPORT_monitor_peers (cfg, 1381 pic = GNUNET_TRANSPORT_monitor_peers (cfg,
1394 (NULL == cpid) ? NULL : &pid, 1382 &pid,
1395 GNUNET_NO, 1383 GNUNET_NO,
1396 &process_peer_monitoring_cb, 1384 &process_peer_monitoring_cb,
1397 NULL); 1385 NULL);
@@ -1439,37 +1427,49 @@ main (int argc,
1439 char * const *argv) 1427 char * const *argv)
1440{ 1428{
1441 int res; 1429 int res;
1442 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 1430 struct GNUNET_GETOPT_CommandLineOption options[] = {
1443 { 'a', "all", NULL, 1431 GNUNET_GETOPT_OPTION_SET_ONE ('a',
1444 gettext_noop ("print information for all peers (instead of only connected peers)"), 1432 "all",
1445 0, &GNUNET_GETOPT_set_one, &iterate_all }, 1433 gettext_noop ("print information for all peers (instead of only connected peers)"),
1446 { 'b', "benchmark", NULL, 1434 &iterate_all),
1447 gettext_noop ("measure how fast we are receiving data from all peers (until CTRL-C)"), 1435 GNUNET_GETOPT_OPTION_SET_ONE ('b',
1448 0, &GNUNET_GETOPT_set_one, &benchmark_receive }, 1436 "benchmark",
1449 { 'D', "disconnect", 1437 gettext_noop ("measure how fast we are receiving data from all peers (until CTRL-C)"),
1450 NULL, gettext_noop ("disconnect from a peer"), 0, 1438 &benchmark_receive),
1451 &GNUNET_GETOPT_set_one, &do_disconnect }, 1439 GNUNET_GETOPT_OPTION_SET_ONE ('D',
1452 { 'i', "information", NULL, 1440 "disconnect",
1453 gettext_noop ("provide information about all current connections (once)"), 1441 gettext_noop ("disconnect from a peer"),
1454 0, &GNUNET_GETOPT_set_one, &iterate_connections }, 1442 &do_disconnect),
1455 { 'm', "monitor", NULL, 1443 GNUNET_GETOPT_OPTION_SET_ONE ('i',
1456 gettext_noop ("provide information about all current connections (continuously)"), 1444 "information",
1457 0, &GNUNET_GETOPT_set_one, &monitor_connections }, 1445 gettext_noop ("provide information about all current connections (once)"),
1458 { 'e', "events", NULL, 1446 &iterate_connections),
1459 gettext_noop ("provide information about all connects and disconnect events (continuously)"), 1447 GNUNET_GETOPT_OPTION_SET_ONE ('m',
1460 0, &GNUNET_GETOPT_set_one, &monitor_connects }, 1448 "monitor",
1461 { 'n', "numeric", 1449 gettext_noop ("provide information about all current connections (continuously)"),
1462 NULL, gettext_noop ("do not resolve hostnames"), 0, 1450 &monitor_connections),
1463 &GNUNET_GETOPT_set_one, &numeric }, 1451 GNUNET_GETOPT_OPTION_SET_ONE ('e',
1464 { 'p', "peer", "PEER", 1452 "events",
1465 gettext_noop ("peer identity"), 1, &GNUNET_GETOPT_set_string, 1453 gettext_noop ("provide information about all connects and disconnect events (continuously)"),
1466 &cpid }, 1454 &monitor_connects),
1467 { 'P', "plugins", NULL, 1455 GNUNET_GETOPT_OPTION_SET_ONE ('n',
1468 gettext_noop ("monitor plugin sessions"), 0, &GNUNET_GETOPT_set_one, 1456 "numeric",
1469 &monitor_plugins }, 1457 gettext_noop ("do not resolve hostnames"),
1470 { 's', "send", NULL, gettext_noop 1458 &numeric),
1471 ("send data for benchmarking to the other peer (until CTRL-C)"), 0, 1459 GNUNET_GETOPT_OPTION_SET_BASE32_AUTO ('p',
1472 &GNUNET_GETOPT_set_one, &benchmark_send }, 1460 "peer",
1461 "PEER",
1462 gettext_noop ("peer identity"),
1463 &pid),
1464 GNUNET_GETOPT_OPTION_SET_ONE ('P',
1465 "plugins",
1466 gettext_noop ("monitor plugin sessions"),
1467 &monitor_plugins),
1468 GNUNET_GETOPT_OPTION_SET_ONE ('s',
1469 "send",
1470 gettext_noop
1471 ("send data for benchmarking to the other peer (until CTRL-C)"),
1472 &benchmark_send),
1473 GNUNET_GETOPT_OPTION_VERBOSE (&verbosity), 1473 GNUNET_GETOPT_OPTION_VERBOSE (&verbosity),
1474 GNUNET_GETOPT_OPTION_END 1474 GNUNET_GETOPT_OPTION_END
1475 }; 1475 };
diff --git a/src/transport/plugin_transport_http_client.c b/src/transport/plugin_transport_http_client.c
index ceed94af8..e20948c5a 100644
--- a/src/transport/plugin_transport_http_client.c
+++ b/src/transport/plugin_transport_http_client.c
@@ -221,7 +221,7 @@ struct GNUNET_ATS_Session
221 /** 221 /**
222 * Message stream tokenizer for incoming data 222 * Message stream tokenizer for incoming data
223 */ 223 */
224 struct GNUNET_SERVER_MessageStreamTokenizer *msg_tk; 224 struct GNUNET_MessageStreamTokenizer *msg_tk;
225 225
226 /** 226 /**
227 * Session timeout task 227 * Session timeout task
@@ -528,7 +528,7 @@ client_delete_session (struct GNUNET_ATS_Session *s)
528 GNUNET_TRANSPORT_SS_DONE); 528 GNUNET_TRANSPORT_SS_DONE);
529 if (NULL != s->msg_tk) 529 if (NULL != s->msg_tk)
530 { 530 {
531 GNUNET_SERVER_mst_destroy (s->msg_tk); 531 GNUNET_MST_destroy (s->msg_tk);
532 s->msg_tk = NULL; 532 s->msg_tk = NULL;
533 } 533 }
534 GNUNET_HELLO_address_free (s->address); 534 GNUNET_HELLO_address_free (s->address);
@@ -1158,13 +1158,11 @@ client_wake_up (void *cls)
1158 * Callback for message stream tokenizer 1158 * Callback for message stream tokenizer
1159 * 1159 *
1160 * @param cls the session 1160 * @param cls the session
1161 * @param client not used
1162 * @param message the message received 1161 * @param message the message received
1163 * @return always #GNUNET_OK 1162 * @return always #GNUNET_OK
1164 */ 1163 */
1165static int 1164static int
1166client_receive_mst_cb (void *cls, 1165client_receive_mst_cb (void *cls,
1167 void *client,
1168 const struct GNUNET_MessageHeader *message) 1166 const struct GNUNET_MessageHeader *message)
1169{ 1167{
1170 struct GNUNET_ATS_Session *s = cls; 1168 struct GNUNET_ATS_Session *s = cls;
@@ -1274,14 +1272,13 @@ client_receive (void *stream,
1274 return CURL_WRITEFUNC_PAUSE; 1272 return CURL_WRITEFUNC_PAUSE;
1275 } 1273 }
1276 if (NULL == s->msg_tk) 1274 if (NULL == s->msg_tk)
1277 s->msg_tk = GNUNET_SERVER_mst_create (&client_receive_mst_cb, 1275 s->msg_tk = GNUNET_MST_create (&client_receive_mst_cb,
1278 s); 1276 s);
1279 GNUNET_SERVER_mst_receive (s->msg_tk, 1277 GNUNET_MST_from_buffer (s->msg_tk,
1280 s, 1278 stream,
1281 stream, 1279 len,
1282 len, 1280 GNUNET_NO,
1283 GNUNET_NO, 1281 GNUNET_NO);
1284 GNUNET_NO);
1285 return len; 1282 return len;
1286} 1283}
1287 1284
@@ -1641,7 +1638,7 @@ client_connect_get (struct GNUNET_ATS_Session *s)
1641 CURLOPT_CONNECTTIMEOUT_MS, 1638 CURLOPT_CONNECTTIMEOUT_MS,
1642 (long) (HTTP_CLIENT_NOT_VALIDATED_TIMEOUT.rel_value_us / 1000LL)); 1639 (long) (HTTP_CLIENT_NOT_VALIDATED_TIMEOUT.rel_value_us / 1000LL));
1643 curl_easy_setopt (s->get.easyhandle, CURLOPT_BUFFERSIZE, 1640 curl_easy_setopt (s->get.easyhandle, CURLOPT_BUFFERSIZE,
1644 2 * GNUNET_SERVER_MAX_MESSAGE_SIZE); 1641 2 * GNUNET_MAX_MESSAGE_SIZE);
1645#if CURL_TCP_NODELAY 1642#if CURL_TCP_NODELAY
1646 curl_easy_setopt (ps->recv_endpoint, 1643 curl_easy_setopt (ps->recv_endpoint,
1647 CURLOPT_TCP_NODELAY, 1644 CURLOPT_TCP_NODELAY,
@@ -1818,7 +1815,7 @@ client_connect_put (struct GNUNET_ATS_Session *s)
1818 CURLOPT_CONNECTTIMEOUT_MS, 1815 CURLOPT_CONNECTTIMEOUT_MS,
1819 (long) (HTTP_CLIENT_NOT_VALIDATED_TIMEOUT.rel_value_us / 1000LL)); 1816 (long) (HTTP_CLIENT_NOT_VALIDATED_TIMEOUT.rel_value_us / 1000LL));
1820 curl_easy_setopt (s->put.easyhandle, CURLOPT_BUFFERSIZE, 1817 curl_easy_setopt (s->put.easyhandle, CURLOPT_BUFFERSIZE,
1821 2 * GNUNET_SERVER_MAX_MESSAGE_SIZE); 1818 2 * GNUNET_MAX_MESSAGE_SIZE);
1822#if CURL_TCP_NODELAY 1819#if CURL_TCP_NODELAY
1823 curl_easy_setopt (s->put.easyhandle, CURLOPT_TCP_NODELAY, 1); 1820 curl_easy_setopt (s->put.easyhandle, CURLOPT_TCP_NODELAY, 1);
1824#endif 1821#endif
diff --git a/src/transport/plugin_transport_http_server.c b/src/transport/plugin_transport_http_server.c
index 63c67b81c..ff2d68602 100644
--- a/src/transport/plugin_transport_http_server.c
+++ b/src/transport/plugin_transport_http_server.c
@@ -201,7 +201,7 @@ struct GNUNET_ATS_Session
201 /** 201 /**
202 * Message stream tokenizer for incoming data 202 * Message stream tokenizer for incoming data
203 */ 203 */
204 struct GNUNET_SERVER_MessageStreamTokenizer *msg_tk; 204 struct GNUNET_MessageStreamTokenizer *msg_tk;
205 205
206 /** 206 /**
207 * Client recv handle 207 * Client recv handle
@@ -608,7 +608,7 @@ server_delete_session (struct GNUNET_ATS_Session *s)
608 } 608 }
609 if (NULL != s->msg_tk) 609 if (NULL != s->msg_tk)
610 { 610 {
611 GNUNET_SERVER_mst_destroy (s->msg_tk); 611 GNUNET_MST_destroy (s->msg_tk);
612 s->msg_tk = NULL; 612 s->msg_tk = NULL;
613 } 613 }
614 GNUNET_HELLO_address_free (s->address); 614 GNUNET_HELLO_address_free (s->address);
@@ -1621,13 +1621,11 @@ server_send_callback (void *cls,
1621 * Callback called by MessageStreamTokenizer when a message has arrived 1621 * Callback called by MessageStreamTokenizer when a message has arrived
1622 * 1622 *
1623 * @param cls current session as closure 1623 * @param cls current session as closure
1624 * @param client client
1625 * @param message the message to be forwarded to transport service 1624 * @param message the message to be forwarded to transport service
1626 * @return #GNUNET_OK 1625 * @return #GNUNET_OK
1627 */ 1626 */
1628static int 1627static int
1629server_receive_mst_cb (void *cls, 1628server_receive_mst_cb (void *cls,
1630 void *client,
1631 const struct GNUNET_MessageHeader *message) 1629 const struct GNUNET_MessageHeader *message)
1632{ 1630{
1633 struct GNUNET_ATS_Session *s = cls; 1631 struct GNUNET_ATS_Session *s = cls;
@@ -1847,13 +1845,16 @@ server_access_cb (void *cls,
1847 *upload_data_size); 1845 *upload_data_size);
1848 if (s->msg_tk == NULL) 1846 if (s->msg_tk == NULL)
1849 { 1847 {
1850 s->msg_tk = GNUNET_SERVER_mst_create (&server_receive_mst_cb, s); 1848 s->msg_tk = GNUNET_MST_create (&server_receive_mst_cb,
1849 s);
1851 } 1850 }
1852 GNUNET_SERVER_mst_receive (s->msg_tk, s, upload_data, *upload_data_size, 1851 GNUNET_MST_from_buffer (s->msg_tk,
1853 GNUNET_NO, GNUNET_NO); 1852 upload_data,
1853 *upload_data_size,
1854 GNUNET_NO, GNUNET_NO);
1854 server_mhd_connection_timeout (plugin, s, 1855 server_mhd_connection_timeout (plugin, s,
1855 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value_us / 1000LL 1856 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value_us / 1000LL
1856 / 1000LL); 1857 / 1000LL);
1857 (*upload_data_size) = 0; 1858 (*upload_data_size) = 0;
1858 } 1859 }
1859 else 1860 else
@@ -1935,7 +1936,7 @@ server_disconnect_cb (void *cls,
1935 sc->session->server_recv = NULL; 1936 sc->session->server_recv = NULL;
1936 if (NULL != sc->session->msg_tk) 1937 if (NULL != sc->session->msg_tk)
1937 { 1938 {
1938 GNUNET_SERVER_mst_destroy (sc->session->msg_tk); 1939 GNUNET_MST_destroy (sc->session->msg_tk);
1939 sc->session->msg_tk = NULL; 1940 sc->session->msg_tk = NULL;
1940 } 1941 }
1941 } 1942 }
@@ -2223,7 +2224,7 @@ run_mhd_start_daemon (struct HTTP_Server_Plugin *plugin,
2223 timeout, 2224 timeout,
2224 MHD_OPTION_CONNECTION_MEMORY_LIMIT, 2225 MHD_OPTION_CONNECTION_MEMORY_LIMIT,
2225 (size_t) (2 * 2226 (size_t) (2 *
2226 GNUNET_SERVER_MAX_MESSAGE_SIZE), 2227 GNUNET_MAX_MESSAGE_SIZE),
2227 MHD_OPTION_NOTIFY_COMPLETED, 2228 MHD_OPTION_NOTIFY_COMPLETED,
2228 &server_disconnect_cb, plugin, 2229 &server_disconnect_cb, plugin,
2229 MHD_OPTION_EXTERNAL_LOGGER, 2230 MHD_OPTION_EXTERNAL_LOGGER,
@@ -2757,7 +2758,7 @@ server_start_report_addresses (struct HTTP_Server_Plugin *plugin)
2757 return; 2758 return;
2758 } 2759 }
2759 2760
2760 plugin->nat 2761 plugin->nat
2761 = GNUNET_NAT_register (plugin->env->cfg, 2762 = GNUNET_NAT_register (plugin->env->cfg,
2762 "transport-http_server", 2763 "transport-http_server",
2763 IPPROTO_TCP, 2764 IPPROTO_TCP,
diff --git a/src/transport/plugin_transport_tcp.c b/src/transport/plugin_transport_tcp.c
index 34bbd00e0..a63013caa 100644
--- a/src/transport/plugin_transport_tcp.c
+++ b/src/transport/plugin_transport_tcp.c
@@ -45,10 +45,538 @@
45 */ 45 */
46#define NAT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10) 46#define NAT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
47 47
48GNUNET_NETWORK_STRUCT_BEGIN 48/**
49 * Opaque handle that can be used to cancel
50 * a transmit-ready notification.
51 */
52struct GNUNET_CONNECTION_TransmitHandle;
53
54/**
55 * @brief handle for a server
56 */
57struct GNUNET_SERVER_Handle;
58
59/**
60 * @brief opaque handle for a client of the server
61 */
62struct GNUNET_SERVER_Client;
63
64/**
65 * @brief opaque handle server returns for aborting transmission to a client.
66 */
67struct GNUNET_SERVER_TransmitHandle;
68
69/**
70 * @brief handle for a network connection
71 */
72struct GNUNET_CONNECTION_Handle;
73
74/**
75 * @brief handle for a network service
76 */
77struct LEGACY_SERVICE_Context;
78
79
80/**
81 * Stops a service that was started with #GNUNET_SERVICE_start().
82 *
83 * @param srv service to stop
84 */
85void
86LEGACY_SERVICE_stop (struct LEGACY_SERVICE_Context *srv);
87
88
89
90/**
91 * Function called to notify a client about the connection begin ready
92 * to queue more data. @a buf will be NULL and @a size zero if the
93 * connection was closed for writing in the meantime.
94 *
95 * @param cls closure
96 * @param size number of bytes available in @a buf
97 * @param buf where the callee should write the message
98 * @return number of bytes written to @a buf
99 */
100typedef size_t
101(*GNUNET_CONNECTION_TransmitReadyNotify) (void *cls,
102 size_t size,
103 void *buf);
104
105/**
106 * Credentials for UNIX domain sockets.
107 */
108struct GNUNET_CONNECTION_Credentials
109{
110 /**
111 * UID of the other end of the connection.
112 */
113 uid_t uid;
114
115 /**
116 * GID of the other end of the connection.
117 */
118 gid_t gid;
119};
120
121
122/**
123 * Functions with this signature are called whenever a client
124 * is disconnected on the network level.
125 *
126 * @param cls closure
127 * @param client identification of the client; NULL
128 * for the last call when the server is destroyed
129 */
130typedef void
131(*GNUNET_SERVER_DisconnectCallback) (void *cls,
132 struct GNUNET_SERVER_Client *client);
133
134
135/**
136 * Functions with this signature are called whenever a client
137 * is connected on the network level.
138 *
139 * @param cls closure
140 * @param client identification of the client
141 */
142typedef void
143(*GNUNET_SERVER_ConnectCallback) (void *cls,
144 struct GNUNET_SERVER_Client *client);
145
146
147
148
149/**
150 * Function to call for access control checks.
151 *
152 * @param cls closure
153 * @param ucred credentials, if available, otherwise NULL
154 * @param addr address
155 * @param addrlen length of address
156 * @return GNUNET_YES to allow, GNUNET_NO to deny, GNUNET_SYSERR
157 * for unknown address family (will be denied).
158 */
159typedef int
160(*GNUNET_CONNECTION_AccessCheck) (void *cls,
161 const struct
162 GNUNET_CONNECTION_Credentials *
163 ucred,
164 const struct sockaddr * addr,
165 socklen_t addrlen);
166
167/**
168 * Callback function for data received from the network. Note that
169 * both "available" and "err" would be 0 if the read simply timed out.
170 *
171 * @param cls closure
172 * @param buf pointer to received data
173 * @param available number of bytes availabe in "buf",
174 * possibly 0 (on errors)
175 * @param addr address of the sender
176 * @param addrlen size of addr
177 * @param errCode value of errno (on errors receiving)
178 */
179typedef void
180(*GNUNET_CONNECTION_Receiver) (void *cls, const void *buf,
181 size_t available,
182 const struct sockaddr * addr,
183 socklen_t addrlen, int errCode);
184
185
186
187/**
188 * Close the connection and free associated resources. There must
189 * not be any pending requests for reading or writing to the
190 * connection at this time.
191 *
192 * @param connection connection to destroy
193 */
194void
195GNUNET_CONNECTION_destroy (struct GNUNET_CONNECTION_Handle *connection);
196
197
198/**
199 * Signature of a function to create a custom tokenizer.
200 *
201 * @param cls closure from #GNUNET_SERVER_set_callbacks
202 * @param client handle to client the tokenzier will be used for
203 * @return handle to custom tokenizer ('mst')
204 */
205typedef void*
206(*GNUNET_SERVER_MstCreateCallback) (void *cls,
207 struct GNUNET_SERVER_Client *client);
208
209
210/**
211 * Signature of a function to destroy a custom tokenizer.
212 *
213 * @param cls closure from #GNUNET_SERVER_set_callbacks
214 * @param mst custom tokenizer handle
215 */
216typedef void
217(*GNUNET_SERVER_MstDestroyCallback) (void *cls,
218 void *mst);
219
220/**
221 * Signature of a function to receive data for a custom tokenizer.
222 *
223 * @param cls closure from #GNUNET_SERVER_set_callbacks
224 * @param mst custom tokenizer handle
225 * @param client_identity ID of client for which this is a buffer,
226 * can be NULL (will be passed back to 'cb')
227 * @param buf input data to add
228 * @param size number of bytes in @a buf
229 * @param purge should any excess bytes in the buffer be discarded
230 * (i.e. for packet-based services like UDP)
231 * @param one_shot only call callback once, keep rest of message in buffer
232 * @return #GNUNET_OK if we are done processing (need more data)
233 * #GNUNET_NO if one_shot was set and we have another message ready
234 * #GNUNET_SYSERR if the data stream is corrupt
235 */
236typedef int
237(*GNUNET_SERVER_MstReceiveCallback) (void *cls, void *mst,
238 struct GNUNET_SERVER_Client *client,
239 const char *buf,
240 size_t size,
241 int purge,
242 int one_shot);
243/**
244 * Functions with this signature are called whenever a message is
245 * received.
246 *
247 * @param cls closure
248 * @param client identification of the client
249 * @param message the actual message
250 */
251typedef void
252(*GNUNET_SERVER_MessageCallback) (void *cls,
253 struct GNUNET_SERVER_Client *client,
254 const struct GNUNET_MessageHeader *message);
255
256/**
257 * Message handler. Each struct specifies how to handle on particular
258 * type of message received.
259 */
260struct GNUNET_SERVER_MessageHandler
261{
262 /**
263 * Function to call for messages of "type".
264 */
265 GNUNET_SERVER_MessageCallback callback;
266
267 /**
268 * Closure argument for @e callback.
269 */
270 void *callback_cls;
271
272 /**
273 * Type of the message this handler covers.
274 */
275 uint16_t type;
276
277 /**
278 * Expected size of messages of this type. Use 0 for
279 * variable-size. If non-zero, messages of the given
280 * type will be discarded (and the connection closed)
281 * if they do not have the right size.
282 */
283 uint16_t expected_size;
284
285};
286
287
288/**
289 * Options for the service (bitmask).
290 */
291enum LEGACY_SERVICE_Options
292{
293 /**
294 * Use defaults. Terminates all client connections and the listen
295 * sockets immediately upon receiving the shutdown signal.
296 */
297 LEGACY_SERVICE_OPTION_NONE = 0,
298
299 /**
300 * Do not trigger server shutdown on signal at all; instead, allow
301 * for the user to terminate the server explicitly when needed
302 * by calling #LEGACY_SERVICE_shutdown().
303 */
304 LEGACY_SERVICE_OPTION_MANUAL_SHUTDOWN = 1,
305
306 /**
307 * Trigger a SOFT server shutdown on signals, allowing active
308 * non-monitor clients to complete their transactions.
309 */
310 LEGACY_SERVICE_OPTION_SOFT_SHUTDOWN = 2
311};
312
313
314
315/**
316 * Ask the server to disconnect from the given client. This is the
317 * same as passing #GNUNET_SYSERR to #GNUNET_SERVER_receive_done,
318 * except that it allows dropping of a client even when not handling a
319 * message from that client.
320 *
321 * @param client the client to disconnect from
322 */
323void
324GNUNET_SERVER_client_disconnect (struct GNUNET_SERVER_Client *client);
325
326/**
327 * Return user context associated with the given client.
328 * Note: you should probably use the macro (call without the underscore).
329 *
330 * @param client client to query
331 * @param size number of bytes in user context struct (for verification only)
332 * @return pointer to user context
333 */
334void *
335GNUNET_SERVER_client_get_user_context_ (struct GNUNET_SERVER_Client *client,
336 size_t size);
337
338
339/**
340 * Functions with this signature are called whenever a
341 * complete message is received by the tokenizer.
342 *
343 * Do not call #GNUNET_SERVER_mst_destroy from within
344 * the scope of this callback.
345 *
346 * @param cls closure
347 * @param client identification of the client
348 * @param message the actual message
349 * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing
350 */
351typedef int
352(*GNUNET_SERVER_MessageTokenizerCallback) (void *cls,
353 void *client,
354 const struct GNUNET_MessageHeader *message);
355
356
357/**
358 * Create a message stream tokenizer.
359 *
360 * @param cb function to call on completed messages
361 * @param cb_cls closure for @a cb
362 * @return handle to tokenizer
363 */
364struct GNUNET_SERVER_MessageStreamTokenizer *
365GNUNET_SERVER_mst_create (GNUNET_SERVER_MessageTokenizerCallback cb,
366 void *cb_cls);
367
368/**
369 * Add incoming data to the receive buffer and call the
370 * callback for all complete messages.
371 *
372 * @param mst tokenizer to use
373 * @param client_identity ID of client for which this is a buffer,
374 * can be NULL (will be passed back to 'cb')
375 * @param buf input data to add
376 * @param size number of bytes in @a buf
377 * @param purge should any excess bytes in the buffer be discarded
378 * (i.e. for packet-based services like UDP)
379 * @param one_shot only call callback once, keep rest of message in buffer
380 * @return #GNUNET_OK if we are done processing (need more data)
381 * #GNUNET_NO if one_shot was set and we have another message ready
382 * #GNUNET_SYSERR if the data stream is corrupt
383 */
384int
385GNUNET_SERVER_mst_receive (struct GNUNET_SERVER_MessageStreamTokenizer *mst,
386 void *client_identity,
387 const char *buf, size_t size,
388 int purge, int one_shot);
389
390
391
392/**
393 * Destroys a tokenizer.
394 *
395 * @param mst tokenizer to destroy
396 */
397void
398GNUNET_SERVER_mst_destroy (struct GNUNET_SERVER_MessageStreamTokenizer *mst);
49 399
50 400
51/** 401/**
402 * Set user context to be associated with the given client.
403 * Note: you should probably use the macro (call without the underscore).
404 *
405 * @param client client to query
406 * @param ptr pointer to user context
407 * @param size number of bytes in user context struct (for verification only)
408 */
409void
410GNUNET_SERVER_client_set_user_context_ (struct GNUNET_SERVER_Client *client,
411 void *ptr,
412 size_t size);
413/**
414 * Return user context associated with the given client.
415 *
416 * @param client client to query
417 * @param type expected return type (i.e. 'struct Foo')
418 * @return pointer to user context of type 'type *'.
419 */
420#define GNUNET_SERVER_client_get_user_context(client,type) \
421 (type *) GNUNET_SERVER_client_get_user_context_ (client, sizeof (type))
422
423/**
424 * Set user context to be associated with the given client.
425 *
426 * @param client client to query
427 * @param value pointer to user context
428 */
429#define GNUNET_SERVER_client_set_user_context(client,value) \
430 GNUNET_SERVER_client_set_user_context_ (client, value, sizeof (*value))
431
432
433
434/**
435 * Notify us when the server has enough space to transmit
436 * a message of the given size to the given client.
437 *
438 * @param client client to transmit message to
439 * @param size requested amount of buffer space
440 * @param timeout after how long should we give up (and call
441 * notify with buf NULL and size 0)?
442 * @param callback function to call when space is available
443 * @param callback_cls closure for @a callback
444 * @return non-NULL if the notify callback was queued; can be used
445 * to cancel the request using
446 * #GNUNET_SERVER_notify_transmit_ready_cancel.
447 * NULL if we are already going to notify someone else (busy)
448 */
449struct GNUNET_SERVER_TransmitHandle *
450GNUNET_SERVER_notify_transmit_ready (struct GNUNET_SERVER_Client *client,
451 size_t size,
452 struct GNUNET_TIME_Relative timeout,
453 GNUNET_CONNECTION_TransmitReadyNotify callback,
454 void *callback_cls);
455
456/**
457 * Abort transmission request.
458 *
459 * @param th request to abort
460 */
461void
462GNUNET_SERVER_notify_transmit_ready_cancel (struct GNUNET_SERVER_TransmitHandle *th);
463
464
465
466
467/**
468 * Notify the server that the given client handle should
469 * be kept (keeps the connection up if possible, increments
470 * the internal reference counter).
471 *
472 * @param client the client to keep
473 */
474void
475GNUNET_SERVER_client_keep (struct GNUNET_SERVER_Client *client);
476
477
478/**
479 * Notify the server that the given client handle is no
480 * longer required. Decrements the reference counter. If
481 * that counter reaches zero an inactive connection maybe
482 * closed.
483 *
484 * @param client the client to drop
485 */
486void
487GNUNET_SERVER_client_drop (struct GNUNET_SERVER_Client *client);
488
489
490/**
491 * Function called by the service's run
492 * method to run service-specific setup code.
493 *
494 * @param cls closure
495 * @param server the initialized server
496 * @param cfg configuration to use
497 */
498typedef void
499(*LEGACY_SERVICE_Main) (void *cls,
500 struct GNUNET_SERVER_Handle *server,
501 const struct GNUNET_CONFIGURATION_Handle *cfg);
502
503
504
505/**
506 * Suspend accepting connections from the listen socket temporarily.
507 * Resume activity using #GNUNET_SERVER_resume.
508 *
509 * @param server server to stop accepting connections.
510 */
511void
512GNUNET_SERVER_suspend (struct GNUNET_SERVER_Handle *server);
513
514/**
515 * Notify us when the server has enough space to transmit
516 * a message of the given size to the given client.
517 *
518 * @param client client to transmit message to
519 * @param size requested amount of buffer space
520 * @param timeout after how long should we give up (and call
521 * notify with buf NULL and size 0)?
522 * @param callback function to call when space is available
523 * @param callback_cls closure for @a callback
524 * @return non-NULL if the notify callback was queued; can be used
525 * to cancel the request using
526 * #GNUNET_SERVER_notify_transmit_ready_cancel.
527 * NULL if we are already going to notify someone else (busy)
528 */
529struct GNUNET_SERVER_TransmitHandle *
530GNUNET_SERVER_notify_transmit_ready (struct GNUNET_SERVER_Client *client,
531 size_t size,
532 struct GNUNET_TIME_Relative timeout,
533 GNUNET_CONNECTION_TransmitReadyNotify callback,
534 void *callback_cls);
535
536
537/**
538 * Add a TCP socket-based connection to the set of handles managed by
539 * this server. Use this function for outgoing (P2P) connections that
540 * we initiated (and where this server should process incoming
541 * messages).
542 *
543 * @param server the server to use
544 * @param connection the connection to manage (client must
545 * stop using this connection from now on)
546 * @return the client handle
547 */
548struct GNUNET_SERVER_Client *
549GNUNET_SERVER_connect_socket (struct GNUNET_SERVER_Handle *server,
550 struct GNUNET_CONNECTION_Handle *connection);
551
552
553/**
554 * Resume accepting connections from the listen socket.
555 *
556 * @param server server to resume accepting connections.
557 */
558void
559GNUNET_SERVER_resume (struct GNUNET_SERVER_Handle *server);
560
561/**
562 * Free resources held by this server.
563 *
564 * @param server server to destroy
565 */
566void
567GNUNET_SERVER_destroy (struct GNUNET_SERVER_Handle *server);
568
569
570
571
572#include "tcp_connection_legacy.c"
573#include "tcp_server_mst_legacy.c"
574#include "tcp_server_legacy.c"
575#include "tcp_service_legacy.c"
576
577GNUNET_NETWORK_STRUCT_BEGIN
578
579/**
52 * Initial handshake message for a session. 580 * Initial handshake message for a session.
53 */ 581 */
54struct WelcomeMessage 582struct WelcomeMessage
@@ -434,7 +962,7 @@ struct Plugin
434 /** 962 /**
435 * Handle to the network service. 963 * Handle to the network service.
436 */ 964 */
437 struct GNUNET_SERVICE_Context *service; 965 struct LEGACY_SERVICE_Context *service;
438 966
439 /** 967 /**
440 * Handle to the server for this service. 968 * Handle to the server for this service.
@@ -521,47 +1049,6 @@ struct Plugin
521}; 1049};
522 1050
523 1051
524/* begin of ancient copy-and-pasted code that should be
525 specialized for TCP ...*/
526/**
527 * Add the given UNIX domain path as an address to the
528 * list (as the first entry).
529 *
530 * @param saddrs array to update
531 * @param saddrlens where to store the address length
532 * @param unixpath path to add
533 * @param abstract #GNUNET_YES to add an abstract UNIX domain socket. This
534 * parameter is ignore on systems other than LINUX
535 */
536static void
537add_unixpath (struct sockaddr **saddrs,
538 socklen_t *saddrlens,
539 const char *unixpath,
540 int abstract)
541{
542#ifdef AF_UNIX
543 struct sockaddr_un *un;
544
545 un = GNUNET_new (struct sockaddr_un);
546 un->sun_family = AF_UNIX;
547 strncpy (un->sun_path, unixpath, sizeof (un->sun_path) - 1);
548#ifdef LINUX
549 if (GNUNET_YES == abstract)
550 un->sun_path[0] = '\0';
551#endif
552#if HAVE_SOCKADDR_UN_SUN_LEN
553 un->sun_len = (u_char) sizeof (struct sockaddr_un);
554#endif
555 *saddrs = (struct sockaddr *) un;
556 *saddrlens = sizeof (struct sockaddr_un);
557#else
558 /* this function should never be called
559 * unless AF_UNIX is defined! */
560 GNUNET_assert (0);
561#endif
562}
563
564
565/** 1052/**
566 * Get the list of addresses that a server for the given service 1053 * Get the list of addresses that a server for the given service
567 * should bind to. 1054 * should bind to.
@@ -3289,7 +3776,7 @@ libgnunet_plugin_transport_tcp_init (void *cls)
3289 struct GNUNET_TRANSPORT_PluginEnvironment *env = cls; 3776 struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
3290 struct GNUNET_TRANSPORT_PluginFunctions *api; 3777 struct GNUNET_TRANSPORT_PluginFunctions *api;
3291 struct Plugin *plugin; 3778 struct Plugin *plugin;
3292 struct GNUNET_SERVICE_Context *service; 3779 struct LEGACY_SERVICE_Context *service;
3293 unsigned long long aport; 3780 unsigned long long aport;
3294 unsigned long long bport; 3781 unsigned long long bport;
3295 unsigned long long max_connections; 3782 unsigned long long max_connections;
@@ -3344,9 +3831,9 @@ libgnunet_plugin_transport_tcp_init (void *cls)
3344 aport = 0; 3831 aport = 0;
3345 if (0 != bport) 3832 if (0 != bport)
3346 { 3833 {
3347 service = GNUNET_SERVICE_start ("transport-tcp", 3834 service = LEGACY_SERVICE_start ("transport-tcp",
3348 env->cfg, 3835 env->cfg,
3349 GNUNET_SERVICE_OPTION_NONE); 3836 LEGACY_SERVICE_OPTION_NONE);
3350 if (NULL == service) 3837 if (NULL == service)
3351 { 3838 {
3352 LOG (GNUNET_ERROR_TYPE_WARNING, 3839 LOG (GNUNET_ERROR_TYPE_WARNING,
@@ -3377,7 +3864,7 @@ libgnunet_plugin_transport_tcp_init (void *cls)
3377 { 3864 {
3378#ifdef TCP_STEALTH 3865#ifdef TCP_STEALTH
3379 plugin->myoptions |= TCP_OPTIONS_TCP_STEALTH; 3866 plugin->myoptions |= TCP_OPTIONS_TCP_STEALTH;
3380 lsocks = GNUNET_SERVICE_get_listen_sockets (service); 3867 lsocks = LEGACY_SERVICE_get_listen_sockets (service);
3381 if (NULL != lsocks) 3868 if (NULL != lsocks)
3382 { 3869 {
3383 uint32_t len = sizeof (struct WelcomeMessage); 3870 uint32_t len = sizeof (struct WelcomeMessage);
@@ -3470,7 +3957,7 @@ libgnunet_plugin_transport_tcp_init (void *cls)
3470 plugin->service = service; 3957 plugin->service = service;
3471 if (NULL != service) 3958 if (NULL != service)
3472 { 3959 {
3473 plugin->server = GNUNET_SERVICE_get_server (service); 3960 plugin->server = LEGACY_SERVICE_get_server (service);
3474 } 3961 }
3475 else 3962 else
3476 { 3963 {
@@ -3533,7 +4020,7 @@ libgnunet_plugin_transport_tcp_init (void *cls)
3533 GNUNET_NAT_unregister (plugin->nat); 4020 GNUNET_NAT_unregister (plugin->nat);
3534 GNUNET_CONTAINER_multipeermap_destroy (plugin->sessionmap); 4021 GNUNET_CONTAINER_multipeermap_destroy (plugin->sessionmap);
3535 if (NULL != service) 4022 if (NULL != service)
3536 GNUNET_SERVICE_stop (service); 4023 LEGACY_SERVICE_stop (service);
3537 GNUNET_free (plugin); 4024 GNUNET_free (plugin);
3538 GNUNET_free_non_null (api); 4025 GNUNET_free_non_null (api);
3539 return NULL; 4026 return NULL;
@@ -3586,7 +4073,7 @@ libgnunet_plugin_transport_tcp_done (void *cls)
3586 } 4073 }
3587 4074
3588 if (NULL != plugin->service) 4075 if (NULL != plugin->service)
3589 GNUNET_SERVICE_stop (plugin->service); 4076 LEGACY_SERVICE_stop (plugin->service);
3590 else 4077 else
3591 GNUNET_SERVER_destroy (plugin->server); 4078 GNUNET_SERVER_destroy (plugin->server);
3592 GNUNET_free (plugin->handlers); 4079 GNUNET_free (plugin->handlers);
diff --git a/src/transport/plugin_transport_udp.c b/src/transport/plugin_transport_udp.c
index 76132523b..1ff962544 100644
--- a/src/transport/plugin_transport_udp.c
+++ b/src/transport/plugin_transport_udp.c
@@ -159,6 +159,11 @@ struct GNUNET_ATS_Session
159 struct GNUNET_PeerIdentity target; 159 struct GNUNET_PeerIdentity target;
160 160
161 /** 161 /**
162 * Tokenizer for inbound messages.
163 */
164 struct GNUNET_MessageStreamTokenizer *mst;
165
166 /**
162 * Plugin this session belongs to. 167 * Plugin this session belongs to.
163 */ 168 */
164 struct Plugin *plugin; 169 struct Plugin *plugin;
@@ -626,6 +631,11 @@ free_session (struct GNUNET_ATS_Session *s)
626 GNUNET_free (s->frag_ctx); 631 GNUNET_free (s->frag_ctx);
627 s->frag_ctx = NULL; 632 s->frag_ctx = NULL;
628 } 633 }
634 if (NULL != s->mst)
635 {
636 GNUNET_MST_destroy (s->mst);
637 s->mst = NULL;
638 }
629 GNUNET_free (s); 639 GNUNET_free (s);
630} 640}
631 641
@@ -1623,7 +1633,7 @@ enqueue (struct Plugin *plugin,
1623 GNUNET_break (0); 1633 GNUNET_break (0);
1624 return; 1634 return;
1625 } 1635 }
1626 if (plugin->bytes_in_buffer + udpw->msg_size > INT64_MAX) 1636 if (plugin->bytes_in_buffer > INT64_MAX - udpw->msg_size)
1627 { 1637 {
1628 GNUNET_break (0); 1638 GNUNET_break (0);
1629 } 1639 }
@@ -2051,7 +2061,7 @@ udp_plugin_send (void *cls,
2051 if ( (sizeof(struct IPv4UdpAddress) == s->address->address_length) && 2061 if ( (sizeof(struct IPv4UdpAddress) == s->address->address_length) &&
2052 (NULL == plugin->sockv4) ) 2062 (NULL == plugin->sockv4) )
2053 return GNUNET_SYSERR; 2063 return GNUNET_SYSERR;
2054 if (udpmlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) 2064 if (udpmlen >= GNUNET_MAX_MESSAGE_SIZE)
2055 { 2065 {
2056 GNUNET_break (0); 2066 GNUNET_break (0);
2057 return GNUNET_SYSERR; 2067 return GNUNET_SYSERR;
@@ -2499,18 +2509,16 @@ read_process_ack (struct Plugin *plugin,
2499 * Message tokenizer has broken up an incomming message. Pass it on 2509 * Message tokenizer has broken up an incomming message. Pass it on
2500 * to the service. 2510 * to the service.
2501 * 2511 *
2502 * @param cls the `struct Plugin *` 2512 * @param cls the `struct GNUNET_ATS_Session *`
2503 * @param client the `struct GNUNET_ATS_Session *`
2504 * @param hdr the actual message 2513 * @param hdr the actual message
2505 * @return #GNUNET_OK (always) 2514 * @return #GNUNET_OK (always)
2506 */ 2515 */
2507static int 2516static int
2508process_inbound_tokenized_messages (void *cls, 2517process_inbound_tokenized_messages (void *cls,
2509 void *client,
2510 const struct GNUNET_MessageHeader *hdr) 2518 const struct GNUNET_MessageHeader *hdr)
2511{ 2519{
2512 struct Plugin *plugin = cls; 2520 struct GNUNET_ATS_Session *session = cls;
2513 struct GNUNET_ATS_Session *session = client; 2521 struct Plugin *plugin = session->plugin;
2514 2522
2515 if (GNUNET_YES == session->in_destroy) 2523 if (GNUNET_YES == session->in_destroy)
2516 return GNUNET_OK; 2524 return GNUNET_OK;
@@ -2626,6 +2634,8 @@ udp_plugin_create_session (void *cls,
2626 struct GNUNET_ATS_Session *s; 2634 struct GNUNET_ATS_Session *s;
2627 2635
2628 s = GNUNET_new (struct GNUNET_ATS_Session); 2636 s = GNUNET_new (struct GNUNET_ATS_Session);
2637 s->mst = GNUNET_MST_create (&process_inbound_tokenized_messages,
2638 s);
2629 s->plugin = plugin; 2639 s->plugin = plugin;
2630 s->address = GNUNET_HELLO_address_copy (address); 2640 s->address = GNUNET_HELLO_address_copy (address);
2631 s->target = address->peer; 2641 s->target = address->peer;
@@ -2792,12 +2802,11 @@ process_udp_message (struct Plugin *plugin,
2792 GNUNET_free (address); 2802 GNUNET_free (address);
2793 2803
2794 s->rc++; 2804 s->rc++;
2795 GNUNET_SERVER_mst_receive (plugin->mst, 2805 GNUNET_MST_from_buffer (s->mst,
2796 s, 2806 (const char *) &msg[1],
2797 (const char *) &msg[1], 2807 ntohs (msg->header.size) - sizeof(struct UDPMessage),
2798 ntohs (msg->header.size) - sizeof(struct UDPMessage), 2808 GNUNET_YES,
2799 GNUNET_YES, 2809 GNUNET_NO);
2800 GNUNET_NO);
2801 s->rc--; 2810 s->rc--;
2802 if ( (0 == s->rc) && 2811 if ( (0 == s->rc) &&
2803 (GNUNET_YES == s->in_destroy) ) 2812 (GNUNET_YES == s->in_destroy) )
@@ -3990,8 +3999,6 @@ libgnunet_plugin_transport_udp_init (void *cls)
3990 p->sessions = GNUNET_CONTAINER_multipeermap_create (16, 3999 p->sessions = GNUNET_CONTAINER_multipeermap_create (16,
3991 GNUNET_NO); 4000 GNUNET_NO);
3992 p->defrag_ctxs = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); 4001 p->defrag_ctxs = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3993 p->mst = GNUNET_SERVER_mst_create (&process_inbound_tokenized_messages,
3994 p);
3995 GNUNET_BANDWIDTH_tracker_init (&p->tracker, 4002 GNUNET_BANDWIDTH_tracker_init (&p->tracker,
3996 NULL, 4003 NULL,
3997 NULL, 4004 NULL,
@@ -4008,7 +4015,6 @@ libgnunet_plugin_transport_udp_init (void *cls)
4008 _("Failed to create UDP network sockets\n")); 4015 _("Failed to create UDP network sockets\n"));
4009 GNUNET_CONTAINER_multipeermap_destroy (p->sessions); 4016 GNUNET_CONTAINER_multipeermap_destroy (p->sessions);
4010 GNUNET_CONTAINER_heap_destroy (p->defrag_ctxs); 4017 GNUNET_CONTAINER_heap_destroy (p->defrag_ctxs);
4011 GNUNET_SERVER_mst_destroy (p->mst);
4012 if (NULL != p->nat) 4018 if (NULL != p->nat)
4013 GNUNET_NAT_unregister (p->nat); 4019 GNUNET_NAT_unregister (p->nat);
4014 GNUNET_free (p); 4020 GNUNET_free (p);
@@ -4120,11 +4126,6 @@ libgnunet_plugin_transport_udp_done (void *cls)
4120 GNUNET_CONTAINER_heap_destroy (plugin->defrag_ctxs); 4126 GNUNET_CONTAINER_heap_destroy (plugin->defrag_ctxs);
4121 plugin->defrag_ctxs = NULL; 4127 plugin->defrag_ctxs = NULL;
4122 } 4128 }
4123 if (NULL != plugin->mst)
4124 {
4125 GNUNET_SERVER_mst_destroy (plugin->mst);
4126 plugin->mst = NULL;
4127 }
4128 while (NULL != (udpw = plugin->ipv4_queue_head)) 4129 while (NULL != (udpw = plugin->ipv4_queue_head))
4129 { 4130 {
4130 dequeue (plugin, 4131 dequeue (plugin,
diff --git a/src/transport/plugin_transport_udp.h b/src/transport/plugin_transport_udp.h
index 152b16099..48c7365c7 100644
--- a/src/transport/plugin_transport_udp.h
+++ b/src/transport/plugin_transport_udp.h
@@ -164,11 +164,6 @@ struct Plugin
164 struct GNUNET_SCHEDULER_Task *select_task_v6; 164 struct GNUNET_SCHEDULER_Task *select_task_v6;
165 165
166 /** 166 /**
167 * Tokenizer for inbound messages.
168 */
169 struct GNUNET_SERVER_MessageStreamTokenizer *mst;
170
171 /**
172 * Bandwidth tracker to limit global UDP traffic. 167 * Bandwidth tracker to limit global UDP traffic.
173 */ 168 */
174 struct GNUNET_BANDWIDTH_Tracker tracker; 169 struct GNUNET_BANDWIDTH_Tracker tracker;
@@ -192,7 +187,7 @@ struct Plugin
192 * Handle to NAT traversal support. 187 * Handle to NAT traversal support.
193 */ 188 */
194 struct GNUNET_NAT_STUN_Handle *stun; 189 struct GNUNET_NAT_STUN_Handle *stun;
195 190
196 /** 191 /**
197 * The read socket for IPv4 192 * The read socket for IPv4
198 */ 193 */
@@ -204,11 +199,6 @@ struct Plugin
204 struct GNUNET_NETWORK_Handle *sockv6; 199 struct GNUNET_NETWORK_Handle *sockv6;
205 200
206 /** 201 /**
207 * Tokenizer for inbound messages.
208 */
209 struct GNUNET_SERVER_MessageStreamTokenizer *broadcast_mst;
210
211 /**
212 * Head of DLL of broadcast addresses 202 * Head of DLL of broadcast addresses
213 */ 203 */
214 struct BroadcastAddress *broadcast_tail; 204 struct BroadcastAddress *broadcast_tail;
diff --git a/src/transport/plugin_transport_udp_broadcasting.c b/src/transport/plugin_transport_udp_broadcasting.c
index a440830fd..c6ddbce9b 100644
--- a/src/transport/plugin_transport_udp_broadcasting.c
+++ b/src/transport/plugin_transport_udp_broadcasting.c
@@ -133,11 +133,10 @@ struct MstContext
133 */ 133 */
134static int 134static int
135broadcast_mst_cb (void *cls, 135broadcast_mst_cb (void *cls,
136 void *client,
137 const struct GNUNET_MessageHeader *message) 136 const struct GNUNET_MessageHeader *message)
138{ 137{
139 struct Plugin *plugin = cls; 138 struct MstContext *mc = cls;
140 struct MstContext *mc = client; 139 struct Plugin *plugin = mc->plugin;
141 struct GNUNET_HELLO_Address *address; 140 struct GNUNET_HELLO_Address *address;
142 const struct GNUNET_MessageHeader *hello; 141 const struct GNUNET_MessageHeader *hello;
143 const struct UDP_Beacon_Message *msg; 142 const struct UDP_Beacon_Message *msg;
@@ -191,16 +190,20 @@ udp_broadcast_receive (struct Plugin *plugin,
191 size_t udp_addr_len, 190 size_t udp_addr_len,
192 enum GNUNET_ATS_Network_Type network_type) 191 enum GNUNET_ATS_Network_Type network_type)
193{ 192{
193 struct GNUNET_MessageStreamTokenizer *broadcast_mst;
194 struct MstContext mc; 194 struct MstContext mc;
195 195
196 broadcast_mst = GNUNET_MST_create (&broadcast_mst_cb,
197 &mc);
198 mc.plugin = plugin;
196 mc.udp_addr = udp_addr; 199 mc.udp_addr = udp_addr;
197 mc.udp_addr_len = udp_addr_len; 200 mc.udp_addr_len = udp_addr_len;
198 mc.ats_address_network_type = network_type; 201 mc.ats_address_network_type = network_type;
199 GNUNET_SERVER_mst_receive (plugin->broadcast_mst, 202 GNUNET_MST_from_buffer (broadcast_mst,
200 &mc, 203 buf, size,
201 buf, size, 204 GNUNET_NO,
202 GNUNET_NO, 205 GNUNET_NO);
203 GNUNET_NO); 206 GNUNET_MST_destroy (broadcast_mst);
204} 207}
205 208
206 209
@@ -546,10 +549,6 @@ setup_broadcast (struct Plugin *plugin,
546 return; 549 return;
547 } 550 }
548 551
549 /* always create tokenizers */
550 plugin->broadcast_mst =
551 GNUNET_SERVER_mst_create (&broadcast_mst_cb, plugin);
552
553 if (GNUNET_YES != plugin->enable_broadcasting) 552 if (GNUNET_YES != plugin->enable_broadcasting)
554 return; /* We do not send, just receive */ 553 return; /* We do not send, just receive */
555 554
@@ -636,13 +635,6 @@ stop_broadcast (struct Plugin *plugin)
636 GNUNET_free (p); 635 GNUNET_free (p);
637 } 636 }
638 } 637 }
639
640 /* Destroy MSTs */
641 if (NULL != plugin->broadcast_mst)
642 {
643 GNUNET_SERVER_mst_destroy (plugin->broadcast_mst);
644 plugin->broadcast_mst = NULL;
645 }
646} 638}
647 639
648/* end of plugin_transport_udp_broadcasting.c */ 640/* end of plugin_transport_udp_broadcasting.c */
diff --git a/src/transport/plugin_transport_wlan.c b/src/transport/plugin_transport_wlan.c
index 376065d24..b23739d3c 100644
--- a/src/transport/plugin_transport_wlan.c
+++ b/src/transport/plugin_transport_wlan.c
@@ -38,6 +38,7 @@
38#include "gnunet_fragmentation_lib.h" 38#include "gnunet_fragmentation_lib.h"
39#include "gnunet_constants.h" 39#include "gnunet_constants.h"
40 40
41
41#if BUILD_WLAN 42#if BUILD_WLAN
42/* begin case wlan */ 43/* begin case wlan */
43#define PLUGIN_NAME "wlan" 44#define PLUGIN_NAME "wlan"
@@ -48,6 +49,7 @@
48#define LIBGNUNET_PLUGIN_TRANSPORT_DONE libgnunet_plugin_transport_wlan_done 49#define LIBGNUNET_PLUGIN_TRANSPORT_DONE libgnunet_plugin_transport_wlan_done
49#define LOG(kind,...) GNUNET_log_from (kind, "transport-wlan",__VA_ARGS__) 50#define LOG(kind,...) GNUNET_log_from (kind, "transport-wlan",__VA_ARGS__)
50 51
52
51/** 53/**
52 * time out of a mac endpoint 54 * time out of a mac endpoint
53 */ 55 */
@@ -92,6 +94,30 @@
92#error need to build wlan or bluetooth 94#error need to build wlan or bluetooth
93#endif 95#endif
94 96
97
98
99/**
100 * Functions with this signature are called whenever a
101 * complete message is received by the tokenizer.
102 *
103 * Do not call #GNUNET_SERVER_mst_destroy from within
104 * the scope of this callback.
105 *
106 * @param cls closure
107 * @param client identification of the client
108 * @param message the actual message
109 * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing
110 */
111typedef int
112(*GNUNET_SERVER_MessageTokenizerCallback) (void *cls,
113 void *client,
114 const struct GNUNET_MessageHeader *message);
115
116
117/* Include legacy message stream tokenizer that was removed from util (for now) */
118#include "tcp_server_mst_legacy.c"
119
120
95/** 121/**
96 * Max size of packet (that we give to the WLAN driver for transmission) 122 * Max size of packet (that we give to the WLAN driver for transmission)
97 */ 123 */
@@ -718,7 +744,7 @@ send_ack (void *cls,
718 GNUNET_break (0); 744 GNUNET_break (0);
719 return; 745 return;
720 } 746 }
721 if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE) 747 if (size >= GNUNET_MAX_MESSAGE_SIZE)
722 { 748 {
723 GNUNET_break (0); 749 GNUNET_break (0);
724 return; 750 return;
@@ -1728,11 +1754,10 @@ send_hello_beacon (void *cls)
1728 * Function used for to process the data from the suid process 1754 * Function used for to process the data from the suid process
1729 * 1755 *
1730 * @param cls the plugin handle 1756 * @param cls the plugin handle
1731 * @param client client that send the data (not used)
1732 * @param hdr header of the GNUNET_MessageHeader 1757 * @param hdr header of the GNUNET_MessageHeader
1733 */ 1758 */
1734static int 1759static int
1735handle_helper_message (void *cls, void *client, 1760handle_helper_message (void *cls,
1736 const struct GNUNET_MessageHeader *hdr) 1761 const struct GNUNET_MessageHeader *hdr)
1737{ 1762{
1738 struct Plugin *plugin = cls; 1763 struct Plugin *plugin = cls;
diff --git a/src/util/connection.c b/src/transport/tcp_connection_legacy.c
index e822b264f..5b219a467 100644
--- a/src/util/connection.c
+++ b/src/transport/tcp_connection_legacy.c
@@ -35,7 +35,15 @@
35#include "gnunet_resolver_service.h" 35#include "gnunet_resolver_service.h"
36 36
37 37
38#define LOG(kind,...) GNUNET_log_from (kind, "util-connection", __VA_ARGS__) 38/**
39 * Timeout we use on TCP connect before trying another
40 * result from the DNS resolver. Actual value used
41 * is this value divided by the number of address families.
42 * Default is 5s.
43 */
44#define CONNECT_RETRY_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
45
46
39 47
40#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-connection", syscall) 48#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-connection", syscall)
41 49
@@ -305,7 +313,7 @@ GNUNET_CONNECTION_create_from_existing (struct GNUNET_NETWORK_Handle *osSocket)
305 struct GNUNET_CONNECTION_Handle *connection; 313 struct GNUNET_CONNECTION_Handle *connection;
306 314
307 connection = GNUNET_new (struct GNUNET_CONNECTION_Handle); 315 connection = GNUNET_new (struct GNUNET_CONNECTION_Handle);
308 connection->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE; 316 connection->write_buffer_size = GNUNET_MIN_MESSAGE_SIZE;
309 connection->write_buffer = GNUNET_malloc (connection->write_buffer_size); 317 connection->write_buffer = GNUNET_malloc (connection->write_buffer_size);
310 connection->sock = osSocket; 318 connection->sock = osSocket;
311 return connection; 319 return connection;
@@ -452,7 +460,7 @@ GNUNET_CONNECTION_create_from_accept (GNUNET_CONNECTION_AccessCheck access_cb,
452 return NULL; 460 return NULL;
453 } 461 }
454 connection = GNUNET_new (struct GNUNET_CONNECTION_Handle); 462 connection = GNUNET_new (struct GNUNET_CONNECTION_Handle);
455 connection->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE; 463 connection->write_buffer_size = GNUNET_MIN_MESSAGE_SIZE;
456 connection->write_buffer = GNUNET_malloc (connection->write_buffer_size); 464 connection->write_buffer = GNUNET_malloc (connection->write_buffer_size);
457 connection->addr = uaddr; 465 connection->addr = uaddr;
458 connection->addrlen = addrlen; 466 connection->addrlen = addrlen;
@@ -825,7 +833,7 @@ try_connect_using_address (void *cls,
825 return; 833 return;
826 } 834 }
827 GNUNET_CONTAINER_DLL_insert (connection->ap_head, connection->ap_tail, ap); 835 GNUNET_CONTAINER_DLL_insert (connection->ap_head, connection->ap_tail, ap);
828 delay = GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT; 836 delay = CONNECT_RETRY_TIMEOUT;
829 if (NULL != connection->nth.notify_ready) 837 if (NULL != connection->nth.notify_ready)
830 delay = GNUNET_TIME_relative_min (delay, 838 delay = GNUNET_TIME_relative_min (delay,
831 GNUNET_TIME_absolute_get_remaining (connection->nth.transmit_timeout)); 839 GNUNET_TIME_absolute_get_remaining (connection->nth.transmit_timeout));
@@ -859,14 +867,14 @@ GNUNET_CONNECTION_create_from_connect (const struct GNUNET_CONFIGURATION_Handle
859 GNUNET_assert (0 < strlen (hostname)); /* sanity check */ 867 GNUNET_assert (0 < strlen (hostname)); /* sanity check */
860 connection = GNUNET_new (struct GNUNET_CONNECTION_Handle); 868 connection = GNUNET_new (struct GNUNET_CONNECTION_Handle);
861 connection->cfg = cfg; 869 connection->cfg = cfg;
862 connection->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE; 870 connection->write_buffer_size = GNUNET_MIN_MESSAGE_SIZE;
863 connection->write_buffer = GNUNET_malloc (connection->write_buffer_size); 871 connection->write_buffer = GNUNET_malloc (connection->write_buffer_size);
864 connection->port = port; 872 connection->port = port;
865 connection->hostname = GNUNET_strdup (hostname); 873 connection->hostname = GNUNET_strdup (hostname);
866 connection->dns_active = 874 connection->dns_active =
867 GNUNET_RESOLVER_ip_get (connection->hostname, 875 GNUNET_RESOLVER_ip_get (connection->hostname,
868 AF_UNSPEC, 876 AF_UNSPEC,
869 GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT, 877 CONNECT_RETRY_TIMEOUT,
870 &try_connect_using_address, 878 &try_connect_using_address,
871 connection); 879 connection);
872 return connection; 880 return connection;
@@ -910,7 +918,7 @@ GNUNET_CONNECTION_create_from_connect_to_unixpath (const struct GNUNET_CONFIGURA
910#endif 918#endif
911 connection = GNUNET_new (struct GNUNET_CONNECTION_Handle); 919 connection = GNUNET_new (struct GNUNET_CONNECTION_Handle);
912 connection->cfg = cfg; 920 connection->cfg = cfg;
913 connection->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE; 921 connection->write_buffer_size = GNUNET_MIN_MESSAGE_SIZE;
914 connection->write_buffer = GNUNET_malloc (connection->write_buffer_size); 922 connection->write_buffer = GNUNET_malloc (connection->write_buffer_size);
915 connection->port = 0; 923 connection->port = 0;
916 connection->hostname = NULL; 924 connection->hostname = NULL;
@@ -1536,7 +1544,7 @@ GNUNET_CONNECTION_notify_transmit_ready (struct GNUNET_CONNECTION_Handle *connec
1536 return NULL; 1544 return NULL;
1537 } 1545 }
1538 GNUNET_assert (NULL != notify); 1546 GNUNET_assert (NULL != notify);
1539 GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE); 1547 GNUNET_assert (size < GNUNET_MAX_MESSAGE_SIZE);
1540 GNUNET_assert (connection->write_buffer_off <= connection->write_buffer_size); 1548 GNUNET_assert (connection->write_buffer_off <= connection->write_buffer_size);
1541 GNUNET_assert (connection->write_buffer_pos <= connection->write_buffer_size); 1549 GNUNET_assert (connection->write_buffer_pos <= connection->write_buffer_size);
1542 GNUNET_assert (connection->write_buffer_pos <= connection->write_buffer_off); 1550 GNUNET_assert (connection->write_buffer_pos <= connection->write_buffer_off);
diff --git a/src/util/server.c b/src/transport/tcp_server_legacy.c
index 83c30e328..6b4daa525 100644
--- a/src/util/server.c
+++ b/src/transport/tcp_server_legacy.c
@@ -28,10 +28,6 @@
28#include "gnunet_util_lib.h" 28#include "gnunet_util_lib.h"
29#include "gnunet_protocols.h" 29#include "gnunet_protocols.h"
30 30
31#define LOG(kind,...) GNUNET_log_from (kind, "util-server", __VA_ARGS__)
32
33#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-server", syscall)
34
35#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util-server", syscall, filename) 31#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util-server", syscall, filename)
36 32
37 33
@@ -1049,7 +1045,7 @@ process_mst (struct GNUNET_SERVER_Client *client,
1049 GNUNET_STRINGS_relative_time_to_string (client->idle_timeout, GNUNET_YES)); 1045 GNUNET_STRINGS_relative_time_to_string (client->idle_timeout, GNUNET_YES));
1050 client->receive_pending = GNUNET_YES; 1046 client->receive_pending = GNUNET_YES;
1051 GNUNET_CONNECTION_receive (client->connection, 1047 GNUNET_CONNECTION_receive (client->connection,
1052 GNUNET_SERVER_MAX_MESSAGE_SIZE - 1, 1048 GNUNET_MAX_MESSAGE_SIZE - 1,
1053 client->idle_timeout, 1049 client->idle_timeout,
1054 &process_incoming, 1050 &process_incoming,
1055 client); 1051 client);
@@ -1128,7 +1124,7 @@ process_incoming (void *cls,
1128 client); 1124 client);
1129 client->receive_pending = GNUNET_YES; 1125 client->receive_pending = GNUNET_YES;
1130 GNUNET_CONNECTION_receive (client->connection, 1126 GNUNET_CONNECTION_receive (client->connection,
1131 GNUNET_SERVER_MAX_MESSAGE_SIZE - 1, 1127 GNUNET_MAX_MESSAGE_SIZE - 1,
1132 GNUNET_TIME_absolute_get_remaining (end), 1128 GNUNET_TIME_absolute_get_remaining (end),
1133 &process_incoming, 1129 &process_incoming,
1134 client); 1130 client);
@@ -1204,7 +1200,7 @@ restart_processing (void *cls)
1204 LOG (GNUNET_ERROR_TYPE_DEBUG, "Server begins to read again from client.\n"); 1200 LOG (GNUNET_ERROR_TYPE_DEBUG, "Server begins to read again from client.\n");
1205 client->receive_pending = GNUNET_YES; 1201 client->receive_pending = GNUNET_YES;
1206 GNUNET_CONNECTION_receive (client->connection, 1202 GNUNET_CONNECTION_receive (client->connection,
1207 GNUNET_SERVER_MAX_MESSAGE_SIZE - 1, 1203 GNUNET_MAX_MESSAGE_SIZE - 1,
1208 client->idle_timeout, 1204 client->idle_timeout,
1209 &process_incoming, 1205 &process_incoming,
1210 client); 1206 client);
@@ -1292,7 +1288,7 @@ GNUNET_SERVER_connect_socket (struct GNUNET_SERVER_Handle *server,
1292 n->callback (n->callback_cls, client); 1288 n->callback (n->callback_cls, client);
1293 client->receive_pending = GNUNET_YES; 1289 client->receive_pending = GNUNET_YES;
1294 GNUNET_CONNECTION_receive (client->connection, 1290 GNUNET_CONNECTION_receive (client->connection,
1295 GNUNET_SERVER_MAX_MESSAGE_SIZE - 1, 1291 GNUNET_MAX_MESSAGE_SIZE - 1,
1296 client->idle_timeout, 1292 client->idle_timeout,
1297 &process_incoming, 1293 &process_incoming,
1298 client); 1294 client);
diff --git a/src/util/server_mst.c b/src/transport/tcp_server_mst_legacy.c
index 5155b54da..78e04c1b1 100644
--- a/src/util/server_mst.c
+++ b/src/transport/tcp_server_mst_legacy.c
@@ -34,8 +34,6 @@
34#define ALIGN_FACTOR 8 34#define ALIGN_FACTOR 8
35#endif 35#endif
36 36
37#define LOG(kind,...) GNUNET_log_from (kind, "util-server-mst", __VA_ARGS__)
38
39 37
40/** 38/**
41 * Handle to a message stream tokenizer. 39 * Handle to a message stream tokenizer.
@@ -91,8 +89,8 @@ GNUNET_SERVER_mst_create (GNUNET_SERVER_MessageTokenizerCallback cb,
91 struct GNUNET_SERVER_MessageStreamTokenizer *ret; 89 struct GNUNET_SERVER_MessageStreamTokenizer *ret;
92 90
93 ret = GNUNET_new (struct GNUNET_SERVER_MessageStreamTokenizer); 91 ret = GNUNET_new (struct GNUNET_SERVER_MessageStreamTokenizer);
94 ret->hdr = GNUNET_malloc (GNUNET_SERVER_MIN_BUFFER_SIZE); 92 ret->hdr = GNUNET_malloc (GNUNET_MIN_MESSAGE_SIZE);
95 ret->curr_buf = GNUNET_SERVER_MIN_BUFFER_SIZE; 93 ret->curr_buf = GNUNET_MIN_MESSAGE_SIZE;
96 ret->cb = cb; 94 ret->cb = cb;
97 ret->cb_cls = cb_cls; 95 ret->cb_cls = cb_cls;
98 return ret; 96 return ret;
diff --git a/src/transport/tcp_service_legacy.c b/src/transport/tcp_service_legacy.c
new file mode 100644
index 000000000..7c2d3e55a
--- /dev/null
+++ b/src/transport/tcp_service_legacy.c
@@ -0,0 +1,1688 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2012 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21/**
22 * @file util/service.c
23 * @brief functions related to starting services
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_protocols.h"
29#include "gnunet_constants.h"
30#include "gnunet_resolver_service.h"
31
32#if HAVE_MALLINFO
33#include <malloc.h>
34#include "gauger.h"
35#endif
36
37
38/* ******************* access control ******************** */
39
40/**
41 * Check if the given IP address is in the list of IP addresses.
42 *
43 * @param list a list of networks
44 * @param add the IP to check (in network byte order)
45 * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is
46 */
47static int
48check_ipv4_listed (const struct GNUNET_STRINGS_IPv4NetworkPolicy *list,
49 const struct in_addr *add)
50{
51 unsigned int i;
52
53 if (NULL == list)
54 return GNUNET_NO;
55 i = 0;
56 while ((list[i].network.s_addr != 0) || (list[i].netmask.s_addr != 0))
57 {
58 if ((add->s_addr & list[i].netmask.s_addr) ==
59 (list[i].network.s_addr & list[i].netmask.s_addr))
60 return GNUNET_YES;
61 i++;
62 }
63 return GNUNET_NO;
64}
65
66
67/**
68 * Check if the given IP address is in the list of IP addresses.
69 *
70 * @param list a list of networks
71 * @param ip the IP to check (in network byte order)
72 * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is
73 */
74static int
75check_ipv6_listed (const struct GNUNET_STRINGS_IPv6NetworkPolicy *list,
76 const struct in6_addr *ip)
77{
78 unsigned int i;
79 unsigned int j;
80 struct in6_addr zero;
81
82 if (NULL == list)
83 return GNUNET_NO;
84 memset (&zero, 0, sizeof (struct in6_addr));
85 i = 0;
86NEXT:
87 while (0 != memcmp (&zero, &list[i].network, sizeof (struct in6_addr)))
88 {
89 for (j = 0; j < sizeof (struct in6_addr) / sizeof (int); j++)
90 if (((((int *) ip)[j] & ((int *) &list[i].netmask)[j])) !=
91 (((int *) &list[i].network)[j] & ((int *) &list[i].netmask)[j]))
92 {
93 i++;
94 goto NEXT;
95 }
96 return GNUNET_YES;
97 }
98 return GNUNET_NO;
99}
100
101
102/* ****************** service struct ****************** */
103
104
105/**
106 * Context for "service_task".
107 */
108struct LEGACY_SERVICE_Context
109{
110 /**
111 * Our configuration.
112 */
113 const struct GNUNET_CONFIGURATION_Handle *cfg;
114
115 /**
116 * Handle for the server.
117 */
118 struct GNUNET_SERVER_Handle *server;
119
120 /**
121 * NULL-terminated array of addresses to bind to, NULL if we got pre-bound
122 * listen sockets.
123 */
124 struct sockaddr **addrs;
125
126 /**
127 * Name of our service.
128 */
129 const char *service_name;
130
131 /**
132 * Main service-specific task to run.
133 */
134 LEGACY_SERVICE_Main task;
135
136 /**
137 * Closure for @e task.
138 */
139 void *task_cls;
140
141 /**
142 * IPv4 addresses that are not allowed to connect.
143 */
144 struct GNUNET_STRINGS_IPv4NetworkPolicy *v4_denied;
145
146 /**
147 * IPv6 addresses that are not allowed to connect.
148 */
149 struct GNUNET_STRINGS_IPv6NetworkPolicy *v6_denied;
150
151 /**
152 * IPv4 addresses that are allowed to connect (if not
153 * set, all are allowed).
154 */
155 struct GNUNET_STRINGS_IPv4NetworkPolicy *v4_allowed;
156
157 /**
158 * IPv6 addresses that are allowed to connect (if not
159 * set, all are allowed).
160 */
161 struct GNUNET_STRINGS_IPv6NetworkPolicy *v6_allowed;
162
163 /**
164 * My (default) message handlers. Adjusted copy
165 * of "defhandlers".
166 */
167 struct GNUNET_SERVER_MessageHandler *my_handlers;
168
169 /**
170 * Array of the lengths of the entries in addrs.
171 */
172 socklen_t *addrlens;
173
174 /**
175 * NULL-terminated array of listen sockets we should take over.
176 */
177 struct GNUNET_NETWORK_Handle **lsocks;
178
179 /**
180 * Task ID of the shutdown task.
181 */
182 struct GNUNET_SCHEDULER_Task *shutdown_task;
183
184 /**
185 * Idle timeout for server.
186 */
187 struct GNUNET_TIME_Relative timeout;
188
189 /**
190 * Overall success/failure of the service start.
191 */
192 int ret;
193
194 /**
195 * If we are daemonizing, this FD is set to the
196 * pipe to the parent. Send '.' if we started
197 * ok, '!' if not. -1 if we are not daemonizing.
198 */
199 int ready_confirm_fd;
200
201 /**
202 * Do we close connections if we receive messages
203 * for which we have no handler?
204 */
205 int require_found;
206
207 /**
208 * Do we require a matching UID for UNIX domain socket connections?
209 * #GNUNET_NO means that the UID does not have to match (however,
210 * @e match_gid may still impose other access control checks).
211 */
212 int match_uid;
213
214 /**
215 * Do we require a matching GID for UNIX domain socket connections?
216 * Ignored if @e match_uid is #GNUNET_YES. Note that this is about
217 * checking that the client's UID is in our group OR that the
218 * client's GID is our GID. If both "match_gid" and @e match_uid are
219 * #GNUNET_NO, all users on the local system have access.
220 */
221 int match_gid;
222
223 /**
224 * Our options.
225 */
226 enum LEGACY_SERVICE_Options options;
227
228};
229
230
231/* ****************** message handlers ****************** */
232
233/**
234 * Send a 'TEST' message back to the client.
235 *
236 * @param cls the 'struct GNUNET_SERVER_Client' to send TEST to
237 * @param size number of bytes available in 'buf'
238 * @param buf where to copy the message
239 * @return number of bytes written to 'buf'
240 */
241static size_t
242write_test (void *cls, size_t size, void *buf)
243{
244 struct GNUNET_SERVER_Client *client = cls;
245 struct GNUNET_MessageHeader *msg;
246
247 if (size < sizeof (struct GNUNET_MessageHeader))
248 {
249 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
250 return 0; /* client disconnected */
251 }
252 msg = (struct GNUNET_MessageHeader *) buf;
253 msg->type = htons (GNUNET_MESSAGE_TYPE_TEST);
254 msg->size = htons (sizeof (struct GNUNET_MessageHeader));
255 GNUNET_SERVER_receive_done (client, GNUNET_OK);
256 return sizeof (struct GNUNET_MessageHeader);
257}
258
259
260/**
261 * Handler for TEST message.
262 *
263 * @param cls closure (refers to service)
264 * @param client identification of the client
265 * @param message the actual message
266 */
267static void
268handle_test (void *cls, struct GNUNET_SERVER_Client *client,
269 const struct GNUNET_MessageHeader *message)
270{
271 /* simply bounce message back to acknowledge */
272 if (NULL ==
273 GNUNET_SERVER_notify_transmit_ready (client,
274 sizeof (struct GNUNET_MessageHeader),
275 GNUNET_TIME_UNIT_FOREVER_REL,
276 &write_test, client))
277 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
278}
279
280
281/**
282 * Default handlers for all services. Will be copied and the
283 * "callback_cls" fields will be replaced with the specific service
284 * struct.
285 */
286static const struct GNUNET_SERVER_MessageHandler defhandlers[] = {
287 {&handle_test, NULL, GNUNET_MESSAGE_TYPE_TEST,
288 sizeof (struct GNUNET_MessageHeader)},
289 {NULL, NULL, 0, 0}
290};
291
292
293/* ****************** service core routines ************** */
294
295
296/**
297 * Check if access to the service is allowed from the given address.
298 *
299 * @param cls closure
300 * @param uc credentials, if available, otherwise NULL
301 * @param addr address
302 * @param addrlen length of address
303 * @return #GNUNET_YES to allow, #GNUNET_NO to deny, #GNUNET_SYSERR
304 * for unknown address family (will be denied).
305 */
306static int
307check_access (void *cls, const struct GNUNET_CONNECTION_Credentials *uc,
308 const struct sockaddr *addr, socklen_t addrlen)
309{
310 struct LEGACY_SERVICE_Context *sctx = cls;
311 const struct sockaddr_in *i4;
312 const struct sockaddr_in6 *i6;
313 int ret;
314
315 switch (addr->sa_family)
316 {
317 case AF_INET:
318 GNUNET_assert (addrlen == sizeof (struct sockaddr_in));
319 i4 = (const struct sockaddr_in *) addr;
320 ret = ((NULL == sctx->v4_allowed) ||
321 (check_ipv4_listed (sctx->v4_allowed, &i4->sin_addr))) &&
322 ((NULL == sctx->v4_denied) ||
323 (!check_ipv4_listed (sctx->v4_denied, &i4->sin_addr)));
324 break;
325 case AF_INET6:
326 GNUNET_assert (addrlen == sizeof (struct sockaddr_in6));
327 i6 = (const struct sockaddr_in6 *) addr;
328 ret = ((NULL == sctx->v6_allowed) ||
329 (check_ipv6_listed (sctx->v6_allowed, &i6->sin6_addr))) &&
330 ((NULL == sctx->v6_denied) ||
331 (!check_ipv6_listed (sctx->v6_denied, &i6->sin6_addr)));
332 break;
333#ifndef WINDOWS
334 case AF_UNIX:
335 ret = GNUNET_OK; /* controlled using file-system ACL now */
336 break;
337#endif
338 default:
339 LOG (GNUNET_ERROR_TYPE_WARNING, _("Unknown address family %d\n"),
340 addr->sa_family);
341 return GNUNET_SYSERR;
342 }
343 if (GNUNET_OK != ret)
344 {
345 LOG (GNUNET_ERROR_TYPE_WARNING,
346 _("Access from `%s' denied to service `%s'\n"),
347 GNUNET_a2s (addr, addrlen),
348 sctx->service_name);
349 }
350 return ret;
351}
352
353
354/**
355 * Get the name of the file where we will
356 * write the PID of the service.
357 *
358 * @param sctx service context
359 * @return name of the file for the process ID
360 */
361static char *
362get_pid_file_name (struct LEGACY_SERVICE_Context *sctx)
363{
364 char *pif;
365
366 if (GNUNET_OK !=
367 GNUNET_CONFIGURATION_get_value_filename (sctx->cfg, sctx->service_name,
368 "PIDFILE", &pif))
369 return NULL;
370 return pif;
371}
372
373
374/**
375 * Parse an IPv4 access control list.
376 *
377 * @param ret location where to write the ACL (set)
378 * @param sctx service context to use to get the configuration
379 * @param option name of the ACL option to parse
380 * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including
381 * no ACL configured)
382 */
383static int
384process_acl4 (struct GNUNET_STRINGS_IPv4NetworkPolicy **ret,
385 struct LEGACY_SERVICE_Context *sctx,
386 const char *option)
387{
388 char *opt;
389
390 if (!GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, option))
391 {
392 *ret = NULL;
393 return GNUNET_OK;
394 }
395 GNUNET_break (GNUNET_OK ==
396 GNUNET_CONFIGURATION_get_value_string (sctx->cfg,
397 sctx->service_name,
398 option, &opt));
399 if (NULL == (*ret = GNUNET_STRINGS_parse_ipv4_policy (opt)))
400 {
401 LOG (GNUNET_ERROR_TYPE_WARNING,
402 _("Could not parse IPv4 network specification `%s' for `%s:%s'\n"),
403 opt, sctx->service_name, option);
404 GNUNET_free (opt);
405 return GNUNET_SYSERR;
406 }
407 GNUNET_free (opt);
408 return GNUNET_OK;
409}
410
411
412/**
413 * Parse an IPv6 access control list.
414 *
415 * @param ret location where to write the ACL (set)
416 * @param sctx service context to use to get the configuration
417 * @param option name of the ACL option to parse
418 * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including
419 * no ACL configured)
420 */
421static int
422process_acl6 (struct GNUNET_STRINGS_IPv6NetworkPolicy **ret,
423 struct LEGACY_SERVICE_Context *sctx,
424 const char *option)
425{
426 char *opt;
427
428 if (!GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, option))
429 {
430 *ret = NULL;
431 return GNUNET_OK;
432 }
433 GNUNET_break (GNUNET_OK ==
434 GNUNET_CONFIGURATION_get_value_string (sctx->cfg,
435 sctx->service_name,
436 option, &opt));
437 if (NULL == (*ret = GNUNET_STRINGS_parse_ipv6_policy (opt)))
438 {
439 LOG (GNUNET_ERROR_TYPE_WARNING,
440 _("Could not parse IPv6 network specification `%s' for `%s:%s'\n"),
441 opt, sctx->service_name, option);
442 GNUNET_free (opt);
443 return GNUNET_SYSERR;
444 }
445 GNUNET_free (opt);
446 return GNUNET_OK;
447}
448
449
450/**
451 * Add the given UNIX domain path as an address to the
452 * list (as the first entry).
453 *
454 * @param saddrs array to update
455 * @param saddrlens where to store the address length
456 * @param unixpath path to add
457 * @param abstract #GNUNET_YES to add an abstract UNIX domain socket. This
458 * parameter is ignore on systems other than LINUX
459 */
460static void
461add_unixpath (struct sockaddr **saddrs,
462 socklen_t *saddrlens,
463 const char *unixpath,
464 int abstract)
465{
466#ifdef AF_UNIX
467 struct sockaddr_un *un;
468
469 un = GNUNET_new (struct sockaddr_un);
470 un->sun_family = AF_UNIX;
471 strncpy (un->sun_path, unixpath, sizeof (un->sun_path) - 1);
472#ifdef LINUX
473 if (GNUNET_YES == abstract)
474 un->sun_path[0] = '\0';
475#endif
476#if HAVE_SOCKADDR_UN_SUN_LEN
477 un->sun_len = (u_char) sizeof (struct sockaddr_un);
478#endif
479 *saddrs = (struct sockaddr *) un;
480 *saddrlens = sizeof (struct sockaddr_un);
481#else
482 /* this function should never be called
483 * unless AF_UNIX is defined! */
484 GNUNET_assert (0);
485#endif
486}
487
488
489/**
490 * Get the list of addresses that a server for the given service
491 * should bind to.
492 *
493 * @param service_name name of the service
494 * @param cfg configuration (which specifies the addresses)
495 * @param addrs set (call by reference) to an array of pointers to the
496 * addresses the server should bind to and listen on; the
497 * array will be NULL-terminated (on success)
498 * @param addr_lens set (call by reference) to an array of the lengths
499 * of the respective `struct sockaddr` struct in the @a addrs
500 * array (on success)
501 * @return number of addresses found on success,
502 * #GNUNET_SYSERR if the configuration
503 * did not specify reasonable finding information or
504 * if it specified a hostname that could not be resolved;
505 * #GNUNET_NO if the number of addresses configured is
506 * zero (in this case, `*addrs` and `*addr_lens` will be
507 * set to NULL).
508 */
509int
510LEGACY_SERVICE_get_server_addresses (const char *service_name,
511 const struct GNUNET_CONFIGURATION_Handle *cfg,
512 struct sockaddr ***addrs,
513 socklen_t ** addr_lens)
514{
515 int disablev6;
516 struct GNUNET_NETWORK_Handle *desc;
517 unsigned long long port;
518 char *unixpath;
519 struct addrinfo hints;
520 struct addrinfo *res;
521 struct addrinfo *pos;
522 struct addrinfo *next;
523 unsigned int i;
524 int resi;
525 int ret;
526 int abstract;
527 struct sockaddr **saddrs;
528 socklen_t *saddrlens;
529 char *hostname;
530
531 *addrs = NULL;
532 *addr_lens = NULL;
533 desc = NULL;
534 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "DISABLEV6"))
535 {
536 if (GNUNET_SYSERR ==
537 (disablev6 =
538 GNUNET_CONFIGURATION_get_value_yesno (cfg, service_name, "DISABLEV6")))
539 return GNUNET_SYSERR;
540 }
541 else
542 disablev6 = GNUNET_NO;
543
544 if (! disablev6)
545 {
546 /* probe IPv6 support */
547 desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
548 if (NULL == desc)
549 {
550 if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
551 (EACCES == errno))
552 {
553 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
554 return GNUNET_SYSERR;
555 }
556 LOG (GNUNET_ERROR_TYPE_INFO,
557 _("Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"),
558 service_name, STRERROR (errno));
559 disablev6 = GNUNET_YES;
560 }
561 else
562 {
563 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
564 desc = NULL;
565 }
566 }
567
568 port = 0;
569 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT"))
570 {
571 if (GNUNET_OK !=
572 GNUNET_CONFIGURATION_get_value_number (cfg, service_name,
573 "PORT", &port))
574 {
575 LOG (GNUNET_ERROR_TYPE_ERROR,
576 _("Require valid port number for service `%s' in configuration!\n"),
577 service_name);
578 }
579 if (port > 65535)
580 {
581 LOG (GNUNET_ERROR_TYPE_ERROR,
582 _("Require valid port number for service `%s' in configuration!\n"),
583 service_name);
584 return GNUNET_SYSERR;
585 }
586 }
587
588 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "BINDTO"))
589 {
590 GNUNET_break (GNUNET_OK ==
591 GNUNET_CONFIGURATION_get_value_string (cfg, service_name,
592 "BINDTO", &hostname));
593 }
594 else
595 hostname = NULL;
596
597 unixpath = NULL;
598 abstract = GNUNET_NO;
599#ifdef AF_UNIX
600 if ((GNUNET_YES ==
601 GNUNET_CONFIGURATION_have_value (cfg, service_name, "UNIXPATH")) &&
602 (GNUNET_OK ==
603 GNUNET_CONFIGURATION_get_value_filename (cfg, service_name, "UNIXPATH",
604 &unixpath)) &&
605 (0 < strlen (unixpath)))
606 {
607 /* probe UNIX support */
608 struct sockaddr_un s_un;
609
610 if (strlen (unixpath) >= sizeof (s_un.sun_path))
611 {
612 LOG (GNUNET_ERROR_TYPE_WARNING,
613 _("UNIXPATH `%s' too long, maximum length is %llu\n"), unixpath,
614 (unsigned long long) sizeof (s_un.sun_path));
615 unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
616 LOG (GNUNET_ERROR_TYPE_INFO,
617 _("Using `%s' instead\n"),
618 unixpath);
619 }
620#ifdef LINUX
621 abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg,
622 "TESTING",
623 "USE_ABSTRACT_SOCKETS");
624 if (GNUNET_SYSERR == abstract)
625 abstract = GNUNET_NO;
626#endif
627 if ((GNUNET_YES != abstract)
628 && (GNUNET_OK !=
629 GNUNET_DISK_directory_create_for_file (unixpath)))
630 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
631 "mkdir",
632 unixpath);
633 }
634 if (NULL != unixpath)
635 {
636 desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
637 if (NULL == desc)
638 {
639 if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
640 (EACCES == errno))
641 {
642 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
643 GNUNET_free_non_null (hostname);
644 GNUNET_free (unixpath);
645 return GNUNET_SYSERR;
646 }
647 LOG (GNUNET_ERROR_TYPE_INFO,
648 _("Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"),
649 service_name,
650 STRERROR (errno));
651 GNUNET_free (unixpath);
652 unixpath = NULL;
653 }
654 else
655 {
656 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
657 desc = NULL;
658 }
659 }
660#endif
661
662 if ((0 == port) && (NULL == unixpath))
663 {
664 LOG (GNUNET_ERROR_TYPE_ERROR,
665 _("Have neither PORT nor UNIXPATH for service `%s', but one is required\n"),
666 service_name);
667 GNUNET_free_non_null (hostname);
668 return GNUNET_SYSERR;
669 }
670 if (0 == port)
671 {
672 saddrs = GNUNET_malloc (2 * sizeof (struct sockaddr *));
673 saddrlens = GNUNET_malloc (2 * sizeof (socklen_t));
674 add_unixpath (saddrs, saddrlens, unixpath, abstract);
675 GNUNET_free_non_null (unixpath);
676 GNUNET_free_non_null (hostname);
677 *addrs = saddrs;
678 *addr_lens = saddrlens;
679 return 1;
680 }
681
682 if (NULL != hostname)
683 {
684 LOG (GNUNET_ERROR_TYPE_DEBUG,
685 "Resolving `%s' since that is where `%s' will bind to.\n",
686 hostname,
687 service_name);
688 memset (&hints, 0, sizeof (struct addrinfo));
689 if (disablev6)
690 hints.ai_family = AF_INET;
691 hints.ai_protocol = IPPROTO_TCP;
692 if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
693 (NULL == res))
694 {
695 LOG (GNUNET_ERROR_TYPE_ERROR,
696 _("Failed to resolve `%s': %s\n"),
697 hostname,
698 gai_strerror (ret));
699 GNUNET_free (hostname);
700 GNUNET_free_non_null (unixpath);
701 return GNUNET_SYSERR;
702 }
703 next = res;
704 i = 0;
705 while (NULL != (pos = next))
706 {
707 next = pos->ai_next;
708 if ((disablev6) && (pos->ai_family == AF_INET6))
709 continue;
710 i++;
711 }
712 if (0 == i)
713 {
714 LOG (GNUNET_ERROR_TYPE_ERROR,
715 _("Failed to find %saddress for `%s'.\n"),
716 disablev6 ? "IPv4 " : "",
717 hostname);
718 freeaddrinfo (res);
719 GNUNET_free (hostname);
720 GNUNET_free_non_null (unixpath);
721 return GNUNET_SYSERR;
722 }
723 resi = i;
724 if (NULL != unixpath)
725 resi++;
726 saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
727 saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
728 i = 0;
729 if (NULL != unixpath)
730 {
731 add_unixpath (saddrs, saddrlens, unixpath, abstract);
732 i++;
733 }
734 next = res;
735 while (NULL != (pos = next))
736 {
737 next = pos->ai_next;
738 if ((disablev6) && (AF_INET6 == pos->ai_family))
739 continue;
740 if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol))
741 continue; /* not TCP */
742 if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype))
743 continue; /* huh? */
744 LOG (GNUNET_ERROR_TYPE_DEBUG, "Service `%s' will bind to `%s'\n",
745 service_name, GNUNET_a2s (pos->ai_addr, pos->ai_addrlen));
746 if (AF_INET == pos->ai_family)
747 {
748 GNUNET_assert (sizeof (struct sockaddr_in) == pos->ai_addrlen);
749 saddrlens[i] = pos->ai_addrlen;
750 saddrs[i] = GNUNET_malloc (saddrlens[i]);
751 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
752 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
753 }
754 else
755 {
756 GNUNET_assert (AF_INET6 == pos->ai_family);
757 GNUNET_assert (sizeof (struct sockaddr_in6) == pos->ai_addrlen);
758 saddrlens[i] = pos->ai_addrlen;
759 saddrs[i] = GNUNET_malloc (saddrlens[i]);
760 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
761 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
762 }
763 i++;
764 }
765 GNUNET_free (hostname);
766 freeaddrinfo (res);
767 resi = i;
768 }
769 else
770 {
771 /* will bind against everything, just set port */
772 if (disablev6)
773 {
774 /* V4-only */
775 resi = 1;
776 if (NULL != unixpath)
777 resi++;
778 i = 0;
779 saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
780 saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
781 if (NULL != unixpath)
782 {
783 add_unixpath (saddrs, saddrlens, unixpath, abstract);
784 i++;
785 }
786 saddrlens[i] = sizeof (struct sockaddr_in);
787 saddrs[i] = GNUNET_malloc (saddrlens[i]);
788#if HAVE_SOCKADDR_IN_SIN_LEN
789 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
790#endif
791 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
792 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
793 }
794 else
795 {
796 /* dual stack */
797 resi = 2;
798 if (NULL != unixpath)
799 resi++;
800 saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
801 saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
802 i = 0;
803 if (NULL != unixpath)
804 {
805 add_unixpath (saddrs, saddrlens, unixpath, abstract);
806 i++;
807 }
808 saddrlens[i] = sizeof (struct sockaddr_in6);
809 saddrs[i] = GNUNET_malloc (saddrlens[i]);
810#if HAVE_SOCKADDR_IN_SIN_LEN
811 ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
812#endif
813 ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
814 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
815 i++;
816 saddrlens[i] = sizeof (struct sockaddr_in);
817 saddrs[i] = GNUNET_malloc (saddrlens[i]);
818#if HAVE_SOCKADDR_IN_SIN_LEN
819 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
820#endif
821 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
822 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
823 }
824 }
825 GNUNET_free_non_null (unixpath);
826 *addrs = saddrs;
827 *addr_lens = saddrlens;
828 return resi;
829}
830
831
832#ifdef MINGW
833/**
834 * Read listen sockets from the parent process (ARM).
835 *
836 * @param sctx service context to initialize
837 * @return #GNUNET_YES if ok, #GNUNET_NO if not ok (must bind yourself),
838 * and #GNUNET_SYSERR on error.
839 */
840static int
841receive_sockets_from_parent (struct LEGACY_SERVICE_Context *sctx)
842{
843 const char *env_buf;
844 int fail;
845 uint64_t count;
846 uint64_t i;
847 HANDLE lsocks_pipe;
848
849 env_buf = getenv ("GNUNET_OS_READ_LSOCKS");
850 if ((NULL == env_buf) || (strlen (env_buf) <= 0))
851 return GNUNET_NO;
852 /* Using W32 API directly here, because this pipe will
853 * never be used outside of this function, and it's just too much of a bother
854 * to create a GNUnet API that boxes a HANDLE (the way it is done with socks)
855 */
856 lsocks_pipe = (HANDLE) strtoul (env_buf, NULL, 10);
857 if ( (0 == lsocks_pipe) || (INVALID_HANDLE_VALUE == lsocks_pipe))
858 return GNUNET_NO;
859 fail = 1;
860 do
861 {
862 int ret;
863 int fail2;
864 DWORD rd;
865
866 ret = ReadFile (lsocks_pipe, &count, sizeof (count), &rd, NULL);
867 if ((0 == ret) || (sizeof (count) != rd) || (0 == count))
868 break;
869 sctx->lsocks =
870 GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (count + 1));
871
872 fail2 = 1;
873 for (i = 0; i < count; i++)
874 {
875 WSAPROTOCOL_INFOA pi;
876 uint64_t size;
877 SOCKET s;
878
879 ret = ReadFile (lsocks_pipe, &size, sizeof (size), &rd, NULL);
880 if ( (0 == ret) || (sizeof (size) != rd) || (sizeof (pi) != size) )
881 break;
882 ret = ReadFile (lsocks_pipe, &pi, sizeof (pi), &rd, NULL);
883 if ( (0 == ret) || (sizeof (pi) != rd))
884 break;
885 s = WSASocketA (pi.iAddressFamily, pi.iSocketType, pi.iProtocol, &pi, 0, WSA_FLAG_OVERLAPPED);
886 sctx->lsocks[i] = GNUNET_NETWORK_socket_box_native (s);
887 if (NULL == sctx->lsocks[i])
888 break;
889 else if (i == count - 1)
890 fail2 = 0;
891 }
892 if (fail2)
893 break;
894 sctx->lsocks[count] = NULL;
895 fail = 0;
896 }
897 while (fail);
898
899 CloseHandle (lsocks_pipe);
900
901 if (fail)
902 {
903 LOG (GNUNET_ERROR_TYPE_ERROR,
904 _("Could not access a pre-bound socket, will try to bind myself\n"));
905 for (i = 0; (i < count) && (NULL != sctx->lsocks[i]); i++)
906 GNUNET_break (0 == GNUNET_NETWORK_socket_close (sctx->lsocks[i]));
907 GNUNET_free_non_null (sctx->lsocks);
908 sctx->lsocks = NULL;
909 return GNUNET_NO;
910 }
911 return GNUNET_YES;
912}
913#endif
914
915
916/**
917 * Setup addr, addrlen, idle_timeout
918 * based on configuration!
919 *
920 * Configuration may specify:
921 * - PORT (where to bind to for TCP)
922 * - UNIXPATH (where to bind to for UNIX domain sockets)
923 * - TIMEOUT (after how many ms does an inactive service timeout);
924 * - DISABLEV6 (disable support for IPv6, otherwise we use dual-stack)
925 * - BINDTO (hostname or IP address to bind to, otherwise we take everything)
926 * - ACCEPT_FROM (only allow connections from specified IPv4 subnets)
927 * - ACCEPT_FROM6 (only allow connections from specified IPv6 subnets)
928 * - REJECT_FROM (disallow allow connections from specified IPv4 subnets)
929 * - REJECT_FROM6 (disallow allow connections from specified IPv6 subnets)
930 *
931 * @param sctx service context to initialize
932 * @return #GNUNET_OK if configuration succeeded
933 */
934static int
935setup_service (struct LEGACY_SERVICE_Context *sctx)
936{
937 struct GNUNET_TIME_Relative idleout;
938 int tolerant;
939
940#ifndef MINGW
941 const char *nfds;
942 unsigned int cnt;
943 int flags;
944#endif
945
946 if (GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, "TIMEOUT"))
947 {
948 if (GNUNET_OK !=
949 GNUNET_CONFIGURATION_get_value_time (sctx->cfg, sctx->service_name,
950 "TIMEOUT", &idleout))
951 {
952 LOG (GNUNET_ERROR_TYPE_ERROR,
953 _("Specified value for `%s' of service `%s' is invalid\n"),
954 "TIMEOUT", sctx->service_name);
955 return GNUNET_SYSERR;
956 }
957 sctx->timeout = idleout;
958 }
959 else
960 sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
961
962 if (GNUNET_CONFIGURATION_have_value
963 (sctx->cfg, sctx->service_name, "TOLERANT"))
964 {
965 if (GNUNET_SYSERR ==
966 (tolerant =
967 GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->service_name,
968 "TOLERANT")))
969 {
970 LOG (GNUNET_ERROR_TYPE_ERROR,
971 _("Specified value for `%s' of service `%s' is invalid\n"),
972 "TOLERANT", sctx->service_name);
973 return GNUNET_SYSERR;
974 }
975 }
976 else
977 tolerant = GNUNET_NO;
978
979#ifndef MINGW
980 errno = 0;
981 if ((NULL != (nfds = getenv ("LISTEN_FDS"))) &&
982 (1 == SSCANF (nfds, "%u", &cnt)) && (cnt > 0) && (cnt < FD_SETSIZE) &&
983 (cnt + 4 < FD_SETSIZE))
984 {
985 sctx->lsocks =
986 GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (cnt + 1));
987 while (0 < cnt--)
988 {
989 flags = fcntl (3 + cnt, F_GETFD);
990 if ((flags < 0) || (0 != (flags & FD_CLOEXEC)) ||
991 (NULL ==
992 (sctx->lsocks[cnt] = GNUNET_NETWORK_socket_box_native (3 + cnt))))
993 {
994 LOG (GNUNET_ERROR_TYPE_ERROR,
995 _
996 ("Could not access pre-bound socket %u, will try to bind myself\n"),
997 (unsigned int) 3 + cnt);
998 cnt++;
999 while (sctx->lsocks[cnt] != NULL)
1000 GNUNET_break (0 == GNUNET_NETWORK_socket_close (sctx->lsocks[cnt++]));
1001 GNUNET_free (sctx->lsocks);
1002 sctx->lsocks = NULL;
1003 break;
1004 }
1005 }
1006 unsetenv ("LISTEN_FDS");
1007 }
1008#else
1009 if (getenv ("GNUNET_OS_READ_LSOCKS") != NULL)
1010 {
1011 receive_sockets_from_parent (sctx);
1012 putenv ("GNUNET_OS_READ_LSOCKS=");
1013 }
1014#endif
1015
1016 if ((NULL == sctx->lsocks) &&
1017 (GNUNET_SYSERR ==
1018 LEGACY_SERVICE_get_server_addresses (sctx->service_name, sctx->cfg,
1019 &sctx->addrs, &sctx->addrlens)))
1020 return GNUNET_SYSERR;
1021 sctx->require_found = tolerant ? GNUNET_NO : GNUNET_YES;
1022 sctx->match_uid =
1023 GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->service_name,
1024 "UNIX_MATCH_UID");
1025 sctx->match_gid =
1026 GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->service_name,
1027 "UNIX_MATCH_GID");
1028 process_acl4 (&sctx->v4_denied, sctx, "REJECT_FROM");
1029 process_acl4 (&sctx->v4_allowed, sctx, "ACCEPT_FROM");
1030 process_acl6 (&sctx->v6_denied, sctx, "REJECT_FROM6");
1031 process_acl6 (&sctx->v6_allowed, sctx, "ACCEPT_FROM6");
1032
1033 return GNUNET_OK;
1034}
1035
1036
1037/**
1038 * Get the name of the user that'll be used
1039 * to provide the service.
1040 *
1041 * @param sctx service context
1042 * @return value of the 'USERNAME' option
1043 */
1044static char *
1045get_user_name (struct LEGACY_SERVICE_Context *sctx)
1046{
1047 char *un;
1048
1049 if (GNUNET_OK !=
1050 GNUNET_CONFIGURATION_get_value_filename (sctx->cfg, sctx->service_name,
1051 "USERNAME", &un))
1052 return NULL;
1053 return un;
1054}
1055
1056
1057/**
1058 * Write PID file.
1059 *
1060 * @param sctx service context
1061 * @param pid PID to write (should be equal to 'getpid()'
1062 * @return #GNUNET_OK on success (including no work to be done)
1063 */
1064static int
1065write_pid_file (struct LEGACY_SERVICE_Context *sctx, pid_t pid)
1066{
1067 FILE *pidfd;
1068 char *pif;
1069 char *user;
1070 char *rdir;
1071 int len;
1072
1073 if (NULL == (pif = get_pid_file_name (sctx)))
1074 return GNUNET_OK; /* no file desired */
1075 user = get_user_name (sctx);
1076 rdir = GNUNET_strdup (pif);
1077 len = strlen (rdir);
1078 while ((len > 0) && (rdir[len] != DIR_SEPARATOR))
1079 len--;
1080 rdir[len] = '\0';
1081 if (0 != ACCESS (rdir, F_OK))
1082 {
1083 /* we get to create a directory -- and claim it
1084 * as ours! */
1085 (void) GNUNET_DISK_directory_create (rdir);
1086 if ((NULL != user) && (0 < strlen (user)))
1087 GNUNET_DISK_file_change_owner (rdir, user);
1088 }
1089 if (0 != ACCESS (rdir, W_OK | X_OK))
1090 {
1091 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "access", rdir);
1092 GNUNET_free (rdir);
1093 GNUNET_free_non_null (user);
1094 GNUNET_free (pif);
1095 return GNUNET_SYSERR;
1096 }
1097 GNUNET_free (rdir);
1098 pidfd = FOPEN (pif, "w");
1099 if (NULL == pidfd)
1100 {
1101 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "fopen", pif);
1102 GNUNET_free (pif);
1103 GNUNET_free_non_null (user);
1104 return GNUNET_SYSERR;
1105 }
1106 if (0 > FPRINTF (pidfd, "%u", pid))
1107 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fprintf", pif);
1108 GNUNET_break (0 == FCLOSE (pidfd));
1109 if ((NULL != user) && (0 < strlen (user)))
1110 GNUNET_DISK_file_change_owner (pif, user);
1111 GNUNET_free_non_null (user);
1112 GNUNET_free (pif);
1113 return GNUNET_OK;
1114}
1115
1116
1117/**
1118 * Task run during shutdown. Stops the server/service.
1119 *
1120 * @param cls the `struct LEGACY_SERVICE_Context`
1121 */
1122static void
1123shutdown_task (void *cls)
1124{
1125 struct LEGACY_SERVICE_Context *service = cls;
1126 struct GNUNET_SERVER_Handle *server = service->server;
1127
1128 service->shutdown_task = NULL;
1129 if (0 != (service->options & LEGACY_SERVICE_OPTION_SOFT_SHUTDOWN))
1130 GNUNET_SERVER_stop_listening (server);
1131 else
1132 GNUNET_SERVER_destroy (server);
1133}
1134
1135
1136/**
1137 * Initial task for the service.
1138 *
1139 * @param cls service context
1140 */
1141static void
1142service_task (void *cls)
1143{
1144 struct LEGACY_SERVICE_Context *sctx = cls;
1145 unsigned int i;
1146
1147 GNUNET_RESOLVER_connect (sctx->cfg);
1148 if (NULL != sctx->lsocks)
1149 sctx->server
1150 = GNUNET_SERVER_create_with_sockets (&check_access, sctx, sctx->lsocks,
1151 sctx->timeout, sctx->require_found);
1152 else
1153 sctx->server
1154 = GNUNET_SERVER_create (&check_access, sctx, sctx->addrs, sctx->addrlens,
1155 sctx->timeout, sctx->require_found);
1156 if (NULL == sctx->server)
1157 {
1158 if (NULL != sctx->addrs)
1159 for (i = 0; NULL != sctx->addrs[i]; i++)
1160 LOG (GNUNET_ERROR_TYPE_INFO,
1161 _("Failed to start `%s' at `%s'\n"),
1162 sctx->service_name, GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i]));
1163 sctx->ret = GNUNET_SYSERR;
1164 return;
1165 }
1166#ifndef WINDOWS
1167 if (NULL != sctx->addrs)
1168 for (i = 0; NULL != sctx->addrs[i]; i++)
1169 if ((AF_UNIX == sctx->addrs[i]->sa_family)
1170 && ('\0' != ((const struct sockaddr_un *)sctx->addrs[i])->sun_path[0]))
1171 GNUNET_DISK_fix_permissions (((const struct sockaddr_un *)sctx->addrs[i])->sun_path,
1172 sctx->match_uid,
1173 sctx->match_gid);
1174#endif
1175
1176
1177 if (0 == (sctx->options & LEGACY_SERVICE_OPTION_MANUAL_SHUTDOWN))
1178 {
1179 /* install a task that will kill the server
1180 * process if the scheduler ever gets a shutdown signal */
1181 sctx->shutdown_task = GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1182 sctx);
1183 }
1184 sctx->my_handlers = GNUNET_malloc (sizeof (defhandlers));
1185 GNUNET_memcpy (sctx->my_handlers, defhandlers, sizeof (defhandlers));
1186 i = 0;
1187 while (NULL != sctx->my_handlers[i].callback)
1188 sctx->my_handlers[i++].callback_cls = sctx;
1189 GNUNET_SERVER_add_handlers (sctx->server, sctx->my_handlers);
1190 if (-1 != sctx->ready_confirm_fd)
1191 {
1192 GNUNET_break (1 == WRITE (sctx->ready_confirm_fd, ".", 1));
1193 GNUNET_break (0 == CLOSE (sctx->ready_confirm_fd));
1194 sctx->ready_confirm_fd = -1;
1195 write_pid_file (sctx, getpid ());
1196 }
1197 if (NULL != sctx->addrs)
1198 {
1199 i = 0;
1200 while (NULL != sctx->addrs[i])
1201 {
1202 LOG (GNUNET_ERROR_TYPE_INFO, _("Service `%s' runs at %s\n"),
1203 sctx->service_name, GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i]));
1204 i++;
1205 }
1206 }
1207 sctx->task (sctx->task_cls, sctx->server, sctx->cfg);
1208}
1209
1210
1211/**
1212 * Detach from terminal.
1213 *
1214 * @param sctx service context
1215 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1216 */
1217static int
1218detach_terminal (struct LEGACY_SERVICE_Context *sctx)
1219{
1220#ifndef MINGW
1221 pid_t pid;
1222 int nullfd;
1223 int filedes[2];
1224
1225 if (0 != PIPE (filedes))
1226 {
1227 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "pipe");
1228 return GNUNET_SYSERR;
1229 }
1230 pid = fork ();
1231 if (pid < 0)
1232 {
1233 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fork");
1234 return GNUNET_SYSERR;
1235 }
1236 if (0 != pid)
1237 {
1238 /* Parent */
1239 char c;
1240
1241 GNUNET_break (0 == CLOSE (filedes[1]));
1242 c = 'X';
1243 if (1 != READ (filedes[0], &c, sizeof (char)))
1244 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "read");
1245 fflush (stdout);
1246 switch (c)
1247 {
1248 case '.':
1249 exit (0);
1250 case 'I':
1251 LOG (GNUNET_ERROR_TYPE_INFO, _("Service process failed to initialize\n"));
1252 break;
1253 case 'S':
1254 LOG (GNUNET_ERROR_TYPE_INFO,
1255 _("Service process could not initialize server function\n"));
1256 break;
1257 case 'X':
1258 LOG (GNUNET_ERROR_TYPE_INFO,
1259 _("Service process failed to report status\n"));
1260 break;
1261 }
1262 exit (1); /* child reported error */
1263 }
1264 GNUNET_break (0 == CLOSE (0));
1265 GNUNET_break (0 == CLOSE (1));
1266 GNUNET_break (0 == CLOSE (filedes[0]));
1267 nullfd = OPEN ("/dev/null", O_RDWR | O_APPEND);
1268 if (nullfd < 0)
1269 return GNUNET_SYSERR;
1270 /* set stdin/stdout to /dev/null */
1271 if ((dup2 (nullfd, 0) < 0) || (dup2 (nullfd, 1) < 0))
1272 {
1273 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2");
1274 (void) CLOSE (nullfd);
1275 return GNUNET_SYSERR;
1276 }
1277 (void) CLOSE (nullfd);
1278 /* Detach from controlling terminal */
1279 pid = setsid ();
1280 if (-1 == pid)
1281 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "setsid");
1282 sctx->ready_confirm_fd = filedes[1];
1283#else
1284 /* FIXME: we probably need to do something else
1285 * elsewhere in order to fork the process itself... */
1286 FreeConsole ();
1287#endif
1288 return GNUNET_OK;
1289}
1290
1291
1292/**
1293 * Set user ID.
1294 *
1295 * @param sctx service context
1296 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1297 */
1298static int
1299set_user_id (struct LEGACY_SERVICE_Context *sctx)
1300{
1301 char *user;
1302
1303 if (NULL == (user = get_user_name (sctx)))
1304 return GNUNET_OK; /* keep */
1305#ifndef MINGW
1306 struct passwd *pws;
1307
1308 errno = 0;
1309 pws = getpwnam (user);
1310 if (NULL == pws)
1311 {
1312 LOG (GNUNET_ERROR_TYPE_ERROR,
1313 _("Cannot obtain information about user `%s': %s\n"), user,
1314 errno == 0 ? _("No such user") : STRERROR (errno));
1315 GNUNET_free (user);
1316 return GNUNET_SYSERR;
1317 }
1318 if ((0 != setgid (pws->pw_gid)) || (0 != setegid (pws->pw_gid)) ||
1319#if HAVE_INITGROUPS
1320 (0 != initgroups (user, pws->pw_gid)) ||
1321#endif
1322 (0 != setuid (pws->pw_uid)) || (0 != seteuid (pws->pw_uid)))
1323 {
1324 if ((0 != setregid (pws->pw_gid, pws->pw_gid)) ||
1325 (0 != setreuid (pws->pw_uid, pws->pw_uid)))
1326 {
1327 LOG (GNUNET_ERROR_TYPE_ERROR, _("Cannot change user/group to `%s': %s\n"),
1328 user, STRERROR (errno));
1329 GNUNET_free (user);
1330 return GNUNET_SYSERR;
1331 }
1332 }
1333#endif
1334 GNUNET_free (user);
1335 return GNUNET_OK;
1336}
1337
1338
1339/**
1340 * Delete the PID file that was created by our parent.
1341 *
1342 * @param sctx service context
1343 */
1344static void
1345pid_file_delete (struct LEGACY_SERVICE_Context *sctx)
1346{
1347 char *pif = get_pid_file_name (sctx);
1348
1349 if (NULL == pif)
1350 return; /* no PID file */
1351 if (0 != UNLINK (pif))
1352 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", pif);
1353 GNUNET_free (pif);
1354}
1355
1356
1357/**
1358 * Run a standard GNUnet service startup sequence (initialize loggers
1359 * and configuration, parse options).
1360 *
1361 * @param argc number of command line arguments
1362 * @param argv command line arguments
1363 * @param service_name our service name
1364 * @param options service options
1365 * @param task main task of the service
1366 * @param task_cls closure for @a task
1367 * @return #GNUNET_SYSERR on error, #GNUNET_OK
1368 * if we shutdown nicely
1369 */
1370int
1371LEGACY_SERVICE_run (int argc, char *const *argv,
1372 const char *service_name,
1373 enum LEGACY_SERVICE_Options options,
1374 LEGACY_SERVICE_Main task,
1375 void *task_cls)
1376{
1377#define HANDLE_ERROR do { GNUNET_break (0); goto shutdown; } while (0)
1378
1379 int err;
1380 int ret;
1381 char *cfg_fn;
1382 char *opt_cfg_fn;
1383 char *loglev;
1384 char *logfile;
1385 int do_daemonize;
1386 unsigned int i;
1387 unsigned long long skew_offset;
1388 unsigned long long skew_variance;
1389 long long clock_offset;
1390 struct LEGACY_SERVICE_Context sctx;
1391 struct GNUNET_CONFIGURATION_Handle *cfg;
1392 const char *xdg;
1393
1394 struct GNUNET_GETOPT_CommandLineOption service_options[] = {
1395 GNUNET_GETOPT_OPTION_CFG_FILE (&opt_cfg_fn),
1396 GNUNET_GETOPT_OPTION_SET_ONE ('d',
1397 "daemonize",
1398 gettext_noop ("do daemonize (detach from terminal)"),
1399 &do_daemonize),
1400 GNUNET_GETOPT_OPTION_HELP (NULL),
1401 GNUNET_GETOPT_OPTION_LOGLEVEL (&loglev),
1402 GNUNET_GETOPT_OPTION_LOGFILE (&logfile),
1403 GNUNET_GETOPT_OPTION_VERSION (PACKAGE_VERSION " " VCS_VERSION),
1404 GNUNET_GETOPT_OPTION_END
1405 };
1406 err = 1;
1407 do_daemonize = 0;
1408 logfile = NULL;
1409 loglev = NULL;
1410 opt_cfg_fn = NULL;
1411 xdg = getenv ("XDG_CONFIG_HOME");
1412 if (NULL != xdg)
1413 GNUNET_asprintf (&cfg_fn,
1414 "%s%s%s",
1415 xdg,
1416 DIR_SEPARATOR_STR,
1417 GNUNET_OS_project_data_get ()->config_file);
1418 else
1419 cfg_fn = GNUNET_strdup (GNUNET_OS_project_data_get ()->user_config_file);
1420 memset (&sctx, 0, sizeof (sctx));
1421 sctx.options = options;
1422 sctx.ready_confirm_fd = -1;
1423 sctx.ret = GNUNET_OK;
1424 sctx.timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1425 sctx.task = task;
1426 sctx.task_cls = task_cls;
1427 sctx.service_name = service_name;
1428 sctx.cfg = cfg = GNUNET_CONFIGURATION_create ();
1429
1430 /* setup subsystems */
1431 ret = GNUNET_GETOPT_run (service_name, service_options, argc, argv);
1432 if (GNUNET_SYSERR == ret)
1433 goto shutdown;
1434 if (GNUNET_NO == ret)
1435 {
1436 err = 0;
1437 goto shutdown;
1438 }
1439 if (GNUNET_OK != GNUNET_log_setup (service_name, loglev, logfile))
1440 HANDLE_ERROR;
1441 if (NULL == opt_cfg_fn)
1442 opt_cfg_fn = GNUNET_strdup (cfg_fn);
1443 if (GNUNET_YES == GNUNET_DISK_file_test (opt_cfg_fn))
1444 {
1445 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, opt_cfg_fn))
1446 {
1447 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1448 _("Malformed configuration file `%s', exit ...\n"),
1449 opt_cfg_fn);
1450 goto shutdown;
1451 }
1452 }
1453 else
1454 {
1455 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, NULL))
1456 {
1457 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1458 _("Malformed configuration, exit ...\n"));
1459 goto shutdown;
1460 }
1461 if (0 != strcmp (opt_cfg_fn, cfg_fn))
1462 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1463 _("Could not access configuration file `%s'\n"),
1464 opt_cfg_fn);
1465 }
1466 if (GNUNET_OK != setup_service (&sctx))
1467 goto shutdown;
1468 if ((1 == do_daemonize) && (GNUNET_OK != detach_terminal (&sctx)))
1469 HANDLE_ERROR;
1470 if (GNUNET_OK != set_user_id (&sctx))
1471 goto shutdown;
1472 LOG (GNUNET_ERROR_TYPE_DEBUG,
1473 "Service `%s' runs with configuration from `%s'\n",
1474 service_name,
1475 opt_cfg_fn);
1476 if ((GNUNET_OK ==
1477 GNUNET_CONFIGURATION_get_value_number (sctx.cfg, "TESTING",
1478 "SKEW_OFFSET", &skew_offset)) &&
1479 (GNUNET_OK ==
1480 GNUNET_CONFIGURATION_get_value_number (sctx.cfg, "TESTING",
1481 "SKEW_VARIANCE", &skew_variance)))
1482 {
1483 clock_offset = skew_offset - skew_variance;
1484 GNUNET_TIME_set_offset (clock_offset);
1485 LOG (GNUNET_ERROR_TYPE_DEBUG, "Skewing clock by %dll ms\n", clock_offset);
1486 }
1487 /* actually run service */
1488 err = 0;
1489 GNUNET_SCHEDULER_run (&service_task, &sctx);
1490 /* shutdown */
1491 if ((1 == do_daemonize) && (NULL != sctx.server))
1492 pid_file_delete (&sctx);
1493 GNUNET_free_non_null (sctx.my_handlers);
1494
1495shutdown:
1496 if (-1 != sctx.ready_confirm_fd)
1497 {
1498 if (1 != WRITE (sctx.ready_confirm_fd, err ? "I" : "S", 1))
1499 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "write");
1500 GNUNET_break (0 == CLOSE (sctx.ready_confirm_fd));
1501 }
1502#if HAVE_MALLINFO
1503 {
1504 char *counter;
1505
1506 if ( (GNUNET_YES ==
1507 GNUNET_CONFIGURATION_have_value (sctx.cfg, service_name,
1508 "GAUGER_HEAP")) &&
1509 (GNUNET_OK ==
1510 GNUNET_CONFIGURATION_get_value_string (sctx.cfg, service_name,
1511 "GAUGER_HEAP",
1512 &counter)) )
1513 {
1514 struct mallinfo mi;
1515
1516 mi = mallinfo ();
1517 GAUGER (service_name, counter, mi.usmblks, "blocks");
1518 GNUNET_free (counter);
1519 }
1520 }
1521#endif
1522 GNUNET_CONFIGURATION_destroy (cfg);
1523 i = 0;
1524 if (NULL != sctx.addrs)
1525 while (NULL != sctx.addrs[i])
1526 GNUNET_free (sctx.addrs[i++]);
1527 GNUNET_free_non_null (sctx.addrs);
1528 GNUNET_free_non_null (sctx.addrlens);
1529 GNUNET_free_non_null (logfile);
1530 GNUNET_free_non_null (loglev);
1531 GNUNET_free (cfg_fn);
1532 GNUNET_free_non_null (opt_cfg_fn);
1533 GNUNET_free_non_null (sctx.v4_denied);
1534 GNUNET_free_non_null (sctx.v6_denied);
1535 GNUNET_free_non_null (sctx.v4_allowed);
1536 GNUNET_free_non_null (sctx.v6_allowed);
1537
1538 return err ? GNUNET_SYSERR : sctx.ret;
1539}
1540
1541
1542/**
1543 * Run a service startup sequence within an existing
1544 * initialized system.
1545 *
1546 * @param service_name our service name
1547 * @param cfg configuration to use
1548 * @param options service options
1549 * @return NULL on error, service handle
1550 */
1551struct LEGACY_SERVICE_Context *
1552LEGACY_SERVICE_start (const char *service_name,
1553 const struct GNUNET_CONFIGURATION_Handle *cfg,
1554 enum LEGACY_SERVICE_Options options)
1555{
1556 int i;
1557 struct LEGACY_SERVICE_Context *sctx;
1558
1559 sctx = GNUNET_new (struct LEGACY_SERVICE_Context);
1560 sctx->ready_confirm_fd = -1; /* no daemonizing */
1561 sctx->ret = GNUNET_OK;
1562 sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1563 sctx->service_name = service_name;
1564 sctx->cfg = cfg;
1565 sctx->options = options;
1566
1567 /* setup subsystems */
1568 if (GNUNET_OK != setup_service (sctx))
1569 {
1570 LEGACY_SERVICE_stop (sctx);
1571 return NULL;
1572 }
1573 if (NULL != sctx->lsocks)
1574 sctx->server =
1575 GNUNET_SERVER_create_with_sockets (&check_access, sctx, sctx->lsocks,
1576 sctx->timeout, sctx->require_found);
1577 else
1578 sctx->server =
1579 GNUNET_SERVER_create (&check_access, sctx, sctx->addrs, sctx->addrlens,
1580 sctx->timeout, sctx->require_found);
1581
1582 if (NULL == sctx->server)
1583 {
1584 LEGACY_SERVICE_stop (sctx);
1585 return NULL;
1586 }
1587#ifndef WINDOWS
1588 if (NULL != sctx->addrs)
1589 for (i = 0; NULL != sctx->addrs[i]; i++)
1590 if ((AF_UNIX == sctx->addrs[i]->sa_family)
1591 && ('\0' != ((const struct sockaddr_un *)sctx->addrs[i])->sun_path[0]))
1592 GNUNET_DISK_fix_permissions (((const struct sockaddr_un *)sctx->addrs[i])->sun_path,
1593 sctx->match_uid,
1594 sctx->match_gid);
1595#endif
1596 sctx->my_handlers = GNUNET_malloc (sizeof (defhandlers));
1597 GNUNET_memcpy (sctx->my_handlers, defhandlers, sizeof (defhandlers));
1598 i = 0;
1599 while ((sctx->my_handlers[i].callback != NULL))
1600 sctx->my_handlers[i++].callback_cls = sctx;
1601 GNUNET_SERVER_add_handlers (sctx->server, sctx->my_handlers);
1602 return sctx;
1603}
1604
1605
1606/**
1607 * Obtain the server used by a service. Note that the server must NOT
1608 * be destroyed by the caller.
1609 *
1610 * @param ctx the service context returned from the start function
1611 * @return handle to the server for this service, NULL if there is none
1612 */
1613struct GNUNET_SERVER_Handle *
1614LEGACY_SERVICE_get_server (struct LEGACY_SERVICE_Context *ctx)
1615{
1616 return ctx->server;
1617}
1618
1619
1620/**
1621 * Get the NULL-terminated array of listen sockets for this service.
1622 *
1623 * @param ctx service context to query
1624 * @return NULL if there are no listen sockets, otherwise NULL-terminated
1625 * array of listen sockets.
1626 */
1627struct GNUNET_NETWORK_Handle *const*
1628LEGACY_SERVICE_get_listen_sockets (struct LEGACY_SERVICE_Context *ctx)
1629{
1630 return ctx->lsocks;
1631}
1632
1633
1634/**
1635 * Stop a service that was started with "LEGACY_SERVICE_start".
1636 *
1637 * @param sctx the service context returned from the start function
1638 */
1639void
1640LEGACY_SERVICE_stop (struct LEGACY_SERVICE_Context *sctx)
1641{
1642 unsigned int i;
1643
1644#if HAVE_MALLINFO
1645 {
1646 char *counter;
1647
1648 if ( (GNUNET_YES ==
1649 GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name,
1650 "GAUGER_HEAP")) &&
1651 (GNUNET_OK ==
1652 GNUNET_CONFIGURATION_get_value_string (sctx->cfg, sctx->service_name,
1653 "GAUGER_HEAP",
1654 &counter)) )
1655 {
1656 struct mallinfo mi;
1657
1658 mi = mallinfo ();
1659 GAUGER (sctx->service_name, counter, mi.usmblks, "blocks");
1660 GNUNET_free (counter);
1661 }
1662 }
1663#endif
1664 if (NULL != sctx->shutdown_task)
1665 {
1666 GNUNET_SCHEDULER_cancel (sctx->shutdown_task);
1667 sctx->shutdown_task = NULL;
1668 }
1669 if (NULL != sctx->server)
1670 GNUNET_SERVER_destroy (sctx->server);
1671 GNUNET_free_non_null (sctx->my_handlers);
1672 if (NULL != sctx->addrs)
1673 {
1674 i = 0;
1675 while (NULL != sctx->addrs[i])
1676 GNUNET_free (sctx->addrs[i++]);
1677 GNUNET_free (sctx->addrs);
1678 }
1679 GNUNET_free_non_null (sctx->addrlens);
1680 GNUNET_free_non_null (sctx->v4_denied);
1681 GNUNET_free_non_null (sctx->v6_denied);
1682 GNUNET_free_non_null (sctx->v4_allowed);
1683 GNUNET_free_non_null (sctx->v6_allowed);
1684 GNUNET_free (sctx);
1685}
1686
1687
1688/* end of service.c */
diff --git a/src/transport/test_plugin_transport.c b/src/transport/test_plugin_transport.c
index be79d5499..1d92588ea 100644
--- a/src/transport/test_plugin_transport.c
+++ b/src/transport/test_plugin_transport.c
@@ -552,7 +552,7 @@ setup_plugin_environment ()
552 552
553 553
554static int 554static int
555handle_helper_message (void *cls, void *client, 555handle_helper_message (void *cls,
556 const struct GNUNET_MessageHeader *hdr) 556 const struct GNUNET_MessageHeader *hdr)
557{ 557{
558 return GNUNET_OK; 558 return GNUNET_OK;
diff --git a/src/transport/test_transport_api_reliability.c b/src/transport/test_transport_api_reliability.c
index 375a935c8..e5ba2831b 100644
--- a/src/transport/test_transport_api_reliability.c
+++ b/src/transport/test_transport_api_reliability.c
@@ -217,7 +217,7 @@ notify_receive (void *cls,
217{ 217{
218 static int n; 218 static int n;
219 unsigned int s; 219 unsigned int s;
220 char cbuf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1]; 220 char cbuf[GNUNET_MAX_MESSAGE_SIZE - 1];
221 221
222 if (GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE != ntohs (hdr->header.type)) 222 if (GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE != ntohs (hdr->header.type))
223 return; 223 return;
diff --git a/src/transport/transport-testing-loggers.c b/src/transport/transport-testing-loggers.c
index de9fa91c1..0ebb07d74 100644
--- a/src/transport/transport-testing-loggers.c
+++ b/src/transport/transport-testing-loggers.c
@@ -71,6 +71,7 @@ GNUNET_TRANSPORT_TESTING_log_disconnect (void *cls,
71 GNUNET_i2s (other), 71 GNUNET_i2s (other),
72 me->no, 72 me->no,
73 ps); 73 ps);
74 GNUNET_free (ps);
74} 75}
75 76
76/* end of transport-testing-loggers.c */ 77/* end of transport-testing-loggers.c */
diff --git a/src/transport/transport-testing-main.c b/src/transport/transport-testing-main.c
index a79d81cb9..81a66e113 100644
--- a/src/transport/transport-testing-main.c
+++ b/src/transport/transport-testing-main.c
@@ -146,7 +146,7 @@ struct GNUNET_TRANSPORT_TESTING_InternalPeerContext
146 146
147/** 147/**
148 * Information tracked per connected peer. 148 * Information tracked per connected peer.
149 */ 149 */
150struct ConnectPairInfo 150struct ConnectPairInfo
151{ 151{
152 /** 152 /**
@@ -235,7 +235,7 @@ my_nc (void *cls,
235 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi = cls; 235 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi = cls;
236 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = ipi->ccc; 236 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = ipi->ccc;
237 struct ConnectPairInfo *cpi; 237 struct ConnectPairInfo *cpi;
238 238
239 if (NULL != ccc->nc) 239 if (NULL != ccc->nc)
240 ccc->nc (ccc->cls, 240 ccc->nc (ccc->cls,
241 ccc->p[ipi->off], 241 ccc->p[ipi->off],
@@ -262,7 +262,7 @@ my_nd (void *cls,
262 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi = cls; 262 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi = cls;
263 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = ipi->ccc; 263 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = ipi->ccc;
264 struct ConnectPairInfo *cpi = custom_cls; 264 struct ConnectPairInfo *cpi = custom_cls;
265 265
266 if (NULL != ccc->nd) 266 if (NULL != ccc->nd)
267 ccc->nd (ccc->cls, 267 ccc->nd (ccc->cls,
268 ccc->p[ipi->off], 268 ccc->p[ipi->off],
@@ -535,13 +535,15 @@ GNUNET_TRANSPORT_TESTING_connect_check (void *cls,
535 ip[i].off = i; 535 ip[i].off = i;
536 ip[i].ccc = ccc; 536 ip[i].ccc = ccc;
537 } 537 }
538 GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, 538 if (GNUNET_OK !=
539 argv, 539 GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
540 test_name_, 540 argv,
541 "nohelp", 541 test_name_,
542 options, 542 "nohelp",
543 &connect_check_run, 543 options,
544 ccc); 544 &connect_check_run,
545 ccc))
546 return GNUNET_SYSERR;
545 return ccc->global_ret; 547 return ccc->global_ret;
546} 548}
547 549
diff --git a/src/transport/transport-testing.c b/src/transport/transport-testing.c
index c0775a135..53a44f338 100644
--- a/src/transport/transport-testing.c
+++ b/src/transport/transport-testing.c
@@ -49,7 +49,7 @@ find_peer_context (struct GNUNET_TRANSPORT_TESTING_Handle *tth,
49 * 49 *
50 * @param p1 first peer 50 * @param p1 first peer
51 * @param p2 second peer 51 * @param p2 second peer
52 * @param cb function to call 52 * @param cb function to call
53 * @param cb_cls closure for @a cb 53 * @param cb_cls closure for @a cb
54 */ 54 */
55void 55void
@@ -66,7 +66,7 @@ GNUNET_TRANSPORT_TESTING_find_connecting_context (struct GNUNET_TRANSPORT_TESTIN
66 { 66 {
67 ccn = cc->next; 67 ccn = cc->next;
68 if ( (cc->p1 == p1) && 68 if ( (cc->p1 == p1) &&
69 (cc->p2 == p2) ) 69 (cc->p2 == p2) )
70 cb (cb_cls, 70 cb (cb_cls,
71 cc); 71 cc);
72 } 72 }
@@ -74,7 +74,7 @@ GNUNET_TRANSPORT_TESTING_find_connecting_context (struct GNUNET_TRANSPORT_TESTIN
74 74
75 75
76static void 76static void
77set_p1c (void *cls, 77set_p1c (void *cls,
78 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx) 78 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
79{ 79{
80 int *found = cls; 80 int *found = cls;
@@ -86,7 +86,7 @@ set_p1c (void *cls,
86 86
87 87
88static void 88static void
89set_mq (void *cls, 89set_mq (void *cls,
90 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx) 90 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
91{ 91{
92 struct GNUNET_MQ_Handle *mq = cls; 92 struct GNUNET_MQ_Handle *mq = cls;
@@ -96,7 +96,7 @@ set_mq (void *cls,
96 96
97 97
98static void 98static void
99set_p2c (void *cls, 99set_p2c (void *cls,
100 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx) 100 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
101{ 101{
102 int *found = cls; 102 int *found = cls;
@@ -108,7 +108,7 @@ set_p2c (void *cls,
108 108
109 109
110static void 110static void
111clear_p1c (void *cls, 111clear_p1c (void *cls,
112 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx) 112 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
113{ 113{
114 int *found = cls; 114 int *found = cls;
@@ -120,7 +120,7 @@ clear_p1c (void *cls,
120 120
121 121
122static void 122static void
123clear_p2c (void *cls, 123clear_p2c (void *cls,
124 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx) 124 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
125{ 125{
126 int *found = cls; 126 int *found = cls;
@@ -154,7 +154,7 @@ notify_connect (void *cls,
154 else 154 else
155 ret = NULL; 155 ret = NULL;
156 156
157 if (p2 != NULL) 157 if (NULL != p2)
158 GNUNET_asprintf (&p2_s, 158 GNUNET_asprintf (&p2_s,
159 "%u (`%s')", 159 "%u (`%s')",
160 p2->no, 160 p2->no,
@@ -267,7 +267,7 @@ notify_disconnect (void *cls,
267 int no = 0; 267 int no = 0;
268 struct GNUNET_TRANSPORT_TESTING_PeerContext *p2 = NULL; 268 struct GNUNET_TRANSPORT_TESTING_PeerContext *p2 = NULL;
269 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc; 269 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
270 270
271 p2 = find_peer_context (p->tth, 271 p2 = find_peer_context (p->tth,
272 peer); 272 peer);
273 no = p->no; 273 no = p->no;
@@ -386,7 +386,7 @@ GNUNET_TRANSPORT_TESTING_start_peer (struct GNUNET_TRANSPORT_TESTING_Handle *tth
386 struct GNUNET_TRANSPORT_TESTING_PeerContext *p; 386 struct GNUNET_TRANSPORT_TESTING_PeerContext *p;
387 struct GNUNET_PeerIdentity *dummy; 387 struct GNUNET_PeerIdentity *dummy;
388 unsigned int i; 388 unsigned int i;
389 389
390 if (GNUNET_NO == GNUNET_DISK_file_test (cfgname)) 390 if (GNUNET_NO == GNUNET_DISK_file_test (cfgname))
391 { 391 {
392 LOG (GNUNET_ERROR_TYPE_ERROR, 392 LOG (GNUNET_ERROR_TYPE_ERROR,
@@ -407,7 +407,7 @@ GNUNET_TRANSPORT_TESTING_start_peer (struct GNUNET_TRANSPORT_TESTING_Handle *tth
407 GNUNET_memcpy (p->handlers, 407 GNUNET_memcpy (p->handlers,
408 handlers, 408 handlers,
409 i * sizeof (struct GNUNET_MQ_MessageHandler)); 409 i * sizeof (struct GNUNET_MQ_MessageHandler));
410 } 410 }
411 if (NULL != cb_cls) 411 if (NULL != cb_cls)
412 p->cb_cls = cb_cls; 412 p->cb_cls = cb_cls;
413 else 413 else
@@ -532,7 +532,7 @@ GNUNET_TRANSPORT_TESTING_restart_peer (struct GNUNET_TRANSPORT_TESTING_PeerConte
532{ 532{
533 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc; 533 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
534 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ccn; 534 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ccn;
535 535
536 /* shutdown */ 536 /* shutdown */
537 LOG (GNUNET_ERROR_TYPE_DEBUG, 537 LOG (GNUNET_ERROR_TYPE_DEBUG,
538 "Stopping peer %u (`%s')\n", 538 "Stopping peer %u (`%s')\n",
@@ -770,7 +770,7 @@ GNUNET_TRANSPORT_TESTING_connect_peers (struct GNUNET_TRANSPORT_TESTING_PeerCont
770 break; 770 break;
771 } 771 }
772 } 772 }
773 773
774 cc = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_ConnectRequest); 774 cc = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_ConnectRequest);
775 cc->p1 = p1; 775 cc->p1 = p1;
776 cc->p2 = p2; 776 cc->p2 = p2;
diff --git a/src/transport/transport_api_address_to_string.c b/src/transport/transport_api_address_to_string.c
index b9c72dcb3..902764a8f 100644
--- a/src/transport/transport_api_address_to_string.c
+++ b/src/transport/transport_api_address_to_string.c
@@ -199,10 +199,10 @@ GNUNET_TRANSPORT_address_to_string (const struct GNUNET_CONFIGURATION_Handle *cf
199 199
200 alen = address->address_length; 200 alen = address->address_length;
201 slen = strlen (address->transport_name) + 1; 201 slen = strlen (address->transport_name) + 1;
202 if ( (alen + slen >= GNUNET_SERVER_MAX_MESSAGE_SIZE 202 if ( (alen + slen >= GNUNET_MAX_MESSAGE_SIZE
203 - sizeof (struct AddressLookupMessage)) || 203 - sizeof (struct AddressLookupMessage)) ||
204 (alen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) || 204 (alen >= GNUNET_MAX_MESSAGE_SIZE) ||
205 (slen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ) 205 (slen >= GNUNET_MAX_MESSAGE_SIZE) )
206 { 206 {
207 GNUNET_break (0); 207 GNUNET_break (0);
208 GNUNET_free (alc); 208 GNUNET_free (alc);
diff --git a/src/transport/transport_api_core.c b/src/transport/transport_api_core.c
index c99ade92f..9c29d4908 100644
--- a/src/transport/transport_api_core.c
+++ b/src/transport/transport_api_core.c
@@ -425,7 +425,7 @@ mq_send_impl (struct GNUNET_MQ_Handle *mq,
425 425
426 GNUNET_assert (GNUNET_YES == n->is_ready); 426 GNUNET_assert (GNUNET_YES == n->is_ready);
427 msize = ntohs (msg->size); 427 msize = ntohs (msg->size);
428 if (msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (*obm)) 428 if (msize >= GNUNET_MAX_MESSAGE_SIZE - sizeof (*obm))
429 { 429 {
430 GNUNET_break (0); 430 GNUNET_break (0);
431 GNUNET_MQ_impl_send_continue (mq); 431 GNUNET_MQ_impl_send_continue (mq);
diff --git a/src/util/Makefile.am b/src/util/Makefile.am
index df319fe77..9be572bb6 100644
--- a/src/util/Makefile.am
+++ b/src/util/Makefile.am
@@ -30,10 +30,9 @@ W32CONSOLEHELPER = gnunet-helper-w32-console
30endif 30endif
31 31
32if !MINGW 32if !MINGW
33 SERVER_CLIENT_UNIX = test_server_with_client_unix 33 TEST_CLIENT_UNIX_NC = test_client_unix.nc
34 TEST_CLIENT_UNIC_NC = test_client_unix.nc
35else 34else
36 TEST_CLIENT_UNIC_NC = 35 TEST_CLIENT_UNIX_NC =
37endif 36endif
38 37
39if USE_COVERAGE 38if USE_COVERAGE
@@ -68,7 +67,6 @@ libgnunetutil_la_SOURCES = \
68 common_logging.c \ 67 common_logging.c \
69 configuration.c \ 68 configuration.c \
70 configuration_loader.c \ 69 configuration_loader.c \
71 connection.c \
72 container_bloomfilter.c \ 70 container_bloomfilter.c \
73 container_heap.c \ 71 container_heap.c \
74 container_meta_data.c \ 72 container_meta_data.c \
@@ -108,16 +106,10 @@ libgnunetutil_la_SOURCES = \
108 program.c \ 106 program.c \
109 resolver_api.c resolver.h \ 107 resolver_api.c resolver.h \
110 scheduler.c \ 108 scheduler.c \
111 server.c \
112 server_mst.c \
113 server_nc.c \
114 server_tc.c \
115 service.c \ 109 service.c \
116 service_new.c \
117 signal.c \ 110 signal.c \
118 strings.c \ 111 strings.c \
119 time.c \ 112 time.c \
120 socks.c \
121 speedup.c speedup.h 113 speedup.c speedup.h
122 114
123libgnunetutil_la_LIBADD = \ 115libgnunetutil_la_LIBADD = \
@@ -263,14 +255,13 @@ if HAVE_BENCHMARKS
263endif 255endif
264 256
265if HAVE_SSH_KEY 257if HAVE_SSH_KEY
266 SSH_USING_TESTS = test_socks.nc 258# SSH_USING_TESTS = test_socks.nc
267endif 259endif
268 260
269check_PROGRAMS = \ 261check_PROGRAMS = \
270 test_bio \ 262 test_bio \
271 test_client.nc \ 263 test_client.nc \
272 $(TEST_CLIENT_UNIX_NC) \ 264 $(TEST_CLIENT_UNIX_NC) \
273 $(SSH_USING_TESTS) \
274 test_common_allocation \ 265 test_common_allocation \
275 test_common_endian \ 266 test_common_endian \
276 test_common_logging \ 267 test_common_logging \
@@ -298,12 +289,6 @@ check_PROGRAMS = \
298 test_crypto_rsa \ 289 test_crypto_rsa \
299 test_disk \ 290 test_disk \
300 test_getopt \ 291 test_getopt \
301 test_connection.nc \
302 test_connection_addressing.nc \
303 test_connection_receive_cancel.nc \
304 test_connection_timeout.nc \
305 test_connection_timeout_no_connect.nc \
306 test_connection_transmit_cancel.nc \
307 test_mq \ 292 test_mq \
308 test_os_network \ 293 test_os_network \
309 test_peer \ 294 test_peer \
@@ -312,11 +297,6 @@ check_PROGRAMS = \
312 test_resolver_api.nc \ 297 test_resolver_api.nc \
313 test_scheduler \ 298 test_scheduler \
314 test_scheduler_delay \ 299 test_scheduler_delay \
315 test_server.nc \
316 test_server_disconnect.nc \
317 test_server_with_client.nc \
318 test_server_mst_interrupt.nc \
319 $(SERVER_CLIENT_UNIX) \
320 test_service \ 300 test_service \
321 test_strings \ 301 test_strings \
322 test_strings_to_data \ 302 test_strings_to_data \
@@ -330,18 +310,7 @@ check_PROGRAMS = \
330# Declare .nc (NO-CONCURRENCY) as a test extension so that we can impart 310# Declare .nc (NO-CONCURRENCY) as a test extension so that we can impart
331# sequential execution order for them 311# sequential execution order for them
332TEST_EXTENSIONS = .nc 312TEST_EXTENSIONS = .nc
333test_connection.log: test_client.log 313test_test_client_unix.log: test_client.log
334test_connection_addressing.log: test_connection.log
335test_connection_timeout_no_connect.log: test_connection_addressing.log
336test_connection_transmit_cancel.log: test_connection_timeout_no_connect.log
337test_connection_receive_cancel.log: test_connection_transmit_cancel.log
338test_connection_timeout.log: test_connection_receive_cancel.log
339test_resolver_api.log: test_connection_timeout.log
340test_server.log: test_resolver_api.log
341test_server_disconnect.log: test_server.log
342test_server_with_client.log: test_server_disconnect.log
343test_server_mst_interrupt.log: test_server_with_client.log
344test_client_unix.log: test_server_mst_interrupt.log
345 314
346test_bio_SOURCES = \ 315test_bio_SOURCES = \
347 test_bio.c 316 test_bio.c
@@ -518,36 +487,6 @@ test_getopt_SOURCES = \
518test_getopt_LDADD = \ 487test_getopt_LDADD = \
519 libgnunetutil.la 488 libgnunetutil.la
520 489
521test_connection_nc_SOURCES = \
522 test_connection.c
523test_connection_nc_LDADD = \
524 libgnunetutil.la
525
526test_connection_addressing_nc_SOURCES = \
527 test_connection_addressing.c
528test_connection_addressing_nc_LDADD = \
529 libgnunetutil.la
530
531test_connection_receive_cancel_nc_SOURCES = \
532 test_connection_receive_cancel.c
533test_connection_receive_cancel_nc_LDADD = \
534 libgnunetutil.la
535
536test_connection_timeout_nc_SOURCES = \
537 test_connection_timeout.c
538test_connection_timeout_nc_LDADD = \
539 libgnunetutil.la
540
541test_connection_timeout_no_connect_nc_SOURCES = \
542 test_connection_timeout_no_connect.c
543test_connection_timeout_no_connect_nc_LDADD = \
544 libgnunetutil.la
545
546test_connection_transmit_cancel_nc_SOURCES = \
547 test_connection_transmit_cancel.c
548test_connection_transmit_cancel_nc_LDADD = \
549 libgnunetutil.la
550
551test_mq_SOURCES = \ 490test_mq_SOURCES = \
552 test_mq.c 491 test_mq.c
553test_mq_LDADD = \ 492test_mq_LDADD = \
@@ -588,32 +527,6 @@ test_scheduler_delay_SOURCES = \
588test_scheduler_delay_LDADD = \ 527test_scheduler_delay_LDADD = \
589 libgnunetutil.la 528 libgnunetutil.la
590 529
591test_server_mst_interrupt_nc_SOURCES = \
592 test_server_mst_interrupt.c
593test_server_mst_interrupt_nc_LDADD = \
594 libgnunetutil.la
595
596test_server_nc_SOURCES = \
597 test_server.c
598test_server_nc_LDADD = \
599 libgnunetutil.la
600
601test_server_disconnect_nc_SOURCES = \
602 test_server_disconnect.c
603test_server_disconnect_nc_LDADD = \
604 libgnunetutil.la
605
606test_server_with_client_nc_SOURCES = \
607 test_server_with_client.c
608test_server_with_client_nc_LDADD = \
609 libgnunetutil.la
610
611test_server_with_client_unix_SOURCES = \
612 test_server_with_client_unix.c
613test_server_with_client_unix_LDADD = \
614 libgnunetutil.la
615
616
617test_service_SOURCES = \ 530test_service_SOURCES = \
618 test_service.c 531 test_service.c
619test_service_LDADD = \ 532test_service_LDADD = \
@@ -624,7 +537,6 @@ test_strings_SOURCES = \
624test_strings_LDADD = \ 537test_strings_LDADD = \
625 libgnunetutil.la 538 libgnunetutil.la
626 539
627
628test_strings_to_data_SOURCES = \ 540test_strings_to_data_SOURCES = \
629 test_strings_to_data.c 541 test_strings_to_data.c
630test_strings_to_data_LDADD = \ 542test_strings_to_data_LDADD = \
diff --git a/src/util/bandwidth.c b/src/util/bandwidth.c
index a059fc738..bc0c3b9b4 100644
--- a/src/util/bandwidth.c
+++ b/src/util/bandwidth.c
@@ -184,8 +184,8 @@ update_excess (struct GNUNET_BANDWIDTH_Tracker *av)
184 } 184 }
185 /* negative current_consumption means that we have savings */ 185 /* negative current_consumption means that we have savings */
186 max_carry = ((uint64_t) av->available_bytes_per_s__) * av->max_carry_s__; 186 max_carry = ((uint64_t) av->available_bytes_per_s__) * av->max_carry_s__;
187 if (max_carry < GNUNET_SERVER_MAX_MESSAGE_SIZE) 187 if (max_carry < GNUNET_MAX_MESSAGE_SIZE)
188 max_carry = GNUNET_SERVER_MAX_MESSAGE_SIZE; 188 max_carry = GNUNET_MAX_MESSAGE_SIZE;
189 if (max_carry > INT64_MAX) 189 if (max_carry > INT64_MAX)
190 max_carry = INT64_MAX; 190 max_carry = INT64_MAX;
191 left_bytes = current_consumption + max_carry; 191 left_bytes = current_consumption + max_carry;
@@ -224,10 +224,10 @@ update_excess (struct GNUNET_BANDWIDTH_Tracker *av)
224/** 224/**
225 * Initialize bandwidth tracker. Note that in addition to the 225 * Initialize bandwidth tracker. Note that in addition to the
226 * 'max_carry_s' limit, we also always allow at least 226 * 'max_carry_s' limit, we also always allow at least
227 * #GNUNET_SERVER_MAX_MESSAGE_SIZE to accumulate. So if the 227 * #GNUNET_MAX_MESSAGE_SIZE to accumulate. So if the
228 * bytes-per-second limit is so small that within 'max_carry_s' not 228 * bytes-per-second limit is so small that within 'max_carry_s' not
229 * even #GNUNET_SERVER_MAX_MESSAGE_SIZE is allowed to accumulate, it is 229 * even #GNUNET_MAX_MESSAGE_SIZE is allowed to accumulate, it is
230 * ignored and replaced by #GNUNET_SERVER_MAX_MESSAGE_SIZE (which is in 230 * ignored and replaced by #GNUNET_MAX_MESSAGE_SIZE (which is in
231 * bytes). 231 * bytes).
232 * 232 *
233 * To stop notifications about updates and excess callbacks use 233 * To stop notifications about updates and excess callbacks use
@@ -271,10 +271,10 @@ GNUNET_BANDWIDTH_tracker_init2 (struct GNUNET_BANDWIDTH_Tracker *av,
271/** 271/**
272 * Initialize bandwidth tracker. Note that in addition to the 272 * Initialize bandwidth tracker. Note that in addition to the
273 * 'max_carry_s' limit, we also always allow at least 273 * 'max_carry_s' limit, we also always allow at least
274 * #GNUNET_SERVER_MAX_MESSAGE_SIZE to accumulate. So if the 274 * #GNUNET_MAX_MESSAGE_SIZE to accumulate. So if the
275 * bytes-per-second limit is so small that within 'max_carry_s' not 275 * bytes-per-second limit is so small that within 'max_carry_s' not
276 * even #GNUNET_SERVER_MAX_MESSAGE_SIZE is allowed to accumulate, it is 276 * even #GNUNET_MAX_MESSAGE_SIZE is allowed to accumulate, it is
277 * ignored and replaced by #GNUNET_SERVER_MAX_MESSAGE_SIZE (which is in 277 * ignored and replaced by #GNUNET_MAX_MESSAGE_SIZE (which is in
278 * bytes). 278 * bytes).
279 * 279 *
280 * @param av tracker to initialize 280 * @param av tracker to initialize
@@ -345,8 +345,8 @@ update_tracker (struct GNUNET_BANDWIDTH_Tracker *av)
345 left_bytes = - av->consumption_since_last_update__; 345 left_bytes = - av->consumption_since_last_update__;
346 max_carry = ((unsigned long long) av->available_bytes_per_s__) * 346 max_carry = ((unsigned long long) av->available_bytes_per_s__) *
347 av->max_carry_s__; 347 av->max_carry_s__;
348 if (max_carry < GNUNET_SERVER_MAX_MESSAGE_SIZE) 348 if (max_carry < GNUNET_MAX_MESSAGE_SIZE)
349 max_carry = GNUNET_SERVER_MAX_MESSAGE_SIZE; 349 max_carry = GNUNET_MAX_MESSAGE_SIZE;
350 if (max_carry > INT64_MAX) 350 if (max_carry > INT64_MAX)
351 max_carry = INT64_MAX; 351 max_carry = INT64_MAX;
352 if (max_carry > left_bytes) 352 if (max_carry > left_bytes)
diff --git a/src/util/client.c b/src/util/client.c
index 0f7d0d359..3d74bff33 100644
--- a/src/util/client.c
+++ b/src/util/client.c
@@ -35,6 +35,15 @@
35 35
36#define LOG(kind,...) GNUNET_log_from (kind, "util-client",__VA_ARGS__) 36#define LOG(kind,...) GNUNET_log_from (kind, "util-client",__VA_ARGS__)
37 37
38/**
39 * Timeout we use on TCP connect before trying another
40 * result from the DNS resolver. Actual value used
41 * is this value divided by the number of address families.
42 * Default is 5s.
43 */
44#define CONNECT_RETRY_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
45
46
38 47
39/** 48/**
40 * Internal state for a client connected to a GNUnet service. 49 * Internal state for a client connected to a GNUnet service.
@@ -298,11 +307,11 @@ recv_message (void *cls,
298 307
299 if (GNUNET_YES == cstate->in_destroy) 308 if (GNUNET_YES == cstate->in_destroy)
300 return GNUNET_SYSERR; 309 return GNUNET_SYSERR;
301 310 LOG (GNUNET_ERROR_TYPE_DEBUG,
302 LOG (GNUNET_ERROR_TYPE_INFO,
303 "Received message of type %u and size %u from %s\n", 311 "Received message of type %u and size %u from %s\n",
304 ntohs (msg->type), ntohs (msg->size), cstate->service_name); 312 ntohs (msg->type),
305 313 ntohs (msg->size),
314 cstate->service_name);
306 GNUNET_MQ_inject_message (cstate->mq, 315 GNUNET_MQ_inject_message (cstate->mq,
307 msg); 316 msg);
308 if (GNUNET_YES == cstate->in_destroy) 317 if (GNUNET_YES == cstate->in_destroy)
@@ -656,7 +665,7 @@ try_connect_using_address (void *cls,
656 GNUNET_CONTAINER_DLL_insert (cstate->ap_head, 665 GNUNET_CONTAINER_DLL_insert (cstate->ap_head,
657 cstate->ap_tail, 666 cstate->ap_tail,
658 ap); 667 ap);
659 ap->task = GNUNET_SCHEDULER_add_write_net (GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT, 668 ap->task = GNUNET_SCHEDULER_add_write_net (CONNECT_RETRY_TIMEOUT,
660 ap->sock, 669 ap->sock,
661 &connect_probe_continuation, 670 &connect_probe_continuation,
662 ap); 671 ap);
@@ -760,7 +769,7 @@ start_connect (void *cls)
760 cstate->dns_active 769 cstate->dns_active
761 = GNUNET_RESOLVER_ip_get (cstate->hostname, 770 = GNUNET_RESOLVER_ip_get (cstate->hostname,
762 AF_UNSPEC, 771 AF_UNSPEC,
763 GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT, 772 CONNECT_RETRY_TIMEOUT,
764 &try_connect_using_address, 773 &try_connect_using_address,
765 cstate); 774 cstate);
766} 775}
diff --git a/src/util/disk.c b/src/util/disk.c
index d3d5d87dc..d536ec897 100644
--- a/src/util/disk.c
+++ b/src/util/disk.c
@@ -329,8 +329,10 @@ GNUNET_DISK_file_get_identifiers (const char *filename, uint64_t * dev,
329 BY_HANDLE_FILE_INFORMATION info; 329 BY_HANDLE_FILE_INFORMATION info;
330 int succ; 330 int succ;
331 331
332 fh = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ, 0); 332 fh = GNUNET_DISK_file_open (filename,
333 if (fh == NULL) 333 GNUNET_DISK_OPEN_READ,
334 GNUNET_DISK_PERM_NONE);
335 if (NULL == fh)
334 return GNUNET_SYSERR; 336 return GNUNET_SYSERR;
335 succ = GetFileInformationByHandle (fh->h, &info); 337 succ = GetFileInformationByHandle (fh->h, &info);
336 GNUNET_DISK_file_close (fh); 338 GNUNET_DISK_file_close (fh);
@@ -1191,7 +1193,7 @@ GNUNET_DISK_fn_write (const char *fn,
1191 fh = GNUNET_DISK_file_open (fn, 1193 fh = GNUNET_DISK_file_open (fn,
1192 GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_TRUNCATE 1194 GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_TRUNCATE
1193 | GNUNET_DISK_OPEN_CREATE, mode); 1195 | GNUNET_DISK_OPEN_CREATE, mode);
1194 if (!fh) 1196 if (! fh)
1195 return GNUNET_SYSERR; 1197 return GNUNET_SYSERR;
1196 ret = GNUNET_DISK_file_write (fh, buffer, n); 1198 ret = GNUNET_DISK_file_write (fh, buffer, n);
1197 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh)); 1199 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
@@ -1756,9 +1758,10 @@ GNUNET_DISK_file_open (const char *fn,
1756 1758
1757 1759
1758/** 1760/**
1759 * Close an open file 1761 * Close an open file.
1762 *
1760 * @param h file handle 1763 * @param h file handle
1761 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise 1764 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
1762 */ 1765 */
1763int 1766int
1764GNUNET_DISK_file_close (struct GNUNET_DISK_FileHandle *h) 1767GNUNET_DISK_file_close (struct GNUNET_DISK_FileHandle *h)
@@ -1773,7 +1776,7 @@ GNUNET_DISK_file_close (struct GNUNET_DISK_FileHandle *h)
1773 ret = GNUNET_OK; 1776 ret = GNUNET_OK;
1774 1777
1775#if MINGW 1778#if MINGW
1776 if (!CloseHandle (h->h)) 1779 if (! CloseHandle (h->h))
1777 { 1780 {
1778 SetErrnoFromWinError (GetLastError ()); 1781 SetErrnoFromWinError (GetLastError ());
1779 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close"); 1782 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close");
@@ -1781,7 +1784,7 @@ GNUNET_DISK_file_close (struct GNUNET_DISK_FileHandle *h)
1781 } 1784 }
1782 if (h->oOverlapRead) 1785 if (h->oOverlapRead)
1783 { 1786 {
1784 if (!CloseHandle (h->oOverlapRead->hEvent)) 1787 if (! CloseHandle (h->oOverlapRead->hEvent))
1785 { 1788 {
1786 SetErrnoFromWinError (GetLastError ()); 1789 SetErrnoFromWinError (GetLastError ());
1787 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close"); 1790 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close");
@@ -1822,7 +1825,6 @@ struct GNUNET_DISK_FileHandle *
1822GNUNET_DISK_get_handle_from_w32_handle (HANDLE osfh) 1825GNUNET_DISK_get_handle_from_w32_handle (HANDLE osfh)
1823{ 1826{
1824 struct GNUNET_DISK_FileHandle *fh; 1827 struct GNUNET_DISK_FileHandle *fh;
1825
1826 DWORD dwret; 1828 DWORD dwret;
1827 enum GNUNET_FILE_Type ftype; 1829 enum GNUNET_FILE_Type ftype;
1828 1830
@@ -1836,7 +1838,8 @@ GNUNET_DISK_get_handle_from_w32_handle (HANDLE osfh)
1836 ftype = GNUNET_DISK_HANLDE_TYPE_PIPE; 1838 ftype = GNUNET_DISK_HANLDE_TYPE_PIPE;
1837 break; 1839 break;
1838 case FILE_TYPE_UNKNOWN: 1840 case FILE_TYPE_UNKNOWN:
1839 if (GetLastError () == NO_ERROR || GetLastError () == ERROR_INVALID_HANDLE) 1841 if ( (GetLastError () == NO_ERROR) ||
1842 (GetLastError () == ERROR_INVALID_HANDLE) )
1840 { 1843 {
1841 if (0 != ResetEvent (osfh)) 1844 if (0 != ResetEvent (osfh))
1842 ftype = GNUNET_DISK_HANLDE_TYPE_EVENT; 1845 ftype = GNUNET_DISK_HANLDE_TYPE_EVENT;
diff --git a/src/util/getopt.c b/src/util/getopt.c
index ff62dba9b..036e0f4be 100644
--- a/src/util/getopt.c
+++ b/src/util/getopt.c
@@ -26,7 +26,7 @@ USA.
26 26
27 27
28This code was heavily modified for GNUnet. 28This code was heavily modified for GNUnet.
29Copyright Copyright (C) 2006 Christian Grothoff 29Copyright Copyright (C) 2006, 2017 Christian Grothoff
30*/ 30*/
31 31
32/** 32/**
@@ -845,9 +845,13 @@ GN_getopt_internal (int argc, char *const *argv, const char *optstring,
845 } 845 }
846} 846}
847 847
848
848static int 849static int
849GNgetopt_long (int argc, char *const *argv, const char *options, 850GNgetopt_long (int argc,
850 const struct GNoption *long_options, int *opt_index) 851 char *const *argv,
852 const char *options,
853 const struct GNoption *long_options,
854 int *opt_index)
851{ 855{
852 return GN_getopt_internal (argc, argv, options, long_options, opt_index, 0); 856 return GN_getopt_internal (argc, argv, options, long_options, opt_index, 0);
853} 857}
@@ -867,16 +871,17 @@ GNgetopt_long (int argc, char *const *argv, const char *options,
867int 871int
868GNUNET_GETOPT_run (const char *binaryOptions, 872GNUNET_GETOPT_run (const char *binaryOptions,
869 const struct GNUNET_GETOPT_CommandLineOption *allOptions, 873 const struct GNUNET_GETOPT_CommandLineOption *allOptions,
870 unsigned int argc, char *const *argv) 874 unsigned int argc,
875 char *const *argv)
871{ 876{
872 struct GNoption *long_options; 877 struct GNoption *long_options;
873 struct GNUNET_GETOPT_CommandLineProcessorContext clpc; 878 struct GNUNET_GETOPT_CommandLineProcessorContext clpc;
874 int count; 879 int count;
875 int i;
876 char *shorts; 880 char *shorts;
877 int spos; 881 int spos;
878 int cont; 882 int cont;
879 int c; 883 int c;
884 uint8_t *seen;
880 885
881 GNUNET_assert (argc > 0); 886 GNUNET_assert (argc > 0);
882 GNoptind = 0; 887 GNoptind = 0;
@@ -885,13 +890,15 @@ GNUNET_GETOPT_run (const char *binaryOptions,
885 clpc.allOptions = allOptions; 890 clpc.allOptions = allOptions;
886 clpc.argv = argv; 891 clpc.argv = argv;
887 clpc.argc = argc; 892 clpc.argc = argc;
888 count = 0; 893 for (count = 0; NULL != allOptions[count].name; count++) ;
889 while (allOptions[count].name != NULL) 894
890 count++; 895 long_options = GNUNET_new_array (count + 1,
891 long_options = GNUNET_malloc (sizeof (struct GNoption) * (count + 1)); 896 struct GNoption);
897 seen = GNUNET_new_array (count,
898 uint8_t);
892 shorts = GNUNET_malloc (count * 2 + 1); 899 shorts = GNUNET_malloc (count * 2 + 1);
893 spos = 0; 900 spos = 0;
894 for (i = 0; i < count; i++) 901 for (unsigned i = 0; i < count; i++)
895 { 902 {
896 long_options[i].name = allOptions[i].name; 903 long_options[i].name = allOptions[i].name;
897 long_options[i].has_arg = allOptions[i].require_argument; 904 long_options[i].has_arg = allOptions[i].require_argument;
@@ -907,13 +914,17 @@ GNUNET_GETOPT_run (const char *binaryOptions,
907 long_options[count].val = '\0'; 914 long_options[count].val = '\0';
908 shorts[spos] = '\0'; 915 shorts[spos] = '\0';
909 cont = GNUNET_OK; 916 cont = GNUNET_OK;
917
910 /* main getopt loop */ 918 /* main getopt loop */
911 while (cont == GNUNET_OK) 919 while (GNUNET_OK == cont)
912 { 920 {
913 int option_index = 0; 921 int option_index = 0;
922 unsigned int i;
914 923
915 c = GNgetopt_long (argc, argv, shorts, long_options, &option_index); 924 c = GNgetopt_long (argc, argv,
916 925 shorts,
926 long_options,
927 &option_index);
917 if (c == GNUNET_SYSERR) 928 if (c == GNUNET_SYSERR)
918 break; /* No more flags to process */ 929 break; /* No more flags to process */
919 930
@@ -922,25 +933,46 @@ GNUNET_GETOPT_run (const char *binaryOptions,
922 clpc.currentArgument = GNoptind - 1; 933 clpc.currentArgument = GNoptind - 1;
923 if ((char) c == allOptions[i].shortName) 934 if ((char) c == allOptions[i].shortName)
924 { 935 {
925 cont = 936 cont = allOptions[i].processor (&clpc,
926 allOptions[i].processor (&clpc, allOptions[i].scls, 937 allOptions[i].scls,
927 allOptions[i].name, GNoptarg); 938 allOptions[i].name,
939 GNoptarg);
940 seen[i] = 1;
928 break; 941 break;
929 } 942 }
930 } 943 }
931 if (i == count) 944 if (i == count)
932 { 945 {
933 FPRINTF (stderr, _("Use %s to get a list of options.\n"), "--help"); 946 FPRINTF (stderr,
947 _("Use %s to get a list of options.\n"),
948 "--help");
934 cont = GNUNET_SYSERR; 949 cont = GNUNET_SYSERR;
935 } 950 }
936 } 951 }
937
938 GNUNET_free (shorts); 952 GNUNET_free (shorts);
939 GNUNET_free (long_options); 953 GNUNET_free (long_options);
940 if (cont != GNUNET_OK) 954
955 if (GNUNET_YES == cont)
941 { 956 {
942 return cont; 957 for (count = 0; NULL != allOptions[count].name; count++)
958 if ( (0 == seen[count]) &&
959 (allOptions[count].option_mandatory) )
960 {
961 FPRINTF (stderr,
962 _("Missing mandatory option `%s'.\n"),
963 allOptions[count].name);
964 cont = GNUNET_SYSERR;
965 }
943 } 966 }
967 GNUNET_free (seen);
968
969 /* call cleaners, if available */
970 for (count = 0; NULL != allOptions[count].name; count++)
971 if (NULL != allOptions[count].cleaner)
972 allOptions[count].cleaner (allOptions[count].scls);
973
974 if (GNUNET_OK != cont)
975 return cont;
944 return GNoptind; 976 return GNoptind;
945} 977}
946 978
diff --git a/src/util/getopt_helpers.c b/src/util/getopt_helpers.c
index 4d7104503..76342a6c9 100644
--- a/src/util/getopt_helpers.c
+++ b/src/util/getopt_helpers.c
@@ -38,11 +38,11 @@
38 * @param value not used (NULL) 38 * @param value not used (NULL)
39 * @return #GNUNET_NO (do not continue, not an error) 39 * @return #GNUNET_NO (do not continue, not an error)
40 */ 40 */
41int 41static int
42GNUNET_GETOPT_print_version_ (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, 42print_version (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
43 void *scls, 43 void *scls,
44 const char *option, 44 const char *option,
45 const char *value) 45 const char *value)
46{ 46{
47 const char *version = scls; 47 const char *version = scls;
48 48
@@ -54,6 +54,26 @@ GNUNET_GETOPT_print_version_ (struct GNUNET_GETOPT_CommandLineProcessorContext *
54 54
55 55
56/** 56/**
57 * Define the option to print the version of
58 * the application (-v option)
59 *
60 * @param version string with the version number
61 */
62struct GNUNET_GETOPT_CommandLineOption
63GNUNET_GETOPT_OPTION_VERSION (const char *version)
64{
65 struct GNUNET_GETOPT_CommandLineOption clo = {
66 .shortName = 'v',
67 .name = "version",
68 .description = gettext_noop("print the version number"),
69 .processor = &print_version,
70 .scls = (void *) version
71 };
72 return clo;
73}
74
75
76/**
57 * At what offset does the help text start? 77 * At what offset does the help text start?
58 */ 78 */
59#define BORDER 29 79#define BORDER 29
@@ -67,11 +87,11 @@ GNUNET_GETOPT_print_version_ (struct GNUNET_GETOPT_CommandLineProcessorContext *
67 * @param value not used (NULL) 87 * @param value not used (NULL)
68 * @return #GNUNET_NO (do not continue, not an error) 88 * @return #GNUNET_NO (do not continue, not an error)
69 */ 89 */
70int 90static int
71GNUNET_GETOPT_format_help_ (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, 91format_help (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
72 void *scls, 92 void *scls,
73 const char *option, 93 const char *option,
74 const char *value) 94 const char *value)
75{ 95{
76 const char *about = scls; 96 const char *about = scls;
77 size_t slen; 97 size_t slen;
@@ -165,6 +185,27 @@ OUTER:
165 185
166 186
167/** 187/**
188 * Defining the option to print the command line
189 * help text (-h option).
190 *
191 * @param about string with brief description of the application
192 */
193struct GNUNET_GETOPT_CommandLineOption
194GNUNET_GETOPT_OPTION_HELP (const char *about)
195{
196 struct GNUNET_GETOPT_CommandLineOption clo = {
197 .shortName = 'h',
198 .name = "help",
199 .description = gettext_noop("print this help"),
200 .processor = format_help,
201 .scls = (void *) about
202 };
203
204 return clo;
205}
206
207
208/**
168 * Set an option of type 'unsigned int' from the command line. Each 209 * Set an option of type 'unsigned int' from the command line. Each
169 * time the option flag is given, the value is incremented by one. 210 * time the option flag is given, the value is incremented by one.
170 * A pointer to this function should be passed as part of the 211 * A pointer to this function should be passed as part of the
@@ -173,17 +214,18 @@ OUTER:
173 * type 'int'. 214 * type 'int'.
174 * 215 *
175 * @param ctx command line processing context 216 * @param ctx command line processing context
176 * @param scls additional closure (will point to the 'int') 217 * @param scls additional closure (will point to the 'unsigned int')
177 * @param option name of the option 218 * @param option name of the option
178 * @param value not used (NULL) 219 * @param value not used (NULL)
179 * @return #GNUNET_OK 220 * @return #GNUNET_OK
180 */ 221 */
181int 222static int
182GNUNET_GETOPT_increment_value (struct GNUNET_GETOPT_CommandLineProcessorContext 223increment_value (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
183 *ctx, void *scls, const char *option, 224 void *scls,
184 const char *value) 225 const char *option,
226 const char *value)
185{ 227{
186 int *val = scls; 228 unsigned int *val = scls;
187 229
188 (*val)++; 230 (*val)++;
189 return GNUNET_OK; 231 return GNUNET_OK;
@@ -191,6 +233,54 @@ GNUNET_GETOPT_increment_value (struct GNUNET_GETOPT_CommandLineProcessorContext
191 233
192 234
193/** 235/**
236 * Increment @a val each time the option flag is given by one.
237 *
238 * @param shortName short name of the option
239 * @param name long name of the option
240 * @param argumentHelp help text for the option argument
241 * @param description long help text for the option
242 * @param[out] val increment by 1 each time the option is present
243 */
244struct GNUNET_GETOPT_CommandLineOption
245GNUNET_GETOPT_OPTION_INCREMENT_VALUE (char shortName,
246 const char *name,
247 const char *description,
248 unsigned int *val)
249{
250 struct GNUNET_GETOPT_CommandLineOption clo = {
251 .shortName = shortName,
252 .name = name,
253 .description = description,
254 .processor = &increment_value,
255 .scls = (void *) val
256 };
257
258 return clo;
259}
260
261
262/**
263 * Define the '-V' verbosity option. Using the option more
264 * than once increments @a level each time.
265 *
266 * @param[out] level set to the verbosity level
267 */
268struct GNUNET_GETOPT_CommandLineOption
269GNUNET_GETOPT_OPTION_VERBOSE (unsigned int *level)
270{
271 struct GNUNET_GETOPT_CommandLineOption clo = {
272 .shortName = 'V',
273 .name = "verbose",
274 .description = gettext_noop("be verbose"),
275 .processor = &increment_value,
276 .scls = (void *) level
277 };
278
279 return clo;
280}
281
282
283/**
194 * Set an option of type 'int' from the command line to 1 if the 284 * Set an option of type 'int' from the command line to 1 if the
195 * given option is present. 285 * given option is present.
196 * A pointer to this function should be passed as part of the 286 * A pointer to this function should be passed as part of the
@@ -204,9 +294,11 @@ GNUNET_GETOPT_increment_value (struct GNUNET_GETOPT_CommandLineProcessorContext
204 * @param value not used (NULL) 294 * @param value not used (NULL)
205 * @return #GNUNET_OK 295 * @return #GNUNET_OK
206 */ 296 */
207int 297static int
208GNUNET_GETOPT_set_one (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, 298set_one (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
209 void *scls, const char *option, const char *value) 299 void *scls,
300 const char *option,
301 const char *value)
210{ 302{
211 int *val = scls; 303 int *val = scls;
212 304
@@ -216,6 +308,34 @@ GNUNET_GETOPT_set_one (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
216 308
217 309
218/** 310/**
311 * Allow user to specify a flag (which internally means setting
312 * an integer to 1/#GNUNET_YES/#GNUNET_OK.
313 *
314 * @param shortName short name of the option
315 * @param name long name of the option
316 * @param argumentHelp help text for the option argument
317 * @param description long help text for the option
318 * @param[out] val set to 1 if the option is present
319 */
320struct GNUNET_GETOPT_CommandLineOption
321GNUNET_GETOPT_OPTION_SET_ONE (char shortName,
322 const char *name,
323 const char *description,
324 int *val)
325{
326 struct GNUNET_GETOPT_CommandLineOption clo = {
327 .shortName = shortName,
328 .name = name,
329 .description = description,
330 .processor = &set_one,
331 .scls = (void *) val
332 };
333
334 return clo;
335}
336
337
338/**
219 * Set an option of type 'char *' from the command line. 339 * Set an option of type 'char *' from the command line.
220 * A pointer to this function should be passed as part of the 340 * A pointer to this function should be passed as part of the
221 * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options 341 * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options
@@ -229,31 +349,174 @@ GNUNET_GETOPT_set_one (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
229 * @param value actual value of the option (a string) 349 * @param value actual value of the option (a string)
230 * @return #GNUNET_OK 350 * @return #GNUNET_OK
231 */ 351 */
232int 352static int
233GNUNET_GETOPT_set_string (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, 353set_string (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
234 void *scls, const char *option, const char *value) 354 void *scls,
355 const char *option,
356 const char *value)
235{ 357{
236 char **val = scls; 358 char **val = scls;
237 359
238 GNUNET_assert (value != NULL); 360 GNUNET_assert (NULL != value);
239 GNUNET_free_non_null (*val); 361 GNUNET_free_non_null (*val);
240 *val = GNUNET_strdup (value); 362 *val = GNUNET_strdup (value);
241 return GNUNET_OK; 363 return GNUNET_OK;
242} 364}
243 365
244 366
245int 367/**
246GNUNET_GETOPT_set_filename (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, 368 * Allow user to specify a string.
247 void *scls, const char *option, const char *value) 369 *
370 * @param shortName short name of the option
371 * @param name long name of the option
372 * @param argumentHelp help text for the option argument
373 * @param description long help text for the option
374 * @param[out] str set to the string
375 */
376struct GNUNET_GETOPT_CommandLineOption
377GNUNET_GETOPT_OPTION_STRING (char shortName,
378 const char *name,
379 const char *argumentHelp,
380 const char *description,
381 char **str)
382{
383 struct GNUNET_GETOPT_CommandLineOption clo = {
384 .shortName = shortName,
385 .name = name,
386 .argumentHelp = argumentHelp,
387 .description = description,
388 .require_argument = 1,
389 .processor = &set_string,
390 .scls = (void *) str
391 };
392
393 return clo;
394}
395
396
397/**
398 * Define the '-L' log level option. Note that we do not check
399 * that the log level is valid here.
400 *
401 * @param[out] level set to the log level
402 */
403struct GNUNET_GETOPT_CommandLineOption
404GNUNET_GETOPT_OPTION_LOGLEVEL (char **level)
405{
406 struct GNUNET_GETOPT_CommandLineOption clo = {
407 .shortName = 'L',
408 .name = "log",
409 .argumentHelp = "LOGLEVEL",
410 .description = gettext_noop("configure logging to use LOGLEVEL"),
411 .require_argument = 1,
412 .processor = &set_string,
413 .scls = (void *) level
414 };
415
416 return clo;
417}
418
419
420/**
421 * Set an option of type 'char *' from the command line with
422 * filename expansion a la #GNUNET_STRINGS_filename_expand().
423 *
424 * @param ctx command line processing context
425 * @param scls additional closure (will point to the `char *`,
426 * which will be allocated)
427 * @param option name of the option
428 * @param value actual value of the option (a string)
429 * @return #GNUNET_OK
430 */
431static int
432set_filename (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
433 void *scls,
434 const char *option,
435 const char *value)
248{ 436{
249 char **val = scls; 437 char **val = scls;
250 438
251 GNUNET_assert (value != NULL); 439 GNUNET_assert (NULL != value);
252 GNUNET_free_non_null (*val); 440 GNUNET_free_non_null (*val);
253 *val = GNUNET_STRINGS_filename_expand (value); 441 *val = GNUNET_STRINGS_filename_expand (value);
254 return GNUNET_OK; 442 return GNUNET_OK;
255} 443}
256 444
445
446/**
447 * Allow user to specify a filename (automatically path expanded).
448 *
449 * @param shortName short name of the option
450 * @param name long name of the option
451 * @param argumentHelp help text for the option argument
452 * @param description long help text for the option
453 * @param[out] str set to the string
454 */
455struct GNUNET_GETOPT_CommandLineOption
456GNUNET_GETOPT_OPTION_FILENAME (char shortName,
457 const char *name,
458 const char *argumentHelp,
459 const char *description,
460 char **str)
461{
462 struct GNUNET_GETOPT_CommandLineOption clo = {
463 .shortName = shortName,
464 .name = name,
465 .argumentHelp = argumentHelp,
466 .description = description,
467 .require_argument = 1,
468 .processor = &set_filename,
469 .scls = (void *) str
470 };
471
472 return clo;
473}
474
475
476/**
477 * Allow user to specify log file name (-l option)
478 *
479 * @param[out] logfn set to the name of the logfile
480 */
481struct GNUNET_GETOPT_CommandLineOption
482GNUNET_GETOPT_OPTION_LOGFILE (char **logfn)
483{
484 struct GNUNET_GETOPT_CommandLineOption clo = {
485 .shortName = 'l',
486 .name = "logfile",
487 .argumentHelp = "FILENAME",
488 .description = gettext_noop ("configure logging to write logs to FILENAME"),
489 .require_argument = 1,
490 .processor = &set_filename,
491 .scls = (void *) logfn
492 };
493
494 return clo;
495}
496
497
498/**
499 * Allow user to specify configuration file name (-c option)
500 *
501 * @param[out] fn set to the name of the configuration file
502 */
503struct GNUNET_GETOPT_CommandLineOption
504GNUNET_GETOPT_OPTION_CFG_FILE (char **fn)
505{
506 struct GNUNET_GETOPT_CommandLineOption clo = {
507 .shortName = 'c',
508 .name = "config",
509 .argumentHelp = "FILENAME",
510 .description = gettext_noop("use configuration file FILENAME"),
511 .require_argument = 1,
512 .processor = &set_filename,
513 .scls = (void *) fn
514 };
515
516 return clo;
517}
518
519
257/** 520/**
258 * Set an option of type 'unsigned long long' from the command line. 521 * Set an option of type 'unsigned long long' from the command line.
259 * A pointer to this function should be passed as part of the 522 * A pointer to this function should be passed as part of the
@@ -267,15 +530,21 @@ GNUNET_GETOPT_set_filename (struct GNUNET_GETOPT_CommandLineProcessorContext *ct
267 * @param value actual value of the option as a string. 530 * @param value actual value of the option as a string.
268 * @return #GNUNET_OK if parsing the value worked 531 * @return #GNUNET_OK if parsing the value worked
269 */ 532 */
270int 533static int
271GNUNET_GETOPT_set_ulong (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, 534set_ulong (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
272 void *scls, const char *option, const char *value) 535 void *scls,
536 const char *option,
537 const char *value)
273{ 538{
274 unsigned long long *val = scls; 539 unsigned long long *val = scls;
275 540
276 if (1 != SSCANF (value, "%llu", val)) 541 if (1 != SSCANF (value,
542 "%llu",
543 val))
277 { 544 {
278 FPRINTF (stderr, _("You must pass a number to the `%s' option.\n"), option); 545 FPRINTF (stderr,
546 _("You must pass a number to the `%s' option.\n"),
547 option);
279 return GNUNET_SYSERR; 548 return GNUNET_SYSERR;
280 } 549 }
281 return GNUNET_OK; 550 return GNUNET_OK;
@@ -283,6 +552,36 @@ GNUNET_GETOPT_set_ulong (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
283 552
284 553
285/** 554/**
555 * Allow user to specify an `unsigned long long`
556 *
557 * @param shortName short name of the option
558 * @param name long name of the option
559 * @param argumentHelp help text for the option argument
560 * @param description long help text for the option
561 * @param[out] val set to the value specified at the command line
562 */
563struct GNUNET_GETOPT_CommandLineOption
564GNUNET_GETOPT_OPTION_SET_ULONG (char shortName,
565 const char *name,
566 const char *argumentHelp,
567 const char *description,
568 unsigned long long *val)
569{
570 struct GNUNET_GETOPT_CommandLineOption clo = {
571 .shortName = shortName,
572 .name = name,
573 .argumentHelp = argumentHelp,
574 .description = description,
575 .require_argument = 1,
576 .processor = &set_ulong,
577 .scls = (void *) val
578 };
579
580 return clo;
581}
582
583
584/**
286 * Set an option of type 'struct GNUNET_TIME_Relative' from the command line. 585 * Set an option of type 'struct GNUNET_TIME_Relative' from the command line.
287 * A pointer to this function should be passed as part of the 586 * A pointer to this function should be passed as part of the
288 * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options 587 * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options
@@ -295,9 +594,11 @@ GNUNET_GETOPT_set_ulong (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
295 * @param value actual value of the option as a string. 594 * @param value actual value of the option as a string.
296 * @return #GNUNET_OK if parsing the value worked 595 * @return #GNUNET_OK if parsing the value worked
297 */ 596 */
298int 597static int
299GNUNET_GETOPT_set_relative_time (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, 598set_relative_time (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
300 void *scls, const char *option, const char *value) 599 void *scls,
600 const char *option,
601 const char *value)
301{ 602{
302 struct GNUNET_TIME_Relative *val = scls; 603 struct GNUNET_TIME_Relative *val = scls;
303 604
@@ -305,7 +606,74 @@ GNUNET_GETOPT_set_relative_time (struct GNUNET_GETOPT_CommandLineProcessorContex
305 GNUNET_STRINGS_fancy_time_to_relative (value, 606 GNUNET_STRINGS_fancy_time_to_relative (value,
306 val)) 607 val))
307 { 608 {
308 FPRINTF (stderr, _("You must pass relative time to the `%s' option.\n"), option); 609 FPRINTF (stderr,
610 _("You must pass relative time to the `%s' option.\n"),
611 option);
612 return GNUNET_SYSERR;
613 }
614 return GNUNET_OK;
615}
616
617
618/**
619 * Allow user to specify a `struct GNUNET_TIME_Relative`
620 * (using human-readable "fancy" time).
621 *
622 * @param shortName short name of the option
623 * @param name long name of the option
624 * @param argumentHelp help text for the option argument
625 * @param description long help text for the option
626 * @param[out] val set to the time specified at the command line
627 */
628struct GNUNET_GETOPT_CommandLineOption
629GNUNET_GETOPT_OPTION_SET_RELATIVE_TIME (char shortName,
630 const char *name,
631 const char *argumentHelp,
632 const char *description,
633 struct GNUNET_TIME_Relative *val)
634{
635 struct GNUNET_GETOPT_CommandLineOption clo = {
636 .shortName = shortName,
637 .name = name,
638 .argumentHelp = argumentHelp,
639 .description = description,
640 .require_argument = 1,
641 .processor = &set_relative_time,
642 .scls = (void *) val
643 };
644
645 return clo;
646}
647
648
649/**
650 * Set an option of type 'struct GNUNET_TIME_Absolute' from the command line.
651 * A pointer to this function should be passed as part of the
652 * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options
653 * of this type. It should be followed by a pointer to a value of
654 * type 'struct GNUNET_TIME_Absolute'.
655 *
656 * @param ctx command line processing context
657 * @param scls additional closure (will point to the `struct GNUNET_TIME_Absolute`)
658 * @param option name of the option
659 * @param value actual value of the option as a string.
660 * @return #GNUNET_OK if parsing the value worked
661 */
662static int
663set_absolute_time (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
664 void *scls,
665 const char *option,
666 const char *value)
667{
668 struct GNUNET_TIME_Absolute *val = scls;
669
670 if (GNUNET_OK !=
671 GNUNET_STRINGS_fancy_time_to_absolute (value,
672 val))
673 {
674 FPRINTF (stderr,
675 _("You must pass absolute time to the `%s' option.\n"),
676 option);
309 return GNUNET_SYSERR; 677 return GNUNET_SYSERR;
310 } 678 }
311 return GNUNET_OK; 679 return GNUNET_OK;
@@ -313,6 +681,37 @@ GNUNET_GETOPT_set_relative_time (struct GNUNET_GETOPT_CommandLineProcessorContex
313 681
314 682
315/** 683/**
684 * Allow user to specify a `struct GNUNET_TIME_Absolute`
685 * (using human-readable "fancy" time).
686 *
687 * @param shortName short name of the option
688 * @param name long name of the option
689 * @param argumentHelp help text for the option argument
690 * @param description long help text for the option
691 * @param[out] val set to the time specified at the command line
692 */
693struct GNUNET_GETOPT_CommandLineOption
694GNUNET_GETOPT_OPTION_SET_ABSOLUTE_TIME (char shortName,
695 const char *name,
696 const char *argumentHelp,
697 const char *description,
698 struct GNUNET_TIME_Absolute *val)
699{
700 struct GNUNET_GETOPT_CommandLineOption clo = {
701 .shortName = shortName,
702 .name = name,
703 .argumentHelp = argumentHelp,
704 .description = description,
705 .require_argument = 1,
706 .processor = &set_absolute_time,
707 .scls = (void *) val
708 };
709
710 return clo;
711}
712
713
714/**
316 * Set an option of type 'unsigned int' from the command line. 715 * Set an option of type 'unsigned int' from the command line.
317 * A pointer to this function should be passed as part of the 716 * A pointer to this function should be passed as part of the
318 * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options 717 * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options
@@ -325,19 +724,172 @@ GNUNET_GETOPT_set_relative_time (struct GNUNET_GETOPT_CommandLineProcessorContex
325 * @param value actual value of the option as a string. 724 * @param value actual value of the option as a string.
326 * @return #GNUNET_OK if parsing the value worked 725 * @return #GNUNET_OK if parsing the value worked
327 */ 726 */
328int 727static int
329GNUNET_GETOPT_set_uint (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, 728set_uint (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
330 void *scls, const char *option, const char *value) 729 void *scls,
730 const char *option,
731 const char *value)
331{ 732{
332 unsigned int *val = scls; 733 unsigned int *val = scls;
333 734
334 if (1 != SSCANF (value, "%u", val)) 735 if (1 != SSCANF (value,
736 "%u",
737 val))
335 { 738 {
336 FPRINTF (stderr, _("You must pass a number to the `%s' option.\n"), option); 739 FPRINTF (stderr,
740 _("You must pass a number to the `%s' option.\n"),
741 option);
337 return GNUNET_SYSERR; 742 return GNUNET_SYSERR;
338 } 743 }
339 return GNUNET_OK; 744 return GNUNET_OK;
340} 745}
341 746
342 747
748/**
749 * Allow user to specify an unsigned integer.
750 *
751 * @param shortName short name of the option
752 * @param name long name of the option
753 * @param argumentHelp help text for the option argument
754 * @param description long help text for the option
755 * @param[out] val set to the value specified at the command line
756 */
757struct GNUNET_GETOPT_CommandLineOption
758GNUNET_GETOPT_OPTION_SET_UINT (char shortName,
759 const char *name,
760 const char *argumentHelp,
761 const char *description,
762 unsigned int *val)
763{
764 struct GNUNET_GETOPT_CommandLineOption clo = {
765 .shortName = shortName,
766 .name = name,
767 .argumentHelp = argumentHelp,
768 .description = description,
769 .require_argument = 1,
770 .processor = &set_uint,
771 .scls = (void *) val
772 };
773
774 return clo;
775}
776
777
778/**
779 * Closure for #set_base32().
780 */
781struct Base32Context
782{
783 /**
784 * Value to initialize (already allocated)
785 */
786 void *val;
787
788 /**
789 * Number of bytes expected for @e val.
790 */
791 size_t val_size;
792};
793
794
795/**
796 * Set an option of type 'unsigned int' from the command line.
797 * A pointer to this function should be passed as part of the
798 * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options
799 * of this type. It should be followed by a pointer to a value of
800 * type 'unsigned int'.
801 *
802 * @param ctx command line processing context
803 * @param scls additional closure (will point to the 'unsigned int')
804 * @param option name of the option
805 * @param value actual value of the option as a string.
806 * @return #GNUNET_OK if parsing the value worked
807 */
808static int
809set_base32 (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
810 void *scls,
811 const char *option,
812 const char *value)
813{
814 struct Base32Context *bc = scls;
815
816 if (GNUNET_OK !=
817 GNUNET_STRINGS_string_to_data (value,
818 strlen (value),
819 bc->val,
820 bc->val_size))
821 {
822 fprintf (stderr,
823 _("Argument `%s' malformed. Expected base32 (Crockford) encoded value.\n"),
824 option);
825 return GNUNET_SYSERR;
826 }
827 return GNUNET_OK;
828}
829
830
831/**
832 * Helper function to clean up after
833 * #GNUNET_GETOPT_OPTION_SET_BASE32_FIXED_SIZE.
834 *
835 * @param cls value to GNUNET_free()
836 */
837static void
838free_bc (void *cls)
839{
840 GNUNET_free (cls);
841}
842
843
844/**
845 * Allow user to specify a binary value using Crockford
846 * Base32 encoding.
847 *
848 * @param shortName short name of the option
849 * @param name long name of the option
850 * @param argumentHelp help text for the option argument
851 * @param description long help text for the option
852 * @param[out] val binary value decoded from Crockford Base32-encoded argument
853 * @param val_size size of @a val in bytes
854 */
855struct GNUNET_GETOPT_CommandLineOption
856GNUNET_GETOPT_OPTION_SET_BASE32_FIXED_SIZE (char shortName,
857 const char *name,
858 const char *argumentHelp,
859 const char *description,
860 void *val,
861 size_t val_size)
862{
863 struct Base32Context *bc = GNUNET_new (struct Base32Context);
864 struct GNUNET_GETOPT_CommandLineOption clo = {
865 .shortName = shortName,
866 .name = name,
867 .argumentHelp = argumentHelp,
868 .description = description,
869 .require_argument = 1,
870 .processor = &set_base32,
871 .cleaner = &free_bc,
872 .scls = (void *) bc
873 };
874
875 bc->val = val;
876 bc->val_size = val_size;
877 return clo;
878}
879
880
881/**
882 * Make the given option mandatory.
883 *
884 * @param opt option to modify
885 * @return @a opt with the mandatory flag set.
886 */
887struct GNUNET_GETOPT_CommandLineOption
888GNUNET_GETOPT_OPTION_MANDATORY (struct GNUNET_GETOPT_CommandLineOption opt)
889{
890 opt.option_mandatory = 1;
891 return opt;
892}
893
894
343/* end of getopt_helpers.c */ 895/* end of getopt_helpers.c */
diff --git a/src/util/gnunet-config.c b/src/util/gnunet-config.c
index 7ec7162f1..2beb772a9 100644
--- a/src/util/gnunet-config.c
+++ b/src/util/gnunet-config.c
@@ -223,34 +223,48 @@ run (void *cls,
223int 223int
224main (int argc, char *const *argv) 224main (int argc, char *const *argv)
225{ 225{
226 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 226 struct GNUNET_GETOPT_CommandLineOption options[] = {
227 { 'f', "filename", NULL, 227 GNUNET_GETOPT_OPTION_SET_ONE ('f',
228 gettext_noop ("obtain option of value as a filename (with $-expansion)"), 228 "filename",
229 0, &GNUNET_GETOPT_set_one, &is_filename }, 229 gettext_noop ("obtain option of value as a filename (with $-expansion)"),
230 { 's', "section", "SECTION", 230 &is_filename),
231 gettext_noop ("name of the section to access"), 231 GNUNET_GETOPT_OPTION_STRING ('s',
232 1, &GNUNET_GETOPT_set_string, &section }, 232 "section",
233 { 'o', "option", "OPTION", 233 "SECTION",
234 gettext_noop ("name of the option to access"), 234 gettext_noop ("name of the section to access"),
235 1, &GNUNET_GETOPT_set_string, &option }, 235 &section),
236 { 'V', "value", "VALUE", 236 GNUNET_GETOPT_OPTION_STRING ('o',
237 gettext_noop ("value to set"), 237 "option",
238 1, &GNUNET_GETOPT_set_string, &value }, 238 "OPTION",
239 { 'S', "list-sections", NULL, 239 gettext_noop ("name of the option to access"),
240 gettext_noop ("print available configuration sections"), 240 &option),
241 0, &GNUNET_GETOPT_set_one, &list_sections }, 241 GNUNET_GETOPT_OPTION_STRING ('V',
242 { 'w', "rewrite", NULL, 242 "value",
243 gettext_noop ("write configuration file that only contains delta to defaults"), 243 "VALUE",
244 0, &GNUNET_GETOPT_set_one, &rewrite }, 244 gettext_noop ("value to set"),
245 &value),
246 GNUNET_GETOPT_OPTION_SET_ONE ('S',
247 "list-sections",
248 gettext_noop ("print available configuration sections"),
249 &list_sections),
250 GNUNET_GETOPT_OPTION_SET_ONE ('w',
251 "rewrite",
252 gettext_noop ("write configuration file that only contains delta to defaults"),
253 &rewrite),
245 GNUNET_GETOPT_OPTION_END 254 GNUNET_GETOPT_OPTION_END
246 }; 255 };
247 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) 256 if (GNUNET_OK !=
257 GNUNET_STRINGS_get_utf8_args (argc, argv,
258 &argc, &argv))
248 return 2; 259 return 2;
249 260
250 ret = (GNUNET_OK == 261 ret = (GNUNET_OK ==
251 GNUNET_PROGRAM_run (argc, argv, "gnunet-config [OPTIONS]", 262 GNUNET_PROGRAM_run (argc,
263 argv,
264 "gnunet-config [OPTIONS]",
252 gettext_noop ("Manipulate GNUnet configuration files"), 265 gettext_noop ("Manipulate GNUnet configuration files"),
253 options, &run, NULL)) ? 0 : ret; 266 options,
267 &run, NULL)) ? 0 : ret;
254 GNUNET_free ((void*) argv); 268 GNUNET_free ((void*) argv);
255 return ret; 269 return ret;
256} 270}
diff --git a/src/util/gnunet-ecc.c b/src/util/gnunet-ecc.c
index ddfd9b1c3..732228b52 100644
--- a/src/util/gnunet-ecc.c
+++ b/src/util/gnunet-ecc.c
@@ -41,7 +41,7 @@ static int list_keys;
41/** 41/**
42 * Flag for listing public key. 42 * Flag for listing public key.
43 */ 43 */
44static int list_keys_count; 44static unsigned int list_keys_count;
45 45
46/** 46/**
47 * Flag for printing public key. 47 * Flag for printing public key.
@@ -406,36 +406,50 @@ run (void *cls, char *const *args, const char *cfgfile,
406 * @return 0 ok, 1 on error 406 * @return 0 ok, 1 on error
407 */ 407 */
408int 408int
409main (int argc, char *const *argv) 409main (int argc,
410 char *const *argv)
410{ 411{
411 list_keys_count = UINT32_MAX; 412 list_keys_count = UINT32_MAX;
412 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 413 struct GNUNET_GETOPT_CommandLineOption options[] = {
413 { 'i', "iterate", "FILE", 414 GNUNET_GETOPT_OPTION_SET_ONE ('i',
414 gettext_noop ("list keys included in a file (for testing)"), 415 "iterate",
415 0, &GNUNET_GETOPT_set_one, &list_keys }, 416 gettext_noop ("list keys included in a file (for testing)"),
416 { 'e', "end=", "COUNT", 417 &list_keys),
417 gettext_noop ("number of keys to list included in a file (for testing)"), 418 GNUNET_GETOPT_OPTION_SET_UINT ('e',
418 1, &GNUNET_GETOPT_set_uint, &list_keys_count }, 419 "end=",
419 { 'g', "generate-keys", "COUNT", 420 "COUNT",
420 gettext_noop ("create COUNT public-private key pairs (for testing)"), 421 gettext_noop ("number of keys to list included in a file (for testing)"),
421 1, &GNUNET_GETOPT_set_uint, &make_keys }, 422 &list_keys_count),
422 { 'p', "print-public-key", NULL, 423 GNUNET_GETOPT_OPTION_SET_UINT ('g',
423 gettext_noop ("print the public key in ASCII format"), 424 "generate-keys",
424 0, &GNUNET_GETOPT_set_one, &print_public_key }, 425 "COUNT",
425 { 'E', "examples", NULL, 426 gettext_noop ("create COUNT public-private key pairs (for testing)"),
426 gettext_noop ("print examples of ECC operations (used for compatibility testing)"), 427 &make_keys),
427 0, &GNUNET_GETOPT_set_one, &print_examples_flag }, 428 GNUNET_GETOPT_OPTION_SET_ONE ('p',
429 "print-public-key",
430 gettext_noop ("print the public key in ASCII format"),
431 &print_public_key),
432 GNUNET_GETOPT_OPTION_SET_ONE ('E',
433 "examples",
434 gettext_noop ("print examples of ECC operations (used for compatibility testing)"),
435 &print_examples_flag),
428 GNUNET_GETOPT_OPTION_END 436 GNUNET_GETOPT_OPTION_END
429 }; 437 };
430 int ret; 438 int ret;
431 439
432 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) 440 if (GNUNET_OK !=
441 GNUNET_STRINGS_get_utf8_args (argc, argv,
442 &argc, &argv))
433 return 2; 443 return 2;
434 444
435 ret = (GNUNET_OK == 445 ret = (GNUNET_OK ==
436 GNUNET_PROGRAM_run (argc, argv, "gnunet-ecc [OPTIONS] keyfile [VANITY_PREFIX]", 446 GNUNET_PROGRAM_run (argc,
447 argv,
448 "gnunet-ecc [OPTIONS] keyfile [VANITY_PREFIX]",
437 gettext_noop ("Manipulate GNUnet private ECC key files"), 449 gettext_noop ("Manipulate GNUnet private ECC key files"),
438 options, &run, NULL)) ? 0 : 1; 450 options,
451 &run,
452 NULL)) ? 0 : 1;
439 GNUNET_free ((void*) argv); 453 GNUNET_free ((void*) argv);
440 return ret; 454 return ret;
441} 455}
diff --git a/src/util/gnunet-resolver.c b/src/util/gnunet-resolver.c
index e84a2332f..563cf9fce 100644
--- a/src/util/gnunet-resolver.c
+++ b/src/util/gnunet-resolver.c
@@ -144,10 +144,11 @@ run (void *cls, char *const *args, const char *cfgfile,
144int 144int
145main (int argc, char *const *argv) 145main (int argc, char *const *argv)
146{ 146{
147 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 147 struct GNUNET_GETOPT_CommandLineOption options[] = {
148 { 'r', "reverse", NULL, 148 GNUNET_GETOPT_OPTION_SET_ONE ('r',
149 gettext_noop ("perform a reverse lookup"), 149 "reverse",
150 0, &GNUNET_GETOPT_set_one, &reverse }, 150 gettext_noop ("perform a reverse lookup"),
151 &reverse),
151 GNUNET_GETOPT_OPTION_END 152 GNUNET_GETOPT_OPTION_END
152 }; 153 };
153 int ret; 154 int ret;
diff --git a/src/util/gnunet-scrypt.c b/src/util/gnunet-scrypt.c
index ab0cf92e0..7c73cfe1e 100644
--- a/src/util/gnunet-scrypt.c
+++ b/src/util/gnunet-scrypt.c
@@ -307,21 +307,30 @@ run (void *cls,
307 * @return 0 ok, 1 on error 307 * @return 0 ok, 1 on error
308 */ 308 */
309int 309int
310main (int argc, char *const *argv) 310main (int argc,
311 char *const *argv)
311{ 312{
312 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 313 struct GNUNET_GETOPT_CommandLineOption options[] = {
313 { 'b', "bits", "BITS", 314 GNUNET_GETOPT_OPTION_SET_ULONG ('b',
314 gettext_noop ("number of bits to require for the proof of work"), 315 "bits",
315 1, &GNUNET_GETOPT_set_ulong, &nse_work_required }, 316 "BITS",
316 { 'k', "keyfile", "FILE", 317 gettext_noop ("number of bits to require for the proof of work"),
317 gettext_noop ("file with private key, otherwise default is used"), 318 &nse_work_required),
318 1, &GNUNET_GETOPT_set_filename, &pkfn }, 319 GNUNET_GETOPT_OPTION_FILENAME ('k',
319 { 'o', "outfile", "FILE", 320 "keyfile",
320 gettext_noop ("file with proof of work, otherwise default is used"), 321 "FILE",
321 1, &GNUNET_GETOPT_set_filename, &pwfn }, 322 gettext_noop ("file with private key, otherwise default is used"),
322 { 't', "timeout", "TIME", 323 &pkfn),
323 gettext_noop ("time to wait between calculations"), 324 GNUNET_GETOPT_OPTION_FILENAME ('o',
324 1, &GNUNET_GETOPT_set_relative_time, &proof_find_delay }, 325 "outfile",
326 "FILE",
327 gettext_noop ("file with proof of work, otherwise default is used"),
328 &pwfn),
329 GNUNET_GETOPT_OPTION_SET_RELATIVE_TIME ('t',
330 "timeout",
331 "TIME",
332 gettext_noop ("time to wait between calculations"),
333 &proof_find_delay),
325 GNUNET_GETOPT_OPTION_END 334 GNUNET_GETOPT_OPTION_END
326 }; 335 };
327 int ret; 336 int ret;
@@ -334,7 +343,9 @@ main (int argc, char *const *argv)
334 GNUNET_PROGRAM_run (argc, argv, 343 GNUNET_PROGRAM_run (argc, argv,
335 "gnunet-scrypt [OPTIONS] prooffile", 344 "gnunet-scrypt [OPTIONS] prooffile",
336 gettext_noop ("Manipulate GNUnet proof of work files"), 345 gettext_noop ("Manipulate GNUnet proof of work files"),
337 options, &run, NULL)) ? 0 : 1; 346 options,
347 &run,
348 NULL)) ? 0 : 1;
338 GNUNET_free ((void*) argv); 349 GNUNET_free ((void*) argv);
339 GNUNET_free_non_null (pwfn); 350 GNUNET_free_non_null (pwfn);
340 return ret; 351 return ret;
diff --git a/src/util/helper.c b/src/util/helper.c
index cdb1b01d4..a84b06e66 100644
--- a/src/util/helper.c
+++ b/src/util/helper.c
@@ -27,6 +27,7 @@
27 */ 27 */
28#include "platform.h" 28#include "platform.h"
29#include "gnunet_util_lib.h" 29#include "gnunet_util_lib.h"
30#include "gnunet_mst_lib.h"
30 31
31 32
32/** 33/**
@@ -107,7 +108,7 @@ struct GNUNET_HELPER_Handle
107 /** 108 /**
108 * The Message-Tokenizer that tokenizes the messages comming from the helper 109 * The Message-Tokenizer that tokenizes the messages comming from the helper
109 */ 110 */
110 struct GNUNET_SERVER_MessageStreamTokenizer *mst; 111 struct GNUNET_MessageStreamTokenizer *mst;
111 112
112 /** 113 /**
113 * The exception callback 114 * The exception callback
@@ -272,7 +273,10 @@ GNUNET_HELPER_wait (struct GNUNET_HELPER_Handle *h)
272 } 273 }
273 /* purge MST buffer */ 274 /* purge MST buffer */
274 if (NULL != h->mst) 275 if (NULL != h->mst)
275 (void) GNUNET_SERVER_mst_receive (h->mst, NULL, NULL, 0, GNUNET_YES, GNUNET_NO); 276 (void) GNUNET_MST_from_buffer (h->mst,
277 NULL, 0,
278 GNUNET_YES,
279 GNUNET_NO);
276 return ret; 280 return ret;
277} 281}
278 282
@@ -319,7 +323,7 @@ static void
319helper_read (void *cls) 323helper_read (void *cls)
320{ 324{
321 struct GNUNET_HELPER_Handle *h = cls; 325 struct GNUNET_HELPER_Handle *h = cls;
322 char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE] GNUNET_ALIGN; 326 char buf[GNUNET_MAX_MESSAGE_SIZE] GNUNET_ALIGN;
323 ssize_t t; 327 ssize_t t;
324 328
325 h->read_task = NULL; 329 h->read_task = NULL;
@@ -373,10 +377,10 @@ helper_read (void *cls)
373 h->fh_from_helper, 377 h->fh_from_helper,
374 &helper_read, h); 378 &helper_read, h);
375 if (GNUNET_SYSERR == 379 if (GNUNET_SYSERR ==
376 GNUNET_SERVER_mst_receive (h->mst, 380 GNUNET_MST_from_buffer (h->mst,
377 NULL, 381 buf, t,
378 buf, t, 382 GNUNET_NO,
379 GNUNET_NO, GNUNET_NO)) 383 GNUNET_NO))
380 { 384 {
381 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 385 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
382 _("Failed to parse inbound message from helper `%s'\n"), 386 _("Failed to parse inbound message from helper `%s'\n"),
@@ -487,7 +491,7 @@ struct GNUNET_HELPER_Handle *
487GNUNET_HELPER_start (int with_control_pipe, 491GNUNET_HELPER_start (int with_control_pipe,
488 const char *binary_name, 492 const char *binary_name,
489 char *const binary_argv[], 493 char *const binary_argv[],
490 GNUNET_SERVER_MessageTokenizerCallback cb, 494 GNUNET_MessageTokenizerCallback cb,
491 GNUNET_HELPER_ExceptionCallback exp_cb, 495 GNUNET_HELPER_ExceptionCallback exp_cb,
492 void *cb_cls) 496 void *cb_cls)
493{ 497{
@@ -508,7 +512,8 @@ GNUNET_HELPER_start (int with_control_pipe,
508 h->binary_argv[c] = NULL; 512 h->binary_argv[c] = NULL;
509 h->cb_cls = cb_cls; 513 h->cb_cls = cb_cls;
510 if (NULL != cb) 514 if (NULL != cb)
511 h->mst = GNUNET_SERVER_mst_create (cb, h->cb_cls); 515 h->mst = GNUNET_MST_create (cb,
516 h->cb_cls);
512 h->exp_cb = exp_cb; 517 h->exp_cb = exp_cb;
513 h->retry_back_off = 0; 518 h->retry_back_off = 0;
514 start_helper (h); 519 start_helper (h);
@@ -544,7 +549,7 @@ GNUNET_HELPER_destroy (struct GNUNET_HELPER_Handle *h)
544 GNUNET_free (sh); 549 GNUNET_free (sh);
545 } 550 }
546 if (NULL != h->mst) 551 if (NULL != h->mst)
547 GNUNET_SERVER_mst_destroy (h->mst); 552 GNUNET_MST_destroy (h->mst);
548 GNUNET_free (h->binary_name); 553 GNUNET_free (h->binary_name);
549 for (c = 0; h->binary_argv[c] != NULL; c++) 554 for (c = 0; h->binary_argv[c] != NULL; c++)
550 GNUNET_free (h->binary_argv[c]); 555 GNUNET_free (h->binary_argv[c]);
diff --git a/src/util/mq.c b/src/util/mq.c
index 79e2d0455..90b2aa968 100644
--- a/src/util/mq.c
+++ b/src/util/mq.c
@@ -202,24 +202,6 @@ struct GNUNET_MQ_Handle
202 202
203 203
204/** 204/**
205 * Implementation-specific state for connection to
206 * client (MQ for server).
207 */
208struct ServerClientSocketState
209{
210 /**
211 * Handle of the client that connected to the server.
212 */
213 struct GNUNET_SERVER_Client *client;
214
215 /**
216 * Active transmission request to the client.
217 */
218 struct GNUNET_SERVER_TransmitHandle *th;
219};
220
221
222/**
223 * Call the message message handler that was registered 205 * Call the message message handler that was registered
224 * for the type of the given message in the given message queue. 206 * for the type of the given message in the given message queue.
225 * 207 *
@@ -708,92 +690,6 @@ GNUNET_MQ_msg_nested_mh_ (struct GNUNET_MessageHeader **mhp,
708 690
709 691
710/** 692/**
711 * Transmit a queued message to the session's client.
712 *
713 * @param cls consensus session
714 * @param size number of bytes available in @a buf
715 * @param buf where the callee should write the message
716 * @return number of bytes written to @a buf
717 */
718static size_t
719transmit_queued (void *cls,
720 size_t size,
721 void *buf)
722{
723 struct GNUNET_MQ_Handle *mq = cls;
724 struct ServerClientSocketState *state = GNUNET_MQ_impl_state (mq);
725 const struct GNUNET_MessageHeader *msg = GNUNET_MQ_impl_current (mq);
726 size_t msg_size;
727
728 GNUNET_assert (NULL != buf);
729 msg_size = ntohs (msg->size);
730 GNUNET_assert (size >= msg_size);
731 GNUNET_memcpy (buf, msg, msg_size);
732 state->th = NULL;
733
734 GNUNET_MQ_impl_send_continue (mq);
735
736 return msg_size;
737}
738
739
740static void
741server_client_destroy_impl (struct GNUNET_MQ_Handle *mq,
742 void *impl_state)
743{
744 struct ServerClientSocketState *state = impl_state;
745
746 if (NULL != state->th)
747 {
748 GNUNET_SERVER_notify_transmit_ready_cancel (state->th);
749 state->th = NULL;
750 }
751
752 GNUNET_assert (NULL != mq);
753 GNUNET_assert (NULL != state);
754 GNUNET_SERVER_client_drop (state->client);
755 GNUNET_free (state);
756}
757
758
759static void
760server_client_send_impl (struct GNUNET_MQ_Handle *mq,
761 const struct GNUNET_MessageHeader *msg,
762 void *impl_state)
763{
764 GNUNET_assert (NULL != mq);
765
766 LOG (GNUNET_ERROR_TYPE_DEBUG,
767 "Sending message of type %u and size %u\n",
768 ntohs (msg->type), ntohs (msg->size));
769
770 struct ServerClientSocketState *state = impl_state;
771 state->th = GNUNET_SERVER_notify_transmit_ready (state->client,
772 ntohs (msg->size),
773 GNUNET_TIME_UNIT_FOREVER_REL,
774 &transmit_queued,
775 mq);
776}
777
778
779struct GNUNET_MQ_Handle *
780GNUNET_MQ_queue_for_server_client (struct GNUNET_SERVER_Client *client)
781{
782 struct GNUNET_MQ_Handle *mq;
783 struct ServerClientSocketState *scss;
784
785 mq = GNUNET_new (struct GNUNET_MQ_Handle);
786 scss = GNUNET_new (struct ServerClientSocketState);
787 mq->impl_state = scss;
788 scss->client = client;
789 GNUNET_SERVER_client_keep (client);
790 mq->send_impl = &server_client_send_impl;
791 mq->destroy_impl = &server_client_destroy_impl;
792 return mq;
793}
794
795
796/**
797 * Associate the assoc_data in mq with a unique request id. 693 * Associate the assoc_data in mq with a unique request id.
798 * 694 *
799 * @param mq message queue, id will be unique for the queue 695 * @param mq message queue, id will be unique for the queue
@@ -811,22 +707,40 @@ GNUNET_MQ_assoc_add (struct GNUNET_MQ_Handle *mq,
811 mq->assoc_id = 1; 707 mq->assoc_id = 1;
812 } 708 }
813 id = mq->assoc_id++; 709 id = mq->assoc_id++;
814 GNUNET_CONTAINER_multihashmap32_put (mq->assoc_map, id, assoc_data, 710 GNUNET_assert (GNUNET_OK ==
815 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); 711 GNUNET_CONTAINER_multihashmap32_put (mq->assoc_map,
712 id,
713 assoc_data,
714 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
816 return id; 715 return id;
817} 716}
818 717
819 718
719/**
720 * Get the data associated with a @a request_id in a queue
721 *
722 * @param mq the message queue with the association
723 * @param request_id the request id we are interested in
724 * @return the associated data
725 */
820void * 726void *
821GNUNET_MQ_assoc_get (struct GNUNET_MQ_Handle *mq, 727GNUNET_MQ_assoc_get (struct GNUNET_MQ_Handle *mq,
822 uint32_t request_id) 728 uint32_t request_id)
823{ 729{
824 if (NULL == mq->assoc_map) 730 if (NULL == mq->assoc_map)
825 return NULL; 731 return NULL;
826 return GNUNET_CONTAINER_multihashmap32_get (mq->assoc_map, request_id); 732 return GNUNET_CONTAINER_multihashmap32_get (mq->assoc_map,
733 request_id);
827} 734}
828 735
829 736
737/**
738 * Remove the association for a @a request_id
739 *
740 * @param mq the message queue with the association
741 * @param request_id the request id we want to remove
742 * @return the associated data
743 */
830void * 744void *
831GNUNET_MQ_assoc_remove (struct GNUNET_MQ_Handle *mq, 745GNUNET_MQ_assoc_remove (struct GNUNET_MQ_Handle *mq,
832 uint32_t request_id) 746 uint32_t request_id)
diff --git a/src/util/mst.c b/src/util/mst.c
index 9f1d30d7a..0d90c5d10 100644
--- a/src/util/mst.c
+++ b/src/util/mst.c
@@ -90,8 +90,8 @@ GNUNET_MST_create (GNUNET_MessageTokenizerCallback cb,
90 struct GNUNET_MessageStreamTokenizer *ret; 90 struct GNUNET_MessageStreamTokenizer *ret;
91 91
92 ret = GNUNET_new (struct GNUNET_MessageStreamTokenizer); 92 ret = GNUNET_new (struct GNUNET_MessageStreamTokenizer);
93 ret->hdr = GNUNET_malloc (GNUNET_SERVER_MIN_BUFFER_SIZE); 93 ret->hdr = GNUNET_malloc (GNUNET_MIN_MESSAGE_SIZE);
94 ret->curr_buf = GNUNET_SERVER_MIN_BUFFER_SIZE; 94 ret->curr_buf = GNUNET_MIN_MESSAGE_SIZE;
95 ret->cb = cb; 95 ret->cb = cb;
96 ret->cb_cls = cb_cls; 96 ret->cb_cls = cb_cls;
97 return ret; 97 return ret;
diff --git a/src/util/resolver_api.c b/src/util/resolver_api.c
index f33c31f1c..0c915932c 100644
--- a/src/util/resolver_api.c
+++ b/src/util/resolver_api.c
@@ -876,7 +876,7 @@ GNUNET_RESOLVER_ip_get (const char *hostname,
876 876
877 slen = strlen (hostname) + 1; 877 slen = strlen (hostname) + 1;
878 if (slen + sizeof (struct GNUNET_RESOLVER_GetMessage) >= 878 if (slen + sizeof (struct GNUNET_RESOLVER_GetMessage) >=
879 GNUNET_SERVER_MAX_MESSAGE_SIZE) 879 GNUNET_MAX_MESSAGE_SIZE)
880 { 880 {
881 GNUNET_break (0); 881 GNUNET_break (0);
882 return NULL; 882 return NULL;
diff --git a/src/util/server_nc.c b/src/util/server_nc.c
deleted file mode 100644
index a95cd7f6d..000000000
--- a/src/util/server_nc.c
+++ /dev/null
@@ -1,472 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21/**
22 * @file util/server_nc.c
23 * @brief convenience functions for transmission of
24 * a notification stream
25 * @author Christian Grothoff
26 */
27
28#include "platform.h"
29#include "gnunet_util_lib.h"
30
31#define LOG(kind,...) GNUNET_log_from (kind, "util-server-nc", __VA_ARGS__)
32
33
34/**
35 * Entry in list of messages pending to be transmitted.
36 */
37struct PendingMessageList
38{
39
40 /**
41 * This is a doubly-linked list.
42 */
43 struct PendingMessageList *next;
44
45 /**
46 * This is a doubly-linked list.
47 */
48 struct PendingMessageList *prev;
49
50 /**
51 * Message to transmit (allocated at the end of this
52 * struct, do not free)
53 */
54 const struct GNUNET_MessageHeader *msg;
55
56 /**
57 * Can this message be dropped?
58 */
59 int can_drop;
60
61};
62
63
64/**
65 * Lists of clients we manage for notifications.
66 */
67struct ClientList
68{
69
70 /**
71 * This is a doubly linked list.
72 */
73 struct ClientList *next;
74
75 /**
76 * This is a doubly linked list.
77 */
78 struct ClientList *prev;
79
80 /**
81 * Overall context this client belongs to.
82 */
83 struct GNUNET_SERVER_NotificationContext *nc;
84
85 /**
86 * Handle to the client.
87 */
88 struct GNUNET_SERVER_Client *client;
89
90 /**
91 * Handle for pending transmission request to the client (or NULL).
92 */
93 struct GNUNET_SERVER_TransmitHandle *th;
94
95 /**
96 * Head of linked list of requests queued for transmission.
97 */
98 struct PendingMessageList *pending_head;
99
100 /**
101 * Tail of linked list of requests queued for transmission.
102 */
103 struct PendingMessageList *pending_tail;
104
105 /**
106 * Number of messages currently in the list.
107 */
108 unsigned int num_pending;
109
110};
111
112
113/**
114 * The notification context is the key datastructure for a convenience
115 * API used for transmission of notifications to the client until the
116 * client disconnects (or the notification context is destroyed, in
117 * which case we disconnect these clients). Essentially, all
118 * (notification) messages are queued up until the client is able to
119 * read them.
120 */
121struct GNUNET_SERVER_NotificationContext
122{
123
124 /**
125 * Server we do notifications for.
126 */
127 struct GNUNET_SERVER_Handle *server;
128
129 /**
130 * Head of list of clients receiving notifications.
131 */
132 struct ClientList *clients_head;
133
134 /**
135 * Tail of list of clients receiving notifications.
136 */
137 struct ClientList *clients_tail;
138
139 /**
140 * Maximum number of optional messages to queue per client.
141 */
142 unsigned int queue_length;
143
144};
145
146
147/**
148 * Client has disconnected, clean up.
149 *
150 * @param cls our `struct GNUNET_SERVER_NotificationContext *`
151 * @param client handle of client that disconnected
152 */
153static void
154handle_client_disconnect (void *cls,
155 struct GNUNET_SERVER_Client *client)
156{
157 struct GNUNET_SERVER_NotificationContext *nc = cls;
158 struct ClientList *pos;
159 struct PendingMessageList *pml;
160
161 if (NULL == client)
162 {
163 nc->server = NULL;
164 return;
165 }
166 for (pos = nc->clients_head; NULL != pos; pos = pos->next)
167 if (pos->client == client)
168 break;
169 if (NULL == pos)
170 return;
171 LOG (GNUNET_ERROR_TYPE_DEBUG,
172 "Client disconnected, cleaning up %u messages in NC queue\n",
173 pos->num_pending);
174 GNUNET_CONTAINER_DLL_remove (nc->clients_head,
175 nc->clients_tail,
176 pos);
177 while (NULL != (pml = pos->pending_head))
178 {
179 GNUNET_CONTAINER_DLL_remove (pos->pending_head,
180 pos->pending_tail,
181 pml);
182 GNUNET_free (pml);
183 pos->num_pending--;
184 }
185 if (NULL != pos->th)
186 {
187 GNUNET_SERVER_notify_transmit_ready_cancel (pos->th);
188 pos->th = NULL;
189 }
190 GNUNET_SERVER_client_drop (client);
191 GNUNET_assert (0 == pos->num_pending);
192 GNUNET_free (pos);
193}
194
195
196/**
197 * Create a new notification context.
198 *
199 * @param server server for which this function creates the context
200 * @param queue_length maximum number of messages to keep in
201 * the notification queue; optional messages are dropped
202 * if the queue gets longer than this number of messages
203 * @return handle to the notification context
204 */
205struct GNUNET_SERVER_NotificationContext *
206GNUNET_SERVER_notification_context_create (struct GNUNET_SERVER_Handle *server,
207 unsigned int queue_length)
208{
209 struct GNUNET_SERVER_NotificationContext *ret;
210
211 ret = GNUNET_new (struct GNUNET_SERVER_NotificationContext);
212 ret->server = server;
213 ret->queue_length = queue_length;
214 GNUNET_SERVER_disconnect_notify (server,
215 &handle_client_disconnect,
216 ret);
217 return ret;
218}
219
220
221/**
222 * Destroy the context, force disconnect for all clients.
223 *
224 * @param nc context to destroy.
225 */
226void
227GNUNET_SERVER_notification_context_destroy (struct GNUNET_SERVER_NotificationContext *nc)
228{
229 struct ClientList *pos;
230 struct PendingMessageList *pml;
231
232 while (NULL != (pos = nc->clients_head))
233 {
234 GNUNET_CONTAINER_DLL_remove (nc->clients_head,
235 nc->clients_tail,
236 pos);
237 if (NULL != pos->th)
238 {
239 GNUNET_SERVER_notify_transmit_ready_cancel (pos->th);
240 pos->th = NULL;
241 }
242 GNUNET_SERVER_client_drop (pos->client);
243 while (NULL != (pml = pos->pending_head))
244 {
245 GNUNET_CONTAINER_DLL_remove (pos->pending_head,
246 pos->pending_tail,
247 pml);
248 GNUNET_free (pml);
249 pos->num_pending--;
250 }
251 GNUNET_assert (0 == pos->num_pending);
252 GNUNET_free (pos);
253 }
254 if (NULL != nc->server)
255 GNUNET_SERVER_disconnect_notify_cancel (nc->server,
256 &handle_client_disconnect,
257 nc);
258 GNUNET_free (nc);
259}
260
261
262/**
263 * Add a client to the notification context.
264 *
265 * @param nc context to modify
266 * @param client client to add
267 */
268void
269GNUNET_SERVER_notification_context_add (struct GNUNET_SERVER_NotificationContext *nc,
270 struct GNUNET_SERVER_Client *client)
271{
272 struct ClientList *cl;
273
274 for (cl = nc->clients_head; NULL != cl; cl = cl->next)
275 if (cl->client == client)
276 return; /* already present */
277 cl = GNUNET_new (struct ClientList);
278 GNUNET_CONTAINER_DLL_insert (nc->clients_head,
279 nc->clients_tail,
280 cl);
281 cl->nc = nc;
282 cl->client = client;
283 GNUNET_SERVER_client_keep (client);
284}
285
286
287/**
288 * Function called to notify a client about the socket begin ready to
289 * queue more data. @a buf will be NULL and @a size zero if the socket
290 * was closed for writing in the meantime.
291 *
292 * @param cls the `struct ClientList *`
293 * @param size number of bytes available in @a buf
294 * @param buf where the callee should write the message
295 * @return number of bytes written to buf
296 */
297static size_t
298transmit_message (void *cls,
299 size_t size,
300 void *buf)
301{
302 struct ClientList *cl = cls;
303 char *cbuf = buf;
304 struct PendingMessageList *pml;
305 uint16_t msize;
306 size_t ret;
307
308 cl->th = NULL;
309 if (NULL == buf)
310 {
311 /* 'cl' should be freed via disconnect notification shortly */
312 LOG (GNUNET_ERROR_TYPE_DEBUG,
313 "Failed to transmit message from NC queue to client\n");
314 return 0;
315 }
316 ret = 0;
317 while (NULL != (pml = cl->pending_head))
318 {
319 msize = ntohs (pml->msg->size);
320 if (size < msize)
321 break;
322 GNUNET_CONTAINER_DLL_remove (cl->pending_head,
323 cl->pending_tail,
324 pml);
325 LOG (GNUNET_ERROR_TYPE_DEBUG,
326 "Copying message of type %u and size %u from pending queue to transmission buffer\n",
327 ntohs (pml->msg->type),
328 msize);
329 GNUNET_memcpy (&cbuf[ret], pml->msg, msize);
330 ret += msize;
331 size -= msize;
332 GNUNET_free (pml);
333 cl->num_pending--;
334 }
335 if (NULL != pml)
336 {
337 LOG (GNUNET_ERROR_TYPE_DEBUG,
338 "Have %u messages left in NC queue, will try transmission again\n",
339 cl->num_pending);
340 cl->th =
341 GNUNET_SERVER_notify_transmit_ready (cl->client,
342 ntohs (pml->msg->size),
343 GNUNET_TIME_UNIT_FOREVER_REL,
344 &transmit_message, cl);
345 }
346 else
347 {
348 GNUNET_assert (0 == cl->num_pending);
349 }
350 return ret;
351}
352
353
354/**
355 * Send a message to a particular client.
356 *
357 * @param nc context to modify
358 * @param client client to transmit to
359 * @param msg message to send
360 * @param can_drop can this message be dropped due to queue length limitations
361 */
362static void
363do_unicast (struct GNUNET_SERVER_NotificationContext *nc,
364 struct ClientList *client,
365 const struct GNUNET_MessageHeader *msg,
366 int can_drop)
367{
368 struct PendingMessageList *pml;
369 uint16_t size;
370
371 if ( (client->num_pending > nc->queue_length) &&
372 (GNUNET_YES == can_drop) )
373 {
374 LOG (GNUNET_ERROR_TYPE_INFO,
375 "Dropping message of type %u and size %u due to full queue (%u entries)\n",
376 ntohs (msg->type), ntohs (msg->size), (unsigned int) nc->queue_length);
377 return; /* drop! */
378 }
379 if (client->num_pending > nc->queue_length)
380 {
381 /* FIXME: consider checking for other messages in the
382 * queue that are 'droppable' */
383 }
384 client->num_pending++;
385 size = ntohs (msg->size);
386 pml = GNUNET_malloc (sizeof (struct PendingMessageList) + size);
387 pml->msg = (const struct GNUNET_MessageHeader *) &pml[1];
388 pml->can_drop = can_drop;
389 LOG (GNUNET_ERROR_TYPE_DEBUG,
390 "Adding message of type %u and size %u to pending queue (which has %u entries)\n",
391 ntohs (msg->type),
392 ntohs (msg->size),
393 (unsigned int) nc->queue_length);
394 GNUNET_memcpy (&pml[1], msg, size);
395 /* append */
396 GNUNET_CONTAINER_DLL_insert_tail (client->pending_head,
397 client->pending_tail,
398 pml);
399 if (NULL == client->th)
400 client->th =
401 GNUNET_SERVER_notify_transmit_ready (client->client,
402 ntohs (client->pending_head->
403 msg->size),
404 GNUNET_TIME_UNIT_FOREVER_REL,
405 &transmit_message, client);
406}
407
408
409/**
410 * Send a message to a particular client; must have
411 * already been added to the notification context.
412 *
413 * @param nc context to modify
414 * @param client client to transmit to
415 * @param msg message to send
416 * @param can_drop can this message be dropped due to queue length limitations
417 */
418void
419GNUNET_SERVER_notification_context_unicast (struct GNUNET_SERVER_NotificationContext *nc,
420 struct GNUNET_SERVER_Client *client,
421 const struct GNUNET_MessageHeader *msg,
422 int can_drop)
423{
424 struct ClientList *pos;
425
426 for (pos = nc->clients_head; NULL != pos; pos = pos->next)
427 if (pos->client == client)
428 break;
429 GNUNET_assert (NULL != pos);
430 do_unicast (nc, pos, msg, can_drop);
431}
432
433
434/**
435 * Send a message to all clients of this context.
436 *
437 * @param nc context to modify
438 * @param msg message to send
439 * @param can_drop can this message be dropped due to queue length limitations
440 */
441void
442GNUNET_SERVER_notification_context_broadcast (struct
443 GNUNET_SERVER_NotificationContext *nc,
444 const struct GNUNET_MessageHeader *msg,
445 int can_drop)
446{
447 struct ClientList *pos;
448
449 for (pos = nc->clients_head; NULL != pos; pos = pos->next)
450 do_unicast (nc, pos, msg, can_drop);
451}
452
453
454/**
455 * Return active number of subscribers in this context.
456 *
457 * @param nc context to query
458 * @return number of current subscribers
459 */
460unsigned int
461GNUNET_SERVER_notification_context_get_size (struct GNUNET_SERVER_NotificationContext *nc)
462{
463 unsigned int num;
464 struct ClientList *pos;
465
466 num = 0;
467 for (pos = nc->clients_head; NULL != pos; pos = pos->next)
468 num++;
469 return num;
470}
471
472/* end of server_nc.c */
diff --git a/src/util/server_tc.c b/src/util/server_tc.c
deleted file mode 100644
index 8ae380a85..000000000
--- a/src/util/server_tc.c
+++ /dev/null
@@ -1,242 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21/**
22 * @file util/server_tc.c
23 * @brief convenience functions for transmission of
24 * complex responses as a server
25 * @author Christian Grothoff
26 */
27
28#include "platform.h"
29#include "gnunet_util_lib.h"
30
31
32#define LOG(kind,...) GNUNET_log_from (kind, "util-server-tc", __VA_ARGS__)
33
34
35/**
36 * How much buffer space do we want to have at least
37 * before transmitting another increment?
38 */
39#define MIN_BLOCK_SIZE 128
40
41
42
43struct GNUNET_SERVER_TransmitContext
44{
45 /**
46 * Which client are we transmitting to?
47 */
48 struct GNUNET_SERVER_Client *client;
49
50 /**
51 * Transmission buffer. (current offset for writing).
52 */
53 char *buf;
54
55 /**
56 * Number of bytes in buf.
57 */
58 size_t total;
59
60 /**
61 * Offset for writing in buf.
62 */
63 size_t off;
64
65 /**
66 * Timeout for this request.
67 */
68 struct GNUNET_TIME_Absolute timeout;
69};
70
71
72/**
73 * Helper function for incremental transmission of the response.
74 */
75static size_t
76transmit_response (void *cls, size_t size, void *buf)
77{
78 struct GNUNET_SERVER_TransmitContext *tc = cls;
79 size_t msize;
80
81 if (NULL == buf)
82 {
83 GNUNET_SERVER_transmit_context_destroy (tc, GNUNET_SYSERR);
84 return 0;
85 }
86 if (tc->total - tc->off > size)
87 msize = size;
88 else
89 msize = tc->total - tc->off;
90 GNUNET_memcpy (buf, &tc->buf[tc->off], msize);
91 tc->off += msize;
92 if (tc->total == tc->off)
93 {
94 GNUNET_SERVER_receive_done (tc->client, GNUNET_OK);
95 GNUNET_SERVER_client_drop (tc->client);
96 GNUNET_free_non_null (tc->buf);
97 GNUNET_free (tc);
98 }
99 else
100 {
101 if (NULL ==
102 GNUNET_SERVER_notify_transmit_ready (tc->client,
103 GNUNET_MIN (MIN_BLOCK_SIZE,
104 tc->total - tc->off),
105 GNUNET_TIME_absolute_get_remaining
106 (tc->timeout), &transmit_response,
107 tc))
108 {
109 GNUNET_break (0);
110 GNUNET_SERVER_transmit_context_destroy (tc, GNUNET_SYSERR);
111 }
112 }
113 return msize;
114}
115
116
117/**
118 * Create a new transmission context for the
119 * given client.
120 *
121 * @param client client to create the context for.
122 * @return NULL on error
123 */
124struct GNUNET_SERVER_TransmitContext *
125GNUNET_SERVER_transmit_context_create (struct GNUNET_SERVER_Client *client)
126{
127 struct GNUNET_SERVER_TransmitContext *tc;
128
129 GNUNET_assert (NULL != client);
130 tc = GNUNET_new (struct GNUNET_SERVER_TransmitContext);
131 GNUNET_SERVER_client_keep (client);
132 tc->client = client;
133 return tc;
134}
135
136
137/**
138 * Append a message to the transmission context.
139 * All messages in the context will be sent by
140 * the transmit_context_run method.
141 *
142 * @param tc context to use
143 * @param data what to append to the result message
144 * @param length length of data
145 * @param type type of the message
146 */
147void
148GNUNET_SERVER_transmit_context_append_data (struct GNUNET_SERVER_TransmitContext
149 *tc, const void *data,
150 size_t length, uint16_t type)
151{
152 struct GNUNET_MessageHeader *msg;
153 size_t size;
154
155 GNUNET_assert (length < GNUNET_SERVER_MAX_MESSAGE_SIZE);
156 size = length + sizeof (struct GNUNET_MessageHeader);
157 GNUNET_assert (size > length);
158 tc->buf = GNUNET_realloc (tc->buf, tc->total + size);
159 msg = (struct GNUNET_MessageHeader *) &tc->buf[tc->total];
160 tc->total += size;
161 msg->size = htons (size);
162 msg->type = htons (type);
163 GNUNET_memcpy (&msg[1], data, length);
164}
165
166
167/**
168 * Append a message to the transmission context.
169 * All messages in the context will be sent by
170 * the transmit_context_run method.
171 *
172 * @param tc context to use
173 * @param msg message to append
174 */
175void
176GNUNET_SERVER_transmit_context_append_message (struct
177 GNUNET_SERVER_TransmitContext
178 *tc,
179 const struct GNUNET_MessageHeader
180 *msg)
181{
182 struct GNUNET_MessageHeader *m;
183 uint16_t size;
184
185 size = ntohs (msg->size);
186 tc->buf = GNUNET_realloc (tc->buf, tc->total + size);
187 m = (struct GNUNET_MessageHeader *) &tc->buf[tc->total];
188 tc->total += size;
189 GNUNET_memcpy (m, msg, size);
190}
191
192
193/**
194 * Execute a transmission context. If there is
195 * an error in the transmission, the #GNUNET_SERVER_receive_done()
196 * method will be called with an error code (#GNUNET_SYSERR),
197 * otherwise with #GNUNET_OK.
198 *
199 * @param tc transmission context to use
200 * @param timeout when to time out and abort the transmission
201 */
202void
203GNUNET_SERVER_transmit_context_run (struct GNUNET_SERVER_TransmitContext *tc,
204 struct GNUNET_TIME_Relative timeout)
205{
206 tc->timeout = GNUNET_TIME_relative_to_absolute (timeout);
207 if (NULL ==
208 GNUNET_SERVER_notify_transmit_ready (tc->client,
209 GNUNET_MIN (MIN_BLOCK_SIZE,
210 tc->total), timeout,
211 &transmit_response, tc))
212 {
213 GNUNET_break (0);
214 GNUNET_SERVER_transmit_context_destroy (tc, GNUNET_SYSERR);
215 }
216}
217
218
219/**
220 * Destroy a transmission context. This function must not be called
221 * after 'GNUNET_SERVER_transmit_context_run'.
222 *
223 * @param tc transmission context to destroy
224 * @param success code to give to 'GNUNET_SERVER_receive_done' for
225 * the client: GNUNET_OK to keep the connection open and
226 * continue to receive
227 * GNUNET_NO to close the connection (normal behavior)
228 * GNUNET_SYSERR to close the connection (signal
229 * serious error)
230 */
231void
232GNUNET_SERVER_transmit_context_destroy (struct GNUNET_SERVER_TransmitContext
233 *tc, int success)
234{
235 GNUNET_SERVER_receive_done (tc->client, success);
236 GNUNET_SERVER_client_drop (tc->client);
237 GNUNET_free_non_null (tc->buf);
238 GNUNET_free (tc);
239}
240
241
242/* end of server_tc.c */
diff --git a/src/util/service.c b/src/util/service.c
index 496904fb1..800d09a42 100644
--- a/src/util/service.c
+++ b/src/util/service.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 Copyright (C) 2009, 2012 GNUnet e.V. 3 Copyright (C) 2016 GNUnet e.V.
4 4
5 GNUnet is free software; you can redistribute it and/or modify 5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published 6 it under the terms of the GNU General Public License as published
@@ -19,9 +19,10 @@
19*/ 19*/
20 20
21/** 21/**
22 * @file util/service.c 22 * @file util/service_new.c
23 * @brief functions related to starting services 23 * @brief functions related to starting services (redesign)
24 * @author Christian Grothoff 24 * @author Christian Grothoff
25 * @author Florian Dold
25 */ 26 */
26#include "platform.h" 27#include "platform.h"
27#include "gnunet_util_lib.h" 28#include "gnunet_util_lib.h"
@@ -43,77 +44,44 @@
43#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util-service", syscall, filename) 44#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util-service", syscall, filename)
44 45
45 46
46/* ******************* access control ******************** */
47
48/** 47/**
49 * Check if the given IP address is in the list of IP addresses. 48 * Information the service tracks per listen operation.
50 *
51 * @param list a list of networks
52 * @param add the IP to check (in network byte order)
53 * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is
54 */ 49 */
55static int 50struct ServiceListenContext
56check_ipv4_listed (const struct GNUNET_STRINGS_IPv4NetworkPolicy *list,
57 const struct in_addr *add)
58{ 51{
59 unsigned int i;
60 52
61 if (NULL == list) 53 /**
62 return GNUNET_NO; 54 * Kept in a DLL.
63 i = 0; 55 */
64 while ((list[i].network.s_addr != 0) || (list[i].netmask.s_addr != 0)) 56 struct ServiceListenContext *next;
65 {
66 if ((add->s_addr & list[i].netmask.s_addr) ==
67 (list[i].network.s_addr & list[i].netmask.s_addr))
68 return GNUNET_YES;
69 i++;
70 }
71 return GNUNET_NO;
72}
73 57
58 /**
59 * Kept in a DLL.
60 */
61 struct ServiceListenContext *prev;
74 62
75/** 63 /**
76 * Check if the given IP address is in the list of IP addresses. 64 * Service this listen context belongs to.
77 * 65 */
78 * @param list a list of networks 66 struct GNUNET_SERVICE_Handle *sh;
79 * @param ip the IP to check (in network byte order)
80 * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is
81 */
82static int
83check_ipv6_listed (const struct GNUNET_STRINGS_IPv6NetworkPolicy *list,
84 const struct in6_addr *ip)
85{
86 unsigned int i;
87 unsigned int j;
88 struct in6_addr zero;
89 67
90 if (NULL == list) 68 /**
91 return GNUNET_NO; 69 * Socket we are listening on.
92 memset (&zero, 0, sizeof (struct in6_addr)); 70 */
93 i = 0; 71 struct GNUNET_NETWORK_Handle *listen_socket;
94NEXT:
95 while (0 != memcmp (&zero, &list[i].network, sizeof (struct in6_addr)))
96 {
97 for (j = 0; j < sizeof (struct in6_addr) / sizeof (int); j++)
98 if (((((int *) ip)[j] & ((int *) &list[i].netmask)[j])) !=
99 (((int *) &list[i].network)[j] & ((int *) &list[i].netmask)[j]))
100 {
101 i++;
102 goto NEXT;
103 }
104 return GNUNET_YES;
105 }
106 return GNUNET_NO;
107}
108 72
73 /**
74 * Task scheduled to do the listening.
75 */
76 struct GNUNET_SCHEDULER_Task *listen_task;
109 77
110/* ****************** service struct ****************** */ 78};
111 79
112 80
113/** 81/**
114 * Context for "service_task". 82 * Handle to a service.
115 */ 83 */
116struct GNUNET_SERVICE_Context 84struct GNUNET_SERVICE_Handle
117{ 85{
118 /** 86 /**
119 * Our configuration. 87 * Our configuration.
@@ -121,25 +89,54 @@ struct GNUNET_SERVICE_Context
121 const struct GNUNET_CONFIGURATION_Handle *cfg; 89 const struct GNUNET_CONFIGURATION_Handle *cfg;
122 90
123 /** 91 /**
124 * Handle for the server. 92 * Name of our service.
125 */ 93 */
126 struct GNUNET_SERVER_Handle *server; 94 const char *service_name;
127 95
128 /** 96 /**
129 * NULL-terminated array of addresses to bind to, NULL if we got pre-bound 97 * Main service-specific task to run.
130 * listen sockets.
131 */ 98 */
132 struct sockaddr **addrs; 99 GNUNET_SERVICE_InitCallback service_init_cb;
133 100
134 /** 101 /**
135 * Name of our service. 102 * Function to call when clients connect.
136 */ 103 */
137 const char *service_name; 104 GNUNET_SERVICE_ConnectHandler connect_cb;
138 105
139 /** 106 /**
140 * Main service-specific task to run. 107 * Function to call when clients disconnect / are disconnected.
141 */ 108 */
142 GNUNET_SERVICE_Main task; 109 GNUNET_SERVICE_DisconnectHandler disconnect_cb;
110
111 /**
112 * Closure for @e service_init_cb, @e connect_cb, @e disconnect_cb.
113 */
114 void *cb_cls;
115
116 /**
117 * DLL of listen sockets used to accept new connections.
118 */
119 struct ServiceListenContext *slc_head;
120
121 /**
122 * DLL of listen sockets used to accept new connections.
123 */
124 struct ServiceListenContext *slc_tail;
125
126 /**
127 * Our clients, kept in a DLL.
128 */
129 struct GNUNET_SERVICE_Client *clients_head;
130
131 /**
132 * Our clients, kept in a DLL.
133 */
134 struct GNUNET_SERVICE_Client *clients_tail;
135
136 /**
137 * Message handlers to use for all clients.
138 */
139 struct GNUNET_MQ_MessageHandler *handlers;
143 140
144 /** 141 /**
145 * Closure for @e task. 142 * Closure for @e task.
@@ -169,30 +166,38 @@ struct GNUNET_SERVICE_Context
169 struct GNUNET_STRINGS_IPv6NetworkPolicy *v6_allowed; 166 struct GNUNET_STRINGS_IPv6NetworkPolicy *v6_allowed;
170 167
171 /** 168 /**
172 * My (default) message handlers. Adjusted copy 169 * Do we require a matching UID for UNIX domain socket connections?
173 * of "defhandlers". 170 * #GNUNET_NO means that the UID does not have to match (however,
171 * @e match_gid may still impose other access control checks).
174 */ 172 */
175 struct GNUNET_SERVER_MessageHandler *my_handlers; 173 int match_uid;
176 174
177 /** 175 /**
178 * Array of the lengths of the entries in addrs. 176 * Do we require a matching GID for UNIX domain socket connections?
177 * Ignored if @e match_uid is #GNUNET_YES. Note that this is about
178 * checking that the client's UID is in our group OR that the
179 * client's GID is our GID. If both "match_gid" and @e match_uid are
180 * #GNUNET_NO, all users on the local system have access.
179 */ 181 */
180 socklen_t *addrlens; 182 int match_gid;
181 183
182 /** 184 /**
183 * NULL-terminated array of listen sockets we should take over. 185 * Set to #GNUNET_YES if we got a shutdown signal and terminate
186 * the service if #have_non_monitor_clients() returns #GNUNET_YES.
184 */ 187 */
185 struct GNUNET_NETWORK_Handle **lsocks; 188 int got_shutdown;
186 189
187 /** 190 /**
188 * Task ID of the shutdown task. 191 * Our options.
189 */ 192 */
190 struct GNUNET_SCHEDULER_Task *shutdown_task; 193 enum GNUNET_SERVICE_Options options;
191 194
192 /** 195 /**
193 * Idle timeout for server. 196 * If we are daemonizing, this FD is set to the
197 * pipe to the parent. Send '.' if we started
198 * ok, '!' if not. -1 if we are not daemonizing.
194 */ 199 */
195 struct GNUNET_TIME_Relative timeout; 200 int ready_confirm_fd;
196 201
197 /** 202 /**
198 * Overall success/failure of the service start. 203 * Overall success/failure of the service start.
@@ -200,182 +205,203 @@ struct GNUNET_SERVICE_Context
200 int ret; 205 int ret;
201 206
202 /** 207 /**
203 * If we are daemonizing, this FD is set to the 208 * If #GNUNET_YES, consider unknown message types an error where the
204 * pipe to the parent. Send '.' if we started 209 * client is disconnected.
205 * ok, '!' if not. -1 if we are not daemonizing.
206 */ 210 */
207 int ready_confirm_fd; 211 int require_found;
212};
213
214
215/**
216 * Handle to a client that is connected to a service.
217 */
218struct GNUNET_SERVICE_Client
219{
208 220
209 /** 221 /**
210 * Do we close connections if we receive messages 222 * Kept in a DLL.
211 * for which we have no handler?
212 */ 223 */
213 int require_found; 224 struct GNUNET_SERVICE_Client *next;
214 225
215 /** 226 /**
216 * Do we require a matching UID for UNIX domain socket connections? 227 * Kept in a DLL.
217 * #GNUNET_NO means that the UID does not have to match (however,
218 * @e match_gid may still impose other access control checks).
219 */ 228 */
220 int match_uid; 229 struct GNUNET_SERVICE_Client *prev;
221 230
222 /** 231 /**
223 * Do we require a matching GID for UNIX domain socket connections? 232 * Service that this client belongs to.
224 * Ignored if @e match_uid is #GNUNET_YES. Note that this is about
225 * checking that the client's UID is in our group OR that the
226 * client's GID is our GID. If both "match_gid" and @e match_uid are
227 * #GNUNET_NO, all users on the local system have access.
228 */ 233 */
229 int match_gid; 234 struct GNUNET_SERVICE_Handle *sh;
230 235
231 /** 236 /**
232 * Our options. 237 * Socket of this client.
233 */ 238 */
234 enum GNUNET_SERVICE_Options options; 239 struct GNUNET_NETWORK_Handle *sock;
235 240
236}; 241 /**
242 * Message queue for the client.
243 */
244 struct GNUNET_MQ_Handle *mq;
245
246 /**
247 * Tokenizer we use for processing incoming data.
248 */
249 struct GNUNET_MessageStreamTokenizer *mst;
250
251 /**
252 * Task that warns about missing calls to
253 * #GNUNET_SERVICE_client_continue().
254 */
255 struct GNUNET_SCHEDULER_Task *warn_task;
237 256
257 /**
258 * Task run to finish dropping the client after the stack has
259 * properly unwound.
260 */
261 struct GNUNET_SCHEDULER_Task *drop_task;
262
263 /**
264 * Task that receives data from the client to
265 * pass it to the handlers.
266 */
267 struct GNUNET_SCHEDULER_Task *recv_task;
268
269 /**
270 * Task that transmit data to the client.
271 */
272 struct GNUNET_SCHEDULER_Task *send_task;
273
274 /**
275 * Pointer to the message to be transmitted by @e send_task.
276 */
277 const struct GNUNET_MessageHeader *msg;
278
279 /**
280 * User context value, value returned from
281 * the connect callback.
282 */
283 void *user_context;
284
285 /**
286 * Time when we last gave a message from this client
287 * to the application.
288 */
289 struct GNUNET_TIME_Absolute warn_start;
290
291 /**
292 * Current position in @e msg at which we are transmitting.
293 */
294 size_t msg_pos;
295
296 /**
297 * Persist the file handle for this client no matter what happens,
298 * force the OS to close once the process actually dies. Should only
299 * be used in special cases!
300 */
301 int persist;
302
303 /**
304 * Is this client a 'monitor' client that should not be counted
305 * when deciding on destroying the server during soft shutdown?
306 * (see also #GNUNET_SERVICE_start)
307 */
308 int is_monitor;
309
310 /**
311 * Are we waiting for the application to call #GNUNET_SERVICE_client_continue()?
312 */
313 int needs_continue;
314
315 /**
316 * Type of last message processed (for warn_no_receive_done).
317 */
318 uint16_t warn_type;
319};
238 320
239/* ****************** message handlers ****************** */
240 321
241/** 322/**
242 * Send a 'TEST' message back to the client. 323 * Check if any of the clients we have left are unrelated to
324 * monitoring.
243 * 325 *
244 * @param cls the 'struct GNUNET_SERVER_Client' to send TEST to 326 * @param sh service to check clients for
245 * @param size number of bytes available in 'buf' 327 * @return #GNUNET_YES if we have non-monitoring clients left
246 * @param buf where to copy the message
247 * @return number of bytes written to 'buf'
248 */ 328 */
249static size_t 329static int
250write_test (void *cls, size_t size, void *buf) 330have_non_monitor_clients (struct GNUNET_SERVICE_Handle *sh)
251{ 331{
252 struct GNUNET_SERVER_Client *client = cls; 332 struct GNUNET_SERVICE_Client *client;
253 struct GNUNET_MessageHeader *msg;
254 333
255 if (size < sizeof (struct GNUNET_MessageHeader)) 334 for (client = sh->clients_head;NULL != client; client = client->next)
256 { 335 {
257 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); 336 if (client->is_monitor)
258 return 0; /* client disconnected */ 337 continue;
338 return GNUNET_YES;
259 } 339 }
260 msg = (struct GNUNET_MessageHeader *) buf; 340 return GNUNET_NO;
261 msg->type = htons (GNUNET_MESSAGE_TYPE_TEST);
262 msg->size = htons (sizeof (struct GNUNET_MessageHeader));
263 GNUNET_SERVER_receive_done (client, GNUNET_OK);
264 return sizeof (struct GNUNET_MessageHeader);
265} 341}
266 342
267 343
268/** 344/**
269 * Handler for TEST message. 345 * Shutdown task triggered when a service should be terminated.
346 * This considers active clients and the service options to see
347 * how this specific service is to be terminated, and depending
348 * on this proceeds with the shutdown logic.
270 * 349 *
271 * @param cls closure (refers to service) 350 * @param cls our `struct GNUNET_SERVICE_Handle`
272 * @param client identification of the client
273 * @param message the actual message
274 */ 351 */
275static void 352static void
276handle_test (void *cls, struct GNUNET_SERVER_Client *client, 353service_shutdown (void *cls)
277 const struct GNUNET_MessageHeader *message)
278{ 354{
279 /* simply bounce message back to acknowledge */ 355 struct GNUNET_SERVICE_Handle *sh = cls;
280 if (NULL ==
281 GNUNET_SERVER_notify_transmit_ready (client,
282 sizeof (struct GNUNET_MessageHeader),
283 GNUNET_TIME_UNIT_FOREVER_REL,
284 &write_test, client))
285 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
286}
287
288
289/**
290 * Default handlers for all services. Will be copied and the
291 * "callback_cls" fields will be replaced with the specific service
292 * struct.
293 */
294static const struct GNUNET_SERVER_MessageHandler defhandlers[] = {
295 {&handle_test, NULL, GNUNET_MESSAGE_TYPE_TEST,
296 sizeof (struct GNUNET_MessageHeader)},
297 {NULL, NULL, 0, 0}
298};
299
300
301/* ****************** service core routines ************** */
302 356
303 357 switch (sh->options)
304/**
305 * Check if access to the service is allowed from the given address.
306 *
307 * @param cls closure
308 * @param uc credentials, if available, otherwise NULL
309 * @param addr address
310 * @param addrlen length of address
311 * @return #GNUNET_YES to allow, #GNUNET_NO to deny, #GNUNET_SYSERR
312 * for unknown address family (will be denied).
313 */
314static int
315check_access (void *cls, const struct GNUNET_CONNECTION_Credentials *uc,
316 const struct sockaddr *addr, socklen_t addrlen)
317{
318 struct GNUNET_SERVICE_Context *sctx = cls;
319 const struct sockaddr_in *i4;
320 const struct sockaddr_in6 *i6;
321 int ret;
322
323 switch (addr->sa_family)
324 { 358 {
325 case AF_INET: 359 case GNUNET_SERVICE_OPTION_NONE:
326 GNUNET_assert (addrlen == sizeof (struct sockaddr_in)); 360 GNUNET_SERVICE_shutdown (sh);
327 i4 = (const struct sockaddr_in *) addr;
328 ret = ((NULL == sctx->v4_allowed) ||
329 (check_ipv4_listed (sctx->v4_allowed, &i4->sin_addr))) &&
330 ((NULL == sctx->v4_denied) ||
331 (!check_ipv4_listed (sctx->v4_denied, &i4->sin_addr)));
332 break; 361 break;
333 case AF_INET6: 362 case GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN:
334 GNUNET_assert (addrlen == sizeof (struct sockaddr_in6)); 363 /* This task should never be run if we are using
335 i6 = (const struct sockaddr_in6 *) addr; 364 the manual shutdown. */
336 ret = ((NULL == sctx->v6_allowed) || 365 GNUNET_assert (0);
337 (check_ipv6_listed (sctx->v6_allowed, &i6->sin6_addr))) &&
338 ((NULL == sctx->v6_denied) ||
339 (!check_ipv6_listed (sctx->v6_denied, &i6->sin6_addr)));
340 break; 366 break;
341#ifndef WINDOWS 367 case GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN:
342 case AF_UNIX: 368 sh->got_shutdown = GNUNET_YES;
343 ret = GNUNET_OK; /* controlled using file-system ACL now */ 369 GNUNET_SERVICE_suspend (sh);
370 if (GNUNET_NO == have_non_monitor_clients (sh))
371 GNUNET_SERVICE_shutdown (sh);
344 break; 372 break;
345#endif
346 default:
347 LOG (GNUNET_ERROR_TYPE_WARNING, _("Unknown address family %d\n"),
348 addr->sa_family);
349 return GNUNET_SYSERR;
350 }
351 if (GNUNET_OK != ret)
352 {
353 LOG (GNUNET_ERROR_TYPE_WARNING,
354 _("Access from `%s' denied to service `%s'\n"),
355 GNUNET_a2s (addr, addrlen),
356 sctx->service_name);
357 } 373 }
358 return ret;
359} 374}
360 375
361 376
362/** 377/**
363 * Get the name of the file where we will 378 * First task run by any service. Initializes our shutdown task,
364 * write the PID of the service. 379 * starts the listening operation on our listen sockets and launches
380 * the custom logic of the application service.
365 * 381 *
366 * @param sctx service context 382 * @param cls our `struct GNUNET_SERVICE_Handle`
367 * @return name of the file for the process ID
368 */ 383 */
369static char * 384static void
370get_pid_file_name (struct GNUNET_SERVICE_Context *sctx) 385service_main (void *cls)
371{ 386{
372 char *pif; 387 struct GNUNET_SERVICE_Handle *sh = cls;
373 388
374 if (GNUNET_OK != 389 if (GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN != sh->options)
375 GNUNET_CONFIGURATION_get_value_filename (sctx->cfg, sctx->service_name, 390 GNUNET_SCHEDULER_add_shutdown (&service_shutdown,
376 "PIDFILE", &pif)) 391 sh);
377 return NULL; 392 GNUNET_SERVICE_resume (sh);
378 return pif; 393
394 if (-1 != sh->ready_confirm_fd)
395 {
396 GNUNET_break (1 == WRITE (sh->ready_confirm_fd, ".", 1));
397 GNUNET_break (0 == CLOSE (sh->ready_confirm_fd));
398 sh->ready_confirm_fd = -1;
399 }
400
401 if (NULL != sh->service_init_cb)
402 sh->service_init_cb (sh->cb_cls,
403 sh->cfg,
404 sh);
379} 405}
380 406
381 407
@@ -383,32 +409,37 @@ get_pid_file_name (struct GNUNET_SERVICE_Context *sctx)
383 * Parse an IPv4 access control list. 409 * Parse an IPv4 access control list.
384 * 410 *
385 * @param ret location where to write the ACL (set) 411 * @param ret location where to write the ACL (set)
386 * @param sctx service context to use to get the configuration 412 * @param sh service context to use to get the configuration
387 * @param option name of the ACL option to parse 413 * @param option name of the ACL option to parse
388 * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including 414 * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including
389 * no ACL configured) 415 * no ACL configured)
390 */ 416 */
391static int 417static int
392process_acl4 (struct GNUNET_STRINGS_IPv4NetworkPolicy **ret, 418process_acl4 (struct GNUNET_STRINGS_IPv4NetworkPolicy **ret,
393 struct GNUNET_SERVICE_Context *sctx, 419 struct GNUNET_SERVICE_Handle *sh,
394 const char *option) 420 const char *option)
395{ 421{
396 char *opt; 422 char *opt;
397 423
398 if (!GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, option)) 424 if (! GNUNET_CONFIGURATION_have_value (sh->cfg,
425 sh->service_name,
426 option))
399 { 427 {
400 *ret = NULL; 428 *ret = NULL;
401 return GNUNET_OK; 429 return GNUNET_OK;
402 } 430 }
403 GNUNET_break (GNUNET_OK == 431 GNUNET_break (GNUNET_OK ==
404 GNUNET_CONFIGURATION_get_value_string (sctx->cfg, 432 GNUNET_CONFIGURATION_get_value_string (sh->cfg,
405 sctx->service_name, 433 sh->service_name,
406 option, &opt)); 434 option,
435 &opt));
407 if (NULL == (*ret = GNUNET_STRINGS_parse_ipv4_policy (opt))) 436 if (NULL == (*ret = GNUNET_STRINGS_parse_ipv4_policy (opt)))
408 { 437 {
409 LOG (GNUNET_ERROR_TYPE_WARNING, 438 LOG (GNUNET_ERROR_TYPE_WARNING,
410 _("Could not parse IPv4 network specification `%s' for `%s:%s'\n"), 439 _("Could not parse IPv4 network specification `%s' for `%s:%s'\n"),
411 opt, sctx->service_name, option); 440 opt,
441 sh->service_name,
442 option);
412 GNUNET_free (opt); 443 GNUNET_free (opt);
413 return GNUNET_SYSERR; 444 return GNUNET_SYSERR;
414 } 445 }
@@ -421,32 +452,37 @@ process_acl4 (struct GNUNET_STRINGS_IPv4NetworkPolicy **ret,
421 * Parse an IPv6 access control list. 452 * Parse an IPv6 access control list.
422 * 453 *
423 * @param ret location where to write the ACL (set) 454 * @param ret location where to write the ACL (set)
424 * @param sctx service context to use to get the configuration 455 * @param sh service context to use to get the configuration
425 * @param option name of the ACL option to parse 456 * @param option name of the ACL option to parse
426 * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including 457 * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including
427 * no ACL configured) 458 * no ACL configured)
428 */ 459 */
429static int 460static int
430process_acl6 (struct GNUNET_STRINGS_IPv6NetworkPolicy **ret, 461process_acl6 (struct GNUNET_STRINGS_IPv6NetworkPolicy **ret,
431 struct GNUNET_SERVICE_Context *sctx, 462 struct GNUNET_SERVICE_Handle *sh,
432 const char *option) 463 const char *option)
433{ 464{
434 char *opt; 465 char *opt;
435 466
436 if (!GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, option)) 467 if (! GNUNET_CONFIGURATION_have_value (sh->cfg,
468 sh->service_name,
469 option))
437 { 470 {
438 *ret = NULL; 471 *ret = NULL;
439 return GNUNET_OK; 472 return GNUNET_OK;
440 } 473 }
441 GNUNET_break (GNUNET_OK == 474 GNUNET_break (GNUNET_OK ==
442 GNUNET_CONFIGURATION_get_value_string (sctx->cfg, 475 GNUNET_CONFIGURATION_get_value_string (sh->cfg,
443 sctx->service_name, 476 sh->service_name,
444 option, &opt)); 477 option,
478 &opt));
445 if (NULL == (*ret = GNUNET_STRINGS_parse_ipv6_policy (opt))) 479 if (NULL == (*ret = GNUNET_STRINGS_parse_ipv6_policy (opt)))
446 { 480 {
447 LOG (GNUNET_ERROR_TYPE_WARNING, 481 LOG (GNUNET_ERROR_TYPE_WARNING,
448 _("Could not parse IPv6 network specification `%s' for `%s:%s'\n"), 482 _("Could not parse IPv6 network specification `%s' for `%s:%s'\n"),
449 opt, sctx->service_name, option); 483 opt,
484 sh->service_name,
485 option);
450 GNUNET_free (opt); 486 GNUNET_free (opt);
451 return GNUNET_SYSERR; 487 return GNUNET_SYSERR;
452 } 488 }
@@ -476,7 +512,9 @@ add_unixpath (struct sockaddr **saddrs,
476 512
477 un = GNUNET_new (struct sockaddr_un); 513 un = GNUNET_new (struct sockaddr_un);
478 un->sun_family = AF_UNIX; 514 un->sun_family = AF_UNIX;
479 strncpy (un->sun_path, unixpath, sizeof (un->sun_path) - 1); 515 strncpy (un->sun_path,
516 unixpath,
517 sizeof (un->sun_path) - 1);
480#ifdef LINUX 518#ifdef LINUX
481 if (GNUNET_YES == abstract) 519 if (GNUNET_YES == abstract)
482 un->sun_path[0] = '\0'; 520 un->sun_path[0] = '\0';
@@ -514,11 +552,11 @@ add_unixpath (struct sockaddr **saddrs,
514 * zero (in this case, `*addrs` and `*addr_lens` will be 552 * zero (in this case, `*addrs` and `*addr_lens` will be
515 * set to NULL). 553 * set to NULL).
516 */ 554 */
517int 555static int
518GNUNET_SERVICE_get_server_addresses (const char *service_name, 556get_server_addresses (const char *service_name,
519 const struct GNUNET_CONFIGURATION_Handle *cfg, 557 const struct GNUNET_CONFIGURATION_Handle *cfg,
520 struct sockaddr ***addrs, 558 struct sockaddr ***addrs,
521 socklen_t ** addr_lens) 559 socklen_t **addr_lens)
522{ 560{
523 int disablev6; 561 int disablev6;
524 struct GNUNET_NETWORK_Handle *desc; 562 struct GNUNET_NETWORK_Handle *desc;
@@ -539,11 +577,15 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name,
539 *addrs = NULL; 577 *addrs = NULL;
540 *addr_lens = NULL; 578 *addr_lens = NULL;
541 desc = NULL; 579 desc = NULL;
542 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "DISABLEV6")) 580 if (GNUNET_CONFIGURATION_have_value (cfg,
581 service_name,
582 "DISABLEV6"))
543 { 583 {
544 if (GNUNET_SYSERR == 584 if (GNUNET_SYSERR ==
545 (disablev6 = 585 (disablev6 =
546 GNUNET_CONFIGURATION_get_value_yesno (cfg, service_name, "DISABLEV6"))) 586 GNUNET_CONFIGURATION_get_value_yesno (cfg,
587 service_name,
588 "DISABLEV6")))
547 return GNUNET_SYSERR; 589 return GNUNET_SYSERR;
548 } 590 }
549 else 591 else
@@ -552,33 +594,44 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name,
552 if (! disablev6) 594 if (! disablev6)
553 { 595 {
554 /* probe IPv6 support */ 596 /* probe IPv6 support */
555 desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0); 597 desc = GNUNET_NETWORK_socket_create (PF_INET6,
598 SOCK_STREAM,
599 0);
556 if (NULL == desc) 600 if (NULL == desc)
557 { 601 {
558 if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) || 602 if ( (ENOBUFS == errno) ||
559 (EACCES == errno)) 603 (ENOMEM == errno) ||
604 (ENFILE == errno) ||
605 (EACCES == errno) )
560 { 606 {
561 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket"); 607 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
608 "socket");
562 return GNUNET_SYSERR; 609 return GNUNET_SYSERR;
563 } 610 }
564 LOG (GNUNET_ERROR_TYPE_INFO, 611 LOG (GNUNET_ERROR_TYPE_INFO,
565 _("Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"), 612 _("Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"),
566 service_name, STRERROR (errno)); 613 service_name,
614 STRERROR (errno));
567 disablev6 = GNUNET_YES; 615 disablev6 = GNUNET_YES;
568 } 616 }
569 else 617 else
570 { 618 {
571 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc)); 619 GNUNET_break (GNUNET_OK ==
620 GNUNET_NETWORK_socket_close (desc));
572 desc = NULL; 621 desc = NULL;
573 } 622 }
574 } 623 }
575 624
576 port = 0; 625 port = 0;
577 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT")) 626 if (GNUNET_CONFIGURATION_have_value (cfg,
627 service_name,
628 "PORT"))
578 { 629 {
579 if (GNUNET_OK != 630 if (GNUNET_OK !=
580 GNUNET_CONFIGURATION_get_value_number (cfg, service_name, 631 GNUNET_CONFIGURATION_get_value_number (cfg,
581 "PORT", &port)) 632 service_name,
633 "PORT",
634 &port))
582 { 635 {
583 LOG (GNUNET_ERROR_TYPE_ERROR, 636 LOG (GNUNET_ERROR_TYPE_ERROR,
584 _("Require valid port number for service `%s' in configuration!\n"), 637 _("Require valid port number for service `%s' in configuration!\n"),
@@ -593,11 +646,15 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name,
593 } 646 }
594 } 647 }
595 648
596 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "BINDTO")) 649 if (GNUNET_CONFIGURATION_have_value (cfg,
650 service_name,
651 "BINDTO"))
597 { 652 {
598 GNUNET_break (GNUNET_OK == 653 GNUNET_break (GNUNET_OK ==
599 GNUNET_CONFIGURATION_get_value_string (cfg, service_name, 654 GNUNET_CONFIGURATION_get_value_string (cfg,
600 "BINDTO", &hostname)); 655 service_name,
656 "BINDTO",
657 &hostname));
601 } 658 }
602 else 659 else
603 hostname = NULL; 660 hostname = NULL;
@@ -606,10 +663,14 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name,
606 abstract = GNUNET_NO; 663 abstract = GNUNET_NO;
607#ifdef AF_UNIX 664#ifdef AF_UNIX
608 if ((GNUNET_YES == 665 if ((GNUNET_YES ==
609 GNUNET_CONFIGURATION_have_value (cfg, service_name, "UNIXPATH")) && 666 GNUNET_CONFIGURATION_have_value (cfg,
667 service_name,
668 "UNIXPATH")) &&
610 (GNUNET_OK == 669 (GNUNET_OK ==
611 GNUNET_CONFIGURATION_get_value_filename (cfg, service_name, "UNIXPATH", 670 GNUNET_CONFIGURATION_get_value_filename (cfg,
612 &unixpath)) && 671 service_name,
672 "UNIXPATH",
673 &unixpath)) &&
613 (0 < strlen (unixpath))) 674 (0 < strlen (unixpath)))
614 { 675 {
615 /* probe UNIX support */ 676 /* probe UNIX support */
@@ -618,7 +679,8 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name,
618 if (strlen (unixpath) >= sizeof (s_un.sun_path)) 679 if (strlen (unixpath) >= sizeof (s_un.sun_path))
619 { 680 {
620 LOG (GNUNET_ERROR_TYPE_WARNING, 681 LOG (GNUNET_ERROR_TYPE_WARNING,
621 _("UNIXPATH `%s' too long, maximum length is %llu\n"), unixpath, 682 _("UNIXPATH `%s' too long, maximum length is %llu\n"),
683 unixpath,
622 (unsigned long long) sizeof (s_un.sun_path)); 684 (unsigned long long) sizeof (s_un.sun_path));
623 unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath); 685 unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
624 LOG (GNUNET_ERROR_TYPE_INFO, 686 LOG (GNUNET_ERROR_TYPE_INFO,
@@ -632,22 +694,27 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name,
632 if (GNUNET_SYSERR == abstract) 694 if (GNUNET_SYSERR == abstract)
633 abstract = GNUNET_NO; 695 abstract = GNUNET_NO;
634#endif 696#endif
635 if ((GNUNET_YES != abstract) 697 if ( (GNUNET_YES != abstract) &&
636 && (GNUNET_OK != 698 (GNUNET_OK !=
637 GNUNET_DISK_directory_create_for_file (unixpath))) 699 GNUNET_DISK_directory_create_for_file (unixpath)) )
638 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, 700 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
639 "mkdir", 701 "mkdir",
640 unixpath); 702 unixpath);
641 } 703 }
642 if (NULL != unixpath) 704 if (NULL != unixpath)
643 { 705 {
644 desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0); 706 desc = GNUNET_NETWORK_socket_create (AF_UNIX,
707 SOCK_STREAM,
708 0);
645 if (NULL == desc) 709 if (NULL == desc)
646 { 710 {
647 if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) || 711 if ((ENOBUFS == errno) ||
712 (ENOMEM == errno) ||
713 (ENFILE == errno) ||
648 (EACCES == errno)) 714 (EACCES == errno))
649 { 715 {
650 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket"); 716 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
717 "socket");
651 GNUNET_free_non_null (hostname); 718 GNUNET_free_non_null (hostname);
652 GNUNET_free (unixpath); 719 GNUNET_free (unixpath);
653 return GNUNET_SYSERR; 720 return GNUNET_SYSERR;
@@ -661,7 +728,8 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name,
661 } 728 }
662 else 729 else
663 { 730 {
664 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc)); 731 GNUNET_break (GNUNET_OK ==
732 GNUNET_NETWORK_socket_close (desc));
665 desc = NULL; 733 desc = NULL;
666 } 734 }
667 } 735 }
@@ -677,9 +745,14 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name,
677 } 745 }
678 if (0 == port) 746 if (0 == port)
679 { 747 {
680 saddrs = GNUNET_malloc (2 * sizeof (struct sockaddr *)); 748 saddrs = GNUNET_new_array (2,
681 saddrlens = GNUNET_malloc (2 * sizeof (socklen_t)); 749 struct sockaddr *);
682 add_unixpath (saddrs, saddrlens, unixpath, abstract); 750 saddrlens = GNUNET_new_array (2,
751 socklen_t);
752 add_unixpath (saddrs,
753 saddrlens,
754 unixpath,
755 abstract);
683 GNUNET_free_non_null (unixpath); 756 GNUNET_free_non_null (unixpath);
684 GNUNET_free_non_null (hostname); 757 GNUNET_free_non_null (hostname);
685 *addrs = saddrs; 758 *addrs = saddrs;
@@ -693,11 +766,16 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name,
693 "Resolving `%s' since that is where `%s' will bind to.\n", 766 "Resolving `%s' since that is where `%s' will bind to.\n",
694 hostname, 767 hostname,
695 service_name); 768 service_name);
696 memset (&hints, 0, sizeof (struct addrinfo)); 769 memset (&hints,
770 0,
771 sizeof (struct addrinfo));
697 if (disablev6) 772 if (disablev6)
698 hints.ai_family = AF_INET; 773 hints.ai_family = AF_INET;
699 hints.ai_protocol = IPPROTO_TCP; 774 hints.ai_protocol = IPPROTO_TCP;
700 if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) || 775 if ((0 != (ret = getaddrinfo (hostname,
776 NULL,
777 &hints,
778 &res))) ||
701 (NULL == res)) 779 (NULL == res))
702 { 780 {
703 LOG (GNUNET_ERROR_TYPE_ERROR, 781 LOG (GNUNET_ERROR_TYPE_ERROR,
@@ -713,7 +791,8 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name,
713 while (NULL != (pos = next)) 791 while (NULL != (pos = next))
714 { 792 {
715 next = pos->ai_next; 793 next = pos->ai_next;
716 if ((disablev6) && (pos->ai_family == AF_INET6)) 794 if ( (disablev6) &&
795 (pos->ai_family == AF_INET6) )
717 continue; 796 continue;
718 i++; 797 i++;
719 } 798 }
@@ -731,32 +810,45 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name,
731 resi = i; 810 resi = i;
732 if (NULL != unixpath) 811 if (NULL != unixpath)
733 resi++; 812 resi++;
734 saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *)); 813 saddrs = GNUNET_new_array (resi + 1,
735 saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t)); 814 struct sockaddr *);
815 saddrlens = GNUNET_new_array (resi + 1,
816 socklen_t);
736 i = 0; 817 i = 0;
737 if (NULL != unixpath) 818 if (NULL != unixpath)
738 { 819 {
739 add_unixpath (saddrs, saddrlens, unixpath, abstract); 820 add_unixpath (saddrs,
821 saddrlens,
822 unixpath,
823 abstract);
740 i++; 824 i++;
741 } 825 }
742 next = res; 826 next = res;
743 while (NULL != (pos = next)) 827 while (NULL != (pos = next))
744 { 828 {
745 next = pos->ai_next; 829 next = pos->ai_next;
746 if ((disablev6) && (AF_INET6 == pos->ai_family)) 830 if ( (disablev6) &&
831 (AF_INET6 == pos->ai_family) )
747 continue; 832 continue;
748 if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol)) 833 if ( (IPPROTO_TCP != pos->ai_protocol) &&
834 (0 != pos->ai_protocol) )
749 continue; /* not TCP */ 835 continue; /* not TCP */
750 if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype)) 836 if ( (SOCK_STREAM != pos->ai_socktype) &&
837 (0 != pos->ai_socktype) )
751 continue; /* huh? */ 838 continue; /* huh? */
752 LOG (GNUNET_ERROR_TYPE_DEBUG, "Service `%s' will bind to `%s'\n", 839 LOG (GNUNET_ERROR_TYPE_DEBUG,
753 service_name, GNUNET_a2s (pos->ai_addr, pos->ai_addrlen)); 840 "Service `%s' will bind to `%s'\n",
841 service_name,
842 GNUNET_a2s (pos->ai_addr,
843 pos->ai_addrlen));
754 if (AF_INET == pos->ai_family) 844 if (AF_INET == pos->ai_family)
755 { 845 {
756 GNUNET_assert (sizeof (struct sockaddr_in) == pos->ai_addrlen); 846 GNUNET_assert (sizeof (struct sockaddr_in) == pos->ai_addrlen);
757 saddrlens[i] = pos->ai_addrlen; 847 saddrlens[i] = pos->ai_addrlen;
758 saddrs[i] = GNUNET_malloc (saddrlens[i]); 848 saddrs[i] = GNUNET_malloc (saddrlens[i]);
759 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]); 849 GNUNET_memcpy (saddrs[i],
850 pos->ai_addr,
851 saddrlens[i]);
760 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port); 852 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
761 } 853 }
762 else 854 else
@@ -765,7 +857,9 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name,
765 GNUNET_assert (sizeof (struct sockaddr_in6) == pos->ai_addrlen); 857 GNUNET_assert (sizeof (struct sockaddr_in6) == pos->ai_addrlen);
766 saddrlens[i] = pos->ai_addrlen; 858 saddrlens[i] = pos->ai_addrlen;
767 saddrs[i] = GNUNET_malloc (saddrlens[i]); 859 saddrs[i] = GNUNET_malloc (saddrlens[i]);
768 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]); 860 GNUNET_memcpy (saddrs[i],
861 pos->ai_addr,
862 saddrlens[i]);
769 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port); 863 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
770 } 864 }
771 i++; 865 i++;
@@ -784,11 +878,16 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name,
784 if (NULL != unixpath) 878 if (NULL != unixpath)
785 resi++; 879 resi++;
786 i = 0; 880 i = 0;
787 saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *)); 881 saddrs = GNUNET_new_array (resi + 1,
788 saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t)); 882 struct sockaddr *);
883 saddrlens = GNUNET_new_array (resi + 1,
884 socklen_t);
789 if (NULL != unixpath) 885 if (NULL != unixpath)
790 { 886 {
791 add_unixpath (saddrs, saddrlens, unixpath, abstract); 887 add_unixpath (saddrs,
888 saddrlens,
889 unixpath,
890 abstract);
792 i++; 891 i++;
793 } 892 }
794 saddrlens[i] = sizeof (struct sockaddr_in); 893 saddrlens[i] = sizeof (struct sockaddr_in);
@@ -805,12 +904,17 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name,
805 resi = 2; 904 resi = 2;
806 if (NULL != unixpath) 905 if (NULL != unixpath)
807 resi++; 906 resi++;
808 saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *)); 907 saddrs = GNUNET_new_array (resi + 1,
809 saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t)); 908 struct sockaddr *);
909 saddrlens = GNUNET_new_array (resi + 1,
910 socklen_t);
810 i = 0; 911 i = 0;
811 if (NULL != unixpath) 912 if (NULL != unixpath)
812 { 913 {
813 add_unixpath (saddrs, saddrlens, unixpath, abstract); 914 add_unixpath (saddrs,
915 saddrlens,
916 unixpath,
917 abstract);
814 i++; 918 i++;
815 } 919 }
816 saddrlens[i] = sizeof (struct sockaddr_in6); 920 saddrlens[i] = sizeof (struct sockaddr_in6);
@@ -841,13 +945,14 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name,
841/** 945/**
842 * Read listen sockets from the parent process (ARM). 946 * Read listen sockets from the parent process (ARM).
843 * 947 *
844 * @param sctx service context to initialize 948 * @param sh service context to initialize
845 * @return #GNUNET_YES if ok, #GNUNET_NO if not ok (must bind yourself), 949 * @return NULL-terminated array of sockets on success,
846 * and #GNUNET_SYSERR on error. 950 * NULL if not ok (must bind yourself)
847 */ 951 */
848static int 952static struct GNUNET_NETWORK_Handle **
849receive_sockets_from_parent (struct GNUNET_SERVICE_Context *sctx) 953receive_sockets_from_parent (struct GNUNET_SERVICE_Handle *sh)
850{ 954{
955 static struct GNUNET_NETWORK_Handle **lsocks;
851 const char *env_buf; 956 const char *env_buf;
852 int fail; 957 int fail;
853 uint64_t count; 958 uint64_t count;
@@ -855,15 +960,19 @@ receive_sockets_from_parent (struct GNUNET_SERVICE_Context *sctx)
855 HANDLE lsocks_pipe; 960 HANDLE lsocks_pipe;
856 961
857 env_buf = getenv ("GNUNET_OS_READ_LSOCKS"); 962 env_buf = getenv ("GNUNET_OS_READ_LSOCKS");
858 if ((NULL == env_buf) || (strlen (env_buf) <= 0)) 963 if ( (NULL == env_buf) ||
859 return GNUNET_NO; 964 (strlen (env_buf) <= 0) )
965 return NULL;
860 /* Using W32 API directly here, because this pipe will 966 /* Using W32 API directly here, because this pipe will
861 * never be used outside of this function, and it's just too much of a bother 967 * never be used outside of this function, and it's just too much of a bother
862 * to create a GNUnet API that boxes a HANDLE (the way it is done with socks) 968 * to create a GNUnet API that boxes a HANDLE (the way it is done with socks)
863 */ 969 */
864 lsocks_pipe = (HANDLE) strtoul (env_buf, NULL, 10); 970 lsocks_pipe = (HANDLE) strtoul (env_buf,
865 if ( (0 == lsocks_pipe) || (INVALID_HANDLE_VALUE == lsocks_pipe)) 971 NULL,
866 return GNUNET_NO; 972 10);
973 if ( (0 == lsocks_pipe) ||
974 (INVALID_HANDLE_VALUE == lsocks_pipe))
975 return NULL;
867 fail = 1; 976 fail = 1;
868 do 977 do
869 { 978 {
@@ -871,11 +980,17 @@ receive_sockets_from_parent (struct GNUNET_SERVICE_Context *sctx)
871 int fail2; 980 int fail2;
872 DWORD rd; 981 DWORD rd;
873 982
874 ret = ReadFile (lsocks_pipe, &count, sizeof (count), &rd, NULL); 983 ret = ReadFile (lsocks_pipe,
875 if ((0 == ret) || (sizeof (count) != rd) || (0 == count)) 984 &count,
985 sizeof (count),
986 &rd,
987 NULL);
988 if ( (0 == ret) ||
989 (sizeof (count) != rd) ||
990 (0 == count) )
876 break; 991 break;
877 sctx->lsocks = 992 lsocks = GNUNET_new_array (count + 1,
878 GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (count + 1)); 993 struct GNUNET_NETWORK_Handle *);
879 994
880 fail2 = 1; 995 fail2 = 1;
881 for (i = 0; i < count; i++) 996 for (i = 0; i < count; i++)
@@ -884,51 +999,165 @@ receive_sockets_from_parent (struct GNUNET_SERVICE_Context *sctx)
884 uint64_t size; 999 uint64_t size;
885 SOCKET s; 1000 SOCKET s;
886 1001
887 ret = ReadFile (lsocks_pipe, &size, sizeof (size), &rd, NULL); 1002 ret = ReadFile (lsocks_pipe,
888 if ( (0 == ret) || (sizeof (size) != rd) || (sizeof (pi) != size) ) 1003 &size,
1004 sizeof (size),
1005 &rd,
1006 NULL);
1007 if ( (0 == ret) ||
1008 (sizeof (size) != rd) ||
1009 (sizeof (pi) != size) )
889 break; 1010 break;
890 ret = ReadFile (lsocks_pipe, &pi, sizeof (pi), &rd, NULL); 1011 ret = ReadFile (lsocks_pipe,
891 if ( (0 == ret) || (sizeof (pi) != rd)) 1012 &pi,
1013 sizeof (pi),
1014 &rd,
1015 NULL);
1016 if ( (0 == ret) ||
1017 (sizeof (pi) != rd))
892 break; 1018 break;
893 s = WSASocketA (pi.iAddressFamily, pi.iSocketType, pi.iProtocol, &pi, 0, WSA_FLAG_OVERLAPPED); 1019 s = WSASocketA (pi.iAddressFamily,
894 sctx->lsocks[i] = GNUNET_NETWORK_socket_box_native (s); 1020 pi.iSocketType,
895 if (NULL == sctx->lsocks[i]) 1021 pi.iProtocol,
1022 &pi,
1023 0,
1024 WSA_FLAG_OVERLAPPED);
1025 lsocks[i] = GNUNET_NETWORK_socket_box_native (s);
1026 if (NULL == lsocks[i])
896 break; 1027 break;
897 else if (i == count - 1) 1028 else if (i == count - 1)
898 fail2 = 0; 1029 fail2 = 0;
899 } 1030 }
900 if (fail2) 1031 if (fail2)
901 break; 1032 break;
902 sctx->lsocks[count] = NULL; 1033 lsocks[count] = NULL;
903 fail = 0; 1034 fail = 0;
904 } 1035 }
905 while (fail); 1036 while (fail);
906
907 CloseHandle (lsocks_pipe); 1037 CloseHandle (lsocks_pipe);
908 1038
909 if (fail) 1039 if (fail)
910 { 1040 {
911 LOG (GNUNET_ERROR_TYPE_ERROR, 1041 LOG (GNUNET_ERROR_TYPE_ERROR,
912 _("Could not access a pre-bound socket, will try to bind myself\n")); 1042 _("Could not access a pre-bound socket, will try to bind myself\n"));
913 for (i = 0; (i < count) && (NULL != sctx->lsocks[i]); i++) 1043 for (i = 0; (i < count) && (NULL != lsocks[i]); i++)
914 GNUNET_break (0 == GNUNET_NETWORK_socket_close (sctx->lsocks[i])); 1044 GNUNET_break (GNUNET_OK ==
915 GNUNET_free_non_null (sctx->lsocks); 1045 GNUNET_NETWORK_socket_close (lsocks[i]));
916 sctx->lsocks = NULL; 1046 GNUNET_free (lsocks);
917 return GNUNET_NO; 1047 return NULL;
918 } 1048 }
919 return GNUNET_YES; 1049 return lsocks;
920} 1050}
921#endif 1051#endif
922 1052
923 1053
924/** 1054/**
925 * Setup addr, addrlen, idle_timeout 1055 * Create and initialize a listen socket for the server.
926 * based on configuration! 1056 *
1057 * @param server_addr address to listen on
1058 * @param socklen length of @a server_addr
1059 * @return NULL on error, otherwise the listen socket
1060 */
1061static struct GNUNET_NETWORK_Handle *
1062open_listen_socket (const struct sockaddr *server_addr,
1063 socklen_t socklen)
1064{
1065 struct GNUNET_NETWORK_Handle *sock;
1066 uint16_t port;
1067 int eno;
1068
1069 switch (server_addr->sa_family)
1070 {
1071 case AF_INET:
1072 port = ntohs (((const struct sockaddr_in *) server_addr)->sin_port);
1073 break;
1074 case AF_INET6:
1075 port = ntohs (((const struct sockaddr_in6 *) server_addr)->sin6_port);
1076 break;
1077 case AF_UNIX:
1078 port = 0;
1079 break;
1080 default:
1081 GNUNET_break (0);
1082 port = 0;
1083 break;
1084 }
1085 sock = GNUNET_NETWORK_socket_create (server_addr->sa_family,
1086 SOCK_STREAM,
1087 0);
1088 if (NULL == sock)
1089 {
1090 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
1091 "socket");
1092 errno = 0;
1093 return NULL;
1094 }
1095 /* bind the socket */
1096 if (GNUNET_OK != GNUNET_NETWORK_socket_bind (sock,
1097 server_addr,
1098 socklen))
1099 {
1100 eno = errno;
1101 if (EADDRINUSE != errno)
1102 {
1103 /* we don't log 'EADDRINUSE' here since an IPv4 bind may
1104 * fail if we already took the port on IPv6; if both IPv4 and
1105 * IPv6 binds fail, then our caller will log using the
1106 * errno preserved in 'eno' */
1107 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
1108 "bind");
1109 if (0 != port)
1110 LOG (GNUNET_ERROR_TYPE_ERROR,
1111 _("`%s' failed for port %d (%s).\n"),
1112 "bind",
1113 port,
1114 (AF_INET == server_addr->sa_family) ? "IPv4" : "IPv6");
1115 eno = 0;
1116 }
1117 else
1118 {
1119 if (0 != port)
1120 LOG (GNUNET_ERROR_TYPE_WARNING,
1121 _("`%s' failed for port %d (%s): address already in use\n"),
1122 "bind", port,
1123 (AF_INET == server_addr->sa_family) ? "IPv4" : "IPv6");
1124 else if (AF_UNIX == server_addr->sa_family)
1125 {
1126 LOG (GNUNET_ERROR_TYPE_WARNING,
1127 _("`%s' failed for `%s': address already in use\n"),
1128 "bind",
1129 GNUNET_a2s (server_addr, socklen));
1130 }
1131 }
1132 GNUNET_break (GNUNET_OK ==
1133 GNUNET_NETWORK_socket_close (sock));
1134 errno = eno;
1135 return NULL;
1136 }
1137 if (GNUNET_OK != GNUNET_NETWORK_socket_listen (sock,
1138 5))
1139 {
1140 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
1141 "listen");
1142 GNUNET_break (GNUNET_OK ==
1143 GNUNET_NETWORK_socket_close (sock));
1144 errno = 0;
1145 return NULL;
1146 }
1147 if (0 != port)
1148 LOG (GNUNET_ERROR_TYPE_DEBUG,
1149 "Server starts to listen on port %u.\n",
1150 port);
1151 return sock;
1152}
1153
1154
1155/**
1156 * Setup service handle
927 * 1157 *
928 * Configuration may specify: 1158 * Configuration may specify:
929 * - PORT (where to bind to for TCP) 1159 * - PORT (where to bind to for TCP)
930 * - UNIXPATH (where to bind to for UNIX domain sockets) 1160 * - UNIXPATH (where to bind to for UNIX domain sockets)
931 * - TIMEOUT (after how many ms does an inactive service timeout);
932 * - DISABLEV6 (disable support for IPv6, otherwise we use dual-stack) 1161 * - DISABLEV6 (disable support for IPv6, otherwise we use dual-stack)
933 * - BINDTO (hostname or IP address to bind to, otherwise we take everything) 1162 * - BINDTO (hostname or IP address to bind to, otherwise we take everything)
934 * - ACCEPT_FROM (only allow connections from specified IPv4 subnets) 1163 * - ACCEPT_FROM (only allow connections from specified IPv4 subnets)
@@ -936,108 +1165,170 @@ receive_sockets_from_parent (struct GNUNET_SERVICE_Context *sctx)
936 * - REJECT_FROM (disallow allow connections from specified IPv4 subnets) 1165 * - REJECT_FROM (disallow allow connections from specified IPv4 subnets)
937 * - REJECT_FROM6 (disallow allow connections from specified IPv6 subnets) 1166 * - REJECT_FROM6 (disallow allow connections from specified IPv6 subnets)
938 * 1167 *
939 * @param sctx service context to initialize 1168 * @param sh service context to initialize
940 * @return #GNUNET_OK if configuration succeeded 1169 * @return #GNUNET_OK if configuration succeeded
941 */ 1170 */
942static int 1171static int
943setup_service (struct GNUNET_SERVICE_Context *sctx) 1172setup_service (struct GNUNET_SERVICE_Handle *sh)
944{ 1173{
945 struct GNUNET_TIME_Relative idleout;
946 int tolerant; 1174 int tolerant;
947 1175 struct GNUNET_NETWORK_Handle **lsocks;
948#ifndef MINGW 1176#ifndef MINGW
949 const char *nfds; 1177 const char *nfds;
950 unsigned int cnt; 1178 unsigned int cnt;
951 int flags; 1179 int flags;
952#endif 1180#endif
953 1181
954 if (GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, "TIMEOUT"))
955 {
956 if (GNUNET_OK !=
957 GNUNET_CONFIGURATION_get_value_time (sctx->cfg, sctx->service_name,
958 "TIMEOUT", &idleout))
959 {
960 LOG (GNUNET_ERROR_TYPE_ERROR,
961 _("Specified value for `%s' of service `%s' is invalid\n"),
962 "TIMEOUT", sctx->service_name);
963 return GNUNET_SYSERR;
964 }
965 sctx->timeout = idleout;
966 }
967 else
968 sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
969
970 if (GNUNET_CONFIGURATION_have_value 1182 if (GNUNET_CONFIGURATION_have_value
971 (sctx->cfg, sctx->service_name, "TOLERANT")) 1183 (sh->cfg,
1184 sh->service_name,
1185 "TOLERANT"))
972 { 1186 {
973 if (GNUNET_SYSERR == 1187 if (GNUNET_SYSERR ==
974 (tolerant = 1188 (tolerant =
975 GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->service_name, 1189 GNUNET_CONFIGURATION_get_value_yesno (sh->cfg,
1190 sh->service_name,
976 "TOLERANT"))) 1191 "TOLERANT")))
977 { 1192 {
978 LOG (GNUNET_ERROR_TYPE_ERROR, 1193 LOG (GNUNET_ERROR_TYPE_ERROR,
979 _("Specified value for `%s' of service `%s' is invalid\n"), 1194 _("Specified value for `%s' of service `%s' is invalid\n"),
980 "TOLERANT", sctx->service_name); 1195 "TOLERANT",
1196 sh->service_name);
981 return GNUNET_SYSERR; 1197 return GNUNET_SYSERR;
982 } 1198 }
983 } 1199 }
984 else 1200 else
985 tolerant = GNUNET_NO; 1201 tolerant = GNUNET_NO;
986 1202
1203 lsocks = NULL;
987#ifndef MINGW 1204#ifndef MINGW
988 errno = 0; 1205 errno = 0;
989 if ((NULL != (nfds = getenv ("LISTEN_FDS"))) && 1206 if ( (NULL != (nfds = getenv ("LISTEN_FDS"))) &&
990 (1 == SSCANF (nfds, "%u", &cnt)) && (cnt > 0) && (cnt < FD_SETSIZE) && 1207 (1 == SSCANF (nfds,
991 (cnt + 4 < FD_SETSIZE)) 1208 "%u",
1209 &cnt)) &&
1210 (cnt > 0) &&
1211 (cnt < FD_SETSIZE) &&
1212 (cnt + 4 < FD_SETSIZE) )
992 { 1213 {
993 sctx->lsocks = 1214 lsocks = GNUNET_new_array (cnt + 1,
994 GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (cnt + 1)); 1215 struct GNUNET_NETWORK_Handle *);
995 while (0 < cnt--) 1216 while (0 < cnt--)
996 { 1217 {
997 flags = fcntl (3 + cnt, F_GETFD); 1218 flags = fcntl (3 + cnt,
998 if ((flags < 0) || (0 != (flags & FD_CLOEXEC)) || 1219 F_GETFD);
999 (NULL == 1220 if ( (flags < 0) ||
1000 (sctx->lsocks[cnt] = GNUNET_NETWORK_socket_box_native (3 + cnt)))) 1221 (0 != (flags & FD_CLOEXEC)) ||
1222 (NULL ==
1223 (lsocks[cnt] = GNUNET_NETWORK_socket_box_native (3 + cnt))))
1001 { 1224 {
1002 LOG (GNUNET_ERROR_TYPE_ERROR, 1225 LOG (GNUNET_ERROR_TYPE_ERROR,
1003 _ 1226 _("Could not access pre-bound socket %u, will try to bind myself\n"),
1004 ("Could not access pre-bound socket %u, will try to bind myself\n"),
1005 (unsigned int) 3 + cnt); 1227 (unsigned int) 3 + cnt);
1006 cnt++; 1228 cnt++;
1007 while (sctx->lsocks[cnt] != NULL) 1229 while (NULL != lsocks[cnt])
1008 GNUNET_break (0 == GNUNET_NETWORK_socket_close (sctx->lsocks[cnt++])); 1230 GNUNET_break (GNUNET_OK ==
1009 GNUNET_free (sctx->lsocks); 1231 GNUNET_NETWORK_socket_close (lsocks[cnt++]));
1010 sctx->lsocks = NULL; 1232 GNUNET_free (lsocks);
1233 lsocks = NULL;
1011 break; 1234 break;
1012 } 1235 }
1013 } 1236 }
1014 unsetenv ("LISTEN_FDS"); 1237 unsetenv ("LISTEN_FDS");
1015 } 1238 }
1016#else 1239#else
1017 if (getenv ("GNUNET_OS_READ_LSOCKS") != NULL) 1240 if (NULL != getenv ("GNUNET_OS_READ_LSOCKS"))
1018 { 1241 {
1019 receive_sockets_from_parent (sctx); 1242 lsocks = receive_sockets_from_parent (sh);
1020 putenv ("GNUNET_OS_READ_LSOCKS="); 1243 putenv ("GNUNET_OS_READ_LSOCKS=");
1021 } 1244 }
1022#endif 1245#endif
1023 1246
1024 if ((NULL == sctx->lsocks) && 1247 if (NULL != lsocks)
1025 (GNUNET_SYSERR == 1248 {
1026 GNUNET_SERVICE_get_server_addresses (sctx->service_name, sctx->cfg, 1249 /* listen only on inherited sockets if we have any */
1027 &sctx->addrs, &sctx->addrlens))) 1250 struct GNUNET_NETWORK_Handle **ls;
1028 return GNUNET_SYSERR; 1251
1029 sctx->require_found = tolerant ? GNUNET_NO : GNUNET_YES; 1252 for (ls = lsocks; NULL != *ls; ls++)
1030 sctx->match_uid = 1253 {
1031 GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->service_name, 1254 struct ServiceListenContext *slc;
1255
1256 slc = GNUNET_new (struct ServiceListenContext);
1257 slc->sh = sh;
1258 slc->listen_socket = *ls;
1259 GNUNET_CONTAINER_DLL_insert (sh->slc_head,
1260 sh->slc_tail,
1261 slc);
1262 }
1263 GNUNET_free (lsocks);
1264 }
1265 else
1266 {
1267 struct sockaddr **addrs;
1268 socklen_t *addrlens;
1269 int num;
1270
1271 num = get_server_addresses (sh->service_name,
1272 sh->cfg,
1273 &addrs,
1274 &addrlens);
1275 if (GNUNET_SYSERR == num)
1276 return GNUNET_SYSERR;
1277
1278 for (int i = 0; i < num; i++)
1279 {
1280 struct ServiceListenContext *slc;
1281
1282 slc = GNUNET_new (struct ServiceListenContext);
1283 slc->sh = sh;
1284 slc->listen_socket = open_listen_socket (addrs[i],
1285 addrlens[i]);
1286 if (NULL == slc->listen_socket)
1287 {
1288 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
1289 "bind");
1290 GNUNET_free (addrs[i++]);
1291 GNUNET_free (slc);
1292 continue;
1293 }
1294 GNUNET_free (addrs[i++]);
1295 GNUNET_CONTAINER_DLL_insert (sh->slc_head,
1296 sh->slc_tail,
1297 slc);
1298 }
1299 GNUNET_free_non_null (addrlens);
1300 GNUNET_free_non_null (addrs);
1301 if ( (0 != num) &&
1302 (NULL == sh->slc_head) )
1303 {
1304 /* All attempts to bind failed, hard failure */
1305 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1306 _("Could not bind to any of the ports I was supposed to, refusing to run!\n"));
1307 return GNUNET_SYSERR;
1308 }
1309 }
1310
1311 sh->require_found = tolerant ? GNUNET_NO : GNUNET_YES;
1312 sh->match_uid
1313 = GNUNET_CONFIGURATION_get_value_yesno (sh->cfg,
1314 sh->service_name,
1032 "UNIX_MATCH_UID"); 1315 "UNIX_MATCH_UID");
1033 sctx->match_gid = 1316 sh->match_gid
1034 GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->service_name, 1317 = GNUNET_CONFIGURATION_get_value_yesno (sh->cfg,
1318 sh->service_name,
1035 "UNIX_MATCH_GID"); 1319 "UNIX_MATCH_GID");
1036 process_acl4 (&sctx->v4_denied, sctx, "REJECT_FROM"); 1320 process_acl4 (&sh->v4_denied,
1037 process_acl4 (&sctx->v4_allowed, sctx, "ACCEPT_FROM"); 1321 sh,
1038 process_acl6 (&sctx->v6_denied, sctx, "REJECT_FROM6"); 1322 "REJECT_FROM");
1039 process_acl6 (&sctx->v6_allowed, sctx, "ACCEPT_FROM6"); 1323 process_acl4 (&sh->v4_allowed,
1040 1324 sh,
1325 "ACCEPT_FROM");
1326 process_acl6 (&sh->v6_denied,
1327 sh,
1328 "REJECT_FROM6");
1329 process_acl6 (&sh->v6_allowed,
1330 sh,
1331 "ACCEPT_FROM6");
1041 return GNUNET_OK; 1332 return GNUNET_OK;
1042} 1333}
1043 1334
@@ -1046,185 +1337,129 @@ setup_service (struct GNUNET_SERVICE_Context *sctx)
1046 * Get the name of the user that'll be used 1337 * Get the name of the user that'll be used
1047 * to provide the service. 1338 * to provide the service.
1048 * 1339 *
1049 * @param sctx service context 1340 * @param sh service context
1050 * @return value of the 'USERNAME' option 1341 * @return value of the 'USERNAME' option
1051 */ 1342 */
1052static char * 1343static char *
1053get_user_name (struct GNUNET_SERVICE_Context *sctx) 1344get_user_name (struct GNUNET_SERVICE_Handle *sh)
1054{ 1345{
1055 char *un; 1346 char *un;
1056 1347
1057 if (GNUNET_OK != 1348 if (GNUNET_OK !=
1058 GNUNET_CONFIGURATION_get_value_filename (sctx->cfg, sctx->service_name, 1349 GNUNET_CONFIGURATION_get_value_filename (sh->cfg,
1059 "USERNAME", &un)) 1350 sh->service_name,
1351 "USERNAME",
1352 &un))
1060 return NULL; 1353 return NULL;
1061 return un; 1354 return un;
1062} 1355}
1063 1356
1064 1357
1065/** 1358/**
1066 * Write PID file. 1359 * Set user ID.
1067 * 1360 *
1068 * @param sctx service context 1361 * @param sh service context
1069 * @param pid PID to write (should be equal to 'getpid()' 1362 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1070 * @return #GNUNET_OK on success (including no work to be done)
1071 */ 1363 */
1072static int 1364static int
1073write_pid_file (struct GNUNET_SERVICE_Context *sctx, pid_t pid) 1365set_user_id (struct GNUNET_SERVICE_Handle *sh)
1074{ 1366{
1075 FILE *pidfd;
1076 char *pif;
1077 char *user; 1367 char *user;
1078 char *rdir; 1368
1079 int len; 1369 if (NULL == (user = get_user_name (sh)))
1080 1370 return GNUNET_OK; /* keep */
1081 if (NULL == (pif = get_pid_file_name (sctx))) 1371#ifndef MINGW
1082 return GNUNET_OK; /* no file desired */ 1372 struct passwd *pws;
1083 user = get_user_name (sctx); 1373
1084 rdir = GNUNET_strdup (pif); 1374 errno = 0;
1085 len = strlen (rdir); 1375 pws = getpwnam (user);
1086 while ((len > 0) && (rdir[len] != DIR_SEPARATOR)) 1376 if (NULL == pws)
1087 len--; 1377 {
1088 rdir[len] = '\0'; 1378 LOG (GNUNET_ERROR_TYPE_ERROR,
1089 if (0 != ACCESS (rdir, F_OK)) 1379 _("Cannot obtain information about user `%s': %s\n"),
1090 { 1380 user,
1091 /* we get to create a directory -- and claim it 1381 errno == 0 ? _("No such user") : STRERROR (errno));
1092 * as ours! */ 1382 GNUNET_free (user);
1093 (void) GNUNET_DISK_directory_create (rdir);
1094 if ((NULL != user) && (0 < strlen (user)))
1095 GNUNET_DISK_file_change_owner (rdir, user);
1096 }
1097 if (0 != ACCESS (rdir, W_OK | X_OK))
1098 {
1099 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "access", rdir);
1100 GNUNET_free (rdir);
1101 GNUNET_free_non_null (user);
1102 GNUNET_free (pif);
1103 return GNUNET_SYSERR; 1383 return GNUNET_SYSERR;
1104 } 1384 }
1105 GNUNET_free (rdir); 1385 if ( (0 != setgid (pws->pw_gid)) ||
1106 pidfd = FOPEN (pif, "w"); 1386 (0 != setegid (pws->pw_gid)) ||
1107 if (NULL == pidfd) 1387#if HAVE_INITGROUPS
1388 (0 != initgroups (user,
1389 pws->pw_gid)) ||
1390#endif
1391 (0 != setuid (pws->pw_uid)) ||
1392 (0 != seteuid (pws->pw_uid)))
1108 { 1393 {
1109 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "fopen", pif); 1394 if ((0 != setregid (pws->pw_gid,
1110 GNUNET_free (pif); 1395 pws->pw_gid)) ||
1111 GNUNET_free_non_null (user); 1396 (0 != setreuid (pws->pw_uid,
1112 return GNUNET_SYSERR; 1397 pws->pw_uid)))
1398 {
1399 LOG (GNUNET_ERROR_TYPE_ERROR,
1400 _("Cannot change user/group to `%s': %s\n"),
1401 user,
1402 STRERROR (errno));
1403 GNUNET_free (user);
1404 return GNUNET_SYSERR;
1405 }
1113 } 1406 }
1114 if (0 > FPRINTF (pidfd, "%u", pid)) 1407#endif
1115 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fprintf", pif); 1408 GNUNET_free (user);
1116 GNUNET_break (0 == FCLOSE (pidfd));
1117 if ((NULL != user) && (0 < strlen (user)))
1118 GNUNET_DISK_file_change_owner (pif, user);
1119 GNUNET_free_non_null (user);
1120 GNUNET_free (pif);
1121 return GNUNET_OK; 1409 return GNUNET_OK;
1122} 1410}
1123 1411
1124 1412
1125/** 1413/**
1126 * Task run during shutdown. Stops the server/service. 1414 * Get the name of the file where we will
1415 * write the PID of the service.
1127 * 1416 *
1128 * @param cls the `struct GNUNET_SERVICE_Context` 1417 * @param sh service context
1418 * @return name of the file for the process ID
1129 */ 1419 */
1130static void 1420static char *
1131shutdown_task (void *cls) 1421get_pid_file_name (struct GNUNET_SERVICE_Handle *sh)
1132{ 1422{
1133 struct GNUNET_SERVICE_Context *service = cls; 1423 char *pif;
1134 struct GNUNET_SERVER_Handle *server = service->server;
1135 1424
1136 service->shutdown_task = NULL; 1425 if (GNUNET_OK !=
1137 if (0 != (service->options & GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN)) 1426 GNUNET_CONFIGURATION_get_value_filename (sh->cfg,
1138 GNUNET_SERVER_stop_listening (server); 1427 sh->service_name,
1139 else 1428 "PIDFILE",
1140 GNUNET_SERVER_destroy (server); 1429 &pif))
1430 return NULL;
1431 return pif;
1141} 1432}
1142 1433
1143 1434
1144/** 1435/**
1145 * Initial task for the service. 1436 * Delete the PID file that was created by our parent.
1146 * 1437 *
1147 * @param cls service context 1438 * @param sh service context
1148 */ 1439 */
1149static void 1440static void
1150service_task (void *cls) 1441pid_file_delete (struct GNUNET_SERVICE_Handle *sh)
1151{ 1442{
1152 struct GNUNET_SERVICE_Context *sctx = cls; 1443 char *pif = get_pid_file_name (sh);
1153 unsigned int i;
1154 1444
1155 (void) GNUNET_SPEEDUP_start_ (sctx->cfg); 1445 if (NULL == pif)
1156 GNUNET_RESOLVER_connect (sctx->cfg); 1446 return; /* no PID file */
1157 if (NULL != sctx->lsocks) 1447 if (0 != UNLINK (pif))
1158 sctx->server 1448 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING,
1159 = GNUNET_SERVER_create_with_sockets (&check_access, sctx, sctx->lsocks, 1449 "unlink",
1160 sctx->timeout, sctx->require_found); 1450 pif);
1161 else 1451 GNUNET_free (pif);
1162 sctx->server
1163 = GNUNET_SERVER_create (&check_access, sctx, sctx->addrs, sctx->addrlens,
1164 sctx->timeout, sctx->require_found);
1165 if (NULL == sctx->server)
1166 {
1167 if (NULL != sctx->addrs)
1168 for (i = 0; NULL != sctx->addrs[i]; i++)
1169 LOG (GNUNET_ERROR_TYPE_INFO,
1170 _("Failed to start `%s' at `%s'\n"),
1171 sctx->service_name, GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i]));
1172 sctx->ret = GNUNET_SYSERR;
1173 return;
1174 }
1175#ifndef WINDOWS
1176 if (NULL != sctx->addrs)
1177 for (i = 0; NULL != sctx->addrs[i]; i++)
1178 if ((AF_UNIX == sctx->addrs[i]->sa_family)
1179 && ('\0' != ((const struct sockaddr_un *)sctx->addrs[i])->sun_path[0]))
1180 GNUNET_DISK_fix_permissions (((const struct sockaddr_un *)sctx->addrs[i])->sun_path,
1181 sctx->match_uid,
1182 sctx->match_gid);
1183#endif
1184
1185
1186 if (0 == (sctx->options & GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN))
1187 {
1188 /* install a task that will kill the server
1189 * process if the scheduler ever gets a shutdown signal */
1190 sctx->shutdown_task = GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1191 sctx);
1192 }
1193 sctx->my_handlers = GNUNET_malloc (sizeof (defhandlers));
1194 GNUNET_memcpy (sctx->my_handlers, defhandlers, sizeof (defhandlers));
1195 i = 0;
1196 while (NULL != sctx->my_handlers[i].callback)
1197 sctx->my_handlers[i++].callback_cls = sctx;
1198 GNUNET_SERVER_add_handlers (sctx->server, sctx->my_handlers);
1199 if (-1 != sctx->ready_confirm_fd)
1200 {
1201 GNUNET_break (1 == WRITE (sctx->ready_confirm_fd, ".", 1));
1202 GNUNET_break (0 == CLOSE (sctx->ready_confirm_fd));
1203 sctx->ready_confirm_fd = -1;
1204 write_pid_file (sctx, getpid ());
1205 }
1206 if (NULL != sctx->addrs)
1207 {
1208 i = 0;
1209 while (NULL != sctx->addrs[i])
1210 {
1211 LOG (GNUNET_ERROR_TYPE_INFO, _("Service `%s' runs at %s\n"),
1212 sctx->service_name, GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i]));
1213 i++;
1214 }
1215 }
1216 sctx->task (sctx->task_cls, sctx->server, sctx->cfg);
1217} 1452}
1218 1453
1219 1454
1220/** 1455/**
1221 * Detach from terminal. 1456 * Detach from terminal.
1222 * 1457 *
1223 * @param sctx service context 1458 * @param sh service context
1224 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error 1459 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1225 */ 1460 */
1226static int 1461static int
1227detach_terminal (struct GNUNET_SERVICE_Context *sctx) 1462detach_terminal (struct GNUNET_SERVICE_Handle *sh)
1228{ 1463{
1229#ifndef MINGW 1464#ifndef MINGW
1230 pid_t pid; 1465 pid_t pid;
@@ -1233,13 +1468,15 @@ detach_terminal (struct GNUNET_SERVICE_Context *sctx)
1233 1468
1234 if (0 != PIPE (filedes)) 1469 if (0 != PIPE (filedes))
1235 { 1470 {
1236 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "pipe"); 1471 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
1472 "pipe");
1237 return GNUNET_SYSERR; 1473 return GNUNET_SYSERR;
1238 } 1474 }
1239 pid = fork (); 1475 pid = fork ();
1240 if (pid < 0) 1476 if (pid < 0)
1241 { 1477 {
1242 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fork"); 1478 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
1479 "fork");
1243 return GNUNET_SYSERR; 1480 return GNUNET_SYSERR;
1244 } 1481 }
1245 if (0 != pid) 1482 if (0 != pid)
@@ -1249,15 +1486,19 @@ detach_terminal (struct GNUNET_SERVICE_Context *sctx)
1249 1486
1250 GNUNET_break (0 == CLOSE (filedes[1])); 1487 GNUNET_break (0 == CLOSE (filedes[1]));
1251 c = 'X'; 1488 c = 'X';
1252 if (1 != READ (filedes[0], &c, sizeof (char))) 1489 if (1 != READ (filedes[0],
1253 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "read"); 1490 &c,
1491 sizeof (char)))
1492 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING,
1493 "read");
1254 fflush (stdout); 1494 fflush (stdout);
1255 switch (c) 1495 switch (c)
1256 { 1496 {
1257 case '.': 1497 case '.':
1258 exit (0); 1498 exit (0);
1259 case 'I': 1499 case 'I':
1260 LOG (GNUNET_ERROR_TYPE_INFO, _("Service process failed to initialize\n")); 1500 LOG (GNUNET_ERROR_TYPE_INFO,
1501 _("Service process failed to initialize\n"));
1261 break; 1502 break;
1262 case 'S': 1503 case 'S':
1263 LOG (GNUNET_ERROR_TYPE_INFO, 1504 LOG (GNUNET_ERROR_TYPE_INFO,
@@ -1273,13 +1514,16 @@ detach_terminal (struct GNUNET_SERVICE_Context *sctx)
1273 GNUNET_break (0 == CLOSE (0)); 1514 GNUNET_break (0 == CLOSE (0));
1274 GNUNET_break (0 == CLOSE (1)); 1515 GNUNET_break (0 == CLOSE (1));
1275 GNUNET_break (0 == CLOSE (filedes[0])); 1516 GNUNET_break (0 == CLOSE (filedes[0]));
1276 nullfd = OPEN ("/dev/null", O_RDWR | O_APPEND); 1517 nullfd = OPEN ("/dev/null",
1518 O_RDWR | O_APPEND);
1277 if (nullfd < 0) 1519 if (nullfd < 0)
1278 return GNUNET_SYSERR; 1520 return GNUNET_SYSERR;
1279 /* set stdin/stdout to /dev/null */ 1521 /* set stdin/stdout to /dev/null */
1280 if ((dup2 (nullfd, 0) < 0) || (dup2 (nullfd, 1) < 0)) 1522 if ( (dup2 (nullfd, 0) < 0) ||
1523 (dup2 (nullfd, 1) < 0) )
1281 { 1524 {
1282 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2"); 1525 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
1526 "dup2");
1283 (void) CLOSE (nullfd); 1527 (void) CLOSE (nullfd);
1284 return GNUNET_SYSERR; 1528 return GNUNET_SYSERR;
1285 } 1529 }
@@ -1287,8 +1531,9 @@ detach_terminal (struct GNUNET_SERVICE_Context *sctx)
1287 /* Detach from controlling terminal */ 1531 /* Detach from controlling terminal */
1288 pid = setsid (); 1532 pid = setsid ();
1289 if (-1 == pid) 1533 if (-1 == pid)
1290 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "setsid"); 1534 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
1291 sctx->ready_confirm_fd = filedes[1]; 1535 "setsid");
1536 sh->ready_confirm_fd = filedes[1];
1292#else 1537#else
1293 /* FIXME: we probably need to do something else 1538 /* FIXME: we probably need to do something else
1294 * elsewhere in order to fork the process itself... */ 1539 * elsewhere in order to fork the process itself... */
@@ -1299,144 +1544,228 @@ detach_terminal (struct GNUNET_SERVICE_Context *sctx)
1299 1544
1300 1545
1301/** 1546/**
1302 * Set user ID. 1547 * Tear down the service, closing the listen sockets and
1548 * freeing the ACLs.
1303 * 1549 *
1304 * @param sctx service context 1550 * @param sh handle to the service to tear down.
1305 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1306 */ 1551 */
1307static int 1552static void
1308set_user_id (struct GNUNET_SERVICE_Context *sctx) 1553teardown_service (struct GNUNET_SERVICE_Handle *sh)
1309{ 1554{
1310 char *user; 1555 struct ServiceListenContext *slc;
1311
1312 if (NULL == (user = get_user_name (sctx)))
1313 return GNUNET_OK; /* keep */
1314#ifndef MINGW
1315 struct passwd *pws;
1316 1556
1317 errno = 0; 1557 GNUNET_free_non_null (sh->v4_denied);
1318 pws = getpwnam (user); 1558 GNUNET_free_non_null (sh->v6_denied);
1319 if (NULL == pws) 1559 GNUNET_free_non_null (sh->v4_allowed);
1560 GNUNET_free_non_null (sh->v6_allowed);
1561 while (NULL != (slc = sh->slc_head))
1320 { 1562 {
1321 LOG (GNUNET_ERROR_TYPE_ERROR, 1563 GNUNET_CONTAINER_DLL_remove (sh->slc_head,
1322 _("Cannot obtain information about user `%s': %s\n"), user, 1564 sh->slc_tail,
1323 errno == 0 ? _("No such user") : STRERROR (errno)); 1565 slc);
1324 GNUNET_free (user); 1566 if (NULL != slc->listen_task)
1325 return GNUNET_SYSERR; 1567 GNUNET_SCHEDULER_cancel (slc->listen_task);
1568 GNUNET_break (GNUNET_OK ==
1569 GNUNET_NETWORK_socket_close (slc->listen_socket));
1570 GNUNET_free (slc);
1326 } 1571 }
1327 if ((0 != setgid (pws->pw_gid)) || (0 != setegid (pws->pw_gid)) || 1572}
1328#if HAVE_INITGROUPS 1573
1329 (0 != initgroups (user, pws->pw_gid)) || 1574
1330#endif 1575/**
1331 (0 != setuid (pws->pw_uid)) || (0 != seteuid (pws->pw_uid))) 1576 * Low-level function to start a service if the scheduler
1577 * is already running. Should only be used directly in
1578 * special cases.
1579 *
1580 * The function will launch the service with the name @a service_name
1581 * using the @a service_options to configure its shutdown
1582 * behavior. When clients connect or disconnect, the respective
1583 * @a connect_cb or @a disconnect_cb functions will be called. For
1584 * messages received from the clients, the respective @a handlers will
1585 * be invoked; for the closure of the handlers we use the return value
1586 * from the @a connect_cb invocation of the respective client.
1587 *
1588 * Each handler MUST call #GNUNET_SERVICE_client_continue() after each
1589 * message to receive further messages from this client. If
1590 * #GNUNET_SERVICE_client_continue() is not called within a short
1591 * time, a warning will be logged. If delays are expected, services
1592 * should call #GNUNET_SERVICE_client_disable_continue_warning() to
1593 * disable the warning.
1594 *
1595 * Clients sending invalid messages (based on @a handlers) will be
1596 * dropped. Additionally, clients can be dropped at any time using
1597 * #GNUNET_SERVICE_client_drop().
1598 *
1599 * The service must be stopped using #GNUNET_SERVICE_stop().
1600 *
1601 * @param service_name name of the service to run
1602 * @param cfg configuration to use
1603 * @param connect_cb function to call whenever a client connects
1604 * @param disconnect_cb function to call whenever a client disconnects
1605 * @param cls closure argument for @a connect_cb and @a disconnect_cb
1606 * @param handlers NULL-terminated array of message handlers for the service,
1607 * the closure will be set to the value returned by
1608 * the @a connect_cb for the respective connection
1609 * @return NULL on error
1610 */
1611struct GNUNET_SERVICE_Handle *
1612GNUNET_SERVICE_start (const char *service_name,
1613 const struct GNUNET_CONFIGURATION_Handle *cfg,
1614 GNUNET_SERVICE_ConnectHandler connect_cb,
1615 GNUNET_SERVICE_DisconnectHandler disconnect_cb,
1616 void *cls,
1617 const struct GNUNET_MQ_MessageHandler *handlers)
1618{
1619 struct GNUNET_SERVICE_Handle *sh;
1620
1621 sh = GNUNET_new (struct GNUNET_SERVICE_Handle);
1622 sh->service_name = service_name;
1623 sh->cfg = cfg;
1624 sh->connect_cb = connect_cb;
1625 sh->disconnect_cb = disconnect_cb;
1626 sh->cb_cls = cls;
1627 sh->handlers = GNUNET_MQ_copy_handlers (handlers);
1628 if (GNUNET_OK != setup_service (sh))
1332 { 1629 {
1333 if ((0 != setregid (pws->pw_gid, pws->pw_gid)) || 1630 GNUNET_free_non_null (sh->handlers);
1334 (0 != setreuid (pws->pw_uid, pws->pw_uid))) 1631 GNUNET_free (sh);
1335 { 1632 return NULL;
1336 LOG (GNUNET_ERROR_TYPE_ERROR, _("Cannot change user/group to `%s': %s\n"),
1337 user, STRERROR (errno));
1338 GNUNET_free (user);
1339 return GNUNET_SYSERR;
1340 }
1341 } 1633 }
1342#endif 1634 GNUNET_SERVICE_resume (sh);
1343 GNUNET_free (user); 1635 return sh;
1344 return GNUNET_OK;
1345} 1636}
1346 1637
1347 1638
1348/** 1639/**
1349 * Delete the PID file that was created by our parent. 1640 * Stops a service that was started with #GNUNET_SERVICE_start().
1350 * 1641 *
1351 * @param sctx service context 1642 * @param srv service to stop
1352 */ 1643 */
1353static void 1644void
1354pid_file_delete (struct GNUNET_SERVICE_Context *sctx) 1645GNUNET_SERVICE_stop (struct GNUNET_SERVICE_Handle *srv)
1355{ 1646{
1356 char *pif = get_pid_file_name (sctx); 1647 struct GNUNET_SERVICE_Client *client;
1357 1648
1358 if (NULL == pif) 1649 GNUNET_SERVICE_suspend (srv);
1359 return; /* no PID file */ 1650 while (NULL != (client = srv->clients_head))
1360 if (0 != UNLINK (pif)) 1651 GNUNET_SERVICE_client_drop (client);
1361 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", pif); 1652 teardown_service (srv);
1362 GNUNET_free (pif); 1653 GNUNET_free_non_null (srv->handlers);
1654 GNUNET_free (srv);
1363} 1655}
1364 1656
1365 1657
1366/** 1658/**
1367 * Run a standard GNUnet service startup sequence (initialize loggers 1659 * Creates the "main" function for a GNUnet service. You
1368 * and configuration, parse options). 1660 * should almost always use the #GNUNET_SERVICE_MAIN macro
1661 * instead of calling this function directly (except
1662 * for ARM, which should call this function directly).
1663 *
1664 * The function will launch the service with the name @a service_name
1665 * using the @a service_options to configure its shutdown
1666 * behavior. Once the service is ready, the @a init_cb will be called
1667 * for service-specific initialization. @a init_cb will be given the
1668 * service handler which can be used to control the service's
1669 * availability. When clients connect or disconnect, the respective
1670 * @a connect_cb or @a disconnect_cb functions will be called. For
1671 * messages received from the clients, the respective @a handlers will
1672 * be invoked; for the closure of the handlers we use the return value
1673 * from the @a connect_cb invocation of the respective client.
1369 * 1674 *
1370 * @param argc number of command line arguments 1675 * Each handler MUST call #GNUNET_SERVICE_client_continue() after each
1371 * @param argv command line arguments 1676 * message to receive further messages from this client. If
1372 * @param service_name our service name 1677 * #GNUNET_SERVICE_client_continue() is not called within a short
1373 * @param options service options 1678 * time, a warning will be logged. If delays are expected, services
1374 * @param task main task of the service 1679 * should call #GNUNET_SERVICE_client_disable_continue_warning() to
1375 * @param task_cls closure for @a task 1680 * disable the warning.
1376 * @return #GNUNET_SYSERR on error, #GNUNET_OK 1681 *
1377 * if we shutdown nicely 1682 * Clients sending invalid messages (based on @a handlers) will be
1683 * dropped. Additionally, clients can be dropped at any time using
1684 * #GNUNET_SERVICE_client_drop().
1685 *
1686 * @param argc number of command-line arguments in @a argv
1687 * @param argv array of command-line arguments
1688 * @param service_name name of the service to run
1689 * @param options options controlling shutdown of the service
1690 * @param service_init_cb function to call once the service is ready
1691 * @param connect_cb function to call whenever a client connects
1692 * @param disconnect_cb function to call whenever a client disconnects
1693 * @param cls closure argument for @a service_init_cb, @a connect_cb and @a disconnect_cb
1694 * @param handlers NULL-terminated array of message handlers for the service,
1695 * the closure will be set to the value returned by
1696 * the @a connect_cb for the respective connection
1697 * @return 0 on success, non-zero on error
1378 */ 1698 */
1379int 1699int
1380GNUNET_SERVICE_run (int argc, char *const *argv, 1700GNUNET_SERVICE_run_ (int argc,
1381 const char *service_name, 1701 char *const *argv,
1382 enum GNUNET_SERVICE_Options options, 1702 const char *service_name,
1383 GNUNET_SERVICE_Main task, 1703 enum GNUNET_SERVICE_Options options,
1384 void *task_cls) 1704 GNUNET_SERVICE_InitCallback service_init_cb,
1705 GNUNET_SERVICE_ConnectHandler connect_cb,
1706 GNUNET_SERVICE_DisconnectHandler disconnect_cb,
1707 void *cls,
1708 const struct GNUNET_MQ_MessageHandler *handlers)
1385{ 1709{
1386#define HANDLE_ERROR do { GNUNET_break (0); goto shutdown; } while (0) 1710 struct GNUNET_SERVICE_Handle sh;
1387 1711 char *cfg_filename;
1388 int err; 1712 char *opt_cfg_filename;
1389 int ret;
1390 char *cfg_fn;
1391 char *opt_cfg_fn;
1392 char *loglev; 1713 char *loglev;
1714 const char *xdg;
1393 char *logfile; 1715 char *logfile;
1394 int do_daemonize; 1716 int do_daemonize;
1395 unsigned int i;
1396 unsigned long long skew_offset; 1717 unsigned long long skew_offset;
1397 unsigned long long skew_variance; 1718 unsigned long long skew_variance;
1398 long long clock_offset; 1719 long long clock_offset;
1399 struct GNUNET_SERVICE_Context sctx;
1400 struct GNUNET_CONFIGURATION_Handle *cfg; 1720 struct GNUNET_CONFIGURATION_Handle *cfg;
1401 const char *xdg; 1721 int ret;
1722 int err;
1402 1723
1403 struct GNUNET_GETOPT_CommandLineOption service_options[] = { 1724 struct GNUNET_GETOPT_CommandLineOption service_options[] = {
1404 GNUNET_GETOPT_OPTION_CFG_FILE (&opt_cfg_fn), 1725 GNUNET_GETOPT_OPTION_CFG_FILE (&opt_cfg_filename),
1405 {'d', "daemonize", NULL, 1726 GNUNET_GETOPT_OPTION_SET_ONE ('d',
1406 gettext_noop ("do daemonize (detach from terminal)"), 0, 1727 "daemonize",
1407 GNUNET_GETOPT_set_one, &do_daemonize}, 1728 gettext_noop ("do daemonize (detach from terminal)"),
1729 &do_daemonize),
1408 GNUNET_GETOPT_OPTION_HELP (NULL), 1730 GNUNET_GETOPT_OPTION_HELP (NULL),
1409 GNUNET_GETOPT_OPTION_LOGLEVEL (&loglev), 1731 GNUNET_GETOPT_OPTION_LOGLEVEL (&loglev),
1410 GNUNET_GETOPT_OPTION_LOGFILE (&logfile), 1732 GNUNET_GETOPT_OPTION_LOGFILE (&logfile),
1411 GNUNET_GETOPT_OPTION_VERSION (PACKAGE_VERSION " " VCS_VERSION), 1733 GNUNET_GETOPT_OPTION_VERSION (PACKAGE_VERSION " " VCS_VERSION),
1412 GNUNET_GETOPT_OPTION_END 1734 GNUNET_GETOPT_OPTION_END
1413 }; 1735 };
1736
1414 err = 1; 1737 err = 1;
1415 do_daemonize = 0; 1738 memset (&sh,
1416 logfile = NULL; 1739 0,
1417 loglev = NULL; 1740 sizeof (sh));
1418 opt_cfg_fn = NULL;
1419 xdg = getenv ("XDG_CONFIG_HOME"); 1741 xdg = getenv ("XDG_CONFIG_HOME");
1420 if (NULL != xdg) 1742 if (NULL != xdg)
1421 GNUNET_asprintf (&cfg_fn, 1743 GNUNET_asprintf (&cfg_filename,
1422 "%s%s%s", 1744 "%s%s%s",
1423 xdg, 1745 xdg,
1424 DIR_SEPARATOR_STR, 1746 DIR_SEPARATOR_STR,
1425 GNUNET_OS_project_data_get ()->config_file); 1747 GNUNET_OS_project_data_get ()->config_file);
1426 else 1748 else
1427 cfg_fn = GNUNET_strdup (GNUNET_OS_project_data_get ()->user_config_file); 1749 cfg_filename = GNUNET_strdup (GNUNET_OS_project_data_get ()->user_config_file);
1428 memset (&sctx, 0, sizeof (sctx)); 1750 sh.ready_confirm_fd = -1;
1429 sctx.options = options; 1751 sh.options = options;
1430 sctx.ready_confirm_fd = -1; 1752 sh.cfg = cfg = GNUNET_CONFIGURATION_create ();
1431 sctx.ret = GNUNET_OK; 1753 sh.service_init_cb = service_init_cb;
1432 sctx.timeout = GNUNET_TIME_UNIT_FOREVER_REL; 1754 sh.connect_cb = connect_cb;
1433 sctx.task = task; 1755 sh.disconnect_cb = disconnect_cb;
1434 sctx.task_cls = task_cls; 1756 sh.cb_cls = cls;
1435 sctx.service_name = service_name; 1757 sh.handlers = GNUNET_MQ_copy_handlers (handlers);
1436 sctx.cfg = cfg = GNUNET_CONFIGURATION_create (); 1758 sh.service_name = service_name;
1437 1759
1438 /* setup subsystems */ 1760 /* setup subsystems */
1439 ret = GNUNET_GETOPT_run (service_name, service_options, argc, argv); 1761 loglev = NULL;
1762 logfile = NULL;
1763 opt_cfg_filename = NULL;
1764 do_daemonize = 0;
1765 ret = GNUNET_GETOPT_run (service_name,
1766 service_options,
1767 argc,
1768 argv);
1440 if (GNUNET_SYSERR == ret) 1769 if (GNUNET_SYSERR == ret)
1441 goto shutdown; 1770 goto shutdown;
1442 if (GNUNET_NO == ret) 1771 if (GNUNET_NO == ret)
@@ -1444,254 +1773,844 @@ GNUNET_SERVICE_run (int argc, char *const *argv,
1444 err = 0; 1773 err = 0;
1445 goto shutdown; 1774 goto shutdown;
1446 } 1775 }
1447 if (GNUNET_OK != GNUNET_log_setup (service_name, loglev, logfile)) 1776 if (GNUNET_OK != GNUNET_log_setup (service_name,
1448 HANDLE_ERROR; 1777 loglev,
1449 if (NULL == opt_cfg_fn) 1778 logfile))
1450 opt_cfg_fn = GNUNET_strdup (cfg_fn); 1779 {
1451 if (GNUNET_YES == GNUNET_DISK_file_test (opt_cfg_fn)) 1780 GNUNET_break (0);
1781 goto shutdown;
1782 }
1783 if (NULL == opt_cfg_filename)
1784 opt_cfg_filename = GNUNET_strdup (cfg_filename);
1785 if (GNUNET_YES == GNUNET_DISK_file_test (opt_cfg_filename))
1452 { 1786 {
1453 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, opt_cfg_fn)) 1787 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg,
1788 opt_cfg_filename))
1454 { 1789 {
1455 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1790 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1456 _("Malformed configuration file `%s', exit ...\n"), 1791 _("Malformed configuration file `%s', exit ...\n"),
1457 opt_cfg_fn); 1792 opt_cfg_filename);
1458 goto shutdown; 1793 goto shutdown;
1459 } 1794 }
1460 } 1795 }
1461 else 1796 else
1462 { 1797 {
1463 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, NULL)) 1798 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg,
1799 NULL))
1464 { 1800 {
1465 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1801 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1466 _("Malformed configuration, exit ...\n")); 1802 _("Malformed configuration, exit ...\n"));
1467 goto shutdown; 1803 goto shutdown;
1468 } 1804 }
1469 if (0 != strcmp (opt_cfg_fn, cfg_fn)) 1805 if (0 != strcmp (opt_cfg_filename,
1806 cfg_filename))
1470 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1807 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1471 _("Could not access configuration file `%s'\n"), 1808 _("Could not access configuration file `%s'\n"),
1472 opt_cfg_fn); 1809 opt_cfg_filename);
1473 } 1810 }
1474 if (GNUNET_OK != setup_service (&sctx)) 1811 if (GNUNET_OK != setup_service (&sh))
1475 goto shutdown; 1812 goto shutdown;
1476 if ((1 == do_daemonize) && (GNUNET_OK != detach_terminal (&sctx))) 1813 if ( (1 == do_daemonize) &&
1477 HANDLE_ERROR; 1814 (GNUNET_OK != detach_terminal (&sh)) )
1478 if (GNUNET_OK != set_user_id (&sctx)) 1815 {
1816 GNUNET_break (0);
1817 goto shutdown;
1818 }
1819 if (GNUNET_OK != set_user_id (&sh))
1479 goto shutdown; 1820 goto shutdown;
1480 LOG (GNUNET_ERROR_TYPE_DEBUG, 1821 LOG (GNUNET_ERROR_TYPE_DEBUG,
1481 "Service `%s' runs with configuration from `%s'\n", 1822 "Service `%s' runs with configuration from `%s'\n",
1482 service_name, 1823 service_name,
1483 opt_cfg_fn); 1824 opt_cfg_filename);
1484 if ((GNUNET_OK == 1825 if ((GNUNET_OK ==
1485 GNUNET_CONFIGURATION_get_value_number (sctx.cfg, "TESTING", 1826 GNUNET_CONFIGURATION_get_value_number (sh.cfg,
1486 "SKEW_OFFSET", &skew_offset)) && 1827 "TESTING",
1828 "SKEW_OFFSET",
1829 &skew_offset)) &&
1487 (GNUNET_OK == 1830 (GNUNET_OK ==
1488 GNUNET_CONFIGURATION_get_value_number (sctx.cfg, "TESTING", 1831 GNUNET_CONFIGURATION_get_value_number (sh.cfg,
1489 "SKEW_VARIANCE", &skew_variance))) 1832 "TESTING",
1833 "SKEW_VARIANCE",
1834 &skew_variance)))
1490 { 1835 {
1491 clock_offset = skew_offset - skew_variance; 1836 clock_offset = skew_offset - skew_variance;
1492 GNUNET_TIME_set_offset (clock_offset); 1837 GNUNET_TIME_set_offset (clock_offset);
1493 LOG (GNUNET_ERROR_TYPE_DEBUG, "Skewing clock by %dll ms\n", clock_offset); 1838 LOG (GNUNET_ERROR_TYPE_DEBUG,
1839 "Skewing clock by %dll ms\n",
1840 clock_offset);
1494 } 1841 }
1842 GNUNET_RESOLVER_connect (sh.cfg);
1843
1495 /* actually run service */ 1844 /* actually run service */
1496 err = 0; 1845 err = 0;
1497 GNUNET_SCHEDULER_run (&service_task, &sctx); 1846 GNUNET_SCHEDULER_run (&service_main,
1847 &sh);
1498 /* shutdown */ 1848 /* shutdown */
1499 if ((1 == do_daemonize) && (NULL != sctx.server)) 1849 if (1 == do_daemonize)
1500 pid_file_delete (&sctx); 1850 pid_file_delete (&sh);
1501 GNUNET_free_non_null (sctx.my_handlers);
1502 1851
1503shutdown: 1852shutdown:
1504 if (-1 != sctx.ready_confirm_fd) 1853 if (-1 != sh.ready_confirm_fd)
1505 { 1854 {
1506 if (1 != WRITE (sctx.ready_confirm_fd, err ? "I" : "S", 1)) 1855 if (1 != WRITE (sh.ready_confirm_fd,
1507 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "write"); 1856 err ? "I" : "S",
1508 GNUNET_break (0 == CLOSE (sctx.ready_confirm_fd)); 1857 1))
1858 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING,
1859 "write");
1860 GNUNET_break (0 == CLOSE (sh.ready_confirm_fd));
1509 } 1861 }
1510#if HAVE_MALLINFO 1862#if HAVE_MALLINFO
1511 { 1863 {
1512 char *counter; 1864 char *counter;
1513 1865
1514 if ( (GNUNET_YES == 1866 if ( (GNUNET_YES ==
1515 GNUNET_CONFIGURATION_have_value (sctx.cfg, service_name, 1867 GNUNET_CONFIGURATION_have_value (sh.cfg,
1868 service_name,
1516 "GAUGER_HEAP")) && 1869 "GAUGER_HEAP")) &&
1517 (GNUNET_OK == 1870 (GNUNET_OK ==
1518 GNUNET_CONFIGURATION_get_value_string (sctx.cfg, service_name, 1871 GNUNET_CONFIGURATION_get_value_string (sh.cfg,
1872 service_name,
1519 "GAUGER_HEAP", 1873 "GAUGER_HEAP",
1520 &counter)) ) 1874 &counter)) )
1521 { 1875 {
1522 struct mallinfo mi; 1876 struct mallinfo mi;
1523 1877
1524 mi = mallinfo (); 1878 mi = mallinfo ();
1525 GAUGER (service_name, counter, mi.usmblks, "blocks"); 1879 GAUGER (service_name,
1880 counter,
1881 mi.usmblks,
1882 "blocks");
1526 GNUNET_free (counter); 1883 GNUNET_free (counter);
1527 } 1884 }
1528 } 1885 }
1529#endif 1886#endif
1887 teardown_service (&sh);
1888 GNUNET_free_non_null (sh.handlers);
1530 GNUNET_SPEEDUP_stop_ (); 1889 GNUNET_SPEEDUP_stop_ ();
1531 GNUNET_CONFIGURATION_destroy (cfg); 1890 GNUNET_CONFIGURATION_destroy (cfg);
1532 i = 0;
1533 if (NULL != sctx.addrs)
1534 while (NULL != sctx.addrs[i])
1535 GNUNET_free (sctx.addrs[i++]);
1536 GNUNET_free_non_null (sctx.addrs);
1537 GNUNET_free_non_null (sctx.addrlens);
1538 GNUNET_free_non_null (logfile); 1891 GNUNET_free_non_null (logfile);
1539 GNUNET_free_non_null (loglev); 1892 GNUNET_free_non_null (loglev);
1540 GNUNET_free (cfg_fn); 1893 GNUNET_free (cfg_filename);
1541 GNUNET_free_non_null (opt_cfg_fn); 1894 GNUNET_free_non_null (opt_cfg_filename);
1542 GNUNET_free_non_null (sctx.v4_denied); 1895
1543 GNUNET_free_non_null (sctx.v6_denied); 1896 return err ? GNUNET_SYSERR : sh.ret;
1544 GNUNET_free_non_null (sctx.v4_allowed);
1545 GNUNET_free_non_null (sctx.v6_allowed);
1546
1547 return err ? GNUNET_SYSERR : sctx.ret;
1548} 1897}
1549 1898
1550 1899
1551/** 1900/**
1552 * Run a service startup sequence within an existing 1901 * Suspend accepting connections from the listen socket temporarily.
1553 * initialized system. 1902 * Resume activity using #GNUNET_SERVICE_resume.
1554 * 1903 *
1555 * @param service_name our service name 1904 * @param sh service to stop accepting connections.
1556 * @param cfg configuration to use
1557 * @param options service options
1558 * @return NULL on error, service handle
1559 */ 1905 */
1560struct GNUNET_SERVICE_Context * 1906void
1561GNUNET_SERVICE_start (const char *service_name, 1907GNUNET_SERVICE_suspend (struct GNUNET_SERVICE_Handle *sh)
1562 const struct GNUNET_CONFIGURATION_Handle *cfg,
1563 enum GNUNET_SERVICE_Options options)
1564{ 1908{
1565 int i; 1909 struct ServiceListenContext *slc;
1566 struct GNUNET_SERVICE_Context *sctx;
1567 1910
1568 sctx = GNUNET_new (struct GNUNET_SERVICE_Context); 1911 for (slc = sh->slc_head; NULL != slc; slc = slc->next)
1569 sctx->ready_confirm_fd = -1; /* no daemonizing */ 1912 {
1570 sctx->ret = GNUNET_OK; 1913 if (NULL != slc->listen_task)
1571 sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL; 1914 {
1572 sctx->service_name = service_name; 1915 GNUNET_SCHEDULER_cancel (slc->listen_task);
1573 sctx->cfg = cfg; 1916 slc->listen_task = NULL;
1574 sctx->options = options; 1917 }
1918 }
1919}
1575 1920
1576 /* setup subsystems */ 1921
1577 if (GNUNET_OK != setup_service (sctx)) 1922/**
1923 * Task run when we are ready to transmit data to the
1924 * client.
1925 *
1926 * @param cls the `struct GNUNET_SERVICE_Client *` to send to
1927 */
1928static void
1929do_send (void *cls)
1930{
1931 struct GNUNET_SERVICE_Client *client = cls;
1932 ssize_t ret;
1933 size_t left;
1934 const char *buf;
1935
1936 client->send_task = NULL;
1937 buf = (const char *) client->msg;
1938 left = ntohs (client->msg->size) - client->msg_pos;
1939 ret = GNUNET_NETWORK_socket_send (client->sock,
1940 &buf[client->msg_pos],
1941 left);
1942 GNUNET_assert (ret <= (ssize_t) left);
1943 if (0 == ret)
1578 { 1944 {
1579 GNUNET_SERVICE_stop (sctx); 1945 GNUNET_MQ_inject_error (client->mq,
1580 return NULL; 1946 GNUNET_MQ_ERROR_WRITE);
1947 return;
1581 } 1948 }
1582 if (NULL != sctx->lsocks) 1949 if (-1 == ret)
1583 sctx->server = 1950 {
1584 GNUNET_SERVER_create_with_sockets (&check_access, sctx, sctx->lsocks, 1951 if ( (EAGAIN == errno) ||
1585 sctx->timeout, sctx->require_found); 1952 (EINTR == errno) )
1586 else 1953 {
1587 sctx->server = 1954 /* ignore */
1588 GNUNET_SERVER_create (&check_access, sctx, sctx->addrs, sctx->addrlens, 1955 ret = 0;
1589 sctx->timeout, sctx->require_found); 1956 }
1957 else
1958 {
1959 if (EPIPE != errno)
1960 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
1961 "send");
1962 GNUNET_MQ_inject_error (client->mq,
1963 GNUNET_MQ_ERROR_WRITE);
1964 return;
1965 }
1966 }
1967 if (0 == client->msg_pos)
1968 {
1969 GNUNET_MQ_impl_send_in_flight (client->mq);
1970 }
1971 client->msg_pos += ret;
1972 if (left > ret)
1973 {
1974 GNUNET_assert (NULL == client->drop_task);
1975 client->send_task
1976 = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
1977 client->sock,
1978 &do_send,
1979 client);
1980 return;
1981 }
1982 GNUNET_MQ_impl_send_continue (client->mq);
1983}
1984
1590 1985
1591 if (NULL == sctx->server) 1986/**
1987 * Signature of functions implementing the sending functionality of a
1988 * message queue.
1989 *
1990 * @param mq the message queue
1991 * @param msg the message to send
1992 * @param impl_state our `struct GNUNET_SERVICE_Client *`
1993 */
1994static void
1995service_mq_send (struct GNUNET_MQ_Handle *mq,
1996 const struct GNUNET_MessageHeader *msg,
1997 void *impl_state)
1998{
1999 struct GNUNET_SERVICE_Client *client = impl_state;
2000
2001 if (NULL != client->drop_task)
2002 return; /* we're going down right now, do not try to send */
2003 GNUNET_assert (NULL == client->send_task);
2004 LOG (GNUNET_ERROR_TYPE_DEBUG,
2005 "Sending message of type %u and size %u to client\n",
2006 ntohs (msg->type),
2007 ntohs (msg->size));
2008 client->msg = msg;
2009 client->msg_pos = 0;
2010 client->send_task
2011 = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
2012 client->sock,
2013 &do_send,
2014 client);
2015}
2016
2017
2018/**
2019 * Implementation function that cancels the currently sent message.
2020 *
2021 * @param mq message queue
2022 * @param impl_state state specific to the implementation
2023 */
2024static void
2025service_mq_cancel (struct GNUNET_MQ_Handle *mq,
2026 void *impl_state)
2027{
2028 struct GNUNET_SERVICE_Client *client = impl_state;
2029
2030 GNUNET_assert (0 == client->msg_pos);
2031 client->msg = NULL;
2032 GNUNET_SCHEDULER_cancel (client->send_task);
2033 client->send_task = NULL;
2034}
2035
2036
2037/**
2038 * Generic error handler, called with the appropriate
2039 * error code and the same closure specified at the creation of
2040 * the message queue.
2041 * Not every message queue implementation supports an error handler.
2042 *
2043 * @param cls closure with our `struct GNUNET_SERVICE_Client`
2044 * @param error error code
2045 */
2046static void
2047service_mq_error_handler (void *cls,
2048 enum GNUNET_MQ_Error error)
2049{
2050 struct GNUNET_SERVICE_Client *client = cls;
2051 struct GNUNET_SERVICE_Handle *sh = client->sh;
2052
2053 if ( (GNUNET_MQ_ERROR_NO_MATCH == error) &&
2054 (GNUNET_NO == sh->require_found) )
1592 { 2055 {
1593 GNUNET_SERVICE_stop (sctx); 2056 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1594 return NULL; 2057 "No handler for message of type %u found\n",
2058 (unsigned int) client->warn_type);
2059 GNUNET_SERVICE_client_continue (client);
2060 return; /* ignore error */
2061 }
2062 GNUNET_SERVICE_client_drop (client);
2063}
2064
2065
2066/**
2067 * Task run to warn about missing calls to #GNUNET_SERVICE_client_continue().
2068 *
2069 * @param cls our `struct GNUNET_SERVICE_Client *` to process more requests from
2070 */
2071static void
2072warn_no_client_continue (void *cls)
2073{
2074 struct GNUNET_SERVICE_Client *client = cls;
2075
2076 GNUNET_break (0 != client->warn_type); /* type should never be 0 here, as we don't use 0 */
2077 client->warn_task
2078 = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
2079 &warn_no_client_continue,
2080 client);
2081 LOG (GNUNET_ERROR_TYPE_WARNING,
2082 _("Processing code for message of type %u did not call `GNUNET_SERVICE_client_continue' after %s\n"),
2083 (unsigned int) client->warn_type,
2084 GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (client->warn_start),
2085 GNUNET_YES));
2086}
2087
2088
2089/**
2090 * Functions with this signature are called whenever a
2091 * complete message is received by the tokenizer for a client.
2092 *
2093 * Do not call #GNUNET_MST_destroy() from within
2094 * the scope of this callback.
2095 *
2096 * @param cls closure with the `struct GNUNET_SERVICE_Client *`
2097 * @param message the actual message
2098 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the client was dropped
2099 */
2100static int
2101service_client_mst_cb (void *cls,
2102 const struct GNUNET_MessageHeader *message)
2103{
2104 struct GNUNET_SERVICE_Client *client = cls;
2105
2106 LOG (GNUNET_ERROR_TYPE_DEBUG,
2107 "Received message of type %u and size %u from client\n",
2108 ntohs (message->type),
2109 ntohs (message->size));
2110 GNUNET_assert (GNUNET_NO == client->needs_continue);
2111 client->needs_continue = GNUNET_YES;
2112 client->warn_type = ntohs (message->type);
2113 client->warn_start = GNUNET_TIME_absolute_get ();
2114 GNUNET_assert (NULL == client->warn_task);
2115 client->warn_task
2116 = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
2117 &warn_no_client_continue,
2118 client);
2119 GNUNET_MQ_inject_message (client->mq,
2120 message);
2121 if (NULL != client->drop_task)
2122 return GNUNET_SYSERR;
2123 return GNUNET_OK;
2124}
2125
2126
2127/**
2128 * A client sent us data. Receive and process it. If we are done,
2129 * reschedule this task.
2130 *
2131 * @param cls the `struct GNUNET_SERVICE_Client` that sent us data.
2132 */
2133static void
2134service_client_recv (void *cls)
2135{
2136 struct GNUNET_SERVICE_Client *client = cls;
2137 int ret;
2138
2139 client->recv_task = NULL;
2140 ret = GNUNET_MST_read (client->mst,
2141 client->sock,
2142 GNUNET_NO,
2143 GNUNET_YES);
2144 if (GNUNET_SYSERR == ret)
2145 {
2146 /* client closed connection (or IO error) */
2147 if (NULL == client->drop_task)
2148 {
2149 GNUNET_assert (GNUNET_NO == client->needs_continue);
2150 GNUNET_SERVICE_client_drop (client);
2151 }
2152 return;
2153 }
2154 if (GNUNET_NO == ret)
2155 return; /* more messages in buffer, wait for application
2156 to be done processing */
2157 GNUNET_assert (GNUNET_OK == ret);
2158 if (GNUNET_YES == client->needs_continue)
2159 return;
2160 if (NULL != client->recv_task)
2161 return;
2162 /* MST needs more data, re-schedule read job */
2163 client->recv_task
2164 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
2165 client->sock,
2166 &service_client_recv,
2167 client);
2168}
2169
2170
2171/**
2172 * We have successfully accepted a connection from a client. Now
2173 * setup the client (with the scheduler) and tell the application.
2174 *
2175 * @param sh service that accepted the client
2176 * @param sock socket associated with the client
2177 */
2178static void
2179start_client (struct GNUNET_SERVICE_Handle *sh,
2180 struct GNUNET_NETWORK_Handle *csock)
2181{
2182 struct GNUNET_SERVICE_Client *client;
2183
2184 client = GNUNET_new (struct GNUNET_SERVICE_Client);
2185 GNUNET_CONTAINER_DLL_insert (sh->clients_head,
2186 sh->clients_tail,
2187 client);
2188 client->sh = sh;
2189 client->sock = csock;
2190 client->mq = GNUNET_MQ_queue_for_callbacks (&service_mq_send,
2191 NULL,
2192 &service_mq_cancel,
2193 client,
2194 sh->handlers,
2195 &service_mq_error_handler,
2196 client);
2197 client->mst = GNUNET_MST_create (&service_client_mst_cb,
2198 client);
2199 if (NULL != sh->connect_cb)
2200 client->user_context = sh->connect_cb (sh->cb_cls,
2201 client,
2202 client->mq);
2203 GNUNET_MQ_set_handlers_closure (client->mq,
2204 client->user_context);
2205 client->recv_task
2206 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
2207 client->sock,
2208 &service_client_recv,
2209 client);
2210}
2211
2212
2213/**
2214 * Check if the given IP address is in the list of IP addresses.
2215 *
2216 * @param list a list of networks
2217 * @param add the IP to check (in network byte order)
2218 * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is
2219 */
2220static int
2221check_ipv4_listed (const struct GNUNET_STRINGS_IPv4NetworkPolicy *list,
2222 const struct in_addr *add)
2223{
2224 unsigned int i;
2225
2226 if (NULL == list)
2227 return GNUNET_NO;
2228 i = 0;
2229 while ( (0 != list[i].network.s_addr) ||
2230 (0 != list[i].netmask.s_addr) )
2231 {
2232 if ((add->s_addr & list[i].netmask.s_addr) ==
2233 (list[i].network.s_addr & list[i].netmask.s_addr))
2234 return GNUNET_YES;
2235 i++;
2236 }
2237 return GNUNET_NO;
2238}
2239
2240
2241/**
2242 * Check if the given IP address is in the list of IP addresses.
2243 *
2244 * @param list a list of networks
2245 * @param ip the IP to check (in network byte order)
2246 * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is
2247 */
2248static int
2249check_ipv6_listed (const struct GNUNET_STRINGS_IPv6NetworkPolicy *list,
2250 const struct in6_addr *ip)
2251{
2252 unsigned int i;
2253 unsigned int j;
2254 struct in6_addr zero;
2255
2256 if (NULL == list)
2257 return GNUNET_NO;
2258 memset (&zero,
2259 0,
2260 sizeof (struct in6_addr));
2261 i = 0;
2262NEXT:
2263 while (0 != memcmp (&zero,
2264 &list[i].network,
2265 sizeof (struct in6_addr)))
2266 {
2267 for (j = 0; j < sizeof (struct in6_addr) / sizeof (int); j++)
2268 if (((((int *) ip)[j] & ((int *) &list[i].netmask)[j])) !=
2269 (((int *) &list[i].network)[j] & ((int *) &list[i].netmask)[j]))
2270 {
2271 i++;
2272 goto NEXT;
2273 }
2274 return GNUNET_YES;
1595 } 2275 }
2276 return GNUNET_NO;
2277}
2278
2279
2280/**
2281 * We have a client. Accept the incoming socket(s) (and reschedule
2282 * the listen task).
2283 *
2284 * @param cls the `struct ServiceListenContext` of the ready listen socket
2285 */
2286static void
2287accept_client (void *cls)
2288{
2289 struct ServiceListenContext *slc = cls;
2290 struct GNUNET_SERVICE_Handle *sh = slc->sh;
2291
2292 slc->listen_task = NULL;
2293 while (1)
2294 {
2295 struct GNUNET_NETWORK_Handle *sock;
2296 const struct sockaddr_in *v4;
2297 const struct sockaddr_in6 *v6;
2298 struct sockaddr_storage sa;
2299 socklen_t addrlen;
2300 int ok;
2301
2302 addrlen = sizeof (sa);
2303 sock = GNUNET_NETWORK_socket_accept (slc->listen_socket,
2304 (struct sockaddr *) &sa,
2305 &addrlen);
2306 if (NULL == sock)
2307 break;
2308 switch (sa.ss_family)
2309 {
2310 case AF_INET:
2311 GNUNET_assert (addrlen == sizeof (struct sockaddr_in));
2312 v4 = (const struct sockaddr_in *) &sa;
2313 ok = ( ( (NULL == sh->v4_allowed) ||
2314 (check_ipv4_listed (sh->v4_allowed,
2315 &v4->sin_addr))) &&
2316 ( (NULL == sh->v4_denied) ||
2317 (! check_ipv4_listed (sh->v4_denied,
2318 &v4->sin_addr)) ) );
2319 break;
2320 case AF_INET6:
2321 GNUNET_assert (addrlen == sizeof (struct sockaddr_in6));
2322 v6 = (const struct sockaddr_in6 *) &sa;
2323 ok = ( ( (NULL == sh->v6_allowed) ||
2324 (check_ipv6_listed (sh->v6_allowed,
2325 &v6->sin6_addr))) &&
2326 ( (NULL == sh->v6_denied) ||
2327 (! check_ipv6_listed (sh->v6_denied,
2328 &v6->sin6_addr)) ) );
2329 break;
1596#ifndef WINDOWS 2330#ifndef WINDOWS
1597 if (NULL != sctx->addrs) 2331 case AF_UNIX:
1598 for (i = 0; NULL != sctx->addrs[i]; i++) 2332 ok = GNUNET_OK; /* controlled using file-system ACL now */
1599 if ((AF_UNIX == sctx->addrs[i]->sa_family) 2333 break;
1600 && ('\0' != ((const struct sockaddr_un *)sctx->addrs[i])->sun_path[0]))
1601 GNUNET_DISK_fix_permissions (((const struct sockaddr_un *)sctx->addrs[i])->sun_path,
1602 sctx->match_uid,
1603 sctx->match_gid);
1604#endif 2334#endif
1605 sctx->my_handlers = GNUNET_malloc (sizeof (defhandlers)); 2335 default:
1606 GNUNET_memcpy (sctx->my_handlers, defhandlers, sizeof (defhandlers)); 2336 LOG (GNUNET_ERROR_TYPE_WARNING,
1607 i = 0; 2337 _("Unknown address family %d\n"),
1608 while ((sctx->my_handlers[i].callback != NULL)) 2338 sa.ss_family);
1609 sctx->my_handlers[i++].callback_cls = sctx; 2339 return;
1610 GNUNET_SERVER_add_handlers (sctx->server, sctx->my_handlers); 2340 }
1611 return sctx; 2341 if (! ok)
2342 {
2343 LOG (GNUNET_ERROR_TYPE_DEBUG,
2344 "Service rejected incoming connection from %s due to policy.\n",
2345 GNUNET_a2s ((const struct sockaddr *) &sa,
2346 addrlen));
2347 GNUNET_break (GNUNET_OK ==
2348 GNUNET_NETWORK_socket_close (sock));
2349 continue;
2350 }
2351 LOG (GNUNET_ERROR_TYPE_DEBUG,
2352 "Service accepted incoming connection from %s.\n",
2353 GNUNET_a2s ((const struct sockaddr *) &sa,
2354 addrlen));
2355 start_client (slc->sh,
2356 sock);
2357 }
2358 slc->listen_task
2359 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
2360 slc->listen_socket,
2361 &accept_client,
2362 slc);
2363}
2364
2365
2366/**
2367 * Resume accepting connections from the listen socket.
2368 *
2369 * @param sh service to resume accepting connections.
2370 */
2371void
2372GNUNET_SERVICE_resume (struct GNUNET_SERVICE_Handle *sh)
2373{
2374 struct ServiceListenContext *slc;
2375
2376 for (slc = sh->slc_head; NULL != slc; slc = slc->next)
2377 {
2378 GNUNET_assert (NULL == slc->listen_task);
2379 slc->listen_task
2380 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
2381 slc->listen_socket,
2382 &accept_client,
2383 slc);
2384 }
1612} 2385}
1613 2386
1614 2387
1615/** 2388/**
1616 * Obtain the server used by a service. Note that the server must NOT 2389 * Task run to resume receiving data from the client after
1617 * be destroyed by the caller. 2390 * the client called #GNUNET_SERVICE_client_continue().
1618 * 2391 *
1619 * @param ctx the service context returned from the start function 2392 * @param cls our `struct GNUNET_SERVICE_Client`
1620 * @return handle to the server for this service, NULL if there is none
1621 */ 2393 */
1622struct GNUNET_SERVER_Handle * 2394static void
1623GNUNET_SERVICE_get_server (struct GNUNET_SERVICE_Context *ctx) 2395resume_client_receive (void *cls)
1624{ 2396{
1625 return ctx->server; 2397 struct GNUNET_SERVICE_Client *c = cls;
2398 int ret;
2399
2400 c->recv_task = NULL;
2401 /* first, check if there is still something in the buffer */
2402 ret = GNUNET_MST_next (c->mst,
2403 GNUNET_YES);
2404 if (GNUNET_SYSERR == ret)
2405 {
2406 if (NULL != c->drop_task)
2407 GNUNET_SERVICE_client_drop (c);
2408 return;
2409 }
2410 if (GNUNET_NO == ret)
2411 return; /* done processing, wait for more later */
2412 GNUNET_assert (GNUNET_OK == ret);
2413 if (GNUNET_YES == c->needs_continue)
2414 return; /* #GNUNET_MST_next() did give a message to the client */
2415 /* need to receive more data from the network first */
2416 if (NULL != c->recv_task)
2417 return;
2418 c->recv_task
2419 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
2420 c->sock,
2421 &service_client_recv,
2422 c);
1626} 2423}
1627 2424
1628 2425
1629/** 2426/**
1630 * Get the NULL-terminated array of listen sockets for this service. 2427 * Continue receiving further messages from the given client.
2428 * Must be called after each message received.
1631 * 2429 *
1632 * @param ctx service context to query 2430 * @param c the client to continue receiving from
1633 * @return NULL if there are no listen sockets, otherwise NULL-terminated
1634 * array of listen sockets.
1635 */ 2431 */
1636struct GNUNET_NETWORK_Handle *const* 2432void
1637GNUNET_SERVICE_get_listen_sockets (struct GNUNET_SERVICE_Context *ctx) 2433GNUNET_SERVICE_client_continue (struct GNUNET_SERVICE_Client *c)
1638{ 2434{
1639 return ctx->lsocks; 2435 GNUNET_assert (GNUNET_YES == c->needs_continue);
2436 GNUNET_assert (NULL == c->recv_task);
2437 c->needs_continue = GNUNET_NO;
2438 if (NULL != c->warn_task)
2439 {
2440 GNUNET_SCHEDULER_cancel (c->warn_task);
2441 c->warn_task = NULL;
2442 }
2443 c->recv_task
2444 = GNUNET_SCHEDULER_add_now (&resume_client_receive,
2445 c);
1640} 2446}
1641 2447
1642 2448
1643/** 2449/**
1644 * Stop a service that was started with "GNUNET_SERVICE_start". 2450 * Disable the warning the server issues if a message is not
2451 * acknowledged in a timely fashion. Use this call if a client is
2452 * intentionally delayed for a while. Only applies to the current
2453 * message.
1645 * 2454 *
1646 * @param sctx the service context returned from the start function 2455 * @param c client for which to disable the warning
1647 */ 2456 */
1648void 2457void
1649GNUNET_SERVICE_stop (struct GNUNET_SERVICE_Context *sctx) 2458GNUNET_SERVICE_client_disable_continue_warning (struct GNUNET_SERVICE_Client *c)
1650{ 2459{
1651 unsigned int i; 2460 GNUNET_break (NULL != c->warn_task);
2461 if (NULL != c->warn_task)
2462 {
2463 GNUNET_SCHEDULER_cancel (c->warn_task);
2464 c->warn_task = NULL;
2465 }
2466}
1652 2467
1653#if HAVE_MALLINFO 2468
2469/**
2470 * Asynchronously finish dropping the client.
2471 *
2472 * @param cls the `struct GNUNET_SERVICE_Client`.
2473 */
2474static void
2475finish_client_drop (void *cls)
2476{
2477 struct GNUNET_SERVICE_Client *c = cls;
2478 struct GNUNET_SERVICE_Handle *sh = c->sh;
2479
2480 c->drop_task = NULL;
2481 GNUNET_assert (NULL == c->send_task);
2482 GNUNET_assert (NULL == c->recv_task);
2483 GNUNET_assert (NULL == c->warn_task);
2484 GNUNET_MST_destroy (c->mst);
2485 GNUNET_MQ_destroy (c->mq);
2486 if (GNUNET_NO == c->persist)
1654 { 2487 {
1655 char *counter; 2488 GNUNET_break (GNUNET_OK ==
2489 GNUNET_NETWORK_socket_close (c->sock));
2490 }
2491 else
2492 {
2493 GNUNET_NETWORK_socket_free_memory_only_ (c->sock);
2494 }
2495 GNUNET_free (c);
2496 if ( (GNUNET_YES == sh->got_shutdown) &&
2497 (GNUNET_NO == have_non_monitor_clients (sh)) )
2498 GNUNET_SERVICE_shutdown (sh);
2499}
1656 2500
1657 if ( (GNUNET_YES ==
1658 GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name,
1659 "GAUGER_HEAP")) &&
1660 (GNUNET_OK ==
1661 GNUNET_CONFIGURATION_get_value_string (sctx->cfg, sctx->service_name,
1662 "GAUGER_HEAP",
1663 &counter)) )
1664 {
1665 struct mallinfo mi;
1666 2501
1667 mi = mallinfo (); 2502/**
1668 GAUGER (sctx->service_name, counter, mi.usmblks, "blocks"); 2503 * Ask the server to disconnect from the given client. This is the
1669 GNUNET_free (counter); 2504 * same as returning #GNUNET_SYSERR within the check procedure when
1670 } 2505 * handling a message, wexcept that it allows dropping of a client even
2506 * when not handling a message from that client. The `disconnect_cb`
2507 * will be called on @a c even if the application closes the connection
2508 * using this function.
2509 *
2510 * @param c client to disconnect now
2511 */
2512void
2513GNUNET_SERVICE_client_drop (struct GNUNET_SERVICE_Client *c)
2514{
2515 struct GNUNET_SERVICE_Handle *sh = c->sh;
2516
2517 if (NULL != c->drop_task)
2518 {
2519 /* asked to drop twice! */
2520 GNUNET_assert (0);
2521 return;
1671 } 2522 }
1672#endif 2523 GNUNET_CONTAINER_DLL_remove (sh->clients_head,
1673 if (NULL != sctx->shutdown_task) 2524 sh->clients_tail,
2525 c);
2526 if (NULL != sh->disconnect_cb)
2527 sh->disconnect_cb (sh->cb_cls,
2528 c,
2529 c->user_context);
2530 if (NULL != c->warn_task)
1674 { 2531 {
1675 GNUNET_SCHEDULER_cancel (sctx->shutdown_task); 2532 GNUNET_SCHEDULER_cancel (c->warn_task);
1676 sctx->shutdown_task = NULL; 2533 c->warn_task = NULL;
1677 } 2534 }
1678 if (NULL != sctx->server) 2535 if (NULL != c->recv_task)
1679 GNUNET_SERVER_destroy (sctx->server);
1680 GNUNET_free_non_null (sctx->my_handlers);
1681 if (NULL != sctx->addrs)
1682 { 2536 {
1683 i = 0; 2537 GNUNET_SCHEDULER_cancel (c->recv_task);
1684 while (NULL != sctx->addrs[i]) 2538 c->recv_task = NULL;
1685 GNUNET_free (sctx->addrs[i++]); 2539 }
1686 GNUNET_free (sctx->addrs); 2540 if (NULL != c->send_task)
1687 } 2541 {
1688 GNUNET_free_non_null (sctx->addrlens); 2542 GNUNET_SCHEDULER_cancel (c->send_task);
1689 GNUNET_free_non_null (sctx->v4_denied); 2543 c->send_task = NULL;
1690 GNUNET_free_non_null (sctx->v6_denied); 2544 }
1691 GNUNET_free_non_null (sctx->v4_allowed); 2545 c->drop_task = GNUNET_SCHEDULER_add_now (&finish_client_drop,
1692 GNUNET_free_non_null (sctx->v6_allowed); 2546 c);
1693 GNUNET_free (sctx); 2547}
2548
2549
2550/**
2551 * Explicitly stops the service.
2552 *
2553 * @param sh server to shutdown
2554 */
2555void
2556GNUNET_SERVICE_shutdown (struct GNUNET_SERVICE_Handle *sh)
2557{
2558 struct GNUNET_SERVICE_Client *client;
2559
2560 GNUNET_SERVICE_suspend (sh);
2561 sh->got_shutdown = GNUNET_NO;
2562 while (NULL != (client = sh->clients_head))
2563 GNUNET_SERVICE_client_drop (client);
2564}
2565
2566
2567/**
2568 * Set the 'monitor' flag on this client. Clients which have been
2569 * marked as 'monitors' won't prevent the server from shutting down
2570 * once #GNUNET_SERVICE_stop_listening() has been invoked. The idea is
2571 * that for "normal" clients we likely want to allow them to process
2572 * their requests; however, monitor-clients are likely to 'never'
2573 * disconnect during shutdown and thus will not be considered when
2574 * determining if the server should continue to exist after
2575 * shutdown has been triggered.
2576 *
2577 * @param c client to mark as a monitor
2578 */
2579void
2580GNUNET_SERVICE_client_mark_monitor (struct GNUNET_SERVICE_Client *c)
2581{
2582 c->is_monitor = GNUNET_YES;
2583 if ( (GNUNET_YES == c->sh->got_shutdown) &&
2584 (GNUNET_NO == have_non_monitor_clients (c->sh)) )
2585 GNUNET_SERVICE_shutdown (c->sh);
2586}
2587
2588
2589/**
2590 * Set the persist option on this client. Indicates that the
2591 * underlying socket or fd should never really be closed. Used for
2592 * indicating process death.
2593 *
2594 * @param c client to persist the socket (never to be closed)
2595 */
2596void
2597GNUNET_SERVICE_client_persist (struct GNUNET_SERVICE_Client *c)
2598{
2599 c->persist = GNUNET_YES;
2600}
2601
2602
2603/**
2604 * Obtain the message queue of @a c. Convenience function.
2605 *
2606 * @param c the client to continue receiving from
2607 * @return the message queue of @a c
2608 */
2609struct GNUNET_MQ_Handle *
2610GNUNET_SERVICE_client_get_mq (struct GNUNET_SERVICE_Client *c)
2611{
2612 return c->mq;
1694} 2613}
1695 2614
1696 2615
1697/* end of service.c */ 2616/* end of service_new.c */
diff --git a/src/util/service_new.c b/src/util/service_new.c
deleted file mode 100644
index 22eec0bde..000000000
--- a/src/util/service_new.c
+++ /dev/null
@@ -1,2615 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2016 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21/**
22 * @file util/service_new.c
23 * @brief functions related to starting services (redesign)
24 * @author Christian Grothoff
25 * @author Florian Dold
26 */
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_protocols.h"
30#include "gnunet_constants.h"
31#include "gnunet_resolver_service.h"
32#include "speedup.h"
33
34#if HAVE_MALLINFO
35#include <malloc.h>
36#include "gauger.h"
37#endif
38
39
40#define LOG(kind,...) GNUNET_log_from (kind, "util-service", __VA_ARGS__)
41
42#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-service", syscall)
43
44#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util-service", syscall, filename)
45
46
47/**
48 * Information the service tracks per listen operation.
49 */
50struct ServiceListenContext
51{
52
53 /**
54 * Kept in a DLL.
55 */
56 struct ServiceListenContext *next;
57
58 /**
59 * Kept in a DLL.
60 */
61 struct ServiceListenContext *prev;
62
63 /**
64 * Service this listen context belongs to.
65 */
66 struct GNUNET_SERVICE_Handle *sh;
67
68 /**
69 * Socket we are listening on.
70 */
71 struct GNUNET_NETWORK_Handle *listen_socket;
72
73 /**
74 * Task scheduled to do the listening.
75 */
76 struct GNUNET_SCHEDULER_Task *listen_task;
77
78};
79
80
81/**
82 * Handle to a service.
83 */
84struct GNUNET_SERVICE_Handle
85{
86 /**
87 * Our configuration.
88 */
89 const struct GNUNET_CONFIGURATION_Handle *cfg;
90
91 /**
92 * Name of our service.
93 */
94 const char *service_name;
95
96 /**
97 * Main service-specific task to run.
98 */
99 GNUNET_SERVICE_InitCallback service_init_cb;
100
101 /**
102 * Function to call when clients connect.
103 */
104 GNUNET_SERVICE_ConnectHandler connect_cb;
105
106 /**
107 * Function to call when clients disconnect / are disconnected.
108 */
109 GNUNET_SERVICE_DisconnectHandler disconnect_cb;
110
111 /**
112 * Closure for @e service_init_cb, @e connect_cb, @e disconnect_cb.
113 */
114 void *cb_cls;
115
116 /**
117 * DLL of listen sockets used to accept new connections.
118 */
119 struct ServiceListenContext *slc_head;
120
121 /**
122 * DLL of listen sockets used to accept new connections.
123 */
124 struct ServiceListenContext *slc_tail;
125
126 /**
127 * Our clients, kept in a DLL.
128 */
129 struct GNUNET_SERVICE_Client *clients_head;
130
131 /**
132 * Our clients, kept in a DLL.
133 */
134 struct GNUNET_SERVICE_Client *clients_tail;
135
136 /**
137 * Message handlers to use for all clients.
138 */
139 struct GNUNET_MQ_MessageHandler *handlers;
140
141 /**
142 * Closure for @e task.
143 */
144 void *task_cls;
145
146 /**
147 * IPv4 addresses that are not allowed to connect.
148 */
149 struct GNUNET_STRINGS_IPv4NetworkPolicy *v4_denied;
150
151 /**
152 * IPv6 addresses that are not allowed to connect.
153 */
154 struct GNUNET_STRINGS_IPv6NetworkPolicy *v6_denied;
155
156 /**
157 * IPv4 addresses that are allowed to connect (if not
158 * set, all are allowed).
159 */
160 struct GNUNET_STRINGS_IPv4NetworkPolicy *v4_allowed;
161
162 /**
163 * IPv6 addresses that are allowed to connect (if not
164 * set, all are allowed).
165 */
166 struct GNUNET_STRINGS_IPv6NetworkPolicy *v6_allowed;
167
168 /**
169 * Do we require a matching UID for UNIX domain socket connections?
170 * #GNUNET_NO means that the UID does not have to match (however,
171 * @e match_gid may still impose other access control checks).
172 */
173 int match_uid;
174
175 /**
176 * Do we require a matching GID for UNIX domain socket connections?
177 * Ignored if @e match_uid is #GNUNET_YES. Note that this is about
178 * checking that the client's UID is in our group OR that the
179 * client's GID is our GID. If both "match_gid" and @e match_uid are
180 * #GNUNET_NO, all users on the local system have access.
181 */
182 int match_gid;
183
184 /**
185 * Set to #GNUNET_YES if we got a shutdown signal and terminate
186 * the service if #have_non_monitor_clients() returns #GNUNET_YES.
187 */
188 int got_shutdown;
189
190 /**
191 * Our options.
192 */
193 enum GNUNET_SERVICE_Options options;
194
195 /**
196 * If we are daemonizing, this FD is set to the
197 * pipe to the parent. Send '.' if we started
198 * ok, '!' if not. -1 if we are not daemonizing.
199 */
200 int ready_confirm_fd;
201
202 /**
203 * Overall success/failure of the service start.
204 */
205 int ret;
206
207 /**
208 * If #GNUNET_YES, consider unknown message types an error where the
209 * client is disconnected.
210 */
211 int require_found;
212};
213
214
215/**
216 * Handle to a client that is connected to a service.
217 */
218struct GNUNET_SERVICE_Client
219{
220
221 /**
222 * Kept in a DLL.
223 */
224 struct GNUNET_SERVICE_Client *next;
225
226 /**
227 * Kept in a DLL.
228 */
229 struct GNUNET_SERVICE_Client *prev;
230
231 /**
232 * Service that this client belongs to.
233 */
234 struct GNUNET_SERVICE_Handle *sh;
235
236 /**
237 * Socket of this client.
238 */
239 struct GNUNET_NETWORK_Handle *sock;
240
241 /**
242 * Message queue for the client.
243 */
244 struct GNUNET_MQ_Handle *mq;
245
246 /**
247 * Tokenizer we use for processing incoming data.
248 */
249 struct GNUNET_MessageStreamTokenizer *mst;
250
251 /**
252 * Task that warns about missing calls to
253 * #GNUNET_SERVICE_client_continue().
254 */
255 struct GNUNET_SCHEDULER_Task *warn_task;
256
257 /**
258 * Task run to finish dropping the client after the stack has
259 * properly unwound.
260 */
261 struct GNUNET_SCHEDULER_Task *drop_task;
262
263 /**
264 * Task that receives data from the client to
265 * pass it to the handlers.
266 */
267 struct GNUNET_SCHEDULER_Task *recv_task;
268
269 /**
270 * Task that transmit data to the client.
271 */
272 struct GNUNET_SCHEDULER_Task *send_task;
273
274 /**
275 * Pointer to the message to be transmitted by @e send_task.
276 */
277 const struct GNUNET_MessageHeader *msg;
278
279 /**
280 * User context value, value returned from
281 * the connect callback.
282 */
283 void *user_context;
284
285 /**
286 * Time when we last gave a message from this client
287 * to the application.
288 */
289 struct GNUNET_TIME_Absolute warn_start;
290
291 /**
292 * Current position in @e msg at which we are transmitting.
293 */
294 size_t msg_pos;
295
296 /**
297 * Persist the file handle for this client no matter what happens,
298 * force the OS to close once the process actually dies. Should only
299 * be used in special cases!
300 */
301 int persist;
302
303 /**
304 * Is this client a 'monitor' client that should not be counted
305 * when deciding on destroying the server during soft shutdown?
306 * (see also #GNUNET_SERVICE_start)
307 */
308 int is_monitor;
309
310 /**
311 * Are we waiting for the application to call #GNUNET_SERVICE_client_continue()?
312 */
313 int needs_continue;
314
315 /**
316 * Type of last message processed (for warn_no_receive_done).
317 */
318 uint16_t warn_type;
319};
320
321
322/**
323 * Check if any of the clients we have left are unrelated to
324 * monitoring.
325 *
326 * @param sh service to check clients for
327 * @return #GNUNET_YES if we have non-monitoring clients left
328 */
329static int
330have_non_monitor_clients (struct GNUNET_SERVICE_Handle *sh)
331{
332 struct GNUNET_SERVICE_Client *client;
333
334 for (client = sh->clients_head;NULL != client; client = client->next)
335 {
336 if (client->is_monitor)
337 continue;
338 return GNUNET_YES;
339 }
340 return GNUNET_NO;
341}
342
343
344/**
345 * Shutdown task triggered when a service should be terminated.
346 * This considers active clients and the service options to see
347 * how this specific service is to be terminated, and depending
348 * on this proceeds with the shutdown logic.
349 *
350 * @param cls our `struct GNUNET_SERVICE_Handle`
351 */
352static void
353service_shutdown (void *cls)
354{
355 struct GNUNET_SERVICE_Handle *sh = cls;
356
357 switch (sh->options)
358 {
359 case GNUNET_SERVICE_OPTION_NONE:
360 GNUNET_SERVICE_shutdown (sh);
361 break;
362 case GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN:
363 /* This task should never be run if we are using
364 the manual shutdown. */
365 GNUNET_assert (0);
366 break;
367 case GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN:
368 sh->got_shutdown = GNUNET_YES;
369 GNUNET_SERVICE_suspend (sh);
370 if (GNUNET_NO == have_non_monitor_clients (sh))
371 GNUNET_SERVICE_shutdown (sh);
372 break;
373 }
374}
375
376
377/**
378 * First task run by any service. Initializes our shutdown task,
379 * starts the listening operation on our listen sockets and launches
380 * the custom logic of the application service.
381 *
382 * @param cls our `struct GNUNET_SERVICE_Handle`
383 */
384static void
385service_main (void *cls)
386{
387 struct GNUNET_SERVICE_Handle *sh = cls;
388
389 if (GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN != sh->options)
390 GNUNET_SCHEDULER_add_shutdown (&service_shutdown,
391 sh);
392 GNUNET_SERVICE_resume (sh);
393
394 if (-1 != sh->ready_confirm_fd)
395 {
396 GNUNET_break (1 == WRITE (sh->ready_confirm_fd, ".", 1));
397 GNUNET_break (0 == CLOSE (sh->ready_confirm_fd));
398 sh->ready_confirm_fd = -1;
399 }
400
401 if (NULL != sh->service_init_cb)
402 sh->service_init_cb (sh->cb_cls,
403 sh->cfg,
404 sh);
405}
406
407
408/**
409 * Parse an IPv4 access control list.
410 *
411 * @param ret location where to write the ACL (set)
412 * @param sh service context to use to get the configuration
413 * @param option name of the ACL option to parse
414 * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including
415 * no ACL configured)
416 */
417static int
418process_acl4 (struct GNUNET_STRINGS_IPv4NetworkPolicy **ret,
419 struct GNUNET_SERVICE_Handle *sh,
420 const char *option)
421{
422 char *opt;
423
424 if (! GNUNET_CONFIGURATION_have_value (sh->cfg,
425 sh->service_name,
426 option))
427 {
428 *ret = NULL;
429 return GNUNET_OK;
430 }
431 GNUNET_break (GNUNET_OK ==
432 GNUNET_CONFIGURATION_get_value_string (sh->cfg,
433 sh->service_name,
434 option,
435 &opt));
436 if (NULL == (*ret = GNUNET_STRINGS_parse_ipv4_policy (opt)))
437 {
438 LOG (GNUNET_ERROR_TYPE_WARNING,
439 _("Could not parse IPv4 network specification `%s' for `%s:%s'\n"),
440 opt,
441 sh->service_name,
442 option);
443 GNUNET_free (opt);
444 return GNUNET_SYSERR;
445 }
446 GNUNET_free (opt);
447 return GNUNET_OK;
448}
449
450
451/**
452 * Parse an IPv6 access control list.
453 *
454 * @param ret location where to write the ACL (set)
455 * @param sh service context to use to get the configuration
456 * @param option name of the ACL option to parse
457 * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including
458 * no ACL configured)
459 */
460static int
461process_acl6 (struct GNUNET_STRINGS_IPv6NetworkPolicy **ret,
462 struct GNUNET_SERVICE_Handle *sh,
463 const char *option)
464{
465 char *opt;
466
467 if (! GNUNET_CONFIGURATION_have_value (sh->cfg,
468 sh->service_name,
469 option))
470 {
471 *ret = NULL;
472 return GNUNET_OK;
473 }
474 GNUNET_break (GNUNET_OK ==
475 GNUNET_CONFIGURATION_get_value_string (sh->cfg,
476 sh->service_name,
477 option,
478 &opt));
479 if (NULL == (*ret = GNUNET_STRINGS_parse_ipv6_policy (opt)))
480 {
481 LOG (GNUNET_ERROR_TYPE_WARNING,
482 _("Could not parse IPv6 network specification `%s' for `%s:%s'\n"),
483 opt,
484 sh->service_name,
485 option);
486 GNUNET_free (opt);
487 return GNUNET_SYSERR;
488 }
489 GNUNET_free (opt);
490 return GNUNET_OK;
491}
492
493
494/**
495 * Add the given UNIX domain path as an address to the
496 * list (as the first entry).
497 *
498 * @param saddrs array to update
499 * @param saddrlens where to store the address length
500 * @param unixpath path to add
501 * @param abstract #GNUNET_YES to add an abstract UNIX domain socket. This
502 * parameter is ignore on systems other than LINUX
503 */
504static void
505add_unixpath (struct sockaddr **saddrs,
506 socklen_t *saddrlens,
507 const char *unixpath,
508 int abstract)
509{
510#ifdef AF_UNIX
511 struct sockaddr_un *un;
512
513 un = GNUNET_new (struct sockaddr_un);
514 un->sun_family = AF_UNIX;
515 strncpy (un->sun_path,
516 unixpath,
517 sizeof (un->sun_path) - 1);
518#ifdef LINUX
519 if (GNUNET_YES == abstract)
520 un->sun_path[0] = '\0';
521#endif
522#if HAVE_SOCKADDR_UN_SUN_LEN
523 un->sun_len = (u_char) sizeof (struct sockaddr_un);
524#endif
525 *saddrs = (struct sockaddr *) un;
526 *saddrlens = sizeof (struct sockaddr_un);
527#else
528 /* this function should never be called
529 * unless AF_UNIX is defined! */
530 GNUNET_assert (0);
531#endif
532}
533
534
535/**
536 * Get the list of addresses that a server for the given service
537 * should bind to.
538 *
539 * @param service_name name of the service
540 * @param cfg configuration (which specifies the addresses)
541 * @param addrs set (call by reference) to an array of pointers to the
542 * addresses the server should bind to and listen on; the
543 * array will be NULL-terminated (on success)
544 * @param addr_lens set (call by reference) to an array of the lengths
545 * of the respective `struct sockaddr` struct in the @a addrs
546 * array (on success)
547 * @return number of addresses found on success,
548 * #GNUNET_SYSERR if the configuration
549 * did not specify reasonable finding information or
550 * if it specified a hostname that could not be resolved;
551 * #GNUNET_NO if the number of addresses configured is
552 * zero (in this case, `*addrs` and `*addr_lens` will be
553 * set to NULL).
554 */
555static int
556get_server_addresses (const char *service_name,
557 const struct GNUNET_CONFIGURATION_Handle *cfg,
558 struct sockaddr ***addrs,
559 socklen_t **addr_lens)
560{
561 int disablev6;
562 struct GNUNET_NETWORK_Handle *desc;
563 unsigned long long port;
564 char *unixpath;
565 struct addrinfo hints;
566 struct addrinfo *res;
567 struct addrinfo *pos;
568 struct addrinfo *next;
569 unsigned int i;
570 int resi;
571 int ret;
572 int abstract;
573 struct sockaddr **saddrs;
574 socklen_t *saddrlens;
575 char *hostname;
576
577 *addrs = NULL;
578 *addr_lens = NULL;
579 desc = NULL;
580 if (GNUNET_CONFIGURATION_have_value (cfg,
581 service_name,
582 "DISABLEV6"))
583 {
584 if (GNUNET_SYSERR ==
585 (disablev6 =
586 GNUNET_CONFIGURATION_get_value_yesno (cfg,
587 service_name,
588 "DISABLEV6")))
589 return GNUNET_SYSERR;
590 }
591 else
592 disablev6 = GNUNET_NO;
593
594 if (! disablev6)
595 {
596 /* probe IPv6 support */
597 desc = GNUNET_NETWORK_socket_create (PF_INET6,
598 SOCK_STREAM,
599 0);
600 if (NULL == desc)
601 {
602 if ( (ENOBUFS == errno) ||
603 (ENOMEM == errno) ||
604 (ENFILE == errno) ||
605 (EACCES == errno) )
606 {
607 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
608 "socket");
609 return GNUNET_SYSERR;
610 }
611 LOG (GNUNET_ERROR_TYPE_INFO,
612 _("Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"),
613 service_name,
614 STRERROR (errno));
615 disablev6 = GNUNET_YES;
616 }
617 else
618 {
619 GNUNET_break (GNUNET_OK ==
620 GNUNET_NETWORK_socket_close (desc));
621 desc = NULL;
622 }
623 }
624
625 port = 0;
626 if (GNUNET_CONFIGURATION_have_value (cfg,
627 service_name,
628 "PORT"))
629 {
630 if (GNUNET_OK !=
631 GNUNET_CONFIGURATION_get_value_number (cfg,
632 service_name,
633 "PORT",
634 &port))
635 {
636 LOG (GNUNET_ERROR_TYPE_ERROR,
637 _("Require valid port number for service `%s' in configuration!\n"),
638 service_name);
639 }
640 if (port > 65535)
641 {
642 LOG (GNUNET_ERROR_TYPE_ERROR,
643 _("Require valid port number for service `%s' in configuration!\n"),
644 service_name);
645 return GNUNET_SYSERR;
646 }
647 }
648
649 if (GNUNET_CONFIGURATION_have_value (cfg,
650 service_name,
651 "BINDTO"))
652 {
653 GNUNET_break (GNUNET_OK ==
654 GNUNET_CONFIGURATION_get_value_string (cfg,
655 service_name,
656 "BINDTO",
657 &hostname));
658 }
659 else
660 hostname = NULL;
661
662 unixpath = NULL;
663 abstract = GNUNET_NO;
664#ifdef AF_UNIX
665 if ((GNUNET_YES ==
666 GNUNET_CONFIGURATION_have_value (cfg,
667 service_name,
668 "UNIXPATH")) &&
669 (GNUNET_OK ==
670 GNUNET_CONFIGURATION_get_value_filename (cfg,
671 service_name,
672 "UNIXPATH",
673 &unixpath)) &&
674 (0 < strlen (unixpath)))
675 {
676 /* probe UNIX support */
677 struct sockaddr_un s_un;
678
679 if (strlen (unixpath) >= sizeof (s_un.sun_path))
680 {
681 LOG (GNUNET_ERROR_TYPE_WARNING,
682 _("UNIXPATH `%s' too long, maximum length is %llu\n"),
683 unixpath,
684 (unsigned long long) sizeof (s_un.sun_path));
685 unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
686 LOG (GNUNET_ERROR_TYPE_INFO,
687 _("Using `%s' instead\n"),
688 unixpath);
689 }
690#ifdef LINUX
691 abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg,
692 "TESTING",
693 "USE_ABSTRACT_SOCKETS");
694 if (GNUNET_SYSERR == abstract)
695 abstract = GNUNET_NO;
696#endif
697 if ( (GNUNET_YES != abstract) &&
698 (GNUNET_OK !=
699 GNUNET_DISK_directory_create_for_file (unixpath)) )
700 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
701 "mkdir",
702 unixpath);
703 }
704 if (NULL != unixpath)
705 {
706 desc = GNUNET_NETWORK_socket_create (AF_UNIX,
707 SOCK_STREAM,
708 0);
709 if (NULL == desc)
710 {
711 if ((ENOBUFS == errno) ||
712 (ENOMEM == errno) ||
713 (ENFILE == errno) ||
714 (EACCES == errno))
715 {
716 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
717 "socket");
718 GNUNET_free_non_null (hostname);
719 GNUNET_free (unixpath);
720 return GNUNET_SYSERR;
721 }
722 LOG (GNUNET_ERROR_TYPE_INFO,
723 _("Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"),
724 service_name,
725 STRERROR (errno));
726 GNUNET_free (unixpath);
727 unixpath = NULL;
728 }
729 else
730 {
731 GNUNET_break (GNUNET_OK ==
732 GNUNET_NETWORK_socket_close (desc));
733 desc = NULL;
734 }
735 }
736#endif
737
738 if ((0 == port) && (NULL == unixpath))
739 {
740 LOG (GNUNET_ERROR_TYPE_ERROR,
741 _("Have neither PORT nor UNIXPATH for service `%s', but one is required\n"),
742 service_name);
743 GNUNET_free_non_null (hostname);
744 return GNUNET_SYSERR;
745 }
746 if (0 == port)
747 {
748 saddrs = GNUNET_new_array (2,
749 struct sockaddr *);
750 saddrlens = GNUNET_new_array (2,
751 socklen_t);
752 add_unixpath (saddrs,
753 saddrlens,
754 unixpath,
755 abstract);
756 GNUNET_free_non_null (unixpath);
757 GNUNET_free_non_null (hostname);
758 *addrs = saddrs;
759 *addr_lens = saddrlens;
760 return 1;
761 }
762
763 if (NULL != hostname)
764 {
765 LOG (GNUNET_ERROR_TYPE_DEBUG,
766 "Resolving `%s' since that is where `%s' will bind to.\n",
767 hostname,
768 service_name);
769 memset (&hints,
770 0,
771 sizeof (struct addrinfo));
772 if (disablev6)
773 hints.ai_family = AF_INET;
774 hints.ai_protocol = IPPROTO_TCP;
775 if ((0 != (ret = getaddrinfo (hostname,
776 NULL,
777 &hints,
778 &res))) ||
779 (NULL == res))
780 {
781 LOG (GNUNET_ERROR_TYPE_ERROR,
782 _("Failed to resolve `%s': %s\n"),
783 hostname,
784 gai_strerror (ret));
785 GNUNET_free (hostname);
786 GNUNET_free_non_null (unixpath);
787 return GNUNET_SYSERR;
788 }
789 next = res;
790 i = 0;
791 while (NULL != (pos = next))
792 {
793 next = pos->ai_next;
794 if ( (disablev6) &&
795 (pos->ai_family == AF_INET6) )
796 continue;
797 i++;
798 }
799 if (0 == i)
800 {
801 LOG (GNUNET_ERROR_TYPE_ERROR,
802 _("Failed to find %saddress for `%s'.\n"),
803 disablev6 ? "IPv4 " : "",
804 hostname);
805 freeaddrinfo (res);
806 GNUNET_free (hostname);
807 GNUNET_free_non_null (unixpath);
808 return GNUNET_SYSERR;
809 }
810 resi = i;
811 if (NULL != unixpath)
812 resi++;
813 saddrs = GNUNET_new_array (resi + 1,
814 struct sockaddr *);
815 saddrlens = GNUNET_new_array (resi + 1,
816 socklen_t);
817 i = 0;
818 if (NULL != unixpath)
819 {
820 add_unixpath (saddrs,
821 saddrlens,
822 unixpath,
823 abstract);
824 i++;
825 }
826 next = res;
827 while (NULL != (pos = next))
828 {
829 next = pos->ai_next;
830 if ( (disablev6) &&
831 (AF_INET6 == pos->ai_family) )
832 continue;
833 if ( (IPPROTO_TCP != pos->ai_protocol) &&
834 (0 != pos->ai_protocol) )
835 continue; /* not TCP */
836 if ( (SOCK_STREAM != pos->ai_socktype) &&
837 (0 != pos->ai_socktype) )
838 continue; /* huh? */
839 LOG (GNUNET_ERROR_TYPE_DEBUG,
840 "Service `%s' will bind to `%s'\n",
841 service_name,
842 GNUNET_a2s (pos->ai_addr,
843 pos->ai_addrlen));
844 if (AF_INET == pos->ai_family)
845 {
846 GNUNET_assert (sizeof (struct sockaddr_in) == pos->ai_addrlen);
847 saddrlens[i] = pos->ai_addrlen;
848 saddrs[i] = GNUNET_malloc (saddrlens[i]);
849 GNUNET_memcpy (saddrs[i],
850 pos->ai_addr,
851 saddrlens[i]);
852 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
853 }
854 else
855 {
856 GNUNET_assert (AF_INET6 == pos->ai_family);
857 GNUNET_assert (sizeof (struct sockaddr_in6) == pos->ai_addrlen);
858 saddrlens[i] = pos->ai_addrlen;
859 saddrs[i] = GNUNET_malloc (saddrlens[i]);
860 GNUNET_memcpy (saddrs[i],
861 pos->ai_addr,
862 saddrlens[i]);
863 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
864 }
865 i++;
866 }
867 GNUNET_free (hostname);
868 freeaddrinfo (res);
869 resi = i;
870 }
871 else
872 {
873 /* will bind against everything, just set port */
874 if (disablev6)
875 {
876 /* V4-only */
877 resi = 1;
878 if (NULL != unixpath)
879 resi++;
880 i = 0;
881 saddrs = GNUNET_new_array (resi + 1,
882 struct sockaddr *);
883 saddrlens = GNUNET_new_array (resi + 1,
884 socklen_t);
885 if (NULL != unixpath)
886 {
887 add_unixpath (saddrs,
888 saddrlens,
889 unixpath,
890 abstract);
891 i++;
892 }
893 saddrlens[i] = sizeof (struct sockaddr_in);
894 saddrs[i] = GNUNET_malloc (saddrlens[i]);
895#if HAVE_SOCKADDR_IN_SIN_LEN
896 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
897#endif
898 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
899 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
900 }
901 else
902 {
903 /* dual stack */
904 resi = 2;
905 if (NULL != unixpath)
906 resi++;
907 saddrs = GNUNET_new_array (resi + 1,
908 struct sockaddr *);
909 saddrlens = GNUNET_new_array (resi + 1,
910 socklen_t);
911 i = 0;
912 if (NULL != unixpath)
913 {
914 add_unixpath (saddrs,
915 saddrlens,
916 unixpath,
917 abstract);
918 i++;
919 }
920 saddrlens[i] = sizeof (struct sockaddr_in6);
921 saddrs[i] = GNUNET_malloc (saddrlens[i]);
922#if HAVE_SOCKADDR_IN_SIN_LEN
923 ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
924#endif
925 ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
926 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
927 i++;
928 saddrlens[i] = sizeof (struct sockaddr_in);
929 saddrs[i] = GNUNET_malloc (saddrlens[i]);
930#if HAVE_SOCKADDR_IN_SIN_LEN
931 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
932#endif
933 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
934 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
935 }
936 }
937 GNUNET_free_non_null (unixpath);
938 *addrs = saddrs;
939 *addr_lens = saddrlens;
940 return resi;
941}
942
943
944#ifdef MINGW
945/**
946 * Read listen sockets from the parent process (ARM).
947 *
948 * @param sh service context to initialize
949 * @return NULL-terminated array of sockets on success,
950 * NULL if not ok (must bind yourself)
951 */
952static struct GNUNET_NETWORK_Handle **
953receive_sockets_from_parent (struct GNUNET_SERVICE_Handle *sh)
954{
955 static struct GNUNET_NETWORK_Handle **lsocks;
956 const char *env_buf;
957 int fail;
958 uint64_t count;
959 uint64_t i;
960 HANDLE lsocks_pipe;
961
962 env_buf = getenv ("GNUNET_OS_READ_LSOCKS");
963 if ( (NULL == env_buf) ||
964 (strlen (env_buf) <= 0) )
965 return NULL;
966 /* Using W32 API directly here, because this pipe will
967 * never be used outside of this function, and it's just too much of a bother
968 * to create a GNUnet API that boxes a HANDLE (the way it is done with socks)
969 */
970 lsocks_pipe = (HANDLE) strtoul (env_buf,
971 NULL,
972 10);
973 if ( (0 == lsocks_pipe) ||
974 (INVALID_HANDLE_VALUE == lsocks_pipe))
975 return NULL;
976 fail = 1;
977 do
978 {
979 int ret;
980 int fail2;
981 DWORD rd;
982
983 ret = ReadFile (lsocks_pipe,
984 &count,
985 sizeof (count),
986 &rd,
987 NULL);
988 if ( (0 == ret) ||
989 (sizeof (count) != rd) ||
990 (0 == count) )
991 break;
992 lsocks = GNUNET_new_array (count + 1,
993 struct GNUNET_NETWORK_Handle *);
994
995 fail2 = 1;
996 for (i = 0; i < count; i++)
997 {
998 WSAPROTOCOL_INFOA pi;
999 uint64_t size;
1000 SOCKET s;
1001
1002 ret = ReadFile (lsocks_pipe,
1003 &size,
1004 sizeof (size),
1005 &rd,
1006 NULL);
1007 if ( (0 == ret) ||
1008 (sizeof (size) != rd) ||
1009 (sizeof (pi) != size) )
1010 break;
1011 ret = ReadFile (lsocks_pipe,
1012 &pi,
1013 sizeof (pi),
1014 &rd,
1015 NULL);
1016 if ( (0 == ret) ||
1017 (sizeof (pi) != rd))
1018 break;
1019 s = WSASocketA (pi.iAddressFamily,
1020 pi.iSocketType,
1021 pi.iProtocol,
1022 &pi,
1023 0,
1024 WSA_FLAG_OVERLAPPED);
1025 lsocks[i] = GNUNET_NETWORK_socket_box_native (s);
1026 if (NULL == lsocks[i])
1027 break;
1028 else if (i == count - 1)
1029 fail2 = 0;
1030 }
1031 if (fail2)
1032 break;
1033 lsocks[count] = NULL;
1034 fail = 0;
1035 }
1036 while (fail);
1037 CloseHandle (lsocks_pipe);
1038
1039 if (fail)
1040 {
1041 LOG (GNUNET_ERROR_TYPE_ERROR,
1042 _("Could not access a pre-bound socket, will try to bind myself\n"));
1043 for (i = 0; (i < count) && (NULL != lsocks[i]); i++)
1044 GNUNET_break (GNUNET_OK ==
1045 GNUNET_NETWORK_socket_close (lsocks[i]));
1046 GNUNET_free (lsocks);
1047 return NULL;
1048 }
1049 return lsocks;
1050}
1051#endif
1052
1053
1054/**
1055 * Create and initialize a listen socket for the server.
1056 *
1057 * @param server_addr address to listen on
1058 * @param socklen length of @a server_addr
1059 * @return NULL on error, otherwise the listen socket
1060 */
1061static struct GNUNET_NETWORK_Handle *
1062open_listen_socket (const struct sockaddr *server_addr,
1063 socklen_t socklen)
1064{
1065 struct GNUNET_NETWORK_Handle *sock;
1066 uint16_t port;
1067 int eno;
1068
1069 switch (server_addr->sa_family)
1070 {
1071 case AF_INET:
1072 port = ntohs (((const struct sockaddr_in *) server_addr)->sin_port);
1073 break;
1074 case AF_INET6:
1075 port = ntohs (((const struct sockaddr_in6 *) server_addr)->sin6_port);
1076 break;
1077 case AF_UNIX:
1078 port = 0;
1079 break;
1080 default:
1081 GNUNET_break (0);
1082 port = 0;
1083 break;
1084 }
1085 sock = GNUNET_NETWORK_socket_create (server_addr->sa_family,
1086 SOCK_STREAM,
1087 0);
1088 if (NULL == sock)
1089 {
1090 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
1091 "socket");
1092 errno = 0;
1093 return NULL;
1094 }
1095 /* bind the socket */
1096 if (GNUNET_OK != GNUNET_NETWORK_socket_bind (sock,
1097 server_addr,
1098 socklen))
1099 {
1100 eno = errno;
1101 if (EADDRINUSE != errno)
1102 {
1103 /* we don't log 'EADDRINUSE' here since an IPv4 bind may
1104 * fail if we already took the port on IPv6; if both IPv4 and
1105 * IPv6 binds fail, then our caller will log using the
1106 * errno preserved in 'eno' */
1107 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
1108 "bind");
1109 if (0 != port)
1110 LOG (GNUNET_ERROR_TYPE_ERROR,
1111 _("`%s' failed for port %d (%s).\n"),
1112 "bind",
1113 port,
1114 (AF_INET == server_addr->sa_family) ? "IPv4" : "IPv6");
1115 eno = 0;
1116 }
1117 else
1118 {
1119 if (0 != port)
1120 LOG (GNUNET_ERROR_TYPE_WARNING,
1121 _("`%s' failed for port %d (%s): address already in use\n"),
1122 "bind", port,
1123 (AF_INET == server_addr->sa_family) ? "IPv4" : "IPv6");
1124 else if (AF_UNIX == server_addr->sa_family)
1125 {
1126 LOG (GNUNET_ERROR_TYPE_WARNING,
1127 _("`%s' failed for `%s': address already in use\n"),
1128 "bind",
1129 GNUNET_a2s (server_addr, socklen));
1130 }
1131 }
1132 GNUNET_break (GNUNET_OK ==
1133 GNUNET_NETWORK_socket_close (sock));
1134 errno = eno;
1135 return NULL;
1136 }
1137 if (GNUNET_OK != GNUNET_NETWORK_socket_listen (sock,
1138 5))
1139 {
1140 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
1141 "listen");
1142 GNUNET_break (GNUNET_OK ==
1143 GNUNET_NETWORK_socket_close (sock));
1144 errno = 0;
1145 return NULL;
1146 }
1147 if (0 != port)
1148 LOG (GNUNET_ERROR_TYPE_DEBUG,
1149 "Server starts to listen on port %u.\n",
1150 port);
1151 return sock;
1152}
1153
1154
1155/**
1156 * Setup service handle
1157 *
1158 * Configuration may specify:
1159 * - PORT (where to bind to for TCP)
1160 * - UNIXPATH (where to bind to for UNIX domain sockets)
1161 * - DISABLEV6 (disable support for IPv6, otherwise we use dual-stack)
1162 * - BINDTO (hostname or IP address to bind to, otherwise we take everything)
1163 * - ACCEPT_FROM (only allow connections from specified IPv4 subnets)
1164 * - ACCEPT_FROM6 (only allow connections from specified IPv6 subnets)
1165 * - REJECT_FROM (disallow allow connections from specified IPv4 subnets)
1166 * - REJECT_FROM6 (disallow allow connections from specified IPv6 subnets)
1167 *
1168 * @param sh service context to initialize
1169 * @return #GNUNET_OK if configuration succeeded
1170 */
1171static int
1172setup_service (struct GNUNET_SERVICE_Handle *sh)
1173{
1174 int tolerant;
1175 struct GNUNET_NETWORK_Handle **lsocks;
1176#ifndef MINGW
1177 const char *nfds;
1178 unsigned int cnt;
1179 int flags;
1180#endif
1181
1182 if (GNUNET_CONFIGURATION_have_value
1183 (sh->cfg,
1184 sh->service_name,
1185 "TOLERANT"))
1186 {
1187 if (GNUNET_SYSERR ==
1188 (tolerant =
1189 GNUNET_CONFIGURATION_get_value_yesno (sh->cfg,
1190 sh->service_name,
1191 "TOLERANT")))
1192 {
1193 LOG (GNUNET_ERROR_TYPE_ERROR,
1194 _("Specified value for `%s' of service `%s' is invalid\n"),
1195 "TOLERANT",
1196 sh->service_name);
1197 return GNUNET_SYSERR;
1198 }
1199 }
1200 else
1201 tolerant = GNUNET_NO;
1202
1203 lsocks = NULL;
1204#ifndef MINGW
1205 errno = 0;
1206 if ( (NULL != (nfds = getenv ("LISTEN_FDS"))) &&
1207 (1 == SSCANF (nfds,
1208 "%u",
1209 &cnt)) &&
1210 (cnt > 0) &&
1211 (cnt < FD_SETSIZE) &&
1212 (cnt + 4 < FD_SETSIZE) )
1213 {
1214 lsocks = GNUNET_new_array (cnt + 1,
1215 struct GNUNET_NETWORK_Handle *);
1216 while (0 < cnt--)
1217 {
1218 flags = fcntl (3 + cnt,
1219 F_GETFD);
1220 if ( (flags < 0) ||
1221 (0 != (flags & FD_CLOEXEC)) ||
1222 (NULL ==
1223 (lsocks[cnt] = GNUNET_NETWORK_socket_box_native (3 + cnt))))
1224 {
1225 LOG (GNUNET_ERROR_TYPE_ERROR,
1226 _("Could not access pre-bound socket %u, will try to bind myself\n"),
1227 (unsigned int) 3 + cnt);
1228 cnt++;
1229 while (NULL != lsocks[cnt])
1230 GNUNET_break (GNUNET_OK ==
1231 GNUNET_NETWORK_socket_close (lsocks[cnt++]));
1232 GNUNET_free (lsocks);
1233 lsocks = NULL;
1234 break;
1235 }
1236 }
1237 unsetenv ("LISTEN_FDS");
1238 }
1239#else
1240 if (NULL != getenv ("GNUNET_OS_READ_LSOCKS"))
1241 {
1242 lsocks = receive_sockets_from_parent (sh);
1243 putenv ("GNUNET_OS_READ_LSOCKS=");
1244 }
1245#endif
1246
1247 if (NULL != lsocks)
1248 {
1249 /* listen only on inherited sockets if we have any */
1250 struct GNUNET_NETWORK_Handle **ls;
1251
1252 for (ls = lsocks; NULL != *ls; ls++)
1253 {
1254 struct ServiceListenContext *slc;
1255
1256 slc = GNUNET_new (struct ServiceListenContext);
1257 slc->sh = sh;
1258 slc->listen_socket = *ls;
1259 GNUNET_CONTAINER_DLL_insert (sh->slc_head,
1260 sh->slc_tail,
1261 slc);
1262 }
1263 GNUNET_free (lsocks);
1264 }
1265 else
1266 {
1267 struct sockaddr **addrs;
1268 socklen_t *addrlens;
1269 int num;
1270
1271 num = get_server_addresses (sh->service_name,
1272 sh->cfg,
1273 &addrs,
1274 &addrlens);
1275 if (GNUNET_SYSERR == num)
1276 return GNUNET_SYSERR;
1277
1278 for (int i = 0; i < num; i++)
1279 {
1280 struct ServiceListenContext *slc;
1281
1282 slc = GNUNET_new (struct ServiceListenContext);
1283 slc->sh = sh;
1284 slc->listen_socket = open_listen_socket (addrs[i],
1285 addrlens[i]);
1286 if (NULL == slc->listen_socket)
1287 {
1288 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
1289 "bind");
1290 GNUNET_free (addrs[i++]);
1291 GNUNET_free (slc);
1292 continue;
1293 }
1294 GNUNET_free (addrs[i++]);
1295 GNUNET_CONTAINER_DLL_insert (sh->slc_head,
1296 sh->slc_tail,
1297 slc);
1298 }
1299 GNUNET_free_non_null (addrlens);
1300 GNUNET_free_non_null (addrs);
1301 if ( (0 != num) &&
1302 (NULL == sh->slc_head) )
1303 {
1304 /* All attempts to bind failed, hard failure */
1305 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1306 _("Could not bind to any of the ports I was supposed to, refusing to run!\n"));
1307 return GNUNET_SYSERR;
1308 }
1309 }
1310
1311 sh->require_found = tolerant ? GNUNET_NO : GNUNET_YES;
1312 sh->match_uid
1313 = GNUNET_CONFIGURATION_get_value_yesno (sh->cfg,
1314 sh->service_name,
1315 "UNIX_MATCH_UID");
1316 sh->match_gid
1317 = GNUNET_CONFIGURATION_get_value_yesno (sh->cfg,
1318 sh->service_name,
1319 "UNIX_MATCH_GID");
1320 process_acl4 (&sh->v4_denied,
1321 sh,
1322 "REJECT_FROM");
1323 process_acl4 (&sh->v4_allowed,
1324 sh,
1325 "ACCEPT_FROM");
1326 process_acl6 (&sh->v6_denied,
1327 sh,
1328 "REJECT_FROM6");
1329 process_acl6 (&sh->v6_allowed,
1330 sh,
1331 "ACCEPT_FROM6");
1332 return GNUNET_OK;
1333}
1334
1335
1336/**
1337 * Get the name of the user that'll be used
1338 * to provide the service.
1339 *
1340 * @param sh service context
1341 * @return value of the 'USERNAME' option
1342 */
1343static char *
1344get_user_name (struct GNUNET_SERVICE_Handle *sh)
1345{
1346 char *un;
1347
1348 if (GNUNET_OK !=
1349 GNUNET_CONFIGURATION_get_value_filename (sh->cfg,
1350 sh->service_name,
1351 "USERNAME",
1352 &un))
1353 return NULL;
1354 return un;
1355}
1356
1357
1358/**
1359 * Set user ID.
1360 *
1361 * @param sh service context
1362 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1363 */
1364static int
1365set_user_id (struct GNUNET_SERVICE_Handle *sh)
1366{
1367 char *user;
1368
1369 if (NULL == (user = get_user_name (sh)))
1370 return GNUNET_OK; /* keep */
1371#ifndef MINGW
1372 struct passwd *pws;
1373
1374 errno = 0;
1375 pws = getpwnam (user);
1376 if (NULL == pws)
1377 {
1378 LOG (GNUNET_ERROR_TYPE_ERROR,
1379 _("Cannot obtain information about user `%s': %s\n"),
1380 user,
1381 errno == 0 ? _("No such user") : STRERROR (errno));
1382 GNUNET_free (user);
1383 return GNUNET_SYSERR;
1384 }
1385 if ( (0 != setgid (pws->pw_gid)) ||
1386 (0 != setegid (pws->pw_gid)) ||
1387#if HAVE_INITGROUPS
1388 (0 != initgroups (user,
1389 pws->pw_gid)) ||
1390#endif
1391 (0 != setuid (pws->pw_uid)) ||
1392 (0 != seteuid (pws->pw_uid)))
1393 {
1394 if ((0 != setregid (pws->pw_gid,
1395 pws->pw_gid)) ||
1396 (0 != setreuid (pws->pw_uid,
1397 pws->pw_uid)))
1398 {
1399 LOG (GNUNET_ERROR_TYPE_ERROR,
1400 _("Cannot change user/group to `%s': %s\n"),
1401 user,
1402 STRERROR (errno));
1403 GNUNET_free (user);
1404 return GNUNET_SYSERR;
1405 }
1406 }
1407#endif
1408 GNUNET_free (user);
1409 return GNUNET_OK;
1410}
1411
1412
1413/**
1414 * Get the name of the file where we will
1415 * write the PID of the service.
1416 *
1417 * @param sh service context
1418 * @return name of the file for the process ID
1419 */
1420static char *
1421get_pid_file_name (struct GNUNET_SERVICE_Handle *sh)
1422{
1423 char *pif;
1424
1425 if (GNUNET_OK !=
1426 GNUNET_CONFIGURATION_get_value_filename (sh->cfg,
1427 sh->service_name,
1428 "PIDFILE",
1429 &pif))
1430 return NULL;
1431 return pif;
1432}
1433
1434
1435/**
1436 * Delete the PID file that was created by our parent.
1437 *
1438 * @param sh service context
1439 */
1440static void
1441pid_file_delete (struct GNUNET_SERVICE_Handle *sh)
1442{
1443 char *pif = get_pid_file_name (sh);
1444
1445 if (NULL == pif)
1446 return; /* no PID file */
1447 if (0 != UNLINK (pif))
1448 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING,
1449 "unlink",
1450 pif);
1451 GNUNET_free (pif);
1452}
1453
1454
1455/**
1456 * Detach from terminal.
1457 *
1458 * @param sh service context
1459 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1460 */
1461static int
1462detach_terminal (struct GNUNET_SERVICE_Handle *sh)
1463{
1464#ifndef MINGW
1465 pid_t pid;
1466 int nullfd;
1467 int filedes[2];
1468
1469 if (0 != PIPE (filedes))
1470 {
1471 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
1472 "pipe");
1473 return GNUNET_SYSERR;
1474 }
1475 pid = fork ();
1476 if (pid < 0)
1477 {
1478 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
1479 "fork");
1480 return GNUNET_SYSERR;
1481 }
1482 if (0 != pid)
1483 {
1484 /* Parent */
1485 char c;
1486
1487 GNUNET_break (0 == CLOSE (filedes[1]));
1488 c = 'X';
1489 if (1 != READ (filedes[0],
1490 &c,
1491 sizeof (char)))
1492 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING,
1493 "read");
1494 fflush (stdout);
1495 switch (c)
1496 {
1497 case '.':
1498 exit (0);
1499 case 'I':
1500 LOG (GNUNET_ERROR_TYPE_INFO,
1501 _("Service process failed to initialize\n"));
1502 break;
1503 case 'S':
1504 LOG (GNUNET_ERROR_TYPE_INFO,
1505 _("Service process could not initialize server function\n"));
1506 break;
1507 case 'X':
1508 LOG (GNUNET_ERROR_TYPE_INFO,
1509 _("Service process failed to report status\n"));
1510 break;
1511 }
1512 exit (1); /* child reported error */
1513 }
1514 GNUNET_break (0 == CLOSE (0));
1515 GNUNET_break (0 == CLOSE (1));
1516 GNUNET_break (0 == CLOSE (filedes[0]));
1517 nullfd = OPEN ("/dev/null",
1518 O_RDWR | O_APPEND);
1519 if (nullfd < 0)
1520 return GNUNET_SYSERR;
1521 /* set stdin/stdout to /dev/null */
1522 if ( (dup2 (nullfd, 0) < 0) ||
1523 (dup2 (nullfd, 1) < 0) )
1524 {
1525 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
1526 "dup2");
1527 (void) CLOSE (nullfd);
1528 return GNUNET_SYSERR;
1529 }
1530 (void) CLOSE (nullfd);
1531 /* Detach from controlling terminal */
1532 pid = setsid ();
1533 if (-1 == pid)
1534 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
1535 "setsid");
1536 sh->ready_confirm_fd = filedes[1];
1537#else
1538 /* FIXME: we probably need to do something else
1539 * elsewhere in order to fork the process itself... */
1540 FreeConsole ();
1541#endif
1542 return GNUNET_OK;
1543}
1544
1545
1546/**
1547 * Tear down the service, closing the listen sockets and
1548 * freeing the ACLs.
1549 *
1550 * @param sh handle to the service to tear down.
1551 */
1552static void
1553teardown_service (struct GNUNET_SERVICE_Handle *sh)
1554{
1555 struct ServiceListenContext *slc;
1556
1557 GNUNET_free_non_null (sh->v4_denied);
1558 GNUNET_free_non_null (sh->v6_denied);
1559 GNUNET_free_non_null (sh->v4_allowed);
1560 GNUNET_free_non_null (sh->v6_allowed);
1561 while (NULL != (slc = sh->slc_head))
1562 {
1563 GNUNET_CONTAINER_DLL_remove (sh->slc_head,
1564 sh->slc_tail,
1565 slc);
1566 if (NULL != slc->listen_task)
1567 GNUNET_SCHEDULER_cancel (slc->listen_task);
1568 GNUNET_break (GNUNET_OK ==
1569 GNUNET_NETWORK_socket_close (slc->listen_socket));
1570 GNUNET_free (slc);
1571 }
1572}
1573
1574
1575/**
1576 * Low-level function to start a service if the scheduler
1577 * is already running. Should only be used directly in
1578 * special cases.
1579 *
1580 * The function will launch the service with the name @a service_name
1581 * using the @a service_options to configure its shutdown
1582 * behavior. When clients connect or disconnect, the respective
1583 * @a connect_cb or @a disconnect_cb functions will be called. For
1584 * messages received from the clients, the respective @a handlers will
1585 * be invoked; for the closure of the handlers we use the return value
1586 * from the @a connect_cb invocation of the respective client.
1587 *
1588 * Each handler MUST call #GNUNET_SERVICE_client_continue() after each
1589 * message to receive further messages from this client. If
1590 * #GNUNET_SERVICE_client_continue() is not called within a short
1591 * time, a warning will be logged. If delays are expected, services
1592 * should call #GNUNET_SERVICE_client_disable_continue_warning() to
1593 * disable the warning.
1594 *
1595 * Clients sending invalid messages (based on @a handlers) will be
1596 * dropped. Additionally, clients can be dropped at any time using
1597 * #GNUNET_SERVICE_client_drop().
1598 *
1599 * The service must be stopped using #GNUNET_SERVICE_stoP().
1600 *
1601 * @param service_name name of the service to run
1602 * @param cfg configuration to use
1603 * @param connect_cb function to call whenever a client connects
1604 * @param disconnect_cb function to call whenever a client disconnects
1605 * @param cls closure argument for @a connect_cb and @a disconnect_cb
1606 * @param handlers NULL-terminated array of message handlers for the service,
1607 * the closure will be set to the value returned by
1608 * the @a connect_cb for the respective connection
1609 * @return NULL on error
1610 */
1611struct GNUNET_SERVICE_Handle *
1612GNUNET_SERVICE_starT (const char *service_name,
1613 const struct GNUNET_CONFIGURATION_Handle *cfg,
1614 GNUNET_SERVICE_ConnectHandler connect_cb,
1615 GNUNET_SERVICE_DisconnectHandler disconnect_cb,
1616 void *cls,
1617 const struct GNUNET_MQ_MessageHandler *handlers)
1618{
1619 struct GNUNET_SERVICE_Handle *sh;
1620
1621 sh = GNUNET_new (struct GNUNET_SERVICE_Handle);
1622 sh->service_name = service_name;
1623 sh->cfg = cfg;
1624 sh->connect_cb = connect_cb;
1625 sh->disconnect_cb = disconnect_cb;
1626 sh->cb_cls = cls;
1627 sh->handlers = GNUNET_MQ_copy_handlers (handlers);
1628 if (GNUNET_OK != setup_service (sh))
1629 {
1630 GNUNET_free_non_null (sh->handlers);
1631 GNUNET_free (sh);
1632 return NULL;
1633 }
1634 GNUNET_SERVICE_resume (sh);
1635 return sh;
1636}
1637
1638
1639/**
1640 * Stops a service that was started with #GNUNET_SERVICE_starT().
1641 *
1642 * @param srv service to stop
1643 */
1644void
1645GNUNET_SERVICE_stoP (struct GNUNET_SERVICE_Handle *srv)
1646{
1647 struct GNUNET_SERVICE_Client *client;
1648
1649 GNUNET_SERVICE_suspend (srv);
1650 while (NULL != (client = srv->clients_head))
1651 GNUNET_SERVICE_client_drop (client);
1652 teardown_service (srv);
1653 GNUNET_free_non_null (srv->handlers);
1654 GNUNET_free (srv);
1655}
1656
1657
1658/**
1659 * Creates the "main" function for a GNUnet service. You
1660 * should almost always use the #GNUNET_SERVICE_MAIN macro
1661 * instead of calling this function directly (except
1662 * for ARM, which should call this function directly).
1663 *
1664 * The function will launch the service with the name @a service_name
1665 * using the @a service_options to configure its shutdown
1666 * behavior. Once the service is ready, the @a init_cb will be called
1667 * for service-specific initialization. @a init_cb will be given the
1668 * service handler which can be used to control the service's
1669 * availability. When clients connect or disconnect, the respective
1670 * @a connect_cb or @a disconnect_cb functions will be called. For
1671 * messages received from the clients, the respective @a handlers will
1672 * be invoked; for the closure of the handlers we use the return value
1673 * from the @a connect_cb invocation of the respective client.
1674 *
1675 * Each handler MUST call #GNUNET_SERVICE_client_continue() after each
1676 * message to receive further messages from this client. If
1677 * #GNUNET_SERVICE_client_continue() is not called within a short
1678 * time, a warning will be logged. If delays are expected, services
1679 * should call #GNUNET_SERVICE_client_disable_continue_warning() to
1680 * disable the warning.
1681 *
1682 * Clients sending invalid messages (based on @a handlers) will be
1683 * dropped. Additionally, clients can be dropped at any time using
1684 * #GNUNET_SERVICE_client_drop().
1685 *
1686 * @param argc number of command-line arguments in @a argv
1687 * @param argv array of command-line arguments
1688 * @param service_name name of the service to run
1689 * @param options options controlling shutdown of the service
1690 * @param service_init_cb function to call once the service is ready
1691 * @param connect_cb function to call whenever a client connects
1692 * @param disconnect_cb function to call whenever a client disconnects
1693 * @param cls closure argument for @a service_init_cb, @a connect_cb and @a disconnect_cb
1694 * @param handlers NULL-terminated array of message handlers for the service,
1695 * the closure will be set to the value returned by
1696 * the @a connect_cb for the respective connection
1697 * @return 0 on success, non-zero on error
1698 */
1699int
1700GNUNET_SERVICE_ruN_ (int argc,
1701 char *const *argv,
1702 const char *service_name,
1703 enum GNUNET_SERVICE_Options options,
1704 GNUNET_SERVICE_InitCallback service_init_cb,
1705 GNUNET_SERVICE_ConnectHandler connect_cb,
1706 GNUNET_SERVICE_DisconnectHandler disconnect_cb,
1707 void *cls,
1708 const struct GNUNET_MQ_MessageHandler *handlers)
1709{
1710 struct GNUNET_SERVICE_Handle sh;
1711 char *cfg_filename;
1712 char *opt_cfg_filename;
1713 char *loglev;
1714 const char *xdg;
1715 char *logfile;
1716 int do_daemonize;
1717 unsigned long long skew_offset;
1718 unsigned long long skew_variance;
1719 long long clock_offset;
1720 struct GNUNET_CONFIGURATION_Handle *cfg;
1721 int ret;
1722 int err;
1723
1724 struct GNUNET_GETOPT_CommandLineOption service_options[] = {
1725 GNUNET_GETOPT_OPTION_CFG_FILE (&opt_cfg_filename),
1726 {'d', "daemonize", NULL,
1727 gettext_noop ("do daemonize (detach from terminal)"), 0,
1728 GNUNET_GETOPT_set_one, &do_daemonize},
1729 GNUNET_GETOPT_OPTION_HELP (NULL),
1730 GNUNET_GETOPT_OPTION_LOGLEVEL (&loglev),
1731 GNUNET_GETOPT_OPTION_LOGFILE (&logfile),
1732 GNUNET_GETOPT_OPTION_VERSION (PACKAGE_VERSION " " VCS_VERSION),
1733 GNUNET_GETOPT_OPTION_END
1734 };
1735
1736 memset (&sh,
1737 0,
1738 sizeof (sh));
1739 xdg = getenv ("XDG_CONFIG_HOME");
1740 if (NULL != xdg)
1741 GNUNET_asprintf (&cfg_filename,
1742 "%s%s%s",
1743 xdg,
1744 DIR_SEPARATOR_STR,
1745 GNUNET_OS_project_data_get ()->config_file);
1746 else
1747 cfg_filename = GNUNET_strdup (GNUNET_OS_project_data_get ()->user_config_file);
1748 sh.ready_confirm_fd = -1;
1749 sh.options = options;
1750 sh.cfg = cfg = GNUNET_CONFIGURATION_create ();
1751 sh.service_init_cb = service_init_cb;
1752 sh.connect_cb = connect_cb;
1753 sh.disconnect_cb = disconnect_cb;
1754 sh.cb_cls = cls;
1755 sh.handlers = GNUNET_MQ_copy_handlers (handlers);
1756 sh.service_name = service_name;
1757
1758 /* setup subsystems */
1759 loglev = NULL;
1760 logfile = NULL;
1761 opt_cfg_filename = NULL;
1762 do_daemonize = 0;
1763 ret = GNUNET_GETOPT_run (service_name,
1764 service_options,
1765 argc,
1766 argv);
1767 if (GNUNET_SYSERR == ret)
1768 goto shutdown;
1769 if (GNUNET_NO == ret)
1770 {
1771 err = 0;
1772 goto shutdown;
1773 }
1774 if (GNUNET_OK != GNUNET_log_setup (service_name,
1775 loglev,
1776 logfile))
1777 {
1778 GNUNET_break (0);
1779 goto shutdown;
1780 }
1781 if (NULL == opt_cfg_filename)
1782 opt_cfg_filename = GNUNET_strdup (cfg_filename);
1783 if (GNUNET_YES == GNUNET_DISK_file_test (opt_cfg_filename))
1784 {
1785 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg,
1786 opt_cfg_filename))
1787 {
1788 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1789 _("Malformed configuration file `%s', exit ...\n"),
1790 opt_cfg_filename);
1791 goto shutdown;
1792 }
1793 }
1794 else
1795 {
1796 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg,
1797 NULL))
1798 {
1799 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1800 _("Malformed configuration, exit ...\n"));
1801 goto shutdown;
1802 }
1803 if (0 != strcmp (opt_cfg_filename,
1804 cfg_filename))
1805 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1806 _("Could not access configuration file `%s'\n"),
1807 opt_cfg_filename);
1808 }
1809 if (GNUNET_OK != setup_service (&sh))
1810 goto shutdown;
1811 if ( (1 == do_daemonize) &&
1812 (GNUNET_OK != detach_terminal (&sh)) )
1813 {
1814 GNUNET_break (0);
1815 goto shutdown;
1816 }
1817 if (GNUNET_OK != set_user_id (&sh))
1818 goto shutdown;
1819 LOG (GNUNET_ERROR_TYPE_DEBUG,
1820 "Service `%s' runs with configuration from `%s'\n",
1821 service_name,
1822 opt_cfg_filename);
1823 if ((GNUNET_OK ==
1824 GNUNET_CONFIGURATION_get_value_number (sh.cfg,
1825 "TESTING",
1826 "SKEW_OFFSET",
1827 &skew_offset)) &&
1828 (GNUNET_OK ==
1829 GNUNET_CONFIGURATION_get_value_number (sh.cfg,
1830 "TESTING",
1831 "SKEW_VARIANCE",
1832 &skew_variance)))
1833 {
1834 clock_offset = skew_offset - skew_variance;
1835 GNUNET_TIME_set_offset (clock_offset);
1836 LOG (GNUNET_ERROR_TYPE_DEBUG,
1837 "Skewing clock by %dll ms\n",
1838 clock_offset);
1839 }
1840 GNUNET_RESOLVER_connect (sh.cfg);
1841
1842 /* actually run service */
1843 err = 0;
1844 GNUNET_SCHEDULER_run (&service_main,
1845 &sh);
1846 /* shutdown */
1847 if (1 == do_daemonize)
1848 pid_file_delete (&sh);
1849
1850shutdown:
1851 if (-1 != sh.ready_confirm_fd)
1852 {
1853 if (1 != WRITE (sh.ready_confirm_fd,
1854 err ? "I" : "S",
1855 1))
1856 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING,
1857 "write");
1858 GNUNET_break (0 == CLOSE (sh.ready_confirm_fd));
1859 }
1860#if HAVE_MALLINFO
1861 {
1862 char *counter;
1863
1864 if ( (GNUNET_YES ==
1865 GNUNET_CONFIGURATION_have_value (sh.cfg,
1866 service_name,
1867 "GAUGER_HEAP")) &&
1868 (GNUNET_OK ==
1869 GNUNET_CONFIGURATION_get_value_string (sh.cfg,
1870 service_name,
1871 "GAUGER_HEAP",
1872 &counter)) )
1873 {
1874 struct mallinfo mi;
1875
1876 mi = mallinfo ();
1877 GAUGER (service_name,
1878 counter,
1879 mi.usmblks,
1880 "blocks");
1881 GNUNET_free (counter);
1882 }
1883 }
1884#endif
1885 teardown_service (&sh);
1886 GNUNET_free_non_null (sh.handlers);
1887 GNUNET_SPEEDUP_stop_ ();
1888 GNUNET_CONFIGURATION_destroy (cfg);
1889 GNUNET_free_non_null (logfile);
1890 GNUNET_free_non_null (loglev);
1891 GNUNET_free (cfg_filename);
1892 GNUNET_free_non_null (opt_cfg_filename);
1893
1894 return err ? GNUNET_SYSERR : sh.ret;
1895}
1896
1897
1898/**
1899 * Suspend accepting connections from the listen socket temporarily.
1900 * Resume activity using #GNUNET_SERVICE_resume.
1901 *
1902 * @param sh service to stop accepting connections.
1903 */
1904void
1905GNUNET_SERVICE_suspend (struct GNUNET_SERVICE_Handle *sh)
1906{
1907 struct ServiceListenContext *slc;
1908
1909 for (slc = sh->slc_head; NULL != slc; slc = slc->next)
1910 {
1911 if (NULL != slc->listen_task)
1912 {
1913 GNUNET_SCHEDULER_cancel (slc->listen_task);
1914 slc->listen_task = NULL;
1915 }
1916 }
1917}
1918
1919
1920/**
1921 * Task run when we are ready to transmit data to the
1922 * client.
1923 *
1924 * @param cls the `struct GNUNET_SERVICE_Client *` to send to
1925 */
1926static void
1927do_send (void *cls)
1928{
1929 struct GNUNET_SERVICE_Client *client = cls;
1930 ssize_t ret;
1931 size_t left;
1932 const char *buf;
1933
1934 client->send_task = NULL;
1935 buf = (const char *) client->msg;
1936 left = ntohs (client->msg->size) - client->msg_pos;
1937 ret = GNUNET_NETWORK_socket_send (client->sock,
1938 &buf[client->msg_pos],
1939 left);
1940 GNUNET_assert (ret <= (ssize_t) left);
1941 if (0 == ret)
1942 {
1943 GNUNET_MQ_inject_error (client->mq,
1944 GNUNET_MQ_ERROR_WRITE);
1945 return;
1946 }
1947 if (-1 == ret)
1948 {
1949 if ( (EAGAIN == errno) ||
1950 (EINTR == errno) )
1951 {
1952 /* ignore */
1953 ret = 0;
1954 }
1955 else
1956 {
1957 if (EPIPE != errno)
1958 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
1959 "send");
1960 GNUNET_MQ_inject_error (client->mq,
1961 GNUNET_MQ_ERROR_WRITE);
1962 return;
1963 }
1964 }
1965 if (0 == client->msg_pos)
1966 {
1967 GNUNET_MQ_impl_send_in_flight (client->mq);
1968 }
1969 client->msg_pos += ret;
1970 if (left > ret)
1971 {
1972 GNUNET_assert (NULL == client->drop_task);
1973 client->send_task
1974 = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
1975 client->sock,
1976 &do_send,
1977 client);
1978 return;
1979 }
1980 GNUNET_MQ_impl_send_continue (client->mq);
1981}
1982
1983
1984/**
1985 * Signature of functions implementing the sending functionality of a
1986 * message queue.
1987 *
1988 * @param mq the message queue
1989 * @param msg the message to send
1990 * @param impl_state our `struct GNUNET_SERVICE_Client *`
1991 */
1992static void
1993service_mq_send (struct GNUNET_MQ_Handle *mq,
1994 const struct GNUNET_MessageHeader *msg,
1995 void *impl_state)
1996{
1997 struct GNUNET_SERVICE_Client *client = impl_state;
1998
1999 if (NULL != client->drop_task)
2000 return; /* we're going down right now, do not try to send */
2001 GNUNET_assert (NULL == client->send_task);
2002
2003 LOG (GNUNET_ERROR_TYPE_INFO,
2004 "Sending message of type %u and size %u to client\n",
2005 ntohs (msg->type), ntohs (msg->size));
2006
2007 client->msg = msg;
2008 client->msg_pos = 0;
2009 client->send_task
2010 = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
2011 client->sock,
2012 &do_send,
2013 client);
2014}
2015
2016
2017/**
2018 * Implementation function that cancels the currently sent message.
2019 *
2020 * @param mq message queue
2021 * @param impl_state state specific to the implementation
2022 */
2023static void
2024service_mq_cancel (struct GNUNET_MQ_Handle *mq,
2025 void *impl_state)
2026{
2027 struct GNUNET_SERVICE_Client *client = impl_state;
2028
2029 GNUNET_assert (0 == client->msg_pos);
2030 client->msg = NULL;
2031 GNUNET_SCHEDULER_cancel (client->send_task);
2032 client->send_task = NULL;
2033}
2034
2035
2036/**
2037 * Generic error handler, called with the appropriate
2038 * error code and the same closure specified at the creation of
2039 * the message queue.
2040 * Not every message queue implementation supports an error handler.
2041 *
2042 * @param cls closure with our `struct GNUNET_SERVICE_Client`
2043 * @param error error code
2044 */
2045static void
2046service_mq_error_handler (void *cls,
2047 enum GNUNET_MQ_Error error)
2048{
2049 struct GNUNET_SERVICE_Client *client = cls;
2050 struct GNUNET_SERVICE_Handle *sh = client->sh;
2051
2052 if ( (GNUNET_MQ_ERROR_NO_MATCH == error) &&
2053 (GNUNET_NO == sh->require_found) )
2054 {
2055 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2056 "No handler for message of type %u found\n",
2057 (unsigned int) client->warn_type);
2058 GNUNET_SERVICE_client_continue (client);
2059 return; /* ignore error */
2060 }
2061 GNUNET_SERVICE_client_drop (client);
2062}
2063
2064
2065/**
2066 * Task run to warn about missing calls to #GNUNET_SERVICE_client_continue().
2067 *
2068 * @param cls our `struct GNUNET_SERVICE_Client *` to process more requests from
2069 */
2070static void
2071warn_no_client_continue (void *cls)
2072{
2073 struct GNUNET_SERVICE_Client *client = cls;
2074
2075 GNUNET_break (0 != client->warn_type); /* type should never be 0 here, as we don't use 0 */
2076 client->warn_task
2077 = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
2078 &warn_no_client_continue,
2079 client);
2080 LOG (GNUNET_ERROR_TYPE_WARNING,
2081 _("Processing code for message of type %u did not call `GNUNET_SERVICE_client_continue' after %s\n"),
2082 (unsigned int) client->warn_type,
2083 GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (client->warn_start),
2084 GNUNET_YES));
2085}
2086
2087
2088/**
2089 * Functions with this signature are called whenever a
2090 * complete message is received by the tokenizer for a client.
2091 *
2092 * Do not call #GNUNET_MST_destroy() from within
2093 * the scope of this callback.
2094 *
2095 * @param cls closure with the `struct GNUNET_SERVICE_Client *`
2096 * @param message the actual message
2097 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the client was dropped
2098 */
2099static int
2100service_client_mst_cb (void *cls,
2101 const struct GNUNET_MessageHeader *message)
2102{
2103 struct GNUNET_SERVICE_Client *client = cls;
2104
2105 LOG (GNUNET_ERROR_TYPE_INFO,
2106 "Received message of type %u and size %u from client\n",
2107 ntohs (message->type), ntohs (message->size));
2108
2109 GNUNET_assert (GNUNET_NO == client->needs_continue);
2110 client->needs_continue = GNUNET_YES;
2111 client->warn_type = ntohs (message->type);
2112 client->warn_start = GNUNET_TIME_absolute_get ();
2113 GNUNET_assert (NULL == client->warn_task);
2114 client->warn_task
2115 = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
2116 &warn_no_client_continue,
2117 client);
2118 GNUNET_MQ_inject_message (client->mq,
2119 message);
2120 if (NULL != client->drop_task)
2121 return GNUNET_SYSERR;
2122 return GNUNET_OK;
2123}
2124
2125
2126/**
2127 * A client sent us data. Receive and process it. If we are done,
2128 * reschedule this task.
2129 *
2130 * @param cls the `struct GNUNET_SERVICE_Client` that sent us data.
2131 */
2132static void
2133service_client_recv (void *cls)
2134{
2135 struct GNUNET_SERVICE_Client *client = cls;
2136 int ret;
2137
2138 client->recv_task = NULL;
2139 ret = GNUNET_MST_read (client->mst,
2140 client->sock,
2141 GNUNET_NO,
2142 GNUNET_YES);
2143 if (GNUNET_SYSERR == ret)
2144 {
2145 /* client closed connection (or IO error) */
2146 if (NULL == client->drop_task)
2147 {
2148 GNUNET_assert (GNUNET_NO == client->needs_continue);
2149 GNUNET_SERVICE_client_drop (client);
2150 }
2151 return;
2152 }
2153 if (GNUNET_NO == ret)
2154 return; /* more messages in buffer, wait for application
2155 to be done processing */
2156 GNUNET_assert (GNUNET_OK == ret);
2157 if (GNUNET_YES == client->needs_continue)
2158 return;
2159 if (NULL != client->recv_task)
2160 return;
2161 /* MST needs more data, re-schedule read job */
2162 client->recv_task
2163 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
2164 client->sock,
2165 &service_client_recv,
2166 client);
2167}
2168
2169
2170/**
2171 * We have successfully accepted a connection from a client. Now
2172 * setup the client (with the scheduler) and tell the application.
2173 *
2174 * @param sh service that accepted the client
2175 * @param sock socket associated with the client
2176 */
2177static void
2178start_client (struct GNUNET_SERVICE_Handle *sh,
2179 struct GNUNET_NETWORK_Handle *csock)
2180{
2181 struct GNUNET_SERVICE_Client *client;
2182
2183 client = GNUNET_new (struct GNUNET_SERVICE_Client);
2184 GNUNET_CONTAINER_DLL_insert (sh->clients_head,
2185 sh->clients_tail,
2186 client);
2187 client->sh = sh;
2188 client->sock = csock;
2189 client->mq = GNUNET_MQ_queue_for_callbacks (&service_mq_send,
2190 NULL,
2191 &service_mq_cancel,
2192 client,
2193 sh->handlers,
2194 &service_mq_error_handler,
2195 client);
2196 client->mst = GNUNET_MST_create (&service_client_mst_cb,
2197 client);
2198 if (NULL != sh->connect_cb)
2199 client->user_context = sh->connect_cb (sh->cb_cls,
2200 client,
2201 client->mq);
2202 GNUNET_MQ_set_handlers_closure (client->mq,
2203 client->user_context);
2204 client->recv_task
2205 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
2206 client->sock,
2207 &service_client_recv,
2208 client);
2209}
2210
2211
2212/**
2213 * Check if the given IP address is in the list of IP addresses.
2214 *
2215 * @param list a list of networks
2216 * @param add the IP to check (in network byte order)
2217 * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is
2218 */
2219static int
2220check_ipv4_listed (const struct GNUNET_STRINGS_IPv4NetworkPolicy *list,
2221 const struct in_addr *add)
2222{
2223 unsigned int i;
2224
2225 if (NULL == list)
2226 return GNUNET_NO;
2227 i = 0;
2228 while ( (0 != list[i].network.s_addr) ||
2229 (0 != list[i].netmask.s_addr) )
2230 {
2231 if ((add->s_addr & list[i].netmask.s_addr) ==
2232 (list[i].network.s_addr & list[i].netmask.s_addr))
2233 return GNUNET_YES;
2234 i++;
2235 }
2236 return GNUNET_NO;
2237}
2238
2239
2240/**
2241 * Check if the given IP address is in the list of IP addresses.
2242 *
2243 * @param list a list of networks
2244 * @param ip the IP to check (in network byte order)
2245 * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is
2246 */
2247static int
2248check_ipv6_listed (const struct GNUNET_STRINGS_IPv6NetworkPolicy *list,
2249 const struct in6_addr *ip)
2250{
2251 unsigned int i;
2252 unsigned int j;
2253 struct in6_addr zero;
2254
2255 if (NULL == list)
2256 return GNUNET_NO;
2257 memset (&zero,
2258 0,
2259 sizeof (struct in6_addr));
2260 i = 0;
2261NEXT:
2262 while (0 != memcmp (&zero,
2263 &list[i].network,
2264 sizeof (struct in6_addr)))
2265 {
2266 for (j = 0; j < sizeof (struct in6_addr) / sizeof (int); j++)
2267 if (((((int *) ip)[j] & ((int *) &list[i].netmask)[j])) !=
2268 (((int *) &list[i].network)[j] & ((int *) &list[i].netmask)[j]))
2269 {
2270 i++;
2271 goto NEXT;
2272 }
2273 return GNUNET_YES;
2274 }
2275 return GNUNET_NO;
2276}
2277
2278
2279/**
2280 * We have a client. Accept the incoming socket(s) (and reschedule
2281 * the listen task).
2282 *
2283 * @param cls the `struct ServiceListenContext` of the ready listen socket
2284 */
2285static void
2286accept_client (void *cls)
2287{
2288 struct ServiceListenContext *slc = cls;
2289 struct GNUNET_SERVICE_Handle *sh = slc->sh;
2290
2291 slc->listen_task = NULL;
2292 while (1)
2293 {
2294 struct GNUNET_NETWORK_Handle *sock;
2295 const struct sockaddr_in *v4;
2296 const struct sockaddr_in6 *v6;
2297 struct sockaddr_storage sa;
2298 socklen_t addrlen;
2299 int ok;
2300
2301 addrlen = sizeof (sa);
2302 sock = GNUNET_NETWORK_socket_accept (slc->listen_socket,
2303 (struct sockaddr *) &sa,
2304 &addrlen);
2305 if (NULL == sock)
2306 break;
2307 switch (sa.ss_family)
2308 {
2309 case AF_INET:
2310 GNUNET_assert (addrlen == sizeof (struct sockaddr_in));
2311 v4 = (const struct sockaddr_in *) &sa;
2312 ok = ( ( (NULL == sh->v4_allowed) ||
2313 (check_ipv4_listed (sh->v4_allowed,
2314 &v4->sin_addr))) &&
2315 ( (NULL == sh->v4_denied) ||
2316 (! check_ipv4_listed (sh->v4_denied,
2317 &v4->sin_addr)) ) );
2318 break;
2319 case AF_INET6:
2320 GNUNET_assert (addrlen == sizeof (struct sockaddr_in6));
2321 v6 = (const struct sockaddr_in6 *) &sa;
2322 ok = ( ( (NULL == sh->v6_allowed) ||
2323 (check_ipv6_listed (sh->v6_allowed,
2324 &v6->sin6_addr))) &&
2325 ( (NULL == sh->v6_denied) ||
2326 (! check_ipv6_listed (sh->v6_denied,
2327 &v6->sin6_addr)) ) );
2328 break;
2329#ifndef WINDOWS
2330 case AF_UNIX:
2331 ok = GNUNET_OK; /* controlled using file-system ACL now */
2332 break;
2333#endif
2334 default:
2335 LOG (GNUNET_ERROR_TYPE_WARNING,
2336 _("Unknown address family %d\n"),
2337 sa.ss_family);
2338 return;
2339 }
2340 if (! ok)
2341 {
2342 LOG (GNUNET_ERROR_TYPE_DEBUG,
2343 "Service rejected incoming connection from %s due to policy.\n",
2344 GNUNET_a2s ((const struct sockaddr *) &sa,
2345 addrlen));
2346 GNUNET_break (GNUNET_OK ==
2347 GNUNET_NETWORK_socket_close (sock));
2348 continue;
2349 }
2350 LOG (GNUNET_ERROR_TYPE_DEBUG,
2351 "Service accepted incoming connection from %s.\n",
2352 GNUNET_a2s ((const struct sockaddr *) &sa,
2353 addrlen));
2354 start_client (slc->sh,
2355 sock);
2356 }
2357 slc->listen_task
2358 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
2359 slc->listen_socket,
2360 &accept_client,
2361 slc);
2362}
2363
2364
2365/**
2366 * Resume accepting connections from the listen socket.
2367 *
2368 * @param sh service to resume accepting connections.
2369 */
2370void
2371GNUNET_SERVICE_resume (struct GNUNET_SERVICE_Handle *sh)
2372{
2373 struct ServiceListenContext *slc;
2374
2375 for (slc = sh->slc_head; NULL != slc; slc = slc->next)
2376 {
2377 GNUNET_assert (NULL == slc->listen_task);
2378 slc->listen_task
2379 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
2380 slc->listen_socket,
2381 &accept_client,
2382 slc);
2383 }
2384}
2385
2386
2387/**
2388 * Task run to resume receiving data from the client after
2389 * the client called #GNUNET_SERVICE_client_continue().
2390 *
2391 * @param cls our `struct GNUNET_SERVICE_Client`
2392 */
2393static void
2394resume_client_receive (void *cls)
2395{
2396 struct GNUNET_SERVICE_Client *c = cls;
2397 int ret;
2398
2399 c->recv_task = NULL;
2400 /* first, check if there is still something in the buffer */
2401 ret = GNUNET_MST_next (c->mst,
2402 GNUNET_YES);
2403 if (GNUNET_SYSERR == ret)
2404 {
2405 if (NULL != c->drop_task)
2406 GNUNET_SERVICE_client_drop (c);
2407 return;
2408 }
2409 if (GNUNET_NO == ret)
2410 return; /* done processing, wait for more later */
2411 GNUNET_assert (GNUNET_OK == ret);
2412 if (GNUNET_YES == c->needs_continue)
2413 return; /* #GNUNET_MST_next() did give a message to the client */
2414 /* need to receive more data from the network first */
2415 if (NULL != c->recv_task)
2416 return;
2417 c->recv_task
2418 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
2419 c->sock,
2420 &service_client_recv,
2421 c);
2422}
2423
2424
2425/**
2426 * Continue receiving further messages from the given client.
2427 * Must be called after each message received.
2428 *
2429 * @param c the client to continue receiving from
2430 */
2431void
2432GNUNET_SERVICE_client_continue (struct GNUNET_SERVICE_Client *c)
2433{
2434 GNUNET_assert (GNUNET_YES == c->needs_continue);
2435 GNUNET_assert (NULL == c->recv_task);
2436 c->needs_continue = GNUNET_NO;
2437 if (NULL != c->warn_task)
2438 {
2439 GNUNET_SCHEDULER_cancel (c->warn_task);
2440 c->warn_task = NULL;
2441 }
2442 c->recv_task
2443 = GNUNET_SCHEDULER_add_now (&resume_client_receive,
2444 c);
2445}
2446
2447
2448/**
2449 * Disable the warning the server issues if a message is not
2450 * acknowledged in a timely fashion. Use this call if a client is
2451 * intentionally delayed for a while. Only applies to the current
2452 * message.
2453 *
2454 * @param c client for which to disable the warning
2455 */
2456void
2457GNUNET_SERVICE_client_disable_continue_warning (struct GNUNET_SERVICE_Client *c)
2458{
2459 GNUNET_break (NULL != c->warn_task);
2460 if (NULL != c->warn_task)
2461 {
2462 GNUNET_SCHEDULER_cancel (c->warn_task);
2463 c->warn_task = NULL;
2464 }
2465}
2466
2467
2468/**
2469 * Asynchronously finish dropping the client.
2470 *
2471 * @param cls the `struct GNUNET_SERVICE_Client`.
2472 */
2473static void
2474finish_client_drop (void *cls)
2475{
2476 struct GNUNET_SERVICE_Client *c = cls;
2477 struct GNUNET_SERVICE_Handle *sh = c->sh;
2478
2479 c->drop_task = NULL;
2480 GNUNET_assert (NULL == c->send_task);
2481 GNUNET_assert (NULL == c->recv_task);
2482 GNUNET_assert (NULL == c->warn_task);
2483 GNUNET_MST_destroy (c->mst);
2484 GNUNET_MQ_destroy (c->mq);
2485 if (GNUNET_NO == c->persist)
2486 {
2487 GNUNET_break (GNUNET_OK ==
2488 GNUNET_NETWORK_socket_close (c->sock));
2489 }
2490 else
2491 {
2492 GNUNET_NETWORK_socket_free_memory_only_ (c->sock);
2493 }
2494 GNUNET_free (c);
2495 if ( (GNUNET_YES == sh->got_shutdown) &&
2496 (GNUNET_NO == have_non_monitor_clients (sh)) )
2497 GNUNET_SERVICE_shutdown (sh);
2498}
2499
2500
2501/**
2502 * Ask the server to disconnect from the given client. This is the
2503 * same as returning #GNUNET_SYSERR within the check procedure when
2504 * handling a message, wexcept that it allows dropping of a client even
2505 * when not handling a message from that client. The `disconnect_cb`
2506 * will be called on @a c even if the application closes the connection
2507 * using this function.
2508 *
2509 * @param c client to disconnect now
2510 */
2511void
2512GNUNET_SERVICE_client_drop (struct GNUNET_SERVICE_Client *c)
2513{
2514 struct GNUNET_SERVICE_Handle *sh = c->sh;
2515
2516 if (NULL != c->drop_task)
2517 {
2518 /* asked to drop twice! */
2519 GNUNET_assert (0);
2520 return;
2521 }
2522 GNUNET_CONTAINER_DLL_remove (sh->clients_head,
2523 sh->clients_tail,
2524 c);
2525 if (NULL != sh->disconnect_cb)
2526 sh->disconnect_cb (sh->cb_cls,
2527 c,
2528 c->user_context);
2529 if (NULL != c->warn_task)
2530 {
2531 GNUNET_SCHEDULER_cancel (c->warn_task);
2532 c->warn_task = NULL;
2533 }
2534 if (NULL != c->recv_task)
2535 {
2536 GNUNET_SCHEDULER_cancel (c->recv_task);
2537 c->recv_task = NULL;
2538 }
2539 if (NULL != c->send_task)
2540 {
2541 GNUNET_SCHEDULER_cancel (c->send_task);
2542 c->send_task = NULL;
2543 }
2544 c->drop_task = GNUNET_SCHEDULER_add_now (&finish_client_drop,
2545 c);
2546}
2547
2548
2549/**
2550 * Explicitly stops the service.
2551 *
2552 * @param sh server to shutdown
2553 */
2554void
2555GNUNET_SERVICE_shutdown (struct GNUNET_SERVICE_Handle *sh)
2556{
2557 struct GNUNET_SERVICE_Client *client;
2558
2559 GNUNET_SERVICE_suspend (sh);
2560 sh->got_shutdown = GNUNET_NO;
2561 while (NULL != (client = sh->clients_head))
2562 GNUNET_SERVICE_client_drop (client);
2563}
2564
2565
2566/**
2567 * Set the 'monitor' flag on this client. Clients which have been
2568 * marked as 'monitors' won't prevent the server from shutting down
2569 * once #GNUNET_SERVICE_stop_listening() has been invoked. The idea is
2570 * that for "normal" clients we likely want to allow them to process
2571 * their requests; however, monitor-clients are likely to 'never'
2572 * disconnect during shutdown and thus will not be considered when
2573 * determining if the server should continue to exist after
2574 * shutdown has been triggered.
2575 *
2576 * @param c client to mark as a monitor
2577 */
2578void
2579GNUNET_SERVICE_client_mark_monitor (struct GNUNET_SERVICE_Client *c)
2580{
2581 c->is_monitor = GNUNET_YES;
2582 if ( (GNUNET_YES == c->sh->got_shutdown) &&
2583 (GNUNET_NO == have_non_monitor_clients (c->sh)) )
2584 GNUNET_SERVICE_shutdown (c->sh);
2585}
2586
2587
2588/**
2589 * Set the persist option on this client. Indicates that the
2590 * underlying socket or fd should never really be closed. Used for
2591 * indicating process death.
2592 *
2593 * @param c client to persist the socket (never to be closed)
2594 */
2595void
2596GNUNET_SERVICE_client_persist (struct GNUNET_SERVICE_Client *c)
2597{
2598 c->persist = GNUNET_YES;
2599}
2600
2601
2602/**
2603 * Obtain the message queue of @a c. Convenience function.
2604 *
2605 * @param c the client to continue receiving from
2606 * @return the message queue of @a c
2607 */
2608struct GNUNET_MQ_Handle *
2609GNUNET_SERVICE_client_get_mq (struct GNUNET_SERVICE_Client *c)
2610{
2611 return c->mq;
2612}
2613
2614
2615/* end of service_new.c */
diff --git a/src/util/socks.c b/src/util/socks.c
index 37e60e3e4..85548fd79 100644
--- a/src/util/socks.c
+++ b/src/util/socks.c
@@ -372,15 +372,18 @@ transmit_ready (void *cls,
372 return 0; 372 return 0;
373 } 373 }
374 374
375 GNUNET_assert (1024 >= size && size > 0); 375 GNUNET_assert ( (1024 >= size) && (size > 0) );
376 GNUNET_assert (SOCKS5_step_done > ih->step && ih->step >= 0); 376 GNUNET_assert ( (SOCKS5_step_done > ih->step) && (ih->step >= 0) );
377 unsigned char * b = ih->outstep[ih->step]; 377 unsigned char * b = ih->outstep[ih->step];
378 unsigned char * e = ih->outstep[ih->step+1]; 378 unsigned char * e = ih->outstep[ih->step+1];
379 GNUNET_assert (e <= &ih->outbuf[1024]); 379 GNUNET_assert (e <= &ih->outbuf[1024]);
380 unsigned l = e - b; 380 unsigned int l = e - b;
381 GNUNET_assert (size >= l && l >= 0); 381 GNUNET_assert (size >= l);
382 GNUNET_memcpy(buf, b, l); 382 GNUNET_memcpy (buf,
383 register_reciever (ih, register_reciever_wants(ih)); 383 b,
384 l);
385 register_reciever (ih,
386 register_reciever_wants (ih));
384 return l; 387 return l;
385} 388}
386 389
@@ -566,17 +569,25 @@ GNUNET_SOCKS_check_service (const char *service_name,
566 */ 569 */
567struct GNUNET_CONNECTION_Handle * 570struct GNUNET_CONNECTION_Handle *
568GNUNET_SOCKS_do_connect (const char *service_name, 571GNUNET_SOCKS_do_connect (const char *service_name,
569 const struct GNUNET_CONFIGURATION_Handle *cfg) 572 const struct GNUNET_CONFIGURATION_Handle *cfg)
570{ 573{
571 struct GNUNET_SOCKS_Handshake *ih; 574 struct GNUNET_SOCKS_Handshake *ih;
572 struct GNUNET_CONNECTION_Handle *socks5; /* *proxied */ 575 struct GNUNET_CONNECTION_Handle *socks5; /* *proxied */
573 char *host0,*host1,*user,*pass; 576 char *host0;
574 unsigned long long port0,port1; 577 char *host1;
575 578 char *user;
576 if (GNUNET_YES != GNUNET_SOCKS_check_service (service_name, cfg)) 579 char *pass;
580 unsigned long long port0;
581 unsigned long long port1;
582
583 if (GNUNET_YES !=
584 GNUNET_SOCKS_check_service (service_name, cfg))
577 return NULL; 585 return NULL;
578 if (GNUNET_OK != 586 if (GNUNET_OK !=
579 GNUNET_CONFIGURATION_get_value_number (cfg, service_name, "SOCKSPORT", &port0)) 587 GNUNET_CONFIGURATION_get_value_number (cfg,
588 service_name,
589 "SOCKSPORT",
590 &port0))
580 port0 = 9050; 591 port0 = 9050;
581 /* A typical Tor client should usually try port 9150 for the TBB too, but 592 /* A typical Tor client should usually try port 9150 for the TBB too, but
582 * GNUnet can probably assume a system Tor installation. */ 593 * GNUnet can probably assume a system Tor installation. */
@@ -588,16 +599,23 @@ GNUNET_SOCKS_do_connect (const char *service_name,
588 service_name); 599 service_name);
589 return NULL; 600 return NULL;
590 } 601 }
591 if ((GNUNET_OK != 602 if ( (GNUNET_OK !=
592 GNUNET_CONFIGURATION_get_value_number (cfg, service_name, "PORT", &port1)) 603 GNUNET_CONFIGURATION_get_value_number (cfg,
593 || (port1 > 65535) || (port1 <= 0) || 604 service_name,
605 "PORT",
606 &port1)) ||
607 (port1 > 65535) ||
608 (port1 <= 0) ||
594 (GNUNET_OK != 609 (GNUNET_OK !=
595 GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "HOSTNAME", &host1))) 610 GNUNET_CONFIGURATION_get_value_string (cfg,
611 service_name,
612 "HOSTNAME",
613 &host1)))
596 { 614 {
597 LOG (GNUNET_ERROR_TYPE_WARNING, 615 LOG (GNUNET_ERROR_TYPE_WARNING,
598 _ 616 _("Attempting to proxy service `%s' to invalid port %d or hostname.\n"),
599 ("Attempting to proxy service `%s' to invalid port %d or hostname `%s'.\n"), 617 service_name,
600 service_name,port1,host1); 618 port1);
601 return NULL; 619 return NULL;
602 } 620 }
603 /* Appeared to still work after host0 corrupted, so either test case is broken, or 621 /* Appeared to still work after host0 corrupted, so either test case is broken, or
@@ -605,20 +623,32 @@ GNUNET_SOCKS_do_connect (const char *service_name,
605 if (GNUNET_OK != 623 if (GNUNET_OK !=
606 GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "SOCKSHOST", &host0)) 624 GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "SOCKSHOST", &host0))
607 host0 = NULL; 625 host0 = NULL;
608 socks5 = GNUNET_CONNECTION_create_from_connect (cfg, (host0 != NULL)? host0:"127.0.0.1", port0); 626 socks5 = GNUNET_CONNECTION_create_from_connect (cfg,
627 (host0 != NULL)
628 ? host0
629 :"127.0.0.1",
630 port0);
609 GNUNET_free_non_null (host0); 631 GNUNET_free_non_null (host0);
610 632
611 /* Sets to NULL if they do not exist */ 633 /* Sets to NULL if they do not exist */
612 (void) GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "SOCKSUSER", &user); 634 (void) GNUNET_CONFIGURATION_get_value_string (cfg,
613 (void) GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "SOCKSPASS", &pass); 635 service_name,
636 "SOCKSUSER",
637 &user);
638 (void) GNUNET_CONFIGURATION_get_value_string (cfg,
639 service_name,
640 "SOCKSPASS",
641 &pass);
614 ih = GNUNET_SOCKS_init_handshake(user,pass); 642 ih = GNUNET_SOCKS_init_handshake(user,pass);
615 if (NULL != user) GNUNET_free (user); 643 GNUNET_free_non_null (user);
616 if (NULL != pass) GNUNET_free (pass); 644 GNUNET_free_non_null (pass);
617 645
618 GNUNET_SOCKS_set_handshake_destination (ih,host1,port1); 646 GNUNET_SOCKS_set_handshake_destination (ih,
647 host1,
648 port1);
619 GNUNET_free (host1); 649 GNUNET_free (host1);
620 650 return GNUNET_SOCKS_run_handshake (ih,
621 return GNUNET_SOCKS_run_handshake(ih,socks5); 651 socks5);
622} 652}
623 653
624/* socks.c */ 654/* socks.c */
diff --git a/src/util/test_client.c b/src/util/test_client.c
index f60e5b7f7..527b400b0 100644
--- a/src/util/test_client.c
+++ b/src/util/test_client.c
@@ -179,7 +179,7 @@ main (int argc,
179 test_argv[2] = "test_client_unix.conf"; 179 test_argv[2] = "test_client_unix.conf";
180 global_ret = 1; 180 global_ret = 1;
181 if (0 != 181 if (0 !=
182 GNUNET_SERVICE_ruN_ (3, 182 GNUNET_SERVICE_run_ (3,
183 test_argv, 183 test_argv,
184 "test_client", 184 "test_client",
185 GNUNET_SERVICE_OPTION_NONE, 185 GNUNET_SERVICE_OPTION_NONE,
diff --git a/src/util/test_common_allocation.c b/src/util/test_common_allocation.c
index 4ef98b629..4d1b6fe7d 100644
--- a/src/util/test_common_allocation.c
+++ b/src/util/test_common_allocation.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 Copyright (C) 2001, 2002, 2003, 2005, 2006 GNUnet e.V. 3 Copyright (C) 2001, 2002, 2003, 2005, 2006, 2017 GNUnet e.V.
4 4
5 GNUnet is free software; you can redistribute it and/or modify 5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published 6 it under the terms of the GNU General Public License as published
@@ -25,6 +25,7 @@
25#include "platform.h" 25#include "platform.h"
26#include "gnunet_util_lib.h" 26#include "gnunet_util_lib.h"
27 27
28
28static int 29static int
29check () 30check ()
30{ 31{
@@ -95,47 +96,57 @@ check ()
95 if (ptrs[0] != NULL) 96 if (ptrs[0] != NULL)
96 return 9; 97 return 9;
97 98
98 /* GNUNET_new_array_2d tests */ 99 /* GNUNET_new_array_2d tests */
99 a2 = GNUNET_new_array_2d (17, 22, unsigned int); 100 a2 = GNUNET_new_array_2d (17, 22, unsigned int);
100 for (i = 0; i < 17; i++) 101 for (i = 0; i < 17; i++)
101 { 102 {
102 for (j = 0; j < 22; j++) 103 for (j = 0; j < 22; j++)
103 { 104 {
104 if (0 != a2[i][j]) 105 if (0 != a2[i][j])
105 return 10; 106 {
106 a2[i][j] = i * 100 + j; 107 GNUNET_free (a2);
107 } 108 return 10;
108 } 109 }
109 free (a2); 110 a2[i][j] = i * 100 + j;
110 111 }
111 /* GNUNET_new_array_3d tests */ 112 }
112 a3 = GNUNET_new_array_3d (2, 3, 4, char); 113 GNUNET_free (a2);
113 for (i = 0; i < 2; i++)
114 {
115 for (j = 0; j < 3; j++)
116 {
117 for (k = 0; k < 4; k++)
118 {
119 if (0 != a3[i][j][k])
120 return 11;
121 a3[i][j][k] = i * 100 + j * 10 + k;
122 }
123 }
124 }
125 free (a3);
126 114
115 /* GNUNET_new_array_3d tests */
116 a3 = GNUNET_new_array_3d (2, 3, 4, char);
117 for (i = 0; i < 2; i++)
118 {
119 for (j = 0; j < 3; j++)
120 {
121 for (k = 0; k < 4; k++)
122 {
123 if (0 != a3[i][j][k])
124 {
125 GNUNET_free (a3);
126 return 11;
127 }
128 a3[i][j][k] = i * 100 + j * 10 + k;
129 }
130 }
131 }
132 GNUNET_free (a3);
127 return 0; 133 return 0;
128} 134}
129 135
136
130int 137int
131main (int argc, char *argv[]) 138main (int argc, char *argv[])
132{ 139{
133 int ret; 140 int ret;
134 141
135 GNUNET_log_setup ("test-common-allocation", "WARNING", NULL); 142 GNUNET_log_setup ("test-common-allocation",
143 "WARNING",
144 NULL);
136 ret = check (); 145 ret = check ();
137 if (ret != 0) 146 if (ret != 0)
138 FPRINTF (stderr, "ERROR %d.\n", ret); 147 FPRINTF (stderr,
148 "ERROR %d.\n",
149 ret);
139 return ret; 150 return ret;
140} 151}
141 152
diff --git a/src/util/test_connection.c b/src/util/test_connection.c
deleted file mode 100644
index eaca75c2e..000000000
--- a/src/util/test_connection.c
+++ /dev/null
@@ -1,167 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20/**
21 * @file util/test_connection.c
22 * @brief tests for connection.c
23 */
24#include "platform.h"
25#include "gnunet_util_lib.h"
26
27#define PORT 12435
28
29
30static struct GNUNET_CONNECTION_Handle *csock;
31
32static struct GNUNET_CONNECTION_Handle *asock;
33
34static struct GNUNET_CONNECTION_Handle *lsock;
35
36static size_t sofar;
37
38static struct GNUNET_NETWORK_Handle *ls;
39
40static struct GNUNET_CONFIGURATION_Handle *cfg;
41
42/**
43 * Create and initialize a listen socket for the server.
44 *
45 * @return -1 on error, otherwise the listen socket
46 */
47static struct GNUNET_NETWORK_Handle *
48open_listen_socket ()
49{
50 const static int on = 1;
51 struct sockaddr_in sa;
52 struct GNUNET_NETWORK_Handle *desc;
53
54 memset (&sa, 0, sizeof (sa));
55#if HAVE_SOCKADDR_IN_SIN_LEN
56 sa.sin_len = sizeof (sa);
57#endif
58 sa.sin_port = htons (PORT);
59 sa.sin_family = AF_INET;
60 desc = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0);
61 GNUNET_assert (desc != NULL);
62 if (GNUNET_NETWORK_socket_setsockopt
63 (desc, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK)
64 GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "setsockopt");
65 GNUNET_assert (GNUNET_OK ==
66 GNUNET_NETWORK_socket_bind (desc, (const struct sockaddr *) &sa,
67 sizeof (sa)));
68 GNUNET_NETWORK_socket_listen (desc, 5);
69 return desc;
70}
71
72static void
73receive_check (void *cls, const void *buf, size_t available,
74 const struct sockaddr *addr, socklen_t addrlen, int errCode)
75{
76 int *ok = cls;
77
78 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receive validates incoming data\n");
79 GNUNET_assert (buf != NULL); /* no timeout */
80 if (0 == memcmp (&"Hello World"[sofar], buf, available))
81 sofar += available;
82 if (sofar < 12)
83 {
84 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receive needs more data\n");
85 GNUNET_CONNECTION_receive (asock, 1024,
86 GNUNET_TIME_relative_multiply
87 (GNUNET_TIME_UNIT_SECONDS, 5), &receive_check,
88 cls);
89 }
90 else
91 {
92 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receive closes accepted socket\n");
93 *ok = 0;
94 GNUNET_CONNECTION_destroy (asock);
95 GNUNET_CONNECTION_destroy (csock);
96 }
97}
98
99
100static void
101run_accept (void *cls)
102{
103 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test accepts connection\n");
104 asock = GNUNET_CONNECTION_create_from_accept (NULL, NULL, ls);
105 GNUNET_assert (asock != NULL);
106 GNUNET_assert (GNUNET_YES == GNUNET_CONNECTION_check (asock));
107 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test destroys listen socket\n");
108 GNUNET_CONNECTION_destroy (lsock);
109 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
110 "Test asks to receive on accepted socket\n");
111 GNUNET_CONNECTION_receive (asock, 1024,
112 GNUNET_TIME_relative_multiply
113 (GNUNET_TIME_UNIT_SECONDS, 5), &receive_check,
114 cls);
115}
116
117
118static size_t
119make_hello (void *cls, size_t size, void *buf)
120{
121 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
122 "Test prepares to transmit on connect socket\n");
123 GNUNET_assert (size >= 12);
124 strcpy ((char *) buf, "Hello World");
125 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test destroys client socket\n");
126 return 12;
127}
128
129
130static void
131task (void *cls)
132{
133 ls = open_listen_socket ();
134 lsock = GNUNET_CONNECTION_create_from_existing (ls);
135 GNUNET_assert (lsock != NULL);
136 csock = GNUNET_CONNECTION_create_from_connect (cfg, "localhost", PORT);
137 GNUNET_assert (csock != NULL);
138 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test asks for write notification\n");
139 GNUNET_assert (NULL !=
140 GNUNET_CONNECTION_notify_transmit_ready (csock, 12,
141 GNUNET_TIME_UNIT_SECONDS,
142 &make_hello, NULL));
143 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test prepares to accept\n");
144 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, ls, &run_accept,
145 cls);
146}
147
148
149int
150main (int argc, char *argv[])
151{
152 int ok;
153
154 GNUNET_log_setup ("test_connection",
155 "WARNING",
156 NULL);
157
158 ok = 1;
159 cfg = GNUNET_CONFIGURATION_create ();
160 GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME",
161 "localhost");
162 GNUNET_SCHEDULER_run (&task, &ok);
163 GNUNET_CONFIGURATION_destroy (cfg);
164 return ok;
165}
166
167/* end of test_connection.c */
diff --git a/src/util/test_connection_addressing.c b/src/util/test_connection_addressing.c
deleted file mode 100644
index a6345b10a..000000000
--- a/src/util/test_connection_addressing.c
+++ /dev/null
@@ -1,186 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20/**
21 * @file util/test_connection_addressing.c
22 * @brief tests for connection.c
23 */
24#include "platform.h"
25#include "gnunet_util_lib.h"
26
27
28#define PORT 12435
29
30
31static struct GNUNET_CONNECTION_Handle *csock;
32
33static struct GNUNET_CONNECTION_Handle *asock;
34
35static struct GNUNET_CONNECTION_Handle *lsock;
36
37static size_t sofar;
38
39static struct GNUNET_NETWORK_Handle *ls;
40
41
42
43/**
44 * Create and initialize a listen socket for the server.
45 *
46 * @return NULL on error, otherwise the listen socket
47 */
48static struct GNUNET_NETWORK_Handle *
49open_listen_socket ()
50{
51 const static int on = 1;
52 struct sockaddr_in sa;
53 struct GNUNET_NETWORK_Handle *desc;
54
55 memset (&sa, 0, sizeof (sa));
56#if HAVE_SOCKADDR_IN_SIN_LEN
57 sa.sin_len = sizeof (sa);
58#endif
59 sa.sin_family = AF_INET;
60 sa.sin_port = htons (PORT);
61 desc = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0);
62 GNUNET_assert (desc != 0);
63 if (GNUNET_NETWORK_socket_setsockopt
64 (desc, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK)
65 GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "setsockopt");
66 if (GNUNET_OK !=
67 GNUNET_NETWORK_socket_bind (desc, (const struct sockaddr *) &sa,
68 sizeof (sa)))
69 {
70 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
71 "bind");
72 GNUNET_assert (0);
73 }
74 GNUNET_NETWORK_socket_listen (desc, 5);
75 return desc;
76}
77
78
79static void
80receive_check (void *cls, const void *buf, size_t available,
81 const struct sockaddr *addr, socklen_t addrlen, int errCode)
82{
83 int *ok = cls;
84
85 GNUNET_assert (buf != NULL); /* no timeout */
86 if (0 == memcmp (&"Hello World"[sofar], buf, available))
87 sofar += available;
88 if (sofar < 12)
89 {
90 GNUNET_CONNECTION_receive (asock, 1024,
91 GNUNET_TIME_relative_multiply
92 (GNUNET_TIME_UNIT_SECONDS, 5), &receive_check,
93 cls);
94 }
95 else
96 {
97 *ok = 0;
98 GNUNET_CONNECTION_destroy (csock);
99 GNUNET_CONNECTION_destroy (asock);
100 }
101}
102
103
104static void
105run_accept (void *cls)
106{
107 void *addr;
108 size_t alen;
109 struct sockaddr_in *v4;
110 struct sockaddr_in expect;
111
112 asock = GNUNET_CONNECTION_create_from_accept (NULL, NULL, ls);
113 GNUNET_assert (asock != NULL);
114 GNUNET_assert (GNUNET_YES == GNUNET_CONNECTION_check (asock));
115 GNUNET_assert (GNUNET_OK ==
116 GNUNET_CONNECTION_get_address (asock, &addr, &alen));
117 GNUNET_assert (alen == sizeof (struct sockaddr_in));
118 v4 = addr;
119 memset (&expect, 0, sizeof (expect));
120#if HAVE_SOCKADDR_IN_SIN_LEN
121 expect.sin_len = sizeof (expect);
122#endif
123 expect.sin_family = AF_INET;
124 expect.sin_port = v4->sin_port;
125 expect.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
126 GNUNET_assert (0 == memcmp (&expect, v4, alen));
127 GNUNET_free (addr);
128 GNUNET_CONNECTION_destroy (lsock);
129 GNUNET_CONNECTION_receive (asock, 1024,
130 GNUNET_TIME_relative_multiply
131 (GNUNET_TIME_UNIT_SECONDS, 5), &receive_check,
132 cls);
133}
134
135static size_t
136make_hello (void *cls, size_t size, void *buf)
137{
138 GNUNET_assert (size >= 12);
139 strcpy ((char *) buf, "Hello World");
140 return 12;
141}
142
143
144static void
145task (void *cls)
146{
147 struct sockaddr_in v4;
148
149 ls = open_listen_socket ();
150 lsock = GNUNET_CONNECTION_create_from_existing (ls);
151 GNUNET_assert (lsock != NULL);
152
153#if HAVE_SOCKADDR_IN_SIN_LEN
154 v4.sin_len = sizeof (v4);
155#endif
156 v4.sin_family = AF_INET;
157 v4.sin_port = htons (PORT);
158 v4.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
159 csock =
160 GNUNET_CONNECTION_create_from_sockaddr (AF_INET,
161 (const struct sockaddr *) &v4,
162 sizeof (v4));
163 GNUNET_assert (csock != NULL);
164 GNUNET_assert (NULL !=
165 GNUNET_CONNECTION_notify_transmit_ready (csock, 12,
166 GNUNET_TIME_UNIT_SECONDS,
167 &make_hello, NULL));
168 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, ls, &run_accept,
169 cls);
170}
171
172
173int
174main (int argc, char *argv[])
175{
176 int ok;
177
178 GNUNET_log_setup ("test_connection_addressing",
179 "WARNING",
180 NULL);
181 ok = 1;
182 GNUNET_SCHEDULER_run (&task, &ok);
183 return ok;
184}
185
186/* end of test_connection_addressing.c */
diff --git a/src/util/test_connection_receive_cancel.c b/src/util/test_connection_receive_cancel.c
deleted file mode 100644
index 9c0ab699e..000000000
--- a/src/util/test_connection_receive_cancel.c
+++ /dev/null
@@ -1,160 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20/**
21 * @file util/test_connection_receive_cancel.c
22 * @brief tests for connection.c
23 */
24#include "platform.h"
25#include "gnunet_util_lib.h"
26
27#define PORT 12435
28
29
30static struct GNUNET_CONNECTION_Handle *csock;
31
32static struct GNUNET_CONNECTION_Handle *asock;
33
34static struct GNUNET_CONNECTION_Handle *lsock;
35
36static struct GNUNET_NETWORK_Handle *ls;
37
38static struct GNUNET_CONFIGURATION_Handle *cfg;
39
40
41/**
42 * Create and initialize a listen socket for the server.
43 *
44 * @return NULL on error, otherwise the listen socket
45 */
46static struct GNUNET_NETWORK_Handle *
47open_listen_socket ()
48{
49 const static int on = 1;
50 struct sockaddr_in sa;
51 struct GNUNET_NETWORK_Handle *desc;
52
53 memset (&sa, 0, sizeof (sa));
54#if HAVE_SOCKADDR_IN_SIN_LEN
55 sa.sin_len = sizeof (sa);
56#endif
57 sa.sin_family = AF_INET;
58 sa.sin_port = htons (PORT);
59 desc = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0);
60 GNUNET_assert (desc != NULL);
61 if (GNUNET_NETWORK_socket_setsockopt
62 (desc, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK)
63 GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
64 "setsockopt");
65 GNUNET_assert (GNUNET_OK ==
66 GNUNET_NETWORK_socket_bind (desc, (const struct sockaddr *) &sa,
67 sizeof (sa)));
68 GNUNET_NETWORK_socket_listen (desc, 5);
69 return desc;
70}
71
72
73static void
74dead_receive (void *cls,
75 const void *buf,
76 size_t available,
77 const struct sockaddr *addr,
78 socklen_t addrlen,
79 int errCode)
80{
81 GNUNET_assert (0);
82}
83
84
85static void
86run_accept_cancel (void *cls)
87{
88 asock = GNUNET_CONNECTION_create_from_accept (NULL, NULL, ls);
89 GNUNET_assert (asock != NULL);
90 GNUNET_assert (GNUNET_YES == GNUNET_CONNECTION_check (asock));
91 GNUNET_CONNECTION_destroy (lsock);
92 GNUNET_CONNECTION_receive (asock, 1024,
93 GNUNET_TIME_relative_multiply
94 (GNUNET_TIME_UNIT_SECONDS, 5),
95 &dead_receive, cls);
96}
97
98
99static void
100receive_cancel_task (void *cls)
101{
102 int *ok = cls;
103
104 GNUNET_CONNECTION_receive_cancel (asock);
105 GNUNET_CONNECTION_destroy (csock);
106 GNUNET_CONNECTION_destroy (asock);
107 *ok = 0;
108}
109
110
111static void
112task_receive_cancel (void *cls)
113{
114 ls = open_listen_socket ();
115 lsock = GNUNET_CONNECTION_create_from_existing (ls);
116 GNUNET_assert (lsock != NULL);
117 csock = GNUNET_CONNECTION_create_from_connect (cfg, "localhost", PORT);
118 GNUNET_assert (csock != NULL);
119 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
120 ls,
121 &run_accept_cancel,
122 cls);
123 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
124 &receive_cancel_task,
125 cls);
126}
127
128
129/**
130 * Main method, starts scheduler with task_timeout.
131 */
132static int
133check_receive_cancel ()
134{
135 int ok;
136
137 ok = 1;
138 cfg = GNUNET_CONFIGURATION_create ();
139 GNUNET_CONFIGURATION_set_value_string (cfg,
140 "resolver",
141 "HOSTNAME",
142 "localhost");
143 GNUNET_SCHEDULER_run (&task_receive_cancel, &ok);
144 GNUNET_CONFIGURATION_destroy (cfg);
145 return ok;
146}
147
148
149int
150main (int argc, char *argv[])
151{
152 int ret = 0;
153
154 GNUNET_log_setup ("test_connection_receive_cancel", "WARNING", NULL);
155 ret += check_receive_cancel ();
156
157 return ret;
158}
159
160/* end of test_connection_receive_cancel.c */
diff --git a/src/util/test_connection_timeout.c b/src/util/test_connection_timeout.c
deleted file mode 100644
index e78cec669..000000000
--- a/src/util/test_connection_timeout.c
+++ /dev/null
@@ -1,129 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20/**
21 * @file util/test_connection_timeout.c
22 * @brief tests for connection.c
23 */
24#include "platform.h"
25#include "gnunet_util_lib.h"
26
27#define PORT 12435
28
29static struct GNUNET_CONNECTION_Handle *csock;
30
31static struct GNUNET_CONNECTION_Handle *lsock;
32
33static struct GNUNET_NETWORK_Handle *ls;
34
35static struct GNUNET_CONFIGURATION_Handle *cfg;
36
37
38/**
39 * Create and initialize a listen socket for the server.
40 *
41 * @return NULL on error, otherwise the listen socket
42 */
43static struct GNUNET_NETWORK_Handle *
44open_listen_socket ()
45{
46 const static int on = 1;
47 struct sockaddr_in sa;
48 struct GNUNET_NETWORK_Handle *desc;
49
50 memset (&sa, 0, sizeof (sa));
51#if HAVE_SOCKADDR_IN_SIN_LEN
52 sa.sin_len = sizeof (sa);
53#endif
54 sa.sin_family = AF_INET;
55 sa.sin_port = htons (PORT);
56 desc = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0);
57 GNUNET_assert (desc != NULL);
58 if (GNUNET_NETWORK_socket_setsockopt
59 (desc, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK)
60 GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "setsockopt");
61 GNUNET_assert (GNUNET_OK ==
62 GNUNET_NETWORK_socket_bind (desc, (const struct sockaddr *) &sa,
63 sizeof (sa)));
64 GNUNET_NETWORK_socket_listen (desc, 5);
65 return desc;
66}
67
68
69static size_t
70send_kilo (void *cls, size_t size, void *buf)
71{
72 int *ok = cls;
73
74 if (size == 0)
75 {
76 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got the desired timeout!\n");
77 GNUNET_assert (buf == NULL);
78 *ok = 0;
79 GNUNET_CONNECTION_destroy (lsock);
80 GNUNET_CONNECTION_destroy (csock);
81 return 0;
82 }
83 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending kilo to fill buffer.\n");
84 GNUNET_assert (size >= 1024);
85 memset (buf, 42, 1024);
86
87 GNUNET_assert (NULL !=
88 GNUNET_CONNECTION_notify_transmit_ready (csock, 1024,
89 GNUNET_TIME_UNIT_SECONDS,
90 &send_kilo, cls));
91 return 1024;
92}
93
94
95static void
96task_timeout (void *cls)
97{
98
99 ls = open_listen_socket ();
100 lsock = GNUNET_CONNECTION_create_from_existing (ls);
101 GNUNET_assert (lsock != NULL);
102 csock = GNUNET_CONNECTION_create_from_connect (cfg, "localhost", PORT);
103 GNUNET_assert (csock != NULL);
104 GNUNET_assert (NULL !=
105 GNUNET_CONNECTION_notify_transmit_ready (csock, 1024,
106 GNUNET_TIME_UNIT_SECONDS,
107 &send_kilo, cls));
108}
109
110
111int
112main (int argc, char *argv[])
113{
114 int ok;
115
116 GNUNET_log_setup ("test_connection_timeout",
117 "WARNING",
118 NULL);
119
120 ok = 1;
121 cfg = GNUNET_CONFIGURATION_create ();
122 GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME",
123 "localhost");
124 GNUNET_SCHEDULER_run (&task_timeout, &ok);
125 GNUNET_CONFIGURATION_destroy (cfg);
126 return ok;
127}
128
129/* 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
deleted file mode 100644
index ebcd4b71e..000000000
--- a/src/util/test_connection_timeout_no_connect.c
+++ /dev/null
@@ -1,76 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20/**
21 * @file util/test_connection_timeout_no_connect.c
22 * @brief tests for connection.c, doing timeout which connect failure
23 */
24#include "platform.h"
25#include "gnunet_util_lib.h"
26
27#define PORT 13425
28
29static struct GNUNET_CONNECTION_Handle *csock;
30
31static struct GNUNET_CONFIGURATION_Handle *cfg;
32
33static size_t
34handle_timeout (void *cls, size_t size, void *buf)
35{
36 int *ok = cls;
37
38 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received timeout signal.\n");
39 GNUNET_assert (size == 0);
40 GNUNET_assert (buf == NULL);
41 *ok = 0;
42 return 0;
43}
44
45
46static void
47task_timeout (void *cls)
48{
49 csock = GNUNET_CONNECTION_create_from_connect (cfg, "localhost", PORT);
50 GNUNET_assert (csock != NULL);
51 GNUNET_assert (NULL !=
52 GNUNET_CONNECTION_notify_transmit_ready (csock, 1024,
53 GNUNET_TIME_UNIT_SECONDS,
54 &handle_timeout,
55 cls));
56}
57
58
59int
60main (int argc, char *argv[])
61{
62 int ok;
63
64 GNUNET_log_setup ("test_connection_timeout_no_connect",
65 "WARNING",
66 NULL);
67 ok = 1;
68 cfg = GNUNET_CONFIGURATION_create ();
69 GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME",
70 "localhost");
71 GNUNET_SCHEDULER_run (&task_timeout, &ok);
72 GNUNET_CONFIGURATION_destroy (cfg);
73 return ok;
74}
75
76/* 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
deleted file mode 100644
index 9ef0720ed..000000000
--- a/src/util/test_connection_transmit_cancel.c
+++ /dev/null
@@ -1,76 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20/**
21 * @file util/test_connection_transmit_cancel.c
22 * @brief tests for connection.c
23 */
24#include "platform.h"
25#include "gnunet_util_lib.h"
26
27#define PORT 12435
28
29static struct GNUNET_CONFIGURATION_Handle *cfg;
30
31
32static size_t
33not_run (void *cls, size_t size, void *buf)
34{
35 GNUNET_assert (0);
36 return 0;
37}
38
39
40static void
41task_transmit_cancel (void *cls)
42{
43 int *ok = cls;
44 struct GNUNET_CONNECTION_TransmitHandle *th;
45 struct GNUNET_CONNECTION_Handle *csock;
46
47 csock = GNUNET_CONNECTION_create_from_connect (cfg, "localhost", PORT);
48 GNUNET_assert (csock != NULL);
49 th = GNUNET_CONNECTION_notify_transmit_ready (csock, 12,
50 GNUNET_TIME_UNIT_MINUTES,
51 &not_run, cls);
52 GNUNET_assert (NULL != th);
53 GNUNET_CONNECTION_notify_transmit_ready_cancel (th);
54 GNUNET_CONNECTION_destroy (csock);
55 *ok = 0;
56}
57
58
59int
60main (int argc, char *argv[])
61{
62 int ok;
63
64 GNUNET_log_setup ("test_connection_transmit_cancel",
65 "WARNING",
66 NULL);
67 ok = 1;
68 cfg = GNUNET_CONFIGURATION_create ();
69 GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME",
70 "localhost");
71 GNUNET_SCHEDULER_run (&task_transmit_cancel, &ok);
72 GNUNET_CONFIGURATION_destroy (cfg);
73 return ok;
74}
75
76/* end of test_connection_transmit_cancel.c */
diff --git a/src/util/test_getopt.c b/src/util/test_getopt.c
index 8e578640d..13cedd7f5 100644
--- a/src/util/test_getopt.c
+++ b/src/util/test_getopt.c
@@ -136,13 +136,16 @@ testLogOpts ()
136 GNUNET_GETOPT_OPTION_END 136 GNUNET_GETOPT_OPTION_END
137 }; 137 };
138 138
139 if (5 != GNUNET_GETOPT_run ("test_getopt", logoptionlist, 5, myargv)) 139 if (5 != GNUNET_GETOPT_run ("test_getopt",
140 logoptionlist,
141 5, myargv))
140 { 142 {
141 GNUNET_break (0); 143 GNUNET_break (0);
142 return 1; 144 return 1;
143 } 145 }
144 GNUNET_assert (fn != NULL); 146 GNUNET_assert (NULL != fn);
145 if ((0 != strcmp (level, "WARNING")) || (0 != strcmp (fn, "filename"))) 147 if ( (0 != strcmp (level, "WARNING")) ||
148 (NULL == strstr (fn, "/filename")) )
146 { 149 {
147 GNUNET_break (0); 150 GNUNET_break (0);
148 GNUNET_free (level); 151 GNUNET_free (level);
@@ -170,21 +173,35 @@ testFlagNum ()
170 unsigned long long lnum = 0; 173 unsigned long long lnum = 0;
171 174
172 const struct GNUNET_GETOPT_CommandLineOption logoptionlist[] = { 175 const struct GNUNET_GETOPT_CommandLineOption logoptionlist[] = {
173 {'f', "--flag", NULL, "helptext", 0, &GNUNET_GETOPT_set_one, 176 GNUNET_GETOPT_OPTION_SET_ONE ('f',
174 (void *) &flag}, 177 "--flag",
175 {'n', "--num", "ARG", "helptext", 1, &GNUNET_GETOPT_set_uint, 178 "helptext",
176 (void *) &num}, 179 &flag),
177 {'N', "--lnum", "ARG", "helptext", 1, &GNUNET_GETOPT_set_ulong, 180 GNUNET_GETOPT_OPTION_SET_UINT ('n',
178 (void *) &lnum}, 181 "--num",
182 "ARG",
183 "helptext",
184 &num),
185 GNUNET_GETOPT_OPTION_SET_ULONG ('N',
186 "--lnum",
187 "ARG",
188 "helptext",
189 &lnum),
179 GNUNET_GETOPT_OPTION_END 190 GNUNET_GETOPT_OPTION_END
180 }; 191 };
181 192
182 if (6 != GNUNET_GETOPT_run ("test_getopt", logoptionlist, 6, myargv)) 193 if (6 !=
194 GNUNET_GETOPT_run ("test_getopt",
195 logoptionlist,
196 6,
197 myargv))
183 { 198 {
184 GNUNET_break (0); 199 GNUNET_break (0);
185 return 1; 200 return 1;
186 } 201 }
187 if ((1 != flag) || (42 != num) || (42 != lnum)) 202 if ( (1 != flag) ||
203 (42 != num) ||
204 (42 != lnum))
188 { 205 {
189 GNUNET_break (0); 206 GNUNET_break (0);
190 return 1; 207 return 1;
@@ -198,7 +215,9 @@ main (int argc, char *argv[])
198{ 215{
199 int errCnt = 0; 216 int errCnt = 0;
200 217
201 GNUNET_log_setup ("test_getopt", "WARNING", NULL); 218 GNUNET_log_setup ("test_getopt",
219 "WARNING",
220 NULL);
202 /* suppress output from -h, -v options */ 221 /* suppress output from -h, -v options */
203#ifndef MINGW 222#ifndef MINGW
204 GNUNET_break (0 == CLOSE (1)); 223 GNUNET_break (0 == CLOSE (1));
diff --git a/src/util/test_program.c b/src/util/test_program.c
index 669cee7bd..d206952af 100644
--- a/src/util/test_program.c
+++ b/src/util/test_program.c
@@ -24,37 +24,19 @@
24#include "platform.h" 24#include "platform.h"
25#include "gnunet_util_lib.h" 25#include "gnunet_util_lib.h"
26 26
27static int setme1, setme2; 27
28 28static int setme1;
29static struct GNUNET_GETOPT_CommandLineOption options1[] = { 29
30 {'n', "name", NULL, "description", 0, &GNUNET_GETOPT_set_one, &setme1}, 30static int setme2;
31 GNUNET_GETOPT_OPTION_END 31
32};
33
34static struct GNUNET_GETOPT_CommandLineOption options2[] = {
35 {'n', "name", NULL, "description", 0, &GNUNET_GETOPT_set_one, &setme1},
36 {'N', "number", NULL, "description", 0, &GNUNET_GETOPT_set_one, &setme2},
37 GNUNET_GETOPT_OPTION_END
38};
39
40static struct GNUNET_GETOPT_CommandLineOption options3[] = {
41 {'N', "number", NULL, "description", 0, &GNUNET_GETOPT_set_one, &setme1},
42 {'n', "name", NULL, "description", 0, &GNUNET_GETOPT_set_one, &setme2},
43 GNUNET_GETOPT_OPTION_END
44};
45
46static struct GNUNET_GETOPT_CommandLineOption options4[] = {
47 {'n', "name", NULL, "description", 0, &GNUNET_GETOPT_set_one, &setme1},
48 {'n', "number", NULL, "description", 0, &GNUNET_GETOPT_set_one, &setme2},
49 GNUNET_GETOPT_OPTION_END
50};
51 32
52/** 33/**
53 * Main function that will be run. 34 * Main function that will be run.
54 */ 35 */
55
56static void 36static void
57runner (void *cls, char *const *args, const char *cfgfile, 37runner (void *cls,
38 char *const *args,
39 const char *cfgfile,
58 const struct GNUNET_CONFIGURATION_Handle *cfg) 40 const struct GNUNET_CONFIGURATION_Handle *cfg)
59{ 41{
60 int *ok = cls; 42 int *ok = cls;
@@ -62,21 +44,16 @@ runner (void *cls, char *const *args, const char *cfgfile,
62 GNUNET_assert (setme1 == 1); 44 GNUNET_assert (setme1 == 1);
63 GNUNET_assert (0 == strcmp (args[0], "extra")); 45 GNUNET_assert (0 == strcmp (args[0], "extra"));
64 GNUNET_assert (args[1] == NULL); 46 GNUNET_assert (args[1] == NULL);
65 GNUNET_assert (0 == strcmp (cfgfile, "test_program_data.conf")); 47 GNUNET_assert (NULL != strstr (cfgfile, "/test_program_data.conf"));
66
67 *ok = 0; 48 *ok = 0;
68} 49}
69 50
70/** 51
71 * Main method, starts scheduler with task1, 52int
72 * checks that "ok" is correct at the end. 53main (int argc, char *argv[])
73 */
74static int
75check ()
76{ 54{
77 int ok = 1; 55 int ok = 1;
78 56 char *const argvx[] = {
79 char *const argv[] = {
80 "test_program", 57 "test_program",
81 "-c", 58 "-c",
82 "test_program_data.conf", 59 "test_program_data.conf",
@@ -86,33 +63,75 @@ check ()
86 "extra", 63 "extra",
87 NULL 64 NULL
88 }; 65 };
66 struct GNUNET_GETOPT_CommandLineOption options1[] = {
67 GNUNET_GETOPT_OPTION_SET_ONE ('n',
68 "name",
69 "description",
70 &setme1),
71 GNUNET_GETOPT_OPTION_END
72 };
73 struct GNUNET_GETOPT_CommandLineOption options2[] = {
74 GNUNET_GETOPT_OPTION_SET_ONE ('n',
75 "name",
76 "description",
77 &setme1),
78 GNUNET_GETOPT_OPTION_SET_ONE ('N',
79 "number",
80 "description",
81 &setme2),
82 GNUNET_GETOPT_OPTION_END
83 };
84 struct GNUNET_GETOPT_CommandLineOption options3[] = {
85 GNUNET_GETOPT_OPTION_SET_ONE ('N',
86 "number",
87 "description",
88 &setme1),
89 GNUNET_GETOPT_OPTION_SET_ONE ('n',
90 "name",
91 "description",
92 &setme2),
93 GNUNET_GETOPT_OPTION_END
94 };
95 struct GNUNET_GETOPT_CommandLineOption options4[] = {
96 GNUNET_GETOPT_OPTION_SET_ONE ('n',
97 "name",
98 "description",
99 &setme1),
100 GNUNET_GETOPT_OPTION_SET_ONE ('n',
101 "name",
102 "description",
103 &setme2),
104 GNUNET_GETOPT_OPTION_END
105 };
89 106
107
108 GNUNET_log_setup ("test_program",
109 "WARNING",
110 NULL);
90 GNUNET_assert (GNUNET_OK == 111 GNUNET_assert (GNUNET_OK ==
91 GNUNET_PROGRAM_run (7, argv, "test_program", "A test", 112 GNUNET_PROGRAM_run (7, argvx,
92 options1, &runner, &ok)); 113 "test_program",
114 "A test",
115 options1,
116 &runner, &ok));
93 117
94 GNUNET_assert (GNUNET_OK == 118 GNUNET_assert (GNUNET_OK ==
95 GNUNET_PROGRAM_run (7, argv, "test_program", "A test", 119 GNUNET_PROGRAM_run (7, argvx,
96 options2, &runner, &ok)); 120 "test_program", "A test",
121 options2,
122 &runner, &ok));
97 GNUNET_assert (GNUNET_OK == 123 GNUNET_assert (GNUNET_OK ==
98 GNUNET_PROGRAM_run (7, argv, "test_program", "A test", 124 GNUNET_PROGRAM_run (7, argvx,
99 options3, &runner, &ok)); 125 "test_program", "A test",
126 options3,
127 &runner, &ok));
100 GNUNET_assert (GNUNET_OK == 128 GNUNET_assert (GNUNET_OK ==
101 GNUNET_PROGRAM_run (7, argv, "test_program", "A test", 129 GNUNET_PROGRAM_run (7, argvx,
102 options4, &runner, &ok)); 130 "test_program", "A test",
131 options4,
132 &runner, &ok));
103 133
104 return ok; 134 return ok;
105} 135}
106 136
107int
108main (int argc, char *argv[])
109{
110 int ret = 0;
111
112 GNUNET_log_setup ("test_program", "WARNING", NULL);
113 ret += check ();
114
115 return ret;
116}
117
118/* end of test_program.c */ 137/* end of test_program.c */
diff --git a/src/util/test_server.c b/src/util/test_server.c
deleted file mode 100644
index 8003adbf4..000000000
--- a/src/util/test_server.c
+++ /dev/null
@@ -1,302 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010, 2014, 2016 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20/**
21 * @file util/test_server.c
22 * @brief tests for server.c
23 */
24#include "platform.h"
25#include "gnunet_util_lib.h"
26
27/**
28 * TCP port to use for the server.
29 */
30#define PORT 12435
31
32/**
33 * Timeout to use for operations.
34 */
35#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2)
36
37/**
38 * Test message type.
39 */
40#define MY_TYPE 128
41
42/**
43 * Test message type.
44 */
45#define MY_TYPE2 129
46
47/**
48 * Handle for the server.
49 */
50static struct GNUNET_SERVER_Handle *server;
51
52/**
53 * Handle for the client.
54 */
55static struct GNUNET_MQ_Handle *mq;
56
57/**
58 * Handle of the server for the client.
59 */
60static struct GNUNET_SERVER_Client *argclient;
61
62/**
63 * Our configuration.
64 */
65static struct GNUNET_CONFIGURATION_Handle *cfg;
66
67/**
68 * Number indiciating in which phase of the test we are.
69 */
70static int ok;
71
72
73/**
74 * Final task invoked to clean up.
75 *
76 * @param cls NULL
77 */
78static void
79finish_up (void *cls)
80{
81 GNUNET_assert (7 == ok);
82 ok = 0;
83 GNUNET_SERVER_destroy (server);
84 GNUNET_MQ_destroy (mq);
85 GNUNET_CONFIGURATION_destroy (cfg);
86}
87
88
89/**
90 * The server has received the second message, initiate clean up.
91 *
92 * @param cls NULL
93 * @param client client we got the message from
94 * @param message the message
95 */
96static void
97recv_fin_cb (void *cls,
98 struct GNUNET_SERVER_Client *client,
99 const struct GNUNET_MessageHeader *message)
100{
101 GNUNET_assert (6 == ok);
102 ok = 7;
103 GNUNET_SERVER_receive_done (client, GNUNET_OK);
104 GNUNET_SCHEDULER_add_now (&finish_up, NULL);
105}
106
107
108/**
109 * We have received the reply from the server, check that we are at
110 * the right stage and queue the next message to the server. Cleans
111 * up #argclient.
112 *
113 * @param cls NULL
114 * @param msg message we got from the server
115 */
116static void
117handle_reply (void *cls,
118 const struct GNUNET_MessageHeader *msg)
119{
120 struct GNUNET_MQ_Envelope *env;
121 struct GNUNET_MessageHeader *m;
122
123 GNUNET_assert (4 == ok);
124 ok = 6;
125 env = GNUNET_MQ_msg (m,
126 MY_TYPE2);
127 GNUNET_MQ_send (mq,
128 env);
129}
130
131
132/**
133 * Send a reply of type #MY_TYPE from the server to the client.
134 * Checks that we are in the right phase and transmits the
135 * reply. Cleans up #argclient state.
136 *
137 * @param cls NULL
138 * @param size number of bytes we are allowed to send
139 * @param buf where to copy the reply
140 * @return number of bytes written to @a buf
141 */
142static size_t
143reply_msg (void *cls,
144 size_t size,
145 void *buf)
146{
147 struct GNUNET_MessageHeader msg;
148
149 GNUNET_assert (3 == ok);
150 ok = 4;
151 GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader));
152 msg.type = htons (MY_TYPE);
153 msg.size = htons (sizeof (struct GNUNET_MessageHeader));
154 GNUNET_memcpy (buf, &msg, sizeof (struct GNUNET_MessageHeader));
155 GNUNET_assert (NULL != argclient);
156 GNUNET_SERVER_receive_done (argclient, GNUNET_OK);
157 GNUNET_SERVER_client_drop (argclient);
158 argclient = NULL;
159 return sizeof (struct GNUNET_MessageHeader);
160}
161
162
163/**
164 * Function called whenever the server receives a message of
165 * type #MY_TYPE. Checks that we are at the stage where
166 * we expect the first message, then sends a reply. Stores
167 * the handle to the client in #argclient.
168 *
169 * @param cls NULL
170 * @param client client that sent the message
171 * @param message the message we received
172 */
173static void
174recv_cb (void *cls,
175 struct GNUNET_SERVER_Client *client,
176 const struct GNUNET_MessageHeader *message)
177{
178 GNUNET_assert (2 == ok);
179 ok = 3;
180 argclient = client;
181 GNUNET_SERVER_client_keep (argclient);
182 GNUNET_assert (sizeof (struct GNUNET_MessageHeader) == ntohs (message->size));
183 GNUNET_assert (MY_TYPE == ntohs (message->type));
184 GNUNET_assert (NULL !=
185 GNUNET_SERVER_notify_transmit_ready (client,
186 ntohs (message->size),
187 TIMEOUT,
188 &reply_msg,
189 NULL));
190}
191
192
193/**
194 * Message handlers for the server.
195 */
196static struct GNUNET_SERVER_MessageHandler handlers[] = {
197 {&recv_cb, NULL, MY_TYPE, sizeof (struct GNUNET_MessageHeader)},
198 {&recv_fin_cb, NULL, MY_TYPE2, sizeof (struct GNUNET_MessageHeader)},
199 {NULL, NULL, 0, 0}
200};
201
202
203/**
204 * Generic error handler, called with the appropriate error code and
205 * the same closure specified at the creation of the message queue.
206 * Not every message queue implementation supports an error handler.
207 *
208 * @param cls closure with the `struct GNUNET_STATISTICS_Handle *`
209 * @param error error code
210 */
211static void
212mq_error_handler (void *cls,
213 enum GNUNET_MQ_Error error)
214{
215 GNUNET_assert (0); /* should never happen */
216}
217
218
219/**
220 * First task run by the scheduler. Initializes the server and
221 * a client and asks for a transmission from the client to the
222 * server.
223 *
224 * @param cls NULL
225 */
226static void
227task (void *cls)
228{
229 struct sockaddr_in sa;
230 struct sockaddr *sap[2];
231 socklen_t slens[2];
232 struct GNUNET_MQ_Envelope *env;
233 struct GNUNET_MessageHeader *msg;
234 struct GNUNET_MQ_MessageHandler chandlers[] = {
235 GNUNET_MQ_hd_fixed_size (reply,
236 MY_TYPE,
237 struct GNUNET_MessageHeader,
238 cls),
239 GNUNET_MQ_handler_end ()
240 };
241
242 sap[0] = (struct sockaddr *) &sa;
243 slens[0] = sizeof (sa);
244 sap[1] = NULL;
245 slens[1] = 0;
246 memset (&sa, 0, sizeof (sa));
247#if HAVE_SOCKADDR_IN_SIN_LEN
248 sa.sin_len = sizeof (sa);
249#endif
250 sa.sin_family = AF_INET;
251 sa.sin_port = htons (PORT);
252 server = GNUNET_SERVER_create (NULL, NULL,
253 sap, slens,
254 TIMEOUT, GNUNET_NO);
255 GNUNET_assert (server != NULL);
256 GNUNET_SERVER_add_handlers (server, handlers);
257 cfg = GNUNET_CONFIGURATION_create ();
258 GNUNET_CONFIGURATION_set_value_number (cfg,
259 "test-server",
260 "PORT",
261 PORT);
262 GNUNET_CONFIGURATION_set_value_string (cfg,
263 "test-server",
264 "HOSTNAME",
265 "localhost");
266 GNUNET_CONFIGURATION_set_value_string (cfg,
267 "resolver",
268 "HOSTNAME",
269 "localhost");
270 mq = GNUNET_CLIENT_connect (cfg,
271 "test-server",
272 chandlers,
273 &mq_error_handler,
274 NULL);
275 GNUNET_assert (NULL != mq);
276 ok = 2;
277 env = GNUNET_MQ_msg (msg,
278 MY_TYPE);
279 GNUNET_MQ_send (mq,
280 env);
281}
282
283
284/**
285 * Runs the test.
286 *
287 * @param argc length of @a argv
288 * @param argv command line arguments (ignored)
289 * @return 0 on success, otherwise phase of failure
290 */
291int
292main (int argc, char *argv[])
293{
294 GNUNET_log_setup ("test_server",
295 "WARNING",
296 NULL);
297 ok = 1;
298 GNUNET_SCHEDULER_run (&task, &ok);
299 return ok;
300}
301
302/* end of test_server.c */
diff --git a/src/util/test_server_disconnect.c b/src/util/test_server_disconnect.c
deleted file mode 100644
index c3d003e90..000000000
--- a/src/util/test_server_disconnect.c
+++ /dev/null
@@ -1,166 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010, 2016 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20/**
21 * @file util/test_server_disconnect.c
22 * @brief tests for server.c, specifically GNUNET_SERVER_client_disconnect
23 */
24#include "platform.h"
25#include "gnunet_util_lib.h"
26
27
28#define PORT 12435
29
30#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 250)
31
32#define MY_TYPE 128
33
34static struct GNUNET_SERVER_Handle *server;
35
36static struct GNUNET_MQ_Handle *mq;
37
38static struct GNUNET_CONFIGURATION_Handle *cfg;
39
40static int ok;
41
42
43static void
44finish_up (void *cls)
45{
46 GNUNET_assert (ok == 5);
47 ok = 0;
48 GNUNET_SERVER_destroy (server);
49 GNUNET_MQ_destroy (mq);
50 GNUNET_CONFIGURATION_destroy (cfg);
51}
52
53
54static void
55notify_disconnect (void *cls,
56 struct GNUNET_SERVER_Client *clientarg)
57{
58 if (NULL == clientarg)
59 return;
60 GNUNET_assert (ok == 4);
61 ok = 5;
62 GNUNET_SCHEDULER_add_now (&finish_up, NULL);
63}
64
65
66static void
67server_disconnect (void *cls)
68{
69 struct GNUNET_SERVER_Client *argclient = cls;
70
71 GNUNET_assert (ok == 3);
72 ok = 4;
73 GNUNET_SERVER_client_disconnect (argclient);
74 GNUNET_SERVER_client_drop (argclient);
75}
76
77
78static void
79recv_cb (void *cls,
80 struct GNUNET_SERVER_Client *client,
81 const struct GNUNET_MessageHeader *message)
82{
83 GNUNET_assert (ok == 2);
84 ok = 3;
85 GNUNET_SERVER_client_keep (client);
86 GNUNET_SCHEDULER_add_now (&server_disconnect, client);
87 GNUNET_assert (sizeof (struct GNUNET_MessageHeader) == ntohs (message->size));
88 GNUNET_assert (MY_TYPE == ntohs (message->type));
89 GNUNET_SERVER_receive_done (client, GNUNET_OK);
90}
91
92
93static struct GNUNET_SERVER_MessageHandler handlers[] = {
94 {&recv_cb, NULL, MY_TYPE, sizeof (struct GNUNET_MessageHeader)},
95 {NULL, NULL, 0, 0}
96};
97
98
99static void
100task (void *cls)
101{
102 struct sockaddr_in sa;
103 struct sockaddr *sap[2];
104 socklen_t slens[2];
105 struct GNUNET_MQ_Envelope *env;
106 struct GNUNET_MessageHeader *msg;
107
108 sap[0] = (struct sockaddr *) &sa;
109 slens[0] = sizeof (sa);
110 sap[1] = NULL;
111 slens[1] = 0;
112 memset (&sa, 0, sizeof (sa));
113#if HAVE_SOCKADDR_IN_SIN_LEN
114 sa.sin_len = sizeof (sa);
115#endif
116 sa.sin_family = AF_INET;
117 sa.sin_port = htons (PORT);
118 server = GNUNET_SERVER_create (NULL, NULL, sap, slens, TIMEOUT, GNUNET_NO);
119 GNUNET_assert (server != NULL);
120 GNUNET_SERVER_add_handlers (server, handlers);
121 GNUNET_SERVER_disconnect_notify (server, &notify_disconnect, NULL);
122 cfg = GNUNET_CONFIGURATION_create ();
123 GNUNET_CONFIGURATION_set_value_number (cfg, "test-server", "PORT", PORT);
124 GNUNET_CONFIGURATION_set_value_string (cfg, "test-server", "HOSTNAME",
125 "localhost");
126 GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME",
127 "localhost");
128 mq = GNUNET_CLIENT_connect (cfg,
129 "test-server",
130 NULL,
131 NULL,
132 NULL);
133 GNUNET_assert (NULL != mq);
134 ok = 2;
135 env = GNUNET_MQ_msg (msg,
136 MY_TYPE);
137 GNUNET_MQ_send (mq,
138 env);
139}
140
141
142/**
143 * Main method, starts scheduler with task1,
144 * checks that "ok" is correct at the end.
145 */
146static int
147check ()
148{
149 ok = 1;
150 GNUNET_SCHEDULER_run (&task, &ok);
151 return ok;
152}
153
154
155int
156main (int argc, char *argv[])
157{
158 int ret = 0;
159
160 GNUNET_log_setup ("test_server_disconnect", "WARNING", NULL);
161 ret += check ();
162
163 return ret;
164}
165
166/* end of test_server_disconnect.c */
diff --git a/src/util/test_server_mst_interrupt.c b/src/util/test_server_mst_interrupt.c
deleted file mode 100644
index 3141a75bd..000000000
--- a/src/util/test_server_mst_interrupt.c
+++ /dev/null
@@ -1,60 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20/**
21 * @file util/test_server_mst_interrupt.c
22 * @brief test for interrupt message processing in server_mst.c
23 */
24#include "platform.h"
25#include "gnunet_protocols.h"
26#include "gnunet_util_lib.h"
27
28static struct GNUNET_SERVER_MessageStreamTokenizer * mst;
29
30
31/* Callback destroying mst with data in buffer */
32static int
33mst_cb (void *cls, void *client,
34 const struct GNUNET_MessageHeader * message)
35{
36 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MST gave me message, destroying\n");
37 GNUNET_SERVER_mst_destroy (mst);
38 return GNUNET_SYSERR;
39}
40
41
42int
43main (int argc, char *argv[])
44{
45 struct GNUNET_PeerIdentity id;
46 struct GNUNET_MessageHeader msg[2];
47
48 GNUNET_log_setup ("test_server_mst_interrupt", "WARNING", NULL);
49 memset (&id, 0, sizeof (id));
50 msg[0].size = htons (sizeof (msg));
51 msg[0].type = htons (sizeof (GNUNET_MESSAGE_TYPE_DUMMY));
52 mst = GNUNET_SERVER_mst_create(mst_cb, NULL);
53 GNUNET_SERVER_mst_receive (mst, &id,
54 (const char *) &msg, 2 * sizeof (msg),
55 GNUNET_NO, GNUNET_NO);
56 /* If we reach this line, it did not crash */
57 return 0;
58}
59
60/* end of test_server_mst_interrupt.c */
diff --git a/src/util/test_server_with_client.c b/src/util/test_server_with_client.c
deleted file mode 100644
index 63bfda00c..000000000
--- a/src/util/test_server_with_client.c
+++ /dev/null
@@ -1,198 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2016 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20/**
21 * @file util/test_server_with_client.c
22 * @brief tests for server.c and client.c,
23 * specifically disconnect_notify,
24 * client_get_address and receive_done (resume processing)
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28
29#define PORT 22335
30
31#define MY_TYPE 128
32
33
34static struct GNUNET_SERVER_Handle *server;
35
36static struct GNUNET_MQ_Handle *mq;
37
38static struct GNUNET_CONFIGURATION_Handle *cfg;
39
40static int ok;
41
42
43static void
44send_done (void *cls)
45{
46 struct GNUNET_SERVER_Client *argclient = cls;
47
48 GNUNET_assert (ok == 3);
49 ok++;
50 GNUNET_SERVER_receive_done (argclient, GNUNET_OK);
51}
52
53
54static void
55recv_cb (void *cls,
56 struct GNUNET_SERVER_Client *argclient,
57 const struct GNUNET_MessageHeader *message)
58{
59 void *addr;
60 size_t addrlen;
61 struct sockaddr_in sa;
62 struct sockaddr_in *have;
63
64 GNUNET_assert (GNUNET_OK ==
65 GNUNET_SERVER_client_get_address (argclient,
66 &addr,
67 &addrlen));
68
69 GNUNET_assert (addrlen == sizeof (struct sockaddr_in));
70 have = addr;
71 memset (&sa, 0, sizeof (sa));
72#if HAVE_SOCKADDR_IN_SIN_LEN
73 sa.sin_len = sizeof (sa);
74#endif
75 sa.sin_family = AF_INET;
76 sa.sin_port = have->sin_port;
77 sa.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
78 GNUNET_assert (0 == memcmp (&sa, addr, addrlen));
79 GNUNET_free (addr);
80 switch (ok)
81 {
82 case 2:
83 ok++;
84 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
85 (GNUNET_TIME_UNIT_MILLISECONDS, 50),
86 &send_done,
87 argclient);
88 break;
89 case 4:
90 ok++;
91 GNUNET_MQ_destroy (mq);
92 GNUNET_SERVER_receive_done (argclient,
93 GNUNET_OK);
94 break;
95 default:
96 GNUNET_assert (0);
97 }
98
99}
100
101
102static void
103clean_up (void *cls)
104{
105 GNUNET_SERVER_destroy (server);
106 server = NULL;
107 GNUNET_CONFIGURATION_destroy (cfg);
108 cfg = NULL;
109}
110
111
112/**
113 * Functions with this signature are called whenever a client
114 * is disconnected on the network level.
115 *
116 * @param cls closure
117 * @param client identification of the client
118 */
119static void
120notify_disconnect (void *cls,
121 struct GNUNET_SERVER_Client *client)
122{
123 if (client == NULL)
124 return;
125 GNUNET_assert (ok == 5);
126 ok = 0;
127 GNUNET_SCHEDULER_add_now (&clean_up, NULL);
128}
129
130
131static struct GNUNET_SERVER_MessageHandler handlers[] = {
132 {&recv_cb, NULL, MY_TYPE, sizeof (struct GNUNET_MessageHeader)},
133 {NULL, NULL, 0, 0}
134};
135
136
137static void
138task (void *cls)
139{
140 struct sockaddr_in sa;
141 struct sockaddr *sap[2];
142 socklen_t slens[2];
143 struct GNUNET_MQ_Envelope *env;
144 struct GNUNET_MessageHeader *msg;
145
146 sap[0] = (struct sockaddr *) &sa;
147 slens[0] = sizeof (sa);
148 sap[1] = NULL;
149 slens[1] = 0;
150 memset (&sa, 0, sizeof (sa));
151#if HAVE_SOCKADDR_IN_SIN_LEN
152 sa.sin_len = sizeof (sa);
153#endif
154 sa.sin_family = AF_INET;
155 sa.sin_port = htons (PORT);
156 server =
157 GNUNET_SERVER_create (NULL, NULL, sap, slens,
158 GNUNET_TIME_relative_multiply
159 (GNUNET_TIME_UNIT_MILLISECONDS, 250), GNUNET_NO);
160 GNUNET_assert (server != NULL);
161 handlers[0].callback_cls = cls;
162 GNUNET_SERVER_add_handlers (server, handlers);
163 GNUNET_SERVER_disconnect_notify (server, &notify_disconnect, cls);
164 cfg = GNUNET_CONFIGURATION_create ();
165 GNUNET_CONFIGURATION_set_value_number (cfg, "test", "PORT", PORT);
166 GNUNET_CONFIGURATION_set_value_string (cfg, "test", "HOSTNAME", "localhost");
167 GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME",
168 "localhost");
169 mq = GNUNET_CLIENT_connect (cfg,
170 "test",
171 NULL,
172 NULL,
173 NULL);
174 GNUNET_assert (NULL != mq);
175 ok = 2;
176 env = GNUNET_MQ_msg (msg,
177 MY_TYPE);
178 GNUNET_MQ_send (mq,
179 env);
180 env = GNUNET_MQ_msg (msg,
181 MY_TYPE);
182 GNUNET_MQ_send (mq,
183 env);
184}
185
186
187int
188main (int argc, char *argv[])
189{
190 GNUNET_log_setup ("test_server_with_client",
191 "WARNING",
192 NULL);
193 ok = 1;
194 GNUNET_SCHEDULER_run (&task, NULL);
195 return ok;
196}
197
198/* 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
deleted file mode 100644
index 8fabbe210..000000000
--- a/src/util/test_server_with_client_unix.c
+++ /dev/null
@@ -1,176 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2016 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20/**
21 * @file util/test_server_with_client_unix.c
22 * @brief tests for server.c and client.c,
23 * specifically disconnect_notify,
24 * client_get_address and receive_done (resume processing)
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28
29#define MY_TYPE 128
30
31
32static struct GNUNET_SERVER_Handle *server;
33
34static struct GNUNET_MQ_Handle *mq;
35
36static struct GNUNET_CONFIGURATION_Handle *cfg;
37
38static int ok;
39
40
41static void
42send_done (void *cls)
43{
44 struct GNUNET_SERVER_Client *argclient = cls;
45
46 GNUNET_assert (ok == 3);
47 ok++;
48 GNUNET_SERVER_receive_done (argclient, GNUNET_OK);
49}
50
51
52static void
53recv_cb (void *cls,
54 struct GNUNET_SERVER_Client *argclient,
55 const struct GNUNET_MessageHeader *message)
56{
57 switch (ok)
58 {
59 case 2:
60 ok++;
61 (void) GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
62 (GNUNET_TIME_UNIT_MILLISECONDS, 50),
63 &send_done,
64 argclient);
65 break;
66 case 4:
67 ok++;
68 GNUNET_MQ_destroy (mq);
69 GNUNET_SERVER_receive_done (argclient, GNUNET_OK);
70 break;
71 default:
72 GNUNET_assert (0);
73 }
74
75}
76
77
78static void
79clean_up (void *cls)
80{
81 GNUNET_SERVER_destroy (server);
82 server = NULL;
83 GNUNET_CONFIGURATION_destroy (cfg);
84 cfg = NULL;
85}
86
87
88/**
89 * Functions with this signature are called whenever a client
90 * is disconnected on the network level.
91 *
92 * @param cls closure
93 * @param client identification of the client
94 */
95static void
96notify_disconnect (void *cls,
97 struct GNUNET_SERVER_Client *client)
98{
99 if (client == NULL)
100 return;
101 GNUNET_assert (ok == 5);
102 ok = 0;
103 (void) GNUNET_SCHEDULER_add_now (&clean_up, NULL);
104}
105
106
107static struct GNUNET_SERVER_MessageHandler handlers[] = {
108 {&recv_cb, NULL, MY_TYPE, sizeof (struct GNUNET_MessageHeader)},
109 {NULL, NULL, 0, 0}
110};
111
112
113static void
114task (void *cls)
115{
116 struct sockaddr_un un;
117 const char *unixpath = "/tmp/testsock";
118 struct sockaddr *sap[2];
119 socklen_t slens[2];
120 struct GNUNET_MQ_Envelope *env;
121 struct GNUNET_MessageHeader *msg;
122
123 memset (&un, 0, sizeof (un));
124 un.sun_family = AF_UNIX;
125 strncpy(un.sun_path, unixpath, sizeof (un.sun_path) - 1);
126#if HAVE_SOCKADDR_UN_SUN_LEN
127 un.sun_len = (u_char) sizeof (un);
128#endif
129
130 sap[0] = (struct sockaddr *) &un;
131 slens[0] = sizeof (un);
132 sap[1] = NULL;
133 slens[1] = 0;
134 server =
135 GNUNET_SERVER_create (NULL, NULL, sap, slens,
136 GNUNET_TIME_relative_multiply
137 (GNUNET_TIME_UNIT_MILLISECONDS, 250), GNUNET_NO);
138 GNUNET_assert (server != NULL);
139 handlers[0].callback_cls = cls;
140 GNUNET_SERVER_add_handlers (server, handlers);
141 GNUNET_SERVER_disconnect_notify (server, &notify_disconnect, cls);
142 cfg = GNUNET_CONFIGURATION_create ();
143
144 GNUNET_CONFIGURATION_set_value_string (cfg, "test", "UNIXPATH", unixpath);
145 GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME",
146 "localhost");
147 mq = GNUNET_CLIENT_connect (cfg,
148 "test",
149 NULL,
150 NULL,
151 NULL);
152 GNUNET_assert (NULL != mq);
153 ok = 2;
154 env = GNUNET_MQ_msg (msg,
155 MY_TYPE);
156 GNUNET_MQ_send (mq,
157 env);
158 env = GNUNET_MQ_msg (msg,
159 MY_TYPE);
160 GNUNET_MQ_send (mq,
161 env);
162}
163
164
165int
166main (int argc, char *argv[])
167{
168 GNUNET_log_setup ("test_server_with_client_unix",
169 "WARNING",
170 NULL);
171 ok = 1;
172 GNUNET_SCHEDULER_run (&task, NULL);
173 return ok;
174}
175
176/* end of test_server_with_client_unix.c */
diff --git a/src/util/test_service.c b/src/util/test_service.c
index d2136b42f..1567c97ce 100644
--- a/src/util/test_service.c
+++ b/src/util/test_service.c
@@ -148,7 +148,7 @@ check (const char *sname)
148 sname); 148 sname);
149 global_ret = 1; 149 global_ret = 1;
150 GNUNET_assert (0 == 150 GNUNET_assert (0 ==
151 GNUNET_SERVICE_ruN_ (3, 151 GNUNET_SERVICE_run_ (3,
152 argv, 152 argv,
153 sname, 153 sname,
154 GNUNET_SERVICE_OPTION_NONE, 154 GNUNET_SERVICE_OPTION_NONE,
diff --git a/src/util/util.conf b/src/util/util.conf
index ecc94ead0..ceb5fdcbb 100644
--- a/src/util/util.conf
+++ b/src/util/util.conf
@@ -37,9 +37,8 @@ GNUNET_RUNTIME_DIR = ${TMPDIR:-${TMP:-/tmp}}/gnunet-system-runtime/
37GNUNET_USER_RUNTIME_DIR = ${TMPDIR:-${TMP:-/tmp}}/gnunet-${USERHOME:-${USER:-user}}-runtime/ 37GNUNET_USER_RUNTIME_DIR = ${TMPDIR:-${TMP:-/tmp}}/gnunet-${USERHOME:-${USER:-user}}-runtime/
38 38
39 39
40# Legacy option... 40# Override for GNUNET_HOME used by test cases.
41# GNUNET_TEST_HOME = ~/.gnunet/ 41# GNUNET_TEST_HOME = /tmp/foo/bar
42# GNUNET_TEST_HOME = /var/lib/gnunet/
43 42
44# DEFAULTCONFIG = /etc/gnunet.conf 43# DEFAULTCONFIG = /etc/gnunet.conf
45# If 'DEFAULTCONFIG' is not defined, the current 44# If 'DEFAULTCONFIG' is not defined, the current
diff --git a/src/vpn/Makefile.am b/src/vpn/Makefile.am
index 417d2eb89..5c16fa349 100644
--- a/src/vpn/Makefile.am
+++ b/src/vpn/Makefile.am
@@ -59,7 +59,7 @@ gnunet_service_vpn_LDADD = \
59 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 59 $(top_builddir)/src/statistics/libgnunetstatistics.la \
60 $(top_builddir)/src/tun/libgnunettun.la \ 60 $(top_builddir)/src/tun/libgnunettun.la \
61 $(top_builddir)/src/util/libgnunetutil.la \ 61 $(top_builddir)/src/util/libgnunetutil.la \
62 $(top_builddir)/src/cadet/libgnunetcadetnew.la \ 62 $(top_builddir)/src/cadet/libgnunetcadet.la \
63 $(top_builddir)/src/regex/libgnunetregex.la \ 63 $(top_builddir)/src/regex/libgnunetregex.la \
64 $(GN_LIBINTL) 64 $(GN_LIBINTL)
65gnunet_service_vpn_CFLAGS = \ 65gnunet_service_vpn_CFLAGS = \
diff --git a/src/vpn/gnunet-helper-vpn-windows.c b/src/vpn/gnunet-helper-vpn-windows.c
index a9596752a..e74a0aa2f 100644
--- a/src/vpn/gnunet-helper-vpn-windows.c
+++ b/src/vpn/gnunet-helper-vpn-windows.c
@@ -77,7 +77,7 @@
77static boolean privilege_testing = FALSE; 77static boolean privilege_testing = FALSE;
78 78
79/** 79/**
80 * Maximum size of a GNUnet message (GNUNET_SERVER_MAX_MESSAGE_SIZE) 80 * Maximum size of a GNUnet message (GNUNET_MAX_MESSAGE_SIZE)
81 */ 81 */
82#define MAX_SIZE 65536 82#define MAX_SIZE 65536
83 83
diff --git a/src/vpn/gnunet-helper-vpn.c b/src/vpn/gnunet-helper-vpn.c
index 02889d65b..4ed4e079e 100644
--- a/src/vpn/gnunet-helper-vpn.c
+++ b/src/vpn/gnunet-helper-vpn.c
@@ -53,7 +53,7 @@
53#define DEBUG GNUNET_NO 53#define DEBUG GNUNET_NO
54 54
55/** 55/**
56 * Maximum size of a GNUnet message (GNUNET_SERVER_MAX_MESSAGE_SIZE) 56 * Maximum size of a GNUnet message (GNUNET_MAX_MESSAGE_SIZE)
57 */ 57 */
58#define MAX_SIZE 65536 58#define MAX_SIZE 65536
59 59
diff --git a/src/vpn/gnunet-service-vpn.c b/src/vpn/gnunet-service-vpn.c
index aa0ea51a3..d9daaa7e2 100644
--- a/src/vpn/gnunet-service-vpn.c
+++ b/src/vpn/gnunet-service-vpn.c
@@ -1384,7 +1384,7 @@ create_channel (struct ChannelState *ts,
1384 GNUNET_MQ_handler_end() 1384 GNUNET_MQ_handler_end()
1385 }; 1385 };
1386 1386
1387 return GNUNET_CADET_channel_creatE (cadet_handle, 1387 return GNUNET_CADET_channel_create (cadet_handle,
1388 ts, 1388 ts,
1389 target, 1389 target,
1390 port, 1390 port,
@@ -1839,7 +1839,7 @@ route_packet (struct DestinationEntry *destination,
1839 1839
1840 mlen = sizeof (struct GNUNET_EXIT_UdpServiceMessage) + 1840 mlen = sizeof (struct GNUNET_EXIT_UdpServiceMessage) +
1841 payload_length - sizeof (struct GNUNET_TUN_UdpHeader); 1841 payload_length - sizeof (struct GNUNET_TUN_UdpHeader);
1842 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) 1842 if (mlen >= GNUNET_MAX_MESSAGE_SIZE)
1843 { 1843 {
1844 GNUNET_break (0); 1844 GNUNET_break (0);
1845 return; 1845 return;
@@ -1864,7 +1864,7 @@ route_packet (struct DestinationEntry *destination,
1864 1864
1865 mlen = sizeof (struct GNUNET_EXIT_UdpInternetMessage) + 1865 mlen = sizeof (struct GNUNET_EXIT_UdpInternetMessage) +
1866 alen + payload_length - sizeof (struct GNUNET_TUN_UdpHeader); 1866 alen + payload_length - sizeof (struct GNUNET_TUN_UdpHeader);
1867 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) 1867 if (mlen >= GNUNET_MAX_MESSAGE_SIZE)
1868 { 1868 {
1869 GNUNET_break (0); 1869 GNUNET_break (0);
1870 return; 1870 return;
@@ -1904,7 +1904,7 @@ route_packet (struct DestinationEntry *destination,
1904 1904
1905 mlen = sizeof (struct GNUNET_EXIT_TcpServiceStartMessage) + 1905 mlen = sizeof (struct GNUNET_EXIT_TcpServiceStartMessage) +
1906 payload_length - sizeof (struct GNUNET_TUN_TcpHeader); 1906 payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1907 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) 1907 if (mlen >= GNUNET_MAX_MESSAGE_SIZE)
1908 { 1908 {
1909 GNUNET_break (0); 1909 GNUNET_break (0);
1910 return; 1910 return;
@@ -1927,7 +1927,7 @@ route_packet (struct DestinationEntry *destination,
1927 1927
1928 mlen = sizeof (struct GNUNET_EXIT_TcpInternetStartMessage) + 1928 mlen = sizeof (struct GNUNET_EXIT_TcpInternetStartMessage) +
1929 alen + payload_length - sizeof (struct GNUNET_TUN_TcpHeader); 1929 alen + payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1930 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) 1930 if (mlen >= GNUNET_MAX_MESSAGE_SIZE)
1931 { 1931 {
1932 GNUNET_break (0); 1932 GNUNET_break (0);
1933 return; 1933 return;
@@ -1963,7 +1963,7 @@ route_packet (struct DestinationEntry *destination,
1963 1963
1964 mlen = sizeof (struct GNUNET_EXIT_TcpDataMessage) + 1964 mlen = sizeof (struct GNUNET_EXIT_TcpDataMessage) +
1965 payload_length - sizeof (struct GNUNET_TUN_TcpHeader); 1965 payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1966 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) 1966 if (mlen >= GNUNET_MAX_MESSAGE_SIZE)
1967 { 1967 {
1968 GNUNET_break (0); 1968 GNUNET_break (0);
1969 return; 1969 return;
@@ -2038,7 +2038,7 @@ route_packet (struct DestinationEntry *destination,
2038 /* update length calculations, as payload_length may have changed */ 2038 /* update length calculations, as payload_length may have changed */
2039 mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) + 2039 mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) +
2040 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader); 2040 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
2041 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) 2041 if (mlen >= GNUNET_MAX_MESSAGE_SIZE)
2042 { 2042 {
2043 GNUNET_break (0); 2043 GNUNET_break (0);
2044 return; 2044 return;
@@ -2061,6 +2061,7 @@ route_packet (struct DestinationEntry *destination,
2061 void *payload; 2061 void *payload;
2062 uint8_t new_type; 2062 uint8_t new_type;
2063 2063
2064 new_type = icmp->type;
2064 /* Perform ICMP protocol-translation (depending on destination AF and source AF) 2065 /* Perform ICMP protocol-translation (depending on destination AF and source AF)
2065 and throw away ICMP payload depending on ICMP message type */ 2066 and throw away ICMP payload depending on ICMP message type */
2066 switch (af) 2067 switch (af)
@@ -2111,8 +2112,8 @@ route_packet (struct DestinationEntry *destination,
2111 switch (icmp->type) 2112 switch (icmp->type)
2112 { 2113 {
2113 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE: 2114 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
2114 if (destination->details.exit_destination.af == AF_INET6) 2115 if (destination->details.exit_destination.af == AF_INET)
2115 new_type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE; 2116 new_type = GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE;
2116 /* throw away IP-payload, exit will have to make it up anyway */ 2117 /* throw away IP-payload, exit will have to make it up anyway */
2117 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader); 2118 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
2118 break; 2119 break;
@@ -2167,7 +2168,7 @@ route_packet (struct DestinationEntry *destination,
2167 /* update length calculations, as payload_length may have changed */ 2168 /* update length calculations, as payload_length may have changed */
2168 mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) + 2169 mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) +
2169 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader); 2170 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
2170 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) 2171 if (mlen >= GNUNET_MAX_MESSAGE_SIZE)
2171 { 2172 {
2172 GNUNET_break (0); 2173 GNUNET_break (0);
2173 return; 2174 return;
@@ -2216,12 +2217,10 @@ route_packet (struct DestinationEntry *destination,
2216 * and forward the packet. 2217 * and forward the packet.
2217 * 2218 *
2218 * @param cls closure, NULL 2219 * @param cls closure, NULL
2219 * @param client NULL
2220 * @param message message we got from the client (VPN channel interface) 2220 * @param message message we got from the client (VPN channel interface)
2221 */ 2221 */
2222static int 2222static int
2223message_token (void *cls, 2223message_token (void *cls,
2224 void *client,
2225 const struct GNUNET_MessageHeader *message) 2224 const struct GNUNET_MessageHeader *message)
2226{ 2225{
2227 const struct GNUNET_TUN_Layer2PacketHeader *tun; 2226 const struct GNUNET_TUN_Layer2PacketHeader *tun;
@@ -3067,7 +3066,7 @@ run (void *cls,
3067 } 3066 }
3068 vpn_argv[6] = NULL; 3067 vpn_argv[6] = NULL;
3069 3068
3070 cadet_handle = GNUNET_CADET_connecT (cfg_); 3069 cadet_handle = GNUNET_CADET_connect (cfg_);
3071 // FIXME never opens ports??? 3070 // FIXME never opens ports???
3072 helper_handle = GNUNET_HELPER_start (GNUNET_NO, 3071 helper_handle = GNUNET_HELPER_start (GNUNET_NO,
3073 "gnunet-helper-vpn", vpn_argv, 3072 "gnunet-helper-vpn", vpn_argv,
diff --git a/src/vpn/gnunet-vpn.c b/src/vpn/gnunet-vpn.c
index 2e7daf7f7..0adbd5c96 100644
--- a/src/vpn/gnunet-vpn.c
+++ b/src/vpn/gnunet-vpn.c
@@ -78,7 +78,7 @@ static int udp;
78/** 78/**
79 * Selected level of verbosity. 79 * Selected level of verbosity.
80 */ 80 */
81static int verbosity; 81static unsigned int verbosity;
82 82
83/** 83/**
84 * Global return value. 84 * Global return value.
@@ -286,33 +286,53 @@ run (void *cls,
286int 286int
287main (int argc, char *const *argv) 287main (int argc, char *const *argv)
288{ 288{
289 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 289 struct GNUNET_GETOPT_CommandLineOption options[] = {
290 {'4', "ipv4", NULL, 290 GNUNET_GETOPT_OPTION_SET_ONE ('4',
291 gettext_noop ("request that result should be an IPv4 address"), 291 "ipv4",
292 0, &GNUNET_GETOPT_set_one, &ipv4}, 292 gettext_noop ("request that result should be an IPv4 address"),
293 {'6', "ipv6", NULL, 293 &ipv4),
294 gettext_noop ("request that result should be an IPv6 address"), 294
295 0, &GNUNET_GETOPT_set_one, &ipv6}, 295 GNUNET_GETOPT_OPTION_SET_ONE ('6',
296 {'d', "duration", "TIME", 296 "ipv6",
297 gettext_noop ("how long should the mapping be valid for new tunnels?"), 297 gettext_noop ("request that result should be an IPv6 address"),
298 1, &GNUNET_GETOPT_set_relative_time, &duration}, 298 &ipv6),
299 {'i', "ip", "IP", 299
300 gettext_noop ("destination IP for the tunnel"), 300 GNUNET_GETOPT_OPTION_SET_RELATIVE_TIME ('d',
301 1, &GNUNET_GETOPT_set_string, &target_ip}, 301 "duration",
302 {'p', "peer", "PEERID", 302 "TIME",
303 gettext_noop ("peer offering the service we would like to access"), 303 gettext_noop ("how long should the mapping be valid for new tunnels?"),
304 1, &GNUNET_GETOPT_set_string, &peer_id}, 304 &duration),
305 {'s', "service", "NAME", 305
306 gettext_noop ("name of the service we would like to access"), 306 GNUNET_GETOPT_OPTION_STRING ('i',
307 1, &GNUNET_GETOPT_set_string, &service_name}, 307 "ip",
308 {'t', "tcp", NULL, 308 "IP",
309 gettext_noop ("service is offered via TCP"), 309 gettext_noop ("destination IP for the tunnel"),
310 0, &GNUNET_GETOPT_set_one, &tcp}, 310 &target_ip),
311 {'u', "udp", NULL, 311
312 gettext_noop ("service is offered via UDP"), 312 GNUNET_GETOPT_OPTION_STRING ('p',
313 0, &GNUNET_GETOPT_set_one, &udp}, 313 "peer",
314 "PEERID",
315 gettext_noop ("peer offering the service we would like to access"),
316 &peer_id),
317
318 GNUNET_GETOPT_OPTION_STRING ('s',
319 "service",
320 "NAME",
321 gettext_noop ("name of the service we would like to access"),
322 &service_name),
323
324 GNUNET_GETOPT_OPTION_SET_ONE ('t',
325 "tcp",
326 gettext_noop ("service is offered via TCP"),
327 &tcp),
328
329 GNUNET_GETOPT_OPTION_SET_ONE ('u',
330 "udp",
331 gettext_noop ("service is offered via UDP"),
332 &udp),
314 333
315 GNUNET_GETOPT_OPTION_VERBOSE (&verbosity), 334 GNUNET_GETOPT_OPTION_VERBOSE (&verbosity),
335
316 GNUNET_GETOPT_OPTION_END 336 GNUNET_GETOPT_OPTION_END
317 }; 337 };
318 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) 338 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))