aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSchanzenbach, Martin <mschanzenbach@posteo.de>2017-03-29 14:26:33 +0200
committerSchanzenbach, Martin <mschanzenbach@posteo.de>2017-03-29 14:26:33 +0200
commitab281595eeb270120f89ec954a572f4fcf78fc53 (patch)
tree335a2caf503596adc400c5ebb9fb742f097bc5a3 /src
parent59d393a1124cfd1aaffdf994bf6f8a9baaac8361 (diff)
parent2b87f173e360aaf4a3bac3fbc6e5b4dc44cf58cd (diff)
downloadgnunet-ab281595eeb270120f89ec954a572f4fcf78fc53.tar.gz
gnunet-ab281595eeb270120f89ec954a572f4fcf78fc53.zip
- merge with master
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am14
-rw-r--r--src/arm/Makefile.am2
-rw-r--r--src/arm/arm_api.c2
-rw-r--r--src/arm/gnunet-arm.c176
-rw-r--r--src/arm/gnunet-service-arm.c5
-rw-r--r--src/ats-tests/Makefile.am6
-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-tests/template_perf_ats.conf4
-rw-r--r--src/ats-tool/gnunet-ats.c84
-rw-r--r--src/ats/.gitignore2
-rw-r--r--src/ats/Makefile.am14
-rw-r--r--src/ats/ats_api_performance.c2
-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/Makefile.am62
-rw-r--r--src/auction/gnunet-auction-create.c67
-rw-r--r--src/block/Makefile.am23
-rw-r--r--src/block/bg_bf.c268
-rw-r--r--src/block/block.c238
-rw-r--r--src/block/plugin_block_template.c111
-rw-r--r--src/block/plugin_block_test.c99
-rw-r--r--src/cadet/.gitignore3
-rw-r--r--src/cadet/Makefile.am116
-rw-r--r--src/cadet/TODO36
-rw-r--r--src/cadet/cadet.conf.in32
-rw-r--r--src/cadet/cadet.h2
-rw-r--r--src/cadet/cadet_api.c1794
-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.h193
-rw-r--r--src/cadet/cadet_test_lib.c133
-rw-r--r--src/cadet/cadet_test_lib.h40
-rw-r--r--src/cadet/desirability_table.c35
-rw-r--r--src/cadet/gnunet-cadet-profiler.c4
-rw-r--r--src/cadet/gnunet-cadet.c630
-rw-r--r--src/cadet/gnunet-service-cadet-new.c1428
-rw-r--r--src/cadet/gnunet-service-cadet-new_channel.c1613
-rw-r--r--src/cadet/gnunet-service-cadet-new_channel.h249
-rw-r--r--src/cadet/gnunet-service-cadet-new_connection.c709
-rw-r--r--src/cadet/gnunet-service-cadet-new_connection.h207
-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.c1282
-rw-r--r--src/cadet/gnunet-service-cadet-new_peer.h380
-rw-r--r--src/cadet/gnunet-service-cadet.c1488
-rw-r--r--src/cadet/gnunet-service-cadet.h (renamed from src/cadet/gnunet-service-cadet-new.h)53
-rw-r--r--src/cadet/gnunet-service-cadet_channel.c3515
-rw-r--r--src/cadet/gnunet-service-cadet_channel.h393
-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)606
-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)119
-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.h516
-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)1712
-rw-r--r--src/cadet/gnunet-service-cadet_tunnels.h (renamed from src/cadet/gnunet-service-cadet-new_tunnels.h)85
-rw-r--r--src/cadet/test_cadet.c819
-rw-r--r--src/cadet/test_cadet_local.c351
-rw-r--r--src/cadet/test_cadet_local_mq.c332
-rw-r--r--src/cadet/test_cadet_single.c354
-rw-r--r--src/consensus/.gitignore2
-rw-r--r--src/consensus/Makefile.am27
-rw-r--r--src/consensus/consensus_protocol.h57
-rw-r--r--src/consensus/gnunet-consensus-profiler.c120
-rw-r--r--src/consensus/gnunet-service-consensus.c775
-rw-r--r--src/consensus/plugin_block_consensus.c137
-rw-r--r--src/consensus/test_consensus.conf19
-rw-r--r--src/conversation/.gitignore3
-rw-r--r--src/conversation/Makefile.am4
-rw-r--r--src/conversation/conversation_api_call.c1
-rw-r--r--src/conversation/gnunet-conversation.c21
-rw-r--r--src/conversation/gnunet-helper-audio-playback-gst.c69
-rw-r--r--src/conversation/gnunet-helper-audio-playback.c15
-rw-r--r--src/conversation/gnunet-helper-audio-record-gst.c9
-rw-r--r--src/conversation/gnunet-service-conversation.c505
-rw-r--r--src/conversation/gnunet_gst.c54
-rw-r--r--src/conversation/gnunet_gst_def.h13
-rw-r--r--src/conversation/gnunet_gst_test.c7
-rw-r--r--src/conversation/microphone.c2
-rw-r--r--src/conversation/test_conversation.conf1
-rw-r--r--src/conversation/test_conversation_api_twocalls.c3
-rw-r--r--src/core/Makefile.am2
-rw-r--r--src/core/core_api.c29
-rw-r--r--src/core/gnunet-core.c9
-rw-r--r--src/core/gnunet-service-core.c69
-rw-r--r--src/core/gnunet-service-core_kx.c171
-rw-r--r--src/core/gnunet-service-core_sessions.c96
-rw-r--r--src/core/gnunet-service-core_typemap.c21
-rw-r--r--src/datacache/Makefile.am3
-rw-r--r--src/datacache/plugin_datacache_sqlite.c550
-rw-r--r--src/datastore/Makefile.am3
-rw-r--r--src/datastore/datastore.h53
-rw-r--r--src/datastore/datastore_api.c179
-rw-r--r--src/datastore/gnunet-datastore.c50
-rw-r--r--src/datastore/gnunet-service-datastore.c125
-rw-r--r--src/datastore/perf_datastore_api.c2
-rw-r--r--src/datastore/perf_plugin_datastore.c33
-rw-r--r--src/datastore/plugin_datastore_heap.c301
-rw-r--r--src/datastore/plugin_datastore_mysql.c311
-rw-r--r--src/datastore/plugin_datastore_postgres.c373
-rw-r--r--src/datastore/plugin_datastore_sqlite.c892
-rw-r--r--src/datastore/plugin_datastore_template.c47
-rw-r--r--src/datastore/test_datastore_api.c95
-rw-r--r--src/datastore/test_datastore_api_management.c63
-rw-r--r--src/datastore/test_plugin_datastore.c14
-rw-r--r--src/dht/.gitignore2
-rw-r--r--src/dht/Makefile.am49
-rw-r--r--src/dht/dht_api.c37
-rw-r--r--src/dht/gnunet-dht-get.c99
-rw-r--r--src/dht/gnunet-dht-monitor.c50
-rw-r--r--src/dht/gnunet-dht-put.c123
-rw-r--r--src/dht/gnunet-service-dht_clients.c35
-rw-r--r--src/dht/gnunet-service-dht_datacache.c46
-rw-r--r--src/dht/gnunet-service-dht_datacache.h6
-rw-r--r--src/dht/gnunet-service-dht_neighbours.c519
-rw-r--r--src/dht/gnunet-service-dht_neighbours.h14
-rw-r--r--src/dht/gnunet-service-dht_routing.c83
-rw-r--r--src/dht/gnunet-service-dht_routing.h19
-rw-r--r--src/dht/gnunet-service-wdht.c103
-rw-r--r--src/dht/gnunet-service-wdht.h50
-rw-r--r--src/dht/gnunet-service-wdht_clients.c1428
-rw-r--r--src/dht/gnunet-service-wdht_neighbours.c1768
-rw-r--r--src/dht/gnunet-service-xdht.c121
-rw-r--r--src/dht/gnunet-service-xdht.h50
-rw-r--r--src/dht/gnunet-service-xdht_hello.c137
-rw-r--r--src/dht/gnunet-service-xdht_hello.h55
-rw-r--r--src/dht/gnunet-service-xdht_neighbours.c6265
-rw-r--r--src/dht/gnunet-service-xdht_neighbours.h47
-rw-r--r--src/dht/gnunet-service-xdht_routing.c368
-rw-r--r--src/dht/gnunet-service-xdht_routing.h141
-rw-r--r--src/dht/gnunet_dht_profiler.c73
-rw-r--r--src/dht/plugin_block_dht.c95
-rw-r--r--src/dht/test_dht_api.c180
-rw-r--r--src/dht/test_dht_monitor.c42
-rw-r--r--src/dht/test_dht_tools.py.in16
-rw-r--r--src/dns/Makefile.am3
-rw-r--r--src/dns/dns_api.c2
-rw-r--r--src/dns/gnunet-dns-monitor.c23
-rw-r--r--src/dns/gnunet-dns-redirector.c24
-rw-r--r--src/dns/gnunet-helper-dns.c4
-rw-r--r--src/dns/gnunet-service-dns.c7
-rw-r--r--src/dns/plugin_block_dns.c82
-rw-r--r--src/dv/Makefile.am2
-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.am6
-rw-r--r--src/exit/gnunet-daemon-exit.c3013
-rw-r--r--src/exit/gnunet-helper-exit-windows.c2
-rw-r--r--src/exit/gnunet-helper-exit.c2
-rw-r--r--src/fragmentation/Makefile.am2
-rw-r--r--src/fs/.gitignore32
-rw-r--r--src/fs/Makefile.am3
-rw-r--r--src/fs/fs.conf.in2
-rw-r--r--src/fs/fs_api.c28
-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.c156
-rw-r--r--src/fs/fs_getopt.c79
-rw-r--r--src/fs/fs_publish.c4
-rw-r--r--src/fs/fs_search.c65
-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.c15
-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.c5
-rw-r--r--src/fs/gnunet-service-fs_cadet.h49
-rw-r--r--src/fs/gnunet-service-fs_cadet_client.c584
-rw-r--r--src/fs/gnunet-service-fs_cadet_server.c328
-rw-r--r--src/fs/gnunet-service-fs_cp.c4
-rw-r--r--src/fs/gnunet-service-fs_indexing.c5
-rw-r--r--src/fs/gnunet-service-fs_indexing.h11
-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.c561
-rw-r--r--src/fs/gnunet-service-fs_push.c6
-rw-r--r--src/fs/gnunet-service-fs_put.c46
-rw-r--r--src/fs/gnunet-unindex.c10
-rw-r--r--src/fs/plugin_block_fs.c105
-rw-r--r--src/fs/test_plugin_block_fs.c6
-rw-r--r--src/gns/Makefile.am23
-rw-r--r--src/gns/gns.h53
-rw-r--r--src/gns/gns_api.c196
-rw-r--r--src/gns/gnunet-bcd.c12
-rw-r--r--src/gns/gnunet-dns2gns.c67
-rw-r--r--src/gns/gnunet-gns-helper-service-w32.c517
-rw-r--r--src/gns/gnunet-gns-import.c71
-rw-r--r--src/gns/gnunet-gns-proxy.c129
-rw-r--r--src/gns/gnunet-gns.c218
-rw-r--r--src/gns/gnunet-service-gns.c199
-rw-r--r--src/gns/gnunet-service-gns_interceptor.c1
-rw-r--r--src/gns/gnunet-service-gns_resolver.c36
-rw-r--r--src/gns/gnunet-service-gns_resolver.h11
-rw-r--r--src/gns/gnunet-service-gns_reverser.c601
-rw-r--r--src/gns/gnunet-service-gns_reverser.h91
-rw-r--r--src/gns/gnunet-service-gns_shorten.c466
-rw-r--r--src/gns/gnunet-service-gns_shorten.h70
-rw-r--r--src/gns/plugin_block_gns.c97
-rw-r--r--src/gns/plugin_gnsrecord_gns.c18
-rw-r--r--src/gns/plugin_rest_gns.c55
-rwxr-xr-xsrc/gns/test_gns_nick_shorten.sh124
-rwxr-xr-xsrc/gns/test_gns_reverse_lookup.sh50
-rw-r--r--src/gns/w32nsp-resolve.c3
-rw-r--r--src/gnsrecord/Makefile.am2
-rw-r--r--src/hello/Makefile.am2
-rw-r--r--src/hello/hello.c2
-rw-r--r--src/hostlist/Makefile.am2
-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/gnunet-service-identity-provider.c8
-rw-r--r--src/identity-provider/identity_provider_api.c2
-rw-r--r--src/identity-provider/plugin_rest_identity_provider.c3
-rw-r--r--src/identity/Makefile.am2
-rw-r--r--src/identity/gnunet-identity.c116
-rw-r--r--src/identity/identity_api.c14
-rw-r--r--src/include/Makefile.am3
-rw-r--r--src/include/gnunet_arm_service.h18
-rw-r--r--src/include/gnunet_bandwidth_lib.h14
-rw-r--r--src/include/gnunet_block_group_lib.h114
-rw-r--r--src/include/gnunet_block_lib.h117
-rw-r--r--src/include/gnunet_block_plugin.h139
-rw-r--r--src/include/gnunet_cadet_service.h544
-rw-r--r--src/include/gnunet_common.h2
-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_container_lib.h53
-rw-r--r--src/include/gnunet_core_service.h53
-rw-r--r--src/include/gnunet_credential_service.h2
-rw-r--r--src/include/gnunet_crypto_lib.h11
-rw-r--r--src/include/gnunet_datastore_plugin.h89
-rw-r--r--src/include/gnunet_datastore_service.h49
-rw-r--r--src/include/gnunet_fs_service.h47
-rw-r--r--src/include/gnunet_getopt_lib.h349
-rw-r--r--src/include/gnunet_gns_service.h44
-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.h90
-rw-r--r--src/include/gnunet_multicast_service.h4
-rw-r--r--src/include/gnunet_mysql_lib.h14
-rw-r--r--src/include/gnunet_network_lib.h12
-rw-r--r--src/include/gnunet_os_lib.h3
-rw-r--r--src/include/gnunet_peerstore_service.h4
-rw-r--r--src/include/gnunet_plugin_lib.h2
-rw-r--r--src/include/gnunet_pq_lib.h20
-rw-r--r--src/include/gnunet_protocols.h43
-rw-r--r--src/include/gnunet_scheduler_lib.h246
-rw-r--r--src/include/gnunet_server_lib.h887
-rw-r--r--src/include/gnunet_service_lib.h107
-rw-r--r--src/include/gnunet_set_service.h61
-rw-r--r--src/include/gnunet_sq_lib.h451
-rw-r--r--src/include/gnunet_strings_lib.h14
-rw-r--r--src/include/gnunet_util_lib.h17
-rw-r--r--src/include/platform.h1
-rw-r--r--src/integration-tests/.gitignore8
-rw-r--r--src/integration-tests/Makefile.am2
-rw-r--r--src/integration-tests/confs/test_defaults.conf4
-rw-r--r--src/json/json.c73
-rw-r--r--src/multicast/.gitignore3
-rw-r--r--src/multicast/Makefile.am15
-rw-r--r--src/multicast/gnunet-service-multicast.c931
-rw-r--r--src/multicast/test_multicast.c9
-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.c430
-rw-r--r--src/namecache/.gitignore1
-rw-r--r--src/namecache/Makefile.am4
-rw-r--r--src/namecache/gnunet-namecache.c20
-rw-r--r--src/namecache/plugin_namecache_sqlite.c215
-rw-r--r--src/namestore/.gitignore31
-rw-r--r--src/namestore/Makefile.am114
-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/namestore/plugin_rest_namestore.c11
-rw-r--r--src/namestore/test_namestore_api_remove.c18
-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.c216
-rw-r--r--src/nat-auto/nat_auto_api.c8
-rw-r--r--src/nat-auto/nat_auto_api_test.c20
-rw-r--r--src/nat/Makefile.am2
-rw-r--r--src/nat/gnunet-helper-nat-client-windows.c2
-rw-r--r--src/nat/gnunet-helper-nat-server-windows.c2
-rw-r--r--src/nat/gnunet-nat.c139
-rw-r--r--src/nat/gnunet-service-nat.c70
-rw-r--r--src/nat/gnunet-service-nat_externalip.c18
-rw-r--r--src/nat/gnunet-service-nat_helper.c29
-rw-r--r--src/nat/gnunet-service-nat_mini.c16
-rw-r--r--src/nat/nat_api.c30
-rw-r--r--src/nat/nat_stun.h15
-rw-r--r--src/nse/Makefile.am2
-rw-r--r--src/nse/gnunet-nse-profiler.c65
-rw-r--r--src/peerinfo-tool/Makefile.am2
-rw-r--r--src/peerinfo-tool/gnunet-peerinfo.c67
-rw-r--r--src/peerinfo/.gitignore1
-rw-r--r--src/peerinfo/Makefile.am2
-rw-r--r--src/peerinfo/gnunet-service-peerinfo.c8
-rw-r--r--src/peerinfo/perf_peerinfo_api.c93
-rw-r--r--src/peerstore/.gitignore1
-rw-r--r--src/peerstore/Makefile.am6
-rw-r--r--src/peerstore/gnunet-service-peerstore.c32
-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/postgres/postgres.c28
-rw-r--r--src/pq/pq.c7
-rw-r--r--src/pq/pq_result_helper.c50
-rw-r--r--src/pq/test_pq.c6
-rw-r--r--src/psyc/.gitignore1
-rw-r--r--src/psyc/Makefile.am2
-rw-r--r--src/psyc/gnunet-service-psyc.c3
-rw-r--r--src/psyc/psyc_api.c4
-rw-r--r--src/psycstore/.gitignore4
-rw-r--r--src/psycstore/Makefile.am7
-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/psycutil/Makefile.am2
-rw-r--r--src/pt/.gitignore5
-rw-r--r--src/pt/Makefile.am2
-rw-r--r--src/pt/gnunet-daemon-pt.c461
-rw-r--r--src/pt/test_gns_vpn.c251
-rw-r--r--src/pt/test_gns_vpn.conf4
-rw-r--r--src/regex/Makefile.am3
-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/plugin_block_regex.c146
-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/.gitignore2
-rw-r--r--src/revocation/Makefile.am19
-rw-r--r--src/revocation/gnunet-revocation.c38
-rw-r--r--src/revocation/gnunet-service-revocation.c20
-rw-r--r--src/revocation/plugin_block_revocation.c257
-rw-r--r--src/revocation/revocation_api.c4
-rw-r--r--src/revocation/test_local_revocation.py.in4
-rw-r--r--src/revocation/test_revocation.c20
-rw-r--r--src/rps/Makefile.am36
-rw-r--r--src/rps/gnunet-rps.c57
-rw-r--r--src/rps/gnunet-service-rps.c226
-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/.gitignore1
-rw-r--r--src/scalarproduct/Makefile.am2
-rw-r--r--src/scalarproduct/gnunet-scalarproduct.c36
-rw-r--r--src/scalarproduct/gnunet-service-scalarproduct-ecc_alice.c131
-rw-r--r--src/scalarproduct/gnunet-service-scalarproduct-ecc_bob.c458
-rw-r--r--src/scalarproduct/gnunet-service-scalarproduct_alice.c214
-rw-r--r--src/scalarproduct/gnunet-service-scalarproduct_bob.c422
-rw-r--r--src/scalarproduct/scalarproduct_api.c8
-rw-r--r--src/scalarproduct/test_scalarproduct.conf3
-rw-r--r--src/secretsharing/.gitignore1
-rw-r--r--src/secretsharing/Makefile.am11
-rw-r--r--src/secretsharing/gnunet-secretsharing-profiler.c59
-rw-r--r--src/secretsharing/gnunet-service-secretsharing.c538
-rw-r--r--src/set/.gitignore4
-rw-r--r--src/set/Makefile.am20
-rw-r--r--src/set/gnunet-service-set.c1936
-rw-r--r--src/set/gnunet-service-set.h346
-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_protocol.h14
-rw-r--r--src/set/gnunet-service-set_union.c1276
-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.c163
-rw-r--r--src/set/plugin_block_set_test.c123
-rw-r--r--src/set/set.conf.in2
-rw-r--r--src/set/set.h53
-rw-r--r--src/set/set_api.c126
-rw-r--r--src/set/test_set.conf1
-rw-r--r--src/set/test_set_api.c81
-rw-r--r--src/set/test_set_intersection_result_full.c97
-rw-r--r--src/set/test_set_union_copy.c70
-rw-r--r--src/set/test_set_union_result_symmetric.c4
-rw-r--r--src/social/.gitignore1
-rw-r--r--src/social/Makefile.am2
-rw-r--r--src/social/gnunet-service-social.c8
-rw-r--r--src/social/gnunet-social.c316
-rw-r--r--src/social/social_api.c10
-rw-r--r--src/sq/.gitignore1
-rw-r--r--src/sq/Makefile.am40
-rw-r--r--src/sq/sq.c140
-rw-r--r--src/sq/sq_query_helper.c493
-rw-r--r--src/sq/sq_result_helper.c782
-rw-r--r--src/sq/test_sq.c285
-rw-r--r--src/statistics/Makefile.am2
-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/template/Makefile.am2
-rw-r--r--src/testbed-logger/Makefile.am2
-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.am6
-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_test.c18
-rw-r--r--src/testbed/testbed_api_topology.c8
-rw-r--r--src/testing/Makefile.am2
-rw-r--r--src/testing/gnunet-testing.c40
-rw-r--r--src/testing/list-keys.c15
-rw-r--r--src/testing/testing.c5
-rw-r--r--src/topology/Makefile.am2
-rw-r--r--src/topology/friends.c18
-rw-r--r--src/topology/gnunet-daemon-topology.c2
-rw-r--r--src/transport/Makefile.am6
-rw-r--r--src/transport/gnunet-helper-transport-wlan-dummy.c30
-rw-r--r--src/transport/gnunet-service-transport.c41
-rw-r--r--src/transport/gnunet-service-transport_neighbours.c38
-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.c56
-rw-r--r--src/transport/gnunet-transport.c122
-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.c679
-rw-r--r--src/transport/plugin_transport_udp.c58
-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_unix.c6
-rw-r--r--src/transport/plugin_transport_wlan.c31
-rw-r--r--src/transport/tcp_connection_legacy.c (renamed from src/util/connection.c)41
-rw-r--r--src/transport/tcp_server_legacy.c (renamed from src/util/server.c)24
-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_address_switch.c11
-rw-r--r--src/transport/test_transport_api_reliability.c14
-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.conf.in17
-rw-r--r--src/transport/transport_api_address_to_string.c6
-rw-r--r--src/transport/transport_api_core.c5
-rw-r--r--src/tun/Makefile.am2
-rw-r--r--src/util/.gitignore4
-rw-r--r--src/util/Makefile.am107
-rw-r--r--src/util/bandwidth.c20
-rw-r--r--src/util/bio.c2
-rw-r--r--src/util/client.c28
-rw-r--r--src/util/common_allocation.c4
-rw-r--r--src/util/common_endian.c2
-rw-r--r--src/util/configuration_loader.c2
-rw-r--r--src/util/container_bloomfilter.c6
-rw-r--r--src/util/container_heap.c2
-rw-r--r--src/util/container_meta_data.c2
-rw-r--r--src/util/container_multihashmap.c2
-rw-r--r--src/util/container_multihashmap32.c2
-rw-r--r--src/util/container_multipeermap.c2
-rw-r--r--src/util/container_multishortmap.c2
-rw-r--r--src/util/crypto_crc.c2
-rw-r--r--src/util/crypto_ecc.c41
-rw-r--r--src/util/crypto_ecc_setup.c6
-rw-r--r--src/util/crypto_hash.c4
-rw-r--r--src/util/crypto_hash_file.c4
-rw-r--r--src/util/crypto_hkdf.c2
-rw-r--r--src/util/crypto_kdf.c2
-rw-r--r--src/util/crypto_mpi.c2
-rw-r--r--src/util/crypto_random.c4
-rw-r--r--src/util/crypto_rsa.c38
-rw-r--r--src/util/crypto_symmetric.c2
-rw-r--r--src/util/disk.c29
-rw-r--r--src/util/getopt.c76
-rw-r--r--src/util/getopt_helpers.c636
-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/load.c2
-rw-r--r--src/util/mq.c322
-rw-r--r--src/util/mst.c14
-rw-r--r--src/util/network.c64
-rw-r--r--src/util/os_installation.c53
-rw-r--r--src/util/os_network.c6
-rw-r--r--src/util/os_priority.c17
-rw-r--r--src/util/peer.c2
-rw-r--r--src/util/plugin.c2
-rw-r--r--src/util/program.c14
-rw-r--r--src/util/resolver_api.c10
-rw-r--r--src/util/scheduler.c328
-rw-r--r--src/util/server_nc.c472
-rw-r--r--src/util/server_tc.c242
-rw-r--r--src/util/service.c2417
-rw-r--r--src/util/service_new.c2617
-rw-r--r--src/util/signal.c2
-rw-r--r--src/util/socks.c88
-rw-r--r--src/util/speedup.c2
-rw-r--r--src/util/strings.c38
-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_container_dll.c112
-rw-r--r--src/util/test_container_meta_data.c34
-rw-r--r--src/util/test_getopt.c53
-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/time.c2
-rw-r--r--src/util/util.conf5
-rw-r--r--src/util/win.c10
-rw-r--r--src/util/winproc.c2
-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.c1768
-rw-r--r--src/vpn/gnunet-vpn.c76
563 files changed, 37646 insertions, 60858 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 120d80a3f..4a1d909ed 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -6,18 +6,13 @@
6if HAVE_TESTING 6if HAVE_TESTING
7 TESTING = testing 7 TESTING = testing
8 TESTBED = testbed-logger testbed 8 TESTBED = testbed-logger testbed
9 CONSENSUS = consensus
10 SECRETSHARING = secretsharing
11 ATS_TESTS = ats-tests 9 ATS_TESTS = ats-tests
12endif 10endif
13 11
14if HAVE_EXPERIMENTAL 12if HAVE_EXPERIMENTAL
15 EXP_DIR = \ 13 EXP_DIR = \
16 dv \ 14 dv \
17 rps \ 15 rps
18 $(CONSENSUS) \
19 $(SECRETSHARING)
20
21endif 16endif
22 17
23if HAVE_JSON 18if HAVE_JSON
@@ -45,6 +40,10 @@ CONVERSATION_DIR = conversation
45endif 40endif
46endif 41endif
47 42
43if HAVE_SQLITE
44 SQLITE_DIR = sq
45endif
46
48if HAVE_MYSQL 47if HAVE_MYSQL
49 MYSQL_DIR = mysql my 48 MYSQL_DIR = mysql my
50endif 49endif
@@ -83,6 +82,7 @@ SUBDIRS = \
83 arm \ 82 arm \
84 $(TESTING) \ 83 $(TESTING) \
85 peerinfo \ 84 peerinfo \
85 $(SQLITE_DIR) \
86 $(MYSQL_DIR) \ 86 $(MYSQL_DIR) \
87 $(POSTGRES_DIR) \ 87 $(POSTGRES_DIR) \
88 datacache \ 88 datacache \
@@ -111,6 +111,7 @@ SUBDIRS = \
111 peerstore \ 111 peerstore \
112 cadet \ 112 cadet \
113 set \ 113 set \
114 consensus \
114 scalarproduct \ 115 scalarproduct \
115 revocation \ 116 revocation \
116 vpn \ 117 vpn \
@@ -121,6 +122,7 @@ SUBDIRS = \
121 fs \ 122 fs \
122 exit \ 123 exit \
123 pt \ 124 pt \
125 secretsharing \
124 integration-tests \ 126 integration-tests \
125 multicast \ 127 multicast \
126 psycutil \ 128 psycutil \
diff --git a/src/arm/Makefile.am b/src/arm/Makefile.am
index d5e59619e..373847fde 100644
--- a/src/arm/Makefile.am
+++ b/src/arm/Makefile.am
@@ -68,7 +68,7 @@ check_SCRIPTS = \
68endif 68endif
69 69
70if ENABLE_TEST_RUN 70if ENABLE_TEST_RUN
71AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; 71AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
72TESTS = $(check_PROGRAMS) $(check_SCRIPTS) 72TESTS = $(check_PROGRAMS) $(check_SCRIPTS)
73endif 73endif
74 74
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 b6f4d99a8..4c30985b1 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
@@ -321,23 +315,21 @@ start_callback (void *cls,
321 enum GNUNET_ARM_RequestStatus rs, 315 enum GNUNET_ARM_RequestStatus rs,
322 enum GNUNET_ARM_Result result) 316 enum GNUNET_ARM_Result result)
323{ 317{
324 char *msg;
325
326 op = NULL; 318 op = NULL;
327 if (GNUNET_ARM_REQUEST_SENT_OK != rs) 319 if (GNUNET_ARM_REQUEST_SENT_OK != rs)
328 { 320 {
329 GNUNET_asprintf (&msg, "%s", _("Failed to start the ARM service: %s\n")); 321 FPRINTF (stdout,
330 FPRINTF (stdout, msg, req_string (rs)); 322 _("Failed to start the ARM service: %s\n"),
331 GNUNET_free (msg); 323 req_string (rs));
332 GNUNET_SCHEDULER_shutdown (); 324 GNUNET_SCHEDULER_shutdown ();
333 return; 325 return;
334 } 326 }
335 if ( (GNUNET_ARM_RESULT_STARTING != result) && 327 if ( (GNUNET_ARM_RESULT_STARTING != result) &&
336 (GNUNET_ARM_RESULT_IS_STARTED_ALREADY != result) ) 328 (GNUNET_ARM_RESULT_IS_STARTED_ALREADY != result) )
337 { 329 {
338 GNUNET_asprintf (&msg, "%s", _("Failed to start the ARM service: %s\n")); 330 FPRINTF (stdout,
339 FPRINTF (stdout, msg, ret_string (result)); 331 _("Failed to start the ARM service: %s\n"),
340 GNUNET_free (msg); 332 ret_string (result));
341 GNUNET_SCHEDULER_shutdown (); 333 GNUNET_SCHEDULER_shutdown ();
342 return; 334 return;
343 } 335 }
@@ -380,10 +372,9 @@ stop_callback (void *cls,
380 (GNUNET_ARM_RESULT_STOPPED != result) && 372 (GNUNET_ARM_RESULT_STOPPED != result) &&
381 (GNUNET_ARM_RESULT_IS_STOPPED_ALREADY != result)) 373 (GNUNET_ARM_RESULT_IS_STOPPED_ALREADY != result))
382 { 374 {
383 GNUNET_asprintf (&msg, "%s", 375 FPRINTF (stdout,
384 _("Failed to stop the ARM service: %s\n")); 376 _("Failed to stop the ARM service: %s\n"),
385 FPRINTF (stdout, msg, ret_string (result)); 377 ret_string (result));
386 GNUNET_free (msg);
387 GNUNET_SCHEDULER_shutdown (); 378 GNUNET_SCHEDULER_shutdown ();
388 return; 379 return;
389 } 380 }
@@ -417,28 +408,23 @@ init_callback (void *cls,
417 enum GNUNET_ARM_RequestStatus rs, 408 enum GNUNET_ARM_RequestStatus rs,
418 enum GNUNET_ARM_Result result) 409 enum GNUNET_ARM_Result result)
419{ 410{
420 char *msg;
421
422 op = NULL; 411 op = NULL;
423 if (GNUNET_ARM_REQUEST_SENT_OK != rs) 412 if (GNUNET_ARM_REQUEST_SENT_OK != rs)
424 { 413 {
425 GNUNET_asprintf (&msg, 414 FPRINTF (stdout,
426 _("Failed to send a request to start the `%s' service: %%s\n"), 415 _("Failed to send a request to start the `%s' service: %s\n"),
427 init); 416 init,
428 FPRINTF (stdout, msg, req_string (rs)); 417 req_string (rs));
429 GNUNET_free (msg);
430 GNUNET_SCHEDULER_shutdown (); 418 GNUNET_SCHEDULER_shutdown ();
431 return; 419 return;
432 } 420 }
433 if ((GNUNET_ARM_RESULT_STARTING != result) && 421 if ((GNUNET_ARM_RESULT_STARTING != result) &&
434 (GNUNET_ARM_RESULT_IS_STARTED_ALREADY != result)) 422 (GNUNET_ARM_RESULT_IS_STARTED_ALREADY != result))
435 { 423 {
436 GNUNET_asprintf (&msg, 424 FPRINTF (stdout,
437 _("Failed to start the `%s' service: %s\n"), 425 _("Failed to start the `%s' service: %s\n"),
438 init, 426 init,
439 ret_string (result)); 427 ret_string (result));
440 FPRINTF (stdout, "%s", msg);
441 GNUNET_free (msg);
442 GNUNET_SCHEDULER_shutdown (); 428 GNUNET_SCHEDULER_shutdown ();
443 return; 429 return;
444 } 430 }
@@ -483,11 +469,10 @@ term_callback (void *cls,
483 if ((GNUNET_ARM_RESULT_STOPPED != result) && 469 if ((GNUNET_ARM_RESULT_STOPPED != result) &&
484 (GNUNET_ARM_RESULT_IS_STOPPED_ALREADY != result)) 470 (GNUNET_ARM_RESULT_IS_STOPPED_ALREADY != result))
485 { 471 {
486 GNUNET_asprintf (&msg, 472 FPRINTF (stdout,
487 _("Failed to kill the `%s' service: %s\n"), 473 _("Failed to kill the `%s' service: %s\n"),
488 term, ret_string (result)); 474 term,
489 FPRINTF (stdout, "%s", msg); 475 ret_string (result));
490 GNUNET_free (msg);
491 GNUNET_SCHEDULER_shutdown (); 476 GNUNET_SCHEDULER_shutdown ();
492 return; 477 return;
493 } 478 }
@@ -777,35 +762,70 @@ run (void *cls,
777int 762int
778main (int argc, char *const *argv) 763main (int argc, char *const *argv)
779{ 764{
780 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 765 struct GNUNET_GETOPT_CommandLineOption options[] = {
781 {'e', "end", NULL, gettext_noop ("stop all GNUnet services"), 766
782 GNUNET_NO, &GNUNET_GETOPT_set_one, &end}, 767 GNUNET_GETOPT_option_flag ('e',
783 {'i', "init", "SERVICE", gettext_noop ("start a particular service"), 768 "end",
784 GNUNET_YES, &GNUNET_GETOPT_set_string, &init}, 769 gettext_noop ("stop all GNUnet services"),
785 {'k', "kill", "SERVICE", gettext_noop ("stop a particular service"), 770 &end),
786 GNUNET_YES, &GNUNET_GETOPT_set_string, &term}, 771
787 {'s', "start", NULL, gettext_noop ("start all GNUnet default services"), 772 GNUNET_GETOPT_option_string ('i',
788 GNUNET_NO, &GNUNET_GETOPT_set_one, &start}, 773 "init",
789 {'r', "restart", NULL, 774 "SERVICE",
790 gettext_noop ("stop and start all GNUnet default services"), 775 gettext_noop ("start a particular service"),
791 GNUNET_NO, &GNUNET_GETOPT_set_one, &restart}, 776 &init),
792 {'d', "delete", NULL, 777
793 gettext_noop ("delete config file and directory on exit"), 778 GNUNET_GETOPT_option_string ('k',
794 GNUNET_NO, &GNUNET_GETOPT_set_one, &delete}, 779 "kill",
795 {'m', "monitor", NULL, 780 "SERVICE",
796 gettext_noop ("monitor ARM activities"), 781 gettext_noop ("stop a particular service"),
797 GNUNET_NO, &GNUNET_GETOPT_set_one, &monitor}, 782 &term),
798 {'q', "quiet", NULL, gettext_noop ("don't print status messages"), 783
799 GNUNET_NO, &GNUNET_GETOPT_set_one, &quiet}, 784 GNUNET_GETOPT_option_flag ('s',
800 {'T', "timeout", "DELAY", 785 "start",
801 gettext_noop ("exit with error status if operation does not finish after DELAY"), 786 gettext_noop ("start all GNUnet default services"),
802 GNUNET_YES, &GNUNET_GETOPT_set_relative_time, &timeout}, 787 &start),
803 {'I', "info", NULL, gettext_noop ("list currently running services"), 788
804 GNUNET_NO, &GNUNET_GETOPT_set_one, &list}, 789 GNUNET_GETOPT_option_flag ('r',
805 {'O', "no-stdout", NULL, gettext_noop ("don't let gnunet-service-arm inherit standard output"), 790 "restart",
806 GNUNET_NO, &GNUNET_GETOPT_set_one, &no_stdout}, 791 gettext_noop ("stop and start all GNUnet default services"),
807 {'E', "no-stderr", NULL, gettext_noop ("don't let gnunet-service-arm inherit standard error"), 792 &restart),
808 GNUNET_NO, &GNUNET_GETOPT_set_one, &no_stderr}, 793 GNUNET_GETOPT_option_flag ('d',
794 "delete",
795 gettext_noop ("delete config file and directory on exit"),
796 &delete),
797
798 GNUNET_GETOPT_option_flag ('m',
799 "monitor",
800 gettext_noop ("monitor ARM activities"),
801 &monitor),
802
803 GNUNET_GETOPT_option_flag ('q',
804 "quiet",
805 gettext_noop ("don't print status messages"),
806 &quiet),
807
808 GNUNET_GETOPT_option_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_flag ('I',
815 "info",
816 gettext_noop ("list currently running services"),
817 &list),
818
819 GNUNET_GETOPT_option_flag ('O',
820 "no-stdout",
821 gettext_noop ("don't let gnunet-service-arm inherit standard output"),
822 &no_stdout),
823
824 GNUNET_GETOPT_option_flag ('E',
825 "no-stderr",
826 gettext_noop ("don't let gnunet-service-arm inherit standard error"),
827 &no_stderr),
828
809 GNUNET_GETOPT_OPTION_END 829 GNUNET_GETOPT_OPTION_END
810 }; 830 };
811 831
diff --git a/src/arm/gnunet-service-arm.c b/src/arm/gnunet-service-arm.c
index 7af3659a4..19088c5cb 100644
--- a/src/arm/gnunet-service-arm.c
+++ b/src/arm/gnunet-service-arm.c
@@ -290,7 +290,7 @@ add_unixpath (struct sockaddr **saddrs,
290 if (GNUNET_YES == abstract) 290 if (GNUNET_YES == abstract)
291 un->sun_path[0] = '\0'; 291 un->sun_path[0] = '\0';
292#endif 292#endif
293#if HAVE_SOCKADDR_IN_SIN_LEN 293#if HAVE_SOCKADDR_UN_SUN_LEN
294 un->sun_len = (u_char) sizeof (struct sockaddr_un); 294 un->sun_len = (u_char) sizeof (struct sockaddr_un);
295#endif 295#endif
296 *saddrs = (struct sockaddr *) un; 296 *saddrs = (struct sockaddr *) un;
@@ -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/Makefile.am b/src/ats-tests/Makefile.am
index 21366484b..4811bc8d7 100644
--- a/src/ats-tests/Makefile.am
+++ b/src/ats-tests/Makefile.am
@@ -13,6 +13,7 @@ if USE_COVERAGE
13 AM_CFLAGS = -fprofile-arcs -ftest-coverage 13 AM_CFLAGS = -fprofile-arcs -ftest-coverage
14endif 14endif
15 15
16if HAVE_EXPERIMENTAL
16if HAVE_LIBGLPK 17if HAVE_LIBGLPK
17 PERF_MLP = \ 18 PERF_MLP = \
18 perf_ats_mlp_transport_none \ 19 perf_ats_mlp_transport_none \
@@ -22,6 +23,7 @@ if HAVE_LIBGLPK
22 perf_ats_mlp_core_bandwidth \ 23 perf_ats_mlp_core_bandwidth \
23 perf_ats_mlp_core_latency 24 perf_ats_mlp_core_latency
24endif 25endif
26endif
25 27
26if HAVE_TESTING 28if HAVE_TESTING
27TESTING_TESTS = \ 29TESTING_TESTS = \
@@ -44,7 +46,7 @@ check_PROGRAMS = \
44 $(TESTING_TESTS) 46 $(TESTING_TESTS)
45 47
46if ENABLE_TEST_RUN 48if ENABLE_TEST_RUN
47AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; 49AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
48TESTS = $(check_PROGRAMS) 50TESTS = $(check_PROGRAMS)
49endif 51endif
50 52
@@ -140,7 +142,7 @@ perf_ats_proportional_transport_bandwidth_LDADD = \
140perf_ats_proportional_transport_bandwidth_DEPENDENCIES = \ 142perf_ats_proportional_transport_bandwidth_DEPENDENCIES = \
141 libgnunetatstesting.la \ 143 libgnunetatstesting.la \
142 $(top_builddir)/src/util/libgnunetutil.la 144 $(top_builddir)/src/util/libgnunetutil.la
143 145
144perf_ats_proportional_core_latency_SOURCES = \ 146perf_ats_proportional_core_latency_SOURCES = \
145 perf_ats.c 147 perf_ats.c
146perf_ats_proportional_core_latency_LDADD = \ 148perf_ats_proportional_core_latency_LDADD = \
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..04508d1df 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_flag ('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-tests/template_perf_ats.conf b/src/ats-tests/template_perf_ats.conf
index 05d11449d..9d320c3dd 100644
--- a/src/ats-tests/template_perf_ats.conf
+++ b/src/ats-tests/template_perf_ats.conf
@@ -14,6 +14,8 @@ USE_INCLUDED_HELLOS = NO
14#PREFIX = valgrind --leak-check=yes 14#PREFIX = valgrind --leak-check=yes
15 15
16[ats] 16[ats]
17# PREFIX = valgrind
18
17# Network specific inbound/outbound quotas 19# Network specific inbound/outbound quotas
18UNSPECIFIED_QUOTA_IN = 128 KiB 20UNSPECIFIED_QUOTA_IN = 128 KiB
19UNSPECIFIED_QUOTA_OUT = 128 KiB 21UNSPECIFIED_QUOTA_OUT = 128 KiB
@@ -47,4 +49,4 @@ CDTU8QQ8UPLGHR3B91V0CLTDOHONLB8QGHGUEM2JM1GANTEV0O6T20SD2N2HDN2QSHDG6IDTBR48KRDC
47 49
48[transport-blacklist-548J7M14O4I0F8I84U0UFARVJ97DB6QOT3MCA8O8SNAIT5JJ8TR95LUVAP3N5L7DN33IB49SNMF3Q3C0VPLTGP9ASCULA9S2OIMHHH8] 50[transport-blacklist-548J7M14O4I0F8I84U0UFARVJ97DB6QOT3MCA8O8SNAIT5JJ8TR95LUVAP3N5L7DN33IB49SNMF3Q3C0VPLTGP9ASCULA9S2OIMHHH8]
49HIJN5O404QNUR37OSJUTNJ6H2KJS198DHI2J3I8SE3DMKVRG1RNQPODN1IJBF14KEMPPPRM0B9F9ILFKHOFCA655CH6M5OCNCMR0FE0 = 51HIJN5O404QNUR37OSJUTNJ6H2KJS198DHI2J3I8SE3DMKVRG1RNQPODN1IJBF14KEMPPPRM0B9F9ILFKHOFCA655CH6M5OCNCMR0FE0 =
50CDTU8QQ8UPLGHR3B91V0CLTDOHONLB8QGHGUEM2JM1GANTEV0O6T20SD2N2HDN2QSHDG6IDTBR48KRDCS601FI6VHG59E7DQA98JD2O = \ No newline at end of file 52CDTU8QQ8UPLGHR3B91V0CLTDOHONLB8QGHGUEM2JM1GANTEV0O6T20SD2N2HDN2QSHDG6IDTBR48KRDCS601FI6VHG59E7DQA98JD2O =
diff --git a/src/ats-tool/gnunet-ats.c b/src/ats-tool/gnunet-ats.c
index 5fc1d6e92..5ec7693b1 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_flag ('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_flag ('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_flag ('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_flag ('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_flag ('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_flag ('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_uint ('k',
994 "value",
995 "VALUE",
996 gettext_noop ("preference value"),
997 &opt_pref_value),
998
999 GNUNET_GETOPT_option_flag ('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/.gitignore b/src/ats/.gitignore
index 983dc2843..97f1088b9 100644
--- a/src/ats/.gitignore
+++ b/src/ats/.gitignore
@@ -1,3 +1,5 @@
1gnunet-service-ats 1gnunet-service-ats
2test_ats_api_proportional 2test_ats_api_proportional
3test_ats_reservation_api_proportional 3test_ats_reservation_api_proportional
4test_ats_api_mlp
5test_ats_api_ril
diff --git a/src/ats/Makefile.am b/src/ats/Makefile.am
index aa3612c2d..759dac0be 100644
--- a/src/ats/Makefile.am
+++ b/src/ats/Makefile.am
@@ -21,14 +21,16 @@ endif
21lib_LTLIBRARIES = libgnunetats.la 21lib_LTLIBRARIES = libgnunetats.la
22 22
23plugin_LTLIBRARIES = \ 23plugin_LTLIBRARIES = \
24 libgnunet_plugin_ats_proportional.la \ 24 libgnunet_plugin_ats_proportional.la
25 $(GN_MLP_LIB) \
26 libgnunet_plugin_ats_ril.la
27 25
26if HAVE_EXPERIMENTAL
27plugin_LTLIBRARIES += \
28 libgnunet_plugin_ats_ril.la
28if HAVE_LIBGLPK 29if HAVE_LIBGLPK
29plugin_LTLIBRARIES += \ 30plugin_LTLIBRARIES += \
30 libgnunet_plugin_ats_mlp.la 31 libgnunet_plugin_ats_mlp.la
31endif 32endif
33endif
32 34
33libgnunetats_la_SOURCES = \ 35libgnunetats_la_SOURCES = \
34 ats_api_connectivity.c \ 36 ats_api_connectivity.c \
@@ -54,7 +56,6 @@ libgnunet_plugin_ats_proportional_la_LDFLAGS = \
54 $(GN_PLUGIN_LDFLAGS) 56 $(GN_PLUGIN_LDFLAGS)
55 57
56 58
57if HAVE_LIBGLPK
58libgnunet_plugin_ats_mlp_la_SOURCES = \ 59libgnunet_plugin_ats_mlp_la_SOURCES = \
59 plugin_ats_mlp.c 60 plugin_ats_mlp.c
60libgnunet_plugin_ats_mlp_la_LIBADD = \ 61libgnunet_plugin_ats_mlp_la_LIBADD = \
@@ -64,7 +65,6 @@ libgnunet_plugin_ats_mlp_la_LIBADD = \
64libgnunet_plugin_ats_mlp_la_LDFLAGS = \ 65libgnunet_plugin_ats_mlp_la_LDFLAGS = \
65 $(GN_PLUGIN_LDFLAGS) \ 66 $(GN_PLUGIN_LDFLAGS) \
66 -lglpk 67 -lglpk
67endif
68 68
69libgnunet_plugin_ats_ril_la_SOURCES = \ 69libgnunet_plugin_ats_ril_la_SOURCES = \
70 plugin_ats_ril.c 70 plugin_ats_ril.c
@@ -99,7 +99,7 @@ if HAVE_TESTING
99TESTING_TESTS = \ 99TESTING_TESTS = \
100 test_ats_api_proportional \ 100 test_ats_api_proportional \
101 test_ats_reservation_api_proportional 101 test_ats_reservation_api_proportional
102if HAVE_WACHS 102if HAVE_EXPERIMENTAL
103TESTING_TESTS += \ 103TESTING_TESTS += \
104 test_ats_api_ril 104 test_ats_api_ril
105if HAVE_LIBGLPK 105if HAVE_LIBGLPK
@@ -113,7 +113,7 @@ check_PROGRAMS = \
113 $(TESTING_TESTS) 113 $(TESTING_TESTS)
114 114
115if ENABLE_TEST_RUN 115if ENABLE_TEST_RUN
116AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; 116AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
117TESTS = $(check_PROGRAMS) 117TESTS = $(check_PROGRAMS)
118endif 118endif
119 119
diff --git a/src/ats/ats_api_performance.c b/src/ats/ats_api_performance.c
index cd67583d1..c5b126e08 100644
--- a/src/ats/ats_api_performance.c
+++ b/src/ats/ats_api_performance.c
@@ -816,7 +816,7 @@ GNUNET_ATS_performance_list_addresses_cancel (struct GNUNET_ATS_AddressListHandl
816 * @return a string or NULL if invalid 816 * @return a string or NULL if invalid
817 */ 817 */
818const char * 818const char *
819GNUNET_ATS_print_preference_type (uint32_t type) 819GNUNET_ATS_print_preference_type (enum GNUNET_ATS_PreferenceKind type)
820{ 820{
821 const char *prefs[] = GNUNET_ATS_PreferenceTypeString; 821 const char *prefs[] = GNUNET_ATS_PreferenceTypeString;
822 822
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..5af2fbce3 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_flag ('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_flag ('f',
3310 "file",
3311 gettext_noop ("save logging to disk"),
3312 &opt_save),
3313
3314 GNUNET_GETOPT_option_flag ('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..7fae3624f 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_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_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_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_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_uint ('p',
1429 "percentage",
1430 gettext_noop ("update a fix percentage of addresses"),
1431 &ph.opt_update_percent),
1432
1433 GNUNET_GETOPT_option_flag ('d',
1434 "data",
1435 gettext_noop ("create data file"),
1436 &ph.create_datafile),
1437
1438 GNUNET_GETOPT_option_flag ('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/Makefile.am b/src/auction/Makefile.am
index 87f917283..bdede0ce0 100644
--- a/src/auction/Makefile.am
+++ b/src/auction/Makefile.am
@@ -1,74 +1,74 @@
1# This Makefile.am is in the public domain 1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include 2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3 3
4pkgcfgdir= $(pkgdatadir)/config.d/ 4pkgcfgdir = $(pkgdatadir)/config.d/
5 5
6libexecdir= $(pkglibdir)/libexec/ 6libexecdir = $(pkglibdir)/libexec/
7 7
8 8
9pkgcfg_DATA = \ 9pkgcfg_DATA = \
10 auction.conf 10 auction.conf
11 11
12if MINGW 12if MINGW
13 WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols 13 WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols
14endif 14endif
15 15
16if USE_COVERAGE 16if USE_COVERAGE
17 AM_CFLAGS = -fprofile-arcs -ftest-coverage 17 AM_CFLAGS = -fprofile-arcs -ftest-coverage
18endif 18endif
19 19
20 20
21libexec_PROGRAMS = \ 21libexec_PROGRAMS = \
22 gnunet-service-auction 22 gnunet-service-auction
23 23
24gnunet_service_auction_SOURCES = \ 24gnunet_service_auction_SOURCES = \
25 gnunet-service-auction.c 25 gnunet-service-auction.c
26gnunet_service_auction_LDADD = \ 26gnunet_service_auction_LDADD = \
27 $(top_builddir)/src/util/libgnunetutil.la \ 27 $(top_builddir)/src/util/libgnunetutil.la \
28 -ljansson \ 28 -ljansson \
29 $(GN_LIBINTL) 29 $(GN_LIBINTL)
30 30
31 31
32bin_PROGRAMS = \ 32bin_PROGRAMS = \
33 gnunet-auction-create \ 33 gnunet-auction-create \
34 gnunet-auction-info \ 34 gnunet-auction-info \
35 gnunet-auction-join 35 gnunet-auction-join
36 36
37gnunet_auction_create_SOURCES = \ 37gnunet_auction_create_SOURCES = \
38 gnunet-auction-create.c 38 gnunet-auction-create.c
39gnunet_auction_create_LDADD = \ 39gnunet_auction_create_LDADD = \
40 $(top_builddir)/src/util/libgnunetutil.la \ 40 $(top_builddir)/src/util/libgnunetutil.la \
41 -ljansson \ 41 -ljansson \
42 $(GN_LIBINTL) 42 $(GN_LIBINTL)
43 43
44gnunet_auction_info_SOURCES = \ 44gnunet_auction_info_SOURCES = \
45 gnunet-auction-info.c 45 gnunet-auction-info.c
46gnunet_auction_info_LDADD = \ 46gnunet_auction_info_LDADD = \
47 $(top_builddir)/src/util/libgnunetutil.la \ 47 $(top_builddir)/src/util/libgnunetutil.la \
48 -ljansson \ 48 -ljansson \
49 $(GN_LIBINTL) 49 $(GN_LIBINTL)
50 50
51gnunet_auction_join_SOURCES = \ 51gnunet_auction_join_SOURCES = \
52 gnunet-auction-join.c 52 gnunet-auction-join.c
53gnunet_auction_join_LDADD = \ 53gnunet_auction_join_LDADD = \
54 $(top_builddir)/src/util/libgnunetutil.la \ 54 $(top_builddir)/src/util/libgnunetutil.la \
55 -ljansson \ 55 -ljansson \
56 $(GN_LIBINTL) 56 $(GN_LIBINTL)
57 57
58 58
59check_PROGRAMS = \ 59check_PROGRAMS = \
60 test_auction_api 60 test_auction_api
61 61
62test_auction_api_SOURCES = \ 62test_auction_api_SOURCES = \
63 test_auction_api.c 63 test_auction_api.c
64test_auction_api_LDADD = \ 64test_auction_api_LDADD = \
65 $(top_builddir)/src/util/libgnunetutil.la 65 $(top_builddir)/src/util/libgnunetutil.la
66 66
67 67
68check_SCRIPTS = \ 68check_SCRIPTS = \
69 test_auction_create.sh 69 test_auction_create.sh
70 70
71if ENABLE_TEST_RUN 71if ENABLE_TEST_RUN
72AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; 72 AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
73TESTS = $(check_PROGRAMS) $(check_SCRIPTS) 73 TESTS = $(check_PROGRAMS) $(check_SCRIPTS)
74endif 74endif
diff --git a/src/auction/gnunet-auction-create.c b/src/auction/gnunet-auction-create.c
index a4c029572..9e6c23b88 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_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_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_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_flag ('u',
192 "public",
193 gettext_noop ("public auction outcome"),
194 &outcome),
195
196 GNUNET_GETOPT_option_flag ('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/Makefile.am b/src/block/Makefile.am
index c54a4c246..05df7541d 100644
--- a/src/block/Makefile.am
+++ b/src/block/Makefile.am
@@ -11,7 +11,9 @@ if USE_COVERAGE
11 AM_CFLAGS = --coverage 11 AM_CFLAGS = --coverage
12endif 12endif
13 13
14lib_LTLIBRARIES = libgnunetblock.la 14lib_LTLIBRARIES = \
15 libgnunetblock.la \
16 libgnunetblockgroup.la
15 17
16plugin_LTLIBRARIES = \ 18plugin_LTLIBRARIES = \
17 libgnunet_plugin_block_test.la 19 libgnunet_plugin_block_test.la
@@ -24,7 +26,7 @@ noinst_LTLIBRARIES = \
24libgnunet_plugin_block_template_la_SOURCES = \ 26libgnunet_plugin_block_template_la_SOURCES = \
25 plugin_block_template.c 27 plugin_block_template.c
26libgnunet_plugin_block_template_la_LIBADD = \ 28libgnunet_plugin_block_template_la_LIBADD = \
27 libgnunetblock.la \ 29 libgnunetblockgroup.la \
28 $(top_builddir)/src/util/libgnunetutil.la \ 30 $(top_builddir)/src/util/libgnunetutil.la \
29 $(LTLIBINTL) 31 $(LTLIBINTL)
30libgnunet_plugin_block_template_la_LDFLAGS = \ 32libgnunet_plugin_block_template_la_LDFLAGS = \
@@ -33,8 +35,8 @@ libgnunet_plugin_block_template_la_LDFLAGS = \
33libgnunet_plugin_block_test_la_SOURCES = \ 35libgnunet_plugin_block_test_la_SOURCES = \
34 plugin_block_test.c 36 plugin_block_test.c
35libgnunet_plugin_block_test_la_LIBADD = \ 37libgnunet_plugin_block_test_la_LIBADD = \
36 libgnunetblock.la \ 38 libgnunetblockgroup.la \
37 $(top_builddir)/src/util/libgnunetutil.la \ 39$(top_builddir)/src/util/libgnunetutil.la \
38 $(LTLIBINTL) 40 $(LTLIBINTL)
39libgnunet_plugin_block_test_la_LDFLAGS = \ 41libgnunet_plugin_block_test_la_LDFLAGS = \
40 $(GN_PLUGIN_LDFLAGS) 42 $(GN_PLUGIN_LDFLAGS)
@@ -49,3 +51,16 @@ libgnunetblock_la_DEPENDENCIES = \
49libgnunetblock_la_LDFLAGS = \ 51libgnunetblock_la_LDFLAGS = \
50 $(GN_LIB_LDFLAGS) \ 52 $(GN_LIB_LDFLAGS) \
51 -version-info 0:0:0 53 -version-info 0:0:0
54
55
56libgnunetblockgroup_la_SOURCES = \
57 bg_bf.c
58libgnunetblockgroup_la_LIBADD = \
59 libgnunetblock.la \
60 $(top_builddir)/src/util/libgnunetutil.la
61libgnunetblockgroup_la_DEPENDENCIES = \
62 libgnunetblock.la \
63 $(top_builddir)/src/util/libgnunetutil.la
64libgnunetblockgroup_la_LDFLAGS = \
65 $(GN_LIB_LDFLAGS) \
66 -version-info 0:0:0
diff --git a/src/block/bg_bf.c b/src/block/bg_bf.c
new file mode 100644
index 000000000..3e7d38892
--- /dev/null
+++ b/src/block/bg_bf.c
@@ -0,0 +1,268 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 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 block/bg_bf.c
22 * @brief implementation of a block group using a Bloom filter
23 * to drop duplicate blocks
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_block_group_lib.h"
29#include "gnunet_block_plugin.h"
30
31
32/**
33 * Internal data structure for a block group.
34 */
35struct BfGroupInternals
36{
37 /**
38 * A Bloom filter to weed out duplicate replies probabilistically.
39 */
40 struct GNUNET_CONTAINER_BloomFilter *bf;
41
42 /**
43 * Set from the nonce to mingle the hashes before going into the @e bf.
44 */
45 uint32_t bf_mutator;
46
47 /**
48 * Size of @a bf.
49 */
50 uint32_t bf_size;
51
52};
53
54
55/**
56 * Serialize state of a block group.
57 *
58 * @param bg group to serialize
59 * @param[out] nonce set to the nonce of the @a bg
60 * @param[out] raw_data set to the serialized state
61 * @param[out] raw_data_size set to the number of bytes in @a raw_data
62 * @return #GNUNET_OK on success, #GNUNET_NO if serialization is not
63 * supported, #GNUNET_SYSERR on error
64 */
65static int
66bf_group_serialize_cb (struct GNUNET_BLOCK_Group *bg,
67 uint32_t *nonce,
68 void **raw_data,
69 size_t *raw_data_size)
70{
71 struct BfGroupInternals *gi = bg->internal_cls;
72 char *raw;
73
74 raw = GNUNET_malloc (gi->bf_size);
75 if (GNUNET_OK !=
76 GNUNET_CONTAINER_bloomfilter_get_raw_data (gi->bf,
77 raw,
78 gi->bf_size))
79 {
80 GNUNET_free (raw);
81 GNUNET_break (0);
82 return GNUNET_SYSERR;
83 }
84 *nonce = gi->bf_mutator;
85 *raw_data = raw;
86 *raw_data_size = gi->bf_size;
87 return GNUNET_OK;
88}
89
90
91/**
92 * Mark elements as "seen" using a hash of the element. Not supported
93 * by all block plugins.
94 *
95 * @param bg group to update
96 * @param seen_results results already seen
97 * @param seen_results_count number of entries in @a seen_results
98 */
99static void
100bf_group_mark_seen_cb (struct GNUNET_BLOCK_Group *bg,
101 const struct GNUNET_HashCode *seen_results,
102 unsigned int seen_results_count)
103{
104 struct BfGroupInternals *gi = bg->internal_cls;
105
106 for (unsigned int i=0;i<seen_results_count;i++)
107 {
108 struct GNUNET_HashCode mhash;
109
110 GNUNET_BLOCK_mingle_hash (&seen_results[i],
111 gi->bf_mutator,
112 &mhash);
113 GNUNET_CONTAINER_bloomfilter_add (gi->bf,
114 &mhash);
115 }
116}
117
118
119/**
120 * Merge two groups, if possible. Not supported by all block plugins,
121 * can also fail if the nonces were different.
122 *
123 * @param bg1 group to update
124 * @param bg2 group to merge into @a bg1
125 * @return #GNUNET_OK on success, #GNUNET_NO if the nonces were different and thus
126 * we failed.
127 */
128static int
129bf_group_merge_cb (struct GNUNET_BLOCK_Group *bg1,
130 const struct GNUNET_BLOCK_Group *bg2)
131{
132 struct BfGroupInternals *gi1 = bg1->internal_cls;
133 struct BfGroupInternals *gi2 = bg2->internal_cls;
134
135 if (gi1->bf_mutator != gi2->bf_mutator)
136 return GNUNET_NO;
137 if (gi1->bf_size != gi2->bf_size)
138 return GNUNET_NO;
139 GNUNET_CONTAINER_bloomfilter_or2 (gi1->bf,
140 gi2->bf);
141 return GNUNET_OK;
142}
143
144
145/**
146 * Destroy resources used by a block group.
147 *
148 * @param bg group to destroy, NULL is allowed
149 */
150static void
151bf_group_destroy_cb (struct GNUNET_BLOCK_Group *bg)
152{
153 struct BfGroupInternals *gi = bg->internal_cls;
154
155 GNUNET_CONTAINER_bloomfilter_free (gi->bf);
156 GNUNET_free (gi);
157 GNUNET_free (bg);
158}
159
160
161/**
162 * Create a new block group that filters duplicates using a Bloom filter.
163 *
164 * @param ctx block context in which the block group is created
165 * @param bf_size size of the Bloom filter
166 * @param bf_k K-value for the Bloom filter
167 * @param type block type
168 * @param nonce random value used to seed the group creation
169 * @param raw_data optional serialized prior state of the group, NULL if unavailable/fresh
170 * @param raw_data_size number of bytes in @a raw_data, 0 if unavailable/fresh
171 * @return block group handle, NULL if block groups are not supported
172 * by this @a type of block (this is not an error)
173 */
174struct GNUNET_BLOCK_Group *
175GNUNET_BLOCK_GROUP_bf_create (void *cls,
176 size_t bf_size,
177 unsigned int bf_k,
178 enum GNUNET_BLOCK_Type type,
179 uint32_t nonce,
180 const void *raw_data,
181 size_t raw_data_size)
182{
183 struct BfGroupInternals *gi;
184 struct GNUNET_BLOCK_Group *bg;
185
186 gi = GNUNET_new (struct BfGroupInternals);
187 gi->bf = GNUNET_CONTAINER_bloomfilter_init ((bf_size != raw_data_size) ? NULL : raw_data,
188 bf_size,
189 bf_k);
190 gi->bf_mutator = nonce;
191 gi->bf_size = bf_size;
192 bg = GNUNET_new (struct GNUNET_BLOCK_Group);
193 bg->type = type;
194 bg->serialize_cb = &bf_group_serialize_cb;
195 bg->mark_seen_cb = &bf_group_mark_seen_cb;
196 bg->merge_cb = &bf_group_merge_cb;
197 bg->destroy_cb = &bf_group_destroy_cb;
198 bg->internal_cls = gi;
199 return bg;
200}
201
202
203/**
204 * Test if @a hc is contained in the Bloom filter of @a bg. If so,
205 * return #GNUNET_YES. If not, add @a hc to the Bloom filter and
206 * return #GNUNET_NO.
207 *
208 * @param bg block group to use for testing
209 * @param hc hash of element to evaluate
210 * @return #GNUNET_YES if @a hc is (likely) a duplicate
211 * #GNUNET_NO if @a hc was definitively not in @bg (but now is)
212 */
213int
214GNUNET_BLOCK_GROUP_bf_test_and_set (struct GNUNET_BLOCK_Group *bg,
215 const struct GNUNET_HashCode *hc)
216{
217 struct BfGroupInternals *gi;
218 struct GNUNET_HashCode mhash;
219
220 if (NULL == bg)
221 return GNUNET_NO;
222 gi = bg->internal_cls;
223 GNUNET_BLOCK_mingle_hash (hc,
224 gi->bf_mutator,
225 &mhash);
226 if (GNUNET_YES ==
227 GNUNET_CONTAINER_bloomfilter_test (gi->bf,
228 &mhash))
229 return GNUNET_YES;
230 GNUNET_CONTAINER_bloomfilter_add (gi->bf,
231 &mhash);
232 return GNUNET_NO;
233}
234
235
236/**
237 * How many bytes should a bloomfilter be if we have already seen
238 * entry_count responses? Sized so that do not have to
239 * re-size the filter too often (to keep it cheap).
240 *
241 * Since other peers will also add entries but not resize the filter,
242 * we should generally pick a slightly larger size than what the
243 * strict math would suggest.
244 *
245 * @param entry_count expected number of entries in the Bloom filter
246 * @param k number of bits set per entry
247 * @return must be a power of two and smaller or equal to 2^15.
248 */
249size_t
250GNUNET_BLOCK_GROUP_compute_bloomfilter_size (unsigned int entry_count,
251 unsigned int k)
252{
253 size_t size;
254 unsigned int ideal = (entry_count * k) / 4;
255 uint16_t max = 1 << 15;
256
257 if (entry_count > max)
258 return max;
259 size = 8;
260 while ((size < max) && (size < ideal))
261 size *= 2;
262 if (size > max)
263 return max;
264 return size;
265}
266
267
268/* end of bg_bf.c */
diff --git a/src/block/block.c b/src/block/block.c
index c104f4bd1..4b6f3826d 100644
--- a/src/block/block.c
+++ b/src/block/block.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 Copyright (C) 2010 GNUnet e.V. 3 Copyright (C) 2010, 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
@@ -84,8 +84,12 @@ GNUNET_BLOCK_mingle_hash (const struct GNUNET_HashCode *in,
84{ 84{
85 struct GNUNET_HashCode m; 85 struct GNUNET_HashCode m;
86 86
87 GNUNET_CRYPTO_hash (&mingle_number, sizeof (uint32_t), &m); 87 GNUNET_CRYPTO_hash (&mingle_number,
88 GNUNET_CRYPTO_hash_xor (&m, in, hc); 88 sizeof (uint32_t),
89 &m);
90 GNUNET_CRYPTO_hash_xor (&m,
91 in,
92 hc);
89} 93}
90 94
91 95
@@ -111,7 +115,9 @@ add_plugin (void *cls,
111 plugin = GNUNET_new (struct Plugin); 115 plugin = GNUNET_new (struct Plugin);
112 plugin->api = api; 116 plugin->api = api;
113 plugin->library_name = GNUNET_strdup (library_name); 117 plugin->library_name = GNUNET_strdup (library_name);
114 GNUNET_array_append (ctx->plugins, ctx->num_plugins, plugin); 118 GNUNET_array_append (ctx->plugins,
119 ctx->num_plugins,
120 plugin);
115} 121}
116 122
117 123
@@ -129,7 +135,10 @@ GNUNET_BLOCK_context_create (const struct GNUNET_CONFIGURATION_Handle *cfg)
129 135
130 ctx = GNUNET_new (struct GNUNET_BLOCK_Context); 136 ctx = GNUNET_new (struct GNUNET_BLOCK_Context);
131 ctx->cfg = cfg; 137 ctx->cfg = cfg;
132 GNUNET_PLUGIN_load_all ("libgnunet_plugin_block_", NULL, &add_plugin, ctx); 138 GNUNET_PLUGIN_load_all ("libgnunet_plugin_block_",
139 (void *) cfg,
140 &add_plugin,
141 ctx);
133 return ctx; 142 return ctx;
134} 143}
135 144
@@ -149,7 +158,8 @@ GNUNET_BLOCK_context_destroy (struct GNUNET_BLOCK_Context *ctx)
149 { 158 {
150 plugin = ctx->plugins[i]; 159 plugin = ctx->plugins[i];
151 GNUNET_break (NULL == 160 GNUNET_break (NULL ==
152 GNUNET_PLUGIN_unload (plugin->library_name, plugin->api)); 161 GNUNET_PLUGIN_unload (plugin->library_name,
162 plugin->api));
153 GNUNET_free (plugin->library_name); 163 GNUNET_free (plugin->library_name);
154 GNUNET_free (plugin); 164 GNUNET_free (plugin);
155 } 165 }
@@ -159,6 +169,85 @@ GNUNET_BLOCK_context_destroy (struct GNUNET_BLOCK_Context *ctx)
159 169
160 170
161/** 171/**
172 * Serialize state of a block group.
173 *
174 * @param bg group to serialize
175 * @param[out] nonce set to the nonce of the @a bg
176 * @param[out] raw_data set to the serialized state
177 * @param[out] raw_data_size set to the number of bytes in @a raw_data
178 * @return #GNUNET_OK on success, #GNUNET_NO if serialization is not
179 * supported, #GNUNET_SYSERR on error
180 */
181int
182GNUNET_BLOCK_group_serialize (struct GNUNET_BLOCK_Group *bg,
183 uint32_t *nonce,
184 void **raw_data,
185 size_t *raw_data_size)
186{
187 *nonce = 0;
188 *raw_data = NULL;
189 *raw_data_size = 0;
190 if (NULL == bg)
191 return GNUNET_NO;
192 if (NULL == bg->serialize_cb)
193 return GNUNET_NO;
194 return bg->serialize_cb (bg,
195 nonce,
196 raw_data,
197 raw_data_size);
198}
199
200
201/**
202 * Destroy resources used by a block group.
203 *
204 * @param bg group to destroy, NULL is allowed
205 */
206void
207GNUNET_BLOCK_group_destroy (struct GNUNET_BLOCK_Group *bg)
208{
209 if (NULL == bg)
210 return;
211 bg->destroy_cb (bg);
212}
213
214
215/**
216 * Try merging two block groups. Afterwards, @a bg1 should remain
217 * valid and contain the rules from both @a bg1 and @bg2, and
218 * @a bg2 should be destroyed (as part of this call). The latter
219 * should happen even if merging is not supported.
220 *
221 * @param[in,out] bg1 first group to merge, is updated
222 * @param bg2 second group to merge, is destroyed
223 * @return #GNUNET_OK on success,
224 * #GNUNET_NO if merge failed due to different nonce
225 * #GNUNET_SYSERR if merging is not supported
226 */
227int
228GNUNET_BLOCK_group_merge (struct GNUNET_BLOCK_Group *bg1,
229 struct GNUNET_BLOCK_Group *bg2)
230{
231 int ret;
232
233 if (NULL == bg2)
234 return GNUNET_OK;
235 if (NULL == bg1)
236 {
237 bg2->destroy_cb (bg2);
238 return GNUNET_OK;
239 }
240 if (NULL == bg1->merge_cb)
241 return GNUNET_SYSERR;
242 GNUNET_assert (bg1->merge_cb == bg1->merge_cb);
243 ret = bg1->merge_cb (bg1,
244 bg2);
245 bg2->destroy_cb (bg2);
246 return ret;
247}
248
249
250/**
162 * Find a plugin for the given type. 251 * Find a plugin for the given type.
163 * 252 *
164 * @param ctx context to search 253 * @param ctx context to search
@@ -170,10 +259,9 @@ find_plugin (struct GNUNET_BLOCK_Context *ctx,
170 enum GNUNET_BLOCK_Type type) 259 enum GNUNET_BLOCK_Type type)
171{ 260{
172 struct Plugin *plugin; 261 struct Plugin *plugin;
173 unsigned int i;
174 unsigned int j; 262 unsigned int j;
175 263
176 for (i = 0; i < ctx->num_plugins; i++) 264 for (unsigned i = 0; i < ctx->num_plugins; i++)
177 { 265 {
178 plugin = ctx->plugins[i]; 266 plugin = ctx->plugins[i];
179 j = 0; 267 j = 0;
@@ -189,6 +277,46 @@ find_plugin (struct GNUNET_BLOCK_Context *ctx,
189 277
190 278
191/** 279/**
280 * Create a new block group.
281 *
282 * @param ctx block context in which the block group is created
283 * @param type type of the block for which we are creating the group
284 * @param nonce random value used to seed the group creation
285 * @param raw_data optional serialized prior state of the group, NULL if unavailable/fresh
286 * @param raw_data_size number of bytes in @a raw_data, 0 if unavailable/fresh
287 * @return block group handle, NULL if block groups are not supported
288 * by this @a type of block (this is not an error)
289 */
290struct GNUNET_BLOCK_Group *
291GNUNET_BLOCK_group_create (struct GNUNET_BLOCK_Context *ctx,
292 enum GNUNET_BLOCK_Type type,
293 uint32_t nonce,
294 const void *raw_data,
295 size_t raw_data_size,
296 ...)
297{
298 struct GNUNET_BLOCK_PluginFunctions *plugin;
299 struct GNUNET_BLOCK_Group *bg;
300 va_list ap;
301
302 plugin = find_plugin (ctx,
303 type);
304 if (NULL == plugin->create_group)
305 return NULL;
306 va_start (ap,
307 raw_data_size);
308 bg = plugin->create_group (plugin->cls,
309 type,
310 nonce,
311 raw_data,
312 raw_data_size,
313 ap);
314 va_end (ap);
315 return bg;
316}
317
318
319/**
192 * Function called to validate a reply or a request. For 320 * Function called to validate a reply or a request. For
193 * request evaluation, simply pass "NULL" for the reply_block. 321 * request evaluation, simply pass "NULL" for the reply_block.
194 * Note that it is assumed that the reply has already been 322 * Note that it is assumed that the reply has already been
@@ -197,10 +325,9 @@ find_plugin (struct GNUNET_BLOCK_Context *ctx,
197 * 325 *
198 * @param ctx block contxt 326 * @param ctx block contxt
199 * @param type block type 327 * @param type block type
328 * @param block block group to use
200 * @param eo control flags 329 * @param eo control flags
201 * @param query original query (hash) 330 * @param query original query (hash)
202 * @param bf pointer to bloom filter associated with query; possibly updated (!)
203 * @param bf_mutator mutation value for @a bf
204 * @param xquery extended query data (can be NULL, depending on type) 331 * @param xquery extended query data (can be NULL, depending on type)
205 * @param xquery_size number of bytes in @a xquery 332 * @param xquery_size number of bytes in @a xquery
206 * @param reply_block response to validate 333 * @param reply_block response to validate
@@ -210,25 +337,25 @@ find_plugin (struct GNUNET_BLOCK_Context *ctx,
210enum GNUNET_BLOCK_EvaluationResult 337enum GNUNET_BLOCK_EvaluationResult
211GNUNET_BLOCK_evaluate (struct GNUNET_BLOCK_Context *ctx, 338GNUNET_BLOCK_evaluate (struct GNUNET_BLOCK_Context *ctx,
212 enum GNUNET_BLOCK_Type type, 339 enum GNUNET_BLOCK_Type type,
340 struct GNUNET_BLOCK_Group *group,
213 enum GNUNET_BLOCK_EvaluationOptions eo, 341 enum GNUNET_BLOCK_EvaluationOptions eo,
214 const struct GNUNET_HashCode *query, 342 const struct GNUNET_HashCode *query,
215 struct GNUNET_CONTAINER_BloomFilter **bf,
216 int32_t bf_mutator,
217 const void *xquery, 343 const void *xquery,
218 size_t xquery_size, 344 size_t xquery_size,
219 const void *reply_block, 345 const void *reply_block,
220 size_t reply_block_size) 346 size_t reply_block_size)
221{ 347{
222 struct GNUNET_BLOCK_PluginFunctions *plugin = find_plugin (ctx, type); 348 struct GNUNET_BLOCK_PluginFunctions *plugin = find_plugin (ctx,
349 type);
223 350
224 if (plugin == NULL) 351 if (NULL == plugin)
225 return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED; 352 return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED;
226 return plugin->evaluate (plugin->cls, 353 return plugin->evaluate (plugin->cls,
354 ctx,
227 type, 355 type,
356 group,
228 eo, 357 eo,
229 query, 358 query,
230 bf,
231 bf_mutator,
232 xquery, 359 xquery,
233 xquery_size, 360 xquery_size,
234 reply_block, 361 reply_block,
@@ -254,74 +381,43 @@ GNUNET_BLOCK_get_key (struct GNUNET_BLOCK_Context *ctx,
254 size_t block_size, 381 size_t block_size,
255 struct GNUNET_HashCode *key) 382 struct GNUNET_HashCode *key)
256{ 383{
257 struct GNUNET_BLOCK_PluginFunctions *plugin = find_plugin (ctx, type); 384 struct GNUNET_BLOCK_PluginFunctions *plugin = find_plugin (ctx,
385 type);
258 386
259 if (plugin == NULL) 387 if (plugin == NULL)
260 return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED; 388 return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED;
261 return plugin->get_key (plugin->cls, type, block, block_size, key); 389 return plugin->get_key (plugin->cls,
390 type,
391 block,
392 block_size,
393 key);
262} 394}
263 395
264 396
265/** 397/**
266 * How many bytes should a bloomfilter be if we have already seen 398 * Update block group to filter out the given results. Note that the
267 * entry_count responses? Note that #GNUNET_CONSTANTS_BLOOMFILTER_K 399 * use of a hash for seen results implies that the caller magically
268 * gives us the number of bits set per entry. Furthermore, we should 400 * knows how the specific block engine hashes for filtering
269 * not re-size the filter too often (to keep it cheap). 401 * duplicates, so this API may not always apply.
270 *
271 * Since other peers will also add entries but not resize the filter,
272 * we should generally pick a slightly larger size than what the
273 * strict math would suggest.
274 *
275 * @param entry_count expected number of entries in the Bloom filter
276 * @return must be a power of two and smaller or equal to 2^15.
277 */
278static size_t
279compute_bloomfilter_size (unsigned int entry_count)
280{
281 size_t size;
282 unsigned int ideal = (entry_count * GNUNET_CONSTANTS_BLOOMFILTER_K) / 4;
283 uint16_t max = 1 << 15;
284
285 if (entry_count > max)
286 return max;
287 size = 8;
288 while ((size < max) && (size < ideal))
289 size *= 2;
290 if (size > max)
291 return max;
292 return size;
293}
294
295
296/**
297 * Construct a bloom filter that would filter out the given
298 * results.
299 * 402 *
300 * @param bf_mutator mutation value to use 403 * @param bf_mutator mutation value to use
301 * @param seen_results results already seen 404 * @param seen_results results already seen
302 * @param seen_results_count number of entries in @a seen_results 405 * @param seen_results_count number of entries in @a seen_results
303 * @return NULL if seen_results_count is 0, otherwise a BF 406 * @return #GNUNET_SYSERR if not supported, #GNUNET_OK on success
304 * that would match the given results.
305 */ 407 */
306struct GNUNET_CONTAINER_BloomFilter * 408int
307GNUNET_BLOCK_construct_bloomfilter (int32_t bf_mutator, 409GNUNET_BLOCK_group_set_seen (struct GNUNET_BLOCK_Group *bg,
308 const struct GNUNET_HashCode *seen_results, 410 const struct GNUNET_HashCode *seen_results,
309 unsigned int seen_results_count) 411 unsigned int seen_results_count)
310{ 412{
311 struct GNUNET_CONTAINER_BloomFilter *bf; 413 if (NULL == bg)
312 struct GNUNET_HashCode mhash; 414 return GNUNET_OK;
313 unsigned int i; 415 if (NULL == bg->mark_seen_cb)
314 size_t nsize; 416 return GNUNET_SYSERR;
315 417 bg->mark_seen_cb (bg,
316 nsize = compute_bloomfilter_size (seen_results_count); 418 seen_results,
317 bf = GNUNET_CONTAINER_bloomfilter_init (NULL, nsize, 419 seen_results_count);
318 GNUNET_CONSTANTS_BLOOMFILTER_K); 420 return GNUNET_OK;
319 for (i = 0; i < seen_results_count; i++)
320 {
321 GNUNET_BLOCK_mingle_hash (&seen_results[i], bf_mutator, &mhash);
322 GNUNET_CONTAINER_bloomfilter_add (bf, &mhash);
323 }
324 return bf;
325} 421}
326 422
327 423
diff --git a/src/block/plugin_block_template.c b/src/block/plugin_block_template.c
index 6cb69ef5f..0105fac38 100644
--- a/src/block/plugin_block_template.c
+++ b/src/block/plugin_block_template.c
@@ -26,20 +26,80 @@
26 26
27#include "platform.h" 27#include "platform.h"
28#include "gnunet_block_plugin.h" 28#include "gnunet_block_plugin.h"
29#include "gnunet_block_group_lib.h"
29 30
30#define DEBUG_TEMPLATE GNUNET_EXTRA_LOGGING 31#define DEBUG_TEMPLATE GNUNET_EXTRA_LOGGING
31 32
33/**
34 * Number of bits we set per entry in the bloomfilter.
35 * Do not change!
36 */
37#define BLOOMFILTER_K 16
38
39
40/**
41 * How big is the BF we use for DHT blocks?
42 */
43#define TEMPLATE_BF_SIZE 8
44
45
46/**
47 * Create a new block group.
48 *
49 * @param ctx block context in which the block group is created
50 * @param type type of the block for which we are creating the group
51 * @param nonce random value used to seed the group creation
52 * @param raw_data optional serialized prior state of the group, NULL if unavailable/fresh
53 * @param raw_data_size number of bytes in @a raw_data, 0 if unavailable/fresh
54 * @param va variable arguments specific to @a type
55 * @return block group handle, NULL if block groups are not supported
56 * by this @a type of block (this is not an error)
57 */
58static struct GNUNET_BLOCK_Group *
59block_plugin_template_create_group (void *cls,
60 enum GNUNET_BLOCK_Type type,
61 uint32_t nonce,
62 const void *raw_data,
63 size_t raw_data_size,
64 va_list va)
65{
66 unsigned int bf_size;
67 const char *guard;
68
69 guard = va_arg (va, const char *);
70 if (0 == strcmp (guard,
71 "seen-set-size"))
72 bf_size = GNUNET_BLOCK_GROUP_compute_bloomfilter_size (va_arg (va, unsigned int),
73 BLOOMFILTER_K);
74 else if (0 == strcmp (guard,
75 "filter-size"))
76 bf_size = va_arg (va, unsigned int);
77 else
78 {
79 GNUNET_break (0);
80 bf_size = TEMPLATE_BF_SIZE;
81 }
82 GNUNET_break (NULL == va_arg (va, const char *));
83 return GNUNET_BLOCK_GROUP_bf_create (cls,
84 bf_size,
85 BLOOMFILTER_K,
86 type,
87 nonce,
88 raw_data,
89 raw_data_size);
90}
91
32 92
33/** 93/**
34 * Function called to validate a reply or a request. For 94 * Function called to validate a reply or a request. For
35 * request evaluation, simply pass "NULL" for the reply_block. 95 * request evaluation, simply pass "NULL" for the reply_block.
36 * 96 *
37 * @param cls closure 97 * @param cls closure
98 * @param ctx context
38 * @param type block type 99 * @param type block type
100 * @param group block group to use
39 * @param eo control flags 101 * @param eo control flags
40 * @param query original query (hash) 102 * @param query original query (hash)
41 * @param bf pointer to bloom filter associated with query; possibly updated (!)
42 * @param bf_mutator mutation value for bf
43 * @param xquery extrended query data (can be NULL, depending on type) 103 * @param xquery extrended query data (can be NULL, depending on type)
44 * @param xquery_size number of bytes in xquery 104 * @param xquery_size number of bytes in xquery
45 * @param reply_block response to validate 105 * @param reply_block response to validate
@@ -48,37 +108,27 @@
48 */ 108 */
49static enum GNUNET_BLOCK_EvaluationResult 109static enum GNUNET_BLOCK_EvaluationResult
50block_plugin_template_evaluate (void *cls, 110block_plugin_template_evaluate (void *cls,
111 struct GNUNET_BLOCK_Context *ctx,
51 enum GNUNET_BLOCK_Type type, 112 enum GNUNET_BLOCK_Type type,
113 struct GNUNET_BLOCK_Group *group,
52 enum GNUNET_BLOCK_EvaluationOptions eo, 114 enum GNUNET_BLOCK_EvaluationOptions eo,
53 const struct GNUNET_HashCode *query, 115 const struct GNUNET_HashCode *query,
54 struct GNUNET_CONTAINER_BloomFilter **bf,
55 int32_t bf_mutator,
56 const void *xquery, 116 const void *xquery,
57 size_t xquery_size, 117 size_t xquery_size,
58 const void *reply_block, 118 const void *reply_block,
59 size_t reply_block_size) 119 size_t reply_block_size)
60{ 120{
61 struct GNUNET_HashCode chash; 121 struct GNUNET_HashCode chash;
62 struct GNUNET_HashCode mhash;
63 /* FIXME: check validity first... */
64 122
65 /* mandatory duplicate-detection code... */ 123 if (NULL == reply_block)
66 if (NULL != bf) 124 return GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
67 { 125 GNUNET_CRYPTO_hash (reply_block,
68 GNUNET_CRYPTO_hash (reply_block, reply_block_size, &chash); 126 reply_block_size,
69 GNUNET_BLOCK_mingle_hash (&chash, bf_mutator, &mhash); 127 &chash);
70 if (NULL != *bf) 128 if (GNUNET_YES ==
71 { 129 GNUNET_BLOCK_GROUP_bf_test_and_set (group,
72 if (GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test (*bf, &mhash)) 130 &chash))
73 return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE; 131 return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
74 }
75 else
76 {
77 *bf = GNUNET_CONTAINER_bloomfilter_init (NULL, 8, 64 /* BLOOMFILTER_K */);
78 }
79 GNUNET_CONTAINER_bloomfilter_add (*bf, &mhash);
80 }
81 /* FIXME: other stuff here... */
82 return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED; 132 return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED;
83} 133}
84 134
@@ -91,13 +141,15 @@ block_plugin_template_evaluate (void *cls,
91 * @param block block to get the key for 141 * @param block block to get the key for
92 * @param block_size number of bytes in block 142 * @param block_size number of bytes in block
93 * @param key set to the key (query) for the given block 143 * @param key set to the key (query) for the given block
94 * @return GNUNET_OK on success, GNUNET_SYSERR if type not supported 144 * @return #GNUNET_OK on success, #GNUNET_SYSERR if type not supported
95 * (or if extracting a key from a block of this type does not work) 145 * (or if extracting a key from a block of this type does not work)
96 */ 146 */
97static int 147static int
98block_plugin_template_get_key (void *cls, enum GNUNET_BLOCK_Type type, 148block_plugin_template_get_key (void *cls,
99 const void *block, size_t block_size, 149 enum GNUNET_BLOCK_Type type,
100 struct GNUNET_HashCode * key) 150 const void *block,
151 size_t block_size,
152 struct GNUNET_HashCode *key)
101{ 153{
102 return GNUNET_SYSERR; 154 return GNUNET_SYSERR;
103} 155}
@@ -105,6 +157,8 @@ block_plugin_template_get_key (void *cls, enum GNUNET_BLOCK_Type type,
105 157
106/** 158/**
107 * Entry point for the plugin. 159 * Entry point for the plugin.
160 *
161 * @param cls a `const struct GNUNET_CONFIGURATION_Handle`
108 */ 162 */
109void * 163void *
110libgnunet_plugin_block_template_init (void *cls) 164libgnunet_plugin_block_template_init (void *cls)
@@ -119,6 +173,7 @@ libgnunet_plugin_block_template_init (void *cls)
119 api = GNUNET_new (struct GNUNET_BLOCK_PluginFunctions); 173 api = GNUNET_new (struct GNUNET_BLOCK_PluginFunctions);
120 api->evaluate = &block_plugin_template_evaluate; 174 api->evaluate = &block_plugin_template_evaluate;
121 api->get_key = &block_plugin_template_get_key; 175 api->get_key = &block_plugin_template_get_key;
176 api->create_group = &block_plugin_template_create_group;
122 api->types = types; 177 api->types = types;
123 return api; 178 return api;
124} 179}
@@ -130,7 +185,7 @@ libgnunet_plugin_block_template_init (void *cls)
130void * 185void *
131libgnunet_plugin_block_template_done (void *cls) 186libgnunet_plugin_block_template_done (void *cls)
132{ 187{
133 struct GNUNET_TRANSPORT_PluginFunctions *api = cls; 188 struct GNUNET_BLOCK_PluginFunctions *api = cls;
134 189
135 GNUNET_free (api); 190 GNUNET_free (api);
136 return NULL; 191 return NULL;
diff --git a/src/block/plugin_block_test.c b/src/block/plugin_block_test.c
index b692d6230..e359acd7f 100644
--- a/src/block/plugin_block_test.c
+++ b/src/block/plugin_block_test.c
@@ -27,7 +27,7 @@
27 27
28#include "platform.h" 28#include "platform.h"
29#include "gnunet_block_plugin.h" 29#include "gnunet_block_plugin.h"
30 30#include "gnunet_block_group_lib.h"
31 31
32/** 32/**
33 * Number of bits we set per entry in the bloomfilter. 33 * Number of bits we set per entry in the bloomfilter.
@@ -36,15 +36,68 @@
36#define BLOOMFILTER_K 16 36#define BLOOMFILTER_K 16
37 37
38/** 38/**
39 * How big is the BF we use for DHT blocks?
40 */
41#define TEST_BF_SIZE 8
42
43
44/**
45 * Create a new block group.
46 *
47 * @param ctx block context in which the block group is created
48 * @param type type of the block for which we are creating the group
49 * @param nonce random value used to seed the group creation
50 * @param raw_data optional serialized prior state of the group, NULL if unavailable/fresh
51 * @param raw_data_size number of bytes in @a raw_data, 0 if unavailable/fresh
52 * @param va variable arguments specific to @a type
53 * @return block group handle, NULL if block groups are not supported
54 * by this @a type of block (this is not an error)
55 */
56static struct GNUNET_BLOCK_Group *
57block_plugin_test_create_group (void *cls,
58 enum GNUNET_BLOCK_Type type,
59 uint32_t nonce,
60 const void *raw_data,
61 size_t raw_data_size,
62 va_list va)
63{
64 unsigned int bf_size;
65 const char *guard;
66
67 guard = va_arg (va, const char *);
68 if (0 == strcmp (guard,
69 "seen-set-size"))
70 bf_size = GNUNET_BLOCK_GROUP_compute_bloomfilter_size (va_arg (va, unsigned int),
71 BLOOMFILTER_K);
72 else if (0 == strcmp (guard,
73 "filter-size"))
74 bf_size = va_arg (va, unsigned int);
75 else
76 {
77 GNUNET_break (0);
78 bf_size = TEST_BF_SIZE;
79 }
80 GNUNET_break (NULL == va_arg (va, const char *));
81 return GNUNET_BLOCK_GROUP_bf_create (cls,
82 bf_size,
83 BLOOMFILTER_K,
84 type,
85 nonce,
86 raw_data,
87 raw_data_size);
88}
89
90
91/**
39 * Function called to validate a reply or a request. For 92 * Function called to validate a reply or a request. For
40 * request evaluation, simply pass "NULL" for the reply_block. 93 * request evaluation, simply pass "NULL" for the reply_block.
41 * 94 *
42 * @param cls closure 95 * @param cls closure
96 * @param ctx block context
43 * @param type block type 97 * @param type block type
98 * @param group group to check against
44 * @param eo control flags 99 * @param eo control flags
45 * @param query original query (hash) 100 * @param query original query (hash)
46 * @param bf pointer to bloom filter associated with query; possibly updated (!)
47 * @param bf_mutator mutation value for @a bf
48 * @param xquery extrended query data (can be NULL, depending on type) 101 * @param xquery extrended query data (can be NULL, depending on type)
49 * @param xquery_size number of bytes in @a xquery 102 * @param xquery_size number of bytes in @a xquery
50 * @param reply_block response to validate 103 * @param reply_block response to validate
@@ -53,21 +106,23 @@
53 */ 106 */
54static enum GNUNET_BLOCK_EvaluationResult 107static enum GNUNET_BLOCK_EvaluationResult
55block_plugin_test_evaluate (void *cls, 108block_plugin_test_evaluate (void *cls,
109 struct GNUNET_BLOCK_Context *ctx,
56 enum GNUNET_BLOCK_Type type, 110 enum GNUNET_BLOCK_Type type,
111 struct GNUNET_BLOCK_Group *group,
57 enum GNUNET_BLOCK_EvaluationOptions eo, 112 enum GNUNET_BLOCK_EvaluationOptions eo,
58 const struct GNUNET_HashCode *query, 113 const struct GNUNET_HashCode *query,
59 struct GNUNET_CONTAINER_BloomFilter **bf,
60 int32_t bf_mutator,
61 const void *xquery, 114 const void *xquery,
62 size_t xquery_size, 115 size_t xquery_size,
63 const void *reply_block, 116 const void *reply_block,
64 size_t reply_block_size) 117 size_t reply_block_size)
65{ 118{
66 struct GNUNET_HashCode chash; 119 struct GNUNET_HashCode chash;
67 struct GNUNET_HashCode mhash;
68 120
69 if ( GNUNET_BLOCK_TYPE_TEST != type) 121 if ( GNUNET_BLOCK_TYPE_TEST != type)
122 {
123 GNUNET_break (0);
70 return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED; 124 return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED;
125 }
71 if (0 != xquery_size) 126 if (0 != xquery_size)
72 { 127 {
73 GNUNET_break_op (0); 128 GNUNET_break_op (0);
@@ -75,22 +130,13 @@ block_plugin_test_evaluate (void *cls,
75 } 130 }
76 if (NULL == reply_block) 131 if (NULL == reply_block)
77 return GNUNET_BLOCK_EVALUATION_REQUEST_VALID; 132 return GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
78 133 GNUNET_CRYPTO_hash (reply_block,
79 if (NULL != bf) 134 reply_block_size,
80 { 135 &chash);
81 GNUNET_CRYPTO_hash (reply_block, reply_block_size, &chash); 136 if (GNUNET_YES ==
82 GNUNET_BLOCK_mingle_hash (&chash, bf_mutator, &mhash); 137 GNUNET_BLOCK_GROUP_bf_test_and_set (group,
83 if (NULL != *bf) 138 &chash))
84 { 139 return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
85 if (GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test (*bf, &mhash))
86 return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
87 }
88 else
89 {
90 *bf = GNUNET_CONTAINER_bloomfilter_init (NULL, 8, BLOOMFILTER_K);
91 }
92 GNUNET_CONTAINER_bloomfilter_add (*bf, &mhash);
93 }
94 return GNUNET_BLOCK_EVALUATION_OK_MORE; 140 return GNUNET_BLOCK_EVALUATION_OK_MORE;
95} 141}
96 142
@@ -107,9 +153,11 @@ block_plugin_test_evaluate (void *cls,
107 * (or if extracting a key from a block of this type does not work) 153 * (or if extracting a key from a block of this type does not work)
108 */ 154 */
109static int 155static int
110block_plugin_test_get_key (void *cls, enum GNUNET_BLOCK_Type type, 156block_plugin_test_get_key (void *cls,
111 const void *block, size_t block_size, 157 enum GNUNET_BLOCK_Type type,
112 struct GNUNET_HashCode * key) 158 const void *block,
159 size_t block_size,
160 struct GNUNET_HashCode *key)
113{ 161{
114 /* always fails since there is no fixed relationship between 162 /* always fails since there is no fixed relationship between
115 * keys and values for test values */ 163 * keys and values for test values */
@@ -136,6 +184,7 @@ libgnunet_plugin_block_test_init (void *cls)
136 api = GNUNET_new (struct GNUNET_BLOCK_PluginFunctions); 184 api = GNUNET_new (struct GNUNET_BLOCK_PluginFunctions);
137 api->evaluate = &block_plugin_test_evaluate; 185 api->evaluate = &block_plugin_test_evaluate;
138 api->get_key = &block_plugin_test_get_key; 186 api->get_key = &block_plugin_test_get_key;
187 api->create_group = &block_plugin_test_create_group;
139 api->types = types; 188 api->types = types;
140 return api; 189 return api;
141} 190}
diff --git a/src/cadet/.gitignore b/src/cadet/.gitignore
index 096ee06eb..44382fde9 100644
--- a/src/cadet/.gitignore
+++ b/src/cadet/.gitignore
@@ -19,3 +19,6 @@ test_cadet_5_speed_reliable
19test_cadet_5_speed_reliable_backwards 19test_cadet_5_speed_reliable_backwards
20test_cadet_local 20test_cadet_local
21test_cadet_single 21test_cadet_single
22gnunet-service-cadet-new
23test_cadet_local_mq
24test_cadet_*_new \ No newline at end of file
diff --git a/src/cadet/Makefile.am b/src/cadet/Makefile.am
index 53d17dd9c..ce30ebe46 100644
--- a/src/cadet/Makefile.am
+++ b/src/cadet/Makefile.am
@@ -23,24 +23,24 @@ 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 libgnunetcadet.la $(EXP_LIB) 32 libgnunetcadet.la \
33 $(EXP_LIB)
34 34
35libgnunetcadet_la_SOURCES = \ 35libgnunetcadet_la_SOURCES = \
36 cadet_api.c cadet_common.c 36 cadet_api.c
37libgnunetcadet_la_LIBADD = \ 37libgnunetcadet_la_LIBADD = \
38 $(top_builddir)/src/util/libgnunetutil.la \ 38 $(top_builddir)/src/util/libgnunetutil.la \
39 $(XLIB) \ 39 $(XLIB) \
40 $(LTLIBINTL) 40 $(LTLIBINTL)
41libgnunetcadet_la_LDFLAGS = \ 41libgnunetcadet_la_LDFLAGS = \
42 $(GN_LIB_LDFLAGS) $(WINFLAGS) \ 42 $(GN_LIB_LDFLAGS) $(WINFLAGS) \
43 -version-info 5:0:0 43 -version-info 7:0:0
44 44
45gnunet_cadet_SOURCES = \ 45gnunet_cadet_SOURCES = \
46 gnunet-cadet.c 46 gnunet-cadet.c
@@ -48,46 +48,23 @@ gnunet_cadet_LDADD = \
48 libgnunetcadet.la \ 48 libgnunetcadet.la \
49 $(top_builddir)/src/util/libgnunetutil.la 49 $(top_builddir)/src/util/libgnunetutil.la
50 50
51gnunet_service_cadet_new_SOURCES = \
52 gnunet-service-cadet-new.c gnunet-service-cadet-new.h \
53 gnunet-service-cadet-new_channel.c gnunet-service-cadet-new_channel.h \
54 gnunet-service-cadet-new_connection.c gnunet-service-cadet-new_connection.h \
55 gnunet-service-cadet-new_core.c gnunet-service-cadet-new_core.h \
56 gnunet-service-cadet-new_dht.c gnunet-service-cadet-new_dht.h \
57 gnunet-service-cadet-new_hello.c gnunet-service-cadet-new_hello.h \
58 gnunet-service-cadet-new_tunnels.c gnunet-service-cadet-new_tunnels.h \
59 gnunet-service-cadet-new_paths.c gnunet-service-cadet-new_paths.h \
60 gnunet-service-cadet-new_peer.c gnunet-service-cadet-new_peer.h
61gnunet_service_cadet_new_LDADD = \
62 $(top_builddir)/src/util/libgnunetutil.la \
63 $(top_builddir)/src/ats/libgnunetats.la \
64 $(top_builddir)/src/core/libgnunetcore.la \
65 $(top_builddir)/src/dht/libgnunetdht.la \
66 $(top_builddir)/src/statistics/libgnunetstatistics.la \
67 $(top_builddir)/src/transport/libgnunettransport.la \
68 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
69 $(top_builddir)/src/hello/libgnunethello.la \
70 $(top_builddir)/src/block/libgnunetblock.la
71
72gnunet_service_cadet_SOURCES = \ 51gnunet_service_cadet_SOURCES = \
73 gnunet-service-cadet_tunnel.c gnunet-service-cadet_tunnel.h \ 52 gnunet-service-cadet.c gnunet-service-cadet.h \
74 gnunet-service-cadet_connection.c gnunet-service-cadet_connection.h \
75 gnunet-service-cadet_channel.c gnunet-service-cadet_channel.h \ 53 gnunet-service-cadet_channel.c gnunet-service-cadet_channel.h \
76 gnunet-service-cadet_local.c gnunet-service-cadet_local.h \ 54 gnunet-service-cadet_connection.c gnunet-service-cadet_connection.h \
77 gnunet-service-cadet_peer.c gnunet-service-cadet_peer.h \ 55 gnunet-service-cadet_core.c gnunet-service-cadet_core.h \
78 gnunet-service-cadet_dht.c gnunet-service-cadet_dht.h \ 56 gnunet-service-cadet_dht.c gnunet-service-cadet_dht.h \
79 gnunet-service-cadet_hello.c gnunet-service-cadet_hello.h \ 57 gnunet-service-cadet_hello.c gnunet-service-cadet_hello.h \
80 cadet_path.c cadet_path.h \ 58 gnunet-service-cadet_tunnels.c gnunet-service-cadet_tunnels.h \
81 cadet_common.c \ 59 gnunet-service-cadet_paths.c gnunet-service-cadet_paths.h \
82 gnunet-service-cadet.c 60 gnunet-service-cadet_peer.c gnunet-service-cadet_peer.h
83gnunet_service_cadet_CFLAGS = $(AM_CFLAGS)
84gnunet_service_cadet_LDADD = \ 61gnunet_service_cadet_LDADD = \
85 $(top_builddir)/src/util/libgnunetutil.la \ 62 $(top_builddir)/src/util/libgnunetutil.la \
86 $(top_builddir)/src/transport/libgnunettransport.la \
87 $(top_builddir)/src/core/libgnunetcore.la \
88 $(top_builddir)/src/ats/libgnunetats.la \ 63 $(top_builddir)/src/ats/libgnunetats.la \
64 $(top_builddir)/src/core/libgnunetcore.la \
89 $(top_builddir)/src/dht/libgnunetdht.la \ 65 $(top_builddir)/src/dht/libgnunetdht.la \
90 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 66 $(top_builddir)/src/statistics/libgnunetstatistics.la \
67 $(top_builddir)/src/transport/libgnunettransport.la \
91 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ 68 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
92 $(top_builddir)/src/hello/libgnunethello.la \ 69 $(top_builddir)/src/hello/libgnunethello.la \
93 $(top_builddir)/src/block/libgnunetblock.la 70 $(top_builddir)/src/block/libgnunetblock.la
@@ -97,26 +74,14 @@ endif
97 74
98 75
99if HAVE_TESTING 76if HAVE_TESTING
100 noinst_LIBRARIES = libgnunetcadettest.a $(noinst_LIB_EXP) 77 noinst_LTLIBRARIES = libgnunetcadettest.la $(noinst_LIB_EXP)
101 noinst_PROGRAMS = gnunet-cadet-profiler 78# noinst_PROGRAMS = gnunet-cadet-profiler
102endif 79endif
103 80
104libgnunetcadettest_a_SOURCES = \
105 cadet_test_lib.c cadet_test_lib.h
106libgnunetcadettest_a_LIBADD = \
107 $(top_builddir)/src/util/libgnunetutil.la \
108 $(top_builddir)/src/testbed/libgnunettestbed.la \
109 libgnunetcadet.la
110
111if HAVE_TESTING 81if HAVE_TESTING
112check_PROGRAMS = \ 82check_PROGRAMS = \
113 test_cadet_2_speed_reliable_backwards \ 83 test_cadet_local_mq \
114 test_cadet_5_speed \ 84 test_cadet_2_forward \
115 test_cadet_5_speed_ack \
116 test_cadet_5_speed_reliable \
117 test_cadet_5_speed_reliable_backwards \
118 test_cadet_single \
119 test_cadet_local \
120 test_cadet_2_forward \ 85 test_cadet_2_forward \
121 test_cadet_2_signal \ 86 test_cadet_2_signal \
122 test_cadet_2_keepalive \ 87 test_cadet_2_keepalive \
@@ -124,40 +89,50 @@ check_PROGRAMS = \
124 test_cadet_2_speed_ack \ 89 test_cadet_2_speed_ack \
125 test_cadet_2_speed_backwards \ 90 test_cadet_2_speed_backwards \
126 test_cadet_2_speed_reliable \ 91 test_cadet_2_speed_reliable \
92 test_cadet_2_speed_reliable_backwards \
127 test_cadet_5_forward \ 93 test_cadet_5_forward \
128 test_cadet_5_signal \ 94 test_cadet_5_signal \
129 test_cadet_5_keepalive \ 95 test_cadet_5_keepalive \
96 test_cadet_5_speed \
97 test_cadet_5_speed_ack \
98 test_cadet_5_speed_reliable \
99 test_cadet_5_speed_reliable_backwards \
130 test_cadet_5_speed_backwards 100 test_cadet_5_speed_backwards
131endif 101endif
132 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
133ld_cadet_test_lib = \ 124ld_cadet_test_lib = \
134 $(top_builddir)/src/util/libgnunetutil.la \ 125 $(top_builddir)/src/util/libgnunetutil.la \
135 $(top_builddir)/src/testing/libgnunettesting.la \ 126 $(top_builddir)/src/testing/libgnunettesting.la \
136 libgnunetcadettest.a \
137 libgnunetcadet.la \ 127 libgnunetcadet.la \
128 libgnunetcadettest.la \
138 $(top_builddir)/src/testbed/libgnunettestbed.la \ 129 $(top_builddir)/src/testbed/libgnunettestbed.la \
139 $(top_builddir)/src/statistics/libgnunetstatistics.la 130 $(top_builddir)/src/statistics/libgnunetstatistics.la
140
141dep_cadet_test_lib = \ 131dep_cadet_test_lib = \
142 libgnunetcadet.la \ 132 libgnunetcadet.la \
143 libgnunetcadettest.a \ 133 libgnunetcadettest.la \
144 $(top_builddir)/src/statistics/libgnunetstatistics.la 134 $(top_builddir)/src/statistics/libgnunetstatistics.la
145 135
146
147gnunet_cadet_profiler_SOURCES = \
148 gnunet-cadet-profiler.c
149gnunet_cadet_profiler_LDADD = $(ld_cadet_test_lib)
150
151
152test_cadet_single_SOURCES = \
153 test_cadet_single.c
154test_cadet_single_LDADD = $(ld_cadet_test_lib)
155
156test_cadet_local_SOURCES = \
157 test_cadet_local.c
158test_cadet_local_LDADD = $(ld_cadet_test_lib)
159
160
161test_cadet_2_forward_SOURCES = \ 136test_cadet_2_forward_SOURCES = \
162 test_cadet.c 137 test_cadet.c
163test_cadet_2_forward_LDADD = $(ld_cadet_test_lib) 138test_cadet_2_forward_LDADD = $(ld_cadet_test_lib)
@@ -190,7 +165,6 @@ test_cadet_2_speed_reliable_backwards_SOURCES = \
190 test_cadet.c 165 test_cadet.c
191test_cadet_2_speed_reliable_backwards_LDADD = $(ld_cadet_test_lib) 166test_cadet_2_speed_reliable_backwards_LDADD = $(ld_cadet_test_lib)
192 167
193
194test_cadet_5_forward_SOURCES = \ 168test_cadet_5_forward_SOURCES = \
195 test_cadet.c 169 test_cadet.c
196test_cadet_5_forward_LDADD = $(ld_cadet_test_lib) 170test_cadet_5_forward_LDADD = $(ld_cadet_test_lib)
@@ -225,7 +199,7 @@ test_cadet_5_speed_reliable_backwards_LDADD = $(ld_cadet_test_lib)
225 199
226 200
227if ENABLE_TEST_RUN 201if ENABLE_TEST_RUN
228AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; 202AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
229TESTS = \ 203TESTS = \
230 $(check_PROGRAMS) 204 $(check_PROGRAMS)
231endif 205endif
diff --git a/src/cadet/TODO b/src/cadet/TODO
new file mode 100644
index 000000000..06567b0ad
--- /dev/null
+++ b/src/cadet/TODO
@@ -0,0 +1,36 @@
1- URGENT:
2 + if 'client-not-ready', we do not ACK at all, and sender keeps
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!)
8
9- HIGH: revisit handling of 'unbuffered' traffic! (CHANNEL/TUNNEL)
10 (need to push down through tunnel into connection selection);
11 At Tunnel-level, try to create connections that match channel
12 preferences (buffered/unbuffered) and select connections for
13 channel traffic that match channel preferences.
14 BUT: not sure this is ideal, discloses traffic type to
15 routers. We don't want that! (Maybe revise decision to do this?)
16
17- HIGH: revisit handling of 'buffered' traffic: 4 is a rather small buffer; (CHANNEL)
18 maybe reserve more bits in 'options' to allow for buffer size control?
19 Or: maybe even better, calculated required buffer size based on latency
20 and throughput (and available memory)
21
22- HIGH: if we receive BROKEN messages, cut down corresponding PATH (up to the
23 point of breakage) as well as connection/route (CORE)
24
25- OPTIMIZATION: proper connection evaluation during connection management:
26 + TUNNELS:
27 * consider quality of current connection set when deciding
28 how often to do maintenance
29 * interact with PEER to drive DHT GET/PUT operations based
30 on how much we like our connections
31
32
33- OPTIMIZATION: optimize stopping/restarting DHT search to situations
34 where we actually need it (i.e. not if we have a direct connection,
35 or if we already have plenty of good short ones, or maybe even
36 to take a break if we have some connections and have searched a lot (?)) (PEER)
diff --git a/src/cadet/cadet.conf.in b/src/cadet/cadet.conf.in
index 48fd03329..d50e168f0 100644
--- a/src/cadet/cadet.conf.in
+++ b/src/cadet/cadet.conf.in
@@ -11,13 +11,43 @@ UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-cadet.sock
11UNIX_MATCH_UID = YES 11UNIX_MATCH_UID = YES
12UNIX_MATCH_GID = YES 12UNIX_MATCH_GID = YES
13 13
14
15# How often do we send KEEPALIVE messages on connections to keep them
16# from timing out?
14REFRESH_CONNECTION_TIME = 5 min 17REFRESH_CONNECTION_TIME = 5 min
18
19# Percentage of packets CADET is artificially dropping. Used for testing only!
20# DROP_PERCENT =
21
22# How frequently do we usually anounce our presence in the DHT?
15ID_ANNOUNCE_TIME = 1 h 23ID_ANNOUNCE_TIME = 1 h
24
25# FIXME: document
16CONNECT_TIMEOUT = 30 s 26CONNECT_TIMEOUT = 30 s
27
28# What is the replication level we give to the DHT when announcing our
29# existence? Usually there is no need to change this.
17DHT_REPLICATION_LEVEL = 3 30DHT_REPLICATION_LEVEL = 3
18MAX_TUNNELS = 1000 31
32# FIXME: not implemented
33# MAX_TUNNELS = 1000
34
35# FIXME: not implemented, replaced by MAX_ROUTES in NEW CADET!
19MAX_CONNECTIONS = 1000 36MAX_CONNECTIONS = 1000
37
38# How many routes do we participate in at most? Should be smaller
39# than MAX_MSGS_QUEUE
40MAX_ROUTES = 5000
41
42# FIXME: not implemented
20MAX_MSGS_QUEUE = 10000 43MAX_MSGS_QUEUE = 10000
44
45# FIXME: not implemented
21MAX_PEERS = 1000 46MAX_PEERS = 1000
47
48# How often do we advance the ratchet even if there is not
49# any traffic?
22RATCHET_TIME = 1 h 50RATCHET_TIME = 1 h
51
52# How often do we advance the ratched if there is traffic?
23RATCHET_MESSAGES = 64 53RATCHET_MESSAGES = 64
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 72b7b692d..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,55 +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 */ 37 */
42struct GNUNET_CADET_TransmitHandle
43{
44 /**
45 * Double Linked list
46 */
47 struct GNUNET_CADET_TransmitHandle *next;
48
49 /**
50 * Double Linked list
51 */
52 struct GNUNET_CADET_TransmitHandle *prev;
53
54 /**
55 * Channel this message is sent on / for (may be NULL for control messages).
56 */
57 struct GNUNET_CADET_Channel *channel;
58
59 /**
60 * Request data task.
61 */
62 struct GNUNET_SCHEDULER_Task *request_data_task;
63
64 /**
65 * Callback to obtain the message to transmit, or NULL if we
66 * got the message in 'data'. Notice that messages built
67 * by 'notify' need to be encapsulated with information about
68 * the 'target'.
69 */
70 GNUNET_CONNECTION_TransmitReadyNotify notify;
71
72 /**
73 * Closure for 'notify'
74 */
75 void *notify_cls;
76
77 /**
78 * Size of the payload.
79 */
80 size_t size;
81};
82
83
84union CadetInfoCB 38union CadetInfoCB
85{ 39{
86 40
@@ -117,54 +71,19 @@ union CadetInfoCB
117struct GNUNET_CADET_Handle 71struct GNUNET_CADET_Handle
118{ 72{
119 /** 73 /**
120 * Message queue (if available). 74 * Message queue.
121 */ 75 */
122 struct GNUNET_MQ_Handle *mq; 76 struct GNUNET_MQ_Handle *mq;
123 77
124 /** 78 /**
125 * Set of handlers used for processing incoming messages in the channels
126 */
127 const struct GNUNET_CADET_MessageHandler *message_handlers;
128
129 /**
130 * Number of handlers in the handlers array.
131 */
132 unsigned int n_handlers;
133
134 /**
135 * Ports open. 79 * Ports open.
136 */ 80 */
137 struct GNUNET_CONTAINER_MultiHashMap *ports; 81 struct GNUNET_CONTAINER_MultiHashMap *ports;
138 82
139 /** 83 /**
140 * Double linked list of the channels this client is connected to, head. 84 * Channels open.
141 */
142 struct GNUNET_CADET_Channel *channels_head;
143
144 /**
145 * Double linked list of the channels this client is connected to, tail.
146 */ 85 */
147 struct GNUNET_CADET_Channel *channels_tail; 86 struct GNUNET_CONTAINER_MultiHashMap32 *channels;
148
149 /**
150 * Callback for inbound channel disconnection
151 */
152 GNUNET_CADET_ChannelEndHandler *cleaner;
153
154 /**
155 * Closure for all the handlers given by the client
156 */
157 void *cls;
158
159 /**
160 * Messages to send to the service, head.
161 */
162 struct GNUNET_CADET_TransmitHandle *th_head;
163
164 /**
165 * Messages to send to the service, tail.
166 */
167 struct GNUNET_CADET_TransmitHandle *th_tail;
168 87
169 /** 88 /**
170 * 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)
@@ -177,14 +96,9 @@ struct GNUNET_CADET_Handle
177 const struct GNUNET_CONFIGURATION_Handle *cfg; 96 const struct GNUNET_CONFIGURATION_Handle *cfg;
178 97
179 /** 98 /**
180 * Time to the next reconnect in case one reconnect fails
181 */
182 struct GNUNET_TIME_Relative reconnect_time;
183
184 /**
185 * Task for trying to reconnect. 99 * Task for trying to reconnect.
186 */ 100 */
187 struct GNUNET_SCHEDULER_Task * reconnect_task; 101 struct GNUNET_SCHEDULER_Task *reconnect_task;
188 102
189 /** 103 /**
190 * Callback for an info task (only one active at a time). 104 * Callback for an info task (only one active at a time).
@@ -195,65 +109,73 @@ struct GNUNET_CADET_Handle
195 * Info callback closure for @c info_cb. 109 * Info callback closure for @c info_cb.
196 */ 110 */
197 void *info_cls; 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
198}; 118};
199 119
200 120
201/** 121/**
202 * Description of a peer 122 * Opaque handle to a channel.
203 */ 123 */
204struct GNUNET_CADET_Peer 124struct GNUNET_CADET_Channel
205{ 125{
126
206 /** 127 /**
207 * ID of the peer in short form 128 * Other end of the channel.
208 */ 129 */
209 GNUNET_PEER_Id id; 130 struct GNUNET_PeerIdentity peer;
210 131
211 /** 132 /**
212 * Channel this peer belongs to 133 * Handle to the cadet this channel belongs to
213 */ 134 */
214 struct GNUNET_CADET_Channel *t; 135 struct GNUNET_CADET_Handle *cadet;
215};
216 136
137 /**
138 * Channel's port, if incoming.
139 */
140 struct GNUNET_CADET_Port *incoming_port;
217 141
218/**
219 * Opaque handle to a channel.
220 */
221struct GNUNET_CADET_Channel
222{
223 /** 142 /**
224 * DLL next 143 * Any data the caller wants to put in here, used for the
144 * various callbacks (@e disconnects, @e window_changes, handlers).
225 */ 145 */
226 struct GNUNET_CADET_Channel *next; 146 void *ctx;
227 147
228 /** 148 /**
229 * DLL prev 149 * Message Queue for the channel (which we are implementing).
230 */ 150 */
231 struct GNUNET_CADET_Channel *prev; 151 struct GNUNET_MQ_Handle *mq;
232 152
233 /** 153 /**
234 * Handle to the cadet this channel belongs to 154 * Task to allow mq to send more traffic.
235 */ 155 */
236 struct GNUNET_CADET_Handle *cadet; 156 struct GNUNET_SCHEDULER_Task *mq_cont;
237 157
238 /** 158 /**
239 * Local ID of the channel 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.
240 */ 162 */
241 struct GNUNET_CADET_ClientChannelNumber ccn; 163 struct GNUNET_MQ_Envelope *pending_env;
242 164
243 /** 165 /**
244 * Channel's port, if any. 166 * Window change handler.
245 */ 167 */
246 struct GNUNET_CADET_Port *port; 168 GNUNET_CADET_WindowSizeEventHandler window_changes;
247 169
248 /** 170 /**
249 * Other end of the channel. 171 * Disconnect handler.
250 */ 172 */
251 GNUNET_PEER_Id peer; 173 GNUNET_CADET_DisconnectEventHandler disconnects;
252 174
253 /** 175 /**
254 * Any data the caller wants to put in here 176 * Local ID of the channel, #GNUNET_CADET_LOCAL_CHANNEL_ID_CLI bit is set if outbound.
255 */ 177 */
256 void *ctx; 178 struct GNUNET_CADET_ClientChannelNumber ccn;
257 179
258 /** 180 /**
259 * Channel options: reliability, etc. 181 * Channel options: reliability, etc.
@@ -261,7 +183,7 @@ struct GNUNET_CADET_Channel
261 enum GNUNET_CADET_ChannelOption options; 183 enum GNUNET_CADET_ChannelOption options;
262 184
263 /** 185 /**
264 * Are we allowed to send to the service? 186 * How many messages are we allowed to send to the service right now?
265 */ 187 */
266 unsigned int allow_send; 188 unsigned int allow_send;
267 189
@@ -273,82 +195,62 @@ struct GNUNET_CADET_Channel
273 */ 195 */
274struct GNUNET_CADET_Port 196struct GNUNET_CADET_Port
275{ 197{
198
199 /**
200 * Port "number"
201 */
202 struct GNUNET_HashCode id;
203
276 /** 204 /**
277 * Handle to the CADET session this port belongs to. 205 * Handle to the CADET session this port belongs to.
278 */ 206 */
279 struct GNUNET_CADET_Handle *cadet; 207 struct GNUNET_CADET_Handle *cadet;
280 208
281 /** 209 /**
282 * Port ID. 210 * Closure for @a handler.
283 */ 211 */
284 struct GNUNET_HashCode *hash; 212 void *cls;
285 213
286 /** 214 /**
287 * Callback handler for incoming channels on this port. 215 * Handler for incoming channels on this port
288 */ 216 */
289 GNUNET_CADET_InboundChannelNotificationHandler *handler; 217 GNUNET_CADET_ConnectEventHandler connects;
290 218
291 /** 219 /**
292 * Closure for @a handler. 220 * Closure for @ref connects
293 */ 221 */
294 void *cls; 222 void *connects_cls;
295};
296 223
224 /**
225 * Window size change handler.
226 */
227 GNUNET_CADET_WindowSizeEventHandler window_changes;
297 228
298/**
299 * Implementation state for cadet's message queue.
300 */
301struct CadetMQState
302{
303 /** 229 /**
304 * The current transmit handle, or NULL 230 * Handler called when an incoming channel is destroyed.
305 * if no transmit is active.
306 */ 231 */
307 struct GNUNET_CADET_TransmitHandle *th; 232 GNUNET_CADET_DisconnectEventHandler disconnects;
308 233
309 /** 234 /**
310 * Channel to send the data over. 235 * Payload handlers for incoming channels.
311 */ 236 */
312 struct GNUNET_CADET_Channel *channel; 237 struct GNUNET_MQ_MessageHandler *handlers;
313}; 238};
314 239
315 240
316/******************************************************************************/
317/*********************** AUXILIARY FUNCTIONS *************************/
318/******************************************************************************/
319
320/**
321 * Check if transmission is a payload packet.
322 *
323 * @param th Transmission handle.
324 *
325 * @return #GNUNET_YES if it is a payload packet,
326 * #GNUNET_NO if it is a cadet management packet.
327 */
328static int
329th_is_payload (struct GNUNET_CADET_TransmitHandle *th)
330{
331 return (th->notify != NULL) ? GNUNET_YES : GNUNET_NO;
332}
333
334
335/** 241/**
336 * Find the Port struct for a hash. 242 * Find the Port struct for a hash.
337 * 243 *
338 * @param h CADET handle. 244 * @param h CADET handle.
339 * @param hash HashCode for the port number. 245 * @param hash HashCode for the port number.
340 *
341 * @return The port handle if known, NULL otherwise. 246 * @return The port handle if known, NULL otherwise.
342 */ 247 */
343static struct GNUNET_CADET_Port * 248static struct GNUNET_CADET_Port *
344find_port (const struct GNUNET_CADET_Handle *h, 249find_port (const struct GNUNET_CADET_Handle *h,
345 const struct GNUNET_HashCode *hash) 250 const struct GNUNET_HashCode *hash)
346{ 251{
347 struct GNUNET_CADET_Port *p; 252 return GNUNET_CONTAINER_multihashmap_get (h->ports,
348 253 hash);
349 p = GNUNET_CONTAINER_multihashmap_get (h->ports, hash);
350
351 return p;
352} 254}
353 255
354 256
@@ -360,15 +262,11 @@ find_port (const struct GNUNET_CADET_Handle *h,
360 * @return handle to the required channel or NULL if not found 262 * @return handle to the required channel or NULL if not found
361 */ 263 */
362static struct GNUNET_CADET_Channel * 264static struct GNUNET_CADET_Channel *
363retrieve_channel (struct GNUNET_CADET_Handle *h, 265find_channel (struct GNUNET_CADET_Handle *h,
364 struct GNUNET_CADET_ClientChannelNumber ccn) 266 struct GNUNET_CADET_ClientChannelNumber ccn)
365{ 267{
366 struct GNUNET_CADET_Channel *ch; 268 return GNUNET_CONTAINER_multihashmap32_get (h->channels,
367 269 ntohl (ccn.channel_of_client));
368 for (ch = h->channels_head; NULL != ch; ch = ch->next)
369 if (ch->ccn.channel_of_client == ccn.channel_of_client)
370 return ch;
371 return NULL;
372} 270}
373 271
374 272
@@ -376,38 +274,37 @@ retrieve_channel (struct GNUNET_CADET_Handle *h,
376 * 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
377 * 275 *
378 * @param h Cadet handle 276 * @param h Cadet handle
379 * @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.
380 *
381 * @return Handle to the created channel. 278 * @return Handle to the created channel.
382 */ 279 */
383static struct GNUNET_CADET_Channel * 280static struct GNUNET_CADET_Channel *
384create_channel (struct GNUNET_CADET_Handle *h, 281create_channel (struct GNUNET_CADET_Handle *h,
385 struct GNUNET_CADET_ClientChannelNumber ccn) 282 const struct GNUNET_CADET_ClientChannelNumber *ccnp)
386{ 283{
387 struct GNUNET_CADET_Channel *ch; 284 struct GNUNET_CADET_Channel *ch;
285 struct GNUNET_CADET_ClientChannelNumber ccn;
388 286
389 ch = GNUNET_new (struct GNUNET_CADET_Channel); 287 ch = GNUNET_new (struct GNUNET_CADET_Channel);
390 GNUNET_CONTAINER_DLL_insert (h->channels_head,
391 h->channels_tail,
392 ch);
393 ch->cadet = h; 288 ch->cadet = h;
394 if (0 == ccn.channel_of_client) 289 if (NULL == ccnp)
395 { 290 {
396 ch->ccn = h->next_ccn; 291 while (NULL !=
397 while (NULL != retrieve_channel (h, 292 find_channel (h,
398 h->next_ccn)) 293 h->next_ccn))
399 {
400 h->next_ccn.channel_of_client 294 h->next_ccn.channel_of_client
401 = 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)));
402 if (0 == ntohl (h->next_ccn.channel_of_client)) 296 ccn = h->next_ccn;
403 h->next_ccn.channel_of_client
404 = htonl (GNUNET_CADET_LOCAL_CHANNEL_ID_CLI);
405 }
406 } 297 }
407 else 298 else
408 { 299 {
409 ch->ccn = ccn; 300 ccn = *ccnp;
410 } 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));
411 return ch; 308 return ch;
412} 309}
413 310
@@ -421,145 +318,273 @@ create_channel (struct GNUNET_CADET_Handle *h,
421 * 318 *
422 * @param ch Pointer to the channel. 319 * @param ch Pointer to the channel.
423 * @param call_cleaner Whether to call the cleaner handler. 320 * @param call_cleaner Whether to call the cleaner handler.
321 */
322static void
323destroy_channel (struct GNUNET_CADET_Channel *ch)
324{
325 struct GNUNET_CADET_Handle *h = ch->cadet;
326
327 LOG (GNUNET_ERROR_TYPE_DEBUG,
328 "Destroying channel %X of %p\n",
329 ch->ccn,
330 h);
331 GNUNET_assert (GNUNET_YES ==
332 GNUNET_CONTAINER_multihashmap32_remove (h->channels,
333 ntohl (ch->ccn.channel_of_client),
334 ch));
335 if (NULL != ch->mq_cont)
336 {
337 GNUNET_SCHEDULER_cancel (ch->mq_cont);
338 ch->mq_cont = NULL;
339 }
340 /* signal channel destruction */
341 if (NULL != ch->disconnects)
342 ch->disconnects (ch->ctx,
343 ch);
344 if (NULL != ch->pending_env)
345 GNUNET_MQ_discard (ch->pending_env);
346 GNUNET_MQ_destroy (ch->mq);
347 GNUNET_free (ch);
348}
349
350
351/**
352 * Reconnect to the service, retransmit all infomation to try to restore the
353 * original state.
424 * 354 *
425 * @return Handle to the required channel or NULL if not found. 355 * @param h handle to the cadet
426 */ 356 */
427// FIXME: simplify: call_cleaner is always #GNUNET_YES!!!
428static void 357static void
429destroy_channel (struct GNUNET_CADET_Channel *ch, 358reconnect (struct GNUNET_CADET_Handle *h);
430 int call_cleaner) 359
360
361/**
362 * Reconnect callback: tries to reconnect again after a failer previous
363 * reconnecttion
364 *
365 * @param cls closure (cadet handle)
366 */
367static void
368reconnect_cbk (void *cls)
431{ 369{
432 struct GNUNET_CADET_Handle *h; 370 struct GNUNET_CADET_Handle *h = cls;
433 struct GNUNET_CADET_TransmitHandle *th;
434 struct GNUNET_CADET_TransmitHandle *next;
435 371
436 if (NULL == ch) 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)
390{
391 /* struct GNUNET_CADET_Handle *handle = cls; */
392 struct GNUNET_CADET_Channel *ch = value;
393
394 destroy_channel (ch);
395 return GNUNET_OK;
396}
397
398
399/**
400 * Reconnect to the service, retransmit all infomation to try to restore the
401 * original state.
402 *
403 * @param h handle to the cadet
404 *
405 * @return #GNUNET_YES in case of sucess, #GNUNET_NO otherwise (service down...)
406 */
407static void
408schedule_reconnect (struct GNUNET_CADET_Handle *h)
409{
410 if (NULL != h->reconnect_task)
411 return;
412 GNUNET_CONTAINER_multihashmap32_iterate (h->channels,
413 &destroy_channel_on_reconnect_cb,
414 h);
415 h->reconnect_task
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);
421}
422
423
424/**
425 * Notify the application about a change in the window size (if needed).
426 *
427 * @param ch Channel to notify about.
428 */
429static void
430notify_window_size (struct GNUNET_CADET_Channel *ch)
431{
432 if (NULL != ch->window_changes)
433 ch->window_changes (ch->ctx,
434 ch, /* FIXME: remove 'ch'? */
435 ch->allow_send);
436}
437
438
439/**
440 * Transmit the next message from our queue.
441 *
442 * @param cls Closure (channel whose mq to activate).
443 */
444static void
445cadet_mq_send_now (void *cls)
446{
447 struct GNUNET_CADET_Channel *ch = cls;
448 struct GNUNET_MQ_Envelope *env = ch->pending_env;
449
450 ch->mq_cont = NULL;
451 if (0 == ch->allow_send)
437 { 452 {
453 /* how did we get here? */
438 GNUNET_break (0); 454 GNUNET_break (0);
439 return; 455 return;
440 } 456 }
441 h = ch->cadet; 457 if (NULL == env)
442 LOG (GNUNET_ERROR_TYPE_DEBUG, 458 {
443 " destroy_channel %X of %p\n", 459 /* how did we get here? */
444 ch->ccn, 460 GNUNET_break (0);
445 h); 461 return;
462 }
463 ch->allow_send--;
464 ch->pending_env = NULL;
465 GNUNET_MQ_send (ch->cadet->mq,
466 env);
467 GNUNET_MQ_impl_send_continue (ch->mq);
468}
446 469
447 GNUNET_CONTAINER_DLL_remove (h->channels_head,
448 h->channels_tail,
449 ch);
450 470
451 /* signal channel destruction */ 471/**
452 if ( (NULL != h->cleaner) && 472 * Implement sending functionality of a message queue for
453 (0 != ch->peer) && 473 * us sending messages to a peer.
454 (GNUNET_YES == call_cleaner) ) 474 *
475 * Encapsulates the payload message in a #GNUNET_CADET_LocalData message
476 * in order to label the message with the channel ID and send the
477 * encapsulated message to the service.
478 *
479 * @param mq the message queue
480 * @param msg the message to send
481 * @param impl_state state of the implementation
482 */
483static void
484cadet_mq_send_impl (struct GNUNET_MQ_Handle *mq,
485 const struct GNUNET_MessageHeader *msg,
486 void *impl_state)
487{
488 struct GNUNET_CADET_Channel *ch = impl_state;
489 struct GNUNET_CADET_Handle *h = ch->cadet;
490 uint16_t msize;
491 struct GNUNET_MQ_Envelope *env;
492 struct GNUNET_CADET_LocalData *cadet_msg;
493
494 if (NULL == h->mq)
455 { 495 {
456 LOG (GNUNET_ERROR_TYPE_DEBUG, 496 /* We're currently reconnecting, pretend this worked */
457 " calling cleaner\n"); 497 GNUNET_MQ_impl_send_continue (mq);
458 h->cleaner (h->cls, ch, ch->ctx); 498 return;
459 } 499 }
460 500
461 /* check that clients did not leave messages behind in the queue */ 501 /* check message size for sanity */
462 for (th = h->th_head; NULL != th; th = next) 502 msize = ntohs (msg->size);
503 if (msize > GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE)
463 { 504 {
464 next = th->next; 505 GNUNET_break (0);
465 if (th->channel != ch) 506 GNUNET_MQ_impl_send_continue (mq);
466 continue; 507 return;
467 /* Clients should have aborted their requests already.
468 * Management traffic should be ok, as clients can't cancel that.
469 * If the service crashed and we are reconnecting, it's ok.
470 */
471 GNUNET_break (GNUNET_NO == th_is_payload (th));
472 GNUNET_CADET_notify_transmit_ready_cancel (th);
473 } 508 }
474 509 env = GNUNET_MQ_msg_nested_mh (cadet_msg,
475 if (0 != ch->peer) 510 GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA,
476 GNUNET_PEER_change_rc (ch->peer, -1); 511 msg);
477 GNUNET_free (ch); 512 cadet_msg->ccn = ch->ccn;
513 GNUNET_assert (NULL == ch->pending_env);
514 ch->pending_env = env;
515 if (0 < ch->allow_send)
516 ch->mq_cont
517 = GNUNET_SCHEDULER_add_now (&cadet_mq_send_now,
518 ch);
478} 519}
479 520
480 521
481/** 522/**
482 * Add a transmit handle to the transmission queue and set the 523 * Handle destruction of a message queue. Implementations must not
483 * timeout if needed. 524 * free @a mq, but should take care of @a impl_state.
484 * 525 *
485 * @param h cadet handle with the queue head and tail 526 * @param mq the message queue to destroy
486 * @param th handle to the packet to be transmitted 527 * @param impl_state state of the implementation
487 */ 528 */
488static void 529static void
489add_to_queue (struct GNUNET_CADET_Handle *h, 530cadet_mq_destroy_impl (struct GNUNET_MQ_Handle *mq,
490 struct GNUNET_CADET_TransmitHandle *th) 531 void *impl_state)
491{ 532{
492 GNUNET_CONTAINER_DLL_insert_tail (h->th_head, 533 struct GNUNET_CADET_Channel *ch = impl_state;
493 h->th_tail, 534
494 th); 535 GNUNET_assert (mq == ch->mq);
536 ch->mq = NULL;
495} 537}
496 538
497 539
498/** 540/**
499 * Remove a transmit handle from the transmission queue, if present. 541 * We had an error processing a message we forwarded from a peer to
500 * 542 * the CADET service. We should just complain about it but otherwise
501 * Safe to call even if not queued. 543 * continue processing.
502 * 544 *
503 * @param th handle to the packet to be unqueued. 545 * @param cls closure with our `struct GNUNET_CADET_Channel`
546 * @param error error code
504 */ 547 */
505static void 548static void
506remove_from_queue (struct GNUNET_CADET_TransmitHandle *th) 549cadet_mq_error_handler (void *cls,
550 enum GNUNET_MQ_Error error)
507{ 551{
508 struct GNUNET_CADET_Handle *h = th->channel->cadet; 552 struct GNUNET_CADET_Channel *ch = cls;
509 553
510 /* It might or might not have been queued (rarely not), but check anyway. */ 554 GNUNET_break (0);
511 if (NULL != th->next || h->th_tail == th) 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
512 { 561 {
513 GNUNET_CONTAINER_DLL_remove (h->th_head, h->th_tail, th); 562 schedule_reconnect (ch->cadet);
514 } 563 }
515} 564}
516 565
517 566
518
519/******************************************************************************/
520/*********************** RECEIVE HANDLERS ****************************/
521/******************************************************************************/
522
523
524/** 567/**
525 * Call the @a notify callback given to #GNUNET_CADET_notify_transmit_ready to 568 * Implementation function that cancels the currently sent message.
526 * request the data to send over MQ. Since MQ manages the queue, this function 569 * Should basically undo whatever #mq_send_impl() did.
527 * is scheduled immediatly after a transmit ready notification.
528 * 570 *
529 * @param cls Closure (transmit handle). 571 * @param mq message queue
572 * @param impl_state state specific to the implementation
530 */ 573 */
531static void 574static void
532request_data (void *cls) 575cadet_mq_cancel_impl (struct GNUNET_MQ_Handle *mq,
576 void *impl_state)
533{ 577{
534 struct GNUNET_CADET_TransmitHandle *th = cls; 578 struct GNUNET_CADET_Channel *ch = impl_state;
535 struct GNUNET_CADET_LocalData *msg;
536 struct GNUNET_MQ_Envelope *env;
537 size_t osize;
538 579
539 LOG (GNUNET_ERROR_TYPE_DEBUG, 580 GNUNET_assert (NULL != ch->pending_env);
540 "Requesting Data: %u bytes (allow send is %u)\n", 581 GNUNET_MQ_discard (ch->pending_env);
541 th->size, 582 ch->pending_env = NULL;
542 th->channel->allow_send); 583 if (NULL != ch->mq_cont)
543 584 {
544 GNUNET_assert (0 < th->channel->allow_send); 585 GNUNET_SCHEDULER_cancel (ch->mq_cont);
545 th->channel->allow_send--; 586 ch->mq_cont = NULL;
546 /* NOTE: we may be allowed to send another packet immediately, 587 }
547 albeit the current logic waits for the ACK. */
548 th->request_data_task = NULL;
549 remove_from_queue (th);
550
551 env = GNUNET_MQ_msg_extra (msg,
552 th->size,
553 GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA);
554 msg->ccn = th->channel->ccn;
555 osize = th->notify (th->notify_cls,
556 th->size,
557 &msg[1]);
558 GNUNET_assert (osize == th->size);
559
560 GNUNET_MQ_send (th->channel->cadet->mq,
561 env);
562 GNUNET_free (th);
563} 588}
564 589
565 590
@@ -586,18 +611,20 @@ handle_channel_created (void *cls,
586 GNUNET_break (0); 611 GNUNET_break (0);
587 return; 612 return;
588 } 613 }
589 port = find_port (h, port_number); 614 port = find_port (h,
615 port_number);
590 if (NULL == port) 616 if (NULL == port)
591 { 617 {
618 /* We could have closed the port but the service didn't know about it yet
619 * This is not an error.
620 */
592 struct GNUNET_CADET_LocalChannelDestroyMessage *d_msg; 621 struct GNUNET_CADET_LocalChannelDestroyMessage *d_msg;
593 struct GNUNET_MQ_Envelope *env; 622 struct GNUNET_MQ_Envelope *env;
594 623
595 GNUNET_break (0);
596 LOG (GNUNET_ERROR_TYPE_DEBUG, 624 LOG (GNUNET_ERROR_TYPE_DEBUG,
597 "No handler for incoming channel %X [%s]\n", 625 "No handler for incoming channel %X (on port %s, recently closed?)\n",
598 ntohl (ccn.channel_of_client), 626 ntohl (ccn.channel_of_client),
599 GNUNET_h2s (port_number)); 627 GNUNET_h2s (port_number));
600 /* FIXME: should disconnect instead, this is a serious error! */
601 env = GNUNET_MQ_msg (d_msg, 628 env = GNUNET_MQ_msg (d_msg,
602 GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY); 629 GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY);
603 d_msg->ccn = msg->ccn; 630 d_msg->ccn = msg->ccn;
@@ -607,23 +634,32 @@ handle_channel_created (void *cls,
607 } 634 }
608 635
609 ch = create_channel (h, 636 ch = create_channel (h,
610 ccn); 637 &ccn);
611 ch->peer = GNUNET_PEER_intern (&msg->peer); 638 ch->peer = msg->peer;
612 ch->cadet = h; 639 ch->cadet = h;
613 ch->ccn = ccn; 640 ch->incoming_port = port;
614 ch->port = port;
615 ch->options = ntohl (msg->opt); 641 ch->options = ntohl (msg->opt);
616
617 LOG (GNUNET_ERROR_TYPE_DEBUG, 642 LOG (GNUNET_ERROR_TYPE_DEBUG,
618 "Creating incoming channel %X [%s] %p\n", 643 "Creating incoming channel %X [%s] %p\n",
619 ntohl (ccn.channel_of_client), 644 ntohl (ccn.channel_of_client),
620 GNUNET_h2s (port_number), 645 GNUNET_h2s (port_number),
621 ch); 646 ch);
622 ch->ctx = port->handler (port->cls, 647
623 ch, 648 GNUNET_assert (NULL != port->connects);
624 &msg->peer, 649 ch->window_changes = port->window_changes;
625 port->hash, 650 ch->disconnects = port->disconnects;
626 ch->options); 651 ch->mq = GNUNET_MQ_queue_for_callbacks (&cadet_mq_send_impl,
652 &cadet_mq_destroy_impl,
653 &cadet_mq_cancel_impl,
654 ch,
655 port->handlers,
656 &cadet_mq_error_handler,
657 ch);
658 ch->ctx = port->connects (port->cls,
659 ch,
660 &msg->peer);
661 GNUNET_MQ_set_handlers_closure (ch->mq,
662 ch->ctx);
627} 663}
628 664
629 665
@@ -639,24 +675,20 @@ handle_channel_destroy (void *cls,
639{ 675{
640 struct GNUNET_CADET_Handle *h = cls; 676 struct GNUNET_CADET_Handle *h = cls;
641 struct GNUNET_CADET_Channel *ch; 677 struct GNUNET_CADET_Channel *ch;
642 struct GNUNET_CADET_ClientChannelNumber ccn;
643
644 ccn = msg->ccn;
645 LOG (GNUNET_ERROR_TYPE_DEBUG,
646 "Channel %X Destroy from service\n",
647 ntohl (ccn.channel_of_client));
648 ch = retrieve_channel (h,
649 ccn);
650 678
679 ch = find_channel (h,
680 msg->ccn);
651 if (NULL == ch) 681 if (NULL == ch)
652 { 682 {
653 LOG (GNUNET_ERROR_TYPE_DEBUG, 683 LOG (GNUNET_ERROR_TYPE_DEBUG,
654 "channel %X unknown\n", 684 "Received channel destroy for unknown channel %X from CADET service (recently close?)\n",
655 ntohl (ccn.channel_of_client)); 685 ntohl (msg->ccn.channel_of_client));
656 return; 686 return;
657 } 687 }
658 destroy_channel (ch, 688 LOG (GNUNET_ERROR_TYPE_DEBUG,
659 GNUNET_YES); 689 "Received channel destroy for channel %X from CADET service\n",
690 ntohl (msg->ccn.channel_of_client));
691 destroy_channel (ch);
660} 692}
661 693
662 694
@@ -672,25 +704,14 @@ static int
672check_local_data (void *cls, 704check_local_data (void *cls,
673 const struct GNUNET_CADET_LocalData *message) 705 const struct GNUNET_CADET_LocalData *message)
674{ 706{
675 struct GNUNET_CADET_Handle *h = cls;
676 struct GNUNET_CADET_Channel *ch;
677 uint16_t size; 707 uint16_t size;
678 708
679 size = ntohs (message->header.size); 709 size = ntohs (message->header.size);
680 if (sizeof (*message) + sizeof (struct GNUNET_MessageHeader) > size) 710 if (sizeof (*message) + sizeof (struct GNUNET_MessageHeader) > size)
681 { 711 {
682 GNUNET_break_op (0); 712 GNUNET_break (0);
683 return GNUNET_SYSERR;
684 }
685
686 ch = retrieve_channel (h,
687 message->ccn);
688 if (NULL == ch)
689 {
690 GNUNET_break_op (0);
691 return GNUNET_SYSERR; 713 return GNUNET_SYSERR;
692 } 714 }
693
694 return GNUNET_OK; 715 return GNUNET_OK;
695} 716}
696 717
@@ -707,46 +728,31 @@ handle_local_data (void *cls,
707{ 728{
708 struct GNUNET_CADET_Handle *h = cls; 729 struct GNUNET_CADET_Handle *h = cls;
709 const struct GNUNET_MessageHeader *payload; 730 const struct GNUNET_MessageHeader *payload;
710 const struct GNUNET_CADET_MessageHandler *handler;
711 struct GNUNET_CADET_Channel *ch; 731 struct GNUNET_CADET_Channel *ch;
712 uint16_t type; 732 uint16_t type;
733 int fwd;
713 734
714 ch = retrieve_channel (h, 735 ch = find_channel (h,
715 message->ccn); 736 message->ccn);
716 GNUNET_assert (NULL != ch); 737 if (NULL == ch)
738 {
739 LOG (GNUNET_ERROR_TYPE_DEBUG,
740 "Unknown channel %X for incoming data (recently closed?)\n",
741 ntohl (message->ccn.channel_of_client));
742 return;
743 }
717 744
718 payload = (struct GNUNET_MessageHeader *) &message[1]; 745 payload = (const struct GNUNET_MessageHeader *) &message[1];
719 type = ntohs (payload->type); 746 type = ntohs (payload->type);
747 fwd = ntohl (ch->ccn.channel_of_client) <= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI;
720 LOG (GNUNET_ERROR_TYPE_DEBUG, 748 LOG (GNUNET_ERROR_TYPE_DEBUG,
721 "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",
722 GC_f2s (ntohl (ch->ccn.channel_of_client) >= 750 fwd ? "FWD" : "BWD",
723 GNUNET_CADET_LOCAL_CHANNEL_ID_CLI), 751 GNUNET_i2s (&ch->peer),
724 GNUNET_i2s (GNUNET_PEER_resolve2 (ch->peer)),
725 ntohl (message->ccn.channel_of_client), 752 ntohl (message->ccn.channel_of_client),
726 GC_m2s (type),
727 type); 753 type);
728 for (unsigned i=0;i<h->n_handlers;i++) 754 GNUNET_MQ_inject_message (ch->mq,
729 { 755 payload);
730 handler = &h->message_handlers[i];
731 if (handler->type == type)
732 {
733 if (GNUNET_OK !=
734 handler->callback (h->cls,
735 ch,
736 &ch->ctx,
737 payload))
738 {
739 LOG (GNUNET_ERROR_TYPE_DEBUG,
740 "callback caused disconnection\n");
741 GNUNET_CADET_channel_destroy (ch);
742 return;
743 }
744 return;
745 }
746 }
747 /* Other peer sent message we do not comprehend. */
748 GNUNET_break_op (0);
749 GNUNET_CADET_receive_done (ch);
750} 756}
751 757
752 758
@@ -763,57 +769,36 @@ handle_local_ack (void *cls,
763{ 769{
764 struct GNUNET_CADET_Handle *h = cls; 770 struct GNUNET_CADET_Handle *h = cls;
765 struct GNUNET_CADET_Channel *ch; 771 struct GNUNET_CADET_Channel *ch;
766 struct GNUNET_CADET_ClientChannelNumber ccn;
767 struct GNUNET_CADET_TransmitHandle *th;
768 772
769 ccn = message->ccn; 773 ch = find_channel (h,
770 ch = retrieve_channel (h, ccn); 774 message->ccn);
771 if (NULL == ch) 775 if (NULL == ch)
772 { 776 {
773 LOG (GNUNET_ERROR_TYPE_DEBUG, 777 LOG (GNUNET_ERROR_TYPE_DEBUG,
774 "ACK on unknown channel %X\n", 778 "ACK on unknown channel %X\n",
775 ntohl (ccn.channel_of_client)); 779 ntohl (message->ccn.channel_of_client));
776 return; 780 return;
777 } 781 }
778 ch->allow_send++; 782 ch->allow_send++;
779 LOG (GNUNET_ERROR_TYPE_DEBUG, 783 if (NULL == ch->pending_env)
780 "Got an ACK on channel %X, allow send now %u!\n",
781 ntohl (ch->ccn.channel_of_client),
782 ch->allow_send);
783 for (th = h->th_head; NULL != th; th = th->next)
784 { 784 {
785 if ( (th->channel == ch) && 785 LOG (GNUNET_ERROR_TYPE_DEBUG,
786 (NULL == th->request_data_task) ) 786 "Got an ACK on mq channel %X, allow send now %u!\n",
787 { 787 ntohl (ch->ccn.channel_of_client),
788 th->request_data_task 788 ch->allow_send);
789 = GNUNET_SCHEDULER_add_now (&request_data, 789 notify_window_size (ch);
790 th); 790 return;
791 break;
792 }
793 } 791 }
792 if (NULL != ch->mq_cont)
793 return; /* already working on it! */
794 LOG (GNUNET_ERROR_TYPE_DEBUG,
795 "Got an ACK on mq channel %X, sending pending message!\n",
796 ntohl (ch->ccn.channel_of_client));
797 ch->mq_cont
798 = GNUNET_SCHEDULER_add_now (&cadet_mq_send_now,
799 ch);
794} 800}
795 801
796/**
797 * Reconnect to the service, retransmit all infomation to try to restore the
798 * original state.
799 *
800 * @param h handle to the cadet
801 *
802 * @return #GNUNET_YES in case of sucess, #GNUNET_NO otherwise (service down...)
803 */
804static void
805reconnect (struct GNUNET_CADET_Handle *h);
806
807
808/**
809 * Reconnect callback: tries to reconnect again after a failer previous
810 * reconnection.
811 *
812 * @param cls closure (cadet handle)
813 */
814static void
815reconnect_cbk (void *cls);
816
817 802
818/** 803/**
819 * Generic error handler, called with the appropriate error code and 804 * Generic error handler, called with the appropriate error code and
@@ -829,134 +814,15 @@ handle_mq_error (void *cls,
829{ 814{
830 struct GNUNET_CADET_Handle *h = cls; 815 struct GNUNET_CADET_Handle *h = cls;
831 816
832 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);
833 GNUNET_MQ_destroy (h->mq); 820 GNUNET_MQ_destroy (h->mq);
834 h->mq = NULL; 821 h->mq = NULL;
835 reconnect (h); 822 reconnect (h);
836} 823}
837 824
838 825
839/*
840 * Process a local reply about info on all channels, pass info to the user.
841 *
842 * @param h Cadet handle.
843 * @param message Message itself.
844 */
845// static void
846// process_get_channels (struct GNUNET_CADET_Handle *h,
847// const struct GNUNET_MessageHeader *message)
848// {
849// struct GNUNET_CADET_LocalInfo *msg;
850//
851// GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Get Channels messasge received\n");
852//
853// if (NULL == h->channels_cb)
854// {
855// GNUNET_log (GNUNET_ERROR_TYPE_ERROR, " ignored\n");
856// return;
857// }
858//
859// msg = (struct GNUNET_CADET_LocalInfo *) message;
860// if (ntohs (message->size) !=
861// (sizeof (struct GNUNET_CADET_LocalInfo) +
862// sizeof (struct GNUNET_PeerIdentity)))
863// {
864// GNUNET_break_op (0);
865// GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
866// "Get channels message: size %hu - expected %u\n",
867// ntohs (message->size),
868// sizeof (struct GNUNET_CADET_LocalInfo));
869// return;
870// }
871// h->channels_cb (h->channels_cls,
872// ntohl (msg->channel_id),
873// &msg->owner,
874// &msg->destination);
875// }
876
877
878
879/*
880 * Process a local monitor_channel reply, pass info to the user.
881 *
882 * @param h Cadet handle.
883 * @param message Message itself.
884 */
885// static void
886// process_show_channel (struct GNUNET_CADET_Handle *h,
887// const struct GNUNET_MessageHeader *message)
888// {
889// struct GNUNET_CADET_LocalInfo *msg;
890// size_t esize;
891//
892// GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Show Channel messasge received\n");
893//
894// if (NULL == h->channel_cb)
895// {
896// GNUNET_log (GNUNET_ERROR_TYPE_ERROR, " ignored\n");
897// return;
898// }
899//
900// /* Verify message sanity */
901// msg = (struct GNUNET_CADET_LocalInfo *) message;
902// esize = sizeof (struct GNUNET_CADET_LocalInfo);
903// if (ntohs (message->size) != esize)
904// {
905// GNUNET_break_op (0);
906// GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
907// "Show channel message: size %hu - expected %u\n",
908// ntohs (message->size),
909// esize);
910//
911// h->channel_cb (h->channel_cls, NULL, NULL);
912// h->channel_cb = NULL;
913// h->channel_cls = NULL;
914//
915// return;
916// }
917//
918// h->channel_cb (h->channel_cls,
919// &msg->destination,
920// &msg->owner);
921// }
922
923
924
925/**
926 * Check that message received from CADET service is well-formed.
927 *
928 * @param cls the `struct GNUNET_CADET_Handle`
929 * @param message the message we got
930 * @return #GNUNET_OK if the message is well-formed,
931 * #GNUNET_SYSERR otherwise
932 */
933static int
934check_get_peers (void *cls,
935 const struct GNUNET_CADET_LocalInfoPeer *message)
936{
937 struct GNUNET_CADET_Handle *h = cls;
938 uint16_t size;
939
940 if (NULL == h->info_cb.peers_cb)
941 {
942 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
943 " no handler for peesr monitor message!\n");
944 return GNUNET_SYSERR;
945 }
946
947 size = ntohs (message->header.size);
948 if (sizeof (struct GNUNET_CADET_LocalInfoPeer) > size)
949 {
950 h->info_cb.peers_cb (h->info_cls, NULL, -1, 0, 0);
951 h->info_cb.peers_cb = NULL;
952 h->info_cls = NULL;
953 return GNUNET_SYSERR;
954 }
955
956 return GNUNET_OK;
957}
958
959
960/** 826/**
961 * 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.
962 * 828 *
@@ -968,9 +834,13 @@ handle_get_peers (void *cls,
968 const struct GNUNET_CADET_LocalInfoPeer *msg) 834 const struct GNUNET_CADET_LocalInfoPeer *msg)
969{ 835{
970 struct GNUNET_CADET_Handle *h = cls; 836 struct GNUNET_CADET_Handle *h = cls;
971 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,
972 (int) ntohs (msg->tunnel), 842 (int) ntohs (msg->tunnel),
973 (unsigned int ) ntohs (msg->paths), 843 (unsigned int) ntohs (msg->paths),
974 0); 844 0);
975} 845}
976 846
@@ -987,62 +857,39 @@ static int
987check_get_peer (void *cls, 857check_get_peer (void *cls,
988 const struct GNUNET_CADET_LocalInfoPeer *message) 858 const struct GNUNET_CADET_LocalInfoPeer *message)
989{ 859{
990 struct GNUNET_CADET_Handle *h = cls; 860 size_t msize = sizeof (struct GNUNET_CADET_LocalInfoPeer);
991 const size_t msize = sizeof (struct GNUNET_CADET_LocalInfoPeer); 861 const struct GNUNET_PeerIdentity *paths_array;
992 struct GNUNET_PeerIdentity *paths_array;
993 size_t esize; 862 size_t esize;
994 unsigned int epaths; 863 unsigned int epaths;
995 unsigned int paths; 864 unsigned int paths;
996 unsigned int peers; 865 unsigned int peers;
997 866
998 if (NULL == h->info_cb.peer_cb)
999 {
1000 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1001 " no handler for peer monitor message!\n");
1002 goto clean_cls;
1003 }
1004
1005 /* Verify message sanity */
1006 esize = ntohs (message->header.size); 867 esize = ntohs (message->header.size);
1007 if (esize < msize) 868 if (esize < msize)
1008 { 869 {
1009 GNUNET_break_op (0); 870 GNUNET_break (0);
1010 h->info_cb.peer_cb (h->info_cls, NULL, 0, 0, 0, NULL); 871 return GNUNET_SYSERR;
1011 goto clean_cls;
1012 } 872 }
1013 if (0 != ((esize - msize) % sizeof (struct GNUNET_PeerIdentity))) 873 if (0 != ((esize - msize) % sizeof (struct GNUNET_PeerIdentity)))
1014 { 874 {
1015 GNUNET_break_op (0); 875 GNUNET_break (0);
1016 h->info_cb.peer_cb (h->info_cls, NULL, 0, 0, 0, NULL); 876 return GNUNET_SYSERR;
1017 goto clean_cls;
1018
1019 } 877 }
1020 peers = (esize - msize) / sizeof (struct GNUNET_PeerIdentity); 878 peers = (esize - msize) / sizeof (struct GNUNET_PeerIdentity);
1021 epaths = (unsigned int) ntohs (message->paths); 879 epaths = ntohs (message->paths);
1022 paths_array = (struct GNUNET_PeerIdentity *) &message[1]; 880 paths_array = (const struct GNUNET_PeerIdentity *) &message[1];
1023 paths = 0; 881 paths = 0;
1024 for (int i = 0; i < peers; i++) 882 for (unsigned int i = 0; i < peers; i++)
1025 { 883 if (0 == memcmp (&paths_array[i],
1026 if (0 == memcmp (&paths_array[i], &message->destination, 884 &message->destination,
1027 sizeof (struct GNUNET_PeerIdentity))) 885 sizeof (struct GNUNET_PeerIdentity)))
1028 {
1029 paths++; 886 paths++;
1030 }
1031 }
1032 if (paths != epaths) 887 if (paths != epaths)
1033 { 888 {
1034 GNUNET_break_op (0); 889 GNUNET_break (0);
1035 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "p:%u, e: %u\n", paths, epaths); 890 return GNUNET_SYSERR;
1036 h->info_cb.peer_cb (h->info_cls, NULL, 0, 0, 0, NULL);
1037 goto clean_cls;
1038 } 891 }
1039
1040 return GNUNET_OK; 892 return GNUNET_OK;
1041
1042clean_cls:
1043 h->info_cb.peer_cb = NULL;
1044 h->info_cls = NULL;
1045 return GNUNET_SYSERR;
1046} 893}
1047 894
1048 895
@@ -1057,22 +904,26 @@ handle_get_peer (void *cls,
1057 const struct GNUNET_CADET_LocalInfoPeer *message) 904 const struct GNUNET_CADET_LocalInfoPeer *message)
1058{ 905{
1059 struct GNUNET_CADET_Handle *h = cls; 906 struct GNUNET_CADET_Handle *h = cls;
1060 struct GNUNET_PeerIdentity *paths_array; 907 const struct GNUNET_PeerIdentity *paths_array;
1061 unsigned int paths; 908 unsigned int paths;
1062 unsigned int path_length; 909 unsigned int path_length;
1063 int neighbor; 910 int neighbor;
1064 unsigned int peers; 911 unsigned int peers;
1065 912
1066 paths = (unsigned int) ntohs (message->paths); 913 if (NULL == h->info_cb.peer_cb)
1067 paths_array = (struct GNUNET_PeerIdentity *) &message[1]; 914 return;
915 paths = ntohs (message->paths);
916 paths_array = (const struct GNUNET_PeerIdentity *) &message[1];
1068 peers = (ntohs (message->header.size) - sizeof (*message)) 917 peers = (ntohs (message->header.size) - sizeof (*message))
1069 / sizeof (struct GNUNET_PeerIdentity); 918 / sizeof (struct GNUNET_PeerIdentity);
1070 path_length = 0; 919 path_length = 0;
1071 neighbor = GNUNET_NO; 920 neighbor = GNUNET_NO;
1072 921
1073 for (int i = 0; i < peers; i++) 922 for (unsigned int i = 0; i < peers; i++)
1074 { 923 {
1075 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]));
1076 path_length++; 927 path_length++;
1077 if (0 == memcmp (&paths_array[i], &message->destination, 928 if (0 == memcmp (&paths_array[i], &message->destination,
1078 sizeof (struct GNUNET_PeerIdentity))) 929 sizeof (struct GNUNET_PeerIdentity)))
@@ -1084,7 +935,7 @@ handle_get_peer (void *cls,
1084 } 935 }
1085 936
1086 /* Call Callback with tunnel info. */ 937 /* Call Callback with tunnel info. */
1087 paths_array = (struct GNUNET_PeerIdentity *) &message[1]; 938 paths_array = (const struct GNUNET_PeerIdentity *) &message[1];
1088 h->info_cb.peer_cb (h->info_cls, 939 h->info_cb.peer_cb (h->info_cls,
1089 &message->destination, 940 &message->destination,
1090 (int) ntohs (message->tunnel), 941 (int) ntohs (message->tunnel),
@@ -1095,40 +946,6 @@ handle_get_peer (void *cls,
1095 946
1096 947
1097/** 948/**
1098 * Check that message received from CADET service is well-formed.
1099 *
1100 * @param cls the `struct GNUNET_CADET_Handle`
1101 * @param msg the message we got
1102 * @return #GNUNET_OK if the message is well-formed,
1103 * #GNUNET_SYSERR otherwise
1104 */
1105static int
1106check_get_tunnels (void *cls,
1107 const struct GNUNET_CADET_LocalInfoTunnel *msg)
1108{
1109 struct GNUNET_CADET_Handle *h = cls;
1110 uint16_t size;
1111
1112 if (NULL == h->info_cb.tunnels_cb)
1113 {
1114 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1115 " no handler for tunnels monitor message!\n");
1116 return GNUNET_SYSERR;
1117 }
1118
1119 size = ntohs (msg->header.size);
1120 if (sizeof (struct GNUNET_CADET_LocalInfoTunnel) > size)
1121 {
1122 h->info_cb.tunnels_cb (h->info_cls, NULL, 0, 0, 0, 0);
1123 h->info_cb.tunnels_cb = NULL;
1124 h->info_cls = NULL;
1125 return GNUNET_SYSERR;
1126 }
1127 return GNUNET_OK;
1128}
1129
1130
1131/**
1132 * 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.
1133 * 950 *
1134 * @param cls Closure (Cadet handle). 951 * @param cls Closure (Cadet handle).
@@ -1140,6 +957,8 @@ handle_get_tunnels (void *cls,
1140{ 957{
1141 struct GNUNET_CADET_Handle *h = cls; 958 struct GNUNET_CADET_Handle *h = cls;
1142 959
960 if (NULL == h->info_cb.tunnels_cb)
961 return;
1143 h->info_cb.tunnels_cb (h->info_cls, 962 h->info_cb.tunnels_cb (h->info_cls,
1144 &msg->destination, 963 &msg->destination,
1145 ntohl (msg->channels), 964 ntohl (msg->channels),
@@ -1162,28 +981,18 @@ static int
1162check_get_tunnel (void *cls, 981check_get_tunnel (void *cls,
1163 const struct GNUNET_CADET_LocalInfoTunnel *msg) 982 const struct GNUNET_CADET_LocalInfoTunnel *msg)
1164{ 983{
1165 struct GNUNET_CADET_Handle *h = cls;
1166 unsigned int ch_n; 984 unsigned int ch_n;
1167 unsigned int c_n; 985 unsigned int c_n;
1168 size_t esize; 986 size_t esize;
1169 size_t msize; 987 size_t msize;
1170 988
1171 if (NULL == h->info_cb.tunnel_cb)
1172 {
1173 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1174 " no handler for tunnel monitor message!\n");
1175 goto clean_cls;
1176 }
1177
1178 /* Verify message sanity */ 989 /* Verify message sanity */
1179 msize = ntohs (msg->header.size); 990 msize = ntohs (msg->header.size);
1180 esize = sizeof (struct GNUNET_CADET_LocalInfoTunnel); 991 esize = sizeof (struct GNUNET_CADET_LocalInfoTunnel);
1181 if (esize > msize) 992 if (esize > msize)
1182 { 993 {
1183 GNUNET_break_op (0); 994 GNUNET_break (0);
1184 h->info_cb.tunnel_cb (h->info_cls, 995 return GNUNET_SYSERR;
1185 NULL, 0, 0, NULL, NULL, 0, 0);
1186 goto clean_cls;
1187 } 996 }
1188 ch_n = ntohl (msg->channels); 997 ch_n = ntohl (msg->channels);
1189 c_n = ntohl (msg->connections); 998 c_n = ntohl (msg->connections);
@@ -1198,17 +1007,9 @@ check_get_tunnel (void *cls,
1198 (unsigned int) esize, 1007 (unsigned int) esize,
1199 ch_n, 1008 ch_n,
1200 c_n); 1009 c_n);
1201 h->info_cb.tunnel_cb (h->info_cls, 1010 return GNUNET_SYSERR;
1202 NULL, 0, 0, NULL, NULL, 0, 0);
1203 goto clean_cls;
1204 } 1011 }
1205
1206 return GNUNET_OK; 1012 return GNUNET_OK;
1207
1208clean_cls:
1209 h->info_cb.tunnel_cb = NULL;
1210 h->info_cls = NULL;
1211 return GNUNET_SYSERR;
1212} 1013}
1213 1014
1214 1015
@@ -1228,6 +1029,9 @@ handle_get_tunnel (void *cls,
1228 const struct GNUNET_CADET_ConnectionTunnelIdentifier *conns; 1029 const struct GNUNET_CADET_ConnectionTunnelIdentifier *conns;
1229 const struct GNUNET_CADET_ChannelTunnelNumber *chns; 1030 const struct GNUNET_CADET_ChannelTunnelNumber *chns;
1230 1031
1032 if (NULL == h->info_cb.tunnel_cb)
1033 return;
1034
1231 ch_n = ntohl (msg->channels); 1035 ch_n = ntohl (msg->channels);
1232 c_n = ntohl (msg->connections); 1036 c_n = ntohl (msg->connections);
1233 1037
@@ -1245,16 +1049,14 @@ handle_get_tunnel (void *cls,
1245} 1049}
1246 1050
1247 1051
1248
1249/** 1052/**
1250 * Reconnect to the service, retransmit all infomation to try to restore the 1053 * Reconnect to the service, retransmit all infomation to try to restore the
1251 * original state. 1054 * original state.
1252 * 1055 *
1253 * @param h handle to the cadet 1056 * @param h handle to the cadet
1254 * @return #GNUNET_YES in case of success, #GNUNET_NO otherwise (service down...)
1255 */ 1057 */
1256static int 1058static void
1257do_reconnect (struct GNUNET_CADET_Handle *h) 1059reconnect (struct GNUNET_CADET_Handle *h)
1258{ 1060{
1259 struct GNUNET_MQ_MessageHandler handlers[] = { 1061 struct GNUNET_MQ_MessageHandler handlers[] = {
1260 GNUNET_MQ_hd_fixed_size (channel_created, 1062 GNUNET_MQ_hd_fixed_size (channel_created,
@@ -1273,32 +1075,25 @@ do_reconnect (struct GNUNET_CADET_Handle *h)
1273 GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK, 1075 GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK,
1274 struct GNUNET_CADET_LocalAck, 1076 struct GNUNET_CADET_LocalAck,
1275 h), 1077 h),
1276 GNUNET_MQ_hd_var_size (get_peers, 1078 GNUNET_MQ_hd_fixed_size (get_peers,
1277 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS, 1079 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS,
1278 struct GNUNET_CADET_LocalInfoPeer, 1080 struct GNUNET_CADET_LocalInfoPeer,
1279 h), 1081 h),
1280 GNUNET_MQ_hd_var_size (get_peer, 1082 GNUNET_MQ_hd_var_size (get_peer,
1281 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER, 1083 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER,
1282 struct GNUNET_CADET_LocalInfoPeer, 1084 struct GNUNET_CADET_LocalInfoPeer,
1283 h), 1085 h),
1284 GNUNET_MQ_hd_var_size (get_tunnels, 1086 GNUNET_MQ_hd_fixed_size (get_tunnels,
1285 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS, 1087 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS,
1286 struct GNUNET_CADET_LocalInfoTunnel, 1088 struct GNUNET_CADET_LocalInfoTunnel,
1287 h), 1089 h),
1288 GNUNET_MQ_hd_var_size (get_tunnel, 1090 GNUNET_MQ_hd_var_size (get_tunnel,
1289 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL, 1091 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL,
1290 struct GNUNET_CADET_LocalInfoTunnel, 1092 struct GNUNET_CADET_LocalInfoTunnel,
1291 h), 1093 h),
1292 // FIXME
1293// GNUNET_MQ_hd_fixed_Y size (channel_destroyed,
1294// GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_NACK_DEPRECATED,
1295// struct GNUNET_CADET_ChannelDestroyMessage);
1296 GNUNET_MQ_handler_end () 1094 GNUNET_MQ_handler_end ()
1297 }; 1095 };
1298 1096
1299 LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to CADET\n");
1300
1301 GNUNET_assert (NULL == h->mq);
1302 h->mq = GNUNET_CLIENT_connect (h->cfg, 1097 h->mq = GNUNET_CLIENT_connect (h->cfg,
1303 "cadet", 1098 "cadet",
1304 handlers, 1099 handlers,
@@ -1306,92 +1101,63 @@ do_reconnect (struct GNUNET_CADET_Handle *h)
1306 h); 1101 h);
1307 if (NULL == h->mq) 1102 if (NULL == h->mq)
1308 { 1103 {
1309 reconnect (h); 1104 schedule_reconnect (h);
1310 return GNUNET_NO; 1105 return;
1311 }
1312 else
1313 {
1314 h->reconnect_time = GNUNET_TIME_UNIT_MILLISECONDS;
1315 } 1106 }
1316 return GNUNET_YES; 1107 h->reconnect_time = GNUNET_TIME_UNIT_MILLISECONDS;
1317} 1108}
1318 1109
1110
1319/** 1111/**
1320 * Reconnect callback: tries to reconnect again after a failer previous 1112 * Function called during #GNUNET_CADET_disconnect() to destroy
1321 * reconnecttion 1113 * all channels that are still open.
1322 * 1114 *
1323 * @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)
1324 */ 1119 */
1325static void 1120static int
1326reconnect_cbk (void *cls) 1121destroy_channel_cb (void *cls,
1122 uint32_t cid,
1123 void *value)
1327{ 1124{
1328 struct GNUNET_CADET_Handle *h = cls; 1125 /* struct GNUNET_CADET_Handle *handle = cls; */
1126 struct GNUNET_CADET_Channel *ch = value;
1329 1127
1330 h->reconnect_task = NULL; 1128 if (ntohl (ch->ccn.channel_of_client) >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
1331 do_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;
1332} 1137}
1333 1138
1334 1139
1335/** 1140/**
1336 * Reconnect to the service, retransmit all infomation to try to restore the 1141 * Function called during #GNUNET_CADET_disconnect() to destroy
1337 * original state. 1142 * all ports that are still open.
1338 *
1339 * @param h handle to the cadet
1340 * 1143 *
1341 * @return #GNUNET_YES in case of sucess, #GNUNET_NO otherwise (service down...) 1144 * @param cls the `struct GNUNET_CADET_Handle`
1145 * @param id port ID
1146 * @param value a `struct GNUNET_CADET_Channel` to destroy
1147 * @return #GNUNET_OK (continue to iterate)
1342 */ 1148 */
1343static void 1149static int
1344reconnect (struct GNUNET_CADET_Handle *h) 1150destroy_port_cb (void *cls,
1345{ 1151 const struct GNUNET_HashCode *id,
1346 struct GNUNET_CADET_Channel *ch; 1152 void *value)
1347
1348 LOG (GNUNET_ERROR_TYPE_DEBUG,
1349 "Requested RECONNECT, destroying all channels\n");
1350 while (NULL != (ch = h->channels_head))
1351 destroy_channel (ch, GNUNET_YES);
1352 if (NULL == h->reconnect_task)
1353 h->reconnect_task = GNUNET_SCHEDULER_add_delayed (h->reconnect_time,
1354 &reconnect_cbk, h);
1355}
1356
1357
1358/******************************************************************************/
1359/********************** API CALL DEFINITIONS *************************/
1360/******************************************************************************/
1361
1362struct GNUNET_CADET_Handle *
1363GNUNET_CADET_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
1364 void *cls,
1365 GNUNET_CADET_ChannelEndHandler cleaner,
1366 const struct GNUNET_CADET_MessageHandler *handlers)
1367{ 1153{
1368 struct GNUNET_CADET_Handle *h; 1154 /* struct GNUNET_CADET_Handle *handle = cls; */
1369 1155 struct GNUNET_CADET_Port *port = value;
1370 h = GNUNET_new (struct GNUNET_CADET_Handle);
1371 LOG (GNUNET_ERROR_TYPE_DEBUG,
1372 "GNUNET_CADET_connect() %p\n",
1373 h);
1374 h->cfg = cfg;
1375 h->cleaner = cleaner;
1376 h->ports = GNUNET_CONTAINER_multihashmap_create (4, GNUNET_YES);
1377 do_reconnect (h);
1378 if (h->mq == NULL)
1379 {
1380 GNUNET_break (0);
1381 GNUNET_CADET_disconnect (h);
1382 return NULL;
1383 }
1384 h->cls = cls;
1385 h->message_handlers = handlers;
1386 h->next_ccn.channel_of_client = htonl (GNUNET_CADET_LOCAL_CHANNEL_ID_CLI);
1387 h->reconnect_time = GNUNET_TIME_UNIT_MILLISECONDS;
1388 h->reconnect_task = NULL;
1389 1156
1390 /* count handlers */ 1157 /* This is a warning, the app should have cleanly closed all open ports */
1391 for (h->n_handlers = 0; 1158 GNUNET_break (0);
1392 handlers && handlers[h->n_handlers].type; 1159 GNUNET_CADET_close_port (port);
1393 h->n_handlers++) ; 1160 return GNUNET_OK;
1394 return h;
1395} 1161}
1396 1162
1397 1163
@@ -1406,58 +1172,16 @@ GNUNET_CADET_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
1406void 1172void
1407GNUNET_CADET_disconnect (struct GNUNET_CADET_Handle *handle) 1173GNUNET_CADET_disconnect (struct GNUNET_CADET_Handle *handle)
1408{ 1174{
1409 struct GNUNET_CADET_Channel *ch; 1175 GNUNET_CONTAINER_multihashmap_iterate (handle->ports,
1410 struct GNUNET_CADET_Channel *aux; 1176 &destroy_port_cb,
1411 struct GNUNET_CADET_TransmitHandle *th; 1177 handle);
1412 1178 GNUNET_CONTAINER_multihashmap_destroy (handle->ports);
1413 LOG (GNUNET_ERROR_TYPE_DEBUG, 1179 handle->ports = NULL;
1414 "CADET DISCONNECT\n"); 1180 GNUNET_CONTAINER_multihashmap32_iterate (handle->channels,
1415 ch = handle->channels_head; 1181 &destroy_channel_cb,
1416 while (NULL != ch) 1182 handle);
1417 { 1183 GNUNET_CONTAINER_multihashmap32_destroy (handle->channels);
1418 aux = ch->next; 1184 handle->channels = NULL;
1419 if (ntohl (ch->ccn.channel_of_client) >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
1420 {
1421 GNUNET_break (0);
1422 LOG (GNUNET_ERROR_TYPE_DEBUG,
1423 "channel %X not destroyed\n",
1424 ntohl (ch->ccn.channel_of_client));
1425 }
1426 destroy_channel (ch,
1427 GNUNET_YES);
1428 ch = aux;
1429 }
1430 while (NULL != (th = handle->th_head))
1431 {
1432 struct GNUNET_MessageHeader *msg;
1433
1434 /* Make sure it is an allowed packet (everything else should have been
1435 * already canceled).
1436 */
1437 GNUNET_break (GNUNET_NO == th_is_payload (th));
1438 msg = (struct GNUNET_MessageHeader *) &th[1];
1439 switch (ntohs(msg->type))
1440 {
1441 case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN:
1442 case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY:
1443 case GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_OPEN:
1444 case GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_CLOSE:
1445 case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CHANNELS:
1446 case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CHANNEL:
1447 case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER:
1448 case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS:
1449 case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL:
1450 case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS:
1451 break;
1452 default:
1453 GNUNET_break (0);
1454 LOG (GNUNET_ERROR_TYPE_ERROR, "unexpected unsent msg %s\n",
1455 GC_m2s (ntohs(msg->type)));
1456 }
1457
1458 GNUNET_CADET_notify_transmit_ready_cancel (th);
1459 }
1460
1461 if (NULL != handle->mq) 1185 if (NULL != handle->mq)
1462 { 1186 {
1463 GNUNET_MQ_destroy (handle->mq); 1187 GNUNET_MQ_destroy (handle->mq);
@@ -1465,58 +1189,15 @@ GNUNET_CADET_disconnect (struct GNUNET_CADET_Handle *handle)
1465 } 1189 }
1466 if (NULL != handle->reconnect_task) 1190 if (NULL != handle->reconnect_task)
1467 { 1191 {
1468 GNUNET_SCHEDULER_cancel(handle->reconnect_task); 1192 GNUNET_SCHEDULER_cancel (handle->reconnect_task);
1469 handle->reconnect_task = NULL; 1193 handle->reconnect_task = NULL;
1470 } 1194 }
1471
1472 GNUNET_CONTAINER_multihashmap_destroy (handle->ports);
1473 handle->ports = NULL;
1474 GNUNET_free (handle); 1195 GNUNET_free (handle);
1475} 1196}
1476 1197
1477 1198
1478/** 1199/**
1479 * Open a port to receive incomming channels. 1200 * Close a port opened with @a GNUNET_CADET_open_port().
1480 *
1481 * @param h CADET handle.
1482 * @param port Hash representing the port number.
1483 * @param new_channel Function called when an channel is received.
1484 * @param new_channel_cls Closure for @a new_channel.
1485 * @return Port handle.
1486 */
1487struct GNUNET_CADET_Port *
1488GNUNET_CADET_open_port (struct GNUNET_CADET_Handle *h,
1489 const struct GNUNET_HashCode *port,
1490 GNUNET_CADET_InboundChannelNotificationHandler
1491 new_channel,
1492 void *new_channel_cls)
1493{
1494 struct GNUNET_CADET_PortMessage *msg;
1495 struct GNUNET_MQ_Envelope *env;
1496 struct GNUNET_CADET_Port *p;
1497
1498 GNUNET_assert (NULL != new_channel);
1499 p = GNUNET_new (struct GNUNET_CADET_Port);
1500 p->cadet = h;
1501 p->hash = GNUNET_new (struct GNUNET_HashCode);
1502 *p->hash = *port;
1503 p->handler = new_channel;
1504 p->cls = new_channel_cls;
1505 GNUNET_assert (GNUNET_OK ==
1506 GNUNET_CONTAINER_multihashmap_put (h->ports,
1507 p->hash,
1508 p,
1509 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1510
1511 env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_OPEN);
1512 msg->port = *p->hash;
1513 GNUNET_MQ_send (h->mq, env);
1514
1515 return p;
1516}
1517
1518/**
1519 * Close a port opened with @a GNUNET_CADET_open_port.
1520 * The @a new_channel callback will no longer be called. 1201 * The @a new_channel callback will no longer be called.
1521 * 1202 *
1522 * @param p Port handle. 1203 * @param p Port handle.
@@ -1527,110 +1208,45 @@ GNUNET_CADET_close_port (struct GNUNET_CADET_Port *p)
1527 struct GNUNET_CADET_PortMessage *msg; 1208 struct GNUNET_CADET_PortMessage *msg;
1528 struct GNUNET_MQ_Envelope *env; 1209 struct GNUNET_MQ_Envelope *env;
1529 1210
1530 env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_CLOSE); 1211 env = GNUNET_MQ_msg (msg,
1531 1212 GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_CLOSE);
1532 msg->port = *p->hash; 1213 msg->port = p->id;
1533 GNUNET_MQ_send (p->cadet->mq, env); 1214 GNUNET_MQ_send (p->cadet->mq,
1534 GNUNET_CONTAINER_multihashmap_remove (p->cadet->ports, p->hash, p); 1215 env);
1535 GNUNET_free (p->hash); 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);
1536 GNUNET_free (p); 1221 GNUNET_free (p);
1537} 1222}
1538 1223
1539 1224
1540/** 1225/**
1541 * Create a new channel towards a remote peer. 1226 * Destroy an existing channel.
1542 * 1227 *
1543 * 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.
1544 * 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
1545 * for this channel. 1230 * accepted and no data callbacks will be called.
1546 * 1231 *
1547 * @param h cadet handle 1232 * @param channel Channel handle, becomes invalid after this call.
1548 * @param channel_ctx client's channel context to associate with the channel
1549 * @param peer peer identity the channel should go to
1550 * @param port Port hash (port number).
1551 * @param options CadetOption flag field, with all desired option bits set to 1.
1552 * @return handle to the channel
1553 */ 1233 */
1554struct GNUNET_CADET_Channel *
1555GNUNET_CADET_channel_create (struct GNUNET_CADET_Handle *h,
1556 void *channel_ctx,
1557 const struct GNUNET_PeerIdentity *peer,
1558 const struct GNUNET_HashCode *port,
1559 enum GNUNET_CADET_ChannelOption options)
1560{
1561 struct GNUNET_CADET_LocalChannelCreateMessage *msg;
1562 struct GNUNET_MQ_Envelope *env;
1563 struct GNUNET_CADET_Channel *ch;
1564 struct GNUNET_CADET_ClientChannelNumber ccn;
1565
1566 ccn.channel_of_client = htonl (0);
1567 ch = create_channel (h, ccn);
1568 ch->ctx = channel_ctx;
1569 ch->peer = GNUNET_PEER_intern (peer);
1570
1571 LOG (GNUNET_ERROR_TYPE_DEBUG,
1572 "Creating new channel to %s:%u at %p number %X\n",
1573 GNUNET_i2s (peer),
1574 port,
1575 ch,
1576 ntohl (ch->ccn.channel_of_client));
1577 env = GNUNET_MQ_msg (msg,
1578 GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_CREATE);
1579 msg->ccn = ch->ccn;
1580 msg->port = *port;
1581 msg->peer = *peer;
1582 msg->opt = htonl (options);
1583 GNUNET_MQ_send (h->mq,
1584 env);
1585 return ch;
1586}
1587
1588
1589void 1234void
1590GNUNET_CADET_channel_destroy (struct GNUNET_CADET_Channel *channel) 1235GNUNET_CADET_channel_destroy (struct GNUNET_CADET_Channel *channel)
1591{ 1236{
1592 struct GNUNET_CADET_Handle *h; 1237 struct GNUNET_CADET_Handle *h = channel->cadet;
1593 struct GNUNET_CADET_LocalChannelDestroyMessage *msg; 1238 struct GNUNET_CADET_LocalChannelDestroyMessage *msg;
1594 struct GNUNET_MQ_Envelope *env; 1239 struct GNUNET_MQ_Envelope *env;
1595 struct GNUNET_CADET_TransmitHandle *th;
1596 struct GNUNET_CADET_TransmitHandle *next;
1597 1240
1598 LOG (GNUNET_ERROR_TYPE_DEBUG, 1241 if (NULL != h->mq)
1599 "Destroying channel\n");
1600 h = channel->cadet;
1601 for (th = h->th_head; th != NULL; th = next)
1602 { 1242 {
1603 next = th->next; 1243 env = GNUNET_MQ_msg (msg,
1604 if (th->channel == channel) 1244 GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY);
1605 { 1245 msg->ccn = channel->ccn;
1606 GNUNET_break (0); 1246 GNUNET_MQ_send (h->mq,
1607 if (GNUNET_YES == th_is_payload (th)) 1247 env);
1608 {
1609 /* applications should cancel before destroying channel */
1610 LOG (GNUNET_ERROR_TYPE_WARNING,
1611 "Channel destroyed without cancelling transmission requests\n");
1612 th->notify (th->notify_cls, 0, NULL);
1613 }
1614 else
1615 {
1616 LOG (GNUNET_ERROR_TYPE_WARNING,
1617 "no meta-traffic should be queued\n");
1618 }
1619 GNUNET_CONTAINER_DLL_remove (h->th_head,
1620 h->th_tail,
1621 th);
1622 GNUNET_CADET_notify_transmit_ready_cancel (th);
1623 }
1624 } 1248 }
1625 1249 destroy_channel (channel);
1626 env = GNUNET_MQ_msg (msg,
1627 GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY);
1628 msg->ccn = channel->ccn;
1629 GNUNET_MQ_send (h->mq,
1630 env);
1631
1632 destroy_channel (channel,
1633 GNUNET_YES);
1634} 1250}
1635 1251
1636 1252
@@ -1645,10 +1261,10 @@ GNUNET_CADET_channel_destroy (struct GNUNET_CADET_Channel *channel)
1645 */ 1261 */
1646const union GNUNET_CADET_ChannelInfo * 1262const union GNUNET_CADET_ChannelInfo *
1647GNUNET_CADET_channel_get_info (struct GNUNET_CADET_Channel *channel, 1263GNUNET_CADET_channel_get_info (struct GNUNET_CADET_Channel *channel,
1648 enum GNUNET_CADET_ChannelOption option, ...) 1264 enum GNUNET_CADET_ChannelOption option,
1265 ...)
1649{ 1266{
1650 static int bool_flag; 1267 static int bool_flag;
1651 const union GNUNET_CADET_ChannelInfo *ret;
1652 1268
1653 switch (option) 1269 switch (option)
1654 { 1270 {
@@ -1659,74 +1275,15 @@ GNUNET_CADET_channel_get_info (struct GNUNET_CADET_Channel *channel,
1659 bool_flag = GNUNET_YES; 1275 bool_flag = GNUNET_YES;
1660 else 1276 else
1661 bool_flag = GNUNET_NO; 1277 bool_flag = GNUNET_NO;
1662 ret = (const union GNUNET_CADET_ChannelInfo *) &bool_flag; 1278 return (const union GNUNET_CADET_ChannelInfo *) &bool_flag;
1663 break; 1279 break;
1664 case GNUNET_CADET_OPTION_PEER: 1280 case GNUNET_CADET_OPTION_PEER:
1665 ret = (const union GNUNET_CADET_ChannelInfo *) GNUNET_PEER_resolve2 (channel->peer); 1281 return (const union GNUNET_CADET_ChannelInfo *) &channel->peer;
1666 break; 1282 break;
1667 default: 1283 default:
1668 GNUNET_break (0); 1284 GNUNET_break (0);
1669 return NULL; 1285 return NULL;
1670 } 1286 }
1671
1672 return ret;
1673}
1674
1675
1676struct GNUNET_CADET_TransmitHandle *
1677GNUNET_CADET_notify_transmit_ready (struct GNUNET_CADET_Channel *channel,
1678 int cork,
1679 struct GNUNET_TIME_Relative maxdelay,
1680 size_t notify_size,
1681 GNUNET_CONNECTION_TransmitReadyNotify notify,
1682 void *notify_cls)
1683{
1684 struct GNUNET_CADET_TransmitHandle *th;
1685
1686 GNUNET_assert (NULL != channel);
1687 GNUNET_assert (NULL != notify);
1688 GNUNET_assert (GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE >= notify_size);
1689 LOG (GNUNET_ERROR_TYPE_DEBUG,
1690 "CADET NOTIFY TRANSMIT READY on channel %X allow_send is %u to %s with %u bytes\n",
1691 channel->ccn,
1692 channel->allow_send,
1693 (ntohl (channel->ccn.channel_of_client) >=
1694 GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
1695 ? "origin"
1696 : "destination",
1697 (unsigned int) notify_size);
1698 if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us != maxdelay.rel_value_us)
1699 {
1700 LOG (GNUNET_ERROR_TYPE_WARNING,
1701 "CADET transmit ready timeout is deprected (has no effect)\n");
1702 }
1703
1704 th = GNUNET_new (struct GNUNET_CADET_TransmitHandle);
1705 th->channel = channel;
1706 th->size = notify_size;
1707 th->notify = notify;
1708 th->notify_cls = notify_cls;
1709 if (0 != channel->allow_send)
1710 th->request_data_task
1711 = GNUNET_SCHEDULER_add_now (&request_data,
1712 th);
1713 else
1714 add_to_queue (channel->cadet,
1715 th);
1716 return th;
1717}
1718
1719
1720void
1721GNUNET_CADET_notify_transmit_ready_cancel (struct GNUNET_CADET_TransmitHandle *th)
1722{
1723 if (NULL != th->request_data_task)
1724 {
1725 GNUNET_SCHEDULER_cancel (th->request_data_task);
1726 th->request_data_task = NULL;
1727 }
1728 remove_from_queue (th);
1729 GNUNET_free (th);
1730} 1287}
1731 1288
1732 1289
@@ -1745,25 +1302,30 @@ GNUNET_CADET_receive_done (struct GNUNET_CADET_Channel *channel)
1745 GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK); 1302 GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK);
1746 LOG (GNUNET_ERROR_TYPE_DEBUG, 1303 LOG (GNUNET_ERROR_TYPE_DEBUG,
1747 "Sending ACK on channel %X\n", 1304 "Sending ACK on channel %X\n",
1748 channel->ccn.channel_of_client); 1305 ntohl (channel->ccn.channel_of_client));
1749 msg->ccn = channel->ccn; 1306 msg->ccn = channel->ccn;
1750 GNUNET_MQ_send (channel->cadet->mq, 1307 GNUNET_MQ_send (channel->cadet->mq,
1751 env); 1308 env);
1752} 1309}
1753 1310
1754 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 */
1755static void 1318static void
1756send_info_request (struct GNUNET_CADET_Handle *h, uint16_t type) 1319send_info_request (struct GNUNET_CADET_Handle *h,
1320 uint16_t type)
1757{ 1321{
1758 struct GNUNET_MessageHeader *msg; 1322 struct GNUNET_MessageHeader *msg;
1759 struct GNUNET_MQ_Envelope *env; 1323 struct GNUNET_MQ_Envelope *env;
1760 1324
1761 LOG (GNUNET_ERROR_TYPE_DEBUG, 1325 env = GNUNET_MQ_msg (msg,
1762 " Sending %s monitor message to service\n", 1326 type);
1763 GC_m2s(type)); 1327 GNUNET_MQ_send (h->mq,
1764 1328 env);
1765 env = GNUNET_MQ_msg (msg, type);
1766 GNUNET_MQ_send (h->mq, env);
1767} 1329}
1768 1330
1769 1331
@@ -1777,8 +1339,8 @@ send_info_request (struct GNUNET_CADET_Handle *h, uint16_t type)
1777void 1339void
1778GNUNET_CADET_request_dump (struct GNUNET_CADET_Handle *h) 1340GNUNET_CADET_request_dump (struct GNUNET_CADET_Handle *h)
1779{ 1341{
1780 LOG (GNUNET_ERROR_TYPE_DEBUG, "requesting dump\n"); 1342 send_info_request (h,
1781 send_info_request (h, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_DUMP); 1343 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_DUMP);
1782} 1344}
1783 1345
1784 1346
@@ -1787,13 +1349,11 @@ GNUNET_CADET_request_dump (struct GNUNET_CADET_Handle *h)
1787 * 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.
1788 * 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.
1789 * 1351 *
1790 *
1791 * WARNING: unstable API, likely to change in the future! 1352 * WARNING: unstable API, likely to change in the future!
1792 * 1353 *
1793 * @param h Handle to the cadet peer. 1354 * @param h Handle to the cadet peer.
1794 * @param callback Function to call with the requested data. 1355 * @param callback Function to call with the requested data.
1795 * @param callback_cls Closure for @c callback. 1356 * @param callback_cls Closure for @c callback.
1796 *
1797 * @return #GNUNET_OK / #GNUNET_SYSERR 1357 * @return #GNUNET_OK / #GNUNET_SYSERR
1798 */ 1358 */
1799int 1359int
@@ -1806,7 +1366,8 @@ GNUNET_CADET_get_peers (struct GNUNET_CADET_Handle *h,
1806 GNUNET_break (0); 1366 GNUNET_break (0);
1807 return GNUNET_SYSERR; 1367 return GNUNET_SYSERR;
1808 } 1368 }
1809 send_info_request (h, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS); 1369 send_info_request (h,
1370 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS);
1810 h->info_cb.peers_cb = callback; 1371 h->info_cb.peers_cb = callback;
1811 h->info_cls = callback_cls; 1372 h->info_cls = callback_cls;
1812 return GNUNET_OK; 1373 return GNUNET_OK;
@@ -1819,15 +1380,13 @@ GNUNET_CADET_get_peers (struct GNUNET_CADET_Handle *h,
1819 * WARNING: unstable API, likely to change in the future! 1380 * WARNING: unstable API, likely to change in the future!
1820 * 1381 *
1821 * @param h Cadet handle. 1382 * @param h Cadet handle.
1822 * 1383 * @return Closure given to GNUNET_CADET_get_peers().
1823 * @return Closure given to GNUNET_CADET_get_peers.
1824 */ 1384 */
1825void * 1385void *
1826GNUNET_CADET_get_peers_cancel (struct GNUNET_CADET_Handle *h) 1386GNUNET_CADET_get_peers_cancel (struct GNUNET_CADET_Handle *h)
1827{ 1387{
1828 void *cls; 1388 void *cls = h->info_cls;
1829 1389
1830 cls = h->info_cls;
1831 h->info_cb.peers_cb = NULL; 1390 h->info_cb.peers_cb = NULL;
1832 h->info_cls = NULL; 1391 h->info_cls = NULL;
1833 return cls; 1392 return cls;
@@ -1845,7 +1404,6 @@ GNUNET_CADET_get_peers_cancel (struct GNUNET_CADET_Handle *h)
1845 * @param id Peer whose tunnel to examine. 1404 * @param id Peer whose tunnel to examine.
1846 * @param callback Function to call with the requested data. 1405 * @param callback Function to call with the requested data.
1847 * @param callback_cls Closure for @c callback. 1406 * @param callback_cls Closure for @c callback.
1848 *
1849 * @return #GNUNET_OK / #GNUNET_SYSERR 1407 * @return #GNUNET_OK / #GNUNET_SYSERR
1850 */ 1408 */
1851int 1409int
@@ -1862,11 +1420,11 @@ GNUNET_CADET_get_peer (struct GNUNET_CADET_Handle *h,
1862 GNUNET_break (0); 1420 GNUNET_break (0);
1863 return GNUNET_SYSERR; 1421 return GNUNET_SYSERR;
1864 } 1422 }
1865 1423 env = GNUNET_MQ_msg (msg,
1866 env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER); 1424 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER);
1867 msg->peer = *id; 1425 msg->peer = *id;
1868 GNUNET_MQ_send (h->mq, env); 1426 GNUNET_MQ_send (h->mq,
1869 1427 env);
1870 h->info_cb.peer_cb = callback; 1428 h->info_cb.peer_cb = callback;
1871 h->info_cls = callback_cls; 1429 h->info_cls = callback_cls;
1872 return GNUNET_OK; 1430 return GNUNET_OK;
@@ -1883,7 +1441,6 @@ GNUNET_CADET_get_peer (struct GNUNET_CADET_Handle *h,
1883 * @param h Handle to the cadet peer. 1441 * @param h Handle to the cadet peer.
1884 * @param callback Function to call with the requested data. 1442 * @param callback Function to call with the requested data.
1885 * @param callback_cls Closure for @c callback. 1443 * @param callback_cls Closure for @c callback.
1886 *
1887 * @return #GNUNET_OK / #GNUNET_SYSERR 1444 * @return #GNUNET_OK / #GNUNET_SYSERR
1888 */ 1445 */
1889int 1446int
@@ -1896,7 +1453,8 @@ GNUNET_CADET_get_tunnels (struct GNUNET_CADET_Handle *h,
1896 GNUNET_break (0); 1453 GNUNET_break (0);
1897 return GNUNET_SYSERR; 1454 return GNUNET_SYSERR;
1898 } 1455 }
1899 send_info_request (h, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS); 1456 send_info_request (h,
1457 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS);
1900 h->info_cb.tunnels_cb = callback; 1458 h->info_cb.tunnels_cb = callback;
1901 h->info_cls = callback_cls; 1459 h->info_cls = callback_cls;
1902 return GNUNET_OK; 1460 return GNUNET_OK;
@@ -1907,23 +1465,19 @@ GNUNET_CADET_get_tunnels (struct GNUNET_CADET_Handle *h,
1907 * Cancel a monitor request. The monitor callback will not be called. 1465 * Cancel a monitor request. The monitor callback will not be called.
1908 * 1466 *
1909 * @param h Cadet handle. 1467 * @param h Cadet handle.
1910 * 1468 * @return Closure given to GNUNET_CADET_get_tunnels().
1911 * @return Closure given to GNUNET_CADET_get_tunnels.
1912 */ 1469 */
1913void * 1470void *
1914GNUNET_CADET_get_tunnels_cancel (struct GNUNET_CADET_Handle *h) 1471GNUNET_CADET_get_tunnels_cancel (struct GNUNET_CADET_Handle *h)
1915{ 1472{
1916 void *cls; 1473 void *cls = h->info_cls;
1917 1474
1918 h->info_cb.tunnels_cb = NULL; 1475 h->info_cb.tunnels_cb = NULL;
1919 cls = h->info_cls;
1920 h->info_cls = NULL; 1476 h->info_cls = NULL;
1921
1922 return cls; 1477 return cls;
1923} 1478}
1924 1479
1925 1480
1926
1927/** 1481/**
1928 * Request information about a tunnel of the running cadet peer. 1482 * Request information about a tunnel of the running cadet peer.
1929 * The callback will be called for the tunnel once. 1483 * The callback will be called for the tunnel once.
@@ -1935,7 +1489,6 @@ GNUNET_CADET_get_tunnels_cancel (struct GNUNET_CADET_Handle *h)
1935 * @param id Peer whose tunnel to examine. 1489 * @param id Peer whose tunnel to examine.
1936 * @param callback Function to call with the requested data. 1490 * @param callback Function to call with the requested data.
1937 * @param callback_cls Closure for @c callback. 1491 * @param callback_cls Closure for @c callback.
1938 *
1939 * @return #GNUNET_OK / #GNUNET_SYSERR 1492 * @return #GNUNET_OK / #GNUNET_SYSERR
1940 */ 1493 */
1941int 1494int
@@ -1952,11 +1505,11 @@ GNUNET_CADET_get_tunnel (struct GNUNET_CADET_Handle *h,
1952 GNUNET_break (0); 1505 GNUNET_break (0);
1953 return GNUNET_SYSERR; 1506 return GNUNET_SYSERR;
1954 } 1507 }
1955 1508 env = GNUNET_MQ_msg (msg,
1956 env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL); 1509 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL);
1957 msg->peer = *id; 1510 msg->peer = *id;
1958 GNUNET_MQ_send (h->mq, env); 1511 GNUNET_MQ_send (h->mq,
1959 1512 env);
1960 h->info_cb.tunnel_cb = callback; 1513 h->info_cb.tunnel_cb = callback;
1961 h->info_cls = callback_cls; 1514 h->info_cls = callback_cls;
1962 return GNUNET_OK; 1515 return GNUNET_OK;
@@ -1964,175 +1517,190 @@ GNUNET_CADET_get_tunnel (struct GNUNET_CADET_Handle *h,
1964 1517
1965 1518
1966/** 1519/**
1967 * Request information about a specific channel of the running cadet peer. 1520 * Transitional function to convert an unsigned int port to a hash value.
1968 * 1521 * WARNING: local static value returned, NOT reentrant!
1969 * WARNING: unstable API, likely to change in the future! 1522 * WARNING: do not use this function for new code!
1970 * FIXME Add destination option.
1971 * 1523 *
1972 * @param h Handle to the cadet peer. 1524 * @param port Numerical port (unsigned int format).
1973 * @param initiator ID of the owner of the channel.
1974 * @param channel_number Channel number.
1975 * @param callback Function to call with the requested data.
1976 * @param callback_cls Closure for @c callback.
1977 * 1525 *
1978 * @return #GNUNET_OK / #GNUNET_SYSERR 1526 * @return A GNUNET_HashCode usable for the new CADET API.
1979 */ 1527 */
1980int 1528const struct GNUNET_HashCode *
1981GNUNET_CADET_show_channel (struct GNUNET_CADET_Handle *h, 1529GC_u2h (uint32_t port)
1982 struct GNUNET_PeerIdentity *initiator,
1983 unsigned int channel_number,
1984 GNUNET_CADET_ChannelCB callback,
1985 void *callback_cls)
1986{ 1530{
1987 struct GNUNET_CADET_LocalInfo *msg; 1531 static struct GNUNET_HashCode hash;
1988 struct GNUNET_MQ_Envelope *env;
1989
1990 if (NULL != h->info_cb.channel_cb)
1991 {
1992 GNUNET_break (0);
1993 return GNUNET_SYSERR;
1994 }
1995
1996 env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CHANNEL);
1997 msg->peer = *initiator;
1998 msg->ccn.channel_of_client = htonl (channel_number);
1999 GNUNET_MQ_send (h->mq, env);
2000 1532
2001 h->info_cb.channel_cb = callback; 1533 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2002 h->info_cls = callback_cls; 1534 "This is a transitional function, use proper crypto hashes as CADET ports\n");
2003 return GNUNET_OK; 1535 GNUNET_CRYPTO_hash (&port,
1536 sizeof (port),
1537 &hash);
1538 return &hash;
2004} 1539}
2005 1540
2006 1541
2007/** 1542/**
2008 * Function called to notify a client about the connection 1543 * Connect to the MQ-based cadet service.
2009 * begin ready to queue more data. "buf" will be
2010 * NULL and "size" zero if the connection was closed for
2011 * writing in the meantime.
2012 * 1544 *
2013 * @param cls closure 1545 * @param cfg Configuration to use.
2014 * @param size number of bytes available in buf 1546 *
2015 * @param buf where the callee should write the message 1547 * @return Handle to the cadet service NULL on error.
2016 * @return number of bytes written to buf
2017 */ 1548 */
2018static size_t 1549struct GNUNET_CADET_Handle *
2019cadet_mq_ntr (void *cls, size_t size, 1550GNUNET_CADET_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
2020 void *buf)
2021{ 1551{
2022 struct GNUNET_MQ_Handle *mq = cls; 1552 struct GNUNET_CADET_Handle *h;
2023 struct CadetMQState *state = GNUNET_MQ_impl_state (mq);
2024 const struct GNUNET_MessageHeader *msg = GNUNET_MQ_impl_current (mq);
2025 uint16_t msize;
2026 1553
2027 state->th = NULL; 1554 LOG (GNUNET_ERROR_TYPE_DEBUG,
2028 if (NULL == buf) 1555 "GNUNET_CADET_connect()\n");
1556 h = GNUNET_new (struct GNUNET_CADET_Handle);
1557 h->cfg = cfg;
1558 h->ports = GNUNET_CONTAINER_multihashmap_create (4,
1559 GNUNET_YES);
1560 h->channels = GNUNET_CONTAINER_multihashmap32_create (4);
1561 reconnect (h);
1562 if (NULL == h->mq)
2029 { 1563 {
2030 GNUNET_MQ_inject_error (mq, GNUNET_MQ_ERROR_WRITE); 1564 GNUNET_break (0);
2031 return 0; 1565 GNUNET_CADET_disconnect (h);
1566 return NULL;
2032 } 1567 }
2033 msize = ntohs (msg->size); 1568 h->next_ccn.channel_of_client = htonl (GNUNET_CADET_LOCAL_CHANNEL_ID_CLI);
2034 GNUNET_assert (msize <= size); 1569 h->reconnect_time = GNUNET_TIME_UNIT_MILLISECONDS;
2035 GNUNET_memcpy (buf, msg, msize); 1570 h->reconnect_task = NULL;
2036 GNUNET_MQ_impl_send_continue (mq); 1571
2037 return msize; 1572 return h;
2038} 1573}
2039 1574
2040 1575
2041/** 1576/**
2042 * Signature of functions implementing the 1577 * Open a port to receive incomming MQ-based channels.
2043 * sending functionality of a message queue.
2044 * 1578 *
2045 * @param mq the message queue 1579 * @param h CADET handle.
2046 * @param msg the message to send 1580 * @param port Hash identifying the port.
2047 * @param impl_state state of the implementation 1581 * @param connects Function called when an incoming channel is connected.
1582 * @param connects_cls Closure for the @a connects handler.
1583 * @param window_changes Function called when the transmit window size changes.
1584 * @param disconnects Function called when a channel is disconnected.
1585 * @param handlers Callbacks for messages we care about, NULL-terminated.
1586 * @return Port handle.
2048 */ 1587 */
2049static void 1588struct GNUNET_CADET_Port *
2050cadet_mq_send_impl (struct GNUNET_MQ_Handle *mq, 1589GNUNET_CADET_open_port (struct GNUNET_CADET_Handle *h,
2051 const struct GNUNET_MessageHeader *msg, 1590 const struct GNUNET_HashCode *port,
2052 void *impl_state) 1591 GNUNET_CADET_ConnectEventHandler connects,
1592 void * connects_cls,
1593 GNUNET_CADET_WindowSizeEventHandler window_changes,
1594 GNUNET_CADET_DisconnectEventHandler disconnects,
1595 const struct GNUNET_MQ_MessageHandler *handlers)
2053{ 1596{
2054 struct CadetMQState *state = impl_state; 1597 struct GNUNET_CADET_PortMessage *msg;
2055 1598 struct GNUNET_MQ_Envelope *env;
2056 GNUNET_assert (NULL == state->th); 1599 struct GNUNET_CADET_Port *p;
2057 state->th =
2058 GNUNET_CADET_notify_transmit_ready (state->channel,
2059 /* FIXME: add option for corking */
2060 GNUNET_NO,
2061 GNUNET_TIME_UNIT_FOREVER_REL,
2062 ntohs (msg->size),
2063 &cadet_mq_ntr, mq);
2064
2065}
2066 1600
1601 GNUNET_assert (NULL != connects);
1602 GNUNET_assert (NULL != disconnects);
2067 1603
2068/** 1604 p = GNUNET_new (struct GNUNET_CADET_Port);
2069 * Signature of functions implementing the 1605 p->cadet = h;
2070 * destruction of a message queue. 1606 p->id = *port;
2071 * Implementations must not free 'mq', but should 1607 p->connects = connects;
2072 * take care of 'impl_state'. 1608 p->cls = connects_cls;
2073 * 1609 p->window_changes = window_changes;
2074 * @param mq the message queue to destroy 1610 p->disconnects = disconnects;
2075 * @param impl_state state of the implementation 1611 p->handlers = GNUNET_MQ_copy_handlers (handlers);
2076 */
2077static void
2078cadet_mq_destroy_impl (struct GNUNET_MQ_Handle *mq,
2079 void *impl_state)
2080{
2081 struct CadetMQState *state = impl_state;
2082 1612
2083 if (NULL != state->th) 1613 GNUNET_assert (GNUNET_OK ==
2084 GNUNET_CADET_notify_transmit_ready_cancel (state->th); 1614 GNUNET_CONTAINER_multihashmap_put (h->ports,
1615 &p->id,
1616 p,
1617 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2085 1618
2086 GNUNET_free (state); 1619 env = GNUNET_MQ_msg (msg,
1620 GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_OPEN);
1621 msg->port = p->id;
1622 GNUNET_MQ_send (h->mq,
1623 env);
1624 return p;
2087} 1625}
2088 1626
2089 1627
2090/** 1628/**
2091 * Create a message queue for a cadet channel. 1629 * Create a new channel towards a remote peer.
2092 * The message queue can only be used to transmit messages,
2093 * not to receive them.
2094 * 1630 *
2095 * @param channel the channel to create the message qeue for 1631 * If the destination port is not open by any peer or the destination peer
2096 * @return a message queue to messages over the channel 1632 * does not accept the channel, #GNUNET_CADET_ChannelEndHandler will be called
1633 * for this channel.
1634 *
1635 * @param h CADET handle.
1636 * @param channel_cls Closure for the channel. It's given to:
1637 * - The disconnect handler @a disconnects
1638 * - Each message type callback in @a handlers
1639 * @param destination Peer identity the channel should go to.
1640 * @param port Identification of the destination port.
1641 * @param options CadetOption flag field, with all desired option bits set to 1.
1642 * @param window_changes Function called when the transmit window size changes.
1643 * @param disconnects Function called when the channel is disconnected.
1644 * @param handlers Callbacks for messages we care about, NULL-terminated.
1645 * @return Handle to the channel.
2097 */ 1646 */
2098struct GNUNET_MQ_Handle * 1647struct GNUNET_CADET_Channel *
2099GNUNET_CADET_mq_create (struct GNUNET_CADET_Channel *channel) 1648GNUNET_CADET_channel_create (struct GNUNET_CADET_Handle *h,
1649 void *channel_cls,
1650 const struct GNUNET_PeerIdentity *destination,
1651 const struct GNUNET_HashCode *port,
1652 enum GNUNET_CADET_ChannelOption options,
1653 GNUNET_CADET_WindowSizeEventHandler window_changes,
1654 GNUNET_CADET_DisconnectEventHandler disconnects,
1655 const struct GNUNET_MQ_MessageHandler *handlers)
2100{ 1656{
2101 struct GNUNET_MQ_Handle *mq; 1657 struct GNUNET_CADET_Channel *ch;
2102 struct CadetMQState *state; 1658 struct GNUNET_CADET_LocalChannelCreateMessage *msg;
2103 1659 struct GNUNET_MQ_Envelope *env;
2104 state = GNUNET_new (struct CadetMQState); 1660
2105 state->channel = channel; 1661 GNUNET_assert (NULL != disconnects);
2106 1662 ch = create_channel (h,
2107 mq = GNUNET_MQ_queue_for_callbacks (&cadet_mq_send_impl, 1663 NULL);
2108 &cadet_mq_destroy_impl, 1664 ch->ctx = channel_cls;
2109 NULL, /* FIXME: cancel impl. */ 1665 ch->peer = *destination;
2110 state, 1666 ch->options = options;
2111 NULL, /* no msg handlers */ 1667 ch->window_changes = window_changes;
2112 NULL, /* no err handlers */ 1668 ch->disconnects = disconnects;
2113 NULL); /* no handler cls */ 1669
2114 return mq; 1670 /* Create MQ for channel */
1671 ch->mq = GNUNET_MQ_queue_for_callbacks (&cadet_mq_send_impl,
1672 &cadet_mq_destroy_impl,
1673 &cadet_mq_cancel_impl,
1674 ch,
1675 handlers,
1676 &cadet_mq_error_handler,
1677 ch);
1678 GNUNET_MQ_set_handlers_closure (ch->mq, channel_cls);
1679
1680 /* Request channel creation to service */
1681 env = GNUNET_MQ_msg (msg,
1682 GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_CREATE);
1683 msg->ccn = ch->ccn;
1684 msg->port = *port;
1685 msg->peer = *destination;
1686 msg->opt = htonl (options);
1687 GNUNET_MQ_send (h->mq,
1688 env);
1689 return ch;
2115} 1690}
2116 1691
2117 1692
2118/** 1693/**
2119 * Transitional function to convert an unsigned int port to a hash value. 1694 * Obtain the message queue for a connected peer.
2120 * WARNING: local static value returned, NOT reentrant!
2121 * WARNING: do not use this function for new code!
2122 * 1695 *
2123 * @param port Numerical port (unsigned int format). 1696 * @param channel The channel handle from which to get the MQ.
2124 * 1697 *
2125 * @return A GNUNET_HashCode usable for the new CADET API. 1698 * @return NULL if @a channel is not yet connected.
2126 */ 1699 */
2127const struct GNUNET_HashCode * 1700struct GNUNET_MQ_Handle *
2128GC_u2h (uint32_t port) 1701GNUNET_CADET_get_mq (const struct GNUNET_CADET_Channel *channel)
2129{ 1702{
2130 static struct GNUNET_HashCode hash; 1703 return channel->mq;
2131
2132 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2133 "This is a transitional function, "
2134 "use proper crypto hashes as CADET ports\n");
2135 GNUNET_CRYPTO_hash (&port, sizeof (port), &hash);
2136
2137 return &hash;
2138} 1704}
1705
1706/* 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 5ec34f7d7..de0cec5d0 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_
@@ -67,9 +69,12 @@ struct GNUNET_CADET_ConnectionCreateMessage
67 struct GNUNET_MessageHeader header; 69 struct GNUNET_MessageHeader header;
68 70
69 /** 71 /**
70 * For alignment. 72 * Connection options in network byte order.
73 * #GNUNET_CADET_OPTION_DEFAULT for buffered;
74 * #GNUNET_CADET_OPTION_NOBUFFER for unbuffered.
75 * Other flags are ignored and should not be set at this level.
71 */ 76 */
72 uint32_t reserved GNUNET_PACKED; 77 uint32_t options GNUNET_PACKED;
73 78
74 /** 79 /**
75 * ID of the connection 80 * ID of the connection
@@ -205,7 +210,9 @@ enum GNUNET_CADET_KX_Flags {
205struct GNUNET_CADET_TunnelKeyExchangeMessage 210struct GNUNET_CADET_TunnelKeyExchangeMessage
206{ 211{
207 /** 212 /**
208 * Type: #GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX. 213 * Type: #GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX or
214 * #GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX_AUTH as part
215 * of `struct GNUNET_CADET_TunnelKeyExchangeAuthMessage`.
209 */ 216 */
210 struct GNUNET_MessageHeader header; 217 struct GNUNET_MessageHeader header;
211 218
@@ -234,50 +241,36 @@ struct GNUNET_CADET_TunnelKeyExchangeMessage
234 */ 241 */
235 struct GNUNET_CRYPTO_EcdhePublicKey ratchet_key; 242 struct GNUNET_CRYPTO_EcdhePublicKey ratchet_key;
236 243
237#ifdef NEW_CADET
238 /**
239 * Proof that sender could compute the 3-DH, in lieu of a signature.
240 */
241 struct GNUNET_HashCode triple_dh_proof;
242#endif
243}; 244};
244 245
245 246
246/** 247/**
247 * Axolotl tunnel message. 248 * Message for a Key eXchange for a tunnel, with authentication.
249 * Used as a response to the initial KX as well as for rekeying.
248 */ 250 */
249struct GNUNET_CADET_TunnelEncryptedMessage 251struct GNUNET_CADET_TunnelKeyExchangeAuthMessage
250{ 252{
251 /**
252 * Type: #GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED
253 */
254 struct GNUNET_MessageHeader header;
255 253
256#if NEW_CADET
257 /** 254 /**
258 * Reserved, for alignment. 255 * Message header with key material.
259 */ 256 */
260 uint32_t reserved GNUNET_PACKED; 257 struct GNUNET_CADET_TunnelKeyExchangeMessage kx;
261#else
262 /**
263 * Maximum packet ID authorized.
264 */
265 struct CadetEncryptedMessageIdentifier cemi;
266#endif
267 258
268 /** 259 /**
269 * ID of the connection. 260 * KDF-proof that sender could compute the 3-DH, used in lieu of a
261 * signature or payload data.
270 */ 262 */
271 struct GNUNET_CADET_ConnectionTunnelIdentifier cid; 263 struct GNUNET_HashCode auth;
264
265};
272 266
273 /**
274 * MAC of the encrypted message, used to verify message integrity.
275 * Everything after this value will be encrypted with the header key
276 * and authenticated.
277 */
278 struct GNUNET_ShortHashCode hmac;
279 267
280 /**************** AX_HEADER start ****************/ 268/**
269 * Encrypted axolotl header with numbers that identify which
270 * keys in which ratchet are to be used to decrypt the body.
271 */
272struct GNUNET_CADET_AxHeader
273{
281 274
282 /** 275 /**
283 * Number of messages sent with the current ratchet key. 276 * Number of messages sent with the current ratchet key.
@@ -294,68 +287,47 @@ struct GNUNET_CADET_TunnelEncryptedMessage
294 */ 287 */
295 struct GNUNET_CRYPTO_EcdhePublicKey DHRs; 288 struct GNUNET_CRYPTO_EcdhePublicKey DHRs;
296 289
297 /**************** AX_HEADER end ****************/
298
299 /**
300 * Encrypted content follows.
301 */
302}; 290};
303 291
304 292
305#ifndef NEW_CADET
306
307/** 293/**
308 * Message to query a peer about its Flow Control status regarding a tunnel. 294 * Axolotl-encrypted tunnel message with application payload.
309 *
310 * It is NOT yet clear if we need this.
311 */ 295 */
312struct GNUNET_CADET_ConnectionHopByHopPollMessage 296struct GNUNET_CADET_TunnelEncryptedMessage
313{ 297{
314 /** 298 /**
315 * Type: #GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED_POLL 299 * Type: #GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED
316 */ 300 */
317 struct GNUNET_MessageHeader header; 301 struct GNUNET_MessageHeader header;
318 302
319 /** 303 /**
320 * Last packet sent. 304 * Reserved, for alignment.
321 */ 305 */
322 struct CadetEncryptedMessageIdentifier cemi; 306 uint32_t reserved GNUNET_PACKED;
323 307
324 /** 308 /**
325 * ID of the connection. 309 * ID of the connection.
326 */ 310 */
327 struct GNUNET_CADET_ConnectionTunnelIdentifier cid; 311 struct GNUNET_CADET_ConnectionTunnelIdentifier cid;
328 312
329};
330
331
332/**
333 * Message to acknowledge cadet encrypted traffic, used for
334 * flow-control on a hop-by-hop basis on the connection-level. Note
335 * that we do use the @e cemi from the tunnel layer as the connection
336 * layer's header is included/shared with the tunnel layer messages,
337 * and we only do flow control for the payload.
338 */
339struct GNUNET_CADET_ConnectionEncryptedAckMessage
340{
341 /** 313 /**
342 * Type: #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_HOP_BY_HOP_ENCRYPTED_ACK 314 * MAC of the encrypted message, used to verify message integrity.
315 * Everything after this value will be encrypted with the header key
316 * and authenticated.
343 */ 317 */
344 struct GNUNET_MessageHeader header; 318 struct GNUNET_ShortHashCode hmac;
345 319
346 /** 320 /**
347 * Maximum packet ID authorized. 321 * Axolotl-header that specifies which keys to use in which ratchet
322 * to decrypt the body that follows.
348 */ 323 */
349 struct CadetEncryptedMessageIdentifier cemi_max; 324 struct GNUNET_CADET_AxHeader ax_header;
350 325
351 /** 326 /**
352 * ID of the connection. 327 * Encrypted content follows.
353 */ 328 */
354 struct GNUNET_CADET_ConnectionTunnelIdentifier cid;
355}; 329};
356 330
357#endif
358
359 331
360/******************************************************************************/ 332/******************************************************************************/
361/******************************* CHANNEL ***********************************/ 333/******************************* CHANNEL ***********************************/
@@ -378,9 +350,9 @@ struct GNUNET_CADET_ChannelOpenMessage
378 uint32_t opt GNUNET_PACKED; 350 uint32_t opt GNUNET_PACKED;
379 351
380 /** 352 /**
381 * Destination port. 353 * Hash of destination port and listener.
382 */ 354 */
383 struct GNUNET_HashCode port; 355 struct GNUNET_HashCode h_port;
384 356
385 /** 357 /**
386 * ID of the channel within the tunnel. 358 * ID of the channel within the tunnel.
@@ -390,93 +362,56 @@ struct GNUNET_CADET_ChannelOpenMessage
390 362
391 363
392/** 364/**
393 * Message to manage a Channel 365 * Message to acknowledge opening a channel of type
394 * (#GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK, 366 * #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK.
395 * #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY).
396 */ 367 */
397struct GNUNET_CADET_ChannelManageMessage 368struct GNUNET_CADET_ChannelOpenAckMessage
398{ 369{
399 /** 370 /**
400 * Type: #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK or 371 * Type: #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK
401 * #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY
402 */ 372 */
403 struct GNUNET_MessageHeader header; 373 struct GNUNET_MessageHeader header;
404 374
405#ifdef NEW_CADET
406 /** 375 /**
407 * For alignment. 376 * For alignment.
408 */ 377 */
409 uint32_t reserved GNUNET_PACKED; 378 uint32_t reserved GNUNET_PACKED;
410#endif
411 379
412 /** 380 /**
413 * ID of the channel 381 * ID of the channel
414 */ 382 */
415 struct GNUNET_CADET_ChannelTunnelNumber ctn; 383 struct GNUNET_CADET_ChannelTunnelNumber ctn;
416};
417
418
419#ifndef NEW_CADET
420
421/**
422 * Message for cadet data traffic.
423 */
424struct GNUNET_CADET_ChannelAppDataMessage
425{
426 /**
427 * Type: #GNUNET_MESSAGE_TYPE_CADET_UNICAST,
428 * #GNUNET_MESSAGE_TYPE_CADET_TO_ORIGIN
429 */
430 struct GNUNET_MessageHeader header;
431
432 /**
433 * Unique ID of the payload message
434 */
435 /* NEW: struct ChannelMessageIdentifier */
436 uint32_t mid GNUNET_PACKED;
437 384
438 /** 385 /**
439 * ID of the channel 386 * Port number of the channel, used to prove to the
440 */ 387 * initiator that the receiver knows the port.
441 struct GNUNET_CADET_ChannelTunnelNumber ctn;
442
443 /**
444 * Payload follows
445 */ 388 */
389 struct GNUNET_HashCode port;
446}; 390};
447 391
448 392
449/** 393/**
450 * Message to acknowledge end-to-end data. 394 * Message to destroy a channel of type
395 * #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY.
451 */ 396 */
452struct GNUNET_CADET_ChannelDataAckMessage 397struct GNUNET_CADET_ChannelDestroyMessage
453{ 398{
454 /** 399 /**
455 * Type: #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK 400 * Type: #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY
456 */ 401 */
457 struct GNUNET_MessageHeader header; 402 struct GNUNET_MessageHeader header;
458 403
459 /** 404 /**
460 * ID of the channel 405 * For alignment.
461 */
462 struct GNUNET_CADET_ChannelTunnelNumber ctn;
463
464 /**
465 * Bitfield of already-received newer messages
466 * pid + 1 @ LSB
467 * pid + 64 @ MSB
468 */ 406 */
469 uint64_t futures GNUNET_PACKED; 407 uint32_t reserved GNUNET_PACKED;
470 408
471 /** 409 /**
472 * Last message ID received. 410 * ID of the channel
473 */ 411 */
474 /* NEW: struct ChannelMessageIdentifier */ 412 struct GNUNET_CADET_ChannelTunnelNumber ctn;
475 uint32_t mid GNUNET_PACKED;
476}; 413};
477 414
478#else
479
480 415
481/** 416/**
482 * Number used to uniquely identify messages in a CADET Channel. 417 * Number used to uniquely identify messages in a CADET Channel.
@@ -532,21 +467,21 @@ struct GNUNET_CADET_ChannelDataAckMessage
532 struct GNUNET_CADET_ChannelTunnelNumber ctn; 467 struct GNUNET_CADET_ChannelTunnelNumber ctn;
533 468
534 /** 469 /**
535 * Bitfield of already-received messages past @e mid. 470 * Bitfield of already-received newer messages. Note that bit 0
536 * pid + 1 @ LSB 471 * corresponds to @e mid + 1.
537 * pid + 64 @ MSB 472 *
473 * pid + 0 @ LSB
474 * pid + 63 @ MSB
538 */ 475 */
539 uint64_t futures GNUNET_PACKED; 476 uint64_t futures GNUNET_PACKED;
540 477
541 /** 478 /**
542 * Last message ID received. 479 * Next message ID expected.
543 */ 480 */
544 struct ChannelMessageIdentifier mid; 481 struct ChannelMessageIdentifier mid;
545}; 482};
546 483
547 484
548#endif
549
550GNUNET_NETWORK_STRUCT_END 485GNUNET_NETWORK_STRUCT_END
551 486
552#if 0 /* keep Emacsens' auto-indent happy */ 487#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/desirability_table.c b/src/cadet/desirability_table.c
new file mode 100644
index 000000000..21ec3e388
--- /dev/null
+++ b/src/cadet/desirability_table.c
@@ -0,0 +1,35 @@
1/* This file is in the public domain. */
2
3/**
4 * @brief Program to simulate results from #GCP_get_desirability_of_path()
5 * for various plausible inputs.
6 * @author Christian Grothoff
7 */
8#include <stdio.h>
9
10int
11main ()
12{
13 for (unsigned int num_alts=1; num_alts<10; num_alts++)
14 for (unsigned int off=0; off<10; off++)
15 for (double delta=-(int) off;delta<=5;delta += 0.25)
16 {
17 double weight_alts;
18
19 if (delta <= - 1.0)
20 weight_alts = - 1.0 * num_alts / delta; /* discount alternative paths */
21 else if (delta >= 1.0)
22 weight_alts = 1.0 * num_alts * delta; /* overcount alternative paths */
23 else
24 weight_alts = 1.0 * num_alts; /* count alternative paths normally */
25
26 fprintf (stderr,
27 "Paths: %u Offset: %u Delta: %5.2f SCORE: %f\n",
28 num_alts,
29 off,
30 delta,
31 ((off + 1.0) / (weight_alts * weight_alts)));
32 }
33
34
35}
diff --git a/src/cadet/gnunet-cadet-profiler.c b/src/cadet/gnunet-cadet-profiler.c
index d688dc60b..15da05b6d 100644
--- a/src/cadet/gnunet-cadet-profiler.c
+++ b/src/cadet/gnunet-cadet-profiler.c
@@ -778,7 +778,9 @@ pong_handler (void *cls, struct GNUNET_CADET_Channel *channel,
778 latency = GNUNET_TIME_absolute_get_duration (send_time); 778 latency = GNUNET_TIME_absolute_get_duration (send_time);
779 r = ntohl (msg->round_number); 779 r = ntohl (msg->round_number);
780 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "%u <- %u (%u) latency: %s\n", 780 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "%u <- %u (%u) latency: %s\n",
781 get_index (peer), get_index (peer->dest), ntohl (msg->counter), 781 get_index (peer),
782 get_index (peer->dest),
783 (uint32_t) ntohl (msg->counter),
782 GNUNET_STRINGS_relative_time_to_string (latency, GNUNET_NO)); 784 GNUNET_STRINGS_relative_time_to_string (latency, GNUNET_NO));
783 785
784 /* Online variance calculation */ 786 /* Online variance calculation */
diff --git a/src/cadet/gnunet-cadet.c b/src/cadet/gnunet-cadet.c
index 80010ec54..675e7faf0 100644
--- a/src/cadet/gnunet-cadet.c
+++ b/src/cadet/gnunet-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) 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
@@ -22,6 +22,7 @@
22 * @file cadet/gnunet-cadet.c 22 * @file cadet/gnunet-cadet.c
23 * @brief Print information about cadet tunnels and peers. 23 * @brief Print information about cadet tunnels and peers.
24 * @author Bartlomiej Polot 24 * @author Bartlomiej Polot
25 * @author Christian Grothoff
25 */ 26 */
26#include "platform.h" 27#include "platform.h"
27#include "gnunet_util_lib.h" 28#include "gnunet_util_lib.h"
@@ -30,11 +31,6 @@
30 31
31 32
32/** 33/**
33 * Option -m.
34 */
35static int monitor_mode;
36
37/**
38 * Option -P. 34 * Option -P.
39 */ 35 */
40static int request_peers; 36static int request_peers;
@@ -100,11 +96,6 @@ static char *target_id;
100static char *target_port = "default"; 96static char *target_port = "default";
101 97
102/** 98/**
103 * Data pending in netcat mode.
104 */
105static size_t data_size;
106
107/**
108 * Cadet handle. 99 * Cadet handle.
109 */ 100 */
110static struct GNUNET_CADET_Handle *mh; 101static struct GNUNET_CADET_Handle *mh;
@@ -115,11 +106,6 @@ static struct GNUNET_CADET_Handle *mh;
115static struct GNUNET_CADET_Channel *ch; 106static struct GNUNET_CADET_Channel *ch;
116 107
117/** 108/**
118 * Transmit handle.
119 */
120static struct GNUNET_CADET_TransmitHandle *th;
121
122/**
123 * HashCode of the given port string 109 * HashCode of the given port string
124 */ 110 */
125static struct GNUNET_HashCode porthash; 111static struct GNUNET_HashCode porthash;
@@ -130,11 +116,6 @@ static struct GNUNET_HashCode porthash;
130struct GNUNET_CADET_Port *lp; 116struct GNUNET_CADET_Port *lp;
131 117
132/** 118/**
133 * Shutdown task handle.
134 */
135static struct GNUNET_SCHEDULER_Task *sd;
136
137/**
138 * Task for reading from stdin. 119 * Task for reading from stdin.
139 */ 120 */
140static struct GNUNET_SCHEDULER_Task *rd_task; 121static struct GNUNET_SCHEDULER_Task *rd_task;
@@ -145,6 +126,9 @@ static struct GNUNET_SCHEDULER_Task *rd_task;
145static struct GNUNET_SCHEDULER_Task *job; 126static struct GNUNET_SCHEDULER_Task *job;
146 127
147 128
129/**
130 * Wait for input on STDIO and send it out over the #ch.
131 */
148static void 132static void
149listen_stdio (void); 133listen_stdio (void);
150 134
@@ -214,22 +198,11 @@ shutdown_task (void *cls)
214{ 198{
215 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 199 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
216 "Shutdown\n"); 200 "Shutdown\n");
217 if (NULL != th)
218 {
219 GNUNET_CADET_notify_transmit_ready_cancel (th);
220 th = NULL;
221 }
222 if (NULL != ch) 201 if (NULL != ch)
223 { 202 {
224 GNUNET_CADET_channel_destroy (ch); 203 GNUNET_CADET_channel_destroy (ch);
225 ch = NULL; 204 ch = NULL;
226 } 205 }
227 else if (NULL != target_id) {
228 // FIXME: would be nicer to have proper NACK support from cadet_api
229 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
230 "Connection refused to %s\n",
231 target_id);
232 }
233 if (NULL != mh) 206 if (NULL != mh)
234 { 207 {
235 GNUNET_CADET_disconnect (mh); 208 GNUNET_CADET_disconnect (mh);
@@ -254,42 +227,38 @@ shutdown_task (void *cls)
254 227
255 228
256/** 229/**
257 * Function called to notify a client about the connection 230 * Task run in stdio mode, after some data is available at stdin.
258 * begin ready to queue more data. "buf" will be
259 * NULL and "size" zero if the connection was closed for
260 * writing in the meantime.
261 *
262 * FIXME
263 * 231 *
264 * @param cls closure 232 * @param cls Closure (unused).
265 * @param size number of bytes available in buf
266 * @param buf where the callee should write the message
267 * @return number of bytes written to buf
268 */ 233 */
269static size_t 234static void
270data_ready (void *cls, size_t size, void *buf) 235read_stdio (void *cls)
271{ 236{
237 struct GNUNET_MQ_Envelope *env;
272 struct GNUNET_MessageHeader *msg; 238 struct GNUNET_MessageHeader *msg;
273 size_t total_size; 239 char buf[60000];
274 240 ssize_t data_size;
275 th = NULL;
276 241
277 if (NULL == buf || 0 == size) 242 rd_task = NULL;
243 data_size = read (0,
244 buf,
245 60000);
246 if (data_size < 1)
278 { 247 {
279 GNUNET_SCHEDULER_shutdown(); 248 GNUNET_SCHEDULER_shutdown();
280 return 0; 249 return;
281 } 250 }
282
283 total_size = data_size + sizeof (struct GNUNET_MessageHeader);
284 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 251 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
285 "sending %u bytes\n", 252 "Read %u bytes from stdio\n",
286 (unsigned int) data_size); 253 (unsigned int) data_size);
287 GNUNET_assert (size >= total_size); 254 env = GNUNET_MQ_msg_extra (msg,
288 255 data_size,
289 msg = buf; 256 GNUNET_MESSAGE_TYPE_CADET_CLI);
290 msg->size = htons (total_size); 257 GNUNET_memcpy (&msg[1],
291 msg->type = htons (GNUNET_MESSAGE_TYPE_CADET_CLI); 258 buf,
292 GNUNET_memcpy (&msg[1], cls, data_size); 259 data_size);
260 GNUNET_MQ_send (GNUNET_CADET_get_mq (ch),
261 env);
293 if (GNUNET_NO == echo) 262 if (GNUNET_NO == echo)
294 { 263 {
295 listen_stdio (); 264 listen_stdio ();
@@ -298,53 +267,27 @@ data_ready (void *cls, size_t size, void *buf)
298 { 267 {
299 echo_time = GNUNET_TIME_absolute_get (); 268 echo_time = GNUNET_TIME_absolute_get ();
300 } 269 }
301
302 return total_size;
303} 270}
304 271
305 272
306/** 273/**
307 * Task run in stdio mode, after some data is available at stdin. 274 * Wait for input on STDIO and send it out over the #ch.
308 *
309 * @param cls Closure (unused).
310 */ 275 */
311static void 276static void
312read_stdio (void *cls) 277listen_stdio ()
313{
314 static char buf[60000];
315
316 data_size = read (0, buf, 60000);
317 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
318 "stdio read %u bytes\n",
319 (unsigned int) data_size);
320 if (data_size < 1)
321 {
322 GNUNET_SCHEDULER_shutdown();
323 return;
324 }
325 GNUNET_assert (NULL == th);
326 th = GNUNET_CADET_notify_transmit_ready (ch, GNUNET_NO,
327 GNUNET_TIME_UNIT_FOREVER_REL,
328 sizeof (struct GNUNET_MessageHeader)
329 + data_size,
330 &data_ready, buf);
331}
332
333
334/**
335 * Start listening to stdin
336 */
337static void
338listen_stdio (void)
339{ 278{
340 struct GNUNET_NETWORK_FDSet *rs; 279 struct GNUNET_NETWORK_FDSet *rs;
341 280
281 /* FIXME: why use 'rs' here, seems overly complicated... */
342 rs = GNUNET_NETWORK_fdset_create (); 282 rs = GNUNET_NETWORK_fdset_create ();
343 GNUNET_NETWORK_fdset_set_native (rs, 0); 283 GNUNET_NETWORK_fdset_set_native (rs,
284 0); /* STDIN */
344 rd_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, 285 rd_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
345 GNUNET_TIME_UNIT_FOREVER_REL, 286 GNUNET_TIME_UNIT_FOREVER_REL,
346 rs, NULL, 287 rs,
347 &read_stdio, NULL); 288 NULL,
289 &read_stdio,
290 NULL);
348 GNUNET_NETWORK_fdset_destroy (rs); 291 GNUNET_NETWORK_fdset_destroy (rs);
349} 292}
350 293
@@ -355,32 +298,17 @@ listen_stdio (void)
355 * 298 *
356 * It must NOT call #GNUNET_CADET_channel_destroy on the channel. 299 * It must NOT call #GNUNET_CADET_channel_destroy on the channel.
357 * 300 *
358 * @param cls closure (set from #GNUNET_CADET_connect) 301 * @param cls closure
359 * @param channel connection to the other end (henceforth invalid) 302 * @param channel connection to the other end (henceforth invalid)
360 * @param channel_ctx place where local state associated
361 * with the channel is stored
362 */ 303 */
363static void 304static void
364channel_ended (void *cls, 305channel_ended (void *cls,
365 const struct GNUNET_CADET_Channel *channel, 306 const struct GNUNET_CADET_Channel *channel)
366 void *channel_ctx)
367{ 307{
368 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Channel ended!\n"); 308 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
369 if (channel != ch) 309 "Channel ended!\n");
370 { 310 GNUNET_assert (channel == ch);
371 GNUNET_break (0); 311 ch = NULL;
372 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ended: %p, expected: %p\n", channel, ch);
373 }
374 else
375 {
376 ch = NULL;
377 }
378 if (NULL != th)
379 {
380 GNUNET_CADET_notify_transmit_ready_cancel (th);
381 th = NULL;
382 }
383
384 GNUNET_SCHEDULER_shutdown (); 312 GNUNET_SCHEDULER_shutdown ();
385} 313}
386 314
@@ -397,65 +325,27 @@ channel_ended (void *cls,
397 * @param cls closure 325 * @param cls closure
398 * @param channel new handle to the channel 326 * @param channel new handle to the channel
399 * @param initiator peer that started the channel 327 * @param initiator peer that started the channel
400 * @param port Port this channel is for. 328 * @return initial channel context for the channel, we use @a channel
401 * @param options CadetOption flag field, with all active option bits set to 1.
402 *
403 * @return initial channel context for the channel
404 * (can be NULL -- that's not an error)
405 */ 329 */
406static void * 330static void *
407channel_incoming (void *cls, 331channel_incoming (void *cls,
408 struct GNUNET_CADET_Channel *channel, 332 struct GNUNET_CADET_Channel *channel,
409 const struct GNUNET_PeerIdentity *initiator, 333 const struct GNUNET_PeerIdentity *initiator)
410 const struct GNUNET_HashCode *port,
411 enum GNUNET_CADET_ChannelOption options)
412{ 334{
413 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, 335 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
414 "Connected from %s\n", 336 "Incoming connection from %s\n",
415 GNUNET_i2s_full (initiator)); 337 GNUNET_i2s_full (initiator));
416 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 338 GNUNET_assert (NULL == ch);
417 "Incoming channel %p on port %s\n", 339 GNUNET_assert (NULL != lp);
418 channel, GNUNET_h2s (port)); 340 GNUNET_CADET_close_port (lp);
419 if (NULL != ch) 341 lp = NULL;
420 {
421 GNUNET_break (0);
422 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
423 "A channel already exists (%p)\n", ch);
424 /*
425 * From now on multiple channels will be sending data to us
426 * making the service of this command unpredictable in its
427 * current implementation. So for now let's just bail out.
428 */
429 GNUNET_SCHEDULER_shutdown();
430 return NULL;
431 }
432 if (NULL == listen_port)
433 {
434 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Not listening to channels\n");
435 return NULL;
436 }
437#if 0
438 // Closing the listen port currently breaks open connections.
439 // Is this an intentional departure from POSIX socket behavior?
440 //
441 if (NULL != lp) {
442 /* Now that we have our circuit up and running, let's not
443 * get confused by further incoming connect requests.
444 */
445 GNUNET_CADET_close_port (lp);
446 lp = NULL;
447 }
448#endif
449 ch = channel; 342 ch = channel;
450 if (GNUNET_NO == echo) 343 if (GNUNET_NO == echo)
451 {
452 listen_stdio (); 344 listen_stdio ();
453 return NULL; 345 return channel;
454 }
455 data_size = 0;
456 return NULL;
457} 346}
458 347
348
459/** 349/**
460 * @brief Send an echo request to the remote peer. 350 * @brief Send an echo request to the remote peer.
461 * 351 *
@@ -464,13 +354,16 @@ channel_incoming (void *cls,
464static void 354static void
465send_echo (void *cls) 355send_echo (void *cls)
466{ 356{
357 struct GNUNET_MQ_Envelope *env;
358 struct GNUNET_MessageHeader *msg;
359
360 echo_task = NULL;
467 if (NULL == ch) 361 if (NULL == ch)
468 return; 362 return;
469 GNUNET_assert (NULL == th); 363 env = GNUNET_MQ_msg (msg,
470 th = GNUNET_CADET_notify_transmit_ready (ch, GNUNET_NO, 364 GNUNET_MESSAGE_TYPE_CADET_CLI);
471 GNUNET_TIME_UNIT_FOREVER_REL, 365 GNUNET_MQ_send (GNUNET_CADET_get_mq (ch),
472 sizeof (struct GNUNET_MessageHeader), 366 env);
473 &data_ready, NULL);
474} 367}
475 368
476 369
@@ -483,44 +376,23 @@ static void
483request_dump (void *cls) 376request_dump (void *cls)
484{ 377{
485 GNUNET_CADET_request_dump (mh); 378 GNUNET_CADET_request_dump (mh);
486 GNUNET_SCHEDULER_cancel (sd); 379 GNUNET_SCHEDULER_shutdown ();
487 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
488 &shutdown_task, NULL);
489} 380}
490 381
491 382
492/** 383/**
493 * Call CADET's monitor API, get info of one connection. 384 * Check data message sanity. Does nothing so far (all messages are OK).
494 * 385 *
495 * @param cls Closure (unused). 386 * @param cls Closure (unused).
387 * @param message The message to check.
388 * @return #GNUNET_OK to keep the channel open,
389 * #GNUNET_SYSERR to close it (signal serious error).
496 */ 390 */
497static void 391static int
498create_channel (void *cls) 392check_data (void *cls,
393 const struct GNUNET_MessageHeader *message)
499{ 394{
500 struct GNUNET_PeerIdentity pid; 395 return GNUNET_OK; /* all is well-formed */
501 enum GNUNET_CADET_ChannelOption opt;
502
503 GNUNET_assert (NULL == ch);
504
505 if (GNUNET_OK !=
506 GNUNET_CRYPTO_eddsa_public_key_from_string (target_id,
507 strlen (target_id),
508 &pid.public_key))
509 {
510 FPRINTF (stderr,
511 _("Invalid target `%s'\n"),
512 target_id);
513 GNUNET_SCHEDULER_shutdown ();
514 return;
515 }
516 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to `%s'\n", target_id);
517 opt = GNUNET_CADET_OPTION_DEFAULT | GNUNET_CADET_OPTION_RELIABLE;
518 GNUNET_CRYPTO_hash (target_port, strlen(target_port), &porthash);
519 ch = GNUNET_CADET_channel_create (mh, NULL, &pid, &porthash, opt);
520 if (GNUNET_NO == echo)
521 listen_stdio ();
522 else
523 echo_task = GNUNET_SCHEDULER_add_now (&send_echo, NULL);
524} 396}
525 397
526 398
@@ -531,42 +403,36 @@ create_channel (void *cls)
531 * in order to receive the next message. This doesn't need to be immediate: 403 * in order to receive the next message. This doesn't need to be immediate:
532 * can be delayed if some processing is done on the message. 404 * can be delayed if some processing is done on the message.
533 * 405 *
534 * @param cls Closure (set from #GNUNET_CADET_connect). 406 * @param cls NULL
535 * @param channel Connection to the other end.
536 * @param channel_ctx Place to store local state associated with the channel.
537 * @param message The actual message. 407 * @param message The actual message.
538 * @return #GNUNET_OK to keep the channel open,
539 * #GNUNET_SYSERR to close it (signal serious error).
540 */ 408 */
541static int 409static void
542data_callback (void *cls, 410handle_data (void *cls,
543 struct GNUNET_CADET_Channel *channel, 411 const struct GNUNET_MessageHeader *message)
544 void **channel_ctx,
545 const struct GNUNET_MessageHeader *message)
546{ 412{
413 size_t payload_size = ntohs (message->size) - sizeof (*message);
547 uint16_t len; 414 uint16_t len;
548 ssize_t done; 415 ssize_t done;
549 uint16_t off; 416 uint16_t off;
550 const char *buf; 417 const char *buf;
551 GNUNET_break (ch == channel);
552 GNUNET_CADET_receive_done (channel);
553 418
419 GNUNET_CADET_receive_done (ch);
554 if (GNUNET_YES == echo) 420 if (GNUNET_YES == echo)
555 { 421 {
556 if (NULL != listen_port) 422 if (NULL != listen_port)
557 { 423 {
558 /* Just listening to echo incoming messages*/ 424 struct GNUNET_MQ_Envelope *env;
559 if (NULL != th) 425 struct GNUNET_MessageHeader *msg;
560 { 426
561 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 427 env = GNUNET_MQ_msg_extra (msg,
562 "Last echo reply not yet sent, dropping current reply.\n"); 428 payload_size,
563 return GNUNET_OK; 429 GNUNET_MESSAGE_TYPE_CADET_CLI);
564 } 430 GNUNET_memcpy (&msg[1],
565 th = GNUNET_CADET_notify_transmit_ready (channel, GNUNET_NO, 431 &message[1],
566 GNUNET_TIME_UNIT_FOREVER_REL, 432 payload_size);
567 sizeof (struct GNUNET_MessageHeader), 433 GNUNET_MQ_send (GNUNET_CADET_get_mq (ch),
568 &data_ready, NULL); 434 env);
569 return GNUNET_OK; 435 return;
570 } 436 }
571 else 437 else
572 { 438 {
@@ -574,30 +440,37 @@ data_callback (void *cls,
574 440
575 latency = GNUNET_TIME_absolute_get_duration (echo_time); 441 latency = GNUNET_TIME_absolute_get_duration (echo_time);
576 echo_time = GNUNET_TIME_UNIT_FOREVER_ABS; 442 echo_time = GNUNET_TIME_UNIT_FOREVER_ABS;
577 FPRINTF (stdout, "time: %s\n", 443 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
578 GNUNET_STRINGS_relative_time_to_string (latency, GNUNET_NO)); 444 "time: %s\n",
445 GNUNET_STRINGS_relative_time_to_string (latency,
446 GNUNET_NO));
579 echo_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, 447 echo_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
580 &send_echo, NULL); 448 &send_echo,
449 NULL);
581 } 450 }
582 } 451 }
583 452
584 len = ntohs (message->size) - sizeof (*message); 453 len = ntohs (message->size) - sizeof (*message);
585 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got %u bytes\n", len); 454 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
455 "Got %u bytes\n",
456 len);
586 buf = (const char *) &message[1]; 457 buf = (const char *) &message[1];
587 off = 0; 458 off = 0;
588 while (off < len) 459 while (off < len)
589 { 460 {
590 done = write (1, &buf[off], len - off); 461 done = write (1,
462 &buf[off],
463 len - off);
591 if (done <= 0) 464 if (done <= 0)
592 { 465 {
593 if (-1 == done) 466 if (-1 == done)
594 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, 467 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
595 "write"); 468 "write");
596 return GNUNET_SYSERR; 469 GNUNET_SCHEDULER_shutdown ();
470 return;
597 } 471 }
598 off += done; 472 off += done;
599 } 473 }
600 return GNUNET_OK;
601} 474}
602 475
603 476
@@ -623,16 +496,17 @@ peers_callback (void *cls,
623{ 496{
624 if (NULL == peer) 497 if (NULL == peer)
625 { 498 {
626 if (GNUNET_YES != monitor_mode) 499 GNUNET_SCHEDULER_shutdown();
627 {
628 GNUNET_SCHEDULER_shutdown();
629 }
630 return; 500 return;
631 } 501 }
632 FPRINTF (stdout, "%s tunnel: %c, paths: %u\n", 502 FPRINTF (stdout,
633 GNUNET_i2s_full (peer), tunnel ? 'Y' : 'N', n_paths); 503 "%s tunnel: %c, paths: %u\n",
504 GNUNET_i2s_full (peer),
505 tunnel ? 'Y' : 'N',
506 n_paths);
634} 507}
635 508
509
636/** 510/**
637 * Method called to retrieve information about a specific peer 511 * Method called to retrieve information about a specific peer
638 * known to the service. 512 * known to the service.
@@ -652,19 +526,26 @@ peer_callback (void *cls,
652 int tunnel, 526 int tunnel,
653 int neighbor, 527 int neighbor,
654 unsigned int n_paths, 528 unsigned int n_paths,
655 struct GNUNET_PeerIdentity *paths) 529 const struct GNUNET_PeerIdentity *paths)
656{ 530{
657 unsigned int i; 531 unsigned int i;
658 struct GNUNET_PeerIdentity *p; 532 const struct GNUNET_PeerIdentity *p;
659 533
660 FPRINTF (stdout, "%s [TUNNEL: %s, NEIGHBOR: %s, PATHS: %u]\n", 534 FPRINTF (stdout,
535 "%s [TUNNEL: %s, NEIGHBOR: %s, PATHS: %u]\n",
661 GNUNET_i2s_full (peer), 536 GNUNET_i2s_full (peer),
662 tunnel ? "Y" : "N", neighbor ? "Y" : "N", n_paths); 537 tunnel ? "Y" : "N",
538 neighbor ? "Y" : "N",
539 n_paths);
663 p = paths; 540 p = paths;
664 for (i = 0; i < n_paths && NULL != p;) 541 for (i = 0; i < n_paths && NULL != p;)
665 { 542 {
666 FPRINTF (stdout, "%s ", GNUNET_i2s (p)); 543 FPRINTF (stdout,
667 if (0 == memcmp (p, peer, sizeof (*p))) 544 "%s ",
545 GNUNET_i2s (p));
546 if (0 == memcmp (p,
547 peer,
548 sizeof (*p)))
668 { 549 {
669 FPRINTF (stdout, "\n"); 550 FPRINTF (stdout, "\n");
670 i++; 551 i++;
@@ -696,16 +577,16 @@ tunnels_callback (void *cls,
696{ 577{
697 if (NULL == peer) 578 if (NULL == peer)
698 { 579 {
699 if (GNUNET_YES != monitor_mode) 580 GNUNET_SCHEDULER_shutdown();
700 {
701 GNUNET_SCHEDULER_shutdown();
702 }
703 return; 581 return;
704 } 582 }
705 FPRINTF (stdout, "%s [ENC: %s, CON: %s] CHs: %u, CONNs: %u\n", 583 FPRINTF (stdout,
584 "%s [ENC: %s, CON: %s] CHs: %u, CONNs: %u\n",
706 GNUNET_i2s_full (peer), 585 GNUNET_i2s_full (peer),
707 enc_2s (estate), conn_2s (cstate), 586 enc_2s (estate),
708 channels, connections); 587 conn_2s (cstate),
588 channels,
589 connections);
709} 590}
710 591
711 592
@@ -746,11 +627,7 @@ tunnel_callback (void *cls,
746 FPRINTF (stdout, "\tencryption state: %s\n", enc_2s (estate)); 627 FPRINTF (stdout, "\tencryption state: %s\n", enc_2s (estate));
747 FPRINTF (stdout, "\tconnection state: %s\n", conn_2s (cstate)); 628 FPRINTF (stdout, "\tconnection state: %s\n", conn_2s (cstate));
748 } 629 }
749 if (GNUNET_YES != monitor_mode) 630 GNUNET_SCHEDULER_shutdown ();
750 {
751 GNUNET_SCHEDULER_shutdown ();
752 }
753 return;
754} 631}
755 632
756 633
@@ -874,93 +751,158 @@ run (void *cls,
874 const char *cfgfile, 751 const char *cfgfile,
875 const struct GNUNET_CONFIGURATION_Handle *cfg) 752 const struct GNUNET_CONFIGURATION_Handle *cfg)
876{ 753{
877 static const struct GNUNET_CADET_MessageHandler handlers[] = { 754 struct GNUNET_MQ_MessageHandler handlers[] = {
878 {&data_callback, GNUNET_MESSAGE_TYPE_CADET_CLI, 0}, 755 GNUNET_MQ_hd_var_size (data,
879 {NULL, 0, 0} /* FIXME add option to monitor msg types */ 756 GNUNET_MESSAGE_TYPE_CADET_CLI,
757 struct GNUNET_MessageHeader,
758 NULL),
759 GNUNET_MQ_handler_end ()
880 }; 760 };
881 761
882 /* FIXME add option to monitor apps */ 762 /* FIXME add option to monitor apps */
883 763
884 target_id = args[0]; 764 target_id = args[0];
885 if (target_id && args[1]) target_port = args[1]; 765 if (target_id && args[1])
766 target_port = args[1];
886 767
887 if ( (0 != (request_peers | request_tunnels) 768 if ( (0 != (request_peers | request_tunnels)
888 || 0 != monitor_mode
889 || NULL != tunnel_id 769 || NULL != tunnel_id
890 || NULL != conn_id 770 || NULL != conn_id
891 || NULL != channel_id) 771 || NULL != channel_id)
892 && target_id != NULL) 772 && target_id != NULL)
893 { 773 {
894 FPRINTF (stderr, 774 FPRINTF (stderr,
895 _("You must NOT give a TARGET " 775 _("Extra arguments are not applicable "
896 "when using 'request all' options\n")); 776 "in combination with this option.\n"));
897 return; 777 return;
898 } 778 }
899 779
900 if (GNUNET_YES == dump) 780 if (GNUNET_YES == dump)
901 { 781 {
902 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 782 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
903 "requesting debug dump\n"); 783 "Requesting debug dump\n");
904 GNUNET_SCHEDULER_add_now (&request_dump, NULL); 784 job = GNUNET_SCHEDULER_add_now (&request_dump,
905 } 785 NULL);
906 else if (NULL != target_id)
907 {
908 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
909 "Creating channel to %s\n",
910 target_id);
911 GNUNET_SCHEDULER_add_now (&create_channel, NULL);
912 } 786 }
913 else if (NULL != peer_id) 787 else if (NULL != peer_id)
914 { 788 {
915 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show peer\n"); 789 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
916 job = GNUNET_SCHEDULER_add_now (&show_peer, NULL); 790 "Show peer\n");
791 job = GNUNET_SCHEDULER_add_now (&show_peer,
792 NULL);
917 } 793 }
918 else if (NULL != tunnel_id) 794 else if (NULL != tunnel_id)
919 { 795 {
920 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show tunnel\n"); 796 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
921 job = GNUNET_SCHEDULER_add_now (&show_tunnel, NULL); 797 "Show tunnel\n");
798 job = GNUNET_SCHEDULER_add_now (&show_tunnel,
799 NULL);
922 } 800 }
923 else if (NULL != channel_id) 801 else if (NULL != channel_id)
924 { 802 {
925 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show channel\n"); 803 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
926 job = GNUNET_SCHEDULER_add_now (&show_channel, NULL); 804 "Show channel\n");
805 job = GNUNET_SCHEDULER_add_now (&show_channel,
806 NULL);
927 } 807 }
928 else if (NULL != conn_id) 808 else if (NULL != conn_id)
929 { 809 {
930 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show connection\n"); 810 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
931 job = GNUNET_SCHEDULER_add_now (&show_connection, NULL); 811 "Show connection\n");
812 job = GNUNET_SCHEDULER_add_now (&show_connection,
813 NULL);
932 } 814 }
933 else if (GNUNET_YES == request_peers) 815 else if (GNUNET_YES == request_peers)
934 { 816 {
935 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show all peers\n"); 817 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
936 job = GNUNET_SCHEDULER_add_now (&get_peers, NULL); 818 "Show all peers\n");
819 job = GNUNET_SCHEDULER_add_now (&get_peers,
820 NULL);
937 } 821 }
938 else if (GNUNET_YES == request_tunnels) 822 else if (GNUNET_YES == request_tunnels)
939 { 823 {
940 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show all tunnels\n"); 824 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
941 job = GNUNET_SCHEDULER_add_now (&get_tunnels, NULL); 825 "Show all tunnels\n");
826 job = GNUNET_SCHEDULER_add_now (&get_tunnels,
827 NULL);
942 } 828 }
943 else if (NULL == listen_port) 829
830 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
831 "Connecting to CADET service\n");
832 mh = GNUNET_CADET_connect (cfg);
833 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
834 NULL);
835 if (NULL == mh)
944 { 836 {
945 FPRINTF (stderr, "No action requested\n"); 837 GNUNET_SCHEDULER_shutdown ();
946 return; 838 return;
947 } 839 }
948
949 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to CADET service\n");
950 mh = GNUNET_CADET_connect (cfg,
951 NULL, /* cls */
952 &channel_ended, /* cleaner */
953 handlers);
954 if (NULL == mh)
955 GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
956 else
957 sd = GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
958
959 if (NULL != listen_port) 840 if (NULL != listen_port)
960 { 841 {
961 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Opening CADET listen port\n"); 842 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
962 GNUNET_CRYPTO_hash (listen_port, strlen(listen_port), &porthash); 843 "Opening CADET listen port\n");
963 lp = GNUNET_CADET_open_port (mh, &porthash, &channel_incoming, NULL); 844 GNUNET_CRYPTO_hash (listen_port,
845 strlen (listen_port),
846 &porthash);
847 lp = GNUNET_CADET_open_port (mh,
848 &porthash,
849 &channel_incoming,
850 NULL,
851 NULL /* window changes */,
852 &channel_ended,
853 handlers);
854 }
855 if (NULL != target_id)
856 {
857 struct GNUNET_PeerIdentity pid;
858 enum GNUNET_CADET_ChannelOption opt;
859
860 if (GNUNET_OK !=
861 GNUNET_CRYPTO_eddsa_public_key_from_string (target_id,
862 strlen (target_id),
863 &pid.public_key))
864 {
865 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
866 _("Invalid target `%s'\n"),
867 target_id);
868 GNUNET_SCHEDULER_shutdown ();
869 return;
870 }
871 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
872 "Connecting to `%s:%s'\n",
873 target_id,
874 target_port);
875 opt = GNUNET_CADET_OPTION_DEFAULT | GNUNET_CADET_OPTION_RELIABLE;
876 GNUNET_CRYPTO_hash (target_port,
877 strlen(target_port),
878 &porthash);
879 ch = GNUNET_CADET_channel_create (mh,
880 NULL,
881 &pid,
882 &porthash,
883 opt,
884 NULL /* window changes */,
885 &channel_ended,
886 handlers);
887 if (GNUNET_YES == echo)
888 {
889 echo_task = GNUNET_SCHEDULER_add_now (&send_echo,
890 NULL);
891 }
892 else
893 {
894 listen_stdio ();
895 }
896 }
897
898 if ( (NULL == lp) &&
899 (NULL == job) &&
900 (NULL == ch) )
901 {
902 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
903 _("No action requested\n"));
904 GNUNET_SCHEDULER_shutdown ();
905 return;
964 } 906 }
965} 907}
966 908
@@ -973,51 +915,70 @@ run (void *cls,
973 * @return 0 ok, 1 on error 915 * @return 0 ok, 1 on error
974 */ 916 */
975int 917int
976main (int argc, char *const *argv) 918main (int argc,
919 char *const *argv)
977{ 920{
978 int res; 921 int res;
979 const char helpstr[] = "Create channels and retreive info about cadets status."; 922 const char helpstr[] = "Create tunnels and retrieve info about CADET's status.";
980 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 923 struct GNUNET_GETOPT_CommandLineOption options[] = {
981// {'a', "channel", "TUNNEL_ID:CHANNEL_ID", 924 /* I would use the terminology 'circuit' here... --lynX */
982// gettext_noop ("provide information about a particular channel"), 925 GNUNET_GETOPT_option_string ('C',
983// GNUNET_YES, &GNUNET_GETOPT_set_string, &channel_id}, 926 "connection",
984 {'C', "connection", "CONNECTION_ID", 927 "CONNECTION_ID",
985 gettext_noop ("provide information about a particular connection"), 928 gettext_noop ("Provide information about a particular connection"),
986 GNUNET_YES, &GNUNET_GETOPT_set_string, &conn_id}, 929 &conn_id),
987 {'e', "echo", NULL, 930
988 gettext_noop ("activate echo mode"), 931 GNUNET_GETOPT_option_flag ('e',
989 GNUNET_NO, &GNUNET_GETOPT_set_one, &echo}, 932 "echo",
990 {'d', "dump", NULL, 933 gettext_noop ("Activate echo mode"),
991 gettext_noop ("dump debug information to STDERR"), 934 &echo),
992 GNUNET_NO, &GNUNET_GETOPT_set_one, &dump}, 935
993// {'m', "monitor", NULL, 936 GNUNET_GETOPT_option_flag ('d',
994// gettext_noop ("provide information about all events (continuously)"), 937 "dump",
995// GNUNET_NO, &GNUNET_GETOPT_set_one, &monitor_mode}, 938 gettext_noop ("Dump debug information to STDERR"),
996 {'o', "open-port", NULL, 939 &dump),
997 gettext_noop ("port to listen to"), 940
998 GNUNET_YES, &GNUNET_GETOPT_set_string, &listen_port}, 941 GNUNET_GETOPT_option_string ('o',
999 {'p', "peer", "PEER_ID", 942 "open-port",
1000 gettext_noop ("provide information about a patricular peer"), 943 "SHARED_SECRET",
1001 GNUNET_YES, &GNUNET_GETOPT_set_string, &peer_id}, 944 gettext_noop ("Listen for connections using a shared secret among sender and recipient"),
1002 {'P', "peers", NULL, 945 &listen_port),
1003 gettext_noop ("provide information about all peers"), 946
1004 GNUNET_NO, &GNUNET_GETOPT_set_one, &request_peers}, 947
1005 {'t', "tunnel", "TUNNEL_ID", 948 GNUNET_GETOPT_option_string ('p',
1006 gettext_noop ("provide information about a particular tunnel"), 949 "peer",
1007 GNUNET_YES, &GNUNET_GETOPT_set_string, &tunnel_id}, 950 "PEER_ID",
1008 {'T', "tunnels", NULL, 951 gettext_noop ("Provide information about a patricular peer"),
1009 gettext_noop ("provide information about all tunnels"), 952 &peer_id),
1010 GNUNET_NO, &GNUNET_GETOPT_set_one, &request_tunnels}, 953
954
955 GNUNET_GETOPT_option_flag ('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_flag ('T',
968 "tunnels",
969 gettext_noop ("Provide information about all tunnels"),
970 &request_tunnels),
1011 971
1012 GNUNET_GETOPT_OPTION_END 972 GNUNET_GETOPT_OPTION_END
1013 }; 973 };
1014 974
1015 monitor_mode = GNUNET_NO; 975 if (GNUNET_OK !=
1016 976 GNUNET_STRINGS_get_utf8_args (argc, argv,
1017 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) 977 &argc, &argv))
1018 return 2; 978 return 2;
1019 979
1020 res = GNUNET_PROGRAM_run (argc, argv, "gnunet-cadet (OPTIONS | TARGET PORT)", 980 res = GNUNET_PROGRAM_run (argc, argv,
981 "gnunet-cadet (OPTIONS | PEER_ID SHARED_SECRET)",
1021 gettext_noop (helpstr), 982 gettext_noop (helpstr),
1022 options, &run, NULL); 983 options, &run, NULL);
1023 984
@@ -1025,8 +986,7 @@ main (int argc, char *const *argv)
1025 986
1026 if (GNUNET_OK == res) 987 if (GNUNET_OK == res)
1027 return 0; 988 return 0;
1028 else 989 return 1;
1029 return 1;
1030} 990}
1031 991
1032/* end of gnunet-cadet.c */ 992/* end of gnunet-cadet.c */
diff --git a/src/cadet/gnunet-service-cadet-new.c b/src/cadet/gnunet-service-cadet-new.c
deleted file mode 100644
index 97489f3fd..000000000
--- a/src/cadet/gnunet-service-cadet-new.c
+++ /dev/null
@@ -1,1428 +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/**
188 * Send a message to a client.
189 *
190 * @param c client to get the message
191 * @param env envelope with the message
192 */
193void
194GSC_send_to_client (struct CadetClient *c,
195 struct GNUNET_MQ_Envelope *env)
196{
197 GNUNET_MQ_send (c->mq,
198 env);
199}
200
201
202/**
203 * Return identifier for a client as a string.
204 *
205 * @param c client to identify
206 * @return string for debugging
207 */
208const char *
209GSC_2s (struct CadetClient *c)
210{
211 static char buf[32];
212
213 GNUNET_snprintf (buf,
214 sizeof (buf),
215 "Client(%u)",
216 c->id);
217 return buf;
218}
219
220
221/**
222 * Lookup channel of client @a c by @a ccn.
223 *
224 * @param c client to look in
225 * @param ccn channel ID to look up
226 * @return NULL if no such channel exists
227 */
228static struct CadetChannel *
229lookup_channel (struct CadetClient *c,
230 struct GNUNET_CADET_ClientChannelNumber ccn)
231{
232 return GNUNET_CONTAINER_multihashmap32_get (c->channels,
233 ntohl (ccn.channel_of_client));
234}
235
236
237/**
238 * Obtain the next LID to use for incoming connections to
239 * the given client.
240 *
241 * @param c client handle
242 */
243static struct GNUNET_CADET_ClientChannelNumber
244client_get_next_ccn (struct CadetClient *c)
245{
246 struct GNUNET_CADET_ClientChannelNumber ccn = c->next_ccn;
247
248 /* increment until we have a free one... */
249 while (NULL !=
250 lookup_channel (c,
251 ccn))
252 {
253 ccn.channel_of_client
254 = htonl (1 + (ntohl (ccn.channel_of_client)));
255 if (ntohl (ccn.channel_of_client) >=
256 GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
257 ccn.channel_of_client = htonl (0);
258 }
259 c->next_ccn.channel_of_client
260 = htonl (1 + (ntohl (ccn.channel_of_client)));
261 return ccn;
262}
263
264
265/**
266 * Bind incoming channel to this client, and notify client about
267 * incoming connection. Caller is responsible for notifying the other
268 * peer about our acceptance of the channel.
269 *
270 * @param c client to bind to
271 * @param ch channel to be bound
272 * @param dest peer that establishes the connection
273 * @param port port number
274 * @param options options
275 * @return local channel number assigned to the new client
276 */
277struct GNUNET_CADET_ClientChannelNumber
278GSC_bind (struct CadetClient *c,
279 struct CadetChannel *ch,
280 struct CadetPeer *dest,
281 const struct GNUNET_HashCode *port,
282 uint32_t options)
283{
284 struct GNUNET_MQ_Envelope *env;
285 struct GNUNET_CADET_LocalChannelCreateMessage *cm;
286 struct GNUNET_CADET_ClientChannelNumber ccn;
287
288 ccn = client_get_next_ccn (c);
289 GNUNET_assert (GNUNET_YES ==
290 GNUNET_CONTAINER_multihashmap32_put (c->channels,
291 ntohl (ccn.channel_of_client),
292 ch,
293 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
294 LOG (GNUNET_ERROR_TYPE_DEBUG,
295 "Accepting incoming %s from %s on open port %s (%u), assigning ccn %X\n",
296 GCCH_2s (ch),
297 GCP_2s (dest),
298 GNUNET_h2s (port),
299 ntohl (options),
300 ntohl (ccn.channel_of_client));
301 /* notify local client about incoming connection! */
302 env = GNUNET_MQ_msg (cm,
303 GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_CREATE);
304 cm->ccn = ccn;
305 cm->port = *port;
306 cm->opt = htonl (options);
307 cm->peer = *GCP_get_id (dest);
308 GSC_send_to_client (c,
309 env);
310 return ccn;
311}
312
313
314/**
315 * Callback invoked on all peers to destroy all tunnels
316 * that may still exist.
317 *
318 * @param cls NULL
319 * @param pid identify of a peer
320 * @param value a `struct CadetPeer` that may still have a tunnel
321 * @return #GNUNET_OK (iterate over all entries)
322 */
323static int
324destroy_tunnels_now (void *cls,
325 const struct GNUNET_PeerIdentity *pid,
326 void *value)
327{
328 struct CadetPeer *cp = value;
329 struct CadetTunnel *t = GCP_get_tunnel (cp,
330 GNUNET_NO);
331
332 if (NULL != t)
333 GCT_destroy_tunnel_now (t);
334 return GNUNET_OK;
335}
336
337
338/**
339 * Callback invoked on all peers to destroy all tunnels
340 * that may still exist.
341 *
342 * @param cls NULL
343 * @param pid identify of a peer
344 * @param value a `struct CadetPeer` that may still have a tunnel
345 * @return #GNUNET_OK (iterate over all entries)
346 */
347static int
348destroy_paths_now (void *cls,
349 const struct GNUNET_PeerIdentity *pid,
350 void *value)
351{
352 struct CadetPeer *cp = value;
353
354 GCP_drop_owned_paths (cp);
355 return GNUNET_OK;
356}
357
358
359/**
360 * Shutdown everything once the clients have disconnected.
361 */
362static void
363shutdown_rest ()
364{
365 if (NULL != stats)
366 {
367 GNUNET_STATISTICS_destroy (stats,
368 GNUNET_NO);
369 stats = NULL;
370 }
371 if (NULL != open_ports)
372 {
373 GNUNET_CONTAINER_multihashmap_destroy (open_ports);
374 open_ports = NULL;
375 }
376 if (NULL != loose_channels)
377 {
378 GNUNET_CONTAINER_multihashmap_destroy (loose_channels);
379 loose_channels = NULL;
380 }
381 /* Destroy tunnels. Note that all channels must be destroyed first! */
382 GCP_iterate_all (&destroy_tunnels_now,
383 NULL);
384 /* All tunnels, channels, connections and CORE must be down before this point. */
385 GCP_iterate_all (&destroy_paths_now,
386 NULL);
387 /* All paths, tunnels, channels, connections and CORE must be down before this point. */
388 GCP_destroy_all_peers ();
389 if (NULL != peers)
390 {
391 GNUNET_CONTAINER_multipeermap_destroy (peers);
392 peers = NULL;
393 }
394 if (NULL != connections)
395 {
396 GNUNET_CONTAINER_multishortmap_destroy (connections);
397 connections = NULL;
398 }
399 if (NULL != ats_ch)
400 {
401 GNUNET_ATS_connectivity_done (ats_ch);
402 ats_ch = NULL;
403 }
404 GCD_shutdown ();
405 GCH_shutdown ();
406 GNUNET_free_non_null (my_private_key);
407 my_private_key = NULL;
408}
409
410
411/**
412 * Task run during shutdown.
413 *
414 * @param cls unused
415 */
416static void
417shutdown_task (void *cls)
418{
419 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
420 "Shutting down\n");
421 shutting_down = GNUNET_YES;
422 GCO_shutdown ();
423 if (NULL == clients_head)
424 shutdown_rest ();
425}
426
427
428/**
429 * We had a remote connection @a value to port @a port before
430 * client @a cls opened port @a port. Bind them now.
431 *
432 * @param cls the `struct CadetClient`
433 * @param port the port
434 * @param value the `struct CadetChannel`
435 * @return #GNUNET_YES (iterate over all such channels)
436 */
437static int
438bind_loose_channel (void *cls,
439 const struct GNUNET_HashCode *port,
440 void *value)
441{
442 struct CadetClient *c = cls;
443 struct CadetChannel *ch = value;
444
445 GCCH_bind (ch,
446 c);
447 GNUNET_assert (GNUNET_YES ==
448 GNUNET_CONTAINER_multihashmap_remove (loose_channels,
449 port,
450 value));
451 return GNUNET_YES;
452}
453
454
455/**
456 * Handle port open request. Creates a mapping from the
457 * port to the respective client and checks whether we have
458 * loose channels trying to bind to the port. If so, those
459 * are bound.
460 *
461 * @param cls Identification of the client.
462 * @param pmsg The actual message.
463 */
464static void
465handle_port_open (void *cls,
466 const struct GNUNET_CADET_PortMessage *pmsg)
467{
468 struct CadetClient *c = cls;
469
470 LOG (GNUNET_ERROR_TYPE_DEBUG,
471 "Open port %s requested by %s\n",
472 GNUNET_h2s (&pmsg->port),
473 GSC_2s (c));
474 if (NULL == c->ports)
475 c->ports = GNUNET_CONTAINER_multihashmap_create (4,
476 GNUNET_NO);
477 if (GNUNET_OK !=
478 GNUNET_CONTAINER_multihashmap_put (c->ports,
479 &pmsg->port,
480 c,
481 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
482 {
483 GNUNET_break (0);
484 GNUNET_SERVICE_client_drop (c->client);
485 return;
486 }
487 (void) GNUNET_CONTAINER_multihashmap_put (open_ports,
488 &pmsg->port,
489 c,
490 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
491 GNUNET_CONTAINER_multihashmap_get_multiple (loose_channels,
492 &pmsg->port,
493 &bind_loose_channel,
494 c);
495 GNUNET_SERVICE_client_continue (c->client);
496}
497
498
499/**
500 * Handler for port close requests. Marks this port as closed
501 * (unless of course we have another client with the same port
502 * open). Note that existing channels accepted on the port are
503 * not affected.
504 *
505 * @param cls Identification of the client.
506 * @param pmsg The actual message.
507 */
508static void
509handle_port_close (void *cls,
510 const struct GNUNET_CADET_PortMessage *pmsg)
511{
512 struct CadetClient *c = cls;
513
514 LOG (GNUNET_ERROR_TYPE_DEBUG,
515 "Closing port %s as requested by %s\n",
516 GNUNET_h2s (&pmsg->port),
517 GSC_2s (c));
518 if (GNUNET_YES !=
519 GNUNET_CONTAINER_multihashmap_remove (c->ports,
520 &pmsg->port,
521 c))
522 {
523 GNUNET_break (0);
524 GNUNET_SERVICE_client_drop (c->client);
525 return;
526 }
527 GNUNET_assert (GNUNET_YES ==
528 GNUNET_CONTAINER_multihashmap_remove (open_ports,
529 &pmsg->port,
530 c));
531 GNUNET_SERVICE_client_continue (c->client);
532}
533
534
535/**
536 * Handler for requests for us creating a new channel to another peer and port.
537 *
538 * @param cls Identification of the client.
539 * @param tcm The actual message.
540 */
541static void
542handle_channel_create (void *cls,
543 const struct GNUNET_CADET_LocalChannelCreateMessage *tcm)
544{
545 struct CadetClient *c = cls;
546 struct CadetChannel *ch;
547
548 if (ntohl (tcm->ccn.channel_of_client) < GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
549 {
550 /* Channel ID not in allowed range. */
551 GNUNET_break (0);
552 GNUNET_SERVICE_client_drop (c->client);
553 return;
554 }
555 ch = lookup_channel (c,
556 tcm->ccn);
557 if (NULL != ch)
558 {
559 /* Channel ID already in use. Not allowed. */
560 GNUNET_break (0);
561 GNUNET_SERVICE_client_drop (c->client);
562 return;
563 }
564 LOG (GNUNET_ERROR_TYPE_DEBUG,
565 "New channel to %s at port %s requested by %s\n",
566 GNUNET_i2s (&tcm->peer),
567 GNUNET_h2s (&tcm->port),
568 GSC_2s (c));
569
570 /* Create channel */
571 ch = GCCH_channel_local_new (c,
572 tcm->ccn,
573 GCP_get (&tcm->peer,
574 GNUNET_YES),
575 &tcm->port,
576 ntohl (tcm->opt));
577 if (NULL == ch)
578 {
579 GNUNET_break (0);
580 GNUNET_SERVICE_client_drop (c->client);
581 return;
582 }
583 GNUNET_assert (GNUNET_YES ==
584 GNUNET_CONTAINER_multihashmap32_put (c->channels,
585 ntohl (tcm->ccn.channel_of_client),
586 ch,
587 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
588
589 GNUNET_SERVICE_client_continue (c->client);
590}
591
592
593/**
594 * Handler for requests of destroying an existing channel.
595 *
596 * @param cls client identification of the client
597 * @param msg the actual message
598 */
599static void
600handle_channel_destroy (void *cls,
601 const struct GNUNET_CADET_LocalChannelDestroyMessage *msg)
602{
603 struct CadetClient *c = cls;
604 struct CadetChannel *ch;
605
606 ch = lookup_channel (c,
607 msg->ccn);
608 if (NULL == ch)
609 {
610 /* Client attempted to destroy unknown channel */
611 GNUNET_break (0);
612 GNUNET_SERVICE_client_drop (c->client);
613 return;
614 }
615 LOG (GNUNET_ERROR_TYPE_INFO,
616 "%s is destroying %s\n",
617 GSC_2s(c),
618 GCCH_2s (ch));
619 GNUNET_assert (GNUNET_YES ==
620 GNUNET_CONTAINER_multihashmap32_remove (c->channels,
621 ntohl (msg->ccn.channel_of_client),
622 ch));
623 GCCH_channel_local_destroy (ch,
624 c,
625 msg->ccn);
626 GNUNET_SERVICE_client_continue (c->client);
627}
628
629
630/**
631 * Check for client traffic data message is well-formed.
632 *
633 * @param cls identification of the client
634 * @param msg the actual message
635 * @return #GNUNET_OK if @a msg is OK, #GNUNET_SYSERR if not
636 */
637static int
638check_local_data (void *cls,
639 const struct GNUNET_CADET_LocalData *msg)
640{
641 size_t payload_size;
642 size_t payload_claimed_size;
643 const char *buf;
644 struct GNUNET_MessageHeader pa;
645
646 /* FIXME: what is the format we shall allow for @a msg?
647 ONE payload item or multiple? Seems current cadet_api
648 at least in theory allows more than one. Next-gen
649 cadet_api will likely no more, so we could then
650 simplify this mess again. */
651 /* Sanity check for message size */
652 payload_size = ntohs (msg->header.size) - sizeof (*msg);
653 buf = (const char *) &msg[1];
654 while (payload_size >= sizeof (struct GNUNET_MessageHeader))
655 {
656 /* need to memcpy() for alignment */
657 GNUNET_memcpy (&pa,
658 buf,
659 sizeof (pa));
660 payload_claimed_size = ntohs (pa.size);
661 if ( (payload_size < payload_claimed_size) ||
662 (payload_claimed_size < sizeof (struct GNUNET_MessageHeader)) ||
663 (GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE < payload_claimed_size) )
664 {
665 GNUNET_break (0);
666 LOG (GNUNET_ERROR_TYPE_DEBUG,
667 "Local data of %u total size had sub-message %u at %u with %u bytes\n",
668 ntohs (msg->header.size),
669 ntohs (pa.type),
670 (unsigned int) (buf - (const char *) &msg[1]),
671 (unsigned int) payload_claimed_size);
672 return GNUNET_SYSERR;
673 }
674 payload_size -= payload_claimed_size;
675 buf += payload_claimed_size;
676 }
677 if (0 != payload_size)
678 {
679 GNUNET_break_op (0);
680 return GNUNET_SYSERR;
681 }
682 return GNUNET_OK;
683}
684
685
686/**
687 * Handler for client payload traffic to be send on a channel to
688 * another peer.
689 *
690 * @param cls identification of the client
691 * @param msg the actual message
692 */
693static void
694handle_local_data (void *cls,
695 const struct GNUNET_CADET_LocalData *msg)
696{
697 struct CadetClient *c = cls;
698 struct CadetChannel *ch;
699 size_t payload_size;
700 const char *buf;
701
702 ch = lookup_channel (c,
703 msg->ccn);
704 if (NULL == ch)
705 {
706 /* Channel does not exist! */
707 GNUNET_break (0);
708 GNUNET_SERVICE_client_drop (c->client);
709 return;
710 }
711 payload_size = ntohs (msg->header.size) - sizeof (*msg);
712 buf = (const char *) &msg[1];
713 LOG (GNUNET_ERROR_TYPE_DEBUG,
714 "Received %u bytes payload from %s for %s\n",
715 (unsigned int) payload_size,
716 GSC_2s (c),
717 GCCH_2s (ch));
718 if (GNUNET_OK !=
719 GCCH_handle_local_data (ch,
720 msg->ccn,
721 buf,
722 payload_size))
723 {
724 GNUNET_SERVICE_client_drop (c->client);
725 return;
726 }
727 GNUNET_SERVICE_client_continue (c->client);
728}
729
730
731/**
732 * Handler for client's ACKs for payload traffic.
733 *
734 * @param cls identification of the client.
735 * @param msg The actual message.
736 */
737static void
738handle_local_ack (void *cls,
739 const struct GNUNET_CADET_LocalAck *msg)
740{
741 struct CadetClient *c = cls;
742 struct CadetChannel *ch;
743
744 ch = lookup_channel (c,
745 msg->ccn);
746 if (NULL == ch)
747 {
748 /* Channel does not exist! */
749 GNUNET_break (0);
750 GNUNET_SERVICE_client_drop (c->client);
751 return;
752 }
753 LOG (GNUNET_ERROR_TYPE_DEBUG,
754 "Got a local ACK from %s for %s\n",
755 GSC_2s(c),
756 GCCH_2s (ch));
757 GCCH_handle_local_ack (ch,
758 msg->ccn);
759 GNUNET_SERVICE_client_continue (c->client);
760}
761
762
763/**
764 * Iterator over all peers to send a monitoring client info about each peer.
765 *
766 * @param cls Closure ().
767 * @param peer Peer ID (tunnel remote peer).
768 * @param value Peer info.
769 * @return #GNUNET_YES, to keep iterating.
770 */
771static int
772get_all_peers_iterator (void *cls,
773 const struct GNUNET_PeerIdentity *peer,
774 void *value)
775{
776 struct CadetClient *c = cls;
777 struct CadetPeer *p = value;
778 struct GNUNET_MQ_Envelope *env;
779 struct GNUNET_CADET_LocalInfoPeer *msg;
780
781 env = GNUNET_MQ_msg (msg,
782 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS);
783 msg->destination = *peer;
784 msg->paths = htons (GCP_count_paths (p));
785 msg->tunnel = htons (NULL != GCP_get_tunnel (p,
786 GNUNET_NO));
787 GNUNET_MQ_send (c->mq,
788 env);
789 return GNUNET_YES;
790}
791
792
793/**
794 * Handler for client's INFO PEERS request.
795 *
796 * @param cls Identification of the client.
797 * @param message The actual message.
798 */
799static void
800handle_get_peers (void *cls,
801 const struct GNUNET_MessageHeader *message)
802{
803 struct CadetClient *c = cls;
804 struct GNUNET_MQ_Envelope *env;
805 struct GNUNET_MessageHeader *reply;
806
807 GCP_iterate_all (&get_all_peers_iterator,
808 c);
809 env = GNUNET_MQ_msg (reply,
810 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS);
811 GNUNET_MQ_send (c->mq,
812 env);
813 GNUNET_SERVICE_client_continue (c->client);
814}
815
816
817/**
818 * Iterator over all paths of a peer to build an InfoPeer message.
819 * Message contains blocks of peers, first not included.
820 *
821 * @param cls message queue for transmission
822 * @param path Path itself
823 * @param off offset of the peer on @a path
824 * @return #GNUNET_YES if should keep iterating.
825 * #GNUNET_NO otherwise.
826 */
827static int
828path_info_iterator (void *cls,
829 struct CadetPeerPath *path,
830 unsigned int off)
831{
832 struct GNUNET_MQ_Handle *mq = cls;
833 struct GNUNET_MQ_Envelope *env;
834 struct GNUNET_MessageHeader *resp;
835 struct GNUNET_PeerIdentity *id;
836 uint16_t path_size;
837 unsigned int i;
838 unsigned int path_length;
839
840 path_length = GCPP_get_length (path);
841 path_size = sizeof (struct GNUNET_PeerIdentity) * (path_length - 1);
842 if (sizeof (*resp) + path_size > UINT16_MAX)
843 {
844 LOG (GNUNET_ERROR_TYPE_WARNING,
845 "Path of %u entries is too long for info message\n",
846 path_length);
847 return GNUNET_YES;
848 }
849 env = GNUNET_MQ_msg_extra (resp,
850 path_size,
851 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER);
852 id = (struct GNUNET_PeerIdentity *) &resp[1];
853
854 /* Don't copy first peer. First peer is always the local one. Last
855 * peer is always the destination (leave as 0, EOL).
856 */
857 for (i = 0; i < off; i++)
858 id[i] = *GCP_get_id (GCPP_get_peer_at_offset (path,
859 i + 1));
860 GNUNET_MQ_send (mq,
861 env);
862 return GNUNET_YES;
863}
864
865
866/**
867 * Handler for client's SHOW_PEER request.
868 *
869 * @param cls Identification of the client.
870 * @param msg The actual message.
871 */
872static void
873handle_show_peer (void *cls,
874 const struct GNUNET_CADET_LocalInfo *msg)
875{
876 struct CadetClient *c = cls;
877 struct CadetPeer *p;
878 struct GNUNET_MQ_Envelope *env;
879 struct GNUNET_MessageHeader *resp;
880
881 p = GCP_get (&msg->peer,
882 GNUNET_NO);
883 if (NULL != p)
884 GCP_iterate_paths (p,
885 &path_info_iterator,
886 c->mq);
887 /* Send message with 0/0 to indicate the end */
888 env = GNUNET_MQ_msg (resp,
889 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER_END);
890 GNUNET_MQ_send (c->mq,
891 env);
892 GNUNET_SERVICE_client_continue (c->client);
893}
894
895
896/**
897 * Iterator over all tunnels to send a monitoring client info about each tunnel.
898 *
899 * @param cls Closure ().
900 * @param peer Peer ID (tunnel remote peer).
901 * @param value a `struct CadetPeer`
902 * @return #GNUNET_YES, to keep iterating.
903 */
904static int
905get_all_tunnels_iterator (void *cls,
906 const struct GNUNET_PeerIdentity *peer,
907 void *value)
908{
909 struct CadetClient *c = cls;
910 struct CadetPeer *p = value;
911 struct GNUNET_MQ_Envelope *env;
912 struct GNUNET_CADET_LocalInfoTunnel *msg;
913 struct CadetTunnel *t;
914
915 t = GCP_get_tunnel (p,
916 GNUNET_NO);
917 if (NULL == t)
918 return GNUNET_YES;
919 env = GNUNET_MQ_msg (msg,
920 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS);
921 msg->destination = *peer;
922 msg->channels = htonl (GCT_count_channels (t));
923 msg->connections = htonl (GCT_count_any_connections (t));
924 msg->cstate = htons (0);
925 msg->estate = htons ((uint16_t) GCT_get_estate (t));
926 GNUNET_MQ_send (c->mq,
927 env);
928 return GNUNET_YES;
929}
930
931
932/**
933 * Handler for client's #GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS request.
934 *
935 * @param cls client Identification of the client.
936 * @param message The actual message.
937 */
938static void
939handle_info_tunnels (void *cls,
940 const struct GNUNET_MessageHeader *message)
941{
942 struct CadetClient *c = cls;
943 struct GNUNET_MQ_Envelope *env;
944 struct GNUNET_MessageHeader *reply;
945
946 GCP_iterate_all (&get_all_tunnels_iterator,
947 c);
948 env = GNUNET_MQ_msg (reply,
949 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS);
950 GNUNET_MQ_send (c->mq,
951 env);
952 GNUNET_SERVICE_client_continue (c->client);
953}
954
955
956/**
957 * Update the message with information about the connection.
958 *
959 * @param cls a `struct GNUNET_CADET_LocalInfoTunnel` message to update
960 * @param c a connection about which we should store information in @a cls
961 */
962static void
963iter_connection (void *cls,
964 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}
972
973
974/**
975 * Update the message with information about the channel.
976 *
977 * @param cls a `struct GNUNET_CADET_LocalInfoTunnel` message to update
978 * @param ch a channel about which we should store information in @a cls
979 */
980static void
981iter_channel (void *cls,
982 struct CadetChannel *ch)
983{
984 struct GNUNET_CADET_LocalInfoTunnel *msg = cls;
985 struct GNUNET_CADET_ConnectionTunnelIdentifier *h = (struct GNUNET_CADET_ConnectionTunnelIdentifier *) &msg[1];
986 struct GNUNET_CADET_ChannelTunnelNumber *chn
987 = (struct GNUNET_CADET_ChannelTunnelNumber *) &h[msg->connections];
988
989 chn[msg->channels++] = GCCH_get_id (ch);
990}
991
992
993/**
994 * Handler for client's #GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL request.
995 *
996 * @param cls Identification of the client.
997 * @param msg The actual message.
998 */
999static void
1000handle_info_tunnel (void *cls,
1001 const struct GNUNET_CADET_LocalInfo *msg)
1002{
1003 struct CadetClient *c = cls;
1004 struct GNUNET_MQ_Envelope *env;
1005 struct GNUNET_CADET_LocalInfoTunnel *resp;
1006 struct CadetTunnel *t;
1007 struct CadetPeer *p;
1008 unsigned int ch_n;
1009 unsigned int c_n;
1010
1011 p = GCP_get (&msg->peer,
1012 GNUNET_NO);
1013 t = GCP_get_tunnel (p,
1014 GNUNET_NO);
1015 if (NULL == t)
1016 {
1017 /* We don't know the tunnel */
1018 struct GNUNET_MQ_Envelope *env;
1019 struct GNUNET_CADET_LocalInfoTunnel *warn;
1020
1021 LOG (GNUNET_ERROR_TYPE_INFO,
1022 "Tunnel to %s unknown\n",
1023 GNUNET_i2s_full (&msg->peer));
1024 env = GNUNET_MQ_msg (warn,
1025 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL);
1026 warn->destination = msg->peer;
1027 GNUNET_MQ_send (c->mq,
1028 env);
1029 GNUNET_SERVICE_client_continue (c->client);
1030 return;
1031 }
1032
1033 /* Initialize context */
1034 ch_n = GCT_count_channels (t);
1035 c_n = GCT_count_any_connections (t);
1036 env = GNUNET_MQ_msg_extra (resp,
1037 c_n * sizeof (struct GNUNET_CADET_ConnectionTunnelIdentifier) +
1038 ch_n * sizeof (struct GNUNET_CADET_ChannelTunnelNumber),
1039 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL);
1040 resp->destination = msg->peer;
1041 /* Do not reorder! #iter_channel needs counters in HBO! */
1042 GCT_iterate_connections (t,
1043 &iter_connection,
1044 resp);
1045 GCT_iterate_channels (t,
1046 &iter_channel,
1047 resp);
1048 resp->connections = htonl (resp->connections);
1049 resp->channels = htonl (resp->channels);
1050 resp->cstate = htons (0);
1051 resp->estate = htons (GCT_get_estate (t));
1052 GNUNET_MQ_send (c->mq,
1053 env);
1054 GNUNET_SERVICE_client_continue (c->client);
1055}
1056
1057
1058/**
1059 * Iterator over all peers to dump info for each peer.
1060 *
1061 * @param cls Closure (unused).
1062 * @param peer Peer ID (tunnel remote peer).
1063 * @param value Peer info.
1064 *
1065 * @return #GNUNET_YES, to keep iterating.
1066 */
1067static int
1068show_peer_iterator (void *cls,
1069 const struct GNUNET_PeerIdentity *peer,
1070 void *value)
1071{
1072 struct CadetPeer *p = value;
1073 struct CadetTunnel *t;
1074
1075 t = GCP_get_tunnel (p,
1076 GNUNET_NO);
1077 if (NULL != t)
1078 GCT_debug (t,
1079 GNUNET_ERROR_TYPE_ERROR);
1080 LOG (GNUNET_ERROR_TYPE_ERROR, "\n");
1081 return GNUNET_YES;
1082}
1083
1084
1085/**
1086 * Handler for client's INFO_DUMP request.
1087 *
1088 * @param cls Identification of the client.
1089 * @param message The actual message.
1090 */
1091static void
1092handle_info_dump (void *cls,
1093 const struct GNUNET_MessageHeader *message)
1094{
1095 struct CadetClient *c = cls;
1096
1097 LOG (GNUNET_ERROR_TYPE_INFO,
1098 "Received dump info request from client %u\n",
1099 c->id);
1100
1101 LOG (GNUNET_ERROR_TYPE_ERROR,
1102 "*************************** DUMP START ***************************\n");
1103 for (struct CadetClient *ci = clients_head;
1104 NULL != ci;
1105 ci = ci->next)
1106 {
1107 LOG (GNUNET_ERROR_TYPE_ERROR,
1108 "Client %u (%p), handle: %p, ports: %u, channels: %u\n",
1109 ci->id,
1110 ci,
1111 ci->client,
1112 (NULL != c->ports)
1113 ? GNUNET_CONTAINER_multihashmap_size (ci->ports)
1114 : 0,
1115 GNUNET_CONTAINER_multihashmap32_size (ci->channels));
1116 }
1117 LOG (GNUNET_ERROR_TYPE_ERROR, "***************************\n");
1118 GCP_iterate_all (&show_peer_iterator,
1119 NULL);
1120
1121 LOG (GNUNET_ERROR_TYPE_ERROR,
1122 "**************************** DUMP END ****************************\n");
1123
1124 GNUNET_SERVICE_client_continue (c->client);
1125}
1126
1127
1128
1129/**
1130 * Callback called when a client connects to the service.
1131 *
1132 * @param cls closure for the service
1133 * @param client the new client that connected to the service
1134 * @param mq the message queue used to send messages to the client
1135 * @return @a c
1136 */
1137static void *
1138client_connect_cb (void *cls,
1139 struct GNUNET_SERVICE_Client *client,
1140 struct GNUNET_MQ_Handle *mq)
1141{
1142 struct CadetClient *c;
1143
1144 c = GNUNET_new (struct CadetClient);
1145 c->client = client;
1146 c->mq = mq;
1147 c->id = next_client_id++; /* overflow not important: just for debug */
1148 c->channels
1149 = GNUNET_CONTAINER_multihashmap32_create (32);
1150 GNUNET_CONTAINER_DLL_insert (clients_head,
1151 clients_tail,
1152 c);
1153 GNUNET_STATISTICS_update (stats,
1154 "# clients",
1155 +1,
1156 GNUNET_NO);
1157 LOG (GNUNET_ERROR_TYPE_DEBUG,
1158 "%s connected\n",
1159 GSC_2s (c));
1160 return c;
1161}
1162
1163
1164/**
1165 * A channel was destroyed by the other peer. Tell our client.
1166 *
1167 * @param c client that lost a channel
1168 * @param ccn channel identification number for the client
1169 * @param ch the channel object
1170 */
1171void
1172GSC_handle_remote_channel_destroy (struct CadetClient *c,
1173 struct GNUNET_CADET_ClientChannelNumber ccn,
1174 struct CadetChannel *ch)
1175{
1176 struct GNUNET_MQ_Envelope *env;
1177 struct GNUNET_CADET_LocalChannelDestroyMessage *tdm;
1178
1179 env = GNUNET_MQ_msg (tdm,
1180 GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY);
1181 tdm->ccn = ccn;
1182 GSC_send_to_client (c,
1183 env);
1184 GNUNET_assert (GNUNET_YES ==
1185 GNUNET_CONTAINER_multihashmap32_remove (c->channels,
1186 ntohl (ccn.channel_of_client),
1187 ch));
1188}
1189
1190
1191/**
1192 * Iterator for deleting each channel whose client endpoint disconnected.
1193 *
1194 * @param cls Closure (client that has disconnected).
1195 * @param key The local channel id in host byte order
1196 * @param value The value stored at the key (channel to destroy).
1197 * @return #GNUNET_OK, keep iterating.
1198 */
1199static int
1200channel_destroy_iterator (void *cls,
1201 uint32_t key,
1202 void *value)
1203{
1204 struct CadetClient *c = cls;
1205 struct GNUNET_CADET_ClientChannelNumber ccn;
1206 struct CadetChannel *ch = value;
1207
1208 LOG (GNUNET_ERROR_TYPE_DEBUG,
1209 "Destroying %s, due to %s disconnecting.\n",
1210 GCCH_2s (ch),
1211 GSC_2s (c));
1212 GNUNET_assert (GNUNET_YES ==
1213 GNUNET_CONTAINER_multihashmap32_remove (c->channels,
1214 key,
1215 ch));
1216 ccn.channel_of_client = htonl (key);
1217 GCCH_channel_local_destroy (ch,
1218 c,
1219 ccn);
1220 return GNUNET_OK;
1221}
1222
1223
1224/**
1225 * Remove client's ports from the global hashmap on disconnect.
1226 *
1227 * @param cls Closure (unused).
1228 * @param key the port.
1229 * @param value the `struct CadetClient` to remove
1230 * @return #GNUNET_OK, keep iterating.
1231 */
1232static int
1233client_release_ports (void *cls,
1234 const struct GNUNET_HashCode *key,
1235 void *value)
1236{
1237 struct CadetClient *c = value;
1238
1239 LOG (GNUNET_ERROR_TYPE_DEBUG,
1240 "Closing port %s due to %s disconnect.\n",
1241 GNUNET_h2s (key),
1242 GSC_2s (c));
1243 GNUNET_assert (GNUNET_YES ==
1244 GNUNET_CONTAINER_multihashmap_remove (open_ports,
1245 key,
1246 value));
1247 GNUNET_assert (GNUNET_YES ==
1248 GNUNET_CONTAINER_multihashmap_remove (c->ports,
1249 key,
1250 value));
1251 return GNUNET_OK;
1252}
1253
1254
1255/**
1256 * Callback called when a client disconnected from the service
1257 *
1258 * @param cls closure for the service
1259 * @param client the client that disconnected
1260 * @param internal_cls should be equal to @a c
1261 */
1262static void
1263client_disconnect_cb (void *cls,
1264 struct GNUNET_SERVICE_Client *client,
1265 void *internal_cls)
1266{
1267 struct CadetClient *c = internal_cls;
1268
1269 GNUNET_assert (c->client == client);
1270 LOG (GNUNET_ERROR_TYPE_DEBUG,
1271 "%s is disconnecting.\n",
1272 GSC_2s (c));
1273 if (NULL != c->channels)
1274 {
1275 GNUNET_CONTAINER_multihashmap32_iterate (c->channels,
1276 &channel_destroy_iterator,
1277 c);
1278 GNUNET_CONTAINER_multihashmap32_destroy (c->channels);
1279 }
1280 if (NULL != c->ports)
1281 {
1282 GNUNET_CONTAINER_multihashmap_iterate (c->ports,
1283 &client_release_ports,
1284 c);
1285 GNUNET_CONTAINER_multihashmap_destroy (c->ports);
1286 }
1287 GNUNET_CONTAINER_DLL_remove (clients_head,
1288 clients_tail,
1289 c);
1290 GNUNET_STATISTICS_update (stats,
1291 "# clients",
1292 -1,
1293 GNUNET_NO);
1294 GNUNET_free (c);
1295 if ( (NULL == clients_head) &&
1296 (GNUNET_YES == shutting_down) )
1297 shutdown_rest ();
1298}
1299
1300
1301/**
1302 * Setup CADET internals.
1303 *
1304 * @param cls closure
1305 * @param server the initialized server
1306 * @param c configuration to use
1307 */
1308static void
1309run (void *cls,
1310 const struct GNUNET_CONFIGURATION_Handle *c,
1311 struct GNUNET_SERVICE_Handle *service)
1312{
1313 cfg = c;
1314 if (GNUNET_OK !=
1315 GNUNET_CONFIGURATION_get_value_number (c,
1316 "CADET",
1317 "RATCHET_MESSAGES",
1318 &ratchet_messages))
1319 {
1320 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
1321 "CADET",
1322 "RATCHET_MESSAGES",
1323 "needs to be a number");
1324 ratchet_messages = 64;
1325 }
1326 if (GNUNET_OK !=
1327 GNUNET_CONFIGURATION_get_value_time (c,
1328 "CADET",
1329 "RATCHET_TIME",
1330 &ratchet_time))
1331 {
1332 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
1333 "CADET",
1334 "RATCHET_TIME",
1335 "need delay value");
1336 ratchet_time = GNUNET_TIME_UNIT_HOURS;
1337 }
1338
1339 my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (c);
1340 if (NULL == my_private_key)
1341 {
1342 GNUNET_break (0);
1343 GNUNET_SCHEDULER_shutdown ();
1344 return;
1345 }
1346 GNUNET_CRYPTO_eddsa_key_get_public (my_private_key,
1347 &my_full_id.public_key);
1348 stats = GNUNET_STATISTICS_create ("cadet",
1349 c);
1350 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1351 NULL);
1352 ats_ch = GNUNET_ATS_connectivity_init (c);
1353 /* FIXME: optimize code to allow GNUNET_YES here! */
1354 open_ports = GNUNET_CONTAINER_multihashmap_create (16,
1355 GNUNET_NO);
1356 loose_channels = GNUNET_CONTAINER_multihashmap_create (16,
1357 GNUNET_NO);
1358 peers = GNUNET_CONTAINER_multipeermap_create (16,
1359 GNUNET_YES);
1360 connections = GNUNET_CONTAINER_multishortmap_create (256,
1361 GNUNET_YES);
1362 GCH_init (c);
1363 GCD_init (c);
1364 GCO_init (c);
1365 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1366 "CADET started for peer %s\n",
1367 GNUNET_i2s (&my_full_id));
1368
1369}
1370
1371
1372/**
1373 * Define "main" method using service macro.
1374 */
1375GNUNET_SERVICE_MAIN
1376("cadet",
1377 GNUNET_SERVICE_OPTION_NONE,
1378 &run,
1379 &client_connect_cb,
1380 &client_disconnect_cb,
1381 NULL,
1382 GNUNET_MQ_hd_fixed_size (port_open,
1383 GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_OPEN,
1384 struct GNUNET_CADET_PortMessage,
1385 NULL),
1386 GNUNET_MQ_hd_fixed_size (port_close,
1387 GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_CLOSE,
1388 struct GNUNET_CADET_PortMessage,
1389 NULL),
1390 GNUNET_MQ_hd_fixed_size (channel_create,
1391 GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_CREATE,
1392 struct GNUNET_CADET_LocalChannelCreateMessage,
1393 NULL),
1394 GNUNET_MQ_hd_fixed_size (channel_destroy,
1395 GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY,
1396 struct GNUNET_CADET_LocalChannelDestroyMessage,
1397 NULL),
1398 GNUNET_MQ_hd_var_size (local_data,
1399 GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA,
1400 struct GNUNET_CADET_LocalData,
1401 NULL),
1402 GNUNET_MQ_hd_fixed_size (local_ack,
1403 GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK,
1404 struct GNUNET_CADET_LocalAck,
1405 NULL),
1406 GNUNET_MQ_hd_fixed_size (get_peers,
1407 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS,
1408 struct GNUNET_MessageHeader,
1409 NULL),
1410 GNUNET_MQ_hd_fixed_size (show_peer,
1411 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER,
1412 struct GNUNET_CADET_LocalInfo,
1413 NULL),
1414 GNUNET_MQ_hd_fixed_size (info_tunnels,
1415 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS,
1416 struct GNUNET_MessageHeader,
1417 NULL),
1418 GNUNET_MQ_hd_fixed_size (info_tunnel,
1419 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL,
1420 struct GNUNET_CADET_LocalInfo,
1421 NULL),
1422 GNUNET_MQ_hd_fixed_size (info_dump,
1423 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_DUMP,
1424 struct GNUNET_MessageHeader,
1425 NULL),
1426 GNUNET_MQ_handler_end ());
1427
1428/* 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 0c6241817..000000000
--- a/src/cadet/gnunet-service-cadet-new_channel.c
+++ /dev/null
@@ -1,1613 +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 * @file cadet/gnunet-service-cadet-new_channel.c
23 * @brief logical links between CADET clients
24 * @author Bartlomiej Polot
25 * @author Christian Grothoff
26 *
27 * TODO:
28 * - FIXME: send ACKs back to loopback clients!
29 *
30 * - introduce shutdown so we can have half-closed channels, modify
31 * destroy to include MID to have FIN-ACK equivalents, etc.
32 * - estimate max bandwidth using bursts and use to for CONGESTION CONTROL!
33 * - check that '0xFFULL' really is sufficient for flow control!
34 * - revisit handling of 'unreliable' traffic!
35 * - revisit handling of 'out-of-order' option, especially in combination with/without 'reliable'.
36 * - figure out flow control without ACKs (unreliable traffic!)
37 */
38#include "platform.h"
39#include "gnunet_util_lib.h"
40#include "cadet.h"
41#include "gnunet_statistics_service.h"
42#include "gnunet-service-cadet-new.h"
43#include "gnunet-service-cadet-new_channel.h"
44#include "gnunet-service-cadet-new_connection.h"
45#include "gnunet-service-cadet-new_tunnels.h"
46#include "gnunet-service-cadet-new_peer.h"
47#include "gnunet-service-cadet-new_paths.h"
48
49#define LOG(level,...) GNUNET_log_from (level,"cadet-chn",__VA_ARGS__)
50
51/**
52 * How long do we initially wait before retransmitting?
53 */
54#define CADET_INITIAL_RETRANSMIT_TIME GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 250)
55
56/**
57 * How long do we wait before dropping state about incoming
58 * connection to closed port?
59 */
60#define TIMEOUT_CLOSED_PORT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30)
61
62
63/**
64 * All the states a connection can be in.
65 */
66enum CadetChannelState
67{
68 /**
69 * Uninitialized status, should never appear in operation.
70 */
71 CADET_CHANNEL_NEW,
72
73 /**
74 * Connection create message sent, waiting for ACK.
75 */
76 CADET_CHANNEL_OPEN_SENT,
77
78 /**
79 * Connection confirmed, ready to carry traffic.
80 */
81 CADET_CHANNEL_READY
82};
83
84
85/**
86 * Info needed to retry a message in case it gets lost.
87 * Note that we DO use this structure also for unreliable
88 * messages.
89 */
90struct CadetReliableMessage
91{
92 /**
93 * Double linked list, FIFO style
94 */
95 struct CadetReliableMessage *next;
96
97 /**
98 * Double linked list, FIFO style
99 */
100 struct CadetReliableMessage *prev;
101
102 /**
103 * Which channel is this message in?
104 */
105 struct CadetChannel *ch;
106
107 /**
108 * Entry in the tunnels queue for this message, NULL if it has left
109 * the tunnel. Used to cancel transmission in case we receive an
110 * ACK in time.
111 */
112 struct CadetTunnelQueueEntry *qe;
113
114 /**
115 * How soon should we retry if we fail to get an ACK?
116 * Messages in the queue are sorted by this value.
117 */
118 struct GNUNET_TIME_Absolute next_retry;
119
120 /**
121 * How long do we wait for an ACK after transmission?
122 * Use for the back-off calculation.
123 */
124 struct GNUNET_TIME_Relative retry_delay;
125
126 /**
127 * Data message we are trying to send.
128 */
129 struct GNUNET_CADET_ChannelAppDataMessage *data_message;
130
131};
132
133
134/**
135 * List of received out-of-order data messages.
136 */
137struct CadetOutOfOrderMessage
138{
139 /**
140 * Double linked list, FIFO style
141 */
142 struct CadetOutOfOrderMessage *next;
143
144 /**
145 * Double linked list, FIFO style
146 */
147 struct CadetOutOfOrderMessage *prev;
148
149 /**
150 * ID of the message (messages up to this point needed
151 * before we give this one to the client).
152 */
153 struct ChannelMessageIdentifier mid;
154
155 /**
156 * The envelope with the payload of the out-of-order message
157 */
158 struct GNUNET_MQ_Envelope *env;
159
160};
161
162
163/**
164 * Client endpoint of a `struct CadetChannel`. A channel may be a
165 * loopback channel, in which case it has two of these endpoints.
166 * Note that flow control also is required in both directions.
167 */
168struct CadetChannelClient
169{
170 /**
171 * Client handle. Not by itself sufficient to designate
172 * the client endpoint, as the same client handle may
173 * be used for both the owner and the destination, and
174 * we thus also need the channel ID to identify the client.
175 */
176 struct CadetClient *c;
177
178 /**
179 * Head of DLL of messages received out of order or while client was unready.
180 */
181 struct CadetOutOfOrderMessage *head_recv;
182
183 /**
184 * Tail DLL of messages received out of order or while client was unready.
185 */
186 struct CadetOutOfOrderMessage *tail_recv;
187
188 /**
189 * Local tunnel number for this client.
190 * (if owner >= #GNUNET_CADET_LOCAL_CHANNEL_ID_CLI,
191 * otherwise < #GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
192 */
193 struct GNUNET_CADET_ClientChannelNumber ccn;
194
195 /**
196 * Can we send data to the client?
197 */
198 int client_ready;
199
200};
201
202
203/**
204 * Struct containing all information regarding a channel to a remote client.
205 */
206struct CadetChannel
207{
208 /**
209 * Tunnel this channel is in.
210 */
211 struct CadetTunnel *t;
212
213 /**
214 * Client owner of the tunnel, if any.
215 * (Used if this channel represends the initiating end of the tunnel.)
216 */
217 struct CadetChannelClient *owner;
218
219 /**
220 * Client destination of the tunnel, if any.
221 * (Used if this channel represents the listening end of the tunnel.)
222 */
223 struct CadetChannelClient *dest;
224
225 /**
226 * Last entry in the tunnel's queue relating to control messages
227 * (#GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN or
228 * #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK). Used to cancel
229 * transmission in case we receive updated information.
230 */
231 struct CadetTunnelQueueEntry *last_control_qe;
232
233 /**
234 * Head of DLL of messages sent and not yet ACK'd.
235 */
236 struct CadetReliableMessage *head_sent;
237
238 /**
239 * Tail of DLL of messages sent and not yet ACK'd.
240 */
241 struct CadetReliableMessage *tail_sent;
242
243 /**
244 * Task to resend/poll in case no ACK is received.
245 */
246 struct GNUNET_SCHEDULER_Task *retry_control_task;
247
248 /**
249 * Task to resend/poll in case no ACK is received.
250 */
251 struct GNUNET_SCHEDULER_Task *retry_data_task;
252
253 /**
254 * Last time the channel was used
255 */
256 struct GNUNET_TIME_Absolute timestamp;
257
258 /**
259 * Destination port of the channel.
260 */
261 struct GNUNET_HashCode port;
262
263 /**
264 * Counter for exponential backoff.
265 */
266 struct GNUNET_TIME_Relative retry_time;
267
268 /**
269 * How long does it usually take to get an ACK.
270 */
271 struct GNUNET_TIME_Relative expected_delay;
272
273 /**
274 * Bitfield of already-received messages past @e mid_recv.
275 */
276 uint64_t mid_futures;
277
278 /**
279 * Next MID expected for incoming traffic.
280 */
281 struct ChannelMessageIdentifier mid_recv;
282
283 /**
284 * Next MID to use for outgoing traffic.
285 */
286 struct ChannelMessageIdentifier mid_send;
287
288 /**
289 * Total (reliable) messages pending ACK for this channel.
290 */
291 unsigned int pending_messages;
292
293 /**
294 * Maximum (reliable) messages pending ACK for this channel
295 * before we throttle the client.
296 */
297 unsigned int max_pending_messages;
298
299 /**
300 * Number identifying this channel in its tunnel.
301 */
302 struct GNUNET_CADET_ChannelTunnelNumber ctn;
303
304 /**
305 * Channel state.
306 */
307 enum CadetChannelState state;
308
309 /**
310 * Is the tunnel bufferless (minimum latency)?
311 */
312 int nobuffer;
313
314 /**
315 * Is the tunnel reliable?
316 */
317 int reliable;
318
319 /**
320 * Is the tunnel out-of-order?
321 */
322 int out_of_order;
323
324 /**
325 * Is this channel a loopback channel, where the destination is us again?
326 */
327 int is_loopback;
328
329 /**
330 * Flag to signal the destruction of the channel. If this is set to
331 * #GNUNET_YES the channel will be destroyed once the queue is
332 * empty.
333 */
334 int destroy;
335
336};
337
338
339/**
340 * Get the static string for identification of the channel.
341 *
342 * @param ch Channel.
343 *
344 * @return Static string with the channel IDs.
345 */
346const char *
347GCCH_2s (const struct CadetChannel *ch)
348{
349 static char buf[128];
350
351 GNUNET_snprintf (buf,
352 sizeof (buf),
353 "Channel %s:%s ctn:%X(%X/%X)",
354 (GNUNET_YES == ch->is_loopback)
355 ? "loopback"
356 : GNUNET_i2s (GCP_get_id (GCT_get_destination (ch->t))),
357 GNUNET_h2s (&ch->port),
358 ch->ctn,
359 (NULL == ch->owner) ? 0 : ntohl (ch->owner->ccn.channel_of_client),
360 (NULL == ch->dest) ? 0 : ntohl (ch->dest->ccn.channel_of_client));
361 return buf;
362}
363
364
365/**
366 * Get the channel's public ID.
367 *
368 * @param ch Channel.
369 *
370 * @return ID used to identify the channel with the remote peer.
371 */
372struct GNUNET_CADET_ChannelTunnelNumber
373GCCH_get_id (const struct CadetChannel *ch)
374{
375 return ch->ctn;
376}
377
378
379/**
380 * Release memory associated with @a ccc
381 *
382 * @param ccc data structure to clean up
383 */
384static void
385free_channel_client (struct CadetChannelClient *ccc)
386{
387 struct CadetOutOfOrderMessage *com;
388
389 while (NULL != (com = ccc->head_recv))
390 {
391 GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
392 ccc->tail_recv,
393 com);
394 GNUNET_MQ_discard (com->env);
395 GNUNET_free (com);
396 }
397 GNUNET_free (ccc);
398}
399
400
401/**
402 * Destroy the given channel.
403 *
404 * @param ch channel to destroy
405 */
406static void
407channel_destroy (struct CadetChannel *ch)
408{
409 struct CadetReliableMessage *crm;
410
411 while (NULL != (crm = ch->head_sent))
412 {
413 GNUNET_assert (ch == crm->ch);
414 if (NULL != crm->qe)
415 {
416 GCT_send_cancel (crm->qe);
417 crm->qe = NULL;
418 }
419 GNUNET_CONTAINER_DLL_remove (ch->head_sent,
420 ch->tail_sent,
421 crm);
422 GNUNET_free (crm->data_message);
423 GNUNET_free (crm);
424 }
425 if (NULL != ch->owner)
426 {
427 free_channel_client (ch->owner);
428 ch->owner = NULL;
429 }
430 if (NULL != ch->dest)
431 {
432 free_channel_client (ch->dest);
433 ch->dest = NULL;
434 }
435 if (NULL != ch->last_control_qe)
436 {
437 GCT_send_cancel (ch->last_control_qe);
438 ch->last_control_qe = NULL;
439 }
440 if (NULL != ch->retry_data_task)
441 {
442 GNUNET_SCHEDULER_cancel (ch->retry_data_task);
443 ch->retry_data_task = NULL;
444 }
445 if (NULL != ch->retry_control_task)
446 {
447 GNUNET_SCHEDULER_cancel (ch->retry_control_task);
448 ch->retry_control_task = NULL;
449 }
450 if (GNUNET_NO == ch->is_loopback)
451 {
452 GCT_remove_channel (ch->t,
453 ch,
454 ch->ctn);
455 ch->t = NULL;
456 }
457 GNUNET_free (ch);
458}
459
460
461/**
462 * Send a channel create message.
463 *
464 * @param cls Channel for which to send.
465 */
466static void
467send_channel_open (void *cls);
468
469
470/**
471 * Function called once the tunnel confirms that we sent the
472 * create message. Delays for a bit until we retry.
473 *
474 * @param cls our `struct CadetChannel`.
475 */
476static void
477channel_open_sent_cb (void *cls)
478{
479 struct CadetChannel *ch = cls;
480
481 GNUNET_assert (NULL != ch->last_control_qe);
482 ch->last_control_qe = NULL;
483 ch->retry_time = GNUNET_TIME_STD_BACKOFF (ch->retry_time);
484 LOG (GNUNET_ERROR_TYPE_DEBUG,
485 "Sent CADET_CHANNEL_OPEN on %s, retrying in %s\n",
486 GCCH_2s (ch),
487 GNUNET_STRINGS_relative_time_to_string (ch->retry_time,
488 GNUNET_YES));
489 ch->retry_control_task
490 = GNUNET_SCHEDULER_add_delayed (ch->retry_time,
491 &send_channel_open,
492 ch);
493}
494
495
496/**
497 * Send a channel open message.
498 *
499 * @param cls Channel for which to send.
500 */
501static void
502send_channel_open (void *cls)
503{
504 struct CadetChannel *ch = cls;
505 struct GNUNET_CADET_ChannelOpenMessage msgcc;
506 uint32_t options;
507
508 ch->retry_control_task = NULL;
509 LOG (GNUNET_ERROR_TYPE_DEBUG,
510 "Sending CHANNEL_OPEN message for %s\n",
511 GCCH_2s (ch));
512 options = 0;
513 if (ch->nobuffer)
514 options |= GNUNET_CADET_OPTION_NOBUFFER;
515 if (ch->reliable)
516 options |= GNUNET_CADET_OPTION_RELIABLE;
517 if (ch->out_of_order)
518 options |= GNUNET_CADET_OPTION_OUT_OF_ORDER;
519 msgcc.header.size = htons (sizeof (msgcc));
520 msgcc.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN);
521 msgcc.opt = htonl (options);
522 msgcc.port = ch->port;
523 msgcc.ctn = ch->ctn;
524 ch->state = CADET_CHANNEL_OPEN_SENT;
525 ch->last_control_qe = GCT_send (ch->t,
526 &msgcc.header,
527 &channel_open_sent_cb,
528 ch);
529}
530
531
532/**
533 * Function called once and only once after a channel was bound
534 * to its tunnel via #GCT_add_channel() is ready for transmission.
535 * Note that this is only the case for channels that this peer
536 * initiates, as for incoming channels we assume that they are
537 * ready for transmission immediately upon receiving the open
538 * message. Used to bootstrap the #GCT_send() process.
539 *
540 * @param ch the channel for which the tunnel is now ready
541 */
542void
543GCCH_tunnel_up (struct CadetChannel *ch)
544{
545 GNUNET_assert (NULL == ch->retry_control_task);
546 LOG (GNUNET_ERROR_TYPE_DEBUG,
547 "Tunnel up, sending CHANNEL_OPEN on %s now\n",
548 GCCH_2s (ch));
549 ch->retry_control_task
550 = GNUNET_SCHEDULER_add_now (&send_channel_open,
551 ch);
552}
553
554
555/**
556 * Create a new channel.
557 *
558 * @param owner local client owning the channel
559 * @param ccn local number of this channel at the @a owner
560 * @param destination peer to which we should build the channel
561 * @param port desired port at @a destination
562 * @param options options for the channel
563 * @return handle to the new channel
564 */
565struct CadetChannel *
566GCCH_channel_local_new (struct CadetClient *owner,
567 struct GNUNET_CADET_ClientChannelNumber ccn,
568 struct CadetPeer *destination,
569 const struct GNUNET_HashCode *port,
570 uint32_t options)
571{
572 struct CadetChannel *ch;
573 struct CadetChannelClient *ccco;
574
575 ccco = GNUNET_new (struct CadetChannelClient);
576 ccco->c = owner;
577 ccco->ccn = ccn;
578 ccco->client_ready = GNUNET_YES;
579
580 ch = GNUNET_new (struct CadetChannel);
581 ch->mid_recv.mid = htonl (1); /* The OPEN_ACK counts as message 0! */
582 ch->nobuffer = (0 != (options & GNUNET_CADET_OPTION_NOBUFFER));
583 ch->reliable = (0 != (options & GNUNET_CADET_OPTION_RELIABLE));
584 ch->out_of_order = (0 != (options & GNUNET_CADET_OPTION_OUT_OF_ORDER));
585 ch->max_pending_messages = (ch->nobuffer) ? 1 : 4; /* FIXME: 4!? Do not hardcode! */
586 ch->owner = ccco;
587 ch->port = *port;
588 if (0 == memcmp (&my_full_id,
589 GCP_get_id (destination),
590 sizeof (struct GNUNET_PeerIdentity)))
591 {
592 struct CadetClient *c;
593
594 ch->is_loopback = GNUNET_YES;
595 c = GNUNET_CONTAINER_multihashmap_get (open_ports,
596 port);
597 if (NULL == c)
598 {
599 /* port closed, wait for it to possibly open */
600 (void) GNUNET_CONTAINER_multihashmap_put (loose_channels,
601 port,
602 ch,
603 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
604 LOG (GNUNET_ERROR_TYPE_DEBUG,
605 "Created loose incoming loopback channel to port %s\n",
606 GNUNET_h2s (&ch->port));
607 }
608 else
609 {
610 ch->dest = GNUNET_new (struct CadetChannelClient);
611 ch->dest->c = c;
612 ch->dest->client_ready = GNUNET_YES;
613 GCCH_bind (ch,
614 ch->dest->c);
615 }
616 }
617 else
618 {
619 ch->t = GCP_get_tunnel (destination,
620 GNUNET_YES);
621 ch->retry_time = CADET_INITIAL_RETRANSMIT_TIME;
622 ch->ctn = GCT_add_channel (ch->t,
623 ch);
624 }
625 GNUNET_STATISTICS_update (stats,
626 "# channels",
627 1,
628 GNUNET_NO);
629 LOG (GNUNET_ERROR_TYPE_DEBUG,
630 "Created channel to port %s at peer %s for %s using %s\n",
631 GNUNET_h2s (port),
632 GCP_2s (destination),
633 GSC_2s (owner),
634 (GNUNET_YES == ch->is_loopback) ? "loopback" : GCT_2s (ch->t));
635 return ch;
636}
637
638
639/**
640 * We had an incoming channel to a port that is closed.
641 * It has not been opened for a while, drop it.
642 *
643 * @param cls the channel to drop
644 */
645static void
646timeout_closed_cb (void *cls)
647{
648 struct CadetChannel *ch = cls;
649
650 ch->retry_control_task = NULL;
651 LOG (GNUNET_ERROR_TYPE_DEBUG,
652 "Closing incoming channel to port %s from peer %s due to timeout\n",
653 GNUNET_h2s (&ch->port),
654 GCP_2s (GCT_get_destination (ch->t)));
655 channel_destroy (ch);
656}
657
658
659/**
660 * Create a new channel based on a request coming in over the network.
661 *
662 * @param t tunnel to the remote peer
663 * @param ctn identifier of this channel in the tunnel
664 * @param port desired local port
665 * @param options options for the channel
666 * @return handle to the new channel
667 */
668struct CadetChannel *
669GCCH_channel_incoming_new (struct CadetTunnel *t,
670 struct GNUNET_CADET_ChannelTunnelNumber ctn,
671 const struct GNUNET_HashCode *port,
672 uint32_t options)
673{
674 struct CadetChannel *ch;
675 struct CadetClient *c;
676
677 ch = GNUNET_new (struct CadetChannel);
678 ch->port = *port;
679 ch->t = t;
680 ch->ctn = ctn;
681 ch->retry_time = CADET_INITIAL_RETRANSMIT_TIME;
682 ch->nobuffer = (0 != (options & GNUNET_CADET_OPTION_NOBUFFER));
683 ch->reliable = (0 != (options & GNUNET_CADET_OPTION_RELIABLE));
684 ch->out_of_order = (0 != (options & GNUNET_CADET_OPTION_OUT_OF_ORDER));
685 ch->max_pending_messages = (ch->nobuffer) ? 1 : 4; /* FIXME: 4!? Do not hardcode! */
686 GNUNET_STATISTICS_update (stats,
687 "# channels",
688 1,
689 GNUNET_NO);
690
691 c = GNUNET_CONTAINER_multihashmap_get (open_ports,
692 port);
693 if (NULL == c)
694 {
695 /* port closed, wait for it to possibly open */
696 (void) GNUNET_CONTAINER_multihashmap_put (loose_channels,
697 port,
698 ch,
699 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
700 ch->retry_control_task
701 = GNUNET_SCHEDULER_add_delayed (TIMEOUT_CLOSED_PORT,
702 &timeout_closed_cb,
703 ch);
704 LOG (GNUNET_ERROR_TYPE_DEBUG,
705 "Created loose incoming channel to port %s from peer %s\n",
706 GNUNET_h2s (&ch->port),
707 GCP_2s (GCT_get_destination (ch->t)));
708 }
709 else
710 {
711 GCCH_bind (ch,
712 c);
713 }
714 GNUNET_STATISTICS_update (stats,
715 "# channels",
716 1,
717 GNUNET_NO);
718 return ch;
719}
720
721
722/**
723 * Function called once the tunnel confirms that we sent the
724 * ACK message. Just remembers it was sent, we do not expect
725 * ACKs for ACKs ;-).
726 *
727 * @param cls our `struct CadetChannel`.
728 */
729static void
730send_ack_cb (void *cls)
731{
732 struct CadetChannel *ch = cls;
733
734 GNUNET_assert (NULL != ch->last_control_qe);
735 ch->last_control_qe = NULL;
736}
737
738
739/**
740 * Compute and send the current #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK to the other peer.
741 *
742 * @param ch channel to send the #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK for
743 */
744static void
745send_channel_data_ack (struct CadetChannel *ch)
746{
747 struct GNUNET_CADET_ChannelDataAckMessage msg;
748
749 msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK);
750 msg.header.size = htons (sizeof (msg));
751 msg.ctn = ch->ctn;
752 msg.mid.mid = htonl (ntohl (ch->mid_recv.mid) - 1);
753 msg.futures = GNUNET_htonll (ch->mid_futures);
754 if (NULL != ch->last_control_qe)
755 GCT_send_cancel (ch->last_control_qe);
756 ch->last_control_qe = GCT_send (ch->t,
757 &msg.header,
758 &send_ack_cb,
759 ch);
760}
761
762
763/**
764 * Send our initial #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK to the client confirming that the
765 * connection is up.
766 *
767 * @param cls the `struct CadetChannel`
768 */
769static void
770send_open_ack (void *cls)
771{
772 struct CadetChannel *ch = cls;
773 struct GNUNET_CADET_ChannelManageMessage msg;
774
775 LOG (GNUNET_ERROR_TYPE_DEBUG,
776 "Sending CHANNEL_OPEN_ACK on %s\n",
777 GCCH_2s (ch));
778 ch->retry_control_task = NULL;
779 msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK);
780 msg.header.size = htons (sizeof (msg));
781 msg.reserved = htonl (0);
782 msg.ctn = ch->ctn;
783 if (NULL != ch->last_control_qe)
784 GCT_send_cancel (ch->last_control_qe);
785 ch->last_control_qe = GCT_send (ch->t,
786 &msg.header,
787 &send_ack_cb,
788 ch);
789}
790
791
792/**
793 * We got a #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN message again for
794 * this channel. If the binding was successful, (re)transmit the
795 * #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK.
796 *
797 * @param ch channel that got the duplicate open
798 */
799void
800GCCH_handle_duplicate_open (struct CadetChannel *ch)
801{
802 if (NULL == ch->dest)
803 {
804 LOG (GNUNET_ERROR_TYPE_DEBUG,
805 "Ignoring duplicate channel OPEN on %s: port is closed\n",
806 GCCH_2s (ch));
807 return;
808 }
809 if (NULL != ch->retry_control_task)
810 {
811 LOG (GNUNET_ERROR_TYPE_DEBUG,
812 "Ignoring duplicate channel OPEN on %s: control message is pending\n",
813 GCCH_2s (ch));
814 return;
815 }
816 LOG (GNUNET_ERROR_TYPE_DEBUG,
817 "Retransmitting OPEN_ACK on %s\n",
818 GCCH_2s (ch));
819 ch->retry_control_task
820 = GNUNET_SCHEDULER_add_now (&send_open_ack,
821 ch);
822}
823
824
825/**
826 * Send a #GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK to the client to solicit more messages.
827 *
828 * @param ch channel the ack is for
829 * @param to_owner #GNUNET_YES to send to owner,
830 * #GNUNET_NO to send to dest
831 */
832static void
833send_ack_to_client (struct CadetChannel *ch,
834 int to_owner)
835{
836 struct GNUNET_MQ_Envelope *env;
837 struct GNUNET_CADET_LocalAck *ack;
838 struct CadetChannelClient *ccc;
839
840 env = GNUNET_MQ_msg (ack,
841 GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK);
842 ccc = (GNUNET_YES == to_owner) ? ch->owner : ch->dest;
843 ack->ccn = ccc->ccn;
844 LOG (GNUNET_ERROR_TYPE_DEBUG,
845 "Sending CADET_LOCAL_ACK to %s (%s) at ccn %X\n",
846 GSC_2s (ccc->c),
847 (GNUNET_YES == to_owner) ? "owner" : "dest",
848 ntohl (ack->ccn.channel_of_client));
849 GSC_send_to_client (ccc->c,
850 env);
851}
852
853
854/**
855 * A client is bound to the port that we have a channel
856 * open to. Send the acknowledgement for the connection
857 * request and establish the link with the client.
858 *
859 * @param ch open incoming channel
860 * @param c client listening on the respective port
861 */
862void
863GCCH_bind (struct CadetChannel *ch,
864 struct CadetClient *c)
865{
866 uint32_t options;
867 struct CadetChannelClient *cccd;
868
869 LOG (GNUNET_ERROR_TYPE_DEBUG,
870 "Binding %s from %s to port %s of %s\n",
871 GCCH_2s (ch),
872 GCT_2s (ch->t),
873 GNUNET_h2s (&ch->port),
874 GSC_2s (c));
875 if (NULL != ch->retry_control_task)
876 {
877 /* there might be a timeout task here */
878 GNUNET_SCHEDULER_cancel (ch->retry_control_task);
879 ch->retry_control_task = NULL;
880 }
881 options = 0;
882 if (ch->nobuffer)
883 options |= GNUNET_CADET_OPTION_NOBUFFER;
884 if (ch->reliable)
885 options |= GNUNET_CADET_OPTION_RELIABLE;
886 if (ch->out_of_order)
887 options |= GNUNET_CADET_OPTION_OUT_OF_ORDER;
888 cccd = GNUNET_new (struct CadetChannelClient);
889 ch->dest = cccd;
890 cccd->c = c;
891 cccd->client_ready = GNUNET_YES;
892 cccd->ccn = GSC_bind (c,
893 ch,
894 (GNUNET_YES == ch->is_loopback)
895 ? GCP_get (&my_full_id,
896 GNUNET_YES)
897 : GCT_get_destination (ch->t),
898 &ch->port,
899 options);
900 GNUNET_assert (ntohl (cccd->ccn.channel_of_client) <
901 GNUNET_CADET_LOCAL_CHANNEL_ID_CLI);
902 ch->mid_recv.mid = htonl (1); /* The OPEN counts as message 0! */
903 if (GNUNET_YES == ch->is_loopback)
904 {
905 ch->state = CADET_CHANNEL_OPEN_SENT;
906 GCCH_handle_channel_open_ack (ch);
907 }
908 else
909 {
910 /* notify other peer that we accepted the connection */
911 ch->retry_control_task
912 = GNUNET_SCHEDULER_add_now (&send_open_ack,
913 ch);
914 }
915 /* give client it's initial supply of ACKs */
916 GNUNET_assert (ntohl (cccd->ccn.channel_of_client) <
917 GNUNET_CADET_LOCAL_CHANNEL_ID_CLI);
918 for (unsigned int i=0;i<ch->max_pending_messages;i++)
919 send_ack_to_client (ch,
920 GNUNET_NO);
921}
922
923
924/**
925 * Destroy locally created channel. Called by the local client, so no
926 * need to tell the client.
927 *
928 * @param ch channel to destroy
929 * @param c client that caused the destruction
930 * @param ccn client number of the client @a c
931 */
932void
933GCCH_channel_local_destroy (struct CadetChannel *ch,
934 struct CadetClient *c,
935 struct GNUNET_CADET_ClientChannelNumber ccn)
936{
937 LOG (GNUNET_ERROR_TYPE_DEBUG,
938 "%s asks for destruction of %s\n",
939 GSC_2s (c),
940 GCCH_2s (ch));
941 GNUNET_assert (NULL != c);
942 if ( (NULL != ch->owner) &&
943 (c == ch->owner->c) &&
944 (ccn.channel_of_client == ch->owner->ccn.channel_of_client) )
945 {
946 free_channel_client (ch->owner);
947 ch->owner = NULL;
948 }
949 else if ( (NULL != ch->dest) &&
950 (c == ch->dest->c) &&
951 (ccn.channel_of_client == ch->dest->ccn.channel_of_client) )
952 {
953 free_channel_client (ch->dest);
954 ch->dest = NULL;
955 }
956 else
957 {
958 GNUNET_assert (0);
959 }
960
961 if (GNUNET_YES == ch->destroy)
962 {
963 /* other end already destroyed, with the local client gone, no need
964 to finish transmissions, just destroy immediately. */
965 channel_destroy (ch);
966 return;
967 }
968 if ( (NULL != ch->head_sent) ||
969 (NULL != ch->owner) ||
970 (NULL != ch->dest) )
971 {
972 /* Wait for other end to destroy us as well,
973 and otherwise allow send queue to be transmitted first */
974 ch->destroy = GNUNET_YES;
975 return;
976 }
977 /* If the we ever sent the CHANNEL_CREATE, we need to send a destroy message. */
978 if (CADET_CHANNEL_NEW != ch->state)
979 GCT_send_channel_destroy (ch->t,
980 ch->ctn);
981 /* Nothing left to do, just finish destruction */
982 channel_destroy (ch);
983}
984
985
986/**
987 * We got an acknowledgement for the creation of the channel
988 * (the port is open on the other side). Begin transmissions.
989 *
990 * @param ch channel to destroy
991 */
992void
993GCCH_handle_channel_open_ack (struct CadetChannel *ch)
994{
995 switch (ch->state)
996 {
997 case CADET_CHANNEL_NEW:
998 /* this should be impossible */
999 GNUNET_break (0);
1000 break;
1001 case CADET_CHANNEL_OPEN_SENT:
1002 if (NULL == ch->owner)
1003 {
1004 /* We're not the owner, wrong direction! */
1005 GNUNET_break_op (0);
1006 return;
1007 }
1008 LOG (GNUNET_ERROR_TYPE_DEBUG,
1009 "Received CHANNEL_OPEN_ACK for waiting %s, entering READY state\n",
1010 GCCH_2s (ch));
1011 if (NULL != ch->retry_control_task) /* can be NULL if ch->is_loopback */
1012 {
1013 GNUNET_SCHEDULER_cancel (ch->retry_control_task);
1014 ch->retry_control_task = NULL;
1015 }
1016 ch->state = CADET_CHANNEL_READY;
1017 /* On first connect, send client as many ACKs as we allow messages
1018 to be buffered! */
1019 for (unsigned int i=0;i<ch->max_pending_messages;i++)
1020 send_ack_to_client (ch,
1021 GNUNET_YES);
1022 break;
1023 case CADET_CHANNEL_READY:
1024 /* duplicate ACK, maybe we retried the CREATE. Ignore. */
1025 LOG (GNUNET_ERROR_TYPE_DEBUG,
1026 "Received duplicate channel OPEN_ACK for %s\n",
1027 GCCH_2s (ch));
1028 GNUNET_STATISTICS_update (stats,
1029 "# duplicate CREATE_ACKs",
1030 1,
1031 GNUNET_NO);
1032 break;
1033 }
1034}
1035
1036
1037/**
1038 * Test if element @a e1 comes before element @a e2.
1039 *
1040 * TODO: use opportunity to create generic list insertion sort
1041 * logic in container!
1042 *
1043 * @param cls closure, our `struct CadetChannel`
1044 * @param e1 an element of to sort
1045 * @param e2 another element to sort
1046 * @return #GNUNET_YES if @e1 < @e2, otherwise #GNUNET_NO
1047 */
1048static int
1049is_before (void *cls,
1050 void *e1,
1051 void *e2)
1052{
1053 struct CadetOutOfOrderMessage *m1 = e1;
1054 struct CadetOutOfOrderMessage *m2 = e2;
1055 uint32_t v1 = ntohl (m1->mid.mid);
1056 uint32_t v2 = ntohl (m2->mid.mid);
1057 uint32_t delta;
1058
1059 delta = v1 - v2;
1060 if (delta > (uint32_t) INT_MAX)
1061 {
1062 /* in overflow range, we can safely assume we wrapped around */
1063 return GNUNET_NO;
1064 }
1065 else
1066 {
1067 return GNUNET_YES;
1068 }
1069}
1070
1071
1072/**
1073 * We got payload data for a channel. Pass it on to the client
1074 * and send an ACK to the other end (once flow control allows it!)
1075 *
1076 * @param ch channel that got data
1077 * @param msg message that was received
1078 */
1079void
1080GCCH_handle_channel_plaintext_data (struct CadetChannel *ch,
1081 const struct GNUNET_CADET_ChannelAppDataMessage *msg)
1082{
1083 struct GNUNET_MQ_Envelope *env;
1084 struct GNUNET_CADET_LocalData *ld;
1085 struct CadetChannelClient *ccc;
1086 struct CadetOutOfOrderMessage *com;
1087 size_t payload_size;
1088
1089 GNUNET_assert (GNUNET_NO == ch->is_loopback);
1090 if ( (GNUNET_YES == ch->destroy) &&
1091 (NULL == ch->owner) &&
1092 (NULL == ch->dest) )
1093 {
1094 /* This client is gone, but we still have messages to send to
1095 the other end (which is why @a ch is not yet dead). However,
1096 we cannot pass messages to our client anymore. */
1097 LOG (GNUNET_ERROR_TYPE_DEBUG,
1098 "Dropping incoming payload on %s as this end is already closed\n",
1099 GCCH_2s (ch));
1100 /* FIXME: send back ACK/NACK/Closed notification
1101 to stop retransmissions! */
1102 return;
1103 }
1104 payload_size = ntohs (msg->header.size) - sizeof (*msg);
1105 env = GNUNET_MQ_msg_extra (ld,
1106 payload_size,
1107 GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA);
1108 ld->ccn = (NULL == ch->dest) ? ch->owner->ccn : ch->dest->ccn;
1109 GNUNET_memcpy (&ld[1],
1110 &msg[1],
1111 payload_size);
1112 ccc = (NULL != ch->owner) ? ch->owner : ch->dest;
1113 if ( (GNUNET_YES == ccc->client_ready) &&
1114 ( (GNUNET_YES == ch->out_of_order) ||
1115 (msg->mid.mid == ch->mid_recv.mid) ) )
1116 {
1117 LOG (GNUNET_ERROR_TYPE_DEBUG,
1118 "Giving %u bytes of payload from %s to client %s\n",
1119 (unsigned int) payload_size,
1120 GCCH_2s (ch),
1121 GSC_2s (ccc->c));
1122 ccc->client_ready = GNUNET_NO;
1123 GSC_send_to_client (ccc->c,
1124 env);
1125 ch->mid_recv.mid = htonl (1 + ntohl (ch->mid_recv.mid));
1126 ch->mid_futures >>= 1;
1127 }
1128 else
1129 {
1130 /* FIXME-SECURITY: if the element is WAY too far ahead,
1131 drop it (can't buffer too much!) */
1132 LOG (GNUNET_ERROR_TYPE_DEBUG,
1133 "Queuing %s payload of %u bytes on %s (mid %u, need %u first)\n",
1134 (GNUNET_YES == ccc->client_ready)
1135 ? "out-of-order"
1136 : "client-not-ready",
1137 (unsigned int) payload_size,
1138 GCCH_2s (ch),
1139 ntohl (msg->mid.mid),
1140 ntohl (ch->mid_recv.mid));
1141
1142 com = GNUNET_new (struct CadetOutOfOrderMessage);
1143 com->mid = msg->mid;
1144 com->env = env;
1145 /* sort into list ordered by "is_before" */
1146 if ( (NULL == ccc->head_recv) ||
1147 (GNUNET_YES == is_before (ch,
1148 com,
1149 ccc->head_recv)) )
1150 {
1151 GNUNET_CONTAINER_DLL_insert (ccc->head_recv,
1152 ccc->tail_recv,
1153 com);
1154 }
1155 else
1156 {
1157 struct CadetOutOfOrderMessage *pos;
1158
1159 for (pos = ccc->head_recv;
1160 NULL != pos;
1161 pos = pos->next)
1162 {
1163 if (GNUNET_YES !=
1164 is_before (NULL,
1165 pos,
1166 com))
1167 break;
1168 }
1169 if (NULL == pos)
1170 GNUNET_CONTAINER_DLL_insert_tail (ccc->head_recv,
1171 ccc->tail_recv,
1172 com);
1173 else
1174 GNUNET_CONTAINER_DLL_insert_after (ccc->head_recv,
1175 ccc->tail_recv,
1176 com,
1177 pos->prev);
1178 }
1179 }
1180}
1181
1182
1183/**
1184 * We got an acknowledgement for payload data for a channel.
1185 * Possibly resume transmissions.
1186 *
1187 * @param ch channel that got the ack
1188 * @param ack details about what was received
1189 */
1190void
1191GCCH_handle_channel_plaintext_data_ack (struct CadetChannel *ch,
1192 const struct GNUNET_CADET_ChannelDataAckMessage *ack)
1193{
1194 struct CadetReliableMessage *crm;
1195
1196 GNUNET_break (GNUNET_NO == ch->is_loopback);
1197 if (GNUNET_NO == ch->reliable)
1198 {
1199 /* not expecting ACKs on unreliable channel, odd */
1200 GNUNET_break_op (0);
1201 return;
1202 }
1203 for (crm = ch->head_sent;
1204 NULL != crm;
1205 crm = crm->next)
1206 if (ack->mid.mid == crm->data_message->mid.mid)
1207 break;
1208 if (NULL == crm)
1209 {
1210 /* ACK for message we already dropped, might have been a
1211 duplicate ACK? Ignore. */
1212 LOG (GNUNET_ERROR_TYPE_DEBUG,
1213 "Duplicate DATA_ACK on %s, ignoring\n",
1214 GCCH_2s (ch));
1215 GNUNET_STATISTICS_update (stats,
1216 "# duplicate DATA_ACKs",
1217 1,
1218 GNUNET_NO);
1219 return;
1220 }
1221 GNUNET_CONTAINER_DLL_remove (ch->head_sent,
1222 ch->tail_sent,
1223 crm);
1224 GNUNET_free (crm->data_message);
1225 GNUNET_free (crm);
1226 ch->pending_messages--;
1227 send_ack_to_client (ch,
1228 (NULL == ch->owner)
1229 ? GNUNET_NO
1230 : GNUNET_YES);
1231 GNUNET_assert (ch->pending_messages < ch->max_pending_messages);
1232 LOG (GNUNET_ERROR_TYPE_DEBUG,
1233 "Received DATA_ACK on %s for message %u (%u ACKs pending)\n",
1234 GCCH_2s (ch),
1235 (unsigned int) ntohl (ack->mid.mid),
1236 ch->pending_messages);
1237 send_ack_to_client (ch,
1238 (NULL == ch->owner)
1239 ? GNUNET_NO
1240 : GNUNET_YES);
1241}
1242
1243
1244/**
1245 * Destroy channel, based on the other peer closing the
1246 * connection. Also needs to remove this channel from
1247 * the tunnel.
1248 *
1249 * @param ch channel to destroy
1250 */
1251void
1252GCCH_handle_remote_destroy (struct CadetChannel *ch)
1253{
1254 struct CadetChannelClient *ccc;
1255
1256 GNUNET_assert (GNUNET_NO == ch->is_loopback);
1257 LOG (GNUNET_ERROR_TYPE_DEBUG,
1258 "Received remote channel DESTROY for %s\n",
1259 GCCH_2s (ch));
1260 if (GNUNET_YES == ch->destroy)
1261 {
1262 /* Local client already gone, this is instant-death. */
1263 channel_destroy (ch);
1264 return;
1265 }
1266 ccc = (NULL != ch->owner) ? ch->owner : ch->dest;
1267 if (NULL != ccc->head_recv)
1268 {
1269 LOG (GNUNET_ERROR_TYPE_WARNING,
1270 "Lost end of transmission due to remote shutdown on %s\n",
1271 GCCH_2s (ch));
1272 /* FIXME: change API to notify client about truncated transmission! */
1273 }
1274 ch->destroy = GNUNET_YES;
1275 GSC_handle_remote_channel_destroy (ccc->c,
1276 ccc->ccn,
1277 ch);
1278 channel_destroy (ch);
1279}
1280
1281
1282/**
1283 * Function called once the tunnel has sent one of our messages.
1284 * If the message is unreliable, simply frees the `crm`. If the
1285 * message was reliable, calculate retransmission time and
1286 * wait for ACK (or retransmit).
1287 *
1288 * @param cls the `struct CadetReliableMessage` that was sent
1289 */
1290static void
1291data_sent_cb (void *cls);
1292
1293
1294/**
1295 * We need to retry a transmission, the last one took too long to
1296 * be acknowledged.
1297 *
1298 * @param cls the `struct CadetChannel` where we need to retransmit
1299 */
1300static void
1301retry_transmission (void *cls)
1302{
1303 struct CadetChannel *ch = cls;
1304 struct CadetReliableMessage *crm = ch->head_sent;
1305
1306 ch->retry_data_task = NULL;
1307 GNUNET_assert (NULL == crm->qe);
1308 crm->qe = GCT_send (ch->t,
1309 &crm->data_message->header,
1310 &data_sent_cb,
1311 crm);
1312}
1313
1314
1315/**
1316 * Function called once the tunnel has sent one of our messages.
1317 * If the message is unreliable, simply frees the `crm`. If the
1318 * message was reliable, calculate retransmission time and
1319 * wait for ACK (or retransmit).
1320 *
1321 * @param cls the `struct CadetReliableMessage` that was sent
1322 */
1323static void
1324data_sent_cb (void *cls)
1325{
1326 struct CadetReliableMessage *crm = cls;
1327 struct CadetChannel *ch = crm->ch;
1328 struct CadetReliableMessage *off;
1329
1330 GNUNET_assert (GNUNET_NO == ch->is_loopback);
1331 crm->qe = NULL;
1332 GNUNET_CONTAINER_DLL_remove (ch->head_sent,
1333 ch->tail_sent,
1334 crm);
1335 if (GNUNET_NO == ch->reliable)
1336 {
1337 GNUNET_free (crm);
1338 ch->pending_messages--;
1339 send_ack_to_client (ch,
1340 (NULL == ch->owner)
1341 ? GNUNET_NO
1342 : GNUNET_YES);
1343 return;
1344 }
1345 if (0 == crm->retry_delay.rel_value_us)
1346 crm->retry_delay = ch->expected_delay;
1347 crm->next_retry = GNUNET_TIME_relative_to_absolute (crm->retry_delay);
1348
1349 /* find position for re-insertion into the DLL */
1350 if ( (NULL == ch->head_sent) ||
1351 (crm->next_retry.abs_value_us < ch->head_sent->next_retry.abs_value_us) )
1352 {
1353 /* insert at HEAD, also (re)schedule retry task! */
1354 GNUNET_CONTAINER_DLL_insert (ch->head_sent,
1355 ch->tail_sent,
1356 crm);
1357 if (NULL != ch->retry_data_task)
1358 GNUNET_SCHEDULER_cancel (ch->retry_data_task);
1359 ch->retry_data_task
1360 = GNUNET_SCHEDULER_add_delayed (crm->retry_delay,
1361 &retry_transmission,
1362 ch);
1363 return;
1364 }
1365 for (off = ch->head_sent; NULL != off; off = off->next)
1366 if (crm->next_retry.abs_value_us < off->next_retry.abs_value_us)
1367 break;
1368 if (NULL == off)
1369 {
1370 /* insert at tail */
1371 GNUNET_CONTAINER_DLL_insert_tail (ch->head_sent,
1372 ch->tail_sent,
1373 crm);
1374 }
1375 else
1376 {
1377 /* insert before off */
1378 GNUNET_CONTAINER_DLL_insert_after (ch->head_sent,
1379 ch->tail_sent,
1380 off->prev,
1381 crm);
1382 }
1383}
1384
1385
1386/**
1387 * Handle data given by a client.
1388 *
1389 * Check whether the client is allowed to send in this tunnel, save if
1390 * channel is reliable and send an ACK to the client if there is still
1391 * buffer space in the tunnel.
1392 *
1393 * @param ch Channel.
1394 * @param sender_ccn ccn of the sender
1395 * @param buf payload to transmit.
1396 * @param buf_len number of bytes in @a buf
1397 * @return #GNUNET_OK if everything goes well,
1398 * #GNUNET_SYSERR in case of an error.
1399 */
1400int
1401GCCH_handle_local_data (struct CadetChannel *ch,
1402 struct GNUNET_CADET_ClientChannelNumber sender_ccn,
1403 const char *buf,
1404 size_t buf_len)
1405{
1406 struct CadetReliableMessage *crm;
1407
1408 if (ch->pending_messages > ch->max_pending_messages)
1409 {
1410 GNUNET_break (0);
1411 return GNUNET_SYSERR;
1412 }
1413 ch->pending_messages++;
1414
1415 if (GNUNET_YES == ch->is_loopback)
1416 {
1417 struct CadetChannelClient *receiver;
1418 struct GNUNET_MQ_Envelope *env;
1419 struct GNUNET_CADET_LocalData *ld;
1420 int to_owner;
1421
1422 env = GNUNET_MQ_msg_extra (ld,
1423 buf_len,
1424 GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA);
1425 if (sender_ccn.channel_of_client ==
1426 ch->owner->ccn.channel_of_client)
1427 {
1428 receiver = ch->dest;
1429 to_owner = GNUNET_NO;
1430 }
1431 else
1432 {
1433 GNUNET_assert (sender_ccn.channel_of_client ==
1434 ch->dest->ccn.channel_of_client);
1435 receiver = ch->owner;
1436 to_owner = GNUNET_YES;
1437 }
1438 ld->ccn = receiver->ccn;
1439 GNUNET_memcpy (&ld[1],
1440 buf,
1441 buf_len);
1442 /* FIXME: this does not provide for flow control! */
1443 GSC_send_to_client (receiver->c,
1444 env);
1445 send_ack_to_client (ch,
1446 to_owner);
1447 return GNUNET_OK;
1448 }
1449
1450 /* Everything is correct, send the message. */
1451 crm = GNUNET_malloc (sizeof (*crm));
1452 crm->ch = ch;
1453 crm->data_message = GNUNET_malloc (sizeof (struct GNUNET_CADET_ChannelAppDataMessage)
1454 + buf_len);
1455 crm->data_message->header.size = htons (sizeof (struct GNUNET_CADET_ChannelAppDataMessage) + buf_len);
1456 crm->data_message->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA);
1457 ch->mid_send.mid = htonl (ntohl (ch->mid_send.mid) + 1);
1458 crm->data_message->mid = ch->mid_send;
1459 crm->data_message->ctn = ch->ctn;
1460 GNUNET_memcpy (&crm->data_message[1],
1461 buf,
1462 buf_len);
1463 GNUNET_CONTAINER_DLL_insert (ch->head_sent,
1464 ch->tail_sent,
1465 crm);
1466 LOG (GNUNET_ERROR_TYPE_DEBUG,
1467 "Sending %u bytes from local client to %s\n",
1468 buf_len,
1469 GCCH_2s (ch));
1470 crm->qe = GCT_send (ch->t,
1471 &crm->data_message->header,
1472 &data_sent_cb,
1473 crm);
1474 return GNUNET_OK;
1475}
1476
1477
1478/**
1479 * Handle ACK from client on local channel. Means the client is ready
1480 * for more data, see if we have any for it.
1481 *
1482 * @param ch channel to destroy
1483 * @param client_ccn ccn of the client sending the ack
1484 */
1485void
1486GCCH_handle_local_ack (struct CadetChannel *ch,
1487 struct GNUNET_CADET_ClientChannelNumber client_ccn)
1488{
1489 struct CadetChannelClient *ccc;
1490 struct CadetOutOfOrderMessage *com;
1491
1492 if ( (NULL != ch->owner) &&
1493 (ch->owner->ccn.channel_of_client == client_ccn.channel_of_client) )
1494 ccc = ch->owner;
1495 else if ( (NULL != ch->dest) &&
1496 (ch->dest->ccn.channel_of_client == client_ccn.channel_of_client) )
1497 ccc = ch->dest;
1498 else
1499 GNUNET_assert (0);
1500 ccc->client_ready = GNUNET_YES;
1501 com = ccc->head_recv;
1502 if (NULL == com)
1503 {
1504 LOG (GNUNET_ERROR_TYPE_DEBUG,
1505 "Got LOCAL_ACK, %s-%X ready to receive more data (but none pending)!\n",
1506 GSC_2s (ccc->c),
1507 ntohl (ccc->ccn.channel_of_client));
1508 return; /* none pending */
1509 }
1510 if ( (com->mid.mid != ch->mid_recv.mid) &&
1511 (GNUNET_NO == ch->out_of_order) )
1512 return; /* missing next one in-order */
1513
1514 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1515 "Got LOCAL ACK, passing payload message to %s-%X on %s\n",
1516 GSC_2s (ccc->c),
1517 ntohl (ccc->ccn.channel_of_client),
1518 GCCH_2s (ch));
1519
1520 /* all good, pass next message to client */
1521 GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
1522 ccc->tail_recv,
1523 com);
1524 /* FIXME: if unreliable, this is not aggressive
1525 enough, as it would be OK to have lost some! */
1526 ch->mid_recv.mid = htonl (1 + ntohl (com->mid.mid));
1527 ch->mid_futures >>= 1; /* equivalent to division by 2 */
1528 ccc->client_ready = GNUNET_NO;
1529 GSC_send_to_client (ccc->c,
1530 com->env);
1531 GNUNET_free (com);
1532 if ( (0xFFULL == (ch->mid_futures & 0xFFULL)) &&
1533 (GNUNET_YES == ch->reliable) )
1534 {
1535 /* The next 15 messages were also already received (0xFF), this
1536 suggests that the sender may be blocked on flow control
1537 urgently waiting for an ACK from us. (As we have an inherent
1538 maximum of 64 bits, and 15 is getting too close for comfort.)
1539 So we should send one now. */
1540 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1541 "Sender on %s likely blocked on flow-control, sending ACK now.\n",
1542 GCCH_2s (ch));
1543 if (GNUNET_YES == ch->reliable)
1544 send_channel_data_ack (ch);
1545 }
1546
1547 if (NULL != ccc->head_recv)
1548 return;
1549 if (GNUNET_NO == ch->destroy)
1550 return;
1551 GCT_send_channel_destroy (ch->t,
1552 ch->ctn);
1553 channel_destroy (ch);
1554}
1555
1556
1557#define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-chn",__VA_ARGS__)
1558
1559
1560/**
1561 * Log channel info.
1562 *
1563 * @param ch Channel.
1564 * @param level Debug level to use.
1565 */
1566void
1567GCCH_debug (struct CadetChannel *ch,
1568 enum GNUNET_ErrorType level)
1569{
1570 int do_log;
1571
1572 do_log = GNUNET_get_log_call_status (level & (~GNUNET_ERROR_TYPE_BULK),
1573 "cadet-chn",
1574 __FILE__, __FUNCTION__, __LINE__);
1575 if (0 == do_log)
1576 return;
1577
1578 if (NULL == ch)
1579 {
1580 LOG2 (level, "CHN *** DEBUG NULL CHANNEL ***\n");
1581 return;
1582 }
1583 LOG2 (level,
1584 "CHN %s:%X (%p)\n",
1585 GCT_2s (ch->t),
1586 ch->ctn,
1587 ch);
1588 if (NULL != ch->owner)
1589 {
1590 LOG2 (level,
1591 "CHN origin %s ready %s local-id: %u\n",
1592 GSC_2s (ch->owner->c),
1593 ch->owner->client_ready ? "YES" : "NO",
1594 ntohl (ch->owner->ccn.channel_of_client));
1595 }
1596 if (NULL != ch->dest)
1597 {
1598 LOG2 (level,
1599 "CHN destination %s ready %s local-id: %u\n",
1600 GSC_2s (ch->dest->c),
1601 ch->dest->client_ready ? "YES" : "NO",
1602 ntohl (ch->dest->ccn.channel_of_client));
1603 }
1604 LOG2 (level,
1605 "CHN Message IDs recv: %d (%LLX), send: %d\n",
1606 ntohl (ch->mid_recv.mid),
1607 (unsigned long long) ch->mid_futures,
1608 ntohl (ch->mid_send.mid));
1609}
1610
1611
1612
1613/* 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 e572b7633..000000000
--- a/src/cadet/gnunet-service-cadet-new_channel.h
+++ /dev/null
@@ -1,249 +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 */
163void
164GCCH_handle_duplicate_open (struct CadetChannel *ch);
165
166
167/**
168 * We got payload data for a channel. Pass it on to the client.
169 *
170 * @param ch channel that got data
171 * @param msg message that was received
172 */
173void
174GCCH_handle_channel_plaintext_data (struct CadetChannel *ch,
175 const struct GNUNET_CADET_ChannelAppDataMessage *msg);
176
177
178/**
179 * We got an acknowledgement for payload data for a channel.
180 * Possibly resume transmissions.
181 *
182 * @param ch channel that got the ack
183 * @param ack details about what was received
184 */
185void
186GCCH_handle_channel_plaintext_data_ack (struct CadetChannel *ch,
187 const struct GNUNET_CADET_ChannelDataAckMessage *ack);
188
189
190/**
191 * We got an acknowledgement for the creation of the channel
192 * (the port is open on the other side). Begin transmissions.
193 *
194 * @param ch channel to destroy
195 */
196void
197GCCH_handle_channel_open_ack (struct CadetChannel *ch);
198
199
200/**
201 * Destroy channel, based on the other peer closing the
202 * connection. Also needs to remove this channel from
203 * the tunnel.
204 *
205 * FIXME: need to make it possible to defer destruction until we have
206 * received all messages up to the destroy, and right now the destroy
207 * message (and this API) fails to give is the information we need!
208 *
209 * FIXME: also need to know if the other peer got a destroy from
210 * us before!
211 *
212 * @param ch channel to destroy
213 */
214void
215GCCH_handle_remote_destroy (struct CadetChannel *ch);
216
217
218/**
219 * Handle data given by a client.
220 *
221 * Check whether the client is allowed to send in this tunnel, save if
222 * channel is reliable and send an ACK to the client if there is still
223 * buffer space in the tunnel.
224 *
225 * @param ch Channel.
226 * @param sender_ccn ccn of the sender
227 * @param buf payload to transmit.
228 * @param buf_len number of bytes in @a buf
229 * @return #GNUNET_OK if everything goes well,
230 * #GNUNET_SYSERR in case of an error.
231 */
232int
233GCCH_handle_local_data (struct CadetChannel *ch,
234 struct GNUNET_CADET_ClientChannelNumber sender_ccn,
235 const char *buf,
236 size_t buf_len);
237
238
239/**
240 * Handle ACK from client on local channel.
241 *
242 * @param ch channel to destroy
243 * @param client_ccn ccn of the client sending the ack
244 */
245void
246GCCH_handle_local_ack (struct CadetChannel *ch,
247 struct GNUNET_CADET_ClientChannelNumber client_ccn);
248
249#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 60389008c..000000000
--- a/src/cadet/gnunet-service-cadet-new_connection.c
+++ /dev/null
@@ -1,709 +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.c
24 * @brief management of CORE-level end-to-end connections; establishes
25 * end-to-end routes and transmits messages along the route
26 * @author Bartlomiej Polot
27 * @author Christian Grothoff
28 *
29 * TODO:
30 * - Optimization: keepalive messages / timeout (timeout to be done @ peer level!)
31 * - Optimization: keep performance metrics (?)
32 */
33#include "platform.h"
34#include "gnunet-service-cadet-new_channel.h"
35#include "gnunet-service-cadet-new_connection.h"
36#include "gnunet-service-cadet-new_paths.h"
37#include "gnunet-service-cadet-new_peer.h"
38#include "gnunet-service-cadet-new_tunnels.h"
39#include "gnunet_cadet_service.h"
40#include "cadet_protocol.h"
41
42
43#define LOG(level, ...) GNUNET_log_from(level,"cadet-con",__VA_ARGS__)
44
45
46/**
47 * All the states a connection can be in.
48 */
49enum CadetConnectionState
50{
51 /**
52 * Uninitialized status, we have not yet even gotten the message queue.
53 */
54 CADET_CONNECTION_NEW,
55
56 /**
57 * Connection create message in queue, awaiting transmission by CORE.
58 */
59 CADET_CONNECTION_SENDING_CREATE,
60
61 /**
62 * Connection create message sent, waiting for ACK.
63 */
64 CADET_CONNECTION_SENT,
65
66 /**
67 * We are an inbound connection, and received a CREATE. Need to
68 * send an CREATE_ACK back.
69 */
70 CADET_CONNECTION_CREATE_RECEIVED,
71
72 /**
73 * Connection confirmed, ready to carry traffic.
74 */
75 CADET_CONNECTION_READY
76
77};
78
79
80/**
81 * Low-level connection to a destination.
82 */
83struct CadetConnection
84{
85
86 /**
87 * ID of the connection.
88 */
89 struct GNUNET_CADET_ConnectionTunnelIdentifier cid;
90
91 /**
92 * To which peer does this connection go?
93 */
94 struct CadetPeer *destination;
95
96 /**
97 * Which tunnel is using this connection?
98 */
99 struct CadetTConnection *ct;
100
101 /**
102 * Path we are using to our destination.
103 */
104 struct CadetPeerPath *path;
105
106 /**
107 * Pending message, NULL if we are ready to transmit.
108 */
109 struct GNUNET_MQ_Envelope *env;
110
111 /**
112 * Handle for calling #GCP_request_mq_cancel() once we are finished.
113 */
114 struct GCP_MessageQueueManager *mq_man;
115
116 /**
117 * Task for connection maintenance.
118 */
119 struct GNUNET_SCHEDULER_Task *task;
120
121 /**
122 * Function to call once we are ready to transmit.
123 */
124 GCC_ReadyCallback ready_cb;
125
126 /**
127 * Closure for @e ready_cb.
128 */
129 void *ready_cb_cls;
130
131 /**
132 * How long do we wait before we try again with a CREATE message?
133 */
134 struct GNUNET_TIME_Relative retry_delay;
135
136 /**
137 * State of the connection.
138 */
139 enum CadetConnectionState state;
140
141 /**
142 * Offset of our @e destination in @e path.
143 */
144 unsigned int off;
145
146 /**
147 * Are we ready to transmit via @e mq_man right now?
148 */
149 int mqm_ready;
150
151};
152
153
154/**
155 * Destroy a connection.
156 *
157 * @param cc connection to destroy
158 */
159void
160GCC_destroy (struct CadetConnection *cc)
161{
162 struct GNUNET_MQ_Envelope *env = NULL;
163
164 LOG (GNUNET_ERROR_TYPE_DEBUG,
165 "Destroying %s\n",
166 GCC_2s (cc));
167 if (CADET_CONNECTION_SENDING_CREATE != cc->state)
168 {
169 struct GNUNET_CADET_ConnectionDestroyMessage *destroy_msg;
170
171 /* Need to notify next hop that we are down. */
172 env = GNUNET_MQ_msg (destroy_msg,
173 GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY);
174 destroy_msg->cid = cc->cid;
175 }
176 if (NULL != cc->mq_man)
177 {
178 GCP_request_mq_cancel (cc->mq_man,
179 env);
180 cc->mq_man = NULL;
181 }
182 if (NULL != cc->task)
183 {
184 GNUNET_SCHEDULER_cancel (cc->task);
185 cc->task = NULL;
186 }
187 GCPP_del_connection (cc->path,
188 cc->off,
189 cc);
190 GNUNET_assert (GNUNET_YES ==
191 GNUNET_CONTAINER_multishortmap_remove (connections,
192 &GCC_get_id (cc)->connection_of_tunnel,
193 cc));
194 GNUNET_free (cc);
195}
196
197
198/**
199 * Return the tunnel associated with this connection.
200 *
201 * @param cc connection to query
202 * @return corresponding entry in the tunnel's connection list
203 */
204struct CadetTConnection *
205GCC_get_ct (struct CadetConnection *cc)
206{
207 return cc->ct;
208}
209
210
211/**
212 * A CADET_CONNECTION_ACK was received for this connection, implying
213 * that the end-to-end connection is up. Process it.
214 *
215 * @param cc the connection that got the ACK.
216 */
217void
218GCC_handle_connection_create_ack (struct CadetConnection *cc)
219{
220 LOG (GNUNET_ERROR_TYPE_DEBUG,
221 "Received CADET_CONNECTION_CREATE_ACK for %s in state %d (%s)\n",
222 GCC_2s (cc),
223 cc->state,
224 (GNUNET_YES == cc->mqm_ready) ? "MQM ready" : "MQM busy");
225 if (NULL != cc->task)
226 {
227 GNUNET_SCHEDULER_cancel (cc->task);
228 cc->task = NULL;
229 }
230#if FIXME_KEEPALIVE
231 cc->task = GNUNET_SCHEDULER_add_delayed (cc->keepalive_period,
232 &send_keepalive,
233 cc);
234#endif
235 cc->state = CADET_CONNECTION_READY;
236 if (GNUNET_YES == cc->mqm_ready)
237 cc->ready_cb (cc->ready_cb_cls,
238 GNUNET_YES);
239}
240
241
242/**
243 * Handle KX message.
244 *
245 * @param cc connection that received encrypted message
246 * @param msg the key exchange message
247 */
248void
249GCC_handle_kx (struct CadetConnection *cc,
250 const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg)
251{
252 if (CADET_CONNECTION_SENT == cc->state)
253 {
254 /* We didn't get the CADET_CONNECTION_CREATE_ACK, but instead got payload. That's fine,
255 clearly something is working, so pretend we got an ACK. */
256 LOG (GNUNET_ERROR_TYPE_DEBUG,
257 "Faking connection CADET_CONNECTION_CREATE_ACK for %s due to KX\n",
258 GCC_2s (cc));
259 GCC_handle_connection_create_ack (cc);
260 }
261 GCT_handle_kx (cc->ct,
262 msg);
263}
264
265
266/**
267 * Handle encrypted message.
268 *
269 * @param cc connection that received encrypted message
270 * @param msg the encrypted message to decrypt
271 */
272void
273GCC_handle_encrypted (struct CadetConnection *cc,
274 const struct GNUNET_CADET_TunnelEncryptedMessage *msg)
275{
276 if (CADET_CONNECTION_SENT == cc->state)
277 {
278 /* We didn't get the CREATE_ACK, but instead got payload. That's fine,
279 clearly something is working, so pretend we got an ACK. */
280 LOG (GNUNET_ERROR_TYPE_DEBUG,
281 "Faking connection ACK for %s due to ENCRYPTED payload\n",
282 GCC_2s (cc));
283 GCC_handle_connection_create_ack (cc);
284 }
285 GCT_handle_encrypted (cc->ct,
286 msg);
287}
288
289
290/**
291 * Send a CREATE message to the first hop.
292 *
293 * @param cls the `struct CadetConnection` to initiate
294 */
295static void
296send_create (void *cls)
297{
298 struct CadetConnection *cc = cls;
299 struct GNUNET_CADET_ConnectionCreateMessage *create_msg;
300 struct GNUNET_PeerIdentity *pids;
301 struct GNUNET_MQ_Envelope *env;
302 unsigned int path_length;
303
304 cc->task = NULL;
305 GNUNET_assert (GNUNET_YES == cc->mqm_ready);
306 path_length = GCPP_get_length (cc->path);
307 env = GNUNET_MQ_msg_extra (create_msg,
308 (1 + path_length) * sizeof (struct GNUNET_PeerIdentity),
309 GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE);
310 create_msg->cid = cc->cid;
311 pids = (struct GNUNET_PeerIdentity *) &create_msg[1];
312 pids[0] = my_full_id;
313 for (unsigned int i=0;i<path_length;i++)
314 pids[i + 1] = *GCP_get_id (GCPP_get_peer_at_offset (cc->path,
315 i));
316 LOG (GNUNET_ERROR_TYPE_DEBUG,
317 "Sending CADET_CONNECTION_CREATE message for %s\n",
318 GCC_2s (cc));
319 cc->env = env;
320 cc->mqm_ready = GNUNET_NO;
321 cc->state = CADET_CONNECTION_SENT;
322 GCP_send (cc->mq_man,
323 env);
324}
325
326
327/**
328 * Send a CREATE_ACK message towards the origin.
329 *
330 * @param cls the `struct CadetConnection` to initiate
331 */
332static void
333send_create_ack (void *cls)
334{
335 struct CadetConnection *cc = cls;
336 struct GNUNET_CADET_ConnectionCreateAckMessage *ack_msg;
337 struct GNUNET_MQ_Envelope *env;
338
339 cc->task = NULL;
340 GNUNET_assert (CADET_CONNECTION_CREATE_RECEIVED == cc->state);
341 LOG (GNUNET_ERROR_TYPE_DEBUG,
342 "Sending CONNECTION_CREATE_ACK message for %s\n",
343 GCC_2s (cc));
344 GNUNET_assert (GNUNET_YES == cc->mqm_ready);
345 env = GNUNET_MQ_msg (ack_msg,
346 GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK);
347 ack_msg->cid = cc->cid;
348 cc->env = env;
349 cc->mqm_ready = GNUNET_NO;
350 cc->state = CADET_CONNECTION_READY;
351 GCP_send (cc->mq_man,
352 env);
353}
354
355
356/**
357 * We got a #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE for a
358 * connection that we already have. Either our ACK got lost
359 * or something is fishy. Consider retransmitting the ACK.
360 *
361 * @param cc connection that got the duplicate CREATE
362 */
363void
364GCC_handle_duplicate_create (struct CadetConnection *cc)
365{
366 if (GNUNET_YES == cc->mqm_ready)
367 {
368 LOG (GNUNET_ERROR_TYPE_DEBUG,
369 "Got duplicate CREATE for %s, scheduling another ACK (%s)\n",
370 GCC_2s (cc),
371 (GNUNET_YES == cc->mqm_ready) ? "MQM ready" : "MQM busy");
372 /* Tell tunnel that we are not ready for transmission anymore
373 (until CREATE_ACK is done) */
374 cc->ready_cb (cc->ready_cb_cls,
375 GNUNET_NO);
376 /* Revert back to the state of having only received the 'CREATE',
377 and immediately proceed to send the CREATE_ACK. */
378 cc->state = CADET_CONNECTION_CREATE_RECEIVED;
379 if (NULL != cc->task)
380 GNUNET_SCHEDULER_cancel (cc->task);
381 cc->task = GNUNET_SCHEDULER_add_now (&send_create_ack,
382 cc);
383 }
384 else
385 {
386 /* We are currently sending something else back, which
387 can only be an ACK or payload, either of which would
388 do. So actually no need to do anything. */
389 LOG (GNUNET_ERROR_TYPE_DEBUG,
390 "Got duplicate CREATE for %s. MQ is busy, not queueing another ACK\n",
391 GCC_2s (cc));
392 }
393}
394
395
396/**
397 * There has been a change in the message queue existence for our
398 * peer at the first hop. Adjust accordingly.
399 *
400 * @param cls the `struct CadetConnection`
401 * @param available #GNUNET_YES if sending is now possible,
402 * #GNUNET_NO if sending is no longer possible
403 * #GNUNET_SYSERR if sending is no longer possible
404 * and the last envelope was discarded
405 */
406static void
407manage_first_hop_mq (void *cls,
408 int available)
409{
410 struct CadetConnection *cc = cls;
411
412 if (GNUNET_YES != available)
413 {
414 /* Connection is down, for now... */
415 LOG (GNUNET_ERROR_TYPE_DEBUG,
416 "Core MQ for %s went down\n",
417 GCC_2s (cc));
418 cc->mqm_ready = GNUNET_NO;
419 cc->state = CADET_CONNECTION_NEW;
420 cc->retry_delay = GNUNET_TIME_UNIT_ZERO;
421 if (NULL != cc->task)
422 {
423 GNUNET_SCHEDULER_cancel (cc->task);
424 cc->task = NULL;
425 }
426 cc->ready_cb (cc->ready_cb_cls,
427 GNUNET_NO);
428 return;
429 }
430
431 cc->mqm_ready = GNUNET_YES;
432 LOG (GNUNET_ERROR_TYPE_DEBUG,
433 "Core MQ for %s became available in state %d\n",
434 GCC_2s (cc),
435 cc->state);
436 switch (cc->state)
437 {
438 case CADET_CONNECTION_NEW:
439 /* Transmit immediately */
440 cc->task = GNUNET_SCHEDULER_add_now (&send_create,
441 cc);
442 break;
443 case CADET_CONNECTION_SENDING_CREATE:
444 /* Should not be possible to be called in this state. */
445 GNUNET_assert (0);
446 break;
447 case CADET_CONNECTION_SENT:
448 /* Retry a bit later... */
449 cc->retry_delay = GNUNET_TIME_STD_BACKOFF (cc->retry_delay);
450 cc->task = GNUNET_SCHEDULER_add_delayed (cc->retry_delay,
451 &send_create,
452 cc);
453 break;
454 case CADET_CONNECTION_CREATE_RECEIVED:
455 /* We got the 'CREATE' (incoming connection), should send the CREATE_ACK */
456 cc->task = GNUNET_SCHEDULER_add_now (&send_create_ack,
457 cc);
458 break;
459 case CADET_CONNECTION_READY:
460 cc->ready_cb (cc->ready_cb_cls,
461 GNUNET_YES);
462 break;
463 }
464}
465
466
467/**
468 * Create a connection to @a destination via @a path and notify @a cb
469 * whenever we are ready for more data. Shared logic independent of
470 * who is initiating the connection.
471 *
472 * @param destination where to go
473 * @param path which path to take (may not be the full path)
474 * @param ct which tunnel uses this connection
475 * @param init_state initial state for the connection
476 * @param ready_cb function to call when ready to transmit
477 * @param ready_cb_cls closure for @a cb
478 * @return handle to the connection
479 */
480static struct CadetConnection *
481connection_create (struct CadetPeer *destination,
482 struct CadetPeerPath *path,
483 struct CadetTConnection *ct,
484 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
485 enum CadetConnectionState init_state,
486 GCC_ReadyCallback ready_cb,
487 void *ready_cb_cls)
488{
489 struct CadetConnection *cc;
490 struct CadetPeer *first_hop;
491 unsigned int off;
492
493 off = GCPP_find_peer (path,
494 destination);
495 GNUNET_assert (UINT_MAX > off);
496 cc = GNUNET_new (struct CadetConnection);
497 cc->state = init_state;
498 cc->ct = ct;
499 cc->cid = *cid;
500 GNUNET_assert (GNUNET_OK ==
501 GNUNET_CONTAINER_multishortmap_put (connections,
502 &GCC_get_id (cc)->connection_of_tunnel,
503 cc,
504 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
505 cc->ready_cb = ready_cb;
506 cc->ready_cb_cls = ready_cb_cls;
507 cc->path = path;
508 cc->off = off;
509 LOG (GNUNET_ERROR_TYPE_DEBUG,
510 "Creating %s using path %s\n",
511 GCC_2s (cc),
512 GCPP_2s (path));
513 GCPP_add_connection (path,
514 off,
515 cc);
516 for (unsigned int i=0;i<off;i++)
517 GCP_add_connection (GCPP_get_peer_at_offset (path,
518 off),
519 cc);
520
521 first_hop = GCPP_get_peer_at_offset (path,
522 0);
523 cc->mq_man = GCP_request_mq (first_hop,
524 &manage_first_hop_mq,
525 cc);
526 return cc;
527}
528
529
530/**
531 * Create a connection to @a destination via @a path and
532 * notify @a cb whenever we are ready for more data. This
533 * is an inbound tunnel, so we must use the existing @a cid
534 *
535 * @param destination where to go
536 * @param path which path to take (may not be the full path)
537 * @param ct which tunnel uses this connection
538 * @param ready_cb function to call when ready to transmit
539 * @param ready_cb_cls closure for @a cb
540 * @return handle to the connection
541 */
542struct CadetConnection *
543GCC_create_inbound (struct CadetPeer *destination,
544 struct CadetPeerPath *path,
545 struct CadetTConnection *ct,
546 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
547 GCC_ReadyCallback ready_cb,
548 void *ready_cb_cls)
549{
550 return connection_create (destination,
551 path,
552 ct,
553 cid,
554 CADET_CONNECTION_CREATE_RECEIVED,
555 ready_cb,
556 ready_cb_cls);
557}
558
559
560/**
561 * Create a connection to @a destination via @a path and
562 * notify @a cb whenever we are ready for more data.
563 *
564 * @param destination where to go
565 * @param path which path to take (may not be the full path)
566 * @param ct tunnel that uses the connection
567 * @param ready_cb function to call when ready to transmit
568 * @param ready_cb_cls closure for @a cb
569 * @return handle to the connection
570 */
571struct CadetConnection *
572GCC_create (struct CadetPeer *destination,
573 struct CadetPeerPath *path,
574 struct CadetTConnection *ct,
575 GCC_ReadyCallback ready_cb,
576 void *ready_cb_cls)
577{
578 struct GNUNET_CADET_ConnectionTunnelIdentifier cid;
579
580 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
581 &cid,
582 sizeof (cid));
583 return connection_create (destination,
584 path,
585 ct,
586 &cid,
587 CADET_CONNECTION_NEW,
588 ready_cb,
589 ready_cb_cls);
590}
591
592
593/**
594 * Transmit message @a msg via connection @a cc. Must only be called
595 * (once) after the connection has signalled that it is ready via the
596 * `ready_cb`. Clients can also use #GCC_is_ready() to check if the
597 * connection is right now ready for transmission.
598 *
599 * @param cc connection identification
600 * @param env envelope with message to transmit; must NOT
601 * yet have a #GNUNET_MQ_notify_sent() callback attached to it
602 */
603void
604GCC_transmit (struct CadetConnection *cc,
605 struct GNUNET_MQ_Envelope *env)
606{
607 LOG (GNUNET_ERROR_TYPE_DEBUG,
608 "Scheduling message for transmission on %s\n",
609 GCC_2s (cc));
610 GNUNET_assert (GNUNET_YES == cc->mqm_ready);
611 GNUNET_assert (CADET_CONNECTION_READY == cc->state);
612 cc->mqm_ready = GNUNET_NO;
613 GCP_send (cc->mq_man,
614 env);
615}
616
617
618/**
619 * Obtain the path used by this connection.
620 *
621 * @param cc connection
622 * @return path to @a cc
623 */
624struct CadetPeerPath *
625GCC_get_path (struct CadetConnection *cc)
626{
627 return cc->path;
628}
629
630
631/**
632 * Obtain unique ID for the connection.
633 *
634 * @param cc connection.
635 * @return unique number of the connection
636 */
637const struct GNUNET_CADET_ConnectionTunnelIdentifier *
638GCC_get_id (struct CadetConnection *cc)
639{
640 return &cc->cid;
641}
642
643
644/**
645 * Get a (static) string for a connection.
646 *
647 * @param cc Connection.
648 */
649const char *
650GCC_2s (const struct CadetConnection *cc)
651{
652 static char buf[128];
653
654 if (NULL == cc)
655 return "Connection(NULL)";
656
657 if (NULL != cc->ct)
658 {
659 GNUNET_snprintf (buf,
660 sizeof (buf),
661 "Connection %s (%s)",
662 GNUNET_sh2s (&cc->cid.connection_of_tunnel),
663 GCT_2s (cc->ct->t));
664 return buf;
665 }
666 GNUNET_snprintf (buf,
667 sizeof (buf),
668 "Connection %s",
669 GNUNET_sh2s (&cc->cid.connection_of_tunnel));
670 return buf;
671}
672
673
674#define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-con",__VA_ARGS__)
675
676
677/**
678 * Log connection info.
679 *
680 * @param cc connection
681 * @param level Debug level to use.
682 */
683void
684GCC_debug (struct CadetConnection *cc,
685 enum GNUNET_ErrorType level)
686{
687 int do_log;
688
689 do_log = GNUNET_get_log_call_status (level & (~GNUNET_ERROR_TYPE_BULK),
690 "cadet-con",
691 __FILE__, __FUNCTION__, __LINE__);
692 if (0 == do_log)
693 return;
694 if (NULL == cc)
695 {
696 LOG2 (level,
697 "Connection (NULL)\n");
698 return;
699 }
700 LOG2 (level,
701 "%s to %s via path %s in state %d is %s\n",
702 GCC_2s (cc),
703 GCP_2s (cc->destination),
704 GCPP_2s (cc->path),
705 cc->state,
706 (GNUNET_YES == cc->mqm_ready) ? "ready" : "busy");
707}
708
709/* 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 efdf9929a..000000000
--- a/src/cadet/gnunet-service-cadet-new_connection.h
+++ /dev/null
@@ -1,207 +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
25 * @author Bartlomiej Polot
26 * @author Christian Grothoff
27 */
28#ifndef GNUNET_SERVICE_CADET_CONNECTION_H
29#define GNUNET_SERVICE_CADET_CONNECTION_H
30
31#include "gnunet_util_lib.h"
32#include "gnunet-service-cadet-new.h"
33#include "gnunet-service-cadet-new_peer.h"
34#include "cadet_protocol.h"
35
36
37/**
38 * Function called to notify tunnel about change in our readyness.
39 *
40 * @param cls closure
41 * @param is_ready #GNUNET_YES if the connection is now ready for transmission,
42 * #GNUNET_NO if the connection is no longer ready for transmission
43 */
44typedef void
45(*GCC_ReadyCallback)(void *cls,
46 int is_ready);
47
48
49/**
50 * Destroy a connection.
51 *
52 * @param cc connection to destroy
53 */
54void
55GCC_destroy (struct CadetConnection *cc);
56
57
58/**
59 * Create a connection to @a destination via @a path and
60 * notify @a cb whenever we are ready for more data.
61 *
62 * @param destination where to go
63 * @param path which path to take (may not be the full path)
64 * @param ct which tunnel uses this connection
65 * @param ready_cb function to call when ready to transmit
66 * @param ready_cb_cls closure for @a cb
67 * @return handle to the connection
68 */
69struct CadetConnection *
70GCC_create (struct CadetPeer *destination,
71 struct CadetPeerPath *path,
72 struct CadetTConnection *ct,
73 GCC_ReadyCallback ready_cb,
74 void *ready_cb_cls);
75
76
77/**
78 * Create a connection to @a destination via @a path and
79 * notify @a cb whenever we are ready for more data. This
80 * is an inbound tunnel, so we must use the existing @a cid
81 *
82 * @param destination where to go
83 * @param path which path to take (may not be the full path)
84 * @param ct which tunnel uses this connection
85 * @param ready_cb function to call when ready to transmit
86 * @param ready_cb_cls closure for @a cb
87 * @return handle to the connection
88 */
89struct CadetConnection *
90GCC_create_inbound (struct CadetPeer *destination,
91 struct CadetPeerPath *path,
92 struct CadetTConnection *ct,
93 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
94 GCC_ReadyCallback ready_cb,
95 void *ready_cb_cls);
96
97
98/**
99 * Transmit message @a msg via connection @a cc. Must only be called
100 * (once) after the connection has signalled that it is ready via the
101 * `ready_cb`. Clients can also use #GCC_is_ready() to check if the
102 * connection is right now ready for transmission.
103 *
104 * @param cc connection identification
105 * @param env envelope with message to transmit;
106 * the #GNUNET_MQ_notify_send() must not have yet been used
107 * for the envelope. Also, the message better match the
108 * connection identifier of this connection...
109 */
110void
111GCC_transmit (struct CadetConnection *cc,
112 struct GNUNET_MQ_Envelope *env);
113
114
115/**
116 * A CREATE_ACK was received for this connection, process it.
117 *
118 * @param cc the connection that got the ACK.
119 */
120void
121GCC_handle_connection_create_ack (struct CadetConnection *cc);
122
123
124/**
125 * We got a #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE for a
126 * connection that we already have. Either our ACK got lost
127 * or something is fishy. Consider retransmitting the ACK.
128 *
129 * @param cc connection that got the duplicate CREATE
130 */
131void
132GCC_handle_duplicate_create (struct CadetConnection *cc);
133
134
135/**
136 * Handle KX message.
137 *
138 * @param cc connection that received encrypted message
139 * @param msg the key exchange message
140 */
141void
142GCC_handle_kx (struct CadetConnection *cc,
143 const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg);
144
145
146/**
147 * Handle encrypted message.
148 *
149 * @param cc connection that received encrypted message
150 * @param msg the encrypted message to decrypt
151 */
152void
153GCC_handle_encrypted (struct CadetConnection *cc,
154 const struct GNUNET_CADET_TunnelEncryptedMessage *msg);
155
156
157/**
158 * Return the tunnel associated with this connection.
159 *
160 * @param cc connection to query
161 * @return corresponding entry in the tunnel's connection list
162 */
163struct CadetTConnection *
164GCC_get_ct (struct CadetConnection *cc);
165
166
167/**
168 * Obtain the path used by this connection.
169 *
170 * @param cc connection
171 * @return path to @a cc
172 */
173struct CadetPeerPath *
174GCC_get_path (struct CadetConnection *cc);
175
176
177/**
178 * Obtain unique ID for the connection.
179 *
180 * @param cc connection.
181 * @return unique number of the connection
182 */
183const struct GNUNET_CADET_ConnectionTunnelIdentifier *
184GCC_get_id (struct CadetConnection *cc);
185
186
187/**
188 * Get a (static) string for a connection.
189 *
190 * @param cc Connection.
191 */
192const char *
193GCC_2s (const struct CadetConnection *cc);
194
195
196/**
197 * Log connection info.
198 *
199 * @param cc connection
200 * @param level Debug level to use.
201 */
202void
203GCC_debug (struct CadetConnection *cc,
204 enum GNUNET_ErrorType level);
205
206
207#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 fe40d76b6..000000000
--- a/src/cadet/gnunet-service-cadet-new_peer.c
+++ /dev/null
@@ -1,1282 +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 * - optimize MQM ready scans (O(n) -> O(1))
33 */
34#include "platform.h"
35#include "gnunet_util_lib.h"
36#include "gnunet_hello_lib.h"
37#include "gnunet_signatures.h"
38#include "gnunet_transport_service.h"
39#include "gnunet_ats_service.h"
40#include "gnunet_core_service.h"
41#include "gnunet_statistics_service.h"
42#include "cadet_protocol.h"
43#include "gnunet-service-cadet-new.h"
44#include "gnunet-service-cadet-new_connection.h"
45#include "gnunet-service-cadet-new_dht.h"
46#include "gnunet-service-cadet-new_peer.h"
47#include "gnunet-service-cadet-new_paths.h"
48#include "gnunet-service-cadet-new_tunnels.h"
49
50
51#define LOG(level, ...) GNUNET_log_from(level,"cadet-per",__VA_ARGS__)
52
53
54/**
55 * How long do we wait until tearing down an idle peer?
56 */
57#define IDLE_PEER_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5)
58
59/**
60 * How long do we keep paths around if we no longer care about the peer?
61 */
62#define IDLE_PATH_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 2)
63
64
65
66
67/**
68 * Data structure used to track whom we have to notify about changes
69 * to our message queue.
70 */
71struct GCP_MessageQueueManager
72{
73
74 /**
75 * Kept in a DLL.
76 */
77 struct GCP_MessageQueueManager *next;
78
79 /**
80 * Kept in a DLL.
81 */
82 struct GCP_MessageQueueManager *prev;
83
84 /**
85 * Function to call with updated message queue object.
86 */
87 GCP_MessageQueueNotificationCallback cb;
88
89 /**
90 * Closure for @e cb.
91 */
92 void *cb_cls;
93
94 /**
95 * The peer this is for.
96 */
97 struct CadetPeer *cp;
98
99 /**
100 * Envelope this manager would like to transmit once it is its turn.
101 */
102 struct GNUNET_MQ_Envelope *env;
103
104};
105
106
107/**
108 * Struct containing all information regarding a given peer
109 */
110struct CadetPeer
111{
112 /**
113 * ID of the peer
114 */
115 struct GNUNET_PeerIdentity pid;
116
117 /**
118 * Last time we heard from this peer
119 */
120 struct GNUNET_TIME_Absolute last_contact;
121
122 /**
123 * Array of DLLs of paths traversing the peer, organized by the
124 * offset of the peer on the larger path.
125 */
126 struct CadetPeerPathEntry **path_heads;
127
128 /**
129 * Array of DLL of paths traversing the peer, organized by the
130 * offset of the peer on the larger path.
131 */
132 struct CadetPeerPathEntry **path_tails;
133
134 /**
135 * Notifications to call when @e core_mq changes.
136 */
137 struct GCP_MessageQueueManager *mqm_head;
138
139 /**
140 * Notifications to call when @e core_mq changes.
141 */
142 struct GCP_MessageQueueManager *mqm_tail;
143
144 /**
145 * MIN-heap of paths owned by this peer (they also end at this
146 * peer). Ordered by desirability.
147 */
148 struct GNUNET_CONTAINER_Heap *path_heap;
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 * Task to stop the DHT search for paths to this peer
157 */
158 struct GNUNET_SCHEDULER_Task *search_delayedXXX;
159
160 /**
161 * Task to destroy this entry.
162 */
163 struct GNUNET_SCHEDULER_Task *destroy_task;
164
165 /**
166 * Tunnel to this peer, if any.
167 */
168 struct CadetTunnel *t;
169
170 /**
171 * Connections that go through this peer; indexed by tid.
172 */
173 struct GNUNET_CONTAINER_MultiShortmap *connections;
174
175 /**
176 * Handle for core transmissions.
177 */
178 struct GNUNET_MQ_Handle *core_mq;
179
180 /**
181 * Hello message of the peer.
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
196 /**
197 * How many messages are in the queue to this peer.
198 */
199 unsigned int queue_n;
200
201 /**
202 * How many paths do we have to this peer (in all @e path_heads DLLs combined).
203 */
204 unsigned int num_paths;
205
206 /**
207 * Number of message queue managers of this peer that have a message in waiting.
208 *
209 * Used to quickly see if we need to bother scanning the @e msm_head DLL.
210 * TODO: could be replaced by another DLL that would then allow us to avoid
211 * the O(n)-scan of the DLL for ready entries!
212 */
213 unsigned int mqm_ready_counter;
214
215 /**
216 * Current length of the @e path_heads and @path_tails arrays.
217 * The arrays should be grown as needed.
218 */
219 unsigned int path_dll_length;
220
221};
222
223
224/**
225 * Get the static string for a peer ID.
226 *
227 * @param cp Peer.
228 * @return Static string for it's ID.
229 */
230const char *
231GCP_2s (const struct CadetPeer *cp)
232{
233 static char buf[32];
234
235 GNUNET_snprintf (buf,
236 sizeof (buf),
237 "P(%s)",
238 GNUNET_i2s (&cp->pid));
239 return buf;
240}
241
242
243/**
244 * This peer is no longer be needed, clean it up now.
245 *
246 * @param cls peer to clean up
247 */
248static void
249destroy_peer (void *cls)
250{
251 struct CadetPeer *cp = cls;
252
253 LOG (GNUNET_ERROR_TYPE_DEBUG,
254 "Destroying state about peer %s\n",
255 GCP_2s (cp));
256 cp->destroy_task = NULL;
257 GNUNET_assert (NULL == cp->t);
258 GNUNET_assert (NULL == cp->core_mq);
259 for (unsigned int i=0;i<cp->path_dll_length;i++)
260 GNUNET_assert (NULL == cp->path_heads[i]);
261 GNUNET_assert (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections));
262 GNUNET_assert (GNUNET_YES ==
263 GNUNET_CONTAINER_multipeermap_remove (peers,
264 &cp->pid,
265 cp));
266 GNUNET_free_non_null (cp->path_heads);
267 GNUNET_free_non_null (cp->path_tails);
268 cp->path_dll_length = 0;
269 if (NULL != cp->search_h)
270 {
271 GCD_search_stop (cp->search_h);
272 cp->search_h = NULL;
273 }
274 /* FIXME: clean up search_delayedXXX! */
275
276 if (NULL != cp->hello_offer)
277 {
278 GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer);
279 cp->hello_offer = NULL;
280 }
281 if (NULL != cp->connectivity_suggestion)
282 {
283 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
284 cp->connectivity_suggestion = NULL;
285 }
286 GNUNET_CONTAINER_multishortmap_destroy (cp->connections);
287 if (NULL != cp->path_heap)
288 {
289 GNUNET_CONTAINER_heap_destroy (cp->path_heap);
290 cp->path_heap = NULL;
291 }
292 GNUNET_free_non_null (cp->hello);
293 /* Peer should not be freed if paths exist; if there are no paths,
294 there ought to be no connections, and without connections, no
295 notifications. Thus we can assert that mqm_head is empty at this
296 point. */
297 GNUNET_assert (NULL == cp->mqm_head);
298 GNUNET_free (cp);
299}
300
301
302/**
303 * This peer is now on more "active" duty, activate processes related to it.
304 *
305 * @param cp the more-active peer
306 */
307static void
308consider_peer_activate (struct CadetPeer *cp)
309{
310 uint32_t strength;
311
312 LOG (GNUNET_ERROR_TYPE_DEBUG,
313 "Updating peer %s activation state (%u connections)%s%s\n",
314 GCP_2s (cp),
315 GNUNET_CONTAINER_multishortmap_size (cp->connections),
316 (NULL == cp->t) ? "" : " with tunnel",
317 (NULL == cp->core_mq) ? "" : " with CORE link");
318 if (NULL != cp->destroy_task)
319 {
320 /* It's active, do not destory! */
321 GNUNET_SCHEDULER_cancel (cp->destroy_task);
322 cp->destroy_task = NULL;
323 }
324 if ( (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections)) &&
325 (NULL == cp->t) )
326 {
327 /* We're just on a path or directly connected; don't bother too much */
328 if (NULL != cp->connectivity_suggestion)
329 {
330 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
331 cp->connectivity_suggestion = NULL;
332 }
333 if (NULL != cp->search_h)
334 {
335 GCD_search_stop (cp->search_h);
336 cp->search_h = NULL;
337 }
338 return;
339 }
340 if (NULL == cp->core_mq)
341 {
342 /* Lacks direct connection, try to create one by querying the DHT */
343 if ( (NULL == cp->search_h) &&
344 (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) )
345 cp->search_h
346 = GCD_search (&cp->pid);
347 }
348 else
349 {
350 /* Have direct connection, stop DHT search if active */
351 if (NULL != cp->search_h)
352 {
353 GCD_search_stop (cp->search_h);
354 cp->search_h = NULL;
355 }
356 }
357
358 /* If we have a tunnel, our urge for connections is much bigger */
359 strength = (NULL != cp->t) ? 32 : 1;
360 if (NULL != cp->connectivity_suggestion)
361 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
362 cp->connectivity_suggestion
363 = GNUNET_ATS_connectivity_suggest (ats_ch,
364 &cp->pid,
365 strength);
366}
367
368
369/**
370 * This peer may no longer be needed, consider cleaning it up.
371 *
372 * @param cp peer to clean up
373 */
374static void
375consider_peer_destroy (struct CadetPeer *cp);
376
377
378/**
379 * We really no longere care about a peer, stop hogging memory with paths to it.
380 * Afterwards, see if there is more to be cleaned up about this peer.
381 *
382 * @param cls a `struct CadetPeer`.
383 */
384static void
385drop_paths (void *cls)
386{
387 struct CadetPeer *cp = cls;
388 struct CadetPeerPath *path;
389
390 cp->destroy_task = NULL;
391 while (NULL != (path = GNUNET_CONTAINER_heap_remove_root (cp->path_heap)))
392 GCPP_release (path);
393 consider_peer_destroy (cp);
394}
395
396
397/**
398 * This peer may no longer be needed, consider cleaning it up.
399 *
400 * @param cp peer to clean up
401 */
402static void
403consider_peer_destroy (struct CadetPeer *cp)
404{
405 struct GNUNET_TIME_Relative exp;
406
407 if (NULL != cp->destroy_task)
408 {
409 GNUNET_SCHEDULER_cancel (cp->destroy_task);
410 cp->destroy_task = NULL;
411 }
412 if (NULL != cp->t)
413 return; /* still relevant! */
414 if (NULL != cp->core_mq)
415 return; /* still relevant! */
416 if (0 != GNUNET_CONTAINER_multishortmap_size (cp->connections))
417 return; /* still relevant! */
418 if (0 < GNUNET_CONTAINER_heap_get_size (cp->path_heap))
419 {
420 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PATH_TIMEOUT,
421 &drop_paths,
422 cp);
423 return;
424 }
425 for (unsigned int i=0;i<cp->path_dll_length;i++)
426 if (NULL != cp->path_heads[i])
427 return; /* still relevant! */
428 if (NULL != cp->hello)
429 {
430 /* relevant only until HELLO expires */
431 exp = GNUNET_TIME_absolute_get_remaining (GNUNET_HELLO_get_last_expiration (cp->hello));
432 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (exp,
433 &destroy_peer,
434 cp);
435 return;
436 }
437 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PEER_TIMEOUT,
438 &destroy_peer,
439 cp);
440}
441
442
443/**
444 * Set the message queue to @a mq for peer @a cp and notify watchers.
445 *
446 * @param cp peer to modify
447 * @param mq message queue to set (can be NULL)
448 */
449void
450GCP_set_mq (struct CadetPeer *cp,
451 struct GNUNET_MQ_Handle *mq)
452{
453 LOG (GNUNET_ERROR_TYPE_DEBUG,
454 "Message queue for peer %s is now %p\n",
455 GCP_2s (cp),
456 mq);
457 cp->core_mq = mq;
458 for (struct GCP_MessageQueueManager *mqm = cp->mqm_head;
459 NULL != mqm;
460 mqm = mqm->next)
461 {
462 if (NULL == mq)
463 {
464 if (NULL != mqm->env)
465 {
466 GNUNET_MQ_discard (mqm->env);
467 mqm->env = NULL;
468 mqm->cb (mqm->cb_cls,
469 GNUNET_SYSERR);
470 }
471 else
472 {
473 mqm->cb (mqm->cb_cls,
474 GNUNET_NO);
475 }
476 }
477 else
478 {
479 GNUNET_assert (NULL == mqm->env);
480 mqm->cb (mqm->cb_cls,
481 GNUNET_YES);
482 }
483 }
484 if ( (NULL != mq) ||
485 (NULL != cp->t) )
486 consider_peer_activate (cp);
487 else
488 consider_peer_destroy (cp);
489
490 if ( (NULL != mq) &&
491 (NULL != cp->t) )
492 {
493 /* have a new, direct path to the target, notify tunnel */
494 struct CadetPeerPath *path;
495
496 path = GCPP_get_path_from_route (1,
497 &cp->pid);
498 GCT_consider_path (cp->t,
499 path,
500 0);
501 }
502}
503
504
505/**
506 * Transmit current envelope from this @a mqm.
507 *
508 * @param mqm mqm to transmit message for now
509 */
510static void
511mqm_execute (struct GCP_MessageQueueManager *mqm)
512{
513 struct CadetPeer *cp = mqm->cp;
514
515 LOG (GNUNET_ERROR_TYPE_DEBUG,
516 "Sending to peer %s from MQM %p\n",
517 GCP_2s (cp),
518 mqm);
519 /* Move entry to the end of the DLL, to be fair. */
520 if (mqm != cp->mqm_tail)
521 {
522 GNUNET_CONTAINER_DLL_remove (cp->mqm_head,
523 cp->mqm_tail,
524 mqm);
525 GNUNET_CONTAINER_DLL_insert_tail (cp->mqm_head,
526 cp->mqm_tail,
527 mqm);
528 }
529 GNUNET_MQ_send (cp->core_mq,
530 mqm->env);
531 mqm->env = NULL;
532 cp->mqm_ready_counter--;
533 mqm->cb (mqm->cb_cls,
534 GNUNET_YES);
535}
536
537
538/**
539 * Function called when CORE took one of the messages from
540 * a message queue manager and transmitted it.
541 *
542 * @param cls the `struct CadetPeeer` where we made progress
543 */
544static void
545mqm_send_done (void *cls)
546{
547 struct CadetPeer *cp = cls;
548
549 LOG (GNUNET_ERROR_TYPE_DEBUG,
550 "Sending to peer %s completed\n",
551 GCP_2s (cp));
552 if (0 == cp->mqm_ready_counter)
553 return; /* nothing to do */
554 for (struct GCP_MessageQueueManager *mqm = cp->mqm_head;
555 NULL != mqm;
556 mqm = mqm->next)
557 {
558 if (NULL == mqm->env)
559 continue;
560 mqm_execute (mqm);
561 return;
562 }
563}
564
565
566/**
567 * Send the message in @a env to @a cp.
568 *
569 * @param mqm the message queue manager to use for transmission
570 * @param env envelope with the message to send; must NOT
571 * yet have a #GNUNET_MQ_notify_sent() callback attached to it
572 */
573void
574GCP_send (struct GCP_MessageQueueManager *mqm,
575 struct GNUNET_MQ_Envelope *env)
576{
577 struct CadetPeer *cp = mqm->cp;
578
579 LOG (GNUNET_ERROR_TYPE_DEBUG,
580 "Queueing message to peer %s in MQM %p\n",
581 GCP_2s (cp),
582 mqm);
583 GNUNET_assert (NULL != cp->core_mq);
584 GNUNET_assert (NULL == mqm->env);
585 GNUNET_MQ_notify_sent (env,
586 &mqm_send_done,
587 cp);
588 mqm->env = env;
589 cp->mqm_ready_counter++;
590 if (0 != GNUNET_MQ_get_length (cp->core_mq))
591 return;
592 mqm_execute (mqm);
593}
594
595
596/**
597 * Function called to destroy a peer now.
598 *
599 * @param cls NULL
600 * @param pid identity of the peer (unused)
601 * @param value the `struct CadetPeer` to clean up
602 * @return #GNUNET_OK (continue to iterate)
603 */
604static int
605destroy_iterator_cb (void *cls,
606 const struct GNUNET_PeerIdentity *pid,
607 void *value)
608{
609 struct CadetPeer *cp = value;
610
611 if (NULL != cp->destroy_task)
612 {
613 GNUNET_SCHEDULER_cancel (cp->destroy_task);
614 cp->destroy_task = NULL;
615 }
616 destroy_peer (cp);
617 return GNUNET_OK;
618}
619
620
621/**
622 * Clean up all entries about all peers.
623 * Must only be called after all tunnels, CORE-connections and
624 * connections are down.
625 */
626void
627GCP_destroy_all_peers ()
628{
629 LOG (GNUNET_ERROR_TYPE_DEBUG,
630 "Destroying all peers now\n");
631 GNUNET_CONTAINER_multipeermap_iterate (peers,
632 &destroy_iterator_cb,
633 NULL);
634}
635
636
637/**
638 * Drop all paths owned by this peer, and do not
639 * allow new ones to be added: We are shutting down.
640 *
641 * @param cp peer to drop paths to
642 */
643void
644GCP_drop_owned_paths (struct CadetPeer *cp)
645{
646 struct CadetPeerPath *path;
647
648 LOG (GNUNET_ERROR_TYPE_DEBUG,
649 "Destroying all paths to %s\n",
650 GCP_2s (cp));
651 while (NULL != (path =
652 GNUNET_CONTAINER_heap_remove_root (cp->path_heap)))
653 GCPP_release (path);
654 GNUNET_CONTAINER_heap_destroy (cp->path_heap);
655 cp->path_heap = NULL;
656}
657
658
659/**
660 * Add an entry to the DLL of all of the paths that this peer is on.
661 *
662 * @param cp peer to modify
663 * @param entry an entry on a path
664 * @param off offset of this peer on the path
665 */
666void
667GCP_path_entry_add (struct CadetPeer *cp,
668 struct CadetPeerPathEntry *entry,
669 unsigned int off)
670{
671 GNUNET_assert (cp == GCPP_get_peer_at_offset (entry->path,
672 off));
673 LOG (GNUNET_ERROR_TYPE_DEBUG,
674 "Discovered that peer %s is on path %s at offset %u\n",
675 GCP_2s (cp),
676 GCPP_2s (entry->path),
677 off);
678 if (off >= cp->path_dll_length)
679 {
680 unsigned int len = cp->path_dll_length;
681
682 GNUNET_array_grow (cp->path_heads,
683 len,
684 off + 4);
685 GNUNET_array_grow (cp->path_tails,
686 cp->path_dll_length,
687 off + 4);
688 }
689 GNUNET_CONTAINER_DLL_insert (cp->path_heads[off],
690 cp->path_tails[off],
691 entry);
692 cp->num_paths++;
693
694 /* If we have a tunnel to this peer, tell the tunnel that there is a
695 new path available. */
696 if (NULL != cp->t)
697 GCT_consider_path (cp->t,
698 entry->path,
699 off);
700
701 if ( (NULL != cp->search_h) &&
702 (DESIRED_CONNECTIONS_PER_TUNNEL <= cp->num_paths) )
703 {
704 /* Now I have enough paths, stop search */
705 GCD_search_stop (cp->search_h);
706 cp->search_h = NULL;
707 }
708}
709
710
711/**
712 * Remove an entry from the DLL of all of the paths that this peer is on.
713 *
714 * @param cp peer to modify
715 * @param entry an entry on a path
716 * @param off offset of this peer on the path
717 */
718void
719GCP_path_entry_remove (struct CadetPeer *cp,
720 struct CadetPeerPathEntry *entry,
721 unsigned int off)
722{
723 LOG (GNUNET_ERROR_TYPE_DEBUG,
724 "Removing knowledge about peer %s beging on path %s at offset %u\n",
725 GCP_2s (cp),
726 GCPP_2s (entry->path),
727 off);
728 GNUNET_CONTAINER_DLL_remove (cp->path_heads[off],
729 cp->path_tails[off],
730 entry);
731 GNUNET_assert (0 < cp->num_paths);
732 cp->num_paths--;
733 if ( (NULL == cp->core_mq) &&
734 (NULL != cp->t) &&
735 (NULL == cp->search_h) &&
736 (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) )
737 cp->search_h
738 = GCD_search (&cp->pid);
739}
740
741
742/**
743 * Try adding a @a path to this @a peer. If the peer already
744 * has plenty of paths, return NULL.
745 *
746 * @param cp peer to which the @a path leads to
747 * @param path a path looking for an owner; may not be fully initialized yet!
748 * @param off offset of @a cp in @a path
749 * @param force force attaching the path
750 * @return NULL if this peer does not care to become a new owner,
751 * otherwise the node in the peer's path heap for the @a path.
752 */
753struct GNUNET_CONTAINER_HeapNode *
754GCP_attach_path (struct CadetPeer *cp,
755 struct CadetPeerPath *path,
756 unsigned int off,
757 int force)
758{
759 GNUNET_CONTAINER_HeapCostType desirability;
760 struct CadetPeerPath *root;
761 GNUNET_CONTAINER_HeapCostType root_desirability;
762 struct GNUNET_CONTAINER_HeapNode *hn;
763
764 GNUNET_assert (cp == GCPP_get_peer_at_offset (path,
765 off));
766 if (NULL == cp->path_heap)
767 {
768 /* #GCP_drop_owned_paths() was already called, we cannot take new ones! */
769 GNUNET_assert (GNUNET_NO == force);
770 return NULL;
771 }
772 desirability = GCPP_get_desirability (path);
773 if (GNUNET_NO == force)
774 {
775 /* FIXME: desirability is not yet initialized; tricky! */
776 if (GNUNET_NO ==
777 GNUNET_CONTAINER_heap_peek2 (cp->path_heap,
778 (void **) &root,
779 &root_desirability))
780 {
781 root = NULL;
782 root_desirability = 0;
783 }
784
785 if ( (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) &&
786 (desirability < root_desirability) )
787 {
788 LOG (GNUNET_ERROR_TYPE_DEBUG,
789 "Decided to not attach path %p to peer %s due to undesirability\n",
790 GCPP_2s (path),
791 GCP_2s (cp));
792 return NULL;
793 }
794 }
795
796 LOG (GNUNET_ERROR_TYPE_DEBUG,
797 "Attaching path %s to peer %s (%s)\n",
798 GCPP_2s (path),
799 GCP_2s (cp),
800 (GNUNET_NO == force) ? "desirable" : "forced");
801
802 /* Yes, we'd like to add this path, add to our heap */
803 hn = GNUNET_CONTAINER_heap_insert (cp->path_heap,
804 path,
805 desirability);
806
807 /* Consider maybe dropping other paths because of the new one */
808 if (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >=
809 2 * DESIRED_CONNECTIONS_PER_TUNNEL)
810 {
811 /* Now we have way too many, drop least desirable UNLESS it is in use!
812 (Note that this intentionally keeps highly desireable, but currently
813 unused paths around in the hope that we might be able to switch, even
814 if the number of paths exceeds the threshold.) */
815 root = GNUNET_CONTAINER_heap_peek (cp->path_heap);
816 if ( (path != root) &&
817 (NULL ==
818 GCPP_get_connection (root,
819 cp,
820 GCPP_get_length (root) - 1)) )
821 {
822 /* Got plenty of paths to this destination, and this is a low-quality
823 one that we don't care, allow it to die. */
824 GNUNET_assert (root ==
825 GNUNET_CONTAINER_heap_remove_root (cp->path_heap));
826 GCPP_release (root);
827 }
828 }
829 return hn;
830}
831
832
833/**
834 * This peer can no longer own @a path as the path
835 * has been extended and a peer further down the line
836 * is now the new owner.
837 *
838 * @param cp old owner of the @a path
839 * @param path path where the ownership is lost
840 * @param hn note in @a cp's path heap that must be deleted
841 */
842void
843GCP_detach_path (struct CadetPeer *cp,
844 struct CadetPeerPath *path,
845 struct GNUNET_CONTAINER_HeapNode *hn)
846{
847 LOG (GNUNET_ERROR_TYPE_DEBUG,
848 "Detatching path %s from peer %s\n",
849 GCPP_2s (path),
850 GCP_2s (cp));
851 GNUNET_assert (path ==
852 GNUNET_CONTAINER_heap_remove_node (hn));
853}
854
855
856/**
857 * Add a @a connection to this @a cp.
858 *
859 * @param cp peer via which the @a connection goes
860 * @param cc the connection to add
861 */
862void
863GCP_add_connection (struct CadetPeer *cp,
864 struct CadetConnection *cc)
865{
866 LOG (GNUNET_ERROR_TYPE_DEBUG,
867 "Adding connection %s to peer %s\n",
868 GCC_2s (cc),
869 GCP_2s (cp));
870 GNUNET_assert (GNUNET_OK ==
871 GNUNET_CONTAINER_multishortmap_put (cp->connections,
872 &GCC_get_id (cc)->connection_of_tunnel,
873 cc,
874 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
875}
876
877
878/**
879 * Remove a @a connection that went via this @a cp.
880 *
881 * @param cp peer via which the @a connection went
882 * @param cc the connection to remove
883 */
884void
885GCP_remove_connection (struct CadetPeer *cp,
886 struct CadetConnection *cc)
887{
888 LOG (GNUNET_ERROR_TYPE_DEBUG,
889 "Removing connection %s from peer %s\n",
890 GCC_2s (cc),
891 GCP_2s (cp));
892 GNUNET_assert (GNUNET_YES ==
893 GNUNET_CONTAINER_multishortmap_remove (cp->connections,
894 &GCC_get_id (cc)->connection_of_tunnel,
895 cc));
896}
897
898
899/**
900 * Retrieve the CadetPeer stucture associated with the
901 * peer. Optionally create one and insert it in the appropriate
902 * structures if the peer is not known yet.
903 *
904 * @param peer_id Full identity of the peer.
905 * @param create #GNUNET_YES if a new peer should be created if unknown.
906 * #GNUNET_NO to return NULL if peer is unknown.
907 * @return Existing or newly created peer structure.
908 * NULL if unknown and not requested @a create
909 */
910struct CadetPeer *
911GCP_get (const struct GNUNET_PeerIdentity *peer_id,
912 int create)
913{
914 struct CadetPeer *cp;
915
916 cp = GNUNET_CONTAINER_multipeermap_get (peers,
917 peer_id);
918 if (NULL != cp)
919 return cp;
920 if (GNUNET_NO == create)
921 return NULL;
922 cp = GNUNET_new (struct CadetPeer);
923 cp->pid = *peer_id;
924 cp->connections = GNUNET_CONTAINER_multishortmap_create (32,
925 GNUNET_YES);
926 cp->path_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
927 GNUNET_assert (GNUNET_YES ==
928 GNUNET_CONTAINER_multipeermap_put (peers,
929 &cp->pid,
930 cp,
931 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
932 LOG (GNUNET_ERROR_TYPE_DEBUG,
933 "Creating peer %s\n",
934 GCP_2s (cp));
935 return cp;
936}
937
938
939/**
940 * Obtain the peer identity for a `struct CadetPeer`.
941 *
942 * @param cp our peer handle
943 * @return the peer identity
944 */
945const struct GNUNET_PeerIdentity *
946GCP_get_id (struct CadetPeer *cp)
947{
948 return &cp->pid;
949}
950
951
952/**
953 * Iterate over all known peers.
954 *
955 * @param iter Iterator.
956 * @param cls Closure for @c iter.
957 */
958void
959GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter,
960 void *cls)
961{
962 GNUNET_CONTAINER_multipeermap_iterate (peers,
963 iter,
964 cls);
965}
966
967
968/**
969 * Count the number of known paths toward the peer.
970 *
971 * @param cp Peer to get path info.
972 * @return Number of known paths.
973 */
974unsigned int
975GCP_count_paths (const struct CadetPeer *cp)
976{
977 return cp->num_paths;
978}
979
980
981/**
982 * Iterate over the paths to a peer.
983 *
984 * @param cp Peer to get path info.
985 * @param callback Function to call for every path.
986 * @param callback_cls Closure for @a callback.
987 * @return Number of iterated paths.
988 */
989unsigned int
990GCP_iterate_paths (struct CadetPeer *cp,
991 GCP_PathIterator callback,
992 void *callback_cls)
993{
994 unsigned int ret = 0;
995
996 LOG (GNUNET_ERROR_TYPE_DEBUG,
997 "Iterating over paths to peer %s%s\n",
998 GCP_2s (cp),
999 (NULL == cp->core_mq) ? "" : " including direct link");
1000 if (NULL != cp->core_mq)
1001 {
1002 struct CadetPeerPath *path;
1003
1004 path = GCPP_get_path_from_route (1,
1005 &cp->pid);
1006 ret++;
1007 if (GNUNET_NO ==
1008 callback (callback_cls,
1009 path,
1010 1))
1011 return ret;
1012 }
1013 for (unsigned int i=0;i<cp->path_dll_length;i++)
1014 {
1015 for (struct CadetPeerPathEntry *pe = cp->path_heads[i];
1016 NULL != pe;
1017 pe = pe->next)
1018 {
1019 ret++;
1020 if (GNUNET_NO ==
1021 callback (callback_cls,
1022 pe->path,
1023 i))
1024 return ret;
1025 }
1026 }
1027 return ret;
1028}
1029
1030
1031/**
1032 * Iterate over the paths to @a cp where
1033 * @a cp is at distance @a dist from us.
1034 *
1035 * @param cp Peer to get path info.
1036 * @param dist desired distance of @a cp to us on the path
1037 * @param callback Function to call for every path.
1038 * @param callback_cls Closure for @a callback.
1039 * @return Number of iterated paths.
1040 */
1041unsigned int
1042GCP_iterate_paths_at (struct CadetPeer *cp,
1043 unsigned int dist,
1044 GCP_PathIterator callback,
1045 void *callback_cls)
1046{
1047 unsigned int ret = 0;
1048
1049 if (dist >= cp->path_dll_length)
1050 {
1051 LOG (GNUNET_ERROR_TYPE_DEBUG,
1052 "Asked to look for paths at distance %u, but maximum for me is < %u\n",
1053 dist,
1054 cp->path_dll_length);
1055 return 0;
1056 }
1057 for (struct CadetPeerPathEntry *pe = cp->path_heads[dist];
1058 NULL != pe;
1059 pe = pe->next)
1060 {
1061 if (GNUNET_NO ==
1062 callback (callback_cls,
1063 pe->path,
1064 dist))
1065 return ret;
1066 ret++;
1067 }
1068 return ret;
1069}
1070
1071
1072/**
1073 * Get the tunnel towards a peer.
1074 *
1075 * @param cp Peer to get from.
1076 * @param create #GNUNET_YES to create a tunnel if we do not have one
1077 * @return Tunnel towards peer.
1078 */
1079struct CadetTunnel *
1080GCP_get_tunnel (struct CadetPeer *cp,
1081 int create)
1082{
1083 if (NULL == cp)
1084 return NULL;
1085 if ( (NULL != cp->t) ||
1086 (GNUNET_NO == create) )
1087 return cp->t;
1088 cp->t = GCT_create_tunnel (cp);
1089 consider_peer_activate (cp);
1090 return cp->t;
1091}
1092
1093
1094/**
1095 * Hello offer was passed to the transport service. Mark it
1096 * as done.
1097 *
1098 * @param cls the `struct CadetPeer` where the offer completed
1099 */
1100static void
1101hello_offer_done (void *cls)
1102{
1103 struct CadetPeer *cp = cls;
1104
1105 cp->hello_offer = NULL;
1106}
1107
1108
1109/**
1110 * We got a HELLO for a @a peer, remember it, and possibly
1111 * trigger adequate actions (like trying to connect).
1112 *
1113 * @param cp the peer we got a HELLO for
1114 * @param hello the HELLO to remember
1115 */
1116void
1117GCP_set_hello (struct CadetPeer *cp,
1118 const struct GNUNET_HELLO_Message *hello)
1119{
1120 struct GNUNET_HELLO_Message *mrg;
1121
1122 LOG (GNUNET_ERROR_TYPE_DEBUG,
1123 "Got %u byte HELLO for peer %s\n",
1124 (unsigned int) GNUNET_HELLO_size (hello),
1125 GCP_2s (cp));
1126 if (NULL != cp->hello_offer)
1127 {
1128 GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer);
1129 cp->hello_offer = NULL;
1130 }
1131 if (NULL != cp->hello)
1132 {
1133 mrg = GNUNET_HELLO_merge (hello,
1134 cp->hello);
1135 GNUNET_free (cp->hello);
1136 cp->hello = mrg;
1137 }
1138 else
1139 {
1140 cp->hello = GNUNET_memdup (hello,
1141 GNUNET_HELLO_size (hello));
1142 }
1143 cp->hello_offer
1144 = GNUNET_TRANSPORT_offer_hello (cfg,
1145 GNUNET_HELLO_get_header (cp->hello) ,
1146 &hello_offer_done,
1147 cp);
1148 /* New HELLO means cp's destruction time may change... */
1149 consider_peer_destroy (cp);
1150}
1151
1152
1153/**
1154 * The tunnel to the given peer no longer exists, remove it from our
1155 * data structures, and possibly clean up the peer itself.
1156 *
1157 * @param cp the peer affected
1158 * @param t the dead tunnel
1159 */
1160void
1161GCP_drop_tunnel (struct CadetPeer *cp,
1162 struct CadetTunnel *t)
1163{
1164 LOG (GNUNET_ERROR_TYPE_DEBUG,
1165 "Dropping tunnel %s to peer %s\n",
1166 GCT_2s (t),
1167 GCP_2s (cp));
1168 GNUNET_assert (cp->t == t);
1169 cp->t = NULL;
1170 consider_peer_destroy (cp);
1171}
1172
1173
1174/**
1175 * Test if @a cp has a core-level connection
1176 *
1177 * @param cp peer to test
1178 * @return #GNUNET_YES if @a cp has a core-level connection
1179 */
1180int
1181GCP_has_core_connection (struct CadetPeer *cp)
1182{
1183 return (NULL != cp->core_mq) ? GNUNET_YES : GNUNET_NO;
1184}
1185
1186
1187/**
1188 * Start message queue change notifications.
1189 *
1190 * @param cp peer to notify for
1191 * @param cb function to call if mq becomes available or unavailable
1192 * @param cb_cls closure for @a cb
1193 * @return handle to cancel request
1194 */
1195struct GCP_MessageQueueManager *
1196GCP_request_mq (struct CadetPeer *cp,
1197 GCP_MessageQueueNotificationCallback cb,
1198 void *cb_cls)
1199{
1200 struct GCP_MessageQueueManager *mqm;
1201
1202 mqm = GNUNET_new (struct GCP_MessageQueueManager);
1203 mqm->cb = cb;
1204 mqm->cb_cls = cb_cls;
1205 mqm->cp = cp;
1206 GNUNET_CONTAINER_DLL_insert (cp->mqm_head,
1207 cp->mqm_tail,
1208 mqm);
1209 LOG (GNUNET_ERROR_TYPE_DEBUG,
1210 "Creating MQM %p for peer %s\n",
1211 mqm,
1212 GCP_2s (cp));
1213 if (NULL != cp->core_mq)
1214 cb (cb_cls,
1215 GNUNET_YES);
1216 return mqm;
1217}
1218
1219
1220/**
1221 * Stops message queue change notifications.
1222 *
1223 * @param mqm handle matching request to cancel
1224 * @param last_env final message to transmit, or NULL
1225 */
1226void
1227GCP_request_mq_cancel (struct GCP_MessageQueueManager *mqm,
1228 struct GNUNET_MQ_Envelope *last_env)
1229{
1230 struct CadetPeer *cp = mqm->cp;
1231
1232 LOG (GNUNET_ERROR_TYPE_DEBUG,
1233 "Destroying MQM %p for peer %s%s\n",
1234 mqm,
1235 GCP_2s (cp),
1236 (NULL == last_env) ? "" : " with last ditch transmission");
1237 if (NULL != mqm->env)
1238 GNUNET_MQ_discard (mqm->env);
1239 if (NULL != last_env)
1240 {
1241 if (NULL != cp->core_mq)
1242 GNUNET_MQ_send (cp->core_mq,
1243 last_env);
1244 else
1245 GNUNET_MQ_discard (last_env);
1246 }
1247 GNUNET_CONTAINER_DLL_remove (cp->mqm_head,
1248 cp->mqm_tail,
1249 mqm);
1250 GNUNET_free (mqm);
1251}
1252
1253
1254/**
1255 * Send the message in @a env to @a cp, overriding queueing logic.
1256 * This function should only be used to send error messages outside
1257 * of flow and congestion control, similar to ICMP. Note that
1258 * the envelope may be silently discarded as well.
1259 *
1260 * @param cp peer to send the message to
1261 * @param env envelope with the message to send
1262 */
1263void
1264GCP_send_ooo (struct CadetPeer *cp,
1265 struct GNUNET_MQ_Envelope *env)
1266{
1267 LOG (GNUNET_ERROR_TYPE_DEBUG,
1268 "Sending message to %s out of management\n",
1269 GCP_2s (cp));
1270 if (NULL == cp->core_mq)
1271 {
1272 GNUNET_MQ_discard (env);
1273 return;
1274 }
1275 GNUNET_MQ_send (cp->core_mq,
1276 env);
1277}
1278
1279
1280
1281
1282/* 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 aaaef15b8..000000000
--- a/src/cadet/gnunet-service-cadet-new_peer.h
+++ /dev/null
@@ -1,380 +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 * Obtain the peer identity for a `struct CadetPeer`.
64 *
65 * @param cp our peer handle
66 * @return the peer identity
67 */
68const struct GNUNET_PeerIdentity *
69GCP_get_id (struct CadetPeer *cp);
70
71
72/**
73 * Iterate over all known peers.
74 *
75 * @param iter Iterator.
76 * @param cls Closure for @c iter.
77 */
78void
79GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter,
80 void *cls);
81
82
83/**
84 * Count the number of known paths toward the peer.
85 *
86 * @param cp Peer to get path info.
87 * @return Number of known paths.
88 */
89unsigned int
90GCP_count_paths (const struct CadetPeer *cp);
91
92
93/**
94 * Drop all paths owned by this peer, and do not
95 * allow new ones to be added: We are shutting down.
96 *
97 * @param cp peer to drop paths to
98 */
99void
100GCP_drop_owned_paths (struct CadetPeer *cp);
101
102
103/**
104 * Peer path iterator.
105 *
106 * @param cls Closure.
107 * @param path Path itself
108 * @param off offset of the target peer in @a path
109 * @return #GNUNET_YES if should keep iterating.
110 * #GNUNET_NO otherwise.
111 */
112typedef int
113(*GCP_PathIterator) (void *cls,
114 struct CadetPeerPath *path,
115 unsigned int off);
116
117
118/**
119 * Iterate over the paths to a peer.
120 *
121 * @param cp Peer to get path info.
122 * @param callback Function to call for every path.
123 * @param callback_cls Closure for @a callback.
124 * @return Number of iterated paths.
125 */
126unsigned int
127GCP_iterate_paths (struct CadetPeer *cp,
128 GCP_PathIterator callback,
129 void *callback_cls);
130
131
132/**
133 * Iterate over the paths to @a peer where
134 * @a peer is at distance @a dist from us.
135 *
136 * @param cp Peer to get path info.
137 * @param dist desired distance of @a peer to us on the path
138 * @param callback Function to call for every path.
139 * @param callback_cls Closure for @a callback.
140 * @return Number of iterated paths.
141 */
142unsigned int
143GCP_iterate_paths_at (struct CadetPeer *cp,
144 unsigned int dist,
145 GCP_PathIterator callback,
146 void *callback_cls);
147
148
149/**
150 * Remove an entry from the DLL of all of the paths that this peer is on.
151 *
152 * @param cp peer to modify
153 * @param entry an entry on a path
154 * @param off offset of this peer on the path
155 */
156void
157GCP_path_entry_remove (struct CadetPeer *cp,
158 struct CadetPeerPathEntry *entry,
159 unsigned int off);
160
161
162/**
163 * Add an entry to the DLL of all of the paths that this peer is on.
164 *
165 * @param cp peer to modify
166 * @param entry an entry on a path
167 * @param off offset of this peer on the path
168 */
169void
170GCP_path_entry_add (struct CadetPeer *cp,
171 struct CadetPeerPathEntry *entry,
172 unsigned int off);
173
174
175/**
176 * Get the tunnel towards a peer.
177 *
178 * @param cp Peer to get from.
179 * @param create #GNUNET_YES to create a tunnel if we do not have one
180 * @return Tunnel towards peer.
181 */
182struct CadetTunnel *
183GCP_get_tunnel (struct CadetPeer *cp,
184 int create);
185
186
187/**
188 * The tunnel to the given peer no longer exists, remove it from our
189 * data structures, and possibly clean up the peer itself.
190 *
191 * @param cp the peer affected
192 * @param t the dead tunnel
193 */
194void
195GCP_drop_tunnel (struct CadetPeer *cp,
196 struct CadetTunnel *t);
197
198
199/**
200 * Try adding a @a path to this @a cp. If the peer already
201 * has plenty of paths, return NULL.
202 *
203 * @param cp peer to which the @a path leads to
204 * @param path a path looking for an owner; may not be fully initialized yet!
205 * @param off offset of @a cp in @a path
206 * @param force for attaching the path
207 * @return NULL if this peer does not care to become a new owner,
208 * otherwise the node in the peer's path heap for the @a path.
209 */
210struct GNUNET_CONTAINER_HeapNode *
211GCP_attach_path (struct CadetPeer *cp,
212 struct CadetPeerPath *path,
213 unsigned int off,
214 int force);
215
216
217/**
218 * This peer can no longer own @a path as the path
219 * has been extended and a peer further down the line
220 * is now the new owner.
221 *
222 * @param cp old owner of the @a path
223 * @param path path where the ownership is lost
224 * @param hn note in @a cp's path heap that must be deleted
225 */
226void
227GCP_detach_path (struct CadetPeer *cp,
228 struct CadetPeerPath *path,
229 struct GNUNET_CONTAINER_HeapNode *hn);
230
231
232/**
233 * Add a @a connection to this @a cp.
234 *
235 * @param cp peer via which the @a connection goes
236 * @param cc the connection to add
237 */
238void
239GCP_add_connection (struct CadetPeer *cp,
240 struct CadetConnection *cc);
241
242
243/**
244 * Remove a @a connection that went via this @a cp.
245 *
246 * @param cp peer via which the @a connection went
247 * @param cc the connection to remove
248 */
249void
250GCP_remove_connection (struct CadetPeer *cp,
251 struct CadetConnection *cc);
252
253
254/**
255 * We got a HELLO for a @a cp, remember it, and possibly
256 * trigger adequate actions (like trying to connect).
257 *
258 * @param cp the peer we got a HELLO for
259 * @param hello the HELLO to remember
260 */
261void
262GCP_set_hello (struct CadetPeer *cp,
263 const struct GNUNET_HELLO_Message *hello);
264
265
266/**
267 * Clean up all entries about all peers.
268 * Must only be called after all tunnels, CORE-connections and
269 * connections are down.
270 */
271void
272GCP_destroy_all_peers (void);
273
274
275/**
276 * Data structure used to track whom we have to notify about changes
277 * in our ability to transmit to a given peer.
278 *
279 * All queue managers will be given equal chance for sending messages
280 * to @a cp. This construct this guarantees fairness for access to @a
281 * cp among the different message queues. Each connection or route
282 * will have its respective message queue managers for each direction.
283 */
284struct GCP_MessageQueueManager;
285
286
287/**
288 * Function to call with updated message queue object.
289 *
290 * @param cls closure
291 * @param available #GNUNET_YES if sending is now possible,
292 * #GNUNET_NO if sending is no longer possible
293 * #GNUNET_SYSERR if sending is no longer possible
294 * and the last envelope was discarded
295 */
296typedef void
297(*GCP_MessageQueueNotificationCallback)(void *cls,
298 int available);
299
300
301/**
302 * Start message queue change notifications. Will create a new slot
303 * to manage the message queue to the given @a cp.
304 *
305 * @param cp peer to notify for
306 * @param cb function to call if mq becomes available or unavailable
307 * @param cb_cls closure for @a cb
308 * @return handle to cancel request
309 */
310struct GCP_MessageQueueManager *
311GCP_request_mq (struct CadetPeer *cp,
312 GCP_MessageQueueNotificationCallback cb,
313 void *cb_cls);
314
315
316/**
317 * Test if @a cp has a core-level connection
318 *
319 * @param cp peer to test
320 * @return #GNUNET_YES if @a cp has a core-level connection
321 */
322int
323GCP_has_core_connection (struct CadetPeer *cp);
324
325
326/**
327 * Send the message in @a env via a @a mqm. Must only be called at
328 * most once after the respective
329 * #GCP_MessageQueueNotificationCallback was called with `available`
330 * set to #GNUNET_YES, and not after the callback was called with
331 * `available` set to #GNUNET_NO or #GNUNET_SYSERR.
332 *
333 * @param mqm message queue manager for the transmission
334 * @param env envelope with the message to send; must NOT
335 * yet have a #GNUNET_MQ_notify_sent() callback attached to it
336 */
337void
338GCP_send (struct GCP_MessageQueueManager *mqm,
339 struct GNUNET_MQ_Envelope *env);
340
341
342/**
343 * Send the message in @a env to @a cp, overriding queueing logic.
344 * This function should only be used to send error messages outside
345 * of flow and congestion control, similar to ICMP. Note that
346 * the envelope may be silently discarded as well.
347 *
348 * @param cp peer to send the message to
349 * @param env envelope with the message to send
350 */
351void
352GCP_send_ooo (struct CadetPeer *cp,
353 struct GNUNET_MQ_Envelope *env);
354
355
356/**
357 * Stops message queue change notifications and sends a last message.
358 * In practice, this is implemented by sending that @a last_env
359 * message immediately (if any), ignoring queue order.
360 *
361 * @param mqm handle matching request to cancel
362 * @param last_env final message to transmit, or NULL
363 */
364void
365GCP_request_mq_cancel (struct GCP_MessageQueueManager *mqm,
366 struct GNUNET_MQ_Envelope *last_env);
367
368
369/**
370 * Set the message queue to @a mq for peer @a cp and notify watchers.
371 *
372 * @param cp peer to modify
373 * @param mq message queue to set (can be NULL)
374 */
375void
376GCP_set_mq (struct CadetPeer *cp,
377 struct GNUNET_MQ_Handle *mq);
378
379
380#endif
diff --git a/src/cadet/gnunet-service-cadet.c b/src/cadet/gnunet-service-cadet.c
index 3a07f0ee5..af4cebfaa 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,37 +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 `struct OpenPort`
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};
56 101
57 102
58/******************************************************************************/ 103/******************************************************************************/
@@ -62,37 +107,318 @@
62/****************************** Global variables ******************************/ 107/****************************** Global variables ******************************/
63 108
64/** 109/**
110 * Handle to our configuration.
111 */
112const struct GNUNET_CONFIGURATION_Handle *cfg;
113
114/**
65 * Handle to the statistics service. 115 * Handle to the statistics service.
66 */ 116 */
67struct GNUNET_STATISTICS_Handle *stats; 117struct GNUNET_STATISTICS_Handle *stats;
68 118
69/** 119/**
70 * Local peer own ID (memory efficient handle). 120 * Handle to communicate with ATS.
71 */ 121 */
72GNUNET_PEER_Id myid; 122struct GNUNET_ATS_ConnectivityHandle *ats_ch;
73 123
74/** 124/**
75 * Local peer own ID (full value). 125 * Local peer own ID.
76 */ 126 */
77struct GNUNET_PeerIdentity my_full_id; 127struct GNUNET_PeerIdentity my_full_id;
78 128
129/**
130 * Own private key.
131 */
132struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
79 133
80/** 134/**
81 * Signal that shutdown is happening: prevent recover measures. 135 * Signal that shutdown is happening: prevent recovery measures.
82 */ 136 */
83int shutting_down; 137int shutting_down;
84 138
85/*************************** Static global variables **************************/ 139/**
140 * DLL with all the clients, head.
141 */
142static struct CadetClient *clients_head;
86 143
87/** 144/**
88 * Own private key. 145 * DLL with all the clients, tail.
89 */ 146 */
90static struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key; 147static struct CadetClient *clients_tail;
91 148
149/**
150 * Next ID to assign to a client.
151 */
152static unsigned int next_client_id;
153
154/**
155 * All ports clients of this peer have opened. Maps from
156 * a hashed port to a `struct OpenPort`.
157 */
158struct GNUNET_CONTAINER_MultiHashMap *open_ports;
159
160/**
161 * Map from ports to channels where the ports were closed at the
162 * time we got the inbound connection.
163 * Indexed by h_port, contains `struct CadetChannel`.
164 */
165struct GNUNET_CONTAINER_MultiHashMap *loose_channels;
166
167/**
168 * Map from PIDs to `struct CadetPeer` entries.
169 */
170struct GNUNET_CONTAINER_MultiPeerMap *peers;
171
172/**
173 * Map from `struct GNUNET_CADET_ConnectionTunnelIdentifier`
174 * hash codes to `struct CadetConnection` objects.
175 */
176struct GNUNET_CONTAINER_MultiShortmap *connections;
177
178/**
179 * How many messages are needed to trigger an AXOLOTL ratchet advance.
180 */
181unsigned long long ratchet_messages;
182
183/**
184 * How long until we trigger a ratched advance due to time.
185 */
186struct GNUNET_TIME_Relative ratchet_time;
187
188/**
189 * How frequently do we send KEEPALIVE messages on idle connections?
190 */
191struct GNUNET_TIME_Relative keepalive_period;
192
193/**
194 * Set to non-zero values to create random drops to test retransmissions.
195 */
196unsigned long long drop_percent;
197
198
199/**
200 * Send a message to a client.
201 *
202 * @param c client to get the message
203 * @param env envelope with the message
204 */
205void
206GSC_send_to_client (struct CadetClient *c,
207 struct GNUNET_MQ_Envelope *env)
208{
209 GNUNET_MQ_send (c->mq,
210 env);
211}
212
213
214/**
215 * Return identifier for a client as a string.
216 *
217 * @param c client to identify
218 * @return string for debugging
219 */
220const char *
221GSC_2s (struct CadetClient *c)
222{
223 static char buf[32];
224
225 GNUNET_snprintf (buf,
226 sizeof (buf),
227 "Client(%u)",
228 c->id);
229 return buf;
230}
231
232
233/**
234 * Lookup channel of client @a c by @a ccn.
235 *
236 * @param c client to look in
237 * @param ccn channel ID to look up
238 * @return NULL if no such channel exists
239 */
240static struct CadetChannel *
241lookup_channel (struct CadetClient *c,
242 struct GNUNET_CADET_ClientChannelNumber ccn)
243{
244 return GNUNET_CONTAINER_multihashmap32_get (c->channels,
245 ntohl (ccn.channel_of_client));
246}
247
248
249/**
250 * Obtain the next LID to use for incoming connections to
251 * the given client.
252 *
253 * @param c client handle
254 */
255static struct GNUNET_CADET_ClientChannelNumber
256client_get_next_ccn (struct CadetClient *c)
257{
258 struct GNUNET_CADET_ClientChannelNumber ccn = c->next_ccn;
259
260 /* increment until we have a free one... */
261 while (NULL !=
262 lookup_channel (c,
263 ccn))
264 {
265 ccn.channel_of_client
266 = htonl (1 + (ntohl (ccn.channel_of_client)));
267 if (ntohl (ccn.channel_of_client) >=
268 GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
269 ccn.channel_of_client = htonl (0);
270 }
271 c->next_ccn.channel_of_client
272 = htonl (1 + (ntohl (ccn.channel_of_client)));
273 return ccn;
274}
275
276
277/**
278 * Bind incoming channel to this client, and notify client about
279 * incoming connection. Caller is responsible for notifying the other
280 * peer about our acceptance of the channel.
281 *
282 * @param c client to bind to
283 * @param ch channel to be bound
284 * @param dest peer that establishes the connection
285 * @param port port number
286 * @param options options
287 * @return local channel number assigned to the new client
288 */
289struct GNUNET_CADET_ClientChannelNumber
290GSC_bind (struct CadetClient *c,
291 struct CadetChannel *ch,
292 struct CadetPeer *dest,
293 const struct GNUNET_HashCode *port,
294 uint32_t options)
295{
296 struct GNUNET_MQ_Envelope *env;
297 struct GNUNET_CADET_LocalChannelCreateMessage *cm;
298 struct GNUNET_CADET_ClientChannelNumber ccn;
299
300 ccn = client_get_next_ccn (c);
301 GNUNET_assert (GNUNET_YES ==
302 GNUNET_CONTAINER_multihashmap32_put (c->channels,
303 ntohl (ccn.channel_of_client),
304 ch,
305 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
306 LOG (GNUNET_ERROR_TYPE_DEBUG,
307 "Accepting incoming %s from %s on open port %s (%u), assigning ccn %X\n",
308 GCCH_2s (ch),
309 GCP_2s (dest),
310 GNUNET_h2s (port),
311 (uint32_t) ntohl (options),
312 (uint32_t) ntohl (ccn.channel_of_client));
313 /* notify local client about incoming connection! */
314 env = GNUNET_MQ_msg (cm,
315 GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_CREATE);
316 cm->ccn = ccn;
317 cm->port = *port;
318 cm->opt = htonl (options);
319 cm->peer = *GCP_get_id (dest);
320 GSC_send_to_client (c,
321 env);
322 return ccn;
323}
324
325
326/**
327 * Callback invoked on all peers to destroy all tunnels
328 * that may still exist.
329 *
330 * @param cls NULL
331 * @param pid identify of a peer
332 * @param value a `struct CadetPeer` that may still have a tunnel
333 * @return #GNUNET_OK (iterate over all entries)
334 */
335static int
336destroy_tunnels_now (void *cls,
337 const struct GNUNET_PeerIdentity *pid,
338 void *value)
339{
340 struct CadetPeer *cp = value;
341 struct CadetTunnel *t = GCP_get_tunnel (cp,
342 GNUNET_NO);
343
344 if (NULL != t)
345 GCT_destroy_tunnel_now (t);
346 return GNUNET_OK;
347}
348
349
350/**
351 * Callback invoked on all peers to destroy all tunnels
352 * that may still exist.
353 *
354 * @param cls NULL
355 * @param pid identify of a peer
356 * @param value a `struct CadetPeer` that may still have a tunnel
357 * @return #GNUNET_OK (iterate over all entries)
358 */
359static int
360destroy_paths_now (void *cls,
361 const struct GNUNET_PeerIdentity *pid,
362 void *value)
363{
364 struct CadetPeer *cp = value;
365
366 GCP_drop_owned_paths (cp);
367 return GNUNET_OK;
368}
369
370
371/**
372 * Shutdown everything once the clients have disconnected.
373 */
374static void
375shutdown_rest ()
376{
377 if (NULL != stats)
378 {
379 GNUNET_STATISTICS_destroy (stats,
380 GNUNET_NO);
381 stats = NULL;
382 }
383 if (NULL != open_ports)
384 {
385 GNUNET_CONTAINER_multihashmap_destroy (open_ports);
386 open_ports = NULL;
387 }
388 if (NULL != loose_channels)
389 {
390 GNUNET_CONTAINER_multihashmap_destroy (loose_channels);
391 loose_channels = NULL;
392 }
393 /* Destroy tunnels. Note that all channels must be destroyed first! */
394 GCP_iterate_all (&destroy_tunnels_now,
395 NULL);
396 /* All tunnels, channels, connections and CORE must be down before this point. */
397 GCP_iterate_all (&destroy_paths_now,
398 NULL);
399 /* All paths, tunnels, channels, connections and CORE must be down before this point. */
400 GCP_destroy_all_peers ();
401 if (NULL != peers)
402 {
403 GNUNET_CONTAINER_multipeermap_destroy (peers);
404 peers = NULL;
405 }
406 if (NULL != connections)
407 {
408 GNUNET_CONTAINER_multishortmap_destroy (connections);
409 connections = NULL;
410 }
411 if (NULL != ats_ch)
412 {
413 GNUNET_ATS_connectivity_done (ats_ch);
414 ats_ch = NULL;
415 }
416 GCD_shutdown ();
417 GCH_shutdown ();
418 GNUNET_free_non_null (my_private_key);
419 my_private_key = NULL;
420}
92 421
93/******************************************************************************/
94/************************ MAIN FUNCTIONS ****************************/
95/******************************************************************************/
96 422
97/** 423/**
98 * Task run during shutdown. 424 * Task run during shutdown.
@@ -102,83 +428,1087 @@ static struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
102static void 428static void
103shutdown_task (void *cls) 429shutdown_task (void *cls)
104{ 430{
105 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "shutting down\n"); 431 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
106 432 "Shutting down\n");
107 shutting_down = GNUNET_YES; 433 shutting_down = GNUNET_YES;
434 GCO_shutdown ();
435 if (NULL == clients_head)
436 shutdown_rest ();
437}
108 438
109 GML_shutdown ();
110 GCH_shutdown ();
111 GCC_shutdown ();
112 GCT_shutdown ();
113 GCD_shutdown ();
114 GCP_shutdown ();
115 439
116 GNUNET_STATISTICS_destroy (stats, GNUNET_NO); 440/**
117 stats = NULL; 441 * We had a remote connection @a value to port @a h_port before
118 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "shut down\n"); 442 * client @a cls opened port @a port. Bind them now.
443 *
444 * @param cls the `struct CadetClient`
445 * @param h_port the hashed port
446 * @param value the `struct CadetChannel`
447 * @return #GNUNET_YES (iterate over all such channels)
448 */
449static int
450bind_loose_channel (void *cls,
451 const struct GNUNET_HashCode *port,
452 void *value)
453{
454 struct OpenPort *op = cls;
455 struct CadetChannel *ch = value;
456
457 GCCH_bind (ch,
458 op->c,
459 &op->port);
460 GNUNET_assert (GNUNET_YES ==
461 GNUNET_CONTAINER_multihashmap_remove (loose_channels,
462 &op->h_port,
463 ch));
464 return GNUNET_YES;
119} 465}
120 466
121 467
122/** 468/**
123 * Process cadet requests. 469 * Handle port open request. Creates a mapping from the
470 * port to the respective client and checks whether we have
471 * loose channels trying to bind to the port. If so, those
472 * are bound.
124 * 473 *
125 * @param cls closure 474 * @param cls Identification of the client.
126 * @param server the initialized server 475 * @param pmsg The actual message.
127 * @param c configuration to use
128 */ 476 */
129static void 477static void
130run (void *cls, struct GNUNET_SERVER_Handle *server, 478handle_port_open (void *cls,
131 const struct GNUNET_CONFIGURATION_Handle *c) 479 const struct GNUNET_CADET_PortMessage *pmsg)
132{ 480{
133 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "starting to run\n"); 481 struct CadetClient *c = cls;
482 struct OpenPort *op;
134 483
135 stats = GNUNET_STATISTICS_create ("cadet", c); 484 LOG (GNUNET_ERROR_TYPE_DEBUG,
485 "Open port %s requested by %s\n",
486 GNUNET_h2s (&pmsg->port),
487 GSC_2s (c));
488 if (NULL == c->ports)
489 c->ports = GNUNET_CONTAINER_multihashmap_create (4,
490 GNUNET_NO);
491 op = GNUNET_new (struct OpenPort);
492 op->c = c;
493 op->port = pmsg->port;
494 GCCH_hash_port (&op->h_port,
495 &pmsg->port,
496 &my_full_id);
497 if (GNUNET_OK !=
498 GNUNET_CONTAINER_multihashmap_put (c->ports,
499 &op->port,
500 op,
501 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
502 {
503 GNUNET_break (0);
504 GNUNET_SERVICE_client_drop (c->client);
505 return;
506 }
507 (void) GNUNET_CONTAINER_multihashmap_put (open_ports,
508 &op->h_port,
509 op,
510 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
511 GNUNET_CONTAINER_multihashmap_get_multiple (loose_channels,
512 &op->h_port,
513 &bind_loose_channel,
514 op);
515 GNUNET_SERVICE_client_continue (c->client);
516}
136 517
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 518
149 GML_init (server); /* Local clients */ 519/**
150 GCH_init (c); /* Hellos */ 520 * Handler for port close requests. Marks this port as closed
151 GCC_init (c); /* Connections */ 521 * (unless of course we have another client with the same port
152 GCP_init (c); /* Peers */ 522 * open). Note that existing channels accepted on the port are
153 GCD_init (c); /* DHT */ 523 * not affected.
154 GCT_init (c, my_private_key); /* Tunnels */ 524 *
525 * @param cls Identification of the client.
526 * @param pmsg The actual message.
527 */
528static void
529handle_port_close (void *cls,
530 const struct GNUNET_CADET_PortMessage *pmsg)
531{
532 struct CadetClient *c = cls;
533 struct OpenPort *op;
155 534
156 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cadet service running\n"); 535 LOG (GNUNET_ERROR_TYPE_DEBUG,
536 "Closing port %s as requested by %s\n",
537 GNUNET_h2s (&pmsg->port),
538 GSC_2s (c));
539 op = GNUNET_CONTAINER_multihashmap_get (c->ports,
540 &pmsg->port);
541 if (NULL == op)
542 {
543 GNUNET_break (0);
544 GNUNET_SERVICE_client_drop (c->client);
545 return;
546 }
547 GNUNET_assert (GNUNET_YES ==
548 GNUNET_CONTAINER_multihashmap_remove (c->ports,
549 &op->port,
550 op));
551 GNUNET_assert (GNUNET_YES ==
552 GNUNET_CONTAINER_multihashmap_remove (open_ports,
553 &op->h_port,
554 op));
555 GNUNET_free (op);
556 GNUNET_SERVICE_client_continue (c->client);
157} 557}
158 558
159 559
160/** 560/**
161 * The main function for the cadet service. 561 * Handler for requests for us creating a new channel to another peer and port.
162 * 562 *
163 * @param argc number of arguments from the command line 563 * @param cls Identification of the client.
164 * @param argv command line arguments 564 * @param tcm The actual message.
165 * @return 0 ok, 1 on error
166 */ 565 */
167int 566static void
168main (int argc, char *const *argv) 567handle_channel_create (void *cls,
568 const struct GNUNET_CADET_LocalChannelCreateMessage *tcm)
169{ 569{
170 int r; 570 struct CadetClient *c = cls;
571 struct CadetChannel *ch;
171 572
172 shutting_down = GNUNET_NO; 573 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, 574 {
174 NULL); 575 /* Channel ID not in allowed range. */
175 GNUNET_free (my_private_key); 576 GNUNET_break (0);
577 GNUNET_SERVICE_client_drop (c->client);
578 return;
579 }
580 ch = lookup_channel (c,
581 tcm->ccn);
582 if (NULL != ch)
583 {
584 /* Channel ID already in use. Not allowed. */
585 GNUNET_break (0);
586 GNUNET_SERVICE_client_drop (c->client);
587 return;
588 }
589 LOG (GNUNET_ERROR_TYPE_DEBUG,
590 "New channel to %s at port %s requested by %s\n",
591 GNUNET_i2s (&tcm->peer),
592 GNUNET_h2s (&tcm->port),
593 GSC_2s (c));
176 594
177 if (GNUNET_OK != r) 595 /* Create channel */
596 ch = GCCH_channel_local_new (c,
597 tcm->ccn,
598 GCP_get (&tcm->peer,
599 GNUNET_YES),
600 &tcm->port,
601 ntohl (tcm->opt));
602 if (NULL == ch)
178 { 603 {
179 FPRINTF (stderr, "GNUNET_SERVICE_run for CADET has failed!\n"); 604 GNUNET_break (0);
180 return 1; 605 GNUNET_SERVICE_client_drop (c->client);
606 return;
181 } 607 }
608 GNUNET_assert (GNUNET_YES ==
609 GNUNET_CONTAINER_multihashmap32_put (c->channels,
610 ntohl (tcm->ccn.channel_of_client),
611 ch,
612 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
182 613
183 return 0; 614 GNUNET_SERVICE_client_continue (c->client);
184} 615}
616
617
618/**
619 * Handler for requests of destroying an existing channel.
620 *
621 * @param cls client identification of the client
622 * @param msg the actual message
623 */
624static void
625handle_channel_destroy (void *cls,
626 const struct GNUNET_CADET_LocalChannelDestroyMessage *msg)
627{
628 struct CadetClient *c = cls;
629 struct CadetChannel *ch;
630
631 ch = lookup_channel (c,
632 msg->ccn);
633 if (NULL == ch)
634 {
635 /* Client attempted to destroy unknown channel.
636 Can happen if the other side went down at the same time.*/
637 LOG (GNUNET_ERROR_TYPE_DEBUG,
638 "%s tried to destroy unknown channel %X\n",
639 GSC_2s(c),
640 (uint32_t) ntohl (msg->ccn.channel_of_client));
641 return;
642 }
643 LOG (GNUNET_ERROR_TYPE_DEBUG,
644 "%s is destroying %s\n",
645 GSC_2s(c),
646 GCCH_2s (ch));
647 GNUNET_assert (GNUNET_YES ==
648 GNUNET_CONTAINER_multihashmap32_remove (c->channels,
649 ntohl (msg->ccn.channel_of_client),
650 ch));
651 GCCH_channel_local_destroy (ch,
652 c,
653 msg->ccn);
654 GNUNET_SERVICE_client_continue (c->client);
655}
656
657
658/**
659 * Check for client traffic data message is well-formed.
660 *
661 * @param cls identification of the client
662 * @param msg the actual message
663 * @return #GNUNET_OK if @a msg is OK, #GNUNET_SYSERR if not
664 */
665static int
666check_local_data (void *cls,
667 const struct GNUNET_CADET_LocalData *msg)
668{
669 size_t payload_size;
670 size_t payload_claimed_size;
671 const char *buf;
672 struct GNUNET_MessageHeader pa;
673
674 /* FIXME: what is the format we shall allow for @a msg?
675 ONE payload item or multiple? Seems current cadet_api
676 at least in theory allows more than one. Next-gen
677 cadet_api will likely no more, so we could then
678 simplify this mess again. */
679 /* Sanity check for message size */
680 payload_size = ntohs (msg->header.size) - sizeof (*msg);
681 buf = (const char *) &msg[1];
682 while (payload_size >= sizeof (struct GNUNET_MessageHeader))
683 {
684 /* need to memcpy() for alignment */
685 GNUNET_memcpy (&pa,
686 buf,
687 sizeof (pa));
688 payload_claimed_size = ntohs (pa.size);
689 if ( (payload_size < payload_claimed_size) ||
690 (payload_claimed_size < sizeof (struct GNUNET_MessageHeader)) ||
691 (GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE < payload_claimed_size) )
692 {
693 GNUNET_break (0);
694 LOG (GNUNET_ERROR_TYPE_DEBUG,
695 "Local data of %u total size had sub-message %u at %u with %u bytes\n",
696 ntohs (msg->header.size),
697 ntohs (pa.type),
698 (unsigned int) (buf - (const char *) &msg[1]),
699 (unsigned int) payload_claimed_size);
700 return GNUNET_SYSERR;
701 }
702 payload_size -= payload_claimed_size;
703 buf += payload_claimed_size;
704 }
705 if (0 != payload_size)
706 {
707 GNUNET_break_op (0);
708 return GNUNET_SYSERR;
709 }
710 return GNUNET_OK;
711}
712
713
714/**
715 * Handler for client payload traffic to be send on a channel to
716 * another peer.
717 *
718 * @param cls identification of the client
719 * @param msg the actual message
720 */
721static void
722handle_local_data (void *cls,
723 const struct GNUNET_CADET_LocalData *msg)
724{
725 struct CadetClient *c = cls;
726 struct CadetChannel *ch;
727 size_t payload_size;
728 const char *buf;
729
730 ch = lookup_channel (c,
731 msg->ccn);
732 if (NULL == ch)
733 {
734 /* Channel does not exist (anymore) */
735 LOG (GNUNET_ERROR_TYPE_WARNING,
736 "Dropping payload for channel %u from client (channel unknown, other endpoint may have disconnected)\n",
737 (unsigned int) ntohl (msg->ccn.channel_of_client));
738 GNUNET_SERVICE_client_continue (c->client);
739 return;
740 }
741 payload_size = ntohs (msg->header.size) - sizeof (*msg);
742 GNUNET_STATISTICS_update (stats,
743 "# payload received from clients",
744 payload_size,
745 GNUNET_NO);
746 buf = (const char *) &msg[1];
747 LOG (GNUNET_ERROR_TYPE_DEBUG,
748 "Received %u bytes payload from %s for %s\n",
749 (unsigned int) payload_size,
750 GSC_2s (c),
751 GCCH_2s (ch));
752 if (GNUNET_OK !=
753 GCCH_handle_local_data (ch,
754 msg->ccn,
755 buf,
756 payload_size))
757 {
758 GNUNET_SERVICE_client_drop (c->client);
759 return;
760 }
761 GNUNET_SERVICE_client_continue (c->client);
762}
763
764
765/**
766 * Handler for client's ACKs for payload traffic.
767 *
768 * @param cls identification of the client.
769 * @param msg The actual message.
770 */
771static void
772handle_local_ack (void *cls,
773 const struct GNUNET_CADET_LocalAck *msg)
774{
775 struct CadetClient *c = cls;
776 struct CadetChannel *ch;
777
778 ch = lookup_channel (c,
779 msg->ccn);
780 if (NULL == ch)
781 {
782 /* Channel does not exist (anymore) */
783 LOG (GNUNET_ERROR_TYPE_WARNING,
784 "Ignoring local ACK for channel %u from client (channel unknown, other endpoint may have disconnected)\n",
785 (unsigned int) ntohl (msg->ccn.channel_of_client));
786 GNUNET_SERVICE_client_continue (c->client);
787 return;
788 }
789 LOG (GNUNET_ERROR_TYPE_DEBUG,
790 "Got a local ACK from %s for %s\n",
791 GSC_2s(c),
792 GCCH_2s (ch));
793 GCCH_handle_local_ack (ch,
794 msg->ccn);
795 GNUNET_SERVICE_client_continue (c->client);
796}
797
798
799/**
800 * Iterator over all peers to send a monitoring client info about each peer.
801 *
802 * @param cls Closure ().
803 * @param peer Peer ID (tunnel remote peer).
804 * @param value Peer info.
805 * @return #GNUNET_YES, to keep iterating.
806 */
807static int
808get_all_peers_iterator (void *cls,
809 const struct GNUNET_PeerIdentity *peer,
810 void *value)
811{
812 struct CadetClient *c = cls;
813 struct CadetPeer *p = value;
814 struct GNUNET_MQ_Envelope *env;
815 struct GNUNET_CADET_LocalInfoPeer *msg;
816
817 env = GNUNET_MQ_msg (msg,
818 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS);
819 msg->destination = *peer;
820 msg->paths = htons (GCP_count_paths (p));
821 msg->tunnel = htons (NULL != GCP_get_tunnel (p,
822 GNUNET_NO));
823 GNUNET_MQ_send (c->mq,
824 env);
825 return GNUNET_YES;
826}
827
828
829/**
830 * Handler for client's INFO PEERS request.
831 *
832 * @param cls Identification of the client.
833 * @param message The actual message.
834 */
835static void
836handle_get_peers (void *cls,
837 const struct GNUNET_MessageHeader *message)
838{
839 struct CadetClient *c = cls;
840 struct GNUNET_MQ_Envelope *env;
841 struct GNUNET_MessageHeader *reply;
842
843 GCP_iterate_all (&get_all_peers_iterator,
844 c);
845 env = GNUNET_MQ_msg (reply,
846 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS);
847 GNUNET_MQ_send (c->mq,
848 env);
849 GNUNET_SERVICE_client_continue (c->client);
850}
851
852
853/**
854 * Iterator over all paths of a peer to build an InfoPeer message.
855 * Message contains blocks of peers, first not included.
856 *
857 * @param cls message queue for transmission
858 * @param path Path itself
859 * @param off offset of the peer on @a path
860 * @return #GNUNET_YES if should keep iterating.
861 * #GNUNET_NO otherwise.
862 */
863static int
864path_info_iterator (void *cls,
865 struct CadetPeerPath *path,
866 unsigned int off)
867{
868 struct GNUNET_MQ_Handle *mq = cls;
869 struct GNUNET_MQ_Envelope *env;
870 struct GNUNET_MessageHeader *resp;
871 struct GNUNET_PeerIdentity *id;
872 uint16_t path_size;
873 unsigned int i;
874 unsigned int path_length;
875
876 path_length = GCPP_get_length (path);
877 path_size = sizeof (struct GNUNET_PeerIdentity) * (path_length - 1);
878 if (sizeof (*resp) + path_size > UINT16_MAX)
879 {
880 LOG (GNUNET_ERROR_TYPE_WARNING,
881 "Path of %u entries is too long for info message\n",
882 path_length);
883 return GNUNET_YES;
884 }
885 env = GNUNET_MQ_msg_extra (resp,
886 path_size,
887 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER);
888 id = (struct GNUNET_PeerIdentity *) &resp[1];
889
890 /* Don't copy first peer. First peer is always the local one. Last
891 * peer is always the destination (leave as 0, EOL).
892 */
893 for (i = 0; i < off; i++)
894 id[i] = *GCP_get_id (GCPP_get_peer_at_offset (path,
895 i + 1));
896 GNUNET_MQ_send (mq,
897 env);
898 return GNUNET_YES;
899}
900
901
902/**
903 * Handler for client's SHOW_PEER request.
904 *
905 * @param cls Identification of the client.
906 * @param msg The actual message.
907 */
908static void
909handle_show_peer (void *cls,
910 const struct GNUNET_CADET_LocalInfo *msg)
911{
912 struct CadetClient *c = cls;
913 struct CadetPeer *p;
914 struct GNUNET_MQ_Envelope *env;
915 struct GNUNET_MessageHeader *resp;
916
917 p = GCP_get (&msg->peer,
918 GNUNET_NO);
919 if (NULL != p)
920 GCP_iterate_paths (p,
921 &path_info_iterator,
922 c->mq);
923 /* Send message with 0/0 to indicate the end */
924 env = GNUNET_MQ_msg (resp,
925 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER_END);
926 GNUNET_MQ_send (c->mq,
927 env);
928 GNUNET_SERVICE_client_continue (c->client);
929}
930
931
932/**
933 * Iterator over all tunnels to send a monitoring client info about each tunnel.
934 *
935 * @param cls Closure ().
936 * @param peer Peer ID (tunnel remote peer).
937 * @param value a `struct CadetPeer`
938 * @return #GNUNET_YES, to keep iterating.
939 */
940static int
941get_all_tunnels_iterator (void *cls,
942 const struct GNUNET_PeerIdentity *peer,
943 void *value)
944{
945 struct CadetClient *c = cls;
946 struct CadetPeer *p = value;
947 struct GNUNET_MQ_Envelope *env;
948 struct GNUNET_CADET_LocalInfoTunnel *msg;
949 struct CadetTunnel *t;
950
951 t = GCP_get_tunnel (p,
952 GNUNET_NO);
953 if (NULL == t)
954 return GNUNET_YES;
955 env = GNUNET_MQ_msg (msg,
956 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS);
957 msg->destination = *peer;
958 msg->channels = htonl (GCT_count_channels (t));
959 msg->connections = htonl (GCT_count_any_connections (t));
960 msg->cstate = htons (0);
961 msg->estate = htons ((uint16_t) GCT_get_estate (t));
962 GNUNET_MQ_send (c->mq,
963 env);
964 return GNUNET_YES;
965}
966
967
968/**
969 * Handler for client's #GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS request.
970 *
971 * @param cls client Identification of the client.
972 * @param message The actual message.
973 */
974static void
975handle_info_tunnels (void *cls,
976 const struct GNUNET_MessageHeader *message)
977{
978 struct CadetClient *c = cls;
979 struct GNUNET_MQ_Envelope *env;
980 struct GNUNET_MessageHeader *reply;
981
982 GCP_iterate_all (&get_all_tunnels_iterator,
983 c);
984 env = GNUNET_MQ_msg (reply,
985 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS);
986 GNUNET_MQ_send (c->mq,
987 env);
988 GNUNET_SERVICE_client_continue (c->client);
989}
990
991
992/**
993 * Update the message with information about the connection.
994 *
995 * @param cls a `struct GNUNET_CADET_LocalInfoTunnel` message to update
996 * @param ct a connection about which we should store information in @a cls
997 */
998static void
999iter_connection (void *cls,
1000 struct CadetTConnection *ct)
1001{
1002 struct GNUNET_CADET_LocalInfoTunnel *msg = cls;
1003 struct CadetConnection *cc = ct->cc;
1004 struct GNUNET_CADET_ConnectionTunnelIdentifier *h;
1005
1006 h = (struct GNUNET_CADET_ConnectionTunnelIdentifier *) &msg[1];
1007 h[msg->connections++] = *(GCC_get_id (cc));
1008}
1009
1010
1011/**
1012 * Update the message with information about the channel.
1013 *
1014 * @param cls a `struct GNUNET_CADET_LocalInfoTunnel` message to update
1015 * @param ch a channel about which we should store information in @a cls
1016 */
1017static void
1018iter_channel (void *cls,
1019 struct CadetChannel *ch)
1020{
1021 struct GNUNET_CADET_LocalInfoTunnel *msg = cls;
1022 struct GNUNET_CADET_ConnectionTunnelIdentifier *h = (struct GNUNET_CADET_ConnectionTunnelIdentifier *) &msg[1];
1023 struct GNUNET_CADET_ChannelTunnelNumber *chn
1024 = (struct GNUNET_CADET_ChannelTunnelNumber *) &h[msg->connections];
1025
1026 chn[msg->channels++] = GCCH_get_id (ch);
1027}
1028
1029
1030/**
1031 * Handler for client's #GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL request.
1032 *
1033 * @param cls Identification of the client.
1034 * @param msg The actual message.
1035 */
1036static void
1037handle_info_tunnel (void *cls,
1038 const struct GNUNET_CADET_LocalInfo *msg)
1039{
1040 struct CadetClient *c = cls;
1041 struct GNUNET_MQ_Envelope *env;
1042 struct GNUNET_CADET_LocalInfoTunnel *resp;
1043 struct CadetTunnel *t;
1044 struct CadetPeer *p;
1045 unsigned int ch_n;
1046 unsigned int c_n;
1047
1048 p = GCP_get (&msg->peer,
1049 GNUNET_NO);
1050 t = GCP_get_tunnel (p,
1051 GNUNET_NO);
1052 if (NULL == t)
1053 {
1054 /* We don't know the tunnel */
1055 struct GNUNET_MQ_Envelope *env;
1056 struct GNUNET_CADET_LocalInfoTunnel *warn;
1057
1058 LOG (GNUNET_ERROR_TYPE_INFO,
1059 "Tunnel to %s unknown\n",
1060 GNUNET_i2s_full (&msg->peer));
1061 env = GNUNET_MQ_msg (warn,
1062 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL);
1063 warn->destination = msg->peer;
1064 GNUNET_MQ_send (c->mq,
1065 env);
1066 GNUNET_SERVICE_client_continue (c->client);
1067 return;
1068 }
1069
1070 /* Initialize context */
1071 ch_n = GCT_count_channels (t);
1072 c_n = GCT_count_any_connections (t);
1073 env = GNUNET_MQ_msg_extra (resp,
1074 c_n * sizeof (struct GNUNET_CADET_ConnectionTunnelIdentifier) +
1075 ch_n * sizeof (struct GNUNET_CADET_ChannelTunnelNumber),
1076 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL);
1077 resp->destination = msg->peer;
1078 /* Do not reorder! #iter_channel needs counters in HBO! */
1079 GCT_iterate_connections (t,
1080 &iter_connection,
1081 resp);
1082 GCT_iterate_channels (t,
1083 &iter_channel,
1084 resp);
1085 resp->connections = htonl (resp->connections);
1086 resp->channels = htonl (resp->channels);
1087 resp->cstate = htons (0);
1088 resp->estate = htons (GCT_get_estate (t));
1089 GNUNET_MQ_send (c->mq,
1090 env);
1091 GNUNET_SERVICE_client_continue (c->client);
1092}
1093
1094
1095/**
1096 * Iterator over all peers to dump info for each peer.
1097 *
1098 * @param cls Closure (unused).
1099 * @param peer Peer ID (tunnel remote peer).
1100 * @param value Peer info.
1101 *
1102 * @return #GNUNET_YES, to keep iterating.
1103 */
1104static int
1105show_peer_iterator (void *cls,
1106 const struct GNUNET_PeerIdentity *peer,
1107 void *value)
1108{
1109 struct CadetPeer *p = value;
1110 struct CadetTunnel *t;
1111
1112 t = GCP_get_tunnel (p,
1113 GNUNET_NO);
1114 if (NULL != t)
1115 GCT_debug (t,
1116 GNUNET_ERROR_TYPE_ERROR);
1117 LOG (GNUNET_ERROR_TYPE_ERROR, "\n");
1118 return GNUNET_YES;
1119}
1120
1121
1122/**
1123 * Handler for client's INFO_DUMP request.
1124 *
1125 * @param cls Identification of the client.
1126 * @param message The actual message.
1127 */
1128static void
1129handle_info_dump (void *cls,
1130 const struct GNUNET_MessageHeader *message)
1131{
1132 struct CadetClient *c = cls;
1133
1134 LOG (GNUNET_ERROR_TYPE_INFO,
1135 "Received dump info request from client %u\n",
1136 c->id);
1137
1138 LOG (GNUNET_ERROR_TYPE_ERROR,
1139 "*************************** DUMP START ***************************\n");
1140 for (struct CadetClient *ci = clients_head;
1141 NULL != ci;
1142 ci = ci->next)
1143 {
1144 LOG (GNUNET_ERROR_TYPE_ERROR,
1145 "Client %u (%p), handle: %p, ports: %u, channels: %u\n",
1146 ci->id,
1147 ci,
1148 ci->client,
1149 (NULL != c->ports)
1150 ? GNUNET_CONTAINER_multihashmap_size (ci->ports)
1151 : 0,
1152 GNUNET_CONTAINER_multihashmap32_size (ci->channels));
1153 }
1154 LOG (GNUNET_ERROR_TYPE_ERROR, "***************************\n");
1155 GCP_iterate_all (&show_peer_iterator,
1156 NULL);
1157
1158 LOG (GNUNET_ERROR_TYPE_ERROR,
1159 "**************************** DUMP END ****************************\n");
1160
1161 GNUNET_SERVICE_client_continue (c->client);
1162}
1163
1164
1165
1166/**
1167 * Callback called when a client connects to the service.
1168 *
1169 * @param cls closure for the service
1170 * @param client the new client that connected to the service
1171 * @param mq the message queue used to send messages to the client
1172 * @return @a c
1173 */
1174static void *
1175client_connect_cb (void *cls,
1176 struct GNUNET_SERVICE_Client *client,
1177 struct GNUNET_MQ_Handle *mq)
1178{
1179 struct CadetClient *c;
1180
1181 c = GNUNET_new (struct CadetClient);
1182 c->client = client;
1183 c->mq = mq;
1184 c->id = next_client_id++; /* overflow not important: just for debug */
1185 c->channels
1186 = GNUNET_CONTAINER_multihashmap32_create (32);
1187 GNUNET_CONTAINER_DLL_insert (clients_head,
1188 clients_tail,
1189 c);
1190 GNUNET_STATISTICS_update (stats,
1191 "# clients",
1192 +1,
1193 GNUNET_NO);
1194 LOG (GNUNET_ERROR_TYPE_DEBUG,
1195 "%s connected\n",
1196 GSC_2s (c));
1197 return c;
1198}
1199
1200
1201/**
1202 * A channel was destroyed by the other peer. Tell our client.
1203 *
1204 * @param c client that lost a channel
1205 * @param ccn channel identification number for the client
1206 * @param ch the channel object
1207 */
1208void
1209GSC_handle_remote_channel_destroy (struct CadetClient *c,
1210 struct GNUNET_CADET_ClientChannelNumber ccn,
1211 struct CadetChannel *ch)
1212{
1213 struct GNUNET_MQ_Envelope *env;
1214 struct GNUNET_CADET_LocalChannelDestroyMessage *tdm;
1215
1216 env = GNUNET_MQ_msg (tdm,
1217 GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY);
1218 tdm->ccn = ccn;
1219 GSC_send_to_client (c,
1220 env);
1221 GNUNET_assert (GNUNET_YES ==
1222 GNUNET_CONTAINER_multihashmap32_remove (c->channels,
1223 ntohl (ccn.channel_of_client),
1224 ch));
1225}
1226
1227
1228/**
1229 * A client that created a loose channel that was not bound to a port
1230 * disconnected, drop it from the #loose_channels list.
1231 *
1232 * @param h_port the hashed port the channel was trying to bind to
1233 * @param ch the channel that was lost
1234 */
1235void
1236GSC_drop_loose_channel (const struct GNUNET_HashCode *h_port,
1237 struct CadetChannel *ch)
1238{
1239 GNUNET_assert (GNUNET_YES ==
1240 GNUNET_CONTAINER_multihashmap_remove (loose_channels,
1241 h_port,
1242 ch));
1243}
1244
1245
1246/**
1247 * Iterator for deleting each channel whose client endpoint disconnected.
1248 *
1249 * @param cls Closure (client that has disconnected).
1250 * @param key The local channel id in host byte order
1251 * @param value The value stored at the key (channel to destroy).
1252 * @return #GNUNET_OK, keep iterating.
1253 */
1254static int
1255channel_destroy_iterator (void *cls,
1256 uint32_t key,
1257 void *value)
1258{
1259 struct CadetClient *c = cls;
1260 struct GNUNET_CADET_ClientChannelNumber ccn;
1261 struct CadetChannel *ch = value;
1262
1263 LOG (GNUNET_ERROR_TYPE_DEBUG,
1264 "Destroying %s, due to %s disconnecting.\n",
1265 GCCH_2s (ch),
1266 GSC_2s (c));
1267 ccn.channel_of_client = htonl (key);
1268 GCCH_channel_local_destroy (ch,
1269 c,
1270 ccn);
1271 GNUNET_assert (GNUNET_YES ==
1272 GNUNET_CONTAINER_multihashmap32_remove (c->channels,
1273 key,
1274 ch));
1275 return GNUNET_OK;
1276}
1277
1278
1279/**
1280 * Remove client's ports from the global hashmap on disconnect.
1281 *
1282 * @param cls the `struct CadetClient`
1283 * @param port the port.
1284 * @param value the `struct OpenPort` to remove
1285 * @return #GNUNET_OK, keep iterating.
1286 */
1287static int
1288client_release_ports (void *cls,
1289 const struct GNUNET_HashCode *port,
1290 void *value)
1291{
1292 struct CadetClient *c = cls;
1293 struct OpenPort *op = value;
1294
1295 GNUNET_assert (c == op->c);
1296 LOG (GNUNET_ERROR_TYPE_DEBUG,
1297 "Closing port %s due to %s disconnect.\n",
1298 GNUNET_h2s (port),
1299 GSC_2s (c));
1300 GNUNET_assert (GNUNET_YES ==
1301 GNUNET_CONTAINER_multihashmap_remove (open_ports,
1302 &op->h_port,
1303 op));
1304 GNUNET_assert (GNUNET_YES ==
1305 GNUNET_CONTAINER_multihashmap_remove (c->ports,
1306 port,
1307 op));
1308 GNUNET_free (op);
1309 return GNUNET_OK;
1310}
1311
1312
1313/**
1314 * Callback called when a client disconnected from the service
1315 *
1316 * @param cls closure for the service
1317 * @param client the client that disconnected
1318 * @param internal_cls should be equal to @a c
1319 */
1320static void
1321client_disconnect_cb (void *cls,
1322 struct GNUNET_SERVICE_Client *client,
1323 void *internal_cls)
1324{
1325 struct CadetClient *c = internal_cls;
1326
1327 GNUNET_assert (c->client == client);
1328 LOG (GNUNET_ERROR_TYPE_DEBUG,
1329 "%s is disconnecting.\n",
1330 GSC_2s (c));
1331 if (NULL != c->channels)
1332 {
1333 GNUNET_CONTAINER_multihashmap32_iterate (c->channels,
1334 &channel_destroy_iterator,
1335 c);
1336 GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap32_size (c->channels));
1337 GNUNET_CONTAINER_multihashmap32_destroy (c->channels);
1338 }
1339 if (NULL != c->ports)
1340 {
1341 GNUNET_CONTAINER_multihashmap_iterate (c->ports,
1342 &client_release_ports,
1343 c);
1344 GNUNET_CONTAINER_multihashmap_destroy (c->ports);
1345 }
1346 GNUNET_CONTAINER_DLL_remove (clients_head,
1347 clients_tail,
1348 c);
1349 GNUNET_STATISTICS_update (stats,
1350 "# clients",
1351 -1,
1352 GNUNET_NO);
1353 GNUNET_free (c);
1354 if ( (NULL == clients_head) &&
1355 (GNUNET_YES == shutting_down) )
1356 shutdown_rest ();
1357}
1358
1359
1360/**
1361 * Setup CADET internals.
1362 *
1363 * @param cls closure
1364 * @param server the initialized server
1365 * @param c configuration to use
1366 */
1367static void
1368run (void *cls,
1369 const struct GNUNET_CONFIGURATION_Handle *c,
1370 struct GNUNET_SERVICE_Handle *service)
1371{
1372 cfg = c;
1373 if (GNUNET_OK !=
1374 GNUNET_CONFIGURATION_get_value_number (c,
1375 "CADET",
1376 "RATCHET_MESSAGES",
1377 &ratchet_messages))
1378 {
1379 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
1380 "CADET",
1381 "RATCHET_MESSAGES",
1382 "needs to be a number");
1383 ratchet_messages = 64;
1384 }
1385 if (GNUNET_OK !=
1386 GNUNET_CONFIGURATION_get_value_time (c,
1387 "CADET",
1388 "RATCHET_TIME",
1389 &ratchet_time))
1390 {
1391 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
1392 "CADET",
1393 "RATCHET_TIME",
1394 "need delay value");
1395 ratchet_time = GNUNET_TIME_UNIT_HOURS;
1396 }
1397 if (GNUNET_OK !=
1398 GNUNET_CONFIGURATION_get_value_time (c,
1399 "CADET",
1400 "REFRESH_CONNECTION_TIME",
1401 &keepalive_period))
1402 {
1403 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
1404 "CADET",
1405 "REFRESH_CONNECTION_TIME",
1406 "need delay value");
1407 keepalive_period = GNUNET_TIME_UNIT_MINUTES;
1408 }
1409 if (GNUNET_OK !=
1410 GNUNET_CONFIGURATION_get_value_number (c,
1411 "CADET",
1412 "DROP_PERCENT",
1413 &drop_percent))
1414 {
1415 drop_percent = 0;
1416 }
1417 else
1418 {
1419 LOG (GNUNET_ERROR_TYPE_WARNING, "**************************************\n");
1420 LOG (GNUNET_ERROR_TYPE_WARNING, "Cadet is running with DROP enabled.\n");
1421 LOG (GNUNET_ERROR_TYPE_WARNING, "This is NOT a good idea!\n");
1422 LOG (GNUNET_ERROR_TYPE_WARNING, "Remove DROP_PERCENT from config file.\n");
1423 LOG (GNUNET_ERROR_TYPE_WARNING, "**************************************\n");
1424 }
1425 my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (c);
1426 if (NULL == my_private_key)
1427 {
1428 GNUNET_break (0);
1429 GNUNET_SCHEDULER_shutdown ();
1430 return;
1431 }
1432 GNUNET_CRYPTO_eddsa_key_get_public (my_private_key,
1433 &my_full_id.public_key);
1434 stats = GNUNET_STATISTICS_create ("cadet",
1435 c);
1436 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1437 NULL);
1438 ats_ch = GNUNET_ATS_connectivity_init (c);
1439 /* FIXME: optimize code to allow GNUNET_YES here! */
1440 open_ports = GNUNET_CONTAINER_multihashmap_create (16,
1441 GNUNET_NO);
1442 loose_channels = GNUNET_CONTAINER_multihashmap_create (16,
1443 GNUNET_NO);
1444 peers = GNUNET_CONTAINER_multipeermap_create (16,
1445 GNUNET_YES);
1446 connections = GNUNET_CONTAINER_multishortmap_create (256,
1447 GNUNET_YES);
1448 GCH_init (c);
1449 GCD_init (c);
1450 GCO_init (c);
1451 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1452 "CADET started for peer %s\n",
1453 GNUNET_i2s (&my_full_id));
1454
1455}
1456
1457
1458/**
1459 * Define "main" method using service macro.
1460 */
1461GNUNET_SERVICE_MAIN
1462("cadet",
1463 GNUNET_SERVICE_OPTION_NONE,
1464 &run,
1465 &client_connect_cb,
1466 &client_disconnect_cb,
1467 NULL,
1468 GNUNET_MQ_hd_fixed_size (port_open,
1469 GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_OPEN,
1470 struct GNUNET_CADET_PortMessage,
1471 NULL),
1472 GNUNET_MQ_hd_fixed_size (port_close,
1473 GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_CLOSE,
1474 struct GNUNET_CADET_PortMessage,
1475 NULL),
1476 GNUNET_MQ_hd_fixed_size (channel_create,
1477 GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_CREATE,
1478 struct GNUNET_CADET_LocalChannelCreateMessage,
1479 NULL),
1480 GNUNET_MQ_hd_fixed_size (channel_destroy,
1481 GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY,
1482 struct GNUNET_CADET_LocalChannelDestroyMessage,
1483 NULL),
1484 GNUNET_MQ_hd_var_size (local_data,
1485 GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA,
1486 struct GNUNET_CADET_LocalData,
1487 NULL),
1488 GNUNET_MQ_hd_fixed_size (local_ack,
1489 GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK,
1490 struct GNUNET_CADET_LocalAck,
1491 NULL),
1492 GNUNET_MQ_hd_fixed_size (get_peers,
1493 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS,
1494 struct GNUNET_MessageHeader,
1495 NULL),
1496 GNUNET_MQ_hd_fixed_size (show_peer,
1497 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER,
1498 struct GNUNET_CADET_LocalInfo,
1499 NULL),
1500 GNUNET_MQ_hd_fixed_size (info_tunnels,
1501 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS,
1502 struct GNUNET_MessageHeader,
1503 NULL),
1504 GNUNET_MQ_hd_fixed_size (info_tunnel,
1505 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL,
1506 struct GNUNET_CADET_LocalInfo,
1507 NULL),
1508 GNUNET_MQ_hd_fixed_size (info_dump,
1509 GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_DUMP,
1510 struct GNUNET_MessageHeader,
1511 NULL),
1512 GNUNET_MQ_handler_end ());
1513
1514/* 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 4a76c578b..162867823 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
@@ -29,7 +29,6 @@
29#define GNUNET_SERVICE_CADET_H 29#define GNUNET_SERVICE_CADET_H
30 30
31#include "gnunet_util_lib.h" 31#include "gnunet_util_lib.h"
32#define NEW_CADET 1
33#include "cadet_protocol.h" 32#include "cadet_protocol.h"
34 33
35/** 34/**
@@ -146,6 +145,30 @@ struct CadetTConnection
146 145
147 146
148/** 147/**
148 * Port opened by a client.
149 */
150struct OpenPort
151{
152
153 /**
154 * Client that opened the port.
155 */
156 struct CadetClient *c;
157
158 /**
159 * Port number.
160 */
161 struct GNUNET_HashCode port;
162
163 /**
164 * Port hashed with our PID (matches incoming OPEN messages).
165 */
166 struct GNUNET_HashCode h_port;
167
168};
169
170
171/**
149 * Active path through the network (used by a tunnel). There may 172 * Active path through the network (used by a tunnel). There may
150 * be at most one connection per path. 173 * be at most one connection per path.
151 */ 174 */
@@ -193,7 +216,8 @@ extern struct GNUNET_PeerIdentity my_full_id;
193extern struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key; 216extern struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
194 217
195/** 218/**
196 * All ports clients of this peer have opened. 219 * All ports clients of this peer have opened. Maps from
220 * a hashed port to a `struct OpenPort`.
197 */ 221 */
198extern struct GNUNET_CONTAINER_MultiHashMap *open_ports; 222extern struct GNUNET_CONTAINER_MultiHashMap *open_ports;
199 223
@@ -206,7 +230,7 @@ extern struct GNUNET_CONTAINER_MultiShortmap *connections;
206/** 230/**
207 * Map from ports to channels where the ports were closed at the 231 * Map from ports to channels where the ports were closed at the
208 * time we got the inbound connection. 232 * time we got the inbound connection.
209 * Indexed by port, contains `struct CadetChannel`. 233 * Indexed by h_port, contains `struct CadetChannel`.
210 */ 234 */
211extern struct GNUNET_CONTAINER_MultiHashMap *loose_channels; 235extern struct GNUNET_CONTAINER_MultiHashMap *loose_channels;
212 236
@@ -226,10 +250,20 @@ extern unsigned long long ratchet_messages;
226extern struct GNUNET_TIME_Relative ratchet_time; 250extern struct GNUNET_TIME_Relative ratchet_time;
227 251
228/** 252/**
253 * How frequently do we send KEEPALIVE messages on idle connections?
254 */
255extern struct GNUNET_TIME_Relative keepalive_period;
256
257/**
229 * Signal that shutdown is happening: prevent recovery measures. 258 * Signal that shutdown is happening: prevent recovery measures.
230 */ 259 */
231extern int shutting_down; 260extern int shutting_down;
232 261
262/**
263 * Set to non-zero values to create random drops to test retransmissions.
264 */
265extern unsigned long long drop_percent;
266
233 267
234/** 268/**
235 * Send a message to a client. 269 * Send a message to a client.
@@ -254,6 +288,17 @@ GSC_handle_remote_channel_destroy (struct CadetClient *c,
254 struct GNUNET_CADET_ClientChannelNumber ccn, 288 struct GNUNET_CADET_ClientChannelNumber ccn,
255 struct CadetChannel *ch); 289 struct CadetChannel *ch);
256 290
291/**
292 * A client that created a loose channel that was not bound to a port
293 * disconnected, drop it from the #loose_channels list.
294 *
295 * @param h_port the hashed port the channel was trying to bind to
296 * @param ch the channel that was lost
297 */
298void
299GSC_drop_loose_channel (const struct GNUNET_HashCode *h_port,
300 struct CadetChannel *ch);
301
257 302
258/** 303/**
259 * Bind incoming channel to this client, and notify client 304 * Bind incoming channel to this client, and notify client
diff --git a/src/cadet/gnunet-service-cadet_channel.c b/src/cadet/gnunet-service-cadet_channel.c
index 7b7c6e57c..739b68228 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,34 @@ 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 * Hash'ed port of the channel with initiator and destination PID.
260 */ 307 */
261 struct CadetClient *dest; 308 struct GNUNET_HashCode h_port;
262 309
263 /** 310 /**
264 * Flag to signal the destruction of the channel. 311 * Counter for exponential backoff.
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 struct GNUNET_TIME_Relative retry_time;
314
315 /**
316 * Bitfield of already-received messages past @e mid_recv.
317 */
318 uint64_t mid_futures;
319
320 /**
321 * Next MID expected for incoming traffic.
322 */
323 struct ChannelMessageIdentifier mid_recv;
324
325 /**
326 * Next MID to use for outgoing traffic.
327 */
328 struct ChannelMessageIdentifier mid_send;
269 329
270 /** 330 /**
271 * Total (reliable) messages pending ACK for this channel. 331 * Total (reliable) messages pending ACK for this channel.
@@ -273,2290 +333,1763 @@ struct CadetChannel
273 unsigned int pending_messages; 333 unsigned int pending_messages;
274 334
275 /** 335 /**
276 * Reliability data. 336 * Maximum (reliable) messages pending ACK for this channel
277 * Only present (non-NULL) at the owner of a tunnel. 337 * before we throttle the client.
278 */ 338 */
279 struct CadetChannelReliability *root_rel; 339 unsigned int max_pending_messages;
280 340
281 /** 341 /**
282 * Reliability data. 342 * Number identifying this channel in its tunnel.
283 * Only present (non-NULL) at the destination of a tunnel.
284 */ 343 */
285 struct CadetChannelReliability *dest_rel; 344 struct GNUNET_CADET_ChannelTunnelNumber ctn;
286 345
287}; 346 /**
347 * Channel state.
348 */
349 enum CadetChannelState state;
350
351 /**
352 * Count how many ACKs we skipped, used to prevent long
353 * sequences of ACK skipping.
354 */
355 unsigned int skip_ack_series;
288 356
357 /**
358 * Is the tunnel bufferless (minimum latency)?
359 */
360 int nobuffer;
289 361
290/******************************************************************************/ 362 /**
291/******************************* GLOBALS ***********************************/ 363 * Is the tunnel reliable?
292/******************************************************************************/ 364 */
365 int reliable;
293 366
294/** 367 /**
295 * Global handle to the statistics service. 368 * Is the tunnel out-of-order?
296 */ 369 */
297extern struct GNUNET_STATISTICS_Handle *stats; 370 int out_of_order;
298 371
299/** 372 /**
300 * Local peer own ID (memory efficient handle). 373 * Is this channel a loopback channel, where the destination is us again?
301 */ 374 */
302extern GNUNET_PEER_Id myid; 375 int is_loopback;
303 376
377 /**
378 * Flag to signal the destruction of the channel. If this is set to
379 * #GNUNET_YES the channel will be destroyed once the queue is
380 * empty.
381 */
382 int destroy;
304 383
305/******************************************************************************/ 384};
306/******************************** STATIC ***********************************/
307/******************************************************************************/
308 385
309 386
310/** 387/**
311 * Destroy a reliable message after it has been acknowledged, either by 388 * Get the static string for identification of the channel.
312 * direct mid ACK or bitfield. Updates the appropriate data structures and
313 * timers and frees all memory.
314 * 389 *
315 * @param copy Message that is no longer needed: remote peer got it. 390 * @param ch Channel.
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 * 391 *
321 * @return #GNUNET_YES if channel was destroyed as a result of the call, 392 * @return Static string with the channel IDs.
322 * #GNUNET_NO otherwise.
323 */ 393 */
324static int 394const char *
325rel_message_free (struct CadetReliableMessage *copy, int update_time); 395GCCH_2s (const struct CadetChannel *ch)
396{
397 static char buf[128];
398
399 GNUNET_snprintf (buf,
400 sizeof (buf),
401 "Channel %s:%s ctn:%X(%X/%X)",
402 (GNUNET_YES == ch->is_loopback)
403 ? "loopback"
404 : GNUNET_i2s (GCP_get_id (GCT_get_destination (ch->t))),
405 GNUNET_h2s (&ch->port),
406 ch->ctn,
407 (NULL == ch->owner) ? 0 : ntohl (ch->owner->ccn.channel_of_client),
408 (NULL == ch->dest) ? 0 : ntohl (ch->dest->ccn.channel_of_client));
409 return buf;
410}
326 411
327/**
328 * send a channel create message.
329 *
330 * @param ch Channel for which to send.
331 */
332static void
333send_create (struct CadetChannel *ch);
334 412
335/** 413/**
336 * Confirm we got a channel create, FWD ack. 414 * Hash the @a port and @a initiator and @a listener to
415 * calculate the "challenge" @a h_port we send to the other
416 * peer on #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN.
337 * 417 *
338 * @param ch The channel to confirm. 418 * @param[out] h_port set to the hash of @a port, @a initiator and @a listener
339 * @param fwd Should we send a FWD ACK? (going dest->root) 419 * @param port cadet port, as seen by CADET clients
420 * @param listener peer that is listining on @a port
340 */ 421 */
341static void 422void
342send_ack (struct CadetChannel *ch, int fwd); 423GCCH_hash_port (struct GNUNET_HashCode *h_port,
343 424 const struct GNUNET_HashCode *port,
425 const struct GNUNET_PeerIdentity *listener)
426{
427 struct GNUNET_HashContext *hc;
428
429 hc = GNUNET_CRYPTO_hash_context_start ();
430 GNUNET_CRYPTO_hash_context_read (hc,
431 port,
432 sizeof (*port));
433 GNUNET_CRYPTO_hash_context_read (hc,
434 listener,
435 sizeof (*listener));
436 GNUNET_CRYPTO_hash_context_finish (hc,
437 h_port);
438 LOG (GNUNET_ERROR_TYPE_DEBUG,
439 "Calculated port hash %s\n",
440 GNUNET_h2s (h_port));
441}
344 442
345 443
346/** 444/**
347 * Test if the channel is loopback: both root and dest are on the local peer. 445 * Get the channel's public ID.
348 * 446 *
349 * @param ch Channel to test. 447 * @param ch Channel.
350 * 448 *
351 * @return #GNUNET_YES if channel is loopback, #GNUNET_NO otherwise. 449 * @return ID used to identify the channel with the remote peer.
352 */ 450 */
353static int 451struct GNUNET_CADET_ChannelTunnelNumber
354is_loopback (const struct CadetChannel *ch) 452GCCH_get_id (const struct CadetChannel *ch)
355{ 453{
356 if (NULL != ch->t) 454 return ch->ctn;
357 return GCT_is_loopback (ch->t);
358
359 return (NULL != ch->root && NULL != ch->dest);
360} 455}
361 456
362 457
363/** 458/**
364 * Save a copy of the data message for later retransmission. 459 * Release memory associated with @a ccc
365 * 460 *
366 * @param msg Message to copy. 461 * @param ccc data structure to clean up
367 * @param mid Message ID.
368 * @param rel Reliability data for retransmission.
369 */ 462 */
370static struct CadetReliableMessage * 463static void
371copy_message (const struct GNUNET_CADET_ChannelAppDataMessage *msg, uint32_t mid, 464free_channel_client (struct CadetChannelClient *ccc)
372 struct CadetChannelReliability *rel)
373{ 465{
374 struct CadetReliableMessage *copy; 466 struct CadetOutOfOrderMessage *com;
375 uint16_t size;
376
377 size = ntohs (msg->header.size);
378 copy = GNUNET_malloc (sizeof (*copy) + size);
379 copy->mid = mid;
380 copy->rel = rel;
381 copy->type = GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA;
382 GNUNET_memcpy (&copy[1], msg, size);
383 467
384 return copy; 468 while (NULL != (com = ccc->head_recv))
469 {
470 GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
471 ccc->tail_recv,
472 com);
473 ccc->num_recv--;
474 GNUNET_MQ_discard (com->env);
475 GNUNET_free (com);
476 }
477 GNUNET_free (ccc);
385} 478}
386 479
480
387/** 481/**
388 * We have received a message out of order, or the client is not ready. 482 * Destroy the given channel.
389 * Buffer it until we receive an ACK from the client or the missing
390 * message from the channel.
391 * 483 *
392 * @param msg Message to buffer (MUST be of type CADET_DATA). 484 * @param ch channel to destroy
393 * @param rel Reliability data to the corresponding direction.
394 */ 485 */
395static void 486static void
396add_buffered_data (const struct GNUNET_CADET_ChannelAppDataMessage *msg, 487channel_destroy (struct CadetChannel *ch)
397 struct CadetChannelReliability *rel)
398{ 488{
399 struct CadetReliableMessage *copy; 489 struct CadetReliableMessage *crm;
400 struct CadetReliableMessage *prev;
401 uint32_t mid;
402 490
403 mid = ntohl (msg->mid); 491 while (NULL != (crm = ch->head_sent))
404
405 LOG (GNUNET_ERROR_TYPE_DEBUG, "add_buffered_data MID %u (%u)\n",
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 { 492 {
414 LOG (GNUNET_ERROR_TYPE_DEBUG, " prev %u\n", prev->mid); 493 GNUNET_assert (ch == crm->ch);
415 if (prev->mid == mid) 494 if (NULL != crm->qe)
416 { 495 {
417 LOG (GNUNET_ERROR_TYPE_DEBUG, " already there!\n"); 496 GCT_send_cancel (crm->qe);
418 rel->n_recv--; 497 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 } 498 }
499 GNUNET_CONTAINER_DLL_remove (ch->head_sent,
500 ch->tail_sent,
501 crm);
502 GNUNET_free (crm->data_message);
503 GNUNET_free (crm);
429 } 504 }
430 copy = copy_message (msg, mid, rel); 505 if (NULL != ch->owner)
431 LOG (GNUNET_ERROR_TYPE_DEBUG, " insert at tail! (now: %u)\n", rel->n_recv); 506 {
432 GNUNET_CONTAINER_DLL_insert_tail (rel->head_recv, rel->tail_recv, copy); 507 free_channel_client (ch->owner);
433 LOG (GNUNET_ERROR_TYPE_DEBUG, "add_buffered_data END\n"); 508 ch->owner = NULL;
509 }
510 if (NULL != ch->dest)
511 {
512 free_channel_client (ch->dest);
513 ch->dest = NULL;
514 }
515 if (NULL != ch->last_control_qe)
516 {
517 GCT_send_cancel (ch->last_control_qe);
518 ch->last_control_qe = NULL;
519 }
520 if (NULL != ch->retry_data_task)
521 {
522 GNUNET_SCHEDULER_cancel (ch->retry_data_task);
523 ch->retry_data_task = NULL;
524 }
525 if (NULL != ch->retry_control_task)
526 {
527 GNUNET_SCHEDULER_cancel (ch->retry_control_task);
528 ch->retry_control_task = NULL;
529 }
530 if (GNUNET_NO == ch->is_loopback)
531 {
532 GCT_remove_channel (ch->t,
533 ch,
534 ch->ctn);
535 ch->t = NULL;
536 }
537 GNUNET_free (ch);
434} 538}
435 539
436 540
437/** 541/**
438 * Add a destination client to a channel, initializing all data structures 542 * Send a channel create message.
439 * in the channel and the client.
440 * 543 *
441 * @param ch Channel to which add the destination. 544 * @param cls Channel for which to send.
442 * @param c Client which to add to the channel.
443 */ 545 */
444static void 546static void
445add_destination (struct CadetChannel *ch, struct CadetClient *c) 547send_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 548
468 549
469/** 550/**
470 * Set options in a channel, extracted from a bit flag field. 551 * Function called once the tunnel confirms that we sent the
552 * create message. Delays for a bit until we retry.
471 * 553 *
472 * @param ch Channel to set options to. 554 * @param cls our `struct CadetChannel`.
473 * @param options Bit array in host byte order. 555 * @param cid identifier of the connection within the tunnel, NULL
556 * if transmission failed
474 */ 557 */
475static void 558static void
476channel_set_options (struct CadetChannel *ch, uint32_t options) 559channel_open_sent_cb (void *cls,
560 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
477{ 561{
478 ch->nobuffer = (options & GNUNET_CADET_OPTION_NOBUFFER) != 0 ? 562 struct CadetChannel *ch = cls;
479 GNUNET_YES : GNUNET_NO; 563
480 ch->reliable = (options & GNUNET_CADET_OPTION_RELIABLE) != 0 ? 564 GNUNET_assert (NULL != ch->last_control_qe);
481 GNUNET_YES : GNUNET_NO; 565 ch->last_control_qe = NULL;
566 ch->retry_time = GNUNET_TIME_STD_BACKOFF (ch->retry_time);
567 LOG (GNUNET_ERROR_TYPE_DEBUG,
568 "Sent CADET_CHANNEL_OPEN on %s, retrying in %s\n",
569 GCCH_2s (ch),
570 GNUNET_STRINGS_relative_time_to_string (ch->retry_time,
571 GNUNET_YES));
572 ch->retry_control_task
573 = GNUNET_SCHEDULER_add_delayed (ch->retry_time,
574 &send_channel_open,
575 ch);
482} 576}
483 577
484 578
485/** 579/**
486 * Get a bit flag field with the options of a channel. 580 * Send a channel open message.
487 *
488 * @param ch Channel to get options from.
489 * 581 *
490 * @return Bit array in host byte order. 582 * @param cls Channel for which to send.
491 */ 583 */
492static uint32_t 584static void
493channel_get_options (struct CadetChannel *ch) 585send_channel_open (void *cls)
494{ 586{
587 struct CadetChannel *ch = cls;
588 struct GNUNET_CADET_ChannelOpenMessage msgcc;
495 uint32_t options; 589 uint32_t options;
496 590
591 ch->retry_control_task = NULL;
592 LOG (GNUNET_ERROR_TYPE_DEBUG,
593 "Sending CHANNEL_OPEN message for %s\n",
594 GCCH_2s (ch));
497 options = 0; 595 options = 0;
498 if (ch->nobuffer) 596 if (ch->nobuffer)
499 options |= GNUNET_CADET_OPTION_NOBUFFER; 597 options |= GNUNET_CADET_OPTION_NOBUFFER;
500 if (ch->reliable) 598 if (ch->reliable)
501 options |= GNUNET_CADET_OPTION_RELIABLE; 599 options |= GNUNET_CADET_OPTION_RELIABLE;
502 600 if (ch->out_of_order)
503 return options; 601 options |= GNUNET_CADET_OPTION_OUT_OF_ORDER;
602 msgcc.header.size = htons (sizeof (msgcc));
603 msgcc.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN);
604 msgcc.opt = htonl (options);
605 msgcc.h_port = ch->h_port;
606 msgcc.ctn = ch->ctn;
607 ch->state = CADET_CHANNEL_OPEN_SENT;
608 if (NULL != ch->last_control_qe)
609 GCT_send_cancel (ch->last_control_qe);
610 ch->last_control_qe = GCT_send (ch->t,
611 &msgcc.header,
612 &channel_open_sent_cb,
613 ch);
614 GNUNET_assert (NULL == ch->retry_control_task);
504} 615}
505 616
506 617
507/** 618/**
508 * Notify a client that the channel is no longer valid. 619 * Function called once and only once after a channel was bound
509 * 620 * to its tunnel via #GCT_add_channel() is ready for transmission.
510 * @param ch Channel that is destroyed. 621 * Note that this is only the case for channels that this peer
511 * @param local_only Should we avoid sending it to other peers? 622 * initiates, as for incoming channels we assume that they are
623 * ready for transmission immediately upon receiving the open
624 * message. Used to bootstrap the #GCT_send() process.
625 *
626 * @param ch the channel for which the tunnel is now ready
512 */ 627 */
513static void 628void
514send_destroy (struct CadetChannel *ch, int local_only) 629GCCH_tunnel_up (struct CadetChannel *ch)
515{ 630{
516 struct GNUNET_CADET_ChannelManageMessage msg; 631 GNUNET_assert (NULL == ch->retry_control_task);
517 632 LOG (GNUNET_ERROR_TYPE_DEBUG,
518 msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY); 633 "Tunnel up, sending CHANNEL_OPEN on %s now\n",
519 msg.header.size = htons (sizeof (msg)); 634 GCCH_2s (ch));
520 msg.ctn = ch->gid; 635 ch->retry_control_task
521 636 = GNUNET_SCHEDULER_add_now (&send_channel_open,
522 /* If root is not NULL, notify. 637 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} 638}
537 639
538 640
539/** 641/**
540 * Notify the destination client that a new incoming channel was created. 642 * Create a new channel.
541 * 643 *
542 * @param ch Channel that was created. 644 * @param owner local client owning the channel
645 * @param ccn local number of this channel at the @a owner
646 * @param destination peer to which we should build the channel
647 * @param port desired port at @a destination
648 * @param options options for the channel
649 * @return handle to the new channel
543 */ 650 */
544static void 651struct CadetChannel *
545send_client_create (struct CadetChannel *ch) 652GCCH_channel_local_new (struct CadetClient *owner,
653 struct GNUNET_CADET_ClientChannelNumber ccn,
654 struct CadetPeer *destination,
655 const struct GNUNET_HashCode *port,
656 uint32_t options)
546{ 657{
547 uint32_t opt; 658 struct CadetChannel *ch;
548 659 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 660
661 ccco = GNUNET_new (struct CadetChannelClient);
662 ccco->c = owner;
663 ccco->ccn = ccn;
664 ccco->client_ready = GNUNET_YES;
563 665
564/** 666 ch = GNUNET_new (struct CadetChannel);
565 * Send data to a client. 667 ch->mid_recv.mid = htonl (1); /* The OPEN_ACK counts as message 0! */
566 * 668 ch->nobuffer = (0 != (options & GNUNET_CADET_OPTION_NOBUFFER));
567 * If the client is ready, send directly, otherwise buffer while listening 669 ch->reliable = (0 != (options & GNUNET_CADET_OPTION_RELIABLE));
568 * for a local ACK. 670 ch->out_of_order = (0 != (options & GNUNET_CADET_OPTION_OUT_OF_ORDER));
569 * 671 ch->max_pending_messages = (ch->nobuffer) ? 1 : 4; /* FIXME: 4!? Do not hardcode! */
570 * @param ch Channel 672 ch->owner = ccco;
571 * @param msg Message. 673 ch->port = *port;
572 * @param fwd Is this a fwd (root->dest) message? 674 GCCH_hash_port (&ch->h_port,
573 */ 675 port,
574static void 676 GCP_get_id (destination));
575send_client_data (struct CadetChannel *ch, 677 if (0 == memcmp (&my_full_id,
576 const struct GNUNET_CADET_ChannelAppDataMessage *msg, 678 GCP_get_id (destination),
577 int fwd) 679 sizeof (struct GNUNET_PeerIdentity)))
578{ 680 {
579 if (fwd) 681 struct OpenPort *op;
580 { 682
581 if (ch->dest_rel->client_ready) 683 ch->is_loopback = GNUNET_YES;
684 op = GNUNET_CONTAINER_multihashmap_get (open_ports,
685 &ch->h_port);
686 if (NULL == op)
582 { 687 {
583 GML_send_data (ch->dest, msg, ch->lid_dest); 688 /* port closed, wait for it to possibly open */
584 ch->dest_rel->client_ready = GNUNET_NO; 689 ch->state = CADET_CHANNEL_LOOSE;
585 ch->dest_rel->mid_recv++; 690 (void) GNUNET_CONTAINER_multihashmap_put (loose_channels,
691 &ch->h_port,
692 ch,
693 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
694 LOG (GNUNET_ERROR_TYPE_DEBUG,
695 "Created loose incoming loopback channel to port %s\n",
696 GNUNET_h2s (&ch->port));
586 } 697 }
587 else 698 else
588 add_buffered_data (msg, ch->dest_rel); 699 {
700 GCCH_bind (ch,
701 op->c,
702 &op->port);
703 }
589 } 704 }
590 else 705 else
591 { 706 {
592 if (ch->root_rel->client_ready) 707 ch->t = GCP_get_tunnel (destination,
593 { 708 GNUNET_YES);
594 GML_send_data (ch->root, msg, ch->lid_root); 709 ch->retry_time = CADET_INITIAL_RETRANSMIT_TIME;
595 ch->root_rel->client_ready = GNUNET_NO; 710 ch->ctn = GCT_add_channel (ch->t,
596 ch->root_rel->mid_recv++; 711 ch);
597 }
598 else
599 add_buffered_data (msg, ch->root_rel);
600 } 712 }
713 GNUNET_STATISTICS_update (stats,
714 "# channels",
715 1,
716 GNUNET_NO);
717 LOG (GNUNET_ERROR_TYPE_DEBUG,
718 "Created channel to port %s at peer %s for %s using %s\n",
719 GNUNET_h2s (port),
720 GCP_2s (destination),
721 GSC_2s (owner),
722 (GNUNET_YES == ch->is_loopback) ? "loopback" : GCT_2s (ch->t));
723 return ch;
601} 724}
602 725
603 726
604/** 727/**
605 * Send a buffered message to the client, for in order delivery or 728 * We had an incoming channel to a port that is closed.
606 * as result of client ACK. 729 * It has not been opened for a while, drop it.
607 * 730 *
608 * @param ch Channel on which to empty the message buffer. 731 * @param cls the channel to drop
609 * @param c Client to send to.
610 * @param fwd Is this to send FWD data?.
611 */ 732 */
612static void 733static void
613send_client_buffered_data (struct CadetChannel *ch, 734timeout_closed_cb (void *cls)
614 struct CadetClient *c,
615 int fwd)
616{ 735{
617 struct CadetReliableMessage *copy; 736 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 737
628 copy = rel->head_recv; 738 ch->retry_control_task = NULL;
629 /* We never buffer channel management messages */ 739 LOG (GNUNET_ERROR_TYPE_DEBUG,
630 if (NULL != copy) 740 "Closing incoming channel to port %s from peer %s due to timeout\n",
631 { 741 GNUNET_h2s (&ch->port),
632 if (copy->mid == rel->mid_recv || GNUNET_NO == ch->reliable) 742 GCP_2s (GCT_get_destination (ch->t)));
633 { 743 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} 744}
664 745
665 746
666/** 747/**
667 * Allow a client to send more data. 748 * 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 * 749 *
671 * @param ch Channel. 750 * @param t tunnel to the remote peer
672 * @param fwd Is this a FWD ACK? (FWD ACKs are sent to root) 751 * @param ctn identifier of this channel in the tunnel
752 * @param h_port desired hash of local port
753 * @param options options for the channel
754 * @return handle to the new channel
673 */ 755 */
674static void 756struct CadetChannel *
675send_client_ack (struct CadetChannel *ch, int fwd) 757GCCH_channel_incoming_new (struct CadetTunnel *t,
758 struct GNUNET_CADET_ChannelTunnelNumber ctn,
759 const struct GNUNET_HashCode *h_port,
760 uint32_t options)
676{ 761{
677 struct CadetChannelReliability *rel = fwd ? ch->root_rel : ch->dest_rel; 762 struct CadetChannel *ch;
678 struct CadetClient *c = fwd ? ch->root : ch->dest; 763 struct OpenPort *op;
679
680 if (NULL == c)
681 {
682 GNUNET_break (GNUNET_NO != ch->destroy);
683 return;
684 }
685 LOG (GNUNET_ERROR_TYPE_DEBUG,
686 " sending %s ack to client on channel %s\n",
687 GC_f2s (fwd), GCCH_2s (ch));
688 764
689 if (NULL == rel) 765 ch = GNUNET_new (struct CadetChannel);
690 { 766 ch->h_port = *h_port;
691 GNUNET_break (0); 767 ch->t = t;
692 return; 768 ch->ctn = ctn;
769 ch->retry_time = CADET_INITIAL_RETRANSMIT_TIME;
770 ch->nobuffer = (0 != (options & GNUNET_CADET_OPTION_NOBUFFER));
771 ch->reliable = (0 != (options & GNUNET_CADET_OPTION_RELIABLE));
772 ch->out_of_order = (0 != (options & GNUNET_CADET_OPTION_OUT_OF_ORDER));
773 ch->max_pending_messages = (ch->nobuffer) ? 1 : 4; /* FIXME: 4!? Do not hardcode! */
774 GNUNET_STATISTICS_update (stats,
775 "# channels",
776 1,
777 GNUNET_NO);
778
779 op = GNUNET_CONTAINER_multihashmap_get (open_ports,
780 h_port);
781 if (NULL == op)
782 {
783 /* port closed, wait for it to possibly open */
784 ch->state = CADET_CHANNEL_LOOSE;
785 (void) GNUNET_CONTAINER_multihashmap_put (loose_channels,
786 &ch->h_port,
787 ch,
788 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
789 GNUNET_assert (NULL == ch->retry_control_task);
790 ch->retry_control_task
791 = GNUNET_SCHEDULER_add_delayed (TIMEOUT_CLOSED_PORT,
792 &timeout_closed_cb,
793 ch);
794 LOG (GNUNET_ERROR_TYPE_DEBUG,
795 "Created loose incoming channel to port %s from peer %s\n",
796 GNUNET_h2s (&ch->port),
797 GCP_2s (GCT_get_destination (ch->t)));
693 } 798 }
694 799 else
695 if (GNUNET_YES == rel->client_allowed)
696 { 800 {
697 LOG (GNUNET_ERROR_TYPE_DEBUG, " already allowed\n"); 801 GCCH_bind (ch,
698 return; 802 op->c,
803 &op->port);
699 } 804 }
700 rel->client_allowed = GNUNET_YES; 805 GNUNET_STATISTICS_update (stats,
701 806 "# channels",
702 GML_send_ack (c, fwd ? ch->lid_root : ch->lid_dest); 807 1,
808 GNUNET_NO);
809 return ch;
703} 810}
704 811
705 812
706/** 813/**
707 * Notify the root that the destination rejected the channel. 814 * Function called once the tunnel confirms that we sent the
815 * ACK message. Just remembers it was sent, we do not expect
816 * ACKs for ACKs ;-).
708 * 817 *
709 * @param ch Rejected channel. 818 * @param cls our `struct CadetChannel`.
819 * @param cid identifier of the connection within the tunnel, NULL
820 * if transmission failed
710 */ 821 */
711static void 822static void
712send_client_nack (struct CadetChannel *ch) 823send_ack_cb (void *cls,
824 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
713{ 825{
714 if (NULL == ch->root) 826 struct CadetChannel *ch = cls;
715 { 827
716 GNUNET_break (0); 828 GNUNET_assert (NULL != ch->last_control_qe);
717 return; 829 ch->last_control_qe = NULL;
718 }
719 GML_send_channel_nack (ch->root, ch->lid_root);
720} 830}
721 831
722 832
723/** 833/**
724 * We haven't received an ACK after a certain time: restransmit the message. 834 * Compute and send the current #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK to the other peer.
725 * 835 *
726 * @param cls Closure (CadetChannelReliability with the message to restransmit) 836 * @param ch channel to send the #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK for
727 */ 837 */
728static void 838static void
729channel_retransmit_message (void *cls) 839send_channel_data_ack (struct CadetChannel *ch)
730{ 840{
731 struct CadetChannelReliability *rel = cls; 841 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 842
752 GCCH_send_prebuilt_message (&payload->header, ch, fwd, copy); 843 if (GNUNET_NO == ch->reliable)
753 GNUNET_STATISTICS_update (stats, "# data retransmitted", 1, GNUNET_NO); 844 return; /* no ACKs */
845 msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK);
846 msg.header.size = htons (sizeof (msg));
847 msg.ctn = ch->ctn;
848 msg.mid.mid = htonl (ntohl (ch->mid_recv.mid));
849 msg.futures = GNUNET_htonll (ch->mid_futures);
850 LOG (GNUNET_ERROR_TYPE_DEBUG,
851 "Sending DATA_ACK %u:%llX via %s\n",
852 (unsigned int) ntohl (msg.mid.mid),
853 (unsigned long long) ch->mid_futures,
854 GCCH_2s (ch));
855 if (NULL != ch->last_control_qe)
856 GCT_send_cancel (ch->last_control_qe);
857 ch->last_control_qe = GCT_send (ch->t,
858 &msg.header,
859 &send_ack_cb,
860 ch);
754} 861}
755 862
756 863
757/** 864/**
758 * We haven't received an Channel ACK after a certain time: resend the CREATE. 865 * Send our initial #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK to the client confirming that the
866 * connection is up.
759 * 867 *
760 * @param cls Closure (CadetChannelReliability of the channel to recreate) 868 * @param cls the `struct CadetChannel`
761 */ 869 */
762static void 870static void
763channel_recreate (void *cls) 871send_open_ack (void *cls)
764{ 872{
765 struct CadetChannelReliability *rel = cls; 873 struct CadetChannel *ch = cls;
874 struct GNUNET_CADET_ChannelOpenAckMessage msg;
766 875
767 rel->retry_task = NULL; 876 ch->retry_control_task = NULL;
768 LOG (GNUNET_ERROR_TYPE_DEBUG, "RE-CREATE\n"); 877 LOG (GNUNET_ERROR_TYPE_DEBUG,
769 GNUNET_STATISTICS_update (stats, 878 "Sending CHANNEL_OPEN_ACK on %s\n",
770 "# data retransmitted", 1, GNUNET_NO); 879 GCCH_2s (ch));
771 880 msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK);
772 if (rel == rel->ch->root_rel) 881 msg.header.size = htons (sizeof (msg));
773 { 882 msg.reserved = htonl (0);
774 send_create (rel->ch); 883 msg.ctn = ch->ctn;
775 } 884 msg.port = ch->port;
776 else if (rel == rel->ch->dest_rel) 885 if (NULL != ch->last_control_qe)
777 { 886 GCT_send_cancel (ch->last_control_qe);
778 send_ack (rel->ch, GNUNET_YES); 887 ch->last_control_qe = GCT_send (ch->t,
779 } 888 &msg.header,
780 else 889 &send_ack_cb,
781 { 890 ch);
782 GNUNET_break (0);
783 }
784} 891}
785 892
786 893
787/** 894/**
788 * Message has been sent: start retransmission timer. 895 * We got a #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN message again for
896 * this channel. If the binding was successful, (re)transmit the
897 * #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK.
789 * 898 *
790 * @param cls Closure (queue structure). 899 * @param ch channel that got the duplicate open
791 * @param t Tunnel. 900 * @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 */ 901 */
796static void 902void
797ch_message_sent (void *cls, 903GCCH_handle_duplicate_open (struct CadetChannel *ch,
798 struct CadetTunnel *t, 904 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti)
799 struct CadetTunnelQueue *q,
800 uint16_t type, size_t size)
801{ 905{
802 struct CadetChannelQueue *chq = cls; 906 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 { 907 {
811 case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA: 908 LOG (GNUNET_ERROR_TYPE_DEBUG,
812 LOG (GNUNET_ERROR_TYPE_DEBUG, "data MID %u sent\n", copy->mid); 909 "Ignoring duplicate CHANNEL_OPEN on %s: port is closed\n",
813 GNUNET_assert (chq == copy->chq); 910 GCCH_2s (ch));
814 copy->timestamp = GNUNET_TIME_absolute_get (); 911 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 } 912 }
872 913 if (NULL != ch->retry_control_task)
873 GNUNET_free (chq); 914 {
915 LOG (GNUNET_ERROR_TYPE_DEBUG,
916 "Ignoring duplicate CHANNEL_OPEN on %s: control message is pending\n",
917 GCCH_2s (ch));
918 return;
919 }
920 LOG (GNUNET_ERROR_TYPE_DEBUG,
921 "Retransmitting CHANNEL_OPEN_ACK on %s\n",
922 GCCH_2s (ch));
923 ch->retry_control_task
924 = GNUNET_SCHEDULER_add_now (&send_open_ack,
925 ch);
874} 926}
875 927
876 928
877/** 929/**
878 * send a channel create message. 930 * Send a #GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK to the client to solicit more messages.
879 * 931 *
880 * @param ch Channel for which to send. 932 * @param ch channel the ack is for
933 * @param to_owner #GNUNET_YES to send to owner,
934 * #GNUNET_NO to send to dest
881 */ 935 */
882static void 936static void
883send_create (struct CadetChannel *ch) 937send_ack_to_client (struct CadetChannel *ch,
938 int to_owner)
884{ 939{
885 struct GNUNET_CADET_ChannelOpenMessage msgcc; 940 struct GNUNET_MQ_Envelope *env;
941 struct GNUNET_CADET_LocalAck *ack;
942 struct CadetChannelClient *ccc;
886 943
887 msgcc.header.size = htons (sizeof (msgcc)); 944 ccc = (GNUNET_YES == to_owner) ? ch->owner : ch->dest;
888 msgcc.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN); 945 if (NULL == ccc)
889 msgcc.ctn = ch->gid; 946 {
890 msgcc.port = ch->port; 947 /* This can happen if we are just getting ACKs after
891 msgcc.opt = htonl (channel_get_options (ch)); 948 our local client already disconnected. */
892 949 GNUNET_assert (GNUNET_YES == ch->destroy);
893 GCCH_send_prebuilt_message (&msgcc.header, ch, GNUNET_YES, NULL); 950 return;
951 }
952 env = GNUNET_MQ_msg (ack,
953 GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK);
954 ack->ccn = ccc->ccn;
955 LOG (GNUNET_ERROR_TYPE_DEBUG,
956 "Sending CADET_LOCAL_ACK to %s (%s) at ccn %X (%u/%u pending)\n",
957 GSC_2s (ccc->c),
958 (GNUNET_YES == to_owner) ? "owner" : "dest",
959 ntohl (ack->ccn.channel_of_client),
960 ch->pending_messages,
961 ch->max_pending_messages);
962 GSC_send_to_client (ccc->c,
963 env);
894} 964}
895 965
896 966
897/** 967/**
898 * Confirm we got a channel create or FWD ack. 968 * A client is bound to the port that we have a channel
969 * open to. Send the acknowledgement for the connection
970 * request and establish the link with the client.
899 * 971 *
900 * @param ch The channel to confirm. 972 * @param ch open incoming channel
901 * @param fwd Should we send a FWD ACK? (going dest->root) 973 * @param c client listening on the respective @a port
974 * @param port the port @a is listening on
902 */ 975 */
903static void 976void
904send_ack (struct CadetChannel *ch, int fwd) 977GCCH_bind (struct CadetChannel *ch,
978 struct CadetClient *c,
979 const struct GNUNET_HashCode *port)
905{ 980{
906 struct GNUNET_CADET_ChannelManageMessage msg; 981 uint32_t options;
982 struct CadetChannelClient *cccd;
907 983
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, 984 LOG (GNUNET_ERROR_TYPE_DEBUG,
911 " sending channel %s ack for channel %s\n", 985 "Binding %s from %s to port %s of %s\n",
912 GC_f2s (fwd), GCCH_2s (ch)); 986 GCCH_2s (ch),
913 987 GCT_2s (ch->t),
914 msg.ctn =ch->gid; 988 GNUNET_h2s (&ch->port),
915 GCCH_send_prebuilt_message (&msg.header, ch, !fwd, NULL); 989 GSC_2s (c));
990 if (NULL != ch->retry_control_task)
991 {
992 /* there might be a timeout task here */
993 GNUNET_SCHEDULER_cancel (ch->retry_control_task);
994 ch->retry_control_task = NULL;
995 }
996 options = 0;
997 if (ch->nobuffer)
998 options |= GNUNET_CADET_OPTION_NOBUFFER;
999 if (ch->reliable)
1000 options |= GNUNET_CADET_OPTION_RELIABLE;
1001 if (ch->out_of_order)
1002 options |= GNUNET_CADET_OPTION_OUT_OF_ORDER;
1003 cccd = GNUNET_new (struct CadetChannelClient);
1004 GNUNET_assert (NULL == ch->dest);
1005 ch->dest = cccd;
1006 ch->port = *port;
1007 cccd->c = c;
1008 cccd->client_ready = GNUNET_YES;
1009 cccd->ccn = GSC_bind (c,
1010 ch,
1011 (GNUNET_YES == ch->is_loopback)
1012 ? GCP_get (&my_full_id,
1013 GNUNET_YES)
1014 : GCT_get_destination (ch->t),
1015 port,
1016 options);
1017 GNUNET_assert (ntohl (cccd->ccn.channel_of_client) <
1018 GNUNET_CADET_LOCAL_CHANNEL_ID_CLI);
1019 ch->mid_recv.mid = htonl (1); /* The OPEN counts as message 0! */
1020 if (GNUNET_YES == ch->is_loopback)
1021 {
1022 ch->state = CADET_CHANNEL_OPEN_SENT;
1023 GCCH_handle_channel_open_ack (ch,
1024 NULL,
1025 port);
1026 }
1027 else
1028 {
1029 /* notify other peer that we accepted the connection */
1030 ch->state = CADET_CHANNEL_READY;
1031 ch->retry_control_task
1032 = GNUNET_SCHEDULER_add_now (&send_open_ack,
1033 ch);
1034 }
1035 /* give client it's initial supply of ACKs */
1036 GNUNET_assert (ntohl (cccd->ccn.channel_of_client) <
1037 GNUNET_CADET_LOCAL_CHANNEL_ID_CLI);
1038 for (unsigned int i=0;i<ch->max_pending_messages;i++)
1039 send_ack_to_client (ch,
1040 GNUNET_NO);
916} 1041}
917 1042
918 1043
919/** 1044/**
920 * Send a message and don't keep any info about it: we won't need to cancel it 1045 * One of our clients has disconnected, tell the other one that we
921 * or resend it. 1046 * are finished. Done asynchronously to avoid concurrent modification
1047 * issues if this is the same client.
922 * 1048 *
923 * @param msg Header of the message to fire away. 1049 * @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 */ 1050 */
927static void 1051static void
928fire_and_forget (const struct GNUNET_MessageHeader *msg, 1052signal_remote_destroy_cb (void *cls)
929 struct CadetChannel *ch,
930 int force)
931{ 1053{
932 GNUNET_break (NULL == 1054 struct CadetChannel *ch = cls;
933 GCT_send_prebuilt_message (msg, ch->t, NULL, 1055 struct CadetChannelClient *ccc;
934 force, NULL, NULL)); 1056
1057 /* Find which end is left... */
1058 ch->retry_control_task = NULL;
1059 ccc = (NULL != ch->owner) ? ch->owner : ch->dest;
1060 GSC_handle_remote_channel_destroy (ccc->c,
1061 ccc->ccn,
1062 ch);
1063 channel_destroy (ch);
935} 1064}
936 1065
937 1066
938/** 1067/**
939 * Notify that a channel create didn't succeed. 1068 * Destroy locally created channel. Called by the local client, so no
1069 * need to tell the client.
940 * 1070 *
941 * @param ch The channel to reject. 1071 * @param ch channel to destroy
1072 * @param c client that caused the destruction
1073 * @param ccn client number of the client @a c
942 */ 1074 */
943static void 1075void
944send_nack (struct CadetChannel *ch) 1076GCCH_channel_local_destroy (struct CadetChannel *ch,
1077 struct CadetClient *c,
1078 struct GNUNET_CADET_ClientChannelNumber ccn)
945{ 1079{
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, 1080 LOG (GNUNET_ERROR_TYPE_DEBUG,
951 " sending channel NACK for channel %s\n", 1081 "%s asks for destruction of %s\n",
1082 GSC_2s (c),
952 GCCH_2s (ch)); 1083 GCCH_2s (ch));
1084 GNUNET_assert (NULL != c);
1085 if ( (NULL != ch->owner) &&
1086 (c == ch->owner->c) &&
1087 (ccn.channel_of_client == ch->owner->ccn.channel_of_client) )
1088 {
1089 free_channel_client (ch->owner);
1090 ch->owner = NULL;
1091 }
1092 else if ( (NULL != ch->dest) &&
1093 (c == ch->dest->c) &&
1094 (ccn.channel_of_client == ch->dest->ccn.channel_of_client) )
1095 {
1096 free_channel_client (ch->dest);
1097 ch->dest = NULL;
1098 }
1099 else
1100 {
1101 GNUNET_assert (0);
1102 }
953 1103
954 msg.ctn = ch->gid; 1104 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 { 1105 {
977 next = copy->next; 1106 /* other end already destroyed, with the local client gone, no need
978 GNUNET_CONTAINER_DLL_remove (rel->head_recv, rel->tail_recv, copy); 1107 to finish transmissions, just destroy immediately. */
979 LOG (GNUNET_ERROR_TYPE_DEBUG, " COPYFREE ALL RECV %p\n", copy); 1108 channel_destroy (ch);
980 GNUNET_break (NULL == copy->chq); 1109 return;
981 GNUNET_free (copy);
982 } 1110 }
983 for (copy = rel->head_sent; NULL != copy; copy = next) 1111 if ( (NULL != ch->head_sent) &&
1112 ( (NULL != ch->owner) ||
1113 (NULL != ch->dest) ) )
984 { 1114 {
985 next = copy->next; 1115 /* Wait for other end to destroy us as well,
986 GNUNET_CONTAINER_DLL_remove (rel->head_sent, rel->tail_sent, copy); 1116 and otherwise allow send queue to be transmitted first */
987 LOG (GNUNET_ERROR_TYPE_DEBUG, " COPYFREE ALL SEND %p\n", copy); 1117 ch->destroy = GNUNET_YES;
988 if (NULL != copy->chq) 1118 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 } 1119 }
1003 if (NULL != rel->uniq && NULL != rel->uniq->tq) 1120 if ( (GNUNET_YES == ch->is_loopback) &&
1121 ( (NULL != ch->owner) ||
1122 (NULL != ch->dest) ) )
1004 { 1123 {
1005 GCT_cancel (rel->uniq->tq); 1124 if (NULL != ch->retry_control_task)
1006 /* ch_message_sent is called freeing uniq */ 1125 GNUNET_SCHEDULER_cancel (ch->retry_control_task);
1126 ch->retry_control_task
1127 = GNUNET_SCHEDULER_add_now (&signal_remote_destroy_cb,
1128 ch);
1129 return;
1007 } 1130 }
1008 if (NULL != rel->retry_task) 1131 if (GNUNET_NO == ch->is_loopback)
1009 { 1132 {
1010 GNUNET_SCHEDULER_cancel (rel->retry_task); 1133 /* If the we ever sent the CHANNEL_CREATE, we need to send a destroy message. */
1011 rel->retry_task = NULL; 1134 switch (ch->state)
1135 {
1136 case CADET_CHANNEL_NEW:
1137 /* We gave up on a channel that we created as a client to a remote
1138 target, but that never went anywhere. Nothing to do here. */
1139 break;
1140 case CADET_CHANNEL_LOOSE:
1141 GSC_drop_loose_channel (&ch->h_port,
1142 ch);
1143 break;
1144 default:
1145 GCT_send_channel_destroy (ch->t,
1146 ch->ctn);
1147 }
1012 } 1148 }
1013 GNUNET_free (rel); 1149 /* Nothing left to do, just finish destruction */
1150 channel_destroy (ch);
1014} 1151}
1015 1152
1016 1153
1017/** 1154/**
1018 * Mark future messages as ACK'd. 1155 * We got an acknowledgement for the creation of the channel
1156 * (the port is open on the other side). Verify that the
1157 * other end really has the right port, and begin transmissions.
1019 * 1158 *
1020 * @param rel Reliability data. 1159 * @param ch channel to destroy
1021 * @param msg DataACK message with a bitfield of future ACK'd messages. 1160 * @param cti identifier of the connection that delivered the message
1022 * 1161 * @param port port number (needed to verify receiver knows the port)
1023 * @return How many messages have been freed.
1024 */ 1162 */
1025static unsigned int 1163void
1026channel_rel_free_sent (struct CadetChannelReliability *rel, 1164GCCH_handle_channel_open_ack (struct CadetChannel *ch,
1027 const struct GNUNET_CADET_ChannelDataAckMessage *msg) 1165 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
1166 const struct GNUNET_HashCode *port)
1028{ 1167{
1029 struct CadetReliableMessage *copy; 1168 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 { 1169 {
1046 LOG (GNUNET_ERROR_TYPE_DEBUG, " trying bit %u (mid %u)\n", i, mid + i + 1); 1170 case CADET_CHANNEL_NEW:
1047 mask = 0x1LL << i; 1171 /* this should be impossible */
1048 if (0 == (bitfield & mask)) 1172 GNUNET_break (0);
1049 continue; 1173 break;
1050 1174 case CADET_CHANNEL_LOOSE:
1051 LOG (GNUNET_ERROR_TYPE_DEBUG, " set!\n"); 1175 /* This makes no sense. */
1052 /* Bit was set, clear the bit from the bitfield */ 1176 GNUNET_break_op (0);
1053 bitfield &= ~mask; 1177 break;
1054 1178 case CADET_CHANNEL_OPEN_SENT:
1055 /* The i-th bit was set. Do we have that copy? */ 1179 if (NULL == ch->owner)
1056 /* Skip copies with mid < target */ 1180 {
1057 target = mid + i + 1; 1181 /* We're not the owner, wrong direction! */
1058 LOG (GNUNET_ERROR_TYPE_DEBUG, " target %u\n", target); 1182 GNUNET_break_op (0);
1059 while (NULL != copy && GC_is_pid_bigger (target, copy->mid)) 1183 return;
1060 copy = copy->next; 1184 }
1061 1185 if (0 != memcmp (&ch->port,
1062 /* Did we run out of copies? (previously freed, it's ok) */ 1186 port,
1063 if (NULL == copy) 1187 sizeof (struct GNUNET_HashCode)))
1064 { 1188 {
1065 LOG (GNUNET_ERROR_TYPE_DEBUG, "run out of copies...\n"); 1189 /* Other peer failed to provide the right port,
1066 return r; 1190 refuse connection. */
1191 GNUNET_break_op (0);
1192 return;
1067 } 1193 }
1068 1194 LOG (GNUNET_ERROR_TYPE_DEBUG,
1069 /* Did we overshoot the target? (previously freed, it's ok) */ 1195 "Received CHANNEL_OPEN_ACK for waiting %s, entering READY state\n",
1070 if (GC_is_pid_bigger (copy->mid, target)) 1196 GCCH_2s (ch));
1197 if (NULL != ch->retry_control_task) /* can be NULL if ch->is_loopback */
1071 { 1198 {
1072 LOG (GNUNET_ERROR_TYPE_DEBUG, " next copy %u\n", copy->mid); 1199 GNUNET_SCHEDULER_cancel (ch->retry_control_task);
1073 i += copy->mid - target - 1; /* MID: 90, t = 85, i += 4 (i++ later) */ 1200 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 } 1201 }
1078 1202 ch->state = CADET_CHANNEL_READY;
1079 /* Now copy->mid == target, free it */ 1203 /* On first connect, send client as many ACKs as we allow messages
1080 next = copy->next; 1204 to be buffered! */
1081 GNUNET_break (GNUNET_YES != rel_message_free (copy, GNUNET_YES)); 1205 for (unsigned int i=0;i<ch->max_pending_messages;i++)
1082 r++; 1206 send_ack_to_client (ch,
1083 copy = next; 1207 GNUNET_YES);
1208 break;
1209 case CADET_CHANNEL_READY:
1210 /* duplicate ACK, maybe we retried the CREATE. Ignore. */
1211 LOG (GNUNET_ERROR_TYPE_DEBUG,
1212 "Received duplicate channel OPEN_ACK for %s\n",
1213 GCCH_2s (ch));
1214 GNUNET_STATISTICS_update (stats,
1215 "# duplicate CREATE_ACKs",
1216 1,
1217 GNUNET_NO);
1218 break;
1084 } 1219 }
1085 LOG (GNUNET_ERROR_TYPE_DEBUG, "free_sent_reliable END\n");
1086 return r;
1087} 1220}
1088 1221
1089 1222
1090/** 1223/**
1091 * Destroy a reliable message after it has been acknowledged, either by 1224 * 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 *
1095 * @param copy Message that is no longer needed: remote peer got it.
1096 * @param update_time Is the timing information relevant?
1097 * If this message is ACK in a batch the timing information
1098 * is skewed by the retransmission, count only for the
1099 * retransmitted message.
1100 * 1225 *
1101 * @return #GNUNET_YES if channel was destroyed as a result of the call, 1226 * @param cls closure, to a flag where we indicate duplicate packets
1102 * #GNUNET_NO otherwise. 1227 * @param m1 a message of to sort
1228 * @param m2 another message to sort
1229 * @return #GNUNET_YES if @e1 < @e2, otherwise #GNUNET_NO
1103 */ 1230 */
1104static int 1231static int
1105rel_message_free (struct CadetReliableMessage *copy, int update_time) 1232is_before (void *cls,
1233 struct CadetOutOfOrderMessage *m1,
1234 struct CadetOutOfOrderMessage *m2)
1106{ 1235{
1107 struct CadetChannelReliability *rel; 1236 int *duplicate = cls;
1108 struct GNUNET_TIME_Relative time; 1237 uint32_t v1 = ntohl (m1->mid.mid);
1238 uint32_t v2 = ntohl (m2->mid.mid);
1239 uint32_t delta;
1109 1240
1110 rel = copy->rel; 1241 delta = v2 - v1;
1111 LOG (GNUNET_ERROR_TYPE_DEBUG, "Freeing %u\n", copy->mid); 1242 if (0 == delta)
1112 if (GNUNET_YES == update_time) 1243 *duplicate = GNUNET_YES;
1244 if (delta > (uint32_t) INT_MAX)
1113 { 1245 {
1114 time = GNUNET_TIME_absolute_get_duration (copy->timestamp); 1246 /* in overflow range, we can safely assume we wrapped around */
1115 if (0 == rel->expected_delay.rel_value_us) 1247 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 } 1248 }
1130 else 1249 else
1131 { 1250 {
1132 LOG (GNUNET_ERROR_TYPE_DEBUG, "batch free, ignoring timing\n"); 1251 /* 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; 1252 return GNUNET_YES;
1149 } 1253 }
1150 return GNUNET_NO;
1151} 1254}
1152 1255
1153 1256
1154/** 1257/**
1155 * Channel was ACK'd by remote peer, mark as ready and cancel retransmission. 1258 * We got payload data for a channel. Pass it on to the client
1259 * and send an ACK to the other end (once flow control allows it!)
1156 * 1260 *
1157 * @param ch Channel to mark as ready. 1261 * @param ch channel that got data
1158 * @param fwd Was the ACK message a FWD ACK? (dest->root, SYNACK) 1262 * @param cti identifier of the connection that delivered the message
1263 * @param msg message that was received
1159 */ 1264 */
1160static void 1265void
1161channel_confirm (struct CadetChannel *ch, int fwd) 1266GCCH_handle_channel_plaintext_data (struct CadetChannel *ch,
1267 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
1268 const struct GNUNET_CADET_ChannelAppDataMessage *msg)
1162{ 1269{
1163 struct CadetChannelReliability *rel; 1270 struct GNUNET_MQ_Envelope *env;
1164 enum CadetChannelState oldstate; 1271 struct GNUNET_CADET_LocalData *ld;
1165 1272 struct CadetChannelClient *ccc;
1166 rel = fwd ? ch->root_rel : ch->dest_rel; 1273 size_t payload_size;
1167 if (NULL == rel) 1274 struct CadetOutOfOrderMessage *com;
1275 int duplicate;
1276 uint32_t mid_min;
1277 uint32_t mid_max;
1278 uint32_t mid_msg;
1279 uint32_t delta;
1280
1281 GNUNET_assert (GNUNET_NO == ch->is_loopback);
1282 if ( (GNUNET_YES == ch->destroy) &&
1283 (NULL == ch->owner) &&
1284 (NULL == ch->dest) )
1285 {
1286 /* This client is gone, but we still have messages to send to
1287 the other end (which is why @a ch is not yet dead). However,
1288 we cannot pass messages to our client anymore. */
1289 LOG (GNUNET_ERROR_TYPE_DEBUG,
1290 "Dropping incoming payload on %s as this end is already closed\n",
1291 GCCH_2s (ch));
1292 /* send back DESTROY notification to stop further retransmissions! */
1293 GCT_send_channel_destroy (ch->t,
1294 ch->ctn);
1295 return;
1296 }
1297 payload_size = ntohs (msg->header.size) - sizeof (*msg);
1298 env = GNUNET_MQ_msg_extra (ld,
1299 payload_size,
1300 GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA);
1301 ld->ccn = (NULL == ch->dest) ? ch->owner->ccn : ch->dest->ccn;
1302 GNUNET_memcpy (&ld[1],
1303 &msg[1],
1304 payload_size);
1305 ccc = (NULL != ch->owner) ? ch->owner : ch->dest;
1306 if ( (GNUNET_YES == ccc->client_ready) &&
1307 ( (GNUNET_YES == ch->out_of_order) ||
1308 (msg->mid.mid == ch->mid_recv.mid) ) )
1168 { 1309 {
1169 GNUNET_break (GNUNET_NO != ch->destroy); 1310 LOG (GNUNET_ERROR_TYPE_DEBUG,
1311 "Giving %u bytes of payload with MID %u from %s to client %s\n",
1312 (unsigned int) payload_size,
1313 ntohl (msg->mid.mid),
1314 GCCH_2s (ch),
1315 GSC_2s (ccc->c));
1316 ccc->client_ready = GNUNET_NO;
1317 GSC_send_to_client (ccc->c,
1318 env);
1319 ch->mid_recv.mid = htonl (1 + ntohl (ch->mid_recv.mid));
1320 ch->mid_futures >>= 1;
1321 send_channel_data_ack (ch);
1170 return; 1322 return;
1171 } 1323 }
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 1324
1177 if (CADET_CHANNEL_READY != oldstate || GNUNET_YES == is_loopback (ch)) 1325 if (GNUNET_YES == ch->reliable)
1178 { 1326 {
1179 rel->client_ready = GNUNET_YES; 1327 /* check if message ought to be dropped because it is ancient/too distant/duplicate */
1180 rel->expected_delay = rel->retry_timer; 1328 mid_min = ntohl (ch->mid_recv.mid);
1181 LOG (GNUNET_ERROR_TYPE_DEBUG, " confirm retry timer %s\n", 1329 mid_max = mid_min + ch->max_pending_messages;
1182 GNUNET_STRINGS_relative_time_to_string (rel->retry_timer, GNUNET_NO)); 1330 mid_msg = ntohl (msg->mid.mid);
1183 if (GCT_get_connections_buffer (ch->t) > 0 || GCT_is_loopback (ch->t)) 1331 if ( ( (uint32_t) (mid_msg - mid_min) > ch->max_pending_messages) ||
1184 send_client_ack (ch, fwd); 1332 ( (uint32_t) (mid_max - mid_msg) > ch->max_pending_messages) )
1185
1186 if (NULL != rel->retry_task)
1187 { 1333 {
1188 GNUNET_SCHEDULER_cancel (rel->retry_task); 1334 LOG (GNUNET_ERROR_TYPE_DEBUG,
1189 rel->retry_task = NULL; 1335 "%s at %u drops ancient or far-future message %u\n",
1190 } 1336 GCCH_2s (ch),
1191 else if (NULL != rel->uniq) 1337 (unsigned int) mid_min,
1192 { 1338 ntohl (msg->mid.mid));
1193 GCT_cancel (rel->uniq->tq); 1339
1194 /* ch_message_sent will free and NULL uniq */ 1340 GNUNET_STATISTICS_update (stats,
1341 "# duplicate DATA (ancient or future)",
1342 1,
1343 GNUNET_NO);
1344 GNUNET_MQ_discard (env);
1345 send_channel_data_ack (ch);
1346 return;
1195 } 1347 }
1196 else if (GNUNET_NO == is_loopback (ch)) 1348 /* mark bit for future ACKs */
1349 delta = mid_msg - mid_min - 1; /* overflow/underflow are OK here */
1350 if (delta < 64)
1197 { 1351 {
1198 /* We SHOULD have been trying to retransmit this! */ 1352 if (0 != (ch->mid_futures & (1LLU << delta)))
1199 GNUNET_break (0); 1353 {
1354 /* Duplicate within the queue, drop also */
1355 LOG (GNUNET_ERROR_TYPE_DEBUG,
1356 "Duplicate payload of %u bytes on %s (mid %u) dropped\n",
1357 (unsigned int) payload_size,
1358 GCCH_2s (ch),
1359 ntohl (msg->mid.mid));
1360 GNUNET_STATISTICS_update (stats,
1361 "# duplicate DATA",
1362 1,
1363 GNUNET_NO);
1364 GNUNET_MQ_discard (env);
1365 send_channel_data_ack (ch);
1366 return;
1367 }
1368 ch->mid_futures |= (1LLU << delta);
1369 LOG (GNUNET_ERROR_TYPE_DEBUG,
1370 "Marked bit %llX for mid %u (base: %u); now: %llX\n",
1371 (1LLU << delta),
1372 mid_msg,
1373 mid_min,
1374 ch->mid_futures);
1200 } 1375 }
1201 } 1376 }
1202 1377 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 { 1378 {
1303 case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA: 1379 /* Channel is unreliable, so we do not ACK. But we also cannot
1304 /* Don't send hop ACK, wait for client to ACK */ 1380 allow buffering everything, so check if we have space... */
1305 LOG (GNUNET_ERROR_TYPE_DEBUG, "SEND loopback %u (%u)\n", 1381 if (ccc->num_recv >= ch->max_pending_messages)
1306 ntohl (((struct GNUNET_CADET_ChannelAppDataMessage *) msgh)->mid), ntohs (msgh->size)); 1382 {
1307 GCCH_handle_data (ch, (struct GNUNET_CADET_ChannelAppDataMessage *) msgh, fwd); 1383 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 1384
1336 default: 1385 /* Yep, need to drop. Drop the oldest message in
1337 GNUNET_break_op (0); 1386 the buffer. */
1338 LOG (GNUNET_ERROR_TYPE_DEBUG, 1387 LOG (GNUNET_ERROR_TYPE_DEBUG,
1339 "end-to-end message not known (%u)\n", 1388 "Queue full due slow client on %s, dropping oldest message\n",
1340 ntohs (msgh->type)); 1389 GCCH_2s (ch));
1390 GNUNET_STATISTICS_update (stats,
1391 "# messages dropped due to slow client",
1392 1,
1393 GNUNET_NO);
1394 drop = ccc->head_recv;
1395 GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
1396 ccc->tail_recv,
1397 drop);
1398 ccc->num_recv--;
1399 GNUNET_MQ_discard (drop->env);
1400 GNUNET_free (drop);
1401 }
1341 } 1402 }
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 1403
1361 if (NULL == ch) 1404 /* Insert message into sorted out-of-order queue */
1405 com = GNUNET_new (struct CadetOutOfOrderMessage);
1406 com->mid = msg->mid;
1407 com->env = env;
1408 duplicate = GNUNET_NO;
1409 GNUNET_CONTAINER_DLL_insert_sorted (struct CadetOutOfOrderMessage,
1410 is_before,
1411 &duplicate,
1412 ccc->head_recv,
1413 ccc->tail_recv,
1414 com);
1415 ccc->num_recv++;
1416 if (GNUNET_YES == duplicate)
1417 {
1418 /* Duplicate within the queue, drop also (this is not covered by
1419 the case above if "delta" >= 64, which could be the case if
1420 max_pending_messages is also >= 64 or if our client is unready
1421 and we are seeing retransmissions of the message our client is
1422 blocked on. */
1423 LOG (GNUNET_ERROR_TYPE_DEBUG,
1424 "Duplicate payload of %u bytes on %s (mid %u) dropped\n",
1425 (unsigned int) payload_size,
1426 GCCH_2s (ch),
1427 ntohl (msg->mid.mid));
1428 GNUNET_STATISTICS_update (stats,
1429 "# duplicate DATA",
1430 1,
1431 GNUNET_NO);
1432 GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
1433 ccc->tail_recv,
1434 com);
1435 ccc->num_recv--;
1436 GNUNET_MQ_discard (com->env);
1437 GNUNET_free (com);
1438 send_channel_data_ack (ch);
1362 return; 1439 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 } 1440 }
1376 1441 LOG (GNUNET_ERROR_TYPE_DEBUG,
1377 c = ch->dest; 1442 "Queued %s payload of %u bytes on %s-%X(%p) (mid %u, need %u first)\n",
1378 if (NULL != c) 1443 (GNUNET_YES == ccc->client_ready)
1379 { 1444 ? "out-of-order"
1380 GML_channel_remove (c, ch->lid_dest, ch); 1445 : "client-not-ready",
1381 } 1446 (unsigned int) payload_size,
1382 1447 GCCH_2s (ch),
1383 channel_rel_free_all (ch->root_rel); 1448 ntohl (ccc->ccn.channel_of_client),
1384 channel_rel_free_all (ch->dest_rel); 1449 ccc,
1385 1450 ntohl (msg->mid.mid),
1386 t = ch->t; 1451 ntohl (ch->mid_recv.mid));
1387 GCT_remove_channel (t, ch); 1452 /* NOTE: this ACK we _could_ skip, as the packet is out-of-order and
1388 GNUNET_STATISTICS_update (stats, "# channels", -1, GNUNET_NO); 1453 the sender may already be transmitting the previous one. Needs
1389 1454 experimental evaluation to see if/when this ACK helps or
1390 GNUNET_free (ch); 1455 hurts. (We might even want another option.) */
1391 GCT_destroy_if_empty (t); 1456 send_channel_data_ack (ch);
1392}
1393
1394
1395/**
1396 * Get the channel's public ID.
1397 *
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} 1457}
1478 1458
1479 1459
1480/** 1460/**
1481 * Is the root client for this channel on this peer? 1461 * Function called once the tunnel has sent one of our messages.
1482 * 1462 * If the message is unreliable, simply frees the `crm`. If the
1483 * @param ch Channel. 1463 * message was reliable, calculate retransmission time and
1484 * @param fwd Is this for fwd traffic? 1464 * wait for ACK (or retransmit).
1485 * 1465 *
1486 * @return #GNUNET_YES in case it is. 1466 * @param cls the `struct CadetReliableMessage` that was sent
1467 * @param cid identifier of the connection within the tunnel, NULL
1468 * if transmission failed
1487 */ 1469 */
1488int 1470static void
1489GCCH_is_origin (struct CadetChannel *ch, int fwd) 1471data_sent_cb (void *cls,
1490{ 1472 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid);
1491 struct CadetClient *c;
1492
1493 c = fwd ? ch->root : ch->dest;
1494 return NULL != c;
1495}
1496 1473
1497 1474
1498/** 1475/**
1499 * Is the destination client for this channel on this peer? 1476 * We need to retry a transmission, the last one took too long to
1500 * 1477 * be acknowledged.
1501 * @param ch Channel.
1502 * @param fwd Is this for fwd traffic?
1503 * 1478 *
1504 * @return #GNUNET_YES in case it is. 1479 * @param cls the `struct CadetChannel` where we need to retransmit
1505 */ 1480 */
1506int 1481static void
1507GCCH_is_terminal (struct CadetChannel *ch, int fwd) 1482retry_transmission (void *cls)
1508{ 1483{
1509 struct CadetClient *c; 1484 struct CadetChannel *ch = cls;
1485 struct CadetReliableMessage *crm = ch->head_sent;
1510 1486
1511 c = fwd ? ch->dest : ch->root; 1487 ch->retry_data_task = NULL;
1512 return NULL != c; 1488 GNUNET_assert (NULL == crm->qe);
1489 LOG (GNUNET_ERROR_TYPE_DEBUG,
1490 "Retrying transmission on %s of message %u\n",
1491 GCCH_2s (ch),
1492 (unsigned int) ntohl (crm->data_message->mid.mid));
1493 crm->qe = GCT_send (ch->t,
1494 &crm->data_message->header,
1495 &data_sent_cb,
1496 crm);
1497 GNUNET_assert (NULL == ch->retry_data_task);
1513} 1498}
1514 1499
1515 1500
1516/** 1501/**
1517 * Send an end-to-end ACK message for the most recent in-sequence payload. 1502 * We got an PLAINTEXT_DATA_ACK for a message in our queue, remove it from
1518 * 1503 * the queue and tell our client that it can send more.
1519 * If channel is not reliable, do nothing.
1520 * 1504 *
1521 * @param ch Channel this is about. 1505 * @param ch the channel that got the PLAINTEXT_DATA_ACK
1522 * @param fwd Is for FWD traffic? (ACK dest->owner) 1506 * @param cti identifier of the connection that delivered the message
1507 * @param crm the message that got acknowledged
1523 */ 1508 */
1524void 1509static void
1525GCCH_send_data_ack (struct CadetChannel *ch, int fwd) 1510handle_matching_ack (struct CadetChannel *ch,
1511 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
1512 struct CadetReliableMessage *crm)
1526{ 1513{
1527 struct GNUNET_CADET_ChannelDataAckMessage msg; 1514 GNUNET_CONTAINER_DLL_remove (ch->head_sent,
1528 struct CadetChannelReliability *rel; 1515 ch->tail_sent,
1529 struct CadetReliableMessage *copy; 1516 crm);
1530 unsigned int delta; 1517 ch->pending_messages--;
1531 uint64_t mask; 1518 GNUNET_assert (ch->pending_messages < ch->max_pending_messages);
1532 uint32_t ack; 1519 LOG (GNUNET_ERROR_TYPE_DEBUG,
1533 1520 "Received DATA_ACK on %s for message %u (%u ACKs pending)\n",
1534 if (GNUNET_NO == ch->reliable) 1521 GCCH_2s (ch),
1535 return; 1522 (unsigned int) ntohl (crm->data_message->mid.mid),
1536 1523 ch->pending_messages);
1537 rel = fwd ? ch->dest_rel : ch->root_rel; 1524 if (NULL != crm->qe)
1538 ack = rel->mid_recv - 1; 1525 {
1539 1526 GCT_send_cancel (crm->qe);
1540 msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK); 1527 crm->qe = NULL;
1541 msg.header.size = htons (sizeof (msg)); 1528 }
1542 msg.ctn = ch->gid; 1529 if ( (1 == crm->num_transmissions) &&
1543 msg.mid = htonl (ack); 1530 (NULL != cti) )
1544 1531 {
1545 msg.futures = 0LL; 1532 GCC_ack_observed (cti);
1546 for (copy = rel->head_recv; NULL != copy; copy = copy->next) 1533 if (0 == memcmp (cti,
1547 { 1534 &crm->connection_taken,
1548 if (copy->type != GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA) 1535 sizeof (struct GNUNET_CADET_ConnectionTunnelIdentifier)))
1549 { 1536 {
1550 LOG (GNUNET_ERROR_TYPE_DEBUG, " Type %s, expected DATA\n", 1537 GCC_latency_observed (cti,
1551 GC_m2s (copy->type)); 1538 GNUNET_TIME_absolute_get_duration (crm->first_transmission_time));
1552 continue;
1553 } 1539 }
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 } 1540 }
1564 1541 GNUNET_free (crm->data_message);
1565 GCCH_send_prebuilt_message (&msg.header, ch, !fwd, NULL); 1542 GNUNET_free (crm);
1566 LOG (GNUNET_ERROR_TYPE_DEBUG, "send_data_ack END\n"); 1543 send_ack_to_client (ch,
1544 (NULL == ch->owner)
1545 ? GNUNET_NO
1546 : GNUNET_YES);
1567} 1547}
1568 1548
1569 1549
1570/** 1550/**
1571 * Allow a client to send us more data, in case it was choked. 1551 * We got an acknowledgement for payload data for a channel.
1552 * Possibly resume transmissions.
1572 * 1553 *
1573 * @param ch Channel. 1554 * @param ch channel that got the ack
1574 * @param fwd Is this about FWD traffic? (Root client). 1555 * @param cti identifier of the connection that delivered the message
1556 * @param ack details about what was received
1575 */ 1557 */
1576void 1558void
1577GCCH_allow_client (struct CadetChannel *ch, int fwd) 1559GCCH_handle_channel_plaintext_data_ack (struct CadetChannel *ch,
1560 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
1561 const struct GNUNET_CADET_ChannelDataAckMessage *ack)
1578{ 1562{
1579 struct CadetChannelReliability *rel; 1563 struct CadetReliableMessage *crm;
1580 unsigned int buffer; 1564 struct CadetReliableMessage *crmn;
1581 1565 int found;
1582 LOG (GNUNET_ERROR_TYPE_DEBUG, "GMCH allow\n"); 1566 uint32_t mid_base;
1567 uint64_t mid_mask;
1568 unsigned int delta;
1583 1569
1584 if (CADET_CHANNEL_READY != ch->state) 1570 GNUNET_break (GNUNET_NO == ch->is_loopback);
1571 if (GNUNET_NO == ch->reliable)
1585 { 1572 {
1586 LOG (GNUNET_ERROR_TYPE_DEBUG, " channel not ready yet!\n"); 1573 /* not expecting ACKs on unreliable channel, odd */
1574 GNUNET_break_op (0);
1587 return; 1575 return;
1588 } 1576 }
1589 1577 /* mid_base is the MID of the next message that the
1590 if (GNUNET_YES == ch->reliable) 1578 other peer expects (i.e. that is missing!), everything
1591 { 1579 LOWER (but excluding mid_base itself) was received. */
1592 rel = fwd ? ch->root_rel : ch->dest_rel; 1580 mid_base = ntohl (ack->mid.mid);
1593 if (NULL == rel) 1581 mid_mask = GNUNET_htonll (ack->futures);
1582 found = GNUNET_NO;
1583 for (crm = ch->head_sent;
1584 NULL != crm;
1585 crm = crmn)
1586 {
1587 crmn = crm->next;
1588 delta = (unsigned int) (ntohl (crm->data_message->mid.mid) - mid_base);
1589 if (delta >= UINT_MAX - ch->max_pending_messages)
1594 { 1590 {
1595 GNUNET_break (GNUNET_NO != ch->destroy); 1591 /* overflow, means crm was a bit in the past, so this ACK counts for it. */
1596 return; 1592 LOG (GNUNET_ERROR_TYPE_DEBUG,
1597 } 1593 "Got DATA_ACK with base %u satisfying past message %u on %s\n",
1598 if (NULL != rel->head_sent) 1594 (unsigned int) mid_base,
1599 { 1595 ntohl (crm->data_message->mid.mid),
1600 if (64 <= rel->mid_send - rel->head_sent->mid) 1596 GCCH_2s (ch));
1601 { 1597 handle_matching_ack (ch,
1602 LOG (GNUNET_ERROR_TYPE_DEBUG, " too big MID gap! Wait for ACK.\n"); 1598 cti,
1603 return; 1599 crm);
1604 } 1600 found = GNUNET_YES;
1605 else 1601 continue;
1606 {
1607 LOG (GNUNET_ERROR_TYPE_DEBUG, " gap ok: %u - %u\n",
1608 rel->head_sent->mid, rel->mid_send);
1609 struct CadetReliableMessage *aux;
1610 for (aux = rel->head_sent; NULL != aux; aux = aux->next)
1611 {
1612 LOG (GNUNET_ERROR_TYPE_DEBUG, " - sent mid %u\n", aux->mid);
1613 }
1614 }
1615 } 1602 }
1616 else 1603 delta--;
1604 if (delta >= 64)
1605 continue;
1606 LOG (GNUNET_ERROR_TYPE_DEBUG,
1607 "Testing bit %llX for mid %u (base: %u)\n",
1608 (1LLU << delta),
1609 ntohl (crm->data_message->mid.mid),
1610 mid_base);
1611 if (0 != (mid_mask & (1LLU << delta)))
1617 { 1612 {
1618 LOG (GNUNET_ERROR_TYPE_DEBUG, " head sent is NULL\n"); 1613 LOG (GNUNET_ERROR_TYPE_DEBUG,
1614 "Got DATA_ACK with mask for %u on %s\n",
1615 ntohl (crm->data_message->mid.mid),
1616 GCCH_2s (ch));
1617 handle_matching_ack (ch,
1618 cti,
1619 crm);
1620 found = GNUNET_YES;
1619 } 1621 }
1620 } 1622 }
1621 1623 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 { 1624 {
1629 LOG (GNUNET_ERROR_TYPE_DEBUG, " no buffer space.\n"); 1625 /* ACK for message we already dropped, might have been a
1626 duplicate ACK? Ignore. */
1627 LOG (GNUNET_ERROR_TYPE_DEBUG,
1628 "Duplicate DATA_ACK on %s, ignoring\n",
1629 GCCH_2s (ch));
1630 GNUNET_STATISTICS_update (stats,
1631 "# duplicate DATA_ACKs",
1632 1,
1633 GNUNET_NO);
1630 return; 1634 return;
1631 } 1635 }
1632 1636 if (NULL != ch->retry_data_task)
1633 LOG (GNUNET_ERROR_TYPE_DEBUG, " buffer space %u, allowing\n", buffer); 1637 {
1634 send_client_ack (ch, fwd); 1638 GNUNET_SCHEDULER_cancel (ch->retry_data_task);
1639 ch->retry_data_task = NULL;
1640 }
1641 if ( (NULL != ch->head_sent) &&
1642 (NULL == ch->head_sent->qe) )
1643 ch->retry_data_task
1644 = GNUNET_SCHEDULER_add_at (ch->head_sent->next_retry,
1645 &retry_transmission,
1646 ch);
1635} 1647}
1636 1648
1637 1649
1638/** 1650/**
1639 * Log channel info. 1651 * Destroy channel, based on the other peer closing the
1652 * connection. Also needs to remove this channel from
1653 * the tunnel.
1640 * 1654 *
1641 * @param ch Channel. 1655 * @param ch channel to destroy
1642 * @param level Debug level to use. 1656 * @param cti identifier of the connection that delivered the message,
1657 * NULL if we are simulating receiving a destroy due to shutdown
1643 */ 1658 */
1644void 1659void
1645GCCH_debug (struct CadetChannel *ch, enum GNUNET_ErrorType level) 1660GCCH_handle_remote_destroy (struct CadetChannel *ch,
1661 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti)
1646{ 1662{
1647 int do_log; 1663 struct CadetChannelClient *ccc;
1648 1664
1649 do_log = GNUNET_get_log_call_status (level & (~GNUNET_ERROR_TYPE_BULK), 1665 GNUNET_assert (GNUNET_NO == ch->is_loopback);
1650 "cadet-chn", 1666 LOG (GNUNET_ERROR_TYPE_DEBUG,
1651 __FILE__, __FUNCTION__, __LINE__); 1667 "Received remote channel DESTROY for %s\n",
1652 if (0 == do_log) 1668 GCCH_2s (ch));
1653 return; 1669 if (GNUNET_YES == ch->destroy)
1654
1655 if (NULL == ch)
1656 { 1670 {
1657 LOG2 (level, "CHN *** DEBUG NULL CHANNEL ***\n"); 1671 /* Local client already gone, this is instant-death. */
1672 channel_destroy (ch);
1658 return; 1673 return;
1659 } 1674 }
1660 LOG2 (level, "CHN Channel %s:%X (%p)\n", GCT_2s (ch->t), ch->gid, ch); 1675 ccc = (NULL != ch->owner) ? ch->owner : ch->dest;
1661 LOG2 (level, "CHN root %p/%p\n", ch->root, ch->root_rel); 1676 if ( (NULL != ccc) &&
1662 if (NULL != ch->root) 1677 (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 { 1678 {
1675 LOG2 (level, "CHN cli %s\n", GML_2s (ch->dest)); 1679 LOG (GNUNET_ERROR_TYPE_WARNING,
1676 LOG2 (level, "CHN ready %s\n", ch->dest_rel->client_ready ? "YES" : "NO"); 1680 "Lost end of transmission due to remote shutdown on %s\n",
1677 LOG2 (level, "CHN id %X\n", ch->lid_dest); 1681 GCCH_2s (ch));
1678 LOG2 (level, "CHN recv %d\n", ch->dest_rel->n_recv); 1682 /* 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 } 1683 }
1684 ch->destroy = GNUNET_YES;
1685 if (NULL != ccc)
1686 GSC_handle_remote_channel_destroy (ccc->c,
1687 ccc->ccn,
1688 ch);
1689 channel_destroy (ch);
1683} 1690}
1684 1691
1685 1692
1686/** 1693/**
1687 * Handle an ACK given by a client. 1694 * Test if element @a e1 comes before element @a e2.
1688 * 1695 *
1689 * Mark client as ready and send him any buffered data we could have for him. 1696 * @param cls closure, to a flag where we indicate duplicate packets
1690 * 1697 * @param crm1 an element of to sort
1691 * @param ch Channel. 1698 * @param crm2 another element to sort
1692 * @param fwd Is this a "FWD ACK"? (FWD ACKs are sent by dest and go BCK) 1699 * @return #GNUNET_YES if @e1 < @e2, otherwise #GNUNET_NO
1693 */ 1700 */
1694void 1701static int
1695GCCH_handle_local_ack (struct CadetChannel *ch, int fwd) 1702cmp_crm_by_next_retry (void *cls,
1703 struct CadetReliableMessage *crm1,
1704 struct CadetReliableMessage *crm2)
1696{ 1705{
1697 struct CadetChannelReliability *rel; 1706 if (crm1->next_retry.abs_value_us <
1698 struct CadetClient *c; 1707 crm2->next_retry.abs_value_us)
1699 1708 return GNUNET_YES;
1700 rel = fwd ? ch->dest_rel : ch->root_rel; 1709 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} 1710}
1727 1711
1728 1712
1729/** 1713/**
1730 * Handle data given by a client. 1714 * Function called once the tunnel has sent one of our messages.
1731 * 1715 * 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 1716 * message was reliable, calculate retransmission time and
1733 * is reliable and send an ACK to the client if there is still buffer space 1717 * wait for ACK (or retransmit).
1734 * in the tunnel. 1718 *
1735 * 1719 * @param cls the `struct CadetReliableMessage` that was sent
1736 * @param ch Channel. 1720 * @param cid identifier of the connection within the tunnel, NULL
1737 * @param c Client which sent the data. 1721 * 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 */ 1722 */
1744int 1723static void
1745GCCH_handle_local_data (struct CadetChannel *ch, 1724data_sent_cb (void *cls,
1746 struct CadetClient *c, 1725 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
1747 int fwd,
1748 const struct GNUNET_MessageHeader *message,
1749 size_t size)
1750{ 1726{
1751 struct CadetChannelReliability *rel; 1727 struct CadetReliableMessage *crm = cls;
1752 struct GNUNET_CADET_ChannelAppDataMessage *payload; 1728 struct CadetChannel *ch = crm->ch;
1753 uint16_t p2p_size = sizeof(struct GNUNET_CADET_ChannelAppDataMessage) + size; 1729
1754 unsigned char cbuf[p2p_size]; 1730 GNUNET_assert (GNUNET_NO == ch->is_loopback);
1755 unsigned char buffer; 1731 GNUNET_assert (NULL != crm->qe);
1756 1732 crm->qe = NULL;
1757 /* Is the client in the channel? */ 1733 GNUNET_CONTAINER_DLL_remove (ch->head_sent,
1758 if ( !( (fwd && 1734 ch->tail_sent,
1759 ch->root == c) 1735 crm);
1760 || 1736 if (GNUNET_NO == ch->reliable)
1761 (!fwd &&
1762 ch->dest == c) ) )
1763 { 1737 {
1764 GNUNET_break_op (0); 1738 GNUNET_free (crm->data_message);
1765 return GNUNET_SYSERR; 1739 GNUNET_free (crm);
1740 ch->pending_messages--;
1741 send_ack_to_client (ch,
1742 (NULL == ch->owner)
1743 ? GNUNET_NO
1744 : GNUNET_YES);
1745 return;
1766 } 1746 }
1767 1747 if (NULL == cid)
1768 rel = fwd ? ch->root_rel : ch->dest_rel;
1769
1770 if (GNUNET_NO == rel->client_allowed)
1771 { 1748 {
1772 GNUNET_break_op (0); 1749 /* There was an error sending. */
1773 return GNUNET_SYSERR; 1750 crm->num_transmissions = GNUNET_SYSERR;
1774 } 1751 }
1775 1752 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 { 1753 {
1821 LOG (GNUNET_ERROR_TYPE_DEBUG, " Client %s is destination.\n", GML_2s (c)); 1754 /* Increment transmission counter, and possibly store @a cid
1822 GML_client_delete_channel (c, ch, ch->lid_dest); 1755 if this was the first transmission. */
1823 ch->dest = NULL; 1756 crm->num_transmissions++;
1757 if (1 == crm->num_transmissions)
1758 {
1759 crm->first_transmission_time = GNUNET_TIME_absolute_get ();
1760 crm->connection_taken = *cid;
1761 GCC_ack_expected (cid);
1762 }
1824 } 1763 }
1825 if (GNUNET_YES == is_root && c == ch->root) 1764 if ( (0 == crm->retry_delay.rel_value_us) &&
1765 (NULL != cid) )
1826 { 1766 {
1827 LOG (GNUNET_ERROR_TYPE_DEBUG, " Client %s is owner.\n", GML_2s (c)); 1767 struct CadetConnection *cc = GCC_lookup (cid);
1828 GML_client_delete_channel (c, ch, ch->lid_root);
1829 ch->root = NULL;
1830 }
1831 1768
1832 send_destroy (ch, GNUNET_NO); 1769 if (NULL != cc)
1833 if (0 == ch->pending_messages) 1770 crm->retry_delay = GCC_get_metrics (cc)->aged_latency;
1834 GCCH_destroy (ch); 1771 else
1772 crm->retry_delay = ch->retry_time;
1773 }
1774 crm->retry_delay = GNUNET_TIME_STD_BACKOFF (crm->retry_delay);
1775 crm->retry_delay = GNUNET_TIME_relative_max (crm->retry_delay,
1776 MIN_RTT_DELAY);
1777 crm->next_retry = GNUNET_TIME_relative_to_absolute (crm->retry_delay);
1778
1779 GNUNET_CONTAINER_DLL_insert_sorted (struct CadetReliableMessage,
1780 cmp_crm_by_next_retry,
1781 NULL,
1782 ch->head_sent,
1783 ch->tail_sent,
1784 crm);
1785 LOG (GNUNET_ERROR_TYPE_DEBUG,
1786 "Message %u sent, next transmission on %s in %s\n",
1787 (unsigned int) ntohl (crm->data_message->mid.mid),
1788 GCCH_2s (ch),
1789 GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (ch->head_sent->next_retry),
1790 GNUNET_YES));
1791 if (NULL == ch->head_sent->qe)
1792 {
1793 if (NULL != ch->retry_data_task)
1794 GNUNET_SCHEDULER_cancel (ch->retry_data_task);
1795 ch->retry_data_task
1796 = GNUNET_SCHEDULER_add_at (ch->head_sent->next_retry,
1797 &retry_transmission,
1798 ch);
1799 }
1835} 1800}
1836 1801
1837 1802
1838/** 1803/**
1839 * Handle a channel create requested by a client. 1804 * Handle data given by a client.
1840 *
1841 * Create the channel and the tunnel in case this was the first0 channel.
1842 * 1805 *
1843 * @param c Client that requested the creation (will be the root). 1806 * Check whether the client is allowed to send in this tunnel, save if
1844 * @param msg Create Channel message. 1807 * channel is reliable and send an ACK to the client if there is still
1808 * buffer space in the tunnel.
1845 * 1809 *
1846 * @return #GNUNET_OK if everything went fine, #GNUNET_SYSERR otherwise. 1810 * @param ch Channel.
1811 * @param sender_ccn ccn of the sender
1812 * @param buf payload to transmit.
1813 * @param buf_len number of bytes in @a buf
1814 * @return #GNUNET_OK if everything goes well,
1815 * #GNUNET_SYSERR in case of an error.
1847 */ 1816 */
1848int 1817int
1849GCCH_handle_local_create (struct CadetClient *c, 1818GCCH_handle_local_data (struct CadetChannel *ch,
1850 struct GNUNET_CADET_LocalChannelCreateMessage *msg) 1819 struct GNUNET_CADET_ClientChannelNumber sender_ccn,
1820 const char *buf,
1821 size_t buf_len)
1851{ 1822{
1852 struct CadetChannel *ch; 1823 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 1824
1861 /* Sanity check for duplicate channel IDs */ 1825 if (ch->pending_messages > ch->max_pending_messages)
1862 if (NULL != GML_channel_get (c, ccn))
1863 { 1826 {
1864 GNUNET_break (0); 1827 GNUNET_break (0);
1865 return GNUNET_SYSERR; 1828 return GNUNET_SYSERR;
1866 } 1829 }
1867 1830 if (GNUNET_YES == ch->destroy)
1868 peer = GCP_get (&msg->peer, GNUNET_YES);
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 { 1831 {
1878 /* FIXME change to a tunnel API, eliminate ch <-> peer connection */ 1832 /* we are going down, drop messages */
1879 GCP_connect (peer); 1833 return GNUNET_OK;
1880 } 1834 }
1835 ch->pending_messages++;
1881 1836
1882 /* Create channel */ 1837 if (GNUNET_YES == ch->is_loopback)
1883 ch = channel_new (t, c, ccn);
1884 if (NULL == ch)
1885 {
1886 GNUNET_break (0);
1887 return GNUNET_SYSERR;
1888 }
1889 ch->port = msg->port;
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 {
1931 if (is_loopback (ch))
1932 {
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 }
1939
1940 /* Initialize FWD/BCK data */
1941 c = fwd ? ch->dest : ch->root;
1942 rel = fwd ? ch->dest_rel : ch->root_rel;
1943
1944 if (NULL == c)
1945 { 1838 {
1946 GNUNET_break (GNUNET_NO != ch->destroy); 1839 struct CadetChannelClient *receiver;
1947 return; 1840 struct GNUNET_MQ_Envelope *env;
1948 } 1841 struct GNUNET_CADET_LocalData *ld;
1842 int ack_to_owner;
1949 1843
1950 if (CADET_CHANNEL_READY != ch->state) 1844 env = GNUNET_MQ_msg_extra (ld,
1951 { 1845 buf_len,
1952 if (GNUNET_NO == fwd) 1846 GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA);
1847 if ( (NULL != ch->owner) &&
1848 (sender_ccn.channel_of_client ==
1849 ch->owner->ccn.channel_of_client) )
1953 { 1850 {
1954 /* If we are the root, this means the other peer has sent traffic before 1851 receiver = ch->dest;
1955 * receiving our ACK. Even if the SYNACK goes missing, no traffic should 1852 ack_to_owner = GNUNET_YES;
1956 * be sent before the ACK.
1957 */
1958 GNUNET_break_op (0);
1959 return;
1960 } 1853 }
1961 /* If we are the dest, this means that the SYNACK got to the root but 1854 else if ( (NULL != ch->dest) &&
1962 * the ACK went missing. Treat this as an ACK. 1855 (sender_ccn.channel_of_client ==
1963 */ 1856 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 { 1857 {
1985 /* Is this the exact next expected messasge? */ 1858 receiver = ch->owner;
1986 if (mid == rel->mid_recv) 1859 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 } 1860 }
1999 else 1861 else
2000 { 1862 {
2001 /* Tunnel is unreliable: send to clients directly */ 1863 GNUNET_break (0);
2002 /* FIXME: accept Out Of Order traffic */ 1864 return GNUNET_SYSERR;
2003 rel->mid_recv = mid + 1;
2004 send_client_data (ch, msg, fwd);
2005 } 1865 }
2006 } 1866 GNUNET_assert (NULL != receiver);
2007 else 1867 ld->ccn = receiver->ccn;
2008 { 1868 GNUNET_memcpy (&ld[1],
2009 GNUNET_STATISTICS_update (stats, "# duplicate MID", 1, GNUNET_NO); 1869 buf,
2010 if (GC_is_pid_bigger (rel->mid_recv, mid)) 1870 buf_len);
1871 if (GNUNET_YES == receiver->client_ready)
2011 { 1872 {
2012 GNUNET_break_op (0); 1873 ch->pending_messages--;
2013 LOG (GNUNET_ERROR_TYPE_WARNING, 1874 GSC_send_to_client (receiver->c,
2014 "MID %u on channel %s not expected (window: %u - %u). Dropping!\n", 1875 env);
2015 mid, GCCH_2s (ch), rel->mid_recv, rel->mid_recv + 63); 1876 send_ack_to_client (ch,
1877 ack_to_owner);
2016 } 1878 }
2017 else 1879 else
2018 { 1880 {
2019 LOG (GNUNET_ERROR_TYPE_INFO, 1881 struct CadetOutOfOrderMessage *oom;
2020 "Duplicate MID %u, channel %s (expecting MID %u). Re-sending ACK!\n", 1882
2021 mid, GCCH_2s (ch), rel->mid_recv); 1883 oom = GNUNET_new (struct CadetOutOfOrderMessage);
2022 if (NULL != rel->uniq) 1884 oom->env = env;
2023 { 1885 GNUNET_CONTAINER_DLL_insert_tail (receiver->head_recv,
2024 LOG (GNUNET_ERROR_TYPE_WARNING, 1886 receiver->tail_recv,
2025 "We are trying to send an ACK, but don't seem have the " 1887 oom);
2026 "bandwidth. Have you set enough [ats] QUOTA in your config?\n"); 1888 receiver->num_recv++;
2027 }
2028
2029 } 1889 }
2030 } 1890 return GNUNET_OK;
2031 1891 }
2032 GCCH_send_data_ack (ch, fwd); 1892
1893 /* Everything is correct, send the message. */
1894 crm = GNUNET_malloc (sizeof (*crm));
1895 crm->ch = ch;
1896 crm->data_message = GNUNET_malloc (sizeof (struct GNUNET_CADET_ChannelAppDataMessage)
1897 + buf_len);
1898 crm->data_message->header.size = htons (sizeof (struct GNUNET_CADET_ChannelAppDataMessage) + buf_len);
1899 crm->data_message->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA);
1900 ch->mid_send.mid = htonl (ntohl (ch->mid_send.mid) + 1);
1901 crm->data_message->mid = ch->mid_send;
1902 crm->data_message->ctn = ch->ctn;
1903 GNUNET_memcpy (&crm->data_message[1],
1904 buf,
1905 buf_len);
1906 GNUNET_CONTAINER_DLL_insert_tail (ch->head_sent,
1907 ch->tail_sent,
1908 crm);
1909 LOG (GNUNET_ERROR_TYPE_DEBUG,
1910 "Sending message %u from local client to %s with %u bytes\n",
1911 ntohl (crm->data_message->mid.mid),
1912 GCCH_2s (ch),
1913 buf_len);
1914 if (NULL != ch->retry_data_task)
1915 {
1916 GNUNET_SCHEDULER_cancel (ch->retry_data_task);
1917 ch->retry_data_task = NULL;
1918 }
1919 crm->qe = GCT_send (ch->t,
1920 &crm->data_message->header,
1921 &data_sent_cb,
1922 crm);
1923 GNUNET_assert (NULL == ch->retry_data_task);
1924 return GNUNET_OK;
2033} 1925}
2034 1926
2035 1927
2036/** 1928/**
2037 * Handler for cadet network traffic end-to-end ACKs. 1929 * Handle ACK from client on local channel. Means the client is ready
1930 * for more data, see if we have any for it.
2038 * 1931 *
2039 * @param ch Channel on which we got this message. 1932 * @param ch channel to destroy
2040 * @param msg Data message. 1933 * @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 */ 1934 */
2046void 1935void
2047GCCH_handle_data_ack (struct CadetChannel *ch, 1936GCCH_handle_local_ack (struct CadetChannel *ch,
2048 const struct GNUNET_CADET_ChannelDataAckMessage *msg, 1937 struct GNUNET_CADET_ClientChannelNumber client_ccn)
2049 int fwd)
2050{ 1938{
2051 struct CadetChannelReliability *rel; 1939 struct CadetChannelClient *ccc;
2052 struct CadetReliableMessage *copy; 1940 struct CadetOutOfOrderMessage *com;
2053 struct CadetReliableMessage *next; 1941
2054 uint32_t ack; 1942 if ( (NULL != ch->owner) &&
2055 int work; 1943 (ch->owner->ccn.channel_of_client == client_ccn.channel_of_client) )
2056 1944 ccc = ch->owner;
2057 /* If this is a remote (non-loopback) channel, find 'fwd'. */ 1945 else if ( (NULL != ch->dest) &&
2058 if (GNUNET_SYSERR == fwd) 1946 (ch->dest->ccn.channel_of_client == client_ccn.channel_of_client) )
2059 { 1947 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 1948 else
2079 rel = ch->dest_rel; 1949 GNUNET_assert (0);
2080 1950 ccc->client_ready = GNUNET_YES;
2081 if (NULL == rel) 1951 com = ccc->head_recv;
2082 { 1952 if (NULL == com)
2083 GNUNET_break (GNUNET_NO != ch->destroy);
2084 return;
2085 }
2086
2087 /* Free ACK'd copies: no need to retransmit those anymore FIXME refactor */
2088 for (work = GNUNET_NO, copy = rel->head_sent; copy != NULL; copy = next)
2089 { 1953 {
2090 if (GC_is_pid_bigger (copy->mid, ack)) 1954 LOG (GNUNET_ERROR_TYPE_DEBUG,
2091 { 1955 "Got LOCAL_ACK, %s-%X ready to receive more data, but none pending on %s-%X(%p)!\n",
2092 LOG (GNUNET_ERROR_TYPE_DEBUG, " head %u, out!\n", copy->mid); 1956 GSC_2s (ccc->c),
2093 if (0 < channel_rel_free_sent (rel, msg)) 1957 ntohl (client_ccn.channel_of_client),
2094 work = GNUNET_YES; 1958 GCCH_2s (ch),
2095 break; 1959 ntohl (ccc->ccn.channel_of_client),
2096 } 1960 ccc);
2097 work = GNUNET_YES; 1961 return; /* none pending */
2098 LOG (GNUNET_ERROR_TYPE_DEBUG, " id %u\n", copy->mid); 1962 }
2099 next = copy->next; 1963 if (GNUNET_YES == ch->is_loopback)
2100 if (GNUNET_YES == rel_message_free (copy, GNUNET_YES)) 1964 {
2101 { 1965 int to_owner;
2102 LOG (GNUNET_ERROR_TYPE_DEBUG, " channel destoyed\n"); 1966
2103 return; 1967 /* Messages are always in-order, just send */
2104 } 1968 GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
2105 } 1969 ccc->tail_recv,
2106 1970 com);
2107 /* ACK client if needed and possible */ 1971 ccc->num_recv--;
2108 GCCH_allow_client (ch, fwd); 1972 GSC_send_to_client (ccc->c,
2109 1973 com->env);
2110 /* If some message was free'd, update the retransmission delay */ 1974 /* Notify sender that we can receive more */
2111 if (GNUNET_YES == work) 1975 if ( (NULL != ch->owner) &&
2112 { 1976 (ccc->ccn.channel_of_client ==
2113 if (NULL != rel->retry_task) 1977 ch->owner->ccn.channel_of_client) )
2114 { 1978 {
2115 GNUNET_SCHEDULER_cancel (rel->retry_task); 1979 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 } 1980 }
2133 else 1981 else
2134 { 1982 {
2135 /* Work was done but no task was pending. 1983 GNUNET_assert ( (NULL != ch->dest) &&
2136 * Task was cancelled by a retransmission that is sitting in the queue. 1984 (ccc->ccn.channel_of_client ==
2137 */ 1985 ch->dest->ccn.channel_of_client) );
2138 // FIXME add test to make sure this is the case, probably add return 1986 to_owner = GNUNET_YES;
2139 // value to GCCH_send_prebuilt_message
2140 } 1987 }
1988 send_ack_to_client (ch,
1989 to_owner);
1990 GNUNET_free (com);
1991 return;
2141 } 1992 }
2142}
2143
2144 1993
2145/** 1994 if ( (com->mid.mid != ch->mid_recv.mid) &&
2146 * Handler for channel create messages. 1995 (GNUNET_NO == ch->out_of_order) &&
2147 * 1996 (GNUNET_YES == ch->reliable) )
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 { 1997 {
2168 /* Create channel */ 1998 LOG (GNUNET_ERROR_TYPE_DEBUG,
2169 ccn.channel_of_client = htonl (0); 1999 "Got LOCAL_ACK, %s-%X ready to receive more data (but next one is out-of-order %u vs. %u)!\n",
2170 ch = channel_new (t, NULL, ccn); 2000 GSC_2s (ccc->c),
2171 ch->gid = gid; 2001 ntohl (ccc->ccn.channel_of_client),
2172 channel_set_options (ch, ntohl (msg->opt)); 2002 ntohl (com->mid.mid),
2173 new_channel = GNUNET_YES; 2003 ntohl (ch->mid_recv.mid));
2174 } 2004 return; /* missing next one in-order */
2175 else
2176 {
2177 new_channel = GNUNET_NO;
2178 } 2005 }
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 2006
2219 send_client_create (ch); 2007 LOG (GNUNET_ERROR_TYPE_DEBUG,
2220 ch->state = CADET_CHANNEL_SENT; 2008 "Got LOCAL_ACK, giving payload message %u to %s-%X on %s\n",
2221 } 2009 ntohl (com->mid.mid),
2222 else 2010 GSC_2s (ccc->c),
2223 { 2011 ntohl (ccc->ccn.channel_of_client),
2224 LOG (GNUNET_ERROR_TYPE_DEBUG, " duplicate create channel\n"); 2012 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 2013
2240 return ch; 2014 /* all good, pass next message to client */
2015 GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
2016 ccc->tail_recv,
2017 com);
2018 ccc->num_recv--;
2019 /* FIXME: if unreliable, this is not aggressive
2020 enough, as it would be OK to have lost some! */
2021
2022 ch->mid_recv.mid = htonl (1 + ntohl (com->mid.mid));
2023 ch->mid_futures >>= 1; /* equivalent to division by 2 */
2024 ccc->client_ready = GNUNET_NO;
2025 GSC_send_to_client (ccc->c,
2026 com->env);
2027 GNUNET_free (com);
2028 send_channel_data_ack (ch);
2029 if (NULL != ccc->head_recv)
2030 return;
2031 if (GNUNET_NO == ch->destroy)
2032 return;
2033 GCT_send_channel_destroy (ch->t,
2034 ch->ctn);
2035 channel_destroy (ch);
2241} 2036}
2242 2037
2243 2038
2244/** 2039#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 2040
2263 2041
2264/** 2042/**
2265 * Handler for channel ack messages. 2043 * Log channel info.
2266 * 2044 *
2267 * @param ch Channel. 2045 * @param ch Channel.
2268 * @param msg Message. 2046 * @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 */ 2047 */
2310void 2048void
2311GCCH_handle_destroy (struct CadetChannel *ch, 2049GCCH_debug (struct CadetChannel *ch,
2312 const struct GNUNET_CADET_ChannelManageMessage *msg, 2050 enum GNUNET_ErrorType level)
2313 int fwd)
2314{ 2051{
2315 struct CadetChannelReliability *rel; 2052 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 2053
2334 GCCH_debug (ch, GNUNET_ERROR_TYPE_DEBUG); 2054 do_log = GNUNET_get_log_call_status (level & (~GNUNET_ERROR_TYPE_BULK),
2335 if ( (fwd && NULL == ch->dest) || (!fwd && NULL == ch->root) ) 2055 "cadet-chn",
2336 { 2056 __FILE__, __FUNCTION__, __LINE__);
2337 /* Not for us (don't destroy twice a half-open loopback channel) */ 2057 if (0 == do_log)
2338 return; 2058 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 2059
2434 if (GCT_is_loopback (ch->t)) 2060 if (NULL == ch)
2435 { 2061 {
2436 handle_loopback (ch, message, fwd); 2062 LOG2 (level, "CHN *** DEBUG NULL CHANNEL ***\n");
2437 return; 2063 return;
2438 } 2064 }
2439 2065 LOG2 (level,
2440 switch (type) 2066 "CHN %s:%X (%p)\n",
2067 GCT_2s (ch->t),
2068 ch->ctn,
2069 ch);
2070 if (NULL != ch->owner)
2441 { 2071 {
2442 case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA: 2072 LOG2 (level,
2443 if (GNUNET_YES == ch->reliable) 2073 "CHN origin %s ready %s local-id: %u\n",
2444 { 2074 GSC_2s (ch->owner->c),
2445 chq = GNUNET_new (struct CadetChannelQueue); 2075 ch->owner->client_ready ? "YES" : "NO",
2446 chq->type = type; 2076 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 } 2077 }
2078 if (NULL != ch->dest)
2079 {
2080 LOG2 (level,
2081 "CHN destination %s ready %s local-id: %u\n",
2082 GSC_2s (ch->dest->c),
2083 ch->dest->client_ready ? "YES" : "NO",
2084 ntohl (ch->dest->ccn.channel_of_client));
2085 }
2086 LOG2 (level,
2087 "CHN Message IDs recv: %d (%LLX), send: %d\n",
2088 ntohl (ch->mid_recv.mid),
2089 (unsigned long long) ch->mid_futures,
2090 ntohl (ch->mid_send.mid));
2535} 2091}
2536 2092
2537 2093
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 2094
2553 SPRINTF (buf, 2095/* 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..16517c457 100644
--- a/src/cadet/gnunet-service-cadet_channel.h
+++ b/src/cadet/gnunet-service-cadet_channel.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) 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
@@ -20,344 +20,261 @@
20 20
21/** 21/**
22 * @file cadet/gnunet-service-cadet_channel.h 22 * @file cadet/gnunet-service-cadet_channel.h
23 * @brief cadet service; dealing with end-to-end channels 23 * @brief GNUnet CADET service with encryption
24 * @author Bartlomiej Polot 24 * @author Bartlomiej Polot
25 * 25 * @author Christian Grothoff
26 * All functions in this file should use the prefix GMCH (Gnunet Cadet CHannel)
27 */ 26 */
28
29#ifndef GNUNET_SERVICE_CADET_CHANNEL_H 27#ifndef GNUNET_SERVICE_CADET_CHANNEL_H
30#define GNUNET_SERVICE_CADET_CHANNEL_H 28#define GNUNET_SERVICE_CADET_CHANNEL_H
31 29
32#ifdef __cplusplus 30#include "gnunet-service-cadet.h"
33extern "C" 31#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" 32#include "cadet_protocol.h"
44#include "cadet.h" 33
45 34
46/** 35/**
47 * Struct containing all information regarding a channel to a remote client. 36 * A channel is a bidirectional connection between two CADET
37 * clients. Communiation can be reliable, unreliable, in-order
38 * or out-of-order. One client is the "local" client, this
39 * one initiated the connection. The other client is the
40 * "incoming" client, this one listened on a port to accept
41 * the connection from the "local" client.
48 */ 42 */
49struct CadetChannel; 43struct CadetChannel;
50 44
51 45
52#include "gnunet-service-cadet_tunnel.h"
53#include "gnunet-service-cadet_local.h"
54
55
56/** 46/**
57 * Destroy a channel and free all resources. 47 * Hash the @a port and @a initiator and @a listener to
48 * calculate the "challenge" @a h_port we send to the other
49 * peer on #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN.
58 * 50 *
59 * @param ch Channel to destroy. 51 * @param[out] h_port set to the hash of @a port, @a initiator and @a listener
52 * @param port cadet port, as seen by CADET clients
53 * @param listener peer that is listining on @a port
60 */ 54 */
61void 55void
62GCCH_destroy (struct CadetChannel *ch); 56GCCH_hash_port (struct GNUNET_HashCode *h_port,
57 const struct GNUNET_HashCode *port,
58 const struct GNUNET_PeerIdentity *listener);
63 59
64 60
65/** 61/**
66 * Get the channel's public ID. 62 * Get the static string for identification of the channel.
67 * 63 *
68 * @param ch Channel. 64 * @param ch Channel.
69 * 65 *
70 * @return ID used to identify the channel with the remote peer. 66 * @return Static string with the channel IDs.
71 */
72struct GNUNET_CADET_ChannelTunnelNumber
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 */ 67 */
83struct CadetTunnel * 68const char *
84GCCH_get_tunnel (const struct CadetChannel *ch); 69GCCH_2s (const struct CadetChannel *ch);
85 70
86 71
87/** 72/**
88 * Get free buffer space towards the client on a specific channel. 73 * Log channel info.
89 * 74 *
90 * @param ch Channel. 75 * @param ch Channel.
91 * @param fwd Is query about FWD traffic? 76 * @param level Debug level to use.
92 *
93 * @return Free buffer space [0 - 64]
94 */ 77 */
95unsigned int 78void
96GCCH_get_buffer (struct CadetChannel *ch, int fwd); 79GCCH_debug (struct CadetChannel *ch,
80 enum GNUNET_ErrorType level);
97 81
98 82
99/** 83/**
100 * Get flow control status of end point: is client allow to send? 84 * Get the channel's public ID.
101 * 85 *
102 * @param ch Channel. 86 * @param ch Channel.
103 * @param fwd Is query about FWD traffic? (Request root status).
104 * 87 *
105 * @return #GNUNET_YES if client is allowed to send us data. 88 * @return ID used to identify the channel with the remote peer.
106 */ 89 */
107int 90struct GNUNET_CADET_ChannelTunnelNumber
108GCCH_get_allowed (struct CadetChannel *ch, int fwd); 91GCCH_get_id (const struct CadetChannel *ch);
109 92
110 93
111/** 94/**
112 * Is the root client for this channel on this peer? 95 * Create a new channel.
113 * 96 *
114 * @param ch Channel. 97 * @param owner local client owning the channel
115 * @param fwd Is this for fwd traffic? 98 * @param owner_id local chid of this channel at the @a owner
116 * 99 * @param destination peer to which we should build the channel
117 * @return #GNUNET_YES in case it is. 100 * @param port desired port at @a destination
101 * @param options options for the channel
102 * @return handle to the new channel
118 */ 103 */
119int 104struct CadetChannel *
120GCCH_is_origin (struct CadetChannel *ch, int fwd); 105GCCH_channel_local_new (struct CadetClient *owner,
106 struct GNUNET_CADET_ClientChannelNumber owner_id,
107 struct CadetPeer *destination,
108 const struct GNUNET_HashCode *port,
109 uint32_t options);
121 110
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 111
133/** 112/**
134 * Send an end-to-end ACK message for the most recent in-sequence payload. 113 * A client is bound to the port that we have a channel
135 * 114 * open to. Send the acknowledgement for the connection
136 * If channel is not reliable, do nothing. 115 * request and establish the link with the client.
137 * 116 *
138 * @param ch Channel this is about. 117 * @param ch open incoming channel
139 * @param fwd Is for FWD traffic? (ACK dest->owner) 118 * @param c client listening on the respective @a port
119 * @param port port number @a c is listening on
140 */ 120 */
141void 121void
142GCCH_send_data_ack (struct CadetChannel *ch, int fwd); 122GCCH_bind (struct CadetChannel *ch,
123 struct CadetClient *c,
124 const struct GNUNET_HashCode *port);
143 125
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 126
152/** 127/**
153 * Allow a client to send us more data, in case it was choked. 128 * Destroy locally created channel. Called by the
129 * local client, so no need to tell the client.
154 * 130 *
155 * @param ch Channel. 131 * @param ch channel to destroy
156 * @param fwd Is this about FWD traffic? (Root client). 132 * @param c client that caused the destruction
133 * @param ccn client number of the client @a c
157 */ 134 */
158void 135void
159GCCH_allow_client (struct CadetChannel *ch, int fwd); 136GCCH_channel_local_destroy (struct CadetChannel *ch,
137 struct CadetClient *c,
138 struct GNUNET_CADET_ClientChannelNumber ccn);
160 139
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 140
170/** 141/**
171 * Handle an ACK given by a client. 142 * Function called once and only once after a channel was bound
172 * 143 * to its tunnel via #GCT_add_channel() is ready for transmission.
173 * Mark client as ready and send him any buffered data we could have for him. 144 * Note that this is only the case for channels that this peer
174 * 145 * initiates, as for incoming channels we assume that they are
175 * @param ch Channel. 146 * ready for transmission immediately upon receiving the open
176 * @param fwd Is this a "FWD ACK"? (FWD ACKs are sent by root and go BCK) 147 * message. Used to bootstrap the #GCT_send() process.
177 */ 148 *
178void 149 * @param ch the channel for which the tunnel is now ready
179GCCH_handle_local_ack (struct CadetChannel *ch, int fwd);
180
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
202/**
203 * Handle a channel destroy requested by a client.
204 *
205 * Destroy the channel and the tunnel in case this was the last channel.
206 *
207 * @param ch Channel.
208 * @param c Client that requested the destruction (to avoid notifying him).
209 * @param is_root Is the request coming from root?
210 */ 150 */
211void 151void
212GCCH_handle_local_destroy (struct CadetChannel *ch, 152GCCH_tunnel_up (struct CadetChannel *ch);
213 struct CadetClient *c,
214 int is_root);
215
216 153
217/**
218 * Handle a channel create requested by a client.
219 *
220 * Create the channel and the tunnel in case this was the first0 channel.
221 *
222 * @param c Client that requested the creation (will be the root).
223 * @param msg Create Channel message.
224 *
225 * @return #GNUNET_OK if everything went fine, #GNUNET_SYSERR otherwise.
226 */
227int
228GCCH_handle_local_create (struct CadetClient *c,
229 struct GNUNET_CADET_LocalChannelCreateMessage *msg);
230 154
231/** 155/**
232 * Handler for cadet network payload traffic. 156 * Create a new channel based on a request coming in over the network.
233 * 157 *
234 * @param ch Channel for the message. 158 * @param t tunnel to the remote peer
235 * @param msg Unencryted data message. 159 * @param chid identifier of this channel in the tunnel
236 * @param fwd Is this message fwd? This only is meaningful in loopback channels. 160 * @param origin peer to who initiated the channel
237 * #GNUNET_YES if message is FWD on the respective channel (loopback) 161 * @param h_port hash of desired local port
238 * #GNUNET_NO if message is BCK on the respective channel (loopback) 162 * @param options options for the channel
239 * #GNUNET_SYSERR if message on a one-ended channel (remote) 163 * @return handle to the new channel
240 */ 164 */
241void 165struct CadetChannel *
242GCCH_handle_data (struct CadetChannel *ch, 166GCCH_channel_incoming_new (struct CadetTunnel *t,
243 const struct GNUNET_CADET_ChannelAppDataMessage *msg, 167 struct GNUNET_CADET_ChannelTunnelNumber chid,
244 int fwd); 168 const struct GNUNET_HashCode *h_port,
169 uint32_t options);
245 170
246 171
247/** 172/**
248 * Handler for cadet network traffic end-to-end ACKs. 173 * We got a #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN message again for
174 * this channel. If the binding was successful, (re)transmit the
175 * #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK.
249 * 176 *
250 * @param ch Channel on which we got this message. 177 * @param ch channel that got the duplicate open
251 * @param msg Data message. 178 * @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 */ 179 */
257void 180void
258GCCH_handle_data_ack (struct CadetChannel *ch, 181GCCH_handle_duplicate_open (struct CadetChannel *ch,
259 const struct GNUNET_CADET_ChannelDataAckMessage *msg, 182 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti);
260 int fwd);
261 183
262 184
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 185
276/** 186/**
277 * Handler for channel NACK messages. 187 * We got payload data for a channel. Pass it on to the client.
278 *
279 * NACK messages always go dest -> root, no need for 'fwd' or 'msg' parameter.
280 * 188 *
281 * @param ch Channel. 189 * @param ch channel that got data
190 * @param cti identifier of the connection that delivered the message
191 * @param msg message that was received
282 */ 192 */
283void 193void
284GCCH_handle_nack (struct CadetChannel *ch); 194GCCH_handle_channel_plaintext_data (struct CadetChannel *ch,
195 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
196 const struct GNUNET_CADET_ChannelAppDataMessage *msg);
285 197
286 198
287/** 199/**
288 * Handler for channel ack messages. 200 * We got an acknowledgement for payload data for a channel.
201 * Possibly resume transmissions.
289 * 202 *
290 * @param ch Channel this channel is to be created in. 203 * @param ch channel that got the ack
291 * @param msg Message. 204 * @param cti identifier of the connection that delivered the message
292 * @param fwd Is this message fwd? This only is meaningful in loopback channels. 205 * @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 */ 206 */
297void 207void
298GCCH_handle_ack (struct CadetChannel *ch, 208GCCH_handle_channel_plaintext_data_ack (struct CadetChannel *ch,
299 const struct GNUNET_CADET_ChannelManageMessage *msg, 209 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
300 int fwd); 210 const struct GNUNET_CADET_ChannelDataAckMessage *ack);
301 211
302 212
303/** 213/**
304 * Handler for channel destroy messages. 214 * We got an acknowledgement for the creation of the channel
215 * (the port is open on the other side). Begin transmissions.
305 * 216 *
306 * @param ch Channel this channel is to be destroyed of. 217 * @param ch channel to destroy
307 * @param msg Message. 218 * @param cti identifier of the connection that delivered the message,
308 * @param fwd Is this message fwd? This only is meaningful in loopback channels. 219 * 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) 220 * @param port port number (needed to verify receiver knows the port)
310 * #GNUNET_NO if message is BCK on the respective channel (loopback)
311 * #GNUNET_SYSERR if message on a one-ended channel (remote)
312 */ 221 */
313void 222void
314GCCH_handle_destroy (struct CadetChannel *ch, 223GCCH_handle_channel_open_ack (struct CadetChannel *ch,
315 const struct GNUNET_CADET_ChannelManageMessage *msg, 224 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
316 int fwd); 225 const struct GNUNET_HashCode *port);
317 226
318 227
319/** 228/**
320 * Sends an already built message on a channel. 229 * Destroy channel, based on the other peer closing the
321 * 230 * connection. Also needs to remove this channel from
322 * If the channel is on a loopback tunnel, notifies the appropriate destination 231 * the tunnel.
323 * client locally.
324 * 232 *
325 * On a normal channel passes the message to the tunnel for encryption and 233 * FIXME: need to make it possible to defer destruction until we have
326 * sending on a connection. 234 * received all messages up to the destroy, and right now the destroy
235 * message (and this API) fails to give is the information we need!
327 * 236 *
328 * This function DOES NOT save the message for retransmission. 237 * FIXME: also need to know if the other peer got a destroy from
238 * us before!
329 * 239 *
330 * @param message Message to send. Function makes a copy of it. 240 * @param ch channel to destroy
331 * @param ch Channel on which this message is transmitted. 241 * @param cti identifier of the connection that delivered the message,
332 * @param fwd Is this a fwd message? 242 * NULL during shutdown
333 * @param existing_copy This is a retransmission, don't save a copy.
334 */ 243 */
335void 244void
336GCCH_send_prebuilt_message (const struct GNUNET_MessageHeader *message, 245GCCH_handle_remote_destroy (struct CadetChannel *ch,
337 struct CadetChannel *ch, int fwd, 246 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti);
338 void *existing_copy);
339 247
340 248
341/** 249/**
342 * Get the static string for identification of the channel. 250 * Handle data given by a client.
343 * 251 *
344 * @param ch Channel.i 252 * Check whether the client is allowed to send in this tunnel, save if
253 * channel is reliable and send an ACK to the client if there is still
254 * buffer space in the tunnel.
345 * 255 *
346 * @return Static string with the channel IDs. 256 * @param ch Channel.
257 * @param sender_ccn ccn of the sender
258 * @param buf payload to transmit.
259 * @param buf_len number of bytes in @a buf
260 * @return #GNUNET_OK if everything goes well,
261 * #GNUNET_SYSERR in case of an error.
347 */ 262 */
348const char * 263int
349GCCH_2s (const struct CadetChannel *ch); 264GCCH_handle_local_data (struct CadetChannel *ch,
350 265 struct GNUNET_CADET_ClientChannelNumber sender_ccn,
351 266 const char *buf,
267 size_t buf_len);
352 268
353 269
354#if 0 /* keep Emacsens' auto-indent happy */ 270/**
355{ 271 * Handle ACK from client on local channel.
356#endif 272 *
357#ifdef __cplusplus 273 * @param ch channel to destroy
358} 274 * @param client_ccn ccn of the client sending the ack
359#endif 275 */
276void
277GCCH_handle_local_ack (struct CadetChannel *ch,
278 struct GNUNET_CADET_ClientChannelNumber client_ccn);
360 279
361/* ifndef GNUNET_SERVICE_CADET_CHANNEL_H */
362#endif 280#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 af27647b3..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->reserved = 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 4a4ead05b..ae03b4f35 100644
--- a/src/cadet/gnunet-service-cadet-new_core.c
+++ b/src/cadet/gnunet-service-cadet_core.c
@@ -30,22 +30,64 @@
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 "cadet_protocol.h" 40#include "cadet_protocol.h"
40 41
41 42
42#define LOG(level, ...) GNUNET_log_from(level,"cadet-cor",__VA_ARGS__) 43#define LOG(level, ...) GNUNET_log_from(level,"cadet-cor",__VA_ARGS__)
43 44
45/**
46 * Information we keep per direction for a route.
47 */
48struct RouteDirection;
49
44 50
45/** 51/**
46 * Number of messages we are willing to buffer per route. 52 * Set of CadetRoutes that have exactly the same number of messages
53 * in their buffer. Used so we can efficiently find all of those
54 * routes that have the current maximum of messages in the buffer (in
55 * case we have to purge).
47 */ 56 */
48#define ROUTE_BUFFER_SIZE 8 57struct Rung
58{
59
60 /**
61 * Rung of RouteDirections with one more buffer entry each.
62 */
63 struct Rung *next;
64
65 /**
66 * Rung of RouteDirections with one less buffer entry each.
67 */
68 struct Rung *prev;
69
70 /**
71 * DLL of route directions with a number of buffer entries matching this rung.
72 */
73 struct RouteDirection *rd_head;
74
75 /**
76 * DLL of route directions with a number of buffer entries matching this rung.
77 */
78 struct RouteDirection *rd_tail;
79
80 /**
81 * Total number of route directions in this rung.
82 */
83 unsigned int num_routes;
84
85 /**
86 * Number of messages route directions at this rung have
87 * in their buffer.
88 */
89 unsigned int rung_off;
90};
49 91
50 92
51/** 93/**
@@ -53,35 +95,46 @@
53 */ 95 */
54struct RouteDirection 96struct RouteDirection
55{ 97{
98
56 /** 99 /**
57 * Target peer. 100 * DLL of other route directions within the same `struct Rung`.
58 */ 101 */
59 struct CadetPeer *hop; 102 struct RouteDirection *prev;
60 103
61 /** 104 /**
62 * Route this direction is part of. 105 * DLL of other route directions within the same `struct Rung`.
63 */ 106 */
64 struct CadetRoute *my_route; 107 struct RouteDirection *next;
65 108
66 /** 109 /**
67 * Message queue manager for @e hop. 110 * Rung of this route direction (matches length of the buffer DLL).
68 */ 111 */
69 struct GCP_MessageQueueManager *mqm; 112 struct Rung *rung;
113
114 /**
115 * Head of DLL of envelopes we have in the buffer for this direction.
116 */
117 struct GNUNET_MQ_Envelope *env_head;
70 118
71 /** 119 /**
72 * Cyclic message buffer to @e hop. 120 * Tail of DLL of envelopes we have in the buffer for this direction.
73 */ 121 */
74 struct GNUNET_MQ_Envelope *out_buffer[ROUTE_BUFFER_SIZE]; 122 struct GNUNET_MQ_Envelope *env_tail;
75 123
76 /** 124 /**
77 * Next write offset to use to append messages to @e out_buffer. 125 * Target peer.
126 */
127 struct CadetPeer *hop;
128
129 /**
130 * Route this direction is part of.
78 */ 131 */
79 unsigned int out_wpos; 132 struct CadetRoute *my_route;
80 133
81 /** 134 /**
82 * Next read offset to use to retrieve messages from @e out_buffer. 135 * Message queue manager for @e hop.
83 */ 136 */
84 unsigned int out_rpos; 137 struct GCP_MessageQueueManager *mqm;
85 138
86 /** 139 /**
87 * Is @e mqm currently ready for transmission? 140 * Is @e mqm currently ready for transmission?
@@ -122,6 +175,15 @@ struct CadetRoute
122 */ 175 */
123 struct GNUNET_TIME_Absolute last_use; 176 struct GNUNET_TIME_Absolute last_use;
124 177
178 /**
179 * Position of this route in the #route_heap.
180 */
181 struct GNUNET_CONTAINER_HeapNode *hn;
182
183 /**
184 * Options for the route, control buffering.
185 */
186 enum GNUNET_CADET_ChannelOption options;
125}; 187};
126 188
127 189
@@ -135,6 +197,47 @@ static struct GNUNET_CORE_Handle *core;
135 */ 197 */
136static struct GNUNET_CONTAINER_MultiShortmap *routes; 198static struct GNUNET_CONTAINER_MultiShortmap *routes;
137 199
200/**
201 * Heap of routes, MIN-sorted by last activity.
202 */
203static struct GNUNET_CONTAINER_Heap *route_heap;
204
205/**
206 * Rung zero (always pointed to by #rung_head).
207 */
208static struct Rung rung_zero;
209
210/**
211 * DLL of rungs, with the head always point to a rung of
212 * route directions with no messages in the queue.
213 */
214static struct Rung *rung_head = &rung_zero;
215
216/**
217 * Tail of the #rung_head DLL.
218 */
219static struct Rung *rung_tail = &rung_zero;
220
221/**
222 * Maximum number of concurrent routes this peer will support.
223 */
224static unsigned long long max_routes;
225
226/**
227 * Maximum number of envelopes we will buffer at this peer.
228 */
229static unsigned long long max_buffers;
230
231/**
232 * Current number of envelopes we have buffered at this peer.
233 */
234static unsigned long long cur_buffers;
235
236/**
237 * Task to timeout routes.
238 */
239static struct GNUNET_SCHEDULER_Task *timeout_task;
240
138 241
139/** 242/**
140 * Get the route corresponding to a hash. 243 * Get the route corresponding to a hash.
@@ -150,6 +253,91 @@ get_route (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
150 253
151 254
152/** 255/**
256 * Lower the rung in which @a dir is by 1.
257 *
258 * @param dir direction to lower in rung.
259 */
260static void
261lower_rung (struct RouteDirection *dir)
262{
263 struct Rung *rung = dir->rung;
264 struct Rung *prev;
265
266 GNUNET_CONTAINER_DLL_remove (rung->rd_head,
267 rung->rd_tail,
268 dir);
269 prev = rung->prev;
270 GNUNET_assert (NULL != prev);
271 if (prev->rung_off != rung->rung_off - 1)
272 {
273 prev = GNUNET_new (struct Rung);
274 prev->rung_off = rung->rung_off - 1;
275 GNUNET_CONTAINER_DLL_insert_after (rung_head,
276 rung_tail,
277 rung->prev,
278 prev);
279 }
280 GNUNET_assert (NULL != prev);
281 GNUNET_CONTAINER_DLL_insert (prev->rd_head,
282 prev->rd_tail,
283 dir);
284 dir->rung = prev;
285}
286
287
288/**
289 * Discard the buffer @a env from the route direction @a dir and
290 * move @a dir down a rung.
291 *
292 * @param dir direction that contains the @a env in the buffer
293 * @param env envelope to discard
294 */
295static void
296discard_buffer (struct RouteDirection *dir,
297 struct GNUNET_MQ_Envelope *env)
298{
299 GNUNET_MQ_dll_remove (&dir->env_head,
300 &dir->env_tail,
301 env);
302 cur_buffers--;
303 GNUNET_MQ_discard (env);
304 lower_rung (dir);
305 GNUNET_STATISTICS_set (stats,
306 "# buffer use",
307 cur_buffers,
308 GNUNET_NO);
309}
310
311
312/**
313 * Discard all messages from the highest rung, to make space.
314 */
315static void
316discard_all_from_rung_tail ()
317{
318 struct Rung *tail = rung_tail;
319 struct RouteDirection *dir;
320
321 while (NULL != (dir = tail->rd_head))
322 {
323 LOG (GNUNET_ERROR_TYPE_DEBUG,
324 "Queue full due new message %s on connection %s, dropping old message\n",
325 GNUNET_sh2s (&dir->my_route->cid.connection_of_tunnel));
326 GNUNET_STATISTICS_update (stats,
327 "# messages dropped due to full buffer",
328 1,
329 GNUNET_NO);
330 discard_buffer (dir,
331 dir->env_head);
332 }
333 GNUNET_CONTAINER_DLL_remove (rung_head,
334 rung_tail,
335 tail);
336 GNUNET_free (tail);
337}
338
339
340/**
153 * We message @a msg from @a prev. Find its route by @a cid and 341 * We message @a msg from @a prev. Find its route by @a cid and
154 * forward to the next hop. Drop and signal broken route if we do not 342 * forward to the next hop. Drop and signal broken route if we do not
155 * have a route. 343 * have a route.
@@ -165,6 +353,8 @@ route_message (struct CadetPeer *prev,
165{ 353{
166 struct CadetRoute *route; 354 struct CadetRoute *route;
167 struct RouteDirection *dir; 355 struct RouteDirection *dir;
356 struct Rung *rung;
357 struct Rung *nxt;
168 struct GNUNET_MQ_Envelope *env; 358 struct GNUNET_MQ_Envelope *env;
169 359
170 route = get_route (cid); 360 route = get_route (cid);
@@ -178,6 +368,13 @@ route_message (struct CadetPeer *prev,
178 ntohs (msg->type), 368 ntohs (msg->type),
179 GCP_2s (prev), 369 GCP_2s (prev),
180 GNUNET_sh2s (&cid->connection_of_tunnel)); 370 GNUNET_sh2s (&cid->connection_of_tunnel));
371 switch (ntohs (msg->type))
372 {
373 case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY:
374 case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN:
375 /* No need to respond to these! */
376 return;
377 }
181 env = GNUNET_MQ_msg (bm, 378 env = GNUNET_MQ_msg (bm,
182 GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN); 379 GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN);
183 bm->cid = *cid; 380 bm->cid = *cid;
@@ -186,6 +383,9 @@ route_message (struct CadetPeer *prev,
186 env); 383 env);
187 return; 384 return;
188 } 385 }
386 route->last_use = GNUNET_TIME_absolute_get ();
387 GNUNET_CONTAINER_heap_update_cost (route->hn,
388 route->last_use.abs_value_us);
189 dir = (prev == route->prev.hop) ? &route->next : &route->prev; 389 dir = (prev == route->prev.hop) ? &route->next : &route->prev;
190 if (GNUNET_YES == dir->is_ready) 390 if (GNUNET_YES == dir->is_ready)
191 { 391 {
@@ -200,22 +400,59 @@ route_message (struct CadetPeer *prev,
200 GNUNET_MQ_msg_copy (msg)); 400 GNUNET_MQ_msg_copy (msg));
201 return; 401 return;
202 } 402 }
203 env = dir->out_buffer[dir->out_wpos]; 403 /* Check if buffering is disallowed, and if so, make sure we only queue
204 if (NULL != env) 404 one message per direction. */
405 if ( (0 != (route->options & GNUNET_CADET_OPTION_NOBUFFER)) &&
406 (NULL != dir->env_head) )
407 discard_buffer (dir,
408 dir->env_head);
409 rung = dir->rung;
410 if (cur_buffers == max_buffers)
205 { 411 {
206 /* Queue full, drop earliest message in queue */ 412 /* Need to make room. */
207 LOG (GNUNET_ERROR_TYPE_DEBUG, 413 if (NULL != rung->next)
208 "Queue full due to new message of type %u from %s to %s on connection %s, dropping old message\n", 414 {
209 ntohs (msg->type), 415 /* Easy case, drop messages from route directions in highest rung */
210 GCP_2s (prev), 416 discard_all_from_rung_tail ();
211 GNUNET_i2s (GCP_get_id (dir->hop)), 417 }
212 GNUNET_sh2s (&cid->connection_of_tunnel)); 418 else
213 GNUNET_assert (dir->out_rpos == dir->out_wpos); 419 {
214 GNUNET_MQ_discard (env); 420 /* We are in the highest rung, drop our own! */
215 dir->out_rpos++; 421 LOG (GNUNET_ERROR_TYPE_DEBUG,
216 if (ROUTE_BUFFER_SIZE == dir->out_rpos) 422 "Queue full due new message %s on connection %s, dropping old message\n",
217 dir->out_rpos = 0; 423 GNUNET_sh2s (&dir->my_route->cid.connection_of_tunnel));
424 GNUNET_STATISTICS_update (stats,
425 "# messages dropped due to full buffer",
426 1,
427 GNUNET_NO);
428 discard_buffer (dir,
429 dir->env_head);
430 rung = dir->rung;
431 }
432 }
433 /* remove 'dir' from current rung */
434 GNUNET_CONTAINER_DLL_remove (rung->rd_head,
435 rung->rd_tail,
436 dir);
437 /* make 'nxt' point to the next higher rung, creat if necessary */
438 nxt = rung->next;
439 if ( (NULL == nxt) ||
440 (rung->rung_off + 1 != nxt->rung_off) )
441 {
442 nxt = GNUNET_new (struct Rung);
443 nxt->rung_off = rung->rung_off + 1;
444 GNUNET_CONTAINER_DLL_insert_after (rung_head,
445 rung_tail,
446 rung,
447 nxt);
218 } 448 }
449 /* insert 'dir' into next higher rung */
450 GNUNET_CONTAINER_DLL_insert (nxt->rd_head,
451 nxt->rd_tail,
452 dir);
453 dir->rung = nxt;
454
455 /* add message into 'dir' buffer */
219 LOG (GNUNET_ERROR_TYPE_DEBUG, 456 LOG (GNUNET_ERROR_TYPE_DEBUG,
220 "Queueing new message of type %u from %s to %s on connection %s\n", 457 "Queueing new message of type %u from %s to %s on connection %s\n",
221 ntohs (msg->type), 458 ntohs (msg->type),
@@ -223,10 +460,23 @@ route_message (struct CadetPeer *prev,
223 GNUNET_i2s (GCP_get_id (dir->hop)), 460 GNUNET_i2s (GCP_get_id (dir->hop)),
224 GNUNET_sh2s (&cid->connection_of_tunnel)); 461 GNUNET_sh2s (&cid->connection_of_tunnel));
225 env = GNUNET_MQ_msg_copy (msg); 462 env = GNUNET_MQ_msg_copy (msg);
226 dir->out_buffer[dir->out_wpos] = env; 463 GNUNET_MQ_dll_insert_tail (&dir->env_head,
227 dir->out_wpos++; 464 &dir->env_tail,
228 if (ROUTE_BUFFER_SIZE == dir->out_wpos) 465 env);
229 dir->out_wpos = 0; 466 cur_buffers++;
467 GNUNET_STATISTICS_set (stats,
468 "# buffer use",
469 cur_buffers,
470 GNUNET_NO);
471 /* Clean up 'rung' if now empty (and not head) */
472 if ( (NULL == rung->rd_head) &&
473 (rung != rung_head) )
474 {
475 GNUNET_CONTAINER_DLL_remove (rung_head,
476 rung_tail,
477 rung);
478 GNUNET_free (rung);
479 }
230} 480}
231 481
232 482
@@ -261,18 +511,26 @@ check_connection_create (void *cls,
261static void 511static void
262destroy_direction (struct RouteDirection *dir) 512destroy_direction (struct RouteDirection *dir)
263{ 513{
264 for (unsigned int i=0;i<ROUTE_BUFFER_SIZE;i++) 514 struct GNUNET_MQ_Envelope *env;
265 if (NULL != dir->out_buffer[i]) 515
266 { 516 while (NULL != (env = dir->env_head))
267 GNUNET_MQ_discard (dir->out_buffer[i]); 517 {
268 dir->out_buffer[i] = NULL; 518 GNUNET_STATISTICS_update (stats,
269 } 519 "# messages dropped due to route destruction",
520 1,
521 GNUNET_NO);
522 discard_buffer (dir,
523 env);
524 }
270 if (NULL != dir->mqm) 525 if (NULL != dir->mqm)
271 { 526 {
272 GCP_request_mq_cancel (dir->mqm, 527 GCP_request_mq_cancel (dir->mqm,
273 NULL); 528 NULL);
274 dir->mqm = NULL; 529 dir->mqm = NULL;
275 } 530 }
531 GNUNET_CONTAINER_DLL_remove (rung_head->rd_head,
532 rung_head->rd_tail,
533 dir);
276} 534}
277 535
278 536
@@ -289,6 +547,16 @@ destroy_route (struct CadetRoute *route)
289 GNUNET_i2s (GCP_get_id (route->prev.hop)), 547 GNUNET_i2s (GCP_get_id (route->prev.hop)),
290 GNUNET_i2s2 (GCP_get_id (route->next.hop)), 548 GNUNET_i2s2 (GCP_get_id (route->next.hop)),
291 GNUNET_sh2s (&route->cid.connection_of_tunnel)); 549 GNUNET_sh2s (&route->cid.connection_of_tunnel));
550 GNUNET_assert (route ==
551 GNUNET_CONTAINER_heap_remove_node (route->hn));
552 GNUNET_assert (GNUNET_YES ==
553 GNUNET_CONTAINER_multishortmap_remove (routes,
554 &route->cid.connection_of_tunnel,
555 route));
556 GNUNET_STATISTICS_set (stats,
557 "# routes",
558 GNUNET_CONTAINER_multishortmap_size (routes),
559 GNUNET_NO);
292 destroy_direction (&route->prev); 560 destroy_direction (&route->prev);
293 destroy_direction (&route->next); 561 destroy_direction (&route->next);
294 GNUNET_free (route); 562 GNUNET_free (route);
@@ -328,7 +596,6 @@ send_broken (struct RouteDirection *target,
328 bm->peer1 = *peer1; 596 bm->peer1 = *peer1;
329 if (NULL != peer2) 597 if (NULL != peer2)
330 bm->peer2 = *peer2; 598 bm->peer2 = *peer2;
331
332 GCP_request_mq_cancel (target->mqm, 599 GCP_request_mq_cancel (target->mqm,
333 env); 600 env);
334 target->mqm = NULL; 601 target->mqm = NULL;
@@ -336,6 +603,49 @@ send_broken (struct RouteDirection *target,
336 603
337 604
338/** 605/**
606 * Function called to check if any routes have timed out, and if
607 * so, to clean them up. Finally, schedules itself again at the
608 * earliest time where there might be more work.
609 *
610 * @param cls NULL
611 */
612static void
613timeout_cb (void *cls)
614{
615 struct CadetRoute *r;
616 struct GNUNET_TIME_Relative linger;
617 struct GNUNET_TIME_Absolute exp;
618
619 timeout_task = NULL;
620 linger = GNUNET_TIME_relative_multiply (keepalive_period,
621 3);
622 while (NULL != (r = GNUNET_CONTAINER_heap_peek (route_heap)))
623 {
624 exp = GNUNET_TIME_absolute_add (r->last_use,
625 linger);
626 if (0 != GNUNET_TIME_absolute_get_duration (exp).rel_value_us)
627 {
628 /* Route not yet timed out, wait until it does. */
629 timeout_task = GNUNET_SCHEDULER_add_at (exp,
630 &timeout_cb,
631 NULL);
632 return;
633 }
634 send_broken (&r->prev,
635 &r->cid,
636 NULL,
637 NULL);
638 send_broken (&r->next,
639 &r->cid,
640 NULL,
641 NULL);
642 destroy_route (r);
643 }
644 /* No more routes left, so no need for a #timeout_task */
645}
646
647
648/**
339 * Function called when the message queue to the previous hop 649 * Function called when the message queue to the previous hop
340 * becomes available/unavailable. We expect this function to 650 * becomes available/unavailable. We expect this function to
341 * be called immediately when we register, and then again 651 * be called immediately when we register, and then again
@@ -360,12 +670,17 @@ dir_ready_cb (void *cls,
360 struct GNUNET_MQ_Envelope *env; 670 struct GNUNET_MQ_Envelope *env;
361 671
362 dir->is_ready = GNUNET_YES; 672 dir->is_ready = GNUNET_YES;
363 if (NULL != (env = dir->out_buffer[dir->out_rpos])) 673 if (NULL != (env = dir->env_head))
364 { 674 {
365 dir->out_buffer[dir->out_rpos] = NULL; 675 GNUNET_MQ_dll_remove (&dir->env_head,
366 dir->out_rpos++; 676 &dir->env_tail,
367 if (ROUTE_BUFFER_SIZE == dir->out_rpos) 677 env);
368 dir->out_rpos = 0; 678 cur_buffers--;
679 GNUNET_STATISTICS_set (stats,
680 "# buffer use",
681 cur_buffers,
682 GNUNET_NO);
683 lower_rung (dir);
369 dir->is_ready = GNUNET_NO; 684 dir->is_ready = GNUNET_NO;
370 GCP_send (dir->mqm, 685 GCP_send (dir->mqm,
371 env); 686 env);
@@ -398,11 +713,44 @@ dir_init (struct RouteDirection *dir,
398 dir->mqm = GCP_request_mq (hop, 713 dir->mqm = GCP_request_mq (hop,
399 &dir_ready_cb, 714 &dir_ready_cb,
400 dir); 715 dir);
716 GNUNET_CONTAINER_DLL_insert (rung_head->rd_head,
717 rung_head->rd_tail,
718 dir);
719 dir->rung = rung_head;
401 GNUNET_assert (GNUNET_YES == dir->is_ready); 720 GNUNET_assert (GNUNET_YES == dir->is_ready);
402} 721}
403 722
404 723
405/** 724/**
725 * We could not create the desired route. Send a
726 * #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN
727 * message to @a target.
728 *
729 * @param target who should receive the message
730 * @param cid identifier of the connection/route that failed
731 * @param failure_at neighbour with which we failed to route,
732 * or NULL.
733 */
734static void
735send_broken_without_mqm (struct CadetPeer *target,
736 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
737 const struct GNUNET_PeerIdentity *failure_at)
738{
739 struct GNUNET_MQ_Envelope *env;
740 struct GNUNET_CADET_ConnectionBrokenMessage *bm;
741
742 env = GNUNET_MQ_msg (bm,
743 GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN);
744 bm->cid = *cid;
745 bm->peer1 = my_full_id;
746 if (NULL != failure_at)
747 bm->peer2 = *failure_at;
748 GCP_send_ooo (target,
749 env);
750}
751
752
753/**
406 * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE 754 * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE
407 * 755 *
408 * @param cls Closure (CadetPeer for neighbor that sent the message). 756 * @param cls Closure (CadetPeer for neighbor that sent the message).
@@ -419,7 +767,9 @@ handle_connection_create (void *cls,
419 uint16_t size = ntohs (msg->header.size) - sizeof (*msg); 767 uint16_t size = ntohs (msg->header.size) - sizeof (*msg);
420 unsigned int path_length; 768 unsigned int path_length;
421 unsigned int off; 769 unsigned int off;
770 enum GNUNET_CADET_ChannelOption options;
422 771
772 options = (enum GNUNET_CADET_ChannelOption) ntohl (msg->options);
423 path_length = size / sizeof (struct GNUNET_PeerIdentity); 773 path_length = size / sizeof (struct GNUNET_PeerIdentity);
424 /* Initiator is at offset 0. */ 774 /* Initiator is at offset 0. */
425 for (off=1;off<path_length;off++) 775 for (off=1;off<path_length;off++)
@@ -460,8 +810,7 @@ handle_connection_create (void *cls,
460 struct CadetPeerPath *path; 810 struct CadetPeerPath *path;
461 struct CadetPeer *origin; 811 struct CadetPeer *origin;
462 812
463 cc = GNUNET_CONTAINER_multishortmap_get (connections, 813 cc = GCC_lookup (&msg->cid);
464 &msg->cid.connection_of_tunnel);
465 if (NULL != cc) 814 if (NULL != cc)
466 { 815 {
467 LOG (GNUNET_ERROR_TYPE_DEBUG, 816 LOG (GNUNET_ERROR_TYPE_DEBUG,
@@ -479,10 +828,25 @@ handle_connection_create (void *cls,
479 GNUNET_sh2s (&msg->cid.connection_of_tunnel)); 828 GNUNET_sh2s (&msg->cid.connection_of_tunnel));
480 path = GCPP_get_path_from_route (path_length - 1, 829 path = GCPP_get_path_from_route (path_length - 1,
481 pids); 830 pids);
482 GCT_add_inbound_connection (GCP_get_tunnel (origin, 831 if (GNUNET_OK !=
483 GNUNET_YES), 832 GCT_add_inbound_connection (GCP_get_tunnel (origin,
484 &msg->cid, 833 GNUNET_YES),
485 path); 834 &msg->cid,
835 (enum GNUNET_CADET_ChannelOption) ntohl (msg->options),
836 path))
837 {
838 /* Send back BROKEN: duplicate connection on the same path,
839 we will use the other one. */
840 LOG (GNUNET_ERROR_TYPE_DEBUG,
841 "Received CADET_CONNECTION_CREATE from %s for %s, but %s already has a connection. Sending BROKEN\n",
842 GCP_2s (sender),
843 GNUNET_sh2s (&msg->cid.connection_of_tunnel),
844 GCPP_2s (path));
845 send_broken_without_mqm (sender,
846 &msg->cid,
847 NULL);
848 return;
849 }
486 return; 850 return;
487 } 851 }
488 /* We are merely a hop on the way, check if we can support the route */ 852 /* We are merely a hop on the way, check if we can support the route */
@@ -492,22 +856,26 @@ handle_connection_create (void *cls,
492 (GNUNET_NO == GCP_has_core_connection (next)) ) 856 (GNUNET_NO == GCP_has_core_connection (next)) )
493 { 857 {
494 /* unworkable, send back BROKEN notification */ 858 /* unworkable, send back BROKEN notification */
495 struct GNUNET_MQ_Envelope *env;
496 struct GNUNET_CADET_ConnectionBrokenMessage *bm;
497
498 LOG (GNUNET_ERROR_TYPE_DEBUG, 859 LOG (GNUNET_ERROR_TYPE_DEBUG,
499 "Received CADET_CONNECTION_CREATE from %s for %s. Next hop %s:%u is down. Sending BROKEN\n", 860 "Received CADET_CONNECTION_CREATE from %s for %s. Next hop %s:%u is down. Sending BROKEN\n",
500 GCP_2s (sender), 861 GCP_2s (sender),
501 GNUNET_sh2s (&msg->cid.connection_of_tunnel), 862 GNUNET_sh2s (&msg->cid.connection_of_tunnel),
502 GNUNET_i2s (&pids[off + 1]), 863 GNUNET_i2s (&pids[off + 1]),
503 off + 1); 864 off + 1);
504 env = GNUNET_MQ_msg (bm, 865 send_broken_without_mqm (sender,
505 GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN); 866 &msg->cid,
506 bm->cid = msg->cid; 867 &pids[off + 1]);
507 bm->peer1 = pids[off + 1]; 868 return;
508 bm->peer2 = my_full_id; 869 }
509 GCP_send_ooo (sender, 870 if (max_routes <= GNUNET_CONTAINER_multishortmap_size (routes))
510 env); 871 {
872 LOG (GNUNET_ERROR_TYPE_DEBUG,
873 "Received CADET_CONNECTION_CREATE from %s for %s. We have reached our route limit. Sending BROKEN\n",
874 GCP_2s (sender),
875 GNUNET_sh2s (&msg->cid.connection_of_tunnel));
876 send_broken_without_mqm (sender,
877 &msg->cid,
878 &pids[off - 1]);
511 return; 879 return;
512 } 880 }
513 881
@@ -519,7 +887,9 @@ handle_connection_create (void *cls,
519 GNUNET_i2s (&pids[off + 1]), 887 GNUNET_i2s (&pids[off + 1]),
520 off + 1); 888 off + 1);
521 route = GNUNET_new (struct CadetRoute); 889 route = GNUNET_new (struct CadetRoute);
890 route->options = options;
522 route->cid = msg->cid; 891 route->cid = msg->cid;
892 route->last_use = GNUNET_TIME_absolute_get ();
523 dir_init (&route->prev, 893 dir_init (&route->prev,
524 route, 894 route,
525 sender); 895 sender);
@@ -531,6 +901,18 @@ handle_connection_create (void *cls,
531 &route->cid.connection_of_tunnel, 901 &route->cid.connection_of_tunnel,
532 route, 902 route,
533 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); 903 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
904 GNUNET_STATISTICS_set (stats,
905 "# routes",
906 GNUNET_CONTAINER_multishortmap_size (routes),
907 GNUNET_NO);
908 route->hn = GNUNET_CONTAINER_heap_insert (route_heap,
909 route,
910 route->last_use.abs_value_us);
911 if (NULL == timeout_task)
912 timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (keepalive_period,
913 3),
914 &timeout_cb,
915 NULL);
534} 916}
535 917
536 918
@@ -548,8 +930,7 @@ handle_connection_create_ack (void *cls,
548 struct CadetConnection *cc; 930 struct CadetConnection *cc;
549 931
550 /* First, check if ACK belongs to a connection that ends here. */ 932 /* First, check if ACK belongs to a connection that ends here. */
551 cc = GNUNET_CONTAINER_multishortmap_get (connections, 933 cc = GCC_lookup (&msg->cid);
552 &msg->cid.connection_of_tunnel);
553 if (NULL != cc) 934 if (NULL != cc)
554 { 935 {
555 /* verify ACK came from the right direction */ 936 /* verify ACK came from the right direction */
@@ -593,8 +974,7 @@ handle_connection_broken (void *cls,
593 struct CadetRoute *route; 974 struct CadetRoute *route;
594 975
595 /* First, check if message belongs to a connection that ends here. */ 976 /* First, check if message belongs to a connection that ends here. */
596 cc = GNUNET_CONTAINER_multishortmap_get (connections, 977 cc = GCC_lookup (&msg->cid);
597 &msg->cid.connection_of_tunnel);
598 if (NULL != cc) 978 if (NULL != cc)
599 { 979 {
600 /* verify message came from the right direction */ 980 /* verify message came from the right direction */
@@ -611,18 +991,19 @@ handle_connection_broken (void *cls,
611 LOG (GNUNET_ERROR_TYPE_DEBUG, 991 LOG (GNUNET_ERROR_TYPE_DEBUG,
612 "Received CONNECTION_BROKEN for connection %s. Destroying it.\n", 992 "Received CONNECTION_BROKEN for connection %s. Destroying it.\n",
613 GNUNET_sh2s (&msg->cid.connection_of_tunnel)); 993 GNUNET_sh2s (&msg->cid.connection_of_tunnel));
614 GCC_destroy (cc); 994 GCC_destroy_without_core (cc);
615 995
616 /* FIXME: also destroy the path up to the specified link! */ 996 /* FIXME: also destroy the path up to the specified link! */
617 return; 997 return;
618 } 998 }
619 999
620 /* We're just an intermediary peer, route the message along its path */ 1000 /* We're just an intermediary peer, route the message along its path */
621 route = get_route (&msg->cid);
622 route_message (peer, 1001 route_message (peer,
623 &msg->cid, 1002 &msg->cid,
624 &msg->header); 1003 &msg->header);
625 destroy_route (route); 1004 route = get_route (&msg->cid);
1005 if (NULL != route)
1006 destroy_route (route);
626 /* FIXME: also destroy paths we MAY have up to the specified link! */ 1007 /* FIXME: also destroy paths we MAY have up to the specified link! */
627} 1008}
628 1009
@@ -642,8 +1023,7 @@ handle_connection_destroy (void *cls,
642 struct CadetRoute *route; 1023 struct CadetRoute *route;
643 1024
644 /* First, check if message belongs to a connection that ends here. */ 1025 /* First, check if message belongs to a connection that ends here. */
645 cc = GNUNET_CONTAINER_multishortmap_get (connections, 1026 cc = GCC_lookup (&msg->cid);
646 &msg->cid.connection_of_tunnel);
647 if (NULL != cc) 1027 if (NULL != cc)
648 { 1028 {
649 /* verify message came from the right direction */ 1029 /* verify message came from the right direction */
@@ -661,7 +1041,7 @@ handle_connection_destroy (void *cls,
661 "Received CONNECTION_DESTROY for connection %s. Destroying connection.\n", 1041 "Received CONNECTION_DESTROY for connection %s. Destroying connection.\n",
662 GNUNET_sh2s (&msg->cid.connection_of_tunnel)); 1042 GNUNET_sh2s (&msg->cid.connection_of_tunnel));
663 1043
664 GCC_destroy (cc); 1044 GCC_destroy_without_core (cc);
665 return; 1045 return;
666 } 1046 }
667 1047
@@ -669,11 +1049,12 @@ handle_connection_destroy (void *cls,
669 LOG (GNUNET_ERROR_TYPE_DEBUG, 1049 LOG (GNUNET_ERROR_TYPE_DEBUG,
670 "Received CONNECTION_DESTROY for connection %s. Destroying route.\n", 1050 "Received CONNECTION_DESTROY for connection %s. Destroying route.\n",
671 GNUNET_sh2s (&msg->cid.connection_of_tunnel)); 1051 GNUNET_sh2s (&msg->cid.connection_of_tunnel));
672 route = get_route (&msg->cid);
673 route_message (peer, 1052 route_message (peer,
674 &msg->cid, 1053 &msg->cid,
675 &msg->header); 1054 &msg->header);
676 destroy_route (route); 1055 route = get_route (&msg->cid);
1056 if (NULL != route)
1057 destroy_route (route);
677} 1058}
678 1059
679 1060
@@ -691,8 +1072,7 @@ handle_tunnel_kx (void *cls,
691 struct CadetConnection *cc; 1072 struct CadetConnection *cc;
692 1073
693 /* First, check if message belongs to a connection that ends here. */ 1074 /* First, check if message belongs to a connection that ends here. */
694 cc = GNUNET_CONTAINER_multishortmap_get (connections, 1075 cc = GCC_lookup (&msg->cid);
695 &msg->cid.connection_of_tunnel);
696 if (NULL != cc) 1076 if (NULL != cc)
697 { 1077 {
698 /* verify message came from the right direction */ 1078 /* verify message came from the right direction */
@@ -719,6 +1099,46 @@ handle_tunnel_kx (void *cls,
719 1099
720 1100
721/** 1101/**
1102 * Handle for #GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX_AUTH
1103 *
1104 * @param cls Closure (CadetPeer for neighbor that sent the message).
1105 * @param msg Message itself.
1106 */
1107static void
1108handle_tunnel_kx_auth (void *cls,
1109 const struct GNUNET_CADET_TunnelKeyExchangeAuthMessage *msg)
1110{
1111 struct CadetPeer *peer = cls;
1112 struct CadetConnection *cc;
1113
1114 /* First, check if message belongs to a connection that ends here. */
1115 cc = GCC_lookup (&msg->kx.cid);
1116 if (NULL != cc)
1117 {
1118 /* verify message came from the right direction */
1119 struct CadetPeerPath *path = GCC_get_path (cc);
1120
1121 if (peer !=
1122 GCPP_get_peer_at_offset (path,
1123 0))
1124 {
1125 /* received message from unexpected direction, ignore! */
1126 GNUNET_break_op (0);
1127 return;
1128 }
1129 GCC_handle_kx_auth (cc,
1130 msg);
1131 return;
1132 }
1133
1134 /* We're just an intermediary peer, route the message along its path */
1135 route_message (peer,
1136 &msg->kx.cid,
1137 &msg->kx.header);
1138}
1139
1140
1141/**
722 * Check if the encrypted message has the appropriate size. 1142 * Check if the encrypted message has the appropriate size.
723 * 1143 *
724 * @param cls Closure (unused). 1144 * @param cls Closure (unused).
@@ -748,8 +1168,7 @@ handle_tunnel_encrypted (void *cls,
748 struct CadetConnection *cc; 1168 struct CadetConnection *cc;
749 1169
750 /* First, check if message belongs to a connection that ends here. */ 1170 /* First, check if message belongs to a connection that ends here. */
751 cc = GNUNET_CONTAINER_multishortmap_get (connections, 1171 cc = GCC_lookup (&msg->cid);
752 &msg->cid.connection_of_tunnel);
753 if (NULL != cc) 1172 if (NULL != cc)
754 { 1173 {
755 /* verify message came from the right direction */ 1174 /* verify message came from the right direction */
@@ -876,6 +1295,10 @@ GCO_init (const struct GNUNET_CONFIGURATION_Handle *c)
876 GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX, 1295 GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX,
877 struct GNUNET_CADET_TunnelKeyExchangeMessage, 1296 struct GNUNET_CADET_TunnelKeyExchangeMessage,
878 NULL), 1297 NULL),
1298 GNUNET_MQ_hd_fixed_size (tunnel_kx_auth,
1299 GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX_AUTH,
1300 struct GNUNET_CADET_TunnelKeyExchangeAuthMessage,
1301 NULL),
879 GNUNET_MQ_hd_var_size (tunnel_encrypted, 1302 GNUNET_MQ_hd_var_size (tunnel_encrypted,
880 GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED, 1303 GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED,
881 struct GNUNET_CADET_TunnelEncryptedMessage, 1304 struct GNUNET_CADET_TunnelEncryptedMessage,
@@ -883,8 +1306,21 @@ GCO_init (const struct GNUNET_CONFIGURATION_Handle *c)
883 GNUNET_MQ_handler_end () 1306 GNUNET_MQ_handler_end ()
884 }; 1307 };
885 1308
1309 if (GNUNET_OK !=
1310 GNUNET_CONFIGURATION_get_value_number (c,
1311 "CADET",
1312 "MAX_ROUTES",
1313 &max_routes))
1314 max_routes = 5000;
1315 if (GNUNET_OK !=
1316 GNUNET_CONFIGURATION_get_value_number (c,
1317 "CADET",
1318 "MAX_MSGS_QUEUE",
1319 &max_buffers))
1320 max_buffers = 10000;
886 routes = GNUNET_CONTAINER_multishortmap_create (1024, 1321 routes = GNUNET_CONTAINER_multishortmap_create (1024,
887 GNUNET_NO); 1322 GNUNET_NO);
1323 route_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
888 core = GNUNET_CORE_connect (c, 1324 core = GNUNET_CORE_connect (c,
889 NULL, 1325 NULL,
890 &core_init_cb, 1326 &core_init_cb,
@@ -907,6 +1343,14 @@ GCO_shutdown ()
907 } 1343 }
908 GNUNET_assert (0 == GNUNET_CONTAINER_multishortmap_size (routes)); 1344 GNUNET_assert (0 == GNUNET_CONTAINER_multishortmap_size (routes));
909 GNUNET_CONTAINER_multishortmap_destroy (routes); 1345 GNUNET_CONTAINER_multishortmap_destroy (routes);
1346 routes = NULL;
1347 GNUNET_CONTAINER_heap_destroy (route_heap);
1348 route_heap = NULL;
1349 if (NULL != timeout_task)
1350 {
1351 GNUNET_SCHEDULER_cancel (timeout_task);
1352 timeout_task = NULL;
1353 }
910} 1354}
911 1355
912/* end of gnunet-cadet-service_core.c */ 1356/* end of gnunet-cadet-service_core.c */
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 685656ec3..13752643c 100644
--- a/src/cadet/gnunet-service-cadet-new_paths.c
+++ b/src/cadet/gnunet-service-cadet_paths.c
@@ -18,18 +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 *
26 * TODO:
27 * - path desirability score calculations are not done
28 */ 25 */
29#include "platform.h" 26#include "platform.h"
30#include "gnunet-service-cadet-new_connection.h" 27#include "gnunet-service-cadet_connection.h"
31#include "gnunet-service-cadet-new_peer.h" 28#include "gnunet-service-cadet_tunnels.h"
32#include "gnunet-service-cadet-new_paths.h" 29#include "gnunet-service-cadet_peer.h"
30#include "gnunet-service-cadet_paths.h"
33 31
34 32
35#define LOG(level, ...) GNUNET_log_from(level,"cadet-pat",__VA_ARGS__) 33#define LOG(level, ...) GNUNET_log_from(level,"cadet-pat",__VA_ARGS__)
@@ -75,8 +73,16 @@ struct CadetPeerPath
75static void 73static void
76recalculate_path_desirability (struct CadetPeerPath *path) 74recalculate_path_desirability (struct CadetPeerPath *path)
77{ 75{
78 /* FIXME: update path desirability! */ 76 double result = 0.0;
79 GNUNET_break (0); // not implemented 77
78 for (unsigned int i=0;i<path->entries_length;i++)
79 {
80 struct CadetPeer *cp = path->entries[i]->peer;
81
82 result += GCP_get_desirability_of_path (cp,
83 i);
84 }
85 path->desirability = (GNUNET_CONTAINER_HeapCostType) result;
80} 86}
81 87
82 88
@@ -147,6 +153,7 @@ GCPP_add_connection (struct CadetPeerPath *path,
147 GNUNET_assert (off < path->entries_length); 153 GNUNET_assert (off < path->entries_length);
148 entry = path->entries[off]; 154 entry = path->entries[off];
149 GNUNET_assert (NULL == entry->cc); 155 GNUNET_assert (NULL == entry->cc);
156 GNUNET_assert (NULL != cc);
150 entry->cc = cc; 157 entry->cc = cc;
151} 158}
152 159
@@ -191,7 +198,20 @@ path_destroy (struct CadetPeerPath *path)
191 "Destroying path %s\n", 198 "Destroying path %s\n",
192 GCPP_2s (path)); 199 GCPP_2s (path));
193 for (unsigned int i=0;i<path->entries_length;i++) 200 for (unsigned int i=0;i<path->entries_length;i++)
194 GNUNET_free (path->entries[i]); 201 {
202 struct CadetPeerPathEntry *entry = path->entries[i];
203
204 if (NULL != entry->cc)
205 {
206 struct CadetTConnection *ct;
207
208 ct = GCC_get_ct (entry->cc);
209 if (NULL != ct)
210 GCT_connection_lost (ct);
211 GCC_destroy_without_tunnel (entry->cc);
212 }
213 GNUNET_free (entry);
214 }
195 GNUNET_free (path->entries); 215 GNUNET_free (path->entries);
196 GNUNET_free (path); 216 GNUNET_free (path);
197} 217}
@@ -208,15 +228,18 @@ void
208GCPP_release (struct CadetPeerPath *path) 228GCPP_release (struct CadetPeerPath *path)
209{ 229{
210 struct CadetPeerPathEntry *entry; 230 struct CadetPeerPathEntry *entry;
231 int force;
211 232
212 LOG (GNUNET_ERROR_TYPE_DEBUG, 233 LOG (GNUNET_ERROR_TYPE_DEBUG,
213 "Owner releases path %s\n", 234 "Owner releases path %s\n",
214 GCPP_2s (path)); 235 GCPP_2s (path));
215 path->hn = NULL; 236 path->hn = NULL;
216 entry = path->entries[path->entries_length - 1]; 237 entry = path->entries[path->entries_length - 1];
238 GNUNET_assert (path == entry->path);
217 while (1) 239 while (1)
218 { 240 {
219 /* cut 'off' end of path */ 241 /* cut 'off' end of path */
242 GNUNET_assert (NULL == entry->cc);
220 GCP_path_entry_remove (entry->peer, 243 GCP_path_entry_remove (entry->peer,
221 entry, 244 entry,
222 path->entries_length - 1); 245 path->entries_length - 1);
@@ -228,12 +251,15 @@ GCPP_release (struct CadetPeerPath *path)
228 251
229 /* see if new peer at the end likes this path any better */ 252 /* see if new peer at the end likes this path any better */
230 entry = path->entries[path->entries_length - 1]; 253 entry = path->entries[path->entries_length - 1];
254 GNUNET_assert (path == entry->path);
255 force = (NULL == entry->cc) ? GNUNET_NO : GNUNET_YES;
231 path->hn = GCP_attach_path (entry->peer, 256 path->hn = GCP_attach_path (entry->peer,
232 path, 257 path,
233 path->entries_length - 1, 258 path->entries_length - 1,
234 GNUNET_NO); 259 force);
235 if (NULL != path->hn) 260 if (NULL != path->hn)
236 return; /* yep, got attached, we are done. */ 261 return; /* yep, got attached, we are done. */
262 GNUNET_assert (GNUNET_NO == force);
237 } 263 }
238 264
239 /* nobody wants us, discard the path */ 265 /* nobody wants us, discard the path */
@@ -367,7 +393,6 @@ extend_path (struct CadetPeerPath *path,
367 int force) 393 int force)
368{ 394{
369 unsigned int old_len = path->entries_length; 395 unsigned int old_len = path->entries_length;
370 struct GNUNET_CONTAINER_HeapNode *hn;
371 int i; 396 int i;
372 397
373 /* Expand path */ 398 /* Expand path */
@@ -393,38 +418,43 @@ extend_path (struct CadetPeerPath *path,
393 418
394 /* If we extend an existing path, detach it from the 419 /* If we extend an existing path, detach it from the
395 old owner and re-attach to the new one */ 420 old owner and re-attach to the new one */
396 hn = NULL; 421 GCP_detach_path (path->entries[old_len-1]->peer,
422 path,
423 path->hn);
424 path->hn = NULL;
397 for (i=num_peers-1;i>=0;i--) 425 for (i=num_peers-1;i>=0;i--)
398 { 426 {
399 struct CadetPeerPathEntry *entry = path->entries[old_len + i]; 427 struct CadetPeerPathEntry *entry = path->entries[old_len + i];
400 428
401 path->entries_length = old_len + i + 1; 429 path->entries_length = old_len + i + 1;
402 recalculate_path_desirability (path); 430 recalculate_path_desirability (path);
403 hn = GCP_attach_path (peers[i], 431 path->hn = GCP_attach_path (peers[i],
404 path, 432 path,
405 old_len + (unsigned int) i, 433 old_len + (unsigned int) i,
406 GNUNET_YES); 434 force);
407 if (NULL != hn) 435 if (NULL != path->hn)
408 break; 436 break;
437 GNUNET_assert (NULL == entry->cc);
409 GCP_path_entry_remove (entry->peer, 438 GCP_path_entry_remove (entry->peer,
410 entry, 439 entry,
411 old_len + i); 440 old_len + i);
412 GNUNET_free (entry); 441 GNUNET_free (entry);
413 path->entries[old_len + i] = NULL; 442 path->entries[old_len + i] = NULL;
414 } 443 }
415 if (NULL == hn) 444 if (NULL == path->hn)
416 { 445 {
417 /* none of the peers is interested in this path; 446 /* none of the peers is interested in this path;
418 shrink path back */ 447 shrink path back and re-attach. */
419 GNUNET_array_grow (path->entries, 448 GNUNET_array_grow (path->entries,
420 path->entries_length, 449 path->entries_length,
421 old_len); 450 old_len);
451 path->hn = GCP_attach_path (path->entries[old_len - 1]->peer,
452 path,
453 old_len - 1,
454 GNUNET_YES);
455 GNUNET_assert (NULL != path->hn);
422 return; 456 return;
423 } 457 }
424 GCP_detach_path (path->entries[old_len-1]->peer,
425 path,
426 path->hn);
427 path->hn = hn;
428 LOG (GNUNET_ERROR_TYPE_DEBUG, 458 LOG (GNUNET_ERROR_TYPE_DEBUG,
429 "Extended path %s\n", 459 "Extended path %s\n",
430 GCPP_2s (path)); 460 GCPP_2s (path));
@@ -454,25 +484,42 @@ GCPP_try_path_from_dht (const struct GNUNET_PeerIdentity *get_path,
454 struct CadetPeerPath *path; 484 struct CadetPeerPath *path;
455 struct GNUNET_CONTAINER_HeapNode *hn; 485 struct GNUNET_CONTAINER_HeapNode *hn;
456 int i; 486 int i;
487 unsigned int skip;
488 unsigned int total_len;
457 489
458 /* precompute 'cpath' so we can avoid doing the lookups lots of times */ 490 /* precompute 'cpath' so we can avoid doing the lookups lots of times */
459 for (unsigned int off=0;off<get_path_length + put_path_length;off++) 491 skip = 0;
492 memset (cpath,
493 0,
494 sizeof (cpath)); /* Just to trigger harder errors later. */
495 total_len = get_path_length + put_path_length;
496 for (unsigned int off=0;off<total_len;off++)
460 { 497 {
461 const struct GNUNET_PeerIdentity *pid; 498 const struct GNUNET_PeerIdentity *pid;
462 499
463 pid = (off < get_path_length) 500 pid = (off < get_path_length)
464 ? &get_path[get_path_length - off] 501 ? &get_path[get_path_length - off]
465 : &put_path[get_path_length + put_path_length - off]; 502 : &put_path[get_path_length + put_path_length - off];
466 cpath[off] = GCP_get (pid, 503 cpath[off - skip] = GCP_get (pid,
467 GNUNET_YES); 504 GNUNET_YES);
505 /* Check that no peer is twice on the path */
506 for (unsigned int i=0;i<off - skip;i++)
507 {
508 if (cpath[i] == cpath[off - skip])
509 {
510 skip = off - i;
511 break;
512 }
513 }
468 } 514 }
515 total_len -= skip;
469 516
470 /* First figure out if this path is a subset of an existing path, an 517 /* First figure out if this path is a subset of an existing path, an
471 extension of an existing path, or a new path. */ 518 extension of an existing path, or a new path. */
472 cm_ctx.cpath_length = get_path_length + put_path_length; 519 cm_ctx.cpath_length = total_len;
473 cm_ctx.cpath = cpath; 520 cm_ctx.cpath = cpath;
474 cm_ctx.match = NULL; 521 cm_ctx.match = NULL;
475 for (i=get_path_length + put_path_length-1;i>=0;i--) 522 for (i=total_len-1;i>=0;i--)
476 { 523 {
477 GCP_iterate_paths_at (cpath[i], 524 GCP_iterate_paths_at (cpath[i],
478 (unsigned int) i, 525 (unsigned int) i,
@@ -480,7 +527,7 @@ GCPP_try_path_from_dht (const struct GNUNET_PeerIdentity *get_path,
480 &cm_ctx); 527 &cm_ctx);
481 if (NULL != cm_ctx.match) 528 if (NULL != cm_ctx.match)
482 { 529 {
483 if (i == get_path_length + put_path_length - 1) 530 if (i == total_len - 1)
484 { 531 {
485 /* Existing path includes this one, nothing to do! */ 532 /* Existing path includes this one, nothing to do! */
486 LOG (GNUNET_ERROR_TYPE_DEBUG, 533 LOG (GNUNET_ERROR_TYPE_DEBUG,
@@ -494,8 +541,8 @@ GCPP_try_path_from_dht (const struct GNUNET_PeerIdentity *get_path,
494 "Trying to extend existing path %s by additional links discovered from DHT\n", 541 "Trying to extend existing path %s by additional links discovered from DHT\n",
495 GCPP_2s (cm_ctx.match)); 542 GCPP_2s (cm_ctx.match));
496 extend_path (cm_ctx.match, 543 extend_path (cm_ctx.match,
497 &cpath[i], 544 &cpath[i + 1],
498 get_path_length + put_path_length - i, 545 total_len - i - 1,
499 GNUNET_NO); 546 GNUNET_NO);
500 return; 547 return;
501 } 548 }
@@ -504,7 +551,7 @@ GCPP_try_path_from_dht (const struct GNUNET_PeerIdentity *get_path,
504 551
505 /* No match at all, create completely new path */ 552 /* No match at all, create completely new path */
506 path = GNUNET_new (struct CadetPeerPath); 553 path = GNUNET_new (struct CadetPeerPath);
507 path->entries_length = get_path_length + put_path_length; 554 path->entries_length = total_len;
508 path->entries = GNUNET_new_array (path->entries_length, 555 path->entries = GNUNET_new_array (path->entries_length,
509 struct CadetPeerPathEntry *); 556 struct CadetPeerPathEntry *);
510 for (i=path->entries_length-1;i>=0;i--) 557 for (i=path->entries_length-1;i>=0;i--)
@@ -526,7 +573,7 @@ GCPP_try_path_from_dht (const struct GNUNET_PeerIdentity *get_path,
526 573
527 /* Finally, try to attach it */ 574 /* Finally, try to attach it */
528 hn = NULL; 575 hn = NULL;
529 for (i=get_path_length + put_path_length-1;i>=0;i--) 576 for (i=total_len-1;i>=0;i--)
530 { 577 {
531 struct CadetPeerPathEntry *entry = path->entries[i]; 578 struct CadetPeerPathEntry *entry = path->entries[i];
532 579
@@ -613,8 +660,8 @@ GCPP_get_path_from_route (unsigned int path_length,
613 "Extending existing path %s to create inverse for incoming connection\n", 660 "Extending existing path %s to create inverse for incoming connection\n",
614 GCPP_2s (cm_ctx.match)); 661 GCPP_2s (cm_ctx.match));
615 extend_path (cm_ctx.match, 662 extend_path (cm_ctx.match,
616 &cpath[i], 663 &cpath[i + 1],
617 path_length - i, 664 path_length - i - 1,
618 GNUNET_YES); 665 GNUNET_YES);
619 /* Check that extension was successful */ 666 /* Check that extension was successful */
620 GNUNET_assert (cm_ctx.match->entries_length == path_length); 667 GNUNET_assert (cm_ctx.match->entries_length == path_length);
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..baa87ea87 100644
--- a/src/cadet/gnunet-service-cadet_peer.h
+++ b/src/cadet/gnunet-service-cadet_peer.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) 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
@@ -20,464 +20,374 @@
20 20
21/** 21/**
22 * @file cadet/gnunet-service-cadet_peer.h 22 * @file cadet/gnunet-service-cadet_peer.h
23 * @brief cadet service; dealing with remote peers 23 * @brief Information we track per peer.
24 * @author Bartlomiej Polot 24 * @author Bartlomiej Polot
25 * 25 * @author Christian Grothoff
26 * All functions in this file should use the prefix GMP (Gnunet Cadet Peer)
27 */ 26 */
28
29#ifndef GNUNET_SERVICE_CADET_PEER_H 27#ifndef GNUNET_SERVICE_CADET_PEER_H
30#define GNUNET_SERVICE_CADET_PEER_H 28#define GNUNET_SERVICE_CADET_PEER_H
31 29
32#ifdef __cplusplus 30#include "gnunet-service-cadet.h"
33extern "C" 31#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 32
44/**
45 * Struct containing all information regarding a given peer
46 */
47struct CadetPeer;
48
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 33
81/** 34/**
82 * Peer path iterator. 35 * Get the static string for a peer ID.
83 * 36 *
84 * @param cls Closure. 37 * @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 * 38 *
103 * @param c Configuration. 39 * @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 */ 40 */
111void 41const char *
112GCP_shutdown (void); 42GCP_2s (const struct CadetPeer *peer);
113 43
114 44
115/** 45/**
116 * Retrieve the CadetPeer stucture associated with the peer. Optionally create 46 * Retrieve the CadetPeer stucture associated with the
117 * one and insert it in the appropriate structures if the peer is not known yet. 47 * peer. Optionally create one and insert it in the appropriate
48 * structures if the peer is not known yet.
118 * 49 *
119 * @param peer_id Full identity of the peer. 50 * @param peer_id Full identity of the peer.
120 * @param create #GNUNET_YES if a new peer should be created if unknown. 51 * @param create #GNUNET_YES if a new peer should be created if unknown.
121 * #GNUNET_NO otherwise. 52 * #GNUNET_NO to return NULL if peer is unknown.
122 *
123 * @return Existing or newly created peer structure. 53 * @return Existing or newly created peer structure.
124 * NULL if unknown and not requested @a create 54 * NULL if unknown and not requested @a create
125 */ 55 */
126struct CadetPeer * 56struct CadetPeer *
127GCP_get (const struct GNUNET_PeerIdentity *peer_id, int create); 57GCP_get (const struct GNUNET_PeerIdentity *peer_id,
58 int create);
128 59
129 60
130/** 61/**
131 * Retrieve the CadetPeer stucture associated with the peer. Optionally create 62 * 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. 63 * @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 * 64 *
138 * @return Existing or newly created peer structure. 65 * @param cp a peer reachable via a path
139 * NULL if unknown and not requested @a create 66 * @param off offset of @a cp in a path
67 * @return score how useful a path is to reach @a cp,
68 * positive scores mean path is more desirable
140 */ 69 */
141struct CadetPeer * 70double
142GCP_get_short (const GNUNET_PEER_Id peer, int create); 71GCP_get_desirability_of_path (struct CadetPeer *cp,
72 unsigned int off);
143 73
144 74
145/** 75/**
146 * Try to establish a new connection to this peer (in its tunnel). 76 * Obtain the peer identity for a `struct CadetPeer`.
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
155/**
156 * @brief Send a message to another peer (using CORE).
157 * 77 *
158 * @param peer Peer towards which to queue the message. 78 * @param cp our peer handle
159 * @param message Message to send. 79 * @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 */ 80 */
169struct CadetPeerQueue * 81const struct GNUNET_PeerIdentity *
170GCP_send (struct CadetPeer *peer, 82GCP_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 83
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 84
191/** 85/**
192 * Set tunnel. 86 * Iterate over all known peers.
193 * 87 *
194 * @param peer Peer. 88 * @param iter Iterator.
195 * @param t Tunnel. 89 * @param cls Closure for @c iter.
196 */ 90 */
197void 91void
198GCP_set_tunnel (struct CadetPeer *peer, struct CadetTunnel *t); 92GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter,
93 void *cls);
199 94
200 95
201/** 96/**
202 * Check whether there is a direct (core level) connection to peer. 97 * Count the number of known paths toward the peer.
203 *
204 * @param peer Peer to check.
205 * 98 *
206 * @return #GNUNET_YES if there is a direct connection. 99 * @param cp Peer to get path info.
100 * @return Number of known paths.
207 */ 101 */
208int 102unsigned int
209GCP_is_neighbor (const struct CadetPeer *peer); 103GCP_count_paths (const struct CadetPeer *cp);
210 104
211 105
212/** 106/**
213 * Create and initialize a new tunnel towards a peer, in case it has none. 107 * Drop all paths owned by this peer, and do not
108 * allow new ones to be added: We are shutting down.
214 * 109 *
215 * Does not generate any traffic, just creates the local data structures. 110 * @param cp peer to drop paths to
216 *
217 * @param peer Peer towards which to create the tunnel.
218 */ 111 */
219void 112void
220GCP_add_tunnel (struct CadetPeer *peer); 113GCP_drop_owned_paths (struct CadetPeer *cp);
221 114
222 115
223/** 116/**
224 * Add a connection to a neighboring peer. 117 * 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 * 118 *
230 * @param peer Peer to add connection to. 119 * @param cls Closure.
231 * @param c Connection to add. 120 * @param path Path itself
232 * @param pred #GNUNET_YES if we are predecessor, #GNUNET_NO if we are successor 121 * @param off offset of the target peer in @a path
122 * @return #GNUNET_YES if should keep iterating.
123 * #GNUNET_NO otherwise.
233 */ 124 */
234void 125typedef int
235GCP_add_connection (struct CadetPeer *peer, 126(*GCP_PathIterator) (void *cls,
236 struct CadetConnection *c, 127 struct CadetPeerPath *path,
237 int pred); 128 unsigned int off);
238 129
239 130
240/** 131/**
241 * Add the path to the peer and update the path used to reach it in case this 132 * 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 * 133 *
249 * @return path if path was taken, pointer to existing duplicate if exists 134 * @param cp Peer to get path info.
250 * NULL on error. 135 * @param callback Function to call for every path.
136 * @param callback_cls Closure for @a callback.
137 * @return Number of iterated paths.
251 */ 138 */
252struct CadetPeerPath * 139unsigned int
253GCP_add_path (struct CadetPeer *peer, 140GCP_iterate_paths (struct CadetPeer *cp,
254 struct CadetPeerPath *p, 141 GCP_PathIterator callback,
255 int trusted); 142 void *callback_cls);
256 143
257 144
258/** 145/**
259 * Add the path to the origin peer and update the path used to reach it in case 146 * Iterate over the paths to @a peer where
260 * this is the shortest. 147 * @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 *
264 * @param peer Peer to add the path to, being the origin of the path.
265 * @param path New path to add after being inversed.
266 * Path will be either used or freed.
267 * @param trusted Do we trust that this path is real?
268 * 148 *
269 * @return path if path was taken, pointer to existing duplicate if exists 149 * @param cp Peer to get path info.
270 * NULL on error. 150 * @param dist desired distance of @a peer to us on the path
151 * @param callback Function to call for every path.
152 * @param callback_cls Closure for @a callback.
153 * @return Number of iterated paths.
271 */ 154 */
272struct CadetPeerPath * 155unsigned int
273GCP_add_path_to_origin (struct CadetPeer *peer, 156GCP_iterate_paths_at (struct CadetPeer *cp,
274 struct CadetPeerPath *path, 157 unsigned int dist,
275 int trusted); 158 GCP_PathIterator callback,
159 void *callback_cls);
160
276 161
277/** 162/**
278 * Adds a path to the info of all the peers in the path 163 * Remove an entry from the DLL of all of the paths that this peer is on.
279 * 164 *
280 * @param p Path to process. 165 * @param cp peer to modify
281 * @param confirmed Whether we know if the path works or not. 166 * @param entry an entry on a path
167 * @param off offset of this peer on the path
282 */ 168 */
283void 169void
284GCP_add_path_to_all (const struct CadetPeerPath *p, int confirmed); 170GCP_path_entry_remove (struct CadetPeer *cp,
171 struct CadetPeerPathEntry *entry,
172 unsigned int off);
285 173
286 174
287/** 175/**
288 * Remove any path to the peer that has the extact same peers as the one given. 176 * Add an entry to the DLL of all of the paths that this peer is on.
289 * 177 *
290 * @param peer Peer to remove the path from. 178 * @param cp peer to modify
291 * @param path Path to remove. Is always destroyed . 179 * @param entry an entry on a path
180 * @param off offset of this peer on the path
292 */ 181 */
293void 182void
294GCP_remove_path (struct CadetPeer *peer, 183GCP_path_entry_add (struct CadetPeer *cp,
295 struct CadetPeerPath *path); 184 struct CadetPeerPathEntry *entry,
185 unsigned int off);
296 186
297 187
298/** 188/**
299 * Check that we are aware of a connection from a neighboring peer. 189 * Get the tunnel towards a peer.
300 * 190 *
301 * @param peer Peer to the connection is with 191 * @param cp Peer to get from.
302 * @param c Connection that should be in the map with this peer. 192 * @param create #GNUNET_YES to create a tunnel if we do not have one
193 * @return Tunnel towards peer.
303 */ 194 */
304void 195struct CadetTunnel *
305GCP_check_connection (const struct CadetPeer *peer, 196GCP_get_tunnel (struct CadetPeer *cp,
306 const struct CadetConnection *c); 197 int create);
307 198
308 199
309/** 200/**
310 * Remove a connection from a neighboring peer. 201 * The tunnel to the given peer no longer exists, remove it from our
202 * data structures, and possibly clean up the peer itself.
311 * 203 *
312 * @param peer Peer to remove connection from. 204 * @param cp the peer affected
313 * @param c Connection to remove. 205 * @param t the dead tunnel
314 */ 206 */
315void 207void
316GCP_remove_connection (struct CadetPeer *peer, 208GCP_drop_tunnel (struct CadetPeer *cp,
317 const struct CadetConnection *c); 209 struct CadetTunnel *t);
318 210
319 211
320/** 212/**
321 * Start the DHT search for new paths towards the peer: we don't have 213 * Try adding a @a path to this @a cp. If the peer already
322 * enough good connections. 214 * has plenty of paths, return NULL.
323 * 215 *
324 * @param peer Destination peer. 216 * @param cp peer to which the @a path leads to
217 * @param path a path looking for an owner; may not be fully initialized yet!
218 * @param off offset of @a cp in @a path
219 * @param force for attaching the path
220 * @return NULL if this peer does not care to become a new owner,
221 * otherwise the node in the peer's path heap for the @a path.
325 */ 222 */
326void 223struct GNUNET_CONTAINER_HeapNode *
327GCP_start_search (struct CadetPeer *peer); 224GCP_attach_path (struct CadetPeer *cp,
225 struct CadetPeerPath *path,
226 unsigned int off,
227 int force);
328 228
329 229
330/** 230/**
331 * Stop the DHT search for new paths towards the peer: we already have 231 * This peer can no longer own @a path as the path
332 * enough good connections. 232 * has been extended and a peer further down the line
233 * is now the new owner.
333 * 234 *
334 * @param peer Destination peer. 235 * @param cp old owner of the @a path
236 * @param path path where the ownership is lost
237 * @param hn note in @a cp's path heap that must be deleted
335 */ 238 */
336void 239void
337GCP_stop_search (struct CadetPeer *peer); 240GCP_detach_path (struct CadetPeer *cp,
241 struct CadetPeerPath *path,
242 struct GNUNET_CONTAINER_HeapNode *hn);
338 243
339 244
340/** 245/**
341 * Get the Full ID of a peer. 246 * Add a @a connection to this @a cp.
342 * 247 *
343 * @param peer Peer to get from. 248 * @param cp peer via which the @a connection goes
344 * 249 * @param cc the connection to add
345 * @return Full ID of peer.
346 */ 250 */
347const struct GNUNET_PeerIdentity * 251void
348GCP_get_id (const struct CadetPeer *peer); 252GCP_add_connection (struct CadetPeer *cp,
253 struct CadetConnection *cc);
349 254
350 255
351/** 256/**
352 * Get the Short ID of a peer. 257 * Remove a @a connection that went via this @a cp.
353 *
354 * @param peer Peer to get from.
355 * 258 *
356 * @return Short ID of peer. 259 * @param cp peer via which the @a connection went
260 * @param cc the connection to remove
357 */ 261 */
358GNUNET_PEER_Id 262void
359GCP_get_short_id (const struct CadetPeer *peer); 263GCP_remove_connection (struct CadetPeer *cp,
264 struct CadetConnection *cc);
360 265
361 266
362/** 267/**
363 * Get the tunnel towards a peer. 268 * We got a HELLO for a @a cp, remember it, and possibly
269 * trigger adequate actions (like trying to connect).
364 * 270 *
365 * @param peer Peer to get from. 271 * @param cp the peer we got a HELLO for
366 * 272 * @param hello the HELLO to remember
367 * @return Tunnel towards peer.
368 */ 273 */
369struct CadetTunnel * 274void
370GCP_get_tunnel (const struct CadetPeer *peer); 275GCP_set_hello (struct CadetPeer *cp,
276 const struct GNUNET_HELLO_Message *hello);
371 277
372 278
373/** 279/**
374 * Set the hello message. 280 * Clean up all entries about all peers.
375 * 281 * Must only be called after all tunnels, CORE-connections and
376 * @param peer Peer whose message to set. 282 * connections are down.
377 * @param hello Hello message.
378 */ 283 */
379void 284void
380GCP_set_hello (struct CadetPeer *peer, 285GCP_destroy_all_peers (void);
381 const struct GNUNET_HELLO_Message *hello);
382 286
383 287
384/** 288/**
385 * Get the hello message. 289 * Data structure used to track whom we have to notify about changes
386 * 290 * in our ability to transmit to a given peer.
387 * @param peer Peer whose message to get.
388 * 291 *
389 * @return Hello message. 292 * All queue managers will be given equal chance for sending messages
293 * to @a cp. This construct this guarantees fairness for access to @a
294 * cp among the different message queues. Each connection or route
295 * will have its respective message queue managers for each direction.
390 */ 296 */
391struct GNUNET_HELLO_Message * 297struct GCP_MessageQueueManager;
392GCP_get_hello (struct CadetPeer *peer);
393 298
394 299
395/** 300/**
396 * Try to connect to a peer on TRANSPORT level. 301 * Function to call with updated message queue object.
397 * 302 *
398 * @param peer Peer to whom to connect. 303 * @param cls closure
304 * @param available #GNUNET_YES if sending is now possible,
305 * #GNUNET_NO if sending is no longer possible
306 * #GNUNET_SYSERR if sending is no longer possible
307 * and the last envelope was discarded
399 */ 308 */
400void 309typedef void
401GCP_try_connect (struct CadetPeer *peer); 310(*GCP_MessageQueueNotificationCallback)(void *cls,
311 int available);
312
402 313
403/** 314/**
404 * Notify a peer that a link between two other peers is broken. If any path 315 * Start message queue change notifications. Will create a new slot
405 * used that link, eliminate it. 316 * to manage the message queue to the given @a cp.
406 * 317 *
407 * @param peer Peer affected by the change. 318 * @param cp peer to notify for
408 * @param peer1 Peer whose link is broken. 319 * @param cb function to call if mq becomes available or unavailable
409 * @param peer2 Peer whose link is broken. 320 * @param cb_cls closure for @a cb
321 * @return handle to cancel request
410 */ 322 */
411void 323struct GCP_MessageQueueManager *
412GCP_notify_broken_link (struct CadetPeer *peer, 324GCP_request_mq (struct CadetPeer *cp,
413 const struct GNUNET_PeerIdentity *peer1, 325 GCP_MessageQueueNotificationCallback cb,
414 const struct GNUNET_PeerIdentity *peer2); 326 void *cb_cls);
415 327
416 328
417/** 329/**
418 * Count the number of known paths toward the peer. 330 * Test if @a cp has a core-level connection
419 * 331 *
420 * @param peer Peer to get path info. 332 * @param cp peer to test
421 * 333 * @return #GNUNET_YES if @a cp has a core-level connection
422 * @return Number of known paths.
423 */ 334 */
424unsigned int 335int
425GCP_count_paths (const struct CadetPeer *peer); 336GCP_has_core_connection (struct CadetPeer *cp);
337
426 338
427/** 339/**
428 * Iterate over the paths to a peer. 340 * Send the message in @a env via a @a mqm. Must only be called at
341 * most once after the respective
342 * #GCP_MessageQueueNotificationCallback was called with `available`
343 * set to #GNUNET_YES, and not after the callback was called with
344 * `available` set to #GNUNET_NO or #GNUNET_SYSERR.
429 * 345 *
430 * @param peer Peer to get path info. 346 * @param mqm message queue manager for the transmission
431 * @param callback Function to call for every path. 347 * @param env envelope with the message to send; must NOT
432 * @param cls Closure for @a callback. 348 * yet have a #GNUNET_MQ_notify_sent() callback attached to it
433 *
434 * @return Number of iterated paths.
435 */ 349 */
436unsigned int 350void
437GCP_iterate_paths (struct CadetPeer *peer, 351GCP_send (struct GCP_MessageQueueManager *mqm,
438 GCP_path_iterator callback, 352 struct GNUNET_MQ_Envelope *env);
439 void *cls);
440 353
441 354
442/** 355/**
443 * Iterate all known peers. 356 * Send the message in @a env to @a cp, overriding queueing logic.
357 * This function should only be used to send error messages outside
358 * of flow and congestion control, similar to ICMP. Note that
359 * the envelope may be silently discarded as well.
444 * 360 *
445 * @param iter Iterator. 361 * @param cp peer to send the message to
446 * @param cls Closure for @c iter. 362 * @param env envelope with the message to send
447 */ 363 */
448void 364void
449GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter, 365GCP_send_ooo (struct CadetPeer *cp,
450 void *cls); 366 struct GNUNET_MQ_Envelope *env);
451 367
452 368
453/** 369/**
454 * Get the static string for a peer ID. 370 * Stops message queue change notifications and sends a last message.
455 * 371 * In practice, this is implemented by sending that @a last_env
456 * @param peer Peer. 372 * message immediately (if any), ignoring queue order.
457 * 373 *
458 * @return Static string for it's ID. 374 * @param mqm handle matching request to cancel
375 * @param last_env final message to transmit, or NULL
459 */ 376 */
460const char * 377void
461GCP_2s (const struct CadetPeer *peer); 378GCP_request_mq_cancel (struct GCP_MessageQueueManager *mqm,
379 struct GNUNET_MQ_Envelope *last_env);
462 380
463 381
464/** 382/**
465 * Log all kinds of info about a peer. 383 * Set the message queue to @a mq for peer @a cp and notify watchers.
466 * 384 *
467 * @param peer Peer. 385 * @param cp peer to modify
386 * @param mq message queue to set (can be NULL)
468 */ 387 */
469void 388void
470GCP_debug (const struct CadetPeer *p, 389GCP_set_mq (struct CadetPeer *cp,
471 enum GNUNET_ErrorType level); 390 struct GNUNET_MQ_Handle *mq);
472
473 391
474#if 0 /* keep Emacsens' auto-indent happy */
475{
476#endif
477#ifdef __cplusplus
478}
479#endif
480 392
481/* ifndef GNUNET_CADET_SERVICE_PEER_H */
482#endif 393#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 3b21f4107..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_SENT:
503 return "CADET_TUNNEL_KEY_SENT";
504 case CADET_TUNNEL_KEY_PING:
505 return "CADET_TUNNEL_KEY_PING";
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_PING == 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_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_PING <= 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_PING);
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_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 0abdc02ce..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_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_PING,
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 fd8335486..28004debc 100644
--- a/src/cadet/gnunet-service-cadet-new_tunnels.c
+++ b/src/cadet/gnunet-service-cadet_tunnels.c
@@ -18,35 +18,38 @@
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
25 * 25 *
26 * FIXME: 26 * FIXME:
27 * - check KX estate machine -- make sure it is never stuck! 27 * - proper connection evaluation during connection management:
28 * - clean up KX logic, including adding sender authentication 28 * + consider quality (or quality spread?) of current connection set
29 * - implement connection management (evaluate, kill old ones, 29 * when deciding how often to do maintenance
30 * search for new ones) 30 * + interact with PEER to drive DHT GET/PUT operations based
31 * - when managing connections, distinguish those that 31 * on how much we like our connections
32 * have (recently) had traffic from those that were
33 * never ready (or not recently)
34 */ 32 */
35#include "platform.h" 33#include "platform.h"
36#include "gnunet_util_lib.h" 34#include "gnunet_util_lib.h"
37#include "gnunet_statistics_service.h" 35#include "gnunet_statistics_service.h"
38#include "gnunet_signatures.h" 36#include "gnunet_signatures.h"
39#include "gnunet-service-cadet-new.h"
40#include "cadet_protocol.h" 37#include "cadet_protocol.h"
41#include "gnunet-service-cadet-new_channel.h" 38#include "gnunet-service-cadet_channel.h"
42#include "gnunet-service-cadet-new_connection.h" 39#include "gnunet-service-cadet_connection.h"
43#include "gnunet-service-cadet-new_tunnels.h" 40#include "gnunet-service-cadet_tunnels.h"
44#include "gnunet-service-cadet-new_peer.h" 41#include "gnunet-service-cadet_peer.h"
45#include "gnunet-service-cadet-new_paths.h" 42#include "gnunet-service-cadet_paths.h"
46 43
47 44
48#define LOG(level, ...) GNUNET_log_from(level,"cadet-tun",__VA_ARGS__) 45#define LOG(level, ...) GNUNET_log_from(level,"cadet-tun",__VA_ARGS__)
49 46
47/**
48 * How often do we try to decrypt payload with unverified key
49 * material? Used to limit CPU increase upon receiving bogus
50 * KX.
51 */
52#define MAX_UNVERIFIED_ATTEMPTS 16
50 53
51/** 54/**
52 * How long do we wait until tearing down an idle tunnel? 55 * How long do we wait until tearing down an idle tunnel?
@@ -54,12 +57,10 @@
54#define IDLE_DESTROY_DELAY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 90) 57#define IDLE_DESTROY_DELAY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 90)
55 58
56/** 59/**
57 * Yuck, replace by 'offsetof' expression? 60 * How long do we wait initially before retransmitting the KX?
58 * FIXME. 61 * TODO: replace by 2 RTT if/once we have connection-level RTT data!
59 */ 62 */
60#define AX_HEADER_SIZE (sizeof (uint32_t) * 2\ 63#define INITIAL_KX_RETRY_DELAY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 250)
61 + sizeof (struct GNUNET_CRYPTO_EcdhePublicKey))
62
63 64
64/** 65/**
65 * Maximum number of skipped keys we keep in memory per tunnel. 66 * Maximum number of skipped keys we keep in memory per tunnel.
@@ -133,52 +134,61 @@ struct CadetTunnelAxolotl
133 struct GNUNET_CRYPTO_SymmetricSessionKey RK; 134 struct GNUNET_CRYPTO_SymmetricSessionKey RK;
134 135
135 /** 136 /**
136 * 32-byte header key (send). 137 * 32-byte header key (currently used for sending).
137 */ 138 */
138 struct GNUNET_CRYPTO_SymmetricSessionKey HKs; 139 struct GNUNET_CRYPTO_SymmetricSessionKey HKs;
139 140
140 /** 141 /**
141 * 32-byte header key (recv) 142 * 32-byte header key (currently used for receiving)
142 */ 143 */
143 struct GNUNET_CRYPTO_SymmetricSessionKey HKr; 144 struct GNUNET_CRYPTO_SymmetricSessionKey HKr;
144 145
145 /** 146 /**
146 * 32-byte next header key (send). 147 * 32-byte next header key (for sending), used once the
148 * ratchet advances. We are sure that the sender has this
149 * key as well only after @e ratchet_allowed is #GNUNET_YES.
147 */ 150 */
148 struct GNUNET_CRYPTO_SymmetricSessionKey NHKs; 151 struct GNUNET_CRYPTO_SymmetricSessionKey NHKs;
149 152
150 /** 153 /**
151 * 32-byte next header key (recv). 154 * 32-byte next header key (for receiving). To be tried
155 * when decrypting with @e HKr fails and thus the sender
156 * may have advanced the ratchet.
152 */ 157 */
153 struct GNUNET_CRYPTO_SymmetricSessionKey NHKr; 158 struct GNUNET_CRYPTO_SymmetricSessionKey NHKr;
154 159
155 /** 160 /**
156 * 32-byte chain keys (used for forward-secrecy updating, send). 161 * 32-byte chain keys (used for forward-secrecy) for
162 * sending messages. Updated for every message.
157 */ 163 */
158 struct GNUNET_CRYPTO_SymmetricSessionKey CKs; 164 struct GNUNET_CRYPTO_SymmetricSessionKey CKs;
159 165
160 /** 166 /**
161 * 32-byte chain keys (used for forward-secrecy updating, recv). 167 * 32-byte chain keys (used for forward-secrecy) for
168 * receiving messages. Updated for every message. If
169 * messages are skipped, the respective derived MKs
170 * (and the current @HKr) are kept in the @e skipped_head DLL.
162 */ 171 */
163 struct GNUNET_CRYPTO_SymmetricSessionKey CKr; 172 struct GNUNET_CRYPTO_SymmetricSessionKey CKr;
164 173
165 /** 174 /**
166 * ECDH for key exchange (A0 / B0). 175 * ECDH for key exchange (A0 / B0).
167 */ 176 */
168 struct GNUNET_CRYPTO_EcdhePrivateKey *kx_0; 177 struct GNUNET_CRYPTO_EcdhePrivateKey kx_0;
169 178
170 /** 179 /**
171 * ECDH Ratchet key (send). 180 * ECDH Ratchet key (our private key in the current DH).
172 */ 181 */
173 struct GNUNET_CRYPTO_EcdhePrivateKey *DHRs; 182 struct GNUNET_CRYPTO_EcdhePrivateKey DHRs;
174 183
175 /** 184 /**
176 * ECDH Ratchet key (recv). 185 * ECDH Ratchet key (other peer's public key in the current DH).
177 */ 186 */
178 struct GNUNET_CRYPTO_EcdhePublicKey DHRr; 187 struct GNUNET_CRYPTO_EcdhePublicKey DHRr;
179 188
180 /** 189 /**
181 * When does this ratchet expire and a new one is triggered. 190 * Time when the current ratchet expires and a new one is triggered
191 * (if @e ratchet_allowed is #GNUNET_YES).
182 */ 192 */
183 struct GNUNET_TIME_Absolute ratchet_expiration; 193 struct GNUNET_TIME_Absolute ratchet_expiration;
184 194
@@ -208,16 +218,28 @@ struct CadetTunnelAxolotl
208 int ratchet_flag; 218 int ratchet_flag;
209 219
210 /** 220 /**
211 * Number of messages recieved since our last ratchet advance. 221 * True (#GNUNET_YES) if we have received a message from the
212 * - If this counter = 0, we cannot send a new ratchet key in next msg. 222 * other peer that uses the keys from our last ratchet step.
213 * - If this counter > 0, we can (but don't yet have to) send a new key. 223 * This implies that we are again allowed to advance the ratchet,
224 * otherwise we have to wait until the other peer sees our current
225 * ephemeral key and advances first.
226 *
227 * #GNUNET_NO if we have advanced the ratched but lack any evidence
228 * that the other peer has noticed this.
214 */ 229 */
215 unsigned int ratchet_allowed; 230 int ratchet_allowed;
216 231
217 /** 232 /**
218 * Number of messages recieved since our last ratchet advance. 233 * Number of messages recieved since our last ratchet advance.
219 * - If this counter = 0, we cannot send a new ratchet key in next msg. 234 *
220 * - If this counter > 0, we can (but don't yet have to) send a new key. 235 * If this counter = 0, we cannot send a new ratchet key in the next
236 * message.
237 *
238 * If this counter > 0, we could (but don't have to) send a new key.
239 *
240 * Once the @e ratchet_counter is larger than
241 * #ratchet_messages (or @e ratchet_expiration time has past), and
242 * @e ratchet_allowed is #GNUNET_YES, we advance the ratchet.
221 */ 243 */
222 unsigned int ratchet_counter; 244 unsigned int ratchet_counter;
223 245
@@ -247,7 +269,7 @@ struct CadetTunnelQueueEntry
247 /** 269 /**
248 * Continuation to call once sent (on the channel layer). 270 * Continuation to call once sent (on the channel layer).
249 */ 271 */
250 GNUNET_SCHEDULER_TaskCallback cont; 272 GCT_SendContinuation cont;
251 273
252 /** 274 /**
253 * Closure for @c cont. 275 * Closure for @c cont.
@@ -299,6 +321,15 @@ struct CadetTunnel
299 struct CadetTunnelAxolotl ax; 321 struct CadetTunnelAxolotl ax;
300 322
301 /** 323 /**
324 * Unverified Axolotl info, used only if we got a fresh KX (not a
325 * KX_AUTH) while our end of the tunnel was still up. In this case,
326 * we keep the fresh KX around but do not put it into action until
327 * we got encrypted payload that assures us of the authenticity of
328 * the KX.
329 */
330 struct CadetTunnelAxolotl *unverified_ax;
331
332 /**
302 * Task scheduled if there are no more channels using the tunnel. 333 * Task scheduled if there are no more channels using the tunnel.
303 */ 334 */
304 struct GNUNET_SCHEDULER_Task *destroy_task; 335 struct GNUNET_SCHEDULER_Task *destroy_task;
@@ -329,14 +360,24 @@ struct CadetTunnel
329 struct GNUNET_MQ_Handle *mq; 360 struct GNUNET_MQ_Handle *mq;
330 361
331 /** 362 /**
332 * DLL of connections that are actively used to reach the destination peer. 363 * DLL of ready connections that are actively used to reach the destination peer.
333 */ 364 */
334 struct CadetTConnection *connection_head; 365 struct CadetTConnection *connection_ready_head;
335 366
336 /** 367 /**
337 * DLL of connections that are actively used to reach the destination peer. 368 * DLL of ready connections that are actively used to reach the destination peer.
338 */ 369 */
339 struct CadetTConnection *connection_tail; 370 struct CadetTConnection *connection_ready_tail;
371
372 /**
373 * DLL of connections that we maintain that might be used to reach the destination peer.
374 */
375 struct CadetTConnection *connection_busy_head;
376
377 /**
378 * DLL of connections that we maintain that might be used to reach the destination peer.
379 */
380 struct CadetTConnection *connection_busy_tail;
340 381
341 /** 382 /**
342 * Channels inside this tunnel. Maps 383 * Channels inside this tunnel. Maps
@@ -359,16 +400,12 @@ struct CadetTunnel
359 */ 400 */
360 struct CadetTunnelQueueEntry *tq_tail; 401 struct CadetTunnelQueueEntry *tq_tail;
361 402
362
363 /**
364 * Ephemeral message in the queue (to avoid queueing more than one).
365 */
366 struct CadetConnectionQueue *ephm_hKILL;
367
368 /** 403 /**
369 * Pong message in the queue. 404 * Identification of the connection from which we are currently processing
405 * a message. Only valid (non-NULL) during #handle_decrypted() and the
406 * handle-*()-functions called from our @e mq during that function.
370 */ 407 */
371 struct CadetConnectionQueue *pong_hKILL; 408 struct CadetTConnection *current_ct;
372 409
373 /** 410 /**
374 * How long do we wait until we retry the KX? 411 * How long do we wait until we retry the KX?
@@ -381,9 +418,21 @@ struct CadetTunnel
381 struct GNUNET_TIME_Absolute next_kx_attempt; 418 struct GNUNET_TIME_Absolute next_kx_attempt;
382 419
383 /** 420 /**
384 * Number of connections in the @e connection_head DLL. 421 * Number of connections in the @e connection_ready_head DLL.
385 */ 422 */
386 unsigned int num_connections; 423 unsigned int num_ready_connections;
424
425 /**
426 * Number of connections in the @e connection_busy_head DLL.
427 */
428 unsigned int num_busy_connections;
429
430 /**
431 * How often have we tried and failed to decrypt a message using
432 * the unverified KX material from @e unverified_ax? Used to
433 * stop trying after #MAX_UNVERIFIED_ATTEMPTS.
434 */
435 unsigned int unverified_attempts;
387 436
388 /** 437 /**
389 * Number of entries in the @e tq_head DLL. 438 * Number of entries in the @e tq_head DLL.
@@ -395,10 +444,40 @@ struct CadetTunnel
395 */ 444 */
396 enum CadetTunnelEState estate; 445 enum CadetTunnelEState estate;
397 446
447 /**
448 * Force triggering KX_AUTH independent of @e estate.
449 */
450 int kx_auth_requested;
451
398}; 452};
399 453
400 454
401/** 455/**
456 * Connection @a ct is now unready, clear it's ready flag
457 * and move it from the ready DLL to the busy DLL.
458 *
459 * @param ct connection to move to unready status
460 */
461static void
462mark_connection_unready (struct CadetTConnection *ct)
463{
464 struct CadetTunnel *t = ct->t;
465
466 GNUNET_assert (GNUNET_YES == ct->is_ready);
467 GNUNET_CONTAINER_DLL_remove (t->connection_ready_head,
468 t->connection_ready_tail,
469 ct);
470 GNUNET_assert (0 < t->num_ready_connections);
471 t->num_ready_connections--;
472 ct->is_ready = GNUNET_NO;
473 GNUNET_CONTAINER_DLL_insert (t->connection_busy_head,
474 t->connection_busy_tail,
475 ct);
476 t->num_busy_connections++;
477}
478
479
480/**
402 * Get the static string for the peer this tunnel is directed. 481 * Get the static string for the peer this tunnel is directed.
403 * 482 *
404 * @param t Tunnel. 483 * @param t Tunnel.
@@ -434,19 +513,24 @@ estate2s (enum CadetTunnelEState es)
434 513
435 switch (es) 514 switch (es)
436 { 515 {
437 case CADET_TUNNEL_KEY_UNINITIALIZED: 516 case CADET_TUNNEL_KEY_UNINITIALIZED:
438 return "CADET_TUNNEL_KEY_UNINITIALIZED"; 517 return "CADET_TUNNEL_KEY_UNINITIALIZED";
439 case CADET_TUNNEL_KEY_SENT: 518 case CADET_TUNNEL_KEY_AX_RECV:
440 return "CADET_TUNNEL_KEY_SENT"; 519 return "CADET_TUNNEL_KEY_AX_RECV";
441 case CADET_TUNNEL_KEY_PING: 520 case CADET_TUNNEL_KEY_AX_SENT:
442 return "CADET_TUNNEL_KEY_PING"; 521 return "CADET_TUNNEL_KEY_AX_SENT";
443 case CADET_TUNNEL_KEY_OK: 522 case CADET_TUNNEL_KEY_AX_SENT_AND_RECV:
444 return "CADET_TUNNEL_KEY_OK"; 523 return "CADET_TUNNEL_KEY_AX_SENT_AND_RECV";
445 case CADET_TUNNEL_KEY_REKEY: 524 case CADET_TUNNEL_KEY_AX_AUTH_SENT:
446 return "CADET_TUNNEL_KEY_REKEY"; 525 return "CADET_TUNNEL_KEY_AX_AUTH_SENT";
447 default: 526 case CADET_TUNNEL_KEY_OK:
448 SPRINTF (buf, "%u (UNKNOWN STATE)", es); 527 return "CADET_TUNNEL_KEY_OK";
449 return buf; 528 default:
529 GNUNET_snprintf (buf,
530 sizeof (buf),
531 "%u (UNKNOWN STATE)",
532 es);
533 return buf;
450 } 534 }
451} 535}
452 536
@@ -502,9 +586,9 @@ lookup_channel (struct CadetTunnel *t,
502 * @return Number of connections created, either being established or ready. 586 * @return Number of connections created, either being established or ready.
503 */ 587 */
504unsigned int 588unsigned int
505GCT_count_any_connections (struct CadetTunnel *t) 589GCT_count_any_connections (const struct CadetTunnel *t)
506{ 590{
507 return t->num_connections; 591 return t->num_ready_connections + t->num_busy_connections;
508} 592}
509 593
510 594
@@ -518,25 +602,11 @@ GCT_count_any_connections (struct CadetTunnel *t)
518static struct CadetTConnection * 602static struct CadetTConnection *
519get_ready_connection (struct CadetTunnel *t) 603get_ready_connection (struct CadetTunnel *t)
520{ 604{
521 for (struct CadetTConnection *pos = t->connection_head; 605 struct CadetTConnection *hd = t->connection_ready_head;
522 NULL != pos; 606
523 pos = pos->next) 607 GNUNET_assert ( (NULL == hd) ||
524 if (GNUNET_YES == pos->is_ready) 608 (GNUNET_YES == hd->is_ready) );
525 { 609 return hd;
526 if (pos != t->connection_tail)
527 {
528 /* move 'pos' to the end, so we try other ready connections
529 first next time (round-robin, modulo availability) */
530 GNUNET_CONTAINER_DLL_remove (t->connection_head,
531 t->connection_tail,
532 pos);
533 GNUNET_CONTAINER_DLL_insert_tail (t->connection_head,
534 t->connection_tail,
535 pos);
536 }
537 return pos;
538 }
539 return NULL;
540} 610}
541 611
542 612
@@ -555,20 +625,6 @@ GCT_get_estate (struct CadetTunnel *t)
555 625
556 626
557/** 627/**
558 * Create a new Axolotl ephemeral (ratchet) key.
559 *
560 * @param t Tunnel.
561 */
562static void
563new_ephemeral (struct CadetTunnel *t)
564{
565 GNUNET_free_non_null (t->ax.DHRs);
566 t->ax.DHRs = GNUNET_CRYPTO_ecdhe_key_create ();
567}
568
569
570
571/**
572 * Called when either we have a new connection, or a new message in the 628 * Called when either we have a new connection, or a new message in the
573 * queue, or some existing connection has transmission capacity. Looks 629 * queue, or some existing connection has transmission capacity. Looks
574 * at our message queue and if there is a message, picks a connection 630 * at our message queue and if there is a message, picks a connection
@@ -584,6 +640,21 @@ trigger_transmissions (void *cls);
584 640
585 641
586/** 642/**
643 * Create a new Axolotl ephemeral (ratchet) key.
644 *
645 * @param ax key material to update
646 */
647static void
648new_ephemeral (struct CadetTunnelAxolotl *ax)
649{
650 LOG (GNUNET_ERROR_TYPE_DEBUG,
651 "Creating new ephemeral ratchet key (DHRs)\n");
652 GNUNET_assert (GNUNET_OK ==
653 GNUNET_CRYPTO_ecdhe_key_create2 (&ax->DHRs));
654}
655
656
657/**
587 * Calculate HMAC. 658 * Calculate HMAC.
588 * 659 *
589 * @param plaintext Content to HMAC. 660 * @param plaintext Content to HMAC.
@@ -609,7 +680,8 @@ t_hmac (const void *plaintext,
609 key, sizeof (*key), 680 key, sizeof (*key),
610 ctx, sizeof (ctx), 681 ctx, sizeof (ctx),
611 NULL); 682 NULL);
612 /* Two step: CADET_Hash is only 256 bits, HashCode is 512. */ 683 /* Two step: GNUNET_ShortHash is only 256 bits,
684 GNUNET_HashCode is 512, so we truncate. */
613 GNUNET_CRYPTO_hmac (&auth_key, 685 GNUNET_CRYPTO_hmac (&auth_key,
614 plaintext, 686 plaintext,
615 size, 687 size,
@@ -624,7 +696,7 @@ t_hmac (const void *plaintext,
624 * Perform a HMAC. 696 * Perform a HMAC.
625 * 697 *
626 * @param key Key to use. 698 * @param key Key to use.
627 * @param hash[out] Resulting HMAC. 699 * @param[out] hash Resulting HMAC.
628 * @param source Source key material (data to HMAC). 700 * @param source Source key material (data to HMAC).
629 * @param len Length of @a source. 701 * @param len Length of @a source.
630 */ 702 */
@@ -679,23 +751,21 @@ t_hmac_derive_key (const struct GNUNET_CRYPTO_SymmetricSessionKey *key,
679/** 751/**
680 * Encrypt data with the axolotl tunnel key. 752 * Encrypt data with the axolotl tunnel key.
681 * 753 *
682 * @param t Tunnel whose key to use. 754 * @param ax key material to use.
683 * @param dst Destination with @a size bytes for the encrypted data. 755 * @param dst Destination with @a size bytes for the encrypted data.
684 * @param src Source of the plaintext. Can overlap with @c dst, must contain @a size bytes 756 * @param src Source of the plaintext. Can overlap with @c dst, must contain @a size bytes
685 * @param size Size of the buffers at @a src and @a dst 757 * @param size Size of the buffers at @a src and @a dst
686 */ 758 */
687static void 759static void
688t_ax_encrypt (struct CadetTunnel *t, 760t_ax_encrypt (struct CadetTunnelAxolotl *ax,
689 void *dst, 761 void *dst,
690 const void *src, 762 const void *src,
691 size_t size) 763 size_t size)
692{ 764{
693 struct GNUNET_CRYPTO_SymmetricSessionKey MK; 765 struct GNUNET_CRYPTO_SymmetricSessionKey MK;
694 struct GNUNET_CRYPTO_SymmetricInitializationVector iv; 766 struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
695 struct CadetTunnelAxolotl *ax;
696 size_t out_size; 767 size_t out_size;
697 768
698 ax = &t->ax;
699 ax->ratchet_counter++; 769 ax->ratchet_counter++;
700 if ( (GNUNET_YES == ax->ratchet_allowed) && 770 if ( (GNUNET_YES == ax->ratchet_allowed) &&
701 ( (ratchet_messages <= ax->ratchet_counter) || 771 ( (ratchet_messages <= ax->ratchet_counter) ||
@@ -711,11 +781,11 @@ t_ax_encrypt (struct CadetTunnel *t,
711 struct GNUNET_HashCode hmac; 781 struct GNUNET_HashCode hmac;
712 static const char ctx[] = "axolotl ratchet"; 782 static const char ctx[] = "axolotl ratchet";
713 783
714 new_ephemeral (t); 784 new_ephemeral (ax);
715 ax->HKs = ax->NHKs; 785 ax->HKs = ax->NHKs;
716 786
717 /* RK, NHKs, CKs = KDF( HMAC-HASH(RK, DH(DHRs, DHRr)) ) */ 787 /* RK, NHKs, CKs = KDF( HMAC-HASH(RK, DH(DHRs, DHRr)) ) */
718 GNUNET_CRYPTO_ecc_ecdh (ax->DHRs, 788 GNUNET_CRYPTO_ecc_ecdh (&ax->DHRs,
719 &ax->DHRr, 789 &ax->DHRr,
720 &dh); 790 &dh);
721 t_ax_hmac_hash (&ax->RK, 791 t_ax_hmac_hash (&ax->RK,
@@ -765,23 +835,21 @@ t_ax_encrypt (struct CadetTunnel *t,
765/** 835/**
766 * Decrypt data with the axolotl tunnel key. 836 * Decrypt data with the axolotl tunnel key.
767 * 837 *
768 * @param t Tunnel whose key to use. 838 * @param ax key material to use.
769 * @param dst Destination for the decrypted data, must contain @a size bytes. 839 * @param dst Destination for the decrypted data, must contain @a size bytes.
770 * @param src Source of the ciphertext. Can overlap with @c dst, must contain @a size bytes. 840 * @param src Source of the ciphertext. Can overlap with @c dst, must contain @a size bytes.
771 * @param size Size of the @a src and @a dst buffers 841 * @param size Size of the @a src and @a dst buffers
772 */ 842 */
773static void 843static void
774t_ax_decrypt (struct CadetTunnel *t, 844t_ax_decrypt (struct CadetTunnelAxolotl *ax,
775 void *dst, 845 void *dst,
776 const void *src, 846 const void *src,
777 size_t size) 847 size_t size)
778{ 848{
779 struct GNUNET_CRYPTO_SymmetricSessionKey MK; 849 struct GNUNET_CRYPTO_SymmetricSessionKey MK;
780 struct GNUNET_CRYPTO_SymmetricInitializationVector iv; 850 struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
781 struct CadetTunnelAxolotl *ax;
782 size_t out_size; 851 size_t out_size;
783 852
784 ax = &t->ax;
785 t_hmac_derive_key (&ax->CKr, 853 t_hmac_derive_key (&ax->CKr,
786 &MK, 854 &MK,
787 "0", 855 "0",
@@ -807,76 +875,72 @@ t_ax_decrypt (struct CadetTunnel *t,
807/** 875/**
808 * Encrypt header with the axolotl header key. 876 * Encrypt header with the axolotl header key.
809 * 877 *
810 * @param t Tunnel whose key to use. 878 * @param ax key material to use.
811 * @param msg Message whose header to encrypt. 879 * @param[in|out] msg Message whose header to encrypt.
812 */ 880 */
813static void 881static void
814t_h_encrypt (struct CadetTunnel *t, 882t_h_encrypt (struct CadetTunnelAxolotl *ax,
815 struct GNUNET_CADET_TunnelEncryptedMessage *msg) 883 struct GNUNET_CADET_TunnelEncryptedMessage *msg)
816{ 884{
817 struct GNUNET_CRYPTO_SymmetricInitializationVector iv; 885 struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
818 struct CadetTunnelAxolotl *ax;
819 size_t out_size; 886 size_t out_size;
820 887
821 ax = &t->ax;
822 GNUNET_CRYPTO_symmetric_derive_iv (&iv, 888 GNUNET_CRYPTO_symmetric_derive_iv (&iv,
823 &ax->HKs, 889 &ax->HKs,
824 NULL, 0, 890 NULL, 0,
825 NULL); 891 NULL);
826 out_size = GNUNET_CRYPTO_symmetric_encrypt (&msg->Ns, 892 out_size = GNUNET_CRYPTO_symmetric_encrypt (&msg->ax_header,
827 AX_HEADER_SIZE, 893 sizeof (struct GNUNET_CADET_AxHeader),
828 &ax->HKs, 894 &ax->HKs,
829 &iv, 895 &iv,
830 &msg->Ns); 896 &msg->ax_header);
831 GNUNET_assert (AX_HEADER_SIZE == out_size); 897 GNUNET_assert (sizeof (struct GNUNET_CADET_AxHeader) == out_size);
832} 898}
833 899
834 900
835/** 901/**
836 * Decrypt header with the current axolotl header key. 902 * Decrypt header with the current axolotl header key.
837 * 903 *
838 * @param t Tunnel whose current ax HK to use. 904 * @param ax key material to use.
839 * @param src Message whose header to decrypt. 905 * @param src Message whose header to decrypt.
840 * @param dst Where to decrypt header to. 906 * @param dst Where to decrypt header to.
841 */ 907 */
842static void 908static void
843t_h_decrypt (struct CadetTunnel *t, 909t_h_decrypt (struct CadetTunnelAxolotl *ax,
844 const struct GNUNET_CADET_TunnelEncryptedMessage *src, 910 const struct GNUNET_CADET_TunnelEncryptedMessage *src,
845 struct GNUNET_CADET_TunnelEncryptedMessage *dst) 911 struct GNUNET_CADET_TunnelEncryptedMessage *dst)
846{ 912{
847 struct GNUNET_CRYPTO_SymmetricInitializationVector iv; 913 struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
848 struct CadetTunnelAxolotl *ax;
849 size_t out_size; 914 size_t out_size;
850 915
851 ax = &t->ax;
852 GNUNET_CRYPTO_symmetric_derive_iv (&iv, 916 GNUNET_CRYPTO_symmetric_derive_iv (&iv,
853 &ax->HKr, 917 &ax->HKr,
854 NULL, 0, 918 NULL, 0,
855 NULL); 919 NULL);
856 out_size = GNUNET_CRYPTO_symmetric_decrypt (&src->Ns, 920 out_size = GNUNET_CRYPTO_symmetric_decrypt (&src->ax_header.Ns,
857 AX_HEADER_SIZE, 921 sizeof (struct GNUNET_CADET_AxHeader),
858 &ax->HKr, 922 &ax->HKr,
859 &iv, 923 &iv,
860 &dst->Ns); 924 &dst->ax_header.Ns);
861 GNUNET_assert (AX_HEADER_SIZE == out_size); 925 GNUNET_assert (sizeof (struct GNUNET_CADET_AxHeader) == out_size);
862} 926}
863 927
864 928
865/** 929/**
866 * Delete a key from the list of skipped keys. 930 * Delete a key from the list of skipped keys.
867 * 931 *
868 * @param t Tunnel to delete from. 932 * @param ax key material to delete @a key from.
869 * @param key Key to delete. 933 * @param key Key to delete.
870 */ 934 */
871static void 935static void
872delete_skipped_key (struct CadetTunnel *t, 936delete_skipped_key (struct CadetTunnelAxolotl *ax,
873 struct CadetTunnelSkippedKey *key) 937 struct CadetTunnelSkippedKey *key)
874{ 938{
875 GNUNET_CONTAINER_DLL_remove (t->ax.skipped_head, 939 GNUNET_CONTAINER_DLL_remove (ax->skipped_head,
876 t->ax.skipped_tail, 940 ax->skipped_tail,
877 key); 941 key);
878 GNUNET_free (key); 942 GNUNET_free (key);
879 t->ax.skipped--; 943 ax->skipped--;
880} 944}
881 945
882 946
@@ -884,14 +948,14 @@ delete_skipped_key (struct CadetTunnel *t,
884 * Decrypt and verify data with the appropriate tunnel key and verify that the 948 * Decrypt and verify data with the appropriate tunnel key and verify that the
885 * data has not been altered since it was sent by the remote peer. 949 * data has not been altered since it was sent by the remote peer.
886 * 950 *
887 * @param t Tunnel whose key to use. 951 * @param ax key material to use.
888 * @param dst Destination for the plaintext. 952 * @param dst Destination for the plaintext.
889 * @param src Source of the message. Can overlap with @c dst. 953 * @param src Source of the message. Can overlap with @c dst.
890 * @param size Size of the message. 954 * @param size Size of the message.
891 * @return Size of the decrypted data, -1 if an error was encountered. 955 * @return Size of the decrypted data, -1 if an error was encountered.
892 */ 956 */
893static ssize_t 957static ssize_t
894try_old_ax_keys (struct CadetTunnel *t, 958try_old_ax_keys (struct CadetTunnelAxolotl *ax,
895 void *dst, 959 void *dst,
896 const struct GNUNET_CADET_TunnelEncryptedMessage *src, 960 const struct GNUNET_CADET_TunnelEncryptedMessage *src,
897 size_t size) 961 size_t size)
@@ -913,10 +977,10 @@ try_old_ax_keys (struct CadetTunnel *t,
913 977
914 /* Find a correct Header Key */ 978 /* Find a correct Header Key */
915 valid_HK = NULL; 979 valid_HK = NULL;
916 for (key = t->ax.skipped_head; NULL != key; key = key->next) 980 for (key = ax->skipped_head; NULL != key; key = key->next)
917 { 981 {
918 t_hmac (&src->Ns, 982 t_hmac (&src->ax_header,
919 AX_HEADER_SIZE + esize, 983 sizeof (struct GNUNET_CADET_AxHeader) + esize,
920 0, 984 0,
921 &key->HK, 985 &key->HK,
922 hmac); 986 hmac);
@@ -941,15 +1005,15 @@ try_old_ax_keys (struct CadetTunnel *t,
941 &key->HK, 1005 &key->HK,
942 NULL, 0, 1006 NULL, 0,
943 NULL); 1007 NULL);
944 res = GNUNET_CRYPTO_symmetric_decrypt (&src->Ns, 1008 res = GNUNET_CRYPTO_symmetric_decrypt (&src->ax_header.Ns,
945 AX_HEADER_SIZE, 1009 sizeof (struct GNUNET_CADET_AxHeader),
946 &key->HK, 1010 &key->HK,
947 &iv, 1011 &iv,
948 &plaintext_header.Ns); 1012 &plaintext_header.ax_header.Ns);
949 GNUNET_assert (AX_HEADER_SIZE == res); 1013 GNUNET_assert (sizeof (struct GNUNET_CADET_AxHeader) == res);
950 1014
951 /* Find the correct message key */ 1015 /* Find the correct message key */
952 N = ntohl (plaintext_header.Ns); 1016 N = ntohl (plaintext_header.ax_header.Ns);
953 while ( (NULL != key) && 1017 while ( (NULL != key) &&
954 (N != key->Kn) ) 1018 (N != key->Kn) )
955 key = key->next; 1019 key = key->next;
@@ -970,7 +1034,7 @@ try_old_ax_keys (struct CadetTunnel *t,
970 &key->MK, 1034 &key->MK,
971 &iv, 1035 &iv,
972 dst); 1036 dst);
973 delete_skipped_key (t, 1037 delete_skipped_key (ax,
974 key); 1038 key);
975 return res; 1039 return res;
976} 1040}
@@ -979,32 +1043,32 @@ try_old_ax_keys (struct CadetTunnel *t,
979/** 1043/**
980 * Delete a key from the list of skipped keys. 1044 * Delete a key from the list of skipped keys.
981 * 1045 *
982 * @param t Tunnel to delete from. 1046 * @param ax key material to delete from.
983 * @param HKr Header Key to use. 1047 * @param HKr Header Key to use.
984 */ 1048 */
985static void 1049static void
986store_skipped_key (struct CadetTunnel *t, 1050store_skipped_key (struct CadetTunnelAxolotl *ax,
987 const struct GNUNET_CRYPTO_SymmetricSessionKey *HKr) 1051 const struct GNUNET_CRYPTO_SymmetricSessionKey *HKr)
988{ 1052{
989 struct CadetTunnelSkippedKey *key; 1053 struct CadetTunnelSkippedKey *key;
990 1054
991 key = GNUNET_new (struct CadetTunnelSkippedKey); 1055 key = GNUNET_new (struct CadetTunnelSkippedKey);
992 key->timestamp = GNUNET_TIME_absolute_get (); 1056 key->timestamp = GNUNET_TIME_absolute_get ();
993 key->Kn = t->ax.Nr; 1057 key->Kn = ax->Nr;
994 key->HK = t->ax.HKr; 1058 key->HK = ax->HKr;
995 t_hmac_derive_key (&t->ax.CKr, 1059 t_hmac_derive_key (&ax->CKr,
996 &key->MK, 1060 &key->MK,
997 "0", 1061 "0",
998 1); 1062 1);
999 t_hmac_derive_key (&t->ax.CKr, 1063 t_hmac_derive_key (&ax->CKr,
1000 &t->ax.CKr, 1064 &ax->CKr,
1001 "1", 1065 "1",
1002 1); 1066 1);
1003 GNUNET_CONTAINER_DLL_insert (t->ax.skipped_head, 1067 GNUNET_CONTAINER_DLL_insert (ax->skipped_head,
1004 t->ax.skipped_tail, 1068 ax->skipped_tail,
1005 key); 1069 key);
1006 t->ax.skipped++; 1070 ax->skipped++;
1007 t->ax.Nr++; 1071 ax->Nr++;
1008} 1072}
1009 1073
1010 1074
@@ -1012,33 +1076,33 @@ store_skipped_key (struct CadetTunnel *t,
1012 * Stage skipped AX keys and calculate the message key. 1076 * Stage skipped AX keys and calculate the message key.
1013 * Stores each HK and MK for skipped messages. 1077 * Stores each HK and MK for skipped messages.
1014 * 1078 *
1015 * @param t Tunnel where to stage the keys. 1079 * @param ax key material to use
1016 * @param HKr Header key. 1080 * @param HKr Header key.
1017 * @param Np Received meesage number. 1081 * @param Np Received meesage number.
1018 * @return #GNUNET_OK if keys were stored. 1082 * @return #GNUNET_OK if keys were stored.
1019 * #GNUNET_SYSERR if an error ocurred (Np not expected). 1083 * #GNUNET_SYSERR if an error ocurred (@a Np not expected).
1020 */ 1084 */
1021static int 1085static int
1022store_ax_keys (struct CadetTunnel *t, 1086store_ax_keys (struct CadetTunnelAxolotl *ax,
1023 const struct GNUNET_CRYPTO_SymmetricSessionKey *HKr, 1087 const struct GNUNET_CRYPTO_SymmetricSessionKey *HKr,
1024 uint32_t Np) 1088 uint32_t Np)
1025{ 1089{
1026 int gap; 1090 int gap;
1027 1091
1028 gap = Np - t->ax.Nr; 1092 gap = Np - ax->Nr;
1029 LOG (GNUNET_ERROR_TYPE_DEBUG, 1093 LOG (GNUNET_ERROR_TYPE_DEBUG,
1030 "Storing skipped keys [%u, %u)\n", 1094 "Storing skipped keys [%u, %u)\n",
1031 t->ax.Nr, 1095 ax->Nr,
1032 Np); 1096 Np);
1033 if (MAX_KEY_GAP < gap) 1097 if (MAX_KEY_GAP < gap)
1034 { 1098 {
1035 /* Avoid DoS (forcing peer to do 2^33 chain HMAC operations) */ 1099 /* Avoid DoS (forcing peer to do more than #MAX_KEY_GAP HMAC operations) */
1036 /* TODO: start new key exchange on return */ 1100 /* TODO: start new key exchange on return */
1037 GNUNET_break_op (0); 1101 GNUNET_break_op (0);
1038 LOG (GNUNET_ERROR_TYPE_WARNING, 1102 LOG (GNUNET_ERROR_TYPE_WARNING,
1039 "Got message %u, expected %u+\n", 1103 "Got message %u, expected %u+\n",
1040 Np, 1104 Np,
1041 t->ax.Nr); 1105 ax->Nr);
1042 return GNUNET_SYSERR; 1106 return GNUNET_SYSERR;
1043 } 1107 }
1044 if (0 > gap) 1108 if (0 > gap)
@@ -1047,13 +1111,13 @@ store_ax_keys (struct CadetTunnel *t,
1047 return GNUNET_SYSERR; 1111 return GNUNET_SYSERR;
1048 } 1112 }
1049 1113
1050 while (t->ax.Nr < Np) 1114 while (ax->Nr < Np)
1051 store_skipped_key (t, 1115 store_skipped_key (ax,
1052 HKr); 1116 HKr);
1053 1117
1054 while (t->ax.skipped > MAX_SKIPPED_KEYS) 1118 while (ax->skipped > MAX_SKIPPED_KEYS)
1055 delete_skipped_key (t, 1119 delete_skipped_key (ax,
1056 t->ax.skipped_tail); 1120 ax->skipped_tail);
1057 return GNUNET_OK; 1121 return GNUNET_OK;
1058} 1122}
1059 1123
@@ -1062,19 +1126,18 @@ store_ax_keys (struct CadetTunnel *t,
1062 * Decrypt and verify data with the appropriate tunnel key and verify that the 1126 * Decrypt and verify data with the appropriate tunnel key and verify that the
1063 * data has not been altered since it was sent by the remote peer. 1127 * data has not been altered since it was sent by the remote peer.
1064 * 1128 *
1065 * @param t Tunnel whose key to use. 1129 * @param ax key material to use
1066 * @param dst Destination for the plaintext. 1130 * @param dst Destination for the plaintext.
1067 * @param src Source of the message. Can overlap with @c dst. 1131 * @param src Source of the message. Can overlap with @c dst.
1068 * @param size Size of the message. 1132 * @param size Size of the message.
1069 * @return Size of the decrypted data, -1 if an error was encountered. 1133 * @return Size of the decrypted data, -1 if an error was encountered.
1070 */ 1134 */
1071static ssize_t 1135static ssize_t
1072t_ax_decrypt_and_validate (struct CadetTunnel *t, 1136t_ax_decrypt_and_validate (struct CadetTunnelAxolotl *ax,
1073 void *dst, 1137 void *dst,
1074 const struct GNUNET_CADET_TunnelEncryptedMessage *src, 1138 const struct GNUNET_CADET_TunnelEncryptedMessage *src,
1075 size_t size) 1139 size_t size)
1076{ 1140{
1077 struct CadetTunnelAxolotl *ax;
1078 struct GNUNET_ShortHashCode msg_hmac; 1141 struct GNUNET_ShortHashCode msg_hmac;
1079 struct GNUNET_HashCode hmac; 1142 struct GNUNET_HashCode hmac;
1080 struct GNUNET_CADET_TunnelEncryptedMessage plaintext_header; 1143 struct GNUNET_CADET_TunnelEncryptedMessage plaintext_header;
@@ -1083,11 +1146,10 @@ t_ax_decrypt_and_validate (struct CadetTunnel *t,
1083 size_t esize; /* Size of encryped payload */ 1146 size_t esize; /* Size of encryped payload */
1084 1147
1085 esize = size - sizeof (struct GNUNET_CADET_TunnelEncryptedMessage); 1148 esize = size - sizeof (struct GNUNET_CADET_TunnelEncryptedMessage);
1086 ax = &t->ax;
1087 1149
1088 /* Try current HK */ 1150 /* Try current HK */
1089 t_hmac (&src->Ns, 1151 t_hmac (&src->ax_header,
1090 AX_HEADER_SIZE + esize, 1152 sizeof (struct GNUNET_CADET_AxHeader) + esize,
1091 0, &ax->HKr, 1153 0, &ax->HKr,
1092 &msg_hmac); 1154 &msg_hmac);
1093 if (0 != memcmp (&msg_hmac, 1155 if (0 != memcmp (&msg_hmac,
@@ -1101,8 +1163,8 @@ t_ax_decrypt_and_validate (struct CadetTunnel *t,
1101 struct GNUNET_CRYPTO_EcdhePublicKey *DHRp; 1163 struct GNUNET_CRYPTO_EcdhePublicKey *DHRp;
1102 1164
1103 /* Try Next HK */ 1165 /* Try Next HK */
1104 t_hmac (&src->Ns, 1166 t_hmac (&src->ax_header,
1105 AX_HEADER_SIZE + esize, 1167 sizeof (struct GNUNET_CADET_AxHeader) + esize,
1106 0, 1168 0,
1107 &ax->NHKr, 1169 &ax->NHKr,
1108 &msg_hmac); 1170 &msg_hmac);
@@ -1111,25 +1173,25 @@ t_ax_decrypt_and_validate (struct CadetTunnel *t,
1111 sizeof (msg_hmac))) 1173 sizeof (msg_hmac)))
1112 { 1174 {
1113 /* Try the skipped keys, if that fails, we're out of luck. */ 1175 /* Try the skipped keys, if that fails, we're out of luck. */
1114 return try_old_ax_keys (t, 1176 return try_old_ax_keys (ax,
1115 dst, 1177 dst,
1116 src, 1178 src,
1117 size); 1179 size);
1118 } 1180 }
1119 HK = ax->HKr; 1181 HK = ax->HKr;
1120 ax->HKr = ax->NHKr; 1182 ax->HKr = ax->NHKr;
1121 t_h_decrypt (t, 1183 t_h_decrypt (ax,
1122 src, 1184 src,
1123 &plaintext_header); 1185 &plaintext_header);
1124 Np = ntohl (plaintext_header.Ns); 1186 Np = ntohl (plaintext_header.ax_header.Ns);
1125 PNp = ntohl (plaintext_header.PNs); 1187 PNp = ntohl (plaintext_header.ax_header.PNs);
1126 DHRp = &plaintext_header.DHRs; 1188 DHRp = &plaintext_header.ax_header.DHRs;
1127 store_ax_keys (t, 1189 store_ax_keys (ax,
1128 &HK, 1190 &HK,
1129 PNp); 1191 PNp);
1130 1192
1131 /* RKp, NHKp, CKp = KDF (HMAC-HASH (RK, DH (DHRp, DHRs))) */ 1193 /* RKp, NHKp, CKp = KDF (HMAC-HASH (RK, DH (DHRp, DHRs))) */
1132 GNUNET_CRYPTO_ecc_ecdh (ax->DHRs, 1194 GNUNET_CRYPTO_ecc_ecdh (&ax->DHRs,
1133 DHRp, 1195 DHRp,
1134 &dh); 1196 &dh);
1135 t_ax_hmac_hash (&ax->RK, 1197 t_ax_hmac_hash (&ax->RK,
@@ -1150,25 +1212,25 @@ t_ax_decrypt_and_validate (struct CadetTunnel *t,
1150 } 1212 }
1151 else 1213 else
1152 { 1214 {
1153 t_h_decrypt (t, 1215 t_h_decrypt (ax,
1154 src, 1216 src,
1155 &plaintext_header); 1217 &plaintext_header);
1156 Np = ntohl (plaintext_header.Ns); 1218 Np = ntohl (plaintext_header.ax_header.Ns);
1157 PNp = ntohl (plaintext_header.PNs); 1219 PNp = ntohl (plaintext_header.ax_header.PNs);
1158 } 1220 }
1159 if ( (Np != ax->Nr) && 1221 if ( (Np != ax->Nr) &&
1160 (GNUNET_OK != store_ax_keys (t, 1222 (GNUNET_OK != store_ax_keys (ax,
1161 &ax->HKr, 1223 &ax->HKr,
1162 Np)) ) 1224 Np)) )
1163 { 1225 {
1164 /* Try the skipped keys, if that fails, we're out of luck. */ 1226 /* Try the skipped keys, if that fails, we're out of luck. */
1165 return try_old_ax_keys (t, 1227 return try_old_ax_keys (ax,
1166 dst, 1228 dst,
1167 src, 1229 src,
1168 size); 1230 size);
1169 } 1231 }
1170 1232
1171 t_ax_decrypt (t, 1233 t_ax_decrypt (ax,
1172 dst, 1234 dst,
1173 &src[1], 1235 &src[1],
1174 esize); 1236 esize);
@@ -1213,10 +1275,10 @@ GCT_change_estate (struct CadetTunnel *t,
1213 1275
1214 t->estate = state; 1276 t->estate = state;
1215 LOG (GNUNET_ERROR_TYPE_DEBUG, 1277 LOG (GNUNET_ERROR_TYPE_DEBUG,
1216 "Tunnel %s estate changed from %d to %d\n", 1278 "%s estate changed from %s to %s\n",
1217 GCT_2s (t), 1279 GCT_2s (t),
1218 old, 1280 estate2s (old),
1219 state); 1281 estate2s (state));
1220 1282
1221 if ( (CADET_TUNNEL_KEY_OK != old) && 1283 if ( (CADET_TUNNEL_KEY_OK != old) &&
1222 (CADET_TUNNEL_KEY_OK == t->estate) ) 1284 (CADET_TUNNEL_KEY_OK == t->estate) )
@@ -1226,15 +1288,14 @@ GCT_change_estate (struct CadetTunnel *t,
1226 GNUNET_SCHEDULER_cancel (t->kx_task); 1288 GNUNET_SCHEDULER_cancel (t->kx_task);
1227 t->kx_task = NULL; 1289 t->kx_task = NULL;
1228 } 1290 }
1229 if (CADET_TUNNEL_KEY_REKEY != old) 1291 /* notify all channels that have been waiting */
1230 { 1292 GNUNET_CONTAINER_multihashmap32_iterate (t->channels,
1231 /* notify all channels that have been waiting */ 1293 &notify_tunnel_up_cb,
1232 GNUNET_CONTAINER_multihashmap32_iterate (t->channels, 1294 t);
1233 &notify_tunnel_up_cb, 1295 if (NULL != t->send_task)
1234 t); 1296 GNUNET_SCHEDULER_cancel (t->send_task);
1235 } 1297 t->send_task = GNUNET_SCHEDULER_add_now (&trigger_transmissions,
1236 1298 t);
1237 /* FIXME: schedule rekey task! */
1238 } 1299 }
1239} 1300}
1240 1301
@@ -1242,80 +1303,179 @@ GCT_change_estate (struct CadetTunnel *t,
1242/** 1303/**
1243 * Send a KX message. 1304 * Send a KX message.
1244 * 1305 *
1245 * FIXME: does not take care of sender-authentication yet! 1306 * @param t tunnel on which to send the KX_AUTH
1246 * 1307 * @param ct Tunnel and connection on which to send the KX_AUTH, NULL if
1247 * @param t Tunnel on which to send it. 1308 * we are to find one that is ready.
1248 * @param force_reply Force the other peer to reply with a KX message. 1309 * @param ax axolotl key context to use
1249 */ 1310 */
1250static void 1311static void
1251send_kx (struct CadetTunnel *t, 1312send_kx (struct CadetTunnel *t,
1252 int force_reply) 1313 struct CadetTConnection *ct,
1314 struct CadetTunnelAxolotl *ax)
1253{ 1315{
1254 struct CadetTunnelAxolotl *ax = &t->ax;
1255 struct CadetTConnection *ct;
1256 struct CadetConnection *cc; 1316 struct CadetConnection *cc;
1257 struct GNUNET_MQ_Envelope *env; 1317 struct GNUNET_MQ_Envelope *env;
1258 struct GNUNET_CADET_TunnelKeyExchangeMessage *msg; 1318 struct GNUNET_CADET_TunnelKeyExchangeMessage *msg;
1259 enum GNUNET_CADET_KX_Flags flags; 1319 enum GNUNET_CADET_KX_Flags flags;
1260 1320
1261 ct = get_ready_connection (t); 1321 if ( (NULL == ct) ||
1322 (GNUNET_NO == ct->is_ready) )
1323 ct = get_ready_connection (t);
1262 if (NULL == ct) 1324 if (NULL == ct)
1263 { 1325 {
1264 LOG (GNUNET_ERROR_TYPE_DEBUG, 1326 LOG (GNUNET_ERROR_TYPE_DEBUG,
1265 "Wanted to send KX on tunnel %s, but no connection is ready, deferring\n", 1327 "Wanted to send %s in state %s, but no connection is ready, deferring\n",
1266 GCT_2s (t)); 1328 GCT_2s (t),
1329 estate2s (t->estate));
1330 t->next_kx_attempt = GNUNET_TIME_absolute_get ();
1267 return; 1331 return;
1268 } 1332 }
1269 cc = ct->cc; 1333 cc = ct->cc;
1270 LOG (GNUNET_ERROR_TYPE_DEBUG, 1334 LOG (GNUNET_ERROR_TYPE_DEBUG,
1271 "Sending KX on tunnel %s using connection %s\n", 1335 "Sending KX on %s via %s in state %s\n",
1272 GCT_2s (t), 1336 GCT_2s (t),
1273 GCC_2s (ct->cc)); 1337 GCC_2s (cc),
1274 1338 estate2s (t->estate));
1275 // GNUNET_assert (GNUNET_NO == GCT_is_loopback (t));
1276 env = GNUNET_MQ_msg (msg, 1339 env = GNUNET_MQ_msg (msg,
1277 GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX); 1340 GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX);
1278 flags = GNUNET_CADET_KX_FLAG_NONE; 1341 flags = GNUNET_CADET_KX_FLAG_FORCE_REPLY; /* always for KX */
1279 if (GNUNET_YES == force_reply)
1280 flags |= GNUNET_CADET_KX_FLAG_FORCE_REPLY;
1281 msg->flags = htonl (flags); 1342 msg->flags = htonl (flags);
1282 msg->cid = *GCC_get_id (cc); 1343 msg->cid = *GCC_get_id (cc);
1283 GNUNET_CRYPTO_ecdhe_key_get_public (ax->kx_0, 1344 GNUNET_CRYPTO_ecdhe_key_get_public (&ax->kx_0,
1284 &msg->ephemeral_key); 1345 &msg->ephemeral_key);
1285 GNUNET_CRYPTO_ecdhe_key_get_public (ax->DHRs, 1346 GNUNET_CRYPTO_ecdhe_key_get_public (&ax->DHRs,
1286 &msg->ratchet_key); 1347 &msg->ratchet_key);
1287 ct->is_ready = GNUNET_NO; 1348 mark_connection_unready (ct);
1288 GCC_transmit (cc,
1289 env);
1290 t->kx_retry_delay = GNUNET_TIME_STD_BACKOFF (t->kx_retry_delay); 1349 t->kx_retry_delay = GNUNET_TIME_STD_BACKOFF (t->kx_retry_delay);
1291 t->next_kx_attempt = GNUNET_TIME_relative_to_absolute (t->kx_retry_delay); 1350 t->next_kx_attempt = GNUNET_TIME_relative_to_absolute (t->kx_retry_delay);
1292 if (CADET_TUNNEL_KEY_UNINITIALIZED == t->estate) 1351 if (CADET_TUNNEL_KEY_UNINITIALIZED == t->estate)
1293 GCT_change_estate (t, 1352 GCT_change_estate (t,
1294 CADET_TUNNEL_KEY_SENT); 1353 CADET_TUNNEL_KEY_AX_SENT);
1354 else if (CADET_TUNNEL_KEY_AX_RECV == t->estate)
1355 GCT_change_estate (t,
1356 CADET_TUNNEL_KEY_AX_SENT_AND_RECV);
1357 GCC_transmit (cc,
1358 env);
1359}
1360
1361
1362/**
1363 * Send a KX_AUTH message.
1364 *
1365 * @param t tunnel on which to send the KX_AUTH
1366 * @param ct Tunnel and connection on which to send the KX_AUTH, NULL if
1367 * we are to find one that is ready.
1368 * @param ax axolotl key context to use
1369 * @param force_reply Force the other peer to reply with a KX_AUTH message
1370 * (set if we would like to transmit right now, but cannot)
1371 */
1372static void
1373send_kx_auth (struct CadetTunnel *t,
1374 struct CadetTConnection *ct,
1375 struct CadetTunnelAxolotl *ax,
1376 int force_reply)
1377{
1378 struct CadetConnection *cc;
1379 struct GNUNET_MQ_Envelope *env;
1380 struct GNUNET_CADET_TunnelKeyExchangeAuthMessage *msg;
1381 enum GNUNET_CADET_KX_Flags flags;
1382
1383 if ( (NULL == ct) ||
1384 (GNUNET_NO == ct->is_ready) )
1385 ct = get_ready_connection (t);
1386 if (NULL == ct)
1387 {
1388 LOG (GNUNET_ERROR_TYPE_DEBUG,
1389 "Wanted to send KX_AUTH on %s, but no connection is ready, deferring\n",
1390 GCT_2s (t));
1391 t->next_kx_attempt = GNUNET_TIME_absolute_get ();
1392 t->kx_auth_requested = GNUNET_YES; /* queue KX_AUTH independent of estate */
1393 return;
1394 }
1395 t->kx_auth_requested = GNUNET_NO; /* clear flag */
1396 cc = ct->cc;
1397 LOG (GNUNET_ERROR_TYPE_DEBUG,
1398 "Sending KX_AUTH on %s using %s\n",
1399 GCT_2s (t),
1400 GCC_2s (ct->cc));
1401
1402 env = GNUNET_MQ_msg (msg,
1403 GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX_AUTH);
1404 flags = GNUNET_CADET_KX_FLAG_NONE;
1405 if (GNUNET_YES == force_reply)
1406 flags |= GNUNET_CADET_KX_FLAG_FORCE_REPLY;
1407 msg->kx.flags = htonl (flags);
1408 msg->kx.cid = *GCC_get_id (cc);
1409 GNUNET_CRYPTO_ecdhe_key_get_public (&ax->kx_0,
1410 &msg->kx.ephemeral_key);
1411 GNUNET_CRYPTO_ecdhe_key_get_public (&ax->DHRs,
1412 &msg->kx.ratchet_key);
1413 /* Compute authenticator (this is the main difference to #send_kx()) */
1414 GNUNET_CRYPTO_hash (&ax->RK,
1415 sizeof (ax->RK),
1416 &msg->auth);
1417
1418 /* Compute when to be triggered again; actual job will
1419 be scheduled via #connection_ready_cb() */
1420 t->kx_retry_delay
1421 = GNUNET_TIME_STD_BACKOFF (t->kx_retry_delay);
1422 t->next_kx_attempt
1423 = GNUNET_TIME_relative_to_absolute (t->kx_retry_delay);
1424
1425 /* Send via cc, mark it as unready */
1426 mark_connection_unready (ct);
1427
1428 /* Update state machine, unless we are already OK */
1429 if (CADET_TUNNEL_KEY_OK != t->estate)
1430 GCT_change_estate (t,
1431 CADET_TUNNEL_KEY_AX_AUTH_SENT);
1432
1433 GCC_transmit (cc,
1434 env);
1295} 1435}
1296 1436
1297 1437
1298/** 1438/**
1299 * Handle KX message. 1439 * Cleanup state used by @a ax.
1300 * 1440 *
1301 * FIXME: sender-authentication in KX is missing! 1441 * @param ax state to free, but not memory of @a ax itself
1442 */
1443static void
1444cleanup_ax (struct CadetTunnelAxolotl *ax)
1445{
1446 while (NULL != ax->skipped_head)
1447 delete_skipped_key (ax,
1448 ax->skipped_head);
1449 GNUNET_assert (0 == ax->skipped);
1450 GNUNET_CRYPTO_ecdhe_key_clear (&ax->kx_0);
1451 GNUNET_CRYPTO_ecdhe_key_clear (&ax->DHRs);
1452}
1453
1454
1455/**
1456 * Update our Axolotl key state based on the KX data we received.
1457 * Computes the new chain keys, and root keys, etc, and also checks
1458 * wether this is a replay of the current chain.
1302 * 1459 *
1303 * @param ct connection/tunnel combo that received encrypted message 1460 * @param[in|out] axolotl chain key state to recompute
1304 * @param msg the key exchange message 1461 * @param pid peer identity of the other peer
1462 * @param ephemeral_key ephemeral public key of the other peer
1463 * @param ratchet_key senders next ephemeral public key
1464 * @return #GNUNET_OK on success, #GNUNET_NO if the resulting
1465 * root key is already in @a ax and thus the KX is useless;
1466 * #GNUNET_SYSERR on hard errors (i.e. @a pid is #my_full_id)
1305 */ 1467 */
1306void 1468static int
1307GCT_handle_kx (struct CadetTConnection *ct, 1469update_ax_by_kx (struct CadetTunnelAxolotl *ax,
1308 const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg) 1470 const struct GNUNET_PeerIdentity *pid,
1471 const struct GNUNET_CRYPTO_EcdhePublicKey *ephemeral_key,
1472 const struct GNUNET_CRYPTO_EcdhePublicKey *ratchet_key)
1309{ 1473{
1310 struct CadetTunnel *t = ct->t;
1311 struct CadetTunnelAxolotl *ax = &t->ax;
1312 struct GNUNET_HashCode key_material[3]; 1474 struct GNUNET_HashCode key_material[3];
1313 struct GNUNET_CRYPTO_SymmetricSessionKey keys[5]; 1475 struct GNUNET_CRYPTO_SymmetricSessionKey keys[5];
1314 const char salt[] = "CADET Axolotl salt"; 1476 const char salt[] = "CADET Axolotl salt";
1315 const struct GNUNET_PeerIdentity *pid;
1316 int am_I_alice; 1477 int am_I_alice;
1317 1478
1318 pid = GCP_get_id (t->destination);
1319 if (0 > GNUNET_CRYPTO_cmp_peer_identity (&my_full_id, 1479 if (0 > GNUNET_CRYPTO_cmp_peer_identity (&my_full_id,
1320 pid)) 1480 pid))
1321 am_I_alice = GNUNET_YES; 1481 am_I_alice = GNUNET_YES;
@@ -1325,41 +1485,30 @@ GCT_handle_kx (struct CadetTConnection *ct,
1325 else 1485 else
1326 { 1486 {
1327 GNUNET_break_op (0); 1487 GNUNET_break_op (0);
1328 return; 1488 return GNUNET_SYSERR;
1329 }
1330
1331 if (0 != (GNUNET_CADET_KX_FLAG_FORCE_REPLY & ntohl (msg->flags)))
1332 {
1333 if (NULL != t->kx_task)
1334 {
1335 GNUNET_SCHEDULER_cancel (t->kx_task);
1336 t->kx_task = NULL;
1337 }
1338 send_kx (t,
1339 GNUNET_NO);
1340 } 1489 }
1341 1490
1342 if (0 == memcmp (&ax->DHRr, 1491 if (0 == memcmp (&ax->DHRr,
1343 &msg->ratchet_key, 1492 ratchet_key,
1344 sizeof (msg->ratchet_key))) 1493 sizeof (*ratchet_key)))
1345 { 1494 {
1346 LOG (GNUNET_ERROR_TYPE_DEBUG, 1495 LOG (GNUNET_ERROR_TYPE_DEBUG,
1347 " known ratchet key, exit\n"); 1496 "Ratchet key already known. Ignoring KX.\n");
1348 return; 1497 return GNUNET_NO;
1349 } 1498 }
1350 1499
1351 ax->DHRr = msg->ratchet_key; 1500 ax->DHRr = *ratchet_key;
1352 1501
1353 /* ECDH A B0 */ 1502 /* ECDH A B0 */
1354 if (GNUNET_YES == am_I_alice) 1503 if (GNUNET_YES == am_I_alice)
1355 { 1504 {
1356 GNUNET_CRYPTO_eddsa_ecdh (my_private_key, /* A */ 1505 GNUNET_CRYPTO_eddsa_ecdh (my_private_key, /* A */
1357 &msg->ephemeral_key, /* B0 */ 1506 ephemeral_key, /* B0 */
1358 &key_material[0]); 1507 &key_material[0]);
1359 } 1508 }
1360 else 1509 else
1361 { 1510 {
1362 GNUNET_CRYPTO_ecdh_eddsa (ax->kx_0, /* B0 */ 1511 GNUNET_CRYPTO_ecdh_eddsa (&ax->kx_0, /* B0 */
1363 &pid->public_key, /* A */ 1512 &pid->public_key, /* A */
1364 &key_material[0]); 1513 &key_material[0]);
1365 } 1514 }
@@ -1367,14 +1516,14 @@ GCT_handle_kx (struct CadetTConnection *ct,
1367 /* ECDH A0 B */ 1516 /* ECDH A0 B */
1368 if (GNUNET_YES == am_I_alice) 1517 if (GNUNET_YES == am_I_alice)
1369 { 1518 {
1370 GNUNET_CRYPTO_ecdh_eddsa (ax->kx_0, /* A0 */ 1519 GNUNET_CRYPTO_ecdh_eddsa (&ax->kx_0, /* A0 */
1371 &pid->public_key, /* B */ 1520 &pid->public_key, /* B */
1372 &key_material[1]); 1521 &key_material[1]);
1373 } 1522 }
1374 else 1523 else
1375 { 1524 {
1376 GNUNET_CRYPTO_eddsa_ecdh (my_private_key, /* A */ 1525 GNUNET_CRYPTO_eddsa_ecdh (my_private_key, /* A */
1377 &msg->ephemeral_key, /* B0 */ 1526 ephemeral_key, /* B0 */
1378 &key_material[1]); 1527 &key_material[1]);
1379 1528
1380 1529
@@ -1383,8 +1532,8 @@ GCT_handle_kx (struct CadetTConnection *ct,
1383 /* ECDH A0 B0 */ 1532 /* ECDH A0 B0 */
1384 /* (This is the triple-DH, we could probably safely skip this, 1533 /* (This is the triple-DH, we could probably safely skip this,
1385 as A0/B0 are already in the key material.) */ 1534 as A0/B0 are already in the key material.) */
1386 GNUNET_CRYPTO_ecc_ecdh (ax->kx_0, /* A0 or B0 */ 1535 GNUNET_CRYPTO_ecc_ecdh (&ax->kx_0, /* A0 or B0 */
1387 &msg->ephemeral_key, /* B0 or A0 */ 1536 ephemeral_key, /* B0 or A0 */
1388 &key_material[2]); 1537 &key_material[2]);
1389 1538
1390 /* KDF */ 1539 /* KDF */
@@ -1397,13 +1546,10 @@ GCT_handle_kx (struct CadetTConnection *ct,
1397 &keys[0], 1546 &keys[0],
1398 sizeof (ax->RK))) 1547 sizeof (ax->RK)))
1399 { 1548 {
1400 LOG (GNUNET_ERROR_TYPE_INFO, 1549 LOG (GNUNET_ERROR_TYPE_DEBUG,
1401 " known handshake key, exit\n"); 1550 "Root key of handshake already known. Ignoring KX.\n");
1402 return; 1551 return GNUNET_NO;
1403 } 1552 }
1404 LOG (GNUNET_ERROR_TYPE_DEBUG,
1405 "Handling KX message for tunnel %s\n",
1406 GCT_2s (t));
1407 1553
1408 ax->RK = keys[0]; 1554 ax->RK = keys[0];
1409 if (GNUNET_YES == am_I_alice) 1555 if (GNUNET_YES == am_I_alice)
@@ -1421,45 +1567,305 @@ GCT_handle_kx (struct CadetTConnection *ct,
1421 ax->NHKs = keys[3]; 1567 ax->NHKs = keys[3];
1422 ax->CKs = keys[4]; 1568 ax->CKs = keys[4];
1423 ax->ratchet_flag = GNUNET_NO; 1569 ax->ratchet_flag = GNUNET_NO;
1424 ax->ratchet_allowed = GNUNET_NO;
1425 ax->ratchet_counter = 0;
1426 ax->ratchet_expiration 1570 ax->ratchet_expiration
1427 = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get(), 1571 = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get(),
1428 ratchet_time); 1572 ratchet_time);
1429 } 1573 }
1430 ax->PNs = 0; 1574 return GNUNET_OK;
1431 ax->Nr = 0; 1575}
1432 ax->Ns = 0;
1433 1576
1577
1578/**
1579 * Try to redo the KX or KX_AUTH handshake, if we can.
1580 *
1581 * @param cls the `struct CadetTunnel` to do KX for.
1582 */
1583static void
1584retry_kx (void *cls)
1585{
1586 struct CadetTunnel *t = cls;
1587 struct CadetTunnelAxolotl *ax;
1588
1589 t->kx_task = NULL;
1590 LOG (GNUNET_ERROR_TYPE_DEBUG,
1591 "Trying to make KX progress on %s in state %s\n",
1592 GCT_2s (t),
1593 estate2s (t->estate));
1434 switch (t->estate) 1594 switch (t->estate)
1435 { 1595 {
1436 case CADET_TUNNEL_KEY_UNINITIALIZED: 1596 case CADET_TUNNEL_KEY_UNINITIALIZED: /* first attempt */
1597 case CADET_TUNNEL_KEY_AX_SENT: /* trying again */
1598 send_kx (t,
1599 NULL,
1600 &t->ax);
1601 break;
1602 case CADET_TUNNEL_KEY_AX_RECV:
1603 case CADET_TUNNEL_KEY_AX_SENT_AND_RECV:
1604 /* We are responding, so only require reply
1605 if WE have a channel waiting. */
1606 if (NULL != t->unverified_ax)
1607 {
1608 /* Send AX_AUTH so we might get this one verified */
1609 ax = t->unverified_ax;
1610 }
1611 else
1612 {
1613 /* How can this be? */
1614 GNUNET_break (0);
1615 ax = &t->ax;
1616 }
1617 send_kx_auth (t,
1618 NULL,
1619 ax,
1620 (0 == GCT_count_channels (t))
1621 ? GNUNET_NO
1622 : GNUNET_YES);
1623 break;
1624 case CADET_TUNNEL_KEY_AX_AUTH_SENT:
1625 /* We are responding, so only require reply
1626 if WE have a channel waiting. */
1627 if (NULL != t->unverified_ax)
1628 {
1629 /* Send AX_AUTH so we might get this one verified */
1630 ax = t->unverified_ax;
1631 }
1632 else
1633 {
1634 /* How can this be? */
1635 GNUNET_break (0);
1636 ax = &t->ax;
1637 }
1638 send_kx_auth (t,
1639 NULL,
1640 ax,
1641 (0 == GCT_count_channels (t))
1642 ? GNUNET_NO
1643 : GNUNET_YES);
1644 break;
1645 case CADET_TUNNEL_KEY_OK:
1646 /* Must have been the *other* peer asking us to
1647 respond with a KX_AUTH. */
1648 if (NULL != t->unverified_ax)
1649 {
1650 /* Sending AX_AUTH in response to AX so we might get this one verified */
1651 ax = t->unverified_ax;
1652 }
1653 else
1654 {
1655 /* Sending AX_AUTH in response to AX_AUTH */
1656 ax = &t->ax;
1657 }
1658 send_kx_auth (t,
1659 NULL,
1660 ax,
1661 GNUNET_NO);
1662 break;
1663 }
1664}
1665
1666
1667/**
1668 * Handle KX message that lacks authentication (and which will thus
1669 * only be considered authenticated after we respond with our own
1670 * KX_AUTH and finally successfully decrypt payload).
1671 *
1672 * @param ct connection/tunnel combo that received encrypted message
1673 * @param msg the key exchange message
1674 */
1675void
1676GCT_handle_kx (struct CadetTConnection *ct,
1677 const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg)
1678{
1679 struct CadetTunnel *t = ct->t;
1680 struct CadetTunnelAxolotl *ax;
1681 int ret;
1682
1683 if (0 ==
1684 memcmp (&t->ax.DHRr,
1685 &msg->ratchet_key,
1686 sizeof (msg->ratchet_key)))
1687 {
1688 LOG (GNUNET_ERROR_TYPE_DEBUG,
1689 "Got duplicate KX. Firing back KX_AUTH.\n");
1690 send_kx_auth (t,
1691 ct,
1692 &t->ax,
1693 GNUNET_NO);
1694 return;
1695 }
1696
1697 /* We only keep ONE unverified KX around, so if there is an existing one,
1698 clean it up. */
1699 if (NULL != t->unverified_ax)
1700 {
1701 if (0 ==
1702 memcmp (&t->unverified_ax->DHRr,
1703 &msg->ratchet_key,
1704 sizeof (msg->ratchet_key)))
1705 {
1706 LOG (GNUNET_ERROR_TYPE_DEBUG,
1707 "Got duplicate unverified KX on %s. Fire back KX_AUTH again.\n",
1708 GCT_2s (t));
1709 send_kx_auth (t,
1710 ct,
1711 t->unverified_ax,
1712 GNUNET_NO);
1713 return;
1714 }
1715 LOG (GNUNET_ERROR_TYPE_DEBUG,
1716 "Dropping old unverified KX state. Got a fresh KX for %s.\n",
1717 GCT_2s (t));
1718 memset (t->unverified_ax,
1719 0,
1720 sizeof (struct CadetTunnelAxolotl));
1721 t->unverified_ax->DHRs = t->ax.DHRs;
1722 t->unverified_ax->kx_0 = t->ax.kx_0;
1723 }
1724 else
1725 {
1726 LOG (GNUNET_ERROR_TYPE_DEBUG,
1727 "Creating fresh unverified KX for %s.\n",
1728 GCT_2s (t));
1729 t->unverified_ax = GNUNET_new (struct CadetTunnelAxolotl);
1730 t->unverified_ax->DHRs = t->ax.DHRs;
1731 t->unverified_ax->kx_0 = t->ax.kx_0;
1732 }
1733 /* Set as the 'current' RK/DHRr the one we are currently using,
1734 so that the duplicate-detection logic of
1735 #update_ax_by_kx can work. */
1736 t->unverified_ax->RK = t->ax.RK;
1737 t->unverified_ax->DHRr = t->ax.DHRr;
1738 t->unverified_attempts = 0;
1739 ax = t->unverified_ax;
1740
1741 /* Update 'ax' by the new key material */
1742 ret = update_ax_by_kx (ax,
1743 GCP_get_id (t->destination),
1744 &msg->ephemeral_key,
1745 &msg->ratchet_key);
1746 GNUNET_break (GNUNET_SYSERR != ret);
1747 if (GNUNET_OK != ret)
1748 return; /* duplicate KX, nothing to do */
1749
1750 /* move ahead in our state machine */
1751 if (CADET_TUNNEL_KEY_UNINITIALIZED == t->estate)
1752 GCT_change_estate (t,
1753 CADET_TUNNEL_KEY_AX_RECV);
1754 else if (CADET_TUNNEL_KEY_AX_SENT == t->estate)
1437 GCT_change_estate (t, 1755 GCT_change_estate (t,
1438 CADET_TUNNEL_KEY_PING); 1756 CADET_TUNNEL_KEY_AX_SENT_AND_RECV);
1757
1758 /* KX is still not done, try again our end. */
1759 if (CADET_TUNNEL_KEY_OK != t->estate)
1760 {
1761 if (NULL != t->kx_task)
1762 GNUNET_SCHEDULER_cancel (t->kx_task);
1763 t->kx_task
1764 = GNUNET_SCHEDULER_add_now (&retry_kx,
1765 t);
1766 }
1767}
1768
1769
1770/**
1771 * Handle KX_AUTH message.
1772 *
1773 * @param ct connection/tunnel combo that received encrypted message
1774 * @param msg the key exchange message
1775 */
1776void
1777GCT_handle_kx_auth (struct CadetTConnection *ct,
1778 const struct GNUNET_CADET_TunnelKeyExchangeAuthMessage *msg)
1779{
1780 struct CadetTunnel *t = ct->t;
1781 struct CadetTunnelAxolotl ax_tmp;
1782 struct GNUNET_HashCode kx_auth;
1783 int ret;
1784
1785 if ( (CADET_TUNNEL_KEY_UNINITIALIZED == t->estate) ||
1786 (CADET_TUNNEL_KEY_AX_RECV == t->estate) )
1787 {
1788 /* Confusing, we got a KX_AUTH before we even send our own
1789 KX. This should not happen. We'll send our own KX ASAP anyway,
1790 so let's ignore this here. */
1791 GNUNET_break_op (0);
1792 return;
1793 }
1794 LOG (GNUNET_ERROR_TYPE_DEBUG,
1795 "Handling KX_AUTH message for %s\n",
1796 GCT_2s (t));
1797
1798 /* We do everything in ax_tmp until we've checked the authentication
1799 so we don't clobber anything we care about by accident. */
1800 ax_tmp = t->ax;
1801
1802 /* Update 'ax' by the new key material */
1803 ret = update_ax_by_kx (&ax_tmp,
1804 GCP_get_id (t->destination),
1805 &msg->kx.ephemeral_key,
1806 &msg->kx.ratchet_key);
1807 if (GNUNET_OK != ret)
1808 {
1809 if (GNUNET_NO == ret)
1810 GNUNET_STATISTICS_update (stats,
1811 "# redundant KX_AUTH received",
1812 1,
1813 GNUNET_NO);
1814 else
1815 GNUNET_break (0); /* connect to self!? */
1816 return;
1817 }
1818 GNUNET_CRYPTO_hash (&ax_tmp.RK,
1819 sizeof (ax_tmp.RK),
1820 &kx_auth);
1821 if (0 != memcmp (&kx_auth,
1822 &msg->auth,
1823 sizeof (kx_auth)))
1824 {
1825 /* This KX_AUTH is not using the latest KX/KX_AUTH data
1826 we transmitted to the sender, refuse it, try KX again. */
1827 GNUNET_STATISTICS_update (stats,
1828 "# KX_AUTH not using our last KX received (auth failure)",
1829 1,
1830 GNUNET_NO);
1831 send_kx (t,
1832 ct,
1833 &t->ax);
1834 return;
1835 }
1836 /* Yep, we're good. */
1837 t->ax = ax_tmp;
1838 if (NULL != t->unverified_ax)
1839 {
1840 /* We got some "stale" KX before, drop that. */
1841 cleanup_ax (t->unverified_ax);
1842 GNUNET_free (t->unverified_ax);
1843 t->unverified_ax = NULL;
1844 }
1845
1846 /* move ahead in our state machine */
1847 switch (t->estate)
1848 {
1849 case CADET_TUNNEL_KEY_UNINITIALIZED:
1850 case CADET_TUNNEL_KEY_AX_RECV:
1851 /* Checked above, this is impossible. */
1852 GNUNET_assert (0);
1439 break; 1853 break;
1440 case CADET_TUNNEL_KEY_SENT: 1854 case CADET_TUNNEL_KEY_AX_SENT: /* This is the normal case */
1441 /* Got a response to us sending our key; now 1855 case CADET_TUNNEL_KEY_AX_SENT_AND_RECV: /* both peers started KX */
1442 we can start transmitting! */ 1856 case CADET_TUNNEL_KEY_AX_AUTH_SENT: /* both peers now did KX_AUTH */
1443 GCT_change_estate (t, 1857 GCT_change_estate (t,
1444 CADET_TUNNEL_KEY_OK); 1858 CADET_TUNNEL_KEY_OK);
1445 if (NULL != t->send_task)
1446 GNUNET_SCHEDULER_cancel (t->send_task);
1447 t->send_task = GNUNET_SCHEDULER_add_now (&trigger_transmissions,
1448 t);
1449 break;
1450 case CADET_TUNNEL_KEY_PING:
1451 /* Got a key yet again; need encrypted payload to advance */
1452 break; 1859 break;
1453 case CADET_TUNNEL_KEY_OK: 1860 case CADET_TUNNEL_KEY_OK:
1454 /* Did not expect a key, but so what. */ 1861 /* Did not expect another KX_AUTH, but so what, still acceptable.
1455 break; 1862 Nothing to do here. */
1456 case CADET_TUNNEL_KEY_REKEY:
1457 /* Got a key yet again; need encrypted payload to advance */
1458 break; 1863 break;
1459 } 1864 }
1460} 1865}
1461 1866
1462 1867
1868
1463/* ************************************** end core crypto ***************************** */ 1869/* ************************************** end core crypto ***************************** */
1464 1870
1465 1871
@@ -1489,12 +1895,12 @@ get_next_free_ctn (struct CadetTunnel *t)
1489 ctn = ntohl (t->next_ctn.cn); 1895 ctn = ntohl (t->next_ctn.cn);
1490 while (NULL != 1896 while (NULL !=
1491 GNUNET_CONTAINER_multihashmap32_get (t->channels, 1897 GNUNET_CONTAINER_multihashmap32_get (t->channels,
1492 ctn)) 1898 ctn | highbit))
1493 { 1899 {
1494 ctn = ((ctn + 1) & (~ HIGH_BIT)) | highbit; 1900 ctn = ((ctn + 1) & (~ HIGH_BIT));
1495 } 1901 }
1496 t->next_ctn.cn = htonl (((ctn + 1) & (~ HIGH_BIT)) | highbit); 1902 t->next_ctn.cn = htonl ((ctn + 1) & (~ HIGH_BIT));
1497 ret.cn = ntohl (ctn); 1903 ret.cn = htonl (ctn | highbit);
1498 return ret; 1904 return ret;
1499} 1905}
1500 1906
@@ -1515,23 +1921,97 @@ GCT_add_channel (struct CadetTunnel *t,
1515 struct GNUNET_CADET_ChannelTunnelNumber ctn; 1921 struct GNUNET_CADET_ChannelTunnelNumber ctn;
1516 1922
1517 ctn = get_next_free_ctn (t); 1923 ctn = get_next_free_ctn (t);
1924 if (NULL != t->destroy_task)
1925 {
1926 GNUNET_SCHEDULER_cancel (t->destroy_task);
1927 t->destroy_task = NULL;
1928 }
1518 GNUNET_assert (GNUNET_YES == 1929 GNUNET_assert (GNUNET_YES ==
1519 GNUNET_CONTAINER_multihashmap32_put (t->channels, 1930 GNUNET_CONTAINER_multihashmap32_put (t->channels,
1520 ntohl (ctn.cn), 1931 ntohl (ctn.cn),
1521 ch, 1932 ch,
1522 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); 1933 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1523 LOG (GNUNET_ERROR_TYPE_DEBUG, 1934 LOG (GNUNET_ERROR_TYPE_DEBUG,
1524 "Adding channel %s to tunnel %s\n", 1935 "Adding %s to %s\n",
1525 GCCH_2s (ch), 1936 GCCH_2s (ch),
1526 GCT_2s (t)); 1937 GCT_2s (t));
1527 if ( (CADET_TUNNEL_KEY_OK == t->estate) || 1938 switch (t->estate)
1528 (CADET_TUNNEL_KEY_REKEY == t->estate) ) 1939 {
1940 case CADET_TUNNEL_KEY_UNINITIALIZED:
1941 /* waiting for connection to start KX */
1942 break;
1943 case CADET_TUNNEL_KEY_AX_RECV:
1944 case CADET_TUNNEL_KEY_AX_SENT:
1945 case CADET_TUNNEL_KEY_AX_SENT_AND_RECV:
1946 /* we're currently waiting for KX to complete */
1947 break;
1948 case CADET_TUNNEL_KEY_AX_AUTH_SENT:
1949 /* waiting for OTHER peer to send us data,
1950 we might need to prompt more aggressively! */
1951 if (NULL == t->kx_task)
1952 t->kx_task
1953 = GNUNET_SCHEDULER_add_at (t->next_kx_attempt,
1954 &retry_kx,
1955 t);
1956 break;
1957 case CADET_TUNNEL_KEY_OK:
1958 /* We are ready. Tell the new channel that we are up. */
1529 GCCH_tunnel_up (ch); 1959 GCCH_tunnel_up (ch);
1960 break;
1961 }
1530 return ctn; 1962 return ctn;
1531} 1963}
1532 1964
1533 1965
1534/** 1966/**
1967 * We lost a connection, remove it from our list and clean up
1968 * the connection object itself.
1969 *
1970 * @param ct binding of connection to tunnel of the connection that was lost.
1971 */
1972void
1973GCT_connection_lost (struct CadetTConnection *ct)
1974{
1975 struct CadetTunnel *t = ct->t;
1976
1977 if (GNUNET_YES == ct->is_ready)
1978 {
1979 GNUNET_CONTAINER_DLL_remove (t->connection_ready_head,
1980 t->connection_ready_tail,
1981 ct);
1982 t->num_ready_connections--;
1983 }
1984 else
1985 {
1986 GNUNET_CONTAINER_DLL_remove (t->connection_busy_head,
1987 t->connection_busy_tail,
1988 ct);
1989 t->num_busy_connections--;
1990 }
1991 GNUNET_free (ct);
1992}
1993
1994
1995/**
1996 * Clean up connection @a ct of a tunnel.
1997 *
1998 * @param cls the `struct CadetTunnel`
1999 * @param ct connection to clean up
2000 */
2001static void
2002destroy_t_connection (void *cls,
2003 struct CadetTConnection *ct)
2004{
2005 struct CadetTunnel *t = cls;
2006 struct CadetConnection *cc = ct->cc;
2007
2008 GNUNET_assert (ct->t == t);
2009 GCT_connection_lost (ct);
2010 GCC_destroy_without_tunnel (cc);
2011}
2012
2013
2014/**
1535 * This tunnel is no longer used, destroy it. 2015 * This tunnel is no longer used, destroy it.
1536 * 2016 *
1537 * @param cls the idle tunnel 2017 * @param cls the idle tunnel
@@ -1540,27 +2020,23 @@ static void
1540destroy_tunnel (void *cls) 2020destroy_tunnel (void *cls)
1541{ 2021{
1542 struct CadetTunnel *t = cls; 2022 struct CadetTunnel *t = cls;
1543 struct CadetTConnection *ct;
1544 struct CadetTunnelQueueEntry *tq; 2023 struct CadetTunnelQueueEntry *tq;
1545 2024
1546 t->destroy_task = NULL; 2025 t->destroy_task = NULL;
1547 LOG (GNUNET_ERROR_TYPE_DEBUG, 2026 LOG (GNUNET_ERROR_TYPE_DEBUG,
1548 "Destroying idle tunnel %s\n", 2027 "Destroying idle %s\n",
1549 GCT_2s (t)); 2028 GCT_2s (t));
1550 GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap32_size (t->channels)); 2029 GNUNET_assert (0 == GCT_count_channels (t));
1551 while (NULL != (ct = t->connection_head)) 2030 GCT_iterate_connections (t,
1552 { 2031 &destroy_t_connection,
1553 GNUNET_assert (ct->t == t); 2032 t);
1554 GNUNET_CONTAINER_DLL_remove (t->connection_head, 2033 GNUNET_assert (NULL == t->connection_ready_head);
1555 t->connection_tail, 2034 GNUNET_assert (NULL == t->connection_busy_head);
1556 ct);
1557 GCC_destroy (ct->cc);
1558 GNUNET_free (ct);
1559 }
1560 while (NULL != (tq = t->tq_head)) 2035 while (NULL != (tq = t->tq_head))
1561 { 2036 {
1562 if (NULL != tq->cont) 2037 if (NULL != tq->cont)
1563 tq->cont (tq->cont_cls); 2038 tq->cont (tq->cont_cls,
2039 NULL);
1564 GCT_send_cancel (tq); 2040 GCT_send_cancel (tq);
1565 } 2041 }
1566 GCP_drop_tunnel (t->destination, 2042 GCP_drop_tunnel (t->destination,
@@ -1583,12 +2059,13 @@ destroy_tunnel (void *cls)
1583 } 2059 }
1584 GNUNET_MST_destroy (t->mst); 2060 GNUNET_MST_destroy (t->mst);
1585 GNUNET_MQ_destroy (t->mq); 2061 GNUNET_MQ_destroy (t->mq);
1586 while (NULL != t->ax.skipped_head) 2062 if (NULL != t->unverified_ax)
1587 delete_skipped_key (t, 2063 {
1588 t->ax.skipped_head); 2064 cleanup_ax (t->unverified_ax);
1589 GNUNET_assert (0 == t->ax.skipped); 2065 GNUNET_free (t->unverified_ax);
1590 GNUNET_free_non_null (t->ax.kx_0); 2066 }
1591 GNUNET_free_non_null (t->ax.DHRs); 2067 cleanup_ax (&t->ax);
2068 GNUNET_assert (NULL == t->destroy_task);
1592 GNUNET_free (t); 2069 GNUNET_free (t);
1593} 2070}
1594 2071
@@ -1606,19 +2083,21 @@ GCT_remove_channel (struct CadetTunnel *t,
1606 struct GNUNET_CADET_ChannelTunnelNumber ctn) 2083 struct GNUNET_CADET_ChannelTunnelNumber ctn)
1607{ 2084{
1608 LOG (GNUNET_ERROR_TYPE_DEBUG, 2085 LOG (GNUNET_ERROR_TYPE_DEBUG,
1609 "Removing channel %s from tunnel %s\n", 2086 "Removing %s from %s\n",
1610 GCCH_2s (ch), 2087 GCCH_2s (ch),
1611 GCT_2s (t)); 2088 GCT_2s (t));
1612 GNUNET_assert (GNUNET_YES == 2089 GNUNET_assert (GNUNET_YES ==
1613 GNUNET_CONTAINER_multihashmap32_remove (t->channels, 2090 GNUNET_CONTAINER_multihashmap32_remove (t->channels,
1614 ntohl (ctn.cn), 2091 ntohl (ctn.cn),
1615 ch)); 2092 ch));
1616 if (0 == 2093 if ( (0 ==
1617 GNUNET_CONTAINER_multihashmap32_size (t->channels)) 2094 GCT_count_channels (t)) &&
2095 (NULL == t->destroy_task) )
1618 { 2096 {
1619 t->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_DESTROY_DELAY, 2097 t->destroy_task
1620 &destroy_tunnel, 2098 = GNUNET_SCHEDULER_add_delayed (IDLE_DESTROY_DELAY,
1621 t); 2099 &destroy_tunnel,
2100 t);
1622 } 2101 }
1623} 2102}
1624 2103
@@ -1638,7 +2117,8 @@ destroy_remaining_channels (void *cls,
1638{ 2117{
1639 struct CadetChannel *ch = value; 2118 struct CadetChannel *ch = value;
1640 2119
1641 GCCH_handle_remote_destroy (ch); 2120 GCCH_handle_remote_destroy (ch,
2121 NULL);
1642 return GNUNET_OK; 2122 return GNUNET_OK;
1643} 2123}
1644 2124
@@ -1656,7 +2136,7 @@ GCT_destroy_tunnel_now (struct CadetTunnel *t)
1656 &destroy_remaining_channels, 2136 &destroy_remaining_channels,
1657 t); 2137 t);
1658 GNUNET_assert (0 == 2138 GNUNET_assert (0 ==
1659 GNUNET_CONTAINER_multihashmap32_size (t->channels)); 2139 GCT_count_channels (t));
1660 if (NULL != t->destroy_task) 2140 if (NULL != t->destroy_task)
1661 { 2141 {
1662 GNUNET_SCHEDULER_cancel (t->destroy_task); 2142 GNUNET_SCHEDULER_cancel (t->destroy_task);
@@ -1667,25 +2147,6 @@ GCT_destroy_tunnel_now (struct CadetTunnel *t)
1667 2147
1668 2148
1669/** 2149/**
1670 * It's been a while, we should try to redo the KX, if we can.
1671 *
1672 * @param cls the `struct CadetTunnel` to do KX for.
1673 */
1674static void
1675retry_kx (void *cls)
1676{
1677 struct CadetTunnel *t = cls;
1678
1679 t->kx_task = NULL;
1680 send_kx (t,
1681 ( (CADET_TUNNEL_KEY_UNINITIALIZED == t->estate) ||
1682 (CADET_TUNNEL_KEY_SENT == t->estate) )
1683 ? GNUNET_YES
1684 : GNUNET_NO);
1685}
1686
1687
1688/**
1689 * Send normal payload from queue in @a t via connection @a ct. 2150 * Send normal payload from queue in @a t via connection @a ct.
1690 * Does nothing if our payload queue is empty. 2151 * Does nothing if our payload queue is empty.
1691 * 2152 *
@@ -1716,7 +2177,7 @@ try_send_normal_payload (struct CadetTunnel *t,
1716 tq); 2177 tq);
1717 if (NULL != tq->cid) 2178 if (NULL != tq->cid)
1718 *tq->cid = *GCC_get_id (ct->cc); 2179 *tq->cid = *GCC_get_id (ct->cc);
1719 ct->is_ready = GNUNET_NO; 2180 mark_connection_unready (ct);
1720 LOG (GNUNET_ERROR_TYPE_DEBUG, 2181 LOG (GNUNET_ERROR_TYPE_DEBUG,
1721 "Sending payload of %s on %s\n", 2182 "Sending payload of %s on %s\n",
1722 GCT_2s (t), 2183 GCT_2s (t),
@@ -1724,7 +2185,8 @@ try_send_normal_payload (struct CadetTunnel *t,
1724 GCC_transmit (ct->cc, 2185 GCC_transmit (ct->cc,
1725 tq->env); 2186 tq->env);
1726 if (NULL != tq->cont) 2187 if (NULL != tq->cont)
1727 tq->cont (tq->cont_cls); 2188 tq->cont (tq->cont_cls,
2189 GCC_get_id (ct->cc));
1728 GNUNET_free (tq); 2190 GNUNET_free (tq);
1729} 2191}
1730 2192
@@ -1747,44 +2209,74 @@ connection_ready_cb (void *cls,
1747 if (GNUNET_NO == is_ready) 2209 if (GNUNET_NO == is_ready)
1748 { 2210 {
1749 LOG (GNUNET_ERROR_TYPE_DEBUG, 2211 LOG (GNUNET_ERROR_TYPE_DEBUG,
1750 "Connection %s no longer ready for tunnel %s\n", 2212 "%s no longer ready for %s\n",
1751 GCC_2s (ct->cc), 2213 GCC_2s (ct->cc),
1752 GCT_2s (t)); 2214 GCT_2s (t));
1753 ct->is_ready = GNUNET_NO; 2215 mark_connection_unready (ct);
1754 return; 2216 return;
1755 } 2217 }
2218 GNUNET_assert (GNUNET_NO == ct->is_ready);
2219 GNUNET_CONTAINER_DLL_remove (t->connection_busy_head,
2220 t->connection_busy_tail,
2221 ct);
2222 GNUNET_assert (0 < t->num_busy_connections);
2223 t->num_busy_connections--;
1756 ct->is_ready = GNUNET_YES; 2224 ct->is_ready = GNUNET_YES;
2225 GNUNET_CONTAINER_DLL_insert_tail (t->connection_ready_head,
2226 t->connection_ready_tail,
2227 ct);
2228 t->num_ready_connections++;
2229
1757 LOG (GNUNET_ERROR_TYPE_DEBUG, 2230 LOG (GNUNET_ERROR_TYPE_DEBUG,
1758 "Connection %s now ready for tunnel %s in state %s\n", 2231 "%s now ready for %s in state %s\n",
1759 GCC_2s (ct->cc), 2232 GCC_2s (ct->cc),
1760 GCT_2s (t), 2233 GCT_2s (t),
1761 estate2s (t->estate)); 2234 estate2s (t->estate));
1762 switch (t->estate) 2235 switch (t->estate)
1763 { 2236 {
1764 case CADET_TUNNEL_KEY_UNINITIALIZED: 2237 case CADET_TUNNEL_KEY_UNINITIALIZED:
2238 /* Do not begin KX if WE have no channels waiting! */
2239 if (0 == GCT_count_channels (t))
2240 return;
2241 /* We are uninitialized, just transmit immediately,
2242 without undue delay. */
2243 if (NULL != t->kx_task)
2244 {
2245 GNUNET_SCHEDULER_cancel (t->kx_task);
2246 t->kx_task = NULL;
2247 }
1765 send_kx (t, 2248 send_kx (t,
1766 GNUNET_YES); 2249 ct,
2250 &t->ax);
1767 break; 2251 break;
1768 case CADET_TUNNEL_KEY_SENT: 2252 case CADET_TUNNEL_KEY_AX_RECV:
1769 case CADET_TUNNEL_KEY_PING: 2253 case CADET_TUNNEL_KEY_AX_SENT:
1770 /* opportunity to #retry_kx() starts now, schedule job */ 2254 case CADET_TUNNEL_KEY_AX_SENT_AND_RECV:
2255 case CADET_TUNNEL_KEY_AX_AUTH_SENT:
2256 /* we're currently waiting for KX to complete, schedule job */
1771 if (NULL == t->kx_task) 2257 if (NULL == t->kx_task)
1772 {
1773 t->kx_task 2258 t->kx_task
1774 = GNUNET_SCHEDULER_add_at (t->next_kx_attempt, 2259 = GNUNET_SCHEDULER_add_at (t->next_kx_attempt,
1775 &retry_kx, 2260 &retry_kx,
1776 t); 2261 t);
1777 }
1778 break; 2262 break;
1779 case CADET_TUNNEL_KEY_OK: 2263 case CADET_TUNNEL_KEY_OK:
2264 if (GNUNET_YES == t->kx_auth_requested)
2265 {
2266 if (NULL != t->kx_task)
2267 {
2268 GNUNET_SCHEDULER_cancel (t->kx_task);
2269 t->kx_task = NULL;
2270 }
2271 send_kx_auth (t,
2272 ct,
2273 &t->ax,
2274 GNUNET_NO);
2275 return;
2276 }
1780 try_send_normal_payload (t, 2277 try_send_normal_payload (t,
1781 ct); 2278 ct);
1782 break; 2279 break;
1783 case CADET_TUNNEL_KEY_REKEY:
1784 send_kx (t,
1785 GNUNET_NO);
1786 t->estate = CADET_TUNNEL_KEY_OK;
1787 break;
1788 } 2280 }
1789} 2281}
1790 2282
@@ -1815,6 +2307,118 @@ trigger_transmissions (void *cls)
1815 2307
1816 2308
1817/** 2309/**
2310 * Closure for #evaluate_connection. Used to assemble summary information
2311 * about the existing connections so we can evaluate a new path.
2312 */
2313struct EvaluationSummary
2314{
2315
2316 /**
2317 * Minimum length of any of our connections, `UINT_MAX` if we have none.
2318 */
2319 unsigned int min_length;
2320
2321 /**
2322 * Maximum length of any of our connections, 0 if we have none.
2323 */
2324 unsigned int max_length;
2325
2326 /**
2327 * Minimum desirability of any of our connections, UINT64_MAX if we have none.
2328 */
2329 GNUNET_CONTAINER_HeapCostType min_desire;
2330
2331 /**
2332 * Maximum desirability of any of our connections, 0 if we have none.
2333 */
2334 GNUNET_CONTAINER_HeapCostType max_desire;
2335
2336 /**
2337 * Path we are comparing against for #evaluate_connection, can be NULL.
2338 */
2339 struct CadetPeerPath *path;
2340
2341 /**
2342 * Connection deemed the "worst" so far encountered by #evaluate_connection,
2343 * NULL if we did not yet encounter any connections.
2344 */
2345 struct CadetTConnection *worst;
2346
2347 /**
2348 * Numeric score of @e worst, only set if @e worst is non-NULL.
2349 */
2350 double worst_score;
2351
2352 /**
2353 * Set to #GNUNET_YES if we have a connection over @e path already.
2354 */
2355 int duplicate;
2356
2357};
2358
2359
2360/**
2361 * Evaluate a connection, updating our summary information in @a cls about
2362 * what kinds of connections we have.
2363 *
2364 * @param cls the `struct EvaluationSummary *` to update
2365 * @param ct a connection to include in the summary
2366 */
2367static void
2368evaluate_connection (void *cls,
2369 struct CadetTConnection *ct)
2370{
2371 struct EvaluationSummary *es = cls;
2372 struct CadetConnection *cc = ct->cc;
2373 struct CadetPeerPath *ps = GCC_get_path (cc);
2374 const struct CadetConnectionMetrics *metrics;
2375 GNUNET_CONTAINER_HeapCostType ct_desirability;
2376 struct GNUNET_TIME_Relative uptime;
2377 struct GNUNET_TIME_Relative last_use;
2378 uint32_t ct_length;
2379 double score;
2380 double success_rate;
2381
2382 if (ps == es->path)
2383 {
2384 LOG (GNUNET_ERROR_TYPE_DEBUG,
2385 "Ignoring duplicate path %s.\n",
2386 GCPP_2s (es->path));
2387 es->duplicate = GNUNET_YES;
2388 return;
2389 }
2390 ct_desirability = GCPP_get_desirability (ps);
2391 ct_length = GCPP_get_length (ps);
2392 metrics = GCC_get_metrics (cc);
2393 uptime = GNUNET_TIME_absolute_get_duration (metrics->age);
2394 last_use = GNUNET_TIME_absolute_get_duration (metrics->last_use);
2395 /* We add 1.0 here to avoid division by zero. */
2396 success_rate = (metrics->num_acked_transmissions + 1.0) / (metrics->num_successes + 1.0);
2397 score
2398 = ct_desirability
2399 + 100.0 / (1.0 + ct_length) /* longer paths = better */
2400 + sqrt (uptime.rel_value_us / 60000000LL) /* larger uptime = better */
2401 - last_use.rel_value_us / 1000L; /* longer idle = worse */
2402 score *= success_rate; /* weigh overall by success rate */
2403
2404 if ( (NULL == es->worst) ||
2405 (score < es->worst_score) )
2406 {
2407 es->worst = ct;
2408 es->worst_score = score;
2409 }
2410 es->min_length = GNUNET_MIN (es->min_length,
2411 ct_length);
2412 es->max_length = GNUNET_MAX (es->max_length,
2413 ct_length);
2414 es->min_desire = GNUNET_MIN (es->min_desire,
2415 ct_desirability);
2416 es->max_desire = GNUNET_MAX (es->max_desire,
2417 ct_desirability);
2418}
2419
2420
2421/**
1818 * Consider using the path @a p for the tunnel @a t. 2422 * Consider using the path @a p for the tunnel @a t.
1819 * The tunnel destination is at offset @a off in path @a p. 2423 * The tunnel destination is at offset @a off in path @a p.
1820 * 2424 *
@@ -1829,31 +2433,24 @@ consider_path_cb (void *cls,
1829 unsigned int off) 2433 unsigned int off)
1830{ 2434{
1831 struct CadetTunnel *t = cls; 2435 struct CadetTunnel *t = cls;
1832 unsigned int min_length = UINT_MAX; 2436 struct EvaluationSummary es;
1833 GNUNET_CONTAINER_HeapCostType max_desire = 0;
1834 struct CadetTConnection *ct; 2437 struct CadetTConnection *ct;
1835 2438
1836 /* Check if we care about the new path. */ 2439 GNUNET_assert (off < GCPP_get_length (path));
1837 for (ct = t->connection_head; 2440 es.min_length = UINT_MAX;
1838 NULL != ct; 2441 es.max_length = 0;
1839 ct = ct->next) 2442 es.max_desire = 0;
1840 { 2443 es.min_desire = UINT64_MAX;
1841 struct CadetPeerPath *ps; 2444 es.path = path;
1842 2445 es.duplicate = GNUNET_NO;
1843 ps = GCC_get_path (ct->cc); 2446 es.worst = NULL;
1844 if (ps == path) 2447
1845 { 2448 /* Compute evaluation summary over existing connections. */
1846 LOG (GNUNET_ERROR_TYPE_DEBUG, 2449 GCT_iterate_connections (t,
1847 "Ignoring duplicate path %s for tunnel %s.\n", 2450 &evaluate_connection,
1848 GCPP_2s (path), 2451 &es);
1849 GCT_2s (t)); 2452 if (GNUNET_YES == es.duplicate)
1850 return GNUNET_YES; /* duplicate */ 2453 return GNUNET_YES;
1851 }
1852 min_length = GNUNET_MIN (min_length,
1853 GCPP_get_length (ps));
1854 max_desire = GNUNET_MAX (max_desire,
1855 GCPP_get_desirability (ps));
1856 }
1857 2454
1858 /* FIXME: not sure we should really just count 2455 /* FIXME: not sure we should really just count
1859 'num_connections' here, as they may all have 2456 'num_connections' here, as they may all have
@@ -1862,18 +2459,20 @@ consider_path_cb (void *cls,
1862 /* We iterate by increasing path length; if we have enough paths and 2459 /* We iterate by increasing path length; if we have enough paths and
1863 this one is more than twice as long than what we are currently 2460 this one is more than twice as long than what we are currently
1864 using, then ignore all of these super-long ones! */ 2461 using, then ignore all of these super-long ones! */
1865 if ( (t->num_connections > DESIRED_CONNECTIONS_PER_TUNNEL) && 2462 if ( (GCT_count_any_connections (t) > DESIRED_CONNECTIONS_PER_TUNNEL) &&
1866 (min_length * 2 < off) ) 2463 (es.min_length * 2 < off) &&
2464 (es.max_length < off) )
1867 { 2465 {
1868 LOG (GNUNET_ERROR_TYPE_DEBUG, 2466 LOG (GNUNET_ERROR_TYPE_DEBUG,
1869 "Ignoring paths of length %u, they are way too long.\n", 2467 "Ignoring paths of length %u, they are way too long.\n",
1870 min_length * 2); 2468 es.min_length * 2);
1871 return GNUNET_NO; 2469 return GNUNET_NO;
1872 } 2470 }
1873 /* If we have enough paths and this one looks no better, ignore it. */ 2471 /* If we have enough paths and this one looks no better, ignore it. */
1874 if ( (t->num_connections >= DESIRED_CONNECTIONS_PER_TUNNEL) && 2472 if ( (GCT_count_any_connections (t) >= DESIRED_CONNECTIONS_PER_TUNNEL) &&
1875 (min_length < GCPP_get_length (path)) && 2473 (es.min_length < GCPP_get_length (path)) &&
1876 (max_desire > GCPP_get_desirability (path)) ) 2474 (es.min_desire > GCPP_get_desirability (path)) &&
2475 (es.max_length < off) )
1877 { 2476 {
1878 LOG (GNUNET_ERROR_TYPE_DEBUG, 2477 LOG (GNUNET_ERROR_TYPE_DEBUG,
1879 "Ignoring path (%u/%llu) to %s, got something better already.\n", 2478 "Ignoring path (%u/%llu) to %s, got something better already.\n",
@@ -1890,19 +2489,22 @@ consider_path_cb (void *cls,
1890 ct->t = t; 2489 ct->t = t;
1891 ct->cc = GCC_create (t->destination, 2490 ct->cc = GCC_create (t->destination,
1892 path, 2491 path,
2492 off,
2493 GNUNET_CADET_OPTION_DEFAULT, /* FIXME: set based on what channels want/need! */
1893 ct, 2494 ct,
1894 &connection_ready_cb, 2495 &connection_ready_cb,
1895 ct); 2496 ct);
2497
1896 /* FIXME: schedule job to kill connection (and path?) if it takes 2498 /* FIXME: schedule job to kill connection (and path?) if it takes
1897 too long to get ready! (And track performance data on how long 2499 too long to get ready! (And track performance data on how long
1898 other connections took with the tunnel!) 2500 other connections took with the tunnel!)
1899 => Note: to be done within 'connection'-logic! */ 2501 => Note: to be done within 'connection'-logic! */
1900 GNUNET_CONTAINER_DLL_insert (t->connection_head, 2502 GNUNET_CONTAINER_DLL_insert (t->connection_busy_head,
1901 t->connection_tail, 2503 t->connection_busy_tail,
1902 ct); 2504 ct);
1903 t->num_connections++; 2505 t->num_busy_connections++;
1904 LOG (GNUNET_ERROR_TYPE_DEBUG, 2506 LOG (GNUNET_ERROR_TYPE_DEBUG,
1905 "Found interesting path %s for tunnel %s, created connection %s\n", 2507 "Found interesting path %s for %s, created %s\n",
1906 GCPP_2s (path), 2508 GCPP_2s (path),
1907 GCT_2s (t), 2509 GCT_2s (t),
1908 GCC_2s (ct->cc)); 2510 GCC_2s (ct->cc));
@@ -1927,17 +2529,50 @@ static void
1927maintain_connections_cb (void *cls) 2529maintain_connections_cb (void *cls)
1928{ 2530{
1929 struct CadetTunnel *t = cls; 2531 struct CadetTunnel *t = cls;
2532 struct GNUNET_TIME_Relative delay;
2533 struct EvaluationSummary es;
1930 2534
1931 t->maintain_connections_task = NULL; 2535 t->maintain_connections_task = NULL;
1932 LOG (GNUNET_ERROR_TYPE_DEBUG, 2536 LOG (GNUNET_ERROR_TYPE_DEBUG,
1933 "Performing connection maintenance for tunnel %s.\n", 2537 "Performing connection maintenance for %s.\n",
1934 GCT_2s (t)); 2538 GCT_2s (t));
1935 2539
2540 es.min_length = UINT_MAX;
2541 es.max_length = 0;
2542 es.max_desire = 0;
2543 es.min_desire = UINT64_MAX;
2544 es.path = NULL;
2545 es.worst = NULL;
2546 es.duplicate = GNUNET_NO;
2547 GCT_iterate_connections (t,
2548 &evaluate_connection,
2549 &es);
2550 if ( (NULL != es.worst) &&
2551 (GCT_count_any_connections (t) > DESIRED_CONNECTIONS_PER_TUNNEL) )
2552 {
2553 /* Clear out worst-performing connection 'es.worst'. */
2554 destroy_t_connection (t,
2555 es.worst);
2556 }
2557
2558 /* Consider additional paths */
1936 (void) GCP_iterate_paths (t->destination, 2559 (void) GCP_iterate_paths (t->destination,
1937 &consider_path_cb, 2560 &consider_path_cb,
1938 t); 2561 t);
1939 2562
1940 GNUNET_break (0); // FIXME: implement! 2563 /* FIXME: calculate when to try again based on how well we are doing;
2564 in particular, if we have to few connections, we might be able
2565 to do without this (as PATHS should tell us whenever a new path
2566 is available instantly; however, need to make sure this job is
2567 restarted after that happens).
2568 Furthermore, if the paths we do know are in a reasonably narrow
2569 quality band and are plentyful, we might also consider us stabilized
2570 and then reduce the frequency accordingly. */
2571 delay = GNUNET_TIME_UNIT_MINUTES;
2572 t->maintain_connections_task
2573 = GNUNET_SCHEDULER_add_delayed (delay,
2574 &maintain_connections_cb,
2575 t);
1941} 2576}
1942 2577
1943 2578
@@ -1954,6 +2589,10 @@ GCT_consider_path (struct CadetTunnel *t,
1954 struct CadetPeerPath *p, 2589 struct CadetPeerPath *p,
1955 unsigned int off) 2590 unsigned int off)
1956{ 2591{
2592 LOG (GNUNET_ERROR_TYPE_DEBUG,
2593 "Considering %s for %s\n",
2594 GCPP_2s (p),
2595 GCT_2s (t));
1957 (void) consider_path_cb (t, 2596 (void) consider_path_cb (t,
1958 p, 2597 p,
1959 off); 2598 off);
@@ -1961,7 +2600,7 @@ GCT_consider_path (struct CadetTunnel *t,
1961 2600
1962 2601
1963/** 2602/**
1964 * NOT IMPLEMENTED. 2603 * We got a keepalive. Track in statistics.
1965 * 2604 *
1966 * @param cls the `struct CadetTunnel` for which we decrypted the message 2605 * @param cls the `struct CadetTunnel` for which we decrypted the message
1967 * @param msg the message we received on the tunnel 2606 * @param msg the message we received on the tunnel
@@ -1972,7 +2611,13 @@ handle_plaintext_keepalive (void *cls,
1972{ 2611{
1973 struct CadetTunnel *t = cls; 2612 struct CadetTunnel *t = cls;
1974 2613
1975 GNUNET_break (0); // FIXME 2614 LOG (GNUNET_ERROR_TYPE_DEBUG,
2615 "Received KEEPALIVE on %s\n",
2616 GCT_2s (t));
2617 GNUNET_STATISTICS_update (stats,
2618 "# keepalives received",
2619 1,
2620 GNUNET_NO);
1976} 2621}
1977 2622
1978 2623
@@ -2012,7 +2657,7 @@ handle_plaintext_data (void *cls,
2012 /* We don't know about such a channel, might have been destroyed on our 2657 /* We don't know about such a channel, might have been destroyed on our
2013 end in the meantime, or never existed. Send back a DESTROY. */ 2658 end in the meantime, or never existed. Send back a DESTROY. */
2014 LOG (GNUNET_ERROR_TYPE_DEBUG, 2659 LOG (GNUNET_ERROR_TYPE_DEBUG,
2015 "Receicved %u bytes of application data for unknown channel %u, sending DESTROY\n", 2660 "Received %u bytes of application data for unknown channel %u, sending DESTROY\n",
2016 (unsigned int) (ntohs (msg->header.size) - sizeof (*msg)), 2661 (unsigned int) (ntohs (msg->header.size) - sizeof (*msg)),
2017 ntohl (msg->ctn.cn)); 2662 ntohl (msg->ctn.cn));
2018 GCT_send_channel_destroy (t, 2663 GCT_send_channel_destroy (t,
@@ -2020,6 +2665,7 @@ handle_plaintext_data (void *cls,
2020 return; 2665 return;
2021 } 2666 }
2022 GCCH_handle_channel_plaintext_data (ch, 2667 GCCH_handle_channel_plaintext_data (ch,
2668 GCC_get_id (t->current_ct->cc),
2023 msg); 2669 msg);
2024} 2670}
2025 2671
@@ -2046,13 +2692,14 @@ handle_plaintext_data_ack (void *cls,
2046 /* We don't know about such a channel, might have been destroyed on our 2692 /* We don't know about such a channel, might have been destroyed on our
2047 end in the meantime, or never existed. Send back a DESTROY. */ 2693 end in the meantime, or never existed. Send back a DESTROY. */
2048 LOG (GNUNET_ERROR_TYPE_DEBUG, 2694 LOG (GNUNET_ERROR_TYPE_DEBUG,
2049 "Receicved DATA_ACK for unknown channel %u, sending DESTROY\n", 2695 "Received DATA_ACK for unknown channel %u, sending DESTROY\n",
2050 ntohl (ack->ctn.cn)); 2696 ntohl (ack->ctn.cn));
2051 GCT_send_channel_destroy (t, 2697 GCT_send_channel_destroy (t,
2052 ack->ctn); 2698 ack->ctn);
2053 return; 2699 return;
2054 } 2700 }
2055 GCCH_handle_channel_plaintext_data_ack (ch, 2701 GCCH_handle_channel_plaintext_data_ack (ch,
2702 GCC_get_id (t->current_ct->cc),
2056 ack); 2703 ack);
2057} 2704}
2058 2705
@@ -2076,21 +2723,27 @@ handle_plaintext_channel_open (void *cls,
2076 if (NULL != ch) 2723 if (NULL != ch)
2077 { 2724 {
2078 LOG (GNUNET_ERROR_TYPE_DEBUG, 2725 LOG (GNUNET_ERROR_TYPE_DEBUG,
2079 "Receicved duplicate channel OPEN on port %s from %s (%s), resending ACK\n", 2726 "Received duplicate channel CHANNEL_OPEN on h_port %s from %s (%s), resending ACK\n",
2080 GNUNET_h2s (&copen->port), 2727 GNUNET_h2s (&copen->h_port),
2081 GCT_2s (t), 2728 GCT_2s (t),
2082 GCCH_2s (ch)); 2729 GCCH_2s (ch));
2083 GCCH_handle_duplicate_open (ch); 2730 GCCH_handle_duplicate_open (ch,
2731 GCC_get_id (t->current_ct->cc));
2084 return; 2732 return;
2085 } 2733 }
2086 LOG (GNUNET_ERROR_TYPE_DEBUG, 2734 LOG (GNUNET_ERROR_TYPE_DEBUG,
2087 "Receicved channel OPEN on port %s from %s\n", 2735 "Received CHANNEL_OPEN on h_port %s from %s\n",
2088 GNUNET_h2s (&copen->port), 2736 GNUNET_h2s (&copen->h_port),
2089 GCT_2s (t)); 2737 GCT_2s (t));
2090 ch = GCCH_channel_incoming_new (t, 2738 ch = GCCH_channel_incoming_new (t,
2091 copen->ctn, 2739 copen->ctn,
2092 &copen->port, 2740 &copen->h_port,
2093 ntohl (copen->opt)); 2741 ntohl (copen->opt));
2742 if (NULL != t->destroy_task)
2743 {
2744 GNUNET_SCHEDULER_cancel (t->destroy_task);
2745 t->destroy_task = NULL;
2746 }
2094 GNUNET_assert (GNUNET_OK == 2747 GNUNET_assert (GNUNET_OK ==
2095 GNUNET_CONTAINER_multihashmap32_put (t->channels, 2748 GNUNET_CONTAINER_multihashmap32_put (t->channels,
2096 ntohl (copen->ctn.cn), 2749 ntohl (copen->ctn.cn),
@@ -2109,7 +2762,7 @@ void
2109GCT_send_channel_destroy (struct CadetTunnel *t, 2762GCT_send_channel_destroy (struct CadetTunnel *t,
2110 struct GNUNET_CADET_ChannelTunnelNumber ctn) 2763 struct GNUNET_CADET_ChannelTunnelNumber ctn)
2111{ 2764{
2112 struct GNUNET_CADET_ChannelManageMessage msg; 2765 struct GNUNET_CADET_ChannelDestroyMessage msg;
2113 2766
2114 LOG (GNUNET_ERROR_TYPE_DEBUG, 2767 LOG (GNUNET_ERROR_TYPE_DEBUG,
2115 "Sending DESTORY message for channel ID %u\n", 2768 "Sending DESTORY message for channel ID %u\n",
@@ -2135,7 +2788,7 @@ GCT_send_channel_destroy (struct CadetTunnel *t,
2135 */ 2788 */
2136static void 2789static void
2137handle_plaintext_channel_open_ack (void *cls, 2790handle_plaintext_channel_open_ack (void *cls,
2138 const struct GNUNET_CADET_ChannelManageMessage *cm) 2791 const struct GNUNET_CADET_ChannelOpenAckMessage *cm)
2139{ 2792{
2140 struct CadetTunnel *t = cls; 2793 struct CadetTunnel *t = cls;
2141 struct CadetChannel *ch; 2794 struct CadetChannel *ch;
@@ -2157,7 +2810,9 @@ handle_plaintext_channel_open_ack (void *cls,
2157 "Received channel OPEN_ACK on channel %s from %s\n", 2810 "Received channel OPEN_ACK on channel %s from %s\n",
2158 GCCH_2s (ch), 2811 GCCH_2s (ch),
2159 GCT_2s (t)); 2812 GCT_2s (t));
2160 GCCH_handle_channel_open_ack (ch); 2813 GCCH_handle_channel_open_ack (ch,
2814 GCC_get_id (t->current_ct->cc),
2815 &cm->port);
2161} 2816}
2162 2817
2163 2818
@@ -2170,7 +2825,7 @@ handle_plaintext_channel_open_ack (void *cls,
2170 */ 2825 */
2171static void 2826static void
2172handle_plaintext_channel_destroy (void *cls, 2827handle_plaintext_channel_destroy (void *cls,
2173 const struct GNUNET_CADET_ChannelManageMessage *cm) 2828 const struct GNUNET_CADET_ChannelDestroyMessage *cm)
2174{ 2829{
2175 struct CadetTunnel *t = cls; 2830 struct CadetTunnel *t = cls;
2176 struct CadetChannel *ch; 2831 struct CadetChannel *ch;
@@ -2187,10 +2842,11 @@ handle_plaintext_channel_destroy (void *cls,
2187 return; 2842 return;
2188 } 2843 }
2189 LOG (GNUNET_ERROR_TYPE_DEBUG, 2844 LOG (GNUNET_ERROR_TYPE_DEBUG,
2190 "Receicved channel DESTROY on %s from %s\n", 2845 "Received channel DESTROY on %s from %s\n",
2191 GCCH_2s (ch), 2846 GCCH_2s (ch),
2192 GCT_2s (t)); 2847 GCT_2s (t));
2193 GCCH_handle_remote_destroy (ch); 2848 GCCH_handle_remote_destroy (ch,
2849 GCC_get_id (t->current_ct->cc));
2194} 2850}
2195 2851
2196 2852
@@ -2208,6 +2864,7 @@ handle_decrypted (void *cls,
2208{ 2864{
2209 struct CadetTunnel *t = cls; 2865 struct CadetTunnel *t = cls;
2210 2866
2867 GNUNET_assert (NULL != t->current_ct);
2211 GNUNET_MQ_inject_message (t->mq, 2868 GNUNET_MQ_inject_message (t->mq,
2212 msg); 2869 msg);
2213 return GNUNET_OK; 2870 return GNUNET_OK;
@@ -2259,17 +2916,19 @@ GCT_create_tunnel (struct CadetPeer *destination)
2259 t), 2916 t),
2260 GNUNET_MQ_hd_fixed_size (plaintext_channel_open_ack, 2917 GNUNET_MQ_hd_fixed_size (plaintext_channel_open_ack,
2261 GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK, 2918 GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK,
2262 struct GNUNET_CADET_ChannelManageMessage, 2919 struct GNUNET_CADET_ChannelOpenAckMessage,
2263 t), 2920 t),
2264 GNUNET_MQ_hd_fixed_size (plaintext_channel_destroy, 2921 GNUNET_MQ_hd_fixed_size (plaintext_channel_destroy,
2265 GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY, 2922 GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY,
2266 struct GNUNET_CADET_ChannelManageMessage, 2923 struct GNUNET_CADET_ChannelDestroyMessage,
2267 t), 2924 t),
2268 GNUNET_MQ_handler_end () 2925 GNUNET_MQ_handler_end ()
2269 }; 2926 };
2270 2927
2271 new_ephemeral (t); 2928 t->kx_retry_delay = INITIAL_KX_RETRY_DELAY;
2272 t->ax.kx_0 = GNUNET_CRYPTO_ecdhe_key_create (); 2929 new_ephemeral (&t->ax);
2930 GNUNET_assert (GNUNET_OK ==
2931 GNUNET_CRYPTO_ecdhe_key_create2 (&t->ax.kx_0));
2273 t->destination = destination; 2932 t->destination = destination;
2274 t->channels = GNUNET_CONTAINER_multihashmap32_create (8); 2933 t->channels = GNUNET_CONTAINER_multihashmap32_create (8);
2275 t->maintain_connections_task 2934 t->maintain_connections_task
@@ -2293,11 +2952,15 @@ GCT_create_tunnel (struct CadetPeer *destination)
2293 * 2952 *
2294 * @param t a tunnel 2953 * @param t a tunnel
2295 * @param cid connection identifer to use for the connection 2954 * @param cid connection identifer to use for the connection
2955 * @param options options for the connection
2296 * @param path path to use for the connection 2956 * @param path path to use for the connection
2957 * @return #GNUNET_OK on success,
2958 * #GNUNET_SYSERR on failure (duplicate connection)
2297 */ 2959 */
2298void 2960int
2299GCT_add_inbound_connection (struct CadetTunnel *t, 2961GCT_add_inbound_connection (struct CadetTunnel *t,
2300 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid, 2962 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
2963 enum GNUNET_CADET_ChannelOption options,
2301 struct CadetPeerPath *path) 2964 struct CadetPeerPath *path)
2302{ 2965{
2303 struct CadetTConnection *ct; 2966 struct CadetTConnection *ct;
@@ -2307,22 +2970,33 @@ GCT_add_inbound_connection (struct CadetTunnel *t,
2307 ct->t = t; 2970 ct->t = t;
2308 ct->cc = GCC_create_inbound (t->destination, 2971 ct->cc = GCC_create_inbound (t->destination,
2309 path, 2972 path,
2973 options,
2310 ct, 2974 ct,
2311 cid, 2975 cid,
2312 &connection_ready_cb, 2976 &connection_ready_cb,
2313 ct); 2977 ct);
2978 if (NULL == ct->cc)
2979 {
2980 LOG (GNUNET_ERROR_TYPE_DEBUG,
2981 "%s refused inbound %s (duplicate)\n",
2982 GCT_2s (t),
2983 GCC_2s (ct->cc));
2984 GNUNET_free (ct);
2985 return GNUNET_SYSERR;
2986 }
2314 /* FIXME: schedule job to kill connection (and path?) if it takes 2987 /* FIXME: schedule job to kill connection (and path?) if it takes
2315 too long to get ready! (And track performance data on how long 2988 too long to get ready! (And track performance data on how long
2316 other connections took with the tunnel!) 2989 other connections took with the tunnel!)
2317 => Note: to be done within 'connection'-logic! */ 2990 => Note: to be done within 'connection'-logic! */
2318 GNUNET_CONTAINER_DLL_insert (t->connection_head, 2991 GNUNET_CONTAINER_DLL_insert (t->connection_busy_head,
2319 t->connection_tail, 2992 t->connection_busy_tail,
2320 ct); 2993 ct);
2321 t->num_connections++; 2994 t->num_busy_connections++;
2322 LOG (GNUNET_ERROR_TYPE_DEBUG, 2995 LOG (GNUNET_ERROR_TYPE_DEBUG,
2323 "Tunnel %s has new connection %s\n", 2996 "%s has new %s\n",
2324 GCT_2s (t), 2997 GCT_2s (t),
2325 GCC_2s (ct->cc)); 2998 GCC_2s (ct->cc));
2999 return GNUNET_OK;
2326} 3000}
2327 3001
2328 3002
@@ -2342,7 +3016,7 @@ GCT_handle_encrypted (struct CadetTConnection *ct,
2342 ssize_t decrypted_size; 3016 ssize_t decrypted_size;
2343 3017
2344 LOG (GNUNET_ERROR_TYPE_DEBUG, 3018 LOG (GNUNET_ERROR_TYPE_DEBUG,
2345 "Tunnel %s received %u bytes of encrypted data in state %d\n", 3019 "%s received %u bytes of encrypted data in state %d\n",
2346 GCT_2s (t), 3020 GCT_2s (t),
2347 (unsigned int) size, 3021 (unsigned int) size,
2348 t->estate); 3022 t->estate);
@@ -2350,66 +3024,158 @@ GCT_handle_encrypted (struct CadetTConnection *ct,
2350 switch (t->estate) 3024 switch (t->estate)
2351 { 3025 {
2352 case CADET_TUNNEL_KEY_UNINITIALIZED: 3026 case CADET_TUNNEL_KEY_UNINITIALIZED:
3027 case CADET_TUNNEL_KEY_AX_RECV:
2353 /* We did not even SEND our KX, how can the other peer 3028 /* We did not even SEND our KX, how can the other peer
2354 send us encrypted data? */ 3029 send us encrypted data? Must have been that we went
2355 GNUNET_break_op (0); 3030 down and the other peer still things we are up.
3031 Let's send it KX back. */
3032 GNUNET_STATISTICS_update (stats,
3033 "# received encrypted without any KX",
3034 1,
3035 GNUNET_NO);
3036 if (NULL != t->kx_task)
3037 {
3038 GNUNET_SCHEDULER_cancel (t->kx_task);
3039 t->kx_task = NULL;
3040 }
3041 send_kx (t,
3042 ct,
3043 &t->ax);
2356 return; 3044 return;
2357 case CADET_TUNNEL_KEY_SENT: 3045 case CADET_TUNNEL_KEY_AX_SENT_AND_RECV:
3046 /* We send KX, and other peer send KX to us at the same time.
3047 Neither KX is AUTH'ed, so let's try KX_AUTH this time. */
3048 GNUNET_STATISTICS_update (stats,
3049 "# received encrypted without KX_AUTH",
3050 1,
3051 GNUNET_NO);
3052 if (NULL != t->kx_task)
3053 {
3054 GNUNET_SCHEDULER_cancel (t->kx_task);
3055 t->kx_task = NULL;
3056 }
3057 send_kx_auth (t,
3058 ct,
3059 &t->ax,
3060 GNUNET_YES);
3061 return;
3062 case CADET_TUNNEL_KEY_AX_SENT:
2358 /* We did not get the KX of the other peer, but that 3063 /* We did not get the KX of the other peer, but that
2359 might have been lost. Ask for KX again. */ 3064 might have been lost. Send our KX again immediately. */
2360 GNUNET_STATISTICS_update (stats, 3065 GNUNET_STATISTICS_update (stats,
2361 "# received encrypted without KX", 3066 "# received encrypted without KX",
2362 1, 3067 1,
2363 GNUNET_NO); 3068 GNUNET_NO);
2364 if (NULL != t->kx_task) 3069 if (NULL != t->kx_task)
3070 {
2365 GNUNET_SCHEDULER_cancel (t->kx_task); 3071 GNUNET_SCHEDULER_cancel (t->kx_task);
2366 t->kx_task = GNUNET_SCHEDULER_add_now (&retry_kx, 3072 t->kx_task = NULL;
2367 t); 3073 }
3074 send_kx (t,
3075 ct,
3076 &t->ax);
2368 return; 3077 return;
2369 case CADET_TUNNEL_KEY_PING: 3078 case CADET_TUNNEL_KEY_AX_AUTH_SENT:
2370 /* Great, first payload, we might graduate to OK */ 3079 /* Great, first payload, we might graduate to OK! */
2371 case CADET_TUNNEL_KEY_OK: 3080 case CADET_TUNNEL_KEY_OK:
2372 case CADET_TUNNEL_KEY_REKEY: 3081 /* We are up and running, all good. */
2373 break; 3082 break;
2374 } 3083 }
2375 3084
2376 GNUNET_STATISTICS_update (stats, 3085 decrypted_size = -1;
2377 "# received encrypted", 3086 if (CADET_TUNNEL_KEY_OK == t->estate)
2378 1, 3087 {
2379 GNUNET_NO); 3088 /* We have well-established key material available,
2380 decrypted_size = t_ax_decrypt_and_validate (t, 3089 try that. (This is the common case.) */
2381 cbuf, 3090 decrypted_size = t_ax_decrypt_and_validate (&t->ax,
2382 msg, 3091 cbuf,
2383 size); 3092 msg,
3093 size);
3094 }
3095
3096 if ( (-1 == decrypted_size) &&
3097 (NULL != t->unverified_ax) )
3098 {
3099 /* We have un-authenticated KX material available. We should try
3100 this as a back-up option, in case the sender crashed and
3101 switched keys. */
3102 decrypted_size = t_ax_decrypt_and_validate (t->unverified_ax,
3103 cbuf,
3104 msg,
3105 size);
3106 if (-1 != decrypted_size)
3107 {
3108 /* It worked! Treat this as authentication of the AX data! */
3109 cleanup_ax (&t->ax);
3110 t->ax = *t->unverified_ax;
3111 GNUNET_free (t->unverified_ax);
3112 t->unverified_ax = NULL;
3113 }
3114 if (CADET_TUNNEL_KEY_AX_AUTH_SENT == t->estate)
3115 {
3116 /* First time it worked, move tunnel into production! */
3117 GCT_change_estate (t,
3118 CADET_TUNNEL_KEY_OK);
3119 if (NULL != t->send_task)
3120 GNUNET_SCHEDULER_cancel (t->send_task);
3121 t->send_task = GNUNET_SCHEDULER_add_now (&trigger_transmissions,
3122 t);
3123 }
3124 }
3125 if (NULL != t->unverified_ax)
3126 {
3127 /* We had unverified KX material that was useless; so increment
3128 counter and eventually move to ignore it. Note that we even do
3129 this increment if we successfully decrypted with the old KX
3130 material and thus didn't even both with the new one. This is
3131 the ideal case, as a malicious injection of bogus KX data
3132 basically only causes us to increment a counter a few times. */
3133 t->unverified_attempts++;
3134 LOG (GNUNET_ERROR_TYPE_DEBUG,
3135 "Failed to decrypt message with unverified KX data %u times\n",
3136 t->unverified_attempts);
3137 if (t->unverified_attempts > MAX_UNVERIFIED_ATTEMPTS)
3138 {
3139 cleanup_ax (t->unverified_ax);
3140 GNUNET_free (t->unverified_ax);
3141 t->unverified_ax = NULL;
3142 }
3143 }
2384 3144
2385 if (-1 == decrypted_size) 3145 if (-1 == decrypted_size)
2386 { 3146 {
2387 GNUNET_break_op (0); 3147 /* Decryption failed for good, complain. */
2388 LOG (GNUNET_ERROR_TYPE_WARNING, 3148 LOG (GNUNET_ERROR_TYPE_WARNING,
2389 "Tunnel %s failed to decrypt and validate encrypted data\n", 3149 "%s failed to decrypt and validate encrypted data, retrying KX\n",
2390 GCT_2s (t)); 3150 GCT_2s (t));
2391 GNUNET_STATISTICS_update (stats, 3151 GNUNET_STATISTICS_update (stats,
2392 "# unable to decrypt", 3152 "# unable to decrypt",
2393 1, 3153 1,
2394 GNUNET_NO); 3154 GNUNET_NO);
3155 if (NULL != t->kx_task)
3156 {
3157 GNUNET_SCHEDULER_cancel (t->kx_task);
3158 t->kx_task = NULL;
3159 }
3160 send_kx (t,
3161 ct,
3162 &t->ax);
2395 return; 3163 return;
2396 } 3164 }
2397 if (CADET_TUNNEL_KEY_PING == t->estate) 3165 GNUNET_STATISTICS_update (stats,
2398 { 3166 "# decrypted bytes",
2399 GCT_change_estate (t, 3167 decrypted_size,
2400 CADET_TUNNEL_KEY_OK); 3168 GNUNET_NO);
2401 if (NULL != t->send_task) 3169
2402 GNUNET_SCHEDULER_cancel (t->send_task);
2403 t->send_task = GNUNET_SCHEDULER_add_now (&trigger_transmissions,
2404 t);
2405 }
2406 /* The MST will ultimately call #handle_decrypted() on each message. */ 3170 /* The MST will ultimately call #handle_decrypted() on each message. */
3171 t->current_ct = ct;
2407 GNUNET_break_op (GNUNET_OK == 3172 GNUNET_break_op (GNUNET_OK ==
2408 GNUNET_MST_from_buffer (t->mst, 3173 GNUNET_MST_from_buffer (t->mst,
2409 cbuf, 3174 cbuf,
2410 decrypted_size, 3175 decrypted_size,
2411 GNUNET_YES, 3176 GNUNET_YES,
2412 GNUNET_NO)); 3177 GNUNET_NO));
3178 t->current_ct = NULL;
2413} 3179}
2414 3180
2415 3181
@@ -2421,12 +3187,12 @@ GCT_handle_encrypted (struct CadetTConnection *ct,
2421 * @param t Tunnel on which this message is transmitted. 3187 * @param t Tunnel on which this message is transmitted.
2422 * @param cont Continuation to call once message is really sent. 3188 * @param cont Continuation to call once message is really sent.
2423 * @param cont_cls Closure for @c cont. 3189 * @param cont_cls Closure for @c cont.
2424 * @return Handle to cancel message. NULL if @c cont is NULL. 3190 * @return Handle to cancel message
2425 */ 3191 */
2426struct CadetTunnelQueueEntry * 3192struct CadetTunnelQueueEntry *
2427GCT_send (struct CadetTunnel *t, 3193GCT_send (struct CadetTunnel *t,
2428 const struct GNUNET_MessageHeader *message, 3194 const struct GNUNET_MessageHeader *message,
2429 GNUNET_SCHEDULER_TaskCallback cont, 3195 GCT_SendContinuation cont,
2430 void *cont_cls) 3196 void *cont_cls)
2431{ 3197{
2432 struct CadetTunnelQueueEntry *tq; 3198 struct CadetTunnelQueueEntry *tq;
@@ -2434,26 +3200,38 @@ GCT_send (struct CadetTunnel *t,
2434 struct GNUNET_MQ_Envelope *env; 3200 struct GNUNET_MQ_Envelope *env;
2435 struct GNUNET_CADET_TunnelEncryptedMessage *ax_msg; 3201 struct GNUNET_CADET_TunnelEncryptedMessage *ax_msg;
2436 3202
3203 if (CADET_TUNNEL_KEY_OK != t->estate)
3204 {
3205 GNUNET_break (0);
3206 return NULL;
3207 }
2437 payload_size = ntohs (message->size); 3208 payload_size = ntohs (message->size);
2438 LOG (GNUNET_ERROR_TYPE_DEBUG, 3209 LOG (GNUNET_ERROR_TYPE_DEBUG,
2439 "Encrypting %u bytes for tunnel %s\n", 3210 "Encrypting %u bytes for %s\n",
2440 (unsigned int) payload_size, 3211 (unsigned int) payload_size,
2441 GCT_2s (t)); 3212 GCT_2s (t));
2442 env = GNUNET_MQ_msg_extra (ax_msg, 3213 env = GNUNET_MQ_msg_extra (ax_msg,
2443 payload_size, 3214 payload_size,
2444 GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED); 3215 GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED);
2445 t_ax_encrypt (t, 3216 t_ax_encrypt (&t->ax,
2446 &ax_msg[1], 3217 &ax_msg[1],
2447 message, 3218 message,
2448 payload_size); 3219 payload_size);
2449 ax_msg->Ns = htonl (t->ax.Ns++); 3220 GNUNET_STATISTICS_update (stats,
2450 ax_msg->PNs = htonl (t->ax.PNs); 3221 "# encrypted bytes",
2451 GNUNET_CRYPTO_ecdhe_key_get_public (t->ax.DHRs, 3222 payload_size,
2452 &ax_msg->DHRs); 3223 GNUNET_NO);
2453 t_h_encrypt (t, 3224 ax_msg->ax_header.Ns = htonl (t->ax.Ns++);
3225 ax_msg->ax_header.PNs = htonl (t->ax.PNs);
3226 /* FIXME: we should do this once, not once per message;
3227 this is a point multiplication, and DHRs does not
3228 change all the time. */
3229 GNUNET_CRYPTO_ecdhe_key_get_public (&t->ax.DHRs,
3230 &ax_msg->ax_header.DHRs);
3231 t_h_encrypt (&t->ax,
2454 ax_msg); 3232 ax_msg);
2455 t_hmac (&ax_msg->Ns, 3233 t_hmac (&ax_msg->ax_header,
2456 AX_HEADER_SIZE + payload_size, 3234 sizeof (struct GNUNET_CADET_AxHeader) + payload_size,
2457 0, 3235 0,
2458 &t->ax.HKs, 3236 &t->ax.HKs,
2459 &ax_msg->hmac); 3237 &ax_msg->hmac);
@@ -2510,11 +3288,23 @@ GCT_iterate_connections (struct CadetTunnel *t,
2510 GCT_ConnectionIterator iter, 3288 GCT_ConnectionIterator iter,
2511 void *iter_cls) 3289 void *iter_cls)
2512{ 3290{
2513 for (struct CadetTConnection *ct = t->connection_head; 3291 struct CadetTConnection *n;
3292 for (struct CadetTConnection *ct = t->connection_ready_head;
2514 NULL != ct; 3293 NULL != ct;
2515 ct = ct->next) 3294 ct = n)
3295 {
3296 n = ct->next;
3297 iter (iter_cls,
3298 ct);
3299 }
3300 for (struct CadetTConnection *ct = t->connection_busy_head;
3301 NULL != ct;
3302 ct = n)
3303 {
3304 n = ct->next;
2516 iter (iter_cls, 3305 iter (iter_cls,
2517 ct->cc); 3306 ct);
3307 }
2518} 3308}
2519 3309
2520 3310
@@ -2628,10 +3418,7 @@ GCT_debug (const struct CadetTunnel *t,
2628 GCT_2s (t), 3418 GCT_2s (t),
2629 estate2s (t->estate), 3419 estate2s (t->estate),
2630 t->tq_len, 3420 t->tq_len,
2631 t->num_connections); 3421 GCT_count_any_connections (t));
2632#if DUMP_KEYS_TO_STDERR
2633 ax_debug (t->ax, level);
2634#endif
2635 LOG2 (level, 3422 LOG2 (level,
2636 "TTT channels:\n"); 3423 "TTT channels:\n");
2637 GNUNET_CONTAINER_multihashmap32_iterate (t->channels, 3424 GNUNET_CONTAINER_multihashmap32_iterate (t->channels,
@@ -2639,7 +3426,10 @@ GCT_debug (const struct CadetTunnel *t,
2639 &level); 3426 &level);
2640 LOG2 (level, 3427 LOG2 (level,
2641 "TTT connections:\n"); 3428 "TTT connections:\n");
2642 for (iter_c = t->connection_head; NULL != iter_c; iter_c = iter_c->next) 3429 for (iter_c = t->connection_ready_head; NULL != iter_c; iter_c = iter_c->next)
3430 GCC_debug (iter_c->cc,
3431 level);
3432 for (iter_c = t->connection_busy_head; NULL != iter_c; iter_c = iter_c->next)
2643 GCC_debug (iter_c->cc, 3433 GCC_debug (iter_c->cc,
2644 level); 3434 level);
2645 3435
diff --git a/src/cadet/gnunet-service-cadet-new_tunnels.h b/src/cadet/gnunet-service-cadet_tunnels.h
index c867a9e82..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
@@ -50,29 +50,36 @@ enum CadetTunnelEState
50 CADET_TUNNEL_KEY_UNINITIALIZED, 50 CADET_TUNNEL_KEY_UNINITIALIZED,
51 51
52 /** 52 /**
53 * Ephemeral key sent, waiting for peer's key. 53 * KX message sent, waiting for other peer's KX_AUTH.
54 */ 54 */
55 CADET_TUNNEL_KEY_SENT, 55 CADET_TUNNEL_KEY_AX_SENT,
56 56
57 /** 57 /**
58 * Key received and we sent ours back, but we got no traffic yet. 58 * KX message received, trying to send back KX_AUTH.
59 */
60 CADET_TUNNEL_KEY_AX_RECV,
61
62 /**
63 * KX message sent and received, trying to send back KX_AUTH.
64 */
65 CADET_TUNNEL_KEY_AX_SENT_AND_RECV,
66
67 /**
68 * KX received and we sent KX_AUTH back, but we got no traffic yet,
69 * so we're waiting for either KX_AUTH or ENCRYPED traffic from
70 * the other peer.
71 *
59 * We will not yet send traffic, as this might have been a replay. 72 * We will not yet send traffic, as this might have been a replay.
60 * The other (initiating) peer should send a CHANNEL_OPEN next 73 * The other (initiating) peer should send a CHANNEL_OPEN next
61 * anyway. 74 * anyway, and then we are in business!
62 */ 75 */
63 CADET_TUNNEL_KEY_PING, 76 CADET_TUNNEL_KEY_AX_AUTH_SENT,
64 77
65 /** 78 /**
66 * Handshake completed: session key available. 79 * Handshake completed: session key available.
67 */ 80 */
68 CADET_TUNNEL_KEY_OK, 81 CADET_TUNNEL_KEY_OK
69 82
70 /**
71 * New ephemeral key and ping sent, waiting for pong. Unlike KEY_PING,
72 * we still have a valid session key and therefore we *can* still send
73 * traffic on the tunnel.
74 */
75 CADET_TUNNEL_KEY_REKEY
76}; 83};
77 84
78 85
@@ -112,15 +119,29 @@ GCT_destroy_tunnel_now (struct CadetTunnel *t);
112 * 119 *
113 * @param t a tunnel 120 * @param t a tunnel
114 * @param cid connection identifer to use for the connection 121 * @param cid connection identifer to use for the connection
122 * @param options options for the connection
115 * @param path path to use for the connection 123 * @param path path to use for the connection
124 * @return #GNUNET_OK on success,
125 * #GNUNET_SYSERR on failure (duplicate connection)
116 */ 126 */
117void 127int
118GCT_add_inbound_connection (struct CadetTunnel *t, 128GCT_add_inbound_connection (struct CadetTunnel *t,
119 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid, 129 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
130 enum GNUNET_CADET_ChannelOption options,
120 struct CadetPeerPath *path); 131 struct CadetPeerPath *path);
121 132
122 133
123/** 134/**
135 * We lost a connection, remove it from our list and clean up
136 * the connection object itself.
137 *
138 * @param ct binding of connection to tunnel of the connection that was lost.
139 */
140void
141GCT_connection_lost (struct CadetTConnection *ct);
142
143
144/**
124 * Return the peer to which this tunnel goes. 145 * Return the peer to which this tunnel goes.
125 * 146 *
126 * @param t a tunnel 147 * @param t a tunnel
@@ -181,6 +202,19 @@ GCT_send_channel_destroy (struct CadetTunnel *t,
181 202
182 203
183/** 204/**
205 * Function called when a transmission requested using #GCT_send is done.
206 *
207 * @param cls closure
208 * @param ctn identifier of the connection used for transmission, NULL if
209 * the transmission failed (to be used to match ACKs to the
210 * respective connection for connection performance evaluation)
211 */
212typedef void
213(*GCT_SendContinuation)(void *cls,
214 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid);
215
216
217/**
184 * Sends an already built message on a tunnel, encrypting it and 218 * Sends an already built message on a tunnel, encrypting it and
185 * choosing the best connection if not provided. 219 * choosing the best connection if not provided.
186 * 220 *
@@ -188,12 +222,12 @@ GCT_send_channel_destroy (struct CadetTunnel *t,
188 * @param t Tunnel on which this message is transmitted. 222 * @param t Tunnel on which this message is transmitted.
189 * @param cont Continuation to call once message is really sent. 223 * @param cont Continuation to call once message is really sent.
190 * @param cont_cls Closure for @c cont. 224 * @param cont_cls Closure for @c cont.
191 * @return Handle to cancel message. NULL if @c cont is NULL. 225 * @return Handle to cancel message.
192 */ 226 */
193struct CadetTunnelQueueEntry * 227struct CadetTunnelQueueEntry *
194GCT_send (struct CadetTunnel *t, 228GCT_send (struct CadetTunnel *t,
195 const struct GNUNET_MessageHeader *message, 229 const struct GNUNET_MessageHeader *message,
196 GNUNET_SCHEDULER_TaskCallback cont, 230 GCT_SendContinuation cont,
197 void *cont_cls); 231 void *cont_cls);
198 232
199 233
@@ -227,18 +261,18 @@ GCT_count_channels (struct CadetTunnel *t);
227 * @return number of connections available for the tunnel 261 * @return number of connections available for the tunnel
228 */ 262 */
229unsigned int 263unsigned int
230GCT_count_any_connections (struct CadetTunnel *t); 264GCT_count_any_connections (const struct CadetTunnel *t);
231 265
232 266
233/** 267/**
234 * Iterator over connections. 268 * Iterator over connections.
235 * 269 *
236 * @param cls closure 270 * @param cls closure
237 * @param c one of the connections 271 * @param ct one of the connections
238 */ 272 */
239typedef void 273typedef void
240(*GCT_ConnectionIterator) (void *cls, 274(*GCT_ConnectionIterator) (void *cls,
241 struct CadetConnection *c); 275 struct CadetTConnection *ct);
242 276
243 277
244/** 278/**
@@ -301,6 +335,17 @@ GCT_handle_kx (struct CadetTConnection *ct,
301 335
302 336
303/** 337/**
338 * Handle KX_AUTH message.
339 *
340 * @param ct connection/tunnel combo that received encrypted message
341 * @param msg the key exchange message
342 */
343void
344GCT_handle_kx_auth (struct CadetTConnection *ct,
345 const struct GNUNET_CADET_TunnelKeyExchangeAuthMessage *msg);
346
347
348/**
304 * Handle encrypted message. 349 * Handle encrypted message.
305 * 350 *
306 * @param ct connection/tunnel combo that received encrypted message 351 * @param ct connection/tunnel combo that received encrypted message
diff --git a/src/cadet/test_cadet.c b/src/cadet/test_cadet.c
index 3a1042eba..72df2203c 100644
--- a/src/cadet/test_cadet.c
+++ b/src/cadet/test_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) 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
@@ -19,8 +19,9 @@
19*/ 19*/
20/** 20/**
21 * @file cadet/test_cadet.c 21 * @file cadet/test_cadet.c
22 * 22 * @author Bart Polot
23 * @brief Test for the cadet service: retransmission of traffic. 23 * @author Christian Grothoff
24 * @brief Test for the cadet service using mq API.
24 */ 25 */
25#include <stdio.h> 26#include <stdio.h>
26#include "platform.h" 27#include "platform.h"
@@ -31,9 +32,20 @@
31 32
32 33
33/** 34/**
34 * How many messages to send 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 by default.
35 */ 47 */
36#define TOTAL_PACKETS 500 /* Cannot exceed 64k! */ 48#define TOTAL_PACKETS 500 /* Cannot exceed 64k! */
37 49
38/** 50/**
39 * How long until we give up on connecting the peers? 51 * How long until we give up on connecting the peers?
@@ -41,7 +53,7 @@
41#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120) 53#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120)
42 54
43/** 55/**
44 * Time to wait for stuff that should be rather fast 56 * Time to wait by default for stuff that should be rather fast.
45 */ 57 */
46#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)
47 59
@@ -64,7 +76,7 @@ static int test;
64/** 76/**
65 * String with test name 77 * String with test name
66 */ 78 */
67char *test_name; 79static char *test_name;
68 80
69/** 81/**
70 * Flag to send traffic leaf->root in speed tests to test BCK_ACK logic. 82 * Flag to send traffic leaf->root in speed tests to test BCK_ACK logic.
@@ -72,6 +84,16 @@ char *test_name;
72static int test_backwards = GNUNET_NO; 84static int test_backwards = GNUNET_NO;
73 85
74/** 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/**
75 * How many events have happened 97 * How many events have happened
76 */ 98 */
77static int ok; 99static int ok;
@@ -79,32 +101,32 @@ static int ok;
79/** 101/**
80 * Number of events expected to conclude the test successfully. 102 * Number of events expected to conclude the test successfully.
81 */ 103 */
82int ok_goal; 104static int ok_goal;
83 105
84/** 106/**
85 * Size of each test packet 107 * Size of each test packet's payload
86 */ 108 */
87size_t size_payload = sizeof (struct GNUNET_MessageHeader) + sizeof (uint32_t); 109static size_t size_payload = sizeof (uint32_t);
88 110
89/** 111/**
90 * Operation to get peer ids. 112 * Operation to get peer ids.
91 */ 113 */
92struct GNUNET_TESTBED_Operation *t_op[2]; 114static struct GNUNET_TESTBED_Operation *t_op[2];
93 115
94/** 116/**
95 * Peer ids. 117 * Peer ids.
96 */ 118 */
97struct GNUNET_PeerIdentity *p_id[2]; 119static struct GNUNET_PeerIdentity *p_id[2];
98 120
99/** 121/**
100 * Port ID 122 * Port ID
101 */ 123 */
102struct GNUNET_HashCode port; 124static struct GNUNET_HashCode port;
103 125
104/** 126/**
105 * Peer ids counter. 127 * Peer ids counter.
106 */ 128 */
107unsigned int p_ids; 129static unsigned int p_ids;
108 130
109/** 131/**
110 * Is the setup initialized? 132 * Is the setup initialized?
@@ -157,9 +179,9 @@ static struct GNUNET_SCHEDULER_Task *disconnect_task;
157static struct GNUNET_SCHEDULER_Task *test_task; 179static struct GNUNET_SCHEDULER_Task *test_task;
158 180
159/** 181/**
160 * Task runnining #data_task(). 182 * Task runnining #send_next_msg().
161 */ 183 */
162static struct GNUNET_SCHEDULER_Task *data_job; 184static struct GNUNET_SCHEDULER_Task *send_next_msg_task;
163 185
164/** 186/**
165 * Cadet handle for the root peer 187 * Cadet handle for the root peer
@@ -174,7 +196,7 @@ static struct GNUNET_CADET_Handle *h2;
174/** 196/**
175 * Channel handle for the root peer 197 * Channel handle for the root peer
176 */ 198 */
177static struct GNUNET_CADET_Channel *ch; 199static struct GNUNET_CADET_Channel *outgoing_ch;
178 200
179/** 201/**
180 * Channel handle for the dest peer 202 * Channel handle for the dest peer
@@ -182,17 +204,6 @@ static struct GNUNET_CADET_Channel *ch;
182static struct GNUNET_CADET_Channel *incoming_ch; 204static struct GNUNET_CADET_Channel *incoming_ch;
183 205
184/** 206/**
185 * Transmit handle for root data calls
186 */
187static struct GNUNET_CADET_TransmitHandle *th;
188
189/**
190 * Transmit handle for root data calls
191 */
192static struct GNUNET_CADET_TransmitHandle *incoming_th;
193
194
195/**
196 * Time we started the data transmission (after channel has been established 207 * Time we started the data transmission (after channel has been established
197 * and initilized). 208 * and initilized).
198 */ 209 */
@@ -218,21 +229,32 @@ static unsigned int ka_sent;
218 */ 229 */
219static unsigned int ka_received; 230static unsigned int ka_received;
220 231
232/**
233 * How many messages were dropped by CADET because of full buffers?
234 */
235static unsigned int msg_dropped;
236
237
238/******************************************************************************/
239
240
241/******************************************************************************/
242
221 243
222/** 244/**
223 * Get the client number considered as the "target" or "receiver", depending on 245 * Get the channel considered as the "target" or "receiver", depending on
224 * the test type and size. 246 * the test type and size.
225 * 247 *
226 * @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)
227 * the last peer in the line (for other tests). 249 * or the last peer in the line (for other tests).
228 */ 250 */
229static unsigned int 251static struct GNUNET_CADET_Channel *
230get_expected_target () 252get_target_channel ()
231{ 253{
232 if (SPEED == test && GNUNET_YES == test_backwards) 254 if (SPEED == test && GNUNET_YES == test_backwards)
233 return 0; 255 return outgoing_ch;
234 else 256 else
235 return peers_requested - 1; 257 return incoming_ch;
236} 258}
237 259
238 260
@@ -245,18 +267,15 @@ show_end_data (void)
245 static struct GNUNET_TIME_Absolute end_time; 267 static struct GNUNET_TIME_Absolute end_time;
246 static struct GNUNET_TIME_Relative total_time; 268 static struct GNUNET_TIME_Relative total_time;
247 269
248 end_time = GNUNET_TIME_absolute_get(); 270 end_time = GNUNET_TIME_absolute_get ();
249 total_time = GNUNET_TIME_absolute_get_difference(start_time, end_time); 271 total_time = GNUNET_TIME_absolute_get_difference (start_time, end_time);
250 FPRINTF (stderr, "\nResults of test \"%s\"\n", test_name); 272 FPRINTF (stderr, "\nResults of test \"%s\"\n", test_name);
251 FPRINTF (stderr, "Test time %s\n", 273 FPRINTF (stderr, "Test time %s\n",
252 GNUNET_STRINGS_relative_time_to_string (total_time, 274 GNUNET_STRINGS_relative_time_to_string (total_time, GNUNET_YES));
253 GNUNET_YES)); 275 FPRINTF (stderr, "Test bandwidth: %f kb/s\n", 4 * total_packets * 1.0 / (total_time.rel_value_us / 1000)); // 4bytes * ms
254 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
255 4 * TOTAL_PACKETS * 1.0 / (total_time.rel_value_us / 1000)); // 4bytes * ms
256 FPRINTF (stderr, "Test throughput: %f packets/s\n\n",
257 TOTAL_PACKETS * 1000.0 / (total_time.rel_value_us / 1000)); // packets * ms
258 GAUGER ("CADET", test_name, 277 GAUGER ("CADET", test_name,
259 TOTAL_PACKETS * 1000.0 / (total_time.rel_value_us / 1000), 278 total_packets * 1000.0 / (total_time.rel_value_us / 1000),
260 "packets/s"); 279 "packets/s");
261} 280}
262 281
@@ -275,29 +294,19 @@ disconnect_cadet_peers (void *cls)
275 294
276 disconnect_task = NULL; 295 disconnect_task = NULL;
277 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 296 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
278 "disconnecting cadet service of peers, called from line %ld\n", 297 "disconnecting cadet service of peers, called from line %ld\n",
279 line); 298 line);
280 for (i = 0; i < 2; i++) 299 for (i = 0; i < 2; i++)
281 { 300 {
282 GNUNET_TESTBED_operation_done (t_op[i]); 301 GNUNET_TESTBED_operation_done (t_op[i]);
283 } 302 }
284 if (NULL != ch) 303 if (NULL != outgoing_ch)
285 { 304 {
286 if (NULL != th) 305 GNUNET_CADET_channel_destroy (outgoing_ch);
287 { 306 outgoing_ch = NULL;
288 GNUNET_CADET_notify_transmit_ready_cancel (th);
289 th = NULL;
290 }
291 GNUNET_CADET_channel_destroy (ch);
292 ch = NULL;
293 } 307 }
294 if (NULL != incoming_ch) 308 if (NULL != incoming_ch)
295 { 309 {
296 if (NULL != incoming_th)
297 {
298 GNUNET_CADET_notify_transmit_ready_cancel (incoming_th);
299 incoming_th = NULL;
300 }
301 GNUNET_CADET_channel_destroy (incoming_ch); 310 GNUNET_CADET_channel_destroy (incoming_ch);
302 incoming_ch = NULL; 311 incoming_ch = NULL;
303 } 312 }
@@ -316,10 +325,10 @@ static void
316shutdown_task (void *cls) 325shutdown_task (void *cls)
317{ 326{
318 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ending test.\n"); 327 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ending test.\n");
319 if (NULL != data_job) 328 if (NULL != send_next_msg_task)
320 { 329 {
321 GNUNET_SCHEDULER_cancel (data_job); 330 GNUNET_SCHEDULER_cancel (send_next_msg_task);
322 data_job = NULL; 331 send_next_msg_task = NULL;
323 } 332 }
324 if (NULL != test_task) 333 if (NULL != test_task)
325 { 334 {
@@ -329,8 +338,8 @@ shutdown_task (void *cls)
329 if (NULL != disconnect_task) 338 if (NULL != disconnect_task)
330 { 339 {
331 GNUNET_SCHEDULER_cancel (disconnect_task); 340 GNUNET_SCHEDULER_cancel (disconnect_task);
332 disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, 341 disconnect_task =
333 (void *) __LINE__); 342 GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, (void *) __LINE__);
334 } 343 }
335} 344}
336 345
@@ -349,14 +358,16 @@ stats_cont (void *cls, struct GNUNET_TESTBED_Operation *op, const char *emsg)
349{ 358{
350 GNUNET_log (GNUNET_ERROR_TYPE_INFO, " KA sent: %u, KA received: %u\n", 359 GNUNET_log (GNUNET_ERROR_TYPE_INFO, " KA sent: %u, KA received: %u\n",
351 ka_sent, ka_received); 360 ka_sent, ka_received);
352 if (KEEPALIVE == test && (ka_sent < 2 || ka_sent > ka_received + 1)) 361 if ((KEEPALIVE == test) && ((ka_sent < 2) || (ka_sent > ka_received + 1)))
362 {
363 GNUNET_break (0);
353 ok--; 364 ok--;
365 }
354 GNUNET_TESTBED_operation_done (stats_op); 366 GNUNET_TESTBED_operation_done (stats_op);
355 367
356 if (NULL != disconnect_task) 368 if (NULL != disconnect_task)
357 GNUNET_SCHEDULER_cancel (disconnect_task); 369 GNUNET_SCHEDULER_cancel (disconnect_task);
358 disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, 370 disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, cls);
359 cls);
360} 371}
361 372
362 373
@@ -372,29 +383,27 @@ stats_cont (void *cls, struct GNUNET_TESTBED_Operation *op, const char *emsg)
372 * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration 383 * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
373 */ 384 */
374static int 385static int
375stats_iterator (void *cls, 386stats_iterator (void *cls, const struct GNUNET_TESTBED_Peer *peer,
376 const struct GNUNET_TESTBED_Peer *peer, 387 const char *subsystem, const char *name, uint64_t value,
377 const char *subsystem,
378 const char *name,
379 uint64_t value,
380 int is_persistent) 388 int is_persistent)
381{ 389{
382 static const char *s_sent = "# keepalives sent"; 390 static const char *s_sent = "# keepalives sent";
383 static const char *s_recv = "# keepalives received"; 391 static const char *s_recv = "# keepalives received";
392 static const char *rdrops = "# messages dropped due to full buffer";
393 static const char *cdrops = "# messages dropped due to slow client";
384 uint32_t i; 394 uint32_t i;
385 395
386 i = GNUNET_TESTBED_get_index (peer); 396 i = GNUNET_TESTBED_get_index (peer);
387 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 397 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "STATS PEER %u - %s [%s]: %llu\n", i,
388 "STATS PEER %u - %s [%s]: %llu\n", 398 subsystem, name, (unsigned long long) value);
389 i,
390 subsystem,
391 name,
392 (unsigned long long) value);
393 if (0 == strncmp (s_sent, name, strlen (s_sent)) && 0 == i) 399 if (0 == strncmp (s_sent, name, strlen (s_sent)) && 0 == i)
394 ka_sent = value; 400 ka_sent = value;
395 401 if (0 == strncmp (s_recv, name, strlen (s_recv)) && peers_requested - 1 == i)
396 if (0 == strncmp(s_recv, name, strlen (s_recv)) && peers_requested - 1 == i)
397 ka_received = value; 402 ka_received = value;
403 if (0 == strncmp (rdrops, name, strlen (rdrops)))
404 msg_dropped += value;
405 if (0 == strncmp (cdrops, name, strlen (cdrops)))
406 msg_dropped += value;
398 407
399 return GNUNET_OK; 408 return GNUNET_OK;
400} 409}
@@ -403,7 +412,7 @@ stats_iterator (void *cls,
403/** 412/**
404 * Task to gather all statistics. 413 * Task to gather all statistics.
405 * 414 *
406 * @param cls Closure (NULL). 415 * @param cls Closure (line from which the task was scheduled).
407 */ 416 */
408static void 417static void
409gather_stats_and_exit (void *cls) 418gather_stats_and_exit (void *cls)
@@ -412,21 +421,20 @@ gather_stats_and_exit (void *cls)
412 421
413 disconnect_task = NULL; 422 disconnect_task = NULL;
414 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 423 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
415 "gathering statistics from line %d\n", 424 "gathering statistics from line %ld\n",
416 (int) l); 425 l);
417 if (NULL != ch) 426 if (NULL != outgoing_ch)
418 { 427 {
419 if (NULL != th) 428 GNUNET_CADET_channel_destroy (outgoing_ch);
420 { 429 outgoing_ch = NULL;
421 GNUNET_CADET_notify_transmit_ready_cancel (th);
422 th = NULL;
423 }
424 GNUNET_CADET_channel_destroy (ch);
425 ch = NULL;
426 } 430 }
427 stats_op = GNUNET_TESTBED_get_statistics (peers_running, testbed_peers, 431 stats_op = GNUNET_TESTBED_get_statistics (peers_running,
428 "cadet", NULL, 432 testbed_peers,
429 stats_iterator, stats_cont, cls); 433 "cadet",
434 NULL,
435 &stats_iterator,
436 stats_cont,
437 cls);
430} 438}
431 439
432 440
@@ -439,165 +447,154 @@ gather_stats_and_exit (void *cls)
439static void 447static void
440abort_test (long line) 448abort_test (long line)
441{ 449{
442 if (disconnect_task != NULL) 450 if (NULL != disconnect_task)
443 { 451 {
444 GNUNET_SCHEDULER_cancel (disconnect_task); 452 GNUNET_SCHEDULER_cancel (disconnect_task);
445 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Aborting test from %ld\n", line); 453 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Aborting test from %ld\n", line);
446 disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, 454 disconnect_task =
447 (void *) line); 455 GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, (void *) line);
448 } 456 }
449} 457}
450 458
451/**
452 * Transmit ready callback.
453 *
454 * @param cls Closure (message type).
455 * @param size Size of the tranmist buffer.
456 * @param buf Pointer to the beginning of the buffer.
457 *
458 * @return Number of bytes written to buf.
459 */
460static size_t
461tmt_rdy (void *cls, size_t size, void *buf);
462
463 459
464/** 460/**
465 * 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.
466 * 464 *
467 * @param cls Closure (peer #). 465 * @param channel Channel to send the message on.
468 */ 466 */
469static void 467static void
470data_task (void *cls) 468send_test_message (struct GNUNET_CADET_Channel *channel)
471{ 469{
472 struct GNUNET_CADET_Channel *channel; 470 struct GNUNET_MQ_Envelope *env;
473 static struct GNUNET_CADET_TransmitHandle **pth; 471 struct GNUNET_MessageHeader *msg;
474 long src; 472 uint32_t *data;
473 int payload;
474 int size;
475 475
476 data_job = NULL; 476 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
477 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Data task\n"); 477 "Sending test message on channel %p\n",
478 if (GNUNET_YES == test_backwards) 478 channel);
479 { 479 size = size_payload;
480 channel = incoming_ch; 480 if (GNUNET_NO == initialized)
481 pth = &incoming_th;
482 src = peers_requested - 1;
483 }
484 else
485 { 481 {
486 channel = ch; 482 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending INITIALIZER\n");
487 pth = &th; 483 size += 1000;
488 src = 0; 484 payload = data_sent;
485 if (SPEED_ACK == test) // FIXME unify SPEED_ACK with an initializer
486 data_sent++;
489 } 487 }
490 488 else if (SPEED == test || SPEED_ACK == test)
491 GNUNET_assert (NULL != channel);
492 GNUNET_assert (NULL == *pth);
493
494 *pth = GNUNET_CADET_notify_transmit_ready (channel, GNUNET_NO,
495 GNUNET_TIME_UNIT_FOREVER_REL,
496 size_payload + data_sent,
497 &tmt_rdy, (void *) src);
498 if (NULL == *pth)
499 { 489 {
500 unsigned long i = (unsigned long) cls; 490 if (get_target_channel() == channel)
501
502 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Retransmission\n");
503 if (0 == i)
504 { 491 {
505 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, " in 1 ms\n"); 492 payload = ack_sent;
506 data_job = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS, 493 size += ack_sent;
507 &data_task, (void *) 1L); 494 ack_sent++;
495 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
496 "Sending ACK %u [%d bytes]\n",
497 payload, size);
508 } 498 }
509 else 499 else
510 { 500 {
511 i++; 501 payload = data_sent;
512 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 502 size += data_sent;
513 "in %llu ms\n", 503 data_sent++;
514 (unsigned long long) i); 504 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
515 data_job = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 505 "Sending DATA %u [%d bytes]\n",
516 i), 506 data_sent, size);
517 &data_task, (void *) i);
518 } 507 }
519 } 508 }
520} 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);
521 522
523 data = (uint32_t *) &msg[1];
524 *data = htonl (payload);
525 GNUNET_MQ_send (GNUNET_CADET_get_mq (channel), env);
526}
522 527
523/** 528/**
524 * 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.
525 * 531 *
526 * @param cls Closure (peer # which is sending the data). 532 * @param cls Closure (unused).
527 * @param size Size of the buffer we have.
528 * @param buf Buffer to copy data to.
529 */ 533 */
530static size_t 534static void
531tmt_rdy (void *cls, size_t size, void *buf) 535send_next_msg (void *cls)
532{ 536{
533 struct GNUNET_MessageHeader *msg = buf; 537 struct GNUNET_CADET_Channel *channel;
534 size_t msg_size;
535 uint32_t *data;
536 long id = (long) cls;
537 unsigned int counter;
538 538
539 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 539 send_next_msg_task = NULL;
540 "tmt_rdy on %ld, filling buffer\n", 540 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending next message: %d\n", data_sent);
541 id); 541
542 if (0 == id) 542 channel = GNUNET_YES == test_backwards ? incoming_ch : outgoing_ch;
543 th = NULL; 543 GNUNET_assert (NULL != channel);
544 else if ((peers_requested - 1) == id) 544 GNUNET_assert (SPEED == test);
545 incoming_th = NULL; 545 send_test_message (channel);
546 else 546 if (data_sent < total_packets)
547 GNUNET_assert (0);
548 counter = get_expected_target () == id ? ack_sent : data_sent;
549 msg_size = size_payload + counter;
550 GNUNET_assert (msg_size > sizeof (struct GNUNET_MessageHeader));
551 if ( (size < msg_size) ||
552 (NULL == buf) )
553 {
554 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
555 "size %u, buf %p, data_sent %u, ack_received %u\n",
556 (unsigned int) size,
557 buf,
558 data_sent,
559 ack_received);
560 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ok %u, ok goal %u\n", ok, ok_goal);
561 GNUNET_break (ok >= ok_goal - 2);
562
563 return 0;
564 }
565 msg->size = htons (msg_size);
566 msg->type = htons (GNUNET_MESSAGE_TYPE_DUMMY);
567 data = (uint32_t *) &msg[1];
568 *data = htonl (counter);
569 if (GNUNET_NO == initialized)
570 { 547 {
548 /* SPEED test: Send all messages as soon as possible */
571 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 549 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
572 "sending initializer\n"); 550 "Scheduling message %d\n",
573 msg_size = size_payload + 1000; 551 data_sent + 1);
574 msg->size = htons (msg_size); 552 send_next_msg_task =
575 if (SPEED_ACK == test) 553 GNUNET_SCHEDULER_add_delayed(GNUNET_TIME_UNIT_SECONDS,
576 data_sent++; 554 &send_next_msg,
555 NULL);
577 } 556 }
578 else if ( (SPEED == test) || 557}
579 (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)
580 { 570 {
581 if (get_expected_target() == id) 571 if (NULL != disconnect_task)
582 ack_sent++;
583 else
584 data_sent++;
585 counter++;
586 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
587 " Sent message %u size %u\n",
588 counter,
589 (unsigned int) msg_size);
590 if ( (data_sent < TOTAL_PACKETS) &&
591 (SPEED == test) )
592 { 572 {
593 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 573 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
594 " Scheduling message %d\n", 574 " reschedule timeout every 10 messages\n");
595 counter + 1); 575 GNUNET_SCHEDULER_cancel (disconnect_task);
596 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);
597 } 579 }
598 } 580 }
581}
599 582
600 return msg_size; 583
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 */
601} 598}
602 599
603 600
@@ -605,75 +602,50 @@ tmt_rdy (void *cls, size_t size, void *buf)
605 * Function is called whenever a message is received. 602 * Function is called whenever a message is received.
606 * 603 *
607 * @param cls closure (set from GNUNET_CADET_connect(), peer number) 604 * @param cls closure (set from GNUNET_CADET_connect(), peer number)
608 * @param channel connection to the other end
609 * @param channel_ctx place to store local state associated with the channel
610 * @param message the actual message 605 * @param message the actual message
611 * @return #GNUNET_OK to keep the connection open,
612 * #GNUNET_SYSERR to close it (signal serious error)
613 */ 606 */
614static int 607static void
615data_callback (void *cls, 608handle_data (void *cls, const struct GNUNET_MessageHeader *message)
616 struct GNUNET_CADET_Channel *channel,
617 void **channel_ctx,
618 const struct GNUNET_MessageHeader *message)
619{ 609{
620 struct GNUNET_CADET_TransmitHandle **pth; 610 struct CadetTestChannelWrapper *ch = cls;
621 long client = (long) cls; 611 struct GNUNET_CADET_Channel *channel = ch->ch;
622 long expected_target_client;
623 uint32_t *data; 612 uint32_t *data;
624 uint32_t payload; 613 uint32_t payload;
625 unsigned int counter; 614 int *counter;
626 615
627 ok++; 616 ok++;
628 counter = get_expected_target () == client ? data_received : ack_received;
629
630 GNUNET_CADET_receive_done (channel); 617 GNUNET_CADET_receive_done (channel);
618 counter = get_target_channel () == channel ? &data_received : &ack_received;
631 619
632 if ((ok % 10) == 0) 620 reschedule_timeout_task ((long) __LINE__);
621
622 if (channel == outgoing_ch)
633 { 623 {
634 if (NULL != disconnect_task) 624 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Root client got a message.\n");
635 {
636 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
637 " reschedule timeout\n");
638 GNUNET_SCHEDULER_cancel (disconnect_task);
639 disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME,
640 &gather_stats_and_exit,
641 (void *) __LINE__);
642 }
643 } 625 }
644 626 else if (channel == incoming_ch)
645 switch (client) 627 {
628 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Leaf client got a message.\n");
629 }
630 else
646 { 631 {
647 case 0L: 632 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unknown channel %p.\n", channel);
648 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Root client got a message!\n");
649 GNUNET_assert (channel == ch);
650 pth = &th;
651 break;
652 case 1L:
653 case 4L:
654 GNUNET_assert (client == peers_requested - 1);
655 GNUNET_assert (channel == incoming_ch);
656 pth = &incoming_th;
657 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Leaf client %ld got a message.\n",
658 client);
659 break;
660 default:
661 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Client %ld not valid.\n", client);
662 GNUNET_assert (0); 633 GNUNET_assert (0);
663 } 634 }
635
664 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);
665 data = (uint32_t *) &message[1]; 637 data = (uint32_t *) &message[1];
666 payload = ntohl (*data); 638 payload = ntohl (*data);
667 if (payload == counter) 639 if (payload == *counter)
668 { 640 {
669 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);
670 } 642 }
671 else 643 else
672 { 644 {
673 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, " payload %u, expected: %u\n", 645 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
674 payload, counter); 646 " payload %u, expected: %u\n",
647 payload, *counter);
675 } 648 }
676 expected_target_client = get_expected_target ();
677 649
678 if (GNUNET_NO == initialized) 650 if (GNUNET_NO == initialized)
679 { 651 {
@@ -681,188 +653,152 @@ data_callback (void *cls,
681 start_time = GNUNET_TIME_absolute_get (); 653 start_time = GNUNET_TIME_absolute_get ();
682 if (SPEED == test) 654 if (SPEED == test)
683 { 655 {
684 GNUNET_assert (peers_requested - 1 == client); 656 GNUNET_assert (incoming_ch == channel);
685 data_job = GNUNET_SCHEDULER_add_now (&data_task, NULL); 657 send_next_msg_task = GNUNET_SCHEDULER_add_now (&send_next_msg, NULL);
686 return GNUNET_OK; 658 return;
687 } 659 }
688 } 660 }
689 661
690 counter++; 662 (*counter)++;
691 if (client == expected_target_client) /* Normally 4 */ 663 if (get_target_channel () == channel) /* Got "data" */
692 { 664 {
693 data_received++;
694 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);
695 if (SPEED != test || (ok_goal - 2) == ok) 666 if (SPEED != test || (ok_goal - 2) == ok)
696 { 667 {
697 /* Send ACK */ 668 /* Send ACK */
698 GNUNET_assert (NULL == *pth); 669 send_test_message (channel);
699 *pth = GNUNET_CADET_notify_transmit_ready (channel, GNUNET_NO, 670 return;
700 GNUNET_TIME_UNIT_FOREVER_REL,
701 size_payload + ack_sent,
702 &tmt_rdy, (void *) client);
703 return GNUNET_OK;
704 } 671 }
705 else 672 else
706 { 673 {
707 if (data_received < TOTAL_PACKETS) 674 if (data_received < total_packets)
708 return GNUNET_OK; 675 return;
709 } 676 }
710 } 677 }
711 else /* Normally 0 */ 678 else /* Got "ack" */
712 { 679 {
713 if (SPEED_ACK == test || SPEED == test) 680 if (SPEED_ACK == test || SPEED == test)
714 { 681 {
715 ack_received++;
716 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);
717 /* send more data */ 683 /* Send more data */
718 GNUNET_assert (NULL == *pth); 684 send_test_message (channel);
719 *pth = GNUNET_CADET_notify_transmit_ready (channel, GNUNET_NO, 685 if (ack_received < total_packets && SPEED != test)
720 GNUNET_TIME_UNIT_FOREVER_REL, 686 return;
721 size_payload + data_sent,
722 &tmt_rdy, (void *) client);
723 if (ack_received < TOTAL_PACKETS && SPEED != test)
724 return GNUNET_OK;
725 if (ok == 2 && SPEED == test) 687 if (ok == 2 && SPEED == test)
726 return GNUNET_OK; 688 return;
727 show_end_data(); 689 show_end_data ();
728 } 690 }
729 if (test == P2P_SIGNAL) 691 if (test == P2P_SIGNAL)
730 { 692 {
731 if (NULL != incoming_th)
732 {
733 GNUNET_CADET_notify_transmit_ready_cancel (incoming_th);
734 incoming_th = NULL;
735 }
736 GNUNET_CADET_channel_destroy (incoming_ch); 693 GNUNET_CADET_channel_destroy (incoming_ch);
737 incoming_ch = NULL; 694 incoming_ch = NULL;
738 } 695 }
739 else 696 else
740 { 697 {
741 if (NULL != th) 698 GNUNET_CADET_channel_destroy (outgoing_ch);
742 { 699 outgoing_ch = NULL;
743 GNUNET_CADET_notify_transmit_ready_cancel (th);
744 th = NULL;
745 }
746 GNUNET_CADET_channel_destroy (ch);
747 ch = NULL;
748 } 700 }
749 } 701 }
750
751 return GNUNET_OK;
752} 702}
753 703
754 704
755/** 705/**
756 * Data handlers for every message type of CADET's payload. 706 * Method called whenever a peer connects to a port in MQ-based CADET.
757 * {callback_function, message_type, size_expected}
758 */
759static struct GNUNET_CADET_MessageHandler handlers[] = {
760 {&data_callback,
761 GNUNET_MESSAGE_TYPE_DUMMY,
762 sizeof (struct GNUNET_MessageHeader)},
763 {NULL, 0, 0}
764};
765
766
767/**
768 * Method called whenever another peer has added us to a channel
769 * the other peer initiated.
770 * 707 *
771 * @param cls Closure. 708 * @param cls Closure from #GNUNET_CADET_open_port (peer # as long).
772 * @param channel New handle to the channel. 709 * @param channel New handle to the channel.
773 * @param initiator Peer that started the channel. 710 * @param source Peer that started this channel.
774 * @param port Port this channel is connected to. 711 * @return Closure for the incoming @a channel. It's given to:
775 * @param options channel option flags 712 * - The #GNUNET_CADET_DisconnectEventHandler (given to
776 * @return Initial channel context for the channel 713 * #GNUNET_CADET_open_port) when the channel dies.
777 * (can be NULL -- that's not an error). 714 * - Each the #GNUNET_MQ_MessageCallback handlers for each message
715 * received on the @a channel.
778 */ 716 */
779static void * 717static void *
780incoming_channel (void *cls, 718connect_handler (void *cls, struct GNUNET_CADET_Channel *channel,
781 struct GNUNET_CADET_Channel *channel, 719 const struct GNUNET_PeerIdentity *source)
782 const struct GNUNET_PeerIdentity *initiator,
783 const struct GNUNET_HashCode *port,
784 enum GNUNET_CADET_ChannelOption options)
785{ 720{
721 struct CadetTestChannelWrapper *ch;
722 long peer = (long) cls;
723
786 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 724 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
787 "Incoming channel from %s to peer %d:%s\n", 725 "Incoming channel from %s to %ld: %p\n",
788 GNUNET_i2s (initiator), 726 GNUNET_i2s (source), peer, channel);
789 (int) (long) cls, GNUNET_h2s (port));
790 ok++; 727 ok++;
791 GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok); 728 GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok);
792 if ((long) cls == peers_requested - 1) 729 if (peer == peers_requested - 1)
793 { 730 {
794 if (NULL != incoming_ch) 731 if (NULL != incoming_ch)
795 { 732 {
796 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 733 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
797 "Duplicate incoming channel for client %lu\n", 734 "Duplicate incoming channel for client %lu\n", (long) cls);
798 (long) cls); 735 GNUNET_assert (0);
799 GNUNET_break(0);
800 } 736 }
801 incoming_ch = channel; 737 incoming_ch = channel;
802 } 738 }
803 else 739 else
804 { 740 {
805 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 741 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
806 "Incoming channel for unknown client %lu\n", (long) cls); 742 "Incoming channel for unexpected peer #%lu\n", (long) cls);
807 GNUNET_break(0); 743 GNUNET_assert (0);
808 } 744 }
809 if (NULL != disconnect_task) 745 if (NULL != disconnect_task)
810 { 746 {
811 GNUNET_SCHEDULER_cancel (disconnect_task); 747 GNUNET_SCHEDULER_cancel (disconnect_task);
812 disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME, 748 disconnect_task = GNUNET_SCHEDULER_add_delayed (short_time,
813 &gather_stats_and_exit, 749 &gather_stats_and_exit,
814 (void *) __LINE__); 750 (void *) __LINE__);
815 } 751 }
816 752
817 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;
818} 758}
819 759
820 760
821/** 761/**
822 * Function called whenever an inbound channel is destroyed. Should clean up 762 * Function called whenever an MQ-channel is destroyed, even if the destruction
823 * any associated state. 763 * was requested by #GNUNET_CADET_channel_destroy.
764 * It must NOT call #GNUNET_CADET_channel_destroy on the channel.
824 * 765 *
825 * @param cls closure (set from GNUNET_CADET_connect, peer number) 766 * It should clean up any associated state, including cancelling any pending
826 * @param channel connection to the other end (henceforth invalid) 767 * transmission on this channel.
827 * @param channel_ctx place where local state associated 768 *
828 * with the channel is stored 769 * @param cls Channel closure (channel wrapper).
770 * @param channel Connection to the other end (henceforth invalid).
829 */ 771 */
830static void 772static void
831channel_cleaner (void *cls, 773disconnect_handler (void *cls, const struct GNUNET_CADET_Channel *channel)
832 const struct GNUNET_CADET_Channel *channel,
833 void *channel_ctx)
834{ 774{
835 long i = (long) cls; 775 struct CadetTestChannelWrapper *ch_w = cls;
836 776
837 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 777 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Channel disconnected\n");
838 "Incoming channel disconnected at peer %ld\n", 778 GNUNET_assert (ch_w->ch == channel);
839 i); 779 if (channel == incoming_ch)
840 if (peers_running - 1 == i)
841 { 780 {
842 ok++; 781 ok++;
843 GNUNET_break (channel == incoming_ch);
844 incoming_ch = NULL; 782 incoming_ch = NULL;
845 } 783 }
846 else if (0L == i) 784 else if (outgoing_ch == channel
785 )
847 { 786 {
848 if (P2P_SIGNAL == test) 787 if (P2P_SIGNAL == test)
849 { 788 {
850 ok++; 789 ok++;
851 } 790 }
852 GNUNET_break (channel == ch); 791 outgoing_ch = NULL;
853 ch = NULL;
854 } 792 }
855 else 793 else
856 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 794 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Unknown channel! %p\n", channel);
857 "Unknown peer! %d\n",
858 (int) i);
859 GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok); 795 GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok);
860 796
861 if (NULL != disconnect_task) 797 if (NULL != disconnect_task)
862 { 798 {
863 GNUNET_SCHEDULER_cancel (disconnect_task); 799 GNUNET_SCHEDULER_cancel (disconnect_task);
864 disconnect_task = GNUNET_SCHEDULER_add_now (&gather_stats_and_exit, 800 disconnect_task =
865 (void *) __LINE__); 801 GNUNET_SCHEDULER_add_now (&gather_stats_and_exit, (void *) __LINE__);
866 } 802 }
867} 803}
868 804
@@ -876,13 +812,20 @@ channel_cleaner (void *cls,
876 * @param cls Closure (unused). 812 * @param cls Closure (unused).
877 */ 813 */
878static void 814static void
879do_test (void *cls) 815start_test (void *cls)
880{ 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;
881 enum GNUNET_CADET_ChannelOption flags; 825 enum GNUNET_CADET_ChannelOption flags;
882 826
883 test_task = NULL; 827 test_task = NULL;
884 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 828 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "start_test\n");
885 "do_test\n");
886 if (NULL != disconnect_task) 829 if (NULL != disconnect_task)
887 { 830 {
888 GNUNET_SCHEDULER_cancel (disconnect_task); 831 GNUNET_SCHEDULER_cancel (disconnect_task);
@@ -896,30 +839,33 @@ do_test (void *cls)
896 flags |= GNUNET_CADET_OPTION_RELIABLE; 839 flags |= GNUNET_CADET_OPTION_RELIABLE;
897 } 840 }
898 841
899 ch = GNUNET_CADET_channel_create (h1, 842 ch = GNUNET_new (struct CadetTestChannelWrapper);
900 NULL, 843 outgoing_ch = GNUNET_CADET_channel_create (h1,
901 p_id[1], 844 ch,
902 &port, 845 p_id[1],
903 flags); 846 &port,
847 flags,
848 NULL,
849 &disconnect_handler,
850 handlers);
904 851
905 disconnect_task 852 ch->ch = outgoing_ch;
906 = GNUNET_SCHEDULER_add_delayed (SHORT_TIME, 853
907 &gather_stats_and_exit, 854 disconnect_task = GNUNET_SCHEDULER_add_delayed (short_time,
908 (void *) __LINE__); 855 &gather_stats_and_exit,
856 (void *) __LINE__);
909 if (KEEPALIVE == test) 857 if (KEEPALIVE == test)
910 return; /* Don't send any data. */ 858 return; /* Don't send any data. */
859
911 860
912 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
913 "Sending data initializer...\n");
914 data_received = 0; 861 data_received = 0;
915 data_sent = 0; 862 data_sent = 0;
916 ack_received = 0; 863 ack_received = 0;
917 ack_sent = 0; 864 ack_sent = 0;
918 th = GNUNET_CADET_notify_transmit_ready (ch, 865 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
919 GNUNET_NO, 866 "Sending data initializer on channel %p...\n",
920 GNUNET_TIME_UNIT_FOREVER_REL, 867 outgoing_ch);
921 size_payload + 1000, 868 send_test_message (outgoing_ch);
922 &tmt_rdy, (void *) 0L);
923} 869}
924 870
925 871
@@ -933,35 +879,26 @@ do_test (void *cls)
933 * NULL if the operation is successfull 879 * NULL if the operation is successfull
934 */ 880 */
935static void 881static void
936pi_cb (void *cls, 882pi_cb (void *cls, struct GNUNET_TESTBED_Operation *op,
937 struct GNUNET_TESTBED_Operation *op, 883 const struct GNUNET_TESTBED_PeerInformation *pinfo, const char *emsg)
938 const struct GNUNET_TESTBED_PeerInformation *pinfo,
939 const char *emsg)
940{ 884{
941 long i = (long) cls; 885 long i = (long) cls;
942 886
943 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 887 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ID callback for %ld\n", i);
944 "id callback for %ld\n", i);
945 888
946 if ( (NULL == pinfo) || 889 if ((NULL == pinfo) || (NULL != emsg))
947 (NULL != emsg) )
948 { 890 {
949 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 891 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "pi_cb: %s\n", emsg);
950 "pi_cb: %s\n", emsg);
951 abort_test (__LINE__); 892 abort_test (__LINE__);
952 return; 893 return;
953 } 894 }
954 p_id[i] = pinfo->result.id; 895 p_id[i] = pinfo->result.id;
955 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 896 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " id: %s\n", GNUNET_i2s (p_id[i]));
956 " id: %s\n", GNUNET_i2s (p_id[i]));
957 p_ids++; 897 p_ids++;
958 if (p_ids < 2) 898 if (p_ids < 2)
959 return; 899 return;
960 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 900 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got all IDs, starting test\n");
961 "Got all IDs, starting test\n"); 901 test_task = GNUNET_SCHEDULER_add_now (&start_test, NULL);
962 test_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
963 &do_test,
964 NULL);
965} 902}
966 903
967 904
@@ -972,7 +909,7 @@ pi_cb (void *cls,
972 * @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.
973 * @param num_peers Number of peers that are running. 910 * @param num_peers Number of peers that are running.
974 * @param peers Array of peers. 911 * @param peers Array of peers.
975 * @param cadetes Handle to each of the CADETs of the peers. 912 * @param cadets Handle to each of the CADETs of the peers.
976 */ 913 */
977static void 914static void
978tmain (void *cls, 915tmain (void *cls,
@@ -989,16 +926,18 @@ tmain (void *cls,
989 testbed_peers = peers; 926 testbed_peers = peers;
990 h1 = cadets[0]; 927 h1 = cadets[0];
991 h2 = cadets[num_peers - 1]; 928 h2 = cadets[num_peers - 1];
992 disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME, 929 disconnect_task = GNUNET_SCHEDULER_add_delayed (short_time,
993 &disconnect_cadet_peers, 930 &disconnect_cadet_peers,
994 (void *) __LINE__); 931 (void *) __LINE__);
995 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); 932 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
996 t_op[0] = GNUNET_TESTBED_peer_get_information (peers[0], 933 t_op[0] = GNUNET_TESTBED_peer_get_information (peers[0],
997 GNUNET_TESTBED_PIT_IDENTITY, 934 GNUNET_TESTBED_PIT_IDENTITY,
998 &pi_cb, (void *) 0L); 935 &pi_cb,
936 (void *) 0L);
999 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],
1000 GNUNET_TESTBED_PIT_IDENTITY, 938 GNUNET_TESTBED_PIT_IDENTITY,
1001 &pi_cb, (void *) 1L); 939 &pi_cb,
940 (void *) 1L);
1002 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "requested peer ids\n"); 941 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "requested peer ids\n");
1003} 942}
1004 943
@@ -1009,16 +948,46 @@ tmain (void *cls,
1009int 948int
1010main (int argc, char *argv[]) 949main (int argc, char *argv[])
1011{ 950{
1012 initialized = GNUNET_NO;
1013 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 };
1014 const char *config_file; 959 const char *config_file;
1015 char port_id[] = "test port"; 960 char port_id[] = "test port";
1016 GNUNET_CRYPTO_hash (port_id, sizeof (port_id), &port); 961 struct GNUNET_GETOPT_CommandLineOption options[] = {
962 GNUNET_GETOPT_option_relative_time ('t',
963 "time",
964 "short_time",
965 gettext_noop ("set short timeout"),
966 &short_time),
967
968 GNUNET_GETOPT_option_uint ('m',
969 "messages",
970 "NUM_MESSAGES",
971 gettext_noop ("set number of messages to send"),
972 &total_packets),
1017 973
974 GNUNET_GETOPT_OPTION_END
975 };
976
977
978 initialized = GNUNET_NO;
1018 GNUNET_log_setup ("test", "DEBUG", NULL); 979 GNUNET_log_setup ("test", "DEBUG", NULL);
1019 config_file = "test_cadet.conf";
1020 980
1021 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);
1022 991
1023 /* Find out requested size */ 992 /* Find out requested size */
1024 if (strstr (argv[0], "_2_") != NULL) 993 if (strstr (argv[0], "_2_") != NULL)
@@ -1056,11 +1025,11 @@ main (int argc, char *argv[])
1056 { 1025 {
1057 /* Test is supposed to generate the following callbacks: 1026 /* Test is supposed to generate the following callbacks:
1058 * 1 incoming channel (@dest) 1027 * 1 incoming channel (@dest)
1059 * TOTAL_PACKETS received data packet (@dest) 1028 * total_packets received data packet (@dest)
1060 * TOTAL_PACKETS received data packet (@orig) 1029 * total_packets received data packet (@orig)
1061 * 1 received channel destroy (@dest) 1030 * 1 received channel destroy (@dest)
1062 */ 1031 */
1063 ok_goal = TOTAL_PACKETS * 2 + 2; 1032 ok_goal = total_packets * 2 + 2;
1064 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SPEED_ACK\n"); 1033 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SPEED_ACK\n");
1065 test = SPEED_ACK; 1034 test = SPEED_ACK;
1066 test_name = "speed ack"; 1035 test_name = "speed ack";
@@ -1070,11 +1039,11 @@ main (int argc, char *argv[])
1070 /* Test is supposed to generate the following callbacks: 1039 /* Test is supposed to generate the following callbacks:
1071 * 1 incoming channel (@dest) 1040 * 1 incoming channel (@dest)
1072 * 1 initial packet (@dest) 1041 * 1 initial packet (@dest)
1073 * TOTAL_PACKETS received data packet (@dest) 1042 * total_packets received data packet (@dest)
1074 * 1 received data packet (@orig) 1043 * 1 received data packet (@orig)
1075 * 1 received channel destroy (@dest) 1044 * 1 received channel destroy (@dest)
1076 */ 1045 */
1077 ok_goal = TOTAL_PACKETS + 4; 1046 ok_goal = total_packets + 4;
1078 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SPEED\n"); 1047 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SPEED\n");
1079 if (strstr (argv[0], "_reliable") != NULL) 1048 if (strstr (argv[0], "_reliable") != NULL)
1080 { 1049 {
@@ -1115,20 +1084,22 @@ main (int argc, char *argv[])
1115 p_ids = 0; 1084 p_ids = 0;
1116 ports[0] = &port; 1085 ports[0] = &port;
1117 ports[1] = NULL; 1086 ports[1] = NULL;
1118 GNUNET_CADET_TEST_run ("test_cadet_small", 1087 GNUNET_CADET_TEST_ruN ("test_cadet_small",
1119 config_file, 1088 config_file,
1120 peers_requested, 1089 peers_requested,
1121 &tmain, 1090 &tmain,
1122 NULL, /* tmain cls */ 1091 NULL, /* tmain cls */
1123 &incoming_channel, 1092 &connect_handler,
1124 &channel_cleaner, 1093 NULL,
1125 handlers, 1094 &disconnect_handler,
1126 ports); 1095 handlers,
1127 1096 ports);
1128 if (ok_goal > ok) 1097 if (NULL != strstr (argv[0], "_reliable"))
1098 msg_dropped = 0; /* dropped should be retransmitted */
1099
1100 if (ok_goal > ok - msg_dropped)
1129 { 1101 {
1130 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1102 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "FAILED! (%d/%d)\n", ok, ok_goal);
1131 "FAILED! (%d/%d)\n", ok, ok_goal);
1132 return 1; 1103 return 1;
1133 } 1104 }
1134 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
new file mode 100644
index 000000000..3089c7fbb
--- /dev/null
+++ b/src/cadet/test_cadet_local_mq.c
@@ -0,0 +1,332 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 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/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
33#define TEST_MESSAGE_TYPE 1
34#define TEST_PORT_ID 1
35
36/**
37 * Test message structure.
38 */
39struct GNUNET_CADET_TestMsg
40{
41 /**
42 * Type: #TEST_MESSAGE_TYPE
43 *
44 * Size: sizeof(struct GNUNET_CADET_TestMsg)
45 */
46 struct GNUNET_MessageHeader header;
47
48 /**
49 * Test payload.
50 */
51 uint64_t payload;
52};
53
54struct GNUNET_TESTING_Peer *me;
55
56static struct GNUNET_CADET_Handle *cadet_peer_1;
57
58static struct GNUNET_CADET_Handle *cadet_peer_2;
59
60static struct GNUNET_CADET_Channel *ch;
61
62static int result = GNUNET_OK;
63
64static int got_data = GNUNET_NO;
65
66static struct GNUNET_SCHEDULER_Task *abort_task;
67
68static struct GNUNET_SCHEDULER_Task *connect_task;
69
70
71/**
72 * Connect to other client and send data
73 *
74 * @param cls Closue (unused).
75 */
76static void
77do_connect (void *cls);
78
79
80/**
81 * Shutdown nicely
82 */
83static void
84do_shutdown (void *cls)
85{
86 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
87 "shutdown\n");
88 if (NULL != abort_task)
89 {
90 GNUNET_SCHEDULER_cancel (abort_task);
91 abort_task = NULL;
92 }
93 if (NULL != ch)
94 {
95 GNUNET_CADET_channel_destroy (ch);
96 ch = NULL;
97 }
98 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
99 "Disconnect client 1\n");
100 if (NULL != cadet_peer_1)
101 {
102 GNUNET_CADET_disconnect (cadet_peer_1);
103 cadet_peer_1 = NULL;
104 }
105 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
106 "Disconnect client 2\n");
107 if (NULL != cadet_peer_2)
108 {
109 GNUNET_CADET_disconnect (cadet_peer_2);
110 cadet_peer_2 = NULL;
111 }
112 if (NULL != connect_task)
113 {
114 GNUNET_SCHEDULER_cancel (connect_task);
115 connect_task = NULL;
116 }
117}
118
119
120/**
121 * Something went wrong and timed out. Kill everything and set error flag
122 */
123static void
124do_abort (void *cls)
125{
126 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ABORT from line %ld\n", (long) cls);
127 result = GNUNET_SYSERR;
128 abort_task = NULL;
129 GNUNET_SCHEDULER_shutdown ();
130}
131
132/**
133 * Method called whenever a peer connects to a port in MQ-based CADET.
134 *
135 * @param cls Closure from #GNUNET_CADET_open_port.
136 * @param channel New handle to the channel.
137 * @param source Peer that started this channel.
138 * @return Closure for the incoming @a channel. It's given to:
139 * - The #GNUNET_CADET_DisconnectEventHandler (given to
140 * #GNUNET_CADET_open_port) when the channel dies.
141 * - Each the #GNUNET_MQ_MessageCallback handlers for each message
142 * received on the @a channel.
143 */
144static void *
145connected (void *cls,
146 struct GNUNET_CADET_Channel *channel,
147 const struct GNUNET_PeerIdentity *source)
148{
149 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
150 "connected %s, cls: %p\n",
151 GNUNET_i2s(source), cls);
152 return channel;
153}
154
155/**
156 * Function called whenever an MQ-channel is destroyed, even if the destruction
157 * was requested by #GNUNET_CADET_channel_destroy.
158 * It must NOT call #GNUNET_CADET_channel_destroy on the channel.
159 *
160 * It should clean up any associated state, including cancelling any pending
161 * transmission on this channel.
162 *
163 * @param cls Channel closure.
164 * @param channel Connection to the other end (henceforth invalid).
165 */
166static void
167disconnected (void *cls,
168 const struct GNUNET_CADET_Channel *channel)
169{
170 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
171 "disconnected channel %p, cls: %p\n",
172 channel, cls);
173 if (channel == ch)
174 ch = NULL;
175}
176
177
178/**
179 * Handle test data
180 *
181 * @param h The cadet handle
182 * @param msg A message with the details of the new incoming channel
183 */
184static void
185handle_data_received (void *cls,
186 const struct GNUNET_CADET_TestMsg *msg)
187{
188 uint64_t payload;
189
190 payload = GNUNET_ntohll (msg->payload);
191 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
192 "Data callback payload %llu with cls: %p! Shutting down.\n",
193 (unsigned long long) payload,
194 cls);
195 GNUNET_assert (42 == payload);
196 got_data = GNUNET_YES;
197 GNUNET_SCHEDULER_shutdown ();
198}
199
200
201/**
202 * Signature of the main function of a task.
203 *
204 * @param cls Closure (unused).
205 */
206static void
207message_sent (void *cls)
208{
209 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "message sent\n");
210}
211
212
213/**
214 * Connect to other client and send data
215 *
216 * @param cls Closure (unused).
217 */
218static void
219do_connect (void *cls)
220{
221 struct GNUNET_PeerIdentity id;
222 struct GNUNET_MQ_Handle *mq;
223 struct GNUNET_MQ_Envelope *env;
224 struct GNUNET_CADET_TestMsg *msg;
225
226 struct GNUNET_MQ_MessageHandler handlers[] = {
227 GNUNET_MQ_hd_fixed_size (data_received,
228 TEST_MESSAGE_TYPE,
229 struct GNUNET_CADET_TestMsg,
230 cadet_peer_1),
231 GNUNET_MQ_handler_end ()
232 };
233
234 connect_task = NULL;
235 GNUNET_TESTING_peer_get_identity (me, &id);
236 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
237 "creating channel\n");
238 ch = GNUNET_CADET_channel_create (cadet_peer_1, /* cadet handle */
239 NULL, /* channel cls */
240 &id, /* destination */
241 GC_u2h (TEST_MESSAGE_TYPE), /* port */
242 GNUNET_CADET_OPTION_DEFAULT, /* opt */
243 NULL, /* window change */
244 &disconnected, /* disconnect handler */
245 handlers /* traffic handlers */
246 );
247 env = GNUNET_MQ_msg (msg, TEST_MESSAGE_TYPE);
248 msg->payload = GNUNET_htonll (42);
249 mq = GNUNET_CADET_get_mq (ch);
250 GNUNET_MQ_notify_sent (env, &message_sent, NULL);
251 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
252 "sending message\n");
253 GNUNET_MQ_send (mq, env);
254}
255
256
257/**
258 * Initialize framework and start test
259 *
260 * @param cls Closure (unused).
261 * @param cfg Configuration handle.
262 * @param peer Testing peer handle.
263 */
264static void
265run (void *cls,
266 const struct GNUNET_CONFIGURATION_Handle *cfg,
267 struct GNUNET_TESTING_Peer *peer)
268{
269 struct GNUNET_MQ_MessageHandler handlers[] = {
270 GNUNET_MQ_hd_fixed_size (data_received,
271 TEST_MESSAGE_TYPE,
272 struct GNUNET_CADET_TestMsg,
273 cadet_peer_2),
274 GNUNET_MQ_handler_end ()
275 };
276 struct GNUNET_TIME_Relative delay;
277
278 me = peer;
279 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
280 NULL);
281 delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15);
282 abort_task = GNUNET_SCHEDULER_add_delayed (delay,
283 &do_abort,
284 (void *) (long) __LINE__);
285 cadet_peer_1 = GNUNET_CADET_connect (cfg);
286 cadet_peer_2 = GNUNET_CADET_connect (cfg);
287
288 if ( (NULL == cadet_peer_1) ||
289 (NULL == cadet_peer_2) )
290 {
291 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
292 "Couldn't connect to cadet\n");
293 result = GNUNET_SYSERR;
294 GNUNET_SCHEDULER_shutdown ();
295 return;
296 }
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);
299 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "handlers 2: %p\n", handlers);
300 GNUNET_CADET_open_port (cadet_peer_2, /* cadet handle */
301 GC_u2h (TEST_PORT_ID), /* port id */
302 &connected, /* connect handler */
303 (void *) 2L, /* handle for #connected */
304 NULL, /* window size handler */
305 &disconnected, /* disconnect handler */
306 handlers); /* traffic handlers */
307 delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2);
308 if (NULL == connect_task)
309 connect_task = GNUNET_SCHEDULER_add_delayed (delay,
310 &do_connect,
311 NULL);
312}
313
314
315/**
316 * Main
317 */
318int
319main (int argc, char *argv[])
320{
321 if (0 != GNUNET_TESTING_peer_run ("test-cadet-local",
322 "test_cadet.conf",
323 &run, NULL))
324 {
325 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "run failed\n");
326 return 2;
327 }
328 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Final result: %d\n", result);
329 return (result == GNUNET_OK) ? 0 : 1;
330}
331
332/* end of test_cadet_local_1.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/.gitignore b/src/consensus/.gitignore
index 8bb7caafe..d49147d17 100644
--- a/src/consensus/.gitignore
+++ b/src/consensus/.gitignore
@@ -1,3 +1,5 @@
1gnunet-service-evil-consensus 1gnunet-service-evil-consensus
2gnunet-consensus-profiler 2gnunet-consensus-profiler
3gnunet-service-consensus 3gnunet-service-consensus
4test_consensus_api
5resource.log.master
diff --git a/src/consensus/Makefile.am b/src/consensus/Makefile.am
index c63434f94..c0205ee5d 100644
--- a/src/consensus/Makefile.am
+++ b/src/consensus/Makefile.am
@@ -5,6 +5,8 @@ pkgcfgdir= $(pkgdatadir)/config.d/
5 5
6libexecdir= $(pkglibdir)/libexec/ 6libexecdir= $(pkglibdir)/libexec/
7 7
8plugindir = $(libdir)/gnunet
9
8pkgcfg_DATA = \ 10pkgcfg_DATA = \
9 consensus.conf 11 consensus.conf
10 12
@@ -16,8 +18,6 @@ if USE_COVERAGE
16 AM_CFLAGS = -fprofile-arcs -ftest-coverage 18 AM_CFLAGS = -fprofile-arcs -ftest-coverage
17endif 19endif
18 20
19bin_PROGRAMS = \
20 gnunet-consensus-profiler
21 21
22libexec_PROGRAMS = \ 22libexec_PROGRAMS = \
23 gnunet-service-consensus 23 gnunet-service-consensus
@@ -67,13 +67,34 @@ libgnunetconsensus_la_LIBADD = \
67libgnunetconsensus_la_LDFLAGS = \ 67libgnunetconsensus_la_LDFLAGS = \
68 $(GN_LIB_LDFLAGS) 68 $(GN_LIB_LDFLAGS)
69 69
70
71plugin_LTLIBRARIES = \
72 libgnunet_plugin_block_consensus.la
73
74libgnunet_plugin_block_consensus_la_SOURCES = \
75 plugin_block_consensus.c
76libgnunet_plugin_block_consensus_la_LIBADD = \
77 $(top_builddir)/src/block/libgnunetblock.la \
78 $(top_builddir)/src/block/libgnunetblockgroup.la \
79 $(top_builddir)/src/util/libgnunetutil.la \
80 $(LTLIBINTL)
81libgnunet_plugin_block_consensus_la_LDFLAGS = \
82 $(GN_PLUGIN_LDFLAGS)
83
84
85
86if HAVE_TESTING
87bin_PROGRAMS = \
88 gnunet-consensus-profiler
89
70check_PROGRAMS = \ 90check_PROGRAMS = \
71 test_consensus_api 91 test_consensus_api
72 92
73if ENABLE_TEST_RUN 93if ENABLE_TEST_RUN
74AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; 94AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
75TESTS = $(check_PROGRAMS) 95TESTS = $(check_PROGRAMS)
76endif 96endif
97endif
77 98
78test_consensus_api_SOURCES = \ 99test_consensus_api_SOURCES = \
79 test_consensus_api.c 100 test_consensus_api.c
diff --git a/src/consensus/consensus_protocol.h b/src/consensus/consensus_protocol.h
index fb3bde628..f2933ed6f 100644
--- a/src/consensus/consensus_protocol.h
+++ b/src/consensus/consensus_protocol.h
@@ -29,6 +29,7 @@
29#define GNUNET_CONSENSUS_PROTOCOL_H 29#define GNUNET_CONSENSUS_PROTOCOL_H
30 30
31#include "platform.h" 31#include "platform.h"
32#include "gnunet_util_lib.h"
32#include "gnunet_common.h" 33#include "gnunet_common.h"
33#include "gnunet_protocols.h" 34#include "gnunet_protocols.h"
34 35
@@ -44,37 +45,37 @@ GNUNET_NETWORK_STRUCT_BEGIN
44struct GNUNET_CONSENSUS_RoundContextMessage 45struct GNUNET_CONSENSUS_RoundContextMessage
45{ 46{
46 /** 47 /**
47 * Type: GNUNET_MESSAGE_TYPE_CONSENSUS_P2P_ROUND_CONTEXT 48 * Type: #GNUNET_MESSAGE_TYPE_CONSENSUS_P2P_ROUND_CONTEXT
48 */ 49 */
49 struct GNUNET_MessageHeader header; 50 struct GNUNET_MessageHeader header;
50 51
51 /** 52 /**
52 * A value from 'enum PhaseKind'. 53 * A value from 'enum PhaseKind'.
53 */ 54 */
54 uint16_t kind; 55 uint16_t kind GNUNET_PACKED;
55 56
56 /** 57 /**
57 * Number of the first peer 58 * Number of the first peer
58 * in canonical order. 59 * in canonical order.
59 */ 60 */
60 int16_t peer1; 61 int16_t peer1 GNUNET_PACKED;
61 62
62 /** 63 /**
63 * Number of the second peer in canonical order. 64 * Number of the second peer in canonical order.
64 */ 65 */
65 int16_t peer2; 66 int16_t peer2 GNUNET_PACKED;
66 67
67 /** 68 /**
68 * Repetition of the gradecast phase. 69 * Repetition of the gradecast phase.
69 */ 70 */
70 int16_t repetition; 71 int16_t repetition GNUNET_PACKED;
71 72
72 /** 73 /**
73 * Leader in the gradecast phase. 74 * Leader in the gradecast phase.
74 * 75 *
75 * Can be different from both peer1 and peer2. 76 * Can be different from both peer1 and peer2.
76 */ 77 */
77 int16_t leader; 78 int16_t leader GNUNET_PACKED;
78 79
79 /** 80 /**
80 * Non-zero if this set reconciliation 81 * Non-zero if this set reconciliation
@@ -84,9 +85,51 @@ struct GNUNET_CONSENSUS_RoundContextMessage
84 * 85 *
85 * Ignored for set operations that are not within gradecasts. 86 * Ignored for set operations that are not within gradecasts.
86 */ 87 */
87 uint16_t is_contested; 88 uint16_t is_contested GNUNET_PACKED;
88}; 89};
89 90
91
92enum {
93 CONSENSUS_MARKER_CONTESTED = 1,
94 CONSENSUS_MARKER_SIZE = 2,
95};
96
97
98/**
99 * Consensus element, either marker or payload.
100 */
101struct ConsensusElement
102{
103 /**
104 * Payload element_type, only valid
105 * if this is not a marker element.
106 */
107 uint16_t payload_type GNUNET_PACKED;
108
109 /**
110 * Is this a marker element?
111 */
112 uint8_t marker;
113
114 /* rest: element data */
115};
116
117
118struct ConsensusSizeElement
119{
120 struct ConsensusElement ce;
121
122 uint64_t size GNUNET_PACKED;
123 uint8_t sender_index;
124};
125
126struct ConsensusStuffedElement
127{
128 struct ConsensusElement ce;
129 struct GNUNET_HashCode rand GNUNET_PACKED;
130};
131
132
90GNUNET_NETWORK_STRUCT_END 133GNUNET_NETWORK_STRUCT_END
91 134
92#endif 135#endif
diff --git a/src/consensus/gnunet-consensus-profiler.c b/src/consensus/gnunet-consensus-profiler.c
index 290263d95..68c2ad594 100644
--- a/src/consensus/gnunet-consensus-profiler.c
+++ b/src/consensus/gnunet-consensus-profiler.c
@@ -55,6 +55,8 @@ static struct GNUNET_HashCode session_id;
55 55
56static unsigned int peers_done = 0; 56static unsigned int peers_done = 0;
57 57
58static int dist_static;
59
58static unsigned *results_for_peer; 60static unsigned *results_for_peer;
59 61
60/** 62/**
@@ -217,26 +219,45 @@ do_consensus ()
217{ 219{
218 int unique_indices[replication]; 220 int unique_indices[replication];
219 unsigned int i; 221 unsigned int i;
222 unsigned int j;
223 struct GNUNET_HashCode val;
224 struct GNUNET_SET_Element element;
220 225
221 for (i = 0; i < num_values; i++) 226 if (dist_static)
222 { 227 {
223 unsigned int j; 228 for (i = 0; i < num_values; i++)
224 struct GNUNET_HashCode val; 229 {
225 struct GNUNET_SET_Element element;
226 230
227 generate_indices (unique_indices); 231 GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, &val);
228 GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, &val);
229 232
230 element.data = &val; 233 element.data = &val;
231 element.size = sizeof (val); 234 element.size = sizeof (val);
232 for (j = 0; j < replication; j++) 235 for (j = 0; j < replication; j++)
236 {
237 GNUNET_CONSENSUS_insert (consensus_handles[j],
238 &element,
239 NULL, NULL);
240 }
241 }
242 }
243 else
244 {
245 for (i = 0; i < num_values; i++)
233 { 246 {
234 int cid; 247 generate_indices (unique_indices);
248 GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, &val);
249
250 element.data = &val;
251 element.size = sizeof (val);
252 for (j = 0; j < replication; j++)
253 {
254 int cid;
235 255
236 cid = unique_indices[j]; 256 cid = unique_indices[j];
237 GNUNET_CONSENSUS_insert (consensus_handles[cid], 257 GNUNET_CONSENSUS_insert (consensus_handles[cid],
238 &element, 258 &element,
239 NULL, NULL); 259 NULL, NULL);
260 }
240 } 261 }
241 } 262 }
242 263
@@ -494,28 +515,55 @@ run (void *cls, char *const *args, const char *cfgfile,
494int 515int
495main (int argc, char **argv) 516main (int argc, char **argv)
496{ 517{
497 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 518 struct GNUNET_GETOPT_CommandLineOption options[] = {
498 { 'n', "num-peers", NULL, 519
499 gettext_noop ("number of peers in consensus"), 520 GNUNET_GETOPT_option_uint ('n',
500 GNUNET_YES, &GNUNET_GETOPT_set_uint, &num_peers }, 521 "num-peers",
501 { 'k', "value-replication", NULL, 522 NULL,
502 gettext_noop ("how many peers (random selection without replacement) receive one value?"), 523 gettext_noop ("number of peers in consensus"),
503 GNUNET_YES, &GNUNET_GETOPT_set_uint, &replication }, 524 &num_peers),
504 { 'x', "num-values", NULL, 525
505 gettext_noop ("number of values"), 526 GNUNET_GETOPT_option_uint ('k',
506 GNUNET_YES, &GNUNET_GETOPT_set_uint, &num_values }, 527 "value-replication",
507 { 't', "timeout", NULL, 528 NULL,
508 gettext_noop ("consensus timeout"), 529 gettext_noop ("how many peers (random selection without replacement) receive one value?"),
509 GNUNET_YES, &GNUNET_GETOPT_set_relative_time, &conclude_timeout }, 530 &replication),
510 { 'd', "delay", NULL, 531
511 gettext_noop ("delay until consensus starts"), 532 GNUNET_GETOPT_option_uint ('x',
512 GNUNET_YES, &GNUNET_GETOPT_set_relative_time, &consensus_delay }, 533 "num-values",
513 { 's', "statistics", NULL, 534 NULL,
514 gettext_noop ("write statistics to file"), 535 gettext_noop ("number of values"),
515 GNUNET_YES, &GNUNET_GETOPT_set_filename, &statistics_filename }, 536 &num_values),
516 { 'V', "verbose", NULL, 537
517 gettext_noop ("be more verbose (print received values)"), 538 GNUNET_GETOPT_option_relative_time ('t',
518 GNUNET_NO, &GNUNET_GETOPT_set_one, &verbose }, 539 "timeout",
540 NULL,
541 gettext_noop ("consensus timeout"),
542 &conclude_timeout),
543
544
545 GNUNET_GETOPT_option_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_flag ('S',
558 "dist-static",
559 gettext_noop ("distribute elements to a static subset of good peers"),
560 &dist_static),
561
562 GNUNET_GETOPT_option_flag ('V',
563 "verbose",
564 gettext_noop ("be more verbose (print received values)"),
565 &verbose),
566
519 GNUNET_GETOPT_OPTION_END 567 GNUNET_GETOPT_OPTION_END
520 }; 568 };
521 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 64decc29e..4af7199aa 100644
--- a/src/consensus/gnunet-service-consensus.c
+++ b/src/consensus/gnunet-service-consensus.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, 2013 GNUnet e.V. 3 Copyright (C) 2012, 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
@@ -26,6 +26,7 @@
26 26
27#include "platform.h" 27#include "platform.h"
28#include "gnunet_util_lib.h" 28#include "gnunet_util_lib.h"
29#include "gnunet_block_lib.h"
29#include "gnunet_protocols.h" 30#include "gnunet_protocols.h"
30#include "gnunet_applications.h" 31#include "gnunet_applications.h"
31#include "gnunet_set_service.h" 32#include "gnunet_set_service.h"
@@ -34,8 +35,6 @@
34#include "consensus_protocol.h" 35#include "consensus_protocol.h"
35#include "consensus.h" 36#include "consensus.h"
36 37
37#define ELEMENT_TYPE_CONTESTED_MARKER (GNUNET_CONSENSUS_ELEMENT_TYPE_USER_MAX + 1)
38
39 38
40enum ReferendumVote 39enum ReferendumVote
41{ 40{
@@ -65,11 +64,6 @@ enum EarlyStoppingPhase
65 64
66GNUNET_NETWORK_STRUCT_BEGIN 65GNUNET_NETWORK_STRUCT_BEGIN
67 66
68
69struct ContestedPayload
70{
71};
72
73/** 67/**
74 * Tuple of integers that together 68 * Tuple of integers that together
75 * identify a task uniquely. 69 * identify a task uniquely.
@@ -147,6 +141,7 @@ GNUNET_NETWORK_STRUCT_END
147enum PhaseKind 141enum PhaseKind
148{ 142{
149 PHASE_KIND_ALL_TO_ALL, 143 PHASE_KIND_ALL_TO_ALL,
144 PHASE_KIND_ALL_TO_ALL_2,
150 PHASE_KIND_GRADECAST_LEADER, 145 PHASE_KIND_GRADECAST_LEADER,
151 PHASE_KIND_GRADECAST_ECHO, 146 PHASE_KIND_GRADECAST_ECHO,
152 PHASE_KIND_GRADECAST_ECHO_GRADE, 147 PHASE_KIND_GRADECAST_ECHO_GRADE,
@@ -398,6 +393,14 @@ struct DiffEntry
398 struct GNUNET_CONTAINER_MultiHashMap *changes; 393 struct GNUNET_CONTAINER_MultiHashMap *changes;
399}; 394};
400 395
396struct SetHandle
397{
398 struct SetHandle *prev;
399 struct SetHandle *next;
400
401 struct GNUNET_SET_Handle *h;
402};
403
401 404
402 405
403/** 406/**
@@ -451,7 +454,7 @@ struct ConsensusSession
451 /** 454 /**
452 * Client that inhabits the session 455 * Client that inhabits the session
453 */ 456 */
454 struct GNUNET_SERVER_Client *client; 457 struct GNUNET_SERVICE_Client *client;
455 458
456 /** 459 /**
457 * Queued messages to the client. 460 * Queued messages to the client.
@@ -492,6 +495,21 @@ struct ConsensusSession
492 * State of our early stopping scheme. 495 * State of our early stopping scheme.
493 */ 496 */
494 int early_stopping; 497 int early_stopping;
498
499 /**
500 * Our set size from the first round.
501 */
502 uint64_t first_size;
503
504 uint64_t *first_sizes_received;
505
506 /**
507 * Bounded Eppstein lower bound.
508 */
509 uint64_t lower_bound;
510
511 struct SetHandle *set_handles_head;
512 struct SetHandle *set_handles_tail;
495}; 513};
496 514
497/** 515/**
@@ -510,11 +528,6 @@ static struct ConsensusSession *sessions_tail;
510static const struct GNUNET_CONFIGURATION_Handle *cfg; 528static const struct GNUNET_CONFIGURATION_Handle *cfg;
511 529
512/** 530/**
513 * Handle to the server for this service.
514 */
515static struct GNUNET_SERVER_Handle *srv;
516
517/**
518 * Peer that runs this service. 531 * Peer that runs this service.
519 */ 532 */
520static struct GNUNET_PeerIdentity my_peer; 533static struct GNUNET_PeerIdentity my_peer;
@@ -528,15 +541,18 @@ struct GNUNET_STATISTICS_Handle *statistics;
528static void 541static void
529finish_task (struct TaskEntry *task); 542finish_task (struct TaskEntry *task);
530 543
544
531static void 545static void
532run_ready_steps (struct ConsensusSession *session); 546run_ready_steps (struct ConsensusSession *session);
533 547
548
534static const char * 549static const char *
535phasename (uint16_t phase) 550phasename (uint16_t phase)
536{ 551{
537 switch (phase) 552 switch (phase)
538 { 553 {
539 case PHASE_KIND_ALL_TO_ALL: return "ALL_TO_ALL"; 554 case PHASE_KIND_ALL_TO_ALL: return "ALL_TO_ALL";
555 case PHASE_KIND_ALL_TO_ALL_2: return "ALL_TO_ALL_2";
540 case PHASE_KIND_FINISH: return "FINISH"; 556 case PHASE_KIND_FINISH: return "FINISH";
541 case PHASE_KIND_GRADECAST_LEADER: return "GRADECAST_LEADER"; 557 case PHASE_KIND_GRADECAST_LEADER: return "GRADECAST_LEADER";
542 case PHASE_KIND_GRADECAST_ECHO: return "GRADECAST_ECHO"; 558 case PHASE_KIND_GRADECAST_ECHO: return "GRADECAST_ECHO";
@@ -653,36 +669,6 @@ debug_str_rfn_key (const struct RfnKey *rk)
653 669
654 670
655/** 671/**
656 * Destroy a session, free all resources associated with it.
657 *
658 * @param session the session to destroy
659 */
660static void
661destroy_session (struct ConsensusSession *session)
662{
663 GNUNET_CONTAINER_DLL_remove (sessions_head, sessions_tail, session);
664 if (NULL != session->set_listener)
665 {
666 GNUNET_SET_listen_cancel (session->set_listener);
667 session->set_listener = NULL;
668 }
669 if (NULL != session->client_mq)
670 {
671 GNUNET_MQ_destroy (session->client_mq);
672 session->client_mq = NULL;
673 /* The MQ cleanup will also disconnect the underlying client. */
674 session->client = NULL;
675 }
676 if (NULL != session->client)
677 {
678 GNUNET_SERVER_client_disconnect (session->client);
679 session->client = NULL;
680 }
681 GNUNET_free (session);
682}
683
684
685/**
686 * Send the final result set of the consensus to the client, element by 672 * Send the final result set of the consensus to the client, element by
687 * element. 673 * element.
688 * 674 *
@@ -702,16 +688,25 @@ send_to_client_iter (void *cls,
702 if (NULL != element) 688 if (NULL != element)
703 { 689 {
704 struct GNUNET_CONSENSUS_ElementMessage *m; 690 struct GNUNET_CONSENSUS_ElementMessage *m;
691 const struct ConsensusElement *ce;
692
693 GNUNET_assert (GNUNET_BLOCK_TYPE_CONSENSUS_ELEMENT == element->element_type);
694 ce = element->data;
695
696 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "marker is %u\n", (unsigned) ce->marker);
697
698 if (0 != ce->marker)
699 return GNUNET_YES;
705 700
706 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 701 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
707 "P%d: sending element %s to client\n", 702 "P%d: sending element %s to client\n",
708 session->local_peer_idx, 703 session->local_peer_idx,
709 debug_str_element (element)); 704 debug_str_element (element));
710 705
711 ev = GNUNET_MQ_msg_extra (m, element->size, 706 ev = GNUNET_MQ_msg_extra (m, element->size - sizeof (struct ConsensusElement),
712 GNUNET_MESSAGE_TYPE_CONSENSUS_CLIENT_RECEIVED_ELEMENT); 707 GNUNET_MESSAGE_TYPE_CONSENSUS_CLIENT_RECEIVED_ELEMENT);
713 m->element_type = htons (element->element_type); 708 m->element_type = ce->payload_type;
714 GNUNET_memcpy (&m[1], element->data, element->size); 709 GNUNET_memcpy (&m[1], &ce[1], element->size - sizeof (struct ConsensusElement));
715 GNUNET_MQ_send (session->client_mq, ev); 710 GNUNET_MQ_send (session->client_mq, ev);
716 } 711 }
717 else 712 else
@@ -881,7 +876,7 @@ rfn_vote (struct ReferendumEntry *rfn,
881} 876}
882 877
883 878
884uint16_t 879static uint16_t
885task_other_peer (struct TaskEntry *task) 880task_other_peer (struct TaskEntry *task)
886{ 881{
887 uint16_t me = task->step->session->local_peer_idx; 882 uint16_t me = task->step->session->local_peer_idx;
@@ -891,17 +886,33 @@ task_other_peer (struct TaskEntry *task)
891} 886}
892 887
893 888
889static int
890cmp_uint64_t (const void *pa, const void *pb)
891{
892 uint64_t a = *(uint64_t *) pa;
893 uint64_t b = *(uint64_t *) pb;
894
895 if (a == b)
896 return 0;
897 if (a < b)
898 return -1;
899 return 1;
900}
901
902
894/** 903/**
895 * Callback for set operation results. Called for each element 904 * Callback for set operation results. Called for each element
896 * in the result set. 905 * in the result set.
897 * 906 *
898 * @param cls closure 907 * @param cls closure
899 * @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
909 * @param current_size current set size
900 * @param status see enum GNUNET_SET_Status 910 * @param status see enum GNUNET_SET_Status
901 */ 911 */
902static void 912static void
903set_result_cb (void *cls, 913set_result_cb (void *cls,
904 const struct GNUNET_SET_Element *element, 914 const struct GNUNET_SET_Element *element,
915 uint64_t current_size,
905 enum GNUNET_SET_Status status) 916 enum GNUNET_SET_Status status)
906{ 917{
907 struct TaskEntry *task = cls; 918 struct TaskEntry *task = cls;
@@ -911,6 +922,18 @@ set_result_cb (void *cls,
911 struct ReferendumEntry *output_rfn = NULL; 922 struct ReferendumEntry *output_rfn = NULL;
912 unsigned int other_idx; 923 unsigned int other_idx;
913 struct SetOpCls *setop; 924 struct SetOpCls *setop;
925 const struct ConsensusElement *consensus_element = NULL;
926
927 if (NULL != element)
928 {
929 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
930 "P%u: got element of type %u, status %u\n",
931 session->local_peer_idx,
932 (unsigned) element->element_type,
933 (unsigned) status);
934 GNUNET_assert (GNUNET_BLOCK_TYPE_CONSENSUS_ELEMENT == element->element_type);
935 consensus_element = element->data;
936 }
914 937
915 setop = &task->cls.setop; 938 setop = &task->cls.setop;
916 939
@@ -963,19 +986,54 @@ set_result_cb (void *cls,
963 return; 986 return;
964 } 987 }
965 988
966 if ( (GNUNET_SET_STATUS_ADD_LOCAL == status) || (GNUNET_SET_STATUS_ADD_REMOTE == status) ) 989 if ( (NULL != consensus_element) && (0 != consensus_element->marker) )
967 { 990 {
968 if ( (GNUNET_YES == setop->transceive_contested) && (ELEMENT_TYPE_CONTESTED_MARKER == element->element_type) ) 991 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
992 "P%u: got some marker\n",
993 session->local_peer_idx);
994 if ( (GNUNET_YES == setop->transceive_contested) &&
995 (CONSENSUS_MARKER_CONTESTED == consensus_element->marker) )
969 { 996 {
970 GNUNET_assert (NULL != output_rfn); 997 GNUNET_assert (NULL != output_rfn);
971 rfn_contest (output_rfn, task_other_peer (task)); 998 rfn_contest (output_rfn, task_other_peer (task));
972 return; 999 return;
973 } 1000 }
1001
1002 if (CONSENSUS_MARKER_SIZE == consensus_element->marker)
1003 {
1004
1005 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1006 "P%u: got size marker\n",
1007 session->local_peer_idx);
1008
1009
1010 struct ConsensusSizeElement *cse = (void *) consensus_element;
1011
1012 if (cse->sender_index == other_idx)
1013 {
1014 if (NULL == session->first_sizes_received)
1015 session->first_sizes_received = GNUNET_new_array (session->num_peers, uint64_t);
1016 session->first_sizes_received[other_idx] = GNUNET_ntohll (cse->size);
1017
1018 uint64_t *copy = GNUNET_memdup (session->first_sizes_received, sizeof (uint64_t) * session->num_peers);
1019 qsort (copy, session->num_peers, sizeof (uint64_t), cmp_uint64_t);
1020 session->lower_bound = copy[session->num_peers / 3 + 1];
1021 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1022 "P%u: lower bound %llu\n",
1023 session->local_peer_idx,
1024 (long long) session->lower_bound);
1025 GNUNET_free (copy);
1026 }
1027 return;
1028 }
1029
1030 return;
974 } 1031 }
975 1032
976 switch (status) 1033 switch (status)
977 { 1034 {
978 case GNUNET_SET_STATUS_ADD_LOCAL: 1035 case GNUNET_SET_STATUS_ADD_LOCAL:
1036 GNUNET_assert (NULL != consensus_element);
979 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1037 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
980 "Adding element in Task {%s}\n", 1038 "Adding element in Task {%s}\n",
981 debug_str_task_key (&task->key)); 1039 debug_str_task_key (&task->key));
@@ -1022,9 +1080,10 @@ set_result_cb (void *cls,
1022 // XXX: add result to structures in task 1080 // XXX: add result to structures in task
1023 break; 1081 break;
1024 case GNUNET_SET_STATUS_ADD_REMOTE: 1082 case GNUNET_SET_STATUS_ADD_REMOTE:
1083 GNUNET_assert (NULL != consensus_element);
1025 if (GNUNET_YES == setop->do_not_remove) 1084 if (GNUNET_YES == setop->do_not_remove)
1026 break; 1085 break;
1027 if (ELEMENT_TYPE_CONTESTED_MARKER == element->element_type) 1086 if (CONSENSUS_MARKER_CONTESTED == consensus_element->marker)
1028 break; 1087 break;
1029 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1088 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1030 "Removing element in Task {%s}\n", 1089 "Removing element in Task {%s}\n",
@@ -1080,6 +1139,10 @@ set_result_cb (void *cls,
1080 { 1139 {
1081 rfn_commit (output_rfn, task_other_peer (task)); 1140 rfn_commit (output_rfn, task_other_peer (task));
1082 } 1141 }
1142 if (PHASE_KIND_ALL_TO_ALL == task->key.kind)
1143 {
1144 session->first_size = current_size;
1145 }
1083 finish_task (task); 1146 finish_task (task);
1084 break; 1147 break;
1085 case GNUNET_SET_STATUS_FAILURE: 1148 case GNUNET_SET_STATUS_FAILURE:
@@ -1102,6 +1165,7 @@ enum EvilnessType
1102 EVILNESS_CRAM_LEAD, 1165 EVILNESS_CRAM_LEAD,
1103 EVILNESS_CRAM_ECHO, 1166 EVILNESS_CRAM_ECHO,
1104 EVILNESS_SLACK, 1167 EVILNESS_SLACK,
1168 EVILNESS_SLACK_A2A,
1105}; 1169};
1106 1170
1107enum EvilnessSubType 1171enum EvilnessSubType
@@ -1194,6 +1258,10 @@ get_evilness (struct ConsensusSession *session, struct Evilness *evil)
1194 { 1258 {
1195 evil->type = EVILNESS_SLACK; 1259 evil->type = EVILNESS_SLACK;
1196 } 1260 }
1261 if (0 == strcmp ("slack-a2a", evil_type_str))
1262 {
1263 evil->type = EVILNESS_SLACK_A2A;
1264 }
1197 else if (0 == strcmp ("cram-all", evil_type_str)) 1265 else if (0 == strcmp ("cram-all", evil_type_str))
1198 { 1266 {
1199 evil->type = EVILNESS_CRAM_ALL; 1267 evil->type = EVILNESS_CRAM_ALL;
@@ -1259,6 +1327,34 @@ commit_set (struct ConsensusSession *session,
1259 set = lookup_set (session, &setop->input_set); 1327 set = lookup_set (session, &setop->input_set);
1260 GNUNET_assert (NULL != set); 1328 GNUNET_assert (NULL != set);
1261 1329
1330 if ( (GNUNET_YES == setop->transceive_contested) && (GNUNET_YES == set->is_contested) )
1331 {
1332 struct GNUNET_SET_Element element;
1333 struct ConsensusElement ce = { 0 };
1334 ce.marker = CONSENSUS_MARKER_CONTESTED;
1335 element.data = &ce;
1336 element.size = sizeof (struct ConsensusElement);
1337 element.element_type = GNUNET_BLOCK_TYPE_CONSENSUS_ELEMENT;
1338 GNUNET_SET_add_element (set->h, &element, NULL, NULL);
1339 }
1340
1341 if (PHASE_KIND_ALL_TO_ALL_2 == task->key.kind)
1342 {
1343 struct GNUNET_SET_Element element;
1344 struct ConsensusSizeElement cse = {
1345 .size = 0,
1346 .sender_index = 0
1347 };
1348 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "inserting size marker\n");
1349 cse.ce.marker = CONSENSUS_MARKER_SIZE;
1350 cse.size = GNUNET_htonll (session->first_size);
1351 cse.sender_index = session->local_peer_idx;
1352 element.data = &cse;
1353 element.size = sizeof (struct ConsensusSizeElement);
1354 element.element_type = GNUNET_BLOCK_TYPE_CONSENSUS_ELEMENT;
1355 GNUNET_SET_add_element (set->h, &element, NULL, NULL);
1356 }
1357
1262#ifdef EVIL 1358#ifdef EVIL
1263 { 1359 {
1264 unsigned int i; 1360 unsigned int i;
@@ -1300,21 +1396,24 @@ commit_set (struct ConsensusSession *session,
1300 } 1396 }
1301 for (i = 0; i < evil.num; i++) 1397 for (i = 0; i < evil.num; i++)
1302 { 1398 {
1303 struct GNUNET_HashCode hash;
1304 struct GNUNET_SET_Element element; 1399 struct GNUNET_SET_Element element;
1305 element.data = &hash; 1400 struct ConsensusStuffedElement se = {
1306 element.size = sizeof (struct GNUNET_HashCode); 1401 .ce.payload_type = 0,
1307 element.element_type = 0; 1402 .ce.marker = 0,
1403 };
1404 element.data = &se;
1405 element.size = sizeof (struct ConsensusStuffedElement);
1406 element.element_type = GNUNET_BLOCK_TYPE_CONSENSUS_ELEMENT;
1308 1407
1309 if (EVILNESS_SUB_REPLACEMENT == evil.subtype) 1408 if (EVILNESS_SUB_REPLACEMENT == evil.subtype)
1310 { 1409 {
1311 /* Always generate a new element. */ 1410 /* Always generate a new element. */
1312 GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, &hash); 1411 GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, &se.rand);
1313 } 1412 }
1314 else if (EVILNESS_SUB_NO_REPLACEMENT == evil.subtype) 1413 else if (EVILNESS_SUB_NO_REPLACEMENT == evil.subtype)
1315 { 1414 {
1316 /* Always cram the same elements, derived from counter. */ 1415 /* Always cram the same elements, derived from counter. */
1317 GNUNET_CRYPTO_hash (&i, sizeof (i), &hash); 1416 GNUNET_CRYPTO_hash (&i, sizeof (i), &se.rand);
1318 } 1417 }
1319 else 1418 else
1320 { 1419 {
@@ -1341,6 +1440,19 @@ commit_set (struct ConsensusSession *session,
1341 "P%u: evil peer: slacking\n", 1440 "P%u: evil peer: slacking\n",
1342 (unsigned int) session->local_peer_idx); 1441 (unsigned int) session->local_peer_idx);
1343 /* Do nothing. */ 1442 /* Do nothing. */
1443 case EVILNESS_SLACK_A2A:
1444 if ( (PHASE_KIND_ALL_TO_ALL_2 == task->key.kind ) ||
1445 (PHASE_KIND_ALL_TO_ALL == task->key.kind) )
1446 {
1447 struct GNUNET_SET_Handle *empty_set;
1448 empty_set = GNUNET_SET_create (cfg, GNUNET_SET_OPERATION_UNION);
1449 GNUNET_SET_commit (setop->op, empty_set);
1450 GNUNET_SET_destroy (empty_set);
1451 }
1452 else
1453 {
1454 GNUNET_SET_commit (setop->op, set->h);
1455 }
1344 break; 1456 break;
1345 case EVILNESS_NONE: 1457 case EVILNESS_NONE:
1346 GNUNET_SET_commit (setop->op, set->h); 1458 GNUNET_SET_commit (setop->op, set->h);
@@ -1348,15 +1460,6 @@ commit_set (struct ConsensusSession *session,
1348 } 1460 }
1349 } 1461 }
1350#else 1462#else
1351 if ( (GNUNET_YES == setop->transceive_contested) && (GNUNET_YES == set->is_contested) )
1352 {
1353 struct GNUNET_SET_Element element;
1354 struct ContestedPayload payload;
1355 element.data = &payload;
1356 element.size = sizeof (struct ContestedPayload);
1357 element.element_type = ELEMENT_TYPE_CONTESTED_MARKER;
1358 GNUNET_SET_add_element (set->h, &element, NULL, NULL);
1359 }
1360 if (GNUNET_NO == session->peers_blacklisted[task_other_peer (task)]) 1463 if (GNUNET_NO == session->peers_blacklisted[task_other_peer (task)])
1361 { 1464 {
1362 GNUNET_SET_commit (setop->op, set->h); 1465 GNUNET_SET_commit (setop->op, set->h);
@@ -1511,12 +1614,14 @@ rfn_create (uint16_t size)
1511} 1614}
1512 1615
1513 1616
1514void 1617#if UNUSED
1618static void
1515diff_destroy (struct DiffEntry *diff) 1619diff_destroy (struct DiffEntry *diff)
1516{ 1620{
1517 GNUNET_CONTAINER_multihashmap_destroy (diff->changes); 1621 GNUNET_CONTAINER_multihashmap_destroy (diff->changes);
1518 GNUNET_free (diff); 1622 GNUNET_free (diff);
1519} 1623}
1624#endif
1520 1625
1521 1626
1522/** 1627/**
@@ -1576,6 +1681,12 @@ set_copy_cb (void *cls, struct GNUNET_SET_Handle *copy)
1576 struct TaskEntry *task = scc->task; 1681 struct TaskEntry *task = scc->task;
1577 struct SetKey dst_set_key = scc->dst_set_key; 1682 struct SetKey dst_set_key = scc->dst_set_key;
1578 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);
1579 1690
1580 GNUNET_free (scc); 1691 GNUNET_free (scc);
1581 set = GNUNET_new (struct SetEntry); 1692 set = GNUNET_new (struct SetEntry);
@@ -2018,7 +2129,7 @@ task_start_reconcile (struct TaskEntry *task)
2018 2129
2019 if (task->key.peer1 == session->local_peer_idx) 2130 if (task->key.peer1 == session->local_peer_idx)
2020 { 2131 {
2021 struct GNUNET_CONSENSUS_RoundContextMessage rcm = { 0 }; 2132 struct GNUNET_CONSENSUS_RoundContextMessage rcm;
2022 2133
2023 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 2134 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2024 "P%u: Looking up set {%s} to run remote union\n", 2135 "P%u: Looking up set {%s} to run remote union\n",
@@ -2033,17 +2144,24 @@ task_start_reconcile (struct TaskEntry *task)
2033 rcm.peer2 = htons (task->key.peer2); 2144 rcm.peer2 = htons (task->key.peer2);
2034 rcm.leader = htons (task->key.leader); 2145 rcm.leader = htons (task->key.leader);
2035 rcm.repetition = htons (task->key.repetition); 2146 rcm.repetition = htons (task->key.repetition);
2147 rcm.is_contested = htons (0);
2036 2148
2037 GNUNET_assert (NULL == setop->op); 2149 GNUNET_assert (NULL == setop->op);
2038 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",
2039 session->local_peer_idx, task->key.peer2, debug_str_set_key (&setop->input_set)); 2151 session->local_peer_idx, task->key.peer2, debug_str_set_key (&setop->input_set));
2040 2152
2153 struct GNUNET_SET_Option opts[] = {
2154 { GNUNET_SET_OPTION_BYZANTINE, { .num = session->lower_bound } },
2155 { GNUNET_SET_OPTION_END },
2156 };
2157
2041 // XXX: maybe this should be done while 2158 // XXX: maybe this should be done while
2042 // setting up tasks alreays? 2159 // setting up tasks alreays?
2043 setop->op = GNUNET_SET_prepare (&session->peers[task->key.peer2], 2160 setop->op = GNUNET_SET_prepare (&session->peers[task->key.peer2],
2044 &session->global_id, 2161 &session->global_id,
2045 &rcm.header, 2162 &rcm.header,
2046 GNUNET_SET_RESULT_SYMMETRIC, 2163 GNUNET_SET_RESULT_SYMMETRIC,
2164 opts,
2047 set_result_cb, 2165 set_result_cb,
2048 task); 2166 task);
2049 2167
@@ -2328,45 +2446,48 @@ peer_id_cmp (const void *h1, const void *h2)
2328/** 2446/**
2329 * Create the sorted list of peers for the session, 2447 * Create the sorted list of peers for the session,
2330 * add the local peer if not in the join message. 2448 * add the local peer if not in the join message.
2449 *
2450 * @param session session to initialize
2451 * @param join_msg join message with the list of peers participating at the end
2331 */ 2452 */
2332static void 2453static void
2333initialize_session_peer_list (struct ConsensusSession *session, 2454initialize_session_peer_list (struct ConsensusSession *session,
2334 struct GNUNET_CONSENSUS_JoinMessage *join_msg) 2455 const struct GNUNET_CONSENSUS_JoinMessage *join_msg)
2335{ 2456{
2336 unsigned int local_peer_in_list; 2457 const struct GNUNET_PeerIdentity *msg_peers
2337 uint32_t listed_peers; 2458 = (const struct GNUNET_PeerIdentity *) &join_msg[1];
2338 const struct GNUNET_PeerIdentity *msg_peers; 2459 int local_peer_in_list;
2339 unsigned int i;
2340
2341 GNUNET_assert (NULL != join_msg);
2342
2343 /* peers in the join message, may or may not include the local peer */
2344 listed_peers = ntohl (join_msg->num_peers);
2345 2460
2346 session->num_peers = listed_peers; 2461 session->num_peers = ntohl (join_msg->num_peers);
2347
2348 msg_peers = (struct GNUNET_PeerIdentity *) &join_msg[1];
2349 2462
2463 /* Peers in the join message, may or may not include the local peer,
2464 Add it if it is missing. */
2350 local_peer_in_list = GNUNET_NO; 2465 local_peer_in_list = GNUNET_NO;
2351 for (i = 0; i < listed_peers; i++) 2466 for (unsigned int i = 0; i < session->num_peers; i++)
2352 { 2467 {
2353 if (0 == memcmp (&msg_peers[i], &my_peer, sizeof (struct GNUNET_PeerIdentity))) 2468 if (0 == memcmp (&msg_peers[i],
2469 &my_peer,
2470 sizeof (struct GNUNET_PeerIdentity)))
2354 { 2471 {
2355 local_peer_in_list = GNUNET_YES; 2472 local_peer_in_list = GNUNET_YES;
2356 break; 2473 break;
2357 } 2474 }
2358 } 2475 }
2359
2360 if (GNUNET_NO == local_peer_in_list) 2476 if (GNUNET_NO == local_peer_in_list)
2361 session->num_peers++; 2477 session->num_peers++;
2362 2478
2363 session->peers = GNUNET_malloc (session->num_peers * sizeof (struct GNUNET_PeerIdentity)); 2479 session->peers = GNUNET_new_array (session->num_peers,
2364 2480 struct GNUNET_PeerIdentity);
2365 if (GNUNET_NO == local_peer_in_list) 2481 if (GNUNET_NO == local_peer_in_list)
2366 session->peers[session->num_peers - 1] = my_peer; 2482 session->peers[session->num_peers - 1] = my_peer;
2367 2483
2368 GNUNET_memcpy (session->peers, msg_peers, listed_peers * sizeof (struct GNUNET_PeerIdentity)); 2484 GNUNET_memcpy (session->peers,
2369 qsort (session->peers, session->num_peers, sizeof (struct GNUNET_PeerIdentity), &peer_id_cmp); 2485 msg_peers,
2486 ntohl (join_msg->num_peers) * sizeof (struct GNUNET_PeerIdentity));
2487 qsort (session->peers,
2488 session->num_peers,
2489 sizeof (struct GNUNET_PeerIdentity),
2490 &peer_id_cmp);
2370} 2491}
2371 2492
2372 2493
@@ -2465,8 +2586,14 @@ set_listen_cb (void *cls,
2465 GNUNET_assert (! ((task->key.peer1 == session->local_peer_idx) && 2586 GNUNET_assert (! ((task->key.peer1 == session->local_peer_idx) &&
2466 (task->key.peer2 == session->local_peer_idx))); 2587 (task->key.peer2 == session->local_peer_idx)));
2467 2588
2589 struct GNUNET_SET_Option opts[] = {
2590 { GNUNET_SET_OPTION_BYZANTINE, { .num = session->lower_bound } },
2591 { GNUNET_SET_OPTION_END },
2592 };
2593
2468 task->cls.setop.op = GNUNET_SET_accept (request, 2594 task->cls.setop.op = GNUNET_SET_accept (request,
2469 GNUNET_SET_RESULT_SYMMETRIC, 2595 GNUNET_SET_RESULT_SYMMETRIC,
2596 opts,
2470 set_result_cb, 2597 set_result_cb,
2471 task); 2598 task);
2472 2599
@@ -2862,11 +2989,42 @@ construct_task_graph (struct ConsensusSession *session)
2862 put_task (session->taskmap, &task); 2989 put_task (session->taskmap, &task);
2863 } 2990 }
2864 2991
2992 round += 1;
2865 prev_step = step; 2993 prev_step = step;
2866 step = NULL; 2994 step = create_step (session, round, GNUNET_NO);;
2995#ifdef GNUNET_EXTRA_LOGGING
2996 step->debug_name = GNUNET_strdup ("all to all 2");
2997#endif
2998 step_depend_on (step, prev_step);
2999
3000
3001 for (i = 0; i < n; i++)
3002 {
3003 uint16_t p1;
3004 uint16_t p2;
3005
3006 p1 = me;
3007 p2 = i;
3008 arrange_peers (&p1, &p2, n);
3009 task = ((struct TaskEntry) {
3010 .key = (struct TaskKey) { PHASE_KIND_ALL_TO_ALL_2, p1, p2, -1, -1 },
3011 .step = step,
3012 .start = task_start_reconcile,
3013 .cancel = task_cancel_reconcile,
3014 });
3015 task.cls.setop.input_set = (struct SetKey) { SET_KIND_CURRENT, 0 };
3016 task.cls.setop.output_set = task.cls.setop.input_set;
3017 task.cls.setop.do_not_remove = GNUNET_YES;
3018 put_task (session->taskmap, &task);
3019 }
2867 3020
2868 round += 1; 3021 round += 1;
2869 3022
3023 prev_step = step;
3024 step = NULL;
3025
3026
3027
2870 /* Byzantine union */ 3028 /* Byzantine union */
2871 3029
2872 /* sequential repetitions of the gradecasts */ 3030 /* sequential repetitions of the gradecasts */
@@ -2924,250 +3082,230 @@ construct_task_graph (struct ConsensusSession *session)
2924} 3082}
2925 3083
2926 3084
3085
3086/**
3087 * Check join message.
3088 *
3089 * @param cls session of client that sent the message
3090 * @param m message sent by the client
3091 * @return #GNUNET_OK if @a m is well-formed
3092 */
3093static int
3094check_client_join (void *cls,
3095 const struct GNUNET_CONSENSUS_JoinMessage *m)
3096{
3097 uint32_t listed_peers = ntohl (m->num_peers);
3098
3099 if ( (ntohs (m->header.size) - sizeof (*m)) !=
3100 listed_peers * sizeof (struct GNUNET_PeerIdentity))
3101 {
3102 GNUNET_break (0);
3103 return GNUNET_SYSERR;
3104 }
3105 return GNUNET_OK;
3106}
3107
3108
2927/** 3109/**
2928 * Initialize the session, continue receiving messages from the owning client 3110 * Called when a client wants to join a consensus session.
2929 * 3111 *
2930 * @param session the session to initialize 3112 * @param cls session of client that sent the message
2931 * @param join_msg the join message from the client 3113 * @param m message sent by the client
2932 */ 3114 */
2933static void 3115static void
2934initialize_session (struct ConsensusSession *session, 3116handle_client_join (void *cls,
2935 struct GNUNET_CONSENSUS_JoinMessage *join_msg) 3117 const struct GNUNET_CONSENSUS_JoinMessage *m)
2936{ 3118{
3119 struct ConsensusSession *session = cls;
2937 struct ConsensusSession *other_session; 3120 struct ConsensusSession *other_session;
2938 3121
2939 initialize_session_peer_list (session, join_msg); 3122 initialize_session_peer_list (session,
2940 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "session with %u peers\n", session->num_peers); 3123 m);
2941 compute_global_id (session, &join_msg->session_id); 3124 compute_global_id (session,
3125 &m->session_id);
2942 3126
2943 /* Check if some local client already owns the session. 3127 /* Check if some local client already owns the session.
2944 It is only legal to have a session with an existing global id 3128 It is only legal to have a session with an existing global id
2945 if all other sessions with this global id are finished.*/ 3129 if all other sessions with this global id are finished.*/
2946 other_session = sessions_head; 3130 for (other_session = sessions_head;
2947 while (NULL != other_session) 3131 NULL != other_session;
3132 other_session = other_session->next)
2948 { 3133 {
2949 if ((other_session != session) && 3134 if ( (other_session != session) &&
2950 (0 == GNUNET_CRYPTO_hash_cmp (&session->global_id, &other_session->global_id))) 3135 (0 == GNUNET_CRYPTO_hash_cmp (&session->global_id,
2951 { 3136 &other_session->global_id)) )
2952 //if (CONSENSUS_ROUND_FINISH != other_session->current_round)
2953 //{
2954 // GNUNET_break (0);
2955 // destroy_session (session);
2956 // return;
2957 //}
2958 break; 3137 break;
2959 }
2960 other_session = other_session->next;
2961 } 3138 }
2962 3139
2963 session->conclude_deadline = GNUNET_TIME_absolute_ntoh (join_msg->deadline); 3140 session->conclude_deadline
2964 session->conclude_start = GNUNET_TIME_absolute_ntoh (join_msg->start); 3141 = GNUNET_TIME_absolute_ntoh (m->deadline);
2965 3142 session->conclude_start
2966 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "consensus with timeout %llums created\n", 3143 = GNUNET_TIME_absolute_ntoh (m->start);
2967 (long long) (GNUNET_TIME_absolute_get_difference (session->conclude_start, session->conclude_deadline)).rel_value_us / 1000); 3144 session->local_peer_idx = get_peer_idx (&my_peer,
2968 3145 session);
2969 session->local_peer_idx = get_peer_idx (&my_peer, session);
2970 GNUNET_assert (-1 != session->local_peer_idx); 3146 GNUNET_assert (-1 != session->local_peer_idx);
2971 session->set_listener = GNUNET_SET_listen (cfg, GNUNET_SET_OPERATION_UNION,
2972 &session->global_id,
2973 set_listen_cb, session);
2974 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%d is the local peer\n", session->local_peer_idx);
2975 3147
2976 session->setmap = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); 3148 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2977 session->taskmap = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); 3149 "Joining consensus session %s containing %u peers as %u with timeout %s\n",
2978 session->diffmap = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); 3150 GNUNET_h2s (&m->session_id),
2979 session->rfnmap = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); 3151 session->num_peers,
3152 session->local_peer_idx,
3153 GNUNET_STRINGS_relative_time_to_string
3154 (GNUNET_TIME_absolute_get_difference (session->conclude_start,
3155 session->conclude_deadline),
3156 GNUNET_YES));
3157
3158 session->set_listener
3159 = GNUNET_SET_listen (cfg,
3160 GNUNET_SET_OPERATION_UNION,
3161 &session->global_id,
3162 &set_listen_cb,
3163 session);
3164
3165 session->setmap = GNUNET_CONTAINER_multihashmap_create (1,
3166 GNUNET_NO);
3167 session->taskmap = GNUNET_CONTAINER_multihashmap_create (1,
3168 GNUNET_NO);
3169 session->diffmap = GNUNET_CONTAINER_multihashmap_create (1,
3170 GNUNET_NO);
3171 session->rfnmap = GNUNET_CONTAINER_multihashmap_create (1,
3172 GNUNET_NO);
2980 3173
2981 { 3174 {
2982 struct SetEntry *client_set; 3175 struct SetEntry *client_set;
3176
2983 client_set = GNUNET_new (struct SetEntry); 3177 client_set = GNUNET_new (struct SetEntry);
2984 client_set->h = GNUNET_SET_create (cfg, GNUNET_SET_OPERATION_UNION); 3178 client_set->h = GNUNET_SET_create (cfg,
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);
2985 client_set->key = ((struct SetKey) { SET_KIND_CURRENT, 0, 0 }); 3185 client_set->key = ((struct SetKey) { SET_KIND_CURRENT, 0, 0 });
2986 put_set (session, client_set); 3186 put_set (session,
3187 client_set);
2987 } 3188 }
2988 3189
2989 session->peers_blacklisted = GNUNET_new_array (session->num_peers, int); 3190 session->peers_blacklisted = GNUNET_new_array (session->num_peers,
3191 int);
2990 3192
2991 /* Just construct the task graph, 3193 /* Just construct the task graph,
2992 but don't run anything until the client calls conclude. */ 3194 but don't run anything until the client calls conclude. */
2993 construct_task_graph (session); 3195 construct_task_graph (session);
2994 3196 GNUNET_SERVICE_client_continue (session->client);
2995 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "session %s initialized\n", GNUNET_h2s (&session->global_id));
2996} 3197}
2997 3198
2998 3199
2999static struct ConsensusSession * 3200static void
3000get_session_by_client (struct GNUNET_SERVER_Client *client) 3201client_insert_done (void *cls)
3001{ 3202{
3002 struct ConsensusSession *session; 3203 // FIXME: implement
3003
3004 session = sessions_head;
3005 while (NULL != session)
3006 {
3007 if (session->client == client)
3008 return session;
3009 session = session->next;
3010 }
3011 return NULL;
3012} 3204}
3013 3205
3014 3206
3015/** 3207/**
3016 * Called when a client wants to join a consensus session. 3208 * Called when a client performs an insert operation.
3017 * 3209 *
3018 * @param cls unused 3210 * @param cls client handle
3019 * @param client client that sent the message 3211 * @param msg message sent by the client
3020 * @param m message sent by the client 3212 * @return #GNUNET_OK (always well-formed)
3021 */ 3213 */
3022static void 3214static int
3023client_join (void *cls, 3215check_client_insert (void *cls,
3024 struct GNUNET_SERVER_Client *client, 3216 const struct GNUNET_CONSENSUS_ElementMessage *msg)
3025 const struct GNUNET_MessageHeader *m)
3026{
3027 struct ConsensusSession *session;
3028
3029 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "join message sent by client\n");
3030
3031 session = get_session_by_client (client);
3032 if (NULL != session)
3033 {
3034 GNUNET_break (0);
3035 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3036 return;
3037 }
3038 session = GNUNET_new (struct ConsensusSession);
3039 session->client = client;
3040 session->client_mq = GNUNET_MQ_queue_for_server_client (client);
3041 GNUNET_CONTAINER_DLL_insert (sessions_head, sessions_tail, session);
3042 initialize_session (session, (struct GNUNET_CONSENSUS_JoinMessage *) m);
3043 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3044
3045 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "join done\n");
3046}
3047
3048
3049static void
3050client_insert_done (void *cls)
3051{ 3217{
3052 // FIXME: implement 3218 return GNUNET_OK;
3053} 3219}
3054 3220
3055 3221
3056/** 3222/**
3057 * Called when a client performs an insert operation. 3223 * Called when a client performs an insert operation.
3058 * 3224 *
3059 * @param cls (unused) 3225 * @param cls client handle
3060 * @param client client handle 3226 * @param msg message sent by the client
3061 * @param m message sent by the client
3062 */ 3227 */
3063void 3228static void
3064client_insert (void *cls, 3229handle_client_insert (void *cls,
3065 struct GNUNET_SERVER_Client *client, 3230 const struct GNUNET_CONSENSUS_ElementMessage *msg)
3066 const struct GNUNET_MessageHeader *m)
3067{ 3231{
3068 struct ConsensusSession *session; 3232 struct ConsensusSession *session = cls;
3069 struct GNUNET_CONSENSUS_ElementMessage *msg;
3070 struct GNUNET_SET_Element *element;
3071 ssize_t element_size; 3233 ssize_t element_size;
3072 struct GNUNET_SET_Handle *initial_set; 3234 struct GNUNET_SET_Handle *initial_set;
3073 3235 struct ConsensusElement *ce;
3074 session = get_session_by_client (client);
3075
3076 if (NULL == session)
3077 {
3078 GNUNET_break (0);
3079 GNUNET_SERVER_client_disconnect (client);
3080 return;
3081 }
3082 3236
3083 if (GNUNET_YES == session->conclude_started) 3237 if (GNUNET_YES == session->conclude_started)
3084 { 3238 {
3085 GNUNET_break (0); 3239 GNUNET_break (0);
3086 GNUNET_SERVER_client_disconnect (client); 3240 GNUNET_SERVICE_client_drop (session->client);
3087 return; 3241 return;
3088 } 3242 }
3089 3243
3090 msg = (struct GNUNET_CONSENSUS_ElementMessage *) m;
3091 element_size = ntohs (msg->header.size) - sizeof (struct GNUNET_CONSENSUS_ElementMessage); 3244 element_size = ntohs (msg->header.size) - sizeof (struct GNUNET_CONSENSUS_ElementMessage);
3092 if (element_size < 0) 3245 ce = GNUNET_malloc (sizeof (struct ConsensusElement) + element_size);
3093 { 3246 GNUNET_memcpy (&ce[1], &msg[1], element_size);
3094 GNUNET_break (0); 3247 ce->payload_type = msg->element_type;
3095 return; 3248
3096 } 3249 struct GNUNET_SET_Element element = {
3250 .element_type = GNUNET_BLOCK_TYPE_CONSENSUS_ELEMENT,
3251 .size = sizeof (struct ConsensusElement) + element_size,
3252 .data = ce,
3253 };
3097 3254
3098 element = GNUNET_malloc (sizeof (struct GNUNET_SET_Element) + element_size);
3099 element->element_type = msg->element_type;
3100 element->size = element_size;
3101 GNUNET_memcpy (&element[1], &msg[1], element_size);
3102 element->data = &element[1];
3103 { 3255 {
3104 struct SetKey key = { SET_KIND_CURRENT, 0, 0 }; 3256 struct SetKey key = { SET_KIND_CURRENT, 0, 0 };
3105 struct SetEntry *entry; 3257 struct SetEntry *entry;
3106 entry = lookup_set (session, &key); 3258
3259 entry = lookup_set (session,
3260 &key);
3107 GNUNET_assert (NULL != entry); 3261 GNUNET_assert (NULL != entry);
3108 initial_set = entry->h; 3262 initial_set = entry->h;
3109 } 3263 }
3264
3110 session->num_client_insert_pending++; 3265 session->num_client_insert_pending++;
3111 GNUNET_SET_add_element (initial_set, element, client_insert_done, session); 3266 GNUNET_SET_add_element (initial_set,
3267 &element,
3268 &client_insert_done,
3269 session);
3112 3270
3113#ifdef GNUNET_EXTRA_LOGGING 3271#ifdef GNUNET_EXTRA_LOGGING
3114 { 3272 {
3115 struct GNUNET_HashCode hash; 3273 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3116 3274 "P%u: element %s added\n",
3117 GNUNET_SET_element_hash (element, &hash);
3118
3119 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: element %s added\n",
3120 session->local_peer_idx, 3275 session->local_peer_idx,
3121 GNUNET_h2s (&hash)); 3276 debug_str_element (&element));
3122 } 3277 }
3123#endif 3278#endif
3124 3279 GNUNET_free (ce);
3125 GNUNET_free (element); 3280 GNUNET_SERVICE_client_continue (session->client);
3126 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3127} 3281}
3128 3282
3129 3283
3130/** 3284/**
3131 * Called when a client performs the conclude operation. 3285 * Called when a client performs the conclude operation.
3132 * 3286 *
3133 * @param cls (unused) 3287 * @param cls client handle
3134 * @param client client handle
3135 * @param message message sent by the client 3288 * @param message message sent by the client
3136 */ 3289 */
3137static void 3290static void
3138client_conclude (void *cls, 3291handle_client_conclude (void *cls,
3139 struct GNUNET_SERVER_Client *client, 3292 const struct GNUNET_MessageHeader *message)
3140 const struct GNUNET_MessageHeader *message)
3141{ 3293{
3142 struct ConsensusSession *session; 3294 struct ConsensusSession *session = cls;
3143
3144 session = get_session_by_client (client);
3145 if (NULL == session)
3146 {
3147 /* client not found */
3148 GNUNET_break (0);
3149 GNUNET_SERVER_client_disconnect (client);
3150 return;
3151 }
3152 3295
3153 if (GNUNET_YES == session->conclude_started) 3296 if (GNUNET_YES == session->conclude_started)
3154 { 3297 {
3155 /* conclude started twice */ 3298 /* conclude started twice */
3156 GNUNET_break (0); 3299 GNUNET_break (0);
3157 GNUNET_SERVER_client_disconnect (client); 3300 GNUNET_SERVICE_client_drop (session->client);
3158 destroy_session (session);
3159 return; 3301 return;
3160 } 3302 }
3161 3303 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3162 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "conclude requested\n"); 3304 "conclude requested\n");
3163
3164 session->conclude_started = GNUNET_YES; 3305 session->conclude_started = GNUNET_YES;
3165
3166 install_step_timeouts (session); 3306 install_step_timeouts (session);
3167 run_ready_steps (session); 3307 run_ready_steps (session);
3168 3308 GNUNET_SERVICE_client_continue (session->client);
3169
3170 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3171} 3309}
3172 3310
3173 3311
@@ -3179,82 +3317,123 @@ client_conclude (void *cls,
3179static void 3317static void
3180shutdown_task (void *cls) 3318shutdown_task (void *cls)
3181{ 3319{
3182 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "shutting down\n"); 3320 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3183 while (NULL != sessions_head) 3321 "shutting down\n");
3184 destroy_session (sessions_head); 3322 GNUNET_STATISTICS_destroy (statistics,
3185 3323 GNUNET_NO);
3186 GNUNET_STATISTICS_destroy (statistics, GNUNET_NO); 3324 statistics = NULL;
3187} 3325}
3188 3326
3189 3327
3190/** 3328/**
3191 * Clean up after a client after it is 3329 * Start processing consensus requests.
3192 * disconnected (either by us or by itself)
3193 * 3330 *
3194 * @param cls closure, unused 3331 * @param cls closure
3195 * @param client the client to clean up after 3332 * @param c configuration to use
3333 * @param service the initialized service
3196 */ 3334 */
3197void 3335static void
3198handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) 3336run (void *cls,
3337 const struct GNUNET_CONFIGURATION_Handle *c,
3338 struct GNUNET_SERVICE_Handle *service)
3199{ 3339{
3200 struct ConsensusSession *session; 3340 cfg = c;
3201 3341 if (GNUNET_OK !=
3202 session = get_session_by_client (client); 3342 GNUNET_CRYPTO_get_peer_identity (cfg,
3203 if (NULL == session) 3343 &my_peer))
3344 {
3345 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3346 "Could not retrieve host identity\n");
3347 GNUNET_SCHEDULER_shutdown ();
3204 return; 3348 return;
3205 // FIXME: destroy if we can 3349 }
3350 statistics = GNUNET_STATISTICS_create ("consensus",
3351 cfg);
3352 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
3353 NULL);
3206} 3354}
3207 3355
3208 3356
3357/**
3358 * Callback called when a client connects to the service.
3359 *
3360 * @param cls closure for the service
3361 * @param c the new client that connected to the service
3362 * @param mq the message queue used to send messages to the client
3363 * @return @a c
3364 */
3365static void *
3366client_connect_cb (void *cls,
3367 struct GNUNET_SERVICE_Client *c,
3368 struct GNUNET_MQ_Handle *mq)
3369{
3370 struct ConsensusSession *session = GNUNET_new (struct ConsensusSession);
3371
3372 session->client = c;
3373 session->client_mq = mq;
3374 GNUNET_CONTAINER_DLL_insert (sessions_head,
3375 sessions_tail,
3376 session);
3377 return session;
3378}
3379
3209 3380
3210/** 3381/**
3211 * Start processing consensus requests. 3382 * Callback called when a client disconnected from the service
3212 * 3383 *
3213 * @param cls closure 3384 * @param cls closure for the service
3214 * @param server the initialized server 3385 * @param c the client that disconnected
3215 * @param c configuration to use 3386 * @param internal_cls should be equal to @a c
3216 */ 3387 */
3217static void 3388static void
3218run (void *cls, struct GNUNET_SERVER_Handle *server, 3389client_disconnect_cb (void *cls,
3219 const struct GNUNET_CONFIGURATION_Handle *c) 3390 struct GNUNET_SERVICE_Client *c,
3220{ 3391 void *internal_cls)
3221 static const struct GNUNET_SERVER_MessageHandler server_handlers[] = { 3392{
3222 {&client_conclude, NULL, GNUNET_MESSAGE_TYPE_CONSENSUS_CLIENT_CONCLUDE, 3393 struct ConsensusSession *session = internal_cls;
3223 sizeof (struct GNUNET_MessageHeader)},
3224 {&client_insert, NULL, GNUNET_MESSAGE_TYPE_CONSENSUS_CLIENT_INSERT, 0},
3225 {&client_join, NULL, GNUNET_MESSAGE_TYPE_CONSENSUS_CLIENT_JOIN, 0},
3226 {NULL, NULL, 0, 0}
3227 };
3228 3394
3229 cfg = c; 3395 if (NULL != session->set_listener)
3230 srv = server;
3231 if (GNUNET_OK != GNUNET_CRYPTO_get_peer_identity (cfg, &my_peer))
3232 { 3396 {
3233 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "could not retrieve host identity\n"); 3397 GNUNET_SET_listen_cancel (session->set_listener);
3234 GNUNET_break (0); 3398 session->set_listener = NULL;
3235 GNUNET_SCHEDULER_shutdown (); 3399 }
3236 return; 3400 GNUNET_CONTAINER_DLL_remove (sessions_head,
3401 sessions_tail,
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);
3237 } 3410 }
3238 statistics = GNUNET_STATISTICS_create ("consensus", cfg); 3411 GNUNET_free (session);
3239 GNUNET_SERVER_add_handlers (server, server_handlers);
3240 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
3241 GNUNET_SERVER_disconnect_notify (server, handle_client_disconnect, NULL);
3242 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "consensus running\n");
3243} 3412}
3244 3413
3245 3414
3246/** 3415/**
3247 * The main function for the consensus service. 3416 * Define "main" method using service macro.
3248 *
3249 * @param argc number of arguments from the command line
3250 * @param argv command line arguments
3251 * @return 0 ok, 1 on error
3252 */ 3417 */
3253int 3418GNUNET_SERVICE_MAIN
3254main (int argc, char *const *argv) 3419("consensus",
3255{ 3420 GNUNET_SERVICE_OPTION_NONE,
3256 int ret; 3421 &run,
3257 ret = GNUNET_SERVICE_run (argc, argv, "consensus", GNUNET_SERVICE_OPTION_NONE, &run, NULL); 3422 &client_connect_cb,
3258 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "exit (%d)\n", GNUNET_OK != ret); 3423 &client_disconnect_cb,
3259 return (GNUNET_OK == ret) ? 0 : 1; 3424 NULL,
3260} 3425 GNUNET_MQ_hd_fixed_size (client_conclude,
3426 GNUNET_MESSAGE_TYPE_CONSENSUS_CLIENT_CONCLUDE,
3427 struct GNUNET_MessageHeader,
3428 NULL),
3429 GNUNET_MQ_hd_var_size (client_insert,
3430 GNUNET_MESSAGE_TYPE_CONSENSUS_CLIENT_INSERT,
3431 struct GNUNET_CONSENSUS_ElementMessage,
3432 NULL),
3433 GNUNET_MQ_hd_var_size (client_join,
3434 GNUNET_MESSAGE_TYPE_CONSENSUS_CLIENT_JOIN,
3435 struct GNUNET_CONSENSUS_JoinMessage,
3436 NULL),
3437 GNUNET_MQ_handler_end ());
3438
3439/* end of gnunet-service-consensus.c */
diff --git a/src/consensus/plugin_block_consensus.c b/src/consensus/plugin_block_consensus.c
new file mode 100644
index 000000000..de0f0886f
--- /dev/null
+++ b/src/consensus/plugin_block_consensus.c
@@ -0,0 +1,137 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 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 consensus/plugin_block_consensus.c
23 * @brief consensus block, either nested block or marker
24 * @author Christian Grothoff
25 */
26
27#include "platform.h"
28#include "consensus_protocol.h"
29#include "gnunet_block_plugin.h"
30#include "gnunet_block_group_lib.h"
31
32
33/**
34 * Function called to validate a reply or a request. For
35 * request evaluation, simply pass "NULL" for the reply_block.
36 *
37 * @param cls closure
38 * @param ctx context
39 * @param type block type
40 * @param group block group to use
41 * @param eo control flags
42 * @param query original query (hash)
43 * @param xquery extrended query data (can be NULL, depending on type)
44 * @param xquery_size number of bytes in xquery
45 * @param reply_block response to validate
46 * @param reply_block_size number of bytes in reply block
47 * @return characterization of result
48 */
49static enum GNUNET_BLOCK_EvaluationResult
50block_plugin_consensus_evaluate (void *cls,
51 struct GNUNET_BLOCK_Context *ctx,
52 enum GNUNET_BLOCK_Type type,
53 struct GNUNET_BLOCK_Group *group,
54 enum GNUNET_BLOCK_EvaluationOptions eo,
55 const struct GNUNET_HashCode *query,
56 const void *xquery,
57 size_t xquery_size,
58 const void *reply_block,
59 size_t reply_block_size)
60{
61 if (reply_block_size < sizeof (struct ConsensusElement))
62 return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
63
64 const struct ConsensusElement *ce = reply_block;
65
66 if ( (0 != ce->marker) ||
67 (0 == ce->payload_type ) )
68 return GNUNET_BLOCK_EVALUATION_OK_MORE;
69
70 return GNUNET_BLOCK_evaluate (ctx,
71 type,
72 group,
73 eo,
74 query,
75 xquery,
76 xquery_size,
77 &ce[1],
78 reply_block_size - sizeof (struct ConsensusElement));
79}
80
81
82/**
83 * Function called to obtain the key for a block.
84 *
85 * @param cls closure
86 * @param type block type
87 * @param block block to get the key for
88 * @param block_size number of bytes in block
89 * @param key set to the key (query) for the given block
90 * @return #GNUNET_OK on success, #GNUNET_SYSERR if type not supported
91 * (or if extracting a key from a block of this type does not work)
92 */
93static int
94block_plugin_consensus_get_key (void *cls,
95 enum GNUNET_BLOCK_Type type,
96 const void *block,
97 size_t block_size,
98 struct GNUNET_HashCode *key)
99{
100 return GNUNET_SYSERR;
101}
102
103
104/**
105 * Entry point for the plugin.
106 */
107void *
108libgnunet_plugin_block_consensus_init (void *cls)
109{
110 static enum GNUNET_BLOCK_Type types[] =
111 {
112 GNUNET_BLOCK_TYPE_CONSENSUS_ELEMENT,
113 GNUNET_BLOCK_TYPE_ANY /* end of list */
114 };
115 struct GNUNET_BLOCK_PluginFunctions *api;
116
117 api = GNUNET_new (struct GNUNET_BLOCK_PluginFunctions);
118 api->evaluate = &block_plugin_consensus_evaluate;
119 api->get_key = &block_plugin_consensus_get_key;
120 api->types = types;
121 return api;
122}
123
124
125/**
126 * Exit point from the plugin.
127 */
128void *
129libgnunet_plugin_block_consensus_done (void *cls)
130{
131 struct GNUNET_BLOCK_PluginFunctions *api = cls;
132
133 GNUNET_free (api);
134 return NULL;
135}
136
137/* end of plugin_block_consensus.c */
diff --git a/src/consensus/test_consensus.conf b/src/consensus/test_consensus.conf
index 8f144fa5e..881251a66 100644
--- a/src/consensus/test_consensus.conf
+++ b/src/consensus/test_consensus.conf
@@ -2,9 +2,11 @@
2GNUNET_TEST_HOME = /tmp/test-consensus/ 2GNUNET_TEST_HOME = /tmp/test-consensus/
3 3
4[consensus] 4[consensus]
5OPTIONS = -L INFO 5#OPTIONS = -L INFO
6BINARY = gnunet-service-evil-consensus 6BINARY = gnunet-service-evil-consensus
7 7
8PREFIX = valgrind
9
8#EVIL_SPEC = 0;cram-all;noreplace;5 10#EVIL_SPEC = 0;cram-all;noreplace;5
9#EVIL_SPEC = 0;cram;5/1;cram;5 11#EVIL_SPEC = 0;cram;5/1;cram;5
10#EVIL_SPEC = 0;cram;5/1;cram;5/2;cram;5 12#EVIL_SPEC = 0;cram;5/1;cram;5/2;cram;5
@@ -15,19 +17,22 @@ BINARY = gnunet-service-evil-consensus
15RESOURCE_DIAGNOSTICS = resource.log.${PEERID:-master} 17RESOURCE_DIAGNOSTICS = resource.log.${PEERID:-master}
16 18
17[core] 19[core]
18FORECESTART = YES 20FORCESTART = YES
19 21
20[revocation] 22[revocation]
21FORECESTART = NO 23FORCESTART = NO
22 24
23[fs] 25[fs]
24FORECESTART = NO 26FORCESTART = NO
25 27
26[gns] 28[gns]
27FORECESTART = NO 29FORCESTART = NO
30
31[zonemaster]
32FORCESTART = NO
28 33
29[hostlist] 34[hostlist]
30FORECESTART = NO 35FORCESTART = NO
31 36
32[cadet] 37[cadet]
33#PREFIX = valgrind 38#PREFIX = valgrind
@@ -37,7 +42,7 @@ PLUGINS = unix
37OPTIONS = -LERROR 42OPTIONS = -LERROR
38 43
39[set] 44[set]
40OPTIONS = -L INFO 45#OPTIONS = -L INFO
41#PREFIX = valgrind --leak-check=full 46#PREFIX = valgrind --leak-check=full
42#PREFIX = valgrind 47#PREFIX = valgrind
43 48
diff --git a/src/conversation/.gitignore b/src/conversation/.gitignore
index 0e4345a8b..e74e259bf 100644
--- a/src/conversation/.gitignore
+++ b/src/conversation/.gitignore
@@ -3,3 +3,6 @@ gnunet-conversation
3gnunet-conversation-test 3gnunet-conversation-test
4gnunet-helper-audio-playback 4gnunet-helper-audio-playback
5gnunet-helper-audio-record 5gnunet-helper-audio-record
6test_conversation_api
7test_conversation_api_reject
8test_conversation_api_twocalls
diff --git a/src/conversation/Makefile.am b/src/conversation/Makefile.am
index f61173a66..cbffc3283 100644
--- a/src/conversation/Makefile.am
+++ b/src/conversation/Makefile.am
@@ -101,7 +101,7 @@ libexec_PROGRAMS += \
101 $(AUDIO_HELPER_RECD) \ 101 $(AUDIO_HELPER_RECD) \
102 $(AUDIO_HELPER_PLAY) 102 $(AUDIO_HELPER_PLAY)
103 103
104AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; 104AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
105if ENABLE_TEST_RUN 105if ENABLE_TEST_RUN
106TESTS = $(AUDIO_TESTS) 106TESTS = $(AUDIO_TESTS)
107endif 107endif
@@ -138,7 +138,7 @@ gnunet_helper_audio_record_CFLAGS = \
138 $(GST_CFLAGS) 138 $(GST_CFLAGS)
139 139
140gnunet_helper_audio_playback_SOURCES = \ 140gnunet_helper_audio_playback_SOURCES = \
141 gnunet_gst_test.c gnunet_gst.c 141 gnunet-helper-audio-playback-gst.c
142gnunet_helper_audio_playback_LDADD = \ 142gnunet_helper_audio_playback_LDADD = \
143 $(top_builddir)/src/util/libgnunetutil.la \ 143 $(top_builddir)/src/util/libgnunetutil.la \
144 $(GST_LIBS) \ 144 $(GST_LIBS) \
diff --git a/src/conversation/conversation_api_call.c b/src/conversation/conversation_api_call.c
index a6bc506bc..7e4a147a0 100644
--- a/src/conversation/conversation_api_call.c
+++ b/src/conversation/conversation_api_call.c
@@ -603,7 +603,6 @@ GNUNET_CONVERSATION_call_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
603 &my_zone, 603 &my_zone,
604 GNUNET_GNSRECORD_TYPE_PHONE, 604 GNUNET_GNSRECORD_TYPE_PHONE,
605 GNUNET_NO, 605 GNUNET_NO,
606 NULL /* FIXME: add shortening support */,
607 &handle_gns_response, call); 606 &handle_gns_response, call);
608 GNUNET_assert (NULL != call->gns_lookup); 607 GNUNET_assert (NULL != call->gns_lookup);
609 return call; 608 return call;
diff --git a/src/conversation/gnunet-conversation.c b/src/conversation/gnunet-conversation.c
index 925db4665..8f9ddec25 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-gst.c b/src/conversation/gnunet-helper-audio-playback-gst.c
index 9307cd12e..264b14e76 100644
--- a/src/conversation/gnunet-helper-audio-playback-gst.c
+++ b/src/conversation/gnunet-helper-audio-playback-gst.c
@@ -56,7 +56,7 @@
56/** 56/**
57 * Tokenizer for the data we get from stdin 57 * Tokenizer for the data we get from stdin
58 */ 58 */
59struct GNUNET_SERVER_MessageStreamTokenizer *stdin_mst; 59struct GNUNET_MessageStreamTokenizer *stdin_mst;
60 60
61/** 61/**
62 * Main pipeline. 62 * Main pipeline.
@@ -82,20 +82,20 @@ static int abort_read;
82 82
83static void 83static void
84sink_child_added (GstChildProxy *child_proxy, 84sink_child_added (GstChildProxy *child_proxy,
85 GObject *object, 85 GObject *object,
86 gchar *name, 86 gchar *name,
87 gpointer user_data) 87 gpointer user_data)
88{ 88{
89 if (GST_IS_AUDIO_BASE_SRC (object)) 89 if (GST_IS_AUDIO_BASE_SRC (object))
90 g_object_set (object, 90 g_object_set (object,
91 "buffer-time", (gint64) BUFFER_TIME, 91 "buffer-time", (gint64) BUFFER_TIME,
92 "latency-time", (gint64) LATENCY_TIME, 92 "latency-time", (gint64) LATENCY_TIME,
93 NULL); 93 NULL);
94} 94}
95 95
96 96
97static void 97static void
98ogg_pad_added (GstElement *element, 98ogg_pad_added (GstElement *element,
99 GstPad *pad, 99 GstPad *pad,
100 gpointer data) 100 gpointer data)
101{ 101{
@@ -127,7 +127,7 @@ quit ()
127static gboolean 127static gboolean
128bus_call (GstBus *bus, GstMessage *msg, gpointer data) 128bus_call (GstBus *bus, GstMessage *msg, gpointer data)
129{ 129{
130 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 130 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
131 "Bus message\n"); 131 "Bus message\n");
132 switch (GST_MESSAGE_TYPE (msg)) 132 switch (GST_MESSAGE_TYPE (msg))
133 { 133 {
@@ -141,15 +141,15 @@ bus_call (GstBus *bus, GstMessage *msg, gpointer data)
141 { 141 {
142 gchar *debug; 142 gchar *debug;
143 GError *error; 143 GError *error;
144 144
145 gst_message_parse_error (msg, &error, &debug); 145 gst_message_parse_error (msg, &error, &debug);
146 g_free (debug); 146 g_free (debug);
147 147
148 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 148 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
149 "Error: %s\n", 149 "Error: %s\n",
150 error->message); 150 error->message);
151 g_error_free (error); 151 g_error_free (error);
152 152
153 quit (); 153 quit ();
154 break; 154 break;
155 } 155 }
@@ -196,7 +196,7 @@ feed_buffer_to_gst (const char *audio, size_t b_len)
196 switch (flow) 196 switch (flow)
197 { 197 {
198 case GST_FLOW_OK: 198 case GST_FLOW_OK:
199 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 199 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
200 "Fed %u bytes to the pipeline\n", 200 "Fed %u bytes to the pipeline\n",
201 (unsigned int) b_len); 201 (unsigned int) b_len);
202 break; 202 break;
@@ -207,7 +207,7 @@ feed_buffer_to_gst (const char *audio, size_t b_len)
207 break; 207 break;
208 case GST_FLOW_EOS: 208 case GST_FLOW_EOS:
209 /* end of stream */ 209 /* end of stream */
210 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 210 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
211 "EOS\n"); 211 "EOS\n");
212 break; 212 break;
213 default: 213 default:
@@ -224,7 +224,6 @@ feed_buffer_to_gst (const char *audio, size_t b_len)
224 */ 224 */
225static int 225static int
226stdin_receiver (void *cls, 226stdin_receiver (void *cls,
227 void *client,
228 const struct GNUNET_MessageHeader *msg) 227 const struct GNUNET_MessageHeader *msg)
229{ 228{
230 struct AudioMessage *audio; 229 struct AudioMessage *audio;
@@ -253,21 +252,21 @@ main (int argc, char **argv)
253 uint64_t toff; 252 uint64_t toff;
254 253
255 typedef void (*SignalHandlerPointer) (int); 254 typedef void (*SignalHandlerPointer) (int);
256 255
257 SignalHandlerPointer inthandler, termhandler; 256 SignalHandlerPointer inthandler, termhandler;
258#ifdef DEBUG_READ_PURE_OGG 257#ifdef DEBUG_READ_PURE_OGG
259 int read_pure_ogg = getenv ("GNUNET_READ_PURE_OGG") ? 1 : 0; 258 int read_pure_ogg = getenv ("GNUNET_READ_PURE_OGG") ? 1 : 0;
260#endif 259#endif
261 260
262 inthandler = signal (SIGINT, 261 inthandler = signal (SIGINT,
263 &signalhandler); 262 &signalhandler);
264 termhandler = signal (SIGTERM, 263 termhandler = signal (SIGTERM,
265 &signalhandler); 264 &signalhandler);
266 265
267#ifdef WINDOWS 266#ifdef WINDOWS
268 setmode (0, _O_BINARY); 267 setmode (0, _O_BINARY);
269#endif 268#endif
270 269
271 /* Initialisation */ 270 /* Initialisation */
272 gst_init (&argc, &argv); 271 gst_init (&argc, &argv);
273 272
@@ -275,13 +274,13 @@ main (int argc, char **argv)
275 GNUNET_log_setup ("gnunet-helper-audio-playback-gst", 274 GNUNET_log_setup ("gnunet-helper-audio-playback-gst",
276 "WARNING", 275 "WARNING",
277 NULL)); 276 NULL));
278 277
279 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 278 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
280 "Audio sink starts\n"); 279 "Audio sink starts\n");
281 280
282 stdin_mst = GNUNET_SERVER_mst_create (&stdin_receiver, 281 stdin_mst = GNUNET_MST_create (&stdin_receiver,
283 NULL); 282 NULL);
284 283
285 /* Create gstreamer elements */ 284 /* Create gstreamer elements */
286 pipeline = gst_pipeline_new ("audio-player"); 285 pipeline = gst_pipeline_new ("audio-player");
287 source = gst_element_factory_make ("appsrc", "audio-input"); 286 source = gst_element_factory_make ("appsrc", "audio-input");
@@ -298,13 +297,13 @@ main (int argc, char **argv)
298 return -1; 297 return -1;
299 } 298 }
300 299
301 g_signal_connect (sink, 300 g_signal_connect (sink,
302 "child-added", 301 "child-added",
303 G_CALLBACK (sink_child_added), 302 G_CALLBACK (sink_child_added),
304 NULL); 303 NULL);
305 g_signal_connect (demuxer, 304 g_signal_connect (demuxer,
306 "pad-added", 305 "pad-added",
307 G_CALLBACK (ogg_pad_added), 306 G_CALLBACK (ogg_pad_added),
308 decoder); 307 decoder);
309 308
310 /* Keep a reference to it, we operate on it */ 309 /* Keep a reference to it, we operate on it */
@@ -362,7 +361,7 @@ main (int argc, char **argv)
362 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 361 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
363 "Received %d bytes of audio data (total: %llu)\n", 362 "Received %d bytes of audio data (total: %llu)\n",
364 (int) ret, 363 (int) ret,
365 toff); 364 (unsigned long long) toff);
366 if (0 == ret) 365 if (0 == ret)
367 break; 366 break;
368#ifdef DEBUG_READ_PURE_OGG 367#ifdef DEBUG_READ_PURE_OGG
@@ -372,20 +371,22 @@ main (int argc, char **argv)
372 } 371 }
373 else 372 else
374#endif 373#endif
375 GNUNET_SERVER_mst_receive (stdin_mst, NULL, 374 GNUNET_MST_from_buffer (stdin_mst,
376 readbuf, ret, 375 readbuf,
377 GNUNET_NO, GNUNET_NO); 376 ret,
377 GNUNET_NO,
378 GNUNET_NO);
378 } 379 }
379 GNUNET_SERVER_mst_destroy (stdin_mst); 380 GNUNET_MST_destroy (stdin_mst);
380 381
381 signal (SIGINT, inthandler); 382 signal (SIGINT, inthandler);
382 signal (SIGINT, termhandler); 383 signal (SIGINT, termhandler);
383 384
384 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 385 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
385 "Returned, stopping playback\n"); 386 "Returned, stopping playback\n");
386 quit (); 387 quit ();
387 388
388 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 389 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
389 "Deleting pipeline\n"); 390 "Deleting pipeline\n");
390 gst_object_unref (GST_OBJECT (source)); 391 gst_object_unref (GST_OBJECT (source));
391 source = NULL; 392 source = NULL;
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-helper-audio-record-gst.c b/src/conversation/gnunet-helper-audio-record-gst.c
index 7f1f3368b..b9aed4ea7 100644
--- a/src/conversation/gnunet-helper-audio-record-gst.c
+++ b/src/conversation/gnunet-helper-audio-record-gst.c
@@ -352,9 +352,12 @@ main (int argc, char **argv)
352 { 352 {
353 if (-1 == ret) 353 if (-1 == ret)
354 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 354 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
355 "Failed to write %u bytes at offset %u (total %u) in phase %d: %s\n", 355 "Failed to write %u bytes at offset %u (total %u) in phase %d: %s\n",
356 (unsigned int) to_send - offset, (unsigned int) offset, 356 (unsigned int) (to_send - offset),
357 (unsigned int) (to_send + offset), phase, strerror (errno)); 357 (unsigned int) offset,
358 (unsigned int) (to_send + offset),
359 phase,
360 strerror (errno));
358 abort_send = 1; 361 abort_send = 1;
359 break; 362 break;
360 } 363 }
diff --git a/src/conversation/gnunet-service-conversation.c b/src/conversation/gnunet-service-conversation.c
index 08458f278..5f43bfe80 100644
--- a/src/conversation/gnunet-service-conversation.c
+++ b/src/conversation/gnunet-service-conversation.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, 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
@@ -226,9 +226,9 @@ static struct Channel *
226find_channel_by_line (struct Line *line, 226find_channel_by_line (struct Line *line,
227 uint32_t cid) 227 uint32_t cid)
228{ 228{
229 struct Channel *ch; 229 for (struct Channel *ch = line->channel_head;
230 230 NULL != ch;
231 for (ch = line->channel_head; NULL != ch; ch = ch->next) 231 ch = ch->next)
232 if (cid == ch->cid) 232 if (cid == ch->cid)
233 return ch; 233 return ch;
234 return NULL; 234 return NULL;
@@ -314,11 +314,6 @@ destroy_line_cadet_channels (struct Channel *ch)
314{ 314{
315 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 315 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
316 "Destroying cadet channels\n"); 316 "Destroying cadet channels\n");
317 if (NULL != ch->mq)
318 {
319 GNUNET_MQ_destroy (ch->mq);
320 ch->mq = NULL;
321 }
322 if (NULL != ch->channel) 317 if (NULL != ch->channel)
323 GNUNET_CADET_channel_destroy (ch->channel); 318 GNUNET_CADET_channel_destroy (ch->channel);
324} 319}
@@ -586,59 +581,6 @@ handle_client_resume_message (void *cls,
586 581
587 582
588/** 583/**
589 * Function to handle call request from the client
590 *
591 * @param cls the `struct Line` the message is about
592 * @param msg the message from the client
593 */
594static void
595handle_client_call_message (void *cls,
596 const struct ClientCallMessage *msg)
597{
598 struct Line *line = cls;
599 struct Channel *ch;
600 struct GNUNET_MQ_Envelope *e;
601 struct CadetPhoneRingMessage *ring;
602 struct CadetPhoneRingInfoPS rs;
603
604 line->line_port = msg->line_port;
605 rs.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING);
606 rs.purpose.size = htonl (sizeof (struct CadetPhoneRingInfoPS));
607 rs.line_port = line->line_port;
608 rs.target_peer = msg->target;
609 rs.expiration_time
610 = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (RING_TIMEOUT));
611
612 ch = GNUNET_new (struct Channel);
613 ch->line = line;
614 GNUNET_CONTAINER_DLL_insert (line->channel_head,
615 line->channel_tail,
616 ch);
617 ch->status = CS_CALLER_CALLING;
618 ch->channel = GNUNET_CADET_channel_create (cadet,
619 ch,
620 &msg->target,
621 &msg->line_port,
622 GNUNET_CADET_OPTION_RELIABLE);
623 ch->mq = GNUNET_CADET_mq_create (ch->channel);
624 e = GNUNET_MQ_msg (ring,
625 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_RING);
626 GNUNET_CRYPTO_ecdsa_key_get_public (&msg->caller_id,
627 &ring->caller_id);
628 ring->expiration_time = rs.expiration_time;
629 GNUNET_assert (GNUNET_OK ==
630 GNUNET_CRYPTO_ecdsa_sign (&msg->caller_id,
631 &rs.purpose,
632 &ring->signature));
633 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
634 "Sending RING message via CADET\n");
635 GNUNET_MQ_send (ch->mq,
636 e);
637 GNUNET_SERVICE_client_continue (line->client);
638}
639
640
641/**
642 * Transmission of audio data via cadet channel finished. 584 * Transmission of audio data via cadet channel finished.
643 * 585 *
644 * @param cls the `struct Channel` we are transmitting for 586 * @param cls the `struct Channel` we are transmitting for
@@ -678,7 +620,7 @@ handle_client_audio_message (void *cls,
678 const struct ClientAudioMessage *msg) 620 const struct ClientAudioMessage *msg)
679{ 621{
680 struct Line *line = cls; 622 struct Line *line = cls;
681 struct ClientAudioMessage *mam; 623 struct CadetAudioMessage *mam;
682 struct Channel *ch; 624 struct Channel *ch;
683 size_t size; 625 size_t size;
684 626
@@ -730,6 +672,10 @@ handle_client_audio_message (void *cls,
730 ch->env = NULL; 672 ch->env = NULL;
731 } 673 }
732 674
675 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
676 "Received %u bytes of AUDIO data from client CID %u\n",
677 (unsigned int) size,
678 msg->cid);
733 ch->env = GNUNET_MQ_msg_extra (mam, 679 ch->env = GNUNET_MQ_msg_extra (mam,
734 size, 680 size,
735 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_AUDIO); 681 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_AUDIO);
@@ -750,26 +696,18 @@ handle_client_audio_message (void *cls,
750 * Function to handle a ring message incoming over cadet 696 * Function to handle a ring message incoming over cadet
751 * 697 *
752 * @param cls closure, NULL 698 * @param cls closure, NULL
753 * @param channel the channel over which the message arrived 699 * @param msg the incoming message
754 * @param channel_ctx the channel context, can be NULL
755 * or point to the `struct Channel`
756 * @param message the incoming message
757 * @return #GNUNET_OK
758 */ 700 */
759static int 701static void
760handle_cadet_ring_message (void *cls, 702handle_cadet_ring_message (void *cls,
761 struct GNUNET_CADET_Channel *channel, 703 const struct CadetPhoneRingMessage *msg)
762 void **channel_ctx,
763 const struct GNUNET_MessageHeader *message)
764{ 704{
765 struct Channel *ch = *channel_ctx; 705 struct Channel *ch = cls;
766 struct Line *line = ch->line; 706 struct Line *line = ch->line;
767 const struct CadetPhoneRingMessage *msg;
768 struct GNUNET_MQ_Envelope *env; 707 struct GNUNET_MQ_Envelope *env;
769 struct ClientPhoneRingMessage *cring; 708 struct ClientPhoneRingMessage *cring;
770 struct CadetPhoneRingInfoPS rs; 709 struct CadetPhoneRingInfoPS rs;
771 710
772 msg = (const struct CadetPhoneRingMessage *) message;
773 rs.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING); 711 rs.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING);
774 rs.purpose.size = htonl (sizeof (struct CadetPhoneRingInfoPS)); 712 rs.purpose.size = htonl (sizeof (struct CadetPhoneRingInfoPS));
775 rs.line_port = line->line_port; 713 rs.line_port = line->line_port;
@@ -783,7 +721,8 @@ handle_cadet_ring_message (void *cls,
783 &msg->caller_id)) 721 &msg->caller_id))
784 { 722 {
785 GNUNET_break_op (0); 723 GNUNET_break_op (0);
786 return GNUNET_SYSERR; 724 destroy_line_cadet_channels (ch);
725 return;
787 } 726 }
788 if (0 == GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (msg->expiration_time)).rel_value_us) 727 if (0 == GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (msg->expiration_time)).rel_value_us)
789 { 728 {
@@ -792,14 +731,16 @@ handle_cadet_ring_message (void *cls,
792 /* Note that our reliance on time here is awkward; better would be 731 /* Note that our reliance on time here is awkward; better would be
793 to use a more complex challenge-response protocol against 732 to use a more complex challenge-response protocol against
794 replay attacks. Left for future work ;-). */ 733 replay attacks. Left for future work ;-). */
795 return GNUNET_SYSERR; 734 destroy_line_cadet_channels (ch);
735 return;
796 } 736 }
797 if (CS_CALLEE_INIT != ch->status) 737 if (CS_CALLEE_INIT != ch->status)
798 { 738 {
799 GNUNET_break_op (0); 739 GNUNET_break_op (0);
800 return GNUNET_SYSERR; 740 destroy_line_cadet_channels (ch);
741 return;
801 } 742 }
802 GNUNET_CADET_receive_done (channel); 743 GNUNET_CADET_receive_done (ch->channel);
803 ch->status = CS_CALLEE_RINGING; 744 ch->status = CS_CALLEE_RINGING;
804 env = GNUNET_MQ_msg (cring, 745 env = GNUNET_MQ_msg (cring,
805 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RING); 746 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RING);
@@ -810,34 +751,27 @@ handle_cadet_ring_message (void *cls,
810 (unsigned int) ch->cid); 751 (unsigned int) ch->cid);
811 GNUNET_MQ_send (line->mq, 752 GNUNET_MQ_send (line->mq,
812 env); 753 env);
813 return GNUNET_OK;
814} 754}
815 755
816 756
817/** 757/**
818 * Function to handle a hangup message incoming over cadet 758 * Function to handle a hangup message incoming over cadet
819 * 759 *
820 * @param cls closure, NULL 760 * @param cls closure, our `struct Channel *`
821 * @param channel the channel over which the message arrived
822 * @param channel_ctx the channel context, can be NULL
823 * or point to the `struct Channel`
824 * @param message the incoming message 761 * @param message the incoming message
825 * @return #GNUNET_OK
826 */ 762 */
827static int 763static void
828handle_cadet_hangup_message (void *cls, 764handle_cadet_hangup_message (void *cls,
829 struct GNUNET_CADET_Channel *channel, 765 const struct CadetPhoneHangupMessage *message)
830 void **channel_ctx,
831 const struct GNUNET_MessageHeader *message)
832{ 766{
833 struct Channel *ch = *channel_ctx; 767 struct Channel *ch = cls;
834 struct Line *line = ch->line; 768 struct Line *line = ch->line;
835 struct GNUNET_MQ_Envelope *env; 769 struct GNUNET_MQ_Envelope *env;
836 struct ClientPhoneHangupMessage *hup; 770 struct ClientPhoneHangupMessage *hup;
837 enum ChannelStatus status; 771 enum ChannelStatus status;
838 uint32_t cid; 772 uint32_t cid;
839 773
840 GNUNET_CADET_receive_done (channel); 774 GNUNET_CADET_receive_done (ch->channel);
841 cid = ch->cid; 775 cid = ch->cid;
842 status = ch->status; 776 status = ch->status;
843 destroy_line_cadet_channels (ch); 777 destroy_line_cadet_channels (ch);
@@ -845,17 +779,17 @@ handle_cadet_hangup_message (void *cls,
845 { 779 {
846 case CS_CALLEE_INIT: 780 case CS_CALLEE_INIT:
847 GNUNET_break_op (0); 781 GNUNET_break_op (0);
848 return GNUNET_OK; 782 return;
849 case CS_CALLEE_RINGING: 783 case CS_CALLEE_RINGING:
850 case CS_CALLEE_CONNECTED: 784 case CS_CALLEE_CONNECTED:
851 break; 785 break;
852 case CS_CALLEE_SHUTDOWN: 786 case CS_CALLEE_SHUTDOWN:
853 return GNUNET_OK; 787 return;
854 case CS_CALLER_CALLING: 788 case CS_CALLER_CALLING:
855 case CS_CALLER_CONNECTED: 789 case CS_CALLER_CONNECTED:
856 break; 790 break;
857 case CS_CALLER_SHUTDOWN: 791 case CS_CALLER_SHUTDOWN:
858 return GNUNET_OK; 792 return;
859 } 793 }
860 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 794 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
861 "Sending HANG UP message to client\n"); 795 "Sending HANG UP message to client\n");
@@ -864,33 +798,25 @@ handle_cadet_hangup_message (void *cls,
864 hup->cid = cid; 798 hup->cid = cid;
865 GNUNET_MQ_send (line->mq, 799 GNUNET_MQ_send (line->mq,
866 env); 800 env);
867 return GNUNET_OK;
868} 801}
869 802
870 803
871/** 804/**
872 * Function to handle a pickup message incoming over cadet 805 * Function to handle a pickup message incoming over cadet
873 * 806 *
874 * @param cls closure, NULL 807 * @param cls closure, our `struct Channel *`
875 * @param channel the channel over which the message arrived
876 * @param channel_ctx the channel context, can be NULL
877 * or point to the `struct Channel`
878 * @param message the incoming message 808 * @param message the incoming message
879 * @return #GNUNET_OK if message was OK,
880 * #GNUNET_SYSERR if message violated the protocol
881 */ 809 */
882static int 810static void
883handle_cadet_pickup_message (void *cls, 811handle_cadet_pickup_message (void *cls,
884 struct GNUNET_CADET_Channel *channel, 812 const struct CadetPhonePickupMessage *message)
885 void **channel_ctx,
886 const struct GNUNET_MessageHeader *message)
887{ 813{
888 struct Channel *ch = *channel_ctx; 814 struct Channel *ch = cls;
889 struct Line *line = ch->line; 815 struct Line *line = ch->line;
890 struct GNUNET_MQ_Envelope *env; 816 struct GNUNET_MQ_Envelope *env;
891 struct ClientPhonePickedupMessage *pick; 817 struct ClientPhonePickedupMessage *pick;
892 818
893 GNUNET_CADET_receive_done (channel); 819 GNUNET_CADET_receive_done (ch->channel);
894 switch (ch->status) 820 switch (ch->status)
895 { 821 {
896 case CS_CALLEE_INIT: 822 case CS_CALLEE_INIT:
@@ -898,21 +824,21 @@ handle_cadet_pickup_message (void *cls,
898 case CS_CALLEE_CONNECTED: 824 case CS_CALLEE_CONNECTED:
899 GNUNET_break_op (0); 825 GNUNET_break_op (0);
900 destroy_line_cadet_channels (ch); 826 destroy_line_cadet_channels (ch);
901 return GNUNET_SYSERR; 827 return;
902 case CS_CALLEE_SHUTDOWN: 828 case CS_CALLEE_SHUTDOWN:
903 GNUNET_break_op (0); 829 GNUNET_break_op (0);
904 destroy_line_cadet_channels (ch); 830 destroy_line_cadet_channels (ch);
905 return GNUNET_SYSERR; 831 return;
906 case CS_CALLER_CALLING: 832 case CS_CALLER_CALLING:
907 ch->status = CS_CALLER_CONNECTED; 833 ch->status = CS_CALLER_CONNECTED;
908 break; 834 break;
909 case CS_CALLER_CONNECTED: 835 case CS_CALLER_CONNECTED:
910 GNUNET_break_op (0); 836 GNUNET_break_op (0);
911 return GNUNET_OK; 837 return;
912 case CS_CALLER_SHUTDOWN: 838 case CS_CALLER_SHUTDOWN:
913 GNUNET_break_op (0); 839 GNUNET_break_op (0);
914 mq_done_finish_caller_shutdown (ch); 840 mq_done_finish_caller_shutdown (ch);
915 return GNUNET_SYSERR; 841 return;
916 } 842 }
917 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 843 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
918 "Sending PICKED UP message to client\n"); 844 "Sending PICKED UP message to client\n");
@@ -921,32 +847,25 @@ handle_cadet_pickup_message (void *cls,
921 pick->cid = ch->cid; 847 pick->cid = ch->cid;
922 GNUNET_MQ_send (line->mq, 848 GNUNET_MQ_send (line->mq,
923 env); 849 env);
924 return GNUNET_OK;
925} 850}
926 851
927 852
928/** 853/**
929 * Function to handle a suspend message incoming over cadet 854 * Function to handle a suspend message incoming over cadet
930 * 855 *
931 * @param cls closure, NULL 856 * @param cls closure, our `struct Channel *`
932 * @param channel the channel over which the message arrived
933 * @param channel_ctx the channel context, can be NULL
934 * or point to the `struct Channel`
935 * @param message the incoming message 857 * @param message the incoming message
936 * @return #GNUNET_OK
937 */ 858 */
938static int 859static void
939handle_cadet_suspend_message (void *cls, 860handle_cadet_suspend_message (void *cls,
940 struct GNUNET_CADET_Channel *channel, 861 const struct CadetPhoneSuspendMessage *message)
941 void **channel_ctx,
942 const struct GNUNET_MessageHeader *message)
943{ 862{
944 struct Channel *ch = *channel_ctx; 863 struct Channel *ch = cls;
945 struct Line *line = ch->line; 864 struct Line *line = ch->line;
946 struct GNUNET_MQ_Envelope *env; 865 struct GNUNET_MQ_Envelope *env;
947 struct ClientPhoneSuspendMessage *suspend; 866 struct ClientPhoneSuspendMessage *suspend;
948 867
949 GNUNET_CADET_receive_done (channel); 868 GNUNET_CADET_receive_done (ch->channel);
950 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 869 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
951 "Suspending channel CID: %u\n", 870 "Suspending channel CID: %u\n",
952 ch->cid); 871 ch->cid);
@@ -962,7 +881,7 @@ handle_cadet_suspend_message (void *cls,
962 ch->suspended_remote = GNUNET_YES; 881 ch->suspended_remote = GNUNET_YES;
963 break; 882 break;
964 case CS_CALLEE_SHUTDOWN: 883 case CS_CALLEE_SHUTDOWN:
965 return GNUNET_OK; 884 return;
966 case CS_CALLER_CALLING: 885 case CS_CALLER_CALLING:
967 GNUNET_break_op (0); 886 GNUNET_break_op (0);
968 break; 887 break;
@@ -970,51 +889,39 @@ handle_cadet_suspend_message (void *cls,
970 ch->suspended_remote = GNUNET_YES; 889 ch->suspended_remote = GNUNET_YES;
971 break; 890 break;
972 case CS_CALLER_SHUTDOWN: 891 case CS_CALLER_SHUTDOWN:
973 return GNUNET_OK; 892 return;
974 } 893 }
975 env = GNUNET_MQ_msg (suspend, 894 env = GNUNET_MQ_msg (suspend,
976 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_SUSPEND); 895 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_SUSPEND);
977 suspend->cid = ch->cid; 896 suspend->cid = ch->cid;
978 GNUNET_MQ_send (line->mq, 897 GNUNET_MQ_send (line->mq,
979 env); 898 env);
980 return GNUNET_OK;
981} 899}
982 900
983 901
984/** 902/**
985 * Function to handle a resume message incoming over cadet 903 * Function to handle a resume message incoming over cadet
986 * 904 *
987 * @param cls closure, NULL 905 * @param cls closure, our `struct Channel *`
988 * @param channel the channel over which the message arrived 906 * @param msg the incoming message
989 * @param channel_ctx the channel context, can be NULL
990 * or point to the `struct Channel`
991 * @param message the incoming message
992 * @return #GNUNET_OK
993 */ 907 */
994static int 908static void
995handle_cadet_resume_message (void *cls, 909handle_cadet_resume_message (void *cls,
996 struct GNUNET_CADET_Channel *channel, 910 const struct CadetPhoneResumeMessage *msg)
997 void **channel_ctx,
998 const struct GNUNET_MessageHeader *message)
999{ 911{
1000 struct Channel *ch = *channel_ctx; 912 struct Channel *ch = cls;
1001 struct Line *line; 913 struct Line *line;
1002 struct GNUNET_MQ_Envelope *env; 914 struct GNUNET_MQ_Envelope *env;
1003 struct ClientPhoneResumeMessage *resume; 915 struct ClientPhoneResumeMessage *resume;
1004 916
1005 if (NULL == ch)
1006 {
1007 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1008 "RESUME message received for non-existing line, dropping channel.\n");
1009 return GNUNET_SYSERR;
1010 }
1011 line = ch->line; 917 line = ch->line;
1012 GNUNET_CADET_receive_done (channel); 918 GNUNET_CADET_receive_done (ch->channel);
1013 if (GNUNET_YES != ch->suspended_remote) 919 if (GNUNET_YES != ch->suspended_remote)
1014 { 920 {
1015 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 921 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1016 "RESUME message received for non-suspended channel, dropping channel.\n"); 922 "RESUME message received for non-suspended channel, dropping channel.\n");
1017 return GNUNET_SYSERR; 923 destroy_line_cadet_channels (ch);
924 return;
1018 } 925 }
1019 switch (ch->status) 926 switch (ch->status)
1020 { 927 {
@@ -1028,7 +935,7 @@ handle_cadet_resume_message (void *cls,
1028 ch->suspended_remote = GNUNET_NO; 935 ch->suspended_remote = GNUNET_NO;
1029 break; 936 break;
1030 case CS_CALLEE_SHUTDOWN: 937 case CS_CALLEE_SHUTDOWN:
1031 return GNUNET_OK; 938 return;
1032 case CS_CALLER_CALLING: 939 case CS_CALLER_CALLING:
1033 GNUNET_break (0); 940 GNUNET_break (0);
1034 break; 941 break;
@@ -1036,41 +943,47 @@ handle_cadet_resume_message (void *cls,
1036 ch->suspended_remote = GNUNET_NO; 943 ch->suspended_remote = GNUNET_NO;
1037 break; 944 break;
1038 case CS_CALLER_SHUTDOWN: 945 case CS_CALLER_SHUTDOWN:
1039 return GNUNET_OK; 946 return;
1040 } 947 }
1041 env = GNUNET_MQ_msg (resume, 948 env = GNUNET_MQ_msg (resume,
1042 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RESUME); 949 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RESUME);
1043 resume->cid = ch->cid; 950 resume->cid = ch->cid;
1044 GNUNET_MQ_send (line->mq, 951 GNUNET_MQ_send (line->mq,
1045 env); 952 env);
1046 return GNUNET_OK;
1047} 953}
1048 954
1049 955
1050/** 956/**
1051 * Function to handle an audio message incoming over cadet 957 * Function to check an audio message incoming over cadet
1052 * 958 *
1053 * @param cls closure, NULL 959 * @param cls closure, our `struct Channel *`
1054 * @param channel the channel over which the message arrived 960 * @param msg the incoming message
1055 * @param channel_ctx the channel context, can be NULL 961 * @return #GNUNET_OK (always)
1056 * or point to the `struct Channel`
1057 * @param message the incoming message
1058 * @return #GNUNET_OK
1059 */ 962 */
1060static int 963static int
964check_cadet_audio_message (void *cls,
965 const struct CadetAudioMessage *msg)
966{
967 return GNUNET_OK; /* any payload is fine */
968}
969
970
971/**
972 * Function to handle an audio message incoming over cadet
973 *
974 * @param cls closure, our `struct Channel *`
975 * @param msg the incoming message
976 */
977static void
1061handle_cadet_audio_message (void *cls, 978handle_cadet_audio_message (void *cls,
1062 struct GNUNET_CADET_Channel *channel, 979 const struct CadetAudioMessage *msg)
1063 void **channel_ctx,
1064 const struct GNUNET_MessageHeader *message)
1065{ 980{
1066 struct Channel *ch = *channel_ctx; 981 struct Channel *ch = cls;
1067 const struct CadetAudioMessage *msg; 982 size_t msize = ntohs (msg->header.size) - sizeof (struct CadetAudioMessage);
1068 size_t msize = ntohs (message->size) - sizeof (struct CadetAudioMessage);
1069 struct GNUNET_MQ_Envelope *env; 983 struct GNUNET_MQ_Envelope *env;
1070 struct ClientAudioMessage *cam; 984 struct ClientAudioMessage *cam;
1071 985
1072 msg = (const struct CadetAudioMessage *) message; 986 GNUNET_CADET_receive_done (ch->channel);
1073 GNUNET_CADET_receive_done (channel);
1074 if ( (GNUNET_YES == ch->suspended_local) || 987 if ( (GNUNET_YES == ch->suspended_local) ||
1075 (GNUNET_YES == ch->suspended_remote) ) 988 (GNUNET_YES == ch->suspended_remote) )
1076 { 989 {
@@ -1078,7 +991,7 @@ handle_cadet_audio_message (void *cls,
1078 "Received %u bytes of AUDIO data on suspended channel CID %u; dropping\n", 991 "Received %u bytes of AUDIO data on suspended channel CID %u; dropping\n",
1079 (unsigned int) msize, 992 (unsigned int) msize,
1080 ch->cid); 993 ch->cid);
1081 return GNUNET_OK; 994 return;
1082 } 995 }
1083 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 996 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1084 "Forwarding %u bytes of AUDIO data to client CID %u\n", 997 "Forwarding %u bytes of AUDIO data to client CID %u\n",
@@ -1093,44 +1006,6 @@ handle_cadet_audio_message (void *cls,
1093 msize); 1006 msize);
1094 GNUNET_MQ_send (ch->line->mq, 1007 GNUNET_MQ_send (ch->line->mq,
1095 env); 1008 env);
1096 return GNUNET_OK;
1097}
1098
1099
1100/**
1101 * Method called whenever another peer has added us to a channel
1102 * the other peer initiated.
1103 *
1104 * @param cls the `struct Line` receiving a connection
1105 * @param channel new handle to the channel
1106 * @param initiator peer that started the channel
1107 * @param port port
1108 * @param options channel option flags
1109 * @return initial channel context for the channel
1110 */
1111static void *
1112inbound_channel (void *cls,
1113 struct GNUNET_CADET_Channel *channel,
1114 const struct GNUNET_PeerIdentity *initiator,
1115 const struct GNUNET_HashCode *port,
1116 enum GNUNET_CADET_ChannelOption options)
1117{
1118 struct Line *line = cls;
1119 struct Channel *ch;
1120
1121 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1122 "Received incoming cadet channel on line %p\n",
1123 line);
1124 ch = GNUNET_new (struct Channel);
1125 ch->status = CS_CALLEE_INIT;
1126 ch->line = line;
1127 ch->channel = channel;
1128 ch->mq = GNUNET_CADET_mq_create (ch->channel);
1129 ch->cid = line->cid_gen++;
1130 GNUNET_CONTAINER_DLL_insert (line->channel_head,
1131 line->channel_tail,
1132 ch);
1133 return ch;
1134} 1009}
1135 1010
1136 1011
@@ -1140,26 +1015,16 @@ inbound_channel (void *cls,
1140 * 1015 *
1141 * @param cls closure (set from #GNUNET_CADET_connect) 1016 * @param cls closure (set from #GNUNET_CADET_connect)
1142 * @param channel connection to the other end (henceforth invalid) 1017 * @param channel connection to the other end (henceforth invalid)
1143 * @param channel_ctx place where local state associated
1144 * with the channel is stored;
1145 * may point to the `struct Channel`
1146 */ 1018 */
1147static void 1019static void
1148inbound_end (void *cls, 1020inbound_end (void *cls,
1149 const struct GNUNET_CADET_Channel *channel, 1021 const struct GNUNET_CADET_Channel *channel)
1150 void *channel_ctx)
1151{ 1022{
1152 struct Channel *ch = channel_ctx; 1023 struct Channel *ch = cls;
1153 struct Line *line; 1024 struct Line *line = ch->line;
1154 struct GNUNET_MQ_Envelope *env; 1025 struct GNUNET_MQ_Envelope *env;
1155 struct ClientPhoneHangupMessage *hup; 1026 struct ClientPhoneHangupMessage *hup;
1156 1027
1157 if (NULL == ch)
1158 {
1159 GNUNET_break (0);
1160 return;
1161 }
1162 line = ch->line;
1163 GNUNET_assert (channel == ch->channel); 1028 GNUNET_assert (channel == ch->channel);
1164 ch->channel = NULL; 1029 ch->channel = NULL;
1165 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1030 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -1185,7 +1050,6 @@ inbound_end (void *cls,
1185 } 1050 }
1186 break; 1051 break;
1187 } 1052 }
1188 destroy_line_cadet_channels (ch);
1189 if (NULL != line) 1053 if (NULL != line)
1190 GNUNET_CONTAINER_DLL_remove (line->channel_head, 1054 GNUNET_CONTAINER_DLL_remove (line->channel_head,
1191 line->channel_tail, 1055 line->channel_tail,
@@ -1195,6 +1059,116 @@ inbound_end (void *cls,
1195 1059
1196 1060
1197/** 1061/**
1062 * Function to handle call request from the client
1063 *
1064 * @param cls the `struct Line` the message is about
1065 * @param msg the message from the client
1066 */
1067static void
1068handle_client_call_message (void *cls,
1069 const struct ClientCallMessage *msg)
1070{
1071 struct Line *line = cls;
1072 struct Channel *ch = GNUNET_new (struct Channel);
1073 struct GNUNET_MQ_MessageHandler cadet_handlers[] = {
1074 GNUNET_MQ_hd_fixed_size (cadet_hangup_message,
1075 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_HANG_UP,
1076 struct CadetPhoneHangupMessage,
1077 ch),
1078 GNUNET_MQ_hd_fixed_size (cadet_pickup_message,
1079 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_PICK_UP,
1080 struct CadetPhonePickupMessage,
1081 ch),
1082 GNUNET_MQ_hd_fixed_size (cadet_suspend_message,
1083 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_SUSPEND,
1084 struct CadetPhoneSuspendMessage,
1085 ch),
1086 GNUNET_MQ_hd_fixed_size (cadet_resume_message,
1087 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_RESUME,
1088 struct CadetPhoneResumeMessage,
1089 ch),
1090 GNUNET_MQ_hd_var_size (cadet_audio_message,
1091 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_AUDIO,
1092 struct CadetAudioMessage,
1093 ch),
1094 GNUNET_MQ_handler_end ()
1095 };
1096 struct GNUNET_MQ_Envelope *e;
1097 struct CadetPhoneRingMessage *ring;
1098 struct CadetPhoneRingInfoPS rs;
1099
1100 line->line_port = msg->line_port;
1101 rs.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING);
1102 rs.purpose.size = htonl (sizeof (struct CadetPhoneRingInfoPS));
1103 rs.line_port = line->line_port;
1104 rs.target_peer = msg->target;
1105 rs.expiration_time
1106 = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (RING_TIMEOUT));
1107 ch->line = line;
1108 GNUNET_CONTAINER_DLL_insert (line->channel_head,
1109 line->channel_tail,
1110 ch);
1111 ch->status = CS_CALLER_CALLING;
1112 ch->channel = GNUNET_CADET_channel_create (cadet,
1113 ch,
1114 &msg->target,
1115 &msg->line_port,
1116 GNUNET_CADET_OPTION_RELIABLE,
1117 NULL,
1118 &inbound_end,
1119 cadet_handlers);
1120 ch->mq = GNUNET_CADET_get_mq (ch->channel);
1121 e = GNUNET_MQ_msg (ring,
1122 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_RING);
1123 GNUNET_CRYPTO_ecdsa_key_get_public (&msg->caller_id,
1124 &ring->caller_id);
1125 ring->expiration_time = rs.expiration_time;
1126 GNUNET_assert (GNUNET_OK ==
1127 GNUNET_CRYPTO_ecdsa_sign (&msg->caller_id,
1128 &rs.purpose,
1129 &ring->signature));
1130 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1131 "Sending RING message via CADET\n");
1132 GNUNET_MQ_send (ch->mq,
1133 e);
1134 GNUNET_SERVICE_client_continue (line->client);
1135}
1136
1137
1138/**
1139 * Method called whenever another peer has added us to a channel
1140 * the other peer initiated.
1141 *
1142 * @param cls the `struct Line` receiving a connection
1143 * @param channel new handle to the channel
1144 * @param initiator peer that started the channel
1145 * @return initial channel context for the channel
1146 */
1147static void *
1148inbound_channel (void *cls,
1149 struct GNUNET_CADET_Channel *channel,
1150 const struct GNUNET_PeerIdentity *initiator)
1151{
1152 struct Line *line = cls;
1153 struct Channel *ch;
1154
1155 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1156 "Received incoming cadet channel on line %p\n",
1157 line);
1158 ch = GNUNET_new (struct Channel);
1159 ch->status = CS_CALLEE_INIT;
1160 ch->line = line;
1161 ch->channel = channel;
1162 ch->mq = GNUNET_CADET_get_mq (ch->channel);
1163 ch->cid = line->cid_gen++;
1164 GNUNET_CONTAINER_DLL_insert (line->channel_head,
1165 line->channel_tail,
1166 ch);
1167 return ch;
1168}
1169
1170
1171/**
1198 * A client connected. Initialize the `struct Line` data structure. 1172 * A client connected. Initialize the `struct Line` data structure.
1199 * 1173 *
1200 * @param cls closure, NULL 1174 * @param cls closure, NULL
@@ -1260,12 +1234,42 @@ handle_client_register_message (void *cls,
1260 const struct ClientPhoneRegisterMessage *msg) 1234 const struct ClientPhoneRegisterMessage *msg)
1261{ 1235{
1262 struct Line *line = cls; 1236 struct Line *line = cls;
1237 struct GNUNET_MQ_MessageHandler cadet_handlers[] = {
1238 GNUNET_MQ_hd_fixed_size (cadet_ring_message,
1239 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_RING,
1240 struct CadetPhoneRingMessage,
1241 NULL),
1242 GNUNET_MQ_hd_fixed_size (cadet_hangup_message,
1243 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_HANG_UP,
1244 struct CadetPhoneHangupMessage,
1245 NULL),
1246 GNUNET_MQ_hd_fixed_size (cadet_pickup_message,
1247 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_PICK_UP,
1248 struct CadetPhonePickupMessage,
1249 NULL),
1250 GNUNET_MQ_hd_fixed_size (cadet_suspend_message,
1251 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_SUSPEND,
1252 struct CadetPhoneSuspendMessage,
1253 NULL),
1254 GNUNET_MQ_hd_fixed_size (cadet_resume_message,
1255 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_RESUME,
1256 struct CadetPhoneResumeMessage,
1257 NULL),
1258 GNUNET_MQ_hd_var_size (cadet_audio_message,
1259 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_AUDIO,
1260 struct CadetAudioMessage,
1261 NULL),
1262 GNUNET_MQ_handler_end ()
1263 };
1263 1264
1264 line->line_port = msg->line_port; 1265 line->line_port = msg->line_port;
1265 line->port = GNUNET_CADET_open_port (cadet, 1266 line->port = GNUNET_CADET_open_port (cadet,
1266 &msg->line_port, 1267 &msg->line_port,
1267 &inbound_channel, 1268 &inbound_channel,
1268 line); 1269 line,
1270 NULL,
1271 &inbound_end,
1272 cadet_handlers);
1269 GNUNET_SERVICE_client_continue (line->client); 1273 GNUNET_SERVICE_client_continue (line->client);
1270} 1274}
1271 1275
@@ -1298,35 +1302,11 @@ run (void *cls,
1298 const struct GNUNET_CONFIGURATION_Handle *c, 1302 const struct GNUNET_CONFIGURATION_Handle *c,
1299 struct GNUNET_SERVICE_Handle *service) 1303 struct GNUNET_SERVICE_Handle *service)
1300{ 1304{
1301 static struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
1302 {&handle_cadet_ring_message,
1303 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_RING,
1304 sizeof (struct CadetPhoneRingMessage)},
1305 {&handle_cadet_hangup_message,
1306 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_HANG_UP,
1307 sizeof (struct CadetPhoneHangupMessage)},
1308 {&handle_cadet_pickup_message,
1309 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_PICK_UP,
1310 sizeof (struct CadetPhonePickupMessage)},
1311 {&handle_cadet_suspend_message,
1312 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_SUSPEND,
1313 sizeof (struct CadetPhoneSuspendMessage)},
1314 {&handle_cadet_resume_message,
1315 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_RESUME,
1316 sizeof (struct CadetPhoneResumeMessage)},
1317 {&handle_cadet_audio_message, GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_AUDIO,
1318 0},
1319 {NULL, 0, 0}
1320 };
1321
1322 cfg = c; 1305 cfg = c;
1323 GNUNET_assert (GNUNET_OK == 1306 GNUNET_assert (GNUNET_OK ==
1324 GNUNET_CRYPTO_get_peer_identity (cfg, 1307 GNUNET_CRYPTO_get_peer_identity (cfg,
1325 &my_identity)); 1308 &my_identity));
1326 cadet = GNUNET_CADET_connect (cfg, 1309 cadet = GNUNET_CADET_connect (cfg);
1327 NULL,
1328 &inbound_end,
1329 cadet_handlers);
1330 if (NULL == cadet) 1310 if (NULL == cadet)
1331 { 1311 {
1332 GNUNET_break (0); 1312 GNUNET_break (0);
@@ -1338,7 +1318,6 @@ run (void *cls,
1338} 1318}
1339 1319
1340 1320
1341
1342/** 1321/**
1343 * Define "main" method using service macro. 1322 * Define "main" method using service macro.
1344 */ 1323 */
@@ -1353,26 +1332,26 @@ GNUNET_SERVICE_MAIN
1353 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_REGISTER, 1332 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_REGISTER,
1354 struct ClientPhoneRegisterMessage, 1333 struct ClientPhoneRegisterMessage,
1355 NULL), 1334 NULL),
1356 GNUNET_MQ_hd_fixed_size (client_pickup_message, 1335 GNUNET_MQ_hd_fixed_size (client_pickup_message,
1357 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICK_UP, 1336 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICK_UP,
1358 struct ClientPhonePickupMessage, 1337 struct ClientPhonePickupMessage,
1359 NULL), 1338 NULL),
1360 GNUNET_MQ_hd_fixed_size (client_suspend_message, 1339 GNUNET_MQ_hd_fixed_size (client_suspend_message,
1361 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_SUSPEND, 1340 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_SUSPEND,
1362 struct ClientPhoneSuspendMessage, 1341 struct ClientPhoneSuspendMessage,
1363 NULL), 1342 NULL),
1364 GNUNET_MQ_hd_fixed_size (client_resume_message, 1343 GNUNET_MQ_hd_fixed_size (client_resume_message,
1365 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RESUME, 1344 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RESUME,
1366 struct ClientPhoneResumeMessage, 1345 struct ClientPhoneResumeMessage,
1367 NULL), 1346 NULL),
1368 GNUNET_MQ_hd_fixed_size (client_hangup_message, 1347 GNUNET_MQ_hd_fixed_size (client_hangup_message,
1369 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP, 1348 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP,
1370 struct ClientPhoneHangupMessage, 1349 struct ClientPhoneHangupMessage,
1371 NULL), 1350 NULL),
1372 GNUNET_MQ_hd_fixed_size (client_call_message, 1351 GNUNET_MQ_hd_fixed_size (client_call_message,
1373 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_CALL, 1352 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_CALL,
1374 struct ClientCallMessage, 1353 struct ClientCallMessage,
1375 NULL), 1354 NULL),
1376 GNUNET_MQ_hd_var_size (client_audio_message, 1355 GNUNET_MQ_hd_var_size (client_audio_message,
1377 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO, 1356 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO,
1378 struct ClientAudioMessage, 1357 struct ClientAudioMessage,
diff --git a/src/conversation/gnunet_gst.c b/src/conversation/gnunet_gst.c
index 91c6ddccb..52cb2ccbc 100644
--- a/src/conversation/gnunet_gst.c
+++ b/src/conversation/gnunet_gst.c
@@ -29,6 +29,7 @@
29 */ 29 */
30static struct GNUNET_CONFIGURATION_Handle *cfg; 30static struct GNUNET_CONFIGURATION_Handle *cfg;
31 31
32
32void 33void
33dump_buffer(unsigned n, const unsigned char* buf) 34dump_buffer(unsigned n, const unsigned char* buf)
34{ 35{
@@ -61,15 +62,13 @@ BREAKOUT:
61/*** 62/***
62 * load gnunet configuration 63 * load gnunet configuration
63 */ 64 */
64 void 65void
65gg_load_configuration(GNUNET_gstData * d) 66gg_load_configuration(GNUNET_gstData * d)
66{ 67{
67 char *audiobackend_string; 68 char *audiobackend_string;
68 cfg = GNUNET_CONFIGURATION_create(); 69 cfg = GNUNET_CONFIGURATION_create();
69 GNUNET_CONFIGURATION_load(cfg, "mediahelper.conf"); 70 GNUNET_CONFIGURATION_load(cfg, "mediahelper.conf");
70 71
71 char *section = "MEDIAHELPER";
72
73 GNUNET_CONFIGURATION_get_value_string(cfg, "MEDIAHELPER", "JACK_PP_IN", &d->jack_pp_in); 72 GNUNET_CONFIGURATION_get_value_string(cfg, "MEDIAHELPER", "JACK_PP_IN", &d->jack_pp_in);
74 GNUNET_CONFIGURATION_get_value_string(cfg, "MEDIAHELPER", "JACK_PP_OUT", &d->jack_pp_out); 73 GNUNET_CONFIGURATION_get_value_string(cfg, "MEDIAHELPER", "JACK_PP_OUT", &d->jack_pp_out);
75 74
@@ -77,19 +76,19 @@ gg_load_configuration(GNUNET_gstData * d)
77 76
78 // printf("abstring: %s \n", audiobackend_string); 77 // printf("abstring: %s \n", audiobackend_string);
79 78
80 if ( audiobackend_string == "AUTO" ) 79 if (0 == strcasecmp (audiobackend_string, "AUTO"))
81 { 80 {
82 d->audiobackend = AUTO; 81 d->audiobackend = AUTO;
83 } else if ( audiobackend_string = "JACK" ) 82 } else if (0 == strcasecmp (audiobackend_string, "JACK"))
84 { 83 {
85 d->audiobackend = JACK; 84 d->audiobackend = JACK;
86 } else if ( audiobackend_string = "ALSA" ) 85 } else if (0 == strcasecmp (audiobackend_string, "ALSA"))
87 { 86 {
88 d->audiobackend = ALSA; 87 d->audiobackend = ALSA;
89 } else if ( audiobackend_string = "FAKE" ) 88 } else if (0 == strcasecmp (audiobackend_string, "FAKE"))
90 { 89 {
91 d->audiobackend = FAKE; 90 d->audiobackend = FAKE;
92 } else if ( audiobackend_string = "TEST" ) 91 } else if (0 == strcasecmp (audiobackend_string, "TEST"))
93 { 92 {
94 d->audiobackend = TEST; 93 d->audiobackend = TEST;
95 } else 94 } else
@@ -147,8 +146,6 @@ write_data (const char *ptr, size_t msg_size)
147extern GstFlowReturn 146extern GstFlowReturn
148on_appsink_new_sample (GstElement * element, GNUNET_gstData * d) 147on_appsink_new_sample (GstElement * element, GNUNET_gstData * d)
149{ 148{
150 static unsigned long long toff;
151
152 //size of message including gnunet header 149 //size of message including gnunet header
153 size_t msg_size; 150 size_t msg_size;
154 151
@@ -161,7 +158,6 @@ on_appsink_new_sample (GstElement * element, GNUNET_gstData * d)
161 GstCaps *s_caps; 158 GstCaps *s_caps;
162 char *caps_str; 159 char *caps_str;
163*/ 160*/
164 (d->audio_message)->header.size = htons ((uint16_t) msg_size);
165 161
166 if (gst_app_sink_is_eos(GST_APP_SINK(element))) 162 if (gst_app_sink_is_eos(GST_APP_SINK(element)))
167 return GST_FLOW_OK; 163 return GST_FLOW_OK;
@@ -197,13 +193,7 @@ on_appsink_new_sample (GstElement * element, GNUNET_gstData * d)
197 193
198 // copy the data into audio_message 194 // copy the data into audio_message
199 GNUNET_memcpy (((char *) &(d->audio_message)[1]), map.data, len); 195 GNUNET_memcpy (((char *) &(d->audio_message)[1]), map.data, len);
200/* 196 (d->audio_message)->header.size = htons ((uint16_t) msg_size);
201 toff += msg_size;
202 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
203 "Sending %u bytes of audio data (total: %llu)\n",
204 (unsigned int) msg_size,
205 toff);
206*/
207 if (d->pure_ogg) 197 if (d->pure_ogg)
208 // write the audio_message without the gnunet headers 198 // write the audio_message without the gnunet headers
209 write_data ((const char *) &(d->audio_message)[1], len); 199 write_data ((const char *) &(d->audio_message)[1], len);
@@ -589,14 +579,15 @@ autoaudiosource_child_added (GstChildProxy *child_proxy, GObject *object, gchar
589 g_object_set (object, "buffer-time", (gint64) BUFFER_TIME, "latency-time", (gint64) LATENCY_TIME, NULL); 579 g_object_set (object, "buffer-time", (gint64) BUFFER_TIME, "latency-time", (gint64) LATENCY_TIME, NULL);
590} 580}
591 581
582
592GstElement * 583GstElement *
593get_pipeline(GstElement *element) 584get_pipeline(GstElement *element)
594{ 585{
595 GstPipeline *p; 586 GstPipeline *p;
596 587
597 p = gst_object_get_parent(element); 588 p = GST_PIPELINE (gst_object_get_parent(GST_OBJECT (element)));
598 589
599 return p; 590 return GST_ELEMENT (p);
600} 591}
601 592
602 static void 593 static void
@@ -617,6 +608,7 @@ decoder_ogg_pad_added (GstElement *element,
617 gst_object_unref (sinkpad); 608 gst_object_unref (sinkpad);
618} 609}
619 610
611
620int 612int
621gnunet_read (GNUNET_gstData * d) 613gnunet_read (GNUNET_gstData * d)
622{ 614{
@@ -646,10 +638,13 @@ gnunet_read (GNUNET_gstData * d)
646 else 638 else
647 { 639 {
648 //#endif 640 //#endif
649 GNUNET_SERVER_mst_receive (d->stdin_mst, NULL, 641 GNUNET_MST_from_buffer (d->stdin_mst,
650 readbuf, ret, 642 readbuf,
651 GNUNET_NO, GNUNET_NO); 643 ret,
644 GNUNET_NO,
645 GNUNET_NO);
652 } 646 }
647 return 0;
653} 648}
654 649
655/** 650/**
@@ -657,13 +652,14 @@ gnunet_read (GNUNET_gstData * d)
657 */ 652 */
658static int 653static int
659stdin_receiver (void *cls, 654stdin_receiver (void *cls,
660 void *client,
661 const struct GNUNET_MessageHeader *msg) 655 const struct GNUNET_MessageHeader *msg)
662{ 656{
663 struct AudioMessage *audio; 657 struct AudioMessage *audio;
664 size_t b_len; 658 size_t b_len;
659
665 printf("stdin receiver \n "); 660 printf("stdin receiver \n ");
666 dump_buffer(sizeof(msg), msg); 661 dump_buffer (sizeof(msg),
662 (const unsigned char *) msg);
667 663
668 switch (ntohs (msg->type)) 664 switch (ntohs (msg->type))
669 { 665 {
@@ -711,7 +707,7 @@ get_app(GNUNET_gstData *d, int type)
711 //d->audio_message.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_AUDIO); 707 //d->audio_message.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_AUDIO);
712 708
713 709
714 d->stdin_mst = GNUNET_SERVER_mst_create (&stdin_receiver, d); 710 d->stdin_mst = GNUNET_MST_create (&stdin_receiver, d);
715 711
716 if ( d->stdin_mst == NULL) 712 if ( d->stdin_mst == NULL)
717 printf("stdin_mst = NULL"); 713 printf("stdin_mst = NULL");
@@ -768,7 +764,7 @@ get_coder(GNUNET_gstData *d , int type)
768{ 764{
769 GstBin *bin; 765 GstBin *bin;
770 GstPad *srcpad, *sinkpad, *srcghostpad, *sinkghostpad; 766 GstPad *srcpad, *sinkpad, *srcghostpad, *sinkghostpad;
771 GstCaps *caps, *rtpcaps; 767 GstCaps *rtpcaps;
772 GstElement *encoder, *muxer, *decoder, *demuxer, *jitterbuffer, *rtpcapsfilter; 768 GstElement *encoder, *muxer, *decoder, *demuxer, *jitterbuffer, *rtpcapsfilter;
773 769
774 if ( d->usertp == TRUE ) 770 if ( d->usertp == TRUE )
@@ -892,7 +888,9 @@ get_coder(GNUNET_gstData *d , int type)
892 888
893 return bin; 889 return bin;
894} 890}
895 extern GstBin * 891
892
893extern GstBin *
896get_audiobin(GNUNET_gstData *d , int type) 894get_audiobin(GNUNET_gstData *d , int type)
897{ 895{
898 GstBin *bin; 896 GstBin *bin;
diff --git a/src/conversation/gnunet_gst_def.h b/src/conversation/gnunet_gst_def.h
index 9f519b564..980ed2f48 100644
--- a/src/conversation/gnunet_gst_def.h
+++ b/src/conversation/gnunet_gst_def.h
@@ -65,20 +65,23 @@
65#include <gst/app/gstappsink.h> 65#include <gst/app/gstappsink.h>
66 66
67// sockets 67// sockets
68#ifndef MINGW
69#if HAVE_NETINET_IN_H
68#include <netinet/in.h> 70#include <netinet/in.h>
71#endif
69#include <sys/socket.h> 72#include <sys/socket.h>
70#include <fcntl.h>
71#include <arpa/inet.h> 73#include <arpa/inet.h>
74#include <netdb.h>
75#endif
72 76
73#include <sys/types.h> 77#include <sys/types.h>
74#include <sys/socket.h> 78#include <fcntl.h>
75#include <netdb.h>
76 79
77 80
78//glib stuff 81//glib stuff
79//#include <glib.h> 82//#include <glib.h>
80#include <glib-2.0/glib/gprintf.h> 83#include <glib-2.0/glib/gprintf.h>
81#include <glib-unix.h> 84//#include <glib-unix.h>
82 85
83// static struct AudioMessage *audio_message; 86// static struct AudioMessage *audio_message;
84 87
@@ -91,7 +94,7 @@ struct GNUNET_gstData {
91 94
92 // things 95 // things
93 struct AudioMessage *audio_message; 96 struct AudioMessage *audio_message;
94 struct GNUNET_SERVER_MessageStreamTokenizer *stdin_mst; 97 struct GNUNET_MessageStreamTokenizer *stdin_mst;
95 GstElement *appsrc; 98 GstElement *appsrc;
96 GstElement *appsink; 99 GstElement *appsink;
97 //settings 100 //settings
diff --git a/src/conversation/gnunet_gst_test.c b/src/conversation/gnunet_gst_test.c
index 2ea007583..03f6a4d95 100644
--- a/src/conversation/gnunet_gst_test.c
+++ b/src/conversation/gnunet_gst_test.c
@@ -18,7 +18,7 @@
18 Boston, MA 02110-1301, USA. 18 Boston, MA 02110-1301, USA.
19*/ 19*/
20/** 20/**
21 * @file conversation/gnunet_gst.c 21 * @file conversation/gnunet_gst_test.c
22 * @brief FIXME 22 * @brief FIXME
23 * @author Hark 23 * @author Hark
24 */ 24 */
@@ -30,8 +30,7 @@ int
30main (int argc, char *argv[]) 30main (int argc, char *argv[])
31{ 31{
32 struct GNUNET_gstData *gst; 32 struct GNUNET_gstData *gst;
33 GstBus *bus; 33 // GstBus *bus;
34 GstMessage *msg;
35 GstElement *gnunetsrc, *gnunetsink, *source, *sink, *encoder, *decoder; 34 GstElement *gnunetsrc, *gnunetsink, *source, *sink, *encoder, *decoder;
36 35
37 36
@@ -137,7 +136,7 @@ main (int argc, char *argv[])
137 } 136 }
138 g_print ("Returned, stopping playback\n"); 137 g_print ("Returned, stopping playback\n");
139 138
140 gst_object_unref (bus); 139 // gst_object_unref (bus);
141 gst_element_set_state (GST_ELEMENT(gst->pipeline), GST_STATE_NULL); 140 gst_element_set_state (GST_ELEMENT(gst->pipeline), GST_STATE_NULL);
142 gst_object_unref (gst->pipeline); 141 gst_object_unref (gst->pipeline);
143 142
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/conversation/test_conversation.conf b/src/conversation/test_conversation.conf
index 46ea95d52..e0fd8200c 100644
--- a/src/conversation/test_conversation.conf
+++ b/src/conversation/test_conversation.conf
@@ -2,6 +2,7 @@
2 2
3[conversation] 3[conversation]
4LINE=1 4LINE=1
5PREFIX = valgrind
5 6
6[nse] 7[nse]
7WORKBITS = 0 8WORKBITS = 0
diff --git a/src/conversation/test_conversation_api_twocalls.c b/src/conversation/test_conversation_api_twocalls.c
index 2e2a73e3f..7d2705e70 100644
--- a/src/conversation/test_conversation_api_twocalls.c
+++ b/src/conversation/test_conversation_api_twocalls.c
@@ -187,7 +187,8 @@ play (void *cls,
187 phone_i++; 187 phone_i++;
188 else 188 else
189 { 189 {
190 LOG_DEBUG ("Received unexpected data %.*s\n", 190 LOG_DEBUG ("Received %u bytes of unexpected data `%.*s'\n",
191 (unsigned int) data_size,
191 (int) data_size, 192 (int) data_size,
192 (const char *) data); 193 (const char *) data);
193 } 194 }
diff --git a/src/core/Makefile.am b/src/core/Makefile.am
index ed80bae73..2723151c5 100644
--- a/src/core/Makefile.am
+++ b/src/core/Makefile.am
@@ -71,7 +71,7 @@ check_PROGRAMS = \
71 $(TESTING_TESTS) 71 $(TESTING_TESTS)
72 72
73if ENABLE_TEST_RUN 73if ENABLE_TEST_RUN
74AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; 74AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
75TESTS = $(check_PROGRAMS) 75TESTS = $(check_PROGRAMS)
76endif 76endif
77 77
diff --git a/src/core/core_api.c b/src/core/core_api.c
index b6d8f61d2..ed8ce364d 100644
--- a/src/core/core_api.c
+++ b/src/core/core_api.c
@@ -204,6 +204,11 @@ disconnect_and_free_peer_entry (void *cls,
204 pr)); 204 pr));
205 GNUNET_MQ_destroy (pr->mq); 205 GNUNET_MQ_destroy (pr->mq);
206 GNUNET_assert (NULL == pr->mq); 206 GNUNET_assert (NULL == pr->mq);
207 if (NULL != pr->env)
208 {
209 GNUNET_MQ_discard (pr->env);
210 pr->env = NULL;
211 }
207 GNUNET_free (pr); 212 GNUNET_free (pr);
208 return GNUNET_YES; 213 return GNUNET_YES;
209} 214}
@@ -316,7 +321,7 @@ core_mq_send_impl (struct GNUNET_MQ_Handle *mq,
316 321
317 /* check message size for sanity */ 322 /* check message size for sanity */
318 msize = ntohs (msg->size); 323 msize = ntohs (msg->size);
319 if (msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct SendMessage)) 324 if (msize >= GNUNET_MAX_MESSAGE_SIZE - sizeof (struct SendMessage))
320 { 325 {
321 GNUNET_break (0); 326 GNUNET_break (0);
322 GNUNET_MQ_impl_send_continue (mq); 327 GNUNET_MQ_impl_send_continue (mq);
@@ -331,7 +336,6 @@ core_mq_send_impl (struct GNUNET_MQ_Handle *mq,
331 env = GNUNET_MQ_msg (smr, 336 env = GNUNET_MQ_msg (smr,
332 GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST); 337 GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST);
333 smr->priority = htonl ((uint32_t) priority); 338 smr->priority = htonl ((uint32_t) priority);
334 // smr->deadline = GNUNET_TIME_absolute_hton (deadline);
335 smr->peer = pr->peer; 339 smr->peer = pr->peer;
336 smr->reserved = htonl (0); 340 smr->reserved = htonl (0);
337 smr->size = htons (msize); 341 smr->size = htons (msize);
@@ -344,7 +348,6 @@ core_mq_send_impl (struct GNUNET_MQ_Handle *mq,
344 GNUNET_MESSAGE_TYPE_CORE_SEND, 348 GNUNET_MESSAGE_TYPE_CORE_SEND,
345 msg); 349 msg);
346 sm->priority = htonl ((uint32_t) priority); 350 sm->priority = htonl ((uint32_t) priority);
347 // sm->deadline = GNUNET_TIME_absolute_hton (deadline);
348 sm->peer = pr->peer; 351 sm->peer = pr->peer;
349 sm->cork = htonl ((uint32_t) cork); 352 sm->cork = htonl ((uint32_t) cork);
350 sm->reserved = htonl (0); 353 sm->reserved = htonl (0);
@@ -781,7 +784,6 @@ GNUNET_CORE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
781 const struct GNUNET_MQ_MessageHandler *handlers) 784 const struct GNUNET_MQ_MessageHandler *handlers)
782{ 785{
783 struct GNUNET_CORE_Handle *h; 786 struct GNUNET_CORE_Handle *h;
784 unsigned int hcnt;
785 787
786 h = GNUNET_new (struct GNUNET_CORE_Handle); 788 h = GNUNET_new (struct GNUNET_CORE_Handle);
787 h->cfg = cfg; 789 h->cfg = cfg;
@@ -791,19 +793,10 @@ GNUNET_CORE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
791 h->disconnects = disconnects; 793 h->disconnects = disconnects;
792 h->peers = GNUNET_CONTAINER_multipeermap_create (128, 794 h->peers = GNUNET_CONTAINER_multipeermap_create (128,
793 GNUNET_NO); 795 GNUNET_NO);
794 hcnt = 0; 796 h->handlers = GNUNET_MQ_copy_handlers (handlers);
795 if (NULL != handlers) 797 h->hcnt = GNUNET_MQ_count_handlers (handlers);
796 while (NULL != handlers[hcnt].cb) 798 GNUNET_assert (h->hcnt <
797 hcnt++; 799 (GNUNET_MAX_MESSAGE_SIZE -
798 h->handlers = GNUNET_new_array (hcnt + 1,
799 struct GNUNET_MQ_MessageHandler);
800 if (NULL != handlers)
801 GNUNET_memcpy (h->handlers,
802 handlers,
803 hcnt * sizeof (struct GNUNET_MQ_MessageHandler));
804 h->hcnt = hcnt;
805 GNUNET_assert (hcnt <
806 (GNUNET_SERVER_MAX_MESSAGE_SIZE -
807 sizeof (struct InitMessage)) / sizeof (uint16_t)); 800 sizeof (struct InitMessage)) / sizeof (uint16_t));
808 LOG (GNUNET_ERROR_TYPE_DEBUG, 801 LOG (GNUNET_ERROR_TYPE_DEBUG,
809 "Connecting to CORE service\n"); 802 "Connecting to CORE service\n");
@@ -842,7 +835,7 @@ GNUNET_CORE_disconnect (struct GNUNET_CORE_Handle *handle)
842 GNUNET_MQ_destroy (handle->mq); 835 GNUNET_MQ_destroy (handle->mq);
843 handle->mq = NULL; 836 handle->mq = NULL;
844 } 837 }
845 GNUNET_free (handle->handlers); 838 GNUNET_free_non_null (handle->handlers);
846 GNUNET_free (handle); 839 GNUNET_free (handle);
847} 840}
848 841
diff --git a/src/core/gnunet-core.c b/src/core/gnunet-core.c
index d91dc304d..76b7e8ac4 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_flag ('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 b0d7b24ba..625bf9655 100644
--- a/src/core/gnunet-service-core.c
+++ b/src/core/gnunet-service-core.c
@@ -32,11 +32,19 @@
32#include "gnunet-service-core_typemap.h" 32#include "gnunet-service-core_typemap.h"
33 33
34/** 34/**
35 * How many messages do we queue up at most for optional 35 * How many messages do we queue up at most for any client? This can
36 * notifications to a client? (this can cause notifications 36 * cause messages to be dropped if clients do not process them fast
37 * about outgoing messages to be dropped). 37 * enough! Note that this is a soft limit; we try
38 * to keep a few larger messages above the limit.
38 */ 39 */
39#define MAX_NOTIFY_QUEUE 1024 40#define SOFT_MAX_QUEUE 128
41
42/**
43 * How many messages do we queue up at most for any client? This can
44 * cause messages to be dropped if clients do not process them fast
45 * enough! Note that this is the hard limit.
46 */
47#define HARD_MAX_QUEUE 256
40 48
41 49
42/** 50/**
@@ -696,6 +704,11 @@ GSC_CLIENTS_notify_client_about_neighbour (struct GSC_Client *client,
696 new_match = GSC_TYPEMAP_test_match (tmap_new, 704 new_match = GSC_TYPEMAP_test_match (tmap_new,
697 client->types, 705 client->types,
698 client->tcnt); 706 client->tcnt);
707 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
708 "Notifying client about neighbour %s (%d/%d)\n",
709 GNUNET_i2s (neighbour),
710 old_match,
711 new_match);
699 if (old_match == new_match) 712 if (old_match == new_match)
700 { 713 {
701 GNUNET_assert (old_match == 714 GNUNET_assert (old_match ==
@@ -720,7 +733,8 @@ GSC_CLIENTS_notify_client_about_neighbour (struct GSC_Client *client,
720 GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT); 733 GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT);
721 cnm->reserved = htonl (0); 734 cnm->reserved = htonl (0);
722 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 735 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
723 "Sending NOTIFY_CONNECT message to client.\n"); 736 "Sending NOTIFY_CONNECT message about peer %s to client.\n",
737 GNUNET_i2s (neighbour));
724 cnm->peer = *neighbour; 738 cnm->peer = *neighbour;
725 GNUNET_MQ_send (client->mq, 739 GNUNET_MQ_send (client->mq,
726 env); 740 env);
@@ -740,6 +754,9 @@ GSC_CLIENTS_notify_client_about_neighbour (struct GSC_Client *client,
740 env = GNUNET_MQ_msg (dcm, 754 env = GNUNET_MQ_msg (dcm,
741 GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT); 755 GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT);
742 dcm->reserved = htonl (0); 756 dcm->reserved = htonl (0);
757 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
758 "Sending NOTIFY_DISCONNECT message about peer %s to client.\n",
759 GNUNET_i2s (neighbour));
743 dcm->peer = *neighbour; 760 dcm->peer = *neighbour;
744 GNUNET_MQ_send (client->mq, 761 GNUNET_MQ_send (client->mq,
745 env); 762 env);
@@ -790,7 +807,7 @@ GSC_CLIENTS_deliver_message (const struct GNUNET_PeerIdentity *sender,
790{ 807{
791 size_t size = msize + sizeof (struct NotifyTrafficMessage); 808 size_t size = msize + sizeof (struct NotifyTrafficMessage);
792 809
793 if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE) 810 if (size >= GNUNET_MAX_MESSAGE_SIZE)
794 { 811 {
795 GNUNET_break (0); 812 GNUNET_break (0);
796 return; 813 return;
@@ -810,6 +827,7 @@ GSC_CLIENTS_deliver_message (const struct GNUNET_PeerIdentity *sender,
810 struct GNUNET_MQ_Envelope *env; 827 struct GNUNET_MQ_Envelope *env;
811 struct NotifyTrafficMessage *ntm; 828 struct NotifyTrafficMessage *ntm;
812 uint16_t mtype; 829 uint16_t mtype;
830 unsigned int qlen;
813 int tm; 831 int tm;
814 832
815 tm = type_match (ntohs (msg->type), 833 tm = type_match (ntohs (msg->type),
@@ -825,6 +843,45 @@ GSC_CLIENTS_deliver_message (const struct GNUNET_PeerIdentity *sender,
825 if ( (0 != (options & GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND)) && 843 if ( (0 != (options & GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND)) &&
826 (0 != (c->options & GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND)) ) 844 (0 != (c->options & GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND)) )
827 continue; 845 continue;
846
847 /* Drop messages if:
848 1) We are above the hard limit, or
849 2) We are above the soft limit, and a coin toss limited
850 to the message size (giving larger messages a
851 proportionally higher chance of being queued) falls
852 below the threshold. The threshold is based on where
853 we are between the soft and the hard limit, scaled
854 to match the range of message sizes we usually encounter
855 (i.e. up to 32k); so a 64k message has a 50% chance of
856 being kept if we are just barely below the hard max,
857 and a 99% chance of being kept if we are at the soft max.
858 The reason is to make it more likely to drop control traffic
859 (ACK, queries) which may be cummulative or highly redundant,
860 and cheap to drop than data traffic. */
861 qlen = GNUNET_MQ_get_length (c->mq);
862 if ( (qlen >= HARD_MAX_QUEUE) ||
863 ( (qlen > SOFT_MAX_QUEUE) &&
864 ( (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
865 ntohs (msg->size)) ) <
866 (qlen - SOFT_MAX_QUEUE) * 0x8000 /
867 (HARD_MAX_QUEUE - SOFT_MAX_QUEUE) ) ) )
868 {
869 char buf[1024];
870
871 GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
872 "Dropping decrypted message of type %u as client is too busy (queue full)\n",
873 (unsigned int) ntohs (msg->type));
874 GNUNET_snprintf (buf,
875 sizeof (buf),
876 gettext_noop ("# messages of type %u discarded (client busy)"),
877 (unsigned int) ntohs (msg->type));
878 GNUNET_STATISTICS_update (GSC_stats,
879 buf,
880 1,
881 GNUNET_NO);
882 continue;
883 }
884
828 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 885 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
829 "Sending %u message with %u bytes to client interested in messages of type %u.\n", 886 "Sending %u message with %u bytes to client interested in messages of type %u.\n",
830 options, 887 options,
diff --git a/src/core/gnunet-service-core_kx.c b/src/core/gnunet-service-core_kx.c
index 6743ce215..8a7cada5c 100644
--- a/src/core/gnunet-service-core_kx.c
+++ b/src/core/gnunet-service-core_kx.c
@@ -261,7 +261,12 @@ struct GSC_KeyExchangeInfo
261 * Message queue for sending messages to @a peer. 261 * Message queue for sending messages to @a peer.
262 */ 262 */
263 struct GNUNET_MQ_Handle *mq; 263 struct GNUNET_MQ_Handle *mq;
264 264
265 /**
266 * Our message stream tokenizer (for encrypted payload).
267 */
268 struct GNUNET_MessageStreamTokenizer *mst;
269
265 /** 270 /**
266 * PING message we transmit to the other peer. 271 * PING message we transmit to the other peer.
267 */ 272 */
@@ -319,7 +324,7 @@ struct GSC_KeyExchangeInfo
319 * last were received (good for accepting out-of-order packets and 324 * last were received (good for accepting out-of-order packets and
320 * estimating reliability of the connection) 325 * estimating reliability of the connection)
321 */ 326 */
322 unsigned int last_packets_bitmap; 327 uint32_t last_packets_bitmap;
323 328
324 /** 329 /**
325 * last sequence number received on this connection (highest) 330 * last sequence number received on this connection (highest)
@@ -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;
@@ -777,7 +828,7 @@ handle_transport_notify_disconnect (void *cls,
777 void *handler_cls) 828 void *handler_cls)
778{ 829{
779 struct GSC_KeyExchangeInfo *kx = handler_cls; 830 struct GSC_KeyExchangeInfo *kx = handler_cls;
780 831
781 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 832 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
782 "Peer `%s' disconnected from us.\n", 833 "Peer `%s' disconnected from us.\n",
783 GNUNET_i2s (peer)); 834 GNUNET_i2s (peer));
@@ -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
@@ -814,7 +866,7 @@ static void
814send_ping (struct GSC_KeyExchangeInfo *kx) 866send_ping (struct GSC_KeyExchangeInfo *kx)
815{ 867{
816 struct GNUNET_MQ_Envelope *env; 868 struct GNUNET_MQ_Envelope *env;
817 869
818 GNUNET_STATISTICS_update (GSC_stats, 870 GNUNET_STATISTICS_update (GSC_stats,
819 gettext_noop ("# PING messages transmitted"), 871 gettext_noop ("# PING messages transmitted"),
820 1, 872 1,
@@ -1332,7 +1384,7 @@ static void
1332send_key (struct GSC_KeyExchangeInfo *kx) 1384send_key (struct GSC_KeyExchangeInfo *kx)
1333{ 1385{
1334 struct GNUNET_MQ_Envelope *env; 1386 struct GNUNET_MQ_Envelope *env;
1335 1387
1336 GNUNET_assert (GNUNET_CORE_KX_STATE_DOWN != kx->status); 1388 GNUNET_assert (GNUNET_CORE_KX_STATE_DOWN != kx->status);
1337 if (NULL != kx->retry_set_key_task) 1389 if (NULL != kx->retry_set_key_task)
1338 { 1390 {
@@ -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
@@ -1520,7 +1553,7 @@ handle_encrypted (void *cls,
1520 sizeof (struct GNUNET_HashCode))) 1553 sizeof (struct GNUNET_HashCode)))
1521 { 1554 {
1522 /* checksum failed */ 1555 /* checksum failed */
1523 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1556 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1524 "Failed checksum validation for a message from `%s'\n", 1557 "Failed checksum validation for a message from `%s'\n",
1525 GNUNET_i2s (kx->peer)); 1558 GNUNET_i2s (kx->peer));
1526 return; 1559 return;
@@ -1536,7 +1569,10 @@ handle_encrypted (void *cls,
1536 &m->sequence_number, 1569 &m->sequence_number,
1537 &buf[ENCRYPTED_HEADER_SIZE], 1570 &buf[ENCRYPTED_HEADER_SIZE],
1538 size - ENCRYPTED_HEADER_SIZE)) 1571 size - ENCRYPTED_HEADER_SIZE))
1572 {
1573 GNUNET_break_op (0);
1539 return; 1574 return;
1575 }
1540 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1576 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1541 "Decrypted %u bytes from %s\n", 1577 "Decrypted %u bytes from %s\n",
1542 (unsigned int) (size - ENCRYPTED_HEADER_SIZE), 1578 (unsigned int) (size - ENCRYPTED_HEADER_SIZE),
@@ -1570,7 +1606,7 @@ handle_encrypted (void *cls,
1570 } 1606 }
1571 if (kx->last_sequence_number_received > snum) 1607 if (kx->last_sequence_number_received > snum)
1572 { 1608 {
1573 unsigned int rotbit = 1 << (kx->last_sequence_number_received - snum - 1); 1609 uint32_t rotbit = 1U << (kx->last_sequence_number_received - snum - 1);
1574 1610
1575 if ((kx->last_packets_bitmap & rotbit) != 0) 1611 if ((kx->last_packets_bitmap & rotbit) != 0)
1576 { 1612 {
@@ -1617,15 +1653,12 @@ handle_encrypted (void *cls,
1617 gettext_noop ("# bytes of payload decrypted"), 1653 gettext_noop ("# bytes of payload decrypted"),
1618 size - sizeof (struct EncryptedMessage), 1654 size - sizeof (struct EncryptedMessage),
1619 GNUNET_NO); 1655 GNUNET_NO);
1620 dmc.kx = kx;
1621 dmc.peer = kx->peer;
1622 if (GNUNET_OK != 1656 if (GNUNET_OK !=
1623 GNUNET_SERVER_mst_receive (mst, 1657 GNUNET_MST_from_buffer (kx->mst,
1624 &dmc, 1658 &buf[sizeof (struct EncryptedMessage)],
1625 &buf[sizeof (struct EncryptedMessage)], 1659 size - sizeof (struct EncryptedMessage),
1626 size - sizeof (struct EncryptedMessage), 1660 GNUNET_YES,
1627 GNUNET_YES, 1661 GNUNET_NO))
1628 GNUNET_NO))
1629 GNUNET_break_op (0); 1662 GNUNET_break_op (0);
1630} 1663}
1631 1664
@@ -1642,7 +1675,7 @@ handle_transport_notify_excess_bw (void *cls,
1642 const struct GNUNET_PeerIdentity *pid, 1675 const struct GNUNET_PeerIdentity *pid,
1643 void *connect_cls) 1676 void *connect_cls)
1644{ 1677{
1645 struct GSC_KeyExchangeInfo *kx = connect_cls; 1678 struct GSC_KeyExchangeInfo *kx = connect_cls;
1646 1679
1647 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1680 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1648 "Peer %s has excess bandwidth available\n", 1681 "Peer %s has excess bandwidth available\n",
@@ -1653,53 +1686,6 @@ handle_transport_notify_excess_bw (void *cls,
1653 1686
1654 1687
1655/** 1688/**
1656 * Deliver P2P message to interested clients. Invokes send twice,
1657 * once for clients that want the full message, and once for clients
1658 * that only want the header
1659 *
1660 * @param cls always NULL
1661 * @param client who sent us the message (struct GSC_KeyExchangeInfo)
1662 * @param m the message
1663 */
1664static int
1665deliver_message (void *cls,
1666 void *client,
1667 const struct GNUNET_MessageHeader *m)
1668{
1669 struct DeliverMessageContext *dmc = client;
1670
1671 if (GNUNET_CORE_KX_STATE_UP != dmc->kx->status)
1672 {
1673 GNUNET_STATISTICS_update (GSC_stats,
1674 gettext_noop ("# PAYLOAD dropped (out of order)"),
1675 1,
1676 GNUNET_NO);
1677 return GNUNET_OK;
1678 }
1679 switch (ntohs (m->type))
1680 {
1681 case GNUNET_MESSAGE_TYPE_CORE_BINARY_TYPE_MAP:
1682 case GNUNET_MESSAGE_TYPE_CORE_COMPRESSED_TYPE_MAP:
1683 GSC_SESSIONS_set_typemap (dmc->peer, m);
1684 return GNUNET_OK;
1685 case GNUNET_MESSAGE_TYPE_CORE_CONFIRM_TYPE_MAP:
1686 GSC_SESSIONS_confirm_typemap (dmc->peer, m);
1687 return GNUNET_OK;
1688 default:
1689 GSC_CLIENTS_deliver_message (dmc->peer,
1690 m,
1691 ntohs (m->size),
1692 GNUNET_CORE_OPTION_SEND_FULL_INBOUND);
1693 GSC_CLIENTS_deliver_message (dmc->peer,
1694 m,
1695 sizeof (struct GNUNET_MessageHeader),
1696 GNUNET_CORE_OPTION_SEND_HDR_INBOUND);
1697 }
1698 return GNUNET_OK;
1699}
1700
1701
1702/**
1703 * Setup the message that links the ephemeral key to our persistent 1689 * Setup the message that links the ephemeral key to our persistent
1704 * public key and generate the appropriate signature. 1690 * public key and generate the appropriate signature.
1705 */ 1691 */
@@ -1822,9 +1808,7 @@ GSC_KX_init (struct GNUNET_CRYPTO_EddsaPrivateKey *pk)
1822 rekey_task = GNUNET_SCHEDULER_add_delayed (REKEY_FREQUENCY, 1808 rekey_task = GNUNET_SCHEDULER_add_delayed (REKEY_FREQUENCY,
1823 &do_rekey, 1809 &do_rekey,
1824 NULL); 1810 NULL);
1825 mst = GNUNET_SERVER_mst_create (&deliver_message, 1811 transport
1826 NULL);
1827 transport
1828 = GNUNET_TRANSPORT_core_connect (GSC_cfg, 1812 = GNUNET_TRANSPORT_core_connect (GSC_cfg,
1829 &GSC_my_identity, 1813 &GSC_my_identity,
1830 handlers, 1814 handlers,
@@ -1867,11 +1851,6 @@ GSC_KX_done ()
1867 GNUNET_free (my_private_key); 1851 GNUNET_free (my_private_key);
1868 my_private_key = NULL; 1852 my_private_key = NULL;
1869 } 1853 }
1870 if (NULL != mst)
1871 {
1872 GNUNET_SERVER_mst_destroy (mst);
1873 mst = NULL;
1874 }
1875 if (NULL != nc) 1854 if (NULL != nc)
1876 { 1855 {
1877 GNUNET_notification_context_destroy (nc); 1856 GNUNET_notification_context_destroy (nc);
@@ -1927,7 +1906,7 @@ GSC_KX_handle_client_monitor_peers (struct GNUNET_MQ_Handle *mq)
1927 { 1906 {
1928 struct GNUNET_MQ_Envelope *env; 1907 struct GNUNET_MQ_Envelope *env;
1929 struct MonitorNotifyMessage *msg; 1908 struct MonitorNotifyMessage *msg;
1930 1909
1931 env = GNUNET_MQ_msg (msg, 1910 env = GNUNET_MQ_msg (msg,
1932 GNUNET_MESSAGE_TYPE_CORE_MONITOR_NOTIFY); 1911 GNUNET_MESSAGE_TYPE_CORE_MONITOR_NOTIFY);
1933 msg->state = htonl ((uint32_t) kx->status); 1912 msg->state = htonl ((uint32_t) kx->status);
diff --git a/src/core/gnunet-service-core_sessions.c b/src/core/gnunet-service-core_sessions.c
index 6687b4819..034f2e883 100644
--- a/src/core/gnunet-service-core_sessions.c
+++ b/src/core/gnunet-service-core_sessions.c
@@ -57,6 +57,21 @@ struct SessionMessageEntry
57 struct SessionMessageEntry *prev; 57 struct SessionMessageEntry *prev;
58 58
59 /** 59 /**
60 * How important is this message.
61 */
62 enum GNUNET_CORE_Priority priority;
63
64 /**
65 * Flag set to #GNUNET_YES if this is a typemap message.
66 */
67 int is_typemap;
68
69 /**
70 * Flag set to #GNUNET_YES if this is a typemap confirmation message.
71 */
72 int is_typemap_confirm;
73
74 /**
60 * Deadline for transmission, 1s after we received it (if we 75 * Deadline for transmission, 1s after we received it (if we
61 * are not corking), otherwise "now". Note that this message 76 * are not corking), otherwise "now". Note that this message
62 * does NOT expire past its deadline. 77 * does NOT expire past its deadline.
@@ -70,11 +85,6 @@ struct SessionMessageEntry
70 */ 85 */
71 size_t size; 86 size_t size;
72 87
73 /**
74 * How important is this message.
75 */
76 enum GNUNET_CORE_Priority priority;
77
78}; 88};
79 89
80 90
@@ -275,14 +285,19 @@ transmit_typemap_task (void *cls)
275 struct GNUNET_MessageHeader *hdr; 285 struct GNUNET_MessageHeader *hdr;
276 struct GNUNET_TIME_Relative delay; 286 struct GNUNET_TIME_Relative delay;
277 287
288 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
289 "Sending TYPEMAP to %s\n",
290 GNUNET_i2s (session->peer));
278 session->typemap_delay = GNUNET_TIME_STD_BACKOFF (session->typemap_delay); 291 session->typemap_delay = GNUNET_TIME_STD_BACKOFF (session->typemap_delay);
279 delay = session->typemap_delay; 292 delay = session->typemap_delay;
280 /* randomize a bit to avoid spont. sync */ 293 /* randomize a bit to avoid spont. sync */
281 delay.rel_value_us += 294 delay.rel_value_us +=
282 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000 * 1000); 295 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
296 1000 * 1000);
283 session->typemap_task = 297 session->typemap_task =
284 GNUNET_SCHEDULER_add_delayed (delay, 298 GNUNET_SCHEDULER_add_delayed (delay,
285 &transmit_typemap_task, session); 299 &transmit_typemap_task,
300 session);
286 GNUNET_STATISTICS_update (GSC_stats, 301 GNUNET_STATISTICS_update (GSC_stats,
287 gettext_noop ("# type map refreshes sent"), 302 gettext_noop ("# type map refreshes sent"),
288 1, 303 1,
@@ -326,7 +341,7 @@ GSC_SESSIONS_create (const struct GNUNET_PeerIdentity *peer,
326 struct Session *session; 341 struct Session *session;
327 342
328 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 343 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
329 "Creating session for peer `%4s'\n", 344 "Creating session for peer `%s'\n",
330 GNUNET_i2s (peer)); 345 GNUNET_i2s (peer));
331 session = GNUNET_new (struct Session); 346 session = GNUNET_new (struct Session);
332 session->tmap = GSC_TYPEMAP_create (); 347 session->tmap = GSC_TYPEMAP_create ();
@@ -406,8 +421,14 @@ GSC_SESSIONS_confirm_typemap (const struct GNUNET_PeerIdentity *peer,
406 gettext_noop 421 gettext_noop
407 ("# outdated typemap confirmations received"), 422 ("# outdated typemap confirmations received"),
408 1, GNUNET_NO); 423 1, GNUNET_NO);
424 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
425 "Got outdated typemap confirmated from peer `%s'\n",
426 GNUNET_i2s (session->peer));
409 return; 427 return;
410 } 428 }
429 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
430 "Got typemap confirmation from peer `%s'\n",
431 GNUNET_i2s (session->peer));
411 if (NULL != session->typemap_task) 432 if (NULL != session->typemap_task)
412 { 433 {
413 GNUNET_SCHEDULER_cancel (session->typemap_task); 434 GNUNET_SCHEDULER_cancel (session->typemap_task);
@@ -502,9 +523,9 @@ GSC_SESSIONS_queue_request (struct GSC_ClientActiveRequest *car)
502 } 523 }
503 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 524 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
504 "Received client transmission request. queueing\n"); 525 "Received client transmission request. queueing\n");
505 GNUNET_CONTAINER_DLL_insert (session->active_client_request_head, 526 GNUNET_CONTAINER_DLL_insert_tail (session->active_client_request_head,
506 session->active_client_request_tail, 527 session->active_client_request_tail,
507 car); 528 car);
508 try_transmission (session); 529 try_transmission (session);
509} 530}
510 531
@@ -751,7 +772,15 @@ try_transmission (struct Session *session)
751 while ( (NULL != (pos = session->sme_head)) && 772 while ( (NULL != (pos = session->sme_head)) &&
752 (used + pos->size <= msize) ) 773 (used + pos->size <= msize) )
753 { 774 {
754 GNUNET_memcpy (&pbuf[used], &pos[1], pos->size); 775 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
776 "Adding message of type %d (%d/%d) to payload for %s\n",
777 ntohs (((const struct GNUNET_MessageHeader *)&pos[1])->type),
778 pos->is_typemap,
779 pos->is_typemap_confirm,
780 GNUNET_i2s (session->peer));
781 GNUNET_memcpy (&pbuf[used],
782 &pos[1],
783 pos->size);
755 used += pos->size; 784 used += pos->size;
756 GNUNET_CONTAINER_DLL_remove (session->sme_head, 785 GNUNET_CONTAINER_DLL_remove (session->sme_head,
757 session->sme_tail, 786 session->sme_tail,
@@ -799,8 +828,23 @@ do_restart_typemap_message (void *cls,
799 struct SessionMessageEntry *sme; 828 struct SessionMessageEntry *sme;
800 uint16_t size; 829 uint16_t size;
801 830
831 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
832 "Restarting sending TYPEMAP to %s\n",
833 GNUNET_i2s (session->peer));
802 size = ntohs (hdr->size); 834 size = ntohs (hdr->size);
835 for (sme = session->sme_head; NULL != sme; sme = sme->next)
836 {
837 if (GNUNET_YES == sme->is_typemap)
838 {
839 GNUNET_CONTAINER_DLL_remove (session->sme_head,
840 session->sme_tail,
841 sme);
842 GNUNET_free (sme);
843 break;
844 }
845 }
803 sme = GNUNET_malloc (sizeof (struct SessionMessageEntry) + size); 846 sme = GNUNET_malloc (sizeof (struct SessionMessageEntry) + size);
847 sme->is_typemap = GNUNET_YES;
804 GNUNET_memcpy (&sme[1], 848 GNUNET_memcpy (&sme[1],
805 hdr, 849 hdr,
806 size); 850 size);
@@ -924,18 +968,36 @@ GSC_SESSIONS_set_typemap (const struct GNUNET_PeerIdentity *peer,
924 968
925 nmap = GSC_TYPEMAP_get_from_message (msg); 969 nmap = GSC_TYPEMAP_get_from_message (msg);
926 if (NULL == nmap) 970 if (NULL == nmap)
971 {
972 GNUNET_break_op (0);
927 return; /* malformed */ 973 return; /* malformed */
974 }
928 session = find_session (peer); 975 session = find_session (peer);
929 if (NULL == session) 976 if (NULL == session)
930 { 977 {
931 GNUNET_break (0); 978 GNUNET_break (0);
932 return; 979 return;
933 } 980 }
981 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
982 "Received TYPEMAP from %s\n",
983 GNUNET_i2s (session->peer));
984 for (sme = session->sme_head; NULL != sme; sme = sme->next)
985 {
986 if (GNUNET_YES == sme->is_typemap_confirm)
987 {
988 GNUNET_CONTAINER_DLL_remove (session->sme_head,
989 session->sme_tail,
990 sme);
991 GNUNET_free (sme);
992 break;
993 }
994 }
934 sme = GNUNET_malloc (sizeof (struct SessionMessageEntry) + 995 sme = GNUNET_malloc (sizeof (struct SessionMessageEntry) +
935 sizeof (struct TypeMapConfirmationMessage)); 996 sizeof (struct TypeMapConfirmationMessage));
936 sme->deadline = GNUNET_TIME_absolute_get (); 997 sme->deadline = GNUNET_TIME_absolute_get ();
937 sme->size = sizeof (struct TypeMapConfirmationMessage); 998 sme->size = sizeof (struct TypeMapConfirmationMessage);
938 sme->priority = GNUNET_CORE_PRIO_CRITICAL_CONTROL; 999 sme->priority = GNUNET_CORE_PRIO_CRITICAL_CONTROL;
1000 sme->is_typemap_confirm = GNUNET_YES;
939 tmc = (struct TypeMapConfirmationMessage *) &sme[1]; 1001 tmc = (struct TypeMapConfirmationMessage *) &sme[1];
940 tmc->header.size = htons (sizeof (struct TypeMapConfirmationMessage)); 1002 tmc->header.size = htons (sizeof (struct TypeMapConfirmationMessage));
941 tmc->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_CONFIRM_TYPE_MAP); 1003 tmc->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_CONFIRM_TYPE_MAP);
@@ -975,11 +1037,15 @@ GSC_SESSIONS_add_to_typemap (const struct GNUNET_PeerIdentity *peer,
975 return; 1037 return;
976 session = find_session (peer); 1038 session = find_session (peer);
977 GNUNET_assert (NULL != session); 1039 GNUNET_assert (NULL != session);
978 if (GNUNET_YES == GSC_TYPEMAP_test_match (session->tmap, &type, 1)) 1040 if (GNUNET_YES == GSC_TYPEMAP_test_match (session->tmap,
1041 &type, 1))
979 return; /* already in it */ 1042 return; /* already in it */
980 nmap = GSC_TYPEMAP_extend (session->tmap, &type, 1); 1043 nmap = GSC_TYPEMAP_extend (session->tmap,
1044 &type,
1045 1);
981 GSC_CLIENTS_notify_clients_about_neighbour (peer, 1046 GSC_CLIENTS_notify_clients_about_neighbour (peer,
982 session->tmap, nmap); 1047 session->tmap,
1048 nmap);
983 GSC_TYPEMAP_destroy (session->tmap); 1049 GSC_TYPEMAP_destroy (session->tmap);
984 session->tmap = nmap; 1050 session->tmap = nmap;
985} 1051}
diff --git a/src/core/gnunet-service-core_typemap.c b/src/core/gnunet-service-core_typemap.c
index d400c0b8b..0600f59ef 100644
--- a/src/core/gnunet-service-core_typemap.c
+++ b/src/core/gnunet-service-core_typemap.c
@@ -177,8 +177,10 @@ GSC_TYPEMAP_get_from_message (const struct GNUNET_MessageHeader *msg)
177 GNUNET_memcpy (ret, &msg[1], sizeof (struct GSC_TypeMap)); 177 GNUNET_memcpy (ret, &msg[1], sizeof (struct GSC_TypeMap));
178 return ret; 178 return ret;
179 case GNUNET_MESSAGE_TYPE_CORE_COMPRESSED_TYPE_MAP: 179 case GNUNET_MESSAGE_TYPE_CORE_COMPRESSED_TYPE_MAP:
180 GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# type maps received"), 180 GNUNET_STATISTICS_update (GSC_stats,
181 1, GNUNET_NO); 181 gettext_noop ("# type maps received"),
182 1,
183 GNUNET_NO);
182 ret = GNUNET_new (struct GSC_TypeMap); 184 ret = GNUNET_new (struct GSC_TypeMap);
183 dlen = sizeof (struct GSC_TypeMap); 185 dlen = sizeof (struct GSC_TypeMap);
184 if ((Z_OK != 186 if ((Z_OK !=
@@ -207,7 +209,8 @@ broadcast_my_type_map ()
207 209
208 hdr = GSC_TYPEMAP_compute_type_map_message (); 210 hdr = GSC_TYPEMAP_compute_type_map_message ();
209 GNUNET_STATISTICS_update (GSC_stats, 211 GNUNET_STATISTICS_update (GSC_stats,
210 gettext_noop ("# updates to my type map"), 1, 212 gettext_noop ("# updates to my type map"),
213 1,
211 GNUNET_NO); 214 GNUNET_NO);
212 GSC_SESSIONS_broadcast_typemap (hdr); 215 GSC_SESSIONS_broadcast_typemap (hdr);
213 GNUNET_free (hdr); 216 GNUNET_free (hdr);
@@ -238,6 +241,8 @@ GSC_TYPEMAP_add (const uint16_t *types,
238 } 241 }
239 if (GNUNET_YES == changed) 242 if (GNUNET_YES == changed)
240 { 243 {
244 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
245 "Typemap changed, broadcasting!\n");
241 rehash_typemap (); 246 rehash_typemap ();
242 broadcast_my_type_map (); 247 broadcast_my_type_map ();
243 } 248 }
@@ -254,11 +259,10 @@ void
254GSC_TYPEMAP_remove (const uint16_t *types, 259GSC_TYPEMAP_remove (const uint16_t *types,
255 unsigned int tlen) 260 unsigned int tlen)
256{ 261{
257 unsigned int i;
258 int changed; 262 int changed;
259 263
260 changed = GNUNET_NO; 264 changed = GNUNET_NO;
261 for (i = 0; i < tlen; i++) 265 for (unsigned int i = 0; i < tlen; i++)
262 { 266 {
263 if (0 == --map_counters[types[i]]) 267 if (0 == --map_counters[types[i]])
264 { 268 {
@@ -288,13 +292,11 @@ GSC_TYPEMAP_test_match (const struct GSC_TypeMap *tmap,
288 const uint16_t *types, 292 const uint16_t *types,
289 unsigned int tcnt) 293 unsigned int tcnt)
290{ 294{
291 unsigned int i;
292
293 if (NULL == tmap) 295 if (NULL == tmap)
294 return GNUNET_NO; 296 return GNUNET_NO;
295 if (0 == tcnt) 297 if (0 == tcnt)
296 return GNUNET_YES; /* matches all */ 298 return GNUNET_YES; /* matches all */
297 for (i = 0; i < tcnt; i++) 299 for (unsigned int i = 0; i < tcnt; i++)
298 if (0 != (tmap->bits[types[i] / 32] & (1 << (types[i] % 32)))) 300 if (0 != (tmap->bits[types[i] / 32] & (1 << (types[i] % 32))))
299 return GNUNET_YES; 301 return GNUNET_YES;
300 return GNUNET_NO; 302 return GNUNET_NO;
@@ -315,12 +317,11 @@ GSC_TYPEMAP_extend (const struct GSC_TypeMap *tmap,
315 unsigned int tcnt) 317 unsigned int tcnt)
316{ 318{
317 struct GSC_TypeMap *ret; 319 struct GSC_TypeMap *ret;
318 unsigned int i;
319 320
320 ret = GNUNET_new (struct GSC_TypeMap); 321 ret = GNUNET_new (struct GSC_TypeMap);
321 if (NULL != tmap) 322 if (NULL != tmap)
322 GNUNET_memcpy (ret, tmap, sizeof (struct GSC_TypeMap)); 323 GNUNET_memcpy (ret, tmap, sizeof (struct GSC_TypeMap));
323 for (i = 0; i < tcnt; i++) 324 for (unsigned int i = 0; i < tcnt; i++)
324 ret->bits[types[i] / 32] |= (1 << (types[i] % 32)); 325 ret->bits[types[i] / 32] |= (1 << (types[i] % 32));
325 return ret; 326 return ret;
326} 327}
diff --git a/src/datacache/Makefile.am b/src/datacache/Makefile.am
index 9b66636e5..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 = \
@@ -127,7 +128,7 @@ check_PROGRAMS = \
127 $(POSTGRES_TESTS) 128 $(POSTGRES_TESTS)
128 129
129if ENABLE_TEST_RUN 130if ENABLE_TEST_RUN
130AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; 131AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
131TESTS = $(check_PROGRAMS) 132TESTS = $(check_PROGRAMS)
132endif 133endif
133 134
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 1e7619d82..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)
@@ -175,7 +176,7 @@ check_PROGRAMS = \
175 $(POSTGRES_TESTS) 176 $(POSTGRES_TESTS)
176 177
177if ENABLE_TEST_RUN 178if ENABLE_TEST_RUN
178AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; 179AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
179TESTS = $(check_PROGRAMS) 180TESTS = $(check_PROGRAMS)
180endif 181endif
181 182
diff --git a/src/datastore/datastore.h b/src/datastore/datastore.h
index dc3d9d1f2..98f8b82ef 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
152 */ 157 */
153 uint64_t offset GNUNET_PACKED; 158 uint64_t next_uid GNUNET_PACKED;
159
160 /**
161 * If true return a random result
162 */
163 uint32_t random GNUNET_PACKED;
154 164
155}; 165};
156 166
@@ -172,38 +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
179};
180
181
182/**
183 * Message to the datastore service requesting an update
184 * to the priority or expiration for some content.
185 */
186struct UpdateMessage
187{
188 /**
189 * Type is GNUNET_MESSAGE_TYPE_DATASTORE_UPDATE.
190 */
191 struct GNUNET_MessageHeader header;
192
193 /**
194 * Desired priority increase.
195 */
196 int32_t priority GNUNET_PACKED;
197
198 /**
199 * Desired new expiration time.
200 */
201 struct GNUNET_TIME_AbsoluteNBO expiration;
202
203 /**
204 * Unique ID for the content.
205 */
206 uint64_t uid;
207 188
208}; 189};
209 190
@@ -248,7 +229,7 @@ struct DataMessage
248 uint32_t anonymity GNUNET_PACKED; 229 uint32_t anonymity GNUNET_PACKED;
249 230
250 /** 231 /**
251 * Desired replication level. 0 from service to API. 232 * Desired replication level.
252 */ 233 */
253 uint32_t replication GNUNET_PACKED; 234 uint32_t replication GNUNET_PACKED;
254 235
diff --git a/src/datastore/datastore_api.c b/src/datastore/datastore_api.c
index db485364e..31f7a997f 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;
@@ -313,7 +352,11 @@ mq_error_handler (void *cls,
313 qc.rc.proc (qc.rc.proc_cls, 352 qc.rc.proc (qc.rc.proc_cls,
314 NULL, 353 NULL,
315 0, 354 0,
316 NULL, 0, 0, 0, 355 NULL,
356 0,
357 0,
358 0,
359 0,
317 GNUNET_TIME_UNIT_ZERO_ABS, 360 GNUNET_TIME_UNIT_ZERO_ABS,
318 0); 361 0);
319 break; 362 break;
@@ -429,7 +472,11 @@ GNUNET_DATASTORE_disconnect (struct GNUNET_DATASTORE_Handle *h,
429 qe->qc.rc.proc (qe->qc.rc.proc_cls, 472 qe->qc.rc.proc (qe->qc.rc.proc_cls,
430 NULL, 473 NULL,
431 0, 474 0,
432 NULL, 0, 0, 0, 475 NULL,
476 0,
477 0,
478 0,
479 0,
433 GNUNET_TIME_UNIT_ZERO_ABS, 480 GNUNET_TIME_UNIT_ZERO_ABS,
434 0); 481 0);
435 break; 482 break;
@@ -498,8 +545,17 @@ make_queue_entry (struct GNUNET_DATASTORE_Handle *h,
498 struct GNUNET_DATASTORE_QueueEntry *pos; 545 struct GNUNET_DATASTORE_QueueEntry *pos;
499 unsigned int c; 546 unsigned int c;
500 547
501 c = 0; 548 if ( (NULL != h->queue_tail) &&
502 pos = h->queue_head; 549 (h->queue_tail->priority >= queue_priority) )
550 {
551 c = h->queue_size;
552 pos = NULL;
553 }
554 else
555 {
556 c = 0;
557 pos = h->queue_head;
558 }
503 while ( (NULL != pos) && 559 while ( (NULL != pos) &&
504 (c < max_queue_size) && 560 (c < max_queue_size) &&
505 (pos->priority >= queue_priority) ) 561 (pos->priority >= queue_priority) )
@@ -585,6 +641,10 @@ process_queue (struct GNUNET_DATASTORE_Handle *h)
585 "Not connected\n"); 641 "Not connected\n");
586 return; 642 return;
587 } 643 }
644 GNUNET_assert (NULL == qe->delay_warn_task);
645 qe->delay_warn_task = GNUNET_SCHEDULER_add_delayed (DELAY_WARN_TIMEOUT,
646 &delay_warning,
647 qe);
588 GNUNET_MQ_send (h->mq, 648 GNUNET_MQ_send (h->mq,
589 qe->env); 649 qe->env);
590 qe->env = NULL; 650 qe->env = NULL;
@@ -773,6 +833,7 @@ handle_data (void *cls,
773 ntohl (dm->type), 833 ntohl (dm->type),
774 ntohl (dm->priority), 834 ntohl (dm->priority),
775 ntohl (dm->anonymity), 835 ntohl (dm->anonymity),
836 ntohl (dm->replication),
776 GNUNET_TIME_absolute_ntoh (dm->expiration), 837 GNUNET_TIME_absolute_ntoh (dm->expiration),
777 GNUNET_ntohll (dm->uid)); 838 GNUNET_ntohll (dm->uid));
778} 839}
@@ -835,6 +896,7 @@ handle_data_end (void *cls,
835 0, 896 0,
836 0, 897 0,
837 0, 898 0,
899 0,
838 GNUNET_TIME_UNIT_ZERO_ABS, 900 GNUNET_TIME_UNIT_ZERO_ABS,
839 0); 901 0);
840} 902}
@@ -949,7 +1011,7 @@ GNUNET_DATASTORE_put (struct GNUNET_DATASTORE_Handle *h,
949 struct DataMessage *dm; 1011 struct DataMessage *dm;
950 union QueueContext qc; 1012 union QueueContext qc;
951 1013
952 if (size + sizeof (*dm) >= GNUNET_SERVER_MAX_MESSAGE_SIZE) 1014 if (size + sizeof (*dm) >= GNUNET_MAX_MESSAGE_SIZE)
953 { 1015 {
954 GNUNET_break (0); 1016 GNUNET_break (0);
955 return NULL; 1017 return NULL;
@@ -970,8 +1032,6 @@ GNUNET_DATASTORE_put (struct GNUNET_DATASTORE_Handle *h,
970 dm->priority = htonl (priority); 1032 dm->priority = htonl (priority);
971 dm->anonymity = htonl (anonymity); 1033 dm->anonymity = htonl (anonymity);
972 dm->replication = htonl (replication); 1034 dm->replication = htonl (replication);
973 dm->reserved = htonl (0);
974 dm->uid = GNUNET_htonll (0);
975 dm->expiration = GNUNET_TIME_absolute_hton (expiration); 1035 dm->expiration = GNUNET_TIME_absolute_hton (expiration);
976 dm->key = *key; 1036 dm->key = *key;
977 GNUNET_memcpy (&dm[1], 1037 GNUNET_memcpy (&dm[1],
@@ -1126,72 +1186,6 @@ GNUNET_DATASTORE_release_reserve (struct GNUNET_DATASTORE_Handle *h,
1126 1186
1127 1187
1128/** 1188/**
1129 * Update a value in the datastore.
1130 *
1131 * @param h handle to the datastore
1132 * @param uid identifier for the value
1133 * @param priority how much to increase the priority of the value
1134 * @param expiration new expiration value should be MAX of existing and this argument
1135 * @param queue_priority ranking of this request in the priority queue
1136 * @param max_queue_size at what queue size should this request be dropped
1137 * (if other requests of higher priority are in the queue)
1138 * @param cont continuation to call when done
1139 * @param cont_cls closure for @a cont
1140 * @return NULL if the entry was not queued, otherwise a handle that can be used to
1141 * cancel; note that even if NULL is returned, the callback will be invoked
1142 * (or rather, will already have been invoked)
1143 */
1144struct GNUNET_DATASTORE_QueueEntry *
1145GNUNET_DATASTORE_update (struct GNUNET_DATASTORE_Handle *h,
1146 uint64_t uid,
1147 uint32_t priority,
1148 struct GNUNET_TIME_Absolute expiration,
1149 unsigned int queue_priority,
1150 unsigned int max_queue_size,
1151 GNUNET_DATASTORE_ContinuationWithStatus cont,
1152 void *cont_cls)
1153{
1154 struct GNUNET_DATASTORE_QueueEntry *qe;
1155 struct GNUNET_MQ_Envelope *env;
1156 struct UpdateMessage *um;
1157 union QueueContext qc;
1158
1159 if (NULL == cont)
1160 cont = &drop_status_cont;
1161 LOG (GNUNET_ERROR_TYPE_DEBUG,
1162 "Asked to update entry %llu raising priority by %u and expiration to %s\n",
1163 uid,
1164 (unsigned int) priority,
1165 GNUNET_STRINGS_absolute_time_to_string (expiration));
1166 env = GNUNET_MQ_msg (um,
1167 GNUNET_MESSAGE_TYPE_DATASTORE_UPDATE);
1168 um->priority = htonl (priority);
1169 um->expiration = GNUNET_TIME_absolute_hton (expiration);
1170 um->uid = GNUNET_htonll (uid);
1171
1172 qc.sc.cont = cont;
1173 qc.sc.cont_cls = cont_cls;
1174 qe = make_queue_entry (h,
1175 env,
1176 queue_priority,
1177 max_queue_size,
1178 GNUNET_MESSAGE_TYPE_DATASTORE_STATUS,
1179 &qc);
1180 if (NULL == qe)
1181 {
1182 LOG (GNUNET_ERROR_TYPE_DEBUG,
1183 "Could not create queue entry for UPDATE\n");
1184 return NULL;
1185 }
1186 GNUNET_STATISTICS_update (h->stats,
1187 gettext_noop ("# UPDATE requests executed"), 1,
1188 GNUNET_NO);
1189 process_queue (h);
1190 return qe;
1191}
1192
1193
1194/**
1195 * Explicitly remove some content from the database. 1189 * Explicitly remove some content from the database.
1196 * The @a cont continuation will be called with `status` 1190 * The @a cont continuation will be called with `status`
1197 * #GNUNET_OK" if content was removed, #GNUNET_NO 1191 * #GNUNET_OK" if content was removed, #GNUNET_NO
@@ -1226,7 +1220,7 @@ GNUNET_DATASTORE_remove (struct GNUNET_DATASTORE_Handle *h,
1226 struct GNUNET_MQ_Envelope *env; 1220 struct GNUNET_MQ_Envelope *env;
1227 union QueueContext qc; 1221 union QueueContext qc;
1228 1222
1229 if (sizeof (*dm) + size >= GNUNET_SERVER_MAX_MESSAGE_SIZE) 1223 if (sizeof (*dm) + size >= GNUNET_MAX_MESSAGE_SIZE)
1230 { 1224 {
1231 GNUNET_break (0); 1225 GNUNET_break (0);
1232 return NULL; 1226 return NULL;
@@ -1240,13 +1234,7 @@ GNUNET_DATASTORE_remove (struct GNUNET_DATASTORE_Handle *h,
1240 env = GNUNET_MQ_msg_extra (dm, 1234 env = GNUNET_MQ_msg_extra (dm,
1241 size, 1235 size,
1242 GNUNET_MESSAGE_TYPE_DATASTORE_REMOVE); 1236 GNUNET_MESSAGE_TYPE_DATASTORE_REMOVE);
1243 dm->rid = htonl (0);
1244 dm->size = htonl (size); 1237 dm->size = htonl (size);
1245 dm->type = htonl (0);
1246 dm->priority = htonl (0);
1247 dm->anonymity = htonl (0);
1248 dm->uid = GNUNET_htonll (0);
1249 dm->expiration = GNUNET_TIME_absolute_hton (GNUNET_TIME_UNIT_ZERO_ABS);
1250 dm->key = *key; 1238 dm->key = *key;
1251 GNUNET_memcpy (&dm[1], 1239 GNUNET_memcpy (&dm[1],
1252 data, 1240 data,
@@ -1339,10 +1327,7 @@ GNUNET_DATASTORE_get_for_replication (struct GNUNET_DATASTORE_Handle *h,
1339 * Get a single zero-anonymity value from the datastore. 1327 * Get a single zero-anonymity value from the datastore.
1340 * 1328 *
1341 * @param h handle to the datastore 1329 * @param h handle to the datastore
1342 * @param offset offset of the result (modulo num-results); set to 1330 * @param next_uid return the result with lowest uid >= next_uid
1343 * a random 64-bit value initially; then increment by
1344 * one each time; detect that all results have been found by uid
1345 * being again the first uid ever returned.
1346 * @param queue_priority ranking of this request in the priority queue 1331 * @param queue_priority ranking of this request in the priority queue
1347 * @param max_queue_size at what queue size should this request be dropped 1332 * @param max_queue_size at what queue size should this request be dropped
1348 * (if other requests of higher priority are in the queue) 1333 * (if other requests of higher priority are in the queue)
@@ -1356,7 +1341,7 @@ GNUNET_DATASTORE_get_for_replication (struct GNUNET_DATASTORE_Handle *h,
1356 */ 1341 */
1357struct GNUNET_DATASTORE_QueueEntry * 1342struct GNUNET_DATASTORE_QueueEntry *
1358GNUNET_DATASTORE_get_zero_anonymity (struct GNUNET_DATASTORE_Handle *h, 1343GNUNET_DATASTORE_get_zero_anonymity (struct GNUNET_DATASTORE_Handle *h,
1359 uint64_t offset, 1344 uint64_t next_uid,
1360 unsigned int queue_priority, 1345 unsigned int queue_priority,
1361 unsigned int max_queue_size, 1346 unsigned int max_queue_size,
1362 enum GNUNET_BLOCK_Type type, 1347 enum GNUNET_BLOCK_Type type,
@@ -1371,13 +1356,12 @@ GNUNET_DATASTORE_get_zero_anonymity (struct GNUNET_DATASTORE_Handle *h,
1371 GNUNET_assert (NULL != proc); 1356 GNUNET_assert (NULL != proc);
1372 GNUNET_assert (type != GNUNET_BLOCK_TYPE_ANY); 1357 GNUNET_assert (type != GNUNET_BLOCK_TYPE_ANY);
1373 LOG (GNUNET_ERROR_TYPE_DEBUG, 1358 LOG (GNUNET_ERROR_TYPE_DEBUG,
1374 "Asked to get %llu-th zero-anonymity entry of type %d\n", 1359 "Asked to get a zero-anonymity entry of type %d\n",
1375 (unsigned long long) offset,
1376 type); 1360 type);
1377 env = GNUNET_MQ_msg (m, 1361 env = GNUNET_MQ_msg (m,
1378 GNUNET_MESSAGE_TYPE_DATASTORE_GET_ZERO_ANONYMITY); 1362 GNUNET_MESSAGE_TYPE_DATASTORE_GET_ZERO_ANONYMITY);
1379 m->type = htonl ((uint32_t) type); 1363 m->type = htonl ((uint32_t) type);
1380 m->offset = GNUNET_htonll (offset); 1364 m->next_uid = GNUNET_htonll (next_uid);
1381 qc.rc.proc = proc; 1365 qc.rc.proc = proc;
1382 qc.rc.proc_cls = proc_cls; 1366 qc.rc.proc_cls = proc_cls;
1383 qe = make_queue_entry (h, 1367 qe = make_queue_entry (h,
@@ -1406,10 +1390,8 @@ GNUNET_DATASTORE_get_zero_anonymity (struct GNUNET_DATASTORE_Handle *h,
1406 * will only be called once. 1390 * will only be called once.
1407 * 1391 *
1408 * @param h handle to the datastore 1392 * @param h handle to the datastore
1409 * @param offset offset of the result (modulo num-results); set to 1393 * @param next_uid return the result with lowest uid >= next_uid
1410 * a random 64-bit value initially; then increment by 1394 * @param random if true, return a random result instead of using next_uid
1411 * one each time; detect that all results have been found by uid
1412 * being again the first uid ever returned.
1413 * @param key maybe NULL (to match all entries) 1395 * @param key maybe NULL (to match all entries)
1414 * @param type desired type, 0 for any 1396 * @param type desired type, 0 for any
1415 * @param queue_priority ranking of this request in the priority queue 1397 * @param queue_priority ranking of this request in the priority queue
@@ -1423,7 +1405,8 @@ GNUNET_DATASTORE_get_zero_anonymity (struct GNUNET_DATASTORE_Handle *h,
1423 */ 1405 */
1424struct GNUNET_DATASTORE_QueueEntry * 1406struct GNUNET_DATASTORE_QueueEntry *
1425GNUNET_DATASTORE_get_key (struct GNUNET_DATASTORE_Handle *h, 1407GNUNET_DATASTORE_get_key (struct GNUNET_DATASTORE_Handle *h,
1426 uint64_t offset, 1408 uint64_t next_uid,
1409 bool random,
1427 const struct GNUNET_HashCode *key, 1410 const struct GNUNET_HashCode *key,
1428 enum GNUNET_BLOCK_Type type, 1411 enum GNUNET_BLOCK_Type type,
1429 unsigned int queue_priority, 1412 unsigned int queue_priority,
@@ -1447,14 +1430,16 @@ GNUNET_DATASTORE_get_key (struct GNUNET_DATASTORE_Handle *h,
1447 env = GNUNET_MQ_msg (gm, 1430 env = GNUNET_MQ_msg (gm,
1448 GNUNET_MESSAGE_TYPE_DATASTORE_GET); 1431 GNUNET_MESSAGE_TYPE_DATASTORE_GET);
1449 gm->type = htonl (type); 1432 gm->type = htonl (type);
1450 gm->offset = GNUNET_htonll (offset); 1433 gm->next_uid = GNUNET_htonll (next_uid);
1434 gm->random = random;
1451 } 1435 }
1452 else 1436 else
1453 { 1437 {
1454 env = GNUNET_MQ_msg (gkm, 1438 env = GNUNET_MQ_msg (gkm,
1455 GNUNET_MESSAGE_TYPE_DATASTORE_GET_KEY); 1439 GNUNET_MESSAGE_TYPE_DATASTORE_GET_KEY);
1456 gkm->type = htonl (type); 1440 gkm->type = htonl (type);
1457 gkm->offset = GNUNET_htonll (offset); 1441 gkm->next_uid = GNUNET_htonll (next_uid);
1442 gkm->random = random;
1458 gkm->key = *key; 1443 gkm->key = *key;
1459 } 1444 }
1460 qc.rc.proc = proc; 1445 qc.rc.proc = proc;
diff --git a/src/datastore/gnunet-datastore.c b/src/datastore/gnunet-datastore.c
index b3d14c43c..9e0ee205e 100644
--- a/src/datastore/gnunet-datastore.c
+++ b/src/datastore/gnunet-datastore.c
@@ -130,20 +130,23 @@ do_finish (void *cls,
130 * @param type type of the content 130 * @param type type of the content
131 * @param priority priority of the content 131 * @param priority priority of the content
132 * @param anonymity anonymity-level for the content 132 * @param anonymity anonymity-level for the content
133 * @param replication replication-level for the content
133 * @param expiration expiration time for the content 134 * @param expiration expiration time for the content
134 * @param uid unique identifier for the datum; 135 * @param uid unique identifier for the datum;
135 * maybe 0 if no unique identifier is available 136 * maybe 0 if no unique identifier is available
136 */ 137 */
137static void 138static void
138do_put (void *cls, 139do_put (void *cls,
139 const struct GNUNET_HashCode *key, 140 const struct GNUNET_HashCode *key,
140 size_t size, 141 size_t size,
141 const void *data, 142 const void *data,
142 enum GNUNET_BLOCK_Type type, 143 enum GNUNET_BLOCK_Type type,
143 uint32_t priority, 144 uint32_t priority,
144 uint32_t anonymity, 145 uint32_t anonymity,
145 struct GNUNET_TIME_Absolute 146 uint32_t replication,
146 expiration, uint64_t uid) 147 struct GNUNET_TIME_Absolute
148 expiration,
149 uint64_t uid)
147{ 150{
148 qe = NULL; 151 qe = NULL;
149 if ( (0 != offset) && 152 if ( (0 != offset) &&
@@ -154,13 +157,20 @@ do_put (void *cls,
154 } 157 }
155 if (0 == offset) 158 if (0 == offset)
156 first_uid = uid; 159 first_uid = uid;
157 qe = GNUNET_DATASTORE_put (db_dst, 0, 160 qe = GNUNET_DATASTORE_put (db_dst,
158 key, size, data, type, 161 0,
159 priority, anonymity, 162 key,
160 0 /* FIXME: replication is lost... */, 163 size,
161 expiration, 164 data,
162 0, 1, 165 type,
163 &do_finish, NULL); 166 priority,
167 anonymity,
168 replication,
169 expiration,
170 0,
171 1,
172 &do_finish,
173 NULL);
164} 174}
165 175
166 176
@@ -171,7 +181,7 @@ static void
171do_get () 181do_get ()
172{ 182{
173 qe = GNUNET_DATASTORE_get_key (db_src, 183 qe = GNUNET_DATASTORE_get_key (db_src,
174 offset, 184 0, false,
175 NULL, GNUNET_BLOCK_TYPE_ANY, 185 NULL, GNUNET_BLOCK_TYPE_ANY,
176 0, 1, 186 0, 1,
177 &do_put, NULL); 187 &do_put, NULL);
@@ -239,10 +249,12 @@ run (void *cls, char *const *args, const char *cfgfile,
239int 249int
240main (int argc, char *const *argv) 250main (int argc, char *const *argv)
241{ 251{
242 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 252 struct GNUNET_GETOPT_CommandLineOption options[] = {
243 { 's', "sourcecfg", "FILENAME", 253 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"), 254 "sourcecfg",
245 1, &GNUNET_GETOPT_set_filename, &alternative_cfg }, 255 "FILENAME",
256 gettext_noop ("specifies the configuration to use to access an alternative datastore; will merge that datastore into our current datastore"),
257 &alternative_cfg),
246 GNUNET_GETOPT_OPTION_END 258 GNUNET_GETOPT_OPTION_END
247 }; 259 };
248 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) 260 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 e632e33e0..277530843 100644
--- a/src/datastore/gnunet-service-datastore.c
+++ b/src/datastore/gnunet-service-datastore.c
@@ -286,6 +286,7 @@ delete_expired (void *cls);
286 * @param type type of the content 286 * @param type type of the content
287 * @param priority priority of the content 287 * @param priority priority of the content
288 * @param anonymity anonymity-level for the content 288 * @param anonymity anonymity-level for the content
289 * @param replication replication-level for the content
289 * @param expiration expiration time for the content 290 * @param expiration expiration time for the content
290 * @param uid unique identifier for the datum; 291 * @param uid unique identifier for the datum;
291 * maybe 0 if no unique identifier is available 292 * maybe 0 if no unique identifier is available
@@ -302,12 +303,13 @@ expired_processor (void *cls,
302 enum GNUNET_BLOCK_Type type, 303 enum GNUNET_BLOCK_Type type,
303 uint32_t priority, 304 uint32_t priority,
304 uint32_t anonymity, 305 uint32_t anonymity,
306 uint32_t replication,
305 struct GNUNET_TIME_Absolute expiration, 307 struct GNUNET_TIME_Absolute expiration,
306 uint64_t uid) 308 uint64_t uid)
307{ 309{
308 struct GNUNET_TIME_Absolute now; 310 struct GNUNET_TIME_Absolute now;
309 311
310 if (key == NULL) 312 if (NULL == key)
311 { 313 {
312 expired_kill_task = 314 expired_kill_task =
313 GNUNET_SCHEDULER_add_delayed_with_priority (MAX_EXPIRE_DELAY, 315 GNUNET_SCHEDULER_add_delayed_with_priority (MAX_EXPIRE_DELAY,
@@ -374,6 +376,7 @@ delete_expired (void *cls)
374 * @param type type of the content 376 * @param type type of the content
375 * @param priority priority of the content 377 * @param priority priority of the content
376 * @param anonymity anonymity-level for the content 378 * @param anonymity anonymity-level for the content
379 * @param replication replication-level for the content
377 * @param expiration expiration time for the content 380 * @param expiration expiration time for the content
378 * @param uid unique identifier for the datum; 381 * @param uid unique identifier for the datum;
379 * maybe 0 if no unique identifier is available 382 * maybe 0 if no unique identifier is available
@@ -389,6 +392,7 @@ quota_processor (void *cls,
389 enum GNUNET_BLOCK_Type type, 392 enum GNUNET_BLOCK_Type type,
390 uint32_t priority, 393 uint32_t priority,
391 uint32_t anonymity, 394 uint32_t anonymity,
395 uint32_t replication,
392 struct GNUNET_TIME_Absolute expiration, 396 struct GNUNET_TIME_Absolute expiration,
393 uint64_t uid) 397 uint64_t uid)
394{ 398{
@@ -495,6 +499,7 @@ transmit_status (struct GNUNET_SERVICE_Client *client,
495 * @param type type of the content 499 * @param type type of the content
496 * @param priority priority of the content 500 * @param priority priority of the content
497 * @param anonymity anonymity-level for the content 501 * @param anonymity anonymity-level for the content
502 * @param replication replication-level for the content
498 * @param expiration expiration time for the content 503 * @param expiration expiration time for the content
499 * @param uid unique identifier for the datum; 504 * @param uid unique identifier for the datum;
500 * maybe 0 if no unique identifier is available 505 * maybe 0 if no unique identifier is available
@@ -509,6 +514,7 @@ transmit_item (void *cls,
509 enum GNUNET_BLOCK_Type type, 514 enum GNUNET_BLOCK_Type type,
510 uint32_t priority, 515 uint32_t priority,
511 uint32_t anonymity, 516 uint32_t anonymity,
517 uint32_t replication,
512 struct GNUNET_TIME_Absolute expiration, 518 struct GNUNET_TIME_Absolute expiration,
513 uint64_t uid) 519 uint64_t uid)
514{ 520{
@@ -529,7 +535,7 @@ transmit_item (void *cls,
529 return GNUNET_OK; 535 return GNUNET_OK;
530 } 536 }
531 GNUNET_assert (sizeof (struct DataMessage) + size < 537 GNUNET_assert (sizeof (struct DataMessage) + size <
532 GNUNET_SERVER_MAX_MESSAGE_SIZE); 538 GNUNET_MAX_MESSAGE_SIZE);
533 env = GNUNET_MQ_msg_extra (dm, 539 env = GNUNET_MQ_msg_extra (dm,
534 size, 540 size,
535 GNUNET_MESSAGE_TYPE_DATASTORE_DATA); 541 GNUNET_MESSAGE_TYPE_DATASTORE_DATA);
@@ -538,8 +544,7 @@ transmit_item (void *cls,
538 dm->type = htonl (type); 544 dm->type = htonl (type);
539 dm->priority = htonl (priority); 545 dm->priority = htonl (priority);
540 dm->anonymity = htonl (anonymity); 546 dm->anonymity = htonl (anonymity);
541 dm->replication = htonl (0); 547 dm->replication = htonl (replication);
542 dm->reserved = htonl (0);
543 dm->expiration = GNUNET_TIME_absolute_hton (expiration); 548 dm->expiration = GNUNET_TIME_absolute_hton (expiration);
544 dm->uid = GNUNET_htonll (uid); 549 dm->uid = GNUNET_htonll (uid);
545 dm->key = *key; 550 dm->key = *key;
@@ -848,6 +853,7 @@ check_present_continuation (void *cls,
848 * @param type type of the content 853 * @param type type of the content
849 * @param priority priority of the content 854 * @param priority priority of the content
850 * @param anonymity anonymity-level for the content 855 * @param anonymity anonymity-level for the content
856 * @param replication replication-level for the content
851 * @param expiration expiration time for the content 857 * @param expiration expiration time for the content
852 * @param uid unique identifier for the datum; 858 * @param uid unique identifier for the datum;
853 * maybe 0 if no unique identifier is available 859 * maybe 0 if no unique identifier is available
@@ -856,13 +862,14 @@ check_present_continuation (void *cls,
856 */ 862 */
857static int 863static int
858check_present (void *cls, 864check_present (void *cls,
859 const struct GNUNET_HashCode *key, 865 const struct GNUNET_HashCode *key,
860 uint32_t size, 866 uint32_t size,
861 const void *data, 867 const void *data,
862 enum GNUNET_BLOCK_Type type, 868 enum GNUNET_BLOCK_Type type,
863 uint32_t priority, 869 uint32_t priority,
864 uint32_t anonymity, 870 uint32_t anonymity,
865 struct GNUNET_TIME_Absolute expiration, 871 uint32_t replication,
872 struct GNUNET_TIME_Absolute expiration,
866 uint64_t uid) 873 uint64_t uid)
867{ 874{
868 struct PutContext *pc = cls; 875 struct PutContext *pc = cls;
@@ -883,16 +890,17 @@ check_present (void *cls,
883 { 890 {
884 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 891 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
885 "Result already present in datastore\n"); 892 "Result already present in datastore\n");
886 /* FIXME: change API to allow increasing 'replication' counter */ 893 if ( (ntohl (dm->priority) > 0) ||
887 if ((ntohl (dm->priority) > 0) || 894 (ntohl (dm->replication) > 0) ||
888 (GNUNET_TIME_absolute_ntoh (dm->expiration).abs_value_us > 895 (GNUNET_TIME_absolute_ntoh (dm->expiration).abs_value_us >
889 expiration.abs_value_us)) 896 expiration.abs_value_us) )
890 plugin->api->update (plugin->api->cls, 897 plugin->api->update (plugin->api->cls,
891 uid, 898 uid,
892 (int32_t) ntohl (dm->priority), 899 ntohl (dm->priority),
900 ntohl (dm->replication),
893 GNUNET_TIME_absolute_ntoh (dm->expiration), 901 GNUNET_TIME_absolute_ntoh (dm->expiration),
894 &check_present_continuation, 902 &check_present_continuation,
895 pc->client); 903 pc->client);
896 else 904 else
897 { 905 {
898 transmit_status (pc->client, 906 transmit_status (pc->client,
@@ -949,7 +957,7 @@ handle_put (void *cls,
949 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 957 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
950 "Processing PUT request for `%s' of type %u\n", 958 "Processing PUT request for `%s' of type %u\n",
951 GNUNET_h2s (&dm->key), 959 GNUNET_h2s (&dm->key),
952 ntohl (dm->type)); 960 (uint32_t) ntohl (dm->type));
953 rid = ntohl (dm->rid); 961 rid = ntohl (dm->rid);
954 size = ntohl (dm->size); 962 size = ntohl (dm->size);
955 if (rid > 0) 963 if (rid > 0)
@@ -984,12 +992,13 @@ handle_put (void *cls,
984 size, 992 size,
985 &vhash); 993 &vhash);
986 plugin->api->get_key (plugin->api->cls, 994 plugin->api->get_key (plugin->api->cls,
987 0, 995 0,
988 &dm->key, 996 false,
989 &vhash, 997 &dm->key,
998 &vhash,
990 ntohl (dm->type), 999 ntohl (dm->type),
991 &check_present, 1000 &check_present,
992 pc); 1001 pc);
993 GNUNET_SERVICE_client_continue (client); 1002 GNUNET_SERVICE_client_continue (client);
994 return; 1003 return;
995 } 1004 }
@@ -1012,13 +1021,14 @@ handle_get (void *cls,
1012 1021
1013 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1022 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1014 "Processing GET request of type %u\n", 1023 "Processing GET request of type %u\n",
1015 ntohl (msg->type)); 1024 (uint32_t) ntohl (msg->type));
1016 GNUNET_STATISTICS_update (stats, 1025 GNUNET_STATISTICS_update (stats,
1017 gettext_noop ("# GET requests received"), 1026 gettext_noop ("# GET requests received"),
1018 1, 1027 1,
1019 GNUNET_NO); 1028 GNUNET_NO);
1020 plugin->api->get_key (plugin->api->cls, 1029 plugin->api->get_key (plugin->api->cls,
1021 GNUNET_ntohll (msg->offset), 1030 GNUNET_ntohll (msg->next_uid),
1031 msg->random,
1022 NULL, 1032 NULL,
1023 NULL, 1033 NULL,
1024 ntohl (msg->type), 1034 ntohl (msg->type),
@@ -1043,7 +1053,7 @@ handle_get_key (void *cls,
1043 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1053 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1044 "Processing GET request for `%s' of type %u\n", 1054 "Processing GET request for `%s' of type %u\n",
1045 GNUNET_h2s (&msg->key), 1055 GNUNET_h2s (&msg->key),
1046 ntohl (msg->type)); 1056 (uint32_t) ntohl (msg->type));
1047 GNUNET_STATISTICS_update (stats, 1057 GNUNET_STATISTICS_update (stats,
1048 gettext_noop ("# GET KEY requests received"), 1058 gettext_noop ("# GET KEY requests received"),
1049 1, 1059 1,
@@ -1062,14 +1072,15 @@ handle_get_key (void *cls,
1062 1, 1072 1,
1063 GNUNET_NO); 1073 GNUNET_NO);
1064 transmit_item (client, 1074 transmit_item (client,
1065 NULL, 0, NULL, 0, 0, 0, 1075 NULL, 0, NULL, 0, 0, 0, 0,
1066 GNUNET_TIME_UNIT_ZERO_ABS, 1076 GNUNET_TIME_UNIT_ZERO_ABS,
1067 0); 1077 0);
1068 GNUNET_SERVICE_client_continue (client); 1078 GNUNET_SERVICE_client_continue (client);
1069 return; 1079 return;
1070 } 1080 }
1071 plugin->api->get_key (plugin->api->cls, 1081 plugin->api->get_key (plugin->api->cls,
1072 GNUNET_ntohll (msg->offset), 1082 GNUNET_ntohll (msg->next_uid),
1083 msg->random,
1073 &msg->key, 1084 &msg->key,
1074 NULL, 1085 NULL,
1075 ntohl (msg->type), 1086 ntohl (msg->type),
@@ -1080,55 +1091,6 @@ handle_get_key (void *cls,
1080 1091
1081 1092
1082/** 1093/**
1083 * Function called with the result of an update operation.
1084 *
1085 * @param cls closure
1086 * @param status #GNUNET_OK or #GNUNET_SYSERR
1087 * @param msg error message on error
1088 */
1089static void
1090update_continuation (void *cls,
1091 int status,
1092 const char *msg)
1093{
1094 struct GNUNET_SERVICE_Client *client = cls;
1095
1096 transmit_status (client,
1097 status,
1098 msg);
1099}
1100
1101
1102/**
1103 * Handle UPDATE-message.
1104 *
1105 * @param cls client identification of the client
1106 * @param message the actual message
1107 */
1108static void
1109handle_update (void *cls,
1110 const struct UpdateMessage *msg)
1111{
1112 struct GNUNET_SERVICE_Client *client = cls;
1113
1114 GNUNET_STATISTICS_update (stats,
1115 gettext_noop ("# UPDATE requests received"),
1116 1,
1117 GNUNET_NO);
1118 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1119 "Processing UPDATE request for %llu\n",
1120 (unsigned long long) GNUNET_ntohll (msg->uid));
1121 plugin->api->update (plugin->api->cls,
1122 GNUNET_ntohll (msg->uid),
1123 (int32_t) ntohl (msg->priority),
1124 GNUNET_TIME_absolute_ntoh (msg->expiration),
1125 &update_continuation,
1126 client);
1127 GNUNET_SERVICE_client_continue (client);
1128}
1129
1130
1131/**
1132 * Handle GET_REPLICATION-message. 1094 * Handle GET_REPLICATION-message.
1133 * 1095 *
1134 * @param cls identification of the client 1096 * @param cls identification of the client
@@ -1180,7 +1142,7 @@ handle_get_zero_anonymity (void *cls,
1180 1, 1142 1,
1181 GNUNET_NO); 1143 GNUNET_NO);
1182 plugin->api->get_zero_anonymity (plugin->api->cls, 1144 plugin->api->get_zero_anonymity (plugin->api->cls,
1183 GNUNET_ntohll (msg->offset), 1145 GNUNET_ntohll (msg->next_uid),
1184 type, 1146 type,
1185 &transmit_item, 1147 &transmit_item,
1186 client); 1148 client);
@@ -1199,6 +1161,7 @@ handle_get_zero_anonymity (void *cls,
1199 * @param type type of the content 1161 * @param type type of the content
1200 * @param priority priority of the content 1162 * @param priority priority of the content
1201 * @param anonymity anonymity-level for the content 1163 * @param anonymity anonymity-level for the content
1164 * @param replication replication-level for the content
1202 * @param expiration expiration time for the content 1165 * @param expiration expiration time for the content
1203 * @param uid unique identifier for the datum 1166 * @param uid unique identifier for the datum
1204 * @return #GNUNET_OK to keep the item 1167 * @return #GNUNET_OK to keep the item
@@ -1212,6 +1175,7 @@ remove_callback (void *cls,
1212 enum GNUNET_BLOCK_Type type, 1175 enum GNUNET_BLOCK_Type type,
1213 uint32_t priority, 1176 uint32_t priority,
1214 uint32_t anonymity, 1177 uint32_t anonymity,
1178 uint32_t replication,
1215 struct GNUNET_TIME_Absolute expiration, 1179 struct GNUNET_TIME_Absolute expiration,
1216 uint64_t uid) 1180 uint64_t uid)
1217{ 1181{
@@ -1287,9 +1251,10 @@ handle_remove (void *cls,
1287 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1251 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1288 "Processing REMOVE request for `%s' of type %u\n", 1252 "Processing REMOVE request for `%s' of type %u\n",
1289 GNUNET_h2s (&dm->key), 1253 GNUNET_h2s (&dm->key),
1290 ntohl (dm->type)); 1254 (uint32_t) ntohl (dm->type));
1291 plugin->api->get_key (plugin->api->cls, 1255 plugin->api->get_key (plugin->api->cls,
1292 0, 1256 0,
1257 false,
1293 &dm->key, 1258 &dm->key,
1294 &vhash, 1259 &vhash,
1295 (enum GNUNET_BLOCK_Type) ntohl (dm->type), 1260 (enum GNUNET_BLOCK_Type) ntohl (dm->type),
@@ -1857,10 +1822,6 @@ GNUNET_SERVICE_MAIN
1857 GNUNET_MESSAGE_TYPE_DATASTORE_PUT, 1822 GNUNET_MESSAGE_TYPE_DATASTORE_PUT,
1858 struct DataMessage, 1823 struct DataMessage,
1859 NULL), 1824 NULL),
1860 GNUNET_MQ_hd_fixed_size (update,
1861 GNUNET_MESSAGE_TYPE_DATASTORE_UPDATE,
1862 struct UpdateMessage,
1863 NULL),
1864 GNUNET_MQ_hd_fixed_size (get, 1825 GNUNET_MQ_hd_fixed_size (get,
1865 GNUNET_MESSAGE_TYPE_DATASTORE_GET, 1826 GNUNET_MESSAGE_TYPE_DATASTORE_GET,
1866 struct GetMessage, 1827 struct GetMessage,
diff --git a/src/datastore/perf_datastore_api.c b/src/datastore/perf_datastore_api.c
index 4f1f99a5c..10d9cf72e 100644
--- a/src/datastore/perf_datastore_api.c
+++ b/src/datastore/perf_datastore_api.c
@@ -303,6 +303,7 @@ remove_next (void *cls,
303 * @param type type of the content 303 * @param type type of the content
304 * @param priority priority of the content 304 * @param priority priority of the content
305 * @param anonymity anonymity-level for the content 305 * @param anonymity anonymity-level for the content
306 * @param replication replication-level for the content
306 * @param expiration expiration time for the content 307 * @param expiration expiration time for the content
307 * @param uid unique identifier for the datum; 308 * @param uid unique identifier for the datum;
308 * maybe 0 if no unique identifier is available 309 * maybe 0 if no unique identifier is available
@@ -315,6 +316,7 @@ delete_value (void *cls,
315 enum GNUNET_BLOCK_Type type, 316 enum GNUNET_BLOCK_Type type,
316 uint32_t priority, 317 uint32_t priority,
317 uint32_t anonymity, 318 uint32_t anonymity,
319 uint32_t replication,
318 struct GNUNET_TIME_Absolute expiration, 320 struct GNUNET_TIME_Absolute expiration,
319 uint64_t uid) 321 uint64_t uid)
320{ 322{
diff --git a/src/datastore/perf_plugin_datastore.c b/src/datastore/perf_plugin_datastore.c
index 1e43b74b4..2f9502989 100644
--- a/src/datastore/perf_plugin_datastore.c
+++ b/src/datastore/perf_plugin_datastore.c
@@ -197,13 +197,14 @@ do_put (struct CpsRunContext *crc)
197 197
198static int 198static int
199iterate_zeros (void *cls, 199iterate_zeros (void *cls,
200 const struct GNUNET_HashCode *key, 200 const struct GNUNET_HashCode *key,
201 uint32_t size, 201 uint32_t size,
202 const void *data, 202 const void *data,
203 enum GNUNET_BLOCK_Type type, 203 enum GNUNET_BLOCK_Type type,
204 uint32_t priority, 204 uint32_t priority,
205 uint32_t anonymity, 205 uint32_t anonymity,
206 struct GNUNET_TIME_Absolute expiration, 206 uint32_t replication,
207 struct GNUNET_TIME_Absolute expiration,
207 uint64_t uid) 208 uint64_t uid)
208{ 209{
209 struct CpsRunContext *crc = cls; 210 struct CpsRunContext *crc = cls;
@@ -253,14 +254,15 @@ iterate_zeros (void *cls,
253 254
254static int 255static int
255expiration_get (void *cls, 256expiration_get (void *cls,
256 const struct GNUNET_HashCode *key, 257 const struct GNUNET_HashCode *key,
257 uint32_t size, 258 uint32_t size,
258 const void *data, 259 const void *data,
259 enum GNUNET_BLOCK_Type type, 260 enum GNUNET_BLOCK_Type type,
260 uint32_t priority, 261 uint32_t priority,
261 uint32_t anonymity, 262 uint32_t anonymity,
263 uint32_t replication,
262 struct GNUNET_TIME_Absolute expiration, 264 struct GNUNET_TIME_Absolute expiration,
263 uint64_t uid) 265 uint64_t uid)
264{ 266{
265 struct CpsRunContext *crc = cls; 267 struct CpsRunContext *crc = cls;
266 int i; 268 int i;
@@ -305,14 +307,15 @@ expiration_get (void *cls,
305 307
306static int 308static int
307replication_get (void *cls, 309replication_get (void *cls,
308 const struct GNUNET_HashCode *key, 310 const struct GNUNET_HashCode *key,
309 uint32_t size, 311 uint32_t size,
310 const void *data, 312 const void *data,
311 enum GNUNET_BLOCK_Type type, 313 enum GNUNET_BLOCK_Type type,
312 uint32_t priority, 314 uint32_t priority,
313 uint32_t anonymity, 315 uint32_t anonymity,
316 uint32_t replication,
314 struct GNUNET_TIME_Absolute expiration, 317 struct GNUNET_TIME_Absolute expiration,
315 uint64_t uid) 318 uint64_t uid)
316{ 319{
317 struct CpsRunContext *crc = cls; 320 struct CpsRunContext *crc = cls;
318 int i; 321 int i;
diff --git a/src/datastore/plugin_datastore_heap.c b/src/datastore/plugin_datastore_heap.c
index 977d599d2..d04c1cf60 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,28 @@ 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, 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->replication,
454 gc.value->expiration,
455 (uint64_t) (intptr_t) gc.value))
456 {
457 delete_value (plugin, gc.value);
458 }
509} 459}
510 460
511 461
@@ -531,8 +481,7 @@ heap_plugin_get_replication (void *cls,
531 value = GNUNET_CONTAINER_heap_remove_root (plugin->by_replication); 481 value = GNUNET_CONTAINER_heap_remove_root (plugin->by_replication);
532 if (NULL == value) 482 if (NULL == value)
533 { 483 {
534 proc (proc_cls, 484 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
535 NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
536 return; 485 return;
537 } 486 }
538 if (value->replication > 0) 487 if (value->replication > 0)
@@ -552,14 +501,15 @@ heap_plugin_get_replication (void *cls,
552 } 501 }
553 if (GNUNET_NO == 502 if (GNUNET_NO ==
554 proc (proc_cls, 503 proc (proc_cls,
555 &value->key, 504 &value->key,
556 value->size, 505 value->size,
557 &value[1], 506 &value[1],
558 value->type, 507 value->type,
559 value->priority, 508 value->priority,
560 value->anonymity, 509 value->anonymity,
561 value->expiration, 510 value->replication,
562 (uint64_t) (long) value)) 511 value->expiration,
512 (uint64_t) (intptr_t) value))
563 delete_value (plugin, value); 513 delete_value (plugin, value);
564} 514}
565 515
@@ -582,38 +532,37 @@ heap_plugin_get_expiration (void *cls, PluginDatumProcessor proc,
582 value = GNUNET_CONTAINER_heap_peek (plugin->by_expiration); 532 value = GNUNET_CONTAINER_heap_peek (plugin->by_expiration);
583 if (NULL == value) 533 if (NULL == value)
584 { 534 {
585 proc (proc_cls, 535 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
586 NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
587 return; 536 return;
588 } 537 }
589 if (GNUNET_NO == 538 if (GNUNET_NO ==
590 proc (proc_cls, 539 proc (proc_cls,
591 &value->key, 540 &value->key,
592 value->size, 541 value->size,
593 &value[1], 542 &value[1],
594 value->type, 543 value->type,
595 value->priority, 544 value->priority,
596 value->anonymity, 545 value->anonymity,
597 value->expiration, 546 value->replication,
598 (uint64_t) (long) value)) 547 value->expiration,
548 (uint64_t) (intptr_t) value))
599 delete_value (plugin, value); 549 delete_value (plugin, value);
600} 550}
601 551
602 552
603/** 553/**
604 * Update the priority for a particular key in the datastore. If 554 * Update the priority, replication and expiration for a particular
605 * the expiration time in value is different than the time found in 555 * unique ID in the datastore. If the expiration time in value is
606 * the datastore, the higher value should be kept. For the 556 * different than the time found in the datastore, the higher value
607 * anonymity level, the lower value is to be used. The specified 557 * should be kept. The specified priority and replication is added
608 * priority should be added to the existing priority, ignoring the 558 * to the existing value.
609 * priority in value.
610 * 559 *
611 * @param cls our `struct Plugin *` 560 * @param cls our `struct Plugin *`
612 * @param uid unique identifier of the datum 561 * @param uid unique identifier of the datum
613 * @param delta by how much should the priority 562 * @param priority by how much should the priority
614 * change? If priority + delta < 0 the 563 * change?
615 * priority should be set to 0 (never go 564 * @param replication by how much should the replication
616 * negative). 565 * change?
617 * @param expire new expiration time should be the 566 * @param expire new expiration time should be the
618 * MAX of any existing expiration time and 567 * MAX of any existing expiration time and
619 * this value 568 * this value
@@ -622,15 +571,16 @@ heap_plugin_get_expiration (void *cls, PluginDatumProcessor proc,
622 */ 571 */
623static void 572static void
624heap_plugin_update (void *cls, 573heap_plugin_update (void *cls,
625 uint64_t uid, 574 uint64_t uid,
626 int delta, 575 uint32_t priority,
627 struct GNUNET_TIME_Absolute expire, 576 uint32_t replication,
628 PluginUpdateCont cont, 577 struct GNUNET_TIME_Absolute expire,
629 void *cont_cls) 578 PluginUpdateCont cont,
579 void *cont_cls)
630{ 580{
631 struct Value *value; 581 struct Value *value;
632 582
633 value = (struct Value*) (long) uid; 583 value = (struct Value*) (intptr_t) uid;
634 GNUNET_assert (NULL != value); 584 GNUNET_assert (NULL != value);
635 if (value->expiration.abs_value_us != expire.abs_value_us) 585 if (value->expiration.abs_value_us != expire.abs_value_us)
636 { 586 {
@@ -638,10 +588,15 @@ heap_plugin_update (void *cls,
638 GNUNET_CONTAINER_heap_update_cost (value->expire_heap, 588 GNUNET_CONTAINER_heap_update_cost (value->expire_heap,
639 expire.abs_value_us); 589 expire.abs_value_us);
640 } 590 }
641 if ( (delta < 0) && (value->priority < - delta) ) 591 /* Saturating adds, don't overflow */
642 value->priority = 0; 592 if (value->priority > UINT32_MAX - priority)
593 value->priority = UINT32_MAX;
594 else
595 value->priority += priority;
596 if (value->replication > UINT32_MAX - replication)
597 value->replication = UINT32_MAX;
643 else 598 else
644 value->priority += delta; 599 value->replication += replication;
645 cont (cont_cls, GNUNET_OK, NULL); 600 cont (cont_cls, GNUNET_OK, NULL);
646} 601}
647 602
@@ -650,63 +605,53 @@ heap_plugin_update (void *cls,
650 * Call the given processor on an item with zero anonymity. 605 * Call the given processor on an item with zero anonymity.
651 * 606 *
652 * @param cls our "struct Plugin*" 607 * @param cls our "struct Plugin*"
653 * @param offset offset of the result (modulo num-results); 608 * @param next_uid return the result with lowest uid >= next_uid
654 * specific ordering does not matter for the offset
655 * @param type entries of which type should be considered? 609 * @param type entries of which type should be considered?
656 * Use 0 for any type. 610 * Must not be zero (ANY).
657 * @param proc function to call on each matching value; 611 * @param proc function to call on each matching value;
658 * will be called with NULL if no value matches 612 * will be called with NULL if no value matches
659 * @param proc_cls closure for proc 613 * @param proc_cls closure for proc
660 */ 614 */
661static void 615static void
662heap_plugin_get_zero_anonymity (void *cls, uint64_t offset, 616heap_plugin_get_zero_anonymity (void *cls, uint64_t next_uid,
663 enum GNUNET_BLOCK_Type type, 617 enum GNUNET_BLOCK_Type type,
664 PluginDatumProcessor proc, void *proc_cls) 618 PluginDatumProcessor proc, void *proc_cls)
665{ 619{
666 struct Plugin *plugin = cls; 620 struct Plugin *plugin = cls;
667 struct ZeroAnonByType *zabt; 621 struct ZeroAnonByType *zabt;
668 struct Value *value; 622 struct Value *value = NULL;
669 uint64_t count;
670 623
671 count = 0;
672 for (zabt = plugin->zero_head; NULL != zabt; zabt = zabt->next) 624 for (zabt = plugin->zero_head; NULL != zabt; zabt = zabt->next)
673 { 625 {
674 if ( (type != GNUNET_BLOCK_TYPE_ANY) && 626 if ( (type != GNUNET_BLOCK_TYPE_ANY) &&
675 (type != zabt->type) ) 627 (type != zabt->type) )
676 continue; 628 continue;
677 count += zabt->array_pos; 629 for (int i = 0; i < zabt->array_pos; ++i)
630 {
631 if ( (uint64_t) (intptr_t) zabt->array[i] < next_uid)
632 continue;
633 if ( (NULL != value) &&
634 (zabt->array[i] > value) )
635 continue;
636 value = zabt->array[i];
637 }
678 } 638 }
679 if (0 == count) 639 if (NULL == value)
680 { 640 {
681 proc (proc_cls, 641 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
682 NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
683 return; 642 return;
684 } 643 }
685 offset = offset % count;
686 for (zabt = plugin->zero_head; NULL != zabt; zabt = zabt->next)
687 {
688 if ( (type != GNUNET_BLOCK_TYPE_ANY) &&
689 (type != zabt->type) )
690 continue;
691 if (offset >= zabt->array_pos)
692 {
693 offset -= zabt->array_pos;
694 continue;
695 }
696 break;
697 }
698 GNUNET_assert (NULL != zabt);
699 value = zabt->array[offset];
700 if (GNUNET_NO == 644 if (GNUNET_NO ==
701 proc (proc_cls, 645 proc (proc_cls,
702 &value->key, 646 &value->key,
703 value->size, 647 value->size,
704 &value[1], 648 &value[1],
705 value->type, 649 value->type,
706 value->priority, 650 value->priority,
707 value->anonymity, 651 value->anonymity,
708 value->expiration, 652 value->replication,
709 (uint64_t) (long) value)) 653 value->expiration,
654 (uint64_t) (intptr_t) value))
710 delete_value (plugin, value); 655 delete_value (plugin, value);
711} 656}
712 657
diff --git a/src/datastore/plugin_datastore_mysql.c b/src/datastore/plugin_datastore_mysql.c
index d76b4ccb4..6f2a76499 100644
--- a/src/datastore/plugin_datastore_mysql.c
+++ b/src/datastore/plugin_datastore_mysql.c
@@ -150,31 +150,56 @@ 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 RESULT_COLUMNS "repl, type, prio, anonLevel, expire, hash, value, uid"
154 struct GNUNET_MYSQL_StatementHandle *count_entry_by_hash; 154
155 155#define SELECT_ENTRY "SELECT " RESULT_COLUMNS " FROM gn090 "\
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 "WHERE uid >= ? AND "\
157 "(rvalue >= ? OR 0 = ?) "\
158 "ORDER BY uid LIMIT 1"
159 struct GNUNET_MYSQL_StatementHandle *select_entry;
160
161#define SELECT_ENTRY_BY_HASH "SELECT " RESULT_COLUMNS " FROM gn090 "\
162 "FORCE INDEX (idx_hash) "\
163 "WHERE hash=? AND "\
164 "uid >= ? AND "\
165 "(rvalue >= ? OR 0 = ?) "\
166 "ORDER BY uid LIMIT 1"
157 struct GNUNET_MYSQL_StatementHandle *select_entry_by_hash; 167 struct GNUNET_MYSQL_StatementHandle *select_entry_by_hash;
158 168
159#define COUNT_ENTRY_BY_HASH_AND_VHASH "SELECT count(*) FROM gn090 FORCE INDEX (idx_hash_vhash) WHERE hash=? AND vhash=?" 169#define SELECT_ENTRY_BY_HASH_AND_VHASH "SELECT " RESULT_COLUMNS " FROM gn090 "\
160 struct GNUNET_MYSQL_StatementHandle *count_entry_by_hash_and_vhash; 170 "FORCE INDEX (idx_hash_vhash) "\
161 171 "WHERE hash = ? AND "\
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 ?" 172 "vhash = ? AND "\
173 "uid >= ? AND "\
174 "(rvalue >= ? OR 0 = ?) "\
175 "ORDER BY uid LIMIT 1"
163 struct GNUNET_MYSQL_StatementHandle *select_entry_by_hash_and_vhash; 176 struct GNUNET_MYSQL_StatementHandle *select_entry_by_hash_and_vhash;
164 177
165#define COUNT_ENTRY_BY_HASH_AND_TYPE "SELECT count(*) FROM gn090 FORCE INDEX (idx_hash_type_uid) WHERE hash=? AND type=?" 178#define SELECT_ENTRY_BY_HASH_AND_TYPE "SELECT " RESULT_COLUMNS " FROM gn090 "\
166 struct GNUNET_MYSQL_StatementHandle *count_entry_by_hash_and_type; 179 "FORCE INDEX (idx_hash_type_uid) "\
167 180 "WHERE hash = ? AND "\
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 ?" 181 "type = ? AND "\
182 "uid >= ? AND "\
183 "(rvalue >= ? OR 0 = ?) "\
184 "ORDER BY uid LIMIT 1"
169 struct GNUNET_MYSQL_StatementHandle *select_entry_by_hash_and_type; 185 struct GNUNET_MYSQL_StatementHandle *select_entry_by_hash_and_type;
170 186
171#define COUNT_ENTRY_BY_HASH_VHASH_AND_TYPE "SELECT count(*) FROM gn090 FORCE INDEX (idx_hash_vhash) WHERE hash=? AND vhash=? AND type=?" 187#define SELECT_ENTRY_BY_HASH_VHASH_AND_TYPE "SELECT " RESULT_COLUMNS " "\
172 struct GNUNET_MYSQL_StatementHandle *count_entry_by_hash_vhash_and_type; 188 "FROM gn090 "\
173 189 "FORCE INDEX (idx_hash_vhash) "\
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 ?" 190 "WHERE hash = ? AND "\
191 "vhash = ? AND "\
192 "type = ? AND "\
193 "uid >= ? AND "\
194 "(rvalue >= ? OR 0 = ?) "\
195 "ORDER BY uid LIMIT 1"
175 struct GNUNET_MYSQL_StatementHandle *select_entry_by_hash_vhash_and_type; 196 struct GNUNET_MYSQL_StatementHandle *select_entry_by_hash_vhash_and_type;
176 197
177#define UPDATE_ENTRY "UPDATE gn090 SET prio=prio+?,expire=IF(expire>=?,expire,?) WHERE uid=?" 198#define UPDATE_ENTRY "UPDATE gn090 SET "\
199 "prio = prio + ?, "\
200 "repl = repl + ?, "\
201 "expire = IF(expire >= ?, expire, ?) "\
202 "WHERE uid = ?"
178 struct GNUNET_MYSQL_StatementHandle *update_entry; 203 struct GNUNET_MYSQL_StatementHandle *update_entry;
179 204
180#define DEC_REPL "UPDATE gn090 SET repl=GREATEST (1, repl) - 1 WHERE uid=?" 205#define DEC_REPL "UPDATE gn090 SET repl=GREATEST (1, repl) - 1 WHERE uid=?"
@@ -183,22 +208,27 @@ struct Plugin
183#define SELECT_SIZE "SELECT SUM(LENGTH(value)+256) FROM gn090" 208#define SELECT_SIZE "SELECT SUM(LENGTH(value)+256) FROM gn090"
184 struct GNUNET_MYSQL_StatementHandle *get_size; 209 struct GNUNET_MYSQL_StatementHandle *get_size;
185 210
186#define SELECT_IT_NON_ANONYMOUS "SELECT type,prio,anonLevel,expire,hash,value,uid "\ 211#define SELECT_IT_NON_ANONYMOUS "SELECT " RESULT_COLUMNS " FROM gn090 "\
187 "FROM gn090 FORCE INDEX (idx_anonLevel_type_rvalue) "\ 212 "FORCE INDEX (idx_anonLevel_type_rvalue) "\
188 "WHERE anonLevel=0 AND type=? AND "\ 213 "WHERE anonLevel=0 AND "\
189 "(rvalue >= ? OR"\ 214 "type=? AND "\
190 " NOT EXISTS (SELECT 1 FROM gn090 FORCE INDEX (idx_anonLevel_type_rvalue) WHERE anonLevel=0 AND type=? AND rvalue>=?)) "\ 215 "uid >= ? "\
191 "ORDER BY rvalue ASC LIMIT 1" 216 "ORDER BY uid LIMIT 1"
192 struct GNUNET_MYSQL_StatementHandle *zero_iter; 217 struct GNUNET_MYSQL_StatementHandle *zero_iter;
193 218
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" 219#define SELECT_IT_EXPIRATION "SELECT " RESULT_COLUMNS " FROM gn090 "\
220 "FORCE INDEX (idx_expire) "\
221 "WHERE expire < ? "\
222 "ORDER BY expire ASC LIMIT 1"
195 struct GNUNET_MYSQL_StatementHandle *select_expiration; 223 struct GNUNET_MYSQL_StatementHandle *select_expiration;
196 224
197#define SELECT_IT_PRIORITY "SELECT type,prio,anonLevel,expire,hash,value,uid FROM gn090 FORCE INDEX (idx_prio) ORDER BY prio ASC LIMIT 1" 225#define SELECT_IT_PRIORITY "SELECT " RESULT_COLUMNS " FROM gn090 "\
226 "FORCE INDEX (idx_prio) "\
227 "ORDER BY prio ASC LIMIT 1"
198 struct GNUNET_MYSQL_StatementHandle *select_priority; 228 struct GNUNET_MYSQL_StatementHandle *select_priority;
199 229
200#define SELECT_IT_REPLICATION "SELECT type,prio,anonLevel,expire,hash,value,uid "\ 230#define SELECT_IT_REPLICATION "SELECT " RESULT_COLUMNS " FROM gn090 "\
201 "FROM gn090 FORCE INDEX (idx_repl_rvalue) "\ 231 "FORCE INDEX (idx_repl_rvalue) "\
202 "WHERE repl=? AND "\ 232 "WHERE repl=? AND "\
203 " (rvalue>=? OR"\ 233 " (rvalue>=? OR"\
204 " NOT EXISTS (SELECT 1 FROM gn090 FORCE INDEX (idx_repl_rvalue) WHERE repl=? AND rvalue>=?)) "\ 234 " NOT EXISTS (SELECT 1 FROM gn090 FORCE INDEX (idx_repl_rvalue) WHERE repl=? AND rvalue>=?)) "\
@@ -382,22 +412,18 @@ mysql_plugin_put (void *cls,
382 412
383 413
384/** 414/**
385 * Update the priority for a particular key in the datastore. If 415 * Update the priority, replication and expiration for a particular
386 * the expiration time in value is different than the time found in 416 * unique ID in the datastore. If the expiration time in value is
387 * the datastore, the higher value should be kept. For the 417 * different than the time found in the datastore, the higher value
388 * anonymity level, the lower value is to be used. The specified 418 * should be kept. The specified priority and replication is added
389 * priority should be added to the existing priority, ignoring the 419 * to the existing value.
390 * priority in value.
391 *
392 * Note that it is possible for multiple values to match this put.
393 * In that case, all of the respective values are updated.
394 * 420 *
395 * @param cls our "struct Plugin*" 421 * @param cls our "struct Plugin*"
396 * @param uid unique identifier of the datum 422 * @param uid unique identifier of the datum
397 * @param delta by how much should the priority 423 * @param priority by how much should the priority
398 * change? If priority + delta < 0 the 424 * change?
399 * priority should be set to 0 (never go 425 * @param replication by how much should the replication
400 * negative). 426 * change?
401 * @param expire new expiration time should be the 427 * @param expire new expiration time should be the
402 * MAX of any existing expiration time and 428 * MAX of any existing expiration time and
403 * this value 429 * this value
@@ -407,24 +433,26 @@ mysql_plugin_put (void *cls,
407static void 433static void
408mysql_plugin_update (void *cls, 434mysql_plugin_update (void *cls,
409 uint64_t uid, 435 uint64_t uid,
410 int delta, 436 uint32_t priority,
437 uint32_t replication,
411 struct GNUNET_TIME_Absolute expire, 438 struct GNUNET_TIME_Absolute expire,
412 PluginUpdateCont cont, 439 PluginUpdateCont cont,
413 void *cont_cls) 440 void *cont_cls)
414{ 441{
415 struct Plugin *plugin = cls; 442 struct Plugin *plugin = cls;
416 uint32_t idelta = (uint32_t) delta;
417 uint64_t lexpire = expire.abs_value_us; 443 uint64_t lexpire = expire.abs_value_us;
418 int ret; 444 int ret;
419 445
420 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 446 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
421 "Updating value %llu adding %d to priority and maxing exp at %s\n", 447 "Updating value %llu adding %d to priority %d to replication and maxing exp at %s\n",
422 (unsigned long long) uid, 448 (unsigned long long) uid,
423 delta, 449 priority,
424 GNUNET_STRINGS_absolute_time_to_string (expire)); 450 replication,
451 GNUNET_STRINGS_absolute_time_to_string (expire));
425 452
426 struct GNUNET_MY_QueryParam params_update[] = { 453 struct GNUNET_MY_QueryParam params_update[] = {
427 GNUNET_MY_query_param_uint32 (&idelta), 454 GNUNET_MY_query_param_uint32 (&priority),
455 GNUNET_MY_query_param_uint32 (&replication),
428 GNUNET_MY_query_param_uint64 (&lexpire), 456 GNUNET_MY_query_param_uint64 (&lexpire),
429 GNUNET_MY_query_param_uint64 (&lexpire), 457 GNUNET_MY_query_param_uint64 (&lexpire),
430 GNUNET_MY_query_param_uint64 (&uid), 458 GNUNET_MY_query_param_uint64 (&uid),
@@ -471,6 +499,7 @@ execute_select (struct Plugin *plugin,
471 struct GNUNET_MY_QueryParam *params_select) 499 struct GNUNET_MY_QueryParam *params_select)
472{ 500{
473 int ret; 501 int ret;
502 uint32_t replication;
474 uint32_t type; 503 uint32_t type;
475 uint32_t priority; 504 uint32_t priority;
476 uint32_t anonymity; 505 uint32_t anonymity;
@@ -480,6 +509,7 @@ execute_select (struct Plugin *plugin,
480 struct GNUNET_HashCode key; 509 struct GNUNET_HashCode key;
481 struct GNUNET_TIME_Absolute expiration; 510 struct GNUNET_TIME_Absolute expiration;
482 struct GNUNET_MY_ResultSpec results_select[] = { 511 struct GNUNET_MY_ResultSpec results_select[] = {
512 GNUNET_MY_result_spec_uint32 (&replication),
483 GNUNET_MY_result_spec_uint32 (&type), 513 GNUNET_MY_result_spec_uint32 (&type),
484 GNUNET_MY_result_spec_uint32 (&priority), 514 GNUNET_MY_result_spec_uint32 (&priority),
485 GNUNET_MY_result_spec_uint32 (&anonymity), 515 GNUNET_MY_result_spec_uint32 (&anonymity),
@@ -496,7 +526,7 @@ execute_select (struct Plugin *plugin,
496 if (GNUNET_OK != ret) 526 if (GNUNET_OK != ret)
497 { 527 {
498 proc (proc_cls, 528 proc (proc_cls,
499 NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); 529 NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
500 return; 530 return;
501 } 531 }
502 532
@@ -505,7 +535,7 @@ execute_select (struct Plugin *plugin,
505 if (GNUNET_OK != ret) 535 if (GNUNET_OK != ret)
506 { 536 {
507 proc (proc_cls, 537 proc (proc_cls,
508 NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); 538 NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
509 return; 539 return;
510 } 540 }
511 541
@@ -527,6 +557,7 @@ execute_select (struct Plugin *plugin,
527 type, 557 type,
528 priority, 558 priority,
529 anonymity, 559 anonymity,
560 replication,
530 expiration, 561 expiration,
531 uid); 562 uid);
532 GNUNET_MY_cleanup_result (results_select); 563 GNUNET_MY_cleanup_result (results_select);
@@ -544,8 +575,8 @@ execute_select (struct Plugin *plugin,
544 * Get one of the results for a particular key in the datastore. 575 * Get one of the results for a particular key in the datastore.
545 * 576 *
546 * @param cls closure 577 * @param cls closure
547 * @param offset offset of the result (modulo num-results); 578 * @param next_uid return the result with lowest uid >= next_uid
548 * specific ordering does not matter for the offset 579 * @param random if true, return a random result instead of using next_uid
549 * @param key key to match, never NULL 580 * @param key key to match, never NULL
550 * @param vhash hash of the value, maybe NULL (to 581 * @param vhash hash of the value, maybe NULL (to
551 * match all values that have the right key). 582 * match all values that have the right key).
@@ -560,7 +591,8 @@ execute_select (struct Plugin *plugin,
560 */ 591 */
561static void 592static void
562mysql_plugin_get_key (void *cls, 593mysql_plugin_get_key (void *cls,
563 uint64_t offset, 594 uint64_t next_uid,
595 bool random,
564 const struct GNUNET_HashCode *key, 596 const struct GNUNET_HashCode *key,
565 const struct GNUNET_HashCode *vhash, 597 const struct GNUNET_HashCode *vhash,
566 enum GNUNET_BLOCK_Type type, 598 enum GNUNET_BLOCK_Type type,
@@ -568,121 +600,33 @@ mysql_plugin_get_key (void *cls,
568 void *proc_cls) 600 void *proc_cls)
569{ 601{
570 struct Plugin *plugin = cls; 602 struct Plugin *plugin = cls;
571 int ret; 603 uint64_t rvalue;
572 uint64_t total;
573 struct GNUNET_MY_ResultSpec results_get[] = {
574 GNUNET_MY_result_spec_uint64 (&total),
575 GNUNET_MY_result_spec_end
576 };
577 604
578 total = UINT64_MAX; 605 if (random)
579 if (0 != type)
580 { 606 {
581 if (NULL != vhash) 607 rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
582 { 608 UINT64_MAX);
583 struct GNUNET_MY_QueryParam params_get[] = { 609 next_uid = 0;
584 GNUNET_MY_query_param_auto_from_type (key),
585 GNUNET_MY_query_param_auto_from_type (vhash),
586 GNUNET_MY_query_param_uint32 (&type),
587 GNUNET_MY_query_param_end
588 };
589
590 ret =
591 GNUNET_MY_exec_prepared (plugin->mc,
592 plugin->count_entry_by_hash_vhash_and_type,
593 params_get);
594 GNUNET_break (GNUNET_OK == ret);
595 if (GNUNET_OK == ret)
596 ret =
597 GNUNET_MY_extract_result (plugin->count_entry_by_hash_vhash_and_type,
598 results_get);
599 if (GNUNET_OK == ret)
600 GNUNET_break (GNUNET_NO ==
601 GNUNET_MY_extract_result (plugin->count_entry_by_hash_vhash_and_type,
602 NULL));
603 }
604 else
605 {
606 struct GNUNET_MY_QueryParam params_get[] = {
607 GNUNET_MY_query_param_auto_from_type (key),
608 GNUNET_MY_query_param_uint32 (&type),
609 GNUNET_MY_query_param_end
610 };
611
612 ret =
613 GNUNET_MY_exec_prepared (plugin->mc,
614 plugin->count_entry_by_hash_and_type,
615 params_get);
616 GNUNET_break (GNUNET_OK == ret);
617 if (GNUNET_OK == ret)
618 ret =
619 GNUNET_MY_extract_result (plugin->count_entry_by_hash_and_type,
620 results_get);
621 if (GNUNET_OK == ret)
622 GNUNET_break (GNUNET_NO ==
623 GNUNET_MY_extract_result (plugin->count_entry_by_hash_and_type,
624 NULL));
625 }
626 } 610 }
627 else 611 else
628 { 612 rvalue = 0;
629 if (NULL != vhash)
630 {
631 struct GNUNET_MY_QueryParam params_get[] = {
632 GNUNET_MY_query_param_auto_from_type (key),
633 GNUNET_MY_query_param_auto_from_type (vhash),
634 GNUNET_MY_query_param_end
635 };
636 613
637 ret = 614 if (NULL == key)
638 GNUNET_MY_exec_prepared (plugin->mc,
639 plugin->count_entry_by_hash_and_vhash,
640 params_get);
641 GNUNET_break (GNUNET_OK == ret);
642 if (GNUNET_OK == ret)
643 ret =
644 GNUNET_MY_extract_result (plugin->count_entry_by_hash_and_vhash,
645 results_get);
646 if (GNUNET_OK == ret)
647 GNUNET_break (GNUNET_NO ==
648 GNUNET_MY_extract_result (plugin->count_entry_by_hash_and_vhash,
649 NULL));
650 }
651 else
652 {
653 struct GNUNET_MY_QueryParam params_get[] = {
654 GNUNET_MY_query_param_auto_from_type (key),
655 GNUNET_MY_query_param_end
656 };
657
658 ret =
659 GNUNET_MY_exec_prepared (plugin->mc,
660 plugin->count_entry_by_hash,
661 params_get);
662 GNUNET_break (GNUNET_OK == ret);
663 if (GNUNET_OK == ret)
664 ret =
665 GNUNET_MY_extract_result (plugin->count_entry_by_hash,
666 results_get);
667 if (GNUNET_OK == ret)
668 GNUNET_break (GNUNET_NO ==
669 GNUNET_MY_extract_result (plugin->count_entry_by_hash,
670 NULL));
671 }
672 }
673 if ( (GNUNET_OK != ret) ||
674 (0 >= total) )
675 { 615 {
676 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); 616 struct GNUNET_MY_QueryParam params_select[] = {
677 return; 617 GNUNET_MY_query_param_uint64 (&next_uid),
618 GNUNET_MY_query_param_uint64 (&rvalue),
619 GNUNET_MY_query_param_uint64 (&rvalue),
620 GNUNET_MY_query_param_end
621 };
622
623 execute_select (plugin,
624 plugin->select_entry,
625 proc,
626 proc_cls,
627 params_select);
678 } 628 }
679 offset = offset % total; 629 else if (type != GNUNET_BLOCK_TYPE_ANY)
680 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
681 "Obtaining %llu/%lld result for GET `%s'\n",
682 (unsigned long long) offset,
683 (unsigned long long) total,
684 GNUNET_h2s (key));
685 if (type != GNUNET_BLOCK_TYPE_ANY)
686 { 630 {
687 if (NULL != vhash) 631 if (NULL != vhash)
688 { 632 {
@@ -690,7 +634,9 @@ mysql_plugin_get_key (void *cls,
690 GNUNET_MY_query_param_auto_from_type (key), 634 GNUNET_MY_query_param_auto_from_type (key),
691 GNUNET_MY_query_param_auto_from_type (vhash), 635 GNUNET_MY_query_param_auto_from_type (vhash),
692 GNUNET_MY_query_param_uint32 (&type), 636 GNUNET_MY_query_param_uint32 (&type),
693 GNUNET_MY_query_param_uint64 (&offset), 637 GNUNET_MY_query_param_uint64 (&next_uid),
638 GNUNET_MY_query_param_uint64 (&rvalue),
639 GNUNET_MY_query_param_uint64 (&rvalue),
694 GNUNET_MY_query_param_end 640 GNUNET_MY_query_param_end
695 }; 641 };
696 642
@@ -705,7 +651,9 @@ mysql_plugin_get_key (void *cls,
705 struct GNUNET_MY_QueryParam params_select[] = { 651 struct GNUNET_MY_QueryParam params_select[] = {
706 GNUNET_MY_query_param_auto_from_type (key), 652 GNUNET_MY_query_param_auto_from_type (key),
707 GNUNET_MY_query_param_uint32 (&type), 653 GNUNET_MY_query_param_uint32 (&type),
708 GNUNET_MY_query_param_uint64 (&offset), 654 GNUNET_MY_query_param_uint64 (&next_uid),
655 GNUNET_MY_query_param_uint64 (&rvalue),
656 GNUNET_MY_query_param_uint64 (&rvalue),
709 GNUNET_MY_query_param_end 657 GNUNET_MY_query_param_end
710 }; 658 };
711 659
@@ -723,7 +671,9 @@ mysql_plugin_get_key (void *cls,
723 struct GNUNET_MY_QueryParam params_select[] = { 671 struct GNUNET_MY_QueryParam params_select[] = {
724 GNUNET_MY_query_param_auto_from_type (key), 672 GNUNET_MY_query_param_auto_from_type (key),
725 GNUNET_MY_query_param_auto_from_type (vhash), 673 GNUNET_MY_query_param_auto_from_type (vhash),
726 GNUNET_MY_query_param_uint64 (&offset), 674 GNUNET_MY_query_param_uint64 (&next_uid),
675 GNUNET_MY_query_param_uint64 (&rvalue),
676 GNUNET_MY_query_param_uint64 (&rvalue),
727 GNUNET_MY_query_param_end 677 GNUNET_MY_query_param_end
728 }; 678 };
729 679
@@ -737,7 +687,9 @@ mysql_plugin_get_key (void *cls,
737 { 687 {
738 struct GNUNET_MY_QueryParam params_select[] = { 688 struct GNUNET_MY_QueryParam params_select[] = {
739 GNUNET_MY_query_param_auto_from_type (key), 689 GNUNET_MY_query_param_auto_from_type (key),
740 GNUNET_MY_query_param_uint64 (&offset), 690 GNUNET_MY_query_param_uint64 (&next_uid),
691 GNUNET_MY_query_param_uint64 (&rvalue),
692 GNUNET_MY_query_param_uint64 (&rvalue),
741 GNUNET_MY_query_param_end 693 GNUNET_MY_query_param_end
742 }; 694 };
743 695
@@ -756,28 +708,26 @@ mysql_plugin_get_key (void *cls,
756 * Get a zero-anonymity datum from the datastore. 708 * Get a zero-anonymity datum from the datastore.
757 * 709 *
758 * @param cls our `struct Plugin *` 710 * @param cls our `struct Plugin *`
759 * @param offset offset of the result 711 * @param next_uid return the result with lowest uid >= next_uid
760 * @param type entries of which type should be considered? 712 * @param type entries of which type should be considered?
761 * Use 0 for any type. 713 * Must not be zero (ANY).
762 * @param proc function to call on a matching value or NULL 714 * @param proc function to call on a matching value;
715 * will be called with NULL if no value matches
763 * @param proc_cls closure for @a proc 716 * @param proc_cls closure for @a proc
764 */ 717 */
765static void 718static void
766mysql_plugin_get_zero_anonymity (void *cls, 719mysql_plugin_get_zero_anonymity (void *cls,
767 uint64_t offset, 720 uint64_t next_uid,
768 enum GNUNET_BLOCK_Type type, 721 enum GNUNET_BLOCK_Type type,
769 PluginDatumProcessor proc, 722 PluginDatumProcessor proc,
770 void *proc_cls) 723 void *proc_cls)
771{ 724{
772 struct Plugin *plugin = cls; 725 struct Plugin *plugin = cls;
773 uint32_t typei = (uint32_t) type; 726 uint32_t typei = (uint32_t) type;
774 uint64_t rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, 727
775 UINT64_MAX);
776 struct GNUNET_MY_QueryParam params_zero_iter[] = { 728 struct GNUNET_MY_QueryParam params_zero_iter[] = {
777 GNUNET_MY_query_param_uint32 (&typei), 729 GNUNET_MY_query_param_uint32 (&typei),
778 GNUNET_MY_query_param_uint64 (&rvalue), 730 GNUNET_MY_query_param_uint64 (&next_uid),
779 GNUNET_MY_query_param_uint32 (&typei),
780 GNUNET_MY_query_param_uint64 (&rvalue),
781 GNUNET_MY_query_param_end 731 GNUNET_MY_query_param_end
782 }; 732 };
783 733
@@ -824,6 +774,7 @@ struct ReplCtx
824 * @param type type of the content 774 * @param type type of the content
825 * @param priority priority of the content 775 * @param priority priority of the content
826 * @param anonymity anonymity-level for the content 776 * @param anonymity anonymity-level for the content
777 * @param replication replication-level for the content
827 * @param expiration expiration time for the content 778 * @param expiration expiration time for the content
828 * @param uid unique identifier for the datum; 779 * @param uid unique identifier for the datum;
829 * maybe 0 if no unique identifier is available 780 * maybe 0 if no unique identifier is available
@@ -839,6 +790,7 @@ repl_proc (void *cls,
839 enum GNUNET_BLOCK_Type type, 790 enum GNUNET_BLOCK_Type type,
840 uint32_t priority, 791 uint32_t priority,
841 uint32_t anonymity, 792 uint32_t anonymity,
793 uint32_t replication,
842 struct GNUNET_TIME_Absolute expiration, 794 struct GNUNET_TIME_Absolute expiration,
843 uint64_t uid) 795 uint64_t uid)
844{ 796{
@@ -854,6 +806,7 @@ repl_proc (void *cls,
854 type, 806 type,
855 priority, 807 priority,
856 anonymity, 808 anonymity,
809 replication,
857 expiration, 810 expiration,
858 uid); 811 uid);
859 if (NULL != key) 812 if (NULL != key)
@@ -921,7 +874,7 @@ mysql_plugin_get_replication (void *cls,
921 plugin->max_repl, 874 plugin->max_repl,
922 params_get)) 875 params_get))
923 { 876 {
924 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); 877 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
925 return; 878 return;
926 } 879 }
927 880
@@ -929,7 +882,7 @@ mysql_plugin_get_replication (void *cls,
929 GNUNET_MY_extract_result (plugin->max_repl, 882 GNUNET_MY_extract_result (plugin->max_repl,
930 results_get)) 883 results_get))
931 { 884 {
932 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); 885 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
933 return; 886 return;
934 } 887 }
935 GNUNET_break (GNUNET_NO == 888 GNUNET_break (GNUNET_NO ==
@@ -1071,6 +1024,7 @@ struct ExpiCtx
1071 * @param type type of the content 1024 * @param type type of the content
1072 * @param priority priority of the content 1025 * @param priority priority of the content
1073 * @param anonymity anonymity-level for the content 1026 * @param anonymity anonymity-level for the content
1027 * @param replication replication-level for the content
1074 * @param expiration expiration time for the content 1028 * @param expiration expiration time for the content
1075 * @param uid unique identifier for the datum; 1029 * @param uid unique identifier for the datum;
1076 * maybe 0 if no unique identifier is available 1030 * maybe 0 if no unique identifier is available
@@ -1086,6 +1040,7 @@ expi_proc (void *cls,
1086 enum GNUNET_BLOCK_Type type, 1040 enum GNUNET_BLOCK_Type type,
1087 uint32_t priority, 1041 uint32_t priority,
1088 uint32_t anonymity, 1042 uint32_t anonymity,
1043 uint32_t replication,
1089 struct GNUNET_TIME_Absolute expiration, 1044 struct GNUNET_TIME_Absolute expiration,
1090 uint64_t uid) 1045 uint64_t uid)
1091{ 1046{
@@ -1111,6 +1066,7 @@ expi_proc (void *cls,
1111 type, 1066 type,
1112 priority, 1067 priority,
1113 anonymity, 1068 anonymity,
1069 replication,
1114 expiration, 1070 expiration,
1115 uid); 1071 uid);
1116} 1072}
@@ -1212,6 +1168,7 @@ libgnunet_plugin_datastore_mysql_init (void *cls)
1212 ") ENGINE=InnoDB") || MRUNS ("SET AUTOCOMMIT = 1") || 1168 ") ENGINE=InnoDB") || MRUNS ("SET AUTOCOMMIT = 1") ||
1213 PINIT (plugin->insert_entry, INSERT_ENTRY) || 1169 PINIT (plugin->insert_entry, INSERT_ENTRY) ||
1214 PINIT (plugin->delete_entry_by_uid, DELETE_ENTRY_BY_UID) || 1170 PINIT (plugin->delete_entry_by_uid, DELETE_ENTRY_BY_UID) ||
1171 PINIT (plugin->select_entry, SELECT_ENTRY) ||
1215 PINIT (plugin->select_entry_by_hash, SELECT_ENTRY_BY_HASH) || 1172 PINIT (plugin->select_entry_by_hash, SELECT_ENTRY_BY_HASH) ||
1216 PINIT (plugin->select_entry_by_hash_and_vhash, 1173 PINIT (plugin->select_entry_by_hash_and_vhash,
1217 SELECT_ENTRY_BY_HASH_AND_VHASH) || 1174 SELECT_ENTRY_BY_HASH_AND_VHASH) ||
@@ -1219,13 +1176,7 @@ libgnunet_plugin_datastore_mysql_init (void *cls)
1219 SELECT_ENTRY_BY_HASH_AND_TYPE) || 1176 SELECT_ENTRY_BY_HASH_AND_TYPE) ||
1220 PINIT (plugin->select_entry_by_hash_vhash_and_type, 1177 PINIT (plugin->select_entry_by_hash_vhash_and_type,
1221 SELECT_ENTRY_BY_HASH_VHASH_AND_TYPE) || 1178 SELECT_ENTRY_BY_HASH_VHASH_AND_TYPE) ||
1222 PINIT (plugin->count_entry_by_hash, COUNT_ENTRY_BY_HASH) ||
1223 PINIT (plugin->get_size, SELECT_SIZE) || 1179 PINIT (plugin->get_size, SELECT_SIZE) ||
1224 PINIT (plugin->count_entry_by_hash_and_vhash,
1225 COUNT_ENTRY_BY_HASH_AND_VHASH) ||
1226 PINIT (plugin->count_entry_by_hash_and_type, COUNT_ENTRY_BY_HASH_AND_TYPE)
1227 || PINIT (plugin->count_entry_by_hash_vhash_and_type,
1228 COUNT_ENTRY_BY_HASH_VHASH_AND_TYPE) ||
1229 PINIT (plugin->update_entry, UPDATE_ENTRY) || 1180 PINIT (plugin->update_entry, UPDATE_ENTRY) ||
1230 PINIT (plugin->dec_repl, DEC_REPL) || 1181 PINIT (plugin->dec_repl, DEC_REPL) ||
1231 PINIT (plugin->zero_iter, SELECT_IT_NON_ANONYMOUS) || 1182 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 994118bfa..87a7acbdc 100644
--- a/src/datastore/plugin_datastore_postgres.c
+++ b/src/datastore/plugin_datastore_postgres.c
@@ -76,6 +76,12 @@ init_connection (struct Plugin *plugin)
76 if (NULL == plugin->dbh) 76 if (NULL == plugin->dbh)
77 return GNUNET_SYSERR; 77 return GNUNET_SYSERR;
78 78
79 /* FIXME: PostgreSQL does not have unsigned integers! This is ok for the type column because
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.
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.
84 */
79 ret = 85 ret =
80 PQexec (plugin->dbh, 86 PQexec (plugin->dbh,
81 "CREATE TABLE IF NOT EXISTS gn090 (" 87 "CREATE TABLE IF NOT EXISTS gn090 ("
@@ -109,13 +115,17 @@ init_connection (struct Plugin *plugin)
109 if (PQresultStatus (ret) == PGRES_COMMAND_OK) 115 if (PQresultStatus (ret) == PGRES_COMMAND_OK)
110 { 116 {
111 if ((GNUNET_OK != 117 if ((GNUNET_OK !=
112 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)")) ||
113 (GNUNET_OK != 120 (GNUNET_OK !=
114 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)")) ||
115 (GNUNET_OK != 123 (GNUNET_OK !=
116 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)")) ||
117 (GNUNET_OK != 126 (GNUNET_OK !=
118 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)")) ||
119 (GNUNET_OK != 129 (GNUNET_OK !=
120 GNUNET_POSTGRES_exec (plugin->dbh, 130 GNUNET_POSTGRES_exec (plugin->dbh,
121 "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)")) ||
@@ -123,9 +133,11 @@ init_connection (struct Plugin *plugin)
123 GNUNET_POSTGRES_exec (plugin->dbh, 133 GNUNET_POSTGRES_exec (plugin->dbh,
124 "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)")) ||
125 (GNUNET_OK != 135 (GNUNET_OK !=
126 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)")) ||
127 (GNUNET_OK != 138 (GNUNET_OK !=
128 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)")))
129 { 141 {
130 PQclear (ret); 142 PQclear (ret);
131 PQfinish (plugin->dbh); 143 PQfinish (plugin->dbh);
@@ -164,64 +176,49 @@ init_connection (struct Plugin *plugin)
164 return GNUNET_SYSERR; 176 return GNUNET_SYSERR;
165 } 177 }
166 PQclear (ret); 178 PQclear (ret);
179#define RESULT_COLUMNS "repl, type, prio, anonLevel, expire, hash, value, oid"
167 if ((GNUNET_OK != 180 if ((GNUNET_OK !=
168 GNUNET_POSTGRES_prepare (plugin->dbh, "getvt",
169 "SELECT type, prio, anonLevel, expire, hash, value, oid FROM gn090 "
170 "WHERE hash=$1 AND vhash=$2 AND type=$3 "
171 "ORDER BY oid ASC LIMIT 1 OFFSET $4", 4)) ||
172 (GNUNET_OK !=
173 GNUNET_POSTGRES_prepare (plugin->dbh, "gett",
174 "SELECT type, prio, anonLevel, expire, hash, value, oid FROM gn090 "
175 "WHERE hash=$1 AND type=$2 "
176 "ORDER BY oid ASC LIMIT 1 OFFSET $3", 3)) ||
177 (GNUNET_OK !=
178 GNUNET_POSTGRES_prepare (plugin->dbh, "getv",
179 "SELECT type, prio, anonLevel, expire, hash, value, oid FROM gn090 "
180 "WHERE hash=$1 AND vhash=$2 "
181 "ORDER BY oid ASC LIMIT 1 OFFSET $3", 3)) ||
182 (GNUNET_OK !=
183 GNUNET_POSTGRES_prepare (plugin->dbh, "get", 181 GNUNET_POSTGRES_prepare (plugin->dbh, "get",
184 "SELECT type, prio, anonLevel, expire, hash, value, oid FROM gn090 " 182 "SELECT " RESULT_COLUMNS " FROM gn090 "
185 "WHERE hash=$1 " "ORDER BY oid ASC LIMIT 1 OFFSET $2", 2)) || 183 "WHERE oid >= $1::bigint AND "
186 (GNUNET_OK != 184 "(rvalue >= $2 OR 0 = $3::smallint) AND "
187 GNUNET_POSTGRES_prepare (plugin->dbh, "count_getvt", 185 "(hash = $4 OR 0 = $5::smallint) AND "
188 "SELECT count(*) FROM gn090 WHERE hash=$1 AND vhash=$2 AND type=$3", 3)) || 186 "(vhash = $6 OR 0 = $7::smallint) AND "
189 (GNUNET_OK != 187 "(type = $8 OR 0 = $9::smallint) "
190 GNUNET_POSTGRES_prepare (plugin->dbh, "count_gett", 188 "ORDER BY oid ASC LIMIT 1", 9)) ||
191 "SELECT count(*) FROM gn090 WHERE hash=$1 AND type=$2", 2)) ||
192 (GNUNET_OK !=
193 GNUNET_POSTGRES_prepare (plugin->dbh, "count_getv",
194 "SELECT count(*) FROM gn090 WHERE hash=$1 AND vhash=$2", 2)) ||
195 (GNUNET_OK !=
196 GNUNET_POSTGRES_prepare (plugin->dbh, "count_get",
197 "SELECT count(*) FROM gn090 WHERE hash=$1", 1)) ||
198 (GNUNET_OK != 189 (GNUNET_OK !=
199 GNUNET_POSTGRES_prepare (plugin->dbh, "put", 190 GNUNET_POSTGRES_prepare (plugin->dbh, "put",
200 "INSERT INTO gn090 (repl, type, prio, anonLevel, expire, rvalue, hash, vhash, value) " 191 "INSERT INTO gn090 (repl, type, prio, anonLevel, expire, rvalue, hash, vhash, value) "
201 "VALUES ($1, $2, $3, $4, $5, RANDOM(), $6, $7, $8)", 9)) || 192 "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)", 9)) ||
202 (GNUNET_OK != 193 (GNUNET_OK !=
203 GNUNET_POSTGRES_prepare (plugin->dbh, "update", 194 GNUNET_POSTGRES_prepare (plugin->dbh, "update",
204 "UPDATE gn090 SET prio = prio + $1, expire = CASE WHEN expire < $2 THEN $2 ELSE expire END " 195 "UPDATE gn090 "
205 "WHERE oid = $3", 3)) || 196 "SET prio = prio + $1, "
197 "repl = repl + $2, "
198 "expire = CASE WHEN expire < $3 THEN $3 ELSE expire END "
199 "WHERE oid = $4", 4)) ||
206 (GNUNET_OK != 200 (GNUNET_OK !=
207 GNUNET_POSTGRES_prepare (plugin->dbh, "decrepl", 201 GNUNET_POSTGRES_prepare (plugin->dbh, "decrepl",
208 "UPDATE gn090 SET repl = GREATEST (repl - 1, 0) " 202 "UPDATE gn090 SET repl = GREATEST (repl - 1, 0) "
209 "WHERE oid = $1", 1)) || 203 "WHERE oid = $1", 1)) ||
210 (GNUNET_OK != 204 (GNUNET_OK !=
211 GNUNET_POSTGRES_prepare (plugin->dbh, "select_non_anonymous", 205 GNUNET_POSTGRES_prepare (plugin->dbh, "select_non_anonymous",
212 "SELECT type, prio, anonLevel, expire, hash, value, oid FROM gn090 " 206 "SELECT " RESULT_COLUMNS " FROM gn090 "
213 "WHERE anonLevel = 0 AND type = $1 ORDER BY oid DESC LIMIT 1 OFFSET $2", 207 "WHERE anonLevel = 0 AND type = $1 AND oid >= $2::bigint "
214 1)) || 208 "ORDER BY oid ASC LIMIT 1",
209 2)) ||
215 (GNUNET_OK != 210 (GNUNET_OK !=
216 GNUNET_POSTGRES_prepare (plugin->dbh, "select_expiration_order", 211 GNUNET_POSTGRES_prepare (plugin->dbh, "select_expiration_order",
217 "(SELECT type, prio, anonLevel, expire, hash, value, oid FROM gn090 " 212 "(SELECT " RESULT_COLUMNS " FROM gn090 "
218 "WHERE expire < $1 ORDER BY prio ASC LIMIT 1) " "UNION " 213 "WHERE expire < $1 ORDER BY prio ASC LIMIT 1) "
219 "(SELECT type, prio, anonLevel, expire, hash, value, oid FROM gn090 " 214 "UNION "
220 "ORDER BY prio ASC LIMIT 1) " "ORDER BY expire ASC LIMIT 1", 215 "(SELECT " RESULT_COLUMNS " FROM gn090 "
216 "ORDER BY prio ASC LIMIT 1) "
217 "ORDER BY expire ASC LIMIT 1",
221 1)) || 218 1)) ||
222 (GNUNET_OK != 219 (GNUNET_OK !=
223 GNUNET_POSTGRES_prepare (plugin->dbh, "select_replication_order", 220 GNUNET_POSTGRES_prepare (plugin->dbh, "select_replication_order",
224 "SELECT type, prio, anonLevel, expire, hash, value, oid FROM gn090 " 221 "SELECT " RESULT_COLUMNS " FROM gn090 "
225 "ORDER BY repl DESC,RANDOM() LIMIT 1", 0)) || 222 "ORDER BY repl DESC,RANDOM() LIMIT 1", 0)) ||
226 (GNUNET_OK != 223 (GNUNET_OK !=
227 GNUNET_POSTGRES_prepare (plugin->dbh, "delrow", "DELETE FROM gn090 " "WHERE oid=$1", 1)) || 224 GNUNET_POSTGRES_prepare (plugin->dbh, "delrow", "DELETE FROM gn090 " "WHERE oid=$1", 1)) ||
@@ -317,6 +314,8 @@ postgres_plugin_put (void *cls,
317 struct Plugin *plugin = cls; 314 struct Plugin *plugin = cls;
318 uint32_t utype = type; 315 uint32_t utype = type;
319 struct GNUNET_HashCode vhash; 316 struct GNUNET_HashCode vhash;
317 uint64_t rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
318 UINT64_MAX);
320 PGresult *ret; 319 PGresult *ret;
321 struct GNUNET_PQ_QueryParam params[] = { 320 struct GNUNET_PQ_QueryParam params[] = {
322 GNUNET_PQ_query_param_uint32 (&replication), 321 GNUNET_PQ_query_param_uint32 (&replication),
@@ -324,6 +323,7 @@ postgres_plugin_put (void *cls,
324 GNUNET_PQ_query_param_uint32 (&priority), 323 GNUNET_PQ_query_param_uint32 (&priority),
325 GNUNET_PQ_query_param_uint32 (&anonymity), 324 GNUNET_PQ_query_param_uint32 (&anonymity),
326 GNUNET_PQ_query_param_absolute_time (&expiration), 325 GNUNET_PQ_query_param_absolute_time (&expiration),
326 GNUNET_PQ_query_param_uint64 (&rvalue),
327 GNUNET_PQ_query_param_auto_from_type (key), 327 GNUNET_PQ_query_param_auto_from_type (key),
328 GNUNET_PQ_query_param_auto_from_type (&vhash), 328 GNUNET_PQ_query_param_auto_from_type (&vhash),
329 GNUNET_PQ_query_param_fixed_size (data, size), 329 GNUNET_PQ_query_param_fixed_size (data, size),
@@ -377,19 +377,21 @@ process_result (struct Plugin *plugin,
377 uint32_t rowid; 377 uint32_t rowid;
378 uint32_t utype; 378 uint32_t utype;
379 uint32_t anonymity; 379 uint32_t anonymity;
380 uint32_t replication;
380 uint32_t priority; 381 uint32_t priority;
381 size_t size; 382 size_t size;
382 void *data; 383 void *data;
383 struct GNUNET_TIME_Absolute expiration_time; 384 struct GNUNET_TIME_Absolute expiration_time;
384 struct GNUNET_HashCode key; 385 struct GNUNET_HashCode key;
385 struct GNUNET_PQ_ResultSpec rs[] = { 386 struct GNUNET_PQ_ResultSpec rs[] = {
387 GNUNET_PQ_result_spec_uint32 ("repl", &replication),
386 GNUNET_PQ_result_spec_uint32 ("type", &utype), 388 GNUNET_PQ_result_spec_uint32 ("type", &utype),
387 GNUNET_PQ_result_spec_uint32 ("prio", &priority), 389 GNUNET_PQ_result_spec_uint32 ("prio", &priority),
388 GNUNET_PQ_result_spec_uint32 ("anonLevel", &anonymity), 390 GNUNET_PQ_result_spec_uint32 ("anonLevel", &anonymity),
389 GNUNET_PQ_result_spec_uint32 ("oid", &rowid),
390 GNUNET_PQ_result_spec_absolute_time ("expire", &expiration_time), 391 GNUNET_PQ_result_spec_absolute_time ("expire", &expiration_time),
391 GNUNET_PQ_result_spec_auto_from_type ("hash", &key), 392 GNUNET_PQ_result_spec_auto_from_type ("hash", &key),
392 GNUNET_PQ_result_spec_variable_size ("value", &data, &size), 393 GNUNET_PQ_result_spec_variable_size ("value", &data, &size),
394 GNUNET_PQ_result_spec_uint32 ("oid", &rowid),
393 GNUNET_PQ_result_spec_end 395 GNUNET_PQ_result_spec_end
394 }; 396 };
395 397
@@ -404,8 +406,7 @@ process_result (struct Plugin *plugin,
404 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, 406 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
405 "datastore-postgres", 407 "datastore-postgres",
406 "Ending iteration (postgres error)\n"); 408 "Ending iteration (postgres error)\n");
407 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 409 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
408 GNUNET_TIME_UNIT_ZERO_ABS, 0);
409 return; 410 return;
410 } 411 }
411 412
@@ -415,16 +416,14 @@ process_result (struct Plugin *plugin,
415 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, 416 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
416 "datastore-postgres", 417 "datastore-postgres",
417 "Ending iteration (no more results)\n"); 418 "Ending iteration (no more results)\n");
418 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 419 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
419 GNUNET_TIME_UNIT_ZERO_ABS, 0);
420 PQclear (res); 420 PQclear (res);
421 return; 421 return;
422 } 422 }
423 if (1 != PQntuples (res)) 423 if (1 != PQntuples (res))
424 { 424 {
425 GNUNET_break (0); 425 GNUNET_break (0);
426 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 426 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
427 GNUNET_TIME_UNIT_ZERO_ABS, 0);
428 PQclear (res); 427 PQclear (res);
429 return; 428 return;
430 } 429 }
@@ -438,8 +437,7 @@ process_result (struct Plugin *plugin,
438 GNUNET_POSTGRES_delete_by_rowid (plugin->dbh, 437 GNUNET_POSTGRES_delete_by_rowid (plugin->dbh,
439 "delrow", 438 "delrow",
440 rowid); 439 rowid);
441 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 440 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
442 GNUNET_TIME_UNIT_ZERO_ABS, 0);
443 return; 441 return;
444 } 442 }
445 443
@@ -449,14 +447,15 @@ process_result (struct Plugin *plugin,
449 (unsigned int) size, 447 (unsigned int) size,
450 (unsigned int) utype); 448 (unsigned int) utype);
451 iret = proc (proc_cls, 449 iret = proc (proc_cls,
452 &key, 450 &key,
453 size, 451 size,
454 data, 452 data,
455 (enum GNUNET_BLOCK_Type) utype, 453 (enum GNUNET_BLOCK_Type) utype,
456 priority, 454 priority,
457 anonymity, 455 anonymity,
458 expiration_time, 456 replication,
459 rowid); 457 expiration_time,
458 rowid);
460 PQclear (res); 459 PQclear (res);
461 if (iret == GNUNET_NO) 460 if (iret == GNUNET_NO)
462 { 461 {
@@ -484,12 +483,11 @@ process_result (struct Plugin *plugin,
484 483
485 484
486/** 485/**
487 * Iterate over the results for a particular key 486 * Get one of the results for a particular key in the datastore.
488 * in the datastore.
489 * 487 *
490 * @param cls closure with the 'struct Plugin' 488 * @param cls closure with the 'struct Plugin'
491 * @param offset offset of the result (modulo num-results); 489 * @param next_uid return the result with lowest uid >= next_uid
492 * specific ordering does not matter for the offset 490 * @param random if true, return a random result instead of using next_uid
493 * @param key maybe NULL (to match all entries) 491 * @param key maybe NULL (to match all entries)
494 * @param vhash hash of the value, maybe NULL (to 492 * @param vhash hash of the value, maybe NULL (to
495 * match all values that have the right key). 493 * match all values that have the right key).
@@ -499,160 +497,52 @@ process_result (struct Plugin *plugin,
499 * @param type entries of which type are relevant? 497 * @param type entries of which type are relevant?
500 * Use 0 for any type. 498 * Use 0 for any type.
501 * @param proc function to call on the matching value; 499 * @param proc function to call on the matching value;
502 * will be called once with a NULL if no value matches 500 * will be called with NULL if nothing matches
503 * @param proc_cls closure for iter 501 * @param proc_cls closure for @a proc
504 */ 502 */
505static void 503static void
506postgres_plugin_get_key (void *cls, 504postgres_plugin_get_key (void *cls,
507 uint64_t offset, 505 uint64_t next_uid,
506 bool random,
508 const struct GNUNET_HashCode *key, 507 const struct GNUNET_HashCode *key,
509 const struct GNUNET_HashCode *vhash, 508 const struct GNUNET_HashCode *vhash,
510 enum GNUNET_BLOCK_Type type, 509 enum GNUNET_BLOCK_Type type,
511 PluginDatumProcessor proc, 510 PluginDatumProcessor proc,
512 void *proc_cls) 511 void *proc_cls)
513{ 512{
514 struct Plugin *plugin = cls; 513 struct Plugin *plugin = cls;
515 uint32_t utype = type; 514 uint32_t utype = type;
515 uint16_t use_rvalue = random;
516 uint16_t use_key = NULL != key;
517 uint16_t use_vhash = NULL != vhash;
518 uint16_t use_type = GNUNET_BLOCK_TYPE_ANY != type;
519 uint64_t rvalue;
520 struct GNUNET_PQ_QueryParam params[] = {
521 GNUNET_PQ_query_param_uint64 (&next_uid),
522 GNUNET_PQ_query_param_uint64 (&rvalue),
523 GNUNET_PQ_query_param_uint16 (&use_rvalue),
524 GNUNET_PQ_query_param_auto_from_type (key),
525 GNUNET_PQ_query_param_uint16 (&use_key),
526 GNUNET_PQ_query_param_auto_from_type (vhash),
527 GNUNET_PQ_query_param_uint16 (&use_vhash),
528 GNUNET_PQ_query_param_uint32 (&utype),
529 GNUNET_PQ_query_param_uint16 (&use_type),
530 GNUNET_PQ_query_param_end
531 };
516 PGresult *ret; 532 PGresult *ret;
517 uint64_t total;
518 uint64_t limit_off;
519 533
520 if (0 != type) 534 if (random)
521 { 535 {
522 if (NULL != vhash) 536 rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
523 { 537 UINT64_MAX);
524 struct GNUNET_PQ_QueryParam params[] = { 538 next_uid = 0;
525 GNUNET_PQ_query_param_auto_from_type (key),
526 GNUNET_PQ_query_param_auto_from_type (vhash),
527 GNUNET_PQ_query_param_uint32 (&utype),
528 GNUNET_PQ_query_param_end
529 };
530 ret = GNUNET_PQ_exec_prepared (plugin->dbh,
531 "count_getvt",
532 params);
533 }
534 else
535 {
536 struct GNUNET_PQ_QueryParam params[] = {
537 GNUNET_PQ_query_param_auto_from_type (key),
538 GNUNET_PQ_query_param_uint32 (&utype),
539 GNUNET_PQ_query_param_end
540 };
541 ret = GNUNET_PQ_exec_prepared (plugin->dbh,
542 "count_gett",
543 params);
544 }
545 } 539 }
546 else 540 else
547 { 541 rvalue = 0;
548 if (NULL != vhash)
549 {
550 struct GNUNET_PQ_QueryParam params[] = {
551 GNUNET_PQ_query_param_auto_from_type (key),
552 GNUNET_PQ_query_param_auto_from_type (vhash),
553 GNUNET_PQ_query_param_end
554 };
555 ret = GNUNET_PQ_exec_prepared (plugin->dbh,
556 "count_getv",
557 params);
558 }
559 else
560 {
561 struct GNUNET_PQ_QueryParam params[] = {
562 GNUNET_PQ_query_param_auto_from_type (key),
563 GNUNET_PQ_query_param_end
564 };
565 ret = GNUNET_PQ_exec_prepared (plugin->dbh,
566 "count_get",
567 params);
568 }
569 }
570 542
571 if (GNUNET_OK != 543 ret = GNUNET_PQ_exec_prepared (plugin->dbh,
572 GNUNET_POSTGRES_check_result (plugin->dbh, 544 "get",
573 ret, 545 params);
574 PGRES_TUPLES_OK,
575 "PQexecParams",
576 "count"))
577 {
578 proc (proc_cls, NULL, 0, NULL, 0, 0, 0,
579 GNUNET_TIME_UNIT_ZERO_ABS, 0);
580 return;
581 }
582 if ( (PQntuples (ret) != 1) ||
583 (PQnfields (ret) != 1) ||
584 (PQgetlength (ret, 0, 0) != sizeof (uint64_t)))
585 {
586 GNUNET_break (0);
587 PQclear (ret);
588 proc (proc_cls, NULL, 0, NULL, 0, 0, 0,
589 GNUNET_TIME_UNIT_ZERO_ABS, 0);
590 return;
591 }
592 total = GNUNET_ntohll (*(const uint64_t *) PQgetvalue (ret, 0, 0));
593 PQclear (ret);
594 if (0 == total)
595 {
596 proc (proc_cls, NULL, 0, NULL, 0, 0, 0,
597 GNUNET_TIME_UNIT_ZERO_ABS, 0);
598 return;
599 }
600 limit_off = offset % total;
601
602 if (0 != type)
603 {
604 if (NULL != vhash)
605 {
606 struct GNUNET_PQ_QueryParam params[] = {
607 GNUNET_PQ_query_param_auto_from_type (key),
608 GNUNET_PQ_query_param_auto_from_type (vhash),
609 GNUNET_PQ_query_param_uint32 (&utype),
610 GNUNET_PQ_query_param_uint64 (&limit_off),
611 GNUNET_PQ_query_param_end
612 };
613 ret = GNUNET_PQ_exec_prepared (plugin->dbh,
614 "getvt",
615 params);
616 }
617 else
618 {
619 struct GNUNET_PQ_QueryParam params[] = {
620 GNUNET_PQ_query_param_auto_from_type (key),
621 GNUNET_PQ_query_param_uint32 (&utype),
622 GNUNET_PQ_query_param_uint64 (&limit_off),
623 GNUNET_PQ_query_param_end
624 };
625 ret = GNUNET_PQ_exec_prepared (plugin->dbh,
626 "gett",
627 params);
628 }
629 }
630 else
631 {
632 if (NULL != vhash)
633 {
634 struct GNUNET_PQ_QueryParam params[] = {
635 GNUNET_PQ_query_param_auto_from_type (key),
636 GNUNET_PQ_query_param_auto_from_type (vhash),
637 GNUNET_PQ_query_param_uint64 (&limit_off),
638 GNUNET_PQ_query_param_end
639 };
640 ret = GNUNET_PQ_exec_prepared (plugin->dbh,
641 "getv",
642 params);
643 }
644 else
645 {
646 struct GNUNET_PQ_QueryParam params[] = {
647 GNUNET_PQ_query_param_auto_from_type (key),
648 GNUNET_PQ_query_param_uint64 (&limit_off),
649 GNUNET_PQ_query_param_end
650 };
651 ret = GNUNET_PQ_exec_prepared (plugin->dbh,
652 "get",
653 params);
654 }
655 }
656 process_result (plugin, 546 process_result (plugin,
657 proc, 547 proc,
658 proc_cls, 548 proc_cls,
@@ -666,26 +556,25 @@ postgres_plugin_get_key (void *cls,
666 * the given iterator for each of them. 556 * the given iterator for each of them.
667 * 557 *
668 * @param cls our `struct Plugin *` 558 * @param cls our `struct Plugin *`
669 * @param offset offset of the result (modulo num-results); 559 * @param next_uid return the result with lowest uid >= next_uid
670 * specific ordering does not matter for the offset
671 * @param type entries of which type should be considered? 560 * @param type entries of which type should be considered?
672 * Use 0 for any type. 561 * Must not be zero (ANY).
673 * @param proc function to call on the matching value; 562 * @param proc function to call on the matching value;
674 * will be called with a NULL if no value matches 563 * will be called with NULL if no value matches
675 * @param proc_cls closure for @a proc 564 * @param proc_cls closure for @a proc
676 */ 565 */
677static void 566static void
678postgres_plugin_get_zero_anonymity (void *cls, 567postgres_plugin_get_zero_anonymity (void *cls,
679 uint64_t offset, 568 uint64_t next_uid,
680 enum GNUNET_BLOCK_Type type, 569 enum GNUNET_BLOCK_Type type,
681 PluginDatumProcessor proc, 570 PluginDatumProcessor proc,
682 void *proc_cls) 571 void *proc_cls)
683{ 572{
684 struct Plugin *plugin = cls; 573 struct Plugin *plugin = cls;
685 uint32_t utype = type; 574 uint32_t utype = type;
686 struct GNUNET_PQ_QueryParam params[] = { 575 struct GNUNET_PQ_QueryParam params[] = {
687 GNUNET_PQ_query_param_uint32 (&utype), 576 GNUNET_PQ_query_param_uint32 (&utype),
688 GNUNET_PQ_query_param_uint64 (&offset), 577 GNUNET_PQ_query_param_uint64 (&next_uid),
689 GNUNET_PQ_query_param_end 578 GNUNET_PQ_query_param_end
690 }; 579 };
691 PGresult *ret; 580 PGresult *ret;
@@ -736,6 +625,7 @@ struct ReplCtx
736 * @param type type of the content 625 * @param type type of the content
737 * @param priority priority of the content 626 * @param priority priority of the content
738 * @param anonymity anonymity-level for the content 627 * @param anonymity anonymity-level for the content
628 * @param replication replication-level for the content
739 * @param expiration expiration time for the content 629 * @param expiration expiration time for the content
740 * @param uid unique identifier for the datum; 630 * @param uid unique identifier for the datum;
741 * maybe 0 if no unique identifier is available 631 * maybe 0 if no unique identifier is available
@@ -746,13 +636,14 @@ struct ReplCtx
746 */ 636 */
747static int 637static int
748repl_proc (void *cls, 638repl_proc (void *cls,
749 const struct GNUNET_HashCode *key, 639 const struct GNUNET_HashCode *key,
750 uint32_t size, 640 uint32_t size,
751 const void *data, 641 const void *data,
752 enum GNUNET_BLOCK_Type type, 642 enum GNUNET_BLOCK_Type type,
753 uint32_t priority, 643 uint32_t priority,
754 uint32_t anonymity, 644 uint32_t anonymity,
755 struct GNUNET_TIME_Absolute expiration, 645 uint32_t replication,
646 struct GNUNET_TIME_Absolute expiration,
756 uint64_t uid) 647 uint64_t uid)
757{ 648{
758 struct ReplCtx *rc = cls; 649 struct ReplCtx *rc = cls;
@@ -766,12 +657,15 @@ repl_proc (void *cls,
766 PGresult *qret; 657 PGresult *qret;
767 658
768 ret = rc->proc (rc->proc_cls, 659 ret = rc->proc (rc->proc_cls,
769 key, 660 key,
770 size, data, 661 size,
771 type, 662 data,
772 priority, 663 type,
773 anonymity, 664 priority,
774 expiration, uid); 665 anonymity,
666 replication,
667 expiration,
668 uid);
775 if (NULL == key) 669 if (NULL == key)
776 return ret; 670 return ret;
777 qret = GNUNET_PQ_exec_prepared (plugin->dbh, 671 qret = GNUNET_PQ_exec_prepared (plugin->dbh,
@@ -856,22 +750,18 @@ postgres_plugin_get_expiration (void *cls,
856 750
857 751
858/** 752/**
859 * Update the priority for a particular key in the datastore. If 753 * Update the priority, replication and expiration for a particular
860 * the expiration time in value is different than the time found in 754 * unique ID in the datastore. If the expiration time in value is
861 * the datastore, the higher value should be kept. For the 755 * different than the time found in the datastore, the higher value
862 * anonymity level, the lower value is to be used. The specified 756 * should be kept. The specified priority and replication is added
863 * priority should be added to the existing priority, ignoring the 757 * to the existing value.
864 * priority in value.
865 *
866 * Note that it is possible for multiple values to match this put.
867 * In that case, all of the respective values are updated.
868 * 758 *
869 * @param cls our `struct Plugin *` 759 * @param cls our `struct Plugin *`
870 * @param uid unique identifier of the datum 760 * @param uid unique identifier of the datum
871 * @param delta by how much should the priority 761 * @param priority by how much should the priority
872 * change? If priority + delta < 0 the 762 * change?
873 * priority should be set to 0 (never go 763 * @param replication by how much should the replication
874 * negative). 764 * change?
875 * @param expire new expiration time should be the 765 * @param expire new expiration time should be the
876 * MAX of any existing expiration time and 766 * MAX of any existing expiration time and
877 * this value 767 * this value
@@ -880,17 +770,18 @@ postgres_plugin_get_expiration (void *cls,
880 */ 770 */
881static void 771static void
882postgres_plugin_update (void *cls, 772postgres_plugin_update (void *cls,
883 uint64_t uid, 773 uint64_t uid,
884 int delta, 774 uint32_t priority,
775 uint32_t replication,
885 struct GNUNET_TIME_Absolute expire, 776 struct GNUNET_TIME_Absolute expire,
886 PluginUpdateCont cont, 777 PluginUpdateCont cont,
887 void *cont_cls) 778 void *cont_cls)
888{ 779{
889 struct Plugin *plugin = cls; 780 struct Plugin *plugin = cls;
890 uint32_t idelta = delta;
891 uint32_t oid = (uint32_t) uid; 781 uint32_t oid = (uint32_t) uid;
892 struct GNUNET_PQ_QueryParam params[] = { 782 struct GNUNET_PQ_QueryParam params[] = {
893 GNUNET_PQ_query_param_uint32 (&idelta), 783 GNUNET_PQ_query_param_uint32 (&priority),
784 GNUNET_PQ_query_param_uint32 (&replication),
894 GNUNET_PQ_query_param_absolute_time (&expire), 785 GNUNET_PQ_query_param_absolute_time (&expire),
895 GNUNET_PQ_query_param_uint32 (&oid), 786 GNUNET_PQ_query_param_uint32 (&oid),
896 GNUNET_PQ_query_param_end 787 GNUNET_PQ_query_param_end
diff --git a/src/datastore/plugin_datastore_sqlite.c b/src/datastore/plugin_datastore_sqlite.c
index 18a3aa4ac..1f874e190 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
@@ -229,35 +241,41 @@ database_setup (const struct GNUNET_CONFIGURATION_Handle *cfg,
229{ 241{
230 sqlite3_stmt *stmt; 242 sqlite3_stmt *stmt;
231 char *afsdir; 243 char *afsdir;
232
233#if ENULL_DEFINED 244#if ENULL_DEFINED
234 char *e; 245 char *e;
235#endif 246#endif
236 247
237 if (GNUNET_OK != 248 if (GNUNET_OK !=
238 GNUNET_CONFIGURATION_get_value_filename (cfg, "datastore-sqlite", 249 GNUNET_CONFIGURATION_get_value_filename (cfg,
239 "FILENAME", &afsdir)) 250 "datastore-sqlite",
251 "FILENAME",
252 &afsdir))
240 { 253 {
241 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 254 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
242 "datastore-sqlite", "FILENAME"); 255 "datastore-sqlite",
256 "FILENAME");
243 return GNUNET_SYSERR; 257 return GNUNET_SYSERR;
244 } 258 }
245 if (GNUNET_OK != GNUNET_DISK_file_test (afsdir)) 259 if (GNUNET_OK != GNUNET_DISK_file_test (afsdir))
246 { 260 {
247 if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (afsdir)) 261 if (GNUNET_OK !=
262 GNUNET_DISK_directory_create_for_file (afsdir))
248 { 263 {
249 GNUNET_break (0); 264 GNUNET_break (0);
250 GNUNET_free (afsdir); 265 GNUNET_free (afsdir);
251 return GNUNET_SYSERR; 266 return GNUNET_SYSERR;
252 } 267 }
253 /* database is new or got deleted, reset payload to zero! */ 268 /* database is new or got deleted, reset payload to zero! */
254 plugin->env->duc (plugin->env->cls, 0); 269 if (NULL != plugin->env->duc)
270 plugin->env->duc (plugin->env->cls,
271 0);
255 } 272 }
256 /* afsdir should be UTF-8-encoded. If it isn't, it's a bug */ 273 /* afsdir should be UTF-8-encoded. If it isn't, it's a bug */
257 plugin->fn = afsdir; 274 plugin->fn = afsdir;
258 275
259 /* Open database and precompile statements */ 276 /* Open database and precompile statements */
260 if (sqlite3_open (plugin->fn, &plugin->dbh) != SQLITE_OK) 277 if (SQLITE_OK !=
278 sqlite3_open (plugin->fn, &plugin->dbh))
261 { 279 {
262 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "sqlite", 280 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "sqlite",
263 _("Unable to initialize SQLite: %s.\n"), 281 _("Unable to initialize SQLite: %s.\n"),
@@ -265,25 +283,32 @@ database_setup (const struct GNUNET_CONFIGURATION_Handle *cfg,
265 return GNUNET_SYSERR; 283 return GNUNET_SYSERR;
266 } 284 }
267 CHECK (SQLITE_OK == 285 CHECK (SQLITE_OK ==
268 sqlite3_exec (plugin->dbh, "PRAGMA temp_store=MEMORY", NULL, NULL, 286 sqlite3_exec (plugin->dbh,
287 "PRAGMA temp_store=MEMORY", NULL, NULL,
269 ENULL)); 288 ENULL));
270 CHECK (SQLITE_OK == 289 CHECK (SQLITE_OK ==
271 sqlite3_exec (plugin->dbh, "PRAGMA synchronous=OFF", NULL, NULL, 290 sqlite3_exec (plugin->dbh,
291 "PRAGMA synchronous=OFF", NULL, NULL,
272 ENULL)); 292 ENULL));
273 CHECK (SQLITE_OK == 293 CHECK (SQLITE_OK ==
274 sqlite3_exec (plugin->dbh, "PRAGMA legacy_file_format=OFF", NULL, NULL, 294 sqlite3_exec (plugin->dbh,
295 "PRAGMA legacy_file_format=OFF", NULL, NULL,
275 ENULL)); 296 ENULL));
276 CHECK (SQLITE_OK == 297 CHECK (SQLITE_OK ==
277 sqlite3_exec (plugin->dbh, "PRAGMA auto_vacuum=INCREMENTAL", NULL, 298 sqlite3_exec (plugin->dbh,
299 "PRAGMA auto_vacuum=INCREMENTAL", NULL,
278 NULL, ENULL)); 300 NULL, ENULL));
279 CHECK (SQLITE_OK == 301 CHECK (SQLITE_OK ==
280 sqlite3_exec (plugin->dbh, "PRAGMA locking_mode=EXCLUSIVE", NULL, NULL, 302 sqlite3_exec (plugin->dbh,
303 "PRAGMA locking_mode=EXCLUSIVE", NULL, NULL,
281 ENULL)); 304 ENULL));
282 CHECK (SQLITE_OK == 305 CHECK (SQLITE_OK ==
283 sqlite3_exec (plugin->dbh, "PRAGMA page_size=4092", NULL, NULL, 306 sqlite3_exec (plugin->dbh,
307 "PRAGMA page_size=4092", NULL, NULL,
284 ENULL)); 308 ENULL));
285 309
286 CHECK (SQLITE_OK == sqlite3_busy_timeout (plugin->dbh, BUSY_TIMEOUT_MS)); 310 CHECK (SQLITE_OK ==
311 sqlite3_busy_timeout (plugin->dbh, BUSY_TIMEOUT_MS));
287 312
288 313
289 /* We have to do it here, because otherwise precompiling SQL might fail */ 314 /* We have to do it here, because otherwise precompiling SQL might fail */
@@ -291,80 +316,120 @@ database_setup (const struct GNUNET_CONFIGURATION_Handle *cfg,
291 sq_prepare (plugin->dbh, 316 sq_prepare (plugin->dbh,
292 "SELECT 1 FROM sqlite_master WHERE tbl_name = 'gn090'", 317 "SELECT 1 FROM sqlite_master WHERE tbl_name = 'gn090'",
293 &stmt)); 318 &stmt));
294 if ((sqlite3_step (stmt) == SQLITE_DONE) && 319
295 (sqlite3_exec 320 /* FIXME: SQLite does not have unsigned integers! This is ok for the type column because
296 (plugin->dbh, 321 * we only test equality on it and can cast it to/from uint32_t. For repl, prio, and anonLevel
297 "CREATE TABLE gn090 (" " repl INT4 NOT NULL DEFAULT 0," 322 * we do math or inequality tests, so we can't handle the entire range of uint32_t.
298 " type INT4 NOT NULL DEFAULT 0," " prio INT4 NOT NULL DEFAULT 0," 323 * This will also cause problems for expiration times after 294247-01-10-04:00:54 UTC.
299 " anonLevel INT4 NOT NULL DEFAULT 0," 324 */
300 " expire INT8 NOT NULL DEFAULT 0," " rvalue INT8 NOT NULL," 325 if ( (SQLITE_DONE ==
301 " hash TEXT NOT NULL DEFAULT ''," " vhash TEXT NOT NULL DEFAULT ''," 326 sqlite3_step (stmt)) &&
302 " value BLOB NOT NULL DEFAULT '')", NULL, NULL, NULL) != SQLITE_OK)) 327 (SQLITE_OK !=
328 sqlite3_exec (plugin->dbh,
329 "CREATE TABLE gn090 ("
330 " repl INT4 NOT NULL DEFAULT 0,"
331 " type INT4 NOT NULL DEFAULT 0,"
332 " prio INT4 NOT NULL DEFAULT 0,"
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)) )
303 { 342 {
304 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite3_exec"); 343 LOG_SQLITE (plugin,
344 GNUNET_ERROR_TYPE_ERROR,
345 "sqlite3_exec");
305 sqlite3_finalize (stmt); 346 sqlite3_finalize (stmt);
306 return GNUNET_SYSERR; 347 return GNUNET_SYSERR;
307 } 348 }
308 sqlite3_finalize (stmt); 349 sqlite3_finalize (stmt);
309 create_indices (plugin->dbh); 350 create_indices (plugin->dbh);
310 351
311 if ((sq_prepare 352#define RESULT_COLUMNS "repl, type, prio, anonLevel, expire, hash, value, _ROWID_"
312 (plugin->dbh, 353 if ( (SQLITE_OK !=
313 "UPDATE gn090 " 354 sq_prepare (plugin->dbh,
314 "SET prio = prio + ?, expire = MAX(expire,?) WHERE _ROWID_ = ?", 355 "UPDATE gn090 "
315 &plugin->updPrio) != SQLITE_OK) || 356 "SET prio = prio + ?, "
316 (sq_prepare 357 "repl = repl + ?, "
317 (plugin->dbh, 358 "expire = MAX(expire, ?) "
318 "UPDATE gn090 " "SET repl = MAX (0, repl - 1) WHERE _ROWID_ = ?", 359 "WHERE _ROWID_ = ?",
319 &plugin->updRepl) != SQLITE_OK) || 360 &plugin->updPrio)) ||
320 (sq_prepare 361 (SQLITE_OK !=
321 (plugin->dbh, 362 sq_prepare (plugin->dbh,
322 "SELECT type,prio,anonLevel,expire,hash,value,_ROWID_ " "FROM gn090 " 363 "UPDATE gn090 " "SET repl = MAX (0, repl - 1) WHERE _ROWID_ = ?",
364 &plugin->updRepl)) ||
365 (SQLITE_OK !=
366 sq_prepare (plugin->dbh,
367 "SELECT " RESULT_COLUMNS " FROM gn090 "
323#if SQLITE_VERSION_NUMBER >= 3007000 368#if SQLITE_VERSION_NUMBER >= 3007000
324 "INDEXED BY idx_repl_rvalue " 369 "INDEXED BY idx_repl_rvalue "
325#endif 370#endif
326 "WHERE repl=?2 AND " " (rvalue>=?1 OR " 371 "WHERE repl=?2 AND " " (rvalue>=?1 OR "
327 " NOT EXISTS (SELECT 1 FROM gn090 " 372 " NOT EXISTS (SELECT 1 FROM gn090 "
328#if SQLITE_VERSION_NUMBER >= 3007000 373#if SQLITE_VERSION_NUMBER >= 3007000
329 "INDEXED BY idx_repl_rvalue " 374 "INDEXED BY idx_repl_rvalue "
330#endif 375#endif
331 "WHERE repl=?2 AND rvalue>=?1 LIMIT 1) ) " 376 "WHERE repl=?2 AND rvalue>=?1 LIMIT 1) ) "
332 "ORDER BY rvalue ASC LIMIT 1", &plugin->selRepl) != SQLITE_OK) || 377 "ORDER BY rvalue ASC LIMIT 1",
333 (sq_prepare (plugin->dbh, "SELECT MAX(repl) FROM gn090" 378 &plugin->selRepl)) ||
379 (SQLITE_OK !=
380 sq_prepare (plugin->dbh,
381 "SELECT MAX(repl) FROM gn090"
334#if SQLITE_VERSION_NUMBER >= 3007000 382#if SQLITE_VERSION_NUMBER >= 3007000
335 " INDEXED BY idx_repl_rvalue" 383 " INDEXED BY idx_repl_rvalue"
336#endif 384#endif
337 "", &plugin->maxRepl) != SQLITE_OK) || 385 "",
338 (sq_prepare 386 &plugin->maxRepl)) ||
339 (plugin->dbh, 387 (SQLITE_OK !=
340 "SELECT type,prio,anonLevel,expire,hash,value,_ROWID_ " "FROM gn090 " 388 sq_prepare (plugin->dbh,
389 "SELECT " RESULT_COLUMNS " FROM gn090 "
341#if SQLITE_VERSION_NUMBER >= 3007000 390#if SQLITE_VERSION_NUMBER >= 3007000
342 "INDEXED BY idx_expire " 391 "INDEXED BY idx_expire "
343#endif 392#endif
344 "WHERE NOT EXISTS (SELECT 1 FROM gn090 WHERE expire < ?1 LIMIT 1) OR (expire < ?1) " 393 "WHERE NOT EXISTS (SELECT 1 FROM gn090 WHERE expire < ?1 LIMIT 1) OR (expire < ?1) "
345 "ORDER BY expire ASC LIMIT 1", &plugin->selExpi) != SQLITE_OK) || 394 "ORDER BY expire ASC LIMIT 1",
346 (sq_prepare 395 &plugin->selExpi)) ||
347 (plugin->dbh, 396 (SQLITE_OK !=
348 "SELECT type,prio,anonLevel,expire,hash,value,_ROWID_ " "FROM gn090 " 397 sq_prepare (plugin->dbh,
398 "SELECT " RESULT_COLUMNS " FROM gn090 "
349#if SQLITE_VERSION_NUMBER >= 3007000 399#if SQLITE_VERSION_NUMBER >= 3007000
350 "INDEXED BY idx_anon_type_hash " 400 "INDEXED BY idx_anon_type_hash "
351#endif 401#endif
352 "WHERE (anonLevel = 0 AND type=?1) " 402 "WHERE _ROWID_ >= ? AND "
353 "ORDER BY hash DESC LIMIT 1 OFFSET ?2", 403 "anonLevel = 0 AND "
354 &plugin->selZeroAnon) != SQLITE_OK) || 404 "type = ? "
355 (sq_prepare 405 "ORDER BY _ROWID_ ASC LIMIT 1",
356 (plugin->dbh, 406 &plugin->selZeroAnon)) ||
357 "INSERT INTO gn090 (repl, type, prio, anonLevel, expire, rvalue, hash, vhash, value) " 407 (SQLITE_OK !=
358 "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", 408 sq_prepare (plugin->dbh,
359 &plugin->insertContent) != SQLITE_OK) || 409 "INSERT INTO gn090 (repl, type, prio, anonLevel, expire, rvalue, hash, vhash, value) "
360 (sq_prepare 410 "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
361 (plugin->dbh, "DELETE FROM gn090 WHERE _ROWID_ = ?", 411 &plugin->insertContent)) ||
362 &plugin->delRow) != SQLITE_OK)) 412 (SQLITE_OK !=
413 sq_prepare (plugin->dbh,
414 "SELECT " RESULT_COLUMNS " FROM gn090 "
415 "WHERE _ROWID_ >= ? AND "
416 "(rvalue >= ? OR 0 = ?) AND "
417 "(hash = ? OR 0 = ?) AND "
418 "(vhash = ? OR 0 = ?) AND "
419 "(type = ? OR 0 = ?) "
420 "ORDER BY _ROWID_ ASC LIMIT 1",
421 &plugin->get)) ||
422 (SQLITE_OK !=
423 sq_prepare (plugin->dbh,
424 "DELETE FROM gn090 WHERE _ROWID_ = ?",
425 &plugin->delRow))
426 )
363 { 427 {
364 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "precompiling"); 428 LOG_SQLITE (plugin,
429 GNUNET_ERROR_TYPE_ERROR,
430 "precompiling");
365 return GNUNET_SYSERR; 431 return GNUNET_SYSERR;
366 } 432 }
367
368 return GNUNET_OK; 433 return GNUNET_OK;
369} 434}
370 435
@@ -379,51 +444,60 @@ static void
379database_shutdown (struct Plugin *plugin) 444database_shutdown (struct Plugin *plugin)
380{ 445{
381 int result; 446 int result;
382
383#if SQLITE_VERSION_NUMBER >= 3007000 447#if SQLITE_VERSION_NUMBER >= 3007000
384 sqlite3_stmt *stmt; 448 sqlite3_stmt *stmt;
385#endif 449#endif
386 450
387 if (plugin->delRow != NULL) 451 if (NULL != plugin->delRow)
388 sqlite3_finalize (plugin->delRow); 452 sqlite3_finalize (plugin->delRow);
389 if (plugin->updPrio != NULL) 453 if (NULL != plugin->updPrio)
390 sqlite3_finalize (plugin->updPrio); 454 sqlite3_finalize (plugin->updPrio);
391 if (plugin->updRepl != NULL) 455 if (NULL != plugin->updRepl)
392 sqlite3_finalize (plugin->updRepl); 456 sqlite3_finalize (plugin->updRepl);
393 if (plugin->selRepl != NULL) 457 if (NULL != plugin->selRepl)
394 sqlite3_finalize (plugin->selRepl); 458 sqlite3_finalize (plugin->selRepl);
395 if (plugin->maxRepl != NULL) 459 if (NULL != plugin->maxRepl)
396 sqlite3_finalize (plugin->maxRepl); 460 sqlite3_finalize (plugin->maxRepl);
397 if (plugin->selExpi != NULL) 461 if (NULL != plugin->selExpi)
398 sqlite3_finalize (plugin->selExpi); 462 sqlite3_finalize (plugin->selExpi);
399 if (plugin->selZeroAnon != NULL) 463 if (NULL != plugin->selZeroAnon)
400 sqlite3_finalize (plugin->selZeroAnon); 464 sqlite3_finalize (plugin->selZeroAnon);
401 if (plugin->insertContent != NULL) 465 if (NULL != plugin->insertContent)
402 sqlite3_finalize (plugin->insertContent); 466 sqlite3_finalize (plugin->insertContent);
467 if (NULL != plugin->get)
468 sqlite3_finalize (plugin->get);
403 result = sqlite3_close (plugin->dbh); 469 result = sqlite3_close (plugin->dbh);
404#if SQLITE_VERSION_NUMBER >= 3007000 470#if SQLITE_VERSION_NUMBER >= 3007000
405 if (result == SQLITE_BUSY) 471 if (result == SQLITE_BUSY)
406 { 472 {
407 GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "sqlite", 473 GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
408 _ 474 "sqlite",
409 ("Tried to close sqlite without finalizing all prepared statements.\n")); 475 _("Tried to close sqlite without finalizing all prepared statements.\n"));
410 stmt = sqlite3_next_stmt (plugin->dbh, NULL); 476 stmt = sqlite3_next_stmt (plugin->dbh,
411 while (stmt != NULL) 477 NULL);
478 while (NULL != stmt)
412 { 479 {
413 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", 480 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
414 "Closing statement %p\n", stmt); 481 "sqlite",
482 "Closing statement %p\n",
483 stmt);
415 result = sqlite3_finalize (stmt); 484 result = sqlite3_finalize (stmt);
416 if (result != SQLITE_OK) 485 if (result != SQLITE_OK)
417 GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "sqlite", 486 GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
418 "Failed to close statement %p: %d\n", stmt, result); 487 "sqlite",
419 stmt = sqlite3_next_stmt (plugin->dbh, NULL); 488 "Failed to close statement %p: %d\n",
489 stmt,
490 result);
491 stmt = sqlite3_next_stmt (plugin->dbh,
492 NULL);
420 } 493 }
421 result = sqlite3_close (plugin->dbh); 494 result = sqlite3_close (plugin->dbh);
422 } 495 }
423#endif 496#endif
424 if (SQLITE_OK != result) 497 if (SQLITE_OK != result)
425 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite3_close"); 498 LOG_SQLITE (plugin,
426 499 GNUNET_ERROR_TYPE_ERROR,
500 "sqlite3_close");
427 GNUNET_free_non_null (plugin->fn); 501 GNUNET_free_non_null (plugin->fn);
428} 502}
429 503
@@ -437,31 +511,27 @@ database_shutdown (struct Plugin *plugin)
437 */ 511 */
438static int 512static int
439delete_by_rowid (struct Plugin *plugin, 513delete_by_rowid (struct Plugin *plugin,
440 unsigned long long rid) 514 uint64_t rid)
441{ 515{
442 if (SQLITE_OK != sqlite3_bind_int64 (plugin->delRow, 1, rid)) 516 struct GNUNET_SQ_QueryParam params[] = {
443 { 517 GNUNET_SQ_query_param_uint64 (&rid),
444 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 518 GNUNET_SQ_query_param_end
445 "sqlite3_bind_XXXX"); 519 };
446 if (SQLITE_OK != sqlite3_reset (plugin->delRow)) 520
447 LOG_SQLITE (plugin, 521 if (GNUNET_OK !=
448 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 522 GNUNET_SQ_bind (plugin->delRow,
449 "sqlite3_reset"); 523 params))
450 return GNUNET_SYSERR; 524 return GNUNET_SYSERR;
451 }
452 if (SQLITE_DONE != sqlite3_step (plugin->delRow)) 525 if (SQLITE_DONE != sqlite3_step (plugin->delRow))
453 { 526 {
454 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 527 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
455 "sqlite3_step"); 528 "sqlite3_step");
456 if (SQLITE_OK != sqlite3_reset (plugin->delRow)) 529 GNUNET_SQ_reset (plugin->dbh,
457 LOG_SQLITE (plugin, 530 plugin->delRow);
458 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
459 "sqlite3_reset");
460 return GNUNET_SYSERR; 531 return GNUNET_SYSERR;
461 } 532 }
462 if (SQLITE_OK != sqlite3_reset (plugin->delRow)) 533 GNUNET_SQ_reset (plugin->dbh,
463 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 534 plugin->delRow);
464 "sqlite3_reset");
465 return GNUNET_OK; 535 return GNUNET_OK;
466} 536}
467 537
@@ -494,12 +564,25 @@ sqlite_plugin_put (void *cls,
494 PluginPutCont cont, 564 PluginPutCont cont,
495 void *cont_cls) 565 void *cont_cls)
496{ 566{
567 uint64_t rvalue;
568 struct GNUNET_HashCode vhash;
569 uint32_t type32 = (uint32_t) type;
570 struct GNUNET_SQ_QueryParam params[] = {
571 GNUNET_SQ_query_param_uint32 (&replication),
572 GNUNET_SQ_query_param_uint32 (&type32),
573 GNUNET_SQ_query_param_uint32 (&priority),
574 GNUNET_SQ_query_param_uint32 (&anonymity),
575 GNUNET_SQ_query_param_absolute_time (&expiration),
576 GNUNET_SQ_query_param_uint64 (&rvalue),
577 GNUNET_SQ_query_param_auto_from_type (key),
578 GNUNET_SQ_query_param_auto_from_type (&vhash),
579 GNUNET_SQ_query_param_fixed_size (data, size),
580 GNUNET_SQ_query_param_end
581 };
497 struct Plugin *plugin = cls; 582 struct Plugin *plugin = cls;
498 int n; 583 int n;
499 int ret; 584 int ret;
500 sqlite3_stmt *stmt; 585 sqlite3_stmt *stmt;
501 struct GNUNET_HashCode vhash;
502 uint64_t rvalue;
503 char *msg = NULL; 586 char *msg = NULL;
504 587
505 if (size > MAX_ITEM_SIZE) 588 if (size > MAX_ITEM_SIZE)
@@ -518,26 +601,10 @@ sqlite_plugin_put (void *cls,
518 GNUNET_CRYPTO_hash (data, size, &vhash); 601 GNUNET_CRYPTO_hash (data, size, &vhash);
519 stmt = plugin->insertContent; 602 stmt = plugin->insertContent;
520 rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX); 603 rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
521 if ((SQLITE_OK != sqlite3_bind_int (stmt, 1, replication)) || 604 if (GNUNET_OK !=
522 (SQLITE_OK != sqlite3_bind_int (stmt, 2, type)) || 605 GNUNET_SQ_bind (stmt,
523 (SQLITE_OK != sqlite3_bind_int (stmt, 3, priority)) || 606 params))
524 (SQLITE_OK != sqlite3_bind_int (stmt, 4, anonymity)) ||
525 (SQLITE_OK != sqlite3_bind_int64 (stmt, 5, expiration.abs_value_us)) ||
526 (SQLITE_OK != sqlite3_bind_int64 (stmt, 6, rvalue)) ||
527 (SQLITE_OK !=
528 sqlite3_bind_blob (stmt, 7, key, sizeof (struct GNUNET_HashCode),
529 SQLITE_TRANSIENT)) ||
530 (SQLITE_OK !=
531 sqlite3_bind_blob (stmt, 8, &vhash, sizeof (struct GNUNET_HashCode),
532 SQLITE_TRANSIENT)) ||
533 (SQLITE_OK != sqlite3_bind_blob (stmt, 9, data, size, SQLITE_TRANSIENT)))
534 { 607 {
535 LOG_SQLITE_MSG (plugin, &msg, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
536 "sqlite3_bind_XXXX");
537 if (SQLITE_OK != sqlite3_reset (stmt))
538 LOG_SQLITE (plugin,
539 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
540 "sqlite3_reset");
541 cont (cont_cls, key, size, GNUNET_SYSERR, msg); 608 cont (cont_cls, key, size, GNUNET_SYSERR, msg);
542 GNUNET_free_non_null(msg); 609 GNUNET_free_non_null(msg);
543 return; 610 return;
@@ -546,7 +613,9 @@ sqlite_plugin_put (void *cls,
546 switch (n) 613 switch (n)
547 { 614 {
548 case SQLITE_DONE: 615 case SQLITE_DONE:
549 plugin->env->duc (plugin->env->cls, size + GNUNET_DATASTORE_ENTRY_OVERHEAD); 616 if (NULL != plugin->env->duc)
617 plugin->env->duc (plugin->env->cls,
618 size + GNUNET_DATASTORE_ENTRY_OVERHEAD);
550 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", 619 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite",
551 "Stored new entry (%u bytes)\n", 620 "Stored new entry (%u bytes)\n",
552 size + GNUNET_DATASTORE_ENTRY_OVERHEAD); 621 size + GNUNET_DATASTORE_ENTRY_OVERHEAD);
@@ -561,77 +630,71 @@ sqlite_plugin_put (void *cls,
561 default: 630 default:
562 LOG_SQLITE_MSG (plugin, &msg, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 631 LOG_SQLITE_MSG (plugin, &msg, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
563 "sqlite3_step"); 632 "sqlite3_step");
564 if (SQLITE_OK != sqlite3_reset (stmt)) 633 GNUNET_SQ_reset (plugin->dbh,
565 LOG_SQLITE (plugin, 634 stmt);
566 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
567 "sqlite3_reset");
568 database_shutdown (plugin); 635 database_shutdown (plugin);
569 database_setup (plugin->env->cfg, plugin); 636 database_setup (plugin->env->cfg, plugin);
570 cont (cont_cls, key, size, GNUNET_SYSERR, msg); 637 cont (cont_cls, key, size, GNUNET_SYSERR, msg);
571 GNUNET_free_non_null(msg); 638 GNUNET_free_non_null(msg);
572 return; 639 return;
573 } 640 }
574 if (SQLITE_OK != sqlite3_reset (stmt)) 641 GNUNET_SQ_reset (plugin->dbh,
575 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 642 stmt);
576 "sqlite3_reset");
577 cont (cont_cls, key, size, ret, msg); 643 cont (cont_cls, key, size, ret, msg);
578 GNUNET_free_non_null(msg); 644 GNUNET_free_non_null(msg);
579} 645}
580 646
581 647
582/** 648/**
583 * Update the priority for a particular key in the datastore. If 649 * Update the priority, replication and expiration for a particular
584 * the expiration time in value is different than the time found in 650 * unique ID in the datastore. If the expiration time in value is
585 * the datastore, the higher value should be kept. For the 651 * different than the time found in the datastore, the higher value
586 * anonymity level, the lower value is to be used. The specified 652 * should be kept. The specified priority and replication is added
587 * priority should be added to the existing priority, ignoring the 653 * to the existing value.
588 * priority in value.
589 *
590 * Note that it is possible for multiple values to match this put.
591 * In that case, all of the respective values are updated.
592 * 654 *
593 * @param cls the plugin context (state for this module) 655 * @param cls the plugin context (state for this module)
594 * @param uid unique identifier of the datum 656 * @param uid unique identifier of the datum
595 * @param delta by how much should the priority 657 * @param priority by how much should the priority
596 * change? If priority + delta < 0 the 658 * change?
597 * priority should be set to 0 (never go 659 * @param replication by how much should the replication
598 * negative). 660 * change?
599 * @param expire new expiration time should be the 661 * @param expire new expiration time should be the
600 * MAX of any existing expiration time and 662 * MAX of any existing expiration time and
601 * this value 663 * this value
602 * @param cont continuation called with success or failure status 664 * @param cont continuation called with success or failure status
603 * @param cons_cls continuation closure 665 * @param cons_cls closure for @a cont
604 */ 666 */
605static void 667static void
606sqlite_plugin_update (void *cls, 668sqlite_plugin_update (void *cls,
607 uint64_t uid, 669 uint64_t uid,
608 int delta, 670 uint32_t priority,
671 uint32_t replication,
609 struct GNUNET_TIME_Absolute expire, 672 struct GNUNET_TIME_Absolute expire,
610 PluginUpdateCont cont, 673 PluginUpdateCont cont,
611 void *cont_cls) 674 void *cont_cls)
612{ 675{
613 struct Plugin *plugin = cls; 676 struct Plugin *plugin = cls;
677 struct GNUNET_SQ_QueryParam params[] = {
678 GNUNET_SQ_query_param_uint32 (&priority),
679 GNUNET_SQ_query_param_uint32 (&replication),
680 GNUNET_SQ_query_param_absolute_time (&expire),
681 GNUNET_SQ_query_param_uint64 (&uid),
682 GNUNET_SQ_query_param_end
683 };
614 int n; 684 int n;
615 char *msg = NULL; 685 char *msg = NULL;
616 686
617 if ((SQLITE_OK != sqlite3_bind_int (plugin->updPrio, 1, delta)) || 687 if (GNUNET_OK !=
618 (SQLITE_OK != sqlite3_bind_int64 (plugin->updPrio, 2, expire.abs_value_us)) 688 GNUNET_SQ_bind (plugin->updPrio,
619 || (SQLITE_OK != sqlite3_bind_int64 (plugin->updPrio, 3, uid))) 689 params))
620 { 690 {
621 LOG_SQLITE_MSG (plugin, &msg, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
622 "sqlite3_bind_XXXX");
623 if (SQLITE_OK != sqlite3_reset (plugin->updPrio))
624 LOG_SQLITE (plugin,
625 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
626 "sqlite3_reset");
627 cont (cont_cls, GNUNET_SYSERR, msg); 691 cont (cont_cls, GNUNET_SYSERR, msg);
628 GNUNET_free_non_null(msg); 692 GNUNET_free_non_null(msg);
629 return; 693 return;
630 } 694 }
631 n = sqlite3_step (plugin->updPrio); 695 n = sqlite3_step (plugin->updPrio);
632 if (SQLITE_OK != sqlite3_reset (plugin->updPrio)) 696 GNUNET_SQ_reset (plugin->dbh,
633 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 697 plugin->updPrio);
634 "sqlite3_reset");
635 switch (n) 698 switch (n)
636 { 699 {
637 case SQLITE_DONE: 700 case SQLITE_DONE:
@@ -672,73 +735,88 @@ execute_get (struct Plugin *plugin,
672{ 735{
673 int n; 736 int n;
674 struct GNUNET_TIME_Absolute expiration; 737 struct GNUNET_TIME_Absolute expiration;
675 unsigned long long rowid; 738 uint32_t replication;
676 unsigned int size; 739 uint32_t type;
740 uint32_t priority;
741 uint32_t anonymity;
742 uint64_t rowid;
743 void *value;
744 size_t value_size;
745 struct GNUNET_HashCode key;
677 int ret; 746 int ret;
747 struct GNUNET_SQ_ResultSpec rs[] = {
748 GNUNET_SQ_result_spec_uint32 (&replication),
749 GNUNET_SQ_result_spec_uint32 (&type),
750 GNUNET_SQ_result_spec_uint32 (&priority),
751 GNUNET_SQ_result_spec_uint32 (&anonymity),
752 GNUNET_SQ_result_spec_absolute_time (&expiration),
753 GNUNET_SQ_result_spec_auto_from_type (&key),
754 GNUNET_SQ_result_spec_variable_size (&value,
755 &value_size),
756 GNUNET_SQ_result_spec_uint64 (&rowid),
757 GNUNET_SQ_result_spec_end
758 };
678 759
679 n = sqlite3_step (stmt); 760 n = sqlite3_step (stmt);
680 switch (n) 761 switch (n)
681 { 762 {
682 case SQLITE_ROW: 763 case SQLITE_ROW:
683 size = sqlite3_column_bytes (stmt, 5); 764 if (GNUNET_OK !=
684 rowid = sqlite3_column_int64 (stmt, 6); 765 GNUNET_SQ_extract_result (stmt,
685 if (sqlite3_column_bytes (stmt, 4) != sizeof (struct GNUNET_HashCode)) 766 rs))
686 { 767 {
687 GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "sqlite", 768 GNUNET_break (0);
688 _("Invalid data in database. Trying to fix (by deletion).\n"));
689 if (SQLITE_OK != sqlite3_reset (stmt))
690 LOG_SQLITE (plugin,
691 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
692 "sqlite3_reset");
693 if (GNUNET_OK == delete_by_rowid (plugin, rowid))
694 plugin->env->duc (plugin->env->cls,
695 -(size + GNUNET_DATASTORE_ENTRY_OVERHEAD));
696 break; 769 break;
697 } 770 }
698 expiration.abs_value_us = sqlite3_column_int64 (stmt, 3); 771 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
699 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", 772 "sqlite",
700 "Found reply in database with expiration %s\n", 773 "Found reply in database with expiration %s\n",
701 GNUNET_STRINGS_absolute_time_to_string (expiration)); 774 GNUNET_STRINGS_absolute_time_to_string (expiration));
702 ret = proc (proc_cls, sqlite3_column_blob (stmt, 4) /* key */ , 775 ret = proc (proc_cls,
703 size, sqlite3_column_blob (stmt, 5) /* data */ , 776 &key,
704 sqlite3_column_int (stmt, 0) /* type */ , 777 value_size,
705 sqlite3_column_int (stmt, 1) /* priority */ , 778 value,
706 sqlite3_column_int (stmt, 2) /* anonymity */ , 779 type,
707 expiration, rowid); 780 priority,
708 if (SQLITE_OK != sqlite3_reset (stmt)) 781 anonymity,
709 LOG_SQLITE (plugin, 782 replication,
710 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 783 expiration,
711 "sqlite3_reset"); 784 rowid);
712 if ((GNUNET_NO == ret) && (GNUNET_OK == delete_by_rowid (plugin, rowid))) 785 GNUNET_SQ_cleanup_result (rs);
786 GNUNET_SQ_reset (plugin->dbh,
787 stmt);
788 if ( (GNUNET_NO == ret) &&
789 (GNUNET_OK == delete_by_rowid (plugin,
790 rowid)) &&
791 (NULL != plugin->env->duc) )
713 plugin->env->duc (plugin->env->cls, 792 plugin->env->duc (plugin->env->cls,
714 -(size + GNUNET_DATASTORE_ENTRY_OVERHEAD)); 793 -(value_size + GNUNET_DATASTORE_ENTRY_OVERHEAD));
715 return; 794 return;
716 case SQLITE_DONE: 795 case SQLITE_DONE:
717 /* database must be empty */ 796 /* database must be empty */
718 if (SQLITE_OK != sqlite3_reset (stmt))
719 LOG_SQLITE (plugin,
720 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
721 "sqlite3_reset");
722 break; 797 break;
723 case SQLITE_BUSY: 798 case SQLITE_BUSY:
724 case SQLITE_ERROR: 799 case SQLITE_ERROR:
725 case SQLITE_MISUSE: 800 case SQLITE_MISUSE:
726 default: 801 default:
727 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 802 LOG_SQLITE (plugin,
803 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
728 "sqlite3_step"); 804 "sqlite3_step");
729 if (SQLITE_OK != sqlite3_reset (stmt)) 805 if (SQLITE_OK !=
806 sqlite3_reset (stmt))
730 LOG_SQLITE (plugin, 807 LOG_SQLITE (plugin,
731 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 808 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
732 "sqlite3_reset"); 809 "sqlite3_reset");
733 GNUNET_break (0); 810 GNUNET_break (0);
811 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
734 database_shutdown (plugin); 812 database_shutdown (plugin);
735 database_setup (plugin->env->cfg, plugin); 813 database_setup (plugin->env->cfg,
736 break; 814 plugin);
815 return;
737 } 816 }
738 if (SQLITE_OK != sqlite3_reset (stmt)) 817 GNUNET_SQ_reset (plugin->dbh,
739 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 818 stmt);
740 "sqlite3_reset"); 819 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
741 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
742} 820}
743 821
744 822
@@ -747,37 +825,36 @@ execute_get (struct Plugin *plugin,
747 * the given processor for the item. 825 * the given processor for the item.
748 * 826 *
749 * @param cls our plugin context 827 * @param cls our plugin context
750 * @param offset offset of the result (modulo num-results); 828 * @param next_uid return the result with lowest uid >= next_uid
751 * specific ordering does not matter for the offset
752 * @param type entries of which type should be considered? 829 * @param type entries of which type should be considered?
753 * Use 0 for any type. 830 * Must not be zero (ANY).
754 * @param proc function to call on each matching value; 831 * @param proc function to call on the matching value;
755 * will be called once with a NULL value at the end 832 * will be called with NULL if no value matches
756 * @param proc_cls closure for @a proc 833 * @param proc_cls closure for @a proc
757 */ 834 */
758static void 835static void
759sqlite_plugin_get_zero_anonymity (void *cls, uint64_t offset, 836sqlite_plugin_get_zero_anonymity (void *cls,
837 uint64_t next_uid,
760 enum GNUNET_BLOCK_Type type, 838 enum GNUNET_BLOCK_Type type,
761 PluginDatumProcessor proc, void *proc_cls) 839 PluginDatumProcessor proc,
840 void *proc_cls)
762{ 841{
763 struct Plugin *plugin = cls; 842 struct Plugin *plugin = cls;
764 sqlite3_stmt *stmt; 843 struct GNUNET_SQ_QueryParam params[] = {
844 GNUNET_SQ_query_param_uint64 (&next_uid),
845 GNUNET_SQ_query_param_uint32 (&type),
846 GNUNET_SQ_query_param_end
847 };
765 848
766 GNUNET_assert (type != GNUNET_BLOCK_TYPE_ANY); 849 GNUNET_assert (type != GNUNET_BLOCK_TYPE_ANY);
767 stmt = plugin->selZeroAnon; 850 if (GNUNET_OK !=
768 if ((SQLITE_OK != sqlite3_bind_int (stmt, 1, type)) || 851 GNUNET_SQ_bind (plugin->selZeroAnon,
769 (SQLITE_OK != sqlite3_bind_int64 (stmt, 2, offset))) 852 params))
770 { 853 {
771 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 854 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
772 "sqlite3_bind_XXXX");
773 if (SQLITE_OK != sqlite3_reset (stmt))
774 LOG_SQLITE (plugin,
775 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
776 "sqlite3_reset");
777 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
778 return; 855 return;
779 } 856 }
780 execute_get (plugin, stmt, proc, proc_cls); 857 execute_get (plugin, plugin->selZeroAnon, proc, proc_cls);
781} 858}
782 859
783 860
@@ -785,8 +862,9 @@ sqlite_plugin_get_zero_anonymity (void *cls, uint64_t offset,
785 * Get results for a particular key in the datastore. 862 * Get results for a particular key in the datastore.
786 * 863 *
787 * @param cls closure 864 * @param cls closure
788 * @param offset offset (mod count). 865 * @param next_uid return the result with lowest uid >= next_uid
789 * @param key key to match, never NULL 866 * @param random if true, return a random result instead of using next_uid
867 * @param key maybe NULL (to match all entries)
790 * @param vhash hash of the value, maybe NULL (to 868 * @param vhash hash of the value, maybe NULL (to
791 * match all values that have the right key). 869 * match all values that have the right key).
792 * Note that for DBlocks there is no difference 870 * Note that for DBlocks there is no difference
@@ -800,7 +878,8 @@ sqlite_plugin_get_zero_anonymity (void *cls, uint64_t offset,
800 */ 878 */
801static void 879static void
802sqlite_plugin_get_key (void *cls, 880sqlite_plugin_get_key (void *cls,
803 uint64_t offset, 881 uint64_t next_uid,
882 bool random,
804 const struct GNUNET_HashCode *key, 883 const struct GNUNET_HashCode *key,
805 const struct GNUNET_HashCode *vhash, 884 const struct GNUNET_HashCode *vhash,
806 enum GNUNET_BLOCK_Type type, 885 enum GNUNET_BLOCK_Type type,
@@ -808,97 +887,45 @@ sqlite_plugin_get_key (void *cls,
808 void *proc_cls) 887 void *proc_cls)
809{ 888{
810 struct Plugin *plugin = cls; 889 struct Plugin *plugin = cls;
811 int ret; 890 uint64_t rvalue;
812 int total; 891 uint16_t use_rvalue = random;
813 int limit_off; 892 uint32_t type32 = (uint32_t) type;
814 unsigned int sqoff; 893 uint16_t use_type = GNUNET_BLOCK_TYPE_ANY != type;
815 sqlite3_stmt *stmt; 894 uint16_t use_key = NULL != key;
816 char scratch[256]; 895 uint16_t use_vhash = NULL != vhash;
817 896 struct GNUNET_SQ_QueryParam params[] = {
818 GNUNET_assert (proc != NULL); 897 GNUNET_SQ_query_param_uint64 (&next_uid),
819 GNUNET_assert (key != NULL); 898 GNUNET_SQ_query_param_uint64 (&rvalue),
820 GNUNET_snprintf (scratch, sizeof (scratch), 899 GNUNET_SQ_query_param_uint16 (&use_rvalue),
821 "SELECT count(*) FROM gn090 WHERE hash=?%s%s", 900 GNUNET_SQ_query_param_auto_from_type (key),
822 vhash == NULL ? "" : " AND vhash=?", 901 GNUNET_SQ_query_param_uint16 (&use_key),
823 type == 0 ? "" : " AND type=?"); 902 GNUNET_SQ_query_param_auto_from_type (vhash),
824 if (sq_prepare (plugin->dbh, scratch, &stmt) != SQLITE_OK) 903 GNUNET_SQ_query_param_uint16 (&use_vhash),
825 { 904 GNUNET_SQ_query_param_uint32 (&type32),
826 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 905 GNUNET_SQ_query_param_uint16 (&use_type),
827 "sqlite_prepare"); 906 GNUNET_SQ_query_param_end
828 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); 907 };
829 return; 908
830 } 909 if (random)
831 sqoff = 1;
832 ret =
833 sqlite3_bind_blob (stmt, sqoff++, key, sizeof (struct GNUNET_HashCode),
834 SQLITE_TRANSIENT);
835 if ((vhash != NULL) && (ret == SQLITE_OK))
836 ret =
837 sqlite3_bind_blob (stmt, sqoff++, vhash, sizeof (struct GNUNET_HashCode),
838 SQLITE_TRANSIENT);
839 if ((type != 0) && (ret == SQLITE_OK))
840 ret = sqlite3_bind_int (stmt, sqoff++, type);
841 if (SQLITE_OK != ret)
842 {
843 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite_bind");
844 sqlite3_finalize (stmt);
845 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
846 return;
847 }
848 ret = sqlite3_step (stmt);
849 if (ret != SQLITE_ROW)
850 {
851 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
852 "sqlite_step");
853 sqlite3_finalize (stmt);
854 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
855 return;
856 }
857 total = sqlite3_column_int (stmt, 0);
858 sqlite3_finalize (stmt);
859 if (0 == total)
860 {
861 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
862 return;
863 }
864 limit_off = (int) (offset % total);
865 if (limit_off < 0)
866 limit_off += total;
867 GNUNET_snprintf (scratch, sizeof (scratch),
868 "SELECT type, prio, anonLevel, expire, hash, value, _ROWID_ "
869 "FROM gn090 WHERE hash=?%s%s "
870 "ORDER BY _ROWID_ ASC LIMIT 1 OFFSET ?",
871 vhash == NULL ? "" : " AND vhash=?",
872 type == 0 ? "" : " AND type=?");
873 if (sq_prepare (plugin->dbh, scratch, &stmt) != SQLITE_OK)
874 { 910 {
875 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 911 rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
876 "sqlite_prepare"); 912 UINT64_MAX);
877 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); 913 next_uid = 0;
878 return;
879 } 914 }
880 sqoff = 1; 915 else
881 ret = sqlite3_bind_blob (stmt, sqoff++, key, 916 rvalue = 0;
882 sizeof (struct GNUNET_HashCode), 917
883 SQLITE_TRANSIENT); 918 if (GNUNET_OK !=
884 if ((vhash != NULL) && (ret == SQLITE_OK)) 919 GNUNET_SQ_bind (plugin->get,
885 ret = sqlite3_bind_blob (stmt, sqoff++, vhash, 920 params))
886 sizeof (struct GNUNET_HashCode),
887 SQLITE_TRANSIENT);
888 if ((type != 0) && (ret == SQLITE_OK))
889 ret = sqlite3_bind_int (stmt, sqoff++, type);
890 if (ret == SQLITE_OK)
891 ret = sqlite3_bind_int64 (stmt, sqoff++, limit_off);
892 if (ret != SQLITE_OK)
893 { 921 {
894 LOG_SQLITE (plugin, 922 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
895 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
896 "sqlite_bind");
897 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
898 return; 923 return;
899 } 924 }
900 execute_get (plugin, stmt, proc, proc_cls); 925 execute_get (plugin,
901 sqlite3_finalize (stmt); 926 plugin->get,
927 proc,
928 proc_cls);
902} 929}
903 930
904 931
@@ -942,6 +969,7 @@ struct ReplCtx
942 * @param type type of the content 969 * @param type type of the content
943 * @param priority priority of the content 970 * @param priority priority of the content
944 * @param anonymity anonymity-level for the content 971 * @param anonymity anonymity-level for the content
972 * @param replication replication-level for the content
945 * @param expiration expiration time for the content 973 * @param expiration expiration time for the content
946 * @param uid unique identifier for the datum; 974 * @param uid unique identifier for the datum;
947 * maybe 0 if no unique identifier is available 975 * maybe 0 if no unique identifier is available
@@ -956,19 +984,25 @@ repl_proc (void *cls,
956 enum GNUNET_BLOCK_Type type, 984 enum GNUNET_BLOCK_Type type,
957 uint32_t priority, 985 uint32_t priority,
958 uint32_t anonymity, 986 uint32_t anonymity,
987 uint32_t replication,
959 struct GNUNET_TIME_Absolute expiration, 988 struct GNUNET_TIME_Absolute expiration,
960 uint64_t uid) 989 uint64_t uid)
961{ 990{
962 struct ReplCtx *rc = cls; 991 struct ReplCtx *rc = cls;
963 int ret; 992 int ret;
964 993
994 if (GNUNET_SYSERR == rc->have_uid)
995 rc->have_uid = GNUNET_NO;
965 ret = rc->proc (rc->proc_cls, 996 ret = rc->proc (rc->proc_cls,
966 key, 997 key,
967 size, data, 998 size,
999 data,
968 type, 1000 type,
969 priority, 1001 priority,
970 anonymity, 1002 anonymity,
971 expiration, uid); 1003 replication,
1004 expiration,
1005 uid);
972 if (NULL != key) 1006 if (NULL != key)
973 { 1007 {
974 rc->uid = uid; 1008 rc->uid = uid;
@@ -989,81 +1023,77 @@ repl_proc (void *cls,
989 * @param proc_cls closure for @a proc 1023 * @param proc_cls closure for @a proc
990 */ 1024 */
991static void 1025static void
992sqlite_plugin_get_replication (void *cls, PluginDatumProcessor proc, 1026sqlite_plugin_get_replication (void *cls,
1027 PluginDatumProcessor proc,
993 void *proc_cls) 1028 void *proc_cls)
994{ 1029{
995 struct Plugin *plugin = cls; 1030 struct Plugin *plugin = cls;
996 struct ReplCtx rc; 1031 struct ReplCtx rc;
997 uint64_t rvalue; 1032 uint64_t rvalue;
998 uint32_t repl; 1033 uint32_t repl;
999 sqlite3_stmt *stmt; 1034 struct GNUNET_SQ_QueryParam params_sel_repl[] = {
1000 1035 GNUNET_SQ_query_param_uint64 (&rvalue),
1001 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", 1036 GNUNET_SQ_query_param_uint32 (&repl),
1037 GNUNET_SQ_query_param_end
1038 };
1039 struct GNUNET_SQ_QueryParam params_upd_repl[] = {
1040 GNUNET_SQ_query_param_uint64 (&rc.uid),
1041 GNUNET_SQ_query_param_end
1042 };
1043
1044 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1045 "datastore-sqlite",
1002 "Getting random block based on replication order.\n"); 1046 "Getting random block based on replication order.\n");
1003 rc.have_uid = GNUNET_NO; 1047 if (SQLITE_ROW !=
1004 rc.proc = proc; 1048 sqlite3_step (plugin->maxRepl))
1005 rc.proc_cls = proc_cls;
1006 stmt = plugin->maxRepl;
1007 if (SQLITE_ROW != sqlite3_step (stmt))
1008 { 1049 {
1009 if (SQLITE_OK != sqlite3_reset (stmt)) 1050 GNUNET_SQ_reset (plugin->dbh,
1010 LOG_SQLITE (plugin, 1051 plugin->maxRepl);
1011 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1012 "sqlite3_reset");
1013 /* DB empty */ 1052 /* DB empty */
1014 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); 1053 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
1015 return; 1054 return;
1016 } 1055 }
1017 repl = sqlite3_column_int (stmt, 0); 1056 repl = sqlite3_column_int (plugin->maxRepl,
1018 if (SQLITE_OK != sqlite3_reset (stmt)) 1057 0);
1019 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 1058 GNUNET_SQ_reset (plugin->dbh,
1020 "sqlite3_reset"); 1059 plugin->maxRepl);
1021 stmt = plugin->selRepl; 1060 rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
1022 rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX); 1061 UINT64_MAX);
1023 if (SQLITE_OK != sqlite3_bind_int64 (stmt, 1, rvalue)) 1062 if (GNUNET_OK !=
1024 { 1063 GNUNET_SQ_bind (plugin->selRepl,
1025 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 1064 params_sel_repl))
1026 "sqlite3_bind_XXXX");
1027 if (SQLITE_OK != sqlite3_reset (stmt))
1028 LOG_SQLITE (plugin,
1029 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1030 "sqlite3_reset");
1031 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
1032 return;
1033 }
1034 if (SQLITE_OK != sqlite3_bind_int (stmt, 2, repl))
1035 { 1065 {
1036 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 1066 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
1037 "sqlite3_bind_XXXX");
1038 if (SQLITE_OK != sqlite3_reset (stmt))
1039 LOG_SQLITE (plugin,
1040 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1041 "sqlite3_reset");
1042 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
1043 return; 1067 return;
1044 } 1068 }
1045 execute_get (plugin, stmt, &repl_proc, &rc); 1069 rc.have_uid = GNUNET_SYSERR;
1070 rc.proc = proc;
1071 rc.proc_cls = proc_cls;
1072 execute_get (plugin,
1073 plugin->selRepl,
1074 &repl_proc,
1075 &rc);
1046 if (GNUNET_YES == rc.have_uid) 1076 if (GNUNET_YES == rc.have_uid)
1047 { 1077 {
1048 if (SQLITE_OK != sqlite3_bind_int64 (plugin->updRepl, 1, rc.uid)) 1078 if (GNUNET_OK !=
1079 GNUNET_SQ_bind (plugin->updRepl,
1080 params_upd_repl))
1049 { 1081 {
1050 LOG_SQLITE (plugin, 1082 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
1051 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1052 "sqlite3_bind_XXXX");
1053 if (SQLITE_OK != sqlite3_reset (plugin->updRepl))
1054 LOG_SQLITE (plugin,
1055 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1056 "sqlite3_reset");
1057 return; 1083 return;
1058 } 1084 }
1059 if (SQLITE_DONE != sqlite3_step (plugin->updRepl)) 1085 if (SQLITE_DONE !=
1086 sqlite3_step (plugin->updRepl))
1060 LOG_SQLITE (plugin, 1087 LOG_SQLITE (plugin,
1061 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 1088 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1062 "sqlite3_step"); 1089 "sqlite3_step");
1063 if (SQLITE_OK != sqlite3_reset (plugin->updRepl)) 1090 GNUNET_SQ_reset (plugin->dbh,
1064 LOG_SQLITE (plugin, 1091 plugin->updRepl);
1065 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 1092 }
1066 "sqlite3_reset"); 1093 if (GNUNET_SYSERR == rc.have_uid)
1094 {
1095 /* proc was not called at all so far, do it now. */
1096 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
1067 } 1097 }
1068} 1098}
1069 1099
@@ -1083,20 +1113,21 @@ sqlite_plugin_get_expiration (void *cls, PluginDatumProcessor proc,
1083 struct Plugin *plugin = cls; 1113 struct Plugin *plugin = cls;
1084 sqlite3_stmt *stmt; 1114 sqlite3_stmt *stmt;
1085 struct GNUNET_TIME_Absolute now; 1115 struct GNUNET_TIME_Absolute now;
1116 struct GNUNET_SQ_QueryParam params[] = {
1117 GNUNET_SQ_query_param_absolute_time (&now),
1118 GNUNET_SQ_query_param_end
1119 };
1086 1120
1087 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", 1121 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1122 "sqlite",
1088 "Getting random block based on expiration and priority order.\n"); 1123 "Getting random block based on expiration and priority order.\n");
1089 now = GNUNET_TIME_absolute_get (); 1124 now = GNUNET_TIME_absolute_get ();
1090 stmt = plugin->selExpi; 1125 stmt = plugin->selExpi;
1091 if (SQLITE_OK != sqlite3_bind_int64 (stmt, 1, now.abs_value_us)) 1126 if (GNUNET_OK !=
1127 GNUNET_SQ_bind (stmt,
1128 params))
1092 { 1129 {
1093 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 1130 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
1094 "sqlite3_bind_XXXX");
1095 if (SQLITE_OK != sqlite3_reset (stmt))
1096 LOG_SQLITE (plugin,
1097 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1098 "sqlite3_reset");
1099 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
1100 return; 1131 return;
1101 } 1132 }
1102 execute_get (plugin, stmt, proc, proc_cls); 1133 execute_get (plugin, stmt, proc, proc_cls);
@@ -1116,30 +1147,47 @@ sqlite_plugin_get_keys (void *cls,
1116 void *proc_cls) 1147 void *proc_cls)
1117{ 1148{
1118 struct Plugin *plugin = cls; 1149 struct Plugin *plugin = cls;
1119 const struct GNUNET_HashCode *key; 1150 struct GNUNET_HashCode key;
1151 struct GNUNET_SQ_ResultSpec results[] = {
1152 GNUNET_SQ_result_spec_auto_from_type (&key),
1153 GNUNET_SQ_result_spec_end
1154 };
1120 sqlite3_stmt *stmt; 1155 sqlite3_stmt *stmt;
1121 int ret; 1156 int ret;
1122 1157
1123 GNUNET_assert (proc != NULL); 1158 GNUNET_assert (NULL != proc);
1124 if (sq_prepare (plugin->dbh, "SELECT hash FROM gn090", &stmt) != SQLITE_OK) 1159 if (SQLITE_OK !=
1160 sq_prepare (plugin->dbh,
1161 "SELECT hash FROM gn090",
1162 &stmt))
1125 { 1163 {
1126 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 1164 LOG_SQLITE (plugin,
1165 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1127 "sqlite_prepare"); 1166 "sqlite_prepare");
1128 proc (proc_cls, NULL, 0); 1167 proc (proc_cls,
1168 NULL,
1169 0);
1129 return; 1170 return;
1130 } 1171 }
1131 while (SQLITE_ROW == (ret = sqlite3_step (stmt))) 1172 while (SQLITE_ROW == (ret = sqlite3_step (stmt)))
1132 { 1173 {
1133 key = sqlite3_column_blob (stmt, 0); 1174 if (GNUNET_OK ==
1134 if (sizeof (struct GNUNET_HashCode) == sqlite3_column_bytes (stmt, 0)) 1175 GNUNET_SQ_extract_result (stmt,
1135 proc (proc_cls, key, 1); 1176 results))
1177 proc (proc_cls,
1178 &key,
1179 1);
1136 else 1180 else
1137 GNUNET_break (0); 1181 GNUNET_break (0);
1138 } 1182 }
1139 if (SQLITE_DONE != ret) 1183 if (SQLITE_DONE != ret)
1140 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite_step"); 1184 LOG_SQLITE (plugin,
1185 GNUNET_ERROR_TYPE_ERROR,
1186 "sqlite_step");
1141 sqlite3_finalize (stmt); 1187 sqlite3_finalize (stmt);
1142 proc (proc_cls, NULL, 0); 1188 proc (proc_cls,
1189 NULL,
1190 0);
1143} 1191}
1144 1192
1145 1193
@@ -1165,7 +1213,8 @@ sqlite_plugin_drop (void *cls)
1165 * @return the size of the database on disk (estimate) 1213 * @return the size of the database on disk (estimate)
1166 */ 1214 */
1167static void 1215static void
1168sqlite_plugin_estimate_size (void *cls, unsigned long long *estimate) 1216sqlite_plugin_estimate_size (void *cls,
1217 unsigned long long *estimate)
1169{ 1218{
1170 struct Plugin *plugin = cls; 1219 struct Plugin *plugin = cls;
1171 sqlite3_stmt *stmt; 1220 sqlite3_stmt *stmt;
@@ -1180,30 +1229,45 @@ sqlite_plugin_estimate_size (void *cls, unsigned long long *estimate)
1180 return; 1229 return;
1181 if (SQLITE_VERSION_NUMBER < 3006000) 1230 if (SQLITE_VERSION_NUMBER < 3006000)
1182 { 1231 {
1183 GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "datastore-sqlite", 1232 GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
1184 _ 1233 "datastore-sqlite",
1185 ("sqlite version to old to determine size, assuming zero\n")); 1234 _("sqlite version to old to determine size, assuming zero\n"));
1186 *estimate = 0; 1235 *estimate = 0;
1187 return; 1236 return;
1188 } 1237 }
1189 CHECK (SQLITE_OK == sqlite3_exec (plugin->dbh, "VACUUM", NULL, NULL, ENULL));
1190 CHECK (SQLITE_OK == 1238 CHECK (SQLITE_OK ==
1191 sqlite3_exec (plugin->dbh, "PRAGMA auto_vacuum=INCREMENTAL", NULL, 1239 sqlite3_exec (plugin->dbh,
1240 "VACUUM",
1241 NULL,
1242 NULL,
1243 ENULL));
1244 CHECK (SQLITE_OK ==
1245 sqlite3_exec (plugin->dbh,
1246 "PRAGMA auto_vacuum=INCREMENTAL",
1247 NULL,
1192 NULL, ENULL)); 1248 NULL, ENULL));
1193 CHECK (SQLITE_OK == sq_prepare (plugin->dbh, "PRAGMA page_count", &stmt)); 1249 CHECK (SQLITE_OK ==
1250 sq_prepare (plugin->dbh,
1251 "PRAGMA page_count",
1252 &stmt));
1194 if (SQLITE_ROW == sqlite3_step (stmt)) 1253 if (SQLITE_ROW == sqlite3_step (stmt))
1195 pages = sqlite3_column_int64 (stmt, 0); 1254 pages = sqlite3_column_int64 (stmt,
1255 0);
1196 else 1256 else
1197 pages = 0; 1257 pages = 0;
1198 sqlite3_finalize (stmt); 1258 sqlite3_finalize (stmt);
1199 CHECK (SQLITE_OK == sq_prepare (plugin->dbh, "PRAGMA page_size", &stmt)); 1259 CHECK (SQLITE_OK ==
1200 CHECK (SQLITE_ROW == sqlite3_step (stmt)); 1260 sq_prepare (plugin->dbh,
1261 "PRAGMA page_size",
1262 &stmt));
1263 CHECK (SQLITE_ROW ==
1264 sqlite3_step (stmt));
1201 page_size = sqlite3_column_int64 (stmt, 0); 1265 page_size = sqlite3_column_int64 (stmt, 0);
1202 sqlite3_finalize (stmt); 1266 sqlite3_finalize (stmt);
1203 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1267 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1204 _ 1268 _("Using sqlite page utilization to estimate payload (%llu pages of size %llu bytes)\n"),
1205 ("Using sqlite page utilization to estimate payload (%llu pages of size %llu bytes)\n"), 1269 (unsigned long long) pages,
1206 (unsigned long long) pages, (unsigned long long) page_size); 1270 (unsigned long long) page_size);
1207 *estimate = pages * page_size; 1271 *estimate = pages * page_size;
1208} 1272}
1209 1273
@@ -1221,9 +1285,11 @@ libgnunet_plugin_datastore_sqlite_init (void *cls)
1221 struct GNUNET_DATASTORE_PluginEnvironment *env = cls; 1285 struct GNUNET_DATASTORE_PluginEnvironment *env = cls;
1222 struct GNUNET_DATASTORE_PluginFunctions *api; 1286 struct GNUNET_DATASTORE_PluginFunctions *api;
1223 1287
1224 if (plugin.env != NULL) 1288 if (NULL != plugin.env)
1225 return NULL; /* can only initialize once! */ 1289 return NULL; /* can only initialize once! */
1226 memset (&plugin, 0, sizeof (struct Plugin)); 1290 memset (&plugin,
1291 0,
1292 sizeof (struct Plugin));
1227 plugin.env = env; 1293 plugin.env = env;
1228 if (GNUNET_OK != database_setup (env->cfg, &plugin)) 1294 if (GNUNET_OK != database_setup (env->cfg, &plugin))
1229 { 1295 {
@@ -1241,7 +1307,8 @@ libgnunet_plugin_datastore_sqlite_init (void *cls)
1241 api->get_zero_anonymity = &sqlite_plugin_get_zero_anonymity; 1307 api->get_zero_anonymity = &sqlite_plugin_get_zero_anonymity;
1242 api->get_keys = &sqlite_plugin_get_keys; 1308 api->get_keys = &sqlite_plugin_get_keys;
1243 api->drop = &sqlite_plugin_drop; 1309 api->drop = &sqlite_plugin_drop;
1244 GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "sqlite", 1310 GNUNET_log_from (GNUNET_ERROR_TYPE_INFO,
1311 "sqlite",
1245 _("Sqlite database running\n")); 1312 _("Sqlite database running\n"));
1246 return api; 1313 return api;
1247} 1314}
@@ -1260,24 +1327,23 @@ libgnunet_plugin_datastore_sqlite_done (void *cls)
1260 struct GNUNET_DATASTORE_PluginFunctions *api = cls; 1327 struct GNUNET_DATASTORE_PluginFunctions *api = cls;
1261 struct Plugin *plugin = api->cls; 1328 struct Plugin *plugin = api->cls;
1262 1329
1263 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", 1330 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1331 "sqlite",
1264 "sqlite plugin is done\n"); 1332 "sqlite plugin is done\n");
1265 fn = NULL; 1333 fn = NULL;
1266 if (plugin->drop_on_shutdown) 1334 if (plugin->drop_on_shutdown)
1267 fn = GNUNET_strdup (plugin->fn); 1335 fn = GNUNET_strdup (plugin->fn);
1268 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite",
1269 "Shutting down database\n");
1270 database_shutdown (plugin); 1336 database_shutdown (plugin);
1271 plugin->env = NULL; 1337 plugin->env = NULL;
1272 GNUNET_free (api); 1338 GNUNET_free (api);
1273 if (fn != NULL) 1339 if (NULL != fn)
1274 { 1340 {
1275 if (0 != UNLINK (fn)) 1341 if (0 != UNLINK (fn))
1276 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", fn); 1342 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
1343 "unlink",
1344 fn);
1277 GNUNET_free (fn); 1345 GNUNET_free (fn);
1278 } 1346 }
1279 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite",
1280 "sqlite plugin is finished\n");
1281 return NULL; 1347 return NULL;
1282} 1348}
1283 1349
diff --git a/src/datastore/plugin_datastore_template.c b/src/datastore/plugin_datastore_template.c
index fdd4fb157..8e44f020d 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,
@@ -151,22 +151,18 @@ template_plugin_get_expiration (void *cls, PluginDatumProcessor proc,
151 151
152 152
153/** 153/**
154 * Update the priority for a particular key in the datastore. If 154 * Update the priority, replication and expiration for a particular
155 * the expiration time in value is different than the time found in 155 * unique ID in the datastore. If the expiration time in value is
156 * the datastore, the higher value should be kept. For the 156 * different than the time found in the datastore, the higher value
157 * anonymity level, the lower value is to be used. The specified 157 * should be kept. The specified priority and replication is added
158 * priority should be added to the existing priority, ignoring the 158 * to the existing value.
159 * priority in value.
160 *
161 * Note that it is possible for multiple values to match this put.
162 * In that case, all of the respective values are updated.
163 * 159 *
164 * @param cls our "struct Plugin*" 160 * @param cls our "struct Plugin*"
165 * @param uid unique identifier of the datum 161 * @param uid unique identifier of the datum
166 * @param delta by how much should the priority 162 * @param priority by how much should the priority
167 * change? If priority + delta < 0 the 163 * change?
168 * priority should be set to 0 (never go 164 * @param replication by how much should the replication
169 * negative). 165 * change?
170 * @param expire new expiration time should be the 166 * @param expire new expiration time should be the
171 * MAX of any existing expiration time and 167 * MAX of any existing expiration time and
172 * this value 168 * this value
@@ -174,9 +170,13 @@ template_plugin_get_expiration (void *cls, PluginDatumProcessor proc,
174 * @param cons_cls continuation closure 170 * @param cons_cls continuation closure
175 */ 171 */
176static void 172static void
177template_plugin_update (void *cls, uint64_t uid, int delta, 173template_plugin_update (void *cls,
174 uint64_t uid,
175 uint32_t priority,
176 uint32_t replication,
178 struct GNUNET_TIME_Absolute expire, 177 struct GNUNET_TIME_Absolute expire,
179 PluginUpdateCont cont, void *cont_cls) 178 PluginUpdateCont cont,
179 void *cont_cls)
180{ 180{
181 GNUNET_break (0); 181 GNUNET_break (0);
182 cont (cont_cls, GNUNET_SYSERR, "not implemented"); 182 cont (cont_cls, GNUNET_SYSERR, "not implemented");
@@ -187,16 +187,15 @@ template_plugin_update (void *cls, uint64_t uid, int delta,
187 * Call the given processor on an item with zero anonymity. 187 * Call the given processor on an item with zero anonymity.
188 * 188 *
189 * @param cls our "struct Plugin*" 189 * @param cls our "struct Plugin*"
190 * @param offset offset of the result (modulo num-results); 190 * @param next_uid return the result with lowest uid >= next_uid
191 * specific ordering does not matter for the offset
192 * @param type entries of which type should be considered? 191 * @param type entries of which type should be considered?
193 * Use 0 for any type. 192 * Must not be zero (ANY).
194 * @param proc function to call on each matching value; 193 * @param proc function to call on the matching value;
195 * will be called with NULL if no value matches 194 * will be called with NULL if no value matches
196 * @param proc_cls closure for proc 195 * @param proc_cls closure for proc
197 */ 196 */
198static void 197static void
199template_plugin_get_zero_anonymity (void *cls, uint64_t offset, 198template_plugin_get_zero_anonymity (void *cls, uint64_t next_uid,
200 enum GNUNET_BLOCK_Type type, 199 enum GNUNET_BLOCK_Type type,
201 PluginDatumProcessor proc, void *proc_cls) 200 PluginDatumProcessor proc, void *proc_cls)
202{ 201{
diff --git a/src/datastore/test_datastore_api.c b/src/datastore/test_datastore_api.c
index 9f89d4087..63927a364 100644
--- a/src/datastore/test_datastore_api.c
+++ b/src/datastore/test_datastore_api.c
@@ -130,8 +130,6 @@ enum RunPhase
130 RP_PUT_MULTIPLE_NEXT = 8, 130 RP_PUT_MULTIPLE_NEXT = 8,
131 RP_GET_MULTIPLE = 9, 131 RP_GET_MULTIPLE = 9,
132 RP_GET_MULTIPLE_NEXT = 10, 132 RP_GET_MULTIPLE_NEXT = 10,
133 RP_UPDATE = 11,
134 RP_UPDATE_VALIDATE = 12,
135 133
136 /** 134 /**
137 * Execution failed with some kind of error. 135 * Execution failed with some kind of error.
@@ -158,8 +156,6 @@ struct CpsRunContext
158 void *data; 156 void *data;
159 size_t size; 157 size_t size;
160 158
161 uint64_t uid;
162 uint64_t offset;
163 uint64_t first_uid; 159 uint64_t first_uid;
164}; 160};
165 161
@@ -235,6 +231,7 @@ check_value (void *cls,
235 enum GNUNET_BLOCK_Type type, 231 enum GNUNET_BLOCK_Type type,
236 uint32_t priority, 232 uint32_t priority,
237 uint32_t anonymity, 233 uint32_t anonymity,
234 uint32_t replication,
238 struct GNUNET_TIME_Absolute expiration, 235 struct GNUNET_TIME_Absolute expiration,
239 uint64_t uid) 236 uint64_t uid)
240{ 237{
@@ -269,7 +266,6 @@ check_value (void *cls,
269 GNUNET_assert (priority == get_priority (i)); 266 GNUNET_assert (priority == get_priority (i));
270 GNUNET_assert (anonymity == get_anonymity (i)); 267 GNUNET_assert (anonymity == get_anonymity (i));
271 GNUNET_assert (expiration.abs_value_us == get_expiration (i).abs_value_us); 268 GNUNET_assert (expiration.abs_value_us == get_expiration (i).abs_value_us);
272 crc->offset++;
273 if (crc->i == 0) 269 if (crc->i == 0)
274 { 270 {
275 crc->phase = RP_DEL; 271 crc->phase = RP_DEL;
@@ -288,6 +284,7 @@ delete_value (void *cls,
288 enum GNUNET_BLOCK_Type type, 284 enum GNUNET_BLOCK_Type type,
289 uint32_t priority, 285 uint32_t priority,
290 uint32_t anonymity, 286 uint32_t anonymity,
287 uint32_t replication,
291 struct GNUNET_TIME_Absolute expiration, 288 struct GNUNET_TIME_Absolute expiration,
292 uint64_t uid) 289 uint64_t uid)
293{ 290{
@@ -313,6 +310,7 @@ check_nothing (void *cls,
313 enum GNUNET_BLOCK_Type type, 310 enum GNUNET_BLOCK_Type type,
314 uint32_t priority, 311 uint32_t priority,
315 uint32_t anonymity, 312 uint32_t anonymity,
313 uint32_t replication,
316 struct GNUNET_TIME_Absolute expiration, 314 struct GNUNET_TIME_Absolute expiration,
317 uint64_t uid) 315 uint64_t uid)
318{ 316{
@@ -334,6 +332,7 @@ check_multiple (void *cls,
334 enum GNUNET_BLOCK_Type type, 332 enum GNUNET_BLOCK_Type type,
335 uint32_t priority, 333 uint32_t priority,
336 uint32_t anonymity, 334 uint32_t anonymity,
335 uint32_t replication,
337 struct GNUNET_TIME_Absolute expiration, 336 struct GNUNET_TIME_Absolute expiration,
338 uint64_t uid) 337 uint64_t uid)
339{ 338{
@@ -345,45 +344,16 @@ check_multiple (void *cls,
345 case RP_GET_MULTIPLE: 344 case RP_GET_MULTIPLE:
346 crc->phase = RP_GET_MULTIPLE_NEXT; 345 crc->phase = RP_GET_MULTIPLE_NEXT;
347 crc->first_uid = uid; 346 crc->first_uid = uid;
348 crc->offset++;
349 break; 347 break;
350 case RP_GET_MULTIPLE_NEXT: 348 case RP_GET_MULTIPLE_NEXT:
351 GNUNET_assert (uid != crc->first_uid); 349 GNUNET_assert (uid != crc->first_uid);
352 crc->phase = RP_UPDATE; 350 crc->phase = RP_DONE;
353 break; 351 break;
354 default: 352 default:
355 GNUNET_break (0); 353 GNUNET_break (0);
356 crc->phase = RP_ERROR; 354 crc->phase = RP_ERROR;
357 break; 355 break;
358 } 356 }
359 if (priority == get_priority (42))
360 crc->uid = uid;
361 GNUNET_SCHEDULER_add_now (&run_continuation, crc);
362}
363
364
365static void
366check_update (void *cls,
367 const struct GNUNET_HashCode *key,
368 size_t size,
369 const void *data,
370 enum GNUNET_BLOCK_Type type,
371 uint32_t priority,
372 uint32_t anonymity,
373 struct GNUNET_TIME_Absolute expiration,
374 uint64_t uid)
375{
376 struct CpsRunContext *crc = cls;
377
378 GNUNET_assert (key != NULL);
379 if ((anonymity == get_anonymity (42)) && (size == get_size (42)) &&
380 (priority == get_priority (42) + 100))
381 crc->phase = RP_DONE;
382 else
383 {
384 GNUNET_assert (size == get_size (43));
385 crc->offset++;
386 }
387 GNUNET_SCHEDULER_add_now (&run_continuation, crc); 357 GNUNET_SCHEDULER_add_now (&run_continuation, crc);
388} 358}
389 359
@@ -428,7 +398,8 @@ run_continuation (void *cls)
428 sizeof (int), 398 sizeof (int),
429 &crc->key); 399 &crc->key);
430 GNUNET_DATASTORE_get_key (datastore, 400 GNUNET_DATASTORE_get_key (datastore,
431 crc->offset, 401 0,
402 false,
432 &crc->key, 403 &crc->key,
433 get_type (crc->i), 404 get_type (crc->i),
434 1, 405 1,
@@ -445,7 +416,8 @@ run_continuation (void *cls)
445 GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key); 416 GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
446 GNUNET_assert (NULL != 417 GNUNET_assert (NULL !=
447 GNUNET_DATASTORE_get_key (datastore, 418 GNUNET_DATASTORE_get_key (datastore,
448 crc->offset, 419 0,
420 false,
449 &crc->key, 421 &crc->key,
450 get_type (crc->i), 422 get_type (crc->i),
451 1, 423 1,
@@ -478,9 +450,15 @@ run_continuation (void *cls)
478 crc->i); 450 crc->i);
479 GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key); 451 GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
480 GNUNET_assert (NULL != 452 GNUNET_assert (NULL !=
481 GNUNET_DATASTORE_get_key (datastore, crc->offset, &crc->key, 453 GNUNET_DATASTORE_get_key (datastore,
482 get_type (crc->i), 1, 1, 454 0,
483 &check_nothing, crc)); 455 false,
456 &crc->key,
457 get_type (crc->i),
458 1,
459 1,
460 &check_nothing,
461 crc));
484 break; 462 break;
485 case RP_RESERVE: 463 case RP_RESERVE:
486 crc->phase = RP_PUT_MULTIPLE; 464 crc->phase = RP_PUT_MULTIPLE;
@@ -511,37 +489,26 @@ run_continuation (void *cls)
511 case RP_GET_MULTIPLE: 489 case RP_GET_MULTIPLE:
512 GNUNET_assert (NULL != 490 GNUNET_assert (NULL !=
513 GNUNET_DATASTORE_get_key (datastore, 491 GNUNET_DATASTORE_get_key (datastore,
514 crc->offset, 492 0,
515 &crc->key, 493 false,
516 get_type (42), 1, 1,
517 &check_multiple, crc));
518 break;
519 case RP_GET_MULTIPLE_NEXT:
520 GNUNET_assert (NULL !=
521 GNUNET_DATASTORE_get_key (datastore,
522 crc->offset,
523 &crc->key, 494 &crc->key,
524 get_type (42), 495 get_type (42),
525 1, 1, 496 1,
526 &check_multiple, crc)); 497 1,
527 break; 498 &check_multiple,
528 case RP_UPDATE: 499 crc));
529 GNUNET_assert (crc->uid > 0);
530 crc->phase = RP_UPDATE_VALIDATE;
531 GNUNET_DATASTORE_update (datastore,
532 crc->uid, 100,
533 get_expiration (42), 1,
534 1,
535 &check_success, crc);
536 break; 500 break;
537 case RP_UPDATE_VALIDATE: 501 case RP_GET_MULTIPLE_NEXT:
538 GNUNET_assert (NULL != 502 GNUNET_assert (NULL !=
539 GNUNET_DATASTORE_get_key (datastore, 503 GNUNET_DATASTORE_get_key (datastore,
540 crc->offset, 504 crc->first_uid + 1,
505 false,
541 &crc->key, 506 &crc->key,
542 get_type (42), 507 get_type (42),
543 1, 1, 508 1,
544 &check_update, crc)); 509 1,
510 &check_multiple,
511 crc));
545 break; 512 break;
546 case RP_DONE: 513 case RP_DONE:
547 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 514 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 5e536d6c5..e50b98909 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
@@ -138,9 +137,15 @@ check_success (void *cls, int success, struct GNUNET_TIME_Absolute min_expiratio
138 137
139 138
140static void 139static void
141check_value (void *cls, const struct GNUNET_HashCode * key, size_t size, 140check_value (void *cls,
142 const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, 141 const struct GNUNET_HashCode *key,
143 uint32_t anonymity, struct GNUNET_TIME_Absolute expiration, 142 size_t size,
143 const void *data,
144 enum GNUNET_BLOCK_Type type,
145 uint32_t priority,
146 uint32_t anonymity,
147 uint32_t replication,
148 struct GNUNET_TIME_Absolute expiration,
144 uint64_t uid) 149 uint64_t uid)
145{ 150{
146 struct CpsRunContext *crc = cls; 151 struct CpsRunContext *crc = cls;
@@ -159,7 +164,6 @@ check_value (void *cls, const struct GNUNET_HashCode * key, size_t size,
159 GNUNET_assert (priority == get_priority (i)); 164 GNUNET_assert (priority == get_priority (i));
160 GNUNET_assert (anonymity == get_anonymity (i)); 165 GNUNET_assert (anonymity == get_anonymity (i));
161 GNUNET_assert (expiration.abs_value_us == get_expiration (i).abs_value_us); 166 GNUNET_assert (expiration.abs_value_us == get_expiration (i).abs_value_us);
162 crc->offset++;
163 crc->i--; 167 crc->i--;
164 if (crc->i == 0) 168 if (crc->i == 0)
165 crc->phase = RP_DONE; 169 crc->phase = RP_DONE;
@@ -168,9 +172,15 @@ check_value (void *cls, const struct GNUNET_HashCode * key, size_t size,
168 172
169 173
170static void 174static void
171check_nothing (void *cls, const struct GNUNET_HashCode * key, size_t size, 175check_nothing (void *cls,
172 const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, 176 const struct GNUNET_HashCode *key,
173 uint32_t anonymity, struct GNUNET_TIME_Absolute expiration, 177 size_t size,
178 const void *data,
179 enum GNUNET_BLOCK_Type type,
180 uint32_t priority,
181 uint32_t anonymity,
182 uint32_t replication,
183 struct GNUNET_TIME_Absolute expiration,
174 uint64_t uid) 184 uint64_t uid)
175{ 185{
176 struct CpsRunContext *crc = cls; 186 struct CpsRunContext *crc = cls;
@@ -221,8 +231,13 @@ run_continuation (void *cls)
221 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing `%s' number %u\n", "GET", 231 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing `%s' number %u\n", "GET",
222 crc->i); 232 crc->i);
223 GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key); 233 GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
224 GNUNET_DATASTORE_get_key (datastore, crc->offset++, &crc->key, 234 GNUNET_DATASTORE_get_key (datastore,
225 get_type (crc->i), 1, 1, 235 0,
236 false,
237 &crc->key,
238 get_type (crc->i),
239 1,
240 1,
226 &check_value, 241 &check_value,
227 crc); 242 crc);
228 break; 243 break;
@@ -230,8 +245,13 @@ run_continuation (void *cls)
230 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing `%s' number %u\n", "GET(f)", 245 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing `%s' number %u\n", "GET(f)",
231 crc->i); 246 crc->i);
232 GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key); 247 GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
233 GNUNET_DATASTORE_get_key (datastore, crc->offset++, &crc->key, 248 GNUNET_DATASTORE_get_key (datastore,
234 get_type (crc->i), 1, 1, 249 0,
250 false,
251 &crc->key,
252 get_type (crc->i),
253 1,
254 1,
235 &check_nothing, 255 &check_nothing,
236 crc); 256 crc);
237 break; 257 break;
@@ -298,7 +318,21 @@ run (void *cls,
298 318
299 319
300/** 320/**
301 * check if plugin is actually working 321 * Function called when disk utilization changes, does nothing.
322 *
323 * @param cls closure
324 * @param delta change in utilization
325 */
326static void
327ignore_payload_cb (void *cls,
328 int delta)
329{
330 /* do nothing */
331}
332
333
334/**
335 * check if plugin is actually working
302 */ 336 */
303static int 337static int
304test_plugin (const char *cfg_name) 338test_plugin (const char *cfg_name)
@@ -307,7 +341,7 @@ test_plugin (const char *cfg_name)
307 struct GNUNET_CONFIGURATION_Handle *cfg; 341 struct GNUNET_CONFIGURATION_Handle *cfg;
308 struct GNUNET_DATASTORE_PluginFunctions *api; 342 struct GNUNET_DATASTORE_PluginFunctions *api;
309 struct GNUNET_DATASTORE_PluginEnvironment env; 343 struct GNUNET_DATASTORE_PluginEnvironment env;
310 344
311 cfg = GNUNET_CONFIGURATION_create (); 345 cfg = GNUNET_CONFIGURATION_create ();
312 if (GNUNET_OK != 346 if (GNUNET_OK !=
313 GNUNET_CONFIGURATION_load (cfg, 347 GNUNET_CONFIGURATION_load (cfg,
@@ -321,6 +355,7 @@ test_plugin (const char *cfg_name)
321 } 355 }
322 memset (&env, 0, sizeof (env)); 356 memset (&env, 0, sizeof (env));
323 env.cfg = cfg; 357 env.cfg = cfg;
358 env.duc = &ignore_payload_cb;
324 GNUNET_snprintf (libname, 359 GNUNET_snprintf (libname,
325 sizeof (libname), 360 sizeof (libname),
326 "libgnunet_plugin_datastore_%s", 361 "libgnunet_plugin_datastore_%s",
diff --git a/src/datastore/test_plugin_datastore.c b/src/datastore/test_plugin_datastore.c
index 9b85d57da..1867d6755 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
@@ -194,6 +193,7 @@ iterate_one_shot (void *cls,
194 enum GNUNET_BLOCK_Type type, 193 enum GNUNET_BLOCK_Type type,
195 uint32_t priority, 194 uint32_t priority,
196 uint32_t anonymity, 195 uint32_t anonymity,
196 uint32_t replication,
197 struct GNUNET_TIME_Absolute expiration, 197 struct GNUNET_TIME_Absolute expiration,
198 uint64_t uid) 198 uint64_t uid)
199{ 199{
@@ -308,7 +308,8 @@ test (void *cls)
308 "Looking for %s\n", 308 "Looking for %s\n",
309 GNUNET_h2s (&key)); 309 GNUNET_h2s (&key));
310 crc->api->get_key (crc->api->cls, 310 crc->api->get_key (crc->api->cls,
311 crc->offset++, 311 0,
312 false,
312 &key, 313 &key,
313 NULL, 314 NULL,
314 GNUNET_BLOCK_TYPE_ANY, 315 GNUNET_BLOCK_TYPE_ANY,
@@ -317,11 +318,12 @@ test (void *cls)
317 break; 318 break;
318 case RP_UPDATE: 319 case RP_UPDATE:
319 crc->api->update (crc->api->cls, 320 crc->api->update (crc->api->cls,
320 guid, 321 guid,
321 1, 322 1,
322 GNUNET_TIME_UNIT_ZERO_ABS, 323 1,
324 GNUNET_TIME_UNIT_ZERO_ABS,
323 &update_continuation, 325 &update_continuation,
324 crc); 326 crc);
325 break; 327 break;
326 328
327 case RP_ITER_ZERO: 329 case RP_ITER_ZERO:
diff --git a/src/dht/.gitignore b/src/dht/.gitignore
index e7f3c2a86..25b1daf28 100644
--- a/src/dht/.gitignore
+++ b/src/dht/.gitignore
@@ -1,10 +1,8 @@
1gnunet-service-dht-xvine
2gnunet-dht-get 1gnunet-dht-get
3gnunet-dht-monitor 2gnunet-dht-monitor
4gnunet-dht-profiler 3gnunet-dht-profiler
5gnunet-dht-put 4gnunet-dht-put
6gnunet-service-dht 5gnunet-service-dht
7gnunet-service-dht-whanau
8test_dht_2dtorus 6test_dht_2dtorus
9test_dht_api 7test_dht_api
10test_dht_line 8test_dht_line
diff --git a/src/dht/Makefile.am b/src/dht/Makefile.am
index 1a174165c..f712890ac 100644
--- a/src/dht/Makefile.am
+++ b/src/dht/Makefile.am
@@ -40,6 +40,7 @@ libgnunet_plugin_block_dht_la_SOURCES = \
40libgnunet_plugin_block_dht_la_LIBADD = \ 40libgnunet_plugin_block_dht_la_LIBADD = \
41 $(top_builddir)/src/hello/libgnunethello.la \ 41 $(top_builddir)/src/hello/libgnunethello.la \
42 $(top_builddir)/src/block/libgnunetblock.la \ 42 $(top_builddir)/src/block/libgnunetblock.la \
43 $(top_builddir)/src/block/libgnunetblockgroup.la \
43 $(top_builddir)/src/util/libgnunetutil.la \ 44 $(top_builddir)/src/util/libgnunetutil.la \
44 $(LTLIBINTL) 45 $(LTLIBINTL)
45libgnunet_plugin_block_dht_la_LDFLAGS = \ 46libgnunet_plugin_block_dht_la_LDFLAGS = \
@@ -49,12 +50,6 @@ libgnunet_plugin_block_dht_la_LDFLAGS = \
49libexec_PROGRAMS = \ 50libexec_PROGRAMS = \
50 gnunet-service-dht 51 gnunet-service-dht
51 52
52if HAVE_EXPERIMENTAL
53libexec_PROGRAMS += \
54 gnunet-service-dht-xvine \
55 gnunet-service-dht-whanau
56endif
57
58noinst_PROGRAMS = \ 53noinst_PROGRAMS = \
59 gnunet-dht-monitor \ 54 gnunet-dht-monitor \
60 gnunet-dht-get \ 55 gnunet-dht-get \
@@ -85,44 +80,6 @@ gnunet_service_dht_LDADD = \
85 $(top_builddir)/src/util/libgnunetutil.la \ 80 $(top_builddir)/src/util/libgnunetutil.la \
86 -lm 81 -lm
87 82
88gnunet_service_dht_xvine_SOURCES = \
89 gnunet-service-xdht.c gnunet-service-dht.h \
90 gnunet-service-dht_datacache.c gnunet-service-dht_datacache.h \
91 gnunet-service-dht_nse.c gnunet-service-dht_nse.h \
92 gnunet-service-xdht_neighbours.c gnunet-service-xdht_neighbours.h \
93 gnunet-service-xdht_routing.c gnunet-service-xdht_routing.h
94
95gnunet_service_dht_xvine_LDADD = \
96 $(top_builddir)/src/statistics/libgnunetstatistics.la \
97 $(top_builddir)/src/core/libgnunetcore.la \
98 $(top_builddir)/src/nse/libgnunetnse.la \
99 $(top_builddir)/src/ats/libgnunetats.la \
100 $(top_builddir)/src/transport/libgnunettransport.la \
101 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
102 $(top_builddir)/src/hello/libgnunethello.la \
103 $(top_builddir)/src/block/libgnunetblock.la \
104 $(top_builddir)/src/datacache/libgnunetdatacache.la \
105 $(top_builddir)/src/util/libgnunetutil.la \
106 -lm
107
108gnunet_service_dht_whanau_SOURCES = \
109 gnunet-service-wdht.c gnunet-service-wdht.h \
110 gnunet-service-dht_datacache.c gnunet-service-dht_datacache.h \
111 gnunet-service-dht_nse.c gnunet-service-dht_nse.h \
112 gnunet-service-wdht_neighbours.c gnunet-service-dht_neighbours.h
113gnunet_service_dht_whanau_LDADD = \
114 $(top_builddir)/src/statistics/libgnunetstatistics.la \
115 $(top_builddir)/src/core/libgnunetcore.la \
116 $(top_builddir)/src/nse/libgnunetnse.la \
117 $(top_builddir)/src/ats/libgnunetats.la \
118 $(top_builddir)/src/transport/libgnunettransport.la \
119 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
120 $(top_builddir)/src/hello/libgnunethello.la \
121 $(top_builddir)/src/block/libgnunetblock.la \
122 $(top_builddir)/src/datacache/libgnunetdatacache.la \
123 $(top_builddir)/src/util/libgnunetutil.la \
124 -lm
125
126gnunet_dht_get_SOURCES = \ 83gnunet_dht_get_SOURCES = \
127 gnunet-dht-get.c 84 gnunet-dht-get.c
128gnunet_dht_get_LDADD = \ 85gnunet_dht_get_LDADD = \
@@ -180,7 +137,7 @@ if HAVE_EXPERIMENTAL
180endif 137endif
181 138
182if ENABLE_TEST_RUN 139if ENABLE_TEST_RUN
183AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; 140AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
184TESTS = test_dht_api $(check_SCRIPTS) \ 141TESTS = test_dht_api $(check_SCRIPTS) \
185 test_dht_twopeer \ 142 test_dht_twopeer \
186 test_dht_line \ 143 test_dht_line \
@@ -254,7 +211,7 @@ check_SCRIPTS = \
254 test_dht_tools.py 211 test_dht_tools.py
255endif 212endif
256 213
257do_subst = $(SED) -e 's,[@]PYTHON[@],$(PYTHON),g' 214do_subst = $(SED) -e 's,[@]PYTHON[@],$(PYTHON),g' -e 's,[@]bindir[@],$(bindir),g'
258 215
259%.py: %.py.in Makefile 216%.py: %.py.in Makefile
260 $(do_subst) < $(srcdir)/$< > $@ 217 $(do_subst) < $(srcdir)/$< > $@
diff --git a/src/dht/dht_api.c b/src/dht/dht_api.c
index 66eaf1064..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)
@@ -503,7 +503,7 @@ check_monitor_get (void *cls,
503 uint16_t msize = ntohs (msg->header.size) - sizeof (*msg); 503 uint16_t msize = ntohs (msg->header.size) - sizeof (*msg);
504 504
505 if ( (plen > UINT16_MAX) || 505 if ( (plen > UINT16_MAX) ||
506 (plen * sizeof (struct GNUNET_HashCode) != msize) ) 506 (plen * sizeof (struct GNUNET_PeerIdentity) != msize) )
507 { 507 {
508 GNUNET_break (0); 508 GNUNET_break (0);
509 return GNUNET_SYSERR; 509 return GNUNET_SYSERR;
@@ -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;
@@ -754,12 +754,25 @@ process_client_result (void *cls,
754 meta_length = 754 meta_length =
755 sizeof (struct GNUNET_PeerIdentity) * (get_path_length + put_path_length); 755 sizeof (struct GNUNET_PeerIdentity) * (get_path_length + put_path_length);
756 data_length = msize - meta_length; 756 data_length = msize - meta_length;
757 LOG (GNUNET_ERROR_TYPE_DEBUG,
758 "Giving %u byte reply for %s to application\n",
759 (unsigned int) data_length,
760 GNUNET_h2s (key));
761 put_path = (const struct GNUNET_PeerIdentity *) &crm[1]; 757 put_path = (const struct GNUNET_PeerIdentity *) &crm[1];
762 get_path = &put_path[put_path_length]; 758 get_path = &put_path[put_path_length];
759 {
760 char *pp;
761 char *gp;
762
763 gp = GNUNET_STRINGS_pp2s (get_path,
764 get_path_length);
765 pp = GNUNET_STRINGS_pp2s (put_path,
766 put_path_length);
767 LOG (GNUNET_ERROR_TYPE_DEBUG,
768 "Giving %u byte reply for %s to application (GP: %s, PP: %s)\n",
769 (unsigned int) data_length,
770 GNUNET_h2s (key),
771 gp,
772 pp);
773 GNUNET_free (gp);
774 GNUNET_free (pp);
775 }
763 data = &get_path[get_path_length]; 776 data = &get_path[get_path_length];
764 /* remember that we've seen this result */ 777 /* remember that we've seen this result */
765 GNUNET_CRYPTO_hash (data, 778 GNUNET_CRYPTO_hash (data,
@@ -985,8 +998,8 @@ GNUNET_DHT_put (struct GNUNET_DHT_Handle *handle,
985 struct GNUNET_DHT_PutHandle *ph; 998 struct GNUNET_DHT_PutHandle *ph;
986 999
987 msize = sizeof (struct GNUNET_DHT_ClientPutMessage) + size; 1000 msize = sizeof (struct GNUNET_DHT_ClientPutMessage) + size;
988 if ((msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) || 1001 if ((msize >= GNUNET_MAX_MESSAGE_SIZE) ||
989 (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)) 1002 (size >= GNUNET_MAX_MESSAGE_SIZE))
990 { 1003 {
991 GNUNET_break (0); 1004 GNUNET_break (0);
992 return NULL; 1005 return NULL;
@@ -1077,8 +1090,8 @@ GNUNET_DHT_get_start (struct GNUNET_DHT_Handle *handle,
1077 size_t msize; 1090 size_t msize;
1078 1091
1079 msize = sizeof (struct GNUNET_DHT_ClientGetMessage) + xquery_size; 1092 msize = sizeof (struct GNUNET_DHT_ClientGetMessage) + xquery_size;
1080 if ((msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) || 1093 if ((msize >= GNUNET_MAX_MESSAGE_SIZE) ||
1081 (xquery_size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)) 1094 (xquery_size >= GNUNET_MAX_MESSAGE_SIZE))
1082 { 1095 {
1083 GNUNET_break (0); 1096 GNUNET_break (0);
1084 return NULL; 1097 return NULL;
diff --git a/src/dht/gnunet-dht-get.c b/src/dht/gnunet-dht-get.c
index 8a1b836f6..e361df336 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
@@ -148,13 +148,36 @@ get_result_iterator (void *cls, struct GNUNET_TIME_Absolute exp,
148 const struct GNUNET_PeerIdentity *get_path, 148 const struct GNUNET_PeerIdentity *get_path,
149 unsigned int get_path_length, 149 unsigned int get_path_length,
150 const struct GNUNET_PeerIdentity *put_path, 150 const struct GNUNET_PeerIdentity *put_path,
151 unsigned int put_path_length, enum GNUNET_BLOCK_Type type, 151 unsigned int put_path_length,
152 size_t size, const void *data) 152 enum GNUNET_BLOCK_Type type,
153 size_t size,
154 const void *data)
153{ 155{
154 FPRINTF (stdout, 156 FPRINTF (stdout,
155 _("Result %d, type %d:\n%.*s\n"), 157 _("Result %d, type %d:\n%.*s\n"),
156 result_count, type, 158 result_count,
157 (unsigned int) size, (char *) data); 159 type,
160 (unsigned int) size,
161 (char *) data);
162 if (verbose)
163 {
164 FPRINTF (stdout,
165 " GET path: ");
166 for (unsigned int i=0;i<get_path_length;i++)
167 FPRINTF (stdout,
168 "%s%s",
169 (0 == i) ? "" : "-",
170 GNUNET_i2s (&get_path[i]));
171 FPRINTF (stdout,
172 "\n PUT path: ");
173 for (unsigned int i=0;i<put_path_length;i++)
174 FPRINTF (stdout,
175 "%s%s",
176 (0 == i) ? "" : "-",
177 GNUNET_i2s (&put_path[i]));
178 FPRINTF (stdout,
179 "\n");
180 }
158 result_count++; 181 result_count++;
159} 182}
160 183
@@ -203,33 +226,6 @@ run (void *cls, char *const *args, const char *cfgfile,
203 226
204} 227}
205 228
206
207/**
208 * gnunet-dht-get command line options
209 */
210static struct GNUNET_GETOPT_CommandLineOption options[] = {
211 {'k', "key", "KEY",
212 gettext_noop ("the query key"),
213 1, &GNUNET_GETOPT_set_string, &query_key},
214 {'r', "replication", "LEVEL",
215 gettext_noop ("how many parallel requests (replicas) to create"),
216 1, &GNUNET_GETOPT_set_uint, &replication},
217 {'t', "type", "TYPE",
218 gettext_noop ("the type of data to look for"),
219 1, &GNUNET_GETOPT_set_uint, &query_type},
220 {'T', "timeout", "TIMEOUT",
221 gettext_noop ("how long to execute this query before giving up?"),
222 1, &GNUNET_GETOPT_set_relative_time, &timeout_request},
223 {'x', "demultiplex", NULL,
224 gettext_noop ("use DHT's demultiplex everywhere option"),
225 0, &GNUNET_GETOPT_set_one, &demultixplex_everywhere},
226 {'V', "verbose", NULL,
227 gettext_noop ("be verbose (print progress information)"),
228 0, &GNUNET_GETOPT_set_one, &verbose},
229 GNUNET_GETOPT_OPTION_END
230};
231
232
233/** 229/**
234 * Entry point for gnunet-dht-get 230 * Entry point for gnunet-dht-get
235 * 231 *
@@ -240,6 +236,45 @@ static struct GNUNET_GETOPT_CommandLineOption options[] = {
240int 236int
241main (int argc, char *const *argv) 237main (int argc, char *const *argv)
242{ 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_uint ('r',
249 "replication",
250 "LEVEL",
251 gettext_noop ("how many parallel requests (replicas) to create"),
252 &replication),
253
254
255 GNUNET_GETOPT_option_uint ('t',
256 "type",
257 "TYPE",
258 gettext_noop ("the type of data to look for"),
259 &query_type),
260
261 GNUNET_GETOPT_option_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_flag ('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
243 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))
244 return 2; 279 return 2;
245 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..b7360bbab 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_uint ('t',
302 "type",
303 "TYPE",
304 gettext_noop ("the type of data to look for"),
305 &block_type),
306
307 GNUNET_GETOPT_option_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_flag ('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 1f3df1d35..f183fe588 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
@@ -44,7 +44,7 @@ static char *query_key;
44/** 44/**
45 * User supplied expiration value 45 * User supplied expiration value
46 */ 46 */
47static unsigned long long expiration_seconds = 3600; 47static struct GNUNET_TIME_Relative expiration;
48 48
49/** 49/**
50 * Desired replication level. 50 * Desired replication level.
@@ -54,14 +54,19 @@ 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 DHT demultixplex_everywhere 60 * Use #GNUNET_DHT_DEMULTIPLEX_EVERYWHERE.
61 */ 61 */
62static int demultixplex_everywhere; 62static int demultixplex_everywhere;
63 63
64/** 64/**
65 * Use #GNUNET_DHT_RO_RECORD_ROUTE.
66 */
67static int record_route;
68
69/**
65 * Handle to the DHT 70 * Handle to the DHT
66 */ 71 */
67static struct GNUNET_DHT_Handle *dht_handle; 72static struct GNUNET_DHT_Handle *dht_handle;
@@ -143,7 +148,7 @@ run (void *cls,
143 const char *cfgfile, 148 const char *cfgfile,
144 const struct GNUNET_CONFIGURATION_Handle *c) 149 const struct GNUNET_CONFIGURATION_Handle *c)
145{ 150{
146 struct GNUNET_TIME_Absolute expiration; 151 enum GNUNET_DHT_RouteOption ro;
147 152
148 cfg = c; 153 cfg = c;
149 if ((NULL == query_key) || (NULL == data)) 154 if ((NULL == query_key) || (NULL == data))
@@ -164,55 +169,28 @@ run (void *cls,
164 169
165 GNUNET_CRYPTO_hash (query_key, strlen (query_key), &key); 170 GNUNET_CRYPTO_hash (query_key, strlen (query_key), &key);
166 171
167 expiration =
168 GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_multiply
169 (GNUNET_TIME_UNIT_SECONDS,
170 expiration_seconds));
171 if (verbose) 172 if (verbose)
172 FPRINTF (stderr, _("Issuing put request for `%s' with data `%s'!\n"), 173 FPRINTF (stderr,
173 query_key, data); 174 _("Issuing put request for `%s' with data `%s'!\n"),
175 query_key,
176 data);
177 ro = GNUNET_DHT_RO_NONE;
178 if (demultixplex_everywhere)
179 ro |= GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE;
180 if (record_route)
181 ro |= GNUNET_DHT_RO_RECORD_ROUTE;
174 GNUNET_DHT_put (dht_handle, 182 GNUNET_DHT_put (dht_handle,
175 &key, 183 &key,
176 replication, 184 replication,
177 (demultixplex_everywhere) ? GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE : GNUNET_DHT_RO_NONE, 185 ro,
178 query_type, 186 query_type,
179 strlen (data), 187 strlen (data),
180 data, 188 data,
181 expiration, 189 GNUNET_TIME_relative_to_absolute (expiration),
182 &message_sent_cont, 190 &message_sent_cont,
183 NULL); 191 NULL);
184} 192}
185 193
186
187/**
188 * gnunet-dht-put command line options
189 */
190static struct GNUNET_GETOPT_CommandLineOption options[] = {
191 {'d', "data", "DATA",
192 gettext_noop ("the data to insert under the key"),
193 1, &GNUNET_GETOPT_set_string, &data},
194 {'e', "expiration", "EXPIRATION",
195 gettext_noop ("how long to store this entry in the dht (in seconds)"),
196 1, &GNUNET_GETOPT_set_ulong, &expiration_seconds},
197 {'k', "key", "KEY",
198 gettext_noop ("the query key"),
199 1, &GNUNET_GETOPT_set_string, &query_key},
200 {'x', "demultiplex", NULL,
201 gettext_noop ("use DHT's demultiplex everywhere option"),
202 0, &GNUNET_GETOPT_set_one, &demultixplex_everywhere},
203 {'r', "replication", "LEVEL",
204 gettext_noop ("how many replicas to create"),
205 1, &GNUNET_GETOPT_set_uint, &replication},
206 {'t', "type", "TYPE",
207 gettext_noop ("the type to insert data as"),
208 1, &GNUNET_GETOPT_set_uint, &query_type},
209 {'V', "verbose", NULL,
210 gettext_noop ("be verbose (print progress information)"),
211 0, &GNUNET_GETOPT_set_one, &verbose},
212 GNUNET_GETOPT_OPTION_END
213};
214
215
216/** 194/**
217 * Entry point for gnunet-dht-put 195 * Entry point for gnunet-dht-put
218 * 196 *
@@ -223,14 +201,69 @@ static struct GNUNET_GETOPT_CommandLineOption options[] = {
223int 201int
224main (int argc, char *const *argv) 202main (int argc, char *const *argv)
225{ 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_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_flag ('x',
226 "demultiplex",
227 gettext_noop ("use DHT's demultiplex everywhere option"),
228 &demultixplex_everywhere),
229
230 GNUNET_GETOPT_option_uint ('r',
231 "replication",
232 "LEVEL",
233 gettext_noop ("how many replicas to create"),
234 &replication),
235
236 GNUNET_GETOPT_option_flag ('R',
237 "record",
238 gettext_noop ("use DHT's record route option"),
239 &record_route),
240
241 GNUNET_GETOPT_option_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
226 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, 253 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv,
227 &argc, &argv)) 254 &argc, &argv))
228 return 2; 255 return 2;
256 expiration = GNUNET_TIME_UNIT_HOURS;
229 return (GNUNET_OK == 257 return (GNUNET_OK ==
230 GNUNET_PROGRAM_run (argc, argv, "gnunet-dht-put", 258 GNUNET_PROGRAM_run (argc,
259 argv,
260 "gnunet-dht-put",
231 gettext_noop 261 gettext_noop
232 ("Issue a PUT request to the GNUnet DHT insert DATA under KEY."), 262 ("Issue a PUT request to the GNUnet DHT insert DATA under KEY."),
233 options, &run, NULL)) ? ret : 1; 263 options,
264 &run,
265 NULL))
266 ? ret : 1;
234} 267}
235 268
236/* end of gnunet-dht-put.c */ 269/* end of gnunet-dht-put.c */
diff --git a/src/dht/gnunet-service-dht_clients.c b/src/dht/gnunet-service-dht_clients.c
index 5ba4e5820..cb155c484 100644
--- a/src/dht/gnunet-service-dht_clients.c
+++ b/src/dht/gnunet-service-dht_clients.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, 2010, 2011, 2016 GNUnet e.V. 3 Copyright (C) 2009, 2010, 2011, 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
@@ -362,21 +362,25 @@ client_disconnect_cb (void *cls,
362static void 362static void
363transmit_request (struct ClientQueryRecord *cqr) 363transmit_request (struct ClientQueryRecord *cqr)
364{ 364{
365 int32_t reply_bf_mutator; 365 struct GNUNET_BLOCK_Group *bg;
366 struct GNUNET_CONTAINER_BloomFilter *reply_bf;
367 struct GNUNET_CONTAINER_BloomFilter *peer_bf; 366 struct GNUNET_CONTAINER_BloomFilter *peer_bf;
368 367
369 GNUNET_STATISTICS_update (GDS_stats, 368 GNUNET_STATISTICS_update (GDS_stats,
370 gettext_noop ("# GET requests from clients injected"), 369 gettext_noop ("# GET requests from clients injected"),
371 1, 370 1,
372 GNUNET_NO); 371 GNUNET_NO);
373 reply_bf_mutator = 372 bg = GNUNET_BLOCK_group_create (GDS_block_context,
374 (int32_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 373 cqr->type,
375 UINT32_MAX); 374 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
376 reply_bf 375 UINT32_MAX),
377 = GNUNET_BLOCK_construct_bloomfilter (reply_bf_mutator, 376 NULL,
378 cqr->seen_replies, 377 0,
379 cqr->seen_replies_count); 378 "seen-set-size",
379 cqr->seen_replies_count,
380 NULL);
381 GNUNET_BLOCK_group_set_seen (bg,
382 cqr->seen_replies,
383 cqr->seen_replies_count);
380 peer_bf 384 peer_bf
381 = GNUNET_CONTAINER_bloomfilter_init (NULL, 385 = GNUNET_CONTAINER_bloomfilter_init (NULL,
382 DHT_BLOOM_SIZE, 386 DHT_BLOOM_SIZE,
@@ -393,10 +397,9 @@ transmit_request (struct ClientQueryRecord *cqr)
393 &cqr->key, 397 &cqr->key,
394 cqr->xquery, 398 cqr->xquery,
395 cqr->xquery_size, 399 cqr->xquery_size,
396 reply_bf, 400 bg,
397 reply_bf_mutator,
398 peer_bf); 401 peer_bf);
399 GNUNET_CONTAINER_bloomfilter_free (reply_bf); 402 GNUNET_BLOCK_group_destroy (bg);
400 GNUNET_CONTAINER_bloomfilter_free (peer_bf); 403 GNUNET_CONTAINER_bloomfilter_free (peer_bf);
401 404
402 /* exponential back-off for retries. 405 /* exponential back-off for retries.
@@ -668,7 +671,6 @@ handle_dht_local_get (void *cls,
668 cqr->xquery, 671 cqr->xquery,
669 xquery_size, 672 xquery_size,
670 NULL, 673 NULL,
671 0,
672 &handle_local_result, 674 &handle_local_result,
673 ch); 675 ch);
674 GNUNET_SERVICE_client_continue (ch->client); 676 GNUNET_SERVICE_client_continue (ch->client);
@@ -1052,10 +1054,9 @@ forward_reply (void *cls,
1052 eval 1054 eval
1053 = GNUNET_BLOCK_evaluate (GDS_block_context, 1055 = GNUNET_BLOCK_evaluate (GDS_block_context,
1054 record->type, 1056 record->type,
1057 NULL,
1055 GNUNET_BLOCK_EO_NONE, 1058 GNUNET_BLOCK_EO_NONE,
1056 key, 1059 key,
1057 NULL,
1058 0,
1059 record->xquery, 1060 record->xquery,
1060 record->xquery_size, 1061 record->xquery_size,
1061 frc->data, 1062 frc->data,
@@ -1165,7 +1166,7 @@ GDS_CLIENTS_handle_reply (struct GNUNET_TIME_Absolute expiration,
1165 1166
1166 msize = sizeof (struct GNUNET_DHT_ClientResultMessage) + data_size + 1167 msize = sizeof (struct GNUNET_DHT_ClientResultMessage) + data_size +
1167 (get_path_length + put_path_length) * sizeof (struct GNUNET_PeerIdentity); 1168 (get_path_length + put_path_length) * sizeof (struct GNUNET_PeerIdentity);
1168 if (msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) 1169 if (msize >= GNUNET_MAX_MESSAGE_SIZE)
1169 { 1170 {
1170 GNUNET_break (0); 1171 GNUNET_break (0);
1171 return; 1172 return;
diff --git a/src/dht/gnunet-service-dht_datacache.c b/src/dht/gnunet-service-dht_datacache.c
index 9b4dace67..36047d561 100644
--- a/src/dht/gnunet-service-dht_datacache.c
+++ b/src/dht/gnunet-service-dht_datacache.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, 2010, 2011, 2015 GNUnet e.V. 3 Copyright (C) 2009, 2010, 2011, 2015, 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
@@ -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;
@@ -109,39 +109,34 @@ struct GetRequestContext
109 const void *xquery; 109 const void *xquery;
110 110
111 /** 111 /**
112 * Bloomfilter to filter out duplicate replies (updated)
113 */
114 struct GNUNET_CONTAINER_BloomFilter **reply_bf;
115
116 /**
117 * The key this request was about 112 * The key this request was about
118 */ 113 */
119 struct GNUNET_HashCode key; 114 struct GNUNET_HashCode key;
120 115
121 /** 116 /**
122 * Number of bytes in xquery. 117 * Block group to use to evaluate replies (updated)
123 */ 118 */
124 size_t xquery_size; 119 struct GNUNET_BLOCK_Group *bg;
125 120
126 /** 121 /**
127 * Mutator value for the @e reply_bf, see gnunet_block_lib.h 122 * Function to call on results.
128 */ 123 */
129 uint32_t reply_bf_mutator; 124 GDS_DATACACHE_GetCallback gc;
130 125
131 /** 126 /**
132 * Return value to give back. 127 * Closure for @e gc.
133 */ 128 */
134 enum GNUNET_BLOCK_EvaluationResult eval; 129 void *gc_cls;
135 130
136 /** 131 /**
137 * Function to call on results. 132 * Number of bytes in xquery.
138 */ 133 */
139 GDS_DATACACHE_GetCallback gc; 134 size_t xquery_size;
140 135
141 /** 136 /**
142 * Closure for @e gc. 137 * Return value to give back.
143 */ 138 */
144 void *gc_cls; 139 enum GNUNET_BLOCK_EvaluationResult eval;
145 140
146}; 141};
147 142
@@ -170,16 +165,20 @@ datacache_get_iterator (void *cls,
170 unsigned int put_path_length, 165 unsigned int put_path_length,
171 const struct GNUNET_PeerIdentity *put_path) 166 const struct GNUNET_PeerIdentity *put_path)
172{ 167{
168 static char non_null;
173 struct GetRequestContext *ctx = cls; 169 struct GetRequestContext *ctx = cls;
174 enum GNUNET_BLOCK_EvaluationResult eval; 170 enum GNUNET_BLOCK_EvaluationResult eval;
175 171
172 if ( (NULL == data) &&
173 (0 == data_size) )
174 data = &non_null; /* point anywhere, but not to NULL */
175
176 eval 176 eval
177 = GNUNET_BLOCK_evaluate (GDS_block_context, 177 = GNUNET_BLOCK_evaluate (GDS_block_context,
178 type, 178 type,
179 ctx->bg,
179 GNUNET_BLOCK_EO_LOCAL_SKIP_CRYPTO, 180 GNUNET_BLOCK_EO_LOCAL_SKIP_CRYPTO,
180 key, 181 key,
181 ctx->reply_bf,
182 ctx->reply_bf_mutator,
183 ctx->xquery, 182 ctx->xquery,
184 ctx->xquery_size, 183 ctx->xquery_size,
185 data, 184 data,
@@ -251,8 +250,7 @@ datacache_get_iterator (void *cls,
251 * @param type requested data type 250 * @param type requested data type
252 * @param xquery extended query 251 * @param xquery extended query
253 * @param xquery_size number of bytes in @a xquery 252 * @param xquery_size number of bytes in @a xquery
254 * @param reply_bf where the reply bf is (to be) stored, possibly updated, can be NULL 253 * @param bg block group to use for reply evaluation
255 * @param reply_bf_mutator mutation value for @a reply_bf
256 * @param gc function to call on the results 254 * @param gc function to call on the results
257 * @param gc_cls closure for @a gc 255 * @param gc_cls closure for @a gc
258 * @return evaluation result for the local replies 256 * @return evaluation result for the local replies
@@ -262,8 +260,7 @@ GDS_DATACACHE_handle_get (const struct GNUNET_HashCode *key,
262 enum GNUNET_BLOCK_Type type, 260 enum GNUNET_BLOCK_Type type,
263 const void *xquery, 261 const void *xquery,
264 size_t xquery_size, 262 size_t xquery_size,
265 struct GNUNET_CONTAINER_BloomFilter **reply_bf, 263 struct GNUNET_BLOCK_Group *bg,
266 uint32_t reply_bf_mutator,
267 GDS_DATACACHE_GetCallback gc, 264 GDS_DATACACHE_GetCallback gc,
268 void *gc_cls) 265 void *gc_cls)
269{ 266{
@@ -280,8 +277,7 @@ GDS_DATACACHE_handle_get (const struct GNUNET_HashCode *key,
280 ctx.key = *key; 277 ctx.key = *key;
281 ctx.xquery = xquery; 278 ctx.xquery = xquery;
282 ctx.xquery_size = xquery_size; 279 ctx.xquery_size = xquery_size;
283 ctx.reply_bf = reply_bf; 280 ctx.bg = bg;
284 ctx.reply_bf_mutator = reply_bf_mutator;
285 ctx.gc = gc; 281 ctx.gc = gc;
286 ctx.gc_cls = gc_cls; 282 ctx.gc_cls = gc_cls;
287 r = GNUNET_DATACACHE_get (datacache, 283 r = GNUNET_DATACACHE_get (datacache,
diff --git a/src/dht/gnunet-service-dht_datacache.h b/src/dht/gnunet-service-dht_datacache.h
index 5069883c7..ff6ae23da 100644
--- a/src/dht/gnunet-service-dht_datacache.h
+++ b/src/dht/gnunet-service-dht_datacache.h
@@ -87,8 +87,7 @@ typedef void
87 * @param type requested data type 87 * @param type requested data type
88 * @param xquery extended query 88 * @param xquery extended query
89 * @param xquery_size number of bytes in xquery 89 * @param xquery_size number of bytes in xquery
90 * @param reply_bf where the reply bf is (to be) stored, possibly updated!, can be NULL 90 * @param bg block group to use for evaluation of replies
91 * @param reply_bf_mutator mutation value for reply_bf
92 * @param gc function to call on the results 91 * @param gc function to call on the results
93 * @param gc_cls closure for @a gc 92 * @param gc_cls closure for @a gc
94 * @return evaluation result for the local replies 93 * @return evaluation result for the local replies
@@ -98,8 +97,7 @@ GDS_DATACACHE_handle_get (const struct GNUNET_HashCode *key,
98 enum GNUNET_BLOCK_Type type, 97 enum GNUNET_BLOCK_Type type,
99 const void *xquery, 98 const void *xquery,
100 size_t xquery_size, 99 size_t xquery_size,
101 struct GNUNET_CONTAINER_BloomFilter **reply_bf, 100 struct GNUNET_BLOCK_Group *bg,
102 uint32_t reply_bf_mutator,
103 GDS_DATACACHE_GetCallback gc, 101 GDS_DATACACHE_GetCallback gc,
104 void *gc_cls); 102 void *gc_cls);
105 103
diff --git a/src/dht/gnunet-service-dht_neighbours.c b/src/dht/gnunet-service-dht_neighbours.c
index 20bdc0ce4..0309bea88 100644
--- a/src/dht/gnunet-service-dht_neighbours.c
+++ b/src/dht/gnunet-service-dht_neighbours.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-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
@@ -49,6 +49,11 @@
49#define LOG_TRAFFIC(kind,...) GNUNET_log_from (kind, "dht-traffic",__VA_ARGS__) 49#define LOG_TRAFFIC(kind,...) GNUNET_log_from (kind, "dht-traffic",__VA_ARGS__)
50 50
51/** 51/**
52 * Enable slow sanity checks to debug issues.
53 */
54#define SANITY_CHECKS 1
55
56/**
52 * How many buckets will we allow total. 57 * How many buckets will we allow total.
53 */ 58 */
54#define MAX_BUCKETS sizeof (struct GNUNET_HashCode) * 8 59#define MAX_BUCKETS sizeof (struct GNUNET_HashCode) * 8
@@ -597,27 +602,10 @@ update_connect_preferences ()
597 602
598 603
599/** 604/**
600 * Closure for #add_known_to_bloom().
601 */
602struct BloomConstructorContext
603{
604 /**
605 * Bloom filter under construction.
606 */
607 struct GNUNET_CONTAINER_BloomFilter *bloom;
608
609 /**
610 * Mutator to use.
611 */
612 uint32_t bf_mutator;
613};
614
615
616/**
617 * Add each of the peers we already know to the bloom filter of 605 * Add each of the peers we already know to the bloom filter of
618 * the request so that we don't get duplicate HELLOs. 606 * the request so that we don't get duplicate HELLOs.
619 * 607 *
620 * @param cls the 'struct BloomConstructorContext'. 608 * @param cls the `struct GNUNET_BLOCK_Group`
621 * @param key peer identity to add to the bloom filter 609 * @param key peer identity to add to the bloom filter
622 * @param value value the peer information (unused) 610 * @param value value the peer information (unused)
623 * @return #GNUNET_YES (we should continue to iterate) 611 * @return #GNUNET_YES (we should continue to iterate)
@@ -627,22 +615,18 @@ add_known_to_bloom (void *cls,
627 const struct GNUNET_PeerIdentity *key, 615 const struct GNUNET_PeerIdentity *key,
628 void *value) 616 void *value)
629{ 617{
630 struct BloomConstructorContext *ctx = cls; 618 struct GNUNET_BLOCK_Group *bg = cls;
631 struct GNUNET_HashCode key_hash; 619 struct GNUNET_HashCode key_hash;
632 struct GNUNET_HashCode mh;
633 620
634 GNUNET_CRYPTO_hash (key, 621 GNUNET_CRYPTO_hash (key,
635 sizeof (struct GNUNET_PeerIdentity), 622 sizeof (struct GNUNET_PeerIdentity),
636 &key_hash); 623 &key_hash);
637 GNUNET_BLOCK_mingle_hash (&key_hash, 624 GNUNET_BLOCK_group_set_seen (bg,
638 ctx->bf_mutator, 625 &key_hash,
639 &mh); 626 1);
640 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 627 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
641 "Adding known peer (%s) to bloomfilter for FIND PEER with mutation %u\n", 628 "Adding known peer (%s) to bloomfilter for FIND PEER\n",
642 GNUNET_i2s (key), 629 GNUNET_i2s (key));
643 ctx->bf_mutator);
644 GNUNET_CONTAINER_bloomfilter_add (ctx->bloom,
645 &mh);
646 return GNUNET_YES; 630 return GNUNET_YES;
647} 631}
648 632
@@ -658,7 +642,7 @@ static void
658send_find_peer_message (void *cls) 642send_find_peer_message (void *cls)
659{ 643{
660 struct GNUNET_TIME_Relative next_send_time; 644 struct GNUNET_TIME_Relative next_send_time;
661 struct BloomConstructorContext bcc; 645 struct GNUNET_BLOCK_Group *bg;
662 struct GNUNET_CONTAINER_BloomFilter *peer_bf; 646 struct GNUNET_CONTAINER_BloomFilter *peer_bf;
663 647
664 find_peer_task = NULL; 648 find_peer_task = NULL;
@@ -672,30 +656,38 @@ send_find_peer_message (void *cls)
672 newly_found_peers = 0; 656 newly_found_peers = 0;
673 return; 657 return;
674 } 658 }
675 bcc.bf_mutator = 659 bg = GNUNET_BLOCK_group_create (GDS_block_context,
676 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 660 GNUNET_BLOCK_TYPE_DHT_HELLO,
677 UINT32_MAX); 661 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
678 bcc.bloom = 662 UINT32_MAX),
679 GNUNET_CONTAINER_bloomfilter_init (NULL, DHT_BLOOM_SIZE, 663 NULL,
680 GNUNET_CONSTANTS_BLOOMFILTER_K); 664 0,
665 "filter-size",
666 DHT_BLOOM_SIZE,
667 NULL);
681 GNUNET_CONTAINER_multipeermap_iterate (all_connected_peers, 668 GNUNET_CONTAINER_multipeermap_iterate (all_connected_peers,
682 &add_known_to_bloom, 669 &add_known_to_bloom,
683 &bcc); 670 bg);
684 GNUNET_STATISTICS_update (GDS_stats, 671 GNUNET_STATISTICS_update (GDS_stats,
685 gettext_noop ("# FIND PEER messages initiated"), 672 gettext_noop ("# FIND PEER messages initiated"),
686 1, 673 1,
687 GNUNET_NO); 674 GNUNET_NO);
688 peer_bf = 675 peer_bf
689 GNUNET_CONTAINER_bloomfilter_init (NULL, DHT_BLOOM_SIZE, 676 = GNUNET_CONTAINER_bloomfilter_init (NULL,
677 DHT_BLOOM_SIZE,
690 GNUNET_CONSTANTS_BLOOMFILTER_K); 678 GNUNET_CONSTANTS_BLOOMFILTER_K);
691 // FIXME: pass priority!? 679 // FIXME: pass priority!?
692 GDS_NEIGHBOURS_handle_get (GNUNET_BLOCK_TYPE_DHT_HELLO, 680 GDS_NEIGHBOURS_handle_get (GNUNET_BLOCK_TYPE_DHT_HELLO,
693 GNUNET_DHT_RO_FIND_PEER, 681 GNUNET_DHT_RO_FIND_PEER | GNUNET_DHT_RO_RECORD_ROUTE,
694 FIND_PEER_REPLICATION_LEVEL, 0, 682 FIND_PEER_REPLICATION_LEVEL,
695 &my_identity_hash, NULL, 0, bcc.bloom, 683 0,
696 bcc.bf_mutator, peer_bf); 684 &my_identity_hash,
685 NULL,
686 0,
687 bg,
688 peer_bf);
697 GNUNET_CONTAINER_bloomfilter_free (peer_bf); 689 GNUNET_CONTAINER_bloomfilter_free (peer_bf);
698 GNUNET_CONTAINER_bloomfilter_free (bcc.bloom); 690 GNUNET_BLOCK_group_destroy (bg);
699 /* schedule next round */ 691 /* schedule next round */
700 next_send_time.rel_value_us = 692 next_send_time.rel_value_us =
701 DHT_MINIMUM_FIND_PEER_INTERVAL.rel_value_us + 693 DHT_MINIMUM_FIND_PEER_INTERVAL.rel_value_us +
@@ -1031,10 +1023,10 @@ select_peer (const struct GNUNET_HashCode *key,
1031 count = 0; 1023 count = 0;
1032 while ((pos != NULL) && (count < bucket_size)) 1024 while ((pos != NULL) && (count < bucket_size))
1033 { 1025 {
1034 if ((bloom == NULL) || 1026 if ( (NULL == bloom) ||
1035 (GNUNET_NO == 1027 (GNUNET_NO ==
1036 GNUNET_CONTAINER_bloomfilter_test (bloom, 1028 GNUNET_CONTAINER_bloomfilter_test (bloom,
1037 &pos->phash))) 1029 &pos->phash)))
1038 { 1030 {
1039 dist = get_distance (key, 1031 dist = get_distance (key,
1040 &pos->phash); 1032 &pos->phash);
@@ -1068,8 +1060,14 @@ select_peer (const struct GNUNET_HashCode *key,
1068 } 1060 }
1069 if (NULL == chosen) 1061 if (NULL == chosen)
1070 GNUNET_STATISTICS_update (GDS_stats, 1062 GNUNET_STATISTICS_update (GDS_stats,
1071 gettext_noop ("# Peer selection failed"), 1, 1063 gettext_noop ("# Peer selection failed"),
1064 1,
1072 GNUNET_NO); 1065 GNUNET_NO);
1066 else
1067 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1068 "Selected peer `%s' in greedy routing for %s\n",
1069 GNUNET_i2s (chosen->id),
1070 GNUNET_h2s (key));
1073 return chosen; 1071 return chosen;
1074 } 1072 }
1075 1073
@@ -1079,12 +1077,12 @@ select_peer (const struct GNUNET_HashCode *key,
1079 for (bc = 0; bc <= closest_bucket; bc++) 1077 for (bc = 0; bc <= closest_bucket; bc++)
1080 { 1078 {
1081 pos = k_buckets[bc].head; 1079 pos = k_buckets[bc].head;
1082 while ((pos != NULL) && (count < bucket_size)) 1080 while ( (NULL != pos) && (count < bucket_size) )
1083 { 1081 {
1084 if ((bloom != NULL) && 1082 if ( (NULL != bloom) &&
1085 (GNUNET_YES == 1083 (GNUNET_YES ==
1086 GNUNET_CONTAINER_bloomfilter_test (bloom, 1084 GNUNET_CONTAINER_bloomfilter_test (bloom,
1087 &pos->phash))) 1085 &pos->phash)) )
1088 { 1086 {
1089 GNUNET_STATISTICS_update (GDS_stats, 1087 GNUNET_STATISTICS_update (GDS_stats,
1090 gettext_noop 1088 gettext_noop
@@ -1124,7 +1122,13 @@ select_peer (const struct GNUNET_HashCode *key,
1124 continue; /* Ignore bloomfiltered peers */ 1122 continue; /* Ignore bloomfiltered peers */
1125 } 1123 }
1126 if (0 == selected--) 1124 if (0 == selected--)
1125 {
1126 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1127 "Selected peer `%s' in random routing for %s\n",
1128 GNUNET_i2s (pos->id),
1129 GNUNET_h2s (key));
1127 return pos; 1130 return pos;
1131 }
1128 } 1132 }
1129 } 1133 }
1130 GNUNET_break (0); 1134 GNUNET_break (0);
@@ -1169,7 +1173,9 @@ get_target_peers (const struct GNUNET_HashCode *key,
1169 struct PeerInfo *); 1173 struct PeerInfo *);
1170 for (off = 0; off < ret; off++) 1174 for (off = 0; off < ret; off++)
1171 { 1175 {
1172 nxt = select_peer (key, bloom, hop_count); 1176 nxt = select_peer (key,
1177 bloom,
1178 hop_count);
1173 if (NULL == nxt) 1179 if (NULL == nxt)
1174 break; 1180 break;
1175 rtargets[off] = nxt; 1181 rtargets[off] = nxt;
@@ -1250,7 +1256,8 @@ GDS_NEIGHBOURS_handle_put (enum GNUNET_BLOCK_Type type,
1250 "Adding myself (%s) to PUT bloomfilter for %s\n", 1256 "Adding myself (%s) to PUT bloomfilter for %s\n",
1251 GNUNET_i2s (&my_identity), 1257 GNUNET_i2s (&my_identity),
1252 GNUNET_h2s (key)); 1258 GNUNET_h2s (key));
1253 GNUNET_CONTAINER_bloomfilter_add (bf, &my_identity_hash); 1259 GNUNET_CONTAINER_bloomfilter_add (bf,
1260 &my_identity_hash);
1254 GNUNET_STATISTICS_update (GDS_stats, 1261 GNUNET_STATISTICS_update (GDS_stats,
1255 gettext_noop ("# PUT requests routed"), 1262 gettext_noop ("# PUT requests routed"),
1256 1, 1263 1,
@@ -1352,8 +1359,7 @@ GDS_NEIGHBOURS_handle_put (enum GNUNET_BLOCK_Type type,
1352 * @param key key for the content 1359 * @param key key for the content
1353 * @param xquery extended query 1360 * @param xquery extended query
1354 * @param xquery_size number of bytes in @a xquery 1361 * @param xquery_size number of bytes in @a xquery
1355 * @param reply_bf bloomfilter to filter duplicates 1362 * @param bg group to use for filtering replies
1356 * @param reply_bf_mutator mutator for @a reply_bf
1357 * @param peer_bf filter for peers not to select (again) 1363 * @param peer_bf filter for peers not to select (again)
1358 * @return #GNUNET_OK if the request was forwarded, #GNUNET_NO if not 1364 * @return #GNUNET_OK if the request was forwarded, #GNUNET_NO if not
1359 */ 1365 */
@@ -1361,14 +1367,14 @@ int
1361GDS_NEIGHBOURS_handle_get (enum GNUNET_BLOCK_Type type, 1367GDS_NEIGHBOURS_handle_get (enum GNUNET_BLOCK_Type type,
1362 enum GNUNET_DHT_RouteOption options, 1368 enum GNUNET_DHT_RouteOption options,
1363 uint32_t desired_replication_level, 1369 uint32_t desired_replication_level,
1364 uint32_t hop_count, const struct GNUNET_HashCode * key, 1370 uint32_t hop_count,
1365 const void *xquery, size_t xquery_size, 1371 const struct GNUNET_HashCode *key,
1366 const struct GNUNET_CONTAINER_BloomFilter *reply_bf, 1372 const void *xquery,
1367 uint32_t reply_bf_mutator, 1373 size_t xquery_size,
1374 struct GNUNET_BLOCK_Group *bg,
1368 struct GNUNET_CONTAINER_BloomFilter *peer_bf) 1375 struct GNUNET_CONTAINER_BloomFilter *peer_bf)
1369{ 1376{
1370 unsigned int target_count; 1377 unsigned int target_count;
1371 unsigned int i;
1372 struct PeerInfo **targets; 1378 struct PeerInfo **targets;
1373 struct PeerInfo *target; 1379 struct PeerInfo *target;
1374 struct GNUNET_MQ_Envelope *env; 1380 struct GNUNET_MQ_Envelope *env;
@@ -1376,7 +1382,9 @@ GDS_NEIGHBOURS_handle_get (enum GNUNET_BLOCK_Type type,
1376 struct PeerGetMessage *pgm; 1382 struct PeerGetMessage *pgm;
1377 char *xq; 1383 char *xq;
1378 size_t reply_bf_size; 1384 size_t reply_bf_size;
1385 void *reply_bf;
1379 unsigned int skip_count; 1386 unsigned int skip_count;
1387 uint32_t bf_nonce;
1380 1388
1381 GNUNET_assert (NULL != peer_bf); 1389 GNUNET_assert (NULL != peer_bf);
1382 GNUNET_STATISTICS_update (GDS_stats, 1390 GNUNET_STATISTICS_update (GDS_stats,
@@ -1403,11 +1411,22 @@ GDS_NEIGHBOURS_handle_get (enum GNUNET_BLOCK_Type type,
1403 GNUNET_i2s (&my_identity)); 1411 GNUNET_i2s (&my_identity));
1404 return GNUNET_NO; 1412 return GNUNET_NO;
1405 } 1413 }
1406 reply_bf_size = GNUNET_CONTAINER_bloomfilter_get_size (reply_bf); 1414 if (GNUNET_OK !=
1415 GNUNET_BLOCK_group_serialize (bg,
1416 &bf_nonce,
1417 &reply_bf,
1418 &reply_bf_size))
1419 {
1420 reply_bf = NULL;
1421 reply_bf_size = 0;
1422 bf_nonce = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
1423 UINT32_MAX);
1424 }
1407 msize = xquery_size + reply_bf_size; 1425 msize = xquery_size + reply_bf_size;
1408 if (msize + sizeof (struct PeerGetMessage) >= GNUNET_SERVER_MAX_MESSAGE_SIZE) 1426 if (msize + sizeof (struct PeerGetMessage) >= GNUNET_MAX_MESSAGE_SIZE)
1409 { 1427 {
1410 GNUNET_break (0); 1428 GNUNET_break (0);
1429 GNUNET_free_non_null (reply_bf);
1411 GNUNET_free (targets); 1430 GNUNET_free (targets);
1412 return GNUNET_NO; 1431 return GNUNET_NO;
1413 } 1432 }
@@ -1417,7 +1436,7 @@ GDS_NEIGHBOURS_handle_get (enum GNUNET_BLOCK_Type type,
1417 GNUNET_NO); 1436 GNUNET_NO);
1418 /* forward request */ 1437 /* forward request */
1419 skip_count = 0; 1438 skip_count = 0;
1420 for (i = 0; i < target_count; i++) 1439 for (unsigned int i = 0; i < target_count; i++)
1421 { 1440 {
1422 target = targets[i]; 1441 target = targets[i];
1423 if (GNUNET_MQ_get_length (target->mq) >= MAXIMUM_PENDING_PER_PEER) 1442 if (GNUNET_MQ_get_length (target->mq) >= MAXIMUM_PENDING_PER_PEER)
@@ -1442,7 +1461,7 @@ GDS_NEIGHBOURS_handle_get (enum GNUNET_BLOCK_Type type,
1442 pgm->hop_count = htonl (hop_count + 1); 1461 pgm->hop_count = htonl (hop_count + 1);
1443 pgm->desired_replication_level = htonl (desired_replication_level); 1462 pgm->desired_replication_level = htonl (desired_replication_level);
1444 pgm->xquery_size = htonl (xquery_size); 1463 pgm->xquery_size = htonl (xquery_size);
1445 pgm->bf_mutator = reply_bf_mutator; 1464 pgm->bf_mutator = bf_nonce;
1446 GNUNET_break (GNUNET_YES == 1465 GNUNET_break (GNUNET_YES ==
1447 GNUNET_CONTAINER_bloomfilter_test (peer_bf, 1466 GNUNET_CONTAINER_bloomfilter_test (peer_bf,
1448 &target->phash)); 1467 &target->phash));
@@ -1455,16 +1474,14 @@ GDS_NEIGHBOURS_handle_get (enum GNUNET_BLOCK_Type type,
1455 GNUNET_memcpy (xq, 1474 GNUNET_memcpy (xq,
1456 xquery, 1475 xquery,
1457 xquery_size); 1476 xquery_size);
1458 if (NULL != reply_bf) 1477 GNUNET_memcpy (&xq[xquery_size],
1459 GNUNET_assert (GNUNET_OK == 1478 reply_bf,
1460 GNUNET_CONTAINER_bloomfilter_get_raw_data (reply_bf, 1479 reply_bf_size);
1461 &xq
1462 [xquery_size],
1463 reply_bf_size));
1464 GNUNET_MQ_send (target->mq, 1480 GNUNET_MQ_send (target->mq,
1465 env); 1481 env);
1466 } 1482 }
1467 GNUNET_free (targets); 1483 GNUNET_free (targets);
1484 GNUNET_free_non_null (reply_bf);
1468 return (skip_count < target_count) ? GNUNET_OK : GNUNET_NO; 1485 return (skip_count < target_count) ? GNUNET_OK : GNUNET_NO;
1469} 1486}
1470 1487
@@ -1505,12 +1522,12 @@ GDS_NEIGHBOURS_handle_reply (const struct GNUNET_PeerIdentity *target,
1505 1522
1506 msize = data_size + (get_path_length + put_path_length) * 1523 msize = data_size + (get_path_length + put_path_length) *
1507 sizeof (struct GNUNET_PeerIdentity); 1524 sizeof (struct GNUNET_PeerIdentity);
1508 if ((msize + sizeof (struct PeerResultMessage) >= GNUNET_SERVER_MAX_MESSAGE_SIZE) || 1525 if ((msize + sizeof (struct PeerResultMessage) >= GNUNET_MAX_MESSAGE_SIZE) ||
1509 (get_path_length > 1526 (get_path_length >
1510 GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)) || 1527 GNUNET_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)) ||
1511 (put_path_length > 1528 (put_path_length >
1512 GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)) || 1529 GNUNET_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)) ||
1513 (data_size > GNUNET_SERVER_MAX_MESSAGE_SIZE)) 1530 (data_size > GNUNET_MAX_MESSAGE_SIZE))
1514 { 1531 {
1515 GNUNET_break (0); 1532 GNUNET_break (0);
1516 return; 1533 return;
@@ -1610,7 +1627,7 @@ check_dht_p2p_put (void *cls,
1610 sizeof (struct PeerPutMessage) + 1627 sizeof (struct PeerPutMessage) +
1611 putlen * sizeof (struct GNUNET_PeerIdentity)) || 1628 putlen * sizeof (struct GNUNET_PeerIdentity)) ||
1612 (putlen > 1629 (putlen >
1613 GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity))) 1630 GNUNET_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)))
1614 { 1631 {
1615 GNUNET_break_op (0); 1632 GNUNET_break_op (0);
1616 return GNUNET_SYSERR; 1633 return GNUNET_SYSERR;
@@ -1663,10 +1680,13 @@ handle_dht_p2p_put (void *cls,
1663 if (GNUNET_YES == log_route_details_stderr) 1680 if (GNUNET_YES == log_route_details_stderr)
1664 { 1681 {
1665 char *tmp; 1682 char *tmp;
1683 char *pp;
1666 1684
1685 pp = GNUNET_STRINGS_pp2s (put_path,
1686 putlen);
1667 tmp = GNUNET_strdup (GNUNET_i2s (&my_identity)); 1687 tmp = GNUNET_strdup (GNUNET_i2s (&my_identity));
1668 LOG_TRAFFIC (GNUNET_ERROR_TYPE_DEBUG, 1688 LOG_TRAFFIC (GNUNET_ERROR_TYPE_DEBUG,
1669 "R5N PUT %s: %s->%s (%u, %u=>%u)\n", 1689 "R5N PUT %s: %s->%s (%u, %u=>%u, PP: %s)\n",
1670 GNUNET_h2s (&put->key), 1690 GNUNET_h2s (&put->key),
1671 GNUNET_i2s (peer->id), 1691 GNUNET_i2s (peer->id),
1672 tmp, 1692 tmp,
@@ -1674,8 +1694,9 @@ handle_dht_p2p_put (void *cls,
1674 GNUNET_CRYPTO_hash_matching_bits (&peer->phash, 1694 GNUNET_CRYPTO_hash_matching_bits (&peer->phash,
1675 &put->key), 1695 &put->key),
1676 GNUNET_CRYPTO_hash_matching_bits (&my_identity_hash, 1696 GNUNET_CRYPTO_hash_matching_bits (&my_identity_hash,
1677 &put->key) 1697 &put->key),
1678 ); 1698 pp);
1699 GNUNET_free (pp);
1679 GNUNET_free (tmp); 1700 GNUNET_free (tmp);
1680 } 1701 }
1681 switch (GNUNET_BLOCK_get_key 1702 switch (GNUNET_BLOCK_get_key
@@ -1712,11 +1733,12 @@ handle_dht_p2p_put (void *cls,
1712 { 1733 {
1713 switch (GNUNET_BLOCK_evaluate (GDS_block_context, 1734 switch (GNUNET_BLOCK_evaluate (GDS_block_context,
1714 ntohl (put->type), 1735 ntohl (put->type),
1736 NULL, /* query group */
1715 GNUNET_BLOCK_EO_NONE, 1737 GNUNET_BLOCK_EO_NONE,
1716 NULL, /* query */ 1738 NULL, /* query */
1717 NULL, 0, /* bloom filer */
1718 NULL, 0, /* xquery */ 1739 NULL, 0, /* xquery */
1719 payload, payload_size)) 1740 payload,
1741 payload_size))
1720 { 1742 {
1721 case GNUNET_BLOCK_EVALUATION_OK_MORE: 1743 case GNUNET_BLOCK_EVALUATION_OK_MORE:
1722 case GNUNET_BLOCK_EVALUATION_OK_LAST: 1744 case GNUNET_BLOCK_EVALUATION_OK_LAST:
@@ -1746,6 +1768,20 @@ handle_dht_p2p_put (void *cls,
1746 /* extend 'put path' by sender */ 1768 /* extend 'put path' by sender */
1747 if (0 != (options & GNUNET_DHT_RO_RECORD_ROUTE)) 1769 if (0 != (options & GNUNET_DHT_RO_RECORD_ROUTE))
1748 { 1770 {
1771#if SANITY_CHECKS
1772 for (unsigned int i=0;i<=putlen;i++)
1773 {
1774 for (unsigned int j=0;j<i;j++)
1775 {
1776 GNUNET_break (0 != memcmp (&pp[i],
1777 &pp[j],
1778 sizeof (struct GNUNET_PeerIdentity)));
1779 }
1780 GNUNET_break (0 != memcmp (&pp[i],
1781 peer->id,
1782 sizeof (struct GNUNET_PeerIdentity)));
1783 }
1784#endif
1749 GNUNET_memcpy (pp, 1785 GNUNET_memcpy (pp,
1750 put_path, 1786 put_path,
1751 putlen * sizeof (struct GNUNET_PeerIdentity)); 1787 putlen * sizeof (struct GNUNET_PeerIdentity));
@@ -1811,39 +1847,38 @@ handle_dht_p2p_put (void *cls,
1811 * 1847 *
1812 * @param sender sender of the FIND PEER request 1848 * @param sender sender of the FIND PEER request
1813 * @param key peers close to this key are desired 1849 * @param key peers close to this key are desired
1814 * @param bf peers matching this bf are excluded 1850 * @param bg group for filtering peers
1815 * @param bf_mutator mutator for bf
1816 */ 1851 */
1817static void 1852static void
1818handle_find_peer (const struct GNUNET_PeerIdentity *sender, 1853handle_find_peer (const struct GNUNET_PeerIdentity *sender,
1819 const struct GNUNET_HashCode *key, 1854 const struct GNUNET_HashCode *key,
1820 struct GNUNET_CONTAINER_BloomFilter *bf, 1855 struct GNUNET_BLOCK_Group *bg)
1821 uint32_t bf_mutator)
1822{ 1856{
1823 int bucket_idx; 1857 int bucket_idx;
1824 struct PeerBucket *bucket; 1858 struct PeerBucket *bucket;
1825 struct PeerInfo *peer; 1859 struct PeerInfo *peer;
1826 unsigned int choice; 1860 unsigned int choice;
1827 struct GNUNET_HashCode mhash;
1828 const struct GNUNET_HELLO_Message *hello; 1861 const struct GNUNET_HELLO_Message *hello;
1862 size_t hello_size;
1829 1863
1830 /* first, check about our own HELLO */ 1864 /* first, check about our own HELLO */
1831 if (NULL != GDS_my_hello) 1865 if (NULL != GDS_my_hello)
1832 { 1866 {
1833 GNUNET_BLOCK_mingle_hash (&my_identity_hash, 1867 hello_size = GNUNET_HELLO_size ((const struct GNUNET_HELLO_Message *) GDS_my_hello);
1834 bf_mutator, 1868 GNUNET_break (hello_size >= sizeof (struct GNUNET_MessageHeader));
1835 &mhash); 1869 if (GNUNET_BLOCK_EVALUATION_OK_MORE ==
1836 if ((NULL == bf) || 1870 GNUNET_BLOCK_evaluate (GDS_block_context,
1837 (GNUNET_YES != GNUNET_CONTAINER_bloomfilter_test (bf, &mhash))) 1871 GNUNET_BLOCK_TYPE_DHT_HELLO,
1872 bg,
1873 GNUNET_BLOCK_EO_LOCAL_SKIP_CRYPTO,
1874 &my_identity_hash,
1875 NULL, 0,
1876 GDS_my_hello,
1877 hello_size))
1838 { 1878 {
1839 size_t hello_size;
1840
1841 hello_size = GNUNET_HELLO_size ((const struct GNUNET_HELLO_Message *) GDS_my_hello);
1842 GNUNET_break (hello_size >= sizeof (struct GNUNET_MessageHeader));
1843 GDS_NEIGHBOURS_handle_reply (sender, 1879 GDS_NEIGHBOURS_handle_reply (sender,
1844 GNUNET_BLOCK_TYPE_DHT_HELLO, 1880 GNUNET_BLOCK_TYPE_DHT_HELLO,
1845 GNUNET_TIME_relative_to_absolute 1881 GNUNET_TIME_relative_to_absolute (hello_expiration),
1846 (hello_expiration),
1847 key, 1882 key,
1848 0, 1883 0,
1849 NULL, 1884 NULL,
@@ -1894,18 +1929,21 @@ handle_find_peer (const struct GNUNET_PeerIdentity *sender,
1894 do 1929 do
1895 { 1930 {
1896 peer = peer->next; 1931 peer = peer->next;
1897 if (choice-- == 0) 1932 if (0 == choice--)
1898 return; /* no non-masked peer available */ 1933 return; /* no non-masked peer available */
1899 if (NULL == peer) 1934 if (NULL == peer)
1900 peer = bucket->head; 1935 peer = bucket->head;
1901 GNUNET_BLOCK_mingle_hash (&peer->phash,
1902 bf_mutator,
1903 &mhash);
1904 hello = GDS_HELLO_get (peer->id); 1936 hello = GDS_HELLO_get (peer->id);
1905 } while ( (hello == NULL) || 1937 } while ( (NULL == hello) ||
1906 (GNUNET_YES == 1938 (GNUNET_BLOCK_EVALUATION_OK_MORE !=
1907 GNUNET_CONTAINER_bloomfilter_test (bf, 1939 GNUNET_BLOCK_evaluate (GDS_block_context,
1908 &mhash)) ); 1940 GNUNET_BLOCK_TYPE_DHT_HELLO,
1941 bg,
1942 GNUNET_BLOCK_EO_LOCAL_SKIP_CRYPTO,
1943 &peer->phash,
1944 NULL, 0,
1945 hello,
1946 (hello_size = GNUNET_HELLO_size (hello)))) );
1909 GDS_NEIGHBOURS_handle_reply (sender, 1947 GDS_NEIGHBOURS_handle_reply (sender,
1910 GNUNET_BLOCK_TYPE_DHT_HELLO, 1948 GNUNET_BLOCK_TYPE_DHT_HELLO,
1911 GNUNET_TIME_relative_to_absolute 1949 GNUNET_TIME_relative_to_absolute
@@ -1916,14 +1954,14 @@ handle_find_peer (const struct GNUNET_PeerIdentity *sender,
1916 0, 1954 0,
1917 NULL, 1955 NULL,
1918 hello, 1956 hello,
1919 GNUNET_HELLO_size (hello)); 1957 hello_size);
1920} 1958}
1921 1959
1922 1960
1923/** 1961/**
1924 * Handle a result from local datacache for a GET operation. 1962 * Handle a result from local datacache for a GET operation.
1925 * 1963 *
1926 * @param cls the `struct ClientHandle` of the client doing the query 1964 * @param cls the `struct PeerInfo` for which this is a reply
1927 * @param type type of the block 1965 * @param type type of the block
1928 * @param expiration_time when does the content expire 1966 * @param expiration_time when does the content expire
1929 * @param key key for the content 1967 * @param key key for the content
@@ -1946,15 +1984,23 @@ handle_local_result (void *cls,
1946 const void *data, 1984 const void *data,
1947 size_t data_size) 1985 size_t data_size)
1948{ 1986{
1949 // FIXME: we can probably do better here by 1987 struct PeerInfo *peer = cls;
1950 // passing the peer that did the query in the closure... 1988 char *pp;
1951 GDS_ROUTING_process (NULL, 1989
1952 type, 1990 pp = GNUNET_STRINGS_pp2s (put_path,
1953 expiration_time, 1991 put_path_length);
1954 key, 1992 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1955 put_path_length, put_path, 1993 "Found local result for %s (PP: %s)\n",
1956 0, NULL, 1994 GNUNET_h2s (key),
1957 data, data_size); 1995 pp);
1996 GNUNET_free (pp);
1997 GDS_NEIGHBOURS_handle_reply (peer->id,
1998 type,
1999 expiration_time,
2000 key,
2001 put_path_length, put_path,
2002 get_path_length, get_path,
2003 data, data_size);
1958} 2004}
1959 2005
1960 2006
@@ -2000,16 +2046,11 @@ handle_dht_p2p_get (void *cls,
2000 enum GNUNET_BLOCK_Type type; 2046 enum GNUNET_BLOCK_Type type;
2001 enum GNUNET_DHT_RouteOption options; 2047 enum GNUNET_DHT_RouteOption options;
2002 enum GNUNET_BLOCK_EvaluationResult eval; 2048 enum GNUNET_BLOCK_EvaluationResult eval;
2003 struct GNUNET_CONTAINER_BloomFilter *reply_bf; 2049 struct GNUNET_BLOCK_Group *bg;
2004 struct GNUNET_CONTAINER_BloomFilter *peer_bf; 2050 struct GNUNET_CONTAINER_BloomFilter *peer_bf;
2005 const char *xquery; 2051 const char *xquery;
2006 int forwarded; 2052 int forwarded;
2007 2053
2008 if (NULL == peer)
2009 {
2010 GNUNET_break (0);
2011 return;
2012 }
2013 /* parse and validate message */ 2054 /* parse and validate message */
2014 msize = ntohs (get->header.size); 2055 msize = ntohs (get->header.size);
2015 xquery_size = ntohl (get->xquery_size); 2056 xquery_size = ntohl (get->xquery_size);
@@ -2017,7 +2058,6 @@ handle_dht_p2p_get (void *cls,
2017 type = ntohl (get->type); 2058 type = ntohl (get->type);
2018 options = ntohl (get->options); 2059 options = ntohl (get->options);
2019 xquery = (const char *) &get[1]; 2060 xquery = (const char *) &get[1];
2020 reply_bf = NULL;
2021 GNUNET_STATISTICS_update (GDS_stats, 2061 GNUNET_STATISTICS_update (GDS_stats,
2022 gettext_noop ("# P2P GET requests received"), 2062 gettext_noop ("# P2P GET requests received"),
2023 1, 2063 1,
@@ -2045,19 +2085,12 @@ handle_dht_p2p_get (void *cls,
2045 xquery); 2085 xquery);
2046 GNUNET_free (tmp); 2086 GNUNET_free (tmp);
2047 } 2087 }
2048 2088 eval
2049 if (reply_bf_size > 0) 2089 = GNUNET_BLOCK_evaluate (GDS_block_context,
2050 reply_bf =
2051 GNUNET_CONTAINER_bloomfilter_init (&xquery[xquery_size],
2052 reply_bf_size,
2053 GNUNET_CONSTANTS_BLOOMFILTER_K);
2054 eval =
2055 GNUNET_BLOCK_evaluate (GDS_block_context,
2056 type, 2090 type,
2091 NULL,
2057 GNUNET_BLOCK_EO_NONE, 2092 GNUNET_BLOCK_EO_NONE,
2058 &get->key, 2093 &get->key,
2059 &reply_bf,
2060 get->bf_mutator,
2061 xquery, 2094 xquery,
2062 xquery_size, 2095 xquery_size,
2063 NULL, 2096 NULL,
@@ -2066,8 +2099,6 @@ handle_dht_p2p_get (void *cls,
2066 { 2099 {
2067 /* request invalid or block type not supported */ 2100 /* request invalid or block type not supported */
2068 GNUNET_break_op (eval == GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED); 2101 GNUNET_break_op (eval == GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED);
2069 if (NULL != reply_bf)
2070 GNUNET_CONTAINER_bloomfilter_free (reply_bf);
2071 return; 2102 return;
2072 } 2103 }
2073 peer_bf = GNUNET_CONTAINER_bloomfilter_init (get->bloomfilter, 2104 peer_bf = GNUNET_CONTAINER_bloomfilter_init (get->bloomfilter,
@@ -2076,15 +2107,14 @@ handle_dht_p2p_get (void *cls,
2076 GNUNET_break_op (GNUNET_YES == 2107 GNUNET_break_op (GNUNET_YES ==
2077 GNUNET_CONTAINER_bloomfilter_test (peer_bf, 2108 GNUNET_CONTAINER_bloomfilter_test (peer_bf,
2078 &peer->phash)); 2109 &peer->phash));
2079 /* remember request for routing replies */ 2110 bg = GNUNET_BLOCK_group_create (GDS_block_context,
2080 GDS_ROUTING_add (peer->id, 2111 type,
2081 type, 2112 get->bf_mutator,
2082 options, 2113 &xquery[xquery_size],
2083 &get->key, 2114 reply_bf_size,
2084 xquery, 2115 "filter-size",
2085 xquery_size, 2116 reply_bf_size,
2086 reply_bf, 2117 NULL);
2087 get->bf_mutator);
2088 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 2118 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2089 "GET for %s at %s after %u hops\n", 2119 "GET for %s at %s after %u hops\n",
2090 GNUNET_h2s (&get->key), 2120 GNUNET_h2s (&get->key),
@@ -2103,8 +2133,7 @@ handle_dht_p2p_get (void *cls,
2103 GNUNET_NO); 2133 GNUNET_NO);
2104 handle_find_peer (peer->id, 2134 handle_find_peer (peer->id,
2105 &get->key, 2135 &get->key,
2106 reply_bf, 2136 bg);
2107 get->bf_mutator);
2108 } 2137 }
2109 else 2138 else
2110 { 2139 {
@@ -2112,10 +2141,9 @@ handle_dht_p2p_get (void *cls,
2112 type, 2141 type,
2113 xquery, 2142 xquery,
2114 xquery_size, 2143 xquery_size,
2115 &reply_bf, 2144 bg,
2116 get->bf_mutator,
2117 &handle_local_result, 2145 &handle_local_result,
2118 NULL); 2146 peer);
2119 } 2147 }
2120 } 2148 }
2121 else 2149 else
@@ -2126,6 +2154,15 @@ handle_dht_p2p_get (void *cls,
2126 GNUNET_NO); 2154 GNUNET_NO);
2127 } 2155 }
2128 2156
2157 /* remember request for routing replies */
2158 GDS_ROUTING_add (peer->id,
2159 type,
2160 bg, /* bg now owned by routing, but valid at least until end of this function! */
2161 options,
2162 &get->key,
2163 xquery,
2164 xquery_size);
2165
2129 /* P2P forwarding */ 2166 /* P2P forwarding */
2130 forwarded = GNUNET_NO; 2167 forwarded = GNUNET_NO;
2131 if (eval != GNUNET_BLOCK_EVALUATION_OK_LAST) 2168 if (eval != GNUNET_BLOCK_EVALUATION_OK_LAST)
@@ -2136,8 +2173,7 @@ handle_dht_p2p_get (void *cls,
2136 &get->key, 2173 &get->key,
2137 xquery, 2174 xquery,
2138 xquery_size, 2175 xquery_size,
2139 reply_bf, 2176 bg,
2140 get->bf_mutator,
2141 peer_bf); 2177 peer_bf);
2142 GDS_CLIENTS_process_get (options 2178 GDS_CLIENTS_process_get (options
2143 | (GNUNET_OK == forwarded) 2179 | (GNUNET_OK == forwarded)
@@ -2149,10 +2185,7 @@ handle_dht_p2p_get (void *cls,
2149 NULL, 2185 NULL,
2150 &get->key); 2186 &get->key);
2151 2187
2152 2188 /* clean up; note that 'bg' is owned by routing now! */
2153 /* clean up */
2154 if (NULL != reply_bf)
2155 GNUNET_CONTAINER_bloomfilter_free (reply_bf);
2156 GNUNET_CONTAINER_bloomfilter_free (peer_bf); 2189 GNUNET_CONTAINER_bloomfilter_free (peer_bf);
2157} 2190}
2158 2191
@@ -2180,9 +2213,9 @@ check_dht_p2p_result (void *cls,
2180 put_path_length) * 2213 put_path_length) *
2181 sizeof (struct GNUNET_PeerIdentity)) || 2214 sizeof (struct GNUNET_PeerIdentity)) ||
2182 (get_path_length > 2215 (get_path_length >
2183 GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)) || 2216 GNUNET_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)) ||
2184 (put_path_length > 2217 (put_path_length >
2185 GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity))) 2218 GNUNET_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)))
2186 { 2219 {
2187 GNUNET_break_op (0); 2220 GNUNET_break_op (0);
2188 return GNUNET_SYSERR; 2221 return GNUNET_SYSERR;
@@ -2192,6 +2225,81 @@ check_dht_p2p_result (void *cls,
2192 2225
2193 2226
2194/** 2227/**
2228 * Process a reply, after the @a get_path has been updated.
2229 *
2230 * @param expiration_time when does the reply expire
2231 * @param key key matching the query
2232 * @param get_path_length number of entries in @a get_path
2233 * @param get_path path the reply has taken
2234 * @param put_path_length number of entries in @a put_path
2235 * @param put_path path the PUT has taken
2236 * @param type type of the block
2237 * @param data_size number of bytes in @a data
2238 * @param data payload of the reply
2239 */
2240static void
2241process_reply_with_path (struct GNUNET_TIME_Absolute expiration_time,
2242 const struct GNUNET_HashCode *key,
2243 unsigned int get_path_length,
2244 const struct GNUNET_PeerIdentity *get_path,
2245 unsigned int put_path_length,
2246 const struct GNUNET_PeerIdentity *put_path,
2247 enum GNUNET_BLOCK_Type type,
2248 size_t data_size,
2249 const void *data)
2250{
2251 /* forward to local clients */
2252 GDS_CLIENTS_handle_reply (expiration_time,
2253 key,
2254 get_path_length,
2255 get_path,
2256 put_path_length,
2257 put_path,
2258 type,
2259 data_size,
2260 data);
2261 GDS_CLIENTS_process_get_resp (type,
2262 get_path,
2263 get_path_length,
2264 put_path,
2265 put_path_length,
2266 expiration_time,
2267 key,
2268 data,
2269 data_size);
2270 if (GNUNET_YES == cache_results)
2271 {
2272 struct GNUNET_PeerIdentity xput_path[get_path_length + 1 + put_path_length];
2273
2274 GNUNET_memcpy (xput_path,
2275 put_path,
2276 put_path_length * sizeof (struct GNUNET_PeerIdentity));
2277 GNUNET_memcpy (&xput_path[put_path_length],
2278 get_path,
2279 get_path_length * sizeof (struct GNUNET_PeerIdentity));
2280
2281 GDS_DATACACHE_handle_put (expiration_time,
2282 key,
2283 get_path_length + put_path_length,
2284 xput_path,
2285 type,
2286 data_size,
2287 data);
2288 }
2289 /* forward to other peers */
2290 GDS_ROUTING_process (type,
2291 expiration_time,
2292 key,
2293 put_path_length,
2294 put_path,
2295 get_path_length,
2296 get_path,
2297 data,
2298 data_size);
2299}
2300
2301
2302/**
2195 * Core handler for p2p result messages. 2303 * Core handler for p2p result messages.
2196 * 2304 *
2197 * @param cls closure 2305 * @param cls closure
@@ -2233,14 +2341,23 @@ handle_dht_p2p_result (void *cls,
2233 if (GNUNET_YES == log_route_details_stderr) 2341 if (GNUNET_YES == log_route_details_stderr)
2234 { 2342 {
2235 char *tmp; 2343 char *tmp;
2344 char *pp;
2345 char *gp;
2236 2346
2347 gp = GNUNET_STRINGS_pp2s (get_path,
2348 get_path_length);
2349 pp = GNUNET_STRINGS_pp2s (put_path,
2350 put_path_length);
2237 tmp = GNUNET_strdup (GNUNET_i2s (&my_identity)); 2351 tmp = GNUNET_strdup (GNUNET_i2s (&my_identity));
2238 LOG_TRAFFIC (GNUNET_ERROR_TYPE_DEBUG, 2352 LOG_TRAFFIC (GNUNET_ERROR_TYPE_DEBUG,
2239 "R5N RESULT %s: %s->%s (%u)\n", 2353 "R5N RESULT %s: %s->%s (GP: %s, PP: %s)\n",
2240 GNUNET_h2s (&prm->key), 2354 GNUNET_h2s (&prm->key),
2241 GNUNET_i2s (peer->id), 2355 GNUNET_i2s (peer->id),
2242 tmp, 2356 tmp,
2243 get_path_length + 1); 2357 gp,
2358 pp);
2359 GNUNET_free (gp);
2360 GNUNET_free (pp);
2244 GNUNET_free (tmp); 2361 GNUNET_free (tmp);
2245 } 2362 }
2246 /* if we got a HELLO, consider it for our own routing table */ 2363 /* if we got a HELLO, consider it for our own routing table */
@@ -2276,7 +2393,27 @@ handle_dht_p2p_result (void *cls,
2276 h); 2393 h);
2277 } 2394 }
2278 2395
2279 /* append 'peer' to 'get_path' */ 2396
2397 /* First, check if 'peer' is already on the path, and if
2398 so, truncate it instead of expanding. */
2399 for (unsigned int i=0;i<=get_path_length;i++)
2400 if (0 == memcmp (&get_path[i],
2401 peer->id,
2402 sizeof (struct GNUNET_PeerIdentity)))
2403 {
2404 process_reply_with_path (GNUNET_TIME_absolute_ntoh (prm->expiration_time),
2405 &prm->key,
2406 i,
2407 get_path,
2408 put_path_length,
2409 put_path,
2410 type,
2411 data_size,
2412 data);
2413 return;
2414 }
2415
2416 /* Need to append 'peer' to 'get_path' (normal case) */
2280 { 2417 {
2281 struct GNUNET_PeerIdentity xget_path[get_path_length + 1]; 2418 struct GNUNET_PeerIdentity xget_path[get_path_length + 1];
2282 2419
@@ -2284,56 +2421,16 @@ handle_dht_p2p_result (void *cls,
2284 get_path, 2421 get_path,
2285 get_path_length * sizeof (struct GNUNET_PeerIdentity)); 2422 get_path_length * sizeof (struct GNUNET_PeerIdentity));
2286 xget_path[get_path_length] = *peer->id; 2423 xget_path[get_path_length] = *peer->id;
2287 get_path_length++;
2288
2289 /* forward to local clients */
2290 GDS_CLIENTS_handle_reply (GNUNET_TIME_absolute_ntoh (prm->expiration_time),
2291 &prm->key,
2292 get_path_length,
2293 xget_path,
2294 put_path_length,
2295 put_path,
2296 type,
2297 data_size,
2298 data);
2299 GDS_CLIENTS_process_get_resp (type,
2300 xget_path,
2301 get_path_length,
2302 put_path, put_path_length,
2303 GNUNET_TIME_absolute_ntoh (prm->expiration_time),
2304 &prm->key,
2305 data,
2306 data_size);
2307 if (GNUNET_YES == cache_results)
2308 {
2309 struct GNUNET_PeerIdentity xput_path[get_path_length + 1 + put_path_length];
2310 2424
2311 GNUNET_memcpy (xput_path, 2425 process_reply_with_path (GNUNET_TIME_absolute_ntoh (prm->expiration_time),
2312 put_path, 2426 &prm->key,
2313 put_path_length * sizeof (struct GNUNET_PeerIdentity)); 2427 get_path_length + 1,
2314 GNUNET_memcpy (&xput_path[put_path_length], 2428 xget_path,
2315 xget_path, 2429 put_path_length,
2316 get_path_length * sizeof (struct GNUNET_PeerIdentity)); 2430 put_path,
2317 2431 type,
2318 GDS_DATACACHE_handle_put (GNUNET_TIME_absolute_ntoh (prm->expiration_time), 2432 data_size,
2319 &prm->key, 2433 data);
2320 get_path_length + put_path_length,
2321 xput_path,
2322 type,
2323 data_size,
2324 data);
2325 }
2326 /* forward to other peers */
2327 GDS_ROUTING_process (NULL,
2328 type,
2329 GNUNET_TIME_absolute_ntoh (prm->expiration_time),
2330 &prm->key,
2331 put_path_length,
2332 put_path,
2333 get_path_length,
2334 xget_path,
2335 data,
2336 data_size);
2337 } 2434 }
2338} 2435}
2339 2436
diff --git a/src/dht/gnunet-service-dht_neighbours.h b/src/dht/gnunet-service-dht_neighbours.h
index d89e5c54f..34b76ee8a 100644
--- a/src/dht/gnunet-service-dht_neighbours.h
+++ b/src/dht/gnunet-service-dht_neighbours.h
@@ -77,8 +77,7 @@ GDS_NEIGHBOURS_handle_put (enum GNUNET_BLOCK_Type type,
77 * @param key key for the content 77 * @param key key for the content
78 * @param xquery extended query 78 * @param xquery extended query
79 * @param xquery_size number of bytes in @a xquery 79 * @param xquery_size number of bytes in @a xquery
80 * @param reply_bf bloomfilter to filter duplicates 80 * @param bg block group to filter replies
81 * @param reply_bf_mutator mutator for @a reply_bf
82 * @param peer_bf filter for peers not to select (again, updated) 81 * @param peer_bf filter for peers not to select (again, updated)
83 * @return #GNUNET_OK if the request was forwarded, #GNUNET_NO if not 82 * @return #GNUNET_OK if the request was forwarded, #GNUNET_NO if not
84 */ 83 */
@@ -88,9 +87,9 @@ GDS_NEIGHBOURS_handle_get (enum GNUNET_BLOCK_Type type,
88 uint32_t desired_replication_level, 87 uint32_t desired_replication_level,
89 uint32_t hop_count, 88 uint32_t hop_count,
90 const struct GNUNET_HashCode *key, 89 const struct GNUNET_HashCode *key,
91 const void *xquery, size_t xquery_size, 90 const void *xquery,
92 const struct GNUNET_CONTAINER_BloomFilter *reply_bf, 91 size_t xquery_size,
93 uint32_t reply_bf_mutator, 92 struct GNUNET_BLOCK_Group *bg,
94 struct GNUNET_CONTAINER_BloomFilter *peer_bf); 93 struct GNUNET_CONTAINER_BloomFilter *peer_bf);
95 94
96 95
@@ -114,12 +113,13 @@ void
114GDS_NEIGHBOURS_handle_reply (const struct GNUNET_PeerIdentity *target, 113GDS_NEIGHBOURS_handle_reply (const struct GNUNET_PeerIdentity *target,
115 enum GNUNET_BLOCK_Type type, 114 enum GNUNET_BLOCK_Type type,
116 struct GNUNET_TIME_Absolute expiration_time, 115 struct GNUNET_TIME_Absolute expiration_time,
117 const struct GNUNET_HashCode * key, 116 const struct GNUNET_HashCode *key,
118 unsigned int put_path_length, 117 unsigned int put_path_length,
119 const struct GNUNET_PeerIdentity *put_path, 118 const struct GNUNET_PeerIdentity *put_path,
120 unsigned int get_path_length, 119 unsigned int get_path_length,
121 const struct GNUNET_PeerIdentity *get_path, 120 const struct GNUNET_PeerIdentity *get_path,
122 const void *data, size_t data_size); 121 const void *data,
122 size_t data_size);
123 123
124 124
125/** 125/**
diff --git a/src/dht/gnunet-service-dht_routing.c b/src/dht/gnunet-service-dht_routing.c
index 978c46d73..098b6e895 100644
--- a/src/dht/gnunet-service-dht_routing.c
+++ b/src/dht/gnunet-service-dht_routing.c
@@ -58,9 +58,9 @@ struct RecentRequest
58 struct GNUNET_CONTAINER_HeapNode *heap_node; 58 struct GNUNET_CONTAINER_HeapNode *heap_node;
59 59
60 /** 60 /**
61 * Bloomfilter for replies to drop. 61 * Block group for filtering replies.
62 */ 62 */
63 struct GNUNET_CONTAINER_BloomFilter *reply_bf; 63 struct GNUNET_BLOCK_Group *bg;
64 64
65 /** 65 /**
66 * Type of the requested block. 66 * Type of the requested block.
@@ -79,11 +79,6 @@ struct RecentRequest
79 size_t xquery_size; 79 size_t xquery_size;
80 80
81 /** 81 /**
82 * Mutator value for the reply_bf, see gnunet_block_lib.h
83 */
84 uint32_t reply_bf_mutator;
85
86 /**
87 * Request options. 82 * Request options.
88 */ 83 */
89 enum GNUNET_DHT_RouteOption options; 84 enum GNUNET_DHT_RouteOption options;
@@ -128,17 +123,17 @@ struct ProcessContext
128 struct GNUNET_TIME_Absolute expiration_time; 123 struct GNUNET_TIME_Absolute expiration_time;
129 124
130 /** 125 /**
131 * Number of entries in 'put_path'. 126 * Number of entries in @e put_path.
132 */ 127 */
133 unsigned int put_path_length; 128 unsigned int put_path_length;
134 129
135 /** 130 /**
136 * Number of entries in 'get_path'. 131 * Number of entries in @e get_path.
137 */ 132 */
138 unsigned int get_path_length; 133 unsigned int get_path_length;
139 134
140 /** 135 /**
141 * Number of bytes in 'data'. 136 * Number of bytes in @e data.
142 */ 137 */
143 size_t data_size; 138 size_t data_size;
144 139
@@ -207,14 +202,18 @@ process (void *cls,
207 eval 202 eval
208 = GNUNET_BLOCK_evaluate (GDS_block_context, 203 = GNUNET_BLOCK_evaluate (GDS_block_context,
209 pc->type, 204 pc->type,
205 rr->bg,
210 GNUNET_BLOCK_EO_NONE, 206 GNUNET_BLOCK_EO_NONE,
211 eval_key, 207 eval_key,
212 &rr->reply_bf,
213 rr->reply_bf_mutator,
214 rr->xquery, 208 rr->xquery,
215 rr->xquery_size, 209 rr->xquery_size,
216 pc->data, 210 pc->data,
217 pc->data_size); 211 pc->data_size);
212 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
213 "Result for %s of type %d was evaluated as %d\n",
214 GNUNET_h2s (key),
215 pc->type,
216 eval);
218 switch (eval) 217 switch (eval)
219 { 218 {
220 case GNUNET_BLOCK_EVALUATION_OK_MORE: 219 case GNUNET_BLOCK_EVALUATION_OK_MORE:
@@ -223,8 +222,13 @@ process (void *cls,
223 gettext_noop 222 gettext_noop
224 ("# Good REPLIES matched against routing table"), 223 ("# Good REPLIES matched against routing table"),
225 1, GNUNET_NO); 224 1, GNUNET_NO);
226 GDS_NEIGHBOURS_handle_reply (&rr->peer, pc->type, pc->expiration_time, key, 225 GDS_NEIGHBOURS_handle_reply (&rr->peer,
227 ppl, pc->put_path, gpl, pc->get_path, pc->data, 226 pc->type,
227 pc->expiration_time,
228 key,
229 ppl, pc->put_path,
230 gpl, pc->get_path,
231 pc->data,
228 pc->data_size); 232 pc->data_size);
229 break; 233 break;
230 case GNUNET_BLOCK_EVALUATION_OK_DUPLICATE: 234 case GNUNET_BLOCK_EVALUATION_OK_DUPLICATE:
@@ -275,16 +279,15 @@ process (void *cls,
275 * @param type type of the block 279 * @param type type of the block
276 * @param expiration_time when does the content expire 280 * @param expiration_time when does the content expire
277 * @param key key for the content 281 * @param key key for the content
278 * @param put_path_length number of entries in put_path 282 * @param put_path_length number of entries in @a put_path
279 * @param put_path peers the original PUT traversed (if tracked) 283 * @param put_path peers the original PUT traversed (if tracked)
280 * @param get_path_length number of entries in get_path 284 * @param get_path_length number of entries in @a get_path
281 * @param get_path peers this reply has traversed so far (if tracked) 285 * @param get_path peers this reply has traversed so far (if tracked)
282 * @param data payload of the reply 286 * @param data payload of the reply
283 * @param data_size number of bytes in data 287 * @param data_size number of bytes in data
284 */ 288 */
285void 289void
286GDS_ROUTING_process (void *cls, 290GDS_ROUTING_process (enum GNUNET_BLOCK_Type type,
287 enum GNUNET_BLOCK_Type type,
288 struct GNUNET_TIME_Absolute expiration_time, 291 struct GNUNET_TIME_Absolute expiration_time,
289 const struct GNUNET_HashCode *key, 292 const struct GNUNET_HashCode *key,
290 unsigned int put_path_length, 293 unsigned int put_path_length,
@@ -338,7 +341,7 @@ expire_oldest_entry ()
338 recent_req = GNUNET_CONTAINER_heap_peek (recent_heap); 341 recent_req = GNUNET_CONTAINER_heap_peek (recent_heap);
339 GNUNET_assert (recent_req != NULL); 342 GNUNET_assert (recent_req != NULL);
340 GNUNET_CONTAINER_heap_remove_node (recent_req->heap_node); 343 GNUNET_CONTAINER_heap_remove_node (recent_req->heap_node);
341 GNUNET_CONTAINER_bloomfilter_free (recent_req->reply_bf); 344 GNUNET_BLOCK_group_destroy (recent_req->bg);
342 GNUNET_assert (GNUNET_YES == 345 GNUNET_assert (GNUNET_YES ==
343 GNUNET_CONTAINER_multihashmap_remove (recent_map, 346 GNUNET_CONTAINER_multihashmap_remove (recent_map,
344 &recent_req->key, 347 &recent_req->key,
@@ -374,18 +377,10 @@ try_combine_recent (void *cls,
374 rr->xquery, 377 rr->xquery,
375 in->xquery_size)) ) 378 in->xquery_size)) )
376 return GNUNET_OK; 379 return GNUNET_OK;
377 if (in->reply_bf_mutator != rr->reply_bf_mutator) 380 GNUNET_break (GNUNET_SYSERR !=
378 { 381 GNUNET_BLOCK_group_merge (in->bg,
379 rr->reply_bf_mutator = in->reply_bf_mutator; 382 rr->bg));
380 GNUNET_CONTAINER_bloomfilter_free (rr->reply_bf); 383 rr->bg = in->bg;
381 rr->reply_bf = in->reply_bf;
382 }
383 else
384 {
385 GNUNET_CONTAINER_bloomfilter_or2 (rr->reply_bf,
386 in->reply_bf);
387 GNUNET_CONTAINER_bloomfilter_free (in->reply_bf);
388 }
389 GNUNET_free (in); 384 GNUNET_free (in);
390 return GNUNET_SYSERR; 385 return GNUNET_SYSERR;
391} 386}
@@ -406,12 +401,11 @@ try_combine_recent (void *cls,
406void 401void
407GDS_ROUTING_add (const struct GNUNET_PeerIdentity *sender, 402GDS_ROUTING_add (const struct GNUNET_PeerIdentity *sender,
408 enum GNUNET_BLOCK_Type type, 403 enum GNUNET_BLOCK_Type type,
404 struct GNUNET_BLOCK_Group *bg,
409 enum GNUNET_DHT_RouteOption options, 405 enum GNUNET_DHT_RouteOption options,
410 const struct GNUNET_HashCode *key, 406 const struct GNUNET_HashCode *key,
411 const void *xquery, 407 const void *xquery,
412 size_t xquery_size, 408 size_t xquery_size)
413 const struct GNUNET_CONTAINER_BloomFilter *reply_bf,
414 uint32_t reply_bf_mutator)
415{ 409{
416 struct RecentRequest *recent_req; 410 struct RecentRequest *recent_req;
417 411
@@ -419,17 +413,19 @@ GDS_ROUTING_add (const struct GNUNET_PeerIdentity *sender,
419 expire_oldest_entry (); 413 expire_oldest_entry ();
420 GNUNET_STATISTICS_update (GDS_stats, 414 GNUNET_STATISTICS_update (GDS_stats,
421 gettext_noop ("# Entries added to routing table"), 415 gettext_noop ("# Entries added to routing table"),
422 1, GNUNET_NO); 416 1,
417 GNUNET_NO);
423 recent_req = GNUNET_malloc (sizeof (struct RecentRequest) + xquery_size); 418 recent_req = GNUNET_malloc (sizeof (struct RecentRequest) + xquery_size);
424 recent_req->peer = *sender; 419 recent_req->peer = *sender;
425 recent_req->key = *key; 420 recent_req->key = *key;
426 recent_req->reply_bf = GNUNET_CONTAINER_bloomfilter_copy (reply_bf); 421 recent_req->bg = bg;
427 recent_req->type = type; 422 recent_req->type = type;
428 recent_req->options = options; 423 recent_req->options = options;
429 recent_req->xquery = &recent_req[1]; 424 recent_req->xquery = &recent_req[1];
430 GNUNET_memcpy (&recent_req[1], xquery, xquery_size); 425 GNUNET_memcpy (&recent_req[1],
426 xquery,
427 xquery_size);
431 recent_req->xquery_size = xquery_size; 428 recent_req->xquery_size = xquery_size;
432 recent_req->reply_bf_mutator = reply_bf_mutator;
433 if (GNUNET_SYSERR == 429 if (GNUNET_SYSERR ==
434 GNUNET_CONTAINER_multihashmap_get_multiple (recent_map, 430 GNUNET_CONTAINER_multihashmap_get_multiple (recent_map,
435 key, 431 key,
@@ -442,13 +438,14 @@ GDS_ROUTING_add (const struct GNUNET_PeerIdentity *sender,
442 1, GNUNET_NO); 438 1, GNUNET_NO);
443 return; 439 return;
444 } 440 }
445 recent_req->heap_node = 441 recent_req->heap_node
446 GNUNET_CONTAINER_heap_insert (recent_heap, recent_req, 442 = GNUNET_CONTAINER_heap_insert (recent_heap,
443 recent_req,
447 GNUNET_TIME_absolute_get ().abs_value_us); 444 GNUNET_TIME_absolute_get ().abs_value_us);
448 GNUNET_CONTAINER_multihashmap_put (recent_map, key, recent_req, 445 GNUNET_CONTAINER_multihashmap_put (recent_map,
446 key,
447 recent_req,
449 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); 448 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
450
451
452} 449}
453 450
454 451
diff --git a/src/dht/gnunet-service-dht_routing.h b/src/dht/gnunet-service-dht_routing.h
index 7c57361dc..ad7958363 100644
--- a/src/dht/gnunet-service-dht_routing.h
+++ b/src/dht/gnunet-service-dht_routing.h
@@ -35,10 +35,9 @@
35 * Handle a reply (route to origin). Only forwards the reply back to 35 * Handle a reply (route to origin). Only forwards the reply back to
36 * other peers waiting for it. Does not do local caching or 36 * other peers waiting for it. Does not do local caching or
37 * forwarding to local clients. Essentially calls 37 * forwarding to local clients. Essentially calls
38 * GDS_NEIGHBOURS_handle_reply for all peers that sent us a matching 38 * #GDS_NEIGHBOURS_handle_reply() for all peers that sent us a matching
39 * request recently. 39 * request recently.
40 * 40 *
41 * @param cls closure
42 * @param type type of the block 41 * @param type type of the block
43 * @param expiration_time when does the content expire 42 * @param expiration_time when does the content expire
44 * @param key key for the content 43 * @param key key for the content
@@ -50,8 +49,7 @@
50 * @param data_size number of bytes in @a data 49 * @param data_size number of bytes in @a data
51 */ 50 */
52void 51void
53GDS_ROUTING_process (void *cls, 52GDS_ROUTING_process (enum GNUNET_BLOCK_Type type,
54 enum GNUNET_BLOCK_Type type,
55 struct GNUNET_TIME_Absolute expiration_time, 53 struct GNUNET_TIME_Absolute expiration_time,
56 const struct GNUNET_HashCode *key, 54 const struct GNUNET_HashCode *key,
57 unsigned int put_path_length, 55 unsigned int put_path_length,
@@ -67,21 +65,20 @@ GDS_ROUTING_process (void *cls,
67 * 65 *
68 * @param sender peer that originated the request 66 * @param sender peer that originated the request
69 * @param type type of the block 67 * @param type type of the block
68 * @param bg block group to evaluate replies, henceforth owned by routing
70 * @param options options for processing 69 * @param options options for processing
71 * @param key key for the content 70 * @param key key for the content
72 * @param xquery extended query 71 * @param xquery extended query
73 * @param xquery_size number of bytes in @a xquery 72 * @param xquery_size number of bytes in @a xquery
74 * @param reply_bf bloomfilter to filter duplicates 73 */
75 * @param reply_bf_mutator mutator for @a reply_bf
76*/
77void 74void
78GDS_ROUTING_add (const struct GNUNET_PeerIdentity *sender, 75GDS_ROUTING_add (const struct GNUNET_PeerIdentity *sender,
79 enum GNUNET_BLOCK_Type type, 76 enum GNUNET_BLOCK_Type type,
77 struct GNUNET_BLOCK_Group *bg,
80 enum GNUNET_DHT_RouteOption options, 78 enum GNUNET_DHT_RouteOption options,
81 const struct GNUNET_HashCode * key, const void *xquery, 79 const struct GNUNET_HashCode * key,
82 size_t xquery_size, 80 const void *xquery,
83 const struct GNUNET_CONTAINER_BloomFilter *reply_bf, 81 size_t xquery_size);
84 uint32_t reply_bf_mutator);
85 82
86 83
87/** 84/**
diff --git a/src/dht/gnunet-service-wdht.c b/src/dht/gnunet-service-wdht.c
deleted file mode 100644
index e1ca1c968..000000000
--- a/src/dht/gnunet-service-wdht.c
+++ /dev/null
@@ -1,103 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010, 2011 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
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 dht/gnunet-service-wdht.c
23 * @brief GNUnet DHT service
24 * @author Christian Grothoff
25 * @author Nathan Evans
26 */
27#include "platform.h"
28#include "gnunet_block_lib.h"
29#include "gnunet_util_lib.h"
30#include "gnunet_transport_service.h"
31#include "gnunet_hello_lib.h"
32#include "gnunet_dht_service.h"
33#include "gnunet_statistics_service.h"
34#include "gnunet-service-wdht.h"
35#include "gnunet-service-dht_datacache.h"
36#include "gnunet-service-dht_neighbours.h"
37#include "gnunet-service-dht_nse.h"
38
39
40/* Code shared between different DHT implementations */
41#include "gnunet-service-dht_clients.c"
42
43
44/**
45 * Task run during shutdown.
46 *
47 * @param cls unused
48 */
49static void
50shutdown_task (void *cls)
51{
52 GDS_NEIGHBOURS_done ();
53 GDS_DATACACHE_done ();
54 GDS_NSE_done ();
55 if (NULL != GDS_block_context)
56 {
57 GNUNET_BLOCK_context_destroy (GDS_block_context);
58 GDS_block_context = NULL;
59 }
60 if (NULL != GDS_stats)
61 {
62 GNUNET_STATISTICS_destroy (GDS_stats, GNUNET_YES);
63 GDS_stats = NULL;
64 }
65 GDS_CLIENTS_stop ();
66}
67
68
69/**
70 * Process dht requests.
71 *
72 * @param cls closure
73 * @param c configuration to use
74 * @param service the initialized service
75 */
76static void
77run (void *cls,
78 const struct GNUNET_CONFIGURATION_Handle *c,
79 struct GNUNET_SERVICE_Handle *service)
80{
81 GDS_cfg = c;
82 GDS_service = service;
83 GDS_block_context = GNUNET_BLOCK_context_create (GDS_cfg);
84 GDS_stats = GNUNET_STATISTICS_create ("dht",
85 GDS_cfg);
86 GDS_NSE_init ();
87 GDS_DATACACHE_init ();
88 GDS_CLIENTS_init ();
89 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
90 NULL);
91 if (GNUNET_OK != GDS_NEIGHBOURS_init ())
92 {
93 GNUNET_SCHEDULER_shutdown ();
94 return;
95 }
96}
97
98
99/* Finally, define the main method */
100GDS_DHT_SERVICE_INIT("wdht", &run);
101
102
103/* end of gnunet-service-wdht.c */
diff --git a/src/dht/gnunet-service-wdht.h b/src/dht/gnunet-service-wdht.h
deleted file mode 100644
index 5a8e2e21d..000000000
--- a/src/dht/gnunet-service-wdht.h
+++ /dev/null
@@ -1,50 +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 dht/gnunet-service-xdht.h
23 * @brief GNUnet DHT globals
24 * @author Christian Grothoff
25 */
26#ifndef GNUNET_SERVICE_XDHT_H
27#define GNUNET_SERVICE_XDHT_H
28
29#include "gnunet_util_lib.h"
30#include "gnunet_statistics_service.h"
31#include "gnunet_transport_service.h"
32
33#define DEBUG_DHT GNUNET_EXTRA_LOGGING
34
35/**
36 * Configuration we use.
37 */
38extern const struct GNUNET_CONFIGURATION_Handle *GDS_cfg;
39
40/**
41 * Our handle to the BLOCK library.
42 */
43extern struct GNUNET_BLOCK_Context *GDS_block_context;
44
45/**
46 * Handle for the statistics service.
47 */
48extern struct GNUNET_STATISTICS_Handle *GDS_stats;
49
50#endif
diff --git a/src/dht/gnunet-service-wdht_clients.c b/src/dht/gnunet-service-wdht_clients.c
deleted file mode 100644
index 7ad0d2904..000000000
--- a/src/dht/gnunet-service-wdht_clients.c
+++ /dev/null
@@ -1,1428 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010, 2011, 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 dht/gnunet-service-wdht_clients.c
23 * @brief GNUnet DHT service's client management code
24 * @author Christian Grothoff
25 * @author Nathan Evans
26 */
27
28#include "platform.h"
29#include "gnunet_constants.h"
30#include "gnunet_protocols.h"
31#include "gnunet_statistics_service.h"
32#include "gnunet-service-wdht.h"
33#include "gnunet-service-wdht_clients.h"
34#include "gnunet-service-dht_datacache.h"
35#include "gnunet-service-wdht_neighbours.h"
36#include "dht.h"
37
38
39/**
40 * Should routing details be logged to stderr (for debugging)?
41 */
42#define LOG_TRAFFIC(kind,...) GNUNET_log_from (kind, "dht-traffic",__VA_ARGS__)
43
44#define LOG(kind,...) GNUNET_log_from (kind, "dht-clients",__VA_ARGS__)
45
46#define DEBUG(...) \
47 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
48
49/**
50 * Linked list of messages to send to clients.
51 */
52struct PendingMessage
53{
54 /**
55 * Pointer to next item in the list
56 */
57 struct PendingMessage *next;
58
59 /**
60 * Pointer to previous item in the list
61 */
62 struct PendingMessage *prev;
63
64 /**
65 * Actual message to be sent, allocated at the end of the struct:
66 * // msg = (cast) &pm[1];
67 * // GNUNET_memcpy (&pm[1], data, len);
68 */
69 const struct GNUNET_MessageHeader *msg;
70
71};
72
73
74/**
75 * Struct containing information about a client,
76 * handle to connect to it, and any pending messages
77 * that need to be sent to it.
78 */
79struct ClientList
80{
81 /**
82 * Linked list of active clients
83 */
84 struct ClientList *next;
85
86 /**
87 * Linked list of active clients
88 */
89 struct ClientList *prev;
90
91 /**
92 * The handle to this client
93 */
94 struct GNUNET_SERVER_Client *client_handle;
95
96 /**
97 * Handle to the current transmission request, NULL
98 * if none pending.
99 */
100 struct GNUNET_SERVER_TransmitHandle *transmit_handle;
101
102 /**
103 * Linked list of pending messages for this client
104 */
105 struct PendingMessage *pending_head;
106
107 /**
108 * Tail of linked list of pending messages for this client
109 */
110 struct PendingMessage *pending_tail;
111
112};
113
114
115/**
116 * Entry in the local forwarding map for a client's GET request.
117 */
118struct ClientQueryRecord
119{
120
121 /**
122 * The key this request was about
123 */
124 struct GNUNET_HashCode key;
125
126 /**
127 * Client responsible for the request.
128 */
129 struct ClientList *client;
130
131 /**
132 * Extended query (see gnunet_block_lib.h), allocated at the end of this struct.
133 */
134 const void *xquery;
135
136 /**
137 * Replies we have already seen for this request.
138 */
139 struct GNUNET_HashCode *seen_replies;
140
141 /**
142 * Pointer to this nodes heap location in the retry-heap (for fast removal)
143 */
144 struct GNUNET_CONTAINER_HeapNode *hnode;
145
146 /**
147 * What's the delay between re-try operations that we currently use for this
148 * request?
149 */
150 struct GNUNET_TIME_Relative retry_frequency;
151
152 /**
153 * What's the next time we should re-try this request?
154 */
155 struct GNUNET_TIME_Absolute retry_time;
156
157 /**
158 * The unique identifier of this request
159 */
160 uint64_t unique_id;
161
162 /**
163 * Number of bytes in xquery.
164 */
165 size_t xquery_size;
166
167 /**
168 * Number of entries in @e seen_replies.
169 */
170 unsigned int seen_replies_count;
171
172 /**
173 * Desired replication level
174 */
175 uint32_t replication;
176
177 /**
178 * Any message options for this request
179 */
180 uint32_t msg_options;
181
182 /**
183 * The type for the data for the GET request.
184 */
185 enum GNUNET_BLOCK_Type type;
186
187};
188
189
190/**
191 * Struct containing paremeters of monitoring requests.
192 */
193struct ClientMonitorRecord
194{
195
196 /**
197 * Next element in DLL.
198 */
199 struct ClientMonitorRecord *next;
200
201 /**
202 * Previous element in DLL.
203 */
204 struct ClientMonitorRecord *prev;
205
206 /**
207 * Type of blocks that are of interest
208 */
209 enum GNUNET_BLOCK_Type type;
210
211 /**
212 * Key of data of interest, NULL for all.
213 */
214 struct GNUNET_HashCode *key;
215
216 /**
217 * Flag whether to notify about GET messages.
218 */
219 int16_t get;
220
221 /**
222 * Flag whether to notify about GET_REPONSE messages.
223 */
224 int16_t get_resp;
225
226 /**
227 * Flag whether to notify about PUT messages.
228 */
229 uint16_t put;
230
231 /**
232 * Client to notify of these requests.
233 */
234 struct ClientList *client;
235};
236
237
238/**
239 * List of active clients.
240 */
241static struct ClientList *client_head;
242
243/**
244 * List of active clients.
245 */
246static struct ClientList *client_tail;
247
248/**
249 * List of active monitoring requests.
250 */
251static struct ClientMonitorRecord *monitor_head;
252
253/**
254 * List of active monitoring requests.
255 */
256static struct ClientMonitorRecord *monitor_tail;
257
258/**
259 * Hashmap for fast key based lookup, maps keys to `struct ClientQueryRecord` entries.
260 */
261static struct GNUNET_CONTAINER_MultiHashMap *forward_map;
262
263/**
264 * Heap with all of our client's request, sorted by retry time (earliest on top).
265 */
266static struct GNUNET_CONTAINER_Heap *retry_heap;
267
268/**
269 * Task that re-transmits requests (using retry_heap).
270 */
271static struct GNUNET_SCHEDULER_Task * retry_task;
272
273
274/**
275 * Task run to check for messages that need to be sent to a client.
276 *
277 * @param client a ClientList, containing the client and any messages to be sent to it
278 */
279static void
280process_pending_messages (struct ClientList *client);
281
282
283/**
284 * Callback called as a result of issuing a #GNUNET_SERVER_notify_transmit_ready()
285 * request. A ClientList is passed as closure, take the head of the list
286 * and copy it into buf, which has the result of sending the message to the
287 * client.
288 *
289 * @param cls closure to this call
290 * @param size maximum number of bytes available to send
291 * @param buf where to copy the actual message to
292 *
293 * @return the number of bytes actually copied, 0 indicates failure
294 */
295static size_t
296send_reply_to_client (void *cls, size_t size, void *buf)
297{
298 struct ClientList *client = cls;
299 char *cbuf = buf;
300 struct PendingMessage *reply;
301 size_t off;
302 size_t msize;
303
304 client->transmit_handle = NULL;
305 if (buf == NULL)
306 {
307 /* client disconnected */
308 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
309 "Client %p disconnected, pending messages will be discarded\n",
310 client->client_handle);
311 return 0;
312 }
313 off = 0;
314 while ((NULL != (reply = client->pending_head)) &&
315 (size >= off + (msize = ntohs (reply->msg->size))))
316 {
317 GNUNET_CONTAINER_DLL_remove (client->pending_head, client->pending_tail,
318 reply);
319 GNUNET_memcpy (&cbuf[off], reply->msg, msize);
320 GNUNET_free (reply);
321 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
322 "Transmitting %u bytes to client %p\n",
323 (unsigned int) msize,
324 client->client_handle);
325 off += msize;
326 }
327 process_pending_messages (client);
328 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
329 "Transmitted %u/%u bytes to client %p\n",
330 (unsigned int) off,
331 (unsigned int) size,
332 client->client_handle);
333 return off;
334}
335
336
337/**
338 * Task run to check for messages that need to be sent to a client.
339 *
340 * @param client a ClientList, containing the client and any messages to be sent to it
341 */
342static void
343process_pending_messages (struct ClientList *client)
344{
345 if ((client->pending_head == NULL) || (client->transmit_handle != NULL))
346 {
347 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
348 "Not asking for transmission to %p now: %s\n",
349 client->client_handle,
350 client->pending_head ==
351 NULL ? "no more messages" : "request already pending");
352 return;
353 }
354 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
355 "Asking for transmission of %u bytes to client %p\n",
356 ntohs (client->pending_head->msg->size), client->client_handle);
357 client->transmit_handle =
358 GNUNET_SERVER_notify_transmit_ready (client->client_handle,
359 ntohs (client->pending_head->
360 msg->size),
361 GNUNET_TIME_UNIT_FOREVER_REL,
362 &send_reply_to_client, client);
363}
364
365
366/**
367 * Add a PendingMessage to the clients list of messages to be sent
368 *
369 * @param client the active client to send the message to
370 * @param pending_message the actual message to send
371 */
372static void
373add_pending_message (struct ClientList *client,
374 struct PendingMessage *pending_message)
375{
376 GNUNET_CONTAINER_DLL_insert_tail (client->pending_head, client->pending_tail,
377 pending_message);
378 process_pending_messages (client);
379}
380
381
382/**
383 * Closure for #forward_reply()
384 */
385struct ForwardReplyContext
386{
387
388 /**
389 * Actual message to send to matching clients.
390 */
391 struct PendingMessage *pm;
392
393 /**
394 * Embedded payload.
395 */
396 const void *data;
397
398 /**
399 * Type of the data.
400 */
401 enum GNUNET_BLOCK_Type type;
402
403 /**
404 * Number of bytes in data.
405 */
406 size_t data_size;
407
408 /**
409 * Do we need to copy @e pm because it was already used?
410 */
411 int do_copy;
412
413};
414
415
416/**
417 * Find a client if it exists, add it otherwise.
418 *
419 * @param client the server handle to the client
420 *
421 * @return the client if found, a new client otherwise
422 */
423static struct ClientList *
424find_active_client (struct GNUNET_SERVER_Client *client)
425{
426 struct ClientList *pos = client_head;
427 struct ClientList *ret;
428
429 while (pos != NULL)
430 {
431 if (pos->client_handle == client)
432 return pos;
433 pos = pos->next;
434 }
435 ret = GNUNET_new (struct ClientList);
436 ret->client_handle = client;
437 GNUNET_CONTAINER_DLL_insert (client_head, client_tail, ret);
438 return ret;
439}
440
441
442/**
443 * Iterator over hash map entries that frees all entries
444 * associated with the given client.
445 *
446 * @param cls client to search for in source routes
447 * @param key current key code (ignored)
448 * @param value value in the hash map, a ClientQueryRecord
449 * @return #GNUNET_YES (we should continue to iterate)
450 */
451static int
452remove_client_records (void *cls, const struct GNUNET_HashCode * key, void *value)
453{
454 struct ClientList *client = cls;
455 struct ClientQueryRecord *record = value;
456
457 if (record->client != client)
458 return GNUNET_YES;
459 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
460 "Removing client %p's record for key %s\n", client,
461 GNUNET_h2s (key));
462 GNUNET_assert (GNUNET_YES ==
463 GNUNET_CONTAINER_multihashmap_remove (forward_map, key,
464 record));
465 if (NULL != record->hnode)
466 GNUNET_CONTAINER_heap_remove_node (record->hnode);
467 GNUNET_array_grow (record->seen_replies, record->seen_replies_count, 0);
468 GNUNET_free (record);
469 return GNUNET_YES;
470}
471
472
473/**
474 * Iterator over hash map entries that send a given reply to
475 * each of the matching clients. With some tricky recycling
476 * of the buffer.
477 *
478 * @param cls the `struct ForwardReplyContext`
479 * @param key current key
480 * @param value value in the hash map, a ClientQueryRecord
481 * @return #GNUNET_YES (we should continue to iterate),
482 * if the result is mal-formed, #GNUNET_NO
483 */
484static int
485forward_reply (void *cls,
486 const struct GNUNET_HashCode *key,
487 void *value)
488{
489 struct ForwardReplyContext *frc = cls;
490 struct ClientQueryRecord *record = value;
491 struct PendingMessage *pm;
492 struct GNUNET_DHT_ClientResultMessage *reply;
493 enum GNUNET_BLOCK_EvaluationResult eval;
494 int do_free;
495 struct GNUNET_HashCode ch;
496 unsigned int i;
497
498 LOG_TRAFFIC (GNUNET_ERROR_TYPE_DEBUG,
499 "XVINE CLIENT-RESULT %s\n",
500 GNUNET_h2s_full (key));
501#if 0
502 if ((record->type != GNUNET_BLOCK_TYPE_ANY) && (record->type != frc->type))
503 {
504 LOG (GNUNET_ERROR_TYPE_DEBUG,
505 "Record type missmatch, not passing request for key %s to local client\n",
506 GNUNET_h2s (key));
507
508 GNUNET_STATISTICS_update (GDS_stats,
509 gettext_noop
510 ("# Key match, type mismatches in REPLY to CLIENT"),
511 1, GNUNET_NO);
512 return GNUNET_YES; /* type mismatch */
513 }
514#endif
515 GNUNET_CRYPTO_hash (frc->data, frc->data_size, &ch);
516 for (i = 0; i < record->seen_replies_count; i++)
517 if (0 == memcmp (&record->seen_replies[i], &ch, sizeof (struct GNUNET_HashCode)))
518 {
519 LOG (GNUNET_ERROR_TYPE_DEBUG,
520 "Duplicate reply, not passing request for key %s to local client\n",
521 GNUNET_h2s (key));
522 GNUNET_STATISTICS_update (GDS_stats,
523 gettext_noop
524 ("# Duplicate REPLIES to CLIENT request dropped"),
525 1, GNUNET_NO);
526 return GNUNET_YES; /* duplicate */
527 }
528 eval =
529 GNUNET_BLOCK_evaluate (GDS_block_context,
530 record->type,
531 GNUNET_BLOCK_EO_NONE,
532 key, NULL, 0,
533 record->xquery,
534 record->xquery_size,
535 frc->data,
536 frc->data_size);
537 LOG (GNUNET_ERROR_TYPE_DEBUG,
538 "Evaluation result is %d for key %s for local client's query\n",
539 (int) eval, GNUNET_h2s (key));
540 switch (eval)
541 {
542 case GNUNET_BLOCK_EVALUATION_OK_LAST:
543 do_free = GNUNET_YES;
544 break;
545 case GNUNET_BLOCK_EVALUATION_OK_MORE:
546 GNUNET_array_append (record->seen_replies, record->seen_replies_count, ch);
547 do_free = GNUNET_NO;
548 break;
549 case GNUNET_BLOCK_EVALUATION_OK_DUPLICATE:
550 /* should be impossible to encounter here */
551 GNUNET_break (0);
552 return GNUNET_YES;
553 case GNUNET_BLOCK_EVALUATION_RESULT_INVALID:
554 GNUNET_break_op (0);
555 return GNUNET_NO;
556 case GNUNET_BLOCK_EVALUATION_REQUEST_VALID:
557 GNUNET_break (0);
558 return GNUNET_NO;
559 case GNUNET_BLOCK_EVALUATION_REQUEST_INVALID:
560 GNUNET_break (0);
561 return GNUNET_NO;
562 case GNUNET_BLOCK_EVALUATION_RESULT_IRRELEVANT:
563 return GNUNET_YES;
564 case GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED:
565 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
566 _("Unsupported block type (%u) in request!\n"), record->type);
567 return GNUNET_NO;
568 default:
569 GNUNET_break (0);
570 return GNUNET_NO;
571 }
572 if (GNUNET_NO == frc->do_copy)
573 {
574 /* first time, we can use the original data */
575 pm = frc->pm;
576 frc->do_copy = GNUNET_YES;
577 }
578 else
579 {
580 /* two clients waiting for same reply, must copy for queueing */
581 pm = GNUNET_malloc (sizeof (struct PendingMessage) +
582 ntohs (frc->pm->msg->size));
583 GNUNET_memcpy (pm, frc->pm,
584 sizeof (struct PendingMessage) + ntohs (frc->pm->msg->size));
585 pm->next = pm->prev = NULL;
586 pm->msg = (struct GNUNET_MessageHeader *) &pm[1];
587 }
588 GNUNET_STATISTICS_update (GDS_stats,
589 gettext_noop ("# RESULTS queued for clients"), 1,
590 GNUNET_NO);
591 reply = (struct GNUNET_DHT_ClientResultMessage *) &pm[1];
592 reply->unique_id = record->unique_id;
593 LOG (GNUNET_ERROR_TYPE_DEBUG,
594 "Queueing reply to query %s for client %p\n",
595 GNUNET_h2s (key),
596 record->client->client_handle);
597 add_pending_message (record->client, pm);
598 if (GNUNET_YES == do_free)
599 remove_client_records (record->client, key, record);
600 return GNUNET_YES;
601}
602
603
604/**
605 * Handle a reply we've received from another peer. If the reply
606 * matches any of our pending queries, forward it to the respective
607 * client(s).
608 *
609 * @param expiration when will the reply expire
610 * @param key the query this reply is for
611 * @param get_path_length number of peers in @a get_path
612 * @param get_path path the reply took on get
613 * @param put_path_length number of peers in @a put_path
614 * @param put_path path the reply took on put
615 * @param type type of the reply
616 * @param data_size number of bytes in @a data
617 * @param data application payload data
618 */
619void
620GDS_CLIENTS_handle_reply (struct GNUNET_TIME_Absolute expiration,
621 const struct GNUNET_HashCode *key,
622 unsigned int get_path_length,
623 const struct GNUNET_PeerIdentity *get_path,
624 unsigned int put_path_length,
625 const struct GNUNET_PeerIdentity *put_path,
626 enum GNUNET_BLOCK_Type type, size_t data_size,
627 const void *data)
628{
629 struct ForwardReplyContext frc;
630 struct PendingMessage *pm;
631 struct GNUNET_DHT_ClientResultMessage *reply;
632 struct GNUNET_PeerIdentity *paths;
633 size_t msize;
634
635 LOG (GNUNET_ERROR_TYPE_DEBUG,
636 "reply for key %s\n",
637 GNUNET_h2s (key));
638
639 if (NULL == GNUNET_CONTAINER_multihashmap_get (forward_map, key))
640 {
641 GNUNET_STATISTICS_update (GDS_stats,
642 gettext_noop
643 ("# REPLIES ignored for CLIENTS (no match)"), 1,
644 GNUNET_NO);
645 return; /* no matching request, fast exit! */
646 }
647 msize =
648 sizeof (struct GNUNET_DHT_ClientResultMessage) + data_size +
649 (get_path_length + put_path_length) * sizeof (struct GNUNET_PeerIdentity);
650 if (msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
651 {
652 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
653 _("Could not pass reply to client, message too big!\n"));
654 return;
655 }
656 DEBUG ("reply FOR DATA_SIZE = %u\n",
657 (unsigned int) msize);
658 pm = GNUNET_malloc (msize + sizeof (struct PendingMessage));
659 reply = (struct GNUNET_DHT_ClientResultMessage *) &pm[1];
660 pm->msg = &reply->header;
661 reply->header.size = htons ((uint16_t) msize);
662 reply->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_CLIENT_RESULT);
663 reply->type = htonl (type);
664 reply->get_path_length = htonl (get_path_length);
665 reply->put_path_length = htonl (put_path_length);
666 reply->unique_id = 0; /* filled in later */
667 reply->expiration = GNUNET_TIME_absolute_hton (expiration);
668 reply->key = *key;
669 paths = (struct GNUNET_PeerIdentity *) &reply[1];
670 GNUNET_memcpy (paths,
671 put_path,
672 sizeof (struct GNUNET_PeerIdentity) * put_path_length);
673 GNUNET_memcpy (&paths[put_path_length],
674 get_path,
675 sizeof (struct GNUNET_PeerIdentity) * get_path_length);
676 GNUNET_memcpy (&paths[get_path_length + put_path_length],
677 data,
678 data_size);
679 frc.do_copy = GNUNET_NO;
680 frc.pm = pm;
681 frc.data = data;
682 frc.data_size = data_size;
683 frc.type = type;
684 GNUNET_CONTAINER_multihashmap_get_multiple (forward_map,
685 key,
686 &forward_reply,
687 &frc);
688 if (GNUNET_NO == frc.do_copy)
689 {
690 /* did not match any of the requests, free! */
691 GNUNET_STATISTICS_update (GDS_stats,
692 gettext_noop
693 ("# REPLIES ignored for CLIENTS (no match)"), 1,
694 GNUNET_NO);
695 GNUNET_free (pm);
696 }
697}
698
699
700/**
701 * Check if some client is monitoring GET messages and notify
702 * them in that case.
703 *
704 * @param options Options, for instance RecordRoute, DemultiplexEverywhere.
705 * @param type The type of data in the request.
706 * @param hop_count Hop count so far.
707 * @param path_length number of entries in path (or 0 if not recorded).
708 * @param path peers on the GET path (or NULL if not recorded).
709 * @param desired_replication_level Desired replication level.
710 * @param key Key of the requested data.
711 */
712void
713GDS_CLIENTS_process_get (uint32_t options,
714 enum GNUNET_BLOCK_Type type,
715 uint32_t hop_count,
716 uint32_t desired_replication_level,
717 unsigned int path_length,
718 const struct GNUNET_PeerIdentity *path,
719 const struct GNUNET_HashCode *key)
720{
721 struct ClientMonitorRecord *m;
722 struct ClientList **cl;
723 unsigned int cl_size;
724
725 cl = NULL;
726 cl_size = 0;
727 for (m = monitor_head; NULL != m; m = m->next)
728 {
729 if ((GNUNET_BLOCK_TYPE_ANY == m->type || m->type == type) &&
730 (NULL == m->key ||
731 memcmp (key, m->key, sizeof(struct GNUNET_HashCode)) == 0))
732 {
733 struct PendingMessage *pm;
734 struct GNUNET_DHT_MonitorGetMessage *mmsg;
735 struct GNUNET_PeerIdentity *msg_path;
736 size_t msize;
737 unsigned int i;
738
739 /* Don't send duplicates */
740 for (i = 0; i < cl_size; i++)
741 if (cl[i] == m->client)
742 break;
743 if (i < cl_size)
744 continue;
745 GNUNET_array_append (cl, cl_size, m->client);
746
747 msize = path_length * sizeof (struct GNUNET_PeerIdentity);
748 msize += sizeof (struct GNUNET_DHT_MonitorGetMessage);
749 msize += sizeof (struct PendingMessage);
750 pm = GNUNET_malloc (msize);
751 mmsg = (struct GNUNET_DHT_MonitorGetMessage *) &pm[1];
752 pm->msg = &mmsg->header;
753 mmsg->header.size = htons (msize - sizeof (struct PendingMessage));
754 mmsg->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_MONITOR_GET);
755 mmsg->options = htonl(options);
756 mmsg->type = htonl(type);
757 mmsg->hop_count = htonl(hop_count);
758 mmsg->desired_replication_level = htonl(desired_replication_level);
759 mmsg->get_path_length = htonl(path_length);
760 GNUNET_memcpy (&mmsg->key, key, sizeof (struct GNUNET_HashCode));
761 msg_path = (struct GNUNET_PeerIdentity *) &mmsg[1];
762 if (path_length > 0)
763 GNUNET_memcpy (msg_path, path,
764 path_length * sizeof (struct GNUNET_PeerIdentity));
765 add_pending_message (m->client, pm);
766 }
767 }
768 GNUNET_free_non_null (cl);
769}
770
771
772/**
773 * Check if some client is monitoring PUT messages and notify
774 * them in that case.
775 *
776 * @param options options, for instance RecordRoute, DemultiplexEverywhere.
777 * @param type type of data in the request.
778 * @param hop_count hop count so far.
779 * @param path_length number of entries in @a path (or 0 if not recorded).
780 * @param path peers on the PUT path (or NULL if not recorded).
781 * @param desired_replication_level desired replication level.
782 * @param exp expiration time of the data.
783 * @param key key under which @a data is to be stored.
784 * @param data pointer to the data carried.
785 * @param size number of bytes in @a data.
786 */
787void
788GDS_CLIENTS_process_put (uint32_t options,
789 enum GNUNET_BLOCK_Type type,
790 uint32_t hop_count,
791 uint32_t desired_replication_level,
792 unsigned int path_length,
793 const struct GNUNET_PeerIdentity *path,
794 struct GNUNET_TIME_Absolute exp,
795 const struct GNUNET_HashCode *key,
796 const void *data,
797 size_t size)
798{
799 struct ClientMonitorRecord *m;
800 struct ClientList **cl;
801 unsigned int cl_size;
802
803 cl = NULL;
804 cl_size = 0;
805 for (m = monitor_head; NULL != m; m = m->next)
806 {
807 if ((GNUNET_BLOCK_TYPE_ANY == m->type || m->type == type) &&
808 (NULL == m->key ||
809 memcmp (key, m->key, sizeof(struct GNUNET_HashCode)) == 0))
810 {
811 struct PendingMessage *pm;
812 struct GNUNET_DHT_MonitorPutMessage *mmsg;
813 struct GNUNET_PeerIdentity *msg_path;
814 size_t msize;
815 unsigned int i;
816
817 /* Don't send duplicates */
818 for (i = 0; i < cl_size; i++)
819 if (cl[i] == m->client)
820 break;
821 if (i < cl_size)
822 continue;
823 GNUNET_array_append (cl, cl_size, m->client);
824
825 msize = size;
826 msize += path_length * sizeof (struct GNUNET_PeerIdentity);
827 msize += sizeof (struct GNUNET_DHT_MonitorPutMessage);
828 msize += sizeof (struct PendingMessage);
829 pm = GNUNET_malloc (msize);
830 mmsg = (struct GNUNET_DHT_MonitorPutMessage *) &pm[1];
831 pm->msg = (struct GNUNET_MessageHeader *) mmsg;
832 mmsg->header.size = htons (msize - sizeof (struct PendingMessage));
833 mmsg->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_MONITOR_PUT);
834 mmsg->options = htonl(options);
835 mmsg->type = htonl(type);
836 mmsg->hop_count = htonl(hop_count);
837 mmsg->desired_replication_level = htonl(desired_replication_level);
838 mmsg->put_path_length = htonl(path_length);
839 msg_path = (struct GNUNET_PeerIdentity *) &mmsg[1];
840 if (path_length > 0)
841 {
842 GNUNET_memcpy (msg_path, path,
843 path_length * sizeof (struct GNUNET_PeerIdentity));
844 }
845 mmsg->expiration_time = GNUNET_TIME_absolute_hton(exp);
846 GNUNET_memcpy (&mmsg->key, key, sizeof (struct GNUNET_HashCode));
847 if (size > 0)
848 GNUNET_memcpy (&msg_path[path_length], data, size);
849 add_pending_message (m->client, pm);
850 }
851 }
852 GNUNET_free_non_null (cl);
853}
854
855
856/**
857 * Route the given request via the DHT.
858 */
859static void
860transmit_request (struct ClientQueryRecord *cqr)
861{
862 GNUNET_STATISTICS_update (GDS_stats,
863 gettext_noop
864 ("# GET requests from clients injected"), 1,
865 GNUNET_NO);
866
867 LOG (GNUNET_ERROR_TYPE_DEBUG,
868 "Initiating GET for %s, replication %u, already have %u replies\n",
869 GNUNET_h2s (&cqr->key),
870 cqr->replication,
871 cqr->seen_replies_count);
872
873 GDS_NEIGHBOURS_handle_get (&cqr->key, cqr->type, cqr->msg_options,
874 cqr->replication);
875
876 /* exponential back-off for retries.
877 * max GNUNET_TIME_STD_EXPONENTIAL_BACKOFF_THRESHOLD (15 min) */
878 cqr->retry_frequency = GNUNET_TIME_STD_BACKOFF (cqr->retry_frequency);
879 cqr->retry_time = GNUNET_TIME_relative_to_absolute (cqr->retry_frequency);
880}
881
882
883/**
884 * Task that looks at the 'retry_heap' and transmits all of the requests
885 * on the heap that are ready for transmission. Then re-schedules
886 * itself (unless the heap is empty).
887 *
888 * @param cls unused
889 */
890static void
891transmit_next_request_task (void *cls)
892{
893 struct ClientQueryRecord *cqr;
894 struct GNUNET_TIME_Relative delay;
895
896 retry_task = NULL;
897 while (NULL != (cqr = GNUNET_CONTAINER_heap_remove_root (retry_heap)))
898 {
899 cqr->hnode = NULL;
900 delay = GNUNET_TIME_absolute_get_remaining (cqr->retry_time);
901 if (delay.rel_value_us > 0)
902 {
903 cqr->hnode =
904 GNUNET_CONTAINER_heap_insert (retry_heap, cqr,
905 cqr->retry_time.abs_value_us);
906 retry_task =
907 GNUNET_SCHEDULER_add_delayed (delay, &transmit_next_request_task,
908 NULL);
909 return;
910 }
911 transmit_request (cqr);
912 cqr->hnode =
913 GNUNET_CONTAINER_heap_insert (retry_heap, cqr,
914 cqr->retry_time.abs_value_us);
915 }
916}
917
918
919/**
920 * Handler for PUT messages.
921 *
922 * @param cls closure for the service
923 * @param client the client we received this message from
924 * @param message the actual message received
925 */
926static void
927handle_dht_local_put (void *cls,
928 struct GNUNET_SERVER_Client *client,
929 const struct GNUNET_MessageHeader *message)
930{
931 const struct GNUNET_DHT_ClientPutMessage *put_msg;
932 struct PendingMessage *pm;
933 struct GNUNET_DHT_ClientPutConfirmationMessage *conf;
934 uint16_t size;
935
936 size = ntohs (message->size);
937 if (size < sizeof (struct GNUNET_DHT_ClientPutMessage))
938 {
939 GNUNET_break (0);
940 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
941 return;
942 }
943 GNUNET_STATISTICS_update (GDS_stats,
944 gettext_noop
945 ("# PUT requests received from clients"), 1,
946 GNUNET_NO);
947 put_msg = (const struct GNUNET_DHT_ClientPutMessage *) message;
948 LOG_TRAFFIC (GNUNET_ERROR_TYPE_DEBUG, "X-VINE DHT CLIENT-PUT %s\n",
949 GNUNET_h2s_full (&put_msg->key));
950 /* give to local clients */
951 LOG (GNUNET_ERROR_TYPE_DEBUG,
952 "Handling local PUT of %u-bytes for query %s\n",
953 size - sizeof (struct GNUNET_DHT_ClientPutMessage),
954 GNUNET_h2s (&put_msg->key));
955 DEBUG("PUT doing put i = %s\n",GNUNET_h2s(&(put_msg->key)));
956 GDS_CLIENTS_handle_reply (GNUNET_TIME_absolute_ntoh (put_msg->expiration),
957 &put_msg->key, 0, NULL, 0, NULL,
958 ntohl (put_msg->type),
959 size - sizeof (struct GNUNET_DHT_ClientPutMessage),
960 &put_msg[1]);
961
962 GDS_NEIGHBOURS_handle_put (&put_msg->key,
963 ntohl (put_msg->type), ntohl (put_msg->options),
964 ntohl (put_msg->desired_replication_level),
965 GNUNET_TIME_absolute_ntoh (put_msg->expiration),
966 &put_msg[1],
967 size - sizeof (struct GNUNET_DHT_ClientPutMessage));
968 pm = GNUNET_malloc (sizeof (struct PendingMessage) +
969 sizeof (struct GNUNET_DHT_ClientPutConfirmationMessage));
970 conf = (struct GNUNET_DHT_ClientPutConfirmationMessage *) &pm[1];
971 conf->header.size = htons (sizeof (struct GNUNET_DHT_ClientPutConfirmationMessage));
972 conf->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_CLIENT_PUT_OK);
973 conf->reserved = htonl (0);
974 conf->unique_id = put_msg->unique_id;
975 pm->msg = &conf->header;
976 add_pending_message (find_active_client (client), pm);
977 GNUNET_SERVER_receive_done (client, GNUNET_OK);
978}
979
980
981/**
982 * Handler for DHT GET messages from the client.
983 *
984 * @param cls closure for the service
985 * @param client the client we received this message from
986 * @param message the actual message received
987 */
988static void
989handle_dht_local_get (void *cls,
990 struct GNUNET_SERVER_Client *client,
991 const struct GNUNET_MessageHeader *message)
992{
993 const struct GNUNET_DHT_ClientGetMessage *get;
994 struct ClientQueryRecord *cqr;
995 size_t xquery_size;
996 const char *xquery;
997 uint16_t size;
998
999 size = ntohs (message->size);
1000 if (size < sizeof (struct GNUNET_DHT_ClientGetMessage))
1001 {
1002 GNUNET_break (0);
1003 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1004 return;
1005 }
1006 xquery_size = size - sizeof (struct GNUNET_DHT_ClientGetMessage);
1007 get = (const struct GNUNET_DHT_ClientGetMessage *) message;
1008 xquery = (const char *) &get[1];
1009 GNUNET_STATISTICS_update (GDS_stats,
1010 gettext_noop
1011 ("# GET requests received from clients"), 1,
1012 GNUNET_NO);
1013 LOG (GNUNET_ERROR_TYPE_DEBUG,
1014 "Received GET request for %s from local client %p, xq: %.*s\n",
1015 GNUNET_h2s (&get->key), client, xquery_size, xquery);
1016
1017 LOG_TRAFFIC (GNUNET_ERROR_TYPE_DEBUG, "X-VINE CLIENT-GET %s\n",
1018 GNUNET_h2s_full (&get->key));
1019
1020
1021 cqr = GNUNET_malloc (sizeof (struct ClientQueryRecord) + xquery_size);
1022 cqr->key = get->key;
1023 cqr->client = find_active_client (client);
1024 cqr->xquery = (void *) &cqr[1];
1025 GNUNET_memcpy (&cqr[1], xquery, xquery_size);
1026 cqr->hnode = GNUNET_CONTAINER_heap_insert (retry_heap, cqr, 0);
1027 cqr->retry_frequency = GNUNET_TIME_UNIT_SECONDS;
1028 cqr->retry_time = GNUNET_TIME_absolute_get ();
1029 cqr->unique_id = get->unique_id;
1030 cqr->xquery_size = xquery_size;
1031 cqr->replication = ntohl (get->desired_replication_level);
1032 cqr->msg_options = ntohl (get->options);
1033 cqr->type = ntohl (get->type);
1034
1035 // FIXME use cqr->key, set multihashmap create to GNUNET_YES
1036 GNUNET_CONTAINER_multihashmap_put (forward_map, &get->key, cqr,
1037 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1038
1039 struct GNUNET_PeerIdentity my_identity;
1040 my_identity = GDS_NEIGHBOURS_get_my_id();
1041 GDS_CLIENTS_process_get (ntohl (get->options),
1042 ntohl (get->type),
1043 0,
1044 ntohl (get->desired_replication_level),
1045 1,
1046 &my_identity,
1047 &get->key);
1048 /* start remote requests */
1049 if (NULL != retry_task)
1050 GNUNET_SCHEDULER_cancel (retry_task);
1051 retry_task = GNUNET_SCHEDULER_add_now (&transmit_next_request_task, NULL);
1052 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1053}
1054
1055
1056/**
1057 * Closure for #find_by_unique_id().
1058 */
1059struct FindByUniqueIdContext
1060{
1061 /**
1062 * Where to store the result, if found.
1063 */
1064 struct ClientQueryRecord *cqr;
1065
1066 /**
1067 * Which ID are we looking for?
1068 */
1069 uint64_t unique_id;
1070};
1071
1072
1073/**
1074 * Function called for each existing DHT record for the given
1075 * query. Checks if it matches the UID given in the closure
1076 * and if so returns the entry as a result.
1077 *
1078 * @param cls the search context
1079 * @param key query for the lookup (not used)
1080 * @param value the `struct ClientQueryRecord`
1081 * @return #GNUNET_YES to continue iteration (result not yet found)
1082 */
1083static int
1084find_by_unique_id (void *cls,
1085 const struct GNUNET_HashCode *key,
1086 void *value)
1087{
1088 struct FindByUniqueIdContext *fui_ctx = cls;
1089 struct ClientQueryRecord *cqr = value;
1090
1091 if (cqr->unique_id != fui_ctx->unique_id)
1092 return GNUNET_YES;
1093 fui_ctx->cqr = cqr;
1094 return GNUNET_NO;
1095}
1096
1097
1098/**
1099 * Handler for "GET result seen" messages from the client.
1100 *
1101 * @param cls closure for the service
1102 * @param client the client we received this message from
1103 * @param message the actual message received
1104 */
1105static void
1106handle_dht_local_get_result_seen (void *cls,
1107 struct GNUNET_SERVER_Client *client,
1108 const struct GNUNET_MessageHeader *message)
1109{
1110 const struct GNUNET_DHT_ClientGetResultSeenMessage *seen;
1111 uint16_t size;
1112 unsigned int hash_count;
1113 unsigned int old_count;
1114 const struct GNUNET_HashCode *hc;
1115 struct FindByUniqueIdContext fui_ctx;
1116 struct ClientQueryRecord *cqr;
1117
1118 size = ntohs (message->size);
1119 if (size < sizeof (struct GNUNET_DHT_ClientGetResultSeenMessage))
1120 {
1121 GNUNET_break (0);
1122 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1123 return;
1124 }
1125 seen = (const struct GNUNET_DHT_ClientGetResultSeenMessage *) message;
1126 hash_count = (size - sizeof (struct GNUNET_DHT_ClientGetResultSeenMessage)) / sizeof (struct GNUNET_HashCode);
1127 if (size != sizeof (struct GNUNET_DHT_ClientGetResultSeenMessage) + hash_count * sizeof (struct GNUNET_HashCode))
1128 {
1129 GNUNET_break (0);
1130 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1131 return;
1132 }
1133 hc = (const struct GNUNET_HashCode*) &seen[1];
1134 fui_ctx.unique_id = seen->unique_id;
1135 fui_ctx.cqr = NULL;
1136 GNUNET_CONTAINER_multihashmap_get_multiple (forward_map,
1137 &seen->key,
1138 &find_by_unique_id,
1139 &fui_ctx);
1140 if (NULL == (cqr = fui_ctx.cqr))
1141 {
1142 GNUNET_break (0);
1143 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1144 return;
1145 }
1146 /* finally, update 'seen' list */
1147 old_count = cqr->seen_replies_count;
1148 GNUNET_array_grow (cqr->seen_replies,
1149 cqr->seen_replies_count,
1150 cqr->seen_replies_count + hash_count);
1151 GNUNET_memcpy (&cqr->seen_replies[old_count],
1152 hc,
1153 sizeof (struct GNUNET_HashCode) * hash_count);
1154}
1155
1156
1157/**
1158 * Closure for #remove_by_unique_id().
1159 */
1160struct RemoveByUniqueIdContext
1161{
1162 /**
1163 * Client that issued the removal request.
1164 */
1165 struct ClientList *client;
1166
1167 /**
1168 * Unique ID of the request.
1169 */
1170 uint64_t unique_id;
1171};
1172
1173
1174/**
1175 * Iterator over hash map entries that frees all entries
1176 * that match the given client and unique ID.
1177 *
1178 * @param cls unique ID and client to search for in source routes
1179 * @param key current key code
1180 * @param value value in the hash map, a ClientQueryRecord
1181 * @return #GNUNET_YES (we should continue to iterate)
1182 */
1183static int
1184remove_by_unique_id (void *cls,
1185 const struct GNUNET_HashCode *key,
1186 void *value)
1187{
1188 const struct RemoveByUniqueIdContext *ctx = cls;
1189 struct ClientQueryRecord *record = value;
1190
1191 if (record->unique_id != ctx->unique_id)
1192 return GNUNET_YES;
1193 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1194 "Removing client %p's record for key %s (by unique id)\n",
1195 ctx->client->client_handle, GNUNET_h2s (key));
1196 return remove_client_records (ctx->client, key, record);
1197}
1198
1199
1200/**
1201 * Handler for any generic DHT stop messages, calls the appropriate handler
1202 * depending on message type (if processed locally)
1203 *
1204 * @param cls closure for the service
1205 * @param client the client we received this message from
1206 * @param message the actual message received
1207 *
1208 */
1209static void
1210handle_dht_local_get_stop (void *cls,
1211 struct GNUNET_SERVER_Client *client,
1212 const struct GNUNET_MessageHeader *message)
1213{
1214 const struct GNUNET_DHT_ClientGetStopMessage *dht_stop_msg =
1215 (const struct GNUNET_DHT_ClientGetStopMessage *) message;
1216 struct RemoveByUniqueIdContext ctx;
1217
1218 GNUNET_STATISTICS_update (GDS_stats,
1219 gettext_noop
1220 ("# GET STOP requests received from clients"), 1,
1221 GNUNET_NO);
1222 LOG (GNUNET_ERROR_TYPE_DEBUG,
1223 "Received GET STOP request for %s from local client %p\n",
1224 GNUNET_h2s (&dht_stop_msg->key),
1225 client);
1226 ctx.client = find_active_client (client);
1227 ctx.unique_id = dht_stop_msg->unique_id;
1228 GNUNET_CONTAINER_multihashmap_get_multiple (forward_map, &dht_stop_msg->key,
1229 &remove_by_unique_id, &ctx);
1230 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1231}
1232
1233
1234/**
1235 * Handler for monitor start messages
1236 *
1237 * @param cls closure for the service
1238 * @param client the client we received this message from
1239 * @param message the actual message received
1240 *
1241 */
1242static void
1243handle_dht_local_monitor (void *cls,
1244 struct GNUNET_SERVER_Client *client,
1245 const struct GNUNET_MessageHeader *message)
1246{
1247 struct ClientMonitorRecord *r;
1248 const struct GNUNET_DHT_MonitorStartStopMessage *msg;
1249
1250 msg = (struct GNUNET_DHT_MonitorStartStopMessage *) message;
1251 r = GNUNET_new (struct ClientMonitorRecord);
1252
1253 r->client = find_active_client(client);
1254 r->type = ntohl(msg->type);
1255 r->get = ntohs(msg->get);
1256 r->get_resp = ntohs(msg->get_resp);
1257 r->put = ntohs(msg->put);
1258 if (0 == ntohs(msg->filter_key))
1259 r->key = NULL;
1260 else
1261 {
1262 r->key = GNUNET_new (struct GNUNET_HashCode);
1263 GNUNET_memcpy (r->key, &msg->key, sizeof (struct GNUNET_HashCode));
1264 }
1265 GNUNET_CONTAINER_DLL_insert (monitor_head, monitor_tail, r);
1266 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1267}
1268
1269
1270/**
1271 * Handler for monitor stop messages
1272 *
1273 * @param cls closure for the service
1274 * @param client the client we received this message from
1275 * @param message the actual message received
1276 */
1277static void
1278handle_dht_local_monitor_stop (void *cls,
1279 struct GNUNET_SERVER_Client *client,
1280 const struct GNUNET_MessageHeader *message)
1281{
1282 struct ClientMonitorRecord *r;
1283 const struct GNUNET_DHT_MonitorStartStopMessage *msg;
1284 int keys_match;
1285
1286 msg = (struct GNUNET_DHT_MonitorStartStopMessage *) message;
1287 r = monitor_head;
1288
1289 while (NULL != r)
1290 {
1291 if (NULL == r->key)
1292 keys_match = (0 == ntohs(msg->filter_key));
1293 else
1294 {
1295 keys_match = (0 != ntohs(msg->filter_key)
1296 && !memcmp(r->key, &msg->key, sizeof(struct GNUNET_HashCode)));
1297 }
1298 if (find_active_client(client) == r->client
1299 && ntohl(msg->type) == r->type
1300 && r->get == msg->get
1301 && r->get_resp == msg->get_resp
1302 && r->put == msg->put
1303 && keys_match
1304 )
1305 {
1306 GNUNET_CONTAINER_DLL_remove (monitor_head, monitor_tail, r);
1307 GNUNET_free_non_null (r->key);
1308 GNUNET_free (r);
1309 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1310 return; /* Delete only ONE entry */
1311 }
1312 r = r->next;
1313 }
1314 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1315}
1316
1317
1318/**
1319 * Functions with this signature are called whenever a client
1320 * is disconnected on the network level.
1321 *
1322 * @param cls closure (NULL for dht)
1323 * @param client identification of the client; NULL
1324 * for the last call when the server is destroyed
1325 */
1326static void
1327handle_client_disconnect (void *cls,
1328 struct GNUNET_SERVER_Client *client)
1329{
1330 struct ClientList *pos;
1331 struct PendingMessage *reply;
1332 struct ClientMonitorRecord *monitor;
1333
1334 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1335 "Local client %p disconnects\n",
1336 client);
1337 pos = find_active_client (client);
1338 GNUNET_CONTAINER_DLL_remove (client_head, client_tail, pos);
1339 if (pos->transmit_handle != NULL)
1340 GNUNET_SERVER_notify_transmit_ready_cancel (pos->transmit_handle);
1341 while (NULL != (reply = pos->pending_head))
1342 {
1343 GNUNET_CONTAINER_DLL_remove (pos->pending_head, pos->pending_tail, reply);
1344 GNUNET_free (reply);
1345 }
1346 monitor = monitor_head;
1347 while (NULL != monitor)
1348 {
1349 if (monitor->client == pos)
1350 {
1351 struct ClientMonitorRecord *next;
1352
1353 GNUNET_free_non_null (monitor->key);
1354 next = monitor->next;
1355 GNUNET_CONTAINER_DLL_remove (monitor_head, monitor_tail, monitor);
1356 GNUNET_free (monitor);
1357 monitor = next;
1358 }
1359 else
1360 monitor = monitor->next;
1361 }
1362 GNUNET_CONTAINER_multihashmap_iterate (forward_map, &remove_client_records,
1363 pos);
1364 GNUNET_free (pos);
1365}
1366
1367
1368/**
1369 * Initialize client subsystem.
1370 *
1371 * @param server the initialized server
1372 */
1373void
1374GDS_CLIENTS_init (struct GNUNET_SERVER_Handle *server)
1375{
1376 static struct GNUNET_SERVER_MessageHandler plugin_handlers[] = {
1377 {&handle_dht_local_put, NULL,
1378 GNUNET_MESSAGE_TYPE_DHT_CLIENT_PUT, 0},
1379 {&handle_dht_local_get, NULL,
1380 GNUNET_MESSAGE_TYPE_DHT_CLIENT_GET, 0},
1381 {&handle_dht_local_get_stop, NULL,
1382 GNUNET_MESSAGE_TYPE_DHT_CLIENT_GET_STOP,
1383 sizeof (struct GNUNET_DHT_ClientGetStopMessage)},
1384 {&handle_dht_local_monitor, NULL,
1385 GNUNET_MESSAGE_TYPE_DHT_MONITOR_START,
1386 sizeof (struct GNUNET_DHT_MonitorStartStopMessage)},
1387 {&handle_dht_local_monitor_stop, NULL,
1388 GNUNET_MESSAGE_TYPE_DHT_MONITOR_STOP,
1389 sizeof (struct GNUNET_DHT_MonitorStartStopMessage)},
1390 {&handle_dht_local_get_result_seen, NULL,
1391 GNUNET_MESSAGE_TYPE_DHT_CLIENT_GET_RESULTS_KNOWN, 0},
1392 {NULL, NULL, 0, 0}
1393 };
1394 forward_map = GNUNET_CONTAINER_multihashmap_create (1024, GNUNET_NO);
1395 retry_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
1396 GNUNET_SERVER_add_handlers (server, plugin_handlers);
1397 GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL);
1398}
1399
1400
1401/**
1402 * Shutdown client subsystem.
1403 */
1404void
1405GDS_CLIENTS_done ()
1406{
1407 GNUNET_assert (client_head == NULL);
1408 GNUNET_assert (client_tail == NULL);
1409 if (NULL != retry_task)
1410 {
1411 GNUNET_SCHEDULER_cancel (retry_task);
1412 retry_task = NULL;
1413 }
1414 if (NULL != retry_heap)
1415 {
1416 GNUNET_assert (0 == GNUNET_CONTAINER_heap_get_size (retry_heap));
1417 GNUNET_CONTAINER_heap_destroy (retry_heap);
1418 retry_heap = NULL;
1419 }
1420 if (NULL != forward_map)
1421 {
1422 GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap_size (forward_map));
1423 GNUNET_CONTAINER_multihashmap_destroy (forward_map);
1424 forward_map = NULL;
1425 }
1426}
1427
1428/* end of gnunet-service-wdht_clients.c */
diff --git a/src/dht/gnunet-service-wdht_neighbours.c b/src/dht/gnunet-service-wdht_neighbours.c
deleted file mode 100644
index 78a04d66d..000000000
--- a/src/dht/gnunet-service-wdht_neighbours.c
+++ /dev/null
@@ -1,1768 +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 dht/gnunet-service-wdht_neighbours.c
22 * @brief GNUnet DHT service's finger and friend table management code
23 * @author Supriti Singh
24 * @author Christian Grothoff
25 * @author Arthur Dewarumez
26 *
27 * TODO:
28 * - initiate finding of successors
29 */
30#include "platform.h"
31#include "gnunet_util_lib.h"
32#include "gnunet_block_lib.h"
33#include "gnunet_hello_lib.h"
34#include "gnunet_constants.h"
35#include "gnunet_protocols.h"
36#include "gnunet_ats_service.h"
37#include "gnunet_core_service.h"
38#include "gnunet_datacache_lib.h"
39#include "gnunet_transport_service.h"
40#include "gnunet_dht_service.h"
41#include "gnunet_statistics_service.h"
42#include "gnunet-service-dht.h"
43#include "gnunet-service-dht_datacache.h"
44#include "gnunet-service-dht_neighbours.h"
45#include "gnunet-service-dht_nse.h"
46#include "dht.h"
47
48#define DEBUG(...) \
49 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
50
51/**
52 * Trail timeout. After what time do trails always die?
53 */
54#define TRAIL_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 42)
55
56/**
57 * Random walk delay. How often do we walk the overlay?
58 */
59#define RANDOM_WALK_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 42)
60
61/**
62 * The number of layered ID to use.
63 */
64#define NUMBER_LAYERED_ID 8
65
66/**
67 * The number of random walk to launch at the beginning of the initialization
68 */
69/* FIXME: find a better value */
70#define NUMBER_RANDOM_WALK 20
71
72
73/******************* The db structure and related functions *******************/
74
75/**
76 * Entry in #friends_peermap.
77 */
78struct FriendInfo;
79
80/**
81 *
82 */
83struct FingerTable;
84
85/**
86 * Information we keep per trail.
87 */
88struct Trail
89{
90
91 /**
92 * Identifier of the trail with the predecessor.
93 */
94 struct GNUNET_HashCode pred_id;
95
96 /**
97 * Identifier of the trail with the successor.
98 */
99 struct GNUNET_HashCode succ_id;
100
101 /**
102 * When does this trail expire.
103 */
104 struct GNUNET_TIME_Absolute expiration_time;
105
106 /**
107 * MDLL entry in the list of all trails with the same predecessor.
108 */
109 struct Trail *prev_succ;
110
111 /**
112 * MDLL entry in the list of all trails with the same predecessor.
113 */
114 struct Trail *next_succ;
115
116 /**
117 * MDLL entry in the list of all trails with the same predecessor.
118 */
119 struct Trail *prev_pred;
120
121 /**
122 * MDLL entry in the list of all trails with the same predecessor.
123 */
124 struct Trail *next_pred;
125
126 /**
127 * Our predecessor in the trail, NULL if we are initiator (?).
128 */
129 struct FriendInfo *pred;
130
131 /**
132 * Our successor in the trail, NULL if we are the last peer.
133 */
134 struct FriendInfo *succ;
135
136 /**
137 * Location of this trail in the heap.
138 */
139 struct GNUNET_CONTAINER_HeapNode *hn;
140
141 /**
142 * If this peer started the to create a Finger (and thus @e pred is
143 * NULL), this is the finger table of the finger we are trying to
144 * intialize.
145 */
146 struct FingerTable *ft;
147
148 /**
149 * If this peer started the trail to create a Finger (and thus @e
150 * pred is NULL), this is the offset of the finger we are trying to
151 * intialize in the unsorted array.
152 */
153 unsigned int finger_off;
154
155};
156
157
158/**
159 * Entry in #friends_peermap.
160 */
161struct FriendInfo
162{
163 /**
164 * Friend Identity
165 */
166 const struct GNUNET_PeerIdentity *id;
167
168 /**
169 *
170 */
171 struct Trail *pred_head;
172
173 /**
174 *
175 */
176 struct Trail *pred_tail;
177
178 /**
179 *
180 */
181 struct Trail *succ_head;
182
183 /**
184 *
185 */
186 struct Trail *succ_tail;
187
188 /**
189 * Core handle for sending messages to this friend.
190 */
191 struct GNUNET_MQ_Handle *mq;
192
193};
194
195
196/**
197 *
198 */
199struct Finger
200{
201 /**
202 *
203 */
204 struct Trail *trail;
205
206 /**
207 *
208 */
209 struct FingerTable *ft;
210
211 /**
212 *
213 */
214 struct GNUNET_HashCode destination;
215
216 /**
217 * #GNUNET_YES if a response has been received. Otherwise #GNUNET_NO.
218 */
219 int valid;
220};
221
222
223struct FingerTable
224{
225 /**
226 * Array of our fingers, unsorted.
227 */
228 struct Finger **fingers;
229
230 /**
231 * Size of the finger array.
232 */
233 unsigned int finger_array_size;
234
235 /**
236 * Number of valid entries in @e fingers
237 */
238 unsigned int number_valid_fingers;
239
240 /**
241 * Which offset in @e fingers will we redo next.
242 */
243 unsigned int walk_offset;
244
245 /**
246 * Is the finger array sorted?
247 */
248 int is_sorted;
249
250};
251
252
253/*********************** end of the db structure part ***********************/
254
255
256GNUNET_NETWORK_STRUCT_BEGIN
257
258/**
259 * Setup a finger using the underlay topology ("social network").
260 */
261struct RandomWalkMessage
262{
263 /**
264 * Type: #GNUNET_MESSAGE_TYPE_WDHT_RANDOM_WALK
265 */
266 struct GNUNET_MessageHeader header;
267
268 /**
269 * Number of hops this message has taken so far, we stop at
270 * log(NSE), in NBO.
271 */
272 uint16_t hops_taken GNUNET_PACKED;
273
274 /**
275 * Layer for the request, in NBO.
276 */
277 uint16_t layer GNUNET_PACKED;
278
279 /**
280 * Unique (random) identifier this peer will use to
281 * identify the trail (in future messages).
282 */
283 struct GNUNET_HashCode trail_id;
284
285};
286
287/**
288 * Response to a `struct RandomWalkMessage`.
289 */
290struct RandomWalkResponseMessage
291{
292 /**
293 * Type: #GNUNET_MESSAGE_TYPE_WDHT_RANDOM_WALK_RESPONSE
294 */
295 struct GNUNET_MessageHeader header;
296
297 /**
298 * Zero, for alignment.
299 */
300 uint32_t reserved GNUNET_PACKED;
301
302 /**
303 * Unique (random) identifier from the
304 * `struct RandomWalkMessage`.
305 */
306 struct GNUNET_HashCode trail_id;
307
308 /**
309 * Random location in the respective layer where the
310 * random path of the finger setup terminated.
311 */
312 struct GNUNET_HashCode location;
313
314};
315
316/**
317 * Response to an event that causes a trail to die.
318 */
319struct TrailDestroyMessage
320{
321 /**
322 * Type: #GNUNET_MESSAGE_TYPE_WDHT_TRAIL_DESTROY
323 */
324 struct GNUNET_MessageHeader header;
325
326 /**
327 * Zero, for alignment.
328 */
329 uint32_t reserved GNUNET_PACKED;
330
331 /**
332 * Unique (random) identifier this peer will use to
333 * identify the finger (in future messages).
334 */
335 struct GNUNET_HashCode trail_id;
336
337};
338
339
340/**
341 * Send a message along a trail.
342 */
343struct FindSuccessorMessage
344{
345 /**
346 * Type: #GNUNET_MESSAGE_TYPE_WDHT_SUCCESSOR_FIND
347 */
348 struct GNUNET_MessageHeader header;
349
350 /**
351 * Zero, for alignment.
352 */
353 uint32_t reserved GNUNET_PACKED;
354
355 /**
356 * Key for which we would like close values returned.
357 * identify the finger (in future messages).
358 */
359 struct GNUNET_HashCode key;
360
361};
362
363
364/**
365 * Send a message along a trail.
366 */
367struct TrailRouteMessage
368{
369 /**
370 * Type: #GNUNET_MESSAGE_TYPE_WDHT_TRAIL_ROUTE
371 */
372 struct GNUNET_MessageHeader header;
373
374 /**
375 * #GNUNET_YES if the path should be recorded, #GNUNET_NO if not; in NBO.
376 */
377 uint16_t record_path GNUNET_PACKED;
378
379 /**
380 * Length of the recorded trail, 0 if @e record_path is #GNUNET_NO; in NBO.
381 */
382 uint16_t path_length GNUNET_PACKED;
383
384 /**
385 * Unique (random) identifier this peer will use to
386 * identify the finger (in future messages).
387 */
388 struct GNUNET_HashCode trail_id;
389
390 /**
391 * Path the message has taken so far (excluding sender).
392 */
393 /* struct GNUNET_PeerIdentity path[path_length]; */
394
395 /* followed by payload (another `struct GNUNET_MessageHeader`) to
396 send along the trail */
397};
398
399
400/**
401 * P2P PUT message
402 */
403struct PeerPutMessage
404{
405 /**
406 * Type: #GNUNET_MESSAGE_TYPE_WDHT_PUT
407 */
408 struct GNUNET_MessageHeader header;
409
410 /**
411 * Processing options
412 */
413 uint32_t options GNUNET_PACKED;
414
415 /**
416 * Content type.
417 */
418 uint32_t block_type GNUNET_PACKED;
419
420 /**
421 * Hop count
422 */
423 uint32_t hop_count GNUNET_PACKED;
424
425 /**
426 * Replication level for this message
427 * In the current implementation, this value is not used.
428 */
429 uint32_t desired_replication_level GNUNET_PACKED;
430
431 /**
432 * Length of the PUT path that follows (if tracked).
433 */
434 uint32_t put_path_length GNUNET_PACKED;
435
436 /**
437 * When does the content expire?
438 */
439 struct GNUNET_TIME_AbsoluteNBO expiration_time;
440
441 /**
442 * The key to store the value under.
443 */
444 struct GNUNET_HashCode key GNUNET_PACKED;
445
446 /* put path (if tracked) */
447
448 /* Payload */
449
450};
451
452/**
453 * P2P GET message
454 */
455struct PeerGetMessage
456{
457 /**
458 * Type: #GNUNET_MESSAGE_TYPE_WDHT_GET
459 */
460 struct GNUNET_MessageHeader header;
461
462 /**
463 * Processing options
464 */
465 uint32_t options GNUNET_PACKED;
466
467 /**
468 * Desired content type.
469 */
470 uint32_t block_type GNUNET_PACKED;
471
472 /**
473 * Hop count
474 */
475 uint32_t hop_count GNUNET_PACKED;
476
477 /**
478 * Desired replication level for this request.
479 * In the current implementation, this value is not used.
480 */
481 uint32_t desired_replication_level GNUNET_PACKED;
482
483 /**
484 * Total number of peers in get path.
485 */
486 unsigned int get_path_length;
487
488 /**
489 * The key we are looking for.
490 */
491 struct GNUNET_HashCode key;
492
493 /* Get path. */
494 /* struct GNUNET_PeerIdentity[]*/
495};
496
497
498/**
499 * P2P Result message
500 */
501struct PeerGetResultMessage
502{
503 /**
504 * Type: #GNUNET_MESSAGE_TYPE_WDHT_GET_RESULT
505 */
506 struct GNUNET_MessageHeader header;
507
508 /**
509 * The type for the data in NBO.
510 */
511 uint32_t type GNUNET_PACKED;
512
513 /**
514 * Number of peers recorded in the outgoing path from source to the
515 * stored location of this message.
516 */
517 uint32_t put_path_length GNUNET_PACKED;
518
519 /**
520 * When does the content expire?
521 */
522 struct GNUNET_TIME_AbsoluteNBO expiration_time;
523
524 /**
525 * The key of the corresponding GET request.
526 */
527 struct GNUNET_HashCode key;
528
529 /* put path (if tracked) */
530
531 /* Payload */
532
533};
534
535GNUNET_NETWORK_STRUCT_END
536
537
538/**
539 * Contains all the layered IDs of this peer.
540 */
541struct GNUNET_PeerIdentity layered_id[NUMBER_LAYERED_ID];
542
543/**
544 * Task to timeout trails that have expired.
545 */
546static struct GNUNET_SCHEDULER_Task *trail_timeout_task;
547
548/**
549 * Task to perform random walks.
550 */
551static struct GNUNET_SCHEDULER_Task *random_walk_task;
552
553/**
554 * Identity of this peer.
555 */
556static struct GNUNET_PeerIdentity my_identity;
557
558/**
559 * Peer map of all the friends of a peer
560 */
561static struct GNUNET_CONTAINER_MultiPeerMap *friends_peermap;
562
563/**
564 * Fingers per layer.
565 */
566static struct FingerTable fingers[NUMBER_LAYERED_ID];
567
568/**
569 * Tail map, mapping tail identifiers to `struct Trail`s
570 */
571static struct GNUNET_CONTAINER_MultiHashMap *trail_map;
572
573/**
574 * Tail heap, organizing trails by expiration time.
575 */
576static struct GNUNET_CONTAINER_Heap *trail_heap;
577
578/**
579 * Handle to CORE.
580 */
581static struct GNUNET_CORE_Handle *core_api;
582
583
584/**
585 * Handle the put request from the client.
586 *
587 * @param block_type Type of the block
588 * @param options routing options
589 * @param desired_replication_level desired replication level
590 * @param expiration_time when does the content expire
591 * @param hop_count how many hops has this message traversed so far
592 * @param bf Bloom filter of peers this PUT has already traversed
593 * @param key key for the content
594 * @param put_path_length number of entries in put_path
595 * @param put_path peers this request has traversed so far (if tracked)
596 * @param data payload to store
597 * @param data_size number of bytes in data
598 * @return #GNUNET_OK if the request was forwarded, #GNUNET_NO if not
599 */
600int
601GDS_NEIGHBOURS_handle_put (enum GNUNET_BLOCK_Type block_type,
602 enum GNUNET_DHT_RouteOption options,
603 uint32_t desired_replication_level,
604 struct GNUNET_TIME_Absolute expiration_time,
605 uint32_t hop_count,
606 struct GNUNET_CONTAINER_BloomFilter *bf,
607 const struct GNUNET_HashCode *key,
608 unsigned int put_path_length,
609 struct GNUNET_PeerIdentity *put_path,
610 const void *data,
611 size_t data_size)
612{
613 GDS_DATACACHE_handle_put (expiration_time,
614 key,
615 0, NULL,
616 block_type,
617 data_size,
618 data);
619 GDS_CLIENTS_process_put (options,
620 block_type,
621 hop_count,
622 desired_replication_level,
623 put_path_length, put_path,
624 expiration_time,
625 key,
626 data,
627 data_size);
628 return GNUNET_OK; /* FIXME... */
629}
630
631
632/**
633 * Perform a GET operation. Forwards the given request to other
634 * peers. Does not lookup the key locally. May do nothing if this is
635 * the only peer in the network (or if we are the closest peer in the
636 * network).
637 *
638 * @param type type of the block
639 * @param options routing options
640 * @param desired_replication_level desired replication count
641 * @param hop_count how many hops did this request traverse so far?
642 * @param key key for the content
643 * @param xquery extended query
644 * @param xquery_size number of bytes in @a xquery
645 * @param reply_bf bloomfilter to filter duplicates
646 * @param reply_bf_mutator mutator for @a reply_bf
647 * @param peer_bf filter for peers not to select (again, updated)
648 * @return #GNUNET_OK if the request was forwarded, #GNUNET_NO if not
649 */
650int
651GDS_NEIGHBOURS_handle_get (enum GNUNET_BLOCK_Type type,
652 enum GNUNET_DHT_RouteOption options,
653 uint32_t desired_replication_level,
654 uint32_t hop_count,
655 const struct GNUNET_HashCode *key,
656 const void *xquery, size_t xquery_size,
657 const struct GNUNET_CONTAINER_BloomFilter *reply_bf,
658 uint32_t reply_bf_mutator,
659 struct GNUNET_CONTAINER_BloomFilter *peer_bf)
660{
661 // find closest finger(s) on all layers
662 // use TrailRoute with PeerGetMessage embedded to contact peer
663 // NOTE: actually more complicated, see paper!
664 GNUNET_break (0); // not implemented!
665 return GNUNET_SYSERR;
666}
667
668
669/**
670 * Delete a trail, it died (timeout, link failure, etc.).
671 *
672 * @param trail trail to delete from all data structures
673 * @param inform_pred should we notify the predecessor?
674 * @param inform_succ should we inform the successor?
675 */
676static void
677delete_trail (struct Trail *trail,
678 int inform_pred,
679 int inform_succ)
680{
681 struct FriendInfo *friend;
682 struct GNUNET_MQ_Envelope *env;
683 struct TrailDestroyMessage *tdm;
684 struct Finger *finger;
685
686 friend = trail->pred;
687 if (NULL != friend)
688 {
689 if (GNUNET_YES == inform_pred)
690 {
691 env = GNUNET_MQ_msg (tdm,
692 GNUNET_MESSAGE_TYPE_WDHT_TRAIL_DESTROY);
693 tdm->trail_id = trail->pred_id;
694 GNUNET_MQ_send (friend->mq,
695 env);
696 }
697 GNUNET_CONTAINER_MDLL_remove (pred,
698 friend->pred_head,
699 friend->pred_tail,
700 trail);
701 }
702 friend = trail->succ;
703 if (NULL != friend)
704 {
705 if (GNUNET_YES == inform_succ)
706 {
707 env = GNUNET_MQ_msg (tdm,
708 GNUNET_MESSAGE_TYPE_WDHT_TRAIL_DESTROY);
709 tdm->trail_id = trail->pred_id;
710 GNUNET_MQ_send (friend->mq,
711 env);
712 }
713 GNUNET_CONTAINER_MDLL_remove (succ,
714 friend->pred_head,
715 friend->pred_tail,
716 trail);
717 }
718 GNUNET_break (trail ==
719 GNUNET_CONTAINER_heap_remove_node (trail->hn));
720 finger = trail->ft->fingers[trail->finger_off];
721 if (NULL != finger)
722 {
723 trail->ft->fingers[trail->finger_off] = NULL;
724 trail->ft->number_valid_fingers--;
725 GNUNET_free (finger);
726 }
727 GNUNET_free (trail);
728}
729
730
731/**
732 * Forward the given payload message along the trail.
733 *
734 * @param next_target which direction along the trail should we forward
735 * @param trail_id which trail should we forward along
736 * @param have_path do we track the forwarding path?
737 * @param predecessor which peer do we tack on to the path?
738 * @param path path the message has taken so far along the trail
739 * @param path_length number of entries in @a path
740 * @param payload payload of the message
741 */
742static void
743forward_message_on_trail (struct FriendInfo *next_target,
744 const struct GNUNET_HashCode *trail_id,
745 int have_path,
746 const struct GNUNET_PeerIdentity *predecessor,
747 const struct GNUNET_PeerIdentity *path,
748 uint16_t path_length,
749 const struct GNUNET_MessageHeader *payload)
750{
751 struct GNUNET_MQ_Envelope *env;
752 struct TrailRouteMessage *trm;
753 struct GNUNET_PeerIdentity *new_path;
754 unsigned int plen;
755 uint16_t payload_len;
756
757 payload_len = ntohs (payload->size);
758 if (have_path)
759 {
760 plen = path_length + 1;
761 if (plen >= (GNUNET_SERVER_MAX_MESSAGE_SIZE
762 - payload_len
763 - sizeof (struct TrailRouteMessage))
764 / sizeof (struct GNUNET_PeerIdentity))
765 {
766 /* Should really not have paths this long... */
767 GNUNET_break_op (0);
768 plen = 0;
769 have_path = 0;
770 }
771 }
772 else
773 {
774 GNUNET_break_op (0 == path_length);
775 path_length = 0;
776 plen = 0;
777 }
778 env = GNUNET_MQ_msg_extra (trm,
779 payload_len +
780 plen * sizeof (struct GNUNET_PeerIdentity),
781 GNUNET_MESSAGE_TYPE_WDHT_TRAIL_ROUTE);
782 trm->record_path = htons (have_path);
783 trm->path_length = htons (plen);
784 trm->trail_id = *trail_id;
785 new_path = (struct GNUNET_PeerIdentity *) &trm[1];
786 if (have_path)
787 {
788 GNUNET_memcpy (new_path,
789 path,
790 path_length * sizeof (struct GNUNET_PeerIdentity));
791 new_path[path_length] = *predecessor;
792 }
793 GNUNET_memcpy (&new_path[plen],
794 payload,
795 payload_len);
796 GNUNET_MQ_send (next_target->mq,
797 env);
798}
799
800
801/**
802 * Send the get result to requesting client.
803 *
804 * @param cls trail identifying where to send the result to, NULL for us
805 * @param options routing options (from GET request)
806 * @param key Key of the requested data.
807 * @param type Block type
808 * @param put_path_length Number of peers in @a put_path
809 * @param put_path Path taken to put the data at its stored location.
810 * @param expiration When will this result expire?
811 * @param data Payload to store
812 * @param data_size Size of the @a data
813 */
814void
815GDS_NEIGHBOURS_send_get_result (void *cls,
816 enum GNUNET_DHT_RouteOption options,
817 const struct GNUNET_HashCode *key,
818 enum GNUNET_BLOCK_Type type,
819 unsigned int put_path_length,
820 const struct GNUNET_PeerIdentity *put_path,
821 struct GNUNET_TIME_Absolute expiration,
822 const void *data,
823 size_t data_size)
824{
825 const struct GNUNET_HashCode *trail_id = cls;
826 struct GNUNET_MessageHeader *payload;
827 struct Trail *trail;
828
829 trail = GNUNET_CONTAINER_multihashmap_get (trail_map,
830 trail_id);
831 if (NULL == trail)
832 {
833 /* TODO: inform statistics */
834 return;
835 }
836 if (NULL == trail->pred)
837 {
838 /* result is for *us* (local client) */
839 GDS_CLIENTS_handle_reply (expiration,
840 key,
841 0, NULL,
842 put_path_length, put_path,
843 type,
844 data_size,
845 data);
846 return;
847 }
848
849 payload = GNUNET_malloc(sizeof(struct GNUNET_MessageHeader) + data_size);
850 payload->size = data_size;
851 payload->type = GNUNET_MESSAGE_TYPE_WDHT_GET_RESULT;
852
853 forward_message_on_trail (trail->pred,
854 trail_id,
855 0 != (options & GNUNET_DHT_RO_RECORD_ROUTE),
856 &my_identity,
857 NULL, 0,
858 payload);
859 GNUNET_free (payload);
860}
861
862
863/**
864 * Method called whenever a peer disconnects.
865 *
866 * @param cls closure
867 * @param peer peer identity this notification is about
868 * @param internal_cls our `struct FriendInfo` for @a peer
869 */
870static void
871handle_core_disconnect (void *cls,
872 const struct GNUNET_PeerIdentity *peer,
873 void *internal_cls)
874{
875 struct FriendInfo *remove_friend = internal_cls;
876 struct Trail *t;
877
878 /* If disconnected to own identity, then return. */
879 if (NULL == remove_friend)
880 return;
881 GNUNET_assert (GNUNET_YES ==
882 GNUNET_CONTAINER_multipeermap_remove (friends_peermap,
883 peer,
884 remove_friend));
885 while (NULL != (t = remove_friend->succ_head))
886 delete_trail (t,
887 GNUNET_YES,
888 GNUNET_NO);
889 while (NULL != (t = remove_friend->pred_head))
890 delete_trail (t,
891 GNUNET_NO,
892 GNUNET_YES);
893 GNUNET_free (remove_friend);
894 if (0 == GNUNET_CONTAINER_multipeermap_size (friends_peermap))
895 {
896 GNUNET_SCHEDULER_cancel (random_walk_task);
897 random_walk_task = NULL;
898 }
899}
900
901
902/**
903 * Function called with a random friend to be returned.
904 *
905 * @param cls a `struct FriendInfo **` with where to store the result
906 * @param peer the peer identity of the friend (ignored)
907 * @param value the `struct FriendInfo *` that was selected at random
908 * @return #GNUNET_OK (all good)
909 */
910static int
911pick_random_helper (void *cls,
912 const struct GNUNET_PeerIdentity *peer,
913 void *value)
914{
915 struct FriendInfo **fi = cls;
916 struct FriendInfo *v = value;
917
918 *fi = v;
919 return GNUNET_OK;
920}
921
922
923/**
924 * Pick random friend from friends for random walk.
925 *
926 * @return NULL if we have no friends
927 */
928static struct FriendInfo *
929pick_random_friend ()
930{
931 struct FriendInfo *ret;
932
933 ret = NULL;
934 if (0 ==
935 GNUNET_CONTAINER_multipeermap_get_random (friends_peermap,
936 &pick_random_helper,
937 &ret))
938 return NULL;
939 return ret;
940}
941
942
943/**
944 * One of our trails might have timed out, check and
945 * possibly initiate cleanup.
946 *
947 * @param cls NULL
948 */
949static void
950trail_timeout_callback (void *cls)
951{
952 struct Trail *trail;
953 struct GNUNET_TIME_Relative left;
954
955 trail_timeout_task = NULL;
956 while (NULL != (trail = GNUNET_CONTAINER_heap_peek (trail_heap)))
957 {
958 left = GNUNET_TIME_absolute_get_remaining (trail->expiration_time);
959 if (0 != left.rel_value_us)
960 break;
961 delete_trail (trail,
962 GNUNET_YES,
963 GNUNET_YES);
964 }
965 if (NULL != trail)
966 trail_timeout_task = GNUNET_SCHEDULER_add_delayed (left,
967 &trail_timeout_callback,
968 NULL);
969}
970
971
972/**
973 * Compute how big our finger arrays should be (at least).
974 *
975 * @return size of the finger array, never 0
976 */
977static unsigned int
978get_desired_finger_array_size ()
979{
980 /* FIXME: This is just a stub... */
981 return 64;
982}
983
984
985/**
986 * Initiate a random walk.
987 *
988 * @param cls NULL
989 */
990static void
991do_random_walk (void *cls)
992{
993 static unsigned int walk_layer;
994 struct FriendInfo *friend;
995 struct GNUNET_MQ_Envelope *env;
996 struct RandomWalkMessage *rwm;
997 struct FingerTable *ft;
998 struct Finger *finger;
999 struct Trail *trail;
1000 unsigned int nsize;
1001
1002 random_walk_task = NULL;
1003 friend = pick_random_friend ();
1004
1005 trail = GNUNET_new (struct Trail);
1006 /* We create the random walk so, no predecessor */
1007 trail->succ = friend;
1008 GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_NONCE,
1009 &trail->succ_id);
1010 if (GNUNET_OK !=
1011 GNUNET_CONTAINER_multihashmap_put (trail_map,
1012 &trail->succ_id,
1013 trail,
1014 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1015 {
1016 GNUNET_break (0);
1017 GNUNET_free (trail);
1018 return;
1019 }
1020 GNUNET_CONTAINER_MDLL_insert (succ,
1021 friend->succ_head,
1022 friend->succ_tail,
1023 trail);
1024 trail->expiration_time = GNUNET_TIME_relative_to_absolute (TRAIL_TIMEOUT);
1025 trail->hn = GNUNET_CONTAINER_heap_insert (trail_heap,
1026 trail,
1027 trail->expiration_time.abs_value_us);
1028 if (NULL == trail_timeout_task)
1029 trail_timeout_task = GNUNET_SCHEDULER_add_delayed (TRAIL_TIMEOUT,
1030 &trail_timeout_callback,
1031 NULL);
1032 env = GNUNET_MQ_msg (rwm,
1033 GNUNET_MESSAGE_TYPE_WDHT_RANDOM_WALK);
1034 rwm->hops_taken = htonl (0);
1035 rwm->trail_id = trail->succ_id;
1036 GNUNET_MQ_send (friend->mq,
1037 env);
1038 /* clean up 'old' entry (implicitly via trail cleanup) */
1039 ft = &fingers[walk_layer];
1040
1041 if ( (NULL != ft->fingers) &&
1042 (NULL != (finger = ft->fingers[ft->walk_offset])) )
1043 delete_trail (finger->trail,
1044 GNUNET_NO,
1045 GNUNET_YES);
1046 if (ft->finger_array_size < (nsize = get_desired_finger_array_size()) )
1047 GNUNET_array_grow (ft->fingers,
1048 ft->finger_array_size,
1049 nsize);
1050 GNUNET_assert (NULL == ft->fingers[ft->walk_offset]);
1051 trail->ft = ft;
1052 trail->finger_off = ft->walk_offset;
1053 finger = GNUNET_new (struct Finger);
1054 finger->trail = trail;
1055 finger->ft = ft;
1056 ft->fingers[ft->walk_offset] = finger;
1057 ft->is_sorted = GNUNET_NO;
1058 ft->number_valid_fingers++;
1059 ft->walk_offset = (ft->walk_offset + 1) % ft->finger_array_size;
1060
1061 walk_layer = (walk_layer + 1) % NUMBER_LAYERED_ID;
1062 random_walk_task = GNUNET_SCHEDULER_add_delayed (RANDOM_WALK_DELAY,
1063 &do_random_walk,
1064 NULL);
1065}
1066
1067
1068/**
1069 * Method called whenever a peer connects.
1070 *
1071 * @param cls closure
1072 * @param peer_identity peer identity this notification is about
1073 * @param mq message queue for transmission to @a peer_identity
1074 * @return the `struct FriendInfo` for the @a peer_identity, NULL for us
1075 */
1076static void *
1077handle_core_connect (void *cls,
1078 const struct GNUNET_PeerIdentity *peer_identity,
1079 struct GNUNET_MQ_Handle *mq)
1080{
1081 struct FriendInfo *friend;
1082
1083 /* Check for connect to self message */
1084 if (0 == memcmp (&my_identity,
1085 peer_identity,
1086 sizeof (struct GNUNET_PeerIdentity)))
1087 return NULL;
1088
1089 friend = GNUNET_new (struct FriendInfo);
1090 friend->id = peer_identity;
1091 friend->mq = mq;
1092 GNUNET_assert (GNUNET_OK ==
1093 GNUNET_CONTAINER_multipeermap_put (friends_peermap,
1094 peer_identity,
1095 friend,
1096 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1097 if (NULL == random_walk_task)
1098 {
1099 /* random walk needs to be started -- we have a first connection */
1100 random_walk_task = GNUNET_SCHEDULER_add_now (&do_random_walk,
1101 NULL);
1102 }
1103 return friend;
1104}
1105
1106
1107/**
1108 * To be called on core init/fail.
1109 *
1110 * @param cls service closure
1111 * @param identity the public identity of this peer
1112 */
1113static void
1114core_init (void *cls,
1115 const struct GNUNET_PeerIdentity *identity)
1116{
1117 my_identity = *identity;
1118}
1119
1120
1121/**
1122 * Handle a `struct RandomWalkMessage` from a
1123 * #GNUNET_MESSAGE_TYPE_WDHT_RANDOM_WALK message.
1124 *
1125 * @param cls the `struct FriendInfo` for the sender
1126 * @param m the setup message
1127 */
1128static void
1129handle_dht_p2p_random_walk (void *cls,
1130 const struct RandomWalkMessage *m)
1131{
1132 struct FriendInfo *pred = cls;
1133 struct Trail *t;
1134 uint16_t layer;
1135
1136 layer = ntohs (m->layer);
1137 if (layer > NUMBER_LAYERED_ID)
1138 {
1139 GNUNET_break_op (0);
1140 return;
1141 }
1142 t = GNUNET_new (struct Trail);
1143 t->pred_id = m->trail_id;
1144 t->pred = pred;
1145 if (GNUNET_OK !=
1146 GNUNET_CONTAINER_multihashmap_put (trail_map,
1147 &t->pred_id,
1148 t,
1149 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1150 {
1151 GNUNET_break_op (0);
1152 GNUNET_free (t);
1153 return;
1154 }
1155 GNUNET_CONTAINER_MDLL_insert (pred,
1156 pred->pred_head,
1157 pred->pred_tail,
1158 t);
1159 t->expiration_time = GNUNET_TIME_relative_to_absolute (TRAIL_TIMEOUT);
1160 t->hn = GNUNET_CONTAINER_heap_insert (trail_heap,
1161 t,
1162 t->expiration_time.abs_value_us);
1163 if (NULL == trail_timeout_task)
1164 trail_timeout_task = GNUNET_SCHEDULER_add_delayed (TRAIL_TIMEOUT,
1165 &trail_timeout_callback,
1166 NULL);
1167
1168 if (ntohl (m->hops_taken) > GDS_NSE_get ())
1169 {
1170 /* We are the last hop, generate response */
1171 struct GNUNET_MQ_Envelope *env;
1172 struct RandomWalkResponseMessage *rwrm;
1173
1174 env = GNUNET_MQ_msg (rwrm,
1175 GNUNET_MESSAGE_TYPE_WDHT_RANDOM_WALK_RESPONSE);
1176 rwrm->reserved = htonl (0);
1177 rwrm->trail_id = m->trail_id;
1178 if (0 == layer)
1179 (void) GDS_DATACACHE_get_random_key (&rwrm->location);
1180 else
1181 {
1182 struct FingerTable *ft;
1183
1184 ft = &fingers[layer-1];
1185 if (0 == ft->number_valid_fingers)
1186 {
1187 GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_NONCE,
1188 &rwrm->location);
1189 }
1190 else
1191 {
1192 struct Finger *f;
1193 unsigned int off;
1194 unsigned int i;
1195
1196 off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
1197 ft->number_valid_fingers);
1198 for (i=0; (NULL == (f = ft->fingers[i])) || (off > 0); i++)
1199 if (NULL != f) off--;
1200 rwrm->location = f->destination;
1201 }
1202 }
1203 GNUNET_MQ_send (pred->mq,
1204 env);
1205 }
1206 else
1207 {
1208 struct GNUNET_MQ_Envelope *env;
1209 struct RandomWalkMessage *rwm;
1210 struct FriendInfo *succ;
1211
1212 /* extend the trail by another random hop */
1213 succ = pick_random_friend ();
1214 GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_NONCE,
1215 &t->succ_id);
1216 t->succ = succ;
1217 if (GNUNET_OK !=
1218 GNUNET_CONTAINER_multihashmap_put (trail_map,
1219 &t->succ_id,
1220 t,
1221 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1222 {
1223 GNUNET_break (0);
1224 GNUNET_CONTAINER_MDLL_remove (pred,
1225 pred->pred_head,
1226 pred->pred_tail,
1227 t);
1228 GNUNET_free (t);
1229 return;
1230 }
1231 GNUNET_CONTAINER_MDLL_insert (succ,
1232 succ->succ_head,
1233 succ->succ_tail,
1234 t);
1235 env = GNUNET_MQ_msg (rwm,
1236 GNUNET_MESSAGE_TYPE_WDHT_RANDOM_WALK);
1237 rwm->hops_taken = htons (1 + ntohs (m->hops_taken));
1238 rwm->layer = m->layer;
1239 rwm->trail_id = t->succ_id;
1240 GNUNET_MQ_send (succ->mq,
1241 env);
1242 }
1243}
1244
1245
1246/**
1247 * Handle a `struct RandomWalkResponseMessage`.
1248 *
1249 * @param cls closure
1250 * @param rwrm the setup response message
1251 */
1252static void
1253handle_dht_p2p_random_walk_response (void *cls,
1254 const struct RandomWalkResponseMessage *rwrm)
1255{
1256 struct Trail *trail;
1257 struct FriendInfo *pred;
1258 struct FingerTable *ft;
1259 struct Finger *finger;
1260
1261 trail = GNUNET_CONTAINER_multihashmap_get (trail_map,
1262 &rwrm->trail_id);
1263 if (NULL == trail)
1264 {
1265 /* TODO: log/statistics: we didn't find the trail (can happen) */
1266 return;
1267 }
1268 if (NULL != (pred = trail->pred))
1269 {
1270 /* We are not the first hop, keep forwarding */
1271 struct GNUNET_MQ_Envelope *env;
1272 struct RandomWalkResponseMessage *rwrm2;
1273
1274 env = GNUNET_MQ_msg (rwrm2,
1275 GNUNET_MESSAGE_TYPE_WDHT_RANDOM_WALK_RESPONSE);
1276 rwrm2->reserved = htonl (0);
1277 rwrm2->location = rwrm->location;
1278 rwrm2->trail_id = trail->pred_id;
1279 GNUNET_MQ_send (pred->mq,
1280 env);
1281 return;
1282 }
1283 /* We are the first hop, complete finger */
1284 if (NULL == (ft = trail->ft))
1285 {
1286 /* Eh, why did we create the trail if we have no FT? */
1287 GNUNET_break (0);
1288 delete_trail (trail,
1289 GNUNET_NO,
1290 GNUNET_YES);
1291 return;
1292 }
1293 if (NULL == (finger = ft->fingers[trail->finger_off]))
1294 {
1295 /* Eh, finger got deleted, but why not the trail as well? */
1296 GNUNET_break (0);
1297 delete_trail (trail,
1298 GNUNET_NO,
1299 GNUNET_YES);
1300 return;
1301 }
1302
1303
1304 // 1) lookup trail => find Finger entry => fill in 'destination' and mark valid, move to end of sorted array,
1305 //mark unsorted, update links from 'trails'
1306 /*
1307 * Steps :
1308 * 1 check if we are the correct layer
1309 * 1.a if true : add the returned value (finger) in the db structure
1310 * 1.b if true : do nothing
1311 */
1312 /* FIXME: add the value in db structure 1.a */
1313
1314}
1315
1316
1317/**
1318 * Handle a `struct TrailDestroyMessage`.
1319 *
1320 * @param cls closure
1321 * @param tdm the trail destroy message
1322 */
1323static void
1324handle_dht_p2p_trail_destroy (void *cls,
1325 const struct TrailDestroyMessage *tdm)
1326{
1327 struct FriendInfo *sender = cls;
1328 struct Trail *trail;
1329
1330 trail = GNUNET_CONTAINER_multihashmap_get (trail_map,
1331 &tdm->trail_id);
1332 delete_trail (trail,
1333 ( (NULL != trail->succ) &&
1334 (0 == memcmp (sender->id,
1335 &trail->succ->id,
1336 sizeof (struct GNUNET_PeerIdentity))) ),
1337 ( (NULL != trail->pred) &&
1338 (0 == memcmp (sender->id,
1339 &trail->pred->id,
1340 sizeof (struct GNUNET_PeerIdentity))) ));
1341}
1342
1343
1344/**
1345 * Handle a `struct FindSuccessorMessage` from a #GNUNET_MESSAGE_TYPE_WDHT_SUCCESSOR_FIND
1346 * message.
1347 *
1348 * @param cls closure (NULL)
1349 * @param trail_id path to the originator
1350 * @param trail_path path the message took on the trail, if available
1351 * @param trail_path_length number of entries on the @a trail_path
1352 * @param message the finger setup message
1353 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1354 */
1355static int
1356handle_dht_p2p_successor_find (void *cls,
1357 const struct GNUNET_HashCode *trail_id,
1358 const struct GNUNET_PeerIdentity *trail_path,
1359 unsigned int trail_path_length,
1360 const struct GNUNET_MessageHeader *message)
1361{
1362 const struct FindSuccessorMessage *fsm;
1363
1364 /* We do not expect to track trails for the forward-direction
1365 of successor finding... */
1366 GNUNET_break_op (0 == trail_path_length);
1367 fsm = (const struct FindSuccessorMessage *) message;
1368 GDS_DATACACHE_get_successors (&fsm->key,
1369 &GDS_NEIGHBOURS_send_get_result,
1370 (void *) trail_id);
1371 return GNUNET_OK;
1372}
1373
1374
1375/**
1376 * Handle a `struct PeerGetMessage`.
1377 *
1378 * @param cls closure (NULL)
1379 * @param trail_id path to the originator
1380 * @param trail_path path the message took on the trail, if available
1381 * @param trail_path_length number of entries on the @a trail_path
1382 * @param message the peer get message
1383 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1384 */
1385static int
1386handle_dht_p2p_peer_get (void *cls,
1387 const struct GNUNET_HashCode *trail_id,
1388 const struct GNUNET_PeerIdentity *trail_path,
1389 unsigned int trail_path_length,
1390 const struct GNUNET_MessageHeader *message)
1391{
1392#if 0
1393 const struct PeerGetMessage *pgm;
1394
1395 // FIXME: note: never called like this, message embedded with trail route!
1396 pgm = (const struct PeerGetMessage *) message;
1397#endif
1398 // -> lookup in datacache (figure out way to remember trail!)
1399 /*
1400 * steps :
1401 * 1 extract the result
1402 * 2 save the peer
1403 * 3 send it using the good trail
1404 *
1405 * What do i do when i don't have the key/value?
1406 */
1407
1408 return GNUNET_OK;
1409}
1410
1411
1412/**
1413 * Handle a `struct PeerGetResultMessage`.
1414 *
1415 * @param cls closure (NULL)
1416 * @param trail_id path to the originator
1417 * @param trail_path path the message took on the trail, if available
1418 * @param trail_path_length number of entries on the @a trail_path
1419 * @param message the peer get result message
1420 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1421 */
1422static int
1423handle_dht_p2p_peer_get_result (void *cls,
1424 const struct GNUNET_HashCode *trail_id,
1425 const struct GNUNET_PeerIdentity *trail_path,
1426 unsigned int trail_path_length,
1427 const struct GNUNET_MessageHeader *message)
1428{
1429#if 0
1430 const struct PeerGetResultMessage *pgrm;
1431
1432 pgrm = (const struct PeerGetResultMessage *) message;
1433#endif
1434 // pretty much: parse, & pass to client (there is some call for that...)
1435
1436#if 0
1437 GDS_CLIENTS_process_get (options,
1438 type,
1439 0, 0,
1440 path_length, path,
1441 key);
1442 (void) GDS_DATACACHE_handle_get (trail_id,
1443 key,
1444 type,
1445 xquery,
1446 xquery_size,
1447 &reply_bf,
1448 reply_bf_mutator);
1449#endif
1450 return GNUNET_OK;
1451}
1452
1453
1454/**
1455 * Handle a `struct PeerPutMessage`.
1456 *
1457 * @param cls closure (NULL)
1458 * @param trail_id path to the originator
1459 * @param trail_path path the message took on the trail, if available
1460 * @param trail_path_length number of entries on the @a trail_path
1461 * @param message the peer put message
1462 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1463 */
1464static int
1465handle_dht_p2p_peer_put (void *cls,
1466 const struct GNUNET_HashCode *trail_id,
1467 const struct GNUNET_PeerIdentity *trail_path,
1468 unsigned int trail_path_length,
1469 const struct GNUNET_MessageHeader *message)
1470{
1471#if 0
1472 const struct PeerGetResultMessage *pgrm;
1473
1474 pgrm = (const struct PeerGetResultMessage *) message;
1475#endif
1476 // parse & store in datacache, this is in response to us asking for successors.
1477 /*
1478 * steps :
1479 * 1 check the size of the message
1480 * 2 use the API to add the value in the "database". Check on the xdht file, how to do it.
1481 * 3 Did i a have to return a notification or did i have to return GNUNET_[OK|SYSERR]?
1482 */
1483#if 0
1484 GDS_DATACACHE_handle_put (expiration_time,
1485 key,
1486 combined_path_length, combined_path,
1487 block_type,
1488 data_size,
1489 data);
1490 GDS_CLIENTS_process_put (options,
1491 block_type,
1492 0, 0,
1493 combined_path_length, combined_path,
1494 expiration_time,
1495 key,
1496 data,
1497 data_size);
1498#endif
1499 return GNUNET_OK;
1500}
1501
1502
1503/**
1504 * Handler for a message we received along some trail.
1505 *
1506 * @param cls closure
1507 * @param trail_id trail identifier
1508 * @param trail_path path the message took on the trail, if available
1509 * @param trail_path_length number of entries on the @a trail_path
1510 * @param message the message we got
1511 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1512 */
1513typedef int
1514(*TrailHandlerCallback)(void *cls,
1515 const struct GNUNET_HashCode *trail_id,
1516 const struct GNUNET_PeerIdentity *trail_path,
1517 unsigned int trail_path_length,
1518 const struct GNUNET_MessageHeader *message);
1519
1520
1521/**
1522 * Definition of a handler for a message received along some trail.
1523 */
1524struct TrailHandler
1525{
1526 /**
1527 * NULL for end-of-list.
1528 */
1529 TrailHandlerCallback callback;
1530
1531 /**
1532 * Closure for @e callback.
1533 */
1534 void *cls;
1535
1536 /**
1537 * Message type this handler addresses.
1538 */
1539 uint16_t message_type;
1540
1541 /**
1542 * Use 0 for variable-size.
1543 */
1544 uint16_t message_size;
1545};
1546
1547
1548/**
1549 * Check that a `struct TrailRouteMessage` is well-formed.
1550 *
1551 * @param cls closure
1552 * @param trm the finger destroy message
1553 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1554 */
1555static int
1556check_dht_p2p_trail_route (void *cls,
1557 const struct TrailRouteMessage *trm)
1558{
1559 const struct GNUNET_PeerIdentity *path;
1560 uint16_t path_length;
1561 const struct GNUNET_MessageHeader *payload;
1562 size_t msize;
1563
1564 msize = ntohs (trm->header.size);
1565 path_length = ntohs (trm->path_length);
1566 if (msize < sizeof (struct TrailRouteMessage) +
1567 path_length * sizeof (struct GNUNET_PeerIdentity) +
1568 sizeof (struct GNUNET_MessageHeader) )
1569 {
1570 GNUNET_break_op (0);
1571 return GNUNET_SYSERR;
1572 }
1573 path = (const struct GNUNET_PeerIdentity *) &trm[1];
1574 payload = (const struct GNUNET_MessageHeader *) &path[path_length];
1575 if (msize != (ntohs (payload->size) +
1576 sizeof (struct TrailRouteMessage) +
1577 path_length * sizeof (struct GNUNET_PeerIdentity)))
1578 {
1579 GNUNET_break_op (0);
1580 return GNUNET_SYSERR;
1581 }
1582 /* FIXME: verify payload is OK!? */
1583 return GNUNET_OK;
1584}
1585
1586
1587/**
1588 * Handle a `struct TrailRouteMessage`.
1589 *
1590 * @param cls closure
1591 * @param trm the finger destroy message
1592 */
1593static void
1594handle_dht_p2p_trail_route (void *cls,
1595 const struct TrailRouteMessage *trm)
1596{
1597 static const struct TrailHandler handlers[] = {
1598 { &handle_dht_p2p_successor_find, NULL,
1599 GNUNET_MESSAGE_TYPE_WDHT_SUCCESSOR_FIND,
1600 sizeof (struct FindSuccessorMessage) },
1601 { &handle_dht_p2p_peer_get, NULL,
1602 GNUNET_MESSAGE_TYPE_WDHT_GET,
1603 0 },
1604 { &handle_dht_p2p_peer_get_result, NULL,
1605 GNUNET_MESSAGE_TYPE_WDHT_GET_RESULT,
1606 0 },
1607 { &handle_dht_p2p_peer_put, NULL,
1608 GNUNET_MESSAGE_TYPE_WDHT_PUT,
1609 0 },
1610 { NULL, NULL, 0, 0 }
1611 };
1612 struct FriendInfo *sender = cls;
1613 unsigned int i;
1614 const struct GNUNET_PeerIdentity *path;
1615 uint16_t path_length;
1616 const struct GNUNET_MessageHeader *payload;
1617 const struct TrailHandler *th;
1618 struct Trail *trail;
1619
1620 path_length = ntohs (trm->path_length);
1621 path = (const struct GNUNET_PeerIdentity *) &trm[1];
1622 payload = (const struct GNUNET_MessageHeader *) &path[path_length];
1623 /* Is this message for us? */
1624 trail = GNUNET_CONTAINER_multihashmap_get (trail_map,
1625 &trm->trail_id);
1626 if ( (NULL != trail->pred) &&
1627 (0 == memcmp (sender->id,
1628 &trail->pred->id,
1629 sizeof (struct GNUNET_PeerIdentity))) )
1630 {
1631 /* forward to 'successor' */
1632 if (NULL != trail->succ)
1633 {
1634 forward_message_on_trail (trail->succ,
1635 &trail->succ_id,
1636 ntohs (trm->record_path),
1637 sender->id,
1638 path,
1639 path_length,
1640 payload);
1641 return;
1642 }
1643 }
1644 else
1645 {
1646 /* forward to 'predecessor' */
1647 GNUNET_break_op ( (NULL != trail->succ) &&
1648 (0 == memcmp (sender->id,
1649 &trail->succ->id,
1650 sizeof (struct GNUNET_PeerIdentity))) );
1651 if (NULL != trail->pred)
1652 {
1653 forward_message_on_trail (trail->pred,
1654 &trail->pred_id,
1655 ntohs (trm->record_path),
1656 sender->id,
1657 path,
1658 path_length,
1659 payload);
1660 return;
1661 }
1662 }
1663
1664 /* Message is for us, dispatch to handler */
1665 th = NULL;
1666 for (i=0; NULL != handlers[i].callback; i++)
1667 {
1668 th = &handlers[i];
1669 if (ntohs (payload->type) == th->message_type)
1670 {
1671 if ( (0 == th->message_size) ||
1672 (ntohs (payload->size) == th->message_size) )
1673 th->callback (th->cls,
1674 &trm->trail_id,
1675 path,
1676 path_length,
1677 payload);
1678 else
1679 GNUNET_break_op (0);
1680 break;
1681 }
1682 }
1683 GNUNET_break_op (NULL != th);
1684}
1685
1686
1687/**
1688 * Initialize neighbours subsystem.
1689 *
1690 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1691 */
1692int
1693GDS_NEIGHBOURS_init (void)
1694{
1695 struct GNUNET_MQ_MessageHandler core_handlers[] = {
1696 GNUNET_MQ_hd_fixed_size (dht_p2p_random_walk,
1697 GNUNET_MESSAGE_TYPE_WDHT_RANDOM_WALK,
1698 struct RandomWalkMessage,
1699 NULL),
1700 GNUNET_MQ_hd_fixed_size (dht_p2p_random_walk_response,
1701 GNUNET_MESSAGE_TYPE_WDHT_RANDOM_WALK_RESPONSE,
1702 struct RandomWalkResponseMessage,
1703 NULL),
1704 GNUNET_MQ_hd_fixed_size (dht_p2p_trail_destroy,
1705 GNUNET_MESSAGE_TYPE_WDHT_TRAIL_DESTROY,
1706 struct TrailDestroyMessage,
1707 NULL),
1708 GNUNET_MQ_hd_var_size (dht_p2p_trail_route,
1709 GNUNET_MESSAGE_TYPE_WDHT_TRAIL_ROUTE,
1710 struct TrailRouteMessage,
1711 NULL),
1712 GNUNET_MQ_handler_end ()
1713 };
1714
1715 core_api = GNUNET_CORE_connect (GDS_cfg, NULL,
1716 &core_init,
1717 &handle_core_connect,
1718 &handle_core_disconnect,
1719 core_handlers);
1720 if (NULL == core_api)
1721 return GNUNET_SYSERR;
1722 friends_peermap = GNUNET_CONTAINER_multipeermap_create (256,
1723 GNUNET_NO);
1724 trail_map = GNUNET_CONTAINER_multihashmap_create (1024,
1725 GNUNET_YES);
1726 trail_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
1727 return GNUNET_OK;
1728}
1729
1730
1731/**
1732 * Shutdown neighbours subsystem.
1733 */
1734void
1735GDS_NEIGHBOURS_done (void)
1736{
1737 if (NULL == core_api)
1738 return;
1739 GNUNET_CORE_disconnect (core_api);
1740 core_api = NULL;
1741 GNUNET_assert (0 == GNUNET_CONTAINER_multipeermap_size (friends_peermap));
1742 GNUNET_CONTAINER_multipeermap_destroy (friends_peermap);
1743 friends_peermap = NULL;
1744 GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap_size (trail_map));
1745 GNUNET_CONTAINER_multihashmap_destroy (trail_map);
1746 trail_map = NULL;
1747 GNUNET_CONTAINER_heap_destroy (trail_heap);
1748 trail_heap = NULL;
1749 if (NULL != trail_timeout_task)
1750 {
1751 GNUNET_SCHEDULER_cancel (trail_timeout_task);
1752 trail_timeout_task = NULL;
1753 }
1754}
1755
1756
1757/**
1758 * Get my identity
1759 *
1760 * @return my identity
1761 */
1762struct GNUNET_PeerIdentity *
1763GDS_NEIGHBOURS_get_id (void)
1764{
1765 return &my_identity;
1766}
1767
1768/* end of gnunet-service-wdht_neighbours.c */
diff --git a/src/dht/gnunet-service-xdht.c b/src/dht/gnunet-service-xdht.c
deleted file mode 100644
index 7d0cb8a3a..000000000
--- a/src/dht/gnunet-service-xdht.c
+++ /dev/null
@@ -1,121 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010, 2011 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
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 dht/gnunet-service-xdht.c
22 * @brief GNUnet DHT service
23 * @author Christian Grothoff
24 * @author Nathan Evans
25 */
26#include "platform.h"
27#include "gnunet_block_lib.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_transport_service.h"
30#include "gnunet_hello_lib.h"
31#include "gnunet_dht_service.h"
32#include "gnunet_statistics_service.h"
33#include "gnunet-service-dht.h"
34#include "gnunet-service-dht_datacache.h"
35#include "gnunet-service-dht_neighbours.h"
36#include "gnunet-service-dht_nse.h"
37#include "gnunet-service-xdht_routing.h"
38
39
40/**
41 * Should we store our topology predecessor and successor IDs into statistics?
42 */
43extern unsigned int track_topology;
44
45
46/* Code shared between different DHT implementations */
47#include "gnunet-service-dht_clients.c"
48
49
50/**
51 * Task run during shutdown.
52 *
53 * @param cls unused
54 */
55static void
56shutdown_task (void *cls)
57{
58 GDS_NEIGHBOURS_done ();
59 GDS_DATACACHE_done ();
60 GDS_ROUTING_done ();
61 GDS_NSE_done ();
62 if (NULL != GDS_block_context)
63 {
64 GNUNET_BLOCK_context_destroy (GDS_block_context);
65 GDS_block_context = NULL;
66 }
67 if (NULL != GDS_stats)
68 {
69 GNUNET_STATISTICS_destroy (GDS_stats, GNUNET_YES);
70 GDS_stats = NULL;
71 }
72 GDS_CLIENTS_stop ();
73}
74
75
76/**
77 * Process dht requests.
78 *
79 * @param cls closure
80 * @param c configuration to use
81 * @param service the initialized service
82 */
83static void
84run (void *cls,
85 const struct GNUNET_CONFIGURATION_Handle *c,
86 struct GNUNET_SERVICE_Handle *service)
87{
88 unsigned long long _track_topology;
89
90 GDS_cfg = c;
91 GDS_service = service;
92 GDS_block_context = GNUNET_BLOCK_context_create (GDS_cfg);
93 GDS_stats = GNUNET_STATISTICS_create ("dht",
94 GDS_cfg);
95 GDS_ROUTING_init ();
96 GDS_NSE_init ();
97 GDS_DATACACHE_init ();
98 GDS_CLIENTS_init ();
99 if (GNUNET_OK ==
100 GNUNET_CONFIGURATION_get_value_number (c,
101 "xdht",
102 "track_toplogy",
103 &_track_topology))
104 {
105 track_topology = (unsigned int) _track_topology;
106 }
107 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
108 NULL);
109 if (GNUNET_OK != GDS_NEIGHBOURS_init ())
110 {
111 GNUNET_SCHEDULER_shutdown ();
112 return;
113 }
114}
115
116
117/* Finally, define the main method */
118GDS_DHT_SERVICE_INIT("xdht", &run);
119
120
121/* end of gnunet-service-xdht.c */
diff --git a/src/dht/gnunet-service-xdht.h b/src/dht/gnunet-service-xdht.h
deleted file mode 100644
index 5a8e2e21d..000000000
--- a/src/dht/gnunet-service-xdht.h
+++ /dev/null
@@ -1,50 +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 dht/gnunet-service-xdht.h
23 * @brief GNUnet DHT globals
24 * @author Christian Grothoff
25 */
26#ifndef GNUNET_SERVICE_XDHT_H
27#define GNUNET_SERVICE_XDHT_H
28
29#include "gnunet_util_lib.h"
30#include "gnunet_statistics_service.h"
31#include "gnunet_transport_service.h"
32
33#define DEBUG_DHT GNUNET_EXTRA_LOGGING
34
35/**
36 * Configuration we use.
37 */
38extern const struct GNUNET_CONFIGURATION_Handle *GDS_cfg;
39
40/**
41 * Our handle to the BLOCK library.
42 */
43extern struct GNUNET_BLOCK_Context *GDS_block_context;
44
45/**
46 * Handle for the statistics service.
47 */
48extern struct GNUNET_STATISTICS_Handle *GDS_stats;
49
50#endif
diff --git a/src/dht/gnunet-service-xdht_hello.c b/src/dht/gnunet-service-xdht_hello.c
deleted file mode 100644
index ceaf6f853..000000000
--- a/src/dht/gnunet-service-xdht_hello.c
+++ /dev/null
@@ -1,137 +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 dht/gnunet-service-xdht_hello.c
23 * @brief GNUnet DHT integration with peerinfo
24 * @author Christian Grothoff
25 *
26 * TODO:
27 * - consider adding mechanism to remove expired HELLOs
28 */
29#include "platform.h"
30#include "gnunet-service-xdht.h"
31#include "gnunet-service-xdht_hello.h"
32#include "gnunet_peerinfo_service.h"
33
34
35/**
36 * Handle for peerinfo notifications.
37 */
38static struct GNUNET_PEERINFO_NotifyContext *pnc;
39
40/**
41 * Hash map of peers to HELLOs.
42 */
43static struct GNUNET_CONTAINER_MultiPeerMap *peer_to_hello;
44
45
46/**
47 * Obtain a peer's HELLO if available
48 *
49 * @param peer peer to look for a HELLO from
50 * @return HELLO for the given peer
51 */
52const struct GNUNET_HELLO_Message *
53GDS_HELLO_get (const struct GNUNET_PeerIdentity *peer)
54{
55 if (NULL == peer_to_hello)
56 return NULL;
57 return GNUNET_CONTAINER_multipeermap_get (peer_to_hello, peer);
58}
59
60
61/**
62 * Function called for each HELLO known to PEERINFO.
63 *
64 * @param cls closure
65 * @param peer id of the peer, NULL for last call
66 * @param hello hello message for the peer (can be NULL)
67 * @param err_msg error message (not used)
68 */
69static void
70process_hello (void *cls, const struct GNUNET_PeerIdentity *peer,
71 const struct GNUNET_HELLO_Message *hello, const char *err_msg)
72{
73 struct GNUNET_TIME_Absolute ex;
74 struct GNUNET_HELLO_Message *hm;
75
76 if (hello == NULL)
77 return;
78 ex = GNUNET_HELLO_get_last_expiration (hello);
79 if (0 == GNUNET_TIME_absolute_get_remaining (ex).rel_value_us)
80 return;
81 GNUNET_STATISTICS_update (GDS_stats,
82 gettext_noop ("# HELLOs obtained from peerinfo"), 1,
83 GNUNET_NO);
84 hm = GNUNET_CONTAINER_multipeermap_get (peer_to_hello, peer);
85 GNUNET_free_non_null (hm);
86 hm = GNUNET_malloc (GNUNET_HELLO_size (hello));
87 GNUNET_memcpy (hm, hello, GNUNET_HELLO_size (hello));
88 GNUNET_assert (GNUNET_SYSERR !=
89 GNUNET_CONTAINER_multipeermap_put (peer_to_hello,
90 peer, hm,
91 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE));
92}
93
94
95/**
96 * Initialize HELLO subsystem.
97 */
98void
99GDS_HELLO_init ()
100{
101 pnc = GNUNET_PEERINFO_notify (GDS_cfg, GNUNET_NO, &process_hello, NULL);
102 peer_to_hello = GNUNET_CONTAINER_multipeermap_create (256, GNUNET_NO);
103}
104
105
106/**
107 * Free memory occopied by the HELLO.
108 */
109static int
110free_hello (void *cls,
111 const struct GNUNET_PeerIdentity *key,
112 void *hello)
113{
114 GNUNET_free (hello);
115 return GNUNET_OK;
116}
117
118
119/**
120 * Shutdown HELLO subsystem.
121 */
122void
123GDS_HELLO_done ()
124{
125 if (NULL != pnc)
126 {
127 GNUNET_PEERINFO_notify_cancel (pnc);
128 pnc = NULL;
129 }
130 if (NULL != peer_to_hello)
131 {
132 GNUNET_CONTAINER_multipeermap_iterate (peer_to_hello, &free_hello, NULL);
133 GNUNET_CONTAINER_multipeermap_destroy (peer_to_hello);
134 }
135}
136
137/* end of gnunet-service-dht_hello.c */
diff --git a/src/dht/gnunet-service-xdht_hello.h b/src/dht/gnunet-service-xdht_hello.h
deleted file mode 100644
index 7e7a79bcf..000000000
--- a/src/dht/gnunet-service-xdht_hello.h
+++ /dev/null
@@ -1,55 +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 dht/gnunet-service-xdht_hello.h
23 * @brief GNUnet DHT integration with peerinfo
24 * @author Christian Grothoff
25 */
26#ifndef GNUNET_SERVICE_XDHT_HELLO_H
27#define GNUNET_SERVICE_XDHT_HELLO_H
28
29#include "gnunet_util_lib.h"
30#include "gnunet_hello_lib.h"
31
32/**
33 * Obtain a peer's HELLO if available
34 *
35 * @param peer peer to look for a HELLO from
36 * @return HELLO for the given peer
37 */
38const struct GNUNET_HELLO_Message *
39GDS_HELLO_get (const struct GNUNET_PeerIdentity *peer);
40
41
42/**
43 * Initialize HELLO subsystem.
44 */
45void
46GDS_HELLO_init (void);
47
48
49/**
50 * Shutdown HELLO subsystem.
51 */
52void
53GDS_HELLO_done (void);
54
55#endif
diff --git a/src/dht/gnunet-service-xdht_neighbours.c b/src/dht/gnunet-service-xdht_neighbours.c
deleted file mode 100644
index d41eb1900..000000000
--- a/src/dht/gnunet-service-xdht_neighbours.c
+++ /dev/null
@@ -1,6265 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-2014, 2016 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
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 dht/gnunet-service-xdht_neighbours.c
23 * @brief GNUnet DHT service's finger and friend table management code
24 * @author Supriti Singh
25 * @author Christian Grothoff
26 */
27
28#include "platform.h"
29#include "gnunet_util_lib.h"
30#include "gnunet_block_lib.h"
31#include "gnunet_hello_lib.h"
32#include "gnunet_constants.h"
33#include "gnunet_protocols.h"
34#include "gnunet_ats_service.h"
35#include "gnunet_core_service.h"
36#include "gnunet_datacache_lib.h"
37#include "gnunet_transport_service.h"
38#include "gnunet_dht_service.h"
39#include "gnunet_statistics_service.h"
40#include "gnunet-service-dht.h"
41#include "gnunet-service-dht_datacache.h"
42#include "gnunet-service-dht_neighbours.h"
43#include "gnunet-service-xdht_routing.h"
44#include "dht.h"
45
46/**
47 * TODO:
48 * 1. In X-Vine paper, there is no policy defined for replicating the data to
49 * recover in case of peer failure. We can do it in Chord way. In R5N, the key
50 * is hashed and then data is stored according to the key value generated after
51 * hashing.
52 */
53
54#define DEBUG(...) \
55 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
56
57/**
58 * Maximum possible fingers (including predecessor) of a peer
59 */
60#define MAX_FINGERS 65
61
62/**
63 * Maximum allowed number of pending messages per friend peer.
64 */
65#define MAXIMUM_PENDING_PER_FRIEND 64
66
67/**
68 * How long to wait before sending another find finger trail request
69 */
70#define DHT_FIND_FINGER_TRAIL_INTERVAL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2)
71
72/**
73 * How long to wait before sending another verify successor message.
74 */
75#define DHT_SEND_VERIFY_SUCCESSOR_INTERVAL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2)
76
77/**
78 * How long to wait before sending another verify successor message.
79 */
80#define DHT_SEND_VERIFY_SUCCESSOR_RETRY_INTERVAL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
81
82/**
83 * How long to wait before retrying notify successor.
84 */
85#define DHT_SEND_NOTIFY_SUCCESSOR_RETRY_INTERVAL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
86
87/**
88 * How long at most to wait for transmission of a request to a friend ?
89 */
90#define PENDING_MESSAGE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 2)
91
92/**
93 * Duration for which I may remain congested.
94 * Note: Its a static value. In future, a peer may do some analysis and calculate
95 * congestion_timeout based on 'some' parameters.
96 */
97#define CONGESTION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 2)
98
99/**
100 * In case we don't hear back from the current successor, then we can start
101 * verify successor.
102 */
103#define WAIT_NOTIFY_CONFIRMATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 200)
104
105/**
106 * Maximum number of trails allowed to go through a friend.
107 */
108#define TRAILS_THROUGH_FRIEND_THRESHOLD 64
109
110/**
111 * Maximum number of trails stored per finger.
112 */
113#define MAXIMUM_TRAILS_PER_FINGER 4
114
115/**
116 * Finger map index for predecessor entry in finger table.
117 */
118#define PREDECESSOR_FINGER_ID 64
119
120/**
121 * FIXME: Its use only at 3 places check if you can remove it.
122 * To check if a finger is predecessor or not.
123 */
124enum GDS_NEIGHBOURS_finger_type
125{
126 GDS_FINGER_TYPE_PREDECESSOR = 1,
127 GDS_FINGER_TYPE_NON_PREDECESSOR = 0
128};
129
130GNUNET_NETWORK_STRUCT_BEGIN
131
132/**
133 * P2P PUT message
134 */
135struct PeerPutMessage
136{
137 /**
138 * Type: #GNUNET_MESSAGE_TYPE_XDHT_P2P_PUT
139 */
140 struct GNUNET_MessageHeader header;
141
142 /**
143 * Processing options
144 */
145 uint32_t options GNUNET_PACKED;
146
147 /**
148 * Content type.
149 */
150 uint32_t block_type GNUNET_PACKED;
151
152 /**
153 * Hop count
154 */
155 uint32_t hop_count GNUNET_PACKED;
156
157 /**
158 * Replication level for this message
159 * In the current implementation, this value is not used.
160 */
161 uint32_t desired_replication_level GNUNET_PACKED;
162
163 /**
164 * Length of the PUT path that follows (if tracked).
165 */
166 uint32_t put_path_length GNUNET_PACKED;
167
168 /**
169 * Best known destination (could be my friend or finger) which should
170 * get this message next.
171 */
172 struct GNUNET_PeerIdentity best_known_destination;
173
174 /**
175 * In case best_known_destination is a finger, then trail to reach
176 * to that finger. Else its default value is 0.
177 */
178 struct GNUNET_HashCode intermediate_trail_id;
179
180 /**
181 * When does the content expire?
182 */
183 struct GNUNET_TIME_AbsoluteNBO expiration_time;
184
185 /**
186 * The key to store the value under.
187 */
188 struct GNUNET_HashCode key GNUNET_PACKED;
189
190 /* put path (if tracked) */
191
192 /* Payload */
193
194};
195
196/**
197 * P2P GET message
198 */
199struct PeerGetMessage
200{
201 /**
202 * Type: #GNUNET_MESSAGE_TYPE_XDHT_P2P_GET
203 */
204 struct GNUNET_MessageHeader header;
205
206 /**
207 * Processing options
208 */
209 uint32_t options GNUNET_PACKED;
210
211 /**
212 * Desired content type.
213 */
214 uint32_t block_type GNUNET_PACKED;
215
216 /**
217 * Hop count
218 */
219 uint32_t hop_count GNUNET_PACKED;
220
221 /**
222 * Desired replication level for this request.
223 * In the current implementation, this value is not used.
224 */
225 uint32_t desired_replication_level GNUNET_PACKED;
226
227 /**
228 * Total number of peers in get path.
229 */
230 unsigned int get_path_length;
231
232 /**
233 * Best known destination (could be my friend or finger) which should
234 * get this message next.
235 */
236 struct GNUNET_PeerIdentity best_known_destination;
237
238 /**
239 * In case best_known_destination is a finger, then trail to reach
240 * to that finger. Else its default value is 0.
241 */
242 struct GNUNET_HashCode intermediate_trail_id;
243
244 /**
245 * The key we are looking for.
246 */
247 struct GNUNET_HashCode key;
248
249 /* Get path. */
250 /* struct GNUNET_PeerIdentity[]*/
251};
252
253/**
254 * P2P Result message
255 */
256struct PeerGetResultMessage
257{
258 /**
259 * Type: #GNUNET_MESSAGE_TYPE_XDHT_P2P_GET_RESULT
260 */
261 struct GNUNET_MessageHeader header;
262
263 /**
264 * The type for the data.
265 */
266 uint32_t type GNUNET_PACKED;
267
268 /**
269 * Number of peers recorded in the outgoing path from source to the
270 * stored location of this message.
271 */
272 uint32_t put_path_length GNUNET_PACKED;
273
274 /**
275 * Length of the GET path that follows (if tracked).
276 */
277 uint32_t get_path_length GNUNET_PACKED;
278
279 /**
280 * Peer which queried for get and should get the result.
281 */
282 struct GNUNET_PeerIdentity querying_peer;
283
284 /**
285 * When does the content expire?
286 */
287 struct GNUNET_TIME_AbsoluteNBO expiration_time;
288
289 /**
290 * The key of the corresponding GET request.
291 */
292 struct GNUNET_HashCode key;
293
294 /* put path (if tracked) */
295
296 /* get path (if tracked) */
297
298 /* Payload */
299
300};
301
302/**
303 * P2P Trail setup message
304 */
305struct PeerTrailSetupMessage
306{
307 /**
308 * Type: #GNUNET_MESSAGE_TYPE_XDHT_P2P_TRAIL_SETUP
309 */
310 struct GNUNET_MessageHeader header;
311
312 /**
313 * Is source_peer trying to setup the trail to a predecessor or any finger.
314 */
315 uint32_t is_predecessor;
316
317 /**
318 * Peer closest to this value will be our finger.
319 */
320 uint64_t final_destination_finger_value;
321
322 /**
323 * Source peer which wants to setup the trail to one of its finger.
324 */
325 struct GNUNET_PeerIdentity source_peer;
326
327 /**
328 * Best known destination (could be my friend or finger) which should
329 * get this message next.
330 *
331 * FIXME: this could be removed if we include trail_source / trail_dest
332 * in the routing table. This way we save 32 bytes of bandwidth by using
333 * extra 8 bytes of memory (2 * sizeof (GNUNET_PEER_ID))
334 */
335 struct GNUNET_PeerIdentity best_known_destination;
336
337 /**
338 * In case best_known_destination is a finger, then trail id of trail to
339 * reach to this finger.
340 */
341 struct GNUNET_HashCode intermediate_trail_id;
342
343 /**
344 * Trail id for trail which we are trying to setup.
345 */
346 struct GNUNET_HashCode trail_id;
347
348 /* List of peers which are part of trail setup so far.
349 * Trail does NOT include source_peer and peer which will be closest to
350 * ultimate_destination_finger_value.
351 * struct GNUNET_PeerIdentity trail[]
352 */
353};
354
355/**
356 * P2P Trail Setup Result message
357 */
358struct PeerTrailSetupResultMessage
359{
360
361 /**
362 * Type: #GNUNET_MESSAGE_TYPE_XDHT_P2P_TRAIL_SETUP_RESULT
363 */
364 struct GNUNET_MessageHeader header;
365
366 /**
367 * Finger to which we have found the path.
368 */
369 struct GNUNET_PeerIdentity finger_identity;
370
371 /**
372 * Peer which started trail_setup to find trail to finger_identity
373 */
374 struct GNUNET_PeerIdentity querying_peer;
375
376 /**
377 * Is the trail setup to querying_peer's predecessor or finger?
378 */
379 uint32_t is_predecessor;
380
381 /**
382 * Value to which finger_identity is the closest peer.
383 */
384 uint64_t ultimate_destination_finger_value;
385
386 /**
387 * Identifier of the trail from querying peer to finger_identity, NOT
388 * including both endpoints.
389 */
390 struct GNUNET_HashCode trail_id;
391
392 /* List of peers which are part of the trail from querying peer to
393 * finger_identity, NOT including both endpoints.
394 * struct GNUNET_PeerIdentity trail[]
395 */
396};
397
398/**
399 * P2P Verify Successor Message.
400 */
401struct PeerVerifySuccessorMessage
402{
403 /**
404 * Type: #GNUNET_MESSAGE_TYPE_XDHT_P2P_VERIFY_SUCCESSOR
405 */
406 struct GNUNET_MessageHeader header;
407
408 /**
409 * Peer which wants to verify its successor.
410 */
411 struct GNUNET_PeerIdentity source_peer;
412
413 /**
414 * Source Peer's current successor.
415 */
416 struct GNUNET_PeerIdentity successor;
417
418 /**
419 * Identifier of trail to reach from source_peer to successor.
420 */
421 struct GNUNET_HashCode trail_id;
422
423 /* List of the peers which are part of trail to reach from source_peer
424 * to successor, NOT including them
425 * struct GNUNET_PeerIdentity trail[]
426 */
427};
428
429/**
430 * P2P Verify Successor Result Message
431 */
432struct PeerVerifySuccessorResultMessage
433{
434 /**
435 * Type: #GNUNET_MESSAGE_TYPE_XDHT_P2P_VERIFY_SUCCESSOR_RESULT
436 */
437 struct GNUNET_MessageHeader header;
438
439 /**
440 * Peer which sent the request to verify its successor.
441 */
442 struct GNUNET_PeerIdentity querying_peer;
443
444 /**
445 * Successor to which PeerVerifySuccessorMessage was sent.
446 */
447 struct GNUNET_PeerIdentity current_successor;
448
449 /**
450 * Current Predecessor of source_successor. It can be same as querying peer
451 * or different. In case it is different then it can be querying_peer's
452 * probable successor.
453 */
454 struct GNUNET_PeerIdentity probable_successor;
455
456 /**
457 * Trail identifier of trail from querying_peer to current_successor.
458 */
459 struct GNUNET_HashCode trail_id;
460
461 /**
462 * Direction in which we are looking at the trail.
463 */
464 uint32_t trail_direction;
465
466 /* In case probable_successor != querying_peer, then trail to reach from
467 * querying_peer to probable_successor, NOT including end points.
468 * struct GNUNET_PeerIdentity trail[]
469 */
470};
471
472/**
473 * P2P Notify New Successor Message.
474 */
475struct PeerNotifyNewSuccessorMessage
476{
477 /**
478 * Type: #GNUNET_MESSAGE_TYPE_XDHT_P2P_NOTIFY_NEW_SUCCESSOR
479 */
480 struct GNUNET_MessageHeader header;
481
482 /**
483 * Peer which wants to notify its new successor.
484 */
485 struct GNUNET_PeerIdentity source_peer;
486
487 /**
488 * New successor of source_peer.
489 */
490 struct GNUNET_PeerIdentity new_successor;
491
492 /**
493 * Unique identifier of the trail from source_peer to new_successor,
494 * NOT including the endpoints.
495 */
496 struct GNUNET_HashCode trail_id;
497
498 /* List of peers in trail from source_peer to new_successor,
499 * NOT including the endpoints.
500 * struct GNUNET_PeerIdentity trail[]
501 */
502};
503
504/**
505 * P2P Notify Successor Confirmation message.
506 */
507struct PeerNotifyConfirmationMessage
508{
509 /**
510 * Type: #GNUNET_MESSAGE_TYPE_XDHT_P2P_TRAIL_TEARDOWN
511 */
512 struct GNUNET_MessageHeader header;
513
514 /**
515 * Unique identifier of the trail.
516 */
517 struct GNUNET_HashCode trail_id;
518
519 /**
520 * Direction of trail.
521 */
522 uint32_t trail_direction;
523};
524
525
526/**
527 * P2P Trail Tear Down message.
528 */
529struct PeerTrailTearDownMessage
530{
531 /**
532 * Type: #GNUNET_MESSAGE_TYPE_XDHT_P2P_TRAIL_TEARDOWN
533 */
534 struct GNUNET_MessageHeader header;
535
536 /**
537 * Unique identifier of the trail.
538 */
539 struct GNUNET_HashCode trail_id;
540
541 /**
542 * Direction of trail.
543 */
544 uint32_t trail_direction;
545};
546
547
548/**
549 * P2P Trail Rejection Message.
550 */
551struct PeerTrailRejectionMessage
552{
553 /**
554 * Type: #GNUNET_MESSAGE_TYPE_XDHT_P2P_TRAIL_SETUP_REJECTION
555 */
556 struct GNUNET_MessageHeader header;
557
558 /**
559 * Peer which wants to set up the trail.
560 */
561 struct GNUNET_PeerIdentity source_peer;
562
563 /**
564 * Peer which sent trail rejection message as it it congested.
565 */
566 struct GNUNET_PeerIdentity congested_peer;
567
568 /**
569 * Peer identity closest to this value will be finger of
570 * source_peer.
571 */
572 uint64_t ultimate_destination_finger_value;
573
574 /**
575 * Is source_peer trying to setup the trail to its predecessor or finger.
576 */
577 uint32_t is_predecessor;
578
579 /**
580 * Identifier for the trail that source peer is trying to setup.
581 */
582 struct GNUNET_HashCode trail_id;
583
584 /**
585 * Relative time for which congested_peer will remain congested.
586 */
587 struct GNUNET_TIME_Relative congestion_time;
588
589 /* Trail_list from source_peer to peer which sent the message for trail setup
590 * to congested peer. This trail does NOT include source_peer.
591 struct GNUNET_PeerIdnetity trail[]*/
592};
593
594/**
595 * P2P Add Trail Message.
596 */
597struct PeerAddTrailMessage
598{
599 /**
600 * Type: #GNUNET_MESSAGE_TYPE_XDHT_P2P_ADD_TRAIL
601 */
602 struct GNUNET_MessageHeader header;
603
604 /**
605 * Source of the routing trail.
606 */
607 struct GNUNET_PeerIdentity source_peer;
608
609 /**
610 * Destination of the routing trail.
611 */
612 struct GNUNET_PeerIdentity destination_peer;
613
614 /**
615 * Unique identifier of the trail from source_peer to destination_peer,
616 * NOT including the endpoints.
617 */
618 struct GNUNET_HashCode trail_id;
619
620 /* Trail from source peer to destination peer, NOT including them.
621 * struct GNUNET_PeerIdentity trail[]
622 */
623};
624
625
626GNUNET_NETWORK_STRUCT_END
627
628
629/**
630 * Entry in friend_peermap.
631 */
632struct FriendInfo
633{
634 /**
635 * Friend Identity
636 */
637 const struct GNUNET_PeerIdentity *id;
638
639 /**
640 * Number of trails for which this friend is the first hop or if the friend
641 * is finger.
642 */
643 unsigned int trails_count;
644
645 /**
646 * In case not 0, then amount of time for which this friend is congested.
647 */
648 struct GNUNET_TIME_Absolute congestion_timestamp;
649
650 /**
651 * Handle for sending messages to this friend.
652 */
653 struct GNUNET_MQ_Handle *mq;
654
655};
656
657/**
658 * An individual element of the trail to reach to a finger.
659 */
660struct Trail_Element
661{
662 /**
663 * Pointer to next item in the list
664 */
665 struct Trail_Element *next;
666
667 /**
668 * Pointer to prev item in the list
669 */
670 struct Trail_Element *prev;
671
672 /**
673 * An element in this trail.
674 */
675 struct GNUNET_PeerIdentity peer;
676};
677
678/**
679 * Information about an individual trail.
680 */
681struct Trail
682{
683 /**
684 * Head of trail.
685 */
686 struct Trail_Element *trail_head;
687
688 /**
689 * Tail of trail.
690 */
691 struct Trail_Element *trail_tail;
692
693 /**
694 * Unique identifier of this trail.
695 */
696 struct GNUNET_HashCode trail_id;
697
698 /**
699 * Length of trail pointed
700 */
701 unsigned int trail_length;
702
703 /**
704 * Is there a valid trail entry.
705 */
706 unsigned int is_present;
707};
708
709/**
710 * An entry in finger_table
711 */
712struct FingerInfo
713{
714 /**
715 * Finger identity.
716 */
717 struct GNUNET_PeerIdentity finger_identity;
718
719 /**
720 * In case not 0, this amount is time to wait for notify successor message.
721 * Used ONLY for successor. NOT for any other finger.
722 */
723 struct GNUNET_TIME_Absolute wait_notify_confirmation;
724
725 /**
726 * Is any finger stored at this finger index.
727 */
728 unsigned int is_present;
729
730 /**
731 * Index in finger peer map
732 */
733 uint32_t finger_table_index;
734
735 /**
736 * Number of trails setup so far for this finger.
737 * Should not cross MAXIMUM_TRAILS_PER_FINGER.
738 */
739 uint32_t trails_count;
740
741 /**
742 * Array of trails to reach to this finger.
743 */
744 struct Trail trail_list[MAXIMUM_TRAILS_PER_FINGER];
745};
746
747
748/**
749 * Stores information about the peer which is closest to destination_finger_value.
750 * 'closest' can be either successor or predecessor depending on is_predecessor
751 * flag.
752 */
753struct Closest_Peer
754{
755 /**
756 * Destination finger value.
757 */
758 uint64_t destination_finger_value;
759
760 /**
761 * Is finger_value a predecessor or any other finger.
762 */
763 unsigned int is_predecessor;
764
765 /**
766 * Trail id to reach to peer.
767 * In case peer is my identity or friend, it is set to 0.
768 */
769 struct GNUNET_HashCode trail_id;
770
771 /**
772 * Next destination. In case of friend and my_identity , it is same as next_hop
773 * In case of finger it is finger identity.
774 */
775 struct GNUNET_PeerIdentity best_known_destination;
776
777 /**
778 * In case best_known_destination is a finger, then first friend in the trail
779 * to reach to it. In other case, same as best_known_destination.
780 */
781 struct GNUNET_PeerIdentity next_hop;
782
783 /**
784 * In case finger is the next hop, it contains a valid finger table index
785 * at which the finger is stored. Else, It contains 65, which is out of range
786 * of finger table index.
787 */
788 unsigned int finger_table_index;
789};
790
791/**
792 * Context for send_verify_successor_task.
793 */
794struct VerifySuccessorContext
795{
796 /**
797 * Number of times this has been scheduled.
798 */
799 unsigned int num_retries_scheduled;
800};
801
802/**
803 * Task that sends FIND FINGER TRAIL requests. This task is started when we have
804 * get our first friend.
805 */
806static struct GNUNET_SCHEDULER_Task *find_finger_trail_task;
807
808/**
809 * Task that sends verify successor message. This task is started when we get
810 * our successor for the first time.
811 */
812static struct GNUNET_SCHEDULER_Task *send_verify_successor_task;
813
814/**
815 * Task that sends verify successor message. This task is started when we get
816 * our successor for the first time.
817 */
818static struct GNUNET_SCHEDULER_Task *send_verify_successor_retry_task;
819
820/**
821 * Task that sends verify successor message. This task is started when we get
822 * our successor for the first time.
823 */
824static struct GNUNET_SCHEDULER_Task *send_notify_new_successor_retry_task;
825
826/**
827 * Identity of this peer.
828 */
829static struct GNUNET_PeerIdentity my_identity;
830
831/**
832 * Peer map of all the friends of a peer
833 */
834static struct GNUNET_CONTAINER_MultiPeerMap *friend_peermap;
835
836/**
837 * Array of all the fingers.
838 */
839static struct FingerInfo finger_table [MAX_FINGERS];
840
841/**
842 * Handle to CORE.
843 */
844static struct GNUNET_CORE_Handle *core_api;
845
846/**
847 * The current finger index that we have want to find trail to. We start the
848 * search with value = 0, i.e. successor and then go to PREDCESSOR_FINGER_ID
849 * and decrement it. For any index 63 <= index < 0, if finger is same as successor,
850 * we reset this index to 0.
851 */
852static unsigned int current_search_finger_index;
853
854/**
855 * Time duration to schedule find finger trail task.
856 */
857static struct GNUNET_TIME_Relative find_finger_trail_task_next_send_time;
858
859/**
860 * Time duration to schedule verify successor task.
861 */
862static struct GNUNET_TIME_Relative verify_successor_next_send_time;
863
864/**
865 * Time duration to send verify successor again, if result was not received in time.
866 */
867static struct GNUNET_TIME_Relative verify_successor_retry_time;
868
869/**
870 * Time duration to retry send_notify_successor.
871 */
872static struct GNUNET_TIME_Relative notify_successor_retry_time;
873
874/**
875 * Are we waiting for confirmation from our new successor that it got the
876 * message
877 */
878//static unsigned int waiting_for_notify_confirmation;
879
880/* Below variables are used only for testing, and statistics collection. */
881/**
882 * Should we store our topology predecessor and successor IDs into statistics?
883 */
884unsigned int track_topology;
885
886/**
887 * Count of fingers found. Ideally we should have O(logn) fingers for a
888 * stable network.
889 */
890static unsigned int total_fingers_found;
891
892/**
893 * Number of times we found the same successor.
894 */
895static unsigned int successor_times;
896
897/**
898 * Number of rounds for which we should search for finger.
899 */
900static unsigned int fingers_round_count;
901
902
903/**
904 * Construct a trail setup message and forward it to @a target_friend
905 *
906 * @param source_peer Peer which wants to setup the trail
907 * @param ultimate_destination_finger_value Peer identity closest to this value
908 * will be finger to @a source_peer
909 * @param best_known_destination Best known destination (could be finger or friend)
910 * which should get this message. In case it is
911 * friend, then it is same as target_friend
912 * @param target_friend Friend to which message is forwarded now.
913 * @param trail_length Total number of peers in trail setup so far.
914 * @param trail_peer_list Trail setup so far
915 * @param is_predecessor Is @a source_peer looking for trail to a predecessor or not.
916 * @param trail_id Unique identifier for the trail we are trying to setup.
917 * @param intermediate_trail_id Trail id of intermediate trail to reach to
918 * best_known_destination when its a finger. If not
919 * used then set to 0.
920 */
921static void
922GDS_NEIGHBOURS_send_trail_setup (const struct GNUNET_PeerIdentity *source_peer,
923 uint64_t ultimate_destination_finger_value,
924 const struct GNUNET_PeerIdentity *best_known_destination,
925 const struct FriendInfo *target_friend,
926 unsigned int trail_length,
927 const struct GNUNET_PeerIdentity *trail_peer_list,
928 unsigned int is_predecessor,
929 const struct GNUNET_HashCode *trail_id,
930 const struct GNUNET_HashCode *intermediate_trail_id)
931{
932 struct GNUNET_MQ_Envelope *env;
933 struct PeerTrailSetupMessage *tsm;
934 size_t msize;
935
936 msize = trail_length * sizeof (struct GNUNET_PeerIdentity);
937 if (msize + sizeof (struct PeerTrailSetupMessage)
938 >= GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE)
939 {
940 GNUNET_break (0);
941 return;
942 }
943 if (GNUNET_MQ_get_length (target_friend->mq) >= MAXIMUM_PENDING_PER_FRIEND)
944 {
945 GNUNET_STATISTICS_update (GDS_stats,
946 gettext_noop ("# P2P messages dropped due to full queue"),
947 1,
948 GNUNET_NO);
949 return;
950 }
951 env = GNUNET_MQ_msg_extra (tsm,
952 msize,
953 GNUNET_MESSAGE_TYPE_XDHT_P2P_TRAIL_SETUP);
954 tsm->final_destination_finger_value = GNUNET_htonll (ultimate_destination_finger_value);
955 tsm->source_peer = *source_peer;
956 tsm->best_known_destination = *best_known_destination;
957 tsm->is_predecessor = htonl (is_predecessor);
958 tsm->trail_id = *trail_id;
959 tsm->intermediate_trail_id = *intermediate_trail_id;
960 GNUNET_memcpy (&tsm[1],
961 trail_peer_list,
962 msize);
963 GNUNET_MQ_send (target_friend->mq,
964 env);
965}
966
967
968/**
969 * Construct a trail setup result message and forward it to @a target_friend.
970 *
971 * @param querying_peer Peer which sent the trail setup request and should get
972 * the result back.
973 * @param Finger Peer to which the trail has been setup to.
974 * @param target_friend Friend to which this message should be forwarded.
975 * @param trail_length Numbers of peers in the trail.
976 * @param trail_peer_list Peers which are part of the trail from
977 * querying_peer to Finger, NOT including them.
978 * @param is_predecessor Is @a Finger predecessor to @a querying_peer ?
979 * @param ultimate_destination_finger_value Value to which @a finger is the closest
980 * peer.
981 * @param trail_id Unique identifier of the trail.
982 */
983static void
984GDS_NEIGHBOURS_send_trail_setup_result (const struct GNUNET_PeerIdentity *querying_peer,
985 const struct GNUNET_PeerIdentity *finger,
986 struct FriendInfo *target_friend,
987 unsigned int trail_length,
988 const struct GNUNET_PeerIdentity *trail_peer_list,
989 unsigned int is_predecessor,
990 uint64_t ultimate_destination_finger_value,
991 const struct GNUNET_HashCode *trail_id)
992{
993 struct GNUNET_MQ_Envelope *env;
994 struct PeerTrailSetupResultMessage *tsrm;
995 size_t msize;
996
997 msize = trail_length * sizeof (struct GNUNET_PeerIdentity);
998 if (msize + sizeof (struct PeerTrailSetupResultMessage)
999 >= GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE)
1000 {
1001 GNUNET_break (0);
1002 return;
1003 }
1004 if (GNUNET_MQ_get_length (target_friend->mq) >= MAXIMUM_PENDING_PER_FRIEND)
1005 {
1006 GNUNET_STATISTICS_update (GDS_stats,
1007 gettext_noop ("# P2P messages dropped due to full queue"),
1008 1,
1009 GNUNET_NO);
1010 return;
1011 }
1012 env = GNUNET_MQ_msg_extra (tsrm,
1013 msize,
1014 GNUNET_MESSAGE_TYPE_XDHT_P2P_TRAIL_SETUP_RESULT);
1015 tsrm->querying_peer = *querying_peer;
1016 tsrm->finger_identity = *finger;
1017 tsrm->is_predecessor = htonl (is_predecessor);
1018 tsrm->trail_id = *trail_id;
1019 tsrm->ultimate_destination_finger_value
1020 = GNUNET_htonll (ultimate_destination_finger_value);
1021 GNUNET_memcpy (&tsrm[1],
1022 trail_peer_list,
1023 msize);
1024 GNUNET_MQ_send (target_friend->mq,
1025 env);
1026}
1027
1028
1029/**
1030 * Send notify successor confirmation message.
1031 *
1032 * @param trail_id Unique Identifier of the trail.
1033 * @param trail_direction Destination to Source.
1034 * @param target_friend Friend to get this message next.
1035 */
1036static void
1037GDS_NEIGHBOURS_send_notify_succcessor_confirmation (const struct GNUNET_HashCode *trail_id,
1038 unsigned int trail_direction,
1039 struct FriendInfo *target_friend)
1040{
1041 struct PeerNotifyConfirmationMessage *ncm;
1042 struct GNUNET_MQ_Envelope *env;
1043
1044 if (GNUNET_MQ_get_length (target_friend->mq) >= MAXIMUM_PENDING_PER_FRIEND)
1045 {
1046 GNUNET_STATISTICS_update (GDS_stats,
1047 gettext_noop ("# P2P messages dropped due to full queue"),
1048 1,
1049 GNUNET_NO);
1050 return;
1051 }
1052 env = GNUNET_MQ_msg (ncm,
1053 GNUNET_MESSAGE_TYPE_XDHT_P2P_NOTIFY_SUCCESSOR_CONFIRMATION);
1054 ncm->trail_id = *trail_id;
1055 ncm->trail_direction = htonl (trail_direction);
1056 GNUNET_MQ_send (target_friend->mq,
1057 env);
1058}
1059
1060
1061/**
1062 * Send trail rejection message to @a target_friend
1063 *
1064 * @param source_peer Peer which is trying to setup the trail.
1065 * @param ultimate_destination_finger_value Peer closest to this value will be
1066 * @a source_peer's finger
1067 * @param congested_peer Peer which sent this message as it is congested.
1068 * @param is_predecessor Is source_peer looking for trail to a predecessor or not.
1069 * @param trail_peer_list Trails seen so far in trail setup before getting rejected
1070 * by congested_peer. This does NOT include @a source_peer
1071 * and congested_peer.
1072 * @param trail_length Total number of peers in trail_peer_list, NOT including
1073 * @a source_peer and @a congested_peer
1074 * @param trail_id Unique identifier of this trail.
1075 * @param congestion_timeout Duration given by congested peer as an estimate of
1076 * how long it may remain congested.
1077 */
1078static void
1079GDS_NEIGHBOURS_send_trail_rejection (const struct GNUNET_PeerIdentity *source_peer,
1080 uint64_t ultimate_destination_finger_value,
1081 const struct GNUNET_PeerIdentity *congested_peer,
1082 unsigned int is_predecessor,
1083 const struct GNUNET_PeerIdentity *trail_peer_list,
1084 unsigned int trail_length,
1085 const struct GNUNET_HashCode *trail_id,
1086 struct FriendInfo *target_friend,
1087 const struct GNUNET_TIME_Relative congestion_timeout)
1088{
1089 struct PeerTrailRejectionMessage *trm;
1090 struct GNUNET_MQ_Envelope *env;
1091 size_t msize;
1092
1093 msize = trail_length * sizeof (struct GNUNET_PeerIdentity);
1094 if (msize + sizeof (struct PeerTrailRejectionMessage)
1095 >= GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE)
1096 {
1097 GNUNET_break (0);
1098 return;
1099 }
1100 if (GNUNET_MQ_get_length (target_friend->mq) >= MAXIMUM_PENDING_PER_FRIEND)
1101 {
1102 GNUNET_STATISTICS_update (GDS_stats,
1103 gettext_noop ("# P2P messages dropped due to full queue"),
1104 1,
1105 GNUNET_NO);
1106 return;
1107 }
1108 env = GNUNET_MQ_msg_extra (trm,
1109 msize,
1110 GNUNET_MESSAGE_TYPE_XDHT_P2P_TRAIL_SETUP_REJECTION);
1111 trm->source_peer = *source_peer;
1112 trm->congested_peer = *congested_peer;
1113 trm->congestion_time = congestion_timeout;
1114 trm->is_predecessor = htonl (is_predecessor);
1115 trm->trail_id = *trail_id;
1116 trm->ultimate_destination_finger_value
1117 = GNUNET_htonll (ultimate_destination_finger_value);
1118 GNUNET_memcpy (&trm[1],
1119 trail_peer_list,
1120 msize);
1121 GNUNET_MQ_send (target_friend->mq,
1122 env);
1123}
1124
1125
1126/**
1127 * Construct a verify successor message and forward it to target_friend.
1128 * @param source_peer Peer which wants to verify its successor.
1129 * @param successor Peer which is @a source_peer's current successor.
1130 * @param trail_id Unique Identifier of trail from @a source_peer to @a successor,
1131 * NOT including them.
1132 * @param trail List of peers which are part of trail to reach from @a source_peer
1133 * to @a successor, NOT including them.
1134 * @param trail_length Total number of peers in @a trail.
1135 * @param target_friend Next friend to get this message.
1136 */
1137static void
1138GDS_NEIGHBOURS_send_verify_successor_message (const struct GNUNET_PeerIdentity *source_peer,
1139 const struct GNUNET_PeerIdentity *successor,
1140 const struct GNUNET_HashCode *trail_id,
1141 struct GNUNET_PeerIdentity *trail,
1142 unsigned int trail_length,
1143 struct FriendInfo *target_friend)
1144{
1145 struct PeerVerifySuccessorMessage *vsm;
1146 struct GNUNET_MQ_Envelope *env;
1147 size_t msize;
1148
1149 msize = trail_length * sizeof (struct GNUNET_PeerIdentity);
1150 if (msize + sizeof (*vsm) >= GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE)
1151 {
1152 GNUNET_break (0);
1153 return;
1154 }
1155 if (GNUNET_MQ_get_length (target_friend->mq) >= MAXIMUM_PENDING_PER_FRIEND)
1156 {
1157 GNUNET_STATISTICS_update (GDS_stats,
1158 gettext_noop ("# P2P messages dropped due to full queue"),
1159 1,
1160 GNUNET_NO);
1161 return;
1162 }
1163 env = GNUNET_MQ_msg_extra (vsm,
1164 msize,
1165 GNUNET_MESSAGE_TYPE_XDHT_P2P_VERIFY_SUCCESSOR);
1166 vsm->source_peer = *source_peer;
1167 vsm->successor = *successor;
1168 vsm->trail_id = *trail_id;
1169 GNUNET_memcpy (&vsm[1],
1170 trail,
1171 msize);
1172 GNUNET_MQ_send (target_friend->mq,
1173 env);
1174}
1175
1176
1177/**
1178 * FIXME: In every function we pass target friend except for this one.
1179 * so, either change everything or this one. also, should we just store
1180 * the pointer to friend in routing table rather than gnunet_peeridentity.
1181 * if yes then we should keep friend info in.h andmake lot of changes.
1182 * Construct a trail teardown message and forward it to target friend.
1183 *
1184 * @param trail_id Unique identifier of the trail.
1185 * @param trail_direction Direction of trail.
1186 * @param target_friend Friend to get this message.
1187 */
1188void
1189GDS_NEIGHBOURS_send_trail_teardown (const struct GNUNET_HashCode *trail_id,
1190 unsigned int trail_direction,
1191 const struct GNUNET_PeerIdentity *peer)
1192{
1193 struct PeerTrailTearDownMessage *ttdm;
1194 struct GNUNET_MQ_Envelope *env;
1195 struct FriendInfo *target_friend;
1196
1197 if (NULL == (target_friend =
1198 GNUNET_CONTAINER_multipeermap_get (friend_peermap,
1199 peer)))
1200 {
1201 /* FIXME: In what case friend can be null. ?*/
1202 GNUNET_break (0);
1203 return;
1204 }
1205 if (GNUNET_MQ_get_length (target_friend->mq) >= MAXIMUM_PENDING_PER_FRIEND)
1206 {
1207 GNUNET_STATISTICS_update (GDS_stats,
1208 gettext_noop ("# P2P messages dropped due to full queue"),
1209 1,
1210 GNUNET_NO);
1211 return;
1212 }
1213 env = GNUNET_MQ_msg (ttdm,
1214 GNUNET_MESSAGE_TYPE_XDHT_P2P_TRAIL_TEARDOWN);
1215 ttdm->trail_id = *trail_id;
1216 ttdm->trail_direction = htonl (trail_direction);
1217 GNUNET_MQ_send (target_friend->mq,
1218 env);
1219}
1220
1221
1222/**
1223 * Construct a verify successor result message and send it to target_friend
1224 *
1225 * @param querying_peer Peer which sent the verify successor message.
1226 * @param source_successor Current_successor of @a querying_peer.
1227 * @param current_predecessor Current predecessor of @a successor. Could be same
1228 * or different from @a querying_peer.
1229 * @param trail_id Unique identifier of the trail from @a querying_peer to
1230 * @a successor, NOT including them.
1231 * @param trail List of peers which are part of trail from @a querying_peer to
1232 * @a successor, NOT including them.
1233 * @param trail_length Total number of peers in @a trail
1234 * @param trail_direction Direction in which we are sending the message. In this
1235 * case we are sending result from @a successor to @a querying_peer.
1236 * @param target_friend Next friend to get this message.
1237 */
1238static void
1239GDS_NEIGHBOURS_send_verify_successor_result (const struct GNUNET_PeerIdentity *querying_peer,
1240 const struct GNUNET_PeerIdentity *current_successor,
1241 const struct GNUNET_PeerIdentity *probable_successor,
1242 const struct GNUNET_HashCode *trail_id,
1243 const struct GNUNET_PeerIdentity *trail,
1244 unsigned int trail_length,
1245 enum GDS_ROUTING_trail_direction trail_direction,
1246 struct FriendInfo *target_friend)
1247{
1248 struct PeerVerifySuccessorResultMessage *vsmr;
1249 struct GNUNET_MQ_Envelope *env;
1250 size_t msize;
1251
1252 msize = trail_length * sizeof(struct GNUNET_PeerIdentity);
1253 if (msize + sizeof (struct PeerVerifySuccessorResultMessage)
1254 >= GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE)
1255 {
1256 GNUNET_break (0);
1257 return;
1258 }
1259 if (GNUNET_MQ_get_length (target_friend->mq) >= MAXIMUM_PENDING_PER_FRIEND)
1260 {
1261 GNUNET_STATISTICS_update (GDS_stats,
1262 gettext_noop ("# P2P messages dropped due to full queue"),
1263 1,
1264 GNUNET_NO);
1265 return;
1266 }
1267 env = GNUNET_MQ_msg_extra (vsmr,
1268 msize,
1269 GNUNET_MESSAGE_TYPE_XDHT_P2P_VERIFY_SUCCESSOR_RESULT);
1270 vsmr->querying_peer = *querying_peer;
1271 vsmr->current_successor = *current_successor;
1272 vsmr->probable_successor = *probable_successor;
1273 vsmr->trail_direction = htonl (trail_direction);
1274 vsmr->trail_id = *trail_id;
1275 GNUNET_memcpy (&vsmr[1],
1276 trail,
1277 msize);
1278 GNUNET_MQ_send (target_friend->mq,
1279 env);
1280}
1281
1282
1283/**
1284 * Construct a notify new successor message and send it to target_friend
1285 * @param source_peer Peer which wants to notify to its new successor that it
1286 * could be its predecessor.
1287 * @param successor New successor of @a source_peer
1288 * @param successor_trail List of peers in Trail to reach from
1289 * @a source_peer to @a new_successor, NOT including
1290 * the endpoints.
1291 * @param successor_trail_length Total number of peers in @a new_successor_trail.
1292 * @param successor_trail_id Unique identifier of @a new_successor_trail.
1293 * @param target_friend Next friend to get this message.
1294 */
1295static void
1296GDS_NEIGHBOURS_send_notify_new_successor (const struct GNUNET_PeerIdentity *source_peer,
1297 const struct GNUNET_PeerIdentity *successor,
1298 const struct GNUNET_PeerIdentity *successor_trail,
1299 unsigned int successor_trail_length,
1300 const struct GNUNET_HashCode *succesor_trail_id,
1301 struct FriendInfo *target_friend)
1302{
1303 struct PeerNotifyNewSuccessorMessage *nsm;
1304 struct GNUNET_MQ_Envelope *env;
1305 size_t msize;
1306
1307 msize = successor_trail_length * sizeof(struct GNUNET_PeerIdentity);
1308 if (msize + sizeof (struct PeerNotifyNewSuccessorMessage)
1309 >= GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE)
1310 {
1311 GNUNET_break (0);
1312 return;
1313 }
1314 if (GNUNET_MQ_get_length (target_friend->mq) >= MAXIMUM_PENDING_PER_FRIEND)
1315 {
1316 GNUNET_STATISTICS_update (GDS_stats,
1317 gettext_noop ("# P2P messages dropped due to full queue"),
1318 1,
1319 GNUNET_NO);
1320 return;
1321 }
1322 env = GNUNET_MQ_msg_extra (nsm,
1323 msize,
1324 GNUNET_MESSAGE_TYPE_XDHT_P2P_NOTIFY_NEW_SUCCESSOR);
1325 nsm->new_successor = *successor;
1326 nsm->source_peer = *source_peer;
1327 nsm->trail_id = *succesor_trail_id;
1328 GNUNET_memcpy (&nsm[1],
1329 successor_trail,
1330 msize);
1331 GNUNET_MQ_send (target_friend->mq,
1332 env);
1333}
1334
1335
1336/**
1337 * Construct an add_trail message and send it to target_friend
1338 *
1339 * @param source_peer Source of the trail.
1340 * @param destination_peer Destination of the trail.
1341 * @param trail_id Unique identifier of the trail from
1342 * @a source_peer to @a destination_peer, NOT including the endpoints.
1343 * @param trail List of peers in Trail from @a source_peer to @a destination_peer,
1344 * NOT including the endpoints.
1345 * @param trail_length Total number of peers in @a trail.
1346 * @param target_friend Next friend to get this message.
1347 */
1348static void
1349GDS_NEIGHBOURS_send_add_trail (const struct GNUNET_PeerIdentity *source_peer,
1350 const struct GNUNET_PeerIdentity *destination_peer,
1351 const struct GNUNET_HashCode *trail_id,
1352 const struct GNUNET_PeerIdentity *trail,
1353 unsigned int trail_length,
1354 struct FriendInfo *target_friend)
1355{
1356 struct PeerAddTrailMessage *adm;
1357 struct GNUNET_MQ_Envelope *env;
1358 size_t msize;
1359
1360 msize = trail_length * sizeof(struct GNUNET_PeerIdentity);
1361 if (msize + sizeof (struct PeerAddTrailMessage)
1362 >= GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE)
1363 {
1364 GNUNET_break (0);
1365 return;
1366 }
1367 if (GNUNET_MQ_get_length (target_friend->mq) >= MAXIMUM_PENDING_PER_FRIEND)
1368 {
1369 GNUNET_STATISTICS_update (GDS_stats,
1370 gettext_noop ("# P2P messages dropped due to full queue"),
1371 1,
1372 GNUNET_NO);
1373 return;
1374 }
1375 env = GNUNET_MQ_msg_extra (adm,
1376 msize,
1377 GNUNET_MESSAGE_TYPE_XDHT_P2P_ADD_TRAIL);
1378 adm->source_peer = *source_peer;
1379 adm->destination_peer = *destination_peer;
1380 adm->trail_id = *trail_id;
1381 GNUNET_memcpy (&adm[1],
1382 trail,
1383 msize);
1384 GNUNET_MQ_send (target_friend->mq,
1385 env);
1386}
1387
1388
1389/**
1390 * Search my location in trail. In case I am present more than once in the
1391 * trail (can happen during trail setup), then return my lowest index.
1392 *
1393 * @param trail List of peers
1394 * @return my_index if found
1395 * trail_length + 1 if an entry is present twice, It is an error.
1396 * -1 if no entry found.
1397 */
1398static int
1399search_my_index (const struct GNUNET_PeerIdentity *trail,
1400 int trail_length)
1401{
1402 int i;
1403 int index_seen = trail_length + 1;
1404 int flag = 0;
1405
1406 for (i = 0; i < trail_length; i++)
1407 {
1408 if (0 == GNUNET_CRYPTO_cmp_peer_identity (&my_identity, &trail[i]))
1409 {
1410 flag = 1;
1411 if(index_seen == (trail_length + 1))
1412 index_seen = i;
1413 else
1414 {
1415 DEBUG("Entry is present twice in trail. Its not allowed\n");
1416 }
1417 break;
1418 }
1419 }
1420
1421 if (1 == flag)
1422 return index_seen;
1423 return -1;
1424}
1425
1426
1427/**
1428 * Check if the friend is congested or have reached maximum number of trails
1429 * it can be part of of.
1430 * @param friend Friend to be checked.
1431 * @return #GNUNET_NO if friend is not congested or have not crossed threshold.
1432 * #GNUNET_YES if friend is either congested or have crossed threshold
1433 */
1434static int
1435is_friend_congested (struct FriendInfo *friend)
1436{
1437 if (( friend->trails_count < TRAILS_THROUGH_FRIEND_THRESHOLD) &&
1438 ((0 == GNUNET_TIME_absolute_get_remaining
1439 (friend->congestion_timestamp).rel_value_us)))
1440 return GNUNET_NO;
1441 return GNUNET_YES;
1442}
1443
1444
1445/**
1446 * Select closest finger to value.
1447 *
1448 * @param peer1 First peer
1449 * @param peer2 Second peer
1450 * @param value Value to be compare
1451 * @return Closest peer
1452 */
1453static const struct GNUNET_PeerIdentity *
1454select_closest_finger (const struct GNUNET_PeerIdentity *peer1,
1455 const struct GNUNET_PeerIdentity *peer2,
1456 uint64_t value)
1457{
1458 uint64_t peer1_value;
1459 uint64_t peer2_value;
1460
1461 GNUNET_memcpy (&peer1_value, peer1, sizeof (uint64_t));
1462 GNUNET_memcpy (&peer2_value, peer2, sizeof (uint64_t));
1463 peer1_value = GNUNET_ntohll (peer1_value);
1464 peer2_value = GNUNET_ntohll (peer2_value);
1465
1466 if (peer1_value == value)
1467 {
1468 return peer1;
1469 }
1470
1471 if (peer2_value == value)
1472 {
1473 return peer2;
1474 }
1475
1476 if (value < peer1_value && peer1_value < peer2_value)
1477 {
1478 return peer1;
1479 }
1480 else if (value < peer2_value && peer2_value < peer1_value)
1481 {
1482 return peer2;
1483 }
1484 else if (peer1_value < value && value < peer2_value)
1485 {
1486 return peer2;
1487 }
1488 else if (peer2_value < value && value < peer1_value)
1489 {
1490 return peer1;
1491 }
1492 else if (peer1_value < peer2_value && peer2_value < value)
1493 {
1494 return peer1;
1495 }
1496 else // if (peer2_value < peer1_value && peer1_value < value)
1497 {
1498 return peer2;
1499 }
1500}
1501
1502
1503/**
1504 * Select closest predecessor to value.
1505 *
1506 * @param peer1 First peer
1507 * @param peer2 Second peer
1508 * @param value Value to be compare
1509 * @return Peer which precedes value in the network.
1510 */
1511static const struct GNUNET_PeerIdentity *
1512select_closest_predecessor (const struct GNUNET_PeerIdentity *peer1,
1513 const struct GNUNET_PeerIdentity *peer2,
1514 uint64_t value)
1515{
1516 uint64_t peer1_value;
1517 uint64_t peer2_value;
1518
1519 GNUNET_memcpy (&peer1_value, peer1, sizeof (uint64_t));
1520 GNUNET_memcpy (&peer2_value, peer2, sizeof (uint64_t));
1521 peer1_value = GNUNET_ntohll (peer1_value);
1522 peer2_value = GNUNET_ntohll (peer2_value);
1523
1524 if (peer1_value == value)
1525 {
1526 return peer1;
1527 }
1528
1529 if (peer2_value == value)
1530 {
1531 return peer2;
1532 }
1533
1534 if (value < peer1_value && peer1_value < peer2_value)
1535 {
1536 return peer2;
1537 }
1538 else if (value < peer2_value && peer2_value < peer1_value)
1539 {
1540 return peer1;
1541 }
1542 else if (peer1_value < value && value < peer2_value)
1543 {
1544 return peer1;
1545 }
1546 else if (peer2_value < value && value < peer1_value)
1547 {
1548 return peer2;
1549 }
1550 else if (peer1_value < peer2_value && peer2_value < value)
1551 {
1552 return peer2;
1553 }
1554 else // if (peer2_value < peer1_value && peer1_value < value)
1555 {
1556 return peer1;
1557 }
1558}
1559
1560#if 0
1561/**
1562 *
1563 *
1564 */
1565void
1566test_print_trail (struct GNUNET_PeerIdentity *trail,
1567 unsigned int trail_length)
1568{
1569 struct GNUNET_PeerIdentity print_peer;
1570 int i;
1571
1572 FPRINTF (stderr,_("\nSUPU %s, %s, %d,trail_length = %d"),
1573 __FILE__, __func__,__LINE__,trail_length);
1574 for (i =0 ; i< trail_length; i++)
1575 {
1576 print_peer = trail[i];
1577 FPRINTF (stderr,_("\nSUPU %s, %s, %d,trail[%d]=%s"),
1578 __FILE__, __func__,__LINE__,i,GNUNET_i2s(&print_peer));
1579 }
1580}
1581#endif
1582
1583#if 0
1584/**
1585 * This is a test function to print all the entries of friend table.
1586 */
1587static void
1588test_friend_peermap_print ()
1589{
1590 struct FriendInfo *friend;
1591 struct GNUNET_CONTAINER_MultiPeerMapIterator *friend_iter;
1592 struct GNUNET_PeerIdentity print_peer;
1593 struct GNUNET_PeerIdentity key_ret;
1594 int i;
1595
1596 print_peer = my_identity;
1597 FPRINTF (stderr,_("\nSUPU************ FRIEND_PEERMAP of %s"),GNUNET_i2s(&print_peer));
1598 friend_iter = GNUNET_CONTAINER_multipeermap_iterator_create (friend_peermap);
1599
1600 for (i = 0; i < GNUNET_CONTAINER_multipeermap_size (friend_peermap); i++)
1601 {
1602 if(GNUNET_YES == GNUNET_CONTAINER_multipeermap_iterator_next (friend_iter,
1603 &key_ret,
1604 (const void **)&friend))
1605 {
1606 GNUNET_memcpy (&print_peer, &key_ret, sizeof (struct GNUNET_PeerIdentity));
1607 FPRINTF (stderr,_("\nSUPU %s, %s, %d, friend = %s, friend->trails_count = %d"),
1608 __FILE__, __func__,__LINE__, GNUNET_i2s(&print_peer), friend->trails_count);
1609 }
1610 }
1611}
1612#endif
1613
1614#if 0
1615/**
1616 * This is a test function, to print all the entries of finger table.
1617 */
1618static void
1619test_finger_table_print()
1620{
1621 struct FingerInfo *finger;
1622 struct GNUNET_PeerIdentity print_peer;
1623 //struct Trail *trail;
1624 int i;
1625 //int j;
1626 //int k;
1627 print_peer = my_identity;
1628 FPRINTF (stderr,_("\nSUPU************ FINGER_TABLE of %s"),GNUNET_i2s(&print_peer));
1629 for (i = 0; i < MAX_FINGERS; i++)
1630 {
1631 finger = &finger_table[i];
1632
1633 if (GNUNET_NO == finger->is_present)
1634 continue;
1635
1636 print_peer = finger->finger_identity;
1637 FPRINTF (stderr,_("\nSUPU %s, %s, %d, finger_table[%d] = %s, trails_count = %d"),
1638 __FILE__, __func__,__LINE__,i,GNUNET_i2s (&print_peer), finger->trails_count);
1639
1640#if 0
1641 for (j = 0; j < finger->trails_count; j++)
1642 {
1643 trail = &finger->trail_list[j];
1644 FPRINTF (stderr,_("\nSUPU %s, %s, %d, trail_id[%d]=%s"),__FILE__, __func__,__LINE__,j, GNUNET_h2s(&trail->trail_id));
1645 struct Trail_Element *element;
1646 element = trail->trail_head;
1647 for (k = 0; k < trail->trail_length; k++)
1648 {
1649 print_peer = element->peer;
1650 FPRINTF (stderr,_("\nSUPU %s, %s, %d,trail[%d] = %s "),__FILE__, __func__,__LINE__,k, GNUNET_i2s(&print_peer));
1651 element = element->next;
1652 }
1653 }
1654 #endif
1655 }
1656}
1657#endif
1658
1659/**
1660 * Select the closest peer among two peers (which should not be same)
1661 * with respect to value and finger_table_index
1662 * NOTE: peer1 != peer2
1663 * @param peer1 First peer
1664 * @param peer2 Second peer
1665 * @param value Value relative to which we find the closest
1666 * @param is_predecessor Is value a predecessor or any other finger.
1667 * @return Closest peer among two peers.
1668 */
1669static const struct GNUNET_PeerIdentity *
1670select_closest_peer (const struct GNUNET_PeerIdentity *peer1,
1671 const struct GNUNET_PeerIdentity *peer2,
1672 uint64_t value,
1673 unsigned int is_predecessor)
1674{
1675 /* This check is here to ensure that calling function never sends
1676 same peer value in peer1 and peer2. Remove it later. */
1677 GNUNET_assert(0 != GNUNET_CRYPTO_cmp_peer_identity (peer1, peer2));
1678 if (1 == is_predecessor)
1679 return select_closest_predecessor (peer1, peer2, value);
1680
1681 // TODO: Change name to something like select_closest_successor!!
1682 return select_closest_finger (peer1, peer2, value);
1683}
1684
1685
1686/**
1687 * Iterate over the list of all the trails of a finger. In case the first
1688 * friend to reach the finger has reached trail threshold or is congested,
1689 * then don't select it. In case there multiple available good trails to reach
1690 * to Finger, choose the one with shortest trail length.
1691 * Note: We use length as parameter. But we can use any other suitable parameter
1692 * also.
1693 * @param finger Finger Finger whose trail we have to select.
1694 * @return Trail Selected Trail.
1695 */
1696static struct Trail *
1697select_finger_trail (struct FingerInfo *finger)
1698{
1699 struct FriendInfo *friend;
1700 struct Trail *current_finger_trail;
1701 struct Trail *best_trail = NULL;
1702 unsigned int i;
1703
1704 GNUNET_assert (finger->trails_count > 0);
1705 for (i = 0; i < finger->trails_count; i++)
1706 {
1707 current_finger_trail = &finger->trail_list[i];
1708
1709 /* No trail stored at this index. */
1710 if (GNUNET_NO == current_finger_trail->is_present)
1711 continue;
1712
1713 GNUNET_assert (NULL !=
1714 (friend =
1715 GNUNET_CONTAINER_multipeermap_get (friend_peermap,
1716 &current_finger_trail->trail_head->peer)));
1717
1718 /* First friend to reach trail is not free. */
1719 if (GNUNET_YES == is_friend_congested (friend))
1720 continue;
1721
1722 if (NULL == best_trail ||
1723 best_trail->trail_length > current_finger_trail->trail_length)
1724 {
1725 best_trail = current_finger_trail;
1726 }
1727 }
1728
1729 return best_trail;
1730}
1731
1732
1733/**
1734 * Compare FINGER entry with current successor. If finger's first friend of all
1735 * its trail is not congested and has not crossed trail threshold, then check
1736 * if finger peer identity is closer to final_destination_finger_value than
1737 * current_successor. If yes then update current_successor.
1738 * @param current_successor[in/out]
1739 * @return
1740 */
1741static void
1742compare_finger_and_current_closest_peer (struct Closest_Peer *current_closest_peer)
1743{
1744 struct FingerInfo *finger;
1745 const struct GNUNET_PeerIdentity *closest_peer;
1746 struct Trail *finger_trail;
1747 int i;
1748
1749 /* Iterate over finger table. */
1750 for (i = 0; i < MAX_FINGERS; i++)
1751 {
1752 finger = &finger_table[i];
1753
1754 if (GNUNET_NO == finger->is_present)
1755 continue;
1756
1757 if (0 == GNUNET_CRYPTO_cmp_peer_identity (&finger->finger_identity,
1758 &current_closest_peer->best_known_destination))
1759 continue;
1760
1761 /* If I am my own finger, then ignore this finger. */
1762 if (0 == GNUNET_CRYPTO_cmp_peer_identity (&finger->finger_identity,
1763 &my_identity))
1764 continue;
1765
1766 /* If finger is a friend, we have already checked it in previous function. */
1767 if (NULL != (GNUNET_CONTAINER_multipeermap_get (friend_peermap,
1768 &finger->finger_identity)))
1769 {
1770 continue;
1771 }
1772
1773 closest_peer = select_closest_peer (&finger->finger_identity,
1774 &current_closest_peer->best_known_destination,
1775 current_closest_peer->destination_finger_value,
1776 current_closest_peer->is_predecessor);
1777
1778 if (0 == GNUNET_CRYPTO_cmp_peer_identity(&finger->finger_identity,
1779 closest_peer))
1780 {
1781 /* Choose one of the trail to reach to finger. */
1782 finger_trail = select_finger_trail (finger);
1783
1784 /* In case no trail found, ignore this finger. */
1785 if (NULL == finger_trail)
1786 continue;
1787
1788 current_closest_peer->best_known_destination = *closest_peer;
1789 current_closest_peer->next_hop = finger_trail->trail_head->peer;
1790 current_closest_peer->trail_id = finger_trail->trail_id;
1791 current_closest_peer->finger_table_index = i;
1792 }
1793 continue;
1794 }
1795}
1796
1797
1798/**
1799 * Compare friend entry with current successor.
1800 * If friend identity and current_successor is same, then do nothing.
1801 * If friend is not congested and has not crossed trail threshold, then check
1802 * if friend peer identity is closer to final_destination_finger_value than
1803 * current_successor. If yes then update current_successor.
1804 *
1805 * @param cls closure
1806 * @param key current public key
1807 * @param value struct Closest_Peer
1808 * @return #GNUNET_YES if we should continue to iterate,
1809 * #GNUNET_NO if not.
1810 */
1811static int
1812compare_friend_and_current_closest_peer (void *cls,
1813 const struct GNUNET_PeerIdentity *key,
1814 void *value)
1815{
1816 struct FriendInfo *friend = value;
1817 struct Closest_Peer *current_closest_peer = cls;
1818 const struct GNUNET_PeerIdentity *closest_peer;
1819
1820 /* Friend is either congested or has crossed threshold. */
1821 if (GNUNET_YES == is_friend_congested (friend))
1822 return GNUNET_YES;
1823
1824 /* If current_closest_peer and friend identity are same, then do nothing.*/
1825 if (0 == GNUNET_CRYPTO_cmp_peer_identity (friend->id,
1826 &current_closest_peer->best_known_destination))
1827 {
1828 GNUNET_break (0);
1829 return GNUNET_YES;
1830 }
1831
1832 closest_peer = select_closest_peer (friend->id,
1833 &current_closest_peer->best_known_destination,
1834 current_closest_peer->destination_finger_value,
1835 current_closest_peer->is_predecessor);
1836
1837 /* Is friend the closest successor? */
1838 if (0 == GNUNET_CRYPTO_cmp_peer_identity (friend->id,
1839 closest_peer))
1840 {
1841 current_closest_peer->best_known_destination = *friend->id;
1842 current_closest_peer->next_hop = *friend->id;
1843 }
1844 return GNUNET_YES;
1845}
1846
1847
1848/**
1849 * Initialize current_successor to my_identity.
1850 * @param my_identity My peer identity
1851 * @return Updated closest_peer
1852 */
1853static struct Closest_Peer
1854init_closest_peer (struct GNUNET_PeerIdentity my_identity,
1855 uint64_t destination_finger_value,
1856 unsigned int is_predecessor)
1857{
1858 struct Closest_Peer current_closest_peer;
1859
1860 memset (&current_closest_peer.trail_id,
1861 0,
1862 sizeof(struct GNUNET_HashCode));
1863 current_closest_peer.destination_finger_value = destination_finger_value;
1864 current_closest_peer.is_predecessor = is_predecessor;
1865 current_closest_peer.next_hop = my_identity;
1866 current_closest_peer.best_known_destination = my_identity;
1867 current_closest_peer.finger_table_index = 65; //65 is a for non valid finger table index.
1868 return current_closest_peer;
1869}
1870
1871
1872/**
1873 * Find locally best known peer, among your own identity, friend and finger list,
1874 * which is closest to given destination_finger_value.
1875 *
1876 * NOTE: In case a friend is also a finger, then it is always chosen as friend
1877 * not a finger.
1878 * @param destination_finger_value Peer closest to this value will be the next destination.
1879 * @param is_predecessor Are we looking for predecessor or finger?
1880 * @return Closest_Peer that contains all the relevant field to reach to
1881 * @a destination_finger_value
1882 */
1883static struct Closest_Peer
1884find_local_best_known_next_hop (uint64_t destination_finger_value,
1885 unsigned int is_predecessor)
1886{
1887 struct Closest_Peer current_closest_peer;
1888
1889 /* Initialize current_successor to my_identity. */
1890 current_closest_peer = init_closest_peer (my_identity,
1891 destination_finger_value,
1892 is_predecessor);
1893
1894 /* Compare each friend entry with current_successor and update current_successor
1895 * with friend if its closest. */
1896 GNUNET_assert
1897 (GNUNET_SYSERR !=
1898 GNUNET_CONTAINER_multipeermap_iterate (friend_peermap,
1899 &compare_friend_and_current_closest_peer,
1900 &current_closest_peer));
1901
1902 /* Compare each finger entry with current_successor and update current_successor
1903 * with finger if its closest. */
1904 compare_finger_and_current_closest_peer (&current_closest_peer);
1905 return current_closest_peer;
1906}
1907
1908
1909/**
1910 * Construct a Put message and send it to target_peer.
1911 * @param key Key for the content
1912 * @param block_type Type of the block
1913 * @param options Routing options
1914 * @param desired_replication_level Desired replication count
1915 * @param best_known_dest Peer to which this message should reach eventually,
1916 * as it is best known destination to me.
1917 * @param intermediate_trail_id Trail id in case
1918 * @param target_peer Peer to which this message will be forwarded.
1919 * @param hop_count Number of hops traversed so far.
1920 * @param put_path_length Total number of peers in @a put_path
1921 * @param put_path Number of peers traversed so far
1922 * @param expiration_time When does the content expire
1923 * @param data Content to store
1924 * @param data_size Size of content @a data in bytes
1925 */
1926void
1927GDS_NEIGHBOURS_send_put (const struct GNUNET_HashCode *key,
1928 enum GNUNET_BLOCK_Type block_type,
1929 enum GNUNET_DHT_RouteOption options,
1930 uint32_t desired_replication_level,
1931 struct GNUNET_PeerIdentity best_known_dest,
1932 struct GNUNET_HashCode intermediate_trail_id,
1933 struct GNUNET_PeerIdentity *target_peer,
1934 uint32_t hop_count,
1935 uint32_t put_path_length,
1936 struct GNUNET_PeerIdentity *put_path,
1937 struct GNUNET_TIME_Absolute expiration_time,
1938 const void *data, size_t data_size)
1939{
1940 struct PeerPutMessage *ppm;
1941 struct GNUNET_MQ_Envelope *env;
1942 struct FriendInfo *target_friend;
1943 struct GNUNET_PeerIdentity *pp;
1944 size_t msize;
1945
1946 msize = put_path_length * sizeof (struct GNUNET_PeerIdentity) + data_size;
1947 if (msize + sizeof (struct PeerPutMessage)
1948 >= GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE)
1949 {
1950 put_path_length = 0;
1951 msize = data_size;
1952 }
1953 if (msize + sizeof (struct PeerPutMessage)
1954 >= GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE)
1955 {
1956 GNUNET_break (0);
1957 return;
1958 }
1959
1960 GNUNET_assert (NULL !=
1961 (target_friend =
1962 GNUNET_CONTAINER_multipeermap_get (friend_peermap,
1963 target_peer)));
1964 env = GNUNET_MQ_msg_extra (ppm,
1965 msize,
1966 GNUNET_MESSAGE_TYPE_XDHT_P2P_PUT);
1967 ppm->options = htonl (options);
1968 ppm->block_type = htonl (block_type);
1969 ppm->hop_count = htonl (hop_count + 1);
1970 ppm->desired_replication_level = htonl (desired_replication_level);
1971 ppm->expiration_time = GNUNET_TIME_absolute_hton (expiration_time);
1972 ppm->best_known_destination = best_known_dest;
1973 ppm->intermediate_trail_id = intermediate_trail_id;
1974 ppm->key = *key;
1975 ppm->put_path_length = htonl (put_path_length);
1976 pp = (struct GNUNET_PeerIdentity *) &ppm[1];
1977 GNUNET_memcpy (pp,
1978 put_path,
1979 put_path_length * sizeof (struct GNUNET_PeerIdentity));
1980 GNUNET_memcpy (&pp[put_path_length],
1981 data,
1982 data_size);
1983 GNUNET_MQ_send (target_friend->mq,
1984 env);
1985}
1986
1987
1988/**
1989 * Handle the put request from the client.
1990 *
1991 * @param block_type Type of the block
1992 * @param options Routing options
1993 * @param desired_replication_level Desired replication count
1994 * @param expiration_time When does the content expire
1995 * @param hop_count how many hops has this message traversed so far
1996 * @param bf Bloom filter of peers this PUT has already traversed
1997 * @param key Key for the content
1998 * @param put_path_length number of entries in put_path
1999 * @param put_path peers this request has traversed so far (if tracked)
2000 * @param data Content to store
2001 * @param data_size Size of content @a data in bytes
2002 * @return #GNUNET_OK if the request was forwarded, #GNUNET_NO if not
2003 */
2004int
2005GDS_NEIGHBOURS_handle_put (enum GNUNET_BLOCK_Type block_type,
2006 enum GNUNET_DHT_RouteOption options,
2007 uint32_t desired_replication_level,
2008 struct GNUNET_TIME_Absolute expiration_time,
2009 uint32_t hop_count,
2010 struct GNUNET_CONTAINER_BloomFilter *bf,
2011 const struct GNUNET_HashCode *key,
2012 unsigned int put_path_length,
2013 struct GNUNET_PeerIdentity *put_path,
2014 const void *data,
2015 size_t data_size)
2016{
2017 struct GNUNET_PeerIdentity best_known_dest;
2018 struct GNUNET_HashCode intermediate_trail_id;
2019 struct GNUNET_PeerIdentity next_hop;
2020 uint64_t key_value;
2021 struct Closest_Peer successor;
2022
2023 GNUNET_memcpy (&key_value,
2024 key,
2025 sizeof (uint64_t));
2026 key_value = GNUNET_ntohll (key_value);
2027 successor = find_local_best_known_next_hop (key_value,
2028 GDS_FINGER_TYPE_NON_PREDECESSOR);
2029 best_known_dest = successor.best_known_destination;
2030 next_hop = successor.next_hop;
2031 intermediate_trail_id = successor.trail_id;
2032
2033 if (0 == GNUNET_CRYPTO_cmp_peer_identity (&best_known_dest,
2034 &my_identity))
2035 {
2036 DEBUG("\n PUT_REQUEST_SUCCESSFUL for key = %s",
2037 GNUNET_h2s(key));
2038 /* I am the destination. */
2039 GDS_DATACACHE_handle_put (expiration_time,
2040 key,
2041 0,
2042 NULL,
2043 block_type,
2044 data_size,
2045 data);
2046 GDS_CLIENTS_process_put (options,
2047 block_type,
2048 0,
2049 ntohl (desired_replication_level),
2050 1,
2051 &my_identity,
2052 expiration_time,
2053 key,
2054 data,
2055 data_size);
2056 return GNUNET_NO;
2057 }
2058 /* In case we are sending the request to a finger, then send across all of its
2059 trail.*/
2060 GDS_NEIGHBOURS_send_put (key,
2061 block_type,
2062 options,
2063 desired_replication_level,
2064 best_known_dest,
2065 intermediate_trail_id,
2066 &next_hop,
2067 0,
2068 1,
2069 &my_identity,
2070 expiration_time,
2071 data,
2072 data_size);
2073 return GNUNET_OK;
2074}
2075
2076
2077/**
2078 * Construct a Get message and send it to target_peer.
2079 *
2080 * @param key Key for the content
2081 * @param block_type Type of the block
2082 * @param options Routing options
2083 * @param desired_replication_level Desired replication count
2084 * @param best_known_dest Peer which should get this message. Same as target peer
2085 * if best_known_dest is a friend else its a finger.
2086 * @param intermediate_trail_id Trail id to reach to @a best_known_dest
2087 * in case it is a finger else set to 0.
2088 * @param target_peer Peer to which this message will be forwarded.
2089 * @param hop_count Number of hops traversed so far.
2090 * @param data Content to store
2091 * @param data_size Size of content @a data in bytes
2092 * @param get_path_length Total number of peers in @a get_path
2093 * @param get_path Number of peers traversed so far
2094 */
2095void
2096GDS_NEIGHBOURS_send_get (const struct GNUNET_HashCode *key,
2097 enum GNUNET_BLOCK_Type block_type,
2098 enum GNUNET_DHT_RouteOption options,
2099 uint32_t desired_replication_level,
2100 const struct GNUNET_PeerIdentity *best_known_dest,
2101 const struct GNUNET_HashCode *intermediate_trail_id,
2102 const struct GNUNET_PeerIdentity *target_peer,
2103 uint32_t hop_count,
2104 uint32_t get_path_length,
2105 const struct GNUNET_PeerIdentity *get_path)
2106{
2107 struct PeerGetMessage *pgm;
2108 struct GNUNET_MQ_Envelope *env;
2109 struct FriendInfo *target_friend;
2110 size_t msize;
2111
2112 msize = get_path_length * sizeof (struct GNUNET_PeerIdentity);
2113 if (msize + sizeof (struct PeerGetMessage)
2114 >= GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE)
2115 {
2116 GNUNET_break (0);
2117 return;
2118 }
2119 GNUNET_assert (NULL !=
2120 (target_friend =
2121 GNUNET_CONTAINER_multipeermap_get (friend_peermap,
2122 target_peer)));
2123 env = GNUNET_MQ_msg_extra (pgm,
2124 msize,
2125 GNUNET_MESSAGE_TYPE_XDHT_P2P_GET);
2126 pgm->get_path_length = htonl (get_path_length);
2127 pgm->best_known_destination = *best_known_dest;
2128 pgm->key = *key;
2129 pgm->intermediate_trail_id = *intermediate_trail_id;
2130 pgm->hop_count = htonl (hop_count + 1);
2131 pgm->get_path_length = htonl (get_path_length);
2132 GNUNET_memcpy (&pgm[1],
2133 get_path,
2134 msize);
2135 GNUNET_MQ_send (target_friend->mq,
2136 env);
2137}
2138
2139
2140/**
2141 * Send the get result to requesting client.
2142 *
2143 * @param key Key of the requested data.
2144 * @param block_type Block type
2145 * @param target_peer Next peer to forward the message to.
2146 * @param source_peer Peer which has the data for the key.
2147 * @param put_path_length Number of peers in @a put_path
2148 * @param put_path Path taken to put the data at its stored location.
2149 * @param get_path_length Number of peers in @a get_path
2150 * @param get_path Path taken to reach to the location of the key.
2151 * @param expiration When will this result expire?
2152 * @param data Payload to store
2153 * @param data_size Size of the @a data
2154 */
2155void
2156GDS_NEIGHBOURS_send_get_result (const struct GNUNET_HashCode *key,
2157 enum GNUNET_BLOCK_Type block_type,
2158 const struct GNUNET_PeerIdentity *target_peer,
2159 const struct GNUNET_PeerIdentity *source_peer,
2160 unsigned int put_path_length,
2161 const struct GNUNET_PeerIdentity *put_path,
2162 unsigned int get_path_length,
2163 const struct GNUNET_PeerIdentity *get_path,
2164 struct GNUNET_TIME_Absolute expiration,
2165 const void *data, size_t data_size)
2166{
2167 struct PeerGetResultMessage *get_result;
2168 struct GNUNET_PeerIdentity *paths;
2169 struct GNUNET_MQ_Envelope *env;
2170 struct FriendInfo *target_friend;
2171 int current_path_index;
2172 size_t msize;
2173
2174 msize = (put_path_length + get_path_length) * sizeof (struct GNUNET_PeerIdentity) +
2175 data_size;
2176 if (msize + sizeof (struct PeerGetResultMessage)
2177 >= GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE)
2178 {
2179 put_path_length = 0;
2180 msize = data_size;
2181 }
2182 if (msize + sizeof (struct PeerGetResultMessage)
2183 >= GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE)
2184 {
2185 GNUNET_break(0);
2186 return;
2187 }
2188 current_path_index = 0;
2189 if (get_path_length > 0)
2190 {
2191 current_path_index = search_my_index (get_path,
2192 get_path_length);
2193 if (-1 == current_path_index)
2194 {
2195 GNUNET_break (0);
2196 return;
2197 }
2198 if ((get_path_length + 1) == current_path_index)
2199 {
2200 DEBUG ("Peer found twice in get path. Not allowed \n");
2201 GNUNET_break (0);
2202 return;
2203 }
2204 }
2205 if (0 == current_path_index)
2206 {
2207 DEBUG ("GET_RESULT TO CLIENT KEY = %s, Peer = %s",
2208 GNUNET_h2s (key),
2209 GNUNET_i2s (&my_identity));
2210 GDS_CLIENTS_handle_reply (expiration,
2211 key,
2212 get_path_length,
2213 get_path,
2214 put_path_length,
2215 put_path,
2216 block_type,
2217 data_size,
2218 data);
2219 return;
2220 }
2221 env = GNUNET_MQ_msg_extra (get_result,
2222 msize,
2223 GNUNET_MESSAGE_TYPE_XDHT_P2P_GET_RESULT);
2224 get_result->key = *key;
2225 get_result->querying_peer = *source_peer;
2226 get_result->expiration_time = GNUNET_TIME_absolute_hton (expiration);
2227 get_result->get_path_length = htonl (get_path_length);
2228 get_result->put_path_length = htonl (put_path_length);
2229 paths = (struct GNUNET_PeerIdentity *)&get_result[1];
2230 GNUNET_memcpy (paths,
2231 put_path,
2232 put_path_length * sizeof (struct GNUNET_PeerIdentity));
2233 GNUNET_memcpy (&paths[put_path_length],
2234 get_path,
2235 get_path_length * sizeof (struct GNUNET_PeerIdentity));
2236 GNUNET_memcpy (&paths[put_path_length + get_path_length],
2237 data,
2238 data_size);
2239
2240 GNUNET_assert (NULL !=
2241 (target_friend =
2242 GNUNET_CONTAINER_multipeermap_get (friend_peermap,
2243 &get_path[current_path_index - 1])));
2244 GNUNET_MQ_send (target_friend->mq,
2245 env);
2246}
2247
2248
2249/**
2250 * Handle a result for a GET operation.
2251 *
2252 * @param cls closure
2253 * @param type type of the block
2254 * @param expiration_time when does the content expire
2255 * @param key key for the content
2256 * @param put_path_length number of entries in @a put_path
2257 * @param put_path peers the original PUT traversed (if tracked)
2258 * @param get_path_length number of entries in @a get_path
2259 * @param get_path peers this reply has traversed so far (if tracked)
2260 * @param data payload of the reply
2261 * @param data_size number of bytes in @a data
2262 */
2263static void
2264get_cb (void *cls,
2265 enum GNUNET_BLOCK_Type type,
2266 struct GNUNET_TIME_Absolute expiration_time,
2267 const struct GNUNET_HashCode *key,
2268 unsigned int put_path_length,
2269 const struct GNUNET_PeerIdentity *put_path,
2270 unsigned int get_path_length,
2271 const struct GNUNET_PeerIdentity *get_path,
2272 const void *data,
2273 size_t data_size)
2274{
2275 struct GNUNET_PeerIdentity *target_peer = cls;
2276 // FIXME: inline?
2277 GDS_NEIGHBOURS_send_get_result (key,
2278 type,
2279 target_peer,
2280 &my_identity,
2281 put_path_length,
2282 put_path,
2283 1,
2284 &my_identity,
2285 expiration_time,
2286 data,
2287 data_size);
2288}
2289
2290
2291/**
2292 * Perform a GET operation. Forwards the given request to other
2293 * peers. Does not lookup the key locally. May do nothing if this is
2294 * the only peer in the network (or if we are the closest peer in the
2295 * network).
2296 *
2297 * @param block_type type of the block
2298 * @param options routing options
2299 * @param desired_replication_level desired replication count
2300 * @param hop_count how many hops did this request traverse so far?
2301 * @param key key for the content
2302 * @param xquery extended query
2303 * @param xquery_size number of bytes in @a xquery
2304 * @param reply_bf bloomfilter to filter duplicates
2305 * @param reply_bf_mutator mutator for @a reply_bf
2306 * @param peer_bf filter for peers not to select (again, updated)
2307 * @return #GNUNET_OK if the request was forwarded, #GNUNET_NO if not
2308 */
2309int
2310GDS_NEIGHBOURS_handle_get (enum GNUNET_BLOCK_Type block_type,
2311 enum GNUNET_DHT_RouteOption options,
2312 uint32_t desired_replication_level,
2313 uint32_t hop_count,
2314 const struct GNUNET_HashCode *key,
2315 const void *xquery, size_t xquery_size,
2316 const struct GNUNET_CONTAINER_BloomFilter *reply_bf,
2317 uint32_t reply_bf_mutator,
2318 struct GNUNET_CONTAINER_BloomFilter *peer_bf)
2319{
2320 struct Closest_Peer successor;
2321 struct GNUNET_PeerIdentity best_known_dest;
2322 struct GNUNET_HashCode intermediate_trail_id;
2323 uint64_t key_value;
2324
2325 GNUNET_memcpy (&key_value,
2326 key,
2327 sizeof (uint64_t));
2328 key_value = GNUNET_ntohll (key_value);
2329 successor = find_local_best_known_next_hop (key_value,
2330 GDS_FINGER_TYPE_NON_PREDECESSOR);
2331 best_known_dest = successor.best_known_destination;
2332 intermediate_trail_id = successor.trail_id;
2333
2334 /* I am the destination. I have the data. */
2335 if (0 == GNUNET_CRYPTO_cmp_peer_identity (&my_identity,
2336 &best_known_dest))
2337 {
2338 GDS_DATACACHE_handle_get (key,
2339 block_type,
2340 NULL,
2341 0,
2342 NULL,
2343 0,
2344 &get_cb,
2345 NULL);
2346 return GNUNET_NO;
2347 }
2348
2349 GDS_NEIGHBOURS_send_get (key,
2350 block_type,
2351 options,
2352 desired_replication_level,
2353 &best_known_dest,
2354 &intermediate_trail_id,
2355 &successor.next_hop,
2356 0,
2357 1,
2358 &my_identity);
2359 return GNUNET_OK;
2360}
2361
2362
2363/**
2364 * Randomly choose one of your friends (which is not congested and have not crossed
2365 * trail threshold) from the friend_peermap
2366 * @return Friend Randomly chosen friend.
2367 * NULL in case friend peermap is empty, or all the friends are either
2368 * congested or have crossed trail threshold.
2369 */
2370static struct FriendInfo *
2371select_random_friend ()
2372{
2373 unsigned int current_size;
2374 uint32_t index;
2375 unsigned int j = 0;
2376 struct GNUNET_CONTAINER_MultiPeerMapIterator *iter;
2377 struct GNUNET_PeerIdentity key_ret;
2378 struct FriendInfo *friend;
2379
2380 current_size = GNUNET_CONTAINER_multipeermap_size (friend_peermap);
2381
2382 /* No friends.*/
2383 if (0 == current_size)
2384 return NULL;
2385
2386 index = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, current_size);
2387 iter = GNUNET_CONTAINER_multipeermap_iterator_create (friend_peermap);
2388
2389 /* Iterate till you don't reach to index. */
2390 for (j = 0; j < index ; j++)
2391 GNUNET_assert (GNUNET_YES ==
2392 GNUNET_CONTAINER_multipeermap_iterator_next (iter, NULL, NULL));
2393
2394 do
2395 {
2396 /* Reset the index in friend peermap to 0 as we reached to the end. */
2397 if (j == current_size)
2398 {
2399 j = 0;
2400 GNUNET_CONTAINER_multipeermap_iterator_destroy (iter);
2401 iter = GNUNET_CONTAINER_multipeermap_iterator_create (friend_peermap);
2402
2403 }
2404
2405 /* Get the friend stored at the index, j*/
2406 GNUNET_assert (GNUNET_YES ==
2407 GNUNET_CONTAINER_multipeermap_iterator_next (iter,
2408 &key_ret,
2409 (const void **)&friend));
2410
2411 /* This friend is not congested and has not crossed trail threshold. */
2412 if ((friend->trails_count < TRAILS_THROUGH_FRIEND_THRESHOLD) &&
2413 (0 == GNUNET_TIME_absolute_get_remaining (friend->congestion_timestamp).rel_value_us))
2414 {
2415 break;
2416 }
2417 friend = NULL;
2418 j++;
2419 } while (j != index);
2420
2421 GNUNET_CONTAINER_multipeermap_iterator_destroy (iter);
2422 return friend;
2423}
2424
2425
2426/**
2427 * Compute 64 bit value of finger_identity corresponding to a finger index using
2428 * Chord formula.
2429 * For all fingers, n.finger[i] = n + pow (2,i),
2430 * For predecessor, n.finger[PREDECESSOR_FINGER_ID] = n - 1, where
2431 * n = my_identity, i = finger_index, n.finger[i] = 64 bit finger value
2432 *
2433 * @param finger_index Index corresponding to which we calculate 64 bit value.
2434 * @return 64 bit value.
2435 */
2436static uint64_t
2437compute_finger_identity_value (unsigned int finger_index)
2438{
2439 uint64_t my_id64;
2440
2441 GNUNET_memcpy (&my_id64,
2442 &my_identity,
2443 sizeof (uint64_t));
2444 my_id64 = GNUNET_ntohll (my_id64);
2445
2446 /* Are we looking for immediate predecessor? */
2447 if (PREDECESSOR_FINGER_ID == finger_index)
2448 return (my_id64 - 1);
2449 uint64_t add = (uint64_t)1 << finger_index;
2450 return (my_id64 + add);
2451}
2452
2453
2454/**
2455 * Choose a random friend. Calculate the next finger identity to search,from
2456 * current_search_finger_index. Start looking for the trail to reach to
2457 * finger identity through this random friend.
2458 *
2459 * @param cls closure for this task
2460 */
2461static void
2462send_find_finger_trail_message (void *cls)
2463{
2464 struct FriendInfo *target_friend;
2465 struct GNUNET_HashCode trail_id;
2466 struct GNUNET_HashCode intermediate_trail_id;
2467 unsigned int is_predecessor = 0;
2468 uint64_t finger_id_value;
2469
2470 /* Schedule another send_find_finger_trail_message task. After one round of
2471 * finger search, this time is exponentially backoff. */
2472 find_finger_trail_task_next_send_time.rel_value_us =
2473 find_finger_trail_task_next_send_time.rel_value_us +
2474 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
2475 DHT_FIND_FINGER_TRAIL_INTERVAL.rel_value_us);
2476 find_finger_trail_task =
2477 GNUNET_SCHEDULER_add_delayed (find_finger_trail_task_next_send_time,
2478 &send_find_finger_trail_message,
2479 NULL);
2480
2481 /* No space in my routing table. (Source and destination peers also store entries
2482 * in their routing table). */
2483 if (GNUNET_YES == GDS_ROUTING_threshold_reached())
2484 return;
2485
2486 target_friend = select_random_friend ();
2487 if (NULL == target_friend)
2488 return;
2489
2490 finger_id_value = compute_finger_identity_value (current_search_finger_index);
2491 if (PREDECESSOR_FINGER_ID == current_search_finger_index)
2492 is_predecessor = 1;
2493
2494 /* Generate a unique trail id for trail we are trying to setup. */
2495 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG,
2496 &trail_id,
2497 sizeof (trail_id));
2498 memset (&intermediate_trail_id,
2499 0,
2500 sizeof (struct GNUNET_HashCode));
2501 GDS_NEIGHBOURS_send_trail_setup (&my_identity,
2502 finger_id_value,
2503 target_friend->id,
2504 target_friend,
2505 0, NULL,
2506 is_predecessor,
2507 &trail_id,
2508 &intermediate_trail_id);
2509}
2510
2511
2512/**
2513 * In case there are already maximum number of possible trails to reach to a
2514 * finger, then check if the new trail's length is lesser than any of the
2515 * existing trails.
2516 * If yes then replace that old trail by new trail.
2517 *
2518 * Note: Here we are taking length as a parameter to choose the best possible
2519 * trail, but there could be other parameters also like:
2520 * 1. duration of existence of a trail - older the better.
2521 * 2. if the new trail is completely disjoint than the
2522 * other trails, then may be choosing it is better.
2523 *
2524 * @param finger Finger
2525 * @param new_finger_trail List of peers to reach from me to @a finger, NOT
2526 * including the endpoints.
2527 * @param new_finger_trail_length Total number of peers in @a new_finger_trail
2528 * @param new_finger_trail_id Unique identifier of @a new_finger_trail.
2529 */
2530static void
2531select_and_replace_trail (struct FingerInfo *finger,
2532 const struct GNUNET_PeerIdentity *new_trail,
2533 unsigned int new_trail_length,
2534 const struct GNUNET_HashCode *new_trail_id)
2535{
2536 struct Trail *current_trail;
2537 unsigned int largest_trail_length;
2538 unsigned int largest_trail_index;
2539 struct Trail_Element *trail_element;
2540 const struct GNUNET_PeerIdentity *next_hop;
2541 unsigned int i;
2542
2543 largest_trail_length = new_trail_length;
2544 largest_trail_index = MAXIMUM_TRAILS_PER_FINGER + 1;
2545
2546 GNUNET_assert (MAXIMUM_TRAILS_PER_FINGER == finger->trails_count);
2547
2548 for (i = 0; i < finger->trails_count; i++)
2549 {
2550 current_trail = &finger->trail_list[i];
2551 GNUNET_assert (GNUNET_YES == current_trail->is_present);
2552 if (current_trail->trail_length > largest_trail_length)
2553 {
2554 largest_trail_length = current_trail->trail_length;
2555 largest_trail_index = i;
2556 }
2557 }
2558
2559 /* New trail is not better than existing ones. Send trail teardown. */
2560 if (largest_trail_index == (MAXIMUM_TRAILS_PER_FINGER + 1))
2561 {
2562 next_hop = GDS_ROUTING_get_next_hop (new_trail_id,
2563 GDS_ROUTING_SRC_TO_DEST);
2564 GDS_ROUTING_remove_trail (new_trail_id);
2565 GDS_NEIGHBOURS_send_trail_teardown (new_trail_id,
2566 GDS_ROUTING_SRC_TO_DEST,
2567 next_hop);
2568 return;
2569 }
2570
2571 /* Send trail teardown message across the replaced trail. */
2572 struct Trail *replace_trail = &finger->trail_list[largest_trail_index];
2573 next_hop = GDS_ROUTING_get_next_hop (&replace_trail->trail_id,
2574 GDS_ROUTING_SRC_TO_DEST);
2575 GNUNET_assert (GNUNET_YES == GDS_ROUTING_remove_trail (&replace_trail->trail_id));
2576 GDS_NEIGHBOURS_send_trail_teardown (&replace_trail->trail_id,
2577 GDS_ROUTING_SRC_TO_DEST,
2578 next_hop);
2579
2580 /* Free the trail. */
2581 while (NULL != (trail_element = replace_trail->trail_head))
2582 {
2583 GNUNET_CONTAINER_DLL_remove (replace_trail->trail_head,
2584 replace_trail->trail_tail,
2585 trail_element);
2586 GNUNET_free_non_null (trail_element);
2587 }
2588
2589 /* Add new trial at that location. */
2590 replace_trail->is_present = GNUNET_YES;
2591 replace_trail->trail_length = new_trail_length;
2592 replace_trail->trail_id = *new_trail_id;
2593
2594 for (i = 0; i < new_trail_length; i++)
2595 {
2596 struct Trail_Element *element = GNUNET_new (struct Trail_Element);
2597 element->peer = new_trail[i];
2598
2599 GNUNET_CONTAINER_DLL_insert_tail (replace_trail->trail_head,
2600 replace_trail->trail_tail,
2601 element);
2602 }
2603 /* FIXME: URGENT Are we adding the trail back to the list. */
2604}
2605
2606
2607/**
2608 * Check if the new trail to reach to finger is unique or do we already have
2609 * such a trail present for finger.
2610 * @param existing_finger Finger identity
2611 * @param new_trail New trail to reach @a existing_finger
2612 * @param trail_length Total number of peers in new_trail.
2613 * @return #GNUNET_YES if the new trail is unique
2614 * #GNUNET_NO if same trail is already present.
2615 */
2616static int
2617is_new_trail_unique (struct FingerInfo *existing_finger,
2618 const struct GNUNET_PeerIdentity *new_trail,
2619 unsigned int trail_length)
2620{
2621 struct Trail *current_trail;
2622 struct Trail_Element *trail_element;
2623 int i;
2624 int j;
2625
2626 GNUNET_assert (existing_finger->trails_count > 0);
2627
2628 /* Iterate over list of trails. */
2629 for (i = 0; i < existing_finger->trails_count; i++)
2630 {
2631 current_trail = &(existing_finger->trail_list[i]);
2632 if(GNUNET_NO == current_trail->is_present)
2633 continue;
2634
2635 /* New trail and existing trail length are not same. */
2636 if (current_trail->trail_length != trail_length)
2637 {
2638 return GNUNET_YES;
2639 }
2640
2641 trail_element = current_trail->trail_head;
2642 for (j = 0; j < current_trail->trail_length; j++)
2643 {
2644 if (0 != GNUNET_CRYPTO_cmp_peer_identity (&new_trail[j],
2645 &trail_element->peer))
2646 {
2647 return GNUNET_YES;
2648 }
2649 trail_element = trail_element->next;
2650 }
2651 }
2652 return GNUNET_NO;
2653}
2654
2655
2656/**
2657 * FIXME; In case of multiple trails, we may have a case where a trail from in
2658 * between has been removed, then we should try to find a free slot , not simply
2659 * add a trail at then end of the list.
2660 * Add a new trail at a free slot in trail array of existing finger.
2661 * @param existing_finger Finger
2662 * @param new_finger_trail New trail from me to finger, NOT including endpoints
2663 * @param new_finger_trail_length Total number of peers in @a new_finger_trail
2664 * @param new_finger_trail_id Unique identifier of the trail.
2665 */
2666static void
2667add_new_trail (struct FingerInfo *existing_finger,
2668 const struct GNUNET_PeerIdentity *new_trail,
2669 unsigned int new_trail_length,
2670 const struct GNUNET_HashCode *new_trail_id)
2671{
2672 struct FriendInfo *friend;
2673 struct Trail *trail;
2674 unsigned int i;
2675 int free_slot = -1;
2676
2677 if (GNUNET_NO == is_new_trail_unique (existing_finger,
2678 new_trail,
2679 new_trail_length))
2680 return;
2681
2682 for (i = 0; i < existing_finger->trails_count; i++)
2683 {
2684 if (GNUNET_NO == existing_finger->trail_list[i].is_present)
2685 {
2686 free_slot = i;
2687 break;
2688 }
2689 }
2690
2691 if (-1 == free_slot)
2692 free_slot = i;
2693
2694 trail = &existing_finger->trail_list[free_slot];
2695 GNUNET_assert (GNUNET_NO == trail->is_present);
2696 trail->trail_id = *new_trail_id;
2697 trail->trail_length = new_trail_length;
2698 existing_finger->trails_count++;
2699 trail->is_present = GNUNET_YES;
2700 if (0 == new_trail_length)
2701 {
2702 friend = GNUNET_CONTAINER_multipeermap_get (friend_peermap,
2703 &existing_finger->finger_identity);
2704 }
2705 else
2706 {
2707 friend = GNUNET_CONTAINER_multipeermap_get (friend_peermap,
2708 &new_trail[0]);
2709 }
2710 GNUNET_assert (NULL != friend);
2711 friend->trails_count++;
2712 for (i = 0; i < new_trail_length; i++)
2713 {
2714 struct Trail_Element *element;
2715
2716 element = GNUNET_new (struct Trail_Element);
2717 element->peer = new_trail[i];
2718 GNUNET_CONTAINER_DLL_insert_tail (trail->trail_head,
2719 trail->trail_tail,
2720 element);
2721 }
2722
2723 existing_finger->trail_list[free_slot].trail_head = trail->trail_head;
2724 existing_finger->trail_list[free_slot].trail_tail = trail->trail_tail;
2725 existing_finger->trail_list[free_slot].trail_length = new_trail_length;
2726 existing_finger->trail_list[free_slot].trail_id = *new_trail_id;
2727 existing_finger->trail_list[free_slot].is_present = GNUNET_YES;
2728}
2729
2730
2731#if 0
2732/**
2733 * FIXME; In case of multiple trails, we may have a case where a trail from in
2734 * between has been removed, then we should try to find a free slot , not simply
2735 * add a trail at then end of the list.
2736 * Add a new trail at a free slot in trail array of existing finger.
2737 * @param existing_finger Finger
2738 * @param new_finger_trail New trail from me to finger, NOT including endpoints
2739 * @param new_finger_trail_length Total number of peers in @a new_finger_trail
2740 * @param new_finger_trail_id Unique identifier of the trail.
2741 */
2742static void
2743add_new_trail (struct FingerInfo *existing_finger,
2744 const struct GNUNET_PeerIdentity *new_trail,
2745 unsigned int new_trail_length,
2746 const struct GNUNET_HashCode *new_trail_id)
2747{
2748 struct Trail *trail;
2749 struct FriendInfo *first_friend;
2750 int i;
2751 int index;
2752
2753 if (GNUNET_NO == is_new_trail_unique (existing_finger,
2754 new_trail,
2755 new_trail_length))
2756 return;
2757
2758 index = existing_finger->trails_count;
2759 trail = &existing_finger->trail_list[index];
2760 GNUNET_assert (GNUNET_NO == trail->is_present);
2761 trail->trail_id = *new_trail_id;
2762 trail->trail_length = new_trail_length;
2763 existing_finger->trails_count++;
2764 trail->is_present = GNUNET_YES;
2765
2766 GNUNET_assert (NULL == (GNUNET_CONTAINER_multipeermap_get (friend_peermap,
2767 &existing_finger->finger_identity)));
2768 /* If finger is a friend then we never call this function. */
2769 GNUNET_assert (new_trail_length > 0);
2770
2771 first_friend = GNUNET_CONTAINER_multipeermap_get (friend_peermap,
2772 &new_trail[0]);
2773 first_friend->trails_count++;
2774
2775 for (i = 0; i < new_trail_length; i++)
2776 {
2777 struct Trail_Element *element;
2778
2779 element = GNUNET_new (struct Trail_Element);
2780 element->peer = new_trail[i];
2781 GNUNET_CONTAINER_DLL_insert_tail (trail->trail_head,
2782 trail->trail_tail,
2783 element);
2784 }
2785 /* Do we need to add trail head and trail tail in the trail list itearator.*/
2786 existing_finger->trail_list[index].trail_head = trail->trail_head;
2787 existing_finger->trail_list[index].trail_tail = trail->trail_tail;
2788 existing_finger->trail_list[index].trail_length = new_trail_length;
2789 existing_finger->trail_list[index].trail_id = *new_trail_id;
2790 existing_finger->trail_list[index].is_present = GNUNET_YES;
2791}
2792#endif
2793
2794/**
2795 * Get the next hop to send trail teardown message from routing table and
2796 * then delete the entry from routing table. Send trail teardown message for a
2797 * specific trail of a finger.
2798 * @param finger Finger whose trail is to be removed.
2799 * @param trail List of peers in trail from me to a finger, NOT including
2800 * endpoints.
2801 */
2802static void
2803send_trail_teardown (struct FingerInfo *finger,
2804 struct Trail *trail)
2805{
2806 struct FriendInfo *friend;
2807 const struct GNUNET_PeerIdentity *next_hop;
2808
2809 next_hop = GDS_ROUTING_get_next_hop (&trail->trail_id,
2810 GDS_ROUTING_SRC_TO_DEST);
2811 if (NULL == next_hop)
2812 {
2813// DEBUG(" NO ENTRY FOUND IN %s ROUTING TABLE for trail id %s, line=%d,traillength = %d",
2814// GNUNET_i2s(&my_identity), GNUNET_h2s(&trail->trail_id), __LINE__,trail->trail_length);
2815 return;
2816 }
2817 GNUNET_assert (0 != GNUNET_CRYPTO_cmp_peer_identity (&finger->finger_identity,
2818 &my_identity));
2819
2820 GNUNET_assert(GNUNET_YES == trail->is_present);
2821 if (trail->trail_length > 0)
2822 {
2823 friend = GNUNET_CONTAINER_multipeermap_get (friend_peermap,
2824 &trail->trail_head->peer);
2825 }
2826 else
2827 {
2828 friend = GNUNET_CONTAINER_multipeermap_get (friend_peermap,
2829 &finger->finger_identity);
2830 }
2831
2832 if(NULL == friend)
2833 {
2834 DEBUG ("\n LINE NO: = %d, Friend not found for trail id %s of peer %s trail length = %d",
2835 __LINE__,
2836 GNUNET_h2s (&trail->trail_id),
2837 GNUNET_i2s(&my_identity),
2838 trail->trail_length);
2839 return;
2840 }
2841 if ( (0 != GNUNET_CRYPTO_cmp_peer_identity (next_hop,
2842 friend->id) ) &&
2843 (0 == trail->trail_length))
2844 {
2845 DEBUG ("\n LINE NO: = %d, Friend not found for trail id %s of peer %s trail length = %d",
2846 __LINE__,
2847 GNUNET_h2s (&trail->trail_id),
2848 GNUNET_i2s (&my_identity),
2849 trail->trail_length);
2850 return;
2851 }
2852 GNUNET_assert (GNUNET_YES ==
2853 GDS_ROUTING_remove_trail (&trail->trail_id));
2854 friend->trails_count--;
2855 GDS_NEIGHBOURS_send_trail_teardown (&trail->trail_id,
2856 GDS_ROUTING_SRC_TO_DEST,
2857 friend->id);
2858}
2859
2860
2861/**
2862 * Send trail teardown message across all the trails to reach to finger.
2863 * @param finger Finger whose all the trail should be freed.
2864 */
2865static void
2866send_all_finger_trails_teardown (struct FingerInfo *finger)
2867{
2868 for (unsigned int i = 0; i < finger->trails_count; i++)
2869 {
2870 struct Trail *trail;
2871
2872 trail = &finger->trail_list[i];
2873 if (GNUNET_YES == trail->is_present)
2874 {
2875 send_trail_teardown (finger, trail);
2876 trail->is_present = GNUNET_NO;
2877 }
2878 }
2879}
2880
2881
2882/**
2883 * Free a specific trail
2884 * @param trail List of peers to be freed.
2885 */
2886static void
2887free_trail (struct Trail *trail)
2888{
2889 struct Trail_Element *trail_element;
2890
2891 while (NULL != (trail_element = trail->trail_head))
2892 {
2893 GNUNET_CONTAINER_DLL_remove (trail->trail_head,
2894 trail->trail_tail,
2895 trail_element);
2896 GNUNET_free_non_null (trail_element);
2897 }
2898 trail->trail_head = NULL;
2899 trail->trail_tail = NULL;
2900}
2901
2902
2903/**
2904 * Free finger and its trail.
2905 *
2906 * @param finger Finger to be freed.
2907 * @param finger_table_index Index at which finger is stored.
2908 */
2909static void
2910free_finger (struct FingerInfo *finger,
2911 unsigned int finger_table_index)
2912{
2913 struct Trail *trail;
2914
2915 for (unsigned int i = 0; i < finger->trails_count; i++)
2916 {
2917 trail = &finger->trail_list[i];
2918 if (GNUNET_NO == trail->is_present)
2919 continue;
2920
2921 if (trail->trail_length > 0)
2922 free_trail (trail);
2923 trail->is_present = GNUNET_NO;
2924 }
2925
2926 finger->is_present = GNUNET_NO;
2927 memset (&finger_table[finger_table_index],
2928 0,
2929 sizeof (finger_table[finger_table_index]));
2930}
2931
2932
2933/**
2934 * Add a new entry in finger table at finger_table_index.
2935 * In case I am my own finger, then we don't have a trail. In case of a friend,
2936 * we have a trail with unique id and '0' trail length.
2937 * In case a finger is a friend, then increment the trails count of the friend.
2938 *
2939 * @param finger_identity Peer Identity of new finger
2940 * @param finger_trail Trail to reach from me to finger (excluding both end points).
2941 * @param finger_trail_length Total number of peers in @a finger_trail.
2942 * @param trail_id Unique identifier of the trail.
2943 * @param finger_table_index Index in finger table.
2944 */
2945static void
2946add_new_finger (const struct GNUNET_PeerIdentity *finger_identity,
2947 const struct GNUNET_PeerIdentity *finger_trail,
2948 unsigned int finger_trail_length,
2949 const struct GNUNET_HashCode *trail_id,
2950 unsigned int finger_table_index)
2951{
2952 struct FingerInfo *new_entry;
2953 struct FriendInfo *first_trail_hop;
2954 struct Trail *trail;
2955 unsigned int i;
2956
2957 new_entry = GNUNET_new (struct FingerInfo);
2958 new_entry->finger_identity = *finger_identity;
2959 new_entry->finger_table_index = finger_table_index;
2960 new_entry->is_present = GNUNET_YES;
2961
2962 /* If the new entry is my own identity. */
2963 if (0 == GNUNET_CRYPTO_cmp_peer_identity (&my_identity,
2964 finger_identity))
2965 {
2966 new_entry->trails_count = 0;
2967 finger_table[finger_table_index] = *new_entry;
2968 GNUNET_free (new_entry);
2969 return;
2970 }
2971
2972 /* Finger is a friend. */
2973 if (0 == finger_trail_length)
2974 {
2975 new_entry->trail_list[0].trail_id = *trail_id;
2976 new_entry->trails_count = 1;
2977 new_entry->trail_list[0].is_present = GNUNET_YES;
2978 new_entry->trail_list[0].trail_length = 0;
2979 new_entry->trail_list[0].trail_head = NULL;
2980 new_entry->trail_list[0].trail_tail = NULL;
2981 finger_table[finger_table_index] = *new_entry;
2982 GNUNET_assert (NULL !=
2983 (first_trail_hop =
2984 GNUNET_CONTAINER_multipeermap_get (friend_peermap,
2985 finger_identity)));
2986
2987 first_trail_hop->trails_count++;
2988 GNUNET_free (new_entry);
2989 return;
2990 }
2991
2992 GNUNET_assert (NULL !=
2993 (first_trail_hop =
2994 GNUNET_CONTAINER_multipeermap_get (friend_peermap,
2995 &finger_trail[0])));
2996 new_entry->trails_count = 1;
2997 first_trail_hop->trails_count++;
2998 /* Copy the finger trail into trail. */
2999 trail = &new_entry->trail_list[0];
3000 for(i = 0; i < finger_trail_length; i++)
3001 {
3002 struct Trail_Element *element = GNUNET_new (struct Trail_Element);
3003
3004 element->next = NULL;
3005 element->prev = NULL;
3006 element->peer = finger_trail[i];
3007 GNUNET_CONTAINER_DLL_insert_tail (trail->trail_head,
3008 trail->trail_tail,
3009 element);
3010 }
3011
3012 /* Add trail to trail list. */
3013 trail->trail_length = finger_trail_length;
3014 trail->trail_id = *trail_id;
3015 trail->is_present = GNUNET_YES;
3016 finger_table[finger_table_index] = *new_entry;
3017 GNUNET_free (new_entry);
3018}
3019
3020
3021/**
3022 * Periodic task to verify current successor. There can be multiple trails to reach
3023 * to successor, choose the shortest one and send verify successor message
3024 * across that trail.
3025 *
3026 * @param cls closure for this task
3027 */
3028static void
3029send_verify_successor_message (void *cls)
3030{
3031 struct FriendInfo *target_friend;
3032 struct Trail *trail;
3033 struct Trail_Element *element;
3034 unsigned int trail_length;
3035 unsigned int i = 0;
3036 struct FingerInfo *successor;
3037
3038 successor = &finger_table[0];
3039
3040 /* This task will be scheduled when the result for Verify Successor is received. */
3041 send_verify_successor_task = NULL;
3042
3043 /* When verify successor is being called for first time *for current context*
3044 * cls will be NULL. If send_verify_successor_retry_task is not NO_TASK, we
3045 * must cancel the retry task scheduled for verify_successor of previous
3046 * context.
3047 */
3048 if (NULL == cls)
3049 {
3050 /* FIXME: Here we are scheduling a new verify successor task, as we
3051 got a new successor. But a send verify successor task may be in progress.
3052 1. We need to be sure that this is indeed a new successor. As this function
3053 is called even if we add a new trail to reach t old successor.
3054 2. Assuming the new successor is different, then verify successor message
3055 * to old successor may be following stages.
3056 * --> Waiting for verify successor result. Don't wait anymore. there is
3057 * no trail to reach from old successor to me, hence, routing
3058 * lookup will fail.
3059 * --> Waiting for notify confirmation. again don't wait for it. notify
3060 * confirmation will not succeded.
3061 */
3062 if (send_verify_successor_retry_task != NULL)
3063 {
3064 /* FIXME: Are we scheduling retry task as soon as we send verify message.
3065 If yes then here before making this task, first check if the message
3066 is for the same peer again. */
3067 struct VerifySuccessorContext *old_ctx =
3068 GNUNET_SCHEDULER_cancel(send_verify_successor_retry_task);
3069 /* old_ctx must not be NULL, as the retry task had been scheduled */
3070 GNUNET_assert(NULL != old_ctx);
3071 GNUNET_free(old_ctx);
3072 /* FIXME: Why don't we reset the task to NO_TASK here? */
3073 }
3074
3075 struct VerifySuccessorContext *ctx;
3076 ctx = GNUNET_new (struct VerifySuccessorContext);
3077
3078 ctx->num_retries_scheduled++;
3079 send_verify_successor_retry_task =
3080 GNUNET_SCHEDULER_add_delayed (verify_successor_retry_time,
3081 &send_verify_successor_message,
3082 ctx);
3083 }
3084 else
3085 {
3086 /* This is a retry attempt for verify_successor for a previous context */
3087 struct VerifySuccessorContext *ctx;
3088
3089 ctx = cls;
3090 ctx->num_retries_scheduled++;
3091 send_verify_successor_retry_task =
3092 GNUNET_SCHEDULER_add_delayed (verify_successor_retry_time,
3093 &send_verify_successor_message,
3094 ctx);
3095 }
3096
3097 /* Among all the trails to reach to successor, select first one which is present.*/
3098 for (i = 0; i < successor->trails_count; i++)
3099 {
3100 trail = &successor->trail_list[i];
3101 if (GNUNET_YES == trail->is_present)
3102 break;
3103 }
3104
3105 /* No valid trail found to reach to successor. */
3106 if (i == successor->trails_count)
3107 return;
3108
3109 GNUNET_assert(0 != GNUNET_CRYPTO_cmp_peer_identity (&my_identity,
3110 &successor->finger_identity));
3111 /* Trail stored at this index. */
3112 GNUNET_assert (GNUNET_YES == trail->is_present);
3113 if (NULL == GDS_ROUTING_get_next_hop (&trail->trail_id,
3114 GDS_ROUTING_SRC_TO_DEST))
3115 {
3116 DEBUG (" NO ENTRY FOUND IN %s ROUTING TABLE for trail id %s, line %u",
3117 GNUNET_i2s (&my_identity),
3118 GNUNET_h2s (&trail->trail_id),
3119 __LINE__);
3120 GNUNET_break(0);
3121 return;
3122 }
3123 trail_length = trail->trail_length;
3124 if (trail_length > 0)
3125 {
3126 /* Copy the trail into peer list. */
3127 struct GNUNET_PeerIdentity peer_list[trail_length];
3128
3129 element = trail->trail_head;
3130 for(i = 0; i < trail_length; i++)
3131 {
3132 peer_list[i] = element->peer;
3133 element = element->next;
3134 }
3135 GNUNET_assert (NULL != (target_friend =
3136 GNUNET_CONTAINER_multipeermap_get (friend_peermap,
3137 &peer_list[0])));
3138 GDS_NEIGHBOURS_send_verify_successor_message (&my_identity,
3139 &successor->finger_identity,
3140 &trail->trail_id,
3141 peer_list,
3142 trail_length,
3143 target_friend);
3144 }
3145 else
3146 {
3147 GNUNET_assert (NULL != (target_friend =
3148 GNUNET_CONTAINER_multipeermap_get (friend_peermap,
3149 &successor->finger_identity)));
3150 GDS_NEIGHBOURS_send_verify_successor_message (&my_identity,
3151 &successor->finger_identity,
3152 &trail->trail_id,
3153 NULL,
3154 0,
3155 target_friend);
3156 }
3157}
3158
3159
3160/**
3161 * FIXME: should this be a periodic task, incrementing the search finger index?
3162 * Update the current search finger index.
3163 * @a finger_identity
3164 * @a finger_table_index
3165 */
3166static void
3167update_current_search_finger_index (unsigned int finger_table_index)
3168{
3169 struct FingerInfo *successor;
3170
3171 /* FIXME correct this: only move current index periodically */
3172 if (finger_table_index != current_search_finger_index)
3173 return;
3174
3175 successor = &finger_table[0];
3176 GNUNET_assert (GNUNET_YES == successor->is_present);
3177
3178 /* We were looking for immediate successor. */
3179 if (0 == current_search_finger_index)
3180 {
3181 current_search_finger_index = PREDECESSOR_FINGER_ID;
3182 if (0 != GNUNET_CRYPTO_cmp_peer_identity (&my_identity,
3183 &successor->finger_identity))
3184 {
3185 if (NULL == send_verify_successor_task)
3186 {
3187 send_verify_successor_task
3188 = GNUNET_SCHEDULER_add_now (&send_verify_successor_message,
3189 NULL);
3190 }
3191 }
3192 return;
3193 }
3194 current_search_finger_index--;
3195}
3196
3197
3198/**
3199 * Get the least significant bit set in val.
3200 *
3201 * @param val Value
3202 * @return Position of first bit set, 65 in case of error.
3203 */
3204static unsigned int
3205find_set_bit (uint64_t val)
3206{
3207 uint64_t i;
3208 unsigned int pos;
3209
3210 i = 1;
3211 pos = 0;
3212
3213 while (!(i & val))
3214 {
3215 i = i << 1;
3216 pos++;
3217 if (pos > 63)
3218 {
3219 GNUNET_break (0);
3220 return 65;
3221 }
3222 }
3223
3224 if (val/i != 1)
3225 return 65; /* Some other bit was set to 1 as well. */
3226
3227 return pos;
3228}
3229
3230
3231/**
3232 * Calculate finger_table_index from initial 64 bit finger identity value that
3233 * we send in trail setup message.
3234 * @param ultimate_destination_finger_value Value that we calculated from our
3235 * identity and finger_table_index.
3236 * @param is_predecessor Is the entry for predecessor or not?
3237 * @return finger_table_index Value between 0 <= finger_table_index <= 64
3238 * finger_table_index > PREDECESSOR_FINGER_ID, if error occurs.
3239 */
3240static unsigned int
3241get_finger_table_index (uint64_t ultimate_destination_finger_value,
3242 unsigned int is_predecessor)
3243{
3244 uint64_t my_id64;
3245 uint64_t diff;
3246 unsigned int finger_table_index;
3247
3248 GNUNET_memcpy (&my_id64, &my_identity, sizeof (uint64_t));
3249 my_id64 = GNUNET_ntohll (my_id64);
3250
3251 /* Is this a predecessor finger? */
3252 if (1 == is_predecessor)
3253 {
3254 diff = my_id64 - ultimate_destination_finger_value;
3255 if (1 == diff)
3256 finger_table_index = PREDECESSOR_FINGER_ID;
3257 else
3258 finger_table_index = PREDECESSOR_FINGER_ID + 1; //error value
3259
3260 }
3261 else
3262 {
3263 diff = ultimate_destination_finger_value - my_id64;
3264 finger_table_index = find_set_bit (diff);
3265 }
3266 return finger_table_index;
3267}
3268
3269
3270/**
3271 * Remove finger and its associated data structures from finger table.
3272 * @param existing_finger Finger to be removed which is in finger table.
3273 * @param finger_table_index Index in finger table where @a existing_finger
3274 * is stored.
3275 */
3276static void
3277remove_existing_finger (struct FingerInfo *existing_finger,
3278 unsigned int finger_table_index)
3279{
3280 GNUNET_assert (GNUNET_YES == existing_finger->is_present);
3281
3282 /* If I am my own finger, then we have no trails. */
3283 if (0 == GNUNET_CRYPTO_cmp_peer_identity (&existing_finger->finger_identity,
3284 &my_identity))
3285 {
3286 existing_finger->is_present = GNUNET_NO;
3287 memset ((void *)&finger_table[finger_table_index], 0,
3288 sizeof (finger_table[finger_table_index]));
3289 return;
3290 }
3291
3292 /* For all other fingers, send trail teardown across all the trails to reach
3293 finger, and free the finger. */
3294 send_all_finger_trails_teardown (existing_finger);
3295 free_finger (existing_finger, finger_table_index);
3296}
3297
3298
3299/**
3300 * Check if there is already an entry in finger_table at finger_table_index.
3301 * We get the finger_table_index from 64bit finger value we got from the network.
3302 * -- If yes, then select the closest finger.
3303 * -- If new and existing finger are same, then check if you can store more
3304 * trails.
3305 * -- If yes then add trail, else keep the best trails to reach to the
3306 * finger.
3307 * -- If the new finger is closest, remove the existing entry, send trail
3308 * teardown message across all the trails to reach the existing entry.
3309 * Add the new finger.
3310 * -- If new and existing finger are different, and existing finger is closest
3311 * then do nothing.
3312 * -- Update current_search_finger_index.
3313 * @param finger_identity Peer Identity of new finger
3314 * @param finger_trail Trail to reach the new finger
3315 * @param finger_trail_length Total number of peers in @a new_finger_trail.
3316 * @param is_predecessor Is this entry for predecessor in finger_table?
3317 * @param finger_value 64 bit value of finger identity that we got from network.
3318 * @param finger_trail_id Unique identifier of @finger_trail.
3319 */
3320static void
3321finger_table_add (const struct GNUNET_PeerIdentity *finger_identity,
3322 const struct GNUNET_PeerIdentity *finger_trail,
3323 unsigned int finger_trail_length,
3324 unsigned int is_predecessor,
3325 uint64_t finger_value,
3326 const struct GNUNET_HashCode *finger_trail_id)
3327{
3328 struct FingerInfo *existing_finger;
3329 const struct GNUNET_PeerIdentity *closest_peer;
3330 struct FingerInfo *successor;
3331 unsigned int finger_table_index;
3332
3333 /* Get the finger_table_index corresponding to finger_value we got from network.*/
3334 finger_table_index = get_finger_table_index (finger_value, is_predecessor);
3335
3336 /* Invalid finger_table_index. */
3337 if ((finger_table_index > PREDECESSOR_FINGER_ID))
3338 {
3339 GNUNET_break_op (0);
3340 return;
3341 }
3342
3343 /* Check if new entry is same as successor. */
3344 if ((0 != finger_table_index) &&
3345 (PREDECESSOR_FINGER_ID != finger_table_index))
3346 {
3347 successor = &finger_table[0];
3348 if (GNUNET_NO == successor->is_present)
3349 {
3350 GNUNET_break (0); //ASSERTION FAILS HERE. FIXME
3351 return;
3352 }
3353 if (0 == GNUNET_CRYPTO_cmp_peer_identity (finger_identity,
3354 &successor->finger_identity))
3355 {
3356 if (0 == fingers_round_count)
3357 {
3358 find_finger_trail_task_next_send_time =
3359 GNUNET_TIME_STD_BACKOFF(find_finger_trail_task_next_send_time);
3360 }
3361 else
3362 fingers_round_count--;
3363 current_search_finger_index = 0;
3364 GNUNET_STATISTICS_update (GDS_stats,
3365 gettext_noop
3366 ("# FINGERS_COUNT"), (int64_t) total_fingers_found,
3367 GNUNET_NO);
3368 total_fingers_found = 0;
3369 return;
3370 }
3371
3372 struct FingerInfo prev_finger;
3373 prev_finger = finger_table[finger_table_index - 1];
3374 if (0 == GNUNET_CRYPTO_cmp_peer_identity (finger_identity,
3375 &prev_finger.finger_identity))
3376 {
3377 current_search_finger_index--;
3378 return;
3379 }
3380 }
3381
3382 total_fingers_found++;
3383 existing_finger = &finger_table[finger_table_index];
3384
3385 /* No entry present in finger_table for given finger map index. */
3386 if (GNUNET_NO == existing_finger->is_present)
3387 {
3388 /* Shorten the trail if possible. */
3389 add_new_finger (finger_identity,
3390 finger_trail,
3391 finger_trail_length,
3392 finger_trail_id,
3393 finger_table_index);
3394 update_current_search_finger_index (finger_table_index);
3395 return;
3396 }
3397
3398 /* If existing entry and finger identity are not same. */
3399 if (0 != GNUNET_CRYPTO_cmp_peer_identity (&existing_finger->finger_identity,
3400 finger_identity))
3401 {
3402 closest_peer = select_closest_peer (&existing_finger->finger_identity,
3403 finger_identity,
3404 finger_value,
3405 is_predecessor);
3406
3407 /* If the new finger is the closest peer. */
3408 if (0 == GNUNET_CRYPTO_cmp_peer_identity (finger_identity,
3409 closest_peer))
3410 {
3411 remove_existing_finger (existing_finger,
3412 finger_table_index);
3413 add_new_finger (finger_identity,
3414 finger_trail,
3415 finger_trail_length,
3416 finger_trail_id,
3417 finger_table_index);
3418 }
3419 else
3420 {
3421 /* Existing finger is the closest one. We need to send trail teardown
3422 across the trail setup in routing table of all the peers. */
3423 if (0 != GNUNET_CRYPTO_cmp_peer_identity (finger_identity,
3424 &my_identity))
3425 {
3426 if (finger_trail_length > 0)
3427 GDS_NEIGHBOURS_send_trail_teardown (finger_trail_id,
3428 GDS_ROUTING_SRC_TO_DEST,
3429 &finger_trail[0]);
3430 else
3431 GDS_NEIGHBOURS_send_trail_teardown (finger_trail_id,
3432 GDS_ROUTING_SRC_TO_DEST,
3433 finger_identity);
3434 }
3435 }
3436 }
3437 else
3438 {
3439 /* If both new and existing entry are same as my_identity, then do nothing. */
3440 if (0 == GNUNET_CRYPTO_cmp_peer_identity (&existing_finger->finger_identity,
3441 &my_identity))
3442 {
3443 return;
3444 }
3445
3446 /* If there is space to store more trails. */
3447 if (existing_finger->trails_count < MAXIMUM_TRAILS_PER_FINGER)
3448 add_new_trail (existing_finger,
3449 finger_trail,
3450 finger_trail_length,
3451 finger_trail_id);
3452 else
3453 select_and_replace_trail (existing_finger,
3454 finger_trail,
3455 finger_trail_length,
3456 finger_trail_id);
3457 }
3458 update_current_search_finger_index (finger_table_index);
3459 return;
3460}
3461
3462
3463/**
3464 * Verify validity of P2P put messages.
3465 *
3466 * @param cls closure
3467 * @param put the message
3468 * @return #GNUNET_OK if the message is well-formed
3469 */
3470static int
3471check_dht_p2p_put (void *cls,
3472 const struct PeerPutMessage *put)
3473{
3474 size_t msize;
3475 uint32_t putlen;
3476
3477 msize = ntohs (put->header.size);
3478 putlen = ntohl (put->put_path_length);
3479 if ((msize <
3480 sizeof (struct PeerPutMessage) +
3481 putlen * sizeof (struct GNUNET_PeerIdentity)) ||
3482 (putlen >
3483 GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)))
3484 {
3485 GNUNET_break_op (0);
3486 return GNUNET_SYSERR;
3487 }
3488 return GNUNET_OK;
3489}
3490
3491
3492/**
3493 * Core handler for P2P put messages.
3494 *
3495 * @param cls closure
3496 * @param put the message
3497 */
3498static void
3499handle_dht_p2p_put (void *cls,
3500 const struct PeerPutMessage *put)
3501{
3502 struct GNUNET_PeerIdentity *put_path;
3503 struct GNUNET_PeerIdentity current_best_known_dest;
3504 struct GNUNET_PeerIdentity best_known_dest;
3505 struct GNUNET_HashCode received_intermediate_trail_id;
3506 struct GNUNET_HashCode intermediate_trail_id;
3507 struct GNUNET_PeerIdentity next_hop;
3508 const struct GNUNET_PeerIdentity *next_routing_hop;
3509 enum GNUNET_DHT_RouteOption options;
3510 struct GNUNET_HashCode test_key;
3511 struct Closest_Peer successor;
3512 void *payload;
3513 size_t msize;
3514 uint32_t putlen = ntohl (put->put_path_length);
3515 struct GNUNET_PeerIdentity pp[putlen + 1];
3516 uint32_t hop_count;
3517 size_t payload_size;
3518 uint64_t key_value;
3519
3520 msize = ntohs (put->header.size);
3521 GNUNET_STATISTICS_update (GDS_stats,
3522 gettext_noop ("# Bytes received from other peers"),
3523 (int64_t) msize,
3524 GNUNET_NO);
3525
3526 current_best_known_dest = put->best_known_destination;
3527 put_path = (struct GNUNET_PeerIdentity *) &put[1];
3528 payload = &put_path[putlen];
3529 options = ntohl (put->options);
3530 received_intermediate_trail_id = put->intermediate_trail_id;
3531 hop_count = ntohl(put->hop_count);
3532 payload_size = msize - (sizeof (struct PeerPutMessage) +
3533 putlen * sizeof (struct GNUNET_PeerIdentity));
3534 hop_count++;
3535 switch (GNUNET_BLOCK_get_key (GDS_block_context,
3536 ntohl (put->block_type),
3537 payload,
3538 payload_size,
3539 &test_key))
3540 {
3541 case GNUNET_YES:
3542 if (0 != memcmp (&test_key,
3543 &put->key,
3544 sizeof (struct GNUNET_HashCode)))
3545 {
3546 char *put_s = GNUNET_strdup (GNUNET_h2s_full (&put->key));
3547 GNUNET_break_op (0);
3548 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3549 "PUT with key `%s' for block with key %s\n",
3550 put_s,
3551 GNUNET_h2s_full (&test_key));
3552 GNUNET_free (put_s);
3553 return;
3554 }
3555 break;
3556 case GNUNET_NO:
3557 GNUNET_break_op (0);
3558 return;
3559 case GNUNET_SYSERR:
3560 /* cannot verify, good luck */
3561 break;
3562 }
3563
3564 if (ntohl (put->block_type) == GNUNET_BLOCK_TYPE_REGEX) /* FIXME: do for all tpyes */
3565 {
3566 switch (GNUNET_BLOCK_evaluate (GDS_block_context,
3567 ntohl (put->block_type),
3568 GNUNET_BLOCK_EO_NONE,
3569 NULL, /* query */
3570 NULL, 0, /* bloom filer */
3571 NULL, 0, /* xquery */
3572 payload,
3573 payload_size))
3574 {
3575 case GNUNET_BLOCK_EVALUATION_OK_MORE:
3576 case GNUNET_BLOCK_EVALUATION_OK_LAST:
3577 break;
3578
3579 case GNUNET_BLOCK_EVALUATION_OK_DUPLICATE:
3580 case GNUNET_BLOCK_EVALUATION_RESULT_INVALID:
3581 case GNUNET_BLOCK_EVALUATION_RESULT_IRRELEVANT:
3582 case GNUNET_BLOCK_EVALUATION_REQUEST_VALID:
3583 case GNUNET_BLOCK_EVALUATION_REQUEST_INVALID:
3584 case GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED:
3585 default:
3586 GNUNET_break_op (0);
3587 return;
3588 }
3589 }
3590
3591 /* Check if you are already a part of put path. */
3592 unsigned int i;
3593 for (i = 0; i < putlen; i++)
3594 {
3595 if (0 == GNUNET_CRYPTO_cmp_peer_identity (&my_identity,
3596 &put_path[i]))
3597 {
3598 putlen = i;
3599 break;
3600 }
3601 }
3602
3603 /* Add yourself to the list. */
3604 //if (0 != (options & GNUNET_DHT_RO_RECORD_ROUTE))
3605 if (1)
3606 {
3607 GNUNET_memcpy (pp,
3608 put_path,
3609 putlen * sizeof (struct GNUNET_PeerIdentity));
3610 pp[putlen] = my_identity;
3611 putlen++;
3612 }
3613 else
3614 {
3615 putlen = 0;
3616 }
3617 GNUNET_memcpy (&key_value,
3618 &put->key,
3619 sizeof (uint64_t));
3620 key_value = GNUNET_ntohll (key_value);
3621 successor = find_local_best_known_next_hop (key_value,
3622 GDS_FINGER_TYPE_NON_PREDECESSOR);
3623 next_hop = successor.next_hop;
3624 intermediate_trail_id = successor.trail_id;
3625 best_known_dest = successor.best_known_destination;
3626
3627 if (0 != (GNUNET_CRYPTO_cmp_peer_identity (&current_best_known_dest,
3628 &my_identity)))
3629 {
3630 next_routing_hop = GDS_ROUTING_get_next_hop (&received_intermediate_trail_id,
3631 GDS_ROUTING_SRC_TO_DEST);
3632 if (NULL != next_routing_hop)
3633 {
3634 next_hop = *next_routing_hop;
3635 intermediate_trail_id = received_intermediate_trail_id;
3636 best_known_dest = current_best_known_dest;
3637 }
3638 }
3639
3640 GDS_CLIENTS_process_put (options,
3641 ntohl (put->block_type),
3642 hop_count,
3643 ntohl (put->desired_replication_level),
3644 putlen,
3645 pp,
3646 GNUNET_TIME_absolute_ntoh (put->expiration_time),
3647 &put->key,
3648 payload,
3649 payload_size);
3650
3651 /* I am the final destination */
3652 if (0 == GNUNET_CRYPTO_cmp_peer_identity (&my_identity,
3653 &best_known_dest))
3654 {
3655 DEBUG ("\n PUT_REQUEST_SUCCESSFUL for key = %s",
3656 GNUNET_h2s(&put->key));
3657 GDS_DATACACHE_handle_put (GNUNET_TIME_absolute_ntoh (put->expiration_time),
3658 &put->key,
3659 putlen,
3660 pp,
3661 ntohl (put->block_type),
3662 payload_size,
3663 payload);
3664 }
3665 GDS_NEIGHBOURS_send_put (&put->key,
3666 ntohl (put->block_type),
3667 ntohl (put->options),
3668 ntohl (put->desired_replication_level),
3669 best_known_dest,
3670 intermediate_trail_id,
3671 &next_hop,
3672 hop_count,
3673 putlen,
3674 pp,
3675 GNUNET_TIME_absolute_ntoh (put->expiration_time),
3676 payload,
3677 payload_size);
3678}
3679
3680
3681/**
3682 * Check integrity of @a get message.
3683 *
3684 * @param cls closure
3685 * @param get the message
3686 * @return #GNUNET_OK if @a get is well-formed
3687 */
3688static int
3689check_dht_p2p_get (void *cls,
3690 const struct PeerGetMessage *get)
3691{
3692 uint32_t get_length;
3693 size_t msize;
3694
3695 msize = ntohs (get->header.size);
3696 get_length = ntohl (get->get_path_length);
3697 if ((msize <
3698 sizeof (struct PeerGetMessage) +
3699 get_length * sizeof (struct GNUNET_PeerIdentity)) ||
3700 (get_length >
3701 GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)))
3702 {
3703 GNUNET_break_op (0);
3704 return GNUNET_SYSERR;
3705 }
3706 return GNUNET_OK;
3707}
3708
3709
3710/**
3711 * FIXME: Check for loop in the request. If you already are part of get path,
3712 * then you need to reset the get path length.
3713 * Core handler for p2p get requests.
3714 *
3715 * @param cls closure
3716 * @param get the message
3717 */
3718static void
3719handle_dht_p2p_get (void *cls,
3720 const struct PeerGetMessage *get)
3721{
3722 const struct GNUNET_PeerIdentity *get_path;
3723 struct GNUNET_PeerIdentity best_known_dest;
3724 struct GNUNET_PeerIdentity current_best_known_dest;
3725 struct GNUNET_HashCode intermediate_trail_id;
3726 struct GNUNET_HashCode received_intermediate_trail_id;
3727 struct Closest_Peer successor;
3728 struct GNUNET_PeerIdentity next_hop;
3729 const struct GNUNET_PeerIdentity *next_routing_hop;
3730 uint32_t get_length;
3731 uint64_t key_value;
3732 uint32_t hop_count;
3733 size_t msize;
3734
3735 msize = ntohs (get->header.size);
3736 get_length = ntohl (get->get_path_length);
3737 current_best_known_dest = get->best_known_destination;
3738 received_intermediate_trail_id = get->intermediate_trail_id;
3739 get_path = (const struct GNUNET_PeerIdentity *) &get[1];
3740 hop_count = get->hop_count;
3741 hop_count++;
3742 GNUNET_STATISTICS_update (GDS_stats,
3743 gettext_noop ("# Bytes received from other peers"),
3744 msize,
3745 GNUNET_NO);
3746 GNUNET_memcpy (&key_value,
3747 &get->key,
3748 sizeof (uint64_t));
3749 key_value = GNUNET_ntohll (key_value);
3750
3751 /* Check if you are already a part of get path. */
3752 for (unsigned int i = 0; i < get_length; i++)
3753 {
3754 if (0 == GNUNET_CRYPTO_cmp_peer_identity (&my_identity,
3755 &get_path[i]))
3756 {
3757 get_length = i;
3758 break;
3759 }
3760 }
3761
3762 /* Add yourself in the get path. */
3763 struct GNUNET_PeerIdentity gp[get_length + 1];
3764 GNUNET_memcpy (gp,
3765 get_path,
3766 get_length * sizeof (struct GNUNET_PeerIdentity));
3767 gp[get_length] = my_identity;
3768 get_length = get_length + 1;
3769 GDS_CLIENTS_process_get (get->options,
3770 get->block_type,
3771 hop_count,
3772 get->desired_replication_level,
3773 get->get_path_length,
3774 gp,
3775 &get->key);
3776
3777
3778 successor = find_local_best_known_next_hop (key_value,
3779 GDS_FINGER_TYPE_NON_PREDECESSOR);
3780 next_hop = successor.next_hop;
3781 best_known_dest = successor.best_known_destination;
3782 intermediate_trail_id = successor.trail_id;
3783 /* I am not the final destination. I am part of trail to reach final dest. */
3784 if (0 != (GNUNET_CRYPTO_cmp_peer_identity (&current_best_known_dest, &my_identity)))
3785 {
3786 next_routing_hop = GDS_ROUTING_get_next_hop (&received_intermediate_trail_id,
3787 GDS_ROUTING_SRC_TO_DEST);
3788 if (NULL != next_routing_hop)
3789 {
3790 next_hop = *next_routing_hop;
3791 best_known_dest = current_best_known_dest;
3792 intermediate_trail_id = received_intermediate_trail_id;
3793 }
3794 }
3795
3796 /* I am the final destination. */
3797 if (0 == GNUNET_CRYPTO_cmp_peer_identity (&my_identity,
3798 &best_known_dest))
3799 {
3800 if (1 == get_length)
3801 {
3802 DEBUG ("\n GET_REQUEST DONE for key = %s",
3803 GNUNET_h2s(&get->key));
3804 GDS_DATACACHE_handle_get (&get->key,
3805 get->block_type, /* FIXME: endianess? */
3806 NULL,
3807 0,
3808 NULL,
3809 0,
3810 &get_cb,
3811 NULL);
3812 }
3813 else
3814 {
3815 GDS_DATACACHE_handle_get (&get->key,
3816 get->block_type, /* FIXME: endianess? */
3817 NULL,
3818 0,
3819 NULL,
3820 0,
3821 &get_cb,
3822 &gp[get_length - 2]);
3823 }
3824 }
3825 else
3826 {
3827 GDS_NEIGHBOURS_send_get (&get->key,
3828 get->block_type, /* FIXME: endianess? */
3829 get->options,
3830 get->desired_replication_level,
3831 &best_known_dest,
3832 &intermediate_trail_id,
3833 &next_hop,
3834 hop_count,
3835 get_length,
3836 gp);
3837 }
3838}
3839
3840
3841/**
3842 * Check validity of @a get_result message.
3843 *
3844 * @param cls closure
3845 * @param get_result the message
3846 * @return #GNUNET_OK if @a get_result is well-formed
3847 */
3848static int
3849check_dht_p2p_get_result (void *cls,
3850 const struct PeerGetResultMessage *get_result)
3851{
3852 size_t msize;
3853 unsigned int getlen;
3854 unsigned int putlen;
3855
3856 msize = ntohs (get_result->header.size);
3857 getlen = ntohl (get_result->get_path_length);
3858 putlen = ntohl (get_result->put_path_length);
3859 if ((msize <
3860 sizeof (struct PeerGetResultMessage) +
3861 getlen * sizeof (struct GNUNET_PeerIdentity) +
3862 putlen * sizeof (struct GNUNET_PeerIdentity)) ||
3863 (getlen >
3864 GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity) ||
3865 (putlen >
3866 GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity))))
3867 {
3868 GNUNET_break_op (0);
3869 return GNUNET_SYSERR;
3870 }
3871 return GNUNET_OK;
3872}
3873
3874
3875/**
3876 * Core handler for get result
3877 *
3878 * @param cls closure
3879 * @param get_result the message
3880 */
3881static void
3882handle_dht_p2p_get_result (void *cls,
3883 const struct PeerGetResultMessage *get_result)
3884{
3885 const struct GNUNET_PeerIdentity *get_path;
3886 const struct GNUNET_PeerIdentity *put_path;
3887 const void *payload;
3888 size_t payload_size;
3889 size_t msize;
3890 unsigned int getlen;
3891 unsigned int putlen;
3892 int current_path_index;
3893
3894 msize = ntohs (get_result->header.size);
3895 getlen = ntohl (get_result->get_path_length);
3896 putlen = ntohl (get_result->put_path_length);
3897 DEBUG ("GET_RESULT FOR DATA_SIZE = %u\n",
3898 (unsigned int) msize);
3899 GNUNET_STATISTICS_update (GDS_stats,
3900 gettext_noop ("# Bytes received from other peers"),
3901 msize,
3902 GNUNET_NO);
3903 put_path = (const struct GNUNET_PeerIdentity *) &get_result[1];
3904 get_path = &put_path[putlen];
3905 payload = (const void *) &get_path[getlen];
3906 payload_size = msize - (sizeof (struct PeerGetResultMessage) +
3907 (getlen + putlen) * sizeof (struct GNUNET_PeerIdentity));
3908
3909 if (0 == (GNUNET_CRYPTO_cmp_peer_identity (&my_identity,
3910 &get_path[0])))
3911 {
3912 GDS_CLIENTS_handle_reply (GNUNET_TIME_absolute_ntoh (get_result->expiration_time),
3913 &get_result->key,
3914 getlen,
3915 get_path,
3916 putlen,
3917 put_path,
3918 get_result->type,
3919 payload_size,
3920 payload);
3921 return;
3922 }
3923 current_path_index = search_my_index (get_path,
3924 getlen);
3925 if (-1 == current_path_index)
3926 {
3927 DEBUG ("No entry found in get path.\n");
3928 GNUNET_break (0);
3929 return;
3930 }
3931 if ((getlen + 1) == current_path_index)
3932 {
3933 DEBUG("Present twice in get path. Not allowed. \n");
3934 GNUNET_break (0);
3935 return;
3936 }
3937 GDS_NEIGHBOURS_send_get_result (&get_result->key,
3938 get_result->type, /* FIXME: endianess? */
3939 &get_path[current_path_index - 1],
3940 &get_result->querying_peer,
3941 putlen,
3942 put_path,
3943 getlen,
3944 get_path,
3945 GNUNET_TIME_absolute_ntoh (get_result->expiration_time),
3946 payload,
3947 payload_size);
3948}
3949
3950
3951/**
3952 * Find the next hop to pass trail setup message. First find the local best known
3953 * hop from your own identity, friends and finger. If you were part of trail,
3954 * then get the next hop from routing table. Compare next_hop from routing table
3955 * and local best known hop, and return the closest one to final_dest_finger_val
3956 * @param final_dest_finger_val 64 bit value of finger identity
3957 * @param intermediate_trail_id If you are part of trail to reach to some other
3958 * finger, then it is the trail id to reach to
3959 * that finger, else set to 0.
3960 * @param is_predecessor Are we looking for closest successor or predecessor.
3961 * @param source Source of trail setup message.
3962 * @param current_dest In case you are part of trail, then finger to which
3963 * we should forward the message. Else my own identity
3964 * @return Closest Peer for @a final_dest_finger_val
3965 */
3966static struct Closest_Peer
3967get_local_best_known_next_hop (uint64_t final_dest_finger_val,
3968 const struct GNUNET_HashCode *intermediate_trail_id,
3969 unsigned int is_predecessor,
3970 const struct GNUNET_PeerIdentity *source,
3971 const struct GNUNET_PeerIdentity *current_dest)
3972{
3973 struct Closest_Peer peer;
3974
3975 peer = find_local_best_known_next_hop (final_dest_finger_val,
3976 is_predecessor);
3977
3978 /* Am I just a part of a trail towards a finger (current_destination)? */
3979 if (0 != GNUNET_CRYPTO_cmp_peer_identity (&my_identity,
3980 current_dest) &&
3981 0 != GNUNET_CRYPTO_cmp_peer_identity (&peer.best_known_destination,
3982 current_dest))
3983 {
3984 const struct GNUNET_PeerIdentity *closest_peer;
3985
3986 /* Select best successor among one found locally and current_destination
3987 * that we got from network.*/
3988 closest_peer = select_closest_peer (&peer.best_known_destination,
3989 current_dest,
3990 final_dest_finger_val,
3991 is_predecessor);
3992
3993 /* Is current dest (end point of the trail of which I am a part) closest_peer? */
3994 if (0 == GNUNET_CRYPTO_cmp_peer_identity (current_dest,
3995 closest_peer))
3996 {
3997 const struct GNUNET_PeerIdentity *next_hop;
3998
3999 next_hop = GDS_ROUTING_get_next_hop (intermediate_trail_id,
4000 GDS_ROUTING_SRC_TO_DEST);
4001 /* next_hop NULL is a valid case. This intermediate trail id is set by
4002 some other finger, and while this trail setup is in progress, that other
4003 peer might have found a better trail ,and send trail teardown message
4004 across the network. In case we got the trail teardown message first,
4005 then next_hop will be NULL. A possible solution could be to keep track
4006 * of all removed trail id, and be sure that there is no other reason . */
4007 if(NULL != next_hop)
4008 {
4009 peer.next_hop = *next_hop;
4010 peer.best_known_destination = *current_dest;
4011 peer.trail_id = *intermediate_trail_id;
4012 }
4013 }
4014 }
4015 return peer;
4016}
4017
4018
4019/**
4020 * Check format of a PeerTrailSetupMessage.
4021 *
4022 * @param cls closure
4023 * @param trail_setup the message
4024 * @return #GNUNET_OK if @a trail_setup is well-formed
4025 */
4026static int
4027check_dht_p2p_trail_setup (void *cls,
4028 const struct PeerTrailSetupMessage *trail_setup)
4029{
4030 size_t msize;
4031
4032 msize = ntohs (trail_setup->header.size);
4033 if ((msize - sizeof (struct PeerTrailSetupMessage)) %
4034 sizeof (struct GNUNET_PeerIdentity) != 0)
4035 {
4036 GNUNET_break_op (0);
4037 return GNUNET_SYSERR;
4038 }
4039 return GNUNET_OK;
4040}
4041
4042
4043/**
4044 * Core handle for PeerTrailSetupMessage.
4045 *
4046 * @param cls closure
4047 * @param trail_setup the message
4048 */
4049static void
4050handle_dht_p2p_trail_setup (void *cls,
4051 const struct PeerTrailSetupMessage *trail_setup)
4052{
4053 struct FriendInfo *friend = cls;
4054 const struct GNUNET_PeerIdentity *trail_peer_list;
4055 struct GNUNET_PeerIdentity current_dest;
4056 struct FriendInfo *target_friend;
4057 struct GNUNET_PeerIdentity source;
4058 struct GNUNET_HashCode intermediate_trail_id;
4059 struct GNUNET_HashCode trail_id;
4060 unsigned int is_predecessor;
4061 uint32_t trail_length;
4062 uint64_t final_dest_finger_val;
4063 int i;
4064 size_t msize;
4065
4066 msize = ntohs (trail_setup->header.size);
4067 trail_length = (msize - sizeof (struct PeerTrailSetupMessage))/
4068 sizeof (struct GNUNET_PeerIdentity);
4069 GNUNET_STATISTICS_update (GDS_stats,
4070 gettext_noop ("# Bytes received from other peers"),
4071 msize,
4072 GNUNET_NO);
4073 trail_peer_list = (const struct GNUNET_PeerIdentity *) &trail_setup[1];
4074 current_dest = trail_setup->best_known_destination;
4075 trail_id = trail_setup->trail_id;
4076 final_dest_finger_val
4077 = GNUNET_ntohll (trail_setup->final_destination_finger_value);
4078 source = trail_setup->source_peer;
4079 is_predecessor = ntohl (trail_setup->is_predecessor);
4080 intermediate_trail_id = trail_setup->intermediate_trail_id;
4081
4082 /* Did the friend insert its ID in the trail list? */
4083 if ( (trail_length > 0) &&
4084 (0 != memcmp (&trail_peer_list[trail_length-1],
4085 friend->id,
4086 sizeof (struct GNUNET_PeerIdentity))) )
4087 {
4088 GNUNET_break_op (0);
4089 return;
4090 }
4091
4092 /* If I was the source and got the message back, then set trail length to 0.*/
4093 if (0 == GNUNET_CRYPTO_cmp_peer_identity (&my_identity,
4094 &source))
4095 {
4096 trail_length = 0;
4097 }
4098
4099 /* Check if you are present in the trail seen so far? */
4100 for (i = 0; i < trail_length; i++)
4101 {
4102 if (0 == GNUNET_CRYPTO_cmp_peer_identity (&trail_peer_list[i],
4103 &my_identity))
4104 {
4105 /* We will add ourself later in code, if NOT destination. */
4106 trail_length = i;
4107 break;
4108 }
4109 }
4110
4111 /* Is my routing table full? */
4112 if (GNUNET_YES == GDS_ROUTING_threshold_reached ())
4113 {
4114 target_friend
4115 = (trail_length > 0)
4116 ? GNUNET_CONTAINER_multipeermap_get (friend_peermap,
4117 &trail_peer_list[trail_length - 1])
4118 : GNUNET_CONTAINER_multipeermap_get (friend_peermap,
4119 &source);
4120 if (NULL == target_friend)
4121 {
4122 DEBUG ("\n friend not found");
4123 GNUNET_break(0);
4124 return;
4125 }
4126 GDS_NEIGHBOURS_send_trail_rejection (&source,
4127 final_dest_finger_val,
4128 &my_identity,
4129 is_predecessor,
4130 trail_peer_list,
4131 trail_length,
4132 &trail_id,
4133 target_friend,
4134 CONGESTION_TIMEOUT);
4135 return;
4136 }
4137
4138 /* Get the next hop to forward the trail setup request. */
4139 struct Closest_Peer next_peer
4140 = get_local_best_known_next_hop (final_dest_finger_val,
4141 &intermediate_trail_id,
4142 is_predecessor,
4143 &source,
4144 &current_dest);
4145
4146 /* Am I the final destination? */
4147 if (0 == GNUNET_CRYPTO_cmp_peer_identity (&next_peer.best_known_destination,
4148 &my_identity))
4149 {
4150 if (0 == GNUNET_CRYPTO_cmp_peer_identity (&source,
4151 &my_identity))
4152 {
4153 finger_table_add (&my_identity,
4154 NULL,
4155 0,
4156 is_predecessor,
4157 final_dest_finger_val,
4158 &trail_id);
4159 return;
4160 }
4161
4162 target_friend
4163 = (trail_length > 0)
4164 ? GNUNET_CONTAINER_multipeermap_get (friend_peermap,
4165 &trail_peer_list[trail_length-1])
4166 : GNUNET_CONTAINER_multipeermap_get (friend_peermap,
4167 &source);
4168 if (NULL == target_friend)
4169 {
4170 GNUNET_break_op (0);
4171 return;
4172 }
4173 GDS_ROUTING_add (&trail_id,
4174 target_friend->id,
4175 &my_identity);
4176 GDS_NEIGHBOURS_send_trail_setup_result (&source,
4177 &my_identity,
4178 target_friend,
4179 trail_length,
4180 trail_peer_list,
4181 is_predecessor,
4182 final_dest_finger_val,
4183 &trail_id);
4184 return;
4185 }
4186 /* I'm not the final destination. */
4187 target_friend = GNUNET_CONTAINER_multipeermap_get (friend_peermap,
4188 &next_peer.next_hop);
4189 if (NULL == target_friend)
4190 {
4191 DEBUG ("\n target friend not found for peer = %s",
4192 GNUNET_i2s(&next_peer.next_hop));
4193 GNUNET_break (0);
4194 return;
4195 }
4196 if (0 != GNUNET_CRYPTO_cmp_peer_identity (&my_identity,
4197 &source))
4198 {
4199 /* Add yourself to list of peers. */
4200 struct GNUNET_PeerIdentity peer_list[trail_length + 1];
4201
4202 GNUNET_memcpy (peer_list,
4203 trail_peer_list,
4204 trail_length * sizeof (struct GNUNET_PeerIdentity));
4205 peer_list[trail_length] = my_identity;
4206 GDS_NEIGHBOURS_send_trail_setup (&source,
4207 final_dest_finger_val,
4208 &next_peer.best_known_destination,
4209 target_friend,
4210 trail_length + 1,
4211 peer_list,
4212 is_predecessor,
4213 &trail_id,
4214 &next_peer.trail_id);
4215 return;
4216 }
4217 GDS_NEIGHBOURS_send_trail_setup (&source,
4218 final_dest_finger_val,
4219 &next_peer.best_known_destination,
4220 target_friend,
4221 0,
4222 NULL,
4223 is_predecessor,
4224 &trail_id,
4225 &next_peer.trail_id);
4226}
4227
4228
4229/**
4230 * Validate format of trail setup result messages.
4231 *
4232 * @param closure
4233 * @param trail_result the message
4234 * @return #GNUNET_OK if @a trail_result is well-formed
4235 */
4236static int
4237check_dht_p2p_trail_setup_result (void *cls,
4238 const struct PeerTrailSetupResultMessage *trail_result)
4239{
4240 size_t msize;
4241
4242 msize = ntohs (trail_result->header.size);
4243 if ((msize - sizeof (struct PeerTrailSetupResultMessage)) %
4244 sizeof (struct GNUNET_PeerIdentity) != 0)
4245 {
4246 GNUNET_break_op (0);
4247 return GNUNET_SYSERR;
4248 }
4249 return GNUNET_OK;
4250}
4251
4252
4253/**
4254 * Core handle for p2p trail setup result messages.
4255 *
4256 * @param closure
4257 * @param trail_result the message
4258 */
4259static void
4260handle_dht_p2p_trail_setup_result (void *cls,
4261 const struct PeerTrailSetupResultMessage *trail_result)
4262{
4263 struct FriendInfo *friend = cls;
4264 const struct GNUNET_PeerIdentity *trail_peer_list;
4265 struct GNUNET_PeerIdentity next_hop;
4266 struct FriendInfo *target_friend;
4267 struct GNUNET_PeerIdentity querying_peer;
4268 struct GNUNET_PeerIdentity finger_identity;
4269 uint32_t trail_length;
4270 uint64_t ultimate_destination_finger_value;
4271 uint32_t is_predecessor;
4272 struct GNUNET_HashCode trail_id;
4273 int my_index;
4274 size_t msize;
4275
4276 msize = ntohs (trail_result->header.size);
4277 trail_length = (msize - sizeof (struct PeerTrailSetupResultMessage))/
4278 sizeof (struct GNUNET_PeerIdentity);
4279
4280 GNUNET_STATISTICS_update (GDS_stats,
4281 gettext_noop ("# Bytes received from other peers"),
4282 msize,
4283 GNUNET_NO);
4284
4285 is_predecessor = ntohl (trail_result->is_predecessor);
4286 querying_peer = trail_result->querying_peer;
4287 finger_identity = trail_result->finger_identity;
4288 trail_id = trail_result->trail_id;
4289 trail_peer_list = (const struct GNUNET_PeerIdentity *) &trail_result[1];
4290 ultimate_destination_finger_value
4291 = GNUNET_ntohll (trail_result->ultimate_destination_finger_value);
4292
4293 /* Am I the one who initiated the query? */
4294 if (0 == (GNUNET_CRYPTO_cmp_peer_identity (&querying_peer,
4295 &my_identity)))
4296 {
4297 /* Check that you got the message from the correct peer. */
4298 if (trail_length > 0)
4299 {
4300 GNUNET_assert (0 == GNUNET_CRYPTO_cmp_peer_identity (&trail_peer_list[0],
4301 friend->id));
4302 }
4303 else
4304 {
4305 GNUNET_assert (0 == GNUNET_CRYPTO_cmp_peer_identity (&finger_identity,
4306 friend->id));
4307 }
4308 GDS_ROUTING_add (&trail_id,
4309 &my_identity,
4310 friend->id);
4311 finger_table_add (&finger_identity,
4312 trail_peer_list,
4313 trail_length,
4314 is_predecessor,
4315 ultimate_destination_finger_value,
4316 &trail_id);
4317 return;
4318 }
4319
4320 /* Get my location in the trail. */
4321 my_index = search_my_index (trail_peer_list,
4322 trail_length);
4323 if (-1 == my_index)
4324 {
4325 DEBUG ("Not found in trail\n");
4326 GNUNET_break_op(0);
4327 return;
4328 }
4329 //TODO; return -2.
4330 if ((trail_length + 1) == my_index)
4331 {
4332 DEBUG ("Found twice in trail.\n");
4333 GNUNET_break_op(0);
4334 return;
4335 }
4336
4337 //TODO; Refactor code here and above to check if sender peer is correct
4338 if (my_index == 0)
4339 {
4340 if (trail_length > 1)
4341 GNUNET_assert (0 == GNUNET_CRYPTO_cmp_peer_identity (&trail_peer_list[1],
4342 friend->id));
4343 else
4344 GNUNET_assert (0 == GNUNET_CRYPTO_cmp_peer_identity (&finger_identity,
4345 friend->id));
4346 next_hop = trail_result->querying_peer;
4347 }
4348 else
4349 {
4350 if (my_index == trail_length - 1)
4351 {
4352 GNUNET_assert (0 ==
4353 GNUNET_CRYPTO_cmp_peer_identity (&finger_identity,
4354 friend->id));
4355 }
4356 else
4357 GNUNET_assert (0 ==
4358 GNUNET_CRYPTO_cmp_peer_identity (&trail_peer_list[my_index + 1],
4359 friend->id));
4360 next_hop = trail_peer_list[my_index - 1];
4361 }
4362
4363 target_friend = GNUNET_CONTAINER_multipeermap_get (friend_peermap,
4364 &next_hop);
4365 if (NULL == target_friend)
4366 {
4367 GNUNET_break_op (0);
4368 return;
4369 }
4370 GDS_ROUTING_add (&trail_id,
4371 &next_hop,
4372 friend->id);
4373 GDS_NEIGHBOURS_send_trail_setup_result (&querying_peer,
4374 &finger_identity,
4375 target_friend,
4376 trail_length,
4377 trail_peer_list,
4378 is_predecessor,
4379 ultimate_destination_finger_value,
4380 &trail_id);
4381}
4382
4383
4384/**
4385 * Invert the trail.
4386 *
4387 * @param trail Trail to be inverted
4388 * @param trail_length Total number of peers in the trail.
4389 * @return Updated trail
4390 */
4391static struct GNUNET_PeerIdentity *
4392invert_trail (const struct GNUNET_PeerIdentity *trail,
4393 unsigned int trail_length)
4394{
4395 int i;
4396 int j;
4397 struct GNUNET_PeerIdentity *inverted_trail;
4398
4399 inverted_trail = GNUNET_new_array (trail_length,
4400 struct GNUNET_PeerIdentity);
4401 i = 0;
4402 j = trail_length - 1;
4403 while (i < trail_length)
4404 {
4405 inverted_trail[i] = trail[j];
4406 i++;
4407 j--;
4408 }
4409
4410 GNUNET_assert (NULL !=
4411 GNUNET_CONTAINER_multipeermap_get (friend_peermap,
4412 &inverted_trail[0]));
4413 return inverted_trail;
4414}
4415
4416
4417/**
4418 * Return the shortest trail among all the trails to reach to finger from me.
4419 *
4420 * @param finger Finger
4421 * @param shortest_trail_length[out] Trail length of shortest trail from me
4422 * to @a finger
4423 * @return Shortest trail.
4424 */
4425static struct GNUNET_PeerIdentity *
4426get_shortest_trail (struct FingerInfo *finger,
4427 unsigned int *trail_length)
4428{
4429 struct Trail *trail;
4430 unsigned int flag = 0;
4431 unsigned int shortest_trail_index = 0;
4432 int shortest_trail_length = -1;
4433 struct Trail_Element *trail_element;
4434 struct GNUNET_PeerIdentity *trail_list;
4435 unsigned int i;
4436
4437 /* Get the shortest trail to reach to current successor. */
4438 for (i = 0; i < finger->trails_count; i++)
4439 {
4440 trail = &finger->trail_list[i];
4441
4442 if (0 == flag)
4443 {
4444 shortest_trail_index = i;
4445 shortest_trail_length = trail->trail_length;
4446 flag = 1;
4447 continue;
4448 }
4449
4450 if (shortest_trail_length > trail->trail_length)
4451 {
4452 shortest_trail_index = i;
4453 shortest_trail_length = trail->trail_length;
4454 }
4455 continue;
4456 }
4457
4458 /* Copy the shortest trail and return. */
4459 trail = &finger->trail_list[shortest_trail_index];
4460 trail_element = trail->trail_head;
4461
4462 trail_list = GNUNET_new_array (shortest_trail_length,
4463 struct GNUNET_PeerIdentity);
4464
4465 for (i = 0; i < shortest_trail_length; i++,trail_element = trail_element->next)
4466 {
4467 trail_list[i] = trail_element->peer;
4468 }
4469
4470 GNUNET_assert(shortest_trail_length != -1);
4471
4472 *trail_length = shortest_trail_length;
4473 return trail_list;
4474}
4475
4476
4477/**
4478 * Check if @a trail_1 and @a trail_2 have any common element. If yes then join
4479 * them at common element. @a trail_1 always preceeds @a trail_2 in joined trail.
4480 *
4481 * @param trail_1 Trail from source to me, NOT including endpoints.
4482 * @param trail_1_len Total number of peers @a trail_1
4483 * @param trail_2 Trail from me to current predecessor, NOT including endpoints.
4484 * @param trail_2_len Total number of peers @a trail_2
4485 * @param joined_trail_len Total number of peers in combined trail of @a trail_1
4486 * @a trail_2.
4487 * @return Joined trail.
4488 */
4489static struct GNUNET_PeerIdentity *
4490check_for_duplicate_entries (const struct GNUNET_PeerIdentity *trail_1,
4491 unsigned int trail_1_len,
4492 const struct GNUNET_PeerIdentity *trail_2,
4493 unsigned int trail_2_len,
4494 unsigned int *joined_trail_len)
4495{
4496 struct GNUNET_PeerIdentity *joined_trail;
4497 unsigned int i;
4498 unsigned int j;
4499 unsigned int k;
4500
4501 for (i = 0; i < trail_1_len; i++)
4502 {
4503 for (j = 0; j < trail_2_len; j++)
4504 {
4505 if (0 != GNUNET_CRYPTO_cmp_peer_identity (&trail_1[i],
4506 &trail_2[j]))
4507 continue;
4508
4509 *joined_trail_len = i + (trail_2_len - j);
4510 joined_trail = GNUNET_new_array (*joined_trail_len,
4511 struct GNUNET_PeerIdentity);
4512
4513
4514 /* Copy all the elements from 0 to i into joined_trail. */
4515 for(k = 0; k < ( i+1); k++)
4516 {
4517 joined_trail[k] = trail_1[k];
4518 }
4519
4520 /* Increment j as entry stored is same as entry stored at i*/
4521 j = j+1;
4522
4523 /* Copy all the elements from j to trail_2_len-1 to joined trail.*/
4524 while(k <= (*joined_trail_len - 1))
4525 {
4526 joined_trail[k] = trail_2[j];
4527 j++;
4528 k++;
4529 }
4530
4531 return joined_trail;
4532 }
4533 }
4534
4535 /* Here you should join the trails. */
4536 *joined_trail_len = trail_1_len + trail_2_len + 1;
4537 joined_trail = GNUNET_new_array (*joined_trail_len,
4538 struct GNUNET_PeerIdentity);
4539
4540
4541 for(i = 0; i < trail_1_len;i++)
4542 {
4543 joined_trail[i] = trail_1[i];
4544 }
4545
4546 joined_trail[i] = my_identity;
4547 i++;
4548
4549 for (j = 0; i < *joined_trail_len; i++,j++)
4550 {
4551 joined_trail[i] = trail_2[j];
4552 }
4553
4554 return joined_trail;
4555}
4556
4557
4558/**
4559 * Return the trail from source to my current predecessor. Check if source
4560 * is already part of the this trail, if yes then return the shorten trail.
4561 *
4562 * @param current_trail Trail from source to me, NOT including the endpoints.
4563 * @param current_trail_length Number of peers in @a current_trail.
4564 * @param trail_src_to_curr_pred_length[out] Number of peers in trail from
4565 * source to my predecessor, NOT including
4566 * the endpoints.
4567 * @return Trail from source to my predecessor.
4568 */
4569static struct GNUNET_PeerIdentity *
4570get_trail_src_to_curr_pred (struct GNUNET_PeerIdentity source_peer,
4571 const struct GNUNET_PeerIdentity *trail_src_to_me,
4572 unsigned int trail_src_to_me_len,
4573 unsigned int *trail_src_to_curr_pred_length)
4574{
4575 struct GNUNET_PeerIdentity *trail_me_to_curr_pred;
4576 struct GNUNET_PeerIdentity *trail_src_to_curr_pred;
4577 unsigned int trail_me_to_curr_pred_length;
4578 struct FingerInfo *current_predecessor;
4579 int i;
4580 unsigned int j;
4581 unsigned int len;
4582
4583 current_predecessor = &finger_table[PREDECESSOR_FINGER_ID];
4584
4585 /* Check if trail_src_to_me contains current_predecessor. */
4586 for (i = 0; i < trail_src_to_me_len; i++)
4587 {
4588 if (0 != GNUNET_CRYPTO_cmp_peer_identity(&trail_src_to_me[i],
4589 &current_predecessor->finger_identity))
4590 continue;
4591
4592
4593 *trail_src_to_curr_pred_length = i;
4594
4595 if(0 == i)
4596 return NULL;
4597
4598 trail_src_to_curr_pred = GNUNET_new_array (*trail_src_to_curr_pred_length,
4599 struct GNUNET_PeerIdentity);
4600 for (j = 0; j < i; j++)
4601 trail_src_to_curr_pred[j] = trail_src_to_me[j];
4602 return trail_src_to_curr_pred;
4603 }
4604
4605
4606 trail_me_to_curr_pred = get_shortest_trail (current_predecessor,
4607 &trail_me_to_curr_pred_length);
4608
4609 /* Check if trail contains the source_peer. */
4610 for (i = trail_me_to_curr_pred_length - 1; i >= 0; i--)
4611 {
4612 if (0 != GNUNET_CRYPTO_cmp_peer_identity (&source_peer,
4613 &trail_me_to_curr_pred[i]))
4614 continue;
4615
4616 /* Source is NOT part of trail. */
4617 i++;
4618
4619 /* Source is the last element in the trail to reach to my pred.
4620 Source is direct friend of the pred. */
4621 if (trail_me_to_curr_pred_length == i)
4622 {
4623 *trail_src_to_curr_pred_length = 0;
4624 GNUNET_free_non_null (trail_me_to_curr_pred);
4625 return NULL;
4626 }
4627
4628 *trail_src_to_curr_pred_length = trail_me_to_curr_pred_length - i;
4629 trail_src_to_curr_pred = GNUNET_new_array (*trail_src_to_curr_pred_length,
4630 struct GNUNET_PeerIdentity);
4631
4632
4633 for (j = 0; j < *trail_src_to_curr_pred_length; i++,j++)
4634 trail_src_to_curr_pred[j] = trail_me_to_curr_pred[i];
4635 GNUNET_free_non_null (trail_me_to_curr_pred);
4636 return trail_src_to_curr_pred;
4637 }
4638
4639 trail_src_to_curr_pred = check_for_duplicate_entries (trail_src_to_me,
4640 trail_src_to_me_len,
4641 trail_me_to_curr_pred,
4642 trail_me_to_curr_pred_length,
4643 &len);
4644 *trail_src_to_curr_pred_length = len;
4645 GNUNET_free_non_null(trail_me_to_curr_pred);
4646 return trail_src_to_curr_pred;
4647}
4648
4649
4650/**
4651 * Add finger as your predecessor. To add, first generate a new trail id, invert
4652 * the trail to get the trail from me to finger, add an entry in your routing
4653 * table, send add trail message to peers which are part of trail from me to
4654 * finger and add finger in finger table.
4655 *
4656 * @param finger
4657 * @param trail
4658 * @param trail_length
4659 */
4660static void
4661update_predecessor (const struct GNUNET_PeerIdentity *finger,
4662 const struct GNUNET_PeerIdentity *trail,
4663 unsigned int trail_length)
4664{
4665 struct GNUNET_HashCode trail_to_new_predecessor_id;
4666 struct GNUNET_PeerIdentity *trail_to_new_predecessor;
4667 struct FriendInfo *target_friend;
4668
4669 /* Generate trail id for trail from me to new predecessor = finger. */
4670 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG,
4671 &trail_to_new_predecessor_id,
4672 sizeof (trail_to_new_predecessor_id));
4673
4674 if (0 == trail_length)
4675 {
4676 trail_to_new_predecessor = NULL;
4677 GDS_ROUTING_add (&trail_to_new_predecessor_id,
4678 &my_identity,
4679 finger);
4680 target_friend = GNUNET_CONTAINER_multipeermap_get (friend_peermap,
4681 finger);
4682 if (NULL == target_friend)
4683 {
4684 GNUNET_break (0);
4685 return;
4686 }
4687 }
4688 else
4689 {
4690 /* Invert the trail to get the trail from me to finger, NOT including the
4691 endpoints.*/
4692 GNUNET_assert(NULL != GNUNET_CONTAINER_multipeermap_get (friend_peermap,
4693 &trail[trail_length-1]));
4694 trail_to_new_predecessor = invert_trail (trail,
4695 trail_length);
4696
4697 /* Add an entry in your routing table. */
4698 GDS_ROUTING_add (&trail_to_new_predecessor_id,
4699 &my_identity,
4700 &trail_to_new_predecessor[0]);
4701
4702 GNUNET_assert (NULL != (target_friend =
4703 GNUNET_CONTAINER_multipeermap_get (friend_peermap,
4704 &trail_to_new_predecessor[0])));
4705 }
4706
4707 /* Add entry in routing table of all peers that are part of trail from me
4708 to finger, including finger. */
4709 GDS_NEIGHBOURS_send_add_trail (&my_identity,
4710 finger,
4711 &trail_to_new_predecessor_id,
4712 trail_to_new_predecessor,
4713 trail_length,
4714 target_friend);
4715
4716 add_new_finger (finger,
4717 trail_to_new_predecessor,
4718 trail_length,
4719 &trail_to_new_predecessor_id,
4720 PREDECESSOR_FINGER_ID);
4721 GNUNET_free_non_null (trail_to_new_predecessor);
4722}
4723
4724
4725/**
4726 * Check if you already have a predecessor. If not then add finger as your
4727 * predecessor. If you have predecessor, then compare two peer identites.
4728 * If finger is correct predecessor, then remove the old entry, add finger in
4729 * finger table and send add_trail message to add the trail in the routing
4730 * table of all peers which are part of trail to reach from me to finger.
4731 * @param finger New peer which may be our predecessor.
4732 * @param trail List of peers to reach from @finger to me.
4733 * @param trail_length Total number of peer in @a trail.
4734 */
4735static void
4736compare_and_update_predecessor (const struct GNUNET_PeerIdentity *finger,
4737 const struct GNUNET_PeerIdentity *trail,
4738 unsigned int trail_length)
4739{
4740 struct FingerInfo *current_predecessor;
4741 const struct GNUNET_PeerIdentity *closest_peer;
4742 uint64_t predecessor_value;
4743 unsigned int is_predecessor = 1;
4744
4745 current_predecessor = &finger_table[PREDECESSOR_FINGER_ID];
4746 GNUNET_assert (0 != GNUNET_CRYPTO_cmp_peer_identity (finger,
4747 &my_identity));
4748
4749 /* No predecessor. Add finger as your predecessor. */
4750 if (GNUNET_NO == current_predecessor->is_present)
4751 {
4752 update_predecessor (finger,
4753 trail,
4754 trail_length);
4755 return;
4756 }
4757
4758 if (0 == GNUNET_CRYPTO_cmp_peer_identity (&current_predecessor->finger_identity,
4759 finger))
4760 {
4761 return;
4762 }
4763
4764 predecessor_value = compute_finger_identity_value (PREDECESSOR_FINGER_ID);
4765 closest_peer = select_closest_peer (finger,
4766 &current_predecessor->finger_identity,
4767 predecessor_value,
4768 is_predecessor);
4769
4770 /* Finger is the closest predecessor. Remove the existing one and add the new
4771 one. */
4772 if (0 == GNUNET_CRYPTO_cmp_peer_identity (closest_peer,
4773 finger))
4774 {
4775 remove_existing_finger (current_predecessor,
4776 PREDECESSOR_FINGER_ID);
4777 update_predecessor (finger,
4778 trail,
4779 trail_length);
4780 return;
4781 }
4782}
4783
4784
4785/**
4786 * Check format of a p2p verify successor messages.
4787 *
4788 * @param cls closure
4789 * @param vsm the message
4790 * @return #GNUNET_OK if @a vsm is well-formed
4791 */
4792static int
4793check_dht_p2p_verify_successor (void *cls,
4794 const struct PeerVerifySuccessorMessage *vsm)
4795{
4796 size_t msize;
4797
4798 msize = ntohs (vsm->header.size);
4799 if ((msize - sizeof (struct PeerVerifySuccessorMessage)) %
4800 sizeof (struct GNUNET_PeerIdentity) != 0)
4801 {
4802 GNUNET_break_op (0);
4803 return GNUNET_SYSERR;
4804 }
4805 return GNUNET_OK;
4806}
4807
4808
4809/**
4810 * Core handle for p2p verify successor messages.
4811 *
4812 * @param cls closure
4813 * @param vsm the message
4814 */
4815static void
4816handle_dht_p2p_verify_successor (void *cls,
4817 const struct PeerVerifySuccessorMessage *vsm)
4818{
4819 struct FriendInfo *friend = cls;
4820 struct GNUNET_HashCode trail_id;
4821 struct GNUNET_PeerIdentity successor;
4822 struct GNUNET_PeerIdentity source_peer;
4823 struct GNUNET_PeerIdentity *trail;
4824 const struct GNUNET_PeerIdentity *next_hop;
4825 struct FingerInfo current_predecessor;
4826 struct FriendInfo *target_friend;
4827 unsigned int trail_src_to_curr_pred_len = 0;
4828 struct GNUNET_PeerIdentity *trail_src_to_curr_pred;
4829 unsigned int trail_length;
4830 size_t msize;
4831
4832 msize = ntohs (vsm->header.size);
4833 trail_length = (msize - sizeof (struct PeerVerifySuccessorMessage))/
4834 sizeof (struct GNUNET_PeerIdentity);
4835 GNUNET_STATISTICS_update (GDS_stats,
4836 gettext_noop ("# Bytes received from other peers"),
4837 msize,
4838 GNUNET_NO);
4839
4840 trail_id = vsm->trail_id;
4841 source_peer = vsm->source_peer;
4842 successor = vsm->successor;
4843 trail = (struct GNUNET_PeerIdentity *)&vsm[1];
4844
4845 /* I am NOT the successor of source_peer. Pass the message to next_hop on
4846 * the trail. */
4847 if (0 != (GNUNET_CRYPTO_cmp_peer_identity (&successor,
4848 &my_identity)))
4849 {
4850 next_hop = GDS_ROUTING_get_next_hop (&trail_id,
4851 GDS_ROUTING_SRC_TO_DEST);
4852 if (NULL == next_hop)
4853 return;
4854
4855 target_friend = GNUNET_CONTAINER_multipeermap_get (friend_peermap,
4856 next_hop);
4857 if (NULL == target_friend)
4858 {
4859 GNUNET_break_op(0);
4860 return;
4861 }
4862 GDS_NEIGHBOURS_send_verify_successor_message (&source_peer,
4863 &successor,
4864 &trail_id,
4865 trail,
4866 trail_length,
4867 target_friend);
4868 return;
4869 }
4870
4871 /* I am the destination of this message. */
4872 /* Check if the source_peer could be our predecessor and if yes then update
4873 * it. */
4874 compare_and_update_predecessor (&source_peer,
4875 trail,
4876 trail_length);
4877 current_predecessor = finger_table[PREDECESSOR_FINGER_ID];
4878
4879 /* Is source of this message NOT my predecessor. */
4880 if (0 != (GNUNET_CRYPTO_cmp_peer_identity (&current_predecessor.finger_identity,
4881 &source_peer)))
4882 {
4883 trail_src_to_curr_pred
4884 = get_trail_src_to_curr_pred (source_peer,
4885 trail,
4886 trail_length,
4887 &trail_src_to_curr_pred_len);
4888 }
4889 else
4890 {
4891 trail_src_to_curr_pred_len = trail_length;
4892 trail_src_to_curr_pred = GNUNET_new_array (trail_src_to_curr_pred_len,
4893 struct GNUNET_PeerIdentity);
4894
4895 for (unsigned int i = 0; i < trail_src_to_curr_pred_len; i++)
4896 {
4897 trail_src_to_curr_pred[i] = trail[i];
4898 }
4899 }
4900
4901 GNUNET_assert (NULL !=
4902 (target_friend =
4903 GNUNET_CONTAINER_multipeermap_get (friend_peermap,
4904 friend->id)));
4905 GDS_NEIGHBOURS_send_verify_successor_result (&source_peer,
4906 &my_identity,
4907 &current_predecessor.finger_identity,
4908 &trail_id,
4909 trail_src_to_curr_pred,
4910 trail_src_to_curr_pred_len,
4911 GDS_ROUTING_DEST_TO_SRC,
4912 target_friend);
4913 GNUNET_free_non_null (trail_src_to_curr_pred);
4914}
4915
4916
4917/**
4918 * If the trail from me to my probable successor contains a friend not
4919 * at index 0, then we can shorten the trail.
4920 *
4921 * @param probable_successor Peer which is our probable successor
4922 * @param trail_me_to_probable_successor Peers in path from me to my probable
4923 * successor, NOT including the endpoints.
4924 * @param trail_me_to_probable_successor_len Total number of peers in
4925 * @a trail_me_to_probable_succesor.
4926 * @return Updated trail, if any friend found.
4927 * Else the trail_me_to_probable_successor.
4928 */
4929const struct GNUNET_PeerIdentity *
4930check_trail_me_to_probable_succ (const struct GNUNET_PeerIdentity *probable_successor,
4931 const struct GNUNET_PeerIdentity *trail_me_to_probable_successor,
4932 unsigned int trail_me_to_probable_successor_len,
4933 unsigned int *trail_to_new_successor_length)
4934{
4935 unsigned int i;
4936 unsigned int j;
4937 struct GNUNET_PeerIdentity *trail_to_new_successor;
4938
4939 /* Probable successor is a friend */
4940 if (NULL != GNUNET_CONTAINER_multipeermap_get (friend_peermap,
4941 probable_successor))
4942 {
4943 trail_to_new_successor = NULL;
4944 *trail_to_new_successor_length = 0;
4945 return trail_to_new_successor;
4946 }
4947
4948 /* Is there any friend of yours in this trail. */
4949 if (trail_me_to_probable_successor_len > 1)
4950 {
4951 for (i = trail_me_to_probable_successor_len - 1; i > 0; i--)
4952 {
4953 if (NULL == GNUNET_CONTAINER_multipeermap_get (friend_peermap,
4954 &trail_me_to_probable_successor[i]))
4955 continue;
4956
4957 *trail_to_new_successor_length = (trail_me_to_probable_successor_len - i);
4958 trail_to_new_successor = GNUNET_new_array (*trail_to_new_successor_length,
4959 struct GNUNET_PeerIdentity);
4960 for (j = 0; j < *trail_to_new_successor_length; i++,j++)
4961 {
4962 trail_to_new_successor[j] = trail_me_to_probable_successor[i];
4963 }
4964
4965 return trail_to_new_successor;
4966 }
4967 }
4968
4969 *trail_to_new_successor_length = trail_me_to_probable_successor_len;
4970 return trail_me_to_probable_successor;
4971}
4972
4973
4974// TODO: Move up
4975struct SendNotifyContext
4976{
4977 struct GNUNET_PeerIdentity source_peer;
4978 struct GNUNET_PeerIdentity successor;
4979 struct GNUNET_PeerIdentity *successor_trail;
4980 unsigned int successor_trail_length;
4981 struct GNUNET_HashCode succesor_trail_id;
4982 struct FriendInfo *target_friend;
4983 unsigned int num_retries_scheduled;
4984};
4985
4986
4987void
4988send_notify_new_successor (void *cls);
4989
4990
4991/**
4992 * Check if the peer which sent us verify successor result message is still ours
4993 * successor or not. If not, then compare existing successor and probable successor.
4994 * In case probable successor is the correct successor, remove the existing
4995 * successor. Add probable successor as new successor. Send notify new successor
4996 * message to new successor.
4997 * @param curr_succ Peer to which we sent the verify successor message. It may
4998 * or may not be our real current successor, as we may have few iterations of
4999 * find finger trail task.
5000 * @param probable_successor Peer which should be our successor accroding to @a
5001 * curr_succ
5002 * @param trail List of peers to reach from me to @a probable successor, NOT including
5003 * endpoints.
5004 * @param trail_length Total number of peers in @a trail.
5005 */
5006static void
5007compare_and_update_successor (const struct GNUNET_PeerIdentity *curr_succ,
5008 const struct GNUNET_PeerIdentity *probable_successor,
5009 const struct GNUNET_PeerIdentity *trail,
5010 unsigned int trail_length)
5011{
5012 struct FingerInfo *current_successor;
5013 const struct GNUNET_PeerIdentity *closest_peer;
5014 struct GNUNET_HashCode trail_id;
5015 const struct GNUNET_PeerIdentity *trail_me_to_probable_succ;
5016 struct FriendInfo *target_friend;
5017 unsigned int trail_me_to_probable_succ_len;
5018 unsigned int is_predecessor = 0;
5019 uint64_t successor_value;
5020 struct SendNotifyContext *notify_ctx;
5021
5022 current_successor = &finger_table[0];
5023 successor_value = compute_finger_identity_value(0);
5024
5025 /* If probable successor is same as current_successor, do nothing. */
5026 if(0 == GNUNET_CRYPTO_cmp_peer_identity (probable_successor,
5027 &current_successor->finger_identity))
5028 {
5029 if ((NULL != GDS_stats))
5030 {
5031 char *my_id_str;
5032 uint64_t succ;
5033 char *key;
5034 uint64_t my_id;
5035 GNUNET_memcpy (&my_id, &my_identity, sizeof(uint64_t));
5036 my_id_str = GNUNET_strdup (GNUNET_i2s_full (&my_identity));
5037 GNUNET_memcpy (&succ,
5038 &current_successor->finger_identity,
5039 sizeof(uint64_t));
5040 succ = GNUNET_ntohll(succ);
5041 GNUNET_asprintf (&key,
5042 "XDHT:%s:",
5043 my_id_str);
5044 GNUNET_free (my_id_str);
5045
5046 GNUNET_STATISTICS_set (GDS_stats, key, succ, 0);
5047 GNUNET_free (key);
5048 }
5049 if (send_verify_successor_task == NULL)
5050 send_verify_successor_task =
5051 GNUNET_SCHEDULER_add_delayed(verify_successor_next_send_time,
5052 &send_verify_successor_message,
5053 NULL);
5054 return;
5055 }
5056 closest_peer = select_closest_peer (probable_successor,
5057 &current_successor->finger_identity,
5058 successor_value,
5059 is_predecessor);
5060
5061 /* If the current_successor in the finger table is closest, then do nothing. */
5062 if (0 == GNUNET_CRYPTO_cmp_peer_identity (closest_peer,
5063 &current_successor->finger_identity))
5064 {
5065 //FIXME: Is this a good place to return the stats.
5066 if ((NULL != GDS_stats))
5067 {
5068 char *my_id_str;
5069 uint64_t succ;
5070 char *key;
5071
5072 my_id_str = GNUNET_strdup (GNUNET_i2s_full (&my_identity));
5073 GNUNET_memcpy(&succ, &current_successor->finger_identity, sizeof(uint64_t));
5074 GNUNET_asprintf (&key, "XDHT:%s:", my_id_str);
5075 GNUNET_free (my_id_str);
5076 GNUNET_STATISTICS_set (GDS_stats, key, succ, 0);
5077 GNUNET_free (key);
5078 }
5079
5080 if(0 == successor_times)
5081 {
5082// successor_times = 3;
5083 verify_successor_next_send_time =
5084 GNUNET_TIME_STD_BACKOFF (verify_successor_next_send_time);
5085 }
5086 else
5087 successor_times--;
5088
5089
5090 if (send_verify_successor_task == NULL)
5091 send_verify_successor_task =
5092 GNUNET_SCHEDULER_add_delayed (verify_successor_next_send_time,
5093 &send_verify_successor_message,
5094 NULL);
5095 return;
5096 }
5097
5098 /* Probable successor is the closest peer.*/
5099 if(trail_length > 0)
5100 {
5101 GNUNET_assert(NULL != GNUNET_CONTAINER_multipeermap_get (friend_peermap,
5102 &trail[0]));
5103 }
5104 else
5105 {
5106 GNUNET_assert(NULL != GNUNET_CONTAINER_multipeermap_get (friend_peermap,
5107 probable_successor));
5108 }
5109
5110 trail_me_to_probable_succ_len = 0;
5111 trail_me_to_probable_succ = check_trail_me_to_probable_succ (probable_successor,
5112 trail,
5113 trail_length,
5114 &trail_me_to_probable_succ_len);
5115
5116 /* Remove the existing successor. */
5117 remove_existing_finger (current_successor, 0);
5118 /* Generate a new trail id to reach to your new successor. */
5119 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG,
5120 &trail_id,
5121 sizeof (trail_id));
5122
5123 if (trail_me_to_probable_succ_len > 0)
5124 {
5125 GDS_ROUTING_add (&trail_id,
5126 &my_identity,
5127 &trail_me_to_probable_succ[0]);
5128 GNUNET_assert (NULL !=
5129 (target_friend =
5130 GNUNET_CONTAINER_multipeermap_get (friend_peermap,
5131 &trail_me_to_probable_succ[0])));
5132 }
5133 else
5134 {
5135 GDS_ROUTING_add (&trail_id,
5136 &my_identity,
5137 probable_successor);
5138 GNUNET_assert (NULL !=
5139 (target_friend =
5140 GNUNET_CONTAINER_multipeermap_get (friend_peermap,
5141 probable_successor)));
5142 }
5143
5144 add_new_finger (probable_successor,
5145 trail_me_to_probable_succ,
5146 trail_me_to_probable_succ_len,
5147 &trail_id,
5148 0);
5149
5150 notify_ctx = GNUNET_new (struct SendNotifyContext);
5151
5152 notify_ctx->source_peer = my_identity;
5153 notify_ctx->successor = *probable_successor;
5154 notify_ctx->successor_trail = GNUNET_new_array (trail_me_to_probable_succ_len,
5155 struct GNUNET_PeerIdentity);
5156 GNUNET_memcpy (notify_ctx->successor_trail,
5157 trail_me_to_probable_succ,
5158 sizeof(struct GNUNET_PeerIdentity) * trail_me_to_probable_succ_len);
5159 notify_ctx->successor_trail_length = trail_me_to_probable_succ_len;
5160 notify_ctx->succesor_trail_id = trail_id;
5161 notify_ctx->target_friend = target_friend;
5162 notify_ctx->num_retries_scheduled = 0;
5163
5164 // TODO: Check if we should verify before schedule if already scheduled.
5165 GNUNET_SCHEDULER_add_now (&send_notify_new_successor,
5166 notify_ctx);
5167}
5168
5169
5170void
5171send_notify_new_successor (void *cls)
5172{
5173 struct SendNotifyContext *ctx = cls;
5174
5175 GDS_NEIGHBOURS_send_notify_new_successor (&ctx->source_peer,
5176 &ctx->successor,
5177 ctx->successor_trail,
5178 ctx->successor_trail_length,
5179 &ctx->succesor_trail_id,
5180 ctx->target_friend);
5181
5182 if ( (0 == ctx->num_retries_scheduled) &&
5183 (send_notify_new_successor_retry_task != NULL) )
5184 {
5185 // Result from previous notify successos hasn't arrived, so the retry task
5186 // hasn't been cancelled! Already a new notify successor must be called.
5187 // We will cancel the retry request.
5188 struct SendNotifyContext *old_notify_ctx;
5189
5190 old_notify_ctx = GNUNET_SCHEDULER_cancel(send_notify_new_successor_retry_task);
5191 GNUNET_free (old_notify_ctx->successor_trail);
5192 GNUNET_free (old_notify_ctx);
5193 send_notify_new_successor_retry_task = NULL;
5194 }
5195
5196 ctx->num_retries_scheduled++;
5197 send_notify_new_successor_retry_task
5198 = GNUNET_SCHEDULER_add_delayed (notify_successor_retry_time,
5199 &send_notify_new_successor,
5200 cls);
5201}
5202
5203
5204/**
5205 * Check integrity of verify successor result messages.
5206 *
5207 * @param cls closure
5208 * @param vsrm the message
5209 * @return #GNUNET_OK if @a vrsm is well-formed
5210 */
5211static int
5212check_dht_p2p_verify_successor_result (void *cls,
5213 const struct PeerVerifySuccessorResultMessage *vsrm)
5214{
5215 size_t msize;
5216
5217 msize = ntohs (vsrm->header.size);
5218 if ((msize - sizeof (struct PeerVerifySuccessorResultMessage)) %
5219 sizeof (struct GNUNET_PeerIdentity) != 0)
5220 {
5221 GNUNET_break_op (0);
5222 return GNUNET_SYSERR;
5223 }
5224 return GNUNET_OK;
5225}
5226
5227
5228/**
5229 * Core handle for p2p verify successor result messages.
5230 *
5231 * @param cls closure
5232 * @param vsrm the message
5233 */
5234static void
5235handle_dht_p2p_verify_successor_result (void *cls,
5236 const struct PeerVerifySuccessorResultMessage *vsrm)
5237{
5238 enum GDS_ROUTING_trail_direction trail_direction;
5239 struct GNUNET_PeerIdentity querying_peer;
5240 struct GNUNET_HashCode trail_id;
5241 const struct GNUNET_PeerIdentity *next_hop;
5242 struct FriendInfo *target_friend;
5243 struct GNUNET_PeerIdentity probable_successor;
5244 struct GNUNET_PeerIdentity current_successor;
5245 const struct GNUNET_PeerIdentity *trail;
5246 unsigned int trail_length;
5247 size_t msize;
5248
5249 msize = ntohs (vsrm->header.size);
5250 trail_length = (msize - sizeof (struct PeerVerifySuccessorResultMessage))
5251 / sizeof (struct GNUNET_PeerIdentity);
5252
5253 GNUNET_STATISTICS_update (GDS_stats,
5254 gettext_noop ("# Bytes received from other peers"),
5255 msize,
5256 GNUNET_NO);
5257
5258 trail = (const struct GNUNET_PeerIdentity *) &vsrm[1];
5259 querying_peer = vsrm->querying_peer;
5260 trail_direction = ntohl (vsrm->trail_direction);
5261 trail_id = vsrm->trail_id;
5262 probable_successor = vsrm->probable_successor;
5263 current_successor = vsrm->current_successor;
5264
5265 /* Am I the querying_peer? */
5266 if (0 == (GNUNET_CRYPTO_cmp_peer_identity (&querying_peer,
5267 &my_identity)))
5268 {
5269 /* Cancel Retry Task */
5270 if (NULL != send_verify_successor_retry_task)
5271 {
5272 struct VerifySuccessorContext *ctx;
5273
5274 ctx = GNUNET_SCHEDULER_cancel (send_verify_successor_retry_task);
5275 GNUNET_free (ctx);
5276 send_verify_successor_retry_task = NULL;
5277 }
5278 compare_and_update_successor (&current_successor,
5279 &probable_successor,
5280 trail,
5281 trail_length);
5282 return;
5283 }
5284
5285 /*If you are not the querying peer then pass on the message */
5286 if(NULL == (next_hop =
5287 GDS_ROUTING_get_next_hop (&trail_id,
5288 trail_direction)))
5289 {
5290 /* Here it may happen that source peer has found a new successor, and removed
5291 the trail, Hence no entry found in the routing table. Fail silently.*/
5292 DEBUG (" NO ENTRY FOUND IN %s ROUTING TABLE for trail id %s, line %u",
5293 GNUNET_i2s (&my_identity),
5294 GNUNET_h2s (&trail_id),
5295 __LINE__);
5296 GNUNET_break_op(0);
5297 return;
5298 }
5299 if (NULL == (target_friend =
5300 GNUNET_CONTAINER_multipeermap_get (friend_peermap, next_hop)))
5301 {
5302 GNUNET_break_op(0);
5303 return;
5304 }
5305 GDS_NEIGHBOURS_send_verify_successor_result (&querying_peer,
5306 &vsrm->current_successor,
5307 &probable_successor,
5308 &trail_id,
5309 trail,
5310 trail_length,
5311 trail_direction,
5312 target_friend);
5313}
5314
5315
5316/**
5317 * Check integrity of p2p notify new successor messages.
5318 *
5319 * @param cls closure
5320 * @param nsm the message
5321 * @return #GNUNET_OK if @a nsm is well-formed
5322 */
5323static int
5324check_dht_p2p_notify_new_successor (void *cls,
5325 const struct PeerNotifyNewSuccessorMessage *nsm)
5326{
5327 size_t msize;
5328
5329 msize = ntohs (nsm->header.size);
5330 if ((msize - sizeof (struct PeerNotifyNewSuccessorMessage)) %
5331 sizeof (struct GNUNET_PeerIdentity) != 0)
5332 {
5333 GNUNET_break_op (0);
5334 return GNUNET_SYSERR;
5335 }
5336 return GNUNET_OK;
5337}
5338
5339
5340/**
5341 * Core handle for p2p notify new successor messages.
5342 *
5343 * @param cls closure
5344 * @param nsm the message
5345 */
5346static void
5347handle_dht_p2p_notify_new_successor (void *cls,
5348 const struct PeerNotifyNewSuccessorMessage *nsm)
5349{
5350 struct FriendInfo *friend = cls;
5351 const struct GNUNET_PeerIdentity *trail;
5352 struct GNUNET_PeerIdentity source;
5353 struct GNUNET_PeerIdentity new_successor;
5354 struct GNUNET_HashCode trail_id;
5355 struct GNUNET_PeerIdentity next_hop;
5356 struct FriendInfo *target_friend;
5357 int my_index;
5358 size_t msize;
5359 uint32_t trail_length;
5360
5361 msize = ntohs (nsm->header.size);
5362 trail_length = (msize - sizeof (struct PeerNotifyNewSuccessorMessage))/
5363 sizeof (struct GNUNET_PeerIdentity);
5364 GNUNET_STATISTICS_update (GDS_stats,
5365 gettext_noop ("# Bytes received from other peers"),
5366 msize,
5367 GNUNET_NO);
5368 trail = (const struct GNUNET_PeerIdentity *) &nsm[1];
5369 source = nsm->source_peer;
5370 new_successor = nsm->new_successor;
5371 trail_id = nsm->trail_id;
5372
5373 /* I am the new_successor to source_peer. */
5374 if (0 == GNUNET_CRYPTO_cmp_peer_identity (&my_identity,
5375 &new_successor))
5376 {
5377 if (trail_length > 0)
5378 GNUNET_assert(0 == GNUNET_CRYPTO_cmp_peer_identity (&trail[trail_length - 1],
5379 friend->id));
5380 else
5381 GNUNET_assert(0 == GNUNET_CRYPTO_cmp_peer_identity (&source,
5382 friend->id));
5383
5384 compare_and_update_predecessor (&source,
5385 trail,
5386 trail_length);
5387 target_friend = GNUNET_CONTAINER_multipeermap_get (friend_peermap,
5388 friend->id);
5389 GNUNET_assert (NULL != target_friend);
5390 GDS_NEIGHBOURS_send_notify_succcessor_confirmation (&trail_id,
5391 GDS_ROUTING_DEST_TO_SRC,
5392 target_friend);
5393 return;
5394 }
5395
5396 GNUNET_assert(trail_length > 0);
5397 /* I am part of trail to reach to successor. */
5398 my_index = search_my_index (trail, trail_length);
5399 if (-1 == my_index)
5400 {
5401 DEBUG ("No entry found in trail\n");
5402 GNUNET_break_op (0);
5403 return;
5404 }
5405 if((trail_length + 1) == my_index)
5406 {
5407 DEBUG ("Found twice in trail.\n");
5408 GNUNET_break_op (0);
5409 return;
5410 }
5411 if ((trail_length-1) == my_index)
5412 next_hop = new_successor;
5413 else
5414 next_hop = trail[my_index + 1];
5415
5416 GDS_ROUTING_add (&trail_id,
5417 friend->id,
5418 &next_hop);
5419 target_friend = GNUNET_CONTAINER_multipeermap_get (friend_peermap,
5420 &next_hop);
5421 if (NULL == target_friend)
5422 {
5423 GNUNET_break(0);
5424 return;
5425 }
5426 GDS_NEIGHBOURS_send_notify_new_successor (&source,
5427 &new_successor,
5428 trail,
5429 trail_length,
5430 &trail_id,
5431 target_friend);
5432}
5433
5434
5435/**
5436 * Core handler for P2P notify successor message
5437 *
5438 * @param cls closure
5439 * @param notify_confirmation the message
5440 */
5441static void
5442handle_dht_p2p_notify_succ_confirmation (void *cls,
5443 const struct PeerNotifyConfirmationMessage *notify_confirmation)
5444{
5445 enum GDS_ROUTING_trail_direction trail_direction;
5446 struct GNUNET_HashCode trail_id;
5447 struct FriendInfo *target_friend;
5448 const struct GNUNET_PeerIdentity *next_hop;
5449
5450 GNUNET_STATISTICS_update (GDS_stats,
5451 gettext_noop ("# Bytes received from other peers"),
5452 ntohs (notify_confirmation->header.size),
5453 GNUNET_NO);
5454 trail_direction = ntohl (notify_confirmation->trail_direction);
5455 trail_id = notify_confirmation->trail_id;
5456
5457 next_hop = GDS_ROUTING_get_next_hop (&trail_id,
5458 trail_direction);
5459 if (NULL == next_hop)
5460 {
5461 /* The source of notify new successor, might have found even a better
5462 successor. In that case it send a trail teardown message, and hence,
5463 the next hop is NULL. */
5464 //Fixme: Add some print to confirm the above theory.
5465 return;
5466 }
5467
5468 /* I peer which sent the notify successor message to the successor. */
5469 if (0 == GNUNET_CRYPTO_cmp_peer_identity (next_hop,
5470 &my_identity))
5471 {
5472 /*
5473 * Schedule another round of verify sucessor with your current successor
5474 * which may or may not be source of this message. This message is used
5475 * only to ensure that we have a path setup to reach to our successor.
5476 */
5477
5478 // TODO: cancel schedule of notify_successor_retry_task
5479 if (send_notify_new_successor_retry_task != NULL)
5480 {
5481 struct SendNotifyContext *notify_ctx;
5482 notify_ctx = GNUNET_SCHEDULER_cancel(send_notify_new_successor_retry_task);
5483 GNUNET_free (notify_ctx->successor_trail);
5484 GNUNET_free (notify_ctx);
5485 send_notify_new_successor_retry_task = NULL;
5486 }
5487 if (send_verify_successor_task == NULL)
5488 {
5489 verify_successor_next_send_time.rel_value_us =
5490 DHT_SEND_VERIFY_SUCCESSOR_INTERVAL.rel_value_us +
5491 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
5492 DHT_SEND_VERIFY_SUCCESSOR_INTERVAL.rel_value_us);
5493 send_verify_successor_task
5494 = GNUNET_SCHEDULER_add_delayed(verify_successor_next_send_time,
5495 &send_verify_successor_message,
5496 NULL);
5497 }
5498 }
5499 else
5500 {
5501 target_friend = GNUNET_CONTAINER_multipeermap_get (friend_peermap,
5502 next_hop);
5503 if (NULL == target_friend)
5504 {
5505 DEBUG ("\n friend not found, line number = %d",
5506 __LINE__);
5507 return;
5508 }
5509 GDS_NEIGHBOURS_send_notify_succcessor_confirmation (&trail_id,
5510 GDS_ROUTING_DEST_TO_SRC,
5511 target_friend);
5512 }
5513}
5514
5515
5516/**
5517 * Check integrity of P2P trail rejection message
5518 *
5519 * @param cls closure
5520 * @param trail_rejection the message
5521 * @return #GNUNET_OK if @a trail_rejection is well-formed
5522 */
5523static int
5524check_dht_p2p_trail_setup_rejection (void *cls,
5525 const struct PeerTrailRejectionMessage *trail_rejection)
5526{
5527 size_t msize;
5528
5529 msize = ntohs (trail_rejection->header.size);
5530 if ((msize - sizeof (struct PeerTrailRejectionMessage)) %
5531 sizeof (struct GNUNET_PeerIdentity) != 0)
5532 {
5533 GNUNET_break_op (0);
5534 return GNUNET_SYSERR;
5535 }
5536 return GNUNET_OK;
5537}
5538
5539
5540/**
5541 * Core handler for P2P trail rejection message
5542 *
5543 * @param cls closure
5544 * @param trail_rejection the message
5545 */
5546static void
5547handle_dht_p2p_trail_setup_rejection (void *cls,
5548 const struct PeerTrailRejectionMessage *trail_rejection)
5549{
5550 struct FriendInfo *friend = cls;
5551 unsigned int trail_length;
5552 const struct GNUNET_PeerIdentity *trail_peer_list;
5553 struct FriendInfo *target_friend;
5554 struct GNUNET_TIME_Relative congestion_timeout;
5555 struct GNUNET_HashCode trail_id;
5556 struct GNUNET_PeerIdentity next_peer;
5557 struct GNUNET_PeerIdentity source;
5558 uint64_t ultimate_destination_finger_value;
5559 unsigned int is_predecessor;
5560 struct Closest_Peer successor;
5561 size_t msize;
5562
5563 msize = ntohs (trail_rejection->header.size);
5564 trail_length = (msize - sizeof (struct PeerTrailRejectionMessage))/
5565 sizeof (struct GNUNET_PeerIdentity);
5566 GNUNET_STATISTICS_update (GDS_stats,
5567 gettext_noop ("# Bytes received from other peers"),
5568 msize,
5569 GNUNET_NO);
5570
5571 trail_peer_list = (const struct GNUNET_PeerIdentity *) &trail_rejection[1];
5572 is_predecessor = ntohl (trail_rejection->is_predecessor);
5573 congestion_timeout = trail_rejection->congestion_time;
5574 source = trail_rejection->source_peer;
5575 trail_id = trail_rejection->trail_id;
5576 ultimate_destination_finger_value
5577 = GNUNET_ntohll (trail_rejection->ultimate_destination_finger_value);
5578 /* First set the congestion time of the friend that sent you this message. */
5579 target_friend = GNUNET_CONTAINER_multipeermap_get (friend_peermap,
5580 friend->id);
5581 if (NULL == target_friend)
5582 {
5583 DEBUG ("\nLINE = %d ,No friend found.",__LINE__);
5584 GNUNET_break(0);
5585 return;
5586 }
5587 target_friend->congestion_timestamp
5588 = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get(),
5589 congestion_timeout);
5590
5591 /* I am the source peer which wants to setup the trail. Do nothing.
5592 * send_find_finger_trail_task is scheduled periodically.*/
5593 if(0 == (GNUNET_CRYPTO_cmp_peer_identity (&my_identity, &source)))
5594 return;
5595
5596 /* If I am congested then pass this message to peer before me in trail. */
5597 if (GNUNET_YES == GDS_ROUTING_threshold_reached())
5598 {
5599 /* First remove yourself from the trail. */
5600 unsigned int new_trail_length = trail_length - 1;
5601 struct GNUNET_PeerIdentity trail[new_trail_length];
5602
5603 GNUNET_memcpy (trail,
5604 trail_peer_list,
5605 new_trail_length * sizeof(struct GNUNET_PeerIdentity));
5606 if (0 == trail_length)
5607 next_peer = source;
5608 else
5609 next_peer = trail[new_trail_length-1];
5610
5611 target_friend
5612 = GNUNET_CONTAINER_multipeermap_get (friend_peermap,
5613 &next_peer);
5614 if (NULL == target_friend)
5615 {
5616 DEBUG ("\nLINE = %d ,No friend found.",
5617 __LINE__);
5618 GNUNET_break(0);
5619 return;
5620 }
5621 GDS_NEIGHBOURS_send_trail_rejection (&source,
5622 ultimate_destination_finger_value,
5623 &my_identity,
5624 is_predecessor,
5625 trail,
5626 new_trail_length,
5627 &trail_id,
5628 target_friend,
5629 CONGESTION_TIMEOUT);
5630 return;
5631 }
5632
5633 successor = find_local_best_known_next_hop (ultimate_destination_finger_value,
5634 is_predecessor);
5635
5636 /* Am I the final destination? */
5637 if (0 == GNUNET_CRYPTO_cmp_peer_identity (&successor.best_known_destination,
5638 &my_identity))
5639 {
5640 /*Here you are already part of trail. Copy the trail removing yourself. */
5641 unsigned int new_trail_length = trail_length - 1;
5642 struct GNUNET_PeerIdentity trail[new_trail_length];
5643
5644 GNUNET_memcpy (trail,
5645 trail_peer_list,
5646 new_trail_length * sizeof(struct GNUNET_PeerIdentity));
5647
5648 if (0 == new_trail_length)
5649 next_peer = source;
5650 else
5651 {
5652 next_peer = trail[new_trail_length-1];
5653 }
5654 target_friend = GNUNET_CONTAINER_multipeermap_get (friend_peermap,
5655 &next_peer);
5656
5657 if (NULL == target_friend)
5658 {
5659 DEBUG ("\nLINE = %d ,No friend found.",
5660 __LINE__);
5661 GNUNET_break(0);
5662 return;
5663 }
5664 GDS_NEIGHBOURS_send_trail_setup_result (&source,
5665 &my_identity,
5666 target_friend,
5667 new_trail_length,
5668 trail,
5669 is_predecessor,
5670 ultimate_destination_finger_value,
5671 &trail_id);
5672 return;
5673 }
5674 /* Here I was already part of trail. So no need to add. */
5675 target_friend = GNUNET_CONTAINER_multipeermap_get (friend_peermap,
5676 &successor.next_hop);
5677 if (NULL == target_friend)
5678 {
5679 DEBUG ("\nLINE = %d ,No friend found.",__LINE__);
5680 GNUNET_break (0);
5681 return;
5682 }
5683 GDS_NEIGHBOURS_send_trail_setup (&source,
5684 ultimate_destination_finger_value,
5685 &successor.best_known_destination,
5686 target_friend,
5687 trail_length,
5688 trail_peer_list,
5689 is_predecessor,
5690 &trail_id,
5691 &successor.trail_id);
5692}
5693
5694
5695/**
5696 * Core handler for trail teardown message.
5697 *
5698 * @param cls closure
5699 * @param trail_teardown the message
5700 */
5701static void
5702handle_dht_p2p_trail_teardown (void *cls,
5703 const struct PeerTrailTearDownMessage *trail_teardown)
5704{
5705 enum GDS_ROUTING_trail_direction trail_direction;
5706 struct GNUNET_HashCode trail_id;
5707 const struct GNUNET_PeerIdentity *next_hop;
5708 size_t msize;
5709
5710 msize = ntohs (trail_teardown->header.size);
5711 GNUNET_STATISTICS_update (GDS_stats,
5712 gettext_noop ("# Bytes received from other peers"),
5713 msize,
5714 GNUNET_NO);
5715 trail_direction = ntohl (trail_teardown->trail_direction);
5716 trail_id = trail_teardown->trail_id;
5717
5718 /* Check if peer is the real peer from which we should get this message.*/
5719 /* Get the prev_hop for this trail by getting the next hop in opposite direction. */
5720#if 0
5721 GNUNET_assert (NULL != (prev_hop =
5722 GDS_ROUTING_get_next_hop (trail_id, ! trail_direction)));
5723 if (0 != GNUNET_CRYPTO_cmp_peer_identity (prev_hop,
5724 friend->id))
5725 {
5726 GNUNET_break (0);
5727 return;
5728 }
5729#endif
5730
5731 next_hop = GDS_ROUTING_get_next_hop (&trail_id,
5732 trail_direction);
5733 if (NULL == next_hop)
5734 {
5735 DEBUG(" NO ENTRY FOUND IN %s ROUTING TABLE for trail id %s, line %u",
5736 GNUNET_i2s (&my_identity),
5737 GNUNET_h2s (&trail_id),
5738 __LINE__);
5739 GNUNET_break (0);
5740 return;
5741 }
5742
5743 /* I am the next hop, which means I am the final destination. */
5744 if (0 == GNUNET_CRYPTO_cmp_peer_identity (next_hop, &my_identity))
5745 {
5746 GNUNET_assert (GNUNET_YES ==
5747 GDS_ROUTING_remove_trail (&trail_id));
5748 return;
5749 }
5750 /* If not final destination, then send a trail teardown message to next hop.*/
5751 GNUNET_assert (NULL != GNUNET_CONTAINER_multipeermap_get (friend_peermap,
5752 next_hop));
5753 GNUNET_assert (GNUNET_YES ==
5754 GDS_ROUTING_remove_trail (&trail_id));
5755 GDS_NEIGHBOURS_send_trail_teardown (&trail_id,
5756 trail_direction,
5757 next_hop);
5758}
5759
5760
5761/**
5762 * Check validity of p2p add trail message.
5763 *
5764 * @param cls closure
5765 * @param add_trail the message
5766 * @return #GNUNET_OK if @a add_trail is well-formed
5767 */
5768static int
5769check_dht_p2p_add_trail (void *cls,
5770 const struct PeerAddTrailMessage *add_trail)
5771{
5772 size_t msize;
5773
5774 msize = ntohs (add_trail->header.size);
5775 if ((msize - sizeof (struct PeerAddTrailMessage)) %
5776 sizeof (struct GNUNET_PeerIdentity) != 0)
5777 {
5778 GNUNET_break_op (0);
5779 return GNUNET_SYSERR;
5780 }
5781 return GNUNET_OK;
5782}
5783
5784
5785/**
5786 * Core handle for p2p add trail message.
5787 *
5788 * @param cls closure
5789 * @param add_trail the message
5790 */
5791static void
5792handle_dht_p2p_add_trail (void *cls,
5793 const struct PeerAddTrailMessage *add_trail)
5794{
5795 struct FriendInfo *friend = cls;
5796 const struct GNUNET_PeerIdentity *trail;
5797 struct GNUNET_HashCode trail_id;
5798 struct GNUNET_PeerIdentity destination_peer;
5799 struct GNUNET_PeerIdentity source_peer;
5800 struct GNUNET_PeerIdentity next_hop;
5801 unsigned int trail_length;
5802 unsigned int my_index;
5803 size_t msize;
5804
5805 msize = ntohs (add_trail->header.size);
5806 /* In this message we pass the whole trail from source to destination as we
5807 * are adding that trail.*/
5808 //FIXME: failed when run with 1000 pears. check why.
5809 trail_length = (msize - sizeof (struct PeerAddTrailMessage))/
5810 sizeof (struct GNUNET_PeerIdentity);
5811 GNUNET_STATISTICS_update (GDS_stats,
5812 gettext_noop ("# Bytes received from other peers"),
5813 msize,
5814 GNUNET_NO);
5815
5816 trail = (const struct GNUNET_PeerIdentity *) &add_trail[1];
5817 destination_peer = add_trail->destination_peer;
5818 source_peer = add_trail->source_peer;
5819 trail_id = add_trail->trail_id;
5820
5821 /* I am not the destination of the trail. */
5822 if (0 != GNUNET_CRYPTO_cmp_peer_identity (&my_identity,
5823 &destination_peer))
5824 {
5825 struct FriendInfo *target_friend;
5826
5827 /* Get my location in the trail. */
5828 my_index = search_my_index (trail, trail_length);
5829 if (-1 == my_index)
5830 {
5831 GNUNET_break_op (0);
5832 return;
5833 }
5834 if((trail_length + 1) == my_index)
5835 {
5836 DEBUG ("Found twice in trail.\n");
5837 GNUNET_break_op (0);
5838 return;
5839 }
5840 if ((trail_length - 1) == my_index)
5841 {
5842 next_hop = destination_peer;
5843 }
5844 else
5845 {
5846 next_hop = trail[my_index + 1];
5847 }
5848 /* Add in your routing table. */
5849 GNUNET_assert (GNUNET_OK == GDS_ROUTING_add (&trail_id,
5850 friend->id,
5851 &next_hop));
5852 //GNUNET_assert (GNUNET_OK == GDS_ROUTING_add (trail_id, next_hop, *peer));
5853 GNUNET_assert (NULL !=
5854 (target_friend =
5855 GNUNET_CONTAINER_multipeermap_get (friend_peermap,
5856 &next_hop)));
5857 GDS_NEIGHBOURS_send_add_trail (&source_peer,
5858 &destination_peer,
5859 &trail_id,
5860 trail,
5861 trail_length,
5862 target_friend);
5863 return;
5864 }
5865 /* I am the destination. Add an entry in routing table. */
5866 GNUNET_assert (GNUNET_OK == GDS_ROUTING_add (&trail_id,
5867 friend->id,
5868 &my_identity));
5869}
5870
5871
5872/**
5873 * Free the finger trail in which the first friend to reach to a finger is
5874 * disconnected_friend. Also remove entry from routing table for that particular
5875 * trail id.
5876 * @param disconnected_friend PeerIdentity of friend which got disconnected
5877 * @param remove_finger Finger whose trail we need to check if it has
5878 * disconnected_friend as the first hop.
5879 * @return Total number of trails in which disconnected_friend was the first
5880 * hop.
5881 */
5882static int
5883remove_matching_trails (const struct GNUNET_PeerIdentity *disconnected_friend,
5884 struct FingerInfo *finger)
5885{
5886 const struct GNUNET_PeerIdentity *next_hop;
5887 struct FriendInfo *remove_friend;
5888 struct Trail *current_trail;
5889 unsigned int matching_trails_count = 0;
5890 int i;
5891
5892 /* Iterate over all the trails of finger. */
5893 for (i = 0; i < finger->trails_count; i++)
5894 {
5895 current_trail = &finger->trail_list[i];
5896 if (GNUNET_NO == current_trail->is_present)
5897 continue;
5898
5899 /* First friend to reach to finger is disconnected_peer. */
5900 if (0 == GNUNET_CRYPTO_cmp_peer_identity (&current_trail->trail_head->peer,
5901 disconnected_friend))
5902 {
5903 remove_friend =
5904 GNUNET_CONTAINER_multipeermap_get (friend_peermap,
5905 disconnected_friend);
5906 GNUNET_assert (NULL != remove_friend);
5907 next_hop = GDS_ROUTING_get_next_hop (&current_trail->trail_id,
5908 GDS_ROUTING_SRC_TO_DEST);
5909
5910 /* Here it may happen that as all the peers got disconnected, the entry in
5911 routing table for that particular trail has been removed, because the
5912 previously disconnected peer was either a next hop or prev hop of that
5913 peer. */
5914 if (NULL != next_hop)
5915 {
5916 GNUNET_assert (0 == (GNUNET_CRYPTO_cmp_peer_identity (disconnected_friend,
5917 next_hop)));
5918 GNUNET_assert (GNUNET_YES ==
5919 GDS_ROUTING_remove_trail (&current_trail->trail_id));
5920 }
5921 matching_trails_count++;
5922 free_trail (current_trail);
5923 current_trail->is_present = GNUNET_NO;
5924 }
5925 }
5926 return matching_trails_count;
5927}
5928
5929
5930/**
5931 * Iterate over finger_table entries.
5932 * 0. Ignore finger which is my_identity or if no valid entry present at
5933 * that finger index.
5934 * 1. If disconnected_friend is a finger, then remove the routing entry from
5935 your own table. Free the trail.
5936 * 2. Check if disconnected_friend is the first friend in the trail to reach to a finger.
5937 * 2.1 Remove all the trails and entry from routing table in which disconnected
5938 * friend is the first friend in the trail. If disconnected_friend is the
5939 * first friend in all the trails to reach finger, then remove the finger.
5940 * @param disconnected_friend Peer identity of friend which got disconnected.
5941 */
5942static void
5943remove_matching_fingers (const struct GNUNET_PeerIdentity *disconnected_peer)
5944{
5945 struct FingerInfo *current_finger;
5946 int removed_trails_count;
5947 int i;
5948
5949 /* Iterate over finger table entries. */
5950 for (i = 0; i < MAX_FINGERS; i++)
5951 {
5952 current_finger = &finger_table[i];
5953
5954 /* No finger stored at this trail index or I am the finger. */
5955 if ((GNUNET_NO == current_finger->is_present) ||
5956 (0 == GNUNET_CRYPTO_cmp_peer_identity (&current_finger->finger_identity,
5957 &my_identity)))
5958 continue;
5959
5960 /* Is disconnected_peer a finger? */
5961 if (0 == GNUNET_CRYPTO_cmp_peer_identity (disconnected_peer,
5962 &current_finger->finger_identity))
5963 {
5964 remove_existing_finger (current_finger, i);
5965 }
5966
5967 /* If finger is a friend but not disconnected_friend, then continue. */
5968 if (NULL != GNUNET_CONTAINER_multipeermap_get (friend_peermap,
5969 &current_finger->finger_identity))
5970 continue;
5971
5972 /* Iterate over the list of trails to reach remove_finger. Check if
5973 * disconnected_friend is the first friend in any of the trail. */
5974 removed_trails_count = remove_matching_trails (disconnected_peer,
5975 current_finger);
5976 current_finger->trails_count =
5977 current_finger->trails_count - removed_trails_count;
5978 if (0 == current_finger->trails_count)
5979 {
5980 current_finger->is_present = GNUNET_NO;
5981 memset (&finger_table[i],
5982 0,
5983 sizeof (finger_table[i]));
5984 }
5985 }
5986}
5987
5988
5989/**
5990 * Method called whenever a peer disconnects.
5991 *
5992 * @param cls closure
5993 * @param peer peer identity this notification is about
5994 * @param internal_cls our `struct FriendInfo` for @a peer
5995 */
5996static void
5997handle_core_disconnect (void *cls,
5998 const struct GNUNET_PeerIdentity *peer,
5999 void *internal_cls)
6000{
6001 struct FriendInfo *remove_friend = internal_cls;
6002
6003 /* If disconnected to own identity, then return. */
6004 if (NULL == remove_friend)
6005 return;
6006 remove_matching_fingers (peer);
6007 GNUNET_assert (GNUNET_SYSERR !=
6008 GDS_ROUTING_remove_trail_by_peer (peer));
6009 GNUNET_assert (GNUNET_YES ==
6010 GNUNET_CONTAINER_multipeermap_remove (friend_peermap,
6011 peer,
6012 remove_friend));
6013 if (0 != GNUNET_CONTAINER_multipeermap_size (friend_peermap))
6014 return;
6015
6016 if (NULL != find_finger_trail_task)
6017 {
6018 GNUNET_SCHEDULER_cancel (find_finger_trail_task);
6019 find_finger_trail_task = NULL;
6020 }
6021 else
6022 GNUNET_break (0);
6023}
6024
6025
6026/**
6027 * Method called whenever a peer connects.
6028 *
6029 * @param cls closure
6030 * @param peer_identity peer identity this notification is about
6031 * @param mq message queue for sending data to @a peer
6032 * @return our `struct FriendInfo` for this peer
6033 */
6034static void *
6035handle_core_connect (void *cls,
6036 const struct GNUNET_PeerIdentity *peer_identity,
6037 struct GNUNET_MQ_Handle *mq)
6038{
6039 struct FriendInfo *friend;
6040
6041 /* Check for connect to self message */
6042 if (0 == memcmp (&my_identity,
6043 peer_identity,
6044 sizeof (struct GNUNET_PeerIdentity)))
6045 return NULL;
6046 friend = GNUNET_new (struct FriendInfo);
6047 friend->id = peer_identity;
6048 friend->mq = mq;
6049 GNUNET_assert (GNUNET_OK ==
6050 GNUNET_CONTAINER_multipeermap_put (friend_peermap,
6051 friend->id,
6052 friend,
6053 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
6054
6055 /* FIXME: now we are not making a distinction between fingers which are friends
6056 * also.But later, we should add a congestion timestamp on the friend, so that it is
6057 * selected after some time out. This is to ensure that both peers have added
6058 * each other as their friend. */
6059 /* Got a first connection, good time to start with FIND FINGER TRAIL requests...*/
6060 if (NULL == find_finger_trail_task)
6061 {
6062 find_finger_trail_task
6063 = GNUNET_SCHEDULER_add_now (&send_find_finger_trail_message,
6064 NULL);
6065 }
6066 return friend;
6067}
6068
6069
6070/**
6071 * To be called on core init/fail.
6072 *
6073 * @param cls service closure
6074 * @param identity the public identity of this peer
6075 */
6076static void
6077core_init (void *cls,
6078 const struct GNUNET_PeerIdentity *identity)
6079{
6080 my_identity = *identity;
6081}
6082
6083
6084/**
6085 * Initialize finger table entries.
6086 */
6087static void
6088finger_table_init ()
6089{
6090 memset (&finger_table, 0, sizeof (finger_table));
6091}
6092
6093
6094/**
6095 * Initialize neighbours subsystem.
6096 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
6097 */
6098int
6099GDS_NEIGHBOURS_init (void)
6100{
6101 struct GNUNET_MQ_MessageHandler core_handlers[] = {
6102 GNUNET_MQ_hd_var_size (dht_p2p_put,
6103 GNUNET_MESSAGE_TYPE_XDHT_P2P_PUT,
6104 struct PeerPutMessage,
6105 NULL),
6106 GNUNET_MQ_hd_var_size (dht_p2p_get,
6107 GNUNET_MESSAGE_TYPE_XDHT_P2P_GET,
6108 struct PeerGetMessage,
6109 NULL),
6110 GNUNET_MQ_hd_var_size (dht_p2p_get_result,
6111 GNUNET_MESSAGE_TYPE_XDHT_P2P_GET_RESULT,
6112 struct PeerGetResultMessage,
6113 NULL),
6114 GNUNET_MQ_hd_var_size (dht_p2p_trail_setup,
6115 GNUNET_MESSAGE_TYPE_XDHT_P2P_TRAIL_SETUP,
6116 struct PeerTrailSetupMessage,
6117 NULL),
6118 GNUNET_MQ_hd_var_size (dht_p2p_trail_setup_result,
6119 GNUNET_MESSAGE_TYPE_XDHT_P2P_TRAIL_SETUP_RESULT,
6120 struct PeerTrailSetupResultMessage,
6121 NULL),
6122 GNUNET_MQ_hd_var_size (dht_p2p_verify_successor,
6123 GNUNET_MESSAGE_TYPE_XDHT_P2P_VERIFY_SUCCESSOR,
6124 struct PeerVerifySuccessorMessage,
6125 NULL),
6126 GNUNET_MQ_hd_var_size (dht_p2p_verify_successor_result,
6127 GNUNET_MESSAGE_TYPE_XDHT_P2P_VERIFY_SUCCESSOR_RESULT,
6128 struct PeerVerifySuccessorResultMessage,
6129 NULL),
6130 GNUNET_MQ_hd_var_size (dht_p2p_notify_new_successor,
6131 GNUNET_MESSAGE_TYPE_XDHT_P2P_NOTIFY_NEW_SUCCESSOR,
6132 struct PeerNotifyNewSuccessorMessage,
6133 NULL),
6134 GNUNET_MQ_hd_var_size (dht_p2p_trail_setup_rejection,
6135 GNUNET_MESSAGE_TYPE_XDHT_P2P_TRAIL_SETUP_REJECTION,
6136 struct PeerTrailRejectionMessage,
6137 NULL),
6138 GNUNET_MQ_hd_fixed_size (dht_p2p_trail_teardown,
6139 GNUNET_MESSAGE_TYPE_XDHT_P2P_TRAIL_TEARDOWN,
6140 struct PeerTrailTearDownMessage,
6141 NULL),
6142 GNUNET_MQ_hd_var_size (dht_p2p_add_trail,
6143 GNUNET_MESSAGE_TYPE_XDHT_P2P_ADD_TRAIL,
6144 struct PeerAddTrailMessage,
6145 NULL),
6146 GNUNET_MQ_hd_fixed_size (dht_p2p_notify_succ_confirmation,
6147 GNUNET_MESSAGE_TYPE_XDHT_P2P_NOTIFY_SUCCESSOR_CONFIRMATION,
6148 struct PeerNotifyConfirmationMessage,
6149 NULL),
6150 GNUNET_MQ_handler_end ()
6151 };
6152
6153 core_api = GNUNET_CORE_connect (GDS_cfg,
6154 NULL,
6155 &core_init,
6156 &handle_core_connect,
6157 &handle_core_disconnect,
6158 core_handlers);
6159 if (NULL == core_api)
6160 return GNUNET_SYSERR;
6161 friend_peermap = GNUNET_CONTAINER_multipeermap_create (256,
6162 GNUNET_YES);
6163 finger_table_init ();
6164 successor_times = 10;
6165 fingers_round_count = 5;
6166 find_finger_trail_task_next_send_time.rel_value_us =
6167 DHT_FIND_FINGER_TRAIL_INTERVAL.rel_value_us +
6168 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
6169 DHT_FIND_FINGER_TRAIL_INTERVAL.rel_value_us);
6170
6171 verify_successor_next_send_time.rel_value_us =
6172 DHT_SEND_VERIFY_SUCCESSOR_INTERVAL.rel_value_us +
6173 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
6174 DHT_SEND_VERIFY_SUCCESSOR_INTERVAL.rel_value_us);
6175
6176 verify_successor_retry_time.rel_value_us =
6177 DHT_SEND_VERIFY_SUCCESSOR_RETRY_INTERVAL.rel_value_us +
6178 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
6179 DHT_SEND_VERIFY_SUCCESSOR_RETRY_INTERVAL.rel_value_us);
6180
6181 notify_successor_retry_time.rel_value_us =
6182 DHT_SEND_NOTIFY_SUCCESSOR_RETRY_INTERVAL.rel_value_us +
6183 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
6184 DHT_SEND_NOTIFY_SUCCESSOR_RETRY_INTERVAL.rel_value_us);
6185
6186 return GNUNET_OK;
6187}
6188
6189
6190/**
6191 * Free the memory held up by trails of a finger.
6192 */
6193static void
6194delete_finger_table_entries()
6195{
6196 for (unsigned int i = 0; i < MAX_FINGERS; i++)
6197 {
6198 if (GNUNET_YES != finger_table[i].is_present)
6199 continue;
6200 for (unsigned int j = 0; j < finger_table[i].trails_count; j++)
6201 free_trail(&finger_table[i].trail_list[j]);
6202 }
6203}
6204
6205
6206/**
6207 * Shutdown neighbours subsystem.
6208 */
6209void
6210GDS_NEIGHBOURS_done (void)
6211{
6212 if (NULL == core_api)
6213 return;
6214
6215 GNUNET_CORE_disconnect (core_api);
6216 core_api = NULL;
6217
6218 delete_finger_table_entries();
6219 GNUNET_assert (0 == GNUNET_CONTAINER_multipeermap_size (friend_peermap));
6220 GNUNET_CONTAINER_multipeermap_destroy (friend_peermap);
6221 friend_peermap = NULL;
6222
6223 if (NULL != find_finger_trail_task)
6224 {
6225 GNUNET_SCHEDULER_cancel (find_finger_trail_task);
6226 find_finger_trail_task = NULL;
6227 }
6228
6229 if (NULL != send_verify_successor_task)
6230 {
6231 GNUNET_SCHEDULER_cancel (send_verify_successor_task);
6232 send_verify_successor_task = NULL;
6233 }
6234 if (NULL != send_verify_successor_retry_task)
6235 {
6236 struct VerifySuccessorContext *ctx;
6237
6238 ctx = GNUNET_SCHEDULER_cancel (send_verify_successor_retry_task);
6239 GNUNET_free (ctx);
6240 send_verify_successor_retry_task = NULL;
6241 }
6242 if (NULL != send_notify_new_successor_retry_task)
6243 {
6244 struct SendNotifyContext *notify_ctx;
6245
6246 notify_ctx = GNUNET_SCHEDULER_cancel (send_notify_new_successor_retry_task);
6247 GNUNET_free (notify_ctx->successor_trail);
6248 GNUNET_free (notify_ctx);
6249 send_notify_new_successor_retry_task = NULL;
6250 }
6251}
6252
6253
6254/**
6255 * Get my identity
6256 *
6257 * @return my identity
6258 */
6259struct GNUNET_PeerIdentity *
6260GDS_NEIGHBOURS_get_id (void)
6261{
6262 return &my_identity;
6263}
6264
6265/* end of gnunet-service-xdht_neighbours.c */
diff --git a/src/dht/gnunet-service-xdht_neighbours.h b/src/dht/gnunet-service-xdht_neighbours.h
deleted file mode 100644
index 2fb118448..000000000
--- a/src/dht/gnunet-service-xdht_neighbours.h
+++ /dev/null
@@ -1,47 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010, 2011 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
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 dht/gnunet-service-xdht_neighbours.h
23 * @brief GNUnet DHT routing code
24 * @author Supriti Singh
25 */
26
27#ifndef GNUNET_SERVICE_XDHT_NEIGHBOURS_H
28#define GNUNET_SERVICE_XDHT_NEIGHBOURS_H
29
30#include "gnunet_util_lib.h"
31#include "gnunet_block_lib.h"
32#include "gnunet_dht_service.h"
33
34
35/**
36 * Construct a trail teardown message and forward it to target friend.
37 * @param trail_id Unique identifier of the trail.
38 * @param trail_direction Direction of trail.
39 * @param target_friend Friend to get this message.
40 */
41void
42GDS_NEIGHBOURS_send_trail_teardown (const struct GNUNET_HashCode *trail_id,
43 unsigned int trail_direction,
44 const struct GNUNET_PeerIdentity *peer);
45
46
47#endif
diff --git a/src/dht/gnunet-service-xdht_routing.c b/src/dht/gnunet-service-xdht_routing.c
deleted file mode 100644
index ec7361579..000000000
--- a/src/dht/gnunet-service-xdht_routing.c
+++ /dev/null
@@ -1,368 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011 - 2014 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 dht/gnunet-service-xdht_routing.c
23 * @brief GNUnet DHT tracking of requests for routing replies
24 * @author Supriti Singh
25 */
26#include "platform.h"
27#include "gnunet-service-dht_neighbours.h"
28#include "gnunet-service-xdht_neighbours.h"
29#include "gnunet-service-xdht_routing.h"
30#include "gnunet-service-dht.h"
31
32
33/**
34 * FIXME: Check if its better to store pointer to friend rather than storing
35 * peer identity next_hop or prev_hop.
36 * keep entries in destnation and source peer also. so when we send the trail
37 * teardown message then we don't know the source but if source gets the message
38 * then it shold remove that trail id from its finger table. But how does
39 * source know what is the desination finger ? It will whenevr contact a trail
40 * will do a lookup in routing table and if no trail id present the remove
41 * that trail of the finger and if only one trail then remove the finger.
42 * because of this use case of trail teardown I think trail compression
43 * and trail teardown should not be merged.
44 * 2. store a pointer to friendInfo in place o peer identity.
45 */
46/**
47 * Maximum number of entries in routing table.
48 */
49#define ROUTING_TABLE_THRESHOLD 80000
50
51/**
52 * FIXME: Store friend pointer instead of peer identifier.
53 * Routing table entry .
54 */
55struct RoutingTrail
56{
57 /**
58 * Global Unique identifier of the trail.
59 */
60 struct GNUNET_HashCode trail_id;
61
62 /**
63 * The peer to which this request should be passed to.
64 */
65 struct GNUNET_PeerIdentity next_hop;
66
67 /**
68 * Peer just before next hop in the trail.
69 */
70 struct GNUNET_PeerIdentity prev_hop;
71};
72
73/**
74 * Routing table of the peer
75 */
76static struct GNUNET_CONTAINER_MultiHashMap *routing_table;
77
78/**
79 * Update the prev. hop of the trail. Call made by trail compression where
80 * if you are the first friend now in the trail then you need to update
81 * your prev. hop.
82 * @param trail_id
83 * @return #GNUNET_OK success
84 * #GNUNET_SYSERR in case no matching entry found in routing table.
85 */
86int
87GDS_ROUTING_update_trail_prev_hop (const struct GNUNET_HashCode *trail_id,
88 const struct GNUNET_PeerIdentity *prev_hop)
89{
90 struct RoutingTrail *trail;
91
92 trail = GNUNET_CONTAINER_multihashmap_get (routing_table,
93 trail_id);
94
95 if (NULL == trail)
96 return GNUNET_SYSERR;
97 trail->prev_hop = *prev_hop;
98 return GNUNET_OK;
99}
100
101
102/**
103 * Update the next hop of the trail. Call made by trail compression where
104 * if you are source of the trail and now you have a new first friend, then
105 * you should update the trail.
106 * @param trail_id
107 * @return #GNUNET_OK success
108 * #GNUNET_SYSERR in case no matching entry found in routing table.
109 */
110int
111GDS_ROUTING_update_trail_next_hop (const struct GNUNET_HashCode *trail_id,
112 const struct GNUNET_PeerIdentity *next_hop)
113{
114 struct RoutingTrail *trail;
115
116 trail = GNUNET_CONTAINER_multihashmap_get (routing_table,
117 trail_id);
118 if (NULL == trail)
119 return GNUNET_SYSERR;
120 trail->next_hop = *next_hop;
121 return GNUNET_OK;
122}
123
124
125/**
126 * Get the next hop for trail corresponding to trail_id
127 *
128 * @param trail_id Trail id to be searched.
129 * @return Next_hop if found
130 * NULL If next hop not found.
131 */
132const struct GNUNET_PeerIdentity *
133GDS_ROUTING_get_next_hop (const struct GNUNET_HashCode *trail_id,
134 enum GDS_ROUTING_trail_direction trail_direction)
135{
136 struct RoutingTrail *trail;
137
138 trail = GNUNET_CONTAINER_multihashmap_get (routing_table,
139 trail_id);
140 if (NULL == trail)
141 {
142 /* If a friend got disconnected and we removed all the entry from the
143 routing table, then trail will be deleted and my identity will not know
144 and when it tries to reach to that finger it fails. thats why
145 assertion always fails in*/
146 return NULL;
147 }
148 switch (trail_direction)
149 {
150 case GDS_ROUTING_SRC_TO_DEST:
151 return &trail->next_hop;
152 case GDS_ROUTING_DEST_TO_SRC:
153 return &trail->prev_hop;
154 }
155 return NULL;
156}
157
158
159/**
160 * Remove trail with trail_id
161 * @param trail_id Trail id to be removed
162 * @return #GNUNET_YES success
163 * #GNUNET_NO if entry not found.
164 */
165int
166GDS_ROUTING_remove_trail (const struct GNUNET_HashCode *remove_trail_id)
167{
168 struct RoutingTrail *remove_entry;
169
170 remove_entry = GNUNET_CONTAINER_multihashmap_get (routing_table,
171 remove_trail_id);
172 if (NULL == remove_entry)
173 return GNUNET_NO;
174
175 if (GNUNET_YES ==
176 GNUNET_CONTAINER_multihashmap_remove (routing_table,
177 remove_trail_id,
178 remove_entry))
179 {
180 GNUNET_free (remove_entry);
181 return GNUNET_YES;
182 }
183 return GNUNET_NO;
184}
185
186
187/**
188 * Iterate over routing table and remove entries with value as part of any trail.
189 *
190 * @param cls closure
191 * @param key current public key
192 * @param value value in the hash map
193 * @return #GNUNET_YES if we should continue to iterate,
194 * #GNUNET_NO if not.
195 */
196static int
197remove_matching_trails (void *cls,
198 const struct GNUNET_HashCode *key,
199 void *value)
200{
201 struct RoutingTrail *remove_trail = value;
202 struct GNUNET_PeerIdentity *disconnected_peer = cls;
203 struct GNUNET_HashCode trail_id = *key;
204 struct GNUNET_PeerIdentity my_identity;
205
206 /* If disconnected_peer is next_hop, then send a trail teardown message through
207 * prev_hop in direction from destination to source. */
208 if (0 == GNUNET_CRYPTO_cmp_peer_identity (&remove_trail->next_hop,
209 disconnected_peer))
210 {
211 my_identity = *GDS_NEIGHBOURS_get_id ();
212 if (0 != GNUNET_CRYPTO_cmp_peer_identity (&my_identity,
213 &remove_trail->prev_hop))
214 {
215 GDS_NEIGHBOURS_send_trail_teardown (&trail_id,
216 GDS_ROUTING_DEST_TO_SRC,
217 &remove_trail->prev_hop);
218 }
219 }
220
221 /* If disconnected_peer is prev_hop, then send a trail teardown through
222 * next_hop in direction from Source to Destination. */
223 if (0 == GNUNET_CRYPTO_cmp_peer_identity (&remove_trail->prev_hop,
224 disconnected_peer))
225 {
226 my_identity = *GDS_NEIGHBOURS_get_id ();
227
228 if (0 != GNUNET_CRYPTO_cmp_peer_identity (&my_identity,
229 &remove_trail->next_hop))
230 {
231 GDS_NEIGHBOURS_send_trail_teardown (&trail_id,
232 GDS_ROUTING_SRC_TO_DEST,
233 &remove_trail->next_hop);
234 }
235 }
236
237 GNUNET_assert (GNUNET_YES ==
238 GNUNET_CONTAINER_multihashmap_remove (routing_table,
239 &trail_id,
240 remove_trail));
241 GNUNET_free (remove_trail);
242 return GNUNET_YES;
243}
244
245#if 0
246/**
247 * TEST FUNCTION
248 * Remove after using.
249 */
250void
251GDS_ROUTING_test_print (void)
252{
253 struct GNUNET_CONTAINER_MultiHashMapIterator *iter;
254 struct RoutingTrail *trail;
255 struct GNUNET_PeerIdentity print_peer;
256 struct GNUNET_HashCode key_ret;
257 int i;
258
259 struct GNUNET_PeerIdentity my_identity = *GDS_NEIGHBOURS_get_id();
260 print_peer = my_identity;
261 FPRINTF (stderr,_("\nSUPU ***PRINTING ROUTING TABLE ***** of =%s"),GNUNET_i2s(&print_peer));
262 iter =GNUNET_CONTAINER_multihashmap_iterator_create (routing_table);
263 for (i = 0; i < GNUNET_CONTAINER_multihashmap_size(routing_table); i++)
264 {
265 if(GNUNET_YES == GNUNET_CONTAINER_multihashmap_iterator_next (iter,
266 &key_ret,
267 (const void **)&trail))
268 {
269 FPRINTF (stderr,_("\nSUPU %s, %s, %d, trail->trail_id = %s"),
270 __FILE__, __func__,__LINE__, GNUNET_h2s(&trail->trail_id));
271 GNUNET_memcpy (&print_peer, &trail->next_hop, sizeof (struct GNUNET_PeerIdentity));
272 FPRINTF (stderr,_("\nSUPU %s, %s, %d, trail->next_hop = %s"),
273 __FILE__, __func__,__LINE__, GNUNET_i2s(&print_peer));
274 GNUNET_memcpy (&print_peer, &trail->prev_hop, sizeof (struct GNUNET_PeerIdentity));
275 FPRINTF (stderr,_("\nSUPU %s, %s, %d, trail->prev_hop = %s"),
276 __FILE__, __func__,__LINE__, GNUNET_i2s(&print_peer));
277 }
278 }
279}
280#endif
281
282/**
283 * Remove every trail where peer is either next_hop or prev_hop. Also send a
284 * trail teardown message in direction of hop which is not disconnected.
285 * @param peer Peer identity. Trail containing this peer should be removed.
286 */
287int
288GDS_ROUTING_remove_trail_by_peer (const struct GNUNET_PeerIdentity *peer)
289{
290 int ret;
291
292
293 /* No entries in my routing table. */
294 if (0 == GNUNET_CONTAINER_multihashmap_size(routing_table))
295 return GNUNET_YES;
296
297 ret = GNUNET_CONTAINER_multihashmap_iterate (routing_table,
298 &remove_matching_trails,
299 (void *)peer);
300 return ret;
301}
302
303
304/**
305 * Add a new entry in routing table
306 * @param new_trail_id
307 * @param prev_hop
308 * @param next_hop
309 * @return #GNUNET_OK success
310 * #GNUNET_SYSERR in case new_trail_id already exists in the network
311 * but with different prev_hop/next_hop
312 */
313int
314GDS_ROUTING_add (const struct GNUNET_HashCode *new_trail_id,
315 const struct GNUNET_PeerIdentity *prev_hop,
316 const struct GNUNET_PeerIdentity *next_hop)
317{
318 struct RoutingTrail *new_entry;
319
320 new_entry = GNUNET_new (struct RoutingTrail);
321 new_entry->trail_id = *new_trail_id;
322 new_entry->next_hop = *next_hop;
323 new_entry->prev_hop = *prev_hop;
324
325 // FIXME: this leaks memory if the put fails!
326 return GNUNET_CONTAINER_multihashmap_put (routing_table,
327 &new_entry->trail_id,
328 new_entry,
329 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
330}
331
332
333/**
334 * Check if the size of routing table has crossed ROUTING_TABLE_THRESHOLD.
335 * It means that I don't have any more space in my routing table and I can not
336 * be part of any more trails till there is free space in my routing table.
337 * @return #GNUNET_YES, if threshold crossed else #GNUNET_NO.
338 */
339int
340GDS_ROUTING_threshold_reached (void)
341{
342 return (GNUNET_CONTAINER_multihashmap_size(routing_table) >
343 ROUTING_TABLE_THRESHOLD) ? GNUNET_YES:GNUNET_NO;
344}
345
346
347/**
348 * Initialize routing subsystem.
349 */
350void
351GDS_ROUTING_init (void)
352{
353 routing_table = GNUNET_CONTAINER_multihashmap_create (ROUTING_TABLE_THRESHOLD * 4 / 3,
354 GNUNET_NO);
355}
356
357
358/**
359 * Shutdown routing subsystem.
360 */
361void
362GDS_ROUTING_done (void)
363{
364 GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap_size (routing_table));
365 GNUNET_CONTAINER_multihashmap_destroy (routing_table);
366}
367
368/* end of gnunet-service-xdht_routing.c */
diff --git a/src/dht/gnunet-service-xdht_routing.h b/src/dht/gnunet-service-xdht_routing.h
deleted file mode 100644
index 69ab1ff78..000000000
--- a/src/dht/gnunet-service-xdht_routing.h
+++ /dev/null
@@ -1,141 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011 - 2014 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 dht/gnunet-service-xdht_routing.h
23 * @brief GNUnet DHT tracking of requests for routing replies
24 * @author Christian Grothoff
25 */
26#ifndef GNUNET_SERVICE_XDHT_ROUTING_H
27#define GNUNET_SERVICE_XDHT_ROUTING_H
28
29#include "gnunet_util_lib.h"
30#include "gnunet_block_lib.h"
31#include "gnunet_dht_service.h"
32
33/**
34 * To understand the direction in which trial should be read.
35 */
36enum GDS_ROUTING_trail_direction
37{
38 GDS_ROUTING_SRC_TO_DEST,
39 GDS_ROUTING_DEST_TO_SRC
40};
41
42
43/**
44 * Update the prev. hop of the trail. Call made by trail teardown where
45 * if you are the first friend now in the trail then you need to update
46 * your prev. hop.
47 * @param trail_id
48 * @return #GNUNET_OK success
49 * #GNUNET_SYSERR in case no matching entry found in routing table.
50 */
51int
52GDS_ROUTING_update_trail_prev_hop (const struct GNUNET_HashCode *trail_id,
53 const struct GNUNET_PeerIdentity *prev_hop);
54
55
56/**
57 * Update the next hop of the trail. Call made by trail compression where
58 * if you are source of the trail and now you have a new first friend, then
59 * you should update the trail.
60 * @param trail_id
61 * @return #GNUNET_OK success
62 * #GNUNET_SYSERR in case no matching entry found in routing table.
63 */
64int
65GDS_ROUTING_update_trail_next_hop (const struct GNUNET_HashCode *trail_id,
66 const struct GNUNET_PeerIdentity *next_hop);
67
68/**
69 * Get the next hop for trail corresponding to trail_id
70 * @param trail_id Trail id to be searched.
71 * @return Next_hop if found
72 * NULL If next hop not found.
73 */
74const struct GNUNET_PeerIdentity *
75GDS_ROUTING_get_next_hop (const struct GNUNET_HashCode *trail_id,
76 enum GDS_ROUTING_trail_direction trail_direction);
77
78
79/**
80 * Remove every trail where peer is either next_hop or prev_hop
81 * @param peer Peer to be searched.
82 */
83int
84GDS_ROUTING_remove_trail_by_peer (const struct GNUNET_PeerIdentity *peer);
85
86
87/**
88 * Remove trail with trail_id
89 *
90 * @param trail_id Trail id to be removed
91 * @return #GNUNET_YES success
92 * #GNUNET_NO if entry not found.
93 */
94int
95GDS_ROUTING_remove_trail (const struct GNUNET_HashCode *remove_trail_id);
96
97
98/**
99 * Add a new entry in routing table
100 * @param new_trail_id
101 * @param prev_hop
102 * @param next_hop
103 * @return #GNUNET_OK success
104 * #GNUNET_SYSERR in case new_trail_id already exists in the network
105 * but with different prev_hop/next_hop
106 */
107int
108GDS_ROUTING_add (const struct GNUNET_HashCode *new_trail_id,
109 const struct GNUNET_PeerIdentity *prev_hop,
110 const struct GNUNET_PeerIdentity *next_hop);
111
112
113/**
114 * Check if the size of routing table has crossed threshold.
115 * @return #GNUNET_YES, if threshold crossed
116 * #GNUNET_NO, if size is within threshold
117 */
118int
119GDS_ROUTING_threshold_reached (void);
120
121#if 0
122/**
123 * Test function. Remove afterwards.
124 */
125void
126GDS_ROUTING_test_print (void);
127#endif
128
129/**
130 * Initialize routing subsystem.
131 */
132void
133GDS_ROUTING_init (void);
134
135/**
136 * Shutdown routing subsystem.
137 */
138void
139GDS_ROUTING_done (void);
140
141#endif
diff --git a/src/dht/gnunet_dht_profiler.c b/src/dht/gnunet_dht_profiler.c
index 460eaa572..a8807bea8 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_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_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_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_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_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_uint ('r',
1221 "replication",
1222 "DEGREE",
1223 gettext_noop ("replication degree for DHT PUTs"),
1224 &replication),
1225
1226
1227 GNUNET_GETOPT_option_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/dht/plugin_block_dht.c b/src/dht/plugin_block_dht.c
index 8bb533961..24f8b21b2 100644
--- a/src/dht/plugin_block_dht.c
+++ b/src/dht/plugin_block_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) 2010 GNUnet e.V. 3 Copyright (C) 2010, 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,25 +25,78 @@
25 * DHT (see fs block plugin) 25 * DHT (see fs block plugin)
26 * @author Christian Grothoff 26 * @author Christian Grothoff
27 */ 27 */
28
29#include "platform.h" 28#include "platform.h"
30#include "gnunet_constants.h" 29#include "gnunet_constants.h"
31#include "gnunet_hello_lib.h" 30#include "gnunet_hello_lib.h"
32#include "gnunet_block_plugin.h" 31#include "gnunet_block_plugin.h"
32#include "gnunet_block_group_lib.h"
33 33
34#define DEBUG_DHT GNUNET_EXTRA_LOGGING 34#define DEBUG_DHT GNUNET_EXTRA_LOGGING
35 35
36/**
37 * Number of bits we set per entry in the bloomfilter.
38 * Do not change!
39 */
40#define BLOOMFILTER_K 16
41
42
43/**
44 * Create a new block group.
45 *
46 * @param ctx block context in which the block group is created
47 * @param type type of the block for which we are creating the group
48 * @param nonce random value used to seed the group creation
49 * @param raw_data optional serialized prior state of the group, NULL if unavailable/fresh
50 * @param raw_data_size number of bytes in @a raw_data, 0 if unavailable/fresh
51 * @param va variable arguments specific to @a type
52 * @return block group handle, NULL if block groups are not supported
53 * by this @a type of block (this is not an error)
54 */
55static struct GNUNET_BLOCK_Group *
56block_plugin_dht_create_group (void *cls,
57 enum GNUNET_BLOCK_Type type,
58 uint32_t nonce,
59 const void *raw_data,
60 size_t raw_data_size,
61 va_list va)
62{
63 unsigned int bf_size;
64 const char *guard;
65
66 guard = va_arg (va, const char *);
67 if (0 == strcmp (guard,
68 "seen-set-size"))
69 bf_size = GNUNET_BLOCK_GROUP_compute_bloomfilter_size (va_arg (va, unsigned int),
70 BLOOMFILTER_K);
71 else if (0 == strcmp (guard,
72 "filter-size"))
73 bf_size = va_arg (va, unsigned int);
74 else
75 {
76 GNUNET_break (0);
77 bf_size = 8;
78 }
79 GNUNET_break (NULL == va_arg (va, const char *));
80 return GNUNET_BLOCK_GROUP_bf_create (cls,
81 bf_size,
82 BLOOMFILTER_K,
83 type,
84 nonce,
85 raw_data,
86 raw_data_size);
87}
88
36 89
37/** 90/**
38 * Function called to validate a reply or a request. For 91 * Function called to validate a reply or a request. For
39 * request evaluation, simply pass "NULL" for the @a reply_block. 92 * request evaluation, simply pass "NULL" for the @a reply_block.
40 * 93 *
41 * @param cls closure 94 * @param cls closure
95 * @param ctx context
42 * @param type block type 96 * @param type block type
97 * @param group block group to check against
43 * @param eo control flags 98 * @param eo control flags
44 * @param query original query (hash) 99 * @param query original query (hash)
45 * @param bf pointer to bloom filter associated with query; possibly updated (!)
46 * @param bf_mutator mutation value for @a bf
47 * @param xquery extended query data (can be NULL, depending on type) 100 * @param xquery extended query data (can be NULL, depending on type)
48 * @param xquery_size number of bytes in @a xquery 101 * @param xquery_size number of bytes in @a xquery
49 * @param reply_block response to validate 102 * @param reply_block response to validate
@@ -52,17 +105,16 @@
52 */ 105 */
53static enum GNUNET_BLOCK_EvaluationResult 106static enum GNUNET_BLOCK_EvaluationResult
54block_plugin_dht_evaluate (void *cls, 107block_plugin_dht_evaluate (void *cls,
108 struct GNUNET_BLOCK_Context *ctx,
55 enum GNUNET_BLOCK_Type type, 109 enum GNUNET_BLOCK_Type type,
110 struct GNUNET_BLOCK_Group *group,
56 enum GNUNET_BLOCK_EvaluationOptions eo, 111 enum GNUNET_BLOCK_EvaluationOptions eo,
57 const struct GNUNET_HashCode *query, 112 const struct GNUNET_HashCode *query,
58 struct GNUNET_CONTAINER_BloomFilter **bf,
59 int32_t bf_mutator,
60 const void *xquery, 113 const void *xquery,
61 size_t xquery_size, 114 size_t xquery_size,
62 const void *reply_block, 115 const void *reply_block,
63 size_t reply_block_size) 116 size_t reply_block_size)
64{ 117{
65 struct GNUNET_HashCode mhash;
66 const struct GNUNET_HELLO_Message *hello; 118 const struct GNUNET_HELLO_Message *hello;
67 struct GNUNET_PeerIdentity pid; 119 struct GNUNET_PeerIdentity pid;
68 const struct GNUNET_MessageHeader *msg; 120 const struct GNUNET_MessageHeader *msg;
@@ -75,8 +127,7 @@ block_plugin_dht_evaluate (void *cls,
75 GNUNET_break_op (0); 127 GNUNET_break_op (0);
76 return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID; 128 return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID;
77 } 129 }
78 if ( (NULL == reply_block) || 130 if (NULL == reply_block)
79 (0 == reply_block_size) )
80 return GNUNET_BLOCK_EVALUATION_REQUEST_VALID; 131 return GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
81 if (reply_block_size < sizeof (struct GNUNET_MessageHeader)) 132 if (reply_block_size < sizeof (struct GNUNET_MessageHeader))
82 { 133 {
@@ -95,22 +146,13 @@ block_plugin_dht_evaluate (void *cls,
95 GNUNET_break_op (0); 146 GNUNET_break_op (0);
96 return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; 147 return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
97 } 148 }
98 if (NULL != bf) 149 GNUNET_CRYPTO_hash (&pid,
99 { 150 sizeof (pid),
100 GNUNET_CRYPTO_hash (&pid, sizeof (pid), &phash); 151 &phash);
101 GNUNET_BLOCK_mingle_hash (&phash, bf_mutator, &mhash); 152 if (GNUNET_YES ==
102 if (NULL != *bf) 153 GNUNET_BLOCK_GROUP_bf_test_and_set (group,
103 { 154 &phash))
104 if (GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test (*bf, &mhash)) 155 return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
105 return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
106 }
107 else
108 {
109 *bf = GNUNET_CONTAINER_bloomfilter_init (NULL, 8,
110 GNUNET_CONSTANTS_BLOOMFILTER_K);
111 }
112 GNUNET_CONTAINER_bloomfilter_add (*bf, &mhash);
113 }
114 return GNUNET_BLOCK_EVALUATION_OK_MORE; 156 return GNUNET_BLOCK_EVALUATION_OK_MORE;
115} 157}
116 158
@@ -183,6 +225,7 @@ libgnunet_plugin_block_dht_init (void *cls)
183 api = GNUNET_new (struct GNUNET_BLOCK_PluginFunctions); 225 api = GNUNET_new (struct GNUNET_BLOCK_PluginFunctions);
184 api->evaluate = &block_plugin_dht_evaluate; 226 api->evaluate = &block_plugin_dht_evaluate;
185 api->get_key = &block_plugin_dht_get_key; 227 api->get_key = &block_plugin_dht_get_key;
228 api->create_group = &block_plugin_dht_create_group;
186 api->types = types; 229 api->types = types;
187 return api; 230 return api;
188} 231}
@@ -194,7 +237,7 @@ libgnunet_plugin_block_dht_init (void *cls)
194void * 237void *
195libgnunet_plugin_block_dht_done (void *cls) 238libgnunet_plugin_block_dht_done (void *cls)
196{ 239{
197 struct GNUNET_TRANSPORT_PluginFunctions *api = cls; 240 struct GNUNET_BLOCK_PluginFunctions *api = cls;
198 241
199 GNUNET_free (api); 242 GNUNET_free (api);
200 return NULL; 243 return NULL;
diff --git a/src/dht/test_dht_api.c b/src/dht/test_dht_api.c
index 99f17699c..8f4e0ed31 100644
--- a/src/dht/test_dht_api.c
+++ b/src/dht/test_dht_api.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, 2015 GNUnet e.V. 3 Copyright (C) 2009, 2015, 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
@@ -20,6 +20,7 @@
20/** 20/**
21 * @file dht/test_dht_api.c 21 * @file dht/test_dht_api.c
22 * @brief base test case for dht api 22 * @brief base test case for dht api
23 * @author Christian Grothoff
23 * 24 *
24 * This test case tests DHT api to DUMMY DHT service communication. 25 * This test case tests DHT api to DUMMY DHT service communication.
25 */ 26 */
@@ -33,116 +34,70 @@
33/** 34/**
34 * How long until we really give up on a particular testcase portion? 35 * How long until we really give up on a particular testcase portion?
35 */ 36 */
36#define TOTAL_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 600) 37#define TOTAL_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
37
38/**
39 * How long until we give up on any particular operation (and retry)?
40 */
41#define BASE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 3)
42
43#define MTYPE 12345
44
45
46struct RetryContext
47{
48 /**
49 * When to really abort the operation.
50 */
51 struct GNUNET_TIME_Absolute real_timeout;
52
53 /**
54 * What timeout to set for the current attempt (increases)
55 */
56 struct GNUNET_TIME_Relative next_timeout;
57
58 /**
59 * The task identifier of the retry task, so it can be cancelled.
60 */
61 struct GNUNET_SCHEDULER_Task * retry_task;
62
63};
64
65 38
66static struct GNUNET_DHT_Handle *dht_handle; 39static struct GNUNET_DHT_Handle *dht_handle;
67 40
68static struct GNUNET_DHT_GetHandle *get_handle; 41static struct GNUNET_DHT_GetHandle *get_handle;
69 42
70struct RetryContext retry_context; 43static struct GNUNET_DHT_PutHandle *put_handle;
71 44
72static int ok = 1; 45static int ok = 1;
73 46
74static struct GNUNET_SCHEDULER_Task * die_task; 47static struct GNUNET_SCHEDULER_Task *die_task;
75
76
77#if VERBOSE
78#define OKPP do { ok++; FPRINTF (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0)
79#else
80#define OKPP do { ok++; } while (0)
81#endif
82 48
83 49
84static void 50static void
85end (void *cls) 51do_shutdown (void *cls)
86{ 52{
87 GNUNET_SCHEDULER_cancel (die_task); 53 if (NULL != die_task)
88 die_task = NULL; 54 {
89 GNUNET_DHT_disconnect (dht_handle); 55 GNUNET_SCHEDULER_cancel (die_task);
90 dht_handle = NULL; 56 die_task = NULL;
91 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 57 }
92 "DHT disconnected, returning success!\n"); 58 if (NULL != put_handle)
93 ok = 0; 59 {
94} 60 GNUNET_DHT_put_cancel (put_handle);
95 61 put_handle = NULL;
96 62 }
97static void 63 if (NULL != get_handle)
98end_badly ()
99{
100 /* do work here */
101 FPRINTF (stderr, "%s", "Ending on an unhappy note.\n");
102 if (get_handle != NULL)
103 { 64 {
104 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping get request!\n");
105 GNUNET_DHT_get_stop (get_handle); 65 GNUNET_DHT_get_stop (get_handle);
66 get_handle = NULL;
106 } 67 }
107 if (retry_context.retry_task != NULL)
108 GNUNET_SCHEDULER_cancel (retry_context.retry_task);
109 GNUNET_DHT_disconnect (dht_handle); 68 GNUNET_DHT_disconnect (dht_handle);
110 dht_handle = NULL; 69 dht_handle = NULL;
111 ok = 1;
112} 70}
113 71
114 72
115/**
116 * Signature of the main function of a task.
117 *
118 * @param cls closure
119 */
120static void 73static void
121test_get_stop (void *cls) 74end_badly (void *cls)
122{ 75{
123 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 76 die_task = NULL;
124 "Called test_get_stop!\n"); 77 FPRINTF (stderr,
125 GNUNET_assert (NULL != dht_handle); 78 "%s",
126 GNUNET_DHT_get_stop (get_handle); 79 "Ending on an unhappy note.\n");
127 get_handle = NULL; 80 GNUNET_SCHEDULER_shutdown ();
128 GNUNET_SCHEDULER_add_now (&end, NULL); 81 ok = 1;
129} 82}
130 83
131 84
132static void 85static void
133test_get_iterator (void *cls, struct GNUNET_TIME_Absolute exp, 86test_get_iterator (void *cls,
134 const struct GNUNET_HashCode * key, 87 struct GNUNET_TIME_Absolute exp,
88 const struct GNUNET_HashCode *key,
135 const struct GNUNET_PeerIdentity *get_path, 89 const struct GNUNET_PeerIdentity *get_path,
136 unsigned int get_path_length, 90 unsigned int get_path_length,
137 const struct GNUNET_PeerIdentity *put_path, 91 const struct GNUNET_PeerIdentity *put_path,
138 unsigned int put_path_length, 92 unsigned int put_path_length,
139 enum GNUNET_BLOCK_Type type, 93 enum GNUNET_BLOCK_Type type,
140 size_t size, const void *data) 94 size_t size,
95 const void *data)
141{ 96{
142 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 97 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
143 "test_get_iterator called (we got a result), stopping get request!\n"); 98 "test_get_iterator called (we got a result), stopping get request!\n");
144 GNUNET_SCHEDULER_add_now (&test_get_stop, 99 GNUNET_SCHEDULER_shutdown ();
145 NULL); 100 ok = 0;
146} 101}
147 102
148 103
@@ -153,31 +108,33 @@ test_get_iterator (void *cls, struct GNUNET_TIME_Absolute exp,
153 * @param success result of PUT 108 * @param success result of PUT
154 */ 109 */
155static void 110static void
156test_get (void *cls, int success) 111test_get (void *cls,
112 int success)
157{ 113{
158 struct GNUNET_HashCode hash; 114 struct GNUNET_HashCode hash;
159 115
116 put_handle = NULL;
160 memset (&hash, 117 memset (&hash,
161 42, 118 42,
162 sizeof (struct GNUNET_HashCode)); 119 sizeof (struct GNUNET_HashCode));
163
164 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 120 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
165 "Called test_get!\n"); 121 "Called test_get!\n");
166 GNUNET_assert (dht_handle != NULL); 122 GNUNET_assert (dht_handle != NULL);
167 retry_context.real_timeout = GNUNET_TIME_relative_to_absolute (TOTAL_TIMEOUT); 123 get_handle = GNUNET_DHT_get_start (dht_handle,
168 retry_context.next_timeout = BASE_TIMEOUT; 124 GNUNET_BLOCK_TYPE_TEST,
169 125 &hash,
170 get_handle = 126 1,
171 GNUNET_DHT_get_start (dht_handle, 127 GNUNET_DHT_RO_NONE,
172 GNUNET_BLOCK_TYPE_TEST, &hash, 1, 128 NULL,
173 GNUNET_DHT_RO_NONE, NULL, 0, &test_get_iterator, 129 0,
174 NULL); 130 &test_get_iterator,
175 131 NULL);
176 if (get_handle == NULL) 132
133 if (NULL == get_handle)
177 { 134 {
178 GNUNET_break (0); 135 GNUNET_break (0);
179 GNUNET_SCHEDULER_cancel (die_task); 136 ok = 1;
180 die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); 137 GNUNET_SCHEDULER_shutdown ();
181 return; 138 return;
182 } 139 }
183} 140}
@@ -193,29 +150,38 @@ run (void *cls,
193 size_t data_size = 42; 150 size_t data_size = 42;
194 151
195 GNUNET_assert (ok == 1); 152 GNUNET_assert (ok == 1);
196 OKPP; 153 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
197 die_task = 154 NULL);
198 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply 155 die_task = GNUNET_SCHEDULER_add_delayed (TOTAL_TIMEOUT,
199 (GNUNET_TIME_UNIT_MINUTES, 1), &end_badly, 156 &end_badly,
200 NULL); 157 NULL);
201 158 memset (&hash,
202 159 42,
203 memset (&hash, 42, sizeof (struct GNUNET_HashCode)); 160 sizeof (struct GNUNET_HashCode));
204 data = GNUNET_malloc (data_size); 161 data = GNUNET_malloc (data_size);
205 memset (data, 43, data_size); 162 memset (data, 43, data_size);
206 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Called test_put!\n"); 163 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
207 dht_handle = GNUNET_DHT_connect (cfg, 100); 164 "Called test_put!\n");
208 GNUNET_assert (dht_handle != NULL); 165 dht_handle = GNUNET_DHT_connect (cfg,
209 GNUNET_DHT_put (dht_handle, &hash, 1, GNUNET_DHT_RO_NONE, 166 100);
210 GNUNET_BLOCK_TYPE_TEST, data_size, data, 167 GNUNET_assert (NULL != dht_handle);
211 GNUNET_TIME_relative_to_absolute (TOTAL_TIMEOUT), 168 put_handle = GNUNET_DHT_put (dht_handle,
212 &test_get, NULL); 169 &hash,
170 1,
171 GNUNET_DHT_RO_NONE,
172 GNUNET_BLOCK_TYPE_TEST,
173 data_size,
174 data,
175 GNUNET_TIME_relative_to_absolute (TOTAL_TIMEOUT),
176 &test_get,
177 NULL);
213 GNUNET_free (data); 178 GNUNET_free (data);
214} 179}
215 180
216 181
217int 182int
218main (int argc, char *argv[]) 183main (int argc,
184 char *argv[])
219{ 185{
220 if (0 != GNUNET_TESTING_peer_run ("test-dht-api", 186 if (0 != GNUNET_TESTING_peer_run ("test-dht-api",
221 "test_dht_api_data.conf", 187 "test_dht_api_data.conf",
diff --git a/src/dht/test_dht_monitor.c b/src/dht/test_dht_monitor.c
index 5e6fc074a..3de800144 100644
--- a/src/dht/test_dht_monitor.c
+++ b/src/dht/test_dht_monitor.c
@@ -90,7 +90,7 @@ static unsigned int NUM_PEERS = 3;
90/** 90/**
91 * Task called to disconnect peers. 91 * Task called to disconnect peers.
92 */ 92 */
93static struct GNUNET_SCHEDULER_Task * timeout_task; 93static struct GNUNET_SCHEDULER_Task *timeout_task;
94 94
95/** 95/**
96 * Task to do DHT_puts 96 * Task to do DHT_puts
@@ -107,7 +107,7 @@ static unsigned int monitor_counter;
107 * Terminates active get operations and shuts down 107 * Terminates active get operations and shuts down
108 * the testbed. 108 * the testbed.
109 * 109 *
110 * @param cls the 'struct GNUNET_DHT_TestContext' 110 * @param cls the `struct GNUNET_DHT_TEST_Context`
111 */ 111 */
112static void 112static void
113shutdown_task (void *cls) 113shutdown_task (void *cls)
@@ -133,6 +133,26 @@ shutdown_task (void *cls)
133 GNUNET_free (monitors); 133 GNUNET_free (monitors);
134 GNUNET_SCHEDULER_cancel (put_task); 134 GNUNET_SCHEDULER_cancel (put_task);
135 GNUNET_DHT_TEST_cleanup (ctx); 135 GNUNET_DHT_TEST_cleanup (ctx);
136 if (NULL != timeout_task)
137 {
138 GNUNET_SCHEDULER_cancel (timeout_task);
139 timeout_task = NULL;
140 }
141}
142
143
144/**
145 * Task run on success or timeout to clean up.
146 * Terminates active get operations and shuts down
147 * the testbed.
148 *
149 * @param cls NULL
150 */
151static void
152timeout_task_cb (void *cls)
153{
154 timeout_task = NULL;
155 GNUNET_SCHEDULER_shutdown ();
136} 156}
137 157
138 158
@@ -157,12 +177,12 @@ dht_get_handler (void *cls, struct GNUNET_TIME_Absolute exp,
157 const struct GNUNET_PeerIdentity *get_path, 177 const struct GNUNET_PeerIdentity *get_path,
158 unsigned int get_path_length, 178 unsigned int get_path_length,
159 const struct GNUNET_PeerIdentity *put_path, 179 const struct GNUNET_PeerIdentity *put_path,
160 unsigned int put_path_length, enum GNUNET_BLOCK_Type type, 180 unsigned int put_path_length,
181 enum GNUNET_BLOCK_Type type,
161 size_t size, const void *data) 182 size_t size, const void *data)
162{ 183{
163 struct GetOperation *get_op = cls; 184 struct GetOperation *get_op = cls;
164 struct GNUNET_HashCode want; 185 struct GNUNET_HashCode want;
165 struct GNUNET_DHT_TestContext *ctx;
166 186
167 if (sizeof (struct GNUNET_HashCode) != size) 187 if (sizeof (struct GNUNET_HashCode) != size)
168 { 188 {
@@ -186,8 +206,7 @@ dht_get_handler (void *cls, struct GNUNET_TIME_Absolute exp,
186 return; 206 return;
187 /* all DHT GET operations successful; terminate! */ 207 /* all DHT GET operations successful; terminate! */
188 ok = 0; 208 ok = 0;
189 ctx = GNUNET_SCHEDULER_cancel (timeout_task); 209 GNUNET_SCHEDULER_shutdown ();
190 timeout_task = GNUNET_SCHEDULER_add_now (&shutdown_task, ctx);
191} 210}
192 211
193 212
@@ -202,11 +221,10 @@ do_puts (void *cls)
202 struct GNUNET_DHT_Handle **hs = cls; 221 struct GNUNET_DHT_Handle **hs = cls;
203 struct GNUNET_HashCode key; 222 struct GNUNET_HashCode key;
204 struct GNUNET_HashCode value; 223 struct GNUNET_HashCode value;
205 unsigned int i;
206 224
207 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 225 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
208 "Putting values into DHT\n"); 226 "Putting values into DHT\n");
209 for (i = 0; i < NUM_PEERS; i++) 227 for (unsigned int i = 0; i < NUM_PEERS; i++)
210 { 228 {
211 GNUNET_CRYPTO_hash (&i, sizeof (i), &key); 229 GNUNET_CRYPTO_hash (&i, sizeof (i), &key);
212 GNUNET_CRYPTO_hash (&key, sizeof (key), &value); 230 GNUNET_CRYPTO_hash (&key, sizeof (key), &value);
@@ -360,7 +378,8 @@ run (void *cls,
360 378
361 GNUNET_assert (NUM_PEERS == num_peers); 379 GNUNET_assert (NUM_PEERS == num_peers);
362 my_peers = peers; 380 my_peers = peers;
363 monitors = GNUNET_malloc (num_peers * sizeof (struct GNUNET_DHT_MonitorHandle *)); 381 monitors = GNUNET_new_array (num_peers,
382 struct GNUNET_DHT_MonitorHandle *);
364 for (i = 0; i < num_peers; i++) 383 for (i = 0; i < num_peers; i++)
365 monitors[i] = GNUNET_DHT_monitor_start (dhts[i], 384 monitors[i] = GNUNET_DHT_monitor_start (dhts[i],
366 GNUNET_BLOCK_TYPE_ANY, 385 GNUNET_BLOCK_TYPE_ANY,
@@ -392,7 +411,10 @@ run (void *cls,
392 } 411 }
393 } 412 }
394 timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, 413 timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
395 &shutdown_task, ctx); 414 &timeout_task_cb,
415 NULL);
416 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
417 ctx);
396} 418}
397 419
398 420
diff --git a/src/dht/test_dht_tools.py.in b/src/dht/test_dht_tools.py.in
index 0f48d7f76..5ceabbfad 100644
--- a/src/dht/test_dht_tools.py.in
+++ b/src/dht/test_dht_tools.py.in
@@ -1,4 +1,16 @@
1#!@PYTHON@ 1#!@PYTHON@
2#
3# This testcase simply checks that the DHT command-line tools work.
4# It launches a single peer, stores a value "testdata" under "testkey",
5# and then gives the system 50 ms to fetch it.
6#
7# This could fail if
8# - command line tool interfaces fail
9# - DHT plugins for storage are not installed / working
10# - block plugins for verification (the test plugin) is not installed
11#
12# The code does NOT depend on DHT routing or any actual P2P functionality.
13#
2from __future__ import print_function 14from __future__ import print_function
3import os 15import os
4import sys 16import sys
@@ -8,6 +20,8 @@ import subprocess
8import time 20import time
9import tempfile 21import tempfile
10 22
23os.environ["PATH"] = "@bindir@" + ":" + os.environ["PATH"];
24
11if os.name == "nt": 25if os.name == "nt":
12 tmp = os.getenv ("TEMP") 26 tmp = os.getenv ("TEMP")
13else: 27else:
@@ -103,7 +117,7 @@ print ("PASS")
103time.sleep (1) 117time.sleep (1)
104 118
105print ("TEST: Testing get...", end='') 119print ("TEST: Testing get...", end='')
106rc, stdo, stde = r_get (['-k', 'testkey', '-T', '5 ms', '-t', '8'], want_stdo = True, failer = end_arm_failer) 120rc, stdo, stde = r_get (['-k', 'testkey', '-T', '50 ms', '-t', '8'], want_stdo = True, failer = end_arm_failer)
107stdo = stdo.replace ('\r', '').splitlines () 121stdo = stdo.replace ('\r', '').splitlines ()
108expect = "Result 0, type 8:\ntestdata".splitlines() 122expect = "Result 0, type 8:\ntestdata".splitlines()
109if len (stdo) != 2 or len (expect) != 2 or stdo[0] != expect[0] or stdo[1] != expect[1]: 123if len (stdo) != 2 or len (expect) != 2 or stdo[0] != expect[0] or stdo[1] != expect[1]:
diff --git a/src/dns/Makefile.am b/src/dns/Makefile.am
index f5fcf3782..5af228121 100644
--- a/src/dns/Makefile.am
+++ b/src/dns/Makefile.am
@@ -106,13 +106,14 @@ 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)
112 113
113 114
114if ENABLE_TEST_RUN 115if ENABLE_TEST_RUN
115AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; 116AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
116TESTS = $(check_PROGRAMS) $(check_SCRIPTS) 117TESTS = $(check_PROGRAMS) $(check_SCRIPTS)
117endif 118endif
118 119
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..fb5c768ac 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,14 +346,19 @@ 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_flag ('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_VERBOSE (&verbosity), 356 GNUNET_GETOPT_option_flag ('o',
357 "outbound-only",
358 gettext_noop ("only monitor DNS queries"),
359 &outbound_only),
360
361 GNUNET_GETOPT_option_verbose (&verbosity),
357 GNUNET_GETOPT_OPTION_END 362 GNUNET_GETOPT_OPTION_END
358 }; 363 };
359 364
diff --git a/src/dns/gnunet-dns-redirector.c b/src/dns/gnunet-dns-redirector.c
index 89929815a..44d3d0b6c 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,14 +230,20 @@ 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_VERBOSE (&verbosity), 240 GNUNET_GETOPT_option_string ('6',
241 "ipv4",
242 "IPV6",
243 gettext_noop ("set AAAA records"),
244 &n6),
245
246 GNUNET_GETOPT_option_verbose (&verbosity),
241 GNUNET_GETOPT_OPTION_END 247 GNUNET_GETOPT_OPTION_END
242 }; 248 };
243 249
diff --git a/src/dns/gnunet-helper-dns.c b/src/dns/gnunet-helper-dns.c
index 1c5744002..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
@@ -794,6 +794,8 @@ main (int argc, char *const*argv)
794 sbin_ip = "/sbin/ip"; 794 sbin_ip = "/sbin/ip";
795 else if (0 == access ("/usr/sbin/ip", X_OK)) 795 else if (0 == access ("/usr/sbin/ip", X_OK))
796 sbin_ip = "/usr/sbin/ip"; 796 sbin_ip = "/usr/sbin/ip";
797 else if (0 == access ("/bin/ip", X_OK)) /* gentoo has it there */
798 sbin_ip = "/bin/ip";
797 else 799 else
798 { 800 {
799 fprintf (stderr, 801 fprintf (stderr,
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/dns/plugin_block_dns.c b/src/dns/plugin_block_dns.c
index dc339dd25..ca6ea84c4 100644
--- a/src/dns/plugin_block_dns.c
+++ b/src/dns/plugin_block_dns.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
@@ -31,6 +31,61 @@
31#include "gnunet_block_plugin.h" 31#include "gnunet_block_plugin.h"
32#include "block_dns.h" 32#include "block_dns.h"
33#include "gnunet_signatures.h" 33#include "gnunet_signatures.h"
34#include "gnunet_block_group_lib.h"
35
36
37/**
38 * Number of bits we set per entry in the bloomfilter.
39 * Do not change!
40 */
41#define BLOOMFILTER_K 16
42
43
44/**
45 * Create a new block group.
46 *
47 * @param ctx block context in which the block group is created
48 * @param type type of the block for which we are creating the group
49 * @param nonce random value used to seed the group creation
50 * @param raw_data optional serialized prior state of the group, NULL if unavailable/fresh
51 * @param raw_data_size number of bytes in @a raw_data, 0 if unavailable/fresh
52 * @param va variable arguments specific to @a type
53 * @return block group handle, NULL if block groups are not supported
54 * by this @a type of block (this is not an error)
55 */
56static struct GNUNET_BLOCK_Group *
57block_plugin_dns_create_group (void *cls,
58 enum GNUNET_BLOCK_Type type,
59 uint32_t nonce,
60 const void *raw_data,
61 size_t raw_data_size,
62 va_list va)
63{
64 unsigned int bf_size;
65 const char *guard;
66
67 guard = va_arg (va, const char *);
68 if (0 == strcmp (guard,
69 "seen-set-size"))
70 bf_size = GNUNET_BLOCK_GROUP_compute_bloomfilter_size (va_arg (va, unsigned int),
71 BLOOMFILTER_K);
72 else if (0 == strcmp (guard,
73 "filter-size"))
74 bf_size = va_arg (va, unsigned int);
75 else
76 {
77 GNUNET_break (0);
78 bf_size = 8;
79 }
80 GNUNET_break (NULL == va_arg (va, const char *));
81 return GNUNET_BLOCK_GROUP_bf_create (cls,
82 bf_size,
83 BLOOMFILTER_K,
84 type,
85 nonce,
86 raw_data,
87 raw_data_size);
88}
34 89
35 90
36/** 91/**
@@ -38,11 +93,11 @@
38 * request evaluation, simply pass "NULL" for the reply_block. 93 * request evaluation, simply pass "NULL" for the reply_block.
39 * 94 *
40 * @param cls closure 95 * @param cls closure
96 * @param ctx block context
41 * @param type block type 97 * @param type block type
98 * @param bg group to evaluate against
42 * @param eo control flags 99 * @param eo control flags
43 * @param query original query (hash) 100 * @param query original query (hash)
44 * @param bf pointer to bloom filter associated with query; possibly updated (!)
45 * @param bf_mutator mutation value for bf
46 * @param xquery extended query data (can be NULL, depending on type) 101 * @param xquery extended query data (can be NULL, depending on type)
47 * @param xquery_size number of bytes in @a xquery 102 * @param xquery_size number of bytes in @a xquery
48 * @param reply_block response to validate 103 * @param reply_block response to validate
@@ -51,17 +106,18 @@
51 */ 106 */
52static enum GNUNET_BLOCK_EvaluationResult 107static enum GNUNET_BLOCK_EvaluationResult
53block_plugin_dns_evaluate (void *cls, 108block_plugin_dns_evaluate (void *cls,
109 struct GNUNET_BLOCK_Context *ctx,
54 enum GNUNET_BLOCK_Type type, 110 enum GNUNET_BLOCK_Type type,
111 struct GNUNET_BLOCK_Group *bg,
55 enum GNUNET_BLOCK_EvaluationOptions eo, 112 enum GNUNET_BLOCK_EvaluationOptions eo,
56 const struct GNUNET_HashCode * query, 113 const struct GNUNET_HashCode * query,
57 struct GNUNET_CONTAINER_BloomFilter **bf,
58 int32_t bf_mutator,
59 const void *xquery, 114 const void *xquery,
60 size_t xquery_size, 115 size_t xquery_size,
61 const void *reply_block, 116 const void *reply_block,
62 size_t reply_block_size) 117 size_t reply_block_size)
63{ 118{
64 const struct GNUNET_DNS_Advertisement *ad; 119 const struct GNUNET_DNS_Advertisement *ad;
120 struct GNUNET_HashCode phash;
65 121
66 switch (type) 122 switch (type)
67 { 123 {
@@ -69,7 +125,7 @@ block_plugin_dns_evaluate (void *cls,
69 if (0 != xquery_size) 125 if (0 != xquery_size)
70 return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID; 126 return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID;
71 127
72 if (0 == reply_block_size) 128 if (NULL == reply_block)
73 return GNUNET_BLOCK_EVALUATION_REQUEST_VALID; 129 return GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
74 130
75 if (sizeof (struct GNUNET_DNS_Advertisement) != reply_block_size) 131 if (sizeof (struct GNUNET_DNS_Advertisement) != reply_block_size)
@@ -96,13 +152,20 @@ block_plugin_dns_evaluate (void *cls,
96 } 152 }
97 if (GNUNET_OK != 153 if (GNUNET_OK !=
98 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_DNS_RECORD, 154 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_DNS_RECORD,
99 &ad->purpose, 155 &ad->purpose,
100 &ad->signature, 156 &ad->signature,
101 &ad->peer.public_key)) 157 &ad->peer.public_key))
102 { 158 {
103 GNUNET_break_op (0); 159 GNUNET_break_op (0);
104 return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; 160 return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
105 } 161 }
162 GNUNET_CRYPTO_hash (reply_block,
163 reply_block_size,
164 &phash);
165 if (GNUNET_YES ==
166 GNUNET_BLOCK_GROUP_bf_test_and_set (bg,
167 &phash))
168 return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
106 return GNUNET_BLOCK_EVALUATION_OK_MORE; 169 return GNUNET_BLOCK_EVALUATION_OK_MORE;
107 default: 170 default:
108 return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED; 171 return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED;
@@ -149,6 +212,7 @@ libgnunet_plugin_block_dns_init (void *cls)
149 api = GNUNET_new (struct GNUNET_BLOCK_PluginFunctions); 212 api = GNUNET_new (struct GNUNET_BLOCK_PluginFunctions);
150 api->evaluate = &block_plugin_dns_evaluate; 213 api->evaluate = &block_plugin_dns_evaluate;
151 api->get_key = &block_plugin_dns_get_key; 214 api->get_key = &block_plugin_dns_get_key;
215 api->create_group = &block_plugin_dns_create_group;
152 api->types = types; 216 api->types = types;
153 return api; 217 return api;
154} 218}
diff --git a/src/dv/Makefile.am b/src/dv/Makefile.am
index c6a620343..c44321151 100644
--- a/src/dv/Makefile.am
+++ b/src/dv/Makefile.am
@@ -73,7 +73,7 @@ check_PROGRAMS = \
73endif 73endif
74 74
75if ENABLE_TEST_RUN 75if ENABLE_TEST_RUN
76 AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; 76 AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
77 TESTS = $(check_PROGRAMS) 77 TESTS = $(check_PROGRAMS)
78endif 78endif
79 79
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..d99097a15 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 6adaa04d9..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;
@@ -1346,11 +1346,13 @@ check_target_added (void *cls,
1346 * 1346 *
1347 * @param cls the `struct DirectNeighbor` we're building the consensus with 1347 * @param cls the `struct DirectNeighbor` we're building the consensus with
1348 * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK 1348 * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
1349 * @param current_size current set size
1349 * @param status see `enum GNUNET_SET_Status` 1350 * @param status see `enum GNUNET_SET_Status`
1350 */ 1351 */
1351static void 1352static void
1352handle_set_union_result (void *cls, 1353handle_set_union_result (void *cls,
1353 const struct GNUNET_SET_Element *element, 1354 const struct GNUNET_SET_Element *element,
1355 uint64_t current_size,
1354 enum GNUNET_SET_Status status) 1356 enum GNUNET_SET_Status status)
1355{ 1357{
1356 struct DirectNeighbor *neighbor = cls; 1358 struct DirectNeighbor *neighbor = cls;
@@ -1528,6 +1530,7 @@ listen_set_union (void *cls,
1528 GNUNET_SET_OPERATION_UNION); 1530 GNUNET_SET_OPERATION_UNION);
1529 neighbor->set_op = GNUNET_SET_accept (request, 1531 neighbor->set_op = GNUNET_SET_accept (request,
1530 GNUNET_SET_RESULT_ADDED, 1532 GNUNET_SET_RESULT_ADDED,
1533 (struct GNUNET_SET_Option[]) {{ 0 }},
1531 &handle_set_union_result, 1534 &handle_set_union_result,
1532 neighbor); 1535 neighbor);
1533 neighbor->consensus_insertion_offset = 0; 1536 neighbor->consensus_insertion_offset = 0;
@@ -1558,6 +1561,7 @@ initiate_set_union (void *cls)
1558 &neighbor->real_session_id, 1561 &neighbor->real_session_id,
1559 NULL, 1562 NULL,
1560 GNUNET_SET_RESULT_ADDED, 1563 GNUNET_SET_RESULT_ADDED,
1564 (struct GNUNET_SET_Option[]) {{ 0 }},
1561 &handle_set_union_result, 1565 &handle_set_union_result,
1562 neighbor); 1566 neighbor);
1563 neighbor->consensus_insertion_offset = 0; 1567 neighbor->consensus_insertion_offset = 0;
diff --git a/src/exit/Makefile.am b/src/exit/Makefile.am
index 6c4cbf114..aa1210269 100644
--- a/src/exit/Makefile.am
+++ b/src/exit/Makefile.am
@@ -30,11 +30,11 @@ endif
30 30
31libexec_PROGRAMS = \ 31libexec_PROGRAMS = \
32 gnunet-daemon-exit \ 32 gnunet-daemon-exit \
33 $(EXITBIN) 33 $(EXITBIN)
34 34
35if MINGW 35if MINGW
36 gnunet_helper_exit_LDFLAGS = \ 36 gnunet_helper_exit_LDFLAGS = \
37 -no-undefined -Wl,--export-all-symbols 37 -no-undefined -Wl,--export-all-symbols
38 38
39 gnunet_helper_exit_LDADD = \ 39 gnunet_helper_exit_LDADD = \
40 -lsetupapi -lnewdev -lshell32 -liconv -lstdc++ \ 40 -lsetupapi -lnewdev -lshell32 -liconv -lstdc++ \
@@ -47,7 +47,7 @@ else
47 gnunet-helper-exit.c 47 gnunet-helper-exit.c
48endif 48endif
49gnunet_daemon_exit_SOURCES = \ 49gnunet_daemon_exit_SOURCES = \
50 gnunet-daemon-exit.c exit.h 50 gnunet-daemon-exit.c exit.h
51gnunet_daemon_exit_LDADD = \ 51gnunet_daemon_exit_LDADD = \
52 $(top_builddir)/src/dns/libgnunetdnsstub.la \ 52 $(top_builddir)/src/dns/libgnunetdnsstub.la \
53 $(top_builddir)/src/dht/libgnunetdht.la \ 53 $(top_builddir)/src/dht/libgnunetdht.la \
diff --git a/src/exit/gnunet-daemon-exit.c b/src/exit/gnunet-daemon-exit.c
index 68699db71..87b30c04a 100644
--- a/src/exit/gnunet-daemon-exit.c
+++ b/src/exit/gnunet-daemon-exit.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 Copyright (C) 2010-2013 Christian Grothoff 3 Copyright (C) 2010-2013, 2017 Christian Grothoff
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
@@ -195,33 +195,6 @@ struct RedirectInformation
195 195
196 196
197/** 197/**
198 * Queue of messages to a channel.
199 */
200struct ChannelMessageQueue
201{
202 /**
203 * This is a doubly-linked list.
204 */
205 struct ChannelMessageQueue *next;
206
207 /**
208 * This is a doubly-linked list.
209 */
210 struct ChannelMessageQueue *prev;
211
212 /**
213 * Payload to send via the channel.
214 */
215 const void *payload;
216
217 /**
218 * Number of bytes in @e payload.
219 */
220 size_t len;
221};
222
223
224/**
225 * This struct is saved into #connections_map to allow finding the 198 * This struct is saved into #connections_map to allow finding the
226 * right channel given an IP packet from TUN. It is also associated 199 * right channel given an IP packet from TUN. It is also associated
227 * with the channel's closure so we can find it again for the next 200 * with the channel's closure so we can find it again for the next
@@ -241,11 +214,6 @@ struct ChannelState
241 struct GNUNET_PeerIdentity peer; 214 struct GNUNET_PeerIdentity peer;
242 215
243 /** 216 /**
244 * Active channel transmission request (or NULL).
245 */
246 struct GNUNET_CADET_TransmitHandle *th;
247
248 /**
249 * #GNUNET_NO if this is a channel for TCP/UDP, 217 * #GNUNET_NO if this is a channel for TCP/UDP,
250 * #GNUNET_YES if this is a channel for DNS, 218 * #GNUNET_YES if this is a channel for DNS,
251 * #GNUNET_SYSERR if the channel is not yet initialized. 219 * #GNUNET_SYSERR if the channel is not yet initialized.
@@ -273,16 +241,6 @@ struct ChannelState
273 struct LocalService *serv; 241 struct LocalService *serv;
274 242
275 /** 243 /**
276 * Head of DLL of messages for this channel.
277 */
278 struct ChannelMessageQueue *head;
279
280 /**
281 * Tail of DLL of messages for this channel.
282 */
283 struct ChannelMessageQueue *tail;
284
285 /**
286 * Primary redirection information for this connection. 244 * Primary redirection information for this connection.
287 */ 245 */
288 struct RedirectInformation ri; 246 struct RedirectInformation ri;
@@ -292,22 +250,12 @@ struct ChannelState
292 { 250 {
293 251
294 /** 252 /**
295 * DNS reply ready for transmission.
296 */
297 char *reply;
298
299 /**
300 * Socket we are using to transmit this request (must match if we receive 253 * Socket we are using to transmit this request (must match if we receive
301 * a response). 254 * a response).
302 */ 255 */
303 struct GNUNET_DNSSTUB_RequestSocket *rs; 256 struct GNUNET_DNSSTUB_RequestSocket *rs;
304 257
305 /** 258 /**
306 * Number of bytes in 'reply'.
307 */
308 size_t reply_length;
309
310 /**
311 * Original DNS request ID as used by the client. 259 * Original DNS request ID as used by the client.
312 */ 260 */
313 uint16_t original_id; 261 uint16_t original_id;
@@ -428,7 +376,7 @@ static struct GNUNET_DHT_Handle *dht;
428/** 376/**
429 * Task for doing DHT PUTs to advertise exit service. 377 * Task for doing DHT PUTs to advertise exit service.
430 */ 378 */
431static struct GNUNET_SCHEDULER_Task * dht_task; 379static struct GNUNET_SCHEDULER_Task *dht_task;
432 380
433/** 381/**
434 * Advertisement message we put into the DHT to advertise us 382 * Advertisement message we put into the DHT to advertise us
@@ -447,6 +395,21 @@ static struct GNUNET_HashCode dht_put_key;
447static struct GNUNET_CRYPTO_EddsaPrivateKey *peer_key; 395static struct GNUNET_CRYPTO_EddsaPrivateKey *peer_key;
448 396
449/** 397/**
398 * Port for DNS exit.
399 */
400static struct GNUNET_CADET_Port *dns_port;
401
402/**
403 * Port for IPv4 exit.
404 */
405static struct GNUNET_CADET_Port *cadet_port4;
406
407/**
408 * Port for IPv6 exit.
409 */
410static struct GNUNET_CADET_Port *cadet_port6;
411
412/**
450 * Are we an IPv4-exit? 413 * Are we an IPv4-exit?
451 */ 414 */
452static int ipv4_exit; 415static int ipv4_exit;
@@ -467,51 +430,27 @@ static int ipv4_enabled;
467static int ipv6_enabled; 430static int ipv6_enabled;
468 431
469 432
433GNUNET_NETWORK_STRUCT_BEGIN
434
470/** 435/**
471 * We got a reply from DNS for a request of a CADET channel. Send it 436 * Message with a DNS response.
472 * via the channel (after changing the request ID back). 437 */
473 * 438struct DnsResponseMessage
474 * @param cls the `struct ChannelState`
475 * @param size number of bytes available in @a buf
476 * @param buf where to copy the reply
477 * @return number of bytes written to @a buf
478 */
479static size_t
480transmit_reply_to_cadet (void *cls,
481 size_t size,
482 void *buf)
483{ 439{
484 struct ChannelState *ts = cls; 440 /**
485 size_t off; 441 * GNUnet header, of type #GNUNET_MESSAGE_TYPE_VPN_DNS_FROM_INTERNET
486 size_t ret; 442 */
487 char *cbuf = buf; 443 struct GNUNET_MessageHeader header;
488 struct GNUNET_MessageHeader hdr; 444
445 /**
446 * DNS header.
447 */
489 struct GNUNET_TUN_DnsHeader dns; 448 struct GNUNET_TUN_DnsHeader dns;
490 449
491 GNUNET_assert (GNUNET_YES == ts->is_dns); 450 /* Followed by more DNS payload */
492 ts->th = NULL; 451};
493 GNUNET_assert (ts->specifics.dns.reply != NULL); 452
494 if (size == 0) 453GNUNET_NETWORK_STRUCT_END
495 return 0;
496 ret = sizeof (struct GNUNET_MessageHeader) + ts->specifics.dns.reply_length;
497 GNUNET_assert (ret <= size);
498 hdr.size = htons (ret);
499 hdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_DNS_FROM_INTERNET);
500 GNUNET_memcpy (&dns, ts->specifics.dns.reply, sizeof (dns));
501 dns.id = ts->specifics.dns.original_id;
502 off = 0;
503 GNUNET_memcpy (&cbuf[off], &hdr, sizeof (hdr));
504 off += sizeof (hdr);
505 GNUNET_memcpy (&cbuf[off], &dns, sizeof (dns));
506 off += sizeof (dns);
507 GNUNET_memcpy (&cbuf[off], &ts->specifics.dns.reply[sizeof (dns)], ts->specifics.dns.reply_length - sizeof (dns));
508 off += ts->specifics.dns.reply_length - sizeof (dns);
509 GNUNET_free (ts->specifics.dns.reply);
510 ts->specifics.dns.reply = NULL;
511 ts->specifics.dns.reply_length = 0;
512 GNUNET_assert (ret == off);
513 return ret;
514}
515 454
516 455
517/** 456/**
@@ -521,7 +460,7 @@ transmit_reply_to_cadet (void *cls,
521 * @param cls NULL 460 * @param cls NULL
522 * @param rs the socket that received the response 461 * @param rs the socket that received the response
523 * @param dns the response itself 462 * @param dns the response itself
524 * @param r number of bytes in dns 463 * @param r number of bytes in @a dns
525 */ 464 */
526static void 465static void
527process_dns_result (void *cls, 466process_dns_result (void *cls,
@@ -530,6 +469,8 @@ process_dns_result (void *cls,
530 size_t r) 469 size_t r)
531{ 470{
532 struct ChannelState *ts; 471 struct ChannelState *ts;
472 struct GNUNET_MQ_Envelope *env;
473 struct DnsResponseMessage *resp;
533 474
534 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 475 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
535 "Processing DNS result from stub resolver\n"); 476 "Processing DNS result from stub resolver\n");
@@ -542,48 +483,35 @@ process_dns_result (void *cls,
542 LOG (GNUNET_ERROR_TYPE_DEBUG, 483 LOG (GNUNET_ERROR_TYPE_DEBUG,
543 "Got a response from the stub resolver for DNS request received via CADET!\n"); 484 "Got a response from the stub resolver for DNS request received via CADET!\n");
544 channels[dns->id] = NULL; 485 channels[dns->id] = NULL;
545 GNUNET_free_non_null (ts->specifics.dns.reply); 486 env = GNUNET_MQ_msg_extra (resp,
546 ts->specifics.dns.reply = GNUNET_malloc (r); 487 r - sizeof (struct GNUNET_TUN_DnsHeader),
547 ts->specifics.dns.reply_length = r; 488 GNUNET_MESSAGE_TYPE_VPN_DNS_FROM_INTERNET);
548 GNUNET_memcpy (ts->specifics.dns.reply, dns, r); 489 GNUNET_memcpy (&resp->dns,
549 if (NULL != ts->th) 490 dns,
550 GNUNET_CADET_notify_transmit_ready_cancel (ts->th); 491 r);
551 ts->th = GNUNET_CADET_notify_transmit_ready (ts->channel, 492 resp->dns.id = ts->specifics.dns.original_id;
552 GNUNET_NO, 493 GNUNET_MQ_send (GNUNET_CADET_get_mq (ts->channel),
553 GNUNET_TIME_UNIT_FOREVER_REL, 494 env);
554 sizeof (struct GNUNET_MessageHeader) + r,
555 &transmit_reply_to_cadet,
556 ts);
557} 495}
558 496
559 497
560/** 498/**
561 * Process a request via cadet to perform a DNS query. 499 * Check a request via cadet to perform a DNS query.
562 *
563 * @param cls closure, NULL
564 * @param channel connection to the other end
565 * @param channel_ctx pointer to our `struct ChannelState *`
566 * @param message the actual message
567 * 500 *
501 * @param cls our `struct ChannelState *`
502 * @param msg the actual message
568 * @return #GNUNET_OK to keep the connection open, 503 * @return #GNUNET_OK to keep the connection open,
569 * #GNUNET_SYSERR to close it (signal serious error) 504 * #GNUNET_SYSERR to close it (signal serious error)
570 */ 505 */
571static int 506static int
572receive_dns_request (void *cls GNUNET_UNUSED, 507check_dns_request (void *cls,
573 struct GNUNET_CADET_Channel *channel, 508 const struct DnsResponseMessage *msg)
574 void **channel_ctx,
575 const struct GNUNET_MessageHeader *message)
576{ 509{
577 struct ChannelState *ts = *channel_ctx; 510 struct ChannelState *ts = cls;
578 const struct GNUNET_TUN_DnsHeader *dns;
579 size_t mlen = ntohs (message->size);
580 size_t dlen = mlen - sizeof (struct GNUNET_MessageHeader);
581 char buf[dlen] GNUNET_ALIGN;
582 struct GNUNET_TUN_DnsHeader *dout;
583 511
584 if (NULL == dnsstub) 512 if (NULL == dnsstub)
585 { 513 {
586 GNUNET_break_op (0); 514 GNUNET_break (0);
587 return GNUNET_SYSERR; 515 return GNUNET_SYSERR;
588 } 516 }
589 if (GNUNET_NO == ts->is_dns) 517 if (GNUNET_NO == ts->is_dns)
@@ -591,34 +519,53 @@ receive_dns_request (void *cls GNUNET_UNUSED,
591 GNUNET_break_op (0); 519 GNUNET_break_op (0);
592 return GNUNET_SYSERR; 520 return GNUNET_SYSERR;
593 } 521 }
522 return GNUNET_OK;
523}
524
525
526/**
527 * Process a request via cadet to perform a DNS query.
528 *
529 * @param cls our `struct ChannelState *`
530 * @param msg the actual message
531 */
532static void
533handle_dns_request (void *cls,
534 const struct DnsResponseMessage *msg)
535{
536 struct ChannelState *ts = cls;
537 size_t mlen = ntohs (msg->header.size);
538 size_t dlen = mlen - sizeof (struct GNUNET_MessageHeader);
539 char buf[dlen] GNUNET_ALIGN;
540 struct GNUNET_TUN_DnsHeader *dout;
541
594 if (GNUNET_SYSERR == ts->is_dns) 542 if (GNUNET_SYSERR == ts->is_dns)
595 { 543 {
596 /* channel is DNS from now on */ 544 /* channel is DNS from now on */
597 ts->is_dns = GNUNET_YES; 545 ts->is_dns = GNUNET_YES;
598 } 546 }
599 if (dlen < sizeof (struct GNUNET_TUN_DnsHeader)) 547 ts->specifics.dns.original_id = msg->dns.id;
600 {
601 GNUNET_break_op (0);
602 return GNUNET_SYSERR;
603 }
604 dns = (const struct GNUNET_TUN_DnsHeader *) &message[1];
605 ts->specifics.dns.original_id = dns->id;
606 if (channels[ts->specifics.dns.my_id] == ts) 548 if (channels[ts->specifics.dns.my_id] == ts)
607 channels[ts->specifics.dns.my_id] = NULL; 549 channels[ts->specifics.dns.my_id] = NULL;
608 ts->specifics.dns.my_id = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 550 ts->specifics.dns.my_id = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
609 UINT16_MAX + 1); 551 UINT16_MAX + 1);
610 channels[ts->specifics.dns.my_id] = ts; 552 channels[ts->specifics.dns.my_id] = ts;
611 GNUNET_memcpy (buf, dns, dlen); 553 GNUNET_memcpy (buf,
554 &msg->dns,
555 dlen);
612 dout = (struct GNUNET_TUN_DnsHeader *) buf; 556 dout = (struct GNUNET_TUN_DnsHeader *) buf;
613 dout->id = ts->specifics.dns.my_id; 557 dout->id = ts->specifics.dns.my_id;
614 ts->specifics.dns.rs = GNUNET_DNSSTUB_resolve2 (dnsstub, 558 ts->specifics.dns.rs = GNUNET_DNSSTUB_resolve2 (dnsstub,
615 buf, dlen, 559 buf,
560 dlen,
616 &process_dns_result, 561 &process_dns_result,
617 NULL); 562 NULL);
618 if (NULL == ts->specifics.dns.rs) 563 if (NULL == ts->specifics.dns.rs)
619 return GNUNET_SYSERR; 564 {
620 GNUNET_CADET_receive_done (channel); 565 GNUNET_break_op (0);
621 return GNUNET_OK; 566 return;
567 }
568 GNUNET_CADET_receive_done (ts->channel);
622} 569}
623 570
624 571
@@ -753,706 +700,445 @@ get_redirect_state (int af,
753} 700}
754 701
755 702
756/**
757 * Free memory associated with a service record.
758 *
759 * @param cls unused
760 * @param key service descriptor
761 * @param value service record to free
762 * @return #GNUNET_OK
763 */
764static int
765free_service_record (void *cls,
766 const struct GNUNET_HashCode *key,
767 void *value)
768{
769 struct LocalService *service = value;
770
771 GNUNET_assert (GNUNET_YES ==
772 GNUNET_CONTAINER_multihashmap_remove (services,
773 key,
774 service));
775 GNUNET_CADET_close_port (service->port);
776 GNUNET_free_non_null (service->name);
777 GNUNET_free (service);
778 return GNUNET_OK;
779}
780
781
782/**
783 * Callback from CADET for new channels.
784 *
785 * @param cls closure
786 * @param channel new handle to the channel
787 * @param initiator peer that started the channel
788 * @param port destination port
789 * @param options channel options flags
790 * @return initial channel context for the channel
791 */
792static void *
793new_service_channel (void *cls,
794 struct GNUNET_CADET_Channel *channel,
795 const struct GNUNET_PeerIdentity *initiator,
796 const struct GNUNET_HashCode *port,
797 enum GNUNET_CADET_ChannelOption options)
798{
799 struct LocalService *ls = cls;
800 struct ChannelState *s = GNUNET_new (struct ChannelState);
801
802 s->peer = *initiator;
803 GNUNET_STATISTICS_update (stats,
804 gettext_noop ("# Inbound CADET channels created"),
805 1,
806 GNUNET_NO);
807 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
808 "Received inbound channel from `%s'\n",
809 GNUNET_i2s (initiator));
810 s->channel = channel;
811 s->specifics.tcp_udp.serv = ls;
812 s->specifics.tcp_udp.ri.remote_address = ls->address;
813 return s;
814}
815
816 703
817/** 704/**
818 * Given a service descriptor and a destination port, find the 705 * Check a request via cadet to send a request to a TCP service
819 * respective service entry. 706 * offered by this system.
820 * 707 *
821 * @param proto IPPROTO_TCP or IPPROTO_UDP 708 * @param cls our `struct ChannelState *`
822 * @param name name of the service 709 * @param start the actual message
823 * @param destination_port destination port 710 * @return #GNUNET_OK to keep the connection open,
824 * @param service service information record to store (service->name will be set). 711 * #GNUNET_SYSERR to close it (signal serious error)
825 */ 712 */
826static void 713static int
827store_service (int proto, 714check_tcp_service (void *cls,
828 const char *name, 715 const struct GNUNET_EXIT_TcpServiceStartMessage *start)
829 uint16_t destination_port,
830 struct LocalService *service)
831{ 716{
832 struct GNUNET_HashCode cadet_port; 717 struct ChannelState *state = cls;
833 718
834 service->name = GNUNET_strdup (name); 719 if (NULL == state)
835 GNUNET_TUN_service_name_to_hash (name,
836 &service->descriptor);
837 GNUNET_TUN_compute_service_cadet_port (&service->descriptor,
838 destination_port,
839 &cadet_port);
840 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
841 "Opening CADET port %s for SERVICE exit %s on port %u\n",
842 GNUNET_h2s (&cadet_port),
843 name,
844 (unsigned int) destination_port);
845 service->port = GNUNET_CADET_open_port (cadet_handle,
846 &cadet_port,
847 &new_service_channel,
848 service);
849 service->is_udp = (IPPROTO_UDP == proto);
850 if (GNUNET_OK !=
851 GNUNET_CONTAINER_multihashmap_put (services,
852 &cadet_port,
853 service,
854 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
855 { 720 {
856 GNUNET_CADET_close_port (service->port); 721 GNUNET_break_op (0);
857 GNUNET_free_non_null (service->name); 722 return GNUNET_SYSERR;
858 GNUNET_free (service);
859 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
860 _("Got duplicate service records for `%s:%u'\n"),
861 name,
862 (unsigned int) destination_port);
863 } 723 }
724 if (GNUNET_YES == state->is_dns)
725 {
726 GNUNET_break_op (0);
727 return GNUNET_SYSERR;
728 }
729 if (NULL == state->specifics.tcp_udp.serv)
730 {
731 GNUNET_break_op (0);
732 return GNUNET_SYSERR;
733 }
734 if (NULL != state->specifics.tcp_udp.heap_node)
735 {
736 GNUNET_break_op (0);
737 return GNUNET_SYSERR;
738 }
739 if (start->tcp_header.off * 4 < sizeof (struct GNUNET_TUN_TcpHeader))
740 {
741 GNUNET_break_op (0);
742 return GNUNET_SYSERR;
743 }
744 return GNUNET_OK;
864} 745}
865 746
866 747
867/** 748/**
868 * CADET is ready to receive a message for the channel. Transmit it. 749 * Prepare an IPv4 packet for transmission via the TUN interface.
869 * 750 * Initializes the IP header and calculates checksums (IP+UDP/TCP).
870 * @param cls the `struct ChannelState`. 751 * For UDP, the UDP header will be fully created, whereas for TCP
871 * @param size number of bytes available in @a buf 752 * only the ports and checksum will be filled in. So for TCP,
872 * @param buf where to copy the message 753 * a skeleton TCP header must be part of the provided payload.
873 * @return number of bytes copied to @a buf
874 */
875static size_t
876send_to_peer_notify_callback (void *cls,
877 size_t size,
878 void *buf)
879{
880 struct ChannelState *s = cls;
881 struct GNUNET_CADET_Channel *channel = s->channel;
882 struct ChannelMessageQueue *tnq;
883
884 s->th = NULL;
885 tnq = s->specifics.tcp_udp.head;
886 if (NULL == tnq)
887 return 0;
888 if (0 == size)
889 {
890 s->th = GNUNET_CADET_notify_transmit_ready (channel,
891 GNUNET_NO /* corking */,
892 GNUNET_TIME_UNIT_FOREVER_REL,
893 tnq->len,
894 &send_to_peer_notify_callback,
895 s);
896 return 0;
897 }
898 GNUNET_assert (size >= tnq->len);
899 GNUNET_memcpy (buf, tnq->payload, tnq->len);
900 size = tnq->len;
901 GNUNET_CONTAINER_DLL_remove (s->specifics.tcp_udp.head,
902 s->specifics.tcp_udp.tail,
903 tnq);
904 GNUNET_free (tnq);
905 if (NULL != (tnq = s->specifics.tcp_udp.head))
906 s->th = GNUNET_CADET_notify_transmit_ready (channel,
907 GNUNET_NO /* corking */,
908 GNUNET_TIME_UNIT_FOREVER_REL,
909 tnq->len,
910 &send_to_peer_notify_callback,
911 s);
912 GNUNET_STATISTICS_update (stats,
913 gettext_noop ("# Bytes transmitted via cadet channels"),
914 size, GNUNET_NO);
915 return size;
916}
917
918
919/**
920 * Send the given packet via the cadet channel.
921 *
922 * @param s channel destination
923 * @param tnq message to queue
924 */
925static void
926send_packet_to_cadet_channel (struct ChannelState *s,
927 struct ChannelMessageQueue *tnq)
928{
929 struct GNUNET_CADET_Channel *cadet_channel;
930
931 cadet_channel = s->channel;
932 GNUNET_assert (NULL != s);
933 GNUNET_CONTAINER_DLL_insert_tail (s->specifics.tcp_udp.head,
934 s->specifics.tcp_udp.tail,
935 tnq);
936 if (NULL == s->th)
937 s->th = GNUNET_CADET_notify_transmit_ready (cadet_channel,
938 GNUNET_NO /* cork */,
939 GNUNET_TIME_UNIT_FOREVER_REL,
940 tnq->len,
941 &send_to_peer_notify_callback,
942 s);
943}
944
945
946/**
947 * @brief Handles an ICMP packet received from the helper.
948 * 754 *
949 * @param icmp A pointer to the Packet 755 * @param payload payload of the packet (starting with UDP payload or
950 * @param pktlen number of bytes in @a icmp 756 * TCP header, depending on protocol)
951 * @param af address family (AFINET or AF_INET6) 757 * @param payload_length number of bytes in @a payload
952 * @param destination_ip destination IP-address of the IP packet (should 758 * @param protocol IPPROTO_UDP or IPPROTO_TCP
953 * be our local address) 759 * @param tcp_header skeleton of the TCP header, NULL for UDP
954 * @param source_ip original source IP-address of the IP packet (should 760 * @param src_address source address to use (IP and port)
955 * be the original destination address) 761 * @param dst_address destination address to use (IP and port)
762 * @param pkt4 where to write the assembled packet; must
763 * contain enough space for the IP header, UDP/TCP header
764 * AND the payload
956 */ 765 */
957static void 766static void
958icmp_from_helper (const struct GNUNET_TUN_IcmpHeader *icmp, 767prepare_ipv4_packet (const void *payload,
959 size_t pktlen, 768 size_t payload_length,
960 int af, 769 int protocol,
961 const void *destination_ip, 770 const struct GNUNET_TUN_TcpHeader *tcp_header,
962 const void *source_ip) 771 const struct SocketAddress *src_address,
772 const struct SocketAddress *dst_address,
773 struct GNUNET_TUN_IPv4Header *pkt4)
963{ 774{
964 struct ChannelState *state; 775 size_t len;
965 struct ChannelMessageQueue *tnq;
966 struct GNUNET_EXIT_IcmpToVPNMessage *i2v;
967 const struct GNUNET_TUN_IPv4Header *ipv4;
968 const struct GNUNET_TUN_IPv6Header *ipv6;
969 const struct GNUNET_TUN_UdpHeader *udp;
970 size_t mlen;
971 uint16_t source_port;
972 uint16_t destination_port;
973 uint8_t protocol;
974 776
777 len = payload_length;
778 switch (protocol)
975 { 779 {
976 char sbuf[INET6_ADDRSTRLEN]; 780 case IPPROTO_UDP:
977 char dbuf[INET6_ADDRSTRLEN]; 781 len += sizeof (struct GNUNET_TUN_UdpHeader);
978 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 782 break;
979 "Received ICMP packet going from %s to %s\n", 783 case IPPROTO_TCP:
980 inet_ntop (af, 784 len += sizeof (struct GNUNET_TUN_TcpHeader);
981 source_ip, 785 GNUNET_assert (NULL != tcp_header);
982 sbuf, sizeof (sbuf)), 786 break;
983 inet_ntop (af, 787 default:
984 destination_ip, 788 GNUNET_break (0);
985 dbuf, sizeof (dbuf))); 789 return;
986 } 790 }
987 if (pktlen < sizeof (struct GNUNET_TUN_IcmpHeader)) 791 if (len + sizeof (struct GNUNET_TUN_IPv4Header) > UINT16_MAX)
988 { 792 {
989 /* blame kernel */
990 GNUNET_break (0); 793 GNUNET_break (0);
991 return; 794 return;
992 } 795 }
993 796
994 /* Find out if this is an ICMP packet in response to an existing 797 GNUNET_TUN_initialize_ipv4_header (pkt4,
995 TCP/UDP packet and if so, figure out ports / protocol of the 798 protocol,
996 existing session from the IP data in the ICMP payload */ 799 len,
997 source_port = 0; 800 &src_address->address.ipv4,
998 destination_port = 0; 801 &dst_address->address.ipv4);
999 switch (af)
1000 {
1001 case AF_INET:
1002 protocol = IPPROTO_ICMP;
1003 switch (icmp->type)
1004 {
1005 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1006 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1007 break;
1008 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1009 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1010 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1011 if (pktlen <
1012 sizeof (struct GNUNET_TUN_IcmpHeader) +
1013 sizeof (struct GNUNET_TUN_IPv4Header) + 8)
1014 {
1015 /* blame kernel */
1016 GNUNET_break (0);
1017 return;
1018 }
1019 ipv4 = (const struct GNUNET_TUN_IPv4Header *) &icmp[1];
1020 protocol = ipv4->protocol;
1021 /* could be TCP or UDP, but both have the ports in the right
1022 place, so that doesn't matter here */
1023 udp = (const struct GNUNET_TUN_UdpHeader *) &ipv4[1];
1024 /* swap ports, as they are from the original message */
1025 destination_port = ntohs (udp->source_port);
1026 source_port = ntohs (udp->destination_port);
1027 /* throw away ICMP payload, won't be useful for the other side anyway */
1028 pktlen = sizeof (struct GNUNET_TUN_IcmpHeader);
1029 break;
1030 default:
1031 GNUNET_STATISTICS_update (stats,
1032 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1033 1, GNUNET_NO);
1034 return;
1035 }
1036 break;
1037 case AF_INET6:
1038 protocol = IPPROTO_ICMPV6;
1039 switch (icmp->type)
1040 {
1041 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1042 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1043 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1044 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1045 if (pktlen <
1046 sizeof (struct GNUNET_TUN_IcmpHeader) +
1047 sizeof (struct GNUNET_TUN_IPv6Header) + 8)
1048 {
1049 /* blame kernel */
1050 GNUNET_break (0);
1051 return;
1052 }
1053 ipv6 = (const struct GNUNET_TUN_IPv6Header *) &icmp[1];
1054 protocol = ipv6->next_header;
1055 /* could be TCP or UDP, but both have the ports in the right
1056 place, so that doesn't matter here */
1057 udp = (const struct GNUNET_TUN_UdpHeader *) &ipv6[1];
1058 /* swap ports, as they are from the original message */
1059 destination_port = ntohs (udp->source_port);
1060 source_port = ntohs (udp->destination_port);
1061 /* throw away ICMP payload, won't be useful for the other side anyway */
1062 pktlen = sizeof (struct GNUNET_TUN_IcmpHeader);
1063 break;
1064 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1065 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1066 break;
1067 default:
1068 GNUNET_STATISTICS_update (stats,
1069 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1070 1, GNUNET_NO);
1071 return;
1072 }
1073 break;
1074 default:
1075 GNUNET_assert (0);
1076 }
1077 switch (protocol) 802 switch (protocol)
1078 { 803 {
1079 case IPPROTO_ICMP:
1080 state = get_redirect_state (af,
1081 IPPROTO_ICMP,
1082 source_ip,
1083 0,
1084 destination_ip,
1085 0,
1086 NULL);
1087 break;
1088 case IPPROTO_ICMPV6:
1089 state = get_redirect_state (af,
1090 IPPROTO_ICMPV6,
1091 source_ip,
1092 0,
1093 destination_ip,
1094 0,
1095 NULL);
1096 break;
1097 case IPPROTO_UDP: 804 case IPPROTO_UDP:
1098 state = get_redirect_state (af, 805 {
1099 IPPROTO_UDP, 806 struct GNUNET_TUN_UdpHeader *pkt4_udp = (struct GNUNET_TUN_UdpHeader *) &pkt4[1];
1100 source_ip, 807
1101 source_port, 808 pkt4_udp->source_port = htons (src_address->port);
1102 destination_ip, 809 pkt4_udp->destination_port = htons (dst_address->port);
1103 destination_port, 810 pkt4_udp->len = htons ((uint16_t) payload_length);
1104 NULL); 811 GNUNET_TUN_calculate_udp4_checksum (pkt4,
812 pkt4_udp,
813 payload,
814 payload_length);
815 GNUNET_memcpy (&pkt4_udp[1],
816 payload,
817 payload_length);
818 }
1105 break; 819 break;
1106 case IPPROTO_TCP: 820 case IPPROTO_TCP:
1107 state = get_redirect_state (af, 821 {
1108 IPPROTO_TCP, 822 struct GNUNET_TUN_TcpHeader *pkt4_tcp = (struct GNUNET_TUN_TcpHeader *) &pkt4[1];
1109 source_ip, 823
1110 source_port, 824 *pkt4_tcp = *tcp_header;
1111 destination_ip, 825 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1112 destination_port, 826 "Sending TCP packet from port %u to port %u\n",
1113 NULL); 827 src_address->port,
828 dst_address->port);
829 pkt4_tcp->source_port = htons (src_address->port);
830 pkt4_tcp->destination_port = htons (dst_address->port);
831 GNUNET_TUN_calculate_tcp4_checksum (pkt4,
832 pkt4_tcp,
833 payload,
834 payload_length);
835 GNUNET_memcpy (&pkt4_tcp[1],
836 payload,
837 payload_length);
838 }
1114 break; 839 break;
1115 default: 840 default:
1116 GNUNET_STATISTICS_update (stats, 841 GNUNET_assert (0);
1117 gettext_noop ("# ICMP packets dropped (not allowed)"),
1118 1,
1119 GNUNET_NO);
1120 return;
1121 }
1122 if (NULL == state)
1123 {
1124 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1125 _("ICMP Packet dropped, have no matching connection information\n"));
1126 return;
1127 } 842 }
1128 mlen = sizeof (struct GNUNET_EXIT_IcmpToVPNMessage) + pktlen - sizeof (struct GNUNET_TUN_IcmpHeader);
1129 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueue) + mlen);
1130 tnq->payload = &tnq[1];
1131 tnq->len = mlen;
1132 i2v = (struct GNUNET_EXIT_IcmpToVPNMessage *) &tnq[1];
1133 i2v->header.size = htons ((uint16_t) mlen);
1134 i2v->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_VPN);
1135 i2v->af = htonl (af);
1136 GNUNET_memcpy (&i2v->icmp_header,
1137 icmp,
1138 pktlen);
1139 send_packet_to_cadet_channel (state, tnq);
1140} 843}
1141 844
1142 845
1143/** 846/**
1144 * @brief Handles an UDP packet received from the helper. 847 * Prepare an IPv6 packet for transmission via the TUN interface.
848 * Initializes the IP header and calculates checksums (IP+UDP/TCP).
849 * For UDP, the UDP header will be fully created, whereas for TCP
850 * only the ports and checksum will be filled in. So for TCP,
851 * a skeleton TCP header must be part of the provided payload.
1145 * 852 *
1146 * @param udp A pointer to the Packet 853 * @param payload payload of the packet (starting with UDP payload or
1147 * @param pktlen number of bytes in 'udp' 854 * TCP header, depending on protocol)
1148 * @param af address family (AFINET or AF_INET6) 855 * @param payload_length number of bytes in @a payload
1149 * @param destination_ip destination IP-address of the IP packet (should 856 * @param protocol IPPROTO_UDP or IPPROTO_TCP
1150 * be our local address) 857 * @param tcp_header skeleton TCP header data to send, NULL for UDP
1151 * @param source_ip original source IP-address of the IP packet (should 858 * @param src_address source address to use (IP and port)
1152 * be the original destination address) 859 * @param dst_address destination address to use (IP and port)
860 * @param pkt6 where to write the assembled packet; must
861 * contain enough space for the IP header, UDP/TCP header
862 * AND the payload
1153 */ 863 */
1154static void 864static void
1155udp_from_helper (const struct GNUNET_TUN_UdpHeader *udp, 865prepare_ipv6_packet (const void *payload,
1156 size_t pktlen, 866 size_t payload_length,
1157 int af, 867 int protocol,
1158 const void *destination_ip, 868 const struct GNUNET_TUN_TcpHeader *tcp_header,
1159 const void *source_ip) 869 const struct SocketAddress *src_address,
870 const struct SocketAddress *dst_address,
871 struct GNUNET_TUN_IPv6Header *pkt6)
1160{ 872{
1161 struct ChannelState *state; 873 size_t len;
1162 struct ChannelMessageQueue *tnq;
1163 struct GNUNET_EXIT_UdpReplyMessage *urm;
1164 size_t mlen;
1165 874
875 len = payload_length;
876 switch (protocol)
1166 { 877 {
1167 char sbuf[INET6_ADDRSTRLEN]; 878 case IPPROTO_UDP:
1168 char dbuf[INET6_ADDRSTRLEN]; 879 len += sizeof (struct GNUNET_TUN_UdpHeader);
1169 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 880 break;
1170 "Received UDP packet going from %s:%u to %s:%u\n", 881 case IPPROTO_TCP:
1171 inet_ntop (af, 882 len += sizeof (struct GNUNET_TUN_TcpHeader);
1172 source_ip, 883 break;
1173 sbuf, sizeof (sbuf)), 884 default:
1174 (unsigned int) ntohs (udp->source_port),
1175 inet_ntop (af,
1176 destination_ip,
1177 dbuf, sizeof (dbuf)),
1178 (unsigned int) ntohs (udp->destination_port));
1179 }
1180 if (pktlen < sizeof (struct GNUNET_TUN_UdpHeader))
1181 {
1182 /* blame kernel */
1183 GNUNET_break (0); 885 GNUNET_break (0);
1184 return; 886 return;
1185 } 887 }
1186 if (pktlen != ntohs (udp->len)) 888 if (len > UINT16_MAX)
1187 { 889 {
1188 /* blame kernel */
1189 GNUNET_break (0); 890 GNUNET_break (0);
1190 return; 891 return;
1191 } 892 }
1192 state = get_redirect_state (af, 893
1193 IPPROTO_UDP, 894 GNUNET_TUN_initialize_ipv6_header (pkt6,
1194 source_ip, 895 protocol,
1195 ntohs (udp->source_port), 896 len,
1196 destination_ip, 897 &src_address->address.ipv6,
1197 ntohs (udp->destination_port), 898 &dst_address->address.ipv6);
1198 NULL); 899
1199 if (NULL == state) 900 switch (protocol)
1200 { 901 {
1201 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 902 case IPPROTO_UDP:
1202 _("UDP Packet dropped, have no matching connection information\n")); 903 {
1203 return; 904 struct GNUNET_TUN_UdpHeader *pkt6_udp = (struct GNUNET_TUN_UdpHeader *) &pkt6[1];
905
906 pkt6_udp->source_port = htons (src_address->port);
907 pkt6_udp->destination_port = htons (dst_address->port);
908 pkt6_udp->len = htons ((uint16_t) payload_length);
909 GNUNET_TUN_calculate_udp6_checksum (pkt6,
910 pkt6_udp,
911 payload,
912 payload_length);
913 GNUNET_memcpy (&pkt6_udp[1],
914 payload,
915 payload_length);
916 }
917 break;
918 case IPPROTO_TCP:
919 {
920 struct GNUNET_TUN_TcpHeader *pkt6_tcp = (struct GNUNET_TUN_TcpHeader *) &pkt6[1];
921
922 /* GNUNET_memcpy first here as some TCP header fields are initialized this way! */
923 *pkt6_tcp = *tcp_header;
924 pkt6_tcp->source_port = htons (src_address->port);
925 pkt6_tcp->destination_port = htons (dst_address->port);
926 GNUNET_TUN_calculate_tcp6_checksum (pkt6,
927 pkt6_tcp,
928 payload,
929 payload_length);
930 GNUNET_memcpy (&pkt6_tcp[1],
931 payload,
932 payload_length);
933 }
934 break;
935 default:
936 GNUNET_assert (0);
937 break;
1204 } 938 }
1205 mlen = sizeof (struct GNUNET_EXIT_UdpReplyMessage) + pktlen - sizeof (struct GNUNET_TUN_UdpHeader);
1206 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueue) + mlen);
1207 tnq->payload = &tnq[1];
1208 tnq->len = mlen;
1209 urm = (struct GNUNET_EXIT_UdpReplyMessage *) &tnq[1];
1210 urm->header.size = htons ((uint16_t) mlen);
1211 urm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_REPLY);
1212 urm->source_port = htons (0);
1213 urm->destination_port = htons (0);
1214 GNUNET_memcpy (&urm[1],
1215 &udp[1],
1216 pktlen - sizeof (struct GNUNET_TUN_UdpHeader));
1217 send_packet_to_cadet_channel (state, tnq);
1218} 939}
1219 940
1220 941
1221/** 942/**
1222 * @brief Handles a TCP packet received from the helper. 943 * Send a TCP packet via the TUN interface.
1223 * 944 *
1224 * @param tcp A pointer to the Packet 945 * @param destination_address IP and port to use for the TCP packet's destination
1225 * @param pktlen the length of the packet, including its TCP header 946 * @param source_address IP and port to use for the TCP packet's source
1226 * @param af address family (AFINET or AF_INET6) 947 * @param tcp_header header template to use
1227 * @param destination_ip destination IP-address of the IP packet (should 948 * @param payload payload of the TCP packet
1228 * be our local address) 949 * @param payload_length number of bytes in @a payload
1229 * @param source_ip original source IP-address of the IP packet (should
1230 * be the original destination address)
1231 */ 950 */
1232static void 951static void
1233tcp_from_helper (const struct GNUNET_TUN_TcpHeader *tcp, 952send_tcp_packet_via_tun (const struct SocketAddress *destination_address,
1234 size_t pktlen, 953 const struct SocketAddress *source_address,
1235 int af, 954 const struct GNUNET_TUN_TcpHeader *tcp_header,
1236 const void *destination_ip, 955 const void *payload,
1237 const void *source_ip) 956 size_t payload_length)
1238{ 957{
1239 struct ChannelState *state; 958 size_t len;
1240 char buf[pktlen] GNUNET_ALIGN;
1241 struct GNUNET_TUN_TcpHeader *mtcp;
1242 struct GNUNET_EXIT_TcpDataMessage *tdm;
1243 struct ChannelMessageQueue *tnq;
1244 size_t mlen;
1245 959
960 GNUNET_STATISTICS_update (stats,
961 gettext_noop ("# TCP packets sent via TUN"),
962 1,
963 GNUNET_NO);
964 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
965 "Sending packet with %u bytes TCP payload via TUN\n",
966 (unsigned int) payload_length);
967 len = sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader);
968 switch (source_address->af)
1246 { 969 {
1247 char sbuf[INET6_ADDRSTRLEN]; 970 case AF_INET:
1248 char dbuf[INET6_ADDRSTRLEN]; 971 len += sizeof (struct GNUNET_TUN_IPv4Header);
1249 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 972 break;
1250 "Received TCP packet with %u bytes going from %s:%u to %s:%u\n", 973 case AF_INET6:
1251 (unsigned int) (pktlen - sizeof (struct GNUNET_TUN_TcpHeader)), 974 len += sizeof (struct GNUNET_TUN_IPv6Header);
1252 inet_ntop (af, 975 break;
1253 source_ip, 976 default:
1254 sbuf, sizeof (sbuf)), 977 GNUNET_break (0);
1255 (unsigned int) ntohs (tcp->source_port), 978 return;
1256 inet_ntop (af,
1257 destination_ip,
1258 dbuf, sizeof (dbuf)),
1259 (unsigned int) ntohs (tcp->destination_port));
1260 } 979 }
1261 if (pktlen < sizeof (struct GNUNET_TUN_TcpHeader)) 980 len += sizeof (struct GNUNET_TUN_TcpHeader);
981 len += payload_length;
982 if (len >= GNUNET_MAX_MESSAGE_SIZE)
1262 { 983 {
1263 /* blame kernel */
1264 GNUNET_break (0); 984 GNUNET_break (0);
1265 return; 985 return;
1266 } 986 }
1267 state = get_redirect_state (af,
1268 IPPROTO_TCP,
1269 source_ip,
1270 ntohs (tcp->source_port),
1271 destination_ip,
1272 ntohs (tcp->destination_port),
1273 NULL);
1274 if (NULL == state)
1275 { 987 {
1276 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 988 char buf[len] GNUNET_ALIGN;
1277 _("TCP Packet dropped, have no matching connection information\n")); 989 struct GNUNET_MessageHeader *hdr;
990 struct GNUNET_TUN_Layer2PacketHeader *tun;
1278 991
1279 return; 992 hdr = (struct GNUNET_MessageHeader *) buf;
1280 } 993 hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1281 /* mug port numbers and crc to avoid information leakage; 994 hdr->size = htons (len);
1282 sender will need to lookup the correct values anyway */ 995 tun = (struct GNUNET_TUN_Layer2PacketHeader*) &hdr[1];
1283 GNUNET_memcpy (buf, tcp, pktlen); 996 tun->flags = htons (0);
1284 mtcp = (struct GNUNET_TUN_TcpHeader *) buf; 997 switch (source_address->af)
1285 mtcp->source_port = 0; 998 {
1286 mtcp->destination_port = 0; 999 case AF_INET:
1287 mtcp->crc = 0; 1000 {
1001 struct GNUNET_TUN_IPv4Header *ipv4
1002 = (struct GNUNET_TUN_IPv4Header*) &tun[1];
1288 1003
1289 mlen = sizeof (struct GNUNET_EXIT_TcpDataMessage) + (pktlen - sizeof (struct GNUNET_TUN_TcpHeader)); 1004 tun->proto = htons (ETH_P_IPV4);
1290 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) 1005 prepare_ipv4_packet (payload,
1291 { 1006 payload_length,
1292 GNUNET_break (0); 1007 IPPROTO_TCP,
1293 return; 1008 tcp_header,
1294 } 1009 source_address,
1010 destination_address,
1011 ipv4);
1012 }
1013 break;
1014 case AF_INET6:
1015 {
1016 struct GNUNET_TUN_IPv6Header *ipv6
1017 = (struct GNUNET_TUN_IPv6Header*) &tun[1];
1295 1018
1296 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueue) + mlen); 1019 tun->proto = htons (ETH_P_IPV6);
1297 tnq->payload = &tnq[1]; 1020 prepare_ipv6_packet (payload,
1298 tnq->len = mlen; 1021 payload_length,
1299 tdm = (struct GNUNET_EXIT_TcpDataMessage *) &tnq[1]; 1022 IPPROTO_TCP,
1300 tdm->header.size = htons ((uint16_t) mlen); 1023 tcp_header,
1301 tdm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_VPN); 1024 source_address,
1302 tdm->reserved = htonl (0); 1025 destination_address,
1303 GNUNET_memcpy (&tdm->tcp_header, 1026 ipv6);
1304 buf, 1027 }
1305 pktlen); 1028 break;
1306 send_packet_to_cadet_channel (state, tnq); 1029 default:
1030 GNUNET_assert (0);
1031 break;
1032 }
1033 if (NULL != helper_handle)
1034 (void) GNUNET_HELPER_send (helper_handle,
1035 (const struct GNUNET_MessageHeader*) buf,
1036 GNUNET_YES,
1037 NULL,
1038 NULL);
1039 }
1307} 1040}
1308 1041
1309 1042
1310/** 1043/**
1311 * Receive packets from the helper-process 1044 * Send an ICMP packet via the TUN interface.
1312 * 1045 *
1313 * @param cls unused 1046 * @param destination_address IP to use for the ICMP packet's destination
1314 * @param client unsued 1047 * @param source_address IP to use for the ICMP packet's source
1315 * @param message message received from helper 1048 * @param icmp_header ICMP header to send
1049 * @param payload payload of the ICMP packet (does NOT include ICMP header)
1050 * @param payload_length number of bytes of data in @a payload
1316 */ 1051 */
1317static int 1052static void
1318message_token (void *cls GNUNET_UNUSED, 1053send_icmp_packet_via_tun (const struct SocketAddress *destination_address,
1319 void *client GNUNET_UNUSED, 1054 const struct SocketAddress *source_address,
1320 const struct GNUNET_MessageHeader *message) 1055 const struct GNUNET_TUN_IcmpHeader *icmp_header,
1056 const void *payload, size_t payload_length)
1321{ 1057{
1322 const struct GNUNET_TUN_Layer2PacketHeader *pkt_tun; 1058 size_t len;
1323 size_t size; 1059 struct GNUNET_TUN_IcmpHeader *icmp;
1324 1060
1325 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1326 "Got %u-byte message of type %u from gnunet-helper-exit\n",
1327 ntohs (message->size),
1328 ntohs (message->type));
1329 GNUNET_STATISTICS_update (stats, 1061 GNUNET_STATISTICS_update (stats,
1330 gettext_noop ("# Packets received from TUN"), 1062 gettext_noop ("# ICMP packets sent via TUN"),
1331 1, GNUNET_NO); 1063 1, GNUNET_NO);
1332 if (ntohs (message->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER) 1064 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1065 "Sending packet with %u bytes ICMP payload via TUN\n",
1066 (unsigned int) payload_length);
1067 len = sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader);
1068 switch (destination_address->af)
1333 { 1069 {
1070 case AF_INET:
1071 len += sizeof (struct GNUNET_TUN_IPv4Header);
1072 break;
1073 case AF_INET6:
1074 len += sizeof (struct GNUNET_TUN_IPv6Header);
1075 break;
1076 default:
1334 GNUNET_break (0); 1077 GNUNET_break (0);
1335 return GNUNET_OK; 1078 return;
1336 } 1079 }
1337 size = ntohs (message->size); 1080 len += sizeof (struct GNUNET_TUN_IcmpHeader);
1338 if (size < sizeof (struct GNUNET_TUN_Layer2PacketHeader) + sizeof (struct GNUNET_MessageHeader)) 1081 len += payload_length;
1082 if (len >= GNUNET_MAX_MESSAGE_SIZE)
1339 { 1083 {
1340 GNUNET_break (0); 1084 GNUNET_break (0);
1341 return GNUNET_OK; 1085 return;
1342 } 1086 }
1343 GNUNET_STATISTICS_update (stats,
1344 gettext_noop ("# Bytes received from TUN"),
1345 size, GNUNET_NO);
1346 pkt_tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1];
1347 size -= sizeof (struct GNUNET_TUN_Layer2PacketHeader) + sizeof (struct GNUNET_MessageHeader);
1348 switch (ntohs (pkt_tun->proto))
1349 { 1087 {
1350 case ETH_P_IPV4: 1088 char buf[len] GNUNET_ALIGN;
1351 { 1089 struct GNUNET_MessageHeader *hdr;
1352 const struct GNUNET_TUN_IPv4Header *pkt4; 1090 struct GNUNET_TUN_Layer2PacketHeader *tun;
1353
1354 if (size < sizeof (struct GNUNET_TUN_IPv4Header))
1355 {
1356 /* Kernel to blame? */
1357 GNUNET_break (0);
1358 return GNUNET_OK;
1359 }
1360 pkt4 = (const struct GNUNET_TUN_IPv4Header *) &pkt_tun[1];
1361 if (size != ntohs (pkt4->total_length))
1362 {
1363 /* Kernel to blame? */
1364 GNUNET_break (0);
1365 return GNUNET_OK;
1366 }
1367 if (pkt4->header_length * 4 != sizeof (struct GNUNET_TUN_IPv4Header))
1368 {
1369 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1370 _("IPv4 packet options received. Ignored.\n"));
1371 return GNUNET_OK;
1372 }
1373 1091
1374 size -= sizeof (struct GNUNET_TUN_IPv4Header); 1092 hdr= (struct GNUNET_MessageHeader *) buf;
1375 switch (pkt4->protocol) 1093 hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1376 { 1094 hdr->size = htons (len);
1377 case IPPROTO_UDP: 1095 tun = (struct GNUNET_TUN_Layer2PacketHeader*) &hdr[1];
1378 udp_from_helper ((const struct GNUNET_TUN_UdpHeader *) &pkt4[1], size, 1096 tun->flags = htons (0);
1379 AF_INET, 1097 switch (source_address->af)
1380 &pkt4->destination_address,
1381 &pkt4->source_address);
1382 break;
1383 case IPPROTO_TCP:
1384 tcp_from_helper ((const struct GNUNET_TUN_TcpHeader *) &pkt4[1], size,
1385 AF_INET,
1386 &pkt4->destination_address,
1387 &pkt4->source_address);
1388 break;
1389 case IPPROTO_ICMP:
1390 icmp_from_helper ((const struct GNUNET_TUN_IcmpHeader *) &pkt4[1], size,
1391 AF_INET,
1392 &pkt4->destination_address,
1393 &pkt4->source_address);
1394 break;
1395 default:
1396 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1397 _("IPv4 packet with unsupported next header %u received. Ignored.\n"),
1398 (int) pkt4->protocol);
1399 return GNUNET_OK;
1400 }
1401 }
1402 break;
1403 case ETH_P_IPV6:
1404 { 1098 {
1405 const struct GNUNET_TUN_IPv6Header *pkt6; 1099 case AF_INET:
1406
1407 if (size < sizeof (struct GNUNET_TUN_IPv6Header))
1408 {
1409 /* Kernel to blame? */
1410 GNUNET_break (0);
1411 return GNUNET_OK;
1412 }
1413 pkt6 = (struct GNUNET_TUN_IPv6Header *) &pkt_tun[1];
1414 if (size != ntohs (pkt6->payload_length) + sizeof (struct GNUNET_TUN_IPv6Header))
1415 { 1100 {
1416 /* Kernel to blame? */ 1101 struct GNUNET_TUN_IPv4Header * ipv4 = (struct GNUNET_TUN_IPv4Header*) &tun[1];
1417 GNUNET_break (0); 1102
1418 return GNUNET_OK; 1103 tun->proto = htons (ETH_P_IPV4);
1104 GNUNET_TUN_initialize_ipv4_header (ipv4,
1105 IPPROTO_ICMP,
1106 sizeof (struct GNUNET_TUN_IcmpHeader) + payload_length,
1107 &source_address->address.ipv4,
1108 &destination_address->address.ipv4);
1109 icmp = (struct GNUNET_TUN_IcmpHeader*) &ipv4[1];
1419 } 1110 }
1420 size -= sizeof (struct GNUNET_TUN_IPv6Header); 1111 break;
1421 switch (pkt6->next_header) 1112 case AF_INET6:
1422 { 1113 {
1423 case IPPROTO_UDP: 1114 struct GNUNET_TUN_IPv6Header * ipv6 = (struct GNUNET_TUN_IPv6Header*) &tun[1];
1424 udp_from_helper ((const struct GNUNET_TUN_UdpHeader *) &pkt6[1], size, 1115
1425 AF_INET6, 1116 tun->proto = htons (ETH_P_IPV6);
1426 &pkt6->destination_address, 1117 GNUNET_TUN_initialize_ipv6_header (ipv6,
1427 &pkt6->source_address); 1118 IPPROTO_ICMPV6,
1428 break; 1119 sizeof (struct GNUNET_TUN_IcmpHeader) + payload_length,
1429 case IPPROTO_TCP: 1120 &source_address->address.ipv6,
1430 tcp_from_helper ((const struct GNUNET_TUN_TcpHeader *) &pkt6[1], size, 1121 &destination_address->address.ipv6);
1431 AF_INET6, 1122 icmp = (struct GNUNET_TUN_IcmpHeader*) &ipv6[1];
1432 &pkt6->destination_address,
1433 &pkt6->source_address);
1434 break;
1435 case IPPROTO_ICMPV6:
1436 icmp_from_helper ((const struct GNUNET_TUN_IcmpHeader *) &pkt6[1], size,
1437 AF_INET6,
1438 &pkt6->destination_address,
1439 &pkt6->source_address);
1440 break;
1441 default:
1442 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1443 _("IPv6 packet with unsupported next header %d received. Ignored.\n"),
1444 pkt6->next_header);
1445 return GNUNET_OK;
1446 } 1123 }
1124 break;
1125 default:
1126 GNUNET_assert (0);
1127 break;
1447 } 1128 }
1448 break; 1129 *icmp = *icmp_header;
1449 default: 1130 GNUNET_memcpy (&icmp[1],
1450 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1131 payload,
1451 _("Packet from unknown protocol %u received. Ignored.\n"), 1132 payload_length);
1452 ntohs (pkt_tun->proto)); 1133 GNUNET_TUN_calculate_icmp_checksum (icmp,
1453 break; 1134 payload,
1135 payload_length);
1136 if (NULL != helper_handle)
1137 (void) GNUNET_HELPER_send (helper_handle,
1138 (const struct GNUNET_MessageHeader*) buf,
1139 GNUNET_YES,
1140 NULL, NULL);
1454 } 1141 }
1455 return GNUNET_OK;
1456} 1142}
1457 1143
1458 1144
@@ -1637,223 +1323,25 @@ setup_state_record (struct ChannelState *state)
1637 1323
1638 1324
1639/** 1325/**
1640 * Prepare an IPv4 packet for transmission via the TUN interface. 1326 * Send a UDP packet via the TUN interface.
1641 * Initializes the IP header and calculates checksums (IP+UDP/TCP).
1642 * For UDP, the UDP header will be fully created, whereas for TCP
1643 * only the ports and checksum will be filled in. So for TCP,
1644 * a skeleton TCP header must be part of the provided payload.
1645 *
1646 * @param payload payload of the packet (starting with UDP payload or
1647 * TCP header, depending on protocol)
1648 * @param payload_length number of bytes in @a payload
1649 * @param protocol IPPROTO_UDP or IPPROTO_TCP
1650 * @param tcp_header skeleton of the TCP header, NULL for UDP
1651 * @param src_address source address to use (IP and port)
1652 * @param dst_address destination address to use (IP and port)
1653 * @param pkt4 where to write the assembled packet; must
1654 * contain enough space for the IP header, UDP/TCP header
1655 * AND the payload
1656 */
1657static void
1658prepare_ipv4_packet (const void *payload,
1659 size_t payload_length,
1660 int protocol,
1661 const struct GNUNET_TUN_TcpHeader *tcp_header,
1662 const struct SocketAddress *src_address,
1663 const struct SocketAddress *dst_address,
1664 struct GNUNET_TUN_IPv4Header *pkt4)
1665{
1666 size_t len;
1667
1668 len = payload_length;
1669 switch (protocol)
1670 {
1671 case IPPROTO_UDP:
1672 len += sizeof (struct GNUNET_TUN_UdpHeader);
1673 break;
1674 case IPPROTO_TCP:
1675 len += sizeof (struct GNUNET_TUN_TcpHeader);
1676 GNUNET_assert (NULL != tcp_header);
1677 break;
1678 default:
1679 GNUNET_break (0);
1680 return;
1681 }
1682 if (len + sizeof (struct GNUNET_TUN_IPv4Header) > UINT16_MAX)
1683 {
1684 GNUNET_break (0);
1685 return;
1686 }
1687
1688 GNUNET_TUN_initialize_ipv4_header (pkt4,
1689 protocol,
1690 len,
1691 &src_address->address.ipv4,
1692 &dst_address->address.ipv4);
1693 switch (protocol)
1694 {
1695 case IPPROTO_UDP:
1696 {
1697 struct GNUNET_TUN_UdpHeader *pkt4_udp = (struct GNUNET_TUN_UdpHeader *) &pkt4[1];
1698
1699 pkt4_udp->source_port = htons (src_address->port);
1700 pkt4_udp->destination_port = htons (dst_address->port);
1701 pkt4_udp->len = htons ((uint16_t) payload_length);
1702 GNUNET_TUN_calculate_udp4_checksum (pkt4,
1703 pkt4_udp,
1704 payload,
1705 payload_length);
1706 GNUNET_memcpy (&pkt4_udp[1],
1707 payload,
1708 payload_length);
1709 }
1710 break;
1711 case IPPROTO_TCP:
1712 {
1713 struct GNUNET_TUN_TcpHeader *pkt4_tcp = (struct GNUNET_TUN_TcpHeader *) &pkt4[1];
1714
1715 *pkt4_tcp = *tcp_header;
1716 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1717 "Sending TCP packet from port %u to port %u\n",
1718 src_address->port,
1719 dst_address->port);
1720 pkt4_tcp->source_port = htons (src_address->port);
1721 pkt4_tcp->destination_port = htons (dst_address->port);
1722 GNUNET_TUN_calculate_tcp4_checksum (pkt4,
1723 pkt4_tcp,
1724 payload,
1725 payload_length);
1726 GNUNET_memcpy (&pkt4_tcp[1],
1727 payload,
1728 payload_length);
1729 }
1730 break;
1731 default:
1732 GNUNET_assert (0);
1733 }
1734}
1735
1736
1737/**
1738 * Prepare an IPv6 packet for transmission via the TUN interface.
1739 * Initializes the IP header and calculates checksums (IP+UDP/TCP).
1740 * For UDP, the UDP header will be fully created, whereas for TCP
1741 * only the ports and checksum will be filled in. So for TCP,
1742 * a skeleton TCP header must be part of the provided payload.
1743 *
1744 * @param payload payload of the packet (starting with UDP payload or
1745 * TCP header, depending on protocol)
1746 * @param payload_length number of bytes in @a payload
1747 * @param protocol IPPROTO_UDP or IPPROTO_TCP
1748 * @param tcp_header skeleton TCP header data to send, NULL for UDP
1749 * @param src_address source address to use (IP and port)
1750 * @param dst_address destination address to use (IP and port)
1751 * @param pkt6 where to write the assembled packet; must
1752 * contain enough space for the IP header, UDP/TCP header
1753 * AND the payload
1754 */
1755static void
1756prepare_ipv6_packet (const void *payload,
1757 size_t payload_length,
1758 int protocol,
1759 const struct GNUNET_TUN_TcpHeader *tcp_header,
1760 const struct SocketAddress *src_address,
1761 const struct SocketAddress *dst_address,
1762 struct GNUNET_TUN_IPv6Header *pkt6)
1763{
1764 size_t len;
1765
1766 len = payload_length;
1767 switch (protocol)
1768 {
1769 case IPPROTO_UDP:
1770 len += sizeof (struct GNUNET_TUN_UdpHeader);
1771 break;
1772 case IPPROTO_TCP:
1773 len += sizeof (struct GNUNET_TUN_TcpHeader);
1774 break;
1775 default:
1776 GNUNET_break (0);
1777 return;
1778 }
1779 if (len > UINT16_MAX)
1780 {
1781 GNUNET_break (0);
1782 return;
1783 }
1784
1785 GNUNET_TUN_initialize_ipv6_header (pkt6,
1786 protocol,
1787 len,
1788 &src_address->address.ipv6,
1789 &dst_address->address.ipv6);
1790
1791 switch (protocol)
1792 {
1793 case IPPROTO_UDP:
1794 {
1795 struct GNUNET_TUN_UdpHeader *pkt6_udp = (struct GNUNET_TUN_UdpHeader *) &pkt6[1];
1796
1797 pkt6_udp->source_port = htons (src_address->port);
1798 pkt6_udp->destination_port = htons (dst_address->port);
1799 pkt6_udp->len = htons ((uint16_t) payload_length);
1800 GNUNET_TUN_calculate_udp6_checksum (pkt6,
1801 pkt6_udp,
1802 payload,
1803 payload_length);
1804 GNUNET_memcpy (&pkt6_udp[1],
1805 payload,
1806 payload_length);
1807 }
1808 break;
1809 case IPPROTO_TCP:
1810 {
1811 struct GNUNET_TUN_TcpHeader *pkt6_tcp = (struct GNUNET_TUN_TcpHeader *) &pkt6[1];
1812
1813 /* GNUNET_memcpy first here as some TCP header fields are initialized this way! */
1814 *pkt6_tcp = *tcp_header;
1815 pkt6_tcp->source_port = htons (src_address->port);
1816 pkt6_tcp->destination_port = htons (dst_address->port);
1817 GNUNET_TUN_calculate_tcp6_checksum (pkt6,
1818 pkt6_tcp,
1819 payload,
1820 payload_length);
1821 GNUNET_memcpy (&pkt6_tcp[1],
1822 payload,
1823 payload_length);
1824 }
1825 break;
1826 default:
1827 GNUNET_assert (0);
1828 break;
1829 }
1830}
1831
1832
1833/**
1834 * Send a TCP packet via the TUN interface.
1835 * 1327 *
1836 * @param destination_address IP and port to use for the TCP packet's destination 1328 * @param destination_address IP and port to use for the UDP packet's destination
1837 * @param source_address IP and port to use for the TCP packet's source 1329 * @param source_address IP and port to use for the UDP packet's source
1838 * @param tcp_header header template to use 1330 * @param payload payload of the UDP packet (does NOT include UDP header)
1839 * @param payload payload of the TCP packet 1331 * @param payload_length number of bytes of data in @a payload
1840 * @param payload_length number of bytes in @a payload
1841 */ 1332 */
1842static void 1333static void
1843send_tcp_packet_via_tun (const struct SocketAddress *destination_address, 1334send_udp_packet_via_tun (const struct SocketAddress *destination_address,
1844 const struct SocketAddress *source_address, 1335 const struct SocketAddress *source_address,
1845 const struct GNUNET_TUN_TcpHeader *tcp_header, 1336 const void *payload, size_t payload_length)
1846 const void *payload,
1847 size_t payload_length)
1848{ 1337{
1849 size_t len; 1338 size_t len;
1850 1339
1851 GNUNET_STATISTICS_update (stats, 1340 GNUNET_STATISTICS_update (stats,
1852 gettext_noop ("# TCP packets sent via TUN"), 1341 gettext_noop ("# UDP packets sent via TUN"),
1853 1, 1342 1, GNUNET_NO);
1854 GNUNET_NO);
1855 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1343 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1856 "Sending packet with %u bytes TCP payload via TUN\n", 1344 "Sending packet with %u bytes UDP payload via TUN\n",
1857 (unsigned int) payload_length); 1345 (unsigned int) payload_length);
1858 len = sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader); 1346 len = sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader);
1859 switch (source_address->af) 1347 switch (source_address->af)
@@ -1868,9 +1356,9 @@ send_tcp_packet_via_tun (const struct SocketAddress *destination_address,
1868 GNUNET_break (0); 1356 GNUNET_break (0);
1869 return; 1357 return;
1870 } 1358 }
1871 len += sizeof (struct GNUNET_TUN_TcpHeader); 1359 len += sizeof (struct GNUNET_TUN_UdpHeader);
1872 len += payload_length; 1360 len += payload_length;
1873 if (len >= GNUNET_SERVER_MAX_MESSAGE_SIZE) 1361 if (len >= GNUNET_MAX_MESSAGE_SIZE)
1874 { 1362 {
1875 GNUNET_break (0); 1363 GNUNET_break (0);
1876 return; 1364 return;
@@ -1880,7 +1368,7 @@ send_tcp_packet_via_tun (const struct SocketAddress *destination_address,
1880 struct GNUNET_MessageHeader *hdr; 1368 struct GNUNET_MessageHeader *hdr;
1881 struct GNUNET_TUN_Layer2PacketHeader *tun; 1369 struct GNUNET_TUN_Layer2PacketHeader *tun;
1882 1370
1883 hdr = (struct GNUNET_MessageHeader *) buf; 1371 hdr= (struct GNUNET_MessageHeader *) buf;
1884 hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); 1372 hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1885 hdr->size = htons (len); 1373 hdr->size = htons (len);
1886 tun = (struct GNUNET_TUN_Layer2PacketHeader*) &hdr[1]; 1374 tun = (struct GNUNET_TUN_Layer2PacketHeader*) &hdr[1];
@@ -1889,14 +1377,13 @@ send_tcp_packet_via_tun (const struct SocketAddress *destination_address,
1889 { 1377 {
1890 case AF_INET: 1378 case AF_INET:
1891 { 1379 {
1892 struct GNUNET_TUN_IPv4Header *ipv4 1380 struct GNUNET_TUN_IPv4Header * ipv4 = (struct GNUNET_TUN_IPv4Header*) &tun[1];
1893 = (struct GNUNET_TUN_IPv4Header*) &tun[1];
1894 1381
1895 tun->proto = htons (ETH_P_IPV4); 1382 tun->proto = htons (ETH_P_IPV4);
1896 prepare_ipv4_packet (payload, 1383 prepare_ipv4_packet (payload,
1897 payload_length, 1384 payload_length,
1898 IPPROTO_TCP, 1385 IPPROTO_UDP,
1899 tcp_header, 1386 NULL,
1900 source_address, 1387 source_address,
1901 destination_address, 1388 destination_address,
1902 ipv4); 1389 ipv4);
@@ -1904,14 +1391,13 @@ send_tcp_packet_via_tun (const struct SocketAddress *destination_address,
1904 break; 1391 break;
1905 case AF_INET6: 1392 case AF_INET6:
1906 { 1393 {
1907 struct GNUNET_TUN_IPv6Header *ipv6 1394 struct GNUNET_TUN_IPv6Header * ipv6 = (struct GNUNET_TUN_IPv6Header*) &tun[1];
1908 = (struct GNUNET_TUN_IPv6Header*) &tun[1];
1909 1395
1910 tun->proto = htons (ETH_P_IPV6); 1396 tun->proto = htons (ETH_P_IPV6);
1911 prepare_ipv6_packet (payload, 1397 prepare_ipv6_packet (payload,
1912 payload_length, 1398 payload_length,
1913 IPPROTO_TCP, 1399 IPPROTO_UDP,
1914 tcp_header, 1400 NULL,
1915 source_address, 1401 source_address,
1916 destination_address, 1402 destination_address,
1917 ipv6); 1403 ipv6);
@@ -1925,48 +1411,202 @@ send_tcp_packet_via_tun (const struct SocketAddress *destination_address,
1925 (void) GNUNET_HELPER_send (helper_handle, 1411 (void) GNUNET_HELPER_send (helper_handle,
1926 (const struct GNUNET_MessageHeader*) buf, 1412 (const struct GNUNET_MessageHeader*) buf,
1927 GNUNET_YES, 1413 GNUNET_YES,
1928 NULL, 1414 NULL, NULL);
1929 NULL);
1930 } 1415 }
1931} 1416}
1932 1417
1933 1418
1934/** 1419/**
1935 * Process a request via cadet to send a request to a TCP service 1420 * Check a request to forward UDP data to the Internet via this peer.
1936 * offered by this system.
1937 * 1421 *
1938 * @param cls closure, NULL 1422 * @param cls our `struct ChannelState *`
1939 * @param channel connection to the other end 1423 * @param msg the actual message
1940 * @param channel_ctx pointer to our `struct ChannelState *`
1941 * @param message the actual message
1942 * @return #GNUNET_OK to keep the connection open, 1424 * @return #GNUNET_OK to keep the connection open,
1943 * #GNUNET_SYSERR to close it (signal serious error) 1425 * #GNUNET_SYSERR to close it (signal serious error)
1944 */ 1426 */
1945static int 1427static int
1946receive_tcp_service (void *cls, 1428check_udp_remote (void *cls,
1947 struct GNUNET_CADET_Channel *channel, 1429 const struct GNUNET_EXIT_UdpInternetMessage *msg)
1948 void **channel_ctx,
1949 const struct GNUNET_MessageHeader *message)
1950{ 1430{
1951 struct ChannelState *state = *channel_ctx; 1431 struct ChannelState *state = cls;
1952 const struct GNUNET_EXIT_TcpServiceStartMessage *start;
1953 uint16_t pkt_len = ntohs (message->size);
1954 1432
1955 if (NULL == state) 1433 if (GNUNET_YES == state->is_dns)
1956 { 1434 {
1957 GNUNET_break_op (0); 1435 GNUNET_break_op (0);
1958 return GNUNET_SYSERR; 1436 return GNUNET_SYSERR;
1959 } 1437 }
1960 if (GNUNET_YES == state->is_dns) 1438 return GNUNET_OK;
1439}
1440
1441
1442/**
1443 * Process a request to forward UDP data to the Internet via this peer.
1444 *
1445 * @param cls our `struct ChannelState *`
1446 * @param msg the actual message
1447 */
1448static void
1449handle_udp_remote (void *cls,
1450 const struct GNUNET_EXIT_UdpInternetMessage *msg)
1451{
1452 struct ChannelState *state = cls;
1453 uint16_t pkt_len = ntohs (msg->header.size) - sizeof (struct GNUNET_EXIT_UdpInternetMessage);
1454 const struct in_addr *v4;
1455 const struct in6_addr *v6;
1456 const void *payload;
1457 int af;
1458
1459 if (GNUNET_SYSERR == state->is_dns)
1460 {
1461 /* channel is UDP/TCP from now on */
1462 state->is_dns = GNUNET_NO;
1463 }
1464 GNUNET_STATISTICS_update (stats,
1465 gettext_noop ("# Bytes received from CADET"),
1466 pkt_len, GNUNET_NO);
1467 GNUNET_STATISTICS_update (stats,
1468 gettext_noop ("# UDP IP-exit requests received via cadet"),
1469 1, GNUNET_NO);
1470 af = (int) ntohl (msg->af);
1471 state->specifics.tcp_udp.ri.remote_address.af = af;
1472 switch (af)
1961 { 1473 {
1474 case AF_INET:
1475 if (pkt_len < sizeof (struct in_addr))
1476 {
1477 GNUNET_break_op (0);
1478 return;
1479 }
1480 if (! ipv4_exit)
1481 {
1482 GNUNET_break_op (0);
1483 return;
1484 }
1485 v4 = (const struct in_addr*) &msg[1];
1486 payload = &v4[1];
1487 pkt_len -= sizeof (struct in_addr);
1488 state->specifics.tcp_udp.ri.remote_address.address.ipv4 = *v4;
1489 break;
1490 case AF_INET6:
1491 if (pkt_len < sizeof (struct in6_addr))
1492 {
1493 GNUNET_break_op (0);
1494 return;
1495 }
1496 if (! ipv6_exit)
1497 {
1498 GNUNET_break_op (0);
1499 return;
1500 }
1501 v6 = (const struct in6_addr*) &msg[1];
1502 payload = &v6[1];
1503 pkt_len -= sizeof (struct in6_addr);
1504 state->specifics.tcp_udp.ri.remote_address.address.ipv6 = *v6;
1505 break;
1506 default:
1962 GNUNET_break_op (0); 1507 GNUNET_break_op (0);
1963 return GNUNET_SYSERR; 1508 return;
1509 }
1510 {
1511 char buf[INET6_ADDRSTRLEN];
1512 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1513 "Received data from %s for forwarding to UDP %s:%u\n",
1514 GNUNET_i2s (&state->peer),
1515 inet_ntop (af,
1516 &state->specifics.tcp_udp.ri.remote_address.address,
1517 buf, sizeof (buf)),
1518 (unsigned int) ntohs (msg->destination_port));
1964 } 1519 }
1520 state->specifics.tcp_udp.ri.remote_address.proto = IPPROTO_UDP;
1521 state->specifics.tcp_udp.ri.remote_address.port = msg->destination_port;
1522 if (NULL == state->specifics.tcp_udp.heap_node)
1523 setup_state_record (state);
1524 if (0 != ntohs (msg->source_port))
1525 state->specifics.tcp_udp.ri.local_address.port = msg->source_port;
1526 send_udp_packet_via_tun (&state->specifics.tcp_udp.ri.remote_address,
1527 &state->specifics.tcp_udp.ri.local_address,
1528 payload,
1529 pkt_len);
1530 GNUNET_CADET_receive_done (state->channel);
1531}
1532
1533
1534/**
1535 * Check a request via cadet to send a request to a UDP service
1536 * offered by this system.
1537 *
1538 * @param cls our `struct ChannelState *`
1539 * @param msg the actual message
1540 * @return #GNUNET_OK to keep the connection open,
1541 * #GNUNET_SYSERR to close it (signal serious error)
1542 */
1543static int
1544check_udp_service (void *cls,
1545 const struct GNUNET_EXIT_UdpServiceMessage *msg)
1546{
1547 struct ChannelState *state = cls;
1548
1965 if (NULL == state->specifics.tcp_udp.serv) 1549 if (NULL == state->specifics.tcp_udp.serv)
1966 { 1550 {
1967 GNUNET_break_op (0); 1551 GNUNET_break_op (0);
1968 return GNUNET_SYSERR; 1552 return GNUNET_SYSERR;
1969 } 1553 }
1554 return GNUNET_OK;
1555}
1556
1557
1558/**
1559 * Process a request via cadet to send a request to a UDP service
1560 * offered by this system.
1561 *
1562 * @param cls our `struct ChannelState *`
1563 * @param msg the actual message
1564 */
1565static void
1566handle_udp_service (void *cls,
1567 const struct GNUNET_EXIT_UdpServiceMessage *msg)
1568{
1569 struct ChannelState *state = cls;
1570 uint16_t pkt_len = ntohs (msg->header.size) - sizeof (struct GNUNET_EXIT_UdpServiceMessage);
1571
1572 GNUNET_STATISTICS_update (stats,
1573 gettext_noop ("# Bytes received from CADET"),
1574 pkt_len, GNUNET_NO);
1575 GNUNET_STATISTICS_update (stats,
1576 gettext_noop ("# UDP service requests received via cadet"),
1577 1, GNUNET_NO);
1578 LOG (GNUNET_ERROR_TYPE_DEBUG,
1579 "Received data from %s for forwarding to UDP service %s on port %u\n",
1580 GNUNET_i2s (&state->peer),
1581 GNUNET_h2s (&state->specifics.tcp_udp.serv->descriptor),
1582 (unsigned int) ntohs (msg->destination_port));
1583 setup_state_record (state);
1584 if (0 != ntohs (msg->source_port))
1585 state->specifics.tcp_udp.ri.local_address.port = msg->source_port;
1586 send_udp_packet_via_tun (&state->specifics.tcp_udp.ri.remote_address,
1587 &state->specifics.tcp_udp.ri.local_address,
1588 &msg[1],
1589 pkt_len);
1590 GNUNET_CADET_receive_done (state->channel);
1591}
1592
1593
1594/**
1595 * Process a request via cadet to send a request to a TCP service
1596 * offered by this system.
1597 *
1598 * @param cls our `struct ChannelState *`
1599 * @param start the actual message
1600 * @return #GNUNET_OK to keep the connection open,
1601 * #GNUNET_SYSERR to close it (signal serious error)
1602 */
1603static void
1604handle_tcp_service (void *cls,
1605 const struct GNUNET_EXIT_TcpServiceStartMessage *start)
1606{
1607 struct ChannelState *state = cls;
1608 uint16_t pkt_len = ntohs (start->header.size) - sizeof (struct GNUNET_EXIT_TcpServiceStartMessage);
1609
1970 if (GNUNET_SYSERR == state->is_dns) 1610 if (GNUNET_SYSERR == state->is_dns)
1971 { 1611 {
1972 /* channel is UDP/TCP from now on */ 1612 /* channel is UDP/TCP from now on */
@@ -1980,24 +1620,6 @@ receive_tcp_service (void *cls,
1980 gettext_noop ("# Bytes received from CADET"), 1620 gettext_noop ("# Bytes received from CADET"),
1981 pkt_len, 1621 pkt_len,
1982 GNUNET_NO); 1622 GNUNET_NO);
1983 /* check that we got at least a valid header */
1984 if (pkt_len < sizeof (struct GNUNET_EXIT_TcpServiceStartMessage))
1985 {
1986 GNUNET_break_op (0);
1987 return GNUNET_SYSERR;
1988 }
1989 start = (const struct GNUNET_EXIT_TcpServiceStartMessage*) message;
1990 pkt_len -= sizeof (struct GNUNET_EXIT_TcpServiceStartMessage);
1991 if (NULL != state->specifics.tcp_udp.heap_node)
1992 {
1993 GNUNET_break_op (0);
1994 return GNUNET_SYSERR;
1995 }
1996 if (start->tcp_header.off * 4 < sizeof (struct GNUNET_TUN_TcpHeader))
1997 {
1998 GNUNET_break_op (0);
1999 return GNUNET_SYSERR;
2000 }
2001 GNUNET_break_op (ntohl (start->reserved) == 0); 1623 GNUNET_break_op (ntohl (start->reserved) == 0);
2002 /* setup fresh connection */ 1624 /* setup fresh connection */
2003 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1625 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -2011,34 +1633,23 @@ receive_tcp_service (void *cls,
2011 &start->tcp_header, 1633 &start->tcp_header,
2012 &start[1], 1634 &start[1],
2013 pkt_len); 1635 pkt_len);
2014 GNUNET_CADET_receive_done (channel); 1636 GNUNET_CADET_receive_done (state->channel);
2015 return GNUNET_YES;
2016} 1637}
2017 1638
2018 1639
2019/** 1640/**
2020 * Process a request to forward TCP data to the Internet via this peer. 1641 * Check a request to forward TCP data to the Internet via this peer.
2021 * 1642 *
2022 * @param cls closure, NULL 1643 * @param cls our `struct ChannelState *`
2023 * @param channel connection to the other end 1644 * @param start the actual message
2024 * @param channel_ctx pointer to our `struct ChannelState *`
2025 * @param message the actual message
2026 * @return #GNUNET_OK to keep the connection open, 1645 * @return #GNUNET_OK to keep the connection open,
2027 * #GNUNET_SYSERR to close it (signal serious error) 1646 * #GNUNET_SYSERR to close it (signal serious error)
2028 */ 1647 */
2029static int 1648static int
2030receive_tcp_remote (void *cls GNUNET_UNUSED, 1649check_tcp_remote (void *cls,
2031 struct GNUNET_CADET_Channel *channel, 1650 const struct GNUNET_EXIT_TcpInternetStartMessage *start)
2032 void **channel_ctx GNUNET_UNUSED,
2033 const struct GNUNET_MessageHeader *message)
2034{ 1651{
2035 struct ChannelState *state = *channel_ctx; 1652 struct ChannelState *state = cls;
2036 const struct GNUNET_EXIT_TcpInternetStartMessage *start;
2037 uint16_t pkt_len = ntohs (message->size);
2038 const struct in_addr *v4;
2039 const struct in6_addr *v6;
2040 const void *payload;
2041 int af;
2042 1653
2043 if (NULL == state) 1654 if (NULL == state)
2044 { 1655 {
@@ -2050,24 +1661,6 @@ receive_tcp_remote (void *cls GNUNET_UNUSED,
2050 GNUNET_break_op (0); 1661 GNUNET_break_op (0);
2051 return GNUNET_SYSERR; 1662 return GNUNET_SYSERR;
2052 } 1663 }
2053 if (GNUNET_SYSERR == state->is_dns)
2054 {
2055 /* channel is UDP/TCP from now on */
2056 state->is_dns = GNUNET_NO;
2057 }
2058 GNUNET_STATISTICS_update (stats,
2059 gettext_noop ("# Bytes received from CADET"),
2060 pkt_len, GNUNET_NO);
2061 GNUNET_STATISTICS_update (stats,
2062 gettext_noop ("# TCP IP-exit creation requests received via cadet"),
2063 1, GNUNET_NO);
2064 if (pkt_len < sizeof (struct GNUNET_EXIT_TcpInternetStartMessage))
2065 {
2066 GNUNET_break_op (0);
2067 return GNUNET_SYSERR;
2068 }
2069 start = (const struct GNUNET_EXIT_TcpInternetStartMessage*) message;
2070 pkt_len -= sizeof (struct GNUNET_EXIT_TcpInternetStartMessage);
2071 if ( (NULL != state->specifics.tcp_udp.serv) || 1664 if ( (NULL != state->specifics.tcp_udp.serv) ||
2072 (NULL != state->specifics.tcp_udp.heap_node) ) 1665 (NULL != state->specifics.tcp_udp.heap_node) )
2073 { 1666 {
@@ -2079,6 +1672,38 @@ receive_tcp_remote (void *cls GNUNET_UNUSED,
2079 GNUNET_break_op (0); 1672 GNUNET_break_op (0);
2080 return GNUNET_SYSERR; 1673 return GNUNET_SYSERR;
2081 } 1674 }
1675 return GNUNET_OK;
1676}
1677
1678
1679/**
1680 * Process a request to forward TCP data to the Internet via this peer.
1681 *
1682 * @param cls our `struct ChannelState *`
1683 * @param start the actual message
1684 */
1685static void
1686handle_tcp_remote (void *cls,
1687 const struct GNUNET_EXIT_TcpInternetStartMessage *start)
1688{
1689 struct ChannelState *state = cls;
1690 uint16_t pkt_len = ntohs (start->header.size) - sizeof (struct GNUNET_EXIT_TcpInternetStartMessage);
1691 const struct in_addr *v4;
1692 const struct in6_addr *v6;
1693 const void *payload;
1694 int af;
1695
1696 if (GNUNET_SYSERR == state->is_dns)
1697 {
1698 /* channel is UDP/TCP from now on */
1699 state->is_dns = GNUNET_NO;
1700 }
1701 GNUNET_STATISTICS_update (stats,
1702 gettext_noop ("# Bytes received from CADET"),
1703 pkt_len, GNUNET_NO);
1704 GNUNET_STATISTICS_update (stats,
1705 gettext_noop ("# TCP IP-exit creation requests received via cadet"),
1706 1, GNUNET_NO);
2082 af = (int) ntohl (start->af); 1707 af = (int) ntohl (start->af);
2083 state->specifics.tcp_udp.ri.remote_address.af = af; 1708 state->specifics.tcp_udp.ri.remote_address.af = af;
2084 switch (af) 1709 switch (af)
@@ -2087,12 +1712,12 @@ receive_tcp_remote (void *cls GNUNET_UNUSED,
2087 if (pkt_len < sizeof (struct in_addr)) 1712 if (pkt_len < sizeof (struct in_addr))
2088 { 1713 {
2089 GNUNET_break_op (0); 1714 GNUNET_break_op (0);
2090 return GNUNET_SYSERR; 1715 return;
2091 } 1716 }
2092 if (! ipv4_exit) 1717 if (! ipv4_exit)
2093 { 1718 {
2094 GNUNET_break_op (0); 1719 GNUNET_break_op (0);
2095 return GNUNET_SYSERR; 1720 return;
2096 } 1721 }
2097 v4 = (const struct in_addr*) &start[1]; 1722 v4 = (const struct in_addr*) &start[1];
2098 payload = &v4[1]; 1723 payload = &v4[1];
@@ -2103,12 +1728,12 @@ receive_tcp_remote (void *cls GNUNET_UNUSED,
2103 if (pkt_len < sizeof (struct in6_addr)) 1728 if (pkt_len < sizeof (struct in6_addr))
2104 { 1729 {
2105 GNUNET_break_op (0); 1730 GNUNET_break_op (0);
2106 return GNUNET_SYSERR; 1731 return;
2107 } 1732 }
2108 if (! ipv6_exit) 1733 if (! ipv6_exit)
2109 { 1734 {
2110 GNUNET_break_op (0); 1735 GNUNET_break_op (0);
2111 return GNUNET_SYSERR; 1736 return;
2112 } 1737 }
2113 v6 = (const struct in6_addr*) &start[1]; 1738 v6 = (const struct in6_addr*) &start[1];
2114 payload = &v6[1]; 1739 payload = &v6[1];
@@ -2117,7 +1742,7 @@ receive_tcp_remote (void *cls GNUNET_UNUSED,
2117 break; 1742 break;
2118 default: 1743 default:
2119 GNUNET_break_op (0); 1744 GNUNET_break_op (0);
2120 return GNUNET_SYSERR; 1745 return;
2121 } 1746 }
2122 { 1747 {
2123 char buf[INET6_ADDRSTRLEN]; 1748 char buf[INET6_ADDRSTRLEN];
@@ -2135,46 +1760,27 @@ receive_tcp_remote (void *cls GNUNET_UNUSED,
2135 send_tcp_packet_via_tun (&state->specifics.tcp_udp.ri.remote_address, 1760 send_tcp_packet_via_tun (&state->specifics.tcp_udp.ri.remote_address,
2136 &state->specifics.tcp_udp.ri.local_address, 1761 &state->specifics.tcp_udp.ri.local_address,
2137 &start->tcp_header, 1762 &start->tcp_header,
2138 payload, pkt_len); 1763 payload,
2139 GNUNET_CADET_receive_done (channel); 1764 pkt_len);
2140 return GNUNET_YES; 1765 GNUNET_CADET_receive_done (state->channel);
2141} 1766}
2142 1767
2143 1768
2144/** 1769/**
2145 * Process a request to forward TCP data on an established 1770 * Check a request to forward TCP data on an established
2146 * connection via this peer. 1771 * connection via this peer.
2147 * 1772 *
2148 * @param cls closure, NULL 1773 * @param cls our `struct ChannelState *`
2149 * @param channel connection to the other end
2150 * @param channel_ctx pointer to our `struct ChannelState *`
2151 * @param message the actual message 1774 * @param message the actual message
2152 * @return #GNUNET_OK to keep the connection open, 1775 * @return #GNUNET_OK to keep the connection open,
2153 * #GNUNET_SYSERR to close it (signal serious error) 1776 * #GNUNET_SYSERR to close it (signal serious error)
2154 */ 1777 */
2155static int 1778static int
2156receive_tcp_data (void *cls GNUNET_UNUSED, 1779check_tcp_data (void *cls,
2157 struct GNUNET_CADET_Channel *channel, 1780 const struct GNUNET_EXIT_TcpDataMessage *data)
2158 void **channel_ctx GNUNET_UNUSED,
2159 const struct GNUNET_MessageHeader *message)
2160{ 1781{
2161 struct ChannelState *state = *channel_ctx; 1782 struct ChannelState *state = cls;
2162 const struct GNUNET_EXIT_TcpDataMessage *data;
2163 uint16_t pkt_len = ntohs (message->size);
2164 1783
2165 GNUNET_STATISTICS_update (stats,
2166 gettext_noop ("# Bytes received from CADET"),
2167 pkt_len, GNUNET_NO);
2168 GNUNET_STATISTICS_update (stats,
2169 gettext_noop ("# TCP data requests received via cadet"),
2170 1, GNUNET_NO);
2171 if (pkt_len < sizeof (struct GNUNET_EXIT_TcpDataMessage))
2172 {
2173 GNUNET_break_op (0);
2174 return GNUNET_SYSERR;
2175 }
2176 data = (const struct GNUNET_EXIT_TcpDataMessage*) message;
2177 pkt_len -= sizeof (struct GNUNET_EXIT_TcpDataMessage);
2178 if ( (NULL == state) || 1784 if ( (NULL == state) ||
2179 (NULL == state->specifics.tcp_udp.heap_node) ) 1785 (NULL == state->specifics.tcp_udp.heap_node) )
2180 { 1786 {
@@ -2195,6 +1801,30 @@ receive_tcp_data (void *cls GNUNET_UNUSED,
2195 GNUNET_break_op (0); 1801 GNUNET_break_op (0);
2196 return GNUNET_SYSERR; 1802 return GNUNET_SYSERR;
2197 } 1803 }
1804 return GNUNET_OK;
1805}
1806
1807
1808/**
1809 * Process a request to forward TCP data on an established
1810 * connection via this peer.
1811 *
1812 * @param cls our `struct ChannelState *`
1813 * @param message the actual message
1814 */
1815static void
1816handle_tcp_data (void *cls,
1817 const struct GNUNET_EXIT_TcpDataMessage *data)
1818{
1819 struct ChannelState *state = cls;
1820 uint16_t pkt_len = ntohs (data->header.size) - sizeof (struct GNUNET_EXIT_TcpDataMessage);
1821
1822 GNUNET_STATISTICS_update (stats,
1823 gettext_noop ("# Bytes received from CADET"),
1824 pkt_len, GNUNET_NO);
1825 GNUNET_STATISTICS_update (stats,
1826 gettext_noop ("# TCP data requests received via cadet"),
1827 1, GNUNET_NO);
2198 if (GNUNET_SYSERR == state->is_dns) 1828 if (GNUNET_SYSERR == state->is_dns)
2199 { 1829 {
2200 /* channel is UDP/TCP from now on */ 1830 /* channel is UDP/TCP from now on */
@@ -2218,110 +1848,7 @@ receive_tcp_data (void *cls GNUNET_UNUSED,
2218 &state->specifics.tcp_udp.ri.local_address, 1848 &state->specifics.tcp_udp.ri.local_address,
2219 &data->tcp_header, 1849 &data->tcp_header,
2220 &data[1], pkt_len); 1850 &data[1], pkt_len);
2221 GNUNET_CADET_receive_done (channel); 1851 GNUNET_CADET_receive_done (state->channel);
2222 return GNUNET_YES;
2223}
2224
2225
2226/**
2227 * Send an ICMP packet via the TUN interface.
2228 *
2229 * @param destination_address IP to use for the ICMP packet's destination
2230 * @param source_address IP to use for the ICMP packet's source
2231 * @param icmp_header ICMP header to send
2232 * @param payload payload of the ICMP packet (does NOT include ICMP header)
2233 * @param payload_length number of bytes of data in @a payload
2234 */
2235static void
2236send_icmp_packet_via_tun (const struct SocketAddress *destination_address,
2237 const struct SocketAddress *source_address,
2238 const struct GNUNET_TUN_IcmpHeader *icmp_header,
2239 const void *payload, size_t payload_length)
2240{
2241 size_t len;
2242 struct GNUNET_TUN_IcmpHeader *icmp;
2243
2244 GNUNET_STATISTICS_update (stats,
2245 gettext_noop ("# ICMP packets sent via TUN"),
2246 1, GNUNET_NO);
2247 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2248 "Sending packet with %u bytes ICMP payload via TUN\n",
2249 (unsigned int) payload_length);
2250 len = sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader);
2251 switch (destination_address->af)
2252 {
2253 case AF_INET:
2254 len += sizeof (struct GNUNET_TUN_IPv4Header);
2255 break;
2256 case AF_INET6:
2257 len += sizeof (struct GNUNET_TUN_IPv6Header);
2258 break;
2259 default:
2260 GNUNET_break (0);
2261 return;
2262 }
2263 len += sizeof (struct GNUNET_TUN_IcmpHeader);
2264 len += payload_length;
2265 if (len >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
2266 {
2267 GNUNET_break (0);
2268 return;
2269 }
2270 {
2271 char buf[len] GNUNET_ALIGN;
2272 struct GNUNET_MessageHeader *hdr;
2273 struct GNUNET_TUN_Layer2PacketHeader *tun;
2274
2275 hdr= (struct GNUNET_MessageHeader *) buf;
2276 hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2277 hdr->size = htons (len);
2278 tun = (struct GNUNET_TUN_Layer2PacketHeader*) &hdr[1];
2279 tun->flags = htons (0);
2280 switch (source_address->af)
2281 {
2282 case AF_INET:
2283 {
2284 struct GNUNET_TUN_IPv4Header * ipv4 = (struct GNUNET_TUN_IPv4Header*) &tun[1];
2285
2286 tun->proto = htons (ETH_P_IPV4);
2287 GNUNET_TUN_initialize_ipv4_header (ipv4,
2288 IPPROTO_ICMP,
2289 sizeof (struct GNUNET_TUN_IcmpHeader) + payload_length,
2290 &source_address->address.ipv4,
2291 &destination_address->address.ipv4);
2292 icmp = (struct GNUNET_TUN_IcmpHeader*) &ipv4[1];
2293 }
2294 break;
2295 case AF_INET6:
2296 {
2297 struct GNUNET_TUN_IPv6Header * ipv6 = (struct GNUNET_TUN_IPv6Header*) &tun[1];
2298
2299 tun->proto = htons (ETH_P_IPV6);
2300 GNUNET_TUN_initialize_ipv6_header (ipv6,
2301 IPPROTO_ICMPV6,
2302 sizeof (struct GNUNET_TUN_IcmpHeader) + payload_length,
2303 &source_address->address.ipv6,
2304 &destination_address->address.ipv6);
2305 icmp = (struct GNUNET_TUN_IcmpHeader*) &ipv6[1];
2306 }
2307 break;
2308 default:
2309 GNUNET_assert (0);
2310 break;
2311 }
2312 *icmp = *icmp_header;
2313 GNUNET_memcpy (&icmp[1],
2314 payload,
2315 payload_length);
2316 GNUNET_TUN_calculate_icmp_checksum (icmp,
2317 payload,
2318 payload_length);
2319 if (NULL != helper_handle)
2320 (void) GNUNET_HELPER_send (helper_handle,
2321 (const struct GNUNET_MessageHeader*) buf,
2322 GNUNET_YES,
2323 NULL, NULL);
2324 }
2325} 1852}
2326 1853
2327 1854
@@ -2378,35 +1905,46 @@ make_up_icmpv6_payload (struct ChannelState *state,
2378 1905
2379 1906
2380/** 1907/**
2381 * Process a request to forward ICMP data to the Internet via this peer. 1908 * Check a request to forward ICMP data to the Internet via this peer.
2382 * 1909 *
2383 * @param cls closure, NULL 1910 * @param cls our `struct ChannelState *`
2384 * @param channel connection to the other end 1911 * @param msg the actual message
2385 * @param channel_ctx pointer to our 'struct ChannelState *'
2386 * @param message the actual message
2387 * @return #GNUNET_OK to keep the connection open, 1912 * @return #GNUNET_OK to keep the connection open,
2388 * #GNUNET_SYSERR to close it (signal serious error) 1913 * #GNUNET_SYSERR to close it (signal serious error)
2389 */ 1914 */
2390static int 1915static int
2391receive_icmp_remote (void *cls, 1916check_icmp_remote (void *cls,
2392 struct GNUNET_CADET_Channel *channel, 1917 const struct GNUNET_EXIT_IcmpInternetMessage *msg)
2393 void **channel_ctx,
2394 const struct GNUNET_MessageHeader *message)
2395{ 1918{
2396 struct ChannelState *state = *channel_ctx; 1919 struct ChannelState *state = cls;
2397 const struct GNUNET_EXIT_IcmpInternetMessage *msg;
2398 uint16_t pkt_len = ntohs (message->size);
2399 const struct in_addr *v4;
2400 const struct in6_addr *v6;
2401 const void *payload;
2402 char buf[sizeof (struct GNUNET_TUN_IPv6Header) + 8] GNUNET_ALIGN;
2403 int af;
2404 1920
2405 if (GNUNET_YES == state->is_dns) 1921 if (GNUNET_YES == state->is_dns)
2406 { 1922 {
2407 GNUNET_break_op (0); 1923 GNUNET_break_op (0);
2408 return GNUNET_SYSERR; 1924 return GNUNET_SYSERR;
2409 } 1925 }
1926 return GNUNET_OK;
1927}
1928
1929
1930/**
1931 * Process a request to forward ICMP data to the Internet via this peer.
1932 *
1933 * @param cls our `struct ChannelState *`
1934 * @param msg the actual message
1935 */
1936static void
1937handle_icmp_remote (void *cls,
1938 const struct GNUNET_EXIT_IcmpInternetMessage *msg)
1939{
1940 struct ChannelState *state = cls;
1941 uint16_t pkt_len = ntohs (msg->header.size) - sizeof (struct GNUNET_EXIT_IcmpInternetMessage);
1942 const struct in_addr *v4;
1943 const struct in6_addr *v6;
1944 const void *payload;
1945 char buf[sizeof (struct GNUNET_TUN_IPv6Header) + 8] GNUNET_ALIGN;
1946 int af;
1947
2410 if (GNUNET_SYSERR == state->is_dns) 1948 if (GNUNET_SYSERR == state->is_dns)
2411 { 1949 {
2412 /* channel is UDP/TCP from now on */ 1950 /* channel is UDP/TCP from now on */
@@ -2418,13 +1956,6 @@ receive_icmp_remote (void *cls,
2418 GNUNET_STATISTICS_update (stats, 1956 GNUNET_STATISTICS_update (stats,
2419 gettext_noop ("# ICMP IP-exit requests received via cadet"), 1957 gettext_noop ("# ICMP IP-exit requests received via cadet"),
2420 1, GNUNET_NO); 1958 1, GNUNET_NO);
2421 if (pkt_len < sizeof (struct GNUNET_EXIT_IcmpInternetMessage))
2422 {
2423 GNUNET_break_op (0);
2424 return GNUNET_SYSERR;
2425 }
2426 msg = (const struct GNUNET_EXIT_IcmpInternetMessage*) message;
2427 pkt_len -= sizeof (struct GNUNET_EXIT_IcmpInternetMessage);
2428 1959
2429 af = (int) ntohl (msg->af); 1960 af = (int) ntohl (msg->af);
2430 if ( (NULL != state->specifics.tcp_udp.heap_node) && 1961 if ( (NULL != state->specifics.tcp_udp.heap_node) &&
@@ -2432,7 +1963,7 @@ receive_icmp_remote (void *cls,
2432 { 1963 {
2433 /* other peer switched AF on this channel; not allowed */ 1964 /* other peer switched AF on this channel; not allowed */
2434 GNUNET_break_op (0); 1965 GNUNET_break_op (0);
2435 return GNUNET_SYSERR; 1966 return;
2436 } 1967 }
2437 1968
2438 switch (af) 1969 switch (af)
@@ -2441,12 +1972,12 @@ receive_icmp_remote (void *cls,
2441 if (pkt_len < sizeof (struct in_addr)) 1972 if (pkt_len < sizeof (struct in_addr))
2442 { 1973 {
2443 GNUNET_break_op (0); 1974 GNUNET_break_op (0);
2444 return GNUNET_SYSERR; 1975 return;
2445 } 1976 }
2446 if (! ipv4_exit) 1977 if (! ipv4_exit)
2447 { 1978 {
2448 GNUNET_break_op (0); 1979 GNUNET_break_op (0);
2449 return GNUNET_SYSERR; 1980 return;
2450 } 1981 }
2451 v4 = (const struct in_addr*) &msg[1]; 1982 v4 = (const struct in_addr*) &msg[1];
2452 payload = &v4[1]; 1983 payload = &v4[1];
@@ -2471,7 +2002,7 @@ receive_icmp_remote (void *cls,
2471 if (0 != pkt_len) 2002 if (0 != pkt_len)
2472 { 2003 {
2473 GNUNET_break_op (0); 2004 GNUNET_break_op (0);
2474 return GNUNET_SYSERR; 2005 return;
2475 } 2006 }
2476 /* make up payload */ 2007 /* make up payload */
2477 { 2008 {
@@ -2491,7 +2022,7 @@ receive_icmp_remote (void *cls,
2491 GNUNET_STATISTICS_update (stats, 2022 GNUNET_STATISTICS_update (stats,
2492 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"), 2023 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
2493 1, GNUNET_NO); 2024 1, GNUNET_NO);
2494 return GNUNET_SYSERR; 2025 return;
2495 } 2026 }
2496 /* end AF_INET */ 2027 /* end AF_INET */
2497 break; 2028 break;
@@ -2499,12 +2030,12 @@ receive_icmp_remote (void *cls,
2499 if (pkt_len < sizeof (struct in6_addr)) 2030 if (pkt_len < sizeof (struct in6_addr))
2500 { 2031 {
2501 GNUNET_break_op (0); 2032 GNUNET_break_op (0);
2502 return GNUNET_SYSERR; 2033 return;
2503 } 2034 }
2504 if (! ipv6_exit) 2035 if (! ipv6_exit)
2505 { 2036 {
2506 GNUNET_break_op (0); 2037 GNUNET_break_op (0);
2507 return GNUNET_SYSERR; 2038 return;
2508 } 2039 }
2509 v6 = (const struct in6_addr*) &msg[1]; 2040 v6 = (const struct in6_addr*) &msg[1];
2510 payload = &v6[1]; 2041 payload = &v6[1];
@@ -2530,7 +2061,7 @@ receive_icmp_remote (void *cls,
2530 if (0 != pkt_len) 2061 if (0 != pkt_len)
2531 { 2062 {
2532 GNUNET_break_op (0); 2063 GNUNET_break_op (0);
2533 return GNUNET_SYSERR; 2064 return;
2534 } 2065 }
2535 /* make up payload */ 2066 /* make up payload */
2536 { 2067 {
@@ -2550,14 +2081,14 @@ receive_icmp_remote (void *cls,
2550 GNUNET_STATISTICS_update (stats, 2081 GNUNET_STATISTICS_update (stats,
2551 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"), 2082 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
2552 1, GNUNET_NO); 2083 1, GNUNET_NO);
2553 return GNUNET_SYSERR; 2084 return;
2554 } 2085 }
2555 /* end AF_INET6 */ 2086 /* end AF_INET6 */
2556 break; 2087 break;
2557 default: 2088 default:
2558 /* bad AF */ 2089 /* bad AF */
2559 GNUNET_break_op (0); 2090 GNUNET_break_op (0);
2560 return GNUNET_SYSERR; 2091 return;
2561 } 2092 }
2562 2093
2563 { 2094 {
@@ -2573,8 +2104,7 @@ receive_icmp_remote (void *cls,
2573 &state->specifics.tcp_udp.ri.local_address, 2104 &state->specifics.tcp_udp.ri.local_address,
2574 &msg->icmp_header, 2105 &msg->icmp_header,
2575 payload, pkt_len); 2106 payload, pkt_len);
2576 GNUNET_CADET_receive_done (channel); 2107 GNUNET_CADET_receive_done (state->channel);
2577 return GNUNET_YES;
2578} 2108}
2579 2109
2580 2110
@@ -2629,28 +2159,19 @@ make_up_icmp_service_payload (struct ChannelState *state,
2629 2159
2630 2160
2631/** 2161/**
2632 * Process a request via cadet to send ICMP data to a service 2162 * Check a request via cadet to send ICMP data to a service
2633 * offered by this system. 2163 * offered by this system.
2634 * 2164 *
2635 * @param cls closure, NULL 2165 * @param cls our `struct ChannelState *`
2636 * @param channel connection to the other end 2166 * @param msg the actual message
2637 * @param channel_ctx pointer to our 'struct ChannelState *'
2638 * @param message the actual message
2639 * @return #GNUNET_OK to keep the connection open, 2167 * @return #GNUNET_OK to keep the connection open,
2640 * #GNUNET_SYSERR to close it (signal serious error) 2168 * #GNUNET_SYSERR to close it (signal serious error)
2641 */ 2169 */
2642static int 2170static int
2643receive_icmp_service (void *cls, 2171check_icmp_service (void *cls,
2644 struct GNUNET_CADET_Channel *channel, 2172 const struct GNUNET_EXIT_IcmpServiceMessage *msg)
2645 void **channel_ctx,
2646 const struct GNUNET_MessageHeader *message)
2647{ 2173{
2648 struct ChannelState *state = *channel_ctx; 2174 struct ChannelState *state = cls;
2649 const struct GNUNET_EXIT_IcmpServiceMessage *msg;
2650 uint16_t pkt_len = ntohs (message->size);
2651 struct GNUNET_TUN_IcmpHeader icmp;
2652 char buf[sizeof (struct GNUNET_TUN_IPv6Header) + 8] GNUNET_ALIGN;
2653 const void *payload;
2654 2175
2655 if (GNUNET_YES == state->is_dns) 2176 if (GNUNET_YES == state->is_dns)
2656 { 2177 {
@@ -2662,6 +2183,27 @@ receive_icmp_service (void *cls,
2662 GNUNET_break_op (0); 2183 GNUNET_break_op (0);
2663 return GNUNET_SYSERR; 2184 return GNUNET_SYSERR;
2664 } 2185 }
2186 return GNUNET_OK;
2187}
2188
2189
2190/**
2191 * Process a request via cadet to send ICMP data to a service
2192 * offered by this system.
2193 *
2194 * @param cls our `struct ChannelState *`
2195 * @param msg the actual message
2196 */
2197static void
2198handle_icmp_service (void *cls,
2199 const struct GNUNET_EXIT_IcmpServiceMessage *msg)
2200{
2201 struct ChannelState *state = cls;
2202 uint16_t pkt_len = ntohs (msg->header.size) - sizeof (struct GNUNET_EXIT_IcmpServiceMessage);
2203 struct GNUNET_TUN_IcmpHeader icmp;
2204 char buf[sizeof (struct GNUNET_TUN_IPv6Header) + 8] GNUNET_ALIGN;
2205 const void *payload;
2206
2665 GNUNET_STATISTICS_update (stats, 2207 GNUNET_STATISTICS_update (stats,
2666 gettext_noop ("# Bytes received from CADET"), 2208 gettext_noop ("# Bytes received from CADET"),
2667 pkt_len, GNUNET_NO); 2209 pkt_len, GNUNET_NO);
@@ -2669,13 +2211,6 @@ receive_icmp_service (void *cls,
2669 gettext_noop ("# ICMP service requests received via cadet"), 2211 gettext_noop ("# ICMP service requests received via cadet"),
2670 1, GNUNET_NO); 2212 1, GNUNET_NO);
2671 /* check that we got at least a valid header */ 2213 /* check that we got at least a valid header */
2672 if (pkt_len < sizeof (struct GNUNET_EXIT_IcmpServiceMessage))
2673 {
2674 GNUNET_break_op (0);
2675 return GNUNET_SYSERR;
2676 }
2677 msg = (const struct GNUNET_EXIT_IcmpServiceMessage*) message;
2678 pkt_len -= sizeof (struct GNUNET_EXIT_IcmpServiceMessage);
2679 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 2214 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2680 "Received data from %s for forwarding to ICMP service %s\n", 2215 "Received data from %s for forwarding to ICMP service %s\n",
2681 GNUNET_i2s (&state->peer), 2216 GNUNET_i2s (&state->peer),
@@ -2707,7 +2242,7 @@ receive_icmp_service (void *cls,
2707 if (0 != pkt_len) 2242 if (0 != pkt_len)
2708 { 2243 {
2709 GNUNET_break_op (0); 2244 GNUNET_break_op (0);
2710 return GNUNET_SYSERR; 2245 return;
2711 } 2246 }
2712 payload = buf; 2247 payload = buf;
2713 pkt_len = make_up_icmp_service_payload (state, buf); 2248 pkt_len = make_up_icmp_service_payload (state, buf);
@@ -2718,7 +2253,7 @@ receive_icmp_service (void *cls,
2718 if (0 != pkt_len) 2253 if (0 != pkt_len)
2719 { 2254 {
2720 GNUNET_break_op (0); 2255 GNUNET_break_op (0);
2721 return GNUNET_SYSERR; 2256 return;
2722 } 2257 }
2723 payload = buf; 2258 payload = buf;
2724 pkt_len = make_up_icmp_service_payload (state, buf); 2259 pkt_len = make_up_icmp_service_payload (state, buf);
@@ -2729,12 +2264,12 @@ receive_icmp_service (void *cls,
2729 GNUNET_STATISTICS_update (stats, 2264 GNUNET_STATISTICS_update (stats,
2730 gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"), 2265 gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
2731 1, GNUNET_NO); 2266 1, GNUNET_NO);
2732 return GNUNET_OK; 2267 return;
2733 } 2268 }
2734 if (0 != pkt_len) 2269 if (0 != pkt_len)
2735 { 2270 {
2736 GNUNET_break_op (0); 2271 GNUNET_break_op (0);
2737 return GNUNET_SYSERR; 2272 return;
2738 } 2273 }
2739 payload = buf; 2274 payload = buf;
2740 pkt_len = make_up_icmp_service_payload (state, buf); 2275 pkt_len = make_up_icmp_service_payload (state, buf);
@@ -2744,7 +2279,7 @@ receive_icmp_service (void *cls,
2744 GNUNET_STATISTICS_update (stats, 2279 GNUNET_STATISTICS_update (stats,
2745 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"), 2280 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
2746 1, GNUNET_NO); 2281 1, GNUNET_NO);
2747 return GNUNET_SYSERR; 2282 return;
2748 } 2283 }
2749 /* end of AF_INET */ 2284 /* end of AF_INET */
2750 break; 2285 break;
@@ -2765,7 +2300,7 @@ receive_icmp_service (void *cls,
2765 if (0 != pkt_len) 2300 if (0 != pkt_len)
2766 { 2301 {
2767 GNUNET_break_op (0); 2302 GNUNET_break_op (0);
2768 return GNUNET_SYSERR; 2303 return;
2769 } 2304 }
2770 payload = buf; 2305 payload = buf;
2771 pkt_len = make_up_icmp_service_payload (state, buf); 2306 pkt_len = make_up_icmp_service_payload (state, buf);
@@ -2776,7 +2311,7 @@ receive_icmp_service (void *cls,
2776 if (0 != pkt_len) 2311 if (0 != pkt_len)
2777 { 2312 {
2778 GNUNET_break_op (0); 2313 GNUNET_break_op (0);
2779 return GNUNET_SYSERR; 2314 return;
2780 } 2315 }
2781 payload = buf; 2316 payload = buf;
2782 pkt_len = make_up_icmp_service_payload (state, buf); 2317 pkt_len = make_up_icmp_service_payload (state, buf);
@@ -2788,12 +2323,12 @@ receive_icmp_service (void *cls,
2788 GNUNET_STATISTICS_update (stats, 2323 GNUNET_STATISTICS_update (stats,
2789 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"), 2324 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
2790 1, GNUNET_NO); 2325 1, GNUNET_NO);
2791 return GNUNET_OK; 2326 return;
2792 } 2327 }
2793 if (0 != pkt_len) 2328 if (0 != pkt_len)
2794 { 2329 {
2795 GNUNET_break_op (0); 2330 GNUNET_break_op (0);
2796 return GNUNET_SYSERR; 2331 return;
2797 } 2332 }
2798 payload = buf; 2333 payload = buf;
2799 pkt_len = make_up_icmp_service_payload (state, buf); 2334 pkt_len = make_up_icmp_service_payload (state, buf);
@@ -2803,283 +2338,713 @@ receive_icmp_service (void *cls,
2803 GNUNET_STATISTICS_update (stats, 2338 GNUNET_STATISTICS_update (stats,
2804 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"), 2339 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
2805 1, GNUNET_NO); 2340 1, GNUNET_NO);
2806 return GNUNET_SYSERR; 2341 return;
2807 } 2342 }
2808 /* end of AF_INET6 */ 2343 /* end of AF_INET6 */
2809 break; 2344 break;
2810 default: 2345 default:
2811 GNUNET_break_op (0); 2346 GNUNET_break_op (0);
2812 return GNUNET_SYSERR; 2347 return;
2813 } 2348 }
2814 2349
2815 send_icmp_packet_via_tun (&state->specifics.tcp_udp.ri.remote_address, 2350 send_icmp_packet_via_tun (&state->specifics.tcp_udp.ri.remote_address,
2816 &state->specifics.tcp_udp.ri.local_address, 2351 &state->specifics.tcp_udp.ri.local_address,
2817 &icmp, 2352 &icmp,
2818 payload, pkt_len); 2353 payload,
2819 GNUNET_CADET_receive_done (channel); 2354 pkt_len);
2820 return GNUNET_YES; 2355 GNUNET_CADET_receive_done (state->channel);
2821} 2356}
2822 2357
2823 2358
2824/** 2359/**
2825 * Send a UDP packet via the TUN interface. 2360 * Free memory associated with a service record.
2826 * 2361 *
2827 * @param destination_address IP and port to use for the UDP packet's destination 2362 * @param cls unused
2828 * @param source_address IP and port to use for the UDP packet's source 2363 * @param key service descriptor
2829 * @param payload payload of the UDP packet (does NOT include UDP header) 2364 * @param value service record to free
2830 * @param payload_length number of bytes of data in @a payload 2365 * @return #GNUNET_OK
2831 */ 2366 */
2832static void 2367static int
2833send_udp_packet_via_tun (const struct SocketAddress *destination_address, 2368free_service_record (void *cls,
2834 const struct SocketAddress *source_address, 2369 const struct GNUNET_HashCode *key,
2835 const void *payload, size_t payload_length) 2370 void *value)
2836{ 2371{
2837 size_t len; 2372 struct LocalService *service = value;
2373
2374 GNUNET_assert (GNUNET_YES ==
2375 GNUNET_CONTAINER_multihashmap_remove (services,
2376 key,
2377 service));
2378 GNUNET_CADET_close_port (service->port);
2379 GNUNET_free_non_null (service->name);
2380 GNUNET_free (service);
2381 return GNUNET_OK;
2382}
2383
2838 2384
2385/**
2386 * Callback from CADET for new channels.
2387 *
2388 * @param cls closure
2389 * @param channel new handle to the channel
2390 * @param initiator peer that started the channel
2391 * @return initial channel context for the channel
2392 */
2393static void *
2394new_service_channel (void *cls,
2395 struct GNUNET_CADET_Channel *channel,
2396 const struct GNUNET_PeerIdentity *initiator)
2397{
2398 struct LocalService *ls = cls;
2399 struct ChannelState *s = GNUNET_new (struct ChannelState);
2400
2401 s->peer = *initiator;
2839 GNUNET_STATISTICS_update (stats, 2402 GNUNET_STATISTICS_update (stats,
2840 gettext_noop ("# UDP packets sent via TUN"), 2403 gettext_noop ("# Inbound CADET channels created"),
2841 1, GNUNET_NO); 2404 1,
2405 GNUNET_NO);
2842 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 2406 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2843 "Sending packet with %u bytes UDP payload via TUN\n", 2407 "Received inbound channel from `%s'\n",
2844 (unsigned int) payload_length); 2408 GNUNET_i2s (initiator));
2845 len = sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader); 2409 s->channel = channel;
2846 switch (source_address->af) 2410 s->specifics.tcp_udp.serv = ls;
2411 s->specifics.tcp_udp.ri.remote_address = ls->address;
2412 return s;
2413}
2414
2415
2416/**
2417 * Function called by cadet whenever an inbound channel is destroyed.
2418 * Should clean up any associated state.
2419 *
2420 * @param cls our `struct ChannelState *`
2421 * @param channel connection to the other end (henceforth invalid)
2422 */
2423static void
2424clean_channel (void *cls,
2425 const struct GNUNET_CADET_Channel *channel)
2426{
2427 struct ChannelState *s = cls;
2428
2429 LOG (GNUNET_ERROR_TYPE_DEBUG,
2430 "Channel destroyed\n");
2431 if (GNUNET_SYSERR == s->is_dns)
2847 { 2432 {
2848 case AF_INET: 2433 GNUNET_free (s);
2849 len += sizeof (struct GNUNET_TUN_IPv4Header);
2850 break;
2851 case AF_INET6:
2852 len += sizeof (struct GNUNET_TUN_IPv6Header);
2853 break;
2854 default:
2855 GNUNET_break (0);
2856 return; 2434 return;
2857 } 2435 }
2858 len += sizeof (struct GNUNET_TUN_UdpHeader); 2436 if (GNUNET_YES == s->is_dns)
2859 len += payload_length;
2860 if (len >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
2861 { 2437 {
2862 GNUNET_break (0); 2438 if (channels[s->specifics.dns.my_id] == s)
2863 return; 2439 channels[s->specifics.dns.my_id] = NULL;
2864 } 2440 }
2441 else
2865 { 2442 {
2866 char buf[len] GNUNET_ALIGN; 2443 if (NULL != s->specifics.tcp_udp.heap_node)
2867 struct GNUNET_MessageHeader *hdr;
2868 struct GNUNET_TUN_Layer2PacketHeader *tun;
2869
2870 hdr= (struct GNUNET_MessageHeader *) buf;
2871 hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2872 hdr->size = htons (len);
2873 tun = (struct GNUNET_TUN_Layer2PacketHeader*) &hdr[1];
2874 tun->flags = htons (0);
2875 switch (source_address->af)
2876 { 2444 {
2877 case AF_INET: 2445 GNUNET_assert (GNUNET_YES ==
2878 { 2446 GNUNET_CONTAINER_multihashmap_remove (connections_map,
2879 struct GNUNET_TUN_IPv4Header * ipv4 = (struct GNUNET_TUN_IPv4Header*) &tun[1]; 2447 &s->specifics.tcp_udp.state_key,
2880 2448 s));
2881 tun->proto = htons (ETH_P_IPV4); 2449 GNUNET_CONTAINER_heap_remove_node (s->specifics.tcp_udp.heap_node);
2882 prepare_ipv4_packet (payload, 2450 s->specifics.tcp_udp.heap_node = NULL;
2883 payload_length,
2884 IPPROTO_UDP,
2885 NULL,
2886 source_address,
2887 destination_address,
2888 ipv4);
2889 }
2890 break;
2891 case AF_INET6:
2892 {
2893 struct GNUNET_TUN_IPv6Header * ipv6 = (struct GNUNET_TUN_IPv6Header*) &tun[1];
2894
2895 tun->proto = htons (ETH_P_IPV6);
2896 prepare_ipv6_packet (payload,
2897 payload_length,
2898 IPPROTO_UDP,
2899 NULL,
2900 source_address,
2901 destination_address,
2902 ipv6);
2903 }
2904 break;
2905 default:
2906 GNUNET_assert (0);
2907 break;
2908 } 2451 }
2909 if (NULL != helper_handle)
2910 (void) GNUNET_HELPER_send (helper_handle,
2911 (const struct GNUNET_MessageHeader*) buf,
2912 GNUNET_YES,
2913 NULL, NULL);
2914 } 2452 }
2453 GNUNET_free (s);
2915} 2454}
2916 2455
2917 2456
2918/** 2457/**
2919 * Process a request to forward UDP data to the Internet via this peer. 2458 * Given a service descriptor and a destination port, find the
2459 * respective service entry.
2920 * 2460 *
2921 * @param cls closure, NULL 2461 * @param proto IPPROTO_TCP or IPPROTO_UDP
2922 * @param channel connection to the other end 2462 * @param name name of the service
2923 * @param channel_ctx pointer to our 'struct ChannelState *' 2463 * @param destination_port destination port
2924 * @param message the actual message 2464 * @param service service information record to store (service->name will be set).
2925 * @return #GNUNET_OK to keep the connection open,
2926 * #GNUNET_SYSERR to close it (signal serious error)
2927 */ 2465 */
2928static int 2466static void
2929receive_udp_remote (void *cls, 2467store_service (int proto,
2930 struct GNUNET_CADET_Channel *channel, 2468 const char *name,
2931 void **channel_ctx, 2469 uint16_t destination_port,
2932 const struct GNUNET_MessageHeader *message) 2470 struct LocalService *service)
2933{ 2471{
2934 struct ChannelState *state = *channel_ctx; 2472 struct GNUNET_MQ_MessageHandler handlers[] = {
2935 const struct GNUNET_EXIT_UdpInternetMessage *msg; 2473 GNUNET_MQ_hd_var_size (icmp_service,
2936 uint16_t pkt_len = ntohs (message->size); 2474 GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_SERVICE,
2937 const struct in_addr *v4; 2475 struct GNUNET_EXIT_IcmpServiceMessage,
2938 const struct in6_addr *v6; 2476 service),
2939 const void *payload; 2477 GNUNET_MQ_hd_var_size (udp_service,
2940 int af; 2478 GNUNET_MESSAGE_TYPE_VPN_UDP_TO_SERVICE,
2479 struct GNUNET_EXIT_UdpServiceMessage,
2480 service),
2481 GNUNET_MQ_hd_var_size (tcp_service,
2482 GNUNET_MESSAGE_TYPE_VPN_TCP_TO_SERVICE_START,
2483 struct GNUNET_EXIT_TcpServiceStartMessage,
2484 service),
2485 GNUNET_MQ_hd_var_size (tcp_data,
2486 GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_EXIT,
2487 struct GNUNET_EXIT_TcpDataMessage,
2488 service),
2489 GNUNET_MQ_handler_end ()
2490 };
2941 2491
2942 if (GNUNET_YES == state->is_dns) 2492 struct GNUNET_HashCode cadet_port;
2493
2494 service->name = GNUNET_strdup (name);
2495 GNUNET_TUN_service_name_to_hash (name,
2496 &service->descriptor);
2497 GNUNET_TUN_compute_service_cadet_port (&service->descriptor,
2498 destination_port,
2499 &cadet_port);
2500 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2501 "Opening CADET port %s for SERVICE exit %s on port %u\n",
2502 GNUNET_h2s (&cadet_port),
2503 name,
2504 (unsigned int) destination_port);
2505 service->port = GNUNET_CADET_open_port (cadet_handle,
2506 &cadet_port,
2507 &new_service_channel,
2508 service,
2509 NULL,
2510 &clean_channel,
2511 handlers);
2512 service->is_udp = (IPPROTO_UDP == proto);
2513 if (GNUNET_OK !=
2514 GNUNET_CONTAINER_multihashmap_put (services,
2515 &cadet_port,
2516 service,
2517 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
2943 { 2518 {
2944 GNUNET_break_op (0); 2519 GNUNET_CADET_close_port (service->port);
2945 return GNUNET_SYSERR; 2520 GNUNET_free_non_null (service->name);
2521 GNUNET_free (service);
2522 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2523 _("Got duplicate service records for `%s:%u'\n"),
2524 name,
2525 (unsigned int) destination_port);
2946 } 2526 }
2947 if (GNUNET_SYSERR == state->is_dns) 2527}
2528
2529
2530/**
2531 * Send the given packet via the cadet channel.
2532 *
2533 * @param s channel destination
2534 * @param env message to queue
2535 */
2536static void
2537send_packet_to_cadet_channel (struct ChannelState *s,
2538 struct GNUNET_MQ_Envelope *env)
2539{
2540 GNUNET_assert (NULL != s);
2541 GNUNET_STATISTICS_update (stats,
2542 gettext_noop ("# Messages transmitted via cadet channels"),
2543 1,
2544 GNUNET_NO);
2545 GNUNET_MQ_send (GNUNET_CADET_get_mq (s->channel),
2546 env);
2547}
2548
2549
2550/**
2551 * @brief Handles an ICMP packet received from the helper.
2552 *
2553 * @param icmp A pointer to the Packet
2554 * @param pktlen number of bytes in @a icmp
2555 * @param af address family (AFINET or AF_INET6)
2556 * @param destination_ip destination IP-address of the IP packet (should
2557 * be our local address)
2558 * @param source_ip original source IP-address of the IP packet (should
2559 * be the original destination address)
2560 */
2561static void
2562icmp_from_helper (const struct GNUNET_TUN_IcmpHeader *icmp,
2563 size_t pktlen,
2564 int af,
2565 const void *destination_ip,
2566 const void *source_ip)
2567{
2568 struct ChannelState *state;
2569 struct GNUNET_MQ_Envelope *env;
2570 struct GNUNET_EXIT_IcmpToVPNMessage *i2v;
2571 const struct GNUNET_TUN_IPv4Header *ipv4;
2572 const struct GNUNET_TUN_IPv6Header *ipv6;
2573 const struct GNUNET_TUN_UdpHeader *udp;
2574 uint16_t source_port;
2575 uint16_t destination_port;
2576 uint8_t protocol;
2577
2948 { 2578 {
2949 /* channel is UDP/TCP from now on */ 2579 char sbuf[INET6_ADDRSTRLEN];
2950 state->is_dns = GNUNET_NO; 2580 char dbuf[INET6_ADDRSTRLEN];
2581 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2582 "Received ICMP packet going from %s to %s\n",
2583 inet_ntop (af,
2584 source_ip,
2585 sbuf, sizeof (sbuf)),
2586 inet_ntop (af,
2587 destination_ip,
2588 dbuf, sizeof (dbuf)));
2951 } 2589 }
2952 GNUNET_STATISTICS_update (stats, 2590 if (pktlen < sizeof (struct GNUNET_TUN_IcmpHeader))
2953 gettext_noop ("# Bytes received from CADET"),
2954 pkt_len, GNUNET_NO);
2955 GNUNET_STATISTICS_update (stats,
2956 gettext_noop ("# UDP IP-exit requests received via cadet"),
2957 1, GNUNET_NO);
2958 if (pkt_len < sizeof (struct GNUNET_EXIT_UdpInternetMessage))
2959 { 2591 {
2960 GNUNET_break_op (0); 2592 /* blame kernel */
2961 return GNUNET_SYSERR; 2593 GNUNET_break (0);
2594 return;
2962 } 2595 }
2963 msg = (const struct GNUNET_EXIT_UdpInternetMessage*) message; 2596
2964 pkt_len -= sizeof (struct GNUNET_EXIT_UdpInternetMessage); 2597 /* Find out if this is an ICMP packet in response to an existing
2965 af = (int) ntohl (msg->af); 2598 TCP/UDP packet and if so, figure out ports / protocol of the
2966 state->specifics.tcp_udp.ri.remote_address.af = af; 2599 existing session from the IP data in the ICMP payload */
2600 source_port = 0;
2601 destination_port = 0;
2967 switch (af) 2602 switch (af)
2968 { 2603 {
2969 case AF_INET: 2604 case AF_INET:
2970 if (pkt_len < sizeof (struct in_addr)) 2605 protocol = IPPROTO_ICMP;
2971 { 2606 switch (icmp->type)
2972 GNUNET_break_op (0); 2607 {
2973 return GNUNET_SYSERR; 2608 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
2974 } 2609 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
2975 if (! ipv4_exit) 2610 break;
2976 { 2611 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
2977 GNUNET_break_op (0); 2612 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
2978 return GNUNET_SYSERR; 2613 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
2979 } 2614 if (pktlen <
2980 v4 = (const struct in_addr*) &msg[1]; 2615 sizeof (struct GNUNET_TUN_IcmpHeader) +
2981 payload = &v4[1]; 2616 sizeof (struct GNUNET_TUN_IPv4Header) + 8)
2982 pkt_len -= sizeof (struct in_addr); 2617 {
2983 state->specifics.tcp_udp.ri.remote_address.address.ipv4 = *v4; 2618 /* blame kernel */
2619 GNUNET_break (0);
2620 return;
2621 }
2622 ipv4 = (const struct GNUNET_TUN_IPv4Header *) &icmp[1];
2623 protocol = ipv4->protocol;
2624 /* could be TCP or UDP, but both have the ports in the right
2625 place, so that doesn't matter here */
2626 udp = (const struct GNUNET_TUN_UdpHeader *) &ipv4[1];
2627 /* swap ports, as they are from the original message */
2628 destination_port = ntohs (udp->source_port);
2629 source_port = ntohs (udp->destination_port);
2630 /* throw away ICMP payload, won't be useful for the other side anyway */
2631 pktlen = sizeof (struct GNUNET_TUN_IcmpHeader);
2632 break;
2633 default:
2634 GNUNET_STATISTICS_update (stats,
2635 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
2636 1, GNUNET_NO);
2637 return;
2638 }
2984 break; 2639 break;
2985 case AF_INET6: 2640 case AF_INET6:
2986 if (pkt_len < sizeof (struct in6_addr)) 2641 protocol = IPPROTO_ICMPV6;
2987 { 2642 switch (icmp->type)
2988 GNUNET_break_op (0); 2643 {
2989 return GNUNET_SYSERR; 2644 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
2990 } 2645 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
2991 if (! ipv6_exit) 2646 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
2992 { 2647 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
2993 GNUNET_break_op (0); 2648 if (pktlen <
2994 return GNUNET_SYSERR; 2649 sizeof (struct GNUNET_TUN_IcmpHeader) +
2995 } 2650 sizeof (struct GNUNET_TUN_IPv6Header) + 8)
2996 v6 = (const struct in6_addr*) &msg[1]; 2651 {
2997 payload = &v6[1]; 2652 /* blame kernel */
2998 pkt_len -= sizeof (struct in6_addr); 2653 GNUNET_break (0);
2999 state->specifics.tcp_udp.ri.remote_address.address.ipv6 = *v6; 2654 return;
2655 }
2656 ipv6 = (const struct GNUNET_TUN_IPv6Header *) &icmp[1];
2657 protocol = ipv6->next_header;
2658 /* could be TCP or UDP, but both have the ports in the right
2659 place, so that doesn't matter here */
2660 udp = (const struct GNUNET_TUN_UdpHeader *) &ipv6[1];
2661 /* swap ports, as they are from the original message */
2662 destination_port = ntohs (udp->source_port);
2663 source_port = ntohs (udp->destination_port);
2664 /* throw away ICMP payload, won't be useful for the other side anyway */
2665 pktlen = sizeof (struct GNUNET_TUN_IcmpHeader);
2666 break;
2667 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
2668 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
2669 break;
2670 default:
2671 GNUNET_STATISTICS_update (stats,
2672 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
2673 1, GNUNET_NO);
2674 return;
2675 }
3000 break; 2676 break;
3001 default: 2677 default:
3002 GNUNET_break_op (0); 2678 GNUNET_assert (0);
3003 return GNUNET_SYSERR;
3004 } 2679 }
2680 switch (protocol)
3005 { 2681 {
3006 char buf[INET6_ADDRSTRLEN]; 2682 case IPPROTO_ICMP:
2683 state = get_redirect_state (af,
2684 IPPROTO_ICMP,
2685 source_ip,
2686 0,
2687 destination_ip,
2688 0,
2689 NULL);
2690 break;
2691 case IPPROTO_ICMPV6:
2692 state = get_redirect_state (af,
2693 IPPROTO_ICMPV6,
2694 source_ip,
2695 0,
2696 destination_ip,
2697 0,
2698 NULL);
2699 break;
2700 case IPPROTO_UDP:
2701 state = get_redirect_state (af,
2702 IPPROTO_UDP,
2703 source_ip,
2704 source_port,
2705 destination_ip,
2706 destination_port,
2707 NULL);
2708 break;
2709 case IPPROTO_TCP:
2710 state = get_redirect_state (af,
2711 IPPROTO_TCP,
2712 source_ip,
2713 source_port,
2714 destination_ip,
2715 destination_port,
2716 NULL);
2717 break;
2718 default:
2719 GNUNET_STATISTICS_update (stats,
2720 gettext_noop ("# ICMP packets dropped (not allowed)"),
2721 1,
2722 GNUNET_NO);
2723 return;
2724 }
2725 if (NULL == state)
2726 {
2727 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2728 _("ICMP Packet dropped, have no matching connection information\n"));
2729 return;
2730 }
2731 env = GNUNET_MQ_msg_extra (i2v,
2732 pktlen - sizeof (struct GNUNET_TUN_IcmpHeader),
2733 GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_VPN);
2734 i2v->af = htonl (af);
2735 GNUNET_memcpy (&i2v->icmp_header,
2736 icmp,
2737 pktlen);
2738 send_packet_to_cadet_channel (state,
2739 env);
2740}
2741
2742
2743/**
2744 * @brief Handles an UDP packet received from the helper.
2745 *
2746 * @param udp A pointer to the Packet
2747 * @param pktlen number of bytes in 'udp'
2748 * @param af address family (AFINET or AF_INET6)
2749 * @param destination_ip destination IP-address of the IP packet (should
2750 * be our local address)
2751 * @param source_ip original source IP-address of the IP packet (should
2752 * be the original destination address)
2753 */
2754static void
2755udp_from_helper (const struct GNUNET_TUN_UdpHeader *udp,
2756 size_t pktlen,
2757 int af,
2758 const void *destination_ip,
2759 const void *source_ip)
2760{
2761 struct ChannelState *state;
2762 struct GNUNET_MQ_Envelope *env;
2763 struct GNUNET_EXIT_UdpReplyMessage *urm;
2764
2765 {
2766 char sbuf[INET6_ADDRSTRLEN];
2767 char dbuf[INET6_ADDRSTRLEN];
2768
3007 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 2769 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3008 "Received data from %s for forwarding to UDP %s:%u\n", 2770 "Received UDP packet going from %s:%u to %s:%u\n",
3009 GNUNET_i2s (&state->peer),
3010 inet_ntop (af, 2771 inet_ntop (af,
3011 &state->specifics.tcp_udp.ri.remote_address.address, 2772 source_ip,
3012 buf, sizeof (buf)), 2773 sbuf, sizeof (sbuf)),
3013 (unsigned int) ntohs (msg->destination_port)); 2774 (unsigned int) ntohs (udp->source_port),
2775 inet_ntop (af,
2776 destination_ip,
2777 dbuf, sizeof (dbuf)),
2778 (unsigned int) ntohs (udp->destination_port));
3014 } 2779 }
3015 state->specifics.tcp_udp.ri.remote_address.proto = IPPROTO_UDP; 2780 if (pktlen < sizeof (struct GNUNET_TUN_UdpHeader))
3016 state->specifics.tcp_udp.ri.remote_address.port = msg->destination_port; 2781 {
3017 if (NULL == state->specifics.tcp_udp.heap_node) 2782 /* blame kernel */
3018 setup_state_record (state); 2783 GNUNET_break (0);
3019 if (0 != ntohs (msg->source_port)) 2784 return;
3020 state->specifics.tcp_udp.ri.local_address.port = msg->source_port; 2785 }
3021 send_udp_packet_via_tun (&state->specifics.tcp_udp.ri.remote_address, 2786 if (pktlen != ntohs (udp->len))
3022 &state->specifics.tcp_udp.ri.local_address, 2787 {
3023 payload, pkt_len); 2788 /* blame kernel */
3024 GNUNET_CADET_receive_done (channel); 2789 GNUNET_break (0);
3025 return GNUNET_YES; 2790 return;
2791 }
2792 state = get_redirect_state (af,
2793 IPPROTO_UDP,
2794 source_ip,
2795 ntohs (udp->source_port),
2796 destination_ip,
2797 ntohs (udp->destination_port),
2798 NULL);
2799 if (NULL == state)
2800 {
2801 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2802 _("UDP Packet dropped, have no matching connection information\n"));
2803 return;
2804 }
2805 env = GNUNET_MQ_msg_extra (urm,
2806 pktlen - sizeof (struct GNUNET_TUN_UdpHeader),
2807 GNUNET_MESSAGE_TYPE_VPN_UDP_REPLY);
2808 urm->source_port = htons (0);
2809 urm->destination_port = htons (0);
2810 GNUNET_memcpy (&urm[1],
2811 &udp[1],
2812 pktlen - sizeof (struct GNUNET_TUN_UdpHeader));
2813 send_packet_to_cadet_channel (state,
2814 env);
3026} 2815}
3027 2816
3028 2817
3029/** 2818/**
3030 * Process a request via cadet to send a request to a UDP service 2819 * @brief Handles a TCP packet received from the helper.
3031 * offered by this system.
3032 * 2820 *
3033 * @param cls closure, NULL 2821 * @param tcp A pointer to the Packet
3034 * @param channel connection to the other end 2822 * @param pktlen the length of the packet, including its TCP header
3035 * @param channel_ctx pointer to our 'struct ChannelState *' 2823 * @param af address family (AFINET or AF_INET6)
3036 * @param message the actual message 2824 * @param destination_ip destination IP-address of the IP packet (should
3037 * @return #GNUNET_OK to keep the connection open, 2825 * be our local address)
3038 * #GNUNET_SYSERR to close it (signal serious error) 2826 * @param source_ip original source IP-address of the IP packet (should
2827 * be the original destination address)
3039 */ 2828 */
3040static int 2829static void
3041receive_udp_service (void *cls, 2830tcp_from_helper (const struct GNUNET_TUN_TcpHeader *tcp,
3042 struct GNUNET_CADET_Channel *channel, 2831 size_t pktlen,
3043 void **channel_ctx, 2832 int af,
3044 const struct GNUNET_MessageHeader *message) 2833 const void *destination_ip,
2834 const void *source_ip)
3045{ 2835{
3046 struct ChannelState *state = *channel_ctx; 2836 struct ChannelState *state;
3047 const struct GNUNET_EXIT_UdpServiceMessage *msg; 2837 char buf[pktlen] GNUNET_ALIGN;
3048 uint16_t pkt_len = ntohs (message->size); 2838 struct GNUNET_TUN_TcpHeader *mtcp;
2839 struct GNUNET_EXIT_TcpDataMessage *tdm;
2840 struct GNUNET_MQ_Envelope *env;
2841 size_t mlen;
3049 2842
3050 if (NULL == state->specifics.tcp_udp.serv)
3051 { 2843 {
3052 GNUNET_break_op (0); 2844 char sbuf[INET6_ADDRSTRLEN];
3053 return GNUNET_SYSERR; 2845 char dbuf[INET6_ADDRSTRLEN];
2846 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2847 "Received TCP packet with %u bytes going from %s:%u to %s:%u\n",
2848 (unsigned int) (pktlen - sizeof (struct GNUNET_TUN_TcpHeader)),
2849 inet_ntop (af,
2850 source_ip,
2851 sbuf, sizeof (sbuf)),
2852 (unsigned int) ntohs (tcp->source_port),
2853 inet_ntop (af,
2854 destination_ip,
2855 dbuf, sizeof (dbuf)),
2856 (unsigned int) ntohs (tcp->destination_port));
3054 } 2857 }
2858 if (pktlen < sizeof (struct GNUNET_TUN_TcpHeader))
2859 {
2860 /* blame kernel */
2861 GNUNET_break (0);
2862 return;
2863 }
2864 state = get_redirect_state (af,
2865 IPPROTO_TCP,
2866 source_ip,
2867 ntohs (tcp->source_port),
2868 destination_ip,
2869 ntohs (tcp->destination_port),
2870 NULL);
2871 if (NULL == state)
2872 {
2873 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2874 _("TCP Packet dropped, have no matching connection information\n"));
2875
2876 return;
2877 }
2878 /* mug port numbers and crc to avoid information leakage;
2879 sender will need to lookup the correct values anyway */
2880 GNUNET_memcpy (buf, tcp, pktlen);
2881 mtcp = (struct GNUNET_TUN_TcpHeader *) buf;
2882 mtcp->source_port = 0;
2883 mtcp->destination_port = 0;
2884 mtcp->crc = 0;
2885
2886 mlen = sizeof (struct GNUNET_EXIT_TcpDataMessage) + (pktlen - sizeof (struct GNUNET_TUN_TcpHeader));
2887 if (mlen >= GNUNET_MAX_MESSAGE_SIZE)
2888 {
2889 GNUNET_break (0);
2890 return;
2891 }
2892 env = GNUNET_MQ_msg_extra (tdm,
2893 pktlen - sizeof (struct GNUNET_TUN_TcpHeader),
2894 GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_VPN);
2895 tdm->reserved = htonl (0);
2896 GNUNET_memcpy (&tdm->tcp_header,
2897 buf,
2898 pktlen);
2899 send_packet_to_cadet_channel (state,
2900 env);
2901}
2902
2903
2904/**
2905 * Receive packets from the helper-process
2906 *
2907 * @param cls unused
2908 * @param message message received from helper
2909 */
2910static int
2911message_token (void *cls GNUNET_UNUSED,
2912 const struct GNUNET_MessageHeader *message)
2913{
2914 const struct GNUNET_TUN_Layer2PacketHeader *pkt_tun;
2915 size_t size;
2916
2917 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2918 "Got %u-byte message of type %u from gnunet-helper-exit\n",
2919 ntohs (message->size),
2920 ntohs (message->type));
3055 GNUNET_STATISTICS_update (stats, 2921 GNUNET_STATISTICS_update (stats,
3056 gettext_noop ("# Bytes received from CADET"), 2922 gettext_noop ("# Packets received from TUN"),
3057 pkt_len, GNUNET_NO);
3058 GNUNET_STATISTICS_update (stats,
3059 gettext_noop ("# UDP service requests received via cadet"),
3060 1, GNUNET_NO); 2923 1, GNUNET_NO);
3061 /* check that we got at least a valid header */ 2924 if (ntohs (message->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER)
3062 if (pkt_len < sizeof (struct GNUNET_EXIT_UdpServiceMessage))
3063 { 2925 {
3064 GNUNET_break_op (0); 2926 GNUNET_break (0);
3065 return GNUNET_SYSERR; 2927 return GNUNET_OK;
3066 } 2928 }
3067 msg = (const struct GNUNET_EXIT_UdpServiceMessage*) message; 2929 size = ntohs (message->size);
3068 pkt_len -= sizeof (struct GNUNET_EXIT_UdpServiceMessage); 2930 if (size < sizeof (struct GNUNET_TUN_Layer2PacketHeader) + sizeof (struct GNUNET_MessageHeader))
3069 LOG (GNUNET_ERROR_TYPE_DEBUG, 2931 {
3070 "Received data from %s for forwarding to UDP service %s on port %u\n", 2932 GNUNET_break (0);
3071 GNUNET_i2s (&state->peer), 2933 return GNUNET_OK;
3072 GNUNET_h2s (&state->specifics.tcp_udp.serv->descriptor), 2934 }
3073 (unsigned int) ntohs (msg->destination_port)); 2935 GNUNET_STATISTICS_update (stats,
3074 setup_state_record (state); 2936 gettext_noop ("# Bytes received from TUN"),
3075 if (0 != ntohs (msg->source_port)) 2937 size, GNUNET_NO);
3076 state->specifics.tcp_udp.ri.local_address.port = msg->source_port; 2938 pkt_tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1];
3077 send_udp_packet_via_tun (&state->specifics.tcp_udp.ri.remote_address, 2939 size -= sizeof (struct GNUNET_TUN_Layer2PacketHeader) + sizeof (struct GNUNET_MessageHeader);
3078 &state->specifics.tcp_udp.ri.local_address, 2940 switch (ntohs (pkt_tun->proto))
3079 &msg[1], 2941 {
3080 pkt_len); 2942 case ETH_P_IPV4:
3081 GNUNET_CADET_receive_done (channel); 2943 {
3082 return GNUNET_YES; 2944 const struct GNUNET_TUN_IPv4Header *pkt4;
2945
2946 if (size < sizeof (struct GNUNET_TUN_IPv4Header))
2947 {
2948 /* Kernel to blame? */
2949 GNUNET_break (0);
2950 return GNUNET_OK;
2951 }
2952 pkt4 = (const struct GNUNET_TUN_IPv4Header *) &pkt_tun[1];
2953 if (size != ntohs (pkt4->total_length))
2954 {
2955 /* Kernel to blame? */
2956 GNUNET_break (0);
2957 return GNUNET_OK;
2958 }
2959 if (pkt4->header_length * 4 != sizeof (struct GNUNET_TUN_IPv4Header))
2960 {
2961 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2962 _("IPv4 packet options received. Ignored.\n"));
2963 return GNUNET_OK;
2964 }
2965
2966 size -= sizeof (struct GNUNET_TUN_IPv4Header);
2967 switch (pkt4->protocol)
2968 {
2969 case IPPROTO_UDP:
2970 udp_from_helper ((const struct GNUNET_TUN_UdpHeader *) &pkt4[1], size,
2971 AF_INET,
2972 &pkt4->destination_address,
2973 &pkt4->source_address);
2974 break;
2975 case IPPROTO_TCP:
2976 tcp_from_helper ((const struct GNUNET_TUN_TcpHeader *) &pkt4[1], size,
2977 AF_INET,
2978 &pkt4->destination_address,
2979 &pkt4->source_address);
2980 break;
2981 case IPPROTO_ICMP:
2982 icmp_from_helper ((const struct GNUNET_TUN_IcmpHeader *) &pkt4[1], size,
2983 AF_INET,
2984 &pkt4->destination_address,
2985 &pkt4->source_address);
2986 break;
2987 default:
2988 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2989 _("IPv4 packet with unsupported next header %u received. Ignored.\n"),
2990 (int) pkt4->protocol);
2991 return GNUNET_OK;
2992 }
2993 }
2994 break;
2995 case ETH_P_IPV6:
2996 {
2997 const struct GNUNET_TUN_IPv6Header *pkt6;
2998
2999 if (size < sizeof (struct GNUNET_TUN_IPv6Header))
3000 {
3001 /* Kernel to blame? */
3002 GNUNET_break (0);
3003 return GNUNET_OK;
3004 }
3005 pkt6 = (struct GNUNET_TUN_IPv6Header *) &pkt_tun[1];
3006 if (size != ntohs (pkt6->payload_length) + sizeof (struct GNUNET_TUN_IPv6Header))
3007 {
3008 /* Kernel to blame? */
3009 GNUNET_break (0);
3010 return GNUNET_OK;
3011 }
3012 size -= sizeof (struct GNUNET_TUN_IPv6Header);
3013 switch (pkt6->next_header)
3014 {
3015 case IPPROTO_UDP:
3016 udp_from_helper ((const struct GNUNET_TUN_UdpHeader *) &pkt6[1], size,
3017 AF_INET6,
3018 &pkt6->destination_address,
3019 &pkt6->source_address);
3020 break;
3021 case IPPROTO_TCP:
3022 tcp_from_helper ((const struct GNUNET_TUN_TcpHeader *) &pkt6[1], size,
3023 AF_INET6,
3024 &pkt6->destination_address,
3025 &pkt6->source_address);
3026 break;
3027 case IPPROTO_ICMPV6:
3028 icmp_from_helper ((const struct GNUNET_TUN_IcmpHeader *) &pkt6[1], size,
3029 AF_INET6,
3030 &pkt6->destination_address,
3031 &pkt6->source_address);
3032 break;
3033 default:
3034 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3035 _("IPv6 packet with unsupported next header %d received. Ignored.\n"),
3036 pkt6->next_header);
3037 return GNUNET_OK;
3038 }
3039 }
3040 break;
3041 default:
3042 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3043 _("Packet from unknown protocol %u received. Ignored.\n"),
3044 ntohs (pkt_tun->proto));
3045 break;
3046 }
3047 return GNUNET_OK;
3083} 3048}
3084 3049
3085 3050
@@ -3089,16 +3054,12 @@ receive_udp_service (void *cls,
3089 * @param cls closure 3054 * @param cls closure
3090 * @param channel new handle to the channel 3055 * @param channel new handle to the channel
3091 * @param initiator peer that started the channel 3056 * @param initiator peer that started the channel
3092 * @param port destination port
3093 * @param options channel options flags
3094 * @return initial channel context for the channel 3057 * @return initial channel context for the channel
3095 */ 3058 */
3096static void * 3059static void *
3097new_channel (void *cls, 3060new_channel (void *cls,
3098 struct GNUNET_CADET_Channel *channel, 3061 struct GNUNET_CADET_Channel *channel,
3099 const struct GNUNET_PeerIdentity *initiator, 3062 const struct GNUNET_PeerIdentity *initiator)
3100 const struct GNUNET_HashCode *port,
3101 enum GNUNET_CADET_ChannelOption options)
3102{ 3063{
3103 struct ChannelState *s = GNUNET_new (struct ChannelState); 3064 struct ChannelState *s = GNUNET_new (struct ChannelState);
3104 3065
@@ -3106,7 +3067,8 @@ new_channel (void *cls,
3106 s->peer = *initiator; 3067 s->peer = *initiator;
3107 GNUNET_STATISTICS_update (stats, 3068 GNUNET_STATISTICS_update (stats,
3108 gettext_noop ("# Inbound CADET channels created"), 3069 gettext_noop ("# Inbound CADET channels created"),
3109 1, GNUNET_NO); 3070 1,
3071 GNUNET_NO);
3110 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 3072 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3111 "Received inbound channel from `%s'\n", 3073 "Received inbound channel from `%s'\n",
3112 GNUNET_i2s (initiator)); 3074 GNUNET_i2s (initiator));
@@ -3116,64 +3078,6 @@ new_channel (void *cls,
3116 3078
3117 3079
3118/** 3080/**
3119 * Function called by cadet whenever an inbound channel is destroyed.
3120 * Should clean up any associated state.
3121 *
3122 * @param cls closure (set from #GNUNET_CADET_connect)
3123 * @param channel connection to the other end (henceforth invalid)
3124 * @param channel_ctx place where local state associated
3125 * with the channel is stored
3126 */
3127static void
3128clean_channel (void *cls,
3129 const struct GNUNET_CADET_Channel *channel,
3130 void *channel_ctx)
3131{
3132 struct ChannelState *s = channel_ctx;
3133 struct ChannelMessageQueue *tnq;
3134
3135 LOG (GNUNET_ERROR_TYPE_DEBUG,
3136 "Channel destroyed\n");
3137 if (GNUNET_SYSERR == s->is_dns)
3138 {
3139 GNUNET_free (s);
3140 return;
3141 }
3142 if (GNUNET_YES == s->is_dns)
3143 {
3144 if (channels[s->specifics.dns.my_id] == s)
3145 channels[s->specifics.dns.my_id] = NULL;
3146 GNUNET_free_non_null (s->specifics.dns.reply);
3147 }
3148 else
3149 {
3150 while (NULL != (tnq = s->specifics.tcp_udp.head))
3151 {
3152 GNUNET_CONTAINER_DLL_remove (s->specifics.tcp_udp.head,
3153 s->specifics.tcp_udp.tail,
3154 tnq);
3155 GNUNET_free (tnq);
3156 }
3157 if (NULL != s->specifics.tcp_udp.heap_node)
3158 {
3159 GNUNET_assert (GNUNET_YES ==
3160 GNUNET_CONTAINER_multihashmap_remove (connections_map,
3161 &s->specifics.tcp_udp.state_key,
3162 s));
3163 GNUNET_CONTAINER_heap_remove_node (s->specifics.tcp_udp.heap_node);
3164 s->specifics.tcp_udp.heap_node = NULL;
3165 }
3166 }
3167 if (NULL != s->th)
3168 {
3169 GNUNET_CADET_notify_transmit_ready_cancel (s->th);
3170 s->th = NULL;
3171 }
3172 GNUNET_free (s);
3173}
3174
3175
3176/**
3177 * Function that frees everything from a hashmap 3081 * Function that frees everything from a hashmap
3178 * 3082 *
3179 * @param cls unused 3083 * @param cls unused
@@ -3241,6 +3145,21 @@ cleanup (void *cls)
3241 NULL); 3145 NULL);
3242 GNUNET_CONTAINER_multihashmap_destroy (services); 3146 GNUNET_CONTAINER_multihashmap_destroy (services);
3243 } 3147 }
3148 if (NULL != dns_port)
3149 {
3150 GNUNET_CADET_close_port (dns_port);
3151 dns_port = NULL;
3152 }
3153 if (NULL != cadet_port4)
3154 {
3155 GNUNET_CADET_close_port (cadet_port4);
3156 cadet_port4 = NULL;
3157 }
3158 if (NULL != cadet_port6)
3159 {
3160 GNUNET_CADET_close_port (cadet_port6);
3161 cadet_port6 = NULL;
3162 }
3244 if (NULL != cadet_handle) 3163 if (NULL != cadet_handle)
3245 { 3164 {
3246 GNUNET_CADET_disconnect (cadet_handle); 3165 GNUNET_CADET_disconnect (cadet_handle);
@@ -3286,7 +3205,8 @@ cleanup (void *cls)
3286 } 3205 }
3287 if (NULL != stats) 3206 if (NULL != stats)
3288 { 3207 {
3289 GNUNET_STATISTICS_destroy (stats, GNUNET_NO); 3208 GNUNET_STATISTICS_destroy (stats,
3209 GNUNET_NO);
3290 stats = NULL; 3210 stats = NULL;
3291 } 3211 }
3292 for (i=0;i<8;i++) 3212 for (i=0;i<8;i++)
@@ -3614,6 +3534,13 @@ parse_ip_options ()
3614static void 3534static void
3615advertise_dns_exit () 3535advertise_dns_exit ()
3616{ 3536{
3537 struct GNUNET_MQ_MessageHandler handlers[] = {
3538 GNUNET_MQ_hd_var_size (dns_request,
3539 GNUNET_MESSAGE_TYPE_VPN_DNS_TO_INTERNET,
3540 struct DnsResponseMessage,
3541 NULL),
3542 GNUNET_MQ_handler_end ()
3543 };
3617 char *dns_exit; 3544 char *dns_exit;
3618 struct GNUNET_HashCode port; 3545 struct GNUNET_HashCode port;
3619 struct in_addr dns_exit4; 3546 struct in_addr dns_exit4;
@@ -3650,10 +3577,13 @@ advertise_dns_exit ()
3650 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 3577 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3651 "Opening CADET port %s for DNS exit service\n", 3578 "Opening CADET port %s for DNS exit service\n",
3652 GNUNET_h2s (&port)); 3579 GNUNET_h2s (&port));
3653 GNUNET_CADET_open_port (cadet_handle, 3580 dns_port = GNUNET_CADET_open_port (cadet_handle,
3654 &port, 3581 &port,
3655 &new_channel, 3582 &new_channel,
3656 NULL); 3583 NULL,
3584 NULL,
3585 &clean_channel,
3586 handlers);
3657 /* advertise exit */ 3587 /* advertise exit */
3658 dht = GNUNET_DHT_connect (cfg, 3588 dht = GNUNET_DHT_connect (cfg,
3659 1); 3589 1);
@@ -3833,16 +3763,24 @@ run (void *cls,
3833 const char *cfgfile, 3763 const char *cfgfile,
3834 const struct GNUNET_CONFIGURATION_Handle *cfg_) 3764 const struct GNUNET_CONFIGURATION_Handle *cfg_)
3835{ 3765{
3836 static struct GNUNET_CADET_MessageHandler handlers[] = { 3766 struct GNUNET_MQ_MessageHandler handlers[] = {
3837 {&receive_icmp_service, GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_SERVICE, 0}, 3767 GNUNET_MQ_hd_var_size (icmp_remote,
3838 {&receive_icmp_remote, GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_INTERNET, 0}, 3768 GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_INTERNET,
3839 {&receive_udp_service, GNUNET_MESSAGE_TYPE_VPN_UDP_TO_SERVICE, 0}, 3769 struct GNUNET_EXIT_IcmpInternetMessage,
3840 {&receive_udp_remote, GNUNET_MESSAGE_TYPE_VPN_UDP_TO_INTERNET, 0}, 3770 NULL),
3841 {&receive_tcp_service, GNUNET_MESSAGE_TYPE_VPN_TCP_TO_SERVICE_START, 0}, 3771 GNUNET_MQ_hd_var_size (udp_remote,
3842 {&receive_tcp_remote, GNUNET_MESSAGE_TYPE_VPN_TCP_TO_INTERNET_START, 0}, 3772 GNUNET_MESSAGE_TYPE_VPN_UDP_TO_INTERNET,
3843 {&receive_tcp_data, GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_EXIT, 0}, 3773 struct GNUNET_EXIT_UdpInternetMessage,
3844 {&receive_dns_request, GNUNET_MESSAGE_TYPE_VPN_DNS_TO_INTERNET, 0}, 3774 NULL),
3845 {NULL, 0, 0} 3775 GNUNET_MQ_hd_var_size (tcp_remote,
3776 GNUNET_MESSAGE_TYPE_VPN_TCP_TO_INTERNET_START,
3777 struct GNUNET_EXIT_TcpInternetStartMessage,
3778 NULL),
3779 GNUNET_MQ_hd_var_size (tcp_data,
3780 GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_EXIT,
3781 struct GNUNET_EXIT_TcpDataMessage,
3782 NULL),
3783 GNUNET_MQ_handler_end ()
3846 }; 3784 };
3847 struct GNUNET_HashCode port; 3785 struct GNUNET_HashCode port;
3848 char *policy; 3786 char *policy;
@@ -3889,10 +3827,7 @@ run (void *cls,
3889 NULL); 3827 NULL);
3890 stats = GNUNET_STATISTICS_create ("exit", 3828 stats = GNUNET_STATISTICS_create ("exit",
3891 cfg); 3829 cfg);
3892 cadet_handle = GNUNET_CADET_connect (cfg, 3830 cadet_handle = GNUNET_CADET_connect (cfg);
3893 NULL,
3894 &clean_channel,
3895 handlers);
3896 if (NULL == cadet_handle) 3831 if (NULL == cadet_handle)
3897 { 3832 {
3898 GNUNET_SCHEDULER_shutdown (); 3833 GNUNET_SCHEDULER_shutdown ();
@@ -3925,10 +3860,13 @@ run (void *cls,
3925 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 3860 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3926 "Opening CADET port %s for IPv4 gateway service\n", 3861 "Opening CADET port %s for IPv4 gateway service\n",
3927 GNUNET_h2s (&port)); 3862 GNUNET_h2s (&port));
3928 GNUNET_CADET_open_port (cadet_handle, 3863 cadet_port4 = GNUNET_CADET_open_port (cadet_handle,
3929 &port, 3864 &port,
3930 &new_channel, 3865 &new_channel,
3931 NULL); 3866 NULL,
3867 NULL,
3868 &clean_channel,
3869 handlers);
3932 policy = NULL; 3870 policy = NULL;
3933 if (GNUNET_OK != 3871 if (GNUNET_OK !=
3934 GNUNET_CONFIGURATION_get_value_string (cfg, 3872 GNUNET_CONFIGURATION_get_value_string (cfg,
@@ -3962,10 +3900,13 @@ run (void *cls,
3962 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 3900 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3963 "Opening CADET port %s for IPv6 gateway service\n", 3901 "Opening CADET port %s for IPv6 gateway service\n",
3964 GNUNET_h2s (&port)); 3902 GNUNET_h2s (&port));
3965 GNUNET_CADET_open_port (cadet_handle, 3903 cadet_port6 = GNUNET_CADET_open_port (cadet_handle,
3966 &port, 3904 &port,
3967 &new_channel, 3905 &new_channel,
3968 NULL); 3906 NULL,
3907 NULL,
3908 &clean_channel,
3909 handlers);
3969 policy = NULL; 3910 policy = NULL;
3970 if (GNUNET_OK != 3911 if (GNUNET_OK !=
3971 GNUNET_CONFIGURATION_get_value_string (cfg, 3912 GNUNET_CONFIGURATION_get_value_string (cfg,
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/fragmentation/Makefile.am b/src/fragmentation/Makefile.am
index 316f69158..85c4767c0 100644
--- a/src/fragmentation/Makefile.am
+++ b/src/fragmentation/Makefile.am
@@ -27,7 +27,7 @@ check_PROGRAMS = \
27 test_fragmentation_parallel 27 test_fragmentation_parallel
28 28
29if ENABLE_TEST_RUN 29if ENABLE_TEST_RUN
30AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; 30AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
31TESTS = $(check_PROGRAMS) 31TESTS = $(check_PROGRAMS)
32endif 32endif
33 33
diff --git a/src/fs/.gitignore b/src/fs/.gitignore
index cdfb27108..f0e2a4f7b 100644
--- a/src/fs/.gitignore
+++ b/src/fs/.gitignore
@@ -9,3 +9,35 @@ gnunet-helper-fs-publish
9gnunet-publish 9gnunet-publish
10gnunet-search 10gnunet-search
11gnunet-service-fs 11gnunet-service-fs
12test_fs_directory
13test_fs_download
14test_fs_download_cadet
15test_fs_download_indexed
16test_fs_download_persistence
17test_fs_file_information
18test_fs_getopt
19test_fs_list_indexed
20test_fs_namespace
21test_fs_namespace_list_updateable
22test_fs_publish
23test_fs_publish_persistence
24test_fs_search
25test_fs_search_persistence
26test_fs_search_probes
27test_fs_search_with_and
28test_fs_start_stop
29test_fs_test_lib
30test_fs_unindex
31test_fs_unindex_persistence
32test_fs_uri
33test_gnunet_fs_idx.py
34test_gnunet_fs_psd.py
35test_gnunet_fs_rec.py
36test_gnunet_service_fs_migration
37test_gnunet_service_fs_p2p
38test_gnunet_service_fs_p2p_cadet
39test_plugin_block_fs
40perf_gnunet_service_fs_p2p
41perf_gnunet_service_fs_p2p_index
42perf_gnunet_service_fs_p2p_respect
43rdir.gnd
diff --git a/src/fs/Makefile.am b/src/fs/Makefile.am
index 34f44f574..33260a794 100644
--- a/src/fs/Makefile.am
+++ b/src/fs/Makefile.am
@@ -219,6 +219,7 @@ gnunet_unindex_LDADD = \
219libgnunet_plugin_block_fs_la_SOURCES = \ 219libgnunet_plugin_block_fs_la_SOURCES = \
220 plugin_block_fs.c 220 plugin_block_fs.c
221libgnunet_plugin_block_fs_la_LIBADD = \ 221libgnunet_plugin_block_fs_la_LIBADD = \
222 $(top_builddir)/src/block/libgnunetblockgroup.la \
222 $(top_builddir)/src/block/libgnunetblock.la \ 223 $(top_builddir)/src/block/libgnunetblock.la \
223 libgnunetfs.la \ 224 libgnunetfs.la \
224 $(top_builddir)/src/util/libgnunetutil.la \ 225 $(top_builddir)/src/util/libgnunetutil.la \
@@ -288,7 +289,7 @@ endif
288 289
289 290
290if ENABLE_TEST_RUN 291if ENABLE_TEST_RUN
291AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; $(MONKEY) 292AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME; $(MONKEY)
292TESTS = \ 293TESTS = \
293 test_fs_directory \ 294 test_fs_directory \
294 test_fs_download \ 295 test_fs_download \
diff --git a/src/fs/fs.conf.in b/src/fs/fs.conf.in
index 3534378ae..d46de387f 100644
--- a/src/fs/fs.conf.in
+++ b/src/fs/fs.conf.in
@@ -36,7 +36,7 @@ MAX_PENDING_REQUESTS = 65536
36 36
37# How many requests do we have at most waiting in the queue towards 37# How many requests do we have at most waiting in the queue towards
38# the datastore? (important for memory consumption) 38# the datastore? (important for memory consumption)
39DATASTORE_QUEUE_SIZE = 1024 39DATASTORE_QUEUE_SIZE = 32
40 40
41# Maximum frequency we're allowed to poll the datastore 41# Maximum frequency we're allowed to poll the datastore
42# for content for migration (can be used to reduce 42# for content for migration (can be used to reduce
diff --git a/src/fs/fs_api.c b/src/fs/fs_api.c
index 7e769483b..a5b82ec27 100644
--- a/src/fs/fs_api.c
+++ b/src/fs/fs_api.c
@@ -1647,7 +1647,9 @@ deserialize_publish_file (void *cls,
1647 filename, emsg); 1647 filename, emsg);
1648 GNUNET_free (emsg); 1648 GNUNET_free (emsg);
1649 } 1649 }
1650 pc->top = GNUNET_FS_make_top (h, &GNUNET_FS_publish_signal_suspend_, pc); 1650 pc->top = GNUNET_FS_make_top (h,
1651 &GNUNET_FS_publish_signal_suspend_,
1652 pc);
1651 return GNUNET_OK; 1653 return GNUNET_OK;
1652cleanup: 1654cleanup:
1653 GNUNET_free_non_null (pc->nid); 1655 GNUNET_free_non_null (pc->nid);
@@ -2278,7 +2280,9 @@ deserialize_unindex_file (void *cls,
2278 GNUNET_break (0); 2280 GNUNET_break (0);
2279 goto cleanup; 2281 goto cleanup;
2280 } 2282 }
2281 uc->top = GNUNET_FS_make_top (h, &GNUNET_FS_unindex_signal_suspend_, uc); 2283 uc->top = GNUNET_FS_make_top (h,
2284 &GNUNET_FS_unindex_signal_suspend_,
2285 uc);
2282 pi.status = GNUNET_FS_STATUS_UNINDEX_RESUME; 2286 pi.status = GNUNET_FS_STATUS_UNINDEX_RESUME;
2283 pi.value.unindex.specifics.resume.message = uc->emsg; 2287 pi.value.unindex.specifics.resume.message = uc->emsg;
2284 GNUNET_FS_unindex_make_status_ (&pi, uc, 2288 GNUNET_FS_unindex_make_status_ (&pi, uc,
@@ -2537,7 +2541,6 @@ signal_download_resume (struct GNUNET_FS_DownloadContext *dc)
2537 signal_download_resume (dcc); 2541 signal_download_resume (dcc);
2538 dcc = dcc->next; 2542 dcc = dcc->next;
2539 } 2543 }
2540 GNUNET_FS_download_start_downloading_ (dc);
2541} 2544}
2542 2545
2543 2546
@@ -2806,7 +2809,8 @@ deserialize_download (struct GNUNET_FS_Handle *h,
2806 GNUNET_FS_compute_depth (GNUNET_FS_uri_chk_get_file_size (dc->uri)); 2809 GNUNET_FS_compute_depth (GNUNET_FS_uri_chk_get_file_size (dc->uri));
2807 if (GNUNET_FS_uri_test_loc (dc->uri)) 2810 if (GNUNET_FS_uri_test_loc (dc->uri))
2808 GNUNET_assert (GNUNET_OK == 2811 GNUNET_assert (GNUNET_OK ==
2809 GNUNET_FS_uri_loc_get_peer_identity (dc->uri, &dc->target)); 2812 GNUNET_FS_uri_loc_get_peer_identity (dc->uri,
2813 &dc->target));
2810 if (NULL == dc->emsg) 2814 if (NULL == dc->emsg)
2811 { 2815 {
2812 dc->top_request = read_download_request (rh); 2816 dc->top_request = read_download_request (rh);
@@ -2816,10 +2820,14 @@ deserialize_download (struct GNUNET_FS_Handle *h,
2816 goto cleanup; 2820 goto cleanup;
2817 } 2821 }
2818 } 2822 }
2819 dn = get_download_sync_filename (dc, dc->serialization, ".dir"); 2823 dn = get_download_sync_filename (dc,
2824 dc->serialization,
2825 ".dir");
2820 if (NULL != dn) 2826 if (NULL != dn)
2821 { 2827 {
2822 if (GNUNET_YES == GNUNET_DISK_directory_test (dn, GNUNET_YES)) 2828 if (GNUNET_YES ==
2829 GNUNET_DISK_directory_test (dn,
2830 GNUNET_YES))
2823 GNUNET_DISK_directory_scan (dn, 2831 GNUNET_DISK_directory_scan (dn,
2824 &deserialize_subdownload, 2832 &deserialize_subdownload,
2825 dc); 2833 dc);
@@ -2836,15 +2844,17 @@ deserialize_download (struct GNUNET_FS_Handle *h,
2836 dc->search = search; 2844 dc->search = search;
2837 search->download = dc; 2845 search->download = dc;
2838 } 2846 }
2839 if ((NULL == parent) && (NULL == search)) 2847 if ( (NULL == parent) &&
2848 (NULL == search) )
2840 { 2849 {
2841 dc->top = 2850 dc->top
2842 GNUNET_FS_make_top (dc->h, 2851 = GNUNET_FS_make_top (dc->h,
2843 &GNUNET_FS_download_signal_suspend_, 2852 &GNUNET_FS_download_signal_suspend_,
2844 dc); 2853 dc);
2845 signal_download_resume (dc); 2854 signal_download_resume (dc);
2846 } 2855 }
2847 GNUNET_free (uris); 2856 GNUNET_free (uris);
2857 GNUNET_assert (NULL == dc->job_queue);
2848 dc->task = GNUNET_SCHEDULER_add_now (&GNUNET_FS_download_start_task_, 2858 dc->task = GNUNET_SCHEDULER_add_now (&GNUNET_FS_download_start_task_,
2849 dc); 2859 dc);
2850 return; 2860 return;
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 53b836f22..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);
@@ -1363,7 +1398,6 @@ do_reconnect (void *cls)
1363static void 1398static void
1364try_reconnect (struct GNUNET_FS_DownloadContext *dc) 1399try_reconnect (struct GNUNET_FS_DownloadContext *dc)
1365{ 1400{
1366
1367 if (NULL != dc->mq) 1401 if (NULL != dc->mq)
1368 { 1402 {
1369 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1403 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -1380,6 +1414,7 @@ try_reconnect (struct GNUNET_FS_DownloadContext *dc)
1380 "Will try to reconnect in %s\n", 1414 "Will try to reconnect in %s\n",
1381 GNUNET_STRINGS_relative_time_to_string (dc->reconnect_backoff, 1415 GNUNET_STRINGS_relative_time_to_string (dc->reconnect_backoff,
1382 GNUNET_YES)); 1416 GNUNET_YES));
1417 GNUNET_break (NULL != dc->job_queue);
1383 dc->task = 1418 dc->task =
1384 GNUNET_SCHEDULER_add_delayed (dc->reconnect_backoff, 1419 GNUNET_SCHEDULER_add_delayed (dc->reconnect_backoff,
1385 &do_reconnect, 1420 &do_reconnect,
@@ -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}
@@ -1533,7 +1572,7 @@ reconstruct_cont (void *cls)
1533 struct GNUNET_FS_DownloadContext *dc = cls; 1572 struct GNUNET_FS_DownloadContext *dc = cls;
1534 1573
1535 /* clean up state from tree encoder */ 1574 /* clean up state from tree encoder */
1536 if (dc->task != NULL) 1575 if (NULL != dc->task)
1537 { 1576 {
1538 GNUNET_SCHEDULER_cancel (dc->task); 1577 GNUNET_SCHEDULER_cancel (dc->task);
1539 dc->task = NULL; 1578 dc->task = NULL;
@@ -1584,9 +1623,13 @@ get_next_block (void *cls)
1584 * @param block_size size of block (in bytes) 1623 * @param block_size size of block (in bytes)
1585 */ 1624 */
1586static void 1625static void
1587reconstruct_cb (void *cls, const struct ContentHashKey *chk, uint64_t offset, 1626reconstruct_cb (void *cls,
1588 unsigned int depth, enum GNUNET_BLOCK_Type type, 1627 const struct ContentHashKey *chk,
1589 const void *block, uint16_t block_size) 1628 uint64_t offset,
1629 unsigned int depth,
1630 enum GNUNET_BLOCK_Type type,
1631 const void *block,
1632 uint16_t block_size)
1590{ 1633{
1591 struct GNUNET_FS_DownloadContext *dc = cls; 1634 struct GNUNET_FS_DownloadContext *dc = cls;
1592 struct GNUNET_FS_ProgressInfo pi; 1635 struct GNUNET_FS_ProgressInfo pi;
@@ -1607,7 +1650,8 @@ reconstruct_cb (void *cls, const struct ContentHashKey *chk, uint64_t offset,
1607 "Block %u < %u irrelevant for our range\n", 1650 "Block %u < %u irrelevant for our range\n",
1608 chld, 1651 chld,
1609 dr->children[0]->chk_idx); 1652 dr->children[0]->chk_idx);
1610 dc->task = GNUNET_SCHEDULER_add_now (&get_next_block, dc); 1653 dc->task = GNUNET_SCHEDULER_add_now (&get_next_block,
1654 dc);
1611 return; /* irrelevant block */ 1655 return; /* irrelevant block */
1612 } 1656 }
1613 if (chld > dr->children[dr->num_children-1]->chk_idx) 1657 if (chld > dr->children[dr->num_children-1]->chk_idx)
@@ -1701,8 +1745,10 @@ reconstruct_cb (void *cls, const struct ContentHashKey *chk, uint64_t offset,
1701 GNUNET_assert (0); 1745 GNUNET_assert (0);
1702 break; 1746 break;
1703 } 1747 }
1704 dc->task = GNUNET_SCHEDULER_add_now (&get_next_block, dc); 1748 dc->task = GNUNET_SCHEDULER_add_now (&get_next_block,
1705 if ((dr == dc->top_request) && (dr->state == BRS_DOWNLOAD_UP)) 1749 dc);
1750 if ( (dr == dc->top_request) &&
1751 (dr->state == BRS_DOWNLOAD_UP) )
1706 check_completed (dc); 1752 check_completed (dc);
1707} 1753}
1708 1754
@@ -1882,7 +1928,8 @@ GNUNET_FS_download_start_task_ (void *cls)
1882 &reconstruct_cb, 1928 &reconstruct_cb,
1883 NULL, 1929 NULL,
1884 &reconstruct_cont); 1930 &reconstruct_cont);
1885 dc->task = GNUNET_SCHEDULER_add_now (&get_next_block, dc); 1931 dc->task = GNUNET_SCHEDULER_add_now (&get_next_block,
1932 dc);
1886 } 1933 }
1887 else 1934 else
1888 { 1935 {
@@ -2037,6 +2084,7 @@ create_download_context (struct GNUNET_FS_Handle *h,
2037 filename, 2084 filename,
2038 (unsigned long long) length, 2085 (unsigned long long) length,
2039 dc->treedepth); 2086 dc->treedepth);
2087 GNUNET_assert (NULL == dc->job_queue);
2040 dc->task = GNUNET_SCHEDULER_add_now (&GNUNET_FS_download_start_task_, 2088 dc->task = GNUNET_SCHEDULER_add_now (&GNUNET_FS_download_start_task_,
2041 dc); 2089 dc);
2042 return dc; 2090 return dc;
@@ -2199,9 +2247,10 @@ GNUNET_FS_download_start_downloading_ (struct GNUNET_FS_DownloadContext *dc)
2199 if (NULL != dc->mq) 2247 if (NULL != dc->mq)
2200 return; /* already running */ 2248 return; /* already running */
2201 GNUNET_assert (NULL == dc->job_queue); 2249 GNUNET_assert (NULL == dc->job_queue);
2250 GNUNET_assert (NULL == dc->task);
2202 GNUNET_assert (NULL != dc->active); 2251 GNUNET_assert (NULL != dc->active);
2203 dc->job_queue = 2252 dc->job_queue
2204 GNUNET_FS_queue_ (dc->h, 2253 = GNUNET_FS_queue_ (dc->h,
2205 &activate_fs_download, 2254 &activate_fs_download,
2206 &deactivate_fs_download, 2255 &deactivate_fs_download,
2207 dc, 2256 dc,
@@ -2240,14 +2289,15 @@ GNUNET_FS_download_resume (struct GNUNET_FS_DownloadContext *dc)
2240 pi.status = GNUNET_FS_STATUS_DOWNLOAD_ACTIVE; 2289 pi.status = GNUNET_FS_STATUS_DOWNLOAD_ACTIVE;
2241 GNUNET_FS_download_make_status_ (&pi, dc); 2290 GNUNET_FS_download_make_status_ (&pi, dc);
2242 2291
2243 dc->job_queue = 2292 GNUNET_assert (NULL == dc->task);
2244 GNUNET_FS_queue_ (dc->h, 2293 dc->job_queue
2245 &activate_fs_download, 2294 = GNUNET_FS_queue_ (dc->h,
2246 &deactivate_fs_download, 2295 &activate_fs_download,
2247 dc, (dc->length + DBLOCK_SIZE - 1) / DBLOCK_SIZE, 2296 &deactivate_fs_download,
2248 (0 == (dc->options & GNUNET_FS_DOWNLOAD_IS_PROBE)) 2297 dc, (dc->length + DBLOCK_SIZE - 1) / DBLOCK_SIZE,
2249 ? GNUNET_FS_QUEUE_PRIORITY_NORMAL 2298 (0 == (dc->options & GNUNET_FS_DOWNLOAD_IS_PROBE))
2250 : GNUNET_FS_QUEUE_PRIORITY_PROBE); 2299 ? GNUNET_FS_QUEUE_PRIORITY_NORMAL
2300 : GNUNET_FS_QUEUE_PRIORITY_PROBE);
2251 2301
2252} 2302}
2253 2303
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 75ce4b54f..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,11 +1141,6 @@ 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,
@@ -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..0976b37e4 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_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_flag ('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_flag ('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_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_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..83c1eb505 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_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_flag ('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_flag ('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_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_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_flag ('R',
338 "recursive",
339 gettext_noop ("download a GNUnet directory recursively"),
340 &do_recursive),
341
342 GNUNET_GETOPT_option_increment_uint ('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..ac9f6777f 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_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_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..ad8f223ff 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,11 +112,14 @@ 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_flag ('i',
118 &GNUNET_GETOPT_set_one, &list_indexed_files}, 118 "list-indexed",
119 GNUNET_GETOPT_OPTION_VERBOSE (&verbose), 119 gettext_noop ("print a list of all indexed files"),
120 &list_indexed_files),
121
122 GNUNET_GETOPT_option_verbose (&verbose),
120 GNUNET_GETOPT_OPTION_END 123 GNUNET_GETOPT_OPTION_END
121 }; 124 };
122 125
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..395aad7db 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_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_flag ('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_flag ('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_flag ('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_flag ('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_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_uint ('r',
960 "replication",
961 "LEVEL",
962 gettext_noop ("set the desired replication LEVEL"),
963 &bo.replication_level),
964
965
966 GNUNET_GETOPT_option_flag ('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..ef1743436 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_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_flag ('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_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_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 e38fdb032..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"
@@ -1177,7 +1176,6 @@ handle_client_unindex (void *cls,
1177static void 1176static void
1178shutdown_task (void *cls) 1177shutdown_task (void *cls)
1179{ 1178{
1180 GSF_cadet_stop_client ();
1181 GSF_cadet_stop_server (); 1179 GSF_cadet_stop_server ();
1182 if (NULL != GSF_core) 1180 if (NULL != GSF_core)
1183 { 1181 {
@@ -1320,7 +1318,6 @@ main_init (const struct GNUNET_CONFIGURATION_Handle *c)
1320 NULL); 1318 NULL);
1321 datastore_get_load = GNUNET_LOAD_value_init (DATASTORE_LOAD_AUTODECLINE); 1319 datastore_get_load = GNUNET_LOAD_value_init (DATASTORE_LOAD_AUTODECLINE);
1322 GSF_cadet_start_server (); 1320 GSF_cadet_start_server ();
1323 GSF_cadet_start_client ();
1324 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, 1321 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1325 NULL); 1322 NULL);
1326 return GNUNET_OK; 1323 return GNUNET_OK;
@@ -1351,7 +1348,7 @@ run (void *cls,
1351 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_INFO, 1348 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_INFO,
1352 "fs", 1349 "fs",
1353 "DATASTORE_QUEUE_SIZE"); 1350 "DATASTORE_QUEUE_SIZE");
1354 dqs = 1024; 1351 dqs = 32;
1355 } 1352 }
1356 GSF_datastore_queue_size = (unsigned int) dqs; 1353 GSF_datastore_queue_size = (unsigned int) dqs;
1357 GSF_enable_randomized_delays = 1354 GSF_enable_randomized_delays =
diff --git a/src/fs/gnunet-service-fs_cadet.h b/src/fs/gnunet-service-fs_cadet.h
index 060a3993c..1fbd3a406 100644
--- a/src/fs/gnunet-service-fs_cadet.h
+++ b/src/fs/gnunet-service-fs_cadet.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
@@ -38,14 +38,15 @@ struct GSF_CadetRequest;
38 * @param cls closure 38 * @param cls closure
39 * @param type type of the block, ANY on error 39 * @param type type of the block, ANY on error
40 * @param expiration expiration time for the block 40 * @param expiration expiration time for the block
41 * @param data_size number of bytes in 'data', 0 on error 41 * @param data_size number of bytes in @a data, 0 on error
42 * @param data reply block data, NULL on error 42 * @param data reply block data, NULL on error
43 */ 43 */
44typedef void (*GSF_CadetReplyProcessor)(void *cls, 44typedef void
45 enum GNUNET_BLOCK_Type type, 45(*GSF_CadetReplyProcessor)(void *cls,
46 struct GNUNET_TIME_Absolute expiration, 46 enum GNUNET_BLOCK_Type type,
47 size_t data_size, 47 struct GNUNET_TIME_Absolute expiration,
48 const void *data); 48 size_t data_size,
49 const void *data);
49 50
50 51
51/** 52/**
@@ -55,14 +56,28 @@ typedef void (*GSF_CadetReplyProcessor)(void *cls,
55 * @param query hash to query for the block 56 * @param query hash to query for the block
56 * @param type desired type for the block 57 * @param type desired type for the block
57 * @param proc function to call with result 58 * @param proc function to call with result
58 * @param proc_cls closure for 'proc' 59 * @param proc_cls closure for @a proc
59 * @return handle to cancel the operation 60 * @return handle to cancel the operation
60 */ 61 */
61struct GSF_CadetRequest * 62struct GSF_CadetRequest *
62GSF_cadet_query (const struct GNUNET_PeerIdentity *target, 63GSF_cadet_query (const struct GNUNET_PeerIdentity *target,
63 const struct GNUNET_HashCode *query, 64 const struct GNUNET_HashCode *query,
64 enum GNUNET_BLOCK_Type type, 65 enum GNUNET_BLOCK_Type type,
65 GSF_CadetReplyProcessor proc, void *proc_cls); 66 GSF_CadetReplyProcessor proc,
67 void *proc_cls);
68
69/**
70 * Function called on each active cadets to shut them down.
71 *
72 * @param cls NULL
73 * @param key target peer, unused
74 * @param value the `struct CadetHandle` to destroy
75 * @return #GNUNET_YES (continue to iterate)
76 */
77int
78GSF_cadet_release_clients (void *cls,
79 const struct GNUNET_PeerIdentity *key,
80 void *value);
66 81
67 82
68/** 83/**
@@ -89,17 +104,15 @@ void
89GSF_cadet_stop_server (void); 104GSF_cadet_stop_server (void);
90 105
91/** 106/**
92 * Initialize subsystem for non-anonymous file-sharing. 107 * Cadet channel for creating outbound channels.
93 */ 108 */
94void 109extern struct GNUNET_CADET_Handle *cadet_handle;
95GSF_cadet_start_client (void);
96
97 110
98/** 111/**
99 * Shutdown subsystem for non-anonymous file-sharing. 112 * Map from peer identities to 'struct CadetHandles' with cadet
113 * channels to those peers.
100 */ 114 */
101void 115extern struct GNUNET_CONTAINER_MultiPeerMap *cadet_map;
102GSF_cadet_stop_client (void);
103 116
104 117
105GNUNET_NETWORK_STRUCT_BEGIN 118GNUNET_NETWORK_STRUCT_BEGIN
diff --git a/src/fs/gnunet-service-fs_cadet_client.c b/src/fs/gnunet-service-fs_cadet_client.c
index 4e268b93c..c729ebe41 100644
--- a/src/fs/gnunet-service-fs_cadet_client.c
+++ b/src/fs/gnunet-service-fs_cadet_client.c
@@ -77,7 +77,7 @@ struct GSF_CadetRequest
77 GSF_CadetReplyProcessor proc; 77 GSF_CadetReplyProcessor proc;
78 78
79 /** 79 /**
80 * Closure for 'proc' 80 * Closure for @e proc
81 */ 81 */
82 void *proc_cls; 82 void *proc_cls;
83 83
@@ -126,11 +126,6 @@ struct CadetHandle
126 struct GNUNET_CADET_Channel *channel; 126 struct GNUNET_CADET_Channel *channel;
127 127
128 /** 128 /**
129 * Handle for active write operation, or NULL.
130 */
131 struct GNUNET_CADET_TransmitHandle *wh;
132
133 /**
134 * Which peer does this cadet go to? 129 * Which peer does this cadet go to?
135 */ 130 */
136 struct GNUNET_PeerIdentity target; 131 struct GNUNET_PeerIdentity target;
@@ -140,14 +135,14 @@ struct CadetHandle
140 * a few seconds to give the application a chance to give 135 * a few seconds to give the application a chance to give
141 * us another query). 136 * us another query).
142 */ 137 */
143 struct GNUNET_SCHEDULER_Task * timeout_task; 138 struct GNUNET_SCHEDULER_Task *timeout_task;
144 139
145 /** 140 /**
146 * Task to reset cadets that had errors (asynchronously, 141 * Task to reset cadets that had errors (asynchronously,
147 * as we may not be able to do it immediately during a 142 * as we may not be able to do it immediately during a
148 * callback from the cadet API). 143 * callback from the cadet API).
149 */ 144 */
150 struct GNUNET_SCHEDULER_Task * reset_task; 145 struct GNUNET_SCHEDULER_Task *reset_task;
151 146
152}; 147};
153 148
@@ -155,13 +150,13 @@ struct CadetHandle
155/** 150/**
156 * Cadet channel for creating outbound channels. 151 * Cadet channel for creating outbound channels.
157 */ 152 */
158static struct GNUNET_CADET_Handle *cadet_handle; 153struct GNUNET_CADET_Handle *cadet_handle;
159 154
160/** 155/**
161 * Map from peer identities to 'struct CadetHandles' with cadet 156 * Map from peer identities to 'struct CadetHandles' with cadet
162 * channels to those peers. 157 * channels to those peers.
163 */ 158 */
164static struct GNUNET_CONTAINER_MultiPeerMap *cadet_map; 159struct GNUNET_CONTAINER_MultiPeerMap *cadet_map;
165 160
166 161
167/* ********************* client-side code ************************* */ 162/* ********************* client-side code ************************* */
@@ -170,10 +165,10 @@ static struct GNUNET_CONTAINER_MultiPeerMap *cadet_map;
170/** 165/**
171 * Transmit pending requests via the cadet. 166 * Transmit pending requests via the cadet.
172 * 167 *
173 * @param mh cadet to process 168 * @param cls `struct CadetHandle` to process
174 */ 169 */
175static void 170static void
176transmit_pending (struct CadetHandle *mh); 171transmit_pending (void *cls);
177 172
178 173
179/** 174/**
@@ -206,65 +201,19 @@ move_to_pending (void *cls,
206 201
207 202
208/** 203/**
209 * We had a serious error, tear down and re-create cadet from scratch. 204 * Functions with this signature are called whenever a complete reply
210 * 205 * is received.
211 * @param mh cadet to reset
212 */
213static void
214reset_cadet (struct CadetHandle *mh)
215{
216 struct GNUNET_CADET_Channel *channel = mh->channel;
217 struct GNUNET_HashCode port;
218
219 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
220 "Resetting cadet channel to %s\n",
221 GNUNET_i2s (&mh->target));
222 mh->channel = NULL;
223
224 if (NULL != channel)
225 {
226 /* Avoid loop */
227 if (NULL != mh->wh)
228 {
229 GNUNET_CADET_notify_transmit_ready_cancel (mh->wh);
230 mh->wh = NULL;
231 }
232 GNUNET_CADET_channel_destroy (channel);
233 }
234 GNUNET_CONTAINER_multihashmap_iterate (mh->waiting_map,
235 &move_to_pending,
236 mh);
237 GNUNET_CRYPTO_hash (GNUNET_APPLICATION_PORT_FS_BLOCK_TRANSFER,
238 strlen (GNUNET_APPLICATION_PORT_FS_BLOCK_TRANSFER),
239 &port);
240 mh->channel = GNUNET_CADET_channel_create (cadet_handle,
241 mh,
242 &mh->target,
243 &port,
244 GNUNET_CADET_OPTION_RELIABLE);
245 transmit_pending (mh);
246}
247
248
249/**
250 * Task called when it is time to destroy an inactive cadet channel.
251 * 206 *
252 * @param cls the `struct CadetHandle` to tear down 207 * @param cls closure with the `struct CadetHandle`
208 * @param srm the actual message
209 * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing
253 */ 210 */
254static void 211static int
255cadet_timeout (void *cls) 212check_reply (void *cls,
213 const struct CadetReplyMessage *srm)
256{ 214{
257 struct CadetHandle *mh = cls; 215 /* We check later... */
258 struct GNUNET_CADET_Channel *tun; 216 return GNUNET_OK;
259
260 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
261 "Timeout on cadet channel to %s\n",
262 GNUNET_i2s (&mh->target));
263 mh->timeout_task = NULL;
264 tun = mh->channel;
265 mh->channel = NULL;
266 if(NULL != tun)
267 GNUNET_CADET_channel_destroy (tun);
268} 217}
269 218
270 219
@@ -274,13 +223,7 @@ cadet_timeout (void *cls)
274 * @param cls the `struct CadetHandle` to tear down 223 * @param cls the `struct CadetHandle` to tear down
275 */ 224 */
276static void 225static void
277reset_cadet_task (void *cls) 226reset_cadet_task (void *cls);
278{
279 struct CadetHandle *mh = cls;
280
281 mh->reset_task = NULL;
282 reset_cadet (mh);
283}
284 227
285 228
286/** 229/**
@@ -300,83 +243,6 @@ reset_cadet_async (struct CadetHandle *mh)
300 243
301 244
302/** 245/**
303 * Functions of this signature are called whenever we are ready to transmit
304 * query via a cadet.
305 *
306 * @param cls the struct CadetHandle for which we did the write call
307 * @param size the number of bytes that can be written to @a buf
308 * @param buf where to write the message
309 * @return number of bytes written to @a buf
310 */
311static size_t
312transmit_sqm (void *cls,
313 size_t size,
314 void *buf)
315{
316 struct CadetHandle *mh = cls;
317 struct CadetQueryMessage sqm;
318 struct GSF_CadetRequest *sr;
319
320 mh->wh = NULL;
321 if (NULL == buf)
322 {
323 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
324 "Cadet channel to %s failed during transmission attempt, rebuilding\n",
325 GNUNET_i2s (&mh->target));
326 reset_cadet_async (mh);
327 return 0;
328 }
329 sr = mh->pending_head;
330 if (NULL == sr)
331 return 0;
332 GNUNET_assert (size >= sizeof (struct CadetQueryMessage));
333 GNUNET_CONTAINER_DLL_remove (mh->pending_head,
334 mh->pending_tail,
335 sr);
336 GNUNET_assert (GNUNET_OK ==
337 GNUNET_CONTAINER_multihashmap_put (mh->waiting_map,
338 &sr->query,
339 sr,
340 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
341 sr->was_transmitted = GNUNET_YES;
342 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
343 "Sending query for %s via cadet to %s\n",
344 GNUNET_h2s (&sr->query),
345 GNUNET_i2s (&mh->target));
346 sqm.header.size = htons (sizeof (sqm));
347 sqm.header.type = htons (GNUNET_MESSAGE_TYPE_FS_CADET_QUERY);
348 sqm.type = htonl (sr->type);
349 sqm.query = sr->query;
350 GNUNET_memcpy (buf, &sqm, sizeof (sqm));
351 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
352 "Successfully transmitted %u bytes via cadet to %s\n",
353 (unsigned int) size,
354 GNUNET_i2s (&mh->target));
355 transmit_pending (mh);
356 return sizeof (sqm);
357}
358
359
360/**
361 * Transmit pending requests via the cadet.
362 *
363 * @param mh cadet to process
364 */
365static void
366transmit_pending (struct CadetHandle *mh)
367{
368 if (NULL == mh->channel)
369 return;
370 if (NULL != mh->wh)
371 return;
372 mh->wh = GNUNET_CADET_notify_transmit_ready (mh->channel, GNUNET_YES /* allow cork */,
373 GNUNET_TIME_UNIT_FOREVER_REL,
374 sizeof (struct CadetQueryMessage),
375 &transmit_sqm, mh);
376}
377
378
379/**
380 * Closure for handle_reply(). 246 * Closure for handle_reply().
381 */ 247 */
382struct HandleReplyClosure 248struct HandleReplyClosure
@@ -393,7 +259,7 @@ struct HandleReplyClosure
393 struct GNUNET_TIME_Absolute expiration; 259 struct GNUNET_TIME_Absolute expiration;
394 260
395 /** 261 /**
396 * Number of bytes in 'data'. 262 * Number of bytes in @e data.
397 */ 263 */
398 size_t data_size; 264 size_t data_size;
399 265
@@ -419,9 +285,9 @@ struct HandleReplyClosure
419 * @return #GNUNET_YES (continue to iterate) 285 * @return #GNUNET_YES (continue to iterate)
420 */ 286 */
421static int 287static int
422handle_reply (void *cls, 288process_reply (void *cls,
423 const struct GNUNET_HashCode *key, 289 const struct GNUNET_HashCode *key,
424 void *value) 290 void *value)
425{ 291{
426 struct HandleReplyClosure *hrc = cls; 292 struct HandleReplyClosure *hrc = cls;
427 struct GSF_CadetRequest *sr = value; 293 struct GSF_CadetRequest *sr = value;
@@ -439,42 +305,52 @@ handle_reply (void *cls,
439 305
440 306
441/** 307/**
308 * Iterator called on each entry in a waiting map to
309 * call the 'proc' continuation and release associated
310 * resources.
311 *
312 * @param cls the `struct CadetHandle`
313 * @param key the key of the entry in the map (the query)
314 * @param value the `struct GSF_CadetRequest` to clean up
315 * @return #GNUNET_YES (continue to iterate)
316 */
317static int
318free_waiting_entry (void *cls,
319 const struct GNUNET_HashCode *key,
320 void *value)
321{
322 struct GSF_CadetRequest *sr = value;
323
324 GSF_cadet_query_cancel (sr);
325 return GNUNET_YES;
326}
327
328
329/**
442 * Functions with this signature are called whenever a complete reply 330 * Functions with this signature are called whenever a complete reply
443 * is received. 331 * is received.
444 * 332 *
445 * @param cls closure with the `struct CadetHandle` 333 * @param cls closure with the `struct CadetHandle`
446 * @param channel channel handle 334 * @param srm the actual message
447 * @param channel_ctx channel context
448 * @param message the actual message
449 * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing
450 */ 335 */
451static int 336static void
452reply_cb (void *cls, 337handle_reply (void *cls,
453 struct GNUNET_CADET_Channel *channel, 338 const struct CadetReplyMessage *srm)
454 void **channel_ctx,
455 const struct GNUNET_MessageHeader *message)
456{ 339{
457 struct CadetHandle *mh = *channel_ctx; 340 struct CadetHandle *mh = cls;
458 const struct CadetReplyMessage *srm;
459 struct HandleReplyClosure hrc; 341 struct HandleReplyClosure hrc;
460 uint16_t msize; 342 uint16_t msize;
461 enum GNUNET_BLOCK_Type type; 343 enum GNUNET_BLOCK_Type type;
462 struct GNUNET_HashCode query; 344 struct GNUNET_HashCode query;
463 345
464 msize = ntohs (message->size); 346 msize = ntohs (srm->header.size) - sizeof (struct CadetReplyMessage);
465 if (sizeof (struct CadetReplyMessage) > msize)
466 {
467 GNUNET_break_op (0);
468 reset_cadet_async (mh);
469 return GNUNET_SYSERR;
470 }
471 srm = (const struct CadetReplyMessage *) message;
472 msize -= sizeof (struct CadetReplyMessage);
473 type = (enum GNUNET_BLOCK_Type) ntohl (srm->type); 347 type = (enum GNUNET_BLOCK_Type) ntohl (srm->type);
474 if (GNUNET_YES != 348 if (GNUNET_YES !=
475 GNUNET_BLOCK_get_key (GSF_block_ctx, 349 GNUNET_BLOCK_get_key (GSF_block_ctx,
476 type, 350 type,
477 &srm[1], msize, &query)) 351 &srm[1],
352 msize,
353 &query))
478 { 354 {
479 GNUNET_break_op (0); 355 GNUNET_break_op (0);
480 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 356 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
@@ -483,13 +359,13 @@ reply_cb (void *cls,
483 msize, 359 msize,
484 GNUNET_i2s (&mh->target)); 360 GNUNET_i2s (&mh->target));
485 reset_cadet_async (mh); 361 reset_cadet_async (mh);
486 return GNUNET_SYSERR; 362 return;
487 } 363 }
488 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 364 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
489 "Received reply `%s' via cadet from peer %s\n", 365 "Received reply `%s' via cadet from peer %s\n",
490 GNUNET_h2s (&query), 366 GNUNET_h2s (&query),
491 GNUNET_i2s (&mh->target)); 367 GNUNET_i2s (&mh->target));
492 GNUNET_CADET_receive_done (channel); 368 GNUNET_CADET_receive_done (mh->channel);
493 GNUNET_STATISTICS_update (GSF_stats, 369 GNUNET_STATISTICS_update (GSF_stats,
494 gettext_noop ("# replies received via cadet"), 1, 370 gettext_noop ("# replies received via cadet"), 1,
495 GNUNET_NO); 371 GNUNET_NO);
@@ -500,16 +376,206 @@ reply_cb (void *cls,
500 hrc.found = GNUNET_NO; 376 hrc.found = GNUNET_NO;
501 GNUNET_CONTAINER_multihashmap_get_multiple (mh->waiting_map, 377 GNUNET_CONTAINER_multihashmap_get_multiple (mh->waiting_map,
502 &query, 378 &query,
503 &handle_reply, 379 &process_reply,
504 &hrc); 380 &hrc);
505 if (GNUNET_NO == hrc.found) 381 if (GNUNET_NO == hrc.found)
506 { 382 {
507 GNUNET_STATISTICS_update (GSF_stats, 383 GNUNET_STATISTICS_update (GSF_stats,
508 gettext_noop ("# replies received via cadet dropped"), 1, 384 gettext_noop ("# replies received via cadet dropped"), 1,
509 GNUNET_NO); 385 GNUNET_NO);
510 return GNUNET_OK;
511 } 386 }
512 return GNUNET_OK; 387}
388
389
390/**
391 * Function called by cadet when a client disconnects.
392 * Cleans up our `struct CadetClient` of that channel.
393 *
394 * @param cls our `struct CadetClient`
395 * @param channel channel of the disconnecting client
396 */
397static void
398disconnect_cb (void *cls,
399 const struct GNUNET_CADET_Channel *channel)
400{
401 struct CadetHandle *mh = cls;
402 struct GSF_CadetRequest *sr;
403
404 if (NULL == mh->channel)
405 return; /* being destroyed elsewhere */
406 GNUNET_assert (channel == mh->channel);
407 mh->channel = NULL;
408 while (NULL != (sr = mh->pending_head))
409 GSF_cadet_query_cancel (sr);
410 /* first remove `mh` from the `cadet_map`, so that if the
411 callback from `free_waiting_entry()` happens to re-issue
412 the request, we don't immediately have it back in the
413 `waiting_map`. */
414 GNUNET_assert (GNUNET_OK ==
415 GNUNET_CONTAINER_multipeermap_remove (cadet_map,
416 &mh->target,
417 mh));
418 GNUNET_CONTAINER_multihashmap_iterate (mh->waiting_map,
419 &free_waiting_entry,
420 mh);
421 if (NULL != mh->timeout_task)
422 GNUNET_SCHEDULER_cancel (mh->timeout_task);
423 if (NULL != mh->reset_task)
424 GNUNET_SCHEDULER_cancel (mh->reset_task);
425 GNUNET_assert (0 ==
426 GNUNET_CONTAINER_multihashmap_size (mh->waiting_map));
427 GNUNET_CONTAINER_multihashmap_destroy (mh->waiting_map);
428 GNUNET_free (mh);
429}
430
431
432/**
433 * Function called whenever an MQ-channel's transmission window size changes.
434 *
435 * The first callback in an outgoing channel will be with a non-zero value
436 * and will mean the channel is connected to the destination.
437 *
438 * For an incoming channel it will be called immediately after the
439 * #GNUNET_CADET_ConnectEventHandler, also with a non-zero value.
440 *
441 * @param cls Channel closure.
442 * @param channel Connection to the other end (henceforth invalid).
443 * @param window_size New window size. If the is more messages than buffer size
444 * this value will be negative..
445 */
446static void
447window_change_cb (void *cls,
448 const struct GNUNET_CADET_Channel *channel,
449 int window_size)
450{
451 /* FIXME: for flow control, implement? */
452#if 0
453 /* Something like this instead of the GNUNET_MQ_notify_sent() in
454 transmit_pending() might be good (once the window change CB works...) */
455 if (0 < window_size) /* test needed? */
456 transmit_pending (mh);
457#endif
458}
459
460
461/**
462 * We had a serious error, tear down and re-create cadet from scratch.
463 *
464 * @param mh cadet to reset
465 */
466static void
467reset_cadet (struct CadetHandle *mh)
468{
469 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
470 "Resetting cadet channel to %s\n",
471 GNUNET_i2s (&mh->target));
472 GNUNET_CADET_channel_destroy (mh->channel);
473 mh->channel = NULL;
474 GNUNET_CONTAINER_multihashmap_iterate (mh->waiting_map,
475 &move_to_pending,
476 mh);
477 {
478 struct GNUNET_MQ_MessageHandler handlers[] = {
479 GNUNET_MQ_hd_var_size (reply,
480 GNUNET_MESSAGE_TYPE_FS_CADET_REPLY,
481 struct CadetReplyMessage,
482 mh),
483 GNUNET_MQ_handler_end ()
484 };
485 struct GNUNET_HashCode port;
486
487 GNUNET_CRYPTO_hash (GNUNET_APPLICATION_PORT_FS_BLOCK_TRANSFER,
488 strlen (GNUNET_APPLICATION_PORT_FS_BLOCK_TRANSFER),
489 &port);
490 mh->channel = GNUNET_CADET_channel_create (cadet_handle,
491 mh,
492 &mh->target,
493 &port,
494 GNUNET_CADET_OPTION_RELIABLE,
495 &window_change_cb,
496 &disconnect_cb,
497 handlers);
498 }
499 transmit_pending (mh);
500}
501
502
503/**
504 * Task called when it is time to destroy an inactive cadet channel.
505 *
506 * @param cls the `struct CadetHandle` to tear down
507 */
508static void
509cadet_timeout (void *cls)
510{
511 struct CadetHandle *mh = cls;
512 struct GNUNET_CADET_Channel *tun;
513
514 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
515 "Timeout on cadet channel to %s\n",
516 GNUNET_i2s (&mh->target));
517 mh->timeout_task = NULL;
518 tun = mh->channel;
519 mh->channel = NULL;
520 if (NULL != tun)
521 GNUNET_CADET_channel_destroy (tun);
522}
523
524
525/**
526 * Task called when it is time to reset an cadet.
527 *
528 * @param cls the `struct CadetHandle` to tear down
529 */
530static void
531reset_cadet_task (void *cls)
532{
533 struct CadetHandle *mh = cls;
534
535 mh->reset_task = NULL;
536 reset_cadet (mh);
537}
538
539
540/**
541 * Transmit pending requests via the cadet.
542 *
543 * @param cls `struct CadetHandle` to process
544 */
545static void
546transmit_pending (void *cls)
547{
548 struct CadetHandle *mh = cls;
549 struct GNUNET_MQ_Handle *mq = GNUNET_CADET_get_mq (mh->channel);
550 struct GSF_CadetRequest *sr;
551 struct GNUNET_MQ_Envelope *env;
552 struct CadetQueryMessage *sqm;
553
554 if ( (0 != GNUNET_MQ_get_length (mq)) ||
555 (NULL == (sr = mh->pending_head)) )
556 return;
557 GNUNET_CONTAINER_DLL_remove (mh->pending_head,
558 mh->pending_tail,
559 sr);
560 GNUNET_assert (GNUNET_OK ==
561 GNUNET_CONTAINER_multihashmap_put (mh->waiting_map,
562 &sr->query,
563 sr,
564 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
565 sr->was_transmitted = GNUNET_YES;
566 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
567 "Sending query for %s via cadet to %s\n",
568 GNUNET_h2s (&sr->query),
569 GNUNET_i2s (&mh->target));
570 env = GNUNET_MQ_msg (sqm,
571 GNUNET_MESSAGE_TYPE_FS_CADET_QUERY);
572 sqm->type = htonl (sr->type);
573 sqm->query = sr->query;
574 GNUNET_MQ_notify_sent (env,
575 &transmit_pending,
576 mh);
577 GNUNET_MQ_send (mq,
578 env);
513} 579}
514 580
515 581
@@ -522,7 +588,6 @@ static struct CadetHandle *
522get_cadet (const struct GNUNET_PeerIdentity *target) 588get_cadet (const struct GNUNET_PeerIdentity *target)
523{ 589{
524 struct CadetHandle *mh; 590 struct CadetHandle *mh;
525 struct GNUNET_HashCode port;
526 591
527 mh = GNUNET_CONTAINER_multipeermap_get (cadet_map, 592 mh = GNUNET_CONTAINER_multipeermap_get (cadet_map,
528 target); 593 target);
@@ -549,17 +614,28 @@ get_cadet (const struct GNUNET_PeerIdentity *target)
549 &mh->target, 614 &mh->target,
550 mh, 615 mh,
551 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); 616 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
552 GNUNET_CRYPTO_hash (GNUNET_APPLICATION_PORT_FS_BLOCK_TRANSFER, 617 {
553 strlen (GNUNET_APPLICATION_PORT_FS_BLOCK_TRANSFER), 618 struct GNUNET_MQ_MessageHandler handlers[] = {
554 &port); 619 GNUNET_MQ_hd_var_size (reply,
555 mh->channel = GNUNET_CADET_channel_create (cadet_handle, 620 GNUNET_MESSAGE_TYPE_FS_CADET_REPLY,
556 mh, 621 struct CadetReplyMessage,
557 &mh->target, 622 mh),
558 &port, 623 GNUNET_MQ_handler_end ()
559 GNUNET_CADET_OPTION_RELIABLE); 624 };
560 GNUNET_assert (mh == 625 struct GNUNET_HashCode port;
561 GNUNET_CONTAINER_multipeermap_get (cadet_map, 626
562 target)); 627 GNUNET_CRYPTO_hash (GNUNET_APPLICATION_PORT_FS_BLOCK_TRANSFER,
628 strlen (GNUNET_APPLICATION_PORT_FS_BLOCK_TRANSFER),
629 &port);
630 mh->channel = GNUNET_CADET_channel_create (cadet_handle,
631 mh,
632 &mh->target,
633 &port,
634 GNUNET_CADET_OPTION_RELIABLE,
635 &window_change_cb,
636 &disconnect_cb,
637 handlers);
638 }
563 return mh; 639 return mh;
564} 640}
565 641
@@ -576,9 +652,10 @@ get_cadet (const struct GNUNET_PeerIdentity *target)
576 */ 652 */
577struct GSF_CadetRequest * 653struct GSF_CadetRequest *
578GSF_cadet_query (const struct GNUNET_PeerIdentity *target, 654GSF_cadet_query (const struct GNUNET_PeerIdentity *target,
579 const struct GNUNET_HashCode *query, 655 const struct GNUNET_HashCode *query,
580 enum GNUNET_BLOCK_Type type, 656 enum GNUNET_BLOCK_Type type,
581 GSF_CadetReplyProcessor proc, void *proc_cls) 657 GSF_CadetReplyProcessor proc,
658 void *proc_cls)
582{ 659{
583 struct CadetHandle *mh; 660 struct CadetHandle *mh;
584 struct GSF_CadetRequest *sr; 661 struct GSF_CadetRequest *sr;
@@ -646,93 +723,6 @@ GSF_cadet_query_cancel (struct GSF_CadetRequest *sr)
646 723
647 724
648/** 725/**
649 * Iterator called on each entry in a waiting map to
650 * call the 'proc' continuation and release associated
651 * resources.
652 *
653 * @param cls the `struct CadetHandle`
654 * @param key the key of the entry in the map (the query)
655 * @param value the `struct GSF_CadetRequest` to clean up
656 * @return #GNUNET_YES (continue to iterate)
657 */
658static int
659free_waiting_entry (void *cls,
660 const struct GNUNET_HashCode *key,
661 void *value)
662{
663 struct GSF_CadetRequest *sr = value;
664
665 GSF_cadet_query_cancel (sr);
666 return GNUNET_YES;
667}
668
669
670/**
671 * Function called by cadet when a client disconnects.
672 * Cleans up our `struct CadetClient` of that channel.
673 *
674 * @param cls NULL
675 * @param channel channel of the disconnecting client
676 * @param channel_ctx our `struct CadetClient`
677 */
678static void
679cleaner_cb (void *cls,
680 const struct GNUNET_CADET_Channel *channel,
681 void *channel_ctx)
682{
683 struct CadetHandle *mh = channel_ctx;
684 struct GSF_CadetRequest *sr;
685
686 if (NULL == mh->channel)
687 return; /* being destroyed elsewhere */
688 GNUNET_assert (channel == mh->channel);
689 mh->channel = NULL;
690 while (NULL != (sr = mh->pending_head))
691 GSF_cadet_query_cancel (sr);
692 /* first remove `mh` from the `cadet_map`, so that if the
693 callback from `free_waiting_entry()` happens to re-issue
694 the request, we don't immediately have it back in the
695 `waiting_map`. */
696 GNUNET_assert (GNUNET_OK ==
697 GNUNET_CONTAINER_multipeermap_remove (cadet_map,
698 &mh->target,
699 mh));
700 GNUNET_CONTAINER_multihashmap_iterate (mh->waiting_map,
701 &free_waiting_entry,
702 mh);
703 if (NULL != mh->wh)
704 GNUNET_CADET_notify_transmit_ready_cancel (mh->wh);
705 if (NULL != mh->timeout_task)
706 GNUNET_SCHEDULER_cancel (mh->timeout_task);
707 if (NULL != mh->reset_task)
708 GNUNET_SCHEDULER_cancel (mh->reset_task);
709 GNUNET_assert (0 ==
710 GNUNET_CONTAINER_multihashmap_size (mh->waiting_map));
711 GNUNET_CONTAINER_multihashmap_destroy (mh->waiting_map);
712 GNUNET_free (mh);
713}
714
715
716/**
717 * Initialize subsystem for non-anonymous file-sharing.
718 */
719void
720GSF_cadet_start_client ()
721{
722 static const struct GNUNET_CADET_MessageHandler handlers[] = {
723 { &reply_cb, GNUNET_MESSAGE_TYPE_FS_CADET_REPLY, 0 },
724 { NULL, 0, 0 }
725 };
726
727 cadet_map = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
728 cadet_handle = GNUNET_CADET_connect (GSF_cfg,
729 NULL,
730 &cleaner_cb,
731 handlers);
732}
733
734
735/**
736 * Function called on each active cadets to shut them down. 726 * Function called on each active cadets to shut them down.
737 * 727 *
738 * @param cls NULL 728 * @param cls NULL
@@ -740,10 +730,10 @@ GSF_cadet_start_client ()
740 * @param value the `struct CadetHandle` to destroy 730 * @param value the `struct CadetHandle` to destroy
741 * @return #GNUNET_YES (continue to iterate) 731 * @return #GNUNET_YES (continue to iterate)
742 */ 732 */
743static int 733int
744release_cadets (void *cls, 734GSF_cadet_release_clients (void *cls,
745 const struct GNUNET_PeerIdentity *key, 735 const struct GNUNET_PeerIdentity *key,
746 void *value) 736 void *value)
747{ 737{
748 struct CadetHandle *mh = value; 738 struct CadetHandle *mh = value;
749 739
@@ -756,23 +746,5 @@ release_cadets (void *cls,
756} 746}
757 747
758 748
759/**
760 * Shutdown subsystem for non-anonymous file-sharing.
761 */
762void
763GSF_cadet_stop_client ()
764{
765 GNUNET_CONTAINER_multipeermap_iterate (cadet_map,
766 &release_cadets,
767 NULL);
768 GNUNET_CONTAINER_multipeermap_destroy (cadet_map);
769 cadet_map = NULL;
770 if (NULL != cadet_handle)
771 {
772 GNUNET_CADET_disconnect (cadet_handle);
773 cadet_handle = NULL;
774 }
775}
776
777 749
778/* end of gnunet-service-fs_cadet_client.c */ 750/* end of gnunet-service-fs_cadet_client.c */
diff --git a/src/fs/gnunet-service-fs_cadet_server.c b/src/fs/gnunet-service-fs_cadet_server.c
index ac86537c3..02ebb2ffe 100644
--- a/src/fs/gnunet-service-fs_cadet_server.c
+++ b/src/fs/gnunet-service-fs_cadet_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) 2012, 2013 GNUnet e.V. 3 Copyright (C) 2012, 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
@@ -86,11 +86,6 @@ struct CadetClient
86 struct GNUNET_CADET_Channel *channel; 86 struct GNUNET_CADET_Channel *channel;
87 87
88 /** 88 /**
89 * Handle for active write operation, or NULL.
90 */
91 struct GNUNET_CADET_TransmitHandle *wh;
92
93 /**
94 * Head of write queue. 89 * Head of write queue.
95 */ 90 */
96 struct WriteQueueItem *wqi_head; 91 struct WriteQueueItem *wqi_head;
@@ -124,9 +119,9 @@ struct CadetClient
124 119
125 120
126/** 121/**
127 * Listen channel for incoming requests. 122 * Listen port for incoming requests.
128 */ 123 */
129static struct GNUNET_CADET_Handle *listen_channel; 124static struct GNUNET_CADET_Port *cadet_port;
130 125
131/** 126/**
132 * Head of DLL of cadet clients. 127 * Head of DLL of cadet clients.
@@ -188,121 +183,29 @@ refresh_timeout_task (struct CadetClient *sc)
188 183
189 184
190/** 185/**
191 * We're done handling a request from a client, read the next one. 186 * Check if we are done with the write queue, and if so tell CADET
187 * that we are ready to read more.
192 * 188 *
193 * @param sc client to continue reading requests from 189 * @param cls where to process the write queue
194 */ 190 */
195static void 191static void
196continue_reading (struct CadetClient *sc) 192continue_writing (void *cls)
197{
198 refresh_timeout_task (sc);
199 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
200 "Finished processing cadet request from client %p, ready to receive the next one\n",
201 sc);
202 GNUNET_CADET_receive_done (sc->channel);
203}
204
205
206/**
207 * Transmit the next entry from the write queue.
208 *
209 * @param sc where to process the write queue
210 */
211static void
212continue_writing (struct CadetClient *sc);
213
214
215/**
216 * Send a reply now, cadet is ready.
217 *
218 * @param cls closure with the `struct CadetClient` which sent the query
219 * @param size number of bytes available in @a buf
220 * @param buf where to write the message
221 * @return number of bytes written to @a buf
222 */
223static size_t
224write_continuation (void *cls,
225 size_t size,
226 void *buf)
227{ 193{
228 struct CadetClient *sc = cls; 194 struct CadetClient *sc = cls;
229 struct GNUNET_CADET_Channel *tun; 195 struct GNUNET_MQ_Handle *mq;
230 struct WriteQueueItem *wqi;
231 size_t ret;
232 196
233 sc->wh = NULL; 197 mq = GNUNET_CADET_get_mq (sc->channel);
234 if (NULL == (wqi = sc->wqi_head)) 198 if (0 != GNUNET_MQ_get_length (mq))
235 {
236 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
237 "Write queue empty, reading more requests\n");
238 return 0;
239 }
240 if ( (0 == size) ||
241 (size < wqi->msize) )
242 {
243 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
244 "Transmission of reply failed, terminating cadet\n");
245 tun = sc->channel;
246 sc->channel = NULL;
247 GNUNET_CADET_channel_destroy (tun);
248 return 0;
249 }
250 GNUNET_CONTAINER_DLL_remove (sc->wqi_head,
251 sc->wqi_tail,
252 wqi);
253 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
254 "Transmitted %u byte reply via cadet to %p\n",
255 (unsigned int) size,
256 sc);
257 GNUNET_STATISTICS_update (GSF_stats,
258 gettext_noop ("# Blocks transferred via cadet"), 1,
259 GNUNET_NO);
260 ret = wqi->msize;
261 GNUNET_memcpy (buf, &wqi[1], ret);
262 GNUNET_free (wqi);
263 continue_writing (sc);
264 return ret;
265}
266
267
268/**
269 * Transmit the next entry from the write queue.
270 *
271 * @param sc where to process the write queue
272 */
273static void
274continue_writing (struct CadetClient *sc)
275{
276 struct WriteQueueItem *wqi;
277 struct GNUNET_CADET_Channel *tun;
278
279 if (NULL != sc->wh)
280 { 199 {
281 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 200 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
282 "Write pending, waiting for it to complete\n"); 201 "Write pending, waiting for it to complete\n");
283 return; /* write already pending */
284 }
285 if (NULL == (wqi = sc->wqi_head))
286 {
287 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
288 "Write queue empty, reading more requests\n");
289 continue_reading (sc);
290 return;
291 }
292 sc->wh = GNUNET_CADET_notify_transmit_ready (sc->channel, GNUNET_NO,
293 GNUNET_TIME_UNIT_FOREVER_REL,
294 wqi->msize,
295 &write_continuation,
296 sc);
297 if (NULL == sc->wh)
298 {
299 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
300 "Write failed; terminating cadet\n");
301 tun = sc->channel;
302 sc->channel = NULL;
303 GNUNET_CADET_channel_destroy (tun);
304 return; 202 return;
305 } 203 }
204 refresh_timeout_task (sc);
205 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
206 "Finished processing cadet request from client %p, ready to receive the next one\n",
207 sc);
208 GNUNET_CADET_receive_done (sc->channel);
306} 209}
307 210
308 211
@@ -316,24 +219,26 @@ continue_writing (struct CadetClient *sc)
316 * @param type type of the content 219 * @param type type of the content
317 * @param priority priority of the content 220 * @param priority priority of the content
318 * @param anonymity anonymity-level for the content 221 * @param anonymity anonymity-level for the content
222 * @param replication replication-level for the content
319 * @param expiration expiration time for the content 223 * @param expiration expiration time for the content
320 * @param uid unique identifier for the datum; 224 * @param uid unique identifier for the datum;
321 * maybe 0 if no unique identifier is available 225 * maybe 0 if no unique identifier is available
322 */ 226 */
323static void 227static void
324handle_datastore_reply (void *cls, 228handle_datastore_reply (void *cls,
325 const struct GNUNET_HashCode *key, 229 const struct GNUNET_HashCode *key,
326 size_t size, 230 size_t size,
327 const void *data, 231 const void *data,
328 enum GNUNET_BLOCK_Type type, 232 enum GNUNET_BLOCK_Type type,
329 uint32_t priority, 233 uint32_t priority,
330 uint32_t anonymity, 234 uint32_t anonymity,
331 struct GNUNET_TIME_Absolute expiration, 235 uint32_t replication,
236 struct GNUNET_TIME_Absolute expiration,
332 uint64_t uid) 237 uint64_t uid)
333{ 238{
334 struct CadetClient *sc = cls; 239 struct CadetClient *sc = cls;
335 size_t msize = size + sizeof (struct CadetReplyMessage); 240 size_t msize = size + sizeof (struct CadetReplyMessage);
336 struct WriteQueueItem *wqi; 241 struct GNUNET_MQ_Envelope *env;
337 struct CadetReplyMessage *srm; 242 struct CadetReplyMessage *srm;
338 243
339 sc->qe = NULL; 244 sc->qe = NULL;
@@ -357,7 +262,8 @@ handle_datastore_reply (void *cls,
357 GNUNET_h2s (key)); 262 GNUNET_h2s (key));
358 } 263 }
359 GNUNET_STATISTICS_update (GSF_stats, 264 GNUNET_STATISTICS_update (GSF_stats,
360 gettext_noop ("# queries received via CADET not answered"), 1, 265 gettext_noop ("# queries received via CADET not answered"),
266 1,
361 GNUNET_NO); 267 GNUNET_NO);
362 continue_writing (sc); 268 continue_writing (sc);
363 return; 269 return;
@@ -369,11 +275,16 @@ handle_datastore_reply (void *cls,
369 GNUNET_h2s (key)); 275 GNUNET_h2s (key));
370 if (GNUNET_OK != 276 if (GNUNET_OK !=
371 GNUNET_FS_handle_on_demand_block (key, 277 GNUNET_FS_handle_on_demand_block (key,
372 size, data, type, 278 size,
373 priority, anonymity, 279 data,
374 expiration, uid, 280 type,
375 &handle_datastore_reply, 281 priority,
376 sc)) 282 anonymity,
283 replication,
284 expiration,
285 uid,
286 &handle_datastore_reply,
287 sc))
377 { 288 {
378 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 289 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
379 "On-demand encoding request failed\n"); 290 "On-demand encoding request failed\n");
@@ -381,7 +292,7 @@ handle_datastore_reply (void *cls,
381 } 292 }
382 return; 293 return;
383 } 294 }
384 if (msize > GNUNET_SERVER_MAX_MESSAGE_SIZE) 295 if (msize > GNUNET_MAX_MESSAGE_SIZE)
385 { 296 {
386 GNUNET_break (0); 297 GNUNET_break (0);
387 continue_writing (sc); 298 continue_writing (sc);
@@ -394,19 +305,23 @@ handle_datastore_reply (void *cls,
394 (unsigned int) type, 305 (unsigned int) type,
395 GNUNET_h2s (key), 306 GNUNET_h2s (key),
396 sc); 307 sc);
397 wqi = GNUNET_malloc (sizeof (struct WriteQueueItem) + msize); 308 env = GNUNET_MQ_msg_extra (srm,
398 wqi->msize = msize; 309 size,
399 srm = (struct CadetReplyMessage *) &wqi[1]; 310 GNUNET_MESSAGE_TYPE_FS_CADET_REPLY);
400 srm->header.size = htons ((uint16_t) msize);
401 srm->header.type = htons (GNUNET_MESSAGE_TYPE_FS_CADET_REPLY);
402 srm->type = htonl (type); 311 srm->type = htonl (type);
403 srm->expiration = GNUNET_TIME_absolute_hton (expiration); 312 srm->expiration = GNUNET_TIME_absolute_hton (expiration);
404 GNUNET_memcpy (&srm[1], data, size); 313 GNUNET_memcpy (&srm[1],
405 sc->reply_size = msize; 314 data,
406 GNUNET_CONTAINER_DLL_insert (sc->wqi_head, 315 size);
407 sc->wqi_tail, 316 GNUNET_MQ_notify_sent (env,
408 wqi); 317 &continue_writing,
409 continue_writing (sc); 318 sc);
319 GNUNET_STATISTICS_update (GSF_stats,
320 gettext_noop ("# Blocks transferred via cadet"),
321 1,
322 GNUNET_NO);
323 GNUNET_MQ_send (GNUNET_CADET_get_mq (sc->channel),
324 env);
410} 325}
411 326
412 327
@@ -414,46 +329,39 @@ handle_datastore_reply (void *cls,
414 * Functions with this signature are called whenever a 329 * Functions with this signature are called whenever a
415 * complete query message is received. 330 * complete query message is received.
416 * 331 *
417 * Do not call #GNUNET_SERVER_mst_destroy() in callback
418 *
419 * @param cls closure with the `struct CadetClient` 332 * @param cls closure with the `struct CadetClient`
420 * @param channel channel handle 333 * @param sqm the actual message
421 * @param channel_ctx channel context
422 * @param message the actual message
423 * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing
424 */ 334 */
425static int 335static void
426request_cb (void *cls, 336handle_request (void *cls,
427 struct GNUNET_CADET_Channel *channel, 337 const struct CadetQueryMessage *sqm)
428 void **channel_ctx,
429 const struct GNUNET_MessageHeader *message)
430{ 338{
431 struct CadetClient *sc = *channel_ctx; 339 struct CadetClient *sc = cls;
432 const struct CadetQueryMessage *sqm;
433 340
434 sqm = (const struct CadetQueryMessage *) message;
435 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 341 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
436 "Received query for `%s' via cadet from client %p\n", 342 "Received query for `%s' via cadet from client %p\n",
437 GNUNET_h2s (&sqm->query), 343 GNUNET_h2s (&sqm->query),
438 sc); 344 sc);
439 GNUNET_STATISTICS_update (GSF_stats, 345 GNUNET_STATISTICS_update (GSF_stats,
440 gettext_noop ("# queries received via cadet"), 1, 346 gettext_noop ("# queries received via cadet"),
347 1,
441 GNUNET_NO); 348 GNUNET_NO);
442 refresh_timeout_task (sc); 349 refresh_timeout_task (sc);
443 sc->qe = GNUNET_DATASTORE_get_key (GSF_dsh, 350 sc->qe = GNUNET_DATASTORE_get_key (GSF_dsh,
444 0, 351 0 /* next_uid */,
445 &sqm->query, 352 false /* random */,
446 ntohl (sqm->type), 353 &sqm->query,
447 0 /* priority */, 354 ntohl (sqm->type),
448 GSF_datastore_queue_size, 355 0 /* priority */,
449 &handle_datastore_reply, sc); 356 GSF_datastore_queue_size,
357 &handle_datastore_reply,
358 sc);
450 if (NULL == sc->qe) 359 if (NULL == sc->qe)
451 { 360 {
452 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 361 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
453 "Queueing request with datastore failed (queue full?)\n"); 362 "Queueing request with datastore failed (queue full?)\n");
454 continue_writing (sc); 363 continue_writing (sc);
455 } 364 }
456 return GNUNET_OK;
457} 365}
458 366
459 367
@@ -464,16 +372,12 @@ request_cb (void *cls,
464 * @param channel the channel representing the cadet 372 * @param channel the channel representing the cadet
465 * @param initiator the identity of the peer who wants to establish a cadet 373 * @param initiator the identity of the peer who wants to establish a cadet
466 * with us; NULL on binding error 374 * with us; NULL on binding error
467 * @param port cadet port used for the incoming connection 375 * @return initial channel context (our `struct CadetClient`)
468 * @param options channel option flags
469 * @return initial channel context (our 'struct CadetClient')
470 */ 376 */
471static void * 377static void *
472accept_cb (void *cls, 378connect_cb (void *cls,
473 struct GNUNET_CADET_Channel *channel, 379 struct GNUNET_CADET_Channel *channel,
474 const struct GNUNET_PeerIdentity *initiator, 380 const struct GNUNET_PeerIdentity *initiator)
475 const struct GNUNET_HashCode *port,
476 enum GNUNET_CADET_ChannelOption options)
477{ 381{
478 struct CadetClient *sc; 382 struct CadetClient *sc;
479 383
@@ -481,13 +385,15 @@ accept_cb (void *cls,
481 if (sc_count >= sc_count_max) 385 if (sc_count >= sc_count_max)
482 { 386 {
483 GNUNET_STATISTICS_update (GSF_stats, 387 GNUNET_STATISTICS_update (GSF_stats,
484 gettext_noop ("# cadet client connections rejected"), 1, 388 gettext_noop ("# cadet client connections rejected"),
389 1,
485 GNUNET_NO); 390 GNUNET_NO);
486 GNUNET_CADET_channel_destroy (channel); 391 GNUNET_CADET_channel_destroy (channel);
487 return NULL; 392 return NULL;
488 } 393 }
489 GNUNET_STATISTICS_update (GSF_stats, 394 GNUNET_STATISTICS_update (GSF_stats,
490 gettext_noop ("# cadet connections active"), 1, 395 gettext_noop ("# cadet connections active"),
396 1,
491 GNUNET_NO); 397 GNUNET_NO);
492 sc = GNUNET_new (struct CadetClient); 398 sc = GNUNET_new (struct CadetClient);
493 sc->channel = channel; 399 sc->channel = channel;
@@ -506,18 +412,17 @@ accept_cb (void *cls,
506 412
507/** 413/**
508 * Function called by cadet when a client disconnects. 414 * Function called by cadet when a client disconnects.
509 * Cleans up our 'struct CadetClient' of that channel. 415 * Cleans up our `struct CadetClient` of that channel.
510 * 416 *
511 * @param cls NULL 417 * @param cls our `struct CadetClient`
512 * @param channel channel of the disconnecting client 418 * @param channel channel of the disconnecting client
513 * @param channel_ctx our 'struct CadetClient' 419 * @param channel_ctx
514 */ 420 */
515static void 421static void
516cleaner_cb (void *cls, 422disconnect_cb (void *cls,
517 const struct GNUNET_CADET_Channel *channel, 423 const struct GNUNET_CADET_Channel *channel)
518 void *channel_ctx)
519{ 424{
520 struct CadetClient *sc = channel_ctx; 425 struct CadetClient *sc = cls;
521 struct WriteQueueItem *wqi; 426 struct WriteQueueItem *wqi;
522 427
523 if (NULL == sc) 428 if (NULL == sc)
@@ -533,8 +438,6 @@ cleaner_cb (void *cls,
533 GNUNET_SCHEDULER_cancel (sc->terminate_task); 438 GNUNET_SCHEDULER_cancel (sc->terminate_task);
534 if (NULL != sc->timeout_task) 439 if (NULL != sc->timeout_task)
535 GNUNET_SCHEDULER_cancel (sc->timeout_task); 440 GNUNET_SCHEDULER_cancel (sc->timeout_task);
536 if (NULL != sc->wh)
537 GNUNET_CADET_notify_transmit_ready_cancel (sc->wh);
538 if (NULL != sc->qe) 441 if (NULL != sc->qe)
539 GNUNET_DATASTORE_cancel (sc->qe); 442 GNUNET_DATASTORE_cancel (sc->qe);
540 while (NULL != (wqi = sc->wqi_head)) 443 while (NULL != (wqi = sc->wqi_head))
@@ -553,14 +456,40 @@ cleaner_cb (void *cls,
553 456
554 457
555/** 458/**
459 * Function called whenever an MQ-channel's transmission window size changes.
460 *
461 * The first callback in an outgoing channel will be with a non-zero value
462 * and will mean the channel is connected to the destination.
463 *
464 * For an incoming channel it will be called immediately after the
465 * #GNUNET_CADET_ConnectEventHandler, also with a non-zero value.
466 *
467 * @param cls Channel closure.
468 * @param channel Connection to the other end (henceforth invalid).
469 * @param window_size New window size. If the is more messages than buffer size
470 * this value will be negative..
471 */
472static void
473window_change_cb (void *cls,
474 const struct GNUNET_CADET_Channel *channel,
475 int window_size)
476{
477 /* FIXME: could do flow control here... */
478}
479
480
481/**
556 * Initialize subsystem for non-anonymous file-sharing. 482 * Initialize subsystem for non-anonymous file-sharing.
557 */ 483 */
558void 484void
559GSF_cadet_start_server () 485GSF_cadet_start_server ()
560{ 486{
561 static const struct GNUNET_CADET_MessageHandler handlers[] = { 487 struct GNUNET_MQ_MessageHandler handlers[] = {
562 { &request_cb, GNUNET_MESSAGE_TYPE_FS_CADET_QUERY, sizeof (struct CadetQueryMessage)}, 488 GNUNET_MQ_hd_fixed_size (request,
563 { NULL, 0, 0 } 489 GNUNET_MESSAGE_TYPE_FS_CADET_QUERY,
490 struct CadetQueryMessage,
491 NULL),
492 GNUNET_MQ_handler_end ()
564 }; 493 };
565 struct GNUNET_HashCode port; 494 struct GNUNET_HashCode port;
566 495
@@ -573,18 +502,19 @@ GSF_cadet_start_server ()
573 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 502 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
574 "Initializing cadet FS server with a limit of %llu connections\n", 503 "Initializing cadet FS server with a limit of %llu connections\n",
575 sc_count_max); 504 sc_count_max);
576 listen_channel = GNUNET_CADET_connect (GSF_cfg, 505 cadet_map = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
577 NULL, 506 cadet_handle = GNUNET_CADET_connect (GSF_cfg);
578 &cleaner_cb, 507 GNUNET_assert (NULL != cadet_handle);
579 handlers);
580 GNUNET_assert (NULL != listen_channel);
581 GNUNET_CRYPTO_hash (GNUNET_APPLICATION_PORT_FS_BLOCK_TRANSFER, 508 GNUNET_CRYPTO_hash (GNUNET_APPLICATION_PORT_FS_BLOCK_TRANSFER,
582 strlen (GNUNET_APPLICATION_PORT_FS_BLOCK_TRANSFER), 509 strlen (GNUNET_APPLICATION_PORT_FS_BLOCK_TRANSFER),
583 &port); 510 &port);
584 GNUNET_CADET_open_port (listen_channel, 511 cadet_port = GNUNET_CADET_open_port (cadet_handle,
585 &port, 512 &port,
586 &accept_cb, 513 &connect_cb,
587 NULL); 514 NULL,
515 &window_change_cb,
516 &disconnect_cb,
517 handlers);
588} 518}
589 519
590 520
@@ -594,10 +524,20 @@ GSF_cadet_start_server ()
594void 524void
595GSF_cadet_stop_server () 525GSF_cadet_stop_server ()
596{ 526{
597 if (NULL != listen_channel) 527 GNUNET_CONTAINER_multipeermap_iterate (cadet_map,
528 &GSF_cadet_release_clients,
529 NULL);
530 GNUNET_CONTAINER_multipeermap_destroy (cadet_map);
531 cadet_map = NULL;
532 if (NULL != cadet_port)
533 {
534 GNUNET_CADET_close_port (cadet_port);
535 cadet_port = NULL;
536 }
537 if (NULL != cadet_handle)
598 { 538 {
599 GNUNET_CADET_disconnect (listen_channel); 539 GNUNET_CADET_disconnect (cadet_handle);
600 listen_channel = NULL; 540 cadet_handle = NULL;
601 } 541 }
602 GNUNET_assert (NULL == sc_head); 542 GNUNET_assert (NULL == sc_head);
603 GNUNET_assert (0 == sc_count); 543 GNUNET_assert (0 == sc_count);
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..b5e8af95f 100644
--- a/src/fs/gnunet-service-fs_indexing.c
+++ b/src/fs/gnunet-service-fs_indexing.c
@@ -266,6 +266,7 @@ remove_cont (void *cls, int success,
266 * @param type type of the content 266 * @param type type of the content
267 * @param priority priority of the content 267 * @param priority priority of the content
268 * @param anonymity anonymity-level for the content 268 * @param anonymity anonymity-level for the content
269 * @param replication replication-level for the content
269 * @param expiration expiration time for the content 270 * @param expiration expiration time for the content
270 * @param uid unique identifier for the datum; 271 * @param uid unique identifier for the datum;
271 * maybe 0 if no unique identifier is available 272 * maybe 0 if no unique identifier is available
@@ -280,6 +281,7 @@ GNUNET_FS_handle_on_demand_block (const struct GNUNET_HashCode * key,
280 enum GNUNET_BLOCK_Type type, 281 enum GNUNET_BLOCK_Type type,
281 uint32_t priority, 282 uint32_t priority,
282 uint32_t anonymity, 283 uint32_t anonymity,
284 uint32_t replication,
283 struct GNUNET_TIME_Absolute expiration, 285 struct GNUNET_TIME_Absolute expiration,
284 uint64_t uid, 286 uint64_t uid,
285 GNUNET_DATASTORE_DatumProcessor cont, 287 GNUNET_DATASTORE_DatumProcessor cont,
@@ -412,6 +414,7 @@ GNUNET_FS_handle_on_demand_block (const struct GNUNET_HashCode * key,
412 GNUNET_BLOCK_TYPE_FS_DBLOCK, 414 GNUNET_BLOCK_TYPE_FS_DBLOCK,
413 priority, 415 priority,
414 anonymity, 416 anonymity,
417 replication,
415 expiration, 418 expiration,
416 uid); 419 uid);
417 return GNUNET_OK; 420 return GNUNET_OK;
@@ -438,7 +441,7 @@ GNUNET_FS_indexing_send_list (struct GNUNET_MQ_Handle *mq)
438 fn = pos->filename; 441 fn = pos->filename;
439 slen = strlen (fn) + 1; 442 slen = strlen (fn) + 1;
440 if (slen + sizeof (struct IndexInfoMessage) >= 443 if (slen + sizeof (struct IndexInfoMessage) >=
441 GNUNET_SERVER_MAX_MESSAGE_SIZE) 444 GNUNET_MAX_MESSAGE_SIZE)
442 { 445 {
443 GNUNET_break (0); 446 GNUNET_break (0);
444 break; 447 break;
diff --git a/src/fs/gnunet-service-fs_indexing.h b/src/fs/gnunet-service-fs_indexing.h
index 8b861e3f7..331c51105 100644
--- a/src/fs/gnunet-service-fs_indexing.h
+++ b/src/fs/gnunet-service-fs_indexing.h
@@ -47,6 +47,7 @@
47 * @param type type of the content 47 * @param type type of the content
48 * @param priority priority of the content 48 * @param priority priority of the content
49 * @param anonymity anonymity-level for the content 49 * @param anonymity anonymity-level for the content
50 * @param replication replication-level for the content
50 * @param expiration expiration time for the content 51 * @param expiration expiration time for the content
51 * @param uid unique identifier for the datum; 52 * @param uid unique identifier for the datum;
52 * maybe 0 if no unique identifier is available 53 * maybe 0 if no unique identifier is available
@@ -55,9 +56,13 @@
55 * @return #GNUNET_OK on success 56 * @return #GNUNET_OK on success
56 */ 57 */
57int 58int
58GNUNET_FS_handle_on_demand_block (const struct GNUNET_HashCode * key, uint32_t size, 59GNUNET_FS_handle_on_demand_block (const struct GNUNET_HashCode *key,
59 const void *data, enum GNUNET_BLOCK_Type type, 60 uint32_t size,
60 uint32_t priority, uint32_t anonymity, 61 const void *data,
62 enum GNUNET_BLOCK_Type type,
63 uint32_t priority,
64 uint32_t anonymity,
65 uint32_t replication,
61 struct GNUNET_TIME_Absolute expiration, 66 struct GNUNET_TIME_Absolute expiration,
62 uint64_t uid, 67 uint64_t uid,
63 GNUNET_DATASTORE_DatumProcessor cont, 68 GNUNET_DATASTORE_DatumProcessor cont,
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 63462f7dc..7c64ab98b 100644
--- a/src/fs/gnunet-service-fs_pr.c
+++ b/src/fs/gnunet-service-fs_pr.c
@@ -97,9 +97,9 @@ struct GSF_PendingRequest
97 struct GNUNET_HashCode *replies_seen; 97 struct GNUNET_HashCode *replies_seen;
98 98
99 /** 99 /**
100 * Bloomfilter masking replies we've already seen. 100 * Block group for filtering replies we've already seen.
101 */ 101 */
102 struct GNUNET_CONTAINER_BloomFilter *bf; 102 struct GNUNET_BLOCK_Group *bg;
103 103
104 /** 104 /**
105 * Entry for this pending request in the expiration heap, or NULL. 105 * Entry for this pending request in the expiration heap, or NULL.
@@ -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,16 +196,6 @@ struct GSF_PendingRequest
189 */ 196 */
190 unsigned int replies_seen_size; 197 unsigned int replies_seen_size;
191 198
192 /**
193 * Mingle value we currently use for the bf.
194 */
195 uint32_t mingle;
196
197 /**
198 * Do we have a first UID yet?
199 */
200 unsigned int have_first_uid;
201
202}; 199};
203 200
204 201
@@ -248,18 +245,36 @@ static unsigned long long max_pending_requests = (32 * 1024);
248 * fresh one of minimal size without problems) OR if our peer is the 245 * fresh one of minimal size without problems) OR if our peer is the
249 * initiator (in which case we may resize to larger than mimimum size). 246 * initiator (in which case we may resize to larger than mimimum size).
250 * 247 *
248 * @param type type of the request
251 * @param pr request for which the BF is to be recomputed 249 * @param pr request for which the BF is to be recomputed
252 */ 250 */
253static void 251static void
254refresh_bloomfilter (struct GSF_PendingRequest *pr) 252refresh_bloomfilter (enum GNUNET_BLOCK_Type type,
253 struct GSF_PendingRequest *pr)
255{ 254{
256 if (pr->bf != NULL) 255 if (NULL != pr->bg)
257 GNUNET_CONTAINER_bloomfilter_free (pr->bf); 256 {
258 pr->mingle = 257 GNUNET_BLOCK_group_destroy (pr->bg);
259 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX); 258 pr->bg = NULL;
260 pr->bf = 259 }
261 GNUNET_BLOCK_construct_bloomfilter (pr->mingle, pr->replies_seen, 260 if (GNUNET_BLOCK_TYPE_FS_UBLOCK != type)
262 pr->replies_seen_count); 261 return; /* no need */
262 pr->bg
263 = GNUNET_BLOCK_group_create (GSF_block_ctx,
264 type,
265 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
266 UINT32_MAX),
267 NULL,
268 0,
269 "seen-set-size",
270 pr->replies_seen_count,
271 NULL);
272 if (NULL == pr->bg)
273 return;
274 GNUNET_break (GNUNET_OK ==
275 GNUNET_BLOCK_group_set_seen (pr->bg,
276 pr->replies_seen,
277 pr->replies_seen_count));
263} 278}
264 279
265 280
@@ -319,8 +334,6 @@ GSF_pending_request_create_ (enum GSF_PendingRequestOptions options,
319 if (NULL != target) 334 if (NULL != target)
320 extra += sizeof (struct GNUNET_PeerIdentity); 335 extra += sizeof (struct GNUNET_PeerIdentity);
321 pr = GNUNET_malloc (sizeof (struct GSF_PendingRequest) + extra); 336 pr = GNUNET_malloc (sizeof (struct GSF_PendingRequest) + extra);
322 pr->local_result_offset =
323 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
324 pr->public_data.query = *query; 337 pr->public_data.query = *query;
325 eptr = (struct GNUNET_HashCode *) &pr[1]; 338 eptr = (struct GNUNET_HashCode *) &pr[1];
326 if (NULL != target) 339 if (NULL != target)
@@ -355,25 +368,31 @@ GSF_pending_request_create_ (enum GSF_PendingRequestOptions options,
355 if (replies_seen_count > 0) 368 if (replies_seen_count > 0)
356 { 369 {
357 pr->replies_seen_size = replies_seen_count; 370 pr->replies_seen_size = replies_seen_count;
358 pr->replies_seen = 371 pr->replies_seen = GNUNET_new_array (pr->replies_seen_size,
359 GNUNET_malloc (sizeof (struct GNUNET_HashCode) * pr->replies_seen_size); 372 struct GNUNET_HashCode);
360 GNUNET_memcpy (pr->replies_seen, 373 GNUNET_memcpy (pr->replies_seen,
361 replies_seen, 374 replies_seen,
362 replies_seen_count * sizeof (struct GNUNET_HashCode)); 375 replies_seen_count * sizeof (struct GNUNET_HashCode));
363 pr->replies_seen_count = replies_seen_count; 376 pr->replies_seen_count = replies_seen_count;
364 } 377 }
365 if (NULL != bf_data) 378 if ( (NULL != bf_data) &&
379 (GNUNET_BLOCK_TYPE_FS_UBLOCK == pr->public_data.type) )
366 { 380 {
367 pr->bf = 381 pr->bg
368 GNUNET_CONTAINER_bloomfilter_init (bf_data, 382 = GNUNET_BLOCK_group_create (GSF_block_ctx,
369 bf_size, 383 pr->public_data.type,
370 GNUNET_CONSTANTS_BLOOMFILTER_K); 384 mingle,
371 pr->mingle = mingle; 385 bf_data,
386 bf_size,
387 "seen-set-size",
388 0,
389 NULL);
372 } 390 }
373 else if ((replies_seen_count > 0) && 391 else if ((replies_seen_count > 0) &&
374 (0 != (options & GSF_PRO_BLOOMFILTER_FULL_REFRESH))) 392 (0 != (options & GSF_PRO_BLOOMFILTER_FULL_REFRESH)))
375 { 393 {
376 refresh_bloomfilter (pr); 394 refresh_bloomfilter (pr->public_data.type,
395 pr);
377 } 396 }
378 GNUNET_CONTAINER_multihashmap_put (pr_map, 397 GNUNET_CONTAINER_multihashmap_put (pr_map,
379 &pr->public_data.query, 398 &pr->public_data.query,
@@ -461,46 +480,37 @@ GSF_pending_request_update_ (struct GSF_PendingRequest *pr,
461 const struct GNUNET_HashCode * replies_seen, 480 const struct GNUNET_HashCode * replies_seen,
462 unsigned int replies_seen_count) 481 unsigned int replies_seen_count)
463{ 482{
464 unsigned int i;
465 struct GNUNET_HashCode mhash;
466
467 if (replies_seen_count + pr->replies_seen_count < pr->replies_seen_count) 483 if (replies_seen_count + pr->replies_seen_count < pr->replies_seen_count)
468 return; /* integer overflow */ 484 return; /* integer overflow */
469 if (0 != (pr->public_data.options & GSF_PRO_BLOOMFILTER_FULL_REFRESH)) 485 if (0 != (pr->public_data.options & GSF_PRO_BLOOMFILTER_FULL_REFRESH))
470 { 486 {
471 /* we're responsible for the BF, full refresh */ 487 /* we're responsible for the BF, full refresh */
472 if (replies_seen_count + pr->replies_seen_count > pr->replies_seen_size) 488 if (replies_seen_count + pr->replies_seen_count > pr->replies_seen_size)
473 GNUNET_array_grow (pr->replies_seen, pr->replies_seen_size, 489 GNUNET_array_grow (pr->replies_seen,
490 pr->replies_seen_size,
474 replies_seen_count + pr->replies_seen_count); 491 replies_seen_count + pr->replies_seen_count);
475 GNUNET_memcpy (&pr->replies_seen[pr->replies_seen_count], replies_seen, 492 GNUNET_memcpy (&pr->replies_seen[pr->replies_seen_count],
476 sizeof (struct GNUNET_HashCode) * replies_seen_count); 493 replies_seen,
494 sizeof (struct GNUNET_HashCode) * replies_seen_count);
477 pr->replies_seen_count += replies_seen_count; 495 pr->replies_seen_count += replies_seen_count;
478 refresh_bloomfilter (pr); 496 refresh_bloomfilter (pr->public_data.type,
497 pr);
479 } 498 }
480 else 499 else
481 { 500 {
482 if (NULL == pr->bf) 501 if (NULL == pr->bg)
483 { 502 {
484 /* we're not the initiator, but the initiator did not give us 503 /* we're not the initiator, but the initiator did not give us
485 * any bloom-filter, so we need to create one on-the-fly */ 504 * any bloom-filter, so we need to create one on-the-fly */
486 pr->mingle = 505 refresh_bloomfilter (pr->public_data.type,
487 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 506 pr);
488 UINT32_MAX);
489 pr->bf =
490 GNUNET_BLOCK_construct_bloomfilter (pr->mingle,
491 replies_seen,
492 replies_seen_count);
493 } 507 }
494 else 508 else
495 { 509 {
496 for (i = 0; i < pr->replies_seen_count; i++) 510 GNUNET_break (GNUNET_OK ==
497 { 511 GNUNET_BLOCK_group_set_seen (pr->bg,
498 GNUNET_BLOCK_mingle_hash (&replies_seen[i], 512 replies_seen,
499 pr->mingle, 513 pr->replies_seen_count));
500 &mhash);
501 GNUNET_CONTAINER_bloomfilter_add (pr->bf,
502 &mhash);
503 }
504 } 514 }
505 } 515 }
506 if (NULL != pr->gh) 516 if (NULL != pr->gh)
@@ -530,6 +540,8 @@ GSF_pending_request_get_message_ (struct GSF_PendingRequest *pr)
530 struct GNUNET_TIME_Absolute now; 540 struct GNUNET_TIME_Absolute now;
531 int64_t ttl; 541 int64_t ttl;
532 int do_route; 542 int do_route;
543 void *bf_data;
544 uint32_t bf_nonce;
533 545
534 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 546 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
535 "Building request message for `%s' of type %d\n", 547 "Building request message for `%s' of type %d\n",
@@ -553,7 +565,15 @@ GSF_pending_request_get_message_ (struct GSF_PendingRequest *pr)
553 bm |= GET_MESSAGE_BIT_TRANSMIT_TO; 565 bm |= GET_MESSAGE_BIT_TRANSMIT_TO;
554 k++; 566 k++;
555 } 567 }
556 bf_size = GNUNET_CONTAINER_bloomfilter_get_size (pr->bf); 568 if (GNUNET_OK !=
569 GNUNET_BLOCK_group_serialize (pr->bg,
570 &bf_nonce,
571 &bf_data,
572 &bf_size))
573 {
574 bf_size = 0;
575 bf_data = NULL;
576 }
557 env = GNUNET_MQ_msg_extra (gm, 577 env = GNUNET_MQ_msg_extra (gm,
558 bf_size + k * sizeof (struct GNUNET_PeerIdentity), 578 bf_size + k * sizeof (struct GNUNET_PeerIdentity),
559 GNUNET_MESSAGE_TYPE_FS_GET); 579 GNUNET_MESSAGE_TYPE_FS_GET);
@@ -571,7 +591,7 @@ GSF_pending_request_get_message_ (struct GSF_PendingRequest *pr)
571 now = GNUNET_TIME_absolute_get (); 591 now = GNUNET_TIME_absolute_get ();
572 ttl = (int64_t) (pr->public_data.ttl.abs_value_us - now.abs_value_us); 592 ttl = (int64_t) (pr->public_data.ttl.abs_value_us - now.abs_value_us);
573 gm->ttl = htonl (ttl / 1000LL / 1000LL); 593 gm->ttl = htonl (ttl / 1000LL / 1000LL);
574 gm->filter_mutator = htonl (pr->mingle); 594 gm->filter_mutator = htonl (bf_nonce);
575 gm->hash_bitmap = htonl (bm); 595 gm->hash_bitmap = htonl (bm);
576 gm->query = pr->public_data.query; 596 gm->query = pr->public_data.query;
577 ext = (struct GNUNET_PeerIdentity *) &gm[1]; 597 ext = (struct GNUNET_PeerIdentity *) &gm[1];
@@ -581,11 +601,10 @@ GSF_pending_request_get_message_ (struct GSF_PendingRequest *pr)
581 &ext[k++]); 601 &ext[k++]);
582 if (NULL != pr->public_data.target) 602 if (NULL != pr->public_data.target)
583 ext[k++] = *pr->public_data.target; 603 ext[k++] = *pr->public_data.target;
584 if (NULL != pr->bf) 604 GNUNET_memcpy (&ext[k],
585 GNUNET_assert (GNUNET_SYSERR != 605 bf_data,
586 GNUNET_CONTAINER_bloomfilter_get_raw_data (pr->bf, 606 bf_size);
587 (char *) &ext[k], 607 GNUNET_free_non_null (bf_data);
588 bf_size));
589 return env; 608 return env;
590} 609}
591 610
@@ -624,11 +643,8 @@ clean_request (void *cls,
624 } 643 }
625 GSF_plan_notify_request_done_ (pr); 644 GSF_plan_notify_request_done_ (pr);
626 GNUNET_free_non_null (pr->replies_seen); 645 GNUNET_free_non_null (pr->replies_seen);
627 if (NULL != pr->bf) 646 GNUNET_BLOCK_group_destroy (pr->bg);
628 { 647 pr->bg = NULL;
629 GNUNET_CONTAINER_bloomfilter_free (pr->bf);
630 pr->bf = NULL;
631 }
632 GNUNET_PEER_change_rc (pr->sender_pid, -1); 648 GNUNET_PEER_change_rc (pr->sender_pid, -1);
633 pr->sender_pid = 0; 649 pr->sender_pid = 0;
634 GNUNET_PEER_change_rc (pr->origin_pid, -1); 650 GNUNET_PEER_change_rc (pr->origin_pid, -1);
@@ -844,10 +860,9 @@ process_reply (void *cls,
844 prq->eval = 860 prq->eval =
845 GNUNET_BLOCK_evaluate (GSF_block_ctx, 861 GNUNET_BLOCK_evaluate (GSF_block_ctx,
846 prq->type, 862 prq->type,
863 pr->bg,
847 prq->eo, 864 prq->eo,
848 key, 865 key,
849 &pr->bf,
850 pr->mingle,
851 NULL, 866 NULL,
852 0, 867 0,
853 prq->data, 868 prq->data,
@@ -1325,6 +1340,124 @@ odc_warn_delay_task (void *cls)
1325} 1340}
1326 1341
1327 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 uint32_t replication,
1413 struct GNUNET_TIME_Absolute expiration,
1414 uint64_t uid);
1415
1416
1417/* Start a local query */
1418static void
1419start_local_query (struct GSF_PendingRequest *pr,
1420 uint64_t next_uid,
1421 bool random)
1422{
1423 pr->qe_start = GNUNET_TIME_absolute_get ();
1424 pr->warn_task =
1425 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
1426 &warn_delay_task,
1427 pr);
1428 pr->qe =
1429 GNUNET_DATASTORE_get_key (GSF_dsh,
1430 next_uid,
1431 random,
1432 &pr->public_data.query,
1433 pr->public_data.type ==
1434 GNUNET_BLOCK_TYPE_FS_DBLOCK ?
1435 GNUNET_BLOCK_TYPE_ANY : pr->public_data.type,
1436 (0 !=
1437 (GSF_PRO_PRIORITY_UNLIMITED & pr->
1438 public_data.options)) ? UINT_MAX : 1
1439 /* queue priority */ ,
1440 (0 !=
1441 (GSF_PRO_PRIORITY_UNLIMITED & pr->
1442 public_data.options)) ? UINT_MAX :
1443 GSF_datastore_queue_size
1444 /* max queue size */ ,
1445 &process_local_reply, pr);
1446 if (NULL != pr->qe)
1447 return;
1448 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1449 "ERROR Requesting `%s' of type %d with next_uid %llu from datastore.\n",
1450 GNUNET_h2s (&pr->public_data.query),
1451 pr->public_data.type,
1452 (unsigned long long) next_uid);
1453 GNUNET_STATISTICS_update (GSF_stats,
1454 gettext_noop ("# Datastore lookups concluded (error queueing)"),
1455 1,
1456 GNUNET_NO);
1457 call_continuation (pr);
1458}
1459
1460
1328/** 1461/**
1329 * We're processing (local) results for a search request 1462 * We're processing (local) results for a search request
1330 * from another peer. Pass applicable results to the 1463 * from another peer. Pass applicable results to the
@@ -1338,6 +1471,7 @@ odc_warn_delay_task (void *cls)
1338 * @param type type of the content 1471 * @param type type of the content
1339 * @param priority priority of the content 1472 * @param priority priority of the content
1340 * @param anonymity anonymity-level for the content 1473 * @param anonymity anonymity-level for the content
1474 * @param replication replication-level for the content
1341 * @param expiration expiration time for the content 1475 * @param expiration expiration time for the content
1342 * @param uid unique identifier for the datum; 1476 * @param uid unique identifier for the datum;
1343 * maybe 0 if no unique identifier is available 1477 * maybe 0 if no unique identifier is available
@@ -1350,73 +1484,76 @@ process_local_reply (void *cls,
1350 enum GNUNET_BLOCK_Type type, 1484 enum GNUNET_BLOCK_Type type,
1351 uint32_t priority, 1485 uint32_t priority,
1352 uint32_t anonymity, 1486 uint32_t anonymity,
1487 uint32_t replication,
1353 struct GNUNET_TIME_Absolute expiration, 1488 struct GNUNET_TIME_Absolute expiration,
1354 uint64_t uid) 1489 uint64_t uid)
1355{ 1490{
1356 struct GSF_PendingRequest *pr = cls; 1491 struct GSF_PendingRequest *pr = cls;
1357 GSF_LocalLookupContinuation cont;
1358 struct ProcessReplyClosure prq; 1492 struct ProcessReplyClosure prq;
1359 struct GNUNET_HashCode query; 1493 struct GNUNET_HashCode query;
1360 unsigned int old_rf; 1494 unsigned int old_rf;
1361 1495
1362 GNUNET_SCHEDULER_cancel (pr->warn_task); 1496 GNUNET_SCHEDULER_cancel (pr->warn_task);
1363 pr->warn_task = NULL; 1497 pr->warn_task = NULL;
1364 if (NULL != pr->qe) 1498 if (NULL == pr->qe)
1499 goto called_from_on_demand;
1500 pr->qe = NULL;
1501 if ( (NULL == key) &&
1502 pr->seen_null &&
1503 !pr->have_first_uid) /* We have hit the end for the 2nd time with no results */
1365 { 1504 {
1366 pr->qe = NULL; 1505 /* No results */
1367 if (NULL == key)
1368 {
1369#if INSANE_STATISTICS 1506#if INSANE_STATISTICS
1370 GNUNET_STATISTICS_update (GSF_stats, 1507 GNUNET_STATISTICS_update (GSF_stats,
1371 gettext_noop 1508 gettext_noop
1372 ("# Datastore lookups concluded (no results)"), 1509 ("# Datastore lookups concluded (no results)"),
1373 1, GNUNET_NO); 1510 1, GNUNET_NO);
1374#endif 1511#endif
1375 } 1512 no_more_local_results (pr);
1376 if (GNUNET_NO == pr->have_first_uid) 1513 return;
1377 { 1514 }
1378 pr->first_uid = uid; 1515 if ( ( (NULL == key) &&
1379 pr->have_first_uid = 1; 1516 pr->seen_null ) || /* We have hit the end for the 2nd time OR */
1380 } 1517 ( pr->seen_null &&
1381 else 1518 pr->have_first_uid &&
1382 { 1519 (uid >= pr->first_uid) ) ) /* We have hit the end and past first UID */
1383 if ((uid == pr->first_uid) && (key != NULL)) 1520 {
1384 { 1521 /* Seen all results */
1385 GNUNET_STATISTICS_update (GSF_stats, 1522 GNUNET_STATISTICS_update (GSF_stats,
1386 gettext_noop 1523 gettext_noop
1387 ("# Datastore lookups concluded (seen all)"), 1524 ("# Datastore lookups concluded (seen all)"),
1388 1, GNUNET_NO); 1525 1, GNUNET_NO);
1389 key = NULL; /* all replies seen! */ 1526 no_more_local_results (pr);
1390 } 1527 return;
1391 pr->have_first_uid++;
1392 if ((pr->have_first_uid > MAX_RESULTS) && (key != NULL))
1393 {
1394 GNUNET_STATISTICS_update (GSF_stats,
1395 gettext_noop
1396 ("# Datastore lookups aborted (more than MAX_RESULTS)"),
1397 1, GNUNET_NO);
1398 key = NULL; /* all replies seen! */
1399 }
1400 }
1401 } 1528 }
1402 if (NULL == key) 1529 if (NULL == key)
1403 { 1530 {
1404 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, 1531 GNUNET_assert (!pr->seen_null);
1405 "No further local responses available.\n"); 1532 pr->seen_null = true;
1406#if INSANE_STATISTICS 1533 start_local_query (pr,
1407 if ((pr->public_data.type == GNUNET_BLOCK_TYPE_FS_DBLOCK) || 1534 0 /* next_uid */,
1408 (pr->public_data.type == GNUNET_BLOCK_TYPE_FS_IBLOCK)) 1535 false /* random */);
1409 GNUNET_STATISTICS_update (GSF_stats, 1536 return;
1410 gettext_noop 1537 }
1411 ("# requested DBLOCK or IBLOCK not found"), 1, 1538 if (!pr->have_first_uid)
1412 GNUNET_NO); 1539 {
1413#endif 1540 pr->first_uid = uid;
1414 goto check_error_and_continue; 1541 pr->have_first_uid = true;
1542 }
1543 pr->result_count++;
1544 if (pr->result_count > MAX_RESULTS)
1545 {
1546 GNUNET_STATISTICS_update (GSF_stats,
1547 gettext_noop
1548 ("# Datastore lookups aborted (more than MAX_RESULTS)"),
1549 1, GNUNET_NO);
1550 no_more_local_results (pr);
1551 return;
1415 } 1552 }
1416 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1553 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1417 "Received reply for `%s' of type %d with UID %llu from datastore.\n", 1554 "Received reply for `%s' of type %d with UID %llu from datastore.\n",
1418 GNUNET_h2s (key), type, (unsigned long long) uid); 1555 GNUNET_h2s (key), type, (unsigned long long) uid);
1419 if (type == GNUNET_BLOCK_TYPE_FS_ONDEMAND) 1556 if (GNUNET_BLOCK_TYPE_FS_ONDEMAND == type)
1420 { 1557 {
1421 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1558 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1422 "Found ONDEMAND block, performing on-demand encoding\n"); 1559 "Found ONDEMAND block, performing on-demand encoding\n");
@@ -1429,9 +1566,17 @@ process_local_reply (void *cls,
1429 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, 1566 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
1430 &odc_warn_delay_task, pr); 1567 &odc_warn_delay_task, pr);
1431 if (GNUNET_OK == 1568 if (GNUNET_OK ==
1432 GNUNET_FS_handle_on_demand_block (key, size, data, type, priority, 1569 GNUNET_FS_handle_on_demand_block (key,
1433 anonymity, expiration, uid, 1570 size,
1434 &process_local_reply, pr)) 1571 data,
1572 type,
1573 priority,
1574 anonymity,
1575 replication,
1576 expiration,
1577 uid,
1578 &process_local_reply,
1579 pr))
1435 { 1580 {
1436 GNUNET_STATISTICS_update (GSF_stats, 1581 GNUNET_STATISTICS_update (GSF_stats,
1437 gettext_noop 1582 gettext_noop
@@ -1443,33 +1588,12 @@ process_local_reply (void *cls,
1443 gettext_noop ("# on-demand lookups failed"), 1, 1588 gettext_noop ("# on-demand lookups failed"), 1,
1444 GNUNET_NO); 1589 GNUNET_NO);
1445 GNUNET_SCHEDULER_cancel (pr->warn_task); 1590 GNUNET_SCHEDULER_cancel (pr->warn_task);
1446 pr->warn_task = 1591 start_local_query (pr,
1447 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, 1592 uid + 1 /* next_uid */,
1448 &warn_delay_task, pr); 1593 false /* random */);
1449 pr->qe = 1594 return;
1450 GNUNET_DATASTORE_get_key (GSF_dsh, pr->local_result_offset - 1,
1451 &pr->public_data.query,
1452 pr->public_data.type ==
1453 GNUNET_BLOCK_TYPE_FS_DBLOCK ?
1454 GNUNET_BLOCK_TYPE_ANY : pr->public_data.type,
1455 (0 !=
1456 (GSF_PRO_PRIORITY_UNLIMITED &
1457 pr->public_data.options)) ? UINT_MAX : 1
1458 /* queue priority */ ,
1459 (0 !=
1460 (GSF_PRO_PRIORITY_UNLIMITED &
1461 pr->public_data.options)) ? UINT_MAX :
1462 GSF_datastore_queue_size
1463 /* max queue size */ ,
1464 &process_local_reply, pr);
1465 if (NULL != pr->qe)
1466 return; /* we're done */
1467 GNUNET_STATISTICS_update (GSF_stats,
1468 gettext_noop
1469 ("# Datastore lookups concluded (error queueing)"),
1470 1, GNUNET_NO);
1471 goto check_error_and_continue;
1472 } 1595 }
1596called_from_on_demand:
1473 old_rf = pr->public_data.results_found; 1597 old_rf = pr->public_data.results_found;
1474 memset (&prq, 0, sizeof (prq)); 1598 memset (&prq, 0, sizeof (prq));
1475 prq.data = data; 1599 prq.data = data;
@@ -1481,34 +1605,9 @@ process_local_reply (void *cls,
1481 GNUNET_break (0); 1605 GNUNET_break (0);
1482 GNUNET_DATASTORE_remove (GSF_dsh, key, size, data, -1, -1, 1606 GNUNET_DATASTORE_remove (GSF_dsh, key, size, data, -1, -1,
1483 NULL, NULL); 1607 NULL, NULL);
1484 pr->qe_start = GNUNET_TIME_absolute_get (); 1608 start_local_query (pr,
1485 pr->warn_task = 1609 uid + 1 /* next_uid */,
1486 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, 1610 false /* random */);
1487 &warn_delay_task, pr);
1488 pr->qe =
1489 GNUNET_DATASTORE_get_key (GSF_dsh, pr->local_result_offset - 1,
1490 &pr->public_data.query,
1491 pr->public_data.type ==
1492 GNUNET_BLOCK_TYPE_FS_DBLOCK ?
1493 GNUNET_BLOCK_TYPE_ANY : pr->public_data.type,
1494 (0 !=
1495 (GSF_PRO_PRIORITY_UNLIMITED &
1496 pr->public_data.options)) ? UINT_MAX : 1
1497 /* queue priority */ ,
1498 (0 !=
1499 (GSF_PRO_PRIORITY_UNLIMITED &
1500 pr->public_data.options)) ? UINT_MAX :
1501 GSF_datastore_queue_size
1502 /* max queue size */ ,
1503 &process_local_reply, pr);
1504 if (NULL == pr->qe)
1505 {
1506 GNUNET_STATISTICS_update (GSF_stats,
1507 gettext_noop
1508 ("# Datastore lookups concluded (error queueing)"),
1509 1, GNUNET_NO);
1510 goto check_error_and_continue;
1511 }
1512 return; 1611 return;
1513 } 1612 }
1514 prq.type = type; 1613 prq.type = type;
@@ -1520,14 +1619,15 @@ process_local_reply (void *cls,
1520 prq.eo = GNUNET_BLOCK_EO_LOCAL_SKIP_CRYPTO; 1619 prq.eo = GNUNET_BLOCK_EO_LOCAL_SKIP_CRYPTO;
1521 process_reply (&prq, key, pr); 1620 process_reply (&prq, key, pr);
1522 pr->local_result = prq.eval; 1621 pr->local_result = prq.eval;
1523 if (prq.eval == GNUNET_BLOCK_EVALUATION_OK_LAST) 1622 if (GNUNET_BLOCK_EVALUATION_OK_LAST == prq.eval)
1524 { 1623 {
1525 GNUNET_STATISTICS_update (GSF_stats, 1624 GNUNET_STATISTICS_update (GSF_stats,
1526 gettext_noop 1625 gettext_noop
1527 ("# Datastore lookups concluded (found last result)"), 1626 ("# Datastore lookups concluded (found last result)"),
1528 1, 1627 1,
1529 GNUNET_NO); 1628 GNUNET_NO);
1530 goto check_error_and_continue; 1629 call_continuation (pr);
1630 return;
1531 } 1631 }
1532 if ((0 == (GSF_PRO_PRIORITY_UNLIMITED & pr->public_data.options)) && 1632 if ((0 == (GSF_PRO_PRIORITY_UNLIMITED & pr->public_data.options)) &&
1533 ((GNUNET_YES == GSF_test_get_load_too_high_ (0)) || 1633 ((GNUNET_YES == GSF_test_get_load_too_high_ (0)) ||
@@ -1539,66 +1639,12 @@ process_local_reply (void *cls,
1539 gettext_noop ("# Datastore lookups concluded (load too high)"), 1639 gettext_noop ("# Datastore lookups concluded (load too high)"),
1540 1, 1640 1,
1541 GNUNET_NO); 1641 GNUNET_NO);
1542 goto check_error_and_continue; 1642 call_continuation (pr);
1543 }
1544 pr->qe_start = GNUNET_TIME_absolute_get ();
1545 pr->warn_task =
1546 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
1547 &warn_delay_task,
1548 pr);
1549 pr->qe =
1550 GNUNET_DATASTORE_get_key (GSF_dsh, pr->local_result_offset++,
1551 &pr->public_data.query,
1552 pr->public_data.type ==
1553 GNUNET_BLOCK_TYPE_FS_DBLOCK ?
1554 GNUNET_BLOCK_TYPE_ANY : pr->public_data.type,
1555 (0 !=
1556 (GSF_PRO_PRIORITY_UNLIMITED & pr->
1557 public_data.options)) ? UINT_MAX : 1
1558 /* queue priority */ ,
1559 (0 !=
1560 (GSF_PRO_PRIORITY_UNLIMITED & pr->
1561 public_data.options)) ? UINT_MAX :
1562 GSF_datastore_queue_size
1563 /* max queue size */ ,
1564 &process_local_reply, pr);
1565 /* check if we successfully queued another datastore request;
1566 * if so, return, otherwise call our continuation (if we have
1567 * any) */
1568check_error_and_continue:
1569 if (NULL != pr->qe)
1570 return;
1571 if (NULL != pr->warn_task)
1572 {
1573 GNUNET_SCHEDULER_cancel (pr->warn_task);
1574 pr->warn_task = NULL;
1575 }
1576 if (NULL == (cont = pr->llc_cont))
1577 return; /* no continuation */
1578 pr->llc_cont = NULL;
1579 if (0 != (GSF_PRO_LOCAL_ONLY & pr->public_data.options))
1580 {
1581 if (GNUNET_BLOCK_EVALUATION_OK_LAST != pr->local_result)
1582 {
1583 /* Signal that we are done and that there won't be any
1584 additional results to allow client to clean up state. */
1585 pr->rh (pr->rh_cls,
1586 GNUNET_BLOCK_EVALUATION_OK_LAST,
1587 pr,
1588 UINT32_MAX,
1589 GNUNET_TIME_UNIT_ZERO_ABS,
1590 GNUNET_TIME_UNIT_FOREVER_ABS,
1591 GNUNET_BLOCK_TYPE_ANY,
1592 NULL, 0);
1593 }
1594 /* Finally, call our continuation to signal that we are
1595 done with local processing of this request; i.e. to
1596 start reading again from the client. */
1597 cont (pr->llc_cont_cls, NULL, GNUNET_BLOCK_EVALUATION_OK_LAST);
1598 return; 1643 return;
1599 } 1644 }
1600 1645 start_local_query (pr,
1601 cont (pr->llc_cont_cls, pr, pr->local_result); 1646 uid + 1 /* next_uid */,
1647 false /* random */);
1602} 1648}
1603 1649
1604 1650
@@ -1642,43 +1688,14 @@ GSF_local_lookup_ (struct GSF_PendingRequest *pr,
1642 GNUNET_assert (NULL == pr->llc_cont); 1688 GNUNET_assert (NULL == pr->llc_cont);
1643 pr->llc_cont = cont; 1689 pr->llc_cont = cont;
1644 pr->llc_cont_cls = cont_cls; 1690 pr->llc_cont_cls = cont_cls;
1645 pr->qe_start = GNUNET_TIME_absolute_get ();
1646 pr->warn_task =
1647 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
1648 &warn_delay_task,
1649 pr);
1650#if INSANE_STATISTICS 1691#if INSANE_STATISTICS
1651 GNUNET_STATISTICS_update (GSF_stats, 1692 GNUNET_STATISTICS_update (GSF_stats,
1652 gettext_noop ("# Datastore lookups initiated"), 1, 1693 gettext_noop ("# Datastore lookups initiated"), 1,
1653 GNUNET_NO); 1694 GNUNET_NO);
1654#endif 1695#endif
1655 pr->qe = 1696 start_local_query(pr,
1656 GNUNET_DATASTORE_get_key (GSF_dsh, pr->local_result_offset++, 1697 0 /* next_uid */,
1657 &pr->public_data.query, 1698 true /* random */);
1658 pr->public_data.type ==
1659 GNUNET_BLOCK_TYPE_FS_DBLOCK ?
1660 GNUNET_BLOCK_TYPE_ANY : pr->public_data.type,
1661 (0 !=
1662 (GSF_PRO_PRIORITY_UNLIMITED & pr->
1663 public_data.options)) ? UINT_MAX : 1
1664 /* queue priority */ ,
1665 (0 !=
1666 (GSF_PRO_PRIORITY_UNLIMITED & pr->
1667 public_data.options)) ? UINT_MAX :
1668 GSF_datastore_queue_size
1669 /* max queue size */ ,
1670 &process_local_reply, pr);
1671 if (NULL != pr->qe)
1672 return;
1673 GNUNET_STATISTICS_update (GSF_stats,
1674 gettext_noop
1675 ("# Datastore lookups concluded (error queueing)"),
1676 1, GNUNET_NO);
1677 GNUNET_SCHEDULER_cancel (pr->warn_task);
1678 pr->warn_task = NULL;
1679 pr->llc_cont = NULL;
1680 if (NULL != cont)
1681 cont (cont_cls, pr, pr->local_result);
1682} 1699}
1683 1700
1684 1701
diff --git a/src/fs/gnunet-service-fs_push.c b/src/fs/gnunet-service-fs_push.c
index 361d30755..21c598a72 100644
--- a/src/fs/gnunet-service-fs_push.c
+++ b/src/fs/gnunet-service-fs_push.c
@@ -448,6 +448,7 @@ consider_gathering ()
448 * @param type type of the content 448 * @param type type of the content
449 * @param priority priority of the content 449 * @param priority priority of the content
450 * @param anonymity anonymity-level for the content 450 * @param anonymity anonymity-level for the content
451 * @param replication replication-level for the content
451 * @param expiration expiration time for the content 452 * @param expiration expiration time for the content
452 * @param uid unique identifier for the datum; 453 * @param uid unique identifier for the datum;
453 * maybe 0 if no unique identifier is available 454 * maybe 0 if no unique identifier is available
@@ -460,6 +461,7 @@ process_migration_content (void *cls,
460 enum GNUNET_BLOCK_Type type, 461 enum GNUNET_BLOCK_Type type,
461 uint32_t priority, 462 uint32_t priority,
462 uint32_t anonymity, 463 uint32_t anonymity,
464 uint32_t replication,
463 struct GNUNET_TIME_Absolute expiration, 465 struct GNUNET_TIME_Absolute expiration,
464 uint64_t uid) 466 uint64_t uid)
465{ 467{
@@ -491,9 +493,11 @@ process_migration_content (void *cls,
491 type, 493 type,
492 priority, 494 priority,
493 anonymity, 495 anonymity,
496 replication,
494 expiration, 497 expiration,
495 uid, 498 uid,
496 &process_migration_content, NULL)) 499 &process_migration_content,
500 NULL))
497 consider_gathering (); 501 consider_gathering ();
498 return; 502 return;
499 } 503 }
diff --git a/src/fs/gnunet-service-fs_put.c b/src/fs/gnunet-service-fs_put.c
index bb4cb4ecb..e8c7f586d 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
@@ -171,43 +176,51 @@ delay_dht_put_task (void *cls)
171 * @param type type of the content 176 * @param type type of the content
172 * @param priority priority of the content 177 * @param priority priority of the content
173 * @param anonymity anonymity-level for the content 178 * @param anonymity anonymity-level for the content
179 * @param replication replication-level for the content
174 * @param expiration expiration time for the content 180 * @param expiration expiration time for the content
175 * @param uid unique identifier for the datum; 181 * @param uid unique identifier for the datum;
176 * maybe 0 if no unique identifier is available 182 * maybe 0 if no unique identifier is available
177 */ 183 */
178static void 184static void
179process_dht_put_content (void *cls, 185process_dht_put_content (void *cls,
180 const struct GNUNET_HashCode * key, 186 const struct GNUNET_HashCode * key,
181 size_t size, 187 size_t size,
182 const void *data, 188 const void *data,
183 enum GNUNET_BLOCK_Type type, 189 enum GNUNET_BLOCK_Type type,
184 uint32_t priority, uint32_t anonymity, 190 uint32_t priority,
185 struct GNUNET_TIME_Absolute expiration, uint64_t uid) 191 uint32_t anonymity,
192 uint32_t replication,
193 struct GNUNET_TIME_Absolute expiration,
194 uint64_t uid)
186{ 195{
187 struct PutOperator *po = cls; 196 struct PutOperator *po = cls;
188 197
189 po->dht_qe = NULL; 198 po->dht_qe = NULL;
190 if (key == NULL) 199 if (key == NULL)
191 { 200 {
192 po->zero_anonymity_count_estimate = po->current_offset - 1; 201 po->zero_anonymity_count_estimate = po->result_count;
193 po->current_offset = 0; 202 po->result_count = 0;
203 po->next_uid = 0;
194 po->dht_task = GNUNET_SCHEDULER_add_now (&delay_dht_put_task, po); 204 po->dht_task = GNUNET_SCHEDULER_add_now (&delay_dht_put_task, po);
195 return; 205 return;
196 } 206 }
207 po->result_count++;
208 po->next_uid = uid + 1;
197 po->zero_anonymity_count_estimate = 209 po->zero_anonymity_count_estimate =
198 GNUNET_MAX (po->current_offset, po->zero_anonymity_count_estimate); 210 GNUNET_MAX (po->result_count, po->zero_anonymity_count_estimate);
199 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 211 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
200 "Retrieved block `%s' of type %u for DHT PUT\n", GNUNET_h2s (key), 212 "Retrieved block `%s' of type %u for DHT PUT\n", GNUNET_h2s (key),
201 type); 213 type);
202 po->dht_put = GNUNET_DHT_put (GSF_dht, 214 po->dht_put = GNUNET_DHT_put (GSF_dht,
203 key, 215 key,
204 DEFAULT_PUT_REPLICATION, 216 DEFAULT_PUT_REPLICATION,
205 GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, 217 GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
206 type, 218 type,
207 size, 219 size,
208 data, 220 data,
209 expiration, 221 expiration,
210 &delay_dht_put_blocks, po); 222 &delay_dht_put_blocks,
223 po);
211} 224}
212 225
213 226
@@ -223,10 +236,13 @@ gather_dht_put_blocks (void *cls)
223 236
224 po->dht_task = NULL; 237 po->dht_task = NULL;
225 po->dht_qe = 238 po->dht_qe =
226 GNUNET_DATASTORE_get_zero_anonymity (GSF_dsh, po->current_offset++, 0, 239 GNUNET_DATASTORE_get_zero_anonymity (GSF_dsh,
240 po->next_uid,
241 0,
227 UINT_MAX, 242 UINT_MAX,
228 po->dht_put_type, 243 po->dht_put_type,
229 &process_dht_put_content, po); 244 &process_dht_put_content,
245 po);
230 if (NULL == po->dht_qe) 246 if (NULL == po->dht_qe)
231 po->dht_task = GNUNET_SCHEDULER_add_now (&delay_dht_put_task, po); 247 po->dht_task = GNUNET_SCHEDULER_add_now (&delay_dht_put_task, po);
232} 248}
diff --git a/src/fs/gnunet-unindex.c b/src/fs/gnunet-unindex.c
index 40fa13b62..213d2b332 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/fs/plugin_block_fs.c b/src/fs/plugin_block_fs.c
index 415a2e3ed..902519f15 100644
--- a/src/fs/plugin_block_fs.c
+++ b/src/fs/plugin_block_fs.c
@@ -23,12 +23,12 @@
23 * @brief blocks used for file-sharing 23 * @brief blocks used for file-sharing
24 * @author Christian Grothoff 24 * @author Christian Grothoff
25 */ 25 */
26
27#include "platform.h" 26#include "platform.h"
28#include "gnunet_block_plugin.h" 27#include "gnunet_block_plugin.h"
29#include "gnunet_fs_service.h" 28#include "gnunet_fs_service.h"
30#include "block_fs.h" 29#include "block_fs.h"
31#include "gnunet_signatures.h" 30#include "gnunet_signatures.h"
31#include "gnunet_block_group_lib.h"
32 32
33 33
34/** 34/**
@@ -37,6 +37,70 @@
37 */ 37 */
38#define BLOOMFILTER_K 16 38#define BLOOMFILTER_K 16
39 39
40
41/**
42 * Create a new block group.
43 *
44 * @param ctx block context in which the block group is created
45 * @param type type of the block for which we are creating the group
46 * @param nonce random value used to seed the group creation
47 * @param raw_data optional serialized prior state of the group, NULL if unavailable/fresh
48 * @param raw_data_size number of bytes in @a raw_data, 0 if unavailable/fresh
49 * @param va variable arguments specific to @a type
50 * @return block group handle, NULL if block groups are not supported
51 * by this @a type of block (this is not an error)
52 */
53static struct GNUNET_BLOCK_Group *
54block_plugin_fs_create_group (void *cls,
55 enum GNUNET_BLOCK_Type type,
56 uint32_t nonce,
57 const void *raw_data,
58 size_t raw_data_size,
59 va_list va)
60{
61 unsigned int size;
62 const char *guard;
63
64 switch (type)
65 {
66 case GNUNET_BLOCK_TYPE_FS_DBLOCK:
67 GNUNET_break (NULL == va_arg (va, const char *));
68 return NULL;
69 case GNUNET_BLOCK_TYPE_FS_IBLOCK:
70 GNUNET_break (NULL == va_arg (va, const char *));
71 return NULL;
72 case GNUNET_BLOCK_TYPE_FS_UBLOCK:
73 guard = va_arg (va, const char *);
74 if (0 != strcmp (guard,
75 "seen-set-size"))
76 {
77 /* va-args invalid! bad bug, complain! */
78 GNUNET_break (0);
79 size = 8;
80 }
81 else
82 {
83 size = GNUNET_BLOCK_GROUP_compute_bloomfilter_size (va_arg (va, unsigned int),
84 BLOOMFILTER_K);
85 }
86 if (0 == size)
87 size = raw_data_size; /* not for us to determine, use what we got! */
88 GNUNET_break (NULL == va_arg (va, const char *));
89 return GNUNET_BLOCK_GROUP_bf_create (cls,
90 size,
91 BLOOMFILTER_K,
92 type,
93 nonce,
94 raw_data,
95 raw_data_size);
96 default:
97 GNUNET_break (NULL == va_arg (va, const char *));
98 GNUNET_break (0);
99 return NULL;
100 }
101}
102
103
40/** 104/**
41 * Function called to validate a reply or a request. For 105 * Function called to validate a reply or a request. For
42 * request evaluation, simply pass "NULL" for the reply_block. 106 * request evaluation, simply pass "NULL" for the reply_block.
@@ -45,11 +109,11 @@
45 * be done with the #GNUNET_BLOCK_get_key() function. 109 * be done with the #GNUNET_BLOCK_get_key() function.
46 * 110 *
47 * @param cls closure 111 * @param cls closure
112 * @param ctx block context
48 * @param type block type 113 * @param type block type
114 * @param bg group to use for evaluation
49 * @param eo control flags 115 * @param eo control flags
50 * @param query original query (hash) 116 * @param query original query (hash)
51 * @param bf pointer to bloom filter associated with query; possibly updated (!)
52 * @param bf_mutator mutation value for @a bf
53 * @param xquery extrended query data (can be NULL, depending on type) 117 * @param xquery extrended query data (can be NULL, depending on type)
54 * @param xquery_size number of bytes in @a xquery 118 * @param xquery_size number of bytes in @a xquery
55 * @param reply_block response to validate 119 * @param reply_block response to validate
@@ -58,11 +122,11 @@
58 */ 122 */
59static enum GNUNET_BLOCK_EvaluationResult 123static enum GNUNET_BLOCK_EvaluationResult
60block_plugin_fs_evaluate (void *cls, 124block_plugin_fs_evaluate (void *cls,
125 struct GNUNET_BLOCK_Context *ctx,
61 enum GNUNET_BLOCK_Type type, 126 enum GNUNET_BLOCK_Type type,
127 struct GNUNET_BLOCK_Group *bg,
62 enum GNUNET_BLOCK_EvaluationOptions eo, 128 enum GNUNET_BLOCK_EvaluationOptions eo,
63 const struct GNUNET_HashCode *query, 129 const struct GNUNET_HashCode *query,
64 struct GNUNET_CONTAINER_BloomFilter **bf,
65 int32_t bf_mutator,
66 const void *xquery, 130 const void *xquery,
67 size_t xquery_size, 131 size_t xquery_size,
68 const void *reply_block, 132 const void *reply_block,
@@ -71,7 +135,6 @@ block_plugin_fs_evaluate (void *cls,
71 const struct UBlock *ub; 135 const struct UBlock *ub;
72 struct GNUNET_HashCode hc; 136 struct GNUNET_HashCode hc;
73 struct GNUNET_HashCode chash; 137 struct GNUNET_HashCode chash;
74 struct GNUNET_HashCode mhash;
75 138
76 switch (type) 139 switch (type)
77 { 140 {
@@ -125,26 +188,13 @@ block_plugin_fs_evaluate (void *cls,
125 GNUNET_break_op (0); 188 GNUNET_break_op (0);
126 return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; 189 return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
127 } 190 }
128 if (NULL != bf) 191 GNUNET_CRYPTO_hash (reply_block,
129 { 192 reply_block_size,
130 GNUNET_CRYPTO_hash (reply_block, 193 &chash);
131 reply_block_size, 194 if (GNUNET_YES ==
132 &chash); 195 GNUNET_BLOCK_GROUP_bf_test_and_set (bg,
133 GNUNET_BLOCK_mingle_hash (&chash, 196 &chash))
134 bf_mutator, 197 return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
135 &mhash);
136 if (NULL != *bf)
137 {
138 if (GNUNET_YES ==
139 GNUNET_CONTAINER_bloomfilter_test (*bf, &mhash))
140 return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
141 }
142 else
143 {
144 *bf = GNUNET_CONTAINER_bloomfilter_init (NULL, 8, BLOOMFILTER_K);
145 }
146 GNUNET_CONTAINER_bloomfilter_add (*bf, &mhash);
147 }
148 return GNUNET_BLOCK_EVALUATION_OK_MORE; 198 return GNUNET_BLOCK_EVALUATION_OK_MORE;
149 default: 199 default:
150 return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED; 200 return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED;
@@ -214,6 +264,7 @@ libgnunet_plugin_block_fs_init (void *cls)
214 api = GNUNET_new (struct GNUNET_BLOCK_PluginFunctions); 264 api = GNUNET_new (struct GNUNET_BLOCK_PluginFunctions);
215 api->evaluate = &block_plugin_fs_evaluate; 265 api->evaluate = &block_plugin_fs_evaluate;
216 api->get_key = &block_plugin_fs_get_key; 266 api->get_key = &block_plugin_fs_get_key;
267 api->create_group = &block_plugin_fs_create_group;
217 api->types = types; 268 api->types = types;
218 return api; 269 return api;
219} 270}
@@ -225,7 +276,7 @@ libgnunet_plugin_block_fs_init (void *cls)
225void * 276void *
226libgnunet_plugin_block_fs_done (void *cls) 277libgnunet_plugin_block_fs_done (void *cls)
227{ 278{
228 struct GNUNET_TRANSPORT_PluginFunctions *api = cls; 279 struct GNUNET_BLOCK_PluginFunctions *api = cls;
229 280
230 GNUNET_free (api); 281 GNUNET_free (api);
231 return NULL; 282 return NULL;
diff --git a/src/fs/test_plugin_block_fs.c b/src/fs/test_plugin_block_fs.c
index 1fc9f2110..ba4f28bc5 100644
--- a/src/fs/test_plugin_block_fs.c
+++ b/src/fs/test_plugin_block_fs.c
@@ -40,28 +40,28 @@ test_fs (struct GNUNET_BLOCK_Context *ctx)
40 if (GNUNET_BLOCK_EVALUATION_OK_LAST != 40 if (GNUNET_BLOCK_EVALUATION_OK_LAST !=
41 GNUNET_BLOCK_evaluate (ctx, 41 GNUNET_BLOCK_evaluate (ctx,
42 GNUNET_BLOCK_TYPE_FS_DBLOCK, 42 GNUNET_BLOCK_TYPE_FS_DBLOCK,
43 NULL,
43 GNUNET_BLOCK_EO_NONE, 44 GNUNET_BLOCK_EO_NONE,
44 &key, 45 &key,
45 NULL, 0, 46 NULL, 0,
46 NULL, 0,
47 block, sizeof (block))) 47 block, sizeof (block)))
48 return 2; 48 return 2;
49 if (GNUNET_BLOCK_EVALUATION_REQUEST_VALID != 49 if (GNUNET_BLOCK_EVALUATION_REQUEST_VALID !=
50 GNUNET_BLOCK_evaluate (ctx, 50 GNUNET_BLOCK_evaluate (ctx,
51 GNUNET_BLOCK_TYPE_FS_DBLOCK, 51 GNUNET_BLOCK_TYPE_FS_DBLOCK,
52 NULL,
52 GNUNET_BLOCK_EO_NONE, 53 GNUNET_BLOCK_EO_NONE,
53 &key, 54 &key,
54 NULL, 0, 55 NULL, 0,
55 NULL, 0,
56 NULL, 0)) 56 NULL, 0))
57 return 4; 57 return 4;
58 GNUNET_log_skip (1, GNUNET_NO); 58 GNUNET_log_skip (1, GNUNET_NO);
59 if (GNUNET_BLOCK_EVALUATION_REQUEST_INVALID != 59 if (GNUNET_BLOCK_EVALUATION_REQUEST_INVALID !=
60 GNUNET_BLOCK_evaluate (ctx, 60 GNUNET_BLOCK_evaluate (ctx,
61 GNUNET_BLOCK_TYPE_FS_DBLOCK, 61 GNUNET_BLOCK_TYPE_FS_DBLOCK,
62 NULL,
62 GNUNET_BLOCK_EO_NONE, 63 GNUNET_BLOCK_EO_NONE,
63 &key, 64 &key,
64 NULL, 0,
65 "bogus", 5, 65 "bogus", 5,
66 NULL, 0)) 66 NULL, 0))
67 return 8; 67 return 8;
diff --git a/src/gns/Makefile.am b/src/gns/Makefile.am
index 0b65a3d17..464bbbca1 100644
--- a/src/gns/Makefile.am
+++ b/src/gns/Makefile.am
@@ -12,7 +12,6 @@ SUBDIRS = . $(NSS_SUBDIR)
12EXTRA_DIST = \ 12EXTRA_DIST = \
13 test_gns_defaults.conf \ 13 test_gns_defaults.conf \
14 test_gns_lookup.conf \ 14 test_gns_lookup.conf \
15 test_gns_nick_shorten.conf \
16 test_gns_proxy.conf \ 15 test_gns_proxy.conf \
17 test_gns_simple_lookup.conf \ 16 test_gns_simple_lookup.conf \
18 gns-helper-service-w32.conf \ 17 gns-helper-service-w32.conf \
@@ -70,8 +69,8 @@ endif
70 69
71libexec_PROGRAMS = \ 70libexec_PROGRAMS = \
72 gnunet-service-gns \ 71 gnunet-service-gns \
73 $(DO_W32_HELPER) \
74 gnunet-dns2gns \ 72 gnunet-dns2gns \
73 $(DO_W32_HELPER) \
75 $(DO_PROXY) 74 $(DO_PROXY)
76 75
77bin_PROGRAMS = \ 76bin_PROGRAMS = \
@@ -114,7 +113,6 @@ gnunet_gns_SOURCES = \
114gnunet_gns_LDADD = \ 113gnunet_gns_LDADD = \
115 libgnunetgns.la \ 114 libgnunetgns.la \
116 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ 115 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
117 $(top_builddir)/src/namestore/libgnunetnamestore.la \
118 $(top_builddir)/src/identity/libgnunetidentity.la \ 116 $(top_builddir)/src/identity/libgnunetidentity.la \
119 $(top_builddir)/src/util/libgnunetutil.la \ 117 $(top_builddir)/src/util/libgnunetutil.la \
120 $(GN_LIBINTL) 118 $(GN_LIBINTL)
@@ -134,11 +132,18 @@ gnunet_dns2gns_LDADD = \
134 libgnunetgns.la \ 132 libgnunetgns.la \
135 $(top_builddir)/src/util/libgnunetutil.la \ 133 $(top_builddir)/src/util/libgnunetutil.la \
136 $(top_builddir)/src/identity/libgnunetidentity.la \ 134 $(top_builddir)/src/identity/libgnunetidentity.la \
137 $(top_builddir)/src/namestore/libgnunetnamestore.la \
138 $(top_builddir)/src/dns/libgnunetdnsparser.la \ 135 $(top_builddir)/src/dns/libgnunetdnsparser.la \
139 $(top_builddir)/src/dns/libgnunetdnsstub.la \ 136 $(top_builddir)/src/dns/libgnunetdnsstub.la \
140 $(GN_LIBINTL) 137 $(GN_LIBINTL)
141 138
139if LINUX
140HIJACKBIN = gnunet-dns2gns
141install-exec-hook:
142 $(SUDO_BINARY) setcap 'cap_net_bind_service=+ep' $(DESTDIR)$(libexecdir)/gnunet-dns2gns || true
143else
144install-exec-hook:
145endif
146
142gnunet_gns_proxy_SOURCES = \ 147gnunet_gns_proxy_SOURCES = \
143 gnunet-gns-proxy.c 148 gnunet-gns-proxy.c
144gnunet_gns_proxy_CPPFLAGS = $(AM_CPPFLAGS) $(CPP_GNURL) 149gnunet_gns_proxy_CPPFLAGS = $(AM_CPPFLAGS) $(CPP_GNURL)
@@ -184,8 +189,6 @@ w32nsp_resolve_LDADD = -lws2_32
184gnunet_service_gns_SOURCES = \ 189gnunet_service_gns_SOURCES = \
185 gnunet-service-gns.c \ 190 gnunet-service-gns.c \
186 gnunet-service-gns_resolver.c gnunet-service-gns_resolver.h \ 191 gnunet-service-gns_resolver.c gnunet-service-gns_resolver.h \
187 gnunet-service-gns_reverser.c gnunet-service-gns_reverser.h \
188 gnunet-service-gns_shorten.c gnunet-service-gns_shorten.h \
189 gnunet-service-gns_interceptor.c gnunet-service-gns_interceptor.h 192 gnunet-service-gns_interceptor.c gnunet-service-gns_interceptor.h
190gnunet_service_gns_LDADD = \ 193gnunet_service_gns_LDADD = \
191 -lm \ 194 -lm \
@@ -200,7 +203,6 @@ gnunet_service_gns_LDADD = \
200 $(top_builddir)/src/dht/libgnunetdht.la \ 203 $(top_builddir)/src/dht/libgnunetdht.la \
201 $(top_builddir)/src/tun/libgnunettun.la \ 204 $(top_builddir)/src/tun/libgnunettun.la \
202 $(top_builddir)/src/namecache/libgnunetnamecache.la \ 205 $(top_builddir)/src/namecache/libgnunetnamecache.la \
203 $(top_builddir)/src/namestore/libgnunetnamestore.la \
204 $(USE_VPN) \ 206 $(USE_VPN) \
205 $(GN_LIBINTL) 207 $(GN_LIBINTL)
206 208
@@ -227,6 +229,7 @@ libgnunet_plugin_block_gns_la_SOURCES = \
227libgnunet_plugin_block_gns_la_LIBADD = \ 229libgnunet_plugin_block_gns_la_LIBADD = \
228 $(top_builddir)/src/util/libgnunetutil.la \ 230 $(top_builddir)/src/util/libgnunetutil.la \
229 $(top_builddir)/src/block/libgnunetblock.la \ 231 $(top_builddir)/src/block/libgnunetblock.la \
232 $(top_builddir)/src/block/libgnunetblockgroup.la \
230 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la 233 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la
231libgnunet_plugin_block_gns_la_LDFLAGS = \ 234libgnunet_plugin_block_gns_la_LDFLAGS = \
232 $(GN_PLUGIN_LDFLAGS) 235 $(GN_PLUGIN_LDFLAGS)
@@ -253,18 +256,16 @@ check_SCRIPTS = \
253 test_gns_gns2dns_lookup.sh \ 256 test_gns_gns2dns_lookup.sh \
254 test_gns_dht_lookup.sh\ 257 test_gns_dht_lookup.sh\
255 test_gns_delegated_lookup.sh \ 258 test_gns_delegated_lookup.sh \
256 test_gns_nick_shorten.sh\
257 test_gns_plus_lookup.sh\ 259 test_gns_plus_lookup.sh\
258 test_gns_zkey_lookup.sh\ 260 test_gns_zkey_lookup.sh\
259 test_gns_rel_expiration.sh\ 261 test_gns_rel_expiration.sh\
260 test_gns_soa_lookup.sh\ 262 test_gns_soa_lookup.sh\
261 test_gns_revocation.sh\ 263 test_gns_revocation.sh\
262 test_gns_cname_lookup.sh \ 264 test_gns_cname_lookup.sh
263 test_gns_reverse_lookup.sh
264 265
265if ENABLE_TEST_RUN 266if ENABLE_TEST_RUN
266if HAVE_SQLITE 267if HAVE_SQLITE
267 AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; 268 AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
268 TESTS = $(check_SCRIPTS) 269 TESTS = $(check_SCRIPTS)
269endif 270endif
270endif 271endif
diff --git a/src/gns/gns.h b/src/gns/gns.h
index ca5525f80..d77bf53c6 100644
--- a/src/gns/gns.h
+++ b/src/gns/gns.h
@@ -72,51 +72,20 @@ struct LookupMessage
72 int16_t options GNUNET_PACKED; 72 int16_t options GNUNET_PACKED;
73 73
74 /** 74 /**
75 * Is a shorten key attached? 75 * Always 0.
76 */ 76 */
77 int16_t have_key GNUNET_PACKED; 77 int16_t reserved GNUNET_PACKED;
78 78
79 /** 79 /**
80 * the type of record to look up 80 * the type of record to look up
81 */ 81 */
82 int32_t type GNUNET_PACKED; 82 int32_t type GNUNET_PACKED;
83 83
84 /**
85 * The key for shorten, if @e have_key is set
86 */
87 struct GNUNET_CRYPTO_EcdsaPrivateKey shorten_key;
88
89 /* Followed by the zero-terminated name to look up */ 84 /* Followed by the zero-terminated name to look up */
90}; 85};
91 86
92 87
93/** 88/**
94 * Message from client to GNS service to lookup records.
95 */
96struct ReverseLookupMessage
97{
98 /**
99 * Header of type #GNUNET_MESSAGE_TYPE_GNS_REVERSE_LOOKUP
100 */
101 struct GNUNET_MessageHeader header;
102
103 /**
104 * Unique identifier for this request (for key collisions).
105 */
106 uint32_t id GNUNET_PACKED;
107
108 /**
109 * Zone that is target for reverse lookup
110 */
111 struct GNUNET_CRYPTO_EcdsaPublicKey zone_pkey;
112
113 /**
114 * Root zone
115 */
116 struct GNUNET_CRYPTO_EcdsaPublicKey root_pkey;
117};
118
119/**
120 * Message from GNS service to client: new results. 89 * Message from GNS service to client: new results.
121 */ 90 */
122struct LookupResultMessage 91struct LookupResultMessage
@@ -140,24 +109,6 @@ struct LookupResultMessage
140 109
141}; 110};
142 111
143/**
144 * Message from GNS service to client: new results.
145 */
146struct ReverseLookupResultMessage
147{
148 /**
149 * Header of type #GNUNET_MESSAGE_TYPE_GNS_REVERSE_LOOKUP_RESULT
150 */
151 struct GNUNET_MessageHeader header;
152
153 /**
154 * Unique identifier for this request (for key collisions).
155 */
156 uint32_t id GNUNET_PACKED;
157
158 /* followed by the resulting name of the reverse lookup */
159};
160
161 112
162GNUNET_NETWORK_STRUCT_END 113GNUNET_NETWORK_STRUCT_END
163 114
diff --git a/src/gns/gns_api.c b/src/gns/gns_api.c
index f6f9889ac..84c4ae189 100644
--- a/src/gns/gns_api.c
+++ b/src/gns/gns_api.c
@@ -79,49 +79,6 @@ struct GNUNET_GNS_LookupRequest
79 79
80}; 80};
81 81
82/**
83 * Handle to a lookup request
84 */
85struct GNUNET_GNS_ReverseLookupRequest
86{
87
88 /**
89 * DLL
90 */
91 struct GNUNET_GNS_ReverseLookupRequest *next;
92
93 /**
94 * DLL
95 */
96 struct GNUNET_GNS_ReverseLookupRequest *prev;
97
98 /**
99 * handle to gns
100 */
101 struct GNUNET_GNS_Handle *gns_handle;
102
103 /**
104 * processor to call on lookup result
105 */
106 GNUNET_GNS_ReverseLookupResultProcessor lookup_proc;
107
108 /**
109 * @e lookup_proc closure
110 */
111 void *proc_cls;
112
113 /**
114 * Envelope with the message for this queue entry.
115 */
116 struct GNUNET_MQ_Envelope *env;
117
118 /**
119 * request id
120 */
121 uint32_t r_id;
122
123};
124
125 82
126/** 83/**
127 * Connection to the GNS service. 84 * Connection to the GNS service.
@@ -150,15 +107,6 @@ struct GNUNET_GNS_Handle
150 struct GNUNET_GNS_LookupRequest *lookup_tail; 107 struct GNUNET_GNS_LookupRequest *lookup_tail;
151 108
152 /** 109 /**
153 * Head of linked list of active reverse lookup requests.
154 */
155 struct GNUNET_GNS_ReverseLookupRequest *rev_lookup_head;
156
157 /**
158 * Tail of linked list of active reverse lookup requests.
159 */
160 struct GNUNET_GNS_ReverseLookupRequest *rev_lookup_tail;
161 /**
162 * Reconnect task 110 * Reconnect task
163 */ 111 */
164 struct GNUNET_SCHEDULER_Task *reconnect_task; 112 struct GNUNET_SCHEDULER_Task *reconnect_task;
@@ -232,71 +180,13 @@ mq_error_handler (void *cls,
232 enum GNUNET_MQ_Error error) 180 enum GNUNET_MQ_Error error)
233{ 181{
234 struct GNUNET_GNS_Handle *handle = cls; 182 struct GNUNET_GNS_Handle *handle = cls;
235 LOG (GNUNET_ERROR_TYPE_WARNING, "Problem with message queue. error: %i\n", 183
184 LOG (GNUNET_ERROR_TYPE_WARNING,
185 "Problem with message queue. error: %i\n",
236 error); 186 error);
237 force_reconnect (handle); 187 force_reconnect (handle);
238} 188}
239 189
240/**
241 * Check validity of message received from the GNS service
242 *
243 * @param cls the `struct GNUNET_GNS_Handle *`
244 * @param loookup_msg the incoming message
245 */
246static int
247check_rev_result (void *cls,
248 const struct ReverseLookupResultMessage *lookup_msg)
249{
250 size_t mlen = ntohs (lookup_msg->header.size) - sizeof (*lookup_msg);
251 char *name;
252
253 name = (char*) &lookup_msg[1];
254 if ('\0' != name[mlen-1])
255 {
256 GNUNET_break (0);
257 return GNUNET_SYSERR;
258 }
259 return GNUNET_OK;
260}
261
262
263/**
264 * Handler for messages received from the GNS service
265 *
266 * @param cls the `struct GNUNET_GNS_Handle *`
267 * @param loookup_msg the incoming message
268 */
269static void
270handle_rev_result (void *cls,
271 const struct ReverseLookupResultMessage *lookup_msg)
272{
273 struct GNUNET_GNS_Handle *handle = cls;
274 char *name;
275 uint32_t r_id = ntohl (lookup_msg->id);
276 struct GNUNET_GNS_ReverseLookupRequest *rlr;
277 GNUNET_GNS_ReverseLookupResultProcessor proc;
278 void *proc_cls;
279
280 name = (char*)&lookup_msg[1];
281 LOG (GNUNET_ERROR_TYPE_DEBUG,
282 "Received reverse lookup reply from GNS service (%s)\n",
283 name);
284 for (rlr = handle->rev_lookup_head; NULL != rlr; rlr = rlr->next)
285 if (rlr->r_id == r_id)
286 break;
287 if (NULL == rlr)
288 return;
289 proc = rlr->lookup_proc;
290 proc_cls = rlr->proc_cls;
291 GNUNET_CONTAINER_DLL_remove (handle->rev_lookup_head,
292 handle->rev_lookup_tail,
293 rlr);
294 GNUNET_free (rlr);
295 proc (proc_cls,
296 name);
297}
298
299
300 190
301/** 191/**
302 * Check validity of message received from the GNS service 192 * Check validity of message received from the GNS service
@@ -385,14 +275,9 @@ reconnect (struct GNUNET_GNS_Handle *handle)
385 GNUNET_MESSAGE_TYPE_GNS_LOOKUP_RESULT, 275 GNUNET_MESSAGE_TYPE_GNS_LOOKUP_RESULT,
386 struct LookupResultMessage, 276 struct LookupResultMessage,
387 handle), 277 handle),
388 GNUNET_MQ_hd_var_size (rev_result,
389 GNUNET_MESSAGE_TYPE_GNS_REVERSE_LOOKUP_RESULT,
390 struct ReverseLookupResultMessage,
391 handle),
392 GNUNET_MQ_handler_end () 278 GNUNET_MQ_handler_end ()
393 }; 279 };
394 struct GNUNET_GNS_LookupRequest *lh; 280 struct GNUNET_GNS_LookupRequest *lh;
395 struct GNUNET_GNS_ReverseLookupRequest *rlh;
396 281
397 GNUNET_assert (NULL == handle->mq); 282 GNUNET_assert (NULL == handle->mq);
398 LOG (GNUNET_ERROR_TYPE_DEBUG, 283 LOG (GNUNET_ERROR_TYPE_DEBUG,
@@ -407,9 +292,6 @@ reconnect (struct GNUNET_GNS_Handle *handle)
407 for (lh = handle->lookup_head; NULL != lh; lh = lh->next) 292 for (lh = handle->lookup_head; NULL != lh; lh = lh->next)
408 GNUNET_MQ_send_copy (handle->mq, 293 GNUNET_MQ_send_copy (handle->mq,
409 lh->env); 294 lh->env);
410 for (rlh = handle->rev_lookup_head; NULL != rlh; rlh = rlh->next)
411 GNUNET_MQ_send_copy (handle->mq,
412 rlh->env);
413} 295}
414 296
415 297
@@ -455,7 +337,6 @@ GNUNET_GNS_disconnect (struct GNUNET_GNS_Handle *handle)
455 handle->reconnect_task = NULL; 337 handle->reconnect_task = NULL;
456 } 338 }
457 GNUNET_assert (NULL == handle->lookup_head); 339 GNUNET_assert (NULL == handle->lookup_head);
458 GNUNET_assert (NULL == handle->rev_lookup_head);
459 GNUNET_free (handle); 340 GNUNET_free (handle);
460} 341}
461 342
@@ -477,22 +358,6 @@ GNUNET_GNS_lookup_cancel (struct GNUNET_GNS_LookupRequest *lr)
477 GNUNET_free (lr); 358 GNUNET_free (lr);
478} 359}
479 360
480/**
481 * Cancel pending reverse lookup request
482 *
483 * @param lr the lookup request to cancel
484 */
485void
486GNUNET_GNS_reverse_lookup_cancel (struct GNUNET_GNS_ReverseLookupRequest *lr)
487{
488 struct GNUNET_GNS_Handle *handle = lr->gns_handle;
489
490 GNUNET_CONTAINER_DLL_remove (handle->rev_lookup_head,
491 handle->rev_lookup_tail,
492 lr);
493 GNUNET_MQ_discard (lr->env);
494 GNUNET_free (lr);
495}
496 361
497/** 362/**
498 * Perform an asynchronous lookup operation on the GNS. 363 * Perform an asynchronous lookup operation on the GNS.
@@ -502,7 +367,6 @@ GNUNET_GNS_reverse_lookup_cancel (struct GNUNET_GNS_ReverseLookupRequest *lr)
502 * @param zone the zone to start the resolution in 367 * @param zone the zone to start the resolution in
503 * @param type the record type to look up 368 * @param type the record type to look up
504 * @param options local options for the lookup 369 * @param options local options for the lookup
505 * @param shorten_zone_key the private key of the shorten zone (can be NULL)
506 * @param proc processor to call on result 370 * @param proc processor to call on result
507 * @param proc_cls closure for @a proc 371 * @param proc_cls closure for @a proc
508 * @return handle to the get request 372 * @return handle to the get request
@@ -513,7 +377,6 @@ GNUNET_GNS_lookup (struct GNUNET_GNS_Handle *handle,
513 const struct GNUNET_CRYPTO_EcdsaPublicKey *zone, 377 const struct GNUNET_CRYPTO_EcdsaPublicKey *zone,
514 uint32_t type, 378 uint32_t type,
515 enum GNUNET_GNS_LocalOptions options, 379 enum GNUNET_GNS_LocalOptions options,
516 const struct GNUNET_CRYPTO_EcdsaPrivateKey *shorten_zone_key,
517 GNUNET_GNS_LookupResultProcessor proc, 380 GNUNET_GNS_LookupResultProcessor proc,
518 void *proc_cls) 381 void *proc_cls)
519{ 382{
@@ -531,7 +394,7 @@ GNUNET_GNS_lookup (struct GNUNET_GNS_Handle *handle,
531 "Trying to lookup `%s' in GNS\n", 394 "Trying to lookup `%s' in GNS\n",
532 name); 395 name);
533 nlen = strlen (name) + 1; 396 nlen = strlen (name) + 1;
534 if (nlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (*lr)) 397 if (nlen >= GNUNET_MAX_MESSAGE_SIZE - sizeof (*lr))
535 { 398 {
536 GNUNET_break (0); 399 GNUNET_break (0);
537 return NULL; 400 return NULL;
@@ -548,11 +411,6 @@ GNUNET_GNS_lookup (struct GNUNET_GNS_Handle *handle,
548 lookup_msg->options = htons ((uint16_t) options); 411 lookup_msg->options = htons ((uint16_t) options);
549 lookup_msg->zone = *zone; 412 lookup_msg->zone = *zone;
550 lookup_msg->type = htonl (type); 413 lookup_msg->type = htonl (type);
551 if (NULL != shorten_zone_key)
552 {
553 lookup_msg->have_key = htons (GNUNET_YES);
554 lookup_msg->shorten_key = *shorten_zone_key;
555 }
556 GNUNET_memcpy (&lookup_msg[1], 414 GNUNET_memcpy (&lookup_msg[1],
557 name, 415 name,
558 nlen); 416 nlen);
@@ -565,50 +423,4 @@ GNUNET_GNS_lookup (struct GNUNET_GNS_Handle *handle,
565 return lr; 423 return lr;
566} 424}
567 425
568/**
569 * Perform an asynchronous reverse lookup operation on the GNS.
570 *
571 * @param handle handle to the GNS service
572 * @param zone_key zone to find a name for
573 * @param root_key our zone
574 * @param proc processor to call on result
575 * @param proc_cls closure for @a proc
576 * @return handle to the request
577 */
578struct GNUNET_GNS_ReverseLookupRequest*
579GNUNET_GNS_reverse_lookup (struct GNUNET_GNS_Handle *handle,
580 const struct GNUNET_CRYPTO_EcdsaPublicKey *zone_key,
581 const struct GNUNET_CRYPTO_EcdsaPublicKey *root_key,
582 GNUNET_GNS_ReverseLookupResultProcessor proc,
583 void *proc_cls)
584{
585 /* IPC to shorten gns names, return shorten_handle */
586 struct ReverseLookupMessage *rev_lookup_msg;
587 struct GNUNET_GNS_ReverseLookupRequest *lr;
588
589 if ((NULL == zone_key) || (NULL == root_key))
590 {
591 GNUNET_break (0);
592 return NULL;
593 }
594 LOG (GNUNET_ERROR_TYPE_DEBUG,
595 "Trying to reverse lookup in GNS\n");
596 lr = GNUNET_new (struct GNUNET_GNS_ReverseLookupRequest);
597 lr->gns_handle = handle;
598 lr->lookup_proc = proc;
599 lr->proc_cls = proc_cls;
600 lr->r_id = handle->r_id_gen++;
601 lr->env = GNUNET_MQ_msg (rev_lookup_msg,
602 GNUNET_MESSAGE_TYPE_GNS_REVERSE_LOOKUP);
603 rev_lookup_msg->id = htonl (lr->r_id);
604 rev_lookup_msg->zone_pkey = *zone_key;
605 rev_lookup_msg->root_pkey = *root_key;
606 GNUNET_CONTAINER_DLL_insert (handle->rev_lookup_head,
607 handle->rev_lookup_tail,
608 lr);
609 if (NULL != handle->mq)
610 GNUNET_MQ_send_copy (handle->mq,
611 lr->env);
612 return lr;
613}
614/* end of gns_api.c */ 426/* end of gns_api.c */
diff --git a/src/gns/gnunet-bcd.c b/src/gns/gnunet-bcd.c
index 21471350d..0746d5c57 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_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 f58303789..424677d14 100644
--- a/src/gns/gnunet-dns2gns.c
+++ b/src/gns/gnunet-dns2gns.c
@@ -138,7 +138,7 @@ static char *dns_ip;
138/** 138/**
139 * UDP Port we listen on for inbound DNS requests. 139 * UDP Port we listen on for inbound DNS requests.
140 */ 140 */
141static unsigned int listen_port = 2853; 141static unsigned int listen_port = 53;
142 142
143/** 143/**
144 * Which GNS zone do we translate incoming DNS requests to? 144 * Which GNS zone do we translate incoming DNS requests to?
@@ -483,7 +483,6 @@ handle_request (struct GNUNET_NETWORK_Handle *lsock,
483 &my_zone, 483 &my_zone,
484 type, 484 type,
485 GNUNET_NO, 485 GNUNET_NO,
486 NULL /* no shorten */,
487 &result_processor, 486 &result_processor,
488 request); 487 request);
489 } 488 }
@@ -618,7 +617,7 @@ run_dnsd ()
618 if (NULL != listen_socket4) 617 if (NULL != listen_socket4)
619 { 618 {
620 struct sockaddr_in v4; 619 struct sockaddr_in v4;
621 620
622 memset (&v4, 0, sizeof (v4)); 621 memset (&v4, 0, sizeof (v4));
623 v4.sin_family = AF_INET; 622 v4.sin_family = AF_INET;
624#if HAVE_SOCKADDR_IN_SIN_LEN 623#if HAVE_SOCKADDR_IN_SIN_LEN
@@ -641,7 +640,7 @@ run_dnsd ()
641 if (NULL != listen_socket6) 640 if (NULL != listen_socket6)
642 { 641 {
643 struct sockaddr_in6 v6; 642 struct sockaddr_in6 v6;
644 643
645 memset (&v6, 0, sizeof (v6)); 644 memset (&v6, 0, sizeof (v6));
646 v6.sin6_family = AF_INET6; 645 v6.sin6_family = AF_INET6;
647#if HAVE_SOCKADDR_IN_SIN_LEN 646#if HAVE_SOCKADDR_IN_SIN_LEN
@@ -777,33 +776,53 @@ int
777main (int argc, 776main (int argc,
778 char *const *argv) 777 char *const *argv)
779{ 778{
780 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 779 struct GNUNET_GETOPT_CommandLineOption options[] = {
781 {'d', "dns", "IP", 780
782 gettext_noop ("IP of recursive DNS resolver to use (required)"), 1, 781 GNUNET_GETOPT_option_string ('d',
783 &GNUNET_GETOPT_set_string, &dns_ip}, 782 "dns",
784 {'f', "fcfs", "NAME", 783 "IP",
785 gettext_noop ("Authoritative FCFS suffix to use (optional); default: fcfs.zkey.eu"), 1, 784 gettext_noop ("IP of recursive DNS resolver to use (required)"),
786 &GNUNET_GETOPT_set_string, &fcfs_suffix}, 785 &dns_ip),
787 {'s', "suffix", "SUFFIX", 786
788 gettext_noop ("Authoritative DNS suffix to use (optional); default: zkey.eu"), 1, 787 GNUNET_GETOPT_option_string ('f',
789 &GNUNET_GETOPT_set_string, &dns_suffix}, 788 "fcfs",
790 {'p', "port", "UDPPORT", 789 "NAME",
791 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"),
792 &GNUNET_GETOPT_set_uint, &listen_port}, 791 &fcfs_suffix),
793 {'z', "zone", "PUBLICKEY", 792
794 gettext_noop ("Public key of the GNS zone to use (overrides default)"), 1, 793 GNUNET_GETOPT_option_string ('s',
795 &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_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
796 GNUNET_GETOPT_OPTION_END 811 GNUNET_GETOPT_OPTION_END
797 }; 812 };
798 int ret; 813 int ret;
799 814
800 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, 815 if (GNUNET_OK !=
801 &argc, &argv)) 816 GNUNET_STRINGS_get_utf8_args (argc, argv,
817 &argc, &argv))
802 return 2; 818 return 2;
803 GNUNET_log_setup ("gnunet-dns2gns", "WARNING", NULL); 819 GNUNET_log_setup ("gnunet-dns2gns",
820 "WARNING",
821 NULL);
804 ret = 822 ret =
805 (GNUNET_OK == 823 (GNUNET_OK ==
806 GNUNET_PROGRAM_run (argc, argv, "gnunet-dns2gns", 824 GNUNET_PROGRAM_run (argc, argv,
825 "gnunet-dns2gns",
807 _("GNUnet DNS-to-GNS proxy (a DNS server)"), 826 _("GNUnet DNS-to-GNS proxy (a DNS server)"),
808 options, 827 options,
809 &run, NULL)) ? 0 : 1; 828 &run, NULL)) ? 0 : 1;
diff --git a/src/gns/gnunet-gns-helper-service-w32.c b/src/gns/gnunet-gns-helper-service-w32.c
index bfee2b498..a59cc5981 100644
--- a/src/gns/gnunet-gns-helper-service-w32.c
+++ b/src/gns/gnunet-gns-helper-service-w32.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
@@ -48,6 +48,7 @@ DEFINE_DNS_GUID(SVCID_DNS_TYPE_SRV, 0x0021);
48DEFINE_GUID(SVCID_HOSTNAME, 0x0002a800, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46); 48DEFINE_GUID(SVCID_HOSTNAME, 0x0002a800, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
49DEFINE_GUID(SVCID_INET_HOSTADDRBYNAME, 0x0002a803, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46); 49DEFINE_GUID(SVCID_INET_HOSTADDRBYNAME, 0x0002a803, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
50 50
51
51struct request 52struct request
52{ 53{
53 /** 54 /**
@@ -60,14 +61,23 @@ struct request
60 */ 61 */
61 struct request *prev; 62 struct request *prev;
62 63
63 struct GNUNET_SERVER_Client *client; 64 /**
65 * Client that issued the request
66 */
67 struct GNUNET_SERVICE_Client *client;
68
64 GUID sc; 69 GUID sc;
70
65 int af; 71 int af;
72
66 wchar_t *name; 73 wchar_t *name;
74
67 char *u8name; 75 char *u8name;
76
68 struct GNUNET_GNS_LookupRequest *lookup_request; 77 struct GNUNET_GNS_LookupRequest *lookup_request;
69}; 78};
70 79
80
71/** 81/**
72 * Head of the doubly-linked list (for cleanup). 82 * Head of the doubly-linked list (for cleanup).
73 */ 83 */
@@ -99,14 +109,10 @@ static struct GNUNET_IDENTITY_Handle *identity;
99static struct GNUNET_CRYPTO_EcdsaPublicKey gns_master_pubkey; 109static struct GNUNET_CRYPTO_EcdsaPublicKey gns_master_pubkey;
100 110
101/** 111/**
102 * Private key of the gns-short ego
103 */
104static struct GNUNET_CRYPTO_EcdsaPrivateKey gns_short_privkey;
105
106/**
107 * Set to 1 once egos are obtained. 112 * Set to 1 once egos are obtained.
108 */ 113 */
109static int got_egos = 0; 114static int got_egos;
115
110 116
111/** 117/**
112 * Task run on shutdown. Cleans up everything. 118 * Task run on shutdown. Cleans up everything.
@@ -117,6 +123,7 @@ static void
117do_shutdown (void *cls) 123do_shutdown (void *cls)
118{ 124{
119 struct request *rq; 125 struct request *rq;
126
120 if (NULL != id_op) 127 if (NULL != id_op)
121 { 128 {
122 GNUNET_IDENTITY_cancel (id_op); 129 GNUNET_IDENTITY_cancel (id_op);
@@ -130,8 +137,10 @@ do_shutdown (void *cls)
130 while (NULL != (rq = rq_head)) 137 while (NULL != (rq = rq_head))
131 { 138 {
132 if (NULL != rq->lookup_request) 139 if (NULL != rq->lookup_request)
133 GNUNET_GNS_lookup_cancel(rq->lookup_request); 140 GNUNET_GNS_lookup_cancel (rq->lookup_request);
134 GNUNET_CONTAINER_DLL_remove (rq_head, rq_tail, rq); 141 GNUNET_CONTAINER_DLL_remove (rq_head,
142 rq_tail,
143 rq);
135 GNUNET_free_non_null (rq->name); 144 GNUNET_free_non_null (rq->name);
136 if (rq->u8name) 145 if (rq->u8name)
137 free (rq->u8name); 146 free (rq->u8name);
@@ -144,133 +153,6 @@ do_shutdown (void *cls)
144 } 153 }
145} 154}
146 155
147/**
148 * Context for transmitting replies to clients.
149 */
150struct TransmitCallbackContext
151{
152
153 /**
154 * We keep these in a doubly-linked list (for cleanup).
155 */
156 struct TransmitCallbackContext *next;
157
158 /**
159 * We keep these in a doubly-linked list (for cleanup).
160 */
161 struct TransmitCallbackContext *prev;
162
163 /**
164 * The message that we're asked to transmit.
165 */
166 struct GNUNET_MessageHeader *msg;
167
168 /**
169 * Handle for the transmission request.
170 */
171 struct GNUNET_SERVER_TransmitHandle *th;
172
173
174 /**
175 * Handle for the client to which to send
176 */
177 struct GNUNET_SERVER_Client *client;
178};
179
180
181/**
182 * Head of the doubly-linked list (for cleanup).
183 */
184static struct TransmitCallbackContext *tcc_head;
185
186/**
187 * Tail of the doubly-linked list (for cleanup).
188 */
189static struct TransmitCallbackContext *tcc_tail;
190
191/**
192 * Have we already cleaned up the TCCs and are hence no longer
193 * willing (or able) to transmit anything to anyone?
194 */
195static int cleaning_done;
196
197
198/**
199 * Function called to notify a client about the socket
200 * being ready to queue more data. "buf" will be
201 * NULL and "size" zero if the socket was closed for
202 * writing in the meantime.
203 *
204 * @param cls closure
205 * @param size number of bytes available in buf
206 * @param buf where the callee should write the message
207 * @return number of bytes written to buf
208 */
209static size_t
210transmit_callback (void *cls, size_t size, void *buf)
211{
212 struct TransmitCallbackContext *tcc = cls;
213 size_t msize;
214
215 tcc->th = NULL;
216 GNUNET_CONTAINER_DLL_remove (tcc_head, tcc_tail, tcc);
217 msize = ntohs (tcc->msg->size);
218 if (size == 0)
219 {
220 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
221 _("Transmission to client failed!\n"));
222 GNUNET_free (tcc->msg);
223 GNUNET_free (tcc);
224 return 0;
225 }
226 GNUNET_assert (size >= msize);
227 GNUNET_memcpy (buf, tcc->msg, msize);
228 GNUNET_free (tcc->msg);
229 GNUNET_free (tcc);
230 for (tcc = tcc_head; tcc; tcc = tcc->next)
231 {
232 if (NULL == tcc->th)
233 {
234 tcc->th = GNUNET_SERVER_notify_transmit_ready (tcc->client,
235 ntohs (tcc->msg->size),
236 GNUNET_TIME_UNIT_FOREVER_REL,
237 &transmit_callback, tcc);
238 break;
239 }
240 }
241 return msize;
242}
243
244
245/**
246 * Transmit the given message to the client.
247 *
248 * @param client target of the message
249 * @param msg message to transmit, will be freed!
250 */
251static void
252transmit (struct GNUNET_SERVER_Client *client,
253 struct GNUNET_MessageHeader *msg)
254{
255 struct TransmitCallbackContext *tcc;
256
257 if (GNUNET_YES == cleaning_done)
258 {
259 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
260 _("Shutdown in progress, aborting transmission.\n"));
261 GNUNET_free (msg);
262 return;
263 }
264 tcc = GNUNET_new (struct TransmitCallbackContext);
265 tcc->msg = msg;
266 tcc->client = client;
267 tcc->th = GNUNET_SERVER_notify_transmit_ready (client,
268 ntohs (msg->size),
269 GNUNET_TIME_UNIT_FOREVER_REL,
270 &transmit_callback, tcc);
271 GNUNET_CONTAINER_DLL_insert (tcc_head, tcc_tail, tcc);
272}
273
274 156
275#define MarshallPtr(ptr, base, type) \ 157#define MarshallPtr(ptr, base, type) \
276 if (ptr) \ 158 if (ptr) \
@@ -280,7 +162,6 @@ transmit (struct GNUNET_SERVER_Client *client,
280void 162void
281MarshallWSAQUERYSETW (WSAQUERYSETW *qs, GUID *sc) 163MarshallWSAQUERYSETW (WSAQUERYSETW *qs, GUID *sc)
282{ 164{
283 int i;
284 MarshallPtr (qs->lpszServiceInstanceName, qs, wchar_t); 165 MarshallPtr (qs->lpszServiceInstanceName, qs, wchar_t);
285 MarshallPtr (qs->lpServiceClassId, qs, GUID); 166 MarshallPtr (qs->lpServiceClassId, qs, GUID);
286 MarshallPtr (qs->lpVersion, qs, WSAVERSION); 167 MarshallPtr (qs->lpVersion, qs, WSAVERSION);
@@ -288,7 +169,7 @@ MarshallWSAQUERYSETW (WSAQUERYSETW *qs, GUID *sc)
288 MarshallPtr (qs->lpszContext, qs, wchar_t); 169 MarshallPtr (qs->lpszContext, qs, wchar_t);
289 MarshallPtr (qs->lpafpProtocols, qs, AFPROTOCOLS); 170 MarshallPtr (qs->lpafpProtocols, qs, AFPROTOCOLS);
290 MarshallPtr (qs->lpszQueryString, qs, wchar_t); 171 MarshallPtr (qs->lpszQueryString, qs, wchar_t);
291 for (i = 0; i < qs->dwNumberOfCsAddrs; i++) 172 for (int i = 0; i < qs->dwNumberOfCsAddrs; i++)
292 { 173 {
293 MarshallPtr (qs->lpcsaBuffer[i].LocalAddr.lpSockaddr, qs, SOCKADDR); 174 MarshallPtr (qs->lpcsaBuffer[i].LocalAddr.lpSockaddr, qs, SOCKADDR);
294 MarshallPtr (qs->lpcsaBuffer[i].RemoteAddr.lpSockaddr, qs, SOCKADDR); 175 MarshallPtr (qs->lpcsaBuffer[i].RemoteAddr.lpSockaddr, qs, SOCKADDR);
@@ -297,12 +178,13 @@ MarshallWSAQUERYSETW (WSAQUERYSETW *qs, GUID *sc)
297 if (IsEqualGUID (&SVCID_INET_HOSTADDRBYNAME, sc) && qs->lpBlob != NULL && qs->lpBlob->pBlobData != NULL) 178 if (IsEqualGUID (&SVCID_INET_HOSTADDRBYNAME, sc) && qs->lpBlob != NULL && qs->lpBlob->pBlobData != NULL)
298 { 179 {
299 struct hostent *he; 180 struct hostent *he;
181
300 he = (struct hostent *) qs->lpBlob->pBlobData; 182 he = (struct hostent *) qs->lpBlob->pBlobData;
301 for (i = 0; he->h_aliases[i] != NULL; i++) 183 for (int i = 0; he->h_aliases[i] != NULL; i++)
302 MarshallPtr (he->h_aliases[i], he, char); 184 MarshallPtr (he->h_aliases[i], he, char);
303 MarshallPtr (he->h_aliases, he, char *); 185 MarshallPtr (he->h_aliases, he, char *);
304 MarshallPtr (he->h_name, he, char); 186 MarshallPtr (he->h_name, he, char);
305 for (i = 0; he->h_addr_list[i] != NULL; i++) 187 for (int i = 0; he->h_addr_list[i] != NULL; i++)
306 MarshallPtr (he->h_addr_list[i], he, void); 188 MarshallPtr (he->h_addr_list[i], he, void);
307 MarshallPtr (he->h_addr_list, he, char *); 189 MarshallPtr (he->h_addr_list, he, char *);
308 MarshallPtr (qs->lpBlob->pBlobData, qs, void); 190 MarshallPtr (qs->lpBlob->pBlobData, qs, void);
@@ -312,13 +194,16 @@ MarshallWSAQUERYSETW (WSAQUERYSETW *qs, GUID *sc)
312 194
313 195
314static void 196static void
315process_lookup_result (void* cls, uint32_t rd_count, 197process_lookup_result (void *cls,
316 const struct GNUNET_GNSRECORD_Data *rd) 198 uint32_t rd_count,
199 const struct GNUNET_GNSRECORD_Data *rd)
317{ 200{
201 struct request *rq = cls;
318 int i, j, csanum; 202 int i, j, csanum;
319 struct request *rq = (struct request *) cls;
320 struct GNUNET_W32RESOLVER_GetMessage *msg; 203 struct GNUNET_W32RESOLVER_GetMessage *msg;
204 struct GNUNET_MQ_Envelope *msg_env;
321 struct GNUNET_MessageHeader *msgend; 205 struct GNUNET_MessageHeader *msgend;
206 struct GNUNET_MQ_Envelope *msgend_env;
322 WSAQUERYSETW *qs; 207 WSAQUERYSETW *qs;
323 size_t size; 208 size_t size;
324 size_t size_recalc; 209 size_t size_recalc;
@@ -327,18 +212,20 @@ process_lookup_result (void* cls, uint32_t rd_count,
327 size_t blobaddrcount = 0; 212 size_t blobaddrcount = 0;
328 213
329 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 214 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
330 "Got lookup result with count %u for rq %p with client %p\n", 215 "Got lookup result with count %u for rq %p with client %p\n",
331 rd_count, rq, rq->client); 216 rd_count,
217 rq,
218 rq->client);
332 rq->lookup_request = NULL; 219 rq->lookup_request = NULL;
333 220
334 if (rd_count == 0) 221 if (0 == rd_count)
335 { 222 {
336 size = sizeof (struct GNUNET_MessageHeader); 223 msgend_env = GNUNET_MQ_msg (msgend, GNUNET_MESSAGE_TYPE_W32RESOLVER_RESPONSE);
337 msg = GNUNET_malloc (size); 224 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (rq->client),
338 msg->header.size = htons (size); 225 msgend_env);
339 msg->header.type = htons (GNUNET_MESSAGE_TYPE_W32RESOLVER_RESPONSE); 226 GNUNET_CONTAINER_DLL_remove (rq_head,
340 transmit (rq->client, &msg->header); 227 rq_tail,
341 GNUNET_CONTAINER_DLL_remove (rq_head, rq_tail, rq); 228 rq);
342 GNUNET_free_non_null (rq->name); 229 GNUNET_free_non_null (rq->name);
343 if (rq->u8name) 230 if (rq->u8name)
344 free (rq->u8name); 231 free (rq->u8name);
@@ -396,9 +283,9 @@ process_lookup_result (void* cls, uint32_t rd_count,
396 size += blobsize; 283 size += blobsize;
397 } 284 }
398 size_recalc = sizeof (struct GNUNET_W32RESOLVER_GetMessage) + sizeof (WSAQUERYSETW); 285 size_recalc = sizeof (struct GNUNET_W32RESOLVER_GetMessage) + sizeof (WSAQUERYSETW);
399 msg = GNUNET_malloc (size); 286 msg_env = GNUNET_MQ_msg_extra (msg,
400 msg->header.size = htons (size - sizeof (struct GNUNET_MessageHeader)); 287 size - sizeof (struct GNUNET_MessageHeader),
401 msg->header.type = htons (GNUNET_MESSAGE_TYPE_W32RESOLVER_RESPONSE); 288 GNUNET_MESSAGE_TYPE_W32RESOLVER_RESPONSE);
402 msg->af = htonl (rq->af); 289 msg->af = htonl (rq->af);
403 msg->sc_data1 = htonl (rq->sc.Data1); 290 msg->sc_data1 = htonl (rq->sc.Data1);
404 msg->sc_data2 = htons (rq->sc.Data2); 291 msg->sc_data2 = htons (rq->sc.Data2);
@@ -557,19 +444,24 @@ process_lookup_result (void* cls, uint32_t rd_count,
557 } 444 }
558 he->h_addr_list[j] = NULL; 445 he->h_addr_list[j] = NULL;
559 } 446 }
560 msgend = GNUNET_new (struct GNUNET_MessageHeader); 447 msgend_env = GNUNET_MQ_msg (msgend, GNUNET_MESSAGE_TYPE_W32RESOLVER_RESPONSE);
561
562 msgend->type = htons (GNUNET_MESSAGE_TYPE_W32RESOLVER_RESPONSE);
563 msgend->size = htons (sizeof (struct GNUNET_MessageHeader));
564 448
565 if ((char *) ptr - (char *) msg != size || size_recalc != size || size_recalc != ((char *) ptr - (char *) msg)) 449 if ((char *) ptr - (char *) msg != size || size_recalc != size || size_recalc != ((char *) ptr - (char *) msg))
566 { 450 {
567 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error in WSAQUERYSETW size calc: expected %lu, got %lu (recalc %lu)\n", size, (unsigned long) ((char *) ptr - (char *) msg), size_recalc); 451 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
452 "Error in WSAQUERYSETW size calc: expected %u, got %lu (recalc %u)\n",
453 size,
454 (unsigned long) ((char *) ptr - (char *) msg),
455 size_recalc);
568 } 456 }
569 MarshallWSAQUERYSETW (qs, &rq->sc); 457 MarshallWSAQUERYSETW (qs, &rq->sc);
570 transmit (rq->client, &msg->header); 458 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (rq->client),
571 transmit (rq->client, msgend); 459 msg_env);
572 GNUNET_CONTAINER_DLL_remove (rq_head, rq_tail, rq); 460 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (rq->client),
461 msgend_env);
462 GNUNET_CONTAINER_DLL_remove (rq_head,
463 rq_tail,
464 rq);
573 GNUNET_free_non_null (rq->name); 465 GNUNET_free_non_null (rq->name);
574 if (rq->u8name) 466 if (rq->u8name)
575 free (rq->u8name); 467 free (rq->u8name);
@@ -578,8 +470,10 @@ process_lookup_result (void* cls, uint32_t rd_count,
578 470
579 471
580static void 472static void
581get_ip_from_hostname (struct GNUNET_SERVER_Client *client, 473get_ip_from_hostname (struct GNUNET_SERVICE_Client *client,
582 const wchar_t *name, int af, GUID sc) 474 const wchar_t *name,
475 int af,
476 GUID sc)
583{ 477{
584 struct request *rq; 478 struct request *rq;
585 char *hostname; 479 char *hostname;
@@ -610,10 +504,19 @@ get_ip_from_hostname (struct GNUNET_SERVER_Client *client,
610 else 504 else
611 { 505 {
612 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 506 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
613 "Unknown GUID: %08X-%04X-%04X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X\n", 507 "Unknown GUID: %08lX-%04X-%04X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X\n",
614 sc.Data1, sc.Data2, sc.Data3, sc.Data4[0], sc.Data4[1], sc.Data4[2], 508 sc.Data1,
615 sc.Data4[3], sc.Data4[4], sc.Data4[5], sc.Data4[6], sc.Data4[7]); 509 sc.Data2,
616 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); 510 sc.Data3,
511 sc.Data4[0],
512 sc.Data4[1],
513 sc.Data4[2],
514 sc.Data4[3],
515 sc.Data4[4],
516 sc.Data4[5],
517 sc.Data4[6],
518 sc.Data4[7]);
519 GNUNET_SERVICE_client_drop (client);
617 return; 520 return;
618 } 521 }
619 522
@@ -640,24 +543,31 @@ get_ip_from_hostname (struct GNUNET_SERVER_Client *client,
640 if (namelen) 543 if (namelen)
641 { 544 {
642 rq->name = GNUNET_malloc ((namelen + 1) * sizeof (wchar_t)); 545 rq->name = GNUNET_malloc ((namelen + 1) * sizeof (wchar_t));
643 GNUNET_memcpy (rq->name, name, (namelen + 1) * sizeof (wchar_t)); 546 GNUNET_memcpy (rq->name,
547 name,
548 (namelen + 1) * sizeof (wchar_t));
644 rq->u8name = hostname; 549 rq->u8name = hostname;
645 } 550 }
646 551
647 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 552 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
648 "Launching a lookup for client %p with rq %p\n", 553 "Launching a lookup for client %p with rq %p\n",
649 client, rq); 554 client,
650 555 rq);
651 rq->lookup_request = GNUNET_GNS_lookup (gns, hostname, &gns_master_pubkey, 556 rq->lookup_request = GNUNET_GNS_lookup (gns,
652 rtype, GNUNET_NO /* Use DHT */, &gns_short_privkey, &process_lookup_result, 557 hostname,
653 rq); 558 &gns_master_pubkey,
654 559 rtype,
560 GNUNET_NO /* Use DHT */,
561 &process_lookup_result,
562 rq);
655 if (NULL != rq->lookup_request) 563 if (NULL != rq->lookup_request)
656 { 564 {
657 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 565 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
658 "Lookup launched, waiting for a reply\n"); 566 "Lookup launched, waiting for a reply\n");
659 GNUNET_SERVER_receive_done (client, GNUNET_OK); 567 GNUNET_SERVICE_client_continue (client);
660 GNUNET_CONTAINER_DLL_insert (rq_head, rq_tail, rq); 568 GNUNET_CONTAINER_DLL_insert (rq_head,
569 rq_tail,
570 rq);
661 } 571 }
662 else 572 else
663 { 573 {
@@ -667,110 +577,105 @@ get_ip_from_hostname (struct GNUNET_SERVER_Client *client,
667 if (rq->u8name) 577 if (rq->u8name)
668 free (rq->u8name); 578 free (rq->u8name);
669 GNUNET_free (rq); 579 GNUNET_free (rq);
670 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); 580 GNUNET_SERVICE_client_drop (client);
671 } 581 }
672} 582}
673 583
674 584
675/** 585/**
676 * Handle GET-message. 586 * Check GET-message.
677 * 587 *
678 * @param cls closure 588 * @param cls identification of the client
679 * @param client identification of the client 589 * @param msg the actual message
680 * @param message the actual message 590 * @return #GNUNET_OK if @a msg is well-formed
681 */ 591 */
682static void 592static int
683handle_get (void *cls, struct GNUNET_SERVER_Client *client, 593check_get (void *cls,
684 const struct GNUNET_MessageHeader *message) 594 const struct GNUNET_W32RESOLVER_GetMessage *msg)
685{ 595{
686 uint16_t msize;
687 const struct GNUNET_W32RESOLVER_GetMessage *msg;
688 GUID sc;
689 uint16_t size; 596 uint16_t size;
690 int i;
691 const wchar_t *hostname; 597 const wchar_t *hostname;
692 int af;
693
694 if (!got_egos)
695 {
696 /*
697 * FIXME: be done with GNUNET_OK, put the get request into a queue?
698 * or postpone GNUNET_SERVER_add_handlers() until egos are obtained?
699 */
700 GNUNET_SERVER_receive_done (client, GNUNET_NO);
701 return;
702 }
703 598
704 msize = ntohs (message->size); 599 if (! got_egos)
705 if (msize <= sizeof (struct GNUNET_W32RESOLVER_GetMessage))
706 { 600 {
707 GNUNET_break (0); 601 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
708 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); 602 _("Not ready to process requests, lacking ego data\n"));
709 return; 603 return GNUNET_SYSERR;
710 } 604 }
711 msg = (const struct GNUNET_W32RESOLVER_GetMessage *) message; 605 size = ntohs (msg->header.size) - sizeof (struct GNUNET_W32RESOLVER_GetMessage);
712 size = msize - sizeof (struct GNUNET_W32RESOLVER_GetMessage);
713 af = ntohl (msg->af);
714 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
715 "Got NBO GUID: %08X-%04X-%04X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X\n",
716 msg->sc_data1, msg->sc_data2, msg->sc_data3, msg->sc_data4[0], msg->sc_data4[1],
717 msg->sc_data4[2], msg->sc_data4[3], msg->sc_data4[4], msg->sc_data4[5],
718 msg->sc_data4[6], msg->sc_data4[7]);
719 sc.Data1 = ntohl (msg->sc_data1);
720 sc.Data2 = ntohs (msg->sc_data2);
721 sc.Data3 = ntohs (msg->sc_data3);
722 for (i = 0; i < 8; i++)
723 sc.Data4[i] = msg->sc_data4[i];
724 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
725 "Got GUID: %08X-%04X-%04X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X\n",
726 sc.Data1, sc.Data2, sc.Data3, sc.Data4[0], sc.Data4[1], sc.Data4[2],
727 sc.Data4[3], sc.Data4[4], sc.Data4[5], sc.Data4[6], sc.Data4[7]);
728
729 hostname = (const wchar_t *) &msg[1]; 606 hostname = (const wchar_t *) &msg[1];
730 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "name of %u bytes (last word is 0x%0X): %*S\n",
731 size, hostname[size / 2 - 2], size / 2, hostname);
732 if (hostname[size / 2 - 1] != L'\0') 607 if (hostname[size / 2 - 1] != L'\0')
733 { 608 {
734 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "name of length %u, not 0-terminated (%d-th word is 0x%0X): %*S\n",
735 size, size / 2 - 1, hostname[size / 2 - 1], size, hostname);
736 GNUNET_break (0); 609 GNUNET_break (0);
737 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); 610 return GNUNET_SYSERR;
738 return;
739 } 611 }
740 get_ip_from_hostname (client, hostname, af, sc); 612 return GNUNET_OK;
741} 613}
742 614
743 615
744/** 616/**
745 * Method called to with the ego we are to use for shortening 617 * Handle GET-message.
746 * during the lookup.
747 * 618 *
748 * @param cls closure (NULL, unused) 619 * @param cls identification of the client
749 * @param ego ego handle, NULL if not found 620 * @param msg the actual message
750 * @param ctx context for application to store data for this ego
751 * (during the lifetime of this process, initially NULL)
752 * @param name name assigned by the user for this ego,
753 * NULL if the user just deleted the ego and it
754 * must thus no longer be used
755 */ 621 */
756static void 622static void
757identity_shorten_cb (void *cls, 623handle_get (void *cls,
758 struct GNUNET_IDENTITY_Ego *ego, 624 const struct GNUNET_W32RESOLVER_GetMessage *msg)
759 void **ctx,
760 const char *name)
761{ 625{
762 id_op = NULL; 626 struct GNUNET_SERVICE_Client *client = cls;
763 if (NULL == ego) 627 GUID sc;
764 { 628 uint16_t size;
765 fprintf (stderr, 629 const wchar_t *hostname;
766 _("Ego for `gns-short' not found. This is not really fatal, but i'll pretend that it is and refuse to perform a lookup. Did you run gnunet-gns-import.sh?\n")); 630 int af;
767 GNUNET_SCHEDULER_shutdown (); 631
768 return; 632 size = ntohs (msg->header.size) - sizeof (struct GNUNET_W32RESOLVER_GetMessage);
769 } 633 af = ntohl (msg->af);
770 gns_short_privkey = *GNUNET_IDENTITY_ego_get_private_key (ego); 634 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
771 got_egos = 1; 635 "Got NBO GUID: %08X-%04X-%04X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X\n",
636 msg->sc_data1,
637 msg->sc_data2,
638 msg->sc_data3,
639 msg->sc_data4[0],
640 msg->sc_data4[1],
641 msg->sc_data4[2],
642 msg->sc_data4[3],
643 msg->sc_data4[4],
644 msg->sc_data4[5],
645 msg->sc_data4[6],
646 msg->sc_data4[7]);
647 sc.Data1 = ntohl (msg->sc_data1);
648 sc.Data2 = ntohs (msg->sc_data2);
649 sc.Data3 = ntohs (msg->sc_data3);
650 for (int i = 0; i < 8; i++)
651 sc.Data4[i] = msg->sc_data4[i];
652 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
653 "Got GUID: %08lX-%04X-%04X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X\n",
654 sc.Data1,
655 sc.Data2,
656 sc.Data3,
657 sc.Data4[0],
658 sc.Data4[1],
659 sc.Data4[2],
660 sc.Data4[3],
661 sc.Data4[4],
662 sc.Data4[5],
663 sc.Data4[6],
664 sc.Data4[7]);
665 hostname = (const wchar_t *) &msg[1];
666 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
667 "Name of %u bytes (last word is 0x%0X): %*S\n",
668 size,
669 hostname[size / 2 - 2],
670 size / 2,
671 hostname);
672 get_ip_from_hostname (client,
673 hostname,
674 af,
675 sc);
772} 676}
773 677
678
774/** 679/**
775 * Method called to with the ego we are to use for the lookup, 680 * Method called to with the ego we are to use for the lookup,
776 * when the ego is the one for the default master zone. 681 * when the ego is the one for the default master zone.
@@ -785,22 +690,21 @@ identity_shorten_cb (void *cls,
785 */ 690 */
786static void 691static void
787identity_master_cb (void *cls, 692identity_master_cb (void *cls,
788 struct GNUNET_IDENTITY_Ego *ego, 693 struct GNUNET_IDENTITY_Ego *ego,
789 void **ctx, 694 void **ctx,
790 const char *name) 695 const char *name)
791{ 696{
792 id_op = NULL; 697 id_op = NULL;
793 if (NULL == ego) 698 if (NULL == ego)
794 { 699 {
795 fprintf (stderr, 700 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
796 _("Ego for `gns-master' not found, cannot perform lookup. Did you run gnunet-gns-import.sh?\n")); 701 _("Ego for `gns-master' not found, cannot perform lookup. Did you run gnunet-gns-import.sh?\n"));
797 GNUNET_SCHEDULER_shutdown (); 702 GNUNET_SCHEDULER_shutdown ();
798 return; 703 return;
799 } 704 }
800 GNUNET_IDENTITY_ego_get_public_key (ego, &gns_master_pubkey); 705 GNUNET_IDENTITY_ego_get_public_key (ego,
801 id_op = GNUNET_IDENTITY_get (identity, "gns-short", &identity_shorten_cb, 706 &gns_master_pubkey);
802 NULL); 707 got_egos = 1;
803 GNUNET_assert (NULL != id_op);
804} 708}
805 709
806 710
@@ -808,59 +712,90 @@ identity_master_cb (void *cls,
808 * Start up gns-helper-w32 service. 712 * Start up gns-helper-w32 service.
809 * 713 *
810 * @param cls closure 714 * @param cls closure
811 * @param server the initialized server
812 * @param cfg configuration to use 715 * @param cfg configuration to use
716 * @param service the initialized service
813 */ 717 */
814static void 718static void
815run (void *cls, struct GNUNET_SERVER_Handle *server, 719run (void *cls,
816 const struct GNUNET_CONFIGURATION_Handle *cfg) 720 const struct GNUNET_CONFIGURATION_Handle *cfg,
721 struct GNUNET_SERVICE_Handle *service)
817{ 722{
818 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
819 {&handle_get, NULL, GNUNET_MESSAGE_TYPE_W32RESOLVER_REQUEST, 0},
820 {NULL, NULL, 0, 0}
821 };
822
823 gns = GNUNET_GNS_connect (cfg); 723 gns = GNUNET_GNS_connect (cfg);
824 if (NULL == gns) 724 if (NULL == gns)
825 { 725 {
826 fprintf (stderr, _("Failed to connect to GNS\n")); 726 fprintf (stderr,
727 _("Failed to connect to GNS\n"));
827 GNUNET_SCHEDULER_shutdown (); 728 GNUNET_SCHEDULER_shutdown ();
828 return; 729 return;
829 } 730 }
830 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, 731 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
831 NULL); 732 NULL);
832 733 identity = GNUNET_IDENTITY_connect (cfg,
833 identity = GNUNET_IDENTITY_connect (cfg, NULL, NULL); 734 NULL,
735 NULL);
834 if (NULL == identity) 736 if (NULL == identity)
835 { 737 {
836 fprintf (stderr, _("Failed to connect to identity service\n")); 738 fprintf (stderr,
739 _("Failed to connect to identity service\n"));
837 GNUNET_SCHEDULER_shutdown (); 740 GNUNET_SCHEDULER_shutdown ();
838 return; 741 return;
839 } 742 }
840 743 id_op = GNUNET_IDENTITY_get (identity,
841 id_op = GNUNET_IDENTITY_get (identity, "gns-master", &identity_master_cb, 744 "gns-master",
842 NULL); 745 &identity_master_cb,
746 NULL);
843 GNUNET_assert (NULL != id_op); 747 GNUNET_assert (NULL != id_op);
844
845 GNUNET_SERVER_add_handlers (server, handlers);
846} 748}
847 749
848 750
849/** 751/**
850 * The main function for gns-helper-w32. 752 * Handle client connecting to the service.
851 * 753 *
852 * @param argc number of arguments from the command line 754 * @param cls NULL
853 * @param argv command line arguments 755 * @param client the new client
854 * @return 0 ok, 1 on error 756 * @param mq the message queue of @a client
757 * @return @a client
855 */ 758 */
856int 759static void *
857main (int argc, char *const *argv) 760client_connect_cb (void *cls,
761 struct GNUNET_SERVICE_Client *client,
762 struct GNUNET_MQ_Handle *mq)
858{ 763{
859 int ret; 764 return client;
765}
860 766
861 ret = GNUNET_SERVICE_run (argc, argv, "gns-helper-service-w32", 767
862 GNUNET_SERVICE_OPTION_NONE, &run, NULL); 768/**
863 return (GNUNET_OK == ret) ? 0 : 1; 769 * Callback called when a client disconnected from the service
770 *
771 * @param cls closure for the service
772 * @param c the client that disconnected
773 * @param internal_cls should be equal to @a c
774 */
775static void
776client_disconnect_cb (void *cls,
777 struct GNUNET_SERVICE_Client *client,
778 void *internal_cls)
779{
780 GNUNET_assert (internal_cls == client);
864} 781}
865 782
783
784/**
785 * Define "main" method using service macro.
786 */
787GNUNET_SERVICE_MAIN
788("gns-helper-service-w32",
789 GNUNET_SERVICE_OPTION_NONE,
790 &run,
791 &client_connect_cb,
792 &client_disconnect_cb,
793 NULL,
794 GNUNET_MQ_hd_var_size (get,
795 GNUNET_MESSAGE_TYPE_W32RESOLVER_REQUEST,
796 struct GNUNET_W32RESOLVER_GetMessage,
797 NULL),
798 GNUNET_MQ_handler_end());
799
800
866/* end of gnunet-gns-helper-service-w32.c */ 801/* end of gnunet-gns-helper-service-w32.c */
diff --git a/src/gns/gnunet-gns-import.c b/src/gns/gnunet-gns-import.c
index e98babfa8..49f6e495f 100644
--- a/src/gns/gnunet-gns-import.c
+++ b/src/gns/gnunet-gns-import.c
@@ -224,45 +224,52 @@ zone_iterator (void *cls,
224 else if (0 == strcmp (rname, "pin")) 224 else if (0 == strcmp (rname, "pin"))
225 check_pkey (rd_len, rd, pin_zone_pkey, &found_pin_rec); 225 check_pkey (rd_len, rd, pin_zone_pkey, &found_pin_rec);
226 } 226 }
227 if (NULL == rname && 0 == rd_len && NULL == rd) 227 GNUNET_NAMESTORE_zone_iterator_next (list_it);
228}
229
230static void
231zone_iteration_error (void *cls)
232{
233 enum GNUNET_OS_ProcessStatusType st;
234 unsigned long code;
235 if (!found_private_rec)
228 { 236 {
229 enum GNUNET_OS_ProcessStatusType st; 237 if (0 != run_process_and_wait (GNUNET_NO, GNUNET_OS_INHERIT_STD_OUT_AND_ERR, NULL, NULL, &st, &code,
230 unsigned long code; 238 "gnunet-namestore",
231 if (!found_private_rec) 239 "gnunet-namestore", "-z", "master-zone", "-a", "-e", "never", "-n", "private", "-p", "-t", "PKEY", "-V", private_zone_pkey, NULL))
232 { 240 {
233 if (0 != run_process_and_wait (GNUNET_NO, GNUNET_OS_INHERIT_STD_OUT_AND_ERR, NULL, NULL, &st, &code, 241 ret = 8;
234 "gnunet-namestore", 242 return;
235 "gnunet-namestore", "-z", "master-zone", "-a", "-e", "never", "-n", "private", "-p", "-t", "PKEY", "-V", private_zone_pkey, NULL))
236 {
237 ret = 8;
238 return;
239 }
240 } 243 }
241 if (!found_short_rec) 244 }
245 if (!found_short_rec)
246 {
247 if (0 != run_process_and_wait (GNUNET_NO, GNUNET_OS_INHERIT_STD_OUT_AND_ERR, NULL, NULL, &st, &code,
248 "gnunet-namestore",
249 "gnunet-namestore", "-z", "master-zone", "-a", "-e", "never", "-n", "short", "-p", "-t", "PKEY", "-V", short_zone_pkey, NULL))
242 { 250 {
243 if (0 != run_process_and_wait (GNUNET_NO, GNUNET_OS_INHERIT_STD_OUT_AND_ERR, NULL, NULL, &st, &code, 251 ret = 9;
244 "gnunet-namestore", 252 return;
245 "gnunet-namestore", "-z", "master-zone", "-a", "-e", "never", "-n", "short", "-p", "-t", "PKEY", "-V", short_zone_pkey, NULL))
246 {
247 ret = 9;
248 return;
249 }
250 } 253 }
251 if (!found_pin_rec) 254 }
255 if (!found_pin_rec)
256 {
257 if (0 != run_process_and_wait (GNUNET_NO, GNUNET_OS_INHERIT_STD_OUT_AND_ERR, NULL, NULL, &st, &code,
258 "gnunet-namestore",
259 "gnunet-namestore", "-z", "master-zone", "-a", "-e", "never", "-n", "pin", "-p", "-t", "PKEY", "-V", pin_zone_pkey, NULL))
252 { 260 {
253 if (0 != run_process_and_wait (GNUNET_NO, GNUNET_OS_INHERIT_STD_OUT_AND_ERR, NULL, NULL, &st, &code, 261 ret = 10;
254 "gnunet-namestore", 262 return;
255 "gnunet-namestore", "-z", "master-zone", "-a", "-e", "never", "-n", "pin", "-p", "-t", "PKEY", "-V", pin_zone_pkey, NULL))
256 {
257 ret = 10;
258 return;
259 }
260 } 263 }
261 list_it = NULL;
262 GNUNET_SCHEDULER_shutdown ();
263 return;
264 } 264 }
265 GNUNET_NAMESTORE_zone_iterator_next (list_it); 265 list_it = NULL;
266 GNUNET_SCHEDULER_shutdown ();
267}
268
269
270static void
271zone_iteration_finished (void *cls)
272{
266} 273}
267 274
268 275
@@ -317,7 +324,7 @@ get_ego (void *cls,
317 return; 324 return;
318 } 325 }
319 list_it = GNUNET_NAMESTORE_zone_iteration_start (ns, 326 list_it = GNUNET_NAMESTORE_zone_iteration_start (ns,
320 &master_pk, &zone_iterator, NULL); 327 &master_pk, &zone_iteration_error, NULL, &zone_iterator, NULL, &zone_iteration_finished, NULL);
321 if (NULL == list_it) 328 if (NULL == list_it)
322 { 329 {
323 ret = 12; 330 ret = 12;
diff --git a/src/gns/gnunet-gns-proxy.c b/src/gns/gnunet-gns-proxy.c
index 3a38970a8..2a6de1c30 100644
--- a/src/gns/gnunet-gns-proxy.c
+++ b/src/gns/gnunet-gns-proxy.c
@@ -606,7 +606,7 @@ struct Socks5Request
606 * Headers from response 606 * Headers from response
607 */ 607 */
608 struct HttpResponseHeader *header_tail; 608 struct HttpResponseHeader *header_tail;
609 609
610 /** 610 /**
611 * SSL Certificate status 611 * SSL Certificate status
612 */ 612 */
@@ -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
@@ -695,16 +695,6 @@ static struct Socks5Request *s5r_tail;
695static struct GNUNET_CRYPTO_EcdsaPublicKey local_gns_zone; 695static struct GNUNET_CRYPTO_EcdsaPublicKey local_gns_zone;
696 696
697/** 697/**
698 * The users local shorten zone
699 */
700static struct GNUNET_CRYPTO_EcdsaPrivateKey local_shorten_zone;
701
702/**
703 * Is shortening enabled?
704 */
705static int do_shorten;
706
707/**
708 * The CA for SSL certificate generation 698 * The CA for SSL certificate generation
709 */ 699 */
710static struct ProxyCA proxy_ca; 700static struct ProxyCA proxy_ca;
@@ -873,9 +863,10 @@ check_ssl_certificate (struct Socks5Request *s5r)
873 gnutls_x509_crt_t x509_cert; 863 gnutls_x509_crt_t x509_cert;
874 int rc; 864 int rc;
875 const char *name; 865 const char *name;
876 866
877 s5r->ssl_checked = GNUNET_YES; 867 s5r->ssl_checked = GNUNET_YES;
878 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "XXXXXX\n"); 868 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
869 "Checking SSL certificate\n");
879 if (CURLE_OK != 870 if (CURLE_OK !=
880 curl_easy_getinfo (s5r->curl, 871 curl_easy_getinfo (s5r->curl,
881 CURLINFO_TLS_SESSION, 872 CURLINFO_TLS_SESSION,
@@ -1039,7 +1030,7 @@ curl_check_hdr (void *buffer, size_t size, size_t nmemb, void *cls)
1039 size_t delta_cdomain; 1030 size_t delta_cdomain;
1040 int domain_matched; 1031 int domain_matched;
1041 char *tok; 1032 char *tok;
1042 1033
1043 /* first, check SSL certificate */ 1034 /* first, check SSL certificate */
1044 if ((GNUNET_YES != s5r->ssl_checked) && 1035 if ((GNUNET_YES != s5r->ssl_checked) &&
1045 (HTTPS_PORT == s5r->port)) 1036 (HTTPS_PORT == s5r->port))
@@ -1047,7 +1038,7 @@ curl_check_hdr (void *buffer, size_t size, size_t nmemb, void *cls)
1047 if (GNUNET_OK != check_ssl_certificate (s5r)) 1038 if (GNUNET_OK != check_ssl_certificate (s5r))
1048 return 0; 1039 return 0;
1049 } 1040 }
1050 1041
1051 ndup = GNUNET_strndup (buffer, bytes); 1042 ndup = GNUNET_strndup (buffer, bytes);
1052 hdr_type = strtok (ndup, ":"); 1043 hdr_type = strtok (ndup, ":");
1053 if (NULL == hdr_type) 1044 if (NULL == hdr_type)
@@ -1287,7 +1278,7 @@ curl_upload_cb (void *buf, size_t size, size_t nmemb, void *cls)
1287 struct Socks5Request *s5r = cls; 1278 struct Socks5Request *s5r = cls;
1288 size_t len = size * nmemb; 1279 size_t len = size * nmemb;
1289 size_t to_copy; 1280 size_t to_copy;
1290 1281
1291 if ( (0 == s5r->io_len) && 1282 if ( (0 == s5r->io_len) &&
1292 (SOCKS5_SOCKET_UPLOAD_DONE != s5r->state) ) 1283 (SOCKS5_SOCKET_UPLOAD_DONE != s5r->state) )
1293 { 1284 {
@@ -1763,7 +1754,7 @@ create_response (void *cls,
1763 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1754 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1764 "Processing %u bytes UPLOAD\n", 1755 "Processing %u bytes UPLOAD\n",
1765 (unsigned int) *upload_data_size); 1756 (unsigned int) *upload_data_size);
1766 1757
1767 /* FIXME: This must be set or a header with Transfer-Encoding: chunked. Else 1758 /* FIXME: This must be set or a header with Transfer-Encoding: chunked. Else
1768 * upload callback is not called! 1759 * upload callback is not called!
1769 */ 1760 */
@@ -1892,19 +1883,22 @@ mhd_connection_cb (void *cls,
1892 { 1883 {
1893 if (GNUNET_NETWORK_get_fd (s5r->sock) == sock) 1884 if (GNUNET_NETWORK_get_fd (s5r->sock) == sock)
1894 { 1885 {
1895 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;
1896 *con_cls = s5r; 1889 *con_cls = s5r;
1897 break; 1890 break;
1898 } 1891 }
1899 } 1892 }
1900 s5r->ssl_checked = GNUNET_NO;
1901 break; 1893 break;
1902 case MHD_CONNECTION_NOTIFY_CLOSED: 1894 case MHD_CONNECTION_NOTIFY_CLOSED:
1903 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connection closed... cleaning up\n"); 1895 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1896 "Connection closed... cleaning up\n");
1904 s5r = *con_cls; 1897 s5r = *con_cls;
1905 if (NULL == s5r) 1898 if (NULL == s5r)
1906 { 1899 {
1907 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Connection stale!\n"); 1900 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1901 "Connection stale!\n");
1908 return; 1902 return;
1909 } 1903 }
1910 cleanup_s5r (s5r); 1904 cleanup_s5r (s5r);
@@ -2827,7 +2821,6 @@ do_s5r_read (void *cls)
2827 &local_gns_zone, 2821 &local_gns_zone,
2828 GNUNET_DNSPARSER_TYPE_A, 2822 GNUNET_DNSPARSER_TYPE_A,
2829 GNUNET_NO /* only cached */, 2823 GNUNET_NO /* only cached */,
2830 (GNUNET_YES == do_shorten) ? &local_shorten_zone : NULL,
2831 &handle_gns_result, 2824 &handle_gns_result,
2832 s5r); 2825 s5r);
2833 break; 2826 break;
@@ -3115,7 +3108,7 @@ run_cont ()
3115 return; 3108 return;
3116 } 3109 }
3117 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 3110 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3118 "Proxy listens on port %lu\n", 3111 "Proxy listens on port %llu\n",
3119 port); 3112 port);
3120 3113
3121 /* start MHD daemon for HTTP */ 3114 /* start MHD daemon for HTTP */
@@ -3141,46 +3134,6 @@ run_cont ()
3141 3134
3142 3135
3143/** 3136/**
3144 * Method called to inform about the egos of the shorten zone of this peer.
3145 *
3146 * When used with #GNUNET_IDENTITY_create or #GNUNET_IDENTITY_get,
3147 * this function is only called ONCE, and 'NULL' being passed in
3148 * @a ego does indicate an error (i.e. name is taken or no default
3149 * value is known). If @a ego is non-NULL and if '*ctx'
3150 * is set in those callbacks, the value WILL be passed to a subsequent
3151 * call to the identity callback of #GNUNET_IDENTITY_connect (if
3152 * that one was not NULL).
3153 *
3154 * @param cls closure, NULL
3155 * @param ego ego handle
3156 * @param ctx context for application to store data for this ego
3157 * (during the lifetime of this process, initially NULL)
3158 * @param name name assigned by the user for this ego,
3159 * NULL if the user just deleted the ego and it
3160 * must thus no longer be used
3161 */
3162static void
3163identity_shorten_cb (void *cls,
3164 struct GNUNET_IDENTITY_Ego *ego,
3165 void **ctx,
3166 const char *name)
3167{
3168 id_op = NULL;
3169 if (NULL == ego)
3170 {
3171 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3172 _("No ego configured for `shorten-zone`\n"));
3173 }
3174 else
3175 {
3176 local_shorten_zone = *GNUNET_IDENTITY_ego_get_private_key (ego);
3177 do_shorten = GNUNET_YES;
3178 }
3179 run_cont ();
3180}
3181
3182
3183/**
3184 * Method called to inform about the egos of the master zone of this peer. 3137 * Method called to inform about the egos of the master zone of this peer.
3185 * 3138 *
3186 * When used with #GNUNET_IDENTITY_create or #GNUNET_IDENTITY_get, 3139 * When used with #GNUNET_IDENTITY_create or #GNUNET_IDENTITY_get,
@@ -3216,10 +3169,7 @@ identity_master_cb (void *cls,
3216 } 3169 }
3217 GNUNET_IDENTITY_ego_get_public_key (ego, 3170 GNUNET_IDENTITY_ego_get_public_key (ego,
3218 &local_gns_zone); 3171 &local_gns_zone);
3219 id_op = GNUNET_IDENTITY_get (identity, 3172 run_cont ();
3220 "gns-short",
3221 &identity_shorten_cb,
3222 NULL);
3223} 3173}
3224 3174
3225 3175
@@ -3232,7 +3182,9 @@ identity_master_cb (void *cls,
3232 * @param c configuration 3182 * @param c configuration
3233 */ 3183 */
3234static void 3184static void
3235run (void *cls, char *const *args, const char *cfgfile, 3185run (void *cls,
3186 char *const *args,
3187 const char *cfgfile,
3236 const struct GNUNET_CONFIGURATION_Handle *c) 3188 const struct GNUNET_CONFIGURATION_Handle *c)
3237{ 3189{
3238 char* cafile_cfg = NULL; 3190 char* cafile_cfg = NULL;
@@ -3309,13 +3261,20 @@ run (void *cls, char *const *args, const char *cfgfile,
3309int 3261int
3310main (int argc, char *const *argv) 3262main (int argc, char *const *argv)
3311{ 3263{
3312 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 3264 struct GNUNET_GETOPT_CommandLineOption options[] = {
3313 {'p', "port", NULL, 3265
3314 gettext_noop ("listen on specified port (default: 7777)"), 1, 3266 GNUNET_GETOPT_option_ulong ('p',
3315 &GNUNET_GETOPT_set_ulong, &port}, 3267 "port",
3316 {'a', "authority", NULL, 3268 NULL,
3317 gettext_noop ("pem file to use as CA"), 1, 3269 gettext_noop ("listen on specified port (default: 7777)"),
3318 &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
3319 GNUNET_GETOPT_OPTION_END 3278 GNUNET_GETOPT_OPTION_END
3320 }; 3279 };
3321 static const char* page = 3280 static const char* page =
@@ -3323,22 +3282,26 @@ main (int argc, char *const *argv)
3323 "</head><body>cURL fail</body></html>"; 3282 "</head><body>cURL fail</body></html>";
3324 int ret; 3283 int ret;
3325 3284
3326 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) 3285 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv,
3286 &argc, &argv))
3327 return 2; 3287 return 2;
3328 GNUNET_log_setup ("gnunet-gns-proxy", "WARNING", NULL); 3288 GNUNET_log_setup ("gnunet-gns-proxy",
3329 curl_failure_response = MHD_create_response_from_buffer (strlen (page), 3289 "WARNING",
3330 (void*)page, 3290 NULL);
3331 MHD_RESPMEM_PERSISTENT); 3291 curl_failure_response
3292 = MHD_create_response_from_buffer (strlen (page),
3293 (void *) page,
3294 MHD_RESPMEM_PERSISTENT);
3332 3295
3333 ret = 3296 ret =
3334 (GNUNET_OK == 3297 (GNUNET_OK ==
3335 GNUNET_PROGRAM_run (argc, argv, "gnunet-gns-proxy", 3298 GNUNET_PROGRAM_run (argc, argv,
3299 "gnunet-gns-proxy",
3336 _("GNUnet GNS proxy"), 3300 _("GNUnet GNS proxy"),
3337 options, 3301 options,
3338 &run, NULL)) ? 0 : 1; 3302 &run, NULL)) ? 0 : 1;
3339 MHD_destroy_response (curl_failure_response); 3303 MHD_destroy_response (curl_failure_response);
3340 GNUNET_free_non_null ((char *) argv); 3304 GNUNET_free_non_null ((char *) argv);
3341 GNUNET_CRYPTO_ecdsa_key_clear (&local_shorten_zone);
3342 return ret; 3305 return ret;
3343} 3306}
3344 3307
diff --git a/src/gns/gnunet-gns.c b/src/gns/gnunet-gns.c
index 17fe4cbda..c0de0f30c 100644
--- a/src/gns/gnunet-gns.c
+++ b/src/gns/gnunet-gns.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-2013 GNUnet e.V. 3 Copyright (C) 2012-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
@@ -66,16 +66,6 @@ static char *zone_ego_name;
66static char *public_key; 66static char *public_key;
67 67
68/** 68/**
69 * Reverse key
70 */
71static char *reverse_key;
72
73/**
74 * Reverse key
75 */
76static struct GNUNET_CRYPTO_EcdsaPublicKey rkey;
77
78/**
79 * Set to GNUNET_GNS_LO_LOCAL_MASTER if we are looking up in the master zone. 69 * Set to GNUNET_GNS_LO_LOCAL_MASTER if we are looking up in the master zone.
80 */ 70 */
81static enum GNUNET_GNS_LocalOptions local_options; 71static enum GNUNET_GNS_LocalOptions local_options;
@@ -96,11 +86,6 @@ static int rtype;
96static struct GNUNET_GNS_LookupRequest *lookup_request; 86static struct GNUNET_GNS_LookupRequest *lookup_request;
97 87
98/** 88/**
99 * Handle to reverse lookup request
100 */
101static struct GNUNET_GNS_ReverseLookupRequest *rev_lookup_request;
102
103/**
104 * Lookup an ego with the identity service. 89 * Lookup an ego with the identity service.
105 */ 90 */
106static struct GNUNET_IDENTITY_EgoLookup *el; 91static struct GNUNET_IDENTITY_EgoLookup *el;
@@ -174,24 +159,6 @@ do_timeout (void *cls)
174 GNUNET_SCHEDULER_shutdown (); 159 GNUNET_SCHEDULER_shutdown ();
175} 160}
176 161
177static void
178process_reverse_result (void *cls,
179 const char *name)
180{
181 rev_lookup_request = NULL;
182 if (NULL == name)
183 {
184 printf ("No name found.\n");
185 return;
186 }
187 if (raw)
188 printf ("%s\n", name);
189 else
190 printf ("%s is known as %s\n",
191 reverse_key,
192 name);
193 GNUNET_SCHEDULER_shutdown ();
194}
195 162
196/** 163/**
197 * Function called with the result of a GNS lookup. 164 * Function called with the result of a GNS lookup.
@@ -201,7 +168,8 @@ process_reverse_result (void *cls,
201 * @param rd array of @a rd_count records with the results 168 * @param rd array of @a rd_count records with the results
202 */ 169 */
203static void 170static void
204process_lookup_result (void *cls, uint32_t rd_count, 171process_lookup_result (void *cls,
172 uint32_t rd_count,
205 const struct GNUNET_GNSRECORD_Data *rd) 173 const struct GNUNET_GNSRECORD_Data *rd)
206{ 174{
207 const char *name = cls; 175 const char *name = cls;
@@ -253,11 +221,9 @@ process_lookup_result (void *cls, uint32_t rd_count,
253 * identified by the given public key and the shorten zone. 221 * identified by the given public key and the shorten zone.
254 * 222 *
255 * @param pkey public key to use for the zone, can be NULL 223 * @param pkey public key to use for the zone, can be NULL
256 * @param shorten_key private key used for shortening, can be NULL
257 */ 224 */
258static void 225static void
259lookup_with_keys (const struct GNUNET_CRYPTO_EcdsaPublicKey *pkey, 226lookup_with_public_key (const struct GNUNET_CRYPTO_EcdsaPublicKey *pkey)
260 const struct GNUNET_CRYPTO_EcdsaPrivateKey *shorten_key)
261{ 227{
262 if (NULL != lookup_type) 228 if (NULL != lookup_type)
263 rtype = GNUNET_GNSRECORD_typename_to_number (lookup_type); 229 rtype = GNUNET_GNSRECORD_typename_to_number (lookup_type);
@@ -277,18 +243,9 @@ lookup_with_keys (const struct GNUNET_CRYPTO_EcdsaPublicKey *pkey,
277 pkey, 243 pkey,
278 rtype, 244 rtype,
279 local_options, 245 local_options,
280 shorten_key,
281 &process_lookup_result, 246 &process_lookup_result,
282 lookup_name); 247 lookup_name);
283 } 248 }
284 else if (NULL != reverse_key)
285 {
286 rev_lookup_request = GNUNET_GNS_reverse_lookup (gns,
287 &rkey,
288 pkey,
289 &process_reverse_result,
290 NULL);
291 }
292 else 249 else
293 { 250 {
294 fprintf (stderr, 251 fprintf (stderr,
@@ -300,63 +257,6 @@ lookup_with_keys (const struct GNUNET_CRYPTO_EcdsaPublicKey *pkey,
300 257
301 258
302/** 259/**
303 * Method called to with the ego we are to use for shortening
304 * during the lookup.
305 *
306 * @param cls closure contains the public key to use
307 * @param ego ego handle, NULL if not found
308 * @param ctx context for application to store data for this ego
309 * (during the lifetime of this process, initially NULL)
310 * @param name name assigned by the user for this ego,
311 * NULL if the user just deleted the ego and it
312 * must thus no longer be used
313 */
314static void
315identity_shorten_cb (void *cls,
316 struct GNUNET_IDENTITY_Ego *ego,
317 void **ctx,
318 const char *name)
319{
320 struct GNUNET_CRYPTO_EcdsaPublicKey *pkeym = cls;
321
322 id_op = NULL;
323 if (NULL == ego)
324 lookup_with_keys (pkeym, NULL);
325 else
326 lookup_with_keys (pkeym,
327 GNUNET_IDENTITY_ego_get_private_key (ego));
328 GNUNET_free (pkeym);
329}
330
331
332/**
333 * Perform the actual resolution, starting with the zone
334 * identified by the given public key.
335 *
336 * @param pkey public key to use for the zone
337 */
338static void
339lookup_with_public_key (const struct GNUNET_CRYPTO_EcdsaPublicKey *pkey)
340{
341 struct GNUNET_CRYPTO_EcdsaPublicKey *pkeym;
342
343 GNUNET_assert (NULL != pkey);
344 pkeym = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPublicKey);
345 *pkeym = *pkey;
346 GNUNET_break (NULL == id_op);
347 id_op = GNUNET_IDENTITY_get (identity,
348 "gns-short",
349 &identity_shorten_cb,
350 pkeym);
351 if (NULL == id_op)
352 {
353 GNUNET_break (0);
354 lookup_with_keys (pkey, NULL);
355 }
356}
357
358
359/**
360 * Method called to with the ego we are to use for the lookup, 260 * Method called to with the ego we are to use for the lookup,
361 * when the ego is determined by a name. 261 * when the ego is determined by a name.
362 * 262 *
@@ -449,7 +349,6 @@ run (void *cls,
449 349
450 cfg = c; 350 cfg = c;
451 gns = GNUNET_GNS_connect (cfg); 351 gns = GNUNET_GNS_connect (cfg);
452 identity = GNUNET_IDENTITY_connect (cfg, NULL, NULL);
453 if (NULL == gns) 352 if (NULL == gns)
454 { 353 {
455 fprintf (stderr, 354 fprintf (stderr,
@@ -457,22 +356,13 @@ run (void *cls,
457 return; 356 return;
458 } 357 }
459 tt = GNUNET_SCHEDULER_add_delayed (timeout, 358 tt = GNUNET_SCHEDULER_add_delayed (timeout,
460 &do_timeout, NULL); 359 &do_timeout,
461 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL); 360 NULL);
462 if (NULL != reverse_key) 361 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
463 { 362 NULL);
464 if (GNUNET_OK != 363 identity = GNUNET_IDENTITY_connect (cfg,
465 GNUNET_CRYPTO_ecdsa_public_key_from_string (reverse_key, 364 NULL,
466 strlen (reverse_key), 365 NULL);
467 &rkey))
468 {
469 fprintf (stderr,
470 _("Reverse key `%s' is not well-formed\n"),
471 reverse_key);
472 GNUNET_SCHEDULER_shutdown ();
473 return;
474 }
475 }
476 if (NULL != public_key) 366 if (NULL != public_key)
477 { 367 {
478 if (GNUNET_OK != 368 if (GNUNET_OK !=
@@ -489,20 +379,6 @@ run (void *cls,
489 lookup_with_public_key (&pkey); 379 lookup_with_public_key (&pkey);
490 return; 380 return;
491 } 381 }
492 if (NULL != reverse_key)
493 {
494 if (GNUNET_OK !=
495 GNUNET_CRYPTO_ecdsa_public_key_from_string (reverse_key,
496 strlen (reverse_key),
497 &rkey))
498 {
499 fprintf (stderr,
500 _("Reverse key `%s' is not well-formed\n"),
501 reverse_key);
502 GNUNET_SCHEDULER_shutdown ();
503 return;
504 }
505 }
506 if (NULL != zone_ego_name) 382 if (NULL != zone_ego_name)
507 { 383 {
508 el = GNUNET_IDENTITY_ego_lookup (cfg, 384 el = GNUNET_IDENTITY_ego_lookup (cfg,
@@ -541,42 +417,62 @@ run (void *cls,
541 * @return 0 ok, 1 on error 417 * @return 0 ok, 1 on error
542 */ 418 */
543int 419int
544main (int argc, char *const *argv) 420main (int argc,
421 char *const *argv)
545{ 422{
546 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 423 struct GNUNET_GETOPT_CommandLineOption options[] = {
547 {'u', "lookup", "NAME", 424
548 gettext_noop ("Lookup a record for the given name"), 1, 425 GNUNET_GETOPT_option_string ('u',
549 &GNUNET_GETOPT_set_string, &lookup_name}, 426 "lookup",
550 {'t', "type", "TYPE", 427 "NAME",
551 gettext_noop ("Specify the type of the record to lookup"), 1, 428 gettext_noop ("Lookup a record for the given name"),
552 &GNUNET_GETOPT_set_string, &lookup_type}, 429 &lookup_name),
553 { 'T', "timeout", "DELAY", 430
554 gettext_noop ("Specify timeout for the lookup"), 1, 431 GNUNET_GETOPT_option_string ('t',
555 &GNUNET_GETOPT_set_relative_time, &timeout }, 432 "type",
556 {'r', "raw", NULL, 433 "TYPE",
557 gettext_noop ("No unneeded output"), 0, 434 gettext_noop ("Specify the type of the record to lookup"),
558 &GNUNET_GETOPT_set_one, &raw}, 435 &lookup_type),
559 {'p', "public-key", "PKEY", 436
560 gettext_noop ("Specify the public key of the zone to lookup the record in"), 1, 437 GNUNET_GETOPT_option_relative_time ('T',
561 &GNUNET_GETOPT_set_string, &public_key}, 438 "timeout",
562 {'z', "zone", "NAME", 439 "DELAY",
563 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"),
564 &GNUNET_GETOPT_set_string, &zone_ego_name}, 441 &timeout),
565 {'R', "reverse", "PKEY", 442
566 gettext_noop ("Specify the public key of the zone to reverse lookup a name for"), 1, 443 GNUNET_GETOPT_option_flag ('r',
567 &GNUNET_GETOPT_set_string, &reverse_key}, 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
568 GNUNET_GETOPT_OPTION_END 460 GNUNET_GETOPT_OPTION_END
569 }; 461 };
570 int ret; 462 int ret;
571 463
572 timeout = GNUNET_TIME_UNIT_FOREVER_REL; 464 timeout = GNUNET_TIME_UNIT_FOREVER_REL;
573 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) 465 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv,
466 &argc, &argv))
574 return 2; 467 return 2;
575 468
576 GNUNET_log_setup ("gnunet-gns", "WARNING", NULL); 469 GNUNET_log_setup ("gnunet-gns",
470 "WARNING",
471 NULL);
577 ret = 472 ret =
578 (GNUNET_OK == 473 (GNUNET_OK ==
579 GNUNET_PROGRAM_run (argc, argv, "gnunet-gns", 474 GNUNET_PROGRAM_run (argc, argv,
475 "gnunet-gns",
580 _("GNUnet GNS resolver tool"), 476 _("GNUnet GNS resolver tool"),
581 options, 477 options,
582 &run, NULL)) ? 0 : 1; 478 &run, NULL)) ? 0 : 1;
diff --git a/src/gns/gnunet-service-gns.c b/src/gns/gnunet-service-gns.c
index cec31ff48..0ca25ac19 100644
--- a/src/gns/gnunet-service-gns.c
+++ b/src/gns/gnunet-service-gns.c
@@ -29,14 +29,11 @@
29#include "gnunet_dnsparser_lib.h" 29#include "gnunet_dnsparser_lib.h"
30#include "gnunet_dht_service.h" 30#include "gnunet_dht_service.h"
31#include "gnunet_namecache_service.h" 31#include "gnunet_namecache_service.h"
32#include "gnunet_namestore_service.h"
33#include "gnunet_identity_service.h" 32#include "gnunet_identity_service.h"
34#include "gnunet_gns_service.h" 33#include "gnunet_gns_service.h"
35#include "gnunet_statistics_service.h" 34#include "gnunet_statistics_service.h"
36#include "gns.h" 35#include "gns.h"
37#include "gnunet-service-gns_resolver.h" 36#include "gnunet-service-gns_resolver.h"
38#include "gnunet-service-gns_reverser.h"
39#include "gnunet-service-gns_shorten.h"
40#include "gnunet-service-gns_interceptor.h" 37#include "gnunet-service-gns_interceptor.h"
41#include "gnunet_protocols.h" 38#include "gnunet_protocols.h"
42 39
@@ -61,7 +58,7 @@ struct ClientLookupHandle
61 * We keep these in a DLL. 58 * We keep these in a DLL.
62 */ 59 */
63 struct ClientLookupHandle *prev; 60 struct ClientLookupHandle *prev;
64 61
65 /** 62 /**
66 * Client handle 63 * Client handle
67 */ 64 */
@@ -73,11 +70,6 @@ struct ClientLookupHandle
73 struct GNS_ResolverHandle *lookup; 70 struct GNS_ResolverHandle *lookup;
74 71
75 /** 72 /**
76 * Active handle for a reverse lookup
77 */
78 struct GNS_ReverserHandle *rev_lookup;
79
80 /**
81 * request id 73 * request id
82 */ 74 */
83 uint32_t request_id; 75 uint32_t request_id;
@@ -119,11 +111,6 @@ static struct GNUNET_DHT_Handle *dht_handle;
119static struct GNUNET_NAMECACHE_Handle *namecache_handle; 111static struct GNUNET_NAMECACHE_Handle *namecache_handle;
120 112
121/** 113/**
122 * Our handle to the namestore service
123 */
124static struct GNUNET_NAMESTORE_Handle *namestore_handle;
125
126/**
127 * Our handle to the identity service 114 * Our handle to the identity service
128 */ 115 */
129static struct GNUNET_IDENTITY_Handle *identity_handle; 116static struct GNUNET_IDENTITY_Handle *identity_handle;
@@ -173,19 +160,12 @@ shutdown_task (void *cls)
173 identity_handle = NULL; 160 identity_handle = NULL;
174 } 161 }
175 GNS_resolver_done (); 162 GNS_resolver_done ();
176 GNS_reverse_done ();
177 GNS_shorten_done ();
178 if (NULL != statistics) 163 if (NULL != statistics)
179 { 164 {
180 GNUNET_STATISTICS_destroy (statistics, 165 GNUNET_STATISTICS_destroy (statistics,
181 GNUNET_NO); 166 GNUNET_NO);
182 statistics = NULL; 167 statistics = NULL;
183 } 168 }
184 if (NULL != namestore_handle)
185 {
186 GNUNET_NAMESTORE_disconnect (namestore_handle);
187 namestore_handle = NULL;
188 }
189 if (NULL != namecache_handle) 169 if (NULL != namecache_handle)
190 { 170 {
191 GNUNET_NAMECACHE_disconnect (namecache_handle); 171 GNUNET_NAMECACHE_disconnect (namecache_handle);
@@ -221,15 +201,13 @@ client_disconnect_cb (void *cls,
221 { 201 {
222 if (NULL != clh->lookup) 202 if (NULL != clh->lookup)
223 GNS_resolver_lookup_cancel (clh->lookup); 203 GNS_resolver_lookup_cancel (clh->lookup);
224 if (NULL != clh->rev_lookup)
225 GNS_reverse_lookup_cancel (clh->rev_lookup);
226 GNUNET_CONTAINER_DLL_remove (gc->clh_head, 204 GNUNET_CONTAINER_DLL_remove (gc->clh_head,
227 gc->clh_tail, 205 gc->clh_tail,
228 clh); 206 clh);
229 GNUNET_free (clh); 207 GNUNET_free (clh);
230 } 208 }
231 209
232 GNUNET_free (gc); 210 GNUNET_free (gc);
233} 211}
234 212
235 213
@@ -288,7 +266,9 @@ send_lookup_response (void* cls,
288 (char*) &rmsg[1]); 266 (char*) &rmsg[1]);
289 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq(clh->gc->client), 267 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq(clh->gc->client),
290 env); 268 env);
291 GNUNET_CONTAINER_DLL_remove (clh->gc->clh_head, clh->gc->clh_tail, clh); 269 GNUNET_CONTAINER_DLL_remove (clh->gc->clh_head,
270 clh->gc->clh_tail,
271 clh);
292 GNUNET_free (clh); 272 GNUNET_free (clh);
293 GNUNET_STATISTICS_update (statistics, 273 GNUNET_STATISTICS_update (statistics,
294 "Completed lookups", 1, 274 "Completed lookups", 1,
@@ -299,47 +279,6 @@ send_lookup_response (void* cls,
299 GNUNET_NO); 279 GNUNET_NO);
300} 280}
301 281
302/**
303 * Reply to client with the result from our reverse lookup.
304 *
305 * @param cls the closure (our client lookup handle)
306 * @param rd_count the number of records in @a rd
307 * @param rd the record data
308 */
309static void
310send_reverse_lookup_response (void* cls,
311 const char *name)
312{
313 struct ClientLookupHandle *clh = cls;
314 struct GNUNET_MQ_Envelope *env;
315 struct ReverseLookupResultMessage *rmsg;
316 size_t len;
317
318 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
319 "Sending LOOKUP_RESULT message with %s\n",
320 name);
321
322 if (NULL == name)
323 len = 1;
324 else
325 len = strlen (name) + 1;
326 env = GNUNET_MQ_msg_extra (rmsg,
327 len,
328 GNUNET_MESSAGE_TYPE_GNS_REVERSE_LOOKUP_RESULT);
329 rmsg->id = clh->request_id;
330 if (1 < len)
331 GNUNET_memcpy ((char*) &rmsg[1],
332 name,
333 strlen (name));
334 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq(clh->gc->client),
335 env);
336 GNUNET_CONTAINER_DLL_remove (clh->gc->clh_head, clh->gc->clh_tail, clh);
337 GNUNET_free (clh);
338 GNUNET_STATISTICS_update (statistics,
339 "Completed reverse lookups", 1,
340 GNUNET_NO);
341}
342
343 282
344/** 283/**
345 * Checks a #GNUNET_MESSAGE_TYPE_GNS_LOOKUP message 284 * Checks a #GNUNET_MESSAGE_TYPE_GNS_LOOKUP message
@@ -371,6 +310,7 @@ check_lookup (void *cls,
371 return GNUNET_OK; 310 return GNUNET_OK;
372} 311}
373 312
313
374/** 314/**
375 * Handle lookup requests from client 315 * Handle lookup requests from client
376 * 316 *
@@ -387,20 +327,18 @@ handle_lookup (void *cls,
387 struct ClientLookupHandle *clh; 327 struct ClientLookupHandle *clh;
388 char *nameptr = name; 328 char *nameptr = name;
389 const char *utf_in; 329 const char *utf_in;
390 const struct GNUNET_CRYPTO_EcdsaPrivateKey *key;
391 330
392 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
393 "Received LOOKUP message\n");
394 GNUNET_SERVICE_client_continue (gc->client); 331 GNUNET_SERVICE_client_continue (gc->client);
395 if (GNUNET_YES == ntohs (sh_msg->have_key))
396 key = &sh_msg->shorten_key;
397 else
398 key = NULL;
399 utf_in = (const char *) &sh_msg[1]; 332 utf_in = (const char *) &sh_msg[1];
400 GNUNET_STRINGS_utf8_tolower (utf_in, nameptr); 333 GNUNET_STRINGS_utf8_tolower (utf_in, nameptr);
334 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
335 "Received LOOKUP `%s' message\n",
336 name);
401 337
402 clh = GNUNET_new (struct ClientLookupHandle); 338 clh = GNUNET_new (struct ClientLookupHandle);
403 GNUNET_CONTAINER_DLL_insert (gc->clh_head, gc->clh_tail, clh); 339 GNUNET_CONTAINER_DLL_insert (gc->clh_head,
340 gc->clh_tail,
341 clh);
404 clh->gc = gc; 342 clh->gc = gc;
405 clh->request_id = sh_msg->id; 343 clh->request_id = sh_msg->id;
406 if ( (GNUNET_DNSPARSER_TYPE_A == ntohl (sh_msg->type)) && 344 if ( (GNUNET_DNSPARSER_TYPE_A == ntohl (sh_msg->type)) &&
@@ -422,7 +360,6 @@ handle_lookup (void *cls,
422 clh->lookup = GNS_resolver_lookup (&sh_msg->zone, 360 clh->lookup = GNS_resolver_lookup (&sh_msg->zone,
423 ntohl (sh_msg->type), 361 ntohl (sh_msg->type),
424 name, 362 name,
425 key,
426 (enum GNUNET_GNS_LocalOptions) ntohs (sh_msg->options), 363 (enum GNUNET_GNS_LocalOptions) ntohs (sh_msg->options),
427 &send_lookup_response, clh); 364 &send_lookup_response, clh);
428 GNUNET_STATISTICS_update (statistics, 365 GNUNET_STATISTICS_update (statistics,
@@ -430,82 +367,6 @@ handle_lookup (void *cls,
430 1, GNUNET_NO); 367 1, GNUNET_NO);
431} 368}
432 369
433/**
434 * Handle reverse lookup requests from client
435 *
436 * @param cls the closure
437 * @param client the client
438 * @param message the message
439 */
440static void
441handle_rev_lookup (void *cls,
442 const struct ReverseLookupMessage *sh_msg)
443{
444 struct GnsClient *gc = cls;
445 struct ClientLookupHandle *clh;
446
447 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
448 "Received REVERSE_LOOKUP message\n");
449 GNUNET_SERVICE_client_continue (gc->client);
450
451 clh = GNUNET_new (struct ClientLookupHandle);
452 GNUNET_CONTAINER_DLL_insert (gc->clh_head, gc->clh_tail, clh);
453 clh->gc = gc;
454 clh->request_id = sh_msg->id;
455 clh->rev_lookup = GNS_reverse_lookup (&sh_msg->zone_pkey,
456 &sh_msg->root_pkey,
457 &send_reverse_lookup_response,
458 clh);
459 GNUNET_STATISTICS_update (statistics,
460 "Reverse lookup attempts",
461 1, GNUNET_NO);
462}
463
464
465/**
466 * Method called to inform about the ego to be used for the master zone
467 * for DNS interceptions.
468 *
469 * This function is only called ONCE, and 'NULL' being passed in
470 * @a ego does indicate that interception is not configured.
471 * If @a ego is non-NULL, we should start to intercept DNS queries
472 * and resolve ".gnu" queries using the given ego as the master zone.
473 *
474 * @param cls closure, our `const struct GNUNET_CONFIGURATION_Handle *c`
475 * @param ego ego handle
476 * @param ctx context for application to store data for this ego
477 * (during the lifetime of this process, initially NULL)
478 * @param name name assigned by the user for this ego,
479 * NULL if the user just deleted the ego and it
480 * must thus no longer be used
481 */
482static void
483identity_reverse_cb (void *cls,
484 struct GNUNET_IDENTITY_Ego *ego,
485 void **ctx,
486 const char *name)
487{
488 identity_op = NULL;
489
490 if (NULL == ego)
491 {
492 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
493 _("No ego configured for `%s`\n"),
494 "gns-master");
495
496 return;
497 }
498 if (GNUNET_SYSERR ==
499 GNS_reverse_init (namestore_handle,
500 GNUNET_IDENTITY_ego_get_private_key (ego),
501 name))
502 {
503 GNUNET_break (0);
504 GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
505 return;
506 }
507}
508
509 370
510/** 371/**
511 * Method called to inform about the ego to be used for the master zone 372 * Method called to inform about the ego to be used for the master zone
@@ -532,16 +393,10 @@ identity_intercept_cb (void *cls,
532{ 393{
533 const struct GNUNET_CONFIGURATION_Handle *cfg = cls; 394 const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
534 struct GNUNET_CRYPTO_EcdsaPublicKey dns_root; 395 struct GNUNET_CRYPTO_EcdsaPublicKey dns_root;
535 identity_op = NULL;
536 396
397 identity_op = NULL;
537 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 398 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
538 "Looking for gns-intercept ego\n"); 399 "Looking for gns-intercept ego\n");
539 identity_op = GNUNET_IDENTITY_get (identity_handle,
540 "gns-reverse",
541 &identity_reverse_cb,
542 (void*)cfg);
543
544
545 if (NULL == ego) 400 if (NULL == ego)
546 { 401 {
547 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 402 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
@@ -553,10 +408,12 @@ identity_intercept_cb (void *cls,
553 GNUNET_IDENTITY_ego_get_public_key (ego, 408 GNUNET_IDENTITY_ego_get_public_key (ego,
554 &dns_root); 409 &dns_root);
555 if (GNUNET_SYSERR == 410 if (GNUNET_SYSERR ==
556 GNS_interceptor_init (&dns_root, cfg)) 411 GNS_interceptor_init (&dns_root,
412 cfg))
557 { 413 {
558 GNUNET_break (0); 414 GNUNET_break (0);
559 GNUNET_SCHEDULER_add_now (&shutdown_task, NULL); 415 GNUNET_SCHEDULER_add_now (&shutdown_task,
416 NULL);
560 return; 417 return;
561 } 418 }
562} 419}
@@ -577,16 +434,8 @@ run (void *cls,
577 unsigned long long max_parallel_bg_queries = 16; 434 unsigned long long max_parallel_bg_queries = 16;
578 435
579 v6_enabled = GNUNET_NETWORK_test_pf (PF_INET6); 436 v6_enabled = GNUNET_NETWORK_test_pf (PF_INET6);
580 v4_enabled = GNUNET_NETWORK_test_pf (PF_INET); 437 v4_enabled = GNUNET_NETWORK_test_pf (PF_INET);
581 namestore_handle = GNUNET_NAMESTORE_connect (c); 438 namecache_handle = GNUNET_NAMECACHE_connect (c);
582 if (NULL == namestore_handle)
583 {
584 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
585 _("Failed to connect to the namestore!\n"));
586 GNUNET_SCHEDULER_shutdown ();
587 return;
588 }
589 namecache_handle = GNUNET_NAMECACHE_connect (c);
590 if (NULL == namecache_handle) 439 if (NULL == namecache_handle)
591 { 440 {
592 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 441 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@@ -635,11 +484,9 @@ run (void *cls,
635 dht_handle, 484 dht_handle,
636 c, 485 c,
637 max_parallel_bg_queries); 486 max_parallel_bg_queries);
638 GNS_shorten_init (namestore_handle,
639 namecache_handle,
640 dht_handle);
641 statistics = GNUNET_STATISTICS_create ("gns", c); 487 statistics = GNUNET_STATISTICS_create ("gns", c);
642 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); 488 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
489 NULL);
643} 490}
644 491
645 492
@@ -657,10 +504,6 @@ GNUNET_SERVICE_MAIN
657 GNUNET_MESSAGE_TYPE_GNS_LOOKUP, 504 GNUNET_MESSAGE_TYPE_GNS_LOOKUP,
658 struct LookupMessage, 505 struct LookupMessage,
659 NULL), 506 NULL),
660 GNUNET_MQ_hd_fixed_size (rev_lookup,
661 GNUNET_MESSAGE_TYPE_GNS_REVERSE_LOOKUP,
662 struct ReverseLookupMessage,
663 NULL),
664 GNUNET_MQ_handler_end()); 507 GNUNET_MQ_handler_end());
665 508
666 509
diff --git a/src/gns/gnunet-service-gns_interceptor.c b/src/gns/gnunet-service-gns_interceptor.c
index 7a3cfc0dd..a9e207891 100644
--- a/src/gns/gnunet-service-gns_interceptor.c
+++ b/src/gns/gnunet-service-gns_interceptor.c
@@ -333,7 +333,6 @@ handle_dns_request (void *cls,
333 ilh->lookup = GNS_resolver_lookup (&zone, 333 ilh->lookup = GNS_resolver_lookup (&zone,
334 p->queries[0].type, 334 p->queries[0].type,
335 p->queries[0].name, 335 p->queries[0].name,
336 NULL /* FIXME: enable shorten for DNS intercepts? */,
337 GNUNET_NO, 336 GNUNET_NO,
338 &reply_to_dns, ilh); 337 &reply_to_dns, ilh);
339 return; 338 return;
diff --git a/src/gns/gnunet-service-gns_resolver.c b/src/gns/gnunet-service-gns_resolver.c
index 5e957871e..c58190599 100644
--- a/src/gns/gnunet-service-gns_resolver.c
+++ b/src/gns/gnunet-service-gns_resolver.c
@@ -30,7 +30,6 @@
30#include "gnunet_dht_service.h" 30#include "gnunet_dht_service.h"
31#include "gnunet_gnsrecord_lib.h" 31#include "gnunet_gnsrecord_lib.h"
32#include "gnunet_namecache_service.h" 32#include "gnunet_namecache_service.h"
33#include "gnunet_namestore_service.h"
34#include "gnunet_dns_service.h" 33#include "gnunet_dns_service.h"
35#include "gnunet_resolver_service.h" 34#include "gnunet_resolver_service.h"
36#include "gnunet_revocation_service.h" 35#include "gnunet_revocation_service.h"
@@ -39,7 +38,6 @@
39#include "gnunet_gns_service.h" 38#include "gnunet_gns_service.h"
40#include "gns.h" 39#include "gns.h"
41#include "gnunet-service-gns_resolver.h" 40#include "gnunet-service-gns_resolver.h"
42#include "gnunet-service-gns_shorten.h"
43#include "gnunet_vpn_service.h" 41#include "gnunet_vpn_service.h"
44 42
45 43
@@ -327,11 +325,6 @@ struct GNS_ResolverHandle
327 struct AuthorityChain *ac_tail; 325 struct AuthorityChain *ac_tail;
328 326
329 /** 327 /**
330 * Private key of the shorten zone, NULL to not shorten.
331 */
332 struct GNUNET_CRYPTO_EcdsaPrivateKey *shorten_key;
333
334 /**
335 * ID of a task associated with the resolution process. 328 * ID of a task associated with the resolution process.
336 */ 329 */
337 struct GNUNET_SCHEDULER_Task * task_id; 330 struct GNUNET_SCHEDULER_Task * task_id;
@@ -1750,23 +1743,6 @@ handle_gns_resolution_result (void *cls,
1750 } /* end: switch */ 1743 } /* end: switch */
1751 } /* end: for rd_count */ 1744 } /* end: for rd_count */
1752 1745
1753 /* trigger shortening */
1754 if ((NULL != rh->shorten_key) &&
1755 (NULL != shorten_ac) &&
1756 (GNUNET_NO == shorten_ac->shortening_started) &&
1757 (NULL != shorten_ac->suggested_shortening_label))
1758 {
1759 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1760 "Start shortening for label `%s' based on nick `%s'\n",
1761 shorten_ac->label,
1762 shorten_ac->suggested_shortening_label);
1763 shorten_ac->shortening_started = GNUNET_YES;
1764 GNS_shorten_start (shorten_ac->label,
1765 shorten_ac->suggested_shortening_label,
1766 &shorten_ac->authority_info.gns_authority,
1767 rh->shorten_key);
1768 }
1769
1770 /* yes, we are done, return result */ 1746 /* yes, we are done, return result */
1771 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1747 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1772 "Returning GNS response for `%s' with %u answers\n", 1748 "Returning GNS response for `%s' with %u answers\n",
@@ -2374,7 +2350,6 @@ start_resolver_lookup (struct GNS_ResolverHandle *rh)
2374 * @param zone the zone to perform the lookup in 2350 * @param zone the zone to perform the lookup in
2375 * @param record_type the record type to look up 2351 * @param record_type the record type to look up
2376 * @param name the name to look up 2352 * @param name the name to look up
2377 * @param shorten_key a private key for use with PSEU import (can be NULL)
2378 * @param options local options to control local lookup 2353 * @param options local options to control local lookup
2379 * @param proc the processor to call on result 2354 * @param proc the processor to call on result
2380 * @param proc_cls the closure to pass to @a proc 2355 * @param proc_cls the closure to pass to @a proc
@@ -2384,16 +2359,13 @@ struct GNS_ResolverHandle *
2384GNS_resolver_lookup (const struct GNUNET_CRYPTO_EcdsaPublicKey *zone, 2359GNS_resolver_lookup (const struct GNUNET_CRYPTO_EcdsaPublicKey *zone,
2385 uint32_t record_type, 2360 uint32_t record_type,
2386 const char *name, 2361 const char *name,
2387 const struct GNUNET_CRYPTO_EcdsaPrivateKey *shorten_key,
2388 enum GNUNET_GNS_LocalOptions options, 2362 enum GNUNET_GNS_LocalOptions options,
2389 GNS_ResultProcessor proc, void *proc_cls) 2363 GNS_ResultProcessor proc, void *proc_cls)
2390{ 2364{
2391 struct GNS_ResolverHandle *rh; 2365 struct GNS_ResolverHandle *rh;
2392 2366
2393 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 2367 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2394 (NULL == shorten_key) 2368 "Starting lookup for `%s'\n",
2395 ? "Starting lookup for `%s' with shortening disabled\n"
2396 : "Starting lookup for `%s' with shortening enabled\n",
2397 name); 2369 name);
2398 rh = GNUNET_new (struct GNS_ResolverHandle); 2370 rh = GNUNET_new (struct GNS_ResolverHandle);
2399 GNUNET_CONTAINER_DLL_insert (rlh_head, 2371 GNUNET_CONTAINER_DLL_insert (rlh_head,
@@ -2406,11 +2378,6 @@ GNS_resolver_lookup (const struct GNUNET_CRYPTO_EcdsaPublicKey *zone,
2406 rh->record_type = record_type; 2378 rh->record_type = record_type;
2407 rh->name = GNUNET_strdup (name); 2379 rh->name = GNUNET_strdup (name);
2408 rh->name_resolution_pos = strlen (name); 2380 rh->name_resolution_pos = strlen (name);
2409 if (NULL != shorten_key)
2410 {
2411 rh->shorten_key = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPrivateKey);
2412 *rh->shorten_key = *shorten_key;
2413 }
2414 start_resolver_lookup (rh); 2381 start_resolver_lookup (rh);
2415 return rh; 2382 return rh;
2416} 2383}
@@ -2507,7 +2474,6 @@ GNS_resolver_lookup_cancel (struct GNS_ResolverHandle *rh)
2507 dr); 2474 dr);
2508 GNUNET_free (dr); 2475 GNUNET_free (dr);
2509 } 2476 }
2510 GNUNET_free_non_null (rh->shorten_key);
2511 GNUNET_free (rh->name); 2477 GNUNET_free (rh->name);
2512 GNUNET_free (rh); 2478 GNUNET_free (rh);
2513} 2479}
diff --git a/src/gns/gnunet-service-gns_resolver.h b/src/gns/gnunet-service-gns_resolver.h
index 863398093..c71d3983d 100644
--- a/src/gns/gnunet-service-gns_resolver.h
+++ b/src/gns/gnunet-service-gns_resolver.h
@@ -65,9 +65,10 @@ struct GNS_ResolverHandle;
65 * @param rd_count number of records in @a rd 65 * @param rd_count number of records in @a rd
66 * @param rd records returned for the lookup 66 * @param rd records returned for the lookup
67 */ 67 */
68typedef void (*GNS_ResultProcessor)(void *cls, 68typedef void
69 uint32_t rd_count, 69(*GNS_ResultProcessor)(void *cls,
70 const struct GNUNET_GNSRECORD_Data *rd); 70 uint32_t rd_count,
71 const struct GNUNET_GNSRECORD_Data *rd);
71 72
72 73
73/** 74/**
@@ -77,7 +78,6 @@ typedef void (*GNS_ResultProcessor)(void *cls,
77 * @param zone the zone to perform the lookup in 78 * @param zone the zone to perform the lookup in
78 * @param record_type the record type to look up 79 * @param record_type the record type to look up
79 * @param name the name to look up 80 * @param name the name to look up
80 * @param shorten_key optional private key for authority caching, can be NULL
81 * @param options options set to control local lookup 81 * @param options options set to control local lookup
82 * @param proc the processor to call 82 * @param proc the processor to call
83 * @param proc_cls the closure to pass to @a proc 83 * @param proc_cls the closure to pass to @a proc
@@ -87,7 +87,6 @@ struct GNS_ResolverHandle *
87GNS_resolver_lookup (const struct GNUNET_CRYPTO_EcdsaPublicKey *zone, 87GNS_resolver_lookup (const struct GNUNET_CRYPTO_EcdsaPublicKey *zone,
88 uint32_t record_type, 88 uint32_t record_type,
89 const char *name, 89 const char *name,
90 const struct GNUNET_CRYPTO_EcdsaPrivateKey *shorten_key,
91 enum GNUNET_GNS_LocalOptions options, 90 enum GNUNET_GNS_LocalOptions options,
92 GNS_ResultProcessor proc, 91 GNS_ResultProcessor proc,
93 void *proc_cls); 92 void *proc_cls);
@@ -102,8 +101,6 @@ void
102GNS_resolver_lookup_cancel (struct GNS_ResolverHandle *rh); 101GNS_resolver_lookup_cancel (struct GNS_ResolverHandle *rh);
103 102
104 103
105
106
107/** 104/**
108 * Generic function to check for TLDs. Checks if "name" ends in ".tld" 105 * Generic function to check for TLDs. Checks if "name" ends in ".tld"
109 * 106 *
diff --git a/src/gns/gnunet-service-gns_reverser.c b/src/gns/gnunet-service-gns_reverser.c
deleted file mode 100644
index b5b8b31b7..000000000
--- a/src/gns/gnunet-service-gns_reverser.c
+++ /dev/null
@@ -1,601 +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 * @file gns/gnunet-service-gns_reverser.c
22 * @brief GNUnet GNS service
23 * @author Martin Schanzenbach
24 */
25
26
27#include "platform.h"
28#include "gnunet_gns_service.h"
29#include "gnunet-service-gns_resolver.h"
30#include "gnunet-service-gns_reverser.h"
31
32struct ReverseRecordEntry
33{
34 /**
35 * DLL
36 */
37 struct ReverseRecordEntry *next;
38
39 /**
40 * DLL
41 */
42 struct ReverseRecordEntry *prev;
43
44 /**
45 * ReverseRecord
46 */
47 struct GNUNET_GNSRECORD_ReverseRecord *record;
48
49 /**
50 * Record length
51 */
52 size_t record_len;
53
54};
55
56struct IteratorHandle
57{
58 /**
59 * Records found
60 */
61 struct ReverseRecordEntry *records_head;
62
63 /**
64 * Records found
65 */
66 struct ReverseRecordEntry *records_tail;
67
68 /**
69 * Record count
70 */
71 uint64_t record_count;
72
73 /**
74 * Current delegation to expect
75 */
76 struct GNUNET_CRYPTO_EcdsaPublicKey target;
77
78 /**
79 * Queue entry
80 */
81 struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
82
83};
84
85struct ReverseTreeNode
86{
87 /**
88 * DLL
89 */
90 struct ReverseTreeNode *next;
91
92 /**
93 * DLL
94 */
95 struct ReverseTreeNode *prev;
96
97 /**
98 * Resolved name until now
99 */
100 char *name;
101
102 /**
103 * Depth of the resolution at this node
104 */
105 uint8_t depth;
106
107 /**
108 * The pkey of the namespace
109 */
110 struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
111
112};
113
114
115struct GNS_ReverserHandle
116{
117 /**
118 * GNS resolver handle
119 */
120 struct GNS_ResolverHandle *rh;
121
122 /**
123 * The authority to look for
124 */
125 struct GNUNET_CRYPTO_EcdsaPublicKey authority;
126
127 /**
128 * Resolution candidate queue
129 */
130 struct ReverseTreeNode *node_queue_head;
131
132 /**
133 * Resolution candidate queue
134 */
135 struct ReverseTreeNode *node_queue_tail;
136
137 /**
138 * Max depth for the resolution
139 */
140 uint8_t max_depth;
141
142 /**
143 * Result callback
144 */
145 GNS_ReverseResultProcessor proc;
146
147 /**
148 * Callback closure
149 */
150 void *proc_cls;
151};
152
153/**
154 * Reverse record collection task
155 */
156static struct GNUNET_SCHEDULER_Task *reverse_record_check_task;
157
158/**
159 * NS iterator task
160 */
161static struct GNUNET_SCHEDULER_Task *it_task;
162
163/**
164 * GNS lookup handle
165 */
166static struct GNS_ResolverHandle *gns_lookup_reverse;
167
168/**
169 * NS handle
170 */
171static struct GNUNET_NAMESTORE_Handle *ns;
172
173/**
174 * NS Iterator
175 */
176static struct GNUNET_NAMESTORE_ZoneIterator *namestore_iter;
177
178/**
179 * The zone target for reverse record resolution
180 */
181static struct GNUNET_CRYPTO_EcdsaPublicKey myzone;
182
183/**
184 * The zone target for reverse record resolution
185 */
186static struct GNUNET_CRYPTO_EcdsaPrivateKey pzone;
187
188/**
189 * The nick of our zone
190 */
191static char *mynick;
192
193
194static void
195cleanup_handle (struct GNS_ReverserHandle *rh)
196{
197 struct ReverseTreeNode *rtn;
198
199 for (rtn = rh->node_queue_head; NULL != rtn; rtn = rh->node_queue_head)
200 {
201 if (NULL != rtn->name)
202 GNUNET_free (rtn->name);
203 GNUNET_CONTAINER_DLL_remove (rh->node_queue_head,
204 rh->node_queue_tail,
205 rtn);
206 GNUNET_free (rtn);
207 }
208 GNUNET_free (rh);
209}
210
211static void
212handle_gns_result (void *cls,
213 uint32_t rd_count,
214 const struct GNUNET_GNSRECORD_Data *rd)
215{
216 struct GNS_ReverserHandle *rh = cls;
217 const struct GNUNET_GNSRECORD_ReverseRecord *rr;
218 struct ReverseTreeNode *rtn;
219 char *result;
220 const char *name;
221 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
222 "Got result (%d)\n", rd_count);
223
224 for (int i = 0; i < rd_count; i++)
225 {
226 /**
227 * Check if we are in the delegation set
228 */
229 if (GNUNET_GNSRECORD_TYPE_REVERSE != rd[i].record_type)
230 continue;
231 rr = rd[i].data;
232 name = (const char*) &rr[1];
233 if (0 == memcmp (&rh->authority,
234 &rr->pkey,
235 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
236 {
237 //Found!
238 GNUNET_asprintf (&result,
239 "%s.%s.gnu",
240 rh->node_queue_head->name,
241 name);
242 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
243 "Found path from %s\n", result);
244
245 rh->proc (rh->proc_cls, result);
246 cleanup_handle (rh);
247 GNUNET_free (result);
248 return;
249 } else {
250 if (rh->node_queue_head->depth >= rh->max_depth)
251 break;
252 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
253 "Found REVERSE from %s\n", name);
254
255 rtn = GNUNET_new (struct ReverseTreeNode);
256 if (NULL == rh->node_queue_head->name)
257 rtn->name = GNUNET_strdup (name);
258 else
259 GNUNET_asprintf (&rtn->name,
260 "%s.%s",
261 rh->node_queue_head->name,
262 name);
263 rtn->depth = rh->node_queue_head->depth + 1;
264 rtn->pkey = rr->pkey;
265 GNUNET_CONTAINER_DLL_insert_tail (rh->node_queue_head,
266 rh->node_queue_tail,
267 rtn);
268 }
269 }
270
271 /**
272 * Done here remove node from queue
273 */
274 rtn = rh->node_queue_head;
275 if (NULL != rtn)
276 GNUNET_CONTAINER_DLL_remove (rh->node_queue_head,
277 rh->node_queue_tail,
278 rtn);
279 if (NULL == rh->node_queue_head)
280 {
281 //No luck
282 rh->proc (rh->proc_cls, NULL);
283 cleanup_handle (rh);
284 return;
285 }
286 rh->rh = GNS_resolver_lookup (&rh->node_queue_head->pkey,
287 GNUNET_GNSRECORD_TYPE_REVERSE,
288 "+.gnu",
289 NULL,
290 GNUNET_GNS_LO_DEFAULT,
291 &handle_gns_result,
292 rh);
293}
294
295/**
296 * Reverse lookup of a specific zone
297 * calls RecordLookupProcessor on result or timeout
298 *
299 * @param target the zone to perform the lookup in
300 * @param authority the authority
301 * @param proc the processor to call
302 * @param proc_cls the closure to pass to @a proc
303 * @return handle to cancel operation
304 */
305struct GNS_ReverserHandle *
306GNS_reverse_lookup (const struct GNUNET_CRYPTO_EcdsaPublicKey *target,
307 const struct GNUNET_CRYPTO_EcdsaPublicKey *authority,
308 GNS_ReverseResultProcessor proc,
309 void *proc_cls)
310{
311 struct GNS_ReverserHandle *rh;
312 struct ReverseTreeNode *rtn;
313
314 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
315 "Starting reverse resolution\n");
316 rh = GNUNET_new (struct GNS_ReverserHandle);
317 rh->proc = proc;
318 rh->proc_cls = proc_cls;
319 rtn = GNUNET_new (struct ReverseTreeNode);
320 rtn->name = NULL;
321 rtn->pkey = *target;
322 rtn->depth = 0;
323 GNUNET_CONTAINER_DLL_insert (rh->node_queue_head,
324 rh->node_queue_tail,
325 rtn);
326 rh->authority = *authority;
327 rh->max_depth = 3; //TODO make argument
328 rh->rh = GNS_resolver_lookup (target,
329 GNUNET_GNSRECORD_TYPE_REVERSE,
330 "+.gnu",
331 NULL,
332 GNUNET_GNS_LO_DEFAULT,
333 &handle_gns_result,
334 rh);
335 return rh;
336}
337
338/**
339 * Cancel active resolution (i.e. client disconnected).
340 *
341 * @param rh resolution to abort
342 */
343void
344GNS_reverse_lookup_cancel (struct GNS_ReverserHandle *rh)
345{
346 cleanup_handle (rh);
347 return;
348}
349
350/********************************************
351 * Reverse iterator
352 * ******************************************/
353
354
355static void
356next_it (void *cls);
357
358static void
359handle_gns_result_iter (void *cls,
360 uint32_t rd_count,
361 const struct GNUNET_GNSRECORD_Data *rd)
362{
363 struct IteratorHandle *ith = cls;
364 struct ReverseRecordEntry *rr;
365 gns_lookup_reverse = NULL;
366 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
367 "GNS for REVERSE (%s)\n", mynick);
368
369
370 if ((rd_count != 1) ||
371 (GNUNET_GNSRECORD_TYPE_PKEY != rd->record_type))
372 {
373 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
374 "GNS invalid REVERSE (%s)\n", mynick);
375 gns_lookup_reverse = NULL;
376 it_task = GNUNET_SCHEDULER_add_now (&next_it, ith);
377 return;
378 }
379
380
381 rr = GNUNET_new (struct ReverseRecordEntry);
382 rr->record_len = sizeof (struct GNUNET_GNSRECORD_ReverseRecord)
383 + strlen (mynick) + 1;
384 rr->record = GNUNET_malloc (rr->record_len);
385 rr->record->pkey = ith->target;
386 rr->record->expiration.abs_value_us = rd->expiration_time;
387 GNUNET_memcpy ((char*)&rr->record[1],
388 mynick,
389 strlen (mynick));
390 GNUNET_CONTAINER_DLL_insert (ith->records_head,
391 ith->records_tail,
392 rr);
393 ith->record_count++;
394 it_task = GNUNET_SCHEDULER_add_now (&next_it, ith);
395}
396
397
398static void
399next_it (void *cls)
400{
401 it_task = NULL;
402 GNUNET_assert (NULL != namestore_iter);
403 GNUNET_NAMESTORE_zone_iterator_next (namestore_iter);
404}
405
406
407static void
408iterator_cb (void *cls,
409 const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
410 const char *label,
411 unsigned int rd_count,
412 const struct GNUNET_GNSRECORD_Data *rd)
413{
414 struct IteratorHandle *ith = cls;
415 struct GNUNET_CRYPTO_EcdsaPublicKey zone;
416 char *name;
417
418 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
419 "iterating for REVERSE (%s / %s)\n",
420 label,
421 mynick);
422
423
424 if ((rd_count != 1) ||
425 (GNUNET_GNSRECORD_TYPE_PKEY != rd->record_type))
426 {
427 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
428 "wrong format (%s)\n", mynick);
429
430
431 it_task = GNUNET_SCHEDULER_add_now (&next_it, ith);
432 return;
433 }
434 GNUNET_CRYPTO_ecdsa_key_get_public (key,
435 &zone);
436 if (0 != memcmp (&zone, &myzone,
437 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
438 {
439 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
440 "wrong zone (%s)\n", mynick);
441
442
443 it_task = GNUNET_SCHEDULER_add_now (&next_it, ith);
444 return;
445 }
446 ith->target = *((struct GNUNET_CRYPTO_EcdsaPublicKey *) rd->data);
447 GNUNET_asprintf (&name,
448 "%s.gnu",
449 mynick);
450 gns_lookup_reverse = GNS_resolver_lookup (&ith->target,
451 GNUNET_GNSRECORD_TYPE_PKEY,
452 name,
453 NULL,
454 GNUNET_GNS_LO_DEFAULT,
455 &handle_gns_result_iter,
456 ith);
457 GNUNET_free (name);
458}
459
460static void check_reverse_records (void *cls);
461
462static void
463store_reverse (void *cls,
464 int32_t success,
465 const char *emsg)
466{
467 struct IteratorHandle *ith = cls;
468 struct ReverseRecordEntry *rr;
469
470 if (GNUNET_SYSERR == success)
471 {
472 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
473 "%s\n",
474 emsg);
475 }
476 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stored records (%s)\n", mynick);
477
478 for (rr = ith->records_head; NULL != rr; rr = ith->records_head)
479 {
480 GNUNET_CONTAINER_DLL_remove (ith->records_head,
481 ith->records_tail,
482 rr);
483 GNUNET_free (rr->record);
484 GNUNET_free (rr);
485 }
486 reverse_record_check_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_DAYS,
487 &check_reverse_records,
488 NULL);
489 GNUNET_free (ith);
490}
491
492
493static void
494finished_cb (void *cls)
495{
496 struct IteratorHandle *ith = cls;
497 struct ReverseRecordEntry *rr;
498 struct GNUNET_GNSRECORD_Data rd[ith->record_count];
499
500 memset (rd, 0, sizeof (struct GNUNET_GNSRECORD_Data) * ith->record_count);
501
502 rr = ith->records_head;
503 for (int i = 0; i < ith->record_count; i++)
504 {
505 rd[i].data_size = rr->record_len;
506 rd[i].data = GNUNET_malloc (rr->record_len);
507 rd[i].record_type = GNUNET_GNSRECORD_TYPE_REVERSE;
508 rd[i].expiration_time = rr->record->expiration.abs_value_us;
509 GNUNET_memcpy ((char*) rd[i].data,
510 rr->record,
511 rr->record_len);
512 rr = rr->next;
513 }
514 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
515 "Finished iterating for REVERSE\n");
516
517 ith->ns_qe = GNUNET_NAMESTORE_records_store (ns,
518 &pzone,
519 "+",
520 ith->record_count,
521 rd,
522 &store_reverse,
523 ith);
524 namestore_iter = NULL;
525
526}
527
528
529static void
530it_error (void *cls)
531{
532 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
533 "Error iterating for REVERSE\n");
534}
535
536
537static void
538check_reverse_records (void *cls)
539{
540 struct IteratorHandle *ith;
541 ith = GNUNET_new (struct IteratorHandle);
542 ith->record_count = 0;
543 reverse_record_check_task = NULL;
544 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
545 "Start iterating for REVERSE (%s)\n", mynick);
546 namestore_iter = GNUNET_NAMESTORE_zone_iteration_start (ns,
547 NULL,
548 &it_error,
549 ith,
550 &iterator_cb,
551 ith,
552 &finished_cb,
553 ith);
554}
555
556
557/**
558 * Initialize reverser
559 *
560 * @param nh handle to a namestore
561 * @param key the private key of the gns-reverse zone
562 * @param name the name of the gns-reverse zone
563 * @return GNUNET_OK
564 */
565int
566GNS_reverse_init (struct GNUNET_NAMESTORE_Handle *nh,
567 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
568 const char *nick)
569{
570 GNUNET_asprintf (&mynick,
571 "%s",
572 nick);
573 GNUNET_CRYPTO_ecdsa_key_get_public (zone,
574 &myzone);
575 GNUNET_memcpy (&pzone,
576 zone,
577 sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey));
578 ns = nh;
579 reverse_record_check_task = GNUNET_SCHEDULER_add_now (&check_reverse_records,
580 NULL);
581 return GNUNET_OK;
582}
583
584/**
585 * Cleanup reverser
586 */
587void
588GNS_reverse_done ()
589{
590 if (NULL != mynick)
591 GNUNET_free (mynick);
592 if (NULL != it_task)
593 GNUNET_SCHEDULER_cancel (it_task);
594 if (NULL != reverse_record_check_task)
595 GNUNET_SCHEDULER_cancel (reverse_record_check_task);
596 if (NULL != gns_lookup_reverse)
597 GNS_resolver_lookup_cancel (gns_lookup_reverse);
598 if (NULL != namestore_iter)
599 GNUNET_NAMESTORE_zone_iteration_stop (namestore_iter);
600}
601
diff --git a/src/gns/gnunet-service-gns_reverser.h b/src/gns/gnunet-service-gns_reverser.h
deleted file mode 100644
index fc9680a29..000000000
--- a/src/gns/gnunet-service-gns_reverser.h
+++ /dev/null
@@ -1,91 +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 * @file gns/gnunet-service-gns_reverser.h
22 * @brief GNUnet GNS service
23 * @author Martin Schanzenbach
24 */
25#ifndef GNS_REVERSER_H
26#define GNS_REVERSER_H
27#include "gns.h"
28#include "gnunet_gns_service.h"
29
30/**
31 * Handle for an active request.
32 */
33struct GNS_ReverserHandle;
34
35
36/**
37 * Function called with results for a GNS resolution.
38 *
39 * @param cls closure
40 * @param rd_count number of records in @a rd
41 * @param rd records returned for the lookup
42 */
43typedef void (*GNS_ReverseResultProcessor)(void *cls,
44 const char *name);
45
46
47/**
48 * Reverse lookup of a specific zone
49 * calls RecordLookupProcessor on result or timeout
50 *
51 * @param target the zone to perform the lookup in
52 * @param authority the authority
53 * @param proc the processor to call
54 * @param proc_cls the closure to pass to @a proc
55 * @return handle to cancel operation
56 */
57struct GNS_ReverserHandle *
58GNS_reverse_lookup (const struct GNUNET_CRYPTO_EcdsaPublicKey *target,
59 const struct GNUNET_CRYPTO_EcdsaPublicKey *authority,
60 GNS_ReverseResultProcessor proc,
61 void *proc_cls);
62
63
64/**
65 * Cancel active resolution (i.e. client disconnected).
66 *
67 * @param rh resolution to abort
68 */
69void
70GNS_reverse_lookup_cancel (struct GNS_ReverserHandle *rh);
71
72/**
73 * Initialize reverser
74 *
75 * @param nh handle to a namestore
76 * @param key the private key of the gns-reverse zone
77 * @param name the name of the gns-reverse zone
78 * @return GNUNET_OK
79 */
80int
81GNS_reverse_init (struct GNUNET_NAMESTORE_Handle *nh,
82 const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
83 const char *name);
84
85/**
86 * Cleanup reverser
87 */
88void
89GNS_reverse_done ();
90
91#endif
diff --git a/src/gns/gnunet-service-gns_shorten.c b/src/gns/gnunet-service-gns_shorten.c
deleted file mode 100644
index 9aa0419aa..000000000
--- a/src/gns/gnunet-service-gns_shorten.c
+++ /dev/null
@@ -1,466 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011-2013 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
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 gns/gnunet-service-gns_shorten.c
23 * @brief GNUnet GNS shortening logic
24 * @author Martin Schanzenbach
25 * @author Christian Grothoff
26 */
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_dht_service.h"
30#include "gnunet_gnsrecord_lib.h"
31#include "gnunet_namestore_service.h"
32#include "gnunet_resolver_service.h"
33#include "gnunet_gns_service.h"
34#include "gns.h"
35#include "gnunet-service-gns_shorten.h"
36#include "gnunet_vpn_service.h"
37
38
39/**
40 * Default DHT timeout for lookups.
41 */
42#define DHT_LOOKUP_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
43
44/**
45 * DHT replication level
46 */
47#define DHT_GNS_REPLICATION_LEVEL 5
48
49
50/**
51 * Handle for a PSEU lookup used to shorten names.
52 */
53struct GetPseuAuthorityHandle
54{
55 /**
56 * DLL
57 */
58 struct GetPseuAuthorityHandle *next;
59
60 /**
61 * DLL
62 */
63 struct GetPseuAuthorityHandle *prev;
64
65 /**
66 * Private key of the (shorten) zone to store the resulting
67 * pseudonym in.
68 */
69 struct GNUNET_CRYPTO_EcdsaPrivateKey shorten_zone_key;
70
71 /**
72 * Original label (used if no PSEU record is found).
73 */
74 char label[GNUNET_DNSPARSER_MAX_LABEL_LENGTH + 1];
75
76 /**
77 * Suggested label based on NICK record
78 */
79 char * suggested_label;
80
81 /**
82 * Label we are currently trying out
83 */
84 char *current_label;
85
86 /**
87 * The zone for which we are trying to find the PSEU record.
88 */
89 struct GNUNET_CRYPTO_EcdsaPublicKey target_zone;
90
91 /**
92 * Handle for DHT lookups. Should be NULL if no lookups are in progress
93 */
94 struct GNUNET_DHT_GetHandle *get_handle;
95
96 /**
97 * Handle to namestore request
98 */
99 struct GNUNET_NAMESTORE_QueueEntry *namestore_task;
100
101 /**
102 * Handle to namecache request
103 */
104 struct GNUNET_NAMECACHE_QueueEntry *namecache_task;
105
106 /**
107 * Task to abort DHT lookup operation.
108 */
109 struct GNUNET_SCHEDULER_Task * timeout_task;
110
111};
112
113
114/**
115 * Head of PSEU/shorten operations list.
116 */
117static struct GetPseuAuthorityHandle *gph_head;
118
119/**
120 * Tail of PSEU/shorten operations list.
121 */
122static struct GetPseuAuthorityHandle *gph_tail;
123
124/**
125 * Our handle to the namestore service
126 */
127static struct GNUNET_NAMESTORE_Handle *namestore_handle;
128
129/**
130 * Our handle to the namecache service
131 */
132static struct GNUNET_NAMECACHE_Handle *namecache_handle;
133
134/**
135 * Resolver handle to the dht
136 */
137static struct GNUNET_DHT_Handle *dht_handle;
138
139/**
140 * Cleanup a 'struct GetPseuAuthorityHandle', terminating all
141 * pending activities.
142 *
143 * @param gph handle to terminate
144 */
145static void
146free_get_pseu_authority_handle (struct GetPseuAuthorityHandle *gph)
147{
148 if (NULL != gph->get_handle)
149 {
150 GNUNET_DHT_get_stop (gph->get_handle);
151 gph->get_handle = NULL;
152 }
153 if (NULL != gph->namestore_task)
154 {
155 GNUNET_NAMESTORE_cancel (gph->namestore_task);
156 gph->namestore_task = NULL;
157 }
158 if (NULL != gph->namecache_task)
159 {
160 GNUNET_NAMECACHE_cancel (gph->namecache_task);
161 gph->namecache_task = NULL;
162 }
163 if (NULL != gph->timeout_task)
164 {
165 GNUNET_SCHEDULER_cancel (gph->timeout_task);
166 gph->timeout_task = NULL;
167 }
168 GNUNET_CONTAINER_DLL_remove (gph_head, gph_tail, gph);
169 GNUNET_free_non_null (gph->current_label);
170 GNUNET_free (gph);
171}
172
173
174/**
175 * Continuation for pkey record creation (shorten)
176 *
177 * @param cls a GetPseuAuthorityHandle
178 * @param success unused
179 * @param emsg unused
180 */
181static void
182create_pkey_cont (void* cls,
183 int32_t success,
184 const char *emsg)
185{
186 struct GetPseuAuthorityHandle* gph = cls;
187
188 gph->namestore_task = NULL;
189 free_get_pseu_authority_handle (gph);
190}
191
192
193/**
194 * Namestore calls this function if we have record for this name.
195 * (or with rd_count=0 to indicate no matches).
196 *
197 * @param cls the pending query
198 * @param rd_count the number of records with 'name'
199 * @param rd the record data
200 */
201static void
202process_pseu_lookup_ns (void *cls,
203 unsigned int rd_count,
204 const struct GNUNET_GNSRECORD_Data *rd);
205
206
207/**
208 * We obtained a result for our query to the shorten zone from
209 * the namestore. Try to decrypt.
210 *
211 * @param cls the handle to our shorten operation
212 * @param block resulting encrypted block
213 */
214static void
215process_pseu_block_ns (void *cls,
216 const struct GNUNET_GNSRECORD_Block *block)
217{
218 struct GetPseuAuthorityHandle *gph = cls;
219 struct GNUNET_CRYPTO_EcdsaPublicKey pub;
220
221 gph->namecache_task = NULL;
222 if (NULL == block)
223 {
224 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
225 "Namecache did not return information for label `%s' \n",
226 gph->current_label);
227 process_pseu_lookup_ns (gph, 0, NULL);
228 return;
229 }
230 GNUNET_CRYPTO_ecdsa_key_get_public (&gph->shorten_zone_key,
231 &pub);
232 if (GNUNET_OK !=
233 GNUNET_GNSRECORD_block_decrypt (block,
234 &pub,
235 gph->current_label,
236 &process_pseu_lookup_ns,
237 gph))
238 {
239 GNUNET_break (0);
240 free_get_pseu_authority_handle (gph);
241 return;
242 }
243}
244
245
246/**
247 * Lookup in the namecache for the shorten zone the given label.
248 *
249 * @param gph the handle to our shorten operation
250 * @param label the label to lookup
251 */
252static void
253perform_nick_lookup (struct GetPseuAuthorityHandle *gph,
254 const char *label)
255{
256 struct GNUNET_CRYPTO_EcdsaPublicKey pub;
257 struct GNUNET_HashCode query;
258
259 GNUNET_CRYPTO_ecdsa_key_get_public (&gph->shorten_zone_key,
260 &pub);
261 GNUNET_free_non_null (gph->current_label);
262 gph->current_label = GNUNET_strdup (label);
263 GNUNET_GNSRECORD_query_from_public_key (&pub,
264 label,
265 &query);
266 gph->namecache_task = GNUNET_NAMECACHE_lookup_block (namecache_handle,
267 &query,
268 &process_pseu_block_ns,
269 gph);
270}
271
272
273/**
274 * Namestore calls this function if we have record for this name.
275 * (or with rd_count=0 to indicate no matches).
276 *
277 * @param cls the pending query
278 * @param rd_count the number of records with 'name'
279 * @param rd the record data
280 */
281static void
282process_pseu_lookup_ns (void *cls,
283 unsigned int rd_count,
284 const struct GNUNET_GNSRECORD_Data *rd)
285{
286 struct GetPseuAuthorityHandle *gph = cls;
287 struct GNUNET_GNSRECORD_Data new_pkey;
288
289 gph->namestore_task = NULL;
290 if (rd_count > 0)
291 {
292 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
293 "Name `%s' already taken, cannot shorten.\n",
294 gph->current_label);
295 /* if this was not yet the original label, try one more
296 time, this time not using PSEU but the original label */
297 if (0 == strcmp (gph->current_label,
298 gph->label))
299 {
300 free_get_pseu_authority_handle (gph);
301 }
302 else
303 {
304 perform_nick_lookup (gph, gph->label);
305 }
306 return;
307 }
308 /* name is available */
309 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
310 "Shortening `%s' to `%s'\n",
311 GNUNET_GNSRECORD_z2s (&gph->target_zone),
312 gph->current_label);
313 new_pkey.expiration_time = UINT64_MAX;
314 new_pkey.data_size = sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
315 new_pkey.data = &gph->target_zone;
316 new_pkey.record_type = GNUNET_GNSRECORD_TYPE_PKEY;
317 new_pkey.flags = GNUNET_GNSRECORD_RF_NONE
318 | GNUNET_GNSRECORD_RF_PRIVATE;
319 gph->namestore_task
320 = GNUNET_NAMESTORE_records_store (namestore_handle,
321 &gph->shorten_zone_key,
322 gph->current_label,
323 1, &new_pkey,
324 &create_pkey_cont, gph);
325}
326
327
328/**
329 * Encountered an error in zone-to-name lookup, give up on shortening.
330 */
331static void
332zone_to_name_error_cb (void *cls)
333{
334 struct GetPseuAuthorityHandle* gph = cls;
335
336 gph->namestore_task = NULL;
337 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
338 "Shortening aborted, internal error talking to namestore\n");
339 free_get_pseu_authority_handle (gph);
340}
341
342
343/**
344 * Callback called by namestore for a zone to name result. We're
345 * trying to see if a short name for a given zone already exists.
346 *
347 * @param cls the closure
348 * @param zone_key the zone we queried
349 * @param name the name found or NULL
350 * @param rd_len number of records for the name
351 * @param rd the record data (PKEY) for the name
352 */
353static void
354process_zone_to_name_discover (void *cls,
355 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
356 const char *name,
357 unsigned int rd_len,
358 const struct GNUNET_GNSRECORD_Data *rd)
359{
360 struct GetPseuAuthorityHandle* gph = cls;
361
362 gph->namestore_task = NULL;
363 if (0 != rd_len)
364 {
365 /* we found a match in our own zone */
366 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
367 "Shortening aborted, name `%s' already reserved for the zone\n",
368 name);
369 free_get_pseu_authority_handle (gph);
370 return;
371 }
372 else
373 {
374 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
375 "Shortening continuing, no name not reserved in shorten zone\n");
376 }
377 /* record does not yet exist, check if suggested label is available */
378 perform_nick_lookup (gph, gph->suggested_label);
379}
380
381
382/**
383 * Start shortening algorithm, try to allocate a nice short
384 * canonical name for @a pub in @a shorten_zone, using
385 * @a original_label as one possible suggestion.
386 *
387 * @param original_label original label for the zone
388 * @param suggested_label suggested label for the zone
389 * @param pub public key of the zone to shorten
390 * @param shorten_zone private key of the target zone for the new record
391 */
392void
393GNS_shorten_start (const char *original_label,
394 const char *suggested_label,
395 const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
396 const struct GNUNET_CRYPTO_EcdsaPrivateKey *shorten_zone)
397{
398 struct GetPseuAuthorityHandle *gph;
399 struct GNUNET_CRYPTO_EcdsaPublicKey shorten_pub;
400
401 if (strlen (original_label) > GNUNET_DNSPARSER_MAX_LABEL_LENGTH)
402 {
403 GNUNET_break (0);
404 return;
405 }
406 GNUNET_CRYPTO_ecdsa_key_get_public (shorten_zone, &shorten_pub);
407 if (0 == memcmp (&shorten_pub, pub, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
408 {
409 /* Do not shorten the shorten zone */
410 return;
411 }
412
413 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
414 "Starting shortening process for `%s' with old label `%s' and suggested nickname `%s'\n",
415 GNUNET_GNSRECORD_z2s (pub),
416 original_label, suggested_label);
417 gph = GNUNET_new (struct GetPseuAuthorityHandle);
418 gph->shorten_zone_key = *shorten_zone;
419 gph->target_zone = *pub;
420 gph->suggested_label = GNUNET_strdup (suggested_label);
421 strcpy (gph->label, original_label);
422 GNUNET_CONTAINER_DLL_insert (gph_head, gph_tail, gph);
423 /* first, check if we *already* have a record for this zone */
424 gph->namestore_task = GNUNET_NAMESTORE_zone_to_name (namestore_handle,
425 shorten_zone,
426 pub,
427 &zone_to_name_error_cb,
428 gph,
429 &process_zone_to_name_discover,
430 gph);
431}
432
433
434/**
435 * Initialize the shortening subsystem
436 *
437 * @param nh the namestore handle
438 * @param nc the namecache handle
439 * @param dht the dht handle
440 */
441void
442GNS_shorten_init (struct GNUNET_NAMESTORE_Handle *nh,
443 struct GNUNET_NAMECACHE_Handle *nc,
444 struct GNUNET_DHT_Handle *dht)
445{
446 namestore_handle = nh;
447 namecache_handle = nc;
448 dht_handle = dht;
449}
450
451
452/**
453 * Shutdown shortening.
454 */
455void
456GNS_shorten_done ()
457{
458 /* abort active shorten operations */
459 while (NULL != gph_head)
460 free_get_pseu_authority_handle (gph_head);
461 dht_handle = NULL;
462 namestore_handle = NULL;
463 namecache_handle = NULL;
464}
465
466/* end of gnunet-service-gns_shorten.c */
diff --git a/src/gns/gnunet-service-gns_shorten.h b/src/gns/gnunet-service-gns_shorten.h
deleted file mode 100644
index d82bb52f7..000000000
--- a/src/gns/gnunet-service-gns_shorten.h
+++ /dev/null
@@ -1,70 +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 * @file gns/gnunet-service-gns_shorten.h
22 * @brief GNUnet GNS shortening API
23 * @author Martin Schanzenbach
24 */
25#ifndef GNS_SHORTEN_H
26#define GNS_SHORTEN_H
27#include "gns.h"
28#include "gnunet_dht_service.h"
29#include "gnunet_namecache_service.h"
30#include "gnunet_namestore_service.h"
31
32
33/**
34 * Initialize the shorten subsystem.
35 * MUST be called before #GNS_shorten_start.
36 *
37 * @param nh handle to the namestore
38 * @param nc the namecache handle
39 * @param dht handle to the dht
40 */
41void
42GNS_shorten_init (struct GNUNET_NAMESTORE_Handle *nh,
43 struct GNUNET_NAMECACHE_Handle *nc,
44 struct GNUNET_DHT_Handle *dht);
45
46
47/**
48 * Cleanup shorten: Terminate pending lookups
49 */
50void
51GNS_shorten_done (void);
52
53
54/**
55 * Start shortening algorithm, try to allocate a nice short
56 * canonical name for @a pub in @a shorten_zone, using
57 * @a original_label as one possible suggestion.
58 *
59 * @param original_label original label for the zone
60 * @param pub public key of the zone to shorten
61 * @param shorten_zone private key of the target zone for the new record
62 */
63void
64GNS_shorten_start (const char *original_label,
65 const char *suggested_label,
66 const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
67 const struct GNUNET_CRYPTO_EcdsaPrivateKey *shorten_zone);
68
69
70#endif
diff --git a/src/gns/plugin_block_gns.c b/src/gns/plugin_block_gns.c
index f0e34a04b..a42fef953 100644
--- a/src/gns/plugin_block_gns.c
+++ b/src/gns/plugin_block_gns.c
@@ -22,9 +22,11 @@
22 * @file gns/plugin_block_gns.c 22 * @file gns/plugin_block_gns.c
23 * @brief blocks used for GNS records 23 * @brief blocks used for GNS records
24 * @author Martin Schanzenbach 24 * @author Martin Schanzenbach
25 * @author Christian Grothoff
25 */ 26 */
26 27
27#include "platform.h" 28#include "platform.h"
29#include "gnunet_block_group_lib.h"
28#include "gnunet_block_plugin.h" 30#include "gnunet_block_plugin.h"
29#include "gnunet_namestore_service.h" 31#include "gnunet_namestore_service.h"
30#include "gnunet_signatures.h" 32#include "gnunet_signatures.h"
@@ -36,6 +38,59 @@
36#define BLOOMFILTER_K 16 38#define BLOOMFILTER_K 16
37 39
38/** 40/**
41 * How big is the BF we use for GNS blocks?
42 */
43#define GNS_BF_SIZE 8
44
45
46/**
47 * Create a new block group.
48 *
49 * @param ctx block context in which the block group is created
50 * @param type type of the block for which we are creating the group
51 * @param nonce random value used to seed the group creation
52 * @param raw_data optional serialized prior state of the group, NULL if unavailable/fresh
53 * @param raw_data_size number of bytes in @a raw_data, 0 if unavailable/fresh
54 * @param va variable arguments specific to @a type
55 * @return block group handle, NULL if block groups are not supported
56 * by this @a type of block (this is not an error)
57 */
58static struct GNUNET_BLOCK_Group *
59block_plugin_gns_create_group (void *cls,
60 enum GNUNET_BLOCK_Type type,
61 uint32_t nonce,
62 const void *raw_data,
63 size_t raw_data_size,
64 va_list va)
65{
66 unsigned int bf_size;
67 const char *guard;
68
69 guard = va_arg (va, const char *);
70 if (0 == strcmp (guard,
71 "seen-set-size"))
72 bf_size = GNUNET_BLOCK_GROUP_compute_bloomfilter_size (va_arg (va, unsigned int),
73 BLOOMFILTER_K);
74 else if (0 == strcmp (guard,
75 "filter-size"))
76 bf_size = va_arg (va, unsigned int);
77 else
78 {
79 GNUNET_break (0);
80 bf_size = GNS_BF_SIZE;
81 }
82 GNUNET_break (NULL == va_arg (va, const char *));
83 return GNUNET_BLOCK_GROUP_bf_create (cls,
84 bf_size,
85 BLOOMFILTER_K,
86 type,
87 nonce,
88 raw_data,
89 raw_data_size);
90}
91
92
93/**
39 * Function called to validate a reply or a request. For 94 * Function called to validate a reply or a request. For
40 * request evaluation, simply pass "NULL" for the reply_block. 95 * request evaluation, simply pass "NULL" for the reply_block.
41 * Note that it is assumed that the reply has already been 96 * Note that it is assumed that the reply has already been
@@ -43,11 +98,11 @@
43 * be done with the "get_key" function. 98 * be done with the "get_key" function.
44 * 99 *
45 * @param cls closure 100 * @param cls closure
101 * @param ctx block context
46 * @param type block type 102 * @param type block type
103 * @param bg block group to use for evaluation
47 * @param eo control flags 104 * @param eo control flags
48 * @param query original query (hash) 105 * @param query original query (hash)
49 * @param bf pointer to bloom filter associated with @a query; possibly updated (!)
50 * @param bf_mutator mutation value for @a bf
51 * @param xquery extrended query data (can be NULL, depending on @a type) 106 * @param xquery extrended query data (can be NULL, depending on @a type)
52 * @param xquery_size number of bytes in @a xquery 107 * @param xquery_size number of bytes in @a xquery
53 * @param reply_block response to validate 108 * @param reply_block response to validate
@@ -56,11 +111,11 @@
56 */ 111 */
57static enum GNUNET_BLOCK_EvaluationResult 112static enum GNUNET_BLOCK_EvaluationResult
58block_plugin_gns_evaluate (void *cls, 113block_plugin_gns_evaluate (void *cls,
114 struct GNUNET_BLOCK_Context *ctx,
59 enum GNUNET_BLOCK_Type type, 115 enum GNUNET_BLOCK_Type type,
116 struct GNUNET_BLOCK_Group *bg,
60 enum GNUNET_BLOCK_EvaluationOptions eo, 117 enum GNUNET_BLOCK_EvaluationOptions eo,
61 const struct GNUNET_HashCode *query, 118 const struct GNUNET_HashCode *query,
62 struct GNUNET_CONTAINER_BloomFilter **bf,
63 int32_t bf_mutator,
64 const void *xquery, 119 const void *xquery,
65 size_t xquery_size, 120 size_t xquery_size,
66 const void *reply_block, 121 const void *reply_block,
@@ -69,7 +124,6 @@ block_plugin_gns_evaluate (void *cls,
69 const struct GNUNET_GNSRECORD_Block *block; 124 const struct GNUNET_GNSRECORD_Block *block;
70 struct GNUNET_HashCode h; 125 struct GNUNET_HashCode h;
71 struct GNUNET_HashCode chash; 126 struct GNUNET_HashCode chash;
72 struct GNUNET_HashCode mhash;
73 127
74 if (type != GNUNET_BLOCK_TYPE_GNS_NAMERECORD) 128 if (type != GNUNET_BLOCK_TYPE_GNS_NAMERECORD)
75 return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED; 129 return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED;
@@ -110,21 +164,13 @@ block_plugin_gns_evaluate (void *cls,
110 GNUNET_break_op (0); 164 GNUNET_break_op (0);
111 return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; 165 return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
112 } 166 }
113 if (NULL != bf) 167 GNUNET_CRYPTO_hash (reply_block,
114 { 168 reply_block_size,
115 GNUNET_CRYPTO_hash (reply_block, reply_block_size, &chash); 169 &chash);
116 GNUNET_BLOCK_mingle_hash (&chash, bf_mutator, &mhash); 170 if (GNUNET_YES ==
117 if (NULL != *bf) 171 GNUNET_BLOCK_GROUP_bf_test_and_set (bg,
118 { 172 &chash))
119 if (GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test(*bf, &mhash)) 173 return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
120 return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
121 }
122 else
123 {
124 *bf = GNUNET_CONTAINER_bloomfilter_init(NULL, 8, BLOOMFILTER_K);
125 }
126 GNUNET_CONTAINER_bloomfilter_add(*bf, &mhash);
127 }
128 return GNUNET_BLOCK_EVALUATION_OK_MORE; 174 return GNUNET_BLOCK_EVALUATION_OK_MORE;
129} 175}
130 176
@@ -141,9 +187,11 @@ block_plugin_gns_evaluate (void *cls,
141 * (or if extracting a key from a block of this type does not work) 187 * (or if extracting a key from a block of this type does not work)
142 */ 188 */
143static int 189static int
144block_plugin_gns_get_key (void *cls, enum GNUNET_BLOCK_Type type, 190block_plugin_gns_get_key (void *cls,
145 const void *reply_block, size_t reply_block_size, 191 enum GNUNET_BLOCK_Type type,
146 struct GNUNET_HashCode *key) 192 const void *reply_block,
193 size_t reply_block_size,
194 struct GNUNET_HashCode *key)
147{ 195{
148 const struct GNUNET_GNSRECORD_Block *block; 196 const struct GNUNET_GNSRECORD_Block *block;
149 197
@@ -178,6 +226,7 @@ libgnunet_plugin_block_gns_init (void *cls)
178 api = GNUNET_new (struct GNUNET_BLOCK_PluginFunctions); 226 api = GNUNET_new (struct GNUNET_BLOCK_PluginFunctions);
179 api->evaluate = &block_plugin_gns_evaluate; 227 api->evaluate = &block_plugin_gns_evaluate;
180 api->get_key = &block_plugin_gns_get_key; 228 api->get_key = &block_plugin_gns_get_key;
229 api->create_group = &block_plugin_gns_create_group;
181 api->types = types; 230 api->types = types;
182 return api; 231 return api;
183} 232}
@@ -189,7 +238,7 @@ libgnunet_plugin_block_gns_init (void *cls)
189void * 238void *
190libgnunet_plugin_block_gns_done (void *cls) 239libgnunet_plugin_block_gns_done (void *cls)
191{ 240{
192 struct GNUNET_TRANSPORT_PluginFunctions *api = cls; 241 struct GNUNET_BLOCK_PluginFunctions *api = cls;
193 242
194 GNUNET_free (api); 243 GNUNET_free (api);
195 return NULL; 244 return NULL;
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/gns/plugin_rest_gns.c b/src/gns/plugin_rest_gns.c
index 3cddbc246..b7775e4ea 100644
--- a/src/gns/plugin_rest_gns.c
+++ b/src/gns/plugin_rest_gns.c
@@ -336,10 +336,9 @@ process_lookup_result (void *cls, uint32_t rd_count,
336 * identified by the given public key and the shorten zone. 336 * identified by the given public key and the shorten zone.
337 * 337 *
338 * @param pkey public key to use for the zone, can be NULL 338 * @param pkey public key to use for the zone, can be NULL
339 * @param shorten_key private key used for shortening, can be NULL
340 */ 339 */
341static void 340static void
342lookup_with_keys (struct LookupHandle *handle, const struct GNUNET_CRYPTO_EcdsaPrivateKey *shorten_key) 341lookup_with_public_key (struct LookupHandle *handle)
343{ 342{
344 if (UINT32_MAX == handle->type) 343 if (UINT32_MAX == handle->type)
345 { 344 {
@@ -354,7 +353,6 @@ lookup_with_keys (struct LookupHandle *handle, const struct GNUNET_CRYPTO_EcdsaP
354 &handle->pkey, 353 &handle->pkey,
355 handle->type, 354 handle->type,
356 handle->options, 355 handle->options,
357 shorten_key,
358 &process_lookup_result, 356 &process_lookup_result,
359 handle); 357 handle);
360 } 358 }
@@ -365,55 +363,6 @@ lookup_with_keys (struct LookupHandle *handle, const struct GNUNET_CRYPTO_EcdsaP
365 } 363 }
366} 364}
367 365
368/**
369 * Method called to with the ego we are to use for shortening
370 * during the lookup.
371 *
372 * @param cls closure contains the public key to use
373 * @param ego ego handle, NULL if not found
374 * @param ctx context for application to store data for this ego
375 * (during the lifetime of this process, initially NULL)
376 * @param name name assigned by the user for this ego,
377 * NULL if the user just deleted the ego and it
378 * must thus no longer be used
379 */
380static void
381identity_shorten_cb (void *cls,
382 struct GNUNET_IDENTITY_Ego *ego,
383 void **ctx,
384 const char *name)
385{
386 struct LookupHandle *handle = cls;
387
388 handle->id_op = NULL;
389 if (NULL == ego)
390 lookup_with_keys (handle, NULL);
391 else
392 lookup_with_keys (handle,
393 GNUNET_IDENTITY_ego_get_private_key (ego));
394}
395
396/**
397 * Perform the actual resolution, starting with the zone
398 * identified by the given public key.
399 *
400 * @param pkey public key to use for the zone
401 */
402static void
403lookup_with_public_key (struct LookupHandle *handle)
404{
405 handle->pkeym = handle->pkey;
406 GNUNET_break (NULL == handle->id_op);
407 handle->id_op = GNUNET_IDENTITY_get (handle->identity,
408 "gns-short",
409 &identity_shorten_cb,
410 handle);
411 if (NULL == handle->id_op)
412 {
413 GNUNET_break (0);
414 lookup_with_keys (handle, NULL);
415 }
416}
417 366
418/** 367/**
419 * Method called to with the ego we are to use for the lookup, 368 * Method called to with the ego we are to use for the lookup,
@@ -444,6 +393,7 @@ identity_zone_cb (void *cls,
444 json_decref(handle->json_root); 393 json_decref(handle->json_root);
445} 394}
446 395
396
447/** 397/**
448 * Method called to with the ego we are to use for the lookup, 398 * Method called to with the ego we are to use for the lookup,
449 * when the ego is the one for the default master zone. 399 * when the ego is the one for the default master zone.
@@ -579,6 +529,7 @@ get_gns_cont (struct GNUNET_REST_RequestHandle *conndata_handle,
579 { 529 {
580 handle->pkey_str = GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map, 530 handle->pkey_str = GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map,
581 &key); 531 &key);
532 GNUNET_assert (NULL != handle->pkey_str);
582 if (GNUNET_OK != 533 if (GNUNET_OK !=
583 GNUNET_CRYPTO_ecdsa_public_key_from_string (handle->pkey_str, 534 GNUNET_CRYPTO_ecdsa_public_key_from_string (handle->pkey_str,
584 strlen(handle->pkey_str), 535 strlen(handle->pkey_str),
diff --git a/src/gns/test_gns_nick_shorten.sh b/src/gns/test_gns_nick_shorten.sh
deleted file mode 100755
index df69bbba9..000000000
--- a/src/gns/test_gns_nick_shorten.sh
+++ /dev/null
@@ -1,124 +0,0 @@
1#!/bin/bash
2trap "gnunet-arm -e -c test_gns_nick_shorten.conf" SIGINT
3which timeout &> /dev/null && DO_TIMEOUT="timeout 5"
4
5# This test tests shortening functionality based on NICK records:
6#
7# zone "delegatedego": Alice's zone
8# zone "testego": Local zone with delegation to alice
9
10LOCATION=$(which gnunet-config)
11if [ -z $LOCATION ]
12then
13 LOCATION="gnunet-config"
14fi
15$LOCATION --version 1> /dev/null
16if test $? != 0
17then
18 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
19 exit 77
20fi
21
22# Deleting home directory from previous runs
23TEST_CONFIG="test_gns_nick_shorten.conf "
24rm -rf /tmp/test-gnunet-gns-peer-1/
25TEST_IP="127.0.0.1"
26TEST_IP="127.0.0.2"
27TEST_NICK_EGO="ego"
28TEST_NICK_DELEGATED="alice"
29TEST_NAME="www.mybestfriendalice.gnu"
30TEST_NAME_SHORT="www.alice.short.gnu"
31
32# export GNUNET_FORCE_LOG="namestore;;;;DEBUG/gns;;;;DEBUG/;;;;WARNING"
33
34# Start gnunet
35echo "Starting arm with configuration $TEST_CONFIG"
36gnunet-arm -s -c $TEST_CONFIG
37
38# Create initial identities: short-zone, delegated-zone, testego
39echo "Creating identities"
40gnunet-identity -d -c $TEST_CONFIG
41gnunet-identity -C short-zone -c $TEST_CONFIG
42gnunet-identity -C delegatedego -c $TEST_CONFIG
43gnunet-identity -e short-zone -s gns-short -c $TEST_CONFIG
44gnunet-identity -C testego -c $TEST_CONFIG
45
46echo "Adding nick names for identities"
47gnunet-namestore -z testego -i $TEST_NICK_EGO -c $TEST_CONFIG
48gnunet-namestore -z delegatedego -i $TEST_NICK_DELEGATED -c $TEST_CONFIG
49
50# Adding label www in Alice's delegatedego zone
51echo "Adding www record with IP $TEST_IP"
52gnunet-namestore -p -z delegatedego -a -n www -t A -V $TEST_IP -e never -c test_gns_nick_shorten.conf
53
54# Retrieve PKEYs for delegation
55DELEGATED_PKEY=$(gnunet-identity -d -c $TEST_CONFIG| grep delegatedego | awk '{print $3}')
56echo "Alice's PKEY is $DELEGATED_PKEY"
57
58SHORTEN_PKEY=$(gnunet-identity -c test_gns_nick_shorten.conf -d | grep short-zone | awk '{print $3}')
59echo "Shorten PKEY is $SHORTEN_PKEY"
60
61# Delegate the name "short" to shortenzone
62gnunet-namestore -p -z testego -a -n short -t PKEY -V $SHORTEN_PKEY -e never -c test_gns_nick_shorten.conf
63
64# Delegate the name "mybestfriendalice" to alice
65gnunet-namestore -p -z testego -a -n mybestfriendalice -t PKEY -V $DELEGATED_PKEY -e never -c test_gns_nick_shorten.conf
66
67# Perform lookup to shorten
68echo "Start gns..."
69gnunet-arm -c test_gns_nick_shorten.conf -i gns
70
71
72RES_IP=`$DO_TIMEOUT gnunet-gns --raw -z testego -u $TEST_NAME -t A -c test_gns_nick_shorten.conf`
73
74sleep 1
75
76echo "Lookup shortened names"
77PKEY_SHORT_RES=$($DO_TIMEOUT gnunet-gns --raw -c test_gns_nick_shorten.conf -z short-zone -u alice.gnu -t PKEY)
78echo "Resolving alice's PKEY in shorten zone: $PKEY_SHORT_RES"
79PKEY_RES=$($DO_TIMEOUT gnunet-gns --raw -c test_gns_nick_shorten.conf -z testego -u alice.short.gnu -t PKEY)
80echo "Resolving alice's PKEY in master zone: $PKEY_RES"
81
82RES=0
83if [ "$DELEGATED_PKEY" == "$PKEY_SHORT_RES" ]
84then
85 echo "PASS: Resolved delegation for shorten name in shortened zone"
86else
87 echo "FAIL: Expected PKEY in $DELEGATED_PKEY, received PKEY '$PKEY_SHORT_RES' in shorten zone."
88 RES=1
89fi
90
91if [ "$DELEGATED_PKEY" == "$PKEY_RES" ]
92then
93 echo "PASS: Resolved delegation for shorten name in master zone"
94else
95 echo "FAIL: Expected PKEY in $DELEGATED_PKEY, received PKEY $PKEY_SHORT_RES in master zone."
96 RES=1
97fi
98
99if [ $RES -eq 0 ]
100then
101 RES_IP=`$DO_TIMEOUT gnunet-gns --raw -z testego -u $TEST_NAME_SHORT -t A -c test_gns_nick_shorten.conf`
102 if [ "$RES_IP" == "$TEST_IP" ]
103 then
104 echo "PASS: Received $TEST_IP for $TEST_NAME_SHORT"
105 else
106 echo "FAIL: Expected IP in $TEST_IP, received IP '$RES_IP' for $TEST_SHORT_NAME."
107 RES=1
108 fi
109fi
110
111
112# Clean up
113echo "Clean up..."
114gnunet-namestore -z testego -d -n mybestfriendalice -t PKEY -V $DELEGATED_PKEY -e never -c test_gns_nick_shorten.conf
115gnunet-namestore -z delegatedego -d -n www -t A -V $TEST_IP -e never -c test_gns_nick_shorten.conf
116gnunet-identity -D -z testego -c $TEST_CONFIG
117gnunet-identity -D -z delegatedego -c $TEST_CONFIG
118gnunet-identity -D -z short-zone -c $TEST_CONFIG
119
120gnunet-arm -e -c test_gns_nick_shorten.conf
121rm -rf /tmp/test-gnunet-gns-peer-1/
122
123exit $RES
124
diff --git a/src/gns/test_gns_reverse_lookup.sh b/src/gns/test_gns_reverse_lookup.sh
deleted file mode 100755
index 189adef11..000000000
--- a/src/gns/test_gns_reverse_lookup.sh
+++ /dev/null
@@ -1,50 +0,0 @@
1#!/bin/bash
2trap "gnunet-arm -e -c test_gns_lookup.conf" SIGINT
3which timeout &> /dev/null && DO_TIMEOUT="timeout 30"
4
5LOCATION=$(which gnunet-config)
6if [ -z $LOCATION ]
7then
8 LOCATION="gnunet-config"
9fi
10$LOCATION --version 1> /dev/null
11if test $? != 0
12then
13 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
14 exit 77
15fi
16
17TEST_NAME="dave.bob.alice.gnu"
18gnunet-arm -s -c test_gns_lookup.conf
19gnunet-identity -C bob -c test_gns_lookup.conf
20BOB_PKEY=$(gnunet-identity -d -c test_gns_lookup.conf | grep bob | awk '{print $3}')
21gnunet-identity -C daveego -c test_gns_lookup.conf
22DAVE_PKEY=$(gnunet-identity -d -c test_gns_lookup.conf | grep dave | awk '{print $3}')
23gnunet-identity -C aliceego -c test_gns_lookup.conf
24ALICE_PKEY=$(gnunet-identity -d -c test_gns_lookup.conf | grep alice | awk '{print $3}')
25gnunet-identity -C testego -c test_gns_lookup.conf
26ROOT_PKEY=$(gnunet-identity -d -c test_gns_lookup.conf | grep testego | awk '{print $3}')
27
28gnunet-identity -s gns-reverse -e bob -c test_gns_lookup.conf
29
30gnunet-namestore -p -z testego -a -n alice -t PKEY -V $ALICE_PKEY -e never -c test_gns_lookup.conf
31gnunet-namestore -p -z aliceego -a -n bob -t PKEY -V $BOB_PKEY -e never -c test_gns_lookup.conf
32gnunet-namestore -p -z aliceego -a -n + -t REVERSE -V "alice $ROOT_PKEY 0" -e never -c test_gns_lookup.conf
33gnunet-namestore -p -z bob -a -n dave -t PKEY -V $DAVE_PKEY -e never -c test_gns_lookup.conf
34gnunet-namestore -p -z bob -a -n alice -t PKEY -V $ALICE_PKEY -e never -c test_gns_lookup.conf
35#gnunet-namestore -p -z bob -a -n + -t REVERSE -V "bob $ALICE_PKEY 0" -e never -c test_gns_lookup.conf
36gnunet-namestore -p -z daveego -a -n + -t REVERSE -V "dave $BOB_PKEY 0" -e never -c test_gns_lookup.conf
37gnunet-namestore -p -z daveego -a -n bob -t PKEY -V $BOB_PKEY -e never -c test_gns_lookup.conf
38gnunet-arm -i gns -c test_gns_lookup.conf
39sleep 10
40RES_NAME=`$DO_TIMEOUT gnunet-gns --raw -z testego -R $DAVE_PKEY -c test_gns_lookup.conf`
41gnunet-arm -e -c test_gns_lookup.conf
42rm -rf /tmp/test-gnunet-gns-peer-1/
43
44if [ "$RES_NAME" == "$TEST_NAME" ]
45then
46 exit 0
47else
48 echo "Failed to resolve to proper IP, got $RES_IP."
49 exit 1
50fi
diff --git a/src/gns/w32nsp-resolve.c b/src/gns/w32nsp-resolve.c
index 1de1a3657..82f15c6cc 100644
--- a/src/gns/w32nsp-resolve.c
+++ b/src/gns/w32nsp-resolve.c
@@ -22,6 +22,9 @@
22 * @brief W32 integration for GNS 22 * @brief W32 integration for GNS
23 * @author LRN 23 * @author LRN
24 */ 24 */
25/* Instead of including gnunet_common.h */
26#define GNUNET_memcpy(dst,src,n) do { if (0 != n) { (void) memcpy (dst,src,n); } } while (0)
27
25#include <ws2tcpip.h> 28#include <ws2tcpip.h>
26#include <windows.h> 29#include <windows.h>
27#include <nspapi.h> 30#include <nspapi.h>
diff --git a/src/gnsrecord/Makefile.am b/src/gnsrecord/Makefile.am
index e32751247..2fb427c69 100644
--- a/src/gnsrecord/Makefile.am
+++ b/src/gnsrecord/Makefile.am
@@ -22,7 +22,7 @@ check_PROGRAMS = \
22 test_gnsrecord_block_expiration 22 test_gnsrecord_block_expiration
23 23
24if ENABLE_TEST_RUN 24if ENABLE_TEST_RUN
25AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; 25AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
26TESTS = \ 26TESTS = \
27 $(check_PROGRAMS) \ 27 $(check_PROGRAMS) \
28 $(check_SCRIPTS) 28 $(check_SCRIPTS)
diff --git a/src/hello/Makefile.am b/src/hello/Makefile.am
index 563bcafb2..79003301b 100644
--- a/src/hello/Makefile.am
+++ b/src/hello/Makefile.am
@@ -29,7 +29,7 @@ check_PROGRAMS = \
29 test_friend_hello 29 test_friend_hello
30 30
31if ENABLE_TEST_RUN 31if ENABLE_TEST_RUN
32AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; 32AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
33TESTS = $(check_PROGRAMS) 33TESTS = $(check_PROGRAMS)
34endif 34endif
35 35
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/Makefile.am b/src/hostlist/Makefile.am
index 31ce5bf62..17f0bdfa0 100644
--- a/src/hostlist/Makefile.am
+++ b/src/hostlist/Makefile.am
@@ -70,7 +70,7 @@ endif
70 70
71if HAVE_MHD 71if HAVE_MHD
72if ENABLE_TEST_RUN 72if ENABLE_TEST_RUN
73AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; 73AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
74TESTS = \ 74TESTS = \
75 $(check_PROGRAMS) 75 $(check_PROGRAMS)
76endif 76endif
diff --git a/src/hostlist/gnunet-daemon-hostlist.c b/src/hostlist/gnunet-daemon-hostlist.c
index a83d46e07..854340d3d 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_flag ('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_flag ('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_flag ('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_flag ('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..30b63bfc4 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_flag ('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/gnunet-service-identity-provider.c b/src/identity-provider/gnunet-service-identity-provider.c
index e97be55d1..f9e06fef9 100644
--- a/src/identity-provider/gnunet-service-identity-provider.c
+++ b/src/identity-provider/gnunet-service-identity-provider.c
@@ -480,6 +480,7 @@ handle_token_update (void *cls)
480 { 480 {
481 cur_value = GNUNET_CONTAINER_multihashmap_get (ego_entry->attr_map, 481 cur_value = GNUNET_CONTAINER_multihashmap_get (ego_entry->attr_map,
482 &key_hash); 482 &key_hash);
483 GNUNET_assert (NULL != cur_value);
483 GNUNET_CONTAINER_DLL_insert (new_token->attr_head, 484 GNUNET_CONTAINER_DLL_insert (new_token->attr_head,
484 new_token->attr_tail, 485 new_token->attr_tail,
485 cur_value); 486 cur_value);
@@ -752,7 +753,7 @@ attribute_collect (void *cls,
752 GNUNET_CONTAINER_DLL_insert (attr->val_head, 753 GNUNET_CONTAINER_DLL_insert (attr->val_head,
753 attr->val_tail, 754 attr->val_tail,
754 val); 755 val);
755 GNUNET_assert (GNUNET_OK == 756 GNUNET_assert (GNUNET_OK ==
756 GNUNET_CONTAINER_multihashmap_put (ego_entry->attr_map, 757 GNUNET_CONTAINER_multihashmap_put (ego_entry->attr_map,
757 &key, 758 &key,
758 attr, 759 attr,
@@ -989,7 +990,7 @@ create_issue_result_message (const char* label,
989 struct IssueResultMessage *irm; 990 struct IssueResultMessage *irm;
990 char *tmp_str; 991 char *tmp_str;
991 size_t len; 992 size_t len;
992 993
993 GNUNET_asprintf (&tmp_str, "%s,%s,%s", label, ticket, token); 994 GNUNET_asprintf (&tmp_str, "%s,%s,%s", label, ticket, token);
994 len = strlen (tmp_str) + 1; 995 len = strlen (tmp_str) + 1;
995 env = GNUNET_MQ_msg_extra (irm, 996 env = GNUNET_MQ_msg_extra (irm,
@@ -1430,7 +1431,7 @@ check_exchange_message (void *cls,
1430 return GNUNET_SYSERR; 1431 return GNUNET_SYSERR;
1431 } 1432 }
1432 return GNUNET_OK; 1433 return GNUNET_OK;
1433} 1434}
1434 1435
1435/** 1436/**
1436 * 1437 *
@@ -1477,7 +1478,6 @@ handle_exchange_message (void *cls,
1477 &xchange_handle->ticket->payload->identity_key, 1478 &xchange_handle->ticket->payload->identity_key,
1478 GNUNET_GNSRECORD_TYPE_ID_TOKEN, 1479 GNUNET_GNSRECORD_TYPE_ID_TOKEN,
1479 GNUNET_GNS_LO_LOCAL_MASTER, 1480 GNUNET_GNS_LO_LOCAL_MASTER,
1480 NULL,
1481 &process_lookup_result, 1481 &process_lookup_result,
1482 xchange_handle); 1482 xchange_handle);
1483 GNUNET_free (lookup_query); 1483 GNUNET_free (lookup_query);
diff --git a/src/identity-provider/identity_provider_api.c b/src/identity-provider/identity_provider_api.c
index 21ec235b6..04e3a54f9 100644
--- a/src/identity-provider/identity_provider_api.c
+++ b/src/identity-provider/identity_provider_api.c
@@ -499,7 +499,7 @@ GNUNET_IDENTITY_PROVIDER_exchange_ticket (struct GNUNET_IDENTITY_PROVIDER_Handle
499 ticket_str = GNUNET_IDENTITY_PROVIDER_ticket_to_string (ticket); 499 ticket_str = GNUNET_IDENTITY_PROVIDER_ticket_to_string (ticket);
500 500
501 slen = strlen (ticket_str) + 1; 501 slen = strlen (ticket_str) + 1;
502 if (slen >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct ExchangeMessage)) 502 if (slen >= GNUNET_MAX_MESSAGE_SIZE - sizeof (struct ExchangeMessage))
503 { 503 {
504 GNUNET_free (ticket_str); 504 GNUNET_free (ticket_str);
505 GNUNET_break (0); 505 GNUNET_break (0);
diff --git a/src/identity-provider/plugin_rest_identity_provider.c b/src/identity-provider/plugin_rest_identity_provider.c
index cd0c76989..5ea7b2821 100644
--- a/src/identity-provider/plugin_rest_identity_provider.c
+++ b/src/identity-provider/plugin_rest_identity_provider.c
@@ -602,6 +602,7 @@ issue_token_cont (struct GNUNET_REST_RequestHandle *con,
602 } 602 }
603 nonce_str = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map, 603 nonce_str = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
604 &key); 604 &key);
605 GNUNET_assert (NULL != nonce_str);
605 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 606 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
606 "Request nonce: %s\n", 607 "Request nonce: %s\n",
607 nonce_str); 608 nonce_str);
@@ -817,6 +818,7 @@ list_token_cont (struct GNUNET_REST_RequestHandle *con_handle,
817 } 818 }
818 ego_val = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map, 819 ego_val = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
819 &key); 820 &key);
821 GNUNET_assert (NULL != ego_val);
820 //Remove non-matching egos 822 //Remove non-matching egos
821 for (ego_entry = handle->ego_head; 823 for (ego_entry = handle->ego_head;
822 NULL != ego_entry;) 824 NULL != ego_entry;)
@@ -889,6 +891,7 @@ exchange_cont (void *cls,
889 } 891 }
890 nonce_str = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map, 892 nonce_str = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
891 &key); 893 &key);
894 GNUNET_assert (NULL != nonce_str);
892 GNUNET_assert (1 == sscanf (nonce_str, "%"SCNu64, &expected_nonce)); 895 GNUNET_assert (1 == sscanf (nonce_str, "%"SCNu64, &expected_nonce));
893 896
894 if (ticket_nonce != expected_nonce) 897 if (ticket_nonce != expected_nonce)
diff --git a/src/identity/Makefile.am b/src/identity/Makefile.am
index c6f6625f4..94e8c5e94 100644
--- a/src/identity/Makefile.am
+++ b/src/identity/Makefile.am
@@ -92,7 +92,7 @@ check_PROGRAMS = \
92endif 92endif
93 93
94if ENABLE_TEST_RUN 94if ENABLE_TEST_RUN
95AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; 95AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
96TESTS = $(check_PROGRAMS) 96TESTS = $(check_PROGRAMS)
97endif 97endif
98 98
diff --git a/src/identity/gnunet-identity.c b/src/identity/gnunet-identity.c
index f632aa0a8..9b66a1bc7 100644
--- a/src/identity/gnunet-identity.c
+++ b/src/identity/gnunet-identity.c
@@ -29,6 +29,12 @@
29#include "gnunet_util_lib.h" 29#include "gnunet_util_lib.h"
30#include "gnunet_identity_service.h" 30#include "gnunet_identity_service.h"
31 31
32
33/**
34 * Return value from main on timeout.
35 */
36#define TIMEOUT_STATUS_CODE 40
37
32/** 38/**
33 * Handle to IDENTITY service. 39 * Handle to IDENTITY service.
34 */ 40 */
@@ -79,6 +85,11 @@ static struct GNUNET_IDENTITY_Operation *create_op;
79 */ 85 */
80static struct GNUNET_IDENTITY_Operation *delete_op; 86static struct GNUNET_IDENTITY_Operation *delete_op;
81 87
88/**
89 * Value to return from #main().
90 */
91static int global_ret;
92
82 93
83/** 94/**
84 * Task run on shutdown. 95 * Task run on shutdown.
@@ -120,7 +131,11 @@ test_finished ()
120 (NULL == set_ego) && 131 (NULL == set_ego) &&
121 (! list) && 132 (! list) &&
122 (! monitor) ) 133 (! monitor) )
134 {
135 if (TIMEOUT_STATUS_CODE == global_ret)
136 global_ret = 0;
123 GNUNET_SCHEDULER_shutdown (); 137 GNUNET_SCHEDULER_shutdown ();
138 }
124} 139}
125 140
126 141
@@ -159,9 +174,12 @@ create_finished (void *cls,
159 174
160 *op = NULL; 175 *op = NULL;
161 if (NULL != emsg) 176 if (NULL != emsg)
177 {
162 fprintf (stderr, 178 fprintf (stderr,
163 _("Failed to create ego: %s\n"), 179 _("Failed to create ego: %s\n"),
164 emsg); 180 emsg);
181 global_ret = 1;
182 }
165 test_finished (); 183 test_finished ();
166} 184}
167 185
@@ -178,9 +196,12 @@ set_done (void *cls,
178{ 196{
179 set_op = NULL; 197 set_op = NULL;
180 if (NULL != emsg) 198 if (NULL != emsg)
199 {
181 fprintf (stderr, 200 fprintf (stderr,
182 _("Failed to set default ego: %s\n"), 201 _("Failed to set default ego: %s\n"),
183 emsg); 202 emsg);
203 global_ret = 1;
204 }
184 test_finished (); 205 test_finished ();
185} 206}
186 207
@@ -257,17 +278,23 @@ print_ego (void *cls,
257 } 278 }
258 if ( (NULL == ego) && (! monitor) ) 279 if ( (NULL == ego) && (! monitor) )
259 { 280 {
260 GNUNET_SCHEDULER_shutdown (); 281 list = 0;
282 test_finished ();
261 return; 283 return;
262 } 284 }
263 if (! (list | monitor)) 285 if (! (list | monitor))
264 return; 286 return;
265 if (NULL == ego) 287 if (NULL == ego)
266 return; 288 return;
267 GNUNET_IDENTITY_ego_get_public_key (ego, &pk); 289 GNUNET_IDENTITY_ego_get_public_key (ego,
290 &pk);
268 s = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk); 291 s = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
269 if ( (monitor) || (NULL != identifier) ) 292 if ( (monitor) ||
270 fprintf (stdout, "%s - %s\n", identifier, s); 293 (NULL != identifier) )
294 fprintf (stdout,
295 "%s - %s\n",
296 identifier,
297 s);
271 GNUNET_free (s); 298 GNUNET_free (s);
272} 299}
273 300
@@ -281,7 +308,9 @@ print_ego (void *cls,
281 * @param cfg configuration 308 * @param cfg configuration
282 */ 309 */
283static void 310static void
284run (void *cls, char *const *args, const char *cfgfile, 311run (void *cls,
312 char *const *args,
313 const char *cfgfile,
285 const struct GNUNET_CONFIGURATION_Handle *cfg) 314 const struct GNUNET_CONFIGURATION_Handle *cfg)
286{ 315{
287 if ( (NULL == set_subsystem) ^ 316 if ( (NULL == set_subsystem) ^
@@ -291,7 +320,9 @@ run (void *cls, char *const *args, const char *cfgfile,
291 "Options -e and -s must always be specified together\n"); 320 "Options -e and -s must always be specified together\n");
292 return; 321 return;
293 } 322 }
294 sh = GNUNET_IDENTITY_connect (cfg, &print_ego, NULL); 323 sh = GNUNET_IDENTITY_connect (cfg,
324 &print_ego,
325 NULL);
295 if (NULL != delete_ego) 326 if (NULL != delete_ego)
296 delete_op = GNUNET_IDENTITY_delete (sh, 327 delete_op = GNUNET_IDENTITY_delete (sh,
297 delete_ego, 328 delete_ego,
@@ -302,7 +333,8 @@ run (void *cls, char *const *args, const char *cfgfile,
302 create_ego, 333 create_ego,
303 &create_finished, 334 &create_finished,
304 &create_op); 335 &create_op);
305 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); 336 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
337 NULL);
306 test_finished (); 338 test_finished ();
307} 339}
308 340
@@ -317,42 +349,60 @@ run (void *cls, char *const *args, const char *cfgfile,
317int 349int
318main (int argc, char *const *argv) 350main (int argc, char *const *argv)
319{ 351{
320 int res; 352 struct GNUNET_GETOPT_CommandLineOption options[] = {
353 GNUNET_GETOPT_option_string ('C',
354 "create",
355 "NAME",
356 gettext_noop ("create ego NAME"),
357 &create_ego),
358
359 GNUNET_GETOPT_option_string ('D',
360 "delete",
361 "NAME",
362 gettext_noop ("delete ego NAME "),
363 &delete_ego),
364
365 GNUNET_GETOPT_option_flag ('d',
366 "display",
367 gettext_noop ("display all egos"),
368 &list),
369
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_flag ('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),
321 386
322 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
323 {'C', "create", "NAME",
324 gettext_noop ("create ego NAME"),
325 1, &GNUNET_GETOPT_set_string, &create_ego},
326 {'D', "delete", "NAME",
327 gettext_noop ("delete ego NAME "),
328 1, &GNUNET_GETOPT_set_string, &delete_ego},
329 {'d', "display", NULL,
330 gettext_noop ("display all egos"),
331 0, &GNUNET_GETOPT_set_one, &list},
332 {'e', "ego", "NAME",
333 gettext_noop ("set default identity to EGO for a subsystem SUBSYSTEM (use together with -s)"),
334 1, &GNUNET_GETOPT_set_string, &set_ego},
335 {'m', "monitor", NULL,
336 gettext_noop ("run in monitor mode egos"),
337 0, &GNUNET_GETOPT_set_one, &monitor},
338 {'s', "set", "SUBSYSTEM",
339 gettext_noop ("set default identity to EGO for a subsystem SUBSYSTEM (use together with -e)"),
340 1, &GNUNET_GETOPT_set_string, &set_subsystem},
341 GNUNET_GETOPT_OPTION_END 387 GNUNET_GETOPT_OPTION_END
342 }; 388 };
389 int res;
343 390
344 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) 391 if (GNUNET_OK !=
345 return 2; 392 GNUNET_STRINGS_get_utf8_args (argc, argv,
346 393 &argc, &argv))
347 res = GNUNET_PROGRAM_run (argc, argv, "gnunet-identity", 394 return 4;
395 global_ret = TIMEOUT_STATUS_CODE; /* timeout */
396 res = GNUNET_PROGRAM_run (argc, argv,
397 "gnunet-identity",
348 gettext_noop ("Maintain egos"), 398 gettext_noop ("Maintain egos"),
349 options, &run, 399 options, &run,
350 NULL); 400 NULL);
351 GNUNET_free ((void *) argv); 401 GNUNET_free ((void *) argv);
352 402
353 if (GNUNET_OK != res) 403 if (GNUNET_OK != res)
354 return 1; 404 return 3;
355 return 0; 405 return global_ret;
356} 406}
357 407
358/* end of gnunet-identity.c */ 408/* end of gnunet-identity.c */
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 bf3ffe482..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,13 +106,13 @@ 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 \
114 gnunet_signatures.h \ 112 gnunet_signatures.h \
115 gnunet_social_service.h \ 113 gnunet_social_service.h \
116 gnunet_speaker_lib.h \ 114 gnunet_speaker_lib.h \
115 gnunet_sq_lib.h \
117 gnunet_statistics_service.h \ 116 gnunet_statistics_service.h \
118 gnunet_strings_lib.h \ 117 gnunet_strings_lib.h \
119 gnunet_testbed_service.h \ 118 gnunet_testbed_service.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_block_group_lib.h b/src/include/gnunet_block_group_lib.h
new file mode 100644
index 000000000..3a3dfb2e2
--- /dev/null
+++ b/src/include/gnunet_block_group_lib.h
@@ -0,0 +1,114 @@
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 * @author Christian Grothoff
23 *
24 * @file
25 * Library for creating block groups (to be used by block plugins)
26 *
27 * @defgroup block Block group library
28 * Library for data group management
29 * @{
30 */
31#ifndef GNUNET_BLOCK_GROUP_LIB_H
32#define GNUNET_BLOCK_GROUP_LIB_H
33
34#include "gnunet_util_lib.h"
35#include "gnunet_block_lib.h"
36
37#ifdef __cplusplus
38extern "C"
39{
40#if 0 /* keep Emacsens' auto-indent happy */
41}
42#endif
43#endif
44
45
46/**
47 * How many bytes should a bloomfilter be if we have already seen
48 * entry_count responses? Sized so that do not have to
49 * re-size the filter too often (to keep it cheap).
50 *
51 * Since other peers will also add entries but not resize the filter,
52 * we should generally pick a slightly larger size than what the
53 * strict math would suggest.
54 *
55 * @param entry_count expected number of entries in the Bloom filter
56 * @param k number of bits set per entry
57 * @return must be a power of two and smaller or equal to 2^15.
58 */
59size_t
60GNUNET_BLOCK_GROUP_compute_bloomfilter_size (unsigned int entry_count,
61 unsigned int k);
62
63
64/**
65 * Create a new block group that filters duplicates using a Bloom filter.
66 *
67 * @param ctx block context in which the block group is created
68 * @param bf_size size of the Bloom filter
69 * @param bf_k K-value for the Bloom filter
70 * @param type block type
71 * @param nonce random value used to seed the group creation
72 * @param raw_data optional serialized prior state of the group, NULL if unavailable/fresh
73 * @param raw_data_size number of bytes in @a raw_data, 0 if unavailable/fresh
74 * @return block group handle, NULL if block groups are not supported
75 * by this @a type of block (this is not an error)
76 */
77struct GNUNET_BLOCK_Group *
78GNUNET_BLOCK_GROUP_bf_create (void *cls,
79 size_t bf_size,
80 unsigned int bf_k,
81 enum GNUNET_BLOCK_Type type,
82 uint32_t nonce,
83 const void *raw_data,
84 size_t raw_data_size);
85
86
87/**
88 * Test if @a hc is contained in the Bloom filter of @a bg. If so,
89 * return #GNUNET_YES. If not, add @a hc to the Bloom filter and
90 * return #GNUNET_NO.
91 *
92 * @param bg block group to use for testing
93 * @param hc hash of element to evaluate
94 * @return #GNUNET_YES if @a hc is (likely) a duplicate
95 * #GNUNET_NO if @a hc was definitively not in @bg (but now is)
96 */
97int
98GNUNET_BLOCK_GROUP_bf_test_and_set (struct GNUNET_BLOCK_Group *bg,
99 const struct GNUNET_HashCode *hc);
100
101
102#if 0 /* keep Emacsens' auto-indent happy */
103{
104#endif
105#ifdef __cplusplus
106}
107#endif
108
109/* ifndef GNUNET_BLOCK_GROUP_LIB_H */
110#endif
111
112/** @} */ /* end of group */
113
114/* end of gnunet_block_group_lib.h */
diff --git a/src/include/gnunet_block_lib.h b/src/include/gnunet_block_lib.h
index b21b3496b..d8ee68c21 100644
--- a/src/include/gnunet_block_lib.h
+++ b/src/include/gnunet_block_lib.h
@@ -112,6 +112,11 @@ enum GNUNET_BLOCK_Type
112 GNUNET_BLOCK_TYPE_GNS_NAMERECORD = 11, 112 GNUNET_BLOCK_TYPE_GNS_NAMERECORD = 11,
113 113
114 /** 114 /**
115 * Block type for a revocation message by which a key is revoked.
116 */
117 GNUNET_BLOCK_TYPE_REVOCATION = 12,
118
119 /**
115 * Block to store a cadet regex state 120 * Block to store a cadet regex state
116 */ 121 */
117 GNUNET_BLOCK_TYPE_REGEX = 22, 122 GNUNET_BLOCK_TYPE_REGEX = 22,
@@ -119,7 +124,19 @@ enum GNUNET_BLOCK_Type
119 /** 124 /**
120 * Block to store a cadet regex accepting state 125 * Block to store a cadet regex accepting state
121 */ 126 */
122 GNUNET_BLOCK_TYPE_REGEX_ACCEPT = 23 127 GNUNET_BLOCK_TYPE_REGEX_ACCEPT = 23,
128
129 /**
130 * Block for testing set/consensus. If first byte of the block
131 * is non-zero, the block is considered invalid.
132 */
133 GNUNET_BLOCK_TYPE_SET_TEST = 24,
134
135 /**
136 * Block type for consensus elements.
137 * Contains either special marker elements or a nested block.
138 */
139 GNUNET_BLOCK_TYPE_CONSENSUS_ELEMENT = 25,
123}; 140};
124 141
125 142
@@ -230,6 +247,61 @@ GNUNET_BLOCK_context_destroy (struct GNUNET_BLOCK_Context *ctx);
230 247
231 248
232/** 249/**
250 * Handle for a group of elements that will be evaluated together.
251 * They must all be of the same type. A block group allows the
252 * plugin to keep some state across individual evaluations.
253 */
254struct GNUNET_BLOCK_Group;
255
256
257/**
258 * Create a new block group.
259 *
260 * @param ctx block context in which the block group is created
261 * @param type type of the block for which we are creating the group
262 * @param nonce random value used to seed the group creation
263 * @param raw_data optional serialized prior state of the group, NULL if unavailable/fresh
264 * @param raw_data_size number of bytes in @a raw_data, 0 if unavailable/fresh
265 * @param ... type-specific additional data, can be empty
266 * @return block group handle, NULL if block groups are not supported
267 * by this @a type of block (this is not an error)
268 */
269struct GNUNET_BLOCK_Group *
270GNUNET_BLOCK_group_create (struct GNUNET_BLOCK_Context *ctx,
271 enum GNUNET_BLOCK_Type type,
272 uint32_t nonce,
273 const void *raw_data,
274 size_t raw_data_size,
275 ...);
276
277
278/**
279 * Serialize state of a block group.
280 *
281 * @param bg group to serialize
282 * @param[out] nonce set to the nonce of the @a bg
283 * @param[out] raw_data set to the serialized state
284 * @param[out] raw_data_size set to the number of bytes in @a raw_data
285 * @return #GNUNET_OK on success, #GNUNET_NO if serialization is not
286 * supported, #GNUNET_SYSERR on error
287 */
288int
289GNUNET_BLOCK_group_serialize (struct GNUNET_BLOCK_Group *bg,
290 uint32_t *nonce,
291 void **raw_data,
292 size_t *raw_data_size);
293
294
295/**
296 * Destroy resources used by a block group.
297 *
298 * @param bg group to destroy, NULL is allowed
299 */
300void
301GNUNET_BLOCK_group_destroy (struct GNUNET_BLOCK_Group *bg);
302
303
304/**
233 * Function called to validate a reply or a request. For 305 * Function called to validate a reply or a request. For
234 * request evaluation, simply pass "NULL" for the @a reply_block. 306 * request evaluation, simply pass "NULL" for the @a reply_block.
235 * Note that it is assumed that the reply has already been 307 * Note that it is assumed that the reply has already been
@@ -238,10 +310,9 @@ GNUNET_BLOCK_context_destroy (struct GNUNET_BLOCK_Context *ctx);
238 * 310 *
239 * @param ctx block contxt 311 * @param ctx block contxt
240 * @param type block type 312 * @param type block type
313 * @param group block group to use for evaluation
241 * @param eo evaluation options to control evaluation 314 * @param eo evaluation options to control evaluation
242 * @param query original query (hash) 315 * @param query original query (hash)
243 * @param bf pointer to bloom filter associated with query; possibly updated (!)
244 * @param bf_mutator mutation value for @a bf
245 * @param xquery extrended query data (can be NULL, depending on type) 316 * @param xquery extrended query data (can be NULL, depending on type)
246 * @param xquery_size number of bytes in @a xquery 317 * @param xquery_size number of bytes in @a xquery
247 * @param reply_block response to validate 318 * @param reply_block response to validate
@@ -251,10 +322,9 @@ GNUNET_BLOCK_context_destroy (struct GNUNET_BLOCK_Context *ctx);
251enum GNUNET_BLOCK_EvaluationResult 322enum GNUNET_BLOCK_EvaluationResult
252GNUNET_BLOCK_evaluate (struct GNUNET_BLOCK_Context *ctx, 323GNUNET_BLOCK_evaluate (struct GNUNET_BLOCK_Context *ctx,
253 enum GNUNET_BLOCK_Type type, 324 enum GNUNET_BLOCK_Type type,
325 struct GNUNET_BLOCK_Group *group,
254 enum GNUNET_BLOCK_EvaluationOptions eo, 326 enum GNUNET_BLOCK_EvaluationOptions eo,
255 const struct GNUNET_HashCode *query, 327 const struct GNUNET_HashCode *query,
256 struct GNUNET_CONTAINER_BloomFilter **bf,
257 int32_t bf_mutator,
258 const void *xquery, 328 const void *xquery,
259 size_t xquery_size, 329 size_t xquery_size,
260 const void *reply_block, 330 const void *reply_block,
@@ -279,24 +349,41 @@ GNUNET_BLOCK_get_key (struct GNUNET_BLOCK_Context *ctx,
279 enum GNUNET_BLOCK_Type type, 349 enum GNUNET_BLOCK_Type type,
280 const void *block, 350 const void *block,
281 size_t block_size, 351 size_t block_size,
282 struct GNUNET_HashCode * key); 352 struct GNUNET_HashCode *key);
283
284 353
285 354
286/** 355/**
287 * Construct a bloom filter that would filter out the given 356 * Update block group to filter out the given results. Note that the
288 * results. 357 * use of a hash for seen results implies that the caller magically
358 * knows how the specific block engine hashes for filtering
359 * duplicates, so this API may not always apply.
289 * 360 *
290 * @param bf_mutator mutation value to use 361 * @param bf_mutator mutation value to use
291 * @param seen_results results already seen 362 * @param seen_results results already seen
292 * @param seen_results_count number of entries in @a seen_results 363 * @param seen_results_count number of entries in @a seen_results
293 * @return NULL if seen_results_count is 0, otherwise a BF 364 * @return #GNUNET_SYSERR if not supported, #GNUNET_OK on success
294 * that would match the given results.
295 */ 365 */
296struct GNUNET_CONTAINER_BloomFilter * 366int
297GNUNET_BLOCK_construct_bloomfilter (int32_t bf_mutator, 367GNUNET_BLOCK_group_set_seen (struct GNUNET_BLOCK_Group *bg,
298 const struct GNUNET_HashCode *seen_results, 368 const struct GNUNET_HashCode *seen_results,
299 unsigned int seen_results_count); 369 unsigned int seen_results_count);
370
371
372/**
373 * Try merging two block groups. Afterwards, @a bg1 should remain
374 * valid and contain the rules from both @a bg1 and @bg2, and
375 * @a bg2 should be destroyed (as part of this call). The latter
376 * should happen even if merging is not supported.
377 *
378 * @param[in,out] bg1 first group to merge, is updated
379 * @param bg2 second group to merge, is destroyed
380 * @return #GNUNET_OK on success,
381 * #GNUNET_NO if merge failed due to different nonce
382 * #GNUNET_SYSERR if merging is not supported
383 */
384int
385GNUNET_BLOCK_group_merge (struct GNUNET_BLOCK_Group *bg1,
386 struct GNUNET_BLOCK_Group *bg2);
300 387
301 388
302#if 0 /* keep Emacsens' auto-indent happy */ 389#if 0 /* keep Emacsens' auto-indent happy */
diff --git a/src/include/gnunet_block_plugin.h b/src/include/gnunet_block_plugin.h
index 5c320457e..3eb031573 100644
--- a/src/include/gnunet_block_plugin.h
+++ b/src/include/gnunet_block_plugin.h
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet 2 This file is part of GNUnet
3 Copyright (C) 2010,2013 GNUnet e.V. 3 Copyright (C) 2010,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
@@ -40,6 +40,130 @@
40 40
41 41
42/** 42/**
43 * Mark elements as "seen" using a hash of the element. Not supported
44 * by all block plugins.
45 *
46 * @param bg group to update
47 * @param seen_results results already seen
48 * @param seen_results_count number of entries in @a seen_results
49 */
50typedef void
51(*GNUNET_BLOCK_GroupMarkSeenFunction)(struct GNUNET_BLOCK_Group *bg,
52 const struct GNUNET_HashCode *seen_results,
53 unsigned int seen_results_count);
54
55
56/**
57 * Merge two groups, if possible. Not supported by all block plugins,
58 * can also fail if the nonces were different.
59 *
60 * @param bg1 group to update
61 * @param bg2 group to merge into @a bg1
62 * @return #GNUNET_OK on success, #GNUNET_NO if the nonces were different and thus
63 * we failed.
64 */
65typedef int
66(*GNUNET_BLOCK_GroupMergeFunction)(struct GNUNET_BLOCK_Group *bg1,
67 const struct GNUNET_BLOCK_Group *bg2);
68
69
70/**
71 * Serialize state of a block group.
72 *
73 * @param bg group to serialize
74 * @param[out] nonce set to the nonce of the @a bg
75 * @param[out] raw_data set to the serialized state
76 * @param[out] raw_data_size set to the number of bytes in @a raw_data
77 * @return #GNUNET_OK on success, #GNUNET_NO if serialization is not
78 * supported, #GNUNET_SYSERR on error
79 */
80typedef int
81(*GNUNET_BLOCK_GroupSerializeFunction)(struct GNUNET_BLOCK_Group *bg,
82 uint32_t *nonce,
83 void **raw_data,
84 size_t *raw_data_size);
85
86
87/**
88 * Destroy resources used by a block group.
89 *
90 * @param bg group to destroy, NULL is allowed
91 */
92typedef void
93(*GNUNET_BLOCK_GroupDestroyFunction)(struct GNUNET_BLOCK_Group *bg);
94
95
96/**
97 * Block group data. The plugin must initialize the callbacks
98 * and can use the @e internal_cls as it likes.
99 */
100struct GNUNET_BLOCK_Group
101{
102
103 /**
104 * Context owning the block group. Set by the main block library.
105 */
106 struct GNUENT_BLOCK_Context *ctx;
107
108 /**
109 * Type for the block group. Set by the main block library.
110 */
111 enum GNUNET_BLOCK_Type type;
112
113 /**
114 * Serialize the block group data, can be NULL if
115 * not supported.
116 */
117 GNUNET_BLOCK_GroupSerializeFunction serialize_cb;
118
119 /**
120 * Function to call to mark elements as seen in the group.
121 * Can be NULL if not supported.
122 */
123 GNUNET_BLOCK_GroupMarkSeenFunction mark_seen_cb;
124
125 /**
126 * Function to call to merge two groups.
127 * Can be NULL if not supported.
128 */
129 GNUNET_BLOCK_GroupMergeFunction merge_cb;
130
131 /**
132 * Function to call to destroy the block group.
133 * Must not be NULL.
134 */
135 GNUNET_BLOCK_GroupDestroyFunction destroy_cb;
136
137 /**
138 * Internal data structure of the plugin.
139 */
140 void *internal_cls;
141
142};
143
144
145/**
146 * Create a new block group.
147 *
148 * @param ctx block context in which the block group is created
149 * @param type type of the block for which we are creating the group
150 * @param nonce random value used to seed the group creation
151 * @param raw_data optional serialized prior state of the group, NULL if unavailable/fresh
152 * @param raw_data_size number of bytes in @a raw_data, 0 if unavailable/fresh
153 * @param va variable arguments specific to @a type
154 * @return block group handle, NULL if block groups are not supported
155 * by this @a type of block (this is not an error)
156 */
157typedef struct GNUNET_BLOCK_Group *
158(*GNUNET_BLOCK_GroupCreateFunction)(void *cls,
159 enum GNUNET_BLOCK_Type type,
160 uint32_t nonce,
161 const void *raw_data,
162 size_t raw_data_size,
163 va_list va);
164
165
166/**
43 * Function called to validate a reply or a request. For 167 * Function called to validate a reply or a request. For
44 * request evaluation, simply pass "NULL" for the @a reply_block. 168 * request evaluation, simply pass "NULL" for the @a reply_block.
45 * Note that it is assumed that the reply has already been 169 * Note that it is assumed that the reply has already been
@@ -47,11 +171,11 @@
47 * be done with the "get_key" function. 171 * be done with the "get_key" function.
48 * 172 *
49 * @param cls closure 173 * @param cls closure
174 * @param ctx block context
50 * @param type block type 175 * @param type block type
176 * @param group which block group to use for evaluation
51 * @param eo evaluation options to control evaluation 177 * @param eo evaluation options to control evaluation
52 * @param query original query (hash) 178 * @param query original query (hash)
53 * @param bf pointer to bloom filter associated with query; possibly updated (!)
54 * @param bf_mutator mutation value for @a bf
55 * @param xquery extrended query data (can be NULL, depending on type) 179 * @param xquery extrended query data (can be NULL, depending on type)
56 * @param xquery_size number of bytes in @a xquery 180 * @param xquery_size number of bytes in @a xquery
57 * @param reply_block response to validate 181 * @param reply_block response to validate
@@ -60,11 +184,11 @@
60 */ 184 */
61typedef enum GNUNET_BLOCK_EvaluationResult 185typedef enum GNUNET_BLOCK_EvaluationResult
62(*GNUNET_BLOCK_EvaluationFunction) (void *cls, 186(*GNUNET_BLOCK_EvaluationFunction) (void *cls,
187 struct GNUNET_BLOCK_Context *ctx,
63 enum GNUNET_BLOCK_Type type, 188 enum GNUNET_BLOCK_Type type,
189 struct GNUNET_BLOCK_Group *group,
64 enum GNUNET_BLOCK_EvaluationOptions eo, 190 enum GNUNET_BLOCK_EvaluationOptions eo,
65 const struct GNUNET_HashCode *query, 191 const struct GNUNET_HashCode *query,
66 struct GNUNET_CONTAINER_BloomFilter **bf,
67 int32_t bf_mutator,
68 const void *xquery, 192 const void *xquery,
69 size_t xquery_size, 193 size_t xquery_size,
70 const void *reply_block, 194 const void *reply_block,
@@ -121,6 +245,11 @@ struct GNUNET_BLOCK_PluginFunctions
121 */ 245 */
122 GNUNET_BLOCK_GetKeyFunction get_key; 246 GNUNET_BLOCK_GetKeyFunction get_key;
123 247
248 /**
249 * Create a block group to process a bunch of blocks in a shared
250 * context (i.e. to detect duplicates).
251 */
252 GNUNET_BLOCK_GroupCreateFunction create_group;
124}; 253};
125 254
126#endif 255#endif
diff --git a/src/include/gnunet_cadet_service.h b/src/include/gnunet_cadet_service.h
index 8d10c3d8d..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 * 139 *
114 * Each time the function must call #GNUNET_CADET_receive_done on the channel 140 * @param cls Closure from #GNUNET_CADET_open_port.
115 * in order to receive the next message. This doesn't need to be immediate: 141 * @param channel New handle to the channel.
116 * can be delayed if some processing is done on the message. 142 * @param source Peer that started this channel.
117 * 143 * @return Closure for the incoming @a channel. It's given to:
118 * @param cls Closure (set from #GNUNET_CADET_connect). 144 * - The #GNUNET_CADET_DisconnectEventHandler (given to
119 * @param channel Connection to the other end. 145 * #GNUNET_CADET_open_port) when the channel dies.
120 * @param channel_ctx Place to store local state associated with the channel. 146 * - Each the #GNUNET_MQ_MessageCallback handlers for each message
121 * @param message The actual message. 147 * received on the @a channel.
122 * @return #GNUNET_OK to keep the channel open,
123 * #GNUNET_SYSERR to close it (signal serious error).
124 */
125typedef int
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.
189 * 176 *
190 * @param cls closure (set from #GNUNET_CADET_connect) 177 * For an incoming channel it will be called immediately after the
191 * @param channel connection to the other end (henceforth invalid) 178 * #GNUNET_CADET_ConnectEventHandler, also with a non-zero value.
192 * @param channel_ctx place where local state associated 179 *
193 * with the channel is stored 180 * @param cls Channel closure.
181 * @param channel Connection to the other end --- FIXME: drop?
182 * @param window_size New window size. If the is more messages than buffer size
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 *
@@ -456,7 +427,7 @@ typedef void
456 int tunnel, 427 int tunnel,
457 int neighbor, 428 int neighbor,
458 unsigned int n_paths, 429 unsigned int n_paths,
459 struct GNUNET_PeerIdentity *paths); 430 const struct GNUNET_PeerIdentity *paths);
460 431
461 432
462/** 433/**
@@ -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,188 +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 * Function called after #GNUNET_CADET_connecT has succeeded (or failed
701 * for good). Implementations of this function must not call
702 * #GNUNET_CADET_disconnecT (other than by scheduling a new task to
703 * do this later).
704 *
705 * @param cls closure
706 * @param connected #GNUNET_YES if successfully connected, #GNUNET_NO otherwise.
707 */
708typedef void
709(*GNUNET_CADET_StartupCallback) (void *cls, int connected);
710
711
712/**
713 * Method called whenever a given peer connects in mq-based CADET.
714 *
715 * @param cls Closure given to @a GNUNET_CADET_connecT.
716 * @param channel New handle to the channel.
717 * @param channel_cls Closure given to @a GNUNET_CADET_open_porT.
718 * NOTE: do we need two cls? I'd get rid of this one.
719 * @param peer Peer that started this channel.
720 *
721 * NOTE: to keep symmetry between incoming and outgoing channels, this call
722 * does not provide the *mq, since we cannot cleanly return an mq
723 * from @a GNUNET_CADET_channel_create.
724 * The client must always call @a GNUNET_CADET_get_mq to the *mq
725 * Alternatively, we can provide the mq here and add and out **mq
726 * to @a GNUNET_CADET_channel_create
727 *
728 * @return initial channel context for the channel
729 * (can be NULL -- that's not an error)
730 */
731typedef void *
732(*GNUNET_CADET_ConnectEventHandler) (void *cls,
733 struct GNUNET_CADET_Channel *channel,
734 const struct GNUNET_PeerIdentity *peer);
735
736/**
737 * Function called whenever an mq-channel is destroyed. Should clean up
738 * any associated state, including cancelling any pending transmission on this
739 * channel.
740 *
741 * It must NOT call @a GNUNET_CADET_channel_destroy on the channel.
742 *
743 * @param cls Closure (set from @a GNUNET_CADET_connecT).
744 * @param channel Connection to the other end (henceforth invalid).
745 * @param channel_ctx Context (set from @a GNUNET_CADET_ConnectEventHandler).
746 */
747typedef void
748(GNUNET_CADET_DisconnectEventHandler) (void *cls,
749 const struct GNUNET_CADET_Channel *channel,
750 void *channel_ctx);
751
752/**
753 * Connect to the mq-based cadet service.
754 *
755 * NOTE: it would be more elegant to provide a separate @a handlers and
756 * @a disconnects for each port, giving them to @a GNUNET_CADET_open_porT,
757 * but how do we handle *incoming* channels?
758 *
759 * @param cfg Configuration to use.
760 * @param cls Closure for the various callbacks that follow (including
761 * handlers in the handlers array).
762 * @param init callback to call once we have successfully connected
763 * to the cadet service
764 * @param disconnects Function called when a channel is destroyed.
765 * It is called immediately if the channel is destroyed by
766 * calling @a GNUNET_CADET_channel_destroy.
767 * @param handlers Callbacks for messages we care about, NULL-terminated.
768 * Messages of a type that is not in the handlers array
769 * are ignored if received.
770 *
771 * @return handle to the cadet service NULL on error
772 * (in this case, init is never called)
773 */
774struct GNUNET_CADET_Handle *
775GNUNET_CADET_connecT (const struct GNUNET_CONFIGURATION_Handle *cfg,
776 void *cls,
777 GNUNET_CADET_StartupCallback init,
778 GNUNET_CADET_DisconnectEventHandler disconnects,
779 const struct GNUNET_MQ_MessageHandler *handlers);
780
781/**
782 * Disconnect from the mq-based cadet service. All channels will be destroyed.
783 * All channel disconnect callbacks will be called on any still connected peers,
784 * notifying about their disconnection. The registered inbound channel cleaner
785 * will be called should any inbound channels still exist.
786 *
787 * @param handle connection to cadet to disconnect
788 */
789void
790GNUNET_CADET_disconnecT (struct GNUNET_CADET_Handle *handle);
791
792/**
793 * Open a port to receive incomming mq-based channels.
794 *
795 * @param h CADET handle.
796 * @param port Hash representing the port number.
797 * @param new_channel Function called when an channel is received.
798 * @param new_channel_cls Closure for @a new_channel.
799 * NOTE: get rid of this cls?
800 *
801 * @return Port handle.
802 */
803struct GNUNET_CADET_Port *
804GNUNET_CADET_open_porT (struct GNUNET_CADET_Handle *h,
805 const struct GNUNET_HashCode *port,
806 GNUNET_CADET_ConnectEventHandler new_channel,
807 void *new_channel_cls);
808
809/**
810 * Close a port opened with @a GNUNET_CADET_open_porT.
811 * The @a new_channel callback will no longer be called.
812 *
813 * @param p Port handle.
814 */
815void
816GNUNET_CADET_close_porT (struct GNUNET_CADET_Port *p);
817
818/**
819 * Obtain the message queue for a connected peer.
820 *
821 * @param h the cadet handle
822 * @param channel the identity of the peer
823 *
824 * @return NULL if @a channel is not yet connected.
825 * NOTE: provide an mq before a channel is connected?
826 * provide a callback to notify a client a channel connected?
827 */
828struct GNUNET_MQ_Handle *
829GNUNET_CADET_get_mq (const struct GNUNET_CADET_Handle *h,
830 const struct GNUNET_CADET_Channel *channel);
831
832/* NOTE:
833 * GNUNET_CADET_channel_create and _destroy can stay the same.
834 * Monitor API can stay the same (low-priority).
835
836struct GNUNET_CADET_Channel *
837GNUNET_CADET_channel_create (struct GNUNET_CADET_Handle *h,
838 void *channel_ctx,
839 const struct GNUNET_PeerIdentity *peer,
840 const struct GNUNET_HashCode *port,
841 enum GNUNET_CADET_ChannelOption options);
842void
843GNUNET_CADET_channel_destroy (struct GNUNET_CADET_Channel *channel);
844
845*/
846
847/******************************************************************************/
848/******************************* MQ-BASED API *********************************/
849/******************************************************************************/
850
851
852 614
853#if 0 /* keep Emacsens' auto-indent happy */ 615#if 0 /* keep Emacsens' auto-indent happy */
854{ 616{
diff --git a/src/include/gnunet_common.h b/src/include/gnunet_common.h
index fdcae66fa..bda011fb2 100644
--- a/src/include/gnunet_common.h
+++ b/src/include/gnunet_common.h
@@ -391,7 +391,7 @@ GNUNET_get_log_call_status (int caller_level,
391 */ 391 */
392void 392void
393GNUNET_log_nocheck (enum GNUNET_ErrorType kind, const char *message, ...) 393GNUNET_log_nocheck (enum GNUNET_ErrorType kind, const char *message, ...)
394 __attribute__ ((format (printf, 2, 3))); 394 __attribute__ ((format (gnu_printf, 2, 3)));
395 395
396/* from glib */ 396/* from glib */
397#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__) 397#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__)
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_container_lib.h b/src/include/gnunet_container_lib.h
index f3aaa943b..c77d82fd3 100644
--- a/src/include/gnunet_container_lib.h
+++ b/src/include/gnunet_container_lib.h
@@ -2073,6 +2073,59 @@ GNUNET_CONTAINER_multihashmap32_iterator_destroy (struct GNUNET_CONTAINER_MultiH
2073 2073
2074 2074
2075 2075
2076/**
2077 * Insertion sort of @a element into DLL from @a head to @a tail
2078 * sorted by @a comparator.
2079 *
2080 * @param TYPE element type of the elements, i.e. `struct ListElement`
2081 * @param comparator function like memcmp() to compare elements; takes
2082 * three arguments, the @a comparator_cls and two elements,
2083 * returns an `int` (-1, 0 or 1)
2084 * @param comparator_cls closure for @a comparator
2085 * @param[in,out] head head of DLL
2086 * @param[in,out] tail tail of DLL
2087 * @param element element to insert
2088 */
2089#define GNUNET_CONTAINER_DLL_insert_sorted(TYPE,comparator,comparator_cls,head,tail,element) do { \
2090 if ( (NULL == head) || \
2091 (0 < comparator (comparator_cls, \
2092 element, \
2093 head)) ) \
2094 { \
2095 /* insert at head, element < head */ \
2096 GNUNET_CONTAINER_DLL_insert (head, \
2097 tail, \
2098 element); \
2099 } \
2100 else \
2101 { \
2102 TYPE *pos; \
2103 \
2104 for (pos = head; \
2105 NULL != pos; \
2106 pos = pos->next) \
2107 if (0 < \
2108 comparator (comparator_cls, \
2109 element, \
2110 pos)) \
2111 break; /* element < pos */ \
2112 if (NULL == pos) /* => element > tail */ \
2113 { \
2114 GNUNET_CONTAINER_DLL_insert_tail (head, \
2115 tail, \
2116 element); \
2117 } \
2118 else /* prev < element < pos */ \
2119 { \
2120 GNUNET_CONTAINER_DLL_insert_after (head, \
2121 tail, \
2122 pos->prev, \
2123 element); \
2124 } \
2125 } \
2126} while (0)
2127
2128
2076/* ******************** Heap *************** */ 2129/* ******************** Heap *************** */
2077 2130
2078 2131
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_credential_service.h b/src/include/gnunet_credential_service.h
index d04c0a253..6c9b477ea 100644
--- a/src/include/gnunet_credential_service.h
+++ b/src/include/gnunet_credential_service.h
@@ -262,8 +262,6 @@ typedef void (*GNUNET_CREDENTIAL_RemoveDelegateResultProcessor) (void *cls,
262 uint32_t success); 262 uint32_t success);
263 263
264 264
265
266
267/** 265/**
268 * Performs attribute verification. 266 * Performs attribute verification.
269 * Checks if there is a delegation chain from 267 * Checks if there is a delegation chain from
diff --git a/src/include/gnunet_crypto_lib.h b/src/include/gnunet_crypto_lib.h
index 43fd32a58..07cade0e3 100644
--- a/src/include/gnunet_crypto_lib.h
+++ b/src/include/gnunet_crypto_lib.h
@@ -1240,6 +1240,17 @@ GNUNET_CRYPTO_eddsa_key_create (void);
1240 1240
1241/** 1241/**
1242 * @ingroup crypto 1242 * @ingroup crypto
1243 * Create a new private key. Clear with #GNUNET_CRYPTO_ecdhe_key_clear().
1244 *
1245 * @param[out] pk set to fresh private key;
1246 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
1247 */
1248int
1249GNUNET_CRYPTO_ecdhe_key_create2 (struct GNUNET_CRYPTO_EcdhePrivateKey *pk);
1250
1251
1252/**
1253 * @ingroup crypto
1243 * Create a new private key. Caller must free return value. 1254 * Create a new private key. Caller must free return value.
1244 * 1255 *
1245 * @return fresh private key; free using #GNUNET_free 1256 * @return fresh private key; free using #GNUNET_free
diff --git a/src/include/gnunet_datastore_plugin.h b/src/include/gnunet_datastore_plugin.h
index 71c69ffaf..516ba525c 100644
--- a/src/include/gnunet_datastore_plugin.h
+++ b/src/include/gnunet_datastore_plugin.h
@@ -93,6 +93,7 @@ struct GNUNET_DATASTORE_PluginEnvironment
93 * @param type type of the content 93 * @param type type of the content
94 * @param priority priority of the content 94 * @param priority priority of the content
95 * @param anonymity anonymity-level for the content 95 * @param anonymity anonymity-level for the content
96 * @param replication replication-level for the content
96 * @param expiration expiration time for the content 97 * @param expiration expiration time for the content
97 * @param uid unique identifier for the datum 98 * @param uid unique identifier for the datum
98 * @return #GNUNET_OK to keep the item 99 * @return #GNUNET_OK to keep the item
@@ -100,14 +101,15 @@ struct GNUNET_DATASTORE_PluginEnvironment
100 */ 101 */
101typedef int 102typedef int
102(*PluginDatumProcessor) (void *cls, 103(*PluginDatumProcessor) (void *cls,
103 const struct GNUNET_HashCode *key, 104 const struct GNUNET_HashCode *key,
104 uint32_t size, 105 uint32_t size,
105 const void *data, 106 const void *data,
106 enum GNUNET_BLOCK_Type type, 107 enum GNUNET_BLOCK_Type type,
107 uint32_t priority, 108 uint32_t priority,
108 uint32_t anonymity, 109 uint32_t anonymity,
109 struct GNUNET_TIME_Absolute expiration, 110 uint32_t replication,
110 uint64_t uid); 111 struct GNUNET_TIME_Absolute expiration,
112 uint64_t uid);
111 113
112 114
113/** 115/**
@@ -204,9 +206,9 @@ typedef void
204 * Get one of the results for a particular key in the datastore. 206 * Get one of the results for a particular key in the datastore.
205 * 207 *
206 * @param cls closure 208 * @param cls closure
207 * @param offset offset of the result (modulo num-results); 209 * @param next_uid return the result with lowest uid >= next_uid
208 * specific ordering does not matter for the offset 210 * @param random if true, return a random result instead of using next_uid
209 * @param key key to match, never NULL 211 * @param key maybe NULL (to match all entries)
210 * @param vhash hash of the value, maybe NULL (to 212 * @param vhash hash of the value, maybe NULL (to
211 * match all values that have the right key). 213 * match all values that have the right key).
212 * Note that for DBlocks there is no difference 214 * Note that for DBlocks there is no difference
@@ -215,17 +217,18 @@ typedef void
215 * @param type entries of which type are relevant? 217 * @param type entries of which type are relevant?
216 * Use 0 for any type. 218 * Use 0 for any type.
217 * @param proc function to call on the matching value; 219 * @param proc function to call on the matching value;
218 * proc should be called with NULL if there is no result 220 * will be called with NULL if nothing matches
219 * @param proc_cls closure for @a proc 221 * @param proc_cls closure for @a proc
220 */ 222 */
221typedef void 223typedef void
222(*PluginGetKey) (void *cls, 224(*PluginGetKey) (void *cls,
223 uint64_t offset, 225 uint64_t next_uid,
224 const struct GNUNET_HashCode *key, 226 bool random,
225 const struct GNUNET_HashCode *vhash, 227 const struct GNUNET_HashCode *key,
226 enum GNUNET_BLOCK_Type type, 228 const struct GNUNET_HashCode *vhash,
227 PluginDatumProcessor proc, 229 enum GNUNET_BLOCK_Type type,
228 void *proc_cls); 230 PluginDatumProcessor proc,
231 void *proc_cls);
229 232
230 233
231/** 234/**
@@ -258,19 +261,18 @@ typedef void
258 261
259 262
260/** 263/**
261 * Update the priority for a particular key in the datastore. If 264 * Update the priority, replication and expiration for a particular
262 * the expiration time in value is different than the time found in 265 * unique ID in the datastore. If the expiration time in value is
263 * the datastore, the higher value should be kept. For the 266 * different than the time found in the datastore, the higher value
264 * anonymity level, the lower value is to be used. The specified 267 * should be kept. The specified priority and replication is added
265 * priority should be added to the existing priority, ignoring the 268 * to the existing value.
266 * priority in value.
267 * 269 *
268 * @param cls closure 270 * @param cls closure
269 * @param uid unique identifier of the datum 271 * @param uid unique identifier of the datum
270 * @param delta by how much should the priority 272 * @param priority by how much should the priority
271 * change? If priority + delta < 0 the 273 * change?
272 * priority should be set to 0 (never go 274 * @param replication by how much should the replication
273 * negative). 275 * change?
274 * @param expire new expiration time should be the 276 * @param expire new expiration time should be the
275 * MAX of any existing expiration time and 277 * MAX of any existing expiration time and
276 * this value 278 * this value
@@ -279,31 +281,31 @@ typedef void
279 */ 281 */
280typedef void 282typedef void
281(*PluginUpdate) (void *cls, 283(*PluginUpdate) (void *cls,
282 uint64_t uid, 284 uint64_t uid,
283 int delta, 285 uint32_t priority,
284 struct GNUNET_TIME_Absolute expire, 286 uint32_t replication,
285 PluginUpdateCont cont, 287 struct GNUNET_TIME_Absolute expire,
286 void *cont_cls); 288 PluginUpdateCont cont,
289 void *cont_cls);
287 290
288 291
289/** 292/**
290 * Select a single item from the datastore at the specified offset 293 * Select a single item from the datastore (among those applicable).
291 * (among those applicable).
292 * 294 *
293 * @param cls closure 295 * @param cls closure
294 * @param offset offset of the result (modulo num-results); 296 * @param next_uid return the result with lowest uid >= next_uid
295 * specific ordering does not matter for the offset
296 * @param type entries of which type should be considered? 297 * @param type entries of which type should be considered?
297 * Must not be zero (ANY). 298 * Must not be zero (ANY).
298 * @param proc function to call on the matching value 299 * @param proc function to call on the matching value;
300 * will be called with NULL if no value matches
299 * @param proc_cls closure for @a proc 301 * @param proc_cls closure for @a proc
300 */ 302 */
301typedef void 303typedef void
302(*PluginGetType) (void *cls, 304(*PluginGetType) (void *cls,
303 uint64_t offset, 305 uint64_t next_uid,
304 enum GNUNET_BLOCK_Type type, 306 enum GNUNET_BLOCK_Type type,
305 PluginDatumProcessor proc, 307 PluginDatumProcessor proc,
306 void *proc_cls); 308 void *proc_cls);
307 309
308 310
309/** 311/**
@@ -356,9 +358,6 @@ struct GNUNET_DATASTORE_PluginFunctions
356 358
357 /** 359 /**
358 * Get datum (of the specified type) with anonymity level zero. 360 * Get datum (of the specified type) with anonymity level zero.
359 * This function is allowed to ignore the 'offset' argument
360 * and instead return a random result (with zero anonymity of
361 * the correct type) if implementing an offset is expensive.
362 */ 361 */
363 PluginGetType get_zero_anonymity; 362 PluginGetType get_zero_anonymity;
364 363
diff --git a/src/include/gnunet_datastore_service.h b/src/include/gnunet_datastore_service.h
index f594d8fa6..f851385c5 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
@@ -267,6 +240,7 @@ GNUNET_DATASTORE_remove (struct GNUNET_DATASTORE_Handle *h,
267 * @param type type of the content 240 * @param type type of the content
268 * @param priority priority of the content 241 * @param priority priority of the content
269 * @param anonymity anonymity-level for the content 242 * @param anonymity anonymity-level for the content
243 * @param replication how often should the content be replicated to other peers?
270 * @param expiration expiration time for the content 244 * @param expiration expiration time for the content
271 * @param uid unique identifier for the datum; 245 * @param uid unique identifier for the datum;
272 * maybe 0 if no unique identifier is available 246 * maybe 0 if no unique identifier is available
@@ -279,6 +253,7 @@ typedef void
279 enum GNUNET_BLOCK_Type type, 253 enum GNUNET_BLOCK_Type type,
280 uint32_t priority, 254 uint32_t priority,
281 uint32_t anonymity, 255 uint32_t anonymity,
256 uint32_t replication,
282 struct GNUNET_TIME_Absolute expiration, 257 struct GNUNET_TIME_Absolute expiration,
283 uint64_t uid); 258 uint64_t uid);
284 259
@@ -288,10 +263,8 @@ typedef void
288 * will only be called once. 263 * will only be called once.
289 * 264 *
290 * @param h handle to the datastore 265 * @param h handle to the datastore
291 * @param offset offset of the result (modulo num-results); set to 266 * @param next_uid return the result with lowest uid >= next_uid
292 * a random 64-bit value initially; then increment by 267 * @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) 268 * @param key maybe NULL (to match all entries)
296 * @param type desired type, 0 for any 269 * @param type desired type, 0 for any
297 * @param queue_priority ranking of this request in the priority queue 270 * @param queue_priority ranking of this request in the priority queue
@@ -305,7 +278,8 @@ typedef void
305 */ 278 */
306struct GNUNET_DATASTORE_QueueEntry * 279struct GNUNET_DATASTORE_QueueEntry *
307GNUNET_DATASTORE_get_key (struct GNUNET_DATASTORE_Handle *h, 280GNUNET_DATASTORE_get_key (struct GNUNET_DATASTORE_Handle *h,
308 uint64_t offset, 281 uint64_t next_uid,
282 bool random,
309 const struct GNUNET_HashCode *key, 283 const struct GNUNET_HashCode *key,
310 enum GNUNET_BLOCK_Type type, 284 enum GNUNET_BLOCK_Type type,
311 unsigned int queue_priority, 285 unsigned int queue_priority,
@@ -316,16 +290,9 @@ GNUNET_DATASTORE_get_key (struct GNUNET_DATASTORE_Handle *h,
316 290
317/** 291/**
318 * Get a single zero-anonymity value from the datastore. 292 * 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 * 293 *
324 * @param h handle to the datastore 294 * @param h handle to the datastore
325 * @param offset offset of the result (modulo num-results); set to 295 * @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 296 * @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 297 * @param max_queue_size at what queue size should this request be dropped
331 * (if other requests of higher priority are in the queue) 298 * (if other requests of higher priority are in the queue)
@@ -339,7 +306,7 @@ GNUNET_DATASTORE_get_key (struct GNUNET_DATASTORE_Handle *h,
339 */ 306 */
340struct GNUNET_DATASTORE_QueueEntry * 307struct GNUNET_DATASTORE_QueueEntry *
341GNUNET_DATASTORE_get_zero_anonymity (struct GNUNET_DATASTORE_Handle *h, 308GNUNET_DATASTORE_get_zero_anonymity (struct GNUNET_DATASTORE_Handle *h,
342 uint64_t offset, 309 uint64_t next_uid,
343 unsigned int queue_priority, 310 unsigned int queue_priority,
344 unsigned int max_queue_size, 311 unsigned int max_queue_size,
345 enum GNUNET_BLOCK_Type type, 312 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..f707bb091 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_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_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_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_flag (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_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_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_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_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_uint (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_cfgfile (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_gns_service.h b/src/include/gnunet_gns_service.h
index 8a1099444..ccc868c05 100644
--- a/src/include/gnunet_gns_service.h
+++ b/src/include/gnunet_gns_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) 2012-2014 GNUnet e.V. 3 Copyright (C) 2012-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
@@ -90,19 +90,10 @@ GNUNET_GNS_disconnect (struct GNUNET_GNS_Handle *handle);
90 * @param rd_count number of records in @a rd 90 * @param rd_count number of records in @a rd
91 * @param rd the records in reply 91 * @param rd the records in reply
92 */ 92 */
93typedef void (*GNUNET_GNS_LookupResultProcessor) (void *cls, 93typedef void
94 uint32_t rd_count, 94(*GNUNET_GNS_LookupResultProcessor) (void *cls,
95 const struct GNUNET_GNSRECORD_Data *rd); 95 uint32_t rd_count,
96 96 const struct GNUNET_GNSRECORD_Data *rd);
97/**
98 * Iterator called on obtained result for a GNS lookup.
99 *
100 * @param cls closure
101 * @param rd_count number of records in @a rd
102 * @param rd the records in reply
103 */
104typedef void (*GNUNET_GNS_ReverseLookupResultProcessor) (void *cls,
105 const char* name);
106 97
107 98
108/** 99/**
@@ -137,13 +128,8 @@ enum GNUNET_GNS_LocalOptions
137 * @param zone zone to look in 128 * @param zone zone to look in
138 * @param type the GNS record type to look for 129 * @param type the GNS record type to look for
139 * @param options local options for the lookup 130 * @param options local options for the lookup
140 * @param shorten_zone_key the private key of the shorten zone (can be NULL);
141 * specify to enable automatic shortening (given a PSEU
142 * record, if a given pseudonym is not yet used in the
143 * shorten zone, we automatically add the respective zone
144 * under that name)
145 * @param proc function to call on result 131 * @param proc function to call on result
146 * @param proc_cls closure for processor 132 * @param proc_cls closure for @a proc
147 * @return handle to the queued request 133 * @return handle to the queued request
148 */ 134 */
149struct GNUNET_GNS_LookupRequest * 135struct GNUNET_GNS_LookupRequest *
@@ -152,27 +138,9 @@ GNUNET_GNS_lookup (struct GNUNET_GNS_Handle *handle,
152 const struct GNUNET_CRYPTO_EcdsaPublicKey *zone, 138 const struct GNUNET_CRYPTO_EcdsaPublicKey *zone,
153 uint32_t type, 139 uint32_t type,
154 enum GNUNET_GNS_LocalOptions options, 140 enum GNUNET_GNS_LocalOptions options,
155 const struct GNUNET_CRYPTO_EcdsaPrivateKey *shorten_zone_key,
156 GNUNET_GNS_LookupResultProcessor proc, 141 GNUNET_GNS_LookupResultProcessor proc,
157 void *proc_cls); 142 void *proc_cls);
158 143
159/**
160 * Perform an asynchronous reverse lookup operation on the GNS.
161 *
162 * @param handle handle to the GNS service
163 * @param zone_key zone to find a name for
164 * @param root_key our zone
165 * @param proc processor to call on result
166 * @param proc_cls closure for @a proc
167 * @return handle to the request
168 */
169struct GNUNET_GNS_ReverseLookupRequest*
170GNUNET_GNS_reverse_lookup (struct GNUNET_GNS_Handle *handle,
171 const struct GNUNET_CRYPTO_EcdsaPublicKey *zone_key,
172 const struct GNUNET_CRYPTO_EcdsaPublicKey *root_key,
173 GNUNET_GNS_ReverseLookupResultProcessor proc,
174 void *proc_cls);
175
176 144
177/** 145/**
178 * Cancel pending lookup request 146 * Cancel pending lookup request
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 108ba5d54..ecee1b223 100644
--- a/src/include/gnunet_mq_lib.h
+++ b/src/include/gnunet_mq_lib.h
@@ -32,9 +32,10 @@
32 * 32 *
33 * @{ 33 * @{
34 */ 34 */
35#ifndef GNUNET_MQ_H 35#ifndef GNUNET_MQ_LIB_H
36#define GNUNET_MQ_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
@@ -269,6 +270,66 @@ typedef void
269 270
270 271
271/** 272/**
273 * Insert @a env into the envelope DLL starting at @a env_head
274 * Note that @a env must not be in any MQ while this function
275 * is used with DLLs defined outside of the MQ module. This
276 * is just in case some application needs to also manage a
277 * FIFO of envelopes independent of MQ itself and wants to
278 * re-use the pointers internal to @a env. Use with caution.
279 *
280 * @param[in|out] env_head of envelope DLL
281 * @param[in|out] env_tail tail of envelope DLL
282 * @param[in|out] env element to insert at the tail
283 */
284void
285GNUNET_MQ_dll_insert_tail (struct GNUNET_MQ_Envelope **env_head,
286 struct GNUNET_MQ_Envelope **env_tail,
287 struct GNUNET_MQ_Envelope *env);
288
289
290/**
291 * Remove @a env from the envelope DLL starting at @a env_head.
292 * Note that @a env must not be in any MQ while this function
293 * is used with DLLs defined outside of the MQ module. This
294 * is just in case some application needs to also manage a
295 * FIFO of envelopes independent of MQ itself and wants to
296 * re-use the pointers internal to @a env. Use with caution.
297 *
298 * @param[in|out] env_head of envelope DLL
299 * @param[in|out] env_tail tail of envelope DLL
300 * @param[in|out] env element to remove from the DLL
301 */
302void
303GNUNET_MQ_dll_remove (struct GNUNET_MQ_Envelope **env_head,
304 struct GNUNET_MQ_Envelope **env_tail,
305 struct GNUNET_MQ_Envelope *env);
306
307
308/**
309 * Copy an array of handlers.
310 *
311 * Useful if the array has been delared in local memory and needs to be
312 * persisted for future use.
313 *
314 * @param handlers Array of handlers to be copied.
315 * @return A newly allocated array of handlers.
316 * Needs to be freed with #GNUNET_free.
317 */
318struct GNUNET_MQ_MessageHandler *
319GNUNET_MQ_copy_handlers (const struct GNUNET_MQ_MessageHandler *handlers);
320
321
322/**
323 * Count the handlers in a handler array.
324 *
325 * @param handlers Array of handlers to be counted.
326 * @return The number of handlers in the array.
327 */
328unsigned int
329GNUNET_MQ_count_handlers (const struct GNUNET_MQ_MessageHandler *handlers);
330
331
332/**
272 * Message handler for a specific message type. 333 * Message handler for a specific message type.
273 */ 334 */
274struct GNUNET_MQ_MessageHandler 335struct GNUNET_MQ_MessageHandler
@@ -413,7 +474,6 @@ struct GNUNET_MQ_MessageHandler
413 */ 474 */
414struct GNUNET_MQ_Envelope * 475struct GNUNET_MQ_Envelope *
415GNUNET_MQ_msg_ (struct GNUNET_MessageHeader **mhp, 476GNUNET_MQ_msg_ (struct GNUNET_MessageHeader **mhp,
416
417 uint16_t size, 477 uint16_t size,
418 uint16_t type); 478 uint16_t type);
419 479
@@ -451,6 +511,17 @@ GNUNET_MQ_get_current_envelope (struct GNUNET_MQ_Handle *mq);
451 511
452 512
453/** 513/**
514 * Function to copy an envelope. The envelope must not yet
515 * be in any queue or have any options or callbacks set.
516 *
517 * @param env envelope to copy
518 * @return copy of @a env
519 */
520struct GNUNET_MQ_Envelope *
521GNUNET_MQ_env_copy (struct GNUNET_MQ_Envelope *env);
522
523
524/**
454 * Function to obtain the last envelope in the queue. 525 * Function to obtain the last envelope in the queue.
455 * 526 *
456 * @param mq message queue to interrogate 527 * @param mq message queue to interrogate
@@ -488,6 +559,17 @@ GNUNET_MQ_env_get_options (struct GNUNET_MQ_Envelope *env,
488 559
489 560
490/** 561/**
562 * Remove the first envelope that has not yet been sent from the message
563 * queue and return it.
564 *
565 * @param mq queue to remove envelope from
566 * @return NULL if queue is empty (or has no envelope that is not under transmission)
567 */
568struct GNUNET_MQ_Envelope *
569GNUNET_MQ_unsent_head (struct GNUNET_MQ_Handle *mq);
570
571
572/**
491 * Set application-specific options for this queue. 573 * Set application-specific options for this queue.
492 * 574 *
493 * @param mq message queue to set options for 575 * @param mq message queue to set options for
@@ -717,7 +799,7 @@ GNUNET_MQ_impl_send_continue (struct GNUNET_MQ_Handle *mq);
717 * try to send the next message until #gnunet_mq_impl_send_continue 799 * try to send the next message until #gnunet_mq_impl_send_continue
718 * is called. 800 * is called.
719 * 801 *
720 * only useful for implementing message queues, results in undefined 802 * Only useful for implementing message queues, results in undefined
721 * behavior if not used carefully. 803 * behavior if not used carefully.
722 * 804 *
723 * @param mq message queue to send the next message with 805 * @param mq message queue to send the next message with
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_mysql_lib.h b/src/include/gnunet_mysql_lib.h
index fc6f42f86..6a1e5b3ac 100644
--- a/src/include/gnunet_mysql_lib.h
+++ b/src/include/gnunet_mysql_lib.h
@@ -61,10 +61,12 @@ struct GNUNET_MYSQL_StatementHandle;
61 * @param cls user-defined argument 61 * @param cls user-defined argument
62 * @param num_values number of elements in values 62 * @param num_values number of elements in values
63 * @param values values returned by MySQL 63 * @param values values returned by MySQL
64 * @return GNUNET_OK to continue iterating, GNUNET_SYSERR to abort 64 * @return #GNUNET_OK to continue iterating, #GNUNET_SYSERR to abort
65 */ 65 */
66typedef int (*GNUNET_MYSQL_DataProcessor) (void *cls, unsigned int num_values, 66typedef int
67 MYSQL_BIND * values); 67(*GNUNET_MYSQL_DataProcessor) (void *cls,
68 unsigned int num_values,
69 MYSQL_BIND * values);
68 70
69 71
70/** 72/**
@@ -102,7 +104,7 @@ GNUNET_MYSQL_statements_invalidate (struct GNUNET_MYSQL_Context *mc);
102/** 104/**
103 * Get internal handle for a prepared statement. This function should rarely 105 * Get internal handle for a prepared statement. This function should rarely
104 * be used, and if, with caution! On failures during the interaction with 106 * be used, and if, with caution! On failures during the interaction with
105 * the handle, you must call 'GNUNET_MYSQL_statements_invalidate'! 107 * the handle, you must call #GNUNET_MYSQL_statements_invalidate()!
106 * 108 *
107 * @param sh prepared statement to introspect 109 * @param sh prepared statement to introspect
108 * @return MySQL statement handle, NULL on error 110 * @return MySQL statement handle, NULL on error
@@ -129,8 +131,8 @@ GNUNET_MYSQL_statement_prepare (struct GNUNET_MYSQL_Context *mc,
129 * 131 *
130 * @param mc mysql context 132 * @param mc mysql context
131 * @param sql SQL statement to run 133 * @param sql SQL statement to run
132 * @return GNUNET_OK on success 134 * @return #GNUNET_OK on success
133 * GNUNET_SYSERR if there was a problem 135 * #GNUNET_SYSERR if there was a problem
134 */ 136 */
135int 137int
136GNUNET_MYSQL_statement_run (struct GNUNET_MYSQL_Context *mc, 138GNUNET_MYSQL_statement_run (struct GNUNET_MYSQL_Context *mc,
diff --git a/src/include/gnunet_network_lib.h b/src/include/gnunet_network_lib.h
index beca83807..d9d3d90e7 100644
--- a/src/include/gnunet_network_lib.h
+++ b/src/include/gnunet_network_lib.h
@@ -588,6 +588,18 @@ void
588GNUNET_NETWORK_fdset_destroy (struct GNUNET_NETWORK_FDSet *fds); 588GNUNET_NETWORK_fdset_destroy (struct GNUNET_NETWORK_FDSet *fds);
589 589
590 590
591/**
592 * Test if the given @a port is available.
593 *
594 * @param ipproto transport protocol to test (i.e. IPPROTO_TCP)
595 * @param port port number to test
596 * @return #GNUNET_OK if the port is available, #GNUNET_NO if not
597 */
598int
599GNUNET_NETWORK_test_port_free (int ipproto,
600 uint16_t port);
601
602
591#if 0 /* keep Emacsens' auto-indent happy */ 603#if 0 /* keep Emacsens' auto-indent happy */
592{ 604{
593#endif 605#endif
diff --git a/src/include/gnunet_os_lib.h b/src/include/gnunet_os_lib.h
index ce3e05f13..b3800f286 100644
--- a/src/include/gnunet_os_lib.h
+++ b/src/include/gnunet_os_lib.h
@@ -381,7 +381,8 @@ GNUNET_OS_process_current (void);
381 * @return 0 on success, -1 on error 381 * @return 0 on success, -1 on error
382 */ 382 */
383int 383int
384GNUNET_OS_process_kill (struct GNUNET_OS_Process *proc, int sig); 384GNUNET_OS_process_kill (struct GNUNET_OS_Process *proc,
385 int sig);
385 386
386 387
387/** 388/**
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_plugin_lib.h b/src/include/gnunet_plugin_lib.h
index b76b9f9cf..9e3e72a21 100644
--- a/src/include/gnunet_plugin_lib.h
+++ b/src/include/gnunet_plugin_lib.h
@@ -87,7 +87,7 @@ GNUNET_PLUGIN_load (const char *library_name,
87 87
88 88
89/** 89/**
90 * Signature of a function called by 'GNUNET_PLUGIN_load_all'. 90 * Signature of a function called by #GNUNET_PLUGIN_load_all().
91 * 91 *
92 * @param cls closure 92 * @param cls closure
93 * @param library_name full name of the library (to be used with 93 * @param library_name full name of the library (to be used with
diff --git a/src/include/gnunet_pq_lib.h b/src/include/gnunet_pq_lib.h
index 33a3e5425..756370b74 100644
--- a/src/include/gnunet_pq_lib.h
+++ b/src/include/gnunet_pq_lib.h
@@ -15,11 +15,11 @@
15*/ 15*/
16/** 16/**
17 * @file include/gnunet_pq_lib.h 17 * @file include/gnunet_pq_lib.h
18 * @brief helper functions for DB interactions 18 * @brief helper functions for Postgres DB interactions
19 * @author Christian Grothoff 19 * @author Christian Grothoff
20 */ 20 */
21#ifndef GNUNET_PQ_LIB_H_ 21#ifndef GNUNET_PQ_LIB_H
22#define GNUNET_PQ_LIB_H_ 22#define GNUNET_PQ_LIB_H
23 23
24#include <libpq-fe.h> 24#include <libpq-fe.h>
25#include "gnunet_util_lib.h" 25#include "gnunet_util_lib.h"
@@ -317,20 +317,6 @@ GNUNET_PQ_result_spec_fixed_size (const char *name,
317 317
318 318
319/** 319/**
320 * Variable-size result expected.
321 *
322 * @param name name of the field in the table
323 * @param[out] dst where to store the result, allocated
324 * @param[out] sptr where to store the size of @a dst
325 * @return array entry for the result specification to use
326 */
327struct GNUNET_PQ_ResultSpec
328GNUNET_PQ_result_spec_variable_size (const char *name,
329 void **dst,
330 size_t *sptr);
331
332
333/**
334 * 0-terminated string expected. 320 * 0-terminated string expected.
335 * 321 *
336 * @param name name of the field in the table 322 * @param name name of the field in the table
diff --git a/src/include/gnunet_protocols.h b/src/include/gnunet_protocols.h
index b2807e990..1d8049593 100644
--- a/src/include/gnunet_protocols.h
+++ b/src/include/gnunet_protocols.h
@@ -424,11 +424,6 @@ extern "C"
424#define GNUNET_MESSAGE_TYPE_DATASTORE_PUT 95 424#define GNUNET_MESSAGE_TYPE_DATASTORE_PUT 95
425 425
426/** 426/**
427 * Message sent by datastore client to update data.
428 */
429#define GNUNET_MESSAGE_TYPE_DATASTORE_UPDATE 96
430
431/**
432 * Message sent by datastore client to get data. 427 * Message sent by datastore client to get data.
433 */ 428 */
434#define GNUNET_MESSAGE_TYPE_DATASTORE_GET 97 429#define GNUNET_MESSAGE_TYPE_DATASTORE_GET 97
@@ -1645,6 +1640,12 @@ extern "C"
1645 * Demand the whole element from the other 1640 * Demand the whole element from the other
1646 * peer, given only the hash code. 1641 * peer, given only the hash code.
1647 */ 1642 */
1643#define GNUNET_MESSAGE_TYPE_SET_UNION_P2P_REQUEST_FULL 565
1644
1645/**
1646 * Demand the whole element from the other
1647 * peer, given only the hash code.
1648 */
1648#define GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DEMAND 566 1649#define GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DEMAND 566
1649 1650
1650/** 1651/**
@@ -1800,6 +1801,19 @@ extern "C"
1800 */ 1801 */
1801#define GNUNET_MESSAGE_TYPE_SET_COPY_LAZY_CONNECT 596 1802#define GNUNET_MESSAGE_TYPE_SET_COPY_LAZY_CONNECT 596
1802 1803
1804/**
1805 * Request all missing elements from the other peer,
1806 * based on their sets and the elements we previously sent
1807 * with #GNUNET_MESSAGE_TYPE_SET_P2P_ELEMENTS.
1808 */
1809#define GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_DONE 597
1810
1811/**
1812 * Send a set element, not as response to a demand but because
1813 * we're sending the full set.
1814 */
1815#define GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_ELEMENT 598
1816
1803 1817
1804/******************************************************************************* 1818/*******************************************************************************
1805 * TESTBED LOGGER message types 1819 * TESTBED LOGGER message types
@@ -2664,10 +2678,21 @@ extern "C"
2664 2678
2665/** 2679/**
2666 * Hop-by-hop, connection dependent ACK. 2680 * Hop-by-hop, connection dependent ACK.
2681 *
2682 * @deprecated
2667 */ 2683 */
2668#define GNUNET_MESSAGE_TYPE_CADET_CONNECTION_HOP_BY_HOP_ENCRYPTED_ACK 1005 2684#define GNUNET_MESSAGE_TYPE_CADET_CONNECTION_HOP_BY_HOP_ENCRYPTED_ACK 1005
2669 2685
2670/** 2686/**
2687 * We do not bother with ACKs for
2688 * #GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED messages, but we instead
2689 * poll for one if we got nothing for a while and start to be worried.
2690 *
2691 * @deprecated
2692 */
2693#define GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED_POLL 1006
2694
2695/**
2671 * Axolotl key exchange. 2696 * Axolotl key exchange.
2672 */ 2697 */
2673#define GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX 1007 2698#define GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX 1007
@@ -2678,11 +2703,9 @@ extern "C"
2678#define GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED 1008 2703#define GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED 1008
2679 2704
2680/** 2705/**
2681 * We do not bother with ACKs for 2706 * Axolotl key exchange response with authentication.
2682 * #GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED messages, but we instead
2683 * poll for one if we got nothing for a while and start to be worried.
2684 */ 2707 */
2685#define GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED_POLL 1006 2708#define GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX_AUTH 1009
2686 2709
2687 2710
2688 2711
@@ -2720,6 +2743,8 @@ extern "C"
2720 2743
2721/** 2744/**
2722 * Reject the creation of a channel 2745 * Reject the creation of a channel
2746 *
2747 * @deprecated
2723 */ 2748 */
2724#define GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_NACK_DEPRECATED 1016 2749#define GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_NACK_DEPRECATED 1016
2725 2750
diff --git a/src/include/gnunet_scheduler_lib.h b/src/include/gnunet_scheduler_lib.h
index 2be1858ce..a7385e31c 100644
--- a/src/include/gnunet_scheduler_lib.h
+++ b/src/include/gnunet_scheduler_lib.h
@@ -97,6 +97,84 @@ enum GNUNET_SCHEDULER_Reason
97 97
98 98
99/** 99/**
100 * Possible events on FDs, used as a bitmask.
101 * Modelled after GPollFD.
102 */
103enum GNUNET_SCHEDULER_EventType
104{
105
106 /**
107 * No event (useful for timeout).
108 */
109 GNUNET_SCHEDULER_ET_NONE = 0,
110
111 /**
112 * Data available for reading.
113 */
114 GNUNET_SCHEDULER_ET_IN = 1,
115
116 /**
117 * Buffer available for writing.
118 */
119 GNUNET_SCHEDULER_ET_OUT = 2,
120
121 /**
122 *
123 */
124 GNUNET_SCHEDULER_ET_HUP = 4,
125
126 /**
127 *
128 */
129 GNUNET_SCHEDULER_ET_ERR = 8,
130
131 /**
132 *
133 */
134 GNUNET_SCHEDULER_ET_PRI = 16,
135
136 /**
137 *
138 */
139 GNUNET_SCHEDULER_ET_NVAL = 32
140
141};
142
143
144/**
145 * Information about an event relating to a file descriptor/socket.
146 */
147struct GNUNET_SCHEDULER_FdInfo
148{
149
150 /**
151 * GNUnet network socket the event is about, matches @a sock,
152 * NULL if this is about a file handle or if no network
153 * handle was given to the scheduler originally.
154 */
155 struct GNUNET_NETWORK_Handle *fd;
156
157 /**
158 * GNUnet file handle the event is about, matches @a sock,
159 * NULL if this is about a network socket or if no network
160 * handle was given to the scheduler originally.
161 */
162 struct GNUNET_DISK_FileHandle *fh;
163
164 /**
165 * Type of the event that was generated related to @e sock.
166 */
167 enum GNUNET_SCHEDULER_EventType et;
168
169 /**
170 * Underlying OS handle the event was about.
171 */
172 int sock;
173
174};
175
176
177/**
100 * Context information passed to each scheduler task. 178 * Context information passed to each scheduler task.
101 */ 179 */
102struct GNUNET_SCHEDULER_TaskContext 180struct GNUNET_SCHEDULER_TaskContext
@@ -107,16 +185,29 @@ struct GNUNET_SCHEDULER_TaskContext
107 enum GNUNET_SCHEDULER_Reason reason; 185 enum GNUNET_SCHEDULER_Reason reason;
108 186
109 /** 187 /**
110 * Set of file descriptors ready for reading; 188 * Length of the following array.
111 * note that additional bits may be set 189 */
112 * that were not in the original request 190 unsigned int fds_len;
191
192 /**
193 * Array of length @e fds_len with information about ready FDs.
194 * Note that we use the same format regardless of the internal
195 * event loop that was used. The given array should only contain
196 * information about file descriptors relevant to the current task.
197 */
198 const struct GNUNET_SCHEDULER_FdInfo *fds;
199
200 /**
201 * Set of file descriptors ready for reading; note that additional
202 * bits may be set that were not in the original request.
203 * @deprecated
113 */ 204 */
114 const struct GNUNET_NETWORK_FDSet *read_ready; 205 const struct GNUNET_NETWORK_FDSet *read_ready;
115 206
116 /** 207 /**
117 * Set of file descriptors ready for writing; 208 * Set of file descriptors ready for writing; note that additional
118 * note that additional bits may be set 209 * bits may be set that were not in the original request.
119 * that were not in the original request. 210 * @deprecated
120 */ 211 */
121 const struct GNUNET_NETWORK_FDSet *write_ready; 212 const struct GNUNET_NETWORK_FDSet *write_ready;
122 213
@@ -124,16 +215,155 @@ struct GNUNET_SCHEDULER_TaskContext
124 215
125 216
126/** 217/**
218 * Function used by event-loop implementations to signal the scheduler
219 * that a particular @a task is ready due to an event of type @a et.
220 *
221 * This function will then queue the task to notify the application
222 * that the task is ready (with the respective priority).
223 *
224 * @param task the task that is ready
225 * @param et information about why the task is ready
226 */
227void
228GNUNET_SCHEDULER_task_ready (struct GNUNET_SCHEDULER_Task *task,
229 enum GNUNET_SCHEDULER_EventType et);
230
231
232/**
233 * Handle to the scheduler's state to be used by the driver.
234 */
235struct GNUNET_SCHEDULER_Handle;
236
237
238/**
239 * Function called by the driver to tell the scheduler to run some of
240 * the tasks that are ready. This function may return even though
241 * there are tasks left to run just to give other tasks a chance as
242 * well. If we return #GNUNET_YES, the driver should call this
243 * function again as soon as possible, while if we return #GNUNET_NO
244 * it must block until the operating system has more work as the
245 * scheduler has no more work to do right now.
246 *
247 * @param sh scheduler handle that was given to the `loop`
248 * @return #GNUNET_OK if there are more tasks that are ready,
249 * and thus we would like to run more (yield to avoid
250 * blocking other activities for too long)
251 * #GNUNET_NO if we are done running tasks (yield to block)
252 * #GNUNET_SYSERR on error
253 */
254int
255GNUNET_SCHEDULER_run_from_driver (struct GNUNET_SCHEDULER_Handle *sh);
256
257
258/**
259 * API a driver has to implement for
260 * #GNUNET_SCHEDULER_run_with_driver().
261 */
262struct GNUNET_SCHEDULER_Driver
263{
264
265 /**
266 * Closure to pass to the functions in this struct.
267 */
268 void *cls;
269
270 /**
271 * Add a @a task to be run if the conditions given
272 * in @a fdi are satisfied.
273 *
274 * @param cls closure
275 * @param task task to add
276 * @param fdi conditions to watch for
277 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
278 * (i.e. @a fdi too high or invalid)
279 */
280 int
281 (*add)(void *cls,
282 struct GNUNET_SCHEDULER_Task *task,
283 struct GNUNET_SCHEDULER_FdInfo *fdi);
284
285 /**
286 * Delete a @a task from the set of tasks to be run.
287 *
288 * @param cls closure
289 * @param task task to delete
290 * @param fdi conditions to watch for (must match @e add call)
291 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
292 * (i.e. @a task or @a fdi do not match prior @e add call)
293 */
294 int
295 (*del)(void *cls,
296 struct GNUNET_SCHEDULER_Task *task,
297 const struct GNUNET_SCHEDULER_FdInfo *fdi);
298
299 /**
300 * Set time at which we definitively want to get a wakeup call.
301 *
302 * @param cls closure
303 * @param dt time when we want to wake up next
304 */
305 void
306 (*set_wakeup)(void *cls,
307 struct GNUNET_TIME_Absolute dt);
308
309 /**
310 * Event loop's "main" function, to be called from
311 * #GNUNET_SCHEDULER_run_with_driver() to actually
312 * launch the loop.
313 *
314 * @param cls closure
315 * @param sh scheduler handle to pass to
316 * #GNUNET_SCHEDULER_run_from_driver()
317 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
318 */
319 int
320 (*loop)(void *cls,
321 struct GNUNET_SCHEDULER_Handle *sh);
322
323};
324
325
326/**
127 * Signature of the main function of a task. 327 * Signature of the main function of a task.
128 * 328 *
129 * @param cls closure 329 * @param cls closure
130 * @param tc context information (why was this task triggered now)
131 */ 330 */
132typedef void 331typedef void
133(*GNUNET_SCHEDULER_TaskCallback) (void *cls); 332(*GNUNET_SCHEDULER_TaskCallback) (void *cls);
134 333
135 334
136/** 335/**
336 * Initialize and run scheduler. This function will return when all
337 * tasks have completed. On systems with signals, receiving a SIGTERM
338 * (and other similar signals) will cause #GNUNET_SCHEDULER_shutdown
339 * to be run after the active task is complete. As a result, SIGTERM
340 * causes all shutdown tasks to be scheduled with reason
341 * #GNUNET_SCHEDULER_REASON_SHUTDOWN. (However, tasks added
342 * afterwards will execute normally!). Note that any particular
343 * signal will only shut down one scheduler; applications should
344 * always only create a single scheduler.
345 *
346 * @param driver drive to use for the event loop
347 * @param task task to run first (and immediately)
348 * @param task_cls closure of @a task
349 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
350 */
351int
352GNUNET_SCHEDULER_run_with_driver (const struct GNUNET_SCHEDULER_Driver *driver,
353 GNUNET_SCHEDULER_TaskCallback task,
354 void *task_cls);
355
356
357/**
358 * Obtain the driver for using select() as the event loop.
359 *
360 * @return NULL on error
361 */
362const struct GNUNET_SCHEDULER_Driver *
363GNUNET_SCHEDULER_driver_select (void);
364
365
366/**
137 * Signature of the select function used by the scheduler. 367 * Signature of the select function used by the scheduler.
138 * #GNUNET_NETWORK_socket_select matches it. 368 * #GNUNET_NETWORK_socket_select matches it.
139 * 369 *
@@ -571,7 +801,7 @@ GNUNET_SCHEDULER_add_select (enum GNUNET_SCHEDULER_Priority prio,
571 * Sets the select function to use in the scheduler (scheduler_select). 801 * Sets the select function to use in the scheduler (scheduler_select).
572 * 802 *
573 * @param new_select new select function to use (NULL to reset to default) 803 * @param new_select new select function to use (NULL to reset to default)
574 * @param new_select_cls closure for 'new_select' 804 * @param new_select_cls closure for @a new_select
575 */ 805 */
576void 806void
577GNUNET_SCHEDULER_set_select (GNUNET_SCHEDULER_select new_select, 807GNUNET_SCHEDULER_set_select (GNUNET_SCHEDULER_select new_select,
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_set_service.h b/src/include/gnunet_set_service.h
index 44773f187..6e822d82e 100644
--- a/src/include/gnunet_set_service.h
+++ b/src/include/gnunet_set_service.h
@@ -126,7 +126,7 @@ enum GNUNET_SET_Status
126 126
127 /** 127 /**
128 * Element should be added to the result set 128 * Element should be added to the result set
129 * of the remove peer, i.e. the remote peer is 129 * of the remote peer, i.e. the remote peer is
130 * missing an element. 130 * missing an element.
131 * 131 *
132 * Only applies to #GNUNET_SET_RESULT_SYMMETRIC 132 * Only applies to #GNUNET_SET_RESULT_SYMMETRIC
@@ -153,6 +153,7 @@ enum GNUNET_SET_Status
153}; 153};
154 154
155 155
156
156/** 157/**
157 * The way results are given to the client. 158 * The way results are given to the client.
158 */ 159 */
@@ -181,7 +182,7 @@ enum GNUNET_SET_ResultMode
181 GNUNET_SET_RESULT_REMOVED, 182 GNUNET_SET_RESULT_REMOVED,
182 183
183 /** 184 /**
184 * Client gets only elements that have been removed from the set. 185 * Client gets only elements that have been added to the set.
185 * 186 *
186 * Only supported for set union. 187 * Only supported for set union.
187 */ 188 */
@@ -212,6 +213,58 @@ struct GNUNET_SET_Element
212 213
213 214
214/** 215/**
216 * Possible options to pass to a set operation.
217 *
218 * Used as tag for struct #GNUNET_SET_Option.
219 */
220enum GNUNET_SET_OptionType
221{
222 /**
223 * List terminator.
224 */
225 GNUNET_SET_OPTION_END=0,
226 /**
227 * Fail set operations when the other peer shows weird behavior
228 * that might by a Byzantine fault.
229 *
230 * For set union, 'v.num' is a lower bound on elements
231 * that the other peer must have in common with us.
232 */
233 GNUNET_SET_OPTION_BYZANTINE=1,
234 /**
235 * Do not use the optimized set operation, but send full sets.
236 * Might trigger Byzantine fault detection.
237 */
238 GNUNET_SET_OPTION_FORCE_FULL=2,
239 /**
240 * Only use optimized set operations, even though for this
241 * particular set operation they might be much slower.
242 * Might trigger Byzantine fault detection.
243 */
244 GNUNET_SET_OPTION_FORCE_DELTA=4,
245};
246
247
248/**
249 * Option for set operations.
250 */
251struct GNUNET_SET_Option
252{
253 /**
254 * Type of the option.
255 */
256 enum GNUNET_SET_OptionType type;
257
258 /**
259 * Value for the option, only used with some options.
260 */
261 union {
262 uint64_t num;
263 } v;
264};
265
266
267/**
215 * Continuation used for some of the set operations 268 * Continuation used for some of the set operations
216 * 269 *
217 * @param cls closure 270 * @param cls closure
@@ -226,11 +279,13 @@ typedef void
226 * 279 *
227 * @param cls closure 280 * @param cls closure
228 * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK 281 * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
282 * @param current_size current set size
229 * @param status see `enum GNUNET_SET_Status` 283 * @param status see `enum GNUNET_SET_Status`
230 */ 284 */
231typedef void 285typedef void
232(*GNUNET_SET_ResultIterator) (void *cls, 286(*GNUNET_SET_ResultIterator) (void *cls,
233 const struct GNUNET_SET_Element *element, 287 const struct GNUNET_SET_Element *element,
288 uint64_t current_size,
234 enum GNUNET_SET_Status status); 289 enum GNUNET_SET_Status status);
235 290
236/** 291/**
@@ -367,6 +422,7 @@ GNUNET_SET_prepare (const struct GNUNET_PeerIdentity *other_peer,
367 const struct GNUNET_HashCode *app_id, 422 const struct GNUNET_HashCode *app_id,
368 const struct GNUNET_MessageHeader *context_msg, 423 const struct GNUNET_MessageHeader *context_msg,
369 enum GNUNET_SET_ResultMode result_mode, 424 enum GNUNET_SET_ResultMode result_mode,
425 struct GNUNET_SET_Option options[],
370 GNUNET_SET_ResultIterator result_cb, 426 GNUNET_SET_ResultIterator result_cb,
371 void *result_cls); 427 void *result_cls);
372 428
@@ -420,6 +476,7 @@ GNUNET_SET_listen_cancel (struct GNUNET_SET_ListenHandle *lh);
420struct GNUNET_SET_OperationHandle * 476struct GNUNET_SET_OperationHandle *
421GNUNET_SET_accept (struct GNUNET_SET_Request *request, 477GNUNET_SET_accept (struct GNUNET_SET_Request *request,
422 enum GNUNET_SET_ResultMode result_mode, 478 enum GNUNET_SET_ResultMode result_mode,
479 struct GNUNET_SET_Option options[],
423 GNUNET_SET_ResultIterator result_cb, 480 GNUNET_SET_ResultIterator result_cb,
424 void *result_cls); 481 void *result_cls);
425 482
diff --git a/src/include/gnunet_sq_lib.h b/src/include/gnunet_sq_lib.h
new file mode 100644
index 000000000..c196d7767
--- /dev/null
+++ b/src/include/gnunet_sq_lib.h
@@ -0,0 +1,451 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2017 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify it under the
6 terms of the GNU General Public License as published by the Free Software
7 Foundation; either version 3, or (at your option) any later version.
8
9 GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License along with
14 GNUnet; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
15*/
16/**
17 * @file include/gnunet_sq_lib.h
18 * @brief helper functions for Sqlite3 DB interactions
19 * @author Christian Grothoff
20 */
21#ifndef GNUNET_SQ_LIB_H
22#define GNUNET_SQ_LIB_H
23
24#include <sqlite3.h>
25#include "gnunet_util_lib.h"
26
27
28/**
29 * Function called to convert input argument into SQL parameters.
30 *
31 * @param cls closure
32 * @param data pointer to input argument
33 * @param data_len number of bytes in @a data (if applicable)
34 * @param stmt sqlite statement to bind parameters for
35 * @param off offset of the argument to bind in @a stmt, numbered from 1,
36 * so immediately suitable for passing to `sqlite3_bind`-functions.
37 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
38 */
39typedef int
40(*GNUNET_SQ_QueryConverter)(void *cls,
41 const void *data,
42 size_t data_len,
43 sqlite3_stmt *stmt,
44 unsigned int off);
45
46
47/**
48 * @brief Description of a DB query parameter.
49 */
50struct GNUNET_SQ_QueryParam
51{
52
53 /**
54 * Function for how to handle this type of entry.
55 */
56 GNUNET_SQ_QueryConverter conv;
57
58 /**
59 * Closure for @e conv.
60 */
61 void *conv_cls;
62
63 /**
64 * Data or NULL.
65 */
66 const void *data;
67
68 /**
69 * Size of @e data
70 */
71 size_t size;
72
73 /**
74 * Number of parameters eaten by this operation.
75 */
76 unsigned int num_params;
77};
78
79
80/**
81 * End of query parameter specification.
82 */
83#define GNUNET_SQ_query_param_end { NULL, NULL, NULL, 0, 0 }
84
85
86/**
87 * Generate query parameter for a buffer @a ptr of
88 * @a ptr_size bytes.
89 *
90 * @param ptr pointer to the query parameter to pass
91 * @oaran ptr_size number of bytes in @a ptr
92 */
93struct GNUNET_SQ_QueryParam
94GNUNET_SQ_query_param_fixed_size (const void *ptr,
95 size_t ptr_size);
96
97
98
99/**
100 * Generate query parameter for a string.
101 *
102 * @param ptr pointer to the string query parameter to pass
103 */
104struct GNUNET_SQ_QueryParam
105GNUNET_SQ_query_param_string (const char *ptr);
106
107
108/**
109 * Generate fixed-size query parameter with size determined
110 * by variable type.
111 *
112 * @param x pointer to the query parameter to pass.
113 */
114#define GNUNET_SQ_query_param_auto_from_type(x) GNUNET_SQ_query_param_fixed_size ((x), sizeof (*(x)))
115
116
117/**
118 * Generate query parameter for an RSA public key. The
119 * database must contain a BLOB type in the respective position.
120 *
121 * @param x the query parameter to pass.
122 */
123struct GNUNET_SQ_QueryParam
124GNUNET_SQ_query_param_rsa_public_key (const struct GNUNET_CRYPTO_RsaPublicKey *x);
125
126
127/**
128 * Generate query parameter for an RSA signature. The
129 * database must contain a BLOB type in the respective position.
130 *
131 * @param x the query parameter to pass
132 */
133struct GNUNET_SQ_QueryParam
134GNUNET_SQ_query_param_rsa_signature (const struct GNUNET_CRYPTO_RsaSignature *x);
135
136
137/**
138 * Generate query parameter for an absolute time value.
139 * The database must store a 64-bit integer.
140 *
141 * @param x pointer to the query parameter to pass
142 */
143struct GNUNET_SQ_QueryParam
144GNUNET_SQ_query_param_absolute_time (const struct GNUNET_TIME_Absolute *x);
145
146
147/**
148 * Generate query parameter for an absolute time value.
149 * The database must store a 64-bit integer.
150 *
151 * @param x pointer to the query parameter to pass
152 */
153struct GNUNET_SQ_QueryParam
154GNUNET_SQ_query_param_absolute_time_nbo (const struct GNUNET_TIME_AbsoluteNBO *x);
155
156
157/**
158 * Generate query parameter for an uint16_t in host byte order.
159 *
160 * @param x pointer to the query parameter to pass
161 */
162struct GNUNET_SQ_QueryParam
163GNUNET_SQ_query_param_uint16 (const uint16_t *x);
164
165
166/**
167 * Generate query parameter for an uint32_t in host byte order.
168 *
169 * @param x pointer to the query parameter to pass
170 */
171struct GNUNET_SQ_QueryParam
172GNUNET_SQ_query_param_uint32 (const uint32_t *x);
173
174
175/**
176 * Generate query parameter for an uint16_t in host byte order.
177 *
178 * @param x pointer to the query parameter to pass
179 */
180struct GNUNET_SQ_QueryParam
181GNUNET_SQ_query_param_uint64 (const uint64_t *x);
182
183
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/**
208 * Extract data from a Postgres database @a result at row @a row.
209 *
210 * @param cls closure
211 * @param result where to extract data from
212 * @param column column to extract data from
213 * @param[in,out] dst_size where to store size of result, may be NULL
214 * @param[out] dst where to store the result
215 * @return
216 * #GNUNET_YES if all results could be extracted
217 * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
218 */
219typedef int
220(*GNUNET_SQ_ResultConverter)(void *cls,
221 sqlite3_stmt *result,
222 unsigned int column,
223 size_t *dst_size,
224 void *dst);
225
226
227/**
228 * @brief Description of a DB result cell.
229 */
230struct GNUNET_SQ_ResultSpec;
231
232
233/**
234 * Function called to clean up memory allocated
235 * by a #GNUNET_SQ_ResultConverter.
236 *
237 * @param cls closure
238 */
239typedef void
240(*GNUNET_SQ_ResultCleanup)(void *cls);
241
242
243/**
244 * @brief Description of a DB result cell.
245 */
246struct GNUNET_SQ_ResultSpec
247{
248
249 /**
250 * What is the format of the result?
251 */
252 GNUNET_SQ_ResultConverter conv;
253
254 /**
255 * Function to clean up result data, NULL if cleanup is
256 * not necessary.
257 */
258 GNUNET_SQ_ResultCleanup cleaner;
259
260 /**
261 * Closure for @e conv and @e cleaner.
262 */
263 void *cls;
264
265 /**
266 * Destination for the data.
267 */
268 void *dst;
269
270 /**
271 * Allowed size for the data, 0 for variable-size
272 * (in this case, the type of @e dst is a `void **`
273 * and we need to allocate a buffer of the right size).
274 */
275 size_t dst_size;
276
277 /**
278 * Where to store actual size of the result. If left at
279 * NULL, will be made to point to @e dst_size before
280 * @a conv is called.
281 */
282 size_t *result_size;
283
284 /**
285 * Number of parameters (columns) eaten by this operation.
286 */
287 unsigned int num_params;
288
289};
290
291
292/**
293 * End of result parameter specification.
294 *
295 * @return array last entry for the result specification to use
296 */
297#define GNUNET_SQ_result_spec_end { NULL, NULL, NULL, NULL, 0, NULL }
298
299
300/**
301 * Variable-size result expected.
302 *
303 * @param[out] dst where to store the result, allocated
304 * @param[out] sptr where to store the size of @a dst
305 * @return array entry for the result specification to use
306 */
307struct GNUNET_SQ_ResultSpec
308GNUNET_SQ_result_spec_variable_size (void **dst,
309 size_t *sptr);
310
311
312/**
313 * Fixed-size result expected.
314 *
315 * @param[out] dst where to store the result
316 * @param dst_size number of bytes in @a dst
317 * @return array entry for the result specification to use
318 */
319struct GNUNET_SQ_ResultSpec
320GNUNET_SQ_result_spec_fixed_size (void *dst,
321 size_t dst_size);
322
323
324/**
325 * We expect a fixed-size result, with size determined by the type of `* dst`
326 *
327 * @param dst point to where to store the result, type fits expected result size
328 * @return array entry for the result specification to use
329 */
330#define GNUNET_SQ_result_spec_auto_from_type(dst) GNUNET_SQ_result_spec_fixed_size ((dst), sizeof (*(dst)))
331
332
333/**
334 * Variable-size result expected.
335 *
336 * @param[out] dst where to store the result, allocated
337 * @param[out] sptr where to store the size of @a dst
338 * @return array entry for the result specification to use
339 */
340struct GNUNET_SQ_ResultSpec
341GNUNET_SQ_result_spec_variable_size (void **dst,
342 size_t *sptr);
343
344
345/**
346 * 0-terminated string expected.
347 *
348 * @param[out] dst where to store the result, allocated
349 * @return array entry for the result specification to use
350 */
351struct GNUNET_SQ_ResultSpec
352GNUNET_SQ_result_spec_string (char **dst);
353
354
355/**
356 * RSA public key expected.
357 *
358 * @param[out] rsa where to store the result
359 * @return array entry for the result specification to use
360 */
361struct GNUNET_SQ_ResultSpec
362GNUNET_SQ_result_spec_rsa_public_key (struct GNUNET_CRYPTO_RsaPublicKey **rsa);
363
364
365/**
366 * RSA signature expected.
367 *
368 * @param[out] sig where to store the result;
369 * @return array entry for the result specification to use
370 */
371struct GNUNET_SQ_ResultSpec
372GNUNET_SQ_result_spec_rsa_signature (struct GNUNET_CRYPTO_RsaSignature **sig);
373
374
375/**
376 * Absolute time expected.
377 *
378 * @param[out] at where to store the result
379 * @return array entry for the result specification to use
380 */
381struct GNUNET_SQ_ResultSpec
382GNUNET_SQ_result_spec_absolute_time (struct GNUNET_TIME_Absolute *at);
383
384
385/**
386 * Absolute time expected.
387 *
388 * @param[out] at where to store the result
389 * @return array entry for the result specification to use
390 */
391struct GNUNET_SQ_ResultSpec
392GNUNET_SQ_result_spec_absolute_time_nbo (struct GNUNET_TIME_AbsoluteNBO *at);
393
394
395/**
396 * uint16_t expected.
397 *
398 * @param[out] u16 where to store the result
399 * @return array entry for the result specification to use
400 */
401struct GNUNET_SQ_ResultSpec
402GNUNET_SQ_result_spec_uint16 (uint16_t *u16);
403
404
405/**
406 * uint32_t expected.
407 *
408 * @param[out] u32 where to store the result
409 * @return array entry for the result specification to use
410 */
411struct GNUNET_SQ_ResultSpec
412GNUNET_SQ_result_spec_uint32 (uint32_t *u32);
413
414
415/**
416 * uint64_t expected.
417 *
418 * @param[out] u64 where to store the result
419 * @return array entry for the result specification to use
420 */
421struct GNUNET_SQ_ResultSpec
422GNUNET_SQ_result_spec_uint64 (uint64_t *u64);
423
424
425/**
426 * Extract results from a query result according to the given specification.
427 *
428 * @param result result to process
429 * @param[in,out] rs result specification to extract for
430 * @return
431 * #GNUNET_OK if all results could be extracted
432 * #GNUNET_SYSERR if a result was invalid (non-existing field)
433 */
434int
435GNUNET_SQ_extract_result (sqlite3_stmt *result,
436 struct GNUNET_SQ_ResultSpec *rs);
437
438
439/**
440 * Free all memory that was allocated in @a rs during
441 * #GNUNET_SQ_extract_result().
442 *
443 * @param rs reult specification to clean up
444 */
445void
446GNUNET_SQ_cleanup_result (struct GNUNET_SQ_ResultSpec *rs);
447
448
449#endif /* GNUNET_SQ_LIB_H_ */
450
451/* end of include/gnunet_sq_lib.h */
diff --git a/src/include/gnunet_strings_lib.h b/src/include/gnunet_strings_lib.h
index 0328882dd..144780c82 100644
--- a/src/include/gnunet_strings_lib.h
+++ b/src/include/gnunet_strings_lib.h
@@ -360,6 +360,18 @@ GNUNET_STRINGS_base64_decode (const char *data,
360 360
361 361
362/** 362/**
363 * Convert a peer path to a human-readable string.
364 *
365 * @param pids array of PIDs to convert to a string
366 * @param num_pids length of the @a pids array
367 * @return string representing the array of @a pids
368 */
369char *
370GNUNET_STRINGS_pp2s (const struct GNUNET_PeerIdentity *pids,
371 unsigned int num_pids);
372
373
374/**
363 * Parse a path that might be an URI. 375 * Parse a path that might be an URI.
364 * 376 *
365 * @param path path to parse. Must be NULL-terminated. 377 * @param path path to parse. Must be NULL-terminated.
@@ -477,7 +489,7 @@ GNUNET_STRINGS_to_address_ipv4 (const char *zt_addr,
477 489
478 490
479/** 491/**
480 * Parse an address given as a string into a 492 * Parse an address given as a string into a
481 * `struct sockaddr`. 493 * `struct sockaddr`.
482 * 494 *
483 * @param addr the address 495 * @param addr the address
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/.gitignore b/src/integration-tests/.gitignore
index c4d1568f0..46915b2a4 100644
--- a/src/integration-tests/.gitignore
+++ b/src/integration-tests/.gitignore
@@ -1,2 +1,10 @@
1gnunet_testing.py 1gnunet_testing.py
2gnunet_pyexpect.py 2gnunet_pyexpect.py
3gnunet_pyexpect.pyc
4gnunet_testing.pyc
5test_integration_bootstrap_and_connect.py
6test_integration_clique.py
7test_integration_disconnect_nat.py
8test_integration_disconnect.py
9test_integration_reconnect_nat.py
10test_integration_reconnect.py
diff --git a/src/integration-tests/Makefile.am b/src/integration-tests/Makefile.am
index 4e96ee173..6fff0b407 100644
--- a/src/integration-tests/Makefile.am
+++ b/src/integration-tests/Makefile.am
@@ -27,7 +27,7 @@ endif
27 27
28if HAVE_MHD 28if HAVE_MHD
29if ENABLE_TEST_RUN 29if ENABLE_TEST_RUN
30AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; 30AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
31if HAVE_LIBGNURL 31if HAVE_LIBGNURL
32TESTS = \ 32TESTS = \
33 $(check_SCRIPTS) 33 $(check_SCRIPTS)
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 0f386fb40..43752ec4b 100644
--- a/src/multicast/.gitignore
+++ b/src/multicast/.gitignore
@@ -1,2 +1,5 @@
1gnunet-service-multicast 1gnunet-service-multicast
2gnunet-multicast 2gnunet-multicast
3test_multicast
4test_multicast_multipeer
5test_multicast_2peers
diff --git a/src/multicast/Makefile.am b/src/multicast/Makefile.am
index b1f422765..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
@@ -49,13 +50,13 @@ gnunet_service_multicast_LDADD = \
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; 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 de65e0ab7..9683efcff 100644
--- a/src/multicast/gnunet-service-multicast.c
+++ b/src/multicast/gnunet-service-multicast.c
@@ -163,6 +163,16 @@ struct Channel
163 struct GNUNET_PeerIdentity peer; 163 struct GNUNET_PeerIdentity peer;
164 164
165 /** 165 /**
166 * Current window size, set by cadet_notify_window_change()
167 */
168 int32_t window_size;
169
170 /**
171 * Is the connection established?
172 */
173 int8_t is_connected;
174
175 /**
166 * Is the remote peer admitted to the group? 176 * Is the remote peer admitted to the group?
167 * @see enum JoinStatus 177 * @see enum JoinStatus
168 */ 178 */
@@ -336,6 +346,17 @@ struct ReplayRequestKey
336}; 346};
337 347
338 348
349static struct Channel *
350cadet_channel_create (struct Group *grp, struct GNUNET_PeerIdentity *peer);
351
352static void
353cadet_channel_destroy (struct Channel *chn);
354
355static void
356client_send_join_decision (struct Member *mem,
357 const struct MulticastJoinDecisionMessageHeader *hdcsn);
358
359
339/** 360/**
340 * Task run during shutdown. 361 * Task run during shutdown.
341 * 362 *
@@ -443,6 +464,9 @@ replay_key_hash (uint64_t fragment_id, uint64_t message_id,
443static int 464static int
444replay_req_remove_cadet (struct Channel *chn) 465replay_req_remove_cadet (struct Channel *chn)
445{ 466{
467 if (NULL == chn || NULL == chn->group)
468 return GNUNET_SYSERR;
469
446 struct GNUNET_CONTAINER_MultiHashMap * 470 struct GNUNET_CONTAINER_MultiHashMap *
447 grp_replay_req = GNUNET_CONTAINER_multihashmap_get (replay_req_cadet, 471 grp_replay_req = GNUNET_CONTAINER_multihashmap_get (replay_req_cadet,
448 &chn->group->pub_key_hash); 472 &chn->group->pub_key_hash);
@@ -497,7 +521,7 @@ replay_req_remove_client (struct Group *grp, struct GNUNET_SERVICE_Client *clien
497 { 521 {
498 if (c == client) 522 if (c == client)
499 { 523 {
500 GNUNET_CONTAINER_multihashmap_remove (replay_req_client, &key, client); 524 GNUNET_CONTAINER_multihashmap_remove (grp_replay_req, &key, client);
501 GNUNET_CONTAINER_multihashmap_iterator_destroy (it); 525 GNUNET_CONTAINER_multihashmap_iterator_destroy (it);
502 return GNUNET_YES; 526 return GNUNET_YES;
503 } 527 }
@@ -653,6 +677,9 @@ client_send_origin (struct GNUNET_HashCode *pub_key_hash,
653static void 677static void
654client_send_ack (struct GNUNET_HashCode *pub_key_hash) 678client_send_ack (struct GNUNET_HashCode *pub_key_hash)
655{ 679{
680 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
681 "Sending message ACK to client.\n");
682
656 static struct GNUNET_MessageHeader *msg = NULL; 683 static struct GNUNET_MessageHeader *msg = NULL;
657 if (NULL == msg) 684 if (NULL == msg)
658 { 685 {
@@ -672,36 +699,6 @@ struct CadetTransmitClosure
672 699
673 700
674/** 701/**
675 * CADET is ready to transmit a message.
676 */
677size_t
678cadet_notify_transmit_ready (void *cls, size_t buf_size, void *buf)
679{
680 if (0 == buf_size)
681 {
682 /* FIXME: connection closed */
683 return 0;
684 }
685 struct CadetTransmitClosure *tcls = cls;
686 struct Channel *chn = tcls->chn;
687 uint16_t msg_size = ntohs (tcls->msg->size);
688 GNUNET_assert (msg_size <= buf_size);
689 GNUNET_memcpy (buf, tcls->msg, msg_size);
690 GNUNET_free (tcls);
691
692 if (0 == chn->msgs_pending)
693 {
694 GNUNET_break (0);
695 }
696 else if (0 == --chn->msgs_pending)
697 {
698 client_send_ack (&chn->group_pub_hash);
699 }
700 return msg_size;
701}
702
703
704/**
705 * Send a message to a CADET channel. 702 * Send a message to a CADET channel.
706 * 703 *
707 * @param chn Channel. 704 * @param chn Channel.
@@ -710,53 +707,22 @@ cadet_notify_transmit_ready (void *cls, size_t buf_size, void *buf)
710static void 707static void
711cadet_send_channel (struct Channel *chn, const struct GNUNET_MessageHeader *msg) 708cadet_send_channel (struct Channel *chn, const struct GNUNET_MessageHeader *msg)
712{ 709{
713 uint16_t msg_size = ntohs (msg->size); 710 struct GNUNET_MQ_Envelope *
714 struct GNUNET_MessageHeader *msg_copy = GNUNET_malloc (msg_size); 711 env = GNUNET_MQ_msg_copy (msg);
715 GNUNET_memcpy (msg_copy, msg, msg_size);
716
717 struct CadetTransmitClosure *tcls = GNUNET_malloc (sizeof (*tcls));
718 tcls->chn = chn;
719 tcls->msg = msg_copy;
720
721 chn->msgs_pending++;
722 chn->tmit_handle
723 = GNUNET_CADET_notify_transmit_ready (chn->channel, GNUNET_NO,
724 GNUNET_TIME_UNIT_FOREVER_REL,
725 msg_size,
726 &cadet_notify_transmit_ready,
727 tcls);
728 GNUNET_assert (NULL != chn->tmit_handle);
729}
730 712
713 GNUNET_MQ_send (GNUNET_CADET_get_mq (chn->channel), env);
731 714
732/** 715 if (0 < chn->window_size)
733 * Create new outgoing CADET channel. 716 {
734 * 717 client_send_ack (&chn->group_pub_hash);
735 * @param peer 718 }
736 * Peer to connect to. 719 else
737 * @param group_pub_key 720 {
738 * Public key of group the channel belongs to. 721 chn->msgs_pending++;
739 * @param group_pub_hash 722 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
740 * Hash of @a group_pub_key. 723 "%p Queuing message. Pending messages: %u\n",
741 * 724 chn, chn->msgs_pending);
742 * @return Channel. 725 }
743 */
744static struct Channel *
745cadet_channel_create (struct Group *grp, struct GNUNET_PeerIdentity *peer)
746{
747 struct Channel *chn = GNUNET_malloc (sizeof (*chn));
748 chn->group = grp;
749 chn->group_pub_key = grp->pub_key;
750 chn->group_pub_hash = grp->pub_key_hash;
751 chn->peer = *peer;
752 chn->direction = DIR_OUTGOING;
753 chn->join_status = JOIN_WAITING;
754 chn->channel = GNUNET_CADET_channel_create (cadet, chn, &chn->peer,
755 &grp->cadet_port_hash,
756 GNUNET_CADET_OPTION_RELIABLE);
757 GNUNET_CONTAINER_multihashmap_put (channels_out, &chn->group_pub_hash, chn,
758 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
759 return chn;
760} 726}
761 727
762 728
@@ -787,7 +753,7 @@ cadet_send_join_decision_cb (void *cls,
787 const struct MulticastJoinDecisionMessageHeader *hdcsn = cls; 753 const struct MulticastJoinDecisionMessageHeader *hdcsn = cls;
788 struct Channel *chn = channel; 754 struct Channel *chn = channel;
789 755
790 const struct MulticastJoinDecisionMessage *dcsn = 756 const struct MulticastJoinDecisionMessage *dcsn =
791 (struct MulticastJoinDecisionMessage *) &hdcsn[1]; 757 (struct MulticastJoinDecisionMessage *) &hdcsn[1];
792 758
793 if (0 == memcmp (&hdcsn->member_pub_key, &chn->member_pub_key, sizeof (chn->member_pub_key)) 759 if (0 == memcmp (&hdcsn->member_pub_key, &chn->member_pub_key, sizeof (chn->member_pub_key))
@@ -870,31 +836,74 @@ cadet_send_parents (struct GNUNET_HashCode *pub_key_hash,
870 836
871 837
872/** 838/**
873 * New incoming CADET channel. 839 * CADET channel connect handler.
840 *
841 * @see GNUNET_CADET_ConnectEventHandler()
874 */ 842 */
875static void * 843static void *
876cadet_notify_channel_new (void *cls, 844cadet_notify_connect (void *cls,
877 struct GNUNET_CADET_Channel *channel, 845 struct GNUNET_CADET_Channel *channel,
878 const struct GNUNET_PeerIdentity *initiator, 846 const struct GNUNET_PeerIdentity *source)
879 const struct GNUNET_HashCode *port,
880 enum GNUNET_CADET_ChannelOption options)
881{ 847{
882 return NULL; 848 struct Channel *chn = GNUNET_malloc (sizeof *chn);
849 chn->group = cls;
850 chn->channel = channel;
851 chn->direction = DIR_INCOMING;
852 chn->join_status = JOIN_NOT_ASKED;
853
854 GNUNET_CONTAINER_multihashmap_put (channels_in, &chn->group_pub_hash, chn,
855 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
856 return chn;
883} 857}
884 858
885 859
886/** 860/**
887 * CADET channel is being destroyed. 861 * CADET window size change handler.
862 *
863 * @see GNUNET_CADET_WindowSizeEventHandler()
888 */ 864 */
889static void 865static void
890cadet_notify_channel_end (void *cls, 866cadet_notify_window_change (void *cls,
891 const struct GNUNET_CADET_Channel *channel, 867 const struct GNUNET_CADET_Channel *channel,
892 void *ctx) 868 int window_size)
893{ 869{
894 if (NULL == ctx) 870 struct Channel *chn = cls;
871
872 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
873 "%p Window size changed to %d. Pending messages: %u\n",
874 chn, window_size, chn->msgs_pending);
875
876 chn->is_connected = GNUNET_YES;
877 chn->window_size = (int32_t) window_size;
878
879 for (int i = 0; i < window_size; i++)
880 {
881 if (0 < chn->msgs_pending)
882 {
883 client_send_ack (&chn->group_pub_hash);
884 chn->msgs_pending--;
885 }
886 else
887 {
888 break;
889 }
890 }
891}
892
893
894/**
895 * CADET channel disconnect handler.
896 *
897 * @see GNUNET_CADET_DisconnectEventHandler()
898 */
899static void
900cadet_notify_disconnect (void *cls,
901 const struct GNUNET_CADET_Channel *channel)
902{
903 if (NULL == cls)
895 return; 904 return;
896 905
897 struct Channel *chn = ctx; 906 struct Channel *chn = cls;
898 if (NULL != chn->group) 907 if (NULL != chn->group)
899 { 908 {
900 if (GNUNET_NO == chn->group->is_origin) 909 if (GNUNET_NO == chn->group->is_origin)
@@ -905,12 +914,331 @@ cadet_notify_channel_end (void *cls,
905 } 914 }
906 } 915 }
907 916
908 while (GNUNET_YES == replay_req_remove_cadet (chn)); 917 int ret;
918 do
919 {
920 ret = replay_req_remove_cadet (chn);
921 }
922 while (GNUNET_YES == ret);
909 923
910 GNUNET_free (chn); 924 GNUNET_free (chn);
911} 925}
912 926
913 927
928static int
929check_cadet_join_request (void *cls,
930 const struct MulticastJoinRequestMessage *req)
931{
932 struct Channel *chn = cls;
933
934 if (NULL == chn
935 || JOIN_NOT_ASKED != chn->join_status)
936 {
937 return GNUNET_SYSERR;
938 }
939
940 uint16_t size = ntohs (req->header.size);
941 if (size < sizeof (*req))
942 {
943 GNUNET_break_op (0);
944 return GNUNET_SYSERR;
945 }
946 if (ntohl (req->purpose.size) != (size
947 - sizeof (req->header)
948 - sizeof (req->reserved)
949 - sizeof (req->signature)))
950 {
951 GNUNET_break_op (0);
952 return GNUNET_SYSERR;
953 }
954 if (GNUNET_OK !=
955 GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_MULTICAST_REQUEST,
956 &req->purpose, &req->signature,
957 &req->member_pub_key))
958 {
959 GNUNET_break_op (0);
960 return GNUNET_SYSERR;
961 }
962
963 return GNUNET_OK;
964}
965
966
967/**
968 * Incoming join request message from CADET.
969 */
970static void
971handle_cadet_join_request (void *cls,
972 const struct MulticastJoinRequestMessage *req)
973{
974 struct Channel *chn = cls;
975 GNUNET_CADET_receive_done (chn->channel);
976
977 struct GNUNET_HashCode group_pub_hash;
978 GNUNET_CRYPTO_hash (&req->group_pub_key, sizeof (req->group_pub_key), &group_pub_hash);
979 chn->group_pub_key = req->group_pub_key;
980 chn->group_pub_hash = group_pub_hash;
981 chn->member_pub_key = req->member_pub_key;
982 chn->peer = req->peer;
983 chn->join_status = JOIN_WAITING;
984
985 client_send_all (&group_pub_hash, &req->header);
986}
987
988
989static int
990check_cadet_join_decision (void *cls,
991 const struct MulticastJoinDecisionMessageHeader *hdcsn)
992{
993 uint16_t size = ntohs (hdcsn->header.size);
994 if (size < sizeof (struct MulticastJoinDecisionMessageHeader) +
995 sizeof (struct MulticastJoinDecisionMessage))
996 {
997 GNUNET_break_op (0);
998 return GNUNET_SYSERR;
999 }
1000
1001 struct Channel *chn = cls;
1002 if (NULL == chn)
1003 {
1004 GNUNET_break (0);
1005 return GNUNET_SYSERR;
1006 }
1007 if (NULL == chn->group || GNUNET_NO != chn->group->is_origin)
1008 {
1009 GNUNET_break (0);
1010 return GNUNET_SYSERR;
1011 }
1012 switch (chn->join_status)
1013 {
1014 case JOIN_REFUSED:
1015 return GNUNET_SYSERR;
1016
1017 case JOIN_ADMITTED:
1018 return GNUNET_OK;
1019
1020 case JOIN_NOT_ASKED:
1021 case JOIN_WAITING:
1022 break;
1023 }
1024
1025 return GNUNET_OK;
1026}
1027
1028
1029/**
1030 * Incoming join decision message from CADET.
1031 */
1032static void
1033handle_cadet_join_decision (void *cls,
1034 const struct MulticastJoinDecisionMessageHeader *hdcsn)
1035{
1036 const struct MulticastJoinDecisionMessage *
1037 dcsn = (const struct MulticastJoinDecisionMessage *) &hdcsn[1];
1038
1039 struct Channel *chn = cls;
1040 GNUNET_CADET_receive_done (chn->channel);
1041
1042 // FIXME: do we need to copy chn->peer or compare it with hdcsn->peer?
1043 struct Member *mem = (struct Member *) chn->group;
1044 client_send_join_decision (mem, hdcsn);
1045 if (GNUNET_YES == ntohl (dcsn->is_admitted))
1046 {
1047 chn->join_status = JOIN_ADMITTED;
1048 }
1049 else
1050 {
1051 chn->join_status = JOIN_REFUSED;
1052 cadet_channel_destroy (chn);
1053 }
1054}
1055
1056
1057static int
1058check_cadet_message (void *cls,
1059 const struct GNUNET_MULTICAST_MessageHeader *msg)
1060{
1061 uint16_t size = ntohs (msg->header.size);
1062 if (size < sizeof (*msg))
1063 {
1064 GNUNET_break_op (0);
1065 return GNUNET_SYSERR;
1066 }
1067
1068 struct Channel *chn = cls;
1069 if (NULL == chn)
1070 {
1071 GNUNET_break (0);
1072 return GNUNET_SYSERR;
1073 }
1074 if (ntohl (msg->purpose.size) != (size
1075 - sizeof (msg->header)
1076 - sizeof (msg->hop_counter)
1077 - sizeof (msg->signature)))
1078 {
1079 GNUNET_break_op (0);
1080 return GNUNET_SYSERR;
1081 }
1082 if (GNUNET_OK !=
1083 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_MULTICAST_MESSAGE,
1084 &msg->purpose, &msg->signature,
1085 &chn->group_pub_key))
1086 {
1087 GNUNET_break_op (0);
1088 return GNUNET_SYSERR;
1089 }
1090
1091 return GNUNET_OK;
1092}
1093
1094
1095/**
1096 * Incoming multicast message from CADET.
1097 */
1098static void
1099handle_cadet_message (void *cls,
1100 const struct GNUNET_MULTICAST_MessageHeader *msg)
1101{
1102 struct Channel *chn = cls;
1103 GNUNET_CADET_receive_done (chn->channel);
1104 client_send_all (&chn->group_pub_hash, &msg->header);
1105}
1106
1107
1108static int
1109check_cadet_request (void *cls,
1110 const struct GNUNET_MULTICAST_RequestHeader *req)
1111{
1112 uint16_t size = ntohs (req->header.size);
1113 if (size < sizeof (*req))
1114 {
1115 GNUNET_break_op (0);
1116 return GNUNET_SYSERR;
1117 }
1118
1119 struct Channel *chn = cls;
1120 if (NULL == chn)
1121 {
1122 GNUNET_break (0);
1123 return GNUNET_SYSERR;
1124 }
1125 if (ntohl (req->purpose.size) != (size
1126 - sizeof (req->header)
1127 - sizeof (req->member_pub_key)
1128 - sizeof (req->signature)))
1129 {
1130 GNUNET_break_op (0);
1131 return GNUNET_SYSERR;
1132 }
1133 if (GNUNET_OK !=
1134 GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_MULTICAST_REQUEST,
1135 &req->purpose, &req->signature,
1136 &req->member_pub_key))
1137 {
1138 GNUNET_break_op (0);
1139 return GNUNET_SYSERR;
1140 }
1141
1142 return GNUNET_OK;
1143}
1144
1145
1146/**
1147 * Incoming multicast request message from CADET.
1148 */
1149static void
1150handle_cadet_request (void *cls,
1151 const struct GNUNET_MULTICAST_RequestHeader *req)
1152{
1153 struct Channel *chn = cls;
1154 GNUNET_CADET_receive_done (chn->channel);
1155 client_send_origin (&chn->group_pub_hash, &req->header);
1156}
1157
1158
1159static int
1160check_cadet_replay_request (void *cls,
1161 const struct MulticastReplayRequestMessage *req)
1162{
1163 uint16_t size = ntohs (req->header.size);
1164 if (size < sizeof (*req))
1165 {
1166 GNUNET_break_op (0);
1167 return GNUNET_SYSERR;
1168 }
1169
1170 struct Channel *chn = cls;
1171 if (NULL == chn)
1172 {
1173 GNUNET_break_op (0);
1174 return GNUNET_SYSERR;
1175 }
1176
1177 return GNUNET_OK;
1178}
1179
1180
1181/**
1182 * Incoming multicast replay request from CADET.
1183 */
1184static void
1185handle_cadet_replay_request (void *cls,
1186 const struct MulticastReplayRequestMessage *req)
1187{
1188 struct Channel *chn = cls;
1189 GNUNET_CADET_receive_done (chn->channel);
1190
1191 struct MulticastReplayRequestMessage rep = *req;
1192 GNUNET_memcpy (&rep.member_pub_key, &chn->member_pub_key, sizeof (chn->member_pub_key));
1193
1194 struct GNUNET_CONTAINER_MultiHashMap *
1195 grp_replay_req = GNUNET_CONTAINER_multihashmap_get (replay_req_cadet,
1196 &chn->group->pub_key_hash);
1197 if (NULL == grp_replay_req)
1198 {
1199 grp_replay_req = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
1200 GNUNET_CONTAINER_multihashmap_put (replay_req_cadet,
1201 &chn->group->pub_key_hash, grp_replay_req,
1202 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1203 }
1204 struct GNUNET_HashCode key_hash;
1205 replay_key_hash (rep.fragment_id, rep.message_id, rep.fragment_offset,
1206 rep.flags, &key_hash);
1207 GNUNET_CONTAINER_multihashmap_put (grp_replay_req, &key_hash, chn,
1208 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1209
1210 client_send_random (&chn->group_pub_hash, &rep.header);
1211}
1212
1213
1214static int
1215check_cadet_replay_response (void *cls,
1216 const struct MulticastReplayResponseMessage *res)
1217{
1218 struct Channel *chn = cls;
1219 if (NULL == chn)
1220 {
1221 GNUNET_break (0);
1222 return GNUNET_SYSERR;
1223 }
1224 return GNUNET_OK;
1225}
1226
1227
1228/**
1229 * Incoming multicast replay response from CADET.
1230 */
1231static void
1232handle_cadet_replay_response (void *cls,
1233 const struct MulticastReplayResponseMessage *res)
1234{
1235 struct Channel *chn = cls;
1236 GNUNET_CADET_receive_done (chn->channel);
1237
1238 /* @todo FIXME: got replay error response, send request to other members */
1239}
1240
1241
914static void 1242static void
915group_set_cadet_port_hash (struct Group *grp) 1243group_set_cadet_port_hash (struct Group *grp)
916{ 1244{
@@ -925,6 +1253,78 @@ group_set_cadet_port_hash (struct Group *grp)
925} 1253}
926 1254
927 1255
1256
1257/**
1258 * Create new outgoing CADET channel.
1259 *
1260 * @param peer
1261 * Peer to connect to.
1262 * @param group_pub_key
1263 * Public key of group the channel belongs to.
1264 * @param group_pub_hash
1265 * Hash of @a group_pub_key.
1266 *
1267 * @return Channel.
1268 */
1269static struct Channel *
1270cadet_channel_create (struct Group *grp, struct GNUNET_PeerIdentity *peer)
1271{
1272 struct Channel *chn = GNUNET_malloc (sizeof (*chn));
1273 chn->group = grp;
1274 chn->group_pub_key = grp->pub_key;
1275 chn->group_pub_hash = grp->pub_key_hash;
1276 chn->peer = *peer;
1277 chn->direction = DIR_OUTGOING;
1278 chn->is_connected = GNUNET_NO;
1279 chn->join_status = JOIN_WAITING;
1280
1281 struct GNUNET_MQ_MessageHandler cadet_handlers[] = {
1282 GNUNET_MQ_hd_var_size (cadet_message,
1283 GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE,
1284 struct GNUNET_MULTICAST_MessageHeader,
1285 chn),
1286
1287 GNUNET_MQ_hd_var_size (cadet_join_decision,
1288 GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION,
1289 struct MulticastJoinDecisionMessageHeader,
1290 chn),
1291
1292 GNUNET_MQ_hd_var_size (cadet_replay_request,
1293 GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_REQUEST,
1294 struct MulticastReplayRequestMessage,
1295 chn),
1296
1297 GNUNET_MQ_hd_var_size (cadet_replay_response,
1298 GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE,
1299 struct MulticastReplayResponseMessage,
1300 chn),
1301
1302 GNUNET_MQ_handler_end ()
1303 };
1304
1305 chn->channel = GNUNET_CADET_channel_create (cadet, chn, &chn->peer,
1306 &grp->cadet_port_hash,
1307 GNUNET_CADET_OPTION_RELIABLE,
1308 cadet_notify_window_change,
1309 cadet_notify_disconnect,
1310 cadet_handlers);
1311 GNUNET_CONTAINER_multihashmap_put (channels_out, &chn->group_pub_hash, chn,
1312 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1313 return chn;
1314}
1315
1316
1317/**
1318 * Destroy outgoing CADET channel.
1319 */
1320static void
1321cadet_channel_destroy (struct Channel *chn)
1322{
1323 GNUNET_CADET_channel_destroy (chn->channel);
1324 GNUNET_CONTAINER_multihashmap_remove_all (channels_out, &chn->group_pub_hash);
1325 GNUNET_free (chn);
1326}
1327
928/** 1328/**
929 * Handle a connecting client starting an origin. 1329 * Handle a connecting client starting an origin.
930 */ 1330 */
@@ -961,8 +1361,44 @@ handle_client_origin_start (void *cls,
961 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); 1361 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
962 1362
963 group_set_cadet_port_hash (grp); 1363 group_set_cadet_port_hash (grp);
964 orig->cadet_port = GNUNET_CADET_open_port (cadet, &grp->cadet_port_hash, 1364
965 cadet_notify_channel_new, NULL); 1365 struct GNUNET_MQ_MessageHandler cadet_handlers[] = {
1366 GNUNET_MQ_hd_var_size (cadet_message,
1367 GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE,
1368 struct GNUNET_MULTICAST_MessageHeader,
1369 grp),
1370
1371 GNUNET_MQ_hd_var_size (cadet_request,
1372 GNUNET_MESSAGE_TYPE_MULTICAST_REQUEST,
1373 struct GNUNET_MULTICAST_RequestHeader,
1374 grp),
1375
1376 GNUNET_MQ_hd_var_size (cadet_join_request,
1377 GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_REQUEST,
1378 struct MulticastJoinRequestMessage,
1379 grp),
1380
1381 GNUNET_MQ_hd_var_size (cadet_replay_request,
1382 GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_REQUEST,
1383 struct MulticastReplayRequestMessage,
1384 grp),
1385
1386 GNUNET_MQ_hd_var_size (cadet_replay_response,
1387 GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE,
1388 struct MulticastReplayResponseMessage,
1389 grp),
1390
1391 GNUNET_MQ_handler_end ()
1392 };
1393
1394
1395 orig->cadet_port = GNUNET_CADET_open_port (cadet,
1396 &grp->cadet_port_hash,
1397 cadet_notify_connect,
1398 NULL,
1399 cadet_notify_window_change,
1400 cadet_notify_disconnect,
1401 cadet_handlers);
966 } 1402 }
967 else 1403 else
968 { 1404 {
@@ -1258,10 +1694,8 @@ handle_client_multicast_message (void *cls,
1258 } 1694 }
1259 1695
1260 client_send_all (&grp->pub_key_hash, &out->header); 1696 client_send_all (&grp->pub_key_hash, &out->header);
1261 if (0 == cadet_send_children (&grp->pub_key_hash, &out->header)) 1697 cadet_send_children (&grp->pub_key_hash, &out->header);
1262 { 1698 client_send_ack (&grp->pub_key_hash);
1263 client_send_ack (&grp->pub_key_hash);
1264 }
1265 GNUNET_free (out); 1699 GNUNET_free (out);
1266 1700
1267 GNUNET_SERVICE_client_continue (client); 1701 GNUNET_SERVICE_client_continue (client);
@@ -1544,278 +1978,6 @@ handle_client_replay_response (void *cls,
1544 1978
1545 1979
1546/** 1980/**
1547 * Incoming join request message from CADET.
1548 */
1549int
1550cadet_recv_join_request (void *cls,
1551 struct GNUNET_CADET_Channel *channel,
1552 void **ctx,
1553 const struct GNUNET_MessageHeader *m)
1554{
1555 GNUNET_CADET_receive_done(channel);
1556 const struct MulticastJoinRequestMessage *
1557 req = (const struct MulticastJoinRequestMessage *) m;
1558 uint16_t size = ntohs (m->size);
1559 if (size < sizeof (*req))
1560 {
1561 GNUNET_break_op (0);
1562 return GNUNET_SYSERR;
1563 }
1564 if (NULL != *ctx)
1565 {
1566 GNUNET_break_op (0);
1567 return GNUNET_SYSERR;
1568 }
1569 if (ntohl (req->purpose.size) != (size
1570 - sizeof (req->header)
1571 - sizeof (req->reserved)
1572 - sizeof (req->signature)))
1573 {
1574 GNUNET_break_op (0);
1575 return GNUNET_SYSERR;
1576 }
1577 if (GNUNET_OK !=
1578 GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_MULTICAST_REQUEST,
1579 &req->purpose, &req->signature,
1580 &req->member_pub_key))
1581 {
1582 GNUNET_break_op (0);
1583 return GNUNET_SYSERR;
1584 }
1585
1586 struct GNUNET_HashCode group_pub_hash;
1587 GNUNET_CRYPTO_hash (&req->group_pub_key, sizeof (req->group_pub_key), &group_pub_hash);
1588
1589 struct Channel *chn = GNUNET_malloc (sizeof *chn);
1590 chn->channel = channel;
1591 chn->group_pub_key = req->group_pub_key;
1592 chn->group_pub_hash = group_pub_hash;
1593 chn->member_pub_key = req->member_pub_key;
1594 chn->peer = req->peer;
1595 chn->join_status = JOIN_WAITING;
1596 GNUNET_CONTAINER_multihashmap_put (channels_in, &chn->group_pub_hash, chn,
1597 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1598 *ctx = chn;
1599
1600 client_send_all (&group_pub_hash, m);
1601 return GNUNET_OK;
1602}
1603
1604
1605/**
1606 * Incoming join decision message from CADET.
1607 */
1608int
1609cadet_recv_join_decision (void *cls,
1610 struct GNUNET_CADET_Channel *channel,
1611 void **ctx,
1612 const struct GNUNET_MessageHeader *m)
1613{
1614 GNUNET_CADET_receive_done (channel);
1615 const struct MulticastJoinDecisionMessageHeader *
1616 hdcsn = (const struct MulticastJoinDecisionMessageHeader *) m;
1617 const struct MulticastJoinDecisionMessage *
1618 dcsn = (const struct MulticastJoinDecisionMessage *) &hdcsn[1];
1619 uint16_t size = ntohs (m->size);
1620 if (size < sizeof (struct MulticastJoinDecisionMessageHeader) +
1621 sizeof (struct MulticastJoinDecisionMessage))
1622 {
1623 GNUNET_break_op (0);
1624 return GNUNET_SYSERR;
1625 }
1626 struct Channel *chn = *ctx;
1627 if (NULL == chn)
1628 {
1629 GNUNET_break_op (0);
1630 return GNUNET_SYSERR;
1631 }
1632 if (NULL == chn->group || GNUNET_NO != chn->group->is_origin)
1633 {
1634 GNUNET_break_op (0);
1635 return GNUNET_SYSERR;
1636 }
1637 switch (chn->join_status)
1638 {
1639 case JOIN_REFUSED:
1640 return GNUNET_SYSERR;
1641
1642 case JOIN_ADMITTED:
1643 return GNUNET_OK;
1644
1645 case JOIN_NOT_ASKED:
1646 case JOIN_WAITING:
1647 break;
1648 }
1649
1650 // FIXME: do we need to copy chn->peer or compare it with hdcsn->peer?
1651 struct Member *mem = (struct Member *) chn->group;
1652 client_send_join_decision (mem, hdcsn);
1653 if (GNUNET_YES == ntohl (dcsn->is_admitted))
1654 {
1655 chn->join_status = JOIN_ADMITTED;
1656 return GNUNET_OK;
1657 }
1658 else
1659 {
1660 chn->join_status = JOIN_REFUSED;
1661 return GNUNET_SYSERR;
1662 }
1663}
1664
1665/**
1666 * Incoming multicast message from CADET.
1667 */
1668int
1669cadet_recv_message (void *cls,
1670 struct GNUNET_CADET_Channel *channel,
1671 void **ctx,
1672 const struct GNUNET_MessageHeader *m)
1673{
1674 GNUNET_CADET_receive_done(channel);
1675 const struct GNUNET_MULTICAST_MessageHeader *
1676 msg = (const struct GNUNET_MULTICAST_MessageHeader *) m;
1677 uint16_t size = ntohs (m->size);
1678 if (size < sizeof (*msg))
1679 {
1680 GNUNET_break_op (0);
1681 return GNUNET_SYSERR;
1682 }
1683 struct Channel *chn = *ctx;
1684 if (NULL == chn)
1685 {
1686 GNUNET_break_op (0);
1687 return GNUNET_SYSERR;
1688 }
1689 if (ntohl (msg->purpose.size) != (size
1690 - sizeof (msg->header)
1691 - sizeof (msg->hop_counter)
1692 - sizeof (msg->signature)))
1693 {
1694 GNUNET_break_op (0);
1695 return GNUNET_SYSERR;
1696 }
1697 if (GNUNET_OK !=
1698 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_MULTICAST_MESSAGE,
1699 &msg->purpose, &msg->signature,
1700 &chn->group_pub_key))
1701 {
1702 GNUNET_break_op (0);
1703 return GNUNET_SYSERR;
1704 }
1705
1706 client_send_all (&chn->group_pub_hash, m);
1707 return GNUNET_OK;
1708}
1709
1710
1711/**
1712 * Incoming multicast request message from CADET.
1713 */
1714int
1715cadet_recv_request (void *cls,
1716 struct GNUNET_CADET_Channel *channel,
1717 void **ctx,
1718 const struct GNUNET_MessageHeader *m)
1719{
1720 GNUNET_CADET_receive_done(channel);
1721 const struct GNUNET_MULTICAST_RequestHeader *
1722 req = (const struct GNUNET_MULTICAST_RequestHeader *) m;
1723 uint16_t size = ntohs (m->size);
1724 if (size < sizeof (*req))
1725 {
1726 GNUNET_break_op (0);
1727 return GNUNET_SYSERR;
1728 }
1729 struct Channel *chn = *ctx;
1730 if (NULL == chn)
1731 {
1732 GNUNET_break_op (0);
1733 return GNUNET_SYSERR;
1734 }
1735 if (ntohl (req->purpose.size) != (size
1736 - sizeof (req->header)
1737 - sizeof (req->member_pub_key)
1738 - sizeof (req->signature)))
1739 {
1740 GNUNET_break_op (0);
1741 return GNUNET_SYSERR;
1742 }
1743 if (GNUNET_OK !=
1744 GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_MULTICAST_REQUEST,
1745 &req->purpose, &req->signature,
1746 &req->member_pub_key))
1747 {
1748 GNUNET_break_op (0);
1749 return GNUNET_SYSERR;
1750 }
1751
1752 client_send_origin (&chn->group_pub_hash, m);
1753 return GNUNET_OK;
1754}
1755
1756
1757/**
1758 * Incoming multicast replay request from CADET.
1759 */
1760int
1761cadet_recv_replay_request (void *cls,
1762 struct GNUNET_CADET_Channel *channel,
1763 void **ctx,
1764 const struct GNUNET_MessageHeader *m)
1765{
1766 GNUNET_CADET_receive_done(channel);
1767 struct MulticastReplayRequestMessage rep;
1768 uint16_t size = ntohs (m->size);
1769 if (size < sizeof (rep))
1770 {
1771 GNUNET_break_op (0);
1772 return GNUNET_SYSERR;
1773 }
1774 struct Channel *chn = *ctx;
1775
1776 GNUNET_memcpy (&rep, m, sizeof (rep));
1777 GNUNET_memcpy (&rep.member_pub_key, &chn->member_pub_key, sizeof (chn->member_pub_key));
1778
1779 struct GNUNET_CONTAINER_MultiHashMap *
1780 grp_replay_req = GNUNET_CONTAINER_multihashmap_get (replay_req_cadet,
1781 &chn->group->pub_key_hash);
1782 if (NULL == grp_replay_req)
1783 {
1784 grp_replay_req = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
1785 GNUNET_CONTAINER_multihashmap_put (replay_req_cadet,
1786 &chn->group->pub_key_hash, grp_replay_req,
1787 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1788 }
1789 struct GNUNET_HashCode key_hash;
1790 replay_key_hash (rep.fragment_id, rep.message_id, rep.fragment_offset,
1791 rep.flags, &key_hash);
1792 GNUNET_CONTAINER_multihashmap_put (grp_replay_req, &key_hash, chn,
1793 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1794
1795 client_send_random (&chn->group_pub_hash, &rep.header);
1796 return GNUNET_OK;
1797}
1798
1799
1800/**
1801 * Incoming multicast replay response from CADET.
1802 */
1803int
1804cadet_recv_replay_response (void *cls,
1805 struct GNUNET_CADET_Channel *channel,
1806 void **ctx,
1807 const struct GNUNET_MessageHeader *m)
1808{
1809 GNUNET_CADET_receive_done(channel);
1810 //struct Channel *chn = *ctx;
1811
1812 /* @todo FIXME: got replay error response, send request to other members */
1813
1814 return GNUNET_OK;
1815}
1816
1817
1818/**
1819 * A new client connected. 1981 * A new client connected.
1820 * 1982 *
1821 * @param cls NULL 1983 * @param cls NULL
@@ -1899,32 +2061,6 @@ client_notify_disconnect (void *cls,
1899 2061
1900 2062
1901/** 2063/**
1902 * Message handlers for CADET.
1903 */
1904static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
1905 { cadet_recv_join_request,
1906 GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_REQUEST, 0 },
1907
1908 { cadet_recv_join_decision,
1909 GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION, 0 },
1910
1911 { cadet_recv_message,
1912 GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE, 0 },
1913
1914 { cadet_recv_request,
1915 GNUNET_MESSAGE_TYPE_MULTICAST_REQUEST, 0 },
1916
1917 { cadet_recv_replay_request,
1918 GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_REQUEST, 0 },
1919
1920 { cadet_recv_replay_response,
1921 GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE, 0 },
1922
1923 { NULL, 0, 0 }
1924};
1925
1926
1927/**
1928 * Service started. 2064 * Service started.
1929 * 2065 *
1930 * @param cls closure 2066 * @param cls closure
@@ -1949,9 +2085,8 @@ run (void *cls,
1949 replay_req_cadet = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); 2085 replay_req_cadet = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
1950 replay_req_client = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); 2086 replay_req_client = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
1951 2087
1952 cadet = GNUNET_CADET_connect (cfg, NULL, 2088 cadet = GNUNET_CADET_connect (cfg);
1953 cadet_notify_channel_end, 2089
1954 cadet_handlers);
1955 GNUNET_assert (NULL != cadet); 2090 GNUNET_assert (NULL != cadet);
1956 2091
1957 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, 2092 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
diff --git a/src/multicast/test_multicast.c b/src/multicast/test_multicast.c
index 1e3a4922b..7e9b51e23 100644
--- a/src/multicast/test_multicast.c
+++ b/src/multicast/test_multicast.c
@@ -484,6 +484,10 @@ member_recv_message (void *cls,
484 484
485 switch (test) 485 switch (test)
486 { 486 {
487 case TEST_ORIGIN_TO_ALL:
488 test = TEST_ORIGIN_TO_ALL_RECV;
489 break;
490
487 case TEST_ORIGIN_TO_ALL_RECV: 491 case TEST_ORIGIN_TO_ALL_RECV:
488 // Test 6 starts here 492 // Test 6 starts here
489 member_to_origin (); 493 member_to_origin ();
@@ -523,6 +527,11 @@ origin_recv_message (void *cls,
523 test = TEST_ORIGIN_TO_ALL_RECV; 527 test = TEST_ORIGIN_TO_ALL_RECV;
524 break; 528 break;
525 529
530 case TEST_ORIGIN_TO_ALL_RECV:
531 // Test 6 starts here
532 member_to_origin ();
533 break;
534
526 default: 535 default:
527 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 536 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
528 "Invalid test #%d in origin_recv_message()\n", test); 537 "Invalid test #%d in origin_recv_message()\n", test);
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 3edf0153e..58e43d4ba 100644
--- a/src/multicast/test_multicast_multipeer.c
+++ b/src/multicast/test_multicast_multipeer.c
@@ -35,16 +35,24 @@
35 35
36#define NUM_PEERS 2 36#define NUM_PEERS 2
37 37
38static struct GNUNET_TESTBED_Operation *peer0; 38static struct GNUNET_TESTBED_Operation *op0;
39static struct GNUNET_TESTBED_Operation *peer1; 39static struct GNUNET_TESTBED_Operation *op1;
40static struct GNUNET_TESTBED_Operation *pi_op0;
41static struct GNUNET_TESTBED_Operation *pi_op1;
42
43static struct GNUNET_TESTBED_Peer **peers;
44const struct GNUNET_PeerIdentity *peer_id[2];
40 45
41static struct GNUNET_SCHEDULER_Task *timeout_tid; 46static struct GNUNET_SCHEDULER_Task *timeout_tid;
42 47
48static struct GNUNET_MULTICAST_Origin *origin;
49static struct GNUNET_MULTICAST_Member *member;
50
43struct GNUNET_CRYPTO_EddsaPrivateKey *group_key; 51struct GNUNET_CRYPTO_EddsaPrivateKey *group_key;
44struct GNUNET_CRYPTO_EddsaPublicKey group_pub_key; 52struct GNUNET_CRYPTO_EddsaPublicKey group_pub_key;
45 53
46struct GNUNET_CRYPTO_EcdsaPrivateKey *member1_key; 54struct GNUNET_CRYPTO_EcdsaPrivateKey *member_key;
47struct GNUNET_CRYPTO_EcdsaPublicKey member1_pub_key; 55struct GNUNET_CRYPTO_EcdsaPublicKey member_pub_key;
48 56
49 57
50enum 58enum
@@ -68,10 +76,25 @@ static int result;
68static void 76static void
69shutdown_task (void *cls) 77shutdown_task (void *cls)
70{ 78{
71 if (NULL != peer0) 79 if (NULL != op0)
80 {
81 GNUNET_TESTBED_operation_done (op0);
82 op0 = NULL;
83 }
84 if (NULL != op1)
85 {
86 GNUNET_TESTBED_operation_done (op1);
87 op1 = NULL;
88 }
89 if (NULL != pi_op0)
90 {
91 GNUNET_TESTBED_operation_done (pi_op0);
92 pi_op0 = NULL;
93 }
94 if (NULL != pi_op1)
72 { 95 {
73 GNUNET_TESTBED_operation_done (peer0); 96 GNUNET_TESTBED_operation_done (pi_op1);
74 peer0 = NULL; 97 pi_op1 = NULL;
75 } 98 }
76 if (NULL != timeout_tid) 99 if (NULL != timeout_tid)
77 { 100 {
@@ -84,7 +107,6 @@ shutdown_task (void *cls)
84static void 107static void
85timeout_task (void *cls) 108timeout_task (void *cls)
86{ 109{
87 timeout_tid = NULL;
88 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 110 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
89 "Timeout!\n"); 111 "Timeout!\n");
90 result = GNUNET_SYSERR; 112 result = GNUNET_SYSERR;
@@ -93,112 +115,275 @@ timeout_task (void *cls)
93 115
94 116
95static void 117static void
96origin_recv_replay_msg (void *cls, 118member_join_request (void *cls,
97 const struct GNUNET_CRYPTO_EcdsaPublicKey *member_key, 119 const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key,
98 uint64_t message_id, 120 const struct GNUNET_MessageHeader *join_msg,
99 uint64_t fragment_offset, 121 struct GNUNET_MULTICAST_JoinHandle *jh)
100 uint64_t flags,
101 struct GNUNET_MULTICAST_ReplayHandle *rh)
102{ 122{
103 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 123 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
104 "Test #%u: origin_recv_replay_msg()\n", test); 124 "Member sent a join request.\n");
105 GNUNET_assert (0); 125
126}
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;
106} 141}
107 142
108 143
109static void 144static void
110member_recv_replay_msg (void *cls, 145member_join_decision (void *cls,
111 const struct GNUNET_CRYPTO_EcdsaPublicKey *member_key, 146 int is_admitted,
112 uint64_t message_id, 147 const struct GNUNET_PeerIdentity *peer,
113 uint64_t fragment_offset, 148 uint16_t relay_count,
114 uint64_t flags, 149 const struct GNUNET_PeerIdentity *relays,
115 struct GNUNET_MULTICAST_ReplayHandle *rh) 150 const struct GNUNET_MessageHeader *join_msg)
116{ 151{
117 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 152 struct GNUNET_MULTICAST_MemberTransmitHandle *req;
118 "Test #%u: member_recv_replay_msg()\n", test); 153
119 GNUNET_assert (0); 154 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
155 "Member received a decision from origin: %s\n", (GNUNET_YES == is_admitted)?"accepted":"rejected");
156
157 if (GNUNET_YES == is_admitted)
158 {
159 req = GNUNET_MULTICAST_member_to_origin (member,
160 0,
161 notify,
162 NULL);
163
164 }
120} 165}
121 166
122
123static void 167static void
124origin_recv_replay_frag (void *cls, 168member_replay_frag ()
125 const struct GNUNET_CRYPTO_EcdsaPublicKey *member_key,
126 uint64_t fragment_id,
127 uint64_t flags,
128 struct GNUNET_MULTICAST_ReplayHandle *rh)
129{ 169{
130 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 170 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
131 "Test #%u: origin_recv_replay_frag()" 171 "member replay frag...\n");
132 " - fragment_id=%" PRIu64 " flags=%" PRIu64 "\n",
133 test, fragment_id, flags);
134} 172}
135 173
174static void
175member_replay_msg ()
176{
177 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
178 "member replay msg...\n");
179}
136 180
137/**
138 * Test: origin receives join request
139 */
140static void 181static void
141origin_recv_join_request (void *cls, 182member_message ()
142 const struct GNUNET_CRYPTO_EcdsaPublicKey *mem_key,
143 const struct GNUNET_MessageHeader *join_msg,
144 struct GNUNET_MULTICAST_JoinHandle *jh)
145{ 183{
146 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 184 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
147 "Test #%u: origin_recv_join_request()\n", test); 185 "member message...\n");
186
187 // FIXME: not finished here
188 result = GNUNET_YES;
189 GNUNET_SCHEDULER_shutdown ();
148} 190}
149 191
192static void
193origin_join_request (void *cls,
194 const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key,
195 const struct GNUNET_MessageHeader *join_msg,
196 struct GNUNET_MULTICAST_JoinHandle *jh)
197{
198 struct GNUNET_MessageHeader *join_resp;
199
200 uint8_t data_size = ntohs (join_msg->size);
201
202 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
203 "origin got a join request...\n");
204 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
205 "origin receives: '%s'\n", (char *)&join_msg[1]);
206
207 char data[] = "Come in!";
208 data_size = strlen (data) + 1;
209 join_resp = GNUNET_malloc (sizeof (join_resp) + data_size);
210 join_resp->size = htons (sizeof (join_resp) + data_size);
211 join_resp->type = htons (123);
212 GNUNET_memcpy (&join_resp[1], data, data_size);
213
214 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
215 "origin sends: '%s'\n", data);
216
217 GNUNET_MULTICAST_join_decision (jh,
218 GNUNET_YES,
219 0,
220 NULL,
221 join_resp);
222
223 result = GNUNET_OK;
224}
150 225
151static void 226static void
152origin_recv_request (void *cls, 227origin_replay_frag (void *cls,
153 const struct GNUNET_MULTICAST_RequestHeader *req) 228 const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key,
229 uint64_t fragment_id,
230 uint64_t flags,
231 struct GNUNET_MULTICAST_ReplayHandle *rh)
154{ 232{
155 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 233 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin replay fraq msg\n");
156 "Test #%u: origin_recv_request()\n", 234}
157 test); 235
236static void
237origin_replay_msg (void *cls,
238 const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key,
239 uint64_t message_id,
240 uint64_t fragment_offset,
241 uint64_t flags,
242 struct GNUNET_MULTICAST_ReplayHandle *rh)
243{
244
245 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin replay msg\n");
246}
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;
158} 261}
159 262
160 263
161static void 264static void
162origin_recv_message (void *cls, 265origin_request (void *cls,
163 const struct GNUNET_MULTICAST_MessageHeader *msg) 266 const struct GNUNET_MULTICAST_RequestHeader *req)
164{ 267{
165 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 268 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin receives: %s\n", (char *)&req[1]);
166 "Test #%u: origin_recv_message()\n", 269
167 test); 270 if (0 != strncmp ("ping", (char *)&req[1], 4)) {
271 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "origin didn't reveice a correct request");
272 }
273
274 GNUNET_MULTICAST_origin_to_all (origin,
275 0,
276 0,
277 origin_notify,
278 NULL);
168} 279}
169 280
281static void
282origin_message (void *cls,
283 const struct GNUNET_MULTICAST_MessageHeader *msg)
284{
285 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin message msg\n");
286}
287
288
289static void
290service_connect1 (void *cls,
291 struct GNUNET_TESTBED_Operation *op,
292 void *ca_result,
293 const char *emsg)
294{
295 member = ca_result;
296
297 if (NULL != member)
298 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connected to multicast service of member\n");
299 else
300 result = GNUNET_SYSERR;
301}
170 302
171static void 303static void
172service_close_peer0 (void *cls, 304multicast_da1 (void *cls,
173 void *op_result) 305 void * op_result)
174{ 306{
175 struct GNUNET_MULTICAST_Origin *orig = op_result; 307 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
308 "Member parting from multicast group\n");
176 309
177 GNUNET_MULTICAST_origin_stop (orig, NULL, NULL); 310 GNUNET_MULTICAST_member_part (member, NULL, NULL);
178} 311}
179 312
180 313
181/**
182 * Function run when service multicast has started and is providing us
183 * with a configuration file.
184 */
185static void * 314static void *
186service_conf_peer0 (void *cls, 315multicast_ca1 (void *cls,
187 const struct GNUNET_CONFIGURATION_Handle *cfg) 316 const struct GNUNET_CONFIGURATION_Handle *cfg)
188{ 317{
189 group_key = GNUNET_CRYPTO_eddsa_key_create (); 318 struct GNUNET_MessageHeader *join_msg;
190 GNUNET_CRYPTO_eddsa_key_get_public (group_key, &group_pub_key); 319
320 // Get members keys
321 member_key = GNUNET_CRYPTO_ecdsa_key_create ();
322 GNUNET_CRYPTO_ecdsa_key_get_public (member_key, &member_pub_key);
323
324 char data[] = "Hi, can I enter?";
325 uint8_t data_size = strlen (data) + 1;
326 join_msg = GNUNET_malloc (sizeof (join_msg) + data_size);
327 join_msg->size = htons (sizeof (join_msg) + data_size);
328 join_msg->type = htons (123);
329 GNUNET_memcpy (&join_msg[1], data, data_size);
191 330
192 return GNUNET_MULTICAST_origin_start (cfg, group_key, 0, 331 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
193 origin_recv_join_request, 332 "Members tries to join multicast group\n");
194 origin_recv_replay_frag, 333
195 origin_recv_replay_msg, 334 return GNUNET_MULTICAST_member_join (cfg,
196 origin_recv_request, 335 &group_pub_key,
197 origin_recv_message, 336 member_key,
198 NULL); 337 peer_id[0],
338 0,
339 NULL,
340 join_msg, /* join message */
341 member_join_request,
342 member_join_decision,
343 member_replay_frag,
344 member_replay_msg,
345 member_message,
346 NULL);
199} 347}
200 348
201 349
350static void
351peer_information_cb (void *cls,
352 struct GNUNET_TESTBED_Operation *op,
353 const struct GNUNET_TESTBED_PeerInformation *pinfo,
354 const char *emsg)
355{
356 int i = (int) (long) cls;
357
358 if (NULL == pinfo) {
359 result = GNUNET_SYSERR;
360 GNUNET_SCHEDULER_shutdown ();
361 }
362
363 peer_id[i] = pinfo->result.id;
364
365 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
366 "Got peer information of %s (%s)\n", (0==i)?"origin":"member" ,GNUNET_i2s(pinfo->result.id));
367
368 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
369 "Create member peer\n");
370
371 if (0 == i) {
372 /* connect to multicast service of member */
373 op1 = GNUNET_TESTBED_service_connect (NULL, /* Closure for operation */
374 peers[1], /* The peer whose service to connect to */
375 "multicast", /* The name of the service */
376 service_connect1, /* callback to call after a handle to service
377 is opened */
378 NULL, /* closure for the above callback */
379 multicast_ca1, /* callback to call with peer's configuration;
380 this should open the needed service connection */
381 multicast_da1, /* callback to be called when closing the
382 opened service connection */
383 NULL); /* closure for the above two callbacks */
384 }
385}
386
202/** 387/**
203 * Test logic of peer "0" being origin starts here. 388 * Test logic of peer "0" being origin starts here.
204 * 389 *
@@ -210,17 +395,65 @@ service_conf_peer0 (void *cls,
210 * connect to the DHT. 395 * connect to the DHT.
211 */ 396 */
212static void 397static void
213service_connect_peer0 (void *cls, 398service_connect0 (void *cls,
214 struct GNUNET_TESTBED_Operation *op, 399 struct GNUNET_TESTBED_Operation *op,
215 void *ca_result, 400 void *ca_result,
216 const char *emsg) 401 const char *emsg)
217{ 402{
218 struct GNUNET_MULTICAST_Origin *orig = ca_result; 403 origin = ca_result;
404
405 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
406 "Connected to multicast service of origin\n");
407
408 // Get GNUnet identity of origin
409 pi_op0 = GNUNET_TESTBED_peer_get_information (peers[0],
410 GNUNET_TESTBED_PIT_IDENTITY,
411 peer_information_cb,
412 (void *) 0);
413 // Get GNUnet identity of member
414 pi_op1 = GNUNET_TESTBED_peer_get_information (peers[1],
415 GNUNET_TESTBED_PIT_IDENTITY,
416 peer_information_cb,
417 (void *) 1);
219 418
220 /* Connection to service successful. Here we'd usually do something with 419 /* Connection to service successful. Here we'd usually do something with
221 * the service. */ 420 * the service. */
222 result = GNUNET_OK; 421 result = GNUNET_OK;
223 GNUNET_SCHEDULER_shutdown (); /* Also kills the testbed */ 422 //GNUNET_SCHEDULER_shutdown (); /* Also kills the testbed */
423}
424
425
426
427/**
428 * Function run when service multicast has started and is providing us
429 * with a configuration file.
430 */
431static void *
432multicast_ca0 (void *cls,
433 const struct GNUNET_CONFIGURATION_Handle *cfg)
434{
435 group_key = GNUNET_CRYPTO_eddsa_key_create ();
436 GNUNET_CRYPTO_eddsa_key_get_public (group_key, &group_pub_key);
437
438 return GNUNET_MULTICAST_origin_start (cfg,
439 group_key,
440 0,
441 origin_join_request,
442 origin_replay_frag,
443 origin_replay_msg,
444 origin_request,
445 origin_message,
446 NULL);
447}
448
449static void
450multicast_da0 (void *cls,
451 void *op_result)
452{
453 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
454 "Origin closes multicast group\n");
455
456 GNUNET_MULTICAST_origin_stop (origin, NULL, NULL);
224} 457}
225 458
226 459
@@ -241,31 +474,38 @@ service_connect_peer0 (void *cls,
241 * @param links_failed number of links testbed was unable to establish 474 * @param links_failed number of links testbed was unable to establish
242 */ 475 */
243static void 476static void
244run (void *cls, 477testbed_master (void *cls,
245 struct GNUNET_TESTBED_RunHandle *h, 478 struct GNUNET_TESTBED_RunHandle *h,
246 unsigned int num_peers, 479 unsigned int num_peers,
247 struct GNUNET_TESTBED_Peer **peers, 480 struct GNUNET_TESTBED_Peer **p,
248 unsigned int links_succeeded, 481 unsigned int links_succeeded,
249 unsigned int links_failed) 482 unsigned int links_failed)
250{ 483{
251 /* Testbed is ready with peers running and connected in a pre-defined overlay 484 /* Testbed is ready with peers running and connected in a pre-defined overlay
252 topology (FIXME) */ 485 topology (FIXME) */
486 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
487 "Connected to testbed_master()\n");
488
489 peers = p;
253 490
254 /* connect to a peers service */ 491 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
255 peer0 = GNUNET_TESTBED_service_connect 492 "Create origin peer\n");
256 (NULL, /* Closure for operation */ 493 op0 = GNUNET_TESTBED_service_connect (NULL, /* Closure for operation */
257 peers[0], /* The peer whose service to connect to */ 494 peers[0], /* The peer whose service to connect to */
258 "multicast", /* The name of the service */ 495 "multicast", /* The name of the service */
259 &service_connect_peer0, /* callback to call after a handle to service 496 service_connect0, /* callback to call after a handle to service
260 is opened */ 497 is opened */
261 NULL, /* closure for the above callback */ 498 NULL, /* closure for the above callback */
262 &service_conf_peer0, /* callback to call with peer's configuration; 499 multicast_ca0, /* callback to call with peer's configuration;
263 this should open the needed service connection */ 500 this should open the needed service connection */
264 &service_close_peer0, /* callback to be called when closing the 501 multicast_da0, /* callback to be called when closing the
265 opened service connection */ 502 opened service connection */
266 NULL); /* closure for the above two callbacks */ 503 NULL); /* closure for the above two callbacks */
267 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); 504
268 timeout_tid = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, 505 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); /* Schedule a new task on shutdown */
506
507 /* Schedule the shutdown task with a delay of a few Seconds */
508 timeout_tid = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 48),
269 &timeout_task, NULL); 509 &timeout_task, NULL);
270} 510}
271 511
@@ -283,7 +523,7 @@ main (int argc, char *argv[])
283 0LL, /* Event mask - set to 0 for no event notifications */ 523 0LL, /* Event mask - set to 0 for no event notifications */
284 NULL, /* Controller event callback */ 524 NULL, /* Controller event callback */
285 NULL, /* Closure for controller event callback */ 525 NULL, /* Closure for controller event callback */
286 run, /* continuation callback to be called when testbed setup is complete */ 526 testbed_master, /* continuation callback to be called when testbed setup is complete */
287 NULL); /* Closure for the test_master callback */ 527 NULL); /* Closure for the test_master callback */
288 if ( (GNUNET_OK != ret) || (GNUNET_OK != result) ) 528 if ( (GNUNET_OK != ret) || (GNUNET_OK != result) )
289 return 1; 529 return 1;
diff --git a/src/namecache/.gitignore b/src/namecache/.gitignore
index 6d2d8488a..2abc07dfb 100644
--- a/src/namecache/.gitignore
+++ b/src/namecache/.gitignore
@@ -4,3 +4,4 @@ test_namecache_api_cache_block
4test_plugin_namecache_postgres 4test_plugin_namecache_postgres
5test_plugin_namecache_sqlite 5test_plugin_namecache_sqlite
6zonefiles 6zonefiles
7test_plugin_namecache_flat
diff --git a/src/namecache/Makefile.am b/src/namecache/Makefile.am
index cb4559552..d379b2602 100644
--- a/src/namecache/Makefile.am
+++ b/src/namecache/Makefile.am
@@ -56,7 +56,7 @@ check_PROGRAMS = \
56endif 56endif
57 57
58if ENABLE_TEST_RUN 58if ENABLE_TEST_RUN
59AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; 59AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
60TESTS = \ 60TESTS = \
61 $(check_PROGRAMS) 61 $(check_PROGRAMS)
62endif 62endif
@@ -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..d867138e4 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/.gitignore b/src/namestore/.gitignore
index a1153c6f9..4995a9e36 100644
--- a/src/namestore/.gitignore
+++ b/src/namestore/.gitignore
@@ -1,20 +1,21 @@
1gnunet-service-namestore 1gnunet-service-namestore
2gnunet-namestore 2gnunet-namestore
3gnunet-namestore-fcfsd 3gnunet-namestore-fcfsd
4test_namestore_api_lookup_nick 4test_namestore_api_lookup_nick.nc
5test_namestore_api_lookup_private 5test_namestore_api_lookup_private.nc
6test_namestore_api_lookup_public 6test_namestore_api_lookup_public.nc
7test_namestore_api_lookup_shadow 7test_namestore_api_lookup_shadow.nc
8test_namestore_api_lookup_shadow_filter 8test_namestore_api_lookup_shadow_filter.nc
9test_namestore_api_monitoring 9test_namestore_api_monitoring.nc
10test_namestore_api_monitoring_existing 10test_namestore_api_monitoring_existing.nc
11test_namestore_api_remove 11test_namestore_api_remove.nc
12test_namestore_api_remove_not_existing_record 12test_namestore_api_remove_not_existing_record.nc
13test_namestore_api_store 13test_namestore_api_store.nc
14test_namestore_api_store_update 14test_namestore_api_store_update.nc
15test_namestore_api_zone_iteration 15test_namestore_api_zone_iteration.nc
16test_namestore_api_zone_iteration_nick 16test_namestore_api_zone_iteration_nick.nc
17test_namestore_api_zone_iteration_specific_zone 17test_namestore_api_zone_iteration_specific_zone.nc
18test_namestore_api_zone_iteration_stop 18test_namestore_api_zone_iteration_stop.nc
19test_plugin_namestore_postgres 19test_plugin_namestore_postgres
20test_plugin_namestore_sqlite 20test_plugin_namestore_sqlite
21test_plugin_namestore_flat
diff --git a/src/namestore/Makefile.am b/src/namestore/Makefile.am
index 23ce477dd..de46e9c89 100644
--- a/src/namestore/Makefile.am
+++ b/src/namestore/Makefile.am
@@ -45,24 +45,43 @@ endif
45# testcases do not even build yet; thus: experimental! 45# testcases do not even build yet; thus: experimental!
46if HAVE_TESTING 46if HAVE_TESTING
47TESTING_TESTS = \ 47TESTING_TESTS = \
48 test_namestore_api_store \ 48 test_namestore_api_store.nc \
49 test_namestore_api_store_update \ 49 test_namestore_api_store_update.nc \
50 test_namestore_api_lookup_public \ 50 test_namestore_api_lookup_public.nc \
51 test_namestore_api_lookup_private \ 51 test_namestore_api_lookup_private.nc \
52 test_namestore_api_lookup_nick \ 52 test_namestore_api_lookup_nick.nc \
53 test_namestore_api_lookup_shadow \ 53 test_namestore_api_lookup_shadow.nc \
54 test_namestore_api_lookup_shadow_filter \ 54 test_namestore_api_lookup_shadow_filter.nc \
55 test_namestore_api_remove \ 55 test_namestore_api_remove.nc \
56 test_namestore_api_remove_not_existing_record \ 56 test_namestore_api_remove_not_existing_record.nc \
57 test_namestore_api_zone_iteration \ 57 test_namestore_api_zone_iteration.nc \
58 test_namestore_api_zone_iteration_nick \ 58 test_namestore_api_zone_iteration_nick.nc \
59 test_namestore_api_zone_iteration_specific_zone \ 59 test_namestore_api_zone_iteration_specific_zone.nc \
60 test_namestore_api_zone_iteration_stop \ 60 test_namestore_api_zone_iteration_stop.nc \
61 test_namestore_api_monitoring \ 61 test_namestore_api_monitoring.nc \
62 test_namestore_api_monitoring_existing 62 test_namestore_api_monitoring_existing.nc
63# test_namestore_api_zone_to_name 63# test_namestore_api_zone_to_name
64endif 64endif
65 65
66# Declare .nc (NO-CONCURRENCY) as a test extension so that we can impart
67# sequential execution order for them
68TEST_EXTENSIONS = .nc
69test_namestore_api_store.log: test_namestore_api_store_update.log
70test_namestore_api_store_update.log: test_namestore_api_lookup_public.log
71test_namestore_api_lookup_public.log: test_namestore_api_lookup_private.log
72test_namestore_api_lookup_private.log: test_namestore_api_lookup_nick.log
73test_namestore_api_lookup_nick.log: test_namestore_api_lookup_shadow.log
74test_namestore_api_lookup_shadow.log: test_namestore_api_lookup_shadow_filter.log
75test_namestore_api_lookup_shadow_filter.log: test_namestore_api_remove.log
76test_namestore_api_remove.log: test_namestore_api_remove_not_existing_record.log
77test_namestore_api_remove_not_existing_record.log: test_namestore_api_zone_iteration.log
78test_namestore_api_zone_iteration.log: test_namestore_api_zone_iteration_nick.log
79test_namestore_api_zone_iteration_nick.log: test_namestore_api_zone_iteration_specific_zone.log
80test_namestore_api_zone_iteration_specific_zone.log: test_namestore_api_zone_iteration_stop.log
81test_namestore_api_zone_iteration_stop.log: test_namestore_api_monitoring.log
82test_namestore_api_monitoring.log: test_namestore_api_monitoring_existing.log
83
84
66if HAVE_SQLITE 85if HAVE_SQLITE
67check_PROGRAMS = \ 86check_PROGRAMS = \
68 $(SQLITE_TESTS) \ 87 $(SQLITE_TESTS) \
@@ -78,7 +97,7 @@ endif
78endif 97endif
79 98
80if ENABLE_TEST_RUN 99if ENABLE_TEST_RUN
81AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; 100AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
82TESTS = \ 101TESTS = \
83 $(check_PROGRAMS) \ 102 $(check_PROGRAMS) \
84 $(check_SCRIPTS) 103 $(check_SCRIPTS)
@@ -170,6 +189,7 @@ libgnunet_plugin_namestore_sqlite_la_SOURCES = \
170 plugin_namestore_sqlite.c 189 plugin_namestore_sqlite.c
171libgnunet_plugin_namestore_sqlite_la_LIBADD = \ 190libgnunet_plugin_namestore_sqlite_la_LIBADD = \
172 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ 191 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
192 $(top_builddir)/src/sq/libgnunetsq.la \
173 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 193 $(top_builddir)/src/statistics/libgnunetstatistics.la \
174 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lsqlite3 \ 194 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lsqlite3 \
175 $(LTLIBINTL) 195 $(LTLIBINTL)
@@ -202,79 +222,79 @@ libgnunet_plugin_rest_namestore_la_LDFLAGS = \
202 $(GN_PLUGIN_LDFLAGS) 222 $(GN_PLUGIN_LDFLAGS)
203 223
204 224
205test_namestore_api_store_SOURCES = \ 225test_namestore_api_store_nc_SOURCES = \
206 test_namestore_api_store.c 226 test_namestore_api_store.c
207test_namestore_api_store_LDADD = \ 227test_namestore_api_store_nc_LDADD = \
208 $(top_builddir)/src/testing/libgnunettesting.la \ 228 $(top_builddir)/src/testing/libgnunettesting.la \
209 $(top_builddir)/src/util/libgnunetutil.la \ 229 $(top_builddir)/src/util/libgnunetutil.la \
210 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ 230 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
211 libgnunetnamestore.la 231 libgnunetnamestore.la
212 232
213test_namestore_api_store_update_SOURCES = \ 233test_namestore_api_store_update_nc_SOURCES = \
214 test_namestore_api_store_update.c 234 test_namestore_api_store_update.c
215test_namestore_api_store_update_LDADD = \ 235test_namestore_api_store_update_nc_LDADD = \
216 $(top_builddir)/src/testing/libgnunettesting.la \ 236 $(top_builddir)/src/testing/libgnunettesting.la \
217 $(top_builddir)/src/util/libgnunetutil.la \ 237 $(top_builddir)/src/util/libgnunetutil.la \
218 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ 238 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
219 $(top_builddir)/src/namecache/libgnunetnamecache.la \ 239 $(top_builddir)/src/namecache/libgnunetnamecache.la \
220 libgnunetnamestore.la 240 libgnunetnamestore.la
221 241
222test_namestore_api_lookup_public_SOURCES = \ 242test_namestore_api_lookup_public_nc_SOURCES = \
223 test_namestore_api_lookup_public.c 243 test_namestore_api_lookup_public.c
224test_namestore_api_lookup_public_LDADD = \ 244test_namestore_api_lookup_public_nc_LDADD = \
225 $(top_builddir)/src/testing/libgnunettesting.la \ 245 $(top_builddir)/src/testing/libgnunettesting.la \
226 $(top_builddir)/src/util/libgnunetutil.la \ 246 $(top_builddir)/src/util/libgnunetutil.la \
227 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ 247 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
228 $(top_builddir)/src/namecache/libgnunetnamecache.la \ 248 $(top_builddir)/src/namecache/libgnunetnamecache.la \
229 libgnunetnamestore.la 249 libgnunetnamestore.la
230 250
231test_namestore_api_lookup_nick_SOURCES = \ 251test_namestore_api_lookup_nick_nc_SOURCES = \
232 test_namestore_api_lookup_nick.c 252 test_namestore_api_lookup_nick.c
233test_namestore_api_lookup_nick_LDADD = \ 253test_namestore_api_lookup_nick_nc_LDADD = \
234 $(top_builddir)/src/testing/libgnunettesting.la \ 254 $(top_builddir)/src/testing/libgnunettesting.la \
235 $(top_builddir)/src/util/libgnunetutil.la \ 255 $(top_builddir)/src/util/libgnunetutil.la \
236 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ 256 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
237 $(top_builddir)/src/namecache/libgnunetnamecache.la \ 257 $(top_builddir)/src/namecache/libgnunetnamecache.la \
238 libgnunetnamestore.la 258 libgnunetnamestore.la
239 259
240test_namestore_api_lookup_private_SOURCES = \ 260test_namestore_api_lookup_private_nc_SOURCES = \
241 test_namestore_api_lookup_private.c 261 test_namestore_api_lookup_private.c
242test_namestore_api_lookup_private_LDADD = \ 262test_namestore_api_lookup_private_nc_LDADD = \
243 $(top_builddir)/src/testing/libgnunettesting.la \ 263 $(top_builddir)/src/testing/libgnunettesting.la \
244 $(top_builddir)/src/util/libgnunetutil.la \ 264 $(top_builddir)/src/util/libgnunetutil.la \
245 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ 265 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
246 $(top_builddir)/src/namecache/libgnunetnamecache.la \ 266 $(top_builddir)/src/namecache/libgnunetnamecache.la \
247 libgnunetnamestore.la 267 libgnunetnamestore.la
248 268
249test_namestore_api_lookup_shadow_SOURCES = \ 269test_namestore_api_lookup_shadow_nc_SOURCES = \
250 test_namestore_api_lookup_shadow.c 270 test_namestore_api_lookup_shadow.c
251test_namestore_api_lookup_shadow_LDADD = \ 271test_namestore_api_lookup_shadow_nc_LDADD = \
252 $(top_builddir)/src/testing/libgnunettesting.la \ 272 $(top_builddir)/src/testing/libgnunettesting.la \
253 $(top_builddir)/src/util/libgnunetutil.la \ 273 $(top_builddir)/src/util/libgnunetutil.la \
254 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ 274 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
255 $(top_builddir)/src/namecache/libgnunetnamecache.la \ 275 $(top_builddir)/src/namecache/libgnunetnamecache.la \
256 libgnunetnamestore.la 276 libgnunetnamestore.la
257 277
258test_namestore_api_lookup_shadow_filter_SOURCES = \ 278test_namestore_api_lookup_shadow_filter_nc_SOURCES = \
259 test_namestore_api_lookup_shadow_filter.c 279 test_namestore_api_lookup_shadow_filter.c
260test_namestore_api_lookup_shadow_filter_LDADD = \ 280test_namestore_api_lookup_shadow_filter_nc_LDADD = \
261 $(top_builddir)/src/testing/libgnunettesting.la \ 281 $(top_builddir)/src/testing/libgnunettesting.la \
262 $(top_builddir)/src/util/libgnunetutil.la \ 282 $(top_builddir)/src/util/libgnunetutil.la \
263 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ 283 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
264 $(top_builddir)/src/namecache/libgnunetnamecache.la \ 284 $(top_builddir)/src/namecache/libgnunetnamecache.la \
265 libgnunetnamestore.la 285 libgnunetnamestore.la
266 286
267test_namestore_api_remove_SOURCES = \ 287test_namestore_api_remove_nc_SOURCES = \
268 test_namestore_api_remove.c 288 test_namestore_api_remove.c
269test_namestore_api_remove_LDADD = \ 289test_namestore_api_remove_nc_LDADD = \
270 $(top_builddir)/src/testing/libgnunettesting.la \ 290 $(top_builddir)/src/testing/libgnunettesting.la \
271 $(top_builddir)/src/util/libgnunetutil.la \ 291 $(top_builddir)/src/util/libgnunetutil.la \
272 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ 292 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
273 libgnunetnamestore.la 293 libgnunetnamestore.la
274 294
275test_namestore_api_remove_not_existing_record_SOURCES = \ 295test_namestore_api_remove_not_existing_record_nc_SOURCES = \
276 test_namestore_api_remove_not_existing_record.c 296 test_namestore_api_remove_not_existing_record.c
277test_namestore_api_remove_not_existing_record_LDADD = \ 297test_namestore_api_remove_not_existing_record_nc_LDADD = \
278 $(top_builddir)/src/testing/libgnunettesting.la \ 298 $(top_builddir)/src/testing/libgnunettesting.la \
279 $(top_builddir)/src/util/libgnunetutil.la \ 299 $(top_builddir)/src/util/libgnunetutil.la \
280 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ 300 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
@@ -287,50 +307,50 @@ test_namestore_api_remove_not_existing_record_LDADD = \
287# $(top_builddir)/src/util/libgnunetutil.la \ 307# $(top_builddir)/src/util/libgnunetutil.la \
288# libgnunetnamestore.la 308# libgnunetnamestore.la
289 309
290test_namestore_api_monitoring_SOURCES = \ 310test_namestore_api_monitoring_nc_SOURCES = \
291 test_namestore_api_monitoring.c 311 test_namestore_api_monitoring.c
292test_namestore_api_monitoring_LDADD = \ 312test_namestore_api_monitoring_nc_LDADD = \
293 $(top_builddir)/src/testing/libgnunettesting.la \ 313 $(top_builddir)/src/testing/libgnunettesting.la \
294 libgnunetnamestore.la \ 314 libgnunetnamestore.la \
295 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ 315 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
296 $(top_builddir)/src/util/libgnunetutil.la 316 $(top_builddir)/src/util/libgnunetutil.la
297 317
298test_namestore_api_monitoring_existing_SOURCES = \ 318test_namestore_api_monitoring_existing_nc_SOURCES = \
299 test_namestore_api_monitoring_existing.c 319 test_namestore_api_monitoring_existing.c
300test_namestore_api_monitoring_existing_LDADD = \ 320test_namestore_api_monitoring_existing_nc_LDADD = \
301 $(top_builddir)/src/testing/libgnunettesting.la \ 321 $(top_builddir)/src/testing/libgnunettesting.la \
302 libgnunetnamestore.la \ 322 libgnunetnamestore.la \
303 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ 323 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
304 $(top_builddir)/src/util/libgnunetutil.la 324 $(top_builddir)/src/util/libgnunetutil.la
305 325
306test_namestore_api_zone_iteration_SOURCES = \ 326test_namestore_api_zone_iteration_nc_SOURCES = \
307 test_namestore_api_zone_iteration.c 327 test_namestore_api_zone_iteration.c
308test_namestore_api_zone_iteration_LDADD = \ 328test_namestore_api_zone_iteration_nc_LDADD = \
309 $(top_builddir)/src/testing/libgnunettesting.la \ 329 $(top_builddir)/src/testing/libgnunettesting.la \
310 $(top_builddir)/src/util/libgnunetutil.la \ 330 $(top_builddir)/src/util/libgnunetutil.la \
311 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ 331 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
312 libgnunetnamestore.la 332 libgnunetnamestore.la
313 333
314test_namestore_api_zone_iteration_nick_SOURCES = \ 334test_namestore_api_zone_iteration_nick_nc_SOURCES = \
315 test_namestore_api_zone_iteration_nick.c 335 test_namestore_api_zone_iteration_nick.c
316test_namestore_api_zone_iteration_nick_LDADD = \ 336test_namestore_api_zone_iteration_nick_nc_LDADD = \
317 $(top_builddir)/src/testing/libgnunettesting.la \ 337 $(top_builddir)/src/testing/libgnunettesting.la \
318 $(top_builddir)/src/util/libgnunetutil.la \ 338 $(top_builddir)/src/util/libgnunetutil.la \
319 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ 339 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
320 libgnunetnamestore.la 340 libgnunetnamestore.la
321 341
322 342
323test_namestore_api_zone_iteration_specific_zone_SOURCES = \ 343test_namestore_api_zone_iteration_specific_zone_nc_SOURCES = \
324 test_namestore_api_zone_iteration_specific_zone.c 344 test_namestore_api_zone_iteration_specific_zone.c
325test_namestore_api_zone_iteration_specific_zone_LDADD = \ 345test_namestore_api_zone_iteration_specific_zone_nc_LDADD = \
326 $(top_builddir)/src/testing/libgnunettesting.la \ 346 $(top_builddir)/src/testing/libgnunettesting.la \
327 $(top_builddir)/src/util/libgnunetutil.la \ 347 $(top_builddir)/src/util/libgnunetutil.la \
328 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ 348 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
329 libgnunetnamestore.la 349 libgnunetnamestore.la
330 350
331test_namestore_api_zone_iteration_stop_SOURCES = \ 351test_namestore_api_zone_iteration_stop_nc_SOURCES = \
332 test_namestore_api_zone_iteration_stop.c 352 test_namestore_api_zone_iteration_stop.c
333test_namestore_api_zone_iteration_stop_LDADD = \ 353test_namestore_api_zone_iteration_stop_nc_LDADD = \
334 $(top_builddir)/src/testing/libgnunettesting.la \ 354 $(top_builddir)/src/testing/libgnunettesting.la \
335 $(top_builddir)/src/util/libgnunetutil.la \ 355 $(top_builddir)/src/util/libgnunetutil.la \
336 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ 356 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
@@ -363,7 +383,7 @@ EXTRA_DIST = \
363 test_namestore_api.conf \ 383 test_namestore_api.conf \
364 test_plugin_namestore_sqlite.conf \ 384 test_plugin_namestore_sqlite.conf \
365 test_plugin_namestore_postgres.conf \ 385 test_plugin_namestore_postgres.conf \
366 test_plugin_namestore_flat.conf \ 386 test_plugin_namestore_flat.conf \
367 test_hostkey \ 387 test_hostkey \
368 zonefiles/S5I9DSGQVAB5FVV16T3B3CC5H1B2JGL3Q412JBKURME8EKU0600G.zkey \ 388 zonefiles/S5I9DSGQVAB5FVV16T3B3CC5H1B2JGL3Q412JBKURME8EKU0600G.zkey \
369 zonefiles/AQ835GVL939H4O8QJQ7GBLPTQC0QAAO91BN7QK01BA63MDSK6I4G.zkey \ 389 zonefiles/AQ835GVL939H4O8QJQ7GBLPTQC0QAAO91BN7QK01BA63MDSK6I4G.zkey \
diff --git a/src/namestore/gnunet-namestore.c b/src/namestore/gnunet-namestore.c
index 457e77022..dcb9dd678 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_flag ('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_flag ('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_flag ('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_flag ('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_flag ('p',
1200 "public",
1201 gettext_noop ("create or list public record"),
1202 &is_public),
1203
1204 GNUNET_GETOPT_option_flag ('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/namestore/plugin_rest_namestore.c b/src/namestore/plugin_rest_namestore.c
index 0d36cf445..50957a5b4 100644
--- a/src/namestore/plugin_rest_namestore.c
+++ b/src/namestore/plugin_rest_namestore.c
@@ -899,10 +899,11 @@ namestore_zkey_cont (struct GNUNET_REST_RequestHandle *con,
899 } 899 }
900 handle->zkey_str = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map, 900 handle->zkey_str = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
901 &key); 901 &key);
902 if (GNUNET_OK != 902 if ((NULL == handle->zkey_str) ||
903 GNUNET_CRYPTO_ecdsa_public_key_from_string (handle->zkey_str, 903 (GNUNET_OK !=
904 GNUNET_CRYPTO_ecdsa_public_key_from_string (handle->zkey_str,
904 strlen (handle->zkey_str), 905 strlen (handle->zkey_str),
905 &pubkey)) 906 &pubkey)))
906 { 907 {
907 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 908 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
908 "Zkey invalid %s\n", handle->zkey_str); 909 "Zkey invalid %s\n", handle->zkey_str);
@@ -1126,8 +1127,8 @@ rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
1126 { 1127 {
1127 type = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map, 1128 type = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
1128 &key); 1129 &key);
1129 1130 if (NULL != type)
1130 handle->type = GNUNET_GNSRECORD_typename_to_number (type); 1131 handle->type = GNUNET_GNSRECORD_typename_to_number (type);
1131 } 1132 }
1132 name = get_name_from_url (handle->url); 1133 name = get_name_from_url (handle->url);
1133 if (NULL != ego) 1134 if (NULL != ego)
diff --git a/src/namestore/test_namestore_api_remove.c b/src/namestore/test_namestore_api_remove.c
index c6c439e86..2d670c1ee 100644
--- a/src/namestore/test_namestore_api_remove.c
+++ b/src/namestore/test_namestore_api_remove.c
@@ -98,19 +98,22 @@ remove_cont (void *cls,
98 int32_t success, 98 int32_t success,
99 const char *emsg) 99 const char *emsg)
100{ 100{
101 nsqe = NULL;
101 if (GNUNET_YES != success) 102 if (GNUNET_YES != success)
102 { 103 {
103 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 104 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
104 _("Records could not be removed: `%s'\n"), emsg); 105 _("Records could not be removed: `%s'\n"),
105 if (endbadly_task != NULL) 106 emsg);
107 if (NULL != endbadly_task)
106 GNUNET_SCHEDULER_cancel (endbadly_task); 108 GNUNET_SCHEDULER_cancel (endbadly_task);
107 endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly, NULL); 109 endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly,
110 NULL);
108 return; 111 return;
109 } 112 }
110 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 113 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
111 "Records were removed, perform lookup\n"); 114 "Records were removed, perform lookup\n");
112 removed = GNUNET_YES; 115 removed = GNUNET_YES;
113 if (endbadly_task != NULL) 116 if (NULL != endbadly_task)
114 GNUNET_SCHEDULER_cancel (endbadly_task); 117 GNUNET_SCHEDULER_cancel (endbadly_task);
115 GNUNET_SCHEDULER_add_now (&end, NULL); 118 GNUNET_SCHEDULER_add_now (&end, NULL);
116} 119}
@@ -139,8 +142,11 @@ put_cont (void *cls, int32_t success,
139 "Name store added record for `%s': %s\n", 142 "Name store added record for `%s': %s\n",
140 name, 143 name,
141 (success == GNUNET_OK) ? "SUCCESS" : "FAIL"); 144 (success == GNUNET_OK) ? "SUCCESS" : "FAIL");
142 nsqe = GNUNET_NAMESTORE_records_store (nsh, privkey, name, 145 nsqe = GNUNET_NAMESTORE_records_store (nsh,
143 0, NULL, &remove_cont, (void *) name); 146 privkey,
147 name,
148 0, NULL,
149 &remove_cont, (void *) name);
144} 150}
145 151
146 152
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..7d09253b8 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_flag ('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_flag ('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_flag ('u',
360 "udp",
361 gettext_noop ("use UDP"),
362 &use_udp),
363
364 GNUNET_GETOPT_option_flag ('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 dd08f8d36..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.
@@ -56,6 +68,7 @@ try_anat (uint32_t dst_ipv4,
56 struct GNUNET_NAT_Handle *h; 68 struct GNUNET_NAT_Handle *h;
57 struct sockaddr_in lsa; 69 struct sockaddr_in lsa;
58 struct sockaddr_in rsa; 70 struct sockaddr_in rsa;
71 const struct sockaddr *sa;
59 socklen_t sa_len; 72 socklen_t sa_len;
60 73
61 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 74 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -77,11 +90,12 @@ try_anat (uint32_t dst_ipv4,
77 rsa.sin_addr.s_addr = dst_ipv4; 90 rsa.sin_addr.s_addr = dst_ipv4;
78 rsa.sin_port = htons (dport); 91 rsa.sin_port = htons (dport);
79 sa_len = sizeof (lsa); 92 sa_len = sizeof (lsa);
93 sa = (const struct sockaddr *) &lsa;
80 h = GNUNET_NAT_register (cfg, 94 h = GNUNET_NAT_register (cfg,
81 "none", 95 "none",
82 is_tcp ? IPPROTO_TCP : IPPROTO_UDP, 96 is_tcp ? IPPROTO_TCP : IPPROTO_UDP,
83 1, 97 1,
84 (const struct sockaddr **) &lsa, 98 &sa,
85 &sa_len, 99 &sa_len,
86 NULL, NULL, NULL); 100 NULL, NULL, NULL);
87 GNUNET_NAT_request_reversal (h, 101 GNUNET_NAT_request_reversal (h,
@@ -246,21 +260,18 @@ try_send_udp (uint32_t dst_ipv4,
246 * We've received a request to probe a NAT 260 * We've received a request to probe a NAT
247 * traversal. Do it. 261 * traversal. Do it.
248 * 262 *
249 * @param cls unused 263 * @param cls handle to client (we always close)
250 * @param client handle to client (we always close)
251 * @param msg message with details about what to test 264 * @param msg message with details about what to test
252 */ 265 */
253static void 266static void
254test (void *cls, 267handle_test (void *cls,
255 struct GNUNET_SERVER_Client *client, 268 const struct GNUNET_NAT_AUTO_TestMessage *tm)
256 const struct GNUNET_MessageHeader *msg)
257{ 269{
258 const struct GNUNET_NAT_AUTO_TestMessage *tm; 270 struct ClientData *cd = cls;
259 uint16_t dport; 271 uint16_t dport;
260 272
261 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 273 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
262 "Received test request\n"); 274 "Received test request\n");
263 tm = (const struct GNUNET_NAT_AUTO_TestMessage *) msg;
264 dport = ntohs (tm->dport); 275 dport = ntohs (tm->dport);
265 if (0 == dport) 276 if (0 == dport)
266 try_anat (tm->dst_ipv4, 277 try_anat (tm->dst_ipv4,
@@ -274,126 +285,119 @@ test (void *cls,
274 try_send_udp (tm->dst_ipv4, 285 try_send_udp (tm->dst_ipv4,
275 dport, 286 dport,
276 tm->data); 287 tm->data);
277 GNUNET_SERVER_receive_done (client, 288 GNUNET_SERVICE_client_drop (cd->client);
278 GNUNET_NO);
279} 289}
280 290
281 291
282/** 292/**
283 * Task run during shutdown. 293 * Main function that will be run.
284 * 294 *
285 * @param cls unused 295 * @param cls closure
296 * @param c configuration
297 * @param srv service handle
286 */ 298 */
287static void 299static void
288shutdown_task (void *cls) 300run (void *cls,
301 const struct GNUNET_CONFIGURATION_Handle *c,
302 struct GNUNET_SERVICE_Handle *srv)
289{ 303{
290 GNUNET_SERVER_destroy (server); 304 cfg = c;
291 server = NULL;
292} 305}
293 306
294 307
295/** 308/**
296 * Main function that will be run. 309 * Forcefully drops client after 1s.
297 * 310 *
298 * @param cls closure 311 * @param cls our `struct ClientData` of a client to drop
299 * @param args remaining command-line arguments
300 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
301 * @param c configuration
302 */ 312 */
303static void 313static void
304run (void *cls, 314force_timeout (void *cls)
305 char *const *args,
306 const char *cfgfile,
307 const struct GNUNET_CONFIGURATION_Handle *c)
308{ 315{
309 static const struct GNUNET_SERVER_MessageHandler handlers[] = { 316 struct ClientData *cd = cls;
310 {&test, NULL, GNUNET_MESSAGE_TYPE_NAT_TEST,
311 sizeof (struct GNUNET_NAT_AUTO_TestMessage)},
312 {NULL, NULL, 0, 0}
313 };
314 unsigned int port;
315 struct sockaddr_in in4;
316 struct sockaddr_in6 in6;
317
318 socklen_t slen[] = {
319 sizeof (in4),
320 sizeof (in6),
321 0
322 };
323 struct sockaddr *sa[] = {
324 (struct sockaddr *) &in4,
325 (struct sockaddr *) &in6,
326 NULL
327 };
328 317
329 cfg = c; 318 cd->tt = NULL;
330 if ( (NULL == args[0]) || 319 GNUNET_SERVICE_client_drop (cd->client);
331 (1 != SSCANF (args[0], "%u", &port)) ||
332 (0 == port) ||
333 (65536 <= port) )
334 {
335 FPRINTF (stderr,
336 _("Please pass valid port number as the first argument! (got `%s')\n"),
337 args[0]);
338 return;
339 }
340 memset (&in4, 0, sizeof (in4));
341 memset (&in6, 0, sizeof (in6));
342 in4.sin_family = AF_INET;
343 in4.sin_port = htons ((uint16_t) port);
344 in6.sin6_family = AF_INET6;
345 in6.sin6_port = htons ((uint16_t) port);
346#if HAVE_SOCKADDR_IN_SIN_LEN
347 in4.sin_len = sizeof (in4);
348 in6.sin6_len = sizeof (in6);
349#endif
350 server = GNUNET_SERVER_create (NULL,
351 NULL,
352 (struct sockaddr * const *) sa,
353 slen,
354 GNUNET_TIME_UNIT_SECONDS,
355 GNUNET_YES);
356 GNUNET_SERVER_add_handlers (server,
357 handlers);
358 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
359 NULL);
360} 320}
361 321
362 322
323
363/** 324/**
364 * Main function of gnunet-nat-server. 325 * Callback called when a client connects to the service.
365 * 326 *
366 * @param argc number of command-line arguments 327 * @param cls closure for the service
367 * @param argv command line 328 * @param c the new client that connected to the service
368 * @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`
369 */ 331 */
370int 332static void *
371main (int argc, char *const argv[]) 333client_connect_cb (void *cls,
334 struct GNUNET_SERVICE_Client *c,
335 struct GNUNET_MQ_Handle *mq)
372{ 336{
373 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 337 struct ClientData *cd;
374 GNUNET_GETOPT_OPTION_END 338
375 }; 339 cd = GNUNET_new (struct ClientData);
376 340 cd->client = c;
377 if (GNUNET_OK != 341 cd->tt = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
378 GNUNET_STRINGS_get_utf8_args (argc, argv, 342 &force_timeout,
379 &argc, &argv)) 343 cd);
380 return 2; 344 return cd;
381 345}
382 if (GNUNET_OK != 346
383 GNUNET_PROGRAM_run (argc, 347
384 argv, 348/**
385 "gnunet-nat-server [options] PORT", 349 * Callback called when a client disconnected from the service
386 _("GNUnet NAT traversal test helper daemon"), 350 *
387 options, 351 * @param cls closure for the service
388 &run, 352 * @param c the client that disconnected
389 NULL)) 353 * @param internal_cls our `struct ClientData`
390 { 354 */
391 GNUNET_free ((void*) argv); 355static void
392 return 1; 356client_disconnect_cb (void *cls,
393 } 357 struct GNUNET_SERVICE_Client *c,
394 GNUNET_free ((void*) argv); 358 void *internal_cls)
395 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);
396} 365}
397 366
398 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
399/* 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 a5b41ac49..8a7eaf264 100644
--- a/src/nat-auto/nat_auto_api.c
+++ b/src/nat-auto/nat_auto_api.c
@@ -42,7 +42,7 @@ struct GNUNET_NAT_AUTO_AutoHandle
42 * Configuration we use. 42 * Configuration we use.
43 */ 43 */
44 const struct GNUNET_CONFIGURATION_Handle *cfg; 44 const struct GNUNET_CONFIGURATION_Handle *cfg;
45 45
46 /** 46 /**
47 * Message queue for communicating with the NAT service. 47 * Message queue for communicating with the NAT service.
48 */ 48 */
@@ -206,8 +206,8 @@ ah_error_handler (void *cls,
206 */ 206 */
207struct GNUNET_NAT_AUTO_AutoHandle * 207struct GNUNET_NAT_AUTO_AutoHandle *
208GNUNET_NAT_AUTO_autoconfig_start (const struct GNUNET_CONFIGURATION_Handle *cfg, 208GNUNET_NAT_AUTO_autoconfig_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
209 GNUNET_NAT_AUTO_AutoResultCallback cb, 209 GNUNET_NAT_AUTO_AutoResultCallback cb,
210 void *cb_cls) 210 void *cb_cls)
211{ 211{
212 struct GNUNET_NAT_AUTO_AutoHandle *ah = GNUNET_new (struct GNUNET_NAT_AUTO_AutoHandle); 212 struct GNUNET_NAT_AUTO_AutoHandle *ah = GNUNET_new (struct GNUNET_NAT_AUTO_AutoHandle);
213 struct GNUNET_MQ_MessageHandler handlers[] = { 213 struct GNUNET_MQ_MessageHandler handlers[] = {
@@ -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-auto/nat_auto_api_test.c b/src/nat-auto/nat_auto_api_test.c
index fb2bcd679..c72b611bf 100644
--- a/src/nat-auto/nat_auto_api_test.c
+++ b/src/nat-auto/nat_auto_api_test.c
@@ -28,7 +28,7 @@
28#include "gnunet_nat_auto_service.h" 28#include "gnunet_nat_auto_service.h"
29#include "nat-auto.h" 29#include "nat-auto.h"
30 30
31#define LOG(kind,...) GNUNET_log_from (kind, "nat", __VA_ARGS__) 31#define LOG(kind,...) GNUNET_log_from (kind, "nat-auto", __VA_ARGS__)
32 32
33#define NAT_SERVER_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) 33#define NAT_SERVER_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
34 34
@@ -508,19 +508,21 @@ GNUNET_NAT_AUTO_test_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
508 { 508 {
509 nh->lsock 509 nh->lsock
510 = GNUNET_NETWORK_socket_create (AF_INET, 510 = GNUNET_NETWORK_socket_create (AF_INET,
511 proto, 511 (IPPROTO_UDP == proto)
512 0); 512 ? SOCK_DGRAM
513 : SOCK_STREAM,
514 proto);
513 if ( (NULL == nh->lsock) || 515 if ( (NULL == nh->lsock) ||
514 (GNUNET_OK != 516 (GNUNET_OK !=
515 GNUNET_NETWORK_socket_bind (nh->lsock, 517 GNUNET_NETWORK_socket_bind (nh->lsock,
516 (const struct sockaddr *) &sa, 518 (const struct sockaddr *) &sa,
517 sizeof (sa)))) 519 sizeof (sa))))
518 { 520 {
519 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 521 LOG (GNUNET_ERROR_TYPE_ERROR,
520 _("Failed to create listen socket bound to `%s' for NAT test: %s\n"), 522 _("Failed to create socket bound to `%s' for NAT test: %s\n"),
521 GNUNET_a2s ((const struct sockaddr *) &sa, 523 GNUNET_a2s ((const struct sockaddr *) &sa,
522 sizeof (sa)), 524 sizeof (sa)),
523 STRERROR (errno)); 525 STRERROR (errno));
524 if (NULL != nh->lsock) 526 if (NULL != nh->lsock)
525 { 527 {
526 GNUNET_NETWORK_socket_close (nh->lsock); 528 GNUNET_NETWORK_socket_close (nh->lsock);
@@ -551,7 +553,7 @@ GNUNET_NAT_AUTO_test_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
551 nh); 553 nh);
552 } 554 }
553 LOG (GNUNET_ERROR_TYPE_INFO, 555 LOG (GNUNET_ERROR_TYPE_INFO,
554 "NAT test listens on port %u (%s)\n", 556 "NAT test listens on port %llu (%s)\n",
555 bnd_port, 557 bnd_port,
556 (IPPROTO_TCP == proto) ? "tcp" : "udp"); 558 (IPPROTO_TCP == proto) ? "tcp" : "udp");
557 nh->nat = GNUNET_NAT_register (cfg, 559 nh->nat = GNUNET_NAT_register (cfg,
diff --git a/src/nat/Makefile.am b/src/nat/Makefile.am
index 3dc001dd7..f0d5639a1 100644
--- a/src/nat/Makefile.am
+++ b/src/nat/Makefile.am
@@ -93,7 +93,7 @@ gnunet_service_nat_LDADD = \
93# test_stun 93# test_stun
94 94
95if ENABLE_TEST_RUN 95if ENABLE_TEST_RUN
96 AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; 96 AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
97 TESTS = $(check_PROGRAMS) 97 TESTS = $(check_PROGRAMS)
98endif 98endif
99 99
diff --git a/src/nat/gnunet-helper-nat-client-windows.c b/src/nat/gnunet-helper-nat-client-windows.c
index 89dad9e7b..622f8c961 100644
--- a/src/nat/gnunet-helper-nat-client-windows.c
+++ b/src/nat/gnunet-helper-nat-client-windows.c
@@ -42,6 +42,8 @@
42 * - Nathan Evans 42 * - Nathan Evans
43 */ 43 */
44#define _GNU_SOURCE 44#define _GNU_SOURCE
45/* Instead of including gnunet_common.h */
46#define GNUNET_memcpy(dst,src,n) do { if (0 != n) { (void) memcpy (dst,src,n); } } while (0)
45 47
46#define FD_SETSIZE 1024 48#define FD_SETSIZE 1024
47#include <winsock2.h> 49#include <winsock2.h>
diff --git a/src/nat/gnunet-helper-nat-server-windows.c b/src/nat/gnunet-helper-nat-server-windows.c
index c8e1193e4..09bd02538 100644
--- a/src/nat/gnunet-helper-nat-server-windows.c
+++ b/src/nat/gnunet-helper-nat-server-windows.c
@@ -41,6 +41,8 @@
41 * - Christian Grothoff 41 * - Christian Grothoff
42 */ 42 */
43#define _GNU_SOURCE 43#define _GNU_SOURCE
44/* Instead of including gnunet_common.h */
45#define GNUNET_memcpy(dst,src,n) do { if (0 != n) { (void) memcpy (dst,src,n); } } while (0)
44 46
45#define FD_SETSIZE 1024 47#define FD_SETSIZE 1024
46#include <winsock2.h> 48#include <winsock2.h>
diff --git a/src/nat/gnunet-nat.c b/src/nat/gnunet-nat.c
index f198adc0a..b3cf2e946 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,10 +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 }
289
286 if (NULL != remote_addr) 290 if (NULL != remote_addr)
287 { 291 {
288 remote_len = GNUNET_STRINGS_parse_socket_addr (remote_addr, 292 remote_len = GNUNET_STRINGS_parse_socket_addr (remote_addr,
@@ -293,8 +297,7 @@ run (void *cls,
293 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, 297 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
294 "Invalid socket address `%s'\n", 298 "Invalid socket address `%s'\n",
295 remote_addr); 299 remote_addr);
296 global_ret = 1; 300 goto fail_and_shutdown;
297 return;
298 } 301 }
299 } 302 }
300 303
@@ -315,32 +318,26 @@ run (void *cls,
315 else if (listen_reversal) 318 else if (listen_reversal)
316 { 319 {
317 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, 320 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
318 "Use of `-W` only effective in combination with `-i`\n"); 321 "Use of `-W` only effective in combination with `-i`\n");
319 global_ret = 1; 322 goto fail_and_shutdown;
320 GNUNET_SCHEDULER_shutdown ();
321 return;
322 } 323 }
323 324
324 if (NULL != remote_addr) 325 if (NULL != remote_addr)
325 { 326 {
326 int ret; 327 int ret;
327 328
328 if ( (NULL == nh) || 329 if ( (NULL == nh) ||
329 (sizeof (struct sockaddr_in) != local_len) ) 330 (sizeof (struct sockaddr_in) != local_len) )
330 { 331 {
331 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, 332 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
332 "Require IPv4 local address to initiate connection reversal\n"); 333 "Require IPv4 local address to initiate connection reversal\n");
333 global_ret = 1; 334 goto fail_and_shutdown;
334 GNUNET_SCHEDULER_shutdown ();
335 return;
336 } 335 }
337 if (sizeof (struct sockaddr_in) != remote_len) 336 if (sizeof (struct sockaddr_in) != remote_len)
338 { 337 {
339 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, 338 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
340 "Require IPv4 reversal target address\n"); 339 "Require IPv4 reversal target address\n");
341 global_ret = 1; 340 goto fail_and_shutdown;
342 GNUNET_SCHEDULER_shutdown ();
343 return;
344 } 341 }
345 GNUNET_assert (AF_INET == local_sa->sa_family); 342 GNUNET_assert (AF_INET == local_sa->sa_family);
346 GNUNET_assert (AF_INET == remote_sa->sa_family); 343 GNUNET_assert (AF_INET == remote_sa->sa_family);
@@ -362,24 +359,20 @@ run (void *cls,
362 break; 359 break;
363 } 360 }
364 } 361 }
365 362
366 if (do_stun) 363 if (do_stun)
367 { 364 {
368 if (NULL == local_addr) 365 if (NULL == local_addr)
369 { 366 {
370 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, 367 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
371 "Require local address to support STUN requests\n"); 368 "Require local address to support STUN requests\n");
372 global_ret = 1; 369 goto fail_and_shutdown;
373 GNUNET_SCHEDULER_shutdown ();
374 return;
375 } 370 }
376 if (IPPROTO_UDP != proto) 371 if (IPPROTO_UDP != proto)
377 { 372 {
378 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, 373 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
379 "STUN only supported over UDP\n"); 374 "STUN only supported over UDP\n");
380 global_ret = 1; 375 goto fail_and_shutdown;
381 GNUNET_SCHEDULER_shutdown ();
382 return;
383 } 376 }
384 ls = GNUNET_NETWORK_socket_create (af, 377 ls = GNUNET_NETWORK_socket_create (af,
385 SOCK_DGRAM, 378 SOCK_DGRAM,
@@ -394,17 +387,22 @@ run (void *cls,
394 GNUNET_a2s (local_sa, 387 GNUNET_a2s (local_sa,
395 local_len), 388 local_len),
396 STRERROR (errno)); 389 STRERROR (errno));
397 global_ret = 1; 390 goto fail_and_shutdown;
398 GNUNET_SCHEDULER_shutdown ();
399 return;
400 } 391 }
401 rtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, 392 rtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
402 ls, 393 ls,
403 &stun_read_task, 394 &stun_read_task,
404 NULL); 395 NULL);
405 } 396 }
406 397 GNUNET_free_non_null (remote_sa);
398 GNUNET_free_non_null (local_sa);
407 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);
408} 406}
409 407
410 408
@@ -419,29 +417,46 @@ int
419main (int argc, 417main (int argc,
420 char *const argv[]) 418 char *const argv[])
421{ 419{
422 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 420 struct GNUNET_GETOPT_CommandLineOption options[] = {
423 {'i', "in", "ADDRESS", 421
424 gettext_noop ("which IP and port are we locally using to bind/listen to"), 422 GNUNET_GETOPT_option_string ('i',
425 GNUNET_YES, &GNUNET_GETOPT_set_string, &local_addr }, 423 "in",
426 {'r', "remote", "ADDRESS", 424 "ADDRESS",
427 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"),
428 GNUNET_YES, &GNUNET_GETOPT_set_string, &remote_addr }, 426 &local_addr),
429 {'S', "section", NULL, 427
430 gettext_noop ("name of configuration section to find additional options, such as manual host punching data"), 428 GNUNET_GETOPT_option_string ('r',
431 GNUNET_YES, &GNUNET_GETOPT_set_string, &section_name }, 429 "remote",
432 {'s', "stun", NULL, 430 "ADDRESS",
433 gettext_noop ("enable STUN processing"), 431 gettext_noop ("which remote IP and port should be asked for connection reversal"),
434 GNUNET_NO, &GNUNET_GETOPT_set_one, &do_stun }, 432 &remote_addr),
435 {'t', "tcp", NULL, 433
436 gettext_noop ("use TCP"), 434 GNUNET_GETOPT_option_string ('S',
437 GNUNET_NO, &GNUNET_GETOPT_set_one, &use_tcp }, 435 "section",
438 {'u', "udp", NULL, 436 NULL,
439 gettext_noop ("use UDP"), 437 gettext_noop ("name of configuration section to find additional options, such as manual host punching data"),
440 GNUNET_NO, &GNUNET_GETOPT_set_one, &use_udp }, 438 &section_name),
441 {'W', "watch", NULL, 439
442 gettext_noop ("watch for connection reversal requests"), 440 GNUNET_GETOPT_option_flag ('s',
443 GNUNET_NO, &GNUNET_GETOPT_set_one, &listen_reversal }, 441 "stun",
444 GNUNET_GETOPT_OPTION_END 442 gettext_noop ("enable STUN processing"),
443 &do_stun),
444
445 GNUNET_GETOPT_option_flag ('t',
446 "tcp",
447 gettext_noop ("use TCP"),
448 &use_tcp),
449
450 GNUNET_GETOPT_option_flag ('u',
451 "udp",
452 gettext_noop ("use UDP"),
453 &use_udp),
454
455 GNUNET_GETOPT_option_flag ('W',
456 "watch",
457 gettext_noop ("watch for connection reversal requests"),
458 &listen_reversal),
459 GNUNET_GETOPT_OPTION_END
445 }; 460 };
446 461
447 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 979d2f0f5..f79ff4070 100644
--- a/src/nat/gnunet-service-nat_externalip.c
+++ b/src/nat/gnunet-service-nat_externalip.c
@@ -23,15 +23,12 @@
23 * 23 *
24 * This can be implemented using different methods, and we allow 24 * This can be implemented using different methods, and we allow
25 * the main service to be notified about changes to what we believe 25 * the main service to be notified about changes to what we believe
26 * is our external IPv4 address. 26 * is our external IPv4 address.
27 * 27 *
28 * Note that this is explicitly only about NATed systems; if one 28 * Note that this is explicitly only about NATed systems; if one
29 * of our network interfaces has a global IP address this does 29 * of our network interfaces has a global IP address this does
30 * not count as "external". 30 * not count as "external".
31 * 31 *
32 * TODO:
33 * - implement NEW logic for external IP detection based on traceroute!
34 *
35 * @file nat/gnunet-service-nat_externalip.c 32 * @file nat/gnunet-service-nat_externalip.c
36 * @brief Functions for monitoring external IPv4 addresses 33 * @brief Functions for monitoring external IPv4 addresses
37 * @author Christian Grothoff 34 * @author Christian Grothoff
@@ -86,7 +83,7 @@ struct GN_ExternalIPMonitor
86 * Kept in DLL. 83 * Kept in DLL.
87 */ 84 */
88 struct GN_ExternalIPMonitor *prev; 85 struct GN_ExternalIPMonitor *prev;
89 86
90 /** 87 /**
91 * Function to call when we believe our external IPv4 address changed. 88 * Function to call when we believe our external IPv4 address changed.
92 */ 89 */
@@ -131,7 +128,7 @@ static struct in_addr mini_external_ipv4;
131/** 128/**
132 * Tell relevant clients about a change in our external 129 * Tell relevant clients about a change in our external
133 * IPv4 address. 130 * IPv4 address.
134 * 131 *
135 * @param add #GNUNET_YES to add, #GNUNET_NO to remove 132 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
136 * @param v4 the external address that changed 133 * @param v4 the external address that changed
137 */ 134 */
@@ -162,7 +159,7 @@ run_external_ip (void *cls);
162 * We learn our current external IP address. If it changed, 159 * We learn our current external IP address. If it changed,
163 * notify all of our applicable clients. Also re-schedule 160 * notify all of our applicable clients. Also re-schedule
164 * #run_external_ip with an appropriate timeout. 161 * #run_external_ip with an appropriate timeout.
165 * 162 *
166 * @param cls NULL 163 * @param cls NULL
167 * @param addr the address, NULL on errors 164 * @param addr the address, NULL on errors
168 * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code 165 * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
@@ -173,7 +170,7 @@ handle_external_ip (void *cls,
173 enum GNUNET_NAT_StatusCode result) 170 enum GNUNET_NAT_StatusCode result)
174{ 171{
175 char buf[INET_ADDRSTRLEN]; 172 char buf[INET_ADDRSTRLEN];
176 173
177 probe_external_ip_op = NULL; 174 probe_external_ip_op = NULL;
178 GNUNET_SCHEDULER_cancel (probe_external_ip_task); 175 GNUNET_SCHEDULER_cancel (probe_external_ip_task);
179 probe_external_ip_task 176 probe_external_ip_task
@@ -185,6 +182,7 @@ handle_external_ip (void *cls,
185 switch (result) 182 switch (result)
186 { 183 {
187 case GNUNET_NAT_ERROR_SUCCESS: 184 case GNUNET_NAT_ERROR_SUCCESS:
185 GNUNET_assert (NULL != addr);
188 if (addr->s_addr == mini_external_ipv4.s_addr) 186 if (addr->s_addr == mini_external_ipv4.s_addr)
189 return; /* not change */ 187 return; /* not change */
190 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 188 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -204,7 +202,7 @@ handle_external_ip (void *cls,
204 if (0 != mini_external_ipv4.s_addr) 202 if (0 != mini_external_ipv4.s_addr)
205 notify_monitors_external_ipv4_change (GNUNET_NO, 203 notify_monitors_external_ipv4_change (GNUNET_NO,
206 &mini_external_ipv4); 204 &mini_external_ipv4);
207 mini_external_ipv4.s_addr = 0; 205 mini_external_ipv4.s_addr = 0;
208 break; 206 break;
209 } 207 }
210} 208}
@@ -254,7 +252,7 @@ GN_nat_status_changed (int have_nat)
254 NULL); 252 NULL);
255 return; 253 return;
256 } 254 }
257 if (GNUNET_NO == have_nat) 255 if (GNUNET_NO == have_nat)
258 { 256 {
259 if (NULL != probe_external_ip_task) 257 if (NULL != probe_external_ip_task)
260 { 258 {
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/gnunet-service-nat_mini.c b/src/nat/gnunet-service-nat_mini.c
index e5b9d021b..8f1229be1 100644
--- a/src/nat/gnunet-service-nat_mini.c
+++ b/src/nat/gnunet-service-nat_mini.c
@@ -123,7 +123,7 @@ read_external_ipv4 (void *cls)
123 { 123 {
124 /* try to read more */ 124 /* try to read more */
125 eh->off += ret; 125 eh->off += ret;
126 eh->task 126 eh->task
127 = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, 127 = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
128 eh->r, 128 eh->r,
129 &read_external_ipv4, 129 &read_external_ipv4,
@@ -233,7 +233,7 @@ GNUNET_NAT_mini_get_external_ipv4_ (GNUNET_NAT_IPCallback cb,
233 GNUNET_DISK_PIPE_END_WRITE); 233 GNUNET_DISK_PIPE_END_WRITE);
234 eh->r = GNUNET_DISK_pipe_handle (eh->opipe, 234 eh->r = GNUNET_DISK_pipe_handle (eh->opipe,
235 GNUNET_DISK_PIPE_END_READ); 235 GNUNET_DISK_PIPE_END_READ);
236 eh->task 236 eh->task
237 = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, 237 = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
238 eh->r, 238 eh->r,
239 &read_external_ipv4, 239 &read_external_ipv4,
@@ -254,6 +254,8 @@ GNUNET_NAT_mini_get_external_ipv4_cancel_ (struct GNUNET_NAT_ExternalHandle *eh)
254 { 254 {
255 (void) GNUNET_OS_process_kill (eh->eip, 255 (void) GNUNET_OS_process_kill (eh->eip,
256 SIGKILL); 256 SIGKILL);
257 GNUNET_break (GNUNET_OK ==
258 GNUNET_OS_process_wait (eh->eip));
257 GNUNET_OS_process_destroy (eh->eip); 259 GNUNET_OS_process_destroy (eh->eip);
258 } 260 }
259 if (NULL != eh->opipe) 261 if (NULL != eh->opipe)
@@ -372,7 +374,7 @@ run_upnpc_r (struct GNUNET_NAT_MiniHandle *mini)
372 sizeof (pstr), 374 sizeof (pstr),
373 "%u", 375 "%u",
374 (unsigned int) mini->port); 376 (unsigned int) mini->port);
375 mini->map_cmd 377 mini->map_cmd
376 = GNUNET_OS_command_run (&process_map_output, 378 = GNUNET_OS_command_run (&process_map_output,
377 mini, 379 mini,
378 MAP_TIMEOUT, 380 MAP_TIMEOUT,
@@ -516,7 +518,7 @@ do_refresh (void *cls)
516 struct GNUNET_NAT_MiniHandle *mini = cls; 518 struct GNUNET_NAT_MiniHandle *mini = cls;
517 int ac; 519 int ac;
518 520
519 mini->refresh_task 521 mini->refresh_task
520 = GNUNET_SCHEDULER_add_delayed (MAP_REFRESH_FREQ, 522 = GNUNET_SCHEDULER_add_delayed (MAP_REFRESH_FREQ,
521 &do_refresh, 523 &do_refresh,
522 mini); 524 mini);
@@ -538,7 +540,7 @@ do_refresh (void *cls)
538 mini->refresh_cmd = NULL; 540 mini->refresh_cmd = NULL;
539 ac = GNUNET_YES; 541 ac = GNUNET_YES;
540 } 542 }
541 mini->refresh_cmd 543 mini->refresh_cmd
542 = GNUNET_OS_command_run (&process_refresh_output, 544 = GNUNET_OS_command_run (&process_refresh_output,
543 mini, 545 mini,
544 MAP_TIMEOUT, 546 MAP_TIMEOUT,
@@ -582,7 +584,7 @@ process_map_output (void *cls,
582 0, 584 0,
583 GNUNET_NAT_ERROR_UPNPC_PORTMAP_FAILED); 585 GNUNET_NAT_ERROR_UPNPC_PORTMAP_FAILED);
584 if (NULL == mini->refresh_task) 586 if (NULL == mini->refresh_task)
585 mini->refresh_task 587 mini->refresh_task
586 = GNUNET_SCHEDULER_add_delayed (MAP_REFRESH_FREQ, 588 = GNUNET_SCHEDULER_add_delayed (MAP_REFRESH_FREQ,
587 &do_refresh, 589 &do_refresh,
588 mini); 590 mini);
@@ -747,7 +749,7 @@ GNUNET_NAT_mini_map_stop (struct GNUNET_NAT_MiniHandle *mini)
747 LOG (GNUNET_ERROR_TYPE_DEBUG, 749 LOG (GNUNET_ERROR_TYPE_DEBUG,
748 "Unmapping port %u with UPnP\n", 750 "Unmapping port %u with UPnP\n",
749 ntohs (mini->current_addr.sin_port)); 751 ntohs (mini->current_addr.sin_port));
750 mini->unmap_cmd 752 mini->unmap_cmd
751 = GNUNET_OS_command_run (&process_unmap_output, 753 = GNUNET_OS_command_run (&process_unmap_output,
752 mini, 754 mini,
753 UNMAP_TIMEOUT, 755 UNMAP_TIMEOUT,
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/Makefile.am b/src/nse/Makefile.am
index 9a163b160..618489780 100644
--- a/src/nse/Makefile.am
+++ b/src/nse/Makefile.am
@@ -82,7 +82,7 @@ check_PROGRAMS = \
82endif 82endif
83 83
84if ENABLE_TEST_RUN 84if ENABLE_TEST_RUN
85AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; 85AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
86TESTS = $(check_PROGRAMS) 86TESTS = $(check_PROGRAMS)
87endif 87endif
88 88
diff --git a/src/nse/gnunet-nse-profiler.c b/src/nse/gnunet-nse-profiler.c
index 48afd9298..4a10022e3 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_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_uint ('V',
870 "verbose",
871 gettext_noop ("be verbose (print progress information)"),
872 &verbose),
873
874 GNUNET_GETOPT_option_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/Makefile.am b/src/peerinfo-tool/Makefile.am
index c79c3ac68..648957a05 100644
--- a/src/peerinfo-tool/Makefile.am
+++ b/src/peerinfo-tool/Makefile.am
@@ -30,7 +30,7 @@ check_SCRIPTS = \
30endif 30endif
31 31
32if ENABLE_TEST_RUN 32if ENABLE_TEST_RUN
33AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; 33AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
34TESTS = $(check_SCRIPTS) 34TESTS = $(check_SCRIPTS)
35endif 35endif
36 36
diff --git a/src/peerinfo-tool/gnunet-peerinfo.c b/src/peerinfo-tool/gnunet-peerinfo.c
index a5907c63f..de7dcd6fa 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_flag ('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_flag ('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_flag ('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_flag ('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_flag ('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_flag ('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/.gitignore b/src/peerinfo/.gitignore
index e2a79a211..152ca2916 100644
--- a/src/peerinfo/.gitignore
+++ b/src/peerinfo/.gitignore
@@ -3,3 +3,4 @@ test_peerinfo_api
3test_peerinfo_api_friend_only 3test_peerinfo_api_friend_only
4test_peerinfo_api_notify_friend_only 4test_peerinfo_api_notify_friend_only
5test_peerinfo_shipped_hellos 5test_peerinfo_shipped_hellos
6perf_peerinfo_api
diff --git a/src/peerinfo/Makefile.am b/src/peerinfo/Makefile.am
index dd41cf15a..eeb5ee54e 100644
--- a/src/peerinfo/Makefile.am
+++ b/src/peerinfo/Makefile.am
@@ -58,7 +58,7 @@ endif
58 58
59 59
60if ENABLE_TEST_RUN 60if ENABLE_TEST_RUN
61AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; 61AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
62TESTS = $(check_PROGRAMS) 62TESTS = $(check_PROGRAMS)
63endif 63endif
64 64
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/peerinfo/perf_peerinfo_api.c b/src/peerinfo/perf_peerinfo_api.c
index d446cbe3f..840c85c1b 100644
--- a/src/peerinfo/perf_peerinfo_api.c
+++ b/src/peerinfo/perf_peerinfo_api.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 Copyright (C) 2004, 2009, 2010 GNUnet e.V. 3 Copyright (C) 2004, 2009, 2010, 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,7 +22,7 @@
22 * @file peerinfo/perf_peerinfo_api.c 22 * @file peerinfo/perf_peerinfo_api.c
23 * @brief testcase for peerinfo_api.c, hopefully hammer the peerinfo service, 23 * @brief testcase for peerinfo_api.c, hopefully hammer the peerinfo service,
24 * this performance test adds up to 5000 peers with one address each and checks 24 * this performance test adds up to 5000 peers with one address each and checks
25 * over how many peers it can iterate before receiving a timeout after 30 seconds 25 * over how many peers it can iterate before receiving a timeout after 5 seconds
26 * @author Nathan Evans 26 * @author Nathan Evans
27 */ 27 */
28 28
@@ -34,8 +34,6 @@
34#include "peerinfo.h" 34#include "peerinfo.h"
35#include <gauger.h> 35#include <gauger.h>
36 36
37#define START_SERVICE 1
38
39#define NUM_REQUESTS 5000 37#define NUM_REQUESTS 5000
40 38
41static struct GNUNET_PEERINFO_IteratorContext *ic[NUM_REQUESTS]; 39static struct GNUNET_PEERINFO_IteratorContext *ic[NUM_REQUESTS];
@@ -46,9 +44,36 @@ static unsigned int numpeers;
46 44
47static struct GNUNET_PeerIdentity pid; 45static struct GNUNET_PeerIdentity pid;
48 46
47static struct GNUNET_SCHEDULER_Task *tt;
48
49
50static void
51do_shutdown (void *cls)
52{
53 if (NULL != tt)
54 {
55 GNUNET_SCHEDULER_cancel (tt);
56 tt = NULL;
57 }
58 for (unsigned int i = 0; i < NUM_REQUESTS; i++)
59 if (NULL != ic[i])
60 GNUNET_PEERINFO_iterate_cancel (ic[i]);
61 GNUNET_PEERINFO_disconnect (h);
62 h = NULL;
63}
64
65
66static void
67do_timeout (void *cls)
68{
69 tt = NULL;
70 GNUNET_SCHEDULER_shutdown ();
71}
72
49 73
50static int 74static int
51check_it (void *cls, const struct GNUNET_HELLO_Address *address, 75check_it (void *cls,
76 const struct GNUNET_HELLO_Address *address,
52 struct GNUNET_TIME_Absolute expiration) 77 struct GNUNET_TIME_Absolute expiration)
53{ 78{
54 return GNUNET_OK; 79 return GNUNET_OK;
@@ -87,23 +112,34 @@ add_peer (size_t i)
87 struct GNUNET_HELLO_Message *h2; 112 struct GNUNET_HELLO_Message *h2;
88 113
89 memset (&pid, i, sizeof (pid)); 114 memset (&pid, i, sizeof (pid));
90 h2 = GNUNET_HELLO_create (&pid.public_key, &address_generator, &i, GNUNET_NO); 115 h2 = GNUNET_HELLO_create (&pid.public_key,
116 &address_generator,
117 &i,
118 GNUNET_NO);
91 GNUNET_PEERINFO_add_peer (h, h2, NULL, NULL); 119 GNUNET_PEERINFO_add_peer (h, h2, NULL, NULL);
92 GNUNET_free (h2); 120 GNUNET_free (h2);
93} 121}
94 122
95 123
96static void 124static void
97process (void *cls, const struct GNUNET_PeerIdentity *peer, 125process (void *cls,
98 const struct GNUNET_HELLO_Message *hello, const char *err_msg) 126 const struct GNUNET_PeerIdentity *peer,
127 const struct GNUNET_HELLO_Message *hello,
128 const char *err_msg)
99{ 129{
100 if (NULL != peer) 130 struct GNUNET_PEERINFO_IteratorContext **icp = cls;
101 {
102 numpeers++;
103 if (0 && (hello != NULL))
104 GNUNET_HELLO_iterate_addresses (hello, GNUNET_NO, &check_it, NULL);
105 131
132 if (NULL == peer)
133 {
134 *icp = NULL;
135 return;
106 } 136 }
137 numpeers++;
138 if (0 && (NULL != hello) )
139 GNUNET_HELLO_iterate_addresses (hello,
140 GNUNET_NO,
141 &check_it,
142 NULL);
107} 143}
108 144
109 145
@@ -112,32 +148,43 @@ run (void *cls,
112 const struct GNUNET_CONFIGURATION_Handle *cfg, 148 const struct GNUNET_CONFIGURATION_Handle *cfg,
113 struct GNUNET_TESTING_Peer *peer) 149 struct GNUNET_TESTING_Peer *peer)
114{ 150{
115 size_t i;
116
117 h = GNUNET_PEERINFO_connect (cfg); 151 h = GNUNET_PEERINFO_connect (cfg);
118 GNUNET_assert (h != NULL); 152 GNUNET_assert (h != NULL);
119 for (i = 0; i < NUM_REQUESTS; i++) 153 for (unsigned int i = 0; i < NUM_REQUESTS; i++)
120 { 154 {
121 add_peer (i); 155 add_peer (i);
122 ic[i] = 156 ic[i] = GNUNET_PEERINFO_iterate (h,
123 GNUNET_PEERINFO_iterate (h, GNUNET_YES, NULL, 157 GNUNET_YES,
124 GNUNET_TIME_relative_multiply 158 NULL,
125 (GNUNET_TIME_UNIT_SECONDS, 30), &process, cls); 159 &process,
160 &ic[i]);
126 } 161 }
162 tt = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
163 5),
164 &do_timeout,
165 NULL);
166 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
167 NULL);
127} 168}
128 169
129 170
130int 171int
131main (int argc, char *argv[]) 172main (int argc,
173 char *argv[])
132{ 174{
133 if (0 != GNUNET_TESTING_service_run ("perf-gnunet-peerinfo", 175 if (0 != GNUNET_TESTING_service_run ("perf-gnunet-peerinfo",
134 "peerinfo", 176 "peerinfo",
135 "test_peerinfo_api_data.conf", 177 "test_peerinfo_api_data.conf",
136 &run, NULL)) 178 &run, NULL))
137 return 1; 179 return 1;
138 FPRINTF (stderr, "Received %u/%u calls before timeout\n", numpeers, 180 FPRINTF (stderr,
181 "Received %u/%u calls before timeout\n",
182 numpeers,
139 NUM_REQUESTS * NUM_REQUESTS / 2); 183 NUM_REQUESTS * NUM_REQUESTS / 2);
140 GAUGER ("PEERINFO", "Peerinfo lookups", numpeers / 30, "peers/s"); 184 GAUGER ("PEERINFO",
185 "Peerinfo lookups",
186 numpeers / 5,
187 "peers/s");
141 return 0; 188 return 0;
142} 189}
143 190
diff --git a/src/peerstore/.gitignore b/src/peerstore/.gitignore
index 33304d90b..7fc22bbdb 100644
--- a/src/peerstore/.gitignore
+++ b/src/peerstore/.gitignore
@@ -6,3 +6,4 @@ test_peerstore_api_store
6test_peerstore_api_sync 6test_peerstore_api_sync
7test_peerstore_api_watch 7test_peerstore_api_watch
8test_plugin_peerstore_sqlite 8test_plugin_peerstore_sqlite
9test_plugin_peerstore_flat
diff --git a/src/peerstore/Makefile.am b/src/peerstore/Makefile.am
index a12fdde2a..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)
@@ -108,7 +110,7 @@ EXTRA_DIST = \
108 test_peerstore_api_data.conf 110 test_peerstore_api_data.conf
109 111
110if ENABLE_TEST_RUN 112if ENABLE_TEST_RUN
111AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; 113AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
112TESTS = $(check_PROGRAMS) 114TESTS = $(check_PROGRAMS)
113endif 115endif
114 116
diff --git a/src/peerstore/gnunet-service-peerstore.c b/src/peerstore/gnunet-service-peerstore.c
index 665e625fd..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);
@@ -523,24 +532,25 @@ handle_store (void *cls,
523 532
524 record = PEERSTORE_parse_record_message (srm); 533 record = PEERSTORE_parse_record_message (srm);
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: %d.\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 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/postgres/postgres.c b/src/postgres/postgres.c
index 4798c129d..14095c5a4 100644
--- a/src/postgres/postgres.c
+++ b/src/postgres/postgres.c
@@ -182,22 +182,22 @@ GNUNET_POSTGRES_connect (const struct GNUNET_CONFIGURATION_Handle * cfg,
182 &conninfo)) 182 &conninfo))
183 conninfo = NULL; 183 conninfo = NULL;
184 dbh = PQconnectdb (conninfo == NULL ? "" : conninfo); 184 dbh = PQconnectdb (conninfo == NULL ? "" : conninfo);
185 GNUNET_free_non_null (conninfo); 185
186 if (NULL == dbh) 186 if (NULL != dbh)
187 {
188 /* FIXME: warn about out-of-memory? */
189 return NULL;
190 }
191 if (PQstatus (dbh) != CONNECTION_OK)
192 { 187 {
193 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, 188 if (PQstatus (dbh) != CONNECTION_OK)
194 "postgres", 189 {
195 _("Unable to connect to Postgres database '%s': %s\n"), 190 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
196 conninfo, 191 "postgres",
197 PQerrorMessage (dbh)); 192 _("Unable to connect to Postgres database '%s': %s\n"),
198 PQfinish (dbh); 193 conninfo,
199 return NULL; 194 PQerrorMessage (dbh));
195 PQfinish (dbh);
196 dbh = NULL;
197 }
200 } 198 }
199 // FIXME: warn about out-of-memory when dbh is NULL?
200 GNUNET_free_non_null (conninfo);
201 return dbh; 201 return dbh;
202} 202}
203 203
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/pq/pq_result_helper.c b/src/pq/pq_result_helper.c
index 180c5fc18..c5c8e56b9 100644
--- a/src/pq/pq_result_helper.c
+++ b/src/pq/pq_result_helper.c
@@ -77,9 +77,7 @@ extract_varsize_blob (void *cls,
77 fname); 77 fname);
78 if (fnum < 0) 78 if (fnum < 0)
79 { 79 {
80 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 80 GNUNET_break (0);
81 "Field `%s' does not exist in result\n",
82 fname);
83 return GNUNET_SYSERR; 81 return GNUNET_SYSERR;
84 } 82 }
85 if (PQgetisnull (result, 83 if (PQgetisnull (result,
@@ -156,9 +154,7 @@ extract_fixed_blob (void *cls,
156 fname); 154 fname);
157 if (fnum < 0) 155 if (fnum < 0)
158 { 156 {
159 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 157 GNUNET_break (0);
160 "Field `%s' does not exist in result\n",
161 fname);
162 return GNUNET_SYSERR; 158 return GNUNET_SYSERR;
163 } 159 }
164 if (PQgetisnull (result, 160 if (PQgetisnull (result,
@@ -173,11 +169,7 @@ extract_fixed_blob (void *cls,
173 fnum); 169 fnum);
174 if (*dst_size != len) 170 if (*dst_size != len)
175 { 171 {
176 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 172 GNUNET_break (0);
177 "Field `%s' has wrong size (got %u, expected %u)\n",
178 fname,
179 (unsigned int) len,
180 (unsigned int) *dst_size);
181 return GNUNET_SYSERR; 173 return GNUNET_SYSERR;
182 } 174 }
183 res = PQgetvalue (result, 175 res = PQgetvalue (result,
@@ -243,9 +235,7 @@ extract_rsa_public_key (void *cls,
243 fname); 235 fname);
244 if (fnum < 0) 236 if (fnum < 0)
245 { 237 {
246 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 238 GNUNET_break (0);
247 "Field `%s' does not exist in result\n",
248 fname);
249 return GNUNET_SYSERR; 239 return GNUNET_SYSERR;
250 } 240 }
251 if (PQgetisnull (result, 241 if (PQgetisnull (result,
@@ -265,9 +255,7 @@ extract_rsa_public_key (void *cls,
265 len); 255 len);
266 if (NULL == *pk) 256 if (NULL == *pk)
267 { 257 {
268 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 258 GNUNET_break (0);
269 "Field `%s' contains bogus value (fails to decode)\n",
270 fname);
271 return GNUNET_SYSERR; 259 return GNUNET_SYSERR;
272 } 260 }
273 return GNUNET_OK; 261 return GNUNET_OK;
@@ -346,9 +334,7 @@ extract_rsa_signature (void *cls,
346 fname); 334 fname);
347 if (fnum < 0) 335 if (fnum < 0)
348 { 336 {
349 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 337 GNUNET_break (0);
350 "Field `%s' does not exist in result\n",
351 fname);
352 return GNUNET_SYSERR; 338 return GNUNET_SYSERR;
353 } 339 }
354 if (PQgetisnull (result, 340 if (PQgetisnull (result,
@@ -368,9 +354,7 @@ extract_rsa_signature (void *cls,
368 len); 354 len);
369 if (NULL == *sig) 355 if (NULL == *sig)
370 { 356 {
371 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 357 GNUNET_break (0);
372 "Field `%s' contains bogus value (fails to decode)\n",
373 fname);
374 return GNUNET_SYSERR; 358 return GNUNET_SYSERR;
375 } 359 }
376 return GNUNET_OK; 360 return GNUNET_OK;
@@ -449,9 +433,7 @@ extract_string (void *cls,
449 fname); 433 fname);
450 if (fnum < 0) 434 if (fnum < 0)
451 { 435 {
452 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 436 GNUNET_break (0);
453 "Field `%s' does not exist in result\n",
454 fname);
455 return GNUNET_SYSERR; 437 return GNUNET_SYSERR;
456 } 438 }
457 if (PQgetisnull (result, 439 if (PQgetisnull (result,
@@ -471,9 +453,7 @@ extract_string (void *cls,
471 len); 453 len);
472 if (NULL == *str) 454 if (NULL == *str)
473 { 455 {
474 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 456 GNUNET_break (0);
475 "Field `%s' contains bogus value (fails to decode)\n",
476 fname);
477 return GNUNET_SYSERR; 457 return GNUNET_SYSERR;
478 } 458 }
479 return GNUNET_OK; 459 return GNUNET_OK;
@@ -583,9 +563,7 @@ extract_uint16 (void *cls,
583 fname); 563 fname);
584 if (fnum < 0) 564 if (fnum < 0)
585 { 565 {
586 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 566 GNUNET_break (0);
587 "Field `%s' does not exist in result\n",
588 fname);
589 return GNUNET_SYSERR; 567 return GNUNET_SYSERR;
590 } 568 }
591 if (PQgetisnull (result, 569 if (PQgetisnull (result,
@@ -655,9 +633,7 @@ extract_uint32 (void *cls,
655 fname); 633 fname);
656 if (fnum < 0) 634 if (fnum < 0)
657 { 635 {
658 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 636 GNUNET_break (0);
659 "Field `%s' does not exist in result\n",
660 fname);
661 return GNUNET_SYSERR; 637 return GNUNET_SYSERR;
662 } 638 }
663 if (PQgetisnull (result, 639 if (PQgetisnull (result,
@@ -727,9 +703,7 @@ extract_uint64 (void *cls,
727 fname); 703 fname);
728 if (fnum < 0) 704 if (fnum < 0)
729 { 705 {
730 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 706 GNUNET_break (0);
731 "Field `%s' does not exist in result\n",
732 fname);
733 return GNUNET_SYSERR; 707 return GNUNET_SYSERR;
734 } 708 }
735 if (PQgetisnull (result, 709 if (PQgetisnull (result,
diff --git a/src/pq/test_pq.c b/src/pq/test_pq.c
index 49705103f..b54318110 100644
--- a/src/pq/test_pq.c
+++ b/src/pq/test_pq.c
@@ -218,8 +218,8 @@ run_queries (PGconn *conn)
218 218
219 219
220int 220int
221main(int argc, 221main (int argc,
222 const char *const argv[]) 222 const char *const argv[])
223{ 223{
224 PGconn *conn; 224 PGconn *conn;
225 PGresult *result; 225 PGresult *result;
@@ -236,7 +236,7 @@ main(int argc,
236 PQerrorMessage (conn)); 236 PQerrorMessage (conn));
237 GNUNET_break (0); 237 GNUNET_break (0);
238 PQfinish (conn); 238 PQfinish (conn);
239 return 0; /* We ignore this type of error... */ 239 return 77; /* signal test was skipped */
240 } 240 }
241 241
242 result = PQexec (conn, 242 result = PQexec (conn,
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/Makefile.am b/src/psyc/Makefile.am
index 0016b1b3b..a16128624 100644
--- a/src/psyc/Makefile.am
+++ b/src/psyc/Makefile.am
@@ -53,7 +53,7 @@ check_PROGRAMS = \
53endif 53endif
54 54
55if ENABLE_TEST_RUN 55if ENABLE_TEST_RUN
56AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; 56AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
57TESTS = $(check_PROGRAMS) 57TESTS = $(check_PROGRAMS)
58endif 58endif
59 59
diff --git a/src/psyc/gnunet-service-psyc.c b/src/psyc/gnunet-service-psyc.c
index eab74b467..73a3ae4ee 100644
--- a/src/psyc/gnunet-service-psyc.c
+++ b/src/psyc/gnunet-service-psyc.c
@@ -467,6 +467,9 @@ schedule_transmit_message (void *cls)
467static void 467static void
468shutdown_task (void *cls) 468shutdown_task (void *cls)
469{ 469{
470 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
471 "shutting down...\n");
472 GNUNET_PSYCSTORE_disconnect (store);
470 if (NULL != stats) 473 if (NULL != stats)
471 { 474 {
472 GNUNET_STATISTICS_destroy (stats, GNUNET_YES); 475 GNUNET_STATISTICS_destroy (stats, GNUNET_YES);
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/Makefile.am b/src/psycstore/Makefile.am
index 30e2a9673..a342c06e6 100644
--- a/src/psycstore/Makefile.am
+++ b/src/psycstore/Makefile.am
@@ -94,7 +94,10 @@ libgnunet_plugin_psycstore_postgres_la_LIBADD = \
94 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lpq \ 94 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lpq \
95 $(LTLIBINTL) 95 $(LTLIBINTL)
96libgnunet_plugin_psycstore_postgres_la_LDFLAGS = \ 96libgnunet_plugin_psycstore_postgres_la_LDFLAGS = \
97 $(GN_PLUGIN_LDFLAGS) $(POSTGRESQL_LDFLAGS) 97 $(GN_PLUGIN_LDFLAGS) $(POSTGRESQL_LDFLAGS)
98libgnunet_plugin_psycstore_postgres_la_CPPFLAGS = \
99 $(POSTGRESQL_CPPFLAGS) $(AM_CPPFLAGS)
100
98 101
99libgnunet_plugin_psycstore_sqlite_la_SOURCES = \ 102libgnunet_plugin_psycstore_sqlite_la_SOURCES = \
100 plugin_psycstore_sqlite.c 103 plugin_psycstore_sqlite.c
@@ -118,7 +121,7 @@ endif
118endif 121endif
119 122
120if ENABLE_TEST_RUN 123if ENABLE_TEST_RUN
121AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; 124AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
122TESTS = $(check_PROGRAMS) 125TESTS = $(check_PROGRAMS)
123endif 126endif
124 127
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/psycutil/Makefile.am b/src/psycutil/Makefile.am
index 2a916fe30..2732c3a21 100644
--- a/src/psycutil/Makefile.am
+++ b/src/psycutil/Makefile.am
@@ -33,7 +33,7 @@ check_PROGRAMS = \
33endif 33endif
34 34
35if ENABLE_TEST_RUN 35if ENABLE_TEST_RUN
36AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; 36AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
37TESTS = $(check_PROGRAMS) 37TESTS = $(check_PROGRAMS)
38endif 38endif
39 39
diff --git a/src/pt/.gitignore b/src/pt/.gitignore
index 22f803ed6..ea678ffe5 100644
--- a/src/pt/.gitignore
+++ b/src/pt/.gitignore
@@ -1 +1,6 @@
1gnunet-daemon-pt 1gnunet-daemon-pt
2test_gns_vpn
3test_gnunet_vpn-4_over
4test_gnunet_vpn-4_to_6
5test_gnunet_vpn-6_over
6test_gnunet_vpn-6_to_4
diff --git a/src/pt/Makefile.am b/src/pt/Makefile.am
index e56990f08..e36630ae4 100644
--- a/src/pt/Makefile.am
+++ b/src/pt/Makefile.am
@@ -82,7 +82,7 @@ endif
82check_PROGRAMS = $(VPN_TEST) 82check_PROGRAMS = $(VPN_TEST)
83 83
84if ENABLE_TEST_RUN 84if ENABLE_TEST_RUN
85AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; 85AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
86TESTS = $(check_PROGRAMS) 86TESTS = $(check_PROGRAMS)
87endif 87endif
88 88
diff --git a/src/pt/gnunet-daemon-pt.c b/src/pt/gnunet-daemon-pt.c
index 06ef88832..295082c0e 100644
--- a/src/pt/gnunet-daemon-pt.c
+++ b/src/pt/gnunet-daemon-pt.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 Copyright (C) 2010, 2012 Christian Grothoff 3 Copyright (C) 2010, 2012, 2017 Christian Grothoff
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,7 +17,6 @@
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
21/** 20/**
22 * @file pt/gnunet-daemon-pt.c 21 * @file pt/gnunet-daemon-pt.c
23 * @brief tool to manipulate DNS and VPN services to perform protocol translation (IPvX over GNUnet) 22 * @brief tool to manipulate DNS and VPN services to perform protocol translation (IPvX over GNUnet)
@@ -161,21 +160,6 @@ struct CadetExit
161 struct RequestContext *receive_queue_tail; 160 struct RequestContext *receive_queue_tail;
162 161
163 /** 162 /**
164 * Head of DLL of requests to be transmitted to a cadet_channel.
165 */
166 struct RequestContext *transmit_queue_head;
167
168 /**
169 * Tail of DLL of requests to be transmitted to a cadet_channel.
170 */
171 struct RequestContext *transmit_queue_tail;
172
173 /**
174 * Active transmission request for this channel (or NULL).
175 */
176 struct GNUNET_CADET_TransmitHandle *cadet_th;
177
178 /**
179 * Identity of the peer that is providing the exit for us. 163 * Identity of the peer that is providing the exit for us.
180 */ 164 */
181 struct GNUNET_PeerIdentity peer; 165 struct GNUNET_PeerIdentity peer;
@@ -190,6 +174,11 @@ struct CadetExit
190 */ 174 */
191 unsigned int num_answered; 175 unsigned int num_answered;
192 176
177 /**
178 * Size of the window, 0 if we are busy.
179 */
180 /* unsigned */ int idle;
181
193}; 182};
194 183
195 184
@@ -220,10 +209,9 @@ struct RequestContext
220 struct GNUNET_DNS_RequestHandle *rh; 209 struct GNUNET_DNS_RequestHandle *rh;
221 210
222 /** 211 /**
223 * Message we're sending out via CADET, allocated at the 212 * Envelope with the request we are transmitting.
224 * end of this struct.
225 */ 213 */
226 const struct GNUNET_MessageHeader *cadet_message; 214 struct GNUNET_MQ_Envelope *env;
227 215
228 /** 216 /**
229 * Task used to abort this operation with timeout. 217 * Task used to abort this operation with timeout.
@@ -240,12 +228,6 @@ struct RequestContext
240 */ 228 */
241 uint16_t dns_id; 229 uint16_t dns_id;
242 230
243 /**
244 * #GNUNET_NO if this request is still in the transmit_queue,
245 * #GNUNET_YES if we are in the receive_queue.
246 */
247 int16_t was_transmitted;
248
249}; 231};
250 232
251 233
@@ -328,59 +310,7 @@ static unsigned int dns_exit_available;
328 * We are short on cadet exits, try to open another one. 310 * We are short on cadet exits, try to open another one.
329 */ 311 */
330static void 312static void
331try_open_exit () 313try_open_exit (void);
332{
333 struct CadetExit *pos;
334 uint32_t candidate_count;
335 uint32_t candidate_selected;
336 struct GNUNET_HashCode port;
337
338 GNUNET_CRYPTO_hash (GNUNET_APPLICATION_PORT_INTERNET_RESOLVER,
339 strlen (GNUNET_APPLICATION_PORT_INTERNET_RESOLVER),
340 &port);
341 candidate_count = 0;
342 for (pos = exit_head; NULL != pos; pos = pos->next)
343 if (NULL == pos->cadet_channel)
344 candidate_count++;
345 if (0 == candidate_count)
346 {
347 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
348 "No DNS exits available yet.\n");
349 return;
350 }
351 candidate_selected = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
352 candidate_count);
353 candidate_count = 0;
354 for (pos = exit_head; NULL != pos; pos = pos->next)
355 if (NULL == pos->cadet_channel)
356 {
357 candidate_count++;
358 if (candidate_selected < candidate_count)
359 {
360 /* move to the head of the DLL */
361 pos->cadet_channel
362 = GNUNET_CADET_channel_create (cadet_handle,
363 pos,
364 &pos->peer,
365 &port,
366 GNUNET_CADET_OPTION_DEFAULT);
367 if (NULL == pos->cadet_channel)
368 {
369 GNUNET_break (0);
370 continue;
371 }
372 GNUNET_CONTAINER_DLL_remove (exit_head,
373 exit_tail,
374 pos);
375 GNUNET_CONTAINER_DLL_insert (exit_head,
376 exit_tail,
377 pos);
378 dns_exit_available++;
379 return;
380 }
381 }
382 GNUNET_assert (NULL == exit_head);
383}
384 314
385 315
386/** 316/**
@@ -443,7 +373,7 @@ choose_exit ()
443 channel_weight = get_channel_weight (pos); 373 channel_weight = get_channel_weight (pos);
444 total_transmitted += channel_weight; 374 total_transmitted += channel_weight;
445 /* double weight for idle channels */ 375 /* double weight for idle channels */
446 if (NULL == pos->cadet_th) 376 if (0 != pos->idle)
447 total_transmitted += channel_weight; 377 total_transmitted += channel_weight;
448 } 378 }
449 if (0 == total_transmitted) 379 if (0 == total_transmitted)
@@ -461,7 +391,7 @@ choose_exit ()
461 channel_weight = get_channel_weight (pos); 391 channel_weight = get_channel_weight (pos);
462 total_transmitted += channel_weight; 392 total_transmitted += channel_weight;
463 /* double weight for idle channels */ 393 /* double weight for idle channels */
464 if (NULL == pos->cadet_th) 394 if (0 != pos->idle)
465 total_transmitted += channel_weight; 395 total_transmitted += channel_weight;
466 if (total_transmitted > selected_offset) 396 if (total_transmitted > selected_offset)
467 return pos; 397 return pos;
@@ -768,62 +698,6 @@ dns_post_request_handler (void *cls,
768 698
769 699
770/** 700/**
771 * Transmit a DNS request via CADET and move the request
772 * handle to the receive queue.
773 *
774 * @param cls the `struct CadetExit`
775 * @param size number of bytes available in buf
776 * @param buf where to copy the message
777 * @return number of bytes written to buf
778 */
779static size_t
780transmit_dns_request_to_cadet (void *cls,
781 size_t size,
782 void *buf)
783{
784 struct CadetExit *exit = cls;
785 struct RequestContext *rc;
786 size_t mlen;
787
788 exit->cadet_th = NULL;
789 if (NULL == (rc = exit->transmit_queue_head))
790 return 0;
791 mlen = rc->mlen;
792 if (mlen > size)
793 {
794 exit->cadet_th
795 = GNUNET_CADET_notify_transmit_ready (exit->cadet_channel,
796 GNUNET_NO,
797 TIMEOUT,
798 mlen,
799 &transmit_dns_request_to_cadet,
800 exit);
801 return 0;
802 }
803 GNUNET_assert (GNUNET_NO == rc->was_transmitted);
804 GNUNET_memcpy (buf,
805 rc->cadet_message,
806 mlen);
807 GNUNET_CONTAINER_DLL_remove (exit->transmit_queue_head,
808 exit->transmit_queue_tail,
809 rc);
810 rc->was_transmitted = GNUNET_YES;
811 GNUNET_CONTAINER_DLL_insert (exit->receive_queue_head,
812 exit->receive_queue_tail,
813 rc);
814 rc = exit->transmit_queue_head;
815 if (NULL != rc)
816 exit->cadet_th = GNUNET_CADET_notify_transmit_ready (exit->cadet_channel,
817 GNUNET_NO,
818 TIMEOUT,
819 rc->mlen,
820 &transmit_dns_request_to_cadet,
821 exit);
822 return mlen;
823}
824
825
826/**
827 * Task run if the time to answer a DNS request via CADET is over. 701 * Task run if the time to answer a DNS request via CADET is over.
828 * 702 *
829 * @param cls the `struct RequestContext` to abort 703 * @param cls the `struct RequestContext` to abort
@@ -834,19 +708,6 @@ timeout_request (void *cls)
834 struct RequestContext *rc = cls; 708 struct RequestContext *rc = cls;
835 struct CadetExit *exit = rc->exit; 709 struct CadetExit *exit = rc->exit;
836 710
837 if (rc->was_transmitted)
838 {
839 exit->num_transmitted++;
840 GNUNET_CONTAINER_DLL_remove (exit->receive_queue_head,
841 exit->receive_queue_tail,
842 rc);
843 }
844 else
845 {
846 GNUNET_CONTAINER_DLL_remove (exit->transmit_queue_head,
847 exit->transmit_queue_tail,
848 rc);
849 }
850 GNUNET_STATISTICS_update (stats, 711 GNUNET_STATISTICS_update (stats,
851 gettext_noop ("# DNS requests dropped (timeout)"), 712 gettext_noop ("# DNS requests dropped (timeout)"),
852 1, 713 1,
@@ -854,12 +715,10 @@ timeout_request (void *cls)
854 GNUNET_DNS_request_drop (rc->rh); 715 GNUNET_DNS_request_drop (rc->rh);
855 GNUNET_free (rc); 716 GNUNET_free (rc);
856 if ( (0 == get_channel_weight (exit)) && 717 if ( (0 == get_channel_weight (exit)) &&
857 (NULL == exit->receive_queue_head) && 718 (NULL == exit->receive_queue_head) )
858 (NULL == exit->transmit_queue_head) )
859 { 719 {
860 /* this straw broke the camel's back: this channel now has 720 /* this straw broke the camel's back: this channel now has
861 such a low score that it will not be used; close it! */ 721 such a low score that it will not be used; close it! */
862 GNUNET_assert (NULL == exit->cadet_th);
863 GNUNET_CADET_channel_destroy (exit->cadet_channel); 722 GNUNET_CADET_channel_destroy (exit->cadet_channel);
864 exit->cadet_channel = NULL; 723 exit->cadet_channel = NULL;
865 GNUNET_CONTAINER_DLL_remove (exit_head, 724 GNUNET_CONTAINER_DLL_remove (exit_head,
@@ -870,7 +729,7 @@ timeout_request (void *cls)
870 exit); 729 exit);
871 /* go back to semi-innocent: mark as not great, but 730 /* go back to semi-innocent: mark as not great, but
872 avoid a prohibitively negative score (see 731 avoid a prohibitively negative score (see
873 #get_channel_weight, which checks for a certain 732 #get_channel_weight(), which checks for a certain
874 minimum number of transmissions before making 733 minimum number of transmissions before making
875 up an opinion) */ 734 up an opinion) */
876 exit->num_transmitted = 5; 735 exit->num_transmitted = 5;
@@ -900,8 +759,8 @@ dns_pre_request_handler (void *cls,
900 const char *request) 759 const char *request)
901{ 760{
902 struct RequestContext *rc; 761 struct RequestContext *rc;
903 size_t mlen; 762 struct GNUNET_MQ_Envelope *env;
904 struct GNUNET_MessageHeader hdr; 763 struct GNUNET_MessageHeader *hdr;
905 struct GNUNET_TUN_DnsHeader dns; 764 struct GNUNET_TUN_DnsHeader dns;
906 struct CadetExit *exit; 765 struct CadetExit *exit;
907 766
@@ -924,93 +783,115 @@ dns_pre_request_handler (void *cls,
924 GNUNET_DNS_request_drop (rh); 783 GNUNET_DNS_request_drop (rh);
925 return; 784 return;
926 } 785 }
927 GNUNET_memcpy (&dns, request, sizeof (dns));
928 mlen = sizeof (struct GNUNET_MessageHeader) + request_length;
929 exit = choose_exit (); 786 exit = choose_exit ();
930 GNUNET_assert (NULL != exit); 787 GNUNET_assert (NULL != exit);
931 GNUNET_assert (NULL != exit->cadet_channel); 788 GNUNET_assert (NULL != exit->cadet_channel);
932 rc = GNUNET_malloc (sizeof (struct RequestContext) + mlen); 789
790 env = GNUNET_MQ_msg_extra (hdr,
791 request_length,
792 GNUNET_MESSAGE_TYPE_VPN_DNS_TO_INTERNET);
793 GNUNET_memcpy (&hdr[1],
794 request,
795 request_length);
796 rc = GNUNET_new (struct RequestContext);
933 rc->exit = exit; 797 rc->exit = exit;
934 rc->rh = rh; 798 rc->rh = rh;
935 rc->cadet_message = (const struct GNUNET_MessageHeader*) &rc[1];
936 rc->timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, 799 rc->timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
937 &timeout_request, 800 &timeout_request,
938 rc); 801 rc);
802 GNUNET_memcpy (&dns,
803 request,
804 sizeof (dns));
939 rc->dns_id = dns.id; 805 rc->dns_id = dns.id;
940 rc->mlen = mlen; 806 rc->env = env;
941 hdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_DNS_TO_INTERNET); 807 GNUNET_CONTAINER_DLL_remove (exit->receive_queue_head,
942 hdr.size = htons (mlen); 808 exit->receive_queue_tail,
943 GNUNET_memcpy (&rc[1], &hdr, sizeof (struct GNUNET_MessageHeader)); 809 rc);
944 GNUNET_memcpy (&(((char*)&rc[1])[sizeof (struct GNUNET_MessageHeader)]), 810 if (0 < exit->idle)
945 request, 811 exit->idle--;
946 request_length); 812 exit->num_transmitted++;
947 GNUNET_CONTAINER_DLL_insert_tail (exit->transmit_queue_head, 813 GNUNET_MQ_send (GNUNET_CADET_get_mq (exit->cadet_channel),
948 exit->transmit_queue_tail, 814 GNUNET_MQ_env_copy (env));
949 rc);
950 if (NULL == exit->cadet_th)
951 exit->cadet_th = GNUNET_CADET_notify_transmit_ready (exit->cadet_channel,
952 GNUNET_NO,
953 TIMEOUT,
954 mlen,
955 &transmit_dns_request_to_cadet,
956 exit);
957} 815}
958 816
959 817
818GNUNET_NETWORK_STRUCT_BEGIN
819
820/**
821 * Message with a DNS response.
822 */
823struct DnsResponseMessage
824{
825 /**
826 * GNUnet header, of type #GNUNET_MESSAGE_TYPE_VPN_DNS_FROM_INTERNET
827 */
828 struct GNUNET_MessageHeader header;
829
830 /**
831 * DNS header.
832 */
833 struct GNUNET_TUN_DnsHeader dns;
834
835 /* Followed by more DNS payload */
836};
837
838GNUNET_NETWORK_STRUCT_END
839
960/** 840/**
961 * Process a request via cadet to perform a DNS query. 841 * Process a request via cadet to perform a DNS query.
962 * 842 *
963 * @param cls NULL 843 * @param cls the `struct CadetExit` which got the message
964 * @param channel connection to the other end 844 * @param msg the actual message
965 * @param channel_ctx pointer to our `struct CadetExit`
966 * @param message the actual message
967 * @return #GNUNET_OK to keep the connection open, 845 * @return #GNUNET_OK to keep the connection open,
968 * #GNUNET_SYSERR to close it (signal serious error) 846 * #GNUNET_SYSERR to close it (signal serious error)
969 */ 847 */
970static int 848static int
971receive_dns_response (void *cls, 849check_dns_response (void *cls,
972 struct GNUNET_CADET_Channel *channel, 850 const struct DnsResponseMessage *msg)
973 void **channel_ctx,
974 const struct GNUNET_MessageHeader *message)
975{ 851{
976 struct CadetExit *exit = *channel_ctx; 852 return GNUNET_OK; /* all OK */
977 struct GNUNET_TUN_DnsHeader dns; 853}
854
855
856/**
857 * Process a request via cadet to perform a DNS query.
858 *
859 * @param cls the `struct CadetExit` which got the message
860 * @param msg the actual message
861 */
862static void
863handle_dns_response (void *cls,
864 const struct DnsResponseMessage *msg)
865{
866 struct CadetExit *exit = cls;
978 size_t mlen; 867 size_t mlen;
979 struct RequestContext *rc; 868 struct RequestContext *rc;
980 869
981 mlen = ntohs (message->size); 870 mlen = ntohs (msg->header.size) - sizeof (*msg);
982 mlen -= sizeof (struct GNUNET_MessageHeader);
983 if (mlen < sizeof (struct GNUNET_TUN_DnsHeader))
984 {
985 GNUNET_break_op (0);
986 return GNUNET_SYSERR;
987 }
988 GNUNET_memcpy (&dns, &message[1], sizeof (dns));
989 for (rc = exit->receive_queue_head; NULL != rc; rc = rc->next) 871 for (rc = exit->receive_queue_head; NULL != rc; rc = rc->next)
990 { 872 {
991 GNUNET_assert (GNUNET_YES == rc->was_transmitted); 873 if (msg->dns.id == rc->dns_id)
992 if (dns.id == rc->dns_id)
993 { 874 {
994 GNUNET_STATISTICS_update (stats, 875 GNUNET_STATISTICS_update (stats,
995 gettext_noop ("# DNS replies received"), 876 gettext_noop ("# DNS replies received"),
996 1, GNUNET_NO); 877 1,
878 GNUNET_NO);
997 GNUNET_DNS_request_answer (rc->rh, 879 GNUNET_DNS_request_answer (rc->rh,
998 mlen, 880 mlen + sizeof (struct GNUNET_TUN_DnsHeader),
999 (const void*) &message[1]); 881 (const void*) &msg->dns);
1000 GNUNET_CONTAINER_DLL_remove (exit->receive_queue_head, 882 GNUNET_CONTAINER_DLL_remove (exit->receive_queue_head,
1001 exit->receive_queue_tail, 883 exit->receive_queue_tail,
1002 rc); 884 rc);
1003 GNUNET_SCHEDULER_cancel (rc->timeout_task); 885 GNUNET_SCHEDULER_cancel (rc->timeout_task);
886 GNUNET_MQ_discard (rc->env);
1004 GNUNET_free (rc); 887 GNUNET_free (rc);
1005 exit->num_answered++; 888 exit->num_answered++;
1006 exit->num_transmitted++; 889 return;
1007 return GNUNET_OK;
1008 } 890 }
1009 } 891 }
1010 GNUNET_STATISTICS_update (stats, 892 GNUNET_STATISTICS_update (stats,
1011 gettext_noop ("# DNS replies dropped (too late?)"), 893 gettext_noop ("# DNS replies dropped (too late?)"),
1012 1, GNUNET_NO); 894 1, GNUNET_NO);
1013 return GNUNET_OK;
1014} 895}
1015 896
1016 897
@@ -1031,15 +912,7 @@ abort_all_requests (struct CadetExit *exit)
1031 rc); 912 rc);
1032 GNUNET_DNS_request_drop (rc->rh); 913 GNUNET_DNS_request_drop (rc->rh);
1033 GNUNET_SCHEDULER_cancel (rc->timeout_task); 914 GNUNET_SCHEDULER_cancel (rc->timeout_task);
1034 GNUNET_free (rc); 915 GNUNET_MQ_discard (rc->env);
1035 }
1036 while (NULL != (rc = exit->transmit_queue_head))
1037 {
1038 GNUNET_CONTAINER_DLL_remove (exit->transmit_queue_head,
1039 exit->transmit_queue_tail,
1040 rc);
1041 GNUNET_DNS_request_drop (rc->rh);
1042 GNUNET_SCHEDULER_cancel (rc->timeout_task);
1043 GNUNET_free (rc); 916 GNUNET_free (rc);
1044 } 917 }
1045} 918}
@@ -1067,11 +940,6 @@ cleanup (void *cls)
1067 GNUNET_CONTAINER_DLL_remove (exit_head, 940 GNUNET_CONTAINER_DLL_remove (exit_head,
1068 exit_tail, 941 exit_tail,
1069 exit); 942 exit);
1070 if (NULL != exit->cadet_th)
1071 {
1072 GNUNET_CADET_notify_transmit_ready_cancel (exit->cadet_th);
1073 exit->cadet_th = NULL;
1074 }
1075 if (NULL != exit->cadet_channel) 943 if (NULL != exit->cadet_channel)
1076 { 944 {
1077 GNUNET_CADET_channel_destroy (exit->cadet_channel); 945 GNUNET_CADET_channel_destroy (exit->cadet_channel);
@@ -1126,63 +994,120 @@ cleanup (void *cls)
1126 */ 994 */
1127static void 995static void
1128cadet_channel_end_cb (void *cls, 996cadet_channel_end_cb (void *cls,
1129 const struct GNUNET_CADET_Channel *channel, 997 const struct GNUNET_CADET_Channel *channel)
1130 void *channel_ctx)
1131{ 998{
1132 struct CadetExit *exit = channel_ctx; 999 struct CadetExit *exit = cls;
1133 struct CadetExit *alt; 1000 struct CadetExit *alt;
1134 struct RequestContext *rc; 1001 struct RequestContext *rc;
1135 1002
1136 if (NULL != exit->cadet_th)
1137 {
1138 GNUNET_CADET_notify_transmit_ready_cancel (exit->cadet_th);
1139 exit->cadet_th = NULL;
1140 }
1141 exit->cadet_channel = NULL; 1003 exit->cadet_channel = NULL;
1142 dns_exit_available--; 1004 dns_exit_available--;
1143 /* open alternative channels */ 1005 /* open alternative channels */
1144 try_open_exit (); 1006 /* our channel is now closed, move our requests to an alternative
1145 if (NULL == exit->cadet_channel) 1007 channel */
1008 alt = choose_exit ();
1009 while (NULL != (rc = exit->receive_queue_head))
1146 { 1010 {
1147 /* our channel is now closed, move our requests to an alternative 1011 GNUNET_CONTAINER_DLL_remove (exit->receive_queue_head,
1148 channel */ 1012 exit->receive_queue_tail,
1149 alt = choose_exit (); 1013 rc);
1150 while (NULL != (rc = exit->transmit_queue_head)) 1014 rc->exit = alt;
1151 { 1015 GNUNET_CONTAINER_DLL_insert (alt->receive_queue_head,
1152 GNUNET_CONTAINER_DLL_remove (exit->transmit_queue_head, 1016 alt->receive_queue_tail,
1153 exit->transmit_queue_tail, 1017 rc);
1154 rc); 1018 GNUNET_MQ_send (GNUNET_CADET_get_mq (alt->cadet_channel),
1155 rc->exit = alt; 1019 GNUNET_MQ_env_copy (rc->env));
1156 GNUNET_CONTAINER_DLL_insert (alt->transmit_queue_head,
1157 alt->transmit_queue_tail,
1158 rc);
1159 }
1160 while (NULL != (rc = exit->receive_queue_head))
1161 {
1162 GNUNET_CONTAINER_DLL_remove (exit->receive_queue_head,
1163 exit->receive_queue_tail,
1164 rc);
1165 rc->was_transmitted = GNUNET_NO;
1166 rc->exit = alt;
1167 GNUNET_CONTAINER_DLL_insert (alt->transmit_queue_head,
1168 alt->transmit_queue_tail,
1169 rc);
1170 }
1171 } 1020 }
1172 else 1021 try_open_exit ();
1022}
1023
1024
1025/**
1026 * Function called whenever a channel has excess capacity.
1027 *
1028 * @param cls the `struct CadetExit`
1029 * @param channel connection to the other end
1030 * @param window_size how much capacity do we have
1031 */
1032static void
1033channel_idle_notify_cb (void *cls,
1034 const struct GNUNET_CADET_Channel *channel,
1035 int window_size)
1036{
1037 struct CadetExit *pos = cls;
1038
1039 pos->idle = window_size;
1040}
1041
1042
1043/**
1044 * We are short on cadet exits, try to open another one.
1045 */
1046static void
1047try_open_exit ()
1048{
1049 struct CadetExit *pos;
1050 uint32_t candidate_count;
1051 uint32_t candidate_selected;
1052 struct GNUNET_HashCode port;
1053
1054 GNUNET_CRYPTO_hash (GNUNET_APPLICATION_PORT_INTERNET_RESOLVER,
1055 strlen (GNUNET_APPLICATION_PORT_INTERNET_RESOLVER),
1056 &port);
1057 candidate_count = 0;
1058 for (pos = exit_head; NULL != pos; pos = pos->next)
1059 if (NULL == pos->cadet_channel)
1060 candidate_count++;
1061 if (0 == candidate_count)
1173 { 1062 {
1174 /* the same peer was chosen, just make sure the queue processing is restarted */ 1063 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1175 alt = exit; 1064 "No DNS exits available yet.\n");
1065 return;
1176 } 1066 }
1177 if ( (NULL == alt->cadet_th) && 1067 candidate_selected = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
1178 (NULL != (rc = alt->transmit_queue_head)) ) 1068 candidate_count);
1179 alt->cadet_th 1069 candidate_count = 0;
1180 = GNUNET_CADET_notify_transmit_ready (alt->cadet_channel, 1070 for (pos = exit_head; NULL != pos; pos = pos->next)
1181 GNUNET_NO, 1071 if (NULL == pos->cadet_channel)
1182 TIMEOUT, 1072 {
1183 rc->mlen, 1073 candidate_count++;
1184 &transmit_dns_request_to_cadet, 1074 if (candidate_selected < candidate_count)
1185 alt); 1075 {
1076 struct GNUNET_MQ_MessageHandler cadet_handlers[] = {
1077 GNUNET_MQ_hd_var_size (dns_response,
1078 GNUNET_MESSAGE_TYPE_VPN_DNS_FROM_INTERNET,
1079 struct DnsResponseMessage,
1080 pos),
1081 GNUNET_MQ_handler_end ()
1082 };
1083
1084
1085 /* move to the head of the DLL */
1086 pos->cadet_channel
1087 = GNUNET_CADET_channel_create (cadet_handle,
1088 pos,
1089 &pos->peer,
1090 &port,
1091 GNUNET_CADET_OPTION_DEFAULT,
1092 &channel_idle_notify_cb,
1093 &cadet_channel_end_cb,
1094 cadet_handlers);
1095 if (NULL == pos->cadet_channel)
1096 {
1097 GNUNET_break (0);
1098 continue;
1099 }
1100 GNUNET_CONTAINER_DLL_remove (exit_head,
1101 exit_tail,
1102 pos);
1103 GNUNET_CONTAINER_DLL_insert (exit_head,
1104 exit_tail,
1105 pos);
1106 dns_exit_available++;
1107 return;
1108 }
1109 }
1110 GNUNET_assert (NULL == exit_head);
1186} 1111}
1187 1112
1188 1113
@@ -1308,11 +1233,6 @@ run (void *cls, char *const *args GNUNET_UNUSED,
1308 } 1233 }
1309 if (dns_channel) 1234 if (dns_channel)
1310 { 1235 {
1311 static struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
1312 {&receive_dns_response, GNUNET_MESSAGE_TYPE_VPN_DNS_FROM_INTERNET, 0},
1313 {NULL, 0, 0}
1314 };
1315
1316 dns_pre_handle 1236 dns_pre_handle
1317 = GNUNET_DNS_connect (cfg, 1237 = GNUNET_DNS_connect (cfg,
1318 GNUNET_DNS_FLAG_PRE_RESOLUTION, 1238 GNUNET_DNS_FLAG_PRE_RESOLUTION,
@@ -1326,10 +1246,7 @@ run (void *cls, char *const *args GNUNET_UNUSED,
1326 GNUNET_SCHEDULER_shutdown (); 1246 GNUNET_SCHEDULER_shutdown ();
1327 return; 1247 return;
1328 } 1248 }
1329 cadet_handle = GNUNET_CADET_connect (cfg, 1249 cadet_handle = GNUNET_CADET_connect (cfg);
1330 NULL,
1331 &cadet_channel_end_cb,
1332 cadet_handlers);
1333 if (NULL == cadet_handle) 1250 if (NULL == cadet_handle)
1334 { 1251 {
1335 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1252 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
diff --git a/src/pt/test_gns_vpn.c b/src/pt/test_gns_vpn.c
index 4b7e817e8..53f27610b 100644
--- a/src/pt/test_gns_vpn.c
+++ b/src/pt/test_gns_vpn.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet 2 This file is part of GNUnet
3 Copyright (C) 2007, 2009, 2011, 2012, 2015 Christian Grothoff 3 Copyright (C) 2007, 2009, 2011, 2012, 2015, 2017 Christian Grothoff
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,6 +22,19 @@
22 * @file test_gns_vpn.c 22 * @file test_gns_vpn.c
23 * @brief testcase for accessing VPN services via GNS 23 * @brief testcase for accessing VPN services via GNS
24 * @author Martin Schanzenbach 24 * @author Martin Schanzenbach
25 * @author Christian Grothoff
26 *
27 * This test requires libcurl/libgnurl *with* support for C-ARES.
28 * This is NOT the default on most platforms, which means the test
29 * will be skipped in many cases. Compile libcurl/libgnurl with
30 * "--enable-ares" to get this test to pass.
31 *
32 * Furthermore, the test relies on gnunet-dns2gns being able to bind
33 * to port 53. This means that 'setcap' has to have worked during
34 * 'make install'. If this failed, but everything else is OK, the
35 * test may FAIL hard even though it is just an installation issue (we
36 * cannot conveniently test for the setcap to have worked). However,
37 * you should get a warning that gnunet-dns2gns failed to 'bind'.
25 */ 38 */
26#include "platform.h" 39#include "platform.h"
27#if HAVE_CURL_CURL_H 40#if HAVE_CURL_CURL_H
@@ -39,7 +52,7 @@
39#define PORT 8080 52#define PORT 8080
40#define TEST_DOMAIN "www.gnu" 53#define TEST_DOMAIN "www.gnu"
41 54
42#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) 55#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
43 56
44/** 57/**
45 * Return value for #main(). 58 * Return value for #main().
@@ -96,7 +109,10 @@ static struct CBC cbc;
96 109
97 110
98static size_t 111static size_t
99copy_buffer (void *ptr, size_t size, size_t nmemb, void *ctx) 112copy_buffer (void *ptr,
113 size_t size,
114 size_t nmemb,
115 void *ctx)
100{ 116{
101 struct CBC *cbc = ctx; 117 struct CBC *cbc = ctx;
102 118
@@ -174,6 +190,11 @@ do_shutdown (void *cls)
174 GNUNET_NAMESTORE_cancel (qe); 190 GNUNET_NAMESTORE_cancel (qe);
175 qe = NULL; 191 qe = NULL;
176 } 192 }
193 if (NULL != namestore)
194 {
195 GNUNET_NAMESTORE_disconnect (namestore);
196 namestore = NULL;
197 }
177 GNUNET_free_non_null (url); 198 GNUNET_free_non_null (url);
178 url = NULL; 199 url = NULL;
179} 200}
@@ -280,6 +301,9 @@ curl_main ()
280static void 301static void
281start_curl (void *cls) 302start_curl (void *cls)
282{ 303{
304 CURLcode ec;
305
306 curl_task_id = NULL;
283 GNUNET_asprintf (&url, 307 GNUNET_asprintf (&url,
284 "http://%s/hello_world", 308 "http://%s/hello_world",
285 TEST_DOMAIN); 309 TEST_DOMAIN);
@@ -291,7 +315,18 @@ start_curl (void *cls)
291 curl_easy_setopt (curl, CURLOPT_TIMEOUT, 150L); 315 curl_easy_setopt (curl, CURLOPT_TIMEOUT, 150L);
292 curl_easy_setopt (curl, CURLOPT_CONNECTTIMEOUT, 150L); 316 curl_easy_setopt (curl, CURLOPT_CONNECTTIMEOUT, 150L);
293 curl_easy_setopt (curl, CURLOPT_NOSIGNAL, 1); 317 curl_easy_setopt (curl, CURLOPT_NOSIGNAL, 1);
294 318 if (CURLE_OK !=
319 (ec = curl_easy_setopt (curl,
320 CURLOPT_DNS_SERVERS,
321 "127.0.0.1:53")))
322 {
323 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
324 "curl build without support for CURLOPT_DNS_SERVERS (%s), cannot run test\n",
325 curl_easy_strerror (ec));
326 global_ret = 77;
327 GNUNET_SCHEDULER_shutdown ();
328 return;
329 }
295 multi = curl_multi_init (); 330 multi = curl_multi_init ();
296 GNUNET_assert (multi != NULL); 331 GNUNET_assert (multi != NULL);
297 GNUNET_assert (CURLM_OK == curl_multi_add_handle (multi, curl)); 332 GNUNET_assert (CURLM_OK == curl_multi_add_handle (multi, curl));
@@ -302,14 +337,6 @@ start_curl (void *cls)
302} 337}
303 338
304 339
305static void
306disco_ns (void* cls)
307{
308 GNUNET_NAMESTORE_disconnect (namestore);
309 namestore = NULL;
310}
311
312
313/** 340/**
314 * Callback invoked from the namestore service once record is 341 * Callback invoked from the namestore service once record is
315 * created. 342 * created.
@@ -328,9 +355,8 @@ commence_testing (void *cls,
328 const char *emsg) 355 const char *emsg)
329{ 356{
330 qe = NULL; 357 qe = NULL;
331 GNUNET_SCHEDULER_add_now (&disco_ns, NULL); 358 if ( (NULL != emsg) &&
332 359 (GNUNET_YES != success) )
333 if ((emsg != NULL) && (GNUNET_YES != success))
334 { 360 {
335 fprintf (stderr, 361 fprintf (stderr,
336 "NS failed to create record %s\n", 362 "NS failed to create record %s\n",
@@ -338,11 +364,14 @@ commence_testing (void *cls,
338 GNUNET_SCHEDULER_shutdown (); 364 GNUNET_SCHEDULER_shutdown ();
339 return; 365 return;
340 } 366 }
367
341 /* wait a little bit before downloading, as we just created the record */ 368 /* wait a little bit before downloading, as we just created the record */
342 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply 369 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
343 (GNUNET_TIME_UNIT_SECONDS, 1), 370 "Launching cURL request\n");
344 &start_curl, 371 curl_task_id
345 NULL); 372 = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
373 &start_curl,
374 NULL);
346} 375}
347 376
348 377
@@ -402,7 +431,6 @@ mhd_main ()
402 431
403 432
404 433
405
406/** 434/**
407 * Open '/dev/null' and make the result the given 435 * Open '/dev/null' and make the result the given
408 * file descriptor. 436 * file descriptor.
@@ -448,9 +476,8 @@ fork_and_exec (const char *file,
448 pid = fork (); 476 pid = fork ();
449 if (-1 == pid) 477 if (-1 == pid)
450 { 478 {
451 fprintf (stderr, 479 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
452 "fork failed: %s\n", 480 "fork");
453 strerror (errno));
454 return 1; 481 return 1;
455 } 482 }
456 if (0 == pid) 483 if (0 == pid)
@@ -464,10 +491,9 @@ fork_and_exec (const char *file,
464 open_dev_null (1, O_WRONLY); 491 open_dev_null (1, O_WRONLY);
465 (void) execv (file, cmd); 492 (void) execv (file, cmd);
466 /* can only get here on error */ 493 /* can only get here on error */
467 fprintf (stderr, 494 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
468 "exec `%s' failed: %s\n", 495 "exec",
469 file, 496 file);
470 strerror (errno));
471 _exit (1); 497 _exit (1);
472 } 498 }
473 /* keep running waitpid as long as the only error we get is 'EINTR' */ 499 /* keep running waitpid as long as the only error we get is 'EINTR' */
@@ -475,13 +501,20 @@ fork_and_exec (const char *file,
475 (errno == EINTR) ); 501 (errno == EINTR) );
476 if (-1 == ret) 502 if (-1 == ret)
477 { 503 {
478 fprintf (stderr, 504 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
479 "waitpid failed: %s\n", 505 "waitpid");
480 strerror (errno));
481 return 1; 506 return 1;
482 } 507 }
483 if (! (WIFEXITED (status) && (0 == WEXITSTATUS (status)))) 508 if (! (WIFEXITED (status) &&
509 (0 == WEXITSTATUS (status))) )
510 {
511 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
512 "Process `%s` returned status code %d/%d.\n",
513 file,
514 WIFEXITED (status),
515 WEXITSTATUS (status));
484 return 1; 516 return 1;
517 }
485 /* child process completed and returned success, we're happy */ 518 /* child process completed and returned success, we're happy */
486 return 0; 519 return 0;
487} 520}
@@ -572,6 +605,8 @@ identity_cb (void *cls,
572 &rd.data_size)); 605 &rd.data_size));
573 rd.record_type = GNUNET_GNSRECORD_TYPE_VPN; 606 rd.record_type = GNUNET_GNSRECORD_TYPE_VPN;
574 607
608 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
609 "Creating `www` record\n");
575 qe = GNUNET_NAMESTORE_records_store (namestore, 610 qe = GNUNET_NAMESTORE_records_store (namestore,
576 zone_key, 611 zone_key,
577 "www", 612 "www",
@@ -593,15 +628,18 @@ run (void *cls,
593 char *bin; 628 char *bin;
594 char *bin_identity; 629 char *bin_identity;
595 char *bin_gns; 630 char *bin_gns;
631 char *bin_arm;
596 char *config; 632 char *config;
597 633
634 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
635 "Test logic starting...\n");
598 if (GNUNET_OK != 636 if (GNUNET_OK !=
599 GNUNET_CONFIGURATION_get_value_string (cfg, 637 GNUNET_CONFIGURATION_get_value_string (cfg,
600 "arm", 638 "arm",
601 "CONFIG", 639 "CONFIG",
602 &config)) 640 &config))
603 { 641 {
604 fprintf (stderr, 642 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
605 "Failed to locate configuration file. Skipping test.\n"); 643 "Failed to locate configuration file. Skipping test.\n");
606 GNUNET_SCHEDULER_shutdown (); 644 GNUNET_SCHEDULER_shutdown ();
607 return; 645 return;
@@ -626,18 +664,27 @@ run (void *cls,
626 { 664 {
627 "gnunet-identity", 665 "gnunet-identity",
628 "-e", "master-zone", 666 "-e", "master-zone",
629 "-s", "gns-intercept", 667 "-s", "dns2gns",
668 "-c", config,
669 NULL
670 };
671 char *const arm_args[] =
672 {
673 "gnunet-arm",
674 "-i", "dns2gns",
630 "-c", config, 675 "-c", config,
631 NULL 676 NULL
632 }; 677 };
633 char *const gns_args[] = 678 char *const gns_args[] =
634 { 679 {
635 "gnunet-gns", 680 "gnunet-gns",
636 "-u", "www.gns", 681 "-u", "www.gnu",
637 "-c", config, 682 "-c", config,
638 NULL 683 NULL
639 }; 684 };
640 GNUNET_TESTING_peer_get_identity (peer, &id); 685
686 GNUNET_TESTING_peer_get_identity (peer,
687 &id);
641 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, 688 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
642 NULL); 689 NULL);
643 timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, 690 timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
@@ -648,20 +695,24 @@ run (void *cls,
648 "%s/%s", 695 "%s/%s",
649 bin, 696 bin,
650 "gnunet-identity"); 697 "gnunet-identity");
698 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
699 "Creating `master-zone` ego\n");
651 if (0 != fork_and_exec (bin_identity, identity_args)) 700 if (0 != fork_and_exec (bin_identity, identity_args))
652 { 701 {
653 fprintf (stderr, 702 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
654 "Failed to run `gnunet-identity -C. Skipping test.\n"); 703 "Failed to run `gnunet-identity -C`. Skipping test.\n");
655 GNUNET_SCHEDULER_shutdown (); 704 GNUNET_SCHEDULER_shutdown ();
656 GNUNET_free (bin_identity); 705 GNUNET_free (bin_identity);
657 GNUNET_free (config); 706 GNUNET_free (config);
658 GNUNET_free (bin); 707 GNUNET_free (bin);
659 return; 708 return;
660 } 709 }
710 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
711 "Setting `master-zone` ego as default for `gns-master` and `dns2gns`\n");
661 if (0 != fork_and_exec (bin_identity, identity2_args)) 712 if (0 != fork_and_exec (bin_identity, identity2_args))
662 { 713 {
663 fprintf (stderr, 714 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
664 "Failed to run `gnunet-identity -e. Skipping test.\n"); 715 "Failed to run `gnunet-identity -e`. Skipping test.\n");
665 GNUNET_SCHEDULER_shutdown (); 716 GNUNET_SCHEDULER_shutdown ();
666 GNUNET_free (bin_identity); 717 GNUNET_free (bin_identity);
667 GNUNET_free (config); 718 GNUNET_free (config);
@@ -670,8 +721,8 @@ run (void *cls,
670 } 721 }
671 if (0 != fork_and_exec (bin_identity, identity3_args)) 722 if (0 != fork_and_exec (bin_identity, identity3_args))
672 { 723 {
673 fprintf (stderr, 724 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
674 "Failed to run `gnunet-identity -e. Skipping test.\n"); 725 "Failed to run `gnunet-identity -e`. Skipping test.\n");
675 GNUNET_SCHEDULER_shutdown (); 726 GNUNET_SCHEDULER_shutdown ();
676 GNUNET_free (bin_identity); 727 GNUNET_free (bin_identity);
677 GNUNET_free (config); 728 GNUNET_free (config);
@@ -681,14 +732,17 @@ run (void *cls,
681 GNUNET_free (bin_identity); 732 GNUNET_free (bin_identity);
682 733
683 /* do lookup just to launch GNS service */ 734 /* do lookup just to launch GNS service */
735 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
736 "Resolving `www.gnu` zone entry to launch GNS (will yield no answer yet)\n");
684 GNUNET_asprintf (&bin_gns, 737 GNUNET_asprintf (&bin_gns,
685 "%s/%s", 738 "%s/%s",
686 bin, 739 bin,
687 "gnunet-gns"); 740 "gnunet-gns");
688 if (0 != fork_and_exec (bin_gns, gns_args)) 741 if (0 != fork_and_exec (bin_gns,
742 gns_args))
689 { 743 {
690 fprintf (stderr, 744 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
691 "Failed to run `gnunet-gns -u. Skipping test.\n"); 745 "Failed to run `gnunet-gns -u. Skipping test.\n");
692 GNUNET_SCHEDULER_shutdown (); 746 GNUNET_SCHEDULER_shutdown ();
693 GNUNET_free (bin_gns); 747 GNUNET_free (bin_gns);
694 GNUNET_free (config); 748 GNUNET_free (config);
@@ -696,9 +750,27 @@ run (void *cls,
696 return; 750 return;
697 } 751 }
698 GNUNET_free (bin_gns); 752 GNUNET_free (bin_gns);
753
754 GNUNET_asprintf (&bin_arm,
755 "%s/%s",
756 bin,
757 "gnunet-arm");
758 if (0 != fork_and_exec (bin_arm,
759 arm_args))
760 {
761 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
762 "Failed to run `gnunet-arm -i dns2gns. Skipping test.\n");
763 GNUNET_SCHEDULER_shutdown ();
764 GNUNET_free (bin_arm);
765 GNUNET_free (config);
766 GNUNET_free (bin);
767 return;
768 }
769 GNUNET_free (bin_arm);
770
699 GNUNET_free (config); 771 GNUNET_free (config);
700 GNUNET_free (bin); 772 GNUNET_free (bin);
701 773 sleep (1); /* give dns2gns chance to really run */
702 774
703 namestore = GNUNET_NAMESTORE_connect (cfg); 775 namestore = GNUNET_NAMESTORE_connect (cfg);
704 GNUNET_assert (NULL != namestore); 776 GNUNET_assert (NULL != namestore);
@@ -720,39 +792,15 @@ run (void *cls,
720 792
721 793
722int 794int
723main (int argc, char *const *argv) 795main (int argc,
796 char *const *argv)
724{ 797{
725 char *sbin_iptables;
726 char *bin_vpn; 798 char *bin_vpn;
727 char *bin_exit; 799 char *bin_exit;
728 char *bin_dns;
729 char *srv_dns;
730 struct stat s;
731 gid_t my_gid;
732 char *const iptables_args[] =
733 {
734 "iptables", "-t", "mangle", "-L", "-v", NULL
735 };
736
737 if (0 == access ("/sbin/iptables", X_OK))
738 sbin_iptables = "/sbin/iptables";
739 else if (0 == access ("/usr/sbin/iptables", X_OK))
740 sbin_iptables = "/usr/sbin/iptables";
741 else
742 {
743 fprintf (stderr,
744 "Executable iptables not found in approved directories: %s, skipping\n",
745 strerror (errno));
746 return 77;
747 }
748
749 if (0 != fork_and_exec (sbin_iptables, iptables_args))
750 {
751 fprintf (stderr,
752 "Failed to run `iptables -t mangle -L -v'. Skipping test.\n");
753 return 77;
754 }
755 800
801 GNUNET_log_setup ("test-gns-vpn",
802 "WARNING",
803 NULL);
756 if (0 != ACCESS ("/dev/net/tun", R_OK)) 804 if (0 != ACCESS ("/dev/net/tun", R_OK))
757 { 805 {
758 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, 806 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
@@ -765,59 +813,26 @@ main (int argc, char *const *argv)
765 813
766 bin_vpn = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-vpn"); 814 bin_vpn = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-vpn");
767 bin_exit = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-exit"); 815 bin_exit = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-exit");
768 bin_dns = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-dns");
769 srv_dns = GNUNET_OS_get_libexec_binary_path ("gnunet-service-dns");
770 if ( (0 != geteuid ()) && 816 if ( (0 != geteuid ()) &&
771 ( (GNUNET_YES != 817 ( (GNUNET_YES !=
772 GNUNET_OS_check_helper_binary (bin_vpn, GNUNET_YES, "-d gnunet-vpn - - 169.1.3.3.7 255.255.255.0")) || //ipv4 only please! 818 GNUNET_OS_check_helper_binary (bin_vpn,
819 GNUNET_YES,
820 "-d gnunet-vpn - - 169.1.3.3.7 255.255.255.0")) || //ipv4 only please!
773 (GNUNET_YES != 821 (GNUNET_YES !=
774 GNUNET_OS_check_helper_binary (bin_exit, GNUNET_YES, "-d gnunet-vpn - - - 169.1.3.3.7 255.255.255.0")) || //no nat, ipv4 only 822 GNUNET_OS_check_helper_binary (bin_exit,
775 (GNUNET_YES != 823 GNUNET_YES,
776 GNUNET_OS_check_helper_binary (bin_dns, GNUNET_YES, NULL))) ) // TODO: once we have a windows-testcase, add test parameters here 824 "-d gnunet-vpn - - - 169.1.3.3.7 255.255.255.0")) ) ) //no nat, ipv4 only
777 { 825 {
778 fprintf (stderr, 826 fprintf (stderr,
779 "WARNING: gnunet-helper-{exit,vpn,dns} binaries in $PATH are not SUID, refusing to run test (as it would have to fail).\n"); 827 "WARNING: gnunet-helper-{exit,vpn} binaries in $PATH are not SUID, refusing to run test (as it would have to fail).\n");
780 fprintf (stderr, 828 fprintf (stderr,
781 "Change $PATH ('.' in $PATH before $GNUNET_PREFIX/bin is problematic) or permissions (run 'make install' as root) to fix this!\n"); 829 "Change $PATH ('.' in $PATH before $GNUNET_PREFIX/bin is problematic) or permissions (run 'make install' as root) to fix this!\n");
782 GNUNET_free (bin_vpn); 830 GNUNET_free (bin_vpn);
783 GNUNET_free (bin_exit); 831 GNUNET_free (bin_exit);
784 GNUNET_free (bin_dns);
785 GNUNET_free (srv_dns);
786 return 77; 832 return 77;
787 } 833 }
788 GNUNET_free (bin_vpn); 834 GNUNET_free (bin_vpn);
789 GNUNET_free (bin_exit); 835 GNUNET_free (bin_exit);
790 my_gid = getgid ();
791 if ( (0 != stat (bin_dns, &s)) ||
792 (my_gid == s.st_gid) ||
793 ( (0 == (S_ISUID & s.st_mode)) && (0 != getuid()) ) )
794 {
795 fprintf (stderr,
796 "WARNING: %s has wrong permissions (%d, %d, %d), refusing to run test (as it would have to fail).\n",
797 bin_dns,
798 (0 != stat (bin_dns, &s)),
799 (my_gid == s.st_gid),
800 (0 == (S_ISUID & s.st_mode)) || (0 != getuid()) );
801 GNUNET_free (bin_dns);
802 GNUNET_free (srv_dns);
803 return 77;
804 }
805 if ( (0 != stat (srv_dns, &s)) ||
806 (my_gid == s.st_gid) ||
807 (0 == (S_ISGID & s.st_mode)) )
808 {
809 fprintf (stderr,
810 "WARNING: %s has wrong permissions (%d, %d, %d), refusing to run test (as it would have to fail).\n",
811 srv_dns,
812 (0 != stat (bin_dns, &s)),
813 (my_gid == s.st_gid),
814 (0 == (S_ISGID & s.st_mode)) );
815 GNUNET_free (bin_dns);
816 GNUNET_free (srv_dns);
817 return 77;
818 }
819 GNUNET_free (bin_dns);
820 GNUNET_free (srv_dns);
821 836
822 dest_ip = "169.254.86.1"; 837 dest_ip = "169.254.86.1";
823 dest_af = AF_INET; 838 dest_af = AF_INET;
@@ -842,9 +857,11 @@ main (int argc, char *const *argv)
842 } 857 }
843 858
844 859
845 if (0 != GNUNET_TESTING_peer_run ("test-gnunet-vpn", 860 if (0 !=
846 "test_gns_vpn.conf", 861 GNUNET_TESTING_peer_run ("test_gns_vpn",
847 &run, NULL)) 862 "test_gns_vpn.conf",
863 &run,
864 NULL))
848 return 1; 865 return 1;
849 GNUNET_DISK_directory_remove ("/tmp/gnunet-test-vpn"); 866 GNUNET_DISK_directory_remove ("/tmp/gnunet-test-vpn");
850 return global_ret; 867 return global_ret;
diff --git a/src/pt/test_gns_vpn.conf b/src/pt/test_gns_vpn.conf
index ac9724c04..86642465f 100644
--- a/src/pt/test_gns_vpn.conf
+++ b/src/pt/test_gns_vpn.conf
@@ -35,6 +35,10 @@ FORCESTART = YES
35AUTOSTART = NO 35AUTOSTART = NO
36FORCESTART = NO 36FORCESTART = NO
37 37
38[zonemaster]
39AUTOSTART = YES
40FORCESTART = YES
41
38#[vpn] 42#[vpn]
39#PREFIX = valgrind 43#PREFIX = valgrind
40 44
diff --git a/src/regex/Makefile.am b/src/regex/Makefile.am
index 7f0fb707f..80997db40 100644
--- a/src/regex/Makefile.am
+++ b/src/regex/Makefile.am
@@ -80,6 +80,7 @@ libgnunet_plugin_block_regex_la_SOURCES = \
80libgnunet_plugin_block_regex_la_LIBADD = \ 80libgnunet_plugin_block_regex_la_LIBADD = \
81 libgnunetregexblock.la \ 81 libgnunetregexblock.la \
82 $(top_builddir)/src/block/libgnunetblock.la \ 82 $(top_builddir)/src/block/libgnunetblock.la \
83 $(top_builddir)/src/block/libgnunetblockgroup.la \
83 $(top_builddir)/src/util/libgnunetutil.la 84 $(top_builddir)/src/util/libgnunetutil.la
84libgnunet_plugin_block_regex_la_LDFLAGS = \ 85libgnunet_plugin_block_regex_la_LDFLAGS = \
85 $(GN_PLUGIN_LDFLAGS) 86 $(GN_PLUGIN_LDFLAGS)
@@ -152,7 +153,7 @@ check_PROGRAMS = \
152 test_regex_api 153 test_regex_api
153 154
154if ENABLE_TEST_RUN 155if ENABLE_TEST_RUN
155 AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; 156 AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
156 TESTS = $(check_PROGRAMS) 157 TESTS = $(check_PROGRAMS)
157endif 158endif
158 159
diff --git a/src/regex/gnunet-regex-profiler.c b/src/regex/gnunet-regex-profiler.c
index dfbcd388a..7d907fec6 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_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..67c2ecfff 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_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/plugin_block_regex.c b/src/regex/plugin_block_regex.c
index 36926c25d..287ecf905 100644
--- a/src/regex/plugin_block_regex.c
+++ b/src/regex/plugin_block_regex.c
@@ -23,16 +23,75 @@
23 * @brief blocks used for regex storage and search 23 * @brief blocks used for regex storage and search
24 * @author Bartlomiej Polot 24 * @author Bartlomiej Polot
25 */ 25 */
26
27#include "platform.h" 26#include "platform.h"
28#include "gnunet_block_plugin.h" 27#include "gnunet_block_plugin.h"
28#include "gnunet_block_group_lib.h"
29#include "block_regex.h" 29#include "block_regex.h"
30#include "regex_block_lib.h" 30#include "regex_block_lib.h"
31#include "gnunet_constants.h"
32#include "gnunet_signatures.h" 31#include "gnunet_signatures.h"
33 32
34 33
35/** 34/**
35 * Number of bits we set per entry in the bloomfilter.
36 * Do not change!
37 */
38#define BLOOMFILTER_K 16
39
40
41/**
42 * How big is the BF we use for REGEX blocks?
43 */
44#define REGEX_BF_SIZE 8
45
46
47/**
48 * Create a new block group.
49 *
50 * @param ctx block context in which the block group is created
51 * @param type type of the block for which we are creating the group
52 * @param nonce random value used to seed the group creation
53 * @param raw_data optional serialized prior state of the group, NULL if unavailable/fresh
54 * @param raw_data_size number of bytes in @a raw_data, 0 if unavailable/fresh
55 * @param va variable arguments specific to @a type
56 * @return block group handle, NULL if block groups are not supported
57 * by this @a type of block (this is not an error)
58 */
59static struct GNUNET_BLOCK_Group *
60block_plugin_regex_create_group (void *cls,
61 enum GNUNET_BLOCK_Type type,
62 uint32_t nonce,
63 const void *raw_data,
64 size_t raw_data_size,
65 va_list va)
66{
67 unsigned int bf_size;
68 const char *guard;
69
70 guard = va_arg (va, const char *);
71 if (0 == strcmp (guard,
72 "seen-set-size"))
73 bf_size = GNUNET_BLOCK_GROUP_compute_bloomfilter_size (va_arg (va, unsigned int),
74 BLOOMFILTER_K);
75 else if (0 == strcmp (guard,
76 "filter-size"))
77 bf_size = va_arg (va, unsigned int);
78 else
79 {
80 GNUNET_break (0);
81 bf_size = REGEX_BF_SIZE;
82 }
83 GNUNET_break (NULL == va_arg (va, const char *));
84 return GNUNET_BLOCK_GROUP_bf_create (cls,
85 bf_size,
86 BLOOMFILTER_K,
87 type,
88 nonce,
89 raw_data,
90 raw_data_size);
91}
92
93
94/**
36 * Function called to validate a reply or a request of type 95 * Function called to validate a reply or a request of type
37 * #GNUNET_BLOCK_TYPE_REGEX. 96 * #GNUNET_BLOCK_TYPE_REGEX.
38 * For request evaluation, pass "NULL" for the reply_block. 97 * For request evaluation, pass "NULL" for the reply_block.
@@ -42,10 +101,9 @@
42 * 101 *
43 * @param cls closure 102 * @param cls closure
44 * @param type block type 103 * @param type block type
104 * @param bg block group to evaluate against
45 * @param eo control flags 105 * @param eo control flags
46 * @param query original query (hash) 106 * @param query original query (hash)
47 * @param bf pointer to bloom filter associated with query; possibly updated (!)
48 * @param bf_mutator mutation value for bf
49 * @param xquery extrended query data (can be NULL, depending on type) 107 * @param xquery extrended query data (can be NULL, depending on type)
50 * @param xquery_size number of bytes in @a xquery 108 * @param xquery_size number of bytes in @a xquery
51 * @param reply_block response to validate 109 * @param reply_block response to validate
@@ -55,15 +113,16 @@
55static enum GNUNET_BLOCK_EvaluationResult 113static enum GNUNET_BLOCK_EvaluationResult
56evaluate_block_regex (void *cls, 114evaluate_block_regex (void *cls,
57 enum GNUNET_BLOCK_Type type, 115 enum GNUNET_BLOCK_Type type,
116 struct GNUNET_BLOCK_Group *bg,
58 enum GNUNET_BLOCK_EvaluationOptions eo, 117 enum GNUNET_BLOCK_EvaluationOptions eo,
59 const struct GNUNET_HashCode *query, 118 const struct GNUNET_HashCode *query,
60 struct GNUNET_CONTAINER_BloomFilter **bf,
61 int32_t bf_mutator,
62 const void *xquery, 119 const void *xquery,
63 size_t xquery_size, 120 size_t xquery_size,
64 const void *reply_block, 121 const void *reply_block,
65 size_t reply_block_size) 122 size_t reply_block_size)
66{ 123{
124 struct GNUNET_HashCode chash;
125
67 if (NULL == reply_block) 126 if (NULL == reply_block)
68 { 127 {
69 if (0 != xquery_size) 128 if (0 != xquery_size)
@@ -112,24 +171,13 @@ evaluate_block_regex (void *cls,
112 default: 171 default:
113 break; 172 break;
114 } 173 }
115 if (NULL != bf) 174 GNUNET_CRYPTO_hash (reply_block,
116 { 175 reply_block_size,
117 struct GNUNET_HashCode chash; 176 &chash);
118 struct GNUNET_HashCode mhash; 177 if (GNUNET_YES ==
119 178 GNUNET_BLOCK_GROUP_bf_test_and_set (bg,
120 GNUNET_CRYPTO_hash (reply_block, reply_block_size, &chash); 179 &chash))
121 GNUNET_BLOCK_mingle_hash (&chash, bf_mutator, &mhash); 180 return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
122 if (NULL != *bf)
123 {
124 if (GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test (*bf, &mhash))
125 return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
126 }
127 else
128 {
129 *bf = GNUNET_CONTAINER_bloomfilter_init (NULL, 8, GNUNET_CONSTANTS_BLOOMFILTER_K);
130 }
131 GNUNET_CONTAINER_bloomfilter_add (*bf, &mhash);
132 }
133 return GNUNET_BLOCK_EVALUATION_OK_MORE; 181 return GNUNET_BLOCK_EVALUATION_OK_MORE;
134} 182}
135 183
@@ -144,10 +192,9 @@ evaluate_block_regex (void *cls,
144 * 192 *
145 * @param cls closure 193 * @param cls closure
146 * @param type block type 194 * @param type block type
195 * @param bg block group to evaluate against
147 * @param eo control flags 196 * @param eo control flags
148 * @param query original query (hash) 197 * @param query original query (hash)
149 * @param bf pointer to bloom filter associated with query; possibly updated (!)
150 * @param bf_mutator mutation value for bf
151 * @param xquery extrended query data (can be NULL, depending on type) 198 * @param xquery extrended query data (can be NULL, depending on type)
152 * @param xquery_size number of bytes in @a xquery 199 * @param xquery_size number of bytes in @a xquery
153 * @param reply_block response to validate 200 * @param reply_block response to validate
@@ -157,14 +204,15 @@ evaluate_block_regex (void *cls,
157static enum GNUNET_BLOCK_EvaluationResult 204static enum GNUNET_BLOCK_EvaluationResult
158evaluate_block_regex_accept (void *cls, 205evaluate_block_regex_accept (void *cls,
159 enum GNUNET_BLOCK_Type type, 206 enum GNUNET_BLOCK_Type type,
207 struct GNUNET_BLOCK_Group *bg,
160 enum GNUNET_BLOCK_EvaluationOptions eo, 208 enum GNUNET_BLOCK_EvaluationOptions eo,
161 const struct GNUNET_HashCode * query, 209 const struct GNUNET_HashCode *query,
162 struct GNUNET_CONTAINER_BloomFilter **bf, 210 const void *xquery,
163 int32_t bf_mutator, const void *xquery,
164 size_t xquery_size, const void *reply_block, 211 size_t xquery_size, const void *reply_block,
165 size_t reply_block_size) 212 size_t reply_block_size)
166{ 213{
167 const struct RegexAcceptBlock *rba; 214 const struct RegexAcceptBlock *rba;
215 struct GNUNET_HashCode chash;
168 216
169 if (0 != xquery_size) 217 if (0 != xquery_size)
170 { 218 {
@@ -202,24 +250,13 @@ evaluate_block_regex_accept (void *cls,
202 GNUNET_break_op(0); 250 GNUNET_break_op(0);
203 return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; 251 return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
204 } 252 }
205 if (NULL != bf) 253 GNUNET_CRYPTO_hash (reply_block,
206 { 254 reply_block_size,
207 struct GNUNET_HashCode chash; 255 &chash);
208 struct GNUNET_HashCode mhash; 256 if (GNUNET_YES ==
209 257 GNUNET_BLOCK_GROUP_bf_test_and_set (bg,
210 GNUNET_CRYPTO_hash (reply_block, reply_block_size, &chash); 258 &chash))
211 GNUNET_BLOCK_mingle_hash (&chash, bf_mutator, &mhash); 259 return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
212 if (NULL != *bf)
213 {
214 if (GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test (*bf, &mhash))
215 return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
216 }
217 else
218 {
219 *bf = GNUNET_CONTAINER_bloomfilter_init (NULL, 8, GNUNET_CONSTANTS_BLOOMFILTER_K);
220 }
221 GNUNET_CONTAINER_bloomfilter_add (*bf, &mhash);
222 }
223 return GNUNET_BLOCK_EVALUATION_OK_MORE; 260 return GNUNET_BLOCK_EVALUATION_OK_MORE;
224} 261}
225 262
@@ -232,11 +269,11 @@ evaluate_block_regex_accept (void *cls,
232 * be done with the #GNUNET_BLOCK_get_key() function. 269 * be done with the #GNUNET_BLOCK_get_key() function.
233 * 270 *
234 * @param cls closure 271 * @param cls closure
272 * @param ctx block context
235 * @param type block type 273 * @param type block type
274 * @param bg group to evaluate against
236 * @param eo control flags 275 * @param eo control flags
237 * @param query original query (hash) 276 * @param query original query (hash)
238 * @param bf pointer to bloom filter associated with query; possibly updated (!)
239 * @param bf_mutator mutation value for bf
240 * @param xquery extrended query data (can be NULL, depending on type) 277 * @param xquery extrended query data (can be NULL, depending on type)
241 * @param xquery_size number of bytes in xquery 278 * @param xquery_size number of bytes in xquery
242 * @param reply_block response to validate 279 * @param reply_block response to validate
@@ -245,11 +282,11 @@ evaluate_block_regex_accept (void *cls,
245 */ 282 */
246static enum GNUNET_BLOCK_EvaluationResult 283static enum GNUNET_BLOCK_EvaluationResult
247block_plugin_regex_evaluate (void *cls, 284block_plugin_regex_evaluate (void *cls,
285 struct GNUNET_BLOCK_Context *ctx,
248 enum GNUNET_BLOCK_Type type, 286 enum GNUNET_BLOCK_Type type,
287 struct GNUNET_BLOCK_Group *bg,
249 enum GNUNET_BLOCK_EvaluationOptions eo, 288 enum GNUNET_BLOCK_EvaluationOptions eo,
250 const struct GNUNET_HashCode *query, 289 const struct GNUNET_HashCode *query,
251 struct GNUNET_CONTAINER_BloomFilter **bf,
252 int32_t bf_mutator,
253 const void *xquery, 290 const void *xquery,
254 size_t xquery_size, 291 size_t xquery_size,
255 const void *reply_block, 292 const void *reply_block,
@@ -262,18 +299,18 @@ block_plugin_regex_evaluate (void *cls,
262 case GNUNET_BLOCK_TYPE_REGEX: 299 case GNUNET_BLOCK_TYPE_REGEX:
263 result = evaluate_block_regex (cls, 300 result = evaluate_block_regex (cls,
264 type, 301 type,
302 bg,
265 eo, 303 eo,
266 query, 304 query,
267 bf, bf_mutator,
268 xquery, xquery_size, 305 xquery, xquery_size,
269 reply_block, reply_block_size); 306 reply_block, reply_block_size);
270 break; 307 break;
271 case GNUNET_BLOCK_TYPE_REGEX_ACCEPT: 308 case GNUNET_BLOCK_TYPE_REGEX_ACCEPT:
272 result = evaluate_block_regex_accept (cls, 309 result = evaluate_block_regex_accept (cls,
273 type, 310 type,
311 bg,
274 eo, 312 eo,
275 query, 313 query,
276 bf, bf_mutator,
277 xquery, xquery_size, 314 xquery, xquery_size,
278 reply_block, reply_block_size); 315 reply_block, reply_block_size);
279 break; 316 break;
@@ -346,6 +383,7 @@ libgnunet_plugin_block_regex_init (void *cls)
346 api = GNUNET_new (struct GNUNET_BLOCK_PluginFunctions); 383 api = GNUNET_new (struct GNUNET_BLOCK_PluginFunctions);
347 api->evaluate = &block_plugin_regex_evaluate; 384 api->evaluate = &block_plugin_regex_evaluate;
348 api->get_key = &block_plugin_regex_get_key; 385 api->get_key = &block_plugin_regex_get_key;
386 api->create_group = &block_plugin_regex_create_group;
349 api->types = types; 387 api->types = types;
350 return api; 388 return api;
351} 389}
@@ -357,7 +395,7 @@ libgnunet_plugin_block_regex_init (void *cls)
357void * 395void *
358libgnunet_plugin_block_regex_done (void *cls) 396libgnunet_plugin_block_regex_done (void *cls)
359{ 397{
360 struct GNUNET_TRANSPORT_PluginFunctions *api = cls; 398 struct GNUNET_BLOCK_PluginFunctions *api = cls;
361 399
362 GNUNET_free (api); 400 GNUNET_free (api);
363 return NULL; 401 return NULL;
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..5b92c6c43 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_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/.gitignore b/src/revocation/.gitignore
index dee463129..9acd3ac33 100644
--- a/src/revocation/.gitignore
+++ b/src/revocation/.gitignore
@@ -1,2 +1,4 @@
1gnunet-service-revocation 1gnunet-service-revocation
2gnunet-revocation 2gnunet-revocation
3test_revocation
4test_local_revocation.py
diff --git a/src/revocation/Makefile.am b/src/revocation/Makefile.am
index a681b2f33..82755b485 100644
--- a/src/revocation/Makefile.am
+++ b/src/revocation/Makefile.am
@@ -1,6 +1,8 @@
1# This Makefile.am is in the public domain 1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include 2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3 3
4plugindir = $(libdir)/gnunet
5
4if MINGW 6if MINGW
5 WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols 7 WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols
6endif 8endif
@@ -21,6 +23,20 @@ bin_PROGRAMS = \
21 gnunet-revocation 23 gnunet-revocation
22 24
23 25
26plugin_LTLIBRARIES = \
27 libgnunet_plugin_block_revocation.la
28
29libgnunet_plugin_block_revocation_la_SOURCES = \
30 plugin_block_revocation.c
31libgnunet_plugin_block_revocation_la_LIBADD = \
32 libgnunetrevocation.la \
33 $(top_builddir)/src/block/libgnunetblockgroup.la \
34 $(top_builddir)/src/util/libgnunetutil.la \
35 $(LTLIBINTL)
36libgnunet_plugin_block_revocation_la_LDFLAGS = \
37 $(GN_PLUGIN_LDFLAGS)
38
39
24gnunet_revocation_SOURCES = \ 40gnunet_revocation_SOURCES = \
25 gnunet-revocation.c 41 gnunet-revocation.c
26gnunet_revocation_LDADD = \ 42gnunet_revocation_LDADD = \
@@ -72,7 +88,7 @@ check_SCRIPTS = \
72 test_local_revocation.py 88 test_local_revocation.py
73 89
74if ENABLE_TEST_RUN 90if ENABLE_TEST_RUN
75 AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; 91 AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
76 TESTS = \ 92 TESTS = \
77 $(check_SCRIPTS) \ 93 $(check_SCRIPTS) \
78 $(check_PROGRAMS) 94 $(check_PROGRAMS)
@@ -86,4 +102,3 @@ test_local_revocation.py: test_local_revocation.py.in Makefile
86 102
87EXTRA_DIST = test_revocation.conf \ 103EXTRA_DIST = test_revocation.conf \
88 test_local_revocation.py.in 104 test_local_revocation.py.in
89
diff --git a/src/revocation/gnunet-revocation.c b/src/revocation/gnunet-revocation.c
index 133468789..13e6b23a5 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_flag ('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/gnunet-service-revocation.c b/src/revocation/gnunet-service-revocation.c
index 2965808fa..9d077f874 100644
--- a/src/revocation/gnunet-service-revocation.c
+++ b/src/revocation/gnunet-service-revocation.c
@@ -38,6 +38,7 @@
38#include "platform.h" 38#include "platform.h"
39#include <math.h> 39#include <math.h>
40#include "gnunet_util_lib.h" 40#include "gnunet_util_lib.h"
41#include "gnunet_block_lib.h"
41#include "gnunet_constants.h" 42#include "gnunet_constants.h"
42#include "gnunet_protocols.h" 43#include "gnunet_protocols.h"
43#include "gnunet_signatures.h" 44#include "gnunet_signatures.h"
@@ -215,7 +216,7 @@ client_connect_cb (void *cls,
215 * @param client the new client 216 * @param client the new client
216 * @param app_cls must alias @a client 217 * @param app_cls must alias @a client
217 */ 218 */
218static void 219static void
219client_disconnect_cb (void *cls, 220client_disconnect_cb (void *cls,
220 struct GNUNET_SERVICE_Client *client, 221 struct GNUNET_SERVICE_Client *client,
221 void *app_cls) 222 void *app_cls)
@@ -352,7 +353,7 @@ publicize_rm (const struct RevokeMessage *rm)
352 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); 353 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
353 /* add to set for future connections */ 354 /* add to set for future connections */
354 e.size = htons (rm->header.size); 355 e.size = htons (rm->header.size);
355 e.element_type = 0; 356 e.element_type = GNUNET_BLOCK_TYPE_REVOCATION;
356 e.data = rm; 357 e.data = rm;
357 if (GNUNET_OK != 358 if (GNUNET_OK !=
358 GNUNET_SET_add_element (revocation_set, 359 GNUNET_SET_add_element (revocation_set,
@@ -432,11 +433,13 @@ handle_p2p_revoke (void *cls,
432 * 433 *
433 * @param cls closure 434 * @param cls closure
434 * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK 435 * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
436 * @param current_size current set size
435 * @param status see `enum GNUNET_SET_Status` 437 * @param status see `enum GNUNET_SET_Status`
436 */ 438 */
437static void 439static void
438add_revocation (void *cls, 440add_revocation (void *cls,
439 const struct GNUNET_SET_Element *element, 441 const struct GNUNET_SET_Element *element,
442 uint64_t current_size,
440 enum GNUNET_SET_Status status) 443 enum GNUNET_SET_Status status)
441{ 444{
442 struct PeerEntry *peer_entry = cls; 445 struct PeerEntry *peer_entry = cls;
@@ -450,11 +453,12 @@ add_revocation (void *cls,
450 GNUNET_break_op (0); 453 GNUNET_break_op (0);
451 return; 454 return;
452 } 455 }
453 if (0 != element->element_type) 456 if (GNUNET_BLOCK_TYPE_REVOCATION != element->element_type)
454 { 457 {
455 GNUNET_STATISTICS_update (stats, 458 GNUNET_STATISTICS_update (stats,
456 gettext_noop ("# unsupported revocations received via set union"), 459 gettext_noop ("# unsupported revocations received via set union"),
457 1, GNUNET_NO); 460 1,
461 GNUNET_NO);
458 return; 462 return;
459 } 463 }
460 rm = element->data; 464 rm = element->data;
@@ -509,6 +513,7 @@ transmit_task_cb (void *cls)
509 &revocation_set_union_app_id, 513 &revocation_set_union_app_id,
510 NULL, 514 NULL,
511 GNUNET_SET_RESULT_ADDED, 515 GNUNET_SET_RESULT_ADDED,
516 (struct GNUNET_SET_Option[]) {{ 0 }},
512 &add_revocation, 517 &add_revocation,
513 peer_entry); 518 peer_entry);
514 if (GNUNET_OK != 519 if (GNUNET_OK !=
@@ -601,12 +606,12 @@ handle_core_disconnect (void *cls,
601 void *internal_cls) 606 void *internal_cls)
602{ 607{
603 struct PeerEntry *peer_entry = internal_cls; 608 struct PeerEntry *peer_entry = internal_cls;
604 609
605 if (0 == memcmp (peer, 610 if (0 == memcmp (peer,
606 &my_identity, 611 &my_identity,
607 sizeof (my_identity))) 612 sizeof (my_identity)))
608 return; 613 return;
609 GNUNET_assert (NULL != peer_entry); 614 GNUNET_assert (NULL != peer_entry);
610 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 615 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
611 "Peer `%s' disconnected from us\n", 616 "Peer `%s' disconnected from us\n",
612 GNUNET_i2s (peer)); 617 GNUNET_i2s (peer));
@@ -755,6 +760,7 @@ handle_revocation_union_request (void *cls,
755 } 760 }
756 peer_entry->so = GNUNET_SET_accept (request, 761 peer_entry->so = GNUNET_SET_accept (request,
757 GNUNET_SET_RESULT_ADDED, 762 GNUNET_SET_RESULT_ADDED,
763 (struct GNUNET_SET_Option[]) {{ 0 }},
758 &add_revocation, 764 &add_revocation,
759 peer_entry); 765 peer_entry);
760 if (GNUNET_OK != 766 if (GNUNET_OK !=
@@ -779,7 +785,7 @@ handle_revocation_union_request (void *cls,
779static void 785static void
780run (void *cls, 786run (void *cls,
781 const struct GNUNET_CONFIGURATION_Handle *c, 787 const struct GNUNET_CONFIGURATION_Handle *c,
782 struct GNUNET_SERVICE_Handle *service) 788 struct GNUNET_SERVICE_Handle *service)
783{ 789{
784 struct GNUNET_MQ_MessageHandler core_handlers[] = { 790 struct GNUNET_MQ_MessageHandler core_handlers[] = {
785 GNUNET_MQ_hd_fixed_size (p2p_revoke, 791 GNUNET_MQ_hd_fixed_size (p2p_revoke,
diff --git a/src/revocation/plugin_block_revocation.c b/src/revocation/plugin_block_revocation.c
new file mode 100644
index 000000000..eb0766b81
--- /dev/null
+++ b/src/revocation/plugin_block_revocation.c
@@ -0,0 +1,257 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 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 block/plugin_block_revocation.c
23 * @brief revocation for a block plugin
24 * @author Christian Grothoff
25 */
26
27#include "platform.h"
28#include "gnunet_signatures.h"
29#include "gnunet_block_plugin.h"
30#include "gnunet_block_group_lib.h"
31#include "revocation.h"
32#include "gnunet_revocation_service.h"
33
34#define DEBUG_REVOCATION GNUNET_EXTRA_LOGGING
35
36/**
37 * Number of bits we set per entry in the bloomfilter.
38 * Do not change!
39 */
40#define BLOOMFILTER_K 16
41
42
43/**
44 * How big is the BF we use for DHT blocks?
45 */
46#define REVOCATION_BF_SIZE 8
47
48
49/**
50 * Context used inside the plugin.
51 */
52struct InternalContext
53{
54
55 unsigned int matching_bits;
56
57};
58
59
60/**
61 * Create a new block group.
62 *
63 * @param ctx block context in which the block group is created
64 * @param type type of the block for which we are creating the group
65 * @param nonce random value used to seed the group creation
66 * @param raw_data optional serialized prior state of the group, NULL if unavailable/fresh
67 * @param raw_data_size number of bytes in @a raw_data, 0 if unavailable/fresh
68 * @param va variable arguments specific to @a type
69 * @return block group handle, NULL if block groups are not supported
70 * by this @a type of block (this is not an error)
71 */
72static struct GNUNET_BLOCK_Group *
73block_plugin_revocation_create_group (void *cls,
74 enum GNUNET_BLOCK_Type type,
75 uint32_t nonce,
76 const void *raw_data,
77 size_t raw_data_size,
78 va_list va)
79{
80 unsigned int bf_size;
81 const char *guard;
82
83 guard = va_arg (va, const char *);
84 if (0 == strcmp (guard,
85 "seen-set-size"))
86 bf_size = GNUNET_BLOCK_GROUP_compute_bloomfilter_size (va_arg (va, unsigned int),
87 BLOOMFILTER_K);
88 else if (0 == strcmp (guard,
89 "filter-size"))
90 bf_size = va_arg (va, unsigned int);
91 else
92 {
93 GNUNET_break (0);
94 bf_size = REVOCATION_BF_SIZE;
95 }
96 GNUNET_break (NULL == va_arg (va, const char *));
97 return GNUNET_BLOCK_GROUP_bf_create (cls,
98 bf_size,
99 BLOOMFILTER_K,
100 type,
101 nonce,
102 raw_data,
103 raw_data_size);
104}
105
106
107/**
108 * Function called to validate a reply or a request. For
109 * request evaluation, simply pass "NULL" for the reply_block.
110 *
111 * @param cls our `struct InternalContext`
112 * @param ctx context
113 * @param type block type
114 * @param group block group to use
115 * @param eo control flags
116 * @param query original query (hash)
117 * @param xquery extrended query data (can be NULL, depending on type)
118 * @param xquery_size number of bytes in xquery
119 * @param reply_block response to validate
120 * @param reply_block_size number of bytes in reply block
121 * @return characterization of result
122 */
123static enum GNUNET_BLOCK_EvaluationResult
124block_plugin_revocation_evaluate (void *cls,
125 struct GNUNET_BLOCK_Context *ctx,
126 enum GNUNET_BLOCK_Type type,
127 struct GNUNET_BLOCK_Group *group,
128 enum GNUNET_BLOCK_EvaluationOptions eo,
129 const struct GNUNET_HashCode *query,
130 const void *xquery,
131 size_t xquery_size,
132 const void *reply_block,
133 size_t reply_block_size)
134{
135 struct InternalContext *ic = cls;
136 struct GNUNET_HashCode chash;
137 const struct RevokeMessage *rm = reply_block;
138
139 if (NULL == reply_block)
140 return GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
141 if (reply_block_size != sizeof (*rm))
142 {
143 GNUNET_break_op (0);
144 return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
145 }
146 if (GNUNET_YES !=
147 GNUNET_REVOCATION_check_pow (&rm->public_key,
148 rm->proof_of_work,
149 ic->matching_bits))
150 {
151 GNUNET_break_op (0);
152 return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
153 }
154 if (GNUNET_OK !=
155 GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_REVOCATION,
156 &rm->purpose,
157 &rm->signature,
158 &rm->public_key))
159 {
160 GNUNET_break_op (0);
161 return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
162 }
163 GNUNET_CRYPTO_hash (&rm->public_key,
164 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
165 &chash);
166 if (GNUNET_YES ==
167 GNUNET_BLOCK_GROUP_bf_test_and_set (group,
168 &chash))
169 return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
170 return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED;
171}
172
173
174/**
175 * Function called to obtain the key for a block.
176 *
177 * @param cls closure
178 * @param type block type
179 * @param block block to get the key for
180 * @param block_size number of bytes in block
181 * @param key set to the key (query) for the given block
182 * @return #GNUNET_OK on success, #GNUNET_SYSERR if type not supported
183 * (or if extracting a key from a block of this type does not work)
184 */
185static int
186block_plugin_revocation_get_key (void *cls,
187 enum GNUNET_BLOCK_Type type,
188 const void *block,
189 size_t block_size,
190 struct GNUNET_HashCode *key)
191{
192 const struct RevokeMessage *rm = block;
193
194 if (block_size != sizeof (*rm))
195 {
196 GNUNET_break_op (0);
197 return GNUNET_SYSERR;
198 }
199 GNUNET_CRYPTO_hash (&rm->public_key,
200 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
201 key);
202 return GNUNET_OK;
203}
204
205
206/**
207 * Entry point for the plugin.
208 *
209 * @param cls the configuration to use
210 */
211void *
212libgnunet_plugin_block_revocation_init (void *cls)
213{
214 static enum GNUNET_BLOCK_Type types[] =
215 {
216 GNUNET_BLOCK_TYPE_REVOCATION,
217 GNUNET_BLOCK_TYPE_ANY /* end of list */
218 };
219 const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
220 struct GNUNET_BLOCK_PluginFunctions *api;
221 struct InternalContext *ic;
222 unsigned long long matching_bits;
223
224 if (GNUNET_OK !=
225 GNUNET_CONFIGURATION_get_value_number (cfg,
226 "REVOCATION",
227 "WORKBITS",
228 &matching_bits))
229 return NULL;
230
231 api = GNUNET_new (struct GNUNET_BLOCK_PluginFunctions);
232 api->evaluate = &block_plugin_revocation_evaluate;
233 api->get_key = &block_plugin_revocation_get_key;
234 api->create_group = &block_plugin_revocation_create_group;
235 api->types = types;
236 ic = GNUNET_new (struct InternalContext);
237 ic->matching_bits = (unsigned int) matching_bits;
238 api->cls = ic;
239 return api;
240}
241
242
243/**
244 * Exit point from the plugin.
245 */
246void *
247libgnunet_plugin_block_revocation_done (void *cls)
248{
249 struct GNUNET_BLOCK_PluginFunctions *api = cls;
250 struct InternalContext *ic = api->cls;
251
252 GNUNET_free (ic);
253 GNUNET_free (api);
254 return NULL;
255}
256
257/* end of plugin_block_revocation.c */
diff --git a/src/revocation/revocation_api.c b/src/revocation/revocation_api.c
index fde0296a4..ef659baa0 100644
--- a/src/revocation/revocation_api.c
+++ b/src/revocation/revocation_api.c
@@ -91,7 +91,7 @@ handle_revocation_query_response (void *cls,
91 91
92 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 92 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
93 "Revocation query result: %d\n", 93 "Revocation query result: %d\n",
94 ntohl (qrm->is_valid)); 94 (uint32_t) ntohl (qrm->is_valid));
95 q->func (q->func_cls, 95 q->func (q->func_cls,
96 ntohl (qrm->is_valid)); 96 ntohl (qrm->is_valid));
97 GNUNET_REVOCATION_query_cancel (q); 97 GNUNET_REVOCATION_query_cancel (q);
@@ -225,7 +225,7 @@ handle_revocation_response (void *cls,
225 225
226 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 226 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
227 "Revocation transmission result: %d\n", 227 "Revocation transmission result: %d\n",
228 ntohl (rrm->is_valid)); 228 (uint32_t) ntohl (rrm->is_valid));
229 h->func (h->func_cls, 229 h->func (h->func_cls,
230 ntohl (rrm->is_valid)); 230 ntohl (rrm->is_valid));
231 GNUNET_REVOCATION_revoke_cancel (h); 231 GNUNET_REVOCATION_revoke_cancel (h);
diff --git a/src/revocation/test_local_revocation.py.in b/src/revocation/test_local_revocation.py.in
index 69e68a197..28257715f 100644
--- a/src/revocation/test_local_revocation.py.in
+++ b/src/revocation/test_local_revocation.py.in
@@ -42,6 +42,7 @@ TEST_REVOCATION_EGO = "revoc_test"
42 42
43get_clean = subprocess.Popen ([config, '-c', TEST_CONFIGURATION, '-s', 'PATHS', '-o', 'GNUNET_HOME', '-f'], stdout=subprocess.PIPE) 43get_clean = subprocess.Popen ([config, '-c', TEST_CONFIGURATION, '-s', 'PATHS', '-o', 'GNUNET_HOME', '-f'], stdout=subprocess.PIPE)
44cleandir, x = get_clean.communicate () 44cleandir, x = get_clean.communicate ()
45cleandir = cleandir.decode("utf-8")
45cleandir = cleandir.rstrip ('\n').rstrip ('\r') 46cleandir = cleandir.rstrip ('\n').rstrip ('\r')
46 47
47if os.path.isdir (cleandir): 48if os.path.isdir (cleandir):
@@ -64,6 +65,7 @@ try:
64 sys.stderr.flush () 65 sys.stderr.flush ()
65 idd = subprocess.Popen ([ident, '-d'], stdout=subprocess.PIPE) 66 idd = subprocess.Popen ([ident, '-d'], stdout=subprocess.PIPE)
66 rev_key, x = idd.communicate () 67 rev_key, x = idd.communicate ()
68 rev_key = rev_key.decode("utf-8")
67 if len (rev_key.split ()) < 3: 69 if len (rev_key.split ()) < 3:
68 raise Exception ("can't get revocation key out of `" + rev_key + "'") 70 raise Exception ("can't get revocation key out of `" + rev_key + "'")
69 rev_key = rev_key.split ()[2] 71 rev_key = rev_key.split ()[2]
@@ -73,6 +75,7 @@ try:
73 sys.stderr.flush () 75 sys.stderr.flush ()
74 tst = subprocess.Popen ([revoc, '-t', rev_key, '-c', TEST_CONFIGURATION], stdout=subprocess.PIPE) 76 tst = subprocess.Popen ([revoc, '-t', rev_key, '-c', TEST_CONFIGURATION], stdout=subprocess.PIPE)
75 output_not_revoked, x = tst.communicate () 77 output_not_revoked, x = tst.communicate ()
78 output_not_revoked = output_not_revoked.decode("utf-8")
76 if tst.returncode != 0: 79 if tst.returncode != 0:
77 raise Exception ("gnunet-revocation failed to test a key - " + str (tst.returncode) + ": " + output_not_revoked) 80 raise Exception ("gnunet-revocation failed to test a key - " + str (tst.returncode) + ": " + output_not_revoked)
78 if 'valid' not in output_not_revoked: 81 if 'valid' not in output_not_revoked:
@@ -94,6 +97,7 @@ try:
94 sys.stderr.flush () 97 sys.stderr.flush ()
95 tst = subprocess.Popen ([revoc, '-t', rev_key, '-c', TEST_CONFIGURATION], stdout=subprocess.PIPE) 98 tst = subprocess.Popen ([revoc, '-t', rev_key, '-c', TEST_CONFIGURATION], stdout=subprocess.PIPE)
96 output_revoked, x = tst.communicate () 99 output_revoked, x = tst.communicate ()
100 output_revoked = output_revoked.decode("utf-8")
97 if tst.returncode != 0: 101 if tst.returncode != 0:
98 raise Exception ("gnunet-revocation failed to test a revoked key") 102 raise Exception ("gnunet-revocation failed to test a revoked key")
99 if 'revoked' not in output_revoked: 103 if 'revoked' not in output_revoked:
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 eee1a91b9..e6c8cd929 100644
--- a/src/rps/Makefile.am
+++ b/src/rps/Makefile.am
@@ -96,26 +96,32 @@ rps_test_src = \
96 gnunet-service-rps_sampler_elem.h gnunet-service-rps_sampler_elem.c 96 gnunet-service-rps_sampler_elem.h gnunet-service-rps_sampler_elem.c
97 97
98if ENABLE_TEST_RUN 98if ENABLE_TEST_RUN
99AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; 99AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
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..bbac0d634 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_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 9de1f8d3a..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
@@ -2241,8 +2208,8 @@ client_connect_cb (void *cls,
2241 */ 2208 */
2242static void 2209static void
2243client_disconnect_cb (void *cls, 2210client_disconnect_cb (void *cls,
2244 struct GNUNET_SERVICE_Client *client, 2211 struct GNUNET_SERVICE_Client *client,
2245 void *internal_cls) 2212 void *internal_cls)
2246{ 2213{
2247 struct ClientContext *cli_ctx = internal_cls; 2214 struct ClientContext *cli_ctx = internal_cls;
2248 2215
@@ -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/.gitignore b/src/scalarproduct/.gitignore
index e244f1108..19909a3f9 100644
--- a/src/scalarproduct/.gitignore
+++ b/src/scalarproduct/.gitignore
@@ -3,3 +3,4 @@ gnunet-scalarproduct
3gnunet-service-scalarproduct-alice 3gnunet-service-scalarproduct-alice
4gnunet-service-scalarproduct-bob 4gnunet-service-scalarproduct-bob
5gnunet-service-scalarproduct-ecc-alice 5gnunet-service-scalarproduct-ecc-alice
6test_ecc_scalarproduct
diff --git a/src/scalarproduct/Makefile.am b/src/scalarproduct/Makefile.am
index e2487d9f3..10e04284f 100644
--- a/src/scalarproduct/Makefile.am
+++ b/src/scalarproduct/Makefile.am
@@ -106,7 +106,7 @@ check_PROGRAMS = \
106 test_ecc_scalarproduct 106 test_ecc_scalarproduct
107 107
108if ENABLE_TEST_RUN 108if ENABLE_TEST_RUN
109 AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; 109 AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
110 TESTS = $(check_SCRIPTS) $(check_PROGRAMS) 110 TESTS = $(check_SCRIPTS) $(check_PROGRAMS)
111endif 111endif
112 112
diff --git a/src/scalarproduct/gnunet-scalarproduct.c b/src/scalarproduct/gnunet-scalarproduct.c
index aa894b61d..4a152e09e 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 0b7f24e7e..c0b33f8ef 100644
--- a/src/scalarproduct/gnunet-service-scalarproduct-ecc_alice.c
+++ b/src/scalarproduct/gnunet-service-scalarproduct-ecc_alice.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
@@ -238,15 +238,10 @@ destroy_service_session (struct AliceServiceSession *s)
238 if (GNUNET_YES == s->in_destroy) 238 if (GNUNET_YES == s->in_destroy)
239 return; 239 return;
240 s->in_destroy = GNUNET_YES; 240 s->in_destroy = GNUNET_YES;
241 if (NULL != s->cadet_mq)
242 {
243 GNUNET_MQ_destroy (s->cadet_mq);
244 s->cadet_mq = NULL;
245 }
246 if (NULL != s->client) 241 if (NULL != s->client)
247 { 242 {
248 struct GNUNET_SERVICE_Client *c = s->client; 243 struct GNUNET_SERVICE_Client *c = s->client;
249 244
250 s->client = NULL; 245 s->client = NULL;
251 GNUNET_SERVICE_client_drop (c); 246 GNUNET_SERVICE_client_drop (c);
252 } 247 }
@@ -265,16 +260,22 @@ destroy_service_session (struct AliceServiceSession *s)
265 } 260 }
266 if (NULL != s->intersection_listen) 261 if (NULL != s->intersection_listen)
267 { 262 {
263 LOG (GNUNET_ERROR_TYPE_DEBUG,
264 "Set intersection, listen still up!\n");
268 GNUNET_SET_listen_cancel (s->intersection_listen); 265 GNUNET_SET_listen_cancel (s->intersection_listen);
269 s->intersection_listen = NULL; 266 s->intersection_listen = NULL;
270 } 267 }
271 if (NULL != s->intersection_op) 268 if (NULL != s->intersection_op)
272 { 269 {
270 LOG (GNUNET_ERROR_TYPE_DEBUG,
271 "Set intersection, op still ongoing!\n");
273 GNUNET_SET_operation_cancel (s->intersection_op); 272 GNUNET_SET_operation_cancel (s->intersection_op);
274 s->intersection_op = NULL; 273 s->intersection_op = NULL;
275 } 274 }
276 if (NULL != s->intersection_set) 275 if (NULL != s->intersection_set)
277 { 276 {
277 LOG (GNUNET_ERROR_TYPE_DEBUG,
278 "Set intersection, set still there!\n");
278 GNUNET_SET_destroy (s->intersection_set); 279 GNUNET_SET_destroy (s->intersection_set);
279 s->intersection_set = NULL; 280 s->intersection_set = NULL;
280 } 281 }
@@ -401,34 +402,25 @@ transmit_client_response (struct AliceServiceSession *s)
401} 402}
402 403
403 404
404
405/** 405/**
406 * Function called whenever a channel is destroyed. Should clean up 406 * Function called whenever a channel is destroyed. Should clean up
407 * any associated state. 407 * any associated state.
408 * 408 *
409 * It must NOT call #GNUNET_CADET_channel_destroy() on the channel. 409 * It must NOT call #GNUNET_CADET_channel_destroy() on the channel.
410 * 410 *
411 * @param cls closure (set from #GNUNET_CADET_connect()) 411 * @param cls the `struct AliceServiceSession`
412 * @param channel connection to the other end (henceforth invalid) 412 * @param channel connection to the other end (henceforth invalid)
413 * @param channel_ctx place where local state associated
414 * with the channel is stored
415 */ 413 */
416static void 414static void
417cb_channel_destruction (void *cls, 415cb_channel_destruction (void *cls,
418 const struct GNUNET_CADET_Channel *channel, 416 const struct GNUNET_CADET_Channel *channel)
419 void *channel_ctx)
420{ 417{
421 struct AliceServiceSession *s = channel_ctx; 418 struct AliceServiceSession *s = cls;
422 419
423 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 420 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
424 "Peer disconnected, terminating session %s with peer %s\n", 421 "Peer disconnected, terminating session %s with peer %s\n",
425 GNUNET_h2s (&s->session_id), 422 GNUNET_h2s (&s->session_id),
426 GNUNET_i2s (&s->peer)); 423 GNUNET_i2s (&s->peer));
427 if (NULL != s->cadet_mq)
428 {
429 GNUNET_MQ_destroy (s->cadet_mq);
430 s->cadet_mq = NULL;
431 }
432 s->channel = NULL; 424 s->channel = NULL;
433 if (GNUNET_SCALARPRODUCT_STATUS_ACTIVE == s->status) 425 if (GNUNET_SCALARPRODUCT_STATUS_ACTIVE == s->status)
434 { 426 {
@@ -492,56 +484,40 @@ compute_scalar_product (struct AliceServiceSession *session,
492 * Handle a response we got from another service we wanted to 484 * Handle a response we got from another service we wanted to
493 * calculate a scalarproduct with. 485 * calculate a scalarproduct with.
494 * 486 *
495 * @param cls closure (set from #GNUNET_CADET_connect) 487 * @param cls the `struct AliceServiceSession *`
496 * @param channel connection to the other end 488 * @param msg the actual message
497 * @param channel_ctx place to store local state associated with the channel
498 * @param message the actual message
499 * @return #GNUNET_OK to keep the connection open,
500 * #GNUNET_SYSERR to close it (we are done)
501 */ 489 */
502static int 490static void
503handle_bobs_cryptodata_message (void *cls, 491handle_bobs_cryptodata_message (void *cls,
504 struct GNUNET_CADET_Channel *channel, 492 const struct EccBobCryptodataMessage *msg)
505 void **channel_ctx,
506 const struct GNUNET_MessageHeader *message)
507{ 493{
508 struct AliceServiceSession *s = *channel_ctx; 494 struct AliceServiceSession *s = cls;
509 const struct EccBobCryptodataMessage *msg;
510 uint32_t contained;
511 uint16_t msg_size;
512 gcry_mpi_point_t prod_g_i_b_i; 495 gcry_mpi_point_t prod_g_i_b_i;
513 gcry_mpi_point_t prod_h_i_b_i; 496 gcry_mpi_point_t prod_h_i_b_i;
497 uint32_t contained;
514 498
515 if (NULL == s)
516 {
517 GNUNET_break_op (0);
518 return GNUNET_SYSERR;
519 }
520 msg_size = ntohs (message->size);
521 if (sizeof (struct EccBobCryptodataMessage) > msg_size)
522 {
523 GNUNET_break_op (0);
524 return GNUNET_SYSERR;
525 }
526 msg = (const struct EccBobCryptodataMessage *) message;
527 contained = ntohl (msg->contained_element_count); 499 contained = ntohl (msg->contained_element_count);
528 if (2 != contained) 500 if (2 != contained)
529 { 501 {
530 GNUNET_break_op (0); 502 GNUNET_break_op (0);
531 return GNUNET_SYSERR; 503 destroy_service_session (s);
504 return;
532 } 505 }
533 if (NULL == s->sorted_elements) 506 if (NULL == s->sorted_elements)
534 { 507 {
535 /* we're not ready yet, how can Bob be? */ 508 /* we're not ready yet, how can Bob be? */
536 GNUNET_break_op (0); 509 GNUNET_break_op (0);
537 return GNUNET_SYSERR; 510 destroy_service_session (s);
511 return;
538 } 512 }
539 if (s->total != s->client_received_element_count) 513 if (s->total != s->client_received_element_count)
540 { 514 {
541 /* we're not ready yet, how can Bob be? */ 515 /* we're not ready yet, how can Bob be? */
542 GNUNET_break_op (0); 516 GNUNET_break_op (0);
543 return GNUNET_SYSERR; 517 destroy_service_session (s);
518 return;
544 } 519 }
520
545 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 521 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
546 "Received %u crypto values from Bob\n", 522 "Received %u crypto values from Bob\n",
547 (unsigned int) contained); 523 (unsigned int) contained);
@@ -556,7 +532,6 @@ handle_bobs_cryptodata_message (void *cls,
556 gcry_mpi_point_release (prod_g_i_b_i); 532 gcry_mpi_point_release (prod_g_i_b_i);
557 gcry_mpi_point_release (prod_h_i_b_i); 533 gcry_mpi_point_release (prod_h_i_b_i);
558 transmit_client_response (s); 534 transmit_client_response (s);
559 return GNUNET_OK;
560} 535}
561 536
562 537
@@ -636,8 +611,8 @@ send_alices_cryptodata_message (struct AliceServiceSession *s)
636 unsigned int todo_count; 611 unsigned int todo_count;
637 612
638 s->sorted_elements 613 s->sorted_elements
639 = GNUNET_malloc (GNUNET_CONTAINER_multihashmap_size (s->intersected_elements) * 614 = GNUNET_new_array (GNUNET_CONTAINER_multihashmap_size (s->intersected_elements),
640 sizeof (struct MpiElement)); 615 struct MpiElement);
641 s->used_element_count = 0; 616 s->used_element_count = 0;
642 GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements, 617 GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
643 &copy_element_cb, 618 &copy_element_cb,
@@ -712,11 +687,13 @@ send_alices_cryptodata_message (struct AliceServiceSession *s)
712 * 687 *
713 * @param cls closure with the `struct AliceServiceSession` 688 * @param cls closure with the `struct AliceServiceSession`
714 * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK 689 * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
690 * @param current_size current set size
715 * @param status what has happened with the set intersection? 691 * @param status what has happened with the set intersection?
716 */ 692 */
717static void 693static void
718cb_intersection_element_removed (void *cls, 694cb_intersection_element_removed (void *cls,
719 const struct GNUNET_SET_Element *element, 695 const struct GNUNET_SET_Element *element,
696 uint64_t current_size,
720 enum GNUNET_SET_Status status) 697 enum GNUNET_SET_Status status)
721{ 698{
722 struct AliceServiceSession *s = cls; 699 struct AliceServiceSession *s = cls;
@@ -800,6 +777,9 @@ cb_intersection_request_alice (void *cls,
800{ 777{
801 struct AliceServiceSession *s = cls; 778 struct AliceServiceSession *s = cls;
802 779
780 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
781 "Received intersection request from %s!\n",
782 GNUNET_i2s (other_peer));
803 if (0 != memcmp (other_peer, 783 if (0 != memcmp (other_peer,
804 &s->peer, 784 &s->peer,
805 sizeof (struct GNUNET_PeerIdentity))) 785 sizeof (struct GNUNET_PeerIdentity)))
@@ -810,6 +790,7 @@ cb_intersection_request_alice (void *cls,
810 s->intersection_op 790 s->intersection_op
811 = GNUNET_SET_accept (request, 791 = GNUNET_SET_accept (request,
812 GNUNET_SET_RESULT_REMOVED, 792 GNUNET_SET_RESULT_REMOVED,
793 (struct GNUNET_SET_Option[]) {{ 0 }},
813 &cb_intersection_element_removed, 794 &cb_intersection_element_removed,
814 s); 795 s);
815 if (NULL == s->intersection_op) 796 if (NULL == s->intersection_op)
@@ -843,6 +824,13 @@ cb_intersection_request_alice (void *cls,
843static void 824static void
844client_request_complete_alice (struct AliceServiceSession *s) 825client_request_complete_alice (struct AliceServiceSession *s)
845{ 826{
827 struct GNUNET_MQ_MessageHandler cadet_handlers[] = {
828 GNUNET_MQ_hd_fixed_size (bobs_cryptodata_message,
829 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_BOB_CRYPTODATA,
830 struct EccBobCryptodataMessage,
831 s),
832 GNUNET_MQ_handler_end ()
833 };
846 struct EccServiceRequestMessage *msg; 834 struct EccServiceRequestMessage *msg;
847 struct GNUNET_MQ_Envelope *e; 835 struct GNUNET_MQ_Envelope *e;
848 struct GNUNET_HashCode set_sid; 836 struct GNUNET_HashCode set_sid;
@@ -858,14 +846,17 @@ client_request_complete_alice (struct AliceServiceSession *s)
858 s, 846 s,
859 &s->peer, 847 &s->peer,
860 &s->session_id, 848 &s->session_id,
861 GNUNET_CADET_OPTION_RELIABLE); 849 GNUNET_CADET_OPTION_RELIABLE,
850 NULL,
851 &cb_channel_destruction,
852 cadet_handlers);
862 if (NULL == s->channel) 853 if (NULL == s->channel)
863 { 854 {
864 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE; 855 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
865 prepare_client_end_notification (s); 856 prepare_client_end_notification (s);
866 return; 857 return;
867 } 858 }
868 s->cadet_mq = GNUNET_CADET_mq_create (s->channel); 859 s->cadet_mq = GNUNET_CADET_get_mq (s->channel);
869 s->intersection_listen 860 s->intersection_listen
870 = GNUNET_SET_listen (cfg, 861 = GNUNET_SET_listen (cfg,
871 GNUNET_SET_OPERATION_INTERSECTION, 862 GNUNET_SET_OPERATION_INTERSECTION,
@@ -890,7 +881,7 @@ client_request_complete_alice (struct AliceServiceSession *s)
890 881
891 882
892/** 883/**
893 * We're receiving additional set data. Check if 884 * We're receiving additional set data. Check if
894 * @a msg is well-formed. 885 * @a msg is well-formed.
895 * 886 *
896 * @param cls client identification of the client 887 * @param cls client identification of the client
@@ -898,7 +889,7 @@ client_request_complete_alice (struct AliceServiceSession *s)
898 * @return #GNUNET_OK if @a msg is well-formed 889 * @return #GNUNET_OK if @a msg is well-formed
899 */ 890 */
900static int 891static int
901check_alice_client_message_multipart (void *cls, 892check_alice_client_message_multipart (void *cls,
902 const struct ComputationBobCryptodataMultipartMessage *msg) 893 const struct ComputationBobCryptodataMultipartMessage *msg)
903{ 894{
904 struct AliceServiceSession *s = cls; 895 struct AliceServiceSession *s = cls;
@@ -928,7 +919,7 @@ check_alice_client_message_multipart (void *cls,
928 * @param msg the actual message 919 * @param msg the actual message
929 */ 920 */
930static void 921static void
931handle_alice_client_message_multipart (void *cls, 922handle_alice_client_message_multipart (void *cls,
932 const struct ComputationBobCryptodataMultipartMessage *msg) 923 const struct ComputationBobCryptodataMultipartMessage *msg)
933{ 924{
934 struct AliceServiceSession *s = cls; 925 struct AliceServiceSession *s = cls;
@@ -968,8 +959,12 @@ handle_alice_client_message_multipart (void *cls,
968 if (s->total != s->client_received_element_count) 959 if (s->total != s->client_received_element_count)
969 { 960 {
970 /* more to come */ 961 /* more to come */
962 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
963 "Received client multipart data, waiting for more!\n");
971 return; 964 return;
972 } 965 }
966 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
967 "Launching computation\n");
973 client_request_complete_alice (s); 968 client_request_complete_alice (s);
974} 969}
975 970
@@ -983,7 +978,7 @@ handle_alice_client_message_multipart (void *cls,
983 * @return #GNUNET_OK if @a msg is well-formed 978 * @return #GNUNET_OK if @a msg is well-formed
984 */ 979 */
985static int 980static int
986check_alice_client_message (void *cls, 981check_alice_client_message (void *cls,
987 const struct AliceComputationMessage *msg) 982 const struct AliceComputationMessage *msg)
988{ 983{
989 struct AliceServiceSession *s = cls; 984 struct AliceServiceSession *s = cls;
@@ -1012,7 +1007,7 @@ check_alice_client_message (void *cls,
1012 return GNUNET_OK; 1007 return GNUNET_OK;
1013} 1008}
1014 1009
1015 1010
1016/** 1011/**
1017 * Handler for Alice's client request message. 1012 * Handler for Alice's client request message.
1018 * We are doing request-initiation to compute a scalar product with a peer. 1013 * We are doing request-initiation to compute a scalar product with a peer.
@@ -1021,7 +1016,7 @@ check_alice_client_message (void *cls,
1021 * @param msg the actual message 1016 * @param msg the actual message
1022 */ 1017 */
1023static void 1018static void
1024handle_alice_client_message (void *cls, 1019handle_alice_client_message (void *cls,
1025 const struct AliceComputationMessage *msg) 1020 const struct AliceComputationMessage *msg)
1026{ 1021{
1027 struct AliceServiceSession *s = cls; 1022 struct AliceServiceSession *s = cls;
@@ -1074,8 +1069,12 @@ handle_alice_client_message (void *cls,
1074 if (s->total != s->client_received_element_count) 1069 if (s->total != s->client_received_element_count)
1075 { 1070 {
1076 /* wait for multipart msg */ 1071 /* wait for multipart msg */
1072 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1073 "Received partial client request, waiting for more!\n");
1077 return; 1074 return;
1078 } 1075 }
1076 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1077 "Launching computation\n");
1079 client_request_complete_alice (s); 1078 client_request_complete_alice (s);
1080} 1079}
1081 1080
@@ -1167,13 +1166,6 @@ run (void *cls,
1167 const struct GNUNET_CONFIGURATION_Handle *c, 1166 const struct GNUNET_CONFIGURATION_Handle *c,
1168 struct GNUNET_SERVICE_Handle *service) 1167 struct GNUNET_SERVICE_Handle *service)
1169{ 1168{
1170 static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
1171 { &handle_bobs_cryptodata_message,
1172 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_BOB_CRYPTODATA,
1173 0},
1174 { NULL, 0, 0}
1175 };
1176
1177 cfg = c; 1169 cfg = c;
1178 edc = GNUNET_CRYPTO_ecc_dlog_prepare (MAX_RESULT, 1170 edc = GNUNET_CRYPTO_ecc_dlog_prepare (MAX_RESULT,
1179 MAX_RAM); 1171 MAX_RAM);
@@ -1181,10 +1173,7 @@ run (void *cls,
1181 GNUNET_CRYPTO_ecc_rnd_mpi (edc, 1173 GNUNET_CRYPTO_ecc_rnd_mpi (edc,
1182 &my_privkey, 1174 &my_privkey,
1183 &my_privkey_inv); 1175 &my_privkey_inv);
1184 my_cadet = GNUNET_CADET_connect (cfg, 1176 my_cadet = GNUNET_CADET_connect (cfg);
1185 NULL,
1186 &cb_channel_destruction,
1187 cadet_handlers);
1188 if (NULL == my_cadet) 1177 if (NULL == my_cadet)
1189 { 1178 {
1190 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1179 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@@ -1216,7 +1205,7 @@ GNUNET_SERVICE_MAIN
1216 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MULTIPART_ALICE, 1205 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MULTIPART_ALICE,
1217 struct ComputationBobCryptodataMultipartMessage, 1206 struct ComputationBobCryptodataMultipartMessage,
1218 NULL), 1207 NULL),
1219 GNUNET_MQ_handler_end ()); 1208 GNUNET_MQ_handler_end ());
1220 1209
1221 1210
1222/* end of gnunet-service-scalarproduct-ecc_alice.c */ 1211/* end of gnunet-service-scalarproduct-ecc_alice.c */
diff --git a/src/scalarproduct/gnunet-service-scalarproduct-ecc_bob.c b/src/scalarproduct/gnunet-service-scalarproduct-ecc_bob.c
index 06e30706e..0b0333332 100644
--- a/src/scalarproduct/gnunet-service-scalarproduct-ecc_bob.c
+++ b/src/scalarproduct/gnunet-service-scalarproduct-ecc_bob.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) 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
@@ -59,12 +59,6 @@ struct MpiElement
59 59
60 60
61/** 61/**
62 * An incoming session from CADET.
63 */
64struct CadetIncomingSession;
65
66
67/**
68 * A scalarproduct session which tracks an offer for a 62 * A scalarproduct session which tracks an offer for a
69 * multiplication service by a local client. 63 * multiplication service by a local client.
70 */ 64 */
@@ -72,11 +66,6 @@ struct BobServiceSession
72{ 66{
73 67
74 /** 68 /**
75 * (hopefully) unique transaction ID
76 */
77 struct GNUNET_HashCode session_id;
78
79 /**
80 * The client this request is related to. 69 * The client this request is related to.
81 */ 70 */
82 struct GNUNET_SERVICE_Client *client; 71 struct GNUNET_SERVICE_Client *client;
@@ -124,12 +113,6 @@ struct BobServiceSession
124 gcry_mpi_point_t prod_h_i_b_i; 113 gcry_mpi_point_t prod_h_i_b_i;
125 114
126 /** 115 /**
127 * Handle for our associated incoming CADET session, or NULL
128 * if we have not gotten one yet.
129 */
130 struct CadetIncomingSession *cadet;
131
132 /**
133 * How many elements will be supplied in total from the client. 116 * How many elements will be supplied in total from the client.
134 */ 117 */
135 uint32_t total; 118 uint32_t total;
@@ -166,20 +149,6 @@ struct BobServiceSession
166 */ 149 */
167 int in_destroy; 150 int in_destroy;
168 151
169};
170
171
172/**
173 * An incoming session from CADET.
174 */
175struct CadetIncomingSession
176{
177
178 /**
179 * Associated client session, or NULL.
180 */
181 struct BobServiceSession *s;
182
183 /** 152 /**
184 * The CADET channel. 153 * The CADET channel.
185 */ 154 */
@@ -200,18 +169,6 @@ struct CadetIncomingSession
200 */ 169 */
201 struct GNUNET_MQ_Handle *cadet_mq; 170 struct GNUNET_MQ_Handle *cadet_mq;
202 171
203 /**
204 * Has this CADET session been added to the map yet?
205 * #GNUNET_YES if so, in which case @e session_id is
206 * the key.
207 */
208 int in_map;
209
210 /**
211 * Are we already in #destroy_cadet_session()?
212 */
213 int in_destroy;
214
215}; 172};
216 173
217 174
@@ -221,16 +178,6 @@ struct CadetIncomingSession
221static const struct GNUNET_CONFIGURATION_Handle *cfg; 178static const struct GNUNET_CONFIGURATION_Handle *cfg;
222 179
223/** 180/**
224 * Map of `struct BobServiceSession`, by session keys.
225 */
226static struct GNUNET_CONTAINER_MultiHashMap *client_sessions;
227
228/**
229 * Map of `struct CadetIncomingSession`, by session keys.
230 */
231static struct GNUNET_CONTAINER_MultiHashMap *cadet_sessions;
232
233/**
234 * Handle to the CADET service. 181 * Handle to the CADET service.
235 */ 182 */
236static struct GNUNET_CADET_Handle *my_cadet; 183static struct GNUNET_CADET_Handle *my_cadet;
@@ -242,35 +189,6 @@ static struct GNUNET_CRYPTO_EccDlogContext *edc;
242 189
243 190
244/** 191/**
245 * Finds a not terminated client session in the respective map based on
246 * session key.
247 *
248 * @param key the session key we want to search for
249 * @return the matching session, or NULL for none
250 */
251static struct BobServiceSession *
252find_matching_client_session (const struct GNUNET_HashCode *key)
253{
254 return GNUNET_CONTAINER_multihashmap_get (client_sessions,
255 key);
256}
257
258
259/**
260 * Finds a CADET session in the respective map based on session key.
261 *
262 * @param key the session key we want to search for
263 * @return the matching session, or NULL for none
264 */
265static struct CadetIncomingSession *
266find_matching_cadet_session (const struct GNUNET_HashCode *key)
267{
268 return GNUNET_CONTAINER_multihashmap_get (cadet_sessions,
269 key);
270}
271
272
273/**
274 * Callback used to free the elements in the map. 192 * Callback used to free the elements in the map.
275 * 193 *
276 * @param cls NULL 194 * @param cls NULL
@@ -295,39 +213,20 @@ free_element_cb (void *cls,
295 * @param session the session to free elements from 213 * @param session the session to free elements from
296 */ 214 */
297static void 215static void
298destroy_cadet_session (struct CadetIncomingSession *s);
299
300
301/**
302 * Destroy session state, we are done with it.
303 *
304 * @param session the session to free elements from
305 */
306static void
307destroy_service_session (struct BobServiceSession *s) 216destroy_service_session (struct BobServiceSession *s)
308{ 217{
309 struct CadetIncomingSession *in;
310 unsigned int i; 218 unsigned int i;
311 219
312 if (GNUNET_YES == s->in_destroy) 220 if (GNUNET_YES == s->in_destroy)
313 return; 221 return;
314 s->in_destroy = GNUNET_YES; 222 s->in_destroy = GNUNET_YES;
315 if (NULL != (in = s->cadet))
316 {
317 s->cadet = NULL;
318 destroy_cadet_session (in);
319 }
320 if (NULL != s->client) 223 if (NULL != s->client)
321 { 224 {
322 struct GNUNET_SERVICE_Client *c = s->client; 225 struct GNUNET_SERVICE_Client *c = s->client;
323 226
324 s->client = NULL; 227 s->client = NULL;
325 GNUNET_SERVICE_client_drop (c); 228 GNUNET_SERVICE_client_drop (c);
326 } 229 }
327 GNUNET_assert (GNUNET_YES ==
328 GNUNET_CONTAINER_multihashmap_remove (client_sessions,
329 &s->session_id,
330 s));
331 if (NULL != s->intersected_elements) 230 if (NULL != s->intersected_elements)
332 { 231 {
333 GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements, 232 GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
@@ -363,48 +262,17 @@ destroy_service_session (struct BobServiceSession *s)
363 gcry_mpi_point_release (s->prod_h_i_b_i); 262 gcry_mpi_point_release (s->prod_h_i_b_i);
364 s->prod_h_i_b_i = NULL; 263 s->prod_h_i_b_i = NULL;
365 } 264 }
366 GNUNET_CADET_close_port (s->port); 265 if (NULL != s->port)
367 GNUNET_free (s);
368}
369
370
371/**
372 * Destroy incoming CADET session state, we are done with it.
373 *
374 * @param in the session to free elements from
375 */
376static void
377destroy_cadet_session (struct CadetIncomingSession *in)
378{
379 struct BobServiceSession *s;
380
381 if (GNUNET_YES == in->in_destroy)
382 return;
383 in->in_destroy = GNUNET_YES;
384 if (NULL != (s = in->s))
385 { 266 {
386 in->s = NULL; 267 GNUNET_CADET_close_port (s->port);
387 destroy_service_session (s); 268 s->port = NULL;
388 } 269 }
389 if (GNUNET_YES == in->in_map) 270 if (NULL != s->channel)
390 { 271 {
391 GNUNET_assert (GNUNET_YES == 272 GNUNET_CADET_channel_destroy (s->channel);
392 GNUNET_CONTAINER_multihashmap_remove (cadet_sessions, 273 s->channel = NULL;
393 &in->session_id,
394 in));
395 in->in_map = GNUNET_NO;
396 } 274 }
397 if (NULL != in->cadet_mq) 275 GNUNET_free (s);
398 {
399 GNUNET_MQ_destroy (in->cadet_mq);
400 in->cadet_mq = NULL;
401 }
402 if (NULL != in->channel)
403 {
404 GNUNET_CADET_channel_destroy (in->channel);
405 in->channel = NULL;
406 }
407 GNUNET_free (in);
408} 276}
409 277
410 278
@@ -443,38 +311,28 @@ prepare_client_end_notification (struct BobServiceSession *session)
443 * 311 *
444 * It must NOT call #GNUNET_CADET_channel_destroy() on the channel. 312 * It must NOT call #GNUNET_CADET_channel_destroy() on the channel.
445 * 313 *
446 * @param cls closure (set from #GNUNET_CADET_connect()) 314 * @param cls the `struct BobServiceSession`
447 * @param channel connection to the other end (henceforth invalid) 315 * @param channel connection to the other end (henceforth invalid)
448 * @param channel_ctx place where local state associated 316 * @param channel_ctx place where local state associated
449 * with the channel is stored 317 * with the channel is stored
450 */ 318 */
451static void 319static void
452cb_channel_destruction (void *cls, 320cb_channel_destruction (void *cls,
453 const struct GNUNET_CADET_Channel *channel, 321 const struct GNUNET_CADET_Channel *channel)
454 void *channel_ctx)
455{ 322{
456 struct CadetIncomingSession *in = channel_ctx; 323 struct BobServiceSession *s = cls;
457 struct BobServiceSession *s;
458 324
459 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 325 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
460 "Peer disconnected, terminating session %s with peer %s\n", 326 "Peer disconnected, terminating session %s with peer %s\n",
461 GNUNET_h2s (&in->session_id), 327 GNUNET_h2s (&s->session_id),
462 GNUNET_i2s (&in->peer)); 328 GNUNET_i2s (&s->peer));
463 if (NULL != in->cadet_mq) 329 s->channel = NULL;
464 { 330 if (GNUNET_SCALARPRODUCT_STATUS_ACTIVE == s->status)
465 GNUNET_MQ_destroy (in->cadet_mq);
466 in->cadet_mq = NULL;
467 }
468 in->channel = NULL;
469 if (NULL != (s = in->s))
470 { 331 {
471 if (GNUNET_SCALARPRODUCT_STATUS_ACTIVE == s->status) 332 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
472 { 333 prepare_client_end_notification (s);
473 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
474 prepare_client_end_notification (s);
475 }
476 } 334 }
477 destroy_cadet_session (in); 335 destroy_service_session (s);
478} 336}
479 337
480 338
@@ -519,7 +377,7 @@ transmit_bobs_cryptodata_message (struct BobServiceSession *s)
519 GNUNET_MQ_notify_sent (e, 377 GNUNET_MQ_notify_sent (e,
520 &bob_cadet_done_cb, 378 &bob_cadet_done_cb,
521 s); 379 s);
522 GNUNET_MQ_send (s->cadet->cadet_mq, 380 GNUNET_MQ_send (s->cadet_mq,
523 e); 381 e);
524} 382}
525 383
@@ -577,56 +435,79 @@ element_cmp (const void *a,
577 435
578 436
579/** 437/**
580 * Handle a multipart-chunk of a request from another service to 438 * Check a multipart-chunk of a request from another service to
581 * calculate a scalarproduct with us. 439 * calculate a scalarproduct with us.
582 * 440 *
583 * @param cls closure (set from #GNUNET_CADET_connect) 441 * @param cls closure (set from #GNUNET_CADET_connect)
584 * @param channel connection to the other end 442 * @param msg the actual message
585 * @param channel_ctx place to store local state associated with the @a channel
586 * @param message the actual message
587 * @return #GNUNET_OK to keep the connection open, 443 * @return #GNUNET_OK to keep the connection open,
588 * #GNUNET_SYSERR to close it (signal serious error) 444 * #GNUNET_SYSERR to close it (signal serious error)
589 */ 445 */
590static int 446static int
591handle_alices_cryptodata_message (void *cls, 447check_alices_cryptodata_message (void *cls,
592 struct GNUNET_CADET_Channel *channel, 448 const struct EccAliceCryptodataMessage *msg)
593 void **channel_ctx,
594 const struct GNUNET_MessageHeader *message)
595{ 449{
596 struct CadetIncomingSession *in = *channel_ctx; 450 struct BobServiceSession *s = cls;
597 struct BobServiceSession *s;
598 const struct EccAliceCryptodataMessage *msg;
599 const struct GNUNET_CRYPTO_EccPoint *payload;
600 uint32_t contained_elements; 451 uint32_t contained_elements;
601 size_t msg_length; 452 size_t msg_length;
602 uint16_t msize; 453 uint16_t msize;
603 unsigned int max; 454 unsigned int max;
604 unsigned int i;
605 const struct MpiElement *b_i;
606 gcry_mpi_point_t tmp;
607 gcry_mpi_point_t g_i;
608 gcry_mpi_point_t h_i;
609 gcry_mpi_point_t g_i_b_i;
610 gcry_mpi_point_t h_i_b_i;
611 455
612 /* sanity checks */ 456 msize = ntohs (msg->header.size);
613 if (NULL == in) 457 if (msize <= sizeof (struct EccAliceCryptodataMessage))
614 { 458 {
615 GNUNET_break_op (0); 459 GNUNET_break_op (0);
616 return GNUNET_SYSERR; 460 return GNUNET_SYSERR;
617 } 461 }
618 s = in->s; 462 contained_elements = ntohl (msg->contained_element_count);
619 if (NULL == s) 463 /* Our intersection may still be ongoing, but this is nevertheless
464 an upper bound on the required array size */
465 max = GNUNET_CONTAINER_multihashmap_size (s->intersected_elements);
466 msg_length = sizeof (struct EccAliceCryptodataMessage)
467 + contained_elements * sizeof (struct GNUNET_CRYPTO_EccPoint) * 2;
468 if ( (msize != msg_length) ||
469 (0 == contained_elements) ||
470 (contained_elements > UINT16_MAX) ||
471 (max < contained_elements + s->cadet_received_element_count) )
620 { 472 {
621 GNUNET_break_op (0); 473 GNUNET_break_op (0);
622 return GNUNET_SYSERR; 474 return GNUNET_SYSERR;
623 } 475 }
476 return GNUNET_OK;
477}
478
479
480/**
481 * Handle a multipart-chunk of a request from another service to
482 * calculate a scalarproduct with us.
483 *
484 * @param cls closure (set from #GNUNET_CADET_connect)
485 * @param msg the actual message
486 */
487static void
488handle_alices_cryptodata_message (void *cls,
489 const struct EccAliceCryptodataMessage *msg)
490{
491 struct BobServiceSession *s = cls;
492 const struct GNUNET_CRYPTO_EccPoint *payload;
493 uint32_t contained_elements;
494 unsigned int max;
495 unsigned int i;
496 const struct MpiElement *b_i;
497 gcry_mpi_point_t tmp;
498 gcry_mpi_point_t g_i;
499 gcry_mpi_point_t h_i;
500 gcry_mpi_point_t g_i_b_i;
501 gcry_mpi_point_t h_i_b_i;
502
503 contained_elements = ntohl (msg->contained_element_count);
504 max = GNUNET_CONTAINER_multihashmap_size (s->intersected_elements);
624 /* sort our vector for the computation */ 505 /* sort our vector for the computation */
625 if (NULL == s->sorted_elements) 506 if (NULL == s->sorted_elements)
626 { 507 {
627 s->sorted_elements 508 s->sorted_elements
628 = GNUNET_malloc (GNUNET_CONTAINER_multihashmap_size (s->intersected_elements) * 509 = GNUNET_new_array (GNUNET_CONTAINER_multihashmap_size (s->intersected_elements),
629 sizeof (struct MpiElement)); 510 struct MpiElement);
630 s->used_element_count = 0; 511 s->used_element_count = 0;
631 GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements, 512 GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
632 &copy_element_cb, 513 &copy_element_cb,
@@ -637,28 +518,6 @@ handle_alices_cryptodata_message (void *cls,
637 &element_cmp); 518 &element_cmp);
638 } 519 }
639 520
640 /* parse message */
641 msize = ntohs (message->size);
642 if (msize <= sizeof (struct EccAliceCryptodataMessage))
643 {
644 GNUNET_break_op (0);
645 return GNUNET_SYSERR;
646 }
647 msg = (const struct EccAliceCryptodataMessage *) message;
648 contained_elements = ntohl (msg->contained_element_count);
649 /* Our intersection may still be ongoing, but this is nevertheless
650 an upper bound on the required array size */
651 max = GNUNET_CONTAINER_multihashmap_size (s->intersected_elements);
652 msg_length = sizeof (struct EccAliceCryptodataMessage)
653 + contained_elements * sizeof (struct GNUNET_CRYPTO_EccPoint) * 2;
654 if ( (msize != msg_length) ||
655 (0 == contained_elements) ||
656 (contained_elements > UINT16_MAX) ||
657 (max < contained_elements + s->cadet_received_element_count) )
658 {
659 GNUNET_break_op (0);
660 return GNUNET_SYSERR;
661 }
662 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 521 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
663 "Received %u crypto values from Alice\n", 522 "Received %u crypto values from Alice\n",
664 (unsigned int) contained_elements); 523 (unsigned int) contained_elements);
@@ -711,8 +570,7 @@ handle_alices_cryptodata_message (void *cls,
711 CADET response(s) */ 570 CADET response(s) */
712 transmit_bobs_cryptodata_message (s); 571 transmit_bobs_cryptodata_message (s);
713 } 572 }
714 GNUNET_CADET_receive_done (s->cadet->channel); 573 GNUNET_CADET_receive_done (s->channel);
715 return GNUNET_OK;
716} 574}
717 575
718 576
@@ -722,11 +580,13 @@ handle_alices_cryptodata_message (void *cls,
722 * 580 *
723 * @param cls closure with the `struct BobServiceSession` 581 * @param cls closure with the `struct BobServiceSession`
724 * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK 582 * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
583 * @param current_size current set size
725 * @param status what has happened with the set intersection? 584 * @param status what has happened with the set intersection?
726 */ 585 */
727static void 586static void
728cb_intersection_element_removed (void *cls, 587cb_intersection_element_removed (void *cls,
729 const struct GNUNET_SET_Element *element, 588 const struct GNUNET_SET_Element *element,
589 uint64_t current_size,
730 enum GNUNET_SET_Status status) 590 enum GNUNET_SET_Status status)
731{ 591{
732 struct BobServiceSession *s = cls; 592 struct BobServiceSession *s = cls;
@@ -752,7 +612,7 @@ cb_intersection_element_removed (void *cls,
752 case GNUNET_SET_STATUS_DONE: 612 case GNUNET_SET_STATUS_DONE:
753 s->intersection_op = NULL; 613 s->intersection_op = NULL;
754 GNUNET_break (NULL == s->intersection_set); 614 GNUNET_break (NULL == s->intersection_set);
755 GNUNET_CADET_receive_done (s->cadet->channel); 615 GNUNET_CADET_receive_done (s->channel);
756 LOG (GNUNET_ERROR_TYPE_DEBUG, 616 LOG (GNUNET_ERROR_TYPE_DEBUG,
757 "Finished intersection, %d items remain\n", 617 "Finished intersection, %d items remain\n",
758 GNUNET_CONTAINER_multihashmap_size (s->intersected_elements)); 618 GNUNET_CONTAINER_multihashmap_size (s->intersected_elements));
@@ -808,10 +668,11 @@ start_intersection (struct BobServiceSession *s)
808 (unsigned int) s->total); 668 (unsigned int) s->total);
809 669
810 s->intersection_op 670 s->intersection_op
811 = GNUNET_SET_prepare (&s->cadet->peer, 671 = GNUNET_SET_prepare (&s->peer,
812 &set_sid, 672 &set_sid,
813 NULL, 673 NULL,
814 GNUNET_SET_RESULT_REMOVED, 674 GNUNET_SET_RESULT_REMOVED,
675 (struct GNUNET_SET_Option[]) {{ 0 }},
815 &cb_intersection_element_removed, 676 &cb_intersection_element_removed,
816 s); 677 s);
817 if (GNUNET_OK != 678 if (GNUNET_OK !=
@@ -832,53 +693,24 @@ start_intersection (struct BobServiceSession *s)
832 * Handle a request from Alice to calculate a scalarproduct with us (Bob). 693 * Handle a request from Alice to calculate a scalarproduct with us (Bob).
833 * 694 *
834 * @param cls closure (set from #GNUNET_CADET_connect) 695 * @param cls closure (set from #GNUNET_CADET_connect)
835 * @param channel connection to the other end 696 * @param msg the actual message
836 * @param channel_ctx place to store the `struct CadetIncomingSession *`
837 * @param message the actual message
838 * @return #GNUNET_OK to keep the connection open,
839 * #GNUNET_SYSERR to close it (signal serious error)
840 */ 697 */
841static int 698static void
842handle_alices_computation_request (void *cls, 699handle_alices_computation_request (void *cls,
843 struct GNUNET_CADET_Channel *channel, 700 const struct EccServiceRequestMessage *msg)
844 void **channel_ctx,
845 const struct GNUNET_MessageHeader *message)
846{ 701{
847 struct CadetIncomingSession *in = *channel_ctx; 702 struct BobServiceSession *s = cls;
848 struct BobServiceSession *s;
849 const struct EccServiceRequestMessage *msg;
850 703
851 msg = (const struct EccServiceRequestMessage *) message; 704 s->session_id = msg->session_id; // ??
852 if (GNUNET_YES == in->in_map) 705 if (s->client_received_element_count < s->total)
853 { 706 {
854 GNUNET_break_op (0); 707 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
855 return GNUNET_SYSERR; 708 "Alice ready, still waiting for Bob client data!\n");
856 } 709 return;
857 if (NULL != find_matching_cadet_session (&msg->session_id))
858 {
859 /* not unique, got one like this already */
860 GNUNET_break_op (0);
861 return GNUNET_SYSERR;
862 }
863 in->session_id = msg->session_id;
864 GNUNET_assert (GNUNET_YES ==
865 GNUNET_CONTAINER_multihashmap_put (cadet_sessions,
866 &in->session_id,
867 in,
868 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
869 s = find_matching_client_session (&in->session_id);
870 if (NULL == s)
871 {
872 /* no client waiting for this request, wait for client */
873 return GNUNET_OK;
874 } 710 }
875 GNUNET_assert (NULL == s->cadet); 711 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
876 /* pair them up */ 712 "Both ready, launching intersection!\n");
877 in->s = s; 713 start_intersection (s);
878 s->cadet = in;
879 if (s->client_received_element_count == s->total)
880 start_intersection (s);
881 return GNUNET_OK;
882} 714}
883 715
884 716
@@ -887,30 +719,27 @@ handle_alices_computation_request (void *cls,
887 * preliminary initialization, more happens after we get Alice's first 719 * preliminary initialization, more happens after we get Alice's first
888 * message. 720 * message.
889 * 721 *
890 * @param cls closure 722 * @param cls our `struct BobServiceSession`
891 * @param channel new handle to the channel 723 * @param channel new handle to the channel
892 * @param initiator peer that started the channel 724 * @param initiator peer that started the channel
893 * @param port unused
894 * @param options unused
895 * @return session associated with the channel 725 * @return session associated with the channel
896 */ 726 */
897static void * 727static void *
898cb_channel_incoming (void *cls, 728cb_channel_incoming (void *cls,
899 struct GNUNET_CADET_Channel *channel, 729 struct GNUNET_CADET_Channel *channel,
900 const struct GNUNET_PeerIdentity *initiator, 730 const struct GNUNET_PeerIdentity *initiator)
901 const struct GNUNET_HashCode *port,
902 enum GNUNET_CADET_ChannelOption options)
903{ 731{
904 struct CadetIncomingSession *in; 732 struct BobServiceSession *s = cls;
905 733
906 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 734 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
907 "New incoming channel from peer %s.\n", 735 "New incoming channel from peer %s.\n",
908 GNUNET_i2s (initiator)); 736 GNUNET_i2s (initiator));
909 in = GNUNET_new (struct CadetIncomingSession); 737 GNUNET_CADET_close_port (s->port);
910 in->peer = *initiator; 738 s->port = NULL;
911 in->channel = channel; 739 s->peer = *initiator;
912 in->cadet_mq = GNUNET_CADET_mq_create (in->channel); 740 s->channel = channel;
913 return in; 741 s->cadet_mq = GNUNET_CADET_get_mq (s->channel);
742 return s;
914} 743}
915 744
916 745
@@ -992,13 +821,19 @@ handle_bob_client_message_multipart (void *cls,
992 if (s->total != s->client_received_element_count) 821 if (s->total != s->client_received_element_count)
993 { 822 {
994 /* more to come */ 823 /* more to come */
824 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
825 "Request still partial, waiting for more client data!\n");
995 return; 826 return;
996 } 827 }
997 if (NULL == s->cadet) 828 if (NULL == s->channel)
998 { 829 {
999 /* no Alice waiting for this request, wait for Alice */ 830 /* no Alice waiting for this request, wait for Alice */
831 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
832 "Client ready, still waiting for Alice!\n");
1000 return; 833 return;
1001 } 834 }
835 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
836 "Both ready, launching intersection!\n");
1002 start_intersection (s); 837 start_intersection (s);
1003} 838}
1004 839
@@ -1037,11 +872,6 @@ check_bob_client_message (void *cls,
1037 GNUNET_break_op (0); 872 GNUNET_break_op (0);
1038 return GNUNET_SYSERR; 873 return GNUNET_SYSERR;
1039 } 874 }
1040 if (NULL != find_matching_client_session (&msg->session_key))
1041 {
1042 GNUNET_break (0);
1043 return GNUNET_SYSERR;
1044 }
1045 return GNUNET_OK; 875 return GNUNET_OK;
1046} 876}
1047 877
@@ -1059,7 +889,17 @@ handle_bob_client_message (void *cls,
1059 const struct BobComputationMessage *msg) 889 const struct BobComputationMessage *msg)
1060{ 890{
1061 struct BobServiceSession *s = cls; 891 struct BobServiceSession *s = cls;
1062 struct CadetIncomingSession *in; 892 struct GNUNET_MQ_MessageHandler cadet_handlers[] = {
893 GNUNET_MQ_hd_fixed_size (alices_computation_request,
894 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_SESSION_INITIALIZATION,
895 struct EccServiceRequestMessage,
896 s),
897 GNUNET_MQ_hd_var_size (alices_cryptodata_message,
898 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_ALICE_CRYPTODATA,
899 struct EccAliceCryptodataMessage,
900 s),
901 GNUNET_MQ_handler_end ()
902 };
1063 uint32_t contained_count; 903 uint32_t contained_count;
1064 uint32_t total_count; 904 uint32_t total_count;
1065 const struct GNUNET_SCALARPRODUCT_Element *elements; 905 const struct GNUNET_SCALARPRODUCT_Element *elements;
@@ -1073,21 +913,6 @@ handle_bob_client_message (void *cls,
1073 s->total = total_count; 913 s->total = total_count;
1074 s->client_received_element_count = contained_count; 914 s->client_received_element_count = contained_count;
1075 s->session_id = msg->session_key; 915 s->session_id = msg->session_key;
1076 s->port = GNUNET_CADET_open_port (my_cadet,
1077 &msg->session_key,
1078 &cb_channel_incoming,
1079 s);
1080 if (NULL == s->port)
1081 {
1082 GNUNET_break (0);
1083 GNUNET_SERVICE_client_drop (s->client);
1084 return;
1085 }
1086 GNUNET_break (GNUNET_YES ==
1087 GNUNET_CONTAINER_multihashmap_put (client_sessions,
1088 &s->session_id,
1089 s,
1090 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1091 elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1]; 916 elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
1092 s->intersected_elements 917 s->intersected_elements
1093 = GNUNET_CONTAINER_multihashmap_create (s->total, 918 = GNUNET_CONTAINER_multihashmap_create (s->total,
@@ -1122,22 +947,22 @@ handle_bob_client_message (void *cls,
1122 s->used_element_count++; 947 s->used_element_count++;
1123 } 948 }
1124 GNUNET_SERVICE_client_continue (s->client); 949 GNUNET_SERVICE_client_continue (s->client);
1125 if (s->total != s->client_received_element_count) 950 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1126 { 951 "Received client request, opening port %s!\n",
1127 /* multipart msg */ 952 GNUNET_h2s (&msg->session_key));
1128 return; 953 s->port = GNUNET_CADET_open_port (my_cadet,
1129 } 954 &msg->session_key,
1130 in = find_matching_cadet_session (&s->session_id); 955 &cb_channel_incoming,
1131 if (NULL == in) 956 s,
957 NULL,
958 &cb_channel_destruction,
959 cadet_handlers);
960 if (NULL == s->port)
1132 { 961 {
1133 /* nothing yet, wait for Alice */ 962 GNUNET_break (0);
963 GNUNET_SERVICE_client_drop (s->client);
1134 return; 964 return;
1135 } 965 }
1136 GNUNET_assert (NULL == in->s);
1137 /* pair them up */
1138 in->s = s;
1139 s->cadet = in;
1140 start_intersection (s);
1141} 966}
1142 967
1143 968
@@ -1162,10 +987,6 @@ shutdown_task (void *cls)
1162 GNUNET_CRYPTO_ecc_dlog_release (edc); 987 GNUNET_CRYPTO_ecc_dlog_release (edc);
1163 edc = NULL; 988 edc = NULL;
1164 } 989 }
1165 GNUNET_CONTAINER_multihashmap_destroy (client_sessions);
1166 client_sessions = NULL;
1167 GNUNET_CONTAINER_multihashmap_destroy (cadet_sessions);
1168 cadet_sessions = NULL;
1169} 990}
1170 991
1171 992
@@ -1229,28 +1050,11 @@ run (void *cls,
1229 const struct GNUNET_CONFIGURATION_Handle *c, 1050 const struct GNUNET_CONFIGURATION_Handle *c,
1230 struct GNUNET_SERVICE_Handle *service) 1051 struct GNUNET_SERVICE_Handle *service)
1231{ 1052{
1232 static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
1233 { &handle_alices_computation_request,
1234 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_SESSION_INITIALIZATION,
1235 sizeof (struct EccServiceRequestMessage) },
1236 { &handle_alices_cryptodata_message,
1237 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_ALICE_CRYPTODATA,
1238 0},
1239 { NULL, 0, 0}
1240 };
1241
1242 cfg = c; 1053 cfg = c;
1243 /* 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 */
1244 edc = GNUNET_CRYPTO_ecc_dlog_prepare (4 /* max value */, 1055 edc = GNUNET_CRYPTO_ecc_dlog_prepare (4 /* max value */,
1245 2 /* RAM */); 1056 2 /* RAM */);
1246 client_sessions = GNUNET_CONTAINER_multihashmap_create (128, 1057 my_cadet = GNUNET_CADET_connect (cfg);
1247 GNUNET_YES);
1248 cadet_sessions = GNUNET_CONTAINER_multihashmap_create (128,
1249 GNUNET_YES);
1250 my_cadet = GNUNET_CADET_connect (cfg,
1251 NULL,
1252 &cb_channel_destruction,
1253 cadet_handlers);
1254 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, 1058 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1255 NULL); 1059 NULL);
1256 if (NULL == my_cadet) 1060 if (NULL == my_cadet)
@@ -1277,10 +1081,10 @@ GNUNET_SERVICE_MAIN
1277 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_BOB, 1081 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_BOB,
1278 struct BobComputationMessage, 1082 struct BobComputationMessage,
1279 NULL), 1083 NULL),
1280GNUNET_MQ_hd_var_size (bob_client_message_multipart, 1084 GNUNET_MQ_hd_var_size (bob_client_message_multipart,
1281 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MULTIPART_BOB, 1085 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MULTIPART_BOB,
1282 struct ComputationBobCryptodataMultipartMessage, 1086 struct ComputationBobCryptodataMultipartMessage,
1283 NULL), 1087 NULL),
1284 GNUNET_MQ_handler_end ()); 1088 GNUNET_MQ_handler_end ());
1285 1089
1286 1090
diff --git a/src/scalarproduct/gnunet-service-scalarproduct_alice.c b/src/scalarproduct/gnunet-service-scalarproduct_alice.c
index 45d1f4e2c..a55d03900 100644
--- a/src/scalarproduct/gnunet-service-scalarproduct_alice.c
+++ b/src/scalarproduct/gnunet-service-scalarproduct_alice.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, 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
@@ -248,15 +248,10 @@ destroy_service_session (struct AliceServiceSession *s)
248 if (GNUNET_YES == s->in_destroy) 248 if (GNUNET_YES == s->in_destroy)
249 return; 249 return;
250 s->in_destroy = GNUNET_YES; 250 s->in_destroy = GNUNET_YES;
251 if (NULL != s->cadet_mq)
252 {
253 GNUNET_MQ_destroy (s->cadet_mq);
254 s->cadet_mq = NULL;
255 }
256 if (NULL != s->client) 251 if (NULL != s->client)
257 { 252 {
258 struct GNUNET_SERVICE_Client *c = s->client; 253 struct GNUNET_SERVICE_Client *c = s->client;
259 254
260 s->client = NULL; 255 s->client = NULL;
261 GNUNET_SERVICE_client_drop (c); 256 GNUNET_SERVICE_client_drop (c);
262 } 257 }
@@ -428,17 +423,14 @@ transmit_client_response (struct AliceServiceSession *s)
428 * 423 *
429 * It must NOT call #GNUNET_CADET_channel_destroy() on the channel. 424 * It must NOT call #GNUNET_CADET_channel_destroy() on the channel.
430 * 425 *
431 * @param cls closure (set from #GNUNET_CADET_connect()) 426 * @param cls our `struct AliceServiceSession`
432 * @param channel connection to the other end (henceforth invalid) 427 * @param channel connection to the other end (henceforth invalid)
433 * @param channel_ctx place where local state associated
434 * with the channel is stored
435 */ 428 */
436static void 429static void
437cb_channel_destruction (void *cls, 430cb_channel_destruction (void *cls,
438 const struct GNUNET_CADET_Channel *channel, 431 const struct GNUNET_CADET_Channel *channel)
439 void *channel_ctx)
440{ 432{
441 struct AliceServiceSession *s = channel_ctx; 433 struct AliceServiceSession *s = cls;
442 434
443 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 435 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
444 "Peer disconnected, terminating session %s with peer %s\n", 436 "Peer disconnected, terminating session %s with peer %s\n",
@@ -450,11 +442,6 @@ cb_channel_destruction (void *cls,
450 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE; 442 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
451 prepare_client_end_notification (s); 443 prepare_client_end_notification (s);
452 } 444 }
453 if (NULL != s->cadet_mq)
454 {
455 GNUNET_MQ_destroy (s->cadet_mq);
456 s->cadet_mq = NULL;
457 }
458 s->channel = NULL; 445 s->channel = NULL;
459} 446}
460 447
@@ -633,42 +620,24 @@ compute_scalar_product (struct AliceServiceSession *session)
633 620
634 621
635/** 622/**
636 * Handle a multipart chunk of a response we got from another service 623 * Check a multipart chunk of a response we got from another service
637 * we wanted to calculate a scalarproduct with. 624 * we wanted to calculate a scalarproduct with.
638 * 625 *
639 * @param cls closure (set from #GNUNET_CADET_connect) 626 * @param cls the `struct AliceServiceSession`
640 * @param channel connection to the other end 627 * @param msg the actual message
641 * @param channel_ctx place to store local state associated with the @a channel
642 * @param message the actual message
643 * @return #GNUNET_OK to keep the connection open, 628 * @return #GNUNET_OK to keep the connection open,
644 * #GNUNET_SYSERR to close it (signal serious error) 629 * #GNUNET_SYSERR to close it (signal serious error)
645 */ 630 */
646static int 631static int
647handle_bobs_cryptodata_multipart (void *cls, 632check_bobs_cryptodata_multipart (void *cls,
648 struct GNUNET_CADET_Channel *channel, 633 const struct BobCryptodataMultipartMessage *msg)
649 void **channel_ctx,
650 const struct GNUNET_MessageHeader *message)
651{ 634{
652 struct AliceServiceSession *s = *channel_ctx; 635 struct AliceServiceSession *s = cls;
653 const struct BobCryptodataMultipartMessage *msg;
654 const struct GNUNET_CRYPTO_PaillierCiphertext *payload;
655 size_t i;
656 uint32_t contained; 636 uint32_t contained;
657 size_t msg_size; 637 size_t msg_size;
658 size_t required_size; 638 size_t required_size;
659 639
660 if (NULL == s) 640 msg_size = ntohs (msg->header.size);
661 {
662 GNUNET_break_op (0);
663 return GNUNET_SYSERR;
664 }
665 msg_size = ntohs (message->size);
666 if (sizeof (struct BobCryptodataMultipartMessage) > msg_size)
667 {
668 GNUNET_break_op (0);
669 return GNUNET_SYSERR;
670 }
671 msg = (const struct BobCryptodataMultipartMessage *) message;
672 contained = ntohl (msg->contained_element_count); 641 contained = ntohl (msg->contained_element_count);
673 required_size = sizeof (struct BobCryptodataMultipartMessage) 642 required_size = sizeof (struct BobCryptodataMultipartMessage)
674 + 2 * contained * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext); 643 + 2 * contained * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
@@ -678,7 +647,26 @@ handle_bobs_cryptodata_multipart (void *cls,
678 GNUNET_break (0); 647 GNUNET_break (0);
679 return GNUNET_SYSERR; 648 return GNUNET_SYSERR;
680 } 649 }
650 return GNUNET_OK;
651}
681 652
653/**
654 * Handle a multipart chunk of a response we got from another service
655 * we wanted to calculate a scalarproduct with.
656 *
657 * @param cls the `struct AliceServiceSession`
658 * @param msg the actual message
659 */
660static void
661handle_bobs_cryptodata_multipart (void *cls,
662 const struct BobCryptodataMultipartMessage *msg)
663{
664 struct AliceServiceSession *s = cls;
665 const struct GNUNET_CRYPTO_PaillierCiphertext *payload;
666 size_t i;
667 uint32_t contained;
668
669 contained = ntohl (msg->contained_element_count);
682 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 670 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
683 "Received %u additional crypto values from Bob\n", 671 "Received %u additional crypto values from Bob\n",
684 (unsigned int) contained); 672 (unsigned int) contained);
@@ -688,60 +676,41 @@ handle_bobs_cryptodata_multipart (void *cls,
688 for (i = 0; i < contained; i++) 676 for (i = 0; i < contained; i++)
689 { 677 {
690 GNUNET_memcpy (&s->r[s->cadet_received_element_count + i], 678 GNUNET_memcpy (&s->r[s->cadet_received_element_count + i],
691 &payload[2 * i], 679 &payload[2 * i],
692 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)); 680 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
693 GNUNET_memcpy (&s->r_prime[s->cadet_received_element_count + i], 681 GNUNET_memcpy (&s->r_prime[s->cadet_received_element_count + i],
694 &payload[2 * i], 682 &payload[2 * i],
695 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)); 683 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
696 } 684 }
697 s->cadet_received_element_count += contained; 685 s->cadet_received_element_count += contained;
698 GNUNET_CADET_receive_done (s->channel); 686 GNUNET_CADET_receive_done (s->channel);
699 if (s->cadet_received_element_count != s->used_element_count) 687 if (s->cadet_received_element_count != s->used_element_count)
700 return GNUNET_OK; 688 return; /* more to come */
701 689
702 s->product = compute_scalar_product (s); 690 s->product = compute_scalar_product (s);
703 transmit_client_response (s); 691 transmit_client_response (s);
704 return GNUNET_OK;
705} 692}
706 693
707 694
708/** 695/**
709 * Handle a response we got from another service we wanted to 696 * Check a response we got from another service we wanted to
710 * calculate a scalarproduct with. 697 * calculate a scalarproduct with.
711 * 698 *
712 * @param cls closure (set from #GNUNET_CADET_connect) 699 * @param cls our `struct AliceServiceSession`
713 * @param channel connection to the other end
714 * @param channel_ctx place to store local state associated with the channel
715 * @param message the actual message 700 * @param message the actual message
716 * @return #GNUNET_OK to keep the connection open, 701 * @return #GNUNET_OK to keep the connection open,
717 * #GNUNET_SYSERR to close it (we are done) 702 * #GNUNET_SYSERR to close it (we are done)
718 */ 703 */
719static int 704static int
720handle_bobs_cryptodata_message (void *cls, 705check_bobs_cryptodata_message (void *cls,
721 struct GNUNET_CADET_Channel *channel, 706 const struct BobCryptodataMessage *msg)
722 void **channel_ctx,
723 const struct GNUNET_MessageHeader *message)
724{ 707{
725 struct AliceServiceSession *s = *channel_ctx; 708 struct AliceServiceSession *s = cls;
726 const struct BobCryptodataMessage *msg;
727 const struct GNUNET_CRYPTO_PaillierCiphertext *payload;
728 uint32_t i;
729 uint32_t contained; 709 uint32_t contained;
730 uint16_t msg_size; 710 uint16_t msg_size;
731 size_t required_size; 711 size_t required_size;
732 712
733 if (NULL == s) 713 msg_size = ntohs (msg->header.size);
734 {
735 GNUNET_break_op (0);
736 return GNUNET_SYSERR;
737 }
738 msg_size = ntohs (message->size);
739 if (sizeof (struct BobCryptodataMessage) > msg_size)
740 {
741 GNUNET_break_op (0);
742 return GNUNET_SYSERR;
743 }
744 msg = (const struct BobCryptodataMessage *) message;
745 contained = ntohl (msg->contained_element_count); 714 contained = ntohl (msg->contained_element_count);
746 required_size = sizeof (struct BobCryptodataMessage) 715 required_size = sizeof (struct BobCryptodataMessage)
747 + 2 * contained * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) 716 + 2 * contained * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)
@@ -765,29 +734,51 @@ handle_bobs_cryptodata_message (void *cls,
765 GNUNET_break_op (0); 734 GNUNET_break_op (0);
766 return GNUNET_SYSERR; 735 return GNUNET_SYSERR;
767 } 736 }
737 return GNUNET_OK;
738}
739
740
741/**
742 * Handle a response we got from another service we wanted to
743 * calculate a scalarproduct with.
744 *
745 * @param cls our `struct AliceServiceSession`
746 * @param msg the actual message
747 */
748static void
749handle_bobs_cryptodata_message (void *cls,
750 const struct BobCryptodataMessage *msg)
751{
752 struct AliceServiceSession *s = cls;
753 const struct GNUNET_CRYPTO_PaillierCiphertext *payload;
754 uint32_t i;
755 uint32_t contained;
756
757 contained = ntohl (msg->contained_element_count);
768 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 758 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
769 "Received %u crypto values from Bob\n", 759 "Received %u crypto values from Bob\n",
770 (unsigned int) contained); 760 (unsigned int) contained);
771
772 payload = (const struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1]; 761 payload = (const struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
773 GNUNET_memcpy (&s->s, 762 GNUNET_memcpy (&s->s,
774 &payload[0], 763 &payload[0],
775 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)); 764 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
776 GNUNET_memcpy (&s->s_prime, 765 GNUNET_memcpy (&s->s_prime,
777 &payload[1], 766 &payload[1],
778 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)); 767 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
779 payload = &payload[2]; 768 payload = &payload[2];
780 769
781 s->r = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * s->used_element_count); 770 s->r = GNUNET_new_array (s->used_element_count,
782 s->r_prime = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * s->used_element_count); 771 struct GNUNET_CRYPTO_PaillierCiphertext);
772 s->r_prime = GNUNET_new_array (s->used_element_count,
773 struct GNUNET_CRYPTO_PaillierCiphertext);
783 for (i = 0; i < contained; i++) 774 for (i = 0; i < contained; i++)
784 { 775 {
785 GNUNET_memcpy (&s->r[i], 776 GNUNET_memcpy (&s->r[i],
786 &payload[2 * i], 777 &payload[2 * i],
787 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)); 778 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
788 GNUNET_memcpy (&s->r_prime[i], 779 GNUNET_memcpy (&s->r_prime[i],
789 &payload[2 * i + 1], 780 &payload[2 * i + 1],
790 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)); 781 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
791 } 782 }
792 s->cadet_received_element_count = contained; 783 s->cadet_received_element_count = contained;
793 GNUNET_CADET_receive_done (s->channel); 784 GNUNET_CADET_receive_done (s->channel);
@@ -795,12 +786,10 @@ handle_bobs_cryptodata_message (void *cls,
795 if (s->cadet_received_element_count != s->used_element_count) 786 if (s->cadet_received_element_count != s->used_element_count)
796 { 787 {
797 /* More to come */ 788 /* More to come */
798 return GNUNET_OK; 789 return;
799 } 790 }
800
801 s->product = compute_scalar_product (s); 791 s->product = compute_scalar_product (s);
802 transmit_client_response (s); 792 transmit_client_response (s);
803 return GNUNET_OK;
804} 793}
805 794
806 795
@@ -935,11 +924,13 @@ send_alices_cryptodata_message (struct AliceServiceSession *s)
935 * 924 *
936 * @param cls closure with the `struct AliceServiceSession` 925 * @param cls closure with the `struct AliceServiceSession`
937 * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK 926 * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
927 * @param current_size current set size
938 * @param status what has happened with the set intersection? 928 * @param status what has happened with the set intersection?
939 */ 929 */
940static void 930static void
941cb_intersection_element_removed (void *cls, 931cb_intersection_element_removed (void *cls,
942 const struct GNUNET_SET_Element *element, 932 const struct GNUNET_SET_Element *element,
933 uint64_t current_size,
943 enum GNUNET_SET_Status status) 934 enum GNUNET_SET_Status status)
944{ 935{
945 struct AliceServiceSession *s = cls; 936 struct AliceServiceSession *s = cls;
@@ -1033,6 +1024,7 @@ cb_intersection_request_alice (void *cls,
1033 s->intersection_op 1024 s->intersection_op
1034 = GNUNET_SET_accept (request, 1025 = GNUNET_SET_accept (request,
1035 GNUNET_SET_RESULT_REMOVED, 1026 GNUNET_SET_RESULT_REMOVED,
1027 (struct GNUNET_SET_Option[]) {{ 0 }},
1036 &cb_intersection_element_removed, 1028 &cb_intersection_element_removed,
1037 s); 1029 s);
1038 if (NULL == s->intersection_op) 1030 if (NULL == s->intersection_op)
@@ -1066,6 +1058,17 @@ cb_intersection_request_alice (void *cls,
1066static void 1058static void
1067client_request_complete_alice (struct AliceServiceSession *s) 1059client_request_complete_alice (struct AliceServiceSession *s)
1068{ 1060{
1061 struct GNUNET_MQ_MessageHandler cadet_handlers[] = {
1062 GNUNET_MQ_hd_var_size (bobs_cryptodata_message,
1063 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA,
1064 struct BobCryptodataMessage,
1065 s),
1066 GNUNET_MQ_hd_var_size (bobs_cryptodata_multipart,
1067 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA_MULTIPART,
1068 struct BobCryptodataMultipartMessage,
1069 s),
1070 GNUNET_MQ_handler_end ()
1071 };
1069 struct ServiceRequestMessage *msg; 1072 struct ServiceRequestMessage *msg;
1070 struct GNUNET_MQ_Envelope *e; 1073 struct GNUNET_MQ_Envelope *e;
1071 1074
@@ -1077,14 +1080,17 @@ client_request_complete_alice (struct AliceServiceSession *s)
1077 s, 1080 s,
1078 &s->peer, 1081 &s->peer,
1079 &s->session_id, 1082 &s->session_id,
1080 GNUNET_CADET_OPTION_RELIABLE); 1083 GNUNET_CADET_OPTION_RELIABLE,
1084 NULL,
1085 &cb_channel_destruction,
1086 cadet_handlers);
1081 if (NULL == s->channel) 1087 if (NULL == s->channel)
1082 { 1088 {
1083 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE; 1089 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
1084 prepare_client_end_notification (s); 1090 prepare_client_end_notification (s);
1085 return; 1091 return;
1086 } 1092 }
1087 s->cadet_mq = GNUNET_CADET_mq_create (s->channel); 1093 s->cadet_mq = GNUNET_CADET_get_mq (s->channel);
1088 s->intersection_listen 1094 s->intersection_listen
1089 = GNUNET_SET_listen (cfg, 1095 = GNUNET_SET_listen (cfg,
1090 GNUNET_SET_OPERATION_INTERSECTION, 1096 GNUNET_SET_OPERATION_INTERSECTION,
@@ -1110,7 +1116,7 @@ client_request_complete_alice (struct AliceServiceSession *s)
1110 1116
1111 1117
1112/** 1118/**
1113 * We're receiving additional set data. Check if 1119 * We're receiving additional set data. Check if
1114 * @a msg is well-formed. 1120 * @a msg is well-formed.
1115 * 1121 *
1116 * @param cls client identification of the client 1122 * @param cls client identification of the client
@@ -1118,7 +1124,7 @@ client_request_complete_alice (struct AliceServiceSession *s)
1118 * @return #GNUNET_OK if @a msg is well-formed 1124 * @return #GNUNET_OK if @a msg is well-formed
1119 */ 1125 */
1120static int 1126static int
1121check_alice_client_message_multipart (void *cls, 1127check_alice_client_message_multipart (void *cls,
1122 const struct ComputationBobCryptodataMultipartMessage *msg) 1128 const struct ComputationBobCryptodataMultipartMessage *msg)
1123{ 1129{
1124 struct AliceServiceSession *s = cls; 1130 struct AliceServiceSession *s = cls;
@@ -1148,7 +1154,7 @@ check_alice_client_message_multipart (void *cls,
1148 * @param msg the actual message 1154 * @param msg the actual message
1149 */ 1155 */
1150static void 1156static void
1151handle_alice_client_message_multipart (void *cls, 1157handle_alice_client_message_multipart (void *cls,
1152 const struct ComputationBobCryptodataMultipartMessage *msg) 1158 const struct ComputationBobCryptodataMultipartMessage *msg)
1153{ 1159{
1154 struct AliceServiceSession *s = cls; 1160 struct AliceServiceSession *s = cls;
@@ -1203,7 +1209,7 @@ handle_alice_client_message_multipart (void *cls,
1203 * @return #GNUNET_OK if @a msg is well-formed 1209 * @return #GNUNET_OK if @a msg is well-formed
1204 */ 1210 */
1205static int 1211static int
1206check_alice_client_message (void *cls, 1212check_alice_client_message (void *cls,
1207 const struct AliceComputationMessage *msg) 1213 const struct AliceComputationMessage *msg)
1208{ 1214{
1209 struct AliceServiceSession *s = cls; 1215 struct AliceServiceSession *s = cls;
@@ -1232,7 +1238,7 @@ check_alice_client_message (void *cls,
1232 return GNUNET_OK; 1238 return GNUNET_OK;
1233} 1239}
1234 1240
1235 1241
1236/** 1242/**
1237 * Handler for Alice's client request message. 1243 * Handler for Alice's client request message.
1238 * We are doing request-initiation to compute a scalar product with a peer. 1244 * We are doing request-initiation to compute a scalar product with a peer.
@@ -1241,7 +1247,7 @@ check_alice_client_message (void *cls,
1241 * @param msg the actual message 1247 * @param msg the actual message
1242 */ 1248 */
1243static void 1249static void
1244handle_alice_client_message (void *cls, 1250handle_alice_client_message (void *cls,
1245 const struct AliceComputationMessage *msg) 1251 const struct AliceComputationMessage *msg)
1246{ 1252{
1247 struct AliceServiceSession *s = cls; 1253 struct AliceServiceSession *s = cls;
@@ -1382,16 +1388,6 @@ run (void *cls,
1382 const struct GNUNET_CONFIGURATION_Handle *c, 1388 const struct GNUNET_CONFIGURATION_Handle *c,
1383 struct GNUNET_SERVICE_Handle *service) 1389 struct GNUNET_SERVICE_Handle *service)
1384{ 1390{
1385 static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
1386 { &handle_bobs_cryptodata_message,
1387 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA,
1388 0},
1389 { &handle_bobs_cryptodata_multipart,
1390 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA_MULTIPART,
1391 0},
1392 { NULL, 0, 0}
1393 };
1394
1395 cfg = c; 1391 cfg = c;
1396 /* 1392 /*
1397 offset has to be sufficiently small to allow computation of: 1393 offset has to be sufficiently small to allow computation of:
@@ -1400,13 +1396,9 @@ run (void *cls,
1400 my_offset = gcry_mpi_new (GNUNET_CRYPTO_PAILLIER_BITS / 3); 1396 my_offset = gcry_mpi_new (GNUNET_CRYPTO_PAILLIER_BITS / 3);
1401 gcry_mpi_set_bit (my_offset, 1397 gcry_mpi_set_bit (my_offset,
1402 GNUNET_CRYPTO_PAILLIER_BITS / 3); 1398 GNUNET_CRYPTO_PAILLIER_BITS / 3);
1403
1404 GNUNET_CRYPTO_paillier_create (&my_pubkey, 1399 GNUNET_CRYPTO_paillier_create (&my_pubkey,
1405 &my_privkey); 1400 &my_privkey);
1406 my_cadet = GNUNET_CADET_connect (cfg, 1401 my_cadet = GNUNET_CADET_connect (cfg);
1407 NULL,
1408 &cb_channel_destruction,
1409 cadet_handlers);
1410 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, 1402 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1411 NULL); 1403 NULL);
1412 if (NULL == my_cadet) 1404 if (NULL == my_cadet)
@@ -1437,7 +1429,7 @@ GNUNET_SERVICE_MAIN
1437 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MULTIPART_ALICE, 1429 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MULTIPART_ALICE,
1438 struct ComputationBobCryptodataMultipartMessage, 1430 struct ComputationBobCryptodataMultipartMessage,
1439 NULL), 1431 NULL),
1440 GNUNET_MQ_handler_end ()); 1432 GNUNET_MQ_handler_end ());
1441 1433
1442 1434
1443/* end of gnunet-service-scalarproduct_alice.c */ 1435/* end of gnunet-service-scalarproduct_alice.c */
diff --git a/src/scalarproduct/gnunet-service-scalarproduct_bob.c b/src/scalarproduct/gnunet-service-scalarproduct_bob.c
index 56cb91fe5..0c38cb426 100644
--- a/src/scalarproduct/gnunet-service-scalarproduct_bob.c
+++ b/src/scalarproduct/gnunet-service-scalarproduct_bob.c
@@ -59,12 +59,6 @@ struct MpiElement
59 59
60 60
61/** 61/**
62 * An incoming session from CADET.
63 */
64struct CadetIncomingSession;
65
66
67/**
68 * A scalarproduct session which tracks an offer for a 62 * A scalarproduct session which tracks an offer for a
69 * multiplication service by a local client. 63 * multiplication service by a local client.
70 */ 64 */
@@ -187,20 +181,6 @@ struct BobServiceSession
187 */ 181 */
188 int in_destroy; 182 int in_destroy;
189 183
190};
191
192
193/**
194 * An incoming session from CADET.
195 */
196struct CadetIncomingSession
197{
198
199 /**
200 * Associated client session, or NULL.
201 */
202 struct BobServiceSession *s;
203
204 /** 184 /**
205 * The CADET channel. 185 * The CADET channel.
206 */ 186 */
@@ -212,11 +192,6 @@ struct CadetIncomingSession
212 struct GNUNET_PeerIdentity peer; 192 struct GNUNET_PeerIdentity peer;
213 193
214 /** 194 /**
215 * (hopefully) unique transaction ID
216 */
217 struct GNUNET_HashCode session_id;
218
219 /**
220 * Public key of the remote service. 195 * Public key of the remote service.
221 */ 196 */
222 struct GNUNET_CRYPTO_PaillierPublicKey remote_pubkey; 197 struct GNUNET_CRYPTO_PaillierPublicKey remote_pubkey;
@@ -226,21 +201,10 @@ struct CadetIncomingSession
226 */ 201 */
227 struct GNUNET_MQ_Handle *cadet_mq; 202 struct GNUNET_MQ_Handle *cadet_mq;
228 203
229 /**
230 * Has this CADET session been added to the map yet?
231 * #GNUNET_YES if so, in which case @e session_id is
232 * the key.
233 */
234 int in_map;
235
236 /**
237 * Are we already in #destroy_cadet_session()?
238 */
239 int in_destroy;
240
241}; 204};
242 205
243 206
207
244/** 208/**
245 * GNUnet configuration handle 209 * GNUnet configuration handle
246 */ 210 */
@@ -262,51 +226,11 @@ static struct GNUNET_CRYPTO_PaillierPrivateKey my_privkey;
262static gcry_mpi_t my_offset; 226static gcry_mpi_t my_offset;
263 227
264/** 228/**
265 * Map of `struct BobServiceSession`, by session keys.
266 */
267static struct GNUNET_CONTAINER_MultiHashMap *client_sessions;
268
269/**
270 * Map of `struct CadetIncomingSession`, by session keys.
271 */
272static struct GNUNET_CONTAINER_MultiHashMap *cadet_sessions;
273
274/**
275 * Handle to the CADET service. 229 * Handle to the CADET service.
276 */ 230 */
277static struct GNUNET_CADET_Handle *my_cadet; 231static struct GNUNET_CADET_Handle *my_cadet;
278 232
279 233
280
281/**
282 * Finds a not terminated client session in the respective map based on
283 * session key.
284 *
285 * @param key the session key we want to search for
286 * @return the matching session, or NULL for none
287 */
288static struct BobServiceSession *
289find_matching_client_session (const struct GNUNET_HashCode *key)
290{
291 return GNUNET_CONTAINER_multihashmap_get (client_sessions,
292 key);
293}
294
295
296/**
297 * Finds a CADET session in the respective map based on session key.
298 *
299 * @param key the session key we want to search for
300 * @return the matching session, or NULL for none
301 */
302static struct CadetIncomingSession *
303find_matching_cadet_session (const struct GNUNET_HashCode *key)
304{
305 return GNUNET_CONTAINER_multihashmap_get (cadet_sessions,
306 key);
307}
308
309
310/** 234/**
311 * Callback used to free the elements in the map. 235 * Callback used to free the elements in the map.
312 * 236 *
@@ -332,39 +256,20 @@ free_element_cb (void *cls,
332 * @param session the session to free elements from 256 * @param session the session to free elements from
333 */ 257 */
334static void 258static void
335destroy_cadet_session (struct CadetIncomingSession *s);
336
337
338/**
339 * Destroy session state, we are done with it.
340 *
341 * @param session the session to free elements from
342 */
343static void
344destroy_service_session (struct BobServiceSession *s) 259destroy_service_session (struct BobServiceSession *s)
345{ 260{
346 struct CadetIncomingSession *in;
347 unsigned int i; 261 unsigned int i;
348 262
349 if (GNUNET_YES == s->in_destroy) 263 if (GNUNET_YES == s->in_destroy)
350 return; 264 return;
351 s->in_destroy = GNUNET_YES; 265 s->in_destroy = GNUNET_YES;
352 if (NULL != (in = s->cadet))
353 {
354 s->cadet = NULL;
355 destroy_cadet_session (in);
356 }
357 if (NULL != s->client) 266 if (NULL != s->client)
358 { 267 {
359 struct GNUNET_SERVICE_Client *c = s->client; 268 struct GNUNET_SERVICE_Client *c = s->client;
360 269
361 s->client = NULL; 270 s->client = NULL;
362 GNUNET_SERVICE_client_drop (c); 271 GNUNET_SERVICE_client_drop (c);
363 } 272 }
364 GNUNET_assert (GNUNET_YES ==
365 GNUNET_CONTAINER_multihashmap_remove (client_sessions,
366 &s->session_id,
367 s));
368 if (NULL != s->intersected_elements) 273 if (NULL != s->intersected_elements)
369 { 274 {
370 GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements, 275 GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
@@ -405,48 +310,17 @@ destroy_service_session (struct BobServiceSession *s)
405 GNUNET_free (s->r_prime); 310 GNUNET_free (s->r_prime);
406 s->r_prime = NULL; 311 s->r_prime = NULL;
407 } 312 }
408 GNUNET_CADET_close_port (s->port); 313 if (NULL != s->port)
409 GNUNET_free (s);
410}
411
412
413/**
414 * Destroy incoming CADET session state, we are done with it.
415 *
416 * @param in the session to free elements from
417 */
418static void
419destroy_cadet_session (struct CadetIncomingSession *in)
420{
421 struct BobServiceSession *s;
422
423 if (GNUNET_YES == in->in_destroy)
424 return;
425 in->in_destroy = GNUNET_YES;
426 if (NULL != (s = in->s))
427 {
428 in->s = NULL;
429 destroy_service_session (s);
430 }
431 if (GNUNET_YES == in->in_map)
432 { 314 {
433 GNUNET_assert (GNUNET_YES == 315 GNUNET_CADET_close_port (s->port);
434 GNUNET_CONTAINER_multihashmap_remove (cadet_sessions, 316 s->port = NULL;
435 &in->session_id,
436 in));
437 in->in_map = GNUNET_NO;
438 }
439 if (NULL != in->cadet_mq)
440 {
441 GNUNET_MQ_destroy (in->cadet_mq);
442 in->cadet_mq = NULL;
443 } 317 }
444 if (NULL != in->channel) 318 if (NULL != s->channel)
445 { 319 {
446 GNUNET_CADET_channel_destroy (in->channel); 320 GNUNET_CADET_channel_destroy (s->channel);
447 in->channel = NULL; 321 s->channel = NULL;
448 } 322 }
449 GNUNET_free (in); 323 GNUNET_free (s);
450} 324}
451 325
452 326
@@ -485,38 +359,26 @@ prepare_client_end_notification (struct BobServiceSession *session)
485 * 359 *
486 * It must NOT call #GNUNET_CADET_channel_destroy() on the channel. 360 * It must NOT call #GNUNET_CADET_channel_destroy() on the channel.
487 * 361 *
488 * @param cls closure (set from #GNUNET_CADET_connect()) 362 * @param cls the `struct BobServiceSession`
489 * @param channel connection to the other end (henceforth invalid) 363 * @param channel connection to the other end (henceforth invalid)
490 * @param channel_ctx place where local state associated
491 * with the channel is stored
492 */ 364 */
493static void 365static void
494cb_channel_destruction (void *cls, 366cb_channel_destruction (void *cls,
495 const struct GNUNET_CADET_Channel *channel, 367 const struct GNUNET_CADET_Channel *channel)
496 void *channel_ctx)
497{ 368{
498 struct CadetIncomingSession *in = channel_ctx; 369 struct BobServiceSession *s = cls;
499 struct BobServiceSession *s;
500 370
501 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 371 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
502 "Peer disconnected, terminating session %s with peer %s\n", 372 "Peer disconnected, terminating session %s with peer %s\n",
503 GNUNET_h2s (&in->session_id), 373 GNUNET_h2s (&s->session_id),
504 GNUNET_i2s (&in->peer)); 374 GNUNET_i2s (&s->peer));
505 if (NULL != (s = in->s)) 375 if (GNUNET_SCALARPRODUCT_STATUS_ACTIVE == s->status)
506 {
507 if (GNUNET_SCALARPRODUCT_STATUS_ACTIVE == s->status)
508 {
509 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
510 prepare_client_end_notification (s);
511 }
512 }
513 if (NULL != in->cadet_mq)
514 { 376 {
515 GNUNET_MQ_destroy (in->cadet_mq); 377 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
516 in->cadet_mq = NULL; 378 prepare_client_end_notification (s);
517 } 379 }
518 in->channel = NULL; 380 s->channel = NULL;
519 destroy_cadet_session (in); 381 destroy_service_session (s);
520} 382}
521 383
522 384
@@ -585,7 +447,7 @@ transmit_bobs_cryptodata_message_multipart (struct BobServiceSession *s)
585 GNUNET_MQ_notify_sent (e, 447 GNUNET_MQ_notify_sent (e,
586 &bob_cadet_done_cb, 448 &bob_cadet_done_cb,
587 s); 449 s);
588 GNUNET_MQ_send (s->cadet->cadet_mq, 450 GNUNET_MQ_send (s->cadet_mq,
589 e); 451 e);
590 } 452 }
591 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 453 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -653,7 +515,7 @@ transmit_bobs_cryptodata_message (struct BobServiceSession *s)
653 GNUNET_MQ_notify_sent (e, 515 GNUNET_MQ_notify_sent (e,
654 &bob_cadet_done_cb, 516 &bob_cadet_done_cb,
655 s); 517 s);
656 GNUNET_MQ_send (s->cadet->cadet_mq, 518 GNUNET_MQ_send (s->cadet_mq,
657 e); 519 e);
658 transmit_bobs_cryptodata_message_multipart (s); 520 transmit_bobs_cryptodata_message_multipart (s);
659} 521}
@@ -752,14 +614,14 @@ compute_service_response (struct BobServiceSession *session)
752 gcry_mpi_sub (tmp, my_offset, rand[p[i]]); 614 gcry_mpi_sub (tmp, my_offset, rand[p[i]]);
753 gcry_mpi_sub (tmp, tmp, b[p[i]].value); 615 gcry_mpi_sub (tmp, tmp, b[p[i]].value);
754 GNUNET_assert (2 == 616 GNUNET_assert (2 ==
755 GNUNET_CRYPTO_paillier_encrypt (&session->cadet->remote_pubkey, 617 GNUNET_CRYPTO_paillier_encrypt (&session->remote_pubkey,
756 tmp, 618 tmp,
757 2, 619 2,
758 &r[i])); 620 &r[i]));
759 621
760 // E(S - r_pi - b_pi) * E(S + a_pi) == E(2*S + a - r - b) 622 // E(S - r_pi - b_pi) * E(S + a_pi) == E(2*S + a - r - b)
761 if (GNUNET_OK != 623 if (GNUNET_OK !=
762 GNUNET_CRYPTO_paillier_hom_add (&session->cadet->remote_pubkey, 624 GNUNET_CRYPTO_paillier_hom_add (&session->remote_pubkey,
763 &r[i], 625 &r[i],
764 &a[p[i]], 626 &a[p[i]],
765 &r[i])) 627 &r[i]))
@@ -775,14 +637,14 @@ compute_service_response (struct BobServiceSession *session)
775 // E(S - r_qi) 637 // E(S - r_qi)
776 gcry_mpi_sub (tmp, my_offset, rand[q[i]]); 638 gcry_mpi_sub (tmp, my_offset, rand[q[i]]);
777 GNUNET_assert (2 == 639 GNUNET_assert (2 ==
778 GNUNET_CRYPTO_paillier_encrypt (&session->cadet->remote_pubkey, 640 GNUNET_CRYPTO_paillier_encrypt (&session->remote_pubkey,
779 tmp, 641 tmp,
780 2, 642 2,
781 &r_prime[i])); 643 &r_prime[i]));
782 644
783 // E(S - r_qi) * E(S + a_qi) == E(2*S + a_qi - r_qi) 645 // E(S - r_qi) * E(S + a_qi) == E(2*S + a_qi - r_qi)
784 if (GNUNET_OK != 646 if (GNUNET_OK !=
785 GNUNET_CRYPTO_paillier_hom_add (&session->cadet->remote_pubkey, 647 GNUNET_CRYPTO_paillier_hom_add (&session->remote_pubkey,
786 &r_prime[i], 648 &r_prime[i],
787 &a[q[i]], 649 &a[q[i]],
788 &r_prime[i])) 650 &r_prime[i]))
@@ -796,7 +658,7 @@ compute_service_response (struct BobServiceSession *session)
796 // Calculate S' = E(SUM( r_i^2 )) 658 // Calculate S' = E(SUM( r_i^2 ))
797 tmp = compute_square_sum (rand, count); 659 tmp = compute_square_sum (rand, count);
798 GNUNET_assert (1 == 660 GNUNET_assert (1 ==
799 GNUNET_CRYPTO_paillier_encrypt (&session->cadet->remote_pubkey, 661 GNUNET_CRYPTO_paillier_encrypt (&session->remote_pubkey,
800 tmp, 662 tmp,
801 1, 663 1,
802 &session->s_prime)); 664 &session->s_prime));
@@ -807,7 +669,7 @@ compute_service_response (struct BobServiceSession *session)
807 gcry_mpi_add (rand[i], rand[i], b[i].value); 669 gcry_mpi_add (rand[i], rand[i], b[i].value);
808 tmp = compute_square_sum (rand, count); 670 tmp = compute_square_sum (rand, count);
809 GNUNET_assert (1 == 671 GNUNET_assert (1 ==
810 GNUNET_CRYPTO_paillier_encrypt (&session->cadet->remote_pubkey, 672 GNUNET_CRYPTO_paillier_encrypt (&session->remote_pubkey,
811 tmp, 673 tmp,
812 1, 674 1,
813 &session->s)); 675 &session->s));
@@ -919,8 +781,8 @@ transmit_cryptographic_reply (struct BobServiceSession *s)
919 if (GNUNET_OK != 781 if (GNUNET_OK !=
920 compute_service_response (s)) 782 compute_service_response (s))
921 { 783 {
922 channel = s->cadet->channel; 784 channel = s->channel;
923 s->cadet->channel = NULL; 785 s->channel = NULL;
924 GNUNET_CADET_channel_destroy (channel); 786 GNUNET_CADET_channel_destroy (channel);
925 return; 787 return;
926 } 788 }
@@ -929,49 +791,25 @@ transmit_cryptographic_reply (struct BobServiceSession *s)
929 791
930 792
931/** 793/**
932 * Handle a multipart-chunk of a request from another service to 794 * Check a multipart-chunk of a request from another service to
933 * calculate a scalarproduct with us. 795 * calculate a scalarproduct with us.
934 * 796 *
935 * @param cls closure (set from #GNUNET_CADET_connect) 797 * @param cls the `struct BobServiceSession *`
936 * @param channel connection to the other end 798 * @param msg the actual message
937 * @param channel_ctx place to store local state associated with the @a channel
938 * @param message the actual message
939 * @return #GNUNET_OK to keep the connection open, 799 * @return #GNUNET_OK to keep the connection open,
940 * #GNUNET_SYSERR to close it (signal serious error) 800 * #GNUNET_SYSERR to close it (signal serious error)
941 */ 801 */
942static int 802static int
943handle_alices_cryptodata_message (void *cls, 803check_alices_cryptodata_message (void *cls,
944 struct GNUNET_CADET_Channel *channel, 804 const struct AliceCryptodataMessage *msg)
945 void **channel_ctx,
946 const struct GNUNET_MessageHeader *message)
947{ 805{
948 struct CadetIncomingSession *in = *channel_ctx; 806 struct BobServiceSession *s = cls;
949 struct BobServiceSession *s;
950 const struct AliceCryptodataMessage *msg;
951 const struct GNUNET_CRYPTO_PaillierCiphertext *payload;
952 uint32_t contained_elements; 807 uint32_t contained_elements;
953 size_t msg_length; 808 size_t msg_length;
954 uint16_t msize; 809 uint16_t msize;
955 unsigned int max; 810 unsigned int max;
956 811
957 if (NULL == in) 812 msize = ntohs (msg->header.size);
958 {
959 GNUNET_break_op (0);
960 return GNUNET_SYSERR;
961 }
962 s = in->s;
963 if (NULL == s)
964 {
965 GNUNET_break_op (0);
966 return GNUNET_SYSERR;
967 }
968 msize = ntohs (message->size);
969 if (msize <= sizeof (struct AliceCryptodataMessage))
970 {
971 GNUNET_break_op (0);
972 return GNUNET_SYSERR;
973 }
974 msg = (const struct AliceCryptodataMessage *) message;
975 contained_elements = ntohl (msg->contained_element_count); 813 contained_elements = ntohl (msg->contained_element_count);
976 /* Our intersection may still be ongoing, but this is nevertheless 814 /* Our intersection may still be ongoing, but this is nevertheless
977 an upper bound on the required array size */ 815 an upper bound on the required array size */
@@ -986,14 +824,38 @@ handle_alices_cryptodata_message (void *cls,
986 GNUNET_break_op (0); 824 GNUNET_break_op (0);
987 return GNUNET_SYSERR; 825 return GNUNET_SYSERR;
988 } 826 }
827 return GNUNET_OK;
828}
829
830
831/**
832 * Handle a multipart-chunk of a request from another service to
833 * calculate a scalarproduct with us.
834 *
835 * @param cls the `struct BobServiceSession *`
836 * @param msg the actual message
837 */
838static void
839handle_alices_cryptodata_message (void *cls,
840 const struct AliceCryptodataMessage *msg)
841{
842 struct BobServiceSession *s = cls;
843 const struct GNUNET_CRYPTO_PaillierCiphertext *payload;
844 uint32_t contained_elements;
845 unsigned int max;
846
847 contained_elements = ntohl (msg->contained_element_count);
848 /* Our intersection may still be ongoing, but this is nevertheless
849 an upper bound on the required array size */
850 max = GNUNET_CONTAINER_multihashmap_size (s->intersected_elements);
989 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 851 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
990 "Received %u crypto values from Alice\n", 852 "Received %u crypto values from Alice\n",
991 (unsigned int) contained_elements); 853 (unsigned int) contained_elements);
992 854
993 payload = (const struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1]; 855 payload = (const struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
994 if (NULL == s->e_a) 856 if (NULL == s->e_a)
995 s->e_a = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * 857 s->e_a = GNUNET_new_array (max,
996 max); 858 struct GNUNET_CRYPTO_PaillierCiphertext);
997 GNUNET_memcpy (&s->e_a[s->cadet_received_element_count], 859 GNUNET_memcpy (&s->e_a[s->cadet_received_element_count],
998 payload, 860 payload,
999 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * contained_elements); 861 sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * contained_elements);
@@ -1007,8 +869,7 @@ handle_alices_cryptodata_message (void *cls,
1007 CADET response(s) */ 869 CADET response(s) */
1008 transmit_cryptographic_reply (s); 870 transmit_cryptographic_reply (s);
1009 } 871 }
1010 GNUNET_CADET_receive_done (s->cadet->channel); 872 GNUNET_CADET_receive_done (s->channel);
1011 return GNUNET_OK;
1012} 873}
1013 874
1014 875
@@ -1018,11 +879,13 @@ handle_alices_cryptodata_message (void *cls,
1018 * 879 *
1019 * @param cls closure with the `struct BobServiceSession` 880 * @param cls closure with the `struct BobServiceSession`
1020 * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK 881 * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
882 * @param current_size current set size
1021 * @param status what has happened with the set intersection? 883 * @param status what has happened with the set intersection?
1022 */ 884 */
1023static void 885static void
1024cb_intersection_element_removed (void *cls, 886cb_intersection_element_removed (void *cls,
1025 const struct GNUNET_SET_Element *element, 887 const struct GNUNET_SET_Element *element,
888 uint64_t current_size,
1026 enum GNUNET_SET_Status status) 889 enum GNUNET_SET_Status status)
1027{ 890{
1028 struct BobServiceSession *s = cls; 891 struct BobServiceSession *s = cls;
@@ -1048,7 +911,7 @@ cb_intersection_element_removed (void *cls,
1048 case GNUNET_SET_STATUS_DONE: 911 case GNUNET_SET_STATUS_DONE:
1049 s->intersection_op = NULL; 912 s->intersection_op = NULL;
1050 GNUNET_break (NULL == s->intersection_set); 913 GNUNET_break (NULL == s->intersection_set);
1051 GNUNET_CADET_receive_done (s->cadet->channel); 914 GNUNET_CADET_receive_done (s->channel);
1052 LOG (GNUNET_ERROR_TYPE_DEBUG, 915 LOG (GNUNET_ERROR_TYPE_DEBUG,
1053 "Finished intersection, %d items remain\n", 916 "Finished intersection, %d items remain\n",
1054 GNUNET_CONTAINER_multihashmap_size (s->intersected_elements)); 917 GNUNET_CONTAINER_multihashmap_size (s->intersected_elements));
@@ -1099,10 +962,11 @@ start_intersection (struct BobServiceSession *s)
1099 (unsigned int) s->total); 962 (unsigned int) s->total);
1100 963
1101 s->intersection_op 964 s->intersection_op
1102 = GNUNET_SET_prepare (&s->cadet->peer, 965 = GNUNET_SET_prepare (&s->peer,
1103 &s->session_id, 966 &s->session_id,
1104 NULL, 967 NULL,
1105 GNUNET_SET_RESULT_REMOVED, 968 GNUNET_SET_RESULT_REMOVED,
969 (struct GNUNET_SET_Option[]) {{ 0 }},
1106 &cb_intersection_element_removed, 970 &cb_intersection_element_removed,
1107 s); 971 s);
1108 if (GNUNET_OK != 972 if (GNUNET_OK !=
@@ -1122,55 +986,19 @@ start_intersection (struct BobServiceSession *s)
1122/** 986/**
1123 * Handle a request from Alice to calculate a scalarproduct with us (Bob). 987 * Handle a request from Alice to calculate a scalarproduct with us (Bob).
1124 * 988 *
1125 * @param cls closure (set from #GNUNET_CADET_connect) 989 * @param cls the `struct BobServiceSession *`
1126 * @param channel connection to the other end 990 * @param msg the actual message
1127 * @param channel_ctx place to store the `struct CadetIncomingSession *`
1128 * @param message the actual message
1129 * @return #GNUNET_OK to keep the connection open,
1130 * #GNUNET_SYSERR to close it (signal serious error)
1131 */ 991 */
1132static int 992static void
1133handle_alices_computation_request (void *cls, 993handle_alices_computation_request (void *cls,
1134 struct GNUNET_CADET_Channel *channel, 994 const struct ServiceRequestMessage *msg)
1135 void **channel_ctx,
1136 const struct GNUNET_MessageHeader *message)
1137{ 995{
1138 struct CadetIncomingSession *in = *channel_ctx; 996 struct BobServiceSession *s = cls;
1139 struct BobServiceSession *s;
1140 const struct ServiceRequestMessage *msg;
1141 997
1142 msg = (const struct ServiceRequestMessage *) message; 998 s->session_id = msg->session_id; // ??
1143 if (GNUNET_YES == in->in_map) 999 s->remote_pubkey = msg->public_key;
1144 {
1145 GNUNET_break_op (0);
1146 return GNUNET_SYSERR;
1147 }
1148 if (NULL != find_matching_cadet_session (&msg->session_id))
1149 {
1150 /* not unique, got one like this already */
1151 GNUNET_break_op (0);
1152 return GNUNET_SYSERR;
1153 }
1154 in->session_id = msg->session_id;
1155 in->remote_pubkey = msg->public_key;
1156 GNUNET_assert (GNUNET_YES ==
1157 GNUNET_CONTAINER_multihashmap_put (cadet_sessions,
1158 &in->session_id,
1159 in,
1160 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1161 s = find_matching_client_session (&in->session_id);
1162 if (NULL == s)
1163 {
1164 /* no client waiting for this request, wait for client */
1165 return GNUNET_OK;
1166 }
1167 GNUNET_assert (NULL == s->cadet);
1168 /* pair them up */
1169 in->s = s;
1170 s->cadet = in;
1171 if (s->client_received_element_count == s->total) 1000 if (s->client_received_element_count == s->total)
1172 start_intersection (s); 1001 start_intersection (s);
1173 return GNUNET_OK;
1174} 1002}
1175 1003
1176 1004
@@ -1182,31 +1010,27 @@ handle_alices_computation_request (void *cls,
1182 * @param cls closure with the `struct BobServiceSession` 1010 * @param cls closure with the `struct BobServiceSession`
1183 * @param channel new handle to the channel 1011 * @param channel new handle to the channel
1184 * @param initiator peer that started the channel 1012 * @param initiator peer that started the channel
1185 * @param port unused
1186 * @param options unused
1187 * @return session associated with the channel 1013 * @return session associated with the channel
1188 */ 1014 */
1189static void * 1015static void *
1190cb_channel_incoming (void *cls, 1016cb_channel_incoming (void *cls,
1191 struct GNUNET_CADET_Channel *channel, 1017 struct GNUNET_CADET_Channel *channel,
1192 const struct GNUNET_PeerIdentity *initiator, 1018 const struct GNUNET_PeerIdentity *initiator)
1193 const struct GNUNET_HashCode *port,
1194 enum GNUNET_CADET_ChannelOption options)
1195{ 1019{
1196 struct CadetIncomingSession *in; 1020 struct BobServiceSession *s = cls;
1197 1021
1198 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1022 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1199 "New incoming channel from peer %s.\n", 1023 "New incoming channel from peer %s.\n",
1200 GNUNET_i2s (initiator)); 1024 GNUNET_i2s (initiator));
1201 in = GNUNET_new (struct CadetIncomingSession); 1025 GNUNET_CADET_close_port (s->port);
1202 in->peer = *initiator; 1026 s->port = NULL;
1203 in->channel = channel; 1027 s->channel = channel;
1204 in->cadet_mq = GNUNET_CADET_mq_create (in->channel); 1028 s->peer = *initiator;
1205 return in; 1029 s->cadet_mq = GNUNET_CADET_get_mq (s->channel);
1030 return s;
1206} 1031}
1207 1032
1208 1033
1209
1210/** 1034/**
1211 * We're receiving additional set data. Check it is well-formed. 1035 * We're receiving additional set data. Check it is well-formed.
1212 * 1036 *
@@ -1287,7 +1111,7 @@ handle_bob_client_message_multipart (void *cls,
1287 /* more to come */ 1111 /* more to come */
1288 return; 1112 return;
1289 } 1113 }
1290 if (NULL == s->cadet) 1114 if (NULL == s->channel)
1291 { 1115 {
1292 /* no Alice waiting for this request, wait for Alice */ 1116 /* no Alice waiting for this request, wait for Alice */
1293 return; 1117 return;
@@ -1330,11 +1154,6 @@ check_bob_client_message (void *cls,
1330 GNUNET_break_op (0); 1154 GNUNET_break_op (0);
1331 return GNUNET_SYSERR; 1155 return GNUNET_SYSERR;
1332 } 1156 }
1333 if (NULL != find_matching_client_session (&msg->session_key))
1334 {
1335 GNUNET_break (0);
1336 return GNUNET_SYSERR;
1337 }
1338 return GNUNET_OK; 1157 return GNUNET_OK;
1339} 1158}
1340 1159
@@ -1352,7 +1171,17 @@ handle_bob_client_message (void *cls,
1352 const struct BobComputationMessage *msg) 1171 const struct BobComputationMessage *msg)
1353{ 1172{
1354 struct BobServiceSession *s = cls; 1173 struct BobServiceSession *s = cls;
1355 struct CadetIncomingSession *in; 1174 struct GNUNET_MQ_MessageHandler cadet_handlers[] = {
1175 GNUNET_MQ_hd_fixed_size (alices_computation_request,
1176 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_SESSION_INITIALIZATION,
1177 struct ServiceRequestMessage,
1178 NULL),
1179 GNUNET_MQ_hd_var_size (alices_cryptodata_message,
1180 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA,
1181 struct AliceCryptodataMessage,
1182 NULL),
1183 GNUNET_MQ_handler_end ()
1184 };
1356 uint32_t contained_count; 1185 uint32_t contained_count;
1357 uint32_t total_count; 1186 uint32_t total_count;
1358 const struct GNUNET_SCALARPRODUCT_Element *elements; 1187 const struct GNUNET_SCALARPRODUCT_Element *elements;
@@ -1366,21 +1195,6 @@ handle_bob_client_message (void *cls,
1366 s->total = total_count; 1195 s->total = total_count;
1367 s->client_received_element_count = contained_count; 1196 s->client_received_element_count = contained_count;
1368 s->session_id = msg->session_key; 1197 s->session_id = msg->session_key;
1369 s->port = GNUNET_CADET_open_port (my_cadet,
1370 &msg->session_key,
1371 &cb_channel_incoming,
1372 s);
1373 if (NULL == s->port)
1374 {
1375 GNUNET_break (0);
1376 GNUNET_SERVICE_client_drop (s->client);
1377 return;
1378 }
1379 GNUNET_break (GNUNET_YES ==
1380 GNUNET_CONTAINER_multihashmap_put (client_sessions,
1381 &s->session_id,
1382 s,
1383 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1384 elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1]; 1198 elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
1385 s->intersected_elements 1199 s->intersected_elements
1386 = GNUNET_CONTAINER_multihashmap_create (s->total, 1200 = GNUNET_CONTAINER_multihashmap_create (s->total,
@@ -1415,22 +1229,20 @@ handle_bob_client_message (void *cls,
1415 s->used_element_count++; 1229 s->used_element_count++;
1416 } 1230 }
1417 GNUNET_SERVICE_client_continue (s->client); 1231 GNUNET_SERVICE_client_continue (s->client);
1418 if (s->total != s->client_received_element_count) 1232 /* We're ready, open the port */
1419 { 1233 s->port = GNUNET_CADET_open_port (my_cadet,
1420 /* multipart msg */ 1234 &msg->session_key,
1421 return; 1235 &cb_channel_incoming,
1422 } 1236 s,
1423 in = find_matching_cadet_session (&s->session_id); 1237 NULL,
1424 if (NULL == in) 1238 &cb_channel_destruction,
1239 cadet_handlers);
1240 if (NULL == s->port)
1425 { 1241 {
1426 /* nothing yet, wait for Alice */ 1242 GNUNET_break (0);
1243 GNUNET_SERVICE_client_drop (s->client);
1427 return; 1244 return;
1428 } 1245 }
1429 GNUNET_assert (NULL == in->s);
1430 /* pair them up */
1431 in->s = s;
1432 s->cadet = in;
1433 start_intersection (s);
1434} 1246}
1435 1247
1436 1248
@@ -1450,10 +1262,6 @@ shutdown_task (void *cls)
1450 GNUNET_CADET_disconnect (my_cadet); 1262 GNUNET_CADET_disconnect (my_cadet);
1451 my_cadet = NULL; 1263 my_cadet = NULL;
1452 } 1264 }
1453 GNUNET_CONTAINER_multihashmap_destroy (client_sessions);
1454 client_sessions = NULL;
1455 GNUNET_CONTAINER_multihashmap_destroy (cadet_sessions);
1456 cadet_sessions = NULL;
1457} 1265}
1458 1266
1459 1267
@@ -1517,16 +1325,6 @@ run (void *cls,
1517 const struct GNUNET_CONFIGURATION_Handle *c, 1325 const struct GNUNET_CONFIGURATION_Handle *c,
1518 struct GNUNET_SERVICE_Handle *service) 1326 struct GNUNET_SERVICE_Handle *service)
1519{ 1327{
1520 static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
1521 { &handle_alices_computation_request,
1522 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_SESSION_INITIALIZATION,
1523 sizeof (struct ServiceRequestMessage) },
1524 { &handle_alices_cryptodata_message,
1525 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA,
1526 0},
1527 { NULL, 0, 0}
1528 };
1529
1530 cfg = c; 1328 cfg = c;
1531 /* 1329 /*
1532 offset has to be sufficiently small to allow computation of: 1330 offset has to be sufficiently small to allow computation of:
@@ -1538,13 +1336,7 @@ run (void *cls,
1538 1336
1539 GNUNET_CRYPTO_paillier_create (&my_pubkey, 1337 GNUNET_CRYPTO_paillier_create (&my_pubkey,
1540 &my_privkey); 1338 &my_privkey);
1541 client_sessions = GNUNET_CONTAINER_multihashmap_create (128, 1339 my_cadet = GNUNET_CADET_connect (cfg);
1542 GNUNET_YES);
1543 cadet_sessions = GNUNET_CONTAINER_multihashmap_create (128,
1544 GNUNET_YES);
1545 my_cadet = GNUNET_CADET_connect (cfg, NULL,
1546 &cb_channel_destruction,
1547 cadet_handlers);
1548 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, 1340 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1549 NULL); 1341 NULL);
1550 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/scalarproduct/test_scalarproduct.conf b/src/scalarproduct/test_scalarproduct.conf
index 3ab47cfeb..73dbadbce 100644
--- a/src/scalarproduct/test_scalarproduct.conf
+++ b/src/scalarproduct/test_scalarproduct.conf
@@ -21,6 +21,3 @@ WAN_QUOTA_OUT = unlimited
21 21
22[peerinfo] 22[peerinfo]
23USE_INCLUDED_HELLOS = NO 23USE_INCLUDED_HELLOS = NO
24
25[nat]
26RETURN_LOCAL_ADDRESSES = YES
diff --git a/src/secretsharing/.gitignore b/src/secretsharing/.gitignore
index bb169f0c4..fe9db53a4 100644
--- a/src/secretsharing/.gitignore
+++ b/src/secretsharing/.gitignore
@@ -1,2 +1,3 @@
1gnunet-service-secretsharing 1gnunet-service-secretsharing
2gnunet-secretsharing-profiler 2gnunet-secretsharing-profiler
3test_secretsharing_api
diff --git a/src/secretsharing/Makefile.am b/src/secretsharing/Makefile.am
index 3d0c73c3b..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
@@ -56,13 +53,18 @@ libgnunetsecretsharing_la_LIBADD = \
56libgnunetsecretsharing_la_LDFLAGS = \ 53libgnunetsecretsharing_la_LDFLAGS = \
57 $(GN_LIB_LDFLAGS) 54 $(GN_LIB_LDFLAGS)
58 55
56if HAVE_TESTING
57bin_PROGRAMS = \
58 gnunet-secretsharing-profiler
59
59check_PROGRAMS = \ 60check_PROGRAMS = \
60 test_secretsharing_api 61 test_secretsharing_api
61 62
62if ENABLE_TEST_RUN 63if ENABLE_TEST_RUN
63AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; 64AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
64TESTS = $(check_PROGRAMS) 65TESTS = $(check_PROGRAMS)
65endif 66endif
67endif
66 68
67test_secretsharing_api_SOURCES = \ 69test_secretsharing_api_SOURCES = \
68 test_secretsharing_api.c 70 test_secretsharing_api.c
@@ -73,4 +75,3 @@ test_secretsharing_api_LDADD = \
73 75
74EXTRA_DIST = \ 76EXTRA_DIST = \
75 test_secretsharing.conf 77 test_secretsharing.conf
76
diff --git a/src/secretsharing/gnunet-secretsharing-profiler.c b/src/secretsharing/gnunet-secretsharing-profiler.c
index 3ff5d7fdd..a83dcd92a 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_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_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_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_uint ('k',
626 "threshold",
627 NULL,
628 gettext_noop ("threshold"),
629 &threshold),
630
631 GNUNET_GETOPT_option_flag ('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/.gitignore b/src/set/.gitignore
index 10f1da0d6..f1c958639 100644
--- a/src/set/.gitignore
+++ b/src/set/.gitignore
@@ -1,3 +1,7 @@
1gnunet-set-profiler 1gnunet-set-profiler
2gnunet-service-set 2gnunet-service-set
3gnunet-set-ibf-profiler 3gnunet-set-ibf-profiler
4test_set_api
5test_set_intersection_result_full
6test_set_union_copy
7test_set_union_result_symmetric
diff --git a/src/set/Makefile.am b/src/set/Makefile.am
index 4d990479c..14667d0ef 100644
--- a/src/set/Makefile.am
+++ b/src/set/Makefile.am
@@ -5,6 +5,8 @@ pkgcfgdir= $(pkgdatadir)/config.d/
5 5
6libexecdir= $(pkglibdir)/libexec/ 6libexecdir= $(pkglibdir)/libexec/
7 7
8plugindir = $(libdir)/gnunet
9
8pkgcfg_DATA = \ 10pkgcfg_DATA = \
9 set.conf 11 set.conf
10 12
@@ -49,7 +51,7 @@ gnunet_set_ibf_profiler_LDADD = \
49 51
50gnunet_service_set_SOURCES = \ 52gnunet_service_set_SOURCES = \
51 gnunet-service-set.c gnunet-service-set.h \ 53 gnunet-service-set.c gnunet-service-set.h \
52 gnunet-service-set_union.c \ 54 gnunet-service-set_union.c gnunet-service-set_union.h \
53 gnunet-service-set_intersection.c \ 55 gnunet-service-set_intersection.c \
54 ibf.c ibf.h \ 56 ibf.c ibf.h \
55 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 \
@@ -80,7 +82,7 @@ check_PROGRAMS = \
80endif 82endif
81 83
82if ENABLE_TEST_RUN 84if ENABLE_TEST_RUN
83AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; 85AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
84TESTS = $(check_PROGRAMS) 86TESTS = $(check_PROGRAMS)
85endif 87endif
86 88
@@ -112,5 +114,19 @@ test_set_union_copy_LDADD = \
112 $(top_builddir)/src/testing/libgnunettesting.la \ 114 $(top_builddir)/src/testing/libgnunettesting.la \
113 libgnunetset.la 115 libgnunetset.la
114 116
117plugin_LTLIBRARIES = \
118 libgnunet_plugin_block_set_test.la
119
120libgnunet_plugin_block_set_test_la_SOURCES = \
121 plugin_block_set_test.c
122libgnunet_plugin_block_set_test_la_LIBADD = \
123 $(top_builddir)/src/block/libgnunetblock.la \
124 $(top_builddir)/src/block/libgnunetblockgroup.la \
125 $(top_builddir)/src/util/libgnunetutil.la \
126 $(LTLIBINTL)
127libgnunet_plugin_block_set_test_la_LDFLAGS = \
128 $(GN_PLUGIN_LDFLAGS)
129
130
115EXTRA_DIST = \ 131EXTRA_DIST = \
116 test_set.conf 132 test_set.conf
diff --git a/src/set/gnunet-service-set.c b/src/set/gnunet-service-set.c
index e4e2535af..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 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_SERVER_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
143 */ 161 * uninitialized).
144static uint32_t suggest_id = 1;
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 */ 162 */
159static struct Set * 163static uint32_t suggest_id;
160set_get (struct GNUNET_SERVER_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_SERVER_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,48 +174,49 @@ listener_get (struct GNUNET_SERVER_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_SERVER_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_SERVER_client_disconnect (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;
231 } 209 }
232 if (NULL != listener->client_mq) 210 if (NULL != op->timeout_task)
233 { 211 {
234 GNUNET_MQ_destroy (listener->client_mq); 212 GNUNET_SCHEDULER_cancel (op->timeout_task);
235 listener->client_mq = NULL; 213 op->timeout_task = NULL;
214 }
215 if (NULL != (channel = op->channel))
216 {
217 op->channel = NULL;
218 GNUNET_CADET_channel_destroy (channel);
236 } 219 }
237 GNUNET_CADET_close_port (listener->open_port);
238 GNUNET_CONTAINER_DLL_remove (listeners_head,
239 listeners_tail,
240 listener);
241 GNUNET_free (listener);
242} 220}
243 221
244 222
@@ -308,12 +286,11 @@ garbage_collect_cb (void *cls,
308static void 286static void
309collect_generation_garbage (struct Set *set) 287collect_generation_garbage (struct Set *set)
310{ 288{
311 struct Operation *op;
312 struct GarbageContext gc; 289 struct GarbageContext gc;
313 290
314 gc.min_op_generation = UINT_MAX; 291 gc.min_op_generation = UINT_MAX;
315 gc.max_op_generation = 0; 292 gc.max_op_generation = 0;
316 for (op = set->ops_head; NULL != op; op = op->next) 293 for (struct Operation *op = set->ops_head; NULL != op; op = op->next)
317 { 294 {
318 gc.min_op_generation = GNUNET_MIN (gc.min_op_generation, 295 gc.min_op_generation = GNUNET_MIN (gc.min_op_generation,
319 op->generation_created); 296 op->generation_created);
@@ -327,23 +304,36 @@ collect_generation_garbage (struct Set *set)
327} 304}
328 305
329 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 */
330static int 315static int
331is_excluded_generation (unsigned int generation, 316is_excluded_generation (unsigned int generation,
332 struct GenerationRange *excluded, 317 struct GenerationRange *excluded,
333 unsigned int excluded_size) 318 unsigned int excluded_size)
334{ 319{
335 unsigned int i; 320 for (unsigned int i = 0; i < excluded_size; i++)
336 321 if ( (generation >= excluded[i].start) &&
337 for (i = 0; i < excluded_size; i++) 322 (generation < excluded[i].end) )
338 {
339 if ( (generation >= excluded[i].start) && (generation < excluded[i].end) )
340 return GNUNET_YES; 323 return GNUNET_YES;
341 }
342
343 return GNUNET_NO; 324 return GNUNET_NO;
344} 325}
345 326
346 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 */
347static int 337static int
348is_element_of_generation (struct ElementEntry *ee, 338is_element_of_generation (struct ElementEntry *ee,
349 unsigned int query_generation, 339 unsigned int query_generation,
@@ -352,11 +342,12 @@ is_element_of_generation (struct ElementEntry *ee,
352{ 342{
353 struct MutationEvent *mut; 343 struct MutationEvent *mut;
354 int is_present; 344 int is_present;
355 unsigned int i;
356 345
357 GNUNET_assert (NULL != ee->mutations); 346 GNUNET_assert (NULL != ee->mutations);
358 347 if (GNUNET_YES ==
359 if (GNUNET_YES == is_excluded_generation (query_generation, excluded, excluded_size)) 348 is_excluded_generation (query_generation,
349 excluded,
350 excluded_size))
360 { 351 {
361 GNUNET_break (0); 352 GNUNET_break (0);
362 return GNUNET_NO; 353 return GNUNET_NO;
@@ -366,7 +357,7 @@ is_element_of_generation (struct ElementEntry *ee,
366 357
367 /* Could be made faster with binary search, but lists 358 /* Could be made faster with binary search, but lists
368 are small, so why bother. */ 359 are small, so why bother. */
369 for (i = 0; i < ee->mutations_size; i++) 360 for (unsigned int i = 0; i < ee->mutations_size; i++)
370 { 361 {
371 mut = &ee->mutations[i]; 362 mut = &ee->mutations[i];
372 363
@@ -378,7 +369,10 @@ is_element_of_generation (struct ElementEntry *ee,
378 continue; 369 continue;
379 } 370 }
380 371
381 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))
382 { 376 {
383 /* The generation is excluded (because it belongs to another 377 /* The generation is excluded (because it belongs to another
384 fork via a lazy copy) and thus mutations aren't considered 378 fork via a lazy copy) and thus mutations aren't considered
@@ -387,11 +381,12 @@ is_element_of_generation (struct ElementEntry *ee,
387 } 381 }
388 382
389 /* This would be an inconsistency in how we manage mutations. */ 383 /* This would be an inconsistency in how we manage mutations. */
390 if ( (GNUNET_YES == is_present) && (GNUNET_YES == mut->added) ) 384 if ( (GNUNET_YES == is_present) &&
385 (GNUNET_YES == mut->added) )
391 GNUNET_assert (0); 386 GNUNET_assert (0);
392
393 /* Likewise. */ 387 /* Likewise. */
394 if ( (GNUNET_NO == is_present) && (GNUNET_NO == mut->added) ) 388 if ( (GNUNET_NO == is_present) &&
389 (GNUNET_NO == mut->added) )
395 GNUNET_assert (0); 390 GNUNET_assert (0);
396 391
397 is_present = mut->added; 392 is_present = mut->added;
@@ -401,44 +396,33 @@ is_element_of_generation (struct ElementEntry *ee,
401} 396}
402 397
403 398
404int 399/**
405_GSS_is_element_of_set (struct ElementEntry *ee, 400 * Is element @a ee part of the set used by @a op?
406 struct Set *set) 401 *
407{ 402 * @param ee element to test
408 return is_element_of_generation (ee, 403 * @param op operation the defines the set and its generation
409 set->current_generation, 404 * @return #GNUNET_YES if the element is in the set, #GNUNET_NO if not
410 set->excluded_generations, 405 */
411 set->excluded_generations_size);
412}
413
414
415static int
416is_element_of_iteration (struct ElementEntry *ee,
417 struct Set *set)
418{
419 return is_element_of_generation (ee,
420 set->iter_generation,
421 set->excluded_generations,
422 set->excluded_generations_size);
423}
424
425
426int 406int
427_GSS_is_element_of_operation (struct ElementEntry *ee, 407_GSS_is_element_of_operation (struct ElementEntry *ee,
428 struct Operation *op) 408 struct Operation *op)
429{ 409{
430 return is_element_of_generation (ee, 410 return is_element_of_generation (ee,
431 op->generation_created, 411 op->generation_created,
432 op->spec->set->excluded_generations, 412 op->set->excluded_generations,
433 op->spec->set->excluded_generations_size); 413 op->set->excluded_generations_size);
434} 414}
435 415
436 416
437/** 417/**
438 * Destroy the given operation. Call the implementation-specific 418 * Destroy the given operation. Used for any operation where both
439 * cancel function of the operation. Disconnects from the remote 419 * peers were known and that thus actually had a vt and channel. Must
440 * 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
441 * 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.
442 * 426 *
443 * @param op operation to destroy 427 * @param op operation to destroy
444 * @param gc #GNUNET_YES to perform garbage collection on the set 428 * @param gc #GNUNET_YES to perform garbage collection on the set
@@ -447,43 +431,39 @@ void
447_GSS_operation_destroy (struct Operation *op, 431_GSS_operation_destroy (struct Operation *op,
448 int gc) 432 int gc)
449{ 433{
450 struct Set *set; 434 struct Set *set = op->set;
451 struct GNUNET_CADET_Channel *channel; 435 struct GNUNET_CADET_Channel *channel;
452 436
453 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)
454 { 442 {
455 /* already in #_GSS_operation_destroy() */ 443 set->vt->cancel (op);
456 return; 444 op->state = NULL;
457 } 445 }
458 GNUNET_assert (GNUNET_NO == op->is_incoming); 446 if (NULL != set)
459 GNUNET_assert (NULL != op->spec);
460 set = op->spec->set;
461 GNUNET_CONTAINER_DLL_remove (set->ops_head,
462 set->ops_tail,
463 op);
464 op->vt->cancel (op);
465 op->vt = NULL;
466 if (NULL != op->spec)
467 { 447 {
468 if (NULL != op->spec->context_msg) 448 GNUNET_CONTAINER_DLL_remove (set->ops_head,
469 { 449 set->ops_tail,
470 GNUNET_free (op->spec->context_msg); 450 op);
471 op->spec->context_msg = NULL; 451 op->set = NULL;
472 }
473 GNUNET_free (op->spec);
474 op->spec = NULL;
475 } 452 }
476 if (NULL != op->mq) 453 if (NULL != op->context_msg)
477 { 454 {
478 GNUNET_MQ_destroy (op->mq); 455 GNUNET_free (op->context_msg);
479 op->mq = NULL; 456 op->context_msg = NULL;
480 } 457 }
481 if (NULL != (channel = op->channel)) 458 if (NULL != (channel = op->channel))
482 { 459 {
460 /* This will free op; called conditionally as this helper function
461 is also called from within the channel disconnect handler. */
483 op->channel = NULL; 462 op->channel = NULL;
484 GNUNET_CADET_channel_destroy (channel); 463 GNUNET_CADET_channel_destroy (channel);
485 } 464 }
486 if (GNUNET_YES == gc) 465 if ( (NULL != set) &&
466 (GNUNET_YES == gc) )
487 collect_generation_garbage (set); 467 collect_generation_garbage (set);
488 /* 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,
489 * 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. */
@@ -491,6 +471,28 @@ _GSS_operation_destroy (struct Operation *op,
491 471
492 472
493/** 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/**
494 * Iterator over hash map entries to free element entries. 496 * Iterator over hash map entries to free element entries.
495 * 497 *
496 * @param cls closure 498 * @param cls closure
@@ -506,71 +508,76 @@ destroy_elements_iterator (void *cls,
506 struct ElementEntry *ee = value; 508 struct ElementEntry *ee = value;
507 509
508 GNUNET_free_non_null (ee->mutations); 510 GNUNET_free_non_null (ee->mutations);
509
510 GNUNET_free (ee); 511 GNUNET_free (ee);
511 return GNUNET_YES; 512 return GNUNET_YES;
512} 513}
513 514
514 515
515/** 516/**
516 * Destroy a set, and free all resources and operations associated with it. 517 * Clean up after a client has disconnected
517 * 518 *
518 * @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`
519 */ 522 */
520static void 523static void
521set_destroy (struct Set *set) 524client_disconnect_cb (void *cls,
525 struct GNUNET_SERVICE_Client *client,
526 void *internal_cls)
522{ 527{
523 if (NULL != set->client) 528 struct ClientState *cs = internal_cls;
524 { 529 struct Operation *op;
525 /* If the client is not dead yet, destroy it. The client's destroy 530 struct Listener *listener;
526 * callback will call `set_destroy()` again in this case. We do 531 struct Set *set;
527 * this so that the channel end handler still has a valid set handle 532
528 * to destroy. */ 533 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
529 struct GNUNET_SERVER_Client *client = set->client; 534 "Client disconnected, cleaning up\n");
530 535 if (NULL != (set = cs->set))
531 set->client = NULL;
532 GNUNET_SERVER_client_disconnect (client);
533 return;
534 }
535 GNUNET_assert (NULL != set->state);
536 while (NULL != set->ops_head)
537 _GSS_operation_destroy (set->ops_head, GNUNET_NO);
538 set->vt->destroy_set (set->state);
539 set->state = NULL;
540 if (NULL != set->client_mq)
541 {
542 GNUNET_MQ_destroy (set->client_mq);
543 set->client_mq = NULL;
544 }
545 if (NULL != set->iter)
546 {
547 GNUNET_CONTAINER_multihashmap_iterator_destroy (set->iter);
548 set->iter = NULL;
549 set->iteration_id++;
550 }
551 { 536 {
552 struct SetContent *content; 537 struct SetContent *content = set->content;
553 struct PendingMutation *pm; 538 struct PendingMutation *pm;
554 struct PendingMutation *pm_current; 539 struct PendingMutation *pm_current;
540 struct LazyCopyRequest *lcr;
555 541
556 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 }
557 561
558 // discard any pending mutations that reference this set 562 /* discard any pending mutations that reference this set */
559 pm = content->pending_mutations_head; 563 pm = content->pending_mutations_head;
560 while (NULL != pm) 564 while (NULL != pm)
561 { 565 {
562 pm_current = pm; 566 pm_current = pm;
563 pm = pm->next; 567 pm = pm->next;
564 if (pm_current-> set == set) 568 if (pm_current->set == set)
569 {
565 GNUNET_CONTAINER_DLL_remove (content->pending_mutations_head, 570 GNUNET_CONTAINER_DLL_remove (content->pending_mutations_head,
566 content->pending_mutations_tail, 571 content->pending_mutations_tail,
567 pm_current); 572 pm_current);
568 573 GNUNET_free (pm_current);
574 }
569 } 575 }
570 576
577 /* free set content (or at least decrement RC) */
571 set->content = NULL; 578 set->content = NULL;
572 GNUNET_assert (0 != content->refcount); 579 GNUNET_assert (0 != content->refcount);
573 content->refcount -= 1; 580 content->refcount--;
574 if (0 == content->refcount) 581 if (0 == content->refcount)
575 { 582 {
576 GNUNET_assert (NULL != content->elements); 583 GNUNET_assert (NULL != content->elements);
@@ -581,140 +588,85 @@ set_destroy (struct Set *set)
581 content->elements = NULL; 588 content->elements = NULL;
582 GNUNET_free (content); 589 GNUNET_free (content);
583 } 590 }
584 } 591 GNUNET_free_non_null (set->excluded_generations);
585 GNUNET_free_non_null (set->excluded_generations); 592 set->excluded_generations = NULL;
586 set->excluded_generations = NULL;
587 GNUNET_CONTAINER_DLL_remove (sets_head,
588 sets_tail,
589 set);
590 593
591 // remove set from pending copy requests 594 /* remove set from pending copy requests */
592 {
593 struct LazyCopyRequest *lcr;
594 lcr = lazy_copy_head; 595 lcr = lazy_copy_head;
595 while (NULL != lcr) 596 while (NULL != lcr)
596 { 597 {
597 struct LazyCopyRequest *lcr_current; 598 struct LazyCopyRequest *lcr_current = lcr;
598 lcr_current = lcr; 599
599 lcr = lcr->next; 600 lcr = lcr->next;
600 if (lcr_current->source_set == set) 601 if (lcr_current->source_set == set)
602 {
601 GNUNET_CONTAINER_DLL_remove (lazy_copy_head, 603 GNUNET_CONTAINER_DLL_remove (lazy_copy_head,
602 lazy_copy_tail, 604 lazy_copy_tail,
603 lcr_current); 605 lcr_current);
606 GNUNET_free (lcr_current);
607 }
604 } 608 }
609 GNUNET_free (set);
605 } 610 }
606 611
607 GNUNET_free (set); 612 if (NULL != (listener = cs->listener))
608}
609
610
611/**
612 * Clean up after a client has disconnected
613 *
614 * @param cls closure, unused
615 * @param client the client to clean up after
616 */
617static void
618handle_client_disconnect (void *cls,
619 struct GNUNET_SERVER_Client *client)
620{
621 struct Listener *listener;
622 struct Set *set;
623
624 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
625 "client disconnected, cleaning up\n");
626 set = set_get (client);
627 if (NULL != set)
628 { 613 {
629 set->client = NULL;
630 set_destroy (set);
631 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 614 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
632 "Client's set destroyed\n"); 615 "Destroying client's listener\n");
633 } 616 GNUNET_CADET_close_port (listener->open_port);
634 listener = listener_get (client); 617 listener->open_port = NULL;
635 if (NULL != listener) 618 while (NULL != (op = listener->op_head))
636 { 619 incoming_destroy (op);
637 listener->client = NULL; 620 GNUNET_CONTAINER_DLL_remove (listener_head,
638 listener_destroy (listener); 621 listener_tail,
639 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 622 listener);
640 "Client's listener destroyed\n"); 623 GNUNET_free (listener);
641 } 624 }
625 GNUNET_free (cs);
642} 626}
643 627
644 628
645/** 629/**
646 * Destroy an incoming request from a remote peer 630 * Check a request for a set operation from another peer.
647 * 631 *
648 * @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
649 */ 636 */
650static void 637static int
651incoming_destroy (struct Operation *incoming) 638check_incoming_msg (void *cls,
639 const struct OperationRequestMessage *msg)
652{ 640{
653 struct GNUNET_CADET_Channel *channel; 641 struct Operation *op = cls;
642 struct Listener *listener = op->listener;
643 const struct GNUNET_MessageHeader *nested_context;
654 644
655 GNUNET_assert (GNUNET_YES == incoming->is_incoming); 645 /* double operation request */
656 GNUNET_CONTAINER_DLL_remove (incoming_head, 646 if (0 != op->suggest_id)
657 incoming_tail,
658 incoming);
659 if (NULL != incoming->timeout_task)
660 { 647 {
661 GNUNET_SCHEDULER_cancel (incoming->timeout_task); 648 GNUNET_break_op (0);
662 incoming->timeout_task = NULL; 649 return GNUNET_SYSERR;
663 } 650 }
664 /* 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 */
665 incoming->vt = NULL; 652 if (NULL == op->listener)
666 if (NULL != incoming->spec)
667 { 653 {
668 GNUNET_free (incoming->spec); 654 GNUNET_break (0);
669 incoming->spec = NULL; 655 return GNUNET_SYSERR;
670 } 656 }
671 if (NULL != incoming->mq) 657 if (listener->operation != (enum GNUNET_SET_OperationType) ntohl (msg->operation))
672 { 658 {
673 GNUNET_MQ_destroy (incoming->mq); 659 GNUNET_break_op (0);
674 incoming->mq = NULL; 660 return GNUNET_SYSERR;
675 } 661 }
676 if (NULL != (channel = incoming->channel)) 662 nested_context = GNUNET_MQ_extract_nested_mh (msg);
663 if ( (NULL != nested_context) &&
664 (ntohs (nested_context->size) > GNUNET_SET_CONTEXT_MESSAGE_MAX_SIZE) )
677 { 665 {
678 incoming->channel = NULL; 666 GNUNET_break_op (0);
679 GNUNET_CADET_channel_destroy (channel); 667 return GNUNET_SYSERR;
680 } 668 }
681} 669 return GNUNET_OK;
682
683
684/**
685 * Suggest the given request to the listener. The listening client can
686 * then accept or reject the remote request.
687 *
688 * @param incoming the incoming peer with the request to suggest
689 * @param listener the listener to suggest the request to
690 */
691static void
692incoming_suggest (struct Operation *incoming,
693 struct Listener *listener)
694{
695 struct GNUNET_MQ_Envelope *mqm;
696 struct GNUNET_SET_RequestMessage *cmsg;
697
698 GNUNET_assert (GNUNET_YES == incoming->is_incoming);
699 GNUNET_assert (NULL != incoming->spec);
700 GNUNET_assert (0 == incoming->suggest_id);
701 incoming->suggest_id = suggest_id++;
702 if (0 == suggest_id)
703 suggest_id++;
704 GNUNET_assert (NULL != incoming->timeout_task);
705 GNUNET_SCHEDULER_cancel (incoming->timeout_task);
706 incoming->timeout_task = NULL;
707 mqm = GNUNET_MQ_msg_nested_mh (cmsg,
708 GNUNET_MESSAGE_TYPE_SET_REQUEST,
709 incoming->spec->context_msg);
710 GNUNET_assert (NULL != mqm);
711 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
712 "Suggesting incoming request with accept id %u to listener\n",
713 incoming->suggest_id);
714 cmsg->accept_id = htonl (incoming->suggest_id);
715 cmsg->peer_id = incoming->spec->peer;
716 GNUNET_MQ_send (listener->client_mq,
717 mqm);
718} 670}
719 671
720 672
@@ -730,93 +682,85 @@ incoming_suggest (struct Operation *incoming,
730 * our virtual table and subsequent msgs would be routed differently (as 682 * our virtual table and subsequent msgs would be routed differently (as
731 * we then know what type of operation this is). 683 * we then know what type of operation this is).
732 * 684 *
733 * @param op the operation state 685 * @param cls the operation state
734 * @param mh the received message 686 * @param msg the received message
735 * @return #GNUNET_OK if the channel should be kept alive, 687 * @return #GNUNET_OK if the channel should be kept alive,
736 * #GNUNET_SYSERR to destroy the channel 688 * #GNUNET_SYSERR to destroy the channel
737 */ 689 */
738static int 690static void
739handle_incoming_msg (struct Operation *op, 691handle_incoming_msg (void *cls,
740 const struct GNUNET_MessageHeader *mh) 692 const struct OperationRequestMessage *msg)
741{ 693{
742 const struct OperationRequestMessage *msg; 694 struct Operation *op = cls;
743 struct Listener *listener = op->listener; 695 struct Listener *listener = op->listener;
744 struct OperationSpecification *spec;
745 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;
746 699
747 msg = (const struct OperationRequestMessage *) mh;
748 GNUNET_assert (GNUNET_YES == op->is_incoming);
749 if (GNUNET_MESSAGE_TYPE_SET_P2P_OPERATION_REQUEST != ntohs (mh->type))
750 {
751 GNUNET_break_op (0);
752 return GNUNET_SYSERR;
753 }
754 /* double operation request */
755 if (NULL != op->spec)
756 {
757 GNUNET_break_op (0);
758 return GNUNET_SYSERR;
759 }
760 spec = GNUNET_new (struct OperationSpecification);
761 nested_context = GNUNET_MQ_extract_nested_mh (msg); 700 nested_context = GNUNET_MQ_extract_nested_mh (msg);
762 if ( (NULL != nested_context) &&
763 (ntohs (nested_context->size) > GNUNET_SET_CONTEXT_MESSAGE_MAX_SIZE) )
764 {
765 GNUNET_break_op (0);
766 GNUNET_free (spec);
767 return GNUNET_SYSERR;
768 }
769 /* Make a copy of the nested_context (application-specific context 701 /* Make a copy of the nested_context (application-specific context
770 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
771 listener later on */ 703 listener later on */
772 if (NULL != nested_context) 704 if (NULL != nested_context)
773 spec->context_msg = GNUNET_copy_message (nested_context); 705 op->context_msg = GNUNET_copy_message (nested_context);
774 spec->operation = ntohl (msg->operation); 706 op->remote_element_count = ntohl (msg->element_count);
775 spec->app_id = listener->app_id;
776 spec->salt = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
777 UINT32_MAX);
778 spec->peer = op->peer;
779 spec->remote_element_count = ntohl (msg->element_count);
780 op->spec = spec;
781
782 listener = op->listener;
783 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 707 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
784 "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",
785 ntohl (msg->operation), 709 (uint32_t) ntohl (msg->operation),
786 GNUNET_h2s (&listener->app_id)); 710 GNUNET_h2s (&op->listener->app_id));
787 incoming_suggest (op, 711 GNUNET_assert (0 == op->suggest_id);
788 listener); 712 if (0 == suggest_id)
789 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() */
790} 732}
791 733
792 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 */
793static void 741static void
794execute_add (struct Set *set, 742execute_add (struct Set *set,
795 const struct GNUNET_MessageHeader *m) 743 const struct GNUNET_SET_ElementMessage *msg)
796{ 744{
797 const struct GNUNET_SET_ElementMessage *msg;
798 struct GNUNET_SET_Element el; 745 struct GNUNET_SET_Element el;
799 struct ElementEntry *ee; 746 struct ElementEntry *ee;
800 struct GNUNET_HashCode hash; 747 struct GNUNET_HashCode hash;
801 748
802 GNUNET_assert (GNUNET_MESSAGE_TYPE_SET_ADD == ntohs (m->type)); 749 GNUNET_assert (GNUNET_MESSAGE_TYPE_SET_ADD == ntohs (msg->header.type));
803 750 el.size = ntohs (msg->header.size) - sizeof (*msg);
804 msg = (const struct GNUNET_SET_ElementMessage *) m;
805 el.size = ntohs (m->size) - sizeof *msg;
806 el.data = &msg[1]; 751 el.data = &msg[1];
807 el.element_type = ntohs (msg->element_type); 752 el.element_type = ntohs (msg->element_type);
808 GNUNET_SET_element_hash (&el, &hash); 753 GNUNET_SET_element_hash (&el,
809 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 754 &hash);
810 "Client inserts element %s of size %u\n",
811 GNUNET_h2s (&hash),
812 el.size);
813
814 ee = GNUNET_CONTAINER_multihashmap_get (set->content->elements, 755 ee = GNUNET_CONTAINER_multihashmap_get (set->content->elements,
815 &hash); 756 &hash);
816
817 if (NULL == ee) 757 if (NULL == ee)
818 { 758 {
819 ee = GNUNET_malloc (el.size + sizeof *ee); 759 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
760 "Client inserts element %s of size %u\n",
761 GNUNET_h2s (&hash),
762 el.size);
763 ee = GNUNET_malloc (el.size + sizeof (*ee));
820 ee->element.size = el.size; 764 ee->element.size = el.size;
821 GNUNET_memcpy (&ee[1], 765 GNUNET_memcpy (&ee[1],
822 el.data, 766 el.data,
@@ -833,8 +777,17 @@ execute_add (struct Set *set,
833 ee, 777 ee,
834 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); 778 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
835 } 779 }
836 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))
837 { 785 {
786 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
787 "Client inserted element %s of size %u twice (ignored)\n",
788 GNUNET_h2s (&hash),
789 el.size);
790
838 /* same element inserted twice */ 791 /* same element inserted twice */
839 return; 792 return;
840 } 793 }
@@ -844,29 +797,31 @@ execute_add (struct Set *set,
844 .generation = set->current_generation, 797 .generation = set->current_generation,
845 .added = GNUNET_YES 798 .added = GNUNET_YES
846 }; 799 };
847 GNUNET_array_append (ee->mutations, ee->mutations_size, mut); 800 GNUNET_array_append (ee->mutations,
801 ee->mutations_size,
802 mut);
848 } 803 }
849 804 set->vt->add (set->state,
850 set->vt->add (set->state, ee); 805 ee);
851} 806}
852 807
853 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 */
854static void 815static void
855execute_remove (struct Set *set, 816execute_remove (struct Set *set,
856 const struct GNUNET_MessageHeader *m) 817 const struct GNUNET_SET_ElementMessage *msg)
857{ 818{
858 const struct GNUNET_SET_ElementMessage *msg;
859 struct GNUNET_SET_Element el; 819 struct GNUNET_SET_Element el;
860 struct ElementEntry *ee; 820 struct ElementEntry *ee;
861 struct GNUNET_HashCode hash; 821 struct GNUNET_HashCode hash;
862 822
863 GNUNET_assert (GNUNET_MESSAGE_TYPE_SET_REMOVE == ntohs (m->type)); 823 GNUNET_assert (GNUNET_MESSAGE_TYPE_SET_REMOVE == ntohs (msg->header.type));
864 824 el.size = ntohs (msg->header.size) - sizeof (*msg);
865 msg = (const struct GNUNET_SET_ElementMessage *) m;
866 el.size = ntohs (m->size) - sizeof *msg;
867 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
868 "Client removes element of size %u\n",
869 el.size);
870 el.data = &msg[1]; 825 el.data = &msg[1];
871 el.element_type = ntohs (msg->element_type); 826 el.element_type = ntohs (msg->element_type);
872 GNUNET_SET_element_hash (&el, &hash); 827 GNUNET_SET_element_hash (&el, &hash);
@@ -875,11 +830,21 @@ execute_remove (struct Set *set,
875 if (NULL == ee) 830 if (NULL == ee)
876 { 831 {
877 /* Client tried to remove non-existing element. */ 832 /* Client tried to remove non-existing element. */
833 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
834 "Client removes non-existing element of size %u\n",
835 el.size);
878 return; 836 return;
879 } 837 }
880 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))
881 { 843 {
882 /* Client tried to remove element twice */ 844 /* Client tried to remove element twice */
845 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
846 "Client removed element of size %u twice (ignored)\n",
847 el.size);
883 return; 848 return;
884 } 849 }
885 else 850 else
@@ -888,24 +853,37 @@ execute_remove (struct Set *set,
888 .generation = set->current_generation, 853 .generation = set->current_generation,
889 .added = GNUNET_NO 854 .added = GNUNET_NO
890 }; 855 };
891 GNUNET_array_append (ee->mutations, ee->mutations_size, mut); 856
857 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
858 "Client removes element of size %u\n",
859 el.size);
860
861 GNUNET_array_append (ee->mutations,
862 ee->mutations_size,
863 mut);
892 } 864 }
893 set->vt->remove (set->state, ee); 865 set->vt->remove (set->state,
866 ee);
894} 867}
895 868
896 869
897 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 */
898static void 876static void
899execute_mutation (struct Set *set, 877execute_mutation (struct Set *set,
900 const struct GNUNET_MessageHeader *m) 878 const struct GNUNET_SET_ElementMessage *msg)
901{ 879{
902 switch (ntohs (m->type)) 880 switch (ntohs (msg->header.type))
903 { 881 {
904 case GNUNET_MESSAGE_TYPE_SET_ADD: 882 case GNUNET_MESSAGE_TYPE_SET_ADD:
905 execute_add (set, m); 883 execute_add (set, msg);
906 break; 884 break;
907 case GNUNET_MESSAGE_TYPE_SET_REMOVE: 885 case GNUNET_MESSAGE_TYPE_SET_REMOVE:
908 execute_remove (set, m); 886 execute_remove (set, msg);
909 break; 887 break;
910 default: 888 default:
911 GNUNET_break (0); 889 GNUNET_break (0);
@@ -913,6 +891,34 @@ execute_mutation (struct Set *set,
913} 891}
914 892
915 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
916 922
917/** 923/**
918 * 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
@@ -936,65 +942,45 @@ send_client_element (struct Set *set)
936 struct GNUNET_SET_IterResponseMessage *msg; 942 struct GNUNET_SET_IterResponseMessage *msg;
937 943
938 GNUNET_assert (NULL != set->iter); 944 GNUNET_assert (NULL != set->iter);
939 945 do {
940again: 946 ret = GNUNET_CONTAINER_multihashmap_iterator_next (set->iter,
941 947 NULL,
942 ret = GNUNET_CONTAINER_multihashmap_iterator_next (set->iter, 948 (const void **) &ee);
943 NULL, 949 if (GNUNET_NO == ret)
944 (const void **) &ee);
945 if (GNUNET_NO == ret)
946 {
947 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
948 "Iteration on %p done.\n",
949 (void *) set);
950 ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_ITER_DONE);
951 GNUNET_CONTAINER_multihashmap_iterator_destroy (set->iter);
952 set->iter = NULL;
953 set->iteration_id++;
954
955 GNUNET_assert (set->content->iterator_count > 0);
956 set->content->iterator_count -= 1;
957
958 if (0 == set->content->iterator_count)
959 { 950 {
960 while (NULL != set->content->pending_mutations_head) 951 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
961 { 952 "Iteration on %p done.\n",
962 struct PendingMutation *pm; 953 set);
963 954 ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_ITER_DONE);
964 pm = set->content->pending_mutations_head; 955 GNUNET_CONTAINER_multihashmap_iterator_destroy (set->iter);
965 GNUNET_CONTAINER_DLL_remove (set->content->pending_mutations_head, 956 set->iter = NULL;
966 set->content->pending_mutations_tail, 957 set->iteration_id++;
967 pm); 958 GNUNET_assert (set->content->iterator_count > 0);
968 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 959 set->content->iterator_count--;
969 "Executing pending mutation on %p.\n", 960 execute_delayed_mutations (set);
970 (void *) pm->set); 961 GNUNET_MQ_send (set->cs->mq,
971 execute_mutation (pm->set, pm->mutation_message); 962 ev);
972 GNUNET_free (pm->mutation_message); 963 return;
973 GNUNET_free (pm);
974 }
975 } 964 }
976
977 }
978 else
979 {
980 GNUNET_assert (NULL != ee); 965 GNUNET_assert (NULL != ee);
981 966 } while (GNUNET_NO ==
982 if (GNUNET_NO == is_element_of_iteration (ee, set)) 967 is_element_of_generation (ee,
983 goto again; 968 set->iter_generation,
984 969 set->excluded_generations,
985 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 970 set->excluded_generations_size));
986 "Sending iteration element on %p.\n", 971 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
987 (void *) set); 972 "Sending iteration element on %p.\n",
988 ev = GNUNET_MQ_msg_extra (msg, 973 set);
989 ee->element.size, 974 ev = GNUNET_MQ_msg_extra (msg,
990 GNUNET_MESSAGE_TYPE_SET_ITER_ELEMENT); 975 ee->element.size,
991 GNUNET_memcpy (&msg[1], 976 GNUNET_MESSAGE_TYPE_SET_ITER_ELEMENT);
992 ee->element.data, 977 GNUNET_memcpy (&msg[1],
993 ee->element.size); 978 ee->element.data,
994 msg->element_type = htons (ee->element.element_type); 979 ee->element.size);
995 msg->iteration_id = htons (set->iteration_id); 980 msg->element_type = htons (ee->element.element_type);
996 } 981 msg->iteration_id = htons (set->iteration_id);
997 GNUNET_MQ_send (set->client_mq, ev); 982 GNUNET_MQ_send (set->cs->mq,
983 ev);
998} 984}
999 985
1000 986
@@ -1004,30 +990,28 @@ again:
1004 * can right now start an iteration. If all checks out, starts 990 * can right now start an iteration. If all checks out, starts
1005 * sending the elements of the set to the client. 991 * sending the elements of the set to the client.
1006 * 992 *
1007 * @param cls unused 993 * @param cls client that sent the message
1008 * @param client client that sent the message
1009 * @param m message sent by the client 994 * @param m message sent by the client
1010 */ 995 */
1011static void 996static void
1012handle_client_iterate (void *cls, 997handle_client_iterate (void *cls,
1013 struct GNUNET_SERVER_Client *client,
1014 const struct GNUNET_MessageHeader *m) 998 const struct GNUNET_MessageHeader *m)
1015{ 999{
1000 struct ClientState *cs = cls;
1016 struct Set *set; 1001 struct Set *set;
1017 1002
1018 set = set_get (client); 1003 if (NULL == (set = cs->set))
1019 if (NULL == set)
1020 { 1004 {
1021 /* attempt to iterate over a non existing set */ 1005 /* attempt to iterate over a non existing set */
1022 GNUNET_break (0); 1006 GNUNET_break (0);
1023 GNUNET_SERVER_client_disconnect (client); 1007 GNUNET_SERVICE_client_drop (cs->client);
1024 return; 1008 return;
1025 } 1009 }
1026 if (NULL != set->iter) 1010 if (NULL != set->iter)
1027 { 1011 {
1028 /* Only one concurrent iterate-action allowed per set */ 1012 /* Only one concurrent iterate-action allowed per set */
1029 GNUNET_break (0); 1013 GNUNET_break (0);
1030 GNUNET_SERVER_client_disconnect (client); 1014 GNUNET_SERVICE_client_drop (cs->client);
1031 return; 1015 return;
1032 } 1016 }
1033 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1017 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -1035,9 +1019,8 @@ handle_client_iterate (void *cls,
1035 (void *) set, 1019 (void *) set,
1036 set->current_generation, 1020 set->current_generation,
1037 GNUNET_CONTAINER_multihashmap_size (set->content->elements)); 1021 GNUNET_CONTAINER_multihashmap_size (set->content->elements));
1038 GNUNET_SERVER_receive_done (client, 1022 GNUNET_SERVICE_client_continue (cs->client);
1039 GNUNET_OK); 1023 set->content->iterator_count++;
1040 set->content->iterator_count += 1;
1041 set->iter = GNUNET_CONTAINER_multihashmap_iterator_create (set->content->elements); 1024 set->iter = GNUNET_CONTAINER_multihashmap_iterator_create (set->content->elements);
1042 set->iter_generation = set->current_generation; 1025 set->iter_generation = set->current_generation;
1043 send_client_element (set); 1026 send_client_element (set);
@@ -1049,27 +1032,24 @@ handle_client_iterate (void *cls,
1049 * the first request from a client, and includes the type of set 1032 * the first request from a client, and includes the type of set
1050 * operation to be performed. 1033 * operation to be performed.
1051 * 1034 *
1052 * @param cls unused 1035 * @param cls client that sent the message
1053 * @param client client that sent the message
1054 * @param m message sent by the client 1036 * @param m message sent by the client
1055 */ 1037 */
1056static void 1038static void
1057handle_client_create_set (void *cls, 1039handle_client_create_set (void *cls,
1058 struct GNUNET_SERVER_Client *client, 1040 const struct GNUNET_SET_CreateMessage *msg)
1059 const struct GNUNET_MessageHeader *m)
1060{ 1041{
1061 const struct GNUNET_SET_CreateMessage *msg; 1042 struct ClientState *cs = cls;
1062 struct Set *set; 1043 struct Set *set;
1063 1044
1064 msg = (const struct GNUNET_SET_CreateMessage *) m;
1065 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1045 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1066 "Client created new set (operation %u)\n", 1046 "Client created new set (operation %u)\n",
1067 ntohl (msg->operation)); 1047 (uint32_t) ntohl (msg->operation));
1068 if (NULL != set_get (client)) 1048 if (NULL != cs->set)
1069 { 1049 {
1070 /* There can only be one set per client */ 1050 /* There can only be one set per client */
1071 GNUNET_break (0); 1051 GNUNET_break (0);
1072 GNUNET_SERVER_client_disconnect (client); 1052 GNUNET_SERVICE_client_drop (cs->client);
1073 return; 1053 return;
1074 } 1054 }
1075 set = GNUNET_new (struct Set); 1055 set = GNUNET_new (struct Set);
@@ -1084,28 +1064,25 @@ handle_client_create_set (void *cls,
1084 default: 1064 default:
1085 GNUNET_free (set); 1065 GNUNET_free (set);
1086 GNUNET_break (0); 1066 GNUNET_break (0);
1087 GNUNET_SERVER_client_disconnect (client); 1067 GNUNET_SERVICE_client_drop (cs->client);
1088 return; 1068 return;
1089 } 1069 }
1090 set->operation = ntohl (msg->operation); 1070 set->operation = (enum GNUNET_SET_OperationType) ntohl (msg->operation);
1091 set->state = set->vt->create (); 1071 set->state = set->vt->create ();
1092 if (NULL == set->state) 1072 if (NULL == set->state)
1093 { 1073 {
1094 /* initialization failed (i.e. out of memory) */ 1074 /* initialization failed (i.e. out of memory) */
1095 GNUNET_free (set); 1075 GNUNET_free (set);
1096 GNUNET_SERVER_client_disconnect (client); 1076 GNUNET_SERVICE_client_drop (cs->client);
1097 return; 1077 return;
1098 } 1078 }
1099 set->content = GNUNET_new (struct SetContent); 1079 set->content = GNUNET_new (struct SetContent);
1100 set->content->refcount = 1; 1080 set->content->refcount = 1;
1101 set->content->elements = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES); 1081 set->content->elements = GNUNET_CONTAINER_multihashmap_create (1,
1102 set->client = client; 1082 GNUNET_YES);
1103 set->client_mq = GNUNET_MQ_queue_for_server_client (client); 1083 set->cs = cs;
1104 GNUNET_CONTAINER_DLL_insert (sets_head, 1084 cs->set = set;
1105 sets_tail, 1085 GNUNET_SERVICE_client_continue (cs->client);
1106 set);
1107 GNUNET_SERVER_receive_done (client,
1108 GNUNET_OK);
1109} 1086}
1110 1087
1111 1088
@@ -1121,31 +1098,12 @@ handle_client_create_set (void *cls,
1121static void 1098static void
1122incoming_timeout_cb (void *cls) 1099incoming_timeout_cb (void *cls)
1123{ 1100{
1124 struct Operation *incoming = cls; 1101 struct Operation *op = cls;
1125 1102
1126 incoming->timeout_task = NULL; 1103 op->timeout_task = NULL;
1127 GNUNET_assert (GNUNET_YES == incoming->is_incoming);
1128 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1104 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1129 "Remote peer's incoming request timed out\n"); 1105 "Remote peer's incoming request timed out\n");
1130 incoming_destroy (incoming);
1131}
1132
1133
1134/**
1135 * Terminates an incoming operation in case we have not yet received an
1136 * operation request. Called by the channel destruction handler.
1137 *
1138 * @param op the channel context
1139 */
1140static void
1141handle_incoming_disconnect (struct Operation *op)
1142{
1143 GNUNET_assert (GNUNET_YES == op->is_incoming);
1144 /* channel is already dead, incoming_destroy must not
1145 * destroy it ... */
1146 op->channel = NULL;
1147 incoming_destroy (op); 1106 incoming_destroy (op);
1148 op->vt = NULL;
1149} 1107}
1150 1108
1151 1109
@@ -1161,108 +1119,200 @@ handle_incoming_disconnect (struct Operation *op)
1161 * 1119 *
1162 * @param cls closure 1120 * @param cls closure
1163 * @param channel new handle to the channel 1121 * @param channel new handle to the channel
1164 * @param initiator peer that started the channel 1122 * @param source peer that started the channel
1165 * @param port Port this channel is for.
1166 * @param options Unused.
1167 * @return initial channel context for the channel 1123 * @return initial channel context for the channel
1168 * returns NULL on error 1124 * returns NULL on error
1169 */ 1125 */
1170static void * 1126static void *
1171channel_new_cb (void *cls, 1127channel_new_cb (void *cls,
1172 struct GNUNET_CADET_Channel *channel, 1128 struct GNUNET_CADET_Channel *channel,
1173 const struct GNUNET_PeerIdentity *initiator, 1129 const struct GNUNET_PeerIdentity *source)
1174 const struct GNUNET_HashCode *port,
1175 enum GNUNET_CADET_ChannelOption options)
1176{ 1130{
1177 static const struct SetVT incoming_vt = {
1178 .msg_handler = &handle_incoming_msg,
1179 .peer_disconnect = &handle_incoming_disconnect
1180 };
1181 struct Listener *listener = cls; 1131 struct Listener *listener = cls;
1182 struct Operation *incoming; 1132 struct Operation *op;
1183 1133
1184 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1134 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1185 "New incoming channel\n"); 1135 "New incoming channel\n");
1186 incoming = GNUNET_new (struct Operation); 1136 op = GNUNET_new (struct Operation);
1187 incoming->listener = listener; 1137 op->listener = listener;
1188 incoming->is_incoming = GNUNET_YES; 1138 op->peer = *source;
1189 incoming->peer = *initiator; 1139 op->channel = channel;
1190 incoming->channel = channel; 1140 op->mq = GNUNET_CADET_get_mq (op->channel);
1191 incoming->mq = GNUNET_CADET_mq_create (incoming->channel); 1141 op->salt = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
1192 incoming->vt = &incoming_vt; 1142 UINT32_MAX);
1193 incoming->timeout_task 1143 op->timeout_task
1194 = GNUNET_SCHEDULER_add_delayed (INCOMING_CHANNEL_TIMEOUT, 1144 = GNUNET_SCHEDULER_add_delayed (INCOMING_CHANNEL_TIMEOUT,
1195 &incoming_timeout_cb, 1145 &incoming_timeout_cb,
1196 incoming); 1146 op);
1197 GNUNET_CONTAINER_DLL_insert_tail (incoming_head, 1147 GNUNET_CONTAINER_DLL_insert (listener->op_head,
1198 incoming_tail, 1148 listener->op_tail,
1199 incoming); 1149 op);
1200 // incoming_suggest (incoming, 1150 return op;
1201 // listener); 1151}
1202 return incoming; 1152
1153
1154/**
1155 * Function called whenever a channel is destroyed. Should clean up
1156 * any associated state. It must NOT call
1157 * GNUNET_CADET_channel_destroy() on the channel.
1158 *
1159 * The peer_disconnect function is part of a a virtual table set initially either
1160 * when a peer creates a new channel with us, or once we create
1161 * a new channel ourselves (evaluate).
1162 *
1163 * Once we know the exact type of operation (union/intersection), the vt is
1164 * replaced with an operation specific instance (_GSS_[op]_vt).
1165 *
1166 * @param channel_ctx place where local state associated
1167 * with the channel is stored
1168 * @param channel connection to the other end (henceforth invalid)
1169 */
1170static void
1171channel_end_cb (void *channel_ctx,
1172 const struct GNUNET_CADET_Channel *channel)
1173{
1174 struct Operation *op = channel_ctx;
1175
1176 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1177 "channel_end_cb called\n");
1178 op->channel = NULL;
1179 if (NULL != op->listener)
1180 incoming_destroy (op);
1181 else if (NULL != op->set)
1182 op->set->vt->channel_death (op);
1183 else
1184 _GSS_operation_destroy (op,
1185 GNUNET_YES);
1186 GNUNET_free (op);
1187}
1188
1189
1190/**
1191 * Function called whenever an MQ-channel's transmission window size changes.
1192 *
1193 * The first callback in an outgoing channel will be with a non-zero value
1194 * and will mean the channel is connected to the destination.
1195 *
1196 * For an incoming channel it will be called immediately after the
1197 * #GNUNET_CADET_ConnectEventHandler, also with a non-zero value.
1198 *
1199 * @param cls Channel closure.
1200 * @param channel Connection to the other end (henceforth invalid).
1201 * @param window_size New window size. If the is more messages than buffer size
1202 * this value will be negative..
1203 */
1204static void
1205channel_window_cb (void *cls,
1206 const struct GNUNET_CADET_Channel *channel,
1207 int window_size)
1208{
1209 /* FIXME: not implemented, we could do flow control here... */
1203} 1210}
1204 1211
1205 1212
1206/** 1213/**
1207 * Called when a client wants to create a new listener. 1214 * Called when a client wants to create a new listener.
1208 * 1215 *
1209 * @param cls unused 1216 * @param cls client that sent the message
1210 * @param client client that sent the message 1217 * @param msg message sent by the client
1211 * @param m message sent by the client
1212 */ 1218 */
1213static void 1219static void
1214handle_client_listen (void *cls, 1220handle_client_listen (void *cls,
1215 struct GNUNET_SERVER_Client *client, 1221 const struct GNUNET_SET_ListenMessage *msg)
1216 const struct GNUNET_MessageHeader *m)
1217{ 1222{
1218 const struct GNUNET_SET_ListenMessage *msg; 1223 struct ClientState *cs = cls;
1224 struct GNUNET_MQ_MessageHandler cadet_handlers[] = {
1225 GNUNET_MQ_hd_var_size (incoming_msg,
1226 GNUNET_MESSAGE_TYPE_SET_P2P_OPERATION_REQUEST,
1227 struct OperationRequestMessage,
1228 NULL),
1229 GNUNET_MQ_hd_var_size (union_p2p_ibf,
1230 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_IBF,
1231 struct IBFMessage,
1232 NULL),
1233 GNUNET_MQ_hd_var_size (union_p2p_elements,
1234 GNUNET_MESSAGE_TYPE_SET_P2P_ELEMENTS,
1235 struct GNUNET_SET_ElementMessage,
1236 NULL),
1237 GNUNET_MQ_hd_var_size (union_p2p_offer,
1238 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_OFFER,
1239 struct GNUNET_MessageHeader,
1240 NULL),
1241 GNUNET_MQ_hd_var_size (union_p2p_inquiry,
1242 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_INQUIRY,
1243 struct InquiryMessage,
1244 NULL),
1245 GNUNET_MQ_hd_var_size (union_p2p_demand,
1246 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DEMAND,
1247 struct GNUNET_MessageHeader,
1248 NULL),
1249 GNUNET_MQ_hd_fixed_size (union_p2p_done,
1250 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DONE,
1251 struct GNUNET_MessageHeader,
1252 NULL),
1253 GNUNET_MQ_hd_fixed_size (union_p2p_full_done,
1254 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_DONE,
1255 struct GNUNET_MessageHeader,
1256 NULL),
1257 GNUNET_MQ_hd_fixed_size (union_p2p_request_full,
1258 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_REQUEST_FULL,
1259 struct GNUNET_MessageHeader,
1260 NULL),
1261 GNUNET_MQ_hd_var_size (union_p2p_strata_estimator,
1262 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SE,
1263 struct StrataEstimatorMessage,
1264 NULL),
1265 GNUNET_MQ_hd_var_size (union_p2p_strata_estimator,
1266 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SEC,
1267 struct StrataEstimatorMessage,
1268 NULL),
1269 GNUNET_MQ_hd_var_size (union_p2p_full_element,
1270 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_ELEMENT,
1271 struct GNUNET_SET_ElementMessage,
1272 NULL),
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,
1278 GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_BF,
1279 struct BFMessage,
1280 NULL),
1281 GNUNET_MQ_hd_fixed_size (intersection_p2p_done,
1282 GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_DONE,
1283 struct IntersectionDoneMessage,
1284 NULL),
1285 GNUNET_MQ_handler_end ()
1286 };
1219 struct Listener *listener; 1287 struct Listener *listener;
1220 struct Operation *op;
1221 1288
1222 msg = (const struct GNUNET_SET_ListenMessage *) m; 1289 if (NULL != cs->listener)
1223 if (NULL != listener_get (client))
1224 { 1290 {
1225 /* max. one active listener per client! */ 1291 /* max. one active listener per client! */
1226 GNUNET_break (0); 1292 GNUNET_break (0);
1227 GNUNET_SERVER_client_disconnect (client); 1293 GNUNET_SERVICE_client_drop (cs->client);
1228 return; 1294 return;
1229 } 1295 }
1230 listener = GNUNET_new (struct Listener); 1296 listener = GNUNET_new (struct Listener);
1231 listener->client = client; 1297 listener->cs = cs;
1232 listener->client_mq = GNUNET_MQ_queue_for_server_client (client);
1233 listener->app_id = msg->app_id; 1298 listener->app_id = msg->app_id;
1234 listener->operation = ntohl (msg->operation); 1299 listener->operation = (enum GNUNET_SET_OperationType) ntohl (msg->operation);
1235 GNUNET_CONTAINER_DLL_insert_tail (listeners_head, 1300 GNUNET_CONTAINER_DLL_insert (listener_head,
1236 listeners_tail, 1301 listener_tail,
1237 listener); 1302 listener);
1238 listener->open_port = GNUNET_CADET_open_port (cadet,
1239 &msg->app_id,
1240 &channel_new_cb,
1241 listener);
1242 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1303 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1243 "New listener created (op %u, port %s)\n", 1304 "New listener created (op %u, port %s)\n",
1244 listener->operation, 1305 listener->operation,
1245 GNUNET_h2s (&listener->app_id)); 1306 GNUNET_h2s (&listener->app_id));
1246 1307 listener->open_port
1247 /* check for existing incoming requests the listener might be interested in */ 1308 = GNUNET_CADET_open_port (cadet,
1248 for (op = incoming_head; NULL != op; op = op->next) 1309 &msg->app_id,
1249 { 1310 &channel_new_cb,
1250 if (NULL == op->spec) 1311 listener,
1251 continue; /* no details available yet */ 1312 &channel_window_cb,
1252 if (0 != op->suggest_id) 1313 &channel_end_cb,
1253 continue; /* this one has been already suggested to a listener */ 1314 cadet_handlers);
1254 if (listener->operation != op->spec->operation) 1315 GNUNET_SERVICE_client_continue (cs->client);
1255 continue; /* incompatible operation */
1256 if (0 != GNUNET_CRYPTO_hash_cmp (&listener->app_id,
1257 &op->spec->app_id))
1258 continue; /* incompatible appliation */
1259 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1260 "Found matching existing request\n");
1261 incoming_suggest (op,
1262 listener);
1263 }
1264 GNUNET_SERVER_receive_done (client,
1265 GNUNET_OK);
1266} 1316}
1267 1317
1268 1318
@@ -1270,64 +1320,73 @@ handle_client_listen (void *cls,
1270 * Called when the listening client rejects an operation 1320 * Called when the listening client rejects an operation
1271 * request by another peer. 1321 * request by another peer.
1272 * 1322 *
1273 * @param cls unused 1323 * @param cls client that sent the message
1274 * @param client client that sent the message 1324 * @param msg message sent by the client
1275 * @param m message sent by the client
1276 */ 1325 */
1277static void 1326static void
1278handle_client_reject (void *cls, 1327handle_client_reject (void *cls,
1279 struct GNUNET_SERVER_Client *client, 1328 const struct GNUNET_SET_RejectMessage *msg)
1280 const struct GNUNET_MessageHeader *m)
1281{ 1329{
1282 struct Operation *incoming; 1330 struct ClientState *cs = cls;
1283 const struct GNUNET_SET_RejectMessage *msg; 1331 struct Operation *op;
1284 1332
1285 msg = (const struct GNUNET_SET_RejectMessage *) m; 1333 op = get_incoming (ntohl (msg->accept_reject_id));
1286 incoming = get_incoming (ntohl (msg->accept_reject_id)); 1334 if (NULL == op)
1287 if (NULL == incoming)
1288 { 1335 {
1289 /* no matching incoming operation for this reject */ 1336 /* no matching incoming operation for this reject;
1290 GNUNET_break (0); 1337 could be that the other peer already disconnected... */
1291 GNUNET_SERVER_receive_done (client, 1338 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1292 GNUNET_SYSERR); 1339 "Client rejected unknown operation %u\n",
1340 (unsigned int) ntohl (msg->accept_reject_id));
1341 GNUNET_SERVICE_client_continue (cs->client);
1293 return; 1342 return;
1294 } 1343 }
1295 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1344 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1296 "Peer request (op %u, app %s) rejected by client\n", 1345 "Peer request (op %u, app %s) rejected by client\n",
1297 incoming->spec->operation, 1346 op->listener->operation,
1298 GNUNET_h2s (&incoming->spec->app_id)); 1347 GNUNET_h2s (&cs->listener->app_id));
1299 GNUNET_CADET_channel_destroy (incoming->channel); 1348 GNUNET_CADET_channel_destroy (op->channel);
1300 GNUNET_SERVER_receive_done (client, 1349 GNUNET_SERVICE_client_continue (cs->client);
1301 GNUNET_OK);
1302} 1350}
1303 1351
1304 1352
1353/**
1354 * Called when a client wants to add or remove an element to a set it inhabits.
1355 *
1356 * @param cls client that sent the message
1357 * @param msg message sent by the client
1358 */
1359static int
1360check_client_mutation (void *cls,
1361 const struct GNUNET_SET_ElementMessage *msg)
1362{
1363 /* NOTE: Technically, we should probably check with the
1364 block library whether the element we are given is well-formed */
1365 return GNUNET_OK;
1366}
1367
1305 1368
1306/** 1369/**
1307 * 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.
1308 * 1371 *
1309 * @param cls unused 1372 * @param cls client that sent the message
1310 * @param client client that sent the message 1373 * @param msg message sent by the client
1311 * @param m message sent by the client
1312 */ 1374 */
1313static void 1375static void
1314handle_client_mutation (void *cls, 1376handle_client_mutation (void *cls,
1315 struct GNUNET_SERVER_Client *client, 1377 const struct GNUNET_SET_ElementMessage *msg)
1316 const struct GNUNET_MessageHeader *m)
1317{ 1378{
1379 struct ClientState *cs = cls;
1318 struct Set *set; 1380 struct Set *set;
1319 1381
1320 set = set_get (client); 1382 if (NULL == (set = cs->set))
1321 if (NULL == set)
1322 { 1383 {
1323 /* client without a set requested an operation */ 1384 /* client without a set requested an operation */
1324 GNUNET_break (0); 1385 GNUNET_break (0);
1325 GNUNET_SERVER_client_disconnect (client); 1386 GNUNET_SERVICE_client_drop (cs->client);
1326 return; 1387 return;
1327 } 1388 }
1328 1389 GNUNET_SERVICE_client_continue (cs->client);
1329 GNUNET_SERVER_receive_done (client,
1330 GNUNET_OK);
1331 1390
1332 if (0 != set->content->iterator_count) 1391 if (0 != set->content->iterator_count)
1333 { 1392 {
@@ -1335,17 +1394,18 @@ handle_client_mutation (void *cls,
1335 1394
1336 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1395 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1337 "Scheduling mutation on set\n"); 1396 "Scheduling mutation on set\n");
1338
1339 pm = GNUNET_new (struct PendingMutation); 1397 pm = GNUNET_new (struct PendingMutation);
1340 pm->mutation_message = GNUNET_copy_message (m); 1398 pm->msg = (struct GNUNET_SET_ElementMessage *) GNUNET_copy_message (&msg->header);
1341 pm->set = set; 1399 pm->set = set;
1342 GNUNET_CONTAINER_DLL_insert (set->content->pending_mutations_head, 1400 GNUNET_CONTAINER_DLL_insert_tail (set->content->pending_mutations_head,
1343 set->content->pending_mutations_tail, 1401 set->content->pending_mutations_tail,
1344 pm); 1402 pm);
1345 return; 1403 return;
1346 } 1404 }
1347 1405 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1348 execute_mutation (set, m); 1406 "Executing mutation on set\n");
1407 execute_mutation (set,
1408 msg);
1349} 1409}
1350 1410
1351 1411
@@ -1362,8 +1422,8 @@ advance_generation (struct Set *set)
1362 1422
1363 if (set->current_generation == set->content->latest_generation) 1423 if (set->current_generation == set->content->latest_generation)
1364 { 1424 {
1365 set->content->latest_generation += 1; 1425 set->content->latest_generation++;
1366 set->current_generation += 1; 1426 set->current_generation++;
1367 return; 1427 return;
1368 } 1428 }
1369 1429
@@ -1371,10 +1431,8 @@ advance_generation (struct Set *set)
1371 1431
1372 r.start = set->current_generation + 1; 1432 r.start = set->current_generation + 1;
1373 r.end = set->content->latest_generation + 1; 1433 r.end = set->content->latest_generation + 1;
1374
1375 set->content->latest_generation = r.end; 1434 set->content->latest_generation = r.end;
1376 set->current_generation = r.end; 1435 set->current_generation = r.end;
1377
1378 GNUNET_array_append (set->excluded_generations, 1436 GNUNET_array_append (set->excluded_generations,
1379 set->excluded_generations_size, 1437 set->excluded_generations_size,
1380 r); 1438 r);
@@ -1386,64 +1444,148 @@ advance_generation (struct Set *set)
1386 * peer. Initiates the CADET connection to the listener and sends the 1444 * peer. Initiates the CADET connection to the listener and sends the
1387 * request. 1445 * request.
1388 * 1446 *
1389 * @param cls unused 1447 * @param cls client that sent the message
1390 * @param client client that sent the message 1448 * @param msg message sent by the client
1391 * @param m message sent by the client 1449 * @return #GNUNET_OK if the message is well-formed
1450 */
1451static int
1452check_client_evaluate (void *cls,
1453 const struct GNUNET_SET_EvaluateMessage *msg)
1454{
1455 /* FIXME: suboptimal, even if the context below could be NULL,
1456 there are malformed messages this does not check for... */
1457 return GNUNET_OK;
1458}
1459
1460
1461/**
1462 * Called when a client wants to initiate a set operation with another
1463 * peer. Initiates the CADET connection to the listener and sends the
1464 * request.
1465 *
1466 * @param cls client that sent the message
1467 * @param msg message sent by the client
1392 */ 1468 */
1393static void 1469static void
1394handle_client_evaluate (void *cls, 1470handle_client_evaluate (void *cls,
1395 struct GNUNET_SERVER_Client *client, 1471 const struct GNUNET_SET_EvaluateMessage *msg)
1396 const struct GNUNET_MessageHeader *m)
1397{ 1472{
1473 struct ClientState *cs = cls;
1474 struct Operation *op = GNUNET_new (struct Operation);
1475 const struct GNUNET_MQ_MessageHandler cadet_handlers[] = {
1476 GNUNET_MQ_hd_var_size (incoming_msg,
1477 GNUNET_MESSAGE_TYPE_SET_P2P_OPERATION_REQUEST,
1478 struct OperationRequestMessage,
1479 op),
1480 GNUNET_MQ_hd_var_size (union_p2p_ibf,
1481 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_IBF,
1482 struct IBFMessage,
1483 op),
1484 GNUNET_MQ_hd_var_size (union_p2p_elements,
1485 GNUNET_MESSAGE_TYPE_SET_P2P_ELEMENTS,
1486 struct GNUNET_SET_ElementMessage,
1487 op),
1488 GNUNET_MQ_hd_var_size (union_p2p_offer,
1489 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_OFFER,
1490 struct GNUNET_MessageHeader,
1491 op),
1492 GNUNET_MQ_hd_var_size (union_p2p_inquiry,
1493 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_INQUIRY,
1494 struct InquiryMessage,
1495 op),
1496 GNUNET_MQ_hd_var_size (union_p2p_demand,
1497 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DEMAND,
1498 struct GNUNET_MessageHeader,
1499 op),
1500 GNUNET_MQ_hd_fixed_size (union_p2p_done,
1501 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DONE,
1502 struct GNUNET_MessageHeader,
1503 op),
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,
1513 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SE,
1514 struct StrataEstimatorMessage,
1515 op),
1516 GNUNET_MQ_hd_var_size (union_p2p_strata_estimator,
1517 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SEC,
1518 struct StrataEstimatorMessage,
1519 op),
1520 GNUNET_MQ_hd_var_size (union_p2p_full_element,
1521 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_ELEMENT,
1522 struct GNUNET_SET_ElementMessage,
1523 op),
1524 GNUNET_MQ_hd_fixed_size (intersection_p2p_element_info,
1525 GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_ELEMENT_INFO,
1526 struct IntersectionElementInfoMessage,
1527 op),
1528 GNUNET_MQ_hd_var_size (intersection_p2p_bf,
1529 GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_BF,
1530 struct BFMessage,
1531 op),
1532 GNUNET_MQ_hd_fixed_size (intersection_p2p_done,
1533 GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_DONE,
1534 struct IntersectionDoneMessage,
1535 op),
1536 GNUNET_MQ_handler_end ()
1537 };
1398 struct Set *set; 1538 struct Set *set;
1399 const struct GNUNET_SET_EvaluateMessage *msg;
1400 struct OperationSpecification *spec;
1401 struct Operation *op;
1402 const struct GNUNET_MessageHeader *context; 1539 const struct GNUNET_MessageHeader *context;
1403 1540
1404 set = set_get (client); 1541 if (NULL == (set = cs->set))
1405 if (NULL == set)
1406 { 1542 {
1407 GNUNET_break (0); 1543 GNUNET_break (0);
1408 GNUNET_SERVER_client_disconnect (client); 1544 GNUNET_free (op);
1545 GNUNET_SERVICE_client_drop (cs->client);
1409 return; 1546 return;
1410 } 1547 }
1411 msg = (const struct GNUNET_SET_EvaluateMessage *) m; 1548 op->salt = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
1412 spec = GNUNET_new (struct OperationSpecification); 1549 UINT32_MAX);
1413 spec->operation = set->operation; 1550 op->peer = msg->target_peer;
1414 spec->app_id = msg->app_id; 1551 op->result_mode = ntohl (msg->result_mode);
1415 spec->salt = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, 1552 op->client_request_id = ntohl (msg->request_id);
1416 UINT32_MAX); 1553 op->byzantine = msg->byzantine;
1417 spec->peer = msg->target_peer; 1554 op->byzantine_lower_bound = msg->byzantine_lower_bound;
1418 spec->set = set; 1555 op->force_full = msg->force_full;
1419 spec->result_mode = ntohl (msg->result_mode); 1556 op->force_delta = msg->force_delta;
1420 spec->client_request_id = ntohl (msg->request_id);
1421 context = GNUNET_MQ_extract_nested_mh (msg); 1557 context = GNUNET_MQ_extract_nested_mh (msg);
1422 op = GNUNET_new (struct Operation);
1423 op->spec = spec;
1424 1558
1425 // Advance generation values, so that 1559 /* Advance generation values, so that
1426 // mutations won't interfer with the running operation. 1560 mutations won't interfer with the running operation. */
1561 op->set = set;
1427 op->generation_created = set->current_generation; 1562 op->generation_created = set->current_generation;
1428 advance_generation (set); 1563 advance_generation (set);
1429
1430 op->vt = set->vt;
1431 GNUNET_CONTAINER_DLL_insert (set->ops_head, 1564 GNUNET_CONTAINER_DLL_insert (set->ops_head,
1432 set->ops_tail, 1565 set->ops_tail,
1433 op); 1566 op);
1434 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1567 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1435 "Creating new CADET channel to port %s\n", 1568 "Creating new CADET channel to port %s for set operation type %u\n",
1436 GNUNET_h2s (&msg->app_id)); 1569 GNUNET_h2s (&msg->app_id),
1570 set->operation);
1437 op->channel = GNUNET_CADET_channel_create (cadet, 1571 op->channel = GNUNET_CADET_channel_create (cadet,
1438 op, 1572 op,
1439 &msg->target_peer, 1573 &msg->target_peer,
1440 &msg->app_id, 1574 &msg->app_id,
1441 GNUNET_CADET_OPTION_RELIABLE); 1575 GNUNET_CADET_OPTION_RELIABLE,
1442 op->mq = GNUNET_CADET_mq_create (op->channel); 1576 &channel_window_cb,
1443 set->vt->evaluate (op, 1577 &channel_end_cb,
1444 context); 1578 cadet_handlers);
1445 GNUNET_SERVER_receive_done (client, 1579 op->mq = GNUNET_CADET_get_mq (op->channel);
1446 GNUNET_OK); 1580 op->state = set->vt->evaluate (op,
1581 context);
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);
1447} 1589}
1448 1590
1449 1591
@@ -1452,24 +1594,21 @@ handle_client_evaluate (void *cls,
1452 * that we only expect acks for set elements, not after the 1594 * that we only expect acks for set elements, not after the
1453 * #GNUNET_MESSAGE_TYPE_SET_ITER_DONE message. 1595 * #GNUNET_MESSAGE_TYPE_SET_ITER_DONE message.
1454 * 1596 *
1455 * @param cls unused 1597 * @param cls client the client
1456 * @param client the client 1598 * @param ack the message
1457 * @param m the message
1458 */ 1599 */
1459static void 1600static void
1460handle_client_iter_ack (void *cls, 1601handle_client_iter_ack (void *cls,
1461 struct GNUNET_SERVER_Client *client, 1602 const struct GNUNET_SET_IterAckMessage *ack)
1462 const struct GNUNET_MessageHeader *m)
1463{ 1603{
1464 const struct GNUNET_SET_IterAckMessage *ack; 1604 struct ClientState *cs = cls;
1465 struct Set *set; 1605 struct Set *set;
1466 1606
1467 set = set_get (client); 1607 if (NULL == (set = cs->set))
1468 if (NULL == set)
1469 { 1608 {
1470 /* client without a set acknowledged receiving a value */ 1609 /* client without a set acknowledged receiving a value */
1471 GNUNET_break (0); 1610 GNUNET_break (0);
1472 GNUNET_SERVER_client_disconnect (client); 1611 GNUNET_SERVICE_client_drop (cs->client);
1473 return; 1612 return;
1474 } 1613 }
1475 if (NULL == set->iter) 1614 if (NULL == set->iter)
@@ -1477,12 +1616,10 @@ handle_client_iter_ack (void *cls,
1477 /* client sent an ack, but we were not expecting one (as 1616 /* client sent an ack, but we were not expecting one (as
1478 set iteration has finished) */ 1617 set iteration has finished) */
1479 GNUNET_break (0); 1618 GNUNET_break (0);
1480 GNUNET_SERVER_client_disconnect (client); 1619 GNUNET_SERVICE_client_drop (cs->client);
1481 return; 1620 return;
1482 } 1621 }
1483 ack = (const struct GNUNET_SET_IterAckMessage *) m; 1622 GNUNET_SERVICE_client_continue (cs->client);
1484 GNUNET_SERVER_receive_done (client,
1485 GNUNET_OK);
1486 if (ntohl (ack->send_more)) 1623 if (ntohl (ack->send_more))
1487 { 1624 {
1488 send_client_element (set); 1625 send_client_element (set);
@@ -1497,86 +1634,68 @@ handle_client_iter_ack (void *cls,
1497 1634
1498 1635
1499/** 1636/**
1500 * Handle a request from the client to 1637 * Handle a request from the client to copy a set.
1501 * copy a set.
1502 * 1638 *
1503 * @param cls unused 1639 * @param cls the client
1504 * @param client the client
1505 * @param mh the message 1640 * @param mh the message
1506 */ 1641 */
1507static void 1642static void
1508handle_client_copy_lazy_prepare (void *cls, 1643handle_client_copy_lazy_prepare (void *cls,
1509 struct GNUNET_SERVER_Client *client,
1510 const struct GNUNET_MessageHeader *mh) 1644 const struct GNUNET_MessageHeader *mh)
1511{ 1645{
1646 struct ClientState *cs = cls;
1512 struct Set *set; 1647 struct Set *set;
1513 struct LazyCopyRequest *cr; 1648 struct LazyCopyRequest *cr;
1514 struct GNUNET_MQ_Envelope *ev; 1649 struct GNUNET_MQ_Envelope *ev;
1515 struct GNUNET_SET_CopyLazyResponseMessage *resp_msg; 1650 struct GNUNET_SET_CopyLazyResponseMessage *resp_msg;
1516 1651
1517 set = set_get (client); 1652 if (NULL == (set = cs->set))
1518 if (NULL == set)
1519 { 1653 {
1520 /* client without a set requested an operation */ 1654 /* client without a set requested an operation */
1521 GNUNET_break (0); 1655 GNUNET_break (0);
1522 GNUNET_SERVER_client_disconnect (client); 1656 GNUNET_SERVICE_client_drop (cs->client);
1523 return; 1657 return;
1524 } 1658 }
1525 1659 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1660 "Client requested creation of lazy copy\n");
1526 cr = GNUNET_new (struct LazyCopyRequest); 1661 cr = GNUNET_new (struct LazyCopyRequest);
1527 1662 cr->cookie = ++lazy_copy_cookie;
1528 cr->cookie = lazy_copy_cookie;
1529 lazy_copy_cookie += 1;
1530 cr->source_set = set; 1663 cr->source_set = set;
1531
1532 GNUNET_CONTAINER_DLL_insert (lazy_copy_head, 1664 GNUNET_CONTAINER_DLL_insert (lazy_copy_head,
1533 lazy_copy_tail, 1665 lazy_copy_tail,
1534 cr); 1666 cr);
1535
1536
1537 ev = GNUNET_MQ_msg (resp_msg, 1667 ev = GNUNET_MQ_msg (resp_msg,
1538 GNUNET_MESSAGE_TYPE_SET_COPY_LAZY_RESPONSE); 1668 GNUNET_MESSAGE_TYPE_SET_COPY_LAZY_RESPONSE);
1539 resp_msg->cookie = cr->cookie; 1669 resp_msg->cookie = cr->cookie;
1540 GNUNET_MQ_send (set->client_mq, ev); 1670 GNUNET_MQ_send (set->cs->mq,
1541 1671 ev);
1542 1672 GNUNET_SERVICE_client_continue (cs->client);
1543 GNUNET_SERVER_receive_done (client,
1544 GNUNET_OK);
1545
1546 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1547 "Client requested lazy copy\n");
1548} 1673}
1549 1674
1550 1675
1551/** 1676/**
1552 * Handle a request from the client to 1677 * Handle a request from the client to connect to a copy of a set.
1553 * connect to a copy of a set.
1554 * 1678 *
1555 * @param cls unused 1679 * @param cls the client
1556 * @param client the client 1680 * @param msg the message
1557 * @param mh the message
1558 */ 1681 */
1559static void 1682static void
1560handle_client_copy_lazy_connect (void *cls, 1683handle_client_copy_lazy_connect (void *cls,
1561 struct GNUNET_SERVER_Client *client, 1684 const struct GNUNET_SET_CopyLazyConnectMessage *msg)
1562 const struct GNUNET_MessageHeader *mh)
1563{ 1685{
1686 struct ClientState *cs = cls;
1564 struct LazyCopyRequest *cr; 1687 struct LazyCopyRequest *cr;
1565 const struct GNUNET_SET_CopyLazyConnectMessage *msg =
1566 (const struct GNUNET_SET_CopyLazyConnectMessage *) mh;
1567 struct Set *set; 1688 struct Set *set;
1568 int found; 1689 int found;
1569 1690
1570 if (NULL != set_get (client)) 1691 if (NULL != cs->set)
1571 { 1692 {
1572 /* There can only be one set per client */ 1693 /* There can only be one set per client */
1573 GNUNET_break (0); 1694 GNUNET_break (0);
1574 GNUNET_SERVER_client_disconnect (client); 1695 GNUNET_SERVICE_client_drop (cs->client);
1575 return; 1696 return;
1576 } 1697 }
1577
1578 found = GNUNET_NO; 1698 found = GNUNET_NO;
1579
1580 for (cr = lazy_copy_head; NULL != cr; cr = cr->next) 1699 for (cr = lazy_copy_head; NULL != cr; cr = cr->next)
1581 { 1700 {
1582 if (cr->cookie == msg->cookie) 1701 if (cr->cookie == msg->cookie)
@@ -1585,21 +1704,20 @@ handle_client_copy_lazy_connect (void *cls,
1585 break; 1704 break;
1586 } 1705 }
1587 } 1706 }
1588
1589 if (GNUNET_NO == found) 1707 if (GNUNET_NO == found)
1590 { 1708 {
1591 /* client asked for copy with cookie we don't know */ 1709 /* client asked for copy with cookie we don't know */
1592 GNUNET_break (0); 1710 GNUNET_break (0);
1593 GNUNET_SERVER_client_disconnect (client); 1711 GNUNET_SERVICE_client_drop (cs->client);
1594 return; 1712 return;
1595 } 1713 }
1596
1597 GNUNET_CONTAINER_DLL_remove (lazy_copy_head, 1714 GNUNET_CONTAINER_DLL_remove (lazy_copy_head,
1598 lazy_copy_tail, 1715 lazy_copy_tail,
1599 cr); 1716 cr);
1600 1717 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1718 "Client %p requested use of lazy copy\n",
1719 cs);
1601 set = GNUNET_new (struct Set); 1720 set = GNUNET_new (struct Set);
1602
1603 switch (cr->source_set->operation) 1721 switch (cr->source_set->operation)
1604 { 1722 {
1605 case GNUNET_SET_OPERATION_INTERSECTION: 1723 case GNUNET_SET_OPERATION_INTERSECTION:
@@ -1619,75 +1737,57 @@ handle_client_copy_lazy_connect (void *cls,
1619 GNUNET_break (0); 1737 GNUNET_break (0);
1620 GNUNET_free (set); 1738 GNUNET_free (set);
1621 GNUNET_free (cr); 1739 GNUNET_free (cr);
1622 GNUNET_SERVER_client_disconnect (client); 1740 GNUNET_SERVICE_client_drop (cs->client);
1623 return; 1741 return;
1624 } 1742 }
1625 1743
1626 set->operation = cr->source_set->operation; 1744 set->operation = cr->source_set->operation;
1627 set->state = set->vt->copy_state (cr->source_set); 1745 set->state = set->vt->copy_state (cr->source_set->state);
1628 set->content = cr->source_set->content; 1746 set->content = cr->source_set->content;
1629 set->content->refcount += 1; 1747 set->content->refcount++;
1630 1748
1631 set->current_generation = cr->source_set->current_generation; 1749 set->current_generation = cr->source_set->current_generation;
1632 set->excluded_generations_size = cr->source_set->excluded_generations_size; 1750 set->excluded_generations_size = cr->source_set->excluded_generations_size;
1633 set->excluded_generations = GNUNET_memdup (cr->source_set->excluded_generations, 1751 set->excluded_generations
1634 set->excluded_generations_size * sizeof (struct GenerationRange)); 1752 = GNUNET_memdup (cr->source_set->excluded_generations,
1753 set->excluded_generations_size * sizeof (struct GenerationRange));
1635 1754
1636 /* 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
1637 of the cloned set and the source set are independent. */ 1756 of the cloned set and the source set are independent. */
1638 advance_generation (set); 1757 advance_generation (set);
1639 1758 set->cs = cs;
1640 1759 cs->set = set;
1641 set->client = client;
1642 set->client_mq = GNUNET_MQ_queue_for_server_client (client);
1643 GNUNET_CONTAINER_DLL_insert (sets_head,
1644 sets_tail,
1645 set);
1646
1647 GNUNET_free (cr); 1760 GNUNET_free (cr);
1648 1761 GNUNET_SERVICE_client_continue (cs->client);
1649 GNUNET_SERVER_receive_done (client,
1650 GNUNET_OK);
1651
1652 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1653 "Client connected to lazy set\n");
1654} 1762}
1655 1763
1656 1764
1657/** 1765/**
1658 * Handle a request from the client to 1766 * Handle a request from the client to cancel a running set operation.
1659 * cancel a running set operation.
1660 * 1767 *
1661 * @param cls unused 1768 * @param cls the client
1662 * @param client the client 1769 * @param msg the message
1663 * @param mh the message
1664 */ 1770 */
1665static void 1771static void
1666handle_client_cancel (void *cls, 1772handle_client_cancel (void *cls,
1667 struct GNUNET_SERVER_Client *client, 1773 const struct GNUNET_SET_CancelMessage *msg)
1668 const struct GNUNET_MessageHeader *mh)
1669{ 1774{
1670 const struct GNUNET_SET_CancelMessage *msg = 1775 struct ClientState *cs = cls;
1671 (const struct GNUNET_SET_CancelMessage *) mh;
1672 struct Set *set; 1776 struct Set *set;
1673 struct Operation *op; 1777 struct Operation *op;
1674 int found; 1778 int found;
1675 1779
1676 set = set_get (client); 1780 if (NULL == (set = cs->set))
1677 if (NULL == set)
1678 { 1781 {
1679 /* client without a set requested an operation */ 1782 /* client without a set requested an operation */
1680 GNUNET_break (0); 1783 GNUNET_break (0);
1681 GNUNET_SERVER_client_disconnect (client); 1784 GNUNET_SERVICE_client_drop (cs->client);
1682 return; 1785 return;
1683 } 1786 }
1684 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1685 "Client requested cancel for op %u\n",
1686 ntohl (msg->request_id));
1687 found = GNUNET_NO; 1787 found = GNUNET_NO;
1688 for (op = set->ops_head; NULL != op; op = op->next) 1788 for (op = set->ops_head; NULL != op; op = op->next)
1689 { 1789 {
1690 if (op->spec->client_request_id == ntohl (msg->request_id)) 1790 if (op->client_request_id == ntohl (msg->request_id))
1691 { 1791 {
1692 found = GNUNET_YES; 1792 found = GNUNET_YES;
1693 break; 1793 break;
@@ -1700,16 +1800,19 @@ handle_client_cancel (void *cls,
1700 * yet and try to cancel the (just barely non-existent) operation. 1800 * yet and try to cancel the (just barely non-existent) operation.
1701 * So this is not a hard error. 1801 * So this is not a hard error.
1702 */ 1802 */
1703 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1803 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1704 "Client canceled non-existent op\n"); 1804 "Client canceled non-existent op %u\n",
1805 (uint32_t) ntohl (msg->request_id));
1705 } 1806 }
1706 else 1807 else
1707 { 1808 {
1809 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1810 "Client requested cancel for op %u\n",
1811 (uint32_t) ntohl (msg->request_id));
1708 _GSS_operation_destroy (op, 1812 _GSS_operation_destroy (op,
1709 GNUNET_YES); 1813 GNUNET_YES);
1710 } 1814 }
1711 GNUNET_SERVER_receive_done (client, 1815 GNUNET_SERVICE_client_continue (cs->client);
1712 GNUNET_OK);
1713} 1816}
1714 1817
1715 1818
@@ -1718,28 +1821,25 @@ handle_client_cancel (void *cls,
1718 * came from a remote peer. We forward the accept to the associated 1821 * came from a remote peer. We forward the accept to the associated
1719 * operation for handling 1822 * operation for handling
1720 * 1823 *
1721 * @param cls unused 1824 * @param cls the client
1722 * @param client the client 1825 * @param msg the message
1723 * @param mh the message
1724 */ 1826 */
1725static void 1827static void
1726handle_client_accept (void *cls, 1828handle_client_accept (void *cls,
1727 struct GNUNET_SERVER_Client *client, 1829 const struct GNUNET_SET_AcceptMessage *msg)
1728 const struct GNUNET_MessageHeader *mh)
1729{ 1830{
1831 struct ClientState *cs = cls;
1730 struct Set *set; 1832 struct Set *set;
1731 const struct GNUNET_SET_AcceptMessage *msg;
1732 struct Operation *op; 1833 struct Operation *op;
1733 struct GNUNET_SET_ResultMessage *result_message; 1834 struct GNUNET_SET_ResultMessage *result_message;
1734 struct GNUNET_MQ_Envelope *ev; 1835 struct GNUNET_MQ_Envelope *ev;
1836 struct Listener *listener;
1735 1837
1736 msg = (const struct GNUNET_SET_AcceptMessage *) mh; 1838 if (NULL == (set = cs->set))
1737 set = set_get (client);
1738 if (NULL == set)
1739 { 1839 {
1740 /* client without a set requested to accept */ 1840 /* client without a set requested to accept */
1741 GNUNET_break (0); 1841 GNUNET_break (0);
1742 GNUNET_SERVER_client_disconnect (client); 1842 GNUNET_SERVICE_client_drop (cs->client);
1743 return; 1843 return;
1744 } 1844 }
1745 op = get_incoming (ntohl (msg->accept_reject_id)); 1845 op = get_incoming (ntohl (msg->accept_reject_id));
@@ -1747,270 +1847,170 @@ handle_client_accept (void *cls,
1747 { 1847 {
1748 /* 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
1749 * have been destroyed when the partner peer disconnected. */ 1849 * have been destroyed when the partner peer disconnected. */
1750 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1850 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1751 "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);
1752 ev = GNUNET_MQ_msg (result_message, 1855 ev = GNUNET_MQ_msg (result_message,
1753 GNUNET_MESSAGE_TYPE_SET_RESULT); 1856 GNUNET_MESSAGE_TYPE_SET_RESULT);
1754 result_message->request_id = msg->request_id; 1857 result_message->request_id = msg->request_id;
1755 result_message->element_type = 0;
1756 result_message->result_status = htons (GNUNET_SET_STATUS_FAILURE); 1858 result_message->result_status = htons (GNUNET_SET_STATUS_FAILURE);
1757 GNUNET_MQ_send (set->client_mq, ev); 1859 GNUNET_MQ_send (set->cs->mq,
1758 GNUNET_SERVER_receive_done (client, GNUNET_OK); 1860 ev);
1861 GNUNET_SERVICE_client_continue (cs->client);
1759 return; 1862 return;
1760 } 1863 }
1761
1762 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1864 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1763 "Client accepting request %u\n", 1865 "Client accepting request %u\n",
1764 ntohl (msg->accept_reject_id)); 1866 (uint32_t) ntohl (msg->accept_reject_id));
1765 GNUNET_assert (GNUNET_YES == op->is_incoming); 1867 listener = op->listener;
1766 op->is_incoming = GNUNET_NO; 1868 op->listener = NULL;
1767 GNUNET_CONTAINER_DLL_remove (incoming_head, 1869 GNUNET_CONTAINER_DLL_remove (listener->op_head,
1768 incoming_tail, 1870 listener->op_tail,
1769 op); 1871 op);
1770 op->spec->set = set; 1872 op->set = set;
1771 GNUNET_CONTAINER_DLL_insert (set->ops_head, 1873 GNUNET_CONTAINER_DLL_insert (set->ops_head,
1772 set->ops_tail, 1874 set->ops_tail,
1773 op); 1875 op);
1774 op->spec->client_request_id = ntohl (msg->request_id); 1876 op->client_request_id = ntohl (msg->request_id);
1775 op->spec->result_mode = ntohl (msg->result_mode); 1877 op->result_mode = ntohl (msg->result_mode);
1776 1878 op->byzantine = msg->byzantine;
1777 // Advance generation values, so that 1879 op->byzantine_lower_bound = msg->byzantine_lower_bound;
1778 // mutations won't interfer with the running operation. 1880 op->force_full = msg->force_full;
1881 op->force_delta = msg->force_delta;
1882
1883 /* Advance generation values, so that future mutations do not
1884 interfer with the running operation. */
1779 op->generation_created = set->current_generation; 1885 op->generation_created = set->current_generation;
1780 advance_generation (set); 1886 advance_generation (set);
1781 1887 GNUNET_assert (NULL == op->state);
1782 op->vt = set->vt; 1888 op->state = set->vt->accept (op);
1783 op->vt->accept (op); 1889 if (NULL == op->state)
1784 GNUNET_SERVER_receive_done (client, 1890 {
1785 GNUNET_OK); 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);
1786} 1900}
1787 1901
1788 1902
1789/** 1903/**
1790 * Called to clean up, after a shutdown has been requested. 1904 * Called to clean up, after a shutdown has been requested.
1791 * 1905 *
1792 * @param cls closure 1906 * @param cls closure, NULL
1793 */ 1907 */
1794static void 1908static void
1795shutdown_task (void *cls) 1909shutdown_task (void *cls)
1796{ 1910{
1797 while (NULL != incoming_head) 1911 /* Delay actual shutdown to allow service to disconnect clients */
1798 incoming_destroy (incoming_head);
1799 while (NULL != listeners_head)
1800 listener_destroy (listeners_head);
1801 while (NULL != sets_head)
1802 set_destroy (sets_head);
1803
1804 /* it's important to destroy cadet at the end, as all channels
1805 * must be destroyed before the cadet handle! */
1806 if (NULL != cadet) 1912 if (NULL != cadet)
1807 { 1913 {
1808 GNUNET_CADET_disconnect (cadet); 1914 GNUNET_CADET_disconnect (cadet);
1809 cadet = NULL; 1915 cadet = NULL;
1810 } 1916 }
1811 GNUNET_STATISTICS_destroy (_GSS_statistics, GNUNET_YES); 1917 GNUNET_STATISTICS_destroy (_GSS_statistics,
1918 GNUNET_YES);
1812 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1919 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1813 "handled shutdown request\n"); 1920 "handled shutdown request\n");
1814} 1921}
1815 1922
1816 1923
1817/** 1924/**
1818 * Function called whenever a channel is destroyed. Should clean up
1819 * any associated state. It must NOT call
1820 * GNUNET_CADET_channel_destroy() on the channel.
1821 *
1822 * The peer_disconnect function is part of a a virtual table set initially either
1823 * when a peer creates a new channel with us, or once we create
1824 * a new channel ourselves (evaluate).
1825 *
1826 * Once we know the exact type of operation (union/intersection), the vt is
1827 * replaced with an operation specific instance (_GSS_[op]_vt).
1828 *
1829 * @param cls closure (set from GNUNET_CADET_connect())
1830 * @param channel connection to the other end (henceforth invalid)
1831 * @param channel_ctx place where local state associated
1832 * with the channel is stored
1833 */
1834static void
1835channel_end_cb (void *cls,
1836 const struct GNUNET_CADET_Channel *channel,
1837 void *channel_ctx)
1838{
1839 struct Operation *op = channel_ctx;
1840
1841 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1842 "channel_end_cb called\n");
1843 op->channel = NULL;
1844 op->keep++;
1845 /* the vt can be null if a client already requested canceling op. */
1846 if (NULL != op->vt)
1847 {
1848 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1849 "calling peer disconnect due to channel end\n");
1850 op->vt->peer_disconnect (op);
1851 }
1852 op->keep--;
1853 if (0 == op->keep)
1854 {
1855 /* cadet will never call us with the context again! */
1856 GNUNET_free (op);
1857 }
1858 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1859 "channel_end_cb finished\n");
1860}
1861
1862
1863/**
1864 * Functions with this signature are called whenever a message is
1865 * received via a cadet channel.
1866 *
1867 * The msg_handler is a virtual table set in initially either when a peer
1868 * creates a new channel with us, or once we create a new channel
1869 * ourselves (evaluate).
1870 *
1871 * Once we know the exact type of operation (union/intersection), the vt is
1872 * replaced with an operation specific instance (_GSS_[op]_vt).
1873 *
1874 * @param cls Closure (set from GNUNET_CADET_connect()).
1875 * @param channel Connection to the other end.
1876 * @param channel_ctx Place to store local state associated with the channel.
1877 * @param message The actual message.
1878 * @return #GNUNET_OK to keep the channel open,
1879 * #GNUNET_SYSERR to close it (signal serious error).
1880 */
1881static int
1882dispatch_p2p_message (void *cls,
1883 struct GNUNET_CADET_Channel *channel,
1884 void **channel_ctx,
1885 const struct GNUNET_MessageHeader *message)
1886{
1887 struct Operation *op = *channel_ctx;
1888 int ret;
1889
1890 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1891 "Dispatching cadet message (type: %u)\n",
1892 ntohs (message->type));
1893 /* do this before the handler, as the handler might kill the channel */
1894 GNUNET_CADET_receive_done (channel);
1895 if (NULL != op->vt)
1896 ret = op->vt->msg_handler (op,
1897 message);
1898 else
1899 ret = GNUNET_SYSERR;
1900 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1901 "Handled cadet message (type: %u)\n",
1902 ntohs (message->type));
1903 return ret;
1904}
1905
1906
1907/**
1908 * Function called by the service's run 1925 * Function called by the service's run
1909 * method to run service-specific setup code. 1926 * method to run service-specific setup code.
1910 * 1927 *
1911 * @param cls closure 1928 * @param cls closure
1912 * @param server the initialized server
1913 * @param cfg configuration to use 1929 * @param cfg configuration to use
1930 * @param service the initialized service
1914 */ 1931 */
1915static void 1932static void
1916run (void *cls, 1933run (void *cls,
1917 struct GNUNET_SERVER_Handle *server, 1934 const struct GNUNET_CONFIGURATION_Handle *cfg,
1918 const struct GNUNET_CONFIGURATION_Handle *cfg) 1935 struct GNUNET_SERVICE_Handle *service)
1919{ 1936{
1920 static const struct GNUNET_SERVER_MessageHandler server_handlers[] = { 1937 /* FIXME: need to modify SERVICE (!) API to allow
1921 { &handle_client_accept, NULL, 1938 us to run a shutdown task *after* clients were
1922 GNUNET_MESSAGE_TYPE_SET_ACCEPT, 1939 forcefully disconnected! */
1923 sizeof (struct GNUNET_SET_AcceptMessage)}, 1940 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1924 { &handle_client_iter_ack, NULL, 1941 NULL);
1925 GNUNET_MESSAGE_TYPE_SET_ITER_ACK, 1942 _GSS_statistics = GNUNET_STATISTICS_create ("set",
1926 sizeof (struct GNUNET_SET_IterAckMessage) }, 1943 cfg);
1927 { &handle_client_mutation, NULL, 1944 cadet = GNUNET_CADET_connect (cfg);
1928 GNUNET_MESSAGE_TYPE_SET_ADD,
1929 0},
1930 { &handle_client_create_set, NULL,
1931 GNUNET_MESSAGE_TYPE_SET_CREATE,
1932 sizeof (struct GNUNET_SET_CreateMessage)},
1933 { &handle_client_iterate, NULL,
1934 GNUNET_MESSAGE_TYPE_SET_ITER_REQUEST,
1935 sizeof (struct GNUNET_MessageHeader)},
1936 { &handle_client_evaluate, NULL,
1937 GNUNET_MESSAGE_TYPE_SET_EVALUATE,
1938 0},
1939 { &handle_client_listen, NULL,
1940 GNUNET_MESSAGE_TYPE_SET_LISTEN,
1941 sizeof (struct GNUNET_SET_ListenMessage)},
1942 { &handle_client_reject, NULL,
1943 GNUNET_MESSAGE_TYPE_SET_REJECT,
1944 sizeof (struct GNUNET_SET_RejectMessage)},
1945 { &handle_client_mutation, NULL,
1946 GNUNET_MESSAGE_TYPE_SET_REMOVE,
1947 0},
1948 { &handle_client_cancel, NULL,
1949 GNUNET_MESSAGE_TYPE_SET_CANCEL,
1950 sizeof (struct GNUNET_SET_CancelMessage)},
1951 { &handle_client_copy_lazy_prepare, NULL,
1952 GNUNET_MESSAGE_TYPE_SET_COPY_LAZY_PREPARE,
1953 sizeof (struct GNUNET_MessageHeader)},
1954 { &handle_client_copy_lazy_connect, NULL,
1955 GNUNET_MESSAGE_TYPE_SET_COPY_LAZY_CONNECT,
1956 sizeof (struct GNUNET_SET_CopyLazyConnectMessage)},
1957 { NULL, NULL, 0, 0}
1958 };
1959 static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
1960 { &dispatch_p2p_message, GNUNET_MESSAGE_TYPE_SET_P2P_OPERATION_REQUEST, 0},
1961 { &dispatch_p2p_message, GNUNET_MESSAGE_TYPE_SET_UNION_P2P_IBF, 0},
1962 { &dispatch_p2p_message, GNUNET_MESSAGE_TYPE_SET_P2P_ELEMENTS, 0},
1963 { &dispatch_p2p_message, GNUNET_MESSAGE_TYPE_SET_UNION_P2P_OFFER, 0},
1964 { &dispatch_p2p_message, GNUNET_MESSAGE_TYPE_SET_UNION_P2P_INQUIRY, 0},
1965 { &dispatch_p2p_message, GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DEMAND, 0},
1966 { &dispatch_p2p_message, GNUNET_MESSAGE_TYPE_SET_P2P_ELEMENT_REQUESTS, 0},
1967 { &dispatch_p2p_message, GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DONE, 0},
1968 { &dispatch_p2p_message, GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SE, 0},
1969 { &dispatch_p2p_message, GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SEC, 0},
1970 { &dispatch_p2p_message, GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_ELEMENT_INFO, 0},
1971 { &dispatch_p2p_message, GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_BF, 0},
1972 { &dispatch_p2p_message, GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_DONE, 0},
1973 {NULL, 0, 0}
1974 };
1975
1976 configuration = cfg;
1977 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
1978 GNUNET_SERVER_disconnect_notify (server,
1979 &handle_client_disconnect,
1980 NULL);
1981 GNUNET_SERVER_add_handlers (server,
1982 server_handlers);
1983 _GSS_statistics = GNUNET_STATISTICS_create ("set", cfg);
1984 cadet = GNUNET_CADET_connect (cfg,
1985 NULL,
1986 &channel_end_cb,
1987 cadet_handlers);
1988 if (NULL == cadet) 1945 if (NULL == cadet)
1989 { 1946 {
1990 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1947 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1991 _("Could not connect to cadet service\n")); 1948 _("Could not connect to CADET service\n"));
1949 GNUNET_SCHEDULER_shutdown ();
1992 return; 1950 return;
1993 } 1951 }
1994} 1952}
1995 1953
1996 1954
1997/** 1955/**
1998 * The main function for the set service. 1956 * Define "main" method using service macro.
1999 *
2000 * @param argc number of arguments from the command line
2001 * @param argv command line arguments
2002 * @return 0 ok, 1 on error
2003 */ 1957 */
2004int 1958GNUNET_SERVICE_MAIN
2005main (int argc, 1959("set",
2006 char *const *argv) 1960 GNUNET_SERVICE_OPTION_NONE,
2007{ 1961 &run,
2008 int ret; 1962 &client_connect_cb,
1963 &client_disconnect_cb,
1964 NULL,
1965 GNUNET_MQ_hd_fixed_size (client_accept,
1966 GNUNET_MESSAGE_TYPE_SET_ACCEPT,
1967 struct GNUNET_SET_AcceptMessage,
1968 NULL),
1969 GNUNET_MQ_hd_fixed_size (client_iter_ack,
1970 GNUNET_MESSAGE_TYPE_SET_ITER_ACK,
1971 struct GNUNET_SET_IterAckMessage,
1972 NULL),
1973 GNUNET_MQ_hd_var_size (client_mutation,
1974 GNUNET_MESSAGE_TYPE_SET_ADD,
1975 struct GNUNET_SET_ElementMessage,
1976 NULL),
1977 GNUNET_MQ_hd_fixed_size (client_create_set,
1978 GNUNET_MESSAGE_TYPE_SET_CREATE,
1979 struct GNUNET_SET_CreateMessage,
1980 NULL),
1981 GNUNET_MQ_hd_fixed_size (client_iterate,
1982 GNUNET_MESSAGE_TYPE_SET_ITER_REQUEST,
1983 struct GNUNET_MessageHeader,
1984 NULL),
1985 GNUNET_MQ_hd_var_size (client_evaluate,
1986 GNUNET_MESSAGE_TYPE_SET_EVALUATE,
1987 struct GNUNET_SET_EvaluateMessage,
1988 NULL),
1989 GNUNET_MQ_hd_fixed_size (client_listen,
1990 GNUNET_MESSAGE_TYPE_SET_LISTEN,
1991 struct GNUNET_SET_ListenMessage,
1992 NULL),
1993 GNUNET_MQ_hd_fixed_size (client_reject,
1994 GNUNET_MESSAGE_TYPE_SET_REJECT,
1995 struct GNUNET_SET_RejectMessage,
1996 NULL),
1997 GNUNET_MQ_hd_var_size (client_mutation,
1998 GNUNET_MESSAGE_TYPE_SET_REMOVE,
1999 struct GNUNET_SET_ElementMessage,
2000 NULL),
2001 GNUNET_MQ_hd_fixed_size (client_cancel,
2002 GNUNET_MESSAGE_TYPE_SET_CANCEL,
2003 struct GNUNET_SET_CancelMessage,
2004 NULL),
2005 GNUNET_MQ_hd_fixed_size (client_copy_lazy_prepare,
2006 GNUNET_MESSAGE_TYPE_SET_COPY_LAZY_PREPARE,
2007 struct GNUNET_MessageHeader,
2008 NULL),
2009 GNUNET_MQ_hd_fixed_size (client_copy_lazy_connect,
2010 GNUNET_MESSAGE_TYPE_SET_COPY_LAZY_CONNECT,
2011 struct GNUNET_SET_CopyLazyConnectMessage,
2012 NULL),
2013 GNUNET_MQ_handler_end ());
2009 2014
2010 ret = GNUNET_SERVICE_run (argc, argv, "set",
2011 GNUNET_SERVICE_OPTION_NONE,
2012 &run, NULL);
2013 return (GNUNET_OK == ret) ? 0 : 1;
2014}
2015 2015
2016/* end of gnunet-service-set.c */ 2016/* end of gnunet-service-set.c */
diff --git a/src/set/gnunet-service-set.h b/src/set/gnunet-service-set.h
index 9e1ffd01a..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,68 +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
125/**
126 * Signature of functions that create the implementation-specific 71 * Signature of functions that create the implementation-specific
127 * state for a set supporting a specific operation. 72 * state for a set supporting a specific operation.
128 * 73 *
129 * @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
130 */ 75 */
131typedef struct SetState * 76typedef struct SetState *
132(*CreateImpl) (void); 77(*SetCreateImpl) (void);
133 78
134 79
135/** 80/**
@@ -140,18 +85,18 @@ typedef struct SetState *
140 * @param ee element message from the client 85 * @param ee element message from the client
141 */ 86 */
142typedef void 87typedef void
143(*AddRemoveImpl) (struct SetState *state, 88(*SetAddRemoveImpl) (struct SetState *state,
144 struct ElementEntry *ee); 89 struct ElementEntry *ee);
145 90
146 91
147/** 92/**
148 * Signature of functions that handle disconnection of the remote 93 * Make a copy of a set's internal state.
149 * peer.
150 * 94 *
151 * @param op the set operation, contains implementation-specific data 95 * @param state set state to copy
96 * @return copy of the internal state
152 */ 97 */
153typedef void 98typedef struct SetState *
154(*PeerDisconnectImpl) (struct Operation *op); 99(*SetCopyStateImpl) (struct SetState *state);
155 100
156 101
157/** 102/**
@@ -161,7 +106,7 @@ typedef void
161 * @param state the set state, contains implementation-specific data 106 * @param state the set state, contains implementation-specific data
162 */ 107 */
163typedef void 108typedef void
164(*DestroySetImpl) (struct SetState *state); 109(*SetDestroyImpl) (struct SetState *state);
165 110
166 111
167/** 112/**
@@ -169,8 +114,9 @@ typedef void
169 * 114 *
170 * @param op operation that is created by accepting the operation, 115 * @param op operation that is created by accepting the operation,
171 * should be initialized by the implementation 116 * should be initialized by the implementation
117 * @return operation-specific state to keep in @a op
172 */ 118 */
173typedef void 119typedef struct OperationState *
174(*OpAcceptImpl) (struct Operation *op); 120(*OpAcceptImpl) (struct Operation *op);
175 121
176 122
@@ -182,38 +128,32 @@ typedef void
182 * begin the evaluation 128 * begin the evaluation
183 * @param opaque_context message to be transmitted to the listener 129 * @param opaque_context message to be transmitted to the listener
184 * 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
185 */ 132 */
186typedef void 133typedef struct OperationState *
187(*OpEvaluateImpl) (struct Operation *op, 134(*OpEvaluateImpl) (struct Operation *op,
188 const struct GNUNET_MessageHeader *opaque_context); 135 const struct GNUNET_MessageHeader *opaque_context);
189 136
190
191/** 137/**
192 * Signature of functions that implement the message handling for 138 * Signature of functions that implement operation cancelation.
193 * the different set operations. 139 * This includes notifying the client about the operation's final
140 * state.
194 * 141 *
195 * @param op operation state 142 * @param op operation state
196 * @param msg received message
197 * @return #GNUNET_OK on success, #GNUNET_SYSERR to
198 * destroy the operation and the tunnel
199 */ 143 */
200typedef int 144typedef void
201(*MsgHandlerImpl) (struct Operation *op, 145(*OpCancelImpl) (struct Operation *op);
202 const struct GNUNET_MessageHeader *msg);
203 146
204 147
205/** 148/**
206 * Signature of functions that implement operation cancellation 149 * Signature of functions called when the CADET channel died.
207 * 150 *
208 * @param op operation state 151 * @param op operation state
209 */ 152 */
210typedef void 153typedef void
211(*CancelImpl) (struct Operation *op); 154(*OpChannelDeathImpl) (struct Operation *op);
212 155
213 156
214typedef struct SetState *
215(*CopyStateImpl) (struct Set *op);
216
217 157
218/** 158/**
219 * Dispatch table for a specific set operation. Every set operation 159 * Dispatch table for a specific set operation. Every set operation
@@ -224,49 +164,48 @@ struct SetVT
224 /** 164 /**
225 * Callback for the set creation. 165 * Callback for the set creation.
226 */ 166 */
227 CreateImpl create; 167 SetCreateImpl create;
228 168
229 /** 169 /**
230 * Callback for element insertion 170 * Callback for element insertion
231 */ 171 */
232 AddRemoveImpl add; 172 SetAddRemoveImpl add;
233 173
234 /** 174 /**
235 * Callback for element removal. 175 * Callback for element removal.
236 */ 176 */
237 AddRemoveImpl remove; 177 SetAddRemoveImpl remove;
238 178
239 /** 179 /**
240 * Callback for accepting a set operation request 180 * Callback for making a copy of a set's internal state.
241 */ 181 */
242 OpAcceptImpl accept; 182 SetCopyStateImpl copy_state;
243 183
244 /** 184 /**
245 * Callback for starting evaluation with a remote peer. 185 * Callback for destruction of the set state.
246 */ 186 */
247 OpEvaluateImpl evaluate; 187 SetDestroyImpl destroy_set;
248 188
249 /** 189 /**
250 * Callback for destruction of the set state. 190 * Callback for accepting a set operation request
251 */ 191 */
252 DestroySetImpl destroy_set; 192 OpAcceptImpl accept;
253 193
254 /** 194 /**
255 * Callback for handling operation-specific messages. 195 * Callback for starting evaluation with a remote peer.
256 */ 196 */
257 MsgHandlerImpl msg_handler; 197 OpEvaluateImpl evaluate;
258 198
259 /** 199 /**
260 * Callback for handling the remote peer's disconnect. 200 * Callback for canceling an operation.
261 */ 201 */
262 PeerDisconnectImpl peer_disconnect; 202 OpCancelImpl cancel;
263 203
264 /** 204 /**
265 * Callback for canceling an operation by its ID. 205 * Callback called in case the CADET channel died.
266 */ 206 */
267 CancelImpl cancel; 207 OpChannelDeathImpl channel_death;
268 208
269 CopyStateImpl copy_state;
270}; 209};
271 210
272 211
@@ -336,20 +275,56 @@ struct ElementEntry
336}; 275};
337 276
338 277
278/**
279 * A listener is inhabited by a client, and waits for evaluation
280 * requests from remote peers.
281 */
339struct Listener; 282struct Listener;
340 283
341 284
342/** 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/**
343 * Operation context used to execute a set operation. 314 * Operation context used to execute a set operation.
344 */ 315 */
345struct Operation 316struct Operation
346{ 317{
318
347 /** 319 /**
348 * V-Table for the operation belonging to the tunnel contest. 320 * Kept in a DLL of the listener, if @e listener is non-NULL.
349 *
350 * Used for all operation specific operations after receiving the ops request
351 */ 321 */
352 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;
353 328
354 /** 329 /**
355 * Channel to the peer. 330 * Channel to the peer.
@@ -367,11 +342,15 @@ struct Operation
367 struct GNUNET_MQ_Handle *mq; 342 struct GNUNET_MQ_Handle *mq;
368 343
369 /** 344 /**
370 * Detail information about the set operation, including the set to 345 * Context message, may be NULL.
371 * use. When 'spec' is NULL, the operation is not yet entirely 346 */
372 * 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.
373 */ 352 */
374 struct OperationSpecification *spec; 353 struct Set *set;
375 354
376 /** 355 /**
377 * Operation-specific operation state. Note that the exact 356 * Operation-specific operation state. Note that the exact
@@ -381,16 +360,6 @@ struct Operation
381 struct OperationState *state; 360 struct OperationState *state;
382 361
383 /** 362 /**
384 * Evaluate operations are held in a linked list.
385 */
386 struct Operation *next;
387
388 /**
389 * Evaluate operations are held in a linked list.
390 */
391 struct Operation *prev;
392
393 /**
394 * The identity of the requesting peer. Needs to 363 * The identity of the requesting peer. Needs to
395 * 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.
396 */ 365 */
@@ -403,6 +372,50 @@ struct Operation
403 struct GNUNET_SCHEDULER_Task *timeout_task; 372 struct GNUNET_SCHEDULER_Task *timeout_task;
404 373
405 /** 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 /**
406 * 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
407 * 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
408 * the request has not been suggested yet. 421 * the request has not been suggested yet.
@@ -410,45 +423,26 @@ struct Operation
410 uint32_t suggest_id; 423 uint32_t suggest_id;
411 424
412 /** 425 /**
413 * #GNUNET_YES if this is not a "real" set operation yet, and we still
414 * need to wait for the other peer to give us more details.
415 */
416 int is_incoming;
417
418 /**
419 * Generation in which the operation handle 426 * Generation in which the operation handle
420 * was created. 427 * was created.
421 */ 428 */
422 unsigned int generation_created; 429 unsigned int generation_created;
423 430
424 /**
425 * Incremented whenever (during shutdown) some component still
426 * needs to do something with this before the operation is freed.
427 * (Used as a reference counter, but only during termination.)
428 */
429 unsigned int keep;
430}; 431};
431 432
432 433
433/** 434/**
434 * SetContent stores the actual set elements, 435 * SetContent stores the actual set elements, which may be shared by
435 * which may be shared by multiple generations derived 436 * multiple generations derived from one set.
436 * from one set.
437 */ 437 */
438struct SetContent 438struct SetContent
439{ 439{
440 /**
441 * Number of references to the content.
442 */
443 unsigned int refcount;
444 440
445 /** 441 /**
446 * Maps `struct GNUNET_HashCode *` to `struct ElementEntry *`. 442 * Maps `struct GNUNET_HashCode *` to `struct ElementEntry *`.
447 */ 443 */
448 struct GNUNET_CONTAINER_MultiHashMap *elements; 444 struct GNUNET_CONTAINER_MultiHashMap *elements;
449 445
450 unsigned int latest_generation;
451
452 /** 446 /**
453 * Mutations requested by the client that we're 447 * Mutations requested by the client that we're
454 * unable to execute right now because we're iterating 448 * unable to execute right now because we're iterating
@@ -464,6 +458,16 @@ struct SetContent
464 struct PendingMutation *pending_mutations_tail; 458 struct PendingMutation *pending_mutations_tail;
465 459
466 /** 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 /**
467 * Number of concurrently active iterators. 471 * Number of concurrently active iterators.
468 */ 472 */
469 int iterator_count; 473 int iterator_count;
@@ -484,19 +488,32 @@ struct GenerationRange
484}; 488};
485 489
486 490
491/**
492 * Information about a mutation to apply to a set.
493 */
487struct PendingMutation 494struct PendingMutation
488{ 495{
496 /**
497 * Mutations are kept in a DLL.
498 */
489 struct PendingMutation *prev; 499 struct PendingMutation *prev;
500
501 /**
502 * Mutations are kept in a DLL.
503 */
490 struct PendingMutation *next; 504 struct PendingMutation *next;
491 505
506 /**
507 * Set this mutation is about.
508 */
492 struct Set *set; 509 struct Set *set;
493 510
494 /** 511 /**
495 * Message that describes the desired mutation. 512 * Message that describes the desired mutation.
496 * May only be a GNUNET_MESSAGE_TYPE_SET_ADD or 513 * May only be a #GNUNET_MESSAGE_TYPE_SET_ADD or
497 * GNUNET_MESSAGE_TYPE_SET_REMOVE. 514 * #GNUNET_MESSAGE_TYPE_SET_REMOVE.
498 */ 515 */
499 struct GNUNET_MessageHeader *mutation_message; 516 struct GNUNET_SET_ElementMessage *msg;
500}; 517};
501 518
502 519
@@ -520,12 +537,13 @@ struct Set
520 * 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,
521 * and there can only be one set per client. 538 * and there can only be one set per client.
522 */ 539 */
523 struct GNUNET_SERVER_Client *client; 540 struct ClientState *cs;
524 541
525 /** 542 /**
526 * Message queue for the client. 543 * Content, possibly shared by multiple sets,
544 * and thus reference counted.
527 */ 545 */
528 struct GNUNET_MQ_Handle *client_mq; 546 struct SetContent *content;
529 547
530 /** 548 /**
531 * Virtual table for this set. Determined by the operation type of 549 * Virtual table for this set. Determined by the operation type of
@@ -558,15 +576,15 @@ struct Set
558 struct Operation *ops_tail; 576 struct Operation *ops_tail;
559 577
560 /** 578 /**
561 * Current generation, that is, number of previously executed 579 * List of generations we have to exclude, due to lazy copies.
562 * operations and lazy copies on the underlying set content.
563 */ 580 */
564 unsigned int current_generation; 581 struct GenerationRange *excluded_generations;
565 582
566 /** 583 /**
567 * 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.
568 */ 586 */
569 struct GenerationRange *excluded_generations; 587 unsigned int current_generation;
570 588
571 /** 589 /**
572 * Number of elements in array @a excluded_generations. 590 * Number of elements in array @a excluded_generations.
@@ -579,21 +597,16 @@ struct Set
579 enum GNUNET_SET_OperationType operation; 597 enum GNUNET_SET_OperationType operation;
580 598
581 /** 599 /**
582 * Each @e iter is assigned a unique number, so that the client
583 * can distinguish iterations.
584 */
585 uint16_t iteration_id;
586
587 /**
588 * Generation we're currently iteration over. 600 * Generation we're currently iteration over.
589 */ 601 */
590 unsigned int iter_generation; 602 unsigned int iter_generation;
591 603
592 /** 604 /**
593 * Content, possibly shared by multiple sets, 605 * Each @e iter is assigned a unique number, so that the client
594 * and thus reference counted. 606 * can distinguish iterations.
595 */ 607 */
596 struct SetContent *content; 608 uint16_t iteration_id;
609
597}; 610};
598 611
599 612
@@ -601,10 +614,14 @@ extern struct GNUNET_STATISTICS_Handle *_GSS_statistics;
601 614
602 615
603/** 616/**
604 * Destroy the given operation. Call the implementation-specific 617 * Destroy the given operation. Used for any operation where both
605 * cancel function of the operation. Disconnects from the remote 618 * peers were known and that thus actually had a vt and channel. Must
606 * 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
607 * 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.
608 * 625 *
609 * @param op operation to destroy 626 * @param op operation to destroy
610 * @param gc #GNUNET_YES to perform garbage collection on the set 627 * @param gc #GNUNET_YES to perform garbage collection on the set
@@ -632,10 +649,13 @@ const struct SetVT *
632_GSS_intersection_vt (void); 649_GSS_intersection_vt (void);
633 650
634 651
635int 652/**
636_GSS_is_element_of_set (struct ElementEntry *ee, 653 * Is element @a ee part of the set used by @a op?
637 struct Set *set); 654 *
638 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 */
639int 659int
640_GSS_is_element_of_operation (struct ElementEntry *ee, 660_GSS_is_element_of_operation (struct ElementEntry *ee,
641 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 258ad6443..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_SERVER_client_disconnect (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_protocol.h b/src/set/gnunet-service-set_protocol.h
index 748da15fc..0138b21c7 100644
--- a/src/set/gnunet-service-set_protocol.h
+++ b/src/set/gnunet-service-set_protocol.h
@@ -208,6 +208,20 @@ struct IntersectionDoneMessage
208 struct GNUNET_HashCode element_xor_hash; 208 struct GNUNET_HashCode element_xor_hash;
209}; 209};
210 210
211
212/**
213 * Strata estimator together with the peer's overall set size.
214 */
215struct StrataEstimatorMessage
216{
217 /**
218 * Type: #GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SE(C)
219 */
220 struct GNUNET_MessageHeader header;
221
222 uint64_t set_size;
223};
224
211GNUNET_NETWORK_STRUCT_END 225GNUNET_NETWORK_STRUCT_END
212 226
213#endif 227#endif
diff --git a/src/set/gnunet-service-set_union.c b/src/set/gnunet-service-set_union.c
index e22465fd3..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>
@@ -85,6 +86,7 @@ enum UnionOperationPhase
85 * upon initialization and later via #PHASE_EXPECT_ELEMENTS_AND_REQUESTS. 86 * upon initialization and later via #PHASE_EXPECT_ELEMENTS_AND_REQUESTS.
86 * 87 *
87 * XXX: could use better wording. 88 * XXX: could use better wording.
89 * XXX: repurposed to also expect a "request full set" message, should be renamed
88 * 90 *
89 * After receiving the complete IBF, we enter #PHASE_EXPECT_ELEMENTS 91 * After receiving the complete IBF, we enter #PHASE_EXPECT_ELEMENTS
90 */ 92 */
@@ -115,14 +117,22 @@ enum UnionOperationPhase
115 * In the penultimate phase, 117 * In the penultimate phase,
116 * we wait until all our demands 118 * we wait until all our demands
117 * are satisfied. Then we send a done 119 * are satisfied. Then we send a done
118 * message, and wait for another done message.*/ 120 * message, and wait for another done message.
121 */
119 PHASE_FINISH_WAITING, 122 PHASE_FINISH_WAITING,
120 123
121 /** 124 /**
122 * In the ultimate phase, we wait until 125 * In the ultimate phase, we wait until
123 * our demands are satisfied and then 126 * our demands are satisfied and then
124 * quit (sending another DONE message). */ 127 * quit (sending another DONE message).
125 PHASE_DONE 128 */
129 PHASE_DONE,
130
131 /**
132 * After sending the full set, wait for responses with the elements
133 * that the local peer is missing.
134 */
135 PHASE_FULL_SENDING,
126}; 136};
127 137
128 138
@@ -148,7 +158,7 @@ struct OperationState
148 struct InvertibleBloomFilter *local_ibf; 158 struct InvertibleBloomFilter *local_ibf;
149 159
150 /** 160 /**
151 * Maps IBF-Keys (specific to the current salt) to elements. 161 * Maps unsalted IBF-Keys to elements.
152 * Used as a multihashmap, the keys being the lower 32bit of the IBF-Key. 162 * Used as a multihashmap, the keys being the lower 32bit of the IBF-Key.
153 * Colliding IBF-Keys are linked. 163 * Colliding IBF-Keys are linked.
154 */ 164 */
@@ -183,6 +193,23 @@ struct OperationState
183 * Salt for the IBF we've received and that we're currently decoding. 193 * Salt for the IBF we've received and that we're currently decoding.
184 */ 194 */
185 uint32_t salt_receive; 195 uint32_t salt_receive;
196
197 /**
198 * Number of elements we received from the other peer
199 * that were not in the local set yet.
200 */
201 uint32_t received_fresh;
202
203 /**
204 * Total number of elements received from the other peer.
205 */
206 uint32_t received_total;
207
208 /**
209 * Initial size of our set, just before
210 * the operation started.
211 */
212 uint64_t initial_size;
186}; 213};
187 214
188 215
@@ -203,6 +230,14 @@ struct KeyEntry
203 * is #GNUNET_YES. 230 * is #GNUNET_YES.
204 */ 231 */
205 struct ElementEntry *element; 232 struct ElementEntry *element;
233
234 /**
235 * Did we receive this element?
236 * Even if element->is_foreign is false, we might
237 * have received the element, so this indicates that
238 * the other peer has it.
239 */
240 int received;
206}; 241};
207 242
208 243
@@ -333,9 +368,10 @@ fail_union_operation (struct Operation *op)
333 "union operation failed\n"); 368 "union operation failed\n");
334 ev = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SET_RESULT); 369 ev = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SET_RESULT);
335 msg->result_status = htons (GNUNET_SET_STATUS_FAILURE); 370 msg->result_status = htons (GNUNET_SET_STATUS_FAILURE);
336 msg->request_id = htonl (op->spec->client_request_id); 371 msg->request_id = htonl (op->client_request_id);
337 msg->element_type = htons (0); 372 msg->element_type = htons (0);
338 GNUNET_MQ_send (op->spec->set->client_mq, ev); 373 GNUNET_MQ_send (op->set->cs->mq,
374 ev);
339 _GSS_operation_destroy (op, GNUNET_YES); 375 _GSS_operation_destroy (op, GNUNET_YES);
340} 376}
341 377
@@ -362,6 +398,23 @@ get_ibf_key (const struct GNUNET_HashCode *src)
362 398
363 399
364/** 400/**
401 * Context for #op_get_element_iterator
402 */
403struct GetElementContext
404{
405 /**
406 * FIXME.
407 */
408 struct GNUNET_HashCode hash;
409
410 /**
411 * FIXME.
412 */
413 struct KeyEntry *k;
414};
415
416
417/**
365 * Iterator over the mapping from IBF keys to element entries. Checks if we 418 * Iterator over the mapping from IBF keys to element entries. Checks if we
366 * have an element with a given GNUNET_HashCode. 419 * have an element with a given GNUNET_HashCode.
367 * 420 *
@@ -372,17 +425,20 @@ get_ibf_key (const struct GNUNET_HashCode *src)
372 * #GNUNET_NO if we've found the element. 425 * #GNUNET_NO if we've found the element.
373 */ 426 */
374static int 427static int
375op_has_element_iterator (void *cls, 428op_get_element_iterator (void *cls,
376 uint32_t key, 429 uint32_t key,
377 void *value) 430 void *value)
378{ 431{
379 struct GNUNET_HashCode *element_hash = cls; 432 struct GetElementContext *ctx = cls;
380 struct KeyEntry *k = value; 433 struct KeyEntry *k = value;
381 434
382 GNUNET_assert (NULL != k); 435 GNUNET_assert (NULL != k);
383 if (0 == GNUNET_CRYPTO_hash_cmp (&k->element->element_hash, 436 if (0 == GNUNET_CRYPTO_hash_cmp (&k->element->element_hash,
384 element_hash)) 437 &ctx->hash))
438 {
439 ctx->k = k;
385 return GNUNET_NO; 440 return GNUNET_NO;
441 }
386 return GNUNET_YES; 442 return GNUNET_YES;
387} 443}
388 444
@@ -395,23 +451,29 @@ op_has_element_iterator (void *cls,
395 * @param element_hash hash of the element to look for 451 * @param element_hash hash of the element to look for
396 * @return #GNUNET_YES if the element has been found, #GNUNET_NO otherwise 452 * @return #GNUNET_YES if the element has been found, #GNUNET_NO otherwise
397 */ 453 */
398static int 454static struct KeyEntry *
399op_has_element (struct Operation *op, 455op_get_element (struct Operation *op,
400 const struct GNUNET_HashCode *element_hash) 456 const struct GNUNET_HashCode *element_hash)
401{ 457{
402 int ret; 458 int ret;
403 struct IBF_Key ibf_key; 459 struct IBF_Key ibf_key;
460 struct GetElementContext ctx = {{{ 0 }} , 0};
461
462 ctx.hash = *element_hash;
404 463
405 ibf_key = get_ibf_key (element_hash); 464 ibf_key = get_ibf_key (element_hash);
406 ret = GNUNET_CONTAINER_multihashmap32_get_multiple (op->state->key_to_element, 465 ret = GNUNET_CONTAINER_multihashmap32_get_multiple (op->state->key_to_element,
407 (uint32_t) ibf_key.key_val, 466 (uint32_t) ibf_key.key_val,
408 op_has_element_iterator, 467 op_get_element_iterator,
409 (void *) element_hash); 468 &ctx);
410 469
411 /* was the iteration aborted because we found the element? */ 470 /* was the iteration aborted because we found the element? */
412 if (GNUNET_SYSERR == ret) 471 if (GNUNET_SYSERR == ret)
413 return GNUNET_YES; 472 {
414 return GNUNET_NO; 473 GNUNET_assert (NULL != ctx.k);
474 return ctx.k;
475 }
476 return NULL;
415} 477}
416 478
417 479
@@ -427,10 +489,12 @@ op_has_element (struct Operation *op,
427 * 489 *
428 * @param op the union operation 490 * @param op the union operation
429 * @param ee the element entry 491 * @param ee the element entry
492 * @parem received was this element received from the remote peer?
430 */ 493 */
431static void 494static void
432op_register_element (struct Operation *op, 495op_register_element (struct Operation *op,
433 struct ElementEntry *ee) 496 struct ElementEntry *ee,
497 int received)
434{ 498{
435 struct IBF_Key ibf_key; 499 struct IBF_Key ibf_key;
436 struct KeyEntry *k; 500 struct KeyEntry *k;
@@ -439,6 +503,7 @@ op_register_element (struct Operation *op,
439 k = GNUNET_new (struct KeyEntry); 503 k = GNUNET_new (struct KeyEntry);
440 k->element = ee; 504 k->element = ee;
441 k->ibf_key = ibf_key; 505 k->ibf_key = ibf_key;
506 k->received = received;
442 GNUNET_assert (GNUNET_OK == 507 GNUNET_assert (GNUNET_OK ==
443 GNUNET_CONTAINER_multihashmap32_put (op->state->key_to_element, 508 GNUNET_CONTAINER_multihashmap32_put (op->state->key_to_element,
444 (uint32_t) ibf_key.key_val, 509 (uint32_t) ibf_key.key_val,
@@ -447,6 +512,9 @@ op_register_element (struct Operation *op,
447} 512}
448 513
449 514
515/**
516 * FIXME.
517 */
450static void 518static void
451salt_key (const struct IBF_Key *k_in, 519salt_key (const struct IBF_Key *k_in,
452 uint32_t salt, 520 uint32_t salt,
@@ -460,6 +528,9 @@ salt_key (const struct IBF_Key *k_in,
460} 528}
461 529
462 530
531/**
532 * FIXME.
533 */
463static void 534static void
464unsalt_key (const struct IBF_Key *k_in, 535unsalt_key (const struct IBF_Key *k_in,
465 uint32_t salt, 536 uint32_t salt,
@@ -493,7 +564,9 @@ prepare_ibf_iterator (void *cls,
493 (void *) op, 564 (void *) op,
494 (unsigned long) ke->ibf_key.key_val, 565 (unsigned long) ke->ibf_key.key_val,
495 GNUNET_h2s (&ke->element->element_hash)); 566 GNUNET_h2s (&ke->element->element_hash));
496 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);
497 ibf_insert (op->state->local_ibf, salted_key); 570 ibf_insert (op->state->local_ibf, salted_key);
498 return GNUNET_YES; 571 return GNUNET_YES;
499} 572}
@@ -519,17 +592,39 @@ init_key_to_element_iterator (void *cls,
519 592
520 /* 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
521 * of creating the operation */ 594 * of creating the operation */
522 if (GNUNET_NO == _GSS_is_element_of_operation (ee, op)) 595 if (GNUNET_NO ==
596 _GSS_is_element_of_operation (ee,
597 op))
523 return GNUNET_YES; 598 return GNUNET_YES;
524
525 GNUNET_assert (GNUNET_NO == ee->remote); 599 GNUNET_assert (GNUNET_NO == ee->remote);
526 600 op_register_element (op,
527 op_register_element (op, ee); 601 ee,
602 GNUNET_NO);
528 return GNUNET_YES; 603 return GNUNET_YES;
529} 604}
530 605
531 606
532/** 607/**
608 * Initialize the IBF key to element mapping local to this set
609 * operation.
610 *
611 * @param op the set union operation
612 */
613static void
614initialize_key_to_element (struct Operation *op)
615{
616 unsigned int len;
617
618 GNUNET_assert (NULL == op->state->key_to_element);
619 len = GNUNET_CONTAINER_multihashmap_size (op->set->content->elements);
620 op->state->key_to_element = GNUNET_CONTAINER_multihashmap32_create (len + 1);
621 GNUNET_CONTAINER_multihashmap_iterate (op->set->content->elements,
622 &init_key_to_element_iterator,
623 op);
624}
625
626
627/**
533 * Create an ibf with the operation's elements 628 * Create an ibf with the operation's elements
534 * of the specified size 629 * of the specified size
535 * 630 *
@@ -541,15 +636,8 @@ static int
541prepare_ibf (struct Operation *op, 636prepare_ibf (struct Operation *op,
542 uint32_t size) 637 uint32_t size)
543{ 638{
544 if (NULL == op->state->key_to_element) 639 GNUNET_assert (NULL != op->state->key_to_element);
545 {
546 unsigned int len;
547 640
548 len = GNUNET_CONTAINER_multihashmap_size (op->spec->set->content->elements);
549 op->state->key_to_element = GNUNET_CONTAINER_multihashmap32_create (len + 1);
550 GNUNET_CONTAINER_multihashmap_iterate (op->spec->set->content->elements,
551 init_key_to_element_iterator, op);
552 }
553 if (NULL != op->state->local_ibf) 641 if (NULL != op->state->local_ibf)
554 ibf_destroy (op->state->local_ibf); 642 ibf_destroy (op->state->local_ibf);
555 op->state->local_ibf = ibf_create (size, SE_IBF_HASH_NUM); 643 op->state->local_ibf = ibf_create (size, SE_IBF_HASH_NUM);
@@ -639,43 +727,6 @@ send_ibf (struct Operation *op,
639 727
640 728
641/** 729/**
642 * Send a strata estimator to the remote peer.
643 *
644 * @param op the union operation with the remote peer
645 */
646static void
647send_strata_estimator (struct Operation *op)
648{
649 const struct StrataEstimator *se = op->state->se;
650 struct GNUNET_MQ_Envelope *ev;
651 struct GNUNET_MessageHeader *strata_msg;
652 char *buf;
653 size_t len;
654 uint16_t type;
655
656 buf = GNUNET_malloc (se->strata_count * IBF_BUCKET_SIZE * se->ibf_size);
657 len = strata_estimator_write (op->state->se,
658 buf);
659 if (len < se->strata_count * IBF_BUCKET_SIZE * se->ibf_size)
660 type = GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SEC;
661 else
662 type = GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SE;
663 ev = GNUNET_MQ_msg_header_extra (strata_msg,
664 len,
665 type);
666 GNUNET_memcpy (&strata_msg[1],
667 buf,
668 len);
669 GNUNET_free (buf);
670 GNUNET_MQ_send (op->mq,
671 ev);
672 op->state->phase = PHASE_EXPECT_IBF;
673 LOG (GNUNET_ERROR_TYPE_DEBUG,
674 "sent SE, expecting IBF\n");
675}
676
677
678/**
679 * Compute the necessary order of an ibf 730 * Compute the necessary order of an ibf
680 * from the size of the symmetric set difference. 731 * from the size of the symmetric set difference.
681 * 732 *
@@ -693,7 +744,68 @@ get_order_from_difference (unsigned int diff)
693 ibf_order++; 744 ibf_order++;
694 if (ibf_order > MAX_IBF_ORDER) 745 if (ibf_order > MAX_IBF_ORDER)
695 ibf_order = MAX_IBF_ORDER; 746 ibf_order = MAX_IBF_ORDER;
696 return ibf_order; 747 // add one for correction
748 return ibf_order + 1;
749}
750
751
752/**
753 * Send a set element.
754 *
755 * @param cls the union operation `struct Operation *`
756 * @param key unused
757 * @param value the `struct ElementEntry *` to insert
758 * into the key-to-element mapping
759 * @return #GNUNET_YES (to continue iterating)
760 */
761static int
762send_full_element_iterator (void *cls,
763 const struct GNUNET_HashCode *key,
764 void *value)
765{
766 struct Operation *op = cls;
767 struct GNUNET_SET_ElementMessage *emsg;
768 struct ElementEntry *ee = value;
769 struct GNUNET_SET_Element *el = &ee->element;
770 struct GNUNET_MQ_Envelope *ev;
771
772 LOG (GNUNET_ERROR_TYPE_INFO,
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);
778 emsg->element_type = htons (el->element_type);
779 GNUNET_memcpy (&emsg[1],
780 el->data,
781 el->size);
782 GNUNET_MQ_send (op->mq,
783 ev);
784 return GNUNET_YES;
785}
786
787
788/**
789 * Switch to full set transmission for @a op.
790 *
791 * @param op operation to switch to full set transmission.
792 */
793static void
794send_full_set (struct Operation *op)
795{
796 struct GNUNET_MQ_Envelope *ev;
797
798 op->state->phase = PHASE_FULL_SENDING;
799 LOG (GNUNET_ERROR_TYPE_INFO,
800 "Dedicing to transmit the full set\n");
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);
807 GNUNET_MQ_send (op->mq,
808 ev);
697} 809}
698 810
699 811
@@ -701,40 +813,57 @@ get_order_from_difference (unsigned int diff)
701 * Handle a strata estimator from a remote peer 813 * Handle a strata estimator from a remote peer
702 * 814 *
703 * @param cls the union operation 815 * @param cls the union operation
704 * @param mh the message 816 * @param msg the message
705 * @param is_compressed #GNUNET_YES if the estimator is compressed
706 * @return #GNUNET_SYSERR if the tunnel should be disconnected,
707 * #GNUNET_OK otherwise
708 */ 817 */
709static int 818int
710handle_p2p_strata_estimator (void *cls, 819check_union_p2p_strata_estimator (void *cls,
711 const struct GNUNET_MessageHeader *mh, 820 const struct StrataEstimatorMessage *msg)
712 int is_compressed)
713{ 821{
714 struct Operation *op = cls; 822 struct Operation *op = cls;
715 struct StrataEstimator *remote_se; 823 int is_compressed;
716 int diff;
717 size_t len; 824 size_t len;
718 825
719 GNUNET_STATISTICS_update (_GSS_statistics,
720 "# bytes of SE received",
721 ntohs (mh->size),
722 GNUNET_NO);
723
724 if (op->state->phase != PHASE_EXPECT_SE) 826 if (op->state->phase != PHASE_EXPECT_SE)
725 { 827 {
726 fail_union_operation (op);
727 GNUNET_break (0); 828 GNUNET_break (0);
728 return GNUNET_SYSERR; 829 return GNUNET_SYSERR;
729 } 830 }
730 len = ntohs (mh->size) - sizeof (struct GNUNET_MessageHeader); 831 is_compressed = (GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SEC == htons (msg->header.type));
832 len = ntohs (msg->header.size) - sizeof (struct StrataEstimatorMessage);
731 if ( (GNUNET_NO == is_compressed) && 833 if ( (GNUNET_NO == is_compressed) &&
732 (len != SE_STRATA_COUNT * SE_IBF_SIZE * IBF_BUCKET_SIZE) ) 834 (len != SE_STRATA_COUNT * SE_IBF_SIZE * IBF_BUCKET_SIZE) )
733 { 835 {
734 fail_union_operation (op);
735 GNUNET_break (0); 836 GNUNET_break (0);
736 return GNUNET_SYSERR; 837 return GNUNET_SYSERR;
737 } 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);
866 other_size = GNUNET_ntohll (msg->set_size);
738 remote_se = strata_estimator_create (SE_STRATA_COUNT, 867 remote_se = strata_estimator_create (SE_STRATA_COUNT,
739 SE_IBF_SIZE, 868 SE_IBF_SIZE,
740 SE_IBF_HASH_NUM); 869 SE_IBF_HASH_NUM);
@@ -742,40 +871,102 @@ handle_p2p_strata_estimator (void *cls,
742 { 871 {
743 /* insufficient resources, fail */ 872 /* insufficient resources, fail */
744 fail_union_operation (op); 873 fail_union_operation (op);
745 return GNUNET_SYSERR; 874 return;
746 } 875 }
747 if (GNUNET_OK != 876 if (GNUNET_OK !=
748 strata_estimator_read (&mh[1], 877 strata_estimator_read (&msg[1],
749 len, 878 len,
750 is_compressed, 879 is_compressed,
751 remote_se)) 880 remote_se))
752 { 881 {
753 /* decompression failed */ 882 /* decompression failed */
754 fail_union_operation (op);
755 strata_estimator_destroy (remote_se); 883 strata_estimator_destroy (remote_se);
756 return GNUNET_SYSERR; 884 fail_union_operation (op);
885 return;
757 } 886 }
758 GNUNET_assert (NULL != op->state->se); 887 GNUNET_assert (NULL != op->state->se);
759 diff = strata_estimator_difference (remote_se, 888 diff = strata_estimator_difference (remote_se,
760 op->state->se); 889 op->state->se);
890
891 if (diff > 200)
892 diff = diff * 3 / 2;
893
761 strata_estimator_destroy (remote_se); 894 strata_estimator_destroy (remote_se);
762 strata_estimator_destroy (op->state->se); 895 strata_estimator_destroy (op->state->se);
763 op->state->se = NULL; 896 op->state->se = NULL;
764 LOG (GNUNET_ERROR_TYPE_DEBUG, 897 LOG (GNUNET_ERROR_TYPE_DEBUG,
765 "got se diff=%d, using ibf size %d\n", 898 "got se diff=%d, using ibf size %d\n",
766 diff, 899 diff,
767 1<<get_order_from_difference (diff)); 900 1U << get_order_from_difference (diff));
768 if (GNUNET_OK != 901
769 send_ibf (op,
770 get_order_from_difference (diff)))
771 { 902 {
772 /* Internal error, best we can do is shut the connection */ 903 char *set_debug;
773 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 904
774 "Failed to send IBF, closing connection\n"); 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) )
917 {
918 GNUNET_break (0);
775 fail_union_operation (op); 919 fail_union_operation (op);
776 return GNUNET_SYSERR; 920 return;
777 } 921 }
778 return GNUNET_OK; 922
923 if ( (GNUNET_YES == op->force_full) ||
924 (diff > op->state->initial_size / 4) ||
925 (0 == other_size) )
926 {
927 LOG (GNUNET_ERROR_TYPE_INFO,
928 "Deciding to go for full set transmission (diff=%d, own set=%u)\n",
929 diff,
930 op->state->initial_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) )
937 {
938 send_full_set (op);
939 }
940 else
941 {
942 struct GNUNET_MQ_Envelope *ev;
943
944 LOG (GNUNET_ERROR_TYPE_INFO,
945 "Telling other peer that we expect its full set\n");
946 op->state->phase = PHASE_EXPECT_IBF;
947 ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_UNION_P2P_REQUEST_FULL);
948 GNUNET_MQ_send (op->mq,
949 ev);
950 }
951 }
952 else
953 {
954 GNUNET_STATISTICS_update (_GSS_statistics,
955 "# of ibf sends",
956 1,
957 GNUNET_NO);
958 if (GNUNET_OK !=
959 send_ibf (op,
960 get_order_from_difference (diff)))
961 {
962 /* Internal error, best we can do is shut the connection */
963 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
964 "Failed to send IBF, closing connection\n");
965 fail_union_operation (op);
966 return;
967 }
968 }
969 GNUNET_CADET_receive_done (op->channel);
779} 970}
780 971
781 972
@@ -856,14 +1047,16 @@ decode_and_send (struct Operation *op)
856 GNUNET_assert (PHASE_INVENTORY_ACTIVE == op->state->phase); 1047 GNUNET_assert (PHASE_INVENTORY_ACTIVE == op->state->phase);
857 1048
858 if (GNUNET_OK != 1049 if (GNUNET_OK !=
859 prepare_ibf (op, op->state->remote_ibf->size)) 1050 prepare_ibf (op,
1051 op->state->remote_ibf->size))
860 { 1052 {
861 GNUNET_break (0); 1053 GNUNET_break (0);
862 /* allocation failed */ 1054 /* allocation failed */
863 return GNUNET_SYSERR; 1055 return GNUNET_SYSERR;
864 } 1056 }
865 diff_ibf = ibf_dup (op->state->local_ibf); 1057 diff_ibf = ibf_dup (op->state->local_ibf);
866 ibf_subtract (diff_ibf, op->state->remote_ibf); 1058 ibf_subtract (diff_ibf,
1059 op->state->remote_ibf);
867 1060
868 ibf_destroy (op->state->remote_ibf); 1061 ibf_destroy (op->state->remote_ibf);
869 op->state->remote_ibf = NULL; 1062 op->state->remote_ibf = NULL;
@@ -960,8 +1153,12 @@ decode_and_send (struct Operation *op)
960 if (1 == side) 1153 if (1 == side)
961 { 1154 {
962 struct IBF_Key unsalted_key; 1155 struct IBF_Key unsalted_key;
963 unsalt_key (&key, op->state->salt_receive, &unsalted_key); 1156
964 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);
965 } 1162 }
966 else if (-1 == side) 1163 else if (-1 == side)
967 { 1164 {
@@ -993,99 +1190,118 @@ decode_and_send (struct Operation *op)
993 1190
994 1191
995/** 1192/**
996 * Handle an IBF message from a remote peer. 1193 * Check an IBF message from a remote peer.
997 * 1194 *
998 * Reassemble the IBF from multiple pieces, and 1195 * Reassemble the IBF from multiple pieces, and
999 * process the whole IBF once possible. 1196 * process the whole IBF once possible.
1000 * 1197 *
1001 * @param cls the union operation 1198 * @param cls the union operation
1002 * @param mh the header of the message 1199 * @param msg the header of the message
1003 * @return #GNUNET_SYSERR if the tunnel should be disconnected, 1200 * @return #GNUNET_OK if @a msg is well-formed
1004 * #GNUNET_OK otherwise
1005 */ 1201 */
1006static int 1202int
1007handle_p2p_ibf (void *cls, 1203check_union_p2p_ibf (void *cls,
1008 const struct GNUNET_MessageHeader *mh) 1204 const struct IBFMessage *msg)
1009{ 1205{
1010 struct Operation *op = cls; 1206 struct Operation *op = cls;
1011 const struct IBFMessage *msg;
1012 unsigned int buckets_in_message; 1207 unsigned int buckets_in_message;
1013 1208
1014 if (ntohs (mh->size) < sizeof (struct IBFMessage)) 1209 if (GNUNET_SET_OPERATION_UNION != op->set->operation)
1015 { 1210 {
1016 GNUNET_break_op (0); 1211 GNUNET_break_op (0);
1017 fail_union_operation (op);
1018 return GNUNET_SYSERR; 1212 return GNUNET_SYSERR;
1019 } 1213 }
1020 msg = (const struct IBFMessage *) mh; 1214 buckets_in_message = (ntohs (msg->header.size) - sizeof *msg) / IBF_BUCKET_SIZE;
1021 if ( (op->state->phase == PHASE_INVENTORY_PASSIVE) || 1215 if (0 == buckets_in_message)
1022 (op->state->phase == PHASE_EXPECT_IBF) )
1023 { 1216 {
1024 op->state->phase = PHASE_EXPECT_IBF_CONT; 1217 GNUNET_break_op (0);
1025 GNUNET_assert (NULL == op->state->remote_ibf); 1218 return GNUNET_SYSERR;
1026 LOG (GNUNET_ERROR_TYPE_DEBUG, 1219 }
1027 "Creating new ibf of size %u\n", 1220 if ((ntohs (msg->header.size) - sizeof *msg) != buckets_in_message * IBF_BUCKET_SIZE)
1028 1 << msg->order); 1221 {
1029 op->state->remote_ibf = ibf_create (1<<msg->order, SE_IBF_HASH_NUM); 1222 GNUNET_break_op (0);
1030 op->state->salt_receive = ntohl (msg->salt); 1223 return GNUNET_SYSERR;
1031 LOG (GNUNET_ERROR_TYPE_DEBUG, "Receiving new IBF with salt %u\n", op->state->salt_receive);
1032 if (NULL == op->state->remote_ibf)
1033 {
1034 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1035 "Failed to parse remote IBF, closing connection\n");
1036 fail_union_operation (op);
1037 return GNUNET_SYSERR;
1038 }
1039 op->state->ibf_buckets_received = 0;
1040 if (0 != ntohl (msg->offset))
1041 {
1042 GNUNET_break_op (0);
1043 fail_union_operation (op);
1044 return GNUNET_SYSERR;
1045 }
1046 } 1224 }
1047 else if (op->state->phase == PHASE_EXPECT_IBF_CONT) 1225 if (op->state->phase == PHASE_EXPECT_IBF_CONT)
1048 { 1226 {
1049 if (ntohl (msg->offset) != op->state->ibf_buckets_received) 1227 if (ntohl (msg->offset) != op->state->ibf_buckets_received)
1050 { 1228 {
1051 GNUNET_break_op (0); 1229 GNUNET_break_op (0);
1052 fail_union_operation (op);
1053 return GNUNET_SYSERR; 1230 return GNUNET_SYSERR;
1054 } 1231 }
1055 if (1<<msg->order != op->state->remote_ibf->size) 1232 if (1<<msg->order != op->state->remote_ibf->size)
1056 { 1233 {
1057 GNUNET_break_op (0); 1234 GNUNET_break_op (0);
1058 fail_union_operation (op);
1059 return GNUNET_SYSERR; 1235 return GNUNET_SYSERR;
1060 } 1236 }
1061 if (ntohl (msg->salt) != op->state->salt_receive) 1237 if (ntohl (msg->salt) != op->state->salt_receive)
1062 { 1238 {
1063 GNUNET_break_op (0); 1239 GNUNET_break_op (0);
1064 fail_union_operation (op);
1065 return GNUNET_SYSERR; 1240 return GNUNET_SYSERR;
1066 } 1241 }
1067 } 1242 }
1068 else 1243 else if ( (op->state->phase != PHASE_INVENTORY_PASSIVE) &&
1244 (op->state->phase != PHASE_EXPECT_IBF) )
1069 { 1245 {
1070 GNUNET_assert (0); 1246 GNUNET_break_op (0);
1247 return GNUNET_SYSERR;
1071 } 1248 }
1072 1249
1073 buckets_in_message = (ntohs (msg->header.size) - sizeof *msg) / IBF_BUCKET_SIZE; 1250 return GNUNET_OK;
1251}
1074 1252
1075 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) )
1076 { 1273 {
1077 GNUNET_break_op (0); 1274 op->state->phase = PHASE_EXPECT_IBF_CONT;
1078 fail_union_operation (op); 1275 GNUNET_assert (NULL == op->state->remote_ibf);
1079 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 }
1080 } 1298 }
1081 1299 else
1082 if ((ntohs (msg->header.size) - sizeof *msg) != buckets_in_message * IBF_BUCKET_SIZE)
1083 { 1300 {
1084 GNUNET_break_op (0); 1301 GNUNET_assert (op->state->phase == PHASE_EXPECT_IBF_CONT);
1085 fail_union_operation (op); 1302 LOG (GNUNET_ERROR_TYPE_INFO,
1086 return GNUNET_SYSERR; 1303 "Received more of IBF\n");
1087 } 1304 }
1088
1089 GNUNET_assert (NULL != op->state->remote_ibf); 1305 GNUNET_assert (NULL != op->state->remote_ibf);
1090 1306
1091 ibf_read_slice (&msg[1], 1307 ibf_read_slice (&msg[1],
@@ -1105,10 +1321,11 @@ handle_p2p_ibf (void *cls,
1105 /* Internal error, best we can do is shut down */ 1321 /* Internal error, best we can do is shut down */
1106 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1322 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1107 "Failed to decode IBF, closing connection\n"); 1323 "Failed to decode IBF, closing connection\n");
1108 return GNUNET_SYSERR; 1324 fail_union_operation (op);
1325 return;
1109 } 1326 }
1110 } 1327 }
1111 return GNUNET_OK; 1328 GNUNET_CADET_receive_done (op->channel);
1112} 1329}
1113 1330
1114 1331
@@ -1131,7 +1348,7 @@ send_client_element (struct Operation *op,
1131 LOG (GNUNET_ERROR_TYPE_DEBUG, 1348 LOG (GNUNET_ERROR_TYPE_DEBUG,
1132 "sending element (size %u) to client\n", 1349 "sending element (size %u) to client\n",
1133 element->size); 1350 element->size);
1134 GNUNET_assert (0 != op->spec->client_request_id); 1351 GNUNET_assert (0 != op->client_request_id);
1135 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);
1136 if (NULL == ev) 1353 if (NULL == ev)
1137 { 1354 {
@@ -1140,10 +1357,14 @@ send_client_element (struct Operation *op,
1140 return; 1357 return;
1141 } 1358 }
1142 rm->result_status = htons (status); 1359 rm->result_status = htons (status);
1143 rm->request_id = htonl (op->spec->client_request_id); 1360 rm->request_id = htonl (op->client_request_id);
1144 rm->element_type = element->element_type; 1361 rm->element_type = htons (element->element_type);
1145 GNUNET_memcpy (&rm[1], element->data, element->size); 1362 rm->current_size = GNUNET_htonll (GNUNET_CONTAINER_multihashmap32_size (op->state->key_to_element));
1146 GNUNET_MQ_send (op->spec->set->client_mq, ev); 1363 GNUNET_memcpy (&rm[1],
1364 element->data,
1365 element->size);
1366 GNUNET_MQ_send (op->set->cs->mq,
1367 ev);
1147} 1368}
1148 1369
1149 1370
@@ -1160,16 +1381,27 @@ send_done_and_destroy (void *cls)
1160 struct GNUNET_MQ_Envelope *ev; 1381 struct GNUNET_MQ_Envelope *ev;
1161 struct GNUNET_SET_ResultMessage *rm; 1382 struct GNUNET_SET_ResultMessage *rm;
1162 1383
1163 ev = GNUNET_MQ_msg (rm, GNUNET_MESSAGE_TYPE_SET_RESULT); 1384 LOG (GNUNET_ERROR_TYPE_INFO,
1164 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);
1165 rm->result_status = htons (GNUNET_SET_STATUS_DONE); 1389 rm->result_status = htons (GNUNET_SET_STATUS_DONE);
1166 rm->element_type = htons (0); 1390 rm->element_type = htons (0);
1167 GNUNET_MQ_send (op->spec->set->client_mq, ev); 1391 rm->current_size = GNUNET_htonll (GNUNET_CONTAINER_multihashmap32_size (op->state->key_to_element));
1392 GNUNET_MQ_send (op->set->cs->mq,
1393 ev);
1168 /* Will also call the union-specific cancel function. */ 1394 /* Will also call the union-specific cancel function. */
1169 _GSS_operation_destroy (op, GNUNET_YES); 1395 _GSS_operation_destroy (op,
1396 GNUNET_YES);
1170} 1397}
1171 1398
1172 1399
1400/**
1401 * Tests if the operation is finished, and if so notify.
1402 *
1403 * @param op operation to check
1404 */
1173static void 1405static void
1174maybe_finish (struct Operation *op) 1406maybe_finish (struct Operation *op)
1175{ 1407{
@@ -1188,8 +1420,8 @@ maybe_finish (struct Operation *op)
1188 1420
1189 op->state->phase = PHASE_DONE; 1421 op->state->phase = PHASE_DONE;
1190 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);
1191 GNUNET_MQ_send (op->mq, ev); 1423 GNUNET_MQ_send (op->mq,
1192 1424 ev);
1193 /* We now wait until the other peer closes the channel 1425 /* We now wait until the other peer closes the channel
1194 * after it got all elements from us. */ 1426 * after it got all elements from us. */
1195 } 1427 }
@@ -1209,44 +1441,59 @@ maybe_finish (struct Operation *op)
1209 1441
1210 1442
1211/** 1443/**
1212 * Handle an element message from a remote peer. 1444 * Check an element message from a remote peer.
1213 * 1445 *
1214 * @param cls the union operation 1446 * @param cls the union operation
1215 * @param mh the message 1447 * @param emsg the message
1216 */ 1448 */
1217static void 1449int
1218handle_p2p_elements (void *cls, 1450check_union_p2p_elements (void *cls,
1219 const struct GNUNET_MessageHeader *mh) 1451 const struct GNUNET_SET_ElementMessage *emsg)
1220{ 1452{
1221 struct Operation *op = cls; 1453 struct Operation *op = cls;
1222 struct ElementEntry *ee;
1223 const struct GNUNET_SET_ElementMessage *emsg;
1224 uint16_t element_size;
1225 1454
1226 if (0 == GNUNET_CONTAINER_multihashmap_size (op->state->demanded_hashes)) 1455 if (GNUNET_SET_OPERATION_UNION != op->set->operation)
1227 { 1456 {
1228 GNUNET_break_op (0); 1457 GNUNET_break_op (0);
1229 fail_union_operation (op); 1458 return GNUNET_SYSERR;
1230 return;
1231 } 1459 }
1232 if (ntohs (mh->size) < sizeof (struct GNUNET_SET_ElementMessage)) 1460 if (0 == GNUNET_CONTAINER_multihashmap_size (op->state->demanded_hashes))
1233 { 1461 {
1234 GNUNET_break_op (0); 1462 GNUNET_break_op (0);
1235 fail_union_operation (op); 1463 return GNUNET_SYSERR;
1236 return;
1237 } 1464 }
1465 return GNUNET_OK;
1466}
1238 1467
1239 emsg = (const struct GNUNET_SET_ElementMessage *) mh;
1240 1468
1241 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);
1242 ee = GNUNET_malloc (sizeof (struct ElementEntry) + element_size); 1487 ee = GNUNET_malloc (sizeof (struct ElementEntry) + element_size);
1243 GNUNET_memcpy (&ee[1], &emsg[1], element_size); 1488 GNUNET_memcpy (&ee[1],
1489 &emsg[1],
1490 element_size);
1244 ee->element.size = element_size; 1491 ee->element.size = element_size;
1245 ee->element.data = &ee[1]; 1492 ee->element.data = &ee[1];
1246 ee->element.element_type = ntohs (emsg->element_type); 1493 ee->element.element_type = ntohs (emsg->element_type);
1247 ee->remote = GNUNET_YES; 1494 ee->remote = GNUNET_YES;
1248 GNUNET_SET_element_hash (&ee->element, &ee->element_hash); 1495 GNUNET_SET_element_hash (&ee->element,
1249 1496 &ee->element_hash);
1250 if (GNUNET_NO == 1497 if (GNUNET_NO ==
1251 GNUNET_CONTAINER_multihashmap_remove (op->state->demanded_hashes, 1498 GNUNET_CONTAINER_multihashmap_remove (op->state->demanded_hashes,
1252 &ee->element_hash, 1499 &ee->element_hash,
@@ -1254,7 +1501,6 @@ handle_p2p_elements (void *cls,
1254 { 1501 {
1255 /* 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. */
1256 GNUNET_break_op (0); 1503 GNUNET_break_op (0);
1257 GNUNET_free (ee);
1258 fail_union_operation (op); 1504 fail_union_operation (op);
1259 return; 1505 return;
1260 } 1506 }
@@ -1273,7 +1519,10 @@ handle_p2p_elements (void *cls,
1273 1, 1519 1,
1274 GNUNET_NO); 1520 GNUNET_NO);
1275 1521
1276 if (GNUNET_YES == op_has_element (op, &ee->element_hash)) 1522 op->state->received_total++;
1523
1524 ke = op_get_element (op, &ee->element_hash);
1525 if (NULL != ke)
1277 { 1526 {
1278 /* Got repeated element. Should not happen since 1527 /* Got repeated element. Should not happen since
1279 * we track demands. */ 1528 * we track demands. */
@@ -1281,15 +1530,17 @@ handle_p2p_elements (void *cls,
1281 "# repeated elements", 1530 "# repeated elements",
1282 1, 1531 1,
1283 GNUNET_NO); 1532 GNUNET_NO);
1533 ke->received = GNUNET_YES;
1284 GNUNET_free (ee); 1534 GNUNET_free (ee);
1285 } 1535 }
1286 else 1536 else
1287 { 1537 {
1288 LOG (GNUNET_ERROR_TYPE_DEBUG, 1538 LOG (GNUNET_ERROR_TYPE_DEBUG,
1289 "Registering new element from remote peer\n"); 1539 "Registering new element from remote peer\n");
1290 op_register_element (op, ee); 1540 op->state->received_fresh++;
1541 op_register_element (op, ee, GNUNET_YES);
1291 /* only send results immediately if the client wants it */ 1542 /* only send results immediately if the client wants it */
1292 switch (op->spec->result_mode) 1543 switch (op->result_mode)
1293 { 1544 {
1294 case GNUNET_SET_RESULT_ADDED: 1545 case GNUNET_SET_RESULT_ADDED:
1295 send_client_element (op, &ee->element, GNUNET_SET_STATUS_OK); 1546 send_client_element (op, &ee->element, GNUNET_SET_STATUS_OK);
@@ -1304,85 +1555,390 @@ handle_p2p_elements (void *cls,
1304 } 1555 }
1305 } 1556 }
1306 1557
1558 if ( (op->state->received_total > 8) &&
1559 (op->state->received_fresh < op->state->received_total / 3) )
1560 {
1561 /* The other peer gave us lots of old elements, there's something wrong. */
1562 GNUNET_break_op (0);
1563 fail_union_operation (op);
1564 return;
1565 }
1566 GNUNET_CADET_receive_done (op->channel);
1307 maybe_finish (op); 1567 maybe_finish (op);
1308} 1568}
1309 1569
1310 1570
1311/** 1571/**
1572 * Check a full element message from a remote peer.
1573 *
1574 * @param cls the union operation
1575 * @param emsg the message
1576 */
1577int
1578check_union_p2p_full_element (void *cls,
1579 const struct GNUNET_SET_ElementMessage *emsg)
1580{
1581 struct Operation *op = cls;
1582
1583 if (GNUNET_SET_OPERATION_UNION != op->set->operation)
1584 {
1585 GNUNET_break_op (0);
1586 return GNUNET_SYSERR;
1587 }
1588 // FIXME: check that we expect full elements here?
1589 return GNUNET_OK;
1590}
1591
1592
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);
1609 ee = GNUNET_malloc (sizeof (struct ElementEntry) + element_size);
1610 GNUNET_memcpy (&ee[1], &emsg[1], element_size);
1611 ee->element.size = element_size;
1612 ee->element.data = &ee[1];
1613 ee->element.element_type = ntohs (emsg->element_type);
1614 ee->remote = GNUNET_YES;
1615 GNUNET_SET_element_hash (&ee->element, &ee->element_hash);
1616
1617 LOG (GNUNET_ERROR_TYPE_DEBUG,
1618 "Got element (full diff, size %u, hash %s) from peer\n",
1619 (unsigned int) element_size,
1620 GNUNET_h2s (&ee->element_hash));
1621
1622 GNUNET_STATISTICS_update (_GSS_statistics,
1623 "# received elements",
1624 1,
1625 GNUNET_NO);
1626 GNUNET_STATISTICS_update (_GSS_statistics,
1627 "# exchanged elements",
1628 1,
1629 GNUNET_NO);
1630
1631 op->state->received_total++;
1632
1633 ke = op_get_element (op, &ee->element_hash);
1634 if (NULL != ke)
1635 {
1636 /* Got repeated element. Should not happen since
1637 * we track demands. */
1638 GNUNET_STATISTICS_update (_GSS_statistics,
1639 "# repeated elements",
1640 1,
1641 GNUNET_NO);
1642 ke->received = GNUNET_YES;
1643 GNUNET_free (ee);
1644 }
1645 else
1646 {
1647 LOG (GNUNET_ERROR_TYPE_DEBUG,
1648 "Registering new element from remote peer\n");
1649 op->state->received_fresh++;
1650 op_register_element (op, ee, GNUNET_YES);
1651 /* only send results immediately if the client wants it */
1652 switch (op->result_mode)
1653 {
1654 case GNUNET_SET_RESULT_ADDED:
1655 send_client_element (op, &ee->element, GNUNET_SET_STATUS_OK);
1656 break;
1657 case GNUNET_SET_RESULT_SYMMETRIC:
1658 send_client_element (op, &ee->element, GNUNET_SET_STATUS_ADD_LOCAL);
1659 break;
1660 default:
1661 /* Result mode not supported, should have been caught earlier. */
1662 GNUNET_break (0);
1663 break;
1664 }
1665 }
1666
1667 if ( (GNUNET_YES == op->byzantine) &&
1668 (op->state->received_total > 384 + op->state->received_fresh * 4) &&
1669 (op->state->received_fresh < op->state->received_total / 6) )
1670 {
1671 /* The other peer gave us lots of old elements, there's something wrong. */
1672 LOG (GNUNET_ERROR_TYPE_ERROR,
1673 "Other peer sent only %llu/%llu fresh elements, failing operation\n",
1674 (unsigned long long) op->state->received_fresh,
1675 (unsigned long long) op->state->received_total);
1676 GNUNET_break_op (0);
1677 fail_union_operation (op);
1678 return;
1679 }
1680 GNUNET_CADET_receive_done (op->channel);
1681}
1682
1683
1684/**
1312 * Send offers (for GNUNET_Hash-es) in response 1685 * Send offers (for GNUNET_Hash-es) in response
1313 * to inquiries (for IBF_Key-s). 1686 * to inquiries (for IBF_Key-s).
1314 * 1687 *
1315 * @param cls the union operation 1688 * @param cls the union operation
1316 * @param mh the message 1689 * @param msg the message
1317 */ 1690 */
1318static void 1691int
1319handle_p2p_inquiry (void *cls, 1692check_union_p2p_inquiry (void *cls,
1320 const struct GNUNET_MessageHeader *mh) 1693 const struct InquiryMessage *msg)
1321{ 1694{
1322 struct Operation *op = cls; 1695 struct Operation *op = cls;
1323 const struct IBF_Key *ibf_key;
1324 unsigned int num_keys; 1696 unsigned int num_keys;
1325 struct InquiryMessage *msg;
1326 1697
1327 /* 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 }
1328 if (op->state->phase != PHASE_INVENTORY_PASSIVE) 1703 if (op->state->phase != PHASE_INVENTORY_PASSIVE)
1329 { 1704 {
1330 GNUNET_break_op (0); 1705 GNUNET_break_op (0);
1331 fail_union_operation (op); 1706 return GNUNET_SYSERR;
1332 return;
1333 } 1707 }
1334 num_keys = (ntohs (mh->size) - sizeof (struct InquiryMessage)) 1708 num_keys = (ntohs (msg->header.size) - sizeof (struct InquiryMessage))
1335 / sizeof (struct IBF_Key); 1709 / sizeof (struct IBF_Key);
1336 if ((ntohs (mh->size) - sizeof (struct InquiryMessage)) 1710 if ((ntohs (msg->header.size) - sizeof (struct InquiryMessage))
1337 != num_keys * sizeof (struct IBF_Key)) 1711 != num_keys * sizeof (struct IBF_Key))
1338 { 1712 {
1339 GNUNET_break_op (0); 1713 GNUNET_break_op (0);
1340 fail_union_operation (op); 1714 return GNUNET_SYSERR;
1341 return;
1342 } 1715 }
1716 return GNUNET_OK;
1717}
1343 1718
1344 msg = (struct InquiryMessage *) mh;
1345 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);
1346 ibf_key = (const struct IBF_Key *) &msg[1]; 1739 ibf_key = (const struct IBF_Key *) &msg[1];
1347 while (0 != num_keys--) 1740 while (0 != num_keys--)
1348 { 1741 {
1349 struct IBF_Key unsalted_key; 1742 struct IBF_Key unsalted_key;
1350 unsalt_key (ibf_key, ntohl (msg->salt), &unsalted_key); 1743
1351 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);
1352 ibf_key++; 1749 ibf_key++;
1353 } 1750 }
1751 GNUNET_CADET_receive_done (op->channel);
1354} 1752}
1355 1753
1356 1754
1357/** 1755/**
1358 * FIXME 1756 * Iterator over hash map entries, called to
1757 * destroy the linked list of colliding ibf key entries.
1758 *
1759 * @param cls closure
1760 * @param key current key code
1761 * @param value value in the hash map
1762 * @return #GNUNET_YES if we should continue to iterate,
1763 * #GNUNET_NO if not.
1359 */ 1764 */
1360static void 1765static int
1361handle_p2p_demand (void *cls, 1766send_missing_full_elements_iter (void *cls,
1362 const struct GNUNET_MessageHeader *mh) 1767 uint32_t key,
1768 void *value)
1363{ 1769{
1364 struct Operation *op = cls; 1770 struct Operation *op = cls;
1365 struct ElementEntry *ee; 1771 struct KeyEntry *ke = value;
1772 struct GNUNET_MQ_Envelope *ev;
1366 struct GNUNET_SET_ElementMessage *emsg; 1773 struct GNUNET_SET_ElementMessage *emsg;
1367 const struct GNUNET_HashCode *hash; 1774 struct ElementEntry *ee = ke->element;
1775
1776 if (GNUNET_YES == ke->received)
1777 return GNUNET_YES;
1778 ev = GNUNET_MQ_msg_extra (emsg,
1779 ee->element.size,
1780 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_ELEMENT);
1781 GNUNET_memcpy (&emsg[1],
1782 ee->element.data,
1783 ee->element.size);
1784 emsg->element_type = htons (ee->element.element_type);
1785 GNUNET_MQ_send (op->mq,
1786 ev);
1787 return GNUNET_YES;
1788}
1789
1790
1791/**
1792 * Handle a request for full set transmission.
1793 *
1794 * @parem cls closure, a set union operation
1795 * @param mh the demand message
1796 */
1797void
1798handle_union_p2p_request_full (void *cls,
1799 const struct GNUNET_MessageHeader *mh)
1800{
1801 struct Operation *op = cls;
1802
1803 LOG (GNUNET_ERROR_TYPE_INFO,
1804 "Received request for full set transmission\n");
1805 if (GNUNET_SET_OPERATION_UNION != op->set->operation)
1806 {
1807 GNUNET_break_op (0);
1808 fail_union_operation (op);
1809 return;
1810 }
1811 if (PHASE_EXPECT_IBF != op->state->phase)
1812 {
1813 GNUNET_break_op (0);
1814 fail_union_operation (op);
1815 return;
1816 }
1817
1818 // FIXME: we need to check that our set is larger than the
1819 // byzantine_lower_bound by some threshold
1820 send_full_set (op);
1821 GNUNET_CADET_receive_done (op->channel);
1822}
1823
1824
1825/**
1826 * Handle a "full done" message.
1827 *
1828 * @parem cls closure, a set union operation
1829 * @param mh the demand message
1830 */
1831void
1832handle_union_p2p_full_done (void *cls,
1833 const struct GNUNET_MessageHeader *mh)
1834{
1835 struct Operation *op = cls;
1836
1837 switch (op->state->phase)
1838 {
1839 case PHASE_EXPECT_IBF:
1840 {
1841 struct GNUNET_MQ_Envelope *ev;
1842
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}
1882
1883
1884/**
1885 * Check a demand by the other peer for elements based on a list
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;
1368 unsigned int num_hashes; 1897 unsigned int num_hashes;
1369 struct GNUNET_MQ_Envelope *ev;
1370 1898
1899 if (GNUNET_SET_OPERATION_UNION != op->set->operation)
1900 {
1901 GNUNET_break_op (0);
1902 return GNUNET_SYSERR;
1903 }
1371 num_hashes = (ntohs (mh->size) - sizeof (struct GNUNET_MessageHeader)) 1904 num_hashes = (ntohs (mh->size) - sizeof (struct GNUNET_MessageHeader))
1372 / sizeof (struct GNUNET_HashCode); 1905 / sizeof (struct GNUNET_HashCode);
1373 if ((ntohs (mh->size) - sizeof (struct GNUNET_MessageHeader)) 1906 if ((ntohs (mh->size) - sizeof (struct GNUNET_MessageHeader))
1374 != num_hashes * sizeof (struct GNUNET_HashCode)) 1907 != num_hashes * sizeof (struct GNUNET_HashCode))
1375 { 1908 {
1376 GNUNET_break_op (0); 1909 GNUNET_break_op (0);
1377 fail_union_operation (op); 1910 return GNUNET_SYSERR;
1378 return;
1379 } 1911 }
1912 return GNUNET_OK;
1913}
1914
1915
1916/**
1917 * Handle a demand by the other peer for elements based on a list
1918 * of `struct GNUNET_HashCode`s.
1919 *
1920 * @parem cls closure, a set union operation
1921 * @param mh the demand message
1922 */
1923void
1924handle_union_p2p_demand (void *cls,
1925 const struct GNUNET_MessageHeader *mh)
1926{
1927 struct Operation *op = cls;
1928 struct ElementEntry *ee;
1929 struct GNUNET_SET_ElementMessage *emsg;
1930 const struct GNUNET_HashCode *hash;
1931 unsigned int num_hashes;
1932 struct GNUNET_MQ_Envelope *ev;
1380 1933
1934 num_hashes = (ntohs (mh->size) - sizeof (struct GNUNET_MessageHeader))
1935 / sizeof (struct GNUNET_HashCode);
1381 for (hash = (const struct GNUNET_HashCode *) &mh[1]; 1936 for (hash = (const struct GNUNET_HashCode *) &mh[1];
1382 num_hashes > 0; 1937 num_hashes > 0;
1383 hash++, num_hashes--) 1938 hash++, num_hashes--)
1384 { 1939 {
1385 ee = GNUNET_CONTAINER_multihashmap_get (op->spec->set->content->elements, hash); 1940 ee = GNUNET_CONTAINER_multihashmap_get (op->set->content->elements,
1941 hash);
1386 if (NULL == ee) 1942 if (NULL == ee)
1387 { 1943 {
1388 /* Demand for non-existing element. */ 1944 /* Demand for non-existing element. */
@@ -1412,7 +1968,7 @@ handle_p2p_demand (void *cls,
1412 1, 1968 1,
1413 GNUNET_NO); 1969 GNUNET_NO);
1414 1970
1415 switch (op->spec->result_mode) 1971 switch (op->result_mode)
1416 { 1972 {
1417 case GNUNET_SET_RESULT_ADDED: 1973 case GNUNET_SET_RESULT_ADDED:
1418 /* Nothing to do. */ 1974 /* Nothing to do. */
@@ -1426,42 +1982,65 @@ handle_p2p_demand (void *cls,
1426 break; 1982 break;
1427 } 1983 }
1428 } 1984 }
1985 GNUNET_CADET_receive_done (op->channel);
1429} 1986}
1430 1987
1431 1988
1432/** 1989/**
1433 * Handle offers (of GNUNET_HashCode-s) and 1990 * Check offer (of `struct GNUNET_HashCode`s).
1434 * respond with demands (of GNUNET_HashCode-s).
1435 * 1991 *
1436 * @param cls the union operation 1992 * @param cls the union operation
1437 * @param mh the message 1993 * @param mh the message
1994 * @return #GNUNET_OK if @a mh is well-formed
1438 */ 1995 */
1439static void 1996int
1440handle_p2p_offer (void *cls, 1997check_union_p2p_offer (void *cls,
1441 const struct GNUNET_MessageHeader *mh) 1998 const struct GNUNET_MessageHeader *mh)
1442{ 1999{
1443 struct Operation *op = cls; 2000 struct Operation *op = cls;
1444 const struct GNUNET_HashCode *hash;
1445 unsigned int num_hashes; 2001 unsigned int num_hashes;
1446 2002
2003 if (GNUNET_SET_OPERATION_UNION != op->set->operation)
2004 {
2005 GNUNET_break_op (0);
2006 return GNUNET_SYSERR;
2007 }
1447 /* look up elements and send them */ 2008 /* look up elements and send them */
1448 if ( (op->state->phase != PHASE_INVENTORY_PASSIVE) && 2009 if ( (op->state->phase != PHASE_INVENTORY_PASSIVE) &&
1449 (op->state->phase != PHASE_INVENTORY_ACTIVE)) 2010 (op->state->phase != PHASE_INVENTORY_ACTIVE))
1450 { 2011 {
1451 GNUNET_break_op (0); 2012 GNUNET_break_op (0);
1452 fail_union_operation (op); 2013 return GNUNET_SYSERR;
1453 return;
1454 } 2014 }
1455 num_hashes = (ntohs (mh->size) - sizeof (struct GNUNET_MessageHeader)) 2015 num_hashes = (ntohs (mh->size) - sizeof (struct GNUNET_MessageHeader))
1456 / sizeof (struct GNUNET_HashCode); 2016 / sizeof (struct GNUNET_HashCode);
1457 if ((ntohs (mh->size) - sizeof (struct GNUNET_MessageHeader)) 2017 if ((ntohs (mh->size) - sizeof (struct GNUNET_MessageHeader)) !=
1458 != num_hashes * sizeof (struct GNUNET_HashCode)) 2018 num_hashes * sizeof (struct GNUNET_HashCode))
1459 { 2019 {
1460 GNUNET_break_op (0); 2020 GNUNET_break_op (0);
1461 fail_union_operation (op); 2021 return GNUNET_SYSERR;
1462 return;
1463 } 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;
1464 2041
2042 num_hashes = (ntohs (mh->size) - sizeof (struct GNUNET_MessageHeader))
2043 / sizeof (struct GNUNET_HashCode);
1465 for (hash = (const struct GNUNET_HashCode *) &mh[1]; 2044 for (hash = (const struct GNUNET_HashCode *) &mh[1];
1466 num_hashes > 0; 2045 num_hashes > 0;
1467 hash++, num_hashes--) 2046 hash++, num_hashes--)
@@ -1470,7 +2049,7 @@ handle_p2p_offer (void *cls,
1470 struct GNUNET_MessageHeader *demands; 2049 struct GNUNET_MessageHeader *demands;
1471 struct GNUNET_MQ_Envelope *ev; 2050 struct GNUNET_MQ_Envelope *ev;
1472 2051
1473 ee = GNUNET_CONTAINER_multihashmap_get (op->spec->set->content->elements, 2052 ee = GNUNET_CONTAINER_multihashmap_get (op->set->content->elements,
1474 hash); 2053 hash);
1475 if (NULL != ee) 2054 if (NULL != ee)
1476 if (GNUNET_YES == _GSS_is_element_of_operation (ee, op)) 2055 if (GNUNET_YES == _GSS_is_element_of_operation (ee, op))
@@ -1497,9 +2076,12 @@ handle_p2p_offer (void *cls,
1497 ev = GNUNET_MQ_msg_header_extra (demands, 2076 ev = GNUNET_MQ_msg_header_extra (demands,
1498 sizeof (struct GNUNET_HashCode), 2077 sizeof (struct GNUNET_HashCode),
1499 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DEMAND); 2078 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DEMAND);
1500 *(struct GNUNET_HashCode *) &demands[1] = *hash; 2079 GNUNET_memcpy (&demands[1],
2080 hash,
2081 sizeof (struct GNUNET_HashCode));
1501 GNUNET_MQ_send (op->mq, ev); 2082 GNUNET_MQ_send (op->mq, ev);
1502 } 2083 }
2084 GNUNET_CADET_receive_done (op->channel);
1503} 2085}
1504 2086
1505 2087
@@ -1509,16 +2091,22 @@ handle_p2p_offer (void *cls,
1509 * @param cls the union operation 2091 * @param cls the union operation
1510 * @param mh the message 2092 * @param mh the message
1511 */ 2093 */
1512static void 2094void
1513handle_p2p_done (void *cls, 2095handle_union_p2p_done (void *cls,
1514 const struct GNUNET_MessageHeader *mh) 2096 const struct GNUNET_MessageHeader *mh)
1515{ 2097{
1516 struct Operation *op = cls; 2098 struct Operation *op = cls;
1517 2099
1518 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)
1519 { 2107 {
2108 case PHASE_INVENTORY_PASSIVE:
1520 /* 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. */
1521
1522 op->state->phase = PHASE_FINISH_WAITING; 2110 op->state->phase = PHASE_FINISH_WAITING;
1523 2111
1524 LOG (GNUNET_ERROR_TYPE_DEBUG, 2112 LOG (GNUNET_ERROR_TYPE_DEBUG,
@@ -1532,11 +2120,10 @@ handle_p2p_done (void *cls,
1532 * all our demands are satisfied, so that the active 2120 * all our demands are satisfied, so that the active
1533 * peer can quit if we gave him everything. 2121 * peer can quit if we gave him everything.
1534 */ 2122 */
2123 GNUNET_CADET_receive_done (op->channel);
1535 maybe_finish (op); 2124 maybe_finish (op);
1536 return; 2125 return;
1537 } 2126 case PHASE_INVENTORY_ACTIVE:
1538 if (op->state->phase == PHASE_INVENTORY_ACTIVE)
1539 {
1540 LOG (GNUNET_ERROR_TYPE_DEBUG, 2127 LOG (GNUNET_ERROR_TYPE_DEBUG,
1541 "got DONE (as active partner), waiting to finish\n"); 2128 "got DONE (as active partner), waiting to finish\n");
1542 /* All demands of the other peer are satisfied, 2129 /* All demands of the other peer are satisfied,
@@ -1547,11 +2134,14 @@ handle_p2p_done (void *cls,
1547 * to the other peer once our demands are met. 2134 * to the other peer once our demands are met.
1548 */ 2135 */
1549 op->state->phase = PHASE_FINISH_CLOSING; 2136 op->state->phase = PHASE_FINISH_CLOSING;
2137 GNUNET_CADET_receive_done (op->channel);
1550 maybe_finish (op); 2138 maybe_finish (op);
1551 return; 2139 return;
2140 default:
2141 GNUNET_break_op (0);
2142 fail_union_operation (op);
2143 return;
1552 } 2144 }
1553 GNUNET_break_op (0);
1554 fail_union_operation (op);
1555} 2145}
1556 2146
1557 2147
@@ -1562,21 +2152,31 @@ handle_p2p_done (void *cls,
1562 * @param opaque_context message to be transmitted to the listener 2152 * @param opaque_context message to be transmitted to the listener
1563 * to convince him to accept, may be NULL 2153 * to convince him to accept, may be NULL
1564 */ 2154 */
1565static void 2155static struct OperationState *
1566union_evaluate (struct Operation *op, 2156union_evaluate (struct Operation *op,
1567 const struct GNUNET_MessageHeader *opaque_context) 2157 const struct GNUNET_MessageHeader *opaque_context)
1568{ 2158{
2159 struct OperationState *state;
1569 struct GNUNET_MQ_Envelope *ev; 2160 struct GNUNET_MQ_Envelope *ev;
1570 struct OperationRequestMessage *msg; 2161 struct OperationRequestMessage *msg;
1571 2162
1572 GNUNET_assert (NULL == op->state); 2163 ev = GNUNET_MQ_msg_nested_mh (msg,
1573 op->state = GNUNET_new (struct OperationState); 2164 GNUNET_MESSAGE_TYPE_SET_P2P_OPERATION_REQUEST,
1574 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);
1575 /* copy the current generation's strata estimator for this operation */ 2175 /* copy the current generation's strata estimator for this operation */
1576 op->state->se = strata_estimator_dup (op->spec->set->state->se); 2176 state->se = strata_estimator_dup (op->set->state->se);
1577 /* 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 */
1578 op->state->phase = PHASE_EXPECT_SE; 2178 state->phase = PHASE_EXPECT_SE;
1579 op->state->salt_receive = op->state->salt_send = 42; 2179 state->salt_receive = state->salt_send = 42; // FIXME?????
1580 LOG (GNUNET_ERROR_TYPE_DEBUG, 2180 LOG (GNUNET_ERROR_TYPE_DEBUG,
1581 "Initiating union operation evaluation\n"); 2181 "Initiating union operation evaluation\n");
1582 GNUNET_STATISTICS_update (_GSS_statistics, 2182 GNUNET_STATISTICS_update (_GSS_statistics,
@@ -1587,16 +2187,6 @@ union_evaluate (struct Operation *op,
1587 "# of initiated union operations", 2187 "# of initiated union operations",
1588 1, 2188 1,
1589 GNUNET_NO); 2189 GNUNET_NO);
1590 ev = GNUNET_MQ_msg_nested_mh (msg,
1591 GNUNET_MESSAGE_TYPE_SET_P2P_OPERATION_REQUEST,
1592 opaque_context);
1593 if (NULL == ev)
1594 {
1595 /* the context message is too large */
1596 GNUNET_break (0);
1597 GNUNET_SERVER_client_disconnect (op->spec->set->client);
1598 return;
1599 }
1600 msg->operation = htonl (GNUNET_SET_OPERATION_UNION); 2190 msg->operation = htonl (GNUNET_SET_OPERATION_UNION);
1601 GNUNET_MQ_send (op->mq, 2191 GNUNET_MQ_send (op->mq,
1602 ev); 2192 ev);
@@ -1607,6 +2197,11 @@ union_evaluate (struct Operation *op,
1607 else 2197 else
1608 LOG (GNUNET_ERROR_TYPE_DEBUG, 2198 LOG (GNUNET_ERROR_TYPE_DEBUG,
1609 "sent op request without context message\n"); 2199 "sent op request without context message\n");
2200
2201 op->state = state;
2202 initialize_key_to_element (op);
2203 state->initial_size = GNUNET_CONTAINER_multihashmap32_size (state->key_to_element);
2204 return state;
1610} 2205}
1611 2206
1612 2207
@@ -1616,13 +2211,19 @@ union_evaluate (struct Operation *op,
1616 * 2211 *
1617 * @param op operation that will be accepted as a union operation 2212 * @param op operation that will be accepted as a union operation
1618 */ 2213 */
1619static void 2214static struct OperationState *
1620union_accept (struct Operation *op) 2215union_accept (struct Operation *op)
1621{ 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
1622 LOG (GNUNET_ERROR_TYPE_DEBUG, 2225 LOG (GNUNET_ERROR_TYPE_DEBUG,
1623 "accepting set union operation\n"); 2226 "accepting set union operation\n");
1624 GNUNET_assert (NULL == op->state);
1625
1626 GNUNET_STATISTICS_update (_GSS_statistics, 2227 GNUNET_STATISTICS_update (_GSS_statistics,
1627 "# of accepted union operations", 2228 "# of accepted union operations",
1628 1, 2229 1,
@@ -1632,12 +2233,37 @@ union_accept (struct Operation *op)
1632 1, 2233 1,
1633 GNUNET_NO); 2234 GNUNET_NO);
1634 2235
1635 op->state = GNUNET_new (struct OperationState); 2236 state = GNUNET_new (struct OperationState);
1636 op->state->se = strata_estimator_dup (op->spec->set->state->se); 2237 state->se = strata_estimator_dup (op->set->state->se);
1637 op->state->demanded_hashes = GNUNET_CONTAINER_multihashmap_create (32, GNUNET_NO); 2238 state->demanded_hashes = GNUNET_CONTAINER_multihashmap_create (32,
1638 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;
2242 initialize_key_to_element (op);
2243 state->initial_size = GNUNET_CONTAINER_multihashmap32_size (state->key_to_element);
2244
1639 /* kick off the operation */ 2245 /* kick off the operation */
1640 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;
1641} 2267}
1642 2268
1643 2269
@@ -1677,7 +2303,8 @@ union_set_create (void)
1677 * @param ee the element to add to the set 2303 * @param ee the element to add to the set
1678 */ 2304 */
1679static void 2305static void
1680union_add (struct SetState *set_state, struct ElementEntry *ee) 2306union_add (struct SetState *set_state,
2307 struct ElementEntry *ee)
1681{ 2308{
1682 strata_estimator_insert (set_state->se, 2309 strata_estimator_insert (set_state->se,
1683 get_ibf_key (&ee->element_hash)); 2310 get_ibf_key (&ee->element_hash));
@@ -1692,7 +2319,8 @@ union_add (struct SetState *set_state, struct ElementEntry *ee)
1692 * @param ee set element to remove 2319 * @param ee set element to remove
1693 */ 2320 */
1694static void 2321static void
1695union_remove (struct SetState *set_state, struct ElementEntry *ee) 2322union_remove (struct SetState *set_state,
2323 struct ElementEntry *ee)
1696{ 2324{
1697 strata_estimator_remove (set_state->se, 2325 strata_estimator_remove (set_state->se,
1698 get_ibf_key (&ee->element_hash)); 2326 get_ibf_key (&ee->element_hash));
@@ -1717,104 +2345,35 @@ union_set_destroy (struct SetState *set_state)
1717 2345
1718 2346
1719/** 2347/**
1720 * Dispatch messages for a union operation. 2348 * Copy union-specific set state.
1721 * 2349 *
1722 * @param op the state of the union evaluate operation 2350 * @param state source state for copying the union state
1723 * @param mh the received message 2351 * @return a copy of the union-specific set state
1724 * @return #GNUNET_SYSERR if the tunnel should be disconnected,
1725 * #GNUNET_OK otherwise
1726 */ 2352 */
1727int 2353static struct SetState *
1728union_handle_p2p_message (struct Operation *op, 2354union_copy_state (struct SetState *state)
1729 const struct GNUNET_MessageHeader *mh)
1730{ 2355{
1731 //LOG (GNUNET_ERROR_TYPE_DEBUG, 2356 struct SetState *new_state;
1732 // "received p2p message (t: %u, s: %u)\n",
1733 // ntohs (mh->type),
1734 // ntohs (mh->size));
1735 switch (ntohs (mh->type))
1736 {
1737 case GNUNET_MESSAGE_TYPE_SET_UNION_P2P_IBF:
1738 return handle_p2p_ibf (op, mh);
1739 case GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SE:
1740 return handle_p2p_strata_estimator (op, mh, GNUNET_NO);
1741 case GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SEC:
1742 return handle_p2p_strata_estimator (op, mh, GNUNET_YES);
1743 case GNUNET_MESSAGE_TYPE_SET_P2P_ELEMENTS:
1744 handle_p2p_elements (op, mh);
1745 break;
1746 case GNUNET_MESSAGE_TYPE_SET_UNION_P2P_INQUIRY:
1747 handle_p2p_inquiry (op, mh);
1748 break;
1749 case GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DONE:
1750 handle_p2p_done (op, mh);
1751 break;
1752 case GNUNET_MESSAGE_TYPE_SET_UNION_P2P_OFFER:
1753 handle_p2p_offer (op, mh);
1754 break;
1755 case GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DEMAND:
1756 handle_p2p_demand (op, mh);
1757 break;
1758 default:
1759 /* Something wrong with cadet's message handlers? */
1760 GNUNET_assert (0);
1761 }
1762 return GNUNET_OK;
1763}
1764 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);
1765 2362
1766/** 2363 return new_state;
1767 * Handler for peer-disconnects, notifies the client
1768 * about the aborted operation in case the op was not concluded.
1769 *
1770 * @param op the destroyed operation
1771 */
1772static void
1773union_peer_disconnect (struct Operation *op)
1774{
1775 if (PHASE_DONE != op->state->phase)
1776 {
1777 struct GNUNET_MQ_Envelope *ev;
1778 struct GNUNET_SET_ResultMessage *msg;
1779
1780 ev = GNUNET_MQ_msg (msg,
1781 GNUNET_MESSAGE_TYPE_SET_RESULT);
1782 msg->request_id = htonl (op->spec->client_request_id);
1783 msg->result_status = htons (GNUNET_SET_STATUS_FAILURE);
1784 msg->element_type = htons (0);
1785 GNUNET_MQ_send (op->spec->set->client_mq,
1786 ev);
1787 LOG (GNUNET_ERROR_TYPE_WARNING,
1788 "other peer disconnected prematurely, phase %u\n",
1789 op->state->phase);
1790 _GSS_operation_destroy (op,
1791 GNUNET_YES);
1792 return;
1793 }
1794 // else: the session has already been concluded
1795 LOG (GNUNET_ERROR_TYPE_DEBUG,
1796 "other peer disconnected (finished)\n");
1797 if (GNUNET_NO == op->state->client_done_sent)
1798 send_done_and_destroy (op);
1799} 2364}
1800 2365
1801 2366
1802/** 2367/**
1803 * Copy union-specific set state. 2368 * Handle case where channel went down for an operation.
1804 * 2369 *
1805 * @param set source set for copying the union state 2370 * @param op operation that lost the channel
1806 * @return a copy of the union-specific set state
1807 */ 2371 */
1808static struct SetState * 2372static void
1809union_copy_state (struct Set *set) 2373union_channel_death (struct Operation *op)
1810{ 2374{
1811 struct SetState *new_state; 2375 _GSS_operation_destroy (op,
1812 2376 GNUNET_YES);
1813 new_state = GNUNET_new (struct SetState);
1814 GNUNET_assert ( (NULL != set->state) && (NULL != set->state->se) );
1815 new_state->se = strata_estimator_dup (set->state->se);
1816
1817 return new_state;
1818} 2377}
1819 2378
1820 2379
@@ -1829,15 +2388,14 @@ _GSS_union_vt ()
1829{ 2388{
1830 static const struct SetVT union_vt = { 2389 static const struct SetVT union_vt = {
1831 .create = &union_set_create, 2390 .create = &union_set_create,
1832 .msg_handler = &union_handle_p2p_message,
1833 .add = &union_add, 2391 .add = &union_add,
1834 .remove = &union_remove, 2392 .remove = &union_remove,
1835 .destroy_set = &union_set_destroy, 2393 .destroy_set = &union_set_destroy,
1836 .evaluate = &union_evaluate, 2394 .evaluate = &union_evaluate,
1837 .accept = &union_accept, 2395 .accept = &union_accept,
1838 .peer_disconnect = &union_peer_disconnect,
1839 .cancel = &union_op_cancel, 2396 .cancel = &union_op_cancel,
1840 .copy_state = &union_copy_state, 2397 .copy_state = &union_copy_state,
2398 .channel_death = &union_channel_death
1841 }; 2399 };
1842 2400
1843 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..70fafa1e1 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_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_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_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_uint ('k',
268 "hash-num",
269 NULL,
270 gettext_noop ("hash num"),
271 &hash_num),
272
273 GNUNET_GETOPT_option_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 f89817ff5..68f7be690 100644
--- a/src/set/gnunet-set-profiler.c
+++ b/src/set/gnunet-set-profiler.c
@@ -58,6 +58,11 @@ static struct GNUNET_PeerIdentity local_peer;
58 58
59static struct GNUNET_SET_ListenHandle *set_listener; 59static struct GNUNET_SET_ListenHandle *set_listener;
60 60
61static int byzantine;
62static unsigned int force_delta;
63static unsigned int force_full;
64static unsigned int element_size = 32;
65
61/** 66/**
62 * Handle to the statistics service. 67 * Handle to the statistics service.
63 */ 68 */
@@ -86,7 +91,7 @@ map_remove_iterator (void *cls,
86 91
87 GNUNET_assert (NULL != key); 92 GNUNET_assert (NULL != key);
88 93
89 ret = GNUNET_CONTAINER_multihashmap_remove (m, key, NULL); 94 ret = GNUNET_CONTAINER_multihashmap_remove_all (m, key);
90 if (GNUNET_OK != ret) 95 if (GNUNET_OK != ret)
91 printf ("spurious element\n"); 96 printf ("spurious element\n");
92 return GNUNET_YES; 97 return GNUNET_YES;
@@ -158,6 +163,7 @@ check_all_done (void)
158static void 163static void
159set_result_cb (void *cls, 164set_result_cb (void *cls,
160 const struct GNUNET_SET_Element *element, 165 const struct GNUNET_SET_Element *element,
166 uint64_t current_size,
161 enum GNUNET_SET_Status status) 167 enum GNUNET_SET_Status status)
162{ 168{
163 struct SetInfo *info = cls; 169 struct SetInfo *info = cls;
@@ -191,7 +197,7 @@ set_result_cb (void *cls,
191 GNUNET_assert (0); 197 GNUNET_assert (0);
192 } 198 }
193 199
194 if (element->size != sizeof (struct GNUNET_HashCode)) 200 if (element->size != element_size)
195 { 201 {
196 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 202 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
197 "wrong element size: %u, expected %u\n", 203 "wrong element size: %u, expected %u\n",
@@ -203,8 +209,10 @@ set_result_cb (void *cls,
203 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",
204 info->id, GNUNET_h2s (element->data)); 210 info->id, GNUNET_h2s (element->data));
205 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);
206 GNUNET_CONTAINER_multihashmap_put (info->received, 214 GNUNET_CONTAINER_multihashmap_put (info->received,
207 element->data, NULL, 215 &data_hash, NULL,
208 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE); 216 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
209} 217}
210 218
@@ -215,6 +223,10 @@ set_listen_cb (void *cls,
215 const struct GNUNET_MessageHeader *context_msg, 223 const struct GNUNET_MessageHeader *context_msg,
216 struct GNUNET_SET_Request *request) 224 struct GNUNET_SET_Request *request)
217{ 225{
226 /* max. 2 options plus terminator */
227 struct GNUNET_SET_Option opts[3] = {{0}};
228 unsigned int n_opts = 0;
229
218 if (NULL == request) 230 if (NULL == request)
219 { 231 {
220 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 232 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@@ -224,8 +236,24 @@ set_listen_cb (void *cls,
224 GNUNET_assert (NULL == info2.oh); 236 GNUNET_assert (NULL == info2.oh);
225 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 237 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
226 "set listen cb called\n"); 238 "set listen cb called\n");
239 if (byzantine)
240 {
241 opts[n_opts++] = (struct GNUNET_SET_Option) { .type = GNUNET_SET_OPTION_BYZANTINE };
242 }
243 GNUNET_assert (!(force_full && force_delta));
244 if (force_full)
245 {
246 opts[n_opts++] = (struct GNUNET_SET_Option) { .type = GNUNET_SET_OPTION_FORCE_FULL };
247 }
248 if (force_delta)
249 {
250 opts[n_opts++] = (struct GNUNET_SET_Option) { .type = GNUNET_SET_OPTION_FORCE_DELTA };
251 }
252
253 opts[n_opts].type = 0;
227 info2.oh = GNUNET_SET_accept (request, GNUNET_SET_RESULT_SYMMETRIC, 254 info2.oh = GNUNET_SET_accept (request, GNUNET_SET_RESULT_SYMMETRIC,
228 set_result_cb, &info2); 255 opts,
256 set_result_cb, &info2);
229 GNUNET_SET_commit (info2.oh, info2.set); 257 GNUNET_SET_commit (info2.oh, info2.set);
230} 258}
231 259
@@ -236,16 +264,12 @@ set_insert_iterator (void *cls,
236 void *value) 264 void *value)
237{ 265{
238 struct GNUNET_SET_Handle *set = cls; 266 struct GNUNET_SET_Handle *set = cls;
239 struct GNUNET_SET_Element *el; 267 struct GNUNET_SET_Element el;
240 268
241 el = GNUNET_malloc (sizeof (struct GNUNET_SET_Element) + 269 el.element_type = 0;
242 sizeof (struct GNUNET_HashCode)); 270 el.data = value;
243 el->element_type = 0; 271 el.size = element_size;
244 GNUNET_memcpy (&el[1], key, sizeof *key); 272 GNUNET_SET_add_element (set, &el, NULL, NULL);
245 el->data = &el[1];
246 el->size = sizeof *key;
247 GNUNET_SET_add_element (set, el, NULL, NULL);
248 GNUNET_free (el);
249 return GNUNET_YES; 273 return GNUNET_YES;
250} 274}
251 275
@@ -291,9 +315,14 @@ run (void *cls,
291{ 315{
292 unsigned int i; 316 unsigned int i;
293 struct GNUNET_HashCode hash; 317 struct GNUNET_HashCode hash;
318 /* max. 2 options plus terminator */
319 struct GNUNET_SET_Option opts[3] = {{0}};
320 unsigned int n_opts = 0;
294 321
295 config = cfg; 322 config = cfg;
296 323
324 GNUNET_assert (element_size > 0);
325
297 if (GNUNET_OK != GNUNET_CRYPTO_get_peer_identity (cfg, &local_peer)) 326 if (GNUNET_OK != GNUNET_CRYPTO_get_peer_identity (cfg, &local_peer))
298 { 327 {
299 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");
@@ -317,22 +346,28 @@ run (void *cls,
317 346
318 for (i = 0; i < num_a; i++) 347 for (i = 0; i < num_a; i++)
319 { 348 {
320 GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_STRONG, &hash); 349 char *data = GNUNET_malloc (element_size);
321 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,
322 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE); 353 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
323 } 354 }
324 355
325 for (i = 0; i < num_b; i++) 356 for (i = 0; i < num_b; i++)
326 { 357 {
327 GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_STRONG, &hash); 358 char *data = GNUNET_malloc (element_size);
328 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,
329 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE); 362 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
330 } 363 }
331 364
332 for (i = 0; i < num_c; i++) 365 for (i = 0; i < num_c; i++)
333 { 366 {
334 GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_STRONG, &hash); 367 char *data = GNUNET_malloc (element_size);
335 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,
336 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE); 371 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
337 } 372 }
338 373
@@ -350,8 +385,26 @@ run (void *cls,
350 set_listener = GNUNET_SET_listen (config, GNUNET_SET_OPERATION_UNION, 385 set_listener = GNUNET_SET_listen (config, GNUNET_SET_OPERATION_UNION,
351 &app_id, set_listen_cb, NULL); 386 &app_id, set_listen_cb, NULL);
352 387
388
389 if (byzantine)
390 {
391 opts[n_opts++] = (struct GNUNET_SET_Option) { .type = GNUNET_SET_OPTION_BYZANTINE };
392 }
393 GNUNET_assert (!(force_full && force_delta));
394 if (force_full)
395 {
396 opts[n_opts++] = (struct GNUNET_SET_Option) { .type = GNUNET_SET_OPTION_FORCE_FULL };
397 }
398 if (force_delta)
399 {
400 opts[n_opts++] = (struct GNUNET_SET_Option) { .type = GNUNET_SET_OPTION_FORCE_DELTA };
401 }
402
403 opts[n_opts].type = 0;
404
353 info1.oh = GNUNET_SET_prepare (&local_peer, &app_id, NULL, 405 info1.oh = GNUNET_SET_prepare (&local_peer, &app_id, NULL,
354 GNUNET_SET_RESULT_SYMMETRIC, 406 GNUNET_SET_RESULT_SYMMETRIC,
407 opts,
355 set_result_cb, &info1); 408 set_result_cb, &info1);
356 GNUNET_SET_commit (info1.oh, info1.set); 409 GNUNET_SET_commit (info1.oh, info1.set);
357 GNUNET_SET_destroy (info1.set); 410 GNUNET_SET_destroy (info1.set);
@@ -373,22 +426,60 @@ pre_run (void *cls, char *const *args, const char *cfgfile,
373int 426int
374main (int argc, char **argv) 427main (int argc, char **argv)
375{ 428{
376 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 429 struct GNUNET_GETOPT_CommandLineOption options[] = {
377 { 'A', "num-first", NULL, 430 GNUNET_GETOPT_option_uint ('A',
378 gettext_noop ("number of values"), 431 "num-first",
379 GNUNET_YES, &GNUNET_GETOPT_set_uint, &num_a }, 432 NULL,
380 { 'B', "num-second", NULL, 433 gettext_noop ("number of values"),
381 gettext_noop ("number of values"), 434 &num_a),
382 GNUNET_YES, &GNUNET_GETOPT_set_uint, &num_b }, 435
383 { 'C', "num-common", NULL, 436 GNUNET_GETOPT_option_uint ('B',
384 gettext_noop ("number of values"), 437 "num-second",
385 GNUNET_YES, &GNUNET_GETOPT_set_uint, &num_c }, 438 NULL,
386 { 'x', "operation", NULL, 439 gettext_noop ("number of values"),
387 gettext_noop ("operation to execute"), 440 &num_b),
388 GNUNET_YES, &GNUNET_GETOPT_set_string, &op_str }, 441
389 { 's', "statistics", NULL, 442 GNUNET_GETOPT_option_flag ('b',
390 gettext_noop ("write statistics to file"), 443 "byzantine",
391 GNUNET_YES, &GNUNET_GETOPT_set_filename, &statistics_filename }, 444 gettext_noop ("use byzantine mode"),
445 &byzantine),
446
447 GNUNET_GETOPT_option_uint ('f',
448 "force-full",
449 NULL,
450 gettext_noop ("force sending full set"),
451 &force_full),
452
453 GNUNET_GETOPT_option_uint ('d',
454 "force-delta",
455 NULL,
456 gettext_noop ("number delta operation"),
457 &force_delta),
458
459 GNUNET_GETOPT_option_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_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
392 GNUNET_GETOPT_OPTION_END 483 GNUNET_GETOPT_OPTION_END
393 }; 484 };
394 GNUNET_PROGRAM_run2 (argc, argv, "gnunet-set-profiler", 485 GNUNET_PROGRAM_run2 (argc, argv, "gnunet-set-profiler",
diff --git a/src/set/plugin_block_set_test.c b/src/set/plugin_block_set_test.c
new file mode 100644
index 000000000..01b0c8602
--- /dev/null
+++ b/src/set/plugin_block_set_test.c
@@ -0,0 +1,123 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 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 set/plugin_block_set_test.c
23 * @brief set test block, recognizes elements with non-zero first byte as invalid
24 * @author Christian Grothoff
25 */
26
27#include "platform.h"
28#include "gnunet_block_plugin.h"
29#include "gnunet_block_group_lib.h"
30
31
32/**
33 * Function called to validate a reply or a request. For
34 * request evaluation, simply pass "NULL" for the reply_block.
35 *
36 * @param cls closure
37 * @param ctx block context
38 * @param type block type
39 * @param group block group to use
40 * @param eo control flags
41 * @param query original query (hash)
42 * @param xquery extrended query data (can be NULL, depending on type)
43 * @param xquery_size number of bytes in xquery
44 * @param reply_block response to validate
45 * @param reply_block_size number of bytes in reply block
46 * @return characterization of result
47 */
48static enum GNUNET_BLOCK_EvaluationResult
49block_plugin_set_test_evaluate (void *cls,
50 struct GNUNET_BLOCK_Context *ctx,
51 enum GNUNET_BLOCK_Type type,
52 struct GNUNET_BLOCK_Group *group,
53 enum GNUNET_BLOCK_EvaluationOptions eo,
54 const struct GNUNET_HashCode *query,
55 const void *xquery,
56 size_t xquery_size,
57 const void *reply_block,
58 size_t reply_block_size)
59{
60 if ( (NULL == reply_block) ||
61 (reply_block_size == 0) ||
62 (0 != ((char *) reply_block)[0]) )
63 return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
64 return GNUNET_BLOCK_EVALUATION_OK_MORE;
65}
66
67
68/**
69 * Function called to obtain the key for a block.
70 *
71 * @param cls closure
72 * @param type block type
73 * @param block block to get the key for
74 * @param block_size number of bytes in block
75 * @param key set to the key (query) for the given block
76 * @return #GNUNET_OK on success, #GNUNET_SYSERR if type not supported
77 * (or if extracting a key from a block of this type does not work)
78 */
79static int
80block_plugin_set_test_get_key (void *cls,
81 enum GNUNET_BLOCK_Type type,
82 const void *block,
83 size_t block_size,
84 struct GNUNET_HashCode *key)
85{
86 return GNUNET_SYSERR;
87}
88
89
90/**
91 * Entry point for the plugin.
92 */
93void *
94libgnunet_plugin_block_set_test_init (void *cls)
95{
96 static enum GNUNET_BLOCK_Type types[] =
97 {
98 GNUNET_BLOCK_TYPE_SET_TEST,
99 GNUNET_BLOCK_TYPE_ANY /* end of list */
100 };
101 struct GNUNET_BLOCK_PluginFunctions *api;
102
103 api = GNUNET_new (struct GNUNET_BLOCK_PluginFunctions);
104 api->evaluate = &block_plugin_set_test_evaluate;
105 api->get_key = &block_plugin_set_test_get_key;
106 api->types = types;
107 return api;
108}
109
110
111/**
112 * Exit point from the plugin.
113 */
114void *
115libgnunet_plugin_block_set_test_done (void *cls)
116{
117 struct GNUNET_BLOCK_PluginFunctions *api = cls;
118
119 GNUNET_free (api);
120 return NULL;
121}
122
123/* end of plugin_block_set_test.c */
diff --git a/src/set/set.conf.in b/src/set/set.conf.in
index 707bc3575..deaa07efb 100644
--- a/src/set/set.conf.in
+++ b/src/set/set.conf.in
@@ -9,4 +9,4 @@ UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-set.sock
9UNIX_MATCH_UID = YES 9UNIX_MATCH_UID = YES
10UNIX_MATCH_GID = YES 10UNIX_MATCH_GID = YES
11 11
12# PREFIX = valgrind 12#PREFIX = valgrind
diff --git a/src/set/set.h b/src/set/set.h
index f31216cb8..258e2bff9 100644
--- a/src/set/set.h
+++ b/src/set/set.h
@@ -102,6 +102,30 @@ struct GNUNET_SET_AcceptMessage
102 * See `enum GNUNET_SET_ResultMode`. 102 * See `enum GNUNET_SET_ResultMode`.
103 */ 103 */
104 uint32_t result_mode GNUNET_PACKED; 104 uint32_t result_mode GNUNET_PACKED;
105
106 /**
107 * Always use delta operation instead of sending full sets,
108 * even it it's less efficient.
109 */
110 uint8_t force_delta;
111
112 /**
113 * Always send full sets, even if delta operations would
114 * be more efficient.
115 */
116 uint8_t force_full;
117
118 /**
119 * #GNUNET_YES to fail operations where Byzantine faults
120 * are suspected
121 */
122 uint8_t byzantine;
123
124 /**
125 * Lower bound for the set size, used only when
126 * byzantine mode is enabled.
127 */
128 uint8_t byzantine_lower_bound;
105}; 129};
106 130
107 131
@@ -184,6 +208,30 @@ struct GNUNET_SET_EvaluateMessage
184 */ 208 */
185 uint32_t request_id GNUNET_PACKED; 209 uint32_t request_id GNUNET_PACKED;
186 210
211 /**
212 * Always use delta operation instead of sending full sets,
213 * even it it's less efficient.
214 */
215 uint8_t force_delta;
216
217 /**
218 * Always send full sets, even if delta operations would
219 * be more efficient.
220 */
221 uint8_t force_full;
222
223 /**
224 * #GNUNET_YES to fail operations where Byzantine faults
225 * are suspected
226 */
227 uint8_t byzantine;
228
229 /**
230 * Lower bound for the set size, used only when
231 * byzantine mode is enabled.
232 */
233 uint8_t byzantine_lower_bound;
234
187 /* rest: context message, that is, application-specific 235 /* rest: context message, that is, application-specific
188 message to convince listener to pick up */ 236 message to convince listener to pick up */
189}; 237};
@@ -203,6 +251,11 @@ struct GNUNET_SET_ResultMessage
203 struct GNUNET_MessageHeader header; 251 struct GNUNET_MessageHeader header;
204 252
205 /** 253 /**
254 * Current set size.
255 */
256 uint64_t current_size;
257
258 /**
206 * id the result belongs to 259 * id the result belongs to
207 */ 260 */
208 uint32_t request_id GNUNET_PACKED; 261 uint32_t request_id GNUNET_PACKED;
diff --git a/src/set/set_api.c b/src/set/set_api.c
index 7a7267a33..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
@@ -297,9 +299,9 @@ check_iter_element (void *cls,
297 * @param cls the `struct GNUNET_SET_Handle *` 299 * @param cls the `struct GNUNET_SET_Handle *`
298 * @param mh the message 300 * @param mh the message
299 */ 301 */
300 static void 302static void
301 handle_iter_element (void *cls, 303handle_iter_element (void *cls,
302 const struct GNUNET_SET_IterResponseMessage *msg) 304 const struct GNUNET_SET_IterResponseMessage *msg)
303{ 305{
304 struct GNUNET_SET_Handle *set = cls; 306 struct GNUNET_SET_Handle *set = cls;
305 GNUNET_SET_ElementIterator iter = set->iterator; 307 GNUNET_SET_ElementIterator iter = set->iterator;
@@ -308,6 +310,8 @@ check_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);
@@ -432,6 +449,7 @@ do_final:
432 { 449 {
433 oh->result_cb (oh->result_cls, 450 oh->result_cb (oh->result_cls,
434 NULL, 451 NULL,
452 GNUNET_ntohll (msg->current_size),
435 result_status); 453 result_status);
436 } 454 }
437 else 455 else
@@ -453,6 +471,7 @@ do_element:
453 if (NULL != oh->result_cb) 471 if (NULL != oh->result_cb)
454 oh->result_cb (oh->result_cls, 472 oh->result_cb (oh->result_cls,
455 &e, 473 &e,
474 GNUNET_ntohll (msg->current_size),
456 result_status); 475 result_status);
457} 476}
458 477
@@ -498,6 +517,8 @@ GNUNET_SET_operation_cancel (struct GNUNET_SET_OperationHandle *oh)
498 struct GNUNET_SET_CancelMessage *m; 517 struct GNUNET_SET_CancelMessage *m;
499 struct GNUNET_MQ_Envelope *mqm; 518 struct GNUNET_MQ_Envelope *mqm;
500 519
520 LOG (GNUNET_ERROR_TYPE_DEBUG,
521 "Cancelling SET operation\n");
501 if (NULL != set) 522 if (NULL != set)
502 { 523 {
503 mqm = GNUNET_MQ_msg (m, GNUNET_MESSAGE_TYPE_SET_CANCEL); 524 mqm = GNUNET_MQ_msg (m, GNUNET_MESSAGE_TYPE_SET_CANCEL);
@@ -530,7 +551,7 @@ handle_client_set_error (void *cls,
530 struct GNUNET_SET_Handle *set = cls; 551 struct GNUNET_SET_Handle *set = cls;
531 GNUNET_SET_ElementIterator iter = set->iterator; 552 GNUNET_SET_ElementIterator iter = set->iterator;
532 553
533 LOG (GNUNET_ERROR_TYPE_DEBUG, 554 LOG (GNUNET_ERROR_TYPE_ERROR,
534 "Handling client set error %d\n", 555 "Handling client set error %d\n",
535 error); 556 error);
536 while (NULL != set->ops_head) 557 while (NULL != set->ops_head)
@@ -538,24 +559,22 @@ handle_client_set_error (void *cls,
538 if (NULL != set->ops_head->result_cb) 559 if (NULL != set->ops_head->result_cb)
539 set->ops_head->result_cb (set->ops_head->result_cls, 560 set->ops_head->result_cb (set->ops_head->result_cls,
540 NULL, 561 NULL,
562 0,
541 GNUNET_SET_STATUS_FAILURE); 563 GNUNET_SET_STATUS_FAILURE);
542 set_operation_destroy (set->ops_head); 564 set_operation_destroy (set->ops_head);
543 } 565 }
544 set->iterator = NULL; 566 set->iterator = NULL;
545 set->iteration_id++; 567 set->iteration_id++;
568 set->invalid = GNUNET_YES;
546 if (NULL != iter) 569 if (NULL != iter)
547 iter (set->iterator_cls, 570 iter (set->iterator_cls,
548 NULL); 571 NULL);
549 set->invalid = GNUNET_YES;
550 if (GNUNET_YES == set->destroy_requested)
551 {
552 LOG (GNUNET_ERROR_TYPE_DEBUG,
553 "Destroying set after operation failure\n");
554 GNUNET_SET_destroy (set);
555 }
556} 572}
557 573
558 574
575/**
576 * FIXME.
577 */
559static struct GNUNET_SET_Handle * 578static struct GNUNET_SET_Handle *
560create_internal (const struct GNUNET_CONFIGURATION_Handle *cfg, 579create_internal (const struct GNUNET_CONFIGURATION_Handle *cfg,
561 enum GNUNET_SET_OperationType op, 580 enum GNUNET_SET_OperationType op,
@@ -614,7 +633,8 @@ create_internal (const struct GNUNET_CONFIGURATION_Handle *cfg,
614 GNUNET_MESSAGE_TYPE_SET_COPY_LAZY_CONNECT); 633 GNUNET_MESSAGE_TYPE_SET_COPY_LAZY_CONNECT);
615 copy_msg->cookie = *cookie; 634 copy_msg->cookie = *cookie;
616 } 635 }
617 GNUNET_MQ_send (set->mq, mqm); 636 GNUNET_MQ_send (set->mq,
637 mqm);
618 return set; 638 return set;
619} 639}
620 640
@@ -634,7 +654,16 @@ struct GNUNET_SET_Handle *
634GNUNET_SET_create (const struct GNUNET_CONFIGURATION_Handle *cfg, 654GNUNET_SET_create (const struct GNUNET_CONFIGURATION_Handle *cfg,
635 enum GNUNET_SET_OperationType op) 655 enum GNUNET_SET_OperationType op)
636{ 656{
637 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;
638} 667}
639 668
640 669
@@ -660,13 +689,18 @@ GNUNET_SET_add_element (struct GNUNET_SET_Handle *set,
660 struct GNUNET_MQ_Envelope *mqm; 689 struct GNUNET_MQ_Envelope *mqm;
661 struct GNUNET_SET_ElementMessage *msg; 690 struct GNUNET_SET_ElementMessage *msg;
662 691
692 LOG (GNUNET_ERROR_TYPE_INFO,
693 "adding element of type %u to set %p\n",
694 (unsigned int) element->element_type,
695 set);
663 if (GNUNET_YES == set->invalid) 696 if (GNUNET_YES == set->invalid)
664 { 697 {
665 if (NULL != cont) 698 if (NULL != cont)
666 cont (cont_cls); 699 cont (cont_cls);
667 return GNUNET_SYSERR; 700 return GNUNET_SYSERR;
668 } 701 }
669 mqm = GNUNET_MQ_msg_extra (msg, element->size, 702 mqm = GNUNET_MQ_msg_extra (msg,
703 element->size,
670 GNUNET_MESSAGE_TYPE_SET_ADD); 704 GNUNET_MESSAGE_TYPE_SET_ADD);
671 msg->element_type = htons (element->element_type); 705 msg->element_type = htons (element->element_type);
672 GNUNET_memcpy (&msg[1], 706 GNUNET_memcpy (&msg[1],
@@ -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");
@@ -771,13 +809,18 @@ GNUNET_SET_prepare (const struct GNUNET_PeerIdentity *other_peer,
771 const struct GNUNET_HashCode *app_id, 809 const struct GNUNET_HashCode *app_id,
772 const struct GNUNET_MessageHeader *context_msg, 810 const struct GNUNET_MessageHeader *context_msg,
773 enum GNUNET_SET_ResultMode result_mode, 811 enum GNUNET_SET_ResultMode result_mode,
812 struct GNUNET_SET_Option options[],
774 GNUNET_SET_ResultIterator result_cb, 813 GNUNET_SET_ResultIterator result_cb,
775 void *result_cls) 814 void *result_cls)
776{ 815{
777 struct GNUNET_MQ_Envelope *mqm; 816 struct GNUNET_MQ_Envelope *mqm;
778 struct GNUNET_SET_OperationHandle *oh; 817 struct GNUNET_SET_OperationHandle *oh;
779 struct GNUNET_SET_EvaluateMessage *msg; 818 struct GNUNET_SET_EvaluateMessage *msg;
819 struct GNUNET_SET_Option *opt;
780 820
821 LOG (GNUNET_ERROR_TYPE_DEBUG,
822 "Client prepares set operation (%d)\n",
823 result_mode);
781 oh = GNUNET_new (struct GNUNET_SET_OperationHandle); 824 oh = GNUNET_new (struct GNUNET_SET_OperationHandle);
782 oh->result_cb = result_cb; 825 oh->result_cb = result_cb;
783 oh->result_cls = result_cls; 826 oh->result_cls = result_cls;
@@ -787,6 +830,25 @@ GNUNET_SET_prepare (const struct GNUNET_PeerIdentity *other_peer,
787 msg->app_id = *app_id; 830 msg->app_id = *app_id;
788 msg->result_mode = htonl (result_mode); 831 msg->result_mode = htonl (result_mode);
789 msg->target_peer = *other_peer; 832 msg->target_peer = *other_peer;
833 for (opt = options; opt->type != 0; opt++)
834 {
835 switch (opt->type)
836 {
837 case GNUNET_SET_OPTION_BYZANTINE:
838 msg->byzantine = GNUNET_YES;
839 msg->byzantine_lower_bound = opt->v.num;
840 break;
841 case GNUNET_SET_OPTION_FORCE_FULL:
842 msg->force_full = GNUNET_YES;
843 break;
844 case GNUNET_SET_OPTION_FORCE_DELTA:
845 msg->force_delta = GNUNET_YES;
846 break;
847 default:
848 LOG (GNUNET_ERROR_TYPE_ERROR,
849 "Option with type %d not recognized\n", (int) opt->type);
850 }
851 }
790 oh->conclude_mqm = mqm; 852 oh->conclude_mqm = mqm;
791 oh->request_id_addr = &msg->request_id; 853 oh->request_id_addr = &msg->request_id;
792 854
@@ -846,7 +908,8 @@ handle_request (void *cls,
846 struct GNUNET_SET_RejectMessage *rmsg; 908 struct GNUNET_SET_RejectMessage *rmsg;
847 909
848 LOG (GNUNET_ERROR_TYPE_DEBUG, 910 LOG (GNUNET_ERROR_TYPE_DEBUG,
849 "Processing incoming operation request\n"); 911 "Processing incoming operation request with id %u\n",
912 ntohl (msg->accept_id));
850 /* we got another valid request => reset the backoff */ 913 /* we got another valid request => reset the backoff */
851 lh->reconnect_backoff = GNUNET_TIME_UNIT_MILLISECONDS; 914 lh->reconnect_backoff = GNUNET_TIME_UNIT_MILLISECONDS;
852 req.accept_id = ntohl (msg->accept_id); 915 req.accept_id = ntohl (msg->accept_id);
@@ -860,7 +923,8 @@ handle_request (void *cls,
860 if (GNUNET_YES == req.accepted) 923 if (GNUNET_YES == req.accepted)
861 return; /* the accept-case is handled in #GNUNET_SET_accept() */ 924 return; /* the accept-case is handled in #GNUNET_SET_accept() */
862 LOG (GNUNET_ERROR_TYPE_DEBUG, 925 LOG (GNUNET_ERROR_TYPE_DEBUG,
863 "Rejecting request\n"); 926 "Rejected request %u\n",
927 ntohl (msg->accept_id));
864 mqm = GNUNET_MQ_msg (rmsg, 928 mqm = GNUNET_MQ_msg (rmsg,
865 GNUNET_MESSAGE_TYPE_SET_REJECT); 929 GNUNET_MESSAGE_TYPE_SET_REJECT);
866 rmsg->accept_reject_id = msg->accept_id; 930 rmsg->accept_reject_id = msg->accept_id;
@@ -950,6 +1014,9 @@ GNUNET_SET_listen (const struct GNUNET_CONFIGURATION_Handle *cfg,
950{ 1014{
951 struct GNUNET_SET_ListenHandle *lh; 1015 struct GNUNET_SET_ListenHandle *lh;
952 1016
1017 LOG (GNUNET_ERROR_TYPE_DEBUG,
1018 "Starting listener for app %s\n",
1019 GNUNET_h2s (app_id));
953 lh = GNUNET_new (struct GNUNET_SET_ListenHandle); 1020 lh = GNUNET_new (struct GNUNET_SET_ListenHandle);
954 lh->listen_cb = listen_cb; 1021 lh->listen_cb = listen_cb;
955 lh->listen_cls = listen_cls; 1022 lh->listen_cls = listen_cls;
@@ -976,7 +1043,8 @@ void
976GNUNET_SET_listen_cancel (struct GNUNET_SET_ListenHandle *lh) 1043GNUNET_SET_listen_cancel (struct GNUNET_SET_ListenHandle *lh)
977{ 1044{
978 LOG (GNUNET_ERROR_TYPE_DEBUG, 1045 LOG (GNUNET_ERROR_TYPE_DEBUG,
979 "Canceling listener\n"); 1046 "Canceling listener %s\n",
1047 GNUNET_h2s (&lh->app_id));
980 if (NULL != lh->mq) 1048 if (NULL != lh->mq)
981 { 1049 {
982 GNUNET_MQ_destroy (lh->mq); 1050 GNUNET_MQ_destroy (lh->mq);
@@ -1008,6 +1076,7 @@ GNUNET_SET_listen_cancel (struct GNUNET_SET_ListenHandle *lh)
1008struct GNUNET_SET_OperationHandle * 1076struct GNUNET_SET_OperationHandle *
1009GNUNET_SET_accept (struct GNUNET_SET_Request *request, 1077GNUNET_SET_accept (struct GNUNET_SET_Request *request,
1010 enum GNUNET_SET_ResultMode result_mode, 1078 enum GNUNET_SET_ResultMode result_mode,
1079 struct GNUNET_SET_Option options[],
1011 GNUNET_SET_ResultIterator result_cb, 1080 GNUNET_SET_ResultIterator result_cb,
1012 void *result_cls) 1081 void *result_cls)
1013{ 1082{
@@ -1016,8 +1085,13 @@ GNUNET_SET_accept (struct GNUNET_SET_Request *request,
1016 struct GNUNET_SET_AcceptMessage *msg; 1085 struct GNUNET_SET_AcceptMessage *msg;
1017 1086
1018 GNUNET_assert (GNUNET_NO == request->accepted); 1087 GNUNET_assert (GNUNET_NO == request->accepted);
1088 LOG (GNUNET_ERROR_TYPE_DEBUG,
1089 "Client accepts set operation (%d) with id %u\n",
1090 result_mode,
1091 request->accept_id);
1019 request->accepted = GNUNET_YES; 1092 request->accepted = GNUNET_YES;
1020 mqm = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SET_ACCEPT); 1093 mqm = GNUNET_MQ_msg (msg,
1094 GNUNET_MESSAGE_TYPE_SET_ACCEPT);
1021 msg->accept_reject_id = htonl (request->accept_id); 1095 msg->accept_reject_id = htonl (request->accept_id);
1022 msg->result_mode = htonl (result_mode); 1096 msg->result_mode = htonl (result_mode);
1023 oh = GNUNET_new (struct GNUNET_SET_OperationHandle); 1097 oh = GNUNET_new (struct GNUNET_SET_OperationHandle);
@@ -1055,14 +1129,18 @@ GNUNET_SET_commit (struct GNUNET_SET_OperationHandle *oh,
1055 } 1129 }
1056 if (GNUNET_YES == set->invalid) 1130 if (GNUNET_YES == set->invalid)
1057 return GNUNET_SYSERR; 1131 return GNUNET_SYSERR;
1132 LOG (GNUNET_ERROR_TYPE_DEBUG,
1133 "Client commits to SET\n");
1058 GNUNET_assert (NULL != oh->conclude_mqm); 1134 GNUNET_assert (NULL != oh->conclude_mqm);
1059 oh->set = set; 1135 oh->set = set;
1060 GNUNET_CONTAINER_DLL_insert (set->ops_head, 1136 GNUNET_CONTAINER_DLL_insert (set->ops_head,
1061 set->ops_tail, 1137 set->ops_tail,
1062 oh); 1138 oh);
1063 oh->request_id = GNUNET_MQ_assoc_add (set->mq, oh); 1139 oh->request_id = GNUNET_MQ_assoc_add (set->mq,
1140 oh);
1064 *oh->request_id_addr = htonl (oh->request_id); 1141 *oh->request_id_addr = htonl (oh->request_id);
1065 GNUNET_MQ_send (set->mq, oh->conclude_mqm); 1142 GNUNET_MQ_send (set->mq,
1143 oh->conclude_mqm);
1066 oh->conclude_mqm = NULL; 1144 oh->conclude_mqm = NULL;
1067 oh->request_id_addr = NULL; 1145 oh->request_id_addr = NULL;
1068 return GNUNET_OK; 1146 return GNUNET_OK;
@@ -1111,6 +1189,8 @@ GNUNET_SET_copy_lazy (struct GNUNET_SET_Handle *set,
1111 struct GNUNET_MQ_Envelope *ev; 1189 struct GNUNET_MQ_Envelope *ev;
1112 struct SetCopyRequest *req; 1190 struct SetCopyRequest *req;
1113 1191
1192 LOG (GNUNET_ERROR_TYPE_DEBUG,
1193 "Creating lazy copy of set\n");
1114 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);
1115 GNUNET_MQ_send (set->mq, ev); 1195 GNUNET_MQ_send (set->mq, ev);
1116 1196
diff --git a/src/set/test_set.conf b/src/set/test_set.conf
index 69e7f5c52..e28dfc6e9 100644
--- a/src/set/test_set.conf
+++ b/src/set/test_set.conf
@@ -5,7 +5,6 @@ GNUNET_TEST_HOME = /tmp/test-gnunet-set/
5 5
6[set] 6[set]
7AUTOSTART = YES 7AUTOSTART = YES
8# PREFIX = valgrind
9#PREFIX = valgrind --leak-check=full 8#PREFIX = valgrind --leak-check=full
10#PREFIX = gdbserver :1234 9#PREFIX = gdbserver :1234
11OPTIONS = -L INFO 10OPTIONS = -L INFO
diff --git a/src/set/test_set_api.c b/src/set/test_set_api.c
index 21af45f8a..ca7d8a4e2 100644
--- a/src/set/test_set_api.c
+++ b/src/set/test_set_api.c
@@ -55,6 +55,7 @@ static struct GNUNET_SCHEDULER_Task *tt;
55static void 55static void
56result_cb_set1 (void *cls, 56result_cb_set1 (void *cls,
57 const struct GNUNET_SET_Element *element, 57 const struct GNUNET_SET_Element *element,
58 uint64_t size,
58 enum GNUNET_SET_Status status) 59 enum GNUNET_SET_Status status)
59{ 60{
60 switch (status) 61 switch (status)
@@ -101,6 +102,7 @@ result_cb_set1 (void *cls,
101static void 102static void
102result_cb_set2 (void *cls, 103result_cb_set2 (void *cls,
103 const struct GNUNET_SET_Element *element, 104 const struct GNUNET_SET_Element *element,
105 uint64_t size,
104 enum GNUNET_SET_Status status) 106 enum GNUNET_SET_Status status)
105{ 107{
106 switch (status) 108 switch (status)
@@ -114,6 +116,7 @@ result_cb_set2 (void *cls,
114 oh2 = NULL; 116 oh2 = NULL;
115 fprintf (stderr, 117 fprintf (stderr,
116 "set 2: received failure status\n"); 118 "set 2: received failure status\n");
119 GNUNET_SCHEDULER_shutdown ();
117 ret = 1; 120 ret = 1;
118 break; 121 break;
119 case GNUNET_SET_STATUS_DONE: 122 case GNUNET_SET_STATUS_DONE:
@@ -145,10 +148,9 @@ listen_cb (void *cls,
145 GNUNET_assert (ntohs (context_msg->type) == GNUNET_MESSAGE_TYPE_DUMMY); 148 GNUNET_assert (ntohs (context_msg->type) == GNUNET_MESSAGE_TYPE_DUMMY);
146 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 149 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
147 "listen cb called\n"); 150 "listen cb called\n");
148 GNUNET_SET_listen_cancel (listen_handle);
149 listen_handle = NULL;
150 oh2 = GNUNET_SET_accept (request, 151 oh2 = GNUNET_SET_accept (request,
151 GNUNET_SET_RESULT_ADDED, 152 GNUNET_SET_RESULT_ADDED,
153 (struct GNUNET_SET_Option[]) { 0 },
152 &result_cb_set2, 154 &result_cb_set2,
153 NULL); 155 NULL);
154 GNUNET_SET_commit (oh2, 156 GNUNET_SET_commit (oh2,
@@ -179,6 +181,7 @@ start (void *cls)
179 &app_id, 181 &app_id,
180 &context_msg, 182 &context_msg,
181 GNUNET_SET_RESULT_ADDED, 183 GNUNET_SET_RESULT_ADDED,
184 (struct GNUNET_SET_Option[]) { 0 },
182 &result_cb_set1, 185 &result_cb_set1,
183 NULL); 186 NULL);
184 GNUNET_SET_commit (oh1, 187 GNUNET_SET_commit (oh1,
@@ -196,19 +199,25 @@ init_set2 (void *cls)
196{ 199{
197 struct GNUNET_SET_Element element; 200 struct GNUNET_SET_Element element;
198 201
199 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "initializing set 2\n"); 202 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
203 "initializing set 2\n");
200 204
201 element.element_type = 0; 205 element.element_type = 0;
202
203 element.data = "hello"; 206 element.data = "hello";
204 element.size = strlen(element.data); 207 element.size = strlen(element.data);
205 GNUNET_SET_add_element (set2, &element, NULL, NULL); 208 GNUNET_SET_add_element (set2,
209 &element,
210 NULL, NULL);
206 element.data = "quux"; 211 element.data = "quux";
207 element.size = strlen(element.data); 212 element.size = strlen(element.data);
208 GNUNET_SET_add_element (set2, &element, NULL, NULL); 213 GNUNET_SET_add_element (set2,
214 &element,
215 NULL, NULL);
209 element.data = "baz"; 216 element.data = "baz";
210 element.size = strlen(element.data); 217 element.size = strlen(element.data);
211 GNUNET_SET_add_element (set2, &element, &start, NULL); 218 GNUNET_SET_add_element (set2,
219 &element,
220 &start, NULL);
212} 221}
213 222
214 223
@@ -221,14 +230,17 @@ init_set1 (void)
221 struct GNUNET_SET_Element element; 230 struct GNUNET_SET_Element element;
222 231
223 element.element_type = 0; 232 element.element_type = 0;
224
225 element.data = "hello"; 233 element.data = "hello";
226 element.size = strlen(element.data); 234 element.size = strlen(element.data);
227 GNUNET_SET_add_element (set1, &element, NULL, NULL); 235 GNUNET_SET_add_element (set1,
236 &element,
237 NULL, NULL);
228 element.data = "bar"; 238 element.data = "bar";
229 element.size = strlen(element.data); 239 element.size = strlen(element.data);
230 GNUNET_SET_add_element (set1, &element, init_set2, NULL); 240 GNUNET_SET_add_element (set1,
231 241 &element,
242 &init_set2,
243 NULL);
232 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 244 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
233 "initialized set 1\n"); 245 "initialized set 1\n");
234} 246}
@@ -238,10 +250,15 @@ static int
238iter_cb (void *cls, 250iter_cb (void *cls,
239 const struct GNUNET_SET_Element *element) 251 const struct GNUNET_SET_Element *element)
240{ 252{
253 struct GNUNET_SET_Handle *set = cls;
254
241 if (NULL == element) 255 if (NULL == element)
242 { 256 {
243 GNUNET_assert (3 == iter_count); 257 GNUNET_assert (3 == iter_count);
244 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);
245 return GNUNET_YES; 262 return GNUNET_YES;
246 } 263 }
247 iter_count++; 264 iter_count++;
@@ -258,21 +275,31 @@ test_iter ()
258 struct GNUNET_SET_Element element; 275 struct GNUNET_SET_Element element;
259 struct GNUNET_SET_Handle *iter_set; 276 struct GNUNET_SET_Handle *iter_set;
260 277
261 iter_set = GNUNET_SET_create (config, GNUNET_SET_OPERATION_UNION); 278 iter_set = GNUNET_SET_create (config,
262 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);
263 element.element_type = 0; 283 element.element_type = 0;
264 284
265 element.data = "hello"; 285 element.data = "hello";
266 element.size = strlen(element.data); 286 element.size = strlen(element.data);
267 GNUNET_SET_add_element (iter_set, &element, NULL, NULL); 287 GNUNET_SET_add_element (iter_set,
288 &element,
289 NULL, NULL);
268 element.data = "bar"; 290 element.data = "bar";
269 element.size = strlen(element.data); 291 element.size = strlen(element.data);
270 GNUNET_SET_add_element (iter_set, &element, NULL, NULL); 292 GNUNET_SET_add_element (iter_set,
293 &element,
294 NULL, NULL);
271 element.data = "quux"; 295 element.data = "quux";
272 element.size = strlen(element.data); 296 element.size = strlen(element.data);
273 GNUNET_SET_add_element (iter_set, &element, NULL, NULL); 297 GNUNET_SET_add_element (iter_set,
274 298 &element,
275 GNUNET_SET_iterate (iter_set, iter_cb, iter_set); 299 NULL, NULL);
300 GNUNET_SET_iterate (iter_set,
301 &iter_cb,
302 iter_set);
276} 303}
277 304
278 305
@@ -368,19 +395,27 @@ run (void *cls,
368 GNUNET_i2s (&local_id)); 395 GNUNET_i2s (&local_id));
369 test_iter (); 396 test_iter ();
370 397
371 set1 = GNUNET_SET_create (cfg, GNUNET_SET_OPERATION_UNION); 398 set1 = GNUNET_SET_create (cfg,
372 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);
373 GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, 406 GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK,
374 &app_id); 407 &app_id);
375 408
376 ///* 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");
377 my_oh = GNUNET_SET_prepare (&local_id, 412 my_oh = GNUNET_SET_prepare (&local_id,
378 &app_id, 413 &app_id,
379 NULL, 414 NULL,
380 GNUNET_SET_RESULT_ADDED, 415 GNUNET_SET_RESULT_ADDED,
416 (struct GNUNET_SET_Option[]) { 0 },
381 NULL, 417 NULL,
382 NULL); 418 NULL);
383
384 GNUNET_SET_operation_cancel (my_oh); 419 GNUNET_SET_operation_cancel (my_oh);
385 420
386 /* test the real set reconciliation */ 421 /* test the real set reconciliation */
diff --git a/src/set/test_set_intersection_result_full.c b/src/set/test_set_intersection_result_full.c
index f78a03eaf..a36aae4d5 100644
--- a/src/set/test_set_intersection_result_full.c
+++ b/src/set/test_set_intersection_result_full.c
@@ -56,10 +56,14 @@ static struct GNUNET_SET_OperationHandle *oh2;
56static void 56static void
57result_cb_set1 (void *cls, 57result_cb_set1 (void *cls,
58 const struct GNUNET_SET_Element *element, 58 const struct GNUNET_SET_Element *element,
59 uint64_t current_size,
59 enum GNUNET_SET_Status status) 60 enum GNUNET_SET_Status status)
60{ 61{
61 static int count; 62 static int count;
62 63
64 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
65 "Processing result set 1 (%d)\n",
66 status);
63 switch (status) 67 switch (status)
64 { 68 {
65 case GNUNET_SET_STATUS_OK: 69 case GNUNET_SET_STATUS_OK:
@@ -74,6 +78,8 @@ result_cb_set1 (void *cls,
74 GNUNET_assert (1 == count); 78 GNUNET_assert (1 == count);
75 GNUNET_SET_destroy (set1); 79 GNUNET_SET_destroy (set1);
76 set1 = NULL; 80 set1 = NULL;
81 if (NULL == set2)
82 GNUNET_SCHEDULER_shutdown ();
77 break; 83 break;
78 default: 84 default:
79 GNUNET_assert (0); 85 GNUNET_assert (0);
@@ -84,10 +90,14 @@ result_cb_set1 (void *cls,
84static void 90static void
85result_cb_set2 (void *cls, 91result_cb_set2 (void *cls,
86 const struct GNUNET_SET_Element *element, 92 const struct GNUNET_SET_Element *element,
93 uint64_t current_size,
87 enum GNUNET_SET_Status status) 94 enum GNUNET_SET_Status status)
88{ 95{
89 static int count; 96 static int count;
90 97
98 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
99 "Processing result set 2 (%d)\n",
100 status);
91 switch (status) 101 switch (status)
92 { 102 {
93 case GNUNET_SET_STATUS_OK: 103 case GNUNET_SET_STATUS_OK:
@@ -102,6 +112,8 @@ result_cb_set2 (void *cls,
102 GNUNET_assert (1 == count); 112 GNUNET_assert (1 == count);
103 GNUNET_SET_destroy (set2); 113 GNUNET_SET_destroy (set2);
104 set2 = NULL; 114 set2 = NULL;
115 if (NULL == set1)
116 GNUNET_SCHEDULER_shutdown ();
105 break; 117 break;
106 default: 118 default:
107 GNUNET_assert (0); 119 GNUNET_assert (0);
@@ -115,14 +127,17 @@ listen_cb (void *cls,
115 const struct GNUNET_MessageHeader *context_msg, 127 const struct GNUNET_MessageHeader *context_msg,
116 struct GNUNET_SET_Request *request) 128 struct GNUNET_SET_Request *request)
117{ 129{
130 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
131 "starting intersection by accepting and committing\n");
118 GNUNET_assert (NULL != context_msg); 132 GNUNET_assert (NULL != context_msg);
119 GNUNET_assert (ntohs (context_msg->type) == GNUNET_MESSAGE_TYPE_DUMMY); 133 GNUNET_assert (ntohs (context_msg->type) == GNUNET_MESSAGE_TYPE_DUMMY);
120 GNUNET_SET_listen_cancel (listen_handle); 134 GNUNET_SET_listen_cancel (listen_handle);
121 listen_handle = NULL; 135 listen_handle = NULL;
122 oh2 = GNUNET_SET_accept (request, 136 oh2 = GNUNET_SET_accept (request,
123 GNUNET_SET_RESULT_FULL, 137 GNUNET_SET_RESULT_FULL,
124 &result_cb_set2, 138 (struct GNUNET_SET_Option[]) { 0 },
125 NULL); 139 &result_cb_set2,
140 NULL);
126 GNUNET_SET_commit (oh2, 141 GNUNET_SET_commit (oh2,
127 set2); 142 set2);
128} 143}
@@ -138,17 +153,21 @@ start (void *cls)
138{ 153{
139 struct GNUNET_MessageHeader context_msg; 154 struct GNUNET_MessageHeader context_msg;
140 155
156 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
157 "starting listener\n");
141 context_msg.size = htons (sizeof context_msg); 158 context_msg.size = htons (sizeof context_msg);
142 context_msg.type = htons (GNUNET_MESSAGE_TYPE_DUMMY); 159 context_msg.type = htons (GNUNET_MESSAGE_TYPE_DUMMY);
143 listen_handle = GNUNET_SET_listen (config, 160 listen_handle = GNUNET_SET_listen (config,
144 GNUNET_SET_OPERATION_INTERSECTION, 161 GNUNET_SET_OPERATION_INTERSECTION,
145 &app_id, 162 &app_id,
146 &listen_cb, NULL); 163 &listen_cb,
164 NULL);
147 oh1 = GNUNET_SET_prepare (&local_id, 165 oh1 = GNUNET_SET_prepare (&local_id,
148 &app_id, 166 &app_id,
149 &context_msg, 167 &context_msg,
150 GNUNET_SET_RESULT_FULL, 168 GNUNET_SET_RESULT_FULL,
151 &result_cb_set1, 169 (struct GNUNET_SET_Option[]) { 0 },
170 &result_cb_set1,
152 NULL); 171 NULL);
153 GNUNET_SET_commit (oh1, 172 GNUNET_SET_commit (oh1,
154 set1); 173 set1);
@@ -170,13 +189,22 @@ init_set2 (void *cls)
170 element.element_type = 0; 189 element.element_type = 0;
171 element.data = "hello"; 190 element.data = "hello";
172 element.size = strlen(element.data); 191 element.size = strlen(element.data);
173 GNUNET_SET_add_element (set2, &element, NULL, NULL); 192 GNUNET_SET_add_element (set2,
193 &element,
194 NULL,
195 NULL);
174 element.data = "quux"; 196 element.data = "quux";
175 element.size = strlen(element.data); 197 element.size = strlen(element.data);
176 GNUNET_SET_add_element (set2, &element, NULL, NULL); 198 GNUNET_SET_add_element (set2,
199 &element,
200 NULL,
201 NULL);
177 element.data = "baz"; 202 element.data = "baz";
178 element.size = strlen(element.data); 203 element.size = strlen(element.data);
179 GNUNET_SET_add_element (set2, &element, &start, NULL); 204 GNUNET_SET_add_element (set2,
205 &element,
206 &start,
207 NULL);
180} 208}
181 209
182 210
@@ -188,13 +216,21 @@ init_set1 (void)
188{ 216{
189 struct GNUNET_SET_Element element; 217 struct GNUNET_SET_Element element;
190 218
219 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
220 "initializing set 1\n");
191 element.element_type = 0; 221 element.element_type = 0;
192 element.data = "hello"; 222 element.data = "hello";
193 element.size = strlen(element.data); 223 element.size = strlen(element.data);
194 GNUNET_SET_add_element (set1, &element, NULL, NULL); 224 GNUNET_SET_add_element (set1,
225 &element,
226 NULL,
227 NULL);
195 element.data = "bar"; 228 element.data = "bar";
196 element.size = strlen(element.data); 229 element.size = strlen(element.data);
197 GNUNET_SET_add_element (set1, &element, &init_set2, NULL); 230 GNUNET_SET_add_element (set1,
231 &element,
232 &init_set2,
233 NULL);
198} 234}
199 235
200 236
@@ -219,17 +255,27 @@ test_iter ()
219 struct GNUNET_SET_Element element; 255 struct GNUNET_SET_Element element;
220 struct GNUNET_SET_Handle *iter_set; 256 struct GNUNET_SET_Handle *iter_set;
221 257
222 iter_set = GNUNET_SET_create (config, GNUNET_SET_OPERATION_INTERSECTION); 258 iter_set = GNUNET_SET_create (config,
259 GNUNET_SET_OPERATION_INTERSECTION);
223 element.element_type = 0; 260 element.element_type = 0;
224 element.data = "hello"; 261 element.data = "hello";
225 element.size = strlen(element.data); 262 element.size = strlen(element.data);
226 GNUNET_SET_add_element (iter_set, &element, NULL, NULL); 263 GNUNET_SET_add_element (iter_set,
264 &element,
265 NULL,
266 NULL);
227 element.data = "bar"; 267 element.data = "bar";
228 element.size = strlen(element.data); 268 element.size = strlen(element.data);
229 GNUNET_SET_add_element (iter_set, &element, NULL, NULL); 269 GNUNET_SET_add_element (iter_set,
270 &element,
271 NULL,
272 NULL);
230 element.data = "quux"; 273 element.data = "quux";
231 element.size = strlen(element.data); 274 element.size = strlen(element.data);
232 GNUNET_SET_add_element (iter_set, &element, NULL, NULL); 275 GNUNET_SET_add_element (iter_set,
276 &element,
277 NULL,
278 NULL);
233 GNUNET_SET_iterate (iter_set, 279 GNUNET_SET_iterate (iter_set,
234 &iter_cb, 280 &iter_cb,
235 iter_set); 281 iter_set);
@@ -307,8 +353,10 @@ run (void *cls,
307 struct GNUNET_TESTING_Peer *peer) 353 struct GNUNET_TESTING_Peer *peer)
308{ 354{
309 config = cfg; 355 config = cfg;
310 GNUNET_TESTING_peer_get_identity (peer, &local_id); 356 GNUNET_TESTING_peer_get_identity (peer,
311 if (0) test_iter (); 357 &local_id);
358 if (0)
359 test_iter ();
312 360
313 tt = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5), 361 tt = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5),
314 &timeout_fail, 362 &timeout_fail,
@@ -316,8 +364,10 @@ run (void *cls,
316 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, 364 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
317 NULL); 365 NULL);
318 366
319 set1 = GNUNET_SET_create (cfg, GNUNET_SET_OPERATION_INTERSECTION); 367 set1 = GNUNET_SET_create (cfg,
320 set2 = GNUNET_SET_create (cfg, GNUNET_SET_OPERATION_INTERSECTION); 368 GNUNET_SET_OPERATION_INTERSECTION);
369 set2 = GNUNET_SET_create (cfg,
370 GNUNET_SET_OPERATION_INTERSECTION);
321 GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, 371 GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK,
322 &app_id); 372 &app_id);
323 373
@@ -327,9 +377,10 @@ run (void *cls,
327 377
328 378
329int 379int
330main (int argc, char **argv) 380main (int argc,
381 char **argv)
331{ 382{
332 if (0 != GNUNET_TESTING_peer_run ("test_set_api", 383 if (0 != GNUNET_TESTING_peer_run ("test_set_intersection_result_full",
333 "test_set.conf", 384 "test_set.conf",
334 &run, NULL)) 385 &run, NULL))
335 return 1; 386 return 1;
diff --git a/src/set/test_set_union_copy.c b/src/set/test_set_union_copy.c
index 6fd78d43a..242b9f2f2 100644
--- a/src/set/test_set_union_copy.c
+++ b/src/set/test_set_union_copy.c
@@ -115,15 +115,23 @@ check_count_iter (void *cls,
115 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 115 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
116 "Expected count (what: %s) to be %u, but it's actually %u\n", 116 "Expected count (what: %s) to be %u, but it's actually %u\n",
117 ci_cls->what, 117 ci_cls->what,
118 ci_cls->expected_count, ci_cls->ongoing_count); 118 ci_cls->expected_count,
119 ci_cls->ongoing_count);
119 ret = 1; 120 ret = 1;
121 GNUNET_SCHEDULER_shutdown ();
120 return GNUNET_NO; 122 return GNUNET_NO;
121 } 123 }
122 ci_cls->cont (ci_cls->cont_cls); 124 ci_cls->cont (ci_cls->cont_cls);
125 GNUNET_free (ci_cls);
123 return GNUNET_NO; 126 return GNUNET_NO;
124 } 127 }
128 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
129 "Set `%s' has element %.*s\n",
130 ci_cls->what,
131 (int) element->size,
132 (const char *) element->data);
125 133
126 ci_cls->ongoing_count += 1; 134 ci_cls->ongoing_count++;
127 return GNUNET_YES; 135 return GNUNET_YES;
128} 136}
129 137
@@ -137,6 +145,10 @@ check_count (struct GNUNET_SET_Handle *set,
137{ 145{
138 struct CountIterClosure *ci_cls = GNUNET_new (struct CountIterClosure); 146 struct CountIterClosure *ci_cls = GNUNET_new (struct CountIterClosure);
139 147
148 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
149 "Checking count of %s\n",
150 what);
151
140 ci_cls->expected_count = expected_count; 152 ci_cls->expected_count = expected_count;
141 ci_cls->ongoing_count = 0; 153 ci_cls->ongoing_count = 0;
142 ci_cls->cont = cont; 154 ci_cls->cont = cont;
@@ -162,7 +174,7 @@ check_new_set_count (void *cls)
162{ 174{
163 check_count (set2, 175 check_count (set2,
164 "new set", 176 "new set",
165 4, 177 3,
166 &test_done, 178 &test_done,
167 NULL); 179 NULL);
168} 180}
@@ -172,15 +184,23 @@ static void
172copy_done (void *cls, 184copy_done (void *cls,
173 struct GNUNET_SET_Handle *new_set) 185 struct GNUNET_SET_Handle *new_set)
174{ 186{
175 printf ("copy done\n"); 187 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
188 "copy done\n");
176 set2 = new_set; 189 set2 = new_set;
177 remove_element_str (set2, "spam"); 190 remove_element_str (set2,
178 add_element_str (set2, "new1"); 191 "k5555");
179 add_element_str (set2, "new2"); 192 add_element_str (set2,
180 remove_element_str (set2, "new2"); 193 "n66666");
181 remove_element_str (set2, "new3"); 194 add_element_str (set2,
195 "new2butremoved");
196 remove_element_str (set2,
197 "new2butremoved");
198 remove_element_str (set2,
199 "new3justremoved");
182 // Check that set1 didn't change. 200 // Check that set1 didn't change.
183 check_count (set1, "old set", 3, 201 check_count (set1,
202 "old set",
203 3,
184 &check_new_set_count, 204 &check_new_set_count,
185 NULL); 205 NULL);
186} 206}
@@ -189,7 +209,8 @@ copy_done (void *cls,
189static void 209static void
190test_copy (void *cls) 210test_copy (void *cls)
191{ 211{
192 printf ("about to copy\n"); 212 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
213 "about to copy\n");
193 GNUNET_SET_copy_lazy (set1, 214 GNUNET_SET_copy_lazy (set1,
194 &copy_done, 215 &copy_done,
195 NULL); 216 NULL);
@@ -244,18 +265,27 @@ run (void *cls,
244 GNUNET_TESTING_peer_get_identity (peer, 265 GNUNET_TESTING_peer_get_identity (peer,
245 &local_id); 266 &local_id);
246 267
247 set1 = GNUNET_SET_create (cfg, GNUNET_SET_OPERATION_UNION); 268 set1 = GNUNET_SET_create (cfg,
248 add_element_str (set1, "foo"); 269 GNUNET_SET_OPERATION_UNION);
249 add_element_str (set1, "bar"); 270 add_element_str (set1,
271 "333");
272 add_element_str (set1,
273 "k444");
250 /* duplicate -- ignored */ 274 /* duplicate -- ignored */
251 add_element_str (set1, "bar"); 275 add_element_str (set1,
252 remove_element_str (set1, "foo"); 276 "k444");
277 remove_element_str (set1,
278 "333");
253 /* non-existent -- ignored */ 279 /* non-existent -- ignored */
254 remove_element_str (set1, "nonexist1"); 280 remove_element_str (set1,
255 add_element_str (set1, "spam"); 281 "999999999");
282 add_element_str (set1,
283 "k5555");
256 /* duplicate -- ignored */ 284 /* duplicate -- ignored */
257 remove_element_str (set1, "foo"); 285 remove_element_str (set1,
258 add_element_str (set1, "eggs"); 286 "333");
287 add_element_str (set1,
288 "k2");
259 289
260 check_count (set1, 290 check_count (set1,
261 "initial test", 291 "initial test",
diff --git a/src/set/test_set_union_result_symmetric.c b/src/set/test_set_union_result_symmetric.c
index ab191a34a..f81c7b8f7 100644
--- a/src/set/test_set_union_result_symmetric.c
+++ b/src/set/test_set_union_result_symmetric.c
@@ -77,6 +77,7 @@ static struct GNUNET_SCHEDULER_Task *timeout_task;
77static void 77static void
78result_cb_set1 (void *cls, 78result_cb_set1 (void *cls,
79 const struct GNUNET_SET_Element *element, 79 const struct GNUNET_SET_Element *element,
80 uint64_t current_size,
80 enum GNUNET_SET_Status status) 81 enum GNUNET_SET_Status status)
81{ 82{
82 switch (status) 83 switch (status)
@@ -125,6 +126,7 @@ result_cb_set1 (void *cls,
125static void 126static void
126result_cb_set2 (void *cls, 127result_cb_set2 (void *cls,
127 const struct GNUNET_SET_Element *element, 128 const struct GNUNET_SET_Element *element,
129 uint64_t current_size,
128 enum GNUNET_SET_Status status) 130 enum GNUNET_SET_Status status)
129{ 131{
130 switch (status) 132 switch (status)
@@ -184,6 +186,7 @@ listen_cb (void *cls,
184 listen_handle = NULL; 186 listen_handle = NULL;
185 oh2 = GNUNET_SET_accept (request, 187 oh2 = GNUNET_SET_accept (request,
186 GNUNET_SET_RESULT_SYMMETRIC, 188 GNUNET_SET_RESULT_SYMMETRIC,
189 (struct GNUNET_SET_Option[]) { 0 },
187 &result_cb_set2, 190 &result_cb_set2,
188 NULL); 191 NULL);
189 GNUNET_SET_commit (oh2, 192 GNUNET_SET_commit (oh2,
@@ -212,6 +215,7 @@ start (void *cls)
212 &app_id, 215 &app_id,
213 &context_msg, 216 &context_msg,
214 GNUNET_SET_RESULT_SYMMETRIC, 217 GNUNET_SET_RESULT_SYMMETRIC,
218 (struct GNUNET_SET_Option[]) { 0 },
215 &result_cb_set1, NULL); 219 &result_cb_set1, NULL);
216 GNUNET_SET_commit (oh1, set1); 220 GNUNET_SET_commit (oh1, set1);
217} 221}
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/Makefile.am b/src/social/Makefile.am
index 693a61411..94a9ba108 100644
--- a/src/social/Makefile.am
+++ b/src/social/Makefile.am
@@ -62,7 +62,7 @@ check_PROGRAMS = \
62endif 62endif
63 63
64if ENABLE_TEST_RUN 64if ENABLE_TEST_RUN
65AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; 65AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
66TESTS = $(check_PROGRAMS) 66TESTS = $(check_PROGRAMS)
67endif 67endif
68 68
diff --git a/src/social/gnunet-service-social.c b/src/social/gnunet-service-social.c
index e6ee24a4f..dee68fdb8 100644
--- a/src/social/gnunet-service-social.c
+++ b/src/social/gnunet-service-social.c
@@ -1955,9 +1955,11 @@ handle_client_guest_enter_by_name (void *cls,
1955 GNUNET_memcpy (gcls->password, password, password_size); 1955 GNUNET_memcpy (gcls->password, password, password_size);
1956 } 1956 }
1957 1957
1958 GNUNET_GNS_lookup (gns, gns_name, &greq->ego_pub_key, 1958 GNUNET_GNS_lookup (gns, gns_name,
1959 GNUNET_GNSRECORD_TYPE_PLACE, GNUNET_GNS_LO_DEFAULT, 1959 &greq->ego_pub_key,
1960 NULL, gns_result_guest_enter, gcls); 1960 GNUNET_GNSRECORD_TYPE_PLACE,
1961 GNUNET_GNS_LO_DEFAULT,
1962 &gns_result_guest_enter, gcls);
1961} 1963}
1962 1964
1963 1965
diff --git a/src/social/gnunet-social.c b/src/social/gnunet-social.c
index 6d72ca552..228d69d58 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 */
@@ -154,6 +154,8 @@ struct GNUNET_SOCIAL_Host *hst;
154struct GNUNET_SOCIAL_Guest *gst; 154struct GNUNET_SOCIAL_Guest *gst;
155struct GNUNET_SOCIAL_Place *plc; 155struct GNUNET_SOCIAL_Place *plc;
156 156
157const char *method_received;
158
157 159
158/* DISCONNECT */ 160/* DISCONNECT */
159 161
@@ -308,7 +310,7 @@ static void
308guest_left (void *cls) 310guest_left (void *cls)
309{ 311{
310 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 312 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
311 "The guest has left the place.\n"); 313 "Guest has left the place.\n");
312} 314}
313 315
314 316
@@ -555,10 +557,15 @@ slicer_recv_method (void *cls,
555 uint64_t message_id, 557 uint64_t message_id,
556 const char *method_name) 558 const char *method_name)
557{ 559{
560 method_received = method_name;
558 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 561 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
559 "Received method for message ID %" PRIu64 ":\n" 562 "Received method for message ID %" PRIu64 ":\n"
560 "%s (flags: %x)\n", 563 "%s (flags: %x)\n",
561 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 */
566 printf("\n");
567 /* we output . instead of | to indicate that this is not proper PSYC syntax */
568 /* FIXME: use libpsyc here */
562} 569}
563 570
564 571
@@ -576,10 +583,16 @@ slicer_recv_modifier (void *cls,
576 uint16_t value_size, 583 uint16_t value_size,
577 uint16_t full_value_size) 584 uint16_t full_value_size)
578{ 585{
586#if 0
579 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 587 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
580 "Received modifier for message ID %" PRIu64 ":\n" 588 "Received modifier for message ID %" PRIu64 ":\n"
581 "%c%s: %.*s (size: %u)\n", 589 "%c%s: %.*s (size: %u)\n",
582 message_id, oper, name, value_size, (const char *) value, value_size); 590 message_id, oper, name, value_size, (const char *) value, value_size);
591#else
592 /* obviously not binary safe */
593 printf("%c%s\t%.*s\n",
594 oper, name, value_size, (const char *) value);
595#endif
583} 596}
584 597
585 598
@@ -594,10 +607,16 @@ slicer_recv_data (void *cls,
594 const void *data, 607 const void *data,
595 uint16_t data_size) 608 uint16_t data_size)
596{ 609{
610#if 0
597 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 611 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
598 "Received data for message ID %" PRIu64 ":\n" 612 "Received data for message ID %" PRIu64 ":\n"
599 "%.*s\n", 613 "%.*s\n",
600 message_id, data_size, (const char *) data); 614 message_id, data_size, (const char *) data);
615#else
616 /* obviously not binary safe */
617 printf("%s\n%.*s\n",
618 method_received, data_size, (const char *) data);
619#endif
601} 620}
602 621
603 622
@@ -611,6 +630,7 @@ slicer_recv_eom (void *cls,
611 uint64_t message_id, 630 uint64_t message_id,
612 uint8_t is_cancelled) 631 uint8_t is_cancelled)
613{ 632{
633 printf(".\n");
614 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 634 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
615 "Received end of message ID %" PRIu64 635 "Received end of message ID %" PRIu64
616 ", cancelled: %u\n", 636 ", cancelled: %u\n",
@@ -685,7 +705,7 @@ guest_recv_local_enter (void *cls, int result,
685{ 705{
686 char *pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (pub_key); 706 char *pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (pub_key);
687 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 707 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
688 "Guest entered to local place: %s, max_message_id: %" PRIu64 "\n", 708 "Guest entered local place: %s, max_message_id: %" PRIu64 "\n",
689 pub_str, max_message_id); 709 pub_str, max_message_id);
690 GNUNET_free (pub_str); 710 GNUNET_free (pub_str);
691 GNUNET_assert (0 <= result); 711 GNUNET_assert (0 <= result);
@@ -998,6 +1018,7 @@ app_connected (void *cls)
998 guest_enter (&place_pub_key, &peer); 1018 guest_enter (&place_pub_key, &peer);
999 } 1019 }
1000 } 1020 }
1021 printf(".\n");
1001} 1022}
1002 1023
1003 1024
@@ -1012,8 +1033,7 @@ app_recv_host (void *cls,
1012 enum GNUNET_SOCIAL_AppPlaceState place_state) 1033 enum GNUNET_SOCIAL_AppPlaceState place_state)
1013{ 1034{
1014 char *host_pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (host_pub_key); 1035 char *host_pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (host_pub_key);
1015 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1036 printf ("Host\t%s\n", host_pub_str);
1016 "Host: %s\n", host_pub_str);
1017 GNUNET_free (host_pub_str); 1037 GNUNET_free (host_pub_str);
1018 1038
1019 if ((op_host_reconnect || op_host_leave || op_host_announce || op_host_assign 1039 if ((op_host_reconnect || op_host_leave || op_host_announce || op_host_assign
@@ -1039,8 +1059,7 @@ app_recv_guest (void *cls,
1039 enum GNUNET_SOCIAL_AppPlaceState place_state) 1059 enum GNUNET_SOCIAL_AppPlaceState place_state)
1040{ 1060{
1041 char *guest_pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (guest_pub_key); 1061 char *guest_pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (guest_pub_key);
1042 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1062 printf ("Guest\t%s\n", guest_pub_str);
1043 "Guest: %s\n", guest_pub_str);
1044 GNUNET_free (guest_pub_str); 1063 GNUNET_free (guest_pub_str);
1045 1064
1046 if ((op_guest_reconnect || op_guest_leave || op_guest_talk 1065 if ((op_guest_reconnect || op_guest_leave || op_guest_talk
@@ -1065,7 +1084,7 @@ app_recv_ego (void *cls,
1065 const char *name) 1084 const char *name)
1066{ 1085{
1067 char *s = GNUNET_CRYPTO_ecdsa_public_key_to_string (pub_key); 1086 char *s = GNUNET_CRYPTO_ecdsa_public_key_to_string (pub_key);
1068 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Ego: %s\t%s\n", s, name); 1087 printf ("Ego\t%s\t%s\n", s, name);
1069 GNUNET_free (s); 1088 GNUNET_free (s);
1070 1089
1071 if (0 == memcmp (&ego_pub_key, pub_key, sizeof (*pub_key)) 1090 if (0 == memcmp (&ego_pub_key, pub_key, sizeof (*pub_key))
@@ -1124,6 +1143,7 @@ run (void *cls, char *const *args, const char *cfgfile,
1124 || op_look_at || op_look_for)) 1143 || op_look_at || op_look_for))
1125 { 1144 {
1126 op_status = 1; 1145 op_status = 1;
1146 fputs("Caution: This tool does not produce correct binary safe PSYC syntax.\n\n", stderr);
1127 } 1147 }
1128 1148
1129 GNUNET_SCHEDULER_add_shutdown (scheduler_shutdown, NULL); 1149 GNUNET_SCHEDULER_add_shutdown (scheduler_shutdown, NULL);
@@ -1144,6 +1164,7 @@ run (void *cls, char *const *args, const char *cfgfile,
1144 { 1164 {
1145 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1165 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1146 _("--place missing or invalid.\n")); 1166 _("--place missing or invalid.\n"));
1167 /* FIXME: why does it segfault here? */
1147 exit_fail (); 1168 exit_fail ();
1148 return; 1169 return;
1149 } 1170 }
@@ -1178,7 +1199,7 @@ int
1178main (int argc, char *const *argv) 1199main (int argc, char *const *argv)
1179{ 1200{
1180 int res; 1201 int res;
1181 static const struct GNUNET_GETOPT_CommandLineOption options[] = { 1202 struct GNUNET_GETOPT_CommandLineOption options[] = {
1182 /* 1203 /*
1183 * gnunet program options in addition to the ones below: 1204 * gnunet program options in addition to the ones below:
1184 * 1205 *
@@ -1191,120 +1212,165 @@ main (int argc, char *const *argv)
1191 1212
1192 /* operations */ 1213 /* operations */
1193 1214
1194 { 'A', "host-assign", NULL, 1215 GNUNET_GETOPT_option_flag ('A',
1195 gettext_noop ("assign --name in state to --data"), 1216 "host-assign",
1196 GNUNET_NO, &GNUNET_GETOPT_set_one, &op_host_assign }, 1217 gettext_noop ("assign --name in state to --data"),
1197 1218 &op_host_assign),
1198 { 'B', "guest-leave", NULL, 1219
1199 gettext_noop ("say good-bye and leave somebody else's place"), 1220 GNUNET_GETOPT_option_flag ('B',
1200 GNUNET_NO, &GNUNET_GETOPT_set_one, &op_guest_leave }, 1221 "guest-leave",
1201 1222 gettext_noop ("say good-bye and leave somebody else's place"),
1202 { 'C', "host-enter", NULL, 1223 &op_guest_leave),
1203 gettext_noop ("create a place"), 1224
1204 GNUNET_NO, &GNUNET_GETOPT_set_one, &op_host_enter }, 1225 GNUNET_GETOPT_option_flag ('C',
1205 1226 "host-enter",
1206 { 'D', "host-leave", NULL, 1227 gettext_noop ("create a place"),
1207 gettext_noop ("destroy a place we were hosting"), 1228 &op_host_enter),
1208 GNUNET_NO, &GNUNET_GETOPT_set_one, &op_host_leave }, 1229
1209 1230 GNUNET_GETOPT_option_flag ('C',
1210 { 'E', "guest-enter", NULL, 1231 "host-enter",
1211 gettext_noop ("enter somebody else's place"), 1232 gettext_noop ("create a place"),
1212 GNUNET_NO, &GNUNET_GETOPT_set_one, &op_guest_enter }, 1233 &op_host_enter),
1213 1234
1214 { 'F', "look-for", NULL, 1235 GNUNET_GETOPT_option_flag ('D',
1215 gettext_noop ("find state matching name prefix"), 1236 "host-leave",
1216 GNUNET_NO, &GNUNET_GETOPT_set_one, &op_look_for }, 1237 gettext_noop ("destroy a place we were hosting"),
1217 1238 &op_host_leave),
1218 { 'H', "replay-latest", NULL, 1239
1219 gettext_noop ("replay history of messages up to the given --limit"), 1240 GNUNET_GETOPT_option_flag ('E',
1220 GNUNET_NO, &GNUNET_GETOPT_set_one, &op_replay_latest }, 1241 "guest-enter",
1221 1242 gettext_noop ("enter somebody else's place"),
1222 { 'N', "host-reconnect", NULL, 1243 &op_guest_enter),
1223 gettext_noop ("reconnect to a previously created place"), 1244
1224 GNUNET_NO, &GNUNET_GETOPT_set_one, &op_host_reconnect }, 1245
1225 1246 GNUNET_GETOPT_option_flag ('F',
1226 { 'P', "host-announce", NULL, 1247 "look-for",
1227 gettext_noop ("publish something to a place we are hosting"), 1248 gettext_noop ("find state matching name prefix"),
1228 GNUNET_NO, &GNUNET_GETOPT_set_one, &op_host_announce }, 1249 &op_look_for),
1229 1250
1230 { 'R', "guest-reconnect", NULL, 1251 GNUNET_GETOPT_option_flag ('H',
1231 gettext_noop ("reconnect to a previously entered place"), 1252 "replay-latest",
1232 GNUNET_NO, &GNUNET_GETOPT_set_one, &op_guest_reconnect }, 1253 gettext_noop ("replay history of messages up to the given --limit"),
1233 1254 &op_replay_latest),
1234 { 'S', "look-at", NULL, 1255
1235 gettext_noop ("search for state matching exact name"), 1256 GNUNET_GETOPT_option_flag ('N',
1236 GNUNET_NO, &GNUNET_GETOPT_set_one, &op_look_at }, 1257 "host-reconnect",
1237 1258 gettext_noop ("reconnect to a previously created place"),
1238 { 'T', "guest-talk", NULL, 1259 &op_host_reconnect),
1239 gettext_noop ("submit something to somebody's place"), 1260
1240 GNUNET_NO, &GNUNET_GETOPT_set_one, &op_guest_talk }, 1261 GNUNET_GETOPT_option_flag ('P',
1241 1262 "host-announce",
1242 { 'U', "status", NULL, 1263 gettext_noop ("publish something to a place we are hosting"),
1243 gettext_noop ("list of egos and subscribed places"), 1264 &op_host_announce),
1244 GNUNET_NO, &GNUNET_GETOPT_set_one, &op_status }, 1265
1245 1266 GNUNET_GETOPT_option_flag ('R',
1246 { 'X', "replay", NULL, 1267 "guest-reconnect",
1247 gettext_noop ("extract and replay history between message IDs --start and --until"), 1268 gettext_noop ("reconnect to a previously entered place"),
1248 GNUNET_NO, &GNUNET_GETOPT_set_one, &op_replay }, 1269 &op_guest_reconnect),
1270
1271 GNUNET_GETOPT_option_flag ('S',
1272 "look-at",
1273 gettext_noop ("search for state matching exact name"),
1274 &op_look_at),
1275
1276 GNUNET_GETOPT_option_flag ('T',
1277 "guest-talk",
1278 gettext_noop ("submit something to somebody's place"),
1279 &op_guest_talk),
1280
1281 GNUNET_GETOPT_option_flag ('U',
1282 "status",
1283 gettext_noop ("list of egos and subscribed places"),
1284 &op_status),
1285
1286 GNUNET_GETOPT_option_flag ('X',
1287 "replay",
1288 gettext_noop ("extract and replay history between message IDs --start and --until"),
1289 &op_replay),
1249 1290
1250 1291
1251 /* options */ 1292 /* options */
1252 1293
1253 { 'a', "app", "APPLICATION_ID", 1294 GNUNET_GETOPT_option_string ('a',
1254 gettext_noop ("application ID to use when connecting"), 1295 "app",
1255 GNUNET_YES, &GNUNET_GETOPT_set_string, &opt_app }, 1296 "APPLICATION_ID",
1256 1297 gettext_noop ("application ID to use when connecting"),
1257 { 'd', "data", "DATA", 1298 &opt_app),
1258 gettext_noop ("message body or state value"), 1299
1259 GNUNET_YES, &GNUNET_GETOPT_set_string, &opt_data }, 1300 GNUNET_GETOPT_option_string ('d',
1260 1301 "data",
1261 { 'e', "ego", "NAME|PUBKEY", 1302 "DATA",
1262 gettext_noop ("name or public key of ego"), 1303 gettext_noop ("message body or state value"),
1263 GNUNET_YES, &GNUNET_GETOPT_set_string, &opt_ego }, 1304 &opt_data),
1264 1305
1265 { 'f', "follow", NULL, 1306 GNUNET_GETOPT_option_string ('e',
1266 gettext_noop ("wait for incoming messages"), 1307 "ego",
1267 GNUNET_NO, &GNUNET_GETOPT_set_one, &opt_follow }, 1308 "NAME|PUBKEY",
1268 1309 gettext_noop ("name or public key of ego"),
1269 { 'g', "gns", "GNS_NAME", 1310 &opt_ego),
1270 gettext_noop ("GNS name"), 1311
1271 GNUNET_YES, &GNUNET_GETOPT_set_string, &opt_gns }, 1312 GNUNET_GETOPT_option_flag ('f',
1272 1313 "follow",
1273 { 'i', "peer", "PEER_ID", 1314 gettext_noop ("wait for incoming messages"),
1274 gettext_noop ("peer ID for --guest-enter"), 1315 &opt_follow),
1275 GNUNET_YES, &GNUNET_GETOPT_set_string, &opt_peer }, 1316
1276 1317 GNUNET_GETOPT_option_string ('g',
1277 { 'k', "name", "VAR_NAME", 1318 "gns",
1278 gettext_noop ("name (key) to query from state"), 1319 "GNS_NAME",
1279 GNUNET_YES, &GNUNET_GETOPT_set_string, &opt_name }, 1320 gettext_noop ("GNS name"),
1280 1321 &opt_gns),
1281 { 'm', "method", "METHOD_NAME", 1322
1282 gettext_noop ("method name"), 1323 GNUNET_GETOPT_option_string ('i',
1283 GNUNET_YES, &GNUNET_GETOPT_set_string, &opt_method }, 1324 "peer",
1284 1325 "PEER_ID",
1285 { 'n', "limit", NULL, 1326 gettext_noop ("peer ID for --guest-enter"),
1286 gettext_noop ("number of messages to replay from history"), 1327 &opt_peer),
1287 GNUNET_YES, &GNUNET_GETOPT_set_ulong, &opt_limit }, 1328
1288 1329 GNUNET_GETOPT_option_string ('k',
1289 { 'p', "place", "PUBKEY", 1330 "name",
1290 gettext_noop ("key address of place"), 1331 "VAR_NAME",
1291 GNUNET_YES, &GNUNET_GETOPT_set_string, &opt_place }, 1332 gettext_noop ("name (key) to query from state"),
1292 1333 &opt_name),
1293 { 's', "start", NULL, 1334
1294 gettext_noop ("start message ID for history replay"), 1335 GNUNET_GETOPT_option_string ('m',
1295 GNUNET_YES, &GNUNET_GETOPT_set_ulong, &opt_start }, 1336 "method",
1296 1337 "METHOD_NAME",
1297 { 'w', "welcome", NULL, 1338 gettext_noop ("method name"),
1298 gettext_noop ("respond to entry requests by admitting all guests"), 1339 &opt_method),
1299 GNUNET_NO, &GNUNET_GETOPT_set_one, &opt_welcome }, 1340
1300 1341 GNUNET_GETOPT_option_ulong ('n',
1301 { 'u', "until", NULL, 1342 "limit",
1302 gettext_noop ("end message ID for history replay"), 1343 NULL,
1303 GNUNET_YES, &GNUNET_GETOPT_set_ulong, &opt_until }, 1344 gettext_noop ("number of messages to replay from history"),
1304 1345 &opt_limit),
1305 { 'y', "deny", NULL, 1346
1306 gettext_noop ("respond to entry requests by refusing all guests"), 1347 GNUNET_GETOPT_option_string ('p',
1307 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_ulong ('s',
1354 "start",
1355 NULL,
1356 gettext_noop ("start message ID for history replay"),
1357 &opt_start),
1358
1359 GNUNET_GETOPT_option_flag ('w',
1360 "welcome",
1361 gettext_noop ("respond to entry requests by admitting all guests"),
1362 &opt_welcome),
1363
1364 GNUNET_GETOPT_option_ulong ('u',
1365 "until",
1366 NULL,
1367 gettext_noop ("end message ID for history replay"),
1368 &opt_until),
1369
1370 GNUNET_GETOPT_option_flag ('y',
1371 "deny",
1372 gettext_noop ("respond to entry requests by refusing all guests"),
1373 &opt_deny),
1308 1374
1309 GNUNET_GETOPT_OPTION_END 1375 GNUNET_GETOPT_OPTION_END
1310 }; 1376 };
@@ -1333,8 +1399,8 @@ main (int argc, char *const *argv)
1333 "gnunet-social --guest-leave --place <PUBKEY>\n" 1399 "gnunet-social --guest-leave --place <PUBKEY>\n"
1334 "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"
1335 "\n" 1401 "\n"
1336 "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"
1337 "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"
1338 "\n" 1404 "\n"
1339 "gnunet-social --look-at --place <PUBKEY> --name <FULL_NAME>\n" 1405 "gnunet-social --look-at --place <PUBKEY> --name <FULL_NAME>\n"
1340 "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/.gitignore b/src/sq/.gitignore
new file mode 100644
index 000000000..951587047
--- /dev/null
+++ b/src/sq/.gitignore
@@ -0,0 +1 @@
test_sq
diff --git a/src/sq/Makefile.am b/src/sq/Makefile.am
new file mode 100644
index 000000000..cfccd89f6
--- /dev/null
+++ b/src/sq/Makefile.am
@@ -0,0 +1,40 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include $(POSTGRESQL_CPPFLAGS)
3
4if MINGW
5 WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols
6endif
7
8if USE_COVERAGE
9 AM_CFLAGS = --coverage
10endif
11
12if HAVE_SQLITE
13lib_LTLIBRARIES = libgnunetsq.la
14endif
15
16libgnunetsq_la_SOURCES = \
17 sq.c \
18 sq_query_helper.c \
19 sq_result_helper.c
20libgnunetsq_la_LIBADD = -lsqlite3 \
21 $(top_builddir)/src/util/libgnunetutil.la
22libgnunetsq_la_LDFLAGS = \
23 $(POSTGRESQL_LDFLAGS) \
24 $(GN_LIB_LDFLAGS) \
25 -version-info 0:0:0
26
27if ENABLE_TEST_RUN
28TESTS = \
29 test_sq
30endif
31
32check_PROGRAMS= \
33 test_sq
34
35test_sq_SOURCES = \
36 test_sq.c
37test_sq_LDADD = \
38 libgnunetsq.la \
39 $(top_builddir)/src/util/libgnunetutil.la \
40 -lsqlite3 $(XLIB)
diff --git a/src/sq/sq.c b/src/sq/sq.c
new file mode 100644
index 000000000..089ebf0ff
--- /dev/null
+++ b/src/sq/sq.c
@@ -0,0 +1,140 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2017 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify it under the
6 terms of the GNU General Public License as published by the Free Software
7 Foundation; either version 3, or (at your option) any later version.
8
9 GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License along with
14 GNUnet; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
15*/
16/**
17 * @file sq/sq.c
18 * @brief helper functions for Sqlite3 DB interactions
19 * @author Christian Grothoff
20 */
21#include "platform.h"
22#include "gnunet_sq_lib.h"
23
24
25/**
26 * Execute a prepared statement.
27 *
28 * @param db_conn database connection
29 * @param params parameters to the statement
30 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
31 */
32int
33GNUNET_SQ_bind (sqlite3_stmt *stmt,
34 const struct GNUNET_SQ_QueryParam *params)
35{
36 unsigned int j;
37
38 j = 1;
39 for (unsigned int i=0;NULL != params[i].conv; i++)
40 {
41 if (GNUNET_OK !=
42 params[i].conv (params[i].conv_cls,
43 params[i].data,
44 params[i].size,
45 stmt,
46 j))
47 {
48 GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
49 "sq",
50 _("Failure to bind %u-th SQL parameter\n"),
51 i);
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 }
60 }
61 GNUNET_assert (0 != params[i].num_params);
62 j += params[i].num_params;
63 }
64 return GNUNET_OK;
65}
66
67
68/**
69 * Extract results from a query result according to the given specification.
70 *
71 * @param result result to process
72 * @param[in,out] rs result specification to extract for
73 * @return
74 * #GNUNET_OK if all results could be extracted
75 * #GNUNET_SYSERR if a result was invalid (non-existing field)
76 */
77int
78GNUNET_SQ_extract_result (sqlite3_stmt *result,
79 struct GNUNET_SQ_ResultSpec *rs)
80{
81 unsigned int j = 0;
82
83 for (unsigned int i=0;NULL != rs[i].conv; i++)
84 {
85 if (NULL == rs[i].result_size)
86 rs[i].result_size = &rs[i].dst_size;
87 if (GNUNET_OK !=
88 rs[i].conv (rs[i].cls,
89 result,
90 j,
91 rs[i].result_size,
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);
97 return GNUNET_SYSERR;
98 }
99 GNUNET_assert (0 != rs[i].num_params);
100 j += rs[i].num_params;
101 }
102 return GNUNET_OK;
103}
104
105
106/**
107 * Free all memory that was allocated in @a rs during
108 * #GNUNET_SQ_extract_result().
109 *
110 * @param rs reult specification to clean up
111 */
112void
113GNUNET_SQ_cleanup_result (struct GNUNET_SQ_ResultSpec *rs)
114{
115 for (unsigned int i=0;NULL != rs[i].conv; i++)
116 if (NULL != rs[i].cleaner)
117 rs[i].cleaner (rs[i].cls);
118}
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
140/* end of sq.c */
diff --git a/src/sq/sq_query_helper.c b/src/sq/sq_query_helper.c
new file mode 100644
index 000000000..94a3a3f1c
--- /dev/null
+++ b/src/sq/sq_query_helper.c
@@ -0,0 +1,493 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2017 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify it under the
6 terms of the GNU General Public License as published by the Free Software
7 Foundation; either version 3, or (at your option) any later version.
8
9 GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License along with
14 GNUnet; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
15*/
16/**
17 * @file sq/sq_query_helper.c
18 * @brief helper functions for queries
19 * @author Christian Grothoff
20 */
21#include "platform.h"
22#include "gnunet_sq_lib.h"
23
24
25/**
26 * Function called to convert input argument into SQL parameters.
27 *
28 * @param cls closure
29 * @param data pointer to input argument
30 * @param data_len number of bytes in @a data (if applicable)
31 * @param stmt sqlite statement to bind parameters for
32 * @param off offset of the argument to bind in @a stmt, numbered from 1,
33 * so immediately suitable for passing to `sqlite3_bind`-functions.
34 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
35 */
36static int
37bind_fixed_blob (void *cls,
38 const void *data,
39 size_t data_len,
40 sqlite3_stmt *stmt,
41 unsigned int off)
42{
43 if (SQLITE_OK !=
44 sqlite3_bind_blob64 (stmt,
45 (int) off,
46 data,
47 (sqlite3_uint64) data_len,
48 SQLITE_TRANSIENT))
49 return GNUNET_SYSERR;
50 return GNUNET_OK;
51}
52
53
54/**
55 * Generate query parameter for a buffer @a ptr of
56 * @a ptr_size bytes.
57 *
58 * @param ptr pointer to the query parameter to pass
59 * @oaran ptr_size number of bytes in @a ptr
60 */
61struct GNUNET_SQ_QueryParam
62GNUNET_SQ_query_param_fixed_size (const void *ptr,
63 size_t ptr_size)
64{
65 struct GNUNET_SQ_QueryParam qp = {
66 .conv = &bind_fixed_blob,
67 .data = ptr,
68 .size = ptr_size,
69 .num_params = 1
70 };
71 return qp;
72}
73
74
75/**
76 * Function called to convert input argument into SQL parameters.
77 *
78 * @param cls closure
79 * @param data pointer to input argument
80 * @param data_len number of bytes in @a data (if applicable)
81 * @param stmt sqlite statement to bind parameters for
82 * @param off offset of the argument to bind in @a stmt, numbered from 1,
83 * so immediately suitable for passing to `sqlite3_bind`-functions.
84 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
85 */
86static int
87bind_string (void *cls,
88 const void *data,
89 size_t data_len,
90 sqlite3_stmt *stmt,
91 unsigned int off)
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 }
101 if (SQLITE_OK !=
102 sqlite3_bind_text (stmt,
103 (int) off,
104 (const char *) data,
105 -1,
106 SQLITE_TRANSIENT))
107 return GNUNET_SYSERR;
108 return GNUNET_OK;
109}
110
111
112/**
113 * Generate query parameter for a string.
114 *
115 * @param ptr pointer to the string query parameter to pass
116 */
117struct GNUNET_SQ_QueryParam
118GNUNET_SQ_query_param_string (const char *ptr)
119{
120 struct GNUNET_SQ_QueryParam qp = {
121 .conv = &bind_string,
122 .data = ptr,
123 .num_params = 1
124 };
125 return qp;
126}
127
128
129/**
130 * Function called to convert input argument into SQL parameters.
131 *
132 * @param cls closure
133 * @param data pointer to input argument
134 * @param data_len number of bytes in @a data (if applicable)
135 * @param stmt sqlite statement to bind parameters for
136 * @param off offset of the argument to bind in @a stmt, numbered from 1,
137 * so immediately suitable for passing to `sqlite3_bind`-functions.
138 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
139 */
140static int
141bind_rsa_pub (void *cls,
142 const void *data,
143 size_t data_len,
144 sqlite3_stmt *stmt,
145 unsigned int off)
146{
147 const struct GNUNET_CRYPTO_RsaPublicKey *rsa = data;
148 char *buf;
149 size_t buf_size;
150
151 GNUNET_break (NULL == cls);
152 buf_size = GNUNET_CRYPTO_rsa_public_key_encode (rsa,
153 &buf);
154 if (SQLITE_OK !=
155 sqlite3_bind_blob64 (stmt,
156 (int) off,
157 buf,
158 (sqlite3_uint64) buf_size,
159 SQLITE_TRANSIENT))
160 {
161 GNUNET_free (buf);
162 return GNUNET_SYSERR;
163 }
164 GNUNET_free (buf);
165 return GNUNET_OK;
166}
167
168
169/**
170 * Generate query parameter for an RSA public key. The
171 * database must contain a BLOB type in the respective position.
172 *
173 * @param x the query parameter to pass.
174 */
175struct GNUNET_SQ_QueryParam
176GNUNET_SQ_query_param_rsa_public_key (const struct GNUNET_CRYPTO_RsaPublicKey *x)
177{
178 struct GNUNET_SQ_QueryParam qp = {
179 .conv = &bind_rsa_pub,
180 .data = x,
181 .num_params = 1
182 };
183 return qp;
184}
185
186
187/**
188 * Function called to convert input argument into SQL parameters.
189 *
190 * @param cls closure
191 * @param data pointer to input argument
192 * @param data_len number of bytes in @a data (if applicable)
193 * @param stmt sqlite statement to bind parameters for
194 * @param off offset of the argument to bind in @a stmt, numbered from 1,
195 * so immediately suitable for passing to `sqlite3_bind`-functions.
196 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
197 */
198static int
199bind_rsa_sig (void *cls,
200 const void *data,
201 size_t data_len,
202 sqlite3_stmt *stmt,
203 unsigned int off)
204{
205 const struct GNUNET_CRYPTO_RsaSignature *sig = data;
206 char *buf;
207 size_t buf_size;
208
209 GNUNET_break (NULL == cls);
210 buf_size = GNUNET_CRYPTO_rsa_signature_encode (sig,
211 &buf);
212 if (SQLITE_OK !=
213 sqlite3_bind_blob64 (stmt,
214 (int) off,
215 buf,
216 (sqlite3_uint64) buf_size,
217 SQLITE_TRANSIENT))
218 {
219 GNUNET_free (buf);
220 return GNUNET_SYSERR;
221 }
222 GNUNET_free (buf);
223 return GNUNET_OK;
224}
225
226
227/**
228 * Generate query parameter for an RSA signature. The
229 * database must contain a BLOB type in the respective position.
230 *
231 * @param x the query parameter to pass
232 */
233struct GNUNET_SQ_QueryParam
234GNUNET_SQ_query_param_rsa_signature (const struct GNUNET_CRYPTO_RsaSignature *x)
235{
236 struct GNUNET_SQ_QueryParam qp = {
237 .conv = &bind_rsa_sig,
238 .data = x,
239 .num_params = 1
240 };
241 return qp;
242}
243
244
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/**
280 * Generate query parameter for an absolute time value.
281 * The database must store a 64-bit integer.
282 *
283 * @param x pointer to the query parameter to pass
284 */
285struct GNUNET_SQ_QueryParam
286GNUNET_SQ_query_param_absolute_time (const struct GNUNET_TIME_Absolute *x)
287{
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;
295}
296
297
298/**
299 * Function called to convert input argument into SQL parameters.
300 *
301 * @param cls closure
302 * @param data pointer to input argument
303 * @param data_len number of bytes in @a data (if applicable)
304 * @param stmt sqlite statement to bind parameters for
305 * @param off offset of the argument to bind in @a stmt, numbered from 1,
306 * so immediately suitable for passing to `sqlite3_bind`-functions.
307 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
308 */
309static int
310bind_nbotime (void *cls,
311 const void *data,
312 size_t data_len,
313 sqlite3_stmt *stmt,
314 unsigned int off)
315{
316 const struct GNUNET_TIME_AbsoluteNBO *u = data;
317 struct GNUNET_TIME_Absolute abs;
318
319 abs = GNUNET_TIME_absolute_ntoh (*u);
320 if (abs.abs_value_us > INT64_MAX)
321 abs.abs_value_us = INT64_MAX;
322 GNUNET_assert (sizeof (uint64_t) == data_len);
323 if (SQLITE_OK !=
324 sqlite3_bind_int64 (stmt,
325 (int) off,
326 (sqlite3_int64) abs.abs_value_us))
327 return GNUNET_SYSERR;
328 return GNUNET_OK;
329}
330
331
332/**
333 * Generate query parameter for an absolute time value.
334 * The database must store a 64-bit integer.
335 *
336 * @param x pointer to the query parameter to pass
337 */
338struct GNUNET_SQ_QueryParam
339GNUNET_SQ_query_param_absolute_time_nbo (const struct GNUNET_TIME_AbsoluteNBO *x)
340{
341 struct GNUNET_SQ_QueryParam qp = {
342 .conv = &bind_nbotime,
343 .data = x,
344 .size = sizeof (struct GNUNET_TIME_AbsoluteNBO),
345 .num_params = 1
346 };
347 return qp;
348}
349
350
351/**
352 * Function called to convert input argument into SQL parameters.
353 *
354 * @param cls closure
355 * @param data pointer to input argument
356 * @param data_len number of bytes in @a data (if applicable)
357 * @param stmt sqlite statement to bind parameters for
358 * @param off offset of the argument to bind in @a stmt, numbered from 1,
359 * so immediately suitable for passing to `sqlite3_bind`-functions.
360 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
361 */
362static int
363bind_u16 (void *cls,
364 const void *data,
365 size_t data_len,
366 sqlite3_stmt *stmt,
367 unsigned int off)
368{
369 const uint16_t *u = data;
370
371 GNUNET_assert (sizeof (uint16_t) == data_len);
372 if (SQLITE_OK !=
373 sqlite3_bind_int (stmt,
374 (int) off,
375 (int) *u))
376 return GNUNET_SYSERR;
377 return GNUNET_OK;
378}
379
380
381/**
382 * Generate query parameter for an uint16_t in host byte order.
383 *
384 * @param x pointer to the query parameter to pass
385 */
386struct GNUNET_SQ_QueryParam
387GNUNET_SQ_query_param_uint16 (const uint16_t *x)
388{
389 struct GNUNET_SQ_QueryParam qp = {
390 .conv = &bind_u16,
391 .data = x,
392 .size = sizeof (uint16_t),
393 .num_params = 1
394 };
395 return qp;
396}
397
398
399/**
400 * Function called to convert input argument into SQL parameters.
401 *
402 * @param cls closure
403 * @param data pointer to input argument
404 * @param data_len number of bytes in @a data (if applicable)
405 * @param stmt sqlite statement to bind parameters for
406 * @param off offset of the argument to bind in @a stmt, numbered from 1,
407 * so immediately suitable for passing to `sqlite3_bind`-functions.
408 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
409 */
410static int
411bind_u32 (void *cls,
412 const void *data,
413 size_t data_len,
414 sqlite3_stmt *stmt,
415 unsigned int off)
416{
417 const uint32_t *u = data;
418
419 GNUNET_assert (sizeof (uint32_t) == data_len);
420 if (SQLITE_OK !=
421 sqlite3_bind_int64 (stmt,
422 (int) off,
423 (sqlite3_int64) *u))
424 return GNUNET_SYSERR;
425 return GNUNET_OK;
426}
427
428/**
429 * Generate query parameter for an uint32_t in host byte order.
430 *
431 * @param x pointer to the query parameter to pass
432 */
433struct GNUNET_SQ_QueryParam
434GNUNET_SQ_query_param_uint32 (const uint32_t *x)
435{
436 struct GNUNET_SQ_QueryParam qp = {
437 .conv = &bind_u32,
438 .data = x,
439 .size = sizeof (uint32_t),
440 .num_params = 1
441 };
442 return qp;
443}
444
445
446/**
447 * Function called to convert input argument into SQL parameters.
448 *
449 * @param cls closure
450 * @param data pointer to input argument
451 * @param data_len number of bytes in @a data (if applicable)
452 * @param stmt sqlite statement to bind parameters for
453 * @param off offset of the argument to bind in @a stmt, numbered from 1,
454 * so immediately suitable for passing to `sqlite3_bind`-functions.
455 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
456 */
457static int
458bind_u64 (void *cls,
459 const void *data,
460 size_t data_len,
461 sqlite3_stmt *stmt,
462 unsigned int off)
463{
464 const uint64_t *u = data;
465
466 GNUNET_assert (sizeof (uint64_t) == data_len);
467 if (SQLITE_OK !=
468 sqlite3_bind_int64 (stmt,
469 (int) off,
470 (sqlite3_int64) *u))
471 return GNUNET_SYSERR;
472 return GNUNET_OK;
473}
474
475
476/**
477 * Generate query parameter for an uint16_t in host byte order.
478 *
479 * @param x pointer to the query parameter to pass
480 */
481struct GNUNET_SQ_QueryParam
482GNUNET_SQ_query_param_uint64 (const uint64_t *x)
483{
484 struct GNUNET_SQ_QueryParam qp = {
485 .conv = &bind_u64,
486 .data = x,
487 .size = sizeof (uint64_t),
488 .num_params = 1
489 };
490 return qp;
491}
492
493/* end of sq_query_helper.c */
diff --git a/src/sq/sq_result_helper.c b/src/sq/sq_result_helper.c
new file mode 100644
index 000000000..9579863b2
--- /dev/null
+++ b/src/sq/sq_result_helper.c
@@ -0,0 +1,782 @@
1
2/*
3 This file is part of GNUnet
4 Copyright (C) 2017 GNUnet e.V.
5
6 GNUnet is free software; you can redistribute it and/or modify it under the
7 terms of the GNU General Public License as published by the Free Software
8 Foundation; either version 3, or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY
11 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along with
15 GNUnet; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
16*/
17/**
18 * @file sq/sq_result_helper.c
19 * @brief helper functions for queries
20 * @author Christian Grothoff
21 */
22#include "platform.h"
23#include "gnunet_sq_lib.h"
24
25
26/**
27 * Extract variable-sized binary data from a Postgres database @a result at row @a row.
28 *
29 * @param cls closure
30 * @param result where to extract data from
31 * @param column column to extract data from
32 * @param[in,out] dst_size where to store size of result, may be NULL
33 * @param[out] dst where to store the result (actually a `void **`)
34 * @return
35 * #GNUNET_YES if all results could be extracted
36 * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
37 */
38static int
39extract_var_blob (void *cls,
40 sqlite3_stmt *result,
41 unsigned int column,
42 size_t *dst_size,
43 void *dst)
44{
45 int have;
46 const void *ret;
47 void **rdst = (void **) dst;
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
58 if (SQLITE_BLOB !=
59 sqlite3_column_type (result,
60 column))
61 {
62 GNUNET_break (0);
63 return GNUNET_SYSERR;
64 }
65 /* sqlite manual says to invoke 'sqlite3_column_blob()'
66 before calling sqlite3_column_bytes() */
67 ret = sqlite3_column_blob (result,
68 column);
69 have = sqlite3_column_bytes (result,
70 column);
71 if (have < 0)
72 {
73 GNUNET_break (0);
74 return GNUNET_SYSERR;
75 }
76 *dst_size = have;
77 if (0 == have)
78 {
79 *rdst = NULL;
80 return GNUNET_OK;
81 }
82 *rdst = GNUNET_malloc (have);
83 GNUNET_memcpy (*rdst,
84 ret,
85 have);
86 return GNUNET_OK;
87}
88
89
90/**
91 * Cleanup memory allocated by #extract_var_blob().
92 *
93 * @param cls pointer to pointer of allocation
94 */
95static void
96clean_var_blob (void *cls)
97{
98 void **dptr = (void **) cls;
99
100 if (NULL != *dptr)
101 {
102 GNUNET_free (*dptr);
103 *dptr = NULL;
104 }
105}
106
107
108/**
109 * Variable-size result expected.
110 *
111 * @param[out] dst where to store the result, allocated
112 * @param[out] sptr where to store the size of @a dst
113 * @return array entry for the result specification to use
114 */
115struct GNUNET_SQ_ResultSpec
116GNUNET_SQ_result_spec_variable_size (void **dst,
117 size_t *sptr)
118{
119 struct GNUNET_SQ_ResultSpec rs = {
120 .conv = &extract_var_blob,
121 .cleaner = &clean_var_blob,
122 .dst = dst,
123 .cls = dst,
124 .result_size = sptr,
125 .num_params = 1
126 };
127
128 return rs;
129}
130
131
132/**
133 * Extract fixed-sized binary data from a Postgres database @a result at row @a row.
134 *
135 * @param cls closure
136 * @param result where to extract data from
137 * @param column column to extract data from
138 * @param[in,out] dst_size where to store size of result, may be NULL
139 * @param[out] dst where to store the result
140 * @return
141 * #GNUNET_YES if all results could be extracted
142 * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
143 */
144static int
145extract_fixed_blob (void *cls,
146 sqlite3_stmt *result,
147 unsigned int column,
148 size_t *dst_size,
149 void *dst)
150{
151 int have;
152 const void *ret;
153
154 if ( (0 == *dst_size) &&
155 (SQLITE_NULL ==
156 sqlite3_column_type (result,
157 column)) )
158 {
159 return GNUNET_YES;
160 }
161
162 if (SQLITE_BLOB !=
163 sqlite3_column_type (result,
164 column))
165 {
166 GNUNET_break (0);
167 return GNUNET_SYSERR;
168 }
169 /* sqlite manual says to invoke 'sqlite3_column_blob()'
170 before calling sqlite3_column_bytes() */
171 ret = sqlite3_column_blob (result,
172 column);
173 have = sqlite3_column_bytes (result,
174 column);
175 if (*dst_size != have)
176 {
177 GNUNET_break (0);
178 return GNUNET_SYSERR;
179 }
180 GNUNET_memcpy (dst,
181 ret,
182 have);
183 return GNUNET_OK;
184}
185
186
187/**
188 * Fixed-size result expected.
189 *
190 * @param[out] dst where to store the result
191 * @param dst_size number of bytes in @a dst
192 * @return array entry for the result specification to use
193 */
194struct GNUNET_SQ_ResultSpec
195GNUNET_SQ_result_spec_fixed_size (void *dst,
196 size_t dst_size)
197{
198 struct GNUNET_SQ_ResultSpec rs = {
199 .conv = &extract_fixed_blob,
200 .dst = dst,
201 .dst_size = dst_size,
202 .num_params = 1
203 };
204
205 return rs;
206}
207
208
209/**
210 * Extract fixed-sized binary data from a Postgres database @a result at row @a row.
211 *
212 * @param cls closure
213 * @param result where to extract data from
214 * @param column column to extract data from
215 * @param[in,out] dst_size where to store size of result, may be NULL
216 * @param[out] dst where to store the result
217 * @return
218 * #GNUNET_YES if all results could be extracted
219 * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
220 */
221static int
222extract_utf8_string (void *cls,
223 sqlite3_stmt *result,
224 unsigned int column,
225 size_t *dst_size,
226 void *dst)
227{
228 const char *text;
229 char **rdst = dst;
230
231 if (SQLITE_NULL ==
232 sqlite3_column_type (result,
233 column))
234 {
235 *rdst = NULL;
236 return GNUNET_OK;
237 }
238 if (SQLITE_TEXT !=
239 sqlite3_column_type (result,
240 column))
241 {
242 GNUNET_break (0);
243 return GNUNET_SYSERR;
244 }
245 /* sqlite manual guarantees that 'sqlite3_column_text()'
246 is 0-terminated */
247 text = (const char *) sqlite3_column_text (result,
248 column);
249 if (NULL == text)
250 {
251 GNUNET_break (0);
252 return GNUNET_SYSERR;
253 }
254 *dst_size = strlen (text) + 1;
255 *rdst = GNUNET_strdup (text);
256 return GNUNET_OK;
257}
258
259
260/**
261 * Cleanup memory allocated by #extract_var_blob().
262 *
263 * @param cls pointer to pointer of allocation
264 */
265static void
266clean_utf8_string (void *cls)
267{
268 char **dptr = (char **) cls;
269
270 if (NULL != *dptr)
271 {
272 GNUNET_free (*dptr);
273 *dptr = NULL;
274 }
275}
276
277
278/**
279 * 0-terminated string expected.
280 *
281 * @param[out] dst where to store the result, allocated
282 * @return array entry for the result specification to use
283 */
284struct GNUNET_SQ_ResultSpec
285GNUNET_SQ_result_spec_string (char **dst)
286{
287 struct GNUNET_SQ_ResultSpec rs = {
288 .conv = &extract_utf8_string,
289 .cleaner = &clean_utf8_string,
290 .cls = dst,
291 .dst = dst,
292 .num_params = 1
293 };
294
295 return rs;
296}
297
298
299/**
300 * Extract data from a Postgres database @a result at row @a row.
301 *
302 * @param cls closure
303 * @param result where to extract data from
304 * @param column column to extract data from
305 * @param[in,out] dst_size where to store size of result, may be NULL
306 * @param[out] dst where to store the result
307 * @return
308 * #GNUNET_YES if all results could be extracted
309 * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
310 */
311static int
312extract_rsa_pub (void *cls,
313 sqlite3_stmt *result,
314 unsigned int column,
315 size_t *dst_size,
316 void *dst)
317{
318 struct GNUNET_CRYPTO_RsaPublicKey **pk = dst;
319 int have;
320 const void *ret;
321
322 if (SQLITE_BLOB !=
323 sqlite3_column_type (result,
324 column))
325 {
326 GNUNET_break (0);
327 return GNUNET_SYSERR;
328 }
329 /* sqlite manual says to invoke 'sqlite3_column_blob()'
330 before calling sqlite3_column_bytes() */
331 ret = sqlite3_column_blob (result,
332 column);
333 have = sqlite3_column_bytes (result,
334 column);
335 if (have < 0)
336 {
337 GNUNET_break (0);
338 return GNUNET_SYSERR;
339 }
340
341 *pk = GNUNET_CRYPTO_rsa_public_key_decode (ret,
342 have);
343 if (NULL == *pk)
344 {
345 GNUNET_break (0);
346 return GNUNET_SYSERR;
347 }
348 return GNUNET_OK;
349}
350
351
352/**
353 * Function called to clean up memory allocated
354 * by a #GNUNET_PQ_ResultConverter.
355 *
356 * @param cls closure
357 */
358static void
359clean_rsa_pub (void *cls)
360{
361 struct GNUNET_CRYPTO_RsaPublicKey **pk = cls;
362
363 if (NULL != *pk)
364 {
365 GNUNET_CRYPTO_rsa_public_key_free (*pk);
366 *pk = NULL;
367 }
368}
369
370
371/**
372 * RSA public key expected.
373 *
374 * @param[out] rsa where to store the result
375 * @return array entry for the result specification to use
376 */
377struct GNUNET_SQ_ResultSpec
378GNUNET_SQ_result_spec_rsa_public_key (struct GNUNET_CRYPTO_RsaPublicKey **rsa)
379{
380 struct GNUNET_SQ_ResultSpec rs = {
381 .conv = &extract_rsa_pub,
382 .cleaner = &clean_rsa_pub,
383 .dst = rsa,
384 .cls = rsa,
385 .num_params = 1
386 };
387
388 return rs;
389}
390
391
392/**
393 * Extract data from a Postgres database @a result at row @a row.
394 *
395 * @param cls closure
396 * @param result where to extract data from
397 * @param column column to extract data from
398 * @param[in,out] dst_size where to store size of result, may be NULL
399 * @param[out] dst where to store the result
400 * @return
401 * #GNUNET_YES if all results could be extracted
402 * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
403 */
404static int
405extract_rsa_sig (void *cls,
406 sqlite3_stmt *result,
407 unsigned int column,
408 size_t *dst_size,
409 void *dst)
410{
411 struct GNUNET_CRYPTO_RsaSignature **sig = dst;
412 int have;
413 const void *ret;
414
415 if (SQLITE_BLOB !=
416 sqlite3_column_type (result,
417 column))
418 {
419 GNUNET_break (0);
420 return GNUNET_SYSERR;
421 }
422 /* sqlite manual says to invoke 'sqlite3_column_blob()'
423 before calling sqlite3_column_bytes() */
424 ret = sqlite3_column_blob (result,
425 column);
426 have = sqlite3_column_bytes (result,
427 column);
428 if (have < 0)
429 {
430 GNUNET_break (0);
431 return GNUNET_SYSERR;
432 }
433
434 *sig = GNUNET_CRYPTO_rsa_signature_decode (ret,
435 have);
436 if (NULL == *sig)
437 {
438 GNUNET_break (0);
439 return GNUNET_SYSERR;
440 }
441 return GNUNET_OK;
442}
443
444
445/**
446 * Function called to clean up memory allocated
447 * by a #GNUNET_PQ_ResultConverter.
448 *
449 * @param cls result data to clean up
450 */
451static void
452clean_rsa_sig (void *cls)
453{
454 struct GNUNET_CRYPTO_RsaSignature **sig = cls;
455
456 if (NULL != *sig)
457 {
458 GNUNET_CRYPTO_rsa_signature_free (*sig);
459 *sig = NULL;
460 }
461}
462
463
464/**
465 * RSA signature expected.
466 *
467 * @param[out] sig where to store the result;
468 * @return array entry for the result specification to use
469 */
470struct GNUNET_SQ_ResultSpec
471GNUNET_SQ_result_spec_rsa_signature (struct GNUNET_CRYPTO_RsaSignature **sig)
472{
473 struct GNUNET_SQ_ResultSpec rs = {
474 .conv = &extract_rsa_sig,
475 .cleaner = &clean_rsa_sig,
476 .dst = sig,
477 .cls = sig,
478 .num_params = 1
479 };
480
481 return rs;
482}
483
484
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/**
525 * Absolute time expected.
526 *
527 * @param[out] at where to store the result
528 * @return array entry for the result specification to use
529 */
530struct GNUNET_SQ_ResultSpec
531GNUNET_SQ_result_spec_absolute_time (struct GNUNET_TIME_Absolute *at)
532{
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;
541}
542
543
544/**
545 * Extract absolute time value in NBO from a Postgres database @a result at row @a row.
546 *
547 * @param cls closure
548 * @param result where to extract data from
549 * @param column column to extract data from
550 * @param[in,out] dst_size where to store size of result, may be NULL
551 * @param[out] dst where to store the result
552 * @return
553 * #GNUNET_YES if all results could be extracted
554 * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
555 */
556static int
557extract_abs_time_nbo (void *cls,
558 sqlite3_stmt *result,
559 unsigned int column,
560 size_t *dst_size,
561 void *dst)
562{
563 struct GNUNET_TIME_AbsoluteNBO *u = dst;
564 struct GNUNET_TIME_Absolute t;
565
566 GNUNET_assert (sizeof (uint64_t) == *dst_size);
567 if (SQLITE_INTEGER !=
568 sqlite3_column_type (result,
569 column))
570 {
571 GNUNET_break (0);
572 return GNUNET_SYSERR;
573 }
574 t.abs_value_us = (uint64_t) sqlite3_column_int64 (result,
575 column);
576 if (INT64_MAX == t.abs_value_us)
577 t = GNUNET_TIME_UNIT_FOREVER_ABS;
578 *u = GNUNET_TIME_absolute_hton (t);
579 return GNUNET_OK;
580}
581
582
583/**
584 * Absolute time expected.
585 *
586 * @param[out] at where to store the result
587 * @return array entry for the result specification to use
588 */
589struct GNUNET_SQ_ResultSpec
590GNUNET_SQ_result_spec_absolute_time_nbo (struct GNUNET_TIME_AbsoluteNBO *at)
591{
592 struct GNUNET_SQ_ResultSpec rs = {
593 .conv = &extract_abs_time_nbo,
594 .dst = at,
595 .dst_size = sizeof (struct GNUNET_TIME_AbsoluteNBO),
596 .num_params = 1
597 };
598
599 return rs;
600}
601
602
603/**
604 * Extract 16-bit integer from a Postgres database @a result at row @a row.
605 *
606 * @param cls closure
607 * @param result where to extract data from
608 * @param column column to extract data from
609 * @param[in,out] dst_size where to store size of result, may be NULL
610 * @param[out] dst where to store the result
611 * @return
612 * #GNUNET_YES if all results could be extracted
613 * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
614 */
615static int
616extract_uint16 (void *cls,
617 sqlite3_stmt *result,
618 unsigned int column,
619 size_t *dst_size,
620 void *dst)
621{
622 uint64_t v;
623 uint32_t *u = dst;
624
625 GNUNET_assert (sizeof (uint16_t) == *dst_size);
626 if (SQLITE_INTEGER !=
627 sqlite3_column_type (result,
628 column))
629 {
630 GNUNET_break (0);
631 return GNUNET_SYSERR;
632 }
633 v = (uint64_t) sqlite3_column_int64 (result,
634 column);
635 if (v > UINT16_MAX)
636 {
637 GNUNET_break (0);
638 return GNUNET_SYSERR;
639 }
640 *u = (uint16_t) v;
641 return GNUNET_OK;
642}
643
644
645/**
646 * uint16_t expected.
647 *
648 * @param[out] u16 where to store the result
649 * @return array entry for the result specification to use
650 */
651struct GNUNET_SQ_ResultSpec
652GNUNET_SQ_result_spec_uint16 (uint16_t *u16)
653{
654 struct GNUNET_SQ_ResultSpec rs = {
655 .conv = &extract_uint16,
656 .dst = u16,
657 .dst_size = sizeof (uint16_t),
658 .num_params = 1
659 };
660
661 return rs;
662}
663
664
665/**
666 * Extract 32-bit integer from a Postgres database @a result at row @a row.
667 *
668 * @param cls closure
669 * @param result where to extract data from
670 * @param column column to extract data from
671 * @param[in,out] dst_size where to store size of result, may be NULL
672 * @param[out] dst where to store the result
673 * @return
674 * #GNUNET_YES if all results could be extracted
675 * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
676 */
677static int
678extract_uint32 (void *cls,
679 sqlite3_stmt *result,
680 unsigned int column,
681 size_t *dst_size,
682 void *dst)
683{
684 uint64_t v;
685 uint32_t *u = dst;
686
687 GNUNET_assert (sizeof (uint32_t) == *dst_size);
688 if (SQLITE_INTEGER !=
689 sqlite3_column_type (result,
690 column))
691 {
692 GNUNET_break (0);
693 return GNUNET_SYSERR;
694 }
695 v = (uint64_t) sqlite3_column_int64 (result,
696 column);
697 if (v > UINT32_MAX)
698 {
699 GNUNET_break (0);
700 return GNUNET_SYSERR;
701 }
702 *u = (uint32_t) v;
703 return GNUNET_OK;
704}
705
706
707/**
708 * uint32_t expected.
709 *
710 * @param[out] u32 where to store the result
711 * @return array entry for the result specification to use
712 */
713struct GNUNET_SQ_ResultSpec
714GNUNET_SQ_result_spec_uint32 (uint32_t *u32)
715{
716 struct GNUNET_SQ_ResultSpec rs = {
717 .conv = &extract_uint32,
718 .dst = u32,
719 .dst_size = sizeof (uint32_t),
720 .num_params = 1
721 };
722
723 return rs;
724}
725
726
727/**
728 * Extract 64-bit integer from a Postgres database @a result at row @a row.
729 *
730 * @param cls closure
731 * @param result where to extract data from
732 * @param column column to extract data from
733 * @param[in,out] dst_size where to store size of result, may be NULL
734 * @param[out] dst where to store the result
735 * @return
736 * #GNUNET_YES if all results could be extracted
737 * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
738 */
739static int
740extract_uint64 (void *cls,
741 sqlite3_stmt *result,
742 unsigned int column,
743 size_t *dst_size,
744 void *dst)
745{
746 uint64_t *u = dst;
747
748 GNUNET_assert (sizeof (uint64_t) == *dst_size);
749 if (SQLITE_INTEGER !=
750 sqlite3_column_type (result,
751 column))
752 {
753 GNUNET_break (0);
754 return GNUNET_SYSERR;
755 }
756 *u = (uint64_t) sqlite3_column_int64 (result,
757 column);
758 return GNUNET_OK;
759}
760
761
762/**
763 * uint64_t expected.
764 *
765 * @param[out] u64 where to store the result
766 * @return array entry for the result specification to use
767 */
768struct GNUNET_SQ_ResultSpec
769GNUNET_SQ_result_spec_uint64 (uint64_t *u64)
770{
771 struct GNUNET_SQ_ResultSpec rs = {
772 .conv = &extract_uint64,
773 .dst = u64,
774 .dst_size = sizeof (uint64_t),
775 .num_params = 1
776 };
777
778 return rs;
779}
780
781
782/* end of sq_result_helper.c */
diff --git a/src/sq/test_sq.c b/src/sq/test_sq.c
new file mode 100644
index 000000000..713809030
--- /dev/null
+++ b/src/sq/test_sq.c
@@ -0,0 +1,285 @@
1/*
2 This file is part of GNUnet
3 (C) 2015, 2016, 2017 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify it under the
6 terms of the GNU General Public License as published by the Free Software
7 Foundation; either version 3, or (at your option) any later version.
8
9 GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License along with
14 GNUnet; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
15*/
16/**
17 * @file sq/test_sq.c
18 * @brief Tests for sqlite3 convenience API
19 * @author Christian Grothoff
20 */
21#include "platform.h"
22#include "gnunet_util_lib.h"
23#include "gnunet_sq_lib.h"
24
25
26/**
27 * @brief Prepare a SQL statement
28 *
29 * @param dbh handle to the database
30 * @param zSql SQL statement, UTF-8 encoded
31 * @param[out] ppStmt set to the prepared statement
32 * @return 0 on success
33 */
34static int
35sq_prepare (sqlite3 *dbh,
36 const char *zSql,
37 sqlite3_stmt **ppStmt)
38{
39 char *dummy;
40 int result;
41
42 result = sqlite3_prepare_v2 (dbh,
43 zSql,
44 strlen (zSql),
45 ppStmt,
46 (const char **) &dummy);
47 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
48 "Prepared `%s' / %p: %d\n",
49 zSql,
50 *ppStmt,
51 result);
52 return result;
53}
54
55
56/**
57 * Run actual test queries.
58 *
59 * @return 0 on success
60 */
61static int
62run_queries (sqlite3 *dbh)
63{
64 struct GNUNET_CRYPTO_RsaPublicKey *pub;
65 struct GNUNET_CRYPTO_RsaPublicKey *pub2 = NULL;
66 struct GNUNET_CRYPTO_RsaSignature *sig;
67 struct GNUNET_CRYPTO_RsaSignature *sig2 = NULL;
68 struct GNUNET_TIME_Absolute abs_time = GNUNET_TIME_absolute_get ();
69 struct GNUNET_TIME_Absolute abs_time2;
70 struct GNUNET_TIME_Absolute forever = GNUNET_TIME_UNIT_FOREVER_ABS;
71 struct GNUNET_TIME_Absolute forever2;
72 struct GNUNET_HashCode hc;
73 struct GNUNET_HashCode hc2;
74 sqlite3_stmt *stmt;
75 struct GNUNET_CRYPTO_RsaPrivateKey *priv;
76 const char msg[] = "hello";
77 void *msg2;
78 struct GNUNET_HashCode hmsg;
79 size_t msg2_len;
80 uint16_t u16;
81 uint16_t u162;
82 uint32_t u32;
83 uint32_t u322;
84 uint64_t u64;
85 uint64_t u642;
86
87 priv = GNUNET_CRYPTO_rsa_private_key_create (1024);
88 pub = GNUNET_CRYPTO_rsa_private_key_get_public (priv);
89 memset (&hmsg, 42, sizeof (hmsg));
90 sig = GNUNET_CRYPTO_rsa_sign_fdh (priv,
91 &hmsg);
92 u16 = 16;
93 u32 = 32;
94 u64 = 64;
95 /* FIXME: test GNUNET_SQ_result_spec_variable_size */
96
97 sq_prepare (dbh,
98 "INSERT INTO test_sq ("
99 " pub"
100 ",sig"
101 ",abs_time"
102 ",forever"
103 ",hash"
104 ",vsize"
105 ",u16"
106 ",u32"
107 ",u64"
108 ") VALUES "
109 "($1, $2, $3, $4, $5, $6,"
110 "$7, $8, $9);",
111 &stmt);
112 {
113 struct GNUNET_SQ_QueryParam params_insert[] = {
114 GNUNET_SQ_query_param_rsa_public_key (pub),
115 GNUNET_SQ_query_param_rsa_signature (sig),
116 GNUNET_SQ_query_param_absolute_time (&abs_time),
117 GNUNET_SQ_query_param_absolute_time (&forever),
118 GNUNET_SQ_query_param_auto_from_type (&hc),
119 GNUNET_SQ_query_param_fixed_size (msg, strlen (msg)),
120 GNUNET_SQ_query_param_uint16 (&u16),
121 GNUNET_SQ_query_param_uint32 (&u32),
122 GNUNET_SQ_query_param_uint64 (&u64),
123 GNUNET_SQ_query_param_end
124 };
125
126 GNUNET_assert (GNUNET_OK ==
127 GNUNET_SQ_bind (stmt,
128 params_insert));
129 if (SQLITE_DONE !=
130 sqlite3_step (stmt))
131 {
132 GNUNET_CRYPTO_rsa_signature_free (sig);
133 GNUNET_CRYPTO_rsa_private_key_free (priv);
134 GNUNET_CRYPTO_rsa_public_key_free (pub);
135 return 1;
136 }
137 }
138 sqlite3_finalize (stmt);
139
140 sq_prepare (dbh,
141 "SELECT"
142 " pub"
143 ",sig"
144 ",abs_time"
145 ",forever"
146 ",hash"
147 ",vsize"
148 ",u16"
149 ",u32"
150 ",u64"
151 " FROM test_sq"
152 " ORDER BY abs_time DESC "
153 " LIMIT 1;",
154 &stmt);
155 {
156 struct GNUNET_SQ_QueryParam params_select[] = {
157 GNUNET_SQ_query_param_end
158 };
159 struct GNUNET_SQ_ResultSpec results_select[] = {
160 GNUNET_SQ_result_spec_rsa_public_key (&pub2),
161 GNUNET_SQ_result_spec_rsa_signature (&sig2),
162 GNUNET_SQ_result_spec_absolute_time (&abs_time2),
163 GNUNET_SQ_result_spec_absolute_time (&forever2),
164 GNUNET_SQ_result_spec_auto_from_type (&hc2),
165 GNUNET_SQ_result_spec_variable_size (&msg2, &msg2_len),
166 GNUNET_SQ_result_spec_uint16 (&u162),
167 GNUNET_SQ_result_spec_uint32 (&u322),
168 GNUNET_SQ_result_spec_uint64 (&u642),
169 GNUNET_SQ_result_spec_end
170 };
171
172 GNUNET_assert (GNUNET_OK ==
173 GNUNET_SQ_bind (stmt,
174 params_select));
175 if (SQLITE_ROW !=
176 sqlite3_step (stmt))
177 {
178 GNUNET_break (0);
179 sqlite3_finalize (stmt);
180 GNUNET_CRYPTO_rsa_signature_free (sig);
181 GNUNET_CRYPTO_rsa_private_key_free (priv);
182 GNUNET_CRYPTO_rsa_public_key_free (pub);
183 return 1;
184 }
185 GNUNET_assert (GNUNET_OK ==
186 GNUNET_SQ_extract_result (stmt,
187 results_select));
188 GNUNET_break (abs_time.abs_value_us == abs_time2.abs_value_us);
189 GNUNET_break (forever.abs_value_us == forever2.abs_value_us);
190 GNUNET_break (0 ==
191 memcmp (&hc,
192 &hc2,
193 sizeof (struct GNUNET_HashCode)));
194 GNUNET_break (0 ==
195 GNUNET_CRYPTO_rsa_signature_cmp (sig,
196 sig2));
197 GNUNET_break (0 ==
198 GNUNET_CRYPTO_rsa_public_key_cmp (pub,
199 pub2));
200 GNUNET_break (strlen (msg) == msg2_len);
201 GNUNET_break (0 ==
202 strncmp (msg,
203 msg2,
204 msg2_len));
205 GNUNET_break (16 == u162);
206 GNUNET_break (32 == u322);
207 GNUNET_break (64 == u642);
208 GNUNET_SQ_cleanup_result (results_select);
209 }
210 sqlite3_finalize (stmt);
211
212 GNUNET_CRYPTO_rsa_signature_free (sig);
213 GNUNET_CRYPTO_rsa_private_key_free (priv);
214 GNUNET_CRYPTO_rsa_public_key_free (pub);
215 return 0;
216}
217
218
219int
220main(int argc,
221 const char *const argv[])
222{
223 sqlite3 *dbh;
224 int ret;
225
226 GNUNET_log_setup ("test-sq",
227 "WARNING",
228 NULL);
229 if (SQLITE_OK !=
230 sqlite3_open ("test.db",
231 &dbh))
232 {
233 fprintf (stderr,
234 "Cannot run test, sqlite3 initialization failed\n");
235 GNUNET_break (0);
236 return 77; /* Signal test was skipped... */
237 }
238
239 if (SQLITE_OK !=
240 sqlite3_exec (dbh,
241 "CREATE TEMPORARY TABLE IF NOT EXISTS test_sq ("
242 " pub BYTEA NOT NULL"
243 ",sig BYTEA NOT NULL"
244 ",abs_time INT8 NOT NULL"
245 ",forever INT8 NOT NULL"
246 ",hash BYTEA NOT NULL"
247 ",vsize VARCHAR NOT NULL"
248 ",u16 INT2 NOT NULL"
249 ",u32 INT4 NOT NULL"
250 ",u64 INT8 NOT NULL"
251 ")",
252 NULL, NULL, NULL))
253 {
254 fprintf (stderr,
255 "Failed to create table\n");
256 GNUNET_break (SQLITE_OK ==
257 sqlite3_close (dbh));
258 if (0 != unlink ("test.db"))
259 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
260 "unlink",
261 "test.db");
262 return 1;
263 }
264
265 ret = run_queries (dbh);
266 if (SQLITE_OK !=
267 sqlite3_exec (dbh,
268 "DROP TABLE test_sq",
269 NULL, NULL, NULL))
270 {
271 fprintf (stderr,
272 "Failed to drop table\n");
273 ret = 1;
274 }
275 GNUNET_break (SQLITE_OK ==
276 sqlite3_close (dbh));
277 if (0 != unlink ("test.db"))
278 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
279 "unlink",
280 "test.db");
281 return ret;
282}
283
284
285/* end of test_sq.c */
diff --git a/src/statistics/Makefile.am b/src/statistics/Makefile.am
index 0907c4a37..b2e256960 100644
--- a/src/statistics/Makefile.am
+++ b/src/statistics/Makefile.am
@@ -55,7 +55,7 @@ check_PROGRAMS = \
55 test_statistics_api_watch_zero_value 55 test_statistics_api_watch_zero_value
56 56
57if ENABLE_TEST_RUN 57if ENABLE_TEST_RUN
58AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; 58AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
59TESTS = $(check_PROGRAMS) $(check_SCRIPTS) 59TESTS = $(check_PROGRAMS) $(check_SCRIPTS)
60endif 60endif
61 61
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..159afda53 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_flag ('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_flag ('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_flag ('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_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/template/Makefile.am b/src/template/Makefile.am
index bdd5d6ebf..5a27a6d60 100644
--- a/src/template/Makefile.am
+++ b/src/template/Makefile.am
@@ -42,7 +42,7 @@ check_PROGRAMS = \
42 test_template_api 42 test_template_api
43 43
44if ENABLE_TEST_RUN 44if ENABLE_TEST_RUN
45AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; 45AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
46TESTS = $(check_PROGRAMS) 46TESTS = $(check_PROGRAMS)
47endif 47endif
48 48
diff --git a/src/testbed-logger/Makefile.am b/src/testbed-logger/Makefile.am
index 7f372fd02..a8c4c7b05 100644
--- a/src/testbed-logger/Makefile.am
+++ b/src/testbed-logger/Makefile.am
@@ -41,7 +41,7 @@ check_PROGRAMS = \
41 test_testbed_logger_api 41 test_testbed_logger_api
42 42
43if ENABLE_TEST_RUN 43if ENABLE_TEST_RUN
44 AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; 44 AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
45 TESTS = \ 45 TESTS = \
46 test_testbed_logger_api 46 test_testbed_logger_api
47endif 47endif
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 e9b667b6c..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)
@@ -157,7 +157,7 @@ check_PROGRAMS = \
157 $(underlay_testcases) 157 $(underlay_testcases)
158 158
159if ENABLE_TEST_RUN 159if ENABLE_TEST_RUN
160 AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; 160 AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
161 TESTS = \ 161 TESTS = \
162 test_testbed_api \ 162 test_testbed_api \
163 test_testbed_api_sd \ 163 test_testbed_api_sd \
diff --git a/src/testbed/generate-underlay-topology.c b/src/testbed/generate-underlay-topology.c
index 36580a2a3..2e78c60be 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_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..9829bbf0d 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_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_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_flag ('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_test.c b/src/testbed/testbed_api_test.c
index e64e9fe2d..559c4abd9 100644
--- a/src/testbed/testbed_api_test.c
+++ b/src/testbed/testbed_api_test.c
@@ -114,13 +114,16 @@ run (void *cls, char *const *args, const char *cfgfile,
114 * handle of each peer 114 * handle of each peer
115 * @param cc_cls closure for cc 115 * @param cc_cls closure for cc
116 * @param test_master task to run once the test is ready 116 * @param test_master task to run once the test is ready
117 * @param test_master_cls closure for 'task'. 117 * @param test_master_cls closure for @a test_master
118 * @return GNUNET_SYSERR on error, GNUNET_OK on success 118 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
119 */ 119 */
120int 120int
121GNUNET_TESTBED_test_run (const char *testname, const char *cfg_filename, 121GNUNET_TESTBED_test_run (const char *testname,
122 unsigned int num_peers, uint64_t event_mask, 122 const char *cfg_filename,
123 GNUNET_TESTBED_ControllerCallback cc, void *cc_cls, 123 unsigned int num_peers,
124 uint64_t event_mask,
125 GNUNET_TESTBED_ControllerCallback cc,
126 void *cc_cls,
124 GNUNET_TESTBED_TestMaster test_master, 127 GNUNET_TESTBED_TestMaster test_master,
125 void *test_master_cls) 128 void *test_master_cls)
126{ 129{
@@ -148,9 +151,8 @@ GNUNET_TESTBED_test_run (const char *testname, const char *cfg_filename,
148 rc->event_mask = event_mask; 151 rc->event_mask = event_mask;
149 rc->cc = cc; 152 rc->cc = cc;
150 rc->cc_cls = cc_cls; 153 rc->cc_cls = cc_cls;
151 ret = 154 ret = GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2,
152 GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2, 155 testname, "nohelp", options, &run, rc);
153 testname, "nohelp", options, &run, rc);
154 GNUNET_free (rc); 156 GNUNET_free (rc);
155 GNUNET_free (argv2[0]); 157 GNUNET_free (argv2[0]);
156 GNUNET_free (argv2[2]); 158 GNUNET_free (argv2[2]);
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/Makefile.am b/src/testing/Makefile.am
index c290dc909..727bfb134 100644
--- a/src/testing/Makefile.am
+++ b/src/testing/Makefile.am
@@ -56,7 +56,7 @@ check_PROGRAMS = \
56 test_testing_sharedservices 56 test_testing_sharedservices
57 57
58if ENABLE_TEST_RUN 58if ENABLE_TEST_RUN
59AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; 59AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
60TESTS = \ 60TESTS = \
61 test_testing_portreservation \ 61 test_testing_portreservation \
62 test_testing_peerstartup \ 62 test_testing_peerstartup \
diff --git a/src/testing/gnunet-testing.c b/src/testing/gnunet-testing.c
index 07f1560cb..3dbe65883 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_flag ('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_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..9210486d3 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_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 043bdd7d2..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 }
@@ -1633,7 +1634,9 @@ GNUNET_TESTING_service_run (const char *testdir,
1633 char *binary; 1634 char *binary;
1634 char *libexec_binary; 1635 char *libexec_binary;
1635 1636
1636 GNUNET_log_setup (testdir, "WARNING", NULL); 1637 GNUNET_log_setup (testdir,
1638 "WARNING",
1639 NULL);
1637 system = GNUNET_TESTING_system_create (testdir, "127.0.0.1", NULL, NULL); 1640 system = GNUNET_TESTING_system_create (testdir, "127.0.0.1", NULL, NULL);
1638 if (NULL == system) 1641 if (NULL == system)
1639 return 1; 1642 return 1;
diff --git a/src/topology/Makefile.am b/src/topology/Makefile.am
index 6c6cbf8ff..97e4652d0 100644
--- a/src/topology/Makefile.am
+++ b/src/topology/Makefile.am
@@ -48,7 +48,7 @@ check_PROGRAMS = \
48endif 48endif
49 49
50if ENABLE_TEST_RUN 50if ENABLE_TEST_RUN
51AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; 51AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
52TESTS = $(check_PROGRAMS) 52TESTS = $(check_PROGRAMS)
53endif 53endif
54 54
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 0b523eecc..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
@@ -500,7 +502,7 @@ endif
500endif 502endif
501 503
502if ENABLE_TEST_RUN 504if ENABLE_TEST_RUN
503AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; 505AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
504TESTS = \ 506TESTS = \
505 test_transport_address_switch_tcp \ 507 test_transport_address_switch_tcp \
506 test_transport_address_switch_udp \ 508 test_transport_address_switch_udp \
@@ -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.c b/src/transport/gnunet-service-transport.c
index e7b221344..ec4d82164 100644
--- a/src/transport/gnunet-service-transport.c
+++ b/src/transport/gnunet-service-transport.c
@@ -150,11 +150,11 @@ struct TransportClient
150 150
151 /** 151 /**
152 * What type of client is this? 152 * What type of client is this?
153 */ 153 */
154 enum ClientType type; 154 enum ClientType type;
155 155
156 union { 156 union {
157 157
158 /** 158 /**
159 * Peer identity to monitor the addresses of. 159 * Peer identity to monitor the addresses of.
160 * Zero to monitor all neighbours. Valid if 160 * Zero to monitor all neighbours. Valid if
@@ -172,21 +172,21 @@ struct TransportClient
172 * if we're performing one that has been cancelled). 172 * if we're performing one that has been cancelled).
173 */ 173 */
174 struct GST_BlacklistCheck *bc; 174 struct GST_BlacklistCheck *bc;
175 175
176 /** 176 /**
177 * Set to #GNUNET_YES if we're currently waiting for a reply. 177 * Set to #GNUNET_YES if we're currently waiting for a reply.
178 */ 178 */
179 int waiting_for_reply; 179 int waiting_for_reply;
180 180
181 /** 181 /**
182 * #GNUNET_YES if we have to call receive_done for this client 182 * #GNUNET_YES if we have to call receive_done for this client
183 */ 183 */
184 int call_receive_done; 184 int call_receive_done;
185 185
186 } blacklist; 186 } blacklist;
187 187
188 } details; 188 } details;
189 189
190}; 190};
191 191
192 192
@@ -272,7 +272,7 @@ struct AddressToStringContext
272 */ 272 */
273struct SendTransmitContinuationContext 273struct SendTransmitContinuationContext
274{ 274{
275 275
276 /** 276 /**
277 * Client that made the request. 277 * Client that made the request.
278 */ 278 */
@@ -563,7 +563,7 @@ client_disconnect_cb (void *cls,
563 bc); 563 bc);
564 } 564 }
565 break; 565 break;
566 } 566 }
567 GNUNET_free (tc); 567 GNUNET_free (tc);
568} 568}
569 569
@@ -793,7 +793,7 @@ handle_client_send (void *cls,
793 const struct OutboundMessage *obm) 793 const struct OutboundMessage *obm)
794{ 794{
795 static unsigned long long uuid_gen; 795 static unsigned long long uuid_gen;
796 struct TransportClient *tc = cls; 796 struct TransportClient *tc = cls;
797 const struct GNUNET_MessageHeader *obmm; 797 const struct GNUNET_MessageHeader *obmm;
798 struct SendTransmitContinuationContext *stcc; 798 struct SendTransmitContinuationContext *stcc;
799 799
@@ -937,7 +937,7 @@ check_client_address_to_string (void *cls,
937 return GNUNET_SYSERR; 937 return GNUNET_SYSERR;
938 } 938 }
939 return GNUNET_OK; 939 return GNUNET_OK;
940} 940}
941 941
942 942
943/** 943/**
@@ -950,7 +950,7 @@ static void
950handle_client_address_to_string (void *cls, 950handle_client_address_to_string (void *cls,
951 const struct AddressLookupMessage *alum) 951 const struct AddressLookupMessage *alum)
952{ 952{
953 struct TransportClient *tc = cls; 953 struct TransportClient *tc = cls;
954 struct GNUNET_TRANSPORT_PluginFunctions *papi; 954 struct GNUNET_TRANSPORT_PluginFunctions *papi;
955 const char *plugin_name; 955 const char *plugin_name;
956 const char *address; 956 const char *address;
@@ -1308,7 +1308,7 @@ handle_client_monitor_plugins (void *cls,
1308 const struct GNUNET_MessageHeader *message) 1308 const struct GNUNET_MessageHeader *message)
1309{ 1309{
1310 struct TransportClient *tc = cls; 1310 struct TransportClient *tc = cls;
1311 1311
1312 GNUNET_SERVICE_client_mark_monitor (tc->client); 1312 GNUNET_SERVICE_client_mark_monitor (tc->client);
1313 GNUNET_SERVICE_client_disable_continue_warning (tc->client); 1313 GNUNET_SERVICE_client_disable_continue_warning (tc->client);
1314 GNUNET_notification_context_add (plugin_nc, 1314 GNUNET_notification_context_add (plugin_nc,
@@ -1690,9 +1690,10 @@ GST_receive_callback (void *cls,
1690 goto end; 1690 goto end;
1691 type = ntohs (message->type); 1691 type = ntohs (message->type);
1692 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1692 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1693 "Received message with type %u from peer `%s'\n", 1693 "Received message with type %u from peer `%s' at %s\n",
1694 type, 1694 type,
1695 GNUNET_i2s (&address->peer)); 1695 GNUNET_i2s (&address->peer),
1696 GST_plugins_a2s (address));
1696 1697
1697 GNUNET_STATISTICS_update (GST_stats, 1698 GNUNET_STATISTICS_update (GST_stats,
1698 gettext_noop ("# bytes total received"), 1699 gettext_noop ("# bytes total received"),
@@ -2226,7 +2227,7 @@ handle_client_set_metric (void *cls,
2226 const struct TrafficMetricMessage *tm) 2227 const struct TrafficMetricMessage *tm)
2227{ 2228{
2228 struct TransportClient *tc = cls; 2229 struct TransportClient *tc = cls;
2229 2230
2230 GST_manipulation_set_metric (tm); 2231 GST_manipulation_set_metric (tm);
2231 GNUNET_SERVICE_client_continue (tc->client); 2232 GNUNET_SERVICE_client_continue (tc->client);
2232} 2233}
@@ -2375,7 +2376,7 @@ handle_client_blacklist_reply (void *cls,
2375 bc = tc->details.blacklist.bc; 2376 bc = tc->details.blacklist.bc;
2376 tc->details.blacklist.bc = NULL; 2377 tc->details.blacklist.bc = NULL;
2377 tc->details.blacklist.waiting_for_reply = GNUNET_NO; 2378 tc->details.blacklist.waiting_for_reply = GNUNET_NO;
2378 tc->details.blacklist.call_receive_done = GNUNET_YES; 2379 tc->details.blacklist.call_receive_done = GNUNET_YES;
2379 if (NULL != bc) 2380 if (NULL != bc)
2380 { 2381 {
2381 /* only run this if the blacklist check has not been 2382 /* only run this if the blacklist check has not been
@@ -2808,7 +2809,7 @@ run (void *cls,
2808#if HAVE_GETRLIMIT 2809#if HAVE_GETRLIMIT
2809 { 2810 {
2810 struct rlimit r_file; 2811 struct rlimit r_file;
2811 2812
2812 if (0 == getrlimit (RLIMIT_NOFILE, 2813 if (0 == getrlimit (RLIMIT_NOFILE,
2813 &r_file)) 2814 &r_file))
2814 { 2815 {
@@ -2893,7 +2894,7 @@ GNUNET_SERVICE_MAIN
2893 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 2894 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND,
2894 struct OutboundMessage, 2895 struct OutboundMessage,
2895 NULL), 2896 NULL),
2896 GNUNET_MQ_hd_var_size (client_address_to_string, 2897 GNUNET_MQ_hd_var_size (client_address_to_string,
2897 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING, 2898 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING,
2898 struct AddressLookupMessage, 2899 struct AddressLookupMessage,
2899 NULL), 2900 NULL),
@@ -2913,7 +2914,7 @@ GNUNET_SERVICE_MAIN
2913 GNUNET_MESSAGE_TYPE_TRANSPORT_TRAFFIC_METRIC, 2914 GNUNET_MESSAGE_TYPE_TRANSPORT_TRAFFIC_METRIC,
2914 struct TrafficMetricMessage, 2915 struct TrafficMetricMessage,
2915 NULL), 2916 NULL),
2916 GNUNET_MQ_hd_fixed_size (client_monitor_plugins, 2917 GNUNET_MQ_hd_fixed_size (client_monitor_plugins,
2917 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PLUGIN_START, 2918 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PLUGIN_START,
2918 struct GNUNET_MessageHeader, 2919 struct GNUNET_MessageHeader,
2919 NULL), 2920 NULL),
diff --git a/src/transport/gnunet-service-transport_neighbours.c b/src/transport/gnunet-service-transport_neighbours.c
index 3952a728e..19f5fd081 100644
--- a/src/transport/gnunet-service-transport_neighbours.c
+++ b/src/transport/gnunet-service-transport_neighbours.c
@@ -1150,17 +1150,18 @@ set_incoming_quota (struct NeighbourMapEntry *n,
1150 sqm.header.size = htons (sizeof (struct GNUNET_ATS_SessionQuotaMessage)); 1150 sqm.header.size = htons (sizeof (struct GNUNET_ATS_SessionQuotaMessage));
1151 sqm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_QUOTA); 1151 sqm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_QUOTA);
1152 sqm.quota = quota.value__; 1152 sqm.quota = quota.value__;
1153 (void) send_with_session (n, 1153 if (NULL != n->primary_address.session)
1154 &sqm, 1154 (void) send_with_session (n,
1155 sizeof (sqm), 1155 &sqm,
1156 UINT32_MAX - 1, 1156 sizeof (sqm),
1157 GNUNET_TIME_UNIT_FOREVER_REL, 1157 UINT32_MAX - 1,
1158 GNUNET_NO, 1158 GNUNET_TIME_UNIT_FOREVER_REL,
1159 NULL, NULL); 1159 GNUNET_NO,
1160 NULL, NULL);
1160 return; 1161 return;
1161 } 1162 }
1162 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1163 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1163 "Disconnecting peer `%4s' due to SET_QUOTA\n", 1164 "Disconnecting peer `%s' due to SET_QUOTA\n",
1164 GNUNET_i2s (&n->id)); 1165 GNUNET_i2s (&n->id));
1165 if (GNUNET_YES == test_connected (n)) 1166 if (GNUNET_YES == test_connected (n))
1166 GNUNET_STATISTICS_update (GST_stats, 1167 GNUNET_STATISTICS_update (GST_stats,
@@ -2135,13 +2136,18 @@ setup_neighbour (const struct GNUNET_PeerIdentity *peer)
2135{ 2136{
2136 struct NeighbourMapEntry *n; 2137 struct NeighbourMapEntry *n;
2137 2138
2139 if (0 ==
2140 memcmp (&GST_my_identity,
2141 peer,
2142 sizeof (struct GNUNET_PeerIdentity)))
2143 {
2144 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2145 "Cowardly refusing to consider myself my neighbour!\n");
2146 return NULL;
2147 }
2138 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 2148 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2139 "Creating new neighbour entry for `%s'\n", 2149 "Creating new neighbour entry for `%s'\n",
2140 GNUNET_i2s (peer)); 2150 GNUNET_i2s (peer));
2141 GNUNET_assert (0 !=
2142 memcmp (&GST_my_identity,
2143 peer,
2144 sizeof (struct GNUNET_PeerIdentity)));
2145 n = GNUNET_new (struct NeighbourMapEntry); 2151 n = GNUNET_new (struct NeighbourMapEntry);
2146 n->id = *peer; 2152 n->id = *peer;
2147 n->ack_state = ACK_UNDEFINED; 2153 n->ack_state = ACK_UNDEFINED;
@@ -2249,6 +2255,7 @@ GST_neighbours_handle_session_syn (const struct GNUNET_MessageHeader *message,
2249 { 2255 {
2250 /* This is a new neighbour and set to not connected */ 2256 /* This is a new neighbour and set to not connected */
2251 n = setup_neighbour (peer); 2257 n = setup_neighbour (peer);
2258 GNUNET_assert (NULL != n);
2252 } 2259 }
2253 2260
2254 /* Remember this SYN message in neighbour */ 2261 /* Remember this SYN message in neighbour */
@@ -2318,6 +2325,7 @@ GST_neighbours_handle_session_syn (const struct GNUNET_MessageHeader *message,
2318 /* Get rid of remains and re-try */ 2325 /* Get rid of remains and re-try */
2319 free_neighbour (n); 2326 free_neighbour (n);
2320 n = setup_neighbour (peer); 2327 n = setup_neighbour (peer);
2328 GNUNET_assert (NULL != n);
2321 /* Remember the SYN time stamp for ACK message */ 2329 /* Remember the SYN time stamp for ACK message */
2322 n->ack_state = ACK_SEND_SYN_ACK; 2330 n->ack_state = ACK_SEND_SYN_ACK;
2323 n->connect_ack_timestamp = ts; 2331 n->connect_ack_timestamp = ts;
@@ -2495,6 +2503,12 @@ switch_address_bl_check_cont (void *cls,
2495 if (NULL == (n = lookup_neighbour (peer))) 2503 if (NULL == (n = lookup_neighbour (peer)))
2496 { 2504 {
2497 n = setup_neighbour (peer); 2505 n = setup_neighbour (peer);
2506 if (NULL == n)
2507 {
2508 /* not sure how this can happen... */
2509 GNUNET_break (0);
2510 goto cleanup;
2511 }
2498 n->state = GNUNET_TRANSPORT_PS_INIT_ATS; 2512 n->state = GNUNET_TRANSPORT_PS_INIT_ATS;
2499 } 2513 }
2500 2514
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..d580fce08 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,27 +610,37 @@ 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_flag ('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_flag ('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_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_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_VERBOSE (&verbosity), 633 GNUNET_GETOPT_option_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),
643 GNUNET_GETOPT_option_verbose (&verbosity),
634 GNUNET_GETOPT_OPTION_END 644 GNUNET_GETOPT_OPTION_END
635 }; 645 };
636 646
diff --git a/src/transport/gnunet-transport.c b/src/transport/gnunet-transport.c
index fcfc94ac8..96d0a6a3a 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,38 +1427,50 @@ 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_flag ('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_flag ('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_flag ('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_flag ('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_flag ('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_flag ('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_flag ('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_base32_auto ('p',
1472 &GNUNET_GETOPT_set_one, &benchmark_send }, 1460 "peer",
1473 GNUNET_GETOPT_OPTION_VERBOSE (&verbosity), 1461 "PEER",
1462 gettext_noop ("peer identity"),
1463 &pid),
1464 GNUNET_GETOPT_option_flag ('P',
1465 "plugins",
1466 gettext_noop ("monitor plugin sessions"),
1467 &monitor_plugins),
1468 GNUNET_GETOPT_option_flag ('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),
1474 GNUNET_GETOPT_OPTION_END 1474 GNUNET_GETOPT_OPTION_END
1475 }; 1475 };
1476 1476
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 eca62a8ca..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);
49 337
50 338
51/** 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);
399
400
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_IN_SIN_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.
@@ -1418,7 +1905,7 @@ create_session (struct Plugin *plugin,
1418 GNUNET_assert (NULL == client); 1905 GNUNET_assert (NULL == client);
1419 1906
1420 LOG (GNUNET_ERROR_TYPE_DEBUG, 1907 LOG (GNUNET_ERROR_TYPE_DEBUG,
1421 "Creating new session for peer `%4s' at address %s\n", 1908 "Creating new session for peer `%s' at address %s\n",
1422 GNUNET_i2s (&address->peer), 1909 GNUNET_i2s (&address->peer),
1423 tcp_plugin_address_to_string (plugin, 1910 tcp_plugin_address_to_string (plugin,
1424 address->address, 1911 address->address,
@@ -1522,7 +2009,7 @@ do_transmit (void *cls,
1522 if (NULL == buf) 2009 if (NULL == buf)
1523 { 2010 {
1524 LOG (GNUNET_ERROR_TYPE_DEBUG, 2011 LOG (GNUNET_ERROR_TYPE_DEBUG,
1525 "Timeout trying to transmit to peer `%4s', discarding message queue.\n", 2012 "Timeout trying to transmit to peer `%s', discarding message queue.\n",
1526 GNUNET_i2s (&session->target)); 2013 GNUNET_i2s (&session->target));
1527 /* timeout; cancel all messages that have already expired */ 2014 /* timeout; cancel all messages that have already expired */
1528 hd = NULL; 2015 hd = NULL;
@@ -1540,7 +2027,7 @@ do_transmit (void *cls,
1540 GNUNET_assert (pos->message_size <= session->bytes_in_queue); 2027 GNUNET_assert (pos->message_size <= session->bytes_in_queue);
1541 session->bytes_in_queue -= pos->message_size; 2028 session->bytes_in_queue -= pos->message_size;
1542 LOG (GNUNET_ERROR_TYPE_DEBUG, 2029 LOG (GNUNET_ERROR_TYPE_DEBUG,
1543 "Failed to transmit %u byte message to `%4s'.\n", 2030 "Failed to transmit %u byte message to `%s'.\n",
1544 pos->message_size, 2031 pos->message_size,
1545 GNUNET_i2s (&session->target)); 2032 GNUNET_i2s (&session->target));
1546 ret += pos->message_size; 2033 ret += pos->message_size;
@@ -1729,10 +2216,10 @@ tcp_plugin_send (void *cls,
1729 pm->transmit_cont = cont; 2216 pm->transmit_cont = cont;
1730 pm->transmit_cont_cls = cont_cls; 2217 pm->transmit_cont_cls = cont_cls;
1731 2218
1732 LOG(GNUNET_ERROR_TYPE_DEBUG, 2219 LOG (GNUNET_ERROR_TYPE_DEBUG,
1733 "Asked to transmit %u bytes to `%s', added message to list.\n", 2220 "Asked to transmit %u bytes to `%s', added message to list.\n",
1734 msgbuf_size, 2221 msgbuf_size,
1735 GNUNET_i2s (&session->target)); 2222 GNUNET_i2s (&session->target));
1736 2223
1737 if (GNUNET_YES == 2224 if (GNUNET_YES ==
1738 GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessionmap, 2225 GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessionmap,
@@ -1997,6 +2484,13 @@ tcp_plugin_get_session (void *cls,
1997 address->address_length)); 2484 address->address_length));
1998 return session; 2485 return session;
1999 } 2486 }
2487 /* This is a bit of a hack, limiting TCP to never allow more than
2488 one TCP connection to any given peer at the same time.
2489 Without this, peers sometimes disagree about which of the TCP
2490 connections they should use, causing one side to believe that
2491 they transmit successfully, while the other receives nothing. */
2492 return NULL; /* Refuse to have more than one TCP connection per
2493 peer pair at the same time. */
2000 } 2494 }
2001 2495
2002 if (addrlen == sizeof(struct IPv6TcpAddress)) 2496 if (addrlen == sizeof(struct IPv6TcpAddress))
@@ -2078,7 +2572,7 @@ tcp_plugin_get_session (void *cls,
2078 &address->peer))) 2572 &address->peer)))
2079 { 2573 {
2080 struct sockaddr_in local_sa; 2574 struct sockaddr_in local_sa;
2081 2575
2082 LOG (GNUNET_ERROR_TYPE_DEBUG, 2576 LOG (GNUNET_ERROR_TYPE_DEBUG,
2083 "Found valid IPv4 NAT address (creating session)!\n"); 2577 "Found valid IPv4 NAT address (creating session)!\n");
2084 session = create_session (plugin, 2578 session = create_session (plugin,
@@ -2168,13 +2662,13 @@ tcp_plugin_get_session (void *cls,
2168 if (NULL == sa) 2662 if (NULL == sa)
2169 { 2663 {
2170 LOG (GNUNET_ERROR_TYPE_DEBUG, 2664 LOG (GNUNET_ERROR_TYPE_DEBUG,
2171 "Failed to create connection to `%4s' at `%s'\n", 2665 "Failed to create connection to `%s' at `%s'\n",
2172 GNUNET_i2s (&address->peer), 2666 GNUNET_i2s (&address->peer),
2173 GNUNET_a2s (sb, sbs)); 2667 GNUNET_a2s (sb, sbs));
2174 return NULL; 2668 return NULL;
2175 } 2669 }
2176 LOG (GNUNET_ERROR_TYPE_DEBUG, 2670 LOG (GNUNET_ERROR_TYPE_DEBUG,
2177 "Asked to transmit to `%4s', creating fresh session using address `%s'.\n", 2671 "Asked to transmit to `%s', creating fresh session using address `%s'.\n",
2178 GNUNET_i2s (&address->peer), 2672 GNUNET_i2s (&address->peer),
2179 GNUNET_a2s (sb, sbs)); 2673 GNUNET_a2s (sb, sbs));
2180 2674
@@ -2246,7 +2740,7 @@ tcp_plugin_disconnect (void *cls,
2246 struct Plugin *plugin = cls; 2740 struct Plugin *plugin = cls;
2247 2741
2248 LOG (GNUNET_ERROR_TYPE_DEBUG, 2742 LOG (GNUNET_ERROR_TYPE_DEBUG,
2249 "Disconnecting peer `%4s'\n", 2743 "Disconnecting peer `%s'\n",
2250 GNUNET_i2s (target)); 2744 GNUNET_i2s (target));
2251 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessionmap, 2745 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessionmap,
2252 target, 2746 target,
@@ -2446,7 +2940,7 @@ tcp_plugin_check_address (void *cls,
2446 if (addrlen == sizeof(struct IPv4TcpAddress)) 2940 if (addrlen == sizeof(struct IPv4TcpAddress))
2447 { 2941 {
2448 struct sockaddr_in s4; 2942 struct sockaddr_in s4;
2449 2943
2450 v4 = (const struct IPv4TcpAddress *) addr; 2944 v4 = (const struct IPv4TcpAddress *) addr;
2451 if (0 != memcmp (&v4->options, 2945 if (0 != memcmp (&v4->options,
2452 &plugin->myoptions, 2946 &plugin->myoptions,
@@ -2462,7 +2956,7 @@ tcp_plugin_check_address (void *cls,
2462#endif 2956#endif
2463 s4.sin_port = v4->t4_port; 2957 s4.sin_port = v4->t4_port;
2464 s4.sin_addr.s_addr = v4->ipv4_addr; 2958 s4.sin_addr.s_addr = v4->ipv4_addr;
2465 2959
2466 if (GNUNET_OK != 2960 if (GNUNET_OK !=
2467 GNUNET_NAT_test_address (plugin->nat, 2961 GNUNET_NAT_test_address (plugin->nat,
2468 &s4, 2962 &s4,
@@ -2472,7 +2966,7 @@ tcp_plugin_check_address (void *cls,
2472 else 2966 else
2473 { 2967 {
2474 struct sockaddr_in6 s6; 2968 struct sockaddr_in6 s6;
2475 2969
2476 v6 = (const struct IPv6TcpAddress *) addr; 2970 v6 = (const struct IPv6TcpAddress *) addr;
2477 if (IN6_IS_ADDR_LINKLOCAL (&v6->ipv6_addr)) 2971 if (IN6_IS_ADDR_LINKLOCAL (&v6->ipv6_addr))
2478 { 2972 {
@@ -2686,27 +3180,37 @@ handle_tcp_welcome (void *cls,
2686 &alen)) 3180 &alen))
2687 { 3181 {
2688 LOG (GNUNET_ERROR_TYPE_INFO, 3182 LOG (GNUNET_ERROR_TYPE_INFO,
2689 "Received WELCOME message from my own identity `%4s' on address `%s'\n", 3183 "Received WELCOME message from my own identity `%s' on address `%s'\n",
2690 GNUNET_i2s (&wm->clientIdentity), 3184 GNUNET_i2s (&wm->clientIdentity),
2691 GNUNET_a2s (vaddr, alen)); 3185 GNUNET_a2s (vaddr, alen));
2692 GNUNET_free(vaddr); 3186 GNUNET_free (vaddr);
2693 } 3187 }
2694 return; 3188 return;
2695 } 3189 }
2696 3190
2697 LOG(GNUNET_ERROR_TYPE_DEBUG, 3191 if (GNUNET_OK ==
2698 "Received WELCOME message from `%4s' %p\n", 3192 GNUNET_SERVER_client_get_address (client,
2699 GNUNET_i2s (&wm->clientIdentity), 3193 &vaddr,
2700 client); 3194 &alen))
3195 {
3196 LOG(GNUNET_ERROR_TYPE_DEBUG,
3197 "Received WELCOME message from `%s' on address `%s'\n",
3198 GNUNET_i2s (&wm->clientIdentity),
3199 GNUNET_a2s (vaddr, alen));
3200 GNUNET_free (vaddr);
3201 }
2701 GNUNET_STATISTICS_update (plugin->env->stats, 3202 GNUNET_STATISTICS_update (plugin->env->stats,
2702 gettext_noop ("# TCP WELCOME messages received"), 3203 gettext_noop ("# TCP WELCOME messages received"),
2703 1, 3204 1,
2704 GNUNET_NO); 3205 GNUNET_NO);
2705 session = lookup_session_by_client (plugin, client); 3206 session = lookup_session_by_client (plugin,
3207 client);
2706 if (NULL != session) 3208 if (NULL != session)
2707 { 3209 {
2708 if (GNUNET_OK == 3210 if (GNUNET_OK ==
2709 GNUNET_SERVER_client_get_address (client, &vaddr, &alen)) 3211 GNUNET_SERVER_client_get_address (client,
3212 &vaddr,
3213 &alen))
2710 { 3214 {
2711 LOG (GNUNET_ERROR_TYPE_DEBUG, 3215 LOG (GNUNET_ERROR_TYPE_DEBUG,
2712 "Found existing session %p for peer `%s'\n", 3216 "Found existing session %p for peer `%s'\n",
@@ -2795,12 +3299,11 @@ handle_tcp_welcome (void *cls,
2795 } 3299 }
2796 } 3300 }
2797 3301
2798 if (session->expecting_welcome != GNUNET_YES) 3302 if (GNUNET_YES != session->expecting_welcome)
2799 { 3303 {
2800 GNUNET_break_op(0); 3304 GNUNET_break_op (0);
2801 GNUNET_SERVER_receive_done (client, 3305 GNUNET_SERVER_receive_done (client,
2802 GNUNET_SYSERR); 3306 GNUNET_SYSERR);
2803 GNUNET_break(0);
2804 return; 3307 return;
2805 } 3308 }
2806 session->last_activity = GNUNET_TIME_absolute_get (); 3309 session->last_activity = GNUNET_TIME_absolute_get ();
@@ -2869,7 +3372,9 @@ handle_tcp_data (void *cls,
2869 void *vaddr; 3372 void *vaddr;
2870 size_t alen; 3373 size_t alen;
2871 3374
2872 GNUNET_SERVER_client_get_address (client, &vaddr, &alen); 3375 GNUNET_SERVER_client_get_address (client,
3376 &vaddr,
3377 &alen);
2873 LOG (GNUNET_ERROR_TYPE_ERROR, 3378 LOG (GNUNET_ERROR_TYPE_ERROR,
2874 "Received unexpected %u bytes of type %u from `%s'\n", 3379 "Received unexpected %u bytes of type %u from `%s'\n",
2875 (unsigned int) ntohs (message->size), 3380 (unsigned int) ntohs (message->size),
@@ -2883,11 +3388,21 @@ handle_tcp_data (void *cls,
2883 } 3388 }
2884 3389
2885 session->last_activity = GNUNET_TIME_absolute_get (); 3390 session->last_activity = GNUNET_TIME_absolute_get ();
2886 LOG (GNUNET_ERROR_TYPE_DEBUG, 3391 {
2887 "Passing %u bytes of type %u from `%4s' to transport service.\n", 3392 void *vaddr;
2888 (unsigned int) ntohs (message->size), 3393 size_t alen;
2889 (unsigned int) ntohs (message->type), 3394
2890 GNUNET_i2s (&session->target)); 3395 GNUNET_SERVER_client_get_address (client,
3396 &vaddr,
3397 &alen);
3398 LOG (GNUNET_ERROR_TYPE_DEBUG,
3399 "Passing %u bytes of type %u from `%s' at %s to transport service.\n",
3400 (unsigned int) ntohs (message->size),
3401 (unsigned int) ntohs (message->type),
3402 GNUNET_i2s (&session->target),
3403 GNUNET_a2s (vaddr, alen));
3404 GNUNET_free_non_null (vaddr);
3405 }
2891 3406
2892 GNUNET_STATISTICS_update (plugin->env->stats, 3407 GNUNET_STATISTICS_update (plugin->env->stats,
2893 gettext_noop ("# bytes received via TCP"), 3408 gettext_noop ("# bytes received via TCP"),
@@ -2984,7 +3499,7 @@ disconnect_notify (void *cls,
2984 if (NULL == session) 3499 if (NULL == session)
2985 return; /* unknown, nothing to do */ 3500 return; /* unknown, nothing to do */
2986 LOG (GNUNET_ERROR_TYPE_DEBUG, 3501 LOG (GNUNET_ERROR_TYPE_DEBUG,
2987 "Destroying session of `%4s' with %s due to network-level disconnect.\n", 3502 "Destroying session of `%s' with %s due to network-level disconnect.\n",
2988 GNUNET_i2s (&session->target), 3503 GNUNET_i2s (&session->target),
2989 tcp_plugin_address_to_string (session->plugin, 3504 tcp_plugin_address_to_string (session->plugin,
2990 session->address->address, 3505 session->address->address,
@@ -3261,7 +3776,7 @@ libgnunet_plugin_transport_tcp_init (void *cls)
3261 struct GNUNET_TRANSPORT_PluginEnvironment *env = cls; 3776 struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
3262 struct GNUNET_TRANSPORT_PluginFunctions *api; 3777 struct GNUNET_TRANSPORT_PluginFunctions *api;
3263 struct Plugin *plugin; 3778 struct Plugin *plugin;
3264 struct GNUNET_SERVICE_Context *service; 3779 struct LEGACY_SERVICE_Context *service;
3265 unsigned long long aport; 3780 unsigned long long aport;
3266 unsigned long long bport; 3781 unsigned long long bport;
3267 unsigned long long max_connections; 3782 unsigned long long max_connections;
@@ -3316,9 +3831,9 @@ libgnunet_plugin_transport_tcp_init (void *cls)
3316 aport = 0; 3831 aport = 0;
3317 if (0 != bport) 3832 if (0 != bport)
3318 { 3833 {
3319 service = GNUNET_SERVICE_start ("transport-tcp", 3834 service = LEGACY_SERVICE_start ("transport-tcp",
3320 env->cfg, 3835 env->cfg,
3321 GNUNET_SERVICE_OPTION_NONE); 3836 LEGACY_SERVICE_OPTION_NONE);
3322 if (NULL == service) 3837 if (NULL == service)
3323 { 3838 {
3324 LOG (GNUNET_ERROR_TYPE_WARNING, 3839 LOG (GNUNET_ERROR_TYPE_WARNING,
@@ -3349,7 +3864,7 @@ libgnunet_plugin_transport_tcp_init (void *cls)
3349 { 3864 {
3350#ifdef TCP_STEALTH 3865#ifdef TCP_STEALTH
3351 plugin->myoptions |= TCP_OPTIONS_TCP_STEALTH; 3866 plugin->myoptions |= TCP_OPTIONS_TCP_STEALTH;
3352 lsocks = GNUNET_SERVICE_get_listen_sockets (service); 3867 lsocks = LEGACY_SERVICE_get_listen_sockets (service);
3353 if (NULL != lsocks) 3868 if (NULL != lsocks)
3354 { 3869 {
3355 uint32_t len = sizeof (struct WelcomeMessage); 3870 uint32_t len = sizeof (struct WelcomeMessage);
@@ -3442,7 +3957,7 @@ libgnunet_plugin_transport_tcp_init (void *cls)
3442 plugin->service = service; 3957 plugin->service = service;
3443 if (NULL != service) 3958 if (NULL != service)
3444 { 3959 {
3445 plugin->server = GNUNET_SERVICE_get_server (service); 3960 plugin->server = LEGACY_SERVICE_get_server (service);
3446 } 3961 }
3447 else 3962 else
3448 { 3963 {
@@ -3505,7 +4020,7 @@ libgnunet_plugin_transport_tcp_init (void *cls)
3505 GNUNET_NAT_unregister (plugin->nat); 4020 GNUNET_NAT_unregister (plugin->nat);
3506 GNUNET_CONTAINER_multipeermap_destroy (plugin->sessionmap); 4021 GNUNET_CONTAINER_multipeermap_destroy (plugin->sessionmap);
3507 if (NULL != service) 4022 if (NULL != service)
3508 GNUNET_SERVICE_stop (service); 4023 LEGACY_SERVICE_stop (service);
3509 GNUNET_free (plugin); 4024 GNUNET_free (plugin);
3510 GNUNET_free_non_null (api); 4025 GNUNET_free_non_null (api);
3511 return NULL; 4026 return NULL;
@@ -3558,7 +4073,7 @@ libgnunet_plugin_transport_tcp_done (void *cls)
3558 } 4073 }
3559 4074
3560 if (NULL != plugin->service) 4075 if (NULL != plugin->service)
3561 GNUNET_SERVICE_stop (plugin->service); 4076 LEGACY_SERVICE_stop (plugin->service);
3562 else 4077 else
3563 GNUNET_SERVER_destroy (plugin->server); 4078 GNUNET_SERVER_destroy (plugin->server);
3564 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 fd8493e5f..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
@@ -1271,10 +1281,7 @@ udp_plugin_check_address (void *cls,
1271 1281
1272 v6 = (const struct IPv6UdpAddress *) addr; 1282 v6 = (const struct IPv6UdpAddress *) addr;
1273 if (IN6_IS_ADDR_LINKLOCAL (&v6->ipv6_addr)) 1283 if (IN6_IS_ADDR_LINKLOCAL (&v6->ipv6_addr))
1274 { 1284 return GNUNET_OK; /* plausible, if unlikely... */
1275 GNUNET_break_op (0);
1276 return GNUNET_SYSERR;
1277 }
1278 memset (&s6, 0, sizeof (s6)); 1285 memset (&s6, 0, sizeof (s6));
1279 s6.sin6_family = AF_INET6; 1286 s6.sin6_family = AF_INET6;
1280#if HAVE_SOCKADDR_IN_SIN_LEN 1287#if HAVE_SOCKADDR_IN_SIN_LEN
@@ -1338,10 +1345,7 @@ udp_nat_port_map_callback (void *cls,
1338 GNUNET_assert (sizeof(struct sockaddr_in) == addrlen); 1345 GNUNET_assert (sizeof(struct sockaddr_in) == addrlen);
1339 i4 = (const struct sockaddr_in *) addr; 1346 i4 = (const struct sockaddr_in *) addr;
1340 if (0 == ntohs (i4->sin_port)) 1347 if (0 == ntohs (i4->sin_port))
1341 { 1348 return; /* Port = 0 means unmapped, ignore these for UDP. */
1342 GNUNET_break (0);
1343 return;
1344 }
1345 memset (&u4, 1349 memset (&u4,
1346 0, 1350 0,
1347 sizeof(u4)); 1351 sizeof(u4));
@@ -1359,10 +1363,7 @@ udp_nat_port_map_callback (void *cls,
1359 GNUNET_assert (sizeof(struct sockaddr_in6) == addrlen); 1363 GNUNET_assert (sizeof(struct sockaddr_in6) == addrlen);
1360 i6 = (const struct sockaddr_in6 *) addr; 1364 i6 = (const struct sockaddr_in6 *) addr;
1361 if (0 == ntohs (i6->sin6_port)) 1365 if (0 == ntohs (i6->sin6_port))
1362 { 1366 return; /* Port = 0 means unmapped, ignore these for UDP. */
1363 GNUNET_break (0);
1364 return;
1365 }
1366 memset (&u6, 1367 memset (&u6,
1367 0, 1368 0,
1368 sizeof(u6)); 1369 sizeof(u6));
@@ -1632,7 +1633,7 @@ enqueue (struct Plugin *plugin,
1632 GNUNET_break (0); 1633 GNUNET_break (0);
1633 return; 1634 return;
1634 } 1635 }
1635 if (plugin->bytes_in_buffer + udpw->msg_size > INT64_MAX) 1636 if (plugin->bytes_in_buffer > INT64_MAX - udpw->msg_size)
1636 { 1637 {
1637 GNUNET_break (0); 1638 GNUNET_break (0);
1638 } 1639 }
@@ -2060,7 +2061,7 @@ udp_plugin_send (void *cls,
2060 if ( (sizeof(struct IPv4UdpAddress) == s->address->address_length) && 2061 if ( (sizeof(struct IPv4UdpAddress) == s->address->address_length) &&
2061 (NULL == plugin->sockv4) ) 2062 (NULL == plugin->sockv4) )
2062 return GNUNET_SYSERR; 2063 return GNUNET_SYSERR;
2063 if (udpmlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) 2064 if (udpmlen >= GNUNET_MAX_MESSAGE_SIZE)
2064 { 2065 {
2065 GNUNET_break (0); 2066 GNUNET_break (0);
2066 return GNUNET_SYSERR; 2067 return GNUNET_SYSERR;
@@ -2508,18 +2509,16 @@ read_process_ack (struct Plugin *plugin,
2508 * Message tokenizer has broken up an incomming message. Pass it on 2509 * Message tokenizer has broken up an incomming message. Pass it on
2509 * to the service. 2510 * to the service.
2510 * 2511 *
2511 * @param cls the `struct Plugin *` 2512 * @param cls the `struct GNUNET_ATS_Session *`
2512 * @param client the `struct GNUNET_ATS_Session *`
2513 * @param hdr the actual message 2513 * @param hdr the actual message
2514 * @return #GNUNET_OK (always) 2514 * @return #GNUNET_OK (always)
2515 */ 2515 */
2516static int 2516static int
2517process_inbound_tokenized_messages (void *cls, 2517process_inbound_tokenized_messages (void *cls,
2518 void *client,
2519 const struct GNUNET_MessageHeader *hdr) 2518 const struct GNUNET_MessageHeader *hdr)
2520{ 2519{
2521 struct Plugin *plugin = cls; 2520 struct GNUNET_ATS_Session *session = cls;
2522 struct GNUNET_ATS_Session *session = client; 2521 struct Plugin *plugin = session->plugin;
2523 2522
2524 if (GNUNET_YES == session->in_destroy) 2523 if (GNUNET_YES == session->in_destroy)
2525 return GNUNET_OK; 2524 return GNUNET_OK;
@@ -2635,6 +2634,8 @@ udp_plugin_create_session (void *cls,
2635 struct GNUNET_ATS_Session *s; 2634 struct GNUNET_ATS_Session *s;
2636 2635
2637 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);
2638 s->plugin = plugin; 2639 s->plugin = plugin;
2639 s->address = GNUNET_HELLO_address_copy (address); 2640 s->address = GNUNET_HELLO_address_copy (address);
2640 s->target = address->peer; 2641 s->target = address->peer;
@@ -2801,12 +2802,11 @@ process_udp_message (struct Plugin *plugin,
2801 GNUNET_free (address); 2802 GNUNET_free (address);
2802 2803
2803 s->rc++; 2804 s->rc++;
2804 GNUNET_SERVER_mst_receive (plugin->mst, 2805 GNUNET_MST_from_buffer (s->mst,
2805 s, 2806 (const char *) &msg[1],
2806 (const char *) &msg[1], 2807 ntohs (msg->header.size) - sizeof(struct UDPMessage),
2807 ntohs (msg->header.size) - sizeof(struct UDPMessage), 2808 GNUNET_YES,
2808 GNUNET_YES, 2809 GNUNET_NO);
2809 GNUNET_NO);
2810 s->rc--; 2810 s->rc--;
2811 if ( (0 == s->rc) && 2811 if ( (0 == s->rc) &&
2812 (GNUNET_YES == s->in_destroy) ) 2812 (GNUNET_YES == s->in_destroy) )
@@ -3999,8 +3999,6 @@ libgnunet_plugin_transport_udp_init (void *cls)
3999 p->sessions = GNUNET_CONTAINER_multipeermap_create (16, 3999 p->sessions = GNUNET_CONTAINER_multipeermap_create (16,
4000 GNUNET_NO); 4000 GNUNET_NO);
4001 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);
4002 p->mst = GNUNET_SERVER_mst_create (&process_inbound_tokenized_messages,
4003 p);
4004 GNUNET_BANDWIDTH_tracker_init (&p->tracker, 4002 GNUNET_BANDWIDTH_tracker_init (&p->tracker,
4005 NULL, 4003 NULL,
4006 NULL, 4004 NULL,
@@ -4017,7 +4015,6 @@ libgnunet_plugin_transport_udp_init (void *cls)
4017 _("Failed to create UDP network sockets\n")); 4015 _("Failed to create UDP network sockets\n"));
4018 GNUNET_CONTAINER_multipeermap_destroy (p->sessions); 4016 GNUNET_CONTAINER_multipeermap_destroy (p->sessions);
4019 GNUNET_CONTAINER_heap_destroy (p->defrag_ctxs); 4017 GNUNET_CONTAINER_heap_destroy (p->defrag_ctxs);
4020 GNUNET_SERVER_mst_destroy (p->mst);
4021 if (NULL != p->nat) 4018 if (NULL != p->nat)
4022 GNUNET_NAT_unregister (p->nat); 4019 GNUNET_NAT_unregister (p->nat);
4023 GNUNET_free (p); 4020 GNUNET_free (p);
@@ -4129,11 +4126,6 @@ libgnunet_plugin_transport_udp_done (void *cls)
4129 GNUNET_CONTAINER_heap_destroy (plugin->defrag_ctxs); 4126 GNUNET_CONTAINER_heap_destroy (plugin->defrag_ctxs);
4130 plugin->defrag_ctxs = NULL; 4127 plugin->defrag_ctxs = NULL;
4131 } 4128 }
4132 if (NULL != plugin->mst)
4133 {
4134 GNUNET_SERVER_mst_destroy (plugin->mst);
4135 plugin->mst = NULL;
4136 }
4137 while (NULL != (udpw = plugin->ipv4_queue_head)) 4129 while (NULL != (udpw = plugin->ipv4_queue_head))
4138 { 4130 {
4139 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_unix.c b/src/transport/plugin_transport_unix.c
index 49a5e89ed..6bcb7290f 100644
--- a/src/transport/plugin_transport_unix.c
+++ b/src/transport/plugin_transport_unix.c
@@ -566,7 +566,7 @@ unix_address_to_sockaddr (const char *unixpath,
566 GNUNET_memcpy (un->sun_path, unixpath, slen); 566 GNUNET_memcpy (un->sun_path, unixpath, slen);
567 un->sun_path[slen] = '\0'; 567 un->sun_path[slen] = '\0';
568 slen = sizeof (struct sockaddr_un); 568 slen = sizeof (struct sockaddr_un);
569#if HAVE_SOCKADDR_IN_SIN_LEN 569#if HAVE_SOCKADDR_UN_SUN_LEN
570 un->sun_len = (u_char) slen; 570 un->sun_len = (u_char) slen;
571#endif 571#endif
572 (*sock_len) = slen; 572 (*sock_len) = slen;
@@ -1229,7 +1229,7 @@ unix_plugin_select_read (void *cls)
1229{ 1229{
1230 struct Plugin *plugin = cls; 1230 struct Plugin *plugin = cls;
1231 const struct GNUNET_SCHEDULER_TaskContext *tc; 1231 const struct GNUNET_SCHEDULER_TaskContext *tc;
1232 1232
1233 plugin->read_task = NULL; 1233 plugin->read_task = NULL;
1234 tc = GNUNET_SCHEDULER_get_task_context (); 1234 tc = GNUNET_SCHEDULER_get_task_context ();
1235 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY)) 1235 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY))
@@ -1252,7 +1252,7 @@ unix_plugin_select_write (void *cls)
1252{ 1252{
1253 struct Plugin *plugin = cls; 1253 struct Plugin *plugin = cls;
1254 const struct GNUNET_SCHEDULER_TaskContext *tc; 1254 const struct GNUNET_SCHEDULER_TaskContext *tc;
1255 1255
1256 plugin->write_task = NULL; 1256 plugin->write_task = NULL;
1257 tc = GNUNET_SCHEDULER_get_task_context (); 1257 tc = GNUNET_SCHEDULER_get_task_context ();
1258 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) 1258 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY))
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 6d3070415..5b219a467 100644
--- a/src/util/connection.c
+++ b/src/transport/tcp_connection_legacy.c
@@ -35,9 +35,17 @@
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", __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", syscall) 48#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-connection", syscall)
41 49
42 50
43/** 51/**
@@ -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;
@@ -335,12 +343,17 @@ GNUNET_CONNECTION_create_from_accept (GNUNET_CONNECTION_AccessCheck access_cb,
335 struct sockaddr_in6 *v6; 343 struct sockaddr_in6 *v6;
336 struct sockaddr *sa; 344 struct sockaddr *sa;
337 void *uaddr; 345 void *uaddr;
338 struct GNUNET_CONNECTION_Credentials *gcp;
339 struct GNUNET_CONNECTION_Credentials gc;
340#ifdef SO_PEERCRED 346#ifdef SO_PEERCRED
341 struct ucred uc; 347 struct ucred uc;
342 socklen_t olen; 348 socklen_t olen;
343#endif 349#endif
350 struct GNUNET_CONNECTION_Credentials *gcp;
351#if HAVE_GETPEEREID || defined(SO_PEERCRED) || HAVE_GETPEERUCRED
352 struct GNUNET_CONNECTION_Credentials gc;
353
354 gc.uid = 0;
355 gc.gid = 0;
356#endif
344 357
345 addrlen = sizeof (addr); 358 addrlen = sizeof (addr);
346 sock = 359 sock =
@@ -386,8 +399,6 @@ GNUNET_CONNECTION_create_from_accept (GNUNET_CONNECTION_AccessCheck access_cb,
386 GNUNET_memcpy (uaddr, addr, addrlen); 399 GNUNET_memcpy (uaddr, addr, addrlen);
387 } 400 }
388 gcp = NULL; 401 gcp = NULL;
389 gc.uid = 0;
390 gc.gid = 0;
391 if (AF_UNIX == sa->sa_family) 402 if (AF_UNIX == sa->sa_family)
392 { 403 {
393#if HAVE_GETPEEREID 404#if HAVE_GETPEEREID
@@ -449,7 +460,7 @@ GNUNET_CONNECTION_create_from_accept (GNUNET_CONNECTION_AccessCheck access_cb,
449 return NULL; 460 return NULL;
450 } 461 }
451 connection = GNUNET_new (struct GNUNET_CONNECTION_Handle); 462 connection = GNUNET_new (struct GNUNET_CONNECTION_Handle);
452 connection->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE; 463 connection->write_buffer_size = GNUNET_MIN_MESSAGE_SIZE;
453 connection->write_buffer = GNUNET_malloc (connection->write_buffer_size); 464 connection->write_buffer = GNUNET_malloc (connection->write_buffer_size);
454 connection->addr = uaddr; 465 connection->addr = uaddr;
455 connection->addrlen = addrlen; 466 connection->addrlen = addrlen;
@@ -822,7 +833,7 @@ try_connect_using_address (void *cls,
822 return; 833 return;
823 } 834 }
824 GNUNET_CONTAINER_DLL_insert (connection->ap_head, connection->ap_tail, ap); 835 GNUNET_CONTAINER_DLL_insert (connection->ap_head, connection->ap_tail, ap);
825 delay = GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT; 836 delay = CONNECT_RETRY_TIMEOUT;
826 if (NULL != connection->nth.notify_ready) 837 if (NULL != connection->nth.notify_ready)
827 delay = GNUNET_TIME_relative_min (delay, 838 delay = GNUNET_TIME_relative_min (delay,
828 GNUNET_TIME_absolute_get_remaining (connection->nth.transmit_timeout)); 839 GNUNET_TIME_absolute_get_remaining (connection->nth.transmit_timeout));
@@ -856,14 +867,14 @@ GNUNET_CONNECTION_create_from_connect (const struct GNUNET_CONFIGURATION_Handle
856 GNUNET_assert (0 < strlen (hostname)); /* sanity check */ 867 GNUNET_assert (0 < strlen (hostname)); /* sanity check */
857 connection = GNUNET_new (struct GNUNET_CONNECTION_Handle); 868 connection = GNUNET_new (struct GNUNET_CONNECTION_Handle);
858 connection->cfg = cfg; 869 connection->cfg = cfg;
859 connection->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE; 870 connection->write_buffer_size = GNUNET_MIN_MESSAGE_SIZE;
860 connection->write_buffer = GNUNET_malloc (connection->write_buffer_size); 871 connection->write_buffer = GNUNET_malloc (connection->write_buffer_size);
861 connection->port = port; 872 connection->port = port;
862 connection->hostname = GNUNET_strdup (hostname); 873 connection->hostname = GNUNET_strdup (hostname);
863 connection->dns_active = 874 connection->dns_active =
864 GNUNET_RESOLVER_ip_get (connection->hostname, 875 GNUNET_RESOLVER_ip_get (connection->hostname,
865 AF_UNSPEC, 876 AF_UNSPEC,
866 GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT, 877 CONNECT_RETRY_TIMEOUT,
867 &try_connect_using_address, 878 &try_connect_using_address,
868 connection); 879 connection);
869 return connection; 880 return connection;
@@ -902,12 +913,12 @@ GNUNET_CONNECTION_create_from_connect_to_unixpath (const struct GNUNET_CONFIGURA
902 un->sun_path[0] = '\0'; 913 un->sun_path[0] = '\0';
903 } 914 }
904#endif 915#endif
905#if HAVE_SOCKADDR_IN_SIN_LEN 916#if HAVE_SOCKADDR_UN_SUN_LEN
906 un->sun_len = (u_char) sizeof (struct sockaddr_un); 917 un->sun_len = (u_char) sizeof (struct sockaddr_un);
907#endif 918#endif
908 connection = GNUNET_new (struct GNUNET_CONNECTION_Handle); 919 connection = GNUNET_new (struct GNUNET_CONNECTION_Handle);
909 connection->cfg = cfg; 920 connection->cfg = cfg;
910 connection->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE; 921 connection->write_buffer_size = GNUNET_MIN_MESSAGE_SIZE;
911 connection->write_buffer = GNUNET_malloc (connection->write_buffer_size); 922 connection->write_buffer = GNUNET_malloc (connection->write_buffer_size);
912 connection->port = 0; 923 connection->port = 0;
913 connection->hostname = NULL; 924 connection->hostname = NULL;
@@ -1012,7 +1023,7 @@ GNUNET_CONNECTION_create_from_sockaddr (int af_family,
1012 return NULL; 1023 return NULL;
1013 } 1024 }
1014 return GNUNET_CONNECTION_connect_socket (s, 1025 return GNUNET_CONNECTION_connect_socket (s,
1015 serv_addr, 1026 serv_addr,
1016 addrlen); 1027 addrlen);
1017} 1028}
1018 1029
@@ -1533,7 +1544,7 @@ GNUNET_CONNECTION_notify_transmit_ready (struct GNUNET_CONNECTION_Handle *connec
1533 return NULL; 1544 return NULL;
1534 } 1545 }
1535 GNUNET_assert (NULL != notify); 1546 GNUNET_assert (NULL != notify);
1536 GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE); 1547 GNUNET_assert (size < GNUNET_MAX_MESSAGE_SIZE);
1537 GNUNET_assert (connection->write_buffer_off <= connection->write_buffer_size); 1548 GNUNET_assert (connection->write_buffer_off <= connection->write_buffer_size);
1538 GNUNET_assert (connection->write_buffer_pos <= connection->write_buffer_size); 1549 GNUNET_assert (connection->write_buffer_pos <= connection->write_buffer_size);
1539 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 00e37c9d9..6b4daa525 100644
--- a/src/util/server.c
+++ b/src/transport/tcp_server_legacy.c
@@ -28,11 +28,7 @@
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", __VA_ARGS__) 31#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util-server", syscall, filename)
32
33#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall)
34
35#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
36 32
37 33
38/** 34/**
@@ -945,9 +941,9 @@ GNUNET_SERVER_inject (struct GNUNET_SERVER_Handle *server,
945 941
946 type = ntohs (message->type); 942 type = ntohs (message->type);
947 size = ntohs (message->size); 943 size = ntohs (message->size);
948 LOG (GNUNET_ERROR_TYPE_DEBUG, 944 LOG (GNUNET_ERROR_TYPE_INFO,
949 "Server schedules transmission of %u-byte message of type %u to client.\n", 945 "Received message of type %u and size %u from client\n",
950 size, type); 946 type, size);
951 found = GNUNET_NO; 947 found = GNUNET_NO;
952 for (pos = server->handlers; NULL != pos; pos = pos->next) 948 for (pos = server->handlers; NULL != pos; pos = pos->next)
953 { 949 {
@@ -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);
@@ -1240,8 +1236,8 @@ client_message_tokenizer_callback (void *cls,
1240 int ret; 1236 int ret;
1241 1237
1242 LOG (GNUNET_ERROR_TYPE_DEBUG, 1238 LOG (GNUNET_ERROR_TYPE_DEBUG,
1243 "Tokenizer gives server message of type %u from client\n", 1239 "Tokenizer gives server message of type %u and size %u from client\n",
1244 ntohs (message->type)); 1240 ntohs (message->type), ntohs (message->size));
1245 sender->in_process_client_buffer = GNUNET_YES; 1241 sender->in_process_client_buffer = GNUNET_YES;
1246 ret = GNUNET_SERVER_inject (server, sender, message); 1242 ret = GNUNET_SERVER_inject (server, sender, message);
1247 sender->in_process_client_buffer = GNUNET_NO; 1243 sender->in_process_client_buffer = GNUNET_NO;
@@ -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 8c9bc4b5b..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", __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..1f1f6c063
--- /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_cfgfile (&opt_cfg_fn),
1396 GNUNET_GETOPT_option_flag ('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_address_switch.c b/src/transport/test_transport_address_switch.c
index 77bc9aef8..e076d3501 100644
--- a/src/transport/test_transport_address_switch.c
+++ b/src/transport/test_transport_address_switch.c
@@ -49,9 +49,9 @@
49 49
50 50
51/** 51/**
52 * Testcase timeout 52 * Testcase timeout (set aggressively as we know this test doesn't work right now)
53 */ 53 */
54#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) 54#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
55 55
56 56
57static struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc; 57static struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
@@ -199,7 +199,7 @@ custom_shutdown (void *cls)
199 { 199 {
200 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 200 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
201 "Fail (timeout)! No transmission after switch! Stopping peers\n"); 201 "Fail (timeout)! No transmission after switch! Stopping peers\n");
202 ccc->global_ret = GNUNET_SYSERR; 202 ccc->global_ret = 77; /* GNUNET_SYSERR; */
203 } 203 }
204 204
205 /* stop statistics */ 205 /* stop statistics */
@@ -277,8 +277,11 @@ custom_shutdown (void *cls)
277 GNUNET_break (0); 277 GNUNET_break (0);
278 result++; 278 result++;
279 } 279 }
280#if 0
281 /* This test is not really expected to pass right now... */
280 if (0 != result) 282 if (0 != result)
281 ccc->global_ret = GNUNET_SYSERR; 283 ccc->global_ret = GNUNET_SYSERR;
284#endif
282} 285}
283 286
284 287
@@ -298,7 +301,7 @@ notify_receive (void *cls,
298 "Peer %u (`%s') got message %u of size %u from peer (`%s')\n", 301 "Peer %u (`%s') got message %u of size %u from peer (`%s')\n",
299 receiver->no, 302 receiver->no,
300 ps, 303 ps,
301 ntohl (hdr->num), 304 (uint32_t) ntohl (hdr->num),
302 ntohs (hdr->header.size), 305 ntohs (hdr->header.size),
303 GNUNET_i2s (sender)); 306 GNUNET_i2s (sender));
304 GNUNET_free (ps); 307 GNUNET_free (ps);
diff --git a/src/transport/test_transport_api_reliability.c b/src/transport/test_transport_api_reliability.c
index d6702cc25..e5ba2831b 100644
--- a/src/transport/test_transport_api_reliability.c
+++ b/src/transport/test_transport_api_reliability.c
@@ -91,7 +91,7 @@ get_size (unsigned int iter)
91#ifndef LINUX 91#ifndef LINUX
92 /* FreeBSD/OSX etc. Unix DGRAMs do not work 92 /* FreeBSD/OSX etc. Unix DGRAMs do not work
93 * with large messages */ 93 * with large messages */
94 if (0 == strcmp ("unix", test_plugin)) 94 if (0 == strcmp ("unix", ccc->test_plugin))
95 ret = sizeof (struct GNUNET_TRANSPORT_TESTING_TestMessage) + (ret % 1024); 95 ret = sizeof (struct GNUNET_TRANSPORT_TESTING_TestMessage) + (ret % 1024);
96#endif 96#endif
97 ret = sizeof (struct GNUNET_TRANSPORT_TESTING_TestMessage) + (ret % 60000); 97 ret = sizeof (struct GNUNET_TRANSPORT_TESTING_TestMessage) + (ret % 60000);
@@ -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;
@@ -228,10 +228,10 @@ notify_receive (void *cls,
228 { 228 {
229 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 229 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
230 "Expected message %u of size %u, got %u bytes of message %u\n", 230 "Expected message %u of size %u, got %u bytes of message %u\n",
231 ntohl (hdr->num), 231 (uint32_t) ntohl (hdr->num),
232 s, 232 s,
233 ntohs (hdr->header.size), 233 ntohs (hdr->header.size),
234 ntohl (hdr->num)); 234 (uint32_t) ntohl (hdr->num));
235 ccc->global_ret = GNUNET_SYSERR; 235 ccc->global_ret = GNUNET_SYSERR;
236 GNUNET_SCHEDULER_shutdown (); 236 GNUNET_SCHEDULER_shutdown ();
237 return; 237 return;
@@ -247,7 +247,7 @@ notify_receive (void *cls,
247 { 247 {
248 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 248 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
249 "Expected message %u with bits %u, but body did not match\n", 249 "Expected message %u with bits %u, but body did not match\n",
250 ntohl (hdr->num), 250 (uint32_t) ntohl (hdr->num),
251 (unsigned char) ntohl (hdr->num)); 251 (unsigned char) ntohl (hdr->num));
252 ccc->global_ret = GNUNET_SYSERR; 252 ccc->global_ret = GNUNET_SYSERR;
253 GNUNET_SCHEDULER_shutdown (); 253 GNUNET_SCHEDULER_shutdown ();
@@ -258,7 +258,7 @@ notify_receive (void *cls,
258 { 258 {
259 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 259 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
260 "Got message %u of size %u\n", 260 "Got message %u of size %u\n",
261 ntohl (hdr->num), 261 (uint32_t) ntohl (hdr->num),
262 ntohs (hdr->header.size)); 262 ntohs (hdr->header.size));
263 } 263 }
264#endif 264#endif
@@ -267,7 +267,7 @@ notify_receive (void *cls,
267 { 267 {
268 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 268 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
269 "Message id %u is bigger than maxmimum number of messages %u expected\n", 269 "Message id %u is bigger than maxmimum number of messages %u expected\n",
270 ntohl (hdr->num), 270 (uint32_t) ntohl (hdr->num),
271 TOTAL_MSGS / xhdr); 271 TOTAL_MSGS / xhdr);
272 } 272 }
273 if (0 == (n % (TOTAL_MSGS / xhdr / 100))) 273 if (0 == (n % (TOTAL_MSGS / xhdr / 100)))
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.conf.in b/src/transport/transport.conf.in
index 7b5413bbe..2c99af000 100644
--- a/src/transport/transport.conf.in
+++ b/src/transport/transport.conf.in
@@ -4,6 +4,8 @@ AUTOSTART = @AUTOSTART@
4HOSTNAME = localhost 4HOSTNAME = localhost
5BINARY = gnunet-service-transport 5BINARY = gnunet-service-transport
6# PREFIX = valgrind 6# PREFIX = valgrind
7
8# Maximum number of neighbours PER PLUGIN (not in total).
7NEIGHBOUR_LIMIT = 50 9NEIGHBOUR_LIMIT = 50
8ACCEPT_FROM = 127.0.0.1; 10ACCEPT_FROM = 127.0.0.1;
9ACCEPT_FROM6 = ::1; 11ACCEPT_FROM6 = ::1;
@@ -65,8 +67,6 @@ MAX_CONNECTIONS = 128
65# Enable TCP stealth? 67# Enable TCP stealth?
66TCP_STEALTH = NO 68TCP_STEALTH = NO
67 69
68# Configuration for manually punched holes in NAT.
69# HOLE_EXTERNAL = auto:2086
70 70
71[transport-udp] 71[transport-udp]
72# Use PORT = 0 to autodetect a port available 72# Use PORT = 0 to autodetect a port available
@@ -110,6 +110,7 @@ TESTING_IGNORE_KEYS = ACCEPT_FROM;
110# Experimental, default: NO 110# Experimental, default: NO
111# PROXY_HTTP_TUNNELING = NO 111# PROXY_HTTP_TUNNELING = NO
112 112
113
113[transport-http_server] 114[transport-http_server]
114#EXTERNAL_HOSTNAME = <your hostname/path> 115#EXTERNAL_HOSTNAME = <your hostname/path>
115PORT = 1080 116PORT = 1080
@@ -122,8 +123,7 @@ ADVERTISED_PORT = 1080
122# Can use IPv6 addresses ([fefc::]:PORT). 123# Can use IPv6 addresses ([fefc::]:PORT).
123# Use "AUTO" for the hostname to automatically detect external IP. 124# Use "AUTO" for the hostname to automatically detect external IP.
124# Do not set if NAT is not manually punched. 125# Do not set if NAT is not manually punched.
125# HOLE_EXTERNAL = AUTO:2086 126# HOLE_EXTERNAL = AUTO:1080
126
127 127
128MAX_CONNECTIONS = 128 128MAX_CONNECTIONS = 128
129TESTING_IGNORE_KEYS = ACCEPT_FROM; 129TESTING_IGNORE_KEYS = ACCEPT_FROM;
@@ -131,8 +131,6 @@ TESTING_IGNORE_KEYS = ACCEPT_FROM;
131# Enable TCP stealth? 131# Enable TCP stealth?
132TCP_STEALTH = NO 132TCP_STEALTH = NO
133 133
134# Configuration for manually punched holes in NAT.
135# HOLE_EXTERNAL = auto:2086
136 134
137[transport-https_client] 135[transport-https_client]
138MAX_CONNECTIONS = 128 136MAX_CONNECTIONS = 128
@@ -155,7 +153,6 @@ TESTING_IGNORE_KEYS = ACCEPT_FROM;
155# PROXY_HTTP_TUNNELING = NO 153# PROXY_HTTP_TUNNELING = NO
156 154
157 155
158
159[transport-https_server] 156[transport-https_server]
160# EXTERNAL_HOSTNAME = <your hostname/path> 157# EXTERNAL_HOSTNAME = <your hostname/path>
161# EXTERNAL_HOSTNAME_ONLY = YES 158# EXTERNAL_HOSTNAME_ONLY = YES
@@ -174,7 +171,7 @@ ADVERTISED_PORT = 4433
174# Can use IPv6 addresses ([fefc::]:PORT). 171# Can use IPv6 addresses ([fefc::]:PORT).
175# Use "AUTO" for the hostname to automatically detect external IP. 172# Use "AUTO" for the hostname to automatically detect external IP.
176# Do not set if NAT is not manually punched. 173# Do not set if NAT is not manually punched.
177# HOLE_EXTERNAL = AUTO:2086 174# HOLE_EXTERNAL = AUTO:4433
178 175
179CRYPTO_INIT = NORMAL 176CRYPTO_INIT = NORMAL
180KEY_FILE = $GNUNET_DATA_HOME/transport/https.key 177KEY_FILE = $GNUNET_DATA_HOME/transport/https.key
@@ -185,9 +182,6 @@ TESTING_IGNORE_KEYS = ACCEPT_FROM;
185# Enable TCP stealth? 182# Enable TCP stealth?
186TCP_STEALTH = NO 183TCP_STEALTH = NO
187 184
188# Configuration for manually punched holes in NAT.
189# HOLE_EXTERNAL = auto:2086
190
191 185
192[transport-wlan] 186[transport-wlan]
193# Name of the interface in monitor mode (typically monX) 187# Name of the interface in monitor mode (typically monX)
@@ -196,6 +190,7 @@ INTERFACE = mon0
196TESTMODE = 0 190TESTMODE = 0
197TESTING_IGNORE_KEYS = ACCEPT_FROM; 191TESTING_IGNORE_KEYS = ACCEPT_FROM;
198 192
193
199[transport-bluetooth] 194[transport-bluetooth]
200# Name of the interface (typically hciX) 195# Name of the interface (typically hciX)
201INTERFACE = hci0 196INTERFACE = hci0
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 a693cb889..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);
@@ -447,7 +447,8 @@ mq_send_impl (struct GNUNET_MQ_Handle *mq,
447 GNUNET_MQ_send (h->mq, 447 GNUNET_MQ_send (h->mq,
448 n->env); 448 n->env);
449 LOG (GNUNET_ERROR_TYPE_DEBUG, 449 LOG (GNUNET_ERROR_TYPE_DEBUG,
450 "Queued message for neighbour `%s'.\n", 450 "Queued message of type %u for neighbour `%s'.\n",
451 ntohs (msg->type),
451 GNUNET_i2s (&n->id)); 452 GNUNET_i2s (&n->id));
452} 453}
453 454
diff --git a/src/tun/Makefile.am b/src/tun/Makefile.am
index d8eb2767e..c741f5654 100644
--- a/src/tun/Makefile.am
+++ b/src/tun/Makefile.am
@@ -28,7 +28,7 @@ check_PROGRAMS = \
28 test_regex 28 test_regex
29 29
30if ENABLE_TEST_RUN 30if ENABLE_TEST_RUN
31AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; 31AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
32TESTS = $(check_PROGRAMS) 32TESTS = $(check_PROGRAMS)
33endif 33endif
34 34
diff --git a/src/util/.gitignore b/src/util/.gitignore
index f207e07bf..3576a2134 100644
--- a/src/util/.gitignore
+++ b/src/util/.gitignore
@@ -22,6 +22,7 @@ test_connection_timeout.nc
22test_connection_timeout_no_connect.nc 22test_connection_timeout_no_connect.nc
23test_connection_transmit_cancel.nc 23test_connection_transmit_cancel.nc
24test_container_bloomfilter 24test_container_bloomfilter
25test_container_dll
25test_container_heap 26test_container_heap
26test_container_meta_data 27test_container_meta_data
27test_container_multihashmap 28test_container_multihashmap
@@ -63,3 +64,6 @@ test_strings
63test_strings_to_data 64test_strings_to_data
64test_time 65test_time
65test_socks.nc 66test_socks.nc
67perf_crypto_asymmetric
68perf_crypto_hash
69perf_crypto_symmetric
diff --git a/src/util/Makefile.am b/src/util/Makefile.am
index f49aee17f..9be572bb6 100644
--- a/src/util/Makefile.am
+++ b/src/util/Makefile.am
@@ -30,7 +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
34else
35 TEST_CLIENT_UNIX_NC =
34endif 36endif
35 37
36if USE_COVERAGE 38if USE_COVERAGE
@@ -65,7 +67,6 @@ libgnunetutil_la_SOURCES = \
65 common_logging.c \ 67 common_logging.c \
66 configuration.c \ 68 configuration.c \
67 configuration_loader.c \ 69 configuration_loader.c \
68 connection.c \
69 container_bloomfilter.c \ 70 container_bloomfilter.c \
70 container_heap.c \ 71 container_heap.c \
71 container_meta_data.c \ 72 container_meta_data.c \
@@ -105,16 +106,10 @@ libgnunetutil_la_SOURCES = \
105 program.c \ 106 program.c \
106 resolver_api.c resolver.h \ 107 resolver_api.c resolver.h \
107 scheduler.c \ 108 scheduler.c \
108 server.c \
109 server_mst.c \
110 server_nc.c \
111 server_tc.c \
112 service.c \ 109 service.c \
113 service_new.c \
114 signal.c \ 110 signal.c \
115 strings.c \ 111 strings.c \
116 time.c \ 112 time.c \
117 socks.c \
118 speedup.c speedup.h 113 speedup.c speedup.h
119 114
120libgnunetutil_la_LIBADD = \ 115libgnunetutil_la_LIBADD = \
@@ -187,7 +182,7 @@ noinst_PROGRAMS = \
187 182
188 183
189if ENABLE_TEST_RUN 184if ENABLE_TEST_RUN
190AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; 185AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
191TESTS = $(check_PROGRAMS) 186TESTS = $(check_PROGRAMS)
192endif 187endif
193 188
@@ -260,19 +255,19 @@ if HAVE_BENCHMARKS
260endif 255endif
261 256
262if HAVE_SSH_KEY 257if HAVE_SSH_KEY
263 SSH_USING_TESTS = test_socks.nc 258# SSH_USING_TESTS = test_socks.nc
264endif 259endif
265 260
266check_PROGRAMS = \ 261check_PROGRAMS = \
267 test_bio \ 262 test_bio \
268 test_client.nc \ 263 test_client.nc \
269 test_client_unix.nc \ 264 $(TEST_CLIENT_UNIX_NC) \
270 $(SSH_USING_TESTS) \
271 test_common_allocation \ 265 test_common_allocation \
272 test_common_endian \ 266 test_common_endian \
273 test_common_logging \ 267 test_common_logging \
274 test_configuration \ 268 test_configuration \
275 test_container_bloomfilter \ 269 test_container_bloomfilter \
270 test_container_dll \
276 test_container_meta_data \ 271 test_container_meta_data \
277 test_container_multihashmap \ 272 test_container_multihashmap \
278 test_container_multihashmap32 \ 273 test_container_multihashmap32 \
@@ -294,12 +289,6 @@ check_PROGRAMS = \
294 test_crypto_rsa \ 289 test_crypto_rsa \
295 test_disk \ 290 test_disk \
296 test_getopt \ 291 test_getopt \
297 test_connection.nc \
298 test_connection_addressing.nc \
299 test_connection_receive_cancel.nc \
300 test_connection_timeout.nc \
301 test_connection_timeout_no_connect.nc \
302 test_connection_transmit_cancel.nc \
303 test_mq \ 292 test_mq \
304 test_os_network \ 293 test_os_network \
305 test_peer \ 294 test_peer \
@@ -308,11 +297,6 @@ check_PROGRAMS = \
308 test_resolver_api.nc \ 297 test_resolver_api.nc \
309 test_scheduler \ 298 test_scheduler \
310 test_scheduler_delay \ 299 test_scheduler_delay \
311 test_server.nc \
312 test_server_disconnect.nc \
313 test_server_with_client.nc \
314 test_server_mst_interrupt.nc \
315 $(SERVER_CLIENT_UNIX) \
316 test_service \ 300 test_service \
317 test_strings \ 301 test_strings \
318 test_strings_to_data \ 302 test_strings_to_data \
@@ -326,18 +310,7 @@ check_PROGRAMS = \
326# 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
327# sequential execution order for them 311# sequential execution order for them
328TEST_EXTENSIONS = .nc 312TEST_EXTENSIONS = .nc
329test_connection.log: test_client.log 313test_test_client_unix.log: test_client.log
330test_connection_addressing.log: test_connection.log
331test_connection_timeout_no_connect.log: test_connection_addressing.log
332test_connection_transmit_cancel.log: test_connection_timeout_no_connect.log
333test_connection_receive_cancel.log: test_connection_transmit_cancel.log
334test_connection_timeout.log: test_connection_receive_cancel.log
335test_resolver_api.log: test_connection_timeout.log
336test_server.log: test_resolver_api.log
337test_server_disconnect.log: test_server.log
338test_server_with_client.log: test_server_disconnect.log
339test_server_mst_interrupt.log: test_server_with_client.log
340test_client_unix.log: test_server_mst_interrupt.log
341 314
342test_bio_SOURCES = \ 315test_bio_SOURCES = \
343 test_bio.c 316 test_bio.c
@@ -398,10 +371,15 @@ test_container_bloomfilter_SOURCES = \
398test_container_bloomfilter_LDADD = \ 371test_container_bloomfilter_LDADD = \
399 libgnunetutil.la 372 libgnunetutil.la
400 373
374test_container_dll_SOURCES = \
375 test_container_dll.c
376test_container_dll_LDADD = \
377 libgnunetutil.la
378
401test_container_meta_data_SOURCES = \ 379test_container_meta_data_SOURCES = \
402 test_container_meta_data.c 380 test_container_meta_data.c
403test_container_meta_data_LDADD = \ 381test_container_meta_data_LDADD = \
404 libgnunetutil.la -lextractor 382 libgnunetutil.la
405 383
406test_container_multihashmap_SOURCES = \ 384test_container_multihashmap_SOURCES = \
407 test_container_multihashmap.c 385 test_container_multihashmap.c
@@ -509,36 +487,6 @@ test_getopt_SOURCES = \
509test_getopt_LDADD = \ 487test_getopt_LDADD = \
510 libgnunetutil.la 488 libgnunetutil.la
511 489
512test_connection_nc_SOURCES = \
513 test_connection.c
514test_connection_nc_LDADD = \
515 libgnunetutil.la
516
517test_connection_addressing_nc_SOURCES = \
518 test_connection_addressing.c
519test_connection_addressing_nc_LDADD = \
520 libgnunetutil.la
521
522test_connection_receive_cancel_nc_SOURCES = \
523 test_connection_receive_cancel.c
524test_connection_receive_cancel_nc_LDADD = \
525 libgnunetutil.la
526
527test_connection_timeout_nc_SOURCES = \
528 test_connection_timeout.c
529test_connection_timeout_nc_LDADD = \
530 libgnunetutil.la
531
532test_connection_timeout_no_connect_nc_SOURCES = \
533 test_connection_timeout_no_connect.c
534test_connection_timeout_no_connect_nc_LDADD = \
535 libgnunetutil.la
536
537test_connection_transmit_cancel_nc_SOURCES = \
538 test_connection_transmit_cancel.c
539test_connection_transmit_cancel_nc_LDADD = \
540 libgnunetutil.la
541
542test_mq_SOURCES = \ 490test_mq_SOURCES = \
543 test_mq.c 491 test_mq.c
544test_mq_LDADD = \ 492test_mq_LDADD = \
@@ -579,32 +527,6 @@ test_scheduler_delay_SOURCES = \
579test_scheduler_delay_LDADD = \ 527test_scheduler_delay_LDADD = \
580 libgnunetutil.la 528 libgnunetutil.la
581 529
582test_server_mst_interrupt_nc_SOURCES = \
583 test_server_mst_interrupt.c
584test_server_mst_interrupt_nc_LDADD = \
585 libgnunetutil.la
586
587test_server_nc_SOURCES = \
588 test_server.c
589test_server_nc_LDADD = \
590 libgnunetutil.la
591
592test_server_disconnect_nc_SOURCES = \
593 test_server_disconnect.c
594test_server_disconnect_nc_LDADD = \
595 libgnunetutil.la
596
597test_server_with_client_nc_SOURCES = \
598 test_server_with_client.c
599test_server_with_client_nc_LDADD = \
600 libgnunetutil.la
601
602test_server_with_client_unix_SOURCES = \
603 test_server_with_client_unix.c
604test_server_with_client_unix_LDADD = \
605 libgnunetutil.la
606
607
608test_service_SOURCES = \ 530test_service_SOURCES = \
609 test_service.c 531 test_service.c
610test_service_LDADD = \ 532test_service_LDADD = \
@@ -615,7 +537,6 @@ test_strings_SOURCES = \
615test_strings_LDADD = \ 537test_strings_LDADD = \
616 libgnunetutil.la 538 libgnunetutil.la
617 539
618
619test_strings_to_data_SOURCES = \ 540test_strings_to_data_SOURCES = \
620 test_strings_to_data.c 541 test_strings_to_data.c
621test_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/bio.c b/src/util/bio.c
index 62f4904f7..08e30dc01 100644
--- a/src/util/bio.c
+++ b/src/util/bio.c
@@ -25,7 +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#define LOG(kind,...) GNUNET_log_from (kind, "util",__VA_ARGS__) 28#define LOG(kind,...) GNUNET_log_from (kind, "util-bio",__VA_ARGS__)
29 29
30#ifndef PATH_MAX 30#ifndef PATH_MAX
31/** 31/**
diff --git a/src/util/client.c b/src/util/client.c
index 4fd971040..3d74bff33 100644
--- a/src/util/client.c
+++ b/src/util/client.c
@@ -33,7 +33,16 @@
33#include "gnunet_socks.h" 33#include "gnunet_socks.h"
34 34
35 35
36#define LOG(kind,...) GNUNET_log_from (kind, "util",__VA_ARGS__) 36#define LOG(kind,...) GNUNET_log_from (kind, "util-client",__VA_ARGS__)
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
37 46
38 47
39/** 48/**
@@ -298,6 +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;
310 LOG (GNUNET_ERROR_TYPE_DEBUG,
311 "Received message of type %u and size %u from %s\n",
312 ntohs (msg->type),
313 ntohs (msg->size),
314 cstate->service_name);
301 GNUNET_MQ_inject_message (cstate->mq, 315 GNUNET_MQ_inject_message (cstate->mq,
302 msg); 316 msg);
303 if (GNUNET_YES == cstate->in_destroy) 317 if (GNUNET_YES == cstate->in_destroy)
@@ -491,8 +505,8 @@ try_unixpath (const char *service_name,
491 s_un.sun_path[0] = '\0'; 505 s_un.sun_path[0] = '\0';
492 } 506 }
493#endif 507#endif
494#if HAVE_SOCKADDR_IN_SIN_LEN 508#if HAVE_SOCKADDR_UN_SUN_LEN
495 un.sun_len = (u_char) sizeof (struct sockaddr_un); 509 s_un.sun_len = (u_char) sizeof (struct sockaddr_un);
496#endif 510#endif
497 sock = GNUNET_NETWORK_socket_create (AF_UNIX, 511 sock = GNUNET_NETWORK_socket_create (AF_UNIX,
498 SOCK_STREAM, 512 SOCK_STREAM,
@@ -510,6 +524,8 @@ try_unixpath (const char *service_name,
510 GNUNET_free (unixpath); 524 GNUNET_free (unixpath);
511 return sock; 525 return sock;
512 } 526 }
527 if (NULL != sock)
528 GNUNET_NETWORK_socket_close (sock);
513 } 529 }
514 GNUNET_free_non_null (unixpath); 530 GNUNET_free_non_null (unixpath);
515#endif 531#endif
@@ -649,7 +665,7 @@ try_connect_using_address (void *cls,
649 GNUNET_CONTAINER_DLL_insert (cstate->ap_head, 665 GNUNET_CONTAINER_DLL_insert (cstate->ap_head,
650 cstate->ap_tail, 666 cstate->ap_tail,
651 ap); 667 ap);
652 ap->task = GNUNET_SCHEDULER_add_write_net (GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT, 668 ap->task = GNUNET_SCHEDULER_add_write_net (CONNECT_RETRY_TIMEOUT,
653 ap->sock, 669 ap->sock,
654 &connect_probe_continuation, 670 &connect_probe_continuation,
655 ap); 671 ap);
@@ -753,7 +769,7 @@ start_connect (void *cls)
753 cstate->dns_active 769 cstate->dns_active
754 = GNUNET_RESOLVER_ip_get (cstate->hostname, 770 = GNUNET_RESOLVER_ip_get (cstate->hostname,
755 AF_UNSPEC, 771 AF_UNSPEC,
756 GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT, 772 CONNECT_RETRY_TIMEOUT,
757 &try_connect_using_address, 773 &try_connect_using_address,
758 cstate); 774 cstate);
759} 775}
@@ -877,4 +893,4 @@ GNUNET_CLIENT_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
877 return cstate->mq; 893 return cstate->mq;
878} 894}
879 895
880/* end of client_new.c */ 896/* end of client.c */
diff --git a/src/util/common_allocation.c b/src/util/common_allocation.c
index 71a2221ee..737584815 100644
--- a/src/util/common_allocation.c
+++ b/src/util/common_allocation.c
@@ -32,9 +32,9 @@
32#include <malloc/malloc.h> 32#include <malloc/malloc.h>
33#endif 33#endif
34 34
35#define LOG(kind,...) GNUNET_log_from (kind, "util",__VA_ARGS__) 35#define LOG(kind,...) GNUNET_log_from (kind, "util-common-allocation",__VA_ARGS__)
36 36
37#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall) 37#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-common-allocation", syscall)
38 38
39#ifndef INT_MAX 39#ifndef INT_MAX
40#define INT_MAX 0x7FFFFFFF 40#define INT_MAX 0x7FFFFFFF
diff --git a/src/util/common_endian.c b/src/util/common_endian.c
index 4c8ad7182..f29e42c98 100644
--- a/src/util/common_endian.c
+++ b/src/util/common_endian.c
@@ -28,7 +28,7 @@
28#include "platform.h" 28#include "platform.h"
29#include "gnunet_crypto_lib.h" 29#include "gnunet_crypto_lib.h"
30 30
31#define LOG(kind,...) GNUNET_log_from (kind, "util",__VA_ARGS__) 31#define LOG(kind,...) GNUNET_log_from (kind, "util-common-endian",__VA_ARGS__)
32 32
33 33
34uint64_t 34uint64_t
diff --git a/src/util/configuration_loader.c b/src/util/configuration_loader.c
index 07eeb98f0..ceaf2a6ea 100644
--- a/src/util/configuration_loader.c
+++ b/src/util/configuration_loader.c
@@ -27,7 +27,7 @@
27#include "platform.h" 27#include "platform.h"
28#include "gnunet_util_lib.h" 28#include "gnunet_util_lib.h"
29 29
30#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) 30#define LOG(kind,...) GNUNET_log_from (kind, "util-configuration", __VA_ARGS__)
31 31
32 32
33/** 33/**
diff --git a/src/util/container_bloomfilter.c b/src/util/container_bloomfilter.c
index 58725dcc5..aedca232d 100644
--- a/src/util/container_bloomfilter.c
+++ b/src/util/container_bloomfilter.c
@@ -42,11 +42,11 @@
42#include "platform.h" 42#include "platform.h"
43#include "gnunet_util_lib.h" 43#include "gnunet_util_lib.h"
44 44
45#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) 45#define LOG(kind,...) GNUNET_log_from (kind, "util-container-bloomfilter", __VA_ARGS__)
46 46
47#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall) 47#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-container-bloomfilter", syscall)
48 48
49#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename) 49#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util-container-bloomfilter", syscall, filename)
50 50
51struct GNUNET_CONTAINER_BloomFilter 51struct GNUNET_CONTAINER_BloomFilter
52{ 52{
diff --git a/src/util/container_heap.c b/src/util/container_heap.c
index 1ead5ec6d..21bdee834 100644
--- a/src/util/container_heap.c
+++ b/src/util/container_heap.c
@@ -28,7 +28,7 @@
28#include "platform.h" 28#include "platform.h"
29#include "gnunet_container_lib.h" 29#include "gnunet_container_lib.h"
30 30
31#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) 31#define LOG(kind,...) GNUNET_log_from (kind, "util-container-heap", __VA_ARGS__)
32 32
33#define EXTRA_CHECKS 0 33#define EXTRA_CHECKS 0
34 34
diff --git a/src/util/container_meta_data.c b/src/util/container_meta_data.c
index b4d231dae..ec527005a 100644
--- a/src/util/container_meta_data.c
+++ b/src/util/container_meta_data.c
@@ -31,7 +31,7 @@
31#endif 31#endif
32#include <zlib.h> 32#include <zlib.h>
33 33
34#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) 34#define LOG(kind,...) GNUNET_log_from (kind, "util-container-meta-data", __VA_ARGS__)
35 35
36 36
37 37
diff --git a/src/util/container_multihashmap.c b/src/util/container_multihashmap.c
index d85562579..ffeb4a71f 100644
--- a/src/util/container_multihashmap.c
+++ b/src/util/container_multihashmap.c
@@ -26,7 +26,7 @@
26#include "platform.h" 26#include "platform.h"
27#include "gnunet_container_lib.h" 27#include "gnunet_container_lib.h"
28 28
29#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) 29#define LOG(kind,...) GNUNET_log_from (kind, "util-container-multihashmap", __VA_ARGS__)
30 30
31/** 31/**
32 * An entry in the hash map with the full key. 32 * An entry in the hash map with the full key.
diff --git a/src/util/container_multihashmap32.c b/src/util/container_multihashmap32.c
index 4cc9b7ebd..d33c3c2d9 100644
--- a/src/util/container_multihashmap32.c
+++ b/src/util/container_multihashmap32.c
@@ -28,7 +28,7 @@
28#include "platform.h" 28#include "platform.h"
29#include "gnunet_container_lib.h" 29#include "gnunet_container_lib.h"
30 30
31#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) 31#define LOG(kind,...) GNUNET_log_from (kind, "util-container-multihashmap32", __VA_ARGS__)
32 32
33/** 33/**
34 * An entry in the hash map. 34 * An entry in the hash map.
diff --git a/src/util/container_multipeermap.c b/src/util/container_multipeermap.c
index 6c62e7403..7830771d8 100644
--- a/src/util/container_multipeermap.c
+++ b/src/util/container_multipeermap.c
@@ -26,7 +26,7 @@
26#include "platform.h" 26#include "platform.h"
27#include "gnunet_util_lib.h" 27#include "gnunet_util_lib.h"
28 28
29#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) 29#define LOG(kind,...) GNUNET_log_from (kind, "util-container-multipeermap", __VA_ARGS__)
30 30
31/** 31/**
32 * An entry in the hash map with the full key. 32 * An entry in the hash map with the full key.
diff --git a/src/util/container_multishortmap.c b/src/util/container_multishortmap.c
index 5e8a47b09..cfa82ca20 100644
--- a/src/util/container_multishortmap.c
+++ b/src/util/container_multishortmap.c
@@ -26,7 +26,7 @@
26#include "platform.h" 26#include "platform.h"
27#include "gnunet_util_lib.h" 27#include "gnunet_util_lib.h"
28 28
29#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) 29#define LOG(kind,...) GNUNET_log_from (kind, "util-container-multishortmap", __VA_ARGS__)
30 30
31/** 31/**
32 * An entry in the hash map with the full key. 32 * An entry in the hash map with the full key.
diff --git a/src/util/crypto_crc.c b/src/util/crypto_crc.c
index d7f5f7fc8..03b24d9f7 100644
--- a/src/util/crypto_crc.c
+++ b/src/util/crypto_crc.c
@@ -30,7 +30,7 @@
30#include "platform.h" 30#include "platform.h"
31#include "gnunet_crypto_lib.h" 31#include "gnunet_crypto_lib.h"
32 32
33#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) 33#define LOG(kind,...) GNUNET_log_from (kind, "util-crypto-crc", __VA_ARGS__)
34 34
35/* Avoid wasting space on 8-byte longs. */ 35/* Avoid wasting space on 8-byte longs. */
36#if UINT_MAX >= 0xffffffff 36#if UINT_MAX >= 0xffffffff
diff --git a/src/util/crypto_ecc.c b/src/util/crypto_ecc.c
index 4bba395b3..eaa49a991 100644
--- a/src/util/crypto_ecc.c
+++ b/src/util/crypto_ecc.c
@@ -38,11 +38,11 @@
38 */ 38 */
39#define CURVE "Ed25519" 39#define CURVE "Ed25519"
40 40
41#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) 41#define LOG(kind,...) GNUNET_log_from (kind, "util-crypto-ecc", __VA_ARGS__)
42 42
43#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall) 43#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-crypto-ecc", syscall)
44 44
45#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename) 45#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util-crypto-ecc", syscall, filename)
46 46
47/** 47/**
48 * Log an error message at log-level 'level' that indicates 48 * Log an error message at log-level 'level' that indicates
@@ -488,6 +488,28 @@ struct GNUNET_CRYPTO_EcdhePrivateKey *
488GNUNET_CRYPTO_ecdhe_key_create () 488GNUNET_CRYPTO_ecdhe_key_create ()
489{ 489{
490 struct GNUNET_CRYPTO_EcdhePrivateKey *priv; 490 struct GNUNET_CRYPTO_EcdhePrivateKey *priv;
491
492 priv = GNUNET_new (struct GNUNET_CRYPTO_EcdhePrivateKey);
493 if (GNUNET_OK !=
494 GNUNET_CRYPTO_ecdhe_key_create2 (priv))
495 {
496 GNUNET_free (priv);
497 return NULL;
498 }
499 return priv;
500}
501
502
503/**
504 * @ingroup crypto
505 * Create a new private key. Clear with #GNUNET_CRYPTO_ecdhe_key_clear().
506 *
507 * @param[out] pk set to fresh private key;
508 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
509 */
510int
511GNUNET_CRYPTO_ecdhe_key_create2 (struct GNUNET_CRYPTO_EcdhePrivateKey *pk)
512{
491 gcry_sexp_t priv_sexp; 513 gcry_sexp_t priv_sexp;
492 gcry_sexp_t s_keyparam; 514 gcry_sexp_t s_keyparam;
493 gcry_mpi_t d; 515 gcry_mpi_t d;
@@ -503,13 +525,13 @@ GNUNET_CRYPTO_ecdhe_key_create ()
503 "(flags eddsa no-keytest)))"))) 525 "(flags eddsa no-keytest)))")))
504 { 526 {
505 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc); 527 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
506 return NULL; 528 return GNUNET_SYSERR;
507 } 529 }
508 if (0 != (rc = gcry_pk_genkey (&priv_sexp, s_keyparam))) 530 if (0 != (rc = gcry_pk_genkey (&priv_sexp, s_keyparam)))
509 { 531 {
510 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_genkey", rc); 532 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_genkey", rc);
511 gcry_sexp_release (s_keyparam); 533 gcry_sexp_release (s_keyparam);
512 return NULL; 534 return GNUNET_SYSERR;
513 } 535 }
514 gcry_sexp_release (s_keyparam); 536 gcry_sexp_release (s_keyparam);
515#if EXTRA_CHECKS 537#if EXTRA_CHECKS
@@ -517,20 +539,19 @@ GNUNET_CRYPTO_ecdhe_key_create ()
517 { 539 {
518 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc); 540 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
519 gcry_sexp_release (priv_sexp); 541 gcry_sexp_release (priv_sexp);
520 return NULL; 542 return GNUNET_SYSERR;
521 } 543 }
522#endif 544#endif
523 if (0 != (rc = key_from_sexp (&d, priv_sexp, "private-key", "d"))) 545 if (0 != (rc = key_from_sexp (&d, priv_sexp, "private-key", "d")))
524 { 546 {
525 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "key_from_sexp", rc); 547 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "key_from_sexp", rc);
526 gcry_sexp_release (priv_sexp); 548 gcry_sexp_release (priv_sexp);
527 return NULL; 549 return GNUNET_SYSERR;
528 } 550 }
529 gcry_sexp_release (priv_sexp); 551 gcry_sexp_release (priv_sexp);
530 priv = GNUNET_new (struct GNUNET_CRYPTO_EcdhePrivateKey); 552 GNUNET_CRYPTO_mpi_print_unsigned (pk->d, sizeof (pk->d), d);
531 GNUNET_CRYPTO_mpi_print_unsigned (priv->d, sizeof (priv->d), d);
532 gcry_mpi_release (d); 553 gcry_mpi_release (d);
533 return priv; 554 return GNUNET_OK;
534} 555}
535 556
536 557
diff --git a/src/util/crypto_ecc_setup.c b/src/util/crypto_ecc_setup.c
index 0ce55ddbf..2f2e2f122 100644
--- a/src/util/crypto_ecc_setup.c
+++ b/src/util/crypto_ecc_setup.c
@@ -27,11 +27,11 @@
27#include <gcrypt.h> 27#include <gcrypt.h>
28#include "gnunet_util_lib.h" 28#include "gnunet_util_lib.h"
29 29
30#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) 30#define LOG(kind,...) GNUNET_log_from (kind, "util-crypto-ecc", __VA_ARGS__)
31 31
32#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall) 32#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-crypto-ecc", syscall)
33 33
34#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename) 34#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util-crypto-ecc", syscall, filename)
35 35
36/** 36/**
37 * Log an error message at log-level 'level' that indicates 37 * Log an error message at log-level 'level' that indicates
diff --git a/src/util/crypto_hash.c b/src/util/crypto_hash.c
index 31824e72a..49dbacd0b 100644
--- a/src/util/crypto_hash.c
+++ b/src/util/crypto_hash.c
@@ -28,9 +28,9 @@
28#include "gnunet_strings_lib.h" 28#include "gnunet_strings_lib.h"
29#include <gcrypt.h> 29#include <gcrypt.h>
30 30
31#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) 31#define LOG(kind,...) GNUNET_log_from (kind, "util-crypto-hash", __VA_ARGS__)
32 32
33#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename) 33#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util-crypto-hash", syscall, filename)
34 34
35/** 35/**
36 * Hash block of given size. 36 * Hash block of given size.
diff --git a/src/util/crypto_hash_file.c b/src/util/crypto_hash_file.c
index ace5212c9..3e5900200 100644
--- a/src/util/crypto_hash_file.c
+++ b/src/util/crypto_hash_file.c
@@ -27,9 +27,9 @@
27#include "gnunet_util_lib.h" 27#include "gnunet_util_lib.h"
28#include <gcrypt.h> 28#include <gcrypt.h>
29 29
30#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) 30#define LOG(kind,...) GNUNET_log_from (kind, "util-crypto-hash-file", __VA_ARGS__)
31 31
32#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename) 32#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util-crypto-hash-file", syscall, filename)
33 33
34 34
35/** 35/**
diff --git a/src/util/crypto_hkdf.c b/src/util/crypto_hkdf.c
index c6c43f800..f04d3e675 100644
--- a/src/util/crypto_hkdf.c
+++ b/src/util/crypto_hkdf.c
@@ -36,7 +36,7 @@
36 * - Matthias Wachs (08.10.2010) 36 * - Matthias Wachs (08.10.2010)
37 */ 37 */
38 38
39#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) 39#define LOG(kind,...) GNUNET_log_from (kind, "util-crypto-hkdf", __VA_ARGS__)
40 40
41/** 41/**
42 * Set this to 0 if you compile this code outside of GNUnet. 42 * Set this to 0 if you compile this code outside of GNUnet.
diff --git a/src/util/crypto_kdf.c b/src/util/crypto_kdf.c
index 78fb1911a..6d7c5a096 100644
--- a/src/util/crypto_kdf.c
+++ b/src/util/crypto_kdf.c
@@ -30,7 +30,7 @@
30#include "platform.h" 30#include "platform.h"
31#include "gnunet_crypto_lib.h" 31#include "gnunet_crypto_lib.h"
32 32
33#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) 33#define LOG(kind,...) GNUNET_log_from (kind, "util-crypto-kdf", __VA_ARGS__)
34 34
35/** 35/**
36 * @brief Derive key 36 * @brief Derive key
diff --git a/src/util/crypto_mpi.c b/src/util/crypto_mpi.c
index 668d5e602..ff3e9a8a7 100644
--- a/src/util/crypto_mpi.c
+++ b/src/util/crypto_mpi.c
@@ -29,7 +29,7 @@
29#include "gnunet_crypto_lib.h" 29#include "gnunet_crypto_lib.h"
30 30
31 31
32#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) 32#define LOG(kind,...) GNUNET_log_from (kind, "util-crypto-mpi", __VA_ARGS__)
33 33
34/** 34/**
35 * Log an error message at log-level 'level' that indicates 35 * Log an error message at log-level 'level' that indicates
diff --git a/src/util/crypto_random.c b/src/util/crypto_random.c
index 8897ae24f..d5b5eb9ec 100644
--- a/src/util/crypto_random.c
+++ b/src/util/crypto_random.c
@@ -28,9 +28,9 @@
28#include "gnunet_crypto_lib.h" 28#include "gnunet_crypto_lib.h"
29#include <gcrypt.h> 29#include <gcrypt.h>
30 30
31#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) 31#define LOG(kind,...) GNUNET_log_from (kind, "util-crypto-random", __VA_ARGS__)
32 32
33#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall) 33#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-crypto-random", syscall)
34 34
35 35
36/* TODO: ndurner, move this to plibc? */ 36/* TODO: ndurner, move this to plibc? */
diff --git a/src/util/crypto_rsa.c b/src/util/crypto_rsa.c
index 443d597e4..7a108c21b 100644
--- a/src/util/crypto_rsa.c
+++ b/src/util/crypto_rsa.c
@@ -25,7 +25,7 @@
25#include <gcrypt.h> 25#include <gcrypt.h>
26#include "gnunet_crypto_lib.h" 26#include "gnunet_crypto_lib.h"
27 27
28#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) 28#define LOG(kind,...) GNUNET_log_from (kind, "util-crypto-rsa", __VA_ARGS__)
29 29
30 30
31/** 31/**
@@ -430,7 +430,7 @@ rsa_blinding_key_derive (const struct GNUNET_CRYPTO_RsaPublicKey *pkey,
430 char *xts = "Blinding KDF extrator HMAC key"; /* Trusts bks' randomness more */ 430 char *xts = "Blinding KDF extrator HMAC key"; /* Trusts bks' randomness more */
431 struct RsaBlindingKey *blind; 431 struct RsaBlindingKey *blind;
432 gcry_mpi_t n; 432 gcry_mpi_t n;
433 433
434 blind = GNUNET_new (struct RsaBlindingKey); 434 blind = GNUNET_new (struct RsaBlindingKey);
435 GNUNET_assert( NULL != blind ); 435 GNUNET_assert( NULL != blind );
436 436
@@ -454,25 +454,25 @@ rsa_blinding_key_derive (const struct GNUNET_CRYPTO_RsaPublicKey *pkey,
454} 454}
455 455
456 456
457/* 457/*
458We originally added GNUNET_CRYPTO_kdf_mod_mpi for the benifit of the 458We originally added GNUNET_CRYPTO_kdf_mod_mpi for the benifit of the
459previous routine. 459previous routine.
460 460
461There was previously a call to GNUNET_CRYPTO_kdf in 461There was previously a call to GNUNET_CRYPTO_kdf in
462 bkey = rsa_blinding_key_derive (len, bks); 462 bkey = rsa_blinding_key_derive (len, bks);
463that gives exactly len bits where 463that gives exactly len bits where
464 len = GNUNET_CRYPTO_rsa_public_key_len (pkey); 464 len = GNUNET_CRYPTO_rsa_public_key_len (pkey);
465 465
466Now r = 2^(len-1)/pkey.n is the probability that a set high bit being 466Now r = 2^(len-1)/pkey.n is the probability that a set high bit being
467okay, meaning bkey < pkey.n. It follows that (1-r)/2 of the time bkey > 467okay, meaning bkey < pkey.n. It follows that (1-r)/2 of the time bkey >
468pkey.n making the effective bkey be 468pkey.n making the effective bkey be
469 bkey mod pkey.n = bkey - pkey.n 469 bkey mod pkey.n = bkey - pkey.n
470so the effective bkey has its high bit set with probability r/2. 470so the effective bkey has its high bit set with probability r/2.
471 471
472We expect r to be close to 1/2 if the exchange is honest, but the 472We expect r to be close to 1/2 if the exchange is honest, but the
473exchange can choose r otherwise. 473exchange can choose r otherwise.
474 474
475In blind signing, the exchange sees 475In blind signing, the exchange sees
476 B = bkey * S mod pkey.n 476 B = bkey * S mod pkey.n
477On deposit, the exchange sees S so they can compute bkey' = B/S mod 477On deposit, the exchange sees S so they can compute bkey' = B/S mod
478pkey.n for all B they recorded to see if bkey' has it's high bit set. 478pkey.n for all B they recorded to see if bkey' has it's high bit set.
@@ -489,7 +489,7 @@ the wrong and right probabilities 1/3 and 1/4, respectively.
489I feared this gives the exchange a meaningful fraction of a bit of 489I feared this gives the exchange a meaningful fraction of a bit of
490information per coin involved in the transaction. It sounds damaging if 490information per coin involved in the transaction. It sounds damaging if
491numerous coins were involved. And it could run across transactions in 491numerous coins were involved. And it could run across transactions in
492some scenarios. 492some scenarios.
493 493
494We fixed this by using a more uniform deterministic pseudo-random number 494We fixed this by using a more uniform deterministic pseudo-random number
495generator for blinding factors. I do not believe this to be a problem 495generator for blinding factors. I do not believe this to be a problem
@@ -748,7 +748,7 @@ GNUNET_CRYPTO_rsa_blind (const struct GNUNET_HashCode *hash,
748 } 748 }
749 749
750 data = rsa_full_domain_hash (pkey, hash); 750 data = rsa_full_domain_hash (pkey, hash);
751 if (NULL == data) 751 if (NULL == data)
752 goto rsa_gcd_validate_failure; 752 goto rsa_gcd_validate_failure;
753 753
754 bkey = rsa_blinding_key_derive (pkey, bks); 754 bkey = rsa_blinding_key_derive (pkey, bks);
@@ -771,7 +771,7 @@ GNUNET_CRYPTO_rsa_blind (const struct GNUNET_HashCode *hash,
771 gcry_mpi_release (ne[0]); 771 gcry_mpi_release (ne[0]);
772 gcry_mpi_release (ne[1]); 772 gcry_mpi_release (ne[1]);
773 gcry_mpi_release (r_e); 773 gcry_mpi_release (r_e);
774 rsa_blinding_key_free (bkey); 774 rsa_blinding_key_free (bkey);
775 775
776 *buf_size = numeric_mpi_alloc_n_print (data_r_e, buf); 776 *buf_size = numeric_mpi_alloc_n_print (data_r_e, buf);
777 gcry_mpi_release (data_r_e); 777 gcry_mpi_release (data_r_e);
@@ -917,7 +917,7 @@ GNUNET_CRYPTO_rsa_sign_fdh (const struct GNUNET_CRYPTO_RsaPrivateKey *key,
917 GNUNET_CRYPTO_rsa_public_key_free (pkey); 917 GNUNET_CRYPTO_rsa_public_key_free (pkey);
918 if (NULL == v) /* rsa_gcd_validate failed meaning */ 918 if (NULL == v) /* rsa_gcd_validate failed meaning */
919 return NULL; /* our *own* RSA key is malicious. */ 919 return NULL; /* our *own* RSA key is malicious. */
920 920
921 sig = rsa_sign_mpi (key, v); 921 sig = rsa_sign_mpi (key, v);
922 gcry_mpi_release (v); 922 gcry_mpi_release (v);
923 return sig; 923 return sig;
@@ -1077,11 +1077,11 @@ GNUNET_CRYPTO_rsa_unblind (struct GNUNET_CRYPTO_RsaSignature *sig,
1077 } 1077 }
1078 1078
1079 bkey = rsa_blinding_key_derive (pkey, bks); 1079 bkey = rsa_blinding_key_derive (pkey, bks);
1080 if (NULL == bkey) 1080 if (NULL == bkey)
1081 { 1081 {
1082 /* RSA key is malicious since rsa_gcd_validate failed here. 1082 /* RSA key is malicious since rsa_gcd_validate failed here.
1083 * It should have failed during GNUNET_CRYPTO_rsa_blind too though, 1083 * It should have failed during GNUNET_CRYPTO_rsa_blind too though,
1084 * so the exchange is being malicious in an unfamilair way, maybe 1084 * so the exchange is being malicious in an unfamilair way, maybe
1085 * just trying to crash us. */ 1085 * just trying to crash us. */
1086 GNUNET_break_op (0); 1086 GNUNET_break_op (0);
1087 gcry_mpi_release (n); 1087 gcry_mpi_release (n);
@@ -1096,10 +1096,10 @@ GNUNET_CRYPTO_rsa_unblind (struct GNUNET_CRYPTO_RsaSignature *sig,
1096 n)) 1096 n))
1097 { 1097 {
1098 /* We cannot find r mod n, so gcd(r,n) != 1, which should get * 1098 /* We cannot find r mod n, so gcd(r,n) != 1, which should get *
1099 * caught above, but we handle it the same here. */ 1099 * caught above, but we handle it the same here. */
1100 GNUNET_break_op (0); 1100 GNUNET_break_op (0);
1101 gcry_mpi_release (r_inv); 1101 gcry_mpi_release (r_inv);
1102 rsa_blinding_key_free (bkey); 1102 rsa_blinding_key_free (bkey);
1103 gcry_mpi_release (n); 1103 gcry_mpi_release (n);
1104 gcry_mpi_release (s); 1104 gcry_mpi_release (s);
1105 return NULL; 1105 return NULL;
@@ -1144,11 +1144,11 @@ GNUNET_CRYPTO_rsa_verify (const struct GNUNET_HashCode *hash,
1144 r = rsa_full_domain_hash (pkey, hash); 1144 r = rsa_full_domain_hash (pkey, hash);
1145 if (NULL == r) { 1145 if (NULL == r) {
1146 GNUNET_break_op (0); 1146 GNUNET_break_op (0);
1147 /* RSA key is malicious since rsa_gcd_validate failed here. 1147 /* RSA key is malicious since rsa_gcd_validate failed here.
1148 * It should have failed during GNUNET_CRYPTO_rsa_blind too though, 1148 * It should have failed during GNUNET_CRYPTO_rsa_blind too though,
1149 * so the exchange is being malicious in an unfamilair way, maybe 1149 * so the exchange is being malicious in an unfamilair way, maybe
1150 * just trying to crash us. Arguably, we've only an internal error 1150 * just trying to crash us. Arguably, we've only an internal error
1151 * though because we should've detected this in our previous call 1151 * though because we should've detected this in our previous call
1152 * to GNUNET_CRYPTO_rsa_unblind. */ 1152 * to GNUNET_CRYPTO_rsa_unblind. */
1153 return GNUNET_NO; 1153 return GNUNET_NO;
1154 } 1154 }
diff --git a/src/util/crypto_symmetric.c b/src/util/crypto_symmetric.c
index 381a5d2f8..e25e2f1dd 100644
--- a/src/util/crypto_symmetric.c
+++ b/src/util/crypto_symmetric.c
@@ -29,7 +29,7 @@
29#include "gnunet_crypto_lib.h" 29#include "gnunet_crypto_lib.h"
30#include <gcrypt.h> 30#include <gcrypt.h>
31 31
32#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) 32#define LOG(kind,...) GNUNET_log_from (kind, "util-crypto-symmetric", __VA_ARGS__)
33 33
34/** 34/**
35 * Create a new SessionKey (for symmetric encryption). 35 * Create a new SessionKey (for symmetric encryption).
diff --git a/src/util/disk.c b/src/util/disk.c
index 40043549b..d536ec897 100644
--- a/src/util/disk.c
+++ b/src/util/disk.c
@@ -28,11 +28,11 @@
28#include "gnunet_strings_lib.h" 28#include "gnunet_strings_lib.h"
29#include "gnunet_disk_lib.h" 29#include "gnunet_disk_lib.h"
30 30
31#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) 31#define LOG(kind,...) GNUNET_log_from (kind, "util-disk", __VA_ARGS__)
32 32
33#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall) 33#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-disk", syscall)
34 34
35#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename) 35#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util-disk", syscall, filename)
36 36
37/** 37/**
38 * Block size for IO for copying files. 38 * Block size for IO for copying files.
@@ -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,10 +1838,13 @@ 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;
1846 else
1847 return NULL;
1843 } 1848 }
1844 else 1849 else
1845 return NULL; 1850 return NULL;
diff --git a/src/util/getopt.c b/src/util/getopt.c
index e150496ae..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/**
@@ -47,9 +47,9 @@ Copyright Copyright (C) 2006 Christian Grothoff
47#endif 47#endif
48#endif 48#endif
49 49
50#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) 50#define LOG(kind,...) GNUNET_log_from (kind, "util-getopt", __VA_ARGS__)
51 51
52#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall) 52#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-getopt", syscall)
53 53
54#if defined (WIN32) && !defined (__CYGWIN32__) 54#if defined (WIN32) && !defined (__CYGWIN32__)
55/* It's not Unix, really. See? Capital letters. */ 55/* It's not Unix, really. See? Capital letters. */
@@ -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 ab0b67412..c3d0e4c7c 100644
--- a/src/util/getopt_helpers.c
+++ b/src/util/getopt_helpers.c
@@ -26,7 +26,7 @@
26#include "platform.h" 26#include "platform.h"
27#include "gnunet_util_lib.h" 27#include "gnunet_util_lib.h"
28 28
29#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) 29#define LOG(kind,...) GNUNET_log_from (kind, "util-getopt", __VA_ARGS__)
30 30
31 31
32/** 32/**
@@ -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_uint (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_flag (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_cfgfile (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_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_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_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_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_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_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..fb3b9ebf9 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_flag ('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_flag ('S',
247 "list-sections",
248 gettext_noop ("print available configuration sections"),
249 &list_sections),
250 GNUNET_GETOPT_option_flag ('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..2a712f4eb 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_flag ('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_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_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_flag ('p',
429 "print-public-key",
430 gettext_noop ("print the public key in ASCII format"),
431 &print_public_key),
432 GNUNET_GETOPT_option_flag ('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..7ffafee32 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_flag ('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..3b3b7d695 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_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_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/load.c b/src/util/load.c
index d374d7a17..d1de6aa36 100644
--- a/src/util/load.c
+++ b/src/util/load.c
@@ -27,7 +27,7 @@
27#include "gnunet_util_lib.h" 27#include "gnunet_util_lib.h"
28 28
29 29
30#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) 30#define LOG(kind,...) GNUNET_log_from (kind, "util-load", __VA_ARGS__)
31 31
32/** 32/**
33 * Values we track for load calculations. 33 * Values we track for load calculations.
diff --git a/src/util/mq.c b/src/util/mq.c
index d12f69e5f..90b2aa968 100644
--- a/src/util/mq.c
+++ b/src/util/mq.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-2014 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
@@ -26,7 +26,7 @@
26#include "platform.h" 26#include "platform.h"
27#include "gnunet_util_lib.h" 27#include "gnunet_util_lib.h"
28 28
29#define LOG(kind,...) GNUNET_log_from (kind, "mq",__VA_ARGS__) 29#define LOG(kind,...) GNUNET_log_from (kind, "util-mq",__VA_ARGS__)
30 30
31 31
32struct GNUNET_MQ_Envelope 32struct GNUNET_MQ_Envelope
@@ -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 *
@@ -235,24 +217,29 @@ GNUNET_MQ_inject_message (struct GNUNET_MQ_Handle *mq,
235{ 217{
236 const struct GNUNET_MQ_MessageHandler *handler; 218 const struct GNUNET_MQ_MessageHandler *handler;
237 int handled = GNUNET_NO; 219 int handled = GNUNET_NO;
238 uint16_t ms = ntohs (mh->size); 220 uint16_t msize = ntohs (mh->size);
221 uint16_t mtype = ntohs (mh->type);
222
223 LOG (GNUNET_ERROR_TYPE_DEBUG,
224 "Received message of type %u and size %u\n",
225 mtype, msize);
239 226
240 if (NULL == mq->handlers) 227 if (NULL == mq->handlers)
241 goto done; 228 goto done;
242 for (handler = mq->handlers; NULL != handler->cb; handler++) 229 for (handler = mq->handlers; NULL != handler->cb; handler++)
243 { 230 {
244 if (handler->type == ntohs (mh->type)) 231 if (handler->type == mtype)
245 { 232 {
246 handled = GNUNET_YES; 233 handled = GNUNET_YES;
247 if ( (handler->expected_size > ms) || 234 if ( (handler->expected_size > msize) ||
248 ( (handler->expected_size != ms) && 235 ( (handler->expected_size != msize) &&
249 (NULL == handler->mv) ) ) 236 (NULL == handler->mv) ) )
250 { 237 {
251 /* Too small, or not an exact size and 238 /* Too small, or not an exact size and
252 no 'mv' handler to check rest */ 239 no 'mv' handler to check rest */
253 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 240 LOG (GNUNET_ERROR_TYPE_ERROR,
254 "Received malformed message of type %u\n", 241 "Received malformed message of type %u\n",
255 (unsigned int) handler->type); 242 (unsigned int) handler->type);
256 GNUNET_MQ_inject_error (mq, 243 GNUNET_MQ_inject_error (mq,
257 GNUNET_MQ_ERROR_MALFORMED); 244 GNUNET_MQ_ERROR_MALFORMED);
258 break; 245 break;
@@ -267,9 +254,9 @@ GNUNET_MQ_inject_message (struct GNUNET_MQ_Handle *mq,
267 else 254 else
268 { 255 {
269 /* Message rejected by check routine */ 256 /* Message rejected by check routine */
270 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 257 LOG (GNUNET_ERROR_TYPE_ERROR,
271 "Received malformed message of type %u\n", 258 "Received malformed message of type %u\n",
272 (unsigned int) handler->type); 259 (unsigned int) handler->type);
273 GNUNET_MQ_inject_error (mq, 260 GNUNET_MQ_inject_error (mq,
274 GNUNET_MQ_ERROR_MALFORMED); 261 GNUNET_MQ_ERROR_MALFORMED);
275 } 262 }
@@ -279,9 +266,8 @@ GNUNET_MQ_inject_message (struct GNUNET_MQ_Handle *mq,
279 done: 266 done:
280 if (GNUNET_NO == handled) 267 if (GNUNET_NO == handled)
281 LOG (GNUNET_ERROR_TYPE_INFO, 268 LOG (GNUNET_ERROR_TYPE_INFO,
282 "No handler for message of type %d and size %d\n", 269 "No handler for message of type %u and size %u\n",
283 ntohs (mh->type), 270 mtype, msize);
284 ntohs (mh->size));
285} 271}
286 272
287 273
@@ -358,6 +344,7 @@ GNUNET_MQ_send (struct GNUNET_MQ_Handle *mq,
358 GNUNET_assert (NULL == ev->parent_queue); 344 GNUNET_assert (NULL == ev->parent_queue);
359 345
360 mq->queue_length++; 346 mq->queue_length++;
347 GNUNET_break (mq->queue_length < 10000); /* This would seem like a bug... */
361 ev->parent_queue = mq; 348 ev->parent_queue = mq;
362 /* is the implementation busy? queue it! */ 349 /* is the implementation busy? queue it! */
363 if ( (NULL != mq->current_envelope) || 350 if ( (NULL != mq->current_envelope) ||
@@ -368,6 +355,7 @@ GNUNET_MQ_send (struct GNUNET_MQ_Handle *mq,
368 ev); 355 ev);
369 return; 356 return;
370 } 357 }
358 GNUNET_assert (NULL == mq->envelope_head);
371 mq->current_envelope = ev; 359 mq->current_envelope = ev;
372 mq->send_impl (mq, 360 mq->send_impl (mq,
373 ev->mh, 361 ev->mh,
@@ -376,6 +364,46 @@ GNUNET_MQ_send (struct GNUNET_MQ_Handle *mq,
376 364
377 365
378/** 366/**
367 * Remove the first envelope that has not yet been sent from the message
368 * queue and return it.
369 *
370 * @param mq queue to remove envelope from
371 * @return NULL if queue is empty (or has no envelope that is not under transmission)
372 */
373struct GNUNET_MQ_Envelope *
374GNUNET_MQ_unsent_head (struct GNUNET_MQ_Handle *mq)
375{
376 struct GNUNET_MQ_Envelope *env;
377
378 env = mq->envelope_head;
379 GNUNET_CONTAINER_DLL_remove (mq->envelope_head,
380 mq->envelope_tail,
381 env);
382 mq->queue_length--;
383 env->parent_queue = NULL;
384 return env;
385}
386
387
388/**
389 * Function to copy an envelope. The envelope must not yet
390 * be in any queue or have any options or callbacks set.
391 *
392 * @param env envelope to copy
393 * @return copy of @a env
394 */
395struct GNUNET_MQ_Envelope *
396GNUNET_MQ_env_copy (struct GNUNET_MQ_Envelope *env)
397{
398 GNUNET_assert (NULL == env->next);
399 GNUNET_assert (NULL == env->parent_queue);
400 GNUNET_assert (NULL == env->sent_cb);
401 GNUNET_assert (GNUNET_NO == env->have_custom_options);
402 return GNUNET_MQ_msg_copy (env->mh);
403}
404
405
406/**
379 * Send a copy of a message with the given message queue. 407 * Send a copy of a message with the given message queue.
380 * Can be called repeatedly on the same envelope. 408 * Can be called repeatedly on the same envelope.
381 * 409 *
@@ -514,21 +542,12 @@ GNUNET_MQ_queue_for_callbacks (GNUNET_MQ_SendImpl send,
514 void *error_handler_cls) 542 void *error_handler_cls)
515{ 543{
516 struct GNUNET_MQ_Handle *mq; 544 struct GNUNET_MQ_Handle *mq;
517 unsigned int i;
518 545
519 mq = GNUNET_new (struct GNUNET_MQ_Handle); 546 mq = GNUNET_new (struct GNUNET_MQ_Handle);
520 mq->send_impl = send; 547 mq->send_impl = send;
521 mq->destroy_impl = destroy; 548 mq->destroy_impl = destroy;
522 mq->cancel_impl = cancel; 549 mq->cancel_impl = cancel;
523 if (NULL != handlers) 550 mq->handlers = GNUNET_MQ_copy_handlers (handlers);
524 {
525 for (i=0;NULL != handlers[i].cb; i++) ;
526 mq->handlers = GNUNET_new_array (i + 1,
527 struct GNUNET_MQ_MessageHandler);
528 GNUNET_memcpy (mq->handlers,
529 handlers,
530 i * sizeof (struct GNUNET_MQ_MessageHandler));
531 }
532 mq->error_handler = error_handler; 551 mq->error_handler = error_handler;
533 mq->error_handler_cls = error_handler_cls; 552 mq->error_handler_cls = error_handler_cls;
534 mq->impl_state = impl_state; 553 mq->impl_state = impl_state;
@@ -671,87 +690,6 @@ GNUNET_MQ_msg_nested_mh_ (struct GNUNET_MessageHeader **mhp,
671 690
672 691
673/** 692/**
674 * Transmit a queued message to the session's client.
675 *
676 * @param cls consensus session
677 * @param size number of bytes available in @a buf
678 * @param buf where the callee should write the message
679 * @return number of bytes written to @a buf
680 */
681static size_t
682transmit_queued (void *cls,
683 size_t size,
684 void *buf)
685{
686 struct GNUNET_MQ_Handle *mq = cls;
687 struct ServerClientSocketState *state = GNUNET_MQ_impl_state (mq);
688 const struct GNUNET_MessageHeader *msg = GNUNET_MQ_impl_current (mq);
689 size_t msg_size;
690
691 GNUNET_assert (NULL != buf);
692 msg_size = ntohs (msg->size);
693 GNUNET_assert (size >= msg_size);
694 GNUNET_memcpy (buf, msg, msg_size);
695 state->th = NULL;
696
697 GNUNET_MQ_impl_send_continue (mq);
698
699 return msg_size;
700}
701
702
703static void
704server_client_destroy_impl (struct GNUNET_MQ_Handle *mq,
705 void *impl_state)
706{
707 struct ServerClientSocketState *state = impl_state;
708
709 if (NULL != state->th)
710 {
711 GNUNET_SERVER_notify_transmit_ready_cancel (state->th);
712 state->th = NULL;
713 }
714
715 GNUNET_assert (NULL != mq);
716 GNUNET_assert (NULL != state);
717 GNUNET_SERVER_client_drop (state->client);
718 GNUNET_free (state);
719}
720
721
722static void
723server_client_send_impl (struct GNUNET_MQ_Handle *mq,
724 const struct GNUNET_MessageHeader *msg,
725 void *impl_state)
726{
727 struct ServerClientSocketState *state = impl_state;
728
729 GNUNET_assert (NULL != mq);
730 state->th = GNUNET_SERVER_notify_transmit_ready (state->client,
731 ntohs (msg->size),
732 GNUNET_TIME_UNIT_FOREVER_REL,
733 &transmit_queued, mq);
734}
735
736
737struct GNUNET_MQ_Handle *
738GNUNET_MQ_queue_for_server_client (struct GNUNET_SERVER_Client *client)
739{
740 struct GNUNET_MQ_Handle *mq;
741 struct ServerClientSocketState *scss;
742
743 mq = GNUNET_new (struct GNUNET_MQ_Handle);
744 scss = GNUNET_new (struct ServerClientSocketState);
745 mq->impl_state = scss;
746 scss->client = client;
747 GNUNET_SERVER_client_keep (client);
748 mq->send_impl = &server_client_send_impl;
749 mq->destroy_impl = &server_client_destroy_impl;
750 return mq;
751}
752
753
754/**
755 * Associate the assoc_data in mq with a unique request id. 693 * Associate the assoc_data in mq with a unique request id.
756 * 694 *
757 * @param mq message queue, id will be unique for the queue 695 * @param mq message queue, id will be unique for the queue
@@ -769,22 +707,40 @@ GNUNET_MQ_assoc_add (struct GNUNET_MQ_Handle *mq,
769 mq->assoc_id = 1; 707 mq->assoc_id = 1;
770 } 708 }
771 id = mq->assoc_id++; 709 id = mq->assoc_id++;
772 GNUNET_CONTAINER_multihashmap32_put (mq->assoc_map, id, assoc_data, 710 GNUNET_assert (GNUNET_OK ==
773 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); 711 GNUNET_CONTAINER_multihashmap32_put (mq->assoc_map,
712 id,
713 assoc_data,
714 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
774 return id; 715 return id;
775} 716}
776 717
777 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 */
778void * 726void *
779GNUNET_MQ_assoc_get (struct GNUNET_MQ_Handle *mq, 727GNUNET_MQ_assoc_get (struct GNUNET_MQ_Handle *mq,
780 uint32_t request_id) 728 uint32_t request_id)
781{ 729{
782 if (NULL == mq->assoc_map) 730 if (NULL == mq->assoc_map)
783 return NULL; 731 return NULL;
784 return GNUNET_CONTAINER_multihashmap32_get (mq->assoc_map, request_id); 732 return GNUNET_CONTAINER_multihashmap32_get (mq->assoc_map,
733 request_id);
785} 734}
786 735
787 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 */
788void * 744void *
789GNUNET_MQ_assoc_remove (struct GNUNET_MQ_Handle *mq, 745GNUNET_MQ_assoc_remove (struct GNUNET_MQ_Handle *mq,
790 uint32_t request_id) 746 uint32_t request_id)
@@ -959,20 +915,16 @@ GNUNET_MQ_send_cancel (struct GNUNET_MQ_Envelope *ev)
959 915
960 if (mq->current_envelope == ev) 916 if (mq->current_envelope == ev)
961 { 917 {
962 // complex case, we already started with transmitting 918 /* complex case, we already started with transmitting
963 // the message 919 the message using the callbacks. */
964 GNUNET_assert (0 < mq->queue_length); 920 GNUNET_assert (0 < mq->queue_length);
965 mq->queue_length--; 921 mq->queue_length--;
966 mq->cancel_impl (mq, 922 mq->cancel_impl (mq,
967 mq->impl_state); 923 mq->impl_state);
968 // continue sending the next message, if any 924 /* continue sending the next message, if any */
969 if (NULL == mq->envelope_head) 925 mq->current_envelope = mq->envelope_head;
970 { 926 if (NULL != mq->current_envelope)
971 mq->current_envelope = NULL;
972 }
973 else
974 { 927 {
975 mq->current_envelope = mq->envelope_head;
976 GNUNET_CONTAINER_DLL_remove (mq->envelope_head, 928 GNUNET_CONTAINER_DLL_remove (mq->envelope_head,
977 mq->envelope_tail, 929 mq->envelope_tail,
978 mq->current_envelope); 930 mq->current_envelope);
@@ -983,7 +935,7 @@ GNUNET_MQ_send_cancel (struct GNUNET_MQ_Envelope *ev)
983 } 935 }
984 else 936 else
985 { 937 {
986 // simple case, message is still waiting in the queue 938 /* simple case, message is still waiting in the queue */
987 GNUNET_CONTAINER_DLL_remove (mq->envelope_head, 939 GNUNET_CONTAINER_DLL_remove (mq->envelope_head,
988 mq->envelope_tail, 940 mq->envelope_tail,
989 ev); 941 ev);
@@ -1140,4 +1092,100 @@ GNUNET_MQ_destroy_notify_cancel (struct GNUNET_MQ_DestroyNotificationHandle *dnh
1140} 1092}
1141 1093
1142 1094
1095/**
1096 * Insert @a env into the envelope DLL starting at @a env_head
1097 * Note that @a env must not be in any MQ while this function
1098 * is used with DLLs defined outside of the MQ module. This
1099 * is just in case some application needs to also manage a
1100 * FIFO of envelopes independent of MQ itself and wants to
1101 * re-use the pointers internal to @a env. Use with caution.
1102 *
1103 * @param[in|out] env_head of envelope DLL
1104 * @param[in|out] env_tail tail of envelope DLL
1105 * @param[in|out] env element to insert at the tail
1106 */
1107void
1108GNUNET_MQ_dll_insert_tail (struct GNUNET_MQ_Envelope **env_head,
1109 struct GNUNET_MQ_Envelope **env_tail,
1110 struct GNUNET_MQ_Envelope *env)
1111{
1112 GNUNET_CONTAINER_DLL_insert_tail (*env_head,
1113 *env_tail,
1114 env);
1115}
1116
1117
1118/**
1119 * Remove @a env from the envelope DLL starting at @a env_head.
1120 * Note that @a env must not be in any MQ while this function
1121 * is used with DLLs defined outside of the MQ module. This
1122 * is just in case some application needs to also manage a
1123 * FIFO of envelopes independent of MQ itself and wants to
1124 * re-use the pointers internal to @a env. Use with caution.
1125 *
1126 * @param[in|out] env_head of envelope DLL
1127 * @param[in|out] env_tail tail of envelope DLL
1128 * @param[in|out] env element to remove from the DLL
1129 */
1130void
1131GNUNET_MQ_dll_remove (struct GNUNET_MQ_Envelope **env_head,
1132 struct GNUNET_MQ_Envelope **env_tail,
1133 struct GNUNET_MQ_Envelope *env)
1134{
1135 GNUNET_CONTAINER_DLL_remove (*env_head,
1136 *env_tail,
1137 env);
1138}
1139
1140
1141/**
1142 * Copy an array of handlers.
1143 *
1144 * Useful if the array has been delared in local memory and needs to be
1145 * persisted for future use.
1146 *
1147 * @param handlers Array of handlers to be copied. Can be NULL (nothing done).
1148 * @return A newly allocated array of handlers.
1149 * Needs to be freed with #GNUNET_free.
1150 */
1151struct GNUNET_MQ_MessageHandler *
1152GNUNET_MQ_copy_handlers (const struct GNUNET_MQ_MessageHandler *handlers)
1153{
1154 struct GNUNET_MQ_MessageHandler *copy;
1155 unsigned int count;
1156
1157 if (NULL == handlers)
1158 return NULL;
1159
1160 count = GNUNET_MQ_count_handlers (handlers);
1161 copy = GNUNET_new_array (count + 1,
1162 struct GNUNET_MQ_MessageHandler);
1163 GNUNET_memcpy (copy,
1164 handlers,
1165 count * sizeof (struct GNUNET_MQ_MessageHandler));
1166 return copy;
1167}
1168
1169
1170/**
1171 * Count the handlers in a handler array.
1172 *
1173 * @param handlers Array of handlers to be counted.
1174 * @return The number of handlers in the array.
1175 */
1176unsigned int
1177GNUNET_MQ_count_handlers (const struct GNUNET_MQ_MessageHandler *handlers)
1178{
1179 unsigned int i;
1180
1181 if (NULL == handlers)
1182 return 0;
1183
1184 for (i=0; NULL != handlers[i].cb; i++) ;
1185
1186 return i;
1187}
1188
1189
1190
1143/* end of mq.c */ 1191/* end of mq.c */
diff --git a/src/util/mst.c b/src/util/mst.c
index 82a21b880..0d90c5d10 100644
--- a/src/util/mst.c
+++ b/src/util/mst.c
@@ -34,7 +34,7 @@
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", __VA_ARGS__) 37#define LOG(kind,...) GNUNET_log_from (kind, "util-mst", __VA_ARGS__)
38 38
39 39
40/** 40/**
@@ -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;
@@ -130,7 +130,7 @@ GNUNET_MST_from_buffer (struct GNUNET_MessageStreamTokenizer *mst,
130 GNUNET_assert (mst->off <= mst->pos); 130 GNUNET_assert (mst->off <= mst->pos);
131 GNUNET_assert (mst->pos <= mst->curr_buf); 131 GNUNET_assert (mst->pos <= mst->curr_buf);
132 LOG (GNUNET_ERROR_TYPE_DEBUG, 132 LOG (GNUNET_ERROR_TYPE_DEBUG,
133 "Server-mst receives %u bytes with %u bytes already in private buffer\n", 133 "MST receives %u bytes with %u bytes already in private buffer\n",
134 (unsigned int) size, 134 (unsigned int) size,
135 (unsigned int) (mst->pos - mst->off)); 135 (unsigned int) (mst->pos - mst->off));
136 ret = GNUNET_OK; 136 ret = GNUNET_OK;
@@ -151,7 +151,7 @@ do_align:
151 } 151 }
152 if (mst->pos - mst->off < sizeof (struct GNUNET_MessageHeader)) 152 if (mst->pos - mst->off < sizeof (struct GNUNET_MessageHeader))
153 { 153 {
154 delta 154 delta
155 = GNUNET_MIN (sizeof (struct GNUNET_MessageHeader) 155 = GNUNET_MIN (sizeof (struct GNUNET_MessageHeader)
156 - (mst->pos - mst->off), 156 - (mst->pos - mst->off),
157 size); 157 size);
@@ -229,8 +229,8 @@ do_align:
229 if (one_shot == GNUNET_YES) 229 if (one_shot == GNUNET_YES)
230 one_shot = GNUNET_SYSERR; 230 one_shot = GNUNET_SYSERR;
231 mst->off += want; 231 mst->off += want;
232 if (GNUNET_SYSERR == mst->cb (mst->cb_cls, 232 if (GNUNET_SYSERR == mst->cb (mst->cb_cls,
233 hdr)) 233 hdr))
234 return GNUNET_SYSERR; 234 return GNUNET_SYSERR;
235 if (mst->off == mst->pos) 235 if (mst->off == mst->pos)
236 { 236 {
diff --git a/src/util/network.c b/src/util/network.c
index 67f2801c5..66a468e45 100644
--- a/src/util/network.c
+++ b/src/util/network.c
@@ -28,9 +28,9 @@
28#include "gnunet_util_lib.h" 28#include "gnunet_util_lib.h"
29#include "disk.h" 29#include "disk.h"
30 30
31#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) 31#define LOG(kind,...) GNUNET_log_from (kind, "util-network", __VA_ARGS__)
32#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename) 32#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util-network", syscall, filename)
33#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall) 33#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-network", syscall)
34 34
35#define DEBUG_NETWORK GNUNET_EXTRA_LOGGING 35#define DEBUG_NETWORK GNUNET_EXTRA_LOGGING
36 36
@@ -1697,6 +1697,64 @@ initialize_select_thread ()
1697 1697
1698#endif 1698#endif
1699 1699
1700/**
1701 * Test if the given @a port is available.
1702 *
1703 * @param ipproto transport protocol to test (i.e. IPPROTO_TCP)
1704 * @param port port number to test
1705 * @return #GNUNET_OK if the port is available, #GNUNET_NO if not
1706 */
1707int
1708GNUNET_NETWORK_test_port_free (int ipproto,
1709 uint16_t port)
1710{
1711 struct GNUNET_NETWORK_Handle *socket;
1712 int bind_status;
1713 int socktype;
1714 char open_port_str[6];
1715 struct addrinfo hint;
1716 struct addrinfo *ret;
1717 struct addrinfo *ai;
1718
1719 GNUNET_snprintf (open_port_str,
1720 sizeof (open_port_str),
1721 "%u",
1722 (unsigned int) port);
1723 socktype = (IPPROTO_TCP == ipproto)
1724 ? SOCK_STREAM
1725 : SOCK_DGRAM;
1726 ret = NULL;
1727 memset (&hint, 0, sizeof (hint));
1728 hint.ai_family = AF_UNSPEC; /* IPv4 and IPv6 */
1729 hint.ai_socktype = socktype;
1730 hint.ai_protocol = ipproto;
1731 hint.ai_addrlen = 0;
1732 hint.ai_addr = NULL;
1733 hint.ai_canonname = NULL;
1734 hint.ai_next = NULL;
1735 hint.ai_flags = AI_PASSIVE | AI_NUMERICSERV; /* Wild card address */
1736 GNUNET_assert (0 == getaddrinfo (NULL,
1737 open_port_str,
1738 &hint,
1739 &ret));
1740 for (ai = ret; NULL != ai; ai = ai->ai_next)
1741 {
1742 socket = GNUNET_NETWORK_socket_create (ai->ai_family,
1743 ai->ai_socktype,
1744 ai->ai_protocol);
1745 if (NULL == socket)
1746 continue;
1747 bind_status = GNUNET_NETWORK_socket_bind (socket,
1748 ai->ai_addr,
1749 ai->ai_addrlen);
1750 GNUNET_NETWORK_socket_close (socket);
1751 if (GNUNET_OK != bind_status)
1752 break;
1753 }
1754 freeaddrinfo (ret);
1755 return bind_status;
1756}
1757
1700 1758
1701#ifndef MINGW 1759#ifndef MINGW
1702/** 1760/**
diff --git a/src/util/os_installation.c b/src/util/os_installation.c
index ea3ae3e79..1226c5966 100644
--- a/src/util/os_installation.c
+++ b/src/util/os_installation.c
@@ -44,9 +44,9 @@
44#endif 44#endif
45 45
46 46
47#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) 47#define LOG(kind,...) GNUNET_log_from (kind, "util-os-installation", __VA_ARGS__)
48 48
49#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename) 49#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util-os-installation", syscall, filename)
50 50
51 51
52/** 52/**
@@ -823,9 +823,13 @@ GNUNET_OS_check_helper_binary (const char *binary,
823#ifdef MINGW 823#ifdef MINGW
824 char *binaryexe; 824 char *binaryexe;
825 825
826 GNUNET_asprintf (&binaryexe, "%s.exe", binary); 826 GNUNET_asprintf (&binaryexe,
827 if ( (GNUNET_YES == GNUNET_STRINGS_path_is_absolute (binaryexe, GNUNET_NO, 827 "%s.exe",
828 NULL, NULL)) || 828 binary);
829 if ( (GNUNET_YES ==
830 GNUNET_STRINGS_path_is_absolute (binaryexe,
831 GNUNET_NO,
832 NULL, NULL)) ||
829 (0 == strncmp (binary, "./", 2)) ) 833 (0 == strncmp (binary, "./", 2)) )
830 p = GNUNET_strdup (binaryexe); 834 p = GNUNET_strdup (binaryexe);
831 else 835 else
@@ -840,16 +844,24 @@ GNUNET_OS_check_helper_binary (const char *binary,
840 } 844 }
841 GNUNET_free (binaryexe); 845 GNUNET_free (binaryexe);
842#else 846#else
843 if ( (GNUNET_YES == GNUNET_STRINGS_path_is_absolute (binary, GNUNET_NO, 847 if ( (GNUNET_YES ==
844 NULL, NULL)) || 848 GNUNET_STRINGS_path_is_absolute (binary,
849 GNUNET_NO,
850 NULL,
851 NULL)) ||
845 (0 == strncmp (binary, "./", 2)) ) 852 (0 == strncmp (binary, "./", 2)) )
853 {
846 p = GNUNET_strdup (binary); 854 p = GNUNET_strdup (binary);
855 }
847 else 856 else
848 { 857 {
849 p = get_path_from_PATH (binary); 858 p = get_path_from_PATH (binary);
850 if (NULL != p) 859 if (NULL != p)
851 { 860 {
852 GNUNET_asprintf (&pf, "%s/%s", p, binary); 861 GNUNET_asprintf (&pf,
862 "%s/%s",
863 p,
864 binary);
853 GNUNET_free (p); 865 GNUNET_free (p);
854 p = pf; 866 p = pf;
855 } 867 }
@@ -862,9 +874,12 @@ GNUNET_OS_check_helper_binary (const char *binary,
862 binary); 874 binary);
863 return GNUNET_SYSERR; 875 return GNUNET_SYSERR;
864 } 876 }
865 if (0 != ACCESS (p, X_OK)) 877 if (0 != ACCESS (p,
878 X_OK))
866 { 879 {
867 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "access", p); 880 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING,
881 "access",
882 p);
868 GNUNET_free (p); 883 GNUNET_free (p);
869 return GNUNET_SYSERR; 884 return GNUNET_SYSERR;
870 } 885 }
@@ -873,22 +888,30 @@ GNUNET_OS_check_helper_binary (const char *binary,
873 { 888 {
874 /* as we run as root, we don't insist on SUID */ 889 /* as we run as root, we don't insist on SUID */
875 GNUNET_free (p); 890 GNUNET_free (p);
876 return GNUNET_OK; 891 return GNUNET_YES;
877 } 892 }
878#endif 893#endif
879 if (0 != STAT (p, &statbuf)) 894 if (0 != STAT (p,
895 &statbuf))
880 { 896 {
881 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", p); 897 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING,
898 "stat",
899 p);
882 GNUNET_free (p); 900 GNUNET_free (p);
883 return GNUNET_SYSERR; 901 return GNUNET_SYSERR;
884 } 902 }
885 if (check_suid){ 903 if (check_suid)
904 {
886#ifndef MINGW 905#ifndef MINGW
887 if ((0 != (statbuf.st_mode & S_ISUID)) && (0 == statbuf.st_uid)) 906 if ( (0 != (statbuf.st_mode & S_ISUID)) &&
907 (0 == statbuf.st_uid) )
888 { 908 {
889 GNUNET_free (p); 909 GNUNET_free (p);
890 return GNUNET_YES; 910 return GNUNET_YES;
891 } 911 }
912 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
913 _("Binary `%s' exists, but is not SUID\n"),
914 p);
892 /* binary exists, but not SUID */ 915 /* binary exists, but not SUID */
893#else 916#else
894 STARTUPINFO start; 917 STARTUPINFO start;
diff --git a/src/util/os_network.c b/src/util/os_network.c
index 5e4546d08..5cb2b6864 100644
--- a/src/util/os_network.c
+++ b/src/util/os_network.c
@@ -31,11 +31,11 @@
31#include "gnunet_util_lib.h" 31#include "gnunet_util_lib.h"
32 32
33 33
34#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) 34#define LOG(kind,...) GNUNET_log_from (kind, "util-os-network", __VA_ARGS__)
35#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename) 35#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util-os-network", syscall, filename)
36 36
37 37
38#if ! (HAVE_GETIFADDRS && HAVE_FREEIFADDRS) 38#if ! (HAVE_GETIFADDRS && HAVE_FREEIFADDRS) && !MINGW
39/** 39/**
40 * Try to enumerate all network interfaces using 'ifconfig'. 40 * Try to enumerate all network interfaces using 'ifconfig'.
41 * 41 *
diff --git a/src/util/os_priority.c b/src/util/os_priority.c
index 4b1dbd491..2c4f7ca09 100644
--- a/src/util/os_priority.c
+++ b/src/util/os_priority.c
@@ -29,11 +29,11 @@
29#include "disk.h" 29#include "disk.h"
30#include <unistr.h> 30#include <unistr.h>
31 31
32#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) 32#define LOG(kind,...) GNUNET_log_from (kind, "util-os-priority", __VA_ARGS__)
33 33
34#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall) 34#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-os-priority", syscall)
35 35
36#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename) 36#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util-os-priority", syscall, filename)
37 37
38#define GNUNET_OS_CONTROL_PIPE "GNUNET_OS_CONTROL_PIPE" 38#define GNUNET_OS_CONTROL_PIPE "GNUNET_OS_CONTROL_PIPE"
39 39
@@ -1091,7 +1091,10 @@ start_process (int pipe_control,
1091 &lsocks_read, sizeof (HANDLE)); 1091 &lsocks_read, sizeof (HANDLE));
1092 } 1092 }
1093 else 1093 else
1094 {
1094 lsocks_pipe = NULL; 1095 lsocks_pipe = NULL;
1096 lsocks_write_fd = NULL;
1097 }
1095 1098
1096 env_off = 0; 1099 env_off = 0;
1097 if (GNUNET_YES == pipe_control) 1100 if (GNUNET_YES == pipe_control)
@@ -1229,7 +1232,7 @@ start_process (int pipe_control,
1229 if (sizeof (count) != wrote) 1232 if (sizeof (count) != wrote)
1230 { 1233 {
1231 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1234 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1232 "Failed to write %u count bytes to the child: %u\n", 1235 "Failed to write %u count bytes to the child: %lu\n",
1233 sizeof (count), GetLastError ()); 1236 sizeof (count), GetLastError ());
1234 break; 1237 break;
1235 } 1238 }
@@ -1240,7 +1243,7 @@ start_process (int pipe_control,
1240 if (SOCKET_ERROR == WSADuplicateSocketA (lsocks[i], gnunet_proc->pid, &pi)) 1243 if (SOCKET_ERROR == WSADuplicateSocketA (lsocks[i], gnunet_proc->pid, &pi))
1241 { 1244 {
1242 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1245 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1243 "Failed to duplicate an socket[%llu]: %u\n", i, 1246 "Failed to duplicate an socket[%u]: %lu\n", i,
1244 GetLastError ()); 1247 GetLastError ());
1245 break; 1248 break;
1246 } 1249 }
@@ -1257,7 +1260,7 @@ start_process (int pipe_control,
1257 if (sizeof (size) != wrote) 1260 if (sizeof (size) != wrote)
1258 { 1261 {
1259 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1262 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1260 "Failed to write %u size[%llu] bytes to the child: %u\n", 1263 "Failed to write %u size[%u] bytes to the child: %lu\n",
1261 sizeof (size), i, GetLastError ()); 1264 sizeof (size), i, GetLastError ());
1262 break; 1265 break;
1263 } 1266 }
@@ -1266,7 +1269,7 @@ start_process (int pipe_control,
1266 if (sizeof (pi) != wrote) 1269 if (sizeof (pi) != wrote)
1267 { 1270 {
1268 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1271 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1269 "Failed to write %u socket[%llu] bytes to the child: %u\n", 1272 "Failed to write %u socket[%u] bytes to the child: %lu\n",
1270 sizeof (pi), i, GetLastError ()); 1273 sizeof (pi), i, GetLastError ());
1271 break; 1274 break;
1272 } 1275 }
diff --git a/src/util/peer.c b/src/util/peer.c
index 5d54a4301..b637dc229 100644
--- a/src/util/peer.c
+++ b/src/util/peer.c
@@ -26,7 +26,7 @@
26#include "platform.h" 26#include "platform.h"
27#include "gnunet_peer_lib.h" 27#include "gnunet_peer_lib.h"
28 28
29#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) 29#define LOG(kind,...) GNUNET_log_from (kind, "util-peer", __VA_ARGS__)
30 30
31 31
32struct PeerEntry 32struct PeerEntry
diff --git a/src/util/plugin.c b/src/util/plugin.c
index c7ac47a7c..fb296f80d 100644
--- a/src/util/plugin.c
+++ b/src/util/plugin.c
@@ -28,7 +28,7 @@
28#include <ltdl.h> 28#include <ltdl.h>
29#include "gnunet_util_lib.h" 29#include "gnunet_util_lib.h"
30 30
31#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) 31#define LOG(kind,...) GNUNET_log_from (kind, "util-plugin", __VA_ARGS__)
32 32
33/** 33/**
34 * Linked list of active plugins. 34 * Linked list of active plugins.
diff --git a/src/util/program.c b/src/util/program.c
index d0dd49909..92a9750f3 100644
--- a/src/util/program.c
+++ b/src/util/program.c
@@ -31,9 +31,9 @@
31#include "speedup.h" 31#include "speedup.h"
32#include <gcrypt.h> 32#include <gcrypt.h>
33 33
34#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) 34#define LOG(kind,...) GNUNET_log_from (kind, "util-program", __VA_ARGS__)
35 35
36#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename) 36#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util-program", syscall, filename)
37 37
38/** 38/**
39 * Context for the command. 39 * Context for the command.
@@ -148,11 +148,11 @@ GNUNET_PROGRAM_run2 (int argc, char *const *argv, const char *binaryName,
148 struct GNUNET_CONFIGURATION_Handle *cfg; 148 struct GNUNET_CONFIGURATION_Handle *cfg;
149 149
150 struct GNUNET_GETOPT_CommandLineOption defoptions[] = { 150 struct GNUNET_GETOPT_CommandLineOption defoptions[] = {
151 GNUNET_GETOPT_OPTION_CFG_FILE (&cc.cfgfile), 151 GNUNET_GETOPT_option_cfgfile (&cc.cfgfile),
152 GNUNET_GETOPT_OPTION_HELP (binaryHelp), 152 GNUNET_GETOPT_option_help (binaryHelp),
153 GNUNET_GETOPT_OPTION_LOGLEVEL (&loglev), 153 GNUNET_GETOPT_option_loglevel (&loglev),
154 GNUNET_GETOPT_OPTION_LOGFILE (&logfile), 154 GNUNET_GETOPT_option_logfile (&logfile),
155 GNUNET_GETOPT_OPTION_VERSION (PACKAGE_VERSION " " VCS_VERSION) 155 GNUNET_GETOPT_option_version (PACKAGE_VERSION " " VCS_VERSION)
156 }; 156 };
157 struct GNUNET_GETOPT_CommandLineOption *allopts; 157 struct GNUNET_GETOPT_CommandLineOption *allopts;
158 const char *gargs; 158 const char *gargs;
diff --git a/src/util/resolver_api.c b/src/util/resolver_api.c
index fdeaed006..0c915932c 100644
--- a/src/util/resolver_api.c
+++ b/src/util/resolver_api.c
@@ -29,9 +29,9 @@
29#include "gnunet_resolver_service.h" 29#include "gnunet_resolver_service.h"
30#include "resolver.h" 30#include "resolver.h"
31 31
32#define LOG(kind,...) GNUNET_log_from (kind, "resolver-api", __VA_ARGS__) 32#define LOG(kind,...) GNUNET_log_from (kind, "util-resolver-api", __VA_ARGS__)
33 33
34#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "resolver-api", syscall) 34#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-resolver-api", syscall)
35 35
36/** 36/**
37 * Maximum supported length for a hostname 37 * Maximum supported length for a hostname
@@ -250,7 +250,7 @@ void
250GNUNET_RESOLVER_disconnect () 250GNUNET_RESOLVER_disconnect ()
251{ 251{
252 struct GNUNET_RESOLVER_RequestHandle *rh; 252 struct GNUNET_RESOLVER_RequestHandle *rh;
253 253
254 while (NULL != (rh = req_head)) 254 while (NULL != (rh = req_head))
255 { 255 {
256 GNUNET_assert (GNUNET_SYSERR == rh->was_transmitted); 256 GNUNET_assert (GNUNET_SYSERR == rh->was_transmitted);
@@ -298,7 +298,7 @@ static void
298check_disconnect () 298check_disconnect ()
299{ 299{
300 struct GNUNET_RESOLVER_RequestHandle *rh; 300 struct GNUNET_RESOLVER_RequestHandle *rh;
301 301
302 for (rh = req_head; NULL != rh; rh = rh->next) 302 for (rh = req_head; NULL != rh; rh = rh->next)
303 if (GNUNET_SYSERR != rh->was_transmitted) 303 if (GNUNET_SYSERR != rh->was_transmitted)
304 return; 304 return;
@@ -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/scheduler.c b/src/util/scheduler.c
index 409a0942f..a7b1d8e2a 100644
--- a/src/util/scheduler.c
+++ b/src/util/scheduler.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-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
@@ -17,7 +17,6 @@
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
21/** 20/**
22 * @file util/scheduler.c 21 * @file util/scheduler.c
23 * @brief schedule computations using continuation passing style 22 * @brief schedule computations using continuation passing style
@@ -71,6 +70,35 @@
71 70
72 71
73/** 72/**
73 * Argument to be passed from the driver to
74 * #GNUNET_SCHEDULER_run_from_driver(). Contains the
75 * scheduler's internal state.
76 */
77struct GNUNET_SCHEDULER_Handle
78{
79 /**
80 * Passed here to avoid constantly allocating/deallocating
81 * this element, but generally we want to get rid of this.
82 * @deprecated
83 */
84 struct GNUNET_NETWORK_FDSet *rs;
85
86 /**
87 * Passed here to avoid constantly allocating/deallocating
88 * this element, but generally we want to get rid of this.
89 * @deprecated
90 */
91 struct GNUNET_NETWORK_FDSet *ws;
92
93 /**
94 * Driver we used for the event loop.
95 */
96 const struct GNUNET_SCHEDULER_Driver *driver;
97
98};
99
100
101/**
74 * Entry in list of pending tasks. 102 * Entry in list of pending tasks.
75 */ 103 */
76struct GNUNET_SCHEDULER_Task 104struct GNUNET_SCHEDULER_Task
@@ -96,6 +124,11 @@ struct GNUNET_SCHEDULER_Task
96 void *callback_cls; 124 void *callback_cls;
97 125
98 /** 126 /**
127 * Handle to the scheduler's state.
128 */
129 const struct GNUNET_SCHEDULER_Handle *sh;
130
131 /**
99 * Set of file descriptors this task is waiting 132 * Set of file descriptors this task is waiting
100 * for for reading. Once ready, this is updated 133 * for for reading. Once ready, this is updated
101 * to reflect the set of file descriptors ready 134 * to reflect the set of file descriptors ready
@@ -111,6 +144,18 @@ struct GNUNET_SCHEDULER_Task
111 struct GNUNET_NETWORK_FDSet *write_set; 144 struct GNUNET_NETWORK_FDSet *write_set;
112 145
113 /** 146 /**
147 * Information about which FDs are ready for this task (and why).
148 */
149 const struct GNUNET_SCHEDULER_FdInfo *fds;
150
151 /**
152 * Storage location used for @e fds if we want to avoid
153 * a separate malloc() call in the common case that this
154 * task is only about a single FD.
155 */
156 struct GNUNET_SCHEDULER_FdInfo fdx;
157
158 /**
114 * Absolute timeout value for the task, or 159 * Absolute timeout value for the task, or
115 * #GNUNET_TIME_UNIT_FOREVER_ABS for "no timeout". 160 * #GNUNET_TIME_UNIT_FOREVER_ABS for "no timeout".
116 */ 161 */
@@ -124,6 +169,11 @@ struct GNUNET_SCHEDULER_Task
124#endif 169#endif
125 170
126 /** 171 /**
172 * Size of the @e fds array.
173 */
174 unsigned int fds_len;
175
176 /**
127 * Why is the task ready? Set after task is added to ready queue. 177 * Why is the task ready? Set after task is added to ready queue.
128 * Initially set to zero. All reasons that have already been 178 * Initially set to zero. All reasons that have already been
129 * satisfied (i.e. read or write ready) will be set over time. 179 * satisfied (i.e. read or write ready) will be set over time.
@@ -1742,7 +1792,8 @@ GNUNET_SCHEDULER_add_select (enum GNUNET_SCHEDULER_Priority prio,
1742 GNUNET_CONTAINER_DLL_insert (pending_head, 1792 GNUNET_CONTAINER_DLL_insert (pending_head,
1743 pending_tail, 1793 pending_tail,
1744 t); 1794 t);
1745 max_priority_added = GNUNET_MAX (max_priority_added, t->priority); 1795 max_priority_added = GNUNET_MAX (max_priority_added,
1796 t->priority);
1746 LOG (GNUNET_ERROR_TYPE_DEBUG, 1797 LOG (GNUNET_ERROR_TYPE_DEBUG,
1747 "Adding task %p\n", 1798 "Adding task %p\n",
1748 t); 1799 t);
@@ -1750,4 +1801,275 @@ GNUNET_SCHEDULER_add_select (enum GNUNET_SCHEDULER_Priority prio,
1750 return t; 1801 return t;
1751} 1802}
1752 1803
1804
1805/**
1806 * Function used by event-loop implementations to signal the scheduler
1807 * that a particular @a task is ready due to an event of type @a et.
1808 *
1809 * This function will then queue the task to notify the application
1810 * that the task is ready (with the respective priority).
1811 *
1812 * @param task the task that is ready, NULL for wake up calls
1813 * @param et information about why the task is ready
1814 */
1815void
1816GNUNET_SCHEDULER_task_ready (struct GNUNET_SCHEDULER_Task *task,
1817 enum GNUNET_SCHEDULER_EventType et)
1818{
1819 enum GNUNET_SCHEDULER_Reason reason;
1820 struct GNUNET_TIME_Absolute now;
1821
1822 now = GNUNET_TIME_absolute_get ();
1823 reason = task->reason;
1824 if (now.abs_value_us >= task->timeout.abs_value_us)
1825 reason |= GNUNET_SCHEDULER_REASON_TIMEOUT;
1826 if ( (0 == (reason & GNUNET_SCHEDULER_REASON_READ_READY)) &&
1827 (0 != (GNUNET_SCHEDULER_ET_IN & et)) )
1828 reason |= GNUNET_SCHEDULER_REASON_READ_READY;
1829 if ( (0 == (reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) &&
1830 (0 != (GNUNET_SCHEDULER_ET_OUT & et)) )
1831 reason |= GNUNET_SCHEDULER_REASON_WRITE_READY;
1832 reason |= GNUNET_SCHEDULER_REASON_PREREQ_DONE;
1833 task->reason = reason;
1834 task->fds = &task->fdx;
1835 task->fdx.et = et;
1836 task->fds_len = 1;
1837 queue_ready_task (task);
1838}
1839
1840
1841/**
1842 * Function called by the driver to tell the scheduler to run some of
1843 * the tasks that are ready. This function may return even though
1844 * there are tasks left to run just to give other tasks a chance as
1845 * well. If we return #GNUNET_YES, the driver should call this
1846 * function again as soon as possible, while if we return #GNUNET_NO
1847 * it must block until the operating system has more work as the
1848 * scheduler has no more work to do right now.
1849 *
1850 * @param sh scheduler handle that was given to the `loop`
1851 * @return #GNUNET_OK if there are more tasks that are ready,
1852 * and thus we would like to run more (yield to avoid
1853 * blocking other activities for too long)
1854 * #GNUNET_NO if we are done running tasks (yield to block)
1855 * #GNUNET_SYSERR on error
1856 */
1857int
1858GNUNET_SCHEDULER_run_from_driver (struct GNUNET_SCHEDULER_Handle *sh)
1859{
1860 enum GNUNET_SCHEDULER_Priority p;
1861 struct GNUNET_SCHEDULER_Task *pos;
1862 struct GNUNET_TIME_Absolute now;
1863
1864 /* check for tasks that reached the timeout! */
1865 now = GNUNET_TIME_absolute_get ();
1866 while (NULL != (pos = pending_timeout_head))
1867 {
1868 if (now.abs_value_us >= pos->timeout.abs_value_us)
1869 pos->reason |= GNUNET_SCHEDULER_REASON_TIMEOUT;
1870 if (0 == pos->reason)
1871 break;
1872 GNUNET_CONTAINER_DLL_remove (pending_timeout_head,
1873 pending_timeout_tail,
1874 pos);
1875 if (pending_timeout_last == pos)
1876 pending_timeout_last = NULL;
1877 queue_ready_task (pos);
1878 }
1879
1880 if (0 == ready_count)
1881 return GNUNET_NO;
1882
1883 /* find out which task priority level we are going to
1884 process this time */
1885 max_priority_added = GNUNET_SCHEDULER_PRIORITY_KEEP;
1886 GNUNET_assert (NULL == ready_head[GNUNET_SCHEDULER_PRIORITY_KEEP]);
1887 /* yes, p>0 is correct, 0 is "KEEP" which should
1888 * always be an empty queue (see assertion)! */
1889 for (p = GNUNET_SCHEDULER_PRIORITY_COUNT - 1; p > 0; p--)
1890 {
1891 pos = ready_head[p];
1892 if (NULL != pos)
1893 break;
1894 }
1895 GNUNET_assert (NULL != pos); /* ready_count wrong? */
1896
1897 /* process all tasks at this priority level, then yield */
1898 while (NULL != (pos = ready_head[p]))
1899 {
1900 GNUNET_CONTAINER_DLL_remove (ready_head[p],
1901 ready_tail[p],
1902 pos);
1903 ready_count--;
1904 current_priority = pos->priority;
1905 current_lifeness = pos->lifeness;
1906 active_task = pos;
1907#if PROFILE_DELAYS
1908 if (GNUNET_TIME_absolute_get_duration (pos->start_time).rel_value_us >
1909 DELAY_THRESHOLD.rel_value_us)
1910 {
1911 LOG (GNUNET_ERROR_TYPE_DEBUG,
1912 "Task %p took %s to be scheduled\n",
1913 pos,
1914 GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (pos->start_time),
1915 GNUNET_YES));
1916 }
1917#endif
1918 tc.reason = pos->reason;
1919 GNUNET_NETWORK_fdset_zero (sh->rs);
1920 GNUNET_NETWORK_fdset_zero (sh->ws);
1921 tc.fds_len = pos->fds_len;
1922 tc.fds = pos->fds;
1923 tc.read_ready = (NULL == pos->read_set) ? sh->rs : pos->read_set;
1924 if ( (-1 != pos->read_fd) &&
1925 (0 != (pos->reason & GNUNET_SCHEDULER_REASON_READ_READY)) )
1926 GNUNET_NETWORK_fdset_set_native (sh->rs,
1927 pos->read_fd);
1928 tc.write_ready = (NULL == pos->write_set) ? sh->ws : pos->write_set;
1929 if ((-1 != pos->write_fd) &&
1930 (0 != (pos->reason & GNUNET_SCHEDULER_REASON_WRITE_READY)))
1931 GNUNET_NETWORK_fdset_set_native (sh->ws,
1932 pos->write_fd);
1933 LOG (GNUNET_ERROR_TYPE_DEBUG,
1934 "Running task: %p\n",
1935 pos);
1936 pos->callback (pos->callback_cls);
1937 active_task = NULL;
1938 dump_backtrace (pos);
1939 destroy_task (pos);
1940 tasks_run++;
1941 }
1942 if (0 == ready_count)
1943 return GNUNET_NO;
1944 return GNUNET_OK;
1945}
1946
1947
1948/**
1949 * Initialize and run scheduler. This function will return when all
1950 * tasks have completed. On systems with signals, receiving a SIGTERM
1951 * (and other similar signals) will cause #GNUNET_SCHEDULER_shutdown
1952 * to be run after the active task is complete. As a result, SIGTERM
1953 * causes all shutdown tasks to be scheduled with reason
1954 * #GNUNET_SCHEDULER_REASON_SHUTDOWN. (However, tasks added
1955 * afterwards will execute normally!). Note that any particular
1956 * signal will only shut down one scheduler; applications should
1957 * always only create a single scheduler.
1958 *
1959 * @param driver drive to use for the event loop
1960 * @param task task to run first (and immediately)
1961 * @param task_cls closure of @a task
1962 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
1963 */
1964int
1965GNUNET_SCHEDULER_run_with_driver (const struct GNUNET_SCHEDULER_Driver *driver,
1966 GNUNET_SCHEDULER_TaskCallback task,
1967 void *task_cls)
1968{
1969 int ret;
1970 struct GNUNET_SIGNAL_Context *shc_int;
1971 struct GNUNET_SIGNAL_Context *shc_term;
1972#if (SIGTERM != GNUNET_TERM_SIG)
1973 struct GNUNET_SIGNAL_Context *shc_gterm;
1974#endif
1975#ifndef MINGW
1976 struct GNUNET_SIGNAL_Context *shc_quit;
1977 struct GNUNET_SIGNAL_Context *shc_hup;
1978 struct GNUNET_SIGNAL_Context *shc_pipe;
1979#endif
1980 struct GNUNET_SCHEDULER_Task tsk;
1981 const struct GNUNET_DISK_FileHandle *pr;
1982 struct GNUNET_SCHEDULER_Handle sh;
1983
1984 /* general set-up */
1985 GNUNET_assert (NULL == active_task);
1986 GNUNET_assert (NULL == shutdown_pipe_handle);
1987 shutdown_pipe_handle = GNUNET_DISK_pipe (GNUNET_NO,
1988 GNUNET_NO,
1989 GNUNET_NO,
1990 GNUNET_NO);
1991 GNUNET_assert (NULL != shutdown_pipe_handle);
1992 pr = GNUNET_DISK_pipe_handle (shutdown_pipe_handle,
1993 GNUNET_DISK_PIPE_END_READ);
1994 GNUNET_assert (NULL != pr);
1995 my_pid = getpid ();
1996
1997 /* install signal handlers */
1998 LOG (GNUNET_ERROR_TYPE_DEBUG,
1999 "Registering signal handlers\n");
2000 shc_int = GNUNET_SIGNAL_handler_install (SIGINT,
2001 &sighandler_shutdown);
2002 shc_term = GNUNET_SIGNAL_handler_install (SIGTERM,
2003 &sighandler_shutdown);
2004#if (SIGTERM != GNUNET_TERM_SIG)
2005 shc_gterm = GNUNET_SIGNAL_handler_install (GNUNET_TERM_SIG,
2006 &sighandler_shutdown);
2007#endif
2008#ifndef MINGW
2009 shc_pipe = GNUNET_SIGNAL_handler_install (SIGPIPE,
2010 &sighandler_pipe);
2011 shc_quit = GNUNET_SIGNAL_handler_install (SIGQUIT,
2012 &sighandler_shutdown);
2013 shc_hup = GNUNET_SIGNAL_handler_install (SIGHUP,
2014 &sighandler_shutdown);
2015#endif
2016
2017 /* Setup initial tasks */
2018 current_priority = GNUNET_SCHEDULER_PRIORITY_DEFAULT;
2019 current_lifeness = GNUNET_YES;
2020 memset (&tsk,
2021 0,
2022 sizeof (tsk));
2023 active_task = &tsk;
2024 tsk.sh = &sh;
2025 GNUNET_SCHEDULER_add_with_reason_and_priority (task,
2026 task_cls,
2027 GNUNET_SCHEDULER_REASON_STARTUP,
2028 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
2029 GNUNET_SCHEDULER_add_now_with_lifeness (GNUNET_NO,
2030 &GNUNET_OS_install_parent_control_handler,
2031 NULL);
2032 active_task = NULL;
2033 driver->set_wakeup (driver->cls,
2034 GNUNET_TIME_absolute_get ());
2035
2036 /* begin main event loop */
2037 sh.rs = GNUNET_NETWORK_fdset_create ();
2038 sh.ws = GNUNET_NETWORK_fdset_create ();
2039 sh.driver = driver;
2040 ret = driver->loop (driver->cls,
2041 &sh);
2042 GNUNET_NETWORK_fdset_destroy (sh.rs);
2043 GNUNET_NETWORK_fdset_destroy (sh.ws);
2044
2045 /* uninstall signal handlers */
2046 GNUNET_SIGNAL_handler_uninstall (shc_int);
2047 GNUNET_SIGNAL_handler_uninstall (shc_term);
2048#if (SIGTERM != GNUNET_TERM_SIG)
2049 GNUNET_SIGNAL_handler_uninstall (shc_gterm);
2050#endif
2051#ifndef MINGW
2052 GNUNET_SIGNAL_handler_uninstall (shc_pipe);
2053 GNUNET_SIGNAL_handler_uninstall (shc_quit);
2054 GNUNET_SIGNAL_handler_uninstall (shc_hup);
2055#endif
2056 GNUNET_DISK_pipe_close (shutdown_pipe_handle);
2057 shutdown_pipe_handle = NULL;
2058 return ret;
2059}
2060
2061
2062/**
2063 * Obtain the driver for using select() as the event loop.
2064 *
2065 * @return NULL on error
2066 */
2067const struct GNUNET_SCHEDULER_Driver *
2068GNUNET_SCHEDULER_driver_select ()
2069{
2070 GNUNET_break (0); // not implemented
2071 return NULL;
2072}
2073
2074
1753/* end of scheduler.c */ 2075/* end of scheduler.c */
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 40a8ba015..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", __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 3beb4a085..f63737e56 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"
@@ -36,84 +37,51 @@
36#endif 37#endif
37 38
38 39
39#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) 40#define LOG(kind,...) GNUNET_log_from (kind, "util-service", __VA_ARGS__)
40 41
41#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall) 42#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-service", syscall)
42 43
43#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", 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,12 +512,14 @@ 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';
483#endif 521#endif
484#if HAVE_SOCKADDR_IN_SIN_LEN 522#if HAVE_SOCKADDR_UN_SUN_LEN
485 un->sun_len = (u_char) sizeof (struct sockaddr_un); 523 un->sun_len = (u_char) sizeof (struct sockaddr_un);
486#endif 524#endif
487 *saddrs = (struct sockaddr *) un; 525 *saddrs = (struct sockaddr *) un;
@@ -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_cfgfile (&opt_cfg_filename),
1405 {'d', "daemonize", NULL, 1726 GNUNET_GETOPT_option_flag ('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)"),
1408 GNUNET_GETOPT_OPTION_HELP (NULL), 1729 &do_daemonize),
1409 GNUNET_GETOPT_OPTION_LOGLEVEL (&loglev), 1730 GNUNET_GETOPT_option_help (NULL),
1410 GNUNET_GETOPT_OPTION_LOGFILE (&logfile), 1731 GNUNET_GETOPT_option_loglevel (&loglev),
1411 GNUNET_GETOPT_OPTION_VERSION (PACKAGE_VERSION " " VCS_VERSION), 1732 GNUNET_GETOPT_option_logfile (&logfile),
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;
1595 } 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;
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 a893d287b..000000000
--- a/src/util/service_new.c
+++ /dev/null
@@ -1,2617 +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", __VA_ARGS__)
41
42#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall)
43
44#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", 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_IN_SIN_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 if (NULL != handlers)
1628 {
1629 unsigned int i;
1630
1631 for (i=0;NULL != handlers[i].cb; i++) ;
1632 sh->handlers = GNUNET_new_array (i + 1,
1633 struct GNUNET_MQ_MessageHandler);
1634 GNUNET_memcpy (sh->handlers,
1635 handlers,
1636 i * sizeof (struct GNUNET_MQ_MessageHandler));
1637 }
1638 if (GNUNET_OK != setup_service (sh))
1639 {
1640 GNUNET_free (sh->handlers);
1641 GNUNET_free (sh);
1642 return NULL;
1643 }
1644 GNUNET_SERVICE_resume (sh);
1645 return sh;
1646}
1647
1648
1649/**
1650 * Stops a service that was started with #GNUNET_SERVICE_starT().
1651 *
1652 * @param srv service to stop
1653 */
1654void
1655GNUNET_SERVICE_stoP (struct GNUNET_SERVICE_Handle *srv)
1656{
1657 struct GNUNET_SERVICE_Client *client;
1658
1659 GNUNET_SERVICE_suspend (srv);
1660 while (NULL != (client = srv->clients_head))
1661 GNUNET_SERVICE_client_drop (client);
1662 teardown_service (srv);
1663 GNUNET_free (srv->handlers);
1664 GNUNET_free (srv);
1665}
1666
1667
1668/**
1669 * Creates the "main" function for a GNUnet service. You
1670 * should almost always use the #GNUNET_SERVICE_MAIN macro
1671 * instead of calling this function directly (except
1672 * for ARM, which should call this function directly).
1673 *
1674 * The function will launch the service with the name @a service_name
1675 * using the @a service_options to configure its shutdown
1676 * behavior. Once the service is ready, the @a init_cb will be called
1677 * for service-specific initialization. @a init_cb will be given the
1678 * service handler which can be used to control the service's
1679 * availability. When clients connect or disconnect, the respective
1680 * @a connect_cb or @a disconnect_cb functions will be called. For
1681 * messages received from the clients, the respective @a handlers will
1682 * be invoked; for the closure of the handlers we use the return value
1683 * from the @a connect_cb invocation of the respective client.
1684 *
1685 * Each handler MUST call #GNUNET_SERVICE_client_continue() after each
1686 * message to receive further messages from this client. If
1687 * #GNUNET_SERVICE_client_continue() is not called within a short
1688 * time, a warning will be logged. If delays are expected, services
1689 * should call #GNUNET_SERVICE_client_disable_continue_warning() to
1690 * disable the warning.
1691 *
1692 * Clients sending invalid messages (based on @a handlers) will be
1693 * dropped. Additionally, clients can be dropped at any time using
1694 * #GNUNET_SERVICE_client_drop().
1695 *
1696 * @param argc number of command-line arguments in @a argv
1697 * @param argv array of command-line arguments
1698 * @param service_name name of the service to run
1699 * @param options options controlling shutdown of the service
1700 * @param service_init_cb function to call once the service is ready
1701 * @param connect_cb function to call whenever a client connects
1702 * @param disconnect_cb function to call whenever a client disconnects
1703 * @param cls closure argument for @a service_init_cb, @a connect_cb and @a disconnect_cb
1704 * @param handlers NULL-terminated array of message handlers for the service,
1705 * the closure will be set to the value returned by
1706 * the @a connect_cb for the respective connection
1707 * @return 0 on success, non-zero on error
1708 */
1709int
1710GNUNET_SERVICE_ruN_ (int argc,
1711 char *const *argv,
1712 const char *service_name,
1713 enum GNUNET_SERVICE_Options options,
1714 GNUNET_SERVICE_InitCallback service_init_cb,
1715 GNUNET_SERVICE_ConnectHandler connect_cb,
1716 GNUNET_SERVICE_DisconnectHandler disconnect_cb,
1717 void *cls,
1718 const struct GNUNET_MQ_MessageHandler *handlers)
1719{
1720 struct GNUNET_SERVICE_Handle sh;
1721 char *cfg_filename;
1722 char *opt_cfg_filename;
1723 char *loglev;
1724 const char *xdg;
1725 char *logfile;
1726 int do_daemonize;
1727 unsigned long long skew_offset;
1728 unsigned long long skew_variance;
1729 long long clock_offset;
1730 struct GNUNET_CONFIGURATION_Handle *cfg;
1731 int ret;
1732 int err;
1733
1734 struct GNUNET_GETOPT_CommandLineOption service_options[] = {
1735 GNUNET_GETOPT_OPTION_CFG_FILE (&opt_cfg_filename),
1736 {'d', "daemonize", NULL,
1737 gettext_noop ("do daemonize (detach from terminal)"), 0,
1738 GNUNET_GETOPT_set_one, &do_daemonize},
1739 GNUNET_GETOPT_OPTION_HELP (NULL),
1740 GNUNET_GETOPT_OPTION_LOGLEVEL (&loglev),
1741 GNUNET_GETOPT_OPTION_LOGFILE (&logfile),
1742 GNUNET_GETOPT_OPTION_VERSION (PACKAGE_VERSION " " VCS_VERSION),
1743 GNUNET_GETOPT_OPTION_END
1744 };
1745
1746 memset (&sh,
1747 0,
1748 sizeof (sh));
1749 xdg = getenv ("XDG_CONFIG_HOME");
1750 if (NULL != xdg)
1751 GNUNET_asprintf (&cfg_filename,
1752 "%s%s%s",
1753 xdg,
1754 DIR_SEPARATOR_STR,
1755 GNUNET_OS_project_data_get ()->config_file);
1756 else
1757 cfg_filename = GNUNET_strdup (GNUNET_OS_project_data_get ()->user_config_file);
1758 sh.ready_confirm_fd = -1;
1759 sh.options = options;
1760 sh.cfg = cfg = GNUNET_CONFIGURATION_create ();
1761 sh.service_init_cb = service_init_cb;
1762 sh.connect_cb = connect_cb;
1763 sh.disconnect_cb = disconnect_cb;
1764 sh.cb_cls = cls;
1765 if (NULL != handlers)
1766 {
1767 unsigned int i;
1768
1769 for (i=0;NULL != handlers[i].cb; i++) ;
1770 sh.handlers = GNUNET_new_array (i + 1,
1771 struct GNUNET_MQ_MessageHandler);
1772 GNUNET_memcpy (sh.handlers,
1773 handlers,
1774 i * sizeof (struct GNUNET_MQ_MessageHandler));
1775 }
1776 sh.service_name = service_name;
1777
1778 /* setup subsystems */
1779 loglev = NULL;
1780 logfile = NULL;
1781 opt_cfg_filename = NULL;
1782 do_daemonize = 0;
1783 ret = GNUNET_GETOPT_run (service_name,
1784 service_options,
1785 argc,
1786 argv);
1787 if (GNUNET_SYSERR == ret)
1788 goto shutdown;
1789 if (GNUNET_NO == ret)
1790 {
1791 err = 0;
1792 goto shutdown;
1793 }
1794 if (GNUNET_OK != GNUNET_log_setup (service_name,
1795 loglev,
1796 logfile))
1797 {
1798 GNUNET_break (0);
1799 goto shutdown;
1800 }
1801 if (NULL == opt_cfg_filename)
1802 opt_cfg_filename = GNUNET_strdup (cfg_filename);
1803 if (GNUNET_YES == GNUNET_DISK_file_test (opt_cfg_filename))
1804 {
1805 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg,
1806 opt_cfg_filename))
1807 {
1808 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1809 _("Malformed configuration file `%s', exit ...\n"),
1810 opt_cfg_filename);
1811 goto shutdown;
1812 }
1813 }
1814 else
1815 {
1816 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg,
1817 NULL))
1818 {
1819 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1820 _("Malformed configuration, exit ...\n"));
1821 goto shutdown;
1822 }
1823 if (0 != strcmp (opt_cfg_filename,
1824 cfg_filename))
1825 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1826 _("Could not access configuration file `%s'\n"),
1827 opt_cfg_filename);
1828 }
1829 if (GNUNET_OK != setup_service (&sh))
1830 goto shutdown;
1831 if ( (1 == do_daemonize) &&
1832 (GNUNET_OK != detach_terminal (&sh)) )
1833 {
1834 GNUNET_break (0);
1835 goto shutdown;
1836 }
1837 if (GNUNET_OK != set_user_id (&sh))
1838 goto shutdown;
1839 LOG (GNUNET_ERROR_TYPE_DEBUG,
1840 "Service `%s' runs with configuration from `%s'\n",
1841 service_name,
1842 opt_cfg_filename);
1843 if ((GNUNET_OK ==
1844 GNUNET_CONFIGURATION_get_value_number (sh.cfg,
1845 "TESTING",
1846 "SKEW_OFFSET",
1847 &skew_offset)) &&
1848 (GNUNET_OK ==
1849 GNUNET_CONFIGURATION_get_value_number (sh.cfg,
1850 "TESTING",
1851 "SKEW_VARIANCE",
1852 &skew_variance)))
1853 {
1854 clock_offset = skew_offset - skew_variance;
1855 GNUNET_TIME_set_offset (clock_offset);
1856 LOG (GNUNET_ERROR_TYPE_DEBUG,
1857 "Skewing clock by %dll ms\n",
1858 clock_offset);
1859 }
1860 GNUNET_RESOLVER_connect (sh.cfg);
1861
1862 /* actually run service */
1863 err = 0;
1864 GNUNET_SCHEDULER_run (&service_main,
1865 &sh);
1866 /* shutdown */
1867 if (1 == do_daemonize)
1868 pid_file_delete (&sh);
1869
1870shutdown:
1871 if (-1 != sh.ready_confirm_fd)
1872 {
1873 if (1 != WRITE (sh.ready_confirm_fd,
1874 err ? "I" : "S",
1875 1))
1876 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING,
1877 "write");
1878 GNUNET_break (0 == CLOSE (sh.ready_confirm_fd));
1879 }
1880#if HAVE_MALLINFO
1881 {
1882 char *counter;
1883
1884 if ( (GNUNET_YES ==
1885 GNUNET_CONFIGURATION_have_value (sh.cfg,
1886 service_name,
1887 "GAUGER_HEAP")) &&
1888 (GNUNET_OK ==
1889 GNUNET_CONFIGURATION_get_value_string (sh.cfg,
1890 service_name,
1891 "GAUGER_HEAP",
1892 &counter)) )
1893 {
1894 struct mallinfo mi;
1895
1896 mi = mallinfo ();
1897 GAUGER (service_name,
1898 counter,
1899 mi.usmblks,
1900 "blocks");
1901 GNUNET_free (counter);
1902 }
1903 }
1904#endif
1905 teardown_service (&sh);
1906 GNUNET_free (sh.handlers);
1907 GNUNET_SPEEDUP_stop_ ();
1908 GNUNET_CONFIGURATION_destroy (cfg);
1909 GNUNET_free_non_null (logfile);
1910 GNUNET_free_non_null (loglev);
1911 GNUNET_free (cfg_filename);
1912 GNUNET_free_non_null (opt_cfg_filename);
1913
1914 return err ? GNUNET_SYSERR : sh.ret;
1915}
1916
1917
1918/**
1919 * Suspend accepting connections from the listen socket temporarily.
1920 * Resume activity using #GNUNET_SERVICE_resume.
1921 *
1922 * @param sh service to stop accepting connections.
1923 */
1924void
1925GNUNET_SERVICE_suspend (struct GNUNET_SERVICE_Handle *sh)
1926{
1927 struct ServiceListenContext *slc;
1928
1929 for (slc = sh->slc_head; NULL != slc; slc = slc->next)
1930 {
1931 if (NULL != slc->listen_task)
1932 {
1933 GNUNET_SCHEDULER_cancel (slc->listen_task);
1934 slc->listen_task = NULL;
1935 }
1936 }
1937}
1938
1939
1940/**
1941 * Task run when we are ready to transmit data to the
1942 * client.
1943 *
1944 * @param cls the `struct GNUNET_SERVICE_Client *` to send to
1945 */
1946static void
1947do_send (void *cls)
1948{
1949 struct GNUNET_SERVICE_Client *client = cls;
1950 ssize_t ret;
1951 size_t left;
1952 const char *buf;
1953
1954 client->send_task = NULL;
1955 buf = (const char *) client->msg;
1956 left = ntohs (client->msg->size) - client->msg_pos;
1957 ret = GNUNET_NETWORK_socket_send (client->sock,
1958 &buf[client->msg_pos],
1959 left);
1960 GNUNET_assert (ret <= (ssize_t) left);
1961 if (0 == ret)
1962 {
1963 GNUNET_MQ_inject_error (client->mq,
1964 GNUNET_MQ_ERROR_WRITE);
1965 return;
1966 }
1967 if (-1 == ret)
1968 {
1969 if ( (EAGAIN == errno) ||
1970 (EINTR == errno) )
1971 {
1972 /* ignore */
1973 ret = 0;
1974 }
1975 else
1976 {
1977 if (EPIPE != errno)
1978 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
1979 "send");
1980 GNUNET_MQ_inject_error (client->mq,
1981 GNUNET_MQ_ERROR_WRITE);
1982 return;
1983 }
1984 }
1985 if (0 == client->msg_pos)
1986 {
1987 GNUNET_MQ_impl_send_in_flight (client->mq);
1988 }
1989 client->msg_pos += ret;
1990 if (left > ret)
1991 {
1992 client->send_task
1993 = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
1994 client->sock,
1995 &do_send,
1996 client);
1997 return;
1998 }
1999 GNUNET_MQ_impl_send_continue (client->mq);
2000}
2001
2002
2003/**
2004 * Signature of functions implementing the sending functionality of a
2005 * message queue.
2006 *
2007 * @param mq the message queue
2008 * @param msg the message to send
2009 * @param impl_state our `struct GNUNET_SERVICE_Client *`
2010 */
2011static void
2012service_mq_send (struct GNUNET_MQ_Handle *mq,
2013 const struct GNUNET_MessageHeader *msg,
2014 void *impl_state)
2015{
2016 struct GNUNET_SERVICE_Client *client = impl_state;
2017
2018 GNUNET_assert (NULL == client->send_task);
2019 client->msg = msg;
2020 client->msg_pos = 0;
2021 client->send_task
2022 = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
2023 client->sock,
2024 &do_send,
2025 client);
2026}
2027
2028
2029/**
2030 * Implementation function that cancels the currently sent message.
2031 *
2032 * @param mq message queue
2033 * @param impl_state state specific to the implementation
2034 */
2035static void
2036service_mq_cancel (struct GNUNET_MQ_Handle *mq,
2037 void *impl_state)
2038{
2039 struct GNUNET_SERVICE_Client *client = impl_state;
2040
2041 GNUNET_assert (0 == client->msg_pos);
2042 client->msg = NULL;
2043 GNUNET_SCHEDULER_cancel (client->send_task);
2044 client->send_task = NULL;
2045}
2046
2047
2048/**
2049 * Generic error handler, called with the appropriate
2050 * error code and the same closure specified at the creation of
2051 * the message queue.
2052 * Not every message queue implementation supports an error handler.
2053 *
2054 * @param cls closure with our `struct GNUNET_SERVICE_Client`
2055 * @param error error code
2056 */
2057static void
2058service_mq_error_handler (void *cls,
2059 enum GNUNET_MQ_Error error)
2060{
2061 struct GNUNET_SERVICE_Client *client = cls;
2062 struct GNUNET_SERVICE_Handle *sh = client->sh;
2063
2064 if ( (GNUNET_MQ_ERROR_NO_MATCH == error) &&
2065 (GNUNET_NO == sh->require_found) )
2066 {
2067 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2068 "No handler for message of type %u found\n",
2069 (unsigned int) client->warn_type);
2070 GNUNET_SERVICE_client_continue (client);
2071 return; /* ignore error */
2072 }
2073 GNUNET_SERVICE_client_drop (client);
2074}
2075
2076
2077/**
2078 * Task run to warn about missing calls to #GNUNET_SERVICE_client_continue().
2079 *
2080 * @param cls our `struct GNUNET_SERVICE_Client *` to process more requests from
2081 */
2082static void
2083warn_no_client_continue (void *cls)
2084{
2085 struct GNUNET_SERVICE_Client *client = cls;
2086
2087 GNUNET_break (0 != client->warn_type); /* type should never be 0 here, as we don't use 0 */
2088 client->warn_task
2089 = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
2090 &warn_no_client_continue,
2091 client);
2092 LOG (GNUNET_ERROR_TYPE_WARNING,
2093 _("Processing code for message of type %u did not call `GNUNET_SERVICE_client_continue' after %s\n"),
2094 (unsigned int) client->warn_type,
2095 GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (client->warn_start),
2096 GNUNET_YES));
2097}
2098
2099
2100/**
2101 * Functions with this signature are called whenever a
2102 * complete message is received by the tokenizer for a client.
2103 *
2104 * Do not call #GNUNET_MST_destroy() from within
2105 * the scope of this callback.
2106 *
2107 * @param cls closure with the `struct GNUNET_SERVICE_Client *`
2108 * @param message the actual message
2109 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the client was dropped
2110 */
2111static int
2112service_client_mst_cb (void *cls,
2113 const struct GNUNET_MessageHeader *message)
2114{
2115 struct GNUNET_SERVICE_Client *client = cls;
2116
2117 GNUNET_assert (GNUNET_NO == client->needs_continue);
2118 client->needs_continue = GNUNET_YES;
2119 client->warn_type = ntohs (message->type);
2120 client->warn_start = GNUNET_TIME_absolute_get ();
2121 GNUNET_assert (NULL == client->warn_task);
2122 client->warn_task
2123 = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
2124 &warn_no_client_continue,
2125 client);
2126 GNUNET_MQ_inject_message (client->mq,
2127 message);
2128 if (NULL != client->drop_task)
2129 return GNUNET_SYSERR;
2130 return GNUNET_OK;
2131}
2132
2133
2134/**
2135 * A client sent us data. Receive and process it. If we are done,
2136 * reschedule this task.
2137 *
2138 * @param cls the `struct GNUNET_SERVICE_Client` that sent us data.
2139 */
2140static void
2141service_client_recv (void *cls)
2142{
2143 struct GNUNET_SERVICE_Client *client = cls;
2144 int ret;
2145
2146 client->recv_task = NULL;
2147 ret = GNUNET_MST_read (client->mst,
2148 client->sock,
2149 GNUNET_NO,
2150 GNUNET_YES);
2151 if (GNUNET_SYSERR == ret)
2152 {
2153 /* client closed connection (or IO error) */
2154 if (NULL == client->drop_task)
2155 {
2156 GNUNET_assert (GNUNET_NO == client->needs_continue);
2157 GNUNET_SERVICE_client_drop (client);
2158 }
2159 return;
2160 }
2161 if (GNUNET_NO == ret)
2162 return; /* more messages in buffer, wait for application
2163 to be done processing */
2164 GNUNET_assert (GNUNET_OK == ret);
2165 if (GNUNET_YES == client->needs_continue)
2166 return;
2167 if (NULL != client->recv_task)
2168 return;
2169 /* MST needs more data, re-schedule read job */
2170 client->recv_task
2171 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
2172 client->sock,
2173 &service_client_recv,
2174 client);
2175}
2176
2177
2178/**
2179 * We have successfully accepted a connection from a client. Now
2180 * setup the client (with the scheduler) and tell the application.
2181 *
2182 * @param sh service that accepted the client
2183 * @param sock socket associated with the client
2184 */
2185static void
2186start_client (struct GNUNET_SERVICE_Handle *sh,
2187 struct GNUNET_NETWORK_Handle *csock)
2188{
2189 struct GNUNET_SERVICE_Client *client;
2190
2191 client = GNUNET_new (struct GNUNET_SERVICE_Client);
2192 GNUNET_CONTAINER_DLL_insert (sh->clients_head,
2193 sh->clients_tail,
2194 client);
2195 client->sh = sh;
2196 client->sock = csock;
2197 client->mq = GNUNET_MQ_queue_for_callbacks (&service_mq_send,
2198 NULL,
2199 &service_mq_cancel,
2200 client,
2201 sh->handlers,
2202 &service_mq_error_handler,
2203 client);
2204 client->mst = GNUNET_MST_create (&service_client_mst_cb,
2205 client);
2206 client->user_context = sh->connect_cb (sh->cb_cls,
2207 client,
2208 client->mq);
2209 GNUNET_MQ_set_handlers_closure (client->mq,
2210 client->user_context);
2211 client->recv_task
2212 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
2213 client->sock,
2214 &service_client_recv,
2215 client);
2216}
2217
2218
2219/**
2220 * Check if the given IP address is in the list of IP addresses.
2221 *
2222 * @param list a list of networks
2223 * @param add the IP to check (in network byte order)
2224 * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is
2225 */
2226static int
2227check_ipv4_listed (const struct GNUNET_STRINGS_IPv4NetworkPolicy *list,
2228 const struct in_addr *add)
2229{
2230 unsigned int i;
2231
2232 if (NULL == list)
2233 return GNUNET_NO;
2234 i = 0;
2235 while ( (0 != list[i].network.s_addr) ||
2236 (0 != list[i].netmask.s_addr) )
2237 {
2238 if ((add->s_addr & list[i].netmask.s_addr) ==
2239 (list[i].network.s_addr & list[i].netmask.s_addr))
2240 return GNUNET_YES;
2241 i++;
2242 }
2243 return GNUNET_NO;
2244}
2245
2246
2247/**
2248 * Check if the given IP address is in the list of IP addresses.
2249 *
2250 * @param list a list of networks
2251 * @param ip the IP to check (in network byte order)
2252 * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is
2253 */
2254static int
2255check_ipv6_listed (const struct GNUNET_STRINGS_IPv6NetworkPolicy *list,
2256 const struct in6_addr *ip)
2257{
2258 unsigned int i;
2259 unsigned int j;
2260 struct in6_addr zero;
2261
2262 if (NULL == list)
2263 return GNUNET_NO;
2264 memset (&zero,
2265 0,
2266 sizeof (struct in6_addr));
2267 i = 0;
2268NEXT:
2269 while (0 != memcmp (&zero,
2270 &list[i].network,
2271 sizeof (struct in6_addr)))
2272 {
2273 for (j = 0; j < sizeof (struct in6_addr) / sizeof (int); j++)
2274 if (((((int *) ip)[j] & ((int *) &list[i].netmask)[j])) !=
2275 (((int *) &list[i].network)[j] & ((int *) &list[i].netmask)[j]))
2276 {
2277 i++;
2278 goto NEXT;
2279 }
2280 return GNUNET_YES;
2281 }
2282 return GNUNET_NO;
2283}
2284
2285
2286/**
2287 * We have a client. Accept the incoming socket(s) (and reschedule
2288 * the listen task).
2289 *
2290 * @param cls the `struct ServiceListenContext` of the ready listen socket
2291 */
2292static void
2293accept_client (void *cls)
2294{
2295 struct ServiceListenContext *slc = cls;
2296 struct GNUNET_SERVICE_Handle *sh = slc->sh;
2297
2298 slc->listen_task = NULL;
2299 while (1)
2300 {
2301 struct GNUNET_NETWORK_Handle *sock;
2302 const struct sockaddr_in *v4;
2303 const struct sockaddr_in6 *v6;
2304 struct sockaddr_storage sa;
2305 socklen_t addrlen;
2306 int ok;
2307
2308 addrlen = sizeof (sa);
2309 sock = GNUNET_NETWORK_socket_accept (slc->listen_socket,
2310 (struct sockaddr *) &sa,
2311 &addrlen);
2312 if (NULL == sock)
2313 break;
2314 switch (sa.ss_family)
2315 {
2316 case AF_INET:
2317 GNUNET_assert (addrlen == sizeof (struct sockaddr_in));
2318 v4 = (const struct sockaddr_in *) &sa;
2319 ok = ( ( (NULL == sh->v4_allowed) ||
2320 (check_ipv4_listed (sh->v4_allowed,
2321 &v4->sin_addr))) &&
2322 ( (NULL == sh->v4_denied) ||
2323 (! check_ipv4_listed (sh->v4_denied,
2324 &v4->sin_addr)) ) );
2325 break;
2326 case AF_INET6:
2327 GNUNET_assert (addrlen == sizeof (struct sockaddr_in6));
2328 v6 = (const struct sockaddr_in6 *) &sa;
2329 ok = ( ( (NULL == sh->v6_allowed) ||
2330 (check_ipv6_listed (sh->v6_allowed,
2331 &v6->sin6_addr))) &&
2332 ( (NULL == sh->v6_denied) ||
2333 (! check_ipv6_listed (sh->v6_denied,
2334 &v6->sin6_addr)) ) );
2335 break;
2336#ifndef WINDOWS
2337 case AF_UNIX:
2338 ok = GNUNET_OK; /* controlled using file-system ACL now */
2339 break;
2340#endif
2341 default:
2342 LOG (GNUNET_ERROR_TYPE_WARNING,
2343 _("Unknown address family %d\n"),
2344 sa.ss_family);
2345 return;
2346 }
2347 if (! ok)
2348 {
2349 LOG (GNUNET_ERROR_TYPE_DEBUG,
2350 "Service rejected incoming connection from %s due to policy.\n",
2351 GNUNET_a2s ((const struct sockaddr *) &sa,
2352 addrlen));
2353 GNUNET_break (GNUNET_OK ==
2354 GNUNET_NETWORK_socket_close (sock));
2355 continue;
2356 }
2357 LOG (GNUNET_ERROR_TYPE_DEBUG,
2358 "Service accepted incoming connection from %s.\n",
2359 GNUNET_a2s ((const struct sockaddr *) &sa,
2360 addrlen));
2361 start_client (slc->sh,
2362 sock);
2363 }
2364 slc->listen_task
2365 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
2366 slc->listen_socket,
2367 &accept_client,
2368 slc);
2369}
2370
2371
2372/**
2373 * Resume accepting connections from the listen socket.
2374 *
2375 * @param sh service to resume accepting connections.
2376 */
2377void
2378GNUNET_SERVICE_resume (struct GNUNET_SERVICE_Handle *sh)
2379{
2380 struct ServiceListenContext *slc;
2381
2382 for (slc = sh->slc_head; NULL != slc; slc = slc->next)
2383 {
2384 GNUNET_assert (NULL == slc->listen_task);
2385 slc->listen_task
2386 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
2387 slc->listen_socket,
2388 &accept_client,
2389 slc);
2390 }
2391}
2392
2393
2394/**
2395 * Task run to resume receiving data from the client after
2396 * the client called #GNUNET_SERVICE_client_continue().
2397 *
2398 * @param cls our `struct GNUNET_SERVICE_Client`
2399 */
2400static void
2401resume_client_receive (void *cls)
2402{
2403 struct GNUNET_SERVICE_Client *c = cls;
2404 int ret;
2405
2406 c->recv_task = NULL;
2407 /* first, check if there is still something in the buffer */
2408 ret = GNUNET_MST_next (c->mst,
2409 GNUNET_YES);
2410 if (GNUNET_SYSERR == ret)
2411 {
2412 GNUNET_break (0);
2413 GNUNET_SERVICE_client_drop (c);
2414 return;
2415 }
2416 if (GNUNET_NO == ret)
2417 return; /* done processing, wait for more later */
2418 GNUNET_assert (GNUNET_OK == ret);
2419 if (GNUNET_YES == c->needs_continue)
2420 return; /* #GNUNET_MST_next() did give a message to the client */
2421 /* need to receive more data from the network first */
2422 if (NULL != c->recv_task)
2423 return;
2424 c->recv_task
2425 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
2426 c->sock,
2427 &service_client_recv,
2428 c);
2429}
2430
2431
2432/**
2433 * Continue receiving further messages from the given client.
2434 * Must be called after each message received.
2435 *
2436 * @param c the client to continue receiving from
2437 */
2438void
2439GNUNET_SERVICE_client_continue (struct GNUNET_SERVICE_Client *c)
2440{
2441 GNUNET_assert (GNUNET_YES == c->needs_continue);
2442 GNUNET_assert (NULL == c->recv_task);
2443 c->needs_continue = GNUNET_NO;
2444 if (NULL != c->warn_task)
2445 {
2446 GNUNET_SCHEDULER_cancel (c->warn_task);
2447 c->warn_task = NULL;
2448 }
2449 c->recv_task
2450 = GNUNET_SCHEDULER_add_now (&resume_client_receive,
2451 c);
2452}
2453
2454
2455/**
2456 * Disable the warning the server issues if a message is not
2457 * acknowledged in a timely fashion. Use this call if a client is
2458 * intentionally delayed for a while. Only applies to the current
2459 * message.
2460 *
2461 * @param c client for which to disable the warning
2462 */
2463void
2464GNUNET_SERVICE_client_disable_continue_warning (struct GNUNET_SERVICE_Client *c)
2465{
2466 GNUNET_break (NULL != c->warn_task);
2467 if (NULL != c->warn_task)
2468 {
2469 GNUNET_SCHEDULER_cancel (c->warn_task);
2470 c->warn_task = NULL;
2471 }
2472}
2473
2474
2475/**
2476 * Asynchronously finish dropping the client.
2477 *
2478 * @param cls the `struct GNUNET_SERVICE_Client`.
2479 */
2480static void
2481finish_client_drop (void *cls)
2482{
2483 struct GNUNET_SERVICE_Client *c = cls;
2484 struct GNUNET_SERVICE_Handle *sh = c->sh;
2485
2486 GNUNET_MST_destroy (c->mst);
2487 GNUNET_MQ_destroy (c->mq);
2488 if (GNUNET_NO == c->persist)
2489 {
2490 GNUNET_break (GNUNET_OK ==
2491 GNUNET_NETWORK_socket_close (c->sock));
2492 }
2493 else
2494 {
2495 GNUNET_NETWORK_socket_free_memory_only_ (c->sock);
2496 }
2497 GNUNET_free (c);
2498 if ( (GNUNET_YES == sh->got_shutdown) &&
2499 (GNUNET_NO == have_non_monitor_clients (sh)) )
2500 GNUNET_SERVICE_shutdown (sh);
2501}
2502
2503
2504/**
2505 * Ask the server to disconnect from the given client. This is the
2506 * same as returning #GNUNET_SYSERR within the check procedure when
2507 * handling a message, wexcept that it allows dropping of a client even
2508 * when not handling a message from that client. The `disconnect_cb`
2509 * will be called on @a c even if the application closes the connection
2510 * using this function.
2511 *
2512 * @param c client to disconnect now
2513 */
2514void
2515GNUNET_SERVICE_client_drop (struct GNUNET_SERVICE_Client *c)
2516{
2517 struct GNUNET_SERVICE_Handle *sh = c->sh;
2518
2519 if (NULL != c->drop_task)
2520 {
2521 /* asked to drop twice! */
2522 GNUNET_break (0);
2523 return;
2524 }
2525 GNUNET_CONTAINER_DLL_remove (sh->clients_head,
2526 sh->clients_tail,
2527 c);
2528 sh->disconnect_cb (sh->cb_cls,
2529 c,
2530 c->user_context);
2531 if (NULL != c->warn_task)
2532 {
2533 GNUNET_SCHEDULER_cancel (c->warn_task);
2534 c->warn_task = NULL;
2535 }
2536 if (NULL != c->recv_task)
2537 {
2538 GNUNET_SCHEDULER_cancel (c->recv_task);
2539 c->recv_task = NULL;
2540 }
2541 if (NULL != c->send_task)
2542 {
2543 GNUNET_SCHEDULER_cancel (c->send_task);
2544 c->send_task = NULL;
2545 }
2546 c->drop_task = GNUNET_SCHEDULER_add_now (&finish_client_drop,
2547 c);
2548}
2549
2550
2551/**
2552 * Explicitly stops the service.
2553 *
2554 * @param sh server to shutdown
2555 */
2556void
2557GNUNET_SERVICE_shutdown (struct GNUNET_SERVICE_Handle *sh)
2558{
2559 struct GNUNET_SERVICE_Client *client;
2560
2561 GNUNET_SERVICE_suspend (sh);
2562 sh->got_shutdown = GNUNET_NO;
2563 while (NULL != (client = sh->clients_head))
2564 GNUNET_SERVICE_client_drop (client);
2565}
2566
2567
2568/**
2569 * Set the 'monitor' flag on this client. Clients which have been
2570 * marked as 'monitors' won't prevent the server from shutting down
2571 * once #GNUNET_SERVICE_stop_listening() has been invoked. The idea is
2572 * that for "normal" clients we likely want to allow them to process
2573 * their requests; however, monitor-clients are likely to 'never'
2574 * disconnect during shutdown and thus will not be considered when
2575 * determining if the server should continue to exist after
2576 * shutdown has been triggered.
2577 *
2578 * @param c client to mark as a monitor
2579 */
2580void
2581GNUNET_SERVICE_client_mark_monitor (struct GNUNET_SERVICE_Client *c)
2582{
2583 c->is_monitor = GNUNET_YES;
2584 if ( (GNUNET_YES == c->sh->got_shutdown) &&
2585 (GNUNET_NO == have_non_monitor_clients (c->sh)) )
2586 GNUNET_SERVICE_shutdown (c->sh);
2587}
2588
2589
2590/**
2591 * Set the persist option on this client. Indicates that the
2592 * underlying socket or fd should never really be closed. Used for
2593 * indicating process death.
2594 *
2595 * @param c client to persist the socket (never to be closed)
2596 */
2597void
2598GNUNET_SERVICE_client_persist (struct GNUNET_SERVICE_Client *c)
2599{
2600 c->persist = GNUNET_YES;
2601}
2602
2603
2604/**
2605 * Obtain the message queue of @a c. Convenience function.
2606 *
2607 * @param c the client to continue receiving from
2608 * @return the message queue of @a c
2609 */
2610struct GNUNET_MQ_Handle *
2611GNUNET_SERVICE_client_get_mq (struct GNUNET_SERVICE_Client *c)
2612{
2613 return c->mq;
2614}
2615
2616
2617/* end of service_new.c */
diff --git a/src/util/signal.c b/src/util/signal.c
index 543fcd899..cb917e36a 100644
--- a/src/util/signal.c
+++ b/src/util/signal.c
@@ -27,7 +27,7 @@
27#include "platform.h" 27#include "platform.h"
28#include "gnunet_util_lib.h" 28#include "gnunet_util_lib.h"
29 29
30#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) 30#define LOG(kind,...) GNUNET_log_from (kind, "util-signal", __VA_ARGS__)
31 31
32 32
33struct GNUNET_SIGNAL_Context 33struct GNUNET_SIGNAL_Context
diff --git a/src/util/socks.c b/src/util/socks.c
index fee79cc80..85548fd79 100644
--- a/src/util/socks.c
+++ b/src/util/socks.c
@@ -29,9 +29,9 @@
29#include "gnunet_util_lib.h" 29#include "gnunet_util_lib.h"
30 30
31 31
32#define LOG(kind,...) GNUNET_log_from (kind, "socks", __VA_ARGS__) 32#define LOG(kind,...) GNUNET_log_from (kind, "util-socks", __VA_ARGS__)
33 33
34#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "socks", syscall) 34#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-socks", syscall)
35 35
36 36
37/* SOCKS5 authentication methods */ 37/* SOCKS5 authentication methods */
@@ -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/speedup.c b/src/util/speedup.c
index 97df65c8e..c6a4cf678 100644
--- a/src/util/speedup.c
+++ b/src/util/speedup.c
@@ -27,7 +27,7 @@
27#include "gnunet_util_lib.h" 27#include "gnunet_util_lib.h"
28#include "speedup.h" 28#include "speedup.h"
29 29
30#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) 30#define LOG(kind,...) GNUNET_log_from (kind, "util-speedup", __VA_ARGS__)
31 31
32 32
33static struct GNUNET_TIME_Relative interval; 33static struct GNUNET_TIME_Relative interval;
diff --git a/src/util/strings.c b/src/util/strings.c
index 2b51d3e52..d3268f4d9 100644
--- a/src/util/strings.c
+++ b/src/util/strings.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 Copyright (C) 2005-2013 GNUnet e.V. 3 Copyright (C) 2005-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,7 +17,6 @@
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
21/** 20/**
22 * @file util/strings.c 21 * @file util/strings.c
23 * @brief string functions 22 * @brief string functions
@@ -35,9 +34,9 @@
35#include <unistr.h> 34#include <unistr.h>
36#include <uniconv.h> 35#include <uniconv.h>
37 36
38#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) 37#define LOG(kind,...) GNUNET_log_from (kind, "util-strings", __VA_ARGS__)
39 38
40#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall) 39#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-strings", syscall)
41 40
42 41
43/** 42/**
@@ -90,6 +89,37 @@ GNUNET_STRINGS_buffer_fill (char *buffer, size_t size, unsigned int count, ...)
90 89
91 90
92/** 91/**
92 * Convert a peer path to a human-readable string.
93 *
94 * @param pids array of PIDs to convert to a string
95 * @param num_pids length of the @a pids array
96 * @return string representing the array of @a pids
97 */
98char *
99GNUNET_STRINGS_pp2s (const struct GNUNET_PeerIdentity *pids,
100 unsigned int num_pids)
101{
102 char *buf;
103 size_t off;
104 size_t plen = num_pids * 5 + 1;
105
106 off = 0;
107 buf = GNUNET_malloc (plen);
108 for (unsigned int i = 0;
109 i < num_pids;
110 i++)
111 {
112 off += GNUNET_snprintf (&buf[off],
113 plen - off,
114 "%s%s",
115 GNUNET_i2s (&pids[i]),
116 (i == num_pids -1) ? "" : "-");
117 }
118 return buf;
119}
120
121
122/**
93 * Given a buffer of a given size, find "count" 123 * Given a buffer of a given size, find "count"
94 * 0-terminated strings in the buffer and assign 124 * 0-terminated strings in the buffer and assign
95 * the count (varargs) of type "const char**" to the 125 * the count (varargs) of type "const char**" to the
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_container_dll.c b/src/util/test_container_dll.c
new file mode 100644
index 000000000..4d2830807
--- /dev/null
+++ b/src/util/test_container_dll.c
@@ -0,0 +1,112 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 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 * @author Christian Grothoff
23 * @file util/test_container_dll.c
24 * @brief Test of DLL operations
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29
30/**
31 * Element in the DLL.
32 */
33struct Element
34{
35 /**
36 * Required pointer to previous element.
37 */
38 struct Element *prev;
39
40 /**
41 * Required pointer to next element.
42 */
43 struct Element *next;
44
45 /**
46 * Used to sort.
47 */
48 unsigned int value;
49};
50
51
52/**
53 * Compare two elements.
54 *
55 * @param cls closure, NULL
56 * @param e1 an element of to sort
57 * @param e2 another element to sort
58 * @return #GNUNET_YES if @e1 < @e2, otherwise #GNUNET_NO
59 */
60static int
61cmp_elem (void *cls,
62 struct Element *e1,
63 struct Element *e2)
64{
65 if (e1->value == e2->value)
66 return 0;
67 return (e1->value < e2->value) ? 1 : -1;
68}
69
70
71int
72main (int argc, char **argv)
73{
74 unsigned int values[] = {
75 4, 5, 8, 6, 9, 3, 7, 2, 1, 0
76 };
77 struct Element *head = NULL;
78 struct Element *tail = NULL;
79 struct Element *e;
80 unsigned int want;
81
82 GNUNET_log_setup ("test-container-dll",
83 "WARNING",
84 NULL);
85 for (unsigned int off=0;
86 0 != values[off];
87 off++)
88 {
89 e = GNUNET_new (struct Element);
90 e->value = values[off];
91 GNUNET_CONTAINER_DLL_insert_sorted (struct Element,
92 cmp_elem,
93 NULL,
94 head,
95 tail,
96 e);
97 }
98
99 want = 1;
100 while (NULL != (e = head))
101 {
102 GNUNET_assert (e->value == want);
103 GNUNET_CONTAINER_DLL_remove (head,
104 tail,
105 e);
106 GNUNET_free (e);
107 want++;
108 }
109 return 0;
110}
111
112/* end of test_container_heap.c */
diff --git a/src/util/test_container_meta_data.c b/src/util/test_container_meta_data.c
index d84935a1e..cd23674a3 100644
--- a/src/util/test_container_meta_data.c
+++ b/src/util/test_container_meta_data.c
@@ -27,10 +27,9 @@
27#include "platform.h" 27#include "platform.h"
28#include "gnunet_util_lib.h" 28#include "gnunet_util_lib.h"
29 29
30#if HAVE_EXTRACTOR_H
31
32#define ABORT(m) { fprintf(stderr, "Error at %s:%d\n", __FILE__, __LINE__); if (m != NULL) GNUNET_CONTAINER_meta_data_destroy(m); return 1; } 30#define ABORT(m) { fprintf(stderr, "Error at %s:%d\n", __FILE__, __LINE__); if (m != NULL) GNUNET_CONTAINER_meta_data_destroy(m); return 1; }
33 31
32
34static int 33static int
35testMeta (int i) 34testMeta (int i)
36{ 35{
@@ -106,10 +105,15 @@ testMeta (int i)
106 ABORT (m); 105 ABORT (m);
107 for (j = 0; j < i; j++) 106 for (j = 0; j < i; j++)
108 { 107 {
109 GNUNET_snprintf (val, sizeof (val), "%s.%d", 108 GNUNET_snprintf (val,
110 "A teststring that should compress well.", j); 109 sizeof (val),
110 "%s.%d",
111 "A teststring that should compress well.",
112 j);
111 if (GNUNET_OK != 113 if (GNUNET_OK !=
112 GNUNET_CONTAINER_meta_data_delete (m, EXTRACTOR_METATYPE_UNKNOWN, val, 114 GNUNET_CONTAINER_meta_data_delete (m,
115 EXTRACTOR_METATYPE_UNKNOWN,
116 val,
113 strlen (val) + 1)) 117 strlen (val) + 1))
114 { 118 {
115 ABORT (m); 119 ABORT (m);
@@ -121,7 +125,8 @@ testMeta (int i)
121 return 0; 125 return 0;
122} 126}
123 127
124int 128
129static int
125testMetaMore (int i) 130testMetaMore (int i)
126{ 131{
127 struct GNUNET_CONTAINER_MetaData *meta; 132 struct GNUNET_CONTAINER_MetaData *meta;
@@ -135,7 +140,7 @@ testMetaMore (int i)
135 { 140 {
136 GNUNET_snprintf (txt, 128, "%u -- %u\n", i, q); 141 GNUNET_snprintf (txt, 128, "%u -- %u\n", i, q);
137 GNUNET_CONTAINER_meta_data_insert (meta, "<test>", 142 GNUNET_CONTAINER_meta_data_insert (meta, "<test>",
138 q % EXTRACTOR_metatype_get_max (), 143 q % 42 /* EXTRACTOR_metatype_get_max () */,
139 EXTRACTOR_METAFORMAT_UTF8, "text/plain", 144 EXTRACTOR_METAFORMAT_UTF8, "text/plain",
140 txt, strlen (txt) + 1); 145 txt, strlen (txt) + 1);
141 } 146 }
@@ -153,6 +158,7 @@ testMetaMore (int i)
153 return 0; 158 return 0;
154} 159}
155 160
161
156static int 162static int
157testMetaLink () 163testMetaLink ()
158{ 164{
@@ -188,7 +194,8 @@ testMetaLink ()
188 return 0; 194 return 0;
189} 195}
190 196
191int 197
198static int
192check () 199check ()
193{ 200{
194 struct GNUNET_CONTAINER_MetaData *meta; 201 struct GNUNET_CONTAINER_MetaData *meta;
@@ -345,16 +352,5 @@ main (int argc, char *argv[])
345 return 0; 352 return 0;
346} 353}
347 354
348#else
349
350int
351main (int argc, char *argv[])
352{
353 fprintf (stderr,
354 "GNU libextractor not found, skipping test.\n");
355 return 0;
356}
357
358#endif
359 355
360/* end of test_container_meta_data.c */ 356/* end of test_container_meta_data.c */
diff --git a/src/util/test_getopt.c b/src/util/test_getopt.c
index 8e578640d..16f2df8d1 100644
--- a/src/util/test_getopt.c
+++ b/src/util/test_getopt.c
@@ -56,7 +56,7 @@ testVerbose ()
56 unsigned int vflags = 0; 56 unsigned int vflags = 0;
57 57
58 const struct GNUNET_GETOPT_CommandLineOption verboseoptionlist[] = { 58 const struct GNUNET_GETOPT_CommandLineOption verboseoptionlist[] = {
59 GNUNET_GETOPT_OPTION_VERBOSE (&vflags), 59 GNUNET_GETOPT_option_verbose (&vflags),
60 GNUNET_GETOPT_OPTION_END 60 GNUNET_GETOPT_OPTION_END
61 }; 61 };
62 62
@@ -83,7 +83,7 @@ testVersion ()
83 NULL 83 NULL
84 }; 84 };
85 const struct GNUNET_GETOPT_CommandLineOption versionoptionlist[] = { 85 const struct GNUNET_GETOPT_CommandLineOption versionoptionlist[] = {
86 GNUNET_GETOPT_OPTION_VERSION (PACKAGE_VERSION " " VCS_VERSION), 86 GNUNET_GETOPT_option_version (PACKAGE_VERSION " " VCS_VERSION),
87 GNUNET_GETOPT_OPTION_END 87 GNUNET_GETOPT_OPTION_END
88 }; 88 };
89 89
@@ -105,7 +105,7 @@ testAbout ()
105 NULL 105 NULL
106 }; 106 };
107 const struct GNUNET_GETOPT_CommandLineOption aboutoptionlist[] = { 107 const struct GNUNET_GETOPT_CommandLineOption aboutoptionlist[] = {
108 GNUNET_GETOPT_OPTION_HELP ("Testing"), 108 GNUNET_GETOPT_option_help ("Testing"),
109 GNUNET_GETOPT_OPTION_END 109 GNUNET_GETOPT_OPTION_END
110 }; 110 };
111 111
@@ -131,18 +131,21 @@ testLogOpts ()
131 char *fn = NULL; 131 char *fn = NULL;
132 132
133 const struct GNUNET_GETOPT_CommandLineOption logoptionlist[] = { 133 const struct GNUNET_GETOPT_CommandLineOption logoptionlist[] = {
134 GNUNET_GETOPT_OPTION_LOGFILE (&fn), 134 GNUNET_GETOPT_option_logfile (&fn),
135 GNUNET_GETOPT_OPTION_LOGLEVEL (&level), 135 GNUNET_GETOPT_option_loglevel (&level),
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_flag ('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_uint ('n',
178 (void *) &lnum}, 181 "--num",
182 "ARG",
183 "helptext",
184 &num),
185 GNUNET_GETOPT_option_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..6d51b1872 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_flag ('n',
68 "name",
69 "description",
70 &setme1),
71 GNUNET_GETOPT_OPTION_END
72 };
73 struct GNUNET_GETOPT_CommandLineOption options2[] = {
74 GNUNET_GETOPT_option_flag ('n',
75 "name",
76 "description",
77 &setme1),
78 GNUNET_GETOPT_option_flag ('N',
79 "number",
80 "description",
81 &setme2),
82 GNUNET_GETOPT_OPTION_END
83 };
84 struct GNUNET_GETOPT_CommandLineOption options3[] = {
85 GNUNET_GETOPT_option_flag ('N',
86 "number",
87 "description",
88 &setme1),
89 GNUNET_GETOPT_option_flag ('n',
90 "name",
91 "description",
92 &setme2),
93 GNUNET_GETOPT_OPTION_END
94 };
95 struct GNUNET_GETOPT_CommandLineOption options4[] = {
96 GNUNET_GETOPT_option_flag ('n',
97 "name",
98 "description",
99 &setme1),
100 GNUNET_GETOPT_option_flag ('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 d240f1a88..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_IN_SIN_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/time.c b/src/util/time.c
index 89b0c2d44..19100ac36 100644
--- a/src/util/time.c
+++ b/src/util/time.c
@@ -27,7 +27,7 @@
27#include "gnunet_crypto_lib.h" 27#include "gnunet_crypto_lib.h"
28#include "gnunet_time_lib.h" 28#include "gnunet_time_lib.h"
29 29
30#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) 30#define LOG(kind,...) GNUNET_log_from (kind, "util-time", __VA_ARGS__)
31 31
32/** 32/**
33 * Variable used to simulate clock skew. Used for testing, never in production. 33 * Variable used to simulate clock skew. Used for testing, never in production.
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/util/win.c b/src/util/win.c
index 7cd7e0f3c..97877b0ca 100644
--- a/src/util/win.c
+++ b/src/util/win.c
@@ -534,10 +534,9 @@ EnumNICs3 (struct EnumNICs3_results **results, int *results_count)
534 for (i = 0; !found && i < interfaces4_len / sizeof (INTERFACE_INFO); i++) 534 for (i = 0; !found && i < interfaces4_len / sizeof (INTERFACE_INFO); i++)
535 { 535 {
536 struct sockaddr_in *m = (struct sockaddr_in *) &r->mask; 536 struct sockaddr_in *m = (struct sockaddr_in *) &r->mask;
537 if (GNUNET_memcpy (&interfaces4[i].iiAddress.Address, 537 GNUNET_memcpy (&interfaces4[i].iiAddress.Address,
538 unicast->Address.lpSockaddr, 538 unicast->Address.lpSockaddr,
539 unicast->Address.iSockaddrLength) != 0) 539 unicast->Address.iSockaddrLength);
540 continue;
541 found = 1; 540 found = 1;
542 GNUNET_memcpy (&r->address, &interfaces4[i].iiAddress.Address, 541 GNUNET_memcpy (&r->address, &interfaces4[i].iiAddress.Address,
543 sizeof (struct sockaddr_in)); 542 sizeof (struct sockaddr_in));
@@ -557,10 +556,9 @@ EnumNICs3 (struct EnumNICs3_results **results, int *results_count)
557 interfaces6 != NULL && !found && i < interfaces6->iAddressCount; 556 interfaces6 != NULL && !found && i < interfaces6->iAddressCount;
558 i++) 557 i++)
559 { 558 {
560 if (GNUNET_memcpy (interfaces6->Address[i].lpSockaddr, 559 GNUNET_memcpy (interfaces6->Address[i].lpSockaddr,
561 unicast->Address.lpSockaddr, 560 unicast->Address.lpSockaddr,
562 unicast->Address.iSockaddrLength) != 0) 561 unicast->Address.iSockaddrLength);
563 continue;
564 found = 1; 562 found = 1;
565 GNUNET_memcpy (&r->address, interfaces6->Address[i].lpSockaddr, 563 GNUNET_memcpy (&r->address, interfaces6->Address[i].lpSockaddr,
566 sizeof (struct sockaddr_in6)); 564 sizeof (struct sockaddr_in6));
diff --git a/src/util/winproc.c b/src/util/winproc.c
index 66c225ce5..318b68a88 100644
--- a/src/util/winproc.c
+++ b/src/util/winproc.c
@@ -69,7 +69,7 @@ TAddAce GNAddAce;
69TAddAccessAllowedAce GNAddAccessAllowedAce; 69TAddAccessAllowedAce GNAddAccessAllowedAce;
70TSetNamedSecurityInfo GNSetNamedSecurityInfo; 70TSetNamedSecurityInfo GNSetNamedSecurityInfo;
71 71
72#define LOG(kind,...) GNUNET_log_from (kind, "winproc", __VA_ARGS__) 72#define LOG(kind,...) GNUNET_log_from (kind, "util-winproc", __VA_ARGS__)
73/** 73/**
74 * Log (panic) messages from PlibC 74 * Log (panic) messages from PlibC
75 */ 75 */
diff --git a/src/vpn/Makefile.am b/src/vpn/Makefile.am
index 5517a45e3..5c16fa349 100644
--- a/src/vpn/Makefile.am
+++ b/src/vpn/Makefile.am
@@ -79,5 +79,3 @@ libgnunetvpn_la_LIBADD = \
79 $(top_builddir)/src/util/libgnunetutil.la $(XLIB) 79 $(top_builddir)/src/util/libgnunetutil.la $(XLIB)
80libgnunetvpn_la_LDFLAGS = \ 80libgnunetvpn_la_LDFLAGS = \
81 $(GN_LIB_LDFLAGS) 81 $(GN_LIB_LDFLAGS)
82
83
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 c66023c85..d9daaa7e2 100644
--- a/src/vpn/gnunet-service-vpn.c
+++ b/src/vpn/gnunet-service-vpn.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 Copyright (C) 2010, 2011, 2012, 2016 Christian Grothoff 3 Copyright (C) 2010, 2011, 2012, 2016, 2017 Christian Grothoff
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
@@ -221,11 +221,6 @@ struct ChannelState
221 struct GNUNET_REGEX_Search *search; 221 struct GNUNET_REGEX_Search *search;
222 222
223 /** 223 /**
224 * Active transmission handle, NULL for none.
225 */
226 struct GNUNET_CADET_TransmitHandle *th;
227
228 /**
229 * Entry for this entry in the channel_heap, NULL as long as this 224 * Entry for this entry in the channel_heap, NULL as long as this
230 * channel state is not fully bound. 225 * channel state is not fully bound.
231 */ 226 */
@@ -535,11 +530,6 @@ free_channel_state (struct ChannelState *ts)
535 530
536 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 531 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
537 "Cleaning up channel state\n"); 532 "Cleaning up channel state\n");
538 if (NULL != ts->th)
539 {
540 GNUNET_CADET_notify_transmit_ready_cancel (ts->th);
541 ts->th = NULL;
542 }
543 if (NULL != (channel = ts->channel)) 533 if (NULL != (channel = ts->channel))
544 { 534 {
545 ts->channel = NULL; 535 ts->channel = NULL;
@@ -585,97 +575,32 @@ free_channel_state (struct ChannelState *ts)
585 575
586 576
587/** 577/**
588 * Send a message from the message queue via cadet.
589 *
590 * @param cls the `struct ChannelState` with the message queue
591 * @param size number of bytes available in @a buf
592 * @param buf where to copy the message
593 * @return number of bytes copied to @a buf
594 */
595static size_t
596send_to_peer_notify_callback (void *cls, size_t size, void *buf)
597{
598 struct ChannelState *ts = cls;
599 struct ChannelMessageQueueEntry *tnq;
600 size_t ret;
601
602 ts->th = NULL;
603 if (NULL == buf)
604 return 0;
605 tnq = ts->tmq_head;
606 GNUNET_assert (NULL != tnq);
607 GNUNET_assert (size >= tnq->len);
608 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
609 "Sending %u bytes via cadet channel\n",
610 (unsigned int) tnq->len);
611 GNUNET_CONTAINER_DLL_remove (ts->tmq_head,
612 ts->tmq_tail,
613 tnq);
614 ts->tmq_length--;
615 GNUNET_memcpy (buf, tnq->msg, tnq->len);
616 ret = tnq->len;
617 GNUNET_free (tnq);
618 if (NULL != (tnq = ts->tmq_head))
619 {
620 if (NULL == ts->th)
621 ts->th = GNUNET_CADET_notify_transmit_ready (ts->channel,
622 GNUNET_NO /* cork */,
623 GNUNET_TIME_UNIT_FOREVER_REL,
624 tnq->len,
625 &send_to_peer_notify_callback,
626 ts);
627 }
628 GNUNET_STATISTICS_update (stats,
629 gettext_noop ("# Bytes given to cadet for transmission"),
630 ret, GNUNET_NO);
631 return ret;
632}
633
634
635/**
636 * Add the given message to the given channel and trigger the 578 * Add the given message to the given channel and trigger the
637 * transmission process. 579 * transmission process.
638 * 580 *
639 * @param tnq message to queue
640 * @param ts channel to queue the message for 581 * @param ts channel to queue the message for
582 * @param env message to queue
641 */ 583 */
642static void 584static void
643send_to_channel (struct ChannelMessageQueueEntry *tnq, 585send_to_channel (struct ChannelState *ts,
644 struct ChannelState *ts) 586 struct GNUNET_MQ_Envelope *env)
645{ 587{
646 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 588 struct GNUNET_MQ_Handle *mq;
647 "Queueing %u bytes for transmission via cadet channel\n", 589
648 (unsigned int) tnq->len);
649 GNUNET_assert (NULL != ts->channel); 590 GNUNET_assert (NULL != ts->channel);
650 GNUNET_CONTAINER_DLL_insert_tail (ts->tmq_head, 591 mq = GNUNET_CADET_get_mq (ts->channel);
651 ts->tmq_tail, 592 GNUNET_MQ_send (mq,
652 tnq); 593 env);
653 ts->tmq_length++; 594 if (GNUNET_MQ_get_length (mq) > MAX_MESSAGE_QUEUE_SIZE)
654 if (ts->tmq_length > MAX_MESSAGE_QUEUE_SIZE)
655 { 595 {
656 struct ChannelMessageQueueEntry *dq; 596 env = GNUNET_MQ_unsent_head (mq);
657 597 GNUNET_assert (NULL != env);
658 dq = ts->tmq_head;
659 GNUNET_assert (dq != tnq);
660 GNUNET_CONTAINER_DLL_remove (ts->tmq_head,
661 ts->tmq_tail,
662 dq);
663 ts->tmq_length--;
664 GNUNET_CADET_notify_transmit_ready_cancel (ts->th);
665 ts->th = NULL;
666 GNUNET_STATISTICS_update (stats, 598 GNUNET_STATISTICS_update (stats,
667 gettext_noop ("# Bytes dropped in cadet queue (overflow)"), 599 gettext_noop ("# Messages dropped in cadet queue (overflow)"),
668 dq->len, 600 1,
669 GNUNET_NO); 601 GNUNET_NO);
670 GNUNET_free (dq); 602 GNUNET_MQ_discard (env);
671 } 603 }
672 if (NULL == ts->th)
673 ts->th = GNUNET_CADET_notify_transmit_ready (ts->channel,
674 GNUNET_NO /* cork */,
675 GNUNET_TIME_UNIT_FOREVER_REL,
676 tnq->len,
677 &send_to_peer_notify_callback,
678 ts);
679} 604}
680 605
681 606
@@ -710,6 +635,767 @@ print_channel_destination (const struct DestinationEntry *de)
710 635
711 636
712/** 637/**
638 * Function called whenever a channel is destroyed. Should clean up
639 * any associated state.
640 *
641 * @param cls our `struct ChannelState`
642 * @param channel connection to the other end (henceforth invalid)
643 */
644static void
645channel_cleaner (void *cls,
646 const struct GNUNET_CADET_Channel *channel)
647{
648 struct ChannelState *ts = cls;
649
650 ts->channel = NULL; /* we must not call GNUNET_CADET_channel_destroy() anymore */
651 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
652 "CADET notified us about death of channel to `%s'\n",
653 print_channel_destination (&ts->destination));
654 free_channel_state (ts);
655}
656
657
658/**
659 * Synthesize a plausible ICMP payload for an ICMP error
660 * response on the given channel.
661 *
662 * @param ts channel information
663 * @param ipp IPv4 header to fill in (ICMP payload)
664 * @param udp "UDP" header to fill in (ICMP payload); might actually
665 * also be the first 8 bytes of the TCP header
666 */
667static void
668make_up_icmpv4_payload (struct ChannelState *ts,
669 struct GNUNET_TUN_IPv4Header *ipp,
670 struct GNUNET_TUN_UdpHeader *udp)
671{
672 GNUNET_TUN_initialize_ipv4_header (ipp,
673 ts->protocol,
674 sizeof (struct GNUNET_TUN_TcpHeader),
675 &ts->source_ip.v4,
676 &ts->destination_ip.v4);
677 udp->source_port = htons (ts->source_port);
678 udp->destination_port = htons (ts->destination_port);
679 udp->len = htons (0);
680 udp->crc = htons (0);
681}
682
683
684/**
685 * Synthesize a plausible ICMP payload for an ICMP error
686 * response on the given channel.
687 *
688 * @param ts channel information
689 * @param ipp IPv6 header to fill in (ICMP payload)
690 * @param udp "UDP" header to fill in (ICMP payload); might actually
691 * also be the first 8 bytes of the TCP header
692 */
693static void
694make_up_icmpv6_payload (struct ChannelState *ts,
695 struct GNUNET_TUN_IPv6Header *ipp,
696 struct GNUNET_TUN_UdpHeader *udp)
697{
698 GNUNET_TUN_initialize_ipv6_header (ipp,
699 ts->protocol,
700 sizeof (struct GNUNET_TUN_TcpHeader),
701 &ts->source_ip.v6,
702 &ts->destination_ip.v6);
703 udp->source_port = htons (ts->source_port);
704 udp->destination_port = htons (ts->destination_port);
705 udp->len = htons (0);
706 udp->crc = htons (0);
707}
708
709
710/**
711 * We got an ICMP packet back from the CADET channel. Check it is OK.
712 *
713 * @param cls our `struct ChannelState *`
714 * @param message the actual message
715 * @return #GNUNET_OK to keep the connection open,
716 * #GNUNET_SYSERR to close it (signal serious error)
717 */
718static int
719check_icmp_back (void *cls,
720 const struct GNUNET_EXIT_IcmpToVPNMessage *i2v)
721{
722 struct ChannelState *ts = cls;
723
724 if (NULL == ts->heap_node)
725 {
726 GNUNET_break_op (0);
727 return GNUNET_SYSERR;
728 }
729 if (AF_UNSPEC == ts->af)
730 {
731 GNUNET_break_op (0);
732 return GNUNET_SYSERR;
733 }
734 return GNUNET_OK;
735}
736
737
738/**
739 * We got an ICMP packet back from the CADET channel. Pass it on to the
740 * local virtual interface via the helper.
741 *
742 * @param cls our `struct ChannelState *`
743 * @param message the actual message
744 */
745static void
746handle_icmp_back (void *cls,
747 const struct GNUNET_EXIT_IcmpToVPNMessage *i2v)
748{
749 struct ChannelState *ts = cls;
750 size_t mlen;
751
752 GNUNET_STATISTICS_update (stats,
753 gettext_noop ("# ICMP packets received from cadet"),
754 1,
755 GNUNET_NO);
756 mlen = ntohs (i2v->header.size) - sizeof (struct GNUNET_EXIT_IcmpToVPNMessage);
757 {
758 char sbuf[INET6_ADDRSTRLEN];
759 char dbuf[INET6_ADDRSTRLEN];
760
761 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
762 "Received ICMP packet from cadet, sending %u bytes from %s -> %s via TUN\n",
763 (unsigned int) mlen,
764 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
765 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)));
766 }
767 switch (ts->af)
768 {
769 case AF_INET:
770 {
771 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
772 + sizeof (struct GNUNET_TUN_IcmpHeader)
773 + sizeof (struct GNUNET_MessageHeader) +
774 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
775 mlen;
776 {
777 /* reserve some extra space in case we have an ICMP type here where
778 we will need to make up the payload ourselves */
779 char buf[size + sizeof (struct GNUNET_TUN_IPv4Header) + 8] GNUNET_ALIGN;
780 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
781 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
782 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
783 struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv4[1];
784 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
785 tun->flags = htons (0);
786 tun->proto = htons (ETH_P_IPV4);
787 GNUNET_TUN_initialize_ipv4_header (ipv4,
788 IPPROTO_ICMP,
789 sizeof (struct GNUNET_TUN_IcmpHeader) + mlen,
790 &ts->destination_ip.v4,
791 &ts->source_ip.v4);
792 *icmp = i2v->icmp_header;
793 GNUNET_memcpy (&icmp[1],
794 &i2v[1],
795 mlen);
796 /* For some ICMP types, we need to adjust (make up) the payload here.
797 Also, depending on the AF used on the other side, we have to
798 do ICMP PT (translate ICMP types) */
799 switch (ntohl (i2v->af))
800 {
801 case AF_INET:
802 switch (icmp->type)
803 {
804 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
805 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
806 break;
807 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
808 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
809 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
810 {
811 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
812 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
813
814 if (mlen != 0)
815 {
816 /* sender did not strip ICMP payload? */
817 GNUNET_break_op (0);
818 return;
819 }
820 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
821 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
822 make_up_icmpv4_payload (ts, ipp, udp);
823 }
824 break;
825 default:
826 GNUNET_break_op (0);
827 GNUNET_STATISTICS_update (stats,
828 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
829 1, GNUNET_NO);
830 return;
831 }
832 /* end AF_INET */
833 break;
834 case AF_INET6:
835 /* ICMP PT 6-to-4 and possibly making up payloads */
836 switch (icmp->type)
837 {
838 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
839 icmp->type = GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE;
840 {
841 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
842 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
843
844 if (mlen != 0)
845 {
846 /* sender did not strip ICMP payload? */
847 GNUNET_break_op (0);
848 return;
849 }
850 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
851 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
852 make_up_icmpv4_payload (ts, ipp, udp);
853 }
854 break;
855 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
856 icmp->type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
857 {
858 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
859 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
860
861 if (mlen != 0)
862 {
863 /* sender did not strip ICMP payload? */
864 GNUNET_break_op (0);
865 return;
866 }
867 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
868 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
869 make_up_icmpv4_payload (ts, ipp, udp);
870 }
871 break;
872 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
873 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
874 GNUNET_STATISTICS_update (stats,
875 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
876 1, GNUNET_NO);
877 return;
878 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
879 icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
880 break;
881 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
882 icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
883 break;
884 default:
885 GNUNET_break_op (0);
886 GNUNET_STATISTICS_update (stats,
887 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
888 1, GNUNET_NO);
889 return;
890 }
891 /* end AF_INET6 */
892 break;
893 default:
894 GNUNET_break_op (0);
895 return;
896 }
897 msg->size = htons (size);
898 GNUNET_TUN_calculate_icmp_checksum (icmp,
899 &i2v[1],
900 mlen);
901 (void) GNUNET_HELPER_send (helper_handle,
902 msg,
903 GNUNET_YES,
904 NULL, NULL);
905 }
906 }
907 break;
908 case AF_INET6:
909 {
910 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
911 + sizeof (struct GNUNET_TUN_IcmpHeader)
912 + sizeof (struct GNUNET_MessageHeader) +
913 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
914 mlen;
915 {
916 char buf[size + sizeof (struct GNUNET_TUN_IPv6Header) + 8] GNUNET_ALIGN;
917 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
918 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
919 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
920 struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv6[1];
921 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
922 tun->flags = htons (0);
923 tun->proto = htons (ETH_P_IPV6);
924 GNUNET_TUN_initialize_ipv6_header (ipv6,
925 IPPROTO_ICMPV6,
926 sizeof (struct GNUNET_TUN_IcmpHeader) + mlen,
927 &ts->destination_ip.v6,
928 &ts->source_ip.v6);
929 *icmp = i2v->icmp_header;
930 GNUNET_memcpy (&icmp[1],
931 &i2v[1],
932 mlen);
933
934 /* For some ICMP types, we need to adjust (make up) the payload here.
935 Also, depending on the AF used on the other side, we have to
936 do ICMP PT (translate ICMP types) */
937 switch (ntohl (i2v->af))
938 {
939 case AF_INET:
940 /* ICMP PT 4-to-6 and possibly making up payloads */
941 switch (icmp->type)
942 {
943 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
944 icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
945 break;
946 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
947 icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
948 break;
949 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
950 icmp->type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
951 {
952 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
953 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
954
955 if (mlen != 0)
956 {
957 /* sender did not strip ICMP payload? */
958 GNUNET_break_op (0);
959 return;
960 }
961 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
962 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
963 make_up_icmpv6_payload (ts, ipp, udp);
964 }
965 break;
966 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
967 icmp->type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
968 {
969 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
970 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
971
972 if (mlen != 0)
973 {
974 /* sender did not strip ICMP payload? */
975 GNUNET_break_op (0);
976 return;
977 }
978 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
979 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
980 make_up_icmpv6_payload (ts, ipp, udp);
981 }
982 break;
983 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
984 GNUNET_STATISTICS_update (stats,
985 gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
986 1, GNUNET_NO);
987 return;
988 default:
989 GNUNET_break_op (0);
990 GNUNET_STATISTICS_update (stats,
991 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
992 1, GNUNET_NO);
993 return;
994 }
995 /* end AF_INET */
996 break;
997 case AF_INET6:
998 switch (icmp->type)
999 {
1000 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1001 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1002 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1003 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1004 {
1005 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1006 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1007
1008 if (mlen != 0)
1009 {
1010 /* sender did not strip ICMP payload? */
1011 GNUNET_break_op (0);
1012 return;
1013 }
1014 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
1015 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1016 make_up_icmpv6_payload (ts, ipp, udp);
1017 }
1018 break;
1019 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1020 break;
1021 default:
1022 GNUNET_break_op (0);
1023 GNUNET_STATISTICS_update (stats,
1024 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1025 1, GNUNET_NO);
1026 return;
1027 }
1028 /* end AF_INET6 */
1029 break;
1030 default:
1031 GNUNET_break_op (0);
1032 return;
1033 }
1034 msg->size = htons (size);
1035 GNUNET_TUN_calculate_icmp_checksum (icmp,
1036 &i2v[1], mlen);
1037 (void) GNUNET_HELPER_send (helper_handle,
1038 msg,
1039 GNUNET_YES,
1040 NULL, NULL);
1041 }
1042 }
1043 break;
1044 default:
1045 GNUNET_assert (0);
1046 }
1047 GNUNET_CONTAINER_heap_update_cost (ts->heap_node,
1048 GNUNET_TIME_absolute_get ().abs_value_us);
1049 GNUNET_CADET_receive_done (ts->channel);
1050}
1051
1052
1053/**
1054 * We got a UDP packet back from the CADET channel. Check that it is OK.
1055 *
1056 * @param cls our `struct ChannelState *`
1057 * @param reply the actual message
1058 * @return #GNUNET_OK to keep the connection open,
1059 * #GNUNET_SYSERR to close it (signal serious error)
1060 */
1061static int
1062check_udp_back (void *cls,
1063 const struct GNUNET_EXIT_UdpReplyMessage *reply)
1064{
1065 struct ChannelState *ts = cls;
1066
1067 if (NULL == ts->heap_node)
1068 {
1069 GNUNET_break_op (0);
1070 return GNUNET_SYSERR;
1071 }
1072 if (AF_UNSPEC == ts->af)
1073 {
1074 GNUNET_break_op (0);
1075 return GNUNET_SYSERR;
1076 }
1077 return GNUNET_OK;
1078}
1079
1080
1081/**
1082 * We got a UDP packet back from the CADET channel. Pass it on to the
1083 * local virtual interface via the helper.
1084 *
1085 * @param cls our `struct ChannelState *`
1086 * @param reply the actual message
1087 */
1088static void
1089handle_udp_back (void *cls,
1090 const struct GNUNET_EXIT_UdpReplyMessage *reply)
1091{
1092 struct ChannelState *ts = cls;
1093 size_t mlen;
1094
1095 GNUNET_STATISTICS_update (stats,
1096 gettext_noop ("# UDP packets received from cadet"),
1097 1,
1098 GNUNET_NO);
1099 mlen = ntohs (reply->header.size) - sizeof (struct GNUNET_EXIT_UdpReplyMessage);
1100 {
1101 char sbuf[INET6_ADDRSTRLEN];
1102 char dbuf[INET6_ADDRSTRLEN];
1103
1104 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1105 "Received UDP reply from cadet, sending %u bytes from [%s]:%u -> [%s]:%u via TUN\n",
1106 (unsigned int) mlen,
1107 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
1108 ts->destination_port,
1109 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
1110 ts->source_port);
1111 }
1112 switch (ts->af)
1113 {
1114 case AF_INET:
1115 {
1116 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
1117 + sizeof (struct GNUNET_TUN_UdpHeader)
1118 + sizeof (struct GNUNET_MessageHeader) +
1119 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
1120 mlen;
1121 {
1122 char buf[size] GNUNET_ALIGN;
1123 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
1124 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
1125 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
1126 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv4[1];
1127 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1128 msg->size = htons (size);
1129 tun->flags = htons (0);
1130 tun->proto = htons (ETH_P_IPV4);
1131 GNUNET_TUN_initialize_ipv4_header (ipv4,
1132 IPPROTO_UDP,
1133 sizeof (struct GNUNET_TUN_UdpHeader) + mlen,
1134 &ts->destination_ip.v4,
1135 &ts->source_ip.v4);
1136 if (0 == ntohs (reply->source_port))
1137 udp->source_port = htons (ts->destination_port);
1138 else
1139 udp->source_port = reply->source_port;
1140 if (0 == ntohs (reply->destination_port))
1141 udp->destination_port = htons (ts->source_port);
1142 else
1143 udp->destination_port = reply->destination_port;
1144 udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader));
1145 GNUNET_TUN_calculate_udp4_checksum (ipv4,
1146 udp,
1147 &reply[1],
1148 mlen);
1149 GNUNET_memcpy (&udp[1],
1150 &reply[1],
1151 mlen);
1152 (void) GNUNET_HELPER_send (helper_handle,
1153 msg,
1154 GNUNET_YES,
1155 NULL, NULL);
1156 }
1157 }
1158 break;
1159 case AF_INET6:
1160 {
1161 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
1162 + sizeof (struct GNUNET_TUN_UdpHeader)
1163 + sizeof (struct GNUNET_MessageHeader) +
1164 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
1165 mlen;
1166 {
1167 char buf[size] GNUNET_ALIGN;
1168 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
1169 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
1170 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
1171 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv6[1];
1172 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1173 msg->size = htons (size);
1174 tun->flags = htons (0);
1175 tun->proto = htons (ETH_P_IPV6);
1176 GNUNET_TUN_initialize_ipv6_header (ipv6,
1177 IPPROTO_UDP,
1178 sizeof (struct GNUNET_TUN_UdpHeader) + mlen,
1179 &ts->destination_ip.v6,
1180 &ts->source_ip.v6);
1181 if (0 == ntohs (reply->source_port))
1182 udp->source_port = htons (ts->destination_port);
1183 else
1184 udp->source_port = reply->source_port;
1185 if (0 == ntohs (reply->destination_port))
1186 udp->destination_port = htons (ts->source_port);
1187 else
1188 udp->destination_port = reply->destination_port;
1189 udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader));
1190 GNUNET_TUN_calculate_udp6_checksum (ipv6,
1191 udp,
1192 &reply[1], mlen);
1193 GNUNET_memcpy (&udp[1],
1194 &reply[1],
1195 mlen);
1196 (void) GNUNET_HELPER_send (helper_handle,
1197 msg,
1198 GNUNET_YES,
1199 NULL, NULL);
1200 }
1201 }
1202 break;
1203 default:
1204 GNUNET_assert (0);
1205 }
1206 GNUNET_CONTAINER_heap_update_cost (ts->heap_node,
1207 GNUNET_TIME_absolute_get ().abs_value_us);
1208 GNUNET_CADET_receive_done (ts->channel);
1209}
1210
1211
1212/**
1213 * We got a TCP packet back from the CADET channel. Check it is OK.
1214 *
1215 * @param cls our `struct ChannelState *`
1216 * @param data the actual message
1217 * @return #GNUNET_OK to keep the connection open,
1218 * #GNUNET_SYSERR to close it (signal serious error)
1219 */
1220static int
1221check_tcp_back (void *cls,
1222 const struct GNUNET_EXIT_TcpDataMessage *data)
1223{
1224 struct ChannelState *ts = cls;
1225
1226 if (NULL == ts->heap_node)
1227 {
1228 GNUNET_break_op (0);
1229 return GNUNET_SYSERR;
1230 }
1231 if (data->tcp_header.off * 4 < sizeof (struct GNUNET_TUN_TcpHeader))
1232 {
1233 GNUNET_break_op (0);
1234 return GNUNET_SYSERR;
1235 }
1236 return GNUNET_OK;
1237}
1238
1239
1240/**
1241 * We got a TCP packet back from the CADET channel. Pass it on to the
1242 * local virtual interface via the helper.
1243 *
1244 * @param cls our `struct ChannelState *`
1245 * @param data the actual message
1246 */
1247static void
1248handle_tcp_back (void *cls,
1249 const struct GNUNET_EXIT_TcpDataMessage *data)
1250{
1251 struct ChannelState *ts = cls;
1252 size_t mlen;
1253
1254 GNUNET_STATISTICS_update (stats,
1255 gettext_noop ("# TCP packets received from cadet"),
1256 1,
1257 GNUNET_NO);
1258 mlen = ntohs (data->header.size) - sizeof (struct GNUNET_EXIT_TcpDataMessage);
1259 {
1260 char sbuf[INET6_ADDRSTRLEN];
1261 char dbuf[INET6_ADDRSTRLEN];
1262
1263 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1264 "Received TCP reply from cadet, sending %u bytes from [%s]:%u -> [%s]:%u via TUN\n",
1265 (unsigned int) mlen,
1266 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
1267 ts->destination_port,
1268 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
1269 ts->source_port);
1270 }
1271 switch (ts->af)
1272 {
1273 case AF_INET:
1274 {
1275 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
1276 + sizeof (struct GNUNET_TUN_TcpHeader)
1277 + sizeof (struct GNUNET_MessageHeader) +
1278 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
1279 mlen;
1280 {
1281 char buf[size] GNUNET_ALIGN;
1282 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
1283 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
1284 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
1285 struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv4[1];
1286 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1287 msg->size = htons (size);
1288 tun->flags = htons (0);
1289 tun->proto = htons (ETH_P_IPV4);
1290 GNUNET_TUN_initialize_ipv4_header (ipv4,
1291 IPPROTO_TCP,
1292 sizeof (struct GNUNET_TUN_TcpHeader) + mlen,
1293 &ts->destination_ip.v4,
1294 &ts->source_ip.v4);
1295 *tcp = data->tcp_header;
1296 tcp->source_port = htons (ts->destination_port);
1297 tcp->destination_port = htons (ts->source_port);
1298 GNUNET_TUN_calculate_tcp4_checksum (ipv4,
1299 tcp,
1300 &data[1],
1301 mlen);
1302 GNUNET_memcpy (&tcp[1],
1303 &data[1],
1304 mlen);
1305 (void) GNUNET_HELPER_send (helper_handle,
1306 msg,
1307 GNUNET_YES,
1308 NULL, NULL);
1309 }
1310 }
1311 break;
1312 case AF_INET6:
1313 {
1314 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
1315 + sizeof (struct GNUNET_TUN_TcpHeader)
1316 + sizeof (struct GNUNET_MessageHeader) +
1317 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
1318 mlen;
1319 {
1320 char buf[size] GNUNET_ALIGN;
1321 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
1322 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
1323 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
1324 struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv6[1];
1325 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1326 msg->size = htons (size);
1327 tun->flags = htons (0);
1328 tun->proto = htons (ETH_P_IPV6);
1329 GNUNET_TUN_initialize_ipv6_header (ipv6,
1330 IPPROTO_TCP,
1331 sizeof (struct GNUNET_TUN_TcpHeader) + mlen,
1332 &ts->destination_ip.v6,
1333 &ts->source_ip.v6);
1334 *tcp = data->tcp_header;
1335 tcp->source_port = htons (ts->destination_port);
1336 tcp->destination_port = htons (ts->source_port);
1337 GNUNET_TUN_calculate_tcp6_checksum (ipv6,
1338 tcp,
1339 &data[1],
1340 mlen);
1341 GNUNET_memcpy (&tcp[1],
1342 &data[1],
1343 mlen);
1344 (void) GNUNET_HELPER_send (helper_handle,
1345 msg,
1346 GNUNET_YES,
1347 NULL, NULL);
1348 }
1349 }
1350 break;
1351 }
1352 GNUNET_CONTAINER_heap_update_cost (ts->heap_node,
1353 GNUNET_TIME_absolute_get ().abs_value_us);
1354 GNUNET_CADET_receive_done (ts->channel);
1355}
1356
1357
1358/**
1359 * Create a channel for @a ts to @a target at @a port
1360 *
1361 * @param ts channel state to create the channel for
1362 * @param target peer to connect to
1363 * @param port destination port
1364 * @return the channel handle
1365 */
1366static struct GNUNET_CADET_Channel *
1367create_channel (struct ChannelState *ts,
1368 const struct GNUNET_PeerIdentity *target,
1369 const struct GNUNET_HashCode *port)
1370{
1371 struct GNUNET_MQ_MessageHandler cadet_handlers[] = {
1372 GNUNET_MQ_hd_var_size (udp_back,
1373 GNUNET_MESSAGE_TYPE_VPN_UDP_REPLY,
1374 struct GNUNET_EXIT_UdpReplyMessage,
1375 ts),
1376 GNUNET_MQ_hd_var_size (tcp_back,
1377 GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_VPN,
1378 struct GNUNET_EXIT_TcpDataMessage,
1379 ts),
1380 GNUNET_MQ_hd_var_size (icmp_back,
1381 GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_VPN,
1382 struct GNUNET_EXIT_IcmpToVPNMessage,
1383 ts),
1384 GNUNET_MQ_handler_end()
1385 };
1386
1387 return GNUNET_CADET_channel_create (cadet_handle,
1388 ts,
1389 target,
1390 port,
1391 GNUNET_CADET_OPTION_DEFAULT,
1392 NULL,
1393 &channel_cleaner,
1394 cadet_handlers);
1395}
1396
1397
1398/**
713 * Regex has found a potential exit peer for us; consider using it. 1399 * Regex has found a potential exit peer for us; consider using it.
714 * 1400 *
715 * @param cls the `struct ChannelState` 1401 * @param cls the `struct ChannelState`
@@ -758,11 +1444,9 @@ handle_regex_result (void *cls,
758 "Creating tunnel to %s for destination %s!\n", 1444 "Creating tunnel to %s for destination %s!\n",
759 GNUNET_i2s (id), 1445 GNUNET_i2s (id),
760 print_channel_destination (&ts->destination)); 1446 print_channel_destination (&ts->destination));
761 ts->channel = GNUNET_CADET_channel_create (cadet_handle, 1447 ts->channel = create_channel (ts,
762 ts, 1448 id,
763 id, 1449 &port);
764 &port,
765 GNUNET_CADET_OPTION_DEFAULT);
766} 1450}
767 1451
768 1452
@@ -795,12 +1479,10 @@ create_channel_to_destination (struct DestinationChannel *dt,
795 GNUNET_TUN_compute_service_cadet_port (&ts->destination.details.service_destination.service_descriptor, 1479 GNUNET_TUN_compute_service_cadet_port (&ts->destination.details.service_destination.service_descriptor,
796 ts->destination_port, 1480 ts->destination_port,
797 &cadet_port); 1481 &cadet_port);
798 ts->channel 1482 ts->channel = create_channel (ts,
799 = GNUNET_CADET_channel_create (cadet_handle, 1483 &dt->destination->details.service_destination.target,
800 ts, 1484 &cadet_port);
801 &dt->destination->details.service_destination.target, 1485
802 &cadet_port,
803 GNUNET_CADET_OPTION_DEFAULT);
804 if (NULL == ts->channel) 1486 if (NULL == ts->channel)
805 { 1487 {
806 GNUNET_break (0); 1488 GNUNET_break (0);
@@ -906,9 +1588,9 @@ route_packet (struct DestinationEntry *destination,
906{ 1588{
907 struct GNUNET_HashCode key; 1589 struct GNUNET_HashCode key;
908 struct ChannelState *ts; 1590 struct ChannelState *ts;
909 struct ChannelMessageQueueEntry *tnq;
910 size_t alen; 1591 size_t alen;
911 size_t mlen; 1592 size_t mlen;
1593 struct GNUNET_MQ_Envelope *env;
912 const struct GNUNET_TUN_UdpHeader *udp; 1594 const struct GNUNET_TUN_UdpHeader *udp;
913 const struct GNUNET_TUN_TcpHeader *tcp; 1595 const struct GNUNET_TUN_TcpHeader *tcp;
914 const struct GNUNET_TUN_IcmpHeader *icmp; 1596 const struct GNUNET_TUN_IcmpHeader *icmp;
@@ -1157,17 +1839,14 @@ route_packet (struct DestinationEntry *destination,
1157 1839
1158 mlen = sizeof (struct GNUNET_EXIT_UdpServiceMessage) + 1840 mlen = sizeof (struct GNUNET_EXIT_UdpServiceMessage) +
1159 payload_length - sizeof (struct GNUNET_TUN_UdpHeader); 1841 payload_length - sizeof (struct GNUNET_TUN_UdpHeader);
1160 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) 1842 if (mlen >= GNUNET_MAX_MESSAGE_SIZE)
1161 { 1843 {
1162 GNUNET_break (0); 1844 GNUNET_break (0);
1163 return; 1845 return;
1164 } 1846 }
1165 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen); 1847 env = GNUNET_MQ_msg_extra (usm,
1166 tnq->len = mlen; 1848 payload_length - sizeof (struct GNUNET_TUN_UdpHeader),
1167 tnq->msg = &tnq[1]; 1849 GNUNET_MESSAGE_TYPE_VPN_UDP_TO_SERVICE);
1168 usm = (struct GNUNET_EXIT_UdpServiceMessage *) &tnq[1];
1169 usm->header.size = htons ((uint16_t) mlen);
1170 usm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_SERVICE);
1171 /* if the source port is below 32000, we assume it has a special 1850 /* if the source port is below 32000, we assume it has a special
1172 meaning; if not, we pick a random port (this is a heuristic) */ 1851 meaning; if not, we pick a random port (this is a heuristic) */
1173 usm->source_port = (ntohs (udp->source_port) < 32000) ? udp->source_port : 0; 1852 usm->source_port = (ntohs (udp->source_port) < 32000) ? udp->source_port : 0;
@@ -1185,17 +1864,14 @@ route_packet (struct DestinationEntry *destination,
1185 1864
1186 mlen = sizeof (struct GNUNET_EXIT_UdpInternetMessage) + 1865 mlen = sizeof (struct GNUNET_EXIT_UdpInternetMessage) +
1187 alen + payload_length - sizeof (struct GNUNET_TUN_UdpHeader); 1866 alen + payload_length - sizeof (struct GNUNET_TUN_UdpHeader);
1188 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) 1867 if (mlen >= GNUNET_MAX_MESSAGE_SIZE)
1189 { 1868 {
1190 GNUNET_break (0); 1869 GNUNET_break (0);
1191 return; 1870 return;
1192 } 1871 }
1193 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen); 1872 env = GNUNET_MQ_msg_extra (uim,
1194 tnq->len = mlen; 1873 payload_length + alen - sizeof (struct GNUNET_TUN_UdpHeader),
1195 tnq->msg = &tnq[1]; 1874 GNUNET_MESSAGE_TYPE_VPN_UDP_TO_INTERNET);
1196 uim = (struct GNUNET_EXIT_UdpInternetMessage *) &tnq[1];
1197 uim->header.size = htons ((uint16_t) mlen);
1198 uim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_INTERNET);
1199 uim->af = htonl (destination->details.exit_destination.af); 1875 uim->af = htonl (destination->details.exit_destination.af);
1200 uim->source_port = (ntohs (udp->source_port) < 32000) ? udp->source_port : 0; 1876 uim->source_port = (ntohs (udp->source_port) < 32000) ? udp->source_port : 0;
1201 uim->destination_port = udp->destination_port; 1877 uim->destination_port = udp->destination_port;
@@ -1215,8 +1891,8 @@ route_packet (struct DestinationEntry *destination,
1215 GNUNET_assert (0); 1891 GNUNET_assert (0);
1216 } 1892 }
1217 GNUNET_memcpy (payload, 1893 GNUNET_memcpy (payload,
1218 &udp[1], 1894 &udp[1],
1219 payload_length - sizeof (struct GNUNET_TUN_UdpHeader)); 1895 payload_length - sizeof (struct GNUNET_TUN_UdpHeader));
1220 } 1896 }
1221 break; 1897 break;
1222 case IPPROTO_TCP: 1898 case IPPROTO_TCP:
@@ -1228,17 +1904,14 @@ route_packet (struct DestinationEntry *destination,
1228 1904
1229 mlen = sizeof (struct GNUNET_EXIT_TcpServiceStartMessage) + 1905 mlen = sizeof (struct GNUNET_EXIT_TcpServiceStartMessage) +
1230 payload_length - sizeof (struct GNUNET_TUN_TcpHeader); 1906 payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1231 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) 1907 if (mlen >= GNUNET_MAX_MESSAGE_SIZE)
1232 { 1908 {
1233 GNUNET_break (0); 1909 GNUNET_break (0);
1234 return; 1910 return;
1235 } 1911 }
1236 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen); 1912 env = GNUNET_MQ_msg_extra (tsm,
1237 tnq->len = mlen; 1913 payload_length - sizeof (struct GNUNET_TUN_TcpHeader),
1238 tnq->msg = &tnq[1]; 1914 GNUNET_MESSAGE_TYPE_VPN_TCP_TO_SERVICE_START);
1239 tsm = (struct GNUNET_EXIT_TcpServiceStartMessage *) &tnq[1];
1240 tsm->header.size = htons ((uint16_t) mlen);
1241 tsm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_SERVICE_START);
1242 tsm->reserved = htonl (0); 1915 tsm->reserved = htonl (0);
1243 tsm->tcp_header = *tcp; 1916 tsm->tcp_header = *tcp;
1244 GNUNET_memcpy (&tsm[1], 1917 GNUNET_memcpy (&tsm[1],
@@ -1254,17 +1927,14 @@ route_packet (struct DestinationEntry *destination,
1254 1927
1255 mlen = sizeof (struct GNUNET_EXIT_TcpInternetStartMessage) + 1928 mlen = sizeof (struct GNUNET_EXIT_TcpInternetStartMessage) +
1256 alen + payload_length - sizeof (struct GNUNET_TUN_TcpHeader); 1929 alen + payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1257 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) 1930 if (mlen >= GNUNET_MAX_MESSAGE_SIZE)
1258 { 1931 {
1259 GNUNET_break (0); 1932 GNUNET_break (0);
1260 return; 1933 return;
1261 } 1934 }
1262 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen); 1935 env = GNUNET_MQ_msg_extra (tim,
1263 tnq->len = mlen; 1936 payload_length + alen - sizeof (struct GNUNET_TUN_TcpHeader),
1264 tnq->msg = &tnq[1]; 1937 GNUNET_MESSAGE_TYPE_VPN_TCP_TO_INTERNET_START);
1265 tim = (struct GNUNET_EXIT_TcpInternetStartMessage *) &tnq[1];
1266 tim->header.size = htons ((uint16_t) mlen);
1267 tim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_INTERNET_START);
1268 tim->af = htonl (destination->details.exit_destination.af); 1938 tim->af = htonl (destination->details.exit_destination.af);
1269 tim->tcp_header = *tcp; 1939 tim->tcp_header = *tcp;
1270 switch (destination->details.exit_destination.af) 1940 switch (destination->details.exit_destination.af)
@@ -1283,8 +1953,8 @@ route_packet (struct DestinationEntry *destination,
1283 GNUNET_assert (0); 1953 GNUNET_assert (0);
1284 } 1954 }
1285 GNUNET_memcpy (payload, 1955 GNUNET_memcpy (payload,
1286 &tcp[1], 1956 &tcp[1],
1287 payload_length - sizeof (struct GNUNET_TUN_TcpHeader)); 1957 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1288 } 1958 }
1289 } 1959 }
1290 else 1960 else
@@ -1293,22 +1963,19 @@ route_packet (struct DestinationEntry *destination,
1293 1963
1294 mlen = sizeof (struct GNUNET_EXIT_TcpDataMessage) + 1964 mlen = sizeof (struct GNUNET_EXIT_TcpDataMessage) +
1295 payload_length - sizeof (struct GNUNET_TUN_TcpHeader); 1965 payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
1296 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) 1966 if (mlen >= GNUNET_MAX_MESSAGE_SIZE)
1297 { 1967 {
1298 GNUNET_break (0); 1968 GNUNET_break (0);
1299 return; 1969 return;
1300 } 1970 }
1301 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen); 1971 env = GNUNET_MQ_msg_extra (tdm,
1302 tnq->len = mlen; 1972 payload_length - sizeof (struct GNUNET_TUN_TcpHeader),
1303 tnq->msg = &tnq[1]; 1973 GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_EXIT);
1304 tdm = (struct GNUNET_EXIT_TcpDataMessage *) &tnq[1];
1305 tdm->header.size = htons ((uint16_t) mlen);
1306 tdm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_EXIT);
1307 tdm->reserved = htonl (0); 1974 tdm->reserved = htonl (0);
1308 tdm->tcp_header = *tcp; 1975 tdm->tcp_header = *tcp;
1309 GNUNET_memcpy (&tdm[1], 1976 GNUNET_memcpy (&tdm[1],
1310 &tcp[1], 1977 &tcp[1],
1311 payload_length - sizeof (struct GNUNET_TUN_TcpHeader)); 1978 payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
1312 } 1979 }
1313 break; 1980 break;
1314 case IPPROTO_ICMP: 1981 case IPPROTO_ICMP:
@@ -1317,19 +1984,6 @@ route_packet (struct DestinationEntry *destination,
1317 { 1984 {
1318 struct GNUNET_EXIT_IcmpServiceMessage *ism; 1985 struct GNUNET_EXIT_IcmpServiceMessage *ism;
1319 1986
1320 mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) +
1321 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1322 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1323 {
1324 GNUNET_break (0);
1325 return;
1326 }
1327 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen);
1328 tnq->msg = &tnq[1];
1329 ism = (struct GNUNET_EXIT_IcmpServiceMessage *) &tnq[1];
1330 ism->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_SERVICE);
1331 ism->af = htonl (af); /* need to tell destination ICMP protocol family! */
1332 ism->icmp_header = *icmp;
1333 /* ICMP protocol translation will be done by the receiver (as we don't know 1987 /* ICMP protocol translation will be done by the receiver (as we don't know
1334 the target AF); however, we still need to possibly discard the payload 1988 the target AF); however, we still need to possibly discard the payload
1335 depending on the ICMP type */ 1989 depending on the ICMP type */
@@ -1384,12 +2038,20 @@ route_packet (struct DestinationEntry *destination,
1384 /* update length calculations, as payload_length may have changed */ 2038 /* update length calculations, as payload_length may have changed */
1385 mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) + 2039 mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) +
1386 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader); 2040 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1387 tnq->len = mlen; 2041 if (mlen >= GNUNET_MAX_MESSAGE_SIZE)
1388 ism->header.size = htons ((uint16_t) mlen); 2042 {
1389 /* finally, copy payload (if there is any left...) */ 2043 GNUNET_break (0);
2044 return;
2045 }
2046
2047 env = GNUNET_MQ_msg_extra (ism,
2048 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader),
2049 GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_SERVICE);
2050 ism->af = htonl (af); /* need to tell destination ICMP protocol family! */
2051 ism->icmp_header = *icmp;
1390 GNUNET_memcpy (&ism[1], 2052 GNUNET_memcpy (&ism[1],
1391 &icmp[1], 2053 &icmp[1],
1392 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader)); 2054 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader));
1393 } 2055 }
1394 else 2056 else
1395 { 2057 {
@@ -1397,19 +2059,9 @@ route_packet (struct DestinationEntry *destination,
1397 struct in_addr *ip4dst; 2059 struct in_addr *ip4dst;
1398 struct in6_addr *ip6dst; 2060 struct in6_addr *ip6dst;
1399 void *payload; 2061 void *payload;
2062 uint8_t new_type;
1400 2063
1401 mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) + 2064 new_type = icmp->type;
1402 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1403 if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1404 {
1405 GNUNET_break (0);
1406 return;
1407 }
1408 tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen);
1409 tnq->msg = &tnq[1];
1410 iim = (struct GNUNET_EXIT_IcmpInternetMessage *) &tnq[1];
1411 iim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_INTERNET);
1412 iim->icmp_header = *icmp;
1413 /* Perform ICMP protocol-translation (depending on destination AF and source AF) 2065 /* Perform ICMP protocol-translation (depending on destination AF and source AF)
1414 and throw away ICMP payload depending on ICMP message type */ 2066 and throw away ICMP payload depending on ICMP message type */
1415 switch (af) 2067 switch (af)
@@ -1419,21 +2071,21 @@ route_packet (struct DestinationEntry *destination,
1419 { 2071 {
1420 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY: 2072 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1421 if (destination->details.exit_destination.af == AF_INET6) 2073 if (destination->details.exit_destination.af == AF_INET6)
1422 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY; 2074 new_type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
1423 break; 2075 break;
1424 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST: 2076 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1425 if (destination->details.exit_destination.af == AF_INET6) 2077 if (destination->details.exit_destination.af == AF_INET6)
1426 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST; 2078 new_type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
1427 break; 2079 break;
1428 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE: 2080 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1429 if (destination->details.exit_destination.af == AF_INET6) 2081 if (destination->details.exit_destination.af == AF_INET6)
1430 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE; 2082 new_type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1431 /* throw away IP-payload, exit will have to make it up anyway */ 2083 /* throw away IP-payload, exit will have to make it up anyway */
1432 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader); 2084 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1433 break; 2085 break;
1434 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED: 2086 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1435 if (destination->details.exit_destination.af == AF_INET6) 2087 if (destination->details.exit_destination.af == AF_INET6)
1436 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED; 2088 new_type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
1437 /* throw away IP-payload, exit will have to make it up anyway */ 2089 /* throw away IP-payload, exit will have to make it up anyway */
1438 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader); 2090 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1439 break; 2091 break;
@@ -1443,7 +2095,6 @@ route_packet (struct DestinationEntry *destination,
1443 GNUNET_STATISTICS_update (stats, 2095 GNUNET_STATISTICS_update (stats,
1444 gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"), 2096 gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
1445 1, GNUNET_NO); 2097 1, GNUNET_NO);
1446 GNUNET_free (tnq);
1447 return; 2098 return;
1448 } 2099 }
1449 /* throw away IP-payload, exit will have to make it up anyway */ 2100 /* throw away IP-payload, exit will have to make it up anyway */
@@ -1453,7 +2104,6 @@ route_packet (struct DestinationEntry *destination,
1453 GNUNET_STATISTICS_update (stats, 2104 GNUNET_STATISTICS_update (stats,
1454 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"), 2105 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1455 1, GNUNET_NO); 2106 1, GNUNET_NO);
1456 GNUNET_free (tnq);
1457 return; 2107 return;
1458 } 2108 }
1459 /* end of AF_INET */ 2109 /* end of AF_INET */
@@ -1462,14 +2112,14 @@ route_packet (struct DestinationEntry *destination,
1462 switch (icmp->type) 2112 switch (icmp->type)
1463 { 2113 {
1464 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE: 2114 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1465 if (destination->details.exit_destination.af == AF_INET6) 2115 if (destination->details.exit_destination.af == AF_INET)
1466 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE; 2116 new_type = GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE;
1467 /* 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 */
1468 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader); 2118 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1469 break; 2119 break;
1470 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED: 2120 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1471 if (destination->details.exit_destination.af == AF_INET) 2121 if (destination->details.exit_destination.af == AF_INET)
1472 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED; 2122 new_type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
1473 /* throw away IP-payload, exit will have to make it up anyway */ 2123 /* throw away IP-payload, exit will have to make it up anyway */
1474 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader); 2124 payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
1475 break; 2125 break;
@@ -1479,7 +2129,6 @@ route_packet (struct DestinationEntry *destination,
1479 GNUNET_STATISTICS_update (stats, 2129 GNUNET_STATISTICS_update (stats,
1480 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"), 2130 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1481 1, GNUNET_NO); 2131 1, GNUNET_NO);
1482 GNUNET_free (tnq);
1483 return; 2132 return;
1484 } 2133 }
1485 /* throw away IP-payload, exit will have to make it up anyway */ 2134 /* throw away IP-payload, exit will have to make it up anyway */
@@ -1491,7 +2140,6 @@ route_packet (struct DestinationEntry *destination,
1491 GNUNET_STATISTICS_update (stats, 2140 GNUNET_STATISTICS_update (stats,
1492 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"), 2141 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1493 1, GNUNET_NO); 2142 1, GNUNET_NO);
1494 GNUNET_free (tnq);
1495 return; 2143 return;
1496 } 2144 }
1497 /* throw away IP-payload, exit will have to make it up anyway */ 2145 /* throw away IP-payload, exit will have to make it up anyway */
@@ -1499,17 +2147,16 @@ route_packet (struct DestinationEntry *destination,
1499 break; 2147 break;
1500 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST: 2148 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1501 if (destination->details.exit_destination.af == AF_INET) 2149 if (destination->details.exit_destination.af == AF_INET)
1502 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST; 2150 new_type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
1503 break; 2151 break;
1504 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY: 2152 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1505 if (destination->details.exit_destination.af == AF_INET) 2153 if (destination->details.exit_destination.af == AF_INET)
1506 iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY; 2154 new_type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
1507 break; 2155 break;
1508 default: 2156 default:
1509 GNUNET_STATISTICS_update (stats, 2157 GNUNET_STATISTICS_update (stats,
1510 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"), 2158 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1511 1, GNUNET_NO); 2159 1, GNUNET_NO);
1512 GNUNET_free (tnq);
1513 return; 2160 return;
1514 } 2161 }
1515 /* end of AF_INET6 */ 2162 /* end of AF_INET6 */
@@ -1517,13 +2164,20 @@ route_packet (struct DestinationEntry *destination,
1517 default: 2164 default:
1518 GNUNET_assert (0); 2165 GNUNET_assert (0);
1519 } 2166 }
2167
1520 /* update length calculations, as payload_length may have changed */ 2168 /* update length calculations, as payload_length may have changed */
1521 mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) + 2169 mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) +
1522 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader); 2170 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
1523 tnq->len = mlen; 2171 if (mlen >= GNUNET_MAX_MESSAGE_SIZE)
1524 iim->header.size = htons ((uint16_t) mlen); 2172 {
1525 2173 GNUNET_break (0);
1526 /* need to tell destination ICMP protocol family! */ 2174 return;
2175 }
2176 env = GNUNET_MQ_msg_extra (iim,
2177 alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader),
2178 GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_INTERNET);
2179 iim->icmp_header = *icmp;
2180 iim->icmp_header.type = new_type;
1527 iim->af = htonl (destination->details.exit_destination.af); 2181 iim->af = htonl (destination->details.exit_destination.af);
1528 switch (destination->details.exit_destination.af) 2182 switch (destination->details.exit_destination.af)
1529 { 2183 {
@@ -1541,8 +2195,8 @@ route_packet (struct DestinationEntry *destination,
1541 GNUNET_assert (0); 2195 GNUNET_assert (0);
1542 } 2196 }
1543 GNUNET_memcpy (payload, 2197 GNUNET_memcpy (payload,
1544 &icmp[1], 2198 &icmp[1],
1545 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader)); 2199 payload_length - sizeof (struct GNUNET_TUN_IcmpHeader));
1546 } 2200 }
1547 break; 2201 break;
1548 default: 2202 default:
@@ -1551,7 +2205,8 @@ route_packet (struct DestinationEntry *destination,
1551 break; 2205 break;
1552 } 2206 }
1553 ts->is_established = GNUNET_YES; 2207 ts->is_established = GNUNET_YES;
1554 send_to_channel (tnq, ts); 2208 send_to_channel (ts,
2209 env);
1555} 2210}
1556 2211
1557 2212
@@ -1562,12 +2217,10 @@ route_packet (struct DestinationEntry *destination,
1562 * and forward the packet. 2217 * and forward the packet.
1563 * 2218 *
1564 * @param cls closure, NULL 2219 * @param cls closure, NULL
1565 * @param client NULL
1566 * @param message message we got from the client (VPN channel interface) 2220 * @param message message we got from the client (VPN channel interface)
1567 */ 2221 */
1568static int 2222static int
1569message_token (void *cls, 2223message_token (void *cls,
1570 void *client,
1571 const struct GNUNET_MessageHeader *message) 2224 const struct GNUNET_MessageHeader *message)
1572{ 2225{
1573 const struct GNUNET_TUN_Layer2PacketHeader *tun; 2226 const struct GNUNET_TUN_Layer2PacketHeader *tun;
@@ -1678,694 +2331,6 @@ message_token (void *cls,
1678 2331
1679 2332
1680/** 2333/**
1681 * Synthesize a plausible ICMP payload for an ICMP error
1682 * response on the given channel.
1683 *
1684 * @param ts channel information
1685 * @param ipp IPv4 header to fill in (ICMP payload)
1686 * @param udp "UDP" header to fill in (ICMP payload); might actually
1687 * also be the first 8 bytes of the TCP header
1688 */
1689static void
1690make_up_icmpv4_payload (struct ChannelState *ts,
1691 struct GNUNET_TUN_IPv4Header *ipp,
1692 struct GNUNET_TUN_UdpHeader *udp)
1693{
1694 GNUNET_TUN_initialize_ipv4_header (ipp,
1695 ts->protocol,
1696 sizeof (struct GNUNET_TUN_TcpHeader),
1697 &ts->source_ip.v4,
1698 &ts->destination_ip.v4);
1699 udp->source_port = htons (ts->source_port);
1700 udp->destination_port = htons (ts->destination_port);
1701 udp->len = htons (0);
1702 udp->crc = htons (0);
1703}
1704
1705
1706/**
1707 * Synthesize a plausible ICMP payload for an ICMP error
1708 * response on the given channel.
1709 *
1710 * @param ts channel information
1711 * @param ipp IPv6 header to fill in (ICMP payload)
1712 * @param udp "UDP" header to fill in (ICMP payload); might actually
1713 * also be the first 8 bytes of the TCP header
1714 */
1715static void
1716make_up_icmpv6_payload (struct ChannelState *ts,
1717 struct GNUNET_TUN_IPv6Header *ipp,
1718 struct GNUNET_TUN_UdpHeader *udp)
1719{
1720 GNUNET_TUN_initialize_ipv6_header (ipp,
1721 ts->protocol,
1722 sizeof (struct GNUNET_TUN_TcpHeader),
1723 &ts->source_ip.v6,
1724 &ts->destination_ip.v6);
1725 udp->source_port = htons (ts->source_port);
1726 udp->destination_port = htons (ts->destination_port);
1727 udp->len = htons (0);
1728 udp->crc = htons (0);
1729}
1730
1731
1732/**
1733 * We got an ICMP packet back from the CADET channel. Pass it on to the
1734 * local virtual interface via the helper.
1735 *
1736 * @param cls closure, NULL
1737 * @param channel connection to the other end
1738 * @param channel_ctx pointer to our 'struct ChannelState *'
1739 * @param message the actual message
1740 * @return #GNUNET_OK to keep the connection open,
1741 * #GNUNET_SYSERR to close it (signal serious error)
1742 */
1743static int
1744receive_icmp_back (void *cls,
1745 struct GNUNET_CADET_Channel *channel,
1746 void **channel_ctx,
1747 const struct GNUNET_MessageHeader *message)
1748{
1749 struct ChannelState *ts = *channel_ctx;
1750 const struct GNUNET_EXIT_IcmpToVPNMessage *i2v;
1751 size_t mlen;
1752
1753 GNUNET_STATISTICS_update (stats,
1754 gettext_noop ("# ICMP packets received from cadet"),
1755 1, GNUNET_NO);
1756 mlen = ntohs (message->size);
1757 if (mlen < sizeof (struct GNUNET_EXIT_IcmpToVPNMessage))
1758 {
1759 GNUNET_break_op (0);
1760 return GNUNET_SYSERR;
1761 }
1762 if (NULL == ts->heap_node)
1763 {
1764 GNUNET_break_op (0);
1765 return GNUNET_SYSERR;
1766 }
1767 if (AF_UNSPEC == ts->af)
1768 {
1769 GNUNET_break_op (0);
1770 return GNUNET_SYSERR;
1771 }
1772 i2v = (const struct GNUNET_EXIT_IcmpToVPNMessage *) message;
1773 mlen -= sizeof (struct GNUNET_EXIT_IcmpToVPNMessage);
1774 {
1775 char sbuf[INET6_ADDRSTRLEN];
1776 char dbuf[INET6_ADDRSTRLEN];
1777
1778 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1779 "Received ICMP packet from cadet, sending %u bytes from %s -> %s via TUN\n",
1780 (unsigned int) mlen,
1781 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
1782 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)));
1783 }
1784 switch (ts->af)
1785 {
1786 case AF_INET:
1787 {
1788 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
1789 + sizeof (struct GNUNET_TUN_IcmpHeader)
1790 + sizeof (struct GNUNET_MessageHeader) +
1791 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
1792 mlen;
1793 {
1794 /* reserve some extra space in case we have an ICMP type here where
1795 we will need to make up the payload ourselves */
1796 char buf[size + sizeof (struct GNUNET_TUN_IPv4Header) + 8] GNUNET_ALIGN;
1797 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
1798 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
1799 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
1800 struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv4[1];
1801 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1802 tun->flags = htons (0);
1803 tun->proto = htons (ETH_P_IPV4);
1804 GNUNET_TUN_initialize_ipv4_header (ipv4,
1805 IPPROTO_ICMP,
1806 sizeof (struct GNUNET_TUN_IcmpHeader) + mlen,
1807 &ts->destination_ip.v4,
1808 &ts->source_ip.v4);
1809 *icmp = i2v->icmp_header;
1810 GNUNET_memcpy (&icmp[1],
1811 &i2v[1],
1812 mlen);
1813 /* For some ICMP types, we need to adjust (make up) the payload here.
1814 Also, depending on the AF used on the other side, we have to
1815 do ICMP PT (translate ICMP types) */
1816 switch (ntohl (i2v->af))
1817 {
1818 case AF_INET:
1819 switch (icmp->type)
1820 {
1821 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1822 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1823 break;
1824 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1825 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
1826 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1827 {
1828 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1829 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1830
1831 if (mlen != 0)
1832 {
1833 /* sender did not strip ICMP payload? */
1834 GNUNET_break_op (0);
1835 return GNUNET_SYSERR;
1836 }
1837 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1838 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1839 make_up_icmpv4_payload (ts, ipp, udp);
1840 }
1841 break;
1842 default:
1843 GNUNET_break_op (0);
1844 GNUNET_STATISTICS_update (stats,
1845 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1846 1, GNUNET_NO);
1847 return GNUNET_SYSERR;
1848 }
1849 /* end AF_INET */
1850 break;
1851 case AF_INET6:
1852 /* ICMP PT 6-to-4 and possibly making up payloads */
1853 switch (icmp->type)
1854 {
1855 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1856 icmp->type = GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE;
1857 {
1858 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1859 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1860
1861 if (mlen != 0)
1862 {
1863 /* sender did not strip ICMP payload? */
1864 GNUNET_break_op (0);
1865 return GNUNET_SYSERR;
1866 }
1867 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1868 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1869 make_up_icmpv4_payload (ts, ipp, udp);
1870 }
1871 break;
1872 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1873 icmp->type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
1874 {
1875 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
1876 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1877
1878 if (mlen != 0)
1879 {
1880 /* sender did not strip ICMP payload? */
1881 GNUNET_break_op (0);
1882 return GNUNET_SYSERR;
1883 }
1884 size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
1885 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1886 make_up_icmpv4_payload (ts, ipp, udp);
1887 }
1888 break;
1889 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1890 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
1891 GNUNET_STATISTICS_update (stats,
1892 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
1893 1, GNUNET_NO);
1894 return GNUNET_OK;
1895 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1896 icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
1897 break;
1898 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
1899 icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
1900 break;
1901 default:
1902 GNUNET_break_op (0);
1903 GNUNET_STATISTICS_update (stats,
1904 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1905 1, GNUNET_NO);
1906 return GNUNET_SYSERR;
1907 }
1908 /* end AF_INET6 */
1909 break;
1910 default:
1911 GNUNET_break_op (0);
1912 return GNUNET_SYSERR;
1913 }
1914 msg->size = htons (size);
1915 GNUNET_TUN_calculate_icmp_checksum (icmp,
1916 &i2v[1],
1917 mlen);
1918 (void) GNUNET_HELPER_send (helper_handle,
1919 msg,
1920 GNUNET_YES,
1921 NULL, NULL);
1922 }
1923 }
1924 break;
1925 case AF_INET6:
1926 {
1927 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
1928 + sizeof (struct GNUNET_TUN_IcmpHeader)
1929 + sizeof (struct GNUNET_MessageHeader) +
1930 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
1931 mlen;
1932 {
1933 char buf[size + sizeof (struct GNUNET_TUN_IPv6Header) + 8] GNUNET_ALIGN;
1934 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
1935 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
1936 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
1937 struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv6[1];
1938 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1939 tun->flags = htons (0);
1940 tun->proto = htons (ETH_P_IPV6);
1941 GNUNET_TUN_initialize_ipv6_header (ipv6,
1942 IPPROTO_ICMPV6,
1943 sizeof (struct GNUNET_TUN_IcmpHeader) + mlen,
1944 &ts->destination_ip.v6,
1945 &ts->source_ip.v6);
1946 *icmp = i2v->icmp_header;
1947 GNUNET_memcpy (&icmp[1],
1948 &i2v[1],
1949 mlen);
1950
1951 /* For some ICMP types, we need to adjust (make up) the payload here.
1952 Also, depending on the AF used on the other side, we have to
1953 do ICMP PT (translate ICMP types) */
1954 switch (ntohl (i2v->af))
1955 {
1956 case AF_INET:
1957 /* ICMP PT 4-to-6 and possibly making up payloads */
1958 switch (icmp->type)
1959 {
1960 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1961 icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
1962 break;
1963 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1964 icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
1965 break;
1966 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
1967 icmp->type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
1968 {
1969 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1970 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1971
1972 if (mlen != 0)
1973 {
1974 /* sender did not strip ICMP payload? */
1975 GNUNET_break_op (0);
1976 return GNUNET_SYSERR;
1977 }
1978 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
1979 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1980 make_up_icmpv6_payload (ts, ipp, udp);
1981 }
1982 break;
1983 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
1984 icmp->type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
1985 {
1986 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1987 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1988
1989 if (mlen != 0)
1990 {
1991 /* sender did not strip ICMP payload? */
1992 GNUNET_break_op (0);
1993 return GNUNET_SYSERR;
1994 }
1995 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
1996 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
1997 make_up_icmpv6_payload (ts, ipp, udp);
1998 }
1999 break;
2000 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
2001 GNUNET_STATISTICS_update (stats,
2002 gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
2003 1, GNUNET_NO);
2004 return GNUNET_OK;
2005 default:
2006 GNUNET_break_op (0);
2007 GNUNET_STATISTICS_update (stats,
2008 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
2009 1, GNUNET_NO);
2010 return GNUNET_SYSERR;
2011 }
2012 /* end AF_INET */
2013 break;
2014 case AF_INET6:
2015 switch (icmp->type)
2016 {
2017 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
2018 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
2019 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
2020 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
2021 {
2022 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
2023 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
2024
2025 if (mlen != 0)
2026 {
2027 /* sender did not strip ICMP payload? */
2028 GNUNET_break_op (0);
2029 return GNUNET_SYSERR;
2030 }
2031 size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
2032 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
2033 make_up_icmpv6_payload (ts, ipp, udp);
2034 }
2035 break;
2036 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
2037 break;
2038 default:
2039 GNUNET_break_op (0);
2040 GNUNET_STATISTICS_update (stats,
2041 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
2042 1, GNUNET_NO);
2043 return GNUNET_SYSERR;
2044 }
2045 /* end AF_INET6 */
2046 break;
2047 default:
2048 GNUNET_break_op (0);
2049 return GNUNET_SYSERR;
2050 }
2051 msg->size = htons (size);
2052 GNUNET_TUN_calculate_icmp_checksum (icmp,
2053 &i2v[1], mlen);
2054 (void) GNUNET_HELPER_send (helper_handle,
2055 msg,
2056 GNUNET_YES,
2057 NULL, NULL);
2058 }
2059 }
2060 break;
2061 default:
2062 GNUNET_assert (0);
2063 }
2064 GNUNET_CONTAINER_heap_update_cost (ts->heap_node,
2065 GNUNET_TIME_absolute_get ().abs_value_us);
2066 GNUNET_CADET_receive_done (channel);
2067 return GNUNET_OK;
2068}
2069
2070
2071/**
2072 * We got a UDP packet back from the CADET channel. Pass it on to the
2073 * local virtual interface via the helper.
2074 *
2075 * @param cls closure, NULL
2076 * @param channel connection to the other end
2077 * @param channel_ctx pointer to our 'struct ChannelState *'
2078 * @param message the actual message
2079 * @return #GNUNET_OK to keep the connection open,
2080 * #GNUNET_SYSERR to close it (signal serious error)
2081 */
2082static int
2083receive_udp_back (void *cls,
2084 struct GNUNET_CADET_Channel *channel,
2085 void **channel_ctx,
2086 const struct GNUNET_MessageHeader *message)
2087{
2088 struct ChannelState *ts = *channel_ctx;
2089 const struct GNUNET_EXIT_UdpReplyMessage *reply;
2090 size_t mlen;
2091
2092 GNUNET_STATISTICS_update (stats,
2093 gettext_noop ("# UDP packets received from cadet"),
2094 1, GNUNET_NO);
2095 mlen = ntohs (message->size);
2096 if (mlen < sizeof (struct GNUNET_EXIT_UdpReplyMessage))
2097 {
2098 GNUNET_break_op (0);
2099 return GNUNET_SYSERR;
2100 }
2101 if (NULL == ts->heap_node)
2102 {
2103 GNUNET_break_op (0);
2104 return GNUNET_SYSERR;
2105 }
2106 if (AF_UNSPEC == ts->af)
2107 {
2108 GNUNET_break_op (0);
2109 return GNUNET_SYSERR;
2110 }
2111 reply = (const struct GNUNET_EXIT_UdpReplyMessage *) message;
2112 mlen -= sizeof (struct GNUNET_EXIT_UdpReplyMessage);
2113 {
2114 char sbuf[INET6_ADDRSTRLEN];
2115 char dbuf[INET6_ADDRSTRLEN];
2116
2117 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2118 "Received UDP reply from cadet, sending %u bytes from [%s]:%u -> [%s]:%u via TUN\n",
2119 (unsigned int) mlen,
2120 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
2121 ts->destination_port,
2122 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
2123 ts->source_port);
2124 }
2125 switch (ts->af)
2126 {
2127 case AF_INET:
2128 {
2129 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
2130 + sizeof (struct GNUNET_TUN_UdpHeader)
2131 + sizeof (struct GNUNET_MessageHeader) +
2132 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2133 mlen;
2134 {
2135 char buf[size] GNUNET_ALIGN;
2136 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2137 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2138 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
2139 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv4[1];
2140 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2141 msg->size = htons (size);
2142 tun->flags = htons (0);
2143 tun->proto = htons (ETH_P_IPV4);
2144 GNUNET_TUN_initialize_ipv4_header (ipv4,
2145 IPPROTO_UDP,
2146 sizeof (struct GNUNET_TUN_UdpHeader) + mlen,
2147 &ts->destination_ip.v4,
2148 &ts->source_ip.v4);
2149 if (0 == ntohs (reply->source_port))
2150 udp->source_port = htons (ts->destination_port);
2151 else
2152 udp->source_port = reply->source_port;
2153 if (0 == ntohs (reply->destination_port))
2154 udp->destination_port = htons (ts->source_port);
2155 else
2156 udp->destination_port = reply->destination_port;
2157 udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader));
2158 GNUNET_TUN_calculate_udp4_checksum (ipv4,
2159 udp,
2160 &reply[1],
2161 mlen);
2162 GNUNET_memcpy (&udp[1],
2163 &reply[1],
2164 mlen);
2165 (void) GNUNET_HELPER_send (helper_handle,
2166 msg,
2167 GNUNET_YES,
2168 NULL, NULL);
2169 }
2170 }
2171 break;
2172 case AF_INET6:
2173 {
2174 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
2175 + sizeof (struct GNUNET_TUN_UdpHeader)
2176 + sizeof (struct GNUNET_MessageHeader) +
2177 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2178 mlen;
2179 {
2180 char buf[size] GNUNET_ALIGN;
2181 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2182 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2183 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
2184 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv6[1];
2185 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2186 msg->size = htons (size);
2187 tun->flags = htons (0);
2188 tun->proto = htons (ETH_P_IPV6);
2189 GNUNET_TUN_initialize_ipv6_header (ipv6,
2190 IPPROTO_UDP,
2191 sizeof (struct GNUNET_TUN_UdpHeader) + mlen,
2192 &ts->destination_ip.v6,
2193 &ts->source_ip.v6);
2194 if (0 == ntohs (reply->source_port))
2195 udp->source_port = htons (ts->destination_port);
2196 else
2197 udp->source_port = reply->source_port;
2198 if (0 == ntohs (reply->destination_port))
2199 udp->destination_port = htons (ts->source_port);
2200 else
2201 udp->destination_port = reply->destination_port;
2202 udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader));
2203 GNUNET_TUN_calculate_udp6_checksum (ipv6,
2204 udp,
2205 &reply[1], mlen);
2206 GNUNET_memcpy (&udp[1],
2207 &reply[1],
2208 mlen);
2209 (void) GNUNET_HELPER_send (helper_handle,
2210 msg,
2211 GNUNET_YES,
2212 NULL, NULL);
2213 }
2214 }
2215 break;
2216 default:
2217 GNUNET_assert (0);
2218 }
2219 GNUNET_CONTAINER_heap_update_cost (ts->heap_node,
2220 GNUNET_TIME_absolute_get ().abs_value_us);
2221 GNUNET_CADET_receive_done (channel);
2222 return GNUNET_OK;
2223}
2224
2225
2226/**
2227 * We got a TCP packet back from the CADET channel. Pass it on to the
2228 * local virtual interface via the helper.
2229 *
2230 * @param cls closure, NULL
2231 * @param channel connection to the other end
2232 * @param channel_ctx pointer to our `struct ChannelState *`
2233 * @param message the actual message
2234 * @return #GNUNET_OK to keep the connection open,
2235 * #GNUNET_SYSERR to close it (signal serious error)
2236 */
2237static int
2238receive_tcp_back (void *cls,
2239 struct GNUNET_CADET_Channel *channel,
2240 void **channel_ctx,
2241 const struct GNUNET_MessageHeader *message)
2242{
2243 struct ChannelState *ts = *channel_ctx;
2244 const struct GNUNET_EXIT_TcpDataMessage *data;
2245 size_t mlen;
2246
2247 GNUNET_STATISTICS_update (stats,
2248 gettext_noop ("# TCP packets received from cadet"),
2249 1, GNUNET_NO);
2250 mlen = ntohs (message->size);
2251 if (mlen < sizeof (struct GNUNET_EXIT_TcpDataMessage))
2252 {
2253 GNUNET_break_op (0);
2254 return GNUNET_SYSERR;
2255 }
2256 if (NULL == ts->heap_node)
2257 {
2258 GNUNET_break_op (0);
2259 return GNUNET_SYSERR;
2260 }
2261 data = (const struct GNUNET_EXIT_TcpDataMessage *) message;
2262 mlen -= sizeof (struct GNUNET_EXIT_TcpDataMessage);
2263 {
2264 char sbuf[INET6_ADDRSTRLEN];
2265 char dbuf[INET6_ADDRSTRLEN];
2266
2267 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2268 "Received TCP reply from cadet, sending %u bytes from [%s]:%u -> [%s]:%u via TUN\n",
2269 (unsigned int) mlen,
2270 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
2271 ts->destination_port,
2272 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
2273 ts->source_port);
2274 }
2275 if (data->tcp_header.off * 4 < sizeof (struct GNUNET_TUN_TcpHeader))
2276 {
2277 GNUNET_break_op (0);
2278 return GNUNET_SYSERR;
2279 }
2280 switch (ts->af)
2281 {
2282 case AF_INET:
2283 {
2284 size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
2285 + sizeof (struct GNUNET_TUN_TcpHeader)
2286 + sizeof (struct GNUNET_MessageHeader) +
2287 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2288 mlen;
2289 {
2290 char buf[size] GNUNET_ALIGN;
2291 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2292 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2293 struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
2294 struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv4[1];
2295 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2296 msg->size = htons (size);
2297 tun->flags = htons (0);
2298 tun->proto = htons (ETH_P_IPV4);
2299 GNUNET_TUN_initialize_ipv4_header (ipv4,
2300 IPPROTO_TCP,
2301 sizeof (struct GNUNET_TUN_TcpHeader) + mlen,
2302 &ts->destination_ip.v4,
2303 &ts->source_ip.v4);
2304 *tcp = data->tcp_header;
2305 tcp->source_port = htons (ts->destination_port);
2306 tcp->destination_port = htons (ts->source_port);
2307 GNUNET_TUN_calculate_tcp4_checksum (ipv4,
2308 tcp,
2309 &data[1],
2310 mlen);
2311 GNUNET_memcpy (&tcp[1],
2312 &data[1],
2313 mlen);
2314 (void) GNUNET_HELPER_send (helper_handle,
2315 msg,
2316 GNUNET_YES,
2317 NULL, NULL);
2318 }
2319 }
2320 break;
2321 case AF_INET6:
2322 {
2323 size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
2324 + sizeof (struct GNUNET_TUN_TcpHeader)
2325 + sizeof (struct GNUNET_MessageHeader) +
2326 sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
2327 mlen;
2328 {
2329 char buf[size] GNUNET_ALIGN;
2330 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
2331 struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
2332 struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
2333 struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv6[1];
2334 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
2335 msg->size = htons (size);
2336 tun->flags = htons (0);
2337 tun->proto = htons (ETH_P_IPV6);
2338 GNUNET_TUN_initialize_ipv6_header (ipv6,
2339 IPPROTO_TCP,
2340 sizeof (struct GNUNET_TUN_TcpHeader) + mlen,
2341 &ts->destination_ip.v6,
2342 &ts->source_ip.v6);
2343 *tcp = data->tcp_header;
2344 tcp->source_port = htons (ts->destination_port);
2345 tcp->destination_port = htons (ts->source_port);
2346 GNUNET_TUN_calculate_tcp6_checksum (ipv6,
2347 tcp,
2348 &data[1],
2349 mlen);
2350 GNUNET_memcpy (&tcp[1],
2351 &data[1],
2352 mlen);
2353 (void) GNUNET_HELPER_send (helper_handle,
2354 msg,
2355 GNUNET_YES,
2356 NULL, NULL);
2357 }
2358 }
2359 break;
2360 }
2361 GNUNET_CONTAINER_heap_update_cost (ts->heap_node,
2362 GNUNET_TIME_absolute_get ().abs_value_us);
2363 GNUNET_CADET_receive_done (channel);
2364 return GNUNET_OK;
2365}
2366
2367
2368/**
2369 * Allocate an IPv4 address from the range of the channel 2334 * Allocate an IPv4 address from the range of the channel
2370 * for a new redirection. 2335 * for a new redirection.
2371 * 2336 *
@@ -2813,29 +2778,6 @@ handle_client_redirect_to_service (void *cls,
2813} 2778}
2814 2779
2815 2780
2816/**
2817 * Function called whenever a channel is destroyed. Should clean up
2818 * any associated state.
2819 *
2820 * @param cls closure (set from #GNUNET_CADET_connect)
2821 * @param channel connection to the other end (henceforth invalid)
2822 * @param channel_ctx place where local state associated
2823 * with the channel is stored (our `struct ChannelState`)
2824 */
2825static void
2826channel_cleaner (void *cls,
2827 const struct GNUNET_CADET_Channel *channel,
2828 void *channel_ctx)
2829{
2830 struct ChannelState *ts = channel_ctx;
2831
2832 ts->channel = NULL; /* we must not call GNUNET_CADET_channel_destroy() anymore */
2833 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2834 "CADET notified us about death of channel to `%s'\n",
2835 print_channel_destination (&ts->destination));
2836 free_channel_state (ts);
2837}
2838
2839 2781
2840/** 2782/**
2841 * Free memory occupied by an entry in the destination map. 2783 * Free memory occupied by an entry in the destination map.
@@ -2984,12 +2926,6 @@ run (void *cls,
2984 const struct GNUNET_CONFIGURATION_Handle *cfg_, 2926 const struct GNUNET_CONFIGURATION_Handle *cfg_,
2985 struct GNUNET_SERVICE_Handle *service) 2927 struct GNUNET_SERVICE_Handle *service)
2986{ 2928{
2987 static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
2988 { &receive_udp_back, GNUNET_MESSAGE_TYPE_VPN_UDP_REPLY, 0},
2989 { &receive_tcp_back, GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_VPN, 0},
2990 { &receive_icmp_back, GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_VPN, 0},
2991 {NULL, 0, 0}
2992 };
2993 char *ifname; 2929 char *ifname;
2994 char *ipv6addr; 2930 char *ipv6addr;
2995 char *ipv6prefix_s; 2931 char *ipv6prefix_s;
@@ -3130,11 +3066,7 @@ run (void *cls,
3130 } 3066 }
3131 vpn_argv[6] = NULL; 3067 vpn_argv[6] = NULL;
3132 3068
3133 cadet_handle 3069 cadet_handle = GNUNET_CADET_connect (cfg_);
3134 = GNUNET_CADET_connect (cfg_,
3135 NULL,
3136 &channel_cleaner,
3137 cadet_handlers);
3138 // FIXME never opens ports??? 3070 // FIXME never opens ports???
3139 helper_handle = GNUNET_HELPER_start (GNUNET_NO, 3071 helper_handle = GNUNET_HELPER_start (GNUNET_NO,
3140 "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..34c545339 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_flag ('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_flag ('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_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 314 "PEERID",
315 GNUNET_GETOPT_OPTION_VERBOSE (&verbosity), 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_flag ('t',
325 "tcp",
326 gettext_noop ("service is offered via TCP"),
327 &tcp),
328
329 GNUNET_GETOPT_option_flag ('u',
330 "udp",
331 gettext_noop ("service is offered via UDP"),
332 &udp),
333
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))