aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Schanzenbach <schanzen@gnunet.org>2023-10-04 22:52:00 +0200
committerMartin Schanzenbach <schanzen@gnunet.org>2023-10-04 22:52:00 +0200
commit5df04510362413a6c215365879058f5c445e1f3c (patch)
tree3c17f355f98529ba36cd4626b723240a7ef429d2
parent9ff663cc02f81cd842fb07e7c29c44a809368423 (diff)
downloadgnunet-5df04510362413a6c215365879058f5c445e1f3c.tar.gz
gnunet-5df04510362413a6c215365879058f5c445e1f3c.zip
Remove most of old transport, ATS and PEERINFO. Disable TESTBED and related tests
-rw-r--r--configure.ac8
-rw-r--r--pkgconfig/Makefile.am4
-rw-r--r--po/POTFILES.in61
-rw-r--r--src/Makefile.am7
-rw-r--r--src/ats-tool/.gitignore1
-rw-r--r--src/ats-tool/Makefile.am19
-rw-r--r--src/ats-tool/gnunet-ats.c992
-rw-r--r--src/ats-tool/meson.build15
-rw-r--r--src/ats/.gitignore6
-rw-r--r--src/ats/Makefile.am102
-rw-r--r--src/ats/ats.conf.in44
-rw-r--r--src/ats/ats.h492
-rw-r--r--src/ats/ats_api_connectivity.c362
-rw-r--r--src/ats/ats_api_performance.c946
-rw-r--r--src/ats/ats_api_scanner.c65
-rw-r--r--src/ats/ats_api_scheduling.c781
-rw-r--r--src/ats/experiments/example.exp104
-rw-r--r--src/ats/experiments/gnunet_ats_sim_default.conf18
-rw-r--r--src/ats/experiments/set_preference.exp95
-rw-r--r--src/ats/gnunet-ats-solver-eval.c3588
-rw-r--r--src/ats/gnunet-ats-solver-eval.h335
-rw-r--r--src/ats/gnunet-service-ats.c538
-rw-r--r--src/ats/gnunet-service-ats.h42
-rw-r--r--src/ats/gnunet-service-ats_addresses.c686
-rw-r--r--src/ats/gnunet-service-ats_addresses.h490
-rw-r--r--src/ats/gnunet-service-ats_connectivity.c222
-rw-r--r--src/ats/gnunet-service-ats_connectivity.h92
-rw-r--r--src/ats/gnunet-service-ats_normalization.c299
-rw-r--r--src/ats/gnunet-service-ats_normalization.h60
-rw-r--r--src/ats/gnunet-service-ats_performance.c282
-rw-r--r--src/ats/gnunet-service-ats_performance.h96
-rw-r--r--src/ats/gnunet-service-ats_plugins.c582
-rw-r--r--src/ats/gnunet-service-ats_plugins.h149
-rw-r--r--src/ats/gnunet-service-ats_preferences.c771
-rw-r--r--src/ats/gnunet-service-ats_preferences.h93
-rw-r--r--src/ats/gnunet-service-ats_reservations.c211
-rw-r--r--src/ats/gnunet-service-ats_reservations.h72
-rw-r--r--src/ats/gnunet-service-ats_scheduling.c195
-rw-r--r--src/ats/gnunet-service-ats_scheduling.h100
-rw-r--r--src/ats/meson.build58
-rw-r--r--src/ats/perf_ats_simplistic_bandwidth.conf27
-rw-r--r--src/ats/perf_ats_simplistic_delay.conf8
-rw-r--r--src/ats/perf_ats_solver.c1510
-rw-r--r--src/ats/perf_ats_solver.conf28
-rw-r--r--src/ats/perf_ats_solver_proportional.conf0
-rw-r--r--src/ats/plugin_ats_proportional.c1243
-rw-r--r--src/ats/test_ats_api.c296
-rw-r--r--src/ats/test_ats_api.conf35
-rw-r--r--src/ats/test_ats_api_delayed.conf36
-rw-r--r--src/ats/test_ats_api_proportional.conf24
-rw-r--r--src/ats/test_ats_lib.c1107
-rw-r--r--src/ats/test_ats_lib.h512
-rw-r--r--src/ats/test_ats_reservation_api.c181
-rw-r--r--src/ats/test_ats_solver_default.conf2
-rw-r--r--src/ats/test_ats_solver_delayed_proportional.conf20
-rw-r--r--src/ats/test_ats_solver_proportional.conf19
-rwxr-xr-xsrc/ats/test_delay18
-rw-r--r--src/cadet/Makefile.am135
-rw-r--r--src/consensus/Makefile.am21
-rw-r--r--src/core/Makefile.am1
-rw-r--r--src/dht/Makefile.am109
-rw-r--r--src/dhtu/Makefile.am1
-rw-r--r--src/dhtu/plugin_dhtu_gnunet.c8
-rw-r--r--src/fs/Makefile.am166
-rw-r--r--src/hostlist/Makefile.am39
-rw-r--r--src/nse/Makefile.am25
-rw-r--r--src/peerinfo-tool/.gitignore2
-rw-r--r--src/peerinfo-tool/Makefile.am64
-rw-r--r--src/peerinfo-tool/gnunet-peerinfo.c864
-rw-r--r--src/peerinfo-tool/gnunet-peerinfo_plugins.c196
-rw-r--r--src/peerinfo-tool/gnunet-peerinfo_plugins.h58
-rw-r--r--src/peerinfo-tool/meson.build31
-rw-r--r--src/peerinfo-tool/plugin_rest_peerinfo.c842
-rwxr-xr-xsrc/peerinfo-tool/test_gnunet_peerinfo.py.in143
-rw-r--r--src/peerinfo-tool/test_gnunet_peerinfo_data.conf13
-rw-r--r--src/peerinfo/.gitignore6
-rw-r--r--src/peerinfo/Makefile.am105
-rw-r--r--src/peerinfo/gnunet-service-peerinfo.c1370
-rw-r--r--src/peerinfo/meson.build41
-rw-r--r--src/peerinfo/peerinfo.conf.in31
-rw-r--r--src/peerinfo/peerinfo.h122
-rw-r--r--src/peerinfo/peerinfo_api.c557
-rw-r--r--src/peerinfo/peerinfo_api_notify.c291
-rw-r--r--src/peerinfo/perf_peerinfo_api.c193
-rw-r--r--src/peerinfo/test_peerinfo_api.c172
-rw-r--r--src/peerinfo/test_peerinfo_api_data.conf15
-rw-r--r--src/peerinfo/test_peerinfo_api_friend_only.c172
-rw-r--r--src/peerinfo/test_peerinfo_api_notify_friend_only.c261
-rw-r--r--src/peerinfo/test_peerinfo_shipped_hellos.c144
-rw-r--r--src/regex/Makefile.am16
-rw-r--r--src/secretsharing/Makefile.am21
-rw-r--r--src/topology/Makefile.am1
-rw-r--r--src/transport/Makefile.am1339
-rw-r--r--src/transport/communicator-unix.conf2
-rw-r--r--src/transport/gnunet-helper-transport-bluetooth.c2286
-rw-r--r--src/transport/gnunet-helper-transport-wlan-dummy.c520
-rw-r--r--src/transport/gnunet-helper-transport-wlan.c2165
-rw-r--r--src/transport/gnunet-service-transport.c2778
-rw-r--r--src/transport/gnunet-service-transport_ats.c906
-rw-r--r--src/transport/gnunet-service-transport_ats.h203
-rw-r--r--src/transport/gnunet-service-transport_hello.c358
-rw-r--r--src/transport/gnunet-service-transport_hello.h102
-rw-r--r--src/transport/gnunet-service-transport_manipulation.c586
-rw-r--r--src/transport/gnunet-service-transport_manipulation.h121
-rw-r--r--src/transport/gnunet-service-transport_neighbours.c3947
-rw-r--r--src/transport/gnunet-service-transport_neighbours.h321
-rw-r--r--src/transport/gnunet-service-transport_plugins.c437
-rw-r--r--src/transport/gnunet-service-transport_plugins.h107
-rw-r--r--src/transport/gnunet-service-transport_validation.c1819
-rw-r--r--src/transport/gnunet-service-transport_validation.h146
-rw-r--r--src/transport/gnunet-transport-wlan-receiver.c114
-rw-r--r--src/transport/gnunet-transport-wlan-sender.c251
-rw-r--r--src/transport/perf_http_peer1.conf37
-rw-r--r--src/transport/perf_http_peer2.conf40
-rw-r--r--src/transport/perf_https_peer1.conf37
-rw-r--r--src/transport/perf_https_peer2.conf40
-rw-r--r--src/transport/perf_tcp_peer1.conf31
-rw-r--r--src/transport/perf_tcp_peer2.conf34
-rw-r--r--src/transport/perf_udp_peer1.conf43
-rw-r--r--src/transport/perf_udp_peer2.conf48
-rw-r--r--src/transport/perf_unix_peer1.conf52
-rw-r--r--src/transport/perf_unix_peer2.conf56
-rw-r--r--src/transport/plugin_transport_http.h579
-rw-r--r--src/transport/plugin_transport_http_client.c2523
-rw-r--r--src/transport/plugin_transport_http_common.c903
-rw-r--r--src/transport/plugin_transport_http_common.h272
-rw-r--r--src/transport/plugin_transport_http_server.c3603
-rw-r--r--src/transport/plugin_transport_smtp.c750
-rw-r--r--src/transport/plugin_transport_tcp.c3967
-rw-r--r--src/transport/plugin_transport_template.c565
-rw-r--r--src/transport/plugin_transport_udp.c3897
-rw-r--r--src/transport/plugin_transport_udp.h355
-rw-r--r--src/transport/plugin_transport_udp_broadcasting.c647
-rw-r--r--src/transport/plugin_transport_unix.c1890
-rw-r--r--src/transport/plugin_transport_wlan.c2405
-rw-r--r--src/transport/plugin_transport_wlan.h276
-rw-r--r--src/transport/tcp_connection_legacy.c1597
-rw-r--r--src/transport/tcp_server_legacy.c1728
-rw-r--r--src/transport/tcp_server_mst_legacy.c307
-rw-r--r--src/transport/tcp_service_legacy.c1646
-rw-r--r--src/transport/test_http_common.c266
-rw-r--r--src/transport/test_plugin_transport.c797
-rw-r--r--src/transport/test_plugin_transport_data.conf47
-rw-r--r--src/transport/test_plugin_transport_data_udp.conf1
-rw-r--r--src/transport/test_quota_compliance.c321
-rw-r--r--src/transport/test_quota_compliance_bluetooth_asymmetric_peer1.conf12
-rw-r--r--src/transport/test_quota_compliance_bluetooth_asymmetric_peer2.conf11
-rw-r--r--src/transport/test_quota_compliance_bluetooth_peer1.conf30
-rw-r--r--src/transport/test_quota_compliance_bluetooth_peer2.conf29
-rw-r--r--src/transport/test_quota_compliance_data.conf24
-rw-r--r--src/transport/test_quota_compliance_http_asymmetric_peer1.conf28
-rw-r--r--src/transport/test_quota_compliance_http_asymmetric_peer2.conf32
-rw-r--r--src/transport/test_quota_compliance_http_peer1.conf28
-rw-r--r--src/transport/test_quota_compliance_http_peer2.conf32
-rw-r--r--src/transport/test_quota_compliance_https_asymmetric_peer1.conf28
-rw-r--r--src/transport/test_quota_compliance_https_asymmetric_peer2.conf31
-rw-r--r--src/transport/test_quota_compliance_https_peer1.conf28
-rw-r--r--src/transport/test_quota_compliance_https_peer2.conf31
-rw-r--r--src/transport/test_quota_compliance_tcp_asymmetric_peer1.conf32
-rw-r--r--src/transport/test_quota_compliance_tcp_asymmetric_peer2.conf29
-rw-r--r--src/transport/test_quota_compliance_tcp_peer1.conf32
-rw-r--r--src/transport/test_quota_compliance_tcp_peer2.conf29
-rw-r--r--src/transport/test_quota_compliance_udp_peer1.conf29
-rw-r--r--src/transport/test_quota_compliance_udp_peer2.conf30
-rw-r--r--src/transport/test_quota_compliance_unix_asymmetric_peer1.conf28
-rw-r--r--src/transport/test_quota_compliance_unix_asymmetric_peer2.conf28
-rw-r--r--src/transport/test_quota_compliance_unix_peer1.conf27
-rw-r--r--src/transport/test_quota_compliance_unix_peer2.conf31
-rw-r--r--src/transport/test_quota_compliance_wlan_asymmetric_peer1.conf29
-rw-r--r--src/transport/test_quota_compliance_wlan_asymmetric_peer2.conf29
-rw-r--r--src/transport/test_quota_compliance_wlan_peer1.conf29
-rw-r--r--src/transport/test_quota_compliance_wlan_peer2.conf29
-rw-r--r--src/transport/test_transport_address_switch_http_peer1.conf26
-rw-r--r--src/transport/test_transport_address_switch_http_peer2.conf26
-rw-r--r--src/transport/test_transport_address_switch_https_peer1.conf44
-rw-r--r--src/transport/test_transport_address_switch_https_peer2.conf44
-rw-r--r--src/transport/test_transport_api_blacklisting.c206
-rw-r--r--src/transport/test_transport_api_blacklisting_tcp_peer1.conf9
-rw-r--r--src/transport/test_transport_api_blacklisting_tcp_peer2.conf9
-rw-r--r--src/transport/test_transport_api_bluetooth_peer1.conf10
-rw-r--r--src/transport/test_transport_api_bluetooth_peer2.conf10
-rw-r--r--src/transport/test_transport_api_disconnect.c134
-rw-r--r--src/transport/test_transport_api_disconnect_tcp_peer1.conf7
-rw-r--r--src/transport/test_transport_api_disconnect_tcp_peer2.conf8
-rw-r--r--src/transport/test_transport_api_http_peer1.conf6
-rw-r--r--src/transport/test_transport_api_http_peer2.conf6
-rw-r--r--src/transport/test_transport_api_http_reverse_peer1.conf11
-rw-r--r--src/transport/test_transport_api_http_reverse_peer2.conf12
-rw-r--r--src/transport/test_transport_api_https_peer1.conf26
-rw-r--r--src/transport/test_transport_api_https_peer2.conf32
-rw-r--r--src/transport/test_transport_api_limited_sockets.c132
-rw-r--r--src/transport/test_transport_api_limited_sockets_tcp_peer1.conf7
-rw-r--r--src/transport/test_transport_api_limited_sockets_tcp_peer2.conf8
-rw-r--r--src/transport/test_transport_api_manipulation_cfg.c186
-rw-r--r--src/transport/test_transport_api_manipulation_cfg_peer1.conf8
-rw-r--r--src/transport/test_transport_api_manipulation_cfg_peer2.conf8
-rw-r--r--src/transport/test_transport_api_manipulation_recv_tcp.c203
-rw-r--r--src/transport/test_transport_api_manipulation_recv_tcp_peer1.conf29
-rw-r--r--src/transport/test_transport_api_manipulation_recv_tcp_peer2.conf29
-rw-r--r--src/transport/test_transport_api_manipulation_send_tcp.c199
-rw-r--r--src/transport/test_transport_api_manipulation_send_tcp_peer1.conf29
-rw-r--r--src/transport/test_transport_api_manipulation_send_tcp_peer2.conf29
-rw-r--r--src/transport/test_transport_api_reliability.c321
-rw-r--r--src/transport/test_transport_api_reliability_bluetooth_peer1.conf33
-rw-r--r--src/transport/test_transport_api_reliability_bluetooth_peer2.conf32
-rw-r--r--src/transport/test_transport_api_reliability_http_peer1.conf33
-rw-r--r--src/transport/test_transport_api_reliability_http_peer2.conf30
-rw-r--r--src/transport/test_transport_api_reliability_http_xhr_peer1.conf34
-rw-r--r--src/transport/test_transport_api_reliability_http_xhr_peer2.conf30
-rw-r--r--src/transport/test_transport_api_reliability_https_peer1.conf27
-rw-r--r--src/transport/test_transport_api_reliability_https_peer2.conf31
-rw-r--r--src/transport/test_transport_api_reliability_https_xhr_peer1.conf28
-rw-r--r--src/transport/test_transport_api_reliability_https_xhr_peer2.conf31
-rw-r--r--src/transport/test_transport_api_reliability_tcp_nat_peer1.conf35
-rw-r--r--src/transport/test_transport_api_reliability_tcp_nat_peer2.conf34
-rw-r--r--src/transport/test_transport_api_reliability_tcp_peer1.conf29
-rw-r--r--src/transport/test_transport_api_reliability_tcp_peer2.conf28
-rw-r--r--src/transport/test_transport_api_reliability_udp_peer1.conf29
-rw-r--r--src/transport/test_transport_api_reliability_udp_peer2.conf29
-rw-r--r--src/transport/test_transport_api_reliability_unix_peer1.conf28
-rw-r--r--src/transport/test_transport_api_reliability_unix_peer2.conf28
-rw-r--r--src/transport/test_transport_api_reliability_wlan_peer1.conf31
-rw-r--r--src/transport/test_transport_api_reliability_wlan_peer2.conf32
-rw-r--r--src/transport/test_transport_api_restart_1peer_peer1.conf9
-rw-r--r--src/transport/test_transport_api_restart_1peer_peer2.conf9
-rw-r--r--src/transport/test_transport_api_restart_2peers_peer1.conf9
-rw-r--r--src/transport/test_transport_api_restart_2peers_peer2.conf9
-rw-r--r--src/transport/test_transport_api_restart_reconnect.c217
-rw-r--r--src/transport/test_transport_api_slow_ats_peer1.conf7
-rw-r--r--src/transport/test_transport_api_slow_ats_peer2.conf9
-rw-r--r--src/transport/test_transport_api_timeout.c164
-rw-r--r--src/transport/test_transport_api_timeout_bluetooth_peer1.conf35
-rw-r--r--src/transport/test_transport_api_timeout_bluetooth_peer2.conf34
-rw-r--r--src/transport/test_transport_api_timeout_http_peer1.conf28
-rw-r--r--src/transport/test_transport_api_timeout_http_peer2.conf31
-rw-r--r--src/transport/test_transport_api_timeout_https_peer1.conf25
-rw-r--r--src/transport/test_transport_api_timeout_https_peer2.conf31
-rw-r--r--src/transport/test_transport_api_timeout_tcp_peer1.conf30
-rw-r--r--src/transport/test_transport_api_timeout_tcp_peer2.conf32
-rw-r--r--src/transport/test_transport_api_timeout_udp_peer1.conf33
-rw-r--r--src/transport/test_transport_api_timeout_udp_peer2.conf31
-rw-r--r--src/transport/test_transport_api_timeout_unix_peer1.conf28
-rw-r--r--src/transport/test_transport_api_timeout_unix_peer2.conf28
-rw-r--r--src/transport/test_transport_api_timeout_wlan_peer1.conf35
-rw-r--r--src/transport/test_transport_api_timeout_wlan_peer2.conf34
-rw-r--r--src/transport/test_transport_api_unix_abstract_peer1.conf31
-rw-r--r--src/transport/test_transport_api_unix_abstract_peer2.conf31
-rw-r--r--src/transport/test_transport_api_unreliability_bluetooth_peer1.conf30
-rw-r--r--src/transport/test_transport_api_unreliability_bluetooth_peer2.conf29
-rw-r--r--src/transport/test_transport_api_unreliability_constant_udp_peer1.conf30
-rw-r--r--src/transport/test_transport_api_unreliability_constant_udp_peer2.conf30
-rw-r--r--src/transport/test_transport_api_unreliability_wlan_peer1.conf29
-rw-r--r--src/transport/test_transport_api_unreliability_wlan_peer2.conf29
-rw-r--r--src/transport/test_transport_api_wlan_peer1.conf35
-rw-r--r--src/transport/test_transport_api_wlan_peer2.conf34
-rw-r--r--src/transport/test_transport_blacklisting.c582
-rw-r--r--src/transport/test_transport_blacklisting_cfg_blp_peer1_full.conf16
-rw-r--r--src/transport/test_transport_blacklisting_cfg_blp_peer1_multiple_plugins.conf13
-rw-r--r--src/transport/test_transport_blacklisting_cfg_blp_peer1_plugin.conf13
-rw-r--r--src/transport/test_transport_blacklisting_cfg_blp_peer2_full.conf12
-rw-r--r--src/transport/test_transport_blacklisting_cfg_blp_peer2_multiple_plugins.conf12
-rw-r--r--src/transport/test_transport_blacklisting_cfg_blp_peer2_plugin.conf12
-rw-r--r--src/transport/test_transport_blacklisting_cfg_peer1.conf29
-rw-r--r--src/transport/test_transport_blacklisting_cfg_peer2.conf28
-rw-r--r--src/transport/test_transport_testing_restart.c163
-rw-r--r--src/transport/transport-testing-filenames.c175
-rw-r--r--src/transport/transport-testing-loggers.c81
-rw-r--r--src/transport/transport-testing-main.c614
-rw-r--r--src/transport/transport-testing-send.c241
-rw-r--r--src/transport/transport-testing.c932
-rw-r--r--src/transport/transport-testing.h914
-rw-r--r--src/transport/transport-testing2.c50
-rw-r--r--src/transport/transport-testing2.h11
-rw-r--r--src/transport/transport_api_address_to_string.c264
-rw-r--r--src/transport/transport_api_blacklist.c197
-rw-r--r--src/transport/transport_api_core.c968
-rw-r--r--src/transport/transport_api_hello_get.c274
-rw-r--r--src/transport/transport_api_manipulation.c249
-rw-r--r--src/transport/transport_api_monitor_peers.c443
-rw-r--r--src/transport/transport_api_monitor_plugins.c463
-rw-r--r--src/transport/transport_api_offer_hello.c137
-rw-r--r--src/util/container_multihashmap32.c1
282 files changed, 239 insertions, 83665 deletions
diff --git a/configure.ac b/configure.ac
index 27fd913eb..04a366f31 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1228,9 +1228,6 @@ po/Makefile.in
1228src/Makefile 1228src/Makefile
1229src/arm/Makefile 1229src/arm/Makefile
1230src/arm/arm.conf 1230src/arm/arm.conf
1231src/ats/Makefile
1232src/ats/ats.conf
1233src/ats-tool/Makefile
1234src/auction/Makefile 1231src/auction/Makefile
1235src/block/Makefile 1232src/block/Makefile
1236src/cadet/Makefile 1233src/cadet/Makefile
@@ -1277,9 +1274,6 @@ src/nat-auto/nat-auto.conf
1277src/nse/Makefile 1274src/nse/Makefile
1278src/nse/nse.conf 1275src/nse/nse.conf
1279src/nt/Makefile 1276src/nt/Makefile
1280src/peerinfo/Makefile
1281src/peerinfo/peerinfo.conf
1282src/peerinfo-tool/Makefile
1283src/peerstore/Makefile 1277src/peerstore/Makefile
1284src/peerstore/peerstore.conf 1278src/peerstore/peerstore.conf
1285src/pq/Makefile 1279src/pq/Makefile
@@ -1326,7 +1320,6 @@ src/messenger/Makefile
1326src/messenger/messenger.conf 1320src/messenger/messenger.conf
1327pkgconfig/Makefile 1321pkgconfig/Makefile
1328pkgconfig/gnunetarm.pc 1322pkgconfig/gnunetarm.pc
1329pkgconfig/gnunetats.pc
1330pkgconfig/gnunetblock.pc 1323pkgconfig/gnunetblock.pc
1331pkgconfig/gnunetcadet.pc 1324pkgconfig/gnunetcadet.pc
1332pkgconfig/gnunetconsensus.pc 1325pkgconfig/gnunetconsensus.pc
@@ -1348,7 +1341,6 @@ pkgconfig/gnunetmicrophone.pc
1348pkgconfig/gnunetnamestore.pc 1341pkgconfig/gnunetnamestore.pc
1349pkgconfig/gnunetnat.pc 1342pkgconfig/gnunetnat.pc
1350pkgconfig/gnunetnse.pc 1343pkgconfig/gnunetnse.pc
1351pkgconfig/gnunetpeerinfo.pc
1352pkgconfig/gnunetpq.pc 1344pkgconfig/gnunetpq.pc
1353pkgconfig/gnunetregex.pc 1345pkgconfig/gnunetregex.pc
1354pkgconfig/gnunetrevocation.pc 1346pkgconfig/gnunetrevocation.pc
diff --git a/pkgconfig/Makefile.am b/pkgconfig/Makefile.am
index eeb048fb8..1759ae5fc 100644
--- a/pkgconfig/Makefile.am
+++ b/pkgconfig/Makefile.am
@@ -1,7 +1,6 @@
1# This Makefile.am is in the public domain 1# This Makefile.am is in the public domain
2pcfiles = \ 2pcfiles = \
3 gnunetarm.pc \ 3 gnunetarm.pc \
4 gnunetats.pc \
5 gnunetblock.pc \ 4 gnunetblock.pc \
6 gnunetconsensus.pc \ 5 gnunetconsensus.pc \
7 gnunetconversation.pc \ 6 gnunetconversation.pc \
@@ -23,7 +22,6 @@ pcfiles = \
23 gnunetnamestore.pc \ 22 gnunetnamestore.pc \
24 gnunetnat.pc \ 23 gnunetnat.pc \
25 gnunetnse.pc \ 24 gnunetnse.pc \
26 gnunetpeerinfo.pc \
27 gnunetregex.pc \ 25 gnunetregex.pc \
28 gnunetrevocation.pc \ 26 gnunetrevocation.pc \
29 gnunetrps.pc \ 27 gnunetrps.pc \
@@ -44,7 +42,6 @@ pkgconfig_DATA = $(pcfiles)
44 42
45EXTRA_DIST = \ 43EXTRA_DIST = \
46 gnunetarm.pc.in \ 44 gnunetarm.pc.in \
47 gnunetats.pc.in \
48 gnunetblock.pc.in \ 45 gnunetblock.pc.in \
49 gnunetconsensus.pc.in \ 46 gnunetconsensus.pc.in \
50 gnunetconversation.pc.in \ 47 gnunetconversation.pc.in \
@@ -66,7 +63,6 @@ EXTRA_DIST = \
66 gnunetnamestore.pc.in \ 63 gnunetnamestore.pc.in \
67 gnunetnat.pc.in \ 64 gnunetnat.pc.in \
68 gnunetnse.pc.in \ 65 gnunetnse.pc.in \
69 gnunetpeerinfo.pc.in \
70 gnunetpostgres.pc.in \ 66 gnunetpostgres.pc.in \
71 gnunetregex.pc.in \ 67 gnunetregex.pc.in \
72 gnunetrevocation.pc.in \ 68 gnunetrevocation.pc.in \
diff --git a/po/POTFILES.in b/po/POTFILES.in
index a9fbe6984..e275d112c 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -9,22 +9,6 @@ src/arm/arm_monitor_api.c
9src/arm/gnunet-arm.c 9src/arm/gnunet-arm.c
10src/arm/gnunet-service-arm.c 10src/arm/gnunet-service-arm.c
11src/arm/mockup-service.c 11src/arm/mockup-service.c
12src/ats-tool/gnunet-ats.c
13src/ats/ats_api_connectivity.c
14src/ats/ats_api_performance.c
15src/ats/ats_api_scanner.c
16src/ats/ats_api_scheduling.c
17src/ats/gnunet-ats-solver-eval.c
18src/ats/gnunet-service-ats.c
19src/ats/gnunet-service-ats_addresses.c
20src/ats/gnunet-service-ats_connectivity.c
21src/ats/gnunet-service-ats_normalization.c
22src/ats/gnunet-service-ats_performance.c
23src/ats/gnunet-service-ats_plugins.c
24src/ats/gnunet-service-ats_preferences.c
25src/ats/gnunet-service-ats_reservations.c
26src/ats/gnunet-service-ats_scheduling.c
27src/ats/plugin_ats_proportional.c
28src/auction/gnunet-auction-create.c 12src/auction/gnunet-auction-create.c
29src/auction/gnunet-auction-info.c 13src/auction/gnunet-auction-info.c
30src/auction/gnunet-auction-join.c 14src/auction/gnunet-auction-join.c
@@ -273,12 +257,6 @@ src/nse/gnunet-nse.c
273src/nse/gnunet-service-nse.c 257src/nse/gnunet-service-nse.c
274src/nse/nse_api.c 258src/nse/nse_api.c
275src/nt/nt.c 259src/nt/nt.c
276src/peerinfo-tool/gnunet-peerinfo.c
277src/peerinfo-tool/gnunet-peerinfo_plugins.c
278src/peerinfo-tool/plugin_rest_peerinfo.c
279src/peerinfo/gnunet-service-peerinfo.c
280src/peerinfo/peerinfo_api.c
281src/peerinfo/peerinfo_api_notify.c
282src/peerstore/gnunet-peerstore.c 260src/peerstore/gnunet-peerstore.c
283src/peerstore/gnunet-service-peerstore.c 261src/peerstore/gnunet-service-peerstore.c
284src/peerstore/peerstore_api.c 262src/peerstore/peerstore_api.c
@@ -449,64 +427,25 @@ src/transport/gnunet-communicator-quic.c
449src/transport/gnunet-communicator-tcp.c 427src/transport/gnunet-communicator-tcp.c
450src/transport/gnunet-communicator-udp.c 428src/transport/gnunet-communicator-udp.c
451src/transport/gnunet-communicator-unix.c 429src/transport/gnunet-communicator-unix.c
452src/transport/gnunet-helper-transport-bluetooth.c
453src/transport/gnunet-helper-transport-wlan-dummy.c
454src/transport/gnunet-helper-transport-wlan.c
455src/transport/gnunet-service-tng.c 430src/transport/gnunet-service-tng.c
456src/transport/gnunet-service-transport.c
457src/transport/gnunet-service-transport_ats.c
458src/transport/gnunet-service-transport_hello.c
459src/transport/gnunet-service-transport_manipulation.c
460src/transport/gnunet-service-transport_neighbours.c
461src/transport/gnunet-service-transport_plugins.c
462src/transport/gnunet-service-transport_validation.c
463src/transport/gnunet-transport-profiler.c 431src/transport/gnunet-transport-profiler.c
464src/transport/gnunet-transport-wlan-receiver.c
465src/transport/gnunet-transport-wlan-sender.c
466src/transport/gnunet-transport.c 432src/transport/gnunet-transport.c
467src/transport/plugin_transport_http_client.c
468src/transport/plugin_transport_http_common.c
469src/transport/plugin_transport_http_server.c
470src/transport/plugin_transport_smtp.c
471src/transport/plugin_transport_tcp.c
472src/transport/plugin_transport_template.c
473src/transport/plugin_transport_udp.c
474src/transport/plugin_transport_udp_broadcasting.c
475src/transport/plugin_transport_unix.c
476src/transport/plugin_transport_wlan.c
477src/transport/tcp_connection_legacy.c
478src/transport/tcp_server_legacy.c
479src/transport/tcp_server_mst_legacy.c
480src/transport/tcp_service_legacy.c
481src/transport/transport-testing-communicator.c 433src/transport/transport-testing-communicator.c
482src/transport/transport-testing-filenames.c
483src/transport/transport-testing-filenames2.c 434src/transport/transport-testing-filenames2.c
484src/transport/transport-testing-loggers.c
485src/transport/transport-testing-loggers2.c 435src/transport/transport-testing-loggers2.c
486src/transport/transport-testing-main.c
487src/transport/transport-testing-main2.c 436src/transport/transport-testing-main2.c
488src/transport/transport-testing-send.c
489src/transport/transport-testing-send2.c 437src/transport/transport-testing-send2.c
490src/transport/transport-testing.c
491src/transport/transport-testing2.c 438src/transport/transport-testing2.c
492src/transport/transport_api2_application.c 439src/transport/transport_api2_application.c
493src/transport/transport_api2_communication.c 440src/transport/transport_api2_communication.c
494src/transport/transport_api2_core.c 441src/transport/transport_api2_core.c
495src/transport/transport_api2_monitor.c 442src/transport/transport_api2_monitor.c
496src/transport/transport_api_address_to_string.c
497src/transport/transport_api_blacklist.c
498src/transport/transport_api_cmd_backchannel_check.c 443src/transport/transport_api_cmd_backchannel_check.c
499src/transport/transport_api_cmd_connecting_peers.c 444src/transport/transport_api_cmd_connecting_peers.c
500src/transport/transport_api_cmd_send_simple.c 445src/transport/transport_api_cmd_send_simple.c
501src/transport/transport_api_cmd_send_simple_performance.c 446src/transport/transport_api_cmd_send_simple_performance.c
502src/transport/transport_api_cmd_start_peer.c 447src/transport/transport_api_cmd_start_peer.c
503src/transport/transport_api_cmd_stop_peer.c 448src/transport/transport_api_cmd_stop_peer.c
504src/transport/transport_api_core.c
505src/transport/transport_api_hello_get.c
506src/transport/transport_api_manipulation.c
507src/transport/transport_api_monitor_peers.c
508src/transport/transport_api_monitor_plugins.c
509src/transport/transport_api_offer_hello.c
510src/transport/transport_api_traits.c 449src/transport/transport_api_traits.c
511src/util/bandwidth.c 450src/util/bandwidth.c
512src/util/benchmark.c 451src/util/benchmark.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 8fb984d4b..b0064688a 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,7 +1,7 @@
1# This Makefile.am is in the public domain 1# This Makefile.am is in the public domain
2 2
3TESTING = testing 3TESTING = testing
4TESTBED = testbed-logger testbed 4#TESTBED = testbed-logger testbed
5 5
6if HAVE_EXPERIMENTAL 6if HAVE_EXPERIMENTAL
7 EXP_DIR = \ 7 EXP_DIR = \
@@ -44,21 +44,17 @@ SUBDIRS = \
44 $(JSON_DIR) \ 44 $(JSON_DIR) \
45 $(CURL_DIR) \ 45 $(CURL_DIR) \
46 $(REST_DIR) \ 46 $(REST_DIR) \
47 peerinfo \
48 $(SQLITE_DIR) \ 47 $(SQLITE_DIR) \
49 $(POSTGRES_DIR) \ 48 $(POSTGRES_DIR) \
50 datacache \ 49 datacache \
51 datastore \ 50 datastore \
52 template \ 51 template \
53 peerstore \ 52 peerstore \
54 ats \
55 nat \ 53 nat \
56 nat-auto \ 54 nat-auto \
57 fragmentation \ 55 fragmentation \
58 transport \ 56 transport \
59 ats-tool \
60 core \ 57 core \
61 $(TESTBED) \
62 nse \ 58 nse \
63 dhtu \ 59 dhtu \
64 dht \ 60 dht \
@@ -70,7 +66,6 @@ SUBDIRS = \
70 gnsrecord \ 66 gnsrecord \
71 namecache \ 67 namecache \
72 namestore \ 68 namestore \
73 peerinfo-tool \
74 cadet \ 69 cadet \
75 set \ 70 set \
76 seti \ 71 seti \
diff --git a/src/ats-tool/.gitignore b/src/ats-tool/.gitignore
deleted file mode 100644
index 2de03f0e8..000000000
--- a/src/ats-tool/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
1gnunet-ats
diff --git a/src/ats-tool/Makefile.am b/src/ats-tool/Makefile.am
deleted file mode 100644
index 3bb99aa08..000000000
--- a/src/ats-tool/Makefile.am
+++ /dev/null
@@ -1,19 +0,0 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3
4if USE_COVERAGE
5 AM_CFLAGS = -fprofile-arcs -ftest-coverage
6endif
7
8bin_PROGRAMS = \
9 gnunet-ats
10
11gnunet_ats_SOURCES = \
12 gnunet-ats.c
13gnunet_ats_LDADD = \
14 $(top_builddir)/src/util/libgnunetutil.la \
15 $(top_builddir)/src/ats/libgnunetats.la \
16 $(top_builddir)/src/nt/libgnunetnt.la \
17 $(top_builddir)/src/transport/libgnunettransport.la \
18 $(top_builddir)/src/hello/libgnunethello.la \
19 $(GN_LIBINTL)
diff --git a/src/ats-tool/gnunet-ats.c b/src/ats-tool/gnunet-ats.c
deleted file mode 100644
index 169daa6f1..000000000
--- a/src/ats-tool/gnunet-ats.c
+++ /dev/null
@@ -1,992 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009--2015 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file ats-tool/gnunet-ats.c
23 * @brief ATS command line tool
24 * @author Matthias Wachs
25 * @author Christian Grothoff
26 */
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_ats_service.h"
30#include "gnunet_transport_service.h"
31
32/**
33 * String to respresent unlimited
34 */
35#define UNLIMITED_STRING "unlimited"
36
37
38/**
39 * CLI Opt:
40 */
41static int opt_resolve_addresses_numeric;
42
43/**
44 * CLI Opt: Print verbose ATS information
45 */
46static int opt_verbose;
47
48/**
49 * CLI Option: List only addresses currently used (active)
50 */
51static int opt_list_used;
52
53/**
54 * CLI Option: List all addresses
55 */
56static int opt_list_all;
57
58/**
59 * CLI Option: set preference
60 */
61static int opt_set_pref;
62
63/**
64 * CLI Option: print quotas configured
65 */
66static int opt_print_quotas;
67
68/**
69 * CLI Option: Monitor addresses used
70 */
71static int opt_monitor;
72
73/**
74 * CLI Option: use specific peer
75 */
76static char *opt_pid_str;
77
78/**
79 * CLI Option: preference type to set
80 */
81static char *opt_type_str;
82
83/**
84 * CLI Option: preference value to set
85 */
86static unsigned int opt_pref_value;
87
88/**
89 * Final status code.
90 */
91static int ret;
92
93/**
94 * Number of results returned from service
95 */
96static int stat_results;
97
98/**
99 * State: all pending receive operations done?
100 */
101static int stat_receive_done;
102
103/**
104 * State: number of pending operations
105 */
106static int stat_pending;
107
108/**
109 * Which peer should we connect to?
110 */
111static char *cpid_str;
112
113/**
114 * ATS performance handle used
115 */
116static struct GNUNET_ATS_PerformanceHandle *ph;
117
118/**
119 * Our connectivity handle.
120 */
121static struct GNUNET_ATS_ConnectivityHandle *ats_ch;
122
123/**
124 * Handle for address suggestion request.
125 */
126static struct GNUNET_ATS_ConnectivitySuggestHandle *ats_sh;
127
128/**
129 * ATS address list handle used
130 */
131static struct GNUNET_ATS_AddressListHandle *alh;
132
133/**
134 * Configuration handle
135 */
136static struct GNUNET_CONFIGURATION_Handle *cfg;
137
138/**
139 * Shutdown task
140 */
141static struct GNUNET_SCHEDULER_Task *shutdown_task;
142
143/**
144 * Hashmap to store addresses
145 */
146static struct GNUNET_CONTAINER_MultiPeerMap *addresses;
147
148
149/**
150 * Structure used to remember all pending address resolutions.
151 * We keep address information in here while we talk to transport
152 * to map the address to a string.
153 */
154struct PendingResolutions
155{
156 /**
157 * Kept in a DLL.
158 */
159 struct PendingResolutions *next;
160
161 /**
162 * Kept in a DLL.
163 */
164 struct PendingResolutions *prev;
165
166 /**
167 * Copy of the address we are resolving.
168 */
169 struct GNUNET_HELLO_Address *address;
170
171 /**
172 * Handle to the transport request to convert the address
173 * to a string.
174 */
175 struct GNUNET_TRANSPORT_AddressToStringContext *tats_ctx;
176
177 /**
178 * Performance data.
179 */
180 struct GNUNET_ATS_Properties properties;
181
182 /**
183 * Amount of outbound bandwidth assigned by ATS.
184 */
185 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out;
186
187 /**
188 * Amount of inbound bandwidth assigned by ATS.
189 */
190 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in;
191
192 /**
193 * Is this an active address?
194 */
195 int active;
196};
197
198
199/**
200 * Information we keep for an address. Used to avoid
201 * printing the same data multiple times.
202 */
203struct ATSAddress
204{
205 /**
206 * Address information.
207 */
208 struct GNUNET_HELLO_Address *address;
209
210 /**
211 * Current outbound bandwidth.
212 */
213 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out;
214
215 /**
216 * Current inbound bandwidth.
217 */
218 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in;
219
220 /**
221 * Is this an active address?
222 */
223 int active;
224};
225
226
227/**
228 * Head of list of pending resolution requests.
229 */
230static struct PendingResolutions *head;
231
232/**
233 * Tail of list of pending resolution requests.
234 */
235static struct PendingResolutions *tail;
236
237
238/**
239 * Free address corresponding to a given peer.
240 *
241 * @param cls NULL
242 * @param key peer identity
243 * @param value the `struct ATSAddress *` to be freed
244 * @return #GNUNET_YES (always)
245 */
246static int
247free_addr_it (void *cls, const struct GNUNET_PeerIdentity *key, void *value)
248{
249 struct ATSAddress *a = value;
250
251 GNUNET_assert (GNUNET_OK ==
252 GNUNET_CONTAINER_multipeermap_remove (addresses, key, value));
253 GNUNET_HELLO_address_free (a->address);
254 GNUNET_free (a);
255 return GNUNET_OK;
256}
257
258
259/**
260 * Task run on shutdown.
261 *
262 * @param cls NULL
263 */
264static void
265end (void *cls)
266{
267 struct PendingResolutions *pr;
268 struct PendingResolutions *next;
269 unsigned int pending;
270
271 if (NULL != alh)
272 {
273 GNUNET_ATS_performance_list_addresses_cancel (alh);
274 alh = NULL;
275 }
276
277 if (NULL != ph)
278 {
279 GNUNET_ATS_performance_done (ph);
280 ph = NULL;
281 }
282
283 pending = 0;
284 next = head;
285 while (NULL != (pr = next))
286 {
287 next = pr->next;
288 GNUNET_CONTAINER_DLL_remove (head, tail, pr);
289 GNUNET_TRANSPORT_address_to_string_cancel (pr->tats_ctx);
290 GNUNET_free (pr->address);
291 GNUNET_free (pr);
292 pending++;
293 }
294 GNUNET_CONTAINER_multipeermap_iterate (addresses, &free_addr_it, NULL);
295 GNUNET_CONTAINER_multipeermap_destroy (addresses);
296 addresses = NULL;
297
298 if (0 < pending)
299 fprintf (stdout, _ ("%u address resolutions had a timeout\n"), pending);
300 if (opt_list_used || opt_list_all)
301 fprintf (stdout,
302 _ ("ATS returned stat_results for %u addresses\n"),
303 stat_results);
304
305 if (NULL != ats_sh)
306 {
307 GNUNET_ATS_connectivity_suggest_cancel (ats_sh);
308 ats_sh = NULL;
309 }
310 if (NULL != ats_ch)
311 {
312 GNUNET_ATS_connectivity_done (ats_ch);
313 ats_ch = NULL;
314 }
315 ret = 0;
316}
317
318
319/**
320 * Function to call with a textual representation of an address. This
321 * function will be called several times with different possible
322 * textual representations, and a last time with @a address being NULL
323 * to signal the end of the iteration. Note that @a address NULL
324 * always is the last call, regardless of the value in @a res.
325 *
326 * @param cls closure, a `struct PendingResolutions *`
327 * @param address NULL on end of iteration,
328 * otherwise 0-terminated printable UTF-8 string,
329 * in particular an empty string if @a res is #GNUNET_NO
330 * @param res result of the address to string conversion:
331 * if #GNUNET_OK: conversion successful
332 * if #GNUNET_NO: address was invalid (or not supported)
333 * if #GNUNET_SYSERR: communication error (IPC error)
334 */
335static void
336transport_addr_to_str_cb (void *cls, const char *address, int res)
337{
338 struct PendingResolutions *pr = cls;
339
340 if (NULL == address)
341 {
342 /* We're done */
343 GNUNET_CONTAINER_DLL_remove (head, tail, pr);
344 GNUNET_free (pr->address);
345 GNUNET_free (pr);
346 stat_pending--;
347
348 if ((GNUNET_YES == stat_receive_done) && (0 == stat_pending))
349 {
350 /* All messages received and no resolutions pending*/
351 if (shutdown_task != NULL)
352 GNUNET_SCHEDULER_cancel (shutdown_task);
353 shutdown_task = GNUNET_SCHEDULER_add_now (&end, NULL);
354 }
355 return;
356 }
357 switch (res)
358 {
359 case GNUNET_SYSERR:
360 fprintf (
361 stderr,
362 "Failed to convert address for peer `%s' plugin `%s' length %u to string (communication error)\n",
363 GNUNET_i2s (&pr->address->peer),
364 pr->address->transport_name,
365 (unsigned int) pr->address->address_length);
366 return;
367
368 case GNUNET_NO:
369 fprintf (
370 stderr,
371 "Failed to convert address for peer `%s' plugin `%s' length %u to string (address invalid or not supported)\n",
372 GNUNET_i2s (&pr->address->peer),
373 pr->address->transport_name,
374 (unsigned int) pr->address->address_length);
375 return;
376
377 case GNUNET_OK:
378 /* continues below */
379 break;
380
381 default:
382 GNUNET_break (0);
383 return;
384 }
385
386 fprintf (
387 stdout,
388 _ (
389 "Peer `%s' plugin `%s', address `%s', `%s' bw out: %u Bytes/s, bw in %u Bytes/s, %s\n"),
390 GNUNET_i2s (&pr->address->peer),
391 pr->address->transport_name,
392 address,
393 GNUNET_NT_to_string (pr->properties.scope),
394 ntohl (pr->bandwidth_out.value__),
395 ntohl (pr->bandwidth_in.value__),
396 pr->active ? _ ("active ") : _ ("inactive "));
397}
398
399
400/**
401 * Closure for #find_address_it().
402 */
403struct AddressFindCtx
404{
405 /**
406 * Address we are looking for.
407 */
408 const struct GNUNET_HELLO_Address *src;
409
410 /**
411 * Where to write the `struct ATSAddress` if we found one that matches.
412 */
413 struct ATSAddress *res;
414};
415
416
417/**
418 * Find address corresponding to a given peer.
419 *
420 * @param cls the `struct AddressFindCtx *`
421 * @param key peer identity
422 * @param value the `struct ATSAddress *` for an existing address
423 * @return #GNUNET_NO if we found a match, #GNUNET_YES if not
424 */
425static int
426find_address_it (void *cls, const struct GNUNET_PeerIdentity *key, void *value)
427{
428 struct AddressFindCtx *actx = cls;
429 struct ATSAddress *exist = value;
430
431 if (0 == GNUNET_HELLO_address_cmp (actx->src, exist->address))
432 {
433 actx->res = exist;
434 return GNUNET_NO;
435 }
436 return GNUNET_YES;
437}
438
439
440/**
441 * Signature of a function that is called with QoS information about an address.
442 *
443 * @param cls closure (NULL)
444 * @param address the address, NULL if ATS service was disconnected
445 * @param active #GNUNET_YES if this address is actively used
446 * to maintain a connection to a peer;
447 * #GNUNET_NO if the address is not actively used;
448 * #GNUNET_SYSERR if this address is no longer available for ATS
449 * @param bandwidth_out assigned outbound bandwidth for the connection
450 * @param bandwidth_in assigned inbound bandwidth for the connection
451 * @param prop performance data for the address (as far as known)
452 */
453static void
454ats_perf_mon_cb (void *cls,
455 const struct GNUNET_HELLO_Address *address,
456 int active,
457 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
458 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
459 const struct GNUNET_ATS_Properties *prop)
460{
461 struct PendingResolutions *pr;
462 struct PendingResolutions *cur;
463 struct PendingResolutions *next;
464
465 if (NULL == address)
466 {
467 /* ATS service temporarily disconnected, remove current state */
468 next = head;
469 for (cur = next; NULL != cur; cur = next)
470 {
471 next = cur->next;
472 GNUNET_CONTAINER_DLL_remove (head, tail, cur);
473 GNUNET_TRANSPORT_address_to_string_cancel (cur->tats_ctx);
474 GNUNET_HELLO_address_free (cur->address);
475 GNUNET_free (cur);
476 }
477 GNUNET_CONTAINER_multipeermap_iterate (addresses, &free_addr_it, NULL);
478 return;
479 }
480 if (GNUNET_SYSERR == active)
481 {
482 /* remove address */
483 struct AddressFindCtx actx;
484
485 actx.src = address;
486 actx.res = NULL;
487 GNUNET_CONTAINER_multipeermap_get_multiple (addresses,
488 &address->peer,
489 &find_address_it,
490 &actx);
491 if (NULL == actx.res)
492 {
493 GNUNET_break (0);
494 return;
495 }
496 GNUNET_break (GNUNET_OK ==
497 GNUNET_CONTAINER_multipeermap_remove (addresses,
498 &address->peer,
499 actx.res));
500 fprintf (stdout,
501 _ ("Removed address of peer `%s' with plugin `%s'\n"),
502 GNUNET_i2s (&address->peer),
503 actx.res->address->transport_name);
504 GNUNET_HELLO_address_free (actx.res);
505 return;
506 }
507
508 if (GNUNET_NO == opt_verbose)
509 {
510 struct AddressFindCtx actx;
511 struct ATSAddress *a;
512
513 actx.src = address;
514 actx.res = NULL;
515 GNUNET_CONTAINER_multipeermap_get_multiple (addresses,
516 &address->peer,
517 &find_address_it,
518 &actx);
519 if ((NULL != actx.res))
520 {
521 if ((bandwidth_in.value__ == actx.res->bandwidth_in.value__) &&
522 (bandwidth_out.value__ == actx.res->bandwidth_out.value__) &&
523 (active == actx.res->active))
524 {
525 return; /* Nothing to do here */
526 }
527 else
528 {
529 actx.res->bandwidth_in = bandwidth_in;
530 actx.res->bandwidth_out = bandwidth_out;
531 }
532 }
533 else
534 {
535 a = GNUNET_new (struct ATSAddress);
536
537 a->address = GNUNET_HELLO_address_copy (address);
538 a->bandwidth_in = bandwidth_in;
539 a->bandwidth_out = bandwidth_out;
540 a->active = active;
541 GNUNET_CONTAINER_multipeermap_put (
542 addresses,
543 &address->peer,
544 a,
545 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
546 }
547 }
548
549 pr = GNUNET_new (struct PendingResolutions);
550 pr->properties = *prop;
551 pr->address = GNUNET_HELLO_address_copy (address);
552 pr->bandwidth_in = bandwidth_in;
553 pr->bandwidth_out = bandwidth_out;
554 pr->active = active;
555 pr->tats_ctx = GNUNET_TRANSPORT_address_to_string (
556 cfg,
557 address,
558 opt_resolve_addresses_numeric,
559 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
560 &transport_addr_to_str_cb,
561 pr);
562 GNUNET_CONTAINER_DLL_insert (head, tail, pr);
563 stat_results++;
564 stat_pending++;
565}
566
567
568/**
569 * Signature of a function that is called with QoS information about an address.
570 *
571 * @param cls closure (NULL)
572 * @param address the address, NULL if ATS service was disconnected
573 * @param active is this address actively used to maintain a connection
574 to a peer
575 * @param bandwidth_out assigned outbound bandwidth for the connection
576 * @param bandwidth_in assigned inbound bandwidth for the connection
577 * @param prop performance data for the address (as far as known)
578 */
579static void
580ats_perf_cb (void *cls,
581 const struct GNUNET_HELLO_Address *address,
582 int active,
583 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
584 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
585 const struct GNUNET_ATS_Properties *prop)
586{
587 struct PendingResolutions *pr;
588
589 if (NULL == address)
590 {
591 /* All messages received */
592 stat_receive_done = GNUNET_YES;
593 alh = NULL;
594 if (0 == stat_pending)
595 {
596 /* All messages received and no resolutions pending*/
597 if (shutdown_task != NULL)
598 GNUNET_SCHEDULER_cancel (shutdown_task);
599 shutdown_task = GNUNET_SCHEDULER_add_now (&end, NULL);
600 }
601 return;
602 }
603
604 pr = GNUNET_new (struct PendingResolutions);
605 pr->properties = *prop;
606 pr->address = GNUNET_HELLO_address_copy (address);
607 pr->bandwidth_in = bandwidth_in;
608 pr->bandwidth_out = bandwidth_out;
609 pr->active = active;
610 pr->tats_ctx = GNUNET_TRANSPORT_address_to_string (
611 cfg,
612 address,
613 opt_resolve_addresses_numeric,
614 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
615 &transport_addr_to_str_cb,
616 pr);
617 GNUNET_CONTAINER_DLL_insert (head, tail, pr);
618 stat_results++;
619 stat_pending++;
620}
621
622
623/**
624 * Print information about the quotas configured for the various
625 * network scopes.
626 *
627 * @param cfg configuration to obtain quota information from
628 * @return total number of ATS network types known
629 */
630static unsigned int
631print_quotas (const struct GNUNET_CONFIGURATION_Handle *cfg)
632{
633 char *entry_in = NULL;
634 char *entry_out = NULL;
635 char *quota_out_str;
636 char *quota_in_str;
637 unsigned long long int quota_out;
638 unsigned long long int quota_in;
639 int c;
640
641 for (c = 0; (c < GNUNET_NT_COUNT); c++)
642 {
643 GNUNET_asprintf (&entry_out, "%s_QUOTA_OUT", GNUNET_NT_to_string (c));
644 GNUNET_asprintf (&entry_in, "%s_QUOTA_IN", GNUNET_NT_to_string (c));
645
646 /* quota out */
647 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg,
648 "ats",
649 entry_out,
650 &quota_out_str))
651 {
652 if ((0 == strcmp (quota_out_str, UNLIMITED_STRING)) ||
653 (GNUNET_SYSERR ==
654 GNUNET_STRINGS_fancy_size_to_bytes (quota_out_str, &quota_out)))
655 quota_out = UINT32_MAX;
656
657 GNUNET_free (quota_out_str);
658 GNUNET_asprintf (&quota_out_str, "%llu", quota_out);
659 }
660 else
661 {
662 fprintf (stderr,
663 "Outbound quota for network `%11s' not configured!\n",
664 GNUNET_NT_to_string (c));
665 GNUNET_asprintf (&quota_out_str, "-");
666 }
667 GNUNET_free (entry_out);
668
669 /* quota in */
670 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg,
671 "ats",
672 entry_in,
673 &quota_in_str))
674 {
675 if ((0 == strcmp (quota_in_str, UNLIMITED_STRING)) ||
676 (GNUNET_SYSERR ==
677 GNUNET_STRINGS_fancy_size_to_bytes (quota_in_str, &quota_in)))
678 quota_in = UINT32_MAX;
679 GNUNET_free (quota_in_str);
680 GNUNET_asprintf (&quota_in_str, "%llu", quota_in);
681 }
682 else
683 {
684 fprintf (stderr,
685 "Inbound quota for network `%11s' not configured!\n",
686 GNUNET_NT_to_string (c));
687 GNUNET_asprintf (&quota_in_str, "-");
688 }
689 GNUNET_free (entry_in);
690
691 fprintf (stdout,
692 _ ("Quota for network `%11s' (in/out): %10s / %10s\n"),
693 GNUNET_NT_to_string (c),
694 quota_in_str,
695 quota_out_str);
696 GNUNET_free (quota_out_str);
697 GNUNET_free (quota_in_str);
698 }
699 return GNUNET_NT_COUNT;
700}
701
702
703/**
704 * Main function that will be run by the scheduler.
705 *
706 * @param cls closure
707 * @param args remaining command-line arguments
708 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
709 * @param my_cfg configuration
710 */
711static void
712run (void *cls,
713 char *const *args,
714 const char *cfgfile,
715 const struct GNUNET_CONFIGURATION_Handle *my_cfg)
716{
717 struct GNUNET_PeerIdentity pid;
718 struct GNUNET_PeerIdentity cpid;
719 unsigned int c;
720 unsigned int type;
721
722 cfg = (struct GNUNET_CONFIGURATION_Handle *) my_cfg;
723 addresses = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO);
724 stat_results = 0;
725
726 c = 0;
727 if (NULL != opt_pid_str)
728 {
729 if (GNUNET_OK !=
730 GNUNET_CRYPTO_eddsa_public_key_from_string (opt_pid_str,
731 strlen (opt_pid_str),
732 &pid.public_key))
733 {
734 fprintf (stderr, _ ("Failed to parse peer identity `%s'\n"), opt_pid_str);
735 return;
736 }
737 }
738 if (NULL != cpid_str)
739 {
740 if (GNUNET_OK !=
741 GNUNET_CRYPTO_eddsa_public_key_from_string (cpid_str,
742 strlen (cpid_str),
743 &cpid.public_key))
744 {
745 fprintf (stderr, _ ("Failed to parse peer identity `%s'\n"), cpid_str);
746 return;
747 }
748 c++;
749 }
750
751 c += opt_list_all + opt_list_used + opt_monitor + opt_set_pref;
752
753 if (1 < c)
754 {
755 fprintf (stderr,
756 _ ("Please select one operation: %s or %s or %s or %s or %s\n"),
757 "--used",
758 "--all",
759 "--monitor",
760 "--preference",
761 "--quotas");
762 return;
763 }
764 if (0 == c)
765 opt_list_used = GNUNET_YES; /* set default */
766 if (opt_print_quotas)
767 {
768 ret = print_quotas (cfg);
769 return;
770 }
771 if (opt_list_all)
772 {
773 ph = GNUNET_ATS_performance_init (cfg, NULL, NULL);
774 if (NULL == ph)
775 {
776 fprintf (stderr, "%s", _ ("Cannot connect to ATS service, exiting...\n"));
777 return;
778 }
779 alh = GNUNET_ATS_performance_list_addresses (ph,
780 (NULL == opt_pid_str) ? NULL
781 : &pid,
782 GNUNET_YES,
783 &ats_perf_cb,
784 NULL);
785 if (NULL == alh)
786 {
787 fprintf (stderr,
788 "%s",
789 _ ("Cannot issue request to ATS service, exiting...\n"));
790 shutdown_task = GNUNET_SCHEDULER_add_now (&end, NULL);
791 return;
792 }
793 shutdown_task = GNUNET_SCHEDULER_add_shutdown (&end, NULL);
794 return;
795 }
796 if (opt_list_used)
797 {
798 ph = GNUNET_ATS_performance_init (cfg, NULL, NULL);
799 if (NULL == ph)
800 fprintf (stderr, "%s", _ ("Cannot connect to ATS service, exiting...\n"));
801
802 alh = GNUNET_ATS_performance_list_addresses (ph,
803 (NULL == opt_pid_str) ? NULL
804 : &pid,
805 GNUNET_NO,
806 &ats_perf_cb,
807 NULL);
808 if (NULL == alh)
809 {
810 fprintf (stderr,
811 "%s",
812 _ ("Cannot issue request to ATS service, exiting...\n"));
813 shutdown_task = GNUNET_SCHEDULER_add_now (&end, NULL);
814 return;
815 }
816 shutdown_task = GNUNET_SCHEDULER_add_shutdown (&end, NULL);
817 return;
818 }
819 if (opt_monitor)
820 {
821 ph = GNUNET_ATS_performance_init (cfg, &ats_perf_mon_cb, NULL);
822 shutdown_task = GNUNET_SCHEDULER_add_shutdown (&end, NULL);
823 if (NULL == ph)
824 {
825 fprintf (stderr, "%s", _ ("Cannot connect to ATS service, exiting...\n"));
826 GNUNET_SCHEDULER_shutdown ();
827 }
828 return;
829 }
830 if (opt_set_pref)
831 {
832 if (NULL == opt_type_str)
833 {
834 fprintf (stderr, "%s", _ ("No preference type given!\n"));
835 return;
836 }
837 if (NULL == opt_pid_str)
838 {
839 fprintf (stderr, "%s", _ ("No peer given!\n"));
840 return;
841 }
842
843 for (c = 0; c < strlen (opt_type_str); c++)
844 {
845 if (isupper ((unsigned char) opt_type_str[c]))
846 opt_type_str[c] = tolower ((unsigned char) opt_type_str[c]);
847 }
848
849 if (0 == strcasecmp ("latency", opt_type_str))
850 type = GNUNET_ATS_PREFERENCE_LATENCY;
851 else if (0 == strcasecmp ("bandwidth", opt_type_str))
852 type = GNUNET_ATS_PREFERENCE_BANDWIDTH;
853 else
854 {
855 fprintf (stderr, "%s", _ ("Valid type required\n"));
856 return;
857 }
858
859 /* set */
860 ph = GNUNET_ATS_performance_init (cfg, NULL, NULL);
861 if (NULL == ph)
862 fprintf (stderr, "%s", _ ("Cannot connect to ATS service, exiting...\n"));
863
864 GNUNET_ATS_performance_change_preference (ph,
865 &pid,
866 type,
867 (double) opt_pref_value,
868 GNUNET_ATS_PREFERENCE_END);
869
870 shutdown_task =
871 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &end, NULL);
872 return;
873 }
874 if (NULL != cpid_str)
875 {
876 ats_ch = GNUNET_ATS_connectivity_init (cfg);
877 ats_sh = GNUNET_ATS_connectivity_suggest (ats_ch, &cpid, 1000);
878 shutdown_task =
879 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &end, NULL);
880 return;
881 }
882 ret = 1;
883}
884
885
886/**
887 * The main function.
888 *
889 * @param argc number of arguments from the command line
890 * @param argv command line arguments
891 * @return 0 ok, 1 on error
892 */
893int
894main (int argc, char *const *argv)
895{
896 int res;
897
898 opt_resolve_addresses_numeric = GNUNET_NO;
899 opt_monitor = GNUNET_NO;
900 opt_list_all = GNUNET_NO;
901 opt_list_used = GNUNET_NO;
902 opt_set_pref = GNUNET_NO;
903 stat_pending = 0;
904 stat_receive_done = GNUNET_NO;
905 opt_type_str = NULL;
906
907 struct GNUNET_GETOPT_CommandLineOption options[] =
908 { GNUNET_GETOPT_option_flag ('u',
909 "used",
910 gettext_noop (
911 "get list of active addresses currently used"),
912 &opt_list_used),
913 GNUNET_GETOPT_option_flag ('a',
914 "all",
915 gettext_noop (
916 "get list of all active addresses"),
917 &opt_list_all),
918
919 GNUNET_GETOPT_option_string ('C',
920 "connect",
921 NULL,
922 gettext_noop ("connect to PEER"),
923 &cpid_str),
924 GNUNET_GETOPT_option_flag ('n',
925 "numeric",
926 gettext_noop (
927 "do not resolve IP addresses to hostnames"),
928 &opt_resolve_addresses_numeric),
929
930 GNUNET_GETOPT_option_flag ('m',
931 "monitor",
932 gettext_noop ("monitor mode"),
933 &opt_monitor),
934
935 GNUNET_GETOPT_option_flag ('p',
936 "preference",
937 gettext_noop (
938 "set preference for the given peer"),
939 &opt_set_pref),
940
941 GNUNET_GETOPT_option_flag ('q',
942 "quotas",
943 gettext_noop ("print all configured quotas"),
944 &opt_print_quotas),
945 GNUNET_GETOPT_option_string ('i',
946 "id",
947 "TYPE",
948 gettext_noop ("peer id"),
949 &opt_pid_str),
950
951 GNUNET_GETOPT_option_string ('t',
952 "type",
953 "TYPE",
954 gettext_noop (
955 "preference type to set: latency | bandwidth"),
956 &opt_type_str),
957
958 GNUNET_GETOPT_option_uint ('k',
959 "value",
960 "VALUE",
961 gettext_noop ("preference value"),
962 &opt_pref_value),
963
964 GNUNET_GETOPT_option_flag (
965 'V',
966 "verbose",
967 gettext_noop ("verbose output (include ATS address properties)"),
968 &opt_verbose),
969 GNUNET_GETOPT_OPTION_END };
970
971 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
972 return 2;
973
974 res = GNUNET_PROGRAM_run (argc,
975 argv,
976 "gnunet-ats",
977 gettext_noop ("Print information about ATS state"),
978 options,
979 &run,
980 NULL);
981 GNUNET_free (opt_pid_str);
982 GNUNET_free (opt_type_str);
983 GNUNET_free_nz ((void *) argv);
984
985 if (GNUNET_OK == res)
986 return ret;
987 else
988 return 1;
989}
990
991
992/* end of gnunet-ats.c */
diff --git a/src/ats-tool/meson.build b/src/ats-tool/meson.build
deleted file mode 100644
index 6b6df7b3d..000000000
--- a/src/ats-tool/meson.build
+++ /dev/null
@@ -1,15 +0,0 @@
1if get_option('monolith')
2 subdir_done()
3endif
4
5executable ('gnunet-ats',
6 ['gnunet-ats.c'],
7 dependencies: [libgnunetats_dep, libgnunetutil_dep,
8 libgnunettransport_dep,
9 libgnunetnt_dep,
10 libgnunethello_dep
11 ],
12 include_directories: [incdir, configuration_inc],
13 install: true,
14 install_dir: get_option('bindir'))
15
diff --git a/src/ats/.gitignore b/src/ats/.gitignore
deleted file mode 100644
index fa72eb136..000000000
--- a/src/ats/.gitignore
+++ /dev/null
@@ -1,6 +0,0 @@
1gnunet-service-ats
2test_ats_api_proportional
3test_ats_reservation_api_proportional
4test_ats_api_mlp
5test_ats_api_ril
6gnunet-service-ats-new
diff --git a/src/ats/Makefile.am b/src/ats/Makefile.am
deleted file mode 100644
index 85a2bb555..000000000
--- a/src/ats/Makefile.am
+++ /dev/null
@@ -1,102 +0,0 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3
4plugindir = $(libdir)/gnunet
5
6pkgcfgdir= $(pkgdatadir)/config.d/
7
8libexecdir= $(pkglibdir)/libexec/
9
10pkgcfg_DATA = \
11 ats.conf
12
13if USE_COVERAGE
14 AM_CFLAGS = -fprofile-arcs -ftest-coverage
15endif
16
17lib_LTLIBRARIES = \
18 libgnunetats.la
19
20plugin_LTLIBRARIES = \
21 libgnunet_plugin_ats_proportional.la
22
23libgnunetats_la_SOURCES = \
24 ats_api_connectivity.c \
25 ats_api_scheduling.c \
26 ats_api_scanner.c \
27 ats_api_performance.c
28libgnunetats_la_LIBADD = \
29 $(top_builddir)/src/hello/libgnunethello.la \
30 $(top_builddir)/src/util/libgnunetutil.la \
31 $(LTLIBINTL)
32libgnunetats_la_LDFLAGS = \
33 $(GN_LIB_LDFLAGS) \
34 -version-info 4:0:0
35
36libgnunet_plugin_ats_proportional_la_SOURCES = \
37 plugin_ats_proportional.c
38libgnunet_plugin_ats_proportional_la_LIBADD = \
39 libgnunetats.la \
40 $(top_builddir)/src/statistics/libgnunetstatistics.la \
41 $(top_builddir)/src/util/libgnunetutil.la \
42 $(top_builddir)/src/nt/libgnunetnt.la \
43 $(LTLIBINTL)
44libgnunet_plugin_ats_proportional_la_LDFLAGS = \
45 $(GN_PLUGIN_LDFLAGS)
46
47
48libexec_PROGRAMS = \
49 gnunet-service-ats
50
51gnunet_service_ats_SOURCES = \
52 gnunet-service-ats.c gnunet-service-ats.h \
53 gnunet-service-ats_addresses.c gnunet-service-ats_addresses.h \
54 gnunet-service-ats_connectivity.c gnunet-service-ats_connectivity.h \
55 gnunet-service-ats_normalization.c gnunet-service-ats_normalization.h \
56 gnunet-service-ats_performance.c gnunet-service-ats_performance.h \
57 gnunet-service-ats_plugins.c gnunet-service-ats_plugins.h \
58 gnunet-service-ats_preferences.c gnunet-service-ats_preferences.h \
59 gnunet-service-ats_scheduling.c gnunet-service-ats_scheduling.h \
60 gnunet-service-ats_reservations.c gnunet-service-ats_reservations.h
61gnunet_service_ats_LDADD = \
62 $(top_builddir)/src/nt/libgnunetnt.la \
63 $(top_builddir)/src/statistics/libgnunetstatistics.la \
64 $(top_builddir)/src/util/libgnunetutil.la \
65 libgnunetats.la \
66 $(GN_LIBINTL)
67
68TESTING_TESTS = \
69 test_ats_api_proportional \
70 test_ats_reservation_api_proportional
71
72check_PROGRAMS = \
73 $(TESTING_TESTS)
74
75if ENABLE_TEST_RUN
76AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
77TESTS = $(check_PROGRAMS)
78endif
79
80test_ats_api_proportional_SOURCES = \
81 test_ats_api.c \
82 test_ats_lib.c test_ats_lib.h
83test_ats_api_proportional_LDADD = \
84 $(top_builddir)/src/util/libgnunetutil.la \
85 $(top_builddir)/src/hello/libgnunethello.la \
86 $(top_builddir)/src/testing/libgnunettesting.la \
87 libgnunetats.la
88
89test_ats_reservation_api_proportional_SOURCES = \
90 test_ats_reservation_api.c \
91 test_ats_lib.c test_ats_lib.h
92test_ats_reservation_api_proportional_LDADD = \
93 $(top_builddir)/src/util/libgnunetutil.la \
94 $(top_builddir)/src/hello/libgnunethello.la \
95 $(top_builddir)/src/testing/libgnunettesting.la \
96 libgnunetats.la
97
98EXTRA_DIST = \
99 ats.h \
100 test_delay \
101 test_ats_api.conf \
102 test_ats_api_proportional.conf
diff --git a/src/ats/ats.conf.in b/src/ats/ats.conf.in
deleted file mode 100644
index 2c65869dd..000000000
--- a/src/ats/ats.conf.in
+++ /dev/null
@@ -1,44 +0,0 @@
1[ats]
2START_ON_DEMAND = @START_ON_DEMAND@
3@UNIXONLY@ PORT = 2098
4HOSTNAME = localhost
5BINARY = gnunet-service-ats
6ACCEPT_FROM = 127.0.0.1;
7ACCEPT_FROM6 = ::1;
8UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-ats.sock
9UNIX_MATCH_UID = NO
10UNIX_MATCH_GID = YES
11# PREFIX = valgrind
12# Designated assignment mode: PROPORTIONAL / MLP / RIL
13MODE = proportional
14
15# IMPORTANT: Do not lower those quotas below 10 MiB
16# Or your peer may not bootstrap correctly.
17# Network specific inbound/outbound quotas
18UNSPECIFIED_QUOTA_IN = unlimited
19UNSPECIFIED_QUOTA_OUT = unlimited
20# LOOPBACK
21LOOPBACK_QUOTA_IN = unlimited
22LOOPBACK_QUOTA_OUT = unlimited
23# LAN
24LAN_QUOTA_IN = unlimited
25LAN_QUOTA_OUT = unlimited
26# WAN
27WAN_QUOTA_IN = 10 MiB
28WAN_QUOTA_OUT = 10 MiB
29# WLAN
30WLAN_QUOTA_IN = unlimited
31WLAN_QUOTA_OUT = unlimited
32# BLUETOOTH
33BLUETOOTH_QUOTA_IN = 10 MiB
34BLUETOOTH_QUOTA_OUT = 10 MiB
35# ATS options
36
37# Proportional specific settings
38# How proportional to preferences is bandwidth distribution in a network
39# 1.0: Fair with respect to addresses without preferences
40# > 1.0: The bigger, the more respect is paid to preferences
41PROP_PROPORTIONALITY_FACTOR = 10.00
42# Should we stick to existing connections or prefer to switch?
43# [1.0...2.0], lower value prefers to switch, bigger value is more tolerant
44PROP_STABILITY_FACTOR = 1.25
diff --git a/src/ats/ats.h b/src/ats/ats.h
deleted file mode 100644
index 711c1c103..000000000
--- a/src/ats/ats.h
+++ /dev/null
@@ -1,492 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010-2015 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file ats/ats.h
22 * @brief automatic transport selection messages
23 * @author Christian Grothoff
24 * @author Matthias Wachs
25 */
26#ifndef ATS_H
27#define ATS_H
28
29#include "gnunet_util_lib.h"
30#include "gnunet_ats_service.h"
31
32
33/**
34 * Flag used to indicate which type of client is connecting
35 * to the ATS service.
36 */
37enum StartFlag
38{
39 /**
40 * This is a scheduling client (aka transport service)
41 */
42 START_FLAG_SCHEDULING = 0,
43
44 /**
45 * Performance monitoring client that wants to learn about
46 * changes in performance characteristics.
47 */
48 START_FLAG_PERFORMANCE_WITH_PIC = 1,
49
50 /**
51 * Performance monitoring client that does NOT want to learn
52 * about changes in performance characteristics.
53 */
54 START_FLAG_PERFORMANCE_NO_PIC = 2,
55
56 /**
57 * Connection suggestion handle.
58 */
59 START_FLAG_CONNECTION_SUGGESTION = 3
60};
61
62
63GNUNET_NETWORK_STRUCT_BEGIN
64
65/**
66 * First message any client sends to ATS, used to self-identify
67 * (what type of client this is).
68 */
69struct ClientStartMessage
70{
71 /**
72 * Type is #GNUNET_MESSAGE_TYPE_ATS_START.
73 */
74 struct GNUNET_MessageHeader header;
75
76 /**
77 * NBO value of an `enum StartFlag`.
78 */
79 uint32_t start_flag GNUNET_PACKED;
80};
81
82
83/**
84 * Connectivity client to ATS service: we would like to have
85 * address suggestions for this peer.
86 */
87struct RequestAddressMessage
88{
89 /**
90 * Type is #GNUNET_MESSAGE_TYPE_ATS_REQUEST_ADDRESS or
91 * #GNUNET_MESSAGE_TYPE_ATS_REQUEST_ADDRESS_CANCEL to stop
92 * suggestions.
93 */
94 struct GNUNET_MessageHeader header;
95
96 /**
97 * How "strong" is our need for an address for this peer?
98 */
99 uint32_t strength GNUNET_PACKED;
100
101 /**
102 * Peer to get address suggestions for.
103 */
104 struct GNUNET_PeerIdentity peer;
105};
106
107
108/**
109 * Scheduling client to ATS service: here is another address you can use.
110 */
111struct AddressAddMessage
112{
113 /**
114 * Type is #GNUNET_MESSAGE_TYPE_ATS_ADDRESS_ADD.
115 */
116 struct GNUNET_MessageHeader header;
117
118 /**
119 * Number of bytes in the address that follows this struct.
120 */
121 uint16_t address_length GNUNET_PACKED;
122
123 /**
124 * Number of bytes in the plugin name that follows this struct.
125 */
126 uint16_t plugin_name_length GNUNET_PACKED;
127
128 /**
129 * Identity of the peer that this address is for.
130 */
131 struct GNUNET_PeerIdentity peer;
132
133 /**
134 * Internal number this client will henceforth use to
135 * refer to this address.
136 */
137 uint32_t session_id GNUNET_PACKED;
138
139 /**
140 * Local-only information of the address, see
141 * `enum GNUNET_HELLO_AddressInfo`.
142 */
143 uint32_t address_local_info GNUNET_PACKED;
144
145 /**
146 * Performance properties of the address.
147 */
148 struct GNUNET_ATS_PropertiesNBO properties;
149
150 /* followed by:
151 * - char address[address_length]
152 * - char plugin_name[plugin_name_length] (including '\0'-termination).
153 */
154};
155
156
157/**
158 * Message used to notify ATS that the performance
159 * characteristics for an address have changed.
160 */
161struct AddressUpdateMessage
162{
163 /**
164 * Message of type #GNUNET_MESSAGE_TYPE_ATS_ADDRESS_UPDATE.
165 */
166 struct GNUNET_MessageHeader header;
167
168 /**
169 * Internal number this client uses to refer to this address.
170 */
171 uint32_t session_id GNUNET_PACKED;
172
173 /**
174 * Which peer is this about? (Technically redundant, as the
175 * @e session_id should be sufficient, but enables ATS service
176 * to find the session faster).
177 */
178 struct GNUNET_PeerIdentity peer;
179
180 /**
181 * Performance properties of the address.
182 */
183 struct GNUNET_ATS_PropertiesNBO properties;
184};
185
186
187/**
188 * Message sent by ATS client to ATS service when an address
189 * was destroyed and must thus henceforth no longer be considered
190 * for scheduling.
191 */
192struct AddressDestroyedMessage
193{
194 /**
195 * Type is #GNUNET_MESSAGE_TYPE_ATS_ADDRESS_DESTROYED.
196 */
197 struct GNUNET_MessageHeader header;
198
199 /**
200 * Internal number this client uses to refer to this address.
201 */
202 uint32_t session_id GNUNET_PACKED;
203
204 /**
205 * Which peer is this about? (Technically redundant, as the
206 * @e session_id should be sufficient, but enables ATS service
207 * to find the session faster).
208 */
209 struct GNUNET_PeerIdentity peer;
210};
211
212
213/**
214 * Message sent by ATS service to client to confirm that it is done
215 * using the given session ID.
216 */
217struct GNUNET_ATS_SessionReleaseMessage
218{
219 /**
220 * Type is #GNUNET_MESSAGE_TYPE_ATS_SESSION_RELEASE.
221 */
222 struct GNUNET_MessageHeader header;
223
224 /**
225 * Number the client used to identify the session.
226 */
227 uint32_t session_id GNUNET_PACKED;
228
229 /**
230 * Which peer is this about? (Technically redundant, as the
231 * @e session_id should be sufficient, but may enable client
232 * to find the session faster).
233 */
234 struct GNUNET_PeerIdentity peer;
235};
236
237
238/**
239 * ATS Service suggests to the transport service to use the address
240 * identified by the given @e session_id for the given @e peer with
241 * the given @e bandwidth_in and @e bandwidth_out limits from now on.
242 */
243struct AddressSuggestionMessage
244{
245 /**
246 * A message of type #GNUNET_MESSAGE_TYPE_ATS_ADDRESS_SUGGESTION.
247 */
248 struct GNUNET_MessageHeader header;
249
250 /**
251 * Internal number this client uses to refer to the address this
252 * suggestion is about.
253 */
254 uint32_t session_id GNUNET_PACKED;
255
256 /**
257 * Which peer is this about? (Technically redundant, as the
258 * @e session_id should be sufficient, but may enable client
259 * to find the session faster and/or check consistency).
260 */
261 struct GNUNET_PeerIdentity peer;
262
263 /**
264 * How much bandwidth we are allowed for sending.
265 */
266 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out;
267
268 /**
269 * How much bandwidth we are allowed for receiving.
270 */
271 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in;
272};
273
274
275/**
276 *
277 */
278struct PeerInformationMessage
279{
280 /**
281 * Type is #GNUNET_MESSAGE_TYPE_ATS_PEER_INFORMATION
282 */
283 struct GNUNET_MessageHeader header;
284
285 /**
286 *
287 */
288 uint16_t address_length GNUNET_PACKED;
289
290 /**
291 *
292 */
293 uint16_t plugin_name_length GNUNET_PACKED;
294
295 /**
296 *
297 */
298 struct GNUNET_PeerIdentity peer;
299
300 /**
301 *
302 */
303 uint32_t address_active GNUNET_PACKED;
304
305 /**
306 *
307 */
308 uint32_t id GNUNET_PACKED;
309
310 /**
311 *
312 */
313 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out;
314
315 /**
316 *
317 */
318 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in;
319
320 /**
321 * Performance properties of the address.
322 */
323 struct GNUNET_ATS_PropertiesNBO properties;
324
325 /**
326 * Local-only information of the address, see
327 * `enum GNUNET_HELLO_AddressInfo`.
328 */
329 uint32_t address_local_info GNUNET_PACKED;
330
331 /* followed by:
332 * - char address[address_length]
333 * - char plugin_name[plugin_name_length] (including '\0'-termination).
334 */
335};
336
337
338/**
339 * Client to service: please give us an overview of the addresses.
340 */
341struct AddressListRequestMessage
342{
343 /**
344 * Type is #GNUNET_MESSAGE_TYPE_ATS_ADDRESSLIST_REQUEST
345 */
346 struct GNUNET_MessageHeader header;
347
348 /**
349 * ID used to match replies to this request.
350 */
351 uint32_t id GNUNET_PACKED;
352
353 /**
354 * Which peer do we care about? All zeros for all.
355 */
356 struct GNUNET_PeerIdentity peer;
357
358 /**
359 * #GNUNET_YES to get information about all addresses,
360 * #GNUNET_NO to only return addresses that are in use.
361 */
362 int32_t all GNUNET_PACKED;
363};
364
365
366/**
367 *
368 */
369struct ReservationRequestMessage
370{
371 /**
372 * Type is #GNUNET_MESSAGE_TYPE_ATS_RESERVATION_REQUEST
373 */
374 struct GNUNET_MessageHeader header;
375
376 /**
377 *
378 */
379 int32_t amount GNUNET_PACKED;
380
381 /**
382 *
383 */
384 struct GNUNET_PeerIdentity peer;
385};
386
387
388/**
389 *
390 */
391struct ReservationResultMessage
392{
393 /**
394 * Type is #GNUNET_MESSAGE_TYPE_ATS_RESERVATION_RESULT
395 */
396 struct GNUNET_MessageHeader header;
397
398 /**
399 *
400 */
401 int32_t amount GNUNET_PACKED;
402
403 /**
404 *
405 */
406 struct GNUNET_PeerIdentity peer;
407
408 /**
409 *
410 */
411 struct GNUNET_TIME_RelativeNBO res_delay;
412};
413
414
415/**
416 * Variable-size entry in a `struct ChangePreferenceMessage` or
417 * `struct FeedbackPreferenceMessage`.
418 */
419struct PreferenceInformation
420{
421 /**
422 * An `enum GNUNET_ATS_PreferenceKind` in NBO.
423 */
424 uint32_t preference_kind GNUNET_PACKED;
425
426 /**
427 * Degree of preference (or appreciation) for this @e
428 * preference_kind being expressed.
429 */
430 float preference_value GNUNET_PACKED;
431};
432
433
434/**
435 * Client to ATS: I have a performance preference for a peer.
436 */
437struct ChangePreferenceMessage
438{
439 /**
440 * Type is #GNUNET_MESSAGE_TYPE_ATS_PREFERENCE_CHANGE.
441 */
442 struct GNUNET_MessageHeader header;
443
444 /**
445 * How many `struct PreferenceInformation` entries follow
446 * this struct?
447 */
448 uint32_t num_preferences GNUNET_PACKED;
449
450 /**
451 * Which peer is the preference being expressed for?
452 */
453 struct GNUNET_PeerIdentity peer;
454
455 /* followed by 'num_preferences'
456 * struct PreferenceInformation values */
457};
458
459
460/**
461 * Message containing application feedback for a peer
462 */
463struct FeedbackPreferenceMessage
464{
465 /**
466 * Type is #GNUNET_MESSAGE_TYPE_ATS_PREFERENCE_FEEDBACK.
467 */
468 struct GNUNET_MessageHeader header;
469
470 /**
471 * Number of feedback values included
472 */
473 uint32_t num_feedback GNUNET_PACKED;
474
475 /**
476 * Relative time describing for which time interval this feedback is
477 */
478 struct GNUNET_TIME_RelativeNBO scope;
479
480 /**
481 * Peer this feedback is for
482 */
483 struct GNUNET_PeerIdentity peer;
484
485 /* followed by 'num_feedback'
486 * struct PreferenceInformation values */
487};
488
489GNUNET_NETWORK_STRUCT_END
490
491
492#endif
diff --git a/src/ats/ats_api_connectivity.c b/src/ats/ats_api_connectivity.c
deleted file mode 100644
index f62d89772..000000000
--- a/src/ats/ats_api_connectivity.c
+++ /dev/null
@@ -1,362 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010-2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file ats/ats_api_connectivity.c
22 * @brief enable clients to ask ATS about establishing connections to peers
23 * @author Christian Grothoff
24 * @author Matthias Wachs
25 */
26#include "platform.h"
27#include "gnunet_ats_service.h"
28#include "ats.h"
29
30
31#define LOG(kind, ...) GNUNET_log_from (kind, "ats-connectivity-api", \
32 __VA_ARGS__)
33
34
35/**
36 * Handle for ATS address suggestion requests.
37 */
38struct GNUNET_ATS_ConnectivitySuggestHandle
39{
40 /**
41 * ID of the peer for which address suggestion was requested.
42 */
43 struct GNUNET_PeerIdentity id;
44
45 /**
46 * Connecitivity handle this suggestion handle belongs to.
47 */
48 struct GNUNET_ATS_ConnectivityHandle *ch;
49
50 /**
51 * How urgent is the request.
52 */
53 uint32_t strength;
54};
55
56
57/**
58 * Handle to the ATS subsystem for connectivity management.
59 */
60struct GNUNET_ATS_ConnectivityHandle
61{
62 /**
63 * Our configuration.
64 */
65 const struct GNUNET_CONFIGURATION_Handle *cfg;
66
67 /**
68 * Map with the identities of all the peers for which we would
69 * like to have address suggestions. The key is the PID, the
70 * value is currently the `struct GNUNET_ATS_ConnectivitySuggestHandle`
71 */
72 struct GNUNET_CONTAINER_MultiPeerMap *sug_requests;
73
74 /**
75 * Message queue for sending requests to the ATS service.
76 */
77 struct GNUNET_MQ_Handle *mq;
78
79 /**
80 * Task to trigger reconnect.
81 */
82 struct GNUNET_SCHEDULER_Task *task;
83
84 /**
85 * Reconnect backoff delay.
86 */
87 struct GNUNET_TIME_Relative backoff;
88};
89
90
91/**
92 * Re-establish the connection to the ATS service.
93 *
94 * @param ch handle to use to re-connect.
95 */
96static void
97reconnect (struct GNUNET_ATS_ConnectivityHandle *ch);
98
99
100/**
101 * Re-establish the connection to the ATS service.
102 *
103 * @param cls handle to use to re-connect.
104 */
105static void
106reconnect_task (void *cls)
107{
108 struct GNUNET_ATS_ConnectivityHandle *ch = cls;
109
110 ch->task = NULL;
111 reconnect (ch);
112}
113
114
115/**
116 * Disconnect from ATS and then reconnect.
117 *
118 * @param ch our handle
119 */
120static void
121force_reconnect (struct GNUNET_ATS_ConnectivityHandle *ch)
122{
123 if (NULL != ch->mq)
124 {
125 GNUNET_MQ_destroy (ch->mq);
126 ch->mq = NULL;
127 }
128 ch->backoff = GNUNET_TIME_STD_BACKOFF (ch->backoff);
129 ch->task = GNUNET_SCHEDULER_add_delayed (ch->backoff,
130 &reconnect_task,
131 ch);
132}
133
134
135/**
136 * We encountered an error handling the MQ to the
137 * ATS service. Reconnect.
138 *
139 * @param cls the `struct GNUNET_ATS_ConnectivityHandle`
140 * @param error details about the error
141 */
142static void
143error_handler (void *cls,
144 enum GNUNET_MQ_Error error)
145{
146 struct GNUNET_ATS_ConnectivityHandle *ch = cls;
147
148 LOG (GNUNET_ERROR_TYPE_DEBUG,
149 "ATS connection died (code %d), reconnecting\n",
150 (int) error);
151 force_reconnect (ch);
152}
153
154
155/**
156 * Transmit request for an address suggestion.
157 *
158 * @param cls the `struct GNUNET_ATS_ConnectivityHandle`
159 * @param peer peer to ask for an address suggestion for
160 * @param value the `struct GNUNET_ATS_SuggestHandle`
161 * @return #GNUNET_OK (continue to iterate), #GNUNET_SYSERR on
162 * failure (message queue no longer exists)
163 */
164static int
165transmit_suggestion (void *cls,
166 const struct GNUNET_PeerIdentity *peer,
167 void *value)
168{
169 struct GNUNET_ATS_ConnectivityHandle *ch = cls;
170 struct GNUNET_ATS_ConnectivitySuggestHandle *sh = value;
171 struct GNUNET_MQ_Envelope *ev;
172 struct RequestAddressMessage *m;
173
174 if (NULL == ch->mq)
175 return GNUNET_SYSERR;
176 ev = GNUNET_MQ_msg (m, GNUNET_MESSAGE_TYPE_ATS_REQUEST_ADDRESS);
177 m->strength = htonl (sh->strength);
178 m->peer = *peer;
179 GNUNET_MQ_send (ch->mq, ev);
180 return GNUNET_OK;
181}
182
183
184/**
185 * Re-establish the connection to the ATS service.
186 *
187 * @param ch handle to use to re-connect.
188 */
189static void
190reconnect (struct GNUNET_ATS_ConnectivityHandle *ch)
191{
192 static const struct GNUNET_MQ_MessageHandler handlers[] =
193 { { NULL, 0, 0 } };
194 struct GNUNET_MQ_Envelope *ev;
195 struct ClientStartMessage *init;
196
197 GNUNET_assert (NULL == ch->mq);
198 ch->mq = GNUNET_CLIENT_connect (ch->cfg,
199 "ats",
200 handlers,
201 &error_handler,
202 ch);
203 if (NULL == ch->mq)
204 {
205 force_reconnect (ch);
206 return;
207 }
208 ev = GNUNET_MQ_msg (init,
209 GNUNET_MESSAGE_TYPE_ATS_START);
210 init->start_flag = htonl (START_FLAG_CONNECTION_SUGGESTION);
211 GNUNET_MQ_send (ch->mq, ev);
212 if (NULL == ch->mq)
213 return;
214 GNUNET_CONTAINER_multipeermap_iterate (ch->sug_requests,
215 &transmit_suggestion,
216 ch);
217}
218
219
220/**
221 * Initialize the ATS connectivity suggestion client handle.
222 *
223 * @param cfg configuration to use
224 * @return ats connectivity handle, NULL on error
225 */
226struct GNUNET_ATS_ConnectivityHandle *
227GNUNET_ATS_connectivity_init (const struct GNUNET_CONFIGURATION_Handle *cfg)
228{
229 struct GNUNET_ATS_ConnectivityHandle *ch;
230
231 ch = GNUNET_new (struct GNUNET_ATS_ConnectivityHandle);
232 ch->cfg = cfg;
233 ch->sug_requests = GNUNET_CONTAINER_multipeermap_create (32,
234 GNUNET_YES);
235 reconnect (ch);
236 return ch;
237}
238
239
240/**
241 * Function called to free all `struct GNUNET_ATS_ConnectivitySuggestHandle`s
242 * in the map.
243 *
244 * @param cls NULL
245 * @param key the key
246 * @param value the value to free
247 * @return #GNUNET_OK (continue to iterate)
248 */
249static int
250free_sug_handle (void *cls,
251 const struct GNUNET_PeerIdentity *key,
252 void *value)
253{
254 struct GNUNET_ATS_ConnectivitySuggestHandle *cur = value;
255
256 GNUNET_free (cur);
257 return GNUNET_OK;
258}
259
260
261/**
262 * Client is done with ATS connectivity management, release resources.
263 *
264 * @param ch handle to release
265 */
266void
267GNUNET_ATS_connectivity_done (struct GNUNET_ATS_ConnectivityHandle *ch)
268{
269 if (NULL != ch->mq)
270 {
271 GNUNET_MQ_destroy (ch->mq);
272 ch->mq = NULL;
273 }
274 if (NULL != ch->task)
275 {
276 GNUNET_SCHEDULER_cancel (ch->task);
277 ch->task = NULL;
278 }
279 GNUNET_CONTAINER_multipeermap_iterate (ch->sug_requests,
280 &free_sug_handle,
281 NULL);
282 GNUNET_CONTAINER_multipeermap_destroy (ch->sug_requests);
283 GNUNET_free (ch);
284}
285
286
287/**
288 * We would like to receive address suggestions for a peer. ATS will
289 * respond with a call to the continuation immediately containing an address or
290 * no address if none is available. ATS can suggest more addresses until we call
291 * #GNUNET_ATS_connectivity_suggest_cancel().
292 *
293 * @param ch handle
294 * @param peer identity of the peer we need an address for
295 * @param strength how urgent is the need for such a suggestion
296 * @return suggest handle, NULL if a request is already pending
297 */
298struct GNUNET_ATS_ConnectivitySuggestHandle *
299GNUNET_ATS_connectivity_suggest (struct GNUNET_ATS_ConnectivityHandle *ch,
300 const struct GNUNET_PeerIdentity *peer,
301 uint32_t strength)
302{
303 struct GNUNET_ATS_ConnectivitySuggestHandle *s;
304
305 s = GNUNET_new (struct GNUNET_ATS_ConnectivitySuggestHandle);
306 s->ch = ch;
307 s->id = *peer;
308 s->strength = strength;
309 if (GNUNET_OK !=
310 GNUNET_CONTAINER_multipeermap_put (ch->sug_requests,
311 &s->id,
312 s,
313 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
314 {
315 LOG (GNUNET_ERROR_TYPE_DEBUG,
316 "Not requesting ATS to suggest address for `%s', request already pending\n",
317 GNUNET_i2s (peer));
318 GNUNET_free (s);
319 return NULL;
320 }
321 LOG (GNUNET_ERROR_TYPE_DEBUG,
322 "Requesting ATS to suggest address for `%s'\n",
323 GNUNET_i2s (peer));
324 if (NULL == ch->mq)
325 return s;
326 (void) transmit_suggestion (ch,
327 &s->id,
328 s);
329 return s;
330}
331
332
333void
334GNUNET_ATS_connectivity_suggest_cancel (struct
335 GNUNET_ATS_ConnectivitySuggestHandle *sh)
336{
337 struct GNUNET_ATS_ConnectivityHandle *ch = sh->ch;
338 struct GNUNET_MQ_Envelope *ev;
339 struct RequestAddressMessage *m;
340
341 LOG (GNUNET_ERROR_TYPE_DEBUG,
342 "Telling ATS we no longer care for an address for `%s'\n",
343 GNUNET_i2s (&sh->id));
344 GNUNET_assert (GNUNET_OK ==
345 GNUNET_CONTAINER_multipeermap_remove (ch->sug_requests,
346 &sh->id,
347 sh));
348 if (NULL == ch->mq)
349 {
350 GNUNET_free (sh);
351 return;
352 }
353 ev = GNUNET_MQ_msg (m,
354 GNUNET_MESSAGE_TYPE_ATS_REQUEST_ADDRESS_CANCEL);
355 m->strength = htonl (0);
356 m->peer = sh->id;
357 GNUNET_MQ_send (ch->mq, ev);
358 GNUNET_free (sh);
359}
360
361
362/* end of ats_api_connectivity.c */
diff --git a/src/ats/ats_api_performance.c b/src/ats/ats_api_performance.c
deleted file mode 100644
index 242589851..000000000
--- a/src/ats/ats_api_performance.c
+++ /dev/null
@@ -1,946 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010, 2011, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file ats/ats_api_performance.c
22 * @brief automatic transport selection and outbound bandwidth determination
23 * @author Christian Grothoff
24 * @author Matthias Wachs
25 */
26#include "platform.h"
27#include "gnunet_ats_service.h"
28#include "ats.h"
29
30
31#define LOG(kind, ...) GNUNET_log_from (kind, "ats-performance-api", \
32 __VA_ARGS__)
33
34
35/**
36 * Linked list of pending reservations.
37 */
38struct GNUNET_ATS_ReservationContext
39{
40 /**
41 * Kept in a DLL.
42 */
43 struct GNUNET_ATS_ReservationContext *next;
44
45 /**
46 * Kept in a DLL.
47 */
48 struct GNUNET_ATS_ReservationContext *prev;
49
50 /**
51 * Target peer.
52 */
53 struct GNUNET_PeerIdentity peer;
54
55 /**
56 * Desired reservation
57 */
58 int32_t size;
59
60 /**
61 * Function to call on result.
62 */
63 GNUNET_ATS_ReservationCallback rcb;
64
65 /**
66 * Closure for @e rcb
67 */
68 void *rcb_cls;
69
70 /**
71 * Do we need to undo this reservation if it succeeded? Set to
72 * #GNUNET_YES if a reservation is cancelled. (at that point, 'info'
73 * is also set to NULL; however, info will ALSO be NULL for the
74 * reservation context that is created to undo the original request,
75 * so 'info' being NULL cannot be used to check if undo is
76 * required).
77 */
78 int undo;
79};
80
81
82/**
83 * Linked list of pending reservations.
84 */
85struct GNUNET_ATS_AddressListHandle
86{
87 /**
88 * Kept in a DLL.
89 */
90 struct GNUNET_ATS_AddressListHandle *next;
91
92 /**
93 * Kept in a DLL.
94 */
95 struct GNUNET_ATS_AddressListHandle *prev;
96
97 /**
98 * Performance handle
99 */
100 struct GNUNET_ATS_PerformanceHandle *ph;
101
102 /**
103 * Callback
104 */
105 GNUNET_ATS_AddressInformationCallback cb;
106
107 /**
108 * Callback closure for @e cb
109 */
110 void *cb_cls;
111
112 /**
113 * Target peer.
114 */
115 struct GNUNET_PeerIdentity peer;
116
117 /**
118 * Return all or specific peer only
119 */
120 int all_peers;
121
122 /**
123 * Return all or used address only
124 */
125 int all_addresses;
126
127 /**
128 * Request multiplexing
129 */
130 uint32_t id;
131};
132
133
134/**
135 * ATS Handle to obtain and/or modify performance information.
136 */
137struct GNUNET_ATS_PerformanceHandle
138{
139 /**
140 * Our configuration.
141 */
142 const struct GNUNET_CONFIGURATION_Handle *cfg;
143
144 /**
145 * Callback to invoke when an address has performance changes.
146 */
147 GNUNET_ATS_AddressInformationCallback addr_info_cb;
148
149 /**
150 * Closure for @e addr_info_cb.
151 */
152 void *addr_info_cb_cls;
153
154 /**
155 * Connection to ATS service.
156 */
157 struct GNUNET_MQ_Handle *mq;
158
159 /**
160 * Head of linked list of pending reservation requests.
161 */
162 struct GNUNET_ATS_ReservationContext *reservation_head;
163
164 /**
165 * Tail of linked list of pending reservation requests.
166 */
167 struct GNUNET_ATS_ReservationContext *reservation_tail;
168
169 /**
170 * Head of linked list of pending address list requests.
171 */
172 struct GNUNET_ATS_AddressListHandle *addresslist_head;
173
174 /**
175 * Tail of linked list of pending address list requests.
176 */
177 struct GNUNET_ATS_AddressListHandle *addresslist_tail;
178
179 /**
180 * Current request for transmission to ATS.
181 */
182 struct GNUNET_CLIENT_TransmitHandle *th;
183
184 /**
185 * Task to trigger reconnect.
186 */
187 struct GNUNET_SCHEDULER_Task *task;
188
189 /**
190 * Reconnect backoff delay.
191 */
192 struct GNUNET_TIME_Relative backoff;
193
194 /**
195 * Monitor request multiplexing
196 */
197 uint32_t monitor_id;
198
199 /**
200 * Request multiplexing
201 */
202 uint32_t id;
203
204 /**
205 * Is the receive loop active?
206 */
207 int in_receive;
208};
209
210/**
211 * Re-establish the connection to the ATS service.
212 *
213 * @param ph handle to use to re-connect.
214 */
215static void
216reconnect (struct GNUNET_ATS_PerformanceHandle *ph);
217
218
219/**
220 * Re-establish the connection to the ATS service.
221 *
222 * @param cls handle to use to re-connect.
223 */
224static void
225reconnect_task (void *cls)
226{
227 struct GNUNET_ATS_PerformanceHandle *ph = cls;
228
229 ph->task = NULL;
230 reconnect (ph);
231}
232
233
234/**
235 * Reconnect to the ATS service, something went wrong.
236 *
237 * @param ph handle to reconnect
238 */
239static void
240do_reconnect (struct GNUNET_ATS_PerformanceHandle *ph)
241{
242 struct GNUNET_ATS_ReservationContext *rc;
243 struct GNUNET_ATS_AddressListHandle *alh;
244 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_zero;
245
246 if (NULL != ph->mq)
247 {
248 GNUNET_MQ_destroy (ph->mq);
249 ph->mq = NULL;
250 }
251 while (NULL != (rc = ph->reservation_head))
252 {
253 GNUNET_CONTAINER_DLL_remove (ph->reservation_head,
254 ph->reservation_tail,
255 rc);
256 if (NULL != rc->rcb)
257 rc->rcb (rc->rcb_cls,
258 NULL,
259 0,
260 GNUNET_TIME_UNIT_FOREVER_REL);
261 GNUNET_free (rc);
262 }
263 bandwidth_zero.value__ = htonl (0);
264 while (NULL != (alh = ph->addresslist_head))
265 {
266 GNUNET_CONTAINER_DLL_remove (ph->addresslist_head,
267 ph->addresslist_tail,
268 alh);
269 if (NULL != alh->cb)
270 alh->cb (alh->cb_cls,
271 NULL,
272 GNUNET_NO,
273 bandwidth_zero,
274 bandwidth_zero,
275 NULL);
276 GNUNET_free (alh);
277 }
278 if (NULL != ph->addr_info_cb)
279 {
280 /* Indicate reconnect */
281 ph->addr_info_cb (ph->addr_info_cb_cls,
282 NULL,
283 GNUNET_NO,
284 bandwidth_zero,
285 bandwidth_zero,
286 NULL);
287 }
288 ph->backoff = GNUNET_TIME_STD_BACKOFF (ph->backoff);
289 ph->task = GNUNET_SCHEDULER_add_delayed (ph->backoff,
290 &reconnect_task,
291 ph);
292}
293
294
295/**
296 * We received a peer information message. Validate and process it.
297 *
298 * @param cls our context with the callback
299 * @param pi the message
300 * @return #GNUNET_OK if the message was well-formed
301 */
302static int
303check_peer_information (void *cls,
304 const struct PeerInformationMessage *pi)
305{
306 const char *plugin_address;
307 const char *plugin_name;
308 uint16_t plugin_address_length;
309 uint16_t plugin_name_length;
310
311 plugin_address_length = ntohs (pi->address_length);
312 plugin_name_length = ntohs (pi->plugin_name_length);
313 plugin_address = (const char *) &pi[1];
314 plugin_name = &plugin_address[plugin_address_length];
315 if ((plugin_address_length + plugin_name_length
316 + sizeof(struct PeerInformationMessage) != ntohs (pi->header.size)) ||
317 (plugin_name[plugin_name_length - 1] != '\0'))
318 {
319 GNUNET_break (0);
320 return GNUNET_SYSERR;
321 }
322 return GNUNET_OK;
323}
324
325
326/**
327 * We received a peer information message. Validate and process it.
328 *
329 * @param cls our context with the callback
330 * @param pi the message
331 * @return #GNUNET_OK if the message was well-formed
332 */
333static void
334handle_peer_information (void *cls,
335 const struct PeerInformationMessage *pi)
336{
337 struct GNUNET_ATS_PerformanceHandle *ph = cls;
338 const char *plugin_address;
339 const char *plugin_name;
340 struct GNUNET_HELLO_Address address;
341 uint16_t plugin_address_length;
342 int addr_active;
343 struct GNUNET_ATS_Properties prop;
344
345 if (NULL == ph->addr_info_cb)
346 return;
347 plugin_address_length = ntohs (pi->address_length);
348 addr_active = (int) ntohl (pi->address_active);
349 plugin_address = (const char *) &pi[1];
350 plugin_name = &plugin_address[plugin_address_length];
351
352 GNUNET_ATS_properties_ntoh (&prop,
353 &pi->properties);
354 address.peer = pi->peer;
355 address.local_info = (enum GNUNET_HELLO_AddressInfo) ntohl (
356 pi->address_local_info);
357 address.address = plugin_address;
358 address.address_length = plugin_address_length;
359 address.transport_name = plugin_name;
360 ph->addr_info_cb (ph->addr_info_cb_cls,
361 &address,
362 addr_active,
363 pi->bandwidth_out,
364 pi->bandwidth_in,
365 &prop);
366}
367
368
369/**
370 * We received a reservation result message. Validate and process it.
371 *
372 * @param cls our context with the callback
373 * @param rr the message
374 */
375static void
376handle_reservation_result (void *cls,
377 const struct ReservationResultMessage *rr)
378{
379 struct GNUNET_ATS_PerformanceHandle *ph = cls;
380 struct GNUNET_ATS_ReservationContext *rc;
381 int32_t amount;
382
383 amount = ntohl (rr->amount);
384 rc = ph->reservation_head;
385 if (0 != GNUNET_memcmp (&rr->peer,
386 &rc->peer))
387 {
388 GNUNET_break (0);
389 reconnect (ph);
390 return;
391 }
392 GNUNET_CONTAINER_DLL_remove (ph->reservation_head,
393 ph->reservation_tail,
394 rc);
395 if ((0 == amount) ||
396 (NULL != rc->rcb))
397 {
398 /* tell client if not cancelled */
399 if (NULL != rc->rcb)
400 rc->rcb (rc->rcb_cls,
401 &rr->peer,
402 amount,
403 GNUNET_TIME_relative_ntoh (rr->res_delay));
404 GNUNET_free (rc);
405 return;
406 }
407 /* amount non-zero, but client cancelled, consider undo! */
408 if (GNUNET_YES != rc->undo)
409 {
410 GNUNET_free (rc);
411 return; /* do not try to undo failed undos or negative amounts */
412 }
413 GNUNET_free (rc);
414 (void) GNUNET_ATS_reserve_bandwidth (ph,
415 &rr->peer,
416 -amount,
417 NULL, NULL);
418}
419
420
421/**
422 * We received a PeerInformationMessage. Validate it.
423 *
424 * @param cls our context with the callback
425 * @param pi the message
426 * @return #GNUNET_OK if the message was well-formed
427 */
428static int
429check_address_list (void *cls,
430 const struct PeerInformationMessage *pi)
431{
432 const char *plugin_address;
433 const char *plugin_name;
434 uint16_t plugin_address_length;
435 uint16_t plugin_name_length;
436
437 plugin_address_length = ntohs (pi->address_length);
438 plugin_name_length = ntohs (pi->plugin_name_length);
439 plugin_address = (const char *) &pi[1];
440 plugin_name = &plugin_address[plugin_address_length];
441 if ((plugin_address_length + plugin_name_length
442 + sizeof(struct PeerInformationMessage) != ntohs (pi->header.size)) ||
443 (plugin_name[plugin_name_length - 1] != '\0'))
444 {
445 GNUNET_break (0);
446 return GNUNET_SYSERR;
447 }
448 return GNUNET_OK;
449}
450
451
452/**
453 * We received a #GNUNET_MESSAGE_TYPE_ATS_ADDRESSLIST_RESPONSE.
454 * Process it.
455 *
456 * @param cls our context with the callback
457 * @param pi the message
458 */
459static void
460handle_address_list (void *cls,
461 const struct PeerInformationMessage *pi)
462{
463 struct GNUNET_ATS_PerformanceHandle *ph = cls;
464 struct GNUNET_ATS_AddressListHandle *alh;
465 struct GNUNET_ATS_AddressListHandle *next;
466 const char *plugin_address;
467 const char *plugin_name;
468 struct GNUNET_HELLO_Address address;
469 struct GNUNET_PeerIdentity allzeros;
470 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_zero;
471 struct GNUNET_ATS_Properties prop;
472 uint16_t plugin_address_length;
473 uint16_t plugin_name_length;
474 uint32_t active;
475 uint32_t id;
476
477 id = ntohl (pi->id);
478 active = ntohl (pi->address_active);
479 plugin_address_length = ntohs (pi->address_length);
480 plugin_name_length = ntohs (pi->plugin_name_length);
481 plugin_address = (const char *) &pi[1];
482 plugin_name = &plugin_address[plugin_address_length];
483 LOG (GNUNET_ERROR_TYPE_DEBUG,
484 "Received ATS_ADDRESSLIST_RESPONSE message for peer %s and plugin %s\n",
485 GNUNET_i2s (&pi->peer),
486 plugin_name);
487
488 next = ph->addresslist_head;
489 while (NULL != (alh = next))
490 {
491 next = alh->next;
492 if (alh->id == id)
493 break;
494 }
495 if (NULL == alh)
496 return; /* was canceled */
497
498 memset (&allzeros, '\0', sizeof(allzeros));
499 if ((GNUNET_YES == GNUNET_is_zero (&pi->peer)) &&
500 (0 == plugin_name_length) &&
501 (0 == plugin_address_length))
502 {
503 /* Done */
504 LOG (GNUNET_ERROR_TYPE_DEBUG,
505 "Received last message for ATS_ADDRESSLIST_RESPONSE\n");
506 bandwidth_zero.value__ = htonl (0);
507 GNUNET_CONTAINER_DLL_remove (ph->addresslist_head,
508 ph->addresslist_tail,
509 alh);
510 if (NULL != alh->cb)
511 alh->cb (alh->cb_cls,
512 NULL,
513 GNUNET_NO,
514 bandwidth_zero,
515 bandwidth_zero,
516 NULL);
517 GNUNET_free (alh);
518 return;
519 }
520
521 address.peer = pi->peer;
522 address.address = plugin_address;
523 address.address_length = plugin_address_length;
524 address.transport_name = plugin_name;
525 if (((GNUNET_YES == alh->all_addresses) ||
526 (GNUNET_YES == active)) &&
527 (NULL != alh->cb))
528 {
529 GNUNET_ATS_properties_ntoh (&prop,
530 &pi->properties);
531 alh->cb (alh->cb_cls,
532 &address,
533 active,
534 pi->bandwidth_out,
535 pi->bandwidth_in,
536 &prop);
537 }
538}
539
540
541/**
542 * Generic error handler, called with the appropriate error code and
543 * the same closure specified at the creation of the message queue.
544 * Not every message queue implementation supports an error handler.
545 *
546 * @param cls closure with the `struct GNUNET_ATS_PerformanceHandle *`
547 * @param error error code
548 */
549static void
550mq_error_handler (void *cls,
551 enum GNUNET_MQ_Error error)
552{
553 struct GNUNET_ATS_PerformanceHandle *ph = cls;
554
555 do_reconnect (ph);
556}
557
558
559/**
560 * Re-establish the connection to the ATS service.
561 *
562 * @param ph handle to use to re-connect.
563 */
564static void
565reconnect (struct GNUNET_ATS_PerformanceHandle *ph)
566{
567 struct GNUNET_MQ_MessageHandler handlers[] = {
568 GNUNET_MQ_hd_var_size (peer_information,
569 GNUNET_MESSAGE_TYPE_ATS_PEER_INFORMATION,
570 struct PeerInformationMessage,
571 ph),
572 GNUNET_MQ_hd_fixed_size (reservation_result,
573 GNUNET_MESSAGE_TYPE_ATS_RESERVATION_RESULT,
574 struct ReservationResultMessage,
575 ph),
576 GNUNET_MQ_hd_var_size (address_list,
577 GNUNET_MESSAGE_TYPE_ATS_ADDRESSLIST_RESPONSE,
578 struct PeerInformationMessage,
579 ph),
580 GNUNET_MQ_handler_end ()
581 };
582 struct GNUNET_MQ_Envelope *env;
583 struct ClientStartMessage *init;
584
585 GNUNET_assert (NULL == ph->mq);
586 ph->mq = GNUNET_CLIENT_connect (ph->cfg,
587 "ats",
588 handlers,
589 &mq_error_handler,
590 ph);
591 if (NULL == ph->mq)
592 return;
593 env = GNUNET_MQ_msg (init,
594 GNUNET_MESSAGE_TYPE_ATS_START);
595 init->start_flag = htonl ((NULL == ph->addr_info_cb)
596 ? START_FLAG_PERFORMANCE_NO_PIC
597 : START_FLAG_PERFORMANCE_WITH_PIC);
598 GNUNET_MQ_send (ph->mq,
599 env);
600}
601
602
603/**
604 * Get handle to access performance API of the ATS subsystem.
605 *
606 * @param cfg configuration to use
607 * @param addr_info_cb callback called when performance characteristics for
608 * an address change
609 * @param addr_info_cb_cls closure for @a addr_info_cb
610 * @return ats performance context
611 */
612struct GNUNET_ATS_PerformanceHandle *
613GNUNET_ATS_performance_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
614 GNUNET_ATS_AddressInformationCallback addr_info_cb,
615 void *addr_info_cb_cls)
616{
617 struct GNUNET_ATS_PerformanceHandle *ph;
618
619 ph = GNUNET_new (struct GNUNET_ATS_PerformanceHandle);
620 ph->cfg = cfg;
621 ph->addr_info_cb = addr_info_cb;
622 ph->addr_info_cb_cls = addr_info_cb_cls;
623 reconnect (ph);
624 if (NULL == ph->mq)
625 {
626 GNUNET_free (ph);
627 return NULL;
628 }
629 return ph;
630}
631
632
633/**
634 * Client is done using the ATS performance subsystem, release resources.
635 *
636 * @param ph handle
637 */
638void
639GNUNET_ATS_performance_done (struct GNUNET_ATS_PerformanceHandle *ph)
640{
641 struct GNUNET_ATS_ReservationContext *rc;
642 struct GNUNET_ATS_AddressListHandle *alh;
643
644 while (NULL != (alh = ph->addresslist_head))
645 {
646 GNUNET_CONTAINER_DLL_remove (ph->addresslist_head,
647 ph->addresslist_tail,
648 alh);
649 GNUNET_free (alh);
650 }
651 while (NULL != (rc = ph->reservation_head))
652 {
653 GNUNET_CONTAINER_DLL_remove (ph->reservation_head,
654 ph->reservation_tail,
655 rc);
656 GNUNET_break (NULL == rc->rcb);
657 GNUNET_free (rc);
658 }
659 if (NULL != ph->task)
660 {
661 GNUNET_SCHEDULER_cancel (ph->task);
662 ph->task = NULL;
663 }
664 if (NULL != ph->mq)
665 {
666 GNUNET_MQ_destroy (ph->mq);
667 ph->mq = NULL;
668 }
669 GNUNET_free (ph);
670}
671
672
673struct GNUNET_ATS_ReservationContext *
674GNUNET_ATS_reserve_bandwidth (struct GNUNET_ATS_PerformanceHandle *ph,
675 const struct GNUNET_PeerIdentity *peer,
676 int32_t amount,
677 GNUNET_ATS_ReservationCallback rcb,
678 void *rcb_cls)
679{
680 struct GNUNET_ATS_ReservationContext *rc;
681 struct GNUNET_MQ_Envelope *env;
682 struct ReservationRequestMessage *m;
683
684 if (NULL == ph->mq)
685 return NULL;
686 rc = GNUNET_new (struct GNUNET_ATS_ReservationContext);
687 rc->size = amount;
688 rc->peer = *peer;
689 rc->rcb = rcb;
690 rc->rcb_cls = rcb_cls;
691 if ((NULL != rcb) &&
692 (amount > 0))
693 rc->undo = GNUNET_YES;
694 GNUNET_CONTAINER_DLL_insert_tail (ph->reservation_head,
695 ph->reservation_tail,
696 rc);
697 env = GNUNET_MQ_msg (m,
698 GNUNET_MESSAGE_TYPE_ATS_RESERVATION_REQUEST);
699 m->amount = htonl (amount);
700 m->peer = *peer;
701 GNUNET_MQ_send (ph->mq,
702 env);
703 return rc;
704}
705
706
707void
708GNUNET_ATS_reserve_bandwidth_cancel (struct GNUNET_ATS_ReservationContext *rc)
709{
710 rc->rcb = NULL;
711}
712
713
714struct GNUNET_ATS_AddressListHandle*
715GNUNET_ATS_performance_list_addresses (struct GNUNET_ATS_PerformanceHandle *ph,
716 const struct GNUNET_PeerIdentity *peer,
717 int all,
718 GNUNET_ATS_AddressInformationCallback
719 infocb,
720 void *infocb_cls)
721{
722 struct GNUNET_ATS_AddressListHandle *alh;
723 struct GNUNET_MQ_Envelope *env;
724 struct AddressListRequestMessage *m;
725
726 if (NULL == ph->mq)
727 return NULL;
728 if (NULL == infocb)
729 {
730 GNUNET_break (0);
731 return NULL;
732 }
733 alh = GNUNET_new (struct GNUNET_ATS_AddressListHandle);
734 alh->id = ph->id++;
735 alh->cb = infocb;
736 alh->cb_cls = infocb_cls;
737 alh->ph = ph;
738 alh->all_addresses = all;
739 if (NULL == peer)
740 {
741 alh->all_peers = GNUNET_YES;
742 }
743 else
744 {
745 alh->all_peers = GNUNET_NO;
746 alh->peer = *peer;
747 }
748 GNUNET_CONTAINER_DLL_insert (ph->addresslist_head,
749 ph->addresslist_tail,
750 alh);
751 env = GNUNET_MQ_msg (m,
752 GNUNET_MESSAGE_TYPE_ATS_ADDRESSLIST_REQUEST);
753 m->all = htonl (all);
754 m->id = htonl (alh->id);
755 if (NULL != peer)
756 m->peer = *peer;
757 GNUNET_MQ_send (ph->mq,
758 env);
759 return alh;
760}
761
762
763void
764GNUNET_ATS_performance_list_addresses_cancel (struct
765 GNUNET_ATS_AddressListHandle *alh)
766{
767 struct GNUNET_ATS_PerformanceHandle *ph = alh->ph;
768
769 GNUNET_CONTAINER_DLL_remove (ph->addresslist_head,
770 ph->addresslist_tail,
771 alh);
772 GNUNET_free (alh);
773}
774
775
776const char *
777GNUNET_ATS_print_preference_type (enum GNUNET_ATS_PreferenceKind type)
778{
779 const char *prefs[] = GNUNET_ATS_PreferenceTypeString;
780
781 if (type < GNUNET_ATS_PREFERENCE_END)
782 return prefs[type];
783 return NULL;
784}
785
786
787void
788GNUNET_ATS_performance_change_preference (struct
789 GNUNET_ATS_PerformanceHandle *ph,
790 const struct
791 GNUNET_PeerIdentity *peer,
792 ...)
793{
794 struct GNUNET_MQ_Envelope *env;
795 struct ChangePreferenceMessage *m;
796 uint32_t count;
797 struct PreferenceInformation *pi;
798 va_list ap;
799 enum GNUNET_ATS_PreferenceKind kind;
800
801 if (NULL == ph->mq)
802 return;
803 count = 0;
804 va_start (ap, peer);
805 while (GNUNET_ATS_PREFERENCE_END !=
806 (kind = GNUNET_VA_ARG_ENUM (ap, GNUNET_ATS_PreferenceKind)))
807 {
808 switch (kind)
809 {
810 case GNUNET_ATS_PREFERENCE_BANDWIDTH:
811 count++;
812 (void) va_arg (ap, double);
813 break;
814
815 case GNUNET_ATS_PREFERENCE_LATENCY:
816 count++;
817 (void) va_arg (ap, double);
818 break;
819
820 default:
821 GNUNET_assert (0);
822 }
823 }
824 va_end (ap);
825 env = GNUNET_MQ_msg_extra (m,
826 count * sizeof(struct PreferenceInformation),
827 GNUNET_MESSAGE_TYPE_ATS_PREFERENCE_CHANGE);
828 m->num_preferences = htonl (count);
829 m->peer = *peer;
830 pi = (struct PreferenceInformation *) &m[1];
831 count = 0;
832 va_start (ap, peer);
833 while (GNUNET_ATS_PREFERENCE_END != (kind =
834 GNUNET_VA_ARG_ENUM (ap,
835 GNUNET_ATS_PreferenceKind)))
836 {
837 pi[count].preference_kind = htonl (kind);
838 switch (kind)
839 {
840 case GNUNET_ATS_PREFERENCE_BANDWIDTH:
841 pi[count].preference_value = (float) va_arg (ap, double);
842
843 count++;
844 break;
845
846 case GNUNET_ATS_PREFERENCE_LATENCY:
847 pi[count].preference_value = (float) va_arg (ap, double);
848
849 count++;
850 break;
851
852 default:
853 GNUNET_assert (0);
854 }
855 }
856 va_end (ap);
857 GNUNET_MQ_send (ph->mq,
858 env);
859}
860
861
862/**
863 * Send feedback to ATS on how good a the requirements for a peer and a
864 * preference is satisfied by ATS
865 *
866 * @param ph performance handle
867 * @param scope the time interval this valid for: [now - scope .. now]
868 * @param peer identifies the peer
869 * @param ... #GNUNET_ATS_PREFERENCE_END-terminated specification of the desired changes
870 */
871void
872GNUNET_ATS_performance_give_feedback (struct GNUNET_ATS_PerformanceHandle *ph,
873 const struct GNUNET_PeerIdentity *peer,
874 const struct GNUNET_TIME_Relative scope,
875 ...)
876{
877 struct GNUNET_MQ_Envelope *env;
878 struct FeedbackPreferenceMessage *m;
879 uint32_t count;
880 struct PreferenceInformation *pi;
881 va_list ap;
882 enum GNUNET_ATS_PreferenceKind kind;
883
884 if (NULL == ph->mq)
885 return;
886 count = 0;
887 va_start (ap, scope);
888 while (GNUNET_ATS_PREFERENCE_END !=
889 (kind = GNUNET_VA_ARG_ENUM (ap, GNUNET_ATS_PreferenceKind)))
890 {
891 switch (kind)
892 {
893 case GNUNET_ATS_PREFERENCE_BANDWIDTH:
894 count++;
895 (void) va_arg (ap, double);
896 break;
897
898 case GNUNET_ATS_PREFERENCE_LATENCY:
899 count++;
900 (void) va_arg (ap, double);
901 break;
902
903 default:
904 GNUNET_assert (0);
905 }
906 }
907 va_end (ap);
908 env = GNUNET_MQ_msg_extra (m,
909 count * sizeof(struct PreferenceInformation),
910 GNUNET_MESSAGE_TYPE_ATS_PREFERENCE_FEEDBACK);
911 m->scope = GNUNET_TIME_relative_hton (scope);
912 m->num_feedback = htonl (count);
913 m->peer = *peer;
914 pi = (struct PreferenceInformation *) &m[1];
915 count = 0;
916 va_start (ap, scope);
917 while (GNUNET_ATS_PREFERENCE_END != (kind =
918 GNUNET_VA_ARG_ENUM (ap,
919 GNUNET_ATS_PreferenceKind)))
920 {
921 pi[count].preference_kind = htonl (kind);
922 switch (kind)
923 {
924 case GNUNET_ATS_PREFERENCE_BANDWIDTH:
925 pi[count].preference_value = (float) va_arg (ap, double);
926
927 count++;
928 break;
929
930 case GNUNET_ATS_PREFERENCE_LATENCY:
931 pi[count].preference_value = (float) va_arg (ap, double);
932
933 count++;
934 break;
935
936 default:
937 GNUNET_assert (0);
938 }
939 }
940 va_end (ap);
941 GNUNET_MQ_send (ph->mq,
942 env);
943}
944
945
946/* end of ats_api_performance.c */
diff --git a/src/ats/ats_api_scanner.c b/src/ats/ats_api_scanner.c
deleted file mode 100644
index 82114f888..000000000
--- a/src/ats/ats_api_scanner.c
+++ /dev/null
@@ -1,65 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010-2015 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file ats/ats_api_scanner.c
22 * @brief LAN interface scanning to determine IPs in LAN
23 * @author Christian Grothoff
24 * @author Matthias Wachs
25 */
26#include "platform.h"
27#include "gnunet_ats_service.h"
28
29/**
30 * Convert ATS properties from host to network byte order.
31 *
32 * @param nbo[OUT] value written
33 * @param hbo value read
34 */
35void
36GNUNET_ATS_properties_hton (struct GNUNET_ATS_PropertiesNBO *nbo,
37 const struct GNUNET_ATS_Properties *hbo)
38{
39 nbo->utilization_out = htonl (hbo->utilization_out);
40 nbo->utilization_in = htonl (hbo->utilization_in);
41 nbo->scope = htonl ((uint32_t) hbo->scope);
42 nbo->distance = htonl (hbo->distance);
43 nbo->delay = GNUNET_TIME_relative_hton (hbo->delay);
44}
45
46
47/**
48 * Convert ATS properties from network to host byte order.
49 *
50 * @param hbo[OUT] value written
51 * @param nbo value read
52 */
53void
54GNUNET_ATS_properties_ntoh (struct GNUNET_ATS_Properties *hbo,
55 const struct GNUNET_ATS_PropertiesNBO *nbo)
56{
57 hbo->utilization_out = ntohl (nbo->utilization_out);
58 hbo->utilization_in = ntohl (nbo->utilization_in);
59 hbo->scope = ntohl ((uint32_t) nbo->scope);
60 hbo->distance = ntohl (nbo->distance);
61 hbo->delay = GNUNET_TIME_relative_ntoh (nbo->delay);
62}
63
64
65/* end of ats_api_scanner.c */
diff --git a/src/ats/ats_api_scheduling.c b/src/ats/ats_api_scheduling.c
deleted file mode 100644
index 6fb61b2e8..000000000
--- a/src/ats/ats_api_scheduling.c
+++ /dev/null
@@ -1,781 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010-2015 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file ats/ats_api_scheduling.c
22 * @brief automatic transport selection and outbound bandwidth determination
23 * @author Christian Grothoff
24 * @author Matthias Wachs
25 *
26 * TODO:
27 * - we could avoid a linear scan over the
28 * active addresses in some cases, so if
29 * there is need, we can still optimize here
30 * - we might want to split off the logic to
31 * determine LAN vs. WAN, as it has nothing
32 * to do with accessing the ATS service.
33 */
34#include "platform.h"
35#include "gnunet_ats_service.h"
36#include "ats.h"
37
38/**
39 * How frequently do we scan the interfaces for changes to the addresses?
40 */
41#define INTERFACE_PROCESSING_INTERVAL GNUNET_TIME_relative_multiply ( \
42 GNUNET_TIME_UNIT_MINUTES, 2)
43
44#define LOG(kind, ...) GNUNET_log_from (kind, "ats-scheduling-api", __VA_ARGS__)
45
46/**
47 * Session ID we use if there is no session / slot.
48 */
49#define NOT_FOUND 0
50
51
52/**
53 * Information we track per address, incoming or outgoing. It also
54 * doesn't matter if we have a session, any address that ATS is
55 * allowed to suggest right now should be tracked.
56 */
57struct GNUNET_ATS_AddressRecord
58{
59 /**
60 * Scheduling handle this address record belongs to.
61 */
62 struct GNUNET_ATS_SchedulingHandle *sh;
63
64 /**
65 * Address data.
66 */
67 struct GNUNET_HELLO_Address *address;
68
69 /**
70 * Session handle. NULL if we have an address but no
71 * active session for this address.
72 */
73 struct GNUNET_ATS_Session *session;
74
75 /**
76 * Performance data about the address.
77 */
78 struct GNUNET_ATS_PropertiesNBO properties;
79
80 /**
81 * Which slot (index) in the session array does
82 * this record correspond to?
83 * FIXME: a linear search on this is really crappy!
84 * Maybe switch to a 64-bit global counter and be
85 * done with it? Or does that then cause too much
86 * trouble on the ATS-service side?
87 */
88 uint32_t slot;
89
90 /**
91 * We're about to destroy this address record, just ATS does
92 * not know this yet. Once ATS confirms its destruction,
93 * we can clean up.
94 */
95 int in_destroy;
96};
97
98
99/**
100 * Handle to the ATS subsystem for bandwidth/transport scheduling information.
101 */
102struct GNUNET_ATS_SchedulingHandle
103{
104 /**
105 * Our configuration.
106 */
107 const struct GNUNET_CONFIGURATION_Handle *cfg;
108
109 /**
110 * Callback to invoke on suggestions.
111 */
112 GNUNET_ATS_AddressSuggestionCallback suggest_cb;
113
114 /**
115 * Closure for @e suggest_cb.
116 */
117 void *suggest_cb_cls;
118
119 /**
120 * Message queue for sending requests to the ATS service.
121 */
122 struct GNUNET_MQ_Handle *mq;
123
124 /**
125 * Array of session objects (we need to translate them to numbers and back
126 * for the protocol; the offset in the array is the session number on the
127 * network). Index 0 is always NULL and reserved to represent the NULL pointer.
128 * Unused entries are also NULL.
129 */
130 struct GNUNET_ATS_AddressRecord **session_array;
131
132 /**
133 * Task to trigger reconnect.
134 */
135 struct GNUNET_SCHEDULER_Task *task;
136
137 /**
138 * Reconnect backoff delay.
139 */
140 struct GNUNET_TIME_Relative backoff;
141
142 /**
143 * Size of the @e session_array.
144 */
145 unsigned int session_array_size;
146};
147
148
149/**
150 * Re-establish the connection to the ATS service.
151 *
152 * @param sh handle to use to re-connect.
153 */
154static void
155reconnect (struct GNUNET_ATS_SchedulingHandle *sh);
156
157
158/**
159 * Re-establish the connection to the ATS service.
160 *
161 * @param cls handle to use to re-connect.
162 */
163static void
164reconnect_task (void *cls)
165{
166 struct GNUNET_ATS_SchedulingHandle *sh = cls;
167
168 sh->task = NULL;
169 reconnect (sh);
170}
171
172
173/**
174 * Disconnect from ATS and then reconnect.
175 *
176 * @param sh our handle
177 */
178static void
179force_reconnect (struct GNUNET_ATS_SchedulingHandle *sh)
180{
181 if (NULL != sh->mq)
182 {
183 GNUNET_MQ_destroy (sh->mq);
184 sh->mq = NULL;
185 }
186 sh->suggest_cb (sh->suggest_cb_cls,
187 NULL, NULL, NULL,
188 GNUNET_BANDWIDTH_ZERO,
189 GNUNET_BANDWIDTH_ZERO);
190 sh->backoff = GNUNET_TIME_STD_BACKOFF (sh->backoff);
191 sh->task = GNUNET_SCHEDULER_add_delayed (sh->backoff,
192 &reconnect_task,
193 sh);
194}
195
196
197/**
198 * Find the session object corresponding to the given session ID.
199 *
200 * @param sh our handle
201 * @param session_id current session ID
202 * @param peer peer the session belongs to
203 * @return the session object (or NULL)
204 */
205static struct GNUNET_ATS_AddressRecord *
206find_session (struct GNUNET_ATS_SchedulingHandle *sh,
207 uint32_t session_id,
208 const struct GNUNET_PeerIdentity *peer)
209{
210 struct GNUNET_ATS_AddressRecord *ar;
211
212 if (session_id >= sh->session_array_size)
213 {
214 GNUNET_break (0);
215 return NULL;
216 }
217 if (0 == session_id)
218 return NULL;
219 ar = sh->session_array[session_id];
220 if (NULL == ar)
221 {
222 GNUNET_break (0);
223 return NULL;
224 }
225 if (NULL == ar->address)
226 {
227 /* address was destroyed in the meantime, this can happen
228 as we communicate asynchronously with the ATS service. */
229 return NULL;
230 }
231 if (0 != GNUNET_memcmp (peer,
232 &ar->address->peer))
233 {
234 GNUNET_break (0);
235 return NULL;
236 }
237 return ar;
238}
239
240
241/**
242 * Get an available session ID.
243 *
244 * @param sh our handle
245 * @return an unused slot, but never NOT_FOUND (0)
246 */
247static uint32_t
248find_empty_session_slot (struct GNUNET_ATS_SchedulingHandle *sh)
249{
250 static uint32_t off;
251 uint32_t i;
252
253 GNUNET_assert (0 != sh->session_array_size);
254 i = 0;
255 while (((NOT_FOUND == off) ||
256 (NULL != sh->session_array[off % sh->session_array_size])) &&
257 (i < sh->session_array_size))
258 {
259 off++;
260 i++;
261 }
262 if ((NOT_FOUND != off % sh->session_array_size) &&
263 (NULL == sh->session_array[off % sh->session_array_size]))
264 return off;
265 i = sh->session_array_size;
266 GNUNET_array_grow (sh->session_array,
267 sh->session_array_size,
268 sh->session_array_size * 2);
269 return i;
270}
271
272
273/**
274 * Get the ID for the given session object.
275 *
276 * @param sh our handle
277 * @param session session object
278 * @param address the address we are looking for
279 * @return the session id or NOT_FOUND for error
280 */
281static uint32_t
282find_session_id (struct GNUNET_ATS_SchedulingHandle *sh,
283 struct GNUNET_ATS_Session *session,
284 const struct GNUNET_HELLO_Address *address)
285{
286 uint32_t i;
287
288 if (NULL == address)
289 {
290 GNUNET_break (0);
291 return NOT_FOUND;
292 }
293 for (i = 1; i < sh->session_array_size; i++)
294 if ((NULL != sh->session_array[i]) &&
295 (GNUNET_NO == sh->session_array[i]->in_destroy) &&
296 ((session == sh->session_array[i]->session) ||
297 (NULL == sh->session_array[i]->session)) &&
298 (0 == GNUNET_memcmp (&address->peer,
299 &sh->session_array[i]->address->peer)) &&
300 (0 == GNUNET_HELLO_address_cmp (address,
301 sh->session_array[i]->address)))
302 return i;
303 return NOT_FOUND;
304}
305
306
307/**
308 * Release the session slot from the session table (ATS service is
309 * also done using it).
310 *
311 * @param sh our handle
312 * @param session_id identifies session that is no longer valid
313 */
314static void
315release_session (struct GNUNET_ATS_SchedulingHandle *sh,
316 uint32_t session_id)
317{
318 struct GNUNET_ATS_AddressRecord *ar;
319
320 if (NOT_FOUND == session_id)
321 return;
322 if (session_id >= sh->session_array_size)
323 {
324 GNUNET_break (0);
325 force_reconnect (sh);
326 return;
327 }
328 /* this slot should have been removed from remove_session before */
329 ar = sh->session_array[session_id];
330 if (NULL != ar->session)
331 {
332 GNUNET_break (0);
333 force_reconnect (sh);
334 return;
335 }
336 GNUNET_HELLO_address_free (ar->address);
337 GNUNET_free (ar);
338 sh->session_array[session_id] = NULL;
339}
340
341
342/**
343 * Type of a function to call when we receive a session release
344 * message from the service.
345 *
346 * @param cls the `struct GNUNET_ATS_SchedulingHandle`
347 * @param srm message received
348 */
349static void
350handle_ats_session_release (void *cls,
351 const struct GNUNET_ATS_SessionReleaseMessage *srm)
352{
353 struct GNUNET_ATS_SchedulingHandle *sh = cls;
354
355 /* Note: peer field in srm not necessary right now,
356 but might be good to have in the future */
357 release_session (sh,
358 ntohl (srm->session_id));
359}
360
361
362/**
363 * Type of a function to call when we receive a address suggestion
364 * message from the service.
365 *
366 * @param cls the `struct GNUNET_ATS_SchedulingHandle`
367 * @param m message received
368 */
369static void
370handle_ats_address_suggestion (void *cls,
371 const struct AddressSuggestionMessage *m)
372{
373 struct GNUNET_ATS_SchedulingHandle *sh = cls;
374 struct GNUNET_ATS_AddressRecord *ar;
375 uint32_t session_id;
376
377 session_id = ntohl (m->session_id);
378 if (0 == session_id)
379 {
380 GNUNET_break (0);
381 force_reconnect (sh);
382 return;
383 }
384 ar = find_session (sh,
385 session_id,
386 &m->peer);
387 if (NULL == ar)
388 {
389 GNUNET_break (0);
390 force_reconnect (sh);
391 return;
392 }
393 if (NULL == sh->suggest_cb)
394 return;
395 if (GNUNET_YES == ar->in_destroy)
396 {
397 /* ignore suggestion, as this address is dying, unless BW is 0,
398 in that case signal 'disconnect' via BW 0 */
399 if ((0 == ntohl (m->bandwidth_out.value__)) &&
400 (0 == ntohl (m->bandwidth_in.value__)))
401 {
402 LOG (GNUNET_ERROR_TYPE_DEBUG,
403 "ATS suggests disconnect from peer `%s' with BW %u/%u\n",
404 GNUNET_i2s (&ar->address->peer),
405 (unsigned int) ntohl (m->bandwidth_out.value__),
406 (unsigned int) ntohl (m->bandwidth_in.value__));
407 sh->suggest_cb (sh->suggest_cb_cls,
408 &m->peer,
409 NULL,
410 NULL,
411 m->bandwidth_out,
412 m->bandwidth_in);
413 }
414 return;
415 }
416 if ((NULL == ar->session) &&
417 (GNUNET_HELLO_address_check_option (ar->address,
418 GNUNET_HELLO_ADDRESS_INFO_INBOUND)))
419 {
420 GNUNET_break (0);
421 return;
422 }
423 sh->backoff = GNUNET_TIME_UNIT_ZERO;
424 LOG (GNUNET_ERROR_TYPE_DEBUG,
425 "ATS suggests address slot %u for peer `%s' using plugin %s\n",
426 ar->slot,
427 GNUNET_i2s (&ar->address->peer),
428 ar->address->transport_name);
429 sh->suggest_cb (sh->suggest_cb_cls,
430 &m->peer,
431 ar->address,
432 ar->session,
433 m->bandwidth_out,
434 m->bandwidth_in);
435}
436
437
438/**
439 * We encountered an error handling the MQ to the
440 * ATS service. Reconnect.
441 *
442 * @param cls the `struct GNUNET_ATS_SchedulingHandle`
443 * @param error details about the error
444 */
445static void
446error_handler (void *cls,
447 enum GNUNET_MQ_Error error)
448{
449 struct GNUNET_ATS_SchedulingHandle *sh = cls;
450
451 LOG (GNUNET_ERROR_TYPE_DEBUG,
452 "ATS connection died (code %d), reconnecting\n",
453 (int) error);
454 force_reconnect (sh);
455}
456
457
458/**
459 * Generate and transmit the `struct AddressAddMessage` for the given
460 * address record.
461 *
462 * @param sh the scheduling handle to use for transmission
463 * @param ar the address to inform the ATS service about
464 */
465static void
466send_add_address_message (struct GNUNET_ATS_SchedulingHandle *sh,
467 const struct GNUNET_ATS_AddressRecord *ar)
468{
469 struct GNUNET_MQ_Envelope *ev;
470 struct AddressAddMessage *m;
471 char *pm;
472 size_t namelen;
473 size_t msize;
474
475 if (NULL == sh->mq)
476 return; /* disconnected, skip for now */
477 GNUNET_break (GNUNET_NT_UNSPECIFIED != ar->properties.scope);
478 namelen = strlen (ar->address->transport_name) + 1;
479 msize = ar->address->address_length + namelen;
480 ev = GNUNET_MQ_msg_extra (m, msize, GNUNET_MESSAGE_TYPE_ATS_ADDRESS_ADD);
481 m->peer = ar->address->peer;
482 m->address_length = htons (ar->address->address_length);
483 m->address_local_info = htonl ((uint32_t) ar->address->local_info);
484 m->plugin_name_length = htons (namelen);
485 m->session_id = htonl (ar->slot);
486 m->properties = ar->properties;
487
488 LOG (GNUNET_ERROR_TYPE_DEBUG,
489 "Adding address for peer `%s', plugin `%s', session %p slot %u\n",
490 GNUNET_i2s (&ar->address->peer),
491 ar->address->transport_name,
492 ar->session,
493 ar->slot);
494 pm = (char *) &m[1];
495 GNUNET_memcpy (pm,
496 ar->address->address,
497 ar->address->address_length);
498 if (NULL != ar->address->transport_name)
499 GNUNET_memcpy (&pm[ar->address->address_length],
500 ar->address->transport_name,
501 namelen);
502 GNUNET_MQ_send (sh->mq, ev);
503}
504
505
506/**
507 * Re-establish the connection to the ATS service.
508 *
509 * @param sh handle to use to re-connect.
510 */
511static void
512reconnect (struct GNUNET_ATS_SchedulingHandle *sh)
513{
514 struct GNUNET_MQ_MessageHandler handlers[] = {
515 GNUNET_MQ_hd_fixed_size (ats_session_release,
516 GNUNET_MESSAGE_TYPE_ATS_SESSION_RELEASE,
517 struct GNUNET_ATS_SessionReleaseMessage,
518 sh),
519 GNUNET_MQ_hd_fixed_size (ats_address_suggestion,
520 GNUNET_MESSAGE_TYPE_ATS_ADDRESS_SUGGESTION,
521 struct AddressSuggestionMessage,
522 sh),
523 GNUNET_MQ_handler_end ()
524 };
525 struct GNUNET_MQ_Envelope *ev;
526 struct ClientStartMessage *init;
527 unsigned int i;
528 struct GNUNET_ATS_AddressRecord *ar;
529
530 GNUNET_assert (NULL == sh->mq);
531 sh->mq = GNUNET_CLIENT_connect (sh->cfg,
532 "ats",
533 handlers,
534 &error_handler,
535 sh);
536 if (NULL == sh->mq)
537 {
538 GNUNET_break (0);
539 force_reconnect (sh);
540 return;
541 }
542 ev = GNUNET_MQ_msg (init,
543 GNUNET_MESSAGE_TYPE_ATS_START);
544 init->start_flag = htonl (START_FLAG_SCHEDULING);
545 GNUNET_MQ_send (sh->mq, ev);
546 if (NULL == sh->mq)
547 return;
548 for (i = 0; i < sh->session_array_size; i++)
549 {
550 ar = sh->session_array[i];
551 if (NULL == ar)
552 continue;
553 send_add_address_message (sh, ar);
554 if (NULL == sh->mq)
555 return;
556 }
557}
558
559
560struct GNUNET_ATS_SchedulingHandle *
561GNUNET_ATS_scheduling_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
562 GNUNET_ATS_AddressSuggestionCallback suggest_cb,
563 void *suggest_cb_cls)
564{
565 struct GNUNET_ATS_SchedulingHandle *sh;
566
567 sh = GNUNET_new (struct GNUNET_ATS_SchedulingHandle);
568 sh->cfg = cfg;
569 sh->suggest_cb = suggest_cb;
570 sh->suggest_cb_cls = suggest_cb_cls;
571 GNUNET_array_grow (sh->session_array,
572 sh->session_array_size,
573 4);
574 reconnect (sh);
575 return sh;
576}
577
578
579/**
580 * Client is done with ATS scheduling, release resources.
581 *
582 * @param sh handle to release
583 */
584void
585GNUNET_ATS_scheduling_done (struct GNUNET_ATS_SchedulingHandle *sh)
586{
587 struct GNUNET_ATS_AddressRecord *ar;
588 unsigned int i;
589
590 if (NULL != sh->mq)
591 {
592 GNUNET_MQ_destroy (sh->mq);
593 sh->mq = NULL;
594 }
595 if (NULL != sh->task)
596 {
597 GNUNET_SCHEDULER_cancel (sh->task);
598 sh->task = NULL;
599 }
600 for (i = 0; i < sh->session_array_size; i++)
601 {
602 if (NULL != (ar = sh->session_array[i]))
603 {
604 GNUNET_HELLO_address_free (ar->address);
605 GNUNET_free (ar);
606 sh->session_array[i] = NULL;
607 }
608 }
609 GNUNET_array_grow (sh->session_array,
610 sh->session_array_size,
611 0);
612 GNUNET_free (sh);
613}
614
615
616/**
617 * We have a new address ATS should know. Addresses have to be added
618 * with this function before they can be: updated, set in use and
619 * destroyed.
620 *
621 * @param sh handle
622 * @param address the address
623 * @param session session handle, can be NULL
624 * @param prop performance data for the address
625 * @return handle to the address representation inside ATS, NULL
626 * on error (i.e. ATS knows this exact address already)
627 */
628struct GNUNET_ATS_AddressRecord *
629GNUNET_ATS_address_add (struct GNUNET_ATS_SchedulingHandle *sh,
630 const struct GNUNET_HELLO_Address *address,
631 struct GNUNET_ATS_Session *session,
632 const struct GNUNET_ATS_Properties *prop)
633{
634 struct GNUNET_ATS_AddressRecord *ar;
635 size_t namelen;
636 size_t msize;
637 uint32_t s;
638
639 if (NULL == address)
640 {
641 /* we need a valid address */
642 GNUNET_break (0);
643 return NULL;
644 }
645 GNUNET_break (GNUNET_NT_UNSPECIFIED != prop->scope);
646 namelen = strlen (address->transport_name) + 1;
647 msize = address->address_length + namelen;
648 if ((msize + sizeof(struct AddressUpdateMessage) >=
649 GNUNET_MAX_MESSAGE_SIZE) ||
650 (address->address_length >= GNUNET_MAX_MESSAGE_SIZE) ||
651 (namelen >= GNUNET_MAX_MESSAGE_SIZE))
652 {
653 /* address too large for us, this should not happen */
654 GNUNET_break (0);
655 return NULL;
656 }
657
658 if (NOT_FOUND !=
659 find_session_id (sh,
660 session,
661 address))
662 {
663 /* Already existing, nothing todo, but this should not happen */
664 GNUNET_break (0);
665 return NULL;
666 }
667 s = find_empty_session_slot (sh);
668 ar = GNUNET_new (struct GNUNET_ATS_AddressRecord);
669 ar->sh = sh;
670 ar->slot = s;
671 ar->session = session;
672 ar->address = GNUNET_HELLO_address_copy (address);
673 GNUNET_ATS_properties_hton (&ar->properties,
674 prop);
675 sh->session_array[s] = ar;
676 send_add_address_message (sh, ar);
677 return ar;
678}
679
680
681/**
682 * An address was used to initiate a session.
683 *
684 * @param ar address record to update information for
685 * @param session session handle
686 */
687void
688GNUNET_ATS_address_add_session (struct GNUNET_ATS_AddressRecord *ar,
689 struct GNUNET_ATS_Session *session)
690{
691 GNUNET_break (NULL == ar->session);
692 ar->session = session;
693}
694
695
696int
697GNUNET_ATS_address_del_session (struct GNUNET_ATS_AddressRecord *ar,
698 struct GNUNET_ATS_Session *session)
699{
700 GNUNET_assert (session == ar->session);
701 ar->session = NULL;
702 if (GNUNET_HELLO_address_check_option (ar->address,
703 GNUNET_HELLO_ADDRESS_INFO_INBOUND))
704 {
705 GNUNET_ATS_address_destroy (ar);
706 return GNUNET_YES;
707 }
708 return GNUNET_NO;
709}
710
711
712/**
713 * We have updated performance statistics for a given address. Note
714 * that this function can be called for addresses that are currently
715 * in use as well as addresses that are valid but not actively in use.
716 * Furthermore, the peer may not even be connected to us right now (in
717 * which case the call may be ignored or the information may be stored
718 * for later use). Update bandwidth assignments.
719 *
720 * @param ar address record to update information for
721 * @param prop performance data for the address
722 */
723void
724GNUNET_ATS_address_update (struct GNUNET_ATS_AddressRecord *ar,
725 const struct GNUNET_ATS_Properties *prop)
726{
727 struct GNUNET_ATS_SchedulingHandle *sh = ar->sh;
728 struct GNUNET_MQ_Envelope *ev;
729 struct AddressUpdateMessage *m;
730
731 LOG (GNUNET_ERROR_TYPE_DEBUG,
732 "Updating address for peer `%s', plugin `%s', session %p slot %u\n",
733 GNUNET_i2s (&ar->address->peer),
734 ar->address->transport_name,
735 ar->session,
736 ar->slot);
737 GNUNET_break (GNUNET_NT_UNSPECIFIED != prop->scope);
738 GNUNET_ATS_properties_hton (&ar->properties,
739 prop);
740 if (NULL == sh->mq)
741 return; /* disconnected, skip for now */
742 ev = GNUNET_MQ_msg (m, GNUNET_MESSAGE_TYPE_ATS_ADDRESS_UPDATE);
743 m->session_id = htonl (ar->slot);
744 m->peer = ar->address->peer;
745 m->properties = ar->properties;
746 GNUNET_MQ_send (sh->mq,
747 ev);
748}
749
750
751/**
752 * An address got destroyed, stop using it as a valid address.
753 *
754 * @param ar address to destroy
755 */
756void
757GNUNET_ATS_address_destroy (struct GNUNET_ATS_AddressRecord *ar)
758{
759 struct GNUNET_ATS_SchedulingHandle *sh = ar->sh;
760 struct GNUNET_MQ_Envelope *ev;
761 struct AddressDestroyedMessage *m;
762
763 LOG (GNUNET_ERROR_TYPE_DEBUG,
764 "Deleting address for peer `%s', plugin `%s', slot %u session %p\n",
765 GNUNET_i2s (&ar->address->peer),
766 ar->address->transport_name,
767 ar->slot,
768 ar->session);
769 GNUNET_break (NULL == ar->session);
770 ar->session = NULL;
771 ar->in_destroy = GNUNET_YES;
772 if (NULL == sh->mq)
773 return;
774 ev = GNUNET_MQ_msg (m, GNUNET_MESSAGE_TYPE_ATS_ADDRESS_DESTROYED);
775 m->session_id = htonl (ar->slot);
776 m->peer = ar->address->peer;
777 GNUNET_MQ_send (sh->mq, ev);
778}
779
780
781/* end of ats_api_scheduling.c */
diff --git a/src/ats/experiments/example.exp b/src/ats/experiments/example.exp
deleted file mode 100644
index a490e5ec6..000000000
--- a/src/ats/experiments/example.exp
+++ /dev/null
@@ -1,104 +0,0 @@
1[experiment]
2name = test
3max_duration = 15 s
4log_freq = 1000 ms
5cfg_file = experiments/gnunet_ats_sim_default.conf
6log_output_dir = data/
7log_append_time_stamp = no
8
9[episode-0]
10# Setup addresses
11
12# operations = address_add, address_del, start_set_property, stop_set_property,
13# start_set_preference, stop_preference, start_request, stop_request
14duration = 0
15op-0-operation = address_add
16op-0-address-id = 0
17op-0-peer-id = 0
18op-0-address-session = 0
19op-0-address-network = 0
20op-0-address = 0_0_test
21op-0-plugin = test
22
23op-1-operation = address_add
24op-1-address-id = 1
25op-1-peer-id = 1
26op-1-address-session = 0
27op-1-address-network = 0
28op-1-address = 1_1_test
29op-1-plugin = test
30
31op-2-operation = start_request
32op-2-peer-id = 0
33
34op-3-operation = start_request
35op-3-peer-id = 1
36
37[episode-1]
38# Set delay
39duration = 5 s
40
41op-0-operation = start_set_property
42op-0-address-id = 0
43op-0-peer-id = 0
44# constant, linear, sinus, random
45op-0-gen-type = random
46op-0-base-rate= 10000
47op-0-max-rate = 20000
48op-0-frequency = 1000 ms
49# bandwidth, latency
50# "TERMINATOR", "UTILIZATION_UP", "UTILIZATION_DOWN", "UTILIZATION_PAYLOAD_UP", "UTILIZATION_PAYLOAD_DOWN", "NETWORK_TYPE", "DELAY", "DISTANCE", "COST_WAN", "COST_LAN", "COST_WLAN"
51op-0-property = DELAY
52
53op-1-operation = start_set_property
54op-1-address-id = 1
55op-1-peer-id = 1
56# constant, linear, sinus, random
57op-1-gen-type = constant
58op-1-base-rate= 1
59op-1-max-rate = 1
60op-1-frequency = 1000 ms
61# bandwidth, latency
62# "TERMINATOR", "UTILIZATION_UP", "UTILIZATION_DOWN", "UTILIZATION_PAYLOAD_UP", "UTILIZATION_PAYLOAD_DOWN", "NETWORK_TYPE", "DELAY", "DISTANCE", "COST_WAN", "COST_LAN", "COST_WLAN"
63op-1-property = DELAY
64
65
66[episode-2]
67# Shutdown
68duration = 2 s
69op-0-operation = stop_set_property
70op-0-address-id = 0
71op-0-peer-id = 0
72op-0-property = DELAY
73
74op-1-operation = stop_set_property
75op-1-address-id = 1
76op-1-peer-id = 1
77op-1-property = DELAY
78
79[episode-3]
80# Shutdown
81duration = 2 s
82
83op-0-operation = stop_request
84op-0-peer-id = 0
85
86op-1-operation = stop_request
87op-1-peer-id = 1
88
89op-2-operation = address_del
90op-2-address-id = 0
91op-2-peer-id = 0
92op-2-address-session = 0
93op-2-address-network = 0
94op-2-address = 0_0_test
95op-2-plugin = test
96
97op-2-operation = address_del
98op-2-address-id = 1
99op-2-peer-id = 1
100op-2-address-session = 0
101op-2-address-network = 0
102op-2-address = 1_1_test
103op-2-plugin = test
104
diff --git a/src/ats/experiments/gnunet_ats_sim_default.conf b/src/ats/experiments/gnunet_ats_sim_default.conf
deleted file mode 100644
index 14e0a2e0b..000000000
--- a/src/ats/experiments/gnunet_ats_sim_default.conf
+++ /dev/null
@@ -1,18 +0,0 @@
1[ats]
2UNSPECIFIED_QUOTA_IN = 64 KiB
3UNSPECIFIED_QUOTA_OUT = 64 KiB
4# LOOPBACK
5LOOPBACK_QUOTA_IN = 64 KiB
6LOOPBACK_QUOTA_OUT = 64 KiB
7# LAN
8LAN_QUOTA_IN = 64 KiB
9LAN_QUOTA_OUT = 64 KiB
10# WAN
11WAN_QUOTA_IN = 64 KiB
12WAN_QUOTA_OUT = 64 KiB
13# WLAN
14WLAN_QUOTA_IN = 64 KiB
15WLAN_QUOTA_OUT = 64 KiB
16# BLUETOOTH
17BLUETOOTH_QUOTA_IN = 64 KiB
18BLUETOOTH_QUOTA_OUT = 64 KiB
diff --git a/src/ats/experiments/set_preference.exp b/src/ats/experiments/set_preference.exp
deleted file mode 100644
index 34f9af296..000000000
--- a/src/ats/experiments/set_preference.exp
+++ /dev/null
@@ -1,95 +0,0 @@
1# Example setting up two peers
2
3[experiment]
4name = test
5max_duration = 15 s
6log_freq = 1000 ms
7log_prefix = set_preference
8cfg_file = experiments/gnunet_ats_sim_default.conf
9
10[episode-0]
11# Setup addresses
12
13# operations = address_add, address_del, start_set_property, stop_set_property,
14# start_set_preference, stop_preference, start_request, stop_request
15duration = 1 s
16
17op-0-operation = address_add
18op-0-address-id = 0
19op-0-peer-id = 0
20op-0-address-session = 0
21op-0-address-network = lan
22op-0-address = 0_0_test
23op-0-plugin = test
24
25op-1-operation = address_add
26op-1-address-id = 1
27op-1-peer-id = 1
28op-1-address-session = 0
29op-1-address-network = lan
30op-1-address = 1_1_test
31op-1-plugin = test
32
33op-2-operation = start_request
34op-2-peer-id = 0
35
36op-3-operation = start_request
37op-3-peer-id = 1
38
39[episode-1]
40# Set delay
41duration = 20 s
42
43op-0-operation = start_set_preference
44op-0-address-id = 0
45op-0-peer-id = 0
46op-0-client-id = 1
47# constant, linear, sinus, random
48op-0-gen-type = linear
49op-0-base-rate= 1000
50op-0-max-rate = 10000
51op-0-period = 10 s
52op-0-frequency = 500 ms
53op-0-feedback_delay = 500 ms
54# BANDWIDTH, LATENCY
55op-0-pref = BANDWIDTH
56
57
58op-1-operation = start_set_preference
59op-1-address-id = 1
60op-1-peer-id = 1
61op-1-client-id = 1
62# constant, linear, sinus, random
63op-1-gen-type = constant
64op-1-base-rate= 1000
65op-1-max-rate = 1000
66op-1-period = 10 s
67op-1-frequency = 500 ms
68# BANDWIDTH, LATENCY
69op-1-pref = BANDWIDTH
70
71[episode-2]
72# Shutdown
73duration = 2 s
74
75op-0-operation = stop_request
76op-0-peer-id = 0
77
78op-1-operation = stop_request
79op-1-peer-id = 1
80
81op-2-operation = address_del
82op-2-address-id = 0
83op-2-peer-id = 0
84op-2-address-session = 0
85op-2-address-network = 0
86op-2-address = 0_0_test
87op-2-plugin = test
88
89op-3-operation = address_del
90op-3-address-id = 1
91op-3-peer-id = 1
92op-3-address-session = 0
93op-3-address-network = 0
94op-3-address = 1_1_test
95op-3-plugin = test
diff --git a/src/ats/gnunet-ats-solver-eval.c b/src/ats/gnunet-ats-solver-eval.c
deleted file mode 100644
index ba7994686..000000000
--- a/src/ats/gnunet-ats-solver-eval.c
+++ /dev/null
@@ -1,3588 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010-2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file ats-tests/ats-testing-experiment.c
22 * @brief ats benchmark: controlled experiment execution
23 * @author Christian Grothoff
24 * @author Matthias Wachs
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet-ats-solver-eval.h"
29#include "gnunet-service-ats_normalization.h"
30#include "gnunet-service-ats_preferences.c"
31
32#define BIG_M_STRING "unlimited"
33
34/**
35 * Handle for statistics.
36 */
37struct GNUNET_STATISTICS_Handle *GSA_stats;
38
39
40static struct Experiment *e;
41
42static struct LoggingHandle *l;
43
44static struct SolverHandle *sh;
45
46static struct TestPeer *peer_head;
47
48static struct TestPeer *peer_tail;
49
50static double default_properties[GNUNET_ATS_PropertyCount];
51static double default_preferences[GNUNET_ATS_PreferenceCount];
52
53/**
54 * cmd option -e: experiment file
55 */
56static char *opt_exp_file;
57
58static char *opt_solver;
59
60/**
61 * cmd option -l: enable logging
62 */
63static int opt_log;
64
65/**
66 * cmd option -p: enable plots
67 */
68static int opt_save;
69
70/**
71 * cmd option -v: verbose logs
72 */
73static int opt_verbose;
74
75/**
76 * cmd option -p: print logs
77 */
78static int opt_print;
79
80/**
81 * cmd option -d: disable normalization
82 */
83static int opt_disable_normalization;
84
85static int res;
86
87static void
88end_now ();
89
90
91static char *
92print_generator_type (enum GeneratorType g)
93{
94 switch (g)
95 {
96 case GNUNET_ATS_TEST_TG_CONSTANT:
97 return "CONSTANT";
98
99 case GNUNET_ATS_TEST_TG_LINEAR:
100 return "LINEAR";
101
102 case GNUNET_ATS_TEST_TG_RANDOM:
103 return "RANDOM";
104
105 case GNUNET_ATS_TEST_TG_SINUS:
106 return "SINUS";
107
108 default:
109 return "INVALID";
110 break;
111 }
112}
113
114
115static struct TestPeer *
116find_peer_by_id (int id)
117{
118 struct TestPeer *cur;
119
120 for (cur = peer_head; NULL != cur; cur = cur->next)
121 if (cur->id == id)
122 return cur;
123 return NULL;
124}
125
126
127static struct TestPeer *
128find_peer_by_pid (const struct GNUNET_PeerIdentity *pid)
129{
130 struct TestPeer *cur;
131
132 for (cur = peer_head; NULL != cur; cur = cur->next)
133 if (0 == GNUNET_memcmp (&cur->peer_id, pid))
134 return cur;
135 return NULL;
136}
137
138
139static struct TestAddress *
140find_address_by_id (struct TestPeer *peer, int aid)
141{
142 struct TestAddress *cur;
143
144 for (cur = peer->addr_head; NULL != cur; cur = cur->next)
145 if (cur->aid == aid)
146 return cur;
147 return NULL;
148}
149
150
151/**
152 * Logging
153 */
154void
155GNUNET_ATS_solver_logging_now (struct LoggingHandle *l)
156{
157 struct LoggingTimeStep *lts;
158 struct TestPeer *cur;
159 struct TestAddress *cur_addr;
160 struct LoggingPeer *log_p;
161 struct LoggingAddress *log_a;
162 int c;
163
164 lts = GNUNET_new (struct LoggingTimeStep);
165 GNUNET_CONTAINER_DLL_insert_tail (l->head, l->tail, lts);
166 lts->timestamp = GNUNET_TIME_absolute_get ();
167 if (NULL == lts->prev)
168 lts->delta = GNUNET_TIME_UNIT_ZERO;
169 else
170 lts->delta = GNUNET_TIME_absolute_get_duration (lts->prev->timestamp);
171
172 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Logging %llu, delta %llu\n",
173 lts->timestamp.abs_value_us, lts->delta.rel_value_us);
174
175
176 /* Store logging data here */
177 for (cur = peer_head; NULL != cur; cur = cur->next)
178 {
179 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
180 "Logging peer id %llu\n", cur->id);
181
182 log_p = GNUNET_new (struct LoggingPeer);
183 log_p->id = cur->id;
184 log_p->peer_id = cur->peer_id;
185 log_p->is_requested = cur->is_requested;
186 for (c = 0; c < GNUNET_ATS_PreferenceCount; c++)
187 {
188 log_p->pref_abs[c] = cur->pref_abs[c];
189 log_p->pref_norm[c] = cur->pref_norm[c];
190 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
191 "\t %s = %.2f %.2f [abs/rel]\n",
192 GNUNET_ATS_print_preference_type (c),
193 log_p->pref_abs[c], log_p->pref_norm[c]);
194 }
195 GNUNET_CONTAINER_DLL_insert_tail (lts->head, lts->tail, log_p);
196
197 for (cur_addr = cur->addr_head; NULL != cur_addr; cur_addr = cur_addr->next)
198 {
199 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
200 "Logging peer id %llu address %llu\n",
201 cur->id, cur_addr->aid);
202 log_a = GNUNET_new (struct LoggingAddress);
203 log_a->aid = cur_addr->aid;
204 log_a->active = cur_addr->ats_addr->active;
205 log_a->network = cur_addr->network;
206 log_a->assigned_bw_in = cur_addr->ats_addr->assigned_bw_in;
207 log_a->assigned_bw_out = cur_addr->ats_addr->assigned_bw_out;
208 for (c = 0; c < GNUNET_ATS_PropertyCount; c++)
209 {
210 log_a->prop_abs[c] = cur_addr->prop_abs[c];
211 log_a->prop_norm[c] = cur_addr->prop_norm[c];
212 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
213 "\t %s = %.2f %.2f [abs/rel]\n",
214 GNUNET_ATS_print_property_type (c),
215 log_a->prop_abs[c],
216 log_a->prop_norm[c]);
217 }
218 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "\t Active = %i\n", log_a->active);
219 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "\t BW in = %llu\n",
220 log_a->assigned_bw_in);
221 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "\t BW out = %llu\n",
222 log_a->assigned_bw_out);
223
224 GNUNET_CONTAINER_DLL_insert_tail (log_p->addr_head, log_p->addr_tail,
225 log_a);
226 }
227 }
228}
229
230
231static void
232logging_task (void *cls)
233{
234 struct LoggingHandle *l = cls;
235
236 l->logging_task = NULL;
237 GNUNET_ATS_solver_logging_now (l);
238 l->logging_task = GNUNET_SCHEDULER_add_delayed (l->log_freq,
239 &logging_task,
240 l);
241}
242
243
244struct LoggingHandle *
245GNUNET_ATS_solver_logging_start (struct GNUNET_TIME_Relative freq)
246{
247 struct LoggingHandle *l;
248
249 l = GNUNET_new (struct LoggingHandle);
250
251 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Start logging every %s\n",
252 GNUNET_STRINGS_relative_time_to_string (freq, GNUNET_NO));
253 l->log_freq = freq;
254 l->logging_task = GNUNET_SCHEDULER_add_now (&logging_task, l);
255 return l;
256}
257
258
259void
260GNUNET_ATS_solver_logging_stop (struct LoggingHandle *l)
261{
262 if (NULL != l->logging_task)
263 GNUNET_SCHEDULER_cancel (l->logging_task);
264
265 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Stop logging\n");
266
267 l->logging_task = NULL;
268}
269
270
271static struct LoggingFileHandle *
272find_logging_file_handle (struct LoggingFileHandle *lf_head,
273 struct LoggingFileHandle *lf_tail,
274 int peer_id, int address_id)
275{
276 struct LoggingFileHandle *res;
277
278 for (res = lf_head; NULL != res; res = res->next)
279 if ((res->pid == peer_id) && (res->aid == address_id))
280 return res;
281 return NULL;
282}
283
284
285void
286GNUNET_ATS_solver_logging_write_to_disk (struct LoggingHandle *l, int
287 add_time_stamp,
288 char *output_dir)
289{
290 struct LoggingTimeStep *lts;
291 struct LoggingPeer *log_p;
292 struct LoggingAddress *log_a;
293 struct LoggingFileHandle *lf_head;
294 struct LoggingFileHandle *lf_tail;
295 struct LoggingFileHandle *cur;
296 struct LoggingFileHandle *next;
297 char *filename;
298 char *datastring;
299 char *propstring;
300 char *propstring_tmp;
301 char *prefstring;
302 char *prefstring_tmp;
303 int c;
304 int use_dir;
305
306 use_dir = GNUNET_NO;
307 if (NULL != output_dir)
308 {
309 if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (output_dir))
310 {
311 fprintf (stderr, "Failed to create directory `%s'\n", output_dir);
312 return;
313 }
314 else
315 {
316 fprintf (stderr, "Created directory `%s'\n", output_dir);
317 use_dir = GNUNET_YES;
318 }
319 }
320
321 lf_head = NULL;
322 lf_tail = NULL;
323
324 for (lts = l->head; NULL != lts; lts = lts->next)
325 {
326 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Writing log step %llu\n",
327 (long long unsigned int) lts->timestamp.abs_value_us);
328
329 for (log_p = lts->head; NULL != log_p; log_p = log_p->next)
330 {
331 for (log_a = log_p->addr_head; NULL != log_a; log_a = log_a->next)
332 {
333 cur = find_logging_file_handle (lf_head, lf_tail, log_p->id,
334 log_a->aid);
335 if (NULL == cur)
336 {
337 cur = GNUNET_new (struct LoggingFileHandle);
338 cur->aid = log_a->aid;
339 cur->pid = log_p->id;
340
341 if (GNUNET_YES == add_time_stamp)
342 GNUNET_asprintf (&filename, "%s%s%s_%s_p%u_a%u_%llu.log",
343 (GNUNET_YES == use_dir) ? output_dir : "",
344 (GNUNET_YES == use_dir) ? DIR_SEPARATOR_STR : "",
345 e->log_prefix,
346 opt_solver,
347 cur->pid,
348 cur->aid,
349 l->head->timestamp.abs_value_us);
350 else
351 GNUNET_asprintf (&filename, "%s%s%s_%s_p%u_a%u.log",
352 (GNUNET_YES == use_dir) ? output_dir : "",
353 (GNUNET_YES == use_dir) ? DIR_SEPARATOR_STR : "",
354 e->log_prefix,
355 opt_solver,
356 cur->pid,
357 cur->aid);
358
359 fprintf (stderr,
360 "Add writing log data for peer %llu address %llu to file `%s'\n",
361 cur->pid, cur->aid, filename);
362
363
364 cur->f_hd = GNUNET_DISK_file_open (filename,
365 GNUNET_DISK_OPEN_READWRITE
366 | GNUNET_DISK_OPEN_CREATE
367 | GNUNET_DISK_OPEN_TRUNCATE,
368 GNUNET_DISK_PERM_USER_READ
369 | GNUNET_DISK_PERM_USER_WRITE
370 | GNUNET_DISK_PERM_GROUP_READ
371 | GNUNET_DISK_PERM_OTHER_READ);
372 if (NULL == cur->f_hd)
373 {
374 fprintf (stderr, "Cannot open `%s' to write log data!\n", filename);
375 GNUNET_free (filename);
376 GNUNET_free (cur);
377 goto cleanup;
378 }
379 GNUNET_free (filename);
380 GNUNET_CONTAINER_DLL_insert (lf_head, lf_tail, cur);
381
382 GNUNET_asprintf (&datastring,
383 "#time delta;log duration;peer_requested;addr net; addr_active; bw in; bw out; " \
384 "UTILIZATION_UP [abs/rel]; UTILIZATION_UP; UTILIZATION_DOWN; UTILIZATION_DOWN; " \
385 "UTILIZATION_PAYLOAD_UP; UTILIZATION_PAYLOAD_UP; UTILIZATION_PAYLOAD_DOWN; UTILIZATION_PAYLOAD_DOWN;" \
386 "DELAY; DELAY; " \
387 "DISTANCE ;DISTANCE ; COST_WAN; COST_WAN; COST_LAN; COST_LAN; " \
388 "COST_WLAN; COST_WLAN;COST_BT; COST_BT; PREF BW abs; PREF BW rel; PREF LATENCY abs; PREF LATENCY rel;\n");
389 GNUNET_DISK_file_write (cur->f_hd, datastring, strlen (datastring));
390 GNUNET_free (datastring);
391 }
392
393 prefstring = GNUNET_strdup ("");
394 for (c = 1; c < GNUNET_ATS_PreferenceCount; c++)
395 {
396 /*
397 fprintf(stderr,"\t %s = %.2f %.2f [abs/rel]\n",
398 GNUNET_ATS_print_preference_type(c),
399 log_p->pref_abs[c], log_p->pref_norm[c]);
400 */GNUNET_asprintf (&prefstring_tmp, "%s;%.3f;%.3f",
401 prefstring, log_p->pref_abs[c], log_p->pref_norm[c]);
402
403
404 GNUNET_free (prefstring);
405 prefstring = GNUNET_strdup (prefstring_tmp);
406 GNUNET_free (prefstring_tmp);
407 }
408
409
410 propstring = GNUNET_strdup ("");
411 for (c = 1; c < GNUNET_ATS_PropertyCount; c++)
412 {
413 if (GNUNET_ATS_NETWORK_TYPE == c)
414 continue;
415 /*
416 fprintf(stderr, "\t %s = %.2f %.2f [abs/rel]\n",
417 GNUNET_ATS_print_property_type(c),
418 log_a->prop_abs[c], log_a->prop_norm[c]);*/
419 GNUNET_asprintf (&propstring_tmp, "%s%.3f;%.3f;",
420 propstring,
421 log_a->prop_abs[c],
422 log_a->prop_norm[c]);
423 GNUNET_free (propstring);
424 propstring = GNUNET_strdup (propstring_tmp);
425 GNUNET_free (propstring_tmp);
426 }
427 GNUNET_asprintf (&datastring, "%llu;%llu;%u;%u;%i;%u;%u;%s;%s\n",
428 GNUNET_TIME_absolute_get_difference (
429 l->head->timestamp,
430 lts->timestamp).
431 rel_value_us / 1000, lts->delta,
432 log_p->is_requested, log_a->network, log_a->active,
433 log_a->assigned_bw_in, log_a->assigned_bw_out,
434 propstring,
435 prefstring);
436
437 GNUNET_DISK_file_write (cur->f_hd, datastring, strlen (datastring));
438 GNUNET_free (datastring);
439 GNUNET_free (prefstring);
440 GNUNET_free (propstring);
441 }
442 }
443 }
444
445 cleanup:
446 next = lf_head;
447 for (cur = next; NULL != cur; cur = next)
448 {
449 next = cur->next;
450 GNUNET_CONTAINER_DLL_remove (lf_head, lf_tail, cur);
451 if (NULL != cur->f_hd)
452 GNUNET_DISK_file_close (cur->f_hd);
453 GNUNET_free (cur);
454 }
455}
456
457
458void
459GNUNET_ATS_solver_logging_eval (struct LoggingHandle *l)
460{
461 struct LoggingTimeStep *lts;
462 struct LoggingPeer *log_p;
463 struct LoggingAddress *log_a;
464 int c;
465
466 for (lts = l->head; NULL != lts; lts = lts->next)
467 {
468 fprintf (stderr, "Log step %llu %llu: \n",
469 (long long unsigned int) lts->timestamp.abs_value_us,
470 (long long unsigned int) lts->delta.rel_value_us);
471
472 for (log_p = lts->head; NULL != log_p; log_p = log_p->next)
473 {
474 fprintf (stderr, "\tLogging peer pid %llu\n", log_p->id);
475 for (c = 1; c < GNUNET_ATS_PreferenceCount; c++)
476 {
477 fprintf (stderr, "\t %s = %.2f %.2f [abs/rel]\n",
478 GNUNET_ATS_print_preference_type (c),
479 log_p->pref_abs[c], log_p->pref_norm[c]);
480 }
481
482 for (log_a = log_p->addr_head; NULL != log_a; log_a = log_a->next)
483 {
484 fprintf (stderr, "\tPeer pid %llu address %llu: %u %u %u\n",
485 log_p->id, log_a->aid, log_a->active,
486 log_a->assigned_bw_in,
487 log_a->assigned_bw_out);
488
489 for (c = 1; c < GNUNET_ATS_PropertyCount; c++)
490 {
491 if (GNUNET_ATS_NETWORK_TYPE == c)
492 continue;
493 fprintf (stderr, "\t %s = %.2f %.2f [abs/rel]\n",
494 GNUNET_ATS_print_property_type (c),
495 log_a->prop_abs[c], log_a->prop_norm[c]);
496 }
497 }
498 }
499 }
500}
501
502
503void
504GNUNET_ATS_solver_logging_free (struct LoggingHandle *l)
505{
506 struct LoggingTimeStep *lts_cur;
507 struct LoggingTimeStep *lts_next;
508 struct LoggingPeer *log_p_cur;
509 struct LoggingPeer *log_p_next;
510 struct LoggingAddress *log_a_cur;
511 struct LoggingAddress *log_a_next;
512
513 if (NULL != l->logging_task)
514 GNUNET_SCHEDULER_cancel (l->logging_task);
515 l->logging_task = NULL;
516
517 lts_next = l->head;
518 while (NULL != (lts_cur = lts_next))
519 {
520 lts_next = lts_cur->next;
521
522 log_p_next = lts_cur->head;
523 while (NULL != (log_p_cur = log_p_next))
524 {
525 log_p_next = log_p_cur->next;
526
527 log_a_next = log_p_cur->addr_head;
528 while (NULL != (log_a_cur = log_a_next))
529 {
530 log_a_next = log_a_cur->next;
531
532 GNUNET_CONTAINER_DLL_remove (log_p_cur->addr_head, log_p_cur->addr_tail,
533 log_a_cur);
534 GNUNET_free (log_a_cur);
535 }
536
537 GNUNET_CONTAINER_DLL_remove (lts_cur->head, lts_cur->tail, log_p_cur);
538 GNUNET_free (log_p_cur);
539 }
540
541 GNUNET_CONTAINER_DLL_remove (l->head, l->tail, lts_cur);
542 GNUNET_free (lts_cur);
543 }
544
545 GNUNET_free (l);
546}
547
548
549/**
550 * Property Generators
551 */
552static struct PropertyGenerator *prop_gen_head;
553static struct PropertyGenerator *prop_gen_tail;
554
555
556static double
557get_property (struct PropertyGenerator *pg)
558{
559 struct GNUNET_TIME_Relative time_delta;
560 double delta_value;
561 double pref_value;
562
563 /* Calculate the current preference value */
564 switch (pg->type)
565 {
566 case GNUNET_ATS_TEST_TG_CONSTANT:
567 pref_value = pg->base_value;
568 break;
569
570 case GNUNET_ATS_TEST_TG_LINEAR:
571 time_delta = GNUNET_TIME_absolute_get_duration (pg->time_start);
572 /* Calculate point of time in the current period */
573 time_delta.rel_value_us = time_delta.rel_value_us
574 % pg->duration_period.rel_value_us;
575 delta_value = ((double) time_delta.rel_value_us
576 / pg->duration_period.rel_value_us) * (pg->max_value
577 - pg->base_value);
578 if ((pg->max_value < pg->base_value) &&
579 ((pg->max_value - pg->base_value) > pg->base_value))
580 {
581 /* This will cause an underflow */
582 GNUNET_break (0);
583 }
584 pref_value = pg->base_value + delta_value;
585 break;
586
587 case GNUNET_ATS_TEST_TG_RANDOM:
588 delta_value = (double) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
589 10000 * (pg->max_value
590 - pg->base_value))
591 / 10000;
592 pref_value = pg->base_value + delta_value;
593 break;
594
595 case GNUNET_ATS_TEST_TG_SINUS:
596 time_delta = GNUNET_TIME_absolute_get_duration (pg->time_start);
597 /* Calculate point of time in the current period */
598 time_delta.rel_value_us = time_delta.rel_value_us
599 % pg->duration_period.rel_value_us;
600 if ((pg->max_value - pg->base_value) > pg->base_value)
601 {
602 /* This will cause an underflow for second half of sinus period,
603 * will be detected in general when experiments are loaded */
604 GNUNET_break (0);
605 }
606 delta_value = (pg->max_value - pg->base_value)
607 * sin ((2 * M_PI)
608 / ((double) pg->duration_period.rel_value_us)
609 * time_delta.rel_value_us);
610 pref_value = pg->base_value + delta_value;
611 break;
612
613 default:
614 pref_value = 0.0;
615 break;
616 }
617 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Current property value is %f\n",
618 pref_value);
619 return pref_value;
620}
621
622
623static void
624set_prop_task (void *cls)
625{
626 struct PropertyGenerator *pg = cls;
627 struct TestPeer *p;
628 struct TestAddress *a;
629 double prop_value;
630 struct GNUNET_ATS_Information atsi;
631
632 pg->set_task = NULL;
633
634 if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains_value (sh->addresses,
635 &pg->test_peer
636 ->peer_id,
637 pg->
638 test_address->
639 ats_addr))
640 {
641 GNUNET_break (0);
642 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
643 "Setting property generation for unknown address [%u:%u]\n",
644 pg->peer, pg->address_id);
645 return;
646 }
647 if (NULL == (p = find_peer_by_id (pg->peer)))
648 {
649 GNUNET_break (0);
650 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
651 "Setting property generation for unknown peer %u\n",
652 pg->peer);
653 return;
654 }
655 if (NULL == (a = find_address_by_id (p, pg->address_id)))
656 {
657 GNUNET_break (0);
658 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
659 "Setting property generation for unknown peer %u\n",
660 pg->peer);
661 return;
662 }
663
664 prop_value = get_property (pg);
665 a->prop_abs[pg->ats_property] = prop_value;
666
667 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
668 "Setting property for peer [%u] address [%u] for %s to %f\n",
669 pg->peer, pg->address_id,
670 GNUNET_ATS_print_property_type (pg->ats_property), prop_value);
671
672 atsi.type = htonl (pg->ats_property);
673 atsi.value = htonl ((uint32_t) prop_value);
674
675 /* set performance here! */
676 sh->sf->s_bulk_start (sh->sf->cls);
677 if (GNUNET_YES == opt_disable_normalization)
678 {
679 a->prop_abs[pg->ats_property] = prop_value;
680 a->prop_norm[pg->ats_property] = prop_value;
681 sh->sf->s_address_update_property (sh->sf->cls, a->ats_addr,
682 pg->ats_property, prop_value,
683 prop_value);
684 }
685 else
686 GAS_normalization_update_property (pg->test_address->ats_addr, &atsi, 1);
687 sh->sf->s_bulk_stop (sh->sf->cls);
688
689 pg->set_task = GNUNET_SCHEDULER_add_delayed (pg->frequency,
690 &set_prop_task, pg);
691}
692
693
694/**
695 * Set ats_property to 0 to find all pgs
696 */
697static struct PropertyGenerator *
698find_prop_gen (unsigned int peer, unsigned int address,
699 uint32_t ats_property)
700{
701 struct PropertyGenerator *cur;
702
703 for (cur = prop_gen_head; NULL != cur; cur = cur->next)
704 if ((cur->peer == peer) && (cur->address_id == address))
705 {
706 if ((cur->ats_property == ats_property) || (0 == ats_property))
707 return cur;
708 }
709 return NULL;
710}
711
712
713void
714GNUNET_ATS_solver_generate_property_stop (struct PropertyGenerator *pg)
715{
716 GNUNET_CONTAINER_DLL_remove (prop_gen_head, prop_gen_tail, pg);
717
718 if (NULL != pg->set_task)
719 {
720 GNUNET_SCHEDULER_cancel (pg->set_task);
721 pg->set_task = NULL;
722 }
723 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
724 "Removing old up preference generator peer [%u] address [%u] `%s'\n",
725 pg->peer, pg->address_id,
726 GNUNET_ATS_print_property_type (pg->ats_property));
727
728 GNUNET_free (pg);
729}
730
731
732/**
733 * Generate between the source master and the partner and set property with a
734 * value depending on the generator.
735 *
736 * @param peer source
737 * @param address_id partner
738 * @param test_peer the peer
739 * @param test_address the address
740 * @param type type of generator
741 * @param base_value base value
742 * @param value_rate maximum value
743 * @param period duration of a period of generation (~ 1/frequency)
744 * @param frequency how long to generate property
745 * @param ats_property ATS property to generate
746 * @return the property generator
747 */
748struct PropertyGenerator *
749GNUNET_ATS_solver_generate_property_start (unsigned int peer,
750 unsigned int address_id,
751 struct TestPeer *test_peer,
752 struct TestAddress *test_address,
753 enum GeneratorType type,
754 long int base_value,
755 long int value_rate,
756 struct GNUNET_TIME_Relative period,
757 struct GNUNET_TIME_Relative
758 frequency,
759 uint32_t ats_property)
760{
761 struct PropertyGenerator *pg;
762
763 pg = GNUNET_new (struct PropertyGenerator);
764 GNUNET_CONTAINER_DLL_insert (prop_gen_head, prop_gen_tail, pg);
765 pg->type = type;
766 pg->peer = peer;
767 pg->test_address = test_address;
768 pg->test_peer = test_peer;
769 pg->address_id = address_id;
770 pg->ats_property = ats_property;
771 pg->base_value = base_value;
772 pg->max_value = value_rate;
773 pg->duration_period = period;
774 pg->frequency = frequency;
775 pg->time_start = GNUNET_TIME_absolute_get ();
776
777 switch (type)
778 {
779 case GNUNET_ATS_TEST_TG_CONSTANT:
780 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
781 "Setting up %s property generator peer [%u] address [%u] `%s'" \
782 "max %u Bips\n",
783 print_generator_type (type), pg->peer, pg->address_id,
784 GNUNET_ATS_print_property_type (ats_property),
785 base_value);
786 break;
787
788 case GNUNET_ATS_TEST_TG_LINEAR:
789 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
790 "Setting up %s property generator peer [%u] address [%u] `%s' " \
791 "min %u Bips max %u Bips\n",
792 print_generator_type (type), pg->peer, pg->address_id,
793 GNUNET_ATS_print_property_type (ats_property),
794 base_value, value_rate);
795 break;
796
797 case GNUNET_ATS_TEST_TG_SINUS:
798 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
799 "Setting up %s property generator peer [%u] address [%u] `%s' " \
800 "baserate %u Bips, amplitude %u Bps\n",
801 print_generator_type (type), pg->peer, pg->address_id,
802 GNUNET_ATS_print_property_type (ats_property),
803 base_value, value_rate);
804 break;
805
806 case GNUNET_ATS_TEST_TG_RANDOM:
807 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
808 "Setting up %s property generator peer [%u] address [%u] `%s' " \
809 "min %u Bips max %u Bps\n",
810 print_generator_type (type), pg->peer, pg->address_id,
811 GNUNET_ATS_print_property_type (ats_property),
812 base_value, value_rate);
813 break;
814
815 default:
816 break;
817 }
818
819 pg->set_task = GNUNET_SCHEDULER_add_now (&set_prop_task, pg);
820 return pg;
821}
822
823
824/**
825 * Stop all preferences generators
826 */
827void
828GNUNET_ATS_solver_generate_property_stop_all ()
829{
830 struct PropertyGenerator *cur;
831 struct PropertyGenerator *next;
832
833 next = prop_gen_head;
834 for (cur = next; NULL != cur; cur = next)
835 {
836 next = cur->next;
837 GNUNET_ATS_solver_generate_property_stop (cur);
838 }
839}
840
841
842/**
843 * Preference Generators
844 */
845static struct PreferenceGenerator *pref_gen_head;
846static struct PreferenceGenerator *pref_gen_tail;
847
848
849static double
850get_preference (struct PreferenceGenerator *pg)
851{
852 struct GNUNET_TIME_Relative time_delta;
853 double delta_value;
854 double pref_value;
855
856 /* Calculate the current preference value */
857 switch (pg->type)
858 {
859 case GNUNET_ATS_TEST_TG_CONSTANT:
860 pref_value = pg->base_value;
861 break;
862
863 case GNUNET_ATS_TEST_TG_LINEAR:
864 time_delta = GNUNET_TIME_absolute_get_duration (pg->time_start);
865 /* Calculate point of time in the current period */
866 time_delta.rel_value_us = time_delta.rel_value_us
867 % pg->duration_period.rel_value_us;
868 delta_value = ((double) time_delta.rel_value_us
869 / pg->duration_period.rel_value_us) * (pg->max_value
870 - pg->base_value);
871 if ((pg->max_value < pg->base_value) &&
872 ((pg->max_value - pg->base_value) > pg->base_value))
873 {
874 /* This will cause an underflow */
875 GNUNET_break (0);
876 }
877 pref_value = pg->base_value + delta_value;
878 break;
879
880 case GNUNET_ATS_TEST_TG_RANDOM:
881 delta_value = (double) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
882 10000 * (pg->max_value
883 - pg->base_value))
884 / 10000;
885 pref_value = pg->base_value + delta_value;
886 break;
887
888 case GNUNET_ATS_TEST_TG_SINUS:
889 time_delta = GNUNET_TIME_absolute_get_duration (pg->time_start);
890 /* Calculate point of time in the current period */
891 time_delta.rel_value_us = time_delta.rel_value_us
892 % pg->duration_period.rel_value_us;
893 if ((pg->max_value - pg->base_value) > pg->base_value)
894 {
895 /* This will cause an underflow for second half of sinus period,
896 * will be detected in general when experiments are loaded */
897 GNUNET_break (0);
898 }
899 delta_value = (pg->max_value - pg->base_value)
900 * sin ((2 * M_PI)
901 / ((double) pg->duration_period.rel_value_us)
902 * time_delta.rel_value_us);
903 pref_value = pg->base_value + delta_value;
904 break;
905
906 default:
907 pref_value = 0.0;
908 break;
909 }
910 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Current preference value is %f\n",
911 pref_value);
912 return pref_value;
913}
914
915
916static void
917set_feedback_task (void *cls)
918{
919 struct PreferenceGenerator *pg = cls;
920 struct TestPeer *p;
921 double feedback;
922 uint32_t bw_acc_out;
923 uint32_t bw_acc_in;
924 uint32_t delay_acc_in;
925 struct GNUNET_TIME_Relative dur;
926 double p_new;
927
928 pg->feedback_task = NULL;
929
930 if (NULL == (p = find_peer_by_id (pg->peer)))
931 {
932 GNUNET_break (0);
933 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
934 "Setting feedback for unknown peer %u\n", pg->peer);
935 return;
936 }
937
938 switch (pg->kind)
939 {
940 case GNUNET_ATS_PREFERENCE_BANDWIDTH:
941 dur = GNUNET_TIME_absolute_get_duration (pg->feedback_last_bw_update);
942 bw_acc_in = dur.rel_value_us * pg->last_assigned_bw_in
943 + pg->feedback_bw_in_acc;
944 pg->feedback_bw_in_acc = 0;
945
946 bw_acc_out = dur.rel_value_us * pg->last_assigned_bw_out
947 + pg->feedback_bw_out_acc;
948 p_new = get_preference (pg);
949 feedback = (p_new / pg->pref_bw_old) * (bw_acc_in + bw_acc_out)
950 / (2 * GNUNET_TIME_absolute_get_duration (
951 pg->feedback_last).rel_value_us);
952
953 break;
954
955 case GNUNET_ATS_PREFERENCE_LATENCY:
956 dur = GNUNET_TIME_absolute_get_duration (pg->feedback_last_delay_update);
957 delay_acc_in = dur.rel_value_us * pg->last_delay_value
958 + pg->feedback_delay_acc;
959 pg->feedback_delay_acc = 0;
960
961 p_new = get_preference (pg);
962 feedback = (p_new / pg->pref_latency_old) * (delay_acc_in)
963 / (GNUNET_TIME_absolute_get_duration (
964 pg->feedback_last).rel_value_us);
965
966 break;
967
968 default:
969 GNUNET_break (0);
970 feedback = 0.0;
971 break;
972 }
973 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
974 "Giving feedback for peer [%u] for client %p pref %s of %.3f\n",
975 pg->peer, NULL + (pg->client_id),
976 GNUNET_ATS_print_preference_type (pg->kind),
977 feedback);
978
979 sh->sf->s_feedback (sh->sf->cls, NULL + (pg->client_id), &p->peer_id,
980 pg->feedback_frequency, pg->kind, feedback);
981 pg->feedback_last = GNUNET_TIME_absolute_get ();
982
983
984 pg->feedback_bw_out_acc = 0;
985 pg->feedback_bw_in_acc = 0;
986 pg->feedback_last_bw_update = GNUNET_TIME_absolute_get ();
987
988 pg->feedback_delay_acc = 0;
989 pg->feedback_last_delay_update = GNUNET_TIME_absolute_get ();
990
991
992 pg->feedback_task = GNUNET_SCHEDULER_add_delayed (pg->feedback_frequency,
993 &set_feedback_task, pg);
994}
995
996
997static void
998set_pref_task (void *cls)
999{
1000 struct PreferenceGenerator *pg = cls;
1001 struct TestPeer *p;
1002 double pref_value;
1003
1004 pg->set_task = NULL;
1005
1006 if (NULL == (p = find_peer_by_id (pg->peer)))
1007 {
1008 GNUNET_break (0);
1009 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1010 "Setting preference for unknown peer %u\n", pg->peer);
1011 return;
1012 }
1013
1014 pref_value = get_preference (pg);
1015 switch (pg->kind)
1016 {
1017 case GNUNET_ATS_PREFERENCE_BANDWIDTH:
1018 pg->pref_bw_old = pref_value;
1019 break;
1020
1021 case GNUNET_ATS_PREFERENCE_LATENCY:
1022 pg->pref_latency_old = pref_value;
1023 break;
1024
1025 default:
1026 break;
1027 }
1028
1029 p->pref_abs[pg->kind] = pref_value;
1030
1031 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1032 "Setting preference for peer [%u] for client %p pref %s to %f\n",
1033 pg->peer, NULL + (pg->client_id),
1034 GNUNET_ATS_print_preference_type (pg->kind), pref_value);
1035
1036 if (GNUNET_YES == opt_disable_normalization)
1037 {
1038 p->pref_abs[pg->kind] = pref_value;
1039 p->pref_norm[pg->kind] = pref_value;
1040 sh->sf->s_pref (sh->sf->cls, &p->peer_id, pg->kind, pref_value);
1041 }
1042 else
1043 update_preference (NULL + (pg->client_id),
1044 &p->peer_id,
1045 pg->kind,
1046 pref_value);
1047
1048 pg->set_task = GNUNET_SCHEDULER_add_delayed (pg->frequency,
1049 &set_pref_task,
1050 pg);
1051}
1052
1053
1054static struct PreferenceGenerator *
1055find_pref_gen (unsigned int peer, enum GNUNET_ATS_PreferenceKind kind)
1056{
1057 struct PreferenceGenerator *cur;
1058
1059 for (cur = pref_gen_head; NULL != cur; cur = cur->next)
1060 if (cur->peer == peer)
1061 {
1062 if ((cur->kind == kind) || (GNUNET_ATS_PREFERENCE_END == kind))
1063 return cur;
1064 }
1065 return NULL;
1066}
1067
1068
1069void
1070GNUNET_ATS_solver_generate_preferences_stop (struct PreferenceGenerator *pg)
1071{
1072 GNUNET_CONTAINER_DLL_remove (pref_gen_head, pref_gen_tail, pg);
1073
1074 if (NULL != pg->feedback_task)
1075 {
1076 GNUNET_SCHEDULER_cancel (pg->feedback_task);
1077 pg->feedback_task = NULL;
1078 }
1079
1080 if (NULL != pg->set_task)
1081 {
1082 GNUNET_SCHEDULER_cancel (pg->set_task);
1083 pg->set_task = NULL;
1084 }
1085 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1086 "Removing old up preference generator peer [%u] `%s'\n",
1087 pg->peer, GNUNET_ATS_print_preference_type (pg->kind));
1088
1089 GNUNET_free (pg);
1090}
1091
1092
1093static struct TestAddress*
1094find_active_address (struct TestPeer *p)
1095{
1096 struct TestAddress *cur;
1097
1098 for (cur = p->addr_head; NULL != cur; cur = cur->next)
1099 if (GNUNET_YES == cur->ats_addr->active)
1100 return cur;
1101 return NULL;
1102}
1103
1104
1105/**
1106 * Generate between the source master and the partner and set property with a
1107 * value depending on the generator.
1108 *
1109 * @param peer source
1110 * @param address_id partner
1111 * @param client_id the client
1112 * @param type type of generator
1113 * @param base_value base value
1114 * @param value_rate maximum value
1115 * @param period duration of a period of generation (~ 1/frequency)
1116 * @param frequency how long to generate property
1117 * @param kind ATS preference to generate
1118 * @param feedback_frequency how often to give feedback
1119 * @return the preference generator
1120 */
1121struct PreferenceGenerator *
1122GNUNET_ATS_solver_generate_preferences_start (unsigned int peer,
1123 unsigned int address_id,
1124 unsigned int client_id,
1125 enum GeneratorType type,
1126 long int base_value,
1127 long int value_rate,
1128 struct GNUNET_TIME_Relative
1129 period,
1130 struct GNUNET_TIME_Relative
1131 frequency,
1132 enum GNUNET_ATS_PreferenceKind
1133 kind,
1134 struct GNUNET_TIME_Relative
1135 feedback_frequency)
1136{
1137 struct PreferenceGenerator *pg;
1138 struct TestPeer *p;
1139
1140 if (NULL == (p = find_peer_by_id (peer)))
1141 {
1142 GNUNET_break (0);
1143 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1144 "Starting preference for unknown peer %u\n", peer);
1145 return NULL;
1146 }
1147
1148 pg = GNUNET_new (struct PreferenceGenerator);
1149 GNUNET_CONTAINER_DLL_insert (pref_gen_head, pref_gen_tail, pg);
1150 pg->type = type;
1151 pg->peer = peer;
1152 pg->client_id = client_id;
1153 pg->kind = kind;
1154 pg->base_value = base_value;
1155 pg->max_value = value_rate;
1156 pg->duration_period = period;
1157 pg->frequency = frequency;
1158 pg->time_start = GNUNET_TIME_absolute_get ();
1159 pg->feedback_frequency = feedback_frequency;
1160
1161 switch (type)
1162 {
1163 case GNUNET_ATS_TEST_TG_CONSTANT:
1164 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1165 "Setting up %s preference generator peer [%u] `%s' max %u Bips\n",
1166 print_generator_type (type), pg->peer,
1167 GNUNET_ATS_print_preference_type (kind),
1168 base_value);
1169 break;
1170
1171 case GNUNET_ATS_TEST_TG_LINEAR:
1172 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1173 "Setting up %s preference generator peer [%u] `%s' min %u Bips max %u Bips\n",
1174 print_generator_type (type), pg->peer,
1175 GNUNET_ATS_print_preference_type (kind),
1176 base_value, value_rate);
1177 break;
1178
1179 case GNUNET_ATS_TEST_TG_SINUS:
1180 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1181 "Setting up %s preference generator peer [%u] `%s' baserate %u Bips, amplitude %u Bps\n",
1182 print_generator_type (type), pg->peer,
1183 GNUNET_ATS_print_preference_type (kind),
1184 base_value, value_rate);
1185 break;
1186
1187 case GNUNET_ATS_TEST_TG_RANDOM:
1188 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1189 "Setting up %s preference generator peer [%u] `%s' min %u Bips max %u Bps\n",
1190 print_generator_type (type), pg->peer,
1191 GNUNET_ATS_print_preference_type (kind),
1192 base_value, value_rate);
1193 break;
1194
1195 default:
1196 break;
1197 }
1198
1199 pg->set_task = GNUNET_SCHEDULER_add_now (&set_pref_task, pg);
1200 if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us !=
1201 feedback_frequency.rel_value_us)
1202 {
1203 struct TestAddress *addr = find_active_address (p);
1204
1205 pg->last_assigned_bw_in = p->assigned_bw_in;
1206 pg->last_assigned_bw_out = p->assigned_bw_out;
1207 pg->feedback_bw_in_acc = 0;
1208 pg->feedback_bw_out_acc = 0;
1209 pg->last_delay_value = addr->prop_norm[GNUNET_ATS_QUALITY_NET_DELAY];
1210 pg->feedback_delay_acc = 0;
1211
1212 pg->feedback_last_bw_update = GNUNET_TIME_absolute_get ();
1213 pg->feedback_last_delay_update = GNUNET_TIME_absolute_get ();
1214 pg->feedback_last = GNUNET_TIME_absolute_get ();
1215 pg->feedback_task = GNUNET_SCHEDULER_add_delayed (feedback_frequency,
1216 &set_feedback_task, pg);
1217 }
1218
1219 return pg;
1220}
1221
1222
1223/**
1224 * Stop all preferences generators
1225 */
1226void
1227GNUNET_ATS_solver_generate_preferences_stop_all ()
1228{
1229 struct PreferenceGenerator *cur;
1230 struct PreferenceGenerator *next;
1231
1232 next = pref_gen_head;
1233 for (cur = next; NULL != cur; cur = next)
1234 {
1235 next = cur->next;
1236 GNUNET_ATS_solver_generate_preferences_stop (cur);
1237 }
1238}
1239
1240
1241/**
1242 * Experiments
1243 */
1244static const char *
1245print_op (enum OperationType op)
1246{
1247 switch (op)
1248 {
1249 case SOLVER_OP_ADD_ADDRESS:
1250 return "ADD_ADDRESS";
1251
1252 case SOLVER_OP_DEL_ADDRESS:
1253 return "DEL_ADDRESS";
1254
1255 case SOLVER_OP_START_SET_PREFERENCE:
1256 return "START_SET_PREFERENCE";
1257
1258 case SOLVER_OP_STOP_SET_PREFERENCE:
1259 return "STOP_STOP_PREFERENCE";
1260
1261 case SOLVER_OP_START_SET_PROPERTY:
1262 return "START_SET_PROPERTY";
1263
1264 case SOLVER_OP_STOP_SET_PROPERTY:
1265 return "STOP_SET_PROPERTY";
1266
1267 case SOLVER_OP_START_REQUEST:
1268 return "START_REQUEST";
1269
1270 case SOLVER_OP_STOP_REQUEST:
1271 return "STOP_REQUEST";
1272
1273 default:
1274 break;
1275 }
1276 return "";
1277}
1278
1279
1280static struct Experiment *
1281create_experiment ()
1282{
1283 struct Experiment *e;
1284
1285 e = GNUNET_new (struct Experiment);
1286 e->name = NULL;
1287 e->start = NULL;
1288 e->total_duration = GNUNET_TIME_UNIT_ZERO;
1289 return e;
1290}
1291
1292
1293static void
1294free_experiment (struct Experiment *e)
1295{
1296 struct Episode *cur;
1297 struct Episode *next;
1298 struct GNUNET_ATS_TEST_Operation *cur_o;
1299 struct GNUNET_ATS_TEST_Operation *next_o;
1300
1301 next = e->start;
1302 for (cur = next; NULL != cur; cur = next)
1303 {
1304 next = cur->next;
1305
1306 next_o = cur->head;
1307 for (cur_o = next_o; NULL != cur_o; cur_o = next_o)
1308 {
1309 next_o = cur_o->next;
1310 GNUNET_free (cur_o->address);
1311 GNUNET_free (cur_o->plugin);
1312 GNUNET_free (cur_o);
1313 }
1314 GNUNET_free (cur);
1315 }
1316
1317 GNUNET_free (e->name);
1318 GNUNET_free (e->log_prefix);
1319 GNUNET_free (e->log_output_dir);
1320 GNUNET_free (e->cfg_file);
1321 GNUNET_free (e);
1322}
1323
1324
1325static int
1326load_op_add_address (struct GNUNET_ATS_TEST_Operation *o,
1327 struct Episode *e,
1328 int op_counter,
1329 char *sec_name,
1330 const struct GNUNET_CONFIGURATION_Handle *cfg)
1331{
1332 char *op_name;
1333 char *op_network;
1334
1335 /* peer pid */
1336 GNUNET_asprintf (&op_name, "op-%u-peer-id", op_counter);
1337 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
1338 sec_name, op_name,
1339 &o->peer_id))
1340 {
1341 fprintf (stderr, "Missing peer-id in operation %u `%s' in episode `%s'\n",
1342 op_counter, "ADD_ADDRESS", op_name);
1343 GNUNET_free (op_name);
1344 return GNUNET_SYSERR;
1345 }
1346 GNUNET_free (op_name);
1347
1348 /* address pid */
1349 GNUNET_asprintf (&op_name, "op-%u-address-id", op_counter);
1350 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
1351 sec_name, op_name,
1352 &o->address_id))
1353 {
1354 fprintf (stderr,
1355 "Missing address-id in operation %u `%s' in episode `%s'\n",
1356 op_counter, "ADD_ADDRESS", op_name);
1357 GNUNET_free (op_name);
1358 return GNUNET_SYSERR;
1359 }
1360 GNUNET_free (op_name);
1361
1362 /* plugin */
1363 GNUNET_asprintf (&op_name, "op-%u-plugin", op_counter);
1364 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg,
1365 sec_name, op_name,
1366 &o->plugin))
1367 {
1368 fprintf (stderr, "Missing plugin in operation %u `%s' in episode `%s'\n",
1369 op_counter, "ADD_ADDRESS", op_name);
1370 GNUNET_free (op_name);
1371 return GNUNET_SYSERR;
1372 }
1373 GNUNET_free (op_name);
1374
1375 /* address */
1376 GNUNET_asprintf (&op_name, "op-%u-address", op_counter);
1377 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg,
1378 sec_name, op_name,
1379 &o->address))
1380 {
1381 fprintf (stderr, "Missing address in operation %u `%s' in episode `%s'\n",
1382 op_counter, "ADD_ADDRESS", op_name);
1383 GNUNET_free (op_name);
1384 return GNUNET_SYSERR;
1385 }
1386 GNUNET_free (op_name);
1387
1388 /* session */
1389 GNUNET_asprintf (&op_name, "op-%u-address-session", op_counter);
1390 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
1391 sec_name, op_name,
1392 &o->
1393 address_session))
1394 {
1395 fprintf (stderr,
1396 "Missing address-session in operation %u `%s' in episode `%s'\n",
1397 op_counter, "ADD_ADDRESS", op_name);
1398 GNUNET_free (op_name);
1399 return GNUNET_SYSERR;
1400 }
1401 GNUNET_free (op_name);
1402
1403 /* network */
1404 GNUNET_asprintf (&op_name, "op-%u-address-network", op_counter);
1405 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg,
1406 sec_name, op_name,
1407 &op_network))
1408 {
1409 fprintf (stderr,
1410 "Missing address-network in operation %u `%s' in episode `%s'\n",
1411 op_counter, "ADD_ADDRESS", op_name);
1412 GNUNET_free (op_name);
1413 return GNUNET_SYSERR;
1414 }
1415 else
1416 {
1417 GNUNET_break (GNUNET_OK == GNUNET_STRINGS_utf8_toupper (op_network,
1418 op_network));
1419 if (0 == strcmp (op_network, "UNSPECIFIED"))
1420 {
1421 o->address_network = GNUNET_NT_UNSPECIFIED;
1422 }
1423 else if (0 == strcmp (op_network, "LOOPBACK"))
1424 {
1425 o->address_network = GNUNET_NT_LOOPBACK;
1426 }
1427 else if (0 == strcmp (op_network, "LAN"))
1428 {
1429 o->address_network = GNUNET_NT_LAN;
1430 }
1431 else if (0 == strcmp (op_network, "WAN"))
1432 {
1433 o->address_network = GNUNET_NT_WAN;
1434 }
1435 else if (0 == strcmp (op_network, "WLAN"))
1436 {
1437 o->address_network = GNUNET_NT_WLAN;
1438 }
1439 else if (0 == strcmp (op_network, "BT"))
1440 {
1441 o->address_network = GNUNET_NT_BT;
1442 }
1443 else
1444 {
1445 fprintf (stderr,
1446 "Invalid address-network in operation %u `%s' in episode `%s': `%s'\n",
1447 op_counter, "ADD_ADDRESS", op_name, op_network);
1448 GNUNET_free (op_network);
1449 GNUNET_free (op_name);
1450 return GNUNET_SYSERR;
1451 }
1452 }
1453 GNUNET_free (op_network);
1454 GNUNET_free (op_name);
1455
1456 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1457 "Found operation %s: [%llu:%llu] address `%s' plugin `%s' \n",
1458 "ADD_ADDRESS", o->peer_id, o->address_id, o->address, o->plugin);
1459
1460 return GNUNET_OK;
1461}
1462
1463
1464static int
1465load_op_del_address (struct GNUNET_ATS_TEST_Operation *o,
1466 struct Episode *e,
1467 int op_counter,
1468 char *sec_name,
1469 const struct GNUNET_CONFIGURATION_Handle *cfg)
1470{
1471 char *op_name;
1472
1473 // char *op_network;
1474
1475 /* peer pid */
1476 GNUNET_asprintf (&op_name, "op-%u-peer-id", op_counter);
1477 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
1478 sec_name, op_name,
1479 &o->peer_id))
1480 {
1481 fprintf (stderr, "Missing peer-id in operation %u `%s' in episode `%s'\n",
1482 op_counter, "DEL_ADDRESS", op_name);
1483 GNUNET_free (op_name);
1484 return GNUNET_SYSERR;
1485 }
1486 GNUNET_free (op_name);
1487
1488 /* address pid */
1489 GNUNET_asprintf (&op_name, "op-%u-address-id", op_counter);
1490 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
1491 sec_name, op_name,
1492 &o->address_id))
1493 {
1494 fprintf (stderr,
1495 "Missing address-id in operation %u `%s' in episode `%s'\n",
1496 op_counter, "DEL_ADDRESS", op_name);
1497 GNUNET_free (op_name);
1498 return GNUNET_SYSERR;
1499 }
1500 GNUNET_free (op_name);
1501
1502#if 0
1503 /* plugin */
1504 GNUNET_asprintf (&op_name, "op-%u-plugin", op_counter);
1505 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg,
1506 sec_name, op_name,
1507 &o->plugin))
1508 {
1509 fprintf (stderr, "Missing plugin in operation %u `%s' in episode `%s'\n",
1510 op_counter, "DEL_ADDRESS", op_name);
1511 GNUNET_free (op_name);
1512 return GNUNET_SYSERR;
1513 }
1514 GNUNET_free (op_name);
1515
1516 /* address */
1517 GNUNET_asprintf (&op_name, "op-%u-address", op_counter);
1518 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg,
1519 sec_name, op_name,
1520 &o->address))
1521 {
1522 fprintf (stderr, "Missing address in operation %u `%s' in episode `%s'\n",
1523 op_counter, "DEL_ADDRESS", op_name);
1524 GNUNET_free (op_name);
1525 return GNUNET_SYSERR;
1526 }
1527 GNUNET_free (op_name);
1528
1529 /* session */
1530 GNUNET_asprintf (&op_name, "op-%u-address-session", op_counter);
1531 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
1532 sec_name, op_name,
1533 &o->
1534 address_session))
1535 {
1536 fprintf (stderr,
1537 "Missing address-session in operation %u `%s' in episode `%s'\n",
1538 op_counter, "DEL_ADDRESS", op_name);
1539 GNUNET_free (op_name);
1540 return GNUNET_SYSERR;
1541 }
1542 GNUNET_free (op_name);
1543#endif
1544
1545 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1546 "Found operation %s: [%llu:%llu] address `%s' plugin `%s' \n",
1547 "DEL_ADDRESS", o->peer_id, o->address_id, o->address, o->plugin);
1548
1549 return GNUNET_OK;
1550}
1551
1552
1553static enum GNUNET_ATS_Property
1554parse_preference_string (const char *str)
1555{
1556 int c = 0;
1557 char *props[GNUNET_ATS_PreferenceCount] = GNUNET_ATS_PreferenceTypeString;
1558
1559 for (c = 0; c < GNUNET_ATS_PreferenceCount; c++)
1560 if (0 == strcmp (str, props[c]))
1561 return c;
1562 return 0;
1563}
1564
1565
1566static int
1567load_op_start_set_preference (struct GNUNET_ATS_TEST_Operation *o,
1568 struct Episode *e,
1569 int op_counter,
1570 char *sec_name,
1571 const struct GNUNET_CONFIGURATION_Handle *cfg)
1572{
1573 char *op_name;
1574 char *type;
1575 char *pref;
1576
1577 /* peer pid */
1578 GNUNET_asprintf (&op_name, "op-%u-peer-id", op_counter);
1579 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
1580 sec_name, op_name,
1581 &o->peer_id))
1582 {
1583 fprintf (stderr, "Missing peer-id in operation %u `%s' in episode `%s'\n",
1584 op_counter, "START_SET_PREFERENCE", op_name);
1585 GNUNET_free (op_name);
1586 return GNUNET_SYSERR;
1587 }
1588 GNUNET_free (op_name);
1589
1590 /* address pid */
1591 GNUNET_asprintf (&op_name, "op-%u-client-id", op_counter);
1592 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
1593 sec_name, op_name,
1594 &o->client_id))
1595 {
1596 fprintf (stderr, "Missing client-id in operation %u `%s' in episode `%s'\n",
1597 op_counter, "START_SET_PREFERENCE", op_name);
1598 GNUNET_free (op_name);
1599 return GNUNET_SYSERR;
1600 }
1601 GNUNET_free (op_name);
1602
1603 /* generator */
1604 GNUNET_asprintf (&op_name, "op-%u-gen-type", op_counter);
1605 if ((GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg,
1606 sec_name,
1607 op_name, &type)))
1608 {
1609 fprintf (stderr, "Missing type in operation %u `%s' in episode `%s'\n",
1610 op_counter, "START_SET_PREFERENCE", op_name);
1611 GNUNET_free (op_name);
1612 return GNUNET_SYSERR;
1613 }
1614
1615 /* Load arguments for set_rate, start_send, set_preference */
1616 if (0 == strcmp (type, "constant"))
1617 {
1618 o->gen_type = GNUNET_ATS_TEST_TG_CONSTANT;
1619 }
1620 else if (0 == strcmp (type, "linear"))
1621 {
1622 o->gen_type = GNUNET_ATS_TEST_TG_LINEAR;
1623 }
1624 else if (0 == strcmp (type, "sinus"))
1625 {
1626 o->gen_type = GNUNET_ATS_TEST_TG_SINUS;
1627 }
1628 else if (0 == strcmp (type, "random"))
1629 {
1630 o->gen_type = GNUNET_ATS_TEST_TG_RANDOM;
1631 }
1632 else
1633 {
1634 fprintf (stderr, "Invalid generator type %u `%s' in episode %u\n",
1635 op_counter, op_name, e->id);
1636 GNUNET_free (type);
1637 GNUNET_free (op_name);
1638 return GNUNET_SYSERR;
1639 }
1640 GNUNET_free (type);
1641 GNUNET_free (op_name);
1642
1643
1644 /* Get base rate */
1645 GNUNET_asprintf (&op_name, "op-%u-base-rate", op_counter);
1646 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
1647 sec_name, op_name,
1648 &o->base_rate))
1649 {
1650 fprintf (stderr, "Missing base rate in operation %u `%s' in episode %u\n",
1651 op_counter, op_name, e->id);
1652 GNUNET_free (op_name);
1653 return GNUNET_SYSERR;
1654 }
1655 GNUNET_free (op_name);
1656
1657
1658 /* Get max rate */
1659 GNUNET_asprintf (&op_name, "op-%u-max-rate", op_counter);
1660 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
1661 sec_name, op_name,
1662 &o->max_rate))
1663 {
1664 if ((GNUNET_ATS_TEST_TG_LINEAR == o->gen_type) ||
1665 (GNUNET_ATS_TEST_TG_RANDOM == o->gen_type) ||
1666 (GNUNET_ATS_TEST_TG_SINUS == o->gen_type))
1667 {
1668 fprintf (stderr, "Missing max rate in operation %u `%s' in episode %u\n",
1669 op_counter, op_name, e->id);
1670 GNUNET_free (op_name);
1671 return GNUNET_SYSERR;
1672 }
1673 }
1674 GNUNET_free (op_name);
1675
1676 /* Get period */
1677 GNUNET_asprintf (&op_name, "op-%u-period", op_counter);
1678 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time (cfg,
1679 sec_name, op_name,
1680 &o->period))
1681 {
1682 o->period = e->duration;
1683 }
1684 GNUNET_free (op_name);
1685
1686 /* Get frequency */
1687 GNUNET_asprintf (&op_name, "op-%u-frequency", op_counter);
1688 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time (cfg,
1689 sec_name, op_name,
1690 &o->frequency))
1691 {
1692 fprintf (stderr, "Missing frequency in operation %u `%s' in episode %u\n",
1693 op_counter, op_name, e->id);
1694 GNUNET_free (op_name);
1695 return GNUNET_SYSERR;
1696 }
1697 GNUNET_free (op_name);
1698
1699 /* Get preference */
1700 GNUNET_asprintf (&op_name, "op-%u-pref", op_counter);
1701 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg,
1702 sec_name, op_name,
1703 &pref))
1704 {
1705 fprintf (stderr, "Missing preference in operation %u `%s' in episode %u\n",
1706 op_counter, op_name, e->id);
1707 GNUNET_free (op_name);
1708 return GNUNET_SYSERR;
1709 }
1710
1711 if (0 == (o->pref_type = parse_preference_string (pref)))
1712 {
1713 fprintf (stderr, "Invalid preference in operation %u `%s' in episode %u\n",
1714 op_counter, op_name, e->id);
1715 GNUNET_free (op_name);
1716 GNUNET_free (pref);
1717 return GNUNET_SYSERR;
1718 }
1719 GNUNET_free (pref);
1720 GNUNET_free (op_name);
1721
1722 /* Get feedback delay */
1723 GNUNET_asprintf (&op_name, "op-%u-feedback_delay", op_counter);
1724 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_time (cfg,
1725 sec_name, op_name,
1726 &o->feedback_delay))
1727 {
1728 fprintf (stderr,
1729 "Using feedback delay %llu in operation %u `%s' in episode %u\n",
1730 (long long unsigned int) o->feedback_delay.rel_value_us,
1731 op_counter, op_name, e->id);
1732 }
1733 else
1734 o->feedback_delay = GNUNET_TIME_UNIT_FOREVER_REL;
1735 GNUNET_free (op_name);
1736
1737 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1738 "Found operation %s: [%llu:%llu]: %s = %llu\n",
1739 "START_SET_PREFERENCE", o->peer_id, o->address_id,
1740 GNUNET_ATS_print_preference_type (o->pref_type), o->base_rate);
1741
1742 return GNUNET_OK;
1743}
1744
1745
1746static int
1747load_op_stop_set_preference (struct GNUNET_ATS_TEST_Operation *o,
1748 struct Episode *e,
1749 int op_counter,
1750 char *sec_name,
1751 const struct GNUNET_CONFIGURATION_Handle *cfg)
1752{
1753 char *op_name;
1754 char *pref;
1755
1756 /* peer pid */
1757 GNUNET_asprintf (&op_name, "op-%u-peer-id", op_counter);
1758 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
1759 sec_name, op_name,
1760 &o->peer_id))
1761 {
1762 fprintf (stderr, "Missing peer-id in operation %u `%s' in episode `%s'\n",
1763 op_counter, "STOP_SET_PREFERENCE", op_name);
1764 GNUNET_free (op_name);
1765 return GNUNET_SYSERR;
1766 }
1767 GNUNET_free (op_name);
1768
1769 /* address pid */
1770 GNUNET_asprintf (&op_name, "op-%u-address-id", op_counter);
1771 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
1772 sec_name, op_name,
1773 &o->address_id))
1774 {
1775 fprintf (stderr,
1776 "Missing address-id in operation %u `%s' in episode `%s'\n",
1777 op_counter, "STOP_SET_PREFERENCE", op_name);
1778 GNUNET_free (op_name);
1779 return GNUNET_SYSERR;
1780 }
1781 GNUNET_free (op_name);
1782
1783 /* Get preference */
1784 GNUNET_asprintf (&op_name, "op-%u-pref", op_counter);
1785 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg,
1786 sec_name, op_name,
1787 &pref))
1788 {
1789 fprintf (stderr,
1790 "Missing preference in operation %u `%s' in episode `%s'\n",
1791 op_counter, "STOP_SET_PREFERENCE", op_name);
1792 GNUNET_free (op_name);
1793 return GNUNET_SYSERR;
1794 }
1795
1796 if (0 == (o->pref_type = parse_preference_string (pref)))
1797 {
1798 fprintf (stderr, "Invalid preference in operation %u `%s' in episode %u\n",
1799 op_counter, op_name, e->id);
1800 GNUNET_free (op_name);
1801 GNUNET_free (pref);
1802 return GNUNET_SYSERR;
1803 }
1804 GNUNET_free (pref);
1805 GNUNET_free (op_name);
1806
1807 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1808 "Found operation %s: [%llu:%llu]: %s\n",
1809 "STOP_SET_PREFERENCE", o->peer_id, o->address_id,
1810 GNUNET_ATS_print_preference_type (o->pref_type));
1811 return GNUNET_OK;
1812}
1813
1814
1815static enum GNUNET_ATS_Property
1816parse_property_string (const char *str)
1817{
1818 enum GNUNET_ATS_Property c;
1819
1820 for (c = 0; c < GNUNET_ATS_PropertyCount; c++)
1821 if (0 == strcmp (str,
1822 GNUNET_ATS_print_property_type (c)))
1823 return c;
1824 return 0;
1825}
1826
1827
1828static int
1829load_op_start_set_property (struct GNUNET_ATS_TEST_Operation *o,
1830 struct Episode *e,
1831 int op_counter,
1832 char *sec_name,
1833 const struct GNUNET_CONFIGURATION_Handle *cfg)
1834{
1835 char *op_name;
1836 char *type;
1837 char *prop;
1838
1839 /* peer pid */
1840 GNUNET_asprintf (&op_name, "op-%u-peer-id", op_counter);
1841 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
1842 sec_name, op_name,
1843 &o->peer_id))
1844 {
1845 fprintf (stderr, "Missing peer-id in operation %u `%s' in episode `%s'\n",
1846 op_counter, "START_SET_PROPERTY", op_name);
1847 GNUNET_free (op_name);
1848 return GNUNET_SYSERR;
1849 }
1850 GNUNET_free (op_name);
1851
1852 /* address pid */
1853 GNUNET_asprintf (&op_name, "op-%u-address-id", op_counter);
1854 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
1855 sec_name, op_name,
1856 &o->address_id))
1857 {
1858 fprintf (stderr,
1859 "Missing address-id in operation %u `%s' in episode `%s'\n",
1860 op_counter, "START_SET_PROPERTY", op_name);
1861 GNUNET_free (op_name);
1862 return GNUNET_SYSERR;
1863 }
1864 GNUNET_free (op_name);
1865
1866 /* generator */
1867 GNUNET_asprintf (&op_name, "op-%u-gen-type", op_counter);
1868 if ((GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg,
1869 sec_name,
1870 op_name, &type)))
1871 {
1872 fprintf (stderr, "Missing type in operation %u `%s' in episode `%s'\n",
1873 op_counter, "START_SET_PROPERTY", op_name);
1874 GNUNET_free (op_name);
1875 return GNUNET_SYSERR;
1876 }
1877
1878 /* Load arguments for set_rate, start_send, set_preference */
1879 if (0 == strcmp (type, "constant"))
1880 {
1881 o->gen_type = GNUNET_ATS_TEST_TG_CONSTANT;
1882 }
1883 else if (0 == strcmp (type, "linear"))
1884 {
1885 o->gen_type = GNUNET_ATS_TEST_TG_LINEAR;
1886 }
1887 else if (0 == strcmp (type, "sinus"))
1888 {
1889 o->gen_type = GNUNET_ATS_TEST_TG_SINUS;
1890 }
1891 else if (0 == strcmp (type, "random"))
1892 {
1893 o->gen_type = GNUNET_ATS_TEST_TG_RANDOM;
1894 }
1895 else
1896 {
1897 fprintf (stderr, "Invalid generator type %u `%s' in episode %u\n",
1898 op_counter, op_name, e->id);
1899 GNUNET_free (type);
1900 GNUNET_free (op_name);
1901 return GNUNET_SYSERR;
1902 }
1903 GNUNET_free (type);
1904 GNUNET_free (op_name);
1905
1906
1907 /* Get base rate */
1908 GNUNET_asprintf (&op_name, "op-%u-base-rate", op_counter);
1909 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
1910 sec_name, op_name,
1911 &o->base_rate))
1912 {
1913 fprintf (stderr, "Missing base rate in operation %u `%s' in episode %u\n",
1914 op_counter, op_name, e->id);
1915 GNUNET_free (op_name);
1916 return GNUNET_SYSERR;
1917 }
1918 GNUNET_free (op_name);
1919
1920
1921 /* Get max rate */
1922 GNUNET_asprintf (&op_name, "op-%u-max-rate", op_counter);
1923 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
1924 sec_name, op_name,
1925 &o->max_rate))
1926 {
1927 if ((GNUNET_ATS_TEST_TG_LINEAR == o->gen_type) ||
1928 (GNUNET_ATS_TEST_TG_RANDOM == o->gen_type) ||
1929 (GNUNET_ATS_TEST_TG_SINUS == o->gen_type))
1930 {
1931 fprintf (stderr, "Missing max rate in operation %u `%s' in episode %u\n",
1932 op_counter, op_name, e->id);
1933 GNUNET_free (op_name);
1934 return GNUNET_SYSERR;
1935 }
1936 }
1937 GNUNET_free (op_name);
1938
1939 /* Get period */
1940 GNUNET_asprintf (&op_name, "op-%u-period", op_counter);
1941 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time (cfg,
1942 sec_name, op_name,
1943 &o->period))
1944 {
1945 o->period = e->duration;
1946 }
1947 GNUNET_free (op_name);
1948
1949 /* Get frequency */
1950 GNUNET_asprintf (&op_name, "op-%u-frequency", op_counter);
1951 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time (cfg,
1952 sec_name, op_name,
1953 &o->frequency))
1954 {
1955 fprintf (stderr, "Missing frequency in operation %u `%s' in episode %u\n",
1956 op_counter, op_name, e->id);
1957 GNUNET_free (op_name);
1958 return GNUNET_SYSERR;
1959 }
1960 GNUNET_free (op_name);
1961
1962 /* Get preference */
1963 GNUNET_asprintf (&op_name, "op-%u-property", op_counter);
1964 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg,
1965 sec_name, op_name,
1966 &prop))
1967 {
1968 fprintf (stderr, "Missing property in operation %u `%s' in episode %u\n",
1969 op_counter, op_name, e->id);
1970 GNUNET_free (op_name);
1971 GNUNET_free (prop);
1972 return GNUNET_SYSERR;
1973 }
1974
1975 if (0 == (o->prop_type = parse_property_string (prop)))
1976 {
1977 fprintf (stderr, "Invalid property in operation %u `%s' in episode %u\n",
1978 op_counter, op_name, e->id);
1979 GNUNET_free (op_name);
1980 GNUNET_free (prop);
1981 return GNUNET_SYSERR;
1982 }
1983
1984 GNUNET_free (prop);
1985 GNUNET_free (op_name);
1986
1987 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1988 "Found operation %s: [%llu:%llu] %s = %llu\n",
1989 "START_SET_PROPERTY", o->peer_id, o->address_id,
1990 GNUNET_ATS_print_property_type (o->prop_type), o->base_rate);
1991
1992 return GNUNET_OK;
1993}
1994
1995
1996static int
1997load_op_stop_set_property (struct GNUNET_ATS_TEST_Operation *o,
1998 struct Episode *e,
1999 int op_counter,
2000 char *sec_name,
2001 const struct GNUNET_CONFIGURATION_Handle *cfg)
2002{
2003 char *op_name;
2004 char *pref;
2005
2006 /* peer pid */
2007 GNUNET_asprintf (&op_name, "op-%u-peer-id", op_counter);
2008 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
2009 sec_name, op_name,
2010 &o->peer_id))
2011 {
2012 fprintf (stderr, "Missing peer-id in operation %u `%s' in episode `%s'\n",
2013 op_counter, "STOP_SET_PROPERTY", op_name);
2014 GNUNET_free (op_name);
2015 return GNUNET_SYSERR;
2016 }
2017 GNUNET_free (op_name);
2018
2019 /* address pid */
2020 GNUNET_asprintf (&op_name, "op-%u-address-id", op_counter);
2021 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
2022 sec_name, op_name,
2023 &o->address_id))
2024 {
2025 fprintf (stderr,
2026 "Missing address-id in operation %u `%s' in episode `%s'\n",
2027 op_counter, "STOP_SET_PROPERTY", op_name);
2028 GNUNET_free (op_name);
2029 return GNUNET_SYSERR;
2030 }
2031 GNUNET_free (op_name);
2032
2033 /* Get property */
2034 GNUNET_asprintf (&op_name, "op-%u-property", op_counter);
2035 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg,
2036 sec_name, op_name,
2037 &pref))
2038 {
2039 fprintf (stderr, "Missing property in operation %u `%s' in episode `%s'\n",
2040 op_counter, "STOP_SET_PROPERTY", op_name);
2041 GNUNET_free (op_name);
2042 GNUNET_free (pref);
2043 return GNUNET_SYSERR;
2044 }
2045
2046 if (0 == (o->prop_type = parse_property_string (pref)))
2047 {
2048 fprintf (stderr, "Invalid property in operation %u `%s' in episode %u\n",
2049 op_counter, op_name, e->id);
2050 GNUNET_free (op_name);
2051 GNUNET_free (pref);
2052 return GNUNET_SYSERR;
2053 }
2054
2055 GNUNET_free (pref);
2056 GNUNET_free (op_name);
2057
2058 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2059 "Found operation %s: [%llu:%llu] %s\n",
2060 "STOP_SET_PROPERTY", o->peer_id, o->address_id,
2061 GNUNET_ATS_print_property_type (o->prop_type));
2062
2063 return GNUNET_OK;
2064}
2065
2066
2067static int
2068load_op_start_request (struct GNUNET_ATS_TEST_Operation *o,
2069 struct Episode *e,
2070 int op_counter,
2071 char *sec_name,
2072 const struct GNUNET_CONFIGURATION_Handle *cfg)
2073{
2074 char *op_name;
2075
2076 /* peer pid */
2077 GNUNET_asprintf (&op_name, "op-%u-peer-id", op_counter);
2078 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
2079 sec_name, op_name,
2080 &o->peer_id))
2081 {
2082 fprintf (stderr, "Missing peer-id in operation %u `%s' in episode `%s'\n",
2083 op_counter, "START_REQUEST", op_name);
2084 GNUNET_free (op_name);
2085 return GNUNET_SYSERR;
2086 }
2087 GNUNET_free (op_name);
2088 return GNUNET_OK;
2089}
2090
2091
2092static int
2093load_op_stop_request (struct GNUNET_ATS_TEST_Operation *o,
2094 struct Episode *e,
2095 int op_counter,
2096 char *sec_name,
2097 const struct GNUNET_CONFIGURATION_Handle *cfg)
2098{
2099 char *op_name;
2100
2101 /* peer pid */
2102 GNUNET_asprintf (&op_name, "op-%u-peer-id", op_counter);
2103 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
2104 sec_name, op_name,
2105 &o->peer_id))
2106 {
2107 fprintf (stderr, "Missing peer-id in operation %u `%s' in episode `%s'\n",
2108 op_counter, "STOP_REQUEST", op_name);
2109 GNUNET_free (op_name);
2110 return GNUNET_SYSERR;
2111 }
2112 GNUNET_free (op_name);
2113 return GNUNET_OK;
2114}
2115
2116
2117static int
2118load_episode (struct Experiment *e, struct Episode *cur,
2119 struct GNUNET_CONFIGURATION_Handle *cfg)
2120{
2121 struct GNUNET_ATS_TEST_Operation *o;
2122 char *sec_name;
2123 char *op_name;
2124 char *op;
2125 int op_counter = 0;
2126 int res;
2127
2128 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "=== Parsing episode %u\n", cur->id);
2129 GNUNET_asprintf (&sec_name, "episode-%u", cur->id);
2130
2131 while (1)
2132 {
2133 /* Load operation */
2134 GNUNET_asprintf (&op_name, "op-%u-operation", op_counter);
2135 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg,
2136 sec_name,
2137 op_name, &op))
2138 {
2139 GNUNET_free (op_name);
2140 break;
2141 }
2142 o = GNUNET_new (struct GNUNET_ATS_TEST_Operation);
2143 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "==== Parsing operation %u: `%s'\n",
2144 cur->id, op_name);
2145
2146 /* operations = set_rate, start_send, stop_send, set_preference */
2147 if (0 == strcmp (op, "address_add"))
2148 {
2149 o->type = SOLVER_OP_ADD_ADDRESS;
2150 res = load_op_add_address (o, cur,
2151 op_counter, sec_name, cfg);
2152 }
2153 else if (0 == strcmp (op, "address_del"))
2154 {
2155 o->type = SOLVER_OP_DEL_ADDRESS;
2156 res = load_op_del_address (o, cur,
2157 op_counter, sec_name, cfg);
2158 }
2159 else if (0 == strcmp (op, "start_set_property"))
2160 {
2161 o->type = SOLVER_OP_START_SET_PROPERTY;
2162 res = load_op_start_set_property (o, cur,
2163 op_counter, sec_name, cfg);
2164 }
2165 else if (0 == strcmp (op, "stop_set_property"))
2166 {
2167 o->type = SOLVER_OP_STOP_SET_PROPERTY;
2168 res = load_op_stop_set_property (o, cur,
2169 op_counter, sec_name, cfg);
2170 }
2171 else if (0 == strcmp (op, "start_set_preference"))
2172 {
2173 o->type = SOLVER_OP_START_SET_PREFERENCE;
2174 res = load_op_start_set_preference (o, cur,
2175 op_counter, sec_name, cfg);
2176 }
2177 else if (0 == strcmp (op, "stop_set_preference"))
2178 {
2179 o->type = SOLVER_OP_STOP_SET_PREFERENCE;
2180 res = load_op_stop_set_preference (o, cur,
2181 op_counter, sec_name, cfg);
2182 }
2183 else if (0 == strcmp (op, "start_request"))
2184 {
2185 o->type = SOLVER_OP_START_REQUEST;
2186 res = load_op_start_request (o, cur,
2187 op_counter, sec_name, cfg);
2188 }
2189 else if (0 == strcmp (op, "stop_request"))
2190 {
2191 o->type = SOLVER_OP_STOP_REQUEST;
2192 res = load_op_stop_request (o, cur,
2193 op_counter, sec_name, cfg);
2194 }
2195 else
2196 {
2197 fprintf (stderr, "Invalid operation %u `%s' in episode %u\n",
2198 op_counter, op, cur->id);
2199 res = GNUNET_SYSERR;
2200 }
2201
2202 GNUNET_free (op);
2203 GNUNET_free (op_name);
2204
2205 if (GNUNET_SYSERR == res)
2206 {
2207 GNUNET_free (o);
2208 GNUNET_free (sec_name);
2209 return GNUNET_SYSERR;
2210 }
2211
2212 GNUNET_CONTAINER_DLL_insert_tail (cur->head, cur->tail, o);
2213 op_counter++;
2214 }
2215 GNUNET_free (sec_name);
2216 return GNUNET_OK;
2217}
2218
2219
2220static int
2221load_episodes (struct Experiment *e, struct GNUNET_CONFIGURATION_Handle *cfg)
2222{
2223 int e_counter = 0;
2224 char *sec_name;
2225 struct GNUNET_TIME_Relative e_duration;
2226 struct Episode *cur;
2227 struct Episode *last;
2228
2229 e_counter = 0;
2230 last = NULL;
2231 while (1)
2232 {
2233 GNUNET_asprintf (&sec_name, "episode-%u", e_counter);
2234 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time (cfg,
2235 sec_name,
2236 "duration",
2237 &e_duration))
2238 {
2239 GNUNET_free (sec_name);
2240 break;
2241 }
2242
2243 cur = GNUNET_new (struct Episode);
2244 cur->duration = e_duration;
2245 cur->id = e_counter;
2246
2247 if (GNUNET_OK != load_episode (e, cur, cfg))
2248 {
2249 GNUNET_free (sec_name);
2250 GNUNET_free (cur);
2251 return GNUNET_SYSERR;
2252 }
2253
2254 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Found episode %u with duration %s \n",
2255 e_counter,
2256 GNUNET_STRINGS_relative_time_to_string (cur->duration,
2257 GNUNET_YES));
2258
2259 /* Update experiment */
2260 e->num_episodes++;
2261 e->total_duration = GNUNET_TIME_relative_add (e->total_duration,
2262 cur->duration);
2263 /* Put in linked list */
2264 if (NULL == last)
2265 e->start = cur;
2266 else
2267 last->next = cur;
2268
2269 GNUNET_free (sec_name);
2270 e_counter++;
2271 last = cur;
2272 }
2273 return e_counter;
2274}
2275
2276
2277static void
2278timeout_experiment (void *cls)
2279{
2280 struct Experiment *e = cls;
2281
2282 e->experiment_timeout_task = NULL;
2283 fprintf (stderr, "Experiment timeout!\n");
2284
2285 if (NULL != e->episode_timeout_task)
2286 {
2287 GNUNET_SCHEDULER_cancel (e->episode_timeout_task);
2288 e->episode_timeout_task = NULL;
2289 }
2290
2291 e->e_done_cb (e, GNUNET_TIME_absolute_get_duration (e->start_time),
2292 GNUNET_SYSERR);
2293}
2294
2295
2296struct ATS_Address *
2297create_ats_address (const struct GNUNET_PeerIdentity *peer,
2298 const char *plugin_name,
2299 const void *plugin_addr,
2300 size_t plugin_addr_len,
2301 uint32_t session_id,
2302 uint32_t network)
2303{
2304 struct ATS_Address *aa = NULL;
2305
2306 aa = GNUNET_malloc (sizeof(struct ATS_Address) + plugin_addr_len + strlen (
2307 plugin_name) + 1);
2308 aa->atsi = GNUNET_new (struct GNUNET_ATS_Information);
2309 aa->atsi[0].type = htonl (GNUNET_ATS_NETWORK_TYPE);
2310 aa->atsi[0].value = htonl (network);
2311 aa->atsi_count = 1;
2312
2313 aa->peer = *peer;
2314 aa->addr_len = plugin_addr_len;
2315 aa->addr = &aa[1];
2316 aa->plugin = (char *) &aa[1] + plugin_addr_len;
2317 GNUNET_memcpy (&aa[1], plugin_addr, plugin_addr_len);
2318 GNUNET_memcpy (aa->plugin, plugin_name, strlen (plugin_name) + 1);
2319 aa->session_id = session_id;
2320
2321 return aa;
2322}
2323
2324
2325static void
2326enforce_add_address (struct GNUNET_ATS_TEST_Operation *op)
2327{
2328 struct TestPeer *p;
2329 struct TestAddress *a;
2330 int c;
2331
2332 if (NULL == (p = find_peer_by_id (op->peer_id)))
2333 {
2334 p = GNUNET_new (struct TestPeer);
2335 p->id = op->peer_id;
2336 p->assigned_bw_in = 0;
2337 p->assigned_bw_out = 0;
2338 memset (&p->peer_id, op->peer_id, sizeof(p->peer_id));
2339 for (c = 0; c < GNUNET_ATS_PreferenceCount; c++)
2340 {
2341 p->pref_abs[c] = DEFAULT_ABS_PREFERENCE;
2342 p->pref_norm[c] = DEFAULT_REL_PREFERENCE;
2343 }
2344
2345 GNUNET_CONTAINER_DLL_insert (peer_head, peer_tail, p);
2346 }
2347
2348 if (NULL != (find_address_by_id (p, op->address_id)))
2349 {
2350 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Duplicate address %u for peer %u\n",
2351 op->address_id, op->peer_id);
2352 return;
2353 }
2354
2355 a = GNUNET_new (struct TestAddress);
2356 a->aid = op->address_id;
2357 a->network = op->address_network;
2358 a->ats_addr = create_ats_address (&p->peer_id, op->plugin, op->address,
2359 strlen (op->address) + 1,
2360 op->address_session, op->address_network);
2361 memset (&p->peer_id, op->peer_id, sizeof(p->peer_id));
2362 GNUNET_CONTAINER_DLL_insert_tail (p->addr_head, p->addr_tail, a);
2363
2364 for (c = 0; c < GNUNET_ATS_PropertyCount; c++)
2365 a->prop_norm[c] = DEFAULT_REL_QUALITY;
2366
2367 GNUNET_CONTAINER_multipeermap_put (sh->addresses, &p->peer_id, a->ats_addr,
2368 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2369
2370 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2371 "Adding address %u for peer %u in network `%s'\n",
2372 op->address_id, op->peer_id, GNUNET_NT_to_string (a->network));
2373
2374 sh->sf->s_add (sh->sf->cls, a->ats_addr, op->address_network);
2375}
2376
2377
2378static void
2379enforce_del_address (struct GNUNET_ATS_TEST_Operation *op)
2380{
2381 struct TestPeer *p;
2382 struct TestAddress *a;
2383 struct PropertyGenerator *pg;
2384
2385 if (NULL == (p = find_peer_by_id (op->peer_id)))
2386 {
2387 GNUNET_break (0);
2388 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2389 "Deleting address for unknown peer %u\n", op->peer_id);
2390 return;
2391 }
2392
2393 if (NULL == (a = find_address_by_id (p, op->address_id)))
2394 {
2395 GNUNET_break (0);
2396 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2397 "Deleting address for unknown peer %u\n", op->peer_id);
2398 return;
2399 }
2400
2401 while (NULL != (pg = find_prop_gen (p->id, a->aid, 0)))
2402 {
2403 GNUNET_ATS_solver_generate_property_stop (pg);
2404 }
2405
2406 GNUNET_assert (GNUNET_YES ==
2407 GNUNET_CONTAINER_multipeermap_remove (sh->addresses,
2408 &p->peer_id,
2409 a->ats_addr));
2410 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2411 "Removing address %u for peer %u\n",
2412 op->address_id,
2413 op->peer_id);
2414
2415 sh->sf->s_del (sh->sf->cls, a->ats_addr);
2416
2417 if (NULL != l)
2418 {
2419 GNUNET_ATS_solver_logging_now (l);
2420 }
2421 GNUNET_CONTAINER_DLL_remove (p->addr_head, p->addr_tail, a);
2422
2423 GNUNET_free (a->ats_addr->atsi);
2424 GNUNET_free (a->ats_addr);
2425 GNUNET_free (a);
2426}
2427
2428
2429static void
2430enforce_start_property (struct GNUNET_ATS_TEST_Operation *op)
2431{
2432 struct PropertyGenerator *pg;
2433 struct TestPeer *p;
2434 struct TestAddress *a;
2435
2436 if (NULL != (pg = find_prop_gen (op->peer_id, op->address_id, op->prop_type)))
2437 {
2438 GNUNET_ATS_solver_generate_property_stop (pg);
2439 GNUNET_free (pg);
2440 }
2441
2442 if (NULL == (p = find_peer_by_id (op->peer_id)))
2443 {
2444 GNUNET_break (0);
2445 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2446 "Starting property generation for unknown peer %u\n",
2447 op->peer_id);
2448 return;
2449 }
2450
2451 if (NULL == (a = find_address_by_id (p, op->address_id)))
2452 {
2453 GNUNET_break (0);
2454 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2455 "Setting property for unknown address %u\n", op->peer_id);
2456 return;
2457 }
2458
2459 GNUNET_ATS_solver_generate_property_start (op->peer_id,
2460 op->address_id,
2461 p, a,
2462 op->gen_type,
2463 op->base_rate,
2464 op->max_rate,
2465 op->period,
2466 op->frequency,
2467 op->prop_type);
2468}
2469
2470
2471static void
2472enforce_stop_property (struct GNUNET_ATS_TEST_Operation *op)
2473{
2474 struct PropertyGenerator *pg = find_prop_gen (op->peer_id, op->address_id,
2475 op->prop_type);
2476
2477 if (NULL != pg)
2478 {
2479 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2480 "Stopping preference generation for peer %u address %u\n",
2481 op->peer_id,
2482 op->address_id);
2483 GNUNET_ATS_solver_generate_property_stop (pg);
2484 }
2485 else
2486 {
2487 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2488 "Cannot find preference generator for peer %u address %u\n",
2489 op->peer_id, op->address_id);
2490 GNUNET_break (0);
2491 }
2492}
2493
2494
2495static void
2496enforce_start_preference (struct GNUNET_ATS_TEST_Operation *op)
2497{
2498 struct PreferenceGenerator *pg;
2499
2500 if (NULL != (pg = find_pref_gen (op->peer_id, op->pref_type)))
2501 {
2502 GNUNET_ATS_solver_generate_preferences_stop (pg);
2503 GNUNET_free (pg);
2504 }
2505
2506 if (NULL == (find_peer_by_id (op->peer_id)))
2507 {
2508 GNUNET_break (0);
2509 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2510 "Starting preference generation for unknown peer %u\n",
2511 op->peer_id);
2512 return;
2513 }
2514
2515 GNUNET_ATS_solver_generate_preferences_start (op->peer_id,
2516 op->address_id,
2517 op->client_id,
2518 op->gen_type,
2519 op->base_rate,
2520 op->max_rate,
2521 op->period,
2522 op->frequency,
2523 op->pref_type,
2524 op->frequency);
2525}
2526
2527
2528static void
2529enforce_stop_preference (struct GNUNET_ATS_TEST_Operation *op)
2530{
2531 struct PreferenceGenerator *pg = find_pref_gen (op->peer_id,
2532 op->pref_type);
2533
2534 if (NULL != pg)
2535 {
2536 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2537 "Stopping property generation for peer %u address %u\n",
2538 op->peer_id,
2539 op->address_id);
2540 GNUNET_ATS_solver_generate_preferences_stop (pg);
2541 }
2542 else
2543 {
2544 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2545 "Cannot find preference generator for peer %u address %u\n",
2546 op->peer_id, op->address_id);
2547 GNUNET_break (0);
2548 }
2549}
2550
2551
2552static void
2553enforce_start_request (struct GNUNET_ATS_TEST_Operation *op)
2554{
2555 struct TestPeer *p;
2556
2557 if (NULL == (p = find_peer_by_id (op->peer_id)))
2558 {
2559 GNUNET_break (0);
2560 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2561 "Requesting address for unknown peer %u\n", op->peer_id);
2562 return;
2563 }
2564
2565 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Requesting address for peer %u\n",
2566 op->peer_id);
2567 p->is_requested = GNUNET_YES;
2568
2569 sh->sf->s_get (sh->sf->cls, &p->peer_id);
2570}
2571
2572
2573static void
2574enforce_stop_request (struct GNUNET_ATS_TEST_Operation *op)
2575{
2576 struct TestPeer *p;
2577
2578 if (NULL == (p = find_peer_by_id (op->peer_id)))
2579 {
2580 GNUNET_break (0);
2581 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2582 "Requesting address for unknown peer %u\n", op->peer_id);
2583 return;
2584 }
2585
2586 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2587 "Stop requesting address for peer %u\n",
2588 op->peer_id);
2589 p->is_requested = GNUNET_NO;
2590 p->assigned_bw_in = 0;
2591 p->assigned_bw_out = 0;
2592 sh->sf->s_get_stop (sh->sf->cls, &p->peer_id);
2593
2594 if (NULL != l)
2595 {
2596 GNUNET_ATS_solver_logging_now (l);
2597 }
2598}
2599
2600
2601static void
2602enforce_episode (struct Episode *ep)
2603{
2604 struct GNUNET_ATS_TEST_Operation *cur;
2605
2606 for (cur = ep->head; NULL != cur; cur = cur->next)
2607 {
2608 switch (cur->type)
2609 {
2610 case SOLVER_OP_ADD_ADDRESS:
2611 fprintf (stderr, "Enforcing operation: %s [%llu:%llu]\n",
2612 print_op (cur->type), cur->peer_id, cur->address_id);
2613 enforce_add_address (cur);
2614 break;
2615
2616 case SOLVER_OP_DEL_ADDRESS:
2617 fprintf (stderr, "Enforcing operation: %s [%llu:%llu]\n",
2618 print_op (cur->type), cur->peer_id, cur->address_id);
2619 enforce_del_address (cur);
2620 break;
2621
2622 case SOLVER_OP_START_SET_PROPERTY:
2623 fprintf (stderr, "Enforcing operation: %s [%llu:%llu] == %llu\n",
2624 print_op (cur->type), cur->peer_id, cur->address_id,
2625 cur->base_rate);
2626 enforce_start_property (cur);
2627 break;
2628
2629 case SOLVER_OP_STOP_SET_PROPERTY:
2630 fprintf (stderr, "Enforcing operation: %s [%llu:%llu] == %llu\n",
2631 print_op (cur->type), cur->peer_id, cur->address_id,
2632 cur->base_rate);
2633 enforce_stop_property (cur);
2634 break;
2635
2636 case SOLVER_OP_START_SET_PREFERENCE:
2637 fprintf (stderr, "Enforcing operation: %s [%llu:%llu] == %llu\n",
2638 print_op (cur->type), cur->peer_id, cur->address_id,
2639 cur->base_rate);
2640 enforce_start_preference (cur);
2641 break;
2642
2643 case SOLVER_OP_STOP_SET_PREFERENCE:
2644 fprintf (stderr, "Enforcing operation: %s [%llu:%llu] == %llu\n",
2645 print_op (cur->type), cur->peer_id, cur->address_id,
2646 cur->base_rate);
2647 enforce_stop_preference (cur);
2648 break;
2649
2650 case SOLVER_OP_START_REQUEST:
2651 fprintf (stderr, "Enforcing operation: %s [%llu]\n",
2652 print_op (cur->type), cur->peer_id);
2653 enforce_start_request (cur);
2654 break;
2655
2656 case SOLVER_OP_STOP_REQUEST:
2657 fprintf (stderr, "Enforcing operation: %s [%llu]\n",
2658 print_op (cur->type), cur->peer_id);
2659 enforce_stop_request (cur);
2660 break;
2661
2662 default:
2663 break;
2664 }
2665 }
2666}
2667
2668
2669static void
2670timeout_episode (void *cls)
2671{
2672 struct Experiment *e = cls;
2673
2674 e->episode_timeout_task = NULL;
2675 if (NULL != e->ep_done_cb)
2676 e->ep_done_cb (e->cur);
2677
2678 /* Scheduling next */
2679 e->cur = e->cur->next;
2680 if (NULL == e->cur)
2681 {
2682 /* done */
2683 fprintf (stderr, "Last episode done!\n");
2684 if (NULL != e->experiment_timeout_task)
2685 {
2686 GNUNET_SCHEDULER_cancel (e->experiment_timeout_task);
2687 e->experiment_timeout_task = NULL;
2688 }
2689 e->e_done_cb (e, GNUNET_TIME_absolute_get_duration (e->start_time),
2690 GNUNET_OK);
2691 return;
2692 }
2693
2694 fprintf (stderr, "Running episode %u with timeout %s\n",
2695 e->cur->id,
2696 GNUNET_STRINGS_relative_time_to_string (e->cur->duration,
2697 GNUNET_YES));
2698 e->episode_timeout_task = GNUNET_SCHEDULER_add_delayed (e->cur->duration,
2699 &timeout_episode, e);
2700 enforce_episode (e->cur);
2701}
2702
2703
2704void
2705GNUNET_ATS_solvers_experimentation_run (struct Experiment *e,
2706 GNUNET_ATS_TESTING_EpisodeDoneCallback
2707 ep_done_cb,
2708 GNUNET_ATS_TESTING_ExperimentDoneCallback
2709 e_done_cb)
2710{
2711 fprintf (stderr, "Running experiment `%s' with timeout %s\n", e->name,
2712 GNUNET_STRINGS_relative_time_to_string (e->max_duration,
2713 GNUNET_YES));
2714 e->e_done_cb = e_done_cb;
2715 e->ep_done_cb = ep_done_cb;
2716 e->start_time = GNUNET_TIME_absolute_get ();
2717
2718 /* Start total time out */
2719 e->experiment_timeout_task = GNUNET_SCHEDULER_add_delayed (e->max_duration,
2720 &timeout_experiment,
2721 e);
2722
2723 /* Start */
2724 if (NULL == e->start)
2725 {
2726 GNUNET_break (0);
2727 return;
2728 }
2729
2730 e->cur = e->start;
2731 fprintf (stderr, "Running episode %u with timeout %s\n",
2732 e->cur->id,
2733 GNUNET_STRINGS_relative_time_to_string (e->cur->duration,
2734 GNUNET_YES));
2735 e->episode_timeout_task = GNUNET_SCHEDULER_add_delayed (e->cur->duration,
2736 &timeout_episode, e);
2737 enforce_episode (e->cur);
2738}
2739
2740
2741void
2742GNUNET_ATS_solvers_experimentation_stop (struct Experiment *e)
2743{
2744 if (NULL != e->experiment_timeout_task)
2745 {
2746 GNUNET_SCHEDULER_cancel (e->experiment_timeout_task);
2747 e->experiment_timeout_task = NULL;
2748 }
2749 if (NULL != e->episode_timeout_task)
2750 {
2751 GNUNET_SCHEDULER_cancel (e->episode_timeout_task);
2752 e->episode_timeout_task = NULL;
2753 }
2754 if (NULL != e->cfg)
2755 {
2756 GNUNET_CONFIGURATION_destroy (e->cfg);
2757 e->cfg = NULL;
2758 }
2759 free_experiment (e);
2760}
2761
2762
2763struct Experiment *
2764GNUNET_ATS_solvers_experimentation_load (char *filename)
2765{
2766 struct Experiment *e;
2767 struct GNUNET_CONFIGURATION_Handle *cfg;
2768
2769 e = NULL;
2770
2771 cfg = GNUNET_CONFIGURATION_create ();
2772 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, filename))
2773 {
2774 fprintf (stderr, "Failed to load `%s'\n", filename);
2775 GNUNET_CONFIGURATION_destroy (cfg);
2776 return NULL;
2777 }
2778
2779 e = create_experiment ();
2780
2781 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg, "experiment",
2782 "name", &e->name))
2783 {
2784 fprintf (stderr, "Invalid %s \n", "name");
2785 free_experiment (e);
2786 return NULL;
2787 }
2788 else
2789 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Experiment name: `%s'\n", e->name);
2790
2791 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg, "experiment",
2792 "log_prefix",
2793 &e->log_prefix))
2794 {
2795 fprintf (stderr, "Invalid %s \n", "log_prefix");
2796 free_experiment (e);
2797 return NULL;
2798 }
2799 else
2800 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Experiment logging prefix: `%s'\n",
2801 e->log_prefix);
2802
2803 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_filename (cfg,
2804 "experiment",
2805 "log_output_dir",
2806 &e->
2807 log_output_dir))
2808 {
2809 e->log_output_dir = NULL;
2810 }
2811 else
2812 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2813 "Experiment logging output directory: `%s'\n",
2814 e->log_output_dir);
2815
2816
2817 if (GNUNET_SYSERR == (e->log_append_time_stamp =
2818 GNUNET_CONFIGURATION_get_value_yesno (cfg,
2819 "experiment",
2820 "log_append_time_stamp")))
2821 e->log_append_time_stamp = GNUNET_YES;
2822 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2823 "Experiment logging append timestamp: `%s'\n",
2824 (GNUNET_YES == e->log_append_time_stamp) ? "yes" : "no");
2825
2826
2827 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_filename (cfg,
2828 "experiment",
2829 "cfg_file",
2830 &e->cfg_file))
2831 {
2832 fprintf (stderr, "Invalid %s \n", "cfg_file");
2833 free_experiment (e);
2834 return NULL;
2835 }
2836 else
2837 {
2838 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Experiment configuration: `%s'\n",
2839 e->cfg_file);
2840 e->cfg = GNUNET_CONFIGURATION_create ();
2841 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (e->cfg, e->cfg_file))
2842 {
2843 fprintf (stderr, "Invalid configuration %s \n", "cfg_file");
2844 free_experiment (e);
2845 return NULL;
2846 }
2847 }
2848
2849 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time (cfg, "experiment",
2850 "log_freq",
2851 &e->log_freq))
2852 {
2853 fprintf (stderr, "Invalid %s \n", "log_freq");
2854 free_experiment (e);
2855 return NULL;
2856 }
2857 else
2858 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Experiment logging frequency: `%s'\n",
2859 GNUNET_STRINGS_relative_time_to_string (e->log_freq,
2860 GNUNET_YES));
2861
2862 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time (cfg, "experiment",
2863 "max_duration",
2864 &e->max_duration))
2865 {
2866 fprintf (stderr, "Invalid %s", "max_duration");
2867 free_experiment (e);
2868 return NULL;
2869 }
2870 else
2871 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Experiment duration: `%s'\n",
2872 GNUNET_STRINGS_relative_time_to_string (e->max_duration,
2873 GNUNET_YES));
2874
2875 if (GNUNET_SYSERR == load_episodes (e, cfg))
2876 {
2877 GNUNET_ATS_solvers_experimentation_stop (e);
2878 GNUNET_CONFIGURATION_destroy (cfg);
2879 e = NULL;
2880 fprintf (stderr, "Failed to load experiment\n");
2881 return NULL;
2882 }
2883 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2884 "Loaded %u episodes with total duration %s\n",
2885 e->num_episodes,
2886 GNUNET_STRINGS_relative_time_to_string (e->total_duration,
2887 GNUNET_YES));
2888
2889 GNUNET_CONFIGURATION_destroy (cfg);
2890 return e;
2891}
2892
2893
2894/**
2895 * Solver
2896 */
2897
2898static int
2899free_all_it (void *cls,
2900 const struct GNUNET_PeerIdentity *key,
2901 void *value)
2902{
2903 struct ATS_Address *address = value;
2904
2905 GNUNET_break (GNUNET_OK == GNUNET_CONTAINER_multipeermap_remove (
2906 sh->env.addresses,
2907 key, value));
2908 GNUNET_free (address);
2909
2910 return GNUNET_OK;
2911}
2912
2913
2914void
2915GNUNET_ATS_solvers_solver_stop (struct SolverHandle *sh)
2916{
2917 GNUNET_STATISTICS_destroy ((struct GNUNET_STATISTICS_Handle *) sh->env.stats,
2918 GNUNET_NO);
2919 GNUNET_PLUGIN_unload (sh->plugin, sh->sf);
2920 sh->sf = NULL;
2921 GAS_normalization_stop ();
2922
2923 GNUNET_CONTAINER_multipeermap_iterate (sh->addresses,
2924 &free_all_it,
2925 NULL);
2926 GNUNET_CONTAINER_multipeermap_destroy (sh->addresses);
2927 GNUNET_free (sh->plugin);
2928 GNUNET_free (sh);
2929}
2930
2931
2932/**
2933 * Load quotas for networks from configuration
2934 *
2935 * @param cfg configuration handle
2936 * @param out_dest where to write outbound quotas
2937 * @param in_dest where to write inbound quotas
2938 * @param dest_length length of inbound and outbound arrays
2939 * @return number of networks loaded
2940 */
2941unsigned int
2942GNUNET_ATS_solvers_load_quotas (const struct GNUNET_CONFIGURATION_Handle *cfg,
2943 unsigned long long *out_dest,
2944 unsigned long long *in_dest,
2945 int dest_length)
2946{
2947 char *entry_in = NULL;
2948 char *entry_out = NULL;
2949 char *quota_out_str;
2950 char *quota_in_str;
2951 int c;
2952 int res;
2953
2954 for (c = 0; (c < GNUNET_NT_COUNT) && (c < dest_length); c++)
2955 {
2956 in_dest[c] = 0;
2957 out_dest[c] = 0;
2958 GNUNET_asprintf (&entry_out,
2959 "%s_QUOTA_OUT",
2960 GNUNET_NT_to_string (c));
2961 GNUNET_asprintf (&entry_in,
2962 "%s_QUOTA_IN",
2963 GNUNET_NT_to_string (c));
2964
2965 /* quota out */
2966 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, "ats",
2967 entry_out,
2968 &quota_out_str))
2969 {
2970 res = GNUNET_NO;
2971 if (0 == strcmp (quota_out_str, BIG_M_STRING))
2972 {
2973 out_dest[c] = GNUNET_ATS_MaxBandwidth;
2974 res = GNUNET_YES;
2975 }
2976 if ((GNUNET_NO == res) && (GNUNET_OK ==
2977 GNUNET_STRINGS_fancy_size_to_bytes (
2978 quota_out_str, &out_dest[c])))
2979 res = GNUNET_YES;
2980 if ((GNUNET_NO == res) && (GNUNET_OK ==
2981 GNUNET_CONFIGURATION_get_value_number (cfg,
2982 "ats",
2983 entry_out,
2984 &
2985 out_dest
2986 [c])))
2987 res = GNUNET_YES;
2988
2989 if (GNUNET_NO == res)
2990 {
2991 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2992 _ (
2993 "Could not load quota for network `%s': `%s', assigning default bandwidth %llu\n"),
2994 GNUNET_NT_to_string (c),
2995 quota_out_str,
2996 GNUNET_ATS_DefaultBandwidth);
2997 out_dest[c] = GNUNET_ATS_DefaultBandwidth;
2998 }
2999 else
3000 {
3001 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3002 "Outbound quota configure for network `%s' is %llu\n",
3003 GNUNET_NT_to_string (c),
3004 out_dest[c]);
3005 }
3006 GNUNET_free (quota_out_str);
3007 }
3008 else
3009 {
3010 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3011 _ (
3012 "No outbound quota configured for network `%s', assigning default bandwidth %llu\n"),
3013 GNUNET_NT_to_string (c),
3014 GNUNET_ATS_DefaultBandwidth);
3015 out_dest[c] = GNUNET_ATS_DefaultBandwidth;
3016 }
3017
3018 /* quota in */
3019 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, "ats",
3020 entry_in,
3021 &quota_in_str))
3022 {
3023 res = GNUNET_NO;
3024 if (0 == strcmp (quota_in_str, BIG_M_STRING))
3025 {
3026 in_dest[c] = GNUNET_ATS_MaxBandwidth;
3027 res = GNUNET_YES;
3028 }
3029 if ((GNUNET_NO == res) && (GNUNET_OK ==
3030 GNUNET_STRINGS_fancy_size_to_bytes (
3031 quota_in_str, &in_dest[c])))
3032 res = GNUNET_YES;
3033 if ((GNUNET_NO == res) && (GNUNET_OK ==
3034 GNUNET_CONFIGURATION_get_value_number (cfg,
3035 "ats",
3036 entry_in,
3037 &in_dest
3038 [c])))
3039 res = GNUNET_YES;
3040
3041 if (GNUNET_NO == res)
3042 {
3043 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3044 _ (
3045 "Could not load quota for network `%s': `%s', assigning default bandwidth %llu\n"),
3046 GNUNET_NT_to_string (c),
3047 quota_in_str,
3048 GNUNET_ATS_DefaultBandwidth);
3049 in_dest[c] = GNUNET_ATS_DefaultBandwidth;
3050 }
3051 else
3052 {
3053 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3054 "Inbound quota configured for network `%s' is %llu\n",
3055 GNUNET_NT_to_string (c),
3056 in_dest[c]);
3057 }
3058 GNUNET_free (quota_in_str);
3059 }
3060 else
3061 {
3062 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3063 _ (
3064 "No outbound quota configure for network `%s', assigning default bandwidth %llu\n"),
3065 GNUNET_NT_to_string (c),
3066 GNUNET_ATS_DefaultBandwidth);
3067 out_dest[c] = GNUNET_ATS_DefaultBandwidth;
3068 }
3069 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3070 "Loaded quota for network `%s' (in/out): %llu %llu\n",
3071 GNUNET_NT_to_string (c),
3072 in_dest[c],
3073 out_dest[c]);
3074 GNUNET_free (entry_out);
3075 GNUNET_free (entry_in);
3076 }
3077 return GNUNET_NT_COUNT;
3078}
3079
3080
3081/**
3082 * Information callback for the solver
3083 *
3084 * @param cls the closure
3085 * @param op the solver operation
3086 * @param stat status of the solver operation
3087 * @param add additional solver information
3088 */
3089static void
3090solver_info_cb (void *cls,
3091 enum GAS_Solver_Operation op,
3092 enum GAS_Solver_Status stat,
3093 enum GAS_Solver_Additional_Information add)
3094{
3095 char *add_info;
3096
3097 switch (add)
3098 {
3099 case GAS_INFO_NONE:
3100 add_info = "GAS_INFO_NONE";
3101 break;
3102
3103 case GAS_INFO_FULL:
3104 add_info = "GAS_INFO_MLP_FULL";
3105 break;
3106
3107 case GAS_INFO_UPDATED:
3108 add_info = "GAS_INFO_MLP_UPDATED";
3109 break;
3110
3111 case GAS_INFO_PROP_ALL:
3112 add_info = "GAS_INFO_PROP_ALL";
3113 break;
3114
3115 case GAS_INFO_PROP_SINGLE:
3116 add_info = "GAS_INFO_PROP_SINGLE";
3117 break;
3118
3119 default:
3120 add_info = "INVALID";
3121 break;
3122 }
3123
3124 switch (op)
3125 {
3126 case GAS_OP_SOLVE_START:
3127 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3128 "Solver notifies `%s' with result `%s' `%s'\n",
3129 "GAS_OP_SOLVE_START",
3130 (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL", add_info);
3131 return;
3132
3133 case GAS_OP_SOLVE_STOP:
3134 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3135 "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_STOP",
3136 (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL", add_info);
3137 return;
3138
3139 case GAS_OP_SOLVE_SETUP_START:
3140 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3141 "Solver notifies `%s' with result `%s'\n",
3142 "GAS_OP_SOLVE_SETUP_START",
3143 (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
3144 return;
3145
3146 case GAS_OP_SOLVE_SETUP_STOP:
3147 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3148 "Solver notifies `%s' with result `%s'\n",
3149 "GAS_OP_SOLVE_SETUP_STOP",
3150 (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
3151 return;
3152
3153 case GAS_OP_SOLVE_MLP_LP_START:
3154 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3155 "Solver notifies `%s' with result `%s'\n",
3156 "GAS_OP_SOLVE_LP_START",
3157 (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
3158 return;
3159
3160 case GAS_OP_SOLVE_MLP_LP_STOP:
3161 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3162 "Solver notifies `%s' with result `%s'\n",
3163 "GAS_OP_SOLVE_LP_STOP",
3164 (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
3165 return;
3166
3167 case GAS_OP_SOLVE_MLP_MLP_START:
3168 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3169 "Solver notifies `%s' with result `%s'\n",
3170 "GAS_OP_SOLVE_MLP_START",
3171 (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
3172 return;
3173
3174 case GAS_OP_SOLVE_MLP_MLP_STOP:
3175 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3176 "Solver notifies `%s' with result `%s'\n",
3177 "GAS_OP_SOLVE_MLP_STOP",
3178 (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
3179 return;
3180
3181 case GAS_OP_SOLVE_UPDATE_NOTIFICATION_START:
3182 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3183 "Solver notifies `%s' with result `%s'\n",
3184 "GAS_OP_SOLVE_UPDATE_NOTIFICATION_START",
3185 (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
3186 return;
3187
3188 case GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP:
3189 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3190 "Solver notifies `%s' with result `%s'\n",
3191 "GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP",
3192 (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
3193 return;
3194
3195 default:
3196 break;
3197 }
3198}
3199
3200
3201static void
3202solver_bandwidth_changed_cb (void *cls, struct ATS_Address *address)
3203{
3204 struct GNUNET_TIME_Relative duration;
3205 struct TestPeer *p;
3206 static struct PreferenceGenerator *pg;
3207 uint32_t delta;
3208
3209 if ((0 == address->assigned_bw_out) && (0 == address->assigned_bw_in))
3210 {
3211 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3212 "Solver notified to disconnect peer `%s'\n",
3213 GNUNET_i2s (&address->peer));
3214 }
3215 p = find_peer_by_pid (&address->peer);
3216 if (NULL == p)
3217 return;
3218 p->assigned_bw_out = address->assigned_bw_out;
3219 p->assigned_bw_in = address->assigned_bw_in;
3220
3221 for (pg = pref_gen_head; NULL != pg; pg = pg->next)
3222 {
3223 if (pg->peer == p->id)
3224 {
3225 duration = GNUNET_TIME_absolute_get_duration (
3226 pg->feedback_last_bw_update);
3227 delta = duration.rel_value_us * pg->last_assigned_bw_out;
3228 pg->feedback_bw_out_acc += delta;
3229
3230 delta = duration.rel_value_us * pg->last_assigned_bw_in;
3231 pg->feedback_bw_in_acc += delta;
3232
3233 pg->last_assigned_bw_in = address->assigned_bw_in;
3234 pg->last_assigned_bw_out = address->assigned_bw_out;
3235 pg->feedback_last_bw_update = GNUNET_TIME_absolute_get ();
3236 }
3237 }
3238
3239 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3240 "Bandwidth changed addresses %s %p to %u Bps out / %u Bps in\n",
3241 GNUNET_i2s (&address->peer),
3242 address,
3243 address->assigned_bw_out,
3244 address->assigned_bw_in);
3245
3246 if (NULL != l)
3247 GNUNET_ATS_solver_logging_now (l);
3248
3249 return;
3250}
3251
3252
3253const double *
3254get_preferences_cb (void *cls, const struct GNUNET_PeerIdentity *id)
3255{
3256 struct TestPeer *p;
3257
3258 if (GNUNET_YES == opt_disable_normalization)
3259 {
3260 if (NULL == (p = find_peer_by_pid (id)))
3261 return NULL;
3262 return p->pref_abs;
3263 }
3264 else
3265 return GAS_preference_get_by_peer (NULL,
3266 id);
3267}
3268
3269
3270struct SolverHandle *
3271GNUNET_ATS_solvers_solver_start (enum GNUNET_ATS_Solvers type)
3272{
3273 struct SolverHandle *sh;
3274 char *solver_str;
3275
3276 switch (type)
3277 {
3278 case GNUNET_ATS_SOLVER_PROPORTIONAL:
3279 solver_str = "proportional";
3280 break;
3281
3282 case GNUNET_ATS_SOLVER_MLP:
3283 solver_str = "mlp";
3284 break;
3285
3286 case GNUNET_ATS_SOLVER_RIL:
3287 solver_str = "ril";
3288 break;
3289
3290 default:
3291 GNUNET_break (0);
3292 return NULL;
3293 break;
3294 }
3295
3296 sh = GNUNET_new (struct SolverHandle);
3297 GNUNET_asprintf (&sh->plugin,
3298 "libgnunet_plugin_ats_%s",
3299 solver_str);
3300 sh->addresses = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_NO);
3301
3302 /* setup environment */
3303 sh->env.cfg = e->cfg;
3304 sh->env.stats = GNUNET_STATISTICS_create ("ats", e->cfg);
3305 sh->env.addresses = sh->addresses;
3306 sh->env.bandwidth_changed_cb = &solver_bandwidth_changed_cb;
3307 sh->env.get_preferences = &get_preferences_cb;
3308 sh->env.network_count = GNUNET_NT_COUNT;
3309 sh->env.info_cb = &solver_info_cb;
3310 sh->env.network_count = GNUNET_NT_COUNT;
3311
3312 /* start normalization */
3313 GAS_normalization_start ();
3314
3315 /* load quotas */
3316 if (GNUNET_NT_COUNT != GNUNET_ATS_solvers_load_quotas (e->cfg,
3317 sh->env.out_quota,
3318 sh->env.in_quota,
3319 GNUNET_NT_COUNT))
3320 {
3321 GNUNET_break (0);
3322 GNUNET_free (sh->plugin);
3323 GNUNET_free (sh);
3324 end_now ();
3325 return NULL;
3326 }
3327
3328 sh->sf = GNUNET_PLUGIN_load (sh->plugin, &sh->env);
3329 if (NULL == sh->sf)
3330 {
3331 fprintf (stderr, "Failed to load solver `%s'\n", sh->plugin);
3332 GNUNET_break (0);
3333 GNUNET_free (sh->plugin);
3334 GNUNET_free (sh);
3335 end_now ();
3336 return NULL;
3337 }
3338 return sh;
3339}
3340
3341
3342static void
3343done ()
3344{
3345 struct TestPeer *cur;
3346 struct TestPeer *next;
3347
3348 struct TestAddress *cur_a;
3349 struct TestAddress *next_a;
3350
3351 /* Stop logging */
3352 GNUNET_ATS_solver_logging_stop (l);
3353
3354 /* Stop all preference generation */
3355 GNUNET_ATS_solver_generate_preferences_stop_all ();
3356
3357 /* Stop all property generation */
3358 GNUNET_ATS_solver_generate_property_stop_all ();
3359
3360 if (opt_print)
3361 {
3362 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "== Printing log information \n");
3363 GNUNET_ATS_solver_logging_eval (l);
3364 }
3365 if (opt_save)
3366 {
3367 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "== Saving log information \n");
3368 GNUNET_ATS_solver_logging_write_to_disk (l, e->log_append_time_stamp,
3369 e->log_output_dir);
3370 }
3371
3372 if (NULL != l)
3373 {
3374 GNUNET_ATS_solver_logging_free (l);
3375 l = NULL;
3376 }
3377
3378 /* Clean up experiment */
3379 if (NULL != e)
3380 {
3381 GNUNET_ATS_solvers_experimentation_stop (e);
3382 e = NULL;
3383 }
3384
3385 next = peer_head;
3386 while (NULL != (cur = next))
3387 {
3388 next = cur->next;
3389 GNUNET_CONTAINER_DLL_remove (peer_head, peer_tail, cur);
3390 next_a = cur->addr_head;
3391 while (NULL != (cur_a = next_a))
3392 {
3393 next_a = cur_a->next;
3394 GNUNET_CONTAINER_DLL_remove (cur->addr_head, cur->addr_tail, cur_a);
3395 GNUNET_free (cur_a);
3396 }
3397 GNUNET_free (cur);
3398 }
3399 if (NULL != sh)
3400 {
3401 GNUNET_ATS_solvers_solver_stop (sh);
3402 sh = NULL;
3403 }
3404
3405 /* Shutdown */
3406 end_now ();
3407}
3408
3409
3410static void
3411experiment_done_cb (struct Experiment *e, struct GNUNET_TIME_Relative duration,
3412 int success)
3413{
3414 if (GNUNET_OK == success)
3415 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Experiment done successful in %s\n",
3416 GNUNET_STRINGS_relative_time_to_string (duration, GNUNET_YES));
3417 else
3418 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Experiment failed \n");
3419
3420 GNUNET_SCHEDULER_add_now (&done, NULL);
3421}
3422
3423
3424static void
3425episode_done_cb (struct Episode *ep)
3426{
3427 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Episode %u done\n", ep->id);
3428}
3429
3430
3431/**
3432 * Do shutdown
3433 */
3434static void
3435end_now ()
3436{
3437 if (NULL != e)
3438 {
3439 GNUNET_ATS_solvers_experimentation_stop (e);
3440 e = NULL;
3441 }
3442 if (NULL != sh)
3443 {
3444 GNUNET_ATS_solvers_solver_stop (sh);
3445 sh = NULL;
3446 }
3447}
3448
3449
3450static void
3451run (void *cls, char *const *args, const char *cfgfile,
3452 const struct GNUNET_CONFIGURATION_Handle *cfg)
3453{
3454 enum GNUNET_ATS_Solvers solver;
3455 int c;
3456
3457 if (NULL == opt_exp_file)
3458 {
3459 fprintf (stderr, "No experiment given ...\n");
3460 res = 1;
3461 end_now ();
3462 return;
3463 }
3464
3465 if (NULL == opt_solver)
3466 {
3467 fprintf (stderr, "No solver given ...\n");
3468 res = 1;
3469 end_now ();
3470 return;
3471 }
3472
3473 if (0 == strcmp (opt_solver, "mlp"))
3474 {
3475 solver = GNUNET_ATS_SOLVER_MLP;
3476 }
3477 else if (0 == strcmp (opt_solver, "proportional"))
3478 {
3479 solver = GNUNET_ATS_SOLVER_PROPORTIONAL;
3480 }
3481 else if (0 == strcmp (opt_solver, "ril"))
3482 {
3483 solver = GNUNET_ATS_SOLVER_RIL;
3484 }
3485 else
3486 {
3487 fprintf (stderr, "No solver given ...");
3488 res = 1;
3489 end_now ();
3490 return;
3491 }
3492
3493 for (c = 0; c < GNUNET_ATS_PropertyCount; c++)
3494 default_properties[c] = DEFAULT_REL_QUALITY;
3495
3496 for (c = 0; c < GNUNET_ATS_PreferenceCount; c++)
3497 default_preferences[c] = DEFAULT_REL_PREFERENCE;
3498
3499 /* load experiment */
3500 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "=== Loading experiment\n");
3501 e = GNUNET_ATS_solvers_experimentation_load (opt_exp_file);
3502 if (NULL == e)
3503 {
3504 fprintf (stderr, "Failed to load experiment ...\n");
3505 res = 1;
3506 end_now ();
3507 return;
3508 }
3509
3510 /* load solver */
3511 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "=== Loading solver\n");
3512 sh = GNUNET_ATS_solvers_solver_start (solver);
3513 if (NULL == sh)
3514 {
3515 fprintf (stderr, "Failed to start solver ...\n");
3516 end_now ();
3517 res = 1;
3518 return;
3519 }
3520
3521 /* start logging */
3522 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "=== Start logging \n");
3523 l = GNUNET_ATS_solver_logging_start (e->log_freq);
3524
3525 /* run experiment */
3526 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "=== Running experiment \n");
3527 GNUNET_ATS_solvers_experimentation_run (e, episode_done_cb,
3528 experiment_done_cb);
3529
3530 /* WAIT */
3531}
3532
3533
3534/**
3535 * Main function of the benchmark
3536 *
3537 * @param argc argument count
3538 * @param argv argument values
3539 */
3540int
3541main (int argc, char *argv[])
3542{
3543 opt_exp_file = NULL;
3544 opt_solver = NULL;
3545 opt_log = GNUNET_NO;
3546 opt_save = GNUNET_NO;
3547
3548 res = 0;
3549
3550 static struct GNUNET_GETOPT_CommandLineOption options[] = {
3551 GNUNET_GETOPT_option_string ('s',
3552 "solver",
3553 gettext_noop ("solver to use"),
3554 &opt_solver),
3555
3556 GNUNET_GETOPT_option_string ('e',
3557 "experiment"
3558 gettext_noop ("experiment to use"),
3559 &opt_exp_file),
3560
3561 GNUNET_GETOPT_option_verbose (&opt_verbose),
3562
3563 GNUNET_GETOPT_option_flag ('p',
3564 "print",
3565 gettext_noop ("print logging"),
3566 &opt_print),
3567
3568 GNUNET_GETOPT_option_flag ('f',
3569 "file",
3570 gettext_noop ("save logging to disk"),
3571 &opt_save),
3572
3573 GNUNET_GETOPT_option_flag ('d',
3574 "dn",
3575 gettext_noop ("disable normalization"),
3576 &opt_disable_normalization),
3577
3578 GNUNET_GETOPT_OPTION_END
3579 };
3580
3581 GNUNET_PROGRAM_run (argc, argv, "gnunet-ats-solver-eval",
3582 NULL, options, &run, argv[0]);
3583
3584 return res;
3585}
3586
3587
3588/* end of file ats-testing-experiment.c*/
diff --git a/src/ats/gnunet-ats-solver-eval.h b/src/ats/gnunet-ats-solver-eval.h
deleted file mode 100644
index 7d14bf761..000000000
--- a/src/ats/gnunet-ats-solver-eval.h
+++ /dev/null
@@ -1,335 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010-2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file ats-tests/ats-testing-experiment.c
22 * @brief ats benchmark: controlled experiment execution
23 * @author Christian Grothoff
24 * @author Matthias Wachs
25 */
26#ifndef GNUNET_ATS_SOLVER_EVAL_H
27#define GNUNET_ATS_SOLVER_EVAL_H
28
29#include "platform.h"
30#include "gnunet_util_lib.h"
31#include "gnunet_ats_plugin.h"
32#include "gnunet_ats_service.h"
33#include "gnunet-service-ats_addresses.h"
34#include "gnunet-service-ats_normalization.h"
35#include "test_ats_api_common.h"
36
37enum GeneratorType
38{
39 GNUNET_ATS_TEST_TG_LINEAR,
40 GNUNET_ATS_TEST_TG_CONSTANT,
41 GNUNET_ATS_TEST_TG_RANDOM,
42 GNUNET_ATS_TEST_TG_SINUS
43};
44
45
46enum OperationType
47{
48 SOLVER_OP_ADD_ADDRESS,
49 SOLVER_OP_DEL_ADDRESS,
50 SOLVER_OP_START_SET_PROPERTY,
51 SOLVER_OP_STOP_SET_PROPERTY,
52 SOLVER_OP_START_SET_PREFERENCE,
53 SOLVER_OP_STOP_SET_PREFERENCE,
54 SOLVER_OP_START_REQUEST,
55 SOLVER_OP_STOP_REQUEST,
56};
57
58struct SolverHandle
59{
60 /**
61 * Solver plugin name
62 */
63 char *plugin;
64
65 /**
66 * Solver environment
67 */
68 struct GNUNET_ATS_PluginEnvironment env;
69
70 /**
71 * Solver handle
72 */
73 struct GNUNET_ATS_SolverFunctions *sf;
74
75 /**
76 * Address hashmap
77 */
78 struct GNUNET_CONTAINER_MultiPeerMap *addresses;
79};
80
81enum GNUNET_ATS_Solvers
82{
83 GNUNET_ATS_SOLVER_PROPORTIONAL,
84 GNUNET_ATS_SOLVER_MLP,
85 GNUNET_ATS_SOLVER_RIL,
86};
87
88struct LoggingFileHandle
89{
90 /* DLL list for logging time steps */
91 struct LoggingFileHandle *next;
92 struct LoggingFileHandle *prev;
93
94 /* peer id */
95 long long unsigned int pid;
96
97 /* address id */
98 long long unsigned int aid;
99
100 struct GNUNET_DISK_FileHandle *f_hd;
101};
102
103struct LoggingTimeStep
104{
105 struct LoggingTimeStep *prev;
106 struct LoggingTimeStep *next;
107
108 struct LoggingPeer *head;
109 struct LoggingPeer *tail;
110
111 struct GNUNET_TIME_Absolute timestamp;
112 struct GNUNET_TIME_Relative delta;
113};
114
115struct LoggingPeer
116{
117 struct LoggingPeer *prev;
118 struct LoggingPeer *next;
119
120 long long unsigned int id;
121 struct GNUNET_PeerIdentity peer_id;
122 double pref_abs[GNUNET_ATS_PREFERENCE_END];
123 double pref_norm[GNUNET_ATS_PREFERENCE_END];
124 int is_requested;
125
126 struct LoggingAddress *addr_head;
127 struct LoggingAddress *addr_tail;
128};
129
130struct LoggingAddress
131{
132 struct LoggingAddress *next;
133 struct LoggingAddress *prev;
134
135 long long unsigned int aid;
136 int active;
137 uint32_t network;
138 uint32_t assigned_bw_in;
139 uint32_t assigned_bw_out;
140
141 double prop_abs[GNUNET_ATS_PropertyCount];
142 double prop_norm[GNUNET_ATS_PropertyCount];
143};
144
145
146struct TestPeer
147{
148 struct TestPeer *prev;
149 struct TestPeer *next;
150
151
152 long long unsigned int id;
153 int is_requested;
154 struct GNUNET_PeerIdentity peer_id;
155
156 double pref_abs[GNUNET_ATS_PreferenceCount];
157 double pref_norm[GNUNET_ATS_PreferenceCount];
158
159 uint32_t assigned_bw_in;
160 uint32_t assigned_bw_out;
161
162 struct TestAddress *addr_head;
163 struct TestAddress *addr_tail;
164};
165
166
167struct TestAddress
168{
169 struct TestAddress *next;
170 struct TestAddress *prev;
171
172 long long unsigned int aid;
173 struct ATS_Address *ats_addr;
174 uint32_t network;
175
176 double prop_abs[GNUNET_ATS_PropertyCount];
177 double prop_norm[GNUNET_ATS_PropertyCount];
178};
179
180struct Episode;
181
182struct Experiment;
183
184typedef void (*GNUNET_ATS_TESTING_EpisodeDoneCallback) (
185 struct Episode *e);
186
187typedef void (*GNUNET_ATS_TESTING_ExperimentDoneCallback) (struct Experiment *e,
188 struct
189 GNUNET_TIME_Relative
190 duration, int
191 success);
192
193/**
194 * An operation in an experiment
195 */
196struct GNUNET_ATS_TEST_Operation
197{
198 struct GNUNET_ATS_TEST_Operation *next;
199 struct GNUNET_ATS_TEST_Operation *prev;
200
201 long long unsigned int address_id;
202 long long unsigned int peer_id;
203 long long unsigned int client_id;
204
205 long long unsigned int address_session;
206 unsigned int address_network;
207 char*address;
208 char*plugin;
209
210
211 long long unsigned int base_rate;
212 long long unsigned int max_rate;
213 struct GNUNET_TIME_Relative period;
214 struct GNUNET_TIME_Relative frequency;
215 struct GNUNET_TIME_Relative feedback_delay;
216
217 enum OperationType type;
218 enum GeneratorType gen_type;
219 enum GNUNET_ATS_PreferenceKind pref_type;
220 // enum GNUNET_ATS_Property prop_type;
221};
222
223struct Episode
224{
225 int id;
226 struct Episode *next;
227 struct GNUNET_TIME_Relative duration;
228
229 struct GNUNET_ATS_TEST_Operation *head;
230 struct GNUNET_ATS_TEST_Operation *tail;
231};
232
233struct LoggingHandle
234{
235 struct GNUNET_SCHEDULER_Task *logging_task;
236 struct GNUNET_TIME_Relative log_freq;
237
238 /* DLL list for logging time steps */
239 struct LoggingTimeStep *head;
240 struct LoggingTimeStep *tail;
241};
242
243struct Experiment
244{
245 char *name;
246 char *log_prefix;
247 char *cfg_file;
248 char *log_output_dir;
249 int log_append_time_stamp;
250
251 struct GNUNET_TIME_Relative log_freq;
252 struct GNUNET_TIME_Relative max_duration;
253 struct GNUNET_TIME_Relative total_duration;
254 struct GNUNET_TIME_Absolute start_time;
255 unsigned int num_episodes;
256 struct Episode *start;
257
258 struct GNUNET_CONFIGURATION_Handle *cfg;
259
260 struct GNUNET_SCHEDULER_Task *experiment_timeout_task;
261 struct GNUNET_SCHEDULER_Task *episode_timeout_task;
262 struct Episode *cur;
263
264 GNUNET_ATS_TESTING_EpisodeDoneCallback ep_done_cb;
265 GNUNET_ATS_TESTING_ExperimentDoneCallback e_done_cb;
266};
267
268struct PreferenceGenerator
269{
270 struct PreferenceGenerator *prev;
271 struct PreferenceGenerator *next;
272
273 enum GeneratorType type;
274
275 long long unsigned int peer;
276 unsigned int client_id;
277
278 enum GNUNET_ATS_PreferenceKind kind;
279
280 long int base_value;
281 long int max_value;
282 struct GNUNET_TIME_Relative duration_period;
283 struct GNUNET_TIME_Relative frequency;
284 struct GNUNET_TIME_Relative feedback_frequency;
285
286 struct GNUNET_SCHEDULER_Task *set_task;
287 struct GNUNET_SCHEDULER_Task *feedback_task;
288 struct GNUNET_TIME_Absolute next_ping_transmission;
289 struct GNUNET_TIME_Absolute time_start;
290
291
292 /* Feedback */
293 uint32_t feedback_bw_out_acc;
294 uint32_t feedback_bw_in_acc;
295 uint32_t feedback_delay_acc;
296
297 double pref_bw_old;
298 double pref_latency_old;
299
300 struct GNUNET_TIME_Absolute feedback_last;
301
302 struct GNUNET_TIME_Absolute feedback_last_bw_update;
303 struct GNUNET_TIME_Absolute feedback_last_delay_update;
304 uint32_t last_assigned_bw_in;
305 uint32_t last_assigned_bw_out;
306 double last_delay_value;
307};
308
309
310struct PropertyGenerator
311{
312 struct PropertyGenerator *prev;
313 struct PropertyGenerator *next;
314
315 enum GeneratorType type;
316
317 long long unsigned int peer;
318 long long unsigned int address_id;
319
320 struct TestPeer *test_peer;
321 struct TestAddress *test_address;
322 uint32_t ats_property;
323
324 long int base_value;
325 long int max_value;
326 struct GNUNET_TIME_Relative duration_period;
327 struct GNUNET_TIME_Relative frequency;
328
329 struct GNUNET_SCHEDULER_Task *set_task;
330 struct GNUNET_TIME_Absolute next_ping_transmission;
331 struct GNUNET_TIME_Absolute time_start;
332};
333
334#endif /* #ifndef GNUNET_ATS_SOLVER_EVAL_H */
335/* end of file ats-testing.h */
diff --git a/src/ats/gnunet-service-ats.c b/src/ats/gnunet-service-ats.c
deleted file mode 100644
index 5e27ecbd0..000000000
--- a/src/ats/gnunet-service-ats.c
+++ /dev/null
@@ -1,538 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file ats/gnunet-service-ats.c
22 * @brief ats service
23 * @author Matthias Wachs
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet-service-ats.h"
29#include "gnunet-service-ats_addresses.h"
30#include "gnunet-service-ats_connectivity.h"
31#include "gnunet-service-ats_normalization.h"
32#include "gnunet-service-ats_performance.h"
33#include "gnunet-service-ats_preferences.h"
34#include "gnunet-service-ats_scheduling.h"
35#include "gnunet-service-ats_reservations.h"
36#include "gnunet-service-ats_plugins.h"
37#include "ats.h"
38
39/**
40 * Handle for statistics.
41 */
42struct GNUNET_STATISTICS_Handle *GSA_stats;
43
44
45/**
46 * We have received a `struct ClientStartMessage` from a client. Find
47 * out which type of client it is and notify the respective subsystem.
48 *
49 * @param cls handle to the client
50 * @param msg the start message
51 */
52static void
53handle_ats_start (void *cls,
54 const struct ClientStartMessage *msg)
55{
56 struct GNUNET_SERVICE_Client *client = cls;
57 enum StartFlag flag;
58
59 flag = ntohl (msg->start_flag);
60 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
61 "Received ATS_START (%d) message\n",
62 (int) flag);
63 switch (flag)
64 {
65 case START_FLAG_SCHEDULING:
66 if (GNUNET_OK !=
67 GAS_scheduling_add_client (client))
68 {
69 GNUNET_SERVICE_client_drop (client);
70 return;
71 }
72 break;
73
74 case START_FLAG_PERFORMANCE_WITH_PIC:
75 GAS_performance_add_client (client,
76 flag);
77 break;
78
79 case START_FLAG_PERFORMANCE_NO_PIC:
80 GAS_performance_add_client (client,
81 flag);
82 break;
83
84 case START_FLAG_CONNECTION_SUGGESTION:
85 /* This client won't receive messages from us, no need to 'add' */
86 break;
87
88 default:
89 GNUNET_break (0);
90 GNUNET_SERVICE_client_drop (client);
91 return;
92 }
93 GNUNET_SERVICE_client_continue (client);
94}
95
96
97/**
98 * Handle 'reservation request' messages from clients.
99 *
100 * @param cls client that sent the request
101 * @param message the request message
102 */
103static void
104handle_reservation_request (void *cls,
105 const struct ReservationRequestMessage *message)
106{
107 struct GNUNET_SERVICE_Client *client = cls;
108
109 GAS_handle_reservation_request (client,
110 message);
111 GNUNET_SERVICE_client_continue (client);
112}
113
114
115/**
116 * Check 'preference feedback' message is well-formed
117 *
118 * @param cls client that sent the request
119 * @param message the request message
120 * @return #GNUNET_OK if @a message is well-formed
121 */
122static int
123check_feedback (void *cls,
124 const struct FeedbackPreferenceMessage *message)
125{
126 uint16_t msize;
127 uint32_t nump;
128
129 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
130 "Received PREFERENCE_FEEDBACK message\n");
131 msize = ntohs (message->header.size);
132 nump = ntohl (message->num_feedback);
133 if (msize !=
134 sizeof(struct FeedbackPreferenceMessage)
135 + nump * sizeof(struct PreferenceInformation))
136 {
137 GNUNET_break (0);
138 return GNUNET_SYSERR;
139 }
140 return GNUNET_OK;
141}
142
143
144/**
145 * Handle 'preference feedback' messages from clients.
146 *
147 * @param cls client that sent the request
148 * @param msg the request message
149 */
150static void
151handle_feedback (void *cls,
152 const struct FeedbackPreferenceMessage *msg)
153{
154 struct GNUNET_SERVICE_Client *client = cls;
155 const struct PreferenceInformation *pi;
156 uint32_t nump;
157
158 nump = ntohl (msg->num_feedback);
159 if (GNUNET_NO ==
160 GNUNET_CONTAINER_multipeermap_contains (GSA_addresses,
161 &msg->peer))
162 {
163 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
164 "Received PREFERENCE FEEDBACK for unknown peer `%s'\n",
165 GNUNET_i2s (&msg->peer));
166 GNUNET_SERVICE_client_continue (client);
167 return;
168 }
169
170 GNUNET_STATISTICS_update (GSA_stats,
171 "# preference feedbacks requests processed",
172 1,
173 GNUNET_NO);
174 pi = (const struct PreferenceInformation *) &msg[1];
175 for (uint32_t i = 0; i < nump; i++)
176 {
177 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
178 "Received PREFERENCE FEEDBACK for peer `%s'\n",
179 GNUNET_i2s (&msg->peer));
180 GAS_plugin_notify_feedback (client,
181 &msg->peer,
182 GNUNET_TIME_relative_ntoh (msg->scope),
183 (enum GNUNET_ATS_PreferenceKind) ntohl (
184 pi[i].preference_kind),
185 pi[i].preference_value);
186 }
187 GNUNET_SERVICE_client_continue (client);
188}
189
190
191/**
192 * Handle 'request address list' messages from clients.
193 *
194 * @param cls client that sent the request
195 * @param message the request message
196 */
197static void
198handle_request_address_list (void *cls,
199 const struct AddressListRequestMessage *message)
200{
201 struct GNUNET_SERVICE_Client *client = cls;
202
203 GAS_handle_request_address_list (client,
204 message);
205 GNUNET_SERVICE_client_continue (client);
206}
207
208
209/**
210 * Handle 'request address' messages from clients.
211 *
212 * @param cls client that sent the request
213 * @param message the request message
214 */
215static void
216handle_request_address (void *cls,
217 const struct RequestAddressMessage *message)
218{
219 struct GNUNET_SERVICE_Client *client = cls;
220
221 GAS_handle_request_address (client,
222 message);
223 GNUNET_SERVICE_client_continue (client);
224}
225
226
227/**
228 * Cancel 'request address' messages from clients.
229 *
230 * @param cls client that sent the request
231 * @param message the request message
232 */
233static void
234handle_request_address_cancel (void *cls,
235 const struct RequestAddressMessage *message)
236{
237 struct GNUNET_SERVICE_Client *client = cls;
238
239 GAS_handle_request_address_cancel (client,
240 message);
241 GNUNET_SERVICE_client_continue (client);
242}
243
244
245/**
246 * Handle 'address add' messages from clients.
247 *
248 * @param cls client that sent the request
249 * @param m the request message
250 */
251static int
252check_address_add (void *cls,
253 const struct AddressAddMessage *m)
254{
255 const char *address;
256 const char *plugin_name;
257 uint16_t address_length;
258 uint16_t plugin_name_length;
259 uint16_t size;
260
261 size = ntohs (m->header.size);
262 address_length = ntohs (m->address_length);
263 plugin_name_length = ntohs (m->plugin_name_length);
264 address = (const char *) &m[1];
265 if (plugin_name_length != 0)
266 plugin_name = &address[address_length];
267 else
268 plugin_name = "";
269
270 if ((address_length + plugin_name_length
271 + sizeof(struct AddressAddMessage) != size) ||
272 ((plugin_name_length > 0) &&
273 (plugin_name[plugin_name_length - 1] != '\0')))
274 {
275 GNUNET_break (0);
276 return GNUNET_SYSERR;
277 }
278 return GNUNET_OK;
279}
280
281
282/**
283 * Handle 'address add' messages from clients.
284 *
285 * @param cls client that sent the request
286 * @param message the request message
287 */
288static void
289handle_address_add (void *cls,
290 const struct AddressAddMessage *message)
291{
292 struct GNUNET_SERVICE_Client *client = cls;
293
294 GAS_handle_address_add (message);
295 GNUNET_SERVICE_client_continue (client);
296}
297
298
299/**
300 * Handle 'address update' messages from clients.
301 *
302 * @param cls client that sent the request
303 * @param message the request message
304 */
305static void
306handle_address_update (void *cls,
307 const struct AddressUpdateMessage *message)
308{
309 struct GNUNET_SERVICE_Client *client = cls;
310
311 GAS_handle_address_update (message);
312 GNUNET_SERVICE_client_continue (client);
313}
314
315
316/**
317 * Handle 'address destroyed' messages from clients.
318 *
319 * @param cls client that sent the request
320 * @param message the request message
321 */
322static void
323handle_address_destroyed (void *cls,
324 const struct AddressDestroyedMessage *message)
325{
326 struct GNUNET_SERVICE_Client *client = cls;
327
328 GAS_handle_address_destroyed (message);
329 GNUNET_SERVICE_client_continue (client);
330}
331
332
333/**
334 * Check that 'change preference' message is well-formed.
335 *
336 * @param cls client that sent the request
337 * @param message the request message
338 * @return #GNUNET_OK if @a message is well-formed
339 */
340static int
341check_preference_change (void *cls,
342 const struct ChangePreferenceMessage *message)
343{
344 uint16_t msize;
345 uint32_t nump;
346
347 msize = ntohs (message->header.size);
348 nump = ntohl (message->num_preferences);
349 if ((msize !=
350 sizeof(struct ChangePreferenceMessage)
351 + nump * sizeof(struct PreferenceInformation)) ||
352 (UINT16_MAX / sizeof(struct PreferenceInformation) < nump))
353 {
354 GNUNET_break (0);
355 return GNUNET_SYSERR;
356 }
357 return GNUNET_OK;
358}
359
360
361/**
362 * Handle 'change preference' messages from clients.
363 *
364 * @param cls client that sent the request
365 * @param message the request message
366 */
367static void
368handle_preference_change (void *cls,
369 const struct ChangePreferenceMessage *message)
370{
371 struct GNUNET_SERVICE_Client *client = cls;
372
373 GAS_handle_preference_change (client,
374 message);
375 GNUNET_SERVICE_client_continue (client);
376}
377
378
379/**
380 * A client connected to us. Setup the local client
381 * record.
382 *
383 * @param cls unused
384 * @param client handle of the client
385 * @param mq message queue to talk to @a client
386 * @return @a client
387 */
388static void *
389client_connect_cb (void *cls,
390 struct GNUNET_SERVICE_Client *client,
391 struct GNUNET_MQ_Handle *mq)
392{
393 return client;
394}
395
396
397/**
398 * A client disconnected from us. Tear down the local client
399 * record.
400 *
401 * @param cls unused
402 * @param client handle of the client
403 * @param app_ctx
404 */
405static void
406client_disconnect_cb (void *cls,
407 struct GNUNET_SERVICE_Client *client,
408 void *app_ctx)
409{
410 if (NULL == client)
411 return;
412 GAS_scheduling_remove_client (client);
413 GAS_connectivity_remove_client (client);
414 GAS_preference_client_disconnect (client);
415}
416
417
418/**
419 * Task run during shutdown.
420 *
421 * @param cls unused
422 */
423static void
424cleanup_task (void *cls)
425{
426 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
427 "ATS shutdown initiated\n");
428 GAS_connectivity_done ();
429 GAS_addresses_done ();
430 GAS_plugin_done ();
431 GAS_normalization_stop ();
432 GAS_performance_done ();
433 GAS_preference_done ();
434 GAS_reservations_done ();
435 if (NULL != GSA_stats)
436 {
437 GNUNET_STATISTICS_destroy (GSA_stats, GNUNET_NO);
438 GSA_stats = NULL;
439 }
440}
441
442
443/**
444 * Process template requests.
445 *
446 * @param cls closure
447 * @param cfg configuration to use
448 * @param service the initialized service
449 */
450static void
451run (void *cls,
452 const struct GNUNET_CONFIGURATION_Handle *cfg,
453 struct GNUNET_SERVICE_Handle *service)
454{
455 GSA_stats = GNUNET_STATISTICS_create ("ats",
456 cfg);
457 GAS_reservations_init ();
458 GAS_connectivity_init ();
459 GAS_preference_init ();
460 GAS_normalization_start ();
461 GAS_addresses_init ();
462 if (GNUNET_OK !=
463 GAS_plugin_init (cfg))
464 {
465 GNUNET_break (0);
466 GAS_addresses_done ();
467 GAS_normalization_stop ();
468 GAS_reservations_done ();
469 GAS_connectivity_done ();
470 GAS_preference_done ();
471 if (NULL != GSA_stats)
472 {
473 GNUNET_STATISTICS_destroy (GSA_stats,
474 GNUNET_NO);
475 GSA_stats = NULL;
476 }
477 return;
478 }
479 GAS_performance_init ();
480 GNUNET_SCHEDULER_add_shutdown (&cleanup_task,
481 NULL);
482}
483
484
485/**
486 * Define "main" method using service macro.
487 */
488GNUNET_SERVICE_MAIN
489 ("ats",
490 GNUNET_SERVICE_OPTION_NONE,
491 &run,
492 &client_connect_cb,
493 &client_disconnect_cb,
494 NULL,
495 GNUNET_MQ_hd_fixed_size (ats_start,
496 GNUNET_MESSAGE_TYPE_ATS_START,
497 struct ClientStartMessage,
498 NULL),
499 GNUNET_MQ_hd_fixed_size (request_address,
500 GNUNET_MESSAGE_TYPE_ATS_REQUEST_ADDRESS,
501 struct RequestAddressMessage,
502 NULL),
503 GNUNET_MQ_hd_fixed_size (request_address_cancel,
504 GNUNET_MESSAGE_TYPE_ATS_REQUEST_ADDRESS_CANCEL,
505 struct RequestAddressMessage,
506 NULL),
507 GNUNET_MQ_hd_fixed_size (request_address_list,
508 GNUNET_MESSAGE_TYPE_ATS_ADDRESSLIST_REQUEST,
509 struct AddressListRequestMessage,
510 NULL),
511 GNUNET_MQ_hd_var_size (address_add,
512 GNUNET_MESSAGE_TYPE_ATS_ADDRESS_ADD,
513 struct AddressAddMessage,
514 NULL),
515 GNUNET_MQ_hd_fixed_size (address_update,
516 GNUNET_MESSAGE_TYPE_ATS_ADDRESS_UPDATE,
517 struct AddressUpdateMessage,
518 NULL),
519 GNUNET_MQ_hd_fixed_size (address_destroyed,
520 GNUNET_MESSAGE_TYPE_ATS_ADDRESS_DESTROYED,
521 struct AddressDestroyedMessage,
522 NULL),
523 GNUNET_MQ_hd_fixed_size (reservation_request,
524 GNUNET_MESSAGE_TYPE_ATS_RESERVATION_REQUEST,
525 struct ReservationRequestMessage,
526 NULL),
527 GNUNET_MQ_hd_var_size (preference_change,
528 GNUNET_MESSAGE_TYPE_ATS_PREFERENCE_CHANGE,
529 struct ChangePreferenceMessage,
530 NULL),
531 GNUNET_MQ_hd_var_size (feedback,
532 GNUNET_MESSAGE_TYPE_ATS_PREFERENCE_FEEDBACK,
533 struct FeedbackPreferenceMessage,
534 NULL),
535 GNUNET_MQ_handler_end ());
536
537
538/* end of gnunet-service-ats.c */
diff --git a/src/ats/gnunet-service-ats.h b/src/ats/gnunet-service-ats.h
deleted file mode 100644
index 85d522b9f..000000000
--- a/src/ats/gnunet-service-ats.h
+++ /dev/null
@@ -1,42 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file ats/gnunet-service-ats.h
23 * @brief ats service
24 * @author Matthias Wachs
25 * @author Christian Grothoff
26 */
27#ifndef GNUNET_SERVICE_ATS_H
28#define GNUNET_SERVICE_ATS_H
29
30#include "gnunet_statistics_service.h"
31
32#define GAS_normalization_queue_length 3
33
34#define BANDWIDTH_ZERO GNUNET_BANDWIDTH_value_init (0)
35
36/**
37 * Handle for statistics.
38 */
39extern struct GNUNET_STATISTICS_Handle *GSA_stats;
40
41
42#endif
diff --git a/src/ats/gnunet-service-ats_addresses.c b/src/ats/gnunet-service-ats_addresses.c
deleted file mode 100644
index 9c9856094..000000000
--- a/src/ats/gnunet-service-ats_addresses.c
+++ /dev/null
@@ -1,686 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011-2015 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file ats/gnunet-service-ats_addresses.c
23 * @brief ats service address management
24 * @author Matthias Wachs
25 * @author Christian Grothoff
26 */
27#include "platform.h"
28#include "gnunet-service-ats_addresses.h"
29#include "gnunet-service-ats_performance.h"
30#include "gnunet-service-ats_normalization.h"
31#include "gnunet-service-ats_plugins.h"
32
33
34/**
35 * A multihashmap to store all addresses
36 */
37struct GNUNET_CONTAINER_MultiPeerMap *GSA_addresses;
38
39
40/**
41 * Update statistic on number of addresses.
42 */
43static void
44update_addresses_stat ()
45{
46 GNUNET_STATISTICS_set (GSA_stats,
47 "# addresses",
48 GNUNET_CONTAINER_multipeermap_size (GSA_addresses),
49 GNUNET_NO);
50}
51
52
53/**
54 * Free the given address
55 *
56 * @param addr address to destroy
57 */
58static void
59free_address (struct ATS_Address *addr)
60{
61 GNUNET_assert (GNUNET_YES ==
62 GNUNET_CONTAINER_multipeermap_remove (GSA_addresses,
63 &addr->peer,
64 addr));
65 update_addresses_stat ();
66 GAS_plugin_delete_address (addr);
67 GAS_performance_notify_all_clients (&addr->peer,
68 addr->plugin,
69 addr->addr,
70 addr->addr_len,
71 GNUNET_NO,
72 NULL,
73 addr->local_address_info,
74 GNUNET_BANDWIDTH_ZERO,
75 GNUNET_BANDWIDTH_ZERO);
76 GNUNET_free (addr->plugin);
77 GNUNET_free (addr);
78}
79
80
81/**
82 * Initialize @a norm. Sets all historic values to undefined.
83 *
84 * @param norm normalization data to initialize
85 */
86static void
87init_norm (struct GAS_NormalizationInfo *norm)
88{
89 unsigned int c;
90
91 for (c = 0; c < GAS_normalization_queue_length; c++)
92 norm->atsi_abs[c] = UINT64_MAX;
93}
94
95
96/**
97 * Create a ATS_address with the given information
98 *
99 * @param peer peer
100 * @param plugin_name plugin
101 * @param plugin_addr address
102 * @param plugin_addr_len address length
103 * @param local_address_info additional local info for the address
104 * @param session_id session identifier, can never be 0
105 * @return the ATS_Address
106 */
107static struct ATS_Address *
108create_address (const struct GNUNET_PeerIdentity *peer,
109 const char *plugin_name,
110 const void *plugin_addr,
111 size_t plugin_addr_len,
112 uint32_t local_address_info,
113 uint32_t session_id)
114{
115 struct ATS_Address *aa;
116
117 aa = GNUNET_malloc (sizeof(struct ATS_Address) + plugin_addr_len);
118 aa->peer = *peer;
119 aa->addr_len = plugin_addr_len;
120 aa->addr = &aa[1];
121 GNUNET_memcpy (&aa[1],
122 plugin_addr,
123 plugin_addr_len);
124 aa->plugin = GNUNET_strdup (plugin_name);
125 aa->session_id = session_id;
126 aa->local_address_info = local_address_info;
127 init_norm (&aa->norm_delay);
128 init_norm (&aa->norm_distance);
129 init_norm (&aa->norm_utilization_in);
130 init_norm (&aa->norm_utilization_out);
131 return aa;
132}
133
134
135/**
136 * Closure for #find_address_cb()
137 */
138struct FindAddressContext
139{
140 /**
141 * Session Id to look for.
142 */
143 uint32_t session_id;
144
145 /**
146 * Where to store matching address result.
147 */
148 struct ATS_Address *exact_address;
149};
150
151
152/**
153 * Find session matching given session ID.
154 *
155 * @param cls a `struct FindAddressContext`
156 * @param key peer id
157 * @param value the address to compare with
158 * @return #GNUNET_YES to continue, #GNUNET_NO if address is found
159 */
160static int
161find_address_cb (void *cls,
162 const struct GNUNET_PeerIdentity *key,
163 void *value)
164{
165 struct FindAddressContext *fac = cls;
166 struct ATS_Address *aa = value;
167
168 if (aa->session_id == fac->session_id)
169 {
170 fac->exact_address = aa;
171 return GNUNET_NO;
172 }
173 return GNUNET_YES;
174}
175
176
177/**
178 * Find the exact address
179 *
180 * @param peer peer
181 * @param session_id session id, can never be 0
182 * @return an ATS_address or NULL
183 */
184static struct ATS_Address *
185find_exact_address (const struct GNUNET_PeerIdentity *peer,
186 uint32_t session_id)
187{
188 struct FindAddressContext fac;
189
190 fac.exact_address = NULL;
191 fac.session_id = session_id;
192 GNUNET_CONTAINER_multipeermap_get_multiple (GSA_addresses,
193 peer,
194 &find_address_cb, &fac);
195 return fac.exact_address;
196}
197
198
199void
200GAS_addresses_add (const struct GNUNET_PeerIdentity *peer,
201 const char *plugin_name,
202 const void *plugin_addr,
203 size_t plugin_addr_len,
204 uint32_t local_address_info,
205 uint32_t session_id,
206 const struct GNUNET_ATS_Properties *prop)
207{
208 struct ATS_Address *new_address;
209
210 if (NULL != find_exact_address (peer,
211 session_id))
212 {
213 GNUNET_break (0);
214 return;
215 }
216 GNUNET_break (GNUNET_NT_UNSPECIFIED != prop->scope);
217 new_address = create_address (peer,
218 plugin_name,
219 plugin_addr,
220 plugin_addr_len,
221 local_address_info,
222 session_id);
223 /* Add a new address */
224 new_address->properties = *prop;
225 new_address->t_added = GNUNET_TIME_absolute_get ();
226 new_address->t_last_activity = GNUNET_TIME_absolute_get ();
227 GNUNET_assert (GNUNET_OK ==
228 GNUNET_CONTAINER_multipeermap_put (GSA_addresses,
229 peer,
230 new_address,
231 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
232 update_addresses_stat ();
233 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
234 "Adding new address for peer `%s' slot %u\n",
235 GNUNET_i2s (peer),
236 session_id);
237 /* Tell solver about new address */
238 GAS_plugin_solver_lock ();
239 GAS_plugin_new_address (new_address);
240 GAS_normalization_update_property (new_address); // FIXME: needed?
241 GAS_plugin_solver_unlock ();
242 /* Notify performance clients about new address */
243 GAS_performance_notify_all_clients (&new_address->peer,
244 new_address->plugin,
245 new_address->addr,
246 new_address->addr_len,
247 new_address->active,
248 &new_address->properties,
249 new_address->local_address_info,
250 GNUNET_BANDWIDTH_value_init (
251 new_address->assigned_bw_out),
252 GNUNET_BANDWIDTH_value_init (
253 new_address->assigned_bw_in));
254}
255
256
257void
258GAS_addresses_update (const struct GNUNET_PeerIdentity *peer,
259 uint32_t session_id,
260 const struct GNUNET_ATS_Properties *prop)
261{
262 struct ATS_Address *aa;
263
264 /* Get existing address */
265 aa = find_exact_address (peer,
266 session_id);
267 if (NULL == aa)
268 {
269 GNUNET_break (0);
270 return;
271 }
272 if (NULL == aa->solver_information)
273 {
274 GNUNET_break (0);
275 return;
276 }
277 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
278 "Received ADDRESS_UPDATE for peer `%s' slot %u\n",
279 GNUNET_i2s (peer),
280 (unsigned int) session_id);
281 GNUNET_break (GNUNET_NT_UNSPECIFIED != prop->scope);
282 /* Update address */
283 aa->t_last_activity = GNUNET_TIME_absolute_get ();
284 aa->properties = *prop;
285 /* Notify performance clients about updated address */
286 GAS_performance_notify_all_clients (&aa->peer,
287 aa->plugin,
288 aa->addr,
289 aa->addr_len,
290 aa->active,
291 prop,
292 aa->local_address_info,
293 GNUNET_BANDWIDTH_value_init (
294 aa->assigned_bw_out),
295 GNUNET_BANDWIDTH_value_init (
296 aa->assigned_bw_in));
297
298 GAS_normalization_update_property (aa);
299}
300
301
302/**
303 * Remove an address for a peer.
304 *
305 * @param peer peer
306 * @param session_id session id, can never be 0
307 */
308void
309GAS_addresses_destroy (const struct GNUNET_PeerIdentity *peer,
310 uint32_t session_id)
311{
312 struct ATS_Address *ea;
313
314 /* Get existing address */
315 ea = find_exact_address (peer,
316 session_id);
317 if (NULL == ea)
318 {
319 GNUNET_break (0);
320 return;
321 }
322 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
323 "Received ADDRESS_DESTROYED for peer `%s' session %u\n",
324 GNUNET_i2s (peer),
325 session_id);
326 free_address (ea);
327}
328
329
330/**
331 * Initialize address subsystem. The addresses subsystem manages the addresses
332 * known and current performance information. It has a solver component
333 * responsible for the resource allocation. It tells the solver about changes
334 * and receives updates when the solver changes the resource allocation.
335 */
336void
337GAS_addresses_init ()
338{
339 GSA_addresses
340 = GNUNET_CONTAINER_multipeermap_create (128,
341 GNUNET_NO);
342 update_addresses_stat ();
343}
344
345
346/**
347 * Destroy all addresses iterator
348 *
349 * @param cls NULL
350 * @param key peer identity (unused)
351 * @param value the 'struct ATS_Address' to free
352 * @return #GNUNET_OK (continue to iterate)
353 */
354static int
355destroy_all_address_it (void *cls,
356 const struct GNUNET_PeerIdentity *key,
357 void *value)
358{
359 struct ATS_Address *aa = value;
360
361 free_address (aa);
362 return GNUNET_OK;
363}
364
365
366/**
367 * Remove all addresses
368 */
369void
370GAS_addresses_destroy_all ()
371{
372 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
373 "Destroying all addresses\n");
374 if (NULL == GSA_addresses)
375 return;
376 if (0 ==
377 GNUNET_CONTAINER_multipeermap_size (GSA_addresses))
378 return;
379 GAS_plugin_solver_lock ();
380 GNUNET_CONTAINER_multipeermap_iterate (GSA_addresses,
381 &destroy_all_address_it,
382 NULL);
383 GAS_plugin_solver_unlock ();
384}
385
386
387/**
388 * Shutdown address subsystem.
389 */
390void
391GAS_addresses_done ()
392{
393 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
394 "Shutting down addresses\n");
395 GAS_plugin_solver_lock ();
396 GAS_addresses_destroy_all ();
397 GAS_plugin_solver_unlock ();
398 GNUNET_CONTAINER_multipeermap_destroy (GSA_addresses);
399 GSA_addresses = NULL;
400}
401
402
403/**
404 * Closure for #peerinfo_it().
405 */
406struct PeerInfoIteratorContext
407{
408 /**
409 * Function to call for each address.
410 */
411 GNUNET_ATS_PeerInfo_Iterator it;
412
413 /**
414 * Closure for @e it.
415 */
416 void *it_cls;
417};
418
419
420/**
421 * Iterator to iterate over a peer's addresses
422 *
423 * @param cls a `struct PeerInfoIteratorContext`
424 * @param key the peer id
425 * @param value the `struct ATS_address`
426 * @return #GNUNET_OK to continue
427 */
428static int
429peerinfo_it (void *cls,
430 const struct GNUNET_PeerIdentity *key,
431 void *value)
432{
433 struct PeerInfoIteratorContext *pi_ctx = cls;
434 struct ATS_Address *addr = value;
435
436 pi_ctx->it (pi_ctx->it_cls,
437 &addr->peer,
438 addr->plugin,
439 addr->addr,
440 addr->addr_len,
441 addr->active,
442 &addr->properties,
443 addr->local_address_info,
444 GNUNET_BANDWIDTH_value_init (addr->assigned_bw_out),
445 GNUNET_BANDWIDTH_value_init (addr->assigned_bw_in));
446 return GNUNET_OK;
447}
448
449
450void
451GAS_addresses_get_peer_info (const struct GNUNET_PeerIdentity *peer,
452 GNUNET_ATS_PeerInfo_Iterator pi_it,
453 void *pi_it_cls)
454{
455 struct PeerInfoIteratorContext pi_ctx;
456
457 if (NULL == pi_it)
458 {
459 /* does not make sense without callback */
460 GNUNET_break (0);
461 return;
462 }
463 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
464 "Returning information for %s from a total of %u known addresses\n",
465 (NULL == peer)
466 ? "all peers"
467 : GNUNET_i2s (peer),
468 (unsigned int) GNUNET_CONTAINER_multipeermap_size (
469 GSA_addresses));
470 pi_ctx.it = pi_it;
471 pi_ctx.it_cls = pi_it_cls;
472 if (NULL == peer)
473 GNUNET_CONTAINER_multipeermap_iterate (GSA_addresses,
474 &peerinfo_it,
475 &pi_ctx);
476 else
477 GNUNET_CONTAINER_multipeermap_get_multiple (GSA_addresses,
478 peer,
479 &peerinfo_it, &pi_ctx);
480 pi_it (pi_it_cls,
481 NULL, NULL, NULL, 0,
482 GNUNET_NO,
483 NULL,
484 GNUNET_HELLO_ADDRESS_INFO_NONE,
485 GNUNET_BANDWIDTH_ZERO,
486 GNUNET_BANDWIDTH_ZERO);
487}
488
489
490/**
491 * Information we need for the callbacks to return a list of addresses
492 * back to the client.
493 */
494struct AddressIteration
495{
496 /**
497 * Actual handle to the client.
498 */
499 struct GNUNET_SERVICE_Client *client;
500
501 /**
502 * Are we sending all addresses, or only those that are active?
503 */
504 int all;
505
506 /**
507 * Which ID should be included in the response?
508 */
509 uint32_t id;
510};
511
512
513/**
514 * Send a #GNUNET_MESSAGE_TYPE_ATS_ADDRESSLIST_RESPONSE with the
515 * given address details to the client identified in @a ai.
516 *
517 * @param ai our address information context (identifies the client)
518 * @param id the peer id this address is for
519 * @param plugin_name name of the plugin that supports this address
520 * @param plugin_addr address
521 * @param plugin_addr_len length of @a plugin_addr
522 * @param active #GNUNET_YES if this address is actively used
523 * @param prop performance information
524 * @param local_address_info flags for the address
525 * @param bandwidth_out current outbound bandwidth assigned to address
526 * @param bandwidth_in current inbound bandwidth assigned to address
527 */
528static void
529transmit_req_addr (struct AddressIteration *ai,
530 const struct GNUNET_PeerIdentity *id,
531 const char *plugin_name,
532 const void *plugin_addr,
533 size_t plugin_addr_len,
534 int active,
535 const struct GNUNET_ATS_Properties *prop,
536 enum GNUNET_HELLO_AddressInfo local_address_info,
537 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
538 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in)
539
540{
541 struct GNUNET_MQ_Envelope *env;
542 struct PeerInformationMessage *msg;
543 char *addrp;
544 size_t plugin_name_length;
545 size_t msize;
546
547 if (NULL != plugin_name)
548 plugin_name_length = strlen (plugin_name) + 1;
549 else
550 plugin_name_length = 0;
551 msize = plugin_addr_len + plugin_name_length;
552
553 GNUNET_assert (sizeof(struct PeerInformationMessage) + msize
554 < GNUNET_MAX_MESSAGE_SIZE);
555 env = GNUNET_MQ_msg_extra (msg,
556 msize,
557 GNUNET_MESSAGE_TYPE_ATS_ADDRESSLIST_RESPONSE);
558 msg->id = htonl (ai->id);
559 if (NULL != id)
560 msg->peer = *id;
561 msg->address_length = htons (plugin_addr_len);
562 msg->address_active = ntohl (active);
563 msg->plugin_name_length = htons (plugin_name_length);
564 msg->bandwidth_out = bandwidth_out;
565 msg->bandwidth_in = bandwidth_in;
566 if (NULL != prop)
567 GNUNET_ATS_properties_hton (&msg->properties,
568 prop);
569 msg->address_local_info = htonl ((uint32_t) local_address_info);
570 addrp = (char *) &msg[1];
571 GNUNET_memcpy (addrp,
572 plugin_addr,
573 plugin_addr_len);
574 if (NULL != plugin_name)
575 strcpy (&addrp[plugin_addr_len],
576 plugin_name);
577 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (ai->client),
578 env);
579}
580
581
582/**
583 * Iterator for #GAS_addresses_get_peer_info(), called with peer-specific
584 * information to be passed back to the client.
585 *
586 * @param cls closure with our `struct AddressIteration *`
587 * @param id the peer id
588 * @param plugin_name plugin name
589 * @param plugin_addr address
590 * @param plugin_addr_len length of @a plugin_addr
591 * @param active is address actively used
592 * @param prop performance information
593 * @param local_address_info additional local info for the address
594 * @param bandwidth_out current outbound bandwidth assigned to address
595 * @param bandwidth_in current inbound bandwidth assigned to address
596 */
597static void
598req_addr_peerinfo_it (void *cls,
599 const struct GNUNET_PeerIdentity *id,
600 const char *plugin_name,
601 const void *plugin_addr,
602 size_t plugin_addr_len,
603 int active,
604 const struct GNUNET_ATS_Properties *prop,
605 enum GNUNET_HELLO_AddressInfo local_address_info,
606 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
607 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in)
608{
609 struct AddressIteration *ai = cls;
610
611 if ((NULL == id) &&
612 (NULL == plugin_name) &&
613 (NULL == plugin_addr))
614 {
615 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
616 "Address iteration done for one peer\n");
617 return;
618 }
619 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
620 "Callback for %s peer `%s' plugin `%s' BW out %u, BW in %u\n",
621 (active == GNUNET_YES) ? "ACTIVE" : "INACTIVE",
622 GNUNET_i2s (id),
623 plugin_name,
624 (unsigned int) ntohl (bandwidth_out.value__),
625 (unsigned int) ntohl (bandwidth_in.value__));
626 /* Transmit result (either if address is active, or if
627 client wanted all addresses) */
628 if ((GNUNET_YES != ai->all) &&
629 (GNUNET_YES != active))
630 return;
631 transmit_req_addr (ai,
632 id,
633 plugin_name,
634 plugin_addr, plugin_addr_len,
635 active,
636 prop,
637 local_address_info,
638 bandwidth_out,
639 bandwidth_in);
640}
641
642
643void
644GAS_handle_request_address_list (struct GNUNET_SERVICE_Client *client,
645 const struct AddressListRequestMessage *alrm)
646{
647 struct AddressIteration ai;
648 struct GNUNET_PeerIdentity allzeros;
649
650 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
651 "Received ADDRESSLIST_REQUEST message\n");
652 ai.all = ntohl (alrm->all);
653 ai.id = ntohl (alrm->id);
654 ai.client = client;
655
656 memset (&allzeros,
657 '\0',
658 sizeof(struct GNUNET_PeerIdentity));
659 if (GNUNET_YES == GNUNET_is_zero (&alrm->peer))
660 {
661 /* Return addresses for all peers */
662 GAS_addresses_get_peer_info (NULL,
663 &req_addr_peerinfo_it,
664 &ai);
665 }
666 else
667 {
668 /* Return addresses for a specific peer */
669 GAS_addresses_get_peer_info (&alrm->peer,
670 &req_addr_peerinfo_it,
671 &ai);
672 }
673 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
674 "Finished handling `%s' message\n",
675 "ADDRESSLIST_REQUEST");
676 transmit_req_addr (&ai,
677 NULL, NULL, NULL,
678 0, GNUNET_NO,
679 NULL,
680 GNUNET_HELLO_ADDRESS_INFO_NONE,
681 GNUNET_BANDWIDTH_ZERO,
682 GNUNET_BANDWIDTH_ZERO);
683}
684
685
686/* end of gnunet-service-ats_addresses.c */
diff --git a/src/ats/gnunet-service-ats_addresses.h b/src/ats/gnunet-service-ats_addresses.h
deleted file mode 100644
index 8e6f40f38..000000000
--- a/src/ats/gnunet-service-ats_addresses.h
+++ /dev/null
@@ -1,490 +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 it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file ats/gnunet-service-ats_addresses.h
23 * @brief ats service address management
24 * @author Matthias Wachs
25 * @author Christian Grothoff
26 */
27#ifndef GNUNET_SERVICE_ATS_ADDRESSES_H
28#define GNUNET_SERVICE_ATS_ADDRESSES_H
29
30#include "gnunet_util_lib.h"
31#include "gnunet_ats_service.h"
32#include "gnunet-service-ats.h"
33#include "ats.h"
34
35/**
36 * NOTE: Do not change this documentation. This documentation is based on
37 * gnunet.org:/vcs/fsnsg/ats-paper.git/tech-doku/ats-tech-guide.tex
38 * use build_txt.sh to generate plaintext output
39 *
40 * 1 ATS addresses : ATS address management
41 *
42 * This ATS addresses ("addresses") component manages the addresses known to
43 * ATS service and suggests addresses to transport service when it is
44 * interested in address suggestion for a peer. ATS addresses also
45 * instantiates the bandwidth assignment mechanism (solver), notifies it
46 * about changes to addresses and forwards changes to bandwidth assignments
47 * to transport, depending if transport is interested in this change.
48 *
49 * 1.1 Input data
50 *
51 * 1.1.1 Addresses
52 *
53 * Addresses are added by specifying peer ID, plugin, address, address length
54 * and session, if available. ATS information can be specified if available.
55 *
56 * 1.1.2 Networks
57 *
58 * ATS specifies a fix set of networks an address can belong to. For each
59 * network an inbound and outbound quota will be specified. The available
60 * networks and additional helper variables are defined in
61 * gnunet_ats_service.h. At the moment 5 networks are defined:
62 * * GNUNET_NT_UNSPECIFIED
63 * * GNUNET_NT_LOOPBACK
64 * * GNUNET_NT_LAN
65 * * GNUNET_NT_WAN
66 * * GNUNET_NT_WLAN
67 *
68 * The total number of networks defined is stored in
69 * GNUNET_NT_COUNT GNUNET_ATS_NetworkType can be used array
70 * initializer for an int array, while GNUNET_ATS_NetworkType is an
71 * initializer for a char array containing a string description of all
72 * networks
73 *
74 * 1.1.3 Quotas
75 *
76 * An inbound and outbound quota for each of the networks mentioned in 1.1.2
77 * is loaded from ats configuration during initialization. This quota defines
78 * to total amount of inbound and outbound traffic allowed for a specific
79 * network. The configuration values used are in section ats:
80 * * "NETWORK"_QUOTA_IN = <value>
81 * * "NETWORK"_QUOTA_IN = <value>
82 *
83 * You can specify quotas by setting the <value> to a:
84 * * unrestricted: unlimited
85 * * number of bytes: e.g. 10240
86 * * fancy value: e.g. 64 Kib
87 *
88 * unlimited is defined as GNUNET_ATS_MaxBandwidthString and equivalent to
89 * the value GNUNET_ATS_MaxBandwidth Important predefined values for quotas
90 * are:
91 * * GNUNET_ATS_DefaultBandwidth: 65536
92 * * GNUNET_ATS_MaxBandwidth: UINT32_MAX
93 * * GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT: 1024
94 *
95 * Details of loading quotas and default values will be described on
96 *
97 * 1.1.4 Preference values
98 *
99 * 1.2 Data structures used
100 *
101 * Addresse uses struct ATS_Address for each address. The structs are stored
102 * in a linked list and provides a pointer void *solver_information for the
103 * solver to store address specific information. It provides the int values
104 * active which is set to GNUNET_YES if the address is select for transport
105 * use and used, representing that transport service is actively using this
106 * address. Address information are stored in peer, addr, addr_len, plugin.
107 *
108 * 1.3 Initialization
109 *
110 * During initialization a hashmap to store addresses is created. The quotas
111 * for all networks defined for ATS are loaded from configuration. For each
112 * network first the logic will check if the string
113 * GNUNET_ATS_MaxBandwidthString is configured, if not it will try to convert
114 * the configured value as a fancy size and if this fails it will try to use
115 * it as a value_number. If no configuration value is found it will assign
116 * GNUNET_ATS_DefaultBandwidth. The most important step is to load the
117 * configured solver using configuration "[ats]:MODE". Current solvers are
118 * MODE_PROPORTIONAL, MODE_MLP. Interaction is done using a solver API
119 *
120 * 1.4 Solver API
121 *
122 * Solver functions:
123 * * s_init: init the solver with required information
124 * * s_add: add a new address
125 * * s_update: update ATS values or session for an address
126 * * s_get: get preferred address for a peer
127 * * s_del: delete an address
128 * * s_pref: change preference value for a peer
129 * * s_done: shutdown solver
130 *
131 * Callbacks: addresses provides a bandwidth_changed_cb callback to the
132 * solver which is called when bandwidth assigned to peer has changed
133 *
134 * 1.5 Shutdown
135 *
136 * During shutdown all addresses are freed and the solver told to shutdown
137 *
138 * 1.6 Addresses and sessions
139 *
140 * Addresses consist of the address itself and a numerical session. When a
141 * new address without a session is added it has no session, so it gets
142 * session 0 assigned. When an address with a session is added and an address
143 * object with session 0 is found, this object is updated with the session
144 * otherwise a new address object with this session assigned is created.
145 *
146 * 1.6.1 Terminology
147 *
148 * Addresses a1,a2 with session s1, s2 are "exact" if:
149 * (a1 == a2)&&(s1 == s2)
150 * Addresses a1,a2 with session s1, s2 are "equivalent" if:
151 * (a1 == a2)&&((s1 == s2)||(s1 == 0)||(s2 == 0)
152 *
153 * 1.7 Address management
154 *
155 * Transport service notifies ATS about changes to the addresses known to
156 * it.
157 *
158 * 1.7.1 Adding an address
159 *
160 * When transport learns a new address it tells ATS and ATS is telling
161 * addresses about it using GAS_address_add. If not known to addresses it
162 * creates a new address object and calls solver's s_add. ATS information are
163 * deserialized and solver is notified about the session and ATS information
164 * using s_update.
165 *
166 * 1.7.2 Updating an address
167 *
168 * Addresses does an lookup up for the existing address with the given
169 * session. If disassembles included ATS information and notifies the solver
170 * using s_update about the update.
171 *
172 * 1.7.3 Deleting an address
173 *
174 * Addresses does an lookup for the exact address and session and if removes
175 * this address. If session != 0 the session is set to 0 and the address is
176 * kept. If session == 0, the addresses is removed.
177 *
178 * 1.7.4 Requesting an address suggestion
179 *
180 * The address client issues a request address message to be notified about
181 * address suggestions for a specific peer. Addresses asks the solver with
182 * s_get. If no address is available, it will not send a response, otherwise
183 * it will respond with the chosen address.
184 *
185 * 1.7.5 Address suggestions
186 *
187 * Addresses will notify the client automatically on any bandwidth_changed_cb
188 * by the solver if a address suggestion request is pending. If no address is
189 * available it will not respond at all If the client is not interested
190 * anymore, it has to cancel the address suggestion request.
191 *
192 * 1.7.6 Suggestions blocks and reset
193 *
194 * After suggesting an address it is blocked for ATS_BLOCKING_DELTA sec. to
195 * prevent the client from being thrashed. If the client requires immediately
196 * it can reset this block using GAS_addresses_handle_backoff_reset.
197 *
198 * 1.7.7 Address lifecycle
199 *
200 * * (add address)
201 * * (updated address)
202 * * (delete address)
203 *
204 * 1.8 Bandwidth assignment
205 *
206 * The addresses are used to perform resource allocation operations. ATS
207 * addresses takes care of instantiating the solver configured and notifies
208 * the respective solver about address changes and receives changes to the
209 * bandwidth assignment from the solver. The current bandwidth assignment is
210 * sent to transport. The specific solvers will be described in the specific
211 * section.
212 *
213 * 1.9 Changing peer preferences
214 *
215 * The bandwidth assigned to a peer can be influenced by setting a preference
216 * for a peer. The preference will be given to to the solver with s_pref which
217 * has to take care of the preference value
218 */
219
220
221/*
222 * How long will address suggestions blocked after a suggestion
223 */
224#define ATS_BLOCKING_DELTA GNUNET_TIME_relative_multiply ( \
225 GNUNET_TIME_UNIT_MILLISECONDS, 100)
226
227/**
228 * Information provided by ATS normalization
229 */
230struct GAS_NormalizationInfo
231{
232 /**
233 * Next index to use in averaging queue
234 */
235 unsigned int avg_queue_index;
236
237 /**
238 * Averaging queue
239 */
240 uint64_t atsi_abs[GAS_normalization_queue_length];
241
242 /**
243 * Averaged ATSI values from queue
244 */
245 uint64_t avg;
246
247 /**
248 * Normalized values from queue to a range of values [1.0...2.0]
249 */
250 double norm;
251};
252
253
254/**
255 * Address with additional information
256 */
257struct ATS_Address
258{
259 /**
260 * Peer ID this address is for.
261 */
262 struct GNUNET_PeerIdentity peer;
263
264 /**
265 * Address (in plugin-specific binary format).
266 */
267 const void *addr;
268
269 /**
270 * Plugin name
271 */
272 char *plugin;
273
274 /**
275 * Solver-specific information for this address
276 */
277 void *solver_information;
278
279 /**
280 * ATS performance information for this address
281 */
282 struct GNUNET_ATS_Properties properties;
283
284 /**
285 * Time when address had last activity (update, in uses)
286 */
287 struct GNUNET_TIME_Absolute t_last_activity;
288
289 /**
290 * Time when address was added
291 */
292 struct GNUNET_TIME_Absolute t_added;
293
294 /**
295 * Address length, number of bytes in @e addr.
296 */
297 size_t addr_len;
298
299 /**
300 * Session ID, can never be 0.
301 */
302 uint32_t session_id;
303
304 /**
305 * Field to store local flags.
306 */
307 enum GNUNET_HELLO_AddressInfo local_address_info;
308
309 /**
310 * ATS performance information for this address, size of the @e atsi array.
311 */
312 uint32_t atsi_count;
313
314 /**
315 * Inbound bandwidth assigned by solver
316 */
317 uint32_t assigned_bw_in;
318
319 /**
320 * Outbound bandwidth assigned by solver
321 */
322 uint32_t assigned_bw_out;
323
324 /**
325 * Inbound bandwidth assigned by solver in NBO
326 */
327 uint32_t last_notified_bw_in;
328
329 /**
330 * Outbound bandwidth assigned by solver in NBO
331 */
332 uint32_t last_notified_bw_out;
333
334 /**
335 * Is this the active address for this peer?
336 */
337 int active;
338
339 /**
340 * Normalized delay information for this address.
341 */
342 struct GAS_NormalizationInfo norm_delay;
343
344 /**
345 * Normalized distance information for this address.
346 */
347 struct GAS_NormalizationInfo norm_distance;
348
349 /**
350 * Normalized utilization inbound for this address.
351 */
352 struct GAS_NormalizationInfo norm_utilization_in;
353
354 /**
355 * Normalized utilization outbound for this address.
356 */
357 struct GAS_NormalizationInfo norm_utilization_out;
358};
359
360
361/**
362 * A multipeermap mapping peer identities to `struct ATS_Address`.
363 */
364extern struct GNUNET_CONTAINER_MultiPeerMap *GSA_addresses;
365
366
367/**
368 * Initialize address subsystem. The addresses subsystem manages the addresses
369 * known and current performance information.
370 */
371void
372GAS_addresses_init (void);
373
374
375/**
376 * Shutdown address subsystem.
377 */
378void
379GAS_addresses_done (void);
380
381
382/**
383 * Add a new address for a peer.
384 *
385 * @param peer peer
386 * @param plugin_name transport plugin name
387 * @param plugin_addr plugin address
388 * @param plugin_addr_len length of the @a plugin_addr
389 * @param local_address_info the local address for the address
390 * @param session_id session id, can never be 0.
391 * @param prop performance information for this address
392 */
393void
394GAS_addresses_add (const struct GNUNET_PeerIdentity *peer,
395 const char *plugin_name,
396 const void *plugin_addr,
397 size_t plugin_addr_len,
398 uint32_t local_address_info,
399 uint32_t session_id,
400 const struct GNUNET_ATS_Properties *prop);
401
402
403/**
404 * Update an address with new performance information for a peer.
405 *
406 * @param peer peer
407 * @param session_id session id, can never be 0
408 * @param prop performance information for this address
409 */
410void
411GAS_addresses_update (const struct GNUNET_PeerIdentity *peer,
412 uint32_t session_id,
413 const struct GNUNET_ATS_Properties *prop);
414
415
416/**
417 * Remove an address for a peer.
418 *
419 * @param peer peer
420 * @param session_id session id, can never be 0
421 */
422void
423GAS_addresses_destroy (const struct GNUNET_PeerIdentity *peer,
424 uint32_t session_id);
425
426
427/**
428 * Remove all addresses.
429 */
430void
431GAS_addresses_destroy_all (void);
432
433
434/**
435 * Iterator for #GAS_addresses_get_peer_info()
436 *
437 * @param cls closure
438 * @param id the peer id
439 * @param plugin_name plugin name
440 * @param plugin_addr address
441 * @param plugin_addr_len length of @a plugin_addr
442 * @param address_active is address actively used
443 * @param atsi ats performance information
444 * @param local_address_info flags for the address
445 * @param bandwidth_out current outbound bandwidth assigned to address
446 * @param bandwidth_in current inbound bandwidth assigned to address
447 */
448typedef void
449(*GNUNET_ATS_PeerInfo_Iterator) (void *cls,
450 const struct GNUNET_PeerIdentity *id,
451 const char *plugin_name,
452 const void *plugin_addr,
453 size_t plugin_addr_len,
454 const int address_active,
455 const struct GNUNET_ATS_Properties *prop,
456 enum GNUNET_HELLO_AddressInfo
457 local_address_info,
458 struct GNUNET_BANDWIDTH_Value32NBO
459 bandwidth_out,
460 struct GNUNET_BANDWIDTH_Value32NBO
461 bandwidth_in);
462
463
464/**
465 * Return information all peers currently known to ATS
466 *
467 * @param peer the respective peer, NULL for 'all' peers
468 * @param pi_it the iterator to call for every peer
469 * @param pi_it_cls the closure for @a pi_it
470 */
471void
472GAS_addresses_get_peer_info (const struct GNUNET_PeerIdentity *peer,
473 GNUNET_ATS_PeerInfo_Iterator pi_it,
474 void *pi_it_cls);
475
476
477/**
478 * Handle 'address list request' messages from clients.
479 *
480 * @param client client that sent the request
481 * @param alrm the request message
482 */
483void
484GAS_handle_request_address_list (struct GNUNET_SERVICE_Client *client,
485 const struct AddressListRequestMessage *alrm);
486
487
488#endif
489
490/* end of gnunet-service-ats_addresses.h */
diff --git a/src/ats/gnunet-service-ats_connectivity.c b/src/ats/gnunet-service-ats_connectivity.c
deleted file mode 100644
index 702c5ba87..000000000
--- a/src/ats/gnunet-service-ats_connectivity.c
+++ /dev/null
@@ -1,222 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011-2015 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file ats/gnunet-service-ats_connectivity.c
23 * @brief ats service, interaction with 'connecivity' API
24 * @author Matthias Wachs
25 * @author Christian Grothoff
26 */
27#include "platform.h"
28#include "gnunet-service-ats.h"
29#include "gnunet-service-ats_addresses.h"
30#include "gnunet-service-ats_connectivity.h"
31#include "gnunet-service-ats_plugins.h"
32#include "ats.h"
33
34
35/**
36 * Active connection requests.
37 */
38struct ConnectionRequest
39{
40 /**
41 * Client that made the request.
42 */
43 struct GNUNET_SERVICE_Client *client;
44
45 /* TODO: allow client to express a 'strength' for this request */
46};
47
48
49/**
50 * Address suggestion requests by peer.
51 */
52static struct GNUNET_CONTAINER_MultiPeerMap *connection_requests;
53
54
55/**
56 * Is the given peer in the list of peers for which we
57 * have an address request?
58 *
59 * @param cls unused, NULL
60 * @param peer peer to query for
61 * @return #GNUNET_YES if so, #GNUNET_NO if not
62 */
63unsigned int
64GAS_connectivity_has_peer (void *cls,
65 const struct GNUNET_PeerIdentity *peer)
66{
67 if (NULL == connection_requests)
68 return 0;
69 /* TODO: return sum of 'strength's of connectivity requests */
70 return GNUNET_CONTAINER_multipeermap_contains (connection_requests,
71 peer);
72}
73
74
75/**
76 * Handle #GNUNET_MESSAGE_TYPE_ATS_REQUEST_ADDRESS messages from clients.
77 *
78 * @param client client that sent the request
79 * @param msg the request message
80 */
81void
82GAS_handle_request_address (struct GNUNET_SERVICE_Client *client,
83 const struct RequestAddressMessage *msg)
84{
85 struct ConnectionRequest *cr;
86
87 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
88 "Received `%s' message\n",
89 "GNUNET_MESSAGE_TYPE_ATS_REQUEST_ADDRESS");
90 /* FIXME: should not ignore "msg->strength" */
91 cr = GNUNET_new (struct ConnectionRequest);
92 cr->client = client;
93 (void) GNUNET_CONTAINER_multipeermap_put (connection_requests,
94 &msg->peer,
95 cr,
96 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
97 GAS_plugin_request_connect_start (&msg->peer);
98}
99
100
101/**
102 * Free the connection request from the map if the
103 * closure matches the client.
104 *
105 * @param cls the client to match
106 * @param pid peer for which the request was made
107 * @param value the `struct ConnectionRequest`
108 * @return #GNUNET_OK (continue to iterate)
109 */
110static int
111free_matching_requests (void *cls,
112 const struct GNUNET_PeerIdentity *pid,
113 void *value)
114{
115 struct GNUNET_SERVICE_Client *client = cls;
116 struct ConnectionRequest *cr = value;
117
118 if (cr->client == client)
119 {
120 GAS_plugin_request_connect_stop (pid);
121 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
122 "Removed request pending for peer `%s\n",
123 GNUNET_i2s (pid));
124 GNUNET_assert (GNUNET_YES ==
125 GNUNET_CONTAINER_multipeermap_remove (connection_requests,
126 pid,
127 cr));
128 GNUNET_free (cr);
129 }
130 return GNUNET_OK;
131}
132
133
134/**
135 * Handle #GNUNET_MESSAGE_TYPE_ATS_REQUEST_ADDRESS_CANCEL messages
136 * from clients.
137 *
138 * @param client the client that sent the request
139 * @param msg the request message
140 */
141void
142GAS_handle_request_address_cancel (struct GNUNET_SERVICE_Client *client,
143 const struct RequestAddressMessage *msg)
144{
145 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
146 "Received GNUNET_MESSAGE_TYPE_ATS_REQUEST_ADDRESS_CANCEL message for peer %s\n",
147 GNUNET_i2s (&msg->peer));
148 GNUNET_break (0 == ntohl (msg->strength));
149 GNUNET_CONTAINER_multipeermap_get_multiple (connection_requests,
150 &msg->peer,
151 &free_matching_requests,
152 client);
153}
154
155
156/**
157 * Unregister a client (which may have been a connectivity client,
158 * but this is not assured).
159 *
160 * @param client handle of the (now dead) client
161 */
162void
163GAS_connectivity_remove_client (struct GNUNET_SERVICE_Client *client)
164{
165 if (NULL != connection_requests)
166 GNUNET_CONTAINER_multipeermap_iterate (connection_requests,
167 &free_matching_requests,
168 client);
169}
170
171
172/**
173 * Shutdown connectivity subsystem.
174 */
175void
176GAS_connectivity_init ()
177{
178 connection_requests
179 = GNUNET_CONTAINER_multipeermap_create (32,
180 GNUNET_NO);
181}
182
183
184/**
185 * Free the connection request from the map.
186 *
187 * @param cls NULL
188 * @param pid peer for which the request was made
189 * @param value the `struct ConnectionRequest`
190 * @return #GNUNET_OK (continue to iterate)
191 */
192static int
193free_request (void *cls,
194 const struct GNUNET_PeerIdentity *pid,
195 void *value)
196{
197 struct ConnectionRequest *cr = value;
198
199 free_matching_requests (cr->client,
200 pid,
201 cr);
202 return GNUNET_OK;
203}
204
205
206/**
207 * Shutdown connectivity subsystem.
208 */
209void
210GAS_connectivity_done ()
211{
212 GAS_plugin_solver_lock ();
213 GNUNET_CONTAINER_multipeermap_iterate (connection_requests,
214 &free_request,
215 NULL);
216 GAS_plugin_solver_unlock ();
217 GNUNET_CONTAINER_multipeermap_destroy (connection_requests);
218 connection_requests = NULL;
219}
220
221
222/* end of gnunet-service-ats_connectivity.c */
diff --git a/src/ats/gnunet-service-ats_connectivity.h b/src/ats/gnunet-service-ats_connectivity.h
deleted file mode 100644
index 39453dfc8..000000000
--- a/src/ats/gnunet-service-ats_connectivity.h
+++ /dev/null
@@ -1,92 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011-2015 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file ats/gnunet-service-ats_connectivity.h
22 * @brief ats service, interaction with 'connecivity' API
23 * @author Matthias Wachs
24 * @author Christian Grothoff
25 */
26#ifndef GNUNET_SERVICE_ATS_CONNECTIVITY_H
27#define GNUNET_SERVICE_ATS_CONNECTIVITY_H
28
29#include "ats.h"
30
31
32/**
33 * Is the given peer in the list of peers for which we
34 * have an address request?
35 *
36 * @param cls unused, NULL
37 * @param peer peer to query for
38 * @return #GNUNET_YES if so, #GNUNET_NO if not
39 */
40unsigned int
41GAS_connectivity_has_peer (void *cls,
42 const struct GNUNET_PeerIdentity *peer);
43
44
45/**
46 * Handle 'request address' messages from clients.
47 *
48 * @param client client that sent the request
49 * @param msg the request message
50 */
51void
52GAS_handle_request_address (struct GNUNET_SERVICE_Client *client,
53 const struct RequestAddressMessage *msg);
54
55
56/**
57 * Cancel 'request address' messages from clients.
58 *
59 * @param client client that sent the request
60 * @param msg the request message
61 */
62void
63GAS_handle_request_address_cancel (struct GNUNET_SERVICE_Client *client,
64 const struct RequestAddressMessage *msg);
65
66
67/**
68 * Unregister a client (which may have been a connectivity client,
69 * but this is not assured).
70 *
71 * @param client handle of the (now dead) client
72 */
73void
74GAS_connectivity_remove_client (struct GNUNET_SERVICE_Client *client);
75
76
77/**
78 * Initialize connectivity subsystem.
79 */
80void
81GAS_connectivity_init (void);
82
83
84/**
85 * Shutdown connectivity subsystem.
86 */
87void
88GAS_connectivity_done (void);
89
90
91#endif
92/* end of gnunet-service-ats_connectivity.h */
diff --git a/src/ats/gnunet-service-ats_normalization.c b/src/ats/gnunet-service-ats_normalization.c
deleted file mode 100644
index 36584e944..000000000
--- a/src/ats/gnunet-service-ats_normalization.c
+++ /dev/null
@@ -1,299 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011-2015 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file ats/gnunet-service-ats_normalization.c
23 * @brief ats service address: management of ATS properties and preferences normalization
24 * @author Matthias Wachs
25 * @author Christian Grothoff
26 */
27#include "platform.h"
28#include <float.h>
29#include "gnunet_ats_service.h"
30#include "gnunet-service-ats_addresses.h"
31#include "gnunet-service-ats_normalization.h"
32#include "gnunet-service-ats_plugins.h"
33
34#define LOG(kind, ...) GNUNET_log_from (kind, "ats-normalization", __VA_ARGS__)
35
36
37/**
38 * Range information for normalization of quality properties.
39 */
40struct PropertyRange
41{
42 /**
43 * Minimum value we see for this property across all addresses.
44 */
45 struct GNUNET_ATS_Properties min;
46
47 /**
48 * Maximum value we see for this property across all addresses.
49 */
50 struct GNUNET_ATS_Properties max;
51};
52
53
54/**
55 * Range information for all quality properties we see.
56 */
57static struct PropertyRange property_range;
58
59
60/**
61 * Add the value from @a atsi to the running average of the
62 * given @a ni quality property.
63 *
64 * @param current_val the updated value
65 * @param ni normalization information to update
66 */
67static void
68update_avg (uint64_t current_val,
69 struct GAS_NormalizationInfo *ni)
70{
71 double sum;
72 uint32_t count;
73 unsigned int c1;
74
75 ni->atsi_abs[ni->avg_queue_index++] = current_val;
76 if (GAS_normalization_queue_length == ni->avg_queue_index)
77 ni->avg_queue_index = 0;
78 count = 0;
79 sum = 0.0;
80 for (c1 = 0; c1 < GAS_normalization_queue_length; c1++)
81 {
82 if (UINT64_MAX != ni->atsi_abs[c1])
83 {
84 count++;
85 sum += (double) ni->atsi_abs[c1];
86 }
87 }
88 if (0 == count)
89 ni->avg = current_val; /* must be UINT64_MAX */
90 else
91 ni->avg = sum / count;
92}
93
94
95/**
96 * Function called for all addresses and peers to find the minimum and
97 * maximum (averaged) values for a given quality property. Given
98 * those, we can then calculate the normalized score.
99 *
100 * @param cls the `struct PropertyRange`
101 * @param h which peer are we looking at (ignored)
102 * @param k the address for that peer
103 * @return #GNUNET_OK (continue to iterate)
104 */
105static int
106find_min_max_it (void *cls,
107 const struct GNUNET_PeerIdentity *h,
108 void *k)
109{
110 struct PropertyRange *pr = cls;
111 const struct ATS_Address *a = k;
112
113 pr->max.utilization_out = GNUNET_MAX (pr->max.utilization_out,
114 a->properties.utilization_out);
115 pr->max.utilization_in = GNUNET_MAX (pr->max.utilization_in,
116 a->properties.utilization_in);
117 pr->max.distance = GNUNET_MAX (pr->max.distance,
118 a->properties.distance);
119 pr->max.delay = GNUNET_TIME_relative_max (pr->max.delay,
120 a->properties.delay);
121 pr->min.utilization_out = GNUNET_MIN (pr->min.utilization_out,
122 a->properties.utilization_out);
123 pr->min.utilization_in = GNUNET_MIN (pr->min.utilization_in,
124 a->properties.utilization_in);
125 pr->min.distance = GNUNET_MIN (pr->min.distance,
126 a->properties.distance);
127 pr->min.delay = GNUNET_TIME_relative_min (pr->min.delay,
128 a->properties.delay);
129 return GNUNET_OK;
130}
131
132
133/**
134 * Compute the normalized value from the given @a ni range
135 * data and the average value.
136 *
137 * @param min minimum value
138 * @param max maximum value
139 * @param ni normalization information to update
140 */
141static void
142update_norm (uint64_t min,
143 uint64_t max,
144 struct GAS_NormalizationInfo *ni)
145{
146 /* max - 2 * min + avg_value / (max - min) */
147 if (min < max)
148 ni->norm = DEFAULT_REL_QUALITY + (ni->avg - min) / (double) (max - min);
149 else
150 ni->norm = DEFAULT_REL_QUALITY;
151}
152
153
154/**
155 * Normalize the property value for a given address based
156 * on the range we know that property values have globally.
157 *
158 * @param cls NULL
159 * @param key which peer are we looking at (ignored)
160 * @param value the address for that peer, from where we get
161 * the original value and where we write the
162 * normalized value
163 * @return #GNUNET_OK (continue to iterate)
164 */
165static int
166normalize_address (void *cls,
167 const struct GNUNET_PeerIdentity *key,
168 void *value)
169{
170 struct ATS_Address *address = value;
171
172 update_norm (property_range.min.delay.rel_value_us,
173 property_range.max.delay.rel_value_us,
174 &address->norm_delay);
175 update_norm (property_range.min.distance,
176 property_range.max.distance,
177 &address->norm_distance);
178 update_norm (property_range.min.utilization_in,
179 property_range.max.utilization_in,
180 &address->norm_utilization_in);
181 update_norm (property_range.min.utilization_out,
182 property_range.max.utilization_out,
183 &address->norm_utilization_out);
184 return GNUNET_OK;
185}
186
187
188/**
189 * Notify about change in normalized property.
190 *
191 * @param cls NULL
192 * @param key which peer are we looking at (ignored)
193 * @param value the address for that peer
194 * @return #GNUNET_OK (continue to iterate)
195 */
196static int
197notify_change (void *cls,
198 const struct GNUNET_PeerIdentity *key,
199 void *value)
200{
201 struct ATS_Address *address = value;
202
203 GAS_plugin_notify_property_changed (address);
204 return GNUNET_OK;
205}
206
207
208/**
209 * Initialize property range to the values corresponding
210 * to an empty set.
211 *
212 * @param pr range to initialize
213 */
214static void
215init_range (struct PropertyRange *pr)
216{
217 memset (pr, 0, sizeof(struct PropertyRange));
218 pr->min.utilization_out = UINT32_MAX;
219 pr->min.utilization_in = UINT32_MAX;
220 pr->min.distance = UINT32_MAX;
221 pr->min.delay = GNUNET_TIME_UNIT_FOREVER_REL;
222}
223
224
225/**
226 * Update and normalize atsi performance information
227 *
228 * @param address the address to update
229 */
230void
231GAS_normalization_update_property (struct ATS_Address *address)
232{
233 const struct GNUNET_ATS_Properties *prop = &address->properties;
234 struct PropertyRange range;
235
236 LOG (GNUNET_ERROR_TYPE_DEBUG,
237 "Updating properties for peer `%s'\n",
238 GNUNET_i2s (&address->peer));
239 GAS_plugin_solver_lock ();
240 update_avg (prop->delay.rel_value_us,
241 &address->norm_delay);
242 update_avg (prop->distance,
243 &address->norm_distance);
244 update_avg (prop->utilization_in,
245 &address->norm_utilization_in);
246 update_avg (prop->utilization_in,
247 &address->norm_utilization_out);
248
249 init_range (&range);
250 GNUNET_CONTAINER_multipeermap_iterate (GSA_addresses,
251 &find_min_max_it,
252 &range);
253 if (0 != GNUNET_memcmp (&range,
254 &property_range))
255 {
256 /* limits changed, (re)normalize all addresses */
257 property_range = range;
258 GNUNET_CONTAINER_multipeermap_iterate (GSA_addresses,
259 &normalize_address,
260 NULL);
261 GNUNET_CONTAINER_multipeermap_iterate (GSA_addresses,
262 &notify_change,
263 NULL);
264 }
265 else
266 {
267 /* renormalize just this one address */
268 normalize_address (NULL,
269 &address->peer,
270 address);
271 notify_change (NULL,
272 &address->peer,
273 address);
274 }
275 GAS_plugin_solver_unlock ();
276}
277
278
279/**
280 * Start the normalization component
281 */
282void
283GAS_normalization_start ()
284{
285 init_range (&property_range);
286}
287
288
289/**
290 * Stop the normalization component and free all items
291 */
292void
293GAS_normalization_stop ()
294{
295 /* nothing to do */
296}
297
298
299/* end of gnunet-service-ats_normalization.c */
diff --git a/src/ats/gnunet-service-ats_normalization.h b/src/ats/gnunet-service-ats_normalization.h
deleted file mode 100644
index 9c02586c2..000000000
--- a/src/ats/gnunet-service-ats_normalization.h
+++ /dev/null
@@ -1,60 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file ats/gnunet-service-ats_normalization.h
23 * @brief ats service address: management of ATS properties and preferences normalization
24 * @author Matthias Wachs
25 * @author Christian Grothoff
26 */
27#ifndef GNUNET_SERVICE_ATS_NORMALIZATION_H
28#define GNUNET_SERVICE_ATS_NORMALIZATION_H
29#include "gnunet_ats_service.h"
30
31/**
32 * Value we return for a normalized quality score if we have no data.
33 */
34#define DEFAULT_REL_QUALITY 1.0
35
36
37/**
38 * Update and normalize a @a prop performance information
39 *
40 * @param address the address to update
41 */
42void
43GAS_normalization_update_property (struct ATS_Address *address);
44
45
46/**
47 * Start the normalization component
48 */
49void
50GAS_normalization_start (void);
51
52
53/**
54 * Stop the normalization component and free all items
55 */
56void
57GAS_normalization_stop (void);
58
59#endif
60/* end of gnunet-service-ats_normalization.h */
diff --git a/src/ats/gnunet-service-ats_performance.c b/src/ats/gnunet-service-ats_performance.c
deleted file mode 100644
index a4d7b36b6..000000000
--- a/src/ats/gnunet-service-ats_performance.c
+++ /dev/null
@@ -1,282 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011-2015 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file ats/gnunet-service-ats_performance.c
22 * @brief ats service, interaction with 'performance' API
23 * @author Matthias Wachs
24 * @author Christian Grothoff
25 *
26 * TODO:
27 * - simplify functions by passing a `struct GNUNET_HELLO_Address`
28 */
29#include "platform.h"
30#include "gnunet-service-ats.h"
31#include "gnunet-service-ats_addresses.h"
32#include "gnunet-service-ats_performance.h"
33#include "ats.h"
34
35
36/**
37 * Context for sending messages to performance clients without PIC.
38 */
39static struct GNUNET_NotificationContext *nc_no_pic;
40
41/**
42 * Context for sending messages to performance clients with PIC.
43 */
44static struct GNUNET_NotificationContext *nc_pic;
45
46
47/**
48 * Transmit the given performance information to all performance
49 * clients.
50 *
51 * @param client client to send to, NULL for all
52 * @param peer peer for which this is an address suggestion
53 * @param plugin_name 0-termintated string specifying the transport plugin
54 * @param plugin_addr binary address for the plugin to use
55 * @param plugin_addr_len number of bytes in plugin_addr
56 * @param active #GNUNET_YES if this address is actively used
57 * to maintain a connection to a peer;
58 * #GNUNET_NO if the address is not actively used;
59 * #GNUNET_SYSERR if this address is no longer available for ATS
60 * @param prop performance data for the address
61 * @param local_address_info information about the local flags for the address
62 * @param bandwidth_out assigned outbound bandwidth
63 * @param bandwidth_in assigned inbound bandwidth
64 */
65static void
66notify_client (struct GNUNET_SERVICE_Client *client,
67 const struct GNUNET_PeerIdentity *peer,
68 const char *plugin_name,
69 const void *plugin_addr,
70 size_t plugin_addr_len,
71 int active,
72 const struct GNUNET_ATS_Properties *prop,
73 enum GNUNET_HELLO_AddressInfo local_address_info,
74 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
75 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in)
76{
77 struct PeerInformationMessage *msg;
78 size_t plugin_name_length = strlen (plugin_name) + 1;
79 size_t msize =
80 sizeof(struct PeerInformationMessage)
81 + plugin_addr_len
82 + plugin_name_length;
83 char buf[msize] GNUNET_ALIGN;
84 char *addrp;
85
86 if (NULL != prop)
87 GNUNET_break (GNUNET_NT_UNSPECIFIED != prop->scope);
88 GNUNET_assert (msize < GNUNET_MAX_MESSAGE_SIZE);
89 msg = (struct PeerInformationMessage *) buf;
90 msg->header.size = htons (msize);
91 msg->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_PEER_INFORMATION);
92 msg->id = htonl (0);
93 msg->peer = *peer;
94 msg->address_length = htons (plugin_addr_len);
95 msg->address_active = ntohl ((uint32_t) active);
96 msg->plugin_name_length = htons (plugin_name_length);
97 msg->bandwidth_out = bandwidth_out;
98 msg->bandwidth_in = bandwidth_in;
99 if (NULL != prop)
100 GNUNET_ATS_properties_hton (&msg->properties,
101 prop);
102 else
103 memset (&msg->properties,
104 0,
105 sizeof(struct GNUNET_ATS_Properties));
106 msg->address_local_info = htonl (local_address_info);
107 addrp = (char *) &msg[1];
108 GNUNET_memcpy (addrp, plugin_addr, plugin_addr_len);
109 strcpy (&addrp[plugin_addr_len], plugin_name);
110 if (NULL == client)
111 {
112 GNUNET_notification_context_broadcast (nc_pic,
113 &msg->header,
114 GNUNET_YES);
115 }
116 else
117 {
118 struct GNUNET_MQ_Envelope *env;
119
120 env = GNUNET_MQ_msg_copy (&msg->header);
121 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
122 env);
123 }
124}
125
126
127/**
128 * Transmit the given performance information to all performance
129 * clients.
130 *
131 * @param peer peer for which this is an address suggestion
132 * @param plugin_name 0-termintated string specifying the transport plugin
133 * @param plugin_addr binary address for the plugin to use
134 * @param plugin_addr_len number of bytes in @a plugin_addr
135 * @param active #GNUNET_YES if this address is actively used
136 * to maintain a connection to a peer;
137 * #GNUNET_NO if the address is not actively used;
138 * #GNUNET_SYSERR if this address is no longer available for ATS
139 * @param prop performance data for the address
140 * @param local_address_info information about the local flags for the address
141 * @param bandwidth_out assigned outbound bandwidth
142 * @param bandwidth_in assigned inbound bandwidth
143 */
144void
145GAS_performance_notify_all_clients (const struct GNUNET_PeerIdentity *peer,
146 const char *plugin_name,
147 const void *plugin_addr,
148 size_t plugin_addr_len,
149 int active,
150 const struct GNUNET_ATS_Properties *prop,
151 enum GNUNET_HELLO_AddressInfo
152 local_address_info,
153 struct GNUNET_BANDWIDTH_Value32NBO
154 bandwidth_out,
155 struct GNUNET_BANDWIDTH_Value32NBO
156 bandwidth_in)
157{
158 GNUNET_break ((NULL == prop) ||
159 (GNUNET_NT_UNSPECIFIED != prop->scope));
160 notify_client (NULL,
161 peer,
162 plugin_name,
163 plugin_addr,
164 plugin_addr_len,
165 active,
166 prop,
167 local_address_info,
168 bandwidth_out,
169 bandwidth_in);
170 GNUNET_STATISTICS_update (GSA_stats,
171 "# performance updates given to clients",
172 1,
173 GNUNET_NO);
174}
175
176
177/**
178 * Iterator for called from #GAS_addresses_get_peer_info()
179 *
180 * @param cls closure with the `struct GNUNET_SERVICE_Client *` to inform.
181 * @param id the peer id
182 * @param plugin_name plugin name
183 * @param plugin_addr address
184 * @param plugin_addr_len length of @a plugin_addr
185 * @param active is address actively used
186 * @param prop performance information
187 * @param local_address_info information about the local flags for the address
188 * @param bandwidth_out current outbound bandwidth assigned to address
189 * @param bandwidth_in current inbound bandwidth assigned to address
190 */
191static void
192peerinfo_it (void *cls,
193 const struct GNUNET_PeerIdentity *id,
194 const char *plugin_name,
195 const void *plugin_addr,
196 size_t plugin_addr_len,
197 int active,
198 const struct GNUNET_ATS_Properties *prop,
199 enum GNUNET_HELLO_AddressInfo local_address_info,
200 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
201 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in)
202{
203 struct GNUNET_SERVICE_Client *client = cls;
204
205 if (NULL == id)
206 return;
207 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
208 "Callback for peer `%s' plugin `%s' BW out %u, BW in %u \n",
209 GNUNET_i2s (id),
210 plugin_name,
211 (unsigned int) ntohl (bandwidth_out.value__),
212 (unsigned int) ntohl (bandwidth_in.value__));
213 GNUNET_break (GNUNET_NT_UNSPECIFIED != prop->scope);
214 notify_client (client,
215 id,
216 plugin_name,
217 plugin_addr,
218 plugin_addr_len,
219 active,
220 prop,
221 local_address_info,
222 bandwidth_out,
223 bandwidth_in);
224}
225
226
227/**
228 * Register a new performance client.
229 *
230 * @param client handle of the new client
231 * @param flag flag specifying the type of the client
232 */
233void
234GAS_performance_add_client (struct GNUNET_SERVICE_Client *client,
235 enum StartFlag flag)
236{
237 struct GNUNET_MQ_Handle *mq;
238
239 mq = GNUNET_SERVICE_client_get_mq (client);
240 if (START_FLAG_PERFORMANCE_WITH_PIC == flag)
241 {
242 GNUNET_notification_context_add (nc_pic,
243 mq);
244 GAS_addresses_get_peer_info (NULL,
245 &peerinfo_it,
246 client);
247 }
248 else
249 {
250 GNUNET_notification_context_add (nc_no_pic,
251 mq);
252 }
253}
254
255
256/**
257 * Initialize performance subsystem.
258 *
259 * @param server handle to our server
260 */
261void
262GAS_performance_init ()
263{
264 nc_no_pic = GNUNET_notification_context_create (32);
265 nc_pic = GNUNET_notification_context_create (32);
266}
267
268
269/**
270 * Shutdown performance subsystem.
271 */
272void
273GAS_performance_done ()
274{
275 GNUNET_notification_context_destroy (nc_no_pic);
276 nc_no_pic = NULL;
277 GNUNET_notification_context_destroy (nc_pic);
278 nc_pic = NULL;
279}
280
281
282/* end of gnunet-service-ats_performance.c */
diff --git a/src/ats/gnunet-service-ats_performance.h b/src/ats/gnunet-service-ats_performance.h
deleted file mode 100644
index 292c27c95..000000000
--- a/src/ats/gnunet-service-ats_performance.h
+++ /dev/null
@@ -1,96 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011-2015 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file ats/gnunet-service-ats_performance.h
23 * @brief ats service, interaction with 'performance' API
24 * @author Matthias Wachs
25 * @author Christian Grothoff
26 */
27#ifndef GNUNET_SERVICE_ATS_PERFORMANCE_H
28#define GNUNET_SERVICE_ATS_PERFORMANCE_H
29
30#include "gnunet_util_lib.h"
31#include "gnunet_ats_service.h"
32#include "ats.h"
33
34
35/**
36 * Transmit the given performance information to all performance
37 * clients.
38 *
39 * @param peer peer for which this is an address suggestion
40 * @param plugin_name 0-termintated string specifying the transport plugin
41 * @param plugin_addr binary address for the plugin to use
42 * @param plugin_addr_len number of bytes in @a plugin_addr
43 * @param active #GNUNET_YES if this address is actively used
44 * to maintain a connection to a peer;
45 * #GNUNET_NO if the address is not actively used;
46 * #GNUNET_SYSERR if this address is no longer available for ATS
47 * @param prop performance data for the address
48 * @param local_address_info information about the local flags for the address
49 * @param bandwidth_out assigned outbound bandwidth
50 * @param bandwidth_in assigned inbound bandwidth
51 */
52void
53GAS_performance_notify_all_clients (const struct GNUNET_PeerIdentity *peer,
54 const char *plugin_name,
55 const void *plugin_addr,
56 size_t plugin_addr_len,
57 int active,
58 const struct GNUNET_ATS_Properties *prop,
59 enum GNUNET_HELLO_AddressInfo
60 local_address_info,
61 struct GNUNET_BANDWIDTH_Value32NBO
62 bandwidth_out,
63 struct GNUNET_BANDWIDTH_Value32NBO
64 bandwidth_in);
65
66
67/**
68 * Register a new performance client.
69 *
70 * @param client handle of the new client
71 * @param flag flag specifying the type of the client
72 */
73void
74GAS_performance_add_client (struct GNUNET_SERVICE_Client *client,
75 enum StartFlag flag);
76
77
78/**
79 * Initialize performance subsystem.
80 *
81 * @param server handle to our server
82 * @param addresses the address handle to use
83 */
84void
85GAS_performance_init (void);
86
87
88/**
89 * Shutdown performance subsystem.
90 */
91void
92GAS_performance_done (void);
93
94
95#endif
96/* end of gnunet-service-ats_performance.h */
diff --git a/src/ats/gnunet-service-ats_plugins.c b/src/ats/gnunet-service-ats_plugins.c
deleted file mode 100644
index d3db69caa..000000000
--- a/src/ats/gnunet-service-ats_plugins.c
+++ /dev/null
@@ -1,582 +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 it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file ats/gnunet-service-ats_plugins.c
23 * @brief ats service plugin management
24 * @author Matthias Wachs
25 * @author Christian Grothoff
26 */
27#include "platform.h"
28#include "gnunet_ats_plugin.h"
29#include "gnunet-service-ats_connectivity.h"
30#include "gnunet-service-ats_performance.h"
31#include "gnunet-service-ats_preferences.h"
32#include "gnunet-service-ats_plugins.h"
33#include "gnunet-service-ats_reservations.h"
34#include "gnunet-service-ats_scheduling.h"
35#include "gnunet-service-ats_normalization.h"
36
37
38/**
39 * Solver handle.
40 */
41static struct GNUNET_ATS_SolverFunctions *sf;
42
43/**
44 * Solver environment.
45 */
46static struct GNUNET_ATS_PluginEnvironment env;
47
48/**
49 * Solver plugin name as string
50 */
51static char *plugin;
52
53
54/**
55 * The preference changed for a peer, update solver.
56 *
57 * @param peer the peer
58 * @param kind the ATS kind
59 * @param pref_rel the new relative preference value
60 */
61void
62GAS_plugin_notify_preference_changed (const struct GNUNET_PeerIdentity *peer,
63 enum GNUNET_ATS_PreferenceKind kind,
64 double pref_rel)
65{
66 sf->s_pref (sf->cls,
67 peer,
68 kind,
69 pref_rel);
70}
71
72
73void
74GAS_plugin_notify_property_changed (struct ATS_Address *address)
75{
76 sf->s_address_update_property (sf->cls,
77 address);
78}
79
80
81/**
82 * Solver information callback
83 *
84 * @param cls the closure
85 * @param op the operation
86 * @param status operation status
87 * @param add additional information
88 */
89static void
90solver_info_cb (void *cls,
91 enum GAS_Solver_Operation op,
92 enum GAS_Solver_Status status,
93 enum GAS_Solver_Additional_Information add)
94{
95 const char *add_info;
96
97 switch (add)
98 {
99 case GAS_INFO_NONE:
100 add_info = "GAS_INFO_NONE";
101 break;
102
103 case GAS_INFO_FULL:
104 add_info = "GAS_INFO_MLP_FULL";
105 break;
106
107 case GAS_INFO_UPDATED:
108 add_info = "GAS_INFO_MLP_UPDATED";
109 break;
110
111 case GAS_INFO_PROP_ALL:
112 add_info = "GAS_INFO_PROP_ALL";
113 break;
114
115 case GAS_INFO_PROP_SINGLE:
116 add_info = "GAS_INFO_PROP_SINGLE";
117 break;
118
119 default:
120 add_info = "INVALID";
121 break;
122 }
123 switch (op)
124 {
125 case GAS_OP_SOLVE_START:
126 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
127 "Solver notifies `%s' with result `%s' `%s'\n",
128 "GAS_OP_SOLVE_START",
129 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL",
130 add_info);
131 return;
132
133 case GAS_OP_SOLVE_STOP:
134 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
135 "Solver notifies `%s' with result `%s'\n",
136 "GAS_OP_SOLVE_STOP",
137 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
138 return;
139
140 case GAS_OP_SOLVE_SETUP_START:
141 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
142 "Solver notifies `%s' with result `%s'\n",
143 "GAS_OP_SOLVE_SETUP_START",
144 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
145 return;
146
147 case GAS_OP_SOLVE_SETUP_STOP:
148 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
149 "Solver notifies `%s' with result `%s'\n",
150 "GAS_OP_SOLVE_SETUP_STOP",
151 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
152 return;
153
154 case GAS_OP_SOLVE_MLP_LP_START:
155 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
156 "Solver notifies `%s' with result `%s'\n",
157 "GAS_OP_SOLVE_LP_START",
158 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
159 return;
160
161 case GAS_OP_SOLVE_MLP_LP_STOP:
162 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
163 "Solver notifies `%s' with result `%s'\n",
164 "GAS_OP_SOLVE_LP_STOP",
165 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
166 return;
167
168 case GAS_OP_SOLVE_MLP_MLP_START:
169 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
170 "Solver notifies `%s' with result `%s'\n",
171 "GAS_OP_SOLVE_MLP_START",
172 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
173 return;
174
175 case GAS_OP_SOLVE_MLP_MLP_STOP:
176 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
177 "Solver notifies `%s' with result `%s'\n",
178 "GAS_OP_SOLVE_MLP_STOP",
179 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
180 return;
181
182 case GAS_OP_SOLVE_UPDATE_NOTIFICATION_START:
183 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
184 "Solver notifies `%s' with result `%s'\n",
185 "GAS_OP_SOLVE_UPDATE_NOTIFICATION_START",
186 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
187 return;
188
189 case GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP:
190 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
191 "Solver notifies `%s' with result `%s'\n",
192 "GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP",
193 (GAS_STAT_SUCCESS == status) ? "SUCCESS" : "FAIL");
194 return;
195
196 default:
197 GNUNET_break (0);
198 break;
199 }
200}
201
202
203/**
204 * Callback for solver to notify about assignment changes
205 *
206 * @param cls NULL
207 * @param address the address with changes
208 */
209static void
210bandwidth_changed_cb (void *cls,
211 struct ATS_Address *address)
212{
213 long long diff_out;
214 long long diff_in;
215
216 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
217 "Bandwidth assignment changed for peer %s to %u/%u\n",
218 GNUNET_i2s (&address->peer),
219 (unsigned int) address->assigned_bw_in,
220 (unsigned int) address->assigned_bw_out);
221 GAS_reservations_set_bandwidth (&address->peer,
222 GNUNET_BANDWIDTH_value_init (
223 address->assigned_bw_in));
224 /* Notify performance clients about changes to address */
225 GAS_performance_notify_all_clients (&address->peer,
226 address->plugin,
227 address->addr,
228 address->addr_len,
229 address->active,
230 &address->properties,
231 address->local_address_info,
232 GNUNET_BANDWIDTH_value_init (
233 address->assigned_bw_out),
234 GNUNET_BANDWIDTH_value_init (
235 address->assigned_bw_in));
236
237 if ((0 == address->assigned_bw_in) &&
238 (0 == address->assigned_bw_out))
239 {
240 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
241 "Telling transport to disconnect peer `%s'\n",
242 GNUNET_i2s (&address->peer));
243
244 /* Notify scheduling clients about suggestion */
245 GAS_scheduling_transmit_address_suggestion (&address->peer,
246 address->session_id,
247 GNUNET_BANDWIDTH_ZERO,
248 GNUNET_BANDWIDTH_ZERO);
249 return;
250 }
251
252 /* Do bandwidth stability check */
253 diff_out = llabs ((long long) address->assigned_bw_out
254 - (long long) address->last_notified_bw_out);
255 diff_in = llabs ((long long) address->assigned_bw_in
256 - (long long) address->last_notified_bw_in);
257 if ((diff_out < htonl (GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__)) &&
258 (diff_in < htonl (GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__)))
259 {
260 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
261 "Bandwidth change too small, not notifying client\n");
262 return;
263 }
264
265 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
266 "Sending bandwidth update for peer `%s': %u/%u\n",
267 GNUNET_i2s (&address->peer),
268 address->assigned_bw_out,
269 address->assigned_bw_out);
270
271 /* *Notify scheduling clients about suggestion */
272 GAS_scheduling_transmit_address_suggestion (&address->peer,
273 address->session_id,
274 GNUNET_BANDWIDTH_value_init (
275 address->assigned_bw_out),
276 GNUNET_BANDWIDTH_value_init (
277 address->assigned_bw_in));
278
279 address->last_notified_bw_out = address->assigned_bw_out;
280 address->last_notified_bw_in = address->assigned_bw_in;
281}
282
283
284/**
285 * Convert quota from text to numeric value.
286 *
287 * @param quota_str the value found in the configuration
288 * @param direction direction of the quota
289 * @param network network the quota applies to
290 * @return numeric quota value to use
291 */
292static unsigned long long
293parse_quota (const char *quota_str,
294 const char *direction,
295 enum GNUNET_NetworkType network)
296{
297 int res;
298 unsigned long long ret;
299
300 res = GNUNET_NO;
301 if (0 == strcmp (quota_str, GNUNET_ATS_MaxBandwidthString))
302 {
303 ret = GNUNET_ATS_MaxBandwidth;
304 res = GNUNET_YES;
305 }
306 if ((GNUNET_NO == res) &&
307 (GNUNET_OK ==
308 GNUNET_STRINGS_fancy_size_to_bytes (quota_str,
309 &ret)))
310 res = GNUNET_YES;
311 if ((GNUNET_NO == res) &&
312 (1 ==
313 sscanf (quota_str,
314 "%llu",
315 &ret)))
316 res = GNUNET_YES;
317 if (GNUNET_NO == res)
318 {
319 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
320 _ (
321 "Could not load %s quota for network `%s': `%s', assigning default bandwidth %llu\n"),
322 direction,
323 GNUNET_NT_to_string (network),
324 quota_str,
325 (unsigned long long) GNUNET_ATS_DefaultBandwidth);
326 ret = GNUNET_ATS_DefaultBandwidth;
327 }
328 else
329 {
330 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
331 _ ("%s quota configured for network `%s' is %llu\n"),
332 direction,
333 GNUNET_NT_to_string (network),
334 ret);
335 }
336 return ret;
337}
338
339
340/**
341 * Load quota value from the configuration @a cfg for the
342 * given network @a type and @a direction.
343 *
344 * @param cfg configuration to parse
345 * @param type network type to parse for
346 * @param direction traffic direction to parse for
347 * @return quota to apply
348 */
349static unsigned long long
350load_quota (const struct GNUNET_CONFIGURATION_Handle *cfg,
351 enum GNUNET_NetworkType type,
352 const char *direction)
353{
354 char *entry;
355 char *quota_str;
356 unsigned long long ret;
357
358 GNUNET_asprintf (&entry,
359 "%s_QUOTA_%s",
360 GNUNET_NT_to_string (type),
361 direction);
362 if (GNUNET_OK ==
363 GNUNET_CONFIGURATION_get_value_string (cfg,
364 "ats",
365 entry,
366 &quota_str))
367 {
368 ret = parse_quota (quota_str,
369 direction,
370 type);
371 GNUNET_free (quota_str);
372 }
373 else
374 {
375 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
376 _ (
377 "No %s-quota configured for network `%s', assigning default bandwidth %llu\n"),
378 direction,
379 GNUNET_NT_to_string (type),
380 (unsigned long long) GNUNET_ATS_DefaultBandwidth);
381 ret = GNUNET_ATS_DefaultBandwidth;
382 }
383 GNUNET_free (entry);
384 return ret;
385}
386
387
388/**
389 * Load quotas for networks from configuration
390 *
391 * @param cfg configuration handle
392 * @param out_dest where to write outbound quotas
393 * @param in_dest where to write inbound quotas
394 * @param dest_length length of inbound and outbound arrays
395 * @return number of networks loaded
396 */
397static unsigned int
398load_quotas (const struct GNUNET_CONFIGURATION_Handle *cfg,
399 unsigned long long *out_dest,
400 unsigned long long *in_dest,
401 int dest_length)
402{
403 unsigned int c;
404
405 for (c = 0; (c < GNUNET_NT_COUNT) && (c < dest_length); c++)
406 {
407 in_dest[c] = load_quota (cfg,
408 c,
409 "out");
410 out_dest[c] = load_quota (cfg,
411 c,
412 "in");
413 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
414 "Loaded quota for network `%s' (in/out): %llu %llu\n",
415 GNUNET_NT_to_string (c),
416 in_dest[c],
417 out_dest[c]);
418 }
419 return c;
420}
421
422
423int
424GAS_plugin_init (const struct GNUNET_CONFIGURATION_Handle *cfg)
425{
426 char *mode_str;
427
428 /* Figure out configured solution method */
429 if (GNUNET_SYSERR ==
430 GNUNET_CONFIGURATION_get_value_string (cfg,
431 "ats",
432 "MODE",
433 &mode_str))
434 {
435 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
436 "No resource assignment method configured, using proportional approach\n");
437 mode_str = GNUNET_strdup ("proportional");
438 }
439 env.cls = NULL;
440 env.info_cb = &solver_info_cb;
441 env.bandwidth_changed_cb = &bandwidth_changed_cb;
442 env.get_preferences = &GAS_preference_get_by_peer;
443 env.get_connectivity = &GAS_connectivity_has_peer;
444 env.cfg = cfg;
445 env.stats = GSA_stats;
446 env.addresses = GSA_addresses;
447 env.network_count = GNUNET_NT_COUNT;
448 load_quotas (cfg,
449 env.out_quota,
450 env.in_quota,
451 GNUNET_NT_COUNT);
452 GNUNET_asprintf (&plugin,
453 "libgnunet_plugin_ats_%s",
454 mode_str);
455 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
456 "Initializing solver `%s'\n",
457 mode_str);
458 GNUNET_free (mode_str);
459 if (NULL == (sf = GNUNET_PLUGIN_load (plugin, &env)))
460 {
461 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
462 _ ("Failed to initialize solver `%s'!\n"),
463 plugin);
464 return GNUNET_SYSERR;
465 }
466 return GNUNET_OK;
467}
468
469
470/**
471 * Shutdown address subsystem.
472 */
473void
474GAS_plugin_done ()
475{
476 GNUNET_PLUGIN_unload (plugin,
477 sf);
478 sf = NULL;
479 GNUNET_free (plugin);
480 plugin = NULL;
481}
482
483
484void
485GAS_plugin_new_address (struct ATS_Address *new_address)
486{
487 sf->s_add (sf->cls,
488 new_address,
489 new_address->properties.scope); /* FIXME: remove 3rd arg here! */
490}
491
492
493/**
494 * Tell the solver that the given address is no longer valid
495 * can cannot be used any longer.
496 *
497 * @param address address that was deleted
498 */
499void
500GAS_plugin_delete_address (struct ATS_Address *address)
501{
502 sf->s_del (sf->cls,
503 address);
504}
505
506
507/**
508 * Tell the solver that the given client has expressed its
509 * appreciation for the past performance of a given connection.
510 *
511 * @param application client providing the feedback
512 * @param peer peer the feedback is about
513 * @param scope timeframe the feedback applies to
514 * @param kind performance property the feedback relates to
515 * @param score_abs degree of the appreciation
516 */
517void
518GAS_plugin_notify_feedback (struct GNUNET_SERVICE_Client *application,
519 const struct GNUNET_PeerIdentity *peer,
520 const struct GNUNET_TIME_Relative scope,
521 enum GNUNET_ATS_PreferenceKind kind,
522 float score_abs)
523{
524 sf->s_feedback (sf->cls,
525 application,
526 peer,
527 scope,
528 kind,
529 score_abs);
530}
531
532
533/**
534 * Stop instant solving, there are many state updates
535 * happening in bulk right now.
536 */
537void
538GAS_plugin_solver_lock ()
539{
540 sf->s_bulk_start (sf->cls);
541}
542
543
544/**
545 * Resume instant solving, we are done with the bulk state updates.
546 */
547void
548GAS_plugin_solver_unlock ()
549{
550 sf->s_bulk_stop (sf->cls);
551}
552
553
554/**
555 * Notify the plugin that a request to connect to
556 * a particular peer was given to us.
557 *
558 * @param pid identity of peer we now care about
559 */
560void
561GAS_plugin_request_connect_start (const struct GNUNET_PeerIdentity *pid)
562{
563 sf->s_get (sf->cls,
564 pid);
565}
566
567
568/**
569 * Notify the plugin that a request to connect to
570 * a particular peer was dropped.
571 *
572 * @param pid identity of peer we care now less about
573 */
574void
575GAS_plugin_request_connect_stop (const struct GNUNET_PeerIdentity *pid)
576{
577 sf->s_get_stop (sf->cls,
578 pid);
579}
580
581
582/* end of gnunet-service-ats_plugins.c */
diff --git a/src/ats/gnunet-service-ats_plugins.h b/src/ats/gnunet-service-ats_plugins.h
deleted file mode 100644
index 1abdbbd80..000000000
--- a/src/ats/gnunet-service-ats_plugins.h
+++ /dev/null
@@ -1,149 +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 it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file ats/gnunet-service-ats_plugins.h
23 * @brief ats service plugin management
24 * @author Matthias Wachs
25 * @author Christian Grothoff
26 */
27#ifndef GNUNET_SERVICE_ATS_PLUGINS_H
28#define GNUNET_SERVICE_ATS_PLUGINS_H
29
30#include "gnunet-service-ats_addresses.h"
31
32
33/**
34 * Initialize address subsystem. The addresses subsystem manages the addresses
35 * known and current performance information. It has a solver component
36 * responsible for the resource allocation. It tells the solver about changes
37 * and receives updates when the solver changes the resource allocation.
38 *
39 * @param cfg configuration to use
40 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error (failed to load
41 * solver plugin)
42 */
43int
44GAS_plugin_init (const struct GNUNET_CONFIGURATION_Handle *cfg);
45
46
47/**
48 * Shutdown address subsystem.
49 */
50void
51GAS_plugin_done (void);
52
53
54/**
55 * The preference changed for a peer, update solver.
56 *
57 * @param peer the peer
58 * @param kind the ATS kind
59 * @param pref_rel the new relative preference value
60 */
61void
62GAS_plugin_notify_preference_changed (const struct GNUNET_PeerIdentity *peer,
63 enum GNUNET_ATS_PreferenceKind kind,
64 double pref_rel);
65
66
67/**
68 * The relative value for a property changed.
69 *
70 * @param address The peer for which a property changed.
71 */
72void
73GAS_plugin_notify_property_changed (struct ATS_Address *address);
74
75
76/**
77 * Tell the solver that the given address can now be used
78 * for talking to the respective peer.
79 *
80 * @param new_address the new address
81 */
82void
83GAS_plugin_new_address (struct ATS_Address *new_address);
84
85
86/**
87 * Tell the solver that the given address is no longer valid
88 * can cannot be used any longer.
89 *
90 * @param address address that was deleted
91 */
92void
93GAS_plugin_delete_address (struct ATS_Address *address);
94
95
96/**
97 * Tell the solver that the given client has expressed its
98 * appreciation for the past performance of a given connection.
99 *
100 * @param application client providing the feedback
101 * @param peer peer the feedback is about
102 * @param scope timeframe the feedback applies to
103 * @param kind performance property the feedback relates to
104 * @param score_abs degree of the appreciation
105 */
106void
107GAS_plugin_notify_feedback (struct GNUNET_SERVICE_Client *application,
108 const struct GNUNET_PeerIdentity *peer,
109 const struct GNUNET_TIME_Relative scope,
110 enum GNUNET_ATS_PreferenceKind kind,
111 float score_abs);
112
113
114/**
115 * Stop instant solving, there are many state updates
116 * happening in bulk right now.
117 */
118void
119GAS_plugin_solver_lock (void);
120
121
122/**
123 * Resume instant solving, we are done with the bulk state updates.
124 */
125void
126GAS_plugin_solver_unlock (void);
127
128
129/**
130 * Notify the plugin that a request to connect to
131 * a particular peer was given to us.
132 *
133 * @param pid identity of peer we now care about
134 */
135void
136GAS_plugin_request_connect_start (const struct GNUNET_PeerIdentity *pid);
137
138
139/**
140 * Notify the plugin that a request to connect to
141 * a particular peer was dropped.
142 *
143 * @param pid identity of peer we care now less about
144 */
145void
146GAS_plugin_request_connect_stop (const struct GNUNET_PeerIdentity *pid);
147
148
149#endif
diff --git a/src/ats/gnunet-service-ats_preferences.c b/src/ats/gnunet-service-ats_preferences.c
deleted file mode 100644
index c2b2dc4c1..000000000
--- a/src/ats/gnunet-service-ats_preferences.c
+++ /dev/null
@@ -1,771 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011-2015 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file ats/gnunet-service-ats_preferences.c
22 * @brief manage preferences expressed by clients
23 * @author Matthias Wachs
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet-service-ats.h"
28#include "gnunet-service-ats_addresses.h"
29#include "gnunet-service-ats_performance.h"
30#include "gnunet-service-ats_plugins.h"
31#include "gnunet-service-ats_preferences.h"
32#include "gnunet-service-ats_reservations.h"
33#include "ats.h"
34
35#define LOG(kind, ...) GNUNET_log_from (kind, "ats-preferences", __VA_ARGS__)
36
37/**
38 * How frequently do we age preference values?
39 */
40#define PREF_AGING_INTERVAL GNUNET_TIME_relative_multiply ( \
41 GNUNET_TIME_UNIT_SECONDS, 10)
42
43/**
44 * By which factor do we age preferences expressed during
45 * each #PREF_AGING_INTERVAL?
46 */
47#define PREF_AGING_FACTOR 0.95
48
49/**
50 * What is the lowest threshold up to which preference values
51 * are aged, and below which we consider them zero and thus
52 * no longer subject to aging?
53 */
54#define PREF_EPSILON 0.01
55
56
57/**
58 * Relative preferences for a peer.
59 */
60struct PeerRelative
61{
62 /**
63 * Array of relative preference values, to be indexed by
64 * an `enum GNUNET_ATS_PreferenceKind`.
65 */
66 double f_rel[GNUNET_ATS_PREFERENCE_END];
67
68 /**
69 * Number of clients that are expressing a preference for
70 * this peer. When this counter reaches zero, this entry
71 * is freed.
72 */
73 unsigned int num_clients;
74};
75
76
77/**
78 * Default values, returned as our preferences if we do not
79 * have any preferences expressed for a peer.
80 */
81static struct PeerRelative defvalues;
82
83
84/**
85 * Preference information per peer and client.
86 */
87struct PreferencePeer
88{
89 /**
90 * Next in DLL of preference entries for the same client.
91 */
92 struct PreferencePeer *next;
93
94 /**
95 * Previous in DLL of preference entries for the same client.
96 */
97 struct PreferencePeer *prev;
98
99 /**
100 * Absolute preference values for all preference types
101 * as expressed by this client for this peer.
102 */
103 double f_abs[GNUNET_ATS_PREFERENCE_END];
104
105 /**
106 * Relative preference values for all preference types,
107 * normalized in [0..1] based on how the respective
108 * client scored other peers.
109 */
110 double f_rel[GNUNET_ATS_PREFERENCE_END];
111};
112
113
114/**
115 * Preference client, as in a client that expressed preferences
116 * for peers. This is the information we keep track of for each
117 * such client.
118 */
119struct PreferenceClient
120{
121 /**
122 * Next in client list
123 */
124 struct PreferenceClient *next;
125
126 /**
127 * Previous in client peer list
128 */
129 struct PreferenceClient *prev;
130
131 /**
132 * Client handle
133 */
134 struct GNUNET_SERVICE_Client *client;
135
136 /**
137 * Mapping peer identities to `struct PreferencePeer` entry
138 * for the respective peer.
139 */
140 struct GNUNET_CONTAINER_MultiPeerMap *peer2pref;
141
142 /**
143 * Array of sums of absolute preferences for all
144 * peers as expressed by this client.
145 */
146 double f_abs_sum[GNUNET_ATS_PREFERENCE_END];
147};
148
149
150/**
151 * Hashmap to store peer information for preference normalization.
152 * Maps the identity of a peer to a `struct PeerRelative` containing
153 * the current relative preference values for that peer.
154 */
155static struct GNUNET_CONTAINER_MultiPeerMap *preference_peers;
156
157/**
158 * Clients in DLL: head
159 */
160static struct PreferenceClient *pc_head;
161
162/**
163 * Clients in DLL: tail
164 */
165static struct PreferenceClient *pc_tail;
166
167/**
168 * Handle for task we run periodically to age preferences over time.
169 */
170static struct GNUNET_SCHEDULER_Task *aging_task;
171
172
173/**
174 * Closure for #sum_relative_preferences().
175 */
176struct SumContext
177{
178 /**
179 * Where to accumulate the result.
180 */
181 double f_rel_total;
182
183 /**
184 * Which kind of preference value are we adding up?
185 */
186 enum GNUNET_ATS_PreferenceKind kind;
187};
188
189
190/**
191 * Add the relative preference for the kind given to the
192 * closure.
193 *
194 * @param cls the `struct SumContext` with the kind and place
195 * to store the result
196 * @param peer ignored
197 * @param value the `struct PreferencePeer` for getting the rel pref.
198 * @return #GNUNET_OK
199 */
200static int
201sum_relative_preferences (void *cls,
202 const struct GNUNET_PeerIdentity *peer,
203 void *value)
204{
205 struct SumContext *sum_ctx = cls;
206 struct PreferencePeer *p_cur = value;
207
208 sum_ctx->f_rel_total += p_cur->f_rel[sum_ctx->kind];
209 return GNUNET_OK;
210}
211
212
213/**
214 * Update the total relative preference for a peer by summing
215 * up the relative preferences all clients have for this peer.
216 *
217 * @param id peer id of the peer for which we should do the update
218 * @param kind the kind of preference value to update
219 * @return the new relative preference
220 */
221static void
222update_relative_values_for_peer (const struct GNUNET_PeerIdentity *id,
223 enum GNUNET_ATS_PreferenceKind kind)
224{
225 struct PreferenceClient *c_cur;
226 struct SumContext sum_ctx;
227 struct PeerRelative *rp;
228
229 sum_ctx.f_rel_total = 0.0;
230 sum_ctx.kind = kind;
231 for (c_cur = pc_head; NULL != c_cur; c_cur = c_cur->next)
232 GNUNET_CONTAINER_multipeermap_get_multiple (c_cur->peer2pref,
233 id,
234 &sum_relative_preferences,
235 &sum_ctx);
236 LOG (GNUNET_ERROR_TYPE_DEBUG,
237 "Total relative preference for peer `%s' for `%s' is %.3f\n",
238 GNUNET_i2s (id),
239 GNUNET_ATS_print_preference_type (kind),
240 sum_ctx.f_rel_total);
241 rp = GNUNET_CONTAINER_multipeermap_get (preference_peers,
242 id);
243 GNUNET_assert (NULL != rp);
244 if (rp->f_rel[kind] != sum_ctx.f_rel_total)
245 {
246 rp->f_rel[kind] = sum_ctx.f_rel_total;
247 GAS_plugin_notify_preference_changed (id,
248 kind,
249 rp->f_rel[kind]);
250 }
251}
252
253
254/**
255 * Free a peer's `struct PeerRelative`.
256 *
257 * @param cls unused
258 * @param key the key
259 * @param value the `struct PeerRelative` to free.
260 * @return #GNUNET_OK to continue
261 */
262static int
263free_peer (void *cls,
264 const struct GNUNET_PeerIdentity *key,
265 void *value)
266{
267 struct PeerRelative *rp = value;
268
269 GNUNET_assert (GNUNET_YES ==
270 GNUNET_CONTAINER_multipeermap_remove (preference_peers,
271 key,
272 value));
273 GNUNET_free (rp);
274 return GNUNET_OK;
275}
276
277
278/**
279 * Free `struct PreferencePeer` entry in map.
280 *
281 * @param cls the `struct PreferenceClient` with the map
282 * @param key the peer the entry is for
283 * @param value the `struct PreferencePeer` entry to free
284 * @return #GNUNET_OK (continue to iterate)
285 */
286static int
287free_preference (void *cls,
288 const struct GNUNET_PeerIdentity *key,
289 void *value)
290{
291 struct PreferenceClient *pc = cls;
292 struct PreferencePeer *p = value;
293 struct PeerRelative *pr;
294
295 GNUNET_assert (GNUNET_OK ==
296 GNUNET_CONTAINER_multipeermap_remove (pc->peer2pref,
297 key,
298 p));
299 GNUNET_free (p);
300 pr = GNUNET_CONTAINER_multipeermap_get (preference_peers,
301 key);
302 GNUNET_assert (NULL != pr);
303 GNUNET_assert (pr->num_clients > 0);
304 pr->num_clients--;
305 if (0 == pr->num_clients)
306 {
307 free_peer (NULL,
308 key,
309 pr);
310 }
311 return GNUNET_OK;
312}
313
314
315/**
316 * Closure for #age_values().
317 */
318struct AgeContext
319{
320 /**
321 * Counter of values remaining to update, incremented for each value
322 * changed (to a new non-zero value).
323 */
324 unsigned int values_to_update;
325
326 /**
327 * Client we are currently aging values for.
328 */
329 struct PreferenceClient *cur_client;
330};
331
332
333/**
334 * Age preference values of the given peer.
335 *
336 * @param cls a `
337 * @param peer peer being aged
338 * @param value the `struct PreferencePeer` for the peer
339 * @return #GNUNET_OK (continue to iterate)
340 */
341static int
342age_values (void *cls,
343 const struct GNUNET_PeerIdentity *peer,
344 void *value)
345{
346 struct AgeContext *ac = cls;
347 struct PreferencePeer *p = value;
348 unsigned int i;
349 int dead;
350
351 dead = GNUNET_YES;
352 for (i = 0; i < GNUNET_ATS_PREFERENCE_END; i++)
353 {
354 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
355 "Aging preference for peer `%s'\n",
356 GNUNET_i2s (peer));
357 if (p->f_abs[i] > DEFAULT_ABS_PREFERENCE)
358 p->f_abs[i] *= PREF_AGING_FACTOR;
359 if (p->f_abs[i] <= DEFAULT_ABS_PREFERENCE + PREF_EPSILON)
360 {
361 p->f_abs[i] = DEFAULT_ABS_PREFERENCE;
362 p->f_rel[i] = DEFAULT_REL_PREFERENCE;
363 update_relative_values_for_peer (peer,
364 i);
365 }
366 else
367 {
368 ac->values_to_update++;
369 dead = GNUNET_NO;
370 }
371 }
372 if (GNUNET_YES == dead)
373 {
374 /* all preferences are zero, remove this entry */
375 free_preference (ac->cur_client,
376 peer,
377 p);
378 }
379 return GNUNET_OK;
380}
381
382
383/**
384 * Reduce absolute preferences since they got old.
385 *
386 * @param cls unused
387 */
388static void
389preference_aging (void *cls)
390{
391 struct AgeContext ac;
392
393 aging_task = NULL;
394 GAS_plugin_solver_lock ();
395 ac.values_to_update = 0;
396 for (ac.cur_client = pc_head; NULL != ac.cur_client; ac.cur_client =
397 ac.cur_client->next)
398 GNUNET_CONTAINER_multipeermap_iterate (ac.cur_client->peer2pref,
399 &age_values,
400 &ac);
401 GAS_plugin_solver_unlock ();
402 if (ac.values_to_update > 0)
403 {
404 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
405 "Rescheduling aging task due to %u elements remaining to age\n",
406 ac.values_to_update);
407 if (NULL == aging_task)
408 aging_task = GNUNET_SCHEDULER_add_delayed (PREF_AGING_INTERVAL,
409 &preference_aging,
410 NULL);
411 }
412 else
413 {
414 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
415 "No values to age left, not rescheduling aging task\n");
416 }
417}
418
419
420/**
421 * Closure for #update_rel_sum() and #update_abs_sum().
422 */
423struct UpdateContext
424{
425 /**
426 * Preference client with the sum of all absolute scores.
427 */
428 struct PreferenceClient *pc;
429
430 /**
431 * Which kind are we updating?
432 */
433 enum GNUNET_ATS_PreferenceKind kind;
434};
435
436
437/**
438 * Compute updated absolute score for the client based on the
439 * current absolute scores for each peer.
440 *
441 * @param cls a `struct UpdateContext`
442 * @param peer peer being updated
443 * @param value the `struct PreferencePeer` for the peer
444 * @return #GNUNET_OK (continue to iterate)
445 */
446static int
447update_abs_sum (void *cls,
448 const struct GNUNET_PeerIdentity *peer,
449 void *value)
450{
451 struct UpdateContext *uc = cls;
452 struct PreferencePeer *p_cur = value;
453
454 uc->pc->f_abs_sum[uc->kind] += p_cur->f_abs[uc->kind];
455 return GNUNET_OK;
456}
457
458
459/**
460 * Compute updated relative score for each peer based on the
461 * current absolute score given by this client.
462 *
463 * @param cls a `struct UpdateContext`
464 * @param peer peer being updated
465 * @param value the `struct PreferencePeer` for the peer (updated)
466 * @return #GNUNET_OK (continue to iterate)
467 */
468static int
469update_rel_sum (void *cls,
470 const struct GNUNET_PeerIdentity *peer,
471 void *value)
472{
473 struct UpdateContext *uc = cls;
474 struct PreferencePeer *p_cur = value;
475
476 p_cur->f_rel[uc->kind] = p_cur->f_abs[uc->kind] / uc->pc->f_abs_sum[uc->kind];
477 LOG (GNUNET_ERROR_TYPE_DEBUG,
478 "Client has relative preference for %s for peer `%s' of %.3f\n",
479 GNUNET_ATS_print_preference_type (uc->kind),
480 GNUNET_i2s (peer),
481 p_cur->f_rel[uc->kind]);
482 return GNUNET_OK;
483}
484
485
486/**
487 * Recalculate preference for a specific ATS property
488 *
489 * @param c the preference client
490 * @param kind the preference kind
491 * @return the result
492 */
493static void
494recalculate_relative_preferences (struct PreferenceClient *c,
495 enum GNUNET_ATS_PreferenceKind kind)
496{
497 struct UpdateContext uc;
498
499 /* For this client: sum of absolute preference values for this preference */
500 uc.kind = kind;
501 uc.pc = c;
502 c->f_abs_sum[kind] = 0.0;
503
504 /* For all peers: calculate sum of absolute preferences */
505 GNUNET_CONTAINER_multipeermap_iterate (c->peer2pref,
506 &update_abs_sum,
507 &uc);
508 LOG (GNUNET_ERROR_TYPE_DEBUG,
509 "Client has sum of total preferences for %s of %.3f\n",
510 GNUNET_ATS_print_preference_type (kind),
511 c->f_abs_sum[kind]);
512
513 /* For all peers: calculate relative preference */
514 GNUNET_CONTAINER_multipeermap_iterate (c->peer2pref,
515 &update_rel_sum,
516 &uc);
517}
518
519
520/**
521 * The relative preferences of one of the clients have
522 * changed, update the global preferences for the given
523 * peer and notify the plugin.
524 *
525 * @param cls the kind of preference to calculate the
526 * new global relative preference values for
527 * @param key the peer to update relative preference values for
528 * @param value a `struct PeerRelative`, unused
529 */
530static int
531update_iterator (void *cls,
532 const struct GNUNET_PeerIdentity *key,
533 void *value)
534{
535 enum GNUNET_ATS_PreferenceKind *kind = cls;
536
537 update_relative_values_for_peer (key,
538 *kind);
539 return GNUNET_OK;
540}
541
542
543/**
544 * Update the absolute preference and calculate the
545 * new relative preference value.
546 *
547 * @param client the client with this preference
548 * @param peer the peer to change the preference for
549 * @param kind the kind to change the preference
550 * @param score_abs the normalized score
551 */
552static void
553update_preference (struct GNUNET_SERVICE_Client *client,
554 const struct GNUNET_PeerIdentity *peer,
555 enum GNUNET_ATS_PreferenceKind kind,
556 float score_abs)
557{
558 struct PreferenceClient *c_cur;
559 struct PreferencePeer *p_cur;
560 struct PeerRelative *r_cur;
561 unsigned int i;
562
563 if (kind >= GNUNET_ATS_PREFERENCE_END)
564 {
565 GNUNET_break (0);
566 return;
567 }
568 LOG (GNUNET_ERROR_TYPE_DEBUG,
569 "Client changes preference for peer `%s' for `%s' to %.2f\n",
570 GNUNET_i2s (peer),
571 GNUNET_ATS_print_preference_type (kind),
572 score_abs);
573
574 /* Find preference client */
575 for (c_cur = pc_head; NULL != c_cur; c_cur = c_cur->next)
576 if (client == c_cur->client)
577 break;
578 /* Not found: create new preference client */
579 if (NULL == c_cur)
580 {
581 c_cur = GNUNET_new (struct PreferenceClient);
582 c_cur->client = client;
583 c_cur->peer2pref = GNUNET_CONTAINER_multipeermap_create (16,
584 GNUNET_NO);
585 for (i = 0; i < GNUNET_ATS_PREFERENCE_END; i++)
586 c_cur->f_abs_sum[i] = DEFAULT_ABS_PREFERENCE;
587 GNUNET_CONTAINER_DLL_insert (pc_head,
588 pc_tail,
589 c_cur);
590 }
591
592 /* check global peer entry exists */
593 if (NULL ==
594 (r_cur = GNUNET_CONTAINER_multipeermap_get (preference_peers,
595 peer)))
596 {
597 /* Create struct for peer */
598 r_cur = GNUNET_new (struct PeerRelative);
599 for (i = 0; i < GNUNET_ATS_PREFERENCE_END; i++)
600 r_cur->f_rel[i] = DEFAULT_REL_PREFERENCE;
601 GNUNET_assert (GNUNET_OK ==
602 GNUNET_CONTAINER_multipeermap_put (preference_peers,
603 peer,
604 r_cur,
605 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
606 }
607
608 /* Find entry for peer */
609 p_cur = GNUNET_CONTAINER_multipeermap_get (c_cur->peer2pref,
610 peer);
611 if (NULL == p_cur)
612 {
613 /* Not found: create new peer entry */
614 p_cur = GNUNET_new (struct PreferencePeer);
615 for (i = 0; i < GNUNET_ATS_PREFERENCE_END; i++)
616 {
617 /* Default value per peer absolute preference for a preference*/
618 p_cur->f_abs[i] = DEFAULT_ABS_PREFERENCE;
619 /* Default value per peer relative preference for a quality */
620 p_cur->f_rel[i] = DEFAULT_REL_PREFERENCE;
621 }
622 GNUNET_assert (GNUNET_YES ==
623 GNUNET_CONTAINER_multipeermap_put (c_cur->peer2pref,
624 peer,
625 p_cur,
626 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
627 r_cur->num_clients++;
628 }
629
630 p_cur->f_abs[kind] += score_abs;
631 recalculate_relative_preferences (c_cur, kind);
632 GNUNET_CONTAINER_multipeermap_iterate (preference_peers,
633 &update_iterator,
634 &kind);
635
636 if (NULL == aging_task)
637 aging_task = GNUNET_SCHEDULER_add_delayed (PREF_AGING_INTERVAL,
638 &preference_aging,
639 NULL);
640}
641
642
643/**
644 * Handle 'preference change' messages from clients.
645 *
646 * @param client the client that sent the request
647 * @param msg the request message
648 */
649void
650GAS_handle_preference_change (struct GNUNET_SERVICE_Client *client,
651 const struct ChangePreferenceMessage *msg)
652{
653 const struct PreferenceInformation *pi;
654 uint32_t nump;
655
656 nump = ntohl (msg->num_preferences);
657 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
658 "Received PREFERENCE_CHANGE message for peer `%s'\n",
659 GNUNET_i2s (&msg->peer));
660 GNUNET_STATISTICS_update (GSA_stats,
661 "# preference change requests processed",
662 1,
663 GNUNET_NO);
664 pi = (const struct PreferenceInformation *) &msg[1];
665 GAS_plugin_solver_lock ();
666 for (uint32_t i = 0; i < nump; i++)
667 update_preference (client,
668 &msg->peer,
669 (enum GNUNET_ATS_PreferenceKind) ntohl (
670 pi[i].preference_kind),
671 pi[i].preference_value);
672 GAS_plugin_solver_unlock ();
673}
674
675
676/**
677 * Initialize preferences subsystem.
678 */
679void
680GAS_preference_init ()
681{
682 unsigned int i;
683
684 preference_peers = GNUNET_CONTAINER_multipeermap_create (16,
685 GNUNET_NO);
686 for (i = 0; i < GNUNET_ATS_PREFERENCE_END; i++)
687 defvalues.f_rel[i] = DEFAULT_REL_PREFERENCE;
688}
689
690
691/**
692 * Shutdown preferences subsystem.
693 */
694void
695GAS_preference_done ()
696{
697 struct PreferenceClient *pc;
698 struct PreferenceClient *next_pc;
699
700 if (NULL != aging_task)
701 {
702 GNUNET_SCHEDULER_cancel (aging_task);
703 aging_task = NULL;
704 }
705 next_pc = pc_head;
706 while (NULL != (pc = next_pc))
707 {
708 next_pc = pc->next;
709 GNUNET_CONTAINER_DLL_remove (pc_head,
710 pc_tail,
711 pc);
712 GNUNET_CONTAINER_multipeermap_iterate (pc->peer2pref,
713 &free_preference,
714 pc);
715 GNUNET_CONTAINER_multipeermap_destroy (pc->peer2pref);
716 GNUNET_free (pc);
717 }
718 GNUNET_CONTAINER_multipeermap_iterate (preference_peers,
719 &free_peer,
720 NULL);
721 GNUNET_CONTAINER_multipeermap_destroy (preference_peers);
722}
723
724
725/**
726 * Get the normalized preference values for a specific peer or
727 * the default values if
728 *
729 * @param cls ignored
730 * @param id the peer
731 * @return pointer to the values, can be indexed with GNUNET_ATS_PreferenceKind,
732 * default preferences if peer does not exist
733 */
734const double *
735GAS_preference_get_by_peer (void *cls,
736 const struct GNUNET_PeerIdentity *id)
737{
738 struct PeerRelative *rp;
739
740 if (NULL ==
741 (rp = GNUNET_CONTAINER_multipeermap_get (preference_peers,
742 id)))
743 {
744 return defvalues.f_rel;
745 }
746 return rp->f_rel;
747}
748
749
750void
751GAS_preference_client_disconnect (struct GNUNET_SERVICE_Client *client)
752{
753 struct PreferenceClient *c_cur;
754
755 for (c_cur = pc_head; NULL != c_cur; c_cur = c_cur->next)
756 if (client == c_cur->client)
757 break;
758 if (NULL == c_cur)
759 return;
760 GNUNET_CONTAINER_DLL_remove (pc_head,
761 pc_tail,
762 c_cur);
763 GNUNET_CONTAINER_multipeermap_iterate (c_cur->peer2pref,
764 &free_preference,
765 c_cur);
766 GNUNET_CONTAINER_multipeermap_destroy (c_cur->peer2pref);
767 GNUNET_free (c_cur);
768}
769
770
771/* end of gnunet-service-ats_preferences.c */
diff --git a/src/ats/gnunet-service-ats_preferences.h b/src/ats/gnunet-service-ats_preferences.h
deleted file mode 100644
index 49bf2ddbd..000000000
--- a/src/ats/gnunet-service-ats_preferences.h
+++ /dev/null
@@ -1,93 +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 it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file ats/gnunet-service-ats_preferences.h
22 * @brief manage preferences expressed by clients
23 * @author Matthias Wachs
24 * @author Christian Grothoff
25 */
26#ifndef GNUNET_SERVICE_ATS_PREFERENCES_H
27#define GNUNET_SERVICE_ATS_PREFERENCES_H
28
29#include "gnunet_util_lib.h"
30#include "gnunet_ats_service.h"
31#include "gnunet-service-ats.h"
32#include "gnunet_statistics_service.h"
33#include "ats.h"
34
35/**
36 * Default preference value we assume if we know nothing.
37 */
38#define DEFAULT_ABS_PREFERENCE 0.0
39
40/**
41 * Default relative preference value we assume if we know nothing.
42 */
43#define DEFAULT_REL_PREFERENCE 0.0
44
45
46/**
47 * Handle 'preference change' messages from clients.
48 *
49 * @param client the client that sent the request
50 * @param msg the request message
51 */
52void
53GAS_handle_preference_change (struct GNUNET_SERVICE_Client *client,
54 const struct ChangePreferenceMessage *msg);
55
56
57/**
58 * Initialize preferences subsystem.
59 */
60void
61GAS_preference_init (void);
62
63
64/**
65 * Shutdown preferences subsystem.
66 */
67void
68GAS_preference_done (void);
69
70
71/**
72 * Get the normalized preference values for a specific peer.
73 *
74 * @param cls ignored
75 * @param id the peer
76 * @return pointer to the values, can be indexed
77 * with `enum GNUNET_ATS_PreferenceKind`, never NULL
78 */
79const double *
80GAS_preference_get_by_peer (void *cls,
81 const struct GNUNET_PeerIdentity *id);
82
83
84/**
85 * A performance client disconnected
86 *
87 * @param client the disconnecting client
88 */
89void
90GAS_preference_client_disconnect (struct GNUNET_SERVICE_Client *client);
91
92
93#endif
diff --git a/src/ats/gnunet-service-ats_reservations.c b/src/ats/gnunet-service-ats_reservations.c
deleted file mode 100644
index 471a19859..000000000
--- a/src/ats/gnunet-service-ats_reservations.c
+++ /dev/null
@@ -1,211 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file ats/gnunet-service-ats_reservations.c
22 * @brief ats service, inbound bandwidth reservation management
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "gnunet-service-ats_reservations.h"
27#include "gnunet-service-ats.h"
28#include "ats.h"
29
30/**
31 * Number of seconds that available bandwidth carries over
32 * (can accumulate). Note that the
33 * test_ats_reservation_api test depends on this value!
34 */
35#define MAX_BANDWIDTH_CARRY_S 5
36
37
38/**
39 * Map of peer identities to `struct GNUNET_BANDWIDTH_Tracker *`s
40 */
41static struct GNUNET_CONTAINER_MultiPeerMap *trackers;
42
43
44/**
45 * Reserve the given amount of incoming bandwidth (in bytes) from the
46 * given peer. If a reservation is not possible right now, return how
47 * long the client should wait before trying again.
48 *
49 * @param peer peer to reserve bandwidth from
50 * @param amount number of bytes to reserve
51 * @return 0 if the reservation was successful, FOREVER if the
52 * peer is not connected, otherwise the time to wait
53 * until the reservation might succeed
54 */
55static struct GNUNET_TIME_Relative
56reservations_reserve (const struct GNUNET_PeerIdentity *peer,
57 int32_t amount)
58{
59 struct GNUNET_BANDWIDTH_Tracker *tracker;
60 struct GNUNET_TIME_Relative ret;
61
62 tracker = GNUNET_CONTAINER_multipeermap_get (trackers,
63 peer);
64 if (NULL == tracker)
65 {
66 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
67 "Not connected, allowing reservation of %d bytes\n",
68 (int) amount);
69 return GNUNET_TIME_UNIT_ZERO; /* not connected, satisfy now */
70 }
71 if (amount >= 0)
72 {
73 ret = GNUNET_BANDWIDTH_tracker_get_delay (tracker, amount);
74 if (ret.rel_value_us > 0)
75 {
76 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
77 "Delay to satisfy reservation for %d bytes is %s\n",
78 (int) amount,
79 GNUNET_STRINGS_relative_time_to_string (ret,
80 GNUNET_YES));
81 return ret;
82 }
83 }
84 (void) GNUNET_BANDWIDTH_tracker_consume (tracker, amount);
85 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
86 "Reserved %d bytes\n",
87 (int) amount);
88 return GNUNET_TIME_UNIT_ZERO;
89}
90
91
92/**
93 * Set the amount of bandwidth the other peer could currently transmit
94 * to us (as far as we know) to the given value.
95 *
96 * @param peer identity of the peer
97 * @param bandwidth_in currently available bandwidth from that peer to
98 * this peer (estimate)
99 */
100void
101GAS_reservations_set_bandwidth (const struct GNUNET_PeerIdentity *peer,
102 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in)
103{
104 struct GNUNET_BANDWIDTH_Tracker *tracker;
105
106 tracker = GNUNET_CONTAINER_multipeermap_get (trackers, peer);
107 if (0 == ntohl (bandwidth_in.value__))
108 {
109 if (NULL == tracker)
110 return;
111 GNUNET_assert (GNUNET_YES ==
112 GNUNET_CONTAINER_multipeermap_remove (trackers,
113 peer,
114 tracker));
115 GNUNET_free (tracker);
116 return;
117 }
118 if (NULL == tracker)
119 {
120 tracker = GNUNET_new (struct GNUNET_BANDWIDTH_Tracker);
121 GNUNET_BANDWIDTH_tracker_init (tracker,
122 NULL,
123 NULL,
124 bandwidth_in,
125 MAX_BANDWIDTH_CARRY_S);
126 GNUNET_assert (GNUNET_OK ==
127 GNUNET_CONTAINER_multipeermap_put (trackers,
128 peer,
129 tracker,
130 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
131 return;
132 }
133 GNUNET_BANDWIDTH_tracker_update_quota (tracker,
134 bandwidth_in);
135}
136
137
138void
139GAS_handle_reservation_request (struct GNUNET_SERVICE_Client *client,
140 const struct ReservationRequestMessage *msg)
141{
142 struct GNUNET_MQ_Envelope *env;
143 struct ReservationResultMessage *result;
144 int32_t amount;
145 struct GNUNET_TIME_Relative res_delay;
146
147 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
148 "Received RESERVATION_REQUEST message\n");
149 amount = (int32_t) ntohl (msg->amount);
150 res_delay = reservations_reserve (&msg->peer, amount);
151 if (res_delay.rel_value_us > 0)
152 amount = 0;
153 env = GNUNET_MQ_msg (result,
154 GNUNET_MESSAGE_TYPE_ATS_RESERVATION_RESULT);
155 result->amount = htonl (amount);
156 result->peer = msg->peer;
157 result->res_delay = GNUNET_TIME_relative_hton (res_delay);
158 GNUNET_STATISTICS_update (GSA_stats,
159 "# reservation requests processed",
160 1,
161 GNUNET_NO);
162 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
163 env);
164}
165
166
167/**
168 * Initialize reservations subsystem.
169 */
170void
171GAS_reservations_init ()
172{
173 trackers = GNUNET_CONTAINER_multipeermap_create (128,
174 GNUNET_NO);
175}
176
177
178/**
179 * Free memory of bandwidth tracker.
180 *
181 * @param cls NULL
182 * @param key peer identity (unused)
183 * @param value the `struct GNUNET_BANDWIDTH_Tracker` to free
184 * @return #GNUNET_OK (continue to iterate)
185 */
186static int
187free_tracker (void *cls,
188 const struct GNUNET_PeerIdentity *key,
189 void *value)
190{
191 struct GNUNET_BANDWIDTH_Tracker *tracker = value;
192
193 GNUNET_free (tracker);
194 return GNUNET_OK;
195}
196
197
198/**
199 * Shutdown reservations subsystem.
200 */
201void
202GAS_reservations_done ()
203{
204 GNUNET_CONTAINER_multipeermap_iterate (trackers,
205 &free_tracker,
206 NULL);
207 GNUNET_CONTAINER_multipeermap_destroy (trackers);
208}
209
210
211/* end of gnunet-service-ats_reservations.c */
diff --git a/src/ats/gnunet-service-ats_reservations.h b/src/ats/gnunet-service-ats_reservations.h
deleted file mode 100644
index 07edd69e0..000000000
--- a/src/ats/gnunet-service-ats_reservations.h
+++ /dev/null
@@ -1,72 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file ats/gnunet-service-ats_reservations.h
23 * @brief ats service, inbound bandwidth reservation management
24 * @author Christian Grothoff
25 */
26#ifndef GNUNET_SERVICE_ATS_RESERVATIONS_H
27#define GNUNET_SERVICE_ATS_RESERVATIONS_H
28
29#include "gnunet_util_lib.h"
30#include "ats.h"
31
32
33/**
34 * Set the amount of bandwidth the other peer could currently transmit
35 * to us (as far as we know) to the given value.
36 *
37 * @param peer identity of the peer
38 * @param bandwidth_in currently available bandwidth from that peer to
39 * this peer (estimate)
40 */
41void
42GAS_reservations_set_bandwidth (const struct GNUNET_PeerIdentity *peer,
43 struct GNUNET_BANDWIDTH_Value32NBO
44 bandwidth_in);
45
46
47/**
48 * Handle 'reservation request' messages from clients.
49 *
50 * @param client client that sent the request
51 * @param message the request message
52 */
53void
54GAS_handle_reservation_request (struct GNUNET_SERVICE_Client *client,
55 const struct
56 ReservationRequestMessage *message);
57
58
59/**
60 * Initialize reservations subsystem.
61 */
62void
63GAS_reservations_init (void);
64
65
66/**
67 * Shutdown reservations subsystem.
68 */
69void
70GAS_reservations_done (void);
71
72#endif
diff --git a/src/ats/gnunet-service-ats_scheduling.c b/src/ats/gnunet-service-ats_scheduling.c
deleted file mode 100644
index 2dfb70343..000000000
--- a/src/ats/gnunet-service-ats_scheduling.c
+++ /dev/null
@@ -1,195 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011-2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file ats/gnunet-service-ats_scheduling.c
23 * @brief ats service, interaction with 'scheduling' API
24 * @author Matthias Wachs
25 * @author Christian Grothoff
26 */
27#include "platform.h"
28#include "gnunet-service-ats_addresses.h"
29#include "gnunet-service-ats_scheduling.h"
30#include "ats.h"
31
32/**
33 * Actual handle to the client.
34 */
35static struct GNUNET_SERVICE_Client *my_client;
36
37
38/**
39 * Register a new scheduling client.
40 *
41 * @param client handle of the new client
42 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
43 */
44int
45GAS_scheduling_add_client (struct GNUNET_SERVICE_Client *client)
46{
47 if (NULL != my_client)
48 {
49 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
50 "This ATS already has a scheduling client, refusing new scheduling client for now.\n");
51 return GNUNET_SYSERR;
52 }
53 my_client = client;
54 return GNUNET_OK;
55}
56
57
58/**
59 * Unregister a client (which may have been a scheduling client,
60 * but this is not assured).
61 *
62 * @param client handle of the (now dead) client
63 */
64void
65GAS_scheduling_remove_client (struct GNUNET_SERVICE_Client *client)
66{
67 if (my_client != client)
68 return;
69 GAS_addresses_destroy_all ();
70 my_client = NULL;
71}
72
73
74void
75GAS_scheduling_transmit_address_suggestion (const struct
76 GNUNET_PeerIdentity *peer,
77 uint32_t session_id,
78 struct GNUNET_BANDWIDTH_Value32NBO
79 bandwidth_out,
80 struct GNUNET_BANDWIDTH_Value32NBO
81 bandwidth_in)
82{
83 struct GNUNET_MQ_Envelope *env;
84 struct AddressSuggestionMessage *msg;
85
86 if (NULL == my_client)
87 return;
88 GNUNET_STATISTICS_update (GSA_stats,
89 "# address suggestions made",
90 1,
91 GNUNET_NO);
92 env = GNUNET_MQ_msg (msg,
93 GNUNET_MESSAGE_TYPE_ATS_ADDRESS_SUGGESTION);
94 msg->peer = *peer;
95 msg->session_id = htonl (session_id);
96 msg->bandwidth_out = bandwidth_out;
97 msg->bandwidth_in = bandwidth_in;
98 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
99 "ATS sends quota for peer `%s': (in/out) %u/%u\n",
100 GNUNET_i2s (peer),
101 (unsigned int) ntohl (bandwidth_in.value__),
102 (unsigned int) ntohl (bandwidth_out.value__));
103 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (my_client),
104 env);
105}
106
107
108void
109GAS_handle_address_add (const struct AddressAddMessage *m)
110{
111 const char *address;
112 const char *plugin_name;
113 uint16_t address_length;
114 uint16_t plugin_name_length;
115 struct GNUNET_ATS_Properties prop;
116
117 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
118 "Received `%s' message\n",
119 "ADDRESS_ADD");
120 address_length = ntohs (m->address_length);
121 plugin_name_length = ntohs (m->plugin_name_length);
122 address = (const char *) &m[1];
123 if (plugin_name_length != 0)
124 plugin_name = &address[address_length];
125 else
126 plugin_name = "";
127 GNUNET_STATISTICS_update (GSA_stats,
128 "# addresses created",
129 1,
130 GNUNET_NO);
131 GNUNET_ATS_properties_ntoh (&prop,
132 &m->properties);
133 GNUNET_break (GNUNET_NT_UNSPECIFIED != prop.scope);
134 GAS_addresses_add (&m->peer,
135 plugin_name,
136 address,
137 address_length,
138 ntohl (m->address_local_info),
139 ntohl (m->session_id),
140 &prop);
141}
142
143
144/**
145 * Handle 'address update' messages from clients.
146 *
147 * @param m the request message
148 */
149void
150GAS_handle_address_update (const struct AddressUpdateMessage *m)
151{
152 struct GNUNET_ATS_Properties prop;
153
154 GNUNET_STATISTICS_update (GSA_stats,
155 "# address updates received",
156 1,
157 GNUNET_NO);
158 GNUNET_ATS_properties_ntoh (&prop,
159 &m->properties);
160 GAS_addresses_update (&m->peer,
161 ntohl (m->session_id),
162 &prop);
163}
164
165
166/**
167 * Handle 'address destroyed' messages from clients.
168 *
169 * @param m the request message
170 */
171void
172GAS_handle_address_destroyed (const struct AddressDestroyedMessage *m)
173{
174 struct GNUNET_MQ_Envelope *env;
175 struct GNUNET_ATS_SessionReleaseMessage *srm;
176
177 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
178 "Received `%s' message\n",
179 "ADDRESS_DESTROYED");
180 GNUNET_STATISTICS_update (GSA_stats,
181 "# addresses destroyed",
182 1,
183 GNUNET_NO);
184 GAS_addresses_destroy (&m->peer,
185 ntohl (m->session_id));
186 env = GNUNET_MQ_msg (srm,
187 GNUNET_MESSAGE_TYPE_ATS_SESSION_RELEASE);
188 srm->session_id = m->session_id;
189 srm->peer = m->peer;
190 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (my_client),
191 env);
192}
193
194
195/* end of gnunet-service-ats_scheduling.c */
diff --git a/src/ats/gnunet-service-ats_scheduling.h b/src/ats/gnunet-service-ats_scheduling.h
deleted file mode 100644
index ca6c1bd57..000000000
--- a/src/ats/gnunet-service-ats_scheduling.h
+++ /dev/null
@@ -1,100 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file ats/gnunet-service-ats_scheduling.h
23 * @brief ats service, interaction with 'scheduling' API
24 * @author Matthias Wachs
25 * @author Christian Grothoff
26 */
27#ifndef GNUNET_SERVICE_ATS_SCHEDULING_H
28#define GNUNET_SERVICE_ATS_SCHEDULING_H
29
30#include "gnunet_util_lib.h"
31
32
33/**
34 * Register a new scheduling client.
35 *
36 * @param client handle of the new client
37 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
38 */
39int
40GAS_scheduling_add_client (struct GNUNET_SERVICE_Client *client);
41
42
43/**
44 * Unregister a client (which may have been a scheduling client,
45 * but this is not assured).
46 *
47 * @param client handle of the (now dead) client
48 */
49void
50GAS_scheduling_remove_client (struct GNUNET_SERVICE_Client *client);
51
52
53/**
54 * Transmit the given address suggestion and bandwidth update to all scheduling
55 * clients.
56 *
57 * @param peer peer for which this is an address suggestion
58 * @param session_id session ID to use for the given client
59 * @param bandwidth_out assigned outbound bandwidth
60 * @param bandwidth_in assigned inbound bandwidth
61 */
62void
63GAS_scheduling_transmit_address_suggestion (const struct
64 GNUNET_PeerIdentity *peer,
65 uint32_t session_id,
66 struct GNUNET_BANDWIDTH_Value32NBO
67 bandwidth_out,
68 struct GNUNET_BANDWIDTH_Value32NBO
69 bandwidth_in);
70
71
72/**
73 * Handle 'address add' messages from clients.
74 *
75 * @param m the request message
76 */
77void
78GAS_handle_address_add (const struct AddressAddMessage *m);
79
80
81/**
82 * Handle 'address update' messages from clients.
83 *
84 * @param m the request message
85 */
86void
87GAS_handle_address_update (const struct AddressUpdateMessage *m);
88
89
90/**
91 * Handle 'address destroyed' messages from clients.
92 *
93 * @param m the request message
94 */
95void
96GAS_handle_address_destroyed (const struct AddressDestroyedMessage *m);
97
98
99#endif
100/* end of gnunet-service-ats_scheduling.h */
diff --git a/src/ats/meson.build b/src/ats/meson.build
deleted file mode 100644
index 4aa4e6972..000000000
--- a/src/ats/meson.build
+++ /dev/null
@@ -1,58 +0,0 @@
1libgnunetats_src = ['ats_api_connectivity.c',
2 'ats_api_scheduling.c',
3 'ats_api_scanner.c',
4 'ats_api_performance.c']
5
6gnunetserviceats_src = ['gnunet-service-ats.c',
7 'gnunet-service-ats_addresses.c',
8 'gnunet-service-ats_connectivity.c',
9 'gnunet-service-ats_normalization.c',
10 'gnunet-service-ats_performance.c',
11 'gnunet-service-ats_plugins.c',
12 'gnunet-service-ats_preferences.c',
13 'gnunet-service-ats_scheduling.c',
14 'gnunet-service-ats_reservations.c']
15
16configure_file(input : 'ats.conf.in',
17 output : 'ats.conf',
18 configuration : cdata,
19 install: true,
20 install_dir: pkgcfgdir)
21
22if get_option('monolith')
23 foreach p : libgnunetats_src + gnunetserviceats_src
24 gnunet_src += 'ats/' + p
25 endforeach
26 subdir_done()
27endif
28
29libgnunetats = library('gnunetats',
30 libgnunetats_src,
31 version: '4.0.0',
32 soversion: '4',
33 dependencies: [libgnunetutil_dep, libgnunethello_dep],
34 include_directories: [incdir, configuration_inc],
35 install: true,
36 install_dir: get_option('libdir'))
37pkg.generate(libgnunetats, url : 'https://www.gnunet.org',
38 description : 'Provides API for allocating bandwidth, expressing preferences for certain peers and accessing allocation information')
39libgnunetats_dep = declare_dependency(link_with : libgnunetats)
40
41shared_module('gnunet_plugin_ats_proportional',
42 ['plugin_ats_proportional.c'],
43 dependencies: [libgnunetutil_dep,
44 libgnunetats_dep,
45 libgnunetstatistics_dep,
46 libgnunetnt_dep,
47 libgnunetstatistics_dep],
48 include_directories: [incdir, configuration_inc],
49 install: true,
50 install_dir: get_option('libdir')/'gnunet')
51
52executable ('gnunet-service-ats',
53 gnunetserviceats_src,
54 dependencies: [libgnunetats_dep, libgnunetutil_dep,
55 libgnunetnt_dep, libgnunetstatistics_dep],
56 include_directories: [incdir, configuration_inc],
57 install: true,
58 install_dir: get_option('libdir') / 'gnunet' / 'libexec')
diff --git a/src/ats/perf_ats_simplistic_bandwidth.conf b/src/ats/perf_ats_simplistic_bandwidth.conf
deleted file mode 100644
index cec5b36f5..000000000
--- a/src/ats/perf_ats_simplistic_bandwidth.conf
+++ /dev/null
@@ -1,27 +0,0 @@
1[hostlist]
2SERVERS =
3
4[transport-udp]
5BROADCAST = NO
6
7[peerinfo]
8USE_INCLUDED_HELLOS = NO
9
10# Network specific inbound/outbound quotas
11UNSPECIFIED_QUOTA_IN = 128 KiB
12UNSPECIFIED_QUOTA_OUT = 128 KiB
13# LOOPBACK
14LOOPBACK_QUOTA_IN = 128 KiB
15LOOPBACK_QUOTA_OUT = 128 KiB
16# LAN
17LAN_QUOTA_IN = 128 KiB
18LAN_QUOTA_OUT = 128 KiB
19# WAN
20WAN_QUOTA_IN = 128 KiB
21WAN_QUOTA_OUT = 128 KiB
22# WLAN
23WLAN_QUOTA_IN = 128 KiB
24WLAN_QUOTA_OUT = 128 KiB
25# BLUETOOTH
26BLUETOOTH_QUOTA_IN = 128 KiB
27BLUETOOTH_QUOTA_OUT = 128 KiB
diff --git a/src/ats/perf_ats_simplistic_delay.conf b/src/ats/perf_ats_simplistic_delay.conf
deleted file mode 100644
index a5127d25f..000000000
--- a/src/ats/perf_ats_simplistic_delay.conf
+++ /dev/null
@@ -1,8 +0,0 @@
1[hostlist]
2SERVERS =
3
4[transport-udp]
5BROADCAST = NO
6
7[peerinfo]
8USE_INCLUDED_HELLOS = NO
diff --git a/src/ats/perf_ats_solver.c b/src/ats/perf_ats_solver.c
deleted file mode 100644
index 363d0cfc9..000000000
--- a/src/ats/perf_ats_solver.c
+++ /dev/null
@@ -1,1510 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010,2011 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file ats/perf_ats_solver.c
22 * @brief generic performance test for ATS solvers
23 * @author Christian Grothoff
24 * @author Matthias Wachs
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_statistics_service.h"
29#include "gnunet-service-ats_addresses.h"
30#include "gnunet-service-ats_plugins.h"
31#include "gnunet-service-ats_normalization.h"
32#include "gnunet-service-ats_preferences.h"
33#include "gnunet_ats_service.h"
34#include "gnunet_ats_plugin.h"
35#include "test_ats_api_common.h"
36
37#define DEFAULT_UPDATE_PERCENTAGE 20
38#define DEFAULT_PEERS_START 10
39#define DEFAULT_PEERS_END 10
40#define DEFAULT_ADDRESSES 10
41#define DEFAULT_ATS_COUNT 2
42
43
44/**
45 * Handle for statistics.
46 */
47struct GNUNET_STATISTICS_Handle *GSA_stats;
48
49/**
50 * Handle for ATS address component
51 */
52struct PerfHandle
53{
54 /**
55 * Performance peers
56 */
57 struct PerfPeer *peers;
58
59 /**
60 * Solver handle
61 */
62 struct GNUNET_ATS_SolverFunctions *sf;
63
64 /**
65 * Statistics stat;
66 */
67 struct GNUNET_STATISTICS_Handle *stat;
68
69 /**
70 * A multihashmap to store all addresses
71 */
72 struct GNUNET_CONTAINER_MultiPeerMap *addresses;
73
74 /**
75 * Solver functions
76 * */
77 struct GNUNET_ATS_PluginEnvironment env;
78
79 /**
80 * Array for results for each iteration with length iterations
81 */
82 struct Iteration *iterations_results;
83
84 /**
85 * The current result
86 */
87 struct Result *current_result;
88
89 /**
90 * Current number of peers benchmarked
91 */
92 int current_p;
93
94 /**
95 * Current number of addresses benchmarked
96 */
97 int current_a;
98
99 /**
100 * Solver description as string
101 */
102 char *ats_string;
103
104 /**
105 * Configured ATS solver
106 */
107 int ats_mode;
108
109 /**
110 * #peers to start benchmarking with
111 */
112 int N_peers_start;
113
114 /**
115 * #peers to end benchmarking with
116 */
117 int N_peers_end;
118
119 /**
120 * #addresses to benchmarking with
121 */
122 int N_address;
123
124 /**
125 * Percentage of peers to update
126 */
127 int opt_update_percent;
128
129 /**
130 * Create gnuplot file
131 */
132 int create_datafile;
133
134 /**
135 * Measure updates
136 */
137 int measure_updates;
138
139 /**
140 * Number of iterations
141 */
142 int total_iterations;
143
144 /**
145 * Current iteration
146 */
147 int current_iteration;
148
149 /**
150 * Is a bulk operation running?
151 */
152 int bulk_running;
153
154 /**
155 * Is a bulk operation running?
156 */
157 int expecting_solution;
158
159 /**
160 * Was the problem just updates?
161 */
162 int performed_update;
163};
164
165/**
166 * Data structure to store results for a single iteration
167 */
168struct Iteration
169{
170 struct Result **results_array;
171
172 struct Result **update_results_array;
173};
174
175
176/**
177 * Result for a solver calculation
178 */
179struct Result
180{
181 /**
182 * Previous element in the linked list
183 */
184 struct Result *prev;
185
186 /**
187 * Next element in the linked list
188 */
189 struct Result *next;
190
191 /**
192 * Number of peers this solution included
193 */
194 int peers;
195
196 /**
197 * Number of addresses per peer this solution included
198 */
199 int addresses;
200
201 /**
202 * Is this an update or a full solution
203 */
204 int update;
205
206 /**
207 * Was the solution valid or did the solver fail
208 */
209 int valid;
210
211 /**
212 * Result of the solver
213 */
214 enum GAS_Solver_Additional_Information info;
215
216 /**
217 * Duration of setting up the problem in the solver
218 */
219 struct GNUNET_TIME_Relative d_setup_full;
220
221 /**
222 * Duration of solving the LP problem in the solver
223 * MLP solver only
224 */
225 struct GNUNET_TIME_Relative d_lp_full;
226
227 /**
228 * Duration of solving the MLP problem in the solver
229 * MLP solver only
230 */
231 struct GNUNET_TIME_Relative d_mlp_full;
232
233 /**
234 * Duration of solving whole problem in the solver
235 */
236 struct GNUNET_TIME_Relative d_total_full;
237
238 /**
239 * Start time of setting up the problem in the solver
240 */
241 struct GNUNET_TIME_Absolute s_setup;
242
243 /**
244 * Start time of solving the LP problem in the solver
245 * MLP solver only
246 */
247 struct GNUNET_TIME_Absolute s_lp;
248
249 /**
250 * Start time of solving the MLP problem in the solver
251 * MLP solver only
252 */
253 struct GNUNET_TIME_Absolute s_mlp;
254
255 /**
256 * Start time of solving whole problem in the solver
257 */
258 struct GNUNET_TIME_Absolute s_total;
259
260 /**
261 * End time of setting up the problem in the solver
262 */
263 struct GNUNET_TIME_Absolute e_setup;
264
265 /**
266 * End time of solving the LP problem in the solver
267 * MLP solver only
268 */
269 struct GNUNET_TIME_Absolute e_lp;
270
271 /**
272 * End time of solving the MLP problem in the solver
273 * MLP solver only
274 */
275 struct GNUNET_TIME_Absolute e_mlp;
276
277 /**
278 * End time of solving whole problem in the solver
279 */
280 struct GNUNET_TIME_Absolute e_total;
281};
282
283/**
284 * Peer used for the benchmarking
285 */
286struct PerfPeer
287{
288 /**
289 * Peer identitity
290 */
291 struct GNUNET_PeerIdentity id;
292
293 /**
294 * Head of linked list of addresses used with this peer
295 */
296 struct ATS_Address *head;
297
298 /**
299 * Head of linked list of addresses used with this peer
300 */
301 struct ATS_Address *tail;
302};
303
304
305/**
306 * ATS performance handle
307 */
308static struct PerfHandle ph;
309
310/**
311 * Return value
312 */
313static int ret;
314
315
316/**
317 * Do shutdown
318 */
319static void
320end_now (int res)
321{
322 if (NULL != ph.stat)
323 {
324 GNUNET_STATISTICS_destroy (ph.stat, GNUNET_NO);
325 ph.stat = NULL;
326 }
327
328 GNUNET_free (ph.peers);
329 GNUNET_free (ph.iterations_results);
330
331 GAS_normalization_stop ();
332 GAS_preference_done ();
333 ret = res;
334}
335
336
337/**
338 * Create a peer used for benchmarking
339 *
340 * @param cp the number of the peer
341 */
342static void
343perf_create_peer (int cp)
344{
345 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
346 &ph.peers[cp].id, sizeof(struct
347 GNUNET_PeerIdentity));
348 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating peer #%u: %s \n", cp,
349 GNUNET_i2s (&ph.peers[cp].id));
350}
351
352
353/**
354 * Perform an update for an address
355 *
356 * @param cur the address to update
357 */
358static void
359perf_update_address (struct ATS_Address *cur)
360{
361 int r_type;
362 int abs_val;
363 double rel_val;
364
365 r_type = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 2);
366 switch (r_type)
367 {
368 case 0:
369 abs_val = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 100);
370 rel_val = (100 + (double) abs_val) / 100;
371
372 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
373 "Updating peer `%s' address %p type %s abs val %u rel val %.3f\n",
374 GNUNET_i2s (&cur->peer), cur,
375 "GNUNET_ATS_QUALITY_NET_DELAY",
376 abs_val, rel_val);
377 ph.sf->s_address_update_property (ph.sf->cls, cur,
378 GNUNET_ATS_QUALITY_NET_DELAY,
379 abs_val, rel_val);
380 break;
381
382 case 1:
383 abs_val = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 10);
384 rel_val = (100 + (double) abs_val) / 100;
385
386 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
387 "Updating peer `%s' address %p type %s abs val %u rel val %.3f\n",
388 GNUNET_i2s (&cur->peer), cur, "GNUNET_ATS_QUALITY_NET_DISTANCE",
389 abs_val, rel_val);
390 ph.sf->s_address_update_property (ph.sf->cls, cur,
391 GNUNET_ATS_QUALITY_NET_DISTANCE,
392 abs_val, rel_val);
393 break;
394
395 default:
396 break;
397 }
398}
399
400
401static void
402bandwidth_changed_cb (void *cls,
403 struct ATS_Address *address)
404{
405 if ((0 == address->assigned_bw_out) && (0 == address->assigned_bw_in))
406 return;
407
408 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
409 "Bandwidth changed addresses %s %p to %u Bps out / %u Bps in\n",
410 GNUNET_i2s (&address->peer),
411 address,
412 address->assigned_bw_out,
413 address->assigned_bw_in);
414 if (GNUNET_YES == ph.bulk_running)
415 GNUNET_break (0);
416 return;
417}
418
419
420static const double *
421get_preferences_cb (void *cls, const struct GNUNET_PeerIdentity *id)
422{
423 return GAS_preference_get_by_peer (NULL, id);
424}
425
426
427static void
428perf_address_initial_update (void *dead,
429 struct GNUNET_CONTAINER_MultiPeerMap *addresses,
430 struct ATS_Address *address)
431{
432 double delay;
433 double distance;
434 uint32_t random = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 100);
435
436 delay = (100 + (double) random) / 100;
437 ph.sf->s_address_update_property (ph.sf->cls,
438 address, GNUNET_ATS_QUALITY_NET_DELAY,
439 100, delay);
440
441 random = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 100);
442 distance = (100 + (double) random) / 100;
443
444 ph.sf->s_address_update_property (ph.sf->cls, address,
445 GNUNET_ATS_QUALITY_NET_DISTANCE,
446 10, distance);
447
448 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
449 "Initial update address %p : %.2f %.2f\n",
450 address, delay, distance);
451}
452
453
454struct DUA_Ctx
455{
456 int r;
457 int c_cur_a;
458};
459
460
461static int
462do_update_address (void *cls,
463 const struct GNUNET_PeerIdentity *pid,
464 void *value)
465{
466 struct DUA_Ctx *ctx = cls;
467 struct ATS_Address *addr = value;
468
469 if (ctx->c_cur_a == ctx->r)
470 perf_update_address (addr);
471 ctx->c_cur_a++;
472 return GNUNET_OK;
473}
474
475
476/**
477 * Update a certain percentage of peers
478 *
479 * @param cp the current number of peers
480 * @param ca the current number of addresses
481 * @param percentage_peers the percentage of peers to update
482 */
483static void
484perf_update_all_addresses (unsigned int cp, unsigned int ca, unsigned int
485 percentage_peers)
486{
487 int c_peer;
488 int c_select;
489 int c_cur_p;
490 int r;
491 int count;
492 unsigned int m[cp];
493 struct DUA_Ctx dua_ctx;
494
495 count = cp * ((double) percentage_peers / 100);
496 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
497 "Updating %u of %u peers \n", count, cp);
498
499 for (c_peer = 0; c_peer < cp; c_peer++)
500 m[c_peer] = 0;
501
502 c_select = 0;
503
504 while (c_select < count)
505 {
506 r = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, cp);
507 if (0 == m[r])
508 {
509 m[r] = 1;
510 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
511 "Updating peer [%u] \n", r);
512 c_select++;
513 }
514 }
515 for (c_cur_p = 0; c_cur_p < cp; c_cur_p++)
516 {
517 if (1 == m[c_cur_p])
518 {
519 r = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, ca);
520 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
521 "Updating peer [%u] address [%u]\n", c_cur_p, r);
522
523 dua_ctx.c_cur_a = 0;
524 dua_ctx.r = r;
525 GNUNET_CONTAINER_multipeermap_get_multiple (ph.addresses,
526 &ph.peers[c_cur_p].id,
527 &do_update_address,
528 &dua_ctx);
529 }
530 }
531}
532
533
534/**
535 * Create an address for a peer
536 *
537 * @param cp index of the peer
538 * @param ca index of the address
539 * @return the address
540 */
541static struct ATS_Address *
542perf_create_address (int cp, int ca)
543{
544 struct ATS_Address *a;
545
546 a = create_address (&ph.peers[cp].id,
547 "Test 1", "test 1", strlen ("test 1") + 1, 0);
548 GNUNET_CONTAINER_multipeermap_put (ph.addresses, &ph.peers[cp].id, a,
549 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
550 return a;
551}
552
553
554/**
555 * Information callback for the solver
556 *
557 * @param op the solver operation
558 * @param stat status of the solver operation
559 * @param add additional solver information
560 */
561static void
562solver_info_cb (void *cls,
563 enum GAS_Solver_Operation op,
564 enum GAS_Solver_Status stat,
565 enum GAS_Solver_Additional_Information add)
566{
567 char *add_info;
568
569 switch (add)
570 {
571 case GAS_INFO_NONE:
572 add_info = "GAS_INFO_NONE";
573 break;
574
575 case GAS_INFO_FULL:
576 add_info = "GAS_INFO_MLP_FULL";
577 break;
578
579 case GAS_INFO_UPDATED:
580 add_info = "GAS_INFO_MLP_UPDATED";
581 break;
582
583 case GAS_INFO_PROP_ALL:
584 add_info = "GAS_INFO_PROP_ALL";
585 break;
586
587 case GAS_INFO_PROP_SINGLE:
588 add_info = "GAS_INFO_PROP_SINGLE";
589 break;
590
591 default:
592 add_info = "INVALID";
593 break;
594 }
595
596 struct Result *tmp;
597 switch (op)
598 {
599 case GAS_OP_SOLVE_START:
600 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
601 "Solver notifies `%s' with result `%s' `%s'\n",
602 "GAS_OP_SOLVE_START",
603 (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL", add_info);
604 if (GNUNET_NO == ph.expecting_solution)
605 {
606 /* We do not expect a solution at the moment */
607 GNUNET_break (0);
608 return;
609 }
610
611 if ((GAS_STAT_SUCCESS == stat) && (NULL == ph.current_result))
612 {
613 tmp = GNUNET_new (struct Result);
614 /* Create new result */
615 if ((add == GAS_INFO_UPDATED) || (GNUNET_YES == ph.performed_update))
616 {
617 ph.current_result = tmp;
618 // fprintf (stderr,"UPDATE %u %u\n",ph.current_iteration-1, ph.current_p);
619 ph.iterations_results[ph.current_iteration
620 - 1].update_results_array[ph.current_p] = tmp;
621 }
622 else
623 {
624 ph.current_result = tmp;
625 // fprintf (stderr,"FULL %u %u\n",ph.current_iteration-1, ph.current_p);
626 ph.iterations_results[ph.current_iteration
627 - 1].results_array[ph.current_p] = tmp;
628 }
629
630 ph.current_result->addresses = ph.current_a;
631 ph.current_result->peers = ph.current_p;
632 ph.current_result->s_total = GNUNET_TIME_absolute_get ();
633 ph.current_result->d_total_full = GNUNET_TIME_UNIT_FOREVER_REL;
634 ph.current_result->d_setup_full = GNUNET_TIME_UNIT_FOREVER_REL;
635 ph.current_result->d_lp_full = GNUNET_TIME_UNIT_FOREVER_REL;
636 ph.current_result->d_mlp_full = GNUNET_TIME_UNIT_FOREVER_REL;
637 ph.current_result->info = add;
638 if ((add == GAS_INFO_UPDATED) || (GNUNET_YES == ph.performed_update))
639 {
640 ph.current_result->update = GNUNET_YES;
641 }
642 else
643 {
644 ph.current_result->update = GNUNET_NO;
645 }
646 }
647 return;
648
649 case GAS_OP_SOLVE_STOP:
650 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
651 "Solver notifies `%s' with result `%s', `%s'\n",
652 "GAS_OP_SOLVE_STOP",
653 (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL", add_info);
654 if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
655 {
656 /* We do not expect a solution at the moment */
657 GNUNET_break (0);
658 return;
659 }
660
661 if (GAS_STAT_SUCCESS == stat)
662 ph.current_result->valid = GNUNET_YES;
663 else
664 ph.current_result->valid = GNUNET_NO;
665
666 if (NULL != ph.current_result)
667 {
668 /* Finalize result */
669 ph.current_result->e_total = GNUNET_TIME_absolute_get ();
670 ph.current_result->d_total_full = GNUNET_TIME_absolute_get_difference (
671 ph.current_result->s_total, ph.current_result->e_total);
672 }
673 ph.current_result = NULL;
674 return;
675
676 case GAS_OP_SOLVE_SETUP_START:
677 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
678 "Solver notifies `%s' with result `%s'\n",
679 "GAS_OP_SOLVE_SETUP_START",
680 (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
681 if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
682 {
683 GNUNET_break (0);
684 return;
685 }
686
687 if (GAS_STAT_SUCCESS == stat)
688 ph.current_result->valid = GNUNET_YES;
689 else
690 ph.current_result->valid = GNUNET_NO;
691
692 ph.current_result->s_setup = GNUNET_TIME_absolute_get ();
693 return;
694
695 case GAS_OP_SOLVE_SETUP_STOP:
696 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
697 "Solver notifies `%s' with result `%s'\n",
698 "GAS_OP_SOLVE_SETUP_STOP",
699 (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
700 if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
701 {
702 GNUNET_break (0);
703 return;
704 }
705
706 if (GAS_STAT_SUCCESS == stat)
707 ph.current_result->valid = GNUNET_YES;
708 else
709 ph.current_result->valid = GNUNET_NO;
710
711 ph.current_result->e_setup = GNUNET_TIME_absolute_get ();
712 ph.current_result->d_setup_full = GNUNET_TIME_absolute_get_difference (
713 ph.current_result->s_setup, ph.current_result->e_setup);
714 return;
715
716 case GAS_OP_SOLVE_MLP_LP_START:
717 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
718 "Solver notifies `%s' with result `%s'\n",
719 "GAS_OP_SOLVE_LP_START",
720 (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
721 if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
722 {
723 GNUNET_break (0);
724 return;
725 }
726
727 if (GAS_STAT_SUCCESS == stat)
728 ph.current_result->valid = GNUNET_YES;
729 else
730 ph.current_result->valid = GNUNET_NO;
731
732 ph.current_result->s_lp = GNUNET_TIME_absolute_get ();
733 return;
734
735 case GAS_OP_SOLVE_MLP_LP_STOP:
736 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
737 "Solver notifies `%s' with result `%s'\n",
738 "GAS_OP_SOLVE_LP_STOP",
739 (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
740 if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
741 {
742 GNUNET_break (0);
743 return;
744 }
745
746 if (GAS_STAT_SUCCESS == stat)
747 ph.current_result->valid = GNUNET_YES;
748 else
749 ph.current_result->valid = GNUNET_NO;
750
751 ph.current_result->e_lp = GNUNET_TIME_absolute_get ();
752 ph.current_result->d_lp_full = GNUNET_TIME_absolute_get_difference (
753 ph.current_result->s_lp, ph.current_result->e_lp);
754 return;
755
756 case GAS_OP_SOLVE_MLP_MLP_START:
757 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
758 "Solver notifies `%s' with result `%s'\n",
759 "GAS_OP_SOLVE_MLP_START",
760 (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
761 if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
762 {
763 GNUNET_break (0);
764 return;
765 }
766
767 if (GAS_STAT_SUCCESS == stat)
768 ph.current_result->valid = GNUNET_YES;
769 else
770 ph.current_result->valid = GNUNET_NO;
771
772 ph.current_result->s_mlp = GNUNET_TIME_absolute_get ();
773 return;
774
775 case GAS_OP_SOLVE_MLP_MLP_STOP:
776 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
777 "Solver notifies `%s' with result `%s'\n",
778 "GAS_OP_SOLVE_MLP_STOP",
779 (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
780 if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
781 {
782 GNUNET_break (0);
783 return;
784 }
785
786 if (GAS_STAT_SUCCESS == stat)
787 ph.current_result->valid = GNUNET_YES;
788 else
789 ph.current_result->valid = GNUNET_NO;
790
791 ph.current_result->e_mlp = GNUNET_TIME_absolute_get ();
792 ph.current_result->d_mlp_full = GNUNET_TIME_absolute_get_difference (
793 ph.current_result->s_mlp, ph.current_result->e_mlp);
794 return;
795
796 case GAS_OP_SOLVE_UPDATE_NOTIFICATION_START:
797 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
798 "Solver notifies `%s' with result `%s'\n",
799 "GAS_OP_SOLVE_UPDATE_NOTIFICATION_START",
800 (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
801 return;
802
803 case GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP:
804 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
805 "Solver notifies `%s' with result `%s'\n",
806 "GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP",
807 (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
808 if (GAS_STAT_SUCCESS != stat)
809 {
810 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
811 "Solver `%s' failed to update problem with %u peers and %u address!\n",
812 ph.ats_string, ph.current_p, ph.current_a);
813 }
814
815 return;
816
817 default:
818 break;
819 }
820}
821
822
823/**
824 * Evaluate results for a specific iteration
825 *
826 * @param iteration the iteration to evaluate
827 */
828static void
829evaluate (int iteration)
830{
831 struct Result *cur;
832 int cp;
833
834 for (cp = ph.N_peers_start; cp <= ph.N_peers_end; cp++)
835 {
836 cur = ph.iterations_results[ph.current_iteration - 1].results_array[cp];
837 if (0 == cp)
838 continue;
839 if (NULL == cur)
840 {
841 GNUNET_break (0);
842 fprintf (stderr,
843 "Missing result for %u peers\n", cp);
844 continue;
845 }
846
847
848 if (GNUNET_NO == cur->valid)
849 {
850 fprintf (stderr,
851 "Total time to solve %s for %u peers %u addresses: %s\n",
852 (GNUNET_YES == cur->update) ? "updated" : "full",
853 cur->peers, cur->addresses, "Failed to solve!");
854 continue;
855 }
856
857
858 if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us !=
859 cur->d_total_full.rel_value_us)
860 {
861 fprintf (stderr,
862 "Total time to solve %s for %u peers %u addresses: %llu us\n",
863 (GNUNET_YES == cur->update) ? "updated" : "full",
864 cur->peers, cur->addresses,
865 (unsigned long long) cur->d_total_full.rel_value_us);
866 }
867
868
869 if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us !=
870 cur->d_setup_full.rel_value_us)
871 {
872 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
873 "Total time to setup %s %u peers %u addresses: %llu us\n",
874 (GNUNET_YES == cur->update) ? "updated" : "full",
875 cur->peers, cur->addresses,
876 (unsigned long long) cur->d_setup_full.rel_value_us);
877 }
878
879 if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us !=
880 cur->d_lp_full.rel_value_us)
881 {
882 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
883 "Total time to solve %s LP for %u peers %u addresses: %llu us\n",
884 (GNUNET_YES == cur->update) ? "updated" : "full",
885 cur->peers,
886 cur->addresses,
887 (unsigned long long ) cur->d_lp_full.rel_value_us);
888 }
889
890 if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us !=
891 cur->d_mlp_full.rel_value_us)
892 {
893 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
894 "Total time to solve %s MLP for %u peers %u addresses: %llu us\n",
895 (GNUNET_YES == cur->update) ? "updated" : "full",
896 cur->peers, cur->addresses,
897 (unsigned long long ) cur->d_mlp_full.rel_value_us);
898 }
899 }
900}
901
902
903static unsigned int
904get_connectivity_cb (void *cls,
905 const struct GNUNET_PeerIdentity *peer)
906{
907 return GNUNET_CONTAINER_multipeermap_contains (ph.addresses,
908 peer);
909}
910
911
912/**
913 * Evaluate average results for all iterations
914 */
915static void
916write_all_iterations (void)
917{
918 int c_iteration;
919 int c_peer;
920
921 struct GNUNET_DISK_FileHandle *f_full;
922 struct GNUNET_DISK_FileHandle *f_update;
923 char *data_fn_full;
924 char *data_fn_update;
925 char *data;
926
927 f_full = NULL;
928 f_update = NULL;
929
930 data_fn_full = NULL;
931
932 if (GNUNET_NO == ph.create_datafile)
933 return;
934
935 GNUNET_asprintf (&data_fn_full,
936 "perf_%s_full_%u-%u_%u_%u.data",
937 ph.ats_string,
938 ph.total_iterations,
939 ph.N_peers_start,
940 ph.N_peers_end,
941 ph.N_address);
942 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
943 "Using data file `%s'\n",
944 data_fn_full);
945
946 f_full = GNUNET_DISK_file_open (data_fn_full,
947 GNUNET_DISK_OPEN_WRITE
948 | GNUNET_DISK_OPEN_CREATE,
949 GNUNET_DISK_PERM_USER_EXEC
950 | GNUNET_DISK_PERM_USER_READ
951 | GNUNET_DISK_PERM_USER_WRITE);
952 if (NULL == f_full)
953 {
954 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
955 "Cannot open data file `%s'\n",
956 data_fn_full);
957 GNUNET_free (data_fn_full);
958 return;
959 }
960
961 data =
962 "#peers;addresses;time total in us;#time setup in us;#time lp in us;#time mlp in us;\n";
963 if (GNUNET_SYSERR == GNUNET_DISK_file_write (f_full, data, strlen (data)))
964 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
965 "Cannot write data to log file `%s'\n",
966 data_fn_full);
967
968 data_fn_update = NULL;
969 if (GNUNET_YES == ph.measure_updates)
970 {
971 GNUNET_asprintf (&data_fn_update, "perf_%s_update_%u-%u_%u_%u.data",
972 ph.ats_string,
973 ph.total_iterations,
974 ph.N_peers_start,
975 ph.N_peers_end,
976 ph.N_address);
977 f_update = GNUNET_DISK_file_open (data_fn_update,
978 GNUNET_DISK_OPEN_WRITE
979 | GNUNET_DISK_OPEN_CREATE,
980 GNUNET_DISK_PERM_USER_EXEC
981 | GNUNET_DISK_PERM_USER_READ
982 | GNUNET_DISK_PERM_USER_WRITE);
983 if (NULL == f_update)
984 {
985 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
986 "Cannot open gnuplot file `%s'\n", data_fn_update);
987 GNUNET_free (data_fn_update);
988 if (NULL != f_full)
989 GNUNET_DISK_file_close (f_full);
990 GNUNET_free (data_fn_full);
991 return;
992 }
993
994 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
995 "Using update data file `%s'\n",
996 data_fn_update);
997
998 data =
999 "#peers;addresses;time total in us;#time setup in us;#time lp in us;#time mlp in us;\n";
1000 if (GNUNET_SYSERR == GNUNET_DISK_file_write (f_update, data, strlen (data)))
1001 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1002 "Cannot write data to log file `%s'\n",
1003 data_fn_update);
1004 }
1005
1006 for (c_peer = ph.N_peers_start; c_peer <= ph.N_peers_end; c_peer++)
1007 {
1008 char *data_str;
1009 char *data_tmp;
1010 char *data_upd_str;
1011 char *data_upd_tmp;
1012 GNUNET_asprintf (&data_str, "%u;%u", c_peer, ph.N_address);
1013 if (ph.measure_updates)
1014 GNUNET_asprintf (&data_upd_str, "%u;%u", c_peer, ph.N_address);
1015 for (c_iteration = 0; c_iteration < ph.total_iterations; c_iteration++)
1016 {
1017 struct Result *cur_full_res;
1018 struct Result *cur_upd_res;
1019
1020
1021 // fprintf (stderr, "P: %u I: %u == %p \n", c_peer, c_iteration, cur_res);
1022 cur_full_res = ph.iterations_results[c_iteration].results_array[c_peer];
1023 if (c_peer == 0)
1024 continue;
1025 if (NULL == cur_full_res)
1026 continue;
1027
1028 if (ph.measure_updates)
1029 {
1030 cur_upd_res =
1031 ph.iterations_results[c_iteration].update_results_array[c_peer];
1032 data_upd_tmp = GNUNET_strdup (data_upd_str);
1033 GNUNET_free (data_upd_str);
1034 if (GNUNET_YES == cur_full_res->valid)
1035 {
1036 GNUNET_asprintf (&data_upd_str, "%s;%llu", data_upd_tmp,
1037 (NULL == cur_upd_res) ? 0 :
1038 cur_upd_res->d_total_full.rel_value_us);
1039 }
1040 else
1041 {
1042 GNUNET_asprintf (&data_upd_str, "%s;", data_upd_tmp);
1043 }
1044 GNUNET_free (data_upd_tmp);
1045 }
1046
1047 // fprintf (stderr, "P: %u I: %u: P %i A %i\n", c_peer, c_iteration, cur_res->peers, cur_res->addresses);
1048 // fprintf (stderr, "D total: %llu\n", (long long unsigned int) cur_res->d_total.rel_value_us);
1049
1050 data_tmp = GNUNET_strdup (data_str);
1051 GNUNET_free (data_str);
1052 if (GNUNET_YES == cur_full_res->valid)
1053 {
1054 GNUNET_asprintf (&data_str, "%s;%llu", data_tmp,
1055 cur_full_res->d_total_full.rel_value_us);
1056 }
1057 else
1058 {
1059 GNUNET_asprintf (&data_str, "%s;", data_tmp);
1060 }
1061
1062 GNUNET_free (data_tmp);
1063 }
1064 data_tmp = GNUNET_strdup (data_str);
1065 GNUNET_free (data_str);
1066 GNUNET_asprintf (&data_str, "%s\n", data_tmp);
1067 GNUNET_free (data_tmp);
1068
1069 fprintf (stderr, "Result full solution: %s\n", data_str);
1070 if (GNUNET_SYSERR == GNUNET_DISK_file_write (f_full, data_str, strlen (
1071 data_str)))
1072 GNUNET_break (0);
1073 GNUNET_free (data_str);
1074
1075 if (ph.measure_updates)
1076 {
1077 data_upd_tmp = GNUNET_strdup (data_upd_str);
1078 GNUNET_free (data_upd_str);
1079 GNUNET_asprintf (&data_upd_str, "%s\n", data_upd_tmp);
1080 GNUNET_free (data_upd_tmp);
1081
1082 fprintf (stderr, "Result updated solution: `%s'\n", data_upd_str);
1083 if (GNUNET_SYSERR == GNUNET_DISK_file_write (f_update, data_upd_str,
1084 strlen (data_upd_str)))
1085 GNUNET_break (0);
1086 GNUNET_free (data_upd_str);
1087 }
1088 }
1089
1090 if ((NULL != f_full) && (GNUNET_SYSERR == GNUNET_DISK_file_close (f_full)))
1091 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Cannot close log file `%s'\n",
1092 data_fn_full);
1093 GNUNET_free (data_fn_full);
1094
1095 if ((NULL != f_update) && (GNUNET_SYSERR == GNUNET_DISK_file_close (
1096 f_update)))
1097 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Cannot close log file `%s'\n",
1098 data_fn_update);
1099 GNUNET_free (data_fn_update);
1100}
1101
1102
1103static int
1104do_delete_address (void *cls,
1105 const struct GNUNET_PeerIdentity *pid,
1106 void *value)
1107{
1108 struct ATS_Address *cur = value;
1109
1110 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1111 "Deleting addresses for peer %u\n",
1112 pid);
1113 GNUNET_assert (GNUNET_OK ==
1114 GNUNET_CONTAINER_multipeermap_remove (ph.addresses,
1115 pid,
1116 cur));
1117 ph.sf->s_del (ph.sf->cls, cur);
1118 GNUNET_free (cur->atsi);
1119 GNUNET_free (cur);
1120 return GNUNET_OK;
1121}
1122
1123
1124/**
1125 * Run a performance iteration
1126 */
1127static void
1128perf_run_iteration (void)
1129{
1130 int cp;
1131 int ca;
1132 int count_p = ph.N_peers_end;
1133 int count_a = ph.N_address;
1134 struct ATS_Address *cur_addr;
1135 uint32_t net;
1136
1137 ph.iterations_results[ph.current_iteration - 1].results_array =
1138 GNUNET_malloc ((count_p + 1) * sizeof(struct Result *));
1139 if (ph.measure_updates)
1140 ph.iterations_results[ph.current_iteration - 1].update_results_array =
1141 GNUNET_malloc ((count_p + 1) * sizeof(struct Result *));
1142 ph.peers = GNUNET_malloc ((count_p) * sizeof(struct PerfPeer));
1143 for (cp = 0; cp < count_p; cp++)
1144 perf_create_peer (cp);
1145 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1146 "Iteration %u of %u, added %u peers\n", ph.current_iteration,
1147 ph.total_iterations, cp);
1148
1149 for (cp = 0; cp < count_p; cp++)
1150 {
1151 fprintf (stderr, "%u..", cp);
1152 if (GNUNET_NO == ph.bulk_running)
1153 {
1154 ph.bulk_running = GNUNET_YES;
1155 ph.sf->s_bulk_start (ph.sf->cls);
1156 }
1157 ph.current_p = cp + 1;
1158 for (ca = 0; ca < count_a; ca++)
1159 {
1160 cur_addr = perf_create_address (cp, ca);
1161 /* Add address */
1162
1163 /* Random network selection */
1164 // net = 1 + GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, GNUNET_NT_COUNT - 1);
1165 /* Random equally distributed network selection */
1166 net = 1 + (ca % (GNUNET_NT_COUNT - 1));
1167 /* fprintf (stderr, "Network: %u `%s'\n",
1168 * mod_net , GNUNET_NT_to_string(mod_net)); */
1169
1170 cur_addr->atsi = GNUNET_new (struct GNUNET_ATS_Information);
1171 cur_addr->atsi_count = 1;
1172 cur_addr->atsi[0].type = htonl (GNUNET_ATS_NETWORK_TYPE);
1173 cur_addr->atsi[0].value = htonl (net);
1174 ph.sf->s_add (ph.sf->cls, cur_addr, net);
1175
1176 ph.current_a = ca + 1;
1177 perf_address_initial_update (NULL, ph.addresses, cur_addr);
1178 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1179 "Adding address for peer %u address %u in network %s\n", cp,
1180 ca,
1181 GNUNET_NT_to_string (net));
1182 }
1183 /* Notify solver about request */
1184 ph.sf->s_get (ph.sf->cls, &ph.peers[cp].id);
1185
1186 if (cp + 1 >= ph.N_peers_start)
1187 {
1188 /* Disable bulk to solve the problem */
1189 if (GNUNET_YES == ph.bulk_running)
1190 {
1191 ph.expecting_solution = GNUNET_YES;
1192 ph.bulk_running = GNUNET_NO;
1193 ph.sf->s_bulk_stop (ph.sf->cls);
1194 }
1195 else
1196 GNUNET_break (0);
1197
1198 /* Problem is solved by the solver here due to unlocking */
1199 ph.expecting_solution = GNUNET_NO;
1200
1201 /* Update the problem */
1202 if ((0 < ph.opt_update_percent) && (GNUNET_YES == ph.measure_updates))
1203 {
1204 /* Update */
1205 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1206 "Updating problem with %u peers and %u addresses\n", cp + 1,
1207 ca);
1208
1209 ph.expecting_solution = GNUNET_YES;
1210 ph.performed_update = GNUNET_YES;
1211 if (GNUNET_NO == ph.bulk_running)
1212 {
1213 ph.bulk_running = GNUNET_YES;
1214 ph.sf->s_bulk_start (ph.sf->cls);
1215 }
1216 perf_update_all_addresses (cp + 1, ca, ph.opt_update_percent);
1217 ph.bulk_running = GNUNET_NO;
1218 ph.sf->s_bulk_stop (ph.sf->cls);
1219 /* Problem is solved by the solver here due to unlocking */
1220 ph.performed_update = GNUNET_NO;
1221 ph.expecting_solution = GNUNET_NO;
1222 }
1223 GNUNET_assert (GNUNET_NO == ph.bulk_running);
1224 }
1225 }
1226 fprintf (stderr, "\n");
1227 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1228 "Done, cleaning up addresses\n");
1229 if (GNUNET_NO == ph.bulk_running)
1230 {
1231 ph.sf->s_bulk_start (ph.sf->cls);
1232 ph.bulk_running = GNUNET_YES;
1233 }
1234
1235 for (cp = 0; cp < count_p; cp++)
1236 {
1237 GNUNET_CONTAINER_multipeermap_get_multiple (ph.addresses,
1238 &ph.peers[cp].id,
1239 &do_delete_address,
1240 NULL);
1241 }
1242 if (GNUNET_NO == ph.bulk_running)
1243 {
1244 ph.sf->s_bulk_stop (ph.sf->cls);
1245 ph.bulk_running = GNUNET_NO;
1246 }
1247
1248 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1249 "Iteration done\n");
1250 GNUNET_free (ph.peers);
1251}
1252
1253
1254static void
1255run (void *cls, char *const *args, const char *cfgfile,
1256 const struct GNUNET_CONFIGURATION_Handle *cfg)
1257{
1258 GNUNET_log_setup ("perf-ats-solver", "WARNING", NULL);
1259 char *sep;
1260 char *src_filename = GNUNET_strdup (__FILE__);
1261 char *test_filename = cls;
1262 char *solver;
1263 char *plugin;
1264 struct GNUNET_CONFIGURATION_Handle *solver_cfg;
1265 unsigned long long quotas_in[GNUNET_NT_COUNT];
1266 unsigned long long quotas_out[GNUNET_NT_COUNT];
1267 int c;
1268 int c2;
1269
1270 /* Extract test name */
1271 if (NULL == (sep = (strstr (src_filename, ".c"))))
1272 {
1273 GNUNET_free (src_filename);
1274 GNUNET_break (0);
1275 ret = 1;
1276 return;
1277 }
1278 sep[0] = '\0';
1279
1280 if (NULL != (sep = strstr (test_filename, ".exe")))
1281 sep[0] = '\0';
1282
1283 if (NULL == (solver = strstr (test_filename, src_filename)))
1284 {
1285 GNUNET_free (src_filename);
1286 GNUNET_break (0);
1287 ret = 1;
1288 return;
1289 }
1290 solver += strlen (src_filename) + 1;
1291
1292 if (0 == strcmp (solver, "proportional"))
1293 {
1294 ph.ats_string = "proportional";
1295 }
1296 else if (0 == strcmp (solver, "mlp"))
1297 {
1298 ph.ats_string = "mlp";
1299 }
1300 else if ((0 == strcmp (solver, "ril")))
1301 {
1302 ph.ats_string = "ril";
1303 }
1304 else
1305 {
1306 GNUNET_free (src_filename);
1307 GNUNET_break (0);
1308 ret = 1;
1309 return;
1310 }
1311 GNUNET_free (src_filename);
1312
1313 /* Calculate peers */
1314 if ((0 == ph.N_peers_start) && (0 == ph.N_peers_end))
1315 {
1316 ph.N_peers_start = DEFAULT_PEERS_START;
1317 ph.N_peers_end = DEFAULT_PEERS_END;
1318 }
1319 if (0 == ph.N_address)
1320 ph.N_address = DEFAULT_ADDRESSES;
1321
1322
1323 if (ph.N_peers_start != ph.N_peers_end)
1324 fprintf (stderr,
1325 "Benchmarking solver `%s' with %u to %u peers and %u addresses in %u iterations\n",
1326 ph.ats_string, ph.N_peers_start, ph.N_peers_end, ph.N_address,
1327 ph.total_iterations);
1328 else
1329 fprintf (stderr,
1330 "Benchmarking solver `%s' with %u peers and %u addresses in %u iterations\n",
1331 ph.ats_string, ph.N_peers_end, ph.N_address, ph.total_iterations);
1332
1333 if (0 == ph.opt_update_percent)
1334 ph.opt_update_percent = DEFAULT_UPDATE_PERCENTAGE;
1335
1336 /* Load quotas */
1337 solver_cfg = GNUNET_CONFIGURATION_create ();
1338 if ((NULL == solver_cfg) || (GNUNET_SYSERR == (GNUNET_CONFIGURATION_load (
1339 solver_cfg,
1340 "perf_ats_solver.conf"))))
1341 {
1342 GNUNET_break (0);
1343 end_now (1);
1344 return;
1345 }
1346 if (GNUNET_NT_COUNT != load_quotas (solver_cfg,
1347 quotas_out, quotas_in, GNUNET_NT_COUNT))
1348 {
1349 GNUNET_break (0);
1350 end_now (1);
1351 return;
1352 }
1353
1354 /* Create array of DLL to store results for iterations */
1355 ph.iterations_results = GNUNET_malloc (sizeof(struct Iteration)
1356 * ph.total_iterations);
1357
1358 /* Load solver */
1359 ph.env.cfg = solver_cfg;
1360 ph.stat = GNUNET_STATISTICS_create ("ats", cfg);
1361 ph.env.stats = ph.stat;
1362 ph.addresses = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_NO);
1363 ph.env.addresses = ph.addresses;
1364 ph.env.bandwidth_changed_cb = bandwidth_changed_cb;
1365 ph.env.get_connectivity = &get_connectivity_cb;
1366 ph.env.get_preferences = &get_preferences_cb;
1367 ph.env.network_count = GNUNET_NT_COUNT;
1368 ph.env.info_cb = &solver_info_cb;
1369
1370 for (c = 0; c < GNUNET_NT_COUNT; c++)
1371 {
1372 ph.env.out_quota[c] = quotas_out[c];
1373 ph.env.in_quota[c] = quotas_in[c];
1374 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1375 "Loading network quotas: `%s' %llu %llu \n",
1376 GNUNET_NT_to_string (c),
1377 ph.env.out_quota[c],
1378 ph.env.in_quota[c]);
1379 }
1380 GAS_normalization_start ();
1381 GAS_preference_init ();
1382
1383 GNUNET_asprintf (&plugin,
1384 "libgnunet_plugin_ats_%s",
1385 ph.ats_string);
1386 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1387 _ ("Initializing solver `%s'\n"),
1388 ph.ats_string);
1389 if (NULL == (ph.sf = GNUNET_PLUGIN_load (plugin, &ph.env)))
1390 {
1391 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1392 _ ("Failed to initialize solver `%s'!\n"),
1393 plugin);
1394 ret = 1;
1395 return;
1396 }
1397
1398 /* Do the benchmark */
1399 for (ph.current_iteration = 1; ph.current_iteration <= ph.total_iterations;
1400 ph.current_iteration++)
1401 {
1402 fprintf (stderr,
1403 "Iteration %u of %u starting\n",
1404 ph.current_iteration,
1405 ph.total_iterations);
1406 perf_run_iteration ();
1407 evaluate (ph.current_iteration);
1408 fprintf (stderr,
1409 "Iteration %u of %u done\n",
1410 ph.current_iteration,
1411 ph.total_iterations);
1412 }
1413 if (ph.create_datafile)
1414 write_all_iterations ();
1415
1416 /* Unload solver*/
1417 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1418 _ ("Unloading solver `%s'\n"),
1419 ph.ats_string);
1420 GNUNET_PLUGIN_unload (plugin, ph.sf);
1421 ph.sf = NULL;
1422 GNUNET_free (plugin);
1423 for (c = 0; c < ph.total_iterations; c++)
1424 {
1425 for (c2 = ph.N_peers_start; c2 < ph.N_peers_end; c2++)
1426 {
1427 if (0 == c2)
1428 continue;
1429 if (ph.measure_updates)
1430 GNUNET_free (
1431 ph.iterations_results[c].update_results_array[c2]);
1432 GNUNET_free (ph.iterations_results[c].results_array[c2]);
1433 }
1434 if (ph.measure_updates)
1435 GNUNET_free (ph.iterations_results[c].update_results_array);
1436 GNUNET_free (ph.iterations_results[c].results_array);
1437 }
1438 GNUNET_free (ph.iterations_results);
1439
1440 GNUNET_CONFIGURATION_destroy (solver_cfg);
1441 GNUNET_STATISTICS_destroy (ph.stat, GNUNET_NO);
1442}
1443
1444
1445/**
1446 * Main function of the benchmark
1447 *
1448 * @param argc argument count
1449 * @param argv argument values
1450 */
1451int
1452main (int argc, char *argv[])
1453{
1454 /* extract command line arguments */
1455 ph.opt_update_percent = 0;
1456 ph.N_peers_start = 0;
1457 ph.N_peers_end = 0;
1458 ph.N_address = 0;
1459 ph.ats_string = NULL;
1460 ph.create_datafile = GNUNET_NO;
1461 ph.measure_updates = GNUNET_NO;
1462 ph.total_iterations = 1;
1463
1464 static struct GNUNET_GETOPT_CommandLineOption options[] = {
1465 GNUNET_GETOPT_option_uint ('a',
1466 "addresses",
1467 gettext_noop ("addresses to use"),
1468 &ph.N_address),
1469
1470 GNUNET_GETOPT_option_uint ('s',
1471 "start",
1472 gettext_noop ("start with peer"),
1473 &ph.N_peers_start),
1474
1475 GNUNET_GETOPT_option_uint ('e',
1476 "end",
1477 gettext_noop ("end with peer"),
1478 &ph.N_peers_end),
1479
1480 GNUNET_GETOPT_option_uint ('i',
1481 "iterations",
1482 gettext_noop (
1483 "number of iterations used for averaging (default: 1)"),
1484 &ph.total_iterations),
1485
1486 GNUNET_GETOPT_option_uint ('p',
1487 "percentage",
1488 gettext_noop (
1489 "update a fix percentage of addresses"),
1490 &ph.opt_update_percent),
1491
1492 GNUNET_GETOPT_option_flag ('d',
1493 "data",
1494 gettext_noop ("create data file"),
1495 &ph.create_datafile),
1496
1497 GNUNET_GETOPT_option_flag ('u',
1498 "update",
1499 gettext_noop ("measure updates"),
1500 &ph.measure_updates),
1501
1502 GNUNET_GETOPT_OPTION_END
1503 };
1504
1505 GNUNET_PROGRAM_run (argc, argv, argv[0], NULL, options, &run, argv[0]);
1506 return ret;
1507}
1508
1509
1510/* end of file perf_ats_solver.c */
diff --git a/src/ats/perf_ats_solver.conf b/src/ats/perf_ats_solver.conf
deleted file mode 100644
index a535891df..000000000
--- a/src/ats/perf_ats_solver.conf
+++ /dev/null
@@ -1,28 +0,0 @@
1[ats]
2# Network specific inbound/outbound quotas
3UNSPECIFIED_QUOTA_IN = 1000000
4UNSPECIFIED_QUOTA_OUT = 1000000
5# LOOPBACK
6LOOPBACK_QUOTA_IN = 10000000
7LOOPBACK_QUOTA_OUT = 10000000
8# LAN
9LAN_QUOTA_IN = 10000000
10LAN_QUOTA_OUT = 10000000
11# WAN
12WAN_QUOTA_IN = 10000000
13WAN_QUOTA_OUT = 10000000
14# WLAN
15WLAN_QUOTA_IN = 10000000
16WLAN_QUOTA_OUT = 10000000
17# BLUETOOTH
18BLUETOOTH_QUOTA_IN = 10000000
19BLUETOOTH_QUOTA_OUT = 10000000
20
21# Proportional specific settings
22# How proportional to preferences is bandwidth distribution in a network
23# 1: Fair with respect to addresses without preferences
24# > 10: The bigger, the more respect is paid to preferences
25PROP_PROPORTIONALITY_FACTOR = 2.00
26# Should we stick to existing connections are prefer to switch?
27# [10...200], lower value prefers to switch, bigger value is more tolerant
28PROP_STABILITY_FACTOR = 1.25
diff --git a/src/ats/perf_ats_solver_proportional.conf b/src/ats/perf_ats_solver_proportional.conf
deleted file mode 100644
index e69de29bb..000000000
--- a/src/ats/perf_ats_solver_proportional.conf
+++ /dev/null
diff --git a/src/ats/plugin_ats_proportional.c b/src/ats/plugin_ats_proportional.c
deleted file mode 100644
index d3062a5c0..000000000
--- a/src/ats/plugin_ats_proportional.c
+++ /dev/null
@@ -1,1243 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011-2015 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file ats/plugin_ats_proportional.c
22 * @brief ATS proportional solver
23 * @author Matthias Wachs
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_statistics_service.h"
28#include "gnunet_ats_service.h"
29#include "gnunet_ats_plugin.h"
30#include "gnunet-service-ats_addresses.h"
31
32#define LOG(kind, ...) GNUNET_log_from (kind, "ats-proportional", __VA_ARGS__)
33
34/**
35 * How much do we value stability over adaptation by default. A low
36 * value (close to 1.0) means we adapt as soon as possible, a larger
37 * value means that we have to have the respective factor of an
38 * advantage (or delay) before we adapt and sacrifice stability.
39 */
40#define PROP_STABILITY_FACTOR 1.25
41
42
43/**
44 * Default value to assume for the proportionality factor, if none is
45 * given in the configuration. This factor determines how strong the
46 * bandwidth allocation will orient itself on the application
47 * preferences. A lower factor means a more balanced bandwidth
48 * distribution while a larger number means a distribution more in
49 * line with application (bandwidth) preferences.
50 */
51#define PROPORTIONALITY_FACTOR 2.0
52
53
54/**
55 * Address information stored for the proportional solver in the
56 * `solver_information` member of `struct GNUNET_ATS_Address`.
57 *
58 * They are also stored in the respective `struct Network`'s linked
59 * list.
60 */
61struct AddressWrapper
62{
63 /**
64 * Next in DLL
65 */
66 struct AddressWrapper *next;
67
68 /**
69 * Previous in DLL
70 */
71 struct AddressWrapper *prev;
72
73 /**
74 * The address
75 */
76 struct ATS_Address *addr;
77
78 /**
79 * Network scope this address is in
80 */
81 struct Network *network;
82
83 /**
84 * Inbound quota
85 */
86 uint32_t calculated_quota_in;
87
88 /**
89 * Outbound quota
90 */
91 uint32_t calculated_quota_out;
92
93 /**
94 * When was this address activated
95 */
96 struct GNUNET_TIME_Absolute activated;
97};
98
99
100/**
101 * Representation of a network
102 */
103struct Network
104{
105 /**
106 * Network description
107 */
108 const char *desc;
109
110 /**
111 * String for statistics total addresses
112 */
113 char *stat_total;
114
115 /**
116 * String for statistics active addresses
117 */
118 char *stat_active;
119
120 /**
121 * Linked list of addresses in this network: head
122 */
123 struct AddressWrapper *head;
124
125 /**
126 * Linked list of addresses in this network: tail
127 */
128 struct AddressWrapper *tail;
129
130 /**
131 * Total inbound quota
132 */
133 unsigned long long total_quota_in;
134
135 /**
136 * Total outbound quota
137 */
138 unsigned long long total_quota_out;
139
140 /**
141 * ATS network type
142 */
143 enum GNUNET_NetworkType type;
144
145 /**
146 * Number of active addresses for this network
147 */
148 unsigned int active_addresses;
149
150 /**
151 * Number of total addresses for this network
152 */
153 unsigned int total_addresses;
154};
155
156
157/**
158 * A handle for the proportional solver
159 */
160struct GAS_PROPORTIONAL_Handle
161{
162 /**
163 * Our execution environment.
164 */
165 struct GNUNET_ATS_PluginEnvironment *env;
166
167 /**
168 * Networks array
169 */
170 struct Network *network_entries;
171
172 /**
173 * Proportionality factor
174 */
175 double prop_factor;
176
177 /**
178 * Stability factor
179 */
180 double stability_factor;
181
182 /**
183 * Bulk lock counter. If zero, we are not locked.
184 */
185 unsigned int bulk_lock;
186
187 /**
188 * Number of changes made while solver was locked. We really only
189 * use 0/non-zero to check on unlock if we have to run the update.
190 */
191 unsigned int bulk_requests;
192
193 /**
194 * Number of active addresses for solver
195 */
196 unsigned int active_addresses;
197};
198
199
200/**
201 * Test if bandwidth is available in this network to add an additional address.
202 *
203 * @param net the network type to check
204 * @param extra for how many extra addresses do we check?
205 * @return #GNUNET_YES or #GNUNET_NO
206 */
207static int
208is_bandwidth_available_in_network (struct Network *net,
209 int extra)
210{
211 unsigned int na;
212 uint32_t min_bw = ntohl (GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__);
213
214 GNUNET_assert (((int) net->active_addresses) + extra >= 0);
215 na = net->active_addresses + extra;
216 if (0 == na)
217 return GNUNET_YES;
218 if (((net->total_quota_in / na) > min_bw) &&
219 ((net->total_quota_out / na) > min_bw))
220 return GNUNET_YES;
221 LOG (GNUNET_ERROR_TYPE_DEBUG,
222 "No bandwidth available in network\n");
223 return GNUNET_NO;
224}
225
226
227/**
228 * Test if all peers in this network require connectivity at level at
229 * least @a con.
230 *
231 * @param s the solver handle
232 * @param net the network type to check
233 * @param con connection return value threshold to check
234 * @return #GNUNET_YES or #GNUNET_NO
235 */
236static int
237all_require_connectivity (struct GAS_PROPORTIONAL_Handle *s,
238 struct Network *net,
239 unsigned int con)
240{
241 struct AddressWrapper *aw;
242
243 for (aw = net->head; NULL != aw; aw = aw->next)
244 if (con >
245 s->env->get_connectivity (s->env->cls,
246 &aw->addr->peer))
247 return GNUNET_NO;
248 return GNUNET_YES;
249}
250
251
252/**
253 * Update bandwidth assigned to peers in this network. The basic idea
254 * is to assign every peer in the network the minimum bandwidth, and
255 * then distribute the remaining bandwidth proportional to application
256 * preferences.
257 *
258 * @param s the solver handle
259 * @param net the network type to update
260 */
261static void
262distribute_bandwidth (struct GAS_PROPORTIONAL_Handle *s,
263 struct Network *net)
264{
265 const uint32_t min_bw = ntohl (GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__);
266 struct AddressWrapper *aw;
267 unsigned long long remaining_quota_in;
268 unsigned long long quota_out_used;
269 unsigned long long remaining_quota_out;
270 unsigned long long quota_in_used;
271 unsigned int count_addresses;
272 double sum_relative_peer_prefences;
273 double peer_weight;
274 double total_weight;
275 const double *peer_relative_prefs;
276
277 LOG (GNUNET_ERROR_TYPE_INFO,
278 "Recalculate quota for network type `%s' for %u addresses (in/out): %llu/%llu \n",
279 net->desc,
280 net->active_addresses,
281 net->total_quota_in,
282 net->total_quota_in);
283
284 if (0 == net->active_addresses)
285 return; /* no addresses to update */
286
287 /* sanity checks */
288 if ((net->active_addresses * min_bw) > net->total_quota_in)
289 {
290 GNUNET_break (0);
291 return;
292 }
293 if ((net->active_addresses * min_bw) > net->total_quota_out)
294 {
295 GNUNET_break (0);
296 return;
297 }
298
299 /* Calculate sum of relative preference for active addresses in this
300 network */
301 sum_relative_peer_prefences = 0.0;
302 count_addresses = 0;
303 for (aw = net->head; NULL != aw; aw = aw->next)
304 {
305 if (GNUNET_YES != aw->addr->active)
306 continue;
307 peer_relative_prefs = s->env->get_preferences (s->env->cls,
308 &aw->addr->peer);
309 sum_relative_peer_prefences
310 += peer_relative_prefs[GNUNET_ATS_PREFERENCE_BANDWIDTH];
311 count_addresses++;
312 }
313 if (count_addresses != net->active_addresses)
314 {
315 GNUNET_break (0);
316 LOG (GNUNET_ERROR_TYPE_WARNING,
317 "%s: Counted %u active addresses, expected %u active addresses\n",
318 net->desc,
319 count_addresses,
320 net->active_addresses);
321 /* try to fix... */
322 net->active_addresses = count_addresses;
323 }
324 LOG (GNUNET_ERROR_TYPE_INFO,
325 "Total relative preference %.3f for %u addresses in network %s\n",
326 sum_relative_peer_prefences,
327 net->active_addresses,
328 net->desc);
329
330 /* check how much we have to distribute */
331 remaining_quota_in = net->total_quota_in - (net->active_addresses * min_bw);
332 remaining_quota_out = net->total_quota_out - (net->active_addresses * min_bw);
333 LOG (GNUNET_ERROR_TYPE_DEBUG,
334 "Proportionally distributable bandwidth (in/out): %llu/%llu\n",
335 remaining_quota_in,
336 remaining_quota_out);
337
338 /* distribute remaining quota; we do not do it exactly proportional,
339 but balance "even" distribution ("net->active_addresses") with
340 the preference sum using the "prop_factor". */
341 total_weight = net->active_addresses
342 + s->prop_factor * sum_relative_peer_prefences;
343 quota_out_used = 0;
344 quota_in_used = 0;
345 for (aw = net->head; NULL != aw; aw = aw->next)
346 {
347 if (GNUNET_YES != aw->addr->active)
348 {
349 /* set to 0, just to be sure */
350 aw->calculated_quota_in = 0;
351 aw->calculated_quota_out = 0;
352 continue;
353 }
354 peer_relative_prefs = s->env->get_preferences (s->env->cls,
355 &aw->addr->peer);
356 peer_weight = 1.0
357 + s->prop_factor
358 * peer_relative_prefs[GNUNET_ATS_PREFERENCE_BANDWIDTH];
359
360 aw->calculated_quota_in = min_bw
361 + (peer_weight / total_weight)
362 * remaining_quota_in;
363 aw->calculated_quota_out = min_bw
364 + (peer_weight / total_weight)
365 * remaining_quota_out;
366
367 LOG (GNUNET_ERROR_TYPE_INFO,
368 "New quotas for peer `%s' with weight (cur/total) %.3f/%.3f (in/out) are: %u/%u\n",
369 GNUNET_i2s (&aw->addr->peer),
370 peer_weight,
371 total_weight,
372 (unsigned int) aw->calculated_quota_in,
373 (unsigned int) aw->calculated_quota_out);
374 quota_in_used += aw->calculated_quota_in;
375 quota_out_used += aw->calculated_quota_out;
376 }
377 LOG (GNUNET_ERROR_TYPE_DEBUG,
378 "Total bandwidth assigned is (in/out): %llu /%llu\n",
379 quota_in_used,
380 quota_out_used);
381 /* +1 due to possible rounding errors */
382 GNUNET_break (quota_out_used <= net->total_quota_out + 1);
383 GNUNET_break (quota_in_used <= net->total_quota_in + 1);
384}
385
386
387/**
388 * Notify ATS service of bandwidth changes to addresses.
389 *
390 * @param s solver handle
391 * @param net the network to propagate changes in
392 */
393static void
394propagate_bandwidth (struct GAS_PROPORTIONAL_Handle *s,
395 struct Network *net)
396{
397 struct AddressWrapper *cur;
398
399 for (cur = net->head; NULL != cur; cur = cur->next)
400 {
401 if ((cur->addr->assigned_bw_in == cur->calculated_quota_in) &&
402 (cur->addr->assigned_bw_out == cur->calculated_quota_out))
403 continue;
404 cur->addr->assigned_bw_in = cur->calculated_quota_in;
405 cur->addr->assigned_bw_out = cur->calculated_quota_out;
406 if (GNUNET_YES == cur->addr->active)
407 s->env->bandwidth_changed_cb (s->env->cls,
408 cur->addr);
409 }
410}
411
412
413/**
414 * Distribute bandwidth. The addresses have already been selected,
415 * this is merely distributed the bandwidth among the addresses.
416 *
417 * @param s the solver handle
418 * @param n the network, can be NULL for all networks
419 */
420static void
421distribute_bandwidth_in_network (struct GAS_PROPORTIONAL_Handle *s,
422 struct Network *n)
423{
424 unsigned int i;
425
426 if (0 != s->bulk_lock)
427 {
428 s->bulk_requests++;
429 return;
430 }
431 if (NULL != n)
432 {
433 LOG (GNUNET_ERROR_TYPE_DEBUG,
434 "Redistributing bandwidth in network %s with %u active and %u total addresses\n",
435 GNUNET_NT_to_string (n->type),
436 n->active_addresses,
437 n->total_addresses);
438 s->env->info_cb (s->env->cls,
439 GAS_OP_SOLVE_START,
440 GAS_STAT_SUCCESS,
441 GAS_INFO_PROP_SINGLE);
442 distribute_bandwidth (s,
443 n);
444 s->env->info_cb (s->env->cls,
445 GAS_OP_SOLVE_STOP,
446 GAS_STAT_SUCCESS,
447 GAS_INFO_PROP_SINGLE);
448 s->env->info_cb (s->env->cls,
449 GAS_OP_SOLVE_UPDATE_NOTIFICATION_START,
450 GAS_STAT_SUCCESS,
451 GAS_INFO_PROP_SINGLE);
452 propagate_bandwidth (s,
453 n);
454
455 s->env->info_cb (s->env->cls,
456 GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP,
457 GAS_STAT_SUCCESS,
458 GAS_INFO_PROP_SINGLE);
459 }
460 else
461 {
462 LOG (GNUNET_ERROR_TYPE_DEBUG,
463 "Redistributing bandwidth in all %u networks\n",
464 s->env->network_count);
465 s->env->info_cb (s->env->cls,
466 GAS_OP_SOLVE_START,
467 GAS_STAT_SUCCESS,
468 GAS_INFO_PROP_ALL);
469 for (i = 0; i < s->env->network_count; i++)
470 distribute_bandwidth (s,
471 &s->network_entries[i]);
472 s->env->info_cb (s->env->cls,
473 GAS_OP_SOLVE_STOP,
474 GAS_STAT_SUCCESS,
475 GAS_INFO_PROP_ALL);
476 s->env->info_cb (s->env->cls,
477 GAS_OP_SOLVE_UPDATE_NOTIFICATION_START,
478 GAS_STAT_SUCCESS,
479 GAS_INFO_PROP_ALL);
480 for (i = 0; i < s->env->network_count; i++)
481 propagate_bandwidth (s,
482 &s->network_entries[i]);
483 s->env->info_cb (s->env->cls,
484 GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP,
485 GAS_STAT_SUCCESS,
486 GAS_INFO_PROP_ALL);
487 }
488}
489
490
491/**
492 * Context for finding the best address* Linked list of addresses in this network: head
493 */
494struct FindBestAddressCtx
495{
496 /**
497 * The solver handle
498 */
499 struct GAS_PROPORTIONAL_Handle *s;
500
501 /**
502 * The currently best address
503 */
504 struct ATS_Address *best;
505};
506
507
508/**
509 * Find a "good" address to use for a peer by iterating over the
510 * addresses for this peer. If we already have an existing address,
511 * we stick to it. Otherwise, we pick by lowest distance and then by
512 * lowest latency.
513 *
514 * @param cls the `struct FindBestAddressCtx *' where we store the result
515 * @param key the peer we are trying to find the best address for
516 * @param value another `struct ATS_Address*` to consider using
517 * @return #GNUNET_OK (continue to iterate)
518 */
519static int
520find_best_address_it (void *cls,
521 const struct GNUNET_PeerIdentity *key,
522 void *value)
523{
524 struct FindBestAddressCtx *ctx = cls;
525 struct ATS_Address *current = value;
526 struct AddressWrapper *asi = current->solver_information;
527 struct GNUNET_TIME_Relative active_time;
528 double best_delay;
529 double best_distance;
530 double cur_delay;
531 double cur_distance;
532 unsigned int con;
533 int bw_available;
534 int need;
535
536 /* we need +1 slot if 'current' is not yet active */
537 need = (GNUNET_YES == current->active) ? 0 : 1;
538 /* we save -1 slot if 'best' is active and belongs
539 to the same network (as we would replace it) */
540 if ((NULL != ctx->best) &&
541 (GNUNET_YES == ctx->best->active) &&
542 (((struct AddressWrapper *) ctx->best->solver_information)->network ==
543 asi->network))
544 need--;
545 /* we can gain -1 slot if this peers connectivity
546 requirement is higher than that of another peer
547 in that network scope */
548 con = ctx->s->env->get_connectivity (ctx->s->env->cls,
549 key);
550 if (GNUNET_YES !=
551 all_require_connectivity (ctx->s,
552 asi->network,
553 con))
554 need--;
555 /* test if minimum bandwidth for 'current' would be available */
556 bw_available
557 = is_bandwidth_available_in_network (asi->network,
558 need);
559 if (! bw_available)
560 {
561 /* Bandwidth for this address is unavailable, so we cannot use
562 it. */
563 return GNUNET_OK;
564 }
565 if (GNUNET_YES == current->active)
566 {
567 active_time = GNUNET_TIME_absolute_get_duration (asi->activated);
568 if (active_time.rel_value_us <=
569 ((double) GNUNET_TIME_UNIT_SECONDS.rel_value_us)
570 * ctx->s->stability_factor)
571 {
572 /* Keep active address for stability reasons */
573 ctx->best = current;
574 return GNUNET_NO;
575 }
576 }
577 if (NULL == ctx->best)
578 {
579 /* We so far have nothing else, so go with it! */
580 ctx->best = current;
581 return GNUNET_OK;
582 }
583
584 /* Now compare ATS information */
585 cur_distance = current->norm_distance.norm;
586 best_distance = ctx->best->norm_distance.norm;
587 cur_delay = current->norm_delay.norm;
588 best_delay = ctx->best->norm_delay.norm;
589
590 /* user shorter distance */
591 if (cur_distance < best_distance)
592 {
593 if (GNUNET_NO == ctx->best->active)
594 {
595 /* Activity doesn't influence the equation, use current */
596 ctx->best = current;
597 }
598 else if ((best_distance / cur_distance) > ctx->s->stability_factor)
599 {
600 /* Distance change is significant, switch active address! */
601 ctx->best = current;
602 }
603 }
604
605 /* User connection with less delay */
606 if (cur_delay < best_delay)
607 {
608 if (GNUNET_NO == ctx->best->active)
609 {
610 /* Activity doesn't influence the equation, use current */
611 ctx->best = current;
612 }
613 else if ((best_delay / cur_delay) > ctx->s->stability_factor)
614 {
615 /* Latency change is significant, switch active address! */
616 ctx->best = current;
617 }
618 }
619 return GNUNET_OK;
620}
621
622
623/**
624 * Find the currently best address for a peer from the set of
625 * addresses available or return NULL of no address is available.
626 *
627 * @param s the proportional handle
628 * @param addresses the address hashmap
629 * @param id the peer id
630 * @return the address or NULL
631 */
632struct ATS_Address *
633get_best_address (struct GAS_PROPORTIONAL_Handle *s,
634 struct GNUNET_CONTAINER_MultiPeerMap *addresses,
635 const struct GNUNET_PeerIdentity *id)
636{
637 struct FindBestAddressCtx fba_ctx;
638
639 fba_ctx.best = NULL;
640 fba_ctx.s = s;
641 GNUNET_CONTAINER_multipeermap_get_multiple (addresses,
642 id,
643 &find_best_address_it,
644 &fba_ctx);
645 return fba_ctx.best;
646}
647
648
649/**
650 * Decrease number of active addresses in network.
651 *
652 * @param s the solver handle
653 * @param net the network type
654 */
655static void
656address_decrement_active (struct GAS_PROPORTIONAL_Handle *s,
657 struct Network *net)
658{
659 GNUNET_assert (net->active_addresses > 0);
660 net->active_addresses--;
661 GNUNET_STATISTICS_update (s->env->stats,
662 net->stat_active,
663 -1,
664 GNUNET_NO);
665 GNUNET_assert (s->active_addresses > 0);
666 s->active_addresses--;
667 GNUNET_STATISTICS_update (s->env->stats,
668 "# ATS addresses total",
669 -1,
670 GNUNET_NO);
671}
672
673
674/**
675 * Address map iterator to find current active address for peer.
676 * Asserts that only one address is active per peer.
677 *
678 * @param cls last active address
679 * @param key peer's key
680 * @param value address to check
681 * @return #GNUNET_NO on double active address else #GNUNET_YES;
682 */
683static int
684get_active_address_it (void *cls,
685 const struct GNUNET_PeerIdentity *key,
686 void *value)
687{
688 struct ATS_Address **dest = cls;
689 struct ATS_Address *aa = value;
690
691 if (GNUNET_YES != aa->active)
692 return GNUNET_OK;
693 GNUNET_assert (NULL == (*dest));
694 (*dest) = aa;
695 return GNUNET_OK;
696}
697
698
699/**
700 * Find current active address for peer
701 *
702 * @param s the solver handle
703 * @param peer the peer
704 * @return active address or NULL
705 */
706static struct ATS_Address *
707get_active_address (struct GAS_PROPORTIONAL_Handle *s,
708 const struct GNUNET_PeerIdentity *peer)
709{
710 struct ATS_Address *dest;
711
712 dest = NULL;
713 GNUNET_CONTAINER_multipeermap_get_multiple (s->env->addresses,
714 peer,
715 &get_active_address_it,
716 &dest);
717 return dest;
718}
719
720
721/**
722 * Update active address for a peer. Check if active address exists
723 * and what the best address is, if addresses are different switch.
724 * Then reallocate bandwidth within the affected network scopes.
725 *
726 * @param s solver handle
727 * @param current_address the address currently active for the peer,
728 * NULL for none
729 * @param peer the peer to check
730 */
731static void
732update_active_address (struct GAS_PROPORTIONAL_Handle *s,
733 struct ATS_Address *current_address,
734 const struct GNUNET_PeerIdentity *peer)
735{
736 struct ATS_Address *best_address;
737 struct AddressWrapper *asi_cur;
738 struct AddressWrapper *asi_best;
739 struct AddressWrapper *aw;
740 struct AddressWrapper *aw_min;
741 unsigned int a_con;
742 unsigned int con_min;
743
744 best_address = get_best_address (s,
745 s->env->addresses,
746 peer);
747 if (NULL != best_address)
748 asi_best = best_address->solver_information;
749 else
750 asi_best = NULL;
751 if (current_address == best_address)
752 return; /* no changes */
753 if (NULL != current_address)
754 {
755 /* We switch to a new address (or to none);
756 mark old address as inactive. */
757 asi_cur = current_address->solver_information;
758 GNUNET_assert (GNUNET_YES == current_address->active);
759 LOG (GNUNET_ERROR_TYPE_INFO,
760 "Disabling previous active address for peer `%s'\n",
761 GNUNET_i2s (peer));
762 asi_cur->activated = GNUNET_TIME_UNIT_ZERO_ABS;
763 current_address->active = GNUNET_NO;
764 current_address->assigned_bw_in = 0;
765 current_address->assigned_bw_out = 0;
766 address_decrement_active (s,
767 asi_cur->network);
768 if ((NULL == best_address) ||
769 (asi_best->network != asi_cur->network))
770 distribute_bandwidth_in_network (s,
771 asi_cur->network);
772 if (NULL == best_address)
773 {
774 /* We previously had an active address, but now we cannot
775 * suggest one. Therefore we have to disconnect the peer.
776 * The above call to "distribute_bandwidth_in_network()
777 * does not see 'current_address' so we need to trigger
778 * the update here. */LOG (GNUNET_ERROR_TYPE_DEBUG,
779 "Disconnecting peer `%s'.\n",
780 GNUNET_i2s (peer));
781 s->env->bandwidth_changed_cb (s->env->cls,
782 current_address);
783 return;
784 }
785 }
786 if (NULL == best_address)
787 {
788 /* We do not have a new address, so we are done. */
789 LOG (GNUNET_ERROR_TYPE_DEBUG,
790 "Cannot suggest address for peer `%s'\n",
791 GNUNET_i2s (peer));
792 return;
793 }
794 /* We do have a new address, activate it */
795 LOG (GNUNET_ERROR_TYPE_DEBUG,
796 "Selecting new address %p for peer `%s'\n",
797 best_address,
798 GNUNET_i2s (peer));
799 /* Mark address as active */
800 best_address->active = GNUNET_YES;
801 asi_best->activated = GNUNET_TIME_absolute_get ();
802 asi_best->network->active_addresses++;
803 s->active_addresses++;
804 GNUNET_STATISTICS_update (s->env->stats,
805 "# ATS active addresses total",
806 1,
807 GNUNET_NO);
808 GNUNET_STATISTICS_update (s->env->stats,
809 asi_best->network->stat_active,
810 1,
811 GNUNET_NO);
812 LOG (GNUNET_ERROR_TYPE_INFO,
813 "Address %p for peer `%s' is now active\n",
814 best_address,
815 GNUNET_i2s (peer));
816
817 if (GNUNET_NO ==
818 is_bandwidth_available_in_network (asi_best->network,
819 0))
820 {
821 /* we went over the maximum number of addresses for
822 this scope; remove the address with the smallest
823 connectivity requirement */
824 con_min = UINT32_MAX;
825 aw_min = NULL;
826 for (aw = asi_best->network->head; NULL != aw; aw = aw->next)
827 {
828 if ((con_min >
829 (a_con = s->env->get_connectivity (s->env->cls,
830 &aw->addr->peer))) &&
831 (GNUNET_YES == aw->addr->active))
832 {
833 aw_min = aw;
834 con_min = a_con;
835 if (0 == con_min)
836 break;
837 }
838 }
839 update_active_address (s,
840 aw_min->addr,
841 &aw_min->addr->peer);
842 }
843 distribute_bandwidth_in_network (s,
844 asi_best->network);
845}
846
847
848/**
849 * The preferences for a peer in the problem changed.
850 *
851 * @param solver the solver handle
852 * @param peer the peer to change the preference for
853 * @param kind the kind to change the preference
854 * @param pref_rel the normalized preference value for this kind over all clients
855 */
856static void
857GAS_proportional_change_preference (void *solver,
858 const struct GNUNET_PeerIdentity *peer,
859 enum GNUNET_ATS_PreferenceKind kind,
860 double pref_rel)
861{
862 struct GAS_PROPORTIONAL_Handle *s = solver;
863
864 if (GNUNET_ATS_PREFERENCE_BANDWIDTH != kind)
865 return; /* we do not care */
866 distribute_bandwidth_in_network (s,
867 NULL);
868}
869
870
871/**
872 * Get application feedback for a peer
873 *
874 * @param solver the solver handle
875 * @param application the application
876 * @param peer the peer to change the preference for
877 * @param scope the time interval for this feedback: [now - scope .. now]
878 * @param kind the kind to change the preference
879 * @param score the score
880 */
881static void
882GAS_proportional_feedback (void *solver,
883 struct GNUNET_SERVICE_Client *application,
884 const struct GNUNET_PeerIdentity *peer,
885 const struct GNUNET_TIME_Relative scope,
886 enum GNUNET_ATS_PreferenceKind kind,
887 double score)
888{
889 /* Proportional does not care about feedback */
890}
891
892
893/**
894 * Get the preferred address for a specific peer
895 *
896 * @param solver the solver handle
897 * @param peer the identity of the peer
898 */
899static void
900GAS_proportional_start_get_address (void *solver,
901 const struct GNUNET_PeerIdentity *peer)
902{
903 struct GAS_PROPORTIONAL_Handle *s = solver;
904
905 update_active_address (s,
906 get_active_address (s,
907 peer),
908 peer);
909}
910
911
912/**
913 * Stop notifying about address and bandwidth changes for this peer
914 *
915 * @param solver the solver handle
916 * @param peer the peer
917 */
918static void
919GAS_proportional_stop_get_address (void *solver,
920 const struct GNUNET_PeerIdentity *peer)
921{
922 struct GAS_PROPORTIONAL_Handle *s = solver;
923 struct ATS_Address *cur;
924 struct AddressWrapper *asi;
925
926 cur = get_active_address (s,
927 peer);
928 if (NULL == cur)
929 return;
930 asi = cur->solver_information;
931 distribute_bandwidth_in_network (s,
932 asi->network);
933}
934
935
936/**
937 * Start a bulk operation
938 *
939 * @param solver the solver
940 */
941static void
942GAS_proportional_bulk_start (void *solver)
943{
944 struct GAS_PROPORTIONAL_Handle *s = solver;
945
946 LOG (GNUNET_ERROR_TYPE_DEBUG,
947 "Locking solver for bulk operation ...\n");
948 GNUNET_assert (NULL != solver);
949 s->bulk_lock++;
950}
951
952
953/**
954 * Bulk operation done.
955 *
956 * @param solver our `struct GAS_PROPORTIONAL_Handle *`
957 */
958static void
959GAS_proportional_bulk_stop (void *solver)
960{
961 struct GAS_PROPORTIONAL_Handle *s = solver;
962
963 LOG (GNUNET_ERROR_TYPE_DEBUG,
964 "Unlocking solver from bulk operation ...\n");
965 if (s->bulk_lock < 1)
966 {
967 GNUNET_break (0);
968 return;
969 }
970 s->bulk_lock--;
971 if ((0 == s->bulk_lock) &&
972 (0 < s->bulk_requests))
973 {
974 LOG (GNUNET_ERROR_TYPE_INFO,
975 "No lock pending, recalculating\n");
976 distribute_bandwidth_in_network (s,
977 NULL);
978 s->bulk_requests = 0;
979 }
980}
981
982
983/**
984 * Transport properties for this address have changed
985 *
986 * @param solver solver handle
987 * @param address the address
988 */
989static void
990GAS_proportional_address_property_changed (void *solver,
991 struct ATS_Address *address)
992{
993 struct GAS_PROPORTIONAL_Handle *s = solver;
994 struct AddressWrapper *asi = address->solver_information;
995
996 distribute_bandwidth_in_network (s,
997 asi->network);
998}
999
1000
1001/**
1002 * Add a new single address to a network
1003 *
1004 * @param solver the solver Handle
1005 * @param address the address to add
1006 * @param network network type of this address
1007 */
1008static void
1009GAS_proportional_address_add (void *solver,
1010 struct ATS_Address *address,
1011 uint32_t network)
1012{
1013 struct GAS_PROPORTIONAL_Handle *s = solver;
1014 struct Network *net;
1015 struct AddressWrapper *aw;
1016
1017 GNUNET_assert (network < s->env->network_count);
1018 net = &s->network_entries[network];
1019 net->total_addresses++;
1020
1021 aw = GNUNET_new (struct AddressWrapper);
1022 aw->addr = address;
1023 aw->network = net;
1024 address->solver_information = aw;
1025 GNUNET_CONTAINER_DLL_insert (net->head,
1026 net->tail,
1027 aw);
1028 GNUNET_STATISTICS_update (s->env->stats,
1029 "# ATS addresses total",
1030 1,
1031 GNUNET_NO);
1032 GNUNET_STATISTICS_update (s->env->stats,
1033 net->stat_total,
1034 1,
1035 GNUNET_NO);
1036 update_active_address (s,
1037 get_active_address (s,
1038 &address->peer),
1039 &address->peer);
1040 LOG (GNUNET_ERROR_TYPE_INFO,
1041 "Added new address for `%s', now total %u and active %u addresses in network `%s'\n",
1042 GNUNET_i2s (&address->peer),
1043 net->total_addresses,
1044 net->active_addresses,
1045 net->desc);
1046}
1047
1048
1049/**
1050 * Remove an address from the solver. To do so, we:
1051 * - Removed it from specific network
1052 * - Decrease the number of total addresses
1053 * - If active:
1054 * - decrease number of active addresses
1055 * - update quotas
1056 *
1057 * @param solver the solver handle
1058 * @param address the address to remove
1059 */
1060static void
1061GAS_proportional_address_delete (void *solver,
1062 struct ATS_Address *address)
1063{
1064 struct GAS_PROPORTIONAL_Handle *s = solver;
1065 struct AddressWrapper *aw = address->solver_information;
1066 struct Network *net = aw->network;
1067
1068 LOG (GNUNET_ERROR_TYPE_DEBUG,
1069 "Deleting %s address for peer `%s' from network `%s' (total: %u/active: %u)\n",
1070 (GNUNET_NO == address->active) ? "inactive" : "active",
1071 GNUNET_i2s (&address->peer),
1072 net->desc,
1073 net->total_addresses,
1074 net->active_addresses);
1075
1076 GNUNET_CONTAINER_DLL_remove (net->head,
1077 net->tail,
1078 aw);
1079 GNUNET_assert (net->total_addresses > 0);
1080 net->total_addresses--;
1081 GNUNET_STATISTICS_update (s->env->stats,
1082 net->stat_total,
1083 -1,
1084 GNUNET_NO);
1085 if (GNUNET_YES == address->active)
1086 {
1087 /* Address was active, remove from network and update quotas */
1088 update_active_address (s,
1089 address,
1090 &address->peer);
1091 distribute_bandwidth_in_network (s, net);
1092 }
1093 GNUNET_free (aw);
1094 address->solver_information = NULL;
1095 LOG (GNUNET_ERROR_TYPE_DEBUG,
1096 "After deleting address now total %u and active %u addresses in network `%s'\n",
1097 net->total_addresses,
1098 net->active_addresses,
1099 net->desc);
1100}
1101
1102
1103/**
1104 * Function invoked when the plugin is loaded.
1105 *
1106 * @param[in,out] cls the `struct GNUNET_ATS_PluginEnvironment *` to use;
1107 * modified to return the API functions (ugh).
1108 * @return the `struct GAS_PROPORTIONAL_Handle` to pass as a closure
1109 */
1110void *
1111libgnunet_plugin_ats_proportional_init (void *cls)
1112{
1113 static struct GNUNET_ATS_SolverFunctions sf;
1114 struct GNUNET_ATS_PluginEnvironment *env = cls;
1115 struct GAS_PROPORTIONAL_Handle *s;
1116 struct Network *cur;
1117 float f_tmp;
1118 unsigned int c;
1119
1120 s = GNUNET_new (struct GAS_PROPORTIONAL_Handle);
1121 s->env = env;
1122 sf.cls = s;
1123 sf.s_add = &GAS_proportional_address_add;
1124 sf.s_address_update_property = &GAS_proportional_address_property_changed;
1125 sf.s_get = &GAS_proportional_start_get_address;
1126 sf.s_get_stop = &GAS_proportional_stop_get_address;
1127 sf.s_pref = &GAS_proportional_change_preference;
1128 sf.s_feedback = &GAS_proportional_feedback;
1129 sf.s_del = &GAS_proportional_address_delete;
1130 sf.s_bulk_start = &GAS_proportional_bulk_start;
1131 sf.s_bulk_stop = &GAS_proportional_bulk_stop;
1132 s->stability_factor = PROP_STABILITY_FACTOR;
1133 if (GNUNET_SYSERR !=
1134 GNUNET_CONFIGURATION_get_value_float (env->cfg,
1135 "ats",
1136 "PROP_STABILITY_FACTOR",
1137 &f_tmp))
1138 {
1139 if ((f_tmp < 1.0) || (f_tmp > 2.0))
1140 {
1141 LOG (GNUNET_ERROR_TYPE_ERROR,
1142 _ ("Invalid %s configuration %f \n"),
1143 "PROP_STABILITY_FACTOR",
1144 f_tmp);
1145 }
1146 else
1147 {
1148 s->stability_factor = f_tmp;
1149 LOG (GNUNET_ERROR_TYPE_INFO,
1150 "Using %s of %.3f\n",
1151 "PROP_STABILITY_FACTOR",
1152 f_tmp);
1153 }
1154 }
1155 s->prop_factor = PROPORTIONALITY_FACTOR;
1156 if (GNUNET_SYSERR !=
1157 GNUNET_CONFIGURATION_get_value_float (env->cfg,
1158 "ats",
1159 "PROP_PROPORTIONALITY_FACTOR",
1160 &f_tmp))
1161 {
1162 if (f_tmp < 1.0)
1163 {
1164 LOG (GNUNET_ERROR_TYPE_ERROR,
1165 _ ("Invalid %s configuration %f\n"),
1166 "PROP_PROPORTIONALITY_FACTOR",
1167 f_tmp);
1168 }
1169 else
1170 {
1171 s->prop_factor = f_tmp;
1172 LOG (GNUNET_ERROR_TYPE_INFO,
1173 "Using %s of %.3f\n",
1174 "PROP_PROPORTIONALITY_FACTOR",
1175 f_tmp);
1176 }
1177 }
1178
1179 s->network_entries = GNUNET_malloc (env->network_count
1180 * sizeof(struct Network));
1181 for (c = 0; c < env->network_count; c++)
1182 {
1183 cur = &s->network_entries[c];
1184 cur->type = c;
1185 cur->total_quota_in = env->in_quota[c];
1186 cur->total_quota_out = env->out_quota[c];
1187 cur->desc = GNUNET_NT_to_string (c);
1188 GNUNET_asprintf (&cur->stat_total,
1189 "# ATS addresses %s total",
1190 cur->desc);
1191 GNUNET_asprintf (&cur->stat_active,
1192 "# ATS active addresses %s total",
1193 cur->desc);
1194 LOG (GNUNET_ERROR_TYPE_INFO,
1195 "Added network %u `%s' (%llu/%llu)\n",
1196 c,
1197 cur->desc,
1198 cur->total_quota_in,
1199 cur->total_quota_out);
1200 }
1201 return &sf;
1202}
1203
1204
1205/**
1206 * Function used to unload the plugin.
1207 *
1208 * @param cls return value from #libgnunet_plugin_ats_proportional_init()
1209 */
1210void *
1211libgnunet_plugin_ats_proportional_done (void *cls)
1212{
1213 struct GNUNET_ATS_SolverFunctions *sf = cls;
1214 struct GAS_PROPORTIONAL_Handle *s = sf->cls;
1215 struct AddressWrapper *cur;
1216 struct AddressWrapper *next;
1217 unsigned int c;
1218
1219 for (c = 0; c < s->env->network_count; c++)
1220 {
1221 GNUNET_break (0 == s->network_entries[c].total_addresses);
1222 GNUNET_break (0 == s->network_entries[c].active_addresses);
1223 next = s->network_entries[c].head;
1224 while (NULL != (cur = next))
1225 {
1226 next = cur->next;
1227 GNUNET_CONTAINER_DLL_remove (s->network_entries[c].head,
1228 s->network_entries[c].tail,
1229 cur);
1230 GNUNET_free (cur->addr->solver_information);
1231 GNUNET_free (cur);
1232 }
1233 GNUNET_free (s->network_entries[c].stat_total);
1234 GNUNET_free (s->network_entries[c].stat_active);
1235 }
1236 GNUNET_break (0 == s->active_addresses);
1237 GNUNET_free (s->network_entries);
1238 GNUNET_free (s);
1239 return NULL;
1240}
1241
1242
1243/* end of plugin_ats_proportional.c */
diff --git a/src/ats/test_ats_api.c b/src/ats/test_ats_api.c
deleted file mode 100644
index 390cafe0f..000000000
--- a/src/ats/test_ats_api.c
+++ /dev/null
@@ -1,296 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010-2015 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file ats/test_ats_api.c
22 * @brief test ATS
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "test_ats_lib.h"
27
28/**
29 * Global timeout for the testcase.
30 */
31#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 3)
32
33/**
34 * Definition of the test as a sequence of commands.
35 */
36static struct Command test_commands[] = {
37 {
38 .code = CMD_ADD_ADDRESS,
39 .label = "add-address-0-0",
40 .details.add_address = {
41 .pid = 0,
42 .addr_num = 0,
43 .addr_flags = GNUNET_HELLO_ADDRESS_INFO_NONE,
44 .session = 0,
45 .properties = {
46 .scope = GNUNET_NT_LAN
47 }
48
49
50 }
51
52
53 },
54 /* 1: adding same address again should fail */
55 {
56 .code = CMD_ADD_ADDRESS,
57 .label = "add-address-0-0:FAIL",
58 .details.add_address = {
59 .pid = 0,
60 .addr_num = 0,
61 .addr_flags = GNUNET_HELLO_ADDRESS_INFO_NONE,
62 .session = 0,
63 .properties = {
64 .scope = GNUNET_NT_LAN
65 },
66 .expect_fail = 1
67 }
68
69
70 },
71 /* 2: some solver still require explicit start */
72 {
73 .code = CMD_REQUEST_CONNECTION_START,
74 .label = "request-0",
75 .details.request_connection_start = {
76 .pid = 0
77 }
78
79
80 },
81 /* 3: check we got an address */
82 {
83 .code = CMD_AWAIT_ADDRESS_SUGGESTION,
84 .details.await_address_suggestion = {
85 .add_label = "add-address-0-0"
86 }
87
88
89 },
90 /* 4: check monitor also got the address */
91 {
92 .code = CMD_AWAIT_ADDRESS_INFORMATION,
93 .details.await_address_information = {
94 .add_label = "add-address-0-0"
95 }
96
97
98 },
99 /* 5: test session API */
100 {
101 .code = CMD_ADD_SESSION,
102 .label = "add-session-0-0-1",
103 .details.add_session = {
104 .add_label = "add-address-0-0",
105 .session = 1
106 }
107
108
109 },
110 {
111 .code = CMD_DEL_SESSION,
112 .details.del_session = {
113 .add_session_label = "add-session-0-0-1",
114 }
115
116
117 },
118 /* 7: test preference API */
119 {
120 .code = CMD_CHANGE_PREFERENCE,
121 .details.change_preference = {
122 .pid = 0
123 /* FIXME: preference details */
124 }
125
126
127 },
128 {
129 .code = CMD_PROVIDE_FEEDBACK,
130 .details.provide_feedback = {
131 .pid = 0,
132 .scope = { 50LL }
133 /* FIXME: preference details */
134 }
135
136
137 },
138 /* 9: test sanity check address listing */
139 {
140 .code = CMD_LIST_ADDRESSES,
141 .details.list_addresses = {
142 .pid = 0,
143 .all = 1,
144 .min_calls = 2, // ?
145 .max_calls = 2,
146 .min_active_calls = 1,
147 .max_active_calls = 1
148 }
149
150
151 },
152 /* 10: remove address testing */
153 {
154 .code = CMD_DEL_ADDRESS,
155 .details.del_address = {
156 .add_label = "add-address-0-0"
157 }
158
159
160 },
161 /* 11: check we got disconnected */
162 {
163 .code = CMD_AWAIT_DISCONNECT_SUGGESTION,
164 .details.await_disconnect_suggestion = {
165 .pid = 0
166 }
167
168
169 },
170 /* 12: just for symmetry, also stop asking for the connection */
171 {
172 .code = CMD_REQUEST_CONNECTION_STOP,
173 .details.request_connection_stop = {
174 .connect_label = "request-0",
175 }
176
177
178 },
179 /* 13: add address again */
180 {
181 .code = CMD_ADD_ADDRESS,
182 .label = "add-address-0-0:1",
183 .details.add_address = {
184 .pid = 0,
185 .addr_num = 0,
186 .session = 0,
187 .properties = {
188 .scope = GNUNET_NT_LAN
189 }
190
191
192 }
193
194
195 },
196 /* 14: some solver still require explicit start */
197 {
198 .code = CMD_REQUEST_CONNECTION_START,
199 .label = "request-0",
200 .details.request_connection_start = {
201 .pid = 0
202 }
203
204
205 },
206 /* 15: check we got an address */
207 {
208 .code = CMD_AWAIT_ADDRESS_SUGGESTION,
209 .details.await_address_suggestion = {
210 .add_label = "add-address-0-0:1"
211 }
212
213
214 },
215 /* 16: add alternative address */
216 {
217 .code = CMD_ADD_ADDRESS,
218 .label = "add-address-0-1",
219 .details.add_address = {
220 .pid = 0,
221 .addr_num = 1,
222 .addr_flags = GNUNET_HELLO_ADDRESS_INFO_NONE,
223 .session = 0,
224 .properties = {
225 .scope = GNUNET_NT_LAN
226 }
227
228
229 }
230
231
232 },
233 /* 17: remove original address */
234 {
235 .code = CMD_DEL_ADDRESS,
236 .details.del_address = {
237 .add_label = "add-address-0-0:1"
238 }
239
240
241 },
242 /* 18: check we switched to alternative address */
243 {
244 .code = CMD_AWAIT_ADDRESS_SUGGESTION,
245 .details.await_address_suggestion = {
246 .add_label = "add-address-0-1"
247 }
248
249
250 },
251 /* 19: remove alternative address */
252 {
253 .code = CMD_DEL_ADDRESS,
254 .details.del_address = {
255 .add_label = "add-address-0-1"
256 }
257
258
259 },
260 /* 20: check we got disconnected */
261 {
262 .code = CMD_AWAIT_DISCONNECT_SUGGESTION,
263 .details.await_disconnect_suggestion = {
264 .pid = 0
265 }
266
267
268 },
269 /* 21: just for symmetry, also stop asking for the connection */
270 {
271 .code = CMD_REQUEST_CONNECTION_STOP,
272 .details.request_connection_stop = {
273 .connect_label = "request-0",
274 }
275
276
277 },
278 /* Test ends successfully */
279 {
280 .code = CMD_END_PASS
281 }
282};
283
284
285int
286main (int argc,
287 char *argv[])
288{
289 return TEST_ATS_run (argc,
290 argv,
291 test_commands,
292 TIMEOUT);
293}
294
295
296/* end of file test_ats_api.c */
diff --git a/src/ats/test_ats_api.conf b/src/ats/test_ats_api.conf
deleted file mode 100644
index d45e84d18..000000000
--- a/src/ats/test_ats_api.conf
+++ /dev/null
@@ -1,35 +0,0 @@
1@INLINE@ ../../contrib/conf/gnunet/no_forcestart.conf
2
3[PATHS]
4GNUNET_TEST_HOME = $GNUNET_TMP/test-ats-api-scheduling/
5
6[ats]
7# Enable MLP mode (default: NO)
8#MODE = ril
9MODE = mlp
10# Network specific inbound/outbound quotas
11# UNSPECIFIED
12UNSPECIFIED_QUOTA_IN = 64 KiB
13UNSPECIFIED_QUOTA_OUT = 64 KiB
14# LOOPBACK
15LOOPBACK_QUOTA_IN = unlimited
16LOOPBACK_QUOTA_OUT = unlimited
17# LAN
18LAN_QUOTA_IN = unlimited
19LAN_QUOTA_OUT = unlimited
20# WAN
21WAN_QUOTA_IN = 64 KiB
22WAN_QUOTA_OUT = 64 KiB
23# WLAN
24WLAN_QUOTA_IN = 512
25WLAN_QUOTA_OUT = 512
26
27# ATS extended options
28DUMP_MLP = NO
29DUMP_SOLUTION = NO
30DUMP_OVERWRITE = NO
31DUMP_MIN_PEERS = 0
32DUMP_MIN_ADDRS = 0
33DUMP_OVERWRITE = NO
34ATS_MIN_INTERVAL = 15000
35ATS_EXEC_INTERVAL = 30000
diff --git a/src/ats/test_ats_api_delayed.conf b/src/ats/test_ats_api_delayed.conf
deleted file mode 100644
index 3aac88cf9..000000000
--- a/src/ats/test_ats_api_delayed.conf
+++ /dev/null
@@ -1,36 +0,0 @@
1@INLINE@ ../../contrib/conf/gnunet/no_forcestart.conf
2
3[PATHS]
4GNUNET_TEST_HOME = $GNUNET_TMP/test-ats-api-scheduling/
5
6[ats]
7PREFIX = ./test_delay -t 10 --
8# Enable MLP mode (default: NO)
9#MODE = ril
10MODE = mlp
11# Network specific inbound/outbound quotas
12# UNSPECIFIED
13UNSPECIFIED_QUOTA_IN = 64 KiB
14UNSPECIFIED_QUOTA_OUT = 64 KiB
15# LOOPBACK
16LOOPBACK_QUOTA_IN = unlimited
17LOOPBACK_QUOTA_OUT = unlimited
18# LAN
19LAN_QUOTA_IN = unlimited
20LAN_QUOTA_OUT = unlimited
21# WAN
22WAN_QUOTA_IN = 64 KiB
23WAN_QUOTA_OUT = 64 KiB
24# WLAN
25WLAN_QUOTA_IN = 512
26WLAN_QUOTA_OUT = 512
27
28# ATS extended options
29DUMP_MLP = NO
30DUMP_SOLUTION = NO
31DUMP_OVERWRITE = NO
32DUMP_MIN_PEERS = 0
33DUMP_MIN_ADDRS = 0
34DUMP_OVERWRITE = NO
35ATS_MIN_INTERVAL = 15000
36ATS_EXEC_INTERVAL = 30000
diff --git a/src/ats/test_ats_api_proportional.conf b/src/ats/test_ats_api_proportional.conf
deleted file mode 100644
index ee8f8f8e7..000000000
--- a/src/ats/test_ats_api_proportional.conf
+++ /dev/null
@@ -1,24 +0,0 @@
1@INLINE@ ../../contrib/conf/gnunet/no_forcestart.conf
2
3[PATHS]
4GNUNET_TEST_HOME = $GNUNET_TMP/test-ats-proportional/
5
6[ats]
7# Enable PROPORTIONAL mode (default: NO)
8MODE = proportional
9# Network specific inbound/outbound quotas
10# UNSPECIFIED
11UNSPECIFIED_QUOTA_IN = unlimited
12UNSPECIFIED_QUOTA_OUT = unlimited
13# LOOPBACK
14LOOPBACK_QUOTA_IN = unlimited
15LOOPBACK_QUOTA_OUT = unlimited
16# LAN
17LAN_QUOTA_IN = unlimited
18LAN_QUOTA_OUT = unlimited
19# WAN
20WAN_QUOTA_IN = 5 MiB
21WAN_QUOTA_OUT = 5 MiB
22# WLAN
23WLAN_QUOTA_IN = 4096
24WLAN_QUOTA_OUT = 4096
diff --git a/src/ats/test_ats_lib.c b/src/ats/test_ats_lib.c
deleted file mode 100644
index d19da0106..000000000
--- a/src/ats/test_ats_lib.c
+++ /dev/null
@@ -1,1107 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010-2015 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file ats/test_ats_lib.c
22 * @brief test ATS library with a generic interpreter for running ATS tests
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "gnunet_util_lib.h"
27#include "gnunet_ats_service.h"
28#include "gnunet_testing_lib.h"
29#include "test_ats_lib.h"
30
31/**
32 * Information about the last address suggestion we got for a peer.
33 */
34struct AddressSuggestData
35{
36 /**
37 * Which session were we given?
38 */
39 struct GNUNET_ATS_Session *session;
40
41 /**
42 * What address was assigned?
43 */
44 struct GNUNET_HELLO_Address *address;
45
46 /**
47 * Outbound bandwidth assigned.
48 */
49 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out;
50
51 /**
52 * Inbound bandwidth assigned.
53 */
54 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in;
55
56 /**
57 * Was the bandwidth assigned non-zero?
58 */
59 int active;
60};
61
62
63/**
64 * Information about the last address information we got for an address.
65 */
66struct AddressInformationData
67{
68 /**
69 * What address is this data about?
70 */
71 struct GNUNET_HELLO_Address *address;
72
73 /**
74 * Which properties were given?
75 */
76 struct GNUNET_ATS_Properties properties;
77
78 /**
79 * Outbound bandwidth reported.
80 */
81 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out;
82
83 /**
84 * Inbound bandwidth reported.
85 */
86 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in;
87
88 /**
89 * Was the address said to be 'active'?
90 */
91 int active;
92};
93
94
95/**
96 * Scheduling handle
97 */
98static struct GNUNET_ATS_SchedulingHandle *sched_ats;
99
100/**
101 * Connectivity handle
102 */
103static struct GNUNET_ATS_ConnectivityHandle *con_ats;
104
105/**
106 * Performance handle
107 */
108static struct GNUNET_ATS_PerformanceHandle *perf_ats;
109
110/**
111 * Handle for the interpreter task.
112 */
113static struct GNUNET_SCHEDULER_Task *interpreter_task;
114
115/**
116 * Map from peer identities to the last address suggestion
117 * `struct AddressSuggestData` we got for the respective peer.
118 */
119static struct GNUNET_CONTAINER_MultiPeerMap *p2asd;
120
121/**
122 * Map from peer identities to the last address information
123 * sets for all addresses of this peer. Each peer is mapped
124 * to one or more `struct AddressInformationData` entries.
125 */
126static struct GNUNET_CONTAINER_MultiPeerMap *p2aid;
127
128/**
129 * Global timeout for the test.
130 */
131static struct GNUNET_TIME_Relative TIMEOUT;
132
133/**
134 * Return value from #main().
135 */
136static int ret;
137
138/**
139 * Current global command offset into the #commands array.
140 */
141static unsigned int off;
142
143/**
144 * Commands for the current test.
145 */
146static struct Command *test_commands;
147
148
149/**
150 * Free `struct AddressSuggestData` entry.
151 *
152 * @param cls NULL
153 * @param key ignored
154 * @param value the `struct AddressSuggestData` to release
155 * @return #GNUNET_OK (continue to iterate)
156 */
157static int
158free_asd (void *cls,
159 const struct GNUNET_PeerIdentity *key,
160 void *value)
161{
162 struct AddressSuggestData *asd = value;
163
164 GNUNET_assert (GNUNET_YES ==
165 GNUNET_CONTAINER_multipeermap_remove (p2asd,
166 key,
167 asd));
168 GNUNET_free (asd->address);
169 GNUNET_free (asd);
170 return GNUNET_OK;
171}
172
173
174/**
175 * Free `struct AddressInformationData` entry.
176 *
177 * @param cls NULL
178 * @param key ignored
179 * @param value the `struct AddressSuggestData` to release
180 * @return #GNUNET_OK (continue to iterate)
181 */
182static int
183free_aid (void *cls,
184 const struct GNUNET_PeerIdentity *key,
185 void *value)
186{
187 struct AddressInformationData *aid = value;
188
189 GNUNET_assert (GNUNET_YES ==
190 GNUNET_CONTAINER_multipeermap_remove (p2aid,
191 key,
192 aid));
193 GNUNET_free (aid->address);
194 GNUNET_free (aid);
195 return GNUNET_OK;
196}
197
198
199/**
200 * Find latest address suggestion made for the given peer.
201 *
202 * @param pid peer to look up
203 * @return NULL if peer was never involved
204 */
205static struct AddressSuggestData *
206find_address_suggestion (const struct GNUNET_PeerIdentity *pid)
207{
208 return GNUNET_CONTAINER_multipeermap_get (p2asd,
209 pid);
210}
211
212
213/**
214 * Closure for #match_address()
215 */
216struct MatchAddressContext
217{
218 /**
219 * Address to find.
220 */
221 const struct GNUNET_HELLO_Address *addr;
222
223 /**
224 * Where to return address information if found.
225 */
226 struct AddressInformationData *ret;
227};
228
229
230/**
231 * Find matching address information.
232 *
233 * @param cls a `struct MatchAddressContext`
234 * @param key unused
235 * @param value a `struct AddressInformationData`
236 * @return #GNUNET_OK if not found
237 */
238static int
239match_address (void *cls,
240 const struct GNUNET_PeerIdentity *key,
241 void *value)
242{
243 struct MatchAddressContext *mac = cls;
244 struct AddressInformationData *aid = value;
245
246 if (0 == GNUNET_HELLO_address_cmp (mac->addr,
247 aid->address))
248 {
249 mac->ret = aid;
250 return GNUNET_NO;
251 }
252 return GNUNET_OK;
253}
254
255
256/**
257 * Find latest address information made for the given address.
258 *
259 * @param addr address to look up
260 * @return NULL if peer was never involved
261 */
262static struct AddressInformationData *
263find_address_information (const struct GNUNET_HELLO_Address *addr)
264{
265 struct MatchAddressContext mac;
266
267 mac.ret = NULL;
268 mac.addr = addr;
269 GNUNET_CONTAINER_multipeermap_get_multiple (p2aid,
270 &addr->peer,
271 &match_address,
272 &mac);
273 return mac.ret;
274}
275
276
277/**
278 * Task run to terminate the testcase.
279 *
280 * @param cls NULL
281 */
282static void
283end (void *cls)
284{
285 if (0 != ret)
286 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
287 "Test failed at stage %u %s\n",
288 off,
289 (NULL != test_commands[off].label)
290 ? test_commands[off].label
291 : "");
292 if (NULL != interpreter_task)
293 {
294 GNUNET_SCHEDULER_cancel (interpreter_task);
295 interpreter_task = NULL;
296 }
297 if (NULL != sched_ats)
298 {
299 GNUNET_ATS_scheduling_done (sched_ats);
300 sched_ats = NULL;
301 }
302 if (NULL != con_ats)
303 {
304 GNUNET_ATS_connectivity_done (con_ats);
305 con_ats = NULL;
306 }
307 if (NULL != perf_ats)
308 {
309 GNUNET_ATS_performance_done (perf_ats);
310 perf_ats = NULL;
311 }
312 if (NULL != p2asd)
313 {
314 GNUNET_CONTAINER_multipeermap_iterate (p2asd,
315 &free_asd,
316 NULL);
317 GNUNET_CONTAINER_multipeermap_destroy (p2asd);
318 p2asd = NULL;
319 }
320 if (NULL != p2aid)
321 {
322 GNUNET_CONTAINER_multipeermap_iterate (p2aid,
323 &free_aid,
324 NULL);
325 GNUNET_CONTAINER_multipeermap_destroy (p2aid);
326 p2aid = NULL;
327 }
328}
329
330
331/**
332 * Main interpreter loop. Runs the steps of the test.
333 *
334 * @param cls NULL
335 */
336static void
337interpreter (void *cls);
338
339
340/**
341 * Run the interpreter next.
342 */
343static void
344run_interpreter ()
345{
346 if (NULL != interpreter_task)
347 GNUNET_SCHEDULER_cancel (interpreter_task);
348 interpreter_task = GNUNET_SCHEDULER_add_now (&interpreter,
349 NULL);
350}
351
352
353/**
354 * Initialize public key of a peer based on a single number.
355 *
356 * @param pid number to use as the basis
357 * @param pk resulting fake public key
358 */
359static void
360make_peer (uint32_t pid,
361 struct GNUNET_PeerIdentity *pk)
362{
363 memset (pk,
364 (int) pid,
365 sizeof(struct GNUNET_PeerIdentity));
366 GNUNET_memcpy (pk,
367 &pid,
368 sizeof(uint32_t));
369}
370
371
372/**
373 * Generate a fake address based on the given parameters.
374 *
375 * @param pid number of the peer
376 * @param num number of the address at peer @a pid
377 * @param addr_flags flags to use for the address
378 * @return the address
379 */
380static struct GNUNET_HELLO_Address *
381make_address (uint32_t pid,
382 uint32_t num,
383 enum GNUNET_HELLO_AddressInfo addr_flags)
384{
385 struct GNUNET_PeerIdentity pk;
386 uint32_t nbo;
387
388 nbo = htonl (num);
389 make_peer (pid,
390 &pk);
391 return GNUNET_HELLO_address_allocate (&pk,
392 "test",
393 &nbo,
394 sizeof(nbo),
395 addr_flags);
396}
397
398
399/**
400 * Our dummy sessions.
401 */
402struct GNUNET_ATS_Session
403{
404 /**
405 * Field to avoid `0 == sizeof(struct GNUNET_ATS_Session)`.
406 */
407 unsigned int non_empty;
408};
409
410
411/**
412 * Create a session instance for ATS.
413 *
414 * @param i which session number to return
415 * @return NULL if @a i is 0, otherwise a pointer unique to @a i
416 */
417static struct GNUNET_ATS_Session *
418make_session (unsigned int i)
419{
420 struct GNUNET_ATS_Session *baseptr = NULL;
421
422 if (0 == i)
423 return NULL;
424 /* Yes, these are *intentionally* out-of-bounds,
425 and offset from NULL, as nobody should ever
426 use those other than to compare pointers! */
427 return baseptr + i;
428}
429
430
431/**
432 * Find a @a code command before the global #off with the
433 * specified @a label.
434 *
435 * @param code opcode to look for
436 * @param label label to look for, NULL for none
437 * @return previous command with the matching label
438 */
439static struct Command *
440find_command (enum CommandCode code,
441 const char *label)
442{
443 int i;
444
445 if (NULL == label)
446 return NULL;
447 for (i = off - 1; i >= 0; i--)
448 if ((code == test_commands[i].code) &&
449 (0 == strcmp (test_commands[i].label,
450 label)))
451 return &test_commands[i];
452 GNUNET_break (0);
453 return NULL;
454}
455
456
457/**
458 * Function called from #GNUNET_ATS_performance_list_addresses when
459 * we process a #CMD_LIST_ADDRESSES command.
460 *
461 * @param cls the `struct Command` that caused the call
462 * @param address the address, NULL if ATS service was disconnected
463 * @param address_active #GNUNET_YES if this address is actively used
464 * to maintain a connection to a peer;
465 * #GNUNET_NO if the address is not actively used;
466 * #GNUNET_SYSERR if this address is no longer available for ATS
467 * @param bandwidth_out assigned outbound bandwidth for the connection
468 * @param bandwidth_in assigned inbound bandwidth for the connection
469 * @param prop performance data for the address
470 */
471static void
472info_cb (void *cls,
473 const struct GNUNET_HELLO_Address *address,
474 int address_active,
475 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
476 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
477 const struct GNUNET_ATS_Properties *prop)
478{
479 struct Command *c = cls;
480 struct CommandListAddresses *cmd = &c->details.list_addresses;
481
482 if (NULL == address)
483 {
484 cmd->alh = NULL;
485 /* we are done with the iteration, continue to execute */
486 if ((cmd->calls < cmd->min_calls) &&
487 (cmd->active_calls < cmd->min_active_calls))
488 {
489 GNUNET_SCHEDULER_shutdown ();
490 return;
491 }
492 off++;
493 run_interpreter ();
494 return;
495 }
496 switch (address_active)
497 {
498 case GNUNET_YES:
499 cmd->active_calls++;
500 cmd->calls++;
501 break;
502
503 case GNUNET_NO:
504 cmd->calls++;
505 break;
506
507 case GNUNET_SYSERR:
508 return;
509 }
510 if ((cmd->calls > cmd->max_calls) &&
511 (cmd->active_calls < cmd->max_active_calls))
512 {
513 GNUNET_break (0);
514 GNUNET_ATS_performance_list_addresses_cancel (cmd->alh);
515 cmd->alh = NULL;
516 GNUNET_SCHEDULER_shutdown ();
517 return;
518 }
519}
520
521
522/**
523 * Function called with reservation result.
524 *
525 * @param cls closure with the reservation command (`struct Command`)
526 * @param peer identifies the peer
527 * @param amount set to the amount that was actually reserved or unreserved;
528 * either the full requested amount or zero (no partial reservations)
529 * @param res_delay if the reservation could not be satisfied (amount was 0), how
530 * long should the client wait until re-trying?
531 */
532static void
533reservation_cb (void *cls,
534 const struct GNUNET_PeerIdentity *peer,
535 int32_t amount,
536 struct GNUNET_TIME_Relative res_delay)
537{
538 struct Command *cmd = cls;
539 struct GNUNET_PeerIdentity pid;
540
541 cmd->details.reserve_bandwidth.rc = NULL;
542 make_peer (cmd->details.reserve_bandwidth.pid,
543 &pid);
544 GNUNET_assert (0 == GNUNET_memcmp (peer,
545 &pid));
546 switch (cmd->details.reserve_bandwidth.expected_result)
547 {
548 case GNUNET_OK:
549 if (amount != cmd->details.reserve_bandwidth.amount)
550 {
551 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
552 "Unexpectedly failed to reserve %d/%d bytes with delay %s!\n",
553 (int) amount,
554 (int) cmd->details.reserve_bandwidth.amount,
555 GNUNET_STRINGS_relative_time_to_string (res_delay,
556 GNUNET_YES));
557 GNUNET_break (0);
558 GNUNET_SCHEDULER_shutdown ();
559 return;
560 }
561 break;
562
563 case GNUNET_NO:
564 GNUNET_break ((0 != amount) ||
565 (0 != res_delay.rel_value_us));
566 break;
567
568 case GNUNET_SYSERR:
569 if ((amount != 0) ||
570 (0 == res_delay.rel_value_us))
571 {
572 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
573 "Unexpectedly reserved %d bytes with delay %s!\n",
574 (int) amount,
575 GNUNET_STRINGS_relative_time_to_string (res_delay,
576 GNUNET_YES));
577 GNUNET_break (0);
578 GNUNET_SCHEDULER_shutdown ();
579 return;
580 }
581 break;
582 }
583 off++;
584 run_interpreter ();
585}
586
587
588/**
589 * Main interpreter loop. Runs the steps of the test.
590 *
591 * @param cls NULL
592 */
593static void
594interpreter (void *cls)
595
596{
597 struct Command *cmd;
598
599 interpreter_task = NULL;
600 while (1)
601 {
602 cmd = &test_commands[off];
603 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
604 "#%u: %d %s\n",
605 off,
606 (int) cmd->code,
607 (NULL != cmd->label) ? cmd->label : "");
608 switch (cmd->code)
609 {
610 case CMD_END_PASS:
611 ret = 0;
612 GNUNET_SCHEDULER_shutdown ();
613 return;
614
615 case CMD_ADD_ADDRESS:
616 {
617 struct GNUNET_HELLO_Address *addr;
618 struct GNUNET_ATS_Session *session;
619
620 addr = make_address (cmd->details.add_address.pid,
621 cmd->details.add_address.addr_num,
622 cmd->details.add_address.addr_flags);
623 session = make_session (cmd->details.add_address.session);
624 if (cmd->details.add_address.expect_fail)
625 GNUNET_log_skip (1, GNUNET_NO);
626 cmd->details.add_address.ar
627 = GNUNET_ATS_address_add (sched_ats,
628 addr,
629 session,
630 &cmd->details.add_address.properties);
631 GNUNET_free (addr);
632 if (cmd->details.add_address.expect_fail)
633 {
634 GNUNET_log_skip (0, GNUNET_YES);
635 }
636 else if (NULL == cmd->details.add_address.ar)
637 {
638 GNUNET_break (0);
639 GNUNET_SCHEDULER_shutdown ();
640 return;
641 }
642 off++;
643 break;
644 }
645
646 case CMD_DEL_ADDRESS:
647 {
648 struct Command *add;
649
650 add = find_command (CMD_ADD_ADDRESS,
651 cmd->details.del_address.add_label);
652 GNUNET_assert (NULL != add->details.add_address.ar);
653 GNUNET_ATS_address_destroy (add->details.add_address.ar);
654 add->details.add_address.ar = NULL;
655 off++;
656 break;
657 }
658
659 case CMD_AWAIT_ADDRESS_SUGGESTION:
660 {
661 struct GNUNET_PeerIdentity pid;
662 struct GNUNET_HELLO_Address *addr;
663 struct Command *add;
664 struct AddressSuggestData *asd;
665 int done;
666
667 make_peer (cmd->details.await_address_suggestion.pid,
668 &pid);
669 asd = find_address_suggestion (&pid);
670 if (NULL == asd)
671 return;
672 if (GNUNET_NO == asd->active)
673 return; /* last suggestion was to disconnect, wait longer */
674 done = GNUNET_YES;
675 if (NULL != cmd->details.await_address_suggestion.add_label)
676 {
677 done = GNUNET_NO;
678 add = find_command (CMD_ADD_ADDRESS,
679 cmd->details.await_address_suggestion.add_label);
680 addr = make_address (add->details.add_address.pid,
681 add->details.add_address.addr_num,
682 add->details.add_address.addr_flags);
683 if ((asd->session ==
684 make_session (add->details.add_address.session)) &&
685 (0 ==
686 GNUNET_HELLO_address_cmp (addr,
687 asd->address)))
688 done = GNUNET_YES;
689 GNUNET_free (addr);
690 }
691 if (GNUNET_NO == done)
692 return;
693 off++;
694 break;
695 }
696
697 case CMD_AWAIT_DISCONNECT_SUGGESTION:
698 {
699 struct GNUNET_PeerIdentity pid;
700 struct AddressSuggestData *asd;
701
702 make_peer (cmd->details.await_disconnect_suggestion.pid,
703 &pid);
704 asd = find_address_suggestion (&pid);
705 if (NULL == asd)
706 return; /* odd, no suggestion at all yet!? */
707 if (GNUNET_YES == asd->active)
708 return; /* last suggestion was to activate, wait longer */
709 /* last suggestion was to deactivate, condition satisfied! */
710 off++;
711 break;
712 }
713
714 case CMD_REQUEST_CONNECTION_START:
715 {
716 struct GNUNET_PeerIdentity pid;
717
718 make_peer (cmd->details.request_connection_start.pid,
719 &pid);
720 cmd->details.request_connection_start.csh
721 = GNUNET_ATS_connectivity_suggest (con_ats,
722 &pid,
723 1);
724 off++;
725 break;
726 }
727
728 case CMD_REQUEST_CONNECTION_STOP:
729 {
730 struct Command *start;
731
732 start = find_command (CMD_REQUEST_CONNECTION_START,
733 cmd->details.request_connection_stop.connect_label);
734 GNUNET_ATS_connectivity_suggest_cancel (
735 start->details.request_connection_start.csh);
736 start->details.request_connection_start.csh = NULL;
737 off++;
738 break;
739 }
740
741 case CMD_AWAIT_ADDRESS_INFORMATION:
742 {
743 struct AddressInformationData *aid;
744 struct Command *add;
745 struct Command *update;
746 struct GNUNET_HELLO_Address *addr;
747 const struct GNUNET_ATS_Properties *cmp;
748
749 add = find_command (CMD_ADD_ADDRESS,
750 cmd->details.await_address_information.add_label);
751 update = find_command (CMD_UPDATE_ADDRESS,
752 cmd->details.await_address_information.
753 update_label);
754 addr = make_address (add->details.add_address.pid,
755 add->details.add_address.addr_num,
756 add->details.add_address.addr_flags);
757 aid = find_address_information (addr);
758 GNUNET_free (addr);
759 if (NULL == update)
760 cmp = &add->details.add_address.properties;
761 else
762 cmp = &update->details.update_address.properties;
763 if ((NULL != aid) &&
764 (cmp->delay.rel_value_us == aid->properties.delay.rel_value_us) &&
765 (cmp->utilization_out == aid->properties.utilization_out) &&
766 (cmp->utilization_in == aid->properties.utilization_in) &&
767 (cmp->distance == aid->properties.distance) &&
768 (cmp->scope == aid->properties.scope))
769 {
770 off++;
771 break;
772 }
773 return;
774 }
775
776 case CMD_UPDATE_ADDRESS:
777 {
778 struct Command *add;
779
780 add = find_command (CMD_ADD_ADDRESS,
781 cmd->details.update_address.add_label);
782 GNUNET_assert (NULL != add->details.add_address.ar);
783 GNUNET_ATS_address_update (add->details.add_address.ar,
784 &cmd->details.update_address.properties);
785 off++;
786 break;
787 }
788
789 case CMD_ADD_SESSION:
790 {
791 struct Command *add;
792 struct GNUNET_ATS_Session *session;
793
794 add = find_command (CMD_ADD_ADDRESS,
795 cmd->details.add_session.add_label);
796 session = make_session (cmd->details.add_session.session);
797 GNUNET_assert (NULL != add->details.add_address.ar);
798 GNUNET_ATS_address_add_session (add->details.add_address.ar,
799 session);
800 off++;
801 break;
802 }
803
804 case CMD_DEL_SESSION:
805 {
806 struct Command *add_address;
807 struct Command *add_session;
808 struct GNUNET_ATS_Session *session;
809
810 add_session = find_command (CMD_ADD_SESSION,
811 cmd->details.del_session.add_session_label);
812 add_address = find_command (CMD_ADD_ADDRESS,
813 add_session->details.add_session.add_label);
814 GNUNET_assert (NULL != add_address->details.add_address.ar);
815 session = make_session (add_session->details.add_session.session);
816 GNUNET_ATS_address_del_session (add_address->details.add_address.ar,
817 session);
818 off++;
819 break;
820 }
821
822 case CMD_CHANGE_PREFERENCE:
823 {
824 struct GNUNET_PeerIdentity pid;
825
826 make_peer (cmd->details.change_preference.pid,
827 &pid);
828 GNUNET_ATS_performance_change_preference (perf_ats,
829 &pid,
830 GNUNET_ATS_PREFERENCE_END);
831 off++;
832 break;
833 }
834
835 case CMD_PROVIDE_FEEDBACK:
836 {
837 struct GNUNET_PeerIdentity pid;
838
839 make_peer (cmd->details.provide_feedback.pid,
840 &pid);
841 GNUNET_ATS_performance_give_feedback (perf_ats,
842 &pid,
843 cmd->details.provide_feedback.
844 scope,
845 GNUNET_ATS_PREFERENCE_END);
846 off++;
847 break;
848 }
849
850 case CMD_LIST_ADDRESSES:
851 {
852 struct GNUNET_PeerIdentity pid;
853
854 make_peer (cmd->details.list_addresses.pid,
855 &pid);
856 cmd->details.list_addresses.alh
857 = GNUNET_ATS_performance_list_addresses (perf_ats,
858 &pid,
859 cmd->details.list_addresses.
860 all,
861 &info_cb,
862 cmd);
863 return;
864 }
865
866 case CMD_RESERVE_BANDWIDTH:
867 {
868 struct GNUNET_PeerIdentity pid;
869
870 make_peer (cmd->details.reserve_bandwidth.pid,
871 &pid);
872 cmd->details.reserve_bandwidth.rc
873 = GNUNET_ATS_reserve_bandwidth (perf_ats,
874 &pid,
875 cmd->details.reserve_bandwidth.amount,
876 &reservation_cb,
877 cmd);
878 return;
879 }
880
881 case CMD_SLEEP:
882 off++;
883 interpreter_task = GNUNET_SCHEDULER_add_delayed (cmd->details.sleep.delay,
884 &interpreter,
885 NULL);
886 return;
887 } /* end switch */
888 } /* end while(1) */
889}
890
891
892/**
893 * Signature of a function called by ATS with the current bandwidth
894 * and address preferences as determined by ATS.
895 *
896 * @param cls closure, should point to "asc-closure"
897 * @param peer for which we suggest an address, NULL if ATS connection died
898 * @param address suggested address (including peer identity of the peer),
899 * may be NULL to signal disconnect from peer
900 * @param session session to use, NULL to establish a new outgoing session
901 * @param bandwidth_out assigned outbound bandwidth for the connection,
902 * 0 to signal disconnect
903 * @param bandwidth_in assigned inbound bandwidth for the connection,
904 * 0 to signal disconnect
905 */
906static void
907address_suggest_cb (void *cls,
908 const struct GNUNET_PeerIdentity *peer,
909 const struct GNUNET_HELLO_Address *address,
910 struct GNUNET_ATS_Session *session,
911 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
912 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in)
913{
914 const char *asc_cls = cls;
915 struct AddressSuggestData *asd;
916
917 GNUNET_break (0 == strcmp (asc_cls, "asc-closure"));
918 if (NULL == peer)
919 {
920 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
921 "Connection to ATS died, likely a crash!\n");
922 GNUNET_SCHEDULER_shutdown ();
923#if 0
924 /* This is what we should do if we wanted to continue past
925 the ATS crash. */
926 GNUNET_CONTAINER_multipeermap_iterate (p2asd,
927 &free_asd,
928 NULL);
929 GNUNET_CONTAINER_multipeermap_iterate (p2aid,
930 &free_aid,
931 NULL);
932#endif
933 return;
934 }
935
936 asd = find_address_suggestion (peer);
937 if (NULL == asd)
938 {
939 asd = GNUNET_new (struct AddressSuggestData);
940 GNUNET_assert (GNUNET_YES ==
941 GNUNET_CONTAINER_multipeermap_put (p2asd,
942 peer,
943 asd,
944 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
945 }
946 if ((0 == ntohl (bandwidth_out.value__)) &&
947 (0 == ntohl (bandwidth_in.value__)))
948 asd->active = GNUNET_NO;
949 else
950 asd->active = GNUNET_YES;
951 asd->bandwidth_out = bandwidth_out;
952 asd->bandwidth_in = bandwidth_in;
953 asd->session = session;
954 GNUNET_free (asd->address);
955 asd->address = NULL;
956 if (NULL != address)
957 asd->address = GNUNET_HELLO_address_copy (address);
958 if (NULL == interpreter_task)
959 run_interpreter ();
960}
961
962
963/**
964 * Signature of a function that is called with QoS information about an address.
965 *
966 * @param cls closure, should point to "aic-closure"
967 * @param address the address, NULL if ATS service was disconnected
968 * @param address_active #GNUNET_YES if this address is actively used
969 * to maintain a connection to a peer;
970 * #GNUNET_NO if the address is not actively used;
971 * #GNUNET_SYSERR if this address is no longer available for ATS
972 * @param bandwidth_out assigned outbound bandwidth for the connection
973 * @param bandwidth_in assigned inbound bandwidth for the connection
974 * @param prop performance data for the address
975 */
976static void
977address_information_cb (void *cls,
978 const struct GNUNET_HELLO_Address *address,
979 int address_active,
980 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
981 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
982 const struct GNUNET_ATS_Properties *prop)
983{
984 const char *aic_cls = cls;
985 struct AddressInformationData *aid;
986
987 GNUNET_break (0 == strcmp (aic_cls, "aic-closure"));
988 if (NULL == address)
989 {
990 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
991 "Connection to ATS died, likely a crash!\n");
992 GNUNET_CONTAINER_multipeermap_iterate (p2aid,
993 &free_aid,
994 NULL);
995 return;
996 }
997
998 aid = find_address_information (address);
999 if (NULL == aid)
1000 {
1001 aid = GNUNET_new (struct AddressInformationData);
1002 aid->address = GNUNET_HELLO_address_copy (address);
1003 GNUNET_assert (GNUNET_YES ==
1004 GNUNET_CONTAINER_multipeermap_put (p2aid,
1005 &address->peer,
1006 aid,
1007 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
1008 }
1009 aid->active = address_active;
1010 aid->bandwidth_out = bandwidth_out;
1011 aid->bandwidth_in = bandwidth_in;
1012 aid->properties = *prop;
1013 if (NULL == interpreter_task)
1014 run_interpreter ();
1015}
1016
1017
1018/**
1019 * Function run once the ATS service has been started.
1020 *
1021 * @param cls NULL
1022 * @param cfg configuration for the testcase
1023 * @param peer handle to the peer
1024 */
1025static void
1026run (void *cls,
1027 const struct GNUNET_CONFIGURATION_Handle *cfg,
1028 struct GNUNET_TESTING_Peer *peer)
1029{
1030 p2asd = GNUNET_CONTAINER_multipeermap_create (128,
1031 GNUNET_NO);
1032 p2aid = GNUNET_CONTAINER_multipeermap_create (128,
1033 GNUNET_NO);
1034 GNUNET_SCHEDULER_add_delayed (TIMEOUT,
1035 &end,
1036 NULL);
1037
1038 sched_ats = GNUNET_ATS_scheduling_init (cfg,
1039 &address_suggest_cb,
1040 "asc-closure");
1041 if (NULL == sched_ats)
1042 {
1043 GNUNET_break (0);
1044 GNUNET_SCHEDULER_shutdown ();
1045 return;
1046 }
1047 con_ats = GNUNET_ATS_connectivity_init (cfg);
1048 if (NULL == con_ats)
1049 {
1050 GNUNET_break (0);
1051 GNUNET_SCHEDULER_shutdown ();
1052 return;
1053 }
1054 perf_ats = GNUNET_ATS_performance_init (cfg,
1055 &address_information_cb,
1056 "aic-closure");
1057 if (NULL == perf_ats)
1058 {
1059 GNUNET_break (0);
1060 GNUNET_SCHEDULER_shutdown ();
1061 return;
1062 }
1063 run_interpreter ();
1064}
1065
1066
1067/**
1068 * Run ATS test.
1069 *
1070 * @param argc length of @a argv
1071 * @param argv command line
1072 * @param cmds commands to run with the interpreter
1073 * @param timeout how long is the test allowed to take?
1074 * @return 0 on success
1075 */
1076int
1077TEST_ATS_run (int argc,
1078 char *argv[],
1079 struct Command *cmds,
1080 struct GNUNET_TIME_Relative timeout)
1081{
1082 char *test_filename = GNUNET_strdup (argv[0]);
1083 char *sep;
1084 char *config_file;
1085 char *underscore;
1086
1087 test_commands = cmds;
1088 TIMEOUT = timeout;
1089 if (NULL != (sep = strstr (test_filename, ".exe")))
1090 sep[0] = '\0';
1091 underscore = strrchr (test_filename, (int) '_');
1092 GNUNET_assert (NULL != underscore);
1093 GNUNET_asprintf (&config_file,
1094 "test_ats_api_%s.conf",
1095 underscore + 1);
1096 ret = 2;
1097 if (0 != GNUNET_TESTING_peer_run ("test-ats-api",
1098 config_file,
1099 &run, NULL))
1100 ret = 1;
1101 GNUNET_free (test_filename);
1102 GNUNET_free (config_file);
1103 return ret;
1104}
1105
1106
1107/* end of test_ats_lib.c */
diff --git a/src/ats/test_ats_lib.h b/src/ats/test_ats_lib.h
deleted file mode 100644
index 60b459f79..000000000
--- a/src/ats/test_ats_lib.h
+++ /dev/null
@@ -1,512 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010-2015 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file ats/test_ats_lib.h
22 * @brief test ATS library with a generic interpreter for running ATS tests
23 * @author Christian Grothoff
24 */
25#ifndef TEST_ATS_LIB_H
26#define TEST_ATS_LIB_H
27
28#include "gnunet_util_lib.h"
29#include "gnunet_ats_service.h"
30#include "gnunet_testing_lib.h"
31
32
33/**
34 * Commands for the interpreter.
35 */
36enum CommandCode
37{
38 /**
39 * End the test (passing).
40 */
41 CMD_END_PASS = 0,
42
43 /**
44 * Call #GNUNET_ATS_address_add().
45 */
46 CMD_ADD_ADDRESS,
47
48 /**
49 * Call #GNUNET_ATS_address_del().
50 */
51 CMD_DEL_ADDRESS,
52
53 /**
54 * Wait for ATS to suggest address.
55 */
56 CMD_AWAIT_ADDRESS_SUGGESTION,
57
58 /**
59 * Wait for ATS to suggest disconnect.
60 */
61 CMD_AWAIT_DISCONNECT_SUGGESTION,
62
63 /**
64 * Ask ATS to connect to a peer, using
65 * #GNUNET_ATS_connectivity_suggest().
66 */
67 CMD_REQUEST_CONNECTION_START,
68
69 /**
70 * Tell ATS we no longer need a connection to a peer, using
71 * #GNUNET_ATS_connectivity_suggest_cancel().
72 */
73 CMD_REQUEST_CONNECTION_STOP,
74
75 /**
76 * Wait for certain address information to be provided.
77 */
78 CMD_AWAIT_ADDRESS_INFORMATION,
79
80 /**
81 * Update properties of an address, using
82 * #GNUNET_ATS_address_update().
83 */
84 CMD_UPDATE_ADDRESS,
85
86 /**
87 * Add session to an address, using
88 * #GNUNET_ATS_address_add_session().
89 */
90 CMD_ADD_SESSION,
91
92 /**
93 * Remove session from an address, using
94 * #GNUNET_ATS_address_del_session().
95 */
96 CMD_DEL_SESSION,
97
98 /**
99 * Change performance preferences for a peer, testing
100 * #GNUNET_ATS_performance_change_preference().
101 */
102 CMD_CHANGE_PREFERENCE,
103
104 /**
105 * Provide allocation quality feedback, testing
106 * #GNUNET_ATS_performance_give_feedback().
107 */
108 CMD_PROVIDE_FEEDBACK,
109
110 /**
111 * Obtain list of all addresses, testing
112 * #GNUNET_ATS_performance_list_addresses().
113 */
114 CMD_LIST_ADDRESSES,
115
116 /**
117 * Reserve bandwidth, testing
118 * #GNUNET_ATS_reserve_bandwidth().
119 */
120 CMD_RESERVE_BANDWIDTH,
121
122 /**
123 * Wait for a bit.
124 */
125 CMD_SLEEP
126};
127
128
129/**
130 * Details for the #CMD_ADD_ADDRESS command.
131 */
132struct CommandAddAddress
133{
134 /**
135 * Number of the peer (used to generate PID).
136 */
137 unsigned int pid;
138
139 /**
140 * Number of the address (used to generate binary address).
141 */
142 unsigned int addr_num;
143
144 /**
145 * Session to supply, 0 for NULL.
146 */
147 unsigned int session;
148
149 /**
150 * Flags to set for the address.
151 */
152 enum GNUNET_HELLO_AddressInfo addr_flags;
153
154 /**
155 * Performance properties to supply.
156 */
157 struct GNUNET_ATS_Properties properties;
158
159 /**
160 * Expect the operation to fail (duplicate).
161 */
162 int expect_fail;
163
164 /**
165 * Here the result of the add address operation will be stored.
166 */
167 struct GNUNET_ATS_AddressRecord *ar;
168};
169
170
171/**
172 * Details for the #CMD_DEL_ADDRESS command.
173 */
174struct CommandDelAddress
175{
176 /**
177 * Label of the corresponding #CMD_ADD_ADDRESS that
178 * we are now to remove.
179 */
180 const char *add_label;
181};
182
183
184/**
185 * Details for the #CMD_AWAIT_ADDRESS_SUGGESTION command.
186 */
187struct CommandAwaitAddressSuggestion
188{
189 /**
190 * For which peer do we expect a suggestion?
191 */
192 unsigned int pid;
193
194 /**
195 * If we expect the address suggested to match a particular
196 * addition, specify the label of the add operation here. Otherwise
197 * use NULL for "any" available address.
198 */
199 const char *add_label;
200};
201
202
203/**
204 * Details for the #CMD_AWAIT_DISCONNECT_SUGGESTION command.
205 */
206struct CommandAwaitDisconnectSuggestion
207{
208 /**
209 * For which peer do we expect the disconnect?
210 */
211 unsigned int pid;
212};
213
214
215/**
216 * Details for the #CMD_REQUEST_CONNECTION_START command.
217 */
218struct CommandRequestConnectionStart
219{
220 /**
221 * Identity of the peer we would like to connect to.
222 */
223 unsigned int pid;
224
225 /**
226 * Location where we store the handle returned from
227 * #GNUNET_ATS_connectivity_suggest().
228 */
229 struct GNUNET_ATS_ConnectivitySuggestHandle *csh;
230};
231
232
233/**
234 * Details for the #CMD_REQUEST_CONNECTION_STOP command.
235 */
236struct CommandRequestConnectionStop
237{
238 /**
239 * Label of the corresponding #CMD_REQUEST_CONNECTION_START that
240 * we are now stopping.
241 */
242 const char *connect_label;
243};
244
245
246/**
247 * Details for the #CMD_AWAIT_ADDRESS_INFORMATION command.
248 */
249struct CommandAwaitAddressInformation
250{
251 /**
252 * For which address do we expect information?
253 * The address is identified by the respective
254 * label of the corresponding add operation.
255 */
256 const char *add_label;
257
258 /**
259 * Label of a possible update operation that may
260 * have modified the properties. NULL to use
261 * the properties from the @e add_label.
262 */
263 const char *update_label;
264};
265
266
267/**
268 * Details for the #CMD_UPDATE_ADDRESS command.
269 */
270struct CommandUpdateAddress
271{
272 /**
273 * Label of the addresses's add operation.
274 */
275 const char *add_label;
276
277 /**
278 * Performance properties to supply.
279 */
280 struct GNUNET_ATS_Properties properties;
281};
282
283
284/**
285 * Details for the #CMD_ADD_SESSION command.
286 */
287struct CommandAddSession
288{
289 /**
290 * Label of the addresses's add operation.
291 */
292 const char *add_label;
293
294 /**
295 * Session to supply.
296 */
297 unsigned int session;
298};
299
300
301/**
302 * Details for the #CMD_DEL_SESSION command.
303 */
304struct CommandDelSession
305{
306 /**
307 * Label of the addresses's add operation.
308 */
309 const char *add_session_label;
310};
311
312
313/**
314 * Details for the #CMD_CHANGE_PREFERENCE command.
315 */
316struct CommandChangePreference
317{
318 /**
319 * Identity of the peer we have a preference change towards.
320 */
321 unsigned int pid;
322
323 /* FIXME: preference details! */
324};
325
326
327/**
328 * Details for the #CMD_PROVIDE_FEEDBACK command.
329 */
330struct CommandProvideFeedback
331{
332 /**
333 * Identity of the peer we have a feedback for.
334 */
335 unsigned int pid;
336
337 /**
338 * Over which timeframe does the feedback apply?
339 */
340 struct GNUNET_TIME_Relative scope;
341
342 /* FIXME: feedback details! */
343};
344
345
346/**
347 * Details for the #CMD_LIST_ADDRESSES command.
348 */
349struct CommandListAddresses
350{
351 /**
352 * Identity of the peer we want a list for.
353 */
354 unsigned int pid;
355
356 /**
357 * All addresses or just active?
358 */
359 int all;
360
361 /**
362 * Minimum number of addresses the callback may report.
363 */
364 unsigned int min_calls;
365
366 /**
367 * Maximum number of addresses the callback may report.
368 */
369 unsigned int max_calls;
370
371 /**
372 * Minimum number of active addresses the callback may report.
373 */
374 unsigned int min_active_calls;
375
376 /**
377 * Maximum number of active addresses the callback may report.
378 */
379 unsigned int max_active_calls;
380
381 /**
382 * Number of calls the command invoked the callback with
383 * an address marked as active. (Set by command).
384 */
385 unsigned int active_calls;
386
387 /**
388 * Number of calls the command invoked the callback with
389 * any address marked as available to ATS. (Set by command).
390 */
391 unsigned int calls;
392
393 /**
394 * Location where we store the return value from
395 * #GNUNET_ATS_performance_list_addresses().
396 */
397 struct GNUNET_ATS_AddressListHandle *alh;
398};
399
400
401/**
402 * Details for the #CMD_RESERVE_BANDWIDTH command.
403 */
404struct CommandReserveBandwidth
405{
406 /**
407 * For which peer do we reserve bandwidth?
408 */
409 unsigned int pid;
410
411 /**
412 * How much should we try to reserve?
413 */
414 int32_t amount;
415
416 /**
417 * Should we expect this to work or fail?
418 * #GNUNET_YES: must work
419 * #GNUNET_NO: may work or fail
420 * #GNUNET_SYSERR: must fail
421 */
422 int expected_result;
423
424 /**
425 * Location where we store the return value from
426 * #GNUNET_ATS_reserve_bandwidth().
427 */
428 struct GNUNET_ATS_ReservationContext *rc;
429};
430
431
432/**
433 * Details for the #CMD_SLEEP command.
434 */
435struct CommandSleep
436{
437 /**
438 * How long should we wait before running the next command?
439 */
440 struct GNUNET_TIME_Relative delay;
441};
442
443
444/**
445 * A command for the test case interpreter.
446 */
447struct Command
448{
449 /**
450 * Command code to run.
451 */
452 enum CommandCode code;
453
454 /**
455 * Commands can be given a label so we can reference them later.
456 */
457 const char *label;
458
459 /**
460 * Additional arguments to commands, if any.
461 */
462 union
463 {
464 struct CommandAddAddress add_address;
465
466 struct CommandDelAddress del_address;
467
468 struct CommandAwaitAddressSuggestion await_address_suggestion;
469
470 struct CommandAwaitDisconnectSuggestion await_disconnect_suggestion;
471
472 struct CommandRequestConnectionStart request_connection_start;
473
474 struct CommandRequestConnectionStop request_connection_stop;
475
476 struct CommandAwaitAddressInformation await_address_information;
477
478 struct CommandUpdateAddress update_address;
479
480 struct CommandAddSession add_session;
481
482 struct CommandDelSession del_session;
483
484 struct CommandChangePreference change_preference;
485
486 struct CommandProvideFeedback provide_feedback;
487
488 struct CommandListAddresses list_addresses;
489
490 struct CommandReserveBandwidth reserve_bandwidth;
491
492 struct CommandSleep sleep;
493 } details;
494};
495
496
497/**
498 * Run ATS test.
499 *
500 * @param argc length of @a argv
501 * @param argv command line
502 * @param cmds commands to run with the interpreter
503 * @param timeout how long is the test allowed to take?
504 * @return 0 on success
505 */
506int
507TEST_ATS_run (int argc,
508 char *argv[],
509 struct Command *cmds,
510 struct GNUNET_TIME_Relative timeout);
511
512#endif
diff --git a/src/ats/test_ats_reservation_api.c b/src/ats/test_ats_reservation_api.c
deleted file mode 100644
index f6a964df4..000000000
--- a/src/ats/test_ats_reservation_api.c
+++ /dev/null
@@ -1,181 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010-2015 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file ats/test_ats_reservation_api.c
22 * @brief test ATS bandwidth reservation API
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "test_ats_lib.h"
27
28/**
29 * Global timeout for the testcase.
30 */
31#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
32
33/**
34 * Definition of the test as a sequence of commands.
35 */
36static struct Command test_commands[] = {
37 /* 0: add initial address */
38 {
39 .code = CMD_ADD_ADDRESS,
40 .label = "add-address-0-0",
41 .details.add_address = {
42 .pid = 0,
43 .addr_num = 0,
44 .session = 0,
45 .properties = {
46 /* use network with 65k quota! */
47 .scope = GNUNET_NT_WAN
48 }
49
50
51 }
52
53
54 },
55 /* 1: some solver still require explicit start */
56 {
57 .code = CMD_REQUEST_CONNECTION_START,
58 .label = "request-0",
59 .details.request_connection_start = {
60 .pid = 0
61 }
62
63
64 },
65 /* 2: check we got an address */
66 {
67 .code = CMD_AWAIT_ADDRESS_SUGGESTION,
68 .details.await_address_suggestion = {
69 .add_label = "add-address-0-0"
70 }
71
72
73 },
74 /* 3: sleep 7s, should give us 5s * 64k/s = 320k buffer;
75 Note that this depends on MAX_BANDWIDTH_CARRY_S. We
76 sleep more than 5s to show that only MAX_BANDWIDTH carries. */
77 {
78 .code = CMD_SLEEP,
79 .label = "sleep",
80 .details.sleep.delay = { 7 * 1000LL * 1000LL }
81 },
82 /* 4: reserve 128k -- should work (5s carry, so we had 320k) */
83 {
84 .code = CMD_RESERVE_BANDWIDTH,
85 .details.reserve_bandwidth = {
86 .pid = 0,
87 .amount = 128 * 1024,
88 .expected_result = GNUNET_YES
89 }
90
91
92 },
93 /* 5: reserve another 192k -- should just work (now exactly pushing the limit) */
94 {
95 .code = CMD_RESERVE_BANDWIDTH,
96 .label = "big reservation",
97 .details.reserve_bandwidth = {
98 .pid = 0,
99 .amount = 192 * 1024,
100 .expected_result = GNUNET_YES
101 }
102
103
104 },
105 /* 6: reserve another 32M -- should now fail (if MAX_BANDWIDTH_CARRY_S
106 is precisely observed) */
107 {
108 .code = CMD_RESERVE_BANDWIDTH,
109 .label = "failing reservation",
110 .details.reserve_bandwidth = {
111 .pid = 0,
112 .amount = 32 * 1024 * 1024,
113 .expected_result = GNUNET_SYSERR
114 }
115
116
117 },
118 /* 7: sleep 3s, should give us 3s * 64k/s - 32k = 160k buffer */
119 {
120 .code = CMD_SLEEP,
121 .label = "sleep",
122 .details.sleep.delay = { 6 * 1000LL * 1000LL }
123 },
124 /* 8: reserve another 160k -- should now work */
125 {
126 .code = CMD_RESERVE_BANDWIDTH,
127 .label = "successful final reservation",
128 .details.reserve_bandwidth = {
129 .pid = 0,
130 .amount = 160 * 1024,
131 .expected_result = GNUNET_YES
132 }
133
134
135 },
136 /* 9: remove address */
137 {
138 .code = CMD_DEL_ADDRESS,
139 .details.del_address = {
140 .add_label = "add-address-0-0"
141 }
142
143
144 },
145 /* 10: check we got disconnected */
146 {
147 .code = CMD_AWAIT_DISCONNECT_SUGGESTION,
148 .details.await_disconnect_suggestion = {
149 .pid = 0
150 }
151
152
153 },
154 /* 11: just for symmetry, also stop asking for the connection */
155 {
156 .code = CMD_REQUEST_CONNECTION_STOP,
157 .details.request_connection_stop = {
158 .connect_label = "request-0",
159 }
160
161
162 },
163 /* Test ends successfully */
164 {
165 .code = CMD_END_PASS
166 }
167};
168
169
170int
171main (int argc,
172 char *argv[])
173{
174 return TEST_ATS_run (argc,
175 argv,
176 test_commands,
177 TIMEOUT);
178}
179
180
181/* end of file test_ats_reservation_api.c */
diff --git a/src/ats/test_ats_solver_default.conf b/src/ats/test_ats_solver_default.conf
deleted file mode 100644
index 2d8927abd..000000000
--- a/src/ats/test_ats_solver_default.conf
+++ /dev/null
@@ -1,2 +0,0 @@
1@INLINE@ ../../contrib/conf/gnunet/no_forcestart.conf
2
diff --git a/src/ats/test_ats_solver_delayed_proportional.conf b/src/ats/test_ats_solver_delayed_proportional.conf
deleted file mode 100644
index fdfeb90b8..000000000
--- a/src/ats/test_ats_solver_delayed_proportional.conf
+++ /dev/null
@@ -1,20 +0,0 @@
1@INLINE@ test_ats_solver_default.conf
2
3[ats]
4PREFIX = ./test_delay -t 10 --
5MODE = proportional
6# UNSPECIFIED
7UNSPECIFIED_QUOTA_IN = 64 KiB
8UNSPECIFIED_QUOTA_OUT = 64 KiB
9# LOOPBACK
10LOOPBACK_QUOTA_IN = unlimited
11LOOPBACK_QUOTA_OUT = unlimited
12# LAN
13LAN_QUOTA_IN = unlimited
14LAN_QUOTA_OUT = unlimited
15# WAN
16WAN_QUOTA_IN = 64 KiB
17WAN_QUOTA_OUT = 64 KiB
18# WLAN
19WLAN_QUOTA_IN = 512
20WLAN_QUOTA_OUT = 512
diff --git a/src/ats/test_ats_solver_proportional.conf b/src/ats/test_ats_solver_proportional.conf
deleted file mode 100644
index 49815134b..000000000
--- a/src/ats/test_ats_solver_proportional.conf
+++ /dev/null
@@ -1,19 +0,0 @@
1@INLINE@ test_ats_solver_default.conf
2
3[ats]
4MODE = proportional
5# UNSPECIFIED
6UNSPECIFIED_QUOTA_IN = 64 KiB
7UNSPECIFIED_QUOTA_OUT = 64 KiB
8# LOOPBACK
9LOOPBACK_QUOTA_IN = unlimited
10LOOPBACK_QUOTA_OUT = unlimited
11# LAN
12LAN_QUOTA_IN = unlimited
13LAN_QUOTA_OUT = unlimited
14# WAN
15WAN_QUOTA_IN = 64 KiB
16WAN_QUOTA_OUT = 64 KiB
17# WLAN
18WLAN_QUOTA_IN = 512
19WLAN_QUOTA_OUT = 512
diff --git a/src/ats/test_delay b/src/ats/test_delay
deleted file mode 100755
index 31c7777c4..000000000
--- a/src/ats/test_delay
+++ /dev/null
@@ -1,18 +0,0 @@
1#!/bin/sh
2
3TEMP=$(getopt -o t: -- "$@")
4
5if [ $? != 0 ] ; then
6 exit 1
7fi
8
9eval set -- "$TEMP"
10
11while true ; do
12 case "$1" in
13 (-t) sleep "$2" ; shift 2 ;;
14 (--) shift ; break ;;
15 (*) echo "Error parsing getopt output" ; exit 1 ;;
16 esac
17done
18exec "$@"
diff --git a/src/cadet/Makefile.am b/src/cadet/Makefile.am
index dec43b516..9f59aba3c 100644
--- a/src/cadet/Makefile.am
+++ b/src/cadet/Makefile.am
@@ -18,15 +18,13 @@ plugindir = $(libdir)/gnunet
18AM_CLFAGS = -g 18AM_CLFAGS = -g
19 19
20libexec_PROGRAMS = \ 20libexec_PROGRAMS = \
21 gnunet-service-cadet \ 21 gnunet-service-cadet
22 $(EXP_LIBEXEC)
23 22
24bin_PROGRAMS = \ 23bin_PROGRAMS = \
25 gnunet-cadet 24 gnunet-cadet
26 25
27lib_LTLIBRARIES = \ 26lib_LTLIBRARIES = \
28 libgnunetcadet.la \ 27 libgnunetcadet.la
29 $(EXP_LIB)
30 28
31libgnunetcadet_la_SOURCES = \ 29libgnunetcadet_la_SOURCES = \
32 cadet_api.c \ 30 cadet_api.c \
@@ -64,7 +62,6 @@ gnunet_service_cadet_SOURCES = \
64 gnunet-service-cadet_peer.c gnunet-service-cadet_peer.h 62 gnunet-service-cadet_peer.c gnunet-service-cadet_peer.h
65gnunet_service_cadet_LDADD = \ 63gnunet_service_cadet_LDADD = \
66 $(top_builddir)/src/util/libgnunetutil.la \ 64 $(top_builddir)/src/util/libgnunetutil.la \
67 $(top_builddir)/src/ats/libgnunetats.la \
68 $(top_builddir)/src/core/libgnunetcore.la \ 65 $(top_builddir)/src/core/libgnunetcore.la \
69 $(top_builddir)/src/dht/libgnunetdht.la \ 66 $(top_builddir)/src/dht/libgnunetdht.la \
70 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 67 $(top_builddir)/src/statistics/libgnunetstatistics.la \
@@ -73,38 +70,11 @@ gnunet_service_cadet_LDADD = \
73 $(top_builddir)/src/hello/libgnunethello.la \ 70 $(top_builddir)/src/hello/libgnunethello.la \
74 $(top_builddir)/src/block/libgnunetblock.la 71 $(top_builddir)/src/block/libgnunetblock.la
75if LINUX 72if LINUX
76 gnunet_service_cadet_LDFLAGS = -lrt \ 73gnunet_service_cadet_LDFLAGS = -lrt \
77 $(GN_LIBINTL) 74 $(GN_LIBINTL)
78endif 75endif
79 76
80 77
81 noinst_LTLIBRARIES = libgnunetcadettest.la $(noinst_LIB_EXP)
82# noinst_PROGRAMS = gnunet-cadet-profiler
83
84check_PROGRAMS = \
85 # test_cadet_local_mq \
86 # test_cadet_2_forward \
87 # test_cadet_2_forward \
88 # test_cadet_2_signal \
89 # test_cadet_2_keepalive \
90 # test_cadet_2_speed \
91 # test_cadet_2_speed_ack \
92 # test_cadet_2_speed_backwards \
93 # test_cadet_2_speed_reliable \
94 # test_cadet_2_speed_reliable_backwards \
95 # test_cadet_2_reopen \
96 # test_cadet_2_destroy \
97 # test_cadet_5_forward \
98 # test_cadet_5_signal \
99 # test_cadet_5_keepalive \
100 # test_cadet_5_speed \
101 # test_cadet_5_speed_ack \
102 # test_cadet_5_speed_reliable \
103 # test_cadet_5_speed_reliable_backwards \
104 # test_cadet_5_speed_backwards \
105 # test_cadet_5_reopen
106
107
108#gnunet_cadet_profiler_SOURCES = \ 78#gnunet_cadet_profiler_SOURCES = \
109# gnunet-cadet-profiler.c 79# gnunet-cadet-profiler.c
110#gnunet_cadet_profiler_LDADD = $(ld_cadet_test_lib) 80#gnunet_cadet_profiler_LDADD = $(ld_cadet_test_lib)
@@ -117,106 +87,9 @@ test_cadet_local_mq_LDADD = \
117 $(top_builddir)/src/testing/libgnunettesting.la \ 87 $(top_builddir)/src/testing/libgnunettesting.la \
118 $(top_builddir)/src/util/libgnunetutil.la 88 $(top_builddir)/src/util/libgnunetutil.la
119 89
120
121libgnunetcadettest_la_SOURCES = \
122 cadet_test_lib.c cadet_test_lib.h
123libgnunetcadettest_la_LIBADD = \
124 $(top_builddir)/src/util/libgnunetutil.la \
125 $(top_builddir)/src/testbed/libgnunettestbed.la \
126 libgnunetcadet.la
127
128ld_cadet_test_lib = \
129 $(top_builddir)/src/util/libgnunetutil.la \
130 $(top_builddir)/src/testing/libgnunettesting.la \
131 libgnunetcadet.la \
132 libgnunetcadettest.la \
133 $(top_builddir)/src/testbed/libgnunettestbed.la \
134 $(top_builddir)/src/statistics/libgnunetstatistics.la
135dep_cadet_test_lib = \
136 libgnunetcadet.la \
137 libgnunetcadettest.la \
138 $(top_builddir)/src/statistics/libgnunetstatistics.la
139
140test_cadet_2_forward_SOURCES = \
141 test_cadet.c
142test_cadet_2_forward_LDADD = $(ld_cadet_test_lib)
143
144test_cadet_2_signal_SOURCES = \
145 test_cadet.c
146test_cadet_2_signal_LDADD = $(ld_cadet_test_lib)
147
148test_cadet_2_keepalive_SOURCES = \
149 test_cadet.c
150test_cadet_2_keepalive_LDADD = $(ld_cadet_test_lib)
151
152test_cadet_2_speed_SOURCES = \
153 test_cadet.c
154test_cadet_2_speed_LDADD = $(ld_cadet_test_lib)
155
156test_cadet_2_speed_ack_SOURCES = \
157 test_cadet.c
158test_cadet_2_speed_ack_LDADD = $(ld_cadet_test_lib)
159
160test_cadet_2_speed_backwards_SOURCES = \
161 test_cadet.c
162test_cadet_2_speed_backwards_LDADD = $(ld_cadet_test_lib)
163
164test_cadet_2_speed_reliable_SOURCES = \
165 test_cadet.c
166test_cadet_2_speed_reliable_LDADD = $(ld_cadet_test_lib)
167
168test_cadet_2_speed_reliable_backwards_SOURCES = \
169 test_cadet.c
170test_cadet_2_speed_reliable_backwards_LDADD = $(ld_cadet_test_lib)
171
172test_cadet_5_forward_SOURCES = \
173 test_cadet.c
174test_cadet_5_forward_LDADD = $(ld_cadet_test_lib)
175
176test_cadet_5_signal_SOURCES = \
177 test_cadet.c
178test_cadet_5_signal_LDADD = $(ld_cadet_test_lib)
179
180test_cadet_5_keepalive_SOURCES = \
181 test_cadet.c
182test_cadet_5_keepalive_LDADD = $(ld_cadet_test_lib)
183
184test_cadet_5_speed_SOURCES = \
185 test_cadet.c
186test_cadet_5_speed_LDADD = $(ld_cadet_test_lib)
187
188test_cadet_5_speed_ack_SOURCES = \
189 test_cadet.c
190test_cadet_5_speed_ack_LDADD = $(ld_cadet_test_lib)
191
192test_cadet_5_speed_backwards_SOURCES = \
193 test_cadet.c
194test_cadet_5_speed_backwards_LDADD = $(ld_cadet_test_lib)
195
196test_cadet_5_speed_reliable_SOURCES = \
197 test_cadet.c
198test_cadet_5_speed_reliable_LDADD = $(ld_cadet_test_lib)
199
200test_cadet_5_speed_reliable_backwards_SOURCES = \
201 test_cadet.c
202test_cadet_5_speed_reliable_backwards_LDADD = $(ld_cadet_test_lib)
203
204test_cadet_2_reopen_SOURCES = \
205 test_cadet.c
206test_cadet_2_reopen_LDADD = $(ld_cadet_test_lib)
207
208test_cadet_5_reopen_SOURCES = \
209 test_cadet.c
210test_cadet_5_reopen_LDADD = $(ld_cadet_test_lib)
211
212test_cadet_2_destroy_SOURCES = \
213 test_cadet.c
214test_cadet_2_destroy_LDADD = $(ld_cadet_test_lib)
215
216if ENABLE_TEST_RUN 90if ENABLE_TEST_RUN
217AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME; 91AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
218TESTS = \ 92TESTS = $(check_PROGRAMS)
219 $(check_PROGRAMS)
220endif 93endif
221 94
222EXTRA_DIST = \ 95EXTRA_DIST = \
diff --git a/src/consensus/Makefile.am b/src/consensus/Makefile.am
index 27743c45e..f77f49f94 100644
--- a/src/consensus/Makefile.am
+++ b/src/consensus/Makefile.am
@@ -18,8 +18,8 @@ endif
18libexec_PROGRAMS = \ 18libexec_PROGRAMS = \
19 gnunet-service-consensus 19 gnunet-service-consensus
20 20
21noinst_PROGRAMS = \ 21#noinst_PROGRAMS = \
22 gnunet-consensus-profiler 22# gnunet-consensus-profiler
23 23
24if ENABLE_MALICIOUS 24if ENABLE_MALICIOUS
25libexec_PROGRAMS += \ 25libexec_PROGRAMS += \
@@ -38,14 +38,15 @@ check-python-style:
38lib_LTLIBRARIES = \ 38lib_LTLIBRARIES = \
39 libgnunetconsensus.la 39 libgnunetconsensus.la
40 40
41gnunet_consensus_profiler_SOURCES = \ 41# TNG
42 gnunet-consensus-profiler.c 42#gnunet_consensus_profiler_SOURCES = \
43gnunet_consensus_profiler_LDADD = \ 43# gnunet-consensus-profiler.c
44 $(top_builddir)/src/util/libgnunetutil.la \ 44#gnunet_consensus_profiler_LDADD = \
45 libgnunetconsensus.la \ 45# $(top_builddir)/src/util/libgnunetutil.la \
46 $(top_builddir)/src/testing/libgnunettesting.la \ 46# libgnunetconsensus.la \
47 $(top_builddir)/src/testbed/libgnunettestbed.la \ 47# $(top_builddir)/src/testing/libgnunettesting.la \
48 $(GN_LIBINTL) 48# $(top_builddir)/src/testbed/libgnunettestbed.la \
49# $(GN_LIBINTL)
49 50
50gnunet_service_consensus_SOURCES = \ 51gnunet_service_consensus_SOURCES = \
51 gnunet-service-consensus.c 52 gnunet-service-consensus.c
diff --git a/src/core/Makefile.am b/src/core/Makefile.am
index 1343fe395..062aa0266 100644
--- a/src/core/Makefile.am
+++ b/src/core/Makefile.am
@@ -45,7 +45,6 @@ libgnunet_test_core_plugin_cmd_just_run_la_LIBADD = \
45 $(top_builddir)/src/core/libgnunetcoretesting.la \ 45 $(top_builddir)/src/core/libgnunetcoretesting.la \
46 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 46 $(top_builddir)/src/statistics/libgnunetstatistics.la \
47 $(top_builddir)/src/hello/libgnunethello.la \ 47 $(top_builddir)/src/hello/libgnunethello.la \
48 $(top_builddir)/src/ats/libgnunetats.la \
49 $(top_builddir)/src/arm/libgnunetarm.la \ 48 $(top_builddir)/src/arm/libgnunetarm.la \
50 $(top_builddir)/src/util/libgnunetutil.la \ 49 $(top_builddir)/src/util/libgnunetutil.la \
51 $(LTLIBINTL) 50 $(LTLIBINTL)
diff --git a/src/dht/Makefile.am b/src/dht/Makefile.am
index 124f95a77..c0ff34449 100644
--- a/src/dht/Makefile.am
+++ b/src/dht/Makefile.am
@@ -53,8 +53,8 @@ bin_PROGRAMS = \
53 gnunet-dht-put \ 53 gnunet-dht-put \
54 gnunet-dht-hello 54 gnunet-dht-hello
55 55
56noinst_PROGRAMS = \ 56#noinst_PROGRAMS = \
57 gnunet-dht-profiler 57# gnunet-dht-profiler
58 58
59gnunet_service_dht_SOURCES = \ 59gnunet_service_dht_SOURCES = \
60 gnunet-service-dht.c gnunet-service-dht.h \ 60 gnunet-service-dht.c gnunet-service-dht.h \
@@ -66,9 +66,7 @@ gnunet_service_dht_LDADD = \
66 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 66 $(top_builddir)/src/statistics/libgnunetstatistics.la \
67 $(top_builddir)/src/core/libgnunetcore.la \ 67 $(top_builddir)/src/core/libgnunetcore.la \
68 $(top_builddir)/src/nse/libgnunetnse.la \ 68 $(top_builddir)/src/nse/libgnunetnse.la \
69 $(top_builddir)/src/ats/libgnunetats.la \ 69 $(top_builddir)/src/peerstore/libgnunetpeerstore.la \
70 $(top_builddir)/src/transport/libgnunettransport.la \
71 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
72 $(top_builddir)/src/hello/libgnunethello.la \ 70 $(top_builddir)/src/hello/libgnunethello.la \
73 $(top_builddir)/src/block/libgnunetblock.la \ 71 $(top_builddir)/src/block/libgnunetblock.la \
74 $(top_builddir)/src/block/libgnunetblockgroup.la \ 72 $(top_builddir)/src/block/libgnunetblockgroup.la \
@@ -110,25 +108,26 @@ gnunet_dht_monitor_LDADD = \
110gnunet_dht_monitor_LDFLAGS = \ 108gnunet_dht_monitor_LDFLAGS = \
111 $(GN_LIBINTL) 109 $(GN_LIBINTL)
112 110
113gnunet_dht_profiler_SOURCES = \ 111# TNG
114 gnunet_dht_profiler.c 112#gnunet_dht_profiler_SOURCES = \
115gnunet_dht_profiler_LDADD = \ 113# gnunet_dht_profiler.c
116 libgnunetdht.la \ 114#gnunet_dht_profiler_LDADD = \
117 $(top_builddir)/src/core/libgnunetcore.la \ 115# libgnunetdht.la \
118 $(top_builddir)/src/util/libgnunetutil.la \ 116# $(top_builddir)/src/core/libgnunetcore.la \
119 $(top_builddir)/src/testing/libgnunettesting.la \ 117# $(top_builddir)/src/util/libgnunetutil.la \
120 $(top_builddir)/src/testbed/libgnunettestbed.la 118# $(top_builddir)/src/testing/libgnunettesting.la \
121gnunet_dht_profiler_LDFLAGS = \ 119# $(top_builddir)/src/testbed/libgnunettestbed.la
122 $(GN_LIBINTL) 120#gnunet_dht_profiler_LDFLAGS = \
123 121# $(GN_LIBINTL)
124noinst_LIBRARIES = libgnunetdhttest.a 122
125 123#noinst_LIBRARIES = libgnunetdhttest.a
126libgnunetdhttest_a_SOURCES = \ 124#
127 dht_test_lib.c dht_test_lib.h 125#libgnunetdhttest_a_SOURCES = \
128libgnunetdhttest_a_LIBADD = \ 126# dht_test_lib.c dht_test_lib.h
129 $(top_builddir)/src/util/libgnunetutil.la \ 127#libgnunetdhttest_a_LIBADD = \
130 $(top_builddir)/src/testbed/libgnunettestbed.la \ 128# $(top_builddir)/src/util/libgnunetutil.la \
131 libgnunetdht.la 129# $(top_builddir)/src/testbed/libgnunettestbed.la \
130# libgnunetdht.la
132 131
133check_PROGRAMS = \ 132check_PROGRAMS = \
134 test_dht_api \ 133 test_dht_api \
@@ -161,69 +160,7 @@ test_dht_api_LDADD = \
161 $(top_builddir)/src/hello/libgnunethello.la \ 160 $(top_builddir)/src/hello/libgnunethello.la \
162 libgnunetdht.la 161 libgnunetdht.la
163 162
164test_dht_twopeer_SOURCES = \
165 test_dht_topo.c
166test_dht_twopeer_LDADD = \
167 libgnunetdhttest.a \
168 $(top_builddir)/src/util/libgnunetutil.la \
169 libgnunetdhttest.a \
170 $(top_builddir)/src/testbed/libgnunettestbed.la \
171 libgnunetdht.la
172
173test_dht_2dtorus_SOURCES = \
174 test_dht_topo.c
175test_dht_2dtorus_LDADD = \
176 libgnunetdhttest.a \
177 $(top_builddir)/src/util/libgnunetutil.la \
178 $(top_builddir)/src/testbed/libgnunettestbed.la \
179 libgnunetdht.la
180
181test_dht_line_SOURCES = \
182 test_dht_topo.c
183test_dht_line_LDADD = \
184 libgnunetdhttest.a \
185 $(top_builddir)/src/util/libgnunetutil.la \
186 $(top_builddir)/src/testbed/libgnunettestbed.la \
187 libgnunetdht.la
188
189test_dht_multipeer_SOURCES = \
190 test_dht_topo.c
191test_dht_multipeer_LDADD = \
192 libgnunetdhttest.a \
193 $(top_builddir)/src/util/libgnunetutil.la \
194 $(top_builddir)/src/statistics/libgnunetstatistics.la \
195 $(top_builddir)/src/testbed/libgnunettestbed.la \
196 libgnunetdht.la
197
198test_dht_monitor_SOURCES = \
199 test_dht_monitor.c
200test_dht_monitor_LDADD = \
201 libgnunetdhttest.a \
202 $(top_builddir)/src/util/libgnunetutil.la \
203 $(top_builddir)/src/testbed/libgnunettestbed.la \
204 libgnunetdht.la
205
206EXTRA_DIST = \ 163EXTRA_DIST = \
207 gnunet-service-dht_clients.c \
208 test_dht_api_data.conf \
209 test_dht_api_peer1.conf \
210 test_dht_monitor.conf \
211 test_dht_multipeer.conf \
212 test_dht_2dtorus.conf \
213 test_dht_line.conf \
214 test_dht_tools.conf \
215 test_dht_tools.py.in \
216 test_dht_multipeer_topology.dat \
217 dhtu_testbed_connect.sh \ 164 dhtu_testbed_connect.sh \
218 dhtu_testbed_deploy.conf \ 165 dhtu_testbed_deploy.conf \
219 dhtu_testbed_deploy.sh 166 dhtu_testbed_deploy.sh
220
221if HAVE_PYTHON
222check_SCRIPTS = \
223 test_dht_tools.py
224endif
225
226SUFFIXES = .py.in .py
227.py.in.py:
228 $(AWK) -v bdir="$(bindir)" -v py="$(PYTHON)" -v awkay="$(AWK_BINARY)" -v pfx="$(prefix)" -v prl="$(PERL)" -v sysconfdirectory="$(sysconfdir)" -v pkgdatadirectory="$(pkgdatadir)" -f $(top_srcdir)/bin/dosubst.awk < $(srcdir)/$< > $@
229 chmod +x $@
diff --git a/src/dhtu/Makefile.am b/src/dhtu/Makefile.am
index 2b0712dcf..732b37ff7 100644
--- a/src/dhtu/Makefile.am
+++ b/src/dhtu/Makefile.am
@@ -33,7 +33,6 @@ endif
33libgnunet_plugin_dhtu_gnunet_la_SOURCES = \ 33libgnunet_plugin_dhtu_gnunet_la_SOURCES = \
34 plugin_dhtu_gnunet.c 34 plugin_dhtu_gnunet.c
35libgnunet_plugin_dhtu_gnunet_la_LIBADD = \ 35libgnunet_plugin_dhtu_gnunet_la_LIBADD = \
36 $(top_builddir)/src/ats/libgnunetats.la \
37 $(top_builddir)/src/core/libgnunetcore.la \ 36 $(top_builddir)/src/core/libgnunetcore.la \
38 $(top_builddir)/src/peerstore/libgnunetpeerstore.la \ 37 $(top_builddir)/src/peerstore/libgnunetpeerstore.la \
39 $(top_builddir)/src/transport/libgnunettransportapplication.la \ 38 $(top_builddir)/src/transport/libgnunettransportapplication.la \
diff --git a/src/dhtu/plugin_dhtu_gnunet.c b/src/dhtu/plugin_dhtu_gnunet.c
index aca641d4e..2c1be6e36 100644
--- a/src/dhtu/plugin_dhtu_gnunet.c
+++ b/src/dhtu/plugin_dhtu_gnunet.c
@@ -176,7 +176,7 @@ struct Plugin
176}; 176};
177 177
178 178
179#include "../peerinfo-tool/gnunet-peerinfo_plugins.c" 179//#include "../peerinfo-tool/gnunet-peerinfo_plugins.c"
180 180
181 181
182/** 182/**
@@ -196,7 +196,7 @@ gnunet_try_connect (void *cls,
196 char *addr; 196 char *addr;
197 const char *eou; 197 const char *eou;
198 int pfx_len; 198 int pfx_len;
199 199
200 eou = strstr (address, 200 eou = strstr (address,
201 "://"); 201 "://");
202 if (NULL == eou) 202 if (NULL == eou)
@@ -545,7 +545,7 @@ libgnunet_plugin_dhtu_gnunet_done (void *cls)
545 GNUNET_PEERSTORE_hello_changed_notify_cancel (plugin->peerstore_notify); 545 GNUNET_PEERSTORE_hello_changed_notify_cancel (plugin->peerstore_notify);
546 if (NULL != plugin->peerstore) 546 if (NULL != plugin->peerstore)
547 GNUNET_PEERSTORE_disconnect (plugin->peerstore, GNUNET_YES); 547 GNUNET_PEERSTORE_disconnect (plugin->peerstore, GNUNET_YES);
548 GPI_plugins_unload (); 548 //GPI_plugins_unload ();
549 GNUNET_free (plugin->my_priv); 549 GNUNET_free (plugin->my_priv);
550 GNUNET_free (plugin); 550 GNUNET_free (plugin);
551 GNUNET_free (api); 551 GNUNET_free (api);
@@ -602,6 +602,6 @@ libgnunet_plugin_dhtu_gnunet_init (void *cls)
602 libgnunet_plugin_dhtu_gnunet_done (plugin); 602 libgnunet_plugin_dhtu_gnunet_done (plugin);
603 return NULL; 603 return NULL;
604 } 604 }
605 GPI_plugins_load (env->cfg); 605 //GPI_plugins_load (env->cfg);
606 return api; 606 return api;
607} 607}
diff --git a/src/fs/Makefile.am b/src/fs/Makefile.am
index 0dd00fec0..046105589 100644
--- a/src/fs/Makefile.am
+++ b/src/fs/Makefile.am
@@ -21,7 +21,7 @@ lib_LTLIBRARIES = libgnunetfs.la
21plugin_LTLIBRARIES = \ 21plugin_LTLIBRARIES = \
22 libgnunet_plugin_block_fs.la 22 libgnunet_plugin_block_fs.la
23 23
24noinst_LIBRARIES = libgnunetfstest.a 24# noinst_LIBRARIES = libgnunetfstest.a
25 25
26libgnunetfs_la_SOURCES = \ 26libgnunetfs_la_SOURCES = \
27 fs_api.c fs_api.h fs.h \ 27 fs_api.c fs_api.h fs.h \
@@ -59,19 +59,18 @@ libgnunetfs_la_LDFLAGS = \
59 -version-info 3:1:1 59 -version-info 3:1:1
60 60
61 61
62libgnunetfstest_a_SOURCES = \ 62#libgnunetfstest_a_SOURCES = \
63 fs_test_lib.c fs_test_lib.h 63# fs_test_lib.c fs_test_lib.h
64 64#
65libgnunetfstest_a_LIBADD = \ 65#libgnunetfstest_a_LIBADD = \
66 $(top_builddir)/src/testing/libgnunettesting.la \ 66# $(top_builddir)/src/testing/libgnunettesting.la \
67 $(top_builddir)/src/testbed/libgnunettestbed.la 67# $(top_builddir)/src/testbed/libgnunettestbed.la
68 68
69libexec_PROGRAMS = \ 69libexec_PROGRAMS = \
70 gnunet-helper-fs-publish \ 70 gnunet-helper-fs-publish \
71 gnunet-service-fs 71 gnunet-service-fs
72 72
73noinst_PROGRAMS = \ 73noinst_PROGRAMS = \
74 gnunet-fs-profiler \
75 gnunet-daemon-fsprofiler 74 gnunet-daemon-fsprofiler
76 75
77bin_PROGRAMS = \ 76bin_PROGRAMS = \
@@ -95,13 +94,14 @@ gnunet_directory_LDADD += \
95 -lextractor 94 -lextractor
96endif 95endif
97 96
98gnunet_fs_profiler_SOURCES = \ 97# TNG
99 gnunet-fs-profiler.c 98#gnunet_fs_profiler_SOURCES = \
100gnunet_fs_profiler_LDADD = \ 99# gnunet-fs-profiler.c
101 $(top_builddir)/src/testing/libgnunettesting.la \ 100#gnunet_fs_profiler_LDADD = \
102 $(top_builddir)/src/testbed/libgnunettestbed.la \ 101# $(top_builddir)/src/testing/libgnunettesting.la \
103 $(top_builddir)/src/util/libgnunetutil.la \ 102# $(top_builddir)/src/testbed/libgnunettestbed.la \
104 $(GN_LIBINTL) 103# $(top_builddir)/src/util/libgnunetutil.la \
104# $(GN_LIBINTL)
105 105
106gnunet_fs_SOURCES = \ 106gnunet_fs_SOURCES = \
107 gnunet-fs.c 107 gnunet-fs.c
@@ -196,7 +196,6 @@ gnunet_service_fs_LDADD = \
196 $(top_builddir)/src/datastore/libgnunetdatastore.la \ 196 $(top_builddir)/src/datastore/libgnunetdatastore.la \
197 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 197 $(top_builddir)/src/statistics/libgnunetstatistics.la \
198 $(top_builddir)/src/cadet/libgnunetcadet.la \ 198 $(top_builddir)/src/cadet/libgnunetcadet.la \
199 $(top_builddir)/src/ats/libgnunetats.la \
200 $(top_builddir)/src/core/libgnunetcore.la \ 199 $(top_builddir)/src/core/libgnunetcore.la \
201 $(top_builddir)/src/util/libgnunetutil.la \ 200 $(top_builddir)/src/util/libgnunetutil.la \
202 $(top_builddir)/src/peerstore/libgnunetpeerstore.la \ 201 $(top_builddir)/src/peerstore/libgnunetpeerstore.la \
@@ -462,73 +461,74 @@ test_fs_uri_LDADD = \
462 libgnunetfs.la \ 461 libgnunetfs.la \
463 $(top_builddir)/src/util/libgnunetutil.la 462 $(top_builddir)/src/util/libgnunetutil.la
464 463
465test_fs_test_lib_SOURCES = \ 464# TNG
466 test_fs_test_lib.c 465#test_fs_test_lib_SOURCES = \
467test_fs_test_lib_LDADD = \ 466# test_fs_test_lib.c
468 libgnunetfstest.a \ 467#test_fs_test_lib_LDADD = \
469 $(top_builddir)/src/testbed/libgnunettestbed.la \ 468# libgnunetfstest.a \
470 libgnunetfs.la \ 469# $(top_builddir)/src/testbed/libgnunettestbed.la \
471 $(top_builddir)/src/util/libgnunetutil.la 470# libgnunetfs.la \
472 471# $(top_builddir)/src/util/libgnunetutil.la
473test_gnunet_service_fs_p2p_SOURCES = \ 472
474 test_gnunet_service_fs_p2p.c 473#test_gnunet_service_fs_p2p_SOURCES = \
475test_gnunet_service_fs_p2p_LDADD = \ 474# test_gnunet_service_fs_p2p.c
476 libgnunetfstest.a \ 475#test_gnunet_service_fs_p2p_LDADD = \
477 $(top_builddir)/src/testbed/libgnunettestbed.la \ 476# libgnunetfstest.a \
478 libgnunetfs.la \ 477# $(top_builddir)/src/testbed/libgnunettestbed.la \
479 $(top_builddir)/src/util/libgnunetutil.la 478# libgnunetfs.la \
480 479# $(top_builddir)/src/util/libgnunetutil.la
481test_gnunet_service_fs_p2p_cadet_SOURCES = \ 480#
482 test_gnunet_service_fs_p2p.c 481#test_gnunet_service_fs_p2p_cadet_SOURCES = \
483test_gnunet_service_fs_p2p_cadet_LDADD = \ 482# test_gnunet_service_fs_p2p.c
484 libgnunetfstest.a \ 483#test_gnunet_service_fs_p2p_cadet_LDADD = \
485 $(top_builddir)/src/testbed/libgnunettestbed.la \ 484# libgnunetfstest.a \
486 libgnunetfs.la \ 485# $(top_builddir)/src/testbed/libgnunettestbed.la \
487 $(top_builddir)/src/util/libgnunetutil.la 486# libgnunetfs.la \
488 487# $(top_builddir)/src/util/libgnunetutil.la
489test_gnunet_service_fs_migration_SOURCES = \ 488#
490 test_gnunet_service_fs_migration.c 489#test_gnunet_service_fs_migration_SOURCES = \
491test_gnunet_service_fs_migration_LDADD = \ 490# test_gnunet_service_fs_migration.c
492 libgnunetfstest.a \ 491#test_gnunet_service_fs_migration_LDADD = \
493 $(top_builddir)/src/testbed/libgnunettestbed.la \ 492# libgnunetfstest.a \
494 libgnunetfs.la \ 493# $(top_builddir)/src/testbed/libgnunettestbed.la \
495 $(top_builddir)/src/util/libgnunetutil.la 494# libgnunetfs.la \
496 495# $(top_builddir)/src/util/libgnunetutil.la
497perf_gnunet_service_fs_p2p_SOURCES = \ 496#
498 perf_gnunet_service_fs_p2p.c 497#perf_gnunet_service_fs_p2p_SOURCES = \
499perf_gnunet_service_fs_p2p_LDADD = \ 498# perf_gnunet_service_fs_p2p.c
500 libgnunetfstest.a \ 499#perf_gnunet_service_fs_p2p_LDADD = \
501 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 500# libgnunetfstest.a \
502 $(top_builddir)/src/testbed/libgnunettestbed.la \ 501# $(top_builddir)/src/statistics/libgnunetstatistics.la \
503 libgnunetfs.la \ 502# $(top_builddir)/src/testbed/libgnunettestbed.la \
504 $(top_builddir)/src/util/libgnunetutil.la 503# libgnunetfs.la \
505 504# $(top_builddir)/src/util/libgnunetutil.la
506perf_gnunet_service_fs_p2p_index_SOURCES = \ 505#
507 perf_gnunet_service_fs_p2p.c 506#perf_gnunet_service_fs_p2p_index_SOURCES = \
508perf_gnunet_service_fs_p2p_index_LDADD = \ 507# perf_gnunet_service_fs_p2p.c
509 libgnunetfstest.a \ 508#perf_gnunet_service_fs_p2p_index_LDADD = \
510 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 509# libgnunetfstest.a \
511 $(top_builddir)/src/testbed/libgnunettestbed.la \ 510# $(top_builddir)/src/statistics/libgnunetstatistics.la \
512 libgnunetfs.la \ 511# $(top_builddir)/src/testbed/libgnunettestbed.la \
513 $(top_builddir)/src/util/libgnunetutil.la 512# libgnunetfs.la \
514 513# $(top_builddir)/src/util/libgnunetutil.la
515perf_gnunet_service_fs_p2p_dht_SOURCES = \ 514#
516 perf_gnunet_service_fs_p2p.c 515#perf_gnunet_service_fs_p2p_dht_SOURCES = \
517perf_gnunet_service_fs_p2p_dht_LDADD = \ 516# perf_gnunet_service_fs_p2p.c
518 libgnunetfstest.a \ 517#perf_gnunet_service_fs_p2p_dht_LDADD = \
519 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 518# libgnunetfstest.a \
520 $(top_builddir)/src/testbed/libgnunettestbed.la \ 519# $(top_builddir)/src/statistics/libgnunetstatistics.la \
521 libgnunetfs.la \ 520# $(top_builddir)/src/testbed/libgnunettestbed.la \
522 $(top_builddir)/src/util/libgnunetutil.la 521# libgnunetfs.la \
523 522# $(top_builddir)/src/util/libgnunetutil.la
524perf_gnunet_service_fs_p2p_respect_SOURCES = \ 523#
525 perf_gnunet_service_fs_p2p_respect.c 524#perf_gnunet_service_fs_p2p_respect_SOURCES = \
526perf_gnunet_service_fs_p2p_respect_LDADD = \ 525# perf_gnunet_service_fs_p2p_respect.c
527 libgnunetfstest.a \ 526#perf_gnunet_service_fs_p2p_respect_LDADD = \
528 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 527# libgnunetfstest.a \
529 $(top_builddir)/src/testbed/libgnunettestbed.la \ 528# $(top_builddir)/src/statistics/libgnunetstatistics.la \
530 libgnunetfs.la \ 529# $(top_builddir)/src/testbed/libgnunettestbed.la \
531 $(top_builddir)/src/util/libgnunetutil.la 530# libgnunetfs.la \
531# $(top_builddir)/src/util/libgnunetutil.la
532 532
533test_gnunet_fs_psd.py: test_gnunet_fs_psd.py.in Makefile 533test_gnunet_fs_psd.py: test_gnunet_fs_psd.py.in Makefile
534 $(AWK) -v bdir="$(bindir)" -v py="$(PYTHON)" -v awkay="$(AWK_BINARY)" -v pfx="$(prefix)" -v prl="$(PERL)" -v sysconfdirectory="$(sysconfdir)" -v pkgdatadirectory="$(pkgdatadir)" -f $(top_srcdir)/bin/dosubst.awk < $(srcdir)/test_gnunet_fs_psd.py.in > test_gnunet_fs_psd.py 534 $(AWK) -v bdir="$(bindir)" -v py="$(PYTHON)" -v awkay="$(AWK_BINARY)" -v pfx="$(prefix)" -v prl="$(PERL)" -v sysconfdirectory="$(sysconfdir)" -v pkgdatadirectory="$(pkgdatadir)" -f $(top_srcdir)/bin/dosubst.awk < $(srcdir)/test_gnunet_fs_psd.py.in > test_gnunet_fs_psd.py
diff --git a/src/hostlist/Makefile.am b/src/hostlist/Makefile.am
index c58147dce..31f2c258d 100644
--- a/src/hostlist/Makefile.am
+++ b/src/hostlist/Makefile.am
@@ -30,7 +30,6 @@ gnunet_daemon_hostlist_LDADD = \
30 $(top_builddir)/src/hello/libgnunethello.la \ 30 $(top_builddir)/src/hello/libgnunethello.la \
31 $(top_builddir)/src/peerstore/libgnunetpeerstore.la \ 31 $(top_builddir)/src/peerstore/libgnunetpeerstore.la \
32 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 32 $(top_builddir)/src/statistics/libgnunetstatistics.la \
33 $(top_builddir)/src/transport/libgnunettransport.la \
34 $(top_builddir)/src/util/libgnunetutil.la \ 33 $(top_builddir)/src/util/libgnunetutil.la \
35 $(GN_LIBMHD) \ 34 $(GN_LIBMHD) \
36 @LIBCURL@ \ 35 @LIBCURL@ \
@@ -52,25 +51,25 @@ TESTS = \
52 $(check_PROGRAMS) 51 $(check_PROGRAMS)
53endif 52endif
54 53
55test_gnunet_daemon_hostlist_SOURCES = \ 54#test_gnunet_daemon_hostlist_SOURCES = \
56 test_gnunet_daemon_hostlist.c 55# test_gnunet_daemon_hostlist.c
57test_gnunet_daemon_hostlist_LDADD = \ 56#test_gnunet_daemon_hostlist_LDADD = \
58 $(top_builddir)/src/transport/libgnunettransport.la \ 57# $(top_builddir)/src/transport/libgnunettransport.la \
59 $(top_builddir)/src/util/libgnunetutil.la 58# $(top_builddir)/src/util/libgnunetutil.la
60 59#
61test_gnunet_daemon_hostlist_reconnect_SOURCES = \ 60#test_gnunet_daemon_hostlist_reconnect_SOURCES = \
62 test_gnunet_daemon_hostlist_reconnect.c 61# test_gnunet_daemon_hostlist_reconnect.c
63test_gnunet_daemon_hostlist_reconnect_LDADD = \ 62#test_gnunet_daemon_hostlist_reconnect_LDADD = \
64 $(top_builddir)/src/transport/libgnunettransport.la \ 63# $(top_builddir)/src/transport/libgnunettransport.la \
65 $(top_builddir)/src/util/libgnunetutil.la 64# $(top_builddir)/src/util/libgnunetutil.la
66 65#
67test_gnunet_daemon_hostlist_learning_SOURCES = \ 66#test_gnunet_daemon_hostlist_learning_SOURCES = \
68 test_gnunet_daemon_hostlist_learning.c 67# test_gnunet_daemon_hostlist_learning.c
69test_gnunet_daemon_hostlist_learning_LDADD = \ 68#test_gnunet_daemon_hostlist_learning_LDADD = \
70 $(top_builddir)/src/transport/libgnunettransport.la \ 69# $(top_builddir)/src/transport/libgnunettransport.la \
71 $(top_builddir)/src/core/libgnunetcore.la \ 70# $(top_builddir)/src/core/libgnunetcore.la \
72 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 71# $(top_builddir)/src/statistics/libgnunetstatistics.la \
73 $(top_builddir)/src/util/libgnunetutil.la 72# $(top_builddir)/src/util/libgnunetutil.la
74 73
75EXTRA_DIST = \ 74EXTRA_DIST = \
76 test_hostlist_defaults.conf \ 75 test_hostlist_defaults.conf \
diff --git a/src/nse/Makefile.am b/src/nse/Makefile.am
index 0c6182e61..460e68e02 100644
--- a/src/nse/Makefile.am
+++ b/src/nse/Makefile.am
@@ -36,18 +36,19 @@ libgnunetnse_la_LDFLAGS = \
36libexec_PROGRAMS = \ 36libexec_PROGRAMS = \
37 gnunet-service-nse 37 gnunet-service-nse
38 38
39noinst_PROGRAMS = \ 39#noinst_PROGRAMS = \
40 gnunet-nse-profiler 40# gnunet-nse-profiler
41 41
42gnunet_nse_profiler_SOURCES = \ 42# FIXME no testbed in TNG
43 gnunet-nse-profiler.c 43#gnunet_nse_profiler_SOURCES = \
44gnunet_nse_profiler_LDADD = -lm \ 44# gnunet-nse-profiler.c
45 libgnunetnse.la \ 45#gnunet_nse_profiler_LDADD = -lm \
46 $(top_builddir)/src/util/libgnunetutil.la \ 46# libgnunetnse.la \
47 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 47# $(top_builddir)/src/util/libgnunetutil.la \
48 $(top_builddir)/src/testing/libgnunettesting.la \ 48# $(top_builddir)/src/statistics/libgnunetstatistics.la \
49 $(top_builddir)/src/testbed/libgnunettestbed.la \ 49# $(top_builddir)/src/testing/libgnunettesting.la \
50 $(GN_LIBINTL) 50# $(top_builddir)/src/testbed/libgnunettestbed.la \
51# $(GN_LIBINTL)
51 52
52gnunet_service_nse_SOURCES = \ 53gnunet_service_nse_SOURCES = \
53 gnunet-service-nse.c 54 gnunet-service-nse.c
diff --git a/src/peerinfo-tool/.gitignore b/src/peerinfo-tool/.gitignore
deleted file mode 100644
index d4ed4f801..000000000
--- a/src/peerinfo-tool/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
1gnunet-peerinfo
2test_gnunet_peerinfo.py
diff --git a/src/peerinfo-tool/Makefile.am b/src/peerinfo-tool/Makefile.am
deleted file mode 100644
index 825ad5452..000000000
--- a/src/peerinfo-tool/Makefile.am
+++ /dev/null
@@ -1,64 +0,0 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3
4if USE_COVERAGE
5 AM_CFLAGS = --coverage -O0
6 XLIB = -lgcov
7endif
8
9REST_PLUGIN = libgnunet_plugin_rest_peerinfo.la
10
11plugindir = $(libdir)/gnunet
12
13plugin_LTLIBRARIES = $(REST_PLUGIN)
14
15bin_PROGRAMS = \
16 gnunet-peerinfo
17
18libgnunet_plugin_rest_peerinfo_la_SOURCES = \
19 plugin_rest_peerinfo.c
20libgnunet_plugin_rest_peerinfo_la_LIBADD = \
21 $(top_builddir)/src/hello/libgnunethello.la \
22 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
23 $(top_builddir)/src/transport/libgnunettransport.la \
24 $(top_builddir)/src/ats/libgnunetats.la \
25 $(top_builddir)/src/rest/libgnunetrest.la \
26 $(top_builddir)/src/json/libgnunetjson.la \
27 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \
28 $(LTLIBINTL) -ljansson $(MHD_LIBS)
29libgnunet_plugin_rest_peerinfo_la_LDFLAGS = \
30 $(GN_PLUGIN_LDFLAGS)
31libgnunet_plugin_rest_peerinfo_la_CFLAGS = $(MHD_CFLAGS) $(AM_CFLAGS)
32
33
34gnunet_peerinfo_SOURCES = \
35 gnunet-peerinfo.c \
36 gnunet-peerinfo_plugins.c gnunet-peerinfo_plugins.h
37gnunet_peerinfo_LDADD = \
38 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
39 $(top_builddir)/src/transport/libgnunettransport.la \
40 $(top_builddir)/src/hello/libgnunethello.la \
41 $(top_builddir)/src/statistics/libgnunetstatistics.la \
42 $(top_builddir)/src/util/libgnunetutil.la
43gnunet_peerinfo_LDFLAGS = \
44 $(GN_LIBINTL)
45
46if HAVE_PYTHON
47check_SCRIPTS = \
48 test_gnunet_peerinfo.py
49endif
50
51if ENABLE_TEST_RUN
52AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
53TESTS = $(check_SCRIPTS)
54endif
55
56test_gnunet_peerinfo.py: test_gnunet_peerinfo.py.in Makefile
57 $(AWK) -v bdir="$(bindir)" -v py="$(PYTHON)" -v awkay="$(AWK_BINARY)" -v pfx="$(prefix)" -v prl="$(PERL)" -v sysconfdirectory="$(sysconfdir)" -v pkgdatadirectory="$(pkgdatadir)" -f $(top_srcdir)/bin/dosubst.awk < $(srcdir)/test_gnunet_peerinfo.py.in > test_gnunet_peerinfo.py
58 chmod +x test_gnunet_peerinfo.py
59
60EXTRA_DIST = \
61 test_gnunet_peerinfo.py.in \
62 test_gnunet_peerinfo_data.conf
63
64CLEANFILES = $(check_SCRIPTS)
diff --git a/src/peerinfo-tool/gnunet-peerinfo.c b/src/peerinfo-tool/gnunet-peerinfo.c
deleted file mode 100644
index 8b149c98e..000000000
--- a/src/peerinfo-tool/gnunet-peerinfo.c
+++ /dev/null
@@ -1,864 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2001-2014, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file peerinfo-tool/gnunet-peerinfo.c
23 * @brief Print information about other known peers.
24 * @author Christian Grothoff
25 * @author Matthias Wachs
26 */
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_hello_lib.h"
30#include "gnunet_transport_service.h"
31#include "gnunet_transport_hello_service.h"
32#include "gnunet_peerinfo_service.h"
33#include "gnunet-peerinfo_plugins.h"
34
35/**
36 * How long until we time out during address lookup?
37 */
38#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
39
40/**
41 * Structure we use to collect printable address information.
42 */
43struct PrintContext;
44
45/**
46 * Record we keep for each printable address.
47 */
48struct AddressRecord
49{
50 /**
51 * Current address-to-string context (if active, otherwise NULL).
52 */
53 struct GNUNET_TRANSPORT_AddressToStringContext *atsc;
54
55 /**
56 * Address expiration time
57 */
58 struct GNUNET_TIME_Absolute expiration;
59
60 /**
61 * Printable address.
62 */
63 char *result;
64
65 /**
66 * Print context this address record belongs to.
67 */
68 struct PrintContext *pc;
69};
70
71
72/**
73 * Structure we use to collect printable address information.
74 */
75struct PrintContext
76{
77 /**
78 * Kept in DLL.
79 */
80 struct PrintContext *next;
81
82 /**
83 * Kept in DLL.
84 */
85 struct PrintContext *prev;
86
87 /**
88 * Identity of the peer.
89 */
90 struct GNUNET_PeerIdentity peer;
91
92 /**
93 * List of printable addresses.
94 */
95 struct AddressRecord *address_list;
96
97 /**
98 * Number of completed addresses in @e address_list.
99 */
100 unsigned int num_addresses;
101
102 /**
103 * Number of addresses allocated in @e address_list.
104 */
105 unsigned int address_list_size;
106
107 /**
108 * Current offset in @e address_list (counted down).
109 */
110 unsigned int off;
111
112 /**
113 * Hello was friend only, #GNUNET_YES or #GNUNET_NO
114 */
115 int friend_only;
116};
117
118
119/**
120 * Option '-n'
121 */
122static int no_resolve;
123
124/**
125 * Option '-q'
126 */
127static int be_quiet;
128
129/**
130 * Option '-f'
131 */
132static int include_friend_only;
133
134/**
135 * Option '-s'
136 */
137static int get_self;
138
139/**
140 * Option
141 */
142static int get_uri;
143
144/**
145 * Option
146 */
147static int default_operation;
148
149/**
150 * Option '-i'
151 */
152static int get_info;
153
154/**
155 * Option
156 */
157static char *put_uri;
158
159/**
160 * Option -d
161 */
162static char *dump_hello;
163
164/**
165 * Handle to peerinfo service.
166 */
167static struct GNUNET_PEERINFO_Handle *peerinfo;
168
169/**
170 * Configuration handle.
171 */
172static const struct GNUNET_CONFIGURATION_Handle *cfg;
173
174/**
175 * Main state machine task (if active).
176 */
177static struct GNUNET_SCHEDULER_Task *tt;
178
179/**
180 * Pending #GNUNET_TRANSPORT_hello_get() operation.
181 */
182static struct GNUNET_TRANSPORT_HelloGetHandle *gh;
183
184/**
185 * Current iterator context (if active, otherwise NULL).
186 */
187static struct GNUNET_PEERINFO_IteratorContext *pic;
188
189/**
190 * My peer identity.
191 */
192static struct GNUNET_PeerIdentity my_peer_identity;
193
194/**
195 * Head of list of print contexts.
196 */
197static struct PrintContext *pc_head;
198
199/**
200 * Tail of list of print contexts.
201 */
202static struct PrintContext *pc_tail;
203
204/**
205 * Handle to current #GNUNET_PEERINFO_add_peer() operation.
206 */
207static struct GNUNET_MQ_Envelope *ac;
208
209/**
210 * Hello of this peer (if initialized).
211 */
212static struct GNUNET_HELLO_Message *my_hello;
213
214
215/**
216 * Main state machine that goes over all options and
217 * runs the next requested function.
218 *
219 * @param cls unused
220 */
221static void
222state_machine (void *cls);
223
224
225/* ********************* 'get_info' ******************* */
226
227/**
228 * Print the collected address information to the console and free @a pc.
229 *
230 * @param pc printing context
231 */
232static void
233dump_pc (struct PrintContext *pc)
234{
235 unsigned int i;
236
237 printf (_ ("%sPeer `%s'\n"),
238 (GNUNET_YES == pc->friend_only) ? "F2F: " : "",
239 GNUNET_i2s_full (&pc->peer));
240 for (i = 0; i < pc->num_addresses; i++)
241 {
242 if (NULL != pc->address_list[i].result)
243 {
244 printf (_ ("\tExpires: %s \t %s\n"),
245 GNUNET_STRINGS_absolute_time_to_string (
246 pc->address_list[i].expiration),
247 pc->address_list[i].result);
248 GNUNET_free (pc->address_list[i].result);
249 }
250 }
251 printf ("\n");
252 GNUNET_free (pc->address_list);
253 GNUNET_CONTAINER_DLL_remove (pc_head, pc_tail, pc);
254 GNUNET_free (pc);
255 if ((NULL == pc_head) && (NULL == pic))
256 tt = GNUNET_SCHEDULER_add_now (&state_machine, NULL);
257}
258
259
260/* ************************* list all known addresses **************** */
261
262
263/**
264 * Function to call with a human-readable format of an address
265 *
266 * @param cls closure
267 * @param address NULL on error, otherwise 0-terminated printable UTF-8 string
268 * @param res result of the address to string conversion:
269 * if #GNUNET_OK: address was valid (conversion to
270 * string might still have failed)
271 * if #GNUNET_SYSERR: address is invalid
272 */
273static void
274process_resolved_address (void *cls, const char *address, int res)
275{
276 struct AddressRecord *ar = cls;
277 struct PrintContext *pc = ar->pc;
278
279 if (NULL != address)
280 {
281 if (0 != strlen (address))
282 {
283 if (NULL != ar->result)
284 GNUNET_free (ar->result);
285 ar->result = GNUNET_strdup (address);
286 }
287 return;
288 }
289 ar->atsc = NULL;
290 if (GNUNET_SYSERR == res)
291 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
292 _ ("Failure: Cannot convert address to string for peer `%s'\n"),
293 GNUNET_i2s (&ar->pc->peer));
294 pc->num_addresses++;
295 if (pc->num_addresses == pc->address_list_size)
296 dump_pc (pc);
297}
298
299
300/**
301 * Iterator callback to go over all addresses and count them.
302 *
303 * @param cls `struct PrintContext *` with `off` to increment
304 * @param address the address
305 * @param expiration expiration time
306 * @return #GNUNET_OK to keep the address and continue
307 */
308static int
309count_address (void *cls,
310 const struct GNUNET_HELLO_Address *address,
311 struct GNUNET_TIME_Absolute expiration)
312{
313 struct PrintContext *pc = cls;
314
315 pc->off++;
316 return GNUNET_OK;
317}
318
319
320/**
321 * Iterator callback to go over all addresses.
322 *
323 * @param cls closure
324 * @param address the address
325 * @param expiration expiration time
326 * @return #GNUNET_OK to keep the address and continue
327 */
328static int
329print_address (void *cls,
330 const struct GNUNET_HELLO_Address *address,
331 struct GNUNET_TIME_Absolute expiration)
332{
333 struct PrintContext *pc = cls;
334 struct AddressRecord *ar;
335
336 GNUNET_assert (0 < pc->off);
337 ar = &pc->address_list[--pc->off];
338 ar->pc = pc;
339 ar->expiration = expiration;
340 GNUNET_asprintf (&ar->result,
341 "%s:%lu:%u",
342 address->transport_name,
343 (unsigned long) address->address_length,
344 address->local_info);
345 ar->atsc = GNUNET_TRANSPORT_address_to_string (cfg,
346 address,
347 no_resolve,
348 TIMEOUT,
349 &process_resolved_address,
350 ar);
351 return GNUNET_OK;
352}
353
354
355/**
356 * Print information about the peer. Currently prints the `struct
357 * GNUNET_PeerIdentity` and the transport address.
358 *
359 * @param cls the `struct PrintContext *`
360 * @param peer identity of the peer
361 * @param hello addresses of the peer
362 * @param err_msg error message
363 */
364static void
365print_peer_info (void *cls,
366 const struct GNUNET_PeerIdentity *peer,
367 const struct GNUNET_HELLO_Message *hello,
368 const char *err_msg)
369{
370 struct PrintContext *pc;
371 int friend_only;
372
373 if (NULL == peer)
374 {
375 pic = NULL; /* end of iteration */
376 if (NULL != err_msg)
377 {
378 fprintf (stderr,
379 _ ("Error in communication with PEERINFO service: %s\n"),
380 err_msg);
381 }
382 if (NULL == pc_head)
383 tt = GNUNET_SCHEDULER_add_now (&state_machine, NULL);
384 return;
385 }
386 friend_only = GNUNET_NO;
387 if (NULL != hello)
388 friend_only = GNUNET_HELLO_is_friend_only (hello);
389 if ((GNUNET_YES == be_quiet) || (NULL == hello))
390 {
391 printf ("%s%s\n",
392 (GNUNET_YES == friend_only) ? "F2F: " : "",
393 GNUNET_i2s_full (peer));
394 return;
395 }
396 pc = GNUNET_new (struct PrintContext);
397 GNUNET_CONTAINER_DLL_insert (pc_head, pc_tail, pc);
398 pc->peer = *peer;
399 pc->friend_only = friend_only;
400 GNUNET_HELLO_iterate_addresses (hello, GNUNET_NO, &count_address, pc);
401 if (0 == pc->off)
402 {
403 dump_pc (pc);
404 return;
405 }
406 pc->address_list_size = pc->off;
407 pc->address_list = GNUNET_malloc (sizeof(struct AddressRecord) * pc->off);
408 GNUNET_HELLO_iterate_addresses (hello, GNUNET_NO, &print_address, pc);
409}
410
411
412/* ************************* DUMP Hello ************************** */
413
414/**
415 * Count the number of addresses in the HELLO.
416 *
417 * @param cls pointer to an `int *` used for the counter
418 * @param address an address to count
419 * @param expiration (unused)
420 * @return #GNUNET_OK
421 */
422static int
423count_addr (void *cls,
424 const struct GNUNET_HELLO_Address *address,
425 struct GNUNET_TIME_Absolute expiration)
426{
427 int *c = cls;
428
429 (*c)++;
430 return GNUNET_OK;
431}
432
433
434/**
435 * Write HELLO of my peer to a file.
436 *
437 * @param cls the `struct GetUriContext *`
438 * @param peer identity of the peer (unused)
439 * @param hello addresses of the peer
440 * @param err_msg error message
441 */
442static void
443dump_my_hello ()
444{
445 unsigned int size;
446 unsigned int c_addr;
447
448 size = GNUNET_HELLO_size (my_hello);
449 if (0 == size)
450 {
451 fprintf (stderr, _ ("Failure: Received invalid %s\n"), "HELLO");
452 return;
453 }
454 if (GNUNET_SYSERR ==
455 GNUNET_DISK_fn_write (dump_hello,
456 my_hello,
457 size,
458 GNUNET_DISK_PERM_USER_READ
459 | GNUNET_DISK_PERM_USER_WRITE
460 | GNUNET_DISK_PERM_GROUP_READ
461 | GNUNET_DISK_PERM_OTHER_READ))
462 {
463 fprintf (stderr,
464 _ ("Failed to write HELLO with %u bytes to file `%s'\n"),
465 size,
466 dump_hello);
467 if (0 != unlink (dump_hello))
468 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING
469 | GNUNET_ERROR_TYPE_BULK,
470 "unlink",
471 dump_hello);
472 }
473 c_addr = 0;
474 GNUNET_HELLO_iterate_addresses (my_hello, GNUNET_NO, count_addr, &c_addr);
475
476 if (! be_quiet)
477 {
478 fprintf (
479 stderr,
480 _ ("Wrote %s HELLO containing %u addresses with %u bytes to file `%s'\n"),
481 (GNUNET_YES == GNUNET_HELLO_is_friend_only (my_hello)) ? "friend-only"
482 : "public",
483 c_addr,
484 size,
485 dump_hello);
486 }
487 GNUNET_free (dump_hello);
488 dump_hello = NULL;
489}
490
491
492/* ************************* GET URI ************************** */
493
494
495/**
496 * Print URI of the peer.
497 *
498 * @param cls the `struct GetUriContext *`
499 * @param peer identity of the peer (unused)
500 * @param hello addresses of the peer
501 * @param err_msg error message
502 */
503static void
504print_my_uri (void *cls,
505 const struct GNUNET_PeerIdentity *peer,
506 const struct GNUNET_HELLO_Message *hello,
507 const char *err_msg)
508{
509 char *uri;
510
511 if (NULL == peer)
512 {
513 pic = NULL;
514 if (NULL != err_msg)
515 fprintf (stderr,
516 _ ("Error in communication with PEERINFO service: %s\n"),
517 err_msg);
518 tt = GNUNET_SCHEDULER_add_now (&state_machine, NULL);
519 return;
520 }
521
522 if (NULL == hello)
523 return;
524 uri = GNUNET_HELLO_compose_uri (hello, &GPI_plugins_find);
525 if (NULL != uri)
526 {
527 printf ("%s\n", (const char *) uri);
528 GNUNET_free (uri);
529 }
530}
531
532
533/* ************************* import HELLO by URI ********************* */
534
535
536/**
537 * Continuation called from #GNUNET_PEERINFO_add_peer()
538 *
539 * @param cls closure, NULL
540 */
541static void
542add_continuation (void *cls)
543{
544 ac = NULL;
545 tt = GNUNET_SCHEDULER_add_now (&state_machine, NULL);
546}
547
548
549/**
550 * Parse the PUT URI given at the command line and add it to our peerinfo
551 * database.
552 *
553 * @param put_uri URI string to parse
554 * @return #GNUNET_OK on success,
555 * #GNUNET_SYSERR if the URI was invalid,
556 * #GNUNET_NO on other errors
557 */
558static int
559parse_hello_uri (const char *put_uri)
560{
561 struct GNUNET_HELLO_Message *hello = NULL;
562
563 int ret = GNUNET_HELLO_parse_uri (put_uri,
564 &my_peer_identity.public_key,
565 &hello,
566 &GPI_plugins_find);
567
568 if (NULL != hello)
569 {
570 /* WARNING: this adds the address from URI WITHOUT verification! */
571 if (GNUNET_OK == ret)
572 ac = GNUNET_PEERINFO_add_peer (peerinfo, hello, &add_continuation, NULL);
573 else
574 tt = GNUNET_SCHEDULER_add_now (&state_machine, NULL);
575 GNUNET_free (hello);
576 }
577 return ret;
578}
579
580
581/* ************************ Main state machine ********************* */
582
583
584/**
585 * Main state machine that goes over all options and
586 * runs the next requested function.
587 *
588 * @param cls unused
589 */
590static void
591shutdown_task (void *cls)
592{
593 struct PrintContext *pc;
594 struct AddressRecord *ar;
595 unsigned int i;
596
597 if (NULL != ac)
598 {
599 GNUNET_MQ_send_cancel (ac);
600 ac = NULL;
601 }
602 if (NULL != tt)
603 {
604 GNUNET_SCHEDULER_cancel (tt);
605 tt = NULL;
606 }
607 if (NULL != pic)
608 {
609 GNUNET_PEERINFO_iterate_cancel (pic);
610 pic = NULL;
611 }
612 if (NULL != gh)
613 {
614 GNUNET_TRANSPORT_hello_get_cancel (gh);
615 gh = NULL;
616 }
617 while (NULL != (pc = pc_head))
618 {
619 GNUNET_CONTAINER_DLL_remove (pc_head, pc_tail, pc);
620 for (i = 0; i < pc->address_list_size; i++)
621 {
622 ar = &pc->address_list[i];
623 GNUNET_free (ar->result);
624 if (NULL != ar->atsc)
625 {
626 GNUNET_TRANSPORT_address_to_string_cancel (ar->atsc);
627 ar->atsc = NULL;
628 }
629 }
630 GNUNET_free (pc->address_list);
631 GNUNET_free (pc);
632 }
633 GPI_plugins_unload ();
634 if (NULL != peerinfo)
635 {
636 GNUNET_PEERINFO_disconnect (peerinfo);
637 peerinfo = NULL;
638 }
639 if (NULL != my_hello)
640 {
641 GNUNET_free (my_hello);
642 my_hello = NULL;
643 }
644}
645
646
647/**
648 * Function called with our peer's HELLO message.
649 * Used to obtain our peer's public key.
650 *
651 * @param cls NULL
652 * @param hello the HELLO message
653 */
654static void
655hello_callback (void *cls, const struct GNUNET_MessageHeader *hello)
656{
657 if (NULL == hello)
658 {
659 fprintf (stderr, "Failed to get my own HELLO from this peer!\n");
660 GNUNET_SCHEDULER_shutdown ();
661 return;
662 }
663 my_hello = (struct GNUNET_HELLO_Message *) GNUNET_copy_message (hello);
664 GNUNET_assert (GNUNET_OK ==
665 GNUNET_HELLO_get_id (my_hello, &my_peer_identity));
666 GNUNET_TRANSPORT_hello_get_cancel (gh);
667 gh = NULL;
668 if (NULL != dump_hello)
669 dump_my_hello ();
670 tt = GNUNET_SCHEDULER_add_now (&state_machine, NULL);
671}
672
673
674/**
675 * Main function that will be run by the scheduler.
676 *
677 * @param cls closure
678 * @param args remaining command-line arguments
679 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
680 * @param c configuration
681 */
682static void
683run (void *cls,
684 char *const *args,
685 const char *cfgfile,
686 const struct GNUNET_CONFIGURATION_Handle *c)
687{
688 cfg = c;
689 if ((NULL != args[0]) && (NULL == put_uri) &&
690 (args[0] == strcasestr (args[0], "gnunet://hello/")))
691 {
692 put_uri = GNUNET_strdup (args[0]);
693 args++;
694 }
695 if (NULL != args[0])
696 {
697 fprintf (stderr, _ ("Invalid command line argument `%s'\n"), args[0]);
698 return;
699 }
700 if (NULL == (peerinfo = GNUNET_PEERINFO_connect (cfg)))
701 {
702 fprintf (stderr, "%s", "Could not access PEERINFO service. Exiting.\n");
703 return;
704 }
705 if ((GNUNET_YES == get_self) || (GNUNET_YES == get_uri) ||
706 (NULL != dump_hello))
707 {
708 gh = GNUNET_TRANSPORT_hello_get (cfg,
709 GNUNET_TRANSPORT_AC_ANY,
710 &hello_callback,
711 NULL);
712 }
713 else
714 {
715 tt = GNUNET_SCHEDULER_add_now (&state_machine, NULL);
716 }
717 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
718}
719
720
721/**
722 * Main state machine that goes over all options and
723 * runs the next requested function.
724 *
725 * @param cls unused
726 */
727static void
728state_machine (void *cls)
729{
730 tt = NULL;
731
732 if (NULL != put_uri)
733 {
734 GPI_plugins_load (cfg);
735 if (GNUNET_SYSERR == parse_hello_uri (put_uri))
736 {
737 fprintf (stderr, _ ("Invalid URI `%s'\n"), put_uri);
738 GNUNET_SCHEDULER_shutdown ();
739 }
740 GNUNET_free (put_uri);
741 put_uri = NULL;
742 }
743 else if (GNUNET_YES == get_info)
744 {
745 get_info = GNUNET_NO;
746 GPI_plugins_load (cfg);
747 pic = GNUNET_PEERINFO_iterate (peerinfo,
748 include_friend_only,
749 NULL,
750 &print_peer_info,
751 NULL);
752 }
753 else if (GNUNET_YES == get_self)
754 {
755 get_self = GNUNET_NO;
756 if (be_quiet)
757 printf ("%s\n", GNUNET_i2s_full (&my_peer_identity));
758 else
759 printf (_ ("I am peer `%s'.\n"), GNUNET_i2s_full (&my_peer_identity));
760 tt = GNUNET_SCHEDULER_add_now (&state_machine, NULL);
761 }
762 else if (GNUNET_YES == get_uri)
763 {
764 GPI_plugins_load (cfg);
765 pic = GNUNET_PEERINFO_iterate (peerinfo,
766 include_friend_only,
767 &my_peer_identity,
768 &print_my_uri,
769 NULL);
770 get_uri = GNUNET_NO;
771 }
772 else if (GNUNET_YES == default_operation)
773 {
774 /* default operation list all */
775 default_operation = GNUNET_NO;
776 get_info = GNUNET_YES;
777 tt = GNUNET_SCHEDULER_add_now (&state_machine, NULL);
778 }
779 else
780 {
781 GNUNET_SCHEDULER_shutdown ();
782 }
783 default_operation = GNUNET_NO;
784}
785
786
787/**
788 * The main function to obtain peer information.
789 *
790 * @param argc number of arguments from the command line
791 * @param argv command line arguments
792 * @return 0 ok, 1 on error
793 */
794int
795main (int argc, char *const *argv)
796{
797 struct GNUNET_GETOPT_CommandLineOption options[] =
798 { GNUNET_GETOPT_option_flag ('n',
799 "numeric",
800 gettext_noop ("don't resolve host names"),
801 &no_resolve),
802
803 GNUNET_GETOPT_option_flag ('q',
804 "quiet",
805 gettext_noop (
806 "output only the identity strings"),
807 &be_quiet),
808 GNUNET_GETOPT_option_flag ('f',
809 "friends",
810 gettext_noop (
811 "include friend-only information"),
812 &include_friend_only),
813
814 GNUNET_GETOPT_option_flag ('s',
815 "self",
816 gettext_noop ("output our own identity only"),
817 &get_self),
818
819 GNUNET_GETOPT_option_flag ('i',
820 "info",
821 gettext_noop ("list all known peers"),
822 &get_info),
823
824 GNUNET_GETOPT_option_string ('d',
825 "dump-hello",
826 NULL,
827 gettext_noop ("dump hello to file"),
828 &dump_hello),
829
830 GNUNET_GETOPT_option_flag ('g',
831 "get-hello",
832 gettext_noop ("also output HELLO uri(s)"),
833 &get_uri),
834
835 GNUNET_GETOPT_option_string ('p',
836 "put-hello",
837 "HELLO",
838 gettext_noop (
839 "add given HELLO uri to the database"),
840 &put_uri),
841
842 GNUNET_GETOPT_OPTION_END };
843 int ret;
844
845 default_operation = GNUNET_YES;
846 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
847 return 2;
848
849 ret = (GNUNET_OK ==
850 GNUNET_PROGRAM_run (argc,
851 argv,
852 "gnunet-peerinfo",
853 gettext_noop ("Print information about peers."),
854 options,
855 &run,
856 NULL))
857 ? 0
858 : 1;
859 GNUNET_free_nz ((void *) argv);
860 return ret;
861}
862
863
864/* end of gnunet-peerinfo.c */
diff --git a/src/peerinfo-tool/gnunet-peerinfo_plugins.c b/src/peerinfo-tool/gnunet-peerinfo_plugins.c
deleted file mode 100644
index e196ec58a..000000000
--- a/src/peerinfo-tool/gnunet-peerinfo_plugins.c
+++ /dev/null
@@ -1,196 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010,2011 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file peerinfo-tool/gnunet-peerinfo_plugins.c
23 * @brief plugin management
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet-peerinfo_plugins.h"
28#include "gnunet_transport_plugin.h"
29#include "gnunet_hello_lib.h"
30
31/**
32 * Entry in doubly-linked list of all of our plugins.
33 */
34struct TransportPlugin
35{
36 /**
37 * This is a doubly-linked list.
38 */
39 struct TransportPlugin *next;
40
41 /**
42 * This is a doubly-linked list.
43 */
44 struct TransportPlugin *prev;
45
46 /**
47 * API of the transport as returned by the plugin's
48 * initialization function.
49 */
50 struct GNUNET_TRANSPORT_PluginFunctions *api;
51
52 /**
53 * Short name for the plugin (e.g. "tcp").
54 */
55 char *short_name;
56
57 /**
58 * Name of the library (e.g. "gnunet_plugin_transport_tcp").
59 */
60 char *lib_name;
61
62 /**
63 * Environment this transport service is using
64 * for this plugin.
65 */
66 struct GNUNET_TRANSPORT_PluginEnvironment env;
67};
68
69/**
70 * Head of DLL of all loaded plugins.
71 */
72static struct TransportPlugin *plugins_head;
73
74/**
75 * Head of DLL of all loaded plugins.
76 */
77static struct TransportPlugin *plugins_tail;
78
79
80/**
81 * Load and initialize all plugins. The respective functions will be
82 * invoked by the plugins when the respective events happen. The
83 * closure will be set to a 'const char*' containing the name of the
84 * plugin that caused the call.
85 *
86 * @param cfg configuration to use
87 */
88void
89GPI_plugins_load (const struct GNUNET_CONFIGURATION_Handle *cfg)
90{
91 struct TransportPlugin *plug;
92 struct TransportPlugin *next;
93 char *libname;
94 char *plugs;
95 char *pos;
96
97 if (NULL != plugins_head)
98 return; /* already loaded */
99 if (GNUNET_OK !=
100 GNUNET_CONFIGURATION_get_value_string (cfg, "TRANSPORT", "PLUGINS",
101 &plugs))
102 return;
103 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Starting transport plugins `%s'\n"),
104 plugs);
105 for (pos = strtok (plugs, " "); pos != NULL; pos = strtok (NULL, " "))
106 {
107 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Loading `%s' transport plugin\n"),
108 pos);
109 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", pos);
110 plug = GNUNET_new (struct TransportPlugin);
111 plug->short_name = GNUNET_strdup (pos);
112 plug->lib_name = libname;
113 plug->env.cfg = cfg;
114 plug->env.cls = plug->short_name;
115 GNUNET_CONTAINER_DLL_insert (plugins_head, plugins_tail, plug);
116 }
117 GNUNET_free (plugs);
118 next = plugins_head;
119 while (next != NULL)
120 {
121 plug = next;
122 next = plug->next;
123 plug->api = GNUNET_PLUGIN_load (plug->lib_name, &plug->env);
124 if (plug->api == NULL)
125 {
126 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
127 _ ("Failed to load transport plugin for `%s'\n"),
128 plug->lib_name);
129 GNUNET_CONTAINER_DLL_remove (plugins_head, plugins_tail, plug);
130 GNUNET_free (plug->short_name);
131 GNUNET_free (plug->lib_name);
132 GNUNET_free (plug);
133 }
134 }
135}
136
137
138/**
139 * Unload all plugins
140 */
141void
142GPI_plugins_unload ()
143{
144 struct TransportPlugin *plug;
145
146 while (NULL != (plug = plugins_head))
147 {
148 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
149 GNUNET_free (plug->lib_name);
150 GNUNET_free (plug->short_name);
151 GNUNET_CONTAINER_DLL_remove (plugins_head, plugins_tail, plug);
152 GNUNET_free (plug);
153 }
154}
155
156
157/**
158 * Obtain the plugin API based on a plugin name.
159 *
160 * @param name name of the plugin
161 * @return the plugin's API, NULL if the plugin is not loaded
162 */
163struct GNUNET_TRANSPORT_PluginFunctions *
164GPI_plugins_find (const char *name)
165{
166 struct TransportPlugin *head = plugins_head;
167
168 char *stripped = GNUNET_strdup (name);
169 char *head_stripped;
170 char *sep = strchr (stripped, '_');
171
172 if (NULL != sep)
173 sep[0] = '\0';
174
175 while (head != NULL)
176 {
177 head_stripped = GNUNET_strdup (head->short_name);
178 char *head_sep = strchr (head_stripped, '_');
179 if (NULL != head_sep)
180 head_sep[0] = '\0';
181 if (0 == strcmp (head_stripped, stripped))
182 {
183 GNUNET_free (head_stripped);
184 break;
185 }
186 GNUNET_free (head_stripped);
187 head = head->next;
188 }
189 GNUNET_free (stripped);
190 if (NULL == head)
191 return NULL;
192 return head->api;
193}
194
195
196/* end of file gnunet-peerinfo_plugins.c */
diff --git a/src/peerinfo-tool/gnunet-peerinfo_plugins.h b/src/peerinfo-tool/gnunet-peerinfo_plugins.h
deleted file mode 100644
index ed8da87d5..000000000
--- a/src/peerinfo-tool/gnunet-peerinfo_plugins.h
+++ /dev/null
@@ -1,58 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010,2011 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file peerinfo-tool/gnunet-peerinfo_plugins.h
23 * @brief plugin management API
24 * @author Christian Grothoff
25 */
26#ifndef GNUNET_PEERINFO_PLUGINS_H
27#define GNUNET_PEERINFO_PLUGINS_H
28
29#include "gnunet_util_lib.h"
30
31/**
32 * Load transport plugins.
33 *
34 * @param cfg configuration to use
35 */
36void
37GPI_plugins_load (const struct GNUNET_CONFIGURATION_Handle *cfg);
38
39
40/**
41 * Unload all plugins
42 */
43void
44GPI_plugins_unload (void);
45
46
47/**
48 * Obtain the plugin API based on a plugin name.
49 *
50 * @param name name of the plugin
51 * @return the plugin's API, NULL if the plugin is not loaded
52 */
53struct GNUNET_TRANSPORT_PluginFunctions *
54GPI_plugins_find (const char *name);
55
56
57#endif
58/* end of file gnunet-peerinfo_plugins.h */
diff --git a/src/peerinfo-tool/meson.build b/src/peerinfo-tool/meson.build
deleted file mode 100644
index 2d5386eba..000000000
--- a/src/peerinfo-tool/meson.build
+++ /dev/null
@@ -1,31 +0,0 @@
1gnunetpeerinfotool_src = ['gnunet-peerinfo.c', 'gnunet-peerinfo_plugins.c']
2
3
4if get_option('monolith')
5 subdir_done()
6endif
7
8shared_module('gnunet_plugin_rest_peerinfo',
9 ['plugin_rest_peerinfo.c'],
10 dependencies: [libgnunetrest_dep,
11 libgnunetpeerinfo_dep,
12 libgnunettransport_dep,
13 libgnunethello_dep,
14 libgnunetutil_dep,
15 json_dep,
16 mhd_dep],
17 include_directories: [incdir, configuration_inc],
18 install: true,
19 install_dir: get_option('libdir') / 'gnunet')
20
21
22executable ('gnunet-peerinfo',
23 gnunetpeerinfotool_src,
24 dependencies: [libgnunetutil_dep,
25 libgnunetpeerinfo_dep,
26 libgnunettransport_dep,
27 libgnunethello_dep,
28 libgnunetstatistics_dep],
29 include_directories: [incdir, configuration_inc],
30 install: true,
31 install_dir: get_option('bindir'))
diff --git a/src/peerinfo-tool/plugin_rest_peerinfo.c b/src/peerinfo-tool/plugin_rest_peerinfo.c
deleted file mode 100644
index 13e2e863b..000000000
--- a/src/peerinfo-tool/plugin_rest_peerinfo.c
+++ /dev/null
@@ -1,842 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012-2015 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Martin Schanzenbach
22 * @author Philippe Buschmann
23 * @file peerinfo/plugin_rest_peerinfo.c
24 * @brief GNUnet Peerinfo REST plugin
25 */
26
27#include "platform.h"
28#include "gnunet_rest_plugin.h"
29#include "gnunet_peerinfo_service.h"
30#include "gnunet_transport_service.h"
31#include "gnunet_rest_lib.h"
32#include "gnunet_json_lib.h"
33#include "microhttpd.h"
34#include <jansson.h>
35
36/**
37 * Peerinfo Namespace
38 */
39#define GNUNET_REST_API_NS_PEERINFO "/peerinfo"
40
41/**
42 * Peerinfo parameter peer
43 */
44#define GNUNET_REST_PEERINFO_PEER "peer"
45
46/**
47 * Peerinfo parameter friend
48 */
49#define GNUNET_REST_PEERINFO_FRIEND "friend"
50
51/**
52 * Peerinfo parameter array
53 */
54#define GNUNET_REST_PEERINFO_ARRAY "array"
55
56/**
57 * Error message Unknown Error
58 */
59#define GNUNET_REST_PEERINFO_ERROR_UNKNOWN "Unknown Error"
60
61/**
62 * How long until we time out during address lookup?
63 */
64#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
65/**
66 * The configuration handle
67 */
68const struct GNUNET_CONFIGURATION_Handle *cfg;
69
70/**
71 * HTTP methods allows for this plugin
72 */
73static char *allow_methods;
74
75/**
76 * Handle to PEERINFO
77 */
78static struct GNUNET_PEERINFO_Handle *peerinfo_handle;
79
80/**
81 * @brief struct returned by the initialization function of the plugin
82 */
83struct Plugin
84{
85 const struct GNUNET_CONFIGURATION_Handle *cfg;
86};
87
88
89/**
90 * Record we keep for each printable address.
91 */
92struct AddressRecord
93{
94 /**
95 * Current address-to-string context (if active, otherwise NULL).
96 */
97 struct GNUNET_TRANSPORT_AddressToStringContext *atsc;
98
99 /**
100 * Address expiration time
101 */
102 struct GNUNET_TIME_Absolute expiration;
103
104 /**
105 * Printable address.
106 */
107 char *result;
108
109 /**
110 * Print context this address record belongs to.
111 */
112 struct PrintContext *pc;
113};
114
115
116/**
117 * Structure we use to collect printable address information.
118 */
119struct PrintContext
120{
121 /**
122 * Kept in DLL.
123 */
124 struct PrintContext *next;
125
126 /**
127 * Kept in DLL.
128 */
129 struct PrintContext *prev;
130
131 /**
132 * Identity of the peer.
133 */
134 struct GNUNET_PeerIdentity peer;
135
136 /**
137 * List of printable addresses.
138 */
139 struct AddressRecord *address_list;
140
141 /**
142 * Number of completed addresses in @e address_list.
143 */
144 unsigned int num_addresses;
145
146 /**
147 * Number of addresses allocated in @e address_list.
148 */
149 unsigned int address_list_size;
150
151 /**
152 * Current offset in @e address_list (counted down).
153 */
154 unsigned int off;
155
156 /**
157 * Hello was friend only, #GNUNET_YES or #GNUNET_NO
158 */
159 int friend_only;
160
161 /**
162 * RequestHandle
163 */
164 struct RequestHandle *handle;
165};
166
167/**
168 * Head of list of print contexts.
169 */
170static struct PrintContext *pc_head;
171
172/**
173 * Tail of list of print contexts.
174 */
175static struct PrintContext *pc_tail;
176
177/**
178 * The request handle
179 */
180struct RequestHandle
181{
182 /**
183 * DLL
184 */
185 struct RequestHandle *next;
186
187 /**
188 * DLL
189 */
190 struct RequestHandle *prev;
191
192 /**
193 * JSON temporary array
194 */
195 json_t *temp_array;
196
197 /**
198 * Expiration time string
199 */
200 char *expiration_str;
201
202 /**
203 * Address string
204 */
205 const char *address;
206
207 /**
208 * Iteration peer public key
209 */
210 char *pubkey;
211
212 /**
213 * JSON response
214 */
215 json_t *response;
216
217 /**
218 * Handle to PEERINFO it
219 */
220 struct GNUNET_PEERINFO_IteratorContext *list_it;
221
222
223 /**
224 * Rest connection
225 */
226 struct GNUNET_REST_RequestHandle *rest_handle;
227
228 /**
229 * Desired timeout for the lookup (default is no timeout).
230 */
231 struct GNUNET_TIME_Relative timeout;
232
233 /**
234 * ID of a task associated with the resolution process.
235 */
236 struct GNUNET_SCHEDULER_Task *timeout_task;
237
238 /**
239 * The plugin result processor
240 */
241 GNUNET_REST_ResultProcessor proc;
242
243 /**
244 * The closure of the result processor
245 */
246 void *proc_cls;
247
248 /**
249 * The url
250 */
251 char *url;
252
253 /**
254 * Error response message
255 */
256 char *emsg;
257
258 /**
259 * Response code
260 */
261 int response_code;
262};
263
264/**
265 * DLL
266 */
267static struct RequestHandle *requests_head;
268
269/**
270 * DLL
271 */
272static struct RequestHandle *requests_tail;
273
274/**
275 * Cleanup lookup handle
276 * @param handle Handle to clean up
277 */
278static void
279cleanup_handle (void *cls)
280{
281 struct RequestHandle *handle = cls;
282
283 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
284 "Cleaning up\n");
285 if (NULL != handle->timeout_task)
286 {
287 GNUNET_SCHEDULER_cancel (handle->timeout_task);
288 handle->timeout_task = NULL;
289 }
290 if (NULL != handle->url)
291 GNUNET_free (handle->url);
292 if (NULL != handle->emsg)
293 GNUNET_free (handle->emsg);
294 if (NULL != handle->address)
295 GNUNET_free_nz ((char *) handle->address);
296 if (NULL != handle->expiration_str)
297 GNUNET_free (handle->expiration_str);
298 if (NULL != handle->pubkey)
299 GNUNET_free (handle->pubkey);
300
301 if (NULL != handle->temp_array)
302 {
303 json_decref (handle->temp_array);
304 handle->temp_array = NULL;
305 }
306 if (NULL != handle->response)
307 {
308 json_decref (handle->response);
309 handle->response = NULL;
310 }
311
312 if (NULL != handle->list_it)
313 {
314 GNUNET_PEERINFO_iterate_cancel (handle->list_it);
315 handle->list_it = NULL;
316 }
317 if (NULL != peerinfo_handle)
318 {
319 GNUNET_PEERINFO_disconnect (peerinfo_handle);
320 peerinfo_handle = NULL;
321 }
322 GNUNET_CONTAINER_DLL_remove (requests_head,
323 requests_tail,
324 handle);
325 GNUNET_free (handle);
326}
327
328
329/**
330 * Task run on errors. Reports an error and cleans up everything.
331 *
332 * @param cls the `struct RequestHandle`
333 */
334static void
335do_error (void *cls)
336{
337 struct RequestHandle *handle = cls;
338 struct MHD_Response *resp;
339 json_t *json_error = json_object ();
340 char *response;
341
342 if (NULL == handle->emsg)
343 handle->emsg = GNUNET_strdup (GNUNET_REST_PEERINFO_ERROR_UNKNOWN);
344
345 json_object_set_new (json_error, "error", json_string (handle->emsg));
346
347 if (0 == handle->response_code)
348 handle->response_code = MHD_HTTP_OK;
349 response = json_dumps (json_error, 0);
350 resp = GNUNET_REST_create_response (response);
351 MHD_add_response_header (resp, "Content-Type", "application/json");
352 handle->proc (handle->proc_cls, resp, handle->response_code);
353 json_decref (json_error);
354 GNUNET_free (response);
355 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
356}
357
358
359/**
360 * Function that assembles the response.
361 *
362 * @param cls the `struct RequestHandle`
363 */
364static void
365peerinfo_list_finished (void *cls)
366{
367 struct RequestHandle *handle = cls;
368 char *result_str;
369 struct MHD_Response *resp;
370
371 if (NULL == handle->response)
372 {
373 handle->response_code = MHD_HTTP_NOT_FOUND;
374 handle->emsg = GNUNET_strdup ("No peers found");
375 GNUNET_SCHEDULER_add_now (&do_error, handle);
376 return;
377 }
378
379 result_str = json_dumps (handle->response, 0);
380 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
381 resp = GNUNET_REST_create_response (result_str);
382 GNUNET_assert (MHD_NO != MHD_add_response_header (resp,
383 "Content-Type",
384 "application/json"));
385 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
386 GNUNET_free (result_str);
387 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
388}
389
390
391/**
392 * Iterator callback to go over all addresses and count them.
393 *
394 * @param cls `struct PrintContext *` with `off` to increment
395 * @param address the address
396 * @param expiration expiration time
397 * @return #GNUNET_OK to keep the address and continue
398 */
399static int
400count_address (void *cls,
401 const struct GNUNET_HELLO_Address *address,
402 struct GNUNET_TIME_Absolute expiration)
403{
404 struct PrintContext *pc = cls;
405
406 if (0 == GNUNET_TIME_absolute_get_remaining (expiration).rel_value_us)
407 {
408 return GNUNET_OK; /* ignore expired address */
409 }
410
411 pc->off++;
412 return GNUNET_OK;
413}
414
415
416/**
417 * Print the collected address information to the console and free @a pc.
418 *
419 * @param pc printing context
420 */
421static void
422dump_pc (struct PrintContext *pc)
423{
424 struct RequestHandle *handle;
425 unsigned int i;
426 json_t *response_entry;
427 json_t *temp_array;
428 json_t *object;
429 json_t *address;
430 json_t *expires;
431 json_t *friend_and_peer_json;
432 char *friend_and_peer;
433
434 temp_array = json_array ();
435 response_entry = json_object ();
436
437 for (i = 0; i < pc->num_addresses; i++)
438 {
439 if (NULL != pc->address_list[i].result)
440 {
441 object = json_object ();
442 address = json_string (pc->address_list[i].result);
443 expires = json_string (
444 GNUNET_STRINGS_absolute_time_to_string (
445 pc->address_list[i].expiration));
446 json_object_set (object, "address", address);
447 json_object_set (object, "expires", expires);
448
449 json_decref (address);
450 json_decref (expires);
451
452 json_array_append (temp_array, object);
453 json_decref (object);
454 GNUNET_free (pc->address_list[i].result);
455 }
456 }
457
458 if (0 < json_array_size (temp_array))
459 {
460 GNUNET_asprintf (&friend_and_peer,
461 "%s%s",
462 (GNUNET_YES == pc->friend_only) ? "F2F:" : "",
463 GNUNET_i2s_full (&pc->peer));
464 friend_and_peer_json = json_string (friend_and_peer);
465 json_object_set (response_entry,
466 GNUNET_REST_PEERINFO_PEER,
467 friend_and_peer_json);
468 json_object_set (response_entry,
469 GNUNET_REST_PEERINFO_ARRAY,
470 temp_array);
471 json_array_append (pc->handle->response, response_entry);
472 json_decref (friend_and_peer_json);
473 GNUNET_free (friend_and_peer);
474 }
475
476 json_decref (temp_array);
477 json_decref (response_entry);
478
479 GNUNET_free (pc->address_list);
480 GNUNET_CONTAINER_DLL_remove (pc_head,
481 pc_tail,
482 pc);
483 handle = pc->handle;
484 GNUNET_free (pc);
485
486 if ((NULL == pc_head) &&
487 (NULL == handle->list_it))
488 {
489 GNUNET_SCHEDULER_add_now (&peerinfo_list_finished, handle);
490 }
491}
492
493
494/**
495 * Function to call with a human-readable format of an address
496 *
497 * @param cls closure
498 * @param address NULL on error, otherwise 0-terminated printable UTF-8 string
499 * @param res result of the address to string conversion:
500 * if #GNUNET_OK: address was valid (conversion to
501 * string might still have failed)
502 * if #GNUNET_SYSERR: address is invalid
503 */
504static void
505process_resolved_address (void *cls,
506 const char *address,
507 int res)
508{
509 struct AddressRecord *ar = cls;
510 struct PrintContext *pc = ar->pc;
511
512 if (NULL != address)
513 {
514 if (0 != strlen (address))
515 {
516 if (NULL != ar->result)
517 GNUNET_free (ar->result);
518 ar->result = GNUNET_strdup (address);
519 }
520 return;
521 }
522 ar->atsc = NULL;
523 if (GNUNET_SYSERR == res)
524 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
525 _ ("Failure: Cannot convert address to string for peer `%s'\n"),
526 GNUNET_i2s (&ar->pc->peer));
527 pc->num_addresses++;
528 if (pc->num_addresses == pc->address_list_size)
529 dump_pc (ar->pc);
530}
531
532
533/**
534 * Iterator callback to go over all addresses.
535 *
536 * @param cls closure
537 * @param address the address
538 * @param expiration expiration time
539 * @return #GNUNET_OK to keep the address and continue
540 */
541static int
542print_address (void *cls,
543 const struct GNUNET_HELLO_Address *address,
544 struct GNUNET_TIME_Absolute expiration)
545{
546 struct PrintContext *pc = cls;
547 struct AddressRecord *ar;
548
549 if (0 == GNUNET_TIME_absolute_get_remaining (expiration).rel_value_us)
550 {
551 return GNUNET_OK; /* ignore expired address */
552 }
553
554 GNUNET_assert (0 < pc->off);
555 ar = &pc->address_list[--pc->off];
556 ar->pc = pc;
557 ar->expiration = expiration;
558 GNUNET_asprintf (&ar->result,
559 "%s:%lu:%u",
560 address->transport_name,
561 (unsigned long) address->address_length,
562 address->local_info);
563 ar->atsc = GNUNET_TRANSPORT_address_to_string (cfg,
564 address,
565 GNUNET_NO,
566 TIMEOUT,
567 &process_resolved_address,
568 ar);
569 return GNUNET_OK;
570}
571
572
573/**
574 * Callback that processes each of the known HELLOs for the
575 * iteration response construction.
576 *
577 * @param cls closure, NULL
578 * @param peer id of the peer, NULL for last call
579 * @param hello hello message for the peer (can be NULL)
580 * @param err_msg message
581 */
582void
583peerinfo_list_iteration (void *cls,
584 const struct GNUNET_PeerIdentity *peer,
585 const struct GNUNET_HELLO_Message *hello,
586 const char *err_msg)
587{
588 struct RequestHandle *handle = cls;
589 struct PrintContext *pc;
590 int friend_only;
591
592 if (NULL == handle->response)
593 {
594 handle->response = json_array ();
595 }
596
597 if (NULL == peer)
598 {
599 handle->list_it = NULL;
600 handle->emsg = GNUNET_strdup ("Error in communication with peerinfo");
601 if (NULL != err_msg)
602 {
603 GNUNET_free (handle->emsg);
604 handle->emsg = GNUNET_strdup (err_msg);
605 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
606 }
607 if (NULL == pc_head)
608 GNUNET_SCHEDULER_add_now (&do_error, handle);
609 return;
610 }
611 if (NULL == hello)
612 return;
613
614 friend_only = GNUNET_NO;
615 if (NULL != hello)
616 friend_only = GNUNET_HELLO_is_friend_only (hello);
617
618 pc = GNUNET_new (struct PrintContext);
619 GNUNET_CONTAINER_DLL_insert (pc_head,
620 pc_tail,
621 pc);
622 pc->peer = *peer;
623 pc->friend_only = friend_only;
624 pc->handle = handle;
625 GNUNET_HELLO_iterate_addresses (hello,
626 GNUNET_NO,
627 &count_address,
628 pc);
629 if (0 == pc->off)
630 {
631 dump_pc (pc);
632 return;
633 }
634 pc->address_list_size = pc->off;
635 pc->address_list = GNUNET_malloc (
636 sizeof(struct AddressRecord) * pc->off);
637 GNUNET_HELLO_iterate_addresses (hello,
638 GNUNET_NO,
639 &print_address,
640 pc);
641}
642
643
644/**
645 * Handle peerinfo GET request
646 *
647 * @param con_handle the connection handle
648 * @param url the url
649 * @param cls the RequestHandle
650 */
651void
652peerinfo_get (struct GNUNET_REST_RequestHandle *con_handle,
653 const char*url,
654 void *cls)
655{
656 struct RequestHandle *handle = cls;
657 struct GNUNET_HashCode key;
658 const struct GNUNET_PeerIdentity *specific_peer;
659 // GNUNET_PEER_Id peer_id;
660 int include_friend_only;
661 char*include_friend_only_str;
662
663 include_friend_only = GNUNET_NO;
664 GNUNET_CRYPTO_hash (GNUNET_REST_PEERINFO_FRIEND,
665 strlen (GNUNET_REST_PEERINFO_FRIEND),
666 &key);
667 if (GNUNET_YES
668 == GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map,
669 &key))
670 {
671 include_friend_only_str = GNUNET_CONTAINER_multihashmap_get (
672 con_handle->url_param_map, &key);
673 if (0 == strcmp (include_friend_only_str, "yes"))
674 {
675 include_friend_only = GNUNET_YES;
676 }
677 }
678
679 specific_peer = NULL;
680 GNUNET_CRYPTO_hash (GNUNET_REST_PEERINFO_PEER,
681 strlen (GNUNET_REST_PEERINFO_PEER),
682 &key);
683 if (GNUNET_YES
684 == GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map,
685 &key))
686 {
687 // peer_id = *(unsigned int*)GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map, &key);
688 // specific_peer = GNUNET_PEER_resolve2(peer_id);
689 }
690
691 handle->list_it = GNUNET_PEERINFO_iterate (peerinfo_handle,
692 include_friend_only,
693 specific_peer,
694 &peerinfo_list_iteration,
695 handle);
696}
697
698
699/**
700 * Respond to OPTIONS request
701 *
702 * @param con_handle the connection handle
703 * @param url the url
704 * @param cls the RequestHandle
705 */
706static void
707options_cont (struct GNUNET_REST_RequestHandle *con_handle,
708 const char*url,
709 void *cls)
710{
711 struct MHD_Response *resp;
712 struct RequestHandle *handle = cls;
713
714 // independent of path return all options
715 resp = GNUNET_REST_create_response (NULL);
716 MHD_add_response_header (resp,
717 "Access-Control-Allow-Methods",
718 allow_methods);
719 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
720 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
721 return;
722}
723
724
725/**
726 * Function processing the REST call
727 *
728 * @param method HTTP method
729 * @param url URL of the HTTP request
730 * @param data body of the HTTP request (optional)
731 * @param data_size length of the body
732 * @param proc callback function for the result
733 * @param proc_cls closure for callback function
734 * @return GNUNET_OK if request accepted
735 */
736static enum GNUNET_GenericReturnValue
737rest_process_request (struct GNUNET_REST_RequestHandle *rest_handle,
738 GNUNET_REST_ResultProcessor proc,
739 void *proc_cls)
740{
741 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
742 struct GNUNET_REST_RequestHandlerError err;
743 static const struct GNUNET_REST_RequestHandler handlers[] = {
744 { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_PEERINFO, &peerinfo_get },
745 { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_PEERINFO, &options_cont },
746 GNUNET_REST_HANDLER_END
747 };
748
749 handle->response_code = 0;
750 handle->timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
751 60);
752 handle->proc_cls = proc_cls;
753 handle->proc = proc;
754 handle->rest_handle = rest_handle;
755
756 handle->url = GNUNET_strdup (rest_handle->url);
757 if (handle->url[strlen (handle->url) - 1] == '/')
758 handle->url[strlen (handle->url) - 1] = '\0';
759 handle->timeout_task =
760 GNUNET_SCHEDULER_add_delayed (handle->timeout,
761 &do_error,
762 handle);
763 GNUNET_CONTAINER_DLL_insert (requests_head,
764 requests_tail,
765 handle);
766 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n");
767 if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle,
768 handlers,
769 &err,
770 handle))
771 {
772 cleanup_handle (handle);
773 return GNUNET_NO;
774 }
775 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n");
776 return GNUNET_YES;
777}
778
779
780/**
781 * Entry point for the plugin.
782 *
783 * @param cls Config info
784 * @return NULL on error, otherwise the plugin context
785 */
786void *
787libgnunet_plugin_rest_peerinfo_init (void *cls)
788{
789 static struct Plugin plugin;
790 struct GNUNET_REST_Plugin *api;
791
792 cfg = cls;
793 if (NULL != plugin.cfg)
794 return NULL; /* can only initialize once! */
795 memset (&plugin, 0, sizeof(struct Plugin));
796 plugin.cfg = cfg;
797 api = GNUNET_new (struct GNUNET_REST_Plugin);
798 api->cls = &plugin;
799 api->name = GNUNET_REST_API_NS_PEERINFO;
800 api->process_request = &rest_process_request;
801 GNUNET_asprintf (&allow_methods,
802 "%s, %s, %s, %s, %s",
803 MHD_HTTP_METHOD_GET,
804 MHD_HTTP_METHOD_POST,
805 MHD_HTTP_METHOD_PUT,
806 MHD_HTTP_METHOD_DELETE,
807 MHD_HTTP_METHOD_OPTIONS);
808 peerinfo_handle = GNUNET_PEERINFO_connect (cfg);
809
810 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
811 _ ("Peerinfo REST API initialized\n"));
812 return api;
813}
814
815
816/**
817 * Exit point from the plugin.
818 *
819 * @param cls the plugin context (as returned by "init")
820 * @return always NULL
821 */
822void *
823libgnunet_plugin_rest_peerinfo_done (void *cls)
824{
825 struct GNUNET_REST_Plugin *api = cls;
826 struct Plugin *plugin = api->cls;
827
828 plugin->cfg = NULL;
829 while (NULL != requests_head)
830 cleanup_handle (requests_head);
831 if (NULL != peerinfo_handle)
832 GNUNET_PEERINFO_disconnect (peerinfo_handle);
833
834 GNUNET_free (allow_methods);
835 GNUNET_free (api);
836 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
837 "Peerinfo REST plugin is finished\n");
838 return NULL;
839}
840
841
842/* end of plugin_rest_peerinfo.c */
diff --git a/src/peerinfo-tool/test_gnunet_peerinfo.py.in b/src/peerinfo-tool/test_gnunet_peerinfo.py.in
deleted file mode 100755
index 709556f70..000000000
--- a/src/peerinfo-tool/test_gnunet_peerinfo.py.in
+++ /dev/null
@@ -1,143 +0,0 @@
1#!@PYTHONEXE@
2# This file is part of GNUnet.
3# (C) 2010, 2018 Christian Grothoff (and other contributing authors)
4#
5# GNUnet is free software: you can redistribute it and/or modify it
6# under the terms of the GNU Affero General Public License as published
7# by the Free Software Foundation, either version 3 of the License,
8# or (at your option) any later version.
9#
10# GNUnet is distributed in the hope that it will be useful, but
11# WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13# Affero General Public License for more details.
14#
15# You should have received a copy of the GNU Affero General Public License
16# along with this program. If not, see <http://www.gnu.org/licenses/>.
17#
18# SPDX-License-Identifier: AGPL3.0-or-later
19#
20# Testcase for gnunet-peerinfo
21import sys
22import os
23import subprocess
24import re
25import shutil
26import time
27
28srcdir = "../.."
29gnunet_pyexpect_dir = os.path.join(srcdir, "contrib/scripts")
30if gnunet_pyexpect_dir not in sys.path:
31 sys.path.append(gnunet_pyexpect_dir)
32
33from gnunet_pyexpect import pexpect
34
35#save LANG and set it to C
36mylang = os.environ.get('LANG')
37os.environ['LANG'] = 'C'
38
39if os.name == 'posix':
40 peerinfo = './gnunet-peerinfo'
41 gnunetarm = 'gnunet-arm'
42 gnunettesting = 'gnunet-testing'
43elif os.name == 'nt':
44 peerinfo = './gnunet-peerinfo.exe'
45 gnunetarm = 'gnunet-arm.exe'
46 gnunettesting = 'gnunet-testing.exe'
47
48pinfo = pexpect()
49
50if os.name == "nt":
51 shutil.rmtree(os.path.join(os.getenv("TEMP"), "gnunet-test-peerinfo"), True)
52else:
53 shutil.rmtree("/tmp/gnunet-test-peerinfo", True)
54
55# create hostkey via testing lib # FIXME: The /tmp/ location needs to be adjusted to the TMP variable!
56hkk = subprocess.Popen([
57 gnunettesting, '-n', '1', '-c', 'test_gnunet_peerinfo_data.conf', '-k',
58 '/tmp/gnunet-test-peerinfo/.hostkey'
59])
60hkk.communicate()
61
62arm = subprocess.Popen([
63 gnunetarm, '-sq', '-c', 'test_gnunet_peerinfo_data.conf'
64])
65arm.communicate()
66
67try:
68 pinfo.spawn(
69 None, [peerinfo, '-c', 'test_gnunet_peerinfo_data.conf', '-s'],
70 stdout=subprocess.PIPE,
71 stderr=subprocess.STDOUT
72 )
73 pinfo.expect("stdout", re.compile(r'I am peer `.*\'.\r?\n'))
74
75 pinfo.spawn(
76 None, [peerinfo, '-c', 'test_gnunet_peerinfo_data.conf', '-qs'],
77 stdout=subprocess.PIPE,
78 stderr=subprocess.STDOUT
79 )
80 pinfo.expect(
81 "stdout",
82 re.
83 compile(r'....................................................\r?\n')
84 )
85
86 pinfo.spawn(
87 None, [peerinfo, '-c', 'test_gnunet_peerinfo_data.conf', 'invalid'],
88 stdout=subprocess.PIPE,
89 stderr=subprocess.STDOUT
90 )
91 pinfo.expect(
92 "stdout", re.compile(r'Invalid command line argument `invalid\'\r?\n')
93 )
94
95 arm = subprocess.Popen([
96 gnunetarm, '-q', '-i', 'transport', '-c',
97 'test_gnunet_peerinfo_data.conf'
98 ])
99 arm.communicate()
100 time.sleep(1)
101
102 pinfo.spawn(
103 None, [peerinfo, '-i', '-c', 'test_gnunet_peerinfo_data.conf'],
104 stdout=subprocess.PIPE,
105 stderr=subprocess.STDOUT
106 )
107 pinfo.expect("stdout", re.compile("Peer `.*'\r?\n"))
108 m = pinfo.expect("stdout", re.compile("\s.*:24357\r?\n"))
109 while len(m.group(0)) > 0:
110 m = pinfo.expect("stdout", re.compile("(\s.*:24357\r?\n|\r?\n|)"))
111
112 pinfo.spawn(
113 None, [peerinfo, '-i', '-c', 'test_gnunet_peerinfo_data.conf', '-n'],
114 stdout=subprocess.PIPE,
115 stderr=subprocess.STDOUT
116 )
117 pinfo.expect("stdout", re.compile("Peer `.*'\r?\n"))
118 m = pinfo.expect("stdout", re.compile("\s.*:24357\r?\n"))
119 while len(m.group(0)) > 0:
120 m = pinfo.expect("stdout", re.compile("(\s.*:24357\r?\n|\r?\n|)"))
121
122 pinfo.spawn(
123 None, [peerinfo, '-c', 'test_gnunet_peerinfo_data.conf', '-qs'],
124 stdout=subprocess.PIPE,
125 stderr=subprocess.STDOUT
126 )
127 pid = pinfo.read("stdout")
128 pid.strip()
129
130finally:
131 arm = subprocess.Popen([
132 gnunetarm, '-eq', '-c', 'test_gnunet_peerinfo_data.conf'
133 ])
134 arm.communicate()
135 if os.name == "nt":
136 shutil.rmtree(
137 os.path.join(os.getenv("TEMP"), "gnunet-test-peerinfo"), True
138 )
139 else:
140 shutil.rmtree("/tmp/gnunet-test-peerinfo", True)
141 #Reset LANG
142 if type(mylang) == str:
143 os.environ['LANG'] = mylang
diff --git a/src/peerinfo-tool/test_gnunet_peerinfo_data.conf b/src/peerinfo-tool/test_gnunet_peerinfo_data.conf
deleted file mode 100644
index d18d3cf96..000000000
--- a/src/peerinfo-tool/test_gnunet_peerinfo_data.conf
+++ /dev/null
@@ -1,13 +0,0 @@
1@INLINE@ ../../contrib/conf/gnunet/no_forcestart.conf
2
3[PATHS]
4GNUNET_TEST_HOME = $GNUNET_TMP/gnunet-test-peerinfo/
5
6[transport]
7plugins = tcp
8
9[nat]
10RETURN_LOCAL_ADDRESSES = YES
11
12[transport-tcp]
13PORT = 24357
diff --git a/src/peerinfo/.gitignore b/src/peerinfo/.gitignore
deleted file mode 100644
index 152ca2916..000000000
--- a/src/peerinfo/.gitignore
+++ /dev/null
@@ -1,6 +0,0 @@
1gnunet-service-peerinfo
2test_peerinfo_api
3test_peerinfo_api_friend_only
4test_peerinfo_api_notify_friend_only
5test_peerinfo_shipped_hellos
6perf_peerinfo_api
diff --git a/src/peerinfo/Makefile.am b/src/peerinfo/Makefile.am
deleted file mode 100644
index cdab22a9d..000000000
--- a/src/peerinfo/Makefile.am
+++ /dev/null
@@ -1,105 +0,0 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3
4pkgcfgdir= $(pkgdatadir)/config.d/
5
6libexecdir= $(pkglibdir)/libexec/
7
8plugindir = $(libdir)/gnunet
9
10pkgcfg_DATA = \
11 peerinfo.conf
12
13if USE_COVERAGE
14 AM_CFLAGS = --coverage -O0
15 XLIB = -lgcov
16endif
17
18lib_LTLIBRARIES = libgnunetpeerinfo.la
19
20
21libgnunetpeerinfo_la_SOURCES = \
22 peerinfo_api.c peerinfo.h \
23 peerinfo_api_notify.c
24libgnunetpeerinfo_la_LIBADD = \
25 $(top_builddir)/src/hello/libgnunethello.la \
26 $(top_builddir)/src/util/libgnunetutil.la \
27 $(XLIB) \
28 $(LTLIBINTL)
29libgnunetpeerinfo_la_LDFLAGS = \
30 $(GN_LIB_LDFLAGS) \
31 -version-info 0:0:0
32
33
34libexec_PROGRAMS = \
35 gnunet-service-peerinfo
36
37gnunet_service_peerinfo_SOURCES = \
38 gnunet-service-peerinfo.c
39gnunet_service_peerinfo_LDADD = \
40 $(top_builddir)/src/hello/libgnunethello.la \
41 $(top_builddir)/src/statistics/libgnunetstatistics.la \
42 $(top_builddir)/src/util/libgnunetutil.la
43gnunet_service_peerinfo_LDFLAGS = \
44 $(GN_LIBINTL)
45
46if HAVE_BENCHMARKS
47 PEERINFO_BENCHMARKS = \
48 perf_peerinfo_api
49endif
50
51check_PROGRAMS = \
52 test_peerinfo_shipped_hellos \
53 test_peerinfo_api \
54 test_peerinfo_api_friend_only \
55 test_peerinfo_api_notify_friend_only \
56 $(PEERINFO_BENCHMARKS)
57
58
59if ENABLE_TEST_RUN
60AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
61TESTS = $(check_PROGRAMS)
62endif
63
64test_peerinfo_shipped_hellos_SOURCES = \
65 test_peerinfo_shipped_hellos.c
66test_peerinfo_shipped_hellos_LDADD = \
67 $(top_builddir)/src/hello/libgnunethello.la \
68 libgnunetpeerinfo.la \
69 $(top_builddir)/src/testing/libgnunettesting.la \
70 $(top_builddir)/src/util/libgnunetutil.la
71
72test_peerinfo_api_SOURCES = \
73 test_peerinfo_api.c
74test_peerinfo_api_LDADD = \
75 $(top_builddir)/src/hello/libgnunethello.la \
76 libgnunetpeerinfo.la \
77 $(top_builddir)/src/testing/libgnunettesting.la \
78 $(top_builddir)/src/util/libgnunetutil.la
79
80test_peerinfo_api_friend_only_SOURCES = \
81 test_peerinfo_api_friend_only.c
82test_peerinfo_api_friend_only_LDADD = \
83 $(top_builddir)/src/hello/libgnunethello.la \
84 libgnunetpeerinfo.la \
85 $(top_builddir)/src/testing/libgnunettesting.la \
86 $(top_builddir)/src/util/libgnunetutil.la
87
88test_peerinfo_api_notify_friend_only_SOURCES = \
89 test_peerinfo_api_notify_friend_only.c
90test_peerinfo_api_notify_friend_only_LDADD = \
91 $(top_builddir)/src/hello/libgnunethello.la \
92 libgnunetpeerinfo.la \
93 $(top_builddir)/src/testing/libgnunettesting.la \
94 $(top_builddir)/src/util/libgnunetutil.la
95
96perf_peerinfo_api_SOURCES = \
97 perf_peerinfo_api.c
98perf_peerinfo_api_LDADD = \
99 $(top_builddir)/src/hello/libgnunethello.la \
100 libgnunetpeerinfo.la \
101 $(top_builddir)/src/testing/libgnunettesting.la \
102 $(top_builddir)/src/util/libgnunetutil.la
103
104EXTRA_DIST = \
105 test_peerinfo_api_data.conf
diff --git a/src/peerinfo/gnunet-service-peerinfo.c b/src/peerinfo/gnunet-service-peerinfo.c
deleted file mode 100644
index 1b1232ecb..000000000
--- a/src/peerinfo/gnunet-service-peerinfo.c
+++ /dev/null
@@ -1,1370 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2001-2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file peerinfo/gnunet-service-peerinfo.c
23 * @brief maintains list of known peers
24 *
25 * Code to maintain the list of currently known hosts (in memory
26 * structure of data/hosts/).
27 *
28 * @author Christian Grothoff
29 */
30
31#include "platform.h"
32#include "gnunet_util_lib.h"
33#include "gnunet_hello_lib.h"
34#include "gnunet_protocols.h"
35#include "gnunet_statistics_service.h"
36#include "peerinfo.h"
37
38/**
39 * How often do we scan the HOST_DIR for new entries?
40 */
41#define DATA_HOST_FREQ \
42 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
43
44/**
45 * How often do we discard old entries in data/hosts/?
46 */
47#define DATA_HOST_CLEAN_FREQ \
48 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 60)
49
50
51/**
52 * In-memory cache of known hosts.
53 */
54struct HostEntry
55{
56 /**
57 * Identity of the peer.
58 */
59 struct GNUNET_PeerIdentity identity;
60
61 /**
62 * Hello for the peer (can be NULL)
63 */
64 struct GNUNET_HELLO_Message *hello;
65
66 /**
67 * Friend only hello for the peer (can be NULL)
68 */
69 struct GNUNET_HELLO_Message *friend_only_hello;
70};
71
72
73/**
74 * Result of reading a file
75 */
76struct ReadHostFileContext
77{
78 /**
79 * Hello for the peer (can be NULL)
80 */
81 struct GNUNET_HELLO_Message *hello;
82
83 /**
84 * Friend only hello for the peer (can be NULL)
85 */
86 struct GNUNET_HELLO_Message *friend_only_hello;
87};
88
89
90/**
91 * The in-memory list of known hosts, mapping of
92 * host IDs to 'struct HostEntry*' values.
93 */
94static struct GNUNET_CONTAINER_MultiPeerMap *hostmap;
95
96/**
97 * Clients to immediately notify about all changes.
98 */
99static struct GNUNET_NotificationContext *notify_list;
100
101/**
102 * Clients to immediately notify about all changes,
103 * even for friend-only HELLOs.
104 */
105static struct GNUNET_NotificationContext *notify_friend_only_list;
106
107/**
108 * Directory where the hellos are stored in (peerinfo/)
109 */
110static char *networkIdDirectory;
111
112/**
113 * Handle for reporting statistics.
114 */
115static struct GNUNET_STATISTICS_Handle *stats;
116
117/**
118 * Handle for task to run #cron_clean_data_hosts()
119 */
120static struct GNUNET_SCHEDULER_Task *cron_clean;
121
122/**
123 * Handle for task to run #cron_scan_directory_data_hosts()
124 */
125static struct GNUNET_SCHEDULER_Task *cron_scan;
126
127
128/**
129 * Notify all clients in the notify list about the
130 * given host entry changing.
131 *
132 * @param he entry of the host for which we generate a notification
133 * @param include_friend_only create public of friend-only message
134 * @return generated notification message
135 */
136static struct InfoMessage *
137make_info_message (const struct HostEntry *he, int include_friend_only)
138{
139 struct InfoMessage *im;
140 struct GNUNET_HELLO_Message *src;
141 size_t hs;
142
143 if (GNUNET_YES == include_friend_only)
144 src = he->friend_only_hello;
145 else
146 src = he->hello;
147 hs = (NULL == src) ? 0 : GNUNET_HELLO_size (src);
148 im = GNUNET_malloc (sizeof(struct InfoMessage) + hs);
149 im->header.size = htons (hs + sizeof(struct InfoMessage));
150 im->header.type = htons (GNUNET_MESSAGE_TYPE_PEERINFO_INFO);
151 im->peer = he->identity;
152 GNUNET_memcpy (&im[1], src, hs);
153 return im;
154}
155
156
157/**
158 * Address iterator that causes expired entries to be discarded.
159 *
160 * @param cls pointer to the current time
161 * @param address the address
162 * @param expiration expiration time for the address
163 * @return #GNUNET_NO if expiration smaller than the current time
164 */
165static int
166discard_expired (void *cls,
167 const struct GNUNET_HELLO_Address *address,
168 struct GNUNET_TIME_Absolute expiration)
169{
170 const struct GNUNET_TIME_Absolute *now = cls;
171
172 if (now->abs_value_us > expiration.abs_value_us)
173 {
174 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
175 _ ("Removing expired address of transport `%s'\n"),
176 address->transport_name);
177 return GNUNET_NO;
178 }
179 return GNUNET_OK;
180}
181
182
183/**
184 * Address iterator that counts the remaining addresses.
185 *
186 * @param cls pointer to the counter
187 * @param address the address
188 * @param expiration expiration time for the address
189 * @return #GNUNET_OK (always)
190 */
191static int
192count_addresses (void *cls,
193 const struct GNUNET_HELLO_Address *address,
194 struct GNUNET_TIME_Absolute expiration)
195{
196 unsigned int *cnt = cls;
197
198 (void) address;
199 (void) expiration;
200 (*cnt)++;
201 return GNUNET_OK;
202}
203
204
205/**
206 * Get the filename under which we would store the GNUNET_HELLO_Message
207 * for the given host and protocol.
208 *
209 * @param id peer for which we need the filename for the HELLO
210 * @return filename of the form DIRECTORY/HOSTID
211 */
212static char *
213get_host_filename (const struct GNUNET_PeerIdentity *id)
214{
215 char *fn;
216
217 if (NULL == networkIdDirectory)
218 return NULL;
219 GNUNET_asprintf (&fn,
220 "%s%s%s",
221 networkIdDirectory,
222 DIR_SEPARATOR_STR,
223 GNUNET_i2s_full (id));
224 return fn;
225}
226
227
228/**
229 * Broadcast information about the given entry to all
230 * clients that care.
231 *
232 * @param entry entry to broadcast about
233 */
234static void
235notify_all (struct HostEntry *entry)
236{
237 struct InfoMessage *msg_pub;
238 struct InfoMessage *msg_friend;
239
240 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
241 "Notifying all clients about peer `%s'\n",
242 GNUNET_i2s (&entry->identity));
243 msg_pub = make_info_message (entry, GNUNET_NO);
244 GNUNET_notification_context_broadcast (notify_list,
245 &msg_pub->header,
246 GNUNET_NO);
247 GNUNET_free (msg_pub);
248 msg_friend = make_info_message (entry, GNUNET_YES);
249 GNUNET_notification_context_broadcast (notify_friend_only_list,
250 &msg_friend->header,
251 GNUNET_NO);
252 GNUNET_free (msg_friend);
253}
254
255
256/**
257 * Bind a host address (hello) to a hostId.
258 *
259 * @param peer the peer for which this is a hello
260 * @param hello the verified (!) hello message
261 */
262static void
263update_hello (const struct GNUNET_PeerIdentity *peer,
264 const struct GNUNET_HELLO_Message *hello);
265
266
267/**
268 * Try to read the HELLOs in the given filename and discard expired
269 * addresses. Removes the file if one the HELLO is malformed. If all
270 * addresses are expired, the HELLO is also removed (but the HELLO
271 * with the public key is still returned if it was found and valid).
272 * The file can contain multiple HELLO messages.
273 *
274 * @param fn name of the file
275 * @param unlink_garbage if #GNUNET_YES, try to remove useless files
276 * @param r ReadHostFileContext to store the resutl
277 */
278static void
279read_host_file (const char *fn,
280 int unlink_garbage,
281 struct ReadHostFileContext *r)
282{
283 char buffer[GNUNET_MAX_MESSAGE_SIZE - 1] GNUNET_ALIGN;
284 ssize_t size_total;
285 struct GNUNET_TIME_Absolute now;
286 unsigned int left;
287 const struct GNUNET_HELLO_Message *hello;
288 struct GNUNET_HELLO_Message *hello_clean;
289 size_t read_pos;
290 uint16_t size_hello;
291
292 r->friend_only_hello = NULL;
293 r->hello = NULL;
294
295 if (GNUNET_YES != GNUNET_DISK_file_test (fn))
296 return;
297 size_total = GNUNET_DISK_fn_read (fn, buffer, sizeof(buffer));
298 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
299 "Read %d bytes from `%s'\n",
300 (int) size_total,
301 fn);
302 if ((size_total < 0) ||
303 (((size_t) size_total) < sizeof(struct GNUNET_MessageHeader)))
304 {
305 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
306 _ ("Failed to parse HELLO in file `%s': %s\n"),
307 fn,
308 "File has invalid size");
309 if ((GNUNET_YES == unlink_garbage) && (0 != unlink (fn)) &&
310 (ENOENT != errno))
311 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", fn);
312 return;
313 }
314
315 read_pos = 0;
316 while (read_pos < (size_t) size_total)
317 {
318 hello = (const struct GNUNET_HELLO_Message *) &buffer[read_pos];
319 size_hello = GNUNET_HELLO_size (hello);
320 if ((0 == size_hello) || (((size_t) size_total) - read_pos < size_hello))
321 {
322 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
323 _ ("Failed to parse HELLO in file `%s'\n"),
324 fn);
325 if (0 == read_pos)
326 {
327 if ((GNUNET_YES == unlink_garbage) && (0 != unlink (fn)) &&
328 (ENOENT != errno))
329 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", fn);
330 }
331 else
332 {
333 if ((GNUNET_YES == unlink_garbage) && (0 != truncate (fn, read_pos)) &&
334 (ENOENT != errno))
335 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "truncate", fn);
336 }
337 return;
338 }
339
340 now = GNUNET_TIME_absolute_get ();
341 hello_clean = GNUNET_HELLO_iterate_addresses (hello,
342 GNUNET_YES,
343 &discard_expired,
344 &now);
345 if (NULL == hello_clean)
346 {
347 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
348 _ ("Failed to parse HELLO in file `%s'\n"),
349 fn);
350 if ((GNUNET_YES == unlink_garbage) && (0 != unlink (fn)) &&
351 (ENOENT != errno))
352 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", fn);
353 return;
354 }
355 left = 0;
356 (void) GNUNET_HELLO_iterate_addresses (hello_clean,
357 GNUNET_NO,
358 &count_addresses,
359 &left);
360
361 if (0 == left)
362 {
363 GNUNET_free (hello_clean);
364 break;
365 }
366
367 if (GNUNET_NO == GNUNET_HELLO_is_friend_only (hello_clean))
368 {
369 if (NULL == r->hello)
370 r->hello = hello_clean;
371 else
372 {
373 GNUNET_break (0);
374 GNUNET_free (r->hello);
375 r->hello = hello_clean;
376 }
377 }
378 else
379 {
380 if (NULL == r->friend_only_hello)
381 r->friend_only_hello = hello_clean;
382 else
383 {
384 GNUNET_break (0);
385 GNUNET_free (r->friend_only_hello);
386 r->friend_only_hello = hello_clean;
387 }
388 }
389 read_pos += size_hello;
390 }
391
392 if (0 == left)
393 {
394 /* no addresses left, remove from disk */
395 if ((GNUNET_YES == unlink_garbage) && (0 != unlink (fn)))
396 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", fn);
397 }
398 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
399 "Found `%s' and `%s' HELLO message in file\n",
400 (NULL != r->hello) ? "public" : "NON-public",
401 (NULL != r->friend_only_hello) ? "friend only"
402 : "NO friend only");
403}
404
405
406/**
407 * Add a host to the list and notify clients about this event
408 *
409 * @param identity the identity of the host
410 * @return the HostEntry
411 */
412static struct HostEntry *
413add_host_to_known_hosts (const struct GNUNET_PeerIdentity *identity)
414{
415 struct HostEntry *entry;
416 struct ReadHostFileContext r;
417 char *fn;
418
419 entry = GNUNET_CONTAINER_multipeermap_get (hostmap, identity);
420 if (NULL == entry)
421 {
422 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
423 "Adding new peer `%s'\n",
424 GNUNET_i2s (identity));
425 GNUNET_STATISTICS_update (stats,
426 gettext_noop ("# peers known"),
427 1,
428 GNUNET_NO);
429 entry = GNUNET_new (struct HostEntry);
430 entry->identity = *identity;
431 GNUNET_assert (GNUNET_OK ==
432 GNUNET_CONTAINER_multipeermap_put (
433 hostmap,
434 &entry->identity,
435 entry,
436 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
437 notify_all (entry);
438 fn = get_host_filename (identity);
439 if (NULL != fn)
440 {
441 read_host_file (fn, GNUNET_YES, &r);
442 if (NULL != r.hello)
443 update_hello (identity, r.hello);
444 if (NULL != r.friend_only_hello)
445 update_hello (identity, r.friend_only_hello);
446 GNUNET_free (r.hello);
447 GNUNET_free (r.friend_only_hello);
448 GNUNET_free (fn);
449 }
450 }
451 return entry;
452}
453
454
455/**
456 * Remove a file that should not be there. LOG
457 * success or failure.
458 *
459 * @param fullname name of the file to remove
460 */
461static void
462remove_garbage (const char *fullname)
463{
464 if (0 == unlink (fullname))
465 GNUNET_log (
466 GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
467 _ (
468 "File `%s' in directory `%s' does not match naming convention. Removed.\n"),
469 fullname,
470 networkIdDirectory);
471 else
472 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
473 "unlink",
474 fullname);
475}
476
477
478/**
479 * Closure for #hosts_directory_scan_callback().
480 */
481struct DirScanContext
482{
483 /**
484 * #GNUNET_YES if we should remove files that are broken,
485 * #GNUNET_NO if the directory we are iterating over should
486 * be treated as read-only by us.
487 */
488 int remove_files;
489
490 /**
491 * Counter for the number of (valid) entries found, incremented
492 * by one for each match.
493 */
494 unsigned int matched;
495};
496
497
498/**
499 * Function that is called on each HELLO file in a particular directory.
500 * Try to parse the file and add the HELLO to our list.
501 *
502 * @param cls pointer to 'unsigned int' to increment for each file, or NULL
503 * if the file is from a read-only, read-once resource directory
504 * @param fullname name of the file to parse
505 * @return #GNUNET_OK (continue iteration)
506 */
507static int
508hosts_directory_scan_callback (void *cls, const char *fullname)
509{
510 struct DirScanContext *dsc = cls;
511 struct GNUNET_PeerIdentity identity;
512 struct ReadHostFileContext r;
513 const char *filename;
514 struct GNUNET_PeerIdentity id_public;
515 struct GNUNET_PeerIdentity id_friend;
516 struct GNUNET_PeerIdentity id;
517
518 if (GNUNET_YES != GNUNET_DISK_file_test (fullname))
519 return GNUNET_OK; /* ignore non-files */
520
521 filename = strrchr (fullname, DIR_SEPARATOR);
522 if ((NULL == filename) || (1 > strlen (filename)))
523 filename = fullname;
524 else
525 filename++;
526
527 read_host_file (fullname, dsc->remove_files, &r);
528 if ((NULL == r.hello) && (NULL == r.friend_only_hello))
529 return GNUNET_OK;
530 if (NULL != r.friend_only_hello)
531 {
532 if (GNUNET_OK != GNUNET_HELLO_get_id (r.friend_only_hello, &id_friend))
533 {
534 if (GNUNET_YES == dsc->remove_files)
535 remove_garbage (fullname);
536 return GNUNET_OK;
537 }
538 id = id_friend;
539 }
540 if (NULL != r.hello)
541 {
542 if (GNUNET_OK != GNUNET_HELLO_get_id (r.hello, &id_public))
543 {
544 if (GNUNET_YES == dsc->remove_files)
545 remove_garbage (fullname);
546 return GNUNET_OK;
547 }
548 id = id_public;
549 }
550
551 if ((NULL != r.hello) && (NULL != r.friend_only_hello) &&
552 (0 != GNUNET_memcmp (&id_friend, &id_public)))
553 {
554 /* HELLOs are not for the same peer */
555 GNUNET_break (0);
556 if (GNUNET_YES == dsc->remove_files)
557 remove_garbage (fullname);
558 return GNUNET_OK;
559 }
560 if (GNUNET_OK ==
561 GNUNET_CRYPTO_eddsa_public_key_from_string (filename,
562 strlen (filename),
563 &identity.public_key))
564 {
565 if (0 != GNUNET_memcmp (&id, &identity))
566 {
567 /* HELLOs are not for the same peer */
568 GNUNET_break (0);
569 if (GNUNET_YES == dsc->remove_files)
570 remove_garbage (fullname);
571 return GNUNET_OK;
572 }
573 }
574
575 /* ok, found something valid, remember HELLO */
576 add_host_to_known_hosts (&id);
577 if (NULL != r.hello)
578 {
579 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
580 "Updating peer `%s' public HELLO \n",
581 GNUNET_i2s (&id));
582 update_hello (&id, r.hello);
583 GNUNET_free (r.hello);
584 }
585 if (NULL != r.friend_only_hello)
586 {
587 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
588 "Updating peer `%s' friend only HELLO \n",
589 GNUNET_i2s (&id));
590 update_hello (&id, r.friend_only_hello);
591 GNUNET_free (r.friend_only_hello);
592 }
593 dsc->matched++;
594 return GNUNET_OK;
595}
596
597
598/**
599 * Call this method periodically to scan data/hosts for new hosts.
600 *
601 * @param cls unused
602 */
603static void
604cron_scan_directory_data_hosts (void *cls)
605{
606 static unsigned int retries;
607 struct DirScanContext dsc;
608
609 (void) cls;
610 cron_scan = NULL;
611 if (GNUNET_SYSERR == GNUNET_DISK_directory_create (networkIdDirectory))
612 {
613 cron_scan =
614 GNUNET_SCHEDULER_add_delayed_with_priority (DATA_HOST_FREQ,
615 GNUNET_SCHEDULER_PRIORITY_IDLE,
616 &
617 cron_scan_directory_data_hosts,
618 NULL);
619 return;
620 }
621 dsc.matched = 0;
622 dsc.remove_files = GNUNET_YES;
623 GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
624 _ ("Scanning directory `%s'\n"),
625 networkIdDirectory);
626 GNUNET_DISK_directory_scan (networkIdDirectory,
627 &hosts_directory_scan_callback,
628 &dsc);
629 if ((0 == dsc.matched) && (0 == (++retries & 31)))
630 GNUNET_log (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
631 _ ("Still no peers found in `%s'!\n"),
632 networkIdDirectory);
633 cron_scan =
634 GNUNET_SCHEDULER_add_delayed_with_priority (DATA_HOST_FREQ,
635 GNUNET_SCHEDULER_PRIORITY_IDLE,
636 &cron_scan_directory_data_hosts,
637 NULL);
638}
639
640
641/**
642 * Update the HELLO of a friend by merging the addresses.
643 *
644 * @param hello original hello
645 * @param friend_hello hello with additional addresses
646 * @return merged HELLO
647 */
648static struct GNUNET_HELLO_Message *
649update_friend_hello (const struct GNUNET_HELLO_Message *hello,
650 const struct GNUNET_HELLO_Message *friend_hello)
651{
652 struct GNUNET_HELLO_Message *res;
653 struct GNUNET_HELLO_Message *tmp;
654 struct GNUNET_PeerIdentity pid;
655
656 if (NULL != friend_hello)
657 {
658 res = GNUNET_HELLO_merge (hello, friend_hello);
659 GNUNET_assert (GNUNET_YES == GNUNET_HELLO_is_friend_only (res));
660 return res;
661 }
662
663 if (GNUNET_OK != GNUNET_HELLO_get_id (hello, &pid))
664 {
665 GNUNET_break (0);
666 return NULL;
667 }
668 tmp = GNUNET_HELLO_create (&pid.public_key, NULL, NULL, GNUNET_YES);
669 res = GNUNET_HELLO_merge (hello, tmp);
670 GNUNET_free (tmp);
671 GNUNET_assert (GNUNET_YES == GNUNET_HELLO_is_friend_only (res));
672 return res;
673}
674
675
676/**
677 * Bind a host address (hello) to a hostId.
678 *
679 * @param peer the peer for which this is a hello
680 * @param hello the verified (!) hello message
681 */
682static void
683update_hello (const struct GNUNET_PeerIdentity *peer,
684 const struct GNUNET_HELLO_Message *hello)
685{
686 char *fn;
687 struct HostEntry *host;
688 struct GNUNET_HELLO_Message *mrg;
689 struct GNUNET_HELLO_Message **dest;
690 struct GNUNET_TIME_Absolute delta;
691 unsigned int cnt;
692 unsigned int size;
693 int friend_hello_type;
694 int store_hello;
695 int store_friend_hello;
696 unsigned int pos;
697 char *buffer;
698
699 host = GNUNET_CONTAINER_multipeermap_get (hostmap, peer);
700 GNUNET_assert (NULL != host);
701
702 friend_hello_type = GNUNET_HELLO_is_friend_only (hello);
703 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
704 "Updating %s HELLO for `%s'\n",
705 (GNUNET_YES == friend_hello_type) ? "friend-only" : "public",
706 GNUNET_i2s (peer));
707
708 dest = NULL;
709 if (GNUNET_YES == friend_hello_type)
710 {
711 dest = &host->friend_only_hello;
712 }
713 else
714 {
715 dest = &host->hello;
716 }
717
718 if (NULL == (*dest))
719 {
720 (*dest) = GNUNET_malloc (GNUNET_HELLO_size (hello));
721 GNUNET_memcpy ((*dest), hello, GNUNET_HELLO_size (hello));
722 }
723 else
724 {
725 mrg = GNUNET_HELLO_merge ((*dest), hello);
726 delta = GNUNET_HELLO_equals (mrg, (*dest), GNUNET_TIME_absolute_get ());
727 if (delta.abs_value_us == GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us)
728 {
729 /* no differences, just ignore the update */
730 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
731 "No change in %s HELLO for `%s'\n",
732 (GNUNET_YES == friend_hello_type) ? "friend-only" : "public",
733 GNUNET_i2s (peer));
734 GNUNET_free (mrg);
735 return;
736 }
737 GNUNET_free ((*dest));
738 (*dest) = mrg;
739 }
740
741 if ((NULL != (host->hello)) && (GNUNET_NO == friend_hello_type))
742 {
743 /* Update friend only hello */
744 mrg = update_friend_hello (host->hello, host->friend_only_hello);
745 if (NULL != host->friend_only_hello)
746 GNUNET_free (host->friend_only_hello);
747 host->friend_only_hello = mrg;
748 }
749
750 if (NULL != host->hello)
751 GNUNET_assert ((GNUNET_NO == GNUNET_HELLO_is_friend_only (host->hello)));
752 if (NULL != host->friend_only_hello)
753 GNUNET_assert (
754 (GNUNET_YES == GNUNET_HELLO_is_friend_only (host->friend_only_hello)));
755
756 fn = get_host_filename (peer);
757 if ((NULL != fn) && (GNUNET_OK == GNUNET_DISK_directory_create_for_file (fn)))
758 {
759 store_hello = GNUNET_NO;
760 size = 0;
761 cnt = 0;
762 if (NULL != host->hello)
763 (void) GNUNET_HELLO_iterate_addresses (host->hello,
764 GNUNET_NO,
765 &count_addresses,
766 &cnt);
767 if (cnt > 0)
768 {
769 store_hello = GNUNET_YES;
770 size += GNUNET_HELLO_size (host->hello);
771 }
772 cnt = 0;
773 if (NULL != host->friend_only_hello)
774 (void) GNUNET_HELLO_iterate_addresses (host->friend_only_hello,
775 GNUNET_NO,
776 &count_addresses,
777 &cnt);
778 store_friend_hello = GNUNET_NO;
779 if (0 < cnt)
780 {
781 store_friend_hello = GNUNET_YES;
782 size += GNUNET_HELLO_size (host->friend_only_hello);
783 }
784
785 if ((GNUNET_NO == store_hello) && (GNUNET_NO == store_friend_hello))
786 {
787 /* no valid addresses, don't put HELLO on disk; in fact,
788 if one exists on disk, remove it */
789 (void) unlink (fn);
790 }
791 else
792 {
793 buffer = GNUNET_malloc (size);
794 pos = 0;
795
796 if (GNUNET_YES == store_hello)
797 {
798 GNUNET_memcpy (buffer, host->hello, GNUNET_HELLO_size (host->hello));
799 pos += GNUNET_HELLO_size (host->hello);
800 }
801 if (GNUNET_YES == store_friend_hello)
802 {
803 GNUNET_memcpy (&buffer[pos],
804 host->friend_only_hello,
805 GNUNET_HELLO_size (host->friend_only_hello));
806 pos += GNUNET_HELLO_size (host->friend_only_hello);
807 }
808 GNUNET_assert (pos == size);
809
810 if (GNUNET_SYSERR ==
811 GNUNET_DISK_fn_write (fn,
812 buffer,
813 size,
814 GNUNET_DISK_PERM_USER_READ
815 | GNUNET_DISK_PERM_USER_WRITE
816 | GNUNET_DISK_PERM_GROUP_READ
817 | GNUNET_DISK_PERM_OTHER_READ))
818 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "write", fn);
819 else
820 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
821 "Stored %s %s HELLO in %s with total size %u\n",
822 (GNUNET_YES == store_friend_hello) ? "friend-only" : "",
823 (GNUNET_YES == store_hello) ? "public" : "",
824 fn,
825 size);
826 GNUNET_free (buffer);
827 }
828 }
829 GNUNET_free (fn);
830 notify_all (host);
831}
832
833
834/**
835 * Closure for #add_to_tc()
836 */
837struct TransmitContext
838{
839 /**
840 * Client to transmit to
841 */
842 struct GNUNET_SERVICE_Client *client;
843
844 /**
845 * Include friend only HELLOs #GNUNET_YES or #GNUNET_NO
846 */
847 int friend_only;
848};
849
850
851/**
852 * Do transmit info about peer to given host.
853 *
854 * @param cls NULL to hit all hosts, otherwise specifies a particular target
855 * @param key hostID
856 * @param value information to transmit
857 * @return #GNUNET_YES (continue to iterate)
858 */
859static int
860add_to_tc (void *cls, const struct GNUNET_PeerIdentity *key, void *value)
861{
862 struct TransmitContext *tc = cls;
863 struct HostEntry *pos = value;
864 struct InfoMessage *im;
865 uint16_t hs;
866 struct GNUNET_MQ_Envelope *env;
867
868 hs = 0;
869
870 if ((NULL != pos->hello) && (GNUNET_NO == tc->friend_only))
871 {
872 /* Copy public HELLO */
873 hs = GNUNET_HELLO_size (pos->hello);
874 GNUNET_assert (hs < GNUNET_MAX_MESSAGE_SIZE - sizeof(struct InfoMessage));
875 env = GNUNET_MQ_msg_extra (im, hs, GNUNET_MESSAGE_TYPE_PEERINFO_INFO);
876 GNUNET_memcpy (&im[1], pos->hello, hs);
877 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
878 "Sending public HELLO with size %u for peer `%s'\n",
879 hs,
880 GNUNET_i2s (key));
881 }
882 else if ((NULL != pos->friend_only_hello) && (GNUNET_YES == tc->friend_only))
883 {
884 /* Copy friend only HELLO */
885 hs = GNUNET_HELLO_size (pos->friend_only_hello);
886 GNUNET_assert (hs < GNUNET_MAX_MESSAGE_SIZE - sizeof(struct InfoMessage));
887 env = GNUNET_MQ_msg_extra (im, hs, GNUNET_MESSAGE_TYPE_PEERINFO_INFO);
888 GNUNET_memcpy (&im[1], pos->friend_only_hello, hs);
889 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
890 "Sending friend-only HELLO with size %u for peer `%s'\n",
891 hs,
892 GNUNET_i2s (key));
893 }
894 else
895 {
896 env = GNUNET_MQ_msg (im, GNUNET_MESSAGE_TYPE_PEERINFO_INFO);
897 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
898 "Adding no HELLO for peer `%s'\n",
899 GNUNET_i2s (key));
900 }
901 im->peer = pos->identity;
902 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (tc->client), env);
903 return GNUNET_YES;
904}
905
906
907/**
908 * @brief delete expired HELLO entries in directory
909 *
910 * @param cls pointer to current time (`struct GNUNET_TIME_Absolute *`)
911 * @param fn filename to test to see if the HELLO expired
912 * @return #GNUNET_OK (continue iteration)
913 */
914static int
915discard_hosts_helper (void *cls, const char *fn)
916{
917 struct GNUNET_TIME_Absolute *now = cls;
918 char buffer[GNUNET_MAX_MESSAGE_SIZE - 1] GNUNET_ALIGN;
919 const struct GNUNET_HELLO_Message *hello;
920 struct GNUNET_HELLO_Message *new_hello;
921 int read_size;
922 unsigned int cur_hello_size;
923 unsigned int new_hello_size;
924 int read_pos;
925 int write_pos;
926 unsigned int cnt;
927 char *writebuffer;
928 uint64_t fsize;
929
930 if (GNUNET_OK != GNUNET_DISK_file_size (fn, &fsize, GNUNET_YES, GNUNET_YES))
931 {
932 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING
933 | GNUNET_ERROR_TYPE_BULK,
934 "fstat",
935 fn);
936 return GNUNET_OK;
937 }
938 read_size = GNUNET_DISK_fn_read (fn, buffer, sizeof(buffer));
939
940 if ((read_size < (int) sizeof(struct GNUNET_MessageHeader)) ||
941 (fsize > GNUNET_MAX_MESSAGE_SIZE))
942 {
943 if (0 != unlink (fn))
944 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING
945 | GNUNET_ERROR_TYPE_BULK,
946 "unlink",
947 fn);
948 return GNUNET_OK;
949 }
950
951 writebuffer = GNUNET_malloc (read_size);
952 read_pos = 0;
953 write_pos = 0;
954 while (read_pos < read_size)
955 {
956 /* Check each HELLO */
957 hello = (const struct GNUNET_HELLO_Message *) &buffer[read_pos];
958 cur_hello_size = GNUNET_HELLO_size (hello);
959 if (0 == cur_hello_size)
960 {
961 /* Invalid data, discard */
962 if (0 != unlink (fn))
963 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING
964 | GNUNET_ERROR_TYPE_BULK,
965 "unlink",
966 fn);
967 GNUNET_free (writebuffer);
968 return GNUNET_OK;
969 }
970 new_hello =
971 GNUNET_HELLO_iterate_addresses (hello, GNUNET_YES, &discard_expired, now);
972 cnt = 0;
973 if (NULL != new_hello)
974 (void) GNUNET_HELLO_iterate_addresses (hello,
975 GNUNET_NO,
976 &count_addresses,
977 &cnt);
978 if ((NULL != new_hello) && (0 < cnt))
979 {
980 /* Store new HELLO to write it when done */
981 new_hello_size = GNUNET_HELLO_size (new_hello);
982 GNUNET_memcpy (&writebuffer[write_pos], new_hello, new_hello_size);
983 write_pos += new_hello_size;
984 }
985 read_pos += cur_hello_size;
986 GNUNET_free (new_hello);
987 }
988
989 if (0 < write_pos)
990 {
991 (void) GNUNET_DISK_directory_remove (fn);
992 GNUNET_assert (GNUNET_OK ==
993 GNUNET_DISK_fn_write (fn,
994 writebuffer,
995 write_pos,
996 GNUNET_DISK_PERM_USER_READ
997 | GNUNET_DISK_PERM_USER_WRITE
998 | GNUNET_DISK_PERM_GROUP_READ
999 | GNUNET_DISK_PERM_OTHER_READ));
1000 }
1001 else if (0 != unlink (fn))
1002 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING
1003 | GNUNET_ERROR_TYPE_BULK,
1004 "unlink",
1005 fn);
1006
1007 GNUNET_free (writebuffer);
1008 return GNUNET_OK;
1009}
1010
1011
1012/**
1013 * Call this method periodically to scan peerinfo/ for ancient
1014 * HELLOs to expire.
1015 *
1016 * @param cls unused
1017 */
1018static void
1019cron_clean_data_hosts (void *cls)
1020{
1021 struct GNUNET_TIME_Absolute now;
1022
1023 (void) cls;
1024 cron_clean = NULL;
1025 now = GNUNET_TIME_absolute_get ();
1026 GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
1027 _ ("Cleaning up directory `%s'\n"),
1028 networkIdDirectory);
1029 GNUNET_DISK_directory_scan (networkIdDirectory, &discard_hosts_helper, &now);
1030 cron_clean = GNUNET_SCHEDULER_add_delayed (DATA_HOST_CLEAN_FREQ,
1031 &cron_clean_data_hosts,
1032 NULL);
1033}
1034
1035
1036/**
1037 * Check HELLO-message.
1038 *
1039 * @param cls identification of the client
1040 * @param hello the actual message
1041 * @return #GNUNET_OK if @a hello is well-formed
1042 */
1043static int
1044check_hello (void *cls, const struct GNUNET_HELLO_Message *hello)
1045{
1046 struct GNUNET_PeerIdentity pid;
1047
1048 (void) cls;
1049 if (GNUNET_OK != GNUNET_HELLO_get_id (hello, &pid))
1050 {
1051 GNUNET_break (0);
1052 return GNUNET_SYSERR;
1053 }
1054 return GNUNET_OK;
1055}
1056
1057
1058/**
1059 * Handle HELLO-message.
1060 *
1061 * @param cls identification of the client
1062 * @param hello the actual message
1063 */
1064static void
1065handle_hello (void *cls, const struct GNUNET_HELLO_Message *hello)
1066{
1067 struct GNUNET_SERVICE_Client *client = cls;
1068 struct GNUNET_PeerIdentity pid;
1069
1070 GNUNET_assert (GNUNET_OK == GNUNET_HELLO_get_id (hello, &pid));
1071 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1072 "HELLO message received for peer `%s'\n",
1073 GNUNET_i2s (&pid));
1074 add_host_to_known_hosts (&pid);
1075 update_hello (&pid, hello);
1076 GNUNET_SERVICE_client_continue (client);
1077}
1078
1079
1080/**
1081 * Handle GET-message.
1082 *
1083 * @param cls identification of the client
1084 * @param lpm the actual message
1085 */
1086static void
1087handle_get (void *cls, const struct ListPeerMessage *lpm)
1088{
1089 struct GNUNET_SERVICE_Client *client = cls;
1090 struct TransmitContext tcx;
1091 struct GNUNET_MessageHeader *msg;
1092 struct GNUNET_MQ_Envelope *env;
1093
1094 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1095 "GET message received for peer `%s'\n",
1096 GNUNET_i2s (&lpm->peer));
1097 tcx.friend_only = ntohl (lpm->include_friend_only);
1098 tcx.client = client;
1099 GNUNET_CONTAINER_multipeermap_get_multiple (hostmap,
1100 &lpm->peer,
1101 &add_to_tc,
1102 &tcx);
1103 env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_PEERINFO_INFO_END);
1104 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), env);
1105 GNUNET_SERVICE_client_continue (client);
1106}
1107
1108
1109/**
1110 * Handle GET-ALL-message.
1111 *
1112 * @param cls identification of the client
1113 * @param lapm the actual message
1114 */
1115static void
1116handle_get_all (void *cls, const struct ListAllPeersMessage *lapm)
1117{
1118 struct GNUNET_SERVICE_Client *client = cls;
1119 struct TransmitContext tcx;
1120 struct GNUNET_MQ_Envelope *env;
1121 struct GNUNET_MessageHeader *msg;
1122
1123 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GET_ALL message received\n");
1124 tcx.friend_only = ntohl (lapm->include_friend_only);
1125 tcx.client = client;
1126 GNUNET_CONTAINER_multipeermap_iterate (hostmap, &add_to_tc, &tcx);
1127 env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_PEERINFO_INFO_END);
1128 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), env);
1129 GNUNET_SERVICE_client_continue (client);
1130}
1131
1132
1133/**
1134 * Handle NOTIFY-message.
1135 *
1136 * @param cls identification of the client
1137 * @param nm the actual message
1138 */
1139static void
1140handle_notify (void *cls, const struct NotifyMessage *nm)
1141{
1142 struct GNUNET_SERVICE_Client *client = cls;
1143 struct GNUNET_MQ_Handle *mq;
1144 struct TransmitContext tcx;
1145 struct GNUNET_MQ_Envelope *env;
1146 struct GNUNET_MessageHeader *msg;
1147
1148 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "NOTIFY message received\n");
1149 mq = GNUNET_SERVICE_client_get_mq (client);
1150 GNUNET_SERVICE_client_mark_monitor (client);
1151 if (ntohl (nm->include_friend_only))
1152 GNUNET_notification_context_add (notify_friend_only_list, mq);
1153 else
1154 GNUNET_notification_context_add (notify_list, mq);
1155 tcx.friend_only = ntohl (nm->include_friend_only);
1156 tcx.client = client;
1157 GNUNET_CONTAINER_multipeermap_iterate (hostmap, &add_to_tc, &tcx);
1158 env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_PEERINFO_INFO_END);
1159 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), env);
1160 GNUNET_SERVICE_client_continue (client);
1161}
1162
1163
1164/**
1165 * Client connect callback
1166 *
1167 * @param cls unused
1168 * @param client server client
1169 * @param mq for @a client
1170 * @return @a client
1171 */
1172static void *
1173client_connect_cb (void *cls,
1174 struct GNUNET_SERVICE_Client *client,
1175 struct GNUNET_MQ_Handle *mq)
1176{
1177 (void) cls;
1178 (void) mq;
1179 return client;
1180}
1181
1182
1183/**
1184 * Client disconnect callback
1185 *
1186 * @param cls unused
1187 * @param client server client
1188 * @param app_ctx should be @a client
1189 */
1190static void
1191client_disconnect_cb (void *cls,
1192 struct GNUNET_SERVICE_Client *client,
1193 void *app_ctx)
1194{
1195 (void) cls;
1196 GNUNET_assert (app_ctx == client);
1197}
1198
1199
1200/**
1201 * Release memory taken by a host entry.
1202 *
1203 * @param cls NULL
1204 * @param key key of the host entry
1205 * @param value the `struct HostEntry` to free
1206 * @return #GNUNET_YES (continue to iterate)
1207 */
1208static int
1209free_host_entry (void *cls, const struct GNUNET_PeerIdentity *key, void *value)
1210{
1211 struct HostEntry *he = value;
1212
1213 (void) cls;
1214 (void) key;
1215 GNUNET_free (he->hello);
1216 GNUNET_free (he->friend_only_hello);
1217 GNUNET_free (he);
1218 return GNUNET_YES;
1219}
1220
1221
1222/**
1223 * Clean up our state. Called during shutdown.
1224 *
1225 * @param cls unused
1226 */
1227static void
1228shutdown_task (void *cls)
1229{
1230 (void) cls;
1231 GNUNET_notification_context_destroy (notify_list);
1232 notify_list = NULL;
1233 GNUNET_notification_context_destroy (notify_friend_only_list);
1234 notify_friend_only_list = NULL;
1235
1236 GNUNET_CONTAINER_multipeermap_iterate (hostmap, &free_host_entry, NULL);
1237 GNUNET_CONTAINER_multipeermap_destroy (hostmap);
1238 if (NULL != stats)
1239 {
1240 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
1241 stats = NULL;
1242 }
1243 if (NULL != cron_clean)
1244 {
1245 GNUNET_SCHEDULER_cancel (cron_clean);
1246 cron_clean = NULL;
1247 }
1248 if (NULL != cron_scan)
1249 {
1250 GNUNET_SCHEDULER_cancel (cron_scan);
1251 cron_scan = NULL;
1252 }
1253 if (NULL != networkIdDirectory)
1254 {
1255 GNUNET_free (networkIdDirectory);
1256 networkIdDirectory = NULL;
1257 }
1258}
1259
1260
1261/**
1262 * Start up peerinfo service.
1263 *
1264 * @param cls closure
1265 * @param cfg configuration to use
1266 * @param service the initialized service
1267 */
1268static void
1269run (void *cls,
1270 const struct GNUNET_CONFIGURATION_Handle *cfg,
1271 struct GNUNET_SERVICE_Handle *service)
1272{
1273 char *peerdir;
1274 char *ip;
1275 struct DirScanContext dsc;
1276 int noio;
1277 int use_included;
1278
1279 (void) cls;
1280 (void) service;
1281 hostmap = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
1282 stats = GNUNET_STATISTICS_create ("peerinfo", cfg);
1283 notify_list = GNUNET_notification_context_create (0);
1284 notify_friend_only_list = GNUNET_notification_context_create (0);
1285 noio = GNUNET_CONFIGURATION_get_value_yesno (cfg, "peerinfo", "NO_IO");
1286 use_included = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1287 "peerinfo",
1288 "USE_INCLUDED_HELLOS");
1289 if (GNUNET_SYSERR == use_included)
1290 use_included = GNUNET_NO;
1291 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
1292 if (GNUNET_YES != noio)
1293 {
1294 GNUNET_assert (
1295 GNUNET_OK ==
1296 GNUNET_CONFIGURATION_get_value_filename (cfg,
1297 "peerinfo",
1298 "HOSTS",
1299 &networkIdDirectory));
1300 if (GNUNET_OK != GNUNET_DISK_directory_create (networkIdDirectory))
1301 {
1302 GNUNET_SCHEDULER_shutdown ();
1303 return;
1304 }
1305
1306 cron_scan =
1307 GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE,
1308 &cron_scan_directory_data_hosts,
1309 NULL);
1310
1311 cron_clean =
1312 GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE,
1313 &cron_clean_data_hosts,
1314 NULL);
1315 if (GNUNET_YES == use_included)
1316 {
1317 ip = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
1318 GNUNET_asprintf (&peerdir, "%shellos", ip);
1319 GNUNET_free (ip);
1320
1321 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1322 _ ("Importing HELLOs from `%s'\n"),
1323 peerdir);
1324 dsc.matched = 0;
1325 dsc.remove_files = GNUNET_NO;
1326
1327 GNUNET_DISK_directory_scan (peerdir,
1328 &hosts_directory_scan_callback,
1329 &dsc);
1330 GNUNET_free (peerdir);
1331 }
1332 else
1333 {
1334 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1335 _ ("Skipping import of included HELLOs\n"));
1336 }
1337 }
1338}
1339
1340
1341/**
1342 * Define "main" method using service macro.
1343 */
1344GNUNET_SERVICE_MAIN (
1345 "peerinfo",
1346 GNUNET_SERVICE_OPTION_NONE,
1347 &run,
1348 &client_connect_cb,
1349 &client_disconnect_cb,
1350 NULL,
1351 GNUNET_MQ_hd_var_size (hello,
1352 GNUNET_MESSAGE_TYPE_HELLO,
1353 struct GNUNET_HELLO_Message,
1354 NULL),
1355 GNUNET_MQ_hd_fixed_size (get,
1356 GNUNET_MESSAGE_TYPE_PEERINFO_GET,
1357 struct ListPeerMessage,
1358 NULL),
1359 GNUNET_MQ_hd_fixed_size (get_all,
1360 GNUNET_MESSAGE_TYPE_PEERINFO_GET_ALL,
1361 struct ListAllPeersMessage,
1362 NULL),
1363 GNUNET_MQ_hd_fixed_size (notify,
1364 GNUNET_MESSAGE_TYPE_PEERINFO_NOTIFY,
1365 struct NotifyMessage,
1366 NULL),
1367 GNUNET_MQ_handler_end ());
1368
1369
1370/* end of gnunet-service-peerinfo.c */
diff --git a/src/peerinfo/meson.build b/src/peerinfo/meson.build
deleted file mode 100644
index ea9aaa331..000000000
--- a/src/peerinfo/meson.build
+++ /dev/null
@@ -1,41 +0,0 @@
1libgnunetpeerinfo_src = ['peerinfo_api.c',
2 'peerinfo_api_notify.c']
3
4gnunetservicepeerinfo_src = ['gnunet-service-peerinfo.c']
5
6configure_file(input : 'peerinfo.conf.in',
7 output : 'peerinfo.conf',
8 configuration : cdata,
9 install: true,
10 install_dir: pkgcfgdir)
11
12
13if get_option('monolith')
14 foreach p : libgnunetpeerinfo_src + gnunetservicepeerinfo_src
15 gnunet_src += 'peerinfo/' + p
16 endforeach
17 subdir_done()
18endif
19
20libgnunetpeerinfo = library('gnunetpeerinfo',
21 libgnunetpeerinfo_src,
22 soversion: '0',
23 version: '0.0.0',
24 dependencies: [libgnunetutil_dep, libgnunethello_dep],
25 include_directories: [incdir, configuration_inc],
26 install: true,
27 install_dir: get_option('libdir'))
28libgnunetpeerinfo_dep = declare_dependency(link_with : libgnunetpeerinfo)
29pkg.generate(libgnunetpeerinfo, url: 'https://www.gnunet.org',
30 description : 'Provides API for accessing the peerinfo service')
31
32executable ('gnunet-service-peerinfo',
33 gnunetservicepeerinfo_src,
34 dependencies: [libgnunetpeerinfo_dep,
35 libgnunetutil_dep,
36 libgnunetstatistics_dep,
37 libgnunethello_dep],
38 include_directories: [incdir, configuration_inc],
39 install: true,
40 install_dir: get_option('libdir') / 'gnunet' / 'libexec')
41
diff --git a/src/peerinfo/peerinfo.conf.in b/src/peerinfo/peerinfo.conf.in
deleted file mode 100644
index 14a41655b..000000000
--- a/src/peerinfo/peerinfo.conf.in
+++ /dev/null
@@ -1,31 +0,0 @@
1[peerinfo]
2START_ON_DEMAND = @START_ON_DEMAND@
3@JAVAPORT@PORT = 2090
4HOSTNAME = localhost
5BINARY = gnunet-service-peerinfo
6ACCEPT_FROM = 127.0.0.1;
7ACCEPT_FROM6 = ::1;
8UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-peerinfo.sock
9UNIX_MATCH_UID = NO
10UNIX_MATCH_GID = YES
11# DISABLE_SOCKET_FORWARDING = NO
12# USERNAME =
13# MAXBUF =
14# TIMEOUT =
15# DISABLEV6 =
16# BINDTO =
17# REJECT_FROM =
18# REJECT_FROM6 =
19# PREFIX =
20HOSTS = $GNUNET_DATA_HOME/peerinfo/hosts/
21
22# Option to disable all disk IO; only useful for testbed runs
23# (large-scale experiments); disables persistence of HELLOs!
24NO_IO = NO
25
26# Load HELLOs shipped with GNUnet
27USE_INCLUDED_HELLOS = YES
28
29[uri]
30hello = gnunet-peerinfo
31friend-hello = gnunet-peerinfo
diff --git a/src/peerinfo/peerinfo.h b/src/peerinfo/peerinfo.h
deleted file mode 100644
index 9968733f0..000000000
--- a/src/peerinfo/peerinfo.h
+++ /dev/null
@@ -1,122 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file peerinfo/peerinfo.h
23 * @brief common internal definitions for peerinfo service
24 * @author Christian Grothoff
25 */
26
27#ifndef PEERINFO_H
28#define PEERINFO_H
29
30#include "gnunet_util_lib.h"
31#include "gnunet_peerinfo_service.h"
32#include "gnunet_time_lib.h"
33
34GNUNET_NETWORK_STRUCT_BEGIN
35
36/**
37 * Message requesting a listing of peers,
38 * restricted to the specified peer identity.
39 */
40struct ListPeerMessage
41{
42 /**
43 * Type will be GNUNET_MESSAGE_TYPE_PEERINFO_GET
44 */
45 struct GNUNET_MessageHeader header;
46
47 /**
48 * Include friend only HELLOs and peers in callbacks
49 */
50 uint32_t include_friend_only GNUNET_PACKED;
51
52 /**
53 * Restrict to peers with this identity (optional
54 * field, check header.size!).
55 */
56 struct GNUNET_PeerIdentity peer;
57};
58
59/**
60 * Message requesting a listing of all peers,
61 * restricted to the specified peer identity.
62 */
63struct ListAllPeersMessage
64{
65 /**
66 * Type will be GNUNET_MESSAGE_TYPE_PEERINFO_GET_ALL
67 */
68 struct GNUNET_MessageHeader header;
69
70 /**
71 * Include friend only HELLOs and peers in callbacks
72 */
73 uint32_t include_friend_only GNUNET_PACKED;
74};
75
76
77/**
78 * Header for all communications.
79 */
80struct NotifyMessage
81{
82 /**
83 * Type will be GNUNET_MESSAGE_TYPE_PEERINFO_NOTIFY
84 */
85 struct GNUNET_MessageHeader header;
86
87 /**
88 * Include friend only HELLOs and peers in callbacks
89 */
90 uint32_t include_friend_only GNUNET_PACKED;
91};
92
93
94/**
95 * Message used to inform the client about
96 * a particular peer; this message is optionally followed
97 * by a HELLO message for the respective peer (if available).
98 * Check the header.size field to see if a HELLO is
99 * present.
100 */
101struct InfoMessage
102{
103 /**
104 * Type will be GNUNET_MESSAGE_TYPE_PEERINFO_INFO
105 */
106 struct GNUNET_MessageHeader header;
107
108 /**
109 * Always zero.
110 */
111 uint32_t reserved GNUNET_PACKED;
112
113 /**
114 * About which peer are we talking here?
115 */
116 struct GNUNET_PeerIdentity peer;
117};
118GNUNET_NETWORK_STRUCT_END
119
120/*#ifndef PEERINFO_H*/
121#endif
122/* end of peerinfo.h */
diff --git a/src/peerinfo/peerinfo_api.c b/src/peerinfo/peerinfo_api.c
deleted file mode 100644
index 65e429bef..000000000
--- a/src/peerinfo/peerinfo_api.c
+++ /dev/null
@@ -1,557 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2001-2014 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file peerinfo/peerinfo_api.c
23 * @brief API to access peerinfo service
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_protocols.h"
29#include "peerinfo.h"
30
31#define LOG(kind, ...) GNUNET_log_from (kind, "peerinfo-api", __VA_ARGS__)
32
33
34/**
35 * Context for an iteration request.
36 */
37struct GNUNET_PEERINFO_IteratorContext
38{
39 /**
40 * Kept in a DLL.
41 */
42 struct GNUNET_PEERINFO_IteratorContext *next;
43
44 /**
45 * Kept in a DLL.
46 */
47 struct GNUNET_PEERINFO_IteratorContext *prev;
48
49 /**
50 * Handle to the PEERINFO service.
51 */
52 struct GNUNET_PEERINFO_Handle *h;
53
54 /**
55 * Function to call with the results.
56 */
57 GNUNET_PEERINFO_Processor callback;
58
59 /**
60 * Closure for @e callback.
61 */
62 void *callback_cls;
63
64 /**
65 * Peer we are interested in (only valid if iteration was restricted to one peer).
66 */
67 struct GNUNET_PeerIdentity peer;
68
69 /**
70 * Is @e peer set?
71 */
72 int have_peer;
73
74 /**
75 * Only include friends in reply?
76 */
77 int include_friend_only;
78};
79
80
81/**
82 * Handle to the peerinfo service.
83 */
84struct GNUNET_PEERINFO_Handle
85{
86 /**
87 * Our configuration.
88 */
89 const struct GNUNET_CONFIGURATION_Handle *cfg;
90
91 /**
92 * Connection to the service.
93 */
94 struct GNUNET_MQ_Handle *mq;
95
96 /**
97 * Head of iterator DLL.
98 */
99 struct GNUNET_PEERINFO_IteratorContext *ic_head;
100
101 /**
102 * Tail of iterator DLL.
103 */
104 struct GNUNET_PEERINFO_IteratorContext *ic_tail;
105
106 /**
107 * ID for a reconnect task.
108 */
109 struct GNUNET_SCHEDULER_Task *r_task;
110};
111
112
113/**
114 * Close the existing connection to PEERINFO and reconnect.
115 *
116 * @param h handle to the service
117 */
118static void
119reconnect (struct GNUNET_PEERINFO_Handle *h);
120
121
122struct GNUNET_PEERINFO_Handle *
123GNUNET_PEERINFO_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
124{
125 struct GNUNET_PEERINFO_Handle *h;
126
127 h = GNUNET_new (struct GNUNET_PEERINFO_Handle);
128 h->cfg = cfg;
129 reconnect (h);
130 if (NULL == h->mq)
131 {
132 GNUNET_free (h);
133 return NULL;
134 }
135 return h;
136}
137
138
139/**
140 * Disconnect from the peerinfo service. Note that all iterators must
141 * have completed or have been cancelled by the time this function is
142 * called (otherwise, calling this function is a serious error).
143 * Furthermore, if #GNUNET_PEERINFO_add_peer() operations are still
144 * pending, they will be cancelled silently on disconnect.
145 *
146 * @param h handle to disconnect
147 */
148void
149GNUNET_PEERINFO_disconnect (struct GNUNET_PEERINFO_Handle *h)
150{
151 struct GNUNET_PEERINFO_IteratorContext *ic;
152
153 while (NULL != (ic = h->ic_head))
154 {
155 GNUNET_CONTAINER_DLL_remove (h->ic_head,
156 h->ic_tail,
157 ic);
158 GNUNET_free (ic);
159 }
160 if (NULL != h->mq)
161 {
162 GNUNET_MQ_destroy (h->mq);
163 h->mq = NULL;
164 }
165 if (NULL != h->r_task)
166 {
167 GNUNET_SCHEDULER_cancel (h->r_task);
168 h->r_task = NULL;
169 }
170 GNUNET_free (h);
171}
172
173
174/**
175 * Task scheduled to re-try connecting to the peerinfo service.
176 *
177 * @param cls the `struct GNUNET_PEERINFO_Handle *`
178 */
179static void
180reconnect_task (void *cls)
181{
182 struct GNUNET_PEERINFO_Handle *h = cls;
183
184 h->r_task = NULL;
185 reconnect (h);
186}
187
188
189/**
190 * We encountered an error, reconnect to the PEERINFO service.
191 *
192 * @param h handle to reconnect
193 */
194static void
195do_reconnect (struct GNUNET_PEERINFO_Handle *h)
196{
197 struct GNUNET_PEERINFO_IteratorContext *ic = h->ic_head;
198
199 GNUNET_MQ_destroy (h->mq);
200 h->mq = NULL;
201 if (NULL != ic)
202 {
203 GNUNET_CONTAINER_DLL_remove (h->ic_head,
204 h->ic_tail,
205 ic);
206 if (NULL != ic->callback)
207 ic->callback (ic->callback_cls,
208 NULL,
209 NULL,
210 _ ("Failed to receive response from `PEERINFO' service."));
211 GNUNET_free (ic);
212 }
213 h->r_task = GNUNET_SCHEDULER_add_now (&reconnect_task,
214 h);
215}
216
217
218/**
219 * We got a disconnect after asking regex to do the announcement.
220 * Retry.
221 *
222 * @param cls the `struct GNUNET_PEERINFO_Handle` to retry
223 * @param error error code
224 */
225static void
226mq_error_handler (void *cls,
227 enum GNUNET_MQ_Error error)
228{
229 struct GNUNET_PEERINFO_Handle *h = cls;
230
231 do_reconnect (h);
232}
233
234
235/**
236 * Function called when we receive an info message. Check it is
237 * well-formed.
238 *
239 * @param cls closure
240 * @param im message received
241 * @return #GNUNET_OK if the message is OK
242 */
243static int
244check_info (void *cls,
245 const struct InfoMessage *im)
246{
247 struct GNUNET_PEERINFO_Handle *h = cls;
248 struct GNUNET_PEERINFO_IteratorContext *ic = h->ic_head;
249 uint16_t ms = ntohs (im->header.size) - sizeof(*im);
250
251 if (0 != ntohl (im->reserved))
252 {
253 GNUNET_break (0);
254 return GNUNET_SYSERR;
255 }
256 if (NULL == ic)
257 {
258 /* didn't expect a response, bad */
259 GNUNET_break (0);
260 return GNUNET_SYSERR;
261 }
262 if ((GNUNET_YES == ic->have_peer) &&
263 (0 != GNUNET_memcmp (&ic->peer,
264 &im->peer)))
265 {
266 /* bogus message (from a different iteration call?); out of sequence! */
267 LOG (GNUNET_ERROR_TYPE_ERROR,
268 "Received HELLO for peer `%s', expected peer `%s'\n",
269 GNUNET_i2s (&im->peer),
270 GNUNET_i2s (&ic->peer));
271 GNUNET_break (0);
272 return GNUNET_SYSERR;
273 }
274 if (ms > sizeof(struct GNUNET_MessageHeader))
275 {
276 const struct GNUNET_HELLO_Message *hello;
277 struct GNUNET_PeerIdentity id;
278
279 hello = (const struct GNUNET_HELLO_Message *) &im[1];
280 if (ms != GNUNET_HELLO_size (hello))
281 {
282 /* malformed message */
283 GNUNET_break (0);
284 return GNUNET_SYSERR;
285 }
286 if (GNUNET_OK !=
287 GNUNET_HELLO_get_id (hello,
288 &id))
289 {
290 /* malformed message */
291 GNUNET_break (0);
292 return GNUNET_SYSERR;
293 }
294 if (0 != GNUNET_memcmp (&im->peer,
295 &id))
296 {
297 /* malformed message */
298 GNUNET_break (0);
299 return GNUNET_SYSERR;
300 }
301 }
302 else if (0 != ms)
303 {
304 /* malformed message */
305 GNUNET_break (0);
306 return GNUNET_SYSERR;
307 }
308 return GNUNET_OK;
309}
310
311
312/**
313 * Handle info message.
314 *
315 * @param cls closure
316 * @param im message received
317 */
318static void
319handle_info (void *cls,
320 const struct InfoMessage *im)
321{
322 struct GNUNET_PEERINFO_Handle *h = cls;
323 struct GNUNET_PEERINFO_IteratorContext *ic = h->ic_head;
324 const struct GNUNET_HELLO_Message *hello = NULL;
325 uint16_t ms;
326
327 ms = ntohs (im->header.size);
328 if (ms > sizeof(struct InfoMessage))
329 hello = (const struct GNUNET_HELLO_Message *) &im[1];
330 if (NULL != ic->callback)
331 ic->callback (ic->callback_cls,
332 &im->peer,
333 hello,
334 NULL);
335}
336
337
338/**
339 * Send the next IC request at the head of the queue.
340 *
341 * @param h handle
342 */
343static void
344send_ic_request (struct GNUNET_PEERINFO_Handle *h)
345{
346 struct GNUNET_PEERINFO_IteratorContext *ic = h->ic_head;
347 struct GNUNET_MQ_Envelope *env;
348 struct ListAllPeersMessage *lapm;
349 struct ListPeerMessage *lpm;
350
351 if (NULL == ic)
352 {
353 GNUNET_break (0);
354 return;
355 }
356 if (NULL == h->mq)
357 {
358 GNUNET_break (0);
359 return;
360 }
361 if (GNUNET_NO == ic->have_peer)
362 {
363 LOG (GNUNET_ERROR_TYPE_DEBUG,
364 "Requesting list of peers from PEERINFO service\n");
365 env = GNUNET_MQ_msg (lapm,
366 GNUNET_MESSAGE_TYPE_PEERINFO_GET_ALL);
367 lapm->include_friend_only = htonl (ic->include_friend_only);
368 }
369 else
370 {
371 LOG (GNUNET_ERROR_TYPE_DEBUG,
372 "Requesting information on peer `%s' from PEERINFO service\n",
373 GNUNET_i2s (&ic->peer));
374 env = GNUNET_MQ_msg (lpm,
375 GNUNET_MESSAGE_TYPE_PEERINFO_GET);
376 lpm->include_friend_only = htonl (ic->include_friend_only);
377 lpm->peer = ic->peer;
378 }
379 GNUNET_MQ_send (h->mq,
380 env);
381}
382
383
384/**
385 * Type of a function to call when we receive a message from the
386 * service. Call the iterator with the result and (if applicable)
387 * continue to receive more messages or trigger processing the next
388 * event (if applicable).
389 *
390 * @param cls closure
391 * @param msg message received, NULL on timeout or fatal error
392 */
393static void
394handle_end_iteration (void *cls,
395 const struct GNUNET_MessageHeader *msg)
396{
397 struct GNUNET_PEERINFO_Handle *h = cls;
398 struct GNUNET_PEERINFO_IteratorContext *ic = h->ic_head;
399
400 if (NULL == ic)
401 {
402 /* didn't expect a response, reconnect */
403 GNUNET_break (0);
404 reconnect (h);
405 return;
406 }
407 LOG (GNUNET_ERROR_TYPE_DEBUG,
408 "Received end of list of peers from PEERINFO service\n");
409 GNUNET_CONTAINER_DLL_remove (h->ic_head,
410 h->ic_tail,
411 ic);
412 if (NULL != h->ic_head)
413 send_ic_request (h);
414 if (NULL != ic->callback)
415 ic->callback (ic->callback_cls,
416 NULL,
417 NULL,
418 NULL);
419 GNUNET_free (ic);
420}
421
422
423/**
424 * Close the existing connection to PEERINFO and reconnect.
425 *
426 * @param h handle to the service
427 */
428static void
429reconnect (struct GNUNET_PEERINFO_Handle *h)
430{
431 struct GNUNET_MQ_MessageHandler handlers[] = {
432 GNUNET_MQ_hd_var_size (info,
433 GNUNET_MESSAGE_TYPE_PEERINFO_INFO,
434 struct InfoMessage,
435 h),
436 GNUNET_MQ_hd_fixed_size (end_iteration,
437 GNUNET_MESSAGE_TYPE_PEERINFO_INFO_END,
438 struct GNUNET_MessageHeader,
439 h),
440 GNUNET_MQ_handler_end ()
441 };
442
443 if (NULL != h->r_task)
444 {
445 GNUNET_SCHEDULER_cancel (h->r_task);
446 h->r_task = NULL;
447 }
448 if (NULL != h->mq)
449 {
450 GNUNET_MQ_destroy (h->mq);
451 h->mq = NULL;
452 }
453 h->mq = GNUNET_CLIENT_connect (h->cfg,
454 "peerinfo",
455 handlers,
456 &mq_error_handler,
457 h);
458 if (NULL != h->ic_head)
459 send_ic_request (h);
460}
461
462
463struct GNUNET_PEERINFO_IteratorContext *
464GNUNET_PEERINFO_iterate (struct GNUNET_PEERINFO_Handle *h,
465 int include_friend_only,
466 const struct GNUNET_PeerIdentity *peer,
467 GNUNET_PEERINFO_Processor callback,
468 void *callback_cls)
469{
470 struct GNUNET_PEERINFO_IteratorContext *ic;
471
472 ic = GNUNET_new (struct GNUNET_PEERINFO_IteratorContext);
473 ic->h = h;
474 ic->include_friend_only = include_friend_only;
475 ic->callback = callback;
476 ic->callback_cls = callback_cls;
477 if (NULL != peer)
478 {
479 ic->have_peer = GNUNET_YES;
480 ic->peer = *peer;
481 }
482 GNUNET_CONTAINER_DLL_insert_tail (h->ic_head,
483 h->ic_tail,
484 ic);
485 if (h->ic_head == ic)
486 send_ic_request (h);
487 return ic;
488}
489
490
491/**
492 * Cancel an iteration over peer information.
493 *
494 * @param ic context of the iterator to cancel
495 */
496void
497GNUNET_PEERINFO_iterate_cancel (struct GNUNET_PEERINFO_IteratorContext *ic)
498{
499 struct GNUNET_PEERINFO_Handle *h = ic->h;
500
501 ic->callback = NULL;
502 if (ic == h->ic_head)
503 return;
504 GNUNET_CONTAINER_DLL_remove (h->ic_head,
505 h->ic_tail,
506 ic);
507 GNUNET_free (ic);
508}
509
510
511/**
512 * Add a host to the persistent list. This method operates in
513 * semi-reliable mode: if the transmission is not completed by
514 * the time #GNUNET_PEERINFO_disconnect() is called, it will be
515 * aborted. Furthermore, if a second HELLO is added for the
516 * same peer before the first one was transmitted, PEERINFO may
517 * merge the two HELLOs prior to transmission to the service.
518 *
519 * @param h handle to the peerinfo service
520 * @param hello the verified (!) HELLO message
521 * @param cont continuation to call when done, NULL is allowed
522 * @param cont_cls closure for @a cont
523 * @return handle to cancel add operation; all pending
524 * 'add' operations will be cancelled automatically
525 * on disconnect, so it is not necessary to keep this
526 * handle (unless @a cont is NULL and at some point
527 * calling @a cont must be prevented)
528 */
529struct GNUNET_MQ_Envelope *
530GNUNET_PEERINFO_add_peer (struct GNUNET_PEERINFO_Handle *h,
531 const struct GNUNET_HELLO_Message *hello,
532 GNUNET_SCHEDULER_TaskCallback cont,
533 void *cont_cls)
534{
535 struct GNUNET_MQ_Envelope *env;
536 struct GNUNET_PeerIdentity peer;
537
538 if (NULL == h->mq)
539 return NULL;
540 GNUNET_assert (GNUNET_OK ==
541 GNUNET_HELLO_get_id (hello,
542 &peer));
543 LOG (GNUNET_ERROR_TYPE_DEBUG,
544 "Adding peer `%s' to PEERINFO database\n",
545 GNUNET_i2s (&peer));
546 env = GNUNET_MQ_msg_copy ((const struct GNUNET_MessageHeader *) hello);
547 if (NULL != cont)
548 GNUNET_MQ_notify_sent (env,
549 cont,
550 cont_cls);
551 GNUNET_MQ_send (h->mq,
552 env);
553 return env;
554}
555
556
557/* end of peerinfo_api.c */
diff --git a/src/peerinfo/peerinfo_api_notify.c b/src/peerinfo/peerinfo_api_notify.c
deleted file mode 100644
index 5f4c123ff..000000000
--- a/src/peerinfo/peerinfo_api_notify.c
+++ /dev/null
@@ -1,291 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2001, 2002, 2004, 2005, 2007, 2009, 2010 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file peerinfo/peerinfo_api_notify.c
23 * @brief notify API to access peerinfo service
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_peerinfo_service.h"
29#include "gnunet_protocols.h"
30#include "peerinfo.h"
31
32#define LOG(kind, ...) GNUNET_log_from (kind, "peerinfo-api", __VA_ARGS__)
33
34/**
35 * Context for the info handler.
36 */
37struct GNUNET_PEERINFO_NotifyContext
38{
39 /**
40 * Our connection to the PEERINFO service.
41 */
42 struct GNUNET_MQ_Handle *mq;
43
44 /**
45 * Function to call with information.
46 */
47 GNUNET_PEERINFO_Processor callback;
48
49 /**
50 * Closure for @e callback.
51 */
52 void *callback_cls;
53
54 /**
55 * Configuration.
56 */
57 const struct GNUNET_CONFIGURATION_Handle *cfg;
58
59 /**
60 * Tasked used for delayed re-connection attempt.
61 */
62 struct GNUNET_SCHEDULER_Task *task;
63
64 /**
65 * Include friend only HELLOs in callbacks
66 */
67 int include_friend_only;
68};
69
70
71/**
72 * Task to re-try connecting to peerinfo.
73 *
74 * @param cls the `struct GNUNET_PEERINFO_NotifyContext *`
75 */
76static void
77reconnect (void *cls);
78
79
80/**
81 * We encountered an error, reconnect to the service.
82 *
83 * @param nc context to reconnect
84 */
85static void
86do_reconnect (struct GNUNET_PEERINFO_NotifyContext *nc)
87{
88 GNUNET_MQ_destroy (nc->mq);
89 nc->mq = NULL;
90 nc->task = GNUNET_SCHEDULER_add_now (&reconnect,
91 nc);
92}
93
94
95/**
96 * We got a disconnect after asking regex to do the announcement.
97 * Retry.
98 *
99 * @param cls the `struct GNUNET_PEERINFO_NotifyContext` to retry
100 * @param error error code
101 */
102static void
103mq_error_handler (void *cls,
104 enum GNUNET_MQ_Error error)
105{
106 struct GNUNET_PEERINFO_NotifyContext *nc = cls;
107
108 do_reconnect (nc);
109}
110
111
112/**
113 * Check that a peerinfo information message is well-formed.
114 *
115 * @param cls closure
116 * @param im message received
117 * @return #GNUNET_OK if the message is well-formed
118 */
119static int
120check_notification (void *cls,
121 const struct InfoMessage *im)
122{
123 uint16_t ms = ntohs (im->header.size) - sizeof(*im);
124
125 if (ms >= sizeof(struct GNUNET_MessageHeader))
126 {
127 const struct GNUNET_HELLO_Message *hello;
128
129 hello = (const struct GNUNET_HELLO_Message *) &im[1];
130 if (ms != GNUNET_HELLO_size (hello))
131 {
132 GNUNET_break (0);
133 return GNUNET_SYSERR;
134 }
135 return GNUNET_OK;
136 }
137 if (0 != ms)
138 {
139 GNUNET_break (0);
140 return GNUNET_SYSERR;
141 }
142 return GNUNET_OK; /* odd... */
143}
144
145
146/**
147 * Receive a peerinfo information message, process it.
148 *
149 * @param cls closure
150 * @param im message received
151 */
152static void
153handle_notification (void *cls,
154 const struct InfoMessage *im)
155{
156 struct GNUNET_PEERINFO_NotifyContext *nc = cls;
157 const struct GNUNET_HELLO_Message *hello;
158 uint16_t ms = ntohs (im->header.size) - sizeof(struct InfoMessage);
159
160 if (0 == ms)
161 return;
162 hello = (const struct GNUNET_HELLO_Message *) &im[1];
163 LOG (GNUNET_ERROR_TYPE_DEBUG,
164 "Received information about peer `%s' from peerinfo database\n",
165 GNUNET_i2s (&im->peer));
166 nc->callback (nc->callback_cls,
167 &im->peer,
168 hello,
169 NULL);
170}
171
172
173/**
174 * Type of a function to call when we receive a message from the
175 * service. Call the iterator with the result and (if applicable)
176 * continue to receive more messages or trigger processing the next
177 * event (if applicable).
178 *
179 * @param cls closure
180 * @param msg message received, NULL on timeout or fatal error
181 */
182static void
183handle_end_iteration (void *cls,
184 const struct GNUNET_MessageHeader *msg)
185{
186 /* these are ignored by the notify API */
187}
188
189
190/**
191 * Task to re-try connecting to peerinfo.
192 *
193 * @param cls the `struct GNUNET_PEERINFO_NotifyContext *`
194 */
195static void
196reconnect (void *cls)
197{
198 struct GNUNET_PEERINFO_NotifyContext *nc = cls;
199 struct GNUNET_MQ_MessageHandler handlers[] = {
200 GNUNET_MQ_hd_var_size (notification,
201 GNUNET_MESSAGE_TYPE_PEERINFO_INFO,
202 struct InfoMessage,
203 nc),
204 GNUNET_MQ_hd_fixed_size (end_iteration,
205 GNUNET_MESSAGE_TYPE_PEERINFO_INFO_END,
206 struct GNUNET_MessageHeader,
207 nc),
208 GNUNET_MQ_handler_end ()
209 };
210 struct GNUNET_MQ_Envelope *env;
211 struct NotifyMessage *nm;
212
213 nc->task = NULL;
214 nc->mq = GNUNET_CLIENT_connect (nc->cfg,
215 "peerinfo",
216 handlers,
217 &mq_error_handler,
218 nc);
219 if (NULL == nc->mq)
220 return;
221 env = GNUNET_MQ_msg (nm,
222 GNUNET_MESSAGE_TYPE_PEERINFO_NOTIFY);
223 nm->include_friend_only = htonl (nc->include_friend_only);
224 GNUNET_MQ_send (nc->mq,
225 env);
226}
227
228
229/**
230 * Call a method whenever our known information about peers
231 * changes. Initially calls the given function for all known
232 * peers and then only signals changes.
233 *
234 * If @a include_friend_only is set to #GNUNET_YES peerinfo will include HELLO
235 * messages which are intended for friend to friend mode and which do not
236 * have to be gossiped. Otherwise these messages are skipped.
237 *
238 * @param cfg configuration to use
239 * @param include_friend_only include HELLO messages for friends only
240 * @param callback the method to call for each peer
241 * @param callback_cls closure for @a callback
242 * @return NULL on error
243 */
244struct GNUNET_PEERINFO_NotifyContext *
245GNUNET_PEERINFO_notify (const struct GNUNET_CONFIGURATION_Handle *cfg,
246 int include_friend_only,
247 GNUNET_PEERINFO_Processor callback,
248 void *callback_cls)
249{
250 struct GNUNET_PEERINFO_NotifyContext *nc;
251
252 nc = GNUNET_new (struct GNUNET_PEERINFO_NotifyContext);
253 nc->cfg = cfg;
254 nc->callback = callback;
255 nc->callback_cls = callback_cls;
256 nc->include_friend_only = include_friend_only;
257 reconnect (nc);
258 if (NULL == nc->mq)
259 {
260 LOG (GNUNET_ERROR_TYPE_WARNING,
261 "Could not connect to PEERINFO service.\n");
262 GNUNET_free (nc);
263 return NULL;
264 }
265 return nc;
266}
267
268
269/**
270 * Stop notifying about changes.
271 *
272 * @param nc context to stop notifying
273 */
274void
275GNUNET_PEERINFO_notify_cancel (struct GNUNET_PEERINFO_NotifyContext *nc)
276{
277 if (NULL != nc->mq)
278 {
279 GNUNET_MQ_destroy (nc->mq);
280 nc->mq = NULL;
281 }
282 if (NULL != nc->task)
283 {
284 GNUNET_SCHEDULER_cancel (nc->task);
285 nc->task = NULL;
286 }
287 GNUNET_free (nc);
288}
289
290
291/* end of peerinfo_api_notify.c */
diff --git a/src/peerinfo/perf_peerinfo_api.c b/src/peerinfo/perf_peerinfo_api.c
deleted file mode 100644
index 055388d43..000000000
--- a/src/peerinfo/perf_peerinfo_api.c
+++ /dev/null
@@ -1,193 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2004, 2009, 2010, 2017 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file peerinfo/perf_peerinfo_api.c
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
25 * over how many peers it can iterate before receiving a timeout after 5 seconds
26 * @author Nathan Evans
27 */
28
29#include "platform.h"
30#include "gnunet_hello_lib.h"
31#include "gnunet_util_lib.h"
32#include "gnunet_testing_lib.h"
33#include "gnunet_peerinfo_service.h"
34#include "peerinfo.h"
35#include <gauger.h>
36
37#define NUM_REQUESTS 5000
38
39static struct GNUNET_PEERINFO_IteratorContext *ic[NUM_REQUESTS];
40
41static struct GNUNET_PEERINFO_Handle *h;
42
43static unsigned int numpeers;
44
45static struct GNUNET_PeerIdentity pid;
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
73
74static int
75check_it (void *cls,
76 const struct GNUNET_HELLO_Address *address,
77 struct GNUNET_TIME_Absolute expiration)
78{
79 return GNUNET_OK;
80}
81
82
83static ssize_t
84address_generator (void *cls, size_t max, void *buf)
85{
86 size_t *agc = cls;
87 ssize_t ret;
88 char *caddress;
89 struct GNUNET_HELLO_Address address;
90
91 if (*agc == 0)
92 return GNUNET_SYSERR; /* Done */
93
94 GNUNET_asprintf (&caddress, "Address%d", *agc);
95 address.peer = pid;
96 address.address_length = strlen (caddress) + 1;
97 address.address = caddress;
98 address.transport_name = "peerinfotest";
99 ret =
100 GNUNET_HELLO_add_address (&address,
101 GNUNET_TIME_relative_to_absolute
102 (GNUNET_TIME_UNIT_HOURS), buf, max);
103 GNUNET_free (caddress);
104 *agc = 0;
105 return ret;
106}
107
108
109static void
110add_peer (size_t i)
111{
112 struct GNUNET_HELLO_Message *h2;
113
114 memset (&pid, i, sizeof(pid));
115 h2 = GNUNET_HELLO_create (&pid.public_key,
116 &address_generator,
117 &i,
118 GNUNET_NO);
119 GNUNET_PEERINFO_add_peer (h, h2, NULL, NULL);
120 GNUNET_free (h2);
121}
122
123
124static void
125process (void *cls,
126 const struct GNUNET_PeerIdentity *peer,
127 const struct GNUNET_HELLO_Message *hello,
128 const char *err_msg)
129{
130 struct GNUNET_PEERINFO_IteratorContext **icp = cls;
131
132 if (NULL == peer)
133 {
134 *icp = NULL;
135 return;
136 }
137 numpeers++;
138 if (0 && (NULL != hello))
139 GNUNET_HELLO_iterate_addresses (hello,
140 GNUNET_NO,
141 &check_it,
142 NULL);
143}
144
145
146static void
147run (void *cls,
148 const struct GNUNET_CONFIGURATION_Handle *cfg,
149 struct GNUNET_TESTING_Peer *peer)
150{
151 h = GNUNET_PEERINFO_connect (cfg);
152 GNUNET_assert (h != NULL);
153 for (unsigned int i = 0; i < NUM_REQUESTS; i++)
154 {
155 add_peer (i);
156 ic[i] = GNUNET_PEERINFO_iterate (h,
157 GNUNET_YES,
158 NULL,
159 &process,
160 &ic[i]);
161 }
162 tt = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (
163 GNUNET_TIME_UNIT_SECONDS,
164 5),
165 &do_timeout,
166 NULL);
167 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
168 NULL);
169}
170
171
172int
173main (int argc,
174 char *argv[])
175{
176 if (0 != GNUNET_TESTING_service_run ("perf-gnunet-peerinfo",
177 "peerinfo",
178 "test_peerinfo_api_data.conf",
179 &run, NULL))
180 return 1;
181 fprintf (stderr,
182 "Received %u/%u calls before timeout\n",
183 numpeers,
184 NUM_REQUESTS * NUM_REQUESTS / 2);
185 GAUGER ("PEERINFO",
186 "Peerinfo lookups",
187 numpeers / 5,
188 "peers/s");
189 return 0;
190}
191
192
193/* end of perf_peerinfo_api.c */
diff --git a/src/peerinfo/test_peerinfo_api.c b/src/peerinfo/test_peerinfo_api.c
deleted file mode 100644
index 27df6e37b..000000000
--- a/src/peerinfo/test_peerinfo_api.c
+++ /dev/null
@@ -1,172 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2004, 2009 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file peerinfo/test_peerinfo_api.c
23 * @brief testcase for peerinfo_api.c
24 * @author Christian Grothoff
25 *
26 * TODO:
27 * - test merging of HELLOs (add same peer twice...)
28 */
29#include "platform.h"
30#include "gnunet_hello_lib.h"
31#include "gnunet_util_lib.h"
32#include "gnunet_peerinfo_service.h"
33#include "gnunet_testing_lib.h"
34#include "peerinfo.h"
35
36static struct GNUNET_PEERINFO_IteratorContext *ic;
37
38static struct GNUNET_PEERINFO_Handle *h;
39
40static unsigned int retries;
41
42static int global_ret;
43
44
45static int
46check_it (void *cls, const struct GNUNET_HELLO_Address *address,
47 struct GNUNET_TIME_Absolute expiration)
48{
49 unsigned int *agc = cls;
50
51 if (address != NULL)
52 {
53 GNUNET_assert (0 == strcmp ("peerinfotest", address->transport_name));
54 GNUNET_assert (0 ==
55 strncmp ("Address", address->address,
56 address->address_length));
57 (*agc) -= (1 << (address->address_length - 1));
58 }
59 return GNUNET_OK;
60}
61
62
63static ssize_t
64address_generator (void *cls, size_t max, void *buf)
65{
66 size_t *agc = cls;
67 ssize_t ret;
68 struct GNUNET_HELLO_Address address;
69
70 if (0 == *agc)
71 return GNUNET_SYSERR; /* Done */
72 memset (&address.peer, 0, sizeof(struct GNUNET_PeerIdentity));
73 address.address = "Address";
74 address.transport_name = "peerinfotest";
75 address.address_length = *agc;
76 ret =
77 GNUNET_HELLO_add_address (&address,
78 GNUNET_TIME_relative_to_absolute
79 (GNUNET_TIME_UNIT_HOURS), buf, max);
80 (*agc)--;
81 return ret;
82}
83
84
85struct GNUNET_PeerIdentity pid;
86
87static void
88add_peer ()
89{
90 struct GNUNET_HELLO_Message *h2;
91 size_t agc;
92
93 agc = 2;
94 memset (&pid, 32, sizeof(pid));
95 h2 = GNUNET_HELLO_create (&pid.public_key, &address_generator, &agc,
96 GNUNET_NO);
97 GNUNET_PEERINFO_add_peer (h, h2, NULL, NULL);
98 GNUNET_free (h2);
99}
100
101
102static void
103process (void *cls, const struct GNUNET_PeerIdentity *peer,
104 const struct GNUNET_HELLO_Message *hello, const char *err_msg)
105{
106 unsigned int agc;
107
108 if (err_msg != NULL)
109 {
110 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
111 _ ("Error in communication with PEERINFO service\n"));
112 }
113
114 if (peer == NULL)
115 {
116 ic = NULL;
117 if ((3 == global_ret) && (retries < 50))
118 {
119 /* try again */
120 retries++;
121 add_peer ();
122 ic = GNUNET_PEERINFO_iterate (h, GNUNET_NO, NULL,
123 &process,
124 cls);
125 return;
126 }
127 GNUNET_assert (peer == NULL);
128 GNUNET_assert (2 == global_ret);
129 GNUNET_PEERINFO_disconnect (h);
130 h = NULL;
131 global_ret = 0;
132 return;
133 }
134 if (hello != NULL)
135 {
136 GNUNET_assert (3 == global_ret);
137 agc = 3;
138 GNUNET_HELLO_iterate_addresses (hello, GNUNET_NO,
139 &check_it, &agc);
140 GNUNET_assert (agc == 0);
141 global_ret = 2;
142 }
143}
144
145
146static void
147run (void *cls,
148 const struct GNUNET_CONFIGURATION_Handle *cfg,
149 struct GNUNET_TESTING_Peer *peer)
150{
151 h = GNUNET_PEERINFO_connect (cfg);
152 GNUNET_assert (NULL != h);
153 add_peer ();
154 ic = GNUNET_PEERINFO_iterate (h, GNUNET_NO, &pid,
155 &process, cls);
156}
157
158
159int
160main (int argc, char *argv[])
161{
162 global_ret = 3;
163 if (0 != GNUNET_TESTING_service_run ("test-gnunet-peerinfo",
164 "peerinfo",
165 "test_peerinfo_api_data.conf",
166 &run, NULL))
167 return 1;
168 return global_ret;
169}
170
171
172/* end of test_peerinfo_api.c */
diff --git a/src/peerinfo/test_peerinfo_api_data.conf b/src/peerinfo/test_peerinfo_api_data.conf
deleted file mode 100644
index e632c341f..000000000
--- a/src/peerinfo/test_peerinfo_api_data.conf
+++ /dev/null
@@ -1,15 +0,0 @@
1[PATHS]
2GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-peerinfo/
3
4[peerinfo]
5PORT = 22354
6
7[dns]
8START_ON_DEMAND = NO
9
10
11
12[nse]
13START_ON_DEMAND = NO
14
15
diff --git a/src/peerinfo/test_peerinfo_api_friend_only.c b/src/peerinfo/test_peerinfo_api_friend_only.c
deleted file mode 100644
index a5414e701..000000000
--- a/src/peerinfo/test_peerinfo_api_friend_only.c
+++ /dev/null
@@ -1,172 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2004, 2009 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file peerinfo/test_peerinfo_api_friend_only.c
23 * @brief testcase friend only HELLO restrictions in for peerinfo
24 * @author Christian Grothoff
25 * @author Matthias Wachs
26 *
27 * TODO:
28 * - test merging of HELLOs (add same peer twice...)
29 */
30#include "platform.h"
31#include "gnunet_hello_lib.h"
32#include "gnunet_util_lib.h"
33#include "gnunet_peerinfo_service.h"
34#include "gnunet_testing_lib.h"
35
36
37static struct GNUNET_PEERINFO_IteratorContext *ic;
38
39static struct GNUNET_PEERINFO_Handle *h;
40
41static struct GNUNET_PeerIdentity pid;
42
43static unsigned int retries;
44
45static int global_ret;
46
47
48static ssize_t
49address_generator (void *cls,
50 size_t max,
51 void *buf)
52{
53 size_t *agc = cls;
54 ssize_t ret;
55 struct GNUNET_HELLO_Address address;
56
57 if (0 == *agc)
58 return GNUNET_SYSERR; /* Done */
59 memset (&address.peer,
60 0,
61 sizeof(struct GNUNET_PeerIdentity));
62 address.address = "Address";
63 address.transport_name = "peerinfotest";
64 address.address_length = *agc;
65 ret = GNUNET_HELLO_add_address (&address,
66 GNUNET_TIME_relative_to_absolute (
67 GNUNET_TIME_UNIT_HOURS),
68 buf,
69 max);
70 (*agc)--;
71 return ret;
72}
73
74
75static void
76add_peer ()
77{
78 struct GNUNET_HELLO_Message *h2;
79 size_t agc;
80
81 agc = 2;
82 memset (&pid, 32, sizeof(pid));
83 h2 = GNUNET_HELLO_create (&pid.public_key,
84 &address_generator,
85 &agc,
86 GNUNET_YES);
87 GNUNET_PEERINFO_add_peer (h,
88 h2,
89 NULL,
90 NULL);
91 GNUNET_free (h2);
92}
93
94
95static void
96process (void *cls,
97 const struct GNUNET_PeerIdentity *peer,
98 const struct GNUNET_HELLO_Message *hello,
99 const char *err_msg)
100{
101 if (NULL != err_msg)
102 {
103 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
104 "Error in communication with PEERINFO service: %s\n",
105 err_msg);
106 }
107 if (NULL == peer)
108 {
109 ic = NULL;
110 if ((3 == global_ret) && (retries < 50))
111 {
112 /* try again */
113 retries++;
114 add_peer ();
115 ic = GNUNET_PEERINFO_iterate (h,
116 GNUNET_NO,
117 NULL,
118 &process,
119 cls);
120 return;
121 }
122 GNUNET_assert (peer == NULL);
123 GNUNET_PEERINFO_disconnect (h);
124 h = NULL;
125 global_ret = 0;
126 return;
127 }
128
129 if ((NULL != hello) &&
130 (GNUNET_YES == GNUNET_HELLO_is_friend_only (hello)))
131 {
132 fprintf (stderr,
133 "Received friend-only HELLO\n");
134 global_ret = 1;
135 GNUNET_PEERINFO_disconnect (h);
136 h = NULL;
137 return;
138 }
139}
140
141
142static void
143run (void *cls,
144 const struct GNUNET_CONFIGURATION_Handle *cfg,
145 struct GNUNET_TESTING_Peer *peer)
146{
147 h = GNUNET_PEERINFO_connect (cfg);
148 GNUNET_assert (NULL != h);
149 add_peer ();
150 ic = GNUNET_PEERINFO_iterate (h,
151 GNUNET_NO,
152 &pid,
153 &process,
154 NULL);
155}
156
157
158int
159main (int argc,
160 char *argv[])
161{
162 global_ret = 3;
163 if (0 != GNUNET_TESTING_service_run ("test-peerinfo-api-friend-only",
164 "peerinfo",
165 "test_peerinfo_api_data.conf",
166 &run, NULL))
167 return 1;
168 return global_ret;
169}
170
171
172/* end of test_peerinfo_api_friend_only */
diff --git a/src/peerinfo/test_peerinfo_api_notify_friend_only.c b/src/peerinfo/test_peerinfo_api_notify_friend_only.c
deleted file mode 100644
index 6d5793dcf..000000000
--- a/src/peerinfo/test_peerinfo_api_notify_friend_only.c
+++ /dev/null
@@ -1,261 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2004, 2009 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file peerinfo/test_peerinfo_api_notify_friend_only.c
23 * @brief testcase friend only HELLO restrictions in for peerinfo
24 * @author Christian Grothoff
25 * @author Matthias Wachs
26 *
27 * TODO:
28 * - test merging of HELLOs (add same peer twice...)
29 */
30#include "platform.h"
31#include "gnunet_hello_lib.h"
32#include "gnunet_util_lib.h"
33#include "gnunet_peerinfo_service.h"
34#include "gnunet_testing_lib.h"
35#include "peerinfo.h"
36
37#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
38
39static struct GNUNET_PEERINFO_Handle *h;
40static struct GNUNET_PEERINFO_NotifyContext *pnc_w_fo;
41static struct GNUNET_PEERINFO_NotifyContext *pnc_wo_fo;
42
43static const struct GNUNET_CONFIGURATION_Handle *mycfg;
44
45static int global_ret;
46
47/**
48 * Did we get a HELLO callback for notification handle with friend HELLOS
49 * (expected)
50 */
51static int res_cb_w_fo;
52
53/**
54 * Did we get a HELLO callback for notification handle without friend HELLOS
55 * (not expected)
56 */
57static int res_cb_wo_fo;
58
59struct GNUNET_PeerIdentity pid;
60
61struct GNUNET_SCHEDULER_Task *timeout_task;
62
63static void
64end_badly (void *cls)
65{
66 timeout_task = NULL;
67 GNUNET_break (0);
68 if (NULL != pnc_wo_fo)
69 {
70 GNUNET_PEERINFO_notify_cancel (pnc_wo_fo);
71 pnc_wo_fo = NULL;
72 }
73 if (NULL != pnc_w_fo)
74 {
75 GNUNET_PEERINFO_notify_cancel (pnc_w_fo);
76 pnc_w_fo = NULL;
77 }
78 if (NULL != h)
79 {
80 GNUNET_PEERINFO_disconnect (h);
81 h = NULL;
82 }
83 global_ret = 255;
84}
85
86
87static void
88done (void *cls)
89{
90 if (NULL != pnc_w_fo)
91 GNUNET_PEERINFO_notify_cancel (pnc_w_fo);
92 pnc_w_fo = NULL;
93 if (NULL != pnc_wo_fo)
94 GNUNET_PEERINFO_notify_cancel (pnc_wo_fo);
95 pnc_wo_fo = NULL;
96 GNUNET_PEERINFO_disconnect (h);
97 h = NULL;
98
99 if (NULL != timeout_task)
100 {
101 GNUNET_SCHEDULER_cancel (timeout_task);
102 timeout_task = NULL;
103 }
104
105 if ((GNUNET_YES == res_cb_w_fo) && (GNUNET_NO == res_cb_wo_fo))
106 global_ret = 0;
107 else
108 GNUNET_break (0);
109}
110
111
112static ssize_t
113address_generator (void *cls, size_t max, void *buf)
114{
115 size_t *agc = cls;
116 ssize_t ret;
117 struct GNUNET_HELLO_Address address;
118
119 if (0 == *agc)
120 return GNUNET_SYSERR; /* Done */
121 memset (&address.peer, 0, sizeof(struct GNUNET_PeerIdentity));
122 address.address = "Address";
123 address.transport_name = "peerinfotest";
124 address.address_length = *agc;
125 ret = GNUNET_HELLO_add_address (&address,
126 GNUNET_TIME_relative_to_absolute (
127 GNUNET_TIME_UNIT_HOURS), buf, max);
128 (*agc)--;
129 return ret;
130}
131
132
133static void
134process_w_fo (void *cls,
135 const struct GNUNET_PeerIdentity *peer,
136 const struct GNUNET_HELLO_Message *hello,
137 const char *err_msg)
138{
139 if (err_msg != NULL)
140 {
141 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
142 _ ("Error in communication with PEERINFO service\n"));
143 GNUNET_SCHEDULER_add_now (&done, NULL);
144 return;
145 }
146
147 if (NULL != peer)
148 {
149 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
150 "Received callback for peer `%s' %s HELLO\n", GNUNET_i2s (peer),
151 (NULL != hello) ? "with" : "without");
152
153 if (NULL == hello)
154 return;
155
156 if (GNUNET_NO == GNUNET_HELLO_is_friend_only (hello))
157 {
158 GNUNET_break (0);
159 return;
160 }
161
162 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Received %s HELLO for peer `%s'\n",
163 (GNUNET_YES == GNUNET_HELLO_is_friend_only (hello)) ?
164 "friend only" : "public",
165 GNUNET_i2s (peer));
166 if (0 == GNUNET_memcmp (&pid, peer))
167 {
168 res_cb_w_fo = GNUNET_YES;
169 GNUNET_SCHEDULER_add_now (&done, NULL);
170 }
171 return;
172 }
173}
174
175
176static void
177process_wo_fo (void *cls, const struct GNUNET_PeerIdentity *peer,
178 const struct GNUNET_HELLO_Message *hello, const char *err_msg)
179{
180 if (err_msg != NULL)
181 {
182 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
183 _ ("Error in communication with PEERINFO service\n"));
184 GNUNET_SCHEDULER_add_now (&done, NULL);
185 return;
186 }
187
188 if (NULL != peer)
189 {
190 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
191 "Received callback for peer `%s' %s HELLO\n", GNUNET_i2s (peer),
192 (NULL != hello) ? "with" : "without");
193
194 if (NULL == hello)
195 return;
196
197 if (GNUNET_YES == GNUNET_HELLO_is_friend_only (hello))
198 {
199 GNUNET_break (0);
200 return;
201 }
202
203 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Received %s HELLO for peer `%s'\n",
204 (GNUNET_YES == GNUNET_HELLO_is_friend_only (hello)) ?
205 "friend only" : "public",
206 GNUNET_i2s (peer));
207 if (0 == GNUNET_memcmp (&pid, peer))
208 {
209 GNUNET_break (0);
210 res_cb_wo_fo = GNUNET_YES;
211 }
212 }
213}
214
215
216static void
217add_peer ()
218{
219 struct GNUNET_HELLO_Message *h2;
220 size_t agc;
221
222 agc = 2;
223 memset (&pid, 32, sizeof(pid));
224 h2 = GNUNET_HELLO_create (&pid.public_key, &address_generator, &agc,
225 GNUNET_YES);
226 GNUNET_PEERINFO_add_peer (h, h2, NULL, NULL);
227 GNUNET_free (h2);
228}
229
230
231static void
232run (void *cls,
233 const struct GNUNET_CONFIGURATION_Handle *cfg,
234 struct GNUNET_TESTING_Peer *peer)
235{
236 timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL);
237 mycfg = cfg;
238 pnc_w_fo = GNUNET_PEERINFO_notify (mycfg, GNUNET_YES, &process_w_fo, NULL);
239 pnc_wo_fo = GNUNET_PEERINFO_notify (mycfg, GNUNET_NO, &process_wo_fo, NULL);
240 h = GNUNET_PEERINFO_connect (cfg);
241 GNUNET_assert (NULL != h);
242 add_peer ();
243}
244
245
246int
247main (int argc, char *argv[])
248{
249 res_cb_w_fo = GNUNET_NO;
250 res_cb_wo_fo = GNUNET_NO;
251 global_ret = 3;
252 if (0 != GNUNET_TESTING_service_run ("test-peerinfo-api-friend-only",
253 "peerinfo",
254 "test_peerinfo_api_data.conf",
255 &run, NULL))
256 return 1;
257 return global_ret;
258}
259
260
261/* end of test_peerinfo_api_notify_friend_only.c */
diff --git a/src/peerinfo/test_peerinfo_shipped_hellos.c b/src/peerinfo/test_peerinfo_shipped_hellos.c
deleted file mode 100644
index 45ea73be6..000000000
--- a/src/peerinfo/test_peerinfo_shipped_hellos.c
+++ /dev/null
@@ -1,144 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2004, 2009 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file peerinfo/test_peerinfo_shipped_hellos.c
23 * @brief testcase for shipped HELLOs getting parsed
24 * @author Christian Grothoff
25 * @author Matthias Wachs
26 *
27 */
28#include "platform.h"
29#include "gnunet_hello_lib.h"
30#include "gnunet_util_lib.h"
31#include "gnunet_peerinfo_service.h"
32#include "gnunet_testing_lib.h"
33#include "peerinfo.h"
34
35static struct GNUNET_PEERINFO_IteratorContext *ic;
36
37static struct GNUNET_PEERINFO_Handle *h;
38
39static int global_ret;
40
41
42static int
43addr_cb (void *cls,
44 const struct GNUNET_HELLO_Address *address,
45 struct GNUNET_TIME_Absolute expiration)
46{
47 unsigned int *addr = cls;
48
49 (*addr)++;
50 return GNUNET_OK;
51}
52
53
54static void
55process (void *cls,
56 const struct GNUNET_PeerIdentity *peer,
57 const struct GNUNET_HELLO_Message *hello,
58 const char *err_msg)
59{
60 static unsigned int calls = 0;
61 unsigned int addr;
62
63 if (NULL != err_msg)
64 {
65 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
66 "Error in communication with PEERINFO service: %s\n",
67 err_msg);
68 }
69 if (NULL != peer)
70 {
71 addr = 0;
72 if (NULL != hello)
73 {
74 GNUNET_HELLO_iterate_addresses (hello,
75 GNUNET_NO,
76 &addr_cb,
77 &addr);
78 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
79 "Got information about peer %s with %u addresses\n",
80 GNUNET_i2s (peer),
81 addr);
82 calls++;
83 }
84 else
85 {
86 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
87 "Got no HELLP for peer %s\n",
88 GNUNET_i2s (peer));
89 }
90 }
91 else
92 {
93 if (0 == calls)
94 {
95 fprintf (stderr,
96 "Failed: got no callbacks!\n");
97 global_ret = 1;
98 GNUNET_PEERINFO_disconnect (h);
99 h = NULL;
100 }
101 else
102 {
103 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
104 "Got %u HELLOs in total\n",
105 calls);
106 global_ret = 0;
107 GNUNET_PEERINFO_disconnect (h);
108 h = NULL;
109 }
110 }
111}
112
113
114static void
115run (void *cls,
116 const struct GNUNET_CONFIGURATION_Handle *cfg,
117 struct GNUNET_TESTING_Peer *peer)
118{
119 h = GNUNET_PEERINFO_connect (cfg);
120 GNUNET_assert (NULL != h);
121 ic = GNUNET_PEERINFO_iterate (h,
122 GNUNET_YES,
123 NULL,
124 &process,
125 cls);
126 GNUNET_assert (NULL != ic);
127}
128
129
130int
131main (int argc,
132 char *argv[])
133{
134 global_ret = 3;
135 if (0 != GNUNET_TESTING_service_run ("test_peerinfo_shipped_hellos",
136 "peerinfo",
137 "test_peerinfo_api_data.conf",
138 &run, NULL))
139 return 1;
140 return global_ret;
141}
142
143
144/* end of test_peerinfo_shipped_hellos.c */
diff --git a/src/regex/Makefile.am b/src/regex/Makefile.am
index b7d14bc41..b526a0c8c 100644
--- a/src/regex/Makefile.am
+++ b/src/regex/Makefile.am
@@ -94,8 +94,7 @@ libgnunet_plugin_block_regex_la_LDFLAGS = \
94#endif 94#endif
95 95
96noinst_PROGRAMS = $(noinst_mysql_progs) \ 96noinst_PROGRAMS = $(noinst_mysql_progs) \
97 perf-regex \ 97 perf-regex
98 gnunet-regex-profiler
99 98
100perf_regex_SOURCES = \ 99perf_regex_SOURCES = \
101 $(REGEX_INTERNAL_TEST) perf-regex.c 100 $(REGEX_INTERNAL_TEST) perf-regex.c
@@ -107,19 +106,6 @@ perf_regex_LDADD = -lm \
107perf_regex_LDFLAGS = \ 106perf_regex_LDFLAGS = \
108 $(GN_LIBINTL) 107 $(GN_LIBINTL)
109 108
110gnunet_regex_profiler_SOURCES = \
111 $(REGEX_INTERNAL_TEST) gnunet-regex-profiler.c
112gnunet_regex_profiler_LDADD = -lm \
113 $(top_builddir)/src/arm/libgnunetarm.la \
114 $(top_builddir)/src/testing/libgnunettesting.la \
115 $(top_builddir)/src/testbed/libgnunettestbed.la \
116 $(top_builddir)/src/dht/libgnunetdht.la \
117 libgnunetregexblock.la \
118 $(top_builddir)/src/statistics/libgnunetstatistics.la \
119 $(top_builddir)/src/util/libgnunetutil.la
120gnunet_regex_profiler_LDFLAGS = \
121 $(GN_LIBINTL)
122
123gnunet_daemon_regexprofiler_SOURCES = \ 109gnunet_daemon_regexprofiler_SOURCES = \
124 $(REGEX_INTERNAL_TEST) gnunet-daemon-regexprofiler.c 110 $(REGEX_INTERNAL_TEST) gnunet-daemon-regexprofiler.c
125gnunet_daemon_regexprofiler_LDADD = -lm \ 111gnunet_daemon_regexprofiler_LDADD = -lm \
diff --git a/src/secretsharing/Makefile.am b/src/secretsharing/Makefile.am
index b13d5a838..3a86236cd 100644
--- a/src/secretsharing/Makefile.am
+++ b/src/secretsharing/Makefile.am
@@ -16,21 +16,22 @@ endif
16libexec_PROGRAMS = \ 16libexec_PROGRAMS = \
17 gnunet-service-secretsharing 17 gnunet-service-secretsharing
18 18
19noinst_PROGRAMS = \ 19#noinst_PROGRAMS = \
20 gnunet-secretsharing-profiler 20# gnunet-secretsharing-profiler
21 21
22lib_LTLIBRARIES = \ 22lib_LTLIBRARIES = \
23 libgnunetsecretsharing.la 23 libgnunetsecretsharing.la
24 24
25 25
26gnunet_secretsharing_profiler_SOURCES = \ 26# TNG
27 gnunet-secretsharing-profiler.c 27#gnunet_secretsharing_profiler_SOURCES = \
28gnunet_secretsharing_profiler_LDADD = \ 28# gnunet-secretsharing-profiler.c
29 libgnunetsecretsharing.la \ 29#gnunet_secretsharing_profiler_LDADD = \
30 $(top_builddir)/src/testing/libgnunettesting.la \ 30# libgnunetsecretsharing.la \
31 $(top_builddir)/src/testbed/libgnunettestbed.la \ 31# $(top_builddir)/src/testing/libgnunettesting.la \
32 $(top_builddir)/src/util/libgnunetutil.la \ 32# $(top_builddir)/src/testbed/libgnunettestbed.la \
33 $(GN_LIBINTL) 33# $(top_builddir)/src/util/libgnunetutil.la \
34# $(GN_LIBINTL)
34 35
35gnunet_service_secretsharing_SOURCES = \ 36gnunet_service_secretsharing_SOURCES = \
36 gnunet-service-secretsharing.c \ 37 gnunet-service-secretsharing.c \
diff --git a/src/topology/Makefile.am b/src/topology/Makefile.am
index cae2c73b8..aeb05eec7 100644
--- a/src/topology/Makefile.am
+++ b/src/topology/Makefile.am
@@ -36,7 +36,6 @@ gnunet_daemon_topology_LDADD = \
36 $(top_builddir)/src/peerstore/libgnunetpeerstore.la \ 36 $(top_builddir)/src/peerstore/libgnunetpeerstore.la \
37 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 37 $(top_builddir)/src/statistics/libgnunetstatistics.la \
38 $(top_builddir)/src/transport/libgnunettransportapplication.la \ 38 $(top_builddir)/src/transport/libgnunettransportapplication.la \
39 $(top_builddir)/src/ats/libgnunetats.la \
40 $(top_builddir)/src/hello/libgnunethello.la \ 39 $(top_builddir)/src/hello/libgnunethello.la \
41 $(top_builddir)/src/util/libgnunetutil.la \ 40 $(top_builddir)/src/util/libgnunetutil.la \
42 $(GN_LIBINTL) 41 $(GN_LIBINTL)
diff --git a/src/transport/Makefile.am b/src/transport/Makefile.am
index d7d25b7b0..fab32146d 100644
--- a/src/transport/Makefile.am
+++ b/src/transport/Makefile.am
@@ -8,121 +8,26 @@ pkgcfgdir= $(pkgdatadir)/config.d/
8libexecdir= $(pkglibdir)/libexec/ 8libexecdir= $(pkglibdir)/libexec/
9 9
10pkgcfg_DATA = \ 10pkgcfg_DATA = \
11 transport.conf \ 11 transport.conf
12 communicator-unix.conf
13
14HTTP_SERVER_PLUGIN_LA = libgnunet_plugin_transport_http_server.la
15HTTPS_SERVER_PLUGIN_LA = libgnunet_plugin_transport_https_server.la
16HTTP_SERVER_PLUGIN_TEST = test_plugin_http_server
17HTTPS_SERVER_PLUGIN_TEST = test_plugin_https_server
18
19HTTP_CLIENT_PLUGIN_TEST = test_plugin_http_client
20HTTPS_CLIENT_PLUGIN_TEST = test_plugin_https_client
21HTTP_CLIENT_PLUGIN_LA = libgnunet_plugin_transport_http_client.la
22HTTPS_CLIENT_PLUGIN_LA = libgnunet_plugin_transport_https_client.la
23
24HTTP_API_TEST = test_transport_api_http
25HTTP_REVERSE_API_TEST = test_transport_api_http_reverse
26HTTP_API_TIMEOUT_TEST = test_transport_api_timeout_http
27HTTP_REL_TEST = test_transport_api_reliability_http \
28 test_transport_api_reliability_http_xhr
29HTTP_QUOTA_TEST = test_quota_compliance_http \
30 test_quota_compliance_http_asymmetric
31HTTP_SWITCH = test_transport_address_switch_http
32HTTPS_API_TEST = test_transport_api_https
33HTTPS_API_TIMEOUT_TEST = test_transport_api_timeout_https
34if HAVE_EXPERIMENTAL
35 HTTPS_REL_TEST = test_transport_api_reliability_https \
36 test_transport_api_reliability_https_xhr
37endif
38HTTPS_QUOTA_TEST = test_quota_compliance_https \
39 test_quota_compliance_https_asymmetric
40HTTPS_SWITCH = test_transport_address_switch_https
41 12
42if USE_COVERAGE 13if USE_COVERAGE
43 AM_CFLAGS = --coverage -O0 14 AM_CFLAGS = --coverage -O0
44endif 15endif
45 16
46if HAVE_EXPERIMENTAL
47if LINUX
48 WLAN_BIN = gnunet-helper-transport-wlan
49 WLAN_BIN_DUMMY = gnunet-helper-transport-wlan-dummy
50 WLAN_BIN_SENDER = gnunet-transport-wlan-sender
51 WLAN_BIN_RECEIVER = gnunet-transport-wlan-receiver
52 WLAN_PLUGIN_LA = libgnunet_plugin_transport_wlan.la
53 WLAN_PLUGIN_TEST = test_plugin_wlan
54 WLAN_API_TEST = test_transport_api_wlan
55 WLAN_TIMEOUT_TEST = test_transport_api_timeout_wlan
56 WLAN_REL_TEST = test_transport_api_reliability_wlan
57 WLAN_QUOTA_TEST = test_quota_compliance_wlan \
58 test_quota_compliance_wlan_asymmetric
59endif
60
61if LINUX
62if HAVE_LIBBLUETOOTH
63 BT_BIN = gnunet-helper-transport-bluetooth
64 BT_PLUGIN_LA = libgnunet_plugin_transport_bluetooth.la
65 BT_PLUGIN_TEST = test_plugin_bluetooth
66 BT_API_TEST = test_transport_api_bluetooth
67 BT_TIMEOUT_TEST = test_transport_api_timeout_bluetooth
68 BT_REL_TEST = test_transport_api_reliability_bluetooth
69 BT_QUOTA_TEST = test_quota_compliance_bluetooth \
70 test_quota_compliance_bluetooth_asymmetric
71endif
72endif
73
74# end of HAVE_EXPERIMENTAL
75endif
76
77
78UNIX_PLUGIN_LA = libgnunet_plugin_transport_unix.la
79UNIX_PLUGIN_TEST = test_transport_api_unix
80UNIX_TEST = test_plugin_unix
81UNIX_PLUGIN_TIMEOUT_TEST = test_transport_api_timeout_unix
82UNIX_REL_TEST = test_transport_api_reliability_unix
83UNIX_QUOTA_TEST = test_quota_compliance_unix \
84 test_quota_compliance_unix_asymmetric
85if LINUX
86 UNIX_API_ABSTRACT_TEST = test_transport_api_unix_abstract
87endif
88
89
90noinst_PROGRAMS = \ 17noinst_PROGRAMS = \
91 test_transport_start_with_config \ 18 test_transport_start_with_config \
92 gnunet-transport-profiler \ 19 gnunet-communicator-udp
93 gnunet-communicator-udp \
94 $(WLAN_BIN_SENDER) \
95 $(WLAN_BIN_RECEIVER)
96 20
97TESTING_LIBS = \ 21TESTING_LIBS = \
98 libgnunettransporttesting.la \
99 libgnunettransporttesting2.la 22 libgnunettransporttesting2.la
100 23
101lib_LTLIBRARIES = \ 24lib_LTLIBRARIES = \
102 libgnunettransport.la \
103 libgnunettransportapplication.la \ 25 libgnunettransportapplication.la \
104 libgnunettransportcore.la \ 26 libgnunettransportcore.la \
105 libgnunettransportcommunicator.la \ 27 libgnunettransportcommunicator.la \
106 libgnunettransportmonitor.la \ 28 libgnunettransportmonitor.la \
107 $(TESTING_LIBS) 29 $(TESTING_LIBS)
108 30
109libgnunettransporttesting_la_SOURCES = \
110 transport-testing.c transport-testing.h \
111 transport-testing-filenames.c \
112 transport-testing-loggers.c \
113 transport-testing-main.c \
114 transport-testing-send.c
115libgnunettransporttesting_la_LIBADD = \
116 libgnunettransport.la \
117 $(top_builddir)/src/hello/libgnunethello.la \
118 $(top_builddir)/src/ats/libgnunetats.la \
119 $(top_builddir)/src/util/libgnunetutil.la \
120 $(top_builddir)/src/testing/libgnunettesting.la \
121 $(top_builddir)/src/arm/libgnunetarm.la \
122 $(GN_LIBINTL)
123libgnunettransporttesting_la_LDFLAGS = \
124 $(GN_LIB_LDFLAGS)
125
126libgnunettransporttesting2_la_SOURCES = \ 31libgnunettransporttesting2_la_SOURCES = \
127 transport_api_traits.c \ 32 transport_api_traits.c \
128 transport_api_cmd_connecting_peers.c \ 33 transport_api_cmd_connecting_peers.c \
@@ -143,7 +48,6 @@ libgnunettransporttesting2_la_LIBADD = \
143 libgnunettransportcore.la \ 48 libgnunettransportcore.la \
144 $(top_builddir)/src/arm/libgnunetarm.la \ 49 $(top_builddir)/src/arm/libgnunetarm.la \
145 $(top_builddir)/src/testing/libgnunettesting.la \ 50 $(top_builddir)/src/testing/libgnunettesting.la \
146 $(top_builddir)/src/ats/libgnunetats.la \
147 $(top_builddir)/src/hello/libgnunethello.la \ 51 $(top_builddir)/src/hello/libgnunethello.la \
148 $(top_builddir)/src/peerstore/libgnunetpeerstore.la \ 52 $(top_builddir)/src/peerstore/libgnunetpeerstore.la \
149 $(top_builddir)/src/util/libgnunetutil.la 53 $(top_builddir)/src/util/libgnunetutil.la
@@ -152,26 +56,6 @@ libgnunettransporttesting2_la_LDFLAGS = \
152 $(GN_LIB_LDFLAGS) \ 56 $(GN_LIB_LDFLAGS) \
153 -version-info 0:0:0 57 -version-info 0:0:0
154 58
155libgnunettransport_la_SOURCES = \
156 transport.h \
157 transport_api_address_to_string.c \
158 transport_api_blacklist.c \
159 transport_api_core.c \
160 transport_api_hello_get.c \
161 transport_api_manipulation.c \
162 transport_api_monitor_peers.c \
163 transport_api_monitor_plugins.c \
164 transport_api_offer_hello.c
165
166libgnunettransport_la_LIBADD = \
167 $(top_builddir)/src/hello/libgnunethello.la \
168 $(top_builddir)/src/ats/libgnunetats.la \
169 $(top_builddir)/src/util/libgnunetutil.la \
170 $(GN_LIBINTL)
171libgnunettransport_la_LDFLAGS = \
172 $(GN_LIB_LDFLAGS) \
173 -version-info 4:0:2
174
175libgnunettransportapplication_la_SOURCES = \ 59libgnunettransportapplication_la_SOURCES = \
176 transport_api2_application.c 60 transport_api2_application.c
177libgnunettransportapplication_la_LIBADD = \ 61libgnunettransportapplication_la_LIBADD = \
@@ -212,10 +96,6 @@ libgnunettransportmonitor_la_LDFLAGS = \
212 96
213 97
214libexec_PROGRAMS = \ 98libexec_PROGRAMS = \
215 $(WLAN_BIN) \
216 $(WLAN_BIN_DUMMY) \
217 $(BT_BIN) \
218 gnunet-service-transport \
219 gnunet-service-tng \ 99 gnunet-service-tng \
220 gnunet-communicator-unix \ 100 gnunet-communicator-unix \
221 gnunet-communicator-udp \ 101 gnunet-communicator-udp \
@@ -228,8 +108,8 @@ endif
228endif 108endif
229 109
230 110
231bin_PROGRAMS = \ 111#bin_PROGRAMS = \
232 gnunet-transport 112# gnunet-transport
233 113
234bin_SCRIPTS = \ 114bin_SCRIPTS = \
235 gnunet-transport-certificate-creation 115 gnunet-transport-certificate-creation
@@ -291,74 +171,22 @@ gnunet_communicator_quic_LDADD = \
291endif 171endif
292endif 172endif
293 173
294gnunet_helper_transport_wlan_SOURCES = \ 174#gnunet_transport_profiler_SOURCES = \
295 gnunet-helper-transport-wlan.c 175# gnunet-transport-profiler.c
296 176#gnunet_transport_profiler_LDADD = \
297gnunet_helper_transport_wlan_dummy_SOURCES = \ 177# libgnunettransport.la \
298 gnunet-helper-transport-wlan-dummy.c 178# $(top_builddir)/src/hello/libgnunethello.la \
299gnunet_helper_transport_wlan_dummy_LDADD = \ 179# $(top_builddir)/src/ats/libgnunetats.la \
300 $(top_builddir)/src/util/libgnunetutil.la 180# $(top_builddir)/src/util/libgnunetutil.la \
301 181# $(GN_LIBINTL)
302gnunet_transport_wlan_sender_SOURCES = \ 182
303 gnunet-transport-wlan-sender.c 183#gnunet_transport_SOURCES = \
304gnunet_transport_wlan_sender_LDADD = \ 184# gnunet-transport.c
305 $(top_builddir)/src/util/libgnunetutil.la 185#gnunet_transport_LDADD = \
306 186# libgnunettransport.la \
307gnunet_transport_wlan_receiver_SOURCES = \ 187# $(top_builddir)/src/hello/libgnunethello.la \
308 gnunet-transport-wlan-receiver.c 188# $(top_builddir)/src/util/libgnunetutil.la \
309gnunet_transport_wlan_receiver_LDADD = \ 189# $(GN_LIBINTL)
310 $(top_builddir)/src/util/libgnunetutil.la
311
312gnunet_helper_transport_bluetooth_SOURCES = \
313 gnunet-helper-transport-bluetooth.c
314
315gnunet_helper_transport_bluetooth_LDFLAGS = -lbluetooth
316
317
318gnunet_transport_profiler_SOURCES = \
319 gnunet-transport-profiler.c
320gnunet_transport_profiler_LDADD = \
321 libgnunettransport.la \
322 $(top_builddir)/src/hello/libgnunethello.la \
323 $(top_builddir)/src/ats/libgnunetats.la \
324 $(top_builddir)/src/util/libgnunetutil.la \
325 $(GN_LIBINTL)
326
327gnunet_transport_SOURCES = \
328 gnunet-transport.c
329gnunet_transport_LDADD = \
330 libgnunettransport.la \
331 $(top_builddir)/src/hello/libgnunethello.la \
332 $(top_builddir)/src/util/libgnunetutil.la \
333 $(GN_LIBINTL)
334
335gnunet_service_transport_SOURCES = \
336 gnunet-service-transport.c gnunet-service-transport.h \
337 gnunet-service-transport_ats.h gnunet-service-transport_ats.c \
338 gnunet-service-transport_hello.h gnunet-service-transport_hello.c \
339 gnunet-service-transport_neighbours.h gnunet-service-transport_neighbours.c \
340 gnunet-service-transport_plugins.h gnunet-service-transport_plugins.c \
341 gnunet-service-transport_validation.h gnunet-service-transport_validation.c \
342 gnunet-service-transport_manipulation.h gnunet-service-transport_manipulation.c
343# Note that while gnunet-service-transport does not use libgnunetnat
344# directly, we must link against it as GNUNET_NAT_mini_map_stop will
345# leave a 'dangling' task to process_unmap_output which will cause
346# a crash on unloading of a plugin unless the service links against
347# that library as well.
348gnunet_service_transport_LDADD = \
349 libgnunettransport.la \
350 $(top_builddir)/src/ats/libgnunetats.la \
351 $(top_builddir)/src/hello/libgnunethello.la \
352 $(top_builddir)/src/nt/libgnunetnt.la \
353 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
354 $(top_builddir)/src/statistics/libgnunetstatistics.la \
355 $(top_builddir)/src/util/libgnunetutil.la \
356 $(GN_GLPK) \
357 $(GN_LIBINTL)
358gnunet_service_transport_CFLAGS = \
359 $(AM_CFLAGS)
360# -DANALYZE
361
362 190
363gnunet_service_tng_SOURCES = \ 191gnunet_service_tng_SOURCES = \
364 gnunet-service-tng.c 192 gnunet-service-tng.c
@@ -371,20 +199,12 @@ gnunet_service_tng_LDADD = \
371 $(GN_LIBINTL) 199 $(GN_LIBINTL)
372 200
373plugin_LTLIBRARIES = \ 201plugin_LTLIBRARIES = \
374 libgnunet_plugin_transport_tcp.la \
375 $(UNIX_PLUGIN_LA) \
376 $(HTTP_CLIENT_PLUGIN_LA) \
377 $(HTTPS_CLIENT_PLUGIN_LA) \
378 $(HTTP_SERVER_PLUGIN_LA) \
379 $(HTTPS_SERVER_PLUGIN_LA) \
380 $(WLAN_PLUGIN_LA) \
381 $(BT_PLUGIN_LA) \
382 libgnunet_test_transport_plugin_cmd_simple_send_performance.la \ 202 libgnunet_test_transport_plugin_cmd_simple_send_performance.la \
383 libgnunet_test_transport_plugin_cmd_nat_upnp.la \ 203 libgnunet_test_transport_plugin_cmd_nat_upnp.la \
384 libgnunet_test_transport_plugin_cmd_simple_send.la \ 204 libgnunet_test_transport_plugin_cmd_simple_send.la \
385 libgnunet_test_transport_plugin_cmd_simple_send_broadcast.la \ 205 libgnunet_test_transport_plugin_cmd_simple_send_broadcast.la \
386 libgnunet_test_transport_plugin_cmd_simple_send_dv.la \ 206 libgnunet_test_transport_plugin_cmd_simple_send_dv.la \
387 libgnunet_test_transport_plugin_cmd_udp_backchannel.la 207 libgnunet_test_transport_plugin_cmd_udp_backchannel.la
388 208
389libgnunet_test_transport_plugin_cmd_nat_upnp_la_SOURCES = \ 209libgnunet_test_transport_plugin_cmd_nat_upnp_la_SOURCES = \
390 test_transport_plugin_cmd_nat_upnp.c 210 test_transport_plugin_cmd_nat_upnp.c
@@ -396,7 +216,6 @@ libgnunet_test_transport_plugin_cmd_nat_upnp_la_LIBADD = \
396 $(top_builddir)/src/peerstore/libgnunetpeerstore.la \ 216 $(top_builddir)/src/peerstore/libgnunetpeerstore.la \
397 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 217 $(top_builddir)/src/statistics/libgnunetstatistics.la \
398 $(top_builddir)/src/hello/libgnunethello.la \ 218 $(top_builddir)/src/hello/libgnunethello.la \
399 $(top_builddir)/src/ats/libgnunetats.la \
400 $(top_builddir)/src/arm/libgnunetarm.la \ 219 $(top_builddir)/src/arm/libgnunetarm.la \
401 $(top_builddir)/src/util/libgnunetutil.la \ 220 $(top_builddir)/src/util/libgnunetutil.la \
402 $(LTLIBINTL) 221 $(LTLIBINTL)
@@ -413,7 +232,6 @@ libgnunet_test_transport_plugin_cmd_udp_backchannel_la_LIBADD = \
413 $(top_builddir)/src/peerstore/libgnunetpeerstore.la \ 232 $(top_builddir)/src/peerstore/libgnunetpeerstore.la \
414 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 233 $(top_builddir)/src/statistics/libgnunetstatistics.la \
415 $(top_builddir)/src/hello/libgnunethello.la \ 234 $(top_builddir)/src/hello/libgnunethello.la \
416 $(top_builddir)/src/ats/libgnunetats.la \
417 $(top_builddir)/src/arm/libgnunetarm.la \ 235 $(top_builddir)/src/arm/libgnunetarm.la \
418 $(top_builddir)/src/util/libgnunetutil.la \ 236 $(top_builddir)/src/util/libgnunetutil.la \
419 $(LTLIBINTL) 237 $(LTLIBINTL)
@@ -430,7 +248,6 @@ libgnunet_test_transport_plugin_cmd_simple_send_la_LIBADD = \
430 $(top_builddir)/src/peerstore/libgnunetpeerstore.la \ 248 $(top_builddir)/src/peerstore/libgnunetpeerstore.la \
431 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 249 $(top_builddir)/src/statistics/libgnunetstatistics.la \
432 $(top_builddir)/src/hello/libgnunethello.la \ 250 $(top_builddir)/src/hello/libgnunethello.la \
433 $(top_builddir)/src/ats/libgnunetats.la \
434 $(top_builddir)/src/arm/libgnunetarm.la \ 251 $(top_builddir)/src/arm/libgnunetarm.la \
435 $(top_builddir)/src/util/libgnunetutil.la \ 252 $(top_builddir)/src/util/libgnunetutil.la \
436 $(LTLIBINTL) 253 $(LTLIBINTL)
@@ -447,7 +264,6 @@ libgnunet_test_transport_plugin_cmd_simple_send_performance_la_LIBADD = \
447 $(top_builddir)/src/peerstore/libgnunetpeerstore.la \ 264 $(top_builddir)/src/peerstore/libgnunetpeerstore.la \
448 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 265 $(top_builddir)/src/statistics/libgnunetstatistics.la \
449 $(top_builddir)/src/hello/libgnunethello.la \ 266 $(top_builddir)/src/hello/libgnunethello.la \
450 $(top_builddir)/src/ats/libgnunetats.la \
451 $(top_builddir)/src/arm/libgnunetarm.la \ 267 $(top_builddir)/src/arm/libgnunetarm.la \
452 $(top_builddir)/src/util/libgnunetutil.la \ 268 $(top_builddir)/src/util/libgnunetutil.la \
453 $(LTLIBINTL) 269 $(LTLIBINTL)
@@ -464,7 +280,6 @@ libgnunet_test_transport_plugin_cmd_simple_send_broadcast_la_LIBADD = \
464 $(top_builddir)/src/peerstore/libgnunetpeerstore.la \ 280 $(top_builddir)/src/peerstore/libgnunetpeerstore.la \
465 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 281 $(top_builddir)/src/statistics/libgnunetstatistics.la \
466 $(top_builddir)/src/hello/libgnunethello.la \ 282 $(top_builddir)/src/hello/libgnunethello.la \
467 $(top_builddir)/src/ats/libgnunetats.la \
468 $(top_builddir)/src/arm/libgnunetarm.la \ 283 $(top_builddir)/src/arm/libgnunetarm.la \
469 $(top_builddir)/src/util/libgnunetutil.la \ 284 $(top_builddir)/src/util/libgnunetutil.la \
470 $(LTLIBINTL) 285 $(LTLIBINTL)
@@ -481,313 +296,41 @@ libgnunet_test_transport_plugin_cmd_simple_send_dv_la_LIBADD = \
481 $(top_builddir)/src/peerstore/libgnunetpeerstore.la \ 296 $(top_builddir)/src/peerstore/libgnunetpeerstore.la \
482 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 297 $(top_builddir)/src/statistics/libgnunetstatistics.la \
483 $(top_builddir)/src/hello/libgnunethello.la \ 298 $(top_builddir)/src/hello/libgnunethello.la \
484 $(top_builddir)/src/ats/libgnunetats.la \
485 $(top_builddir)/src/arm/libgnunetarm.la \ 299 $(top_builddir)/src/arm/libgnunetarm.la \
486 $(top_builddir)/src/util/libgnunetutil.la \ 300 $(top_builddir)/src/util/libgnunetutil.la \
487 $(LTLIBINTL) 301 $(LTLIBINTL)
488libgnunet_test_transport_plugin_cmd_simple_send_dv_la_LDFLAGS = \ 302libgnunet_test_transport_plugin_cmd_simple_send_dv_la_LDFLAGS = \
489 $(GN_PLUGIN_LDFLAGS) 303 $(GN_PLUGIN_LDFLAGS)
490 304
491if HAVE_EXPERIMENTAL
492plugin_LTLIBRARIES += \
493 libgnunet_plugin_transport_udp.la
494endif
495
496# Note: real plugins of course need to be added
497# to the plugin_LTLIBRARIES above
498noinst_LTLIBRARIES = \
499 libgnunet_plugin_transport_template.la
500
501libgnunet_plugin_transport_tcp_la_SOURCES = \
502 plugin_transport_tcp.c
503libgnunet_plugin_transport_tcp_la_LIBADD = \
504 $(top_builddir)/src/hello/libgnunethello.la \
505 $(top_builddir)/src/statistics/libgnunetstatistics.la \
506 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
507 $(top_builddir)/src/nat/libgnunetnatnew.la \
508 $(top_builddir)/src/util/libgnunetutil.la \
509 $(LTLIBINTL)
510libgnunet_plugin_transport_tcp_la_LDFLAGS = \
511 $(GN_PLUGIN_LDFLAGS)
512
513libgnunet_plugin_transport_template_la_SOURCES = \
514 plugin_transport_template.c
515libgnunet_plugin_transport_template_la_LIBADD = \
516 $(top_builddir)/src/util/libgnunetutil.la \
517 $(LTLIBINTL)
518libgnunet_plugin_transport_template_la_LDFLAGS = \
519 $(GN_PLUGIN_LDFLAGS)
520
521libgnunet_plugin_transport_wlan_la_SOURCES = \
522 plugin_transport_wlan.c plugin_transport_wlan.h
523libgnunet_plugin_transport_wlan_la_LIBADD = \
524 $(top_builddir)/src/hello/libgnunethello.la \
525 $(top_builddir)/src/statistics/libgnunetstatistics.la \
526 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
527 $(top_builddir)/src/fragmentation/libgnunetfragmentation.la \
528 $(top_builddir)/src/util/libgnunetutil.la
529libgnunet_plugin_transport_wlan_la_LDFLAGS = \
530 $(GN_PLUGIN_LDFLAGS)
531libgnunet_plugin_transport_wlan_la_CFLAGS = \
532 $(AM_CFLAGS) -DBUILD_WLAN
533
534libgnunet_plugin_transport_bluetooth_la_SOURCES = \
535 plugin_transport_wlan.c plugin_transport_wlan.h
536libgnunet_plugin_transport_bluetooth_la_LIBADD = \
537 $(top_builddir)/src/hello/libgnunethello.la \
538 $(top_builddir)/src/statistics/libgnunetstatistics.la \
539 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
540 $(top_builddir)/src/fragmentation/libgnunetfragmentation.la \
541 $(top_builddir)/src/util/libgnunetutil.la
542libgnunet_plugin_transport_bluetooth_la_LDFLAGS = \
543 $(GN_PLUGIN_LDFLAGS)
544libgnunet_plugin_transport_bluetooth_la_CFLAGS = \
545 $(AM_CFLAGS) -DBUILD_BLUETOOTH
546
547if HAVE_EXPERIMENTAL
548libgnunet_plugin_transport_udp_la_SOURCES = \
549 plugin_transport_udp.c plugin_transport_udp.h \
550 plugin_transport_udp_broadcasting.c
551libgnunet_plugin_transport_udp_la_LIBADD = \
552 $(top_builddir)/src/hello/libgnunethello.la \
553 $(top_builddir)/src/fragmentation/libgnunetfragmentation.la \
554 $(top_builddir)/src/statistics/libgnunetstatistics.la \
555 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
556 $(top_builddir)/src/nat/libgnunetnatnew.la \
557 $(top_builddir)/src/util/libgnunetutil.la \
558 $(LTLIBINTL)
559libgnunet_plugin_transport_udp_la_LDFLAGS = \
560 $(GN_PLUGIN_LDFLAGS)
561endif
562
563libgnunet_plugin_transport_unix_la_SOURCES = \
564 plugin_transport_unix.c
565libgnunet_plugin_transport_unix_la_LIBADD = \
566 $(top_builddir)/src/hello/libgnunethello.la \
567 $(top_builddir)/src/statistics/libgnunetstatistics.la \
568 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
569 $(top_builddir)/src/util/libgnunetutil.la \
570 $(LTLIBINTL)
571libgnunet_plugin_transport_unix_la_LDFLAGS = \
572 $(GN_PLUGIN_LDFLAGS)
573
574
575libgnunet_plugin_transport_http_client_la_SOURCES = \
576 plugin_transport_http_client.c plugin_transport_http_common.c plugin_transport_http_common.h
577libgnunet_plugin_transport_http_client_la_LIBADD = \
578 $(top_builddir)/src/hello/libgnunethello.la \
579 $(top_builddir)/src/statistics/libgnunetstatistics.la \
580 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
581 @LIBCURL@ \
582 $(top_builddir)/src/util/libgnunetutil.la
583libgnunet_plugin_transport_http_client_la_LDFLAGS = \
584 $(GN_LIBINTL) \
585 $(GN_PLUGIN_LDFLAGS)
586libgnunet_plugin_transport_http_client_la_CFLAGS = \
587 @LIBCURL_CPPFLAGS@ $(AM_CFLAGS)
588
589
590libgnunet_plugin_transport_http_server_la_SOURCES = \
591 plugin_transport_http_server.c plugin_transport_http_common.c
592libgnunet_plugin_transport_http_server_la_LIBADD = \
593 $(MHD_LIBS) \
594 $(top_builddir)/src/hello/libgnunethello.la \
595 $(top_builddir)/src/statistics/libgnunetstatistics.la \
596 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
597 $(top_builddir)/src/nat/libgnunetnatnew.la \
598 $(top_builddir)/src/util/libgnunetutil.la
599libgnunet_plugin_transport_http_server_la_LDFLAGS = \
600 $(GN_LIBINTL) \
601 $(GN_PLUGIN_LDFLAGS)
602libgnunet_plugin_transport_http_server_la_CFLAGS = \
603 $(MHD_CFLAGS) $(AM_CFLAGS)
604
605libgnunet_plugin_transport_https_client_la_SOURCES = \
606 plugin_transport_http_client.c plugin_transport_http_common.c
607libgnunet_plugin_transport_https_client_la_LIBADD = \
608 $(top_builddir)/src/hello/libgnunethello.la \
609 $(top_builddir)/src/statistics/libgnunetstatistics.la \
610 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
611 @LIBCURL@ \
612 $(top_builddir)/src/util/libgnunetutil.la
613libgnunet_plugin_transport_https_client_la_LDFLAGS = \
614 $(GN_LIBINTL) \
615 $(GN_PLUGIN_LDFLAGS)
616libgnunet_plugin_transport_https_client_la_CFLAGS = \
617 @LIBCURL_CPPFLAGS@ $(AM_CFLAGS) -DBUILD_HTTPS
618
619
620libgnunet_plugin_transport_https_server_la_SOURCES = \
621 plugin_transport_http_server.c plugin_transport_http_common.c
622libgnunet_plugin_transport_https_server_la_LIBADD = \
623 $(MHD_LIBS) \
624 $(top_builddir)/src/hello/libgnunethello.la \
625 $(top_builddir)/src/statistics/libgnunetstatistics.la \
626 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
627 $(top_builddir)/src/nat/libgnunetnatnew.la \
628 $(top_builddir)/src/util/libgnunetutil.la
629libgnunet_plugin_transport_https_server_la_LDFLAGS = \
630 $(GN_LIBINTL) \
631 $(GN_PLUGIN_LDFLAGS)
632libgnunet_plugin_transport_https_server_la_CFLAGS = \
633 $(MHD_CFLAGS) $(AM_CFLAGS) -DBUILD_HTTPS
634
635check_PROGRAMS = \ 305check_PROGRAMS = \
636 test_transport_address_switch_tcp \ 306 test_communicator_basic-unix \
637 test_transport_testing_startstop \ 307 test_communicator_basic-tcp \
638 test_transport_testing_restart \ 308 test_communicator_basic-udp \
639 test_plugin_tcp \ 309 test_communicator_basic-quic \
640 $(UNIX_TEST) \ 310 test_communicator_rekey-tcp \
641 $(WLAN_PLUGIN_TEST) \ 311 test_communicator_rekey-udp \
642 $(BT_PLUGIN_TEST) \ 312 test_communicator_backchannel-udp \
643 test_http_common \ 313 test_communicator_bidirect-tcp
644 $(HTTP_CLIENT_PLUGIN_TEST) \ 314
645 $(HTTPS_CLIENT_PLUGIN_TEST) \ 315# Only test TNG if we run experimental
646 $(HTTP_SERVER_PLUGIN_TEST) \
647 $(HTTPS_SERVER_PLUGIN_TEST) \
648 test_transport_api_blacklisting_tcp \
649 test_transport_api_disconnect_tcp \
650 test_transport_api_tcp \
651 test_transport_api2_tcp \
652 test_transport_api_restart_1peer \
653 test_transport_api_restart_2peers \
654 test_transport_api_timeout_tcp \
655 test_transport_api_limited_sockets_tcp \
656 test_transport_api_tcp_nat \
657 $(UNIX_PLUGIN_TEST) \
658 $(UNIX_PLUGIN_TIMEOUT_TEST) \
659 $(UNIX_API_ABSTRACT_TEST) \
660 $(HTTP_API_TEST) \
661 $(HTTP_REVERSE_API_TEST) \
662 $(HTTP_API_TIMEOUT_TEST) \
663 $(HTTP_SWITCH) \
664 $(HTTPS_API_TEST) \
665 $(HTTPS_API_TIMEOUT_TEST) \
666 $(HTTPS_SWITCH) \
667 $(WLAN_API_TEST) \
668 $(WLAN_TIMEOUT_TEST) \
669 $(BT_API_TEST) \
670 $(BT_TIMEOUT_TEST) \
671 test_transport_api_multi \
672 test_transport_api_monitor_peers \
673 test_transport_blacklisting_no_bl \
674 test_transport_blacklisting_outbound_bl_full \
675 test_transport_blacklisting_outbound_bl_plugin \
676 test_transport_blacklisting_inbound_bl_plugin \
677 test_transport_blacklisting_inbound_bl_full \
678 test_transport_blacklisting_multiple_plugins \
679 test_transport_api_manipulation_send_tcp \
680 test_transport_api_manipulation_recv_tcp \
681 test_transport_api_manipulation_cfg \
682 test_transport_api_reliability_tcp \
683 test_transport_api_reliability_tcp_nat \
684 $(UNIX_REL_TEST) \
685 $(HTTP_REL_TEST) \
686 $(HTTPS_REL_TEST) \
687 $(WLAN_REL_TEST) \
688 $(WLAN_UREL_TEST) \
689 $(BT_REL_TEST) \
690 $(BT_UREL_TEST) \
691 test_quota_compliance_tcp \
692 test_quota_compliance_tcp_asymmetric \
693 $(UNIX_QUOTA_TEST) \
694 $(HTTP_QUOTA_TEST) \
695 $(HTTPS_QUOTA_TEST) \
696 $(WLAN_QUOTA_TEST) \
697 $(BT_QUOTA_TEST)
698if HAVE_GETOPT_BINARY
699check_PROGRAMS += \
700test_transport_api_slow_ats
701endif
702if HAVE_EXPERIMENTAL 316if HAVE_EXPERIMENTAL
703check_PROGRAMS += \ 317check_SCRIPTS= \
704 test_transport_address_switch_udp \ 318 test_transport_start_testcase.sh \
705 test_plugin_udp \ 319 test_transport_simple_send_performance.sh \
706 test_transport_api_udp \ 320 test_transport_nat_icmp_tcp.sh \
707 test_transport_api_timeout_udp \ 321 test_transport_nat_upnp.sh \
708 test_transport_api_udp_nat \ 322 test_transport_simple_send_string.sh \
709 test_transport_api_reliability_udp \ 323 test_transport_simple_send.sh \
710 test_quota_compliance_udp \ 324 test_transport_simple_send_broadcast.sh \
711 test_communicator_basic-unix \ 325 test_transport_udp_backchannel.sh \
712 test_communicator_basic-tcp \ 326 test_transport_simple_send_dv_circle.sh \
713 test_communicator_basic-udp \ 327 test_transport_simple_send_dv_inverse.sh
714 test_communicator_basic-quic \
715 test_communicator_rekey-tcp \
716 test_communicator_rekey-udp \
717 test_communicator_backchannel-udp \
718 test_communicator_bidirect-tcp
719endif 328endif
720 329
721if ENABLE_TEST_RUN 330if ENABLE_TEST_RUN
722AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME; 331AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
723TESTS = \ 332TESTS = \
724 test_transport_address_switch_tcp \ 333 $(check_SCRIPTS) \
725 $(HTTP_SWITCH) \
726 $(HTTPS_SWITCH) \
727 test_transport_testing_startstop \
728 test_transport_testing_restart \
729 test_plugin_tcp \
730 $(UNIX_TEST) \
731 $(WLAN_PLUGIN_TEST) \
732 $(BT_PLUGIN_TEST) \
733 test_transport_api_blacklisting_tcp \
734 test_transport_api_disconnect_tcp \
735 test_transport_api_tcp \
736 test_transport_api_restart_1peer \
737 test_transport_api_restart_2peers \
738 test_transport_api_limited_sockets_tcp \
739 test_transport_api_tcp_nat \
740 $(UNIX_PLUGIN_TEST) \
741 $(UNIX_API_ABSTRACT_TEST) \
742 $(HTTP_API_TEST) \
743 $(HTTPS_API_TEST) \
744 $(WLAN_API_TEST) \
745 $(BT_API_TEST) \
746 test_transport_api_multi \
747 test_transport_api_monitor_peers \
748 test_transport_blacklisting_no_bl \
749 test_transport_blacklisting_outbound_bl_full \
750 test_transport_blacklisting_outbound_bl_plugin \
751 test_transport_blacklisting_inbound_bl_plugin \
752 test_transport_blacklisting_inbound_bl_full \
753 test_transport_blacklisting_multiple_plugins \
754 test_transport_api_manipulation_send_tcp \
755 test_transport_api_manipulation_recv_tcp \
756 test_transport_api_manipulation_cfg \
757 test_transport_api_reliability_tcp \
758 test_transport_api_reliability_tcp_nat \
759 $(UNIX_REL_TEST) \
760 $(HTTP_REL_TEST) \
761 $(HTTPS_REL_TEST) \
762 $(WLAN_REL_TEST) \
763 $(WLAN_UREL_TEST) \
764 $(BT_REL_TEST) \
765 $(BT_UREL_TEST) \
766 test_quota_compliance_tcp \
767 test_quota_compliance_tcp_asymmetric \
768 $(UNIX_QUOTA_TEST) \
769 $(HTTP_QUOTA_TEST) \
770 $(HTTPS_QUOTA_TEST) \
771 test_transport_api_timeout_tcp \
772 $(UNIX_PLUGIN_TIMEOUT_TEST) \
773 $(HTTP_API_TIMEOUT_TEST) \
774 $(HTTPS_API_TIMEOUT_TEST) \
775 $(WLAN_TIMEOUT_TEST) \
776 $(BT_TIMEOUT_TEST) \
777 $(check_SCRIPTS)
778if HAVE_GETOPT_BINARY
779TESTS += \
780test_transport_api_slow_ats
781endif
782if HAVE_EXPERIMENTAL
783TESTS += \
784 test_transport_address_switch_udp \
785 test_plugin_udp \
786 test_transport_api_udp \
787 test_transport_api_timeout_udp \
788 test_transport_api_udp_nat \
789 test_transport_api_reliability_udp \
790 test_quota_compliance_udp \
791 test_communicator_basic-unix \ 334 test_communicator_basic-unix \
792 test_communicator_basic-tcp \ 335 test_communicator_basic-tcp \
793 test_communicator_basic-quic \ 336 test_communicator_basic-quic \
@@ -797,22 +340,7 @@ TESTS += \
797 test_communicator_backchannel-udp \ 340 test_communicator_backchannel-udp \
798 test_communicator_bidirect-tcp 341 test_communicator_bidirect-tcp
799endif 342endif
800endif
801 343
802# Only test TNG if we run experimental
803if HAVE_EXPERIMENTAL
804check_SCRIPTS= \
805 test_transport_start_testcase.sh \
806 test_transport_simple_send_performance.sh \
807 test_transport_nat_icmp_tcp.sh \
808 test_transport_nat_upnp.sh \
809 test_transport_simple_send_string.sh \
810 test_transport_simple_send.sh \
811 test_transport_simple_send_broadcast.sh \
812 test_transport_udp_backchannel.sh \
813 test_transport_simple_send_dv_circle.sh \
814 test_transport_simple_send_dv_inverse.sh
815endif
816 344
817test_transport_start_with_config_SOURCES = \ 345test_transport_start_with_config_SOURCES = \
818 test_transport_start_with_config.c 346 test_transport_start_with_config.c
@@ -823,116 +351,6 @@ test_transport_start_with_config_LDADD = \
823 libgnunettransportcore.la \ 351 libgnunettransportcore.la \
824 libgnunettransporttesting2.la 352 libgnunettransporttesting2.la
825 353
826test_transport_testing_startstop_SOURCES = \
827 test_transport_testing_startstop.c
828test_transport_testing_startstop_LDADD = \
829 $(top_builddir)/src/util/libgnunetutil.la \
830 libgnunettransport.la \
831 $(top_builddir)/src/hello/libgnunethello.la \
832 libgnunettransporttesting.la
833
834test_transport_testing_restart_SOURCES = \
835 test_transport_testing_restart.c
836test_transport_testing_restart_LDADD = \
837 $(top_builddir)/src/util/libgnunetutil.la \
838 libgnunettransport.la \
839 $(top_builddir)/src/hello/libgnunethello.la \
840 libgnunettransporttesting.la
841
842test_transport_api_blacklisting_tcp_SOURCES = \
843 test_transport_api_blacklisting.c
844test_transport_api_blacklisting_tcp_LDADD = \
845 libgnunettransport.la \
846 $(top_builddir)/src/hello/libgnunethello.la \
847 $(top_builddir)/src/statistics/libgnunetstatistics.la \
848 $(top_builddir)/src/util/libgnunetutil.la \
849 libgnunettransporttesting.la
850
851test_transport_blacklisting_no_bl_SOURCES = \
852 test_transport_blacklisting.c
853test_transport_blacklisting_no_bl_LDADD = \
854 libgnunettransport.la \
855 $(top_builddir)/src/hello/libgnunethello.la \
856 $(top_builddir)/src/statistics/libgnunetstatistics.la \
857 $(top_builddir)/src/util/libgnunetutil.la \
858 libgnunettransporttesting.la
859
860test_transport_blacklisting_outbound_bl_full_SOURCES = \
861 test_transport_blacklisting.c
862test_transport_blacklisting_outbound_bl_full_LDADD = \
863 libgnunettransport.la \
864 $(top_builddir)/src/hello/libgnunethello.la \
865 $(top_builddir)/src/statistics/libgnunetstatistics.la \
866 $(top_builddir)/src/util/libgnunetutil.la \
867 libgnunettransporttesting.la
868
869test_transport_blacklisting_outbound_bl_plugin_SOURCES = \
870 test_transport_blacklisting.c
871test_transport_blacklisting_outbound_bl_plugin_LDADD = \
872 libgnunettransport.la \
873 $(top_builddir)/src/hello/libgnunethello.la \
874 $(top_builddir)/src/statistics/libgnunetstatistics.la \
875 $(top_builddir)/src/util/libgnunetutil.la \
876 libgnunettransporttesting.la
877
878test_transport_blacklisting_inbound_bl_full_SOURCES = \
879 test_transport_blacklisting.c
880test_transport_blacklisting_inbound_bl_full_LDADD = \
881 libgnunettransport.la \
882 $(top_builddir)/src/hello/libgnunethello.la \
883 $(top_builddir)/src/statistics/libgnunetstatistics.la \
884 $(top_builddir)/src/util/libgnunetutil.la \
885 libgnunettransporttesting.la
886
887test_transport_blacklisting_inbound_bl_plugin_SOURCES = \
888 test_transport_blacklisting.c
889test_transport_blacklisting_inbound_bl_plugin_LDADD = \
890 libgnunettransport.la \
891 $(top_builddir)/src/hello/libgnunethello.la \
892 $(top_builddir)/src/statistics/libgnunetstatistics.la \
893 $(top_builddir)/src/util/libgnunetutil.la \
894 libgnunettransporttesting.la
895
896test_transport_blacklisting_multiple_plugins_SOURCES = \
897 test_transport_blacklisting.c
898test_transport_blacklisting_multiple_plugins_LDADD = \
899 libgnunettransport.la \
900 $(top_builddir)/src/hello/libgnunethello.la \
901 $(top_builddir)/src/statistics/libgnunetstatistics.la \
902 $(top_builddir)/src/util/libgnunetutil.la \
903 libgnunettransporttesting.la
904
905
906test_transport_api_disconnect_tcp_SOURCES = \
907 test_transport_api_disconnect.c
908test_transport_api_disconnect_tcp_LDADD = \
909 libgnunettransport.la \
910 $(top_builddir)/src/hello/libgnunethello.la \
911 $(top_builddir)/src/statistics/libgnunetstatistics.la \
912 $(top_builddir)/src/util/libgnunetutil.la \
913 libgnunettransporttesting.la
914
915test_plugin_tcp_SOURCES = \
916 test_plugin_transport.c
917test_plugin_tcp_LDADD = \
918 libgnunettransport.la \
919 $(top_builddir)/src/statistics/libgnunetstatistics.la \
920 $(top_builddir)/src/hello/libgnunethello.la \
921 $(top_builddir)/src/util/libgnunetutil.la \
922 libgnunettransporttesting.la
923
924if HAVE_EXPERIMENTAL
925test_plugin_udp_SOURCES = \
926 test_plugin_transport.c
927test_plugin_udp_LDADD = \
928 libgnunettransport.la \
929 $(top_builddir)/src/statistics/libgnunetstatistics.la \
930 $(top_builddir)/src/hello/libgnunethello.la \
931 $(top_builddir)/src/util/libgnunetutil.la \
932 libgnunettransporttesting.la
933endif
934
935if HAVE_EXPERIMENTAL
936test_communicator_basic_unix_SOURCES = \ 354test_communicator_basic_unix_SOURCES = \
937 test_communicator_basic.c 355 test_communicator_basic.c
938test_communicator_basic_unix_LDADD = \ 356test_communicator_basic_unix_LDADD = \
@@ -996,87 +414,6 @@ test_communicator_bidirect_tcp_LDADD = \
996 $(top_builddir)/src/testing/libgnunettesting.la \ 414 $(top_builddir)/src/testing/libgnunettesting.la \
997 $(top_builddir)/src/util/libgnunetutil.la \ 415 $(top_builddir)/src/util/libgnunetutil.la \
998 $(top_builddir)/src/statistics/libgnunetstatistics.la 416 $(top_builddir)/src/statistics/libgnunetstatistics.la
999endif
1000
1001test_plugin_unix_SOURCES = \
1002 test_plugin_transport.c
1003test_plugin_unix_LDADD = \
1004 libgnunettransport.la \
1005 $(top_builddir)/src/statistics/libgnunetstatistics.la \
1006 $(top_builddir)/src/hello/libgnunethello.la \
1007 $(top_builddir)/src/util/libgnunetutil.la \
1008 libgnunettransporttesting.la
1009
1010test_plugin_wlan_SOURCES = \
1011 test_plugin_transport.c
1012test_plugin_wlan_LDADD = \
1013 libgnunettransport.la \
1014 $(top_builddir)/src/statistics/libgnunetstatistics.la \
1015 $(top_builddir)/src/hello/libgnunethello.la \
1016 $(top_builddir)/src/util/libgnunetutil.la \
1017 libgnunettransporttesting.la
1018
1019test_plugin_bluetooth_SOURCES = \
1020 test_plugin_transport.c
1021test_plugin_bluetooth_LDADD = \
1022 libgnunettransport.la \
1023 $(top_builddir)/src/statistics/libgnunetstatistics.la \
1024 $(top_builddir)/src/hello/libgnunethello.la \
1025 $(top_builddir)/src/util/libgnunetutil.la \
1026 libgnunettransporttesting.la
1027
1028test_http_common_SOURCES = \
1029 test_http_common.c plugin_transport_http_common.c
1030test_http_common_LDADD = \
1031 libgnunettransport.la \
1032 $(top_builddir)/src/statistics/libgnunetstatistics.la \
1033 $(top_builddir)/src/hello/libgnunethello.la \
1034 $(top_builddir)/src/util/libgnunetutil.la \
1035 libgnunettransporttesting.la
1036
1037test_plugin_http_server_SOURCES = \
1038 test_plugin_transport.c
1039test_plugin_http_server_LDADD = \
1040 libgnunettransport.la \
1041 $(top_builddir)/src/statistics/libgnunetstatistics.la \
1042 $(top_builddir)/src/hello/libgnunethello.la \
1043 $(top_builddir)/src/util/libgnunetutil.la \
1044 libgnunettransporttesting.la
1045
1046test_plugin_https_server_SOURCES = \
1047 test_plugin_transport.c
1048test_plugin_https_server_LDADD = \
1049 libgnunettransport.la \
1050 $(top_builddir)/src/statistics/libgnunetstatistics.la \
1051 $(top_builddir)/src/hello/libgnunethello.la \
1052 $(top_builddir)/src/util/libgnunetutil.la \
1053 libgnunettransporttesting.la
1054
1055test_plugin_http_client_SOURCES = \
1056 test_plugin_transport.c
1057test_plugin_http_client_LDADD = \
1058 libgnunettransport.la \
1059 $(top_builddir)/src/statistics/libgnunetstatistics.la \
1060 $(top_builddir)/src/hello/libgnunethello.la \
1061 $(top_builddir)/src/util/libgnunetutil.la \
1062 libgnunettransporttesting.la
1063
1064test_plugin_https_client_SOURCES = \
1065 test_plugin_transport.c
1066test_plugin_https_client_LDADD = \
1067 libgnunettransport.la \
1068 $(top_builddir)/src/statistics/libgnunetstatistics.la \
1069 $(top_builddir)/src/hello/libgnunethello.la \
1070 $(top_builddir)/src/util/libgnunetutil.la \
1071 libgnunettransporttesting.la
1072
1073test_transport_api_tcp_SOURCES = \
1074 test_transport_api.c
1075test_transport_api_tcp_LDADD = \
1076 libgnunettransport.la \
1077 $(top_builddir)/src/hello/libgnunethello.la \
1078 $(top_builddir)/src/util/libgnunetutil.la \
1079 libgnunettransporttesting.la
1080 417
1081test_transport_api2_tcp_SOURCES = \ 418test_transport_api2_tcp_SOURCES = \
1082 test_transport_api2.c 419 test_transport_api2.c
@@ -1085,482 +422,6 @@ test_transport_api2_tcp_LDADD = \
1085 $(top_builddir)/src/util/libgnunetutil.la \ 422 $(top_builddir)/src/util/libgnunetutil.la \
1086 libgnunettransporttesting2.la 423 libgnunettransporttesting2.la
1087 424
1088test_transport_api_restart_1peer_SOURCES = \
1089 test_transport_api_restart_reconnect.c
1090test_transport_api_restart_1peer_LDADD = \
1091 libgnunettransport.la \
1092 $(top_builddir)/src/hello/libgnunethello.la \
1093 $(top_builddir)/src/ats/libgnunetats.la \
1094 $(top_builddir)/src/statistics/libgnunetstatistics.la \
1095 $(top_builddir)/src/util/libgnunetutil.la \
1096 libgnunettransporttesting.la
1097
1098test_transport_api_restart_2peers_SOURCES = \
1099 test_transport_api_restart_reconnect.c
1100test_transport_api_restart_2peers_LDADD = \
1101 libgnunettransport.la \
1102 $(top_builddir)/src/hello/libgnunethello.la \
1103 $(top_builddir)/src/ats/libgnunetats.la \
1104$(top_builddir)/src/statistics/libgnunetstatistics.la \
1105 $(top_builddir)/src/util/libgnunetutil.la \
1106 libgnunettransporttesting.la
1107
1108test_transport_api_limited_sockets_tcp_SOURCES = \
1109 test_transport_api_limited_sockets.c
1110test_transport_api_limited_sockets_tcp_LDADD = \
1111 libgnunettransport.la \
1112 $(top_builddir)/src/hello/libgnunethello.la \
1113 $(top_builddir)/src/util/libgnunetutil.la \
1114 libgnunettransporttesting.la
1115
1116test_transport_api_tcp_nat_SOURCES = \
1117 test_transport_api.c
1118test_transport_api_tcp_nat_LDADD = \
1119 libgnunettransport.la \
1120 $(top_builddir)/src/hello/libgnunethello.la \
1121 $(top_builddir)/src/util/libgnunetutil.la \
1122 libgnunettransporttesting.la
1123
1124test_transport_api_manipulation_send_tcp_SOURCES = \
1125 test_transport_api_manipulation_send_tcp.c
1126test_transport_api_manipulation_send_tcp_LDADD = \
1127 libgnunettransport.la \
1128 $(top_builddir)/src/hello/libgnunethello.la \
1129 $(top_builddir)/src/util/libgnunetutil.la \
1130 libgnunettransporttesting.la
1131
1132test_transport_api_manipulation_recv_tcp_SOURCES = \
1133 test_transport_api_manipulation_recv_tcp.c
1134test_transport_api_manipulation_recv_tcp_LDADD = \
1135 libgnunettransport.la \
1136 $(top_builddir)/src/hello/libgnunethello.la \
1137 $(top_builddir)/src/util/libgnunetutil.la \
1138 libgnunettransporttesting.la
1139
1140test_transport_api_manipulation_cfg_SOURCES = \
1141 test_transport_api_manipulation_cfg.c
1142test_transport_api_manipulation_cfg_LDADD = \
1143 libgnunettransport.la \
1144 $(top_builddir)/src/hello/libgnunethello.la \
1145 $(top_builddir)/src/util/libgnunetutil.la \
1146 libgnunettransporttesting.la
1147
1148test_transport_api_reliability_tcp_SOURCES = \
1149 test_transport_api_reliability.c
1150test_transport_api_reliability_tcp_LDADD = \
1151 libgnunettransport.la \
1152 $(top_builddir)/src/hello/libgnunethello.la \
1153 $(top_builddir)/src/util/libgnunetutil.la \
1154 libgnunettransporttesting.la
1155
1156test_transport_api_timeout_tcp_SOURCES = \
1157 test_transport_api_timeout.c
1158test_transport_api_timeout_tcp_LDADD = \
1159 libgnunettransport.la \
1160 $(top_builddir)/src/hello/libgnunethello.la \
1161 $(top_builddir)/src/util/libgnunetutil.la \
1162 libgnunettransporttesting.la
1163
1164test_transport_api_timeout_unix_SOURCES = \
1165 test_transport_api_timeout.c
1166test_transport_api_timeout_unix_LDADD = \
1167 libgnunettransport.la \
1168 $(top_builddir)/src/hello/libgnunethello.la \
1169 $(top_builddir)/src/util/libgnunetutil.la \
1170 libgnunettransporttesting.la
1171
1172test_transport_api_timeout_wlan_SOURCES = \
1173 test_transport_api_timeout.c
1174test_transport_api_timeout_wlan_LDADD = \
1175 libgnunettransport.la \
1176 $(top_builddir)/src/hello/libgnunethello.la \
1177 $(top_builddir)/src/util/libgnunetutil.la \
1178 libgnunettransporttesting.la
1179
1180test_transport_api_timeout_bluetooth_SOURCES = \
1181 test_transport_api_timeout.c
1182test_transport_api_timeout_bluetooth_LDADD = \
1183 libgnunettransport.la \
1184 $(top_builddir)/src/hello/libgnunethello.la \
1185 $(top_builddir)/src/util/libgnunetutil.la \
1186 libgnunettransporttesting.la
1187
1188test_transport_api_reliability_tcp_nat_SOURCES = \
1189 test_transport_api_reliability.c
1190test_transport_api_reliability_tcp_nat_LDADD = \
1191 libgnunettransport.la \
1192 $(top_builddir)/src/hello/libgnunethello.la \
1193 $(top_builddir)/src/util/libgnunetutil.la \
1194 libgnunettransporttesting.la
1195
1196test_transport_api_reliability_bluetooth_SOURCES = \
1197 test_transport_api_reliability.c
1198test_transport_api_reliability_bluetooth_LDADD = \
1199 libgnunettransport.la \
1200 $(top_builddir)/src/hello/libgnunethello.la \
1201 $(top_builddir)/src/util/libgnunetutil.la \
1202 libgnunettransporttesting.la
1203
1204test_transport_api_reliability_wlan_SOURCES = \
1205 test_transport_api_reliability.c
1206test_transport_api_reliability_wlan_LDADD = \
1207 libgnunettransport.la \
1208 $(top_builddir)/src/hello/libgnunethello.la \
1209 $(top_builddir)/src/util/libgnunetutil.la \
1210 libgnunettransporttesting.la
1211
1212if HAVE_EXPERIMENTAL
1213test_transport_api_udp_SOURCES = \
1214 test_transport_api.c
1215test_transport_api_udp_LDADD = \
1216 libgnunettransport.la \
1217 $(top_builddir)/src/hello/libgnunethello.la \
1218 $(top_builddir)/src/util/libgnunetutil.la \
1219 libgnunettransporttesting.la
1220
1221test_transport_api_timeout_udp_SOURCES = \
1222 test_transport_api_timeout.c
1223test_transport_api_timeout_udp_LDADD = \
1224 libgnunettransport.la \
1225 $(top_builddir)/src/hello/libgnunethello.la \
1226 $(top_builddir)/src/util/libgnunetutil.la \
1227 libgnunettransporttesting.la
1228
1229test_transport_api_udp_nat_SOURCES = \
1230 test_transport_api.c
1231test_transport_api_udp_nat_LDADD = \
1232 libgnunettransport.la \
1233 $(top_builddir)/src/hello/libgnunethello.la \
1234 $(top_builddir)/src/util/libgnunetutil.la \
1235 libgnunettransporttesting.la
1236endif
1237
1238test_transport_api_unix_SOURCES = \
1239 test_transport_api.c
1240test_transport_api_unix_LDADD = \
1241 libgnunettransport.la \
1242 $(top_builddir)/src/hello/libgnunethello.la \
1243 $(top_builddir)/src/util/libgnunetutil.la \
1244 libgnunettransporttesting.la
1245
1246test_transport_api_unix_abstract_SOURCES = \
1247 test_transport_api.c
1248test_transport_api_unix_abstract_LDADD = \
1249 libgnunettransport.la \
1250 $(top_builddir)/src/hello/libgnunethello.la \
1251 $(top_builddir)/src/util/libgnunetutil.la \
1252 libgnunettransporttesting.la
1253
1254# HTTP tests
1255test_transport_api_http_SOURCES = \
1256 test_transport_api.c
1257test_transport_api_http_LDADD = \
1258 libgnunettransport.la \
1259 $(top_builddir)/src/hello/libgnunethello.la \
1260 $(top_builddir)/src/util/libgnunetutil.la \
1261 libgnunettransporttesting.la
1262
1263test_transport_api_http_reverse_SOURCES = \
1264 test_transport_api.c
1265test_transport_api_http_reverse_LDADD = \
1266 libgnunettransport.la \
1267 $(top_builddir)/src/hello/libgnunethello.la \
1268 $(top_builddir)/src/util/libgnunetutil.la \
1269 libgnunettransporttesting.la
1270
1271test_transport_api_timeout_http_SOURCES = \
1272 test_transport_api_timeout.c
1273test_transport_api_timeout_http_LDADD = \
1274 libgnunettransport.la \
1275 $(top_builddir)/src/hello/libgnunethello.la \
1276 $(top_builddir)/src/util/libgnunetutil.la \
1277 libgnunettransporttesting.la
1278
1279test_transport_api_reliability_http_SOURCES = \
1280 test_transport_api_reliability.c
1281test_transport_api_reliability_http_LDADD = \
1282 libgnunettransport.la \
1283 $(top_builddir)/src/hello/libgnunethello.la \
1284 $(top_builddir)/src/util/libgnunetutil.la \
1285 libgnunettransporttesting.la
1286
1287test_transport_api_reliability_http_xhr_SOURCES = \
1288 test_transport_api_reliability.c
1289test_transport_api_reliability_http_xhr_LDADD = \
1290 libgnunettransport.la \
1291 $(top_builddir)/src/hello/libgnunethello.la \
1292 $(top_builddir)/src/util/libgnunetutil.la \
1293 libgnunettransporttesting.la
1294
1295test_quota_compliance_http_SOURCES = \
1296 test_quota_compliance.c
1297test_quota_compliance_http_LDADD = \
1298 libgnunettransport.la \
1299 $(top_builddir)/src/hello/libgnunethello.la \
1300 $(top_builddir)/src/ats/libgnunetats.la \
1301 $(top_builddir)/src/nt/libgnunetnt.la \
1302 $(top_builddir)/src/util/libgnunetutil.la \
1303 libgnunettransporttesting.la
1304
1305test_quota_compliance_http_asymmetric_SOURCES = \
1306 test_quota_compliance.c
1307test_quota_compliance_http_asymmetric_LDADD = \
1308 libgnunettransport.la \
1309 $(top_builddir)/src/hello/libgnunethello.la \
1310 $(top_builddir)/src/ats/libgnunetats.la \
1311 $(top_builddir)/src/nt/libgnunetnt.la \
1312 $(top_builddir)/src/util/libgnunetutil.la \
1313 libgnunettransporttesting.la
1314
1315test_quota_compliance_https_SOURCES = \
1316 test_quota_compliance.c
1317test_quota_compliance_https_LDADD = \
1318 libgnunettransport.la \
1319 $(top_builddir)/src/hello/libgnunethello.la \
1320 $(top_builddir)/src/ats/libgnunetats.la \
1321 $(top_builddir)/src/nt/libgnunetnt.la \
1322 $(top_builddir)/src/util/libgnunetutil.la \
1323 libgnunettransporttesting.la
1324
1325test_quota_compliance_https_asymmetric_SOURCES = \
1326 test_quota_compliance.c
1327test_quota_compliance_https_asymmetric_LDADD = \
1328 libgnunettransport.la \
1329 $(top_builddir)/src/hello/libgnunethello.la \
1330 $(top_builddir)/src/ats/libgnunetats.la \
1331 $(top_builddir)/src/nt/libgnunetnt.la \
1332 $(top_builddir)/src/util/libgnunetutil.la \
1333 libgnunettransporttesting.la
1334
1335# HTTPS tests
1336test_transport_api_https_SOURCES = \
1337 test_transport_api.c
1338test_transport_api_https_LDADD = \
1339 libgnunettransport.la \
1340 $(top_builddir)/src/hello/libgnunethello.la \
1341 $(top_builddir)/src/util/libgnunetutil.la \
1342 libgnunettransporttesting.la
1343
1344test_transport_api_timeout_https_SOURCES = \
1345 test_transport_api_timeout.c
1346test_transport_api_timeout_https_LDADD = \
1347 libgnunettransport.la \
1348 $(top_builddir)/src/hello/libgnunethello.la \
1349 $(top_builddir)/src/util/libgnunetutil.la \
1350 libgnunettransporttesting.la
1351
1352
1353test_transport_api_reliability_https_SOURCES = \
1354 test_transport_api_reliability.c
1355test_transport_api_reliability_https_LDADD = \
1356 libgnunettransport.la \
1357 $(top_builddir)/src/hello/libgnunethello.la \
1358 $(top_builddir)/src/util/libgnunetutil.la \
1359 libgnunettransporttesting.la
1360
1361test_transport_api_reliability_https_xhr_SOURCES = \
1362 test_transport_api_reliability.c
1363test_transport_api_reliability_https_xhr_LDADD = \
1364 libgnunettransport.la \
1365 $(top_builddir)/src/hello/libgnunethello.la \
1366 $(top_builddir)/src/util/libgnunetutil.la \
1367 libgnunettransporttesting.la
1368
1369test_transport_api_reliability_unix_SOURCES = \
1370 test_transport_api_reliability.c
1371test_transport_api_reliability_unix_LDADD = \
1372 libgnunettransport.la \
1373 $(top_builddir)/src/hello/libgnunethello.la \
1374 $(top_builddir)/src/util/libgnunetutil.la \
1375 libgnunettransporttesting.la
1376
1377if HAVE_EXPERIMENTAL
1378test_transport_api_reliability_udp_SOURCES = \
1379 test_transport_api_reliability.c
1380test_transport_api_reliability_udp_LDADD = \
1381 libgnunettransport.la \
1382 $(top_builddir)/src/hello/libgnunethello.la \
1383 $(top_builddir)/src/util/libgnunetutil.la \
1384 libgnunettransporttesting.la
1385endif
1386
1387if LINUX
1388test_transport_api_wlan_SOURCES = \
1389 test_transport_api.c
1390test_transport_api_wlan_LDADD = \
1391 libgnunettransport.la \
1392 $(top_builddir)/src/hello/libgnunethello.la \
1393 $(top_builddir)/src/util/libgnunetutil.la \
1394 libgnunettransporttesting.la
1395endif
1396
1397if LINUX
1398if HAVE_LIBBLUETOOTH
1399test_transport_api_bluetooth_SOURCES = \
1400 test_transport_api.c
1401test_transport_api_bluetooth_LDADD = \
1402 libgnunettransport.la \
1403 $(top_builddir)/src/hello/libgnunethello.la \
1404 $(top_builddir)/src/util/libgnunetutil.la \
1405 libgnunettransporttesting.la
1406endif
1407endif
1408
1409test_transport_address_switch_tcp_SOURCES = \
1410 test_transport_address_switch.c
1411test_transport_address_switch_tcp_LDADD = \
1412 libgnunettransport.la \
1413 $(top_builddir)/src/hello/libgnunethello.la \
1414 $(top_builddir)/src/statistics/libgnunetstatistics.la \
1415 $(top_builddir)/src/util/libgnunetutil.la \
1416 libgnunettransporttesting.la
1417
1418if HAVE_EXPERIMENTAL
1419test_transport_address_switch_udp_SOURCES = \
1420 test_transport_address_switch.c
1421test_transport_address_switch_udp_LDADD = \
1422 libgnunettransport.la \
1423 $(top_builddir)/src/hello/libgnunethello.la \
1424 $(top_builddir)/src/statistics/libgnunetstatistics.la \
1425 $(top_builddir)/src/util/libgnunetutil.la \
1426 libgnunettransporttesting.la
1427endif
1428
1429 test_transport_address_switch_http_SOURCES = \
1430 test_transport_address_switch.c
1431test_transport_address_switch_http_LDADD = \
1432 libgnunettransport.la \
1433 $(top_builddir)/src/hello/libgnunethello.la \
1434 $(top_builddir)/src/statistics/libgnunetstatistics.la \
1435 $(top_builddir)/src/util/libgnunetutil.la \
1436 libgnunettransporttesting.la
1437
1438 test_transport_address_switch_https_SOURCES = \
1439 test_transport_address_switch.c
1440test_transport_address_switch_https_LDADD = \
1441 libgnunettransport.la \
1442 $(top_builddir)/src/hello/libgnunethello.la \
1443 $(top_builddir)/src/statistics/libgnunetstatistics.la \
1444 $(top_builddir)/src/util/libgnunetutil.la \
1445 libgnunettransporttesting.la
1446
1447test_quota_compliance_tcp_SOURCES = \
1448 test_quota_compliance.c
1449test_quota_compliance_tcp_LDADD = \
1450 libgnunettransport.la \
1451 $(top_builddir)/src/hello/libgnunethello.la \
1452 $(top_builddir)/src/ats/libgnunetats.la \
1453 $(top_builddir)/src/nt/libgnunetnt.la \
1454 $(top_builddir)/src/util/libgnunetutil.la \
1455 libgnunettransporttesting.la
1456
1457test_quota_compliance_tcp_asymmetric_SOURCES = \
1458 test_quota_compliance.c
1459test_quota_compliance_tcp_asymmetric_LDADD = \
1460 libgnunettransport.la \
1461 $(top_builddir)/src/hello/libgnunethello.la \
1462 $(top_builddir)/src/nt/libgnunetnt.la \
1463 $(top_builddir)/src/ats/libgnunetats.la \
1464 $(top_builddir)/src/util/libgnunetutil.la \
1465 libgnunettransporttesting.la
1466
1467if HAVE_EXPERIMENTAL
1468test_quota_compliance_udp_SOURCES = \
1469 test_quota_compliance.c
1470test_quota_compliance_udp_LDADD = \
1471 libgnunettransport.la \
1472 $(top_builddir)/src/hello/libgnunethello.la \
1473 $(top_builddir)/src/ats/libgnunetats.la \
1474 $(top_builddir)/src/nt/libgnunetnt.la \
1475 $(top_builddir)/src/util/libgnunetutil.la \
1476 libgnunettransporttesting.la
1477endif
1478
1479test_quota_compliance_unix_SOURCES = \
1480 test_quota_compliance.c
1481test_quota_compliance_unix_LDADD = \
1482 libgnunettransport.la \
1483 $(top_builddir)/src/hello/libgnunethello.la \
1484 $(top_builddir)/src/ats/libgnunetats.la \
1485 $(top_builddir)/src/nt/libgnunetnt.la \
1486 $(top_builddir)/src/util/libgnunetutil.la \
1487 libgnunettransporttesting.la
1488
1489test_quota_compliance_unix_asymmetric_SOURCES = \
1490 test_quota_compliance.c
1491test_quota_compliance_unix_asymmetric_LDADD = \
1492 libgnunettransport.la \
1493 $(top_builddir)/src/hello/libgnunethello.la \
1494 $(top_builddir)/src/ats/libgnunetats.la \
1495 $(top_builddir)/src/nt/libgnunetnt.la \
1496 $(top_builddir)/src/util/libgnunetutil.la \
1497 libgnunettransporttesting.la
1498
1499test_quota_compliance_wlan_SOURCES = \
1500 test_quota_compliance.c
1501test_quota_compliance_wlan_LDADD = \
1502 libgnunettransport.la \
1503 $(top_builddir)/src/hello/libgnunethello.la \
1504 $(top_builddir)/src/ats/libgnunetats.la \
1505 $(top_builddir)/src/nt/libgnunetnt.la \
1506 $(top_builddir)/src/util/libgnunetutil.la \
1507 libgnunettransporttesting.la
1508
1509test_quota_compliance_wlan_asymmetric_SOURCES = \
1510 test_quota_compliance.c
1511test_quota_compliance_wlan_asymmetric_LDADD = \
1512 libgnunettransport.la \
1513 $(top_builddir)/src/hello/libgnunethello.la \
1514 $(top_builddir)/src/ats/libgnunetats.la \
1515 $(top_builddir)/src/nt/libgnunetnt.la \
1516 $(top_builddir)/src/util/libgnunetutil.la \
1517 libgnunettransporttesting.la
1518
1519test_quota_compliance_bluetooth_SOURCES = \
1520 test_quota_compliance.c
1521test_quota_compliance_bluetooth_LDADD = \
1522 libgnunettransport.la \
1523 $(top_builddir)/src/hello/libgnunethello.la \
1524 $(top_builddir)/src/ats/libgnunetats.la \
1525 $(top_builddir)/src/nt/libgnunetnt.la \
1526 $(top_builddir)/src/util/libgnunetutil.la \
1527 libgnunettransporttesting.la
1528
1529test_quota_compliance_bluetooth_asymmetric_SOURCES = \
1530 test_quota_compliance.c
1531test_quota_compliance_bluetooth_asymmetric_LDADD = \
1532 libgnunettransport.la \
1533 $(top_builddir)/src/hello/libgnunethello.la \
1534 $(top_builddir)/src/ats/libgnunetats.la \
1535 $(top_builddir)/src/nt/libgnunetnt.la \
1536 $(top_builddir)/src/util/libgnunetutil.la \
1537 libgnunettransporttesting.la
1538
1539test_transport_api_multi_SOURCES = \
1540 test_transport_api.c
1541test_transport_api_multi_LDADD = \
1542 libgnunettransport.la \
1543 $(top_builddir)/src/hello/libgnunethello.la \
1544 $(top_builddir)/src/util/libgnunetutil.la \
1545 libgnunettransporttesting.la
1546
1547test_transport_api_monitor_peers_SOURCES = \
1548 test_transport_api_monitor_peers.c
1549test_transport_api_monitor_peers_LDADD = \
1550 libgnunettransport.la \
1551 $(top_builddir)/src/hello/libgnunethello.la \
1552 $(top_builddir)/src/util/libgnunetutil.la \
1553 libgnunettransporttesting.la
1554
1555test_transport_api_slow_ats_SOURCES = \
1556 test_transport_api.c
1557test_transport_api_slow_ats_LDADD = \
1558 libgnunettransport.la \
1559 $(top_builddir)/src/hello/libgnunethello.la \
1560 $(top_builddir)/src/util/libgnunetutil.la \
1561 libgnunettransporttesting.la
1562
1563
1564EXTRA_DIST = \ 425EXTRA_DIST = \
1565test_transport_start_testcase.sh \ 426test_transport_start_testcase.sh \
1566test_transport_simple_send_performance.sh \ 427test_transport_simple_send_performance.sh \
@@ -1573,78 +434,16 @@ test_transport_udp_backchannel.sh \
1573test_transport_simple_send_dv_circle.sh \ 434test_transport_simple_send_dv_circle.sh \
1574test_transport_simple_send_dv_inverse.sh \ 435test_transport_simple_send_dv_inverse.sh \
1575gnunet-transport-certificate-creation.in \ 436gnunet-transport-certificate-creation.in \
1576communicator-unix.conf \
1577test_plugin_hostkey \ 437test_plugin_hostkey \
1578test_plugin_hostkey.ecc \ 438test_plugin_hostkey.ecc \
1579test_delay \ 439test_delay \
1580template_cfg_peer1.conf\ 440template_cfg_peer1.conf\
1581template_cfg_peer2.conf\ 441template_cfg_peer2.conf\
1582test_plugin_transport_data.conf\
1583test_plugin_transport_data_udp.conf\
1584test_quota_compliance_data.conf\
1585test_quota_compliance_http_peer1.conf\
1586test_quota_compliance_http_peer2.conf\
1587test_quota_compliance_https_peer1.conf\
1588test_quota_compliance_https_peer2.conf\
1589test_quota_compliance_tcp_peer1.conf\
1590test_quota_compliance_tcp_peer2.conf\
1591test_quota_compliance_udp_peer1.conf\
1592test_quota_compliance_udp_peer2.conf\
1593test_quota_compliance_unix_peer1.conf\
1594test_quota_compliance_unix_peer2.conf\
1595test_quota_compliance_wlan_peer1.conf\
1596test_quota_compliance_wlan_peer2.conf\
1597test_quota_compliance_bluetooth_peer1.conf\
1598test_quota_compliance_bluetooth_peer2.conf\
1599test_quota_compliance_http_asymmetric_peer1.conf\
1600test_quota_compliance_http_asymmetric_peer2.conf\
1601test_quota_compliance_https_asymmetric_peer1.conf\
1602test_quota_compliance_https_asymmetric_peer2.conf\
1603test_quota_compliance_tcp_asymmetric_peer1.conf\
1604test_quota_compliance_tcp_asymmetric_peer2.conf\
1605test_quota_compliance_unix_asymmetric_peer1.conf\
1606test_quota_compliance_unix_asymmetric_peer2.conf\
1607test_quota_compliance_wlan_asymmetric_peer1.conf\
1608test_quota_compliance_wlan_asymmetric_peer2.conf\
1609test_quota_compliance_bluetooth_asymmetric_peer1.conf\
1610test_quota_compliance_bluetooth_asymmetric_peer2.conf\
1611test_transport_api_data.conf\ 442test_transport_api_data.conf\
1612test_transport_api_blacklisting_tcp_peer1.conf \
1613test_transport_api_blacklisting_tcp_peer2.conf \
1614test_transport_api_http_peer1.conf\
1615test_transport_api_http_peer2.conf\
1616test_transport_api_https_peer1.conf\
1617test_transport_api_https_peer2.conf\
1618test_transport_api_limited_sockets_tcp_peer1.conf\
1619test_transport_api_limited_sockets_tcp_peer2.conf\
1620test_transport_api_timeout_tcp_peer1.conf\ 443test_transport_api_timeout_tcp_peer1.conf\
1621test_transport_api_timeout_tcp_peer2.conf\ 444test_transport_api_timeout_tcp_peer2.conf\
1622test_transport_api_multi_peer1.conf\ 445test_transport_api_multi_peer1.conf\
1623test_transport_api_multi_peer2.conf\ 446test_transport_api_multi_peer2.conf\
1624test_transport_api_restart_1peer_peer1.conf\
1625test_transport_api_restart_1peer_peer2.conf\
1626test_transport_api_reliability_http_peer1.conf\
1627test_transport_api_reliability_http_peer2.conf\
1628test_transport_api_reliability_https_peer1.conf\
1629test_transport_api_reliability_https_peer2.conf\
1630test_transport_api_reliability_tcp_nat_peer1.conf\
1631test_transport_api_reliability_tcp_nat_peer2.conf\
1632test_transport_api_reliability_tcp_peer1.conf\
1633test_transport_api_reliability_tcp_peer2.conf\
1634test_transport_api_reliability_wlan_peer1.conf\
1635test_transport_api_reliability_wlan_peer2.conf\
1636test_transport_api_reliability_bluetooth_peer1.conf\
1637test_transport_api_reliability_bluetooth_peer2.conf\
1638test_transport_api_manipulation_send_tcp_peer1.conf\
1639test_transport_api_manipulation_send_tcp_peer2.conf\
1640test_transport_api_manipulation_recv_tcp_peer1.conf\
1641test_transport_api_manipulation_recv_tcp_peer2.conf\
1642test_transport_api_manipulation_cfg_peer1.conf\
1643test_transport_api_manipulation_cfg_peer2.conf\
1644test_transport_api_restart_1peer_peer1.conf\
1645test_transport_api_restart_1peer_peer2.conf\
1646test_transport_api_restart_2peers_peer1.conf\
1647test_transport_api_restart_2peers_peer2.conf\
1648test_transport_api_tcp_nat_peer1.conf\ 447test_transport_api_tcp_nat_peer1.conf\
1649test_transport_api_tcp_nat_peer2.conf\ 448test_transport_api_tcp_nat_peer2.conf\
1650test_transport_api_tcp_peer1.conf\ 449test_transport_api_tcp_peer1.conf\
@@ -1655,65 +454,13 @@ test_transport_api_udp_nat_peer1.conf\
1655test_transport_api_udp_nat_peer2.conf\ 454test_transport_api_udp_nat_peer2.conf\
1656test_transport_api_udp_peer1.conf\ 455test_transport_api_udp_peer1.conf\
1657test_transport_api_udp_peer2.conf\ 456test_transport_api_udp_peer2.conf\
1658test_transport_api_timeout_udp_peer1.conf\
1659test_transport_api_timeout_udp_peer2.conf\
1660test_transport_api_unix_peer1.conf\ 457test_transport_api_unix_peer1.conf\
1661test_transport_api_unix_peer2.conf\ 458test_transport_api_unix_peer2.conf\
1662test_transport_api_unix_abstract_peer1.conf \
1663test_transport_api_unix_abstract_peer2.conf \
1664test_transport_api_timeout_unix_peer1.conf\
1665test_transport_api_timeout_unix_peer2.conf\
1666test_transport_api_timeout_wlan_peer1.conf \
1667test_transport_api_timeout_wlan_peer2.conf \
1668test_transport_api_timeout_bluetooth_peer1.conf\
1669test_transport_api_timeout_bluetooth_peer2.conf\
1670test_transport_api_reliability_udp_peer1.conf\
1671test_transport_api_reliability_udp_peer2.conf\
1672test_transport_api_reliability_http_xhr_peer1.conf\
1673test_transport_api_reliability_http_xhr_peer2.conf\
1674test_transport_api_reliability_https_xhr_peer1.conf\
1675test_transport_api_reliability_https_xhr_peer2.conf\
1676test_transport_api_reliability_unix_peer1.conf\
1677test_transport_api_reliability_unix_peer2.conf\
1678test_transport_api_reliability_wlan_peer1.conf\
1679test_transport_api_reliability_wlan_peer2.conf\
1680test_transport_api_unreliability_wlan_peer1.conf\
1681test_transport_api_unreliability_wlan_peer2.conf\
1682test_transport_api_reliability_bluetooth_peer1.conf\
1683test_transport_api_reliability_bluetooth_peer2.conf\
1684test_transport_api_wlan_peer1.conf\
1685test_transport_api_wlan_peer2.conf\
1686test_transport_api_bluetooth_peer1.conf\
1687test_transport_api_bluetooth_peer2.conf\
1688test_transport_api_monitor_peers_peer1.conf\ 459test_transport_api_monitor_peers_peer1.conf\
1689test_transport_api_monitor_peers_peer2.conf\ 460test_transport_api_monitor_peers_peer2.conf\
1690test_transport_api_monitor_validation_peer1.conf\ 461test_transport_api_monitor_validation_peer1.conf\
1691test_transport_api_monitor_validation_peer2.conf\ 462test_transport_api_monitor_validation_peer2.conf\
1692test_transport_defaults.conf\ 463test_transport_defaults.conf\
1693test_transport_api_disconnect_tcp_peer1.conf\
1694test_transport_api_disconnect_tcp_peer2.conf\
1695test_transport_api_timeout_http_peer1.conf\
1696test_transport_api_timeout_http_peer2.conf\
1697test_transport_api_timeout_https_peer1.conf\
1698test_transport_api_timeout_https_peer2.conf\
1699test_transport_blacklisting_cfg_peer1.conf \
1700test_transport_blacklisting_cfg_peer2.conf \
1701test_transport_blacklisting_cfg_blp_peer1_full.conf\
1702test_transport_blacklisting_cfg_blp_peer1_plugin.conf \
1703test_transport_blacklisting_cfg_blp_peer2_full.conf\
1704test_transport_blacklisting_cfg_blp_peer2_plugin.conf \
1705test_transport_blacklisting_cfg_blp_peer1_multiple_plugins.conf \
1706test_transport_blacklisting_cfg_blp_peer2_multiple_plugins.conf \
1707test_transport_api_http_reverse_peer1.conf \
1708test_transport_api_http_reverse_peer2.conf \
1709perf_tcp_peer1.conf \
1710perf_tcp_peer2.conf \
1711test_transport_api_slow_ats_peer1.conf \
1712test_transport_api_slow_ats_peer2.conf \
1713 tcp_connection_legacy.c \
1714 tcp_server_mst_legacy.c \
1715 tcp_server_legacy.c \
1716 tcp_service_legacy.c \
1717test_communicator_unix_basic_peer1.conf \ 464test_communicator_unix_basic_peer1.conf \
1718test_communicator_unix_basic_peer2.conf \ 465test_communicator_unix_basic_peer2.conf \
1719test_communicator_tcp_basic_peer1.conf \ 466test_communicator_tcp_basic_peer1.conf \
diff --git a/src/transport/communicator-unix.conf b/src/transport/communicator-unix.conf
deleted file mode 100644
index ad92616c6..000000000
--- a/src/transport/communicator-unix.conf
+++ /dev/null
@@ -1,2 +0,0 @@
1[communicator-unix]
2UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-communicator-unix.sock
diff --git a/src/transport/gnunet-helper-transport-bluetooth.c b/src/transport/gnunet-helper-transport-bluetooth.c
deleted file mode 100644
index 64f3b6160..000000000
--- a/src/transport/gnunet-helper-transport-bluetooth.c
+++ /dev/null
@@ -1,2286 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010, 2011, 2012 GNUnet e.V.
4 Copyright (C) 2007, 2008, Andy Green <andy@warmcat.com>
5 Copyright (C) 2009 Thomas d'Otreppe
6
7 GNUnet is free software: you can redistribute it and/or modify it
8 under the terms of the GNU Affero General Public License as published
9 by the Free Software Foundation, either version 3 of the License,
10 or (at your option) any later version.
11
12 GNUnet is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Affero General Public License for more details.
16
17 You should have received a copy of the GNU Affero General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20 SPDX-License-Identifier: AGPL3.0-or-later
21 */
22#include "platform.h"
23#include "gnunet_private_config.h"
24
25#include <bluetooth/bluetooth.h>
26#include <bluetooth/hci.h>
27#include <bluetooth/hci_lib.h>
28#include <bluetooth/rfcomm.h>
29#include <bluetooth/sdp.h>
30#include <bluetooth/sdp_lib.h>
31#include <errno.h>
32#include <linux/if.h>
33#include <stdio.h>
34#include <stdlib.h>
35#include <sys/ioctl.h>
36#include <sys/param.h>
37#include <sys/socket.h>
38#include <sys/stat.h>
39#include <sys/types.h>
40#include <unistd.h>
41
42#include "plugin_transport_wlan.h"
43#include "gnunet_protocols.h"
44
45
46/**
47 * Maximum number of ports assignable for RFCOMMM protocol.
48 */
49#define MAX_PORTS 30
50
51/**
52 * Maximum size of a message allowed in either direction
53 * (used for our receive and sent buffers).
54 */
55#define MAXLINE 4096
56
57
58/**
59 * Maximum number of loops without inquiring for new devices.
60 */
61#define MAX_LOOPS 5
62
63/**
64 * In bluez library, the maximum name length of a device is 8
65 */
66#define BLUEZ_DEVNAME_SIZE 8
67
68/**
69 * struct for storing the information of the hardware. There is only
70 * one of these.
71 */
72struct HardwareInfos
73{
74 /**
75 * Name of the interface, not necessarily 0-terminated (!).
76 */
77 char iface[IFNAMSIZ];
78
79 /**
80 * file descriptor for the rfcomm socket
81 */
82 int fd_rfcomm;
83
84 /**
85 * MAC address of our own bluetooth interface.
86 */
87 struct GNUNET_TRANSPORT_WLAN_MacAddress pl_mac;
88
89 /**
90 * SDP session
91 */
92 sdp_session_t *session;
93};
94
95/**
96 * IO buffer used for buffering data in transit (to wireless or to stdout).
97 */
98struct SendBuffer
99{
100 /**
101 * How many bytes of data are stored in 'buf' for transmission right now?
102 * Data always starts at offset 0 and extends to 'size'.
103 */
104 size_t size;
105
106 /**
107 * How many bytes that were stored in 'buf' did we already write to the
108 * destination? Always smaller than 'size'.
109 */
110 size_t pos;
111
112 /**
113 * Buffered data; twice the maximum allowed message size as we add some
114 * headers.
115 */
116 char buf[MAXLINE * 2];
117};
118
119#ifdef __linux__
120/**
121 * Devices buffer used to keep a list with all the discoverable devices in
122 * order to send them HELLO messages one by one when it receive a broadcast message.
123 */
124struct BroadcastMessages
125{
126 /* List with the discoverable devices' addresses */
127 bdaddr_t devices[MAX_PORTS];
128
129 /* List with the open sockets */
130 int fds[MAX_PORTS];
131
132
133 /* The number of the devices */
134 int size;
135
136 /* The current position */
137 int pos;
138
139 /* The device id */
140 int dev_id;
141};
142
143/**
144 * Address used to identify the broadcast messages.
145 */
146static struct GNUNET_TRANSPORT_WLAN_MacAddress broadcast_address = { { 255, 255,
147 255, 255,
148 255,
149 255 } };
150
151/**
152 * Buffer with the discoverable devices.
153 */
154static struct BroadcastMessages neighbours;
155
156static int searching_devices_count = 0;
157#endif
158
159/**
160 * Buffer for data read from stdin to be transmitted to the bluetooth device
161 */
162static struct SendBuffer write_pout;
163
164/**
165 * Buffer for data read from the bluetooth device to be transmitted to stdout.
166 */
167static struct SendBuffer write_std;
168
169
170/* ****** this are the same functions as the ones used in gnunet-helper-transport-wlan.c ****** */
171
172/**
173 * To what multiple do we align messages? 8 byte should suffice for everyone
174 * for now.
175 */
176#define ALIGN_FACTOR 8
177
178/**
179 * Smallest supported message.
180 */
181#define MIN_BUFFER_SIZE sizeof(struct GNUNET_MessageHeader)
182
183
184/**
185 * Functions with this signature are called whenever a
186 * complete message is received by the tokenizer.
187 *
188 * @param cls closure
189 * @param message the actual message
190 */
191typedef void (*MessageTokenizerCallback) (void *cls,
192 const struct
193 GNUNET_MessageHeader *
194 message);
195
196/**
197 * Handle to a message stream tokenizer.
198 */
199struct MessageStreamTokenizer
200{
201 /**
202 * Function to call on completed messages.
203 */
204 MessageTokenizerCallback cb;
205
206 /**
207 * Closure for cb.
208 */
209 void *cb_cls;
210
211 /**
212 * Size of the buffer (starting at 'hdr').
213 */
214 size_t curr_buf;
215
216 /**
217 * How many bytes in buffer have we already processed?
218 */
219 size_t off;
220
221 /**
222 * How many bytes in buffer are valid right now?
223 */
224 size_t pos;
225
226 /**
227 * Beginning of the buffer. Typed like this to force alignment.
228 */
229 struct GNUNET_MessageHeader *hdr;
230};
231
232
233/**
234 * Create a message stream tokenizer.
235 *
236 * @param cb function to call on completed messages
237 * @param cb_cls closure for cb
238 * @return handle to tokenizer
239 */
240static struct MessageStreamTokenizer *
241mst_create (MessageTokenizerCallback cb,
242 void *cb_cls)
243{
244 struct MessageStreamTokenizer *ret;
245
246 ret = malloc (sizeof(struct MessageStreamTokenizer));
247 if (NULL == ret)
248 {
249 fprintf (stderr, "Failed to allocate buffer for tokenizer\n");
250 exit (1);
251 }
252 ret->hdr = malloc (MIN_BUFFER_SIZE);
253 if (NULL == ret->hdr)
254 {
255 fprintf (stderr, "Failed to allocate buffer for alignment\n");
256 exit (1);
257 }
258 ret->curr_buf = MIN_BUFFER_SIZE;
259 ret->cb = cb;
260 ret->cb_cls = cb_cls;
261 ret->pos = 0;
262
263 return ret;
264}
265
266
267/**
268 * Add incoming data to the receive buffer and call the
269 * callback for all complete messages.
270 *
271 * @param mst tokenizer to use
272 * @param buf input data to add
273 * @param size number of bytes in buf
274 * @return GNUNET_OK if we are done processing (need more data)
275 * GNUNET_SYSERR if the data stream is corrupt
276 */
277static int
278mst_receive (struct MessageStreamTokenizer *mst,
279 const char *buf, size_t size)
280{
281 const struct GNUNET_MessageHeader *hdr;
282 size_t delta;
283 uint16_t want;
284 char *ibuf;
285 int need_align;
286 unsigned long offset;
287 int ret;
288
289 ret = GNUNET_OK;
290 ibuf = (char *) mst->hdr;
291 while (mst->pos > 0)
292 {
293do_align:
294 if (mst->pos < mst->off)
295 {
296 // fprintf (stderr, "We processed too many bytes!\n");
297 return GNUNET_SYSERR;
298 }
299 if ((mst->curr_buf - mst->off < sizeof(struct GNUNET_MessageHeader)) ||
300 (0 != (mst->off % ALIGN_FACTOR)))
301 {
302 /* need to align or need more space */
303 mst->pos -= mst->off;
304 memmove (ibuf, &ibuf[mst->off], mst->pos);
305 mst->off = 0;
306 }
307 if (mst->pos - mst->off < sizeof(struct GNUNET_MessageHeader))
308 {
309 delta =
310 GNUNET_MIN (sizeof(struct GNUNET_MessageHeader)
311 - (mst->pos - mst->off), size);
312 GNUNET_memcpy (&ibuf[mst->pos], buf, delta);
313 mst->pos += delta;
314 buf += delta;
315 size -= delta;
316 }
317 if (mst->pos - mst->off < sizeof(struct GNUNET_MessageHeader))
318 {
319 // FIXME should I reset ??
320 // mst->off = 0;
321 // mst->pos = 0;
322 return GNUNET_OK;
323 }
324 hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off];
325 want = ntohs (hdr->size);
326 if (want < sizeof(struct GNUNET_MessageHeader))
327 {
328 fprintf (stderr,
329 "Received invalid message from stdin\n");
330 return GNUNET_SYSERR;
331 }
332 if ((mst->curr_buf - mst->off < want) &&
333 (mst->off > 0))
334 {
335 /* need more space */
336 mst->pos -= mst->off;
337 memmove (ibuf, &ibuf[mst->off], mst->pos);
338 mst->off = 0;
339 }
340 if (want > mst->curr_buf)
341 {
342 if (mst->off != 0)
343 {
344 fprintf (stderr, "Error! We should proceeded 0 bytes\n");
345 return GNUNET_SYSERR;
346 }
347 mst->hdr = realloc (mst->hdr, want);
348 if (NULL == mst->hdr)
349 {
350 fprintf (stderr, "Failed to allocate buffer for alignment\n");
351 exit (1);
352 }
353 ibuf = (char *) mst->hdr;
354 mst->curr_buf = want;
355 }
356 hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off];
357 if (mst->pos - mst->off < want)
358 {
359 delta = GNUNET_MIN (want - (mst->pos - mst->off), size);
360 if (mst->pos + delta > mst->curr_buf)
361 {
362 fprintf (stderr, "The size of the buffer will be exceeded!\n");
363 return GNUNET_SYSERR;
364 }
365 GNUNET_memcpy (&ibuf[mst->pos], buf, delta);
366 mst->pos += delta;
367 buf += delta;
368 size -= delta;
369 }
370 if (mst->pos - mst->off < want)
371 {
372 // FIXME should I use this?
373 // mst->off = 0;
374 // mst->pos = 0;
375 return GNUNET_OK;
376 }
377 mst->cb (mst->cb_cls, hdr);
378 mst->off += want;
379 if (mst->off == mst->pos)
380 {
381 /* reset to beginning of buffer, it's free right now! */
382 mst->off = 0;
383 mst->pos = 0;
384 }
385 }
386 if (0 != mst->pos)
387 {
388 fprintf (stderr,
389 "There should some valid bytes in the buffer on this stage\n");
390 return GNUNET_SYSERR;
391 }
392 while (size > 0)
393 {
394 if (size < sizeof(struct GNUNET_MessageHeader))
395 break;
396 offset = (unsigned long) buf;
397 need_align = (0 != offset % ALIGN_FACTOR) ? GNUNET_YES : GNUNET_NO;
398 if (GNUNET_NO == need_align)
399 {
400 /* can try to do zero-copy and process directly from original buffer */
401 hdr = (const struct GNUNET_MessageHeader *) buf;
402 want = ntohs (hdr->size);
403 if (want < sizeof(struct GNUNET_MessageHeader))
404 {
405 fprintf (stderr,
406 "Received invalid message from stdin\n");
407 // exit (1);
408 mst->off = 0;
409 return GNUNET_SYSERR;
410 }
411 if (size < want)
412 break; /* or not, buffer incomplete, so copy to private buffer... */
413 mst->cb (mst->cb_cls, hdr);
414 buf += want;
415 size -= want;
416 }
417 else
418 {
419 /* need to copy to private buffer to align;
420 * yes, we go a bit more spaghetti than usual here */
421 goto do_align;
422 }
423 }
424 if (size > 0)
425 {
426 if (size + mst->pos > mst->curr_buf)
427 {
428 mst->hdr = realloc (mst->hdr, size + mst->pos);
429 if (NULL == mst->hdr)
430 {
431 fprintf (stderr, "Failed to allocate buffer for alignment\n");
432 exit (1);
433 }
434 ibuf = (char *) mst->hdr;
435 mst->curr_buf = size + mst->pos;
436 }
437 if (mst->pos + size > mst->curr_buf)
438 {
439 fprintf (stderr,
440 "Assertion failed\n");
441 exit (1);
442 }
443 GNUNET_memcpy (&ibuf[mst->pos], buf, size);
444 mst->pos += size;
445 }
446 return ret;
447}
448
449
450/**
451 * Destroys a tokenizer.
452 *
453 * @param mst tokenizer to destroy
454 */
455static void
456mst_destroy (struct MessageStreamTokenizer *mst)
457{
458 free (mst->hdr);
459 free (mst);
460}
461
462
463/**
464 * Calculate crc32, the start of the calculation
465 *
466 * @param buf buffer to calc the crc
467 * @param len len of the buffer
468 * @return crc sum
469 */
470static unsigned long
471calc_crc_osdep (const unsigned char *buf, size_t len)
472{
473 static const unsigned long int crc_tbl_osdep[256] = {
474 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
475 0xE963A535, 0x9E6495A3,
476 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD,
477 0xE7B82D07, 0x90BF1D91,
478 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB,
479 0xF4D4B551, 0x83D385C7,
480 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
481 0xFA0F3D63, 0x8D080DF5,
482 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447,
483 0xD20D85FD, 0xA50AB56B,
484 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75,
485 0xDCD60DCF, 0xABD13D59,
486 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
487 0xCFBA9599, 0xB8BDA50F,
488 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11,
489 0xC1611DAB, 0xB6662D3D,
490 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F,
491 0x9FBFE4A5, 0xE8B8D433,
492 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
493 0x91646C97, 0xE6635C01,
494 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B,
495 0x8208F4C1, 0xF50FC457,
496 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49,
497 0x8CD37CF3, 0xFBD44C65,
498 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
499 0xA4D1C46D, 0xD3D6F4FB,
500 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5,
501 0xAA0A4C5F, 0xDD0D7CC9,
502 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3,
503 0xB966D409, 0xCE61E49F,
504 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
505 0xB7BD5C3B, 0xC0BA6CAD,
506 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF,
507 0x04DB2615, 0x73DC1683,
508 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D,
509 0x0A00AE27, 0x7D079EB1,
510 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
511 0x196C3671, 0x6E6B06E7,
512 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9,
513 0x17B7BE43, 0x60B08ED5,
514 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767,
515 0x3FB506DD, 0x48B2364B,
516 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
517 0x316E8EEF, 0x4669BE79,
518 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703,
519 0x220216B9, 0x5505262F,
520 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31,
521 0x2CD99E8B, 0x5BDEAE1D,
522 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
523 0x72076785, 0x05005713,
524 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D,
525 0x7CDCEFB7, 0x0BDBDF21,
526 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B,
527 0x6FB077E1, 0x18B74777,
528 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
529 0x616BFFD3, 0x166CCF45,
530 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7,
531 0x4969474D, 0x3E6E77DB,
532 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5,
533 0x47B2CF7F, 0x30B5FFE9,
534 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
535 0x54DE5729, 0x23D967BF,
536 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1,
537 0x5A05DF1B, 0x2D02EF8D
538 };
539
540 unsigned long crc = 0xFFFFFFFF;
541
542 for (; len > 0; len--, buf++)
543 crc = crc_tbl_osdep[(crc ^ *buf) & 0xFF] ^ (crc >> 8);
544 return(~crc);
545}
546
547
548/**
549 * Calculate and check crc of the bluetooth packet
550 *
551 * @param buf buffer of the packet, with len + 4 bytes of data,
552 * the last 4 bytes being the checksum
553 * @param len length of the payload in data
554 * @return 0 on success (checksum matches), 1 on error
555 */
556static int
557check_crc_buf_osdep (const unsigned char *buf, size_t len)
558{
559 unsigned long crc;
560
561 crc = calc_crc_osdep (buf, len);
562 buf += len;
563 if ((((crc) & 0xFF) == buf[0]) && (((crc >> 8) & 0xFF) == buf[1]) &&
564 ( ((crc >> 16) & 0xFF) == buf[2]) && ( ((crc >> 24) & 0xFF) == buf[3]) )
565 return 0;
566 return 1;
567}
568
569
570/* ************** end of clone ***************** */
571#ifdef __linux__
572/**
573 * Function for assigning a port number
574 *
575 * @param socket the socket used to bind
576 * @param addr pointer to the rfcomm address
577 * @return 0 on success
578 */
579static int
580bind_socket (int socket, struct sockaddr_rc *addr)
581{
582 int port, status;
583
584 /* Bind every possible port (from 0 to 30) and stop when binding doesn't fail */
585 // FIXME : it should start from port 1, but on my computer it doesn't work :)
586 for (port = 3; port <= 30; port++)
587 {
588 addr->rc_channel = port;
589 status = bind (socket, (struct sockaddr *) addr, sizeof(struct
590 sockaddr_rc));
591 if (status == 0)
592 return 0;
593 }
594
595 return -1;
596}
597
598
599#endif
600
601/**
602 * Function used for creating the service record and registering it.
603 *
604 * @param dev pointer to the device struct
605 * @param rc_channel the rfcomm channel
606 * @return 0 on success
607 */
608static int
609register_service (struct HardwareInfos *dev, int rc_channel)
610{
611 /**
612 * 1. initializations
613 * 2. set the service ID, class, profile information
614 * 3. make the service record publicly browsable
615 * 4. register the RFCOMM channel
616 * 5. set the name, provider and description
617 * 6. register the service record to the local SDP server
618 * 7. cleanup
619 */uint8_t svc_uuid_int[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
620 dev->pl_mac.mac[5], dev->pl_mac.mac[4],
621 dev->pl_mac.mac[3],
622 dev->pl_mac.mac[2], dev->pl_mac.mac[1],
623 dev->pl_mac.mac[0] };
624 const char *service_dsc = "Bluetooth plugin services";
625 const char *service_prov = "GNUnet provider";
626 uuid_t root_uuid, rfcomm_uuid, svc_uuid;
627 sdp_list_t *root_list = 0, *rfcomm_list = 0, *proto_list = 0,
628 *access_proto_list = 0, *svc_list = 0;
629 sdp_record_t *record = 0;
630 sdp_data_t *channel = 0;
631
632 record = sdp_record_alloc ();
633
634 /* Set the general service ID */
635 sdp_uuid128_create (&svc_uuid, &svc_uuid_int);
636 svc_list = sdp_list_append (0, &svc_uuid);
637 sdp_set_service_classes (record, svc_list);
638 sdp_set_service_id (record, svc_uuid);
639
640 /* Make the service record publicly browsable */
641 sdp_uuid16_create (&root_uuid, PUBLIC_BROWSE_GROUP);
642 root_list = sdp_list_append (0, &root_uuid);
643 sdp_set_browse_groups (record, root_list);
644
645 /* Register the RFCOMM channel */
646 sdp_uuid16_create (&rfcomm_uuid, RFCOMM_UUID);
647 channel = sdp_data_alloc (SDP_UINT8, &rc_channel);
648 rfcomm_list = sdp_list_append (0, &rfcomm_uuid);
649 sdp_list_append (rfcomm_list, channel);
650 proto_list = sdp_list_append (0, rfcomm_list);
651
652 /* Set protocol information */
653 access_proto_list = sdp_list_append (0, proto_list);
654 sdp_set_access_protos (record, access_proto_list);
655
656 /* Set the name, provider, and description */
657 sdp_set_info_attr (record, dev->iface, service_prov, service_dsc);
658
659 /* Connect to the local SDP server */
660 dev->session = sdp_connect (BDADDR_ANY, BDADDR_LOCAL, SDP_RETRY_IF_BUSY);
661
662 if (! dev->session)
663 {
664 fprintf (stderr,
665 "Failed to connect to the SDP server on interface `%.*s': %s\n",
666 IFNAMSIZ, dev->iface, strerror (errno));
667 // FIXME exit?
668 return 1;
669 }
670
671 /* Register the service record */
672 if (sdp_record_register (dev->session, record, 0) < 0)
673 {
674 fprintf (stderr,
675 "Failed to register a service record on interface `%.*s': %s\n",
676 IFNAMSIZ, dev->iface, strerror (errno));
677 // FIXME exit?
678 return 1;
679 }
680
681 /* Cleanup */
682 sdp_data_free (channel);
683 sdp_list_free (root_list, 0);
684 sdp_list_free (rfcomm_list, 0);
685 sdp_list_free (proto_list, 0);
686 sdp_list_free (access_proto_list, 0);
687 sdp_list_free (svc_list, 0);
688 sdp_record_free (record);
689
690 return 0;
691}
692
693
694/**
695 * Function used for searching and browsing for a service. This will return the
696 * port number on which the service is running.
697 *
698 * @param dev pointer to the device struct
699 * @param dest target address
700 * @return channel
701 */
702static int
703get_channel (struct HardwareInfos *dev, bdaddr_t dest)
704{
705 /**
706 * 1. detect all nearby devices
707 * 2. for each device:
708 * 2.1. connect to the SDP server running
709 * 2.2. get a list of service records with the specific UUID
710 * 2.3. for each service record get a list of the protocol sequences and get
711 * the port number
712 */uint8_t svc_uuid_int[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
713 dest.b[5], dest.b[4], dest.b[3],
714 dest.b[2], dest.b[1], dest.b[0] };
715 sdp_session_t *session = 0;
716 sdp_list_t *search_list = 0, *attrid_list = 0, *response_list = 0, *it = 0;
717 uuid_t svc_uuid;
718 uint32_t range = 0x0000ffff;
719 int channel = -1;
720
721 /* Connect to the local SDP server */
722 session = sdp_connect (BDADDR_ANY, &dest, 0);
723 if (! session)
724 {
725 fprintf (stderr,
726 "Failed to connect to the SDP server on interface `%.*s': %s\n",
727 IFNAMSIZ, dev->iface, strerror (errno));
728 return -1;
729 }
730
731 sdp_uuid128_create (&svc_uuid, &svc_uuid_int);
732 search_list = sdp_list_append (0, &svc_uuid);
733 attrid_list = sdp_list_append (0, &range);
734
735 if (sdp_service_search_attr_req (session, search_list,
736 SDP_ATTR_REQ_RANGE, attrid_list,
737 &response_list) == 0)
738 {
739 for (it = response_list; it; it = it->next)
740 {
741 sdp_record_t *record = (sdp_record_t *) it->data;
742 sdp_list_t *proto_list = 0;
743 if (sdp_get_access_protos (record, &proto_list) == 0)
744 {
745 channel = sdp_get_proto_port (proto_list, RFCOMM_UUID);
746 sdp_list_free (proto_list, 0);
747 }
748 sdp_record_free (record);
749 }
750 }
751
752 sdp_list_free (search_list, 0);
753 sdp_list_free (attrid_list, 0);
754 sdp_list_free (response_list, 0);
755
756 sdp_close (session);
757
758 if (-1 == channel)
759 fprintf (stderr,
760 "Failed to find the listening channel for interface `%.*s': %s\n",
761 IFNAMSIZ,
762 dev->iface,
763 strerror (errno));
764
765 return channel;
766}
767
768
769/**
770 * Read from the socket and put the result into the buffer for transmission to 'stdout'.
771 *
772 * @param sock file descriptor for reading
773 * @param buf buffer to read to; first bytes will be the 'struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame',
774 * followed by the actual payload
775 * @param buf_size size of the buffer
776 * @param ri where to write radiotap_rx info
777 * @return number of bytes written to 'buf'
778 */
779static ssize_t
780read_from_the_socket (void *sock,
781 unsigned char *buf, size_t buf_size,
782 struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage *ri)
783{
784 unsigned char tmpbuf[buf_size];
785 ssize_t count;
786 count = read (*((int *) sock), tmpbuf, buf_size);
787
788 if (0 > count)
789 {
790 if (EAGAIN == errno)
791 return 0;
792
793 fprintf (stderr, "Failed to read from the HCI socket: %s\n", strerror (
794 errno));
795
796 return -1;
797 }
798
799 #ifdef __linux__
800 /* Get the channel used */
801 int len;
802 struct sockaddr_rc rc_addr = { 0 };
803
804 memset (&rc_addr, 0, sizeof(rc_addr));
805 len = sizeof(rc_addr);
806 if (0 > getsockname (*((int *) sock), (struct sockaddr *) &rc_addr,
807 (socklen_t *) &len))
808 {
809 fprintf (stderr, "getsockname() call failed : %s\n", strerror (errno));
810 return -1;
811 }
812
813 memset (ri, 0, sizeof(*ri));
814 ri->ri_channel = rc_addr.rc_channel;
815 #endif
816
817 /* Detect CRC32 at the end */
818 if (0 == check_crc_buf_osdep (tmpbuf, count - sizeof(uint32_t)))
819 {
820 count -= sizeof(uint32_t);
821 }
822
823 GNUNET_memcpy (buf, tmpbuf, count);
824
825 return count;
826}
827
828
829/**
830 * Open the bluetooth interface for reading/writing
831 *
832 * @param dev pointer to the device struct
833 * @return 0 on success, non-zero on error
834 */
835static int
836open_device (struct HardwareInfos *dev)
837{
838 int i, dev_id = -1, fd_hci;
839 struct
840 {
841 struct hci_dev_list_req list;
842 struct hci_dev_req dev[HCI_MAX_DEV];
843 } request; // used for detecting the local devices
844 struct sockaddr_rc rc_addr = { 0 }; // used for binding
845
846 /* Initialize the neighbour structure */
847 neighbours.dev_id = -1;
848 for (i = 0; i < MAX_PORTS; i++)
849 neighbours.fds[i] = -1;
850
851 /* Open a HCI socket */
852 fd_hci = socket (AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
853
854 if (fd_hci < 0)
855 {
856 fprintf (stderr,
857 "Failed to create HCI socket: %s\n",
858 strerror (errno));
859 return -1;
860 }
861
862 memset (&request, 0, sizeof(request));
863 request.list.dev_num = HCI_MAX_DEV;
864
865 if (ioctl (fd_hci, HCIGETDEVLIST, (void *) &request) < 0)
866 {
867 fprintf (stderr,
868 "ioctl(HCIGETDEVLIST) on interface `%.*s' failed: %s\n",
869 IFNAMSIZ,
870 dev->iface,
871 strerror (errno));
872 (void) close (fd_hci);
873 return 1;
874 }
875
876 /* Search for a device with dev->iface name */
877 for (i = 0; i < request.list.dev_num; i++)
878 {
879 struct hci_dev_info dev_info;
880
881 memset (&dev_info, 0, sizeof(struct hci_dev_info));
882 dev_info.dev_id = request.dev[i].dev_id;
883 strncpy (dev_info.name, dev->iface, BLUEZ_DEVNAME_SIZE);
884
885 if (ioctl (fd_hci, HCIGETDEVINFO, (void *) &dev_info))
886 {
887 fprintf (stderr,
888 "ioctl(HCIGETDEVINFO) on interface `%.*s' failed: %s\n",
889 IFNAMSIZ,
890 dev->iface,
891 strerror (errno));
892 (void) close (fd_hci);
893 return 1;
894 }
895
896 if (strncmp (dev_info.name, dev->iface, BLUEZ_DEVNAME_SIZE) == 0)
897 {
898 dev_id = dev_info.dev_id; // the device was found
899 /**
900 * Copy the MAC address to the device structure
901 */
902 GNUNET_memcpy (&dev->pl_mac, &dev_info.bdaddr, sizeof(bdaddr_t));
903
904 /* Check if the interface is up */
905 if (hci_test_bit (HCI_UP, (void *) &dev_info.flags) == 0)
906 {
907 /* Bring the interface up */
908 if (ioctl (fd_hci, HCIDEVUP, dev_info.dev_id))
909 {
910 fprintf (stderr,
911 "ioctl(HCIDEVUP) on interface `%.*s' failed: %s\n",
912 IFNAMSIZ,
913 dev->iface,
914 strerror (errno));
915 (void) close (fd_hci);
916 return 1;
917 }
918 }
919
920 /* Check if the device is discoverable */
921 if ((hci_test_bit (HCI_PSCAN, (void *) &dev_info.flags) == 0) ||
922 (hci_test_bit (HCI_ISCAN, (void *) &dev_info.flags) == 0) )
923 {
924 /* Set interface Page Scan and Inqury Scan ON */
925 struct hci_dev_req dev_req;
926
927 memset (&dev_req, 0, sizeof(dev_req));
928 dev_req.dev_id = dev_info.dev_id;
929 dev_req.dev_opt = SCAN_PAGE | SCAN_INQUIRY;
930
931 if (ioctl (fd_hci, HCISETSCAN, (unsigned long) &dev_req))
932 {
933 fprintf (stderr,
934 "ioctl(HCISETSCAN) on interface `%.*s' failed: %s\n",
935 IFNAMSIZ,
936 dev->iface,
937 strerror (errno));
938 (void) close (fd_hci);
939 return 1;
940 }
941 }
942 break;
943 }
944 }
945
946 /* Check if the interface was not found */
947 if (-1 == dev_id)
948 {
949 fprintf (stderr,
950 "The interface %s was not found\n",
951 dev->iface);
952 (void) close (fd_hci);
953 return 1;
954 }
955
956 /* Close the hci socket */
957 (void) close (fd_hci);
958
959
960 /* Bind the rfcomm socket to the interface */
961 memset (&rc_addr, 0, sizeof(rc_addr));
962 rc_addr.rc_family = AF_BLUETOOTH;
963 rc_addr.rc_bdaddr = *BDADDR_ANY;
964
965 if (bind_socket (dev->fd_rfcomm, &rc_addr) != 0)
966 {
967 fprintf (stderr,
968 "Failed to bind interface `%.*s': %s\n",
969 IFNAMSIZ,
970 dev->iface,
971 strerror (errno));
972 return 1;
973 }
974
975 /* Register a SDP service */
976 if (register_service (dev, rc_addr.rc_channel) != 0)
977 {
978 fprintf (stderr,
979 "Failed to register a service on interface `%.*s': %s\n",
980 IFNAMSIZ,
981 dev->iface, strerror (errno));
982 return 1;
983 }
984
985 /* Switch socket in listening mode */
986 if (listen (dev->fd_rfcomm, 5) == -1) // FIXME: probably we need a bigger number
987 {
988 fprintf (stderr, "Failed to listen on socket for interface `%.*s': %s\n",
989 IFNAMSIZ,
990 dev->iface, strerror (errno));
991 return 1;
992 }
993
994 return 0;
995}
996
997
998/**
999 * Set the header to sane values to make attacks more difficult
1000 *
1001 * @param taIeeeHeader pointer to the header of the packet
1002 * @param dev pointer to the Hardware_Infos struct
1003 *
1004 **** copy from gnunet-helper-transport-wlan.c ****
1005 */
1006static void
1007mac_set (struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *taIeeeHeader,
1008 const struct HardwareInfos *dev)
1009{
1010 taIeeeHeader->frame_control = htons (IEEE80211_FC0_TYPE_DATA);
1011 taIeeeHeader->addr3 = mac_bssid_gnunet;
1012 taIeeeHeader->addr2 = dev->pl_mac;
1013}
1014
1015
1016#ifdef __linux__
1017/**
1018 * Test if the given interface name really corresponds to a bluetooth
1019 * device.
1020 *
1021 * @param iface name of the interface
1022 * @return 0 on success, 1 on error
1023 **** similar with the one from gnunet-helper-transport-wlan.c ****
1024 */
1025static int
1026test_bluetooth_interface (const char *iface)
1027{
1028 char strbuf[512];
1029 struct stat sbuf;
1030 int ret;
1031
1032 ret = snprintf (strbuf, sizeof(strbuf),
1033 "/sys/class/bluetooth/%s/subsystem",
1034 iface);
1035 if ((ret < 0) || (ret >= sizeof(strbuf)) || (0 != stat (strbuf, &sbuf)))
1036 {
1037 fprintf (stderr,
1038 "Did not find 802.15.1 interface `%s'. Exiting.\n",
1039 iface);
1040 exit (1);
1041 }
1042 return 0;
1043}
1044
1045
1046#endif
1047
1048/**
1049 * Test incoming packets mac for being our own.
1050 *
1051 * @param taIeeeHeader buffer of the packet
1052 * @param dev the Hardware_Infos struct
1053 * @return 0 if mac belongs to us, 1 if mac is for another target
1054 *
1055 **** same as the one from gnunet-helper-transport-wlan.c ****
1056 */
1057static int
1058mac_test (const struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *taIeeeHeader,
1059 const struct HardwareInfos *dev)
1060{
1061 static struct GNUNET_TRANSPORT_WLAN_MacAddress all_zeros;
1062
1063 if ((0 == memcmp (&taIeeeHeader->addr3, &all_zeros, MAC_ADDR_SIZE)) ||
1064 (0 == memcmp (&taIeeeHeader->addr1, &all_zeros, MAC_ADDR_SIZE)))
1065 return 0; /* some drivers set no Macs, then assume it is all for us! */
1066
1067 if (0 != memcmp (&taIeeeHeader->addr3, &mac_bssid_gnunet, MAC_ADDR_SIZE))
1068 return 1; /* not a GNUnet ad-hoc package */
1069 if ((0 == memcmp (&taIeeeHeader->addr1, &dev->pl_mac, MAC_ADDR_SIZE)) ||
1070 (0 == memcmp (&taIeeeHeader->addr1, &bc_all_mac, MAC_ADDR_SIZE)))
1071 return 0; /* for us, or broadcast */
1072 return 1; /* not for us */
1073}
1074
1075
1076/**
1077 * Process data from the stdin. Takes the message, forces the sender MAC to be correct
1078 * and puts it into our buffer for transmission to the receiver.
1079 *
1080 * @param cls pointer to the device struct ('struct HardwareInfos*')
1081 * @param hdr pointer to the start of the packet
1082 *
1083 **** same as the one from gnunet-helper-transport-wlan.c ****
1084 */
1085static void
1086stdin_send_hw (void *cls, const struct GNUNET_MessageHeader *hdr)
1087{
1088 struct HardwareInfos *dev = cls;
1089 const struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *header;
1090 struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *blueheader;
1091 size_t sendsize;
1092
1093 sendsize = ntohs (hdr->size);
1094 if ((sendsize <
1095 sizeof(struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage)) ||
1096 (GNUNET_MESSAGE_TYPE_WLAN_DATA_TO_HELPER != ntohs (hdr->type)))
1097 {
1098 fprintf (stderr, "Received malformed message\n");
1099 exit (1);
1100 }
1101 sendsize -= (sizeof(struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage)
1102 - sizeof(struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame));
1103 if (MAXLINE < sendsize)
1104 {
1105 fprintf (stderr, "Packet too big for buffer\n");
1106 exit (1);
1107 }
1108 header = (const struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *) hdr;
1109 GNUNET_memcpy (&write_pout.buf, &header->frame, sendsize);
1110 blueheader = (struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *) &write_pout.buf;
1111
1112 /* payload contains MAC address, but we don't trust it, so we'll
1113 * overwrite it with OUR MAC address to prevent mischief */
1114 mac_set (blueheader, dev);
1115 GNUNET_memcpy (&blueheader->addr1, &header->frame.addr1,
1116 sizeof(struct GNUNET_TRANSPORT_WLAN_MacAddress));
1117 write_pout.size = sendsize;
1118}
1119
1120
1121#ifdef __linux__
1122/**
1123 * Broadcast a HELLO message for peer discovery
1124 *
1125 * @param dev pointer to the device struct
1126 * @param dev pointer to the socket which was added to the set
1127 * @return 0 on success
1128 */
1129static int
1130send_broadcast (struct HardwareInfos *dev, int *sendsocket)
1131{
1132 int new_device = 0;
1133 int loops = 0;
1134
1135search_for_devices:
1136 if (((neighbours.size == neighbours.pos) && (new_device == 1)) ||
1137 (neighbours.size == 0) )
1138 {
1139inquiry_devices: // skip the conditions and force a inquiry for new devices
1140 {
1141 /**
1142 * It means that I sent HELLO messages to all the devices from the list and I should search
1143 * for new ones or that this is the first time when I do a search.
1144 */
1145 inquiry_info *devices = NULL;
1146 int i, responses, max_responses = MAX_PORTS;
1147
1148 /* sanity checks */
1149 if (neighbours.size >= MAX_PORTS)
1150 {
1151 fprintf (stderr,
1152 "%.*s reached the top limit for the discovarable devices\n",
1153 IFNAMSIZ,
1154 dev->iface);
1155 return 2;
1156 }
1157
1158 /* Get the device id */
1159 if (neighbours.dev_id == -1)
1160 {
1161 char addr[19] = { 0 }; // the device MAC address
1162
1163 ba2str ((bdaddr_t *) &dev->pl_mac, addr);
1164 neighbours.dev_id = hci_devid (addr);
1165 if (neighbours.dev_id < 0)
1166 {
1167 fprintf (stderr,
1168 "Failed to get the device id for interface %.*s : %s\n",
1169 IFNAMSIZ,
1170 dev->iface, strerror (errno));
1171 return 1;
1172 }
1173 }
1174
1175 devices = malloc (max_responses * sizeof(inquiry_info));
1176 if (devices == NULL)
1177 {
1178 fprintf (stderr,
1179 "Failed to allocate memory for inquiry info list on interface %.*s\n",
1180 IFNAMSIZ,
1181 dev->iface);
1182 return 1;
1183 }
1184
1185 responses = hci_inquiry (neighbours.dev_id, 8, max_responses, NULL,
1186 &devices, IREQ_CACHE_FLUSH);
1187 if (responses < 0)
1188 {
1189 fprintf (stderr, "Failed to inquiry on interface %.*s\n", IFNAMSIZ,
1190 dev->iface);
1191 return 1;
1192 }
1193
1194 fprintf (stderr, "LOG : Found %d devices\n", responses); // FIXME delete it after debugging stage
1195
1196 if (responses == 0)
1197 {
1198 fprintf (stderr, "LOG : No devices discoverable\n");
1199 return 1;
1200 }
1201
1202 for (i = 0; i < responses; i++)
1203 {
1204 int j;
1205 int found = 0;
1206
1207 /* sanity check */
1208 if (i >= MAX_PORTS)
1209 {
1210 fprintf (stderr,
1211 "%.*s reached the top limit for the discoverable devices (after inquiry)\n",
1212 IFNAMSIZ,
1213 dev->iface);
1214 return 2;
1215 }
1216
1217 /* Search if the address already exists on the list */
1218 for (j = 0; j < neighbours.size; j++)
1219 {
1220 if (memcmp (&(devices + i)->bdaddr, &(neighbours.devices[j]),
1221 sizeof(bdaddr_t)) == 0)
1222 {
1223 found = 1;
1224 fprintf (stderr, "LOG : the device already exists on the list\n"); // FIXME debugging message
1225 break;
1226 }
1227 }
1228
1229 if (found == 0)
1230 {
1231 char addr[19] = { 0 };
1232
1233 ba2str (&(devices + i)->bdaddr, addr);
1234 fprintf (stderr, "LOG : %s was added to the list\n", addr); // FIXME debugging message
1235 GNUNET_memcpy (&(neighbours.devices[neighbours.size++]), &(devices
1236 + i)->
1237 bdaddr, sizeof(bdaddr_t));
1238 }
1239 }
1240
1241 free (devices);
1242 }
1243 }
1244
1245 int connection_successful = 0;
1246 struct sockaddr_rc addr_rc = { 0 };
1247 int errno_copy = 0;
1248 addr_rc.rc_family = AF_BLUETOOTH;
1249
1250 /* Try to connect to a new device from the list */
1251 while (neighbours.pos < neighbours.size)
1252 {
1253 /* Check if we are already connected to this device */
1254 if (neighbours.fds[neighbours.pos] == -1)
1255 {
1256 memset (&addr_rc.rc_bdaddr, 0, sizeof(addr_rc.rc_bdaddr));
1257 GNUNET_memcpy (&addr_rc.rc_bdaddr, &(neighbours.devices[neighbours.pos]),
1258 sizeof(addr_rc.rc_bdaddr));
1259
1260 addr_rc.rc_channel = get_channel (dev, addr_rc.rc_bdaddr);
1261
1262 *sendsocket = socket (AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
1263 if ((-1 < *sendsocket) &&
1264 (0 == connect (*sendsocket,
1265 (struct sockaddr *) &addr_rc,
1266 sizeof(addr_rc))))
1267 {
1268 neighbours.fds[neighbours.pos++] = *sendsocket;
1269 connection_successful = 1;
1270 char addr[19] = { 0 };
1271 ba2str (&(neighbours.devices[neighbours.pos - 1]), addr);
1272 fprintf (stderr, "LOG : Connected to %s\n", addr);
1273 break;
1274 }
1275 else
1276 {
1277 char addr[19] = { 0 };
1278 errno_copy = errno; // Save a copy for later
1279
1280 if (-1 != *sendsocket)
1281 {
1282 (void) close (*sendsocket);
1283 *sendsocket = -1;
1284 }
1285 ba2str (&(neighbours.devices[neighbours.pos]), addr);
1286 fprintf (stderr,
1287 "LOG : Couldn't connect on device %s, error : %s\n",
1288 addr,
1289 strerror (errno));
1290 if (errno != ECONNREFUSED) // FIXME be sure that this works
1291 {
1292 fprintf (stderr, "LOG : Removes %d device from the list\n",
1293 neighbours.pos);
1294 /* Remove the device from the list */
1295 GNUNET_memcpy (&neighbours.devices[neighbours.pos],
1296 &neighbours.devices[neighbours.size - 1],
1297 sizeof(bdaddr_t));
1298 memset (&neighbours.devices[neighbours.size - 1], 0,
1299 sizeof(bdaddr_t));
1300 neighbours.fds[neighbours.pos] = neighbours.fds[neighbours.size - 1];
1301 neighbours.fds[neighbours.size - 1] = -1;
1302 neighbours.size -= 1;
1303 }
1304
1305 neighbours.pos += 1;
1306
1307 if (neighbours.pos >= neighbours.size)
1308 neighbours.pos = 0;
1309
1310 loops += 1;
1311
1312 if (loops == MAX_LOOPS) // don't get stuck trying to connect to one device
1313 return 1;
1314 }
1315 }
1316 else
1317 {
1318 fprintf (stderr, "LOG : Search for a new device\n"); // FIXME debugging message
1319 neighbours.pos += 1;
1320 }
1321 }
1322
1323 /* Cycle on the list */
1324 if (neighbours.pos == neighbours.size)
1325 {
1326 neighbours.pos = 0;
1327 searching_devices_count += 1;
1328
1329 if (searching_devices_count == MAX_LOOPS)
1330 {
1331 fprintf (stderr, "LOG : Force to inquiry for new devices\n");
1332 searching_devices_count = 0;
1333 goto inquiry_devices;
1334 }
1335 }
1336 /* If a new device wasn't found, search an old one */
1337 if (connection_successful == 0)
1338 {
1339 int loop_check = neighbours.pos;
1340 while (neighbours.fds[neighbours.pos] == -1)
1341 {
1342 if (neighbours.pos == neighbours.size)
1343 neighbours.pos = 0;
1344
1345 if (neighbours.pos == loop_check)
1346 {
1347 if (errno_copy == ECONNREFUSED)
1348 {
1349 fprintf (stderr, "LOG : No device found. Go back and search again\n"); // FIXME debugging message
1350 new_device = 1;
1351 loops += 1;
1352 goto search_for_devices;
1353 }
1354 else
1355 {
1356 return 1; // Skip the broadcast message
1357 }
1358 }
1359
1360 neighbours.pos += 1;
1361 }
1362
1363 *sendsocket = neighbours.fds[neighbours.pos++];
1364 }
1365
1366 return 0;
1367}
1368
1369
1370#endif
1371
1372/**
1373 * Main function of the helper. This code accesses a bluetooth interface
1374 * forwards traffic in both directions between the bluetooth interface and
1375 * stdin/stdout of this process. Error messages are written to stderr.
1376 *
1377 * @param argc number of arguments, must be 2
1378 * @param argv arguments only argument is the name of the interface (e.g. 'hci0')
1379 * @return 0 on success (never happens, as we don't return unless aborted), 1 on error
1380 *
1381 **** similar to gnunet-helper-transport-wlan.c ****
1382 */
1383int
1384main (int argc, char *argv[])
1385{
1386#ifdef __linux__
1387 struct HardwareInfos dev;
1388 char readbuf[MAXLINE];
1389 int maxfd;
1390 fd_set rfds;
1391 fd_set wfds;
1392 int stdin_open;
1393 struct MessageStreamTokenizer *stdin_mst;
1394 int raw_eno, i;
1395 int crt_rfds = 0, rfds_list[MAX_PORTS];
1396 int broadcast, sendsocket;
1397
1398 /* Assert privs so we can modify the firewall rules! */
1399 {
1400#ifdef HAVE_SETRESUID
1401 uid_t uid = getuid ();
1402
1403 if (0 != setresuid (uid, 0, 0))
1404 {
1405 fprintf (stderr,
1406 "Failed to setresuid to root: %s\n",
1407 strerror (errno));
1408 return 254;
1409 }
1410#else
1411 if (0 != seteuid (0))
1412 {
1413 fprintf (stderr,
1414 "Failed to seteuid back to root: %s\n", strerror (errno));
1415 return 254;
1416 }
1417#endif
1418 }
1419
1420 /* Make use of SGID capabilities on POSIX */
1421 memset (&dev, 0, sizeof(dev));
1422 dev.fd_rfcomm = socket (AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
1423 raw_eno = errno; /* remember for later */
1424
1425 /* Now that we've dropped root rights, we can do error checking */
1426 if (2 != argc)
1427 {
1428 fprintf (stderr,
1429 "You must specify the name of the interface as the first \
1430 and only argument to this program.\n");
1431 if (-1 != dev.fd_rfcomm)
1432 (void) close (dev.fd_rfcomm);
1433 return 1;
1434 }
1435
1436 if (-1 == dev.fd_rfcomm)
1437 {
1438 fprintf (stderr, "Failed to create a RFCOMM socket: %s\n", strerror (
1439 raw_eno));
1440 return 1;
1441 }
1442 if (dev.fd_rfcomm >= FD_SETSIZE)
1443 {
1444 fprintf (stderr, "File descriptor too large for select (%d > %d)\n",
1445 dev.fd_rfcomm, FD_SETSIZE);
1446 (void) close (dev.fd_rfcomm);
1447 return 1;
1448 }
1449 if (0 != test_bluetooth_interface (argv[1]))
1450 {
1451 (void) close (dev.fd_rfcomm);
1452 return 1;
1453 }
1454 strncpy (dev.iface, argv[1], IFNAMSIZ);
1455 if (0 != open_device (&dev))
1456 {
1457 (void) close (dev.fd_rfcomm);
1458 return 1;
1459 }
1460
1461 /* Drop privs */
1462 {
1463 uid_t uid = getuid ();
1464 #ifdef HAVE_SETRESUID
1465 if (0 != setresuid (uid, uid, uid))
1466 {
1467 fprintf (stderr, "Failed to setresuid: %s\n", strerror (errno));
1468 if (-1 != dev.fd_rfcomm)
1469 (void) close (dev.fd_rfcomm);
1470 return 1;
1471 }
1472 #else
1473 if (0 != (setuid (uid) | seteuid (uid)))
1474 {
1475 fprintf (stderr, "Failed to setuid: %s\n", strerror (errno));
1476 if (-1 != dev.fd_rfcomm)
1477 (void) close (dev.fd_rfcomm);
1478 return 1;
1479 }
1480 #endif
1481 }
1482
1483 /* Send MAC address of the bluetooth interface to STDOUT first */
1484 {
1485 struct GNUNET_TRANSPORT_WLAN_HelperControlMessage macmsg;
1486
1487 macmsg.hdr.size = htons (sizeof(macmsg));
1488 macmsg.hdr.type = htons (GNUNET_MESSAGE_TYPE_WLAN_HELPER_CONTROL);
1489 GNUNET_memcpy (&macmsg.mac, &dev.pl_mac, sizeof(struct
1490 GNUNET_TRANSPORT_WLAN_MacAddress));
1491 GNUNET_memcpy (write_std.buf, &macmsg, sizeof(macmsg));
1492 write_std.size = sizeof(macmsg);
1493 }
1494
1495
1496 stdin_mst = mst_create (&stdin_send_hw, &dev);
1497 stdin_open = 1;
1498
1499 /**
1500 * TODO : I should make the time out of a mac endpoint smaller and check if the rate
1501 * from get_wlan_header (plugin_transport_bluetooth.c) is correct.
1502 */
1503 while (1)
1504 {
1505 maxfd = -1;
1506 broadcast = 0;
1507 sendsocket = -1;
1508
1509 FD_ZERO (&rfds);
1510 if ((0 == write_pout.size) && (1 == stdin_open))
1511 {
1512 FD_SET (STDIN_FILENO, &rfds);
1513 maxfd = MAX (maxfd, STDIN_FILENO);
1514 }
1515 if (0 == write_std.size)
1516 {
1517 FD_SET (dev.fd_rfcomm, &rfds);
1518 maxfd = MAX (maxfd, dev.fd_rfcomm);
1519 }
1520
1521 for (i = 0; i < crt_rfds; i++) // it can receive messages from multiple devices
1522 {
1523 FD_SET (rfds_list[i], &rfds);
1524 maxfd = MAX (maxfd, rfds_list[i]);
1525 }
1526 FD_ZERO (&wfds);
1527 if (0 < write_std.size)
1528 {
1529 FD_SET (STDOUT_FILENO, &wfds);
1530 maxfd = MAX (maxfd, STDOUT_FILENO);
1531 }
1532 if (0 < write_pout.size) // it can send messages only to one device per loop
1533 {
1534 struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *frame;
1535 /* Get the destination address */
1536 frame = (struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *) write_pout.buf;
1537
1538 if (memcmp (&frame->addr1, &dev.pl_mac,
1539 sizeof(struct GNUNET_TRANSPORT_WLAN_MacAddress)) == 0)
1540 {
1541 broadcast = 1;
1542 memset (&write_pout, 0, sizeof(write_pout)); // clear the buffer
1543 }
1544 else if (memcmp (&frame->addr1, &broadcast_address,
1545 sizeof(struct GNUNET_TRANSPORT_WLAN_MacAddress)) == 0)
1546 {
1547 fprintf (stderr, "LOG : %s has a broadcast message (pos %d, size %d)\n",
1548 dev.iface, neighbours.pos, neighbours.size); // FIXME: debugging message
1549
1550 if (send_broadcast (&dev, &sendsocket) != 0) // if the searching wasn't successful don't get stuck on the select stage
1551 {
1552 broadcast = 1;
1553 memset (&write_pout, 0, sizeof(write_pout)); // remove the message
1554 fprintf (stderr,
1555 "LOG : Skipping the broadcast message (pos %d, size %d)\n",
1556 neighbours.pos, neighbours.size);
1557 }
1558 else
1559 {
1560 FD_SET (sendsocket, &wfds);
1561 maxfd = MAX (maxfd, sendsocket);
1562 }
1563 }
1564 else
1565 {
1566 int found = 0;
1567 int pos = 0;
1568 /* Search if the address already exists on the list */
1569 for (i = 0; i < neighbours.size; i++)
1570 {
1571 if (memcmp (&frame->addr1, &(neighbours.devices[i]),
1572 sizeof(bdaddr_t)) == 0)
1573 {
1574 pos = i;
1575 if (neighbours.fds[i] != -1)
1576 {
1577 found = 1; // save the position where it was found
1578 FD_SET (neighbours.fds[i], &wfds);
1579 maxfd = MAX (maxfd, neighbours.fds[i]);
1580 sendsocket = neighbours.fds[i];
1581 fprintf (stderr, "LOG: the address was found in the list\n");
1582 break;
1583 }
1584 }
1585 }
1586 if (found == 0)
1587 {
1588 int status;
1589 struct sockaddr_rc addr = { 0 };
1590
1591 fprintf (stderr,
1592 "LOG : %s has a new message for %.2X:%.2X:%.2X:%.2X:%.2X:%.2X which isn't on the broadcast list\n",
1593 dev.iface,
1594 frame->addr1.mac[5], frame->addr1.mac[4],
1595 frame->addr1.mac[3],
1596 frame->addr1.mac[2], frame->addr1.mac[1],
1597 frame->addr1.mac[0]); // FIXME: debugging message
1598
1599 sendsocket = socket (AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
1600
1601 if (sendsocket < 0)
1602 {
1603 fprintf (stderr,
1604 "Failed to create a RFCOMM socket (sending stage): %s\n",
1605 strerror (errno));
1606 return -1;
1607 }
1608
1609 GNUNET_memcpy (&addr.rc_bdaddr, &frame->addr1, sizeof(bdaddr_t));
1610 addr.rc_family = AF_BLUETOOTH;
1611 addr.rc_channel = get_channel (&dev, addr.rc_bdaddr);
1612
1613 int tries = 0;
1614connect_retry:
1615 status = connect (sendsocket, (struct sockaddr *) &addr,
1616 sizeof(addr));
1617 if ((0 != status) && (errno != EAGAIN) )
1618 {
1619 if ((errno == ECONNREFUSED) && (tries < 2) )
1620 {
1621 fprintf (stderr, "LOG : %.*s failed to connect. Trying again!\n",
1622 IFNAMSIZ, dev.iface);
1623 tries++;
1624 goto connect_retry;
1625 }
1626 else if (errno == EBADF)
1627 {
1628 fprintf (stderr, "LOG : %s failed to connect : %s. Skip it!\n",
1629 dev.iface, strerror (errno));
1630 memset (&write_pout, 0, sizeof(write_pout));
1631 broadcast = 1;
1632 }
1633 else
1634 {
1635 fprintf (stderr,
1636 "LOG : %s failed to connect : %s. Try again later!\n",
1637 dev.iface,
1638 strerror (errno));
1639 memset (&write_pout, 0, sizeof(write_pout));
1640 broadcast = 1;
1641 }
1642 }
1643 else
1644 {
1645 FD_SET (sendsocket, &wfds);
1646 maxfd = MAX (maxfd, sendsocket);
1647 fprintf (stderr, "LOG : Connection successful\n");
1648 if (pos != 0) // save the socket
1649 {
1650 neighbours.fds[pos] = sendsocket;
1651 }
1652 else
1653 {
1654 /* Add the new device to the discovered devices list */
1655 if (neighbours.size < MAX_PORTS)
1656 {
1657 neighbours.fds[neighbours.size] = sendsocket;
1658 GNUNET_memcpy (&(neighbours.devices[neighbours.size++]),
1659 &addr.rc_bdaddr, sizeof(bdaddr_t));
1660 }
1661 else
1662 {
1663 fprintf (stderr,
1664 "The top limit for the discovarable devices' list was reached\n");
1665 }
1666 }
1667 }
1668 }
1669 }
1670 }
1671
1672 if (broadcast == 0)
1673 {
1674 /* Select a fd which is ready for action :) */
1675 {
1676 int retval = select (maxfd + 1, &rfds, &wfds, NULL, NULL);
1677 if ((-1 == retval) && (EINTR == errno))
1678 continue;
1679 if ((0 > retval) && (errno != EBADF) ) // we handle BADF errors later
1680 {
1681 fprintf (stderr, "select failed: %s\n", strerror (errno));
1682 break;
1683 }
1684 }
1685 if (FD_ISSET (STDOUT_FILENO, &wfds))
1686 {
1687 ssize_t ret =
1688 write (STDOUT_FILENO, write_std.buf + write_std.pos,
1689 write_std.size - write_std.pos);
1690 if (0 > ret)
1691 {
1692 fprintf (stderr, "Failed to write to STDOUT: %s\n", strerror (errno));
1693 break;
1694 }
1695 write_std.pos += ret;
1696 if (write_std.pos == write_std.size)
1697 {
1698 write_std.pos = 0;
1699 write_std.size = 0;
1700 }
1701 fprintf (stderr, "LOG : %s sends a message to STDOUT\n", dev.iface); // FIXME: debugging message
1702 }
1703 if (-1 != sendsocket)
1704 {
1705 if (FD_ISSET (sendsocket, &wfds))
1706 {
1707 ssize_t ret = write (sendsocket,
1708 write_pout.buf + write_std.pos,
1709 write_pout.size - write_pout.pos);
1710 if (0 > ret) // FIXME should I first check the error type?
1711 {
1712 fprintf (stderr,
1713 "Failed to write to bluetooth device: %s. Closing the socket!\n",
1714 strerror (errno));
1715 for (i = 0; i < neighbours.size; i++)
1716 {
1717 if (neighbours.fds[i] == sendsocket)
1718 {
1719 (void) close (sendsocket);
1720 neighbours.fds[i] = -1;
1721 break;
1722 }
1723 }
1724 /* Remove the message */
1725 memset (&write_pout.buf + write_std.pos, 0, (write_pout.size
1726 - write_pout.pos));
1727 write_pout.pos = 0;
1728 write_pout.size = 0;
1729 }
1730 else
1731 {
1732 write_pout.pos += ret;
1733 if ((write_pout.pos != write_pout.size) && (0 != ret))
1734 {
1735 /* We should not get partial sends with packet-oriented devices... */
1736 fprintf (stderr, "Write error, partial send: %u/%u\n",
1737 (unsigned int) write_pout.pos,
1738 (unsigned int) write_pout.size);
1739 break;
1740 }
1741
1742 if (write_pout.pos == write_pout.size)
1743 {
1744 write_pout.pos = 0;
1745 write_pout.size = 0;
1746 }
1747 fprintf (stderr, "LOG : %s sends a message to a DEVICE\n",
1748 dev.iface); // FIXME: debugging message
1749 }
1750 }
1751 }
1752 for (i = 0; i <= maxfd; i++)
1753 {
1754 if (FD_ISSET (i, &rfds))
1755 {
1756 if (i == STDIN_FILENO)
1757 {
1758 ssize_t ret =
1759 read (i, readbuf, sizeof(readbuf));
1760 if (0 > ret)
1761 {
1762 fprintf (stderr,
1763 "Read error from STDIN: %s\n",
1764 strerror (errno));
1765 break;
1766 }
1767 if (0 == ret)
1768 {
1769 /* stop reading... */
1770 stdin_open = 0;
1771 }
1772 else
1773 {
1774 mst_receive (stdin_mst, readbuf, ret);
1775 fprintf (stderr, "LOG : %s receives a message from STDIN\n",
1776 dev.iface); // FIXME: debugging message
1777 }
1778 }
1779 else if (i == dev.fd_rfcomm)
1780 {
1781 int readsocket;
1782 struct sockaddr_rc addr = { 0 };
1783 unsigned int opt = sizeof(addr);
1784
1785 readsocket = accept (dev.fd_rfcomm, (struct sockaddr *) &addr,
1786 &opt);
1787 fprintf (stderr, "LOG : %s accepts a message\n", dev.iface); // FIXME: debugging message
1788 if (readsocket == -1)
1789 {
1790 fprintf (stderr,
1791 "Failed to accept a connection on interface: %.*s\n",
1792 IFNAMSIZ,
1793 strerror (errno));
1794 break;
1795 }
1796 else
1797 {
1798 FD_SET (readsocket, &rfds);
1799 maxfd = MAX (maxfd, readsocket);
1800
1801 if (crt_rfds < MAX_PORTS)
1802 rfds_list[crt_rfds++] = readsocket;
1803 else
1804 {
1805 fprintf (stderr,
1806 "The limit for the read file descriptors list was \
1807 reached\n");
1808 break;
1809 }
1810 }
1811 }
1812 else
1813 {
1814 struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage *rrm;
1815 ssize_t ret;
1816 fprintf (stderr, "LOG : %s reads something from the socket\n",
1817 dev.iface); // FIXME : debugging message
1818 rrm = (struct
1819 GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage *) write_std.buf;
1820 ret =
1821 read_from_the_socket ((void *) &i, (unsigned char *) &rrm->frame,
1822 sizeof(write_std.buf)
1823 - sizeof(struct
1824 GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage)
1825 + sizeof(struct
1826 GNUNET_TRANSPORT_WLAN_Ieee80211Frame),
1827 rrm);
1828 if (0 >= ret)
1829 {
1830 int j;
1831 FD_CLR (i, &rfds);
1832 close (i);
1833 /* Remove the socket from the list */
1834 for (j = 0; j < crt_rfds; j++)
1835 {
1836 if (rfds_list[j] == i)
1837 {
1838 rfds_list[j] ^= rfds_list[crt_rfds - 1];
1839 rfds_list[crt_rfds - 1] ^= rfds_list[j];
1840 rfds_list[j] ^= rfds_list[crt_rfds - 1];
1841 crt_rfds -= 1;
1842 break;
1843 }
1844 }
1845
1846 fprintf (stderr, "Read error from raw socket: %s\n", strerror (
1847 errno));
1848 break;
1849 }
1850 if ((0 < ret) && (0 == mac_test (&rrm->frame, &dev)))
1851 {
1852 write_std.size = ret
1853 + sizeof(struct
1854 GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage)
1855 - sizeof(struct
1856 GNUNET_TRANSPORT_WLAN_Ieee80211Frame);
1857 rrm->header.size = htons (write_std.size);
1858 rrm->header.type = htons (
1859 GNUNET_MESSAGE_TYPE_WLAN_DATA_FROM_HELPER);
1860 }
1861 }
1862 }
1863 }
1864 }
1865 }
1866 /* Error handling, try to clean up a bit at least */
1867 mst_destroy (stdin_mst);
1868 stdin_mst = NULL;
1869 sdp_close (dev.session);
1870 (void) close (dev.fd_rfcomm);
1871 if (-1 != sendsocket)
1872 (void) close (sendsocket);
1873
1874 for (i = 0; i < crt_rfds; i++)
1875 (void) close (rfds_list[i]);
1876
1877 for (i = 0; i < neighbours.size; i++)
1878 (void) close (neighbours.fds[i]);
1879 #else
1880 struct HardwareInfos dev;
1881 struct GNUNET_NETWORK_Handle *sendsocket;
1882 struct GNUNET_NETWORK_FDSet *rfds;
1883 struct GNUNET_NETWORK_FDSet *wfds;
1884 struct GNUNET_NETWORK_Handle *rfds_list[MAX_PORTS];
1885 char readbuf[MAXLINE] = { 0 };
1886 SOCKADDR_BTH acc_addr = { 0 };
1887 int addr_len = sizeof(SOCKADDR_BTH);
1888 int broadcast, i, stdin_open, crt_rfds = 0;
1889 HANDLE stdin_handle = GetStdHandle (STD_INPUT_HANDLE);
1890 HANDLE stdout_handle = GetStdHandle (STD_OUTPUT_HANDLE);
1891 struct MessageStreamTokenizer *stdin_mst;
1892
1893 /* check the handles */
1894 if (stdin_handle == INVALID_HANDLE_VALUE)
1895 {
1896 fprintf (stderr, "Failed to get the stdin handle\n");
1897 ExitProcess (2);
1898 }
1899
1900 if (stdout_handle == INVALID_HANDLE_VALUE)
1901 {
1902 fprintf (stderr, "Failed to get the stdout handle\n");
1903 ExitProcess (2);
1904 }
1905
1906 /* initialize windows sockets */
1907 initialize_windows_sockets ();
1908
1909 // /* test bluetooth socket family support */ --> it return false because the GNUNET_NETWORK_test_pf should also receive the type of socket (BTHPROTO_RFCOMM)
1910 // if (GNUNET_NETWORK_test_pf (AF_BTH) != GNUNET_OK)
1911 // {
1912 // fprintf (stderr, "AF_BTH family is not supported\n");
1913 // ExitProcess (2);
1914 // }
1915
1916 /* create the socket */
1917 dev.handle = GNUNET_NETWORK_socket_create (AF_BTH, SOCK_STREAM,
1918 BTHPROTO_RFCOMM);
1919 if (dev.handle == NULL)
1920 {
1921 fprintf (stderr, "Failed to create RFCOMM socket: ");
1922 print_last_error ();
1923 ExitProcess (2);
1924 }
1925
1926
1927 if (open_device (&dev) == -1)
1928 {
1929 fprintf (stderr, "Failed to open the device\n");
1930 print_last_error ();
1931 if (GNUNET_NETWORK_socket_close (dev.handle) != GNUNET_OK)
1932 {
1933 fprintf (stderr, "Failed to close the socket!\n");
1934 print_last_error ();
1935 }
1936 ExitProcess (2);
1937 }
1938
1939 if (GNUNET_OK != GNUNET_NETWORK_socket_set_blocking (dev.handle, 1))
1940 {
1941 fprintf (stderr, "Failed to change the socket mode\n");
1942 ExitProcess (2);
1943 }
1944
1945 memset (&write_std, 0, sizeof(write_std));
1946 memset (&write_pout, 0, sizeof(write_pout));
1947 stdin_open = 1;
1948
1949 rfds = GNUNET_NETWORK_fdset_create ();
1950 wfds = GNUNET_NETWORK_fdset_create ();
1951
1952 /* Send MAC address of the bluetooth interface to STDOUT first */
1953 {
1954 struct GNUNET_TRANSPORT_WLAN_HelperControlMessage macmsg;
1955
1956 macmsg.hdr.size = htons (sizeof(macmsg));
1957 macmsg.hdr.type = htons (GNUNET_MESSAGE_TYPE_WLAN_HELPER_CONTROL);
1958 GNUNET_memcpy (&macmsg.mac, &dev.pl_mac, sizeof(struct
1959 GNUNET_TRANSPORT_WLAN_MacAddress_Copy));
1960 GNUNET_memcpy (write_std.buf, &macmsg, sizeof(macmsg));
1961 write_std.size = sizeof(macmsg);
1962 }
1963
1964
1965 stdin_mst = mst_create (&stdin_send_hw, &dev);
1966 stdin_open = 1;
1967
1968 int pos = 0;
1969 int stdin_pos = -1;
1970 int stdout_pos = -1;
1971 while (1)
1972 {
1973 broadcast = 0;
1974 pos = 0;
1975 stdin_pos = -1;
1976 stdout_pos = -1;
1977 sendsocket = NULL; // FIXME ???memleaks
1978
1979 GNUNET_NETWORK_fdset_zero (rfds);
1980 if ((0 == write_pout.size) && (1 == stdin_open))
1981 {
1982 stdin_pos = pos;
1983 pos += 1;
1984 GNUNET_NETWORK_fdset_handle_set (rfds, (struct
1985 GNUNET_DISK_FileHandle*) &
1986 stdin_handle);
1987 }
1988
1989 if (0 == write_std.size)
1990 {
1991 pos += 1;
1992 GNUNET_NETWORK_fdset_set (rfds, dev.handle);
1993 }
1994
1995 for (i = 0; i < crt_rfds; i++)
1996 {
1997 pos += 1;
1998 GNUNET_NETWORK_fdset_set (rfds, rfds_list[i]);
1999 }
2000
2001 GNUNET_NETWORK_fdset_zero (wfds);
2002 if (0 < write_std.size)
2003 {
2004 stdout_pos = pos;
2005 GNUNET_NETWORK_fdset_handle_set (wfds, (struct
2006 GNUNET_DISK_FileHandle*) &
2007 stdout_handle);
2008 // printf ("%s\n", write_std.buf);
2009 // memset (write_std.buf, 0, write_std.size);
2010 // write_std.size = 0;
2011 }
2012
2013 if (0 < write_pout.size)
2014 {
2015 if (strcmp (argv[1], "ff:ff:ff:ff:ff:ff") == 0)
2016 {
2017 fprintf (stderr, "LOG: BROADCAST! Skipping the message\n");
2018 // skip the message
2019 broadcast = 1;
2020 memset (write_pout.buf, 0, write_pout.size);
2021 write_pout.size = 0;
2022 }
2023 else
2024 {
2025 SOCKADDR_BTH addr;
2026 fprintf (stderr, "LOG : has a new message for %s\n", argv[1]);
2027 sendsocket = GNUNET_NETWORK_socket_create (AF_BTH, SOCK_STREAM,
2028 BTHPROTO_RFCOMM);
2029
2030 if (sendsocket == NULL)
2031 {
2032 fprintf (stderr, "Failed to create RFCOMM socket: \n");
2033 print_last_error ();
2034 ExitProcess (2);
2035 }
2036
2037 memset (&addr, 0, sizeof(addr));
2038 // addr.addressFamily = AF_BTH;
2039 if (SOCKET_ERROR ==
2040 WSAStringToAddress (argv[1], AF_BTH, NULL, (LPSOCKADDR) &addr,
2041 &addr_len))
2042 {
2043 fprintf (stderr, "Failed to translate the address: ");
2044 print_last_error ();
2045 ExitProcess (2);
2046 }
2047 addr.port = get_channel (argv[1]);
2048 if (addr.port == -1)
2049 {
2050 fprintf (stderr,
2051 "Couldn't find the sdp service for the address: %s\n",
2052 argv[1]);
2053 memset (write_pout.buf, 0, write_pout.size);
2054 write_pout.size = 0;
2055 broadcast = 1; // skipping the select part
2056 }
2057 else
2058 {
2059 if (GNUNET_OK != GNUNET_NETWORK_socket_connect (sendsocket,
2060 (LPSOCKADDR) &addr,
2061 addr_len))
2062 {
2063 fprintf (stderr, "Failed to connect: ");
2064 print_last_error ();
2065 ExitProcess (2);
2066 }
2067
2068 if (GNUNET_OK != GNUNET_NETWORK_socket_set_blocking (sendsocket, 1))
2069 {
2070 fprintf (stderr, "Failed to change the socket mode\n");
2071 ExitProcess (2);
2072 }
2073
2074 GNUNET_NETWORK_fdset_set (wfds, sendsocket);
2075 }
2076 }
2077 }
2078
2079 if (broadcast == 0)
2080 {
2081 int retval = GNUNET_NETWORK_socket_select (rfds, wfds, NULL,
2082 GNUNET_TIME_relative_get_forever_ ());
2083 if (retval < 0)
2084 {
2085 fprintf (stderr, "Select error\n");
2086 ExitProcess (2);
2087 }
2088 // if (GNUNET_NETWORK_fdset_isset (wfds, (struct GNUNET_NETWORK_Handle*)&stdout_handle))
2089 if (retval == stdout_pos)
2090 {
2091 fprintf (stderr, "LOG : sends a message to STDOUT\n"); // FIXME: debugging message
2092 // ssize_t ret;
2093 // ret = GNUNET_NETWORK_socket_send ((struct GNUNET_NETWORK_Handle *)&stdout_handle, write_std.buf + write_std.pos, write_std.size - write_std.pos);
2094 // ret = write (STDOUT_FILENO, write_std.buf + write_std.pos, write_std.size - write_std.pos);
2095 DWORD ret;
2096 if (FALSE == WriteFile (stdout_handle, write_std.buf + write_std.pos,
2097 write_std.size - write_std.pos, &ret, NULL))
2098 {
2099 fprintf (stderr, "Failed to write to STDOUT: ");
2100 print_last_error ();
2101 break;
2102 }
2103
2104 if (ret <= 0)
2105 {
2106 fprintf (stderr, "Failed to write to STDOUT\n");
2107 ExitProcess (2);
2108 }
2109
2110 write_std.pos += ret;
2111 if (write_std.pos == write_std.size)
2112 {
2113 write_std.pos = 0;
2114 write_std.size = 0;
2115 }
2116 }
2117 if (sendsocket != NULL)
2118 {
2119 if (GNUNET_NETWORK_fdset_isset (wfds, sendsocket))
2120 {
2121 ssize_t ret;
2122 ret = GNUNET_NETWORK_socket_send (sendsocket, write_pout.buf
2123 + write_pout.pos,
2124 write_pout.size - write_pout.pos);
2125
2126 if (GNUNET_SYSERR == ret)
2127 {
2128 fprintf (stderr,
2129 "Failed to send to the socket. Closing the socket. Error: \n");
2130 print_last_error ();
2131 if (GNUNET_NETWORK_socket_close (sendsocket) != GNUNET_OK)
2132 {
2133 fprintf (stderr, "Failed to close the sendsocket!\n");
2134 print_last_error ();
2135 }
2136 ExitProcess (2);
2137 }
2138 else
2139 {
2140 write_pout.pos += ret;
2141 if ((write_pout.pos != write_pout.size) && (0 != ret))
2142 {
2143 /* we should not get partial sends with packet-oriented devices... */
2144 fprintf (stderr, "Write error, partial send: %u/%u\n",
2145 (unsigned int) write_pout.pos,
2146 (unsigned int) write_pout.size);
2147 break;
2148 }
2149
2150 if (write_pout.pos == write_pout.size)
2151 {
2152 write_pout.pos = 0;
2153 write_pout.size = 0;
2154 }
2155 fprintf (stderr, "LOG : sends a message to a DEVICE\n"); // FIXME: debugging message
2156 }
2157 }
2158 }
2159
2160 // if (GNUNET_NETWORK_fdset_isset (rfds, (struct GNUNET_NETWORK_Handle*)&stdin_handle))
2161 if (retval == stdin_pos)
2162 {
2163 // ssize_t ret;
2164 // ret = GNUNET_NETWORK_socket_recv ((struct GNUNET_NETWORK_Handle *)&stdin_handle, readbuf, sizeof (write_pout.buf));
2165 // ret = read (STDIN_FILENO, readbuf, sizeof (readbuf));
2166 DWORD ret;
2167 if (FALSE == ReadFile (stdin_handle, readbuf, sizeof(readbuf), &ret,
2168 NULL)) /* do nothing asynchronous */
2169 {
2170 fprintf (stderr, "Read error from STDIN: ");
2171 print_last_error ();
2172 break;
2173 }
2174 if (0 == ret)
2175 {
2176 /* stop reading... */
2177 stdin_open = 0;
2178 }
2179 else
2180 {
2181 mst_receive (stdin_mst, readbuf, ret);
2182 fprintf (stderr, "LOG : receives a message from STDIN\n"); // FIXME: debugging message
2183 }
2184 }
2185 else if (GNUNET_NETWORK_fdset_isset (rfds, dev.handle))
2186 {
2187 fprintf (stderr, "LOG: accepting connection\n");
2188 struct GNUNET_NETWORK_Handle *readsocket;
2189 readsocket = GNUNET_NETWORK_socket_accept (dev.handle,
2190 (LPSOCKADDR) &acc_addr,
2191 &addr_len);
2192 if (readsocket == NULL)
2193 {
2194 fprintf (stderr, "Accept error %d: ", GetLastError ());
2195 print_last_error ();
2196 ExitProcess (2);
2197 }
2198 else
2199 {
2200 if (GNUNET_OK != GNUNET_NETWORK_socket_set_blocking (readsocket, 1))
2201 {
2202 fprintf (stderr, "Failed to change the socket mode\n");
2203 ExitProcess (2);
2204 }
2205 GNUNET_NETWORK_fdset_set (rfds, readsocket);
2206
2207 if (crt_rfds < MAX_PORTS)
2208 rfds_list[crt_rfds++] = readsocket;
2209 else
2210 {
2211 fprintf (stderr,
2212 "The limit for the read file descriptors list was reached\n");
2213 break;
2214 }
2215 }
2216 }
2217 else
2218 for (i = 0; i < crt_rfds; i++)
2219 {
2220 if (GNUNET_NETWORK_fdset_isset (rfds, rfds_list[i]))
2221 {
2222 struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage *rrm;
2223 ssize_t ret;
2224 fprintf (stderr, "LOG: reading something from the socket\n"); // FIXME : debugging message
2225 rrm = (struct
2226 GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage *) write_std.buf;
2227 ret = read_from_the_socket (rfds_list[i], (unsigned
2228 char *) &rrm->frame,
2229 sizeof(write_std.buf)
2230 - sizeof(struct
2231 GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage)
2232 + sizeof(struct
2233 GNUNET_TRANSPORT_WLAN_Ieee80211Frame),
2234 rrm);
2235 if (0 >= ret)
2236 {
2237 // TODO remove the socket from the list
2238 if (GNUNET_NETWORK_socket_close (rfds_list[i]) != GNUNET_OK)
2239 {
2240 fprintf (stderr, "Failed to close the sendsocket!\n");
2241 print_last_error ();
2242 }
2243
2244 fprintf (stderr, "Read error from raw socket: ");
2245 print_last_error ();
2246 break;
2247 }
2248 if ((0 < ret) && (0 == mac_test (&rrm->frame, &dev)))
2249 {
2250 write_std.size = ret
2251 + sizeof(struct
2252 GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage)
2253 - sizeof(struct
2254 GNUNET_TRANSPORT_WLAN_Ieee80211Frame);
2255 rrm->header.size = htons (write_std.size);
2256 rrm->header.type = htons (
2257 GNUNET_MESSAGE_TYPE_WLAN_DATA_FROM_HELPER);
2258 }
2259 break;
2260 }
2261 }
2262 }
2263 }
2264
2265 mst_destroy (stdin_mst);
2266 stdin_mst = NULL;
2267
2268 if (GNUNET_NETWORK_socket_close (dev.handle) != GNUNET_OK)
2269 {
2270 fprintf (stderr, "Failed to close the socket!\n");
2271 print_last_error ();
2272 }
2273
2274 for (i = 0; i < crt_rfds; i++)
2275 {
2276 if (GNUNET_NETWORK_socket_close (rfds_list[i]) != GNUNET_OK)
2277 {
2278 fprintf (stderr, "Failed to close the socket!\n");
2279 print_last_error ();
2280 }
2281 }
2282
2283 WSACleanup ();
2284 #endif
2285 return 1; /* we never exit 'normally' */
2286}
diff --git a/src/transport/gnunet-helper-transport-wlan-dummy.c b/src/transport/gnunet-helper-transport-wlan-dummy.c
deleted file mode 100644
index ab77f5c68..000000000
--- a/src/transport/gnunet-helper-transport-wlan-dummy.c
+++ /dev/null
@@ -1,520 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010, 2012 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport/gnunet-helper-transport-wlan-dummy.c
22 * @brief helper for the testcases for plugin_transport_wlan.c
23 * @author David Brodski
24 */
25#include "platform.h"
26#include "gnunet_protocols.h"
27#include "gnunet_util_lib.h"
28#include "plugin_transport_wlan.h"
29
30/**
31 * Name of the fifo to use for IPC with the other dummy process.
32 */
33#define FIFO_FILE1 "/tmp/test-transport/api-wlan-p1/WLAN_FIFO_in"
34
35/**
36 * Name of the fifo to use for IPC with the other dummy process.
37 */
38#define FIFO_FILE2 "/tmp/test-transport/api-wlan-p1/WLAN_FIFO_out"
39
40/**
41 * Maximum size of a message allowed in either direction
42 * (used for our receive and sent buffers).
43 */
44#define MAXLINE 4096
45
46
47/**
48 * IO buffer used for buffering data in transit.
49 */
50struct SendBuffer
51{
52 /**
53 * How many bytes that were stored in 'buf' did we already write to the
54 * destination? Always smaller than 'size'.
55 */
56 size_t pos;
57
58 /**
59 * How many bytes of data are stored in 'buf' for transmission right now?
60 * Data always starts at offset 0 and extends to 'size'.
61 */
62 size_t size;
63
64 /**
65 * Buffered data; twice the maximum allowed message size as we add some
66 * headers.
67 */
68 char buf[MAXLINE * 2];
69};
70
71
72/**
73 * Flag set to 1 if we are to terminate, otherwise 0.
74 */
75static int closeprog;
76
77
78/**
79 * We're being killed, clean up.
80 *
81 * @param sig killing signal
82 */
83static void
84sigfunc (int sig)
85{
86 closeprog = 1;
87 (void) unlink (FIFO_FILE1);
88 (void) unlink (FIFO_FILE2);
89}
90
91
92/**
93 * Create control message for plugin
94 *
95 * @param buffer pointer to buffer for the message
96 * @param mac pointer to the mac address
97 * @return number of bytes written
98 */
99static int
100send_mac_to_plugin (char *buffer, struct GNUNET_TRANSPORT_WLAN_MacAddress *mac)
101{
102 struct GNUNET_TRANSPORT_WLAN_HelperControlMessage macmsg;
103
104 GNUNET_memcpy (&macmsg.mac,
105 (char *) mac,
106 sizeof(struct GNUNET_TRANSPORT_WLAN_MacAddress));
107 macmsg.hdr.size =
108 htons (sizeof(struct GNUNET_TRANSPORT_WLAN_HelperControlMessage));
109 macmsg.hdr.type = htons (GNUNET_MESSAGE_TYPE_WLAN_HELPER_CONTROL);
110 GNUNET_memcpy (buffer,
111 &macmsg,
112 sizeof(struct GNUNET_TRANSPORT_WLAN_HelperControlMessage));
113 return sizeof(struct GNUNET_TRANSPORT_WLAN_HelperControlMessage);
114}
115
116
117/**
118 * We got a message from the FIFO, check it, convert the message
119 * type to the output forward and copy it to the buffer for stdout.
120 *
121 * @param cls the 'struct SendBuffer' to copy the converted message to
122 * @param hdr inbound message from the FIFO
123 * @return #GNUNET_OK on success,
124 * #GNUNET_NO to stop further processing (no error)
125 * #GNUNET_SYSERR to stop further processing with error
126 */
127static int
128stdin_send (void *cls, const struct GNUNET_MessageHeader *hdr)
129{
130 struct SendBuffer *write_pout = cls;
131 const struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *in;
132 size_t payload_size;
133 struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage newheader;
134 uint16_t sendsize;
135
136 sendsize = ntohs (hdr->size);
137 in = (const struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *) hdr;
138 if ((GNUNET_MESSAGE_TYPE_WLAN_DATA_TO_HELPER != ntohs (hdr->type)) ||
139 (sizeof(struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage) > sendsize))
140 {
141 fprintf (stderr, "%s", "Received malformed message\n");
142 exit (1);
143 }
144 payload_size =
145 sendsize - sizeof(struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage);
146 if ((payload_size
147 + sizeof(struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage)
148 + write_pout->size) > MAXLINE * 2)
149 {
150 fprintf (stderr, "%s", "Packet too big for buffer\n");
151 exit (1);
152 }
153 memset (&newheader, 0, sizeof(newheader));
154 newheader.header.size = htons (payload_size + sizeof(newheader));
155 newheader.header.type = htons (GNUNET_MESSAGE_TYPE_WLAN_DATA_FROM_HELPER);
156 newheader.frame = in->frame;
157 GNUNET_memcpy (write_pout->buf + write_pout->size,
158 &newheader,
159 sizeof(newheader));
160 write_pout->size += sizeof(newheader);
161 GNUNET_memcpy (write_pout->buf + write_pout->size, &in[1], payload_size);
162 write_pout->size += payload_size;
163 return GNUNET_OK;
164}
165
166
167/**
168 * We read a full message from stdin. Copy it to our send buffer.
169 *
170 * @param cls the 'struct SendBuffer' to copy to
171 * @param hdr the message we received to copy to the buffer
172 * @return #GNUNET_OK on success,
173 * #GNUNET_NO to stop further processing (no error)
174 * #GNUNET_SYSERR to stop further processing with error
175 */
176static int
177file_in_send (void *cls, const struct GNUNET_MessageHeader *hdr)
178{
179 struct SendBuffer *write_std = cls;
180 uint16_t sendsize;
181
182 sendsize = ntohs (hdr->size);
183 if ((sendsize + write_std->size) > MAXLINE * 2)
184 {
185 fprintf (stderr, "%s", "Packet too big for buffer\n");
186 exit (1);
187 }
188 GNUNET_memcpy (write_std->buf + write_std->size, hdr, sendsize);
189 write_std->size += sendsize;
190 return GNUNET_OK;
191}
192
193
194/**
195 * Main function of a program that pretends to be a WLAN card.
196 *
197 * @param argc should be 2
198 * @param argv either '1' or '2', depending on which of the two cards this dummy is to emulate
199 * @return 1 on error, 0 if terminated normally via signal
200 */
201int
202main (int argc, char *argv[])
203{
204 struct stat st;
205 int erg;
206 FILE *fpin = NULL;
207 FILE *fpout = NULL;
208 int fdpin;
209 int fdpout;
210 char readbuf[MAXLINE];
211 int readsize;
212 struct SendBuffer write_std;
213 struct SendBuffer write_pout;
214 int ret;
215 int maxfd;
216 fd_set rfds;
217 fd_set wfds;
218 struct timeval tv;
219 int retval;
220 struct GNUNET_MessageStreamTokenizer *stdin_mst = NULL;
221 struct GNUNET_MessageStreamTokenizer *file_in_mst = NULL;
222 struct GNUNET_TRANSPORT_WLAN_MacAddress macaddr;
223 int first;
224
225 if ((2 != argc) ||
226 ((0 != strcmp (argv[1], "1")) && (0 != strcmp (argv[1], "2"))))
227 {
228 fprintf (
229 stderr,
230 "%s",
231 "This program must be started with the operating mode (1 or 2) as the only argument.\n");
232 return 1;
233 }
234
235 /* make the fifos if needed */
236 umask (0);
237 if ((GNUNET_OK != GNUNET_DISK_directory_create_for_file (FIFO_FILE1)) ||
238 (GNUNET_OK != GNUNET_DISK_directory_create_for_file (FIFO_FILE2)))
239 {
240 fprintf (stderr, "Failed to create directory for file `%s'\n", FIFO_FILE1);
241 return 1;
242 }
243 if (0 == strcmp (argv[1], "1"))
244 {
245 if (0 != stat (FIFO_FILE1, &st))
246 {
247 erg = mkfifo (FIFO_FILE1, 0666);
248 if ((0 != erg) && (EEXIST != errno))
249 fprintf (stderr,
250 "Error in mkfifo(%s): %s\n",
251 FIFO_FILE1,
252 strerror (errno));
253 }
254 }
255 else
256 {
257 if (0 != stat (FIFO_FILE2, &st))
258 {
259 GNUNET_break (0 == (erg = mkfifo (FIFO_FILE2, 0666)));
260 if ((0 != erg) && (EEXIST != errno))
261 fprintf (stderr,
262 "Error in mkfifo(%s): %s\n",
263 FIFO_FILE2,
264 strerror (errno));
265 }
266 }
267
268 if (0 == strcmp (argv[1], "1"))
269 {
270 first = 1;
271 fpin = fopen (FIFO_FILE1, "r");
272 if (NULL == fpin)
273 {
274 fprintf (stderr,
275 "fopen of read FIFO_FILE1 failed: %s\n",
276 strerror (errno));
277 goto end;
278 }
279 if (NULL == (fpout = fopen (FIFO_FILE2, "w")))
280 {
281 GNUNET_break (0 == mkfifo (FIFO_FILE2, 0666));
282 fpout = fopen (FIFO_FILE2, "w");
283 }
284 if (NULL == fpout)
285 {
286 fprintf (stderr,
287 "fopen of write FIFO_FILE2 failed: %s\n",
288 strerror (errno));
289 goto end;
290 }
291 }
292 else
293 {
294 first = 0;
295 if (NULL == (fpout = fopen (FIFO_FILE1, "w")))
296 {
297 GNUNET_break (0 == mkfifo (FIFO_FILE1, 0666));
298 fpout = fopen (FIFO_FILE1, "w");
299 }
300 if (NULL == fpout)
301 {
302 fprintf (stderr,
303 "fopen of write FIFO_FILE1 failed: %s\n",
304 strerror (errno));
305 goto end;
306 }
307 fpin = fopen (FIFO_FILE2, "r");
308 if (NULL == fpin)
309 {
310 fprintf (stderr,
311 "fopen of read FIFO_FILE2 failed: %s\n",
312 strerror (errno));
313 goto end;
314 }
315 }
316
317 fdpin = fileno (fpin);
318 GNUNET_assert (fpin >= 0);
319 if (fdpin >= FD_SETSIZE)
320 {
321 fprintf (stderr,
322 "File fdpin number too large (%d > %u)\n",
323 fdpin,
324 (unsigned int) FD_SETSIZE);
325 goto end;
326 }
327
328 fdpout = fileno (fpout);
329 GNUNET_assert (fdpout >= 0);
330
331 if (fdpout >= FD_SETSIZE)
332 {
333 fprintf (stderr,
334 "File fdpout number too large (%d > %u)\n",
335 fdpout,
336 (unsigned int) FD_SETSIZE);
337 goto end;
338 }
339
340 signal (SIGINT, &sigfunc);
341 signal (SIGTERM, &sigfunc);
342 signal (GNUNET_TERM_SIG, &sigfunc);
343
344 write_std.size = 0;
345 write_std.pos = 0;
346 write_pout.size = 0;
347 write_pout.pos = 0;
348 stdin_mst = GNUNET_MST_create (&stdin_send, &write_pout);
349 file_in_mst = GNUNET_MST_create (&file_in_send, &write_std);
350
351 /* Send 'random' mac address */
352 macaddr.mac[0] = 0x13;
353 macaddr.mac[1] = 0x22;
354 macaddr.mac[2] = 0x33;
355 macaddr.mac[3] = 0x44;
356 macaddr.mac[4] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG, 256);
357 macaddr.mac[5] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, 256);
358 write_std.size = send_mac_to_plugin (write_std.buf, &macaddr);
359
360 while (0 == closeprog)
361 {
362 maxfd = -1;
363 tv.tv_sec = 5;
364 tv.tv_usec = 0;
365
366 FD_ZERO (&rfds);
367 FD_ZERO (&wfds);
368 /* if output queue is empty, read */
369 if (0 == write_pout.size)
370 {
371 FD_SET (STDIN_FILENO, &rfds);
372 maxfd = MAX (STDIN_FILENO, maxfd);
373 }
374 if (0 == write_std.size)
375 {
376 FD_SET (fdpin, &rfds);
377 maxfd = MAX (fdpin, maxfd);
378 }
379
380 /* if there is something to write, try to write */
381 if (0 < write_std.size)
382 {
383 FD_SET (STDOUT_FILENO, &wfds);
384 maxfd = MAX (maxfd, STDOUT_FILENO);
385 }
386 if (0 < write_pout.size)
387 {
388 FD_SET (fdpout, &wfds);
389 maxfd = MAX (maxfd, fdpout);
390 }
391
392 retval = select (maxfd + 1, &rfds, &wfds, NULL, &tv);
393 if ((-1 == retval) && (EINTR == errno))
394 continue;
395 if (0 > retval)
396 {
397 fprintf (stderr, "select failed: %s\n", strerror (errno));
398 closeprog = 1;
399 break;
400 }
401
402 if (FD_ISSET (STDOUT_FILENO, &wfds))
403 {
404 ret = write (STDOUT_FILENO,
405 write_std.buf + write_std.pos,
406 write_std.size - write_std.pos);
407 if (0 > ret)
408 {
409 closeprog = 1;
410 fprintf (stderr,
411 "Write ERROR to STDOUT_FILENO: %s\n",
412 strerror (errno));
413 break;
414 }
415 else
416 {
417 write_std.pos += ret;
418 /* check if finished writing */
419 if (write_std.pos == write_std.size)
420 {
421 write_std.pos = 0;
422 write_std.size = 0;
423 }
424 }
425 }
426
427 if (FD_ISSET (fdpout, &wfds))
428 {
429 ret = write (fdpout,
430 write_pout.buf + write_pout.pos,
431 write_pout.size - write_pout.pos);
432
433 if (0 > ret)
434 {
435 closeprog = 1;
436 fprintf (stderr,
437 "Write ERROR to fdpout failed: %s\n",
438 strerror (errno));
439 }
440 else
441 {
442 write_pout.pos += ret;
443 /* check if finished writing */
444 if (write_pout.pos == write_pout.size)
445 {
446 write_pout.pos = 0;
447 write_pout.size = 0;
448 }
449 }
450 }
451
452 if (FD_ISSET (STDIN_FILENO, &rfds))
453 {
454 readsize = read (STDIN_FILENO, readbuf, sizeof(readbuf));
455
456 if (0 > readsize)
457 {
458 closeprog = 1;
459 fprintf (stderr,
460 "Error reading from STDIN_FILENO: %s\n",
461 strerror (errno));
462 }
463 else if (0 < readsize)
464 {
465 GNUNET_MST_from_buffer (stdin_mst,
466 readbuf,
467 readsize,
468 GNUNET_NO,
469 GNUNET_NO);
470 }
471 else
472 {
473 /* eof */
474 closeprog = 1;
475 }
476 }
477
478 if (FD_ISSET (fdpin, &rfds))
479 {
480 readsize = read (fdpin, readbuf, sizeof(readbuf));
481 if (0 > readsize)
482 {
483 closeprog = 1;
484 fprintf (stderr, "Error reading from fdpin: %s\n", strerror (errno));
485 break;
486 }
487 else if (0 < readsize)
488 {
489 GNUNET_MST_from_buffer (file_in_mst,
490 readbuf,
491 readsize,
492 GNUNET_NO,
493 GNUNET_NO);
494 }
495 else
496 {
497 /* eof */
498 closeprog = 1;
499 }
500 }
501 }
502
503end:
504 /* clean up */
505 if (NULL != stdin_mst)
506 GNUNET_MST_destroy (stdin_mst);
507 if (NULL != file_in_mst)
508 GNUNET_MST_destroy (file_in_mst);
509
510 if (NULL != fpout)
511 fclose (fpout);
512 if (NULL != fpin)
513 fclose (fpin);
514 if (1 == first)
515 {
516 (void) unlink (FIFO_FILE1);
517 (void) unlink (FIFO_FILE2);
518 }
519 return 0;
520}
diff --git a/src/transport/gnunet-helper-transport-wlan.c b/src/transport/gnunet-helper-transport-wlan.c
deleted file mode 100644
index c1a230bef..000000000
--- a/src/transport/gnunet-helper-transport-wlan.c
+++ /dev/null
@@ -1,2165 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010, 2011, 2012 GNUnet e.V.
4 Copyright (c) 2007, 2008, Andy Green <andy@warmcat.com>
5 Copyright Copyright (C) 2009 Thomas d'Otreppe
6
7 GNUnet is free software: you can redistribute it and/or modify it
8 under the terms of the GNU Affero General Public License as published
9 by the Free Software Foundation, either version 3 of the License,
10 or (at your option) any later version.
11
12 GNUnet is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Affero General Public License for more details.
16
17 You should have received a copy of the GNU Affero General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20 SPDX-License-Identifier: AGPL3.0-or-later
21 */
22/**
23 * @file src/transport/gnunet-helper-transport-wlan.c
24 * @brief mediator between the wlan interface and gnunet; must run as root (SUID will do)
25 * This code will work under GNU/Linux only.
26 * @author David Brodski
27 * @author Christian Grothoff
28 *
29 * This program will allow receiving and sending traffic from the WLAN
30 * interface. It will force traffic to be in 'ad-hoc' mode, use the
31 * proper MAC address of the WLAN interface and use a GNUnet-specific
32 * SSID (and a GNUnet-specific SNAP header). It only takes a single
33 * argument, which is the name of the WLAN interface to use. The
34 * program detects if the interface is not a WLAN interface and exits
35 * with an error in that case.
36 *
37 * Once initialized, the program will first send a 'struct
38 * GNUNET_TRANSPORT_WLAN_HelperControlMessage' to 'stdout'. That
39 * message contains the MAC address of the WLAN interface. It will
40 * then read messages from the WLAN interface and send them together
41 * with performance information as 'struct
42 * GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage' messages to 'stdout'.
43 * Furthermore, it will read a stream of messages from 'stdin' that
44 * have the format from 'struct
45 * GNUNET_TRANSPORT_WLAN_RadiotapSendMessage'. Those messages will
46 * then be sent via the WLAN interface; however, the sender MAC
47 * address will be forced to be the correct address from our WLAN
48 * card. If 'stdin' closes, receiving from the WLAN interface will
49 * continue. If 'stdout' causes a SIGPIPE, the process dies from the
50 * signal. Errors cause an error message to be reported to 'stderr',
51 * in most cases the process also exits (with status code '1'). The
52 * program never terminates normally; it is safe to kill the
53 * process with SIGTERM or SIGKILL at any time.
54 *
55 * Since it uses RAW sockets, the binary must be installed SUID or run
56 * as 'root'. In order to keep the security risk of the resulting
57 * SUID binary minimal, the program ONLY opens the RAW socket with
58 * root privileges, then drops them and only then starts to process
59 * command line arguments. The code also does not link against any
60 * shared libraries (except libc) and is strictly minimal (except for
61 * checking for errors). The following list of people have reviewed
62 * this code and considered it safe since the last modification (if
63 * you reviewed it, please have your name added to the list):
64 *
65 * - Christian Grothoff (Apr 3rd 2012)
66 */
67
68/*-
69 * we use our local copy of ieee80211_radiotap.h
70 *
71 * - since we can't support extensions we don't understand
72 * - since linux does not include it in userspace headers
73 *
74 * Portions of this code were taken from the ieee80211_radiotap.h header,
75 * which is
76 *
77 * Copyright (c) 2003, 2004 David Young. All rights reserved.
78 *
79 * Redistribution and use in source and binary forms, with or without
80 * modification, are permitted provided that the following conditions
81 * are met:
82 * 1. Redistributions of source code must retain the above copyright
83 * notice, this list of conditions and the following disclaimer.
84 * 2. Redistributions in binary form must reproduce the above copyright
85 * notice, this list of conditions and the following disclaimer in the
86 * documentation and/or other materials provided with the distribution.
87 * 3. The name of David Young may not be used to endorse or promote
88 * products derived from this software without specific prior
89 * written permission.
90 *
91 * THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY
92 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
93 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
94 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID
95 * YOUNG BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
96 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
97 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
98 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
99 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
100 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
101 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
102 * OF SUCH DAMAGE.
103 */
104
105/*
106 * Modifications to fit into the linux IEEE 802.11 stack,
107 * Mike Kershaw (dragorn@kismetwireless.net)
108 */
109/*
110 * parts taken from aircrack-ng, parts changend.
111 */
112#include "platform.h"
113#include "gnunet_private_config.h"
114#include <netpacket/packet.h>
115#include <linux/if_ether.h>
116#include <linux/wireless.h>
117
118#include "gnunet_protocols.h"
119#include "plugin_transport_wlan.h"
120
121/**
122 * Packet format type for the messages we receive from
123 * the kernel. This is for Ethernet 10Mbps format (no
124 * performance information included).
125 */
126#define ARPHRD_ETHER 1
127
128
129/**
130 * Packet format type for the messages we receive from
131 * the kernel. This is for plain messages (with no
132 * performance information included).
133 */
134#define ARPHRD_IEEE80211 801
135
136
137/**
138 * Packet format type for the messages we receive from
139 * the kernel. This is for the PRISM format.
140 */
141#define ARPHRD_IEEE80211_PRISM 802
142
143/**
144 * Packet format type for the messages we receive from
145 * the kernel. This is for messages with a
146 * 'struct Ieee80211RadiotapHeader' (see below).
147 */
148#define ARPHRD_IEEE80211_FULL 803
149
150
151/**
152 * Maximum size of a message allowed in either direction
153 * (used for our receive and sent buffers).
154 */
155#define MAXLINE 4096
156
157
158/* ********* structure of messages of type ARPHRD_IEEE80211_PRISM *********** */
159
160/**
161 * Device name length in PRISM frames.
162 * (In the kernel, this is "WLAN_DEVNAMELEN_MAX")
163 */
164#define PRISM_DEVICE_NAME_LENGTH 16
165
166/**
167 * Monitor Frame (indicator that we have a 'struct PrismHeader').
168 */
169#define PRISM_MSGCODE_MONITOR 0x0041
170
171/**
172 * Mac time element. In micro-seconds.
173 * Drivers appear to use a 64bit counter to hold mactime internal
174 * the then fill the prism header with the lower 32 bits
175 */
176#define PRISM_DID_MACTIME 0x2041
177
178/**
179 * Channel element
180 */
181#define PRISM_DID_CHANNEL 0x3041
182
183/**
184 * Signal element. Should be the signal strength in dbm, some people
185 * suggest that instead "100 - (strength in dbm)" is used (to make this
186 * a positive integer).
187 */
188#define PRISM_DID_SIGNAL 0x6041
189
190/**
191 * Noise element
192 */
193#define PRISM_DID_NOISE 0x7041
194
195/**
196 * Rate element, in units/multiples of 500Khz
197 */
198#define PRISM_DID_RATE 0x8041
199
200
201/**
202 * Value is set (supplied)
203 */
204#define PRISM_STATUS_OK 0
205
206/**
207 * Value not supplied.
208 */
209#define PRISM_STATUS_NO_VALUE 1
210
211
212/**
213 * Values in the 'struct PrismHeader'. All in host byte order (!).
214 */
215struct PrismValue
216{
217 /**
218 * This has a different ID for each parameter, see
219 * PRISM_DID_* constants.
220 */
221 uint32_t did;
222
223 /**
224 * See PRISM_STATUS_*-constants. Note that they are unusual: 0 = set; 1 = not set
225 */
226 uint16_t status;
227
228 /**
229 * length of data (which is always a uint32_t, but presumably this can be used
230 * to specify that fewer bytes are used (with values in 'len' from 0-4). We
231 * ignore this field.
232 */
233 uint16_t len;
234
235 /**
236 * The data value
237 */
238 uint32_t data;
239} __attribute__ ((packed));
240
241
242/**
243 * Prism header format ('struct p80211msg' in Linux). All in host byte order (!).
244 */
245struct PrismHeader
246{
247 /**
248 * We expect this to be a PRISM_MSGCODE_*.
249 */
250 uint32_t msgcode;
251
252 /**
253 * The length of the entire header.
254 */
255 uint32_t msglen;
256
257 /**
258 * Name of the device that captured the packet.
259 */
260 char devname[PRISM_DEVICE_NAME_LENGTH];
261
262 /* followed by 'struct PrismValue's. Documentation suggests that these
263 are typically the hosttime, mactime, channel, rssi, sq, signal, noise,
264 rate, istx and frmlen values, but documentation is sparse. So we
265 will use the 'did' fields to find out what we actually got. */
266} __attribute__ ((packed));
267
268
269/* ****** end of structure of messages of type ARPHRD_IEEE80211_PRISM ******* */
270
271/* ********** structure of messages of type ARPHRD_IEEE80211_FULL *********** */
272
273/**
274 * Bits in the 'it_present' bitmask from the 'struct
275 * Ieee80211RadiotapHeader'. For each value, we give the name, data
276 * type, unit and then a description below. Note that the actual size
277 * of the extension can be bigger as arguments must be padded so that
278 * args of a given length must begin at a boundary of that length.
279 * However, note that compound args are allowed (eg, 2 x uint16_t for
280 * IEEE80211_RADIOTAP_CHANNEL) so total argument length is not a
281 * reliable indicator of alignment requirement. See also
282 * 'man 9 ieee80211_radiotap'.
283 */
284enum RadiotapType
285{
286 /**
287 * IEEE80211_RADIOTAP_TSFT __le64 microseconds
288 *
289 * Value in microseconds of the MAC's 64-bit 802.11 Time
290 * Synchronization Function timer when the first bit of the
291 * MPDU arrived at the MAC. For received frames, only.
292 */
293 IEEE80211_RADIOTAP_TSFT = 0,
294
295 /**
296 * IEEE80211_RADIOTAP_FLAGS uint8_t bitmap
297 *
298 * Properties of transmitted and received frames. See flags
299 * defined below.
300 */
301 IEEE80211_RADIOTAP_FLAGS = 1,
302
303 /**
304 * IEEE80211_RADIOTAP_RATE uint8_t 500kb/s
305 *
306 * Tx/Rx data rate
307 */
308 IEEE80211_RADIOTAP_RATE = 2,
309
310 /**
311 * IEEE80211_RADIOTAP_CHANNEL 2 x __le16 MHz, bitmap
312 *
313 * Tx/Rx frequency in MHz, followed by flags (see below).
314 */
315 IEEE80211_RADIOTAP_CHANNEL = 3,
316 /**
317 * IEEE80211_RADIOTAP_FHSS __le16 see below
318 *
319 * For frequency-hopping radios, the hop set (first byte)
320 * and pattern (second byte).
321 */
322 IEEE80211_RADIOTAP_FHSS = 4,
323
324 /**
325 * IEEE80211_RADIOTAP_DBM_ANTSIGNAL s8 decibels from
326 * one milliwatt (dBm)
327 *
328 * RF signal power at the antenna, decibel difference from
329 * one milliwatt.
330 */
331 IEEE80211_RADIOTAP_DBM_ANTSIGNAL = 5,
332
333 /**
334 * IEEE80211_RADIOTAP_DBM_ANTNOISE s8 decibels from
335 * one milliwatt (dBm)
336 *
337 * RF noise power at the antenna, decibel difference from one
338 * milliwatt.
339 */
340 IEEE80211_RADIOTAP_DBM_ANTNOISE = 6,
341
342 /**
343 * IEEE80211_RADIOTAP_LOCK_QUALITY __le16 unitless
344 *
345 * Quality of Barker code lock. Unitless. Monotonically
346 * nondecreasing with "better" lock strength. Called "Signal
347 * Quality" in datasheets. (Is there a standard way to measure
348 * this?)
349 */
350 IEEE80211_RADIOTAP_LOCK_QUALITY = 7,
351
352 /**
353 * IEEE80211_RADIOTAP_TX_ATTENUATION __le16 unitless
354 *
355 * Transmit power expressed as unitless distance from max
356 * power set at factory calibration. 0 is max power.
357 * Monotonically nondecreasing with lower power levels.
358 */
359 IEEE80211_RADIOTAP_TX_ATTENUATION = 8,
360
361 /**
362 * IEEE80211_RADIOTAP_DB_TX_ATTENUATION __le16 decibels (dB)
363 *
364 * Transmit power expressed as decibel distance from max power
365 * set at factory calibration. 0 is max power. Monotonically
366 * nondecreasing with lower power levels.
367 */
368 IEEE80211_RADIOTAP_DB_TX_ATTENUATION = 9,
369
370 /**
371 * IEEE80211_RADIOTAP_DBM_TX_POWER s8 decibels from
372 * one milliwatt (dBm)
373 *
374 * Transmit power expressed as dBm (decibels from a 1 milliwatt
375 * reference). This is the absolute power level measured at
376 * the antenna port.
377 */
378 IEEE80211_RADIOTAP_DBM_TX_POWER = 10,
379
380 /**
381 * IEEE80211_RADIOTAP_ANTENNA uint8_t antenna index
382 *
383 * Unitless indication of the Rx/Tx antenna for this packet.
384 * The first antenna is antenna 0.
385 */
386 IEEE80211_RADIOTAP_ANTENNA = 11,
387
388 /**
389 * IEEE80211_RADIOTAP_DB_ANTSIGNAL uint8_t decibel (dB)
390 *
391 * RF signal power at the antenna, decibel difference from an
392 * arbitrary, fixed reference.
393 */
394 IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12,
395
396 /**
397 * IEEE80211_RADIOTAP_DB_ANTNOISE uint8_t decibel (dB)
398 *
399 * RF noise power at the antenna, decibel difference from an
400 * arbitrary, fixed reference point.
401 */
402 IEEE80211_RADIOTAP_DB_ANTNOISE = 13,
403
404 /**
405 * IEEE80211_RADIOTAP_RX_FLAGS __le16 bitmap
406 *
407 * Properties of received frames. See flags defined below.
408 */
409 IEEE80211_RADIOTAP_RX_FLAGS = 14,
410
411 /**
412 * IEEE80211_RADIOTAP_TX_FLAGS __le16 bitmap
413 *
414 * Properties of transmitted frames. See flags defined below.
415 */
416 IEEE80211_RADIOTAP_TX_FLAGS = 15,
417
418 /**
419 * IEEE80211_RADIOTAP_RTS_RETRIES uint8_t data
420 *
421 * Number of rts retries a transmitted frame used.
422 */
423 IEEE80211_RADIOTAP_RTS_RETRIES = 16,
424
425 /**
426 * IEEE80211_RADIOTAP_DATA_RETRIES uint8_t data
427 *
428 * Number of unicast retries a transmitted frame used.
429 */
430 IEEE80211_RADIOTAP_DATA_RETRIES = 17,
431
432 /**
433 * Extension bit, used to indicate that more bits are needed for
434 * the bitmask.
435 */
436 IEEE80211_RADIOTAP_EXT = 31
437};
438
439/**
440 * Bitmask indicating an extension of the bitmask is used.
441 * (Mask corresponding to IEEE80211_RADIOTAP_EXT).
442 */
443#define IEEE80211_RADIOTAP_PRESENT_EXTEND_MASK (1 << IEEE80211_RADIOTAP_EXT)
444
445
446/**
447 * Bit in IEEE80211_RADIOTAP_FLAGS (which we might get
448 * as part of a 'struct Ieee80211RadiotapHeader' extension
449 * if the IEEE80211_RADIOTAP_FLAGS bit is set in
450 * 'it_present'). The radiotap flags are an 8-bit field.
451 *
452 * Frame was sent/received during CFP (Contention Free Period)
453 */
454#define IEEE80211_RADIOTAP_F_CFP 0x01
455
456/**
457 * Bit in IEEE80211_RADIOTAP_FLAGS (which we might get
458 * as part of a 'struct Ieee80211RadiotapHeader' extension
459 * if the IEEE80211_RADIOTAP_FLAGS bit is set in
460 * 'it_present'). The radiotap flags are an 8-bit field.
461 *
462 * Frame was sent/received with short preamble
463 */
464#define IEEE80211_RADIOTAP_F_SHORTPRE 0x02
465
466/**
467 * Bit in IEEE80211_RADIOTAP_FLAGS (which we might get
468 * as part of a 'struct Ieee80211RadiotapHeader' extension
469 * if the IEEE80211_RADIOTAP_FLAGS bit is set in
470 * 'it_present'). The radiotap flags are an 8-bit field.
471 *
472 * Frame was sent/received with WEP encryption
473 */
474#define IEEE80211_RADIOTAP_F_WEP 0x04
475
476/**
477 * Bit in IEEE80211_RADIOTAP_FLAGS (which we might get
478 * as part of a 'struct Ieee80211RadiotapHeader' extension
479 * if the IEEE80211_RADIOTAP_FLAGS bit is set in
480 * 'it_present'). The radiotap flags are an 8-bit field.
481 *
482 * Frame was sent/received with fragmentation
483 */
484#define IEEE80211_RADIOTAP_F_FRAG 0x08
485
486/**
487 * Bit in IEEE80211_RADIOTAP_FLAGS (which we might get
488 * as part of a 'struct Ieee80211RadiotapHeader' extension
489 * if the IEEE80211_RADIOTAP_FLAGS bit is set in
490 * 'it_present'). The radiotap flags are an 8-bit field.
491 *
492 * Frame includes FCS (CRC at the end that needs to be removeD).
493 */
494#define IEEE80211_RADIOTAP_F_FCS 0x10
495
496/**
497 * Bit in IEEE80211_RADIOTAP_FLAGS (which we might get
498 * as part of a 'struct Ieee80211RadiotapHeader' extension
499 * if the IEEE80211_RADIOTAP_FLAGS bit is set in
500 * 'it_present'). The radiotap flags are an 8-bit field.
501 *
502 * Frame has padding between 802.11 header and payload
503 * (to 32-bit boundary)
504 */
505#define IEEE80211_RADIOTAP_F_DATAPAD 0x20
506
507
508/**
509 * For IEEE80211_RADIOTAP_RX_FLAGS:
510 * frame failed crc check
511 */
512#define IEEE80211_RADIOTAP_F_RX_BADFCS 0x0001
513
514/**
515 * For IEEE80211_RADIOTAP_TX_FLAGS ('txflags' in 'struct RadiotapTransmissionHeader'):
516 * failed due to excessive retries
517 */
518#define IEEE80211_RADIOTAP_F_TX_FAIL 0x0001
519
520/**
521 * For IEEE80211_RADIOTAP_TX_FLAGS ('txflags' in 'struct RadiotapTransmissionHeader'):
522 * used cts 'protection'
523 */
524#define IEEE80211_RADIOTAP_F_TX_CTS 0x0002
525
526/**
527 * For IEEE80211_RADIOTAP_TX_FLAGS ('txflags' in 'struct RadiotapTransmissionHeader'):
528 * used rts/cts handshake
529 */
530#define IEEE80211_RADIOTAP_F_TX_RTS 0x0004
531
532/**
533 * For IEEE80211_RADIOTAP_TX_FLAGS ('txflags' in 'struct RadiotapTransmissionHeader'):
534 * frame should not be ACKed
535 */
536#define IEEE80211_RADIOTAP_F_TX_NOACK 0x0008
537
538/**
539 * For IEEE80211_RADIOTAP_TX_FLAGS ('txflags' in 'struct RadiotapTransmissionHeader'):
540 * sequence number handled by userspace
541 */
542#define IEEE80211_RADIOTAP_F_TX_NOSEQ 0x0010
543
544
545/**
546 * Generic header for radiotap messages (receiving and sending). A
547 * bit mask (it_present) determines which specific records follow.
548 *
549 * I am trying to describe precisely what the application programmer
550 * should expect in the following, and for that reason I tell the
551 * units and origin of each measurement (where it applies), or else I
552 * use sufficiently weaselly language ("is a monotonically nondecreasing
553 * function of...") that I cannot set false expectations for lawyerly
554 * readers.
555 *
556 * The radio capture header precedes the 802.11 header.
557 * All data in the header is little endian on all platforms.
558 */
559struct Ieee80211RadiotapHeader
560{
561 /**
562 * Version 0. Only increases for drastic changes, introduction of
563 * compatible new fields does not count.
564 */
565 uint8_t it_version;
566
567 /**
568 * Padding. Set to 0.
569 */
570 uint8_t it_pad;
571
572 /**
573 * length of the whole header in bytes, including it_version,
574 * it_pad, it_len, and data fields.
575 */
576 uint16_t it_len;
577
578 /**
579 * A bitmap telling which fields are present. Set bit 31
580 * (0x80000000) to extend the bitmap by another 32 bits. Additional
581 * extensions are made by setting bit 31.
582 */
583 uint32_t it_present;
584};
585
586
587/**
588 * Format of the header we need to prepend to messages to be sent to the
589 * Kernel.
590 */
591struct RadiotapTransmissionHeader
592{
593 /**
594 * First we begin with the 'generic' header we also get when receiving
595 * messages.
596 */
597 struct Ieee80211RadiotapHeader header;
598
599 /**
600 * Transmission rate (we use 0, kernel makes up its mind anyway).
601 */
602 uint8_t rate;
603
604 /**
605 * Padding (we use 0). There is a requirement to pad args, so that
606 * args of a given length must begin at a boundary of that length.
607 * As our next argument is the 'it_len' with 2 bytes, we need 1 byte
608 * of padding.
609 */
610 uint8_t pad1;
611
612 /**
613 * Transmission flags from on the IEEE80211_RADIOTAP_F_TX_* constant family.
614 */
615 uint16_t txflags;
616};
617
618/**
619 * The above 'struct RadiotapTransmissionHeader' should have the
620 * following value for 'header.it_present' based on the presence of
621 * the 'rate' and 'txflags' in the overall struct.
622 */
623#define IEEE80211_RADIOTAP_OUR_TRANSMISSION_HEADER_MASK ((1 \
624 << \
625 IEEE80211_RADIOTAP_RATE) \
626 | (1 \
627 << \
628 IEEE80211_RADIOTAP_TX_FLAGS))
629
630
631/**
632 * struct Ieee80211RadiotapHeaderIterator - tracks walk through present radiotap arguments
633 * in the radiotap header. Used when we parse radiotap packets received from the kernel.
634 */
635struct Ieee80211RadiotapHeaderIterator
636{
637 /**
638 * pointer to the radiotap header we are walking through
639 */
640 const struct Ieee80211RadiotapHeader *rtheader;
641
642 /**
643 * pointer to current radiotap arg
644 */
645 const uint8_t *this_arg;
646
647 /**
648 * internal next argument pointer
649 */
650 const uint8_t *arg;
651
652 /**
653 * internal pointer to next present uint32_t (if IEEE80211_RADIOTAP_EXT is used).
654 */
655 const uint32_t *next_bitmap;
656
657 /**
658 * length of radiotap header in host byte ordering
659 */
660 size_t max_length;
661
662 /**
663 * internal shifter for current uint32_t bitmap, (it_present in host byte order),
664 * If bit 0 is set, the 'arg_index' argument is present.
665 */
666 uint32_t bitmap_shifter;
667
668 /**
669 * IEEE80211_RADIOTAP_... index of current arg
670 */
671 unsigned int this_arg_index;
672
673 /**
674 * internal next argument index
675 */
676 unsigned int arg_index;
677};
678
679
680/* ************** end of structure of ARPHRD_IEEE80211_FULL ************** */
681
682/* ************************** our globals ******************************* */
683
684/**
685 * struct for storing the information of the hardware. There is only
686 * one of these.
687 */
688struct HardwareInfos
689{
690 /**
691 * file descriptor for the raw socket
692 */
693 int fd_raw;
694
695 /**
696 * Which format has the header that we're getting when receiving packets?
697 * Some ARPHRD_IEEE80211_XXX-value.
698 */
699 int arptype_in;
700
701 /**
702 * Name of the interface, not necessarily 0-terminated (!).
703 */
704 char iface[IFNAMSIZ];
705
706 /**
707 * MAC address of our own WLAN interface.
708 */
709 struct GNUNET_TRANSPORT_WLAN_MacAddress pl_mac;
710};
711
712
713/**
714 * IO buffer used for buffering data in transit (to wireless or to stdout).
715 */
716struct SendBuffer
717{
718 /**
719 * How many bytes of data are stored in 'buf' for transmission right now?
720 * Data always starts at offset 0 and extends to 'size'.
721 */
722 size_t size;
723
724 /**
725 * How many bytes that were stored in 'buf' did we already write to the
726 * destination? Always smaller than 'size'.
727 */
728 size_t pos;
729
730 /**
731 * Buffered data; twice the maximum allowed message size as we add some
732 * headers.
733 */
734 char buf[MAXLINE * 2];
735};
736
737
738/**
739 * Buffer for data read from stdin to be transmitted to the wirless card.
740 */
741static struct SendBuffer write_pout;
742
743/**
744 * Buffer for data read from the wireless card to be transmitted to stdout.
745 */
746static struct SendBuffer write_std;
747
748
749/* *********** specialized version of server_mst.c begins here ********** */
750
751/**
752 * To what multiple do we align messages? 8 byte should suffice for everyone
753 * for now.
754 */
755#define ALIGN_FACTOR 8
756
757/**
758 * Smallest supported message.
759 */
760#define MIN_BUFFER_SIZE sizeof(struct GNUNET_MessageHeader)
761
762
763/**
764 * Functions with this signature are called whenever a
765 * complete message is received by the tokenizer.
766 *
767 * @param cls closure
768 * @param message the actual message
769 */
770typedef void (*MessageTokenizerCallback) (void *cls,
771 const struct
772 GNUNET_MessageHeader *
773 message);
774
775/**
776 * Handle to a message stream tokenizer.
777 */
778struct MessageStreamTokenizer
779{
780 /**
781 * Function to call on completed messages.
782 */
783 MessageTokenizerCallback cb;
784
785 /**
786 * Closure for cb.
787 */
788 void *cb_cls;
789
790 /**
791 * Size of the buffer (starting at 'hdr').
792 */
793 size_t curr_buf;
794
795 /**
796 * How many bytes in buffer have we already processed?
797 */
798 size_t off;
799
800 /**
801 * How many bytes in buffer are valid right now?
802 */
803 size_t pos;
804
805 /**
806 * Beginning of the buffer. Typed like this to force alignment.
807 */
808 struct GNUNET_MessageHeader *hdr;
809};
810
811
812/**
813 * Create a message stream tokenizer.
814 *
815 * @param cb function to call on completed messages
816 * @param cb_cls closure for cb
817 * @return handle to tokenizer
818 */
819static struct MessageStreamTokenizer *
820mst_create (MessageTokenizerCallback cb,
821 void *cb_cls)
822{
823 struct MessageStreamTokenizer *ret;
824
825 ret = malloc (sizeof(struct MessageStreamTokenizer));
826 if (NULL == ret)
827 {
828 fprintf (stderr, "Failed to allocate buffer for tokenizer\n");
829 exit (1);
830 }
831 ret->hdr = malloc (MIN_BUFFER_SIZE);
832 if (NULL == ret->hdr)
833 {
834 fprintf (stderr, "Failed to allocate buffer for alignment\n");
835 exit (1);
836 }
837 ret->curr_buf = MIN_BUFFER_SIZE;
838 ret->cb = cb;
839 ret->cb_cls = cb_cls;
840 return ret;
841}
842
843
844/**
845 * Add incoming data to the receive buffer and call the
846 * callback for all complete messages.
847 *
848 * @param mst tokenizer to use
849 * @param buf input data to add
850 * @param size number of bytes in buf
851 * @return GNUNET_OK if we are done processing (need more data)
852 * GNUNET_SYSERR if the data stream is corrupt
853 */
854static int
855mst_receive (struct MessageStreamTokenizer *mst,
856 const char *buf, size_t size)
857{
858 const struct GNUNET_MessageHeader *hdr;
859 size_t delta;
860 uint16_t want;
861 char *ibuf;
862 int need_align;
863 unsigned long offset;
864 int ret;
865
866 ret = GNUNET_OK;
867 ibuf = (char *) mst->hdr;
868 while (mst->pos > 0)
869 {
870do_align:
871 if ((mst->curr_buf - mst->off < sizeof(struct GNUNET_MessageHeader)) ||
872 (0 != (mst->off % ALIGN_FACTOR)))
873 {
874 /* need to align or need more space */
875 mst->pos -= mst->off;
876 memmove (ibuf, &ibuf[mst->off], mst->pos);
877 mst->off = 0;
878 }
879 if (mst->pos - mst->off < sizeof(struct GNUNET_MessageHeader))
880 {
881 delta =
882 GNUNET_MIN (sizeof(struct GNUNET_MessageHeader)
883 - (mst->pos - mst->off), size);
884 GNUNET_memcpy (&ibuf[mst->pos], buf, delta);
885 mst->pos += delta;
886 buf += delta;
887 size -= delta;
888 }
889 if (mst->pos - mst->off < sizeof(struct GNUNET_MessageHeader))
890 {
891 return GNUNET_OK;
892 }
893 hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off];
894 want = ntohs (hdr->size);
895 if (want < sizeof(struct GNUNET_MessageHeader))
896 {
897 fprintf (stderr,
898 "Received invalid message from stdin\n");
899 exit (1);
900 }
901 if (mst->curr_buf - mst->off < want)
902 {
903 /* need more space */
904 mst->pos -= mst->off;
905 memmove (ibuf, &ibuf[mst->off], mst->pos);
906 mst->off = 0;
907 }
908 if (want > mst->curr_buf)
909 {
910 mst->hdr = realloc (mst->hdr, want);
911 if (NULL == mst->hdr)
912 {
913 fprintf (stderr, "Failed to allocate buffer for alignment\n");
914 exit (1);
915 }
916 ibuf = (char *) mst->hdr;
917 mst->curr_buf = want;
918 }
919 hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off];
920 if (mst->pos - mst->off < want)
921 {
922 delta = GNUNET_MIN (want - (mst->pos - mst->off), size);
923 GNUNET_memcpy (&ibuf[mst->pos], buf, delta);
924 mst->pos += delta;
925 buf += delta;
926 size -= delta;
927 }
928 if (mst->pos - mst->off < want)
929 {
930 return GNUNET_OK;
931 }
932 mst->cb (mst->cb_cls, hdr);
933 mst->off += want;
934 if (mst->off == mst->pos)
935 {
936 /* reset to beginning of buffer, it's free right now! */
937 mst->off = 0;
938 mst->pos = 0;
939 }
940 }
941 while (size > 0)
942 {
943 if (size < sizeof(struct GNUNET_MessageHeader))
944 break;
945 offset = (unsigned long) buf;
946 need_align = (0 != offset % ALIGN_FACTOR) ? GNUNET_YES : GNUNET_NO;
947 if (GNUNET_NO == need_align)
948 {
949 /* can try to do zero-copy and process directly from original buffer */
950 hdr = (const struct GNUNET_MessageHeader *) buf;
951 want = ntohs (hdr->size);
952 if (want < sizeof(struct GNUNET_MessageHeader))
953 {
954 fprintf (stderr,
955 "Received invalid message from stdin\n");
956 exit (1);
957 }
958 if (size < want)
959 break; /* or not, buffer incomplete, so copy to private buffer... */
960 mst->cb (mst->cb_cls, hdr);
961 buf += want;
962 size -= want;
963 }
964 else
965 {
966 /* need to copy to private buffer to align;
967 * yes, we go a bit more spaghetti than usual here */
968 goto do_align;
969 }
970 }
971 if (size > 0)
972 {
973 if (size + mst->pos > mst->curr_buf)
974 {
975 mst->hdr = realloc (mst->hdr, size + mst->pos);
976 if (NULL == mst->hdr)
977 {
978 fprintf (stderr, "Failed to allocate buffer for alignment\n");
979 exit (1);
980 }
981 ibuf = (char *) mst->hdr;
982 mst->curr_buf = size + mst->pos;
983 }
984 if (mst->pos + size > mst->curr_buf)
985 {
986 fprintf (stderr,
987 "Assertion failed\n");
988 exit (1);
989 }
990 GNUNET_memcpy (&ibuf[mst->pos], buf, size);
991 mst->pos += size;
992 }
993 return ret;
994}
995
996
997/**
998 * Destroys a tokenizer.
999 *
1000 * @param mst tokenizer to destroy
1001 */
1002static void
1003mst_destroy (struct MessageStreamTokenizer *mst)
1004{
1005 free (mst->hdr);
1006 free (mst);
1007}
1008
1009
1010/* ***************** end of server_mst.c clone ***************** **/
1011
1012
1013/* ************** code for handling of ARPHRD_IEEE80211_FULL ************** */
1014
1015/**
1016 * Radiotap header iteration
1017 *
1018 * call __ieee80211_radiotap_iterator_init() to init a semi-opaque iterator
1019 * struct Ieee80211RadiotapHeaderIterator (no need to init the struct beforehand)
1020 * then loop calling __ieee80211_radiotap_iterator_next()... it returns -1
1021 * if there are no more args in the header, or the next argument type index
1022 * that is present. The iterator's this_arg member points to the start of the
1023 * argument associated with the current argument index that is present,
1024 * which can be found in the iterator's this_arg_index member. This arg
1025 * index corresponds to the IEEE80211_RADIOTAP_... defines.
1026 *
1027 * @param iterator iterator to initialize
1028 * @param radiotap_header message to parse
1029 * @param max_length number of valid bytes in radiotap_header
1030 * @return 0 on success, -1 on error
1031 */
1032static int
1033ieee80211_radiotap_iterator_init (struct
1034 Ieee80211RadiotapHeaderIterator *iterator,
1035 const struct
1036 Ieee80211RadiotapHeader *radiotap_header,
1037 size_t max_length)
1038{
1039 if ((iterator == NULL) ||
1040 (radiotap_header == NULL))
1041 return -1;
1042
1043 /* Linux only supports version 0 radiotap format */
1044 if (0 != radiotap_header->it_version)
1045 return -1;
1046
1047 /* sanity check for allowed length and radiotap length field */
1048 if ((max_length < sizeof(struct Ieee80211RadiotapHeader)) ||
1049 (max_length < (GNUNET_le16toh (radiotap_header->it_len))))
1050 return -1;
1051
1052 memset (iterator, 0, sizeof(struct Ieee80211RadiotapHeaderIterator));
1053 iterator->rtheader = radiotap_header;
1054 iterator->max_length = GNUNET_le16toh (radiotap_header->it_len);
1055 iterator->bitmap_shifter = GNUNET_le32toh (radiotap_header->it_present);
1056 iterator->arg = ((uint8_t *) radiotap_header) + sizeof(struct
1057 Ieee80211RadiotapHeader);
1058
1059 /* find payload start allowing for extended bitmap(s) */
1060 if (0 != (iterator->bitmap_shifter & IEEE80211_RADIOTAP_PRESENT_EXTEND_MASK))
1061 {
1062 while (GNUNET_le32toh (*((uint32_t *) iterator->arg))
1063 & IEEE80211_RADIOTAP_PRESENT_EXTEND_MASK)
1064 {
1065 iterator->arg += sizeof(uint32_t);
1066 /*
1067 * check for insanity where the present bitmaps
1068 * keep claiming to extend up to or even beyond the
1069 * stated radiotap header length
1070 */if (iterator->arg - ((uint8_t *) iterator->rtheader) >
1071 iterator->max_length)
1072 return -1;
1073 }
1074 iterator->arg += sizeof(uint32_t);
1075 /*
1076 * no need to check again for blowing past stated radiotap
1077 * header length, because ieee80211_radiotap_iterator_next
1078 * checks it before it is dereferenced
1079 */}
1080 /* we are all initialized happily */
1081 return 0;
1082}
1083
1084
1085/**
1086 * Returns the next radiotap parser iterator arg.
1087 *
1088 * This function returns the next radiotap arg index (IEEE80211_RADIOTAP_...)
1089 * and sets iterator->this_arg to point to the payload for the arg. It takes
1090 * care of alignment handling and extended present fields. interator->this_arg
1091 * can be changed by the caller. The args pointed to are in little-endian
1092 * format.
1093 *
1094 * @param iterator: radiotap_iterator to move to next arg (if any)
1095 * @return next present arg index on success or -1 if no more or error
1096 */
1097static int
1098ieee80211_radiotap_iterator_next (struct
1099 Ieee80211RadiotapHeaderIterator *iterator)
1100{
1101 /*
1102 * small length lookup table for all radiotap types we heard of
1103 * starting from b0 in the bitmap, so we can walk the payload
1104 * area of the radiotap header
1105 *
1106 * There is a requirement to pad args, so that args
1107 * of a given length must begin at a boundary of that length
1108 * -- but note that compound args are allowed (eg, 2 x uint16_t
1109 * for IEEE80211_RADIOTAP_CHANNEL) so total arg length is not
1110 * a reliable indicator of alignment requirement.
1111 *
1112 * upper nybble: content alignment for arg
1113 * lower nybble: content length for arg
1114 */static const uint8_t rt_sizes[] = {
1115 [IEEE80211_RADIOTAP_TSFT] = 0x88,
1116 [IEEE80211_RADIOTAP_FLAGS] = 0x11,
1117 [IEEE80211_RADIOTAP_RATE] = 0x11,
1118 [IEEE80211_RADIOTAP_CHANNEL] = 0x24,
1119 [IEEE80211_RADIOTAP_FHSS] = 0x22,
1120 [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = 0x11,
1121 [IEEE80211_RADIOTAP_DBM_ANTNOISE] = 0x11,
1122 [IEEE80211_RADIOTAP_LOCK_QUALITY] = 0x22,
1123 [IEEE80211_RADIOTAP_TX_ATTENUATION] = 0x22,
1124 [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = 0x22,
1125 [IEEE80211_RADIOTAP_DBM_TX_POWER] = 0x11,
1126 [IEEE80211_RADIOTAP_ANTENNA] = 0x11,
1127 [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = 0x11,
1128 [IEEE80211_RADIOTAP_DB_ANTNOISE] = 0x11,
1129 [IEEE80211_RADIOTAP_TX_FLAGS] = 0x22,
1130 [IEEE80211_RADIOTAP_RX_FLAGS] = 0x22,
1131 [IEEE80211_RADIOTAP_RTS_RETRIES] = 0x11,
1132 [IEEE80211_RADIOTAP_DATA_RETRIES] = 0x11
1133 /*
1134 * add more here as they are defined in
1135 * include/net/ieee80211_radiotap.h
1136 */
1137 };
1138
1139 /*
1140 * for every radiotap entry we can at
1141 * least skip (by knowing the length)...
1142 */
1143 while (iterator->arg_index < sizeof(rt_sizes))
1144 {
1145 int hit = (0 != (iterator->bitmap_shifter & 1));
1146
1147 if (hit)
1148 {
1149 unsigned int wanted_alignment;
1150 unsigned int unalignment;
1151 /*
1152 * arg is present, account for alignment padding
1153 * 8-bit args can be at any alignment
1154 * 16-bit args must start on 16-bit boundary
1155 * 32-bit args must start on 32-bit boundary
1156 * 64-bit args must start on 64-bit boundary
1157 *
1158 * note that total arg size can differ from alignment of
1159 * elements inside arg, so we use upper nybble of length table
1160 * to base alignment on. First, 'wanted_alignment' is set to be
1161 * 1 for 8-bit, 2 for 16-bit, 4 for 32-bit and 8 for 64-bit
1162 * arguments. Then, we calculate the 'unalignment' (how many
1163 * bytes we are over by taking the difference of 'arg' and the
1164 * overall starting point modulo the desired alignment. As
1165 * desired alignments are powers of two, we can do modulo with
1166 * binary "&" (and also avoid the possibility of a division by
1167 * zero if the 'rt_sizes' table contains bogus entries).
1168 *
1169 * also note: these alignments are relative to the start of the
1170 * radiotap header. There is no guarantee that the radiotap
1171 * header itself is aligned on any kind of boundary, thus we
1172 * need to really look at the delta here.
1173 */wanted_alignment = rt_sizes[iterator->arg_index] >> 4;
1174 unalignment = (((void *) iterator->arg) - ((void *) iterator->rtheader))
1175 & (wanted_alignment - 1);
1176 if (0 != unalignment)
1177 {
1178 /* need padding (by 'wanted_alignment - unalignment') */
1179 iterator->arg_index += wanted_alignment - unalignment;
1180 }
1181
1182 /*
1183 * this is what we will return to user, but we need to
1184 * move on first so next call has something fresh to test
1185 */
1186 iterator->this_arg_index = iterator->arg_index;
1187 iterator->this_arg = iterator->arg;
1188
1189 /* internally move on the size of this arg (using lower nybble from
1190 the table) */
1191 iterator->arg += rt_sizes[iterator->arg_index] & 0x0f;
1192
1193 /*
1194 * check for insanity where we are given a bitmap that
1195 * claims to have more arg content than the length of the
1196 * radiotap section. We will normally end up equalling this
1197 * max_length on the last arg, never exceeding it.
1198 */if ((((void *) iterator->arg) - ((void *) iterator->rtheader)) >
1199 iterator->max_length)
1200 return -1;
1201 }
1202
1203 /* Now, move on to next bit / next entry */
1204 iterator->arg_index++;
1205
1206 if (0 == (iterator->arg_index % 32))
1207 {
1208 /* completed current uint32_t bitmap */
1209 if (0 != (iterator->bitmap_shifter & 1))
1210 {
1211 /* bit 31 was set, there is more; move to next uint32_t bitmap */
1212 iterator->bitmap_shifter = GNUNET_le32toh (*iterator->next_bitmap);
1213 iterator->next_bitmap++;
1214 }
1215 else
1216 {
1217 /* no more bitmaps: end (by setting arg_index to high, unsupported value) */
1218 iterator->arg_index = sizeof(rt_sizes);
1219 }
1220 }
1221 else
1222 {
1223 /* just try the next bit (while loop will move on) */
1224 iterator->bitmap_shifter >>= 1;
1225 }
1226
1227 /* if we found a valid arg earlier, return it now */
1228 if (hit)
1229 return iterator->this_arg_index;
1230 }
1231
1232 /* we don't know how to handle any more args (or there are no more),
1233 so we're done (this is not an error) */
1234 return -1;
1235}
1236
1237
1238/**
1239 * Calculate crc32, the start of the calculation
1240 *
1241 * @param buf buffer to calc the crc
1242 * @param len len of the buffer
1243 * @return crc sum
1244 */
1245static unsigned long
1246calc_crc_osdep (const unsigned char *buf, size_t len)
1247{
1248 static const unsigned long int crc_tbl_osdep[256] = {
1249 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
1250 0xE963A535, 0x9E6495A3,
1251 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD,
1252 0xE7B82D07, 0x90BF1D91,
1253 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB,
1254 0xF4D4B551, 0x83D385C7,
1255 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
1256 0xFA0F3D63, 0x8D080DF5,
1257 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447,
1258 0xD20D85FD, 0xA50AB56B,
1259 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75,
1260 0xDCD60DCF, 0xABD13D59,
1261 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
1262 0xCFBA9599, 0xB8BDA50F,
1263 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11,
1264 0xC1611DAB, 0xB6662D3D,
1265 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F,
1266 0x9FBFE4A5, 0xE8B8D433,
1267 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
1268 0x91646C97, 0xE6635C01,
1269 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B,
1270 0x8208F4C1, 0xF50FC457,
1271 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49,
1272 0x8CD37CF3, 0xFBD44C65,
1273 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
1274 0xA4D1C46D, 0xD3D6F4FB,
1275 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5,
1276 0xAA0A4C5F, 0xDD0D7CC9,
1277 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3,
1278 0xB966D409, 0xCE61E49F,
1279 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
1280 0xB7BD5C3B, 0xC0BA6CAD,
1281 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF,
1282 0x04DB2615, 0x73DC1683,
1283 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D,
1284 0x0A00AE27, 0x7D079EB1,
1285 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
1286 0x196C3671, 0x6E6B06E7,
1287 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9,
1288 0x17B7BE43, 0x60B08ED5,
1289 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767,
1290 0x3FB506DD, 0x48B2364B,
1291 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
1292 0x316E8EEF, 0x4669BE79,
1293 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703,
1294 0x220216B9, 0x5505262F,
1295 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31,
1296 0x2CD99E8B, 0x5BDEAE1D,
1297 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
1298 0x72076785, 0x05005713,
1299 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D,
1300 0x7CDCEFB7, 0x0BDBDF21,
1301 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B,
1302 0x6FB077E1, 0x18B74777,
1303 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
1304 0x616BFFD3, 0x166CCF45,
1305 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7,
1306 0x4969474D, 0x3E6E77DB,
1307 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5,
1308 0x47B2CF7F, 0x30B5FFE9,
1309 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
1310 0x54DE5729, 0x23D967BF,
1311 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1,
1312 0x5A05DF1B, 0x2D02EF8D
1313 };
1314
1315 unsigned long crc = 0xFFFFFFFF;
1316
1317 for (; len > 0; len--, buf++)
1318 crc = crc_tbl_osdep[(crc ^ *buf) & 0xFF] ^ (crc >> 8);
1319 return(~crc);
1320}
1321
1322
1323/**
1324 * Calculate and check crc of the wlan packet
1325 *
1326 * @param buf buffer of the packet, with len + 4 bytes of data,
1327 * the last 4 bytes being the checksum
1328 * @param len length of the payload in data
1329 * @return 0 on success (checksum matches), 1 on error
1330 */
1331static int
1332check_crc_buf_osdep (const unsigned char *buf, size_t len)
1333{
1334 unsigned long crc;
1335
1336 crc = calc_crc_osdep (buf, len);
1337 buf += len;
1338 if ((((crc) & 0xFF) == buf[0]) && (((crc >> 8) & 0xFF) == buf[1]) &&
1339 ( ((crc >> 16) & 0xFF) == buf[2]) && ( ((crc >> 24) & 0xFF) == buf[3]) )
1340 return 0;
1341 return 1;
1342}
1343
1344
1345/* ************end of code for handling of ARPHRD_IEEE80211_FULL ************** */
1346
1347
1348/* ************beginning of code for reading packets from kernel ************** */
1349
1350/**
1351 * Return the channel from the frequency (in Mhz)
1352 *
1353 * @param frequency of the channel
1354 * @return number of the channel
1355 */
1356static int
1357get_channel_from_frequency (int32_t frequency)
1358{
1359 if ((frequency >= 2412) && (frequency <= 2472))
1360 return (frequency - 2407) / 5;
1361 if (frequency == 2484)
1362 return 14;
1363 if ((frequency >= 5000) && (frequency <= 6100))
1364 return (frequency - 5000) / 5;
1365 return -1;
1366}
1367
1368
1369/**
1370 * Get the channel used by our WLAN interface.
1371 *
1372 * @param dev pointer to the dev struct of the card
1373 * @return channel number, -1 on error
1374 */
1375static int
1376linux_get_channel (const struct HardwareInfos *dev)
1377{
1378 struct iwreq wrq;
1379 int32_t frequency;
1380
1381 memset (&wrq, 0, sizeof(struct iwreq));
1382 strncpy (wrq.ifr_name, dev->iface, IFNAMSIZ);
1383 if (0 > ioctl (dev->fd_raw, SIOCGIWFREQ, &wrq))
1384 return -1;
1385 frequency = wrq.u.freq.m; /* 'iw_freq' defines 'm' as '__s32', so we keep it signed */
1386 if (100000000 < frequency)
1387 frequency /= 100000;
1388 else if (1000000 < frequency)
1389 frequency /= 1000;
1390 if (1000 < frequency)
1391 return get_channel_from_frequency (frequency);
1392 return frequency;
1393}
1394
1395
1396/**
1397 * Read from the raw socket (the wlan card), parse the packet and
1398 * put the result into the buffer for transmission to 'stdout'.
1399 *
1400 * @param dev pointer to the struct of the wlan card
1401 * @param buf buffer to read to; first bytes will be the 'struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame',
1402 * followed by the actual payload
1403 * @param buf_size size of the buffer
1404 * @param ri where to write radiotap_rx info
1405 * @return number of bytes written to 'buf'
1406 */
1407static ssize_t
1408linux_read (struct HardwareInfos *dev,
1409 unsigned char *buf, size_t buf_size,
1410 struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage *ri)
1411{
1412 unsigned char tmpbuf[buf_size];
1413 ssize_t caplen;
1414 size_t n;
1415 int got_signal = 0;
1416 int got_noise = 0;
1417 int got_channel = 0;
1418 int fcs_removed = 0;
1419
1420 caplen = read (dev->fd_raw, tmpbuf, buf_size);
1421 if (0 > caplen)
1422 {
1423 if (EAGAIN == errno)
1424 return 0;
1425 fprintf (stderr, "Failed to read from RAW socket: %s\n", strerror (errno));
1426 return -1;
1427 }
1428
1429 memset (ri, 0, sizeof(*ri));
1430 switch (dev->arptype_in)
1431 {
1432 case ARPHRD_IEEE80211_PRISM:
1433 {
1434 const struct PrismHeader *ph;
1435
1436 ph = (const struct PrismHeader*) tmpbuf;
1437 n = ph->msglen;
1438 if ((n < 8) || (n >= caplen))
1439 return 0; /* invalid format */
1440 if ((PRISM_MSGCODE_MONITOR == ph->msgcode) &&
1441 (n >= sizeof(struct PrismHeader)))
1442 {
1443 const char *pos;
1444 size_t left;
1445 struct PrismValue pv;
1446
1447 left = n - sizeof(struct PrismHeader);
1448 pos = (const char *) &ph[1];
1449 while (left > sizeof(struct PrismValue))
1450 {
1451 left -= sizeof(struct PrismValue);
1452 GNUNET_memcpy (&pv, pos, sizeof(struct PrismValue));
1453 pos += sizeof(struct PrismValue);
1454
1455 switch (pv.did)
1456 {
1457 case PRISM_DID_NOISE:
1458 if (PRISM_STATUS_OK == pv.status)
1459 {
1460 ri->ri_noise = pv.data;
1461 /* got_noise = 1; */
1462 }
1463 break;
1464
1465 case PRISM_DID_RATE:
1466 if (PRISM_STATUS_OK == pv.status)
1467 ri->ri_rate = pv.data * 500000;
1468 break;
1469
1470 case PRISM_DID_CHANNEL:
1471 if (PRISM_STATUS_OK == pv.status)
1472 {
1473 ri->ri_channel = pv.data;
1474 got_channel = 1;
1475 }
1476 break;
1477
1478 case PRISM_DID_MACTIME:
1479 if (PRISM_STATUS_OK == pv.status)
1480 ri->ri_mactime = pv.data;
1481 break;
1482
1483 case PRISM_DID_SIGNAL:
1484 if (PRISM_STATUS_OK == pv.status)
1485 {
1486 ri->ri_power = pv.data;
1487 /* got_signal = 1; */
1488 }
1489 break;
1490 }
1491 }
1492 }
1493 if ((n < 8) || (n >= caplen))
1494 return 0; /* invalid format */
1495 }
1496 break;
1497
1498 case ARPHRD_IEEE80211_FULL:
1499 {
1500 struct Ieee80211RadiotapHeaderIterator iterator;
1501 struct Ieee80211RadiotapHeader *rthdr;
1502
1503 memset (&iterator, 0, sizeof(iterator));
1504 rthdr = (struct Ieee80211RadiotapHeader *) tmpbuf;
1505 n = GNUNET_le16toh (rthdr->it_len);
1506 if ((n < sizeof(struct Ieee80211RadiotapHeader)) || (n >= caplen))
1507 return 0; /* invalid 'it_len' */
1508 if (0 != ieee80211_radiotap_iterator_init (&iterator, rthdr, caplen))
1509 return 0;
1510 /* go through the radiotap arguments we have been given by the driver */
1511 while (0 <= ieee80211_radiotap_iterator_next (&iterator))
1512 {
1513 switch (iterator.this_arg_index)
1514 {
1515 case IEEE80211_RADIOTAP_TSFT:
1516 ri->ri_mactime = GNUNET_le64toh (*((uint64_t *) iterator.this_arg));
1517 break;
1518
1519 case IEEE80211_RADIOTAP_DBM_ANTSIGNAL:
1520 if (! got_signal)
1521 {
1522 ri->ri_power = *((int8_t *) iterator.this_arg);
1523 got_signal = 1;
1524 }
1525 break;
1526
1527 case IEEE80211_RADIOTAP_DB_ANTSIGNAL:
1528 if (! got_signal)
1529 {
1530 ri->ri_power = *((int8_t *) iterator.this_arg);
1531 got_signal = 1;
1532 }
1533 break;
1534
1535 case IEEE80211_RADIOTAP_DBM_ANTNOISE:
1536 if (! got_noise)
1537 {
1538 ri->ri_noise = *((int8_t *) iterator.this_arg);
1539 got_noise = 1;
1540 }
1541 break;
1542
1543 case IEEE80211_RADIOTAP_DB_ANTNOISE:
1544 if (! got_noise)
1545 {
1546 ri->ri_noise = *((int8_t *) iterator.this_arg);
1547 got_noise = 1;
1548 }
1549 break;
1550
1551 case IEEE80211_RADIOTAP_ANTENNA:
1552 ri->ri_antenna = *iterator.this_arg;
1553 break;
1554
1555 case IEEE80211_RADIOTAP_CHANNEL:
1556 ri->ri_channel = *iterator.this_arg;
1557 got_channel = 1;
1558 break;
1559
1560 case IEEE80211_RADIOTAP_RATE:
1561 ri->ri_rate = (*iterator.this_arg) * 500000;
1562 break;
1563
1564 case IEEE80211_RADIOTAP_FLAGS:
1565 {
1566 uint8_t flags = *iterator.this_arg;
1567 /* is the CRC visible at the end? if so, remove */
1568 if (0 != (flags & IEEE80211_RADIOTAP_F_FCS))
1569 {
1570 fcs_removed = 1;
1571 caplen -= sizeof(uint32_t);
1572 }
1573 break;
1574 }
1575
1576 case IEEE80211_RADIOTAP_RX_FLAGS:
1577 {
1578 uint16_t flags = ntohs (*((uint16_t *) iterator.this_arg));
1579 if (0 != (flags & IEEE80211_RADIOTAP_F_RX_BADFCS))
1580 return 0;
1581 }
1582 break;
1583 } /* end of 'switch' */
1584 } /* end of the 'while' loop */
1585 }
1586 break;
1587
1588 case ARPHRD_IEEE80211:
1589 n = 0; /* no header */
1590 break;
1591
1592 case ARPHRD_ETHER:
1593 {
1594 if (sizeof(struct GNUNET_TRANSPORT_WLAN_Ieee8023Frame) > caplen)
1595 return 0; /* invalid */
1596 GNUNET_memcpy (&buf[sizeof(struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame)],
1597 tmpbuf + sizeof(struct
1598 GNUNET_TRANSPORT_WLAN_Ieee8023Frame),
1599 caplen - sizeof(struct
1600 GNUNET_TRANSPORT_WLAN_Ieee8023Frame)
1601 - 4 /* 4 byte FCS */);
1602 return caplen - sizeof(struct GNUNET_TRANSPORT_WLAN_Ieee8023Frame) - 4;
1603 }
1604
1605 default:
1606 errno = ENOTSUP; /* unsupported format */
1607 return -1;
1608 }
1609 caplen -= n;
1610 if (! got_channel)
1611 ri->ri_channel = linux_get_channel (dev);
1612
1613 /* detect CRC32 at the end, even if the flag wasn't set and remove it */
1614 if ((0 == fcs_removed) &&
1615 (0 == check_crc_buf_osdep (tmpbuf + n, caplen - sizeof(uint32_t))))
1616 {
1617 /* NOTE: this heuristic can of course fail if there happens to
1618 be a matching checksum at the end. Would be good to have
1619 some data to see how often this heuristic actually works. */
1620 caplen -= sizeof(uint32_t);
1621 }
1622 /* copy payload to target buffer */
1623 GNUNET_memcpy (buf, tmpbuf + n, caplen);
1624 return caplen;
1625}
1626
1627
1628/* ************end of code for reading packets from kernel ************** */
1629
1630/* ************other helper functions for main start here ************** */
1631
1632
1633/**
1634 * Open the wireless network interface for reading/writing.
1635 *
1636 * @param dev pointer to the device struct
1637 * @return 0 on success
1638 */
1639static int
1640open_device_raw (struct HardwareInfos *dev)
1641{
1642 struct ifreq ifr;
1643 struct iwreq wrq;
1644 struct packet_mreq mr;
1645 struct sockaddr_ll sll;
1646
1647 /* find the interface index */
1648 memset (&ifr, 0, sizeof(ifr));
1649 strncpy (ifr.ifr_name, dev->iface, IFNAMSIZ);
1650 if (-1 == ioctl (dev->fd_raw, SIOCGIFINDEX, &ifr))
1651 {
1652 fprintf (stderr, "ioctl(SIOCGIFINDEX) on interface `%.*s' failed: %s\n",
1653 IFNAMSIZ, dev->iface, strerror (errno));
1654 return 1;
1655 }
1656
1657 /* lookup the hardware type */
1658 memset (&sll, 0, sizeof(sll));
1659 sll.sll_family = AF_PACKET;
1660 sll.sll_ifindex = ifr.ifr_ifindex;
1661 sll.sll_protocol = htons (ETH_P_ALL);
1662 if (-1 == ioctl (dev->fd_raw, SIOCGIFHWADDR, &ifr))
1663 {
1664 fprintf (stderr, "ioctl(SIOCGIFHWADDR) on interface `%.*s' failed: %s\n",
1665 IFNAMSIZ, dev->iface, strerror (errno));
1666 return 1;
1667 }
1668 if (((ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211) &&
1669 (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) &&
1670 (ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211_PRISM) &&
1671 (ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211_FULL)))
1672 {
1673 fprintf (stderr,
1674 "Error: interface `%.*s' is not using a supported hardware address family (got %d)\n",
1675 IFNAMSIZ, dev->iface,
1676 ifr.ifr_hwaddr.sa_family);
1677 return 1;
1678 }
1679
1680 /* lookup iw mode */
1681 memset (&wrq, 0, sizeof(struct iwreq));
1682 strncpy (wrq.ifr_name, dev->iface, IFNAMSIZ);
1683 if (-1 == ioctl (dev->fd_raw, SIOCGIWMODE, &wrq))
1684 {
1685 /* most probably not supported (ie for rtap ipw interface) *
1686 * so just assume its correctly set... */
1687 wrq.u.mode = IW_MODE_MONITOR;
1688 }
1689
1690 if ((wrq.u.mode != IW_MODE_MONITOR) &&
1691 (wrq.u.mode != IW_MODE_ADHOC))
1692 {
1693 fprintf (stderr,
1694 "Error: interface `%.*s' is not in monitor or ad-hoc mode (got %d)\n",
1695 IFNAMSIZ, dev->iface,
1696 wrq.u.mode);
1697 return 1;
1698 }
1699
1700 /* Is interface st to up, broadcast & running ? */
1701 if ((ifr.ifr_flags | IFF_UP | IFF_BROADCAST | IFF_RUNNING) != ifr.ifr_flags)
1702 {
1703 /* Bring interface up */
1704 ifr.ifr_flags |= IFF_UP | IFF_BROADCAST | IFF_RUNNING;
1705
1706 if (-1 == ioctl (dev->fd_raw, SIOCSIFFLAGS, &ifr))
1707 {
1708 fprintf (stderr, "ioctl(SIOCSIFFLAGS) on interface `%.*s' failed: %s\n",
1709 IFNAMSIZ, dev->iface, strerror (errno));
1710 return 1;
1711 }
1712 }
1713
1714 /* bind the raw socket to the interface */
1715 if (-1 == bind (dev->fd_raw, (struct sockaddr *) &sll, sizeof(sll)))
1716 {
1717 fprintf (stderr, "Failed to bind interface `%.*s': %s\n", IFNAMSIZ,
1718 dev->iface, strerror (errno));
1719 return 1;
1720 }
1721
1722 /* lookup the hardware type */
1723 if (-1 == ioctl (dev->fd_raw, SIOCGIFHWADDR, &ifr))
1724 {
1725 fprintf (stderr, "ioctl(SIOCGIFHWADDR) on interface `%.*s' failed: %s\n",
1726 IFNAMSIZ, dev->iface, strerror (errno));
1727 return 1;
1728 }
1729
1730 GNUNET_memcpy (&dev->pl_mac, ifr.ifr_hwaddr.sa_data, MAC_ADDR_SIZE);
1731 dev->arptype_in = ifr.ifr_hwaddr.sa_family;
1732 if ((ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) &&
1733 (ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211) &&
1734 (ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211_PRISM) &&
1735 (ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211_FULL))
1736 {
1737 fprintf (stderr, "Unsupported hardware link type %d on interface `%.*s'\n",
1738 ifr.ifr_hwaddr.sa_family, IFNAMSIZ, dev->iface);
1739 return 1;
1740 }
1741
1742 /* enable promiscuous mode */
1743 memset (&mr, 0, sizeof(mr));
1744 mr.mr_ifindex = sll.sll_ifindex;
1745 mr.mr_type = PACKET_MR_PROMISC;
1746 if (0 !=
1747 setsockopt (dev->fd_raw, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mr,
1748 sizeof(mr)))
1749 {
1750 fprintf (stderr,
1751 "Failed to enable promiscuous mode on interface `%.*s'\n",
1752 IFNAMSIZ,
1753 dev->iface);
1754 return 1;
1755 }
1756 return 0;
1757}
1758
1759
1760/**
1761 * Test if the given interface name really corresponds to a wireless
1762 * device.
1763 *
1764 * @param iface name of the interface
1765 * @return 0 on success, 1 on error
1766 */
1767static int
1768test_wlan_interface (const char *iface)
1769{
1770 char strbuf[512];
1771 struct stat sbuf;
1772 int ret;
1773
1774 ret = snprintf (strbuf, sizeof(strbuf),
1775 "/sys/class/net/%s/phy80211/subsystem",
1776 iface);
1777 if ((ret < 0) || (ret >= sizeof(strbuf)) || (0 != stat (strbuf, &sbuf)))
1778 {
1779 fprintf (stderr,
1780 "Did not find 802.11 interface `%s'. Exiting.\n",
1781 iface);
1782 exit (1);
1783 }
1784 return 0;
1785}
1786
1787
1788/**
1789 * Test incoming packets mac for being our own.
1790 *
1791 * @param taIeeeHeader buffer of the packet
1792 * @param dev the Hardware_Infos struct
1793 * @return 0 if mac belongs to us, 1 if mac is for another target
1794 */
1795static int
1796mac_test (const struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *taIeeeHeader,
1797 const struct HardwareInfos *dev)
1798{
1799 static struct GNUNET_TRANSPORT_WLAN_MacAddress all_zeros;
1800
1801 if ((0 == memcmp (&taIeeeHeader->addr3, &all_zeros, MAC_ADDR_SIZE)) ||
1802 (0 == memcmp (&taIeeeHeader->addr1, &all_zeros, MAC_ADDR_SIZE)))
1803 return 0; /* some drivers set no Macs, then assume it is all for us! */
1804
1805 if (0 != memcmp (&taIeeeHeader->addr3, &mac_bssid_gnunet, MAC_ADDR_SIZE))
1806 return 1; /* not a GNUnet ad-hoc package */
1807 if ((0 == memcmp (&taIeeeHeader->addr1, &dev->pl_mac, MAC_ADDR_SIZE)) ||
1808 (0 == memcmp (&taIeeeHeader->addr1, &bc_all_mac, MAC_ADDR_SIZE)))
1809 return 0; /* for us, or broadcast */
1810 return 1; /* not for us */
1811}
1812
1813
1814/**
1815 * Set the wlan header to sane values to make attacks more difficult
1816 *
1817 * @param taIeeeHeader pointer to the header of the packet
1818 * @param dev pointer to the Hardware_Infos struct
1819 */
1820static void
1821mac_set (struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *taIeeeHeader,
1822 const struct HardwareInfos *dev)
1823{
1824 taIeeeHeader->frame_control = htons (IEEE80211_FC0_TYPE_DATA);
1825 taIeeeHeader->addr2 = dev->pl_mac;
1826 taIeeeHeader->addr3 = mac_bssid_gnunet;
1827}
1828
1829
1830/**
1831 * Process data from the stdin. Takes the message, prepends the
1832 * radiotap transmission header, forces the sender MAC to be correct
1833 * and puts it into our buffer for transmission to the kernel.
1834 *
1835 * @param cls pointer to the device struct ('struct HardwareInfos*')
1836 * @param hdr pointer to the start of the packet
1837 */
1838static void
1839stdin_send_hw (void *cls, const struct GNUNET_MessageHeader *hdr)
1840{
1841 struct HardwareInfos *dev = cls;
1842 const struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *header;
1843 struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *wlanheader;
1844 size_t sendsize;
1845 struct RadiotapTransmissionHeader rtheader;
1846 struct GNUNET_TRANSPORT_WLAN_Ieee8023Frame etheader;
1847
1848 sendsize = ntohs (hdr->size);
1849 if ((sendsize <
1850 sizeof(struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage)) ||
1851 (GNUNET_MESSAGE_TYPE_WLAN_DATA_TO_HELPER != ntohs (hdr->type)))
1852 {
1853 fprintf (stderr, "Received malformed message\n");
1854 exit (1);
1855 }
1856 sendsize -= (sizeof(struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage)
1857 - sizeof(struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame));
1858 if (MAXLINE < sendsize)
1859 {
1860 fprintf (stderr, "Packet too big for buffer\n");
1861 exit (1);
1862 }
1863 header = (const struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *) hdr;
1864 switch (dev->arptype_in)
1865 {
1866 case ARPHRD_IEEE80211_PRISM:
1867 case ARPHRD_IEEE80211_FULL:
1868 case ARPHRD_IEEE80211:
1869 rtheader.header.it_version = 0;
1870 rtheader.header.it_pad = 0;
1871 rtheader.header.it_len = GNUNET_htole16 (sizeof(rtheader));
1872 rtheader.header.it_present = GNUNET_htole16 (
1873 IEEE80211_RADIOTAP_OUR_TRANSMISSION_HEADER_MASK);
1874 rtheader.rate = header->rate;
1875 rtheader.pad1 = 0;
1876 rtheader.txflags = GNUNET_htole16 (IEEE80211_RADIOTAP_F_TX_NOACK
1877 | IEEE80211_RADIOTAP_F_TX_NOSEQ);
1878 GNUNET_memcpy (write_pout.buf, &rtheader, sizeof(rtheader));
1879 GNUNET_memcpy (&write_pout.buf[sizeof(rtheader)], &header->frame, sendsize);
1880 wlanheader = (struct
1881 GNUNET_TRANSPORT_WLAN_Ieee80211Frame *) &write_pout.buf[sizeof(
1882 rtheader)
1883 ];
1884
1885 /* payload contains MAC address, but we don't trust it, so we'll
1886 * overwrite it with OUR MAC address to prevent mischief */
1887 mac_set (wlanheader, dev);
1888 write_pout.size = sendsize + sizeof(rtheader);
1889 break;
1890
1891 case ARPHRD_ETHER:
1892 etheader.dst = header->frame.addr1;
1893 /* etheader.src = header->frame.addr2; --- untrusted input */
1894 etheader.src = dev->pl_mac;
1895 etheader.type = htons (ETH_P_IP);
1896 GNUNET_memcpy (write_pout.buf, &etheader, sizeof(etheader));
1897 GNUNET_memcpy (&write_pout.buf[sizeof(etheader)], &header[1], sendsize
1898 - sizeof(struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame));
1899 write_pout.size = sendsize - sizeof(struct
1900 GNUNET_TRANSPORT_WLAN_Ieee80211Frame)
1901 + sizeof(etheader);
1902 break;
1903
1904 default:
1905 fprintf (stderr,
1906 "Unsupported ARPTYPE!\n");
1907 break;
1908 }
1909}
1910
1911
1912/**
1913 * Main function of the helper. This code accesses a WLAN interface
1914 * in monitoring mode (layer 2) and then forwards traffic in both
1915 * directions between the WLAN interface and stdin/stdout of this
1916 * process. Error messages are written to stdout.
1917 *
1918 * @param argc number of arguments, must be 2
1919 * @param argv arguments only argument is the name of the interface (e.g. 'mon0')
1920 * @return 0 on success (never happens, as we don't return unless aborted), 1 on error
1921 */
1922int
1923main (int argc, char *argv[])
1924{
1925 struct HardwareInfos dev;
1926 char readbuf[MAXLINE];
1927 int maxfd;
1928 fd_set rfds;
1929 fd_set wfds;
1930 int stdin_open;
1931 struct MessageStreamTokenizer *stdin_mst;
1932 int raw_eno;
1933
1934 /* assert privs so we can modify the firewall rules! */
1935 {
1936#ifdef HAVE_SETRESUID
1937 uid_t uid = getuid ();
1938
1939 if (0 != setresuid (uid, 0, 0))
1940 {
1941 fprintf (stderr,
1942 "Failed to setresuid to root: %s\n",
1943 strerror (errno));
1944 return 254;
1945 }
1946#else
1947 if (0 != seteuid (0))
1948 {
1949 fprintf (stderr,
1950 "Failed to seteuid back to root: %s\n", strerror (errno));
1951 return 254;
1952 }
1953#endif
1954 }
1955
1956 /* make use of SGID capabilities on POSIX */
1957 memset (&dev, 0, sizeof(dev));
1958 dev.fd_raw = socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ALL));
1959 raw_eno = errno; /* remember for later */
1960
1961 /* now that we've dropped root rights, we can do error checking */
1962 if (2 != argc)
1963 {
1964 fprintf (stderr,
1965 "You must specify the name of the interface as the first and only argument to this program.\n");
1966 if (-1 != dev.fd_raw)
1967 (void) close (dev.fd_raw);
1968 return 1;
1969 }
1970
1971 if (-1 == dev.fd_raw)
1972 {
1973 fprintf (stderr, "Failed to create raw socket: %s\n", strerror (raw_eno));
1974 return 1;
1975 }
1976 if (dev.fd_raw >= FD_SETSIZE)
1977 {
1978 fprintf (stderr, "File descriptor too large for select (%d > %d)\n",
1979 dev.fd_raw, FD_SETSIZE);
1980 (void) close (dev.fd_raw);
1981 return 1;
1982 }
1983 if (0 != test_wlan_interface (argv[1]))
1984 {
1985 (void) close (dev.fd_raw);
1986 return 1;
1987 }
1988 memcpy (dev.iface, argv[1], IFNAMSIZ);
1989 if (0 != open_device_raw (&dev))
1990 {
1991 (void) close (dev.fd_raw);
1992 return 1;
1993 }
1994
1995 /* drop privs */
1996 {
1997 uid_t uid = getuid ();
1998#ifdef HAVE_SETRESUID
1999 if (0 != setresuid (uid, uid, uid))
2000 {
2001 fprintf (stderr, "Failed to setresuid: %s\n", strerror (errno));
2002 if (-1 != dev.fd_raw)
2003 (void) close (dev.fd_raw);
2004 return 1;
2005 }
2006#else
2007 if (0 != (setuid (uid) | seteuid (uid)))
2008 {
2009 fprintf (stderr, "Failed to setuid: %s\n", strerror (errno));
2010 if (-1 != dev.fd_raw)
2011 (void) close (dev.fd_raw);
2012 return 1;
2013 }
2014#endif
2015 }
2016
2017
2018 /* send MAC address of the WLAN interface to STDOUT first */
2019 {
2020 struct GNUNET_TRANSPORT_WLAN_HelperControlMessage macmsg;
2021
2022 macmsg.hdr.size = htons (sizeof(macmsg));
2023 macmsg.hdr.type = htons (GNUNET_MESSAGE_TYPE_WLAN_HELPER_CONTROL);
2024 GNUNET_memcpy (&macmsg.mac, &dev.pl_mac, sizeof(struct
2025 GNUNET_TRANSPORT_WLAN_MacAddress));
2026 GNUNET_memcpy (write_std.buf, &macmsg, sizeof(macmsg));
2027 write_std.size = sizeof(macmsg);
2028 }
2029
2030 stdin_mst = mst_create (&stdin_send_hw, &dev);
2031 stdin_open = 1;
2032 while (1)
2033 {
2034 maxfd = -1;
2035 FD_ZERO (&rfds);
2036 if ((0 == write_pout.size) && (1 == stdin_open))
2037 {
2038 FD_SET (STDIN_FILENO, &rfds);
2039 maxfd = MAX (maxfd, STDIN_FILENO);
2040 }
2041 if (0 == write_std.size)
2042 {
2043 FD_SET (dev.fd_raw, &rfds);
2044 maxfd = MAX (maxfd, dev.fd_raw);
2045 }
2046 FD_ZERO (&wfds);
2047 if (0 < write_std.size)
2048 {
2049 FD_SET (STDOUT_FILENO, &wfds);
2050 maxfd = MAX (maxfd, STDOUT_FILENO);
2051 }
2052 if (0 < write_pout.size)
2053 {
2054 FD_SET (dev.fd_raw, &wfds);
2055 maxfd = MAX (maxfd, dev.fd_raw);
2056 }
2057 {
2058 int retval = select (maxfd + 1, &rfds, &wfds, NULL, NULL);
2059 if ((-1 == retval) && (EINTR == errno))
2060 continue;
2061 if (0 > retval)
2062 {
2063 fprintf (stderr, "select failed: %s\n", strerror (errno));
2064 break;
2065 }
2066 }
2067 if (FD_ISSET (STDOUT_FILENO, &wfds))
2068 {
2069 ssize_t ret =
2070 write (STDOUT_FILENO, write_std.buf + write_std.pos,
2071 write_std.size - write_std.pos);
2072 if (0 > ret)
2073 {
2074 fprintf (stderr, "Failed to write to STDOUT: %s\n", strerror (errno));
2075 break;
2076 }
2077 write_std.pos += ret;
2078 if (write_std.pos == write_std.size)
2079 {
2080 write_std.pos = 0;
2081 write_std.size = 0;
2082 }
2083 }
2084 if (FD_ISSET (dev.fd_raw, &wfds))
2085 {
2086 ssize_t ret =
2087 write (dev.fd_raw, write_pout.buf + write_pout.pos,
2088 write_pout.size - write_pout.pos);
2089 if (0 > ret)
2090 {
2091 fprintf (stderr, "Failed to write to WLAN device: %s\n",
2092 strerror (errno));
2093 break;
2094 }
2095 write_pout.pos += ret;
2096 if ((write_pout.pos != write_pout.size) && (0 != ret))
2097 {
2098 /* we should not get partial sends with packet-oriented devices... */
2099 fprintf (stderr, "Write error, partial send: %u/%u\n",
2100 (unsigned int) write_pout.pos,
2101 (unsigned int) write_pout.size);
2102 break;
2103 }
2104 if (write_pout.pos == write_pout.size)
2105 {
2106 write_pout.pos = 0;
2107 write_pout.size = 0;
2108 }
2109 }
2110
2111 if (FD_ISSET (STDIN_FILENO, &rfds))
2112 {
2113 ssize_t ret =
2114 read (STDIN_FILENO, readbuf, sizeof(readbuf));
2115 if (0 > ret)
2116 {
2117 fprintf (stderr, "Read error from STDIN: %s\n", strerror (errno));
2118 break;
2119 }
2120 if (0 == ret)
2121 {
2122 /* stop reading... */
2123 stdin_open = 0;
2124 }
2125 mst_receive (stdin_mst, readbuf, ret);
2126 }
2127
2128 if (FD_ISSET (dev.fd_raw, &rfds))
2129 {
2130 struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage *rrm;
2131 ssize_t ret;
2132
2133 rrm = (struct
2134 GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage *) write_std.buf;
2135 ret =
2136 linux_read (&dev, (unsigned char *) &rrm->frame,
2137 sizeof(write_std.buf)
2138 - sizeof(struct
2139 GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage)
2140 + sizeof(struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame),
2141 rrm);
2142 if (0 > ret)
2143 {
2144 fprintf (stderr, "Read error from raw socket: %s\n", strerror (errno));
2145 break;
2146 }
2147 if ((0 < ret) && (0 == mac_test (&rrm->frame, &dev)))
2148 {
2149 write_std.size = ret
2150 + sizeof(struct
2151 GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage)
2152 - sizeof(struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame);
2153 rrm->header.size = htons (write_std.size);
2154 rrm->header.type = htons (GNUNET_MESSAGE_TYPE_WLAN_DATA_FROM_HELPER);
2155 }
2156 }
2157 }
2158 /* Error handling, try to clean up a bit at least */
2159 mst_destroy (stdin_mst);
2160 (void) close (dev.fd_raw);
2161 return 1; /* we never exit 'normally' */
2162}
2163
2164
2165/* end of gnunet-helper-transport-wlan.c */
diff --git a/src/transport/gnunet-service-transport.c b/src/transport/gnunet-service-transport.c
deleted file mode 100644
index 93790e293..000000000
--- a/src/transport/gnunet-service-transport.c
+++ /dev/null
@@ -1,2778 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010-2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport/gnunet-service-transport.c
22 * @brief main for gnunet-service-transport
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "gnunet_util_lib.h"
27#include "gnunet_hello_lib.h"
28#include "gnunet_statistics_service.h"
29#include "gnunet_transport_service.h"
30#include "gnunet_peerinfo_service.h"
31#include "gnunet_ats_service.h"
32#include "gnunet-service-transport.h"
33#include "gnunet-service-transport_ats.h"
34#include "gnunet-service-transport_hello.h"
35#include "gnunet-service-transport_neighbours.h"
36#include "gnunet-service-transport_plugins.h"
37#include "gnunet-service-transport_validation.h"
38#include "gnunet-service-transport_manipulation.h"
39#include "transport.h"
40
41/**
42 * Size of the blacklist hash map.
43 */
44#define TRANSPORT_BLACKLIST_HT_SIZE 64
45
46/**
47 * How many messages can we have pending for a given client process
48 * before we start to drop incoming messages? We typically should
49 * have only one client and so this would be the primary buffer for
50 * messages, so the number should be chosen rather generously.
51 *
52 * The expectation here is that most of the time the queue is large
53 * enough so that a drop is virtually never required. Note that
54 * this value must be about as large as 'TOTAL_MSGS' in the
55 * 'test_transport_api_reliability.c', otherwise that testcase may
56 * fail.
57 */
58#define MAX_PENDING (128 * 1024)
59
60
61/**
62 * Information we need for an asynchronous session kill.
63 */
64struct GNUNET_ATS_SessionKiller
65{
66 /**
67 * Kept in a DLL.
68 */
69 struct GNUNET_ATS_SessionKiller *next;
70
71 /**
72 * Kept in a DLL.
73 */
74 struct GNUNET_ATS_SessionKiller *prev;
75
76 /**
77 * Session to kill.
78 */
79 struct GNUNET_ATS_Session *session;
80
81 /**
82 * Plugin for the session.
83 */
84 struct GNUNET_TRANSPORT_PluginFunctions *plugin;
85
86 /**
87 * The kill task.
88 */
89 struct GNUNET_SCHEDULER_Task *task;
90};
91
92
93/**
94 * What type of client is the `struct TransportClient` about?
95 */
96enum ClientType
97{
98 /**
99 * We do not know yet (client is fresh).
100 */
101 CT_NONE = 0,
102
103 /**
104 * Is the CORE service, we need to forward traffic to it.
105 */
106 CT_CORE = 1,
107
108 /**
109 * It is a monitor, forward monitor data.
110 */
111 CT_MONITOR = 2,
112
113 /**
114 * It is a blacklist, query about allowed connections.
115 */
116 CT_BLACKLIST = 3,
117
118 /**
119 * CORE client without any handlers.
120 */
121 CT_CORE_NO_HANDLERS = 4
122};
123
124
125/**
126 * Context we use when performing a blacklist check.
127 */
128struct GST_BlacklistCheck;
129
130/**
131 * Client connected to the transport service.
132 */
133struct TransportClient
134{
135 /**
136 * This is a doubly-linked list.
137 */
138 struct TransportClient *next;
139
140 /**
141 * This is a doubly-linked list.
142 */
143 struct TransportClient *prev;
144
145 /**
146 * Handle to the client.
147 */
148 struct GNUNET_SERVICE_Client *client;
149
150 /**
151 * Message queue to the client.
152 */
153 struct GNUNET_MQ_Handle *mq;
154
155 /**
156 * What type of client is this?
157 */
158 enum ClientType type;
159
160 union
161 {
162 /**
163 * Peer identity to monitor the addresses of.
164 * Zero to monitor all neighbours. Valid if
165 * @e type is CT_MONITOR.
166 */
167 struct GNUNET_PeerIdentity monitor_peer;
168
169 /**
170 * Additional details if @e type is CT_BLACKLIST.
171 */
172 struct
173 {
174 /**
175 * Blacklist check that we're currently performing (or NULL
176 * if we're performing one that has been cancelled).
177 */
178 struct GST_BlacklistCheck *bc;
179
180 /**
181 * Set to #GNUNET_YES if we're currently waiting for a reply.
182 */
183 int waiting_for_reply;
184
185 /**
186 * #GNUNET_YES if we have to call receive_done for this client
187 */
188 int call_receive_done;
189 } blacklist;
190 } details;
191};
192
193
194/**
195 * Context we use when performing a blacklist check.
196 */
197struct GST_BlacklistCheck
198{
199 /**
200 * This is a linked list.
201 */
202 struct GST_BlacklistCheck *next;
203
204 /**
205 * This is a linked list.
206 */
207 struct GST_BlacklistCheck *prev;
208
209 /**
210 * Peer being checked.
211 */
212 struct GNUNET_PeerIdentity peer;
213
214 /**
215 * Continuation to call with the result.
216 */
217 GST_BlacklistTestContinuation cont;
218
219 /**
220 * Closure for @e cont.
221 */
222 void *cont_cls;
223
224 /**
225 * Address for #GST_blacklist_abort_matching(), can be NULL.
226 */
227 struct GNUNET_HELLO_Address *address;
228
229 /**
230 * Session for #GST_blacklist_abort_matching(), can be NULL.
231 */
232 struct GNUNET_ATS_Session *session;
233
234 /**
235 * Our current position in the blacklisters list.
236 */
237 struct TransportClient *bl_pos;
238
239 /**
240 * Current task performing the check.
241 */
242 struct GNUNET_SCHEDULER_Task *task;
243};
244
245
246/**
247 * Context for address to string operations
248 */
249struct AddressToStringContext
250{
251 /**
252 * This is a doubly-linked list.
253 */
254 struct AddressToStringContext *next;
255
256 /**
257 * This is a doubly-linked list.
258 */
259 struct AddressToStringContext *prev;
260
261 /**
262 * Client that made the request.
263 */
264 struct TransportClient *tc;
265};
266
267
268/**
269 * Closure for #handle_send_transmit_continuation()
270 */
271struct SendTransmitContinuationContext
272{
273 /**
274 * Client that made the request.
275 */
276 struct TransportClient *tc;
277
278 /**
279 * Peer that was the target.
280 */
281 struct GNUNET_PeerIdentity target;
282
283 /**
284 * At what time did we receive the message?
285 */
286 struct GNUNET_TIME_Absolute send_time;
287
288 /**
289 * Unique ID, for logging.
290 */
291 unsigned long long uuid;
292
293 /**
294 * Set to #GNUNET_YES if the connection for @e target goes
295 * down and we thus must no longer send the
296 * #GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK message.
297 */
298 int down;
299};
300
301
302/**
303 * Head of linked list of all clients to this service.
304 */
305static struct TransportClient *clients_head;
306
307/**
308 * Tail of linked list of all clients to this service.
309 */
310static struct TransportClient *clients_tail;
311
312/**
313 * Map of peer identities to active send transmit continuation
314 * contexts. Used to flag contexts as 'dead' when a connection goes
315 * down. Values are of type `struct SendTransmitContinuationContext
316 * *`.
317 */
318static struct GNUNET_CONTAINER_MultiPeerMap *active_stccs;
319
320/**
321 * Head of linked list of all pending address iterations
322 */
323static struct AddressToStringContext *a2s_head;
324
325/**
326 * Tail of linked list of all pending address iterations
327 */
328static struct AddressToStringContext *a2s_tail;
329
330/**
331 * Head of DLL of active blacklisting queries.
332 */
333static struct GST_BlacklistCheck *bc_head;
334
335/**
336 * Tail of DLL of active blacklisting queries.
337 */
338static struct GST_BlacklistCheck *bc_tail;
339
340/**
341 * Hashmap of blacklisted peers. Values are of type 'char *' (transport names),
342 * can be NULL if we have no static blacklist.
343 */
344static struct GNUNET_CONTAINER_MultiPeerMap *blacklist;
345
346/**
347 * Notification context, to send updates on changes to active plugin
348 * connections.
349 */
350static struct GNUNET_NotificationContext *plugin_nc;
351
352/**
353 * Plugin monitoring client we are currently syncing, NULL if all
354 * monitoring clients are in sync.
355 */
356static struct TransportClient *sync_client;
357
358/**
359 * Peer identity that is all zeros, used as a way to indicate
360 * "all peers". Used for comparisons.
361 */
362static struct GNUNET_PeerIdentity all_zeros;
363
364/**
365 * Statistics handle.
366 */
367struct GNUNET_STATISTICS_Handle *GST_stats;
368
369/**
370 * Configuration handle.
371 */
372const struct GNUNET_CONFIGURATION_Handle *GST_cfg;
373
374/**
375 * Configuration handle.
376 */
377struct GNUNET_PeerIdentity GST_my_identity;
378
379/**
380 * Handle to peerinfo service.
381 */
382struct GNUNET_PEERINFO_Handle *GST_peerinfo;
383
384/**
385 * Our private key.
386 */
387struct GNUNET_CRYPTO_EddsaPrivateKey GST_my_private_key;
388
389/**
390 * ATS scheduling handle.
391 */
392struct GNUNET_ATS_SchedulingHandle *GST_ats;
393
394/**
395 * ATS connectivity handle.
396 */
397struct GNUNET_ATS_ConnectivityHandle *GST_ats_connect;
398
399/**
400 * Hello address expiration
401 */
402struct GNUNET_TIME_Relative hello_expiration;
403
404/**
405 * Head of DLL of asynchronous tasks to kill sessions.
406 */
407static struct GNUNET_ATS_SessionKiller *sk_head;
408
409/**
410 * Tail of DLL of asynchronous tasks to kill sessions.
411 */
412static struct GNUNET_ATS_SessionKiller *sk_tail;
413
414/**
415 * Interface scanner determines our LAN address range(s).
416 */
417struct GNUNET_NT_InterfaceScanner *GST_is;
418
419/**
420 * Queue the given message for transmission to the given client
421 *
422 * @param tc target of the message
423 * @param msg message to transmit
424 * @param may_drop #GNUNET_YES if the message can be dropped
425 */
426static void
427unicast (struct TransportClient *tc,
428 const struct GNUNET_MessageHeader *msg,
429 int may_drop)
430{
431 struct GNUNET_MQ_Envelope *env;
432
433 if ((GNUNET_MQ_get_length (tc->mq) >= MAX_PENDING) &&
434 (GNUNET_YES == may_drop))
435 {
436 GNUNET_log (
437 GNUNET_ERROR_TYPE_DEBUG,
438 "Dropping message of type %u and size %u, have %u/%u messages pending\n",
439 ntohs (msg->type),
440 ntohs (msg->size),
441 GNUNET_MQ_get_length (tc->mq),
442 MAX_PENDING);
443 GNUNET_STATISTICS_update (GST_stats,
444 gettext_noop (
445 "# messages dropped due to slow client"),
446 1,
447 GNUNET_NO);
448 return;
449 }
450 env = GNUNET_MQ_msg_copy (msg);
451 GNUNET_MQ_send (tc->mq, env);
452}
453
454
455/**
456 * Called whenever a client connects. Allocates our
457 * data structures associated with that client.
458 *
459 * @param cls closure, NULL
460 * @param client identification of the client
461 * @param mq message queue for the client
462 * @return our `struct TransportClient`
463 */
464static void *
465client_connect_cb (void *cls,
466 struct GNUNET_SERVICE_Client *client,
467 struct GNUNET_MQ_Handle *mq)
468{
469 struct TransportClient *tc;
470
471 tc = GNUNET_new (struct TransportClient);
472 tc->client = client;
473 tc->mq = mq;
474 GNUNET_CONTAINER_DLL_insert (clients_head, clients_tail, tc);
475 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", tc);
476 return tc;
477}
478
479
480/**
481 * Perform next action in the blacklist check.
482 *
483 * @param cls the `struct GST_BlacklistCheck *`
484 */
485static void
486do_blacklist_check (void *cls);
487
488
489/**
490 * Mark the peer as down so we don't call the continuation
491 * context in the future.
492 *
493 * @param cls a `struct TransportClient`
494 * @param peer a peer we are sending to
495 * @param value a `struct SendTransmitContinuationContext` to mark
496 * @return #GNUNET_OK (continue to iterate)
497 */
498static int
499mark_match_down (void *cls, const struct GNUNET_PeerIdentity *peer, void *value)
500{
501 struct TransportClient *tc = cls;
502 struct SendTransmitContinuationContext *stcc = value;
503
504 if (tc == stcc->tc)
505 {
506 stcc->down = GNUNET_YES;
507 stcc->tc = NULL;
508 }
509 return GNUNET_OK;
510}
511
512
513/**
514 * Called whenever a client is disconnected. Frees our
515 * resources associated with that client.
516 *
517 * @param cls closure, NULL
518 * @param client identification of the client
519 * @param app_ctx our `struct TransportClient`
520 */
521static void
522client_disconnect_cb (void *cls,
523 struct GNUNET_SERVICE_Client *client,
524 void *app_ctx)
525{
526 struct TransportClient *tc = app_ctx;
527 struct GST_BlacklistCheck *bc;
528
529 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
530 "Client %p disconnected, cleaning up.\n",
531 tc);
532 if (NULL != active_stccs)
533 GNUNET_CONTAINER_multipeermap_iterate (active_stccs,
534 &mark_match_down,
535 tc);
536 for (struct AddressToStringContext *cur = a2s_head; NULL != cur;
537 cur = cur->next)
538 {
539 if (cur->tc == tc)
540 cur->tc = NULL;
541 }
542 GNUNET_CONTAINER_DLL_remove (clients_head, clients_tail, tc);
543 switch (tc->type)
544 {
545 case CT_NONE:
546 break;
547
548 case CT_CORE:
549 break;
550
551 case CT_MONITOR:
552 break;
553
554 case CT_BLACKLIST:
555 for (bc = bc_head; NULL != bc; bc = bc->next)
556 {
557 if (bc->bl_pos != tc)
558 continue;
559 bc->bl_pos = tc->next;
560 if (NULL == bc->task)
561 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
562 }
563 break;
564
565 case CT_CORE_NO_HANDLERS:
566 break;
567 }
568 GNUNET_free (tc);
569}
570
571
572/**
573 * Function called for each of our connected neighbours. Notify the
574 * client about the existing neighbour.
575 *
576 * @param cls the `struct TransportClient *` to notify
577 * @param peer identity of the neighbour
578 * @param address the address
579 * @param state the current state of the peer
580 * @param state_timeout the time out for the state
581 * @param bandwidth_in inbound bandwidth in NBO
582 * @param bandwidth_out outbound bandwidth in NBO
583 */
584static void
585notify_client_about_neighbour (void *cls,
586 const struct GNUNET_PeerIdentity *peer,
587 const struct GNUNET_HELLO_Address *address,
588 enum GNUNET_TRANSPORT_PeerState state,
589 struct GNUNET_TIME_Absolute state_timeout,
590 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
591 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
592{
593 struct TransportClient *tc = cls;
594 struct ConnectInfoMessage cim;
595
596 if (GNUNET_NO == GST_neighbours_test_connected (peer))
597 return;
598 cim.header.size = htons (sizeof(struct ConnectInfoMessage));
599 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
600 cim.id = *peer;
601 cim.quota_out = bandwidth_out;
602 unicast (tc, &cim.header, GNUNET_NO);
603}
604
605
606/**
607 * Initialize a normal client. We got a start message from this
608 * client, add it to the list of clients for broadcasting of inbound
609 * messages.
610 *
611 * @param cls the client
612 * @param start the start message that was sent
613 */
614static void
615handle_client_start (void *cls, const struct StartMessage *start)
616{
617 struct TransportClient *tc = cls;
618 const struct GNUNET_MessageHeader *hello;
619 uint32_t options;
620
621 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p sent START\n", tc);
622 options = ntohl (start->options);
623 if ((0 != (1 & options)) &&
624 (0 != memcmp (&start->self,
625 &GST_my_identity,
626 sizeof(struct GNUNET_PeerIdentity))))
627 {
628 /* client thinks this is a different peer, reject */
629 GNUNET_break (0);
630 GNUNET_SERVICE_client_drop (tc->client);
631 return;
632 }
633 if (CT_NONE != tc->type)
634 {
635 GNUNET_break (0);
636 GNUNET_SERVICE_client_drop (tc->client);
637 return;
638 }
639 if (0 != (2 & options))
640 tc->type = CT_CORE;
641 else
642 tc->type = CT_CORE_NO_HANDLERS;
643 hello = GST_hello_get ();
644 if (NULL != hello)
645 unicast (tc, hello, GNUNET_NO);
646 GST_neighbours_iterate (&notify_client_about_neighbour, tc);
647 GNUNET_SERVICE_client_continue (tc->client);
648}
649
650
651/**
652 * Client sent us a HELLO. Check the request.
653 *
654 * @param cls the client
655 * @param message the HELLO message
656 */
657static int
658check_client_hello (void *cls, const struct GNUNET_MessageHeader *message)
659{
660 return GNUNET_OK; /* FIXME: check here? */
661}
662
663
664/**
665 * Client sent us a HELLO. Process the request.
666 *
667 * @param cls the client
668 * @param message the HELLO message
669 */
670static void
671handle_client_hello (void *cls, const struct GNUNET_MessageHeader *message)
672{
673 struct TransportClient *tc = cls;
674
675 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Received HELLO message\n");
676 GST_validation_handle_hello (message);
677 GNUNET_SERVICE_client_continue (tc->client);
678}
679
680
681/**
682 * Function called after the transmission is done. Notify the client that it is
683 * OK to send the next message.
684 *
685 * @param cls closure
686 * @param success #GNUNET_OK on success, #GNUNET_NO on failure, #GNUNET_SYSERR if we're not connected
687 * @param bytes_payload bytes payload sent
688 * @param bytes_on_wire bytes sent on wire
689 */
690static void
691handle_send_transmit_continuation (void *cls,
692 int success,
693 size_t bytes_payload,
694 size_t bytes_on_wire)
695{
696 struct SendTransmitContinuationContext *stcc = cls;
697 struct SendOkMessage send_ok_msg;
698#ifdef ENABLE_TTD
699 struct GNUNET_TIME_Relative delay;
700 const struct GNUNET_HELLO_Address *addr;
701
702 delay = GNUNET_TIME_absolute_get_duration (stcc->send_time);
703 addr = GST_neighbour_get_current_address (&stcc->target);
704
705 if (delay.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
706 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
707 "It took us %s to send %u/%u bytes to %s (%d, %s)\n",
708 GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES),
709 (unsigned int) bytes_payload,
710 (unsigned int) bytes_on_wire,
711 GNUNET_i2s (&stcc->target),
712 success,
713 (NULL != addr) ? addr->transport_name : "%");
714 else
715 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
716 "It took us %s to send %u/%u bytes to %s (%d, %s)\n",
717 GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES),
718 (unsigned int) bytes_payload,
719 (unsigned int) bytes_on_wire,
720 GNUNET_i2s (&stcc->target),
721 success,
722 (NULL != addr) ? addr->transport_name : "%");
723#endif
724
725 if (GNUNET_NO == stcc->down)
726 {
727 /* Only send confirmation if we are still connected */
728 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
729 "Sending SEND_OK for transmission request %llu\n",
730 stcc->uuid);
731 send_ok_msg.header.size = htons (sizeof(send_ok_msg));
732 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
733 send_ok_msg.bytes_msg = htons (bytes_payload);
734 send_ok_msg.bytes_physical = htonl (bytes_on_wire);
735 send_ok_msg.success = htons (success);
736 send_ok_msg.peer = stcc->target;
737 unicast (stcc->tc, &send_ok_msg.header, GNUNET_NO);
738 }
739 GNUNET_assert (
740 GNUNET_OK ==
741 GNUNET_CONTAINER_multipeermap_remove (active_stccs, &stcc->target, stcc));
742 GNUNET_free (stcc);
743}
744
745
746/**
747 * Client asked for transmission to a peer. Process the request.
748 *
749 * @param cls the client
750 * @param obm the send message that was sent
751 */
752static int
753check_client_send (void *cls, const struct OutboundMessage *obm)
754{
755 uint16_t size;
756 const struct GNUNET_MessageHeader *obmm;
757
758 size = ntohs (obm->header.size) - sizeof(struct OutboundMessage);
759 if (size < sizeof(struct GNUNET_MessageHeader))
760 {
761 GNUNET_break (0);
762 return GNUNET_SYSERR;
763 }
764 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
765 if (size != ntohs (obmm->size))
766 {
767 GNUNET_break (0);
768 return GNUNET_SYSERR;
769 }
770 return GNUNET_OK;
771}
772
773
774/**
775 * Client asked for transmission to a peer. Process the request.
776 *
777 * @param cls the client
778 * @param obm the send message that was sent
779 */
780static void
781handle_client_send (void *cls, const struct OutboundMessage *obm)
782{
783 static unsigned long long uuid_gen;
784 struct TransportClient *tc = cls;
785 const struct GNUNET_MessageHeader *obmm;
786 struct SendTransmitContinuationContext *stcc;
787
788 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
789 if (GNUNET_NO == GST_neighbours_test_connected (&obm->peer))
790 {
791 /* not connected, not allowed to send; can happen due to asynchronous operations */
792 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
793 "Could not send message to peer `%s': not connected\n",
794 GNUNET_i2s (&obm->peer));
795 GNUNET_STATISTICS_update (
796 GST_stats,
797 gettext_noop ("# bytes payload dropped (other peer was not connected)"),
798 ntohs (obmm->size),
799 GNUNET_NO);
800 GNUNET_SERVICE_client_continue (tc->client);
801 return;
802 }
803 GNUNET_log (
804 GNUNET_ERROR_TYPE_DEBUG,
805 "Received SEND request %llu for `%s' and first message of type %u and total size %u\n",
806 uuid_gen,
807 GNUNET_i2s (&obm->peer),
808 ntohs (obmm->type),
809 ntohs (obmm->size));
810 GNUNET_SERVICE_client_continue (tc->client);
811
812 stcc = GNUNET_new (struct SendTransmitContinuationContext);
813 stcc->target = obm->peer;
814 stcc->tc = tc;
815 stcc->send_time = GNUNET_TIME_absolute_get ();
816 stcc->uuid = uuid_gen++;
817 (void) GNUNET_CONTAINER_multipeermap_put (
818 active_stccs,
819 &stcc->target,
820 stcc,
821 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
822 GST_manipulation_send (&obm->peer,
823 obmm,
824 ntohs (obmm->size),
825 GNUNET_TIME_relative_ntoh (obm->timeout),
826 &handle_send_transmit_continuation,
827 stcc);
828}
829
830
831/**
832 * Take the given address and append it to the set of results sent back to
833 * the client. This function may be called several times for a single
834 * conversion. The last invocation will be with a @a address of
835 * NULL and a @a res of #GNUNET_OK. Thus, to indicate conversion
836 * errors, the callback might be called first with @a address NULL and
837 * @a res being #GNUNET_SYSERR. In that case, there will still be a
838 * subsequent call later with @a address NULL and @a res #GNUNET_OK.
839 *
840 * @param cls the `struct AddressToStringContext`
841 * @param buf text to transmit (contains the human-readable address, or NULL)
842 * @param res #GNUNET_OK if conversion was successful, #GNUNET_SYSERR on error,
843 * never #GNUNET_NO
844 */
845static void
846transmit_address_to_client (void *cls, const char *buf, int res)
847{
848 struct AddressToStringContext *actx = cls;
849 struct GNUNET_MQ_Envelope *env;
850 struct AddressToStringResultMessage *atsm;
851 size_t slen;
852
853 GNUNET_assert ((GNUNET_OK == res) || (GNUNET_SYSERR == res));
854 if (NULL == actx->tc)
855 return;
856 if (NULL == buf)
857 {
858 env = GNUNET_MQ_msg (atsm,
859 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY);
860 if (GNUNET_OK == res)
861 {
862 /* this was the last call, transmit */
863 atsm->res = htonl (GNUNET_OK);
864 atsm->addr_len = htonl (0);
865 GNUNET_MQ_send (actx->tc->mq, env);
866 GNUNET_CONTAINER_DLL_remove (a2s_head, a2s_tail, actx);
867 GNUNET_free (actx);
868 return;
869 }
870 if (GNUNET_SYSERR == res)
871 {
872 /* address conversion failed, but there will be more callbacks */
873 atsm->res = htonl (GNUNET_SYSERR);
874 atsm->addr_len = htonl (0);
875 GNUNET_MQ_send (actx->tc->mq, env);
876 return;
877 }
878 }
879 GNUNET_assert (GNUNET_OK == res);
880 /* successful conversion, append*/
881 slen = strlen (buf) + 1;
882 env =
883 GNUNET_MQ_msg_extra (atsm,
884 slen,
885 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY);
886 atsm->res = htonl (GNUNET_YES);
887 atsm->addr_len = htonl (slen);
888 GNUNET_memcpy (&atsm[1], buf, slen);
889 GNUNET_MQ_send (actx->tc->mq, env);
890}
891
892
893/**
894 * Client asked to resolve an address. Check the request.
895 *
896 * @param cls the client
897 * @param alum the resolution request
898 * @return #GNUNET_OK if @a alum is well-formed
899 */
900static int
901check_client_address_to_string (void *cls,
902 const struct AddressLookupMessage *alum)
903{
904 const char *plugin_name;
905 const char *address;
906 uint32_t address_len;
907 uint16_t size;
908
909 size = ntohs (alum->header.size);
910 address_len = ntohs (alum->addrlen);
911 if (size <= sizeof(struct AddressLookupMessage) + address_len)
912 {
913 GNUNET_break (0);
914 return GNUNET_SYSERR;
915 }
916 address = (const char *) &alum[1];
917 plugin_name = (const char *) &address[address_len];
918 if ('\0' != plugin_name[size - sizeof(struct AddressLookupMessage)
919 - address_len - 1])
920 {
921 GNUNET_break (0);
922 return GNUNET_SYSERR;
923 }
924 return GNUNET_OK;
925}
926
927
928/**
929 * Client asked to resolve an address. Process the request.
930 *
931 * @param cls the client
932 * @param alum the resolution request
933 */
934static void
935handle_client_address_to_string (void *cls,
936 const struct AddressLookupMessage *alum)
937{
938 struct TransportClient *tc = cls;
939 struct GNUNET_TRANSPORT_PluginFunctions *papi;
940 const char *plugin_name;
941 const char *address;
942 uint32_t address_len;
943 struct AddressToStringContext *actx;
944 struct GNUNET_MQ_Envelope *env;
945 struct AddressToStringResultMessage *atsm;
946 struct GNUNET_TIME_Relative rtimeout;
947 int32_t numeric;
948
949 address_len = ntohs (alum->addrlen);
950 address = (const char *) &alum[1];
951 plugin_name = (const char *) &address[address_len];
952 rtimeout = GNUNET_TIME_relative_ntoh (alum->timeout);
953 numeric = ntohs (alum->numeric_only);
954 papi = GST_plugins_printer_find (plugin_name);
955 if (NULL == papi)
956 {
957 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
958 "Failed to find plugin `%s'\n",
959 plugin_name);
960 env = GNUNET_MQ_msg (atsm,
961 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY);
962 atsm->res = htonl (GNUNET_SYSERR);
963 atsm->addr_len = htonl (0);
964 GNUNET_MQ_send (tc->mq, env);
965 env = GNUNET_MQ_msg (atsm,
966 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY);
967 atsm->res = htonl (GNUNET_OK);
968 atsm->addr_len = htonl (0);
969 GNUNET_MQ_send (tc->mq, env);
970 return;
971 }
972 actx = GNUNET_new (struct AddressToStringContext);
973 actx->tc = tc;
974 GNUNET_CONTAINER_DLL_insert (a2s_head, a2s_tail, actx);
975 GNUNET_SERVICE_client_disable_continue_warning (tc->client);
976 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
977 "Pretty-printing address of %u bytes using plugin `%s'\n",
978 address_len,
979 plugin_name);
980 papi->address_pretty_printer (papi->cls,
981 plugin_name,
982 address,
983 address_len,
984 numeric,
985 rtimeout,
986 &transmit_address_to_client,
987 actx);
988}
989
990
991/**
992 * Compose #PeerIterateResponseMessage using the given peer and address.
993 *
994 * @param peer identity of the peer
995 * @param address the address, NULL on disconnect
996 * @return composed message
997 */
998static struct PeerIterateResponseMessage *
999compose_address_iterate_response_message (
1000 const struct GNUNET_PeerIdentity *peer,
1001 const struct GNUNET_HELLO_Address *address)
1002{
1003 struct PeerIterateResponseMessage *msg;
1004 size_t size;
1005 size_t tlen;
1006 size_t alen;
1007 char *addr;
1008
1009 GNUNET_assert (NULL != peer);
1010 if (NULL != address)
1011 {
1012 tlen = strlen (address->transport_name) + 1;
1013 alen = address->address_length;
1014 }
1015 else
1016 {
1017 tlen = 0;
1018 alen = 0;
1019 }
1020 size = (sizeof(struct PeerIterateResponseMessage) + alen + tlen);
1021 msg = GNUNET_malloc (size);
1022 msg->header.size = htons (size);
1023 msg->header.type =
1024 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_RESPONSE);
1025 msg->reserved = htonl (0);
1026 msg->peer = *peer;
1027 msg->addrlen = htonl (alen);
1028 msg->pluginlen = htonl (tlen);
1029
1030 if (NULL != address)
1031 {
1032 msg->local_address_info = htonl ((uint32_t) address->local_info);
1033 addr = (char *) &msg[1];
1034 GNUNET_memcpy (addr, address->address, alen);
1035 GNUNET_memcpy (&addr[alen], address->transport_name, tlen);
1036 }
1037 return msg;
1038}
1039
1040
1041/**
1042 * Context for #send_validation_information() and
1043 * #send_peer_information().
1044 */
1045struct IterationContext
1046{
1047 /**
1048 * Context to use for the transmission.
1049 */
1050 struct TransportClient *tc;
1051
1052 /**
1053 * Which peers do we care about?
1054 */
1055 struct GNUNET_PeerIdentity id;
1056
1057 /**
1058 * #GNUNET_YES if @e id should be ignored because we want all peers.
1059 */
1060 int all;
1061};
1062
1063
1064/**
1065 * Output information of neighbours to the given client.
1066 *
1067 * @param cls the `struct PeerIterationContext *`
1068 * @param peer identity of the neighbour
1069 * @param address the address
1070 * @param state current state this peer is in
1071 * @param state_timeout timeout for the current state of the peer
1072 * @param bandwidth_in inbound quota in NBO
1073 * @param bandwidth_out outbound quota in NBO
1074 */
1075static void
1076send_peer_information (void *cls,
1077 const struct GNUNET_PeerIdentity *peer,
1078 const struct GNUNET_HELLO_Address *address,
1079 enum GNUNET_TRANSPORT_PeerState state,
1080 struct GNUNET_TIME_Absolute state_timeout,
1081 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
1082 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
1083{
1084 struct IterationContext *pc = cls;
1085 struct GNUNET_MQ_Envelope *env;
1086 struct PeerIterateResponseMessage *msg;
1087
1088 if ((GNUNET_YES != pc->all) && (0 != memcmp (peer, &pc->id, sizeof(pc->id))))
1089 return;
1090 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1091 "Sending information about `%s' using address `%s' in state `%s'\n",
1092 GNUNET_i2s (peer),
1093 (NULL != address) ? GST_plugins_a2s (address) : "<none>",
1094 GNUNET_TRANSPORT_ps2s (state));
1095 msg = compose_address_iterate_response_message (peer, address);
1096 msg->state = htonl (state);
1097 msg->state_timeout = GNUNET_TIME_absolute_hton (state_timeout);
1098 env = GNUNET_MQ_msg_copy (&msg->header);
1099 GNUNET_free (msg);
1100 GNUNET_MQ_send (pc->tc->mq, env);
1101}
1102
1103
1104/**
1105 * Client asked to obtain information about a specific or all peers
1106 * Process the request.
1107 *
1108 * @param cls the client
1109 * @param msg the peer address information request
1110 */
1111static void
1112handle_client_monitor_peers (void *cls, const struct PeerMonitorMessage *msg)
1113{
1114 struct TransportClient *tc = cls;
1115 struct IterationContext pc;
1116
1117 if (CT_NONE != tc->type)
1118 {
1119 GNUNET_break (0);
1120 GNUNET_SERVICE_client_drop (tc->client);
1121 return;
1122 }
1123 GNUNET_SERVICE_client_disable_continue_warning (tc->client);
1124 GNUNET_SERVICE_client_mark_monitor (tc->client);
1125
1126 /* Send initial list */
1127 pc.tc = tc;
1128 if (0 == memcmp (&msg->peer, &all_zeros, sizeof(struct GNUNET_PeerIdentity)))
1129 {
1130 /* iterate over all neighbours */
1131 pc.all = GNUNET_YES;
1132 pc.id = msg->peer;
1133 }
1134 else
1135 {
1136 /* just return one neighbour */
1137 pc.all = GNUNET_NO;
1138 pc.id = msg->peer;
1139 }
1140 GST_neighbours_iterate (&send_peer_information, &pc);
1141
1142 if (GNUNET_YES != ntohl (msg->one_shot))
1143 {
1144 tc->details.monitor_peer = msg->peer;
1145 tc->type = CT_MONITOR;
1146 if (0 !=
1147 memcmp (&msg->peer, &all_zeros, sizeof(struct GNUNET_PeerIdentity)))
1148 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1149 "Client %p started monitoring of the peer `%s'\n",
1150 tc,
1151 GNUNET_i2s (&msg->peer));
1152 else
1153 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1154 "Client %p started monitoring all peers\n",
1155 tc);
1156 }
1157 else
1158 {
1159 struct GNUNET_MessageHeader *msg;
1160 struct GNUNET_MQ_Envelope *env;
1161
1162 env =
1163 GNUNET_MQ_msg (msg,
1164 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_RESPONSE_END);
1165 GNUNET_MQ_send (tc->mq, env);
1166 }
1167}
1168
1169
1170/**
1171 * Function called by the plugin with information about the
1172 * current sessions managed by the plugin (for monitoring).
1173 *
1174 * @param cls closure
1175 * @param session session handle this information is about,
1176 * NULL to indicate that we are "in sync" (initial
1177 * iteration complete)
1178 * @param info information about the state of the session,
1179 * NULL if @a session is also NULL and we are
1180 * merely signalling that the initial iteration is over
1181 */
1182static void
1183plugin_session_info_cb (void *cls,
1184 struct GNUNET_ATS_Session *session,
1185 const struct GNUNET_TRANSPORT_SessionInfo *info)
1186{
1187 struct GNUNET_MQ_Envelope *env;
1188 struct TransportPluginMonitorMessage *msg;
1189 struct GNUNET_MessageHeader *sync;
1190 size_t size;
1191 size_t slen;
1192 uint16_t alen;
1193 char *name;
1194 char *addr;
1195
1196 if (0 == GNUNET_notification_context_get_size (plugin_nc))
1197 {
1198 GST_plugins_monitor_subscribe (NULL, NULL);
1199 return;
1200 }
1201 if ((NULL == info) && (NULL == session))
1202 {
1203 /* end of initial iteration */
1204 if (NULL != sync_client)
1205 {
1206 env =
1207 GNUNET_MQ_msg (sync, GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PLUGIN_SYNC);
1208 GNUNET_MQ_send (sync_client->mq, env);
1209 sync_client = NULL;
1210 }
1211 return;
1212 }
1213 GNUNET_assert (NULL != info);
1214 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1215 "Plugin event for peer %s on transport %s\n",
1216 GNUNET_i2s (&info->address->peer),
1217 info->address->transport_name);
1218 slen = strlen (info->address->transport_name) + 1;
1219 alen = info->address->address_length;
1220 size = sizeof(struct TransportPluginMonitorMessage) + slen + alen;
1221 if (size > UINT16_MAX)
1222 {
1223 GNUNET_break (0);
1224 return;
1225 }
1226 msg = GNUNET_malloc (size);
1227 msg->header.size = htons (size);
1228 msg->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PLUGIN_EVENT);
1229 msg->session_state = htons ((uint16_t) info->state);
1230 msg->is_inbound = htons ((int16_t) info->is_inbound);
1231 msg->msgs_pending = htonl (info->num_msg_pending);
1232 msg->bytes_pending = htonl (info->num_bytes_pending);
1233 msg->timeout = GNUNET_TIME_absolute_hton (info->session_timeout);
1234 msg->delay = GNUNET_TIME_absolute_hton (info->receive_delay);
1235 msg->peer = info->address->peer;
1236 msg->session_id = (uint64_t) (intptr_t) session;
1237 msg->plugin_name_len = htons (slen);
1238 msg->plugin_address_len = htons (alen);
1239 name = (char *) &msg[1];
1240 GNUNET_memcpy (name, info->address->transport_name, slen);
1241 addr = &name[slen];
1242 GNUNET_memcpy (addr, info->address->address, alen);
1243 if (NULL != sync_client)
1244 {
1245 struct GNUNET_MQ_Envelope *env;
1246
1247 env = GNUNET_MQ_msg_copy (&msg->header);
1248 GNUNET_MQ_send (sync_client->mq, env);
1249 }
1250 else
1251 {
1252 GNUNET_notification_context_broadcast (plugin_nc, &msg->header, GNUNET_NO);
1253 }
1254 GNUNET_free (msg);
1255}
1256
1257
1258/**
1259 * Client asked to obtain information about all plugin connections.
1260 *
1261 * @param cls the client
1262 * @param message the peer address information request
1263 */
1264static void
1265handle_client_monitor_plugins (void *cls,
1266 const struct GNUNET_MessageHeader *message)
1267{
1268 struct TransportClient *tc = cls;
1269
1270 GNUNET_SERVICE_client_mark_monitor (tc->client);
1271 GNUNET_SERVICE_client_disable_continue_warning (tc->client);
1272 GNUNET_notification_context_add (plugin_nc, tc->mq);
1273 GNUNET_assert (NULL == sync_client);
1274 sync_client = tc;
1275 GST_plugins_monitor_subscribe (&plugin_session_info_cb, NULL);
1276}
1277
1278
1279/**
1280 * Broadcast the given message to all of our clients.
1281 *
1282 * @param msg message to broadcast
1283 * @param may_drop #GNUNET_YES if the message can be dropped / is payload
1284 */
1285void
1286GST_clients_broadcast (const struct GNUNET_MessageHeader *msg, int may_drop)
1287{
1288 int done;
1289
1290 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1291 "Asked to broadcast message of type %u with %u bytes\n",
1292 (unsigned int) ntohs (msg->type),
1293 (unsigned int) ntohs (msg->size));
1294 done = GNUNET_NO;
1295 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
1296 {
1297 if (CT_NONE == tc->type)
1298 continue; /* client not yet ready */
1299 if ((GNUNET_YES == may_drop) && (CT_CORE != tc->type))
1300 continue; /* skip, this client does not care about payload */
1301 unicast (tc, msg, may_drop);
1302 done = GNUNET_YES;
1303 }
1304 if (GNUNET_NO == done)
1305 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1306 "Message of type %u not delivered, is CORE service up?\n",
1307 ntohs (msg->type));
1308}
1309
1310
1311/**
1312 * Broadcast the new active address to all clients monitoring the peer.
1313 *
1314 * @param peer peer this update is about (never NULL)
1315 * @param address address, NULL on disconnect
1316 * @param state the current state of the peer
1317 * @param state_timeout the time out for the state
1318 */
1319void
1320GST_clients_broadcast_peer_notification (
1321 const struct GNUNET_PeerIdentity *peer,
1322 const struct GNUNET_HELLO_Address *address,
1323 enum GNUNET_TRANSPORT_PeerState state,
1324 struct GNUNET_TIME_Absolute state_timeout)
1325{
1326 struct GNUNET_MQ_Envelope *env;
1327 struct PeerIterateResponseMessage *msg;
1328
1329 msg = compose_address_iterate_response_message (peer, address);
1330 msg->state = htonl (state);
1331 msg->state_timeout = GNUNET_TIME_absolute_hton (state_timeout);
1332 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
1333 {
1334 if (CT_MONITOR != tc->type)
1335 continue;
1336 if ((0 == memcmp (&tc->details.monitor_peer,
1337 &all_zeros,
1338 sizeof(struct GNUNET_PeerIdentity))) ||
1339 (0 == memcmp (&tc->details.monitor_peer,
1340 peer,
1341 sizeof(struct GNUNET_PeerIdentity))))
1342 {
1343 env = GNUNET_MQ_msg_copy (&msg->header);
1344 GNUNET_MQ_send (tc->mq, env);
1345 }
1346 }
1347 GNUNET_free (msg);
1348}
1349
1350
1351/**
1352 * Mark the peer as down so we don't call the continuation
1353 * context in the future.
1354 *
1355 * @param cls NULL
1356 * @param peer peer that got disconnected
1357 * @param value a `struct SendTransmitContinuationContext` to mark
1358 * @return #GNUNET_OK (continue to iterate)
1359 */
1360static int
1361mark_peer_down (void *cls, const struct GNUNET_PeerIdentity *peer, void *value)
1362{
1363 struct SendTransmitContinuationContext *stcc = value;
1364
1365 stcc->down = GNUNET_YES;
1366 return GNUNET_OK;
1367}
1368
1369
1370/**
1371 * Notify all clients about a disconnect, and cancel
1372 * pending SEND_OK messages for this peer.
1373 *
1374 * @param peer peer that disconnected
1375 */
1376void
1377GST_clients_broadcast_disconnect (const struct GNUNET_PeerIdentity *peer)
1378{
1379 struct DisconnectInfoMessage disconnect_msg;
1380
1381 GNUNET_CONTAINER_multipeermap_get_multiple (active_stccs,
1382 peer,
1383 &mark_peer_down,
1384 NULL);
1385 disconnect_msg.header.size = htons (sizeof(struct DisconnectInfoMessage));
1386 disconnect_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
1387 disconnect_msg.reserved = htonl (0);
1388 disconnect_msg.peer = *peer;
1389 GST_clients_broadcast (&disconnect_msg.header, GNUNET_NO);
1390}
1391
1392
1393/**
1394 * Transmit our HELLO message to the given (connected) neighbour.
1395 *
1396 * @param cls the 'HELLO' message
1397 * @param peer identity of the peer
1398 * @param address the address
1399 * @param state current state this peer is in
1400 * @param state_timeout timeout for the current state of the peer
1401 * @param bandwidth_in inbound quota in NBO
1402 * @param bandwidth_out outbound quota in NBO
1403 */
1404static void
1405transmit_our_hello (void *cls,
1406 const struct GNUNET_PeerIdentity *peer,
1407 const struct GNUNET_HELLO_Address *address,
1408 enum GNUNET_TRANSPORT_PeerState state,
1409 struct GNUNET_TIME_Absolute state_timeout,
1410 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
1411 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
1412{
1413 const struct GNUNET_MessageHeader *hello = cls;
1414
1415 if (0 == memcmp (peer, &GST_my_identity, sizeof(struct GNUNET_PeerIdentity)))
1416 return; /* not to ourselves */
1417 if (GNUNET_NO == GST_neighbours_test_connected (peer))
1418 return;
1419
1420 GST_neighbours_send (peer,
1421 hello,
1422 ntohs (hello->size),
1423 hello_expiration,
1424 NULL,
1425 NULL);
1426}
1427
1428
1429/**
1430 * My HELLO has changed. Tell everyone who should know.
1431 *
1432 * @param cls unused
1433 * @param hello new HELLO
1434 */
1435static void
1436process_hello_update (void *cls, const struct GNUNET_MessageHeader *hello)
1437{
1438 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Broadcasting HELLO to clients\n");
1439 GST_clients_broadcast (hello, GNUNET_NO);
1440 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Broadcasting HELLO to neighbours\n");
1441 GST_neighbours_iterate (&transmit_our_hello, (void *) hello);
1442}
1443
1444
1445/**
1446 * We received some payload. Prepare to pass it on to our clients.
1447 *
1448 * @param address address and (claimed) identity of the other peer
1449 * @param session identifier used for this session (NULL for plugins
1450 * that do not offer bi-directional communication to the sender
1451 * using the same "connection")
1452 * @param message the message to process
1453 * @return how long the plugin should wait until receiving more data
1454 */
1455static struct GNUNET_TIME_Relative
1456process_payload (const struct GNUNET_HELLO_Address *address,
1457 struct GNUNET_ATS_Session *session,
1458 const struct GNUNET_MessageHeader *message)
1459{
1460 struct GNUNET_TIME_Relative ret;
1461 int do_forward;
1462 struct InboundMessage *im;
1463 size_t msg_size = ntohs (message->size);
1464 size_t size = sizeof(struct InboundMessage) + msg_size;
1465 char buf[size] GNUNET_ALIGN;
1466
1467 do_forward = GNUNET_SYSERR;
1468 ret = GST_neighbours_calculate_receive_delay (&address->peer,
1469 msg_size,
1470 &do_forward);
1471 if (! GST_neighbours_test_connected (&address->peer))
1472 {
1473 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1474 "Discarded %u bytes type %u payload from peer `%s'\n",
1475 (unsigned int) msg_size,
1476 ntohs (message->type),
1477 GNUNET_i2s (&address->peer));
1478 GNUNET_STATISTICS_update (
1479 GST_stats,
1480 gettext_noop ("# bytes payload discarded due to not connected peer"),
1481 msg_size,
1482 GNUNET_NO);
1483 return ret;
1484 }
1485
1486 if (GNUNET_YES != do_forward)
1487 return ret;
1488 im = (struct InboundMessage *) buf;
1489 im->header.size = htons (size);
1490 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
1491 im->peer = address->peer;
1492 GNUNET_memcpy (&im[1], message, ntohs (message->size));
1493 GST_clients_broadcast (&im->header, GNUNET_YES);
1494 return ret;
1495}
1496
1497
1498/**
1499 * Task to asynchronously terminate a session.
1500 *
1501 * @param cls the `struct GNUNET_ATS_SessionKiller` with the information for the kill
1502 */
1503static void
1504kill_session_task (void *cls)
1505{
1506 struct GNUNET_ATS_SessionKiller *sk = cls;
1507
1508 sk->task = NULL;
1509 GNUNET_CONTAINER_DLL_remove (sk_head, sk_tail, sk);
1510 sk->plugin->disconnect_session (sk->plugin->cls, sk->session);
1511 GNUNET_free (sk);
1512}
1513
1514
1515/**
1516 * Force plugin to terminate session due to communication
1517 * issue.
1518 *
1519 * @param plugin_name name of the plugin
1520 * @param session session to termiante
1521 */
1522static void
1523kill_session (const char *plugin_name, struct GNUNET_ATS_Session *session)
1524{
1525 struct GNUNET_TRANSPORT_PluginFunctions *plugin;
1526 struct GNUNET_ATS_SessionKiller *sk;
1527
1528 for (sk = sk_head; NULL != sk; sk = sk->next)
1529 if (sk->session == session)
1530 return;
1531 plugin = GST_plugins_find (plugin_name);
1532 if (NULL == plugin)
1533 {
1534 GNUNET_break (0);
1535 return;
1536 }
1537 /* need to issue disconnect asynchronously */
1538 sk = GNUNET_new (struct GNUNET_ATS_SessionKiller);
1539 sk->session = session;
1540 sk->plugin = plugin;
1541 sk->task = GNUNET_SCHEDULER_add_now (&kill_session_task, sk);
1542 GNUNET_CONTAINER_DLL_insert (sk_head, sk_tail, sk);
1543}
1544
1545
1546/**
1547 * Black list check result for try_connect call
1548 * If connection to the peer is allowed request address and ???
1549 *
1550 * @param cls the message
1551 * @param peer the peer
1552 * @param address the address
1553 * @param session the session
1554 * @param result the result
1555 */
1556static void
1557connect_bl_check_cont (void *cls,
1558 const struct GNUNET_PeerIdentity *peer,
1559 const struct GNUNET_HELLO_Address *address,
1560 struct GNUNET_ATS_Session *session,
1561 int result)
1562{
1563 struct GNUNET_MessageHeader *msg = cls;
1564
1565 if (GNUNET_OK == result)
1566 {
1567 /* Blacklist allows to speak to this peer, forward SYN to neighbours */
1568 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1569 "Received SYN message from peer `%s' at `%s'\n",
1570 GNUNET_i2s (peer),
1571 GST_plugins_a2s (address));
1572 if (GNUNET_OK != GST_neighbours_handle_session_syn (msg, peer))
1573 {
1574 GST_blacklist_abort_matching (address, session);
1575 kill_session (address->transport_name, session);
1576 }
1577 GNUNET_free (msg);
1578 return;
1579 }
1580 GNUNET_free (msg);
1581 if (GNUNET_SYSERR == result)
1582 return; /* check was aborted, session destroyed */
1583 /* Blacklist denies to speak to this peer */
1584 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1585 "Discarding SYN message from `%s' due to denied blacklist check\n",
1586 GNUNET_i2s (peer));
1587 kill_session (address->transport_name, session);
1588}
1589
1590
1591/**
1592 * Function called by the transport for each received message.
1593 *
1594 * @param cls closure, const char* with the name of the plugin we received the message from
1595 * @param address address and (claimed) identity of the other peer
1596 * @param message the message, NULL if we only care about
1597 * learning about the delay until we should receive again
1598 * @param session identifier used for this session (NULL for plugins
1599 * that do not offer bi-directional communication to the sender
1600 * using the same "connection")
1601 * @return how long the plugin should wait until receiving more data
1602 * (plugins that do not support this, can ignore the return value)
1603 */
1604struct GNUNET_TIME_Relative
1605GST_receive_callback (void *cls,
1606 const struct GNUNET_HELLO_Address *address,
1607 struct GNUNET_ATS_Session *session,
1608 const struct GNUNET_MessageHeader *message)
1609{
1610 const char *plugin_name = cls;
1611 struct GNUNET_TIME_Relative ret;
1612 uint16_t type;
1613
1614 ret = GNUNET_TIME_UNIT_ZERO;
1615 if (NULL == message)
1616 goto end;
1617 type = ntohs (message->type);
1618 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1619 "Received message with type %u from peer `%s' at %s\n",
1620 type,
1621 GNUNET_i2s (&address->peer),
1622 GST_plugins_a2s (address));
1623
1624 GNUNET_STATISTICS_update (GST_stats,
1625 gettext_noop ("# bytes total received"),
1626 ntohs (message->size),
1627 GNUNET_NO);
1628 GST_neighbours_notify_data_recv (address, message);
1629 switch (type)
1630 {
1631 case GNUNET_MESSAGE_TYPE_HELLO_URI:
1632 /* Future HELLO message, discard */
1633 return ret;
1634
1635 case GNUNET_MESSAGE_TYPE_HELLO:
1636 if (GNUNET_OK != GST_validation_handle_hello (message))
1637 {
1638 GNUNET_break_op (0);
1639 GST_blacklist_abort_matching (address, session);
1640 }
1641 return ret;
1642
1643 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
1644 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1645 "Processing PING from `%s'\n",
1646 GST_plugins_a2s (address));
1647 if (GNUNET_OK !=
1648 GST_validation_handle_ping (&address->peer, message, address, session))
1649 {
1650 GST_blacklist_abort_matching (address, session);
1651 kill_session (plugin_name, session);
1652 }
1653 break;
1654
1655 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
1656 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1657 "Processing PONG from `%s'\n",
1658 GST_plugins_a2s (address));
1659 if (GNUNET_OK != GST_validation_handle_pong (&address->peer, message))
1660 {
1661 GNUNET_break_op (0);
1662 GST_blacklist_abort_matching (address, session);
1663 kill_session (plugin_name, session);
1664 }
1665 break;
1666
1667 case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_SYN:
1668 /* Do blacklist check if communication with this peer is allowed */
1669 (void) GST_blacklist_test_allowed (&address->peer,
1670 NULL,
1671 &connect_bl_check_cont,
1672 GNUNET_copy_message (message),
1673 address,
1674 session);
1675 break;
1676
1677 case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_SYN_ACK:
1678 if (GNUNET_OK !=
1679 GST_neighbours_handle_session_syn_ack (message, address, session))
1680 {
1681 GST_blacklist_abort_matching (address, session);
1682 kill_session (plugin_name, session);
1683 }
1684 break;
1685
1686 case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_ACK:
1687 if (GNUNET_OK !=
1688 GST_neighbours_handle_session_ack (message, address, session))
1689 {
1690 GNUNET_break_op (0);
1691 GST_blacklist_abort_matching (address, session);
1692 kill_session (plugin_name, session);
1693 }
1694 break;
1695
1696 case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT:
1697 GST_neighbours_handle_disconnect_message (&address->peer, message);
1698 break;
1699
1700 case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_QUOTA:
1701 GST_neighbours_handle_quota_message (&address->peer, message);
1702 break;
1703
1704 case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE:
1705 GST_neighbours_keepalive (&address->peer, message);
1706 break;
1707
1708 case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE_RESPONSE:
1709 GST_neighbours_keepalive_response (&address->peer, message);
1710 break;
1711
1712 default:
1713 /* should be payload */
1714 GNUNET_STATISTICS_update (GST_stats,
1715 gettext_noop ("# bytes payload received"),
1716 ntohs (message->size),
1717 GNUNET_NO);
1718 ret = process_payload (address, session, message);
1719 break;
1720 }
1721end:
1722 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1723 "Allowing receive from peer %s to continue in %s\n",
1724 GNUNET_i2s (&address->peer),
1725 GNUNET_STRINGS_relative_time_to_string (ret, GNUNET_YES));
1726 return ret;
1727}
1728
1729
1730/**
1731 * Function that will be called for each address the transport
1732 * is aware that it might be reachable under. Update our HELLO.
1733 *
1734 * @param cls name of the plugin (const char*)
1735 * @param add_remove should the address added (YES) or removed (NO) from the
1736 * set of valid addresses?
1737 * @param address the address to add or remove
1738 */
1739static void
1740plugin_env_address_change_notification (
1741 void *cls,
1742 int add_remove,
1743 const struct GNUNET_HELLO_Address *address)
1744{
1745 static int addresses = 0;
1746
1747 if (GNUNET_YES == add_remove)
1748 {
1749 addresses++;
1750 GNUNET_STATISTICS_update (GST_stats, "# transport addresses", 1, GNUNET_NO);
1751 }
1752 else if (GNUNET_NO == add_remove)
1753 {
1754 if (0 == addresses)
1755 {
1756 GNUNET_break (0);
1757 }
1758 else
1759 {
1760 addresses--;
1761 GNUNET_STATISTICS_update (GST_stats,
1762 "# transport addresses",
1763 -1,
1764 GNUNET_NO);
1765 }
1766 }
1767 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1768 "Transport now has %u addresses to communicate\n",
1769 addresses);
1770 GST_hello_modify_addresses (add_remove, address);
1771}
1772
1773
1774/**
1775 * Function that will be called whenever the plugin internally
1776 * cleans up a session pointer and hence the service needs to
1777 * discard all of those sessions as well. Plugins that do not
1778 * use sessions can simply omit calling this function and always
1779 * use NULL wherever a session pointer is needed. This function
1780 * should be called BEFORE a potential "TransmitContinuation"
1781 * from the "TransmitFunction".
1782 *
1783 * @param cls closure
1784 * @param address which address was the session for
1785 * @param session which session is being destroyed
1786 */
1787static void
1788plugin_env_session_end (void *cls,
1789 const struct GNUNET_HELLO_Address *address,
1790 struct GNUNET_ATS_Session *session)
1791{
1792 struct GNUNET_ATS_SessionKiller *sk;
1793
1794 if (NULL == address)
1795 {
1796 GNUNET_break (0);
1797 return;
1798 }
1799 if (NULL == session)
1800 {
1801 GNUNET_break (0);
1802 return;
1803 }
1804 GNUNET_assert (strlen (address->transport_name) > 0);
1805
1806 GNUNET_log (
1807 GNUNET_ERROR_TYPE_DEBUG,
1808 "Notification from plugin about terminated session %p from peer `%s' address `%s'\n",
1809 session,
1810 GNUNET_i2s (&address->peer),
1811 GST_plugins_a2s (address));
1812
1813 GST_neighbours_session_terminated (&address->peer, session);
1814 GST_ats_del_session (address, session);
1815 GST_blacklist_abort_matching (address, session);
1816
1817 for (sk = sk_head; NULL != sk; sk = sk->next)
1818 {
1819 if (sk->session == session)
1820 {
1821 GNUNET_CONTAINER_DLL_remove (sk_head, sk_tail, sk);
1822 GNUNET_SCHEDULER_cancel (sk->task);
1823 GNUNET_free (sk);
1824 break;
1825 }
1826 }
1827}
1828
1829
1830/**
1831 * Black list check result from blacklist check triggered when a
1832 * plugin gave us a new session in #plugin_env_session_start(). If
1833 * connection to the peer is disallowed, kill the session.
1834 *
1835 * @param cls NULL
1836 * @param peer the peer
1837 * @param address address associated with the request
1838 * @param session session associated with the request
1839 * @param result the result
1840 */
1841static void
1842plugin_env_session_start_bl_check_cont (
1843 void *cls,
1844 const struct GNUNET_PeerIdentity *peer,
1845 const struct GNUNET_HELLO_Address *address,
1846 struct GNUNET_ATS_Session *session,
1847 int result)
1848{
1849 if (GNUNET_OK != result)
1850 {
1851 kill_session (address->transport_name, session);
1852 return;
1853 }
1854 if (GNUNET_YES !=
1855 GNUNET_HELLO_address_check_option (address,
1856 GNUNET_HELLO_ADDRESS_INFO_INBOUND))
1857 {
1858 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1859 "Informing verifier about inbound session's address `%s'\n",
1860 GST_plugins_a2s (address));
1861 GST_validation_handle_address (address);
1862 }
1863}
1864
1865
1866/**
1867 * Plugin tells transport service about a new inbound session
1868 *
1869 * @param cls unused
1870 * @param address the address
1871 * @param session the new session
1872 * @param scope network scope information
1873 */
1874static void
1875plugin_env_session_start (void *cls,
1876 const struct GNUNET_HELLO_Address *address,
1877 struct GNUNET_ATS_Session *session,
1878 enum GNUNET_NetworkType scope)
1879{
1880 struct GNUNET_ATS_Properties prop;
1881
1882 if (NULL == address)
1883 {
1884 GNUNET_break (0);
1885 return;
1886 }
1887 if (NULL == session)
1888 {
1889 GNUNET_break (0);
1890 return;
1891 }
1892 GNUNET_log (
1893 GNUNET_ERROR_TYPE_INFO,
1894 "Notification from plugin `%s' about new session from peer `%s' address `%s'\n",
1895 address->transport_name,
1896 GNUNET_i2s (&address->peer),
1897 GST_plugins_a2s (address));
1898 if (GNUNET_YES ==
1899 GNUNET_HELLO_address_check_option (address,
1900 GNUNET_HELLO_ADDRESS_INFO_INBOUND))
1901 {
1902 /* inbound is always new, but outbound MAY already be known, but
1903 for example for UNIX, we have symmetric connections and thus we
1904 may not know the address yet; add if necessary! */
1905 /* FIXME: maybe change API here so we just pass scope? */
1906 memset (&prop, 0, sizeof(prop));
1907 GNUNET_break (GNUNET_NT_UNSPECIFIED != scope);
1908 prop.scope = scope;
1909 GST_ats_add_inbound_address (address, session, &prop);
1910 }
1911 /* Do blacklist check if communication with this peer is allowed */
1912 (void) GST_blacklist_test_allowed (&address->peer,
1913 address->transport_name,
1914 &plugin_env_session_start_bl_check_cont,
1915 NULL,
1916 address,
1917 session);
1918}
1919
1920
1921/**
1922 * Function called by ATS to notify the callee that the
1923 * assigned bandwidth or address for a given peer was changed. If the
1924 * callback is called with address/bandwidth assignments of zero, the
1925 * ATS disconnect function will still be called once the disconnect
1926 * actually happened.
1927 *
1928 * @param cls closure
1929 * @param peer the peer this address is intended for
1930 * @param address address to use (for peer given in address)
1931 * @param session session to use (if available)
1932 * @param bandwidth_out assigned outbound bandwidth for the connection in NBO,
1933 * 0 to disconnect from peer
1934 * @param bandwidth_in assigned inbound bandwidth for the connection in NBO,
1935 * 0 to disconnect from peer
1936 * @param ats ATS information
1937 * @param ats_count number of @a ats elements
1938 */
1939static void
1940ats_request_address_change (void *cls,
1941 const struct GNUNET_PeerIdentity *peer,
1942 const struct GNUNET_HELLO_Address *address,
1943 struct GNUNET_ATS_Session *session,
1944 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
1945 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in)
1946{
1947 uint32_t bw_in = ntohl (bandwidth_in.value__);
1948 uint32_t bw_out = ntohl (bandwidth_out.value__);
1949
1950 if (NULL == peer)
1951 {
1952 /* ATS service died, all suggestions become invalid!
1953 (but we'll keep using the allocations for a little
1954 while, to keep going while ATS restarts) */
1955 /* FIXME: We should drop all
1956 connections now, as ATS won't explicitly tell
1957 us and be unaware of ongoing resource allocations! */
1958 return;
1959 }
1960 /* ATS tells me to disconnect from peer */
1961 if ((0 == bw_in) && (0 == bw_out))
1962 {
1963 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1964 "ATS tells me to disconnect from peer `%s'\n",
1965 GNUNET_i2s (peer));
1966 GST_neighbours_force_disconnect (peer);
1967 return;
1968 }
1969 GNUNET_assert (NULL != address);
1970 GNUNET_STATISTICS_update (GST_stats,
1971 "# ATS suggestions received",
1972 1,
1973 GNUNET_NO);
1974 GST_neighbours_switch_to_address (address,
1975 session,
1976 bandwidth_in,
1977 bandwidth_out);
1978}
1979
1980
1981/**
1982 * Closure for #test_connection_ok().
1983 */
1984struct TestConnectionContext
1985{
1986 /**
1987 * Is this the first neighbour we're checking?
1988 */
1989 int first;
1990
1991 /**
1992 * Handle to the blacklisting client we need to ask.
1993 */
1994 struct TransportClient *tc;
1995};
1996
1997
1998/**
1999 * Got the result about an existing connection from a new blacklister.
2000 * Shutdown the neighbour if necessary.
2001 *
2002 * @param cls unused
2003 * @param peer the neighbour that was investigated
2004 * @param address address associated with the request
2005 * @param session session associated with the request
2006 * @param allowed #GNUNET_OK if we can keep it,
2007 * #GNUNET_NO if we must shutdown the connection
2008 */
2009static void
2010confirm_or_drop_neighbour (void *cls,
2011 const struct GNUNET_PeerIdentity *peer,
2012 const struct GNUNET_HELLO_Address *address,
2013 struct GNUNET_ATS_Session *session,
2014 int allowed)
2015{
2016 if (GNUNET_OK == allowed)
2017 return; /* we're done */
2018 GNUNET_STATISTICS_update (GST_stats,
2019 gettext_noop ("# disconnects due to blacklist"),
2020 1,
2021 GNUNET_NO);
2022 GST_neighbours_force_disconnect (peer);
2023}
2024
2025
2026/**
2027 * Test if an existing connection is still acceptable given a new
2028 * blacklisting client.
2029 *
2030 * @param cls the `struct TestConnectionContext *`
2031 * @param peer identity of the peer
2032 * @param address the address
2033 * @param state current state this peer is in
2034 * @param state_timeout timeout for the current state of the peer
2035 * @param bandwidth_in bandwidth assigned inbound
2036 * @param bandwidth_out bandwidth assigned outbound
2037 */
2038static void
2039test_connection_ok (void *cls,
2040 const struct GNUNET_PeerIdentity *peer,
2041 const struct GNUNET_HELLO_Address *address,
2042 enum GNUNET_TRANSPORT_PeerState state,
2043 struct GNUNET_TIME_Absolute state_timeout,
2044 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
2045 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
2046{
2047 struct TestConnectionContext *tcc = cls;
2048 struct GST_BlacklistCheck *bc;
2049
2050 bc = GNUNET_new (struct GST_BlacklistCheck);
2051 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
2052 bc->peer = *peer;
2053 bc->address = GNUNET_HELLO_address_copy (address);
2054 bc->cont = &confirm_or_drop_neighbour;
2055 bc->cont_cls = NULL;
2056 bc->bl_pos = tcc->tc;
2057 if (GNUNET_YES == tcc->first)
2058 {
2059 /* all would wait for the same client, no need to
2060 * create more than just the first task right now */
2061 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
2062 tcc->first = GNUNET_NO;
2063 }
2064}
2065
2066
2067/**
2068 * Initialize a blacklisting client. We got a blacklist-init
2069 * message from this client, add it to the list of clients
2070 * to query for blacklisting.
2071 *
2072 * @param cls the client
2073 * @param message the blacklist-init message that was sent
2074 */
2075static void
2076handle_client_blacklist_init (void *cls,
2077 const struct GNUNET_MessageHeader *message)
2078{
2079 struct TransportClient *tc = cls;
2080 struct TestConnectionContext tcc;
2081
2082 if (CT_NONE != tc->type)
2083 {
2084 GNUNET_break (0);
2085 GNUNET_SERVICE_client_drop (tc->client);
2086 return;
2087 }
2088 GNUNET_SERVICE_client_mark_monitor (tc->client);
2089 tc->type = CT_BLACKLIST;
2090 tc->details.blacklist.call_receive_done = GNUNET_YES;
2091 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "New blacklist client %p\n", tc);
2092 /* confirm that all existing connections are OK! */
2093 tcc.tc = tc;
2094 tcc.first = GNUNET_YES;
2095 GST_neighbours_iterate (&test_connection_ok, &tcc);
2096}
2097
2098
2099/**
2100 * Free the given entry in the blacklist.
2101 *
2102 * @param cls unused
2103 * @param key host identity (unused)
2104 * @param value the blacklist entry
2105 * @return #GNUNET_OK (continue to iterate)
2106 */
2107static int
2108free_blacklist_entry (void *cls,
2109 const struct GNUNET_PeerIdentity *key,
2110 void *value)
2111{
2112 char *be = value;
2113
2114 GNUNET_free (be);
2115 return GNUNET_OK;
2116}
2117
2118
2119/**
2120 * Set traffic metric to manipulate
2121 *
2122 * @param cls closure
2123 * @param tm message containing information
2124 */
2125static void
2126handle_client_set_metric (void *cls, const struct TrafficMetricMessage *tm)
2127{
2128 struct TransportClient *tc = cls;
2129
2130 GST_manipulation_set_metric (tm);
2131 GNUNET_SERVICE_client_continue (tc->client);
2132}
2133
2134
2135/**
2136 * Function called when the service shuts down. Unloads our plugins
2137 * and cancels pending validations.
2138 *
2139 * @param cls closure, unused
2140 */
2141static void
2142shutdown_task (void *cls)
2143{
2144 struct AddressToStringContext *cur;
2145
2146 GST_neighbours_stop ();
2147 GST_plugins_unload ();
2148 GST_validation_stop ();
2149 GST_ats_done ();
2150 GNUNET_ATS_scheduling_done (GST_ats);
2151 GST_ats = NULL;
2152 GNUNET_ATS_connectivity_done (GST_ats_connect);
2153 GST_ats_connect = NULL;
2154 GNUNET_NT_scanner_done (GST_is);
2155 GST_is = NULL;
2156 while (NULL != (cur = a2s_head))
2157 {
2158 GNUNET_CONTAINER_DLL_remove (a2s_head, a2s_tail, cur);
2159 GNUNET_free (cur);
2160 }
2161 if (NULL != plugin_nc)
2162 {
2163 GNUNET_notification_context_destroy (plugin_nc);
2164 plugin_nc = NULL;
2165 }
2166 GNUNET_CONTAINER_multipeermap_destroy (active_stccs);
2167 active_stccs = NULL;
2168 if (NULL != blacklist)
2169 {
2170 GNUNET_CONTAINER_multipeermap_iterate (blacklist,
2171 &free_blacklist_entry,
2172 NULL);
2173 GNUNET_CONTAINER_multipeermap_destroy (blacklist);
2174 blacklist = NULL;
2175 }
2176 GST_hello_stop ();
2177 GST_manipulation_stop ();
2178
2179 if (NULL != GST_peerinfo)
2180 {
2181 GNUNET_PEERINFO_disconnect (GST_peerinfo);
2182 GST_peerinfo = NULL;
2183 }
2184 if (NULL != GST_stats)
2185 {
2186 GNUNET_STATISTICS_destroy (GST_stats, GNUNET_NO);
2187 GST_stats = NULL;
2188 }
2189}
2190
2191
2192static void
2193do_blacklist_check (void *cls)
2194{
2195 struct GST_BlacklistCheck *bc = cls;
2196 struct TransportClient *tc;
2197 struct GNUNET_MQ_Envelope *env;
2198 struct BlacklistMessage *bm;
2199
2200 bc->task = NULL;
2201 while (NULL != (tc = bc->bl_pos))
2202 {
2203 if (CT_BLACKLIST == tc->type)
2204 break;
2205 bc->bl_pos = tc->next;
2206 }
2207 if (NULL == tc)
2208 {
2209 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2210 "No other blacklist clients active, will allow neighbour `%s'\n",
2211 GNUNET_i2s (&bc->peer));
2212
2213 bc->cont (bc->cont_cls, &bc->peer, bc->address, bc->session, GNUNET_OK);
2214 GST_blacklist_test_cancel (bc);
2215 return;
2216 }
2217 if ((NULL != tc->details.blacklist.bc) ||
2218 (GNUNET_NO != tc->details.blacklist.waiting_for_reply))
2219 return; /* someone else busy with this client */
2220 tc->details.blacklist.bc = bc;
2221 env = GNUNET_MQ_msg (bm, GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
2222 bm->is_allowed = htonl (0);
2223 bm->peer = bc->peer;
2224 GNUNET_MQ_send (tc->mq, env);
2225 if (GNUNET_YES == tc->details.blacklist.call_receive_done)
2226 {
2227 tc->details.blacklist.call_receive_done = GNUNET_NO;
2228 GNUNET_SERVICE_client_continue (tc->client);
2229 }
2230 tc->details.blacklist.waiting_for_reply = GNUNET_YES;
2231}
2232
2233
2234/**
2235 * A blacklisting client has sent us reply. Process it.
2236 *
2237 * @param cls the client
2238 * @param msg the blacklist-reply message that was sent
2239 */
2240static void
2241handle_client_blacklist_reply (void *cls, const struct BlacklistMessage *msg)
2242{
2243 struct TransportClient *tc = cls;
2244 struct GST_BlacklistCheck *bc;
2245
2246 if (CT_BLACKLIST != tc->type)
2247 {
2248 GNUNET_break (0);
2249 GNUNET_SERVICE_client_drop (tc->client);
2250 return;
2251 }
2252 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2253 "Blacklist client %p sent reply for `%s'\n",
2254 tc,
2255 GNUNET_i2s (&msg->peer));
2256 bc = tc->details.blacklist.bc;
2257 tc->details.blacklist.bc = NULL;
2258 tc->details.blacklist.waiting_for_reply = GNUNET_NO;
2259 tc->details.blacklist.call_receive_done = GNUNET_YES;
2260 if (NULL != bc)
2261 {
2262 /* only run this if the blacklist check has not been
2263 * cancelled in the meantime... */
2264 GNUNET_assert (bc->bl_pos == tc);
2265 if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
2266 {
2267 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2268 "Blacklist check failed, peer not allowed\n");
2269 /* For the duration of the continuation, make the ongoing
2270 check invisible (to avoid double-cancellation); then
2271 add it back again so we can re-use GST_blacklist_test_cancel() */
2272 GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
2273 bc->cont (bc->cont_cls, &bc->peer, bc->address, bc->session, GNUNET_NO);
2274 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
2275 GST_blacklist_test_cancel (bc);
2276 tc->details.blacklist.call_receive_done = GNUNET_NO;
2277 GNUNET_SERVICE_client_continue (tc->client);
2278 return;
2279 }
2280 else
2281 {
2282 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2283 "Blacklist check succeeded, continuing with checks\n");
2284 tc->details.blacklist.call_receive_done = GNUNET_NO;
2285 GNUNET_SERVICE_client_continue (tc->client);
2286 bc->bl_pos = tc->next;
2287 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
2288 }
2289 }
2290 /* check if any other blacklist checks are waiting for this blacklister */
2291 for (bc = bc_head; bc != NULL; bc = bc->next)
2292 if ((bc->bl_pos == tc) && (NULL == bc->task))
2293 {
2294 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
2295 break;
2296 }
2297}
2298
2299
2300/**
2301 * Add the given peer to the blacklist (for the given transport).
2302 *
2303 * @param peer peer to blacklist
2304 * @param transport_name transport to blacklist for this peer, NULL for all
2305 */
2306void
2307GST_blacklist_add_peer (const struct GNUNET_PeerIdentity *peer,
2308 const char *transport_name)
2309{
2310 char *transport = NULL;
2311
2312 if (NULL != transport_name)
2313 {
2314 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2315 "Adding peer `%s' with plugin `%s' to blacklist\n",
2316 GNUNET_i2s (peer),
2317 transport_name);
2318 transport = GNUNET_strdup (transport_name);
2319 }
2320 else
2321 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2322 "Adding peer `%s' with all plugins to blacklist\n",
2323 GNUNET_i2s (peer));
2324 if (NULL == blacklist)
2325 blacklist =
2326 GNUNET_CONTAINER_multipeermap_create (TRANSPORT_BLACKLIST_HT_SIZE,
2327 GNUNET_NO);
2328
2329 GNUNET_CONTAINER_multipeermap_put (blacklist,
2330 peer,
2331 transport,
2332 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2333}
2334
2335
2336/**
2337 * Abort blacklist if @a address and @a session match.
2338 *
2339 * @param address address used to abort matching checks
2340 * @param session session used to abort matching checks
2341 */
2342void
2343GST_blacklist_abort_matching (const struct GNUNET_HELLO_Address *address,
2344 struct GNUNET_ATS_Session *session)
2345{
2346 struct GST_BlacklistCheck *bc;
2347 struct GST_BlacklistCheck *n;
2348
2349 n = bc_head;
2350 while (NULL != (bc = n))
2351 {
2352 n = bc->next;
2353 if ((bc->session == session) &&
2354 (0 == GNUNET_HELLO_address_cmp (bc->address, address)))
2355 {
2356 bc->cont (bc->cont_cls,
2357 &bc->peer,
2358 bc->address,
2359 bc->session,
2360 GNUNET_SYSERR);
2361 GST_blacklist_test_cancel (bc);
2362 }
2363 }
2364}
2365
2366
2367/**
2368 * Test if the given blacklist entry matches. If so,
2369 * abort the iteration.
2370 *
2371 * @param cls the transport name to match (const char*)
2372 * @param key the key (unused)
2373 * @param value the 'char *' (name of a blacklisted transport)
2374 * @return #GNUNET_OK if the entry does not match, #GNUNET_NO if it matches
2375 */
2376static int
2377test_blacklisted (void *cls, const struct GNUNET_PeerIdentity *key, void *value)
2378{
2379 const char *transport_name = cls;
2380 char *be = value;
2381
2382 /* Blacklist entry be:
2383 * (NULL == be): peer is blacklisted with all plugins
2384 * (NULL != be): peer is blacklisted for a specific plugin
2385 *
2386 * If (NULL != transport_name) we look for a transport specific entry:
2387 * if (transport_name == be) forbidden
2388 *
2389 */GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2390 "Comparing BL request for peer `%4s':`%s' with BL entry: `%s'\n",
2391 GNUNET_i2s (key),
2392 (NULL == transport_name) ? "unspecified" : transport_name,
2393 (NULL == be) ? "all plugins" : be);
2394 /* all plugins for this peer were blacklisted: disallow */
2395 if (NULL == value)
2396 return GNUNET_NO;
2397
2398 /* blacklist check for specific transport */
2399 if ((NULL != transport_name) && (NULL != value))
2400 {
2401 if (0 == strcmp (transport_name, be))
2402 return GNUNET_NO; /* plugin is blacklisted! */
2403 }
2404 return GNUNET_OK;
2405}
2406
2407
2408/**
2409 * Test if a peer/transport combination is blacklisted.
2410 *
2411 * @param peer the identity of the peer to test
2412 * @param transport_name name of the transport to test, never NULL
2413 * @param cont function to call with result
2414 * @param cont_cls closure for @a cont
2415 * @param address address to pass back to @a cont, can be NULL
2416 * @param session session to pass back to @a cont, can be NULL
2417 * @return handle to the blacklist check, NULL if the decision
2418 * was made instantly and @a cont was already called
2419 */
2420struct GST_BlacklistCheck *
2421GST_blacklist_test_allowed (const struct GNUNET_PeerIdentity *peer,
2422 const char *transport_name,
2423 GST_BlacklistTestContinuation cont,
2424 void *cont_cls,
2425 const struct GNUNET_HELLO_Address *address,
2426 struct GNUNET_ATS_Session *session)
2427{
2428 struct GST_BlacklistCheck *bc;
2429 struct TransportClient *tc;
2430
2431 GNUNET_assert (NULL != peer);
2432 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2433 "Blacklist check for peer `%s':%s\n",
2434 GNUNET_i2s (peer),
2435 (NULL != transport_name) ? transport_name : "unspecified");
2436
2437 /* Check local blacklist by iterating over hashmap
2438 * If iteration is aborted, we found a matching blacklist entry */
2439 if ((NULL != blacklist) &&
2440 (GNUNET_SYSERR ==
2441 GNUNET_CONTAINER_multipeermap_get_multiple (blacklist,
2442 peer,
2443 &test_blacklisted,
2444 (void *) transport_name)))
2445 {
2446 /* Disallowed by config, disapprove instantly */
2447 GNUNET_STATISTICS_update (GST_stats,
2448 gettext_noop ("# disconnects due to blacklist"),
2449 1,
2450 GNUNET_NO);
2451 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2452 _ ("Disallowing connection to peer `%s' on transport %s\n"),
2453 GNUNET_i2s (peer),
2454 (NULL != transport_name) ? transport_name : "unspecified");
2455 if (NULL != cont)
2456 cont (cont_cls, peer, address, session, GNUNET_NO);
2457 return NULL;
2458 }
2459
2460 for (tc = clients_head; NULL != tc; tc = tc->next)
2461 if (CT_BLACKLIST == tc->type)
2462 break;
2463 if (NULL == tc)
2464 {
2465 /* no blacklist clients, approve instantly */
2466 if (NULL != cont)
2467 cont (cont_cls, peer, address, session, GNUNET_OK);
2468 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2469 "Allowing connection to peer `%s' %s\n",
2470 GNUNET_i2s (peer),
2471 (NULL != transport_name) ? transport_name : "");
2472 return NULL;
2473 }
2474
2475 /* need to query blacklist clients */
2476 bc = GNUNET_new (struct GST_BlacklistCheck);
2477 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
2478 bc->peer = *peer;
2479 bc->address = GNUNET_HELLO_address_copy (address);
2480 bc->session = session;
2481 bc->cont = cont;
2482 bc->cont_cls = cont_cls;
2483 bc->bl_pos = tc;
2484 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
2485 return bc;
2486}
2487
2488
2489void
2490GST_blacklist_test_cancel (struct GST_BlacklistCheck *bc)
2491{
2492 GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
2493 if (NULL != bc->bl_pos)
2494 {
2495 if ((CT_BLACKLIST == bc->bl_pos->type) &&
2496 (bc->bl_pos->details.blacklist.bc == bc))
2497 {
2498 /* we're at the head of the queue, remove us! */
2499 bc->bl_pos->details.blacklist.bc = NULL;
2500 }
2501 }
2502 if (NULL != bc->task)
2503 {
2504 GNUNET_SCHEDULER_cancel (bc->task);
2505 bc->task = NULL;
2506 }
2507 GNUNET_free (bc->address);
2508 GNUNET_free (bc);
2509}
2510
2511
2512/**
2513 * Function to iterate over options in the blacklisting section for a peer.
2514 *
2515 * @param cls closure
2516 * @param section name of the section
2517 * @param option name of the option
2518 * @param value value of the option
2519 */
2520static void
2521blacklist_cfg_iter (void *cls,
2522 const char *section,
2523 const char *option,
2524 const char *value)
2525{
2526 unsigned int *res = cls;
2527 struct GNUNET_PeerIdentity peer;
2528 char *plugs;
2529 char *pos;
2530
2531 if (GNUNET_OK !=
2532 GNUNET_CRYPTO_eddsa_public_key_from_string (option,
2533 strlen (option),
2534 &peer.public_key))
2535 return;
2536
2537 if ((NULL == value) || (0 == strcmp (value, "")))
2538 {
2539 /* Blacklist whole peer */
2540 GST_blacklist_add_peer (&peer, NULL);
2541 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2542 _ ("Adding blacklisting entry for peer `%s'\n"),
2543 GNUNET_i2s (&peer));
2544 }
2545 else
2546 {
2547 plugs = GNUNET_strdup (value);
2548 for (pos = strtok (plugs, " "); pos != NULL; pos = strtok (NULL, " "))
2549 {
2550 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2551 _ ("Adding blacklisting entry for peer `%s':`%s'\n"),
2552 GNUNET_i2s (&peer),
2553 pos);
2554 GST_blacklist_add_peer (&peer, pos);
2555 }
2556 GNUNET_free (plugs);
2557 }
2558 (*res)++;
2559}
2560
2561
2562/**
2563 * Read blacklist configuration
2564 *
2565 * @param cfg the configuration handle
2566 * @param my_id my peer identity
2567 */
2568static void
2569read_blacklist_configuration (const struct GNUNET_CONFIGURATION_Handle *cfg,
2570 const struct GNUNET_PeerIdentity *my_id)
2571{
2572 char cfg_sect[512];
2573 unsigned int res = 0;
2574
2575 GNUNET_snprintf (cfg_sect,
2576 sizeof(cfg_sect),
2577 "transport-blacklist-%s",
2578 GNUNET_i2s_full (my_id));
2579 GNUNET_CONFIGURATION_iterate_section_values (cfg,
2580 cfg_sect,
2581 &blacklist_cfg_iter,
2582 &res);
2583 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2584 "Loaded %u blacklisting entries from configuration\n",
2585 res);
2586}
2587
2588
2589/**
2590 * Initiate transport service.
2591 *
2592 * @param cls closure
2593 * @param c configuration to use
2594 * @param service the initialized service
2595 */
2596static void
2597run (void *cls,
2598 const struct GNUNET_CONFIGURATION_Handle *c,
2599 struct GNUNET_SERVICE_Handle *service)
2600{
2601 char *keyfile;
2602 long long unsigned int max_fd_cfg;
2603 int max_fd_rlimit;
2604 int max_fd;
2605 int friend_only;
2606
2607 /* setup globals */
2608 GST_cfg = c;
2609 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (c,
2610 "PEER",
2611 "PRIVATE_KEY",
2612 &keyfile))
2613 {
2614 GNUNET_log (
2615 GNUNET_ERROR_TYPE_ERROR,
2616 _ (
2617 "Transport service is lacking key configuration settings. Exiting.\n"));
2618 GNUNET_SCHEDULER_shutdown ();
2619 return;
2620 }
2621 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (c,
2622 "transport",
2623 "HELLO_EXPIRATION",
2624 &hello_expiration))
2625 {
2626 hello_expiration = GNUNET_CONSTANTS_HELLO_ADDRESS_EXPIRATION;
2627 }
2628 if (GNUNET_SYSERR ==
2629 GNUNET_CRYPTO_eddsa_key_from_file (keyfile,
2630 GNUNET_YES,
2631 &GST_my_private_key))
2632 {
2633 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2634 "Failed to setup peer's private key\n");
2635 GNUNET_SCHEDULER_shutdown ();
2636 GNUNET_free (keyfile);
2637 return;
2638 }
2639 GNUNET_free (keyfile);
2640 GST_stats = GNUNET_STATISTICS_create ("transport", GST_cfg);
2641 GST_peerinfo = GNUNET_PEERINFO_connect (GST_cfg);
2642 GNUNET_CRYPTO_eddsa_key_get_public (&GST_my_private_key,
2643 &GST_my_identity.public_key);
2644 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2645 "My identity is `%s'\n",
2646 GNUNET_i2s_full (&GST_my_identity));
2647
2648 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
2649 if (NULL == GST_peerinfo)
2650 {
2651 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2652 _ ("Could not access PEERINFO service. Exiting.\n"));
2653 GNUNET_SCHEDULER_shutdown ();
2654 return;
2655 }
2656
2657 max_fd_rlimit = 0;
2658#if HAVE_GETRLIMIT
2659 {
2660 struct rlimit r_file;
2661
2662 if (0 == getrlimit (RLIMIT_NOFILE, &r_file))
2663 {
2664 max_fd_rlimit = r_file.rlim_cur;
2665 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2666 "Maximum number of open files was: %u/%u\n",
2667 (unsigned int) r_file.rlim_cur,
2668 (unsigned int) r_file.rlim_max);
2669 }
2670 max_fd_rlimit =
2671 (9 * max_fd_rlimit) / 10; /* Keep 10% for rest of transport */
2672 }
2673#endif
2674 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (GST_cfg,
2675 "transport",
2676 "MAX_FD",
2677 &max_fd_cfg))
2678 max_fd_cfg = max_fd_rlimit;
2679
2680 if (max_fd_cfg > max_fd_rlimit)
2681 max_fd = max_fd_cfg;
2682 else
2683 max_fd = max_fd_rlimit;
2684 if (max_fd < DEFAULT_MAX_FDS)
2685 max_fd = DEFAULT_MAX_FDS;
2686
2687 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2688 "Limiting number of sockets to %u: validation %u, neighbors: %u\n",
2689 max_fd,
2690 (max_fd / 3),
2691 (max_fd / 3) * 2);
2692
2693 friend_only =
2694 GNUNET_CONFIGURATION_get_value_yesno (GST_cfg, "topology", "FRIENDS-ONLY");
2695 if (GNUNET_SYSERR == friend_only)
2696 friend_only = GNUNET_NO; /* According to topology defaults */
2697 /* start subsystems */
2698 /* Disable DSTJ peer */
2699 {
2700 struct GNUNET_PeerIdentity dstj;
2701 const char *ds = "DSTJBRRKZ8TBW3FGK6B0M5QXWT9WYNZ45H5MCV4HY7ST64Q8T9F0";
2702
2703 GNUNET_assert (
2704 GNUNET_OK ==
2705 GNUNET_CRYPTO_eddsa_public_key_from_string (ds,
2706 strlen (ds),
2707 &dstj.public_key));
2708 GST_blacklist_add_peer (&dstj, NULL);
2709 }
2710 read_blacklist_configuration (GST_cfg, &GST_my_identity);
2711 GST_is = GNUNET_NT_scanner_init ();
2712 GST_ats_connect = GNUNET_ATS_connectivity_init (GST_cfg);
2713 GST_ats =
2714 GNUNET_ATS_scheduling_init (GST_cfg, &ats_request_address_change, NULL);
2715 GST_ats_init ();
2716 GST_manipulation_init ();
2717 GST_plugins_load (&GST_manipulation_recv,
2718 &plugin_env_address_change_notification,
2719 &plugin_env_session_start,
2720 &plugin_env_session_end);
2721 GST_hello_start (friend_only, &process_hello_update, NULL);
2722 GST_neighbours_start ((max_fd / 3) * 2);
2723 active_stccs = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_YES);
2724 plugin_nc = GNUNET_notification_context_create (0);
2725 GST_validation_start ((max_fd / 3));
2726}
2727
2728
2729/**
2730 * Define "main" method using service macro.
2731 */
2732GNUNET_SERVICE_MAIN (
2733 "transport",
2734 GNUNET_SERVICE_OPTION_NONE,
2735 &run,
2736 &client_connect_cb,
2737 &client_disconnect_cb,
2738 NULL,
2739 GNUNET_MQ_hd_fixed_size (client_start,
2740 GNUNET_MESSAGE_TYPE_TRANSPORT_START,
2741 struct StartMessage,
2742 NULL),
2743 GNUNET_MQ_hd_var_size (client_hello,
2744 GNUNET_MESSAGE_TYPE_HELLO,
2745 struct GNUNET_MessageHeader,
2746 NULL),
2747 GNUNET_MQ_hd_var_size (client_send,
2748 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND,
2749 struct OutboundMessage,
2750 NULL),
2751 GNUNET_MQ_hd_var_size (client_address_to_string,
2752 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING,
2753 struct AddressLookupMessage,
2754 NULL),
2755 GNUNET_MQ_hd_fixed_size (client_monitor_peers,
2756 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_REQUEST,
2757 struct PeerMonitorMessage,
2758 NULL),
2759 GNUNET_MQ_hd_fixed_size (client_blacklist_init,
2760 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT,
2761 struct GNUNET_MessageHeader,
2762 NULL),
2763 GNUNET_MQ_hd_fixed_size (client_blacklist_reply,
2764 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY,
2765 struct BlacklistMessage,
2766 NULL),
2767 GNUNET_MQ_hd_fixed_size (client_set_metric,
2768 GNUNET_MESSAGE_TYPE_TRANSPORT_TRAFFIC_METRIC,
2769 struct TrafficMetricMessage,
2770 NULL),
2771 GNUNET_MQ_hd_fixed_size (client_monitor_plugins,
2772 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PLUGIN_START,
2773 struct GNUNET_MessageHeader,
2774 NULL),
2775 GNUNET_MQ_handler_end ());
2776
2777
2778/* end of file gnunet-service-transport.c */
diff --git a/src/transport/gnunet-service-transport_ats.c b/src/transport/gnunet-service-transport_ats.c
deleted file mode 100644
index 2438a0a48..000000000
--- a/src/transport/gnunet-service-transport_ats.c
+++ /dev/null
@@ -1,906 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2015 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport/gnunet-service-transport_ats.c
22 * @brief interfacing between transport and ATS service
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "gnunet-service-transport.h"
27#include "gnunet-service-transport_ats.h"
28#include "gnunet-service-transport_manipulation.h"
29#include "gnunet-service-transport_plugins.h"
30#include "gnunet_ats_service.h"
31
32/**
33 * Log convenience function.
34 */
35#define LOG(kind, ...) GNUNET_log_from (kind, "transport-ats", __VA_ARGS__)
36
37
38/**
39 * Information we track for each address known to ATS.
40 */
41struct AddressInfo
42{
43 /**
44 * The address (with peer identity). Must never change
45 * while this struct is in the #p2a map.
46 */
47 struct GNUNET_HELLO_Address *address;
48
49 /**
50 * Session (can be NULL)
51 */
52 struct GNUNET_ATS_Session *session;
53
54 /**
55 * Record with ATS API for the address.
56 */
57 struct GNUNET_ATS_AddressRecord *ar;
58
59 /**
60 * Performance properties of this address.
61 */
62 struct GNUNET_ATS_Properties properties;
63
64 /**
65 * Time until when this address is blocked and should thus not be
66 * made available to ATS (@e ar should be NULL until this time).
67 * Used when transport determines that for some reason it
68 * (temporarily) cannot use an address, even though it has been
69 * validated.
70 */
71 struct GNUNET_TIME_Absolute blocked;
72
73 /**
74 * If an address is blocked as part of an exponential back-off,
75 * we track the current size of the backoff here.
76 */
77 struct GNUNET_TIME_Relative back_off;
78
79 /**
80 * Task scheduled to unblock an ATS-blocked address at
81 * @e blocked time, or NULL if the address is not blocked
82 * (and thus @e ar is non-NULL).
83 */
84 struct GNUNET_SCHEDULER_Task *unblock_task;
85
86 /**
87 * Set to #GNUNET_YES if the address has expired but we could
88 * not yet remove it because we still have a valid session.
89 */
90 int expired;
91};
92
93
94/**
95 * Map from peer identities to one or more `struct AddressInfo` values
96 * for the peer.
97 */
98static struct GNUNET_CONTAINER_MultiPeerMap *p2a;
99
100/**
101 * Number of blocked addresses.
102 */
103static unsigned int num_blocked;
104
105
106/**
107 * Closure for #find_ai_cb() and #find_ai_no_session_cb().
108 */
109struct FindClosure
110{
111 /**
112 * Session to look for (only used if the address is inbound).
113 */
114 struct GNUNET_ATS_Session *session;
115
116 /**
117 * Address to look for.
118 */
119 const struct GNUNET_HELLO_Address *address;
120
121 /**
122 * Where to store the result.
123 */
124 struct AddressInfo *ret;
125};
126
127
128/**
129 * Provide an update on the `p2a` map size to statistics.
130 * This function should be called whenever the `p2a` map
131 * is changed.
132 */
133static void
134publish_p2a_stat_update ()
135{
136 GNUNET_STATISTICS_set (GST_stats,
137 gettext_noop ("# Addresses given to ATS"),
138 GNUNET_CONTAINER_multipeermap_size (p2a) - num_blocked,
139 GNUNET_NO);
140 GNUNET_STATISTICS_set (GST_stats,
141 "# blocked addresses",
142 num_blocked,
143 GNUNET_NO);
144}
145
146
147/**
148 * Find matching address info. Both the address and the session
149 * must match; note that expired addresses are still found (as
150 * the session kind-of keeps those alive).
151 *
152 * @param cls the `struct FindClosure`
153 * @param key which peer is this about
154 * @param value the `struct AddressInfo`
155 * @return #GNUNET_YES to continue to iterate, #GNUNET_NO if we found the value
156 */
157static int
158find_ai_cb (void *cls,
159 const struct GNUNET_PeerIdentity *key,
160 void *value)
161{
162 struct FindClosure *fc = cls;
163 struct AddressInfo *ai = value;
164
165 if ((0 ==
166 GNUNET_HELLO_address_cmp (fc->address,
167 ai->address)) &&
168 (fc->session == ai->session))
169 {
170 fc->ret = ai;
171 return GNUNET_NO;
172 }
173 return GNUNET_YES;
174}
175
176
177/**
178 * Find the address information struct for the
179 * given @a address and @a session.
180 *
181 * @param address address to look for
182 * @param session session to match for inbound connections
183 * @return NULL if this combination is unknown
184 */
185static struct AddressInfo *
186find_ai (const struct GNUNET_HELLO_Address *address,
187 struct GNUNET_ATS_Session *session)
188{
189 struct FindClosure fc;
190
191 fc.address = address;
192 fc.session = session;
193 fc.ret = NULL;
194 GNUNET_CONTAINER_multipeermap_get_multiple (p2a,
195 &address->peer,
196 &find_ai_cb,
197 &fc);
198 return fc.ret;
199}
200
201
202/**
203 * Find matching address info, ignoring sessions and expired
204 * addresses.
205 *
206 * @param cls the `struct FindClosure`
207 * @param key which peer is this about
208 * @param value the `struct AddressInfo`
209 * @return #GNUNET_YES to continue to iterate, #GNUNET_NO if we found the value
210 */
211static int
212find_ai_no_session_cb (void *cls,
213 const struct GNUNET_PeerIdentity *key,
214 void *value)
215{
216 struct FindClosure *fc = cls;
217 struct AddressInfo *ai = value;
218
219 if (ai->expired)
220 return GNUNET_YES; /* expired do not count here */
221 if (0 ==
222 GNUNET_HELLO_address_cmp (fc->address,
223 ai->address))
224 {
225 fc->ret = ai;
226 return GNUNET_NO;
227 }
228 return GNUNET_YES;
229}
230
231
232/**
233 * Find the address information struct for the
234 * given address (ignoring sessions)
235 *
236 * @param address address to look for
237 * @return NULL if this combination is unknown
238 */
239static struct AddressInfo *
240find_ai_no_session (const struct GNUNET_HELLO_Address *address)
241{
242 struct FindClosure fc;
243
244 fc.address = address;
245 fc.session = NULL;
246 fc.ret = NULL;
247 GNUNET_CONTAINER_multipeermap_get_multiple (p2a,
248 &address->peer,
249 &find_ai_no_session_cb,
250 &fc);
251 return fc.ret;
252}
253
254
255/**
256 * Test if ATS knows about this @a address and @a session.
257 * Note that even if the address is expired, we return
258 * #GNUNET_YES if the respective session matches.
259 *
260 * @param address the address
261 * @param session the session
262 * @return #GNUNET_YES if @a address is known, #GNUNET_NO if not.
263 */
264int
265GST_ats_is_known (const struct GNUNET_HELLO_Address *address,
266 struct GNUNET_ATS_Session *session)
267{
268 return (NULL != find_ai (address, session)) ? GNUNET_YES : GNUNET_NO;
269}
270
271
272/**
273 * Test if ATS knows about this @a address. Note that
274 * expired addresses do not count.
275 *
276 * @param address the address
277 * @return #GNUNET_YES if @a address is known, #GNUNET_NO if not.
278 */
279int
280GST_ats_is_known_no_session (const struct GNUNET_HELLO_Address *address)
281{
282 return (NULL != find_ai_no_session (address))
283 ? GNUNET_YES
284 : GNUNET_NO;
285}
286
287
288/**
289 * The blocking time for an address has expired, allow ATS to
290 * suggest it again.
291 *
292 * @param cls the `struct AddressInfo` of the address to unblock
293 */
294static void
295unblock_address (void *cls)
296{
297 struct AddressInfo *ai = cls;
298
299 ai->unblock_task = NULL;
300 LOG (GNUNET_ERROR_TYPE_DEBUG,
301 "Unblocking address %s of peer %s\n",
302 GST_plugins_a2s (ai->address),
303 GNUNET_i2s (&ai->address->peer));
304 ai->ar = GNUNET_ATS_address_add (GST_ats,
305 ai->address,
306 ai->session,
307 &ai->properties);
308 GNUNET_break (NULL != ai->ar);
309 num_blocked--;
310 publish_p2a_stat_update ();
311}
312
313
314/**
315 * Temporarily block a valid address for use by ATS for address
316 * suggestions. This function should be called if an address was
317 * suggested by ATS but failed to perform (i.e. failure to establish a
318 * session or to exchange the PING/PONG).
319 *
320 * @param address the address to block
321 * @param session the session (can be NULL)
322 */
323void
324GST_ats_block_address (const struct GNUNET_HELLO_Address *address,
325 struct GNUNET_ATS_Session *session)
326{
327 struct AddressInfo *ai;
328
329 if (0 ==
330 memcmp (&GST_my_identity,
331 &address->peer,
332 sizeof(struct GNUNET_PeerIdentity)))
333 return; /* our own, ignore! */
334 ai = find_ai (address,
335 session);
336 if ((NULL == ai) || (NULL == ai->ar))
337 {
338 /* The address is already gone/blocked, this can happen during a blacklist
339 * callback. */
340 return;
341 }
342 ai->back_off = GNUNET_TIME_STD_BACKOFF (ai->back_off);
343 if (GNUNET_YES ==
344 GNUNET_HELLO_address_check_option (address,
345 GNUNET_HELLO_ADDRESS_INFO_INBOUND))
346 LOG (GNUNET_ERROR_TYPE_DEBUG,
347 "Removing address %s of peer %s from use (inbound died)\n",
348 GST_plugins_a2s (address),
349 GNUNET_i2s (&address->peer));
350 else
351 LOG (GNUNET_ERROR_TYPE_INFO,
352 "Blocking address %s of peer %s from use for %s\n",
353 GST_plugins_a2s (address),
354 GNUNET_i2s (&address->peer),
355 GNUNET_STRINGS_relative_time_to_string (ai->back_off,
356 GNUNET_YES));
357 /* destroy session and address */
358 if ((NULL == session) ||
359 (GNUNET_NO ==
360 GNUNET_ATS_address_del_session (ai->ar,
361 session)))
362 {
363 GNUNET_ATS_address_destroy (ai->ar);
364 }
365 /* "ar" has been freed, regardless how the branch
366 above played out: it was either freed in
367 #GNUNET_ATS_address_del_session() because it was
368 incoming, or explicitly in
369 #GNUNET_ATS_address_del_session(). */ai->ar = NULL;
370
371 /* determine when the address should come back to life */
372 ai->blocked = GNUNET_TIME_relative_to_absolute (ai->back_off);
373 ai->unblock_task = GNUNET_SCHEDULER_add_delayed (ai->back_off,
374 &unblock_address,
375 ai);
376 num_blocked++;
377 publish_p2a_stat_update ();
378}
379
380
381/**
382 * Reset address blocking time. Resets the exponential
383 * back-off timer for this address to zero. Called when
384 * an address was used to create a successful connection.
385 *
386 * @param address the address to reset the blocking timer
387 * @param session the session (can be NULL)
388 */
389void
390GST_ats_block_reset (const struct GNUNET_HELLO_Address *address,
391 struct GNUNET_ATS_Session *session)
392{
393 struct AddressInfo *ai;
394
395 if (0 ==
396 memcmp (&GST_my_identity,
397 &address->peer,
398 sizeof(struct GNUNET_PeerIdentity)))
399 return; /* our own, ignore! */
400 ai = find_ai (address, session);
401 if (NULL == ai)
402 {
403 GNUNET_break (0);
404 return;
405 }
406 /* address is in successful use, so it should not be blocked right now */
407 GNUNET_break (NULL == ai->unblock_task);
408 ai->back_off = GNUNET_TIME_UNIT_ZERO;
409}
410
411
412/**
413 * Notify ATS about a new inbound @a address. The @a address in
414 * combination with the @a session must be new, but this function will
415 * perform a santiy check. If the @a address is indeed new, make it
416 * available to ATS.
417 *
418 * @param address the address
419 * @param session the session
420 * @param prop performance information
421 */
422void
423GST_ats_add_inbound_address (const struct GNUNET_HELLO_Address *address,
424 struct GNUNET_ATS_Session *session,
425 const struct GNUNET_ATS_Properties *prop)
426{
427 struct GNUNET_ATS_AddressRecord *ar;
428 struct AddressInfo *ai;
429
430 if (0 ==
431 memcmp (&GST_my_identity,
432 &address->peer,
433 sizeof(struct GNUNET_PeerIdentity)))
434 return; /* our own, ignore! */
435
436 /* Sanity checks for a valid inbound address */
437 if (NULL == address->transport_name)
438 {
439 GNUNET_break (0);
440 return;
441 }
442 GNUNET_break (GNUNET_NT_UNSPECIFIED != prop->scope);
443 GNUNET_assert (GNUNET_YES ==
444 GNUNET_HELLO_address_check_option (address,
445 GNUNET_HELLO_ADDRESS_INFO_INBOUND));
446 GNUNET_assert (NULL != session);
447 ai = find_ai (address, session);
448 if (NULL != ai)
449 {
450 /* This should only be called for new sessions, and thus
451 we should not already have the address */
452 GNUNET_break (0);
453 return;
454 }
455 /* Is indeed new, let's tell ATS */
456 LOG (GNUNET_ERROR_TYPE_DEBUG,
457 "Notifying ATS about peer `%s''s new inbound address `%s' session %p in network %s\n",
458 GNUNET_i2s (&address->peer),
459 GST_plugins_a2s (address),
460 session,
461 GNUNET_NT_to_string (prop->scope));
462 ar = GNUNET_ATS_address_add (GST_ats,
463 address,
464 session,
465 prop);
466 GNUNET_assert (NULL != ar);
467 ai = GNUNET_new (struct AddressInfo);
468 ai->address = GNUNET_HELLO_address_copy (address);
469 ai->session = session;
470 ai->properties = *prop;
471 ai->ar = ar;
472 (void) GNUNET_CONTAINER_multipeermap_put (p2a,
473 &ai->address->peer,
474 ai,
475 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
476 publish_p2a_stat_update ();
477}
478
479
480void
481GST_ats_add_address (const struct GNUNET_HELLO_Address *address,
482 const struct GNUNET_ATS_Properties *prop)
483{
484 struct GNUNET_ATS_AddressRecord *ar;
485 struct AddressInfo *ai;
486
487 if (0 ==
488 memcmp (&GST_my_identity,
489 &address->peer,
490 sizeof(struct GNUNET_PeerIdentity)))
491 return; /* our own, ignore! */
492 /* validadte address */
493 if (NULL == address->transport_name)
494 {
495 GNUNET_break (0);
496 return;
497 }
498 GNUNET_assert (GNUNET_YES !=
499 GNUNET_HELLO_address_check_option (address,
500 GNUNET_HELLO_ADDRESS_INFO_INBOUND));
501 ai = find_ai_no_session (address);
502 GNUNET_assert (NULL == ai);
503 GNUNET_break (GNUNET_NT_UNSPECIFIED != prop->scope);
504
505 /* address seems sane, let's tell ATS */
506 LOG (GNUNET_ERROR_TYPE_INFO,
507 "Notifying ATS about peer %s's new address `%s'\n",
508 GNUNET_i2s (&address->peer),
509 GST_plugins_a2s (address));
510 ar = GNUNET_ATS_address_add (GST_ats,
511 address,
512 NULL,
513 prop);
514 GNUNET_assert (NULL != ar);
515 ai = GNUNET_new (struct AddressInfo);
516 ai->address = GNUNET_HELLO_address_copy (address);
517 ai->ar = ar;
518 ai->properties = *prop;
519 (void) GNUNET_CONTAINER_multipeermap_put (p2a,
520 &ai->address->peer,
521 ai,
522 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
523 publish_p2a_stat_update ();
524}
525
526
527/**
528 * Notify ATS about a new @a session now existing for the given
529 * @a address. Essentially, an outbound @a address was used
530 * to establish a @a session. It is safe to call this function
531 * repeatedly for the same @a address and @a session pair.
532 *
533 * @param address the address
534 * @param session the session
535 */
536void
537GST_ats_new_session (const struct GNUNET_HELLO_Address *address,
538 struct GNUNET_ATS_Session *session)
539{
540 struct AddressInfo *ai;
541
542 if (0 ==
543 memcmp (&GST_my_identity,
544 &address->peer,
545 sizeof(struct GNUNET_PeerIdentity)))
546 return; /* our own, ignore! */
547 ai = find_ai (address, NULL);
548 if (NULL == ai)
549 {
550 /* We may simply already be aware of the session, even if some
551 other part of the code could not tell if it just created a new
552 session or just got one recycled from the plugin; hence, we may
553 be called with "new" session even for an "old" session; in that
554 case, check that this is the case, but just ignore it. */GNUNET_assert (NULL != (find_ai (address, session)));
555 return;
556 }
557 GNUNET_assert (NULL == ai->session);
558 ai->session = session;
559 LOG (GNUNET_ERROR_TYPE_DEBUG,
560 "Telling ATS about new session for peer %s\n",
561 GNUNET_i2s (&address->peer));
562 /* Note that the address might currently be blocked; we only
563 tell ATS about the session if the address is currently not
564 blocked; otherwise, ATS will be told about the session on
565 unblock. */
566 if (NULL != ai->ar)
567 GNUNET_ATS_address_add_session (ai->ar,
568 session);
569 else
570 GNUNET_assert (NULL != ai->unblock_task);
571}
572
573
574/**
575 * Release memory used by the given address data.
576 *
577 * @param ai the `struct AddressInfo`
578 */
579static void
580destroy_ai (struct AddressInfo *ai)
581{
582 GNUNET_assert (NULL == ai->session);
583 if (NULL != ai->unblock_task)
584 {
585 GNUNET_SCHEDULER_cancel (ai->unblock_task);
586 ai->unblock_task = NULL;
587 num_blocked--;
588 }
589 GNUNET_assert (GNUNET_YES ==
590 GNUNET_CONTAINER_multipeermap_remove (p2a,
591 &ai->address->peer,
592 ai));
593 LOG (GNUNET_ERROR_TYPE_DEBUG,
594 "Telling ATS to destroy address from peer %s\n",
595 GNUNET_i2s (&ai->address->peer));
596 if (NULL != ai->ar)
597 {
598 GNUNET_ATS_address_destroy (ai->ar);
599 ai->ar = NULL;
600 }
601 publish_p2a_stat_update ();
602 GNUNET_HELLO_address_free (ai->address);
603 GNUNET_free (ai);
604}
605
606
607/**
608 * Notify ATS that the @a session (but not the @a address) of
609 * a given @a address is no longer relevant. (The @a session
610 * went down.) This function may be called even if for the
611 * respective outbound address #GST_ats_new_session() was
612 * never called and thus the pair is unknown to ATS. In this
613 * case, the call is simply ignored.
614 *
615 * @param address the address
616 * @param session the session
617 */
618void
619GST_ats_del_session (const struct GNUNET_HELLO_Address *address,
620 struct GNUNET_ATS_Session *session)
621{
622 struct AddressInfo *ai;
623
624 if (0 ==
625 memcmp (&GST_my_identity,
626 &address->peer,
627 sizeof(struct GNUNET_PeerIdentity)))
628 return; /* our own, ignore! */
629 if (NULL == session)
630 {
631 GNUNET_break (0);
632 return;
633 }
634 ai = find_ai (address,
635 session);
636 if (NULL == ai)
637 {
638 /* We sometimes create sessions just for sending a PING,
639 and if those are destroyed they were never known to
640 ATS which means we end up here (however, in this
641 case, the address must be an outbound address). */
642 GNUNET_break (GNUNET_YES !=
643 GNUNET_HELLO_address_check_option (address,
644 GNUNET_HELLO_ADDRESS_INFO_INBOUND));
645 return;
646 }
647 GNUNET_assert (session == ai->session);
648 ai->session = NULL;
649 LOG (GNUNET_ERROR_TYPE_DEBUG,
650 "Telling ATS to destroy session %p from peer %s\n",
651 session,
652 GNUNET_i2s (&address->peer));
653 if (GNUNET_YES == ai->expired)
654 {
655 /* last reason to keep this 'ai' around is now gone, the
656 session is dead as well, clean up */
657 if (NULL != ai->ar)
658 {
659 /* Address expired but not blocked, and thus 'ar' was still
660 live because of the session; deleting just the session
661 will do for an inbound session, but for an outbound we
662 then also need to destroy the address with ATS. */
663 if (GNUNET_NO ==
664 GNUNET_ATS_address_del_session (ai->ar,
665 session))
666 {
667 GNUNET_ATS_address_destroy (ai->ar);
668 }
669 /* "ar" has been freed, regardless how the branch
670 above played out: it was either freed in
671 #GNUNET_ATS_address_del_session() because it was
672 incoming, or explicitly in
673 #GNUNET_ATS_address_del_session(). */ai->ar = NULL;
674 }
675 destroy_ai (ai);
676 return;
677 }
678
679 if (NULL == ai->ar)
680 {
681 /* If ATS doesn't know about the address/session, this means
682 this address was blocked. */
683 if (GNUNET_YES ==
684 GNUNET_HELLO_address_check_option (address,
685 GNUNET_HELLO_ADDRESS_INFO_INBOUND))
686 {
687 /* This was a blocked inbound session, which now lost the
688 session. But inbound addresses are by themselves useless,
689 so we must forget about the address as well. */
690 destroy_ai (ai);
691 return;
692 }
693 /* Otherwise, we are done as we have set `ai->session` to NULL
694 already and ATS will simply not be told about the session when
695 the connection is unblocked and the outbound address becomes
696 available again. . */
697 return;
698 }
699
700 /* This is the "simple" case where ATS knows about the session and
701 the address is neither blocked nor expired. Delete the session,
702 and if it was inbound, free the address as well. */
703 if (GNUNET_YES ==
704 GNUNET_ATS_address_del_session (ai->ar,
705 session))
706 {
707 /* This was an inbound address, the session is now gone, so we
708 need to also forget about the address itself. */
709 ai->ar = NULL;
710 destroy_ai (ai);
711 }
712}
713
714
715/**
716 * Notify ATS about DV @a distance change to an @a address.
717 * Does nothing if the @a address is not known to us.
718 *
719 * @param address the address
720 * @param distance new distance value
721 */
722void
723GST_ats_update_distance (const struct GNUNET_HELLO_Address *address,
724 uint32_t distance)
725{
726 struct AddressInfo *ai;
727
728 ai = find_ai_no_session (address);
729 if (NULL == ai)
730 {
731 /* We do not know about this address, do nothing. */
732 return;
733 }
734 LOG (GNUNET_ERROR_TYPE_DEBUG,
735 "Updated distance for peer `%s' to %u\n",
736 GNUNET_i2s (&address->peer),
737 distance);
738 ai->properties.distance = distance;
739 /* Give manipulation its chance to change metrics */
740 GST_manipulation_manipulate_metrics (address,
741 ai->session,
742 &ai->properties);
743 /* Address may be blocked, only give ATS if address is
744 currently active. */
745 if (NULL != ai->ar)
746 GNUNET_ATS_address_update (ai->ar,
747 &ai->properties);
748}
749
750
751void
752GST_ats_update_delay (const struct GNUNET_HELLO_Address *address,
753 struct GNUNET_TIME_Relative delay)
754{
755 struct AddressInfo *ai;
756
757 ai = find_ai_no_session (address);
758 if (NULL == ai)
759 {
760 /* We do not know about this address, do nothing. */
761 return;
762 }
763 LOG (GNUNET_ERROR_TYPE_DEBUG,
764 "Updated latency for peer `%s' to %s\n",
765 GNUNET_i2s (&address->peer),
766 GNUNET_STRINGS_relative_time_to_string (delay,
767 GNUNET_YES));
768 ai->properties.delay = delay;
769 /* Give manipulation its chance to change metrics */
770 GST_manipulation_manipulate_metrics (address,
771 ai->session,
772 &ai->properties);
773 /* Address may be blocked, only give ATS if address is
774 currently active. */
775 if (NULL != ai->ar)
776 GNUNET_ATS_address_update (ai->ar,
777 &ai->properties);
778}
779
780
781/**
782 * Notify ATS about utilization changes to an @a address.
783 * Does nothing if the @a address is not known to us.
784 *
785 * @param address our information about the address
786 * @param bps_in new utilization inbound
787 * @param bps_out new utilization outbound
788 */
789void
790GST_ats_update_utilization (const struct GNUNET_HELLO_Address *address,
791 uint32_t bps_in,
792 uint32_t bps_out)
793{
794 struct AddressInfo *ai;
795
796 ai = find_ai_no_session (address);
797 if (NULL == ai)
798 {
799 /* We do not know about this address, do nothing. */
800 return;
801 }
802 LOG (GNUNET_ERROR_TYPE_DEBUG,
803 "Updating utilization for peer `%s' address %s: %u/%u\n",
804 GNUNET_i2s (&address->peer),
805 GST_plugins_a2s (address),
806 (unsigned int) bps_in,
807 (unsigned int) bps_out);
808 ai->properties.utilization_in = bps_in;
809 ai->properties.utilization_out = bps_out;
810 /* Give manipulation its chance to change metrics */
811 GST_manipulation_manipulate_metrics (address,
812 ai->session,
813 &ai->properties);
814 /* Address may be blocked, only give ATS if address is
815 currently active. */
816 if (NULL != ai->ar)
817 GNUNET_ATS_address_update (ai->ar,
818 &ai->properties);
819}
820
821
822/**
823 * Notify ATS that the address has expired and thus cannot
824 * be used any longer. This function must only be called
825 * if the corresponding session is already gone.
826 *
827 * @param address the address
828 */
829void
830GST_ats_expire_address (const struct GNUNET_HELLO_Address *address)
831{
832 struct AddressInfo *ai;
833
834 if (0 ==
835 memcmp (&GST_my_identity,
836 &address->peer,
837 sizeof(struct GNUNET_PeerIdentity)))
838 return; /* our own, ignore! */
839 LOG (GNUNET_ERROR_TYPE_DEBUG,
840 "Address %s of peer %s expired\n",
841 GST_plugins_a2s (address),
842 GNUNET_i2s (&address->peer));
843 ai = find_ai_no_session (address);
844 if (NULL == ai)
845 {
846 GNUNET_assert (0);
847 return;
848 }
849 if (NULL != ai->session)
850 {
851 /* Got an active session, just remember the expiration
852 and act upon it when the session goes down. */
853 ai->expired = GNUNET_YES;
854 return;
855 }
856 /* Address expired, no session, free resources */
857 destroy_ai (ai);
858}
859
860
861/**
862 * Initialize ATS subsystem.
863 */
864void
865GST_ats_init ()
866{
867 p2a = GNUNET_CONTAINER_multipeermap_create (4, GNUNET_YES);
868}
869
870
871/**
872 * Release memory used by the given address data.
873 *
874 * @param cls NULL
875 * @param key which peer is this about
876 * @param value the `struct AddressInfo`
877 * @return #GNUNET_OK (continue to iterate)
878 */
879static int
880destroy_ai_cb (void *cls,
881 const struct GNUNET_PeerIdentity *key,
882 void *value)
883{
884 struct AddressInfo *ai = value;
885
886 destroy_ai (ai);
887 return GNUNET_OK;
888}
889
890
891/**
892 * Shutdown ATS subsystem.
893 */
894void
895GST_ats_done ()
896{
897 GNUNET_CONTAINER_multipeermap_iterate (p2a,
898 &destroy_ai_cb,
899 NULL);
900 publish_p2a_stat_update ();
901 GNUNET_CONTAINER_multipeermap_destroy (p2a);
902 p2a = NULL;
903}
904
905
906/* end of gnunet-service-transport_ats.c */
diff --git a/src/transport/gnunet-service-transport_ats.h b/src/transport/gnunet-service-transport_ats.h
deleted file mode 100644
index ca972d1cc..000000000
--- a/src/transport/gnunet-service-transport_ats.h
+++ /dev/null
@@ -1,203 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2015 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport/gnunet-service-transport_ats.h
22 * @brief interfacing between transport and ATS service
23 * @author Christian Grothoff
24 */
25#ifndef GNUNET_SERVICE_TRANSPORT_ATS_H
26#define GNUNET_SERVICE_TRANSPORT_ATS_H
27
28#include "gnunet_ats_service.h"
29
30/**
31 * Initialize ATS subsystem.
32 */
33void
34GST_ats_init (void);
35
36
37/**
38 * Shutdown ATS subsystem.
39 */
40void
41GST_ats_done (void);
42
43
44/**
45 * Test if ATS knows about this @a address and @a session.
46 * Note that even if the address is expired, we return
47 * #GNUNET_YES if the respective session matches.
48 *
49 * @param address the address
50 * @param session the session
51 * @return #GNUNET_YES if @a address is known, #GNUNET_NO if not.
52 */
53int
54GST_ats_is_known (const struct GNUNET_HELLO_Address *address,
55 struct GNUNET_ATS_Session *session);
56
57
58/**
59 * Test if ATS knows about this @a address. Note that
60 * expired addresses do not count.
61 *
62 * @param address the address
63 * @return #GNUNET_YES if @a address is known, #GNUNET_NO if not.
64 */
65int
66GST_ats_is_known_no_session (const struct GNUNET_HELLO_Address *address);
67
68
69/**
70 * Temporarily block a valid address for use by ATS for address
71 * suggestions. This function should be called if an address was
72 * suggested by ATS but failed to perform (i.e. failure to establish a
73 * session or to exchange the PING/PONG).
74 *
75 * @param address the address to block
76 * @param session the session (can be NULL)
77 */
78void
79GST_ats_block_address (const struct GNUNET_HELLO_Address *address,
80 struct GNUNET_ATS_Session *session);
81
82
83/**
84 * Reset address blocking time. Resets the exponential
85 * back-off timer for this address to zero. Called when
86 * an address was used to create a successful connection.
87 *
88 * @param address the address to reset the blocking timer
89 * @param session the session (can be NULL)
90 */
91void
92GST_ats_block_reset (const struct GNUNET_HELLO_Address *address,
93 struct GNUNET_ATS_Session *session);
94
95
96/**
97 * Notify ATS about a new inbound @a address. The @a address in
98 * combination with the @a session must be new, but this function will
99 * perform a santiy check. If the @a address is indeed new, make it
100 * available to ATS.
101 *
102 * @param address the address
103 * @param session the session
104 * @param prop performance information
105 */
106void
107GST_ats_add_inbound_address (const struct GNUNET_HELLO_Address *address,
108 struct GNUNET_ATS_Session *session,
109 const struct GNUNET_ATS_Properties *prop);
110
111
112/**
113 * Notify ATS about a new address including the network the address is
114 * located in. The address must NOT be inbound and must be new to ATS.
115 *
116 * @param address the address
117 * @param prop performance information
118 */
119void
120GST_ats_add_address (const struct GNUNET_HELLO_Address *address,
121 const struct GNUNET_ATS_Properties *prop);
122
123
124/**
125 * Notify ATS about a new @a session now existing for the given
126 * @a address. Essentially, an outbound @a address was used
127 * to establish a @a session. It is safe to call this function
128 * repeatedly for the same @a address and @a session pair.
129 *
130 * @param address the address
131 * @param session the session
132 */
133void
134GST_ats_new_session (const struct GNUNET_HELLO_Address *address,
135 struct GNUNET_ATS_Session *session);
136
137
138/**
139 * Notify ATS about utilization changes to an @a address.
140 * Does nothing if the @a address is not known to us.
141 *
142 * @param address our information about the address
143 * @param bps_in new utilization inbound
144 * @param bps_out new utilization outbound
145 */
146void
147GST_ats_update_utilization (const struct GNUNET_HELLO_Address *address,
148 uint32_t bps_in,
149 uint32_t bps_out);
150
151
152/**
153 * Notify ATS about @a delay changes to properties of an @a address.
154 * Does nothing if the @a address is not known to us.
155 *
156 * @param address the address
157 * @param delay new delay value
158 */
159void
160GST_ats_update_delay (const struct GNUNET_HELLO_Address *address,
161 struct GNUNET_TIME_Relative delay);
162
163
164/**
165 * Notify ATS about DV @a distance change to an @a address.
166 * Does nothing if the @a address is not known to us.
167 *
168 * @param address the address
169 * @param distance new distance value
170 */
171void
172GST_ats_update_distance (const struct GNUNET_HELLO_Address *address,
173 uint32_t distance);
174
175
176/**
177 * Notify ATS that the @a session (but not the @a address) of
178 * a given @a address is no longer relevant. (The @a session
179 * went down.) This function may be called even if for the
180 * respective outbound address #GST_ats_new_session() was
181 * never called and thus the pair is unknown to ATS. In this
182 * case, the call is simply ignored.
183 *
184 * @param address the address
185 * @param session the session
186 */
187void
188GST_ats_del_session (const struct GNUNET_HELLO_Address *address,
189 struct GNUNET_ATS_Session *session);
190
191
192/**
193 * Notify ATS that the address has expired and thus cannot
194 * be used any longer. This function must only be called
195 * if the corresponding session is already gone.
196 *
197 * @param address the address
198 */
199void
200GST_ats_expire_address (const struct GNUNET_HELLO_Address *address);
201
202
203#endif
diff --git a/src/transport/gnunet-service-transport_hello.c b/src/transport/gnunet-service-transport_hello.c
deleted file mode 100644
index 1e5e8a225..000000000
--- a/src/transport/gnunet-service-transport_hello.c
+++ /dev/null
@@ -1,358 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010,2011 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/gnunet-service-transport_hello.c
23 * @brief hello management implementation
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_constants.h"
28#include "gnunet_hello_lib.h"
29#include "gnunet_peerinfo_service.h"
30#include "gnunet_statistics_service.h"
31#include "gnunet-service-transport_hello.h"
32#include "gnunet-service-transport.h"
33#include "gnunet-service-transport_plugins.h"
34
35
36/**
37 * How often do we refresh our HELLO (due to expiration concerns)?
38 */
39#define HELLO_REFRESH_PERIOD GNUNET_TIME_relative_multiply ( \
40 GNUNET_TIME_UNIT_HOURS, 6)
41
42/**
43 * Hello address expiration
44 */
45extern struct GNUNET_TIME_Relative hello_expiration;
46
47
48/**
49 * Entry in linked list of network addresses for ourselves. Also
50 * includes a cached signature for 'struct TransportPongMessage's.
51 */
52struct OwnAddressList
53{
54 /**
55 * This is a doubly-linked list.
56 */
57 struct OwnAddressList *next;
58
59 /**
60 * This is a doubly-linked list.
61 */
62 struct OwnAddressList *prev;
63
64 /**
65 * The address.
66 */
67 struct GNUNET_HELLO_Address *address;
68
69 /**
70 * How long until the current signature expires? (ZERO if the
71 * signature was never created).
72 */
73 struct GNUNET_TIME_Absolute pong_sig_expires;
74
75 /**
76 * Signature for a 'struct TransportPongMessage' for this address.
77 */
78 struct GNUNET_CRYPTO_EddsaSignature pong_signature;
79
80 /**
81 * How often has this address been added/removed? Used as
82 * some plugins may learn the same external address from
83 * multiple origins.
84 */
85 unsigned int rc;
86};
87
88
89/**
90 * Our HELLO message.
91 */
92static struct GNUNET_HELLO_Message *our_hello;
93
94/**
95 * Function to call on HELLO changes.
96 */
97static GST_HelloCallback hello_cb;
98
99/**
100 * Closure for #hello_cb.
101 */
102static void *hello_cb_cls;
103
104/**
105 * Head of my addresses.
106 */
107static struct OwnAddressList *oal_head;
108
109/**
110 * Tail of my addresses.
111 */
112static struct OwnAddressList *oal_tail;
113
114/**
115 * Should we use a friend-only HELLO?
116 */
117static int friend_option;
118
119/**
120 * Identifier of #refresh_hello_task().
121 */
122static struct GNUNET_SCHEDULER_Task *hello_task;
123
124
125/**
126 * Closure for #address_generator().
127 */
128struct GeneratorContext
129{
130 /**
131 * Where are we in the DLL?
132 */
133 struct OwnAddressList *addr_pos;
134
135 /**
136 * When do addresses expire?
137 */
138 struct GNUNET_TIME_Absolute expiration;
139};
140
141
142/**
143 * Add an address from the `struct OwnAddressList` to the buffer.
144 *
145 * @param cls the `struct GeneratorContext`
146 * @param max maximum number of bytes left
147 * @param buf where to write the address
148 * @return bytes written or #GNUNET_SYSERR to signal the
149 * end of the iteration.
150 */
151static ssize_t
152address_generator (void *cls,
153 size_t max,
154 void *buf)
155{
156 struct GeneratorContext *gc = cls;
157 ssize_t ret;
158
159 if (NULL == gc->addr_pos)
160 return GNUNET_SYSERR; /* Done */
161 ret = GNUNET_HELLO_add_address (gc->addr_pos->address,
162 gc->expiration,
163 buf,
164 max);
165 gc->addr_pos = gc->addr_pos->next;
166 return ret;
167}
168
169
170/**
171 * Construct our HELLO message from all of the addresses of
172 * all of the transports.
173 *
174 * @param cls unused
175 */
176static void
177refresh_hello_task (void *cls)
178{
179 struct GeneratorContext gc;
180
181 hello_task = NULL;
182 gc.addr_pos = oal_head;
183 gc.expiration = GNUNET_TIME_relative_to_absolute (hello_expiration);
184
185 GNUNET_free (our_hello);
186 our_hello = GNUNET_HELLO_create (&GST_my_identity.public_key,
187 &address_generator,
188 &gc,
189 friend_option);
190 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
191 "Refreshed my %s HELLO, new size is %d\n",
192 (GNUNET_YES == friend_option) ? "friend-only" : "public",
193 GNUNET_HELLO_size (our_hello));
194 GNUNET_STATISTICS_update (GST_stats,
195 gettext_noop ("# refreshed my HELLO"),
196 1,
197 GNUNET_NO);
198 if (NULL != hello_cb)
199 hello_cb (hello_cb_cls,
200 GST_hello_get ());
201 GNUNET_PEERINFO_add_peer (GST_peerinfo,
202 our_hello,
203 NULL,
204 NULL);
205 hello_task =
206 GNUNET_SCHEDULER_add_delayed (HELLO_REFRESH_PERIOD,
207 &refresh_hello_task,
208 NULL);
209}
210
211
212/**
213 * Schedule task to refresh hello (but only if such a
214 * task exists already, as otherwise the module might
215 * have been shutdown).
216 */
217static void
218refresh_hello ()
219{
220 if (NULL != hello_task)
221 {
222 GNUNET_SCHEDULER_cancel (hello_task);
223 hello_task = GNUNET_SCHEDULER_add_now (&refresh_hello_task,
224 NULL);
225 }
226}
227
228
229/**
230 * Initialize the HELLO module.
231 *
232 * @param friend_only use a friend only hello
233 * @param cb function to call whenever our HELLO changes
234 * @param cb_cls closure for @a cb
235 */
236void
237GST_hello_start (int friend_only,
238 GST_HelloCallback cb,
239 void *cb_cls)
240{
241 hello_cb = cb;
242 hello_cb_cls = cb_cls;
243 friend_option = friend_only;
244 refresh_hello_task (NULL);
245}
246
247
248/**
249 * Shutdown the HELLO module.
250 */
251void
252GST_hello_stop ()
253{
254 hello_cb = NULL;
255 hello_cb_cls = NULL;
256 if (NULL != hello_task)
257 {
258 GNUNET_SCHEDULER_cancel (hello_task);
259 hello_task = NULL;
260 }
261 if (NULL != our_hello)
262 {
263 GNUNET_free (our_hello);
264 our_hello = NULL;
265 }
266}
267
268
269/**
270 * Obtain this peers HELLO message.
271 *
272 * @return our HELLO message
273 */
274const struct GNUNET_MessageHeader *
275GST_hello_get ()
276{
277 return (const struct GNUNET_MessageHeader *) our_hello;
278}
279
280
281/**
282 * Add or remove an address from this peer's HELLO message.
283 *
284 * @param addremove #GNUNET_YES to add, #GNUNET_NO to remove
285 * @param address address to add or remove
286 */
287void
288GST_hello_modify_addresses (int addremove,
289 const struct GNUNET_HELLO_Address *address)
290{
291 struct OwnAddressList *al;
292
293 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
294 (GNUNET_YES == addremove)
295 ? "Adding `%s' to the set of our addresses\n"
296 : "Removing `%s' from the set of our addresses\n",
297 GST_plugins_a2s (address));
298 GNUNET_assert (NULL != address);
299 for (al = oal_head; al != NULL; al = al->next)
300 if (0 == GNUNET_HELLO_address_cmp (address, al->address))
301 break;
302 if (GNUNET_NO == addremove)
303 {
304 if (NULL == al)
305 {
306 /* address to be removed not found!? */
307 GNUNET_break (0);
308 return;
309 }
310 al->rc--;
311 if (0 != al->rc)
312 return; /* RC not yet zero */
313 GNUNET_CONTAINER_DLL_remove (oal_head,
314 oal_tail,
315 al);
316 GNUNET_HELLO_address_free (al->address);
317 GNUNET_free (al);
318 refresh_hello ();
319 return;
320 }
321 if (NULL != al)
322 {
323 /* address added twice or more */
324 al->rc++;
325 return;
326 }
327 al = GNUNET_new (struct OwnAddressList);
328 al->rc = 1;
329 GNUNET_CONTAINER_DLL_insert (oal_head,
330 oal_tail,
331 al);
332 al->address = GNUNET_HELLO_address_copy (address);
333 refresh_hello ();
334}
335
336
337int
338GST_hello_test_address (const struct GNUNET_HELLO_Address *address,
339 struct GNUNET_CRYPTO_EddsaSignature **sig,
340 struct GNUNET_TIME_Absolute **sig_expiration)
341{
342 struct OwnAddressList *al;
343
344 for (al = oal_head; al != NULL; al = al->next)
345 if (0 == GNUNET_HELLO_address_cmp (address,
346 al->address))
347 {
348 *sig = &al->pong_signature;
349 *sig_expiration = &al->pong_sig_expires;
350 return GNUNET_YES;
351 }
352 *sig = NULL;
353 *sig_expiration = NULL;
354 return GNUNET_NO;
355}
356
357
358/* end of file gnunet-service-transport_hello.c */
diff --git a/src/transport/gnunet-service-transport_hello.h b/src/transport/gnunet-service-transport_hello.h
deleted file mode 100644
index be089dd35..000000000
--- a/src/transport/gnunet-service-transport_hello.h
+++ /dev/null
@@ -1,102 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010,2011 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport/gnunet-service-transport_hello.h
22 * @brief hello API
23 * @author Christian Grothoff
24 */
25#ifndef GNUNET_SERVICE_TRANSPORT_HELLO_H
26#define GNUNET_SERVICE_TRANSPORT_HELLO_H
27
28#include "gnunet_statistics_service.h"
29#include "gnunet_transport_service.h"
30#include "gnunet_util_lib.h"
31#include "gnunet_hello_lib.h"
32
33
34/**
35 * Signature of a function to call whenever our hello changes.
36 *
37 * @param cls closure
38 * @param hello updated HELLO
39 */
40typedef void
41(*GST_HelloCallback) (void *cls,
42 const struct GNUNET_MessageHeader *hello);
43
44
45/**
46 * Initialize the HELLO module.
47 *
48 * @param friend_only use a friend only hello
49 * @param cb function to call whenever our HELLO changes
50 * @param cb_cls closure for @a cb
51 */
52void
53GST_hello_start (int friend_only,
54 GST_HelloCallback cb,
55 void *cb_cls);
56
57
58/**
59 * Shutdown the HELLO module.
60 */
61void
62GST_hello_stop (void);
63
64
65/**
66 * Obtain this peers HELLO message.
67 *
68 * @return our HELLO message
69 */
70const struct GNUNET_MessageHeader *
71GST_hello_get (void);
72
73
74/**
75 * Add or remove an address from this peer's HELLO message.
76 *
77 * @param addremove #GNUNET_YES to add, #GNUNET_NO to remove
78 * @param address address to add or remove
79 */
80void
81GST_hello_modify_addresses (int addremove,
82 const struct GNUNET_HELLO_Address *address);
83
84
85/**
86 * Test if a particular address is one of ours.
87 *
88 * @param address the address to test
89 * @param sig location where to cache PONG signatures for this address [set]
90 * @param sig_expiration how long until the current 'sig' expires?
91 * (ZERO if sig was never created) [set]
92 * @return #GNUNET_YES if this is one of our addresses,
93 * #GNUNET_NO if not
94 */
95int
96GST_hello_test_address (const struct GNUNET_HELLO_Address *address,
97 struct GNUNET_CRYPTO_EddsaSignature **sig,
98 struct GNUNET_TIME_Absolute **sig_expiration);
99
100
101#endif
102/* end of file gnunet-service-transport_hello.h */
diff --git a/src/transport/gnunet-service-transport_manipulation.c b/src/transport/gnunet-service-transport_manipulation.c
deleted file mode 100644
index 9f39b2dca..000000000
--- a/src/transport/gnunet-service-transport_manipulation.c
+++ /dev/null
@@ -1,586 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010-2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/gnunet-service-transport_manipulation.c
23 * @brief transport component manipulation traffic for simulation
24 * @author Christian Grothoff
25 * @author Matthias Wachs
26 */
27#include "platform.h"
28#include "gnunet-service-transport_hello.h"
29#include "gnunet-service-transport_neighbours.h"
30#include "gnunet-service-transport_plugins.h"
31#include "gnunet-service-transport_validation.h"
32#include "gnunet-service-transport.h"
33#include "transport.h"
34
35
36/**
37 * Struct containing information about manipulations to a specific peer
38 */
39struct TM_Peer
40{
41 /**
42 * Peer ID
43 */
44 struct GNUNET_PeerIdentity peer;
45
46 /**
47 * How long to delay incoming messages for this peer.
48 */
49 struct GNUNET_TIME_Relative delay_in;
50
51 /**
52 * How long to delay outgoing messages for this peer.
53 */
54 struct GNUNET_TIME_Relative delay_out;
55
56 /**
57 * Manipulated properties to use for this peer.
58 */
59 struct GNUNET_ATS_Properties properties;
60
61 /**
62 * Task to schedule delayed sendding
63 */
64 struct GNUNET_SCHEDULER_Task *send_delay_task;
65
66 /**
67 * Send queue DLL head
68 */
69 struct DelayQueueEntry *send_head;
70
71 /**
72 * Send queue DLL tail
73 */
74 struct DelayQueueEntry *send_tail;
75};
76
77
78/**
79 * Entry in the delay queue for an outbound delayed message
80 */
81struct DelayQueueEntry
82{
83 /**
84 * Next in DLL
85 */
86 struct DelayQueueEntry *prev;
87
88 /**
89 * Previous in DLL
90 */
91 struct DelayQueueEntry *next;
92
93 /**
94 * Peer this entry is belonging to if (NULL == tmp): enqueued in
95 * generic DLL and scheduled by generic_send_delay_task else:
96 * enqueued in tmp->send_head and tmp->send_tail and scheduled by
97 * tmp->send_delay_task
98 */
99 struct TM_Peer *tmp;
100
101 /**
102 * Peer ID
103 */
104 struct GNUNET_PeerIdentity id;
105
106 /**
107 * Absolute time when to send
108 */
109 struct GNUNET_TIME_Absolute sent_at;
110
111 /**
112 * The message
113 */
114 void *msg;
115
116 /**
117 * The message size
118 */
119 size_t msg_size;
120
121 /**
122 * Message timeout
123 */
124 struct GNUNET_TIME_Relative timeout;
125
126 /**
127 * Transports send continuation
128 */
129 GST_NeighbourSendContinuation cont;
130
131 /**
132 * Transports send continuation cls
133 */
134 void *cont_cls;
135};
136
137/**
138 * Hashmap contain all peers currently manipulated
139 */
140static struct GNUNET_CONTAINER_MultiPeerMap *peers;
141
142/**
143 * Inbound delay to apply to all peers.
144 */
145static struct GNUNET_TIME_Relative delay_in;
146
147/**
148 * Outbound delay to apply to all peers.
149 */
150static struct GNUNET_TIME_Relative delay_out;
151
152/**
153 * DLL head for delayed messages based on general delay
154 */
155static struct DelayQueueEntry *generic_dqe_head;
156
157/**
158 * DLL tail for delayed messages based on general delay
159 */
160static struct DelayQueueEntry *generic_dqe_tail;
161
162/**
163 * Task to schedule delayed sending based on general delay
164 */
165static struct GNUNET_SCHEDULER_Task *generic_send_delay_task;
166
167
168/**
169 * Set traffic metric to manipulate
170 *
171 * @param tm message containing information
172 */
173void
174GST_manipulation_set_metric (const struct TrafficMetricMessage *tm)
175{
176 static struct GNUNET_PeerIdentity zero;
177 struct TM_Peer *tmp;
178
179 if (0 == memcmp (&tm->peer,
180 &zero,
181 sizeof(struct GNUNET_PeerIdentity)))
182 {
183 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
184 "Received traffic metrics for all peers\n");
185 delay_in = GNUNET_TIME_relative_ntoh (tm->delay_in);
186 delay_out = GNUNET_TIME_relative_ntoh (tm->delay_out);
187 return;
188 }
189 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
190 "Received traffic metrics for peer `%s'\n",
191 GNUNET_i2s (&tm->peer));
192 if (NULL ==
193 (tmp = GNUNET_CONTAINER_multipeermap_get (peers,
194 &tm->peer)))
195 {
196 tmp = GNUNET_new (struct TM_Peer);
197 tmp->peer = tm->peer;
198 GNUNET_CONTAINER_multipeermap_put (peers,
199 &tm->peer,
200 tmp,
201 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
202 }
203 GNUNET_ATS_properties_ntoh (&tmp->properties,
204 &tm->properties);
205 tmp->delay_in = GNUNET_TIME_relative_ntoh (tm->delay_in);
206 tmp->delay_out = GNUNET_TIME_relative_ntoh (tm->delay_out);
207}
208
209
210/**
211 * We have delayed transmission, now it is time to send the
212 * message.
213 *
214 * @param cls the `struct DelayQueueEntry` to transmit
215 */
216static void
217send_delayed (void *cls)
218{
219 struct DelayQueueEntry *dqe = cls;
220 struct DelayQueueEntry *next;
221 struct TM_Peer *tmp = dqe->tmp;
222
223 GNUNET_break (GNUNET_YES ==
224 GST_neighbours_test_connected (&dqe->id));
225 if (NULL != tmp)
226 {
227 tmp->send_delay_task = NULL;
228 GNUNET_CONTAINER_DLL_remove (tmp->send_head,
229 tmp->send_tail,
230 dqe);
231 next = tmp->send_head;
232 if (NULL != next)
233 {
234 /* More delayed messages */
235 tmp->send_delay_task = GNUNET_SCHEDULER_add_at (next->sent_at,
236 &send_delayed,
237 next);
238 }
239 }
240 else
241 {
242 /* Remove from generic queue */
243 generic_send_delay_task = NULL;
244 GNUNET_CONTAINER_DLL_remove (generic_dqe_head,
245 generic_dqe_tail,
246 dqe);
247 next = generic_dqe_head;
248 if (NULL != next)
249 {
250 /* More delayed messages */
251 generic_send_delay_task = GNUNET_SCHEDULER_add_at (next->sent_at,
252 &send_delayed,
253 next);
254 }
255 }
256 GST_neighbours_send (&dqe->id,
257 dqe->msg,
258 dqe->msg_size,
259 dqe->timeout,
260 dqe->cont,
261 dqe->cont_cls);
262 GNUNET_free (dqe);
263}
264
265
266/**
267 * Adapter function between transport's send function and transport plugins.
268 * Delays message transmission if an artificial delay is configured.
269 *
270 * @param target the peer the message to send to
271 * @param msg the message received
272 * @param msg_size message size
273 * @param timeout timeout
274 * @param cont the continuation to call after sending
275 * @param cont_cls cls for @a cont
276 */
277void
278GST_manipulation_send (const struct GNUNET_PeerIdentity *target,
279 const void *msg,
280 size_t msg_size,
281 struct GNUNET_TIME_Relative timeout,
282 GST_NeighbourSendContinuation cont,
283 void *cont_cls)
284{
285 struct TM_Peer *tmp;
286 struct DelayQueueEntry *dqe;
287 struct GNUNET_TIME_Relative delay;
288
289 if (NULL != (tmp =
290 GNUNET_CONTAINER_multipeermap_get (peers,
291 target)))
292 delay = tmp->delay_out;
293 else
294 delay = delay_out;
295 if (0 == delay.rel_value_us)
296 {
297 /* Normal sending */
298 GST_neighbours_send (target,
299 msg,
300 msg_size,
301 timeout,
302 cont, cont_cls);
303 return;
304 }
305 dqe = GNUNET_malloc (sizeof(struct DelayQueueEntry) + msg_size);
306 dqe->id = *target;
307 dqe->tmp = tmp;
308 dqe->sent_at = GNUNET_TIME_relative_to_absolute (delay);
309 dqe->cont = cont;
310 dqe->cont_cls = cont_cls;
311 dqe->msg = &dqe[1];
312 dqe->msg_size = msg_size;
313 dqe->timeout = timeout;
314 GNUNET_memcpy (dqe->msg,
315 msg,
316 msg_size);
317 if (NULL == tmp)
318 {
319 GNUNET_CONTAINER_DLL_insert_tail (generic_dqe_head,
320 generic_dqe_tail,
321 dqe);
322 if (NULL == generic_send_delay_task)
323 generic_send_delay_task = GNUNET_SCHEDULER_add_delayed (delay,
324 &send_delayed,
325 dqe);
326 }
327 else
328 {
329 GNUNET_CONTAINER_DLL_insert_tail (tmp->send_head,
330 tmp->send_tail,
331 dqe);
332 if (NULL == tmp->send_delay_task)
333 tmp->send_delay_task = GNUNET_SCHEDULER_add_delayed (delay,
334 &send_delayed,
335 dqe);
336 }
337 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
338 "Delaying %u byte message to peer `%s' with peer specific delay for %s\n",
339 (unsigned int) msg_size,
340 GNUNET_i2s (target),
341 GNUNET_STRINGS_relative_time_to_string (delay,
342 GNUNET_YES));
343}
344
345
346/**
347 * Function that will be called to manipulate ATS information according to
348 * current manipulation settings
349 *
350 * @param address binary address
351 * @param session the session
352 * @param[in,out] prop metrics to modify
353 */
354void
355GST_manipulation_manipulate_metrics (const struct GNUNET_HELLO_Address *address,
356 struct GNUNET_ATS_Session *session,
357 struct GNUNET_ATS_Properties *prop)
358{
359 const struct GNUNET_PeerIdentity *peer = &address->peer;
360 struct TM_Peer *tmp;
361
362 tmp = GNUNET_CONTAINER_multipeermap_get (peers,
363 peer);
364 if (NULL != tmp)
365 *prop = tmp->properties;
366}
367
368
369/**
370 * Adapter function between transport plugins and transport receive function
371 * manipulation delays for next send.
372 *
373 * @param cls the closure for transport
374 * @param address the address and the peer the message was received from
375 * @param message the message received
376 * @param session the session the message was received on
377 * @return manipulated delay for next receive
378 */
379struct GNUNET_TIME_Relative
380GST_manipulation_recv (void *cls,
381 const struct GNUNET_HELLO_Address *address,
382 struct GNUNET_ATS_Session *session,
383 const struct GNUNET_MessageHeader *message)
384{
385 struct TM_Peer *tmp;
386 struct GNUNET_TIME_Relative quota_delay;
387 struct GNUNET_TIME_Relative m_delay;
388
389 if (NULL !=
390 (tmp = GNUNET_CONTAINER_multipeermap_get (peers,
391 &address->peer)))
392 m_delay = tmp->delay_in;
393 else
394 m_delay = delay_in;
395
396 quota_delay = GST_receive_callback (cls,
397 address,
398 session,
399 message);
400 m_delay = GNUNET_TIME_relative_max (m_delay,
401 quota_delay);
402 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
403 "Delaying next receive for peer `%s' for %s\n",
404 GNUNET_i2s (&address->peer),
405 GNUNET_STRINGS_relative_time_to_string (m_delay,
406 GNUNET_YES));
407 return m_delay;
408}
409
410
411/**
412 * Initialize traffic manipulation
413 */
414void
415GST_manipulation_init ()
416{
417 struct GNUNET_TIME_Relative delay;
418
419 if ((GNUNET_OK ==
420 GNUNET_CONFIGURATION_get_value_time (GST_cfg,
421 "transport",
422 "MANIPULATE_DELAY_IN",
423 &delay)) &&
424 (delay.rel_value_us > 0))
425 {
426 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
427 "Delaying inbound traffic for %s\n",
428 GNUNET_STRINGS_relative_time_to_string (delay,
429 GNUNET_YES));
430 delay_in = delay;
431 }
432 if ((GNUNET_OK ==
433 GNUNET_CONFIGURATION_get_value_time (GST_cfg,
434 "transport",
435 "MANIPULATE_DELAY_OUT",
436 &delay)) &&
437 (delay.rel_value_us > 0))
438 {
439 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
440 "Delaying outbound traffic for %s\n",
441 GNUNET_STRINGS_relative_time_to_string (delay,
442 GNUNET_YES));
443 delay_out = delay;
444 }
445 peers = GNUNET_CONTAINER_multipeermap_create (4,
446 GNUNET_NO);
447}
448
449
450/**
451 * Notify manipulation about disconnect so it can discard queued messages
452 *
453 * @param peer the disconnecting peer
454 */
455void
456GST_manipulation_peer_disconnect (const struct GNUNET_PeerIdentity *peer)
457{
458 struct TM_Peer *tmp;
459 struct DelayQueueEntry *dqe;
460 struct DelayQueueEntry *next;
461
462 tmp = GNUNET_CONTAINER_multipeermap_get (peers,
463 peer);
464 if (NULL != tmp)
465 {
466 while (NULL != (dqe = tmp->send_head))
467 {
468 GNUNET_CONTAINER_DLL_remove (tmp->send_head,
469 tmp->send_tail,
470 dqe);
471 if (NULL != dqe->cont)
472 dqe->cont (dqe->cont_cls,
473 GNUNET_SYSERR,
474 dqe->msg_size,
475 0);
476 GNUNET_free (dqe);
477 }
478 }
479 next = generic_dqe_head;
480 while (NULL != (dqe = next))
481 {
482 next = dqe->next;
483 if (0 == memcmp (peer,
484 &dqe->id,
485 sizeof(dqe->id)))
486 {
487 GNUNET_CONTAINER_DLL_remove (generic_dqe_head,
488 generic_dqe_tail,
489 dqe);
490 if (NULL != dqe->cont)
491 dqe->cont (dqe->cont_cls,
492 GNUNET_SYSERR,
493 dqe->msg_size,
494 0);
495 GNUNET_free (dqe);
496 }
497 }
498 if (NULL != generic_send_delay_task)
499 {
500 GNUNET_SCHEDULER_cancel (generic_send_delay_task);
501 generic_send_delay_task = NULL;
502 if (NULL != generic_dqe_head)
503 generic_send_delay_task
504 = GNUNET_SCHEDULER_add_at (generic_dqe_head->sent_at,
505 &send_delayed,
506 generic_dqe_head);
507 }
508}
509
510
511/**
512 * Free manipulation information about a peer.
513 *
514 * @param cls NULL
515 * @param key peer the info is about
516 * @param value a `struct TM_Peer` to free
517 * @return #GNUNET_OK (continue to iterate)
518 */
519static int
520free_tmps (void *cls,
521 const struct GNUNET_PeerIdentity *key,
522 void *value)
523{
524 struct TM_Peer *tmp = value;
525 struct DelayQueueEntry *dqe;
526
527 GNUNET_break (GNUNET_YES ==
528 GNUNET_CONTAINER_multipeermap_remove (peers,
529 key,
530 value));
531 while (NULL != (dqe = tmp->send_head))
532 {
533 GNUNET_CONTAINER_DLL_remove (tmp->send_head,
534 tmp->send_tail,
535 dqe);
536 if (NULL != dqe->cont)
537 dqe->cont (dqe->cont_cls,
538 GNUNET_SYSERR,
539 dqe->msg_size,
540 0);
541 GNUNET_free (dqe);
542 }
543 if (NULL != tmp->send_delay_task)
544 {
545 GNUNET_SCHEDULER_cancel (tmp->send_delay_task);
546 tmp->send_delay_task = NULL;
547 }
548 GNUNET_free (tmp);
549 return GNUNET_OK;
550}
551
552
553/**
554 * Stop traffic manipulation
555 */
556void
557GST_manipulation_stop ()
558{
559 struct DelayQueueEntry *cur;
560
561 GNUNET_CONTAINER_multipeermap_iterate (peers,
562 &free_tmps,
563 NULL);
564 GNUNET_CONTAINER_multipeermap_destroy (peers);
565 peers = NULL;
566 while (NULL != (cur = generic_dqe_head))
567 {
568 GNUNET_CONTAINER_DLL_remove (generic_dqe_head,
569 generic_dqe_tail,
570 cur);
571 if (NULL != cur->cont)
572 cur->cont (cur->cont_cls,
573 GNUNET_SYSERR,
574 cur->msg_size,
575 0);
576 GNUNET_free (cur);
577 }
578 if (NULL != generic_send_delay_task)
579 {
580 GNUNET_SCHEDULER_cancel (generic_send_delay_task);
581 generic_send_delay_task = NULL;
582 }
583}
584
585
586/* end of file gnunet-service-transport_manipulation.c */
diff --git a/src/transport/gnunet-service-transport_manipulation.h b/src/transport/gnunet-service-transport_manipulation.h
deleted file mode 100644
index b84f3fc32..000000000
--- a/src/transport/gnunet-service-transport_manipulation.h
+++ /dev/null
@@ -1,121 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010-2015 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/gnunet-service-transport_neighbours.h
23 * @brief neighbour manipulation API, allows manipulation of
24 * performance metrics (delay and towards ATS)
25 * @author Christian Grothoff
26 */
27#ifndef GNUNET_SERVICE_TRANSPORT_MANIPULATION_H
28#define GNUNET_SERVICE_TRANSPORT_MANIPULATION_H
29
30#include "platform.h"
31#include "gnunet-service-transport_hello.h"
32#include "gnunet-service-transport_neighbours.h"
33#include "gnunet-service-transport_plugins.h"
34#include "gnunet-service-transport_validation.h"
35#include "gnunet-service-transport.h"
36#include "transport.h"
37
38
39/**
40 * Set traffic metric to manipulate
41 *
42 * @param message containing information
43 */
44void
45GST_manipulation_set_metric (const struct TrafficMetricMessage *tm);
46
47
48/**
49 * Adapter function between transport's send function and transport plugins
50 *
51 * @param target the peer the message to send to
52 * @param msg the message received
53 * @param msg_size message size
54 * @param timeout timeout
55 * @param cont the continuation to call after sending
56 * @param cont_cls cls for continuation
57 */
58void
59GST_manipulation_send (const struct GNUNET_PeerIdentity *target,
60 const void *msg,
61 size_t msg_size,
62 struct GNUNET_TIME_Relative timeout,
63 GST_NeighbourSendContinuation cont,
64 void *cont_cls);
65
66
67/**
68 * Adapter function between transport plugins and transport receive function
69 * manipulation delays for next send.
70 *
71 * @param cls the closure for transport
72 * @param address the address and the peer the message was received from
73 * @param message the message received
74 * @param session the session the message was received on
75 * @return manipulated delay for next receive
76 */
77struct GNUNET_TIME_Relative
78GST_manipulation_recv (void *cls,
79 const struct GNUNET_HELLO_Address *address,
80 struct GNUNET_ATS_Session *session,
81 const struct GNUNET_MessageHeader *message);
82
83
84/**
85 * Function that will be called to manipulate ATS information according to
86 * current manipulation settings
87 *
88 * @param address binary address
89 * @param session the session
90 * @param prop[IN|OUT] metrics to modify
91 */
92void
93GST_manipulation_manipulate_metrics (const struct GNUNET_HELLO_Address *address,
94 struct GNUNET_ATS_Session *session,
95 struct GNUNET_ATS_Properties *prop);
96
97
98/**
99 * Notify manipulation about disconnect so it can discard queued messages
100 *
101 * @param peer the disconnecting peer
102 */
103void
104GST_manipulation_peer_disconnect (const struct GNUNET_PeerIdentity *peer);
105
106
107/**
108 * Initialize traffic manipulation
109 */
110void
111GST_manipulation_init (void);
112
113
114/**
115 * Stop traffic manipulation
116 */
117void
118GST_manipulation_stop (void);
119
120#endif
121/* end of file gnunet-service-transport_neighbours.h */
diff --git a/src/transport/gnunet-service-transport_neighbours.c b/src/transport/gnunet-service-transport_neighbours.c
deleted file mode 100644
index e61441d9f..000000000
--- a/src/transport/gnunet-service-transport_neighbours.c
+++ /dev/null
@@ -1,3947 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010-2015 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/gnunet-service-transport_neighbours.c
23 * @brief neighbour management
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_ats_service.h"
28#include "gnunet-service-transport_ats.h"
29#include "gnunet-service-transport_neighbours.h"
30#include "gnunet-service-transport_manipulation.h"
31#include "gnunet-service-transport_plugins.h"
32#include "gnunet-service-transport_validation.h"
33#include "gnunet-service-transport.h"
34#include "gnunet_peerinfo_service.h"
35#include "gnunet_constants.h"
36#include "transport.h"
37
38/**
39 * Experimental option to ignore SessionQuotaMessages from
40 * the other peer.
41 */
42#define IGNORE_INBOUND_QUOTA GNUNET_YES
43
44/**
45 * Size of the neighbour hash map.
46 */
47#define NEIGHBOUR_TABLE_SIZE 256
48
49/**
50 * Time we give plugin to transmit DISCONNECT message before the
51 * neighbour entry self-destructs.
52 */
53#define DISCONNECT_SENT_TIMEOUT GNUNET_TIME_relative_multiply ( \
54 GNUNET_TIME_UNIT_MILLISECONDS, 500)
55
56/**
57 * How often must a peer violate bandwidth quotas before we start
58 * to simply drop its messages?
59 */
60#define QUOTA_VIOLATION_DROP_THRESHOLD 10
61
62/**
63 * How long are we willing to wait for a response from ATS before timing out?
64 */
65#define ATS_RESPONSE_TIMEOUT GNUNET_TIME_relative_multiply ( \
66 GNUNET_TIME_UNIT_SECONDS, 5)
67
68/**
69 * How long are we willing to wait for an ACK from the other peer before
70 * giving up on our connect operation?
71 */
72#define SETUP_CONNECTION_TIMEOUT GNUNET_TIME_relative_multiply ( \
73 GNUNET_TIME_UNIT_SECONDS, 15)
74
75/**
76 * How long are we willing to wait for a successful reconnect if
77 * an existing connection went down? Much shorter than the
78 * usual SETUP_CONNECTION_TIMEOUT as we do not inform the
79 * higher layers about the disconnect during this period.
80 */
81#define FAST_RECONNECT_TIMEOUT GNUNET_TIME_UNIT_SECONDS
82
83/**
84 * Interval to send utilization data
85 */
86#define UTIL_TRANSMISSION_INTERVAL GNUNET_TIME_UNIT_SECONDS
87
88/**
89 * State describing which kind a reply this neighbour should send
90 */
91enum GST_ACK_State
92{
93 /**
94 * We did not receive a SYN message for this neighbour
95 */
96 ACK_UNDEFINED = 0,
97
98 /**
99 * The neighbour received a SYN message and has to send a SYN_ACK
100 * as reply
101 */
102 ACK_SEND_SYN_ACK = 1,
103
104 /**
105 * The neighbour sent a SYN_ACK message and has to send a ACK
106 * as reply
107 */
108 ACK_SEND_ACK = 2
109};
110
111
112GNUNET_NETWORK_STRUCT_BEGIN
113
114/**
115 * Message a peer sends to another to indicate that it intends to
116 * setup a connection/session for data exchange. A 'SESSION_SYN'
117 * should be answered with a 'SESSION_SYN_ACK' with the same body
118 * to confirm. A 'SESSION_SYN_ACK' should then be followed with
119 * a 'ACK'. Once the 'ACK' is received, both peers
120 * should be connected.
121 */
122struct TransportSynMessage
123{
124 /**
125 * Header of type #GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_SYN
126 * or #GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_SYN_ACK
127 */
128 struct GNUNET_MessageHeader header;
129
130 /**
131 * Always zero.
132 */
133 uint32_t reserved GNUNET_PACKED;
134
135 /**
136 * Absolute time at the sender. Only the most recent connect
137 * message implies which session is preferred by the sender.
138 */
139 struct GNUNET_TIME_AbsoluteNBO timestamp;
140};
141
142
143/**
144 * Message a peer sends to another when connected to indicate that a
145 * session is in use and the peer is still alive or to respond to a keep alive.
146 * A peer sends a message with type #GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE
147 * to request a message with #GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE_RESPONSE.
148 * When the keep alive response with type is received, transport service
149 * will call the respective plugin to update the session timeout
150 */
151struct GNUNET_ATS_SessionKeepAliveMessage
152{
153 /**
154 * Header of type #GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE or
155 * #GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE_RESPONSE.
156 */
157 struct GNUNET_MessageHeader header;
158
159 /**
160 * A nonce to identify the session the keep alive is used for
161 */
162 uint32_t nonce GNUNET_PACKED;
163};
164
165
166/**
167 * Message a peer sends to another when connected to indicate that
168 * the other peer should limit transmissions to the indicated
169 * quota.
170 */
171struct GNUNET_ATS_SessionQuotaMessage
172{
173 /**
174 * Header of type #GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_QUOTA.
175 */
176 struct GNUNET_MessageHeader header;
177
178 /**
179 * Quota to use (for sending), in bytes per second.
180 */
181 uint32_t quota GNUNET_PACKED;
182};
183
184
185/**
186 * Message we send to the other peer to notify it that we intentionally
187 * are disconnecting (to reduce timeouts). This is just a friendly
188 * notification, peers must not rely on always receiving disconnect
189 * messages.
190 */
191struct GNUNET_ATS_SessionDisconnectMessage
192{
193 /**
194 * Header of type #GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT
195 */
196 struct GNUNET_MessageHeader header;
197
198 /**
199 * Always zero.
200 */
201 uint32_t reserved GNUNET_PACKED;
202
203 /**
204 * Purpose of the signature. Extends over the timestamp.
205 * Purpose should be #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DISCONNECT.
206 */
207 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
208
209 /**
210 * Absolute time at the sender. Only the most recent connect
211 * message implies which session is preferred by the sender.
212 */
213 struct GNUNET_TIME_AbsoluteNBO timestamp;
214
215 /**
216 * Public key of the sender.
217 */
218 struct GNUNET_CRYPTO_EddsaPublicKey public_key;
219
220 /**
221 * Signature of the peer that sends us the disconnect. Only
222 * valid if the timestamp is AFTER the timestamp from the
223 * corresponding 'SYN' message.
224 */
225 struct GNUNET_CRYPTO_EddsaSignature signature;
226};
227
228GNUNET_NETWORK_STRUCT_END
229
230
231/**
232 * For each neighbour we keep a list of messages
233 * that we still want to transmit to the neighbour.
234 */
235struct MessageQueue
236{
237 /**
238 * This is a doubly linked list.
239 */
240 struct MessageQueue *next;
241
242 /**
243 * This is a doubly linked list.
244 */
245 struct MessageQueue *prev;
246
247 /**
248 * Function to call once we're done.
249 */
250 GST_NeighbourSendContinuation cont;
251
252 /**
253 * Closure for @e cont
254 */
255 void *cont_cls;
256
257 /**
258 * The message(s) we want to transmit, GNUNET_MessageHeader(s)
259 * stuck together in memory. Allocated at the end of this struct.
260 */
261 const char *message_buf;
262
263 /**
264 * Size of the message buf
265 */
266 size_t message_buf_size;
267
268 /**
269 * At what time should we fail?
270 */
271 struct GNUNET_TIME_Absolute timeout;
272};
273
274
275/**
276 * A possible address we could use to communicate with a neighbour.
277 */
278struct NeighbourAddress
279{
280 /**
281 * Active session for this address.
282 */
283 struct GNUNET_ATS_Session *session;
284
285 /**
286 * Network-level address information.
287 */
288 struct GNUNET_HELLO_Address *address;
289
290 /**
291 * Timestamp of the 'SESSION_CONNECT' message we sent to the other
292 * peer for this address. Use to check that the ACK is in response
293 * to our most recent 'SYN'.
294 */
295 struct GNUNET_TIME_Absolute connect_timestamp;
296
297 /**
298 * Inbound bandwidth from ATS for this address.
299 */
300 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in;
301
302 /**
303 * Outbound bandwidth from ATS for this address.
304 */
305 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out;
306
307 /**
308 * Did we tell ATS that this is our 'active' address?
309 */
310 int ats_active;
311
312 /**
313 * The current nonce sent in the last keep alive messages
314 */
315 uint32_t keep_alive_nonce;
316};
317
318
319/**
320 * Entry in neighbours.
321 */
322struct NeighbourMapEntry
323{
324 /**
325 * Head of list of messages we would like to send to this peer;
326 * must contain at most one message per client.
327 */
328 struct MessageQueue *messages_head;
329
330 /**
331 * Tail of list of messages we would like to send to this peer; must
332 * contain at most one message per client.
333 */
334 struct MessageQueue *messages_tail;
335
336 /**
337 * Are we currently trying to send a message? If so, which one?
338 */
339 struct MessageQueue *is_active;
340
341 /**
342 * Primary address we currently use to communicate with the neighbour.
343 */
344 struct NeighbourAddress primary_address;
345
346 /**
347 * Alternative address currently under consideration for communicating
348 * with the neighbour.
349 */
350 struct NeighbourAddress alternative_address;
351
352 /**
353 * Identity of this neighbour.
354 */
355 struct GNUNET_PeerIdentity id;
356
357 /**
358 * Main task that drives this peer (timeouts, keepalives, etc.).
359 * Always runs the #master_task().
360 */
361 struct GNUNET_SCHEDULER_Task *task;
362
363 /**
364 * Task to disconnect neighbour after we received a DISCONNECT message
365 */
366 struct GNUNET_SCHEDULER_Task *delayed_disconnect_task;
367
368 /**
369 * At what time should we sent the next keep-alive message?
370 */
371 struct GNUNET_TIME_Absolute keep_alive_time;
372
373 /**
374 * At what time did we sent the last keep-alive message? Used
375 * to calculate round-trip time ("latency").
376 */
377 struct GNUNET_TIME_Absolute last_keep_alive_time;
378
379 /**
380 * Timestamp we should include in our next SYN_ACK message.
381 * (only valid if 'send_connect_ack' is #GNUNET_YES). Used to build
382 * our SYN_ACK message.
383 */
384 struct GNUNET_TIME_Absolute connect_ack_timestamp;
385
386 /**
387 * ATS address suggest handle
388 */
389 struct GNUNET_ATS_ConnectivitySuggestHandle *suggest_handle;
390
391 /**
392 * Time where we should cut the connection (timeout) if we don't
393 * make progress in the state machine (or get a KEEPALIVE_RESPONSE
394 * if we are in #GNUNET_TRANSPORT_PS_CONNECTED).
395 */
396 struct GNUNET_TIME_Absolute timeout;
397
398 /**
399 * Tracker for inbound bandwidth.
400 */
401 struct GNUNET_BANDWIDTH_Tracker in_tracker;
402
403 /**
404 * How often has the other peer (recently) violated the inbound
405 * traffic limit? Incremented by 10 per violation, decremented by 1
406 * per non-violation (for each time interval).
407 */
408 unsigned int quota_violation_count;
409
410 /**
411 * Latest quota the other peer send us in bytes per second.
412 * We should not send more, least the other peer throttle
413 * receiving our traffic.
414 */
415 struct GNUNET_BANDWIDTH_Value32NBO neighbour_receive_quota;
416
417 /**
418 * The current state of the peer.
419 */
420 enum GNUNET_TRANSPORT_PeerState state;
421
422 /**
423 * Did we sent an KEEP_ALIVE message and are we expecting a response?
424 */
425 int expect_latency_response;
426
427 /**
428 * When a peer wants to connect we have to reply to the 1st SYN message
429 * with a SYN_ACK message. But sometime we cannot send this message
430 * immediately since we do not have an address and then we have to remember
431 * to send this message as soon as we have an address.
432 *
433 * Flag to set if we still need to send a SYN_ACK message to the other peer
434 * (once we have an address to use and the peer has been allowed by our
435 * blacklist). Initially set to #ACK_UNDEFINED. Set to #ACK_SEND_SYN_ACK
436 * if we need to send a SYN_ACK. Set to #ACK_SEND_ACK if we did
437 * send a SYN_ACK and should go to #S_CONNECTED upon receiving a
438 * 'ACK' (regardless of what our own state machine might say).
439 */
440 enum GST_ACK_State ack_state;
441
442 /**
443 * Tracking utilization of outbound bandwidth
444 */
445 uint32_t util_total_bytes_sent;
446
447 /**
448 * Tracking utilization of inbound bandwidth
449 */
450 uint32_t util_total_bytes_recv;
451
452 /**
453 * Date of last utilization transmission
454 */
455 struct GNUNET_TIME_Absolute last_util_transmission;
456};
457
458
459/**
460 * Hash map from peer identities to the respective `struct NeighbourMapEntry`.
461 */
462static struct GNUNET_CONTAINER_MultiPeerMap *neighbours;
463
464/**
465 * List of pending blacklist checks: head
466 */
467static struct BlacklistCheckSwitchContext *pending_bc_head;
468
469/**
470 * List of pending blacklist checks: tail
471 */
472static struct BlacklistCheckSwitchContext *pending_bc_tail;
473
474/**
475 * counter for connected neighbours
476 */
477static unsigned int neighbours_connected;
478
479/**
480 * Number of bytes we have currently queued for transmission.
481 */
482static unsigned long long bytes_in_send_queue;
483
484/**
485 * Task transmitting utilization data
486 */
487static struct GNUNET_SCHEDULER_Task *util_transmission_tk;
488
489
490/**
491 * Convert the given ACK state to a string.
492 *
493 * @param s state
494 * @return corresponding human-readable string
495 */
496static char *
497print_ack_state (enum GST_ACK_State s)
498{
499 switch (s)
500 {
501 case ACK_UNDEFINED:
502 return "UNDEFINED";
503
504 case ACK_SEND_SYN_ACK:
505 return "SEND_SYN_ACK";
506
507 case ACK_SEND_ACK:
508 return "SEND_ACK";
509
510 default:
511 GNUNET_break (0);
512 return "N/A";
513 }
514}
515
516
517/**
518 * Send information about a new outbound quota to our clients.
519 * Note that the outbound quota is enforced client-side (i.e.
520 * in libgnunettransport).
521 *
522 * @param n affected peer
523 */
524static void
525send_outbound_quota_to_clients (struct NeighbourMapEntry *n)
526{
527 struct QuotaSetMessage q_msg;
528 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_min;
529
530 if (! GNUNET_TRANSPORT_is_connected (n->state))
531 return;
532#if IGNORE_INBOUND_QUOTA
533 bandwidth_min = n->primary_address.bandwidth_out;
534#else
535 bandwidth_min = GNUNET_BANDWIDTH_value_min (n->primary_address.bandwidth_out,
536 n->neighbour_receive_quota);
537#endif
538
539 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
540 "Sending outbound quota of %u Bps for peer `%s' to all clients\n",
541 ntohl (bandwidth_min.value__),
542 GNUNET_i2s (&n->id));
543 q_msg.header.size = htons (sizeof(struct QuotaSetMessage));
544 q_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA);
545 q_msg.quota = bandwidth_min;
546 q_msg.peer = n->id;
547 GST_clients_broadcast (&q_msg.header,
548 GNUNET_NO);
549}
550
551
552/**
553 * Notify our clients that another peer connected to us.
554 *
555 * @param n the peer that connected
556 */
557static void
558neighbours_connect_notification (struct NeighbourMapEntry *n)
559{
560 size_t len = sizeof(struct ConnectInfoMessage);
561 char buf[len] GNUNET_ALIGN;
562 struct ConnectInfoMessage *connect_msg = (struct ConnectInfoMessage *) buf;
563 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_min;
564
565#if IGNORE_INBOUND_QUOTA
566 bandwidth_min = n->primary_address.bandwidth_out;
567#else
568 bandwidth_min = GNUNET_BANDWIDTH_value_min (n->primary_address.bandwidth_out,
569 n->neighbour_receive_quota);
570#endif
571 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
572 "We are now connected to peer `%s'\n",
573 GNUNET_i2s (&n->id));
574 connect_msg->header.size = htons (sizeof(buf));
575 connect_msg->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
576 connect_msg->id = n->id;
577 connect_msg->quota_out = bandwidth_min;
578 GST_clients_broadcast (&connect_msg->header,
579 GNUNET_NO);
580}
581
582
583/**
584 * Notify our clients (and manipulation) that a peer disconnected from
585 * us.
586 *
587 * @param n the peer that disconnected
588 */
589static void
590neighbours_disconnect_notification (struct NeighbourMapEntry *n)
591{
592 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
593 "Peer `%s' disconnected\n",
594 GNUNET_i2s (&n->id));
595 GST_manipulation_peer_disconnect (&n->id);
596 GST_clients_broadcast_disconnect (&n->id);
597}
598
599
600/**
601 * Notify transport clients that a neighbour peer changed its active
602 * address.
603 *
604 * @param peer identity of the peer
605 * @param address address possibly NULL if peer is not connected
606 * @param state current state this peer is in
607 * @param state_timeout timeout for the current state of the peer
608 * @param bandwidth_in bandwidth assigned inbound, 0 on disconnect
609 * @param bandwidth_out bandwidth assigned outbound, 0 on disconnect
610 */
611static void
612neighbours_changed_notification (const struct GNUNET_PeerIdentity *peer,
613 const struct GNUNET_HELLO_Address *address,
614 enum GNUNET_TRANSPORT_PeerState state,
615 struct GNUNET_TIME_Absolute state_timeout,
616 struct GNUNET_BANDWIDTH_Value32NBO
617 bandwidth_in,
618 struct GNUNET_BANDWIDTH_Value32NBO
619 bandwidth_out)
620{
621 (void) bandwidth_in;
622 (void) bandwidth_out;
623 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
624 "Notifying about change for peer `%s' with address `%s' in state `%s' timing out at %s\n",
625 GNUNET_i2s (peer),
626 GST_plugins_a2s (address),
627 GNUNET_TRANSPORT_ps2s (state),
628 GNUNET_STRINGS_absolute_time_to_string (state_timeout));
629 /* FIXME: include bandwidth in notification! */
630 GST_clients_broadcast_peer_notification (peer,
631 address,
632 state,
633 state_timeout);
634}
635
636
637/**
638 * Lookup a neighbour entry in the neighbours hash map.
639 *
640 * @param pid identity of the peer to look up
641 * @return the entry, NULL if there is no existing record
642 */
643static struct NeighbourMapEntry *
644lookup_neighbour (const struct GNUNET_PeerIdentity *pid)
645{
646 if (NULL == neighbours)
647 return NULL;
648 return GNUNET_CONTAINER_multipeermap_get (neighbours, pid);
649}
650
651
652/**
653 * Test if we're connected to the given peer.
654 *
655 * @param n neighbour entry of peer to test
656 * @return #GNUNET_YES if we are connected, #GNUNET_NO if not
657 */
658static int
659test_connected (struct NeighbourMapEntry *n)
660{
661 if (NULL == n)
662 return GNUNET_NO;
663 return GNUNET_TRANSPORT_is_connected (n->state);
664}
665
666
667/**
668 * We don't need a given neighbour address any more.
669 * Release its resources and give appropriate notifications
670 * to ATS and other subsystems.
671 *
672 * @param na address we are done with; @a na itself must NOT be 'free'd, only the contents!
673 */
674static void
675free_address (struct NeighbourAddress *na)
676{
677 if (GNUNET_YES == na->ats_active)
678 GST_validation_set_address_use (na->address,
679 GNUNET_NO);
680 if (NULL != na->address)
681 {
682 GST_ats_block_address (na->address,
683 na->session);
684 GNUNET_HELLO_address_free (na->address);
685 na->address = NULL;
686 }
687 na->bandwidth_in = GNUNET_BANDWIDTH_value_init (0);
688 na->bandwidth_out = GNUNET_BANDWIDTH_value_init (0);
689 na->ats_active = GNUNET_NO;
690 na->keep_alive_nonce = 0;
691 na->session = NULL;
692}
693
694
695/**
696 * Master task run for every neighbour. Performs all of the time-related
697 * activities (keep alive, send next message, disconnect if idle, finish
698 * clean up after disconnect).
699 *
700 * @param cls the `struct NeighbourMapEntry` for which we are running
701 */
702static void
703master_task (void *cls);
704
705
706/**
707 * Set net state and state timeout for this neighbour and notify monitoring
708 *
709 * @param n the respective neighbour
710 * @param s the new state
711 * @param timeout the new timeout
712 */
713static void
714set_state_and_timeout (struct NeighbourMapEntry *n,
715 enum GNUNET_TRANSPORT_PeerState s,
716 struct GNUNET_TIME_Absolute timeout)
717{
718 if (GNUNET_TRANSPORT_is_connected (s) &&
719 (! GNUNET_TRANSPORT_is_connected (n->state)))
720 {
721 neighbours_connect_notification (n);
722 GNUNET_STATISTICS_set (GST_stats,
723 gettext_noop ("# peers connected"),
724 ++neighbours_connected,
725 GNUNET_NO);
726 }
727 if ((! GNUNET_TRANSPORT_is_connected (s)) &&
728 GNUNET_TRANSPORT_is_connected (n->state))
729 {
730 GNUNET_STATISTICS_set (GST_stats,
731 gettext_noop ("# peers connected"),
732 --neighbours_connected,
733 GNUNET_NO);
734 neighbours_disconnect_notification (n);
735 }
736 n->state = s;
737 if ((timeout.abs_value_us < n->timeout.abs_value_us) &&
738 (NULL != n->task))
739 {
740 /* new timeout is earlier, reschedule master task */
741 GNUNET_SCHEDULER_cancel (n->task);
742 n->task = GNUNET_SCHEDULER_add_at (timeout,
743 &master_task,
744 n);
745 }
746 n->timeout = timeout;
747 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
748 "Neighbour `%s' changed state to %s with timeout %s\n",
749 GNUNET_i2s (&n->id),
750 GNUNET_TRANSPORT_ps2s (s),
751 GNUNET_STRINGS_absolute_time_to_string (timeout));
752 neighbours_changed_notification (&n->id,
753 n->primary_address.address,
754 n->state,
755 n->timeout,
756 n->primary_address.bandwidth_in,
757 n->primary_address.bandwidth_out);
758}
759
760
761/**
762 * Initialize the alternative address of a neighbour
763 *
764 * @param n the neighbour
765 * @param address address of the other peer, NULL if other peer
766 * connected to us
767 * @param session session to use (or NULL, in which case an
768 * address must be setup)
769 * @param bandwidth_in inbound quota to be used when connection is up
770 * @param bandwidth_out outbound quota to be used when connection is up
771 */
772static void
773set_alternative_address (struct NeighbourMapEntry *n,
774 const struct GNUNET_HELLO_Address *address,
775 struct GNUNET_ATS_Session *session,
776 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
777 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
778{
779 struct GNUNET_TRANSPORT_PluginFunctions *papi;
780
781 if (NULL == (papi = GST_plugins_find (address->transport_name)))
782 {
783 GNUNET_break (0);
784 return;
785 }
786 if (session == n->alternative_address.session)
787 {
788 n->alternative_address.bandwidth_in = bandwidth_in;
789 n->alternative_address.bandwidth_out = bandwidth_out;
790 return;
791 }
792 if (NULL != n->alternative_address.address)
793 {
794 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
795 "Replacing existing alternative address with another one\n");
796 free_address (&n->alternative_address);
797 }
798 if (NULL == session)
799 session = papi->get_session (papi->cls,
800 address);
801 if (NULL == session)
802 {
803 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
804 "Failed to obtain new session for peer `%s' and address '%s'\n",
805 GNUNET_i2s (&address->peer),
806 GST_plugins_a2s (address));
807 GNUNET_STATISTICS_update (GST_stats,
808 gettext_noop ("# session creation failed"),
809 1,
810 GNUNET_NO);
811 return;
812 }
813 GST_ats_new_session (address,
814 session);
815 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
816 "Neighbour `%s' configured alternative address %s\n",
817 GNUNET_i2s (&n->id),
818 GST_plugins_a2s (address));
819
820 n->alternative_address.address = GNUNET_HELLO_address_copy (address);
821 n->alternative_address.bandwidth_in = bandwidth_in;
822 n->alternative_address.bandwidth_out = bandwidth_out;
823 n->alternative_address.session = session;
824 n->alternative_address.ats_active = GNUNET_NO;
825 n->alternative_address.keep_alive_nonce = 0;
826 GNUNET_assert (GNUNET_YES ==
827 GST_ats_is_known (n->alternative_address.address,
828 n->alternative_address.session));
829}
830
831
832/**
833 * Transmit a message using the current session of the given
834 * neighbour.
835 *
836 * @param n entry for the recipient
837 * @param msgbuf buffer to transmit
838 * @param msgbuf_size number of bytes in @a msgbuf buffer
839 * @param priority transmission priority
840 * @param timeout transmission timeout
841 * @param use_keepalive_timeout #GNUNET_YES to use plugin-specific keep-alive
842 * timeout (@a timeout is ignored in that case), #GNUNET_NO otherwise
843 * @param cont continuation to call when finished (can be NULL)
844 * @param cont_cls closure for @a cont
845 * @return timeout (copy of @a timeout or a calculated one if
846 * @a use_keepalive_timeout is #GNUNET_YES.
847 */
848static struct GNUNET_TIME_Relative
849send_with_session (struct NeighbourMapEntry *n,
850 const void *msgbuf,
851 size_t msgbuf_size,
852 uint32_t priority,
853 struct GNUNET_TIME_Relative timeout,
854 unsigned int use_keepalive_timeout,
855 GNUNET_TRANSPORT_TransmitContinuation cont,
856 void *cont_cls)
857{
858 struct GNUNET_TRANSPORT_PluginFunctions *papi;
859 struct GNUNET_TIME_Relative result = GNUNET_TIME_UNIT_FOREVER_REL;
860
861 GNUNET_assert (NULL != n->primary_address.session);
862 if ((((NULL == (papi = GST_plugins_find (
863 n->primary_address.address->transport_name))) ||
864 (-1 == papi->send (papi->cls,
865 n->primary_address.session,
866 msgbuf,
867 msgbuf_size,
868 priority,
869 (result = (GNUNET_NO == use_keepalive_timeout) ?
870 timeout :
871 GNUNET_TIME_relative_divide (
872 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
873 papi->
874 query_keepalive_factor (papi->cls))),
875 cont,
876 cont_cls)))) &&
877 (NULL != cont))
878 cont (cont_cls,
879 &n->id,
880 GNUNET_SYSERR,
881 msgbuf_size,
882 0);
883 GST_neighbours_notify_data_sent (n->primary_address.address,
884 n->primary_address.session,
885 msgbuf_size);
886 GNUNET_break (NULL != papi);
887 return result;
888}
889
890
891/**
892 * Clear the primary address of a neighbour since this address is not
893 * valid anymore and notify monitoring about it
894 *
895 * @param n the neighbour
896 */
897static void
898unset_primary_address (struct NeighbourMapEntry *n)
899{
900 /* Notify monitoring about change */
901 if (NULL == n->primary_address.address)
902 return;
903 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
904 "Disabling primary address\n");
905 neighbours_changed_notification (&n->id,
906 n->primary_address.address,
907 n->state,
908 n->timeout,
909 GNUNET_BANDWIDTH_value_init (0),
910 GNUNET_BANDWIDTH_value_init (0));
911 free_address (&n->primary_address);
912}
913
914
915/**
916 * Free a neighbour map entry.
917 *
918 * @param n entry to free
919 */
920static void
921free_neighbour (struct NeighbourMapEntry *n)
922{
923 struct MessageQueue *mq;
924
925 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
926 "Freeing neighbour state of peer `%s'\n",
927 GNUNET_i2s (&n->id));
928 n->is_active = NULL; /* always free'd by its own continuation! */
929
930 /* fail messages currently in the queue */
931 while (NULL != (mq = n->messages_head))
932 {
933 GNUNET_CONTAINER_DLL_remove (n->messages_head,
934 n->messages_tail,
935 mq);
936 if (NULL != mq->cont)
937 mq->cont (mq->cont_cls,
938 GNUNET_SYSERR,
939 mq->message_buf_size,
940 0);
941 GNUNET_free (mq);
942 }
943 /* Mark peer as disconnected */
944 set_state_and_timeout (n,
945 GNUNET_TRANSPORT_PS_DISCONNECT_FINISHED,
946 GNUNET_TIME_UNIT_FOREVER_ABS);
947 /* free addresses and mark as unused */
948 unset_primary_address (n);
949
950 if (NULL != n->alternative_address.address)
951 {
952 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
953 "Cleaning up alternative address\n");
954 free_address (&n->alternative_address);
955 }
956 GNUNET_assert (GNUNET_YES ==
957 GNUNET_CONTAINER_multipeermap_remove (neighbours,
958 &n->id,
959 n));
960
961 /* Cancel address requests for this peer */
962 if (NULL != n->suggest_handle)
963 {
964 GNUNET_ATS_connectivity_suggest_cancel (n->suggest_handle);
965 n->suggest_handle = NULL;
966 }
967
968 /* Cancel the disconnect task */
969 if (NULL != n->delayed_disconnect_task)
970 {
971 GNUNET_SCHEDULER_cancel (n->delayed_disconnect_task);
972 n->delayed_disconnect_task = NULL;
973 }
974
975 /* Cancel the master task */
976 if (NULL != n->task)
977 {
978 GNUNET_SCHEDULER_cancel (n->task);
979 n->task = NULL;
980 }
981 /* free rest of memory */
982 GNUNET_free (n);
983}
984
985
986/**
987 * Function called when the 'DISCONNECT' message has been sent by the
988 * plugin. Frees the neighbour --- if the entry still exists.
989 *
990 * @param cls NULL
991 * @param target identity of the neighbour that was disconnected
992 * @param result #GNUNET_OK if the disconnect got out successfully
993 * @param payload bytes payload
994 * @param physical bytes on wire
995 */
996static void
997send_disconnect_cont (void *cls,
998 const struct GNUNET_PeerIdentity *target,
999 int result,
1000 size_t payload,
1001 size_t physical)
1002{
1003 struct NeighbourMapEntry *n;
1004
1005 (void) cls;
1006 (void) result;
1007 (void) payload;
1008 (void) physical;
1009 n = lookup_neighbour (target);
1010 if (NULL == n)
1011 return; /* already gone */
1012 if (GNUNET_TRANSPORT_PS_DISCONNECT != n->state)
1013 return; /* have created a fresh entry since */
1014 if (NULL != n->task)
1015 GNUNET_SCHEDULER_cancel (n->task);
1016 n->task = GNUNET_SCHEDULER_add_now (&master_task, n);
1017}
1018
1019
1020/**
1021 * Transmit a DISCONNECT message to the other peer.
1022 *
1023 * @param n neighbour to send DISCONNECT message.
1024 */
1025static void
1026send_disconnect (struct NeighbourMapEntry *n)
1027{
1028 struct GNUNET_ATS_SessionDisconnectMessage disconnect_msg;
1029
1030 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1031 "Sending DISCONNECT message to peer `%4s'\n",
1032 GNUNET_i2s (&n->id));
1033 disconnect_msg.header.size = htons (sizeof(struct
1034 GNUNET_ATS_SessionDisconnectMessage));
1035 disconnect_msg.header.type =
1036 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT);
1037 disconnect_msg.reserved = htonl (0);
1038 disconnect_msg.purpose.size =
1039 htonl (sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose)
1040 + sizeof(struct GNUNET_CRYPTO_EddsaPublicKey)
1041 + sizeof(struct GNUNET_TIME_AbsoluteNBO));
1042 disconnect_msg.purpose.purpose =
1043 htonl (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT);
1044 disconnect_msg.timestamp =
1045 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
1046 disconnect_msg.public_key = GST_my_identity.public_key;
1047 GNUNET_assert (GNUNET_OK ==
1048 GNUNET_CRYPTO_eddsa_sign_ (&GST_my_private_key,
1049 &disconnect_msg.purpose,
1050 &disconnect_msg.signature));
1051
1052 (void) send_with_session (n,
1053 &disconnect_msg,
1054 sizeof(disconnect_msg),
1055 UINT32_MAX,
1056 GNUNET_TIME_UNIT_FOREVER_REL,
1057 GNUNET_NO,
1058 &send_disconnect_cont,
1059 NULL);
1060 GNUNET_STATISTICS_update (GST_stats,
1061 gettext_noop ("# DISCONNECT messages sent"),
1062 1,
1063 GNUNET_NO);
1064}
1065
1066
1067/**
1068 * Disconnect from the given neighbour, clean up the record.
1069 *
1070 * @param n neighbour to disconnect from
1071 */
1072static void
1073disconnect_neighbour (struct NeighbourMapEntry *n)
1074{
1075 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1076 "Disconnecting from peer %s in state %s\n",
1077 GNUNET_i2s (&n->id),
1078 GNUNET_TRANSPORT_ps2s (n->state));
1079 /* depending on state, notify neighbour and/or upper layers of this peer
1080 about disconnect */
1081 switch (n->state)
1082 {
1083 case GNUNET_TRANSPORT_PS_NOT_CONNECTED:
1084 case GNUNET_TRANSPORT_PS_INIT_ATS:
1085 /* other peer is completely unaware of us, no need to send DISCONNECT */
1086 free_neighbour (n);
1087 return;
1088
1089 case GNUNET_TRANSPORT_PS_SYN_SENT:
1090 send_disconnect (n);
1091 set_state_and_timeout (n,
1092 GNUNET_TRANSPORT_PS_DISCONNECT,
1093 GNUNET_TIME_UNIT_FOREVER_ABS);
1094 break;
1095
1096 case GNUNET_TRANSPORT_PS_SYN_RECV_ATS:
1097 /* we never ACK'ed the other peer's request, no need to send DISCONNECT */
1098 free_neighbour (n);
1099 return;
1100
1101 case GNUNET_TRANSPORT_PS_SYN_RECV_ACK:
1102 /* we DID ACK the other peer's request, must send DISCONNECT */
1103 send_disconnect (n);
1104 set_state_and_timeout (n,
1105 GNUNET_TRANSPORT_PS_DISCONNECT,
1106 GNUNET_TIME_UNIT_FOREVER_ABS);
1107 break;
1108
1109 case GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT:
1110 case GNUNET_TRANSPORT_PS_CONNECTED:
1111 case GNUNET_TRANSPORT_PS_RECONNECT_SENT:
1112 /* we are currently connected, need to send disconnect and do
1113 internal notifications and update statistics */
1114 send_disconnect (n);
1115 set_state_and_timeout (n,
1116 GNUNET_TRANSPORT_PS_DISCONNECT,
1117 GNUNET_TIME_UNIT_FOREVER_ABS);
1118 break;
1119
1120 case GNUNET_TRANSPORT_PS_RECONNECT_ATS:
1121 /* Disconnecting while waiting for an ATS address to reconnect,
1122 * cannot send DISCONNECT */
1123 free_neighbour (n);
1124 return;
1125
1126 case GNUNET_TRANSPORT_PS_DISCONNECT:
1127 /* already disconnected, ignore */
1128 break;
1129
1130 case GNUNET_TRANSPORT_PS_DISCONNECT_FINISHED:
1131 /* already cleaned up, how did we get here!? */
1132 GNUNET_assert (0);
1133 break;
1134
1135 default:
1136 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1137 "Unhandled state `%s'\n",
1138 GNUNET_TRANSPORT_ps2s (n->state));
1139 GNUNET_break (0);
1140 break;
1141 }
1142 /* schedule timeout to clean up */
1143 if (NULL != n->task)
1144 GNUNET_SCHEDULER_cancel (n->task);
1145 n->task = GNUNET_SCHEDULER_add_delayed (DISCONNECT_SENT_TIMEOUT,
1146 &master_task,
1147 n);
1148}
1149
1150
1151/**
1152 * Change the incoming quota for the given peer. Updates
1153 * our own receive rate and informs the neighbour about
1154 * the new quota.
1155 *
1156 * @param n neighbour entry to change quota for
1157 * @param quota new quota
1158 * @return #GNUNET_YES if @a n is still valid, #GNUNET_NO if
1159 * @a n was freed
1160 */
1161static int
1162set_incoming_quota (struct NeighbourMapEntry *n,
1163 struct GNUNET_BANDWIDTH_Value32NBO quota)
1164{
1165 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1166 "Setting inbound quota of %u Bps for peer `%s' to all clients\n",
1167 ntohl (quota.value__), GNUNET_i2s (&n->id));
1168 GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
1169 quota);
1170 if (0 != ntohl (quota.value__))
1171 {
1172 struct GNUNET_ATS_SessionQuotaMessage sqm;
1173
1174 sqm.header.size = htons (sizeof(struct GNUNET_ATS_SessionQuotaMessage));
1175 sqm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_QUOTA);
1176 sqm.quota = quota.value__;
1177 if (NULL != n->primary_address.session)
1178 (void) send_with_session (n,
1179 &sqm,
1180 sizeof(sqm),
1181 UINT32_MAX - 1,
1182 GNUNET_TIME_UNIT_FOREVER_REL,
1183 GNUNET_NO,
1184 NULL, NULL);
1185 return GNUNET_YES;
1186 }
1187 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1188 "Disconnecting peer `%s' due to SET_QUOTA\n",
1189 GNUNET_i2s (&n->id));
1190 if (GNUNET_YES == test_connected (n))
1191 GNUNET_STATISTICS_update (GST_stats,
1192 gettext_noop ("# disconnects due to quota of 0"),
1193 1, GNUNET_NO);
1194 disconnect_neighbour (n);
1195 return GNUNET_NO;
1196}
1197
1198
1199/**
1200 * Initialize the primary address of a neighbour
1201 *
1202 * @param n the neighbour
1203 * @param address address of the other peer, NULL if other peer
1204 * connected to us
1205 * @param session session to use (or NULL, in which case an
1206 * address must be setup)
1207 * @param bandwidth_in inbound quota to be used when connection is up
1208 * @param bandwidth_out outbound quota to be used when connection is up
1209 */
1210static void
1211set_primary_address (struct NeighbourMapEntry *n,
1212 const struct GNUNET_HELLO_Address *address,
1213 struct GNUNET_ATS_Session *session,
1214 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
1215 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
1216{
1217 if (session == n->primary_address.session)
1218 {
1219 GST_validation_set_address_use (n->primary_address.address,
1220 GNUNET_YES);
1221 if (n->primary_address.bandwidth_in.value__ != bandwidth_in.value__)
1222 {
1223 n->primary_address.bandwidth_in = bandwidth_in;
1224 if (GNUNET_YES !=
1225 set_incoming_quota (n,
1226 bandwidth_in))
1227 return;
1228 }
1229 if (n->primary_address.bandwidth_out.value__ != bandwidth_out.value__)
1230 {
1231 n->primary_address.bandwidth_out = bandwidth_out;
1232 send_outbound_quota_to_clients (n);
1233 }
1234 return;
1235 }
1236 if ((NULL != n->primary_address.address) &&
1237 (0 == GNUNET_HELLO_address_cmp (address,
1238 n->primary_address.address)))
1239 {
1240 GNUNET_break (0);
1241 return;
1242 }
1243 if (NULL == session)
1244 {
1245 GNUNET_break (0);
1246 GST_ats_block_address (address,
1247 session);
1248 return;
1249 }
1250 if (NULL != n->primary_address.address)
1251 {
1252 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1253 "Replacing existing primary address with another one\n");
1254 free_address (&n->primary_address);
1255 }
1256 n->primary_address.address = GNUNET_HELLO_address_copy (address);
1257 n->primary_address.bandwidth_in = bandwidth_in;
1258 n->primary_address.bandwidth_out = bandwidth_out;
1259 n->primary_address.session = session;
1260 n->primary_address.keep_alive_nonce = 0;
1261 GNUNET_assert (GNUNET_YES ==
1262 GST_ats_is_known (n->primary_address.address,
1263 n->primary_address.session));
1264 /* subsystems about address use */
1265 GST_validation_set_address_use (n->primary_address.address,
1266 GNUNET_YES);
1267 if (GNUNET_YES !=
1268 set_incoming_quota (n,
1269 bandwidth_in))
1270 return;
1271 send_outbound_quota_to_clients (n);
1272 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1273 "Neighbour `%s' switched to address `%s'\n",
1274 GNUNET_i2s (&n->id),
1275 GST_plugins_a2s (address));
1276
1277 neighbours_changed_notification (&n->id,
1278 n->primary_address.address,
1279 n->state,
1280 n->timeout,
1281 n->primary_address.bandwidth_in,
1282 n->primary_address.bandwidth_out);
1283}
1284
1285
1286/**
1287 * We're done with our transmission attempt, continue processing.
1288 *
1289 * @param cls the `struct MessageQueue` of the message
1290 * @param receiver intended receiver
1291 * @param success whether it worked or not
1292 * @param size_payload bytes payload sent
1293 * @param physical bytes sent on wire
1294 */
1295static void
1296transmit_send_continuation (void *cls,
1297 const struct GNUNET_PeerIdentity *receiver,
1298 int success,
1299 size_t size_payload,
1300 size_t physical)
1301{
1302 struct MessageQueue *mq = cls;
1303 struct NeighbourMapEntry *n;
1304
1305 if (NULL == (n = lookup_neighbour (receiver)))
1306 {
1307 if (NULL != mq->cont)
1308 mq->cont (mq->cont_cls,
1309 GNUNET_SYSERR /* not connected */,
1310 size_payload,
1311 0);
1312 GNUNET_free (mq);
1313 return; /* disconnect or other error while transmitting, can happen */
1314 }
1315 if (n->is_active == mq)
1316 {
1317 /* this is still "our" neighbour, remove us from its queue
1318 and allow it to send the next message now */
1319 n->is_active = NULL;
1320 if (NULL != n->task)
1321 GNUNET_SCHEDULER_cancel (n->task);
1322 n->task = GNUNET_SCHEDULER_add_now (&master_task,
1323 n);
1324 }
1325 if (bytes_in_send_queue < mq->message_buf_size)
1326 {
1327 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1328 "Bytes_in_send_queue `%llu', Message_size %u, result: %s, payload %u, on wire %u\n",
1329 bytes_in_send_queue,
1330 (unsigned int) mq->message_buf_size,
1331 (GNUNET_OK == success) ? "OK" : "FAIL",
1332 (unsigned int) size_payload,
1333 (unsigned int) physical);
1334 GNUNET_break (0);
1335 }
1336
1337 GNUNET_break (size_payload == mq->message_buf_size);
1338 bytes_in_send_queue -= mq->message_buf_size;
1339 GNUNET_STATISTICS_set (GST_stats,
1340 gettext_noop (
1341 "# bytes in message queue for other peers"),
1342 bytes_in_send_queue,
1343 GNUNET_NO);
1344 if (GNUNET_OK == success)
1345 GNUNET_STATISTICS_update (GST_stats,
1346 gettext_noop (
1347 "# messages transmitted to other peers"),
1348 1,
1349 GNUNET_NO);
1350 else
1351 GNUNET_STATISTICS_update (GST_stats,
1352 gettext_noop
1353 (
1354 "# transmission failures for messages to other peers"),
1355 1, GNUNET_NO);
1356 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1357 "Sending message to `%s' of type %u with %u bytes was a %s\n",
1358 GNUNET_i2s (receiver),
1359 ntohs (((struct GNUNET_MessageHeader *) mq->message_buf)->type),
1360 (unsigned int) mq->message_buf_size,
1361 (success == GNUNET_OK) ? "success" : "FAILURE");
1362 if (NULL != mq->cont)
1363 mq->cont (mq->cont_cls,
1364 success,
1365 size_payload,
1366 physical);
1367 GNUNET_free (mq);
1368}
1369
1370
1371/**
1372 * Check the message list for the given neighbour and if we can
1373 * send a message, do so. This function should only be called
1374 * if the connection is at least generally ready for transmission.
1375 * While we will only send one message at a time, no bandwidth
1376 * quota management is performed here. If a message was given to
1377 * the plugin, the continuation will automatically re-schedule
1378 * the 'master' task once the next message might be transmitted.
1379 *
1380 * @param n target peer for which to transmit
1381 */
1382static void
1383try_transmission_to_peer (struct NeighbourMapEntry *n)
1384{
1385 struct MessageQueue *mq;
1386 struct GNUNET_TIME_Relative timeout;
1387
1388 if (NULL == n->primary_address.address)
1389 {
1390 /* no address, why are we here? */
1391 GNUNET_break (0);
1392 return;
1393 }
1394 if ((0 == n->primary_address.address->address_length) &&
1395 (NULL == n->primary_address.session))
1396 {
1397 /* no address, why are we here? */
1398 GNUNET_break (0);
1399 return;
1400 }
1401 if (NULL != n->is_active)
1402 {
1403 /* transmission already pending */
1404 return;
1405 }
1406
1407 /* timeout messages from the queue that are past their due date */
1408 while (NULL != (mq = n->messages_head))
1409 {
1410 timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout);
1411 if (timeout.rel_value_us > 0)
1412 break;
1413 GNUNET_STATISTICS_update (GST_stats,
1414 gettext_noop (
1415 "# messages timed out while in transport queue"),
1416 1,
1417 GNUNET_NO);
1418 GNUNET_CONTAINER_DLL_remove (n->messages_head,
1419 n->messages_tail,
1420 mq);
1421 n->is_active = mq;
1422 transmit_send_continuation (mq,
1423 &n->id,
1424 GNUNET_SYSERR,
1425 mq->message_buf_size,
1426 0); /* timeout */
1427 }
1428 if (NULL == mq)
1429 return; /* no more messages */
1430 if (NULL == n->primary_address.address)
1431 {
1432 /* transmit_send_continuation() caused us to drop session,
1433 can't try transmission anymore. */
1434 return;
1435 }
1436
1437
1438 GNUNET_CONTAINER_DLL_remove (n->messages_head,
1439 n->messages_tail,
1440 mq);
1441 n->is_active = mq;
1442
1443 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1444 "Giving message with %u bytes to plugin session %p\n",
1445 (unsigned int) mq->message_buf_size,
1446 n->primary_address.session);
1447 (void) send_with_session (n,
1448 mq->message_buf,
1449 mq->message_buf_size,
1450 0 /* priority */,
1451 timeout,
1452 GNUNET_NO,
1453 &transmit_send_continuation,
1454 mq);
1455}
1456
1457
1458/**
1459 * Send keepalive message to the neighbour. Must only be called
1460 * if we are on 'connected' state or while trying to switch addresses.
1461 * Will internally determine if a keepalive is truly needed (so can
1462 * always be called).
1463 *
1464 * @param n neighbour that went idle and needs a keepalive
1465 */
1466static void
1467send_keepalive (struct NeighbourMapEntry *n)
1468{
1469 struct GNUNET_ATS_SessionKeepAliveMessage m;
1470 struct GNUNET_TIME_Relative timeout;
1471 uint32_t nonce;
1472
1473 GNUNET_assert ((GNUNET_TRANSPORT_PS_CONNECTED == n->state) ||
1474 (GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT == n->state));
1475 if (GNUNET_TIME_absolute_get_remaining (n->keep_alive_time).rel_value_us > 0)
1476 return; /* no keepalive needed at this time */
1477
1478 nonce = 0; /* 0 indicates 'not set' */
1479 while (0 == nonce)
1480 nonce = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
1481 UINT32_MAX);
1482
1483 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1484 "Sending KEEPALIVE to peer `%s' with nonce %u\n",
1485 GNUNET_i2s (&n->id),
1486 nonce);
1487 m.header.size = htons (sizeof(struct GNUNET_ATS_SessionKeepAliveMessage));
1488 m.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE);
1489 m.nonce = htonl (nonce);
1490
1491 timeout = send_with_session (n,
1492 &m,
1493 sizeof(m),
1494 UINT32_MAX /* priority */,
1495 GNUNET_TIME_UNIT_FOREVER_REL,
1496 GNUNET_YES,
1497 NULL, NULL);
1498 GNUNET_STATISTICS_update (GST_stats,
1499 gettext_noop ("# KEEPALIVES sent"),
1500 1,
1501 GNUNET_NO);
1502 n->primary_address.keep_alive_nonce = nonce;
1503 n->expect_latency_response = GNUNET_YES;
1504 n->last_keep_alive_time = GNUNET_TIME_absolute_get ();
1505 n->keep_alive_time = GNUNET_TIME_relative_to_absolute (timeout);
1506}
1507
1508
1509/**
1510 * Keep the connection to the given neighbour alive longer,
1511 * we received a KEEPALIVE (or equivalent); send a response.
1512 *
1513 * @param neighbour neighbour to keep alive (by sending keep alive response)
1514 * @param m the keep alive message containing the nonce to respond to
1515 */
1516void
1517GST_neighbours_keepalive (const struct GNUNET_PeerIdentity *neighbour,
1518 const struct GNUNET_MessageHeader *m)
1519{
1520 struct NeighbourMapEntry *n;
1521 const struct GNUNET_ATS_SessionKeepAliveMessage *msg_in;
1522 struct GNUNET_ATS_SessionKeepAliveMessage msg;
1523
1524 if (sizeof(struct GNUNET_ATS_SessionKeepAliveMessage) != ntohs (m->size))
1525 {
1526 GNUNET_break_op (0);
1527 return;
1528 }
1529
1530 msg_in = (const struct GNUNET_ATS_SessionKeepAliveMessage *) m;
1531 if (NULL == (n = lookup_neighbour (neighbour)))
1532 {
1533 GNUNET_STATISTICS_update (GST_stats,
1534 gettext_noop
1535 ("# KEEPALIVE messages discarded (peer unknown)"),
1536 1, GNUNET_NO);
1537 return;
1538 }
1539 if (NULL == n->primary_address.session)
1540 {
1541 GNUNET_STATISTICS_update (GST_stats,
1542 gettext_noop
1543 ("# KEEPALIVE messages discarded (no session)"),
1544 1, GNUNET_NO);
1545 return;
1546 }
1547
1548 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1549 "Received KEEPALIVE request from peer `%s' with nonce %u\n",
1550 GNUNET_i2s (&n->id),
1551 ntohl (msg_in->nonce));
1552 GNUNET_STATISTICS_update (GST_stats,
1553 gettext_noop (
1554 "# KEEPALIVES received in good order"),
1555 1,
1556 GNUNET_NO);
1557
1558 /* send reply to allow neighbour to measure latency */
1559 msg.header.size = htons (sizeof(struct GNUNET_ATS_SessionKeepAliveMessage));
1560 msg.header.type = htons (
1561 GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE_RESPONSE);
1562 msg.nonce = msg_in->nonce;
1563 (void) send_with_session (n,
1564 &msg,
1565 sizeof(struct GNUNET_ATS_SessionKeepAliveMessage),
1566 UINT32_MAX /* priority */,
1567 GNUNET_TIME_UNIT_FOREVER_REL,
1568 GNUNET_YES,
1569 NULL, NULL);
1570}
1571
1572
1573/**
1574 * We received a KEEP_ALIVE_RESPONSE message and use this to calculate
1575 * latency to this peer. Pass the updated information (existing ats
1576 * plus calculated latency) to ATS.
1577 *
1578 * @param neighbour neighbour to keep alive
1579 * @param m the message containing the keep alive response
1580 */
1581void
1582GST_neighbours_keepalive_response (const struct GNUNET_PeerIdentity *neighbour,
1583 const struct GNUNET_MessageHeader *m)
1584{
1585 struct NeighbourMapEntry *n;
1586 const struct GNUNET_ATS_SessionKeepAliveMessage *msg;
1587 struct GNUNET_TRANSPORT_PluginFunctions *papi;
1588 struct GNUNET_TIME_Relative latency;
1589
1590 if (sizeof(struct GNUNET_ATS_SessionKeepAliveMessage) != ntohs (m->size))
1591 {
1592 GNUNET_break_op (0);
1593 return;
1594 }
1595
1596 msg = (const struct GNUNET_ATS_SessionKeepAliveMessage *) m;
1597 if (NULL == (n = lookup_neighbour (neighbour)))
1598 {
1599 GNUNET_STATISTICS_update (GST_stats,
1600 gettext_noop (
1601 "# KEEPALIVE_RESPONSEs discarded (not connected)"),
1602 1,
1603 GNUNET_NO);
1604 return;
1605 }
1606 if ((GNUNET_TRANSPORT_PS_CONNECTED != n->state) ||
1607 (GNUNET_YES != n->expect_latency_response))
1608 {
1609 GNUNET_STATISTICS_update (GST_stats,
1610 gettext_noop (
1611 "# KEEPALIVE_RESPONSEs discarded (not expected)"),
1612 1,
1613 GNUNET_NO);
1614 return;
1615 }
1616 if (NULL == n->primary_address.address)
1617 {
1618 GNUNET_STATISTICS_update (GST_stats,
1619 gettext_noop (
1620 "# KEEPALIVE_RESPONSEs discarded (address changed)"),
1621 1,
1622 GNUNET_NO);
1623 return;
1624 }
1625 if (n->primary_address.keep_alive_nonce != ntohl (msg->nonce))
1626 {
1627 if (0 == n->primary_address.keep_alive_nonce)
1628 GNUNET_STATISTICS_update (GST_stats,
1629 gettext_noop (
1630 "# KEEPALIVE_RESPONSEs discarded (no nonce)"),
1631 1,
1632 GNUNET_NO);
1633 else
1634 GNUNET_STATISTICS_update (GST_stats,
1635 gettext_noop (
1636 "# KEEPALIVE_RESPONSEs discarded (bad nonce)"),
1637 1,
1638 GNUNET_NO);
1639 return;
1640 }
1641 GNUNET_STATISTICS_update (GST_stats,
1642 gettext_noop (
1643 "# KEEPALIVE_RESPONSEs received (OK)"),
1644 1,
1645 GNUNET_NO);
1646
1647
1648 /* Update session timeout here */
1649 if (NULL != (papi = GST_plugins_find (
1650 n->primary_address.address->transport_name)))
1651 {
1652 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1653 "Updating session for peer `%s' for session %p\n",
1654 GNUNET_i2s (&n->id),
1655 n->primary_address.session);
1656 papi->update_session_timeout (papi->cls,
1657 &n->id,
1658 n->primary_address.session);
1659 }
1660 else
1661 {
1662 GNUNET_break (0);
1663 }
1664
1665 n->primary_address.keep_alive_nonce = 0;
1666 n->expect_latency_response = GNUNET_NO;
1667 set_state_and_timeout (n,
1668 n->state,
1669 GNUNET_TIME_relative_to_absolute (
1670 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT));
1671
1672 latency = GNUNET_TIME_absolute_get_duration (n->last_keep_alive_time);
1673 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1674 "Received KEEPALIVE_RESPONSE from peer `%s', latency is %s\n",
1675 GNUNET_i2s (&n->id),
1676 GNUNET_STRINGS_relative_time_to_string (latency,
1677 GNUNET_YES));
1678 GST_ats_update_delay (n->primary_address.address,
1679 GNUNET_TIME_relative_divide (latency,
1680 2));
1681}
1682
1683
1684/**
1685 * We have received a message from the given sender. How long should
1686 * we delay before receiving more? (Also used to keep the peer marked
1687 * as live).
1688 *
1689 * @param sender sender of the message
1690 * @param size size of the message
1691 * @param do_forward set to #GNUNET_YES if the message should be forwarded to clients
1692 * #GNUNET_NO if the neighbour is not connected or violates the quota,
1693 * #GNUNET_SYSERR if the connection is not fully up yet
1694 * @return how long to wait before reading more from this sender
1695 */
1696struct GNUNET_TIME_Relative
1697GST_neighbours_calculate_receive_delay (const struct
1698 GNUNET_PeerIdentity *sender,
1699 ssize_t size,
1700 int *do_forward)
1701{
1702 struct NeighbourMapEntry *n;
1703 struct GNUNET_TIME_Relative ret;
1704
1705 if (NULL == neighbours)
1706 {
1707 *do_forward = GNUNET_NO;
1708 return GNUNET_TIME_UNIT_FOREVER_REL; /* This can happen during shutdown */
1709 }
1710 if (NULL == (n = lookup_neighbour (sender)))
1711 {
1712 GNUNET_STATISTICS_update (GST_stats,
1713 gettext_noop (
1714 "# messages discarded due to lack of neighbour record"),
1715 1,
1716 GNUNET_NO);
1717 *do_forward = GNUNET_NO;
1718 return GNUNET_TIME_UNIT_ZERO;
1719 }
1720 if (! test_connected (n))
1721 {
1722 *do_forward = GNUNET_SYSERR;
1723 return GNUNET_TIME_UNIT_ZERO;
1724 }
1725 if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker, size))
1726 {
1727 n->quota_violation_count++;
1728 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1729 "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
1730 n->in_tracker.available_bytes_per_s__,
1731 n->quota_violation_count);
1732 /* Discount 32k per violation */
1733 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker, -32 * 1024);
1734 }
1735 else
1736 {
1737 if (n->quota_violation_count > 0)
1738 {
1739 /* try to add 32k back */
1740 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker, 32 * 1024);
1741 n->quota_violation_count--;
1742 }
1743 }
1744 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
1745 {
1746 GNUNET_STATISTICS_update (GST_stats,
1747 gettext_noop
1748 ("# bandwidth quota violations by other peers"),
1749 1, GNUNET_NO);
1750 *do_forward = GNUNET_NO;
1751 return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
1752 }
1753 *do_forward = GNUNET_YES;
1754 ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 32 * 1024);
1755 if (ret.rel_value_us > 0)
1756 {
1757 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1758 "Throttling read (%lld bytes excess at %u b/s), waiting %s before reading more.\n",
1759 (long long) n->in_tracker.consumption_since_last_update__,
1760 (unsigned int) n->in_tracker.available_bytes_per_s__,
1761 GNUNET_STRINGS_relative_time_to_string (ret, GNUNET_YES));
1762 GNUNET_STATISTICS_update (GST_stats,
1763 gettext_noop ("# ms throttling suggested"),
1764 (int64_t) ret.rel_value_us / 1000LL,
1765 GNUNET_NO);
1766 }
1767 return ret;
1768}
1769
1770
1771void
1772GST_neighbours_send (const struct GNUNET_PeerIdentity *target,
1773 const void *msg,
1774 size_t msg_size,
1775 struct GNUNET_TIME_Relative timeout,
1776 GST_NeighbourSendContinuation cont,
1777 void *cont_cls)
1778{
1779 struct NeighbourMapEntry *n;
1780 struct MessageQueue *mq;
1781
1782 /* All ove these cases should never happen; they are all API violations.
1783 But we check anyway, just to be sure. */
1784 if (NULL == (n = lookup_neighbour (target)))
1785 {
1786 GNUNET_break (0);
1787 if (NULL != cont)
1788 cont (cont_cls,
1789 GNUNET_SYSERR,
1790 msg_size,
1791 0);
1792 return;
1793 }
1794 if (GNUNET_YES != test_connected (n))
1795 {
1796 GNUNET_break (0);
1797 if (NULL != cont)
1798 cont (cont_cls,
1799 GNUNET_SYSERR,
1800 msg_size,
1801 0);
1802 return;
1803 }
1804 bytes_in_send_queue += msg_size;
1805 GNUNET_STATISTICS_set (GST_stats,
1806 gettext_noop
1807 ("# bytes in message queue for other peers"),
1808 bytes_in_send_queue, GNUNET_NO);
1809 mq = GNUNET_malloc (sizeof(struct MessageQueue) + msg_size);
1810 mq->cont = cont;
1811 mq->cont_cls = cont_cls;
1812 GNUNET_memcpy (&mq[1], msg, msg_size);
1813 mq->message_buf = (const char *) &mq[1];
1814 mq->message_buf_size = msg_size;
1815 mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1816
1817 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1818 "Enqueueing %u bytes to send to peer %s\n",
1819 (unsigned int) msg_size,
1820 GNUNET_i2s (target));
1821 GNUNET_CONTAINER_DLL_insert_tail (n->messages_head,
1822 n->messages_tail,
1823 mq);
1824 if (NULL != n->task)
1825 GNUNET_SCHEDULER_cancel (n->task);
1826 n->task = GNUNET_SCHEDULER_add_now (&master_task, n);
1827}
1828
1829
1830/**
1831 * Continuation called from our attempt to transmitted our
1832 * #GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_SYN to the specified @a
1833 * target. Continue processing based on the @a result. Specifically,
1834 * if we failed to transmit, discard the address we used.
1835 *
1836 * @param cls NULL
1837 * @param target which peer received the transmission
1838 * @param result #GNUNET_OK if sending worked
1839 * @param size_payload how many bytes of payload were sent (ignored)
1840 * @param size_on_wire how much bandwidth was consumed on the wire (ignored)
1841 */
1842static void
1843send_session_syn_cont (void *cls,
1844 const struct GNUNET_PeerIdentity *target,
1845 int result,
1846 size_t size_payload,
1847 size_t size_on_wire)
1848{
1849 struct NeighbourMapEntry *n;
1850
1851 (void) cls;
1852 (void) size_payload;
1853 (void) size_on_wire;
1854 n = lookup_neighbour (target);
1855 if (NULL == n)
1856 {
1857 /* SYN continuation was called after neighbor was freed,
1858 * for example due to a time out for the state or the session
1859 * used was already terminated: nothing to do here... */
1860 return;
1861 }
1862
1863 if ((GNUNET_TRANSPORT_PS_SYN_SENT != n->state) &&
1864 (GNUNET_TRANSPORT_PS_RECONNECT_SENT != n->state) &&
1865 (GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT != n->state))
1866 {
1867 /* SYN continuation was called after neighbor changed state,
1868 * for example due to a time out for the state or the session
1869 * used was already terminated: nothing to do here... */
1870 return;
1871 }
1872 if (GNUNET_OK == result)
1873 return;
1874
1875 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1876 _ ("Failed to send SYN message to peer `%s'\n"),
1877 GNUNET_i2s (target));
1878 switch (n->state)
1879 {
1880 case GNUNET_TRANSPORT_PS_SYN_SENT:
1881 /* Remove address and request an additional one */
1882 unset_primary_address (n);
1883 set_state_and_timeout (n,
1884 GNUNET_TRANSPORT_PS_INIT_ATS,
1885 GNUNET_TIME_relative_to_absolute (
1886 FAST_RECONNECT_TIMEOUT));
1887 break;
1888
1889 case GNUNET_TRANSPORT_PS_RECONNECT_SENT:
1890 /* Remove address and request an additional one */
1891 unset_primary_address (n);
1892 set_state_and_timeout (n,
1893 GNUNET_TRANSPORT_PS_RECONNECT_ATS,
1894 GNUNET_TIME_relative_to_absolute (
1895 ATS_RESPONSE_TIMEOUT));
1896 break;
1897
1898 case GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT:
1899 /* Remove address and request and go back to primary address */
1900 GNUNET_STATISTICS_update (GST_stats,
1901 gettext_noop (
1902 "# Failed attempts to switch addresses (failed to send SYN CONT)"),
1903 1,
1904 GNUNET_NO);
1905 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1906 "Switch failed, cleaning up alternative address\n");
1907 free_address (&n->alternative_address);
1908 set_state_and_timeout (n,
1909 GNUNET_TRANSPORT_PS_CONNECTED,
1910 GNUNET_TIME_relative_to_absolute (
1911 ATS_RESPONSE_TIMEOUT));
1912 break;
1913
1914 default:
1915 disconnect_neighbour (n);
1916 break;
1917 }
1918}
1919
1920
1921/**
1922 * Send a SYN message via the given address.
1923 *
1924 * @param na address to use
1925 */
1926static void
1927send_syn (struct NeighbourAddress *na)
1928{
1929 struct GNUNET_TRANSPORT_PluginFunctions *papi;
1930 struct TransportSynMessage connect_msg;
1931 struct NeighbourMapEntry *n;
1932
1933 GNUNET_assert (NULL != na->session);
1934 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1935 "Sending SYN message to peer `%s' at %s\n",
1936 GNUNET_i2s (&na->address->peer),
1937 GST_plugins_a2s (na->address));
1938
1939 papi = GST_plugins_find (na->address->transport_name);
1940 GNUNET_assert (NULL != papi);
1941 GNUNET_STATISTICS_update (GST_stats,
1942 gettext_noop
1943 ("# SYN messages sent"),
1944 1, GNUNET_NO);
1945 na->connect_timestamp = GNUNET_TIME_absolute_get ();
1946 connect_msg.header.size = htons (sizeof(struct TransportSynMessage));
1947 connect_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_SYN);
1948 connect_msg.reserved = htonl (0);
1949 connect_msg.timestamp = GNUNET_TIME_absolute_hton (na->connect_timestamp);
1950 if (-1 ==
1951 papi->send (papi->cls,
1952 na->session,
1953 (const char *) &connect_msg,
1954 sizeof(struct TransportSynMessage),
1955 UINT_MAX,
1956 SETUP_CONNECTION_TIMEOUT,
1957 &send_session_syn_cont, NULL))
1958 {
1959 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1960 _ ("Failed to transmit SYN message to %s\n"),
1961 GST_plugins_a2s (na->address));
1962 n = lookup_neighbour (&na->address->peer);
1963 if (NULL == n)
1964 {
1965 GNUNET_break (0);
1966 return;
1967 }
1968 switch (n->state)
1969 {
1970 case GNUNET_TRANSPORT_PS_SYN_SENT:
1971 /* Remove address and request and additional one */
1972 GNUNET_assert (na == &n->primary_address);
1973 unset_primary_address (n);
1974 set_state_and_timeout (n,
1975 GNUNET_TRANSPORT_PS_INIT_ATS,
1976 GNUNET_TIME_relative_to_absolute (
1977 FAST_RECONNECT_TIMEOUT));
1978 /* Hard failure to send the SYN message with this address:
1979 Destroy address and session */
1980 break;
1981
1982 case GNUNET_TRANSPORT_PS_RECONNECT_SENT:
1983 /* Remove address and request an additional one */
1984 GNUNET_assert (na == &n->primary_address);
1985 unset_primary_address (n);
1986 set_state_and_timeout (n,
1987 GNUNET_TRANSPORT_PS_RECONNECT_ATS,
1988 GNUNET_TIME_relative_to_absolute (
1989 ATS_RESPONSE_TIMEOUT));
1990 break;
1991
1992 case GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT:
1993 GNUNET_assert (na == &n->alternative_address);
1994 GNUNET_STATISTICS_update (GST_stats,
1995 gettext_noop (
1996 "# Failed attempts to switch addresses (failed to send SYN)"),
1997 1,
1998 GNUNET_NO);
1999 /* Remove address and request an additional one */
2000 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2001 "Switch failed, cleaning up alternative address\n");
2002 free_address (&n->alternative_address);
2003 set_state_and_timeout (n,
2004 GNUNET_TRANSPORT_PS_CONNECTED,
2005 GNUNET_TIME_relative_to_absolute (
2006 ATS_RESPONSE_TIMEOUT));
2007 break;
2008
2009 default:
2010 GNUNET_break (0);
2011 disconnect_neighbour (n);
2012 break;
2013 }
2014 return;
2015 }
2016 GST_neighbours_notify_data_sent (na->address,
2017 na->session,
2018 sizeof(struct TransportSynMessage));
2019}
2020
2021
2022/**
2023 * Continuation called from our attempt to transmitted our
2024 * #GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_SYN_ACK to the specified @a
2025 * target. Continue processing based on the @a result. Specifically,
2026 * if we failed to transmit, discard the address we used.
2027 *
2028 * @param cls NULL
2029 * @param target which peer received the transmission
2030 * @param result #GNUNET_OK if sending worked
2031 * @param size_payload how many bytes of payload were sent (ignored)
2032 * @param size_on_wire how much bandwidth was consumed on the wire (ignored)
2033 */
2034static void
2035send_session_syn_ack_cont (void *cls,
2036 const struct GNUNET_PeerIdentity *target,
2037 int result,
2038 size_t size_payload,
2039 size_t size_on_wire)
2040{
2041 struct NeighbourMapEntry *n;
2042
2043 (void) cls;
2044 (void) size_payload;
2045 (void) size_on_wire;
2046 n = lookup_neighbour (target);
2047 if (NULL == n)
2048 {
2049 /* SYN_ACK continuation was called after neighbor was freed,
2050 * for example due to a time out for the state or the session
2051 * used was already terminated: nothing to do here... */
2052 return;
2053 }
2054
2055 if (GNUNET_TRANSPORT_PS_SYN_RECV_ACK != n->state)
2056 {
2057 /* SYN_ACK continuation was called after neighbor changed state,
2058 * for example due to a time out for the state or the session
2059 * used was already terminated: nothing to do here... */
2060 return;
2061 }
2062 if (GNUNET_OK == result)
2063 return;
2064
2065 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2066 _ (
2067 "Failed to send SYN_ACK message to peer `%s' using address `%s'\n"),
2068 GNUNET_i2s (target),
2069 GST_plugins_a2s (n->primary_address.address));
2070
2071 /* Remove address and request and additional one */
2072 /* FIXME: what if the neighbour's primary address
2073 changed in the meantime? Might want to instead
2074 pass "something" around in closure to be sure. */
2075 unset_primary_address (n);
2076 n->ack_state = ACK_SEND_SYN_ACK;
2077 set_state_and_timeout (n,
2078 GNUNET_TRANSPORT_PS_SYN_RECV_ATS,
2079 GNUNET_TIME_relative_to_absolute (
2080 ATS_RESPONSE_TIMEOUT));
2081}
2082
2083
2084/**
2085 * Send a SYN_ACK message via the given address.
2086 *
2087 * @param na address and session to use
2088 * @param timestamp timestamp to use for the ACK message
2089 * @return #GNUNET_SYSERR if sending immediately failed, #GNUNET_OK otherwise
2090 */
2091static void
2092send_syn_ack_message (struct NeighbourAddress *na,
2093 struct GNUNET_TIME_Absolute timestamp)
2094{
2095 const struct GNUNET_HELLO_Address *address = na->address;
2096 struct GNUNET_ATS_Session *session = na->session;
2097 struct GNUNET_TRANSPORT_PluginFunctions *papi;
2098 struct TransportSynMessage connect_msg;
2099 struct NeighbourMapEntry *n;
2100
2101 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2102 "Sending SYN_ACK to peer `%s'\n",
2103 GNUNET_i2s (&address->peer));
2104
2105 if (NULL == (papi = GST_plugins_find (address->transport_name)))
2106 {
2107 GNUNET_break (0);
2108 return;
2109 }
2110 if (NULL == session)
2111 session = papi->get_session (papi->cls,
2112 address);
2113 if (NULL == session)
2114 {
2115 GNUNET_break (0);
2116 return;
2117 }
2118 GST_ats_new_session (address,
2119 session);
2120 GNUNET_STATISTICS_update (GST_stats,
2121 gettext_noop
2122 ("# SYN_ACK messages sent"),
2123 1, GNUNET_NO);
2124 connect_msg.header.size = htons (sizeof(struct TransportSynMessage));
2125 connect_msg.header.type = htons (
2126 GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_SYN_ACK);
2127 connect_msg.reserved = htonl (0);
2128 connect_msg.timestamp = GNUNET_TIME_absolute_hton (timestamp);
2129
2130 if (GNUNET_SYSERR ==
2131 papi->send (papi->cls,
2132 session,
2133 (const char *) &connect_msg,
2134 sizeof(struct TransportSynMessage),
2135 UINT_MAX,
2136 GNUNET_TIME_UNIT_FOREVER_REL,
2137 &send_session_syn_ack_cont, NULL))
2138 {
2139 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2140 _ ("Failed to transmit SYN_ACK message to %s\n"),
2141 GST_plugins_a2s (address));
2142
2143 n = lookup_neighbour (&address->peer);
2144 if (NULL == n)
2145 {
2146 GNUNET_break (0);
2147 return;
2148 }
2149 /* Remove address and request and additional one */
2150 unset_primary_address (n);
2151 n->ack_state = ACK_SEND_SYN_ACK;
2152 set_state_and_timeout (n,
2153 GNUNET_TRANSPORT_PS_SYN_RECV_ATS,
2154 GNUNET_TIME_relative_to_absolute (
2155 ATS_RESPONSE_TIMEOUT));
2156 return;
2157 }
2158}
2159
2160
2161/**
2162 * Function called by the bandwidth tracker for a peer whenever
2163 * the tracker's state changed such that we need to recalculate
2164 * the delay for flow control. We calculate the latest delay
2165 * and inform the plugin (if applicable).
2166 *
2167 * @param cls the `struct NeighbourMapEntry` to update calculations for
2168 */
2169static void
2170inbound_bw_tracker_update (void *cls)
2171{
2172 struct NeighbourMapEntry *n = cls;
2173 struct GNUNET_TRANSPORT_PluginFunctions *papi;
2174 struct GNUNET_TIME_Relative delay;
2175 int do_forward;
2176
2177 if (NULL == n->primary_address.address)
2178 return; /* not active, ignore */
2179 papi = GST_plugins_find (n->primary_address.address->transport_name);
2180 GNUNET_assert (NULL != papi);
2181 if (NULL == papi->update_inbound_delay)
2182 return;
2183 delay = GST_neighbours_calculate_receive_delay (&n->id,
2184 0,
2185 &do_forward);
2186 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2187 "New inbound delay for peer `%s' is %llu ms\n",
2188 GNUNET_i2s (&n->id),
2189 (unsigned long long) delay.rel_value_us / 1000LL);
2190 if (NULL == n->primary_address.session)
2191 return;
2192 papi->update_inbound_delay (papi->cls,
2193 &n->id,
2194 n->primary_address.session,
2195 delay);
2196}
2197
2198
2199/**
2200 * Create a fresh entry in the neighbour map for the given peer
2201 *
2202 * @param peer peer to create an entry for
2203 * @return new neighbour map entry
2204 */
2205static struct NeighbourMapEntry *
2206setup_neighbour (const struct GNUNET_PeerIdentity *peer)
2207{
2208 struct NeighbourMapEntry *n;
2209
2210 if (0 ==
2211 memcmp (&GST_my_identity,
2212 peer,
2213 sizeof(struct GNUNET_PeerIdentity)))
2214 {
2215 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2216 "Cowardly refusing to consider myself my neighbour!\n");
2217 return NULL;
2218 }
2219 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2220 "Creating new neighbour entry for `%s'\n",
2221 GNUNET_i2s (peer));
2222 n = GNUNET_new (struct NeighbourMapEntry);
2223 n->id = *peer;
2224 n->ack_state = ACK_UNDEFINED;
2225 n->last_util_transmission = GNUNET_TIME_absolute_get ();
2226 n->neighbour_receive_quota = GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT;
2227 GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
2228 &inbound_bw_tracker_update,
2229 n,
2230 GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
2231 MAX_BANDWIDTH_CARRY_S);
2232 n->task = GNUNET_SCHEDULER_add_now (&master_task, n);
2233 set_state_and_timeout (n,
2234 GNUNET_TRANSPORT_PS_NOT_CONNECTED,
2235 GNUNET_TIME_UNIT_FOREVER_ABS);
2236 GNUNET_assert (GNUNET_OK ==
2237 GNUNET_CONTAINER_multipeermap_put (neighbours,
2238 &n->id,
2239 n,
2240 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2241 n->suggest_handle = GNUNET_ATS_connectivity_suggest (GST_ats_connect,
2242 peer,
2243 0);
2244
2245 return n;
2246}
2247
2248
2249/**
2250 * Entry in a DLL we use to keep track of pending blacklist checks.
2251 */
2252struct BlacklistCheckSwitchContext
2253{
2254 /**
2255 * DLL prev pointer.
2256 */
2257 struct BlacklistCheckSwitchContext *prev;
2258
2259 /**
2260 * DLL next pointer.
2261 */
2262 struct BlacklistCheckSwitchContext *next;
2263
2264 /**
2265 * Handle to the blacklist check we are performing.
2266 */
2267 struct GST_BlacklistCheck *blc;
2268
2269 /**
2270 * Inbound bandwidth that was assigned to @e address.
2271 */
2272 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in;
2273
2274 /**
2275 * Outbound bandwidth that was assigned to @e address.
2276 */
2277 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out;
2278};
2279
2280
2281/**
2282 * We received a 'SYN' message from the other peer.
2283 * Consider switching to it.
2284 *
2285 * @param message possibly a `struct TransportSynMessage` (check format)
2286 * @param peer identity of the peer to switch the address for
2287 * @return #GNUNET_OK if the message was fine, #GNUNET_SYSERR on serious error
2288 */
2289int
2290GST_neighbours_handle_session_syn (const struct GNUNET_MessageHeader *message,
2291 const struct GNUNET_PeerIdentity *peer)
2292{
2293 const struct TransportSynMessage *scm;
2294 struct NeighbourMapEntry *n;
2295 struct GNUNET_TIME_Absolute ts;
2296
2297 if (ntohs (message->size) != sizeof(struct TransportSynMessage))
2298 {
2299 GNUNET_break_op (0);
2300 return GNUNET_SYSERR;
2301 }
2302 GNUNET_STATISTICS_update (GST_stats,
2303 gettext_noop
2304 ("# SYN messages received"),
2305 1, GNUNET_NO);
2306 if (NULL == neighbours)
2307 {
2308 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2309 _ (
2310 "SYN request from peer `%s' ignored due impending shutdown\n"),
2311 GNUNET_i2s (peer));
2312 return GNUNET_OK; /* we're shutting down */
2313 }
2314 scm = (const struct TransportSynMessage *) message;
2315 GNUNET_break_op (0 == ntohl (scm->reserved));
2316 ts = GNUNET_TIME_absolute_ntoh (scm->timestamp);
2317 if (0 ==
2318 memcmp (&GST_my_identity,
2319 peer,
2320 sizeof(struct GNUNET_PeerIdentity)))
2321 {
2322 /* loopback connection-to-self, ignore */
2323 return GNUNET_SYSERR;
2324 }
2325 n = lookup_neighbour (peer);
2326 if (NULL == n)
2327 {
2328 /* This is a new neighbour and set to not connected */
2329 n = setup_neighbour (peer);
2330 GNUNET_assert (NULL != n);
2331 }
2332
2333 /* Remember this SYN message in neighbour */
2334 n->ack_state = ACK_SEND_SYN_ACK;
2335 n->connect_ack_timestamp = ts;
2336
2337 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2338 "Received SYN for peer `%s' in state %s/%s\n",
2339 GNUNET_i2s (peer),
2340 GNUNET_TRANSPORT_ps2s (n->state),
2341 print_ack_state (n->ack_state));
2342
2343 switch (n->state)
2344 {
2345 case GNUNET_TRANSPORT_PS_NOT_CONNECTED:
2346 /* Request an address from ATS to send SYN_ACK to this peer */
2347 set_state_and_timeout (n,
2348 GNUNET_TRANSPORT_PS_SYN_RECV_ATS,
2349 GNUNET_TIME_relative_to_absolute (
2350 ATS_RESPONSE_TIMEOUT));
2351 break;
2352
2353 case GNUNET_TRANSPORT_PS_INIT_ATS:
2354 /* SYN message takes priority over us asking ATS for address:
2355 * Wait for ATS to suggest an address and send SYN_ACK */
2356 set_state_and_timeout (n,
2357 GNUNET_TRANSPORT_PS_SYN_RECV_ATS,
2358 GNUNET_TIME_relative_to_absolute (
2359 ATS_RESPONSE_TIMEOUT));
2360 break;
2361
2362 case GNUNET_TRANSPORT_PS_SYN_RECV_ATS:
2363 /* We already wait for an address to send an SYN_ACK */
2364 break;
2365
2366 case GNUNET_TRANSPORT_PS_SYN_SENT:
2367 case GNUNET_TRANSPORT_PS_SYN_RECV_ACK:
2368 /* Send ACK immediately */
2369 n->ack_state = ACK_SEND_ACK;
2370 send_syn_ack_message (&n->primary_address,
2371 ts);
2372 break;
2373
2374 case GNUNET_TRANSPORT_PS_CONNECTED:
2375 /* we are already connected and can thus send the ACK immediately */
2376 GNUNET_assert (NULL != n->primary_address.address);
2377 GNUNET_assert (NULL != n->primary_address.session);
2378 n->ack_state = ACK_SEND_ACK;
2379 send_syn_ack_message (&n->primary_address,
2380 ts);
2381 break;
2382
2383 case GNUNET_TRANSPORT_PS_RECONNECT_ATS:
2384 /* We wait for ATS address suggestion */
2385 break;
2386
2387 case GNUNET_TRANSPORT_PS_RECONNECT_SENT:
2388 /* We received a SYN message while waiting for a SYN_ACK in fast
2389 * reconnect. Send SYN_ACK immediately */
2390 n->ack_state = ACK_SEND_ACK;
2391 send_syn_ack_message (&n->primary_address,
2392 n->connect_ack_timestamp);
2393 break;
2394
2395 case GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT:
2396 /* We are already connected and can thus send the ACK immediately;
2397 still, it can never hurt to have an alternative address, so also
2398 tell ATS about it */
2399 GNUNET_assert (NULL != n->primary_address.address);
2400 GNUNET_assert (NULL != n->primary_address.session);
2401 n->ack_state = ACK_SEND_ACK;
2402 send_syn_ack_message (&n->primary_address,
2403 ts);
2404 break;
2405
2406 case GNUNET_TRANSPORT_PS_DISCONNECT:
2407 /* Get rid of remains and re-try */
2408 free_neighbour (n);
2409 n = setup_neighbour (peer);
2410 GNUNET_assert (NULL != n);
2411 /* Remember the SYN time stamp for ACK message */
2412 n->ack_state = ACK_SEND_SYN_ACK;
2413 n->connect_ack_timestamp = ts;
2414 /* Request an address for the peer */
2415 set_state_and_timeout (n,
2416 GNUNET_TRANSPORT_PS_SYN_RECV_ATS,
2417 GNUNET_TIME_relative_to_absolute (
2418 ATS_RESPONSE_TIMEOUT));
2419 break;
2420
2421 case GNUNET_TRANSPORT_PS_DISCONNECT_FINISHED:
2422 /* should not be possible */
2423 GNUNET_assert (0);
2424 break;
2425
2426 default:
2427 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2428 "Unhandled state `%s'\n",
2429 GNUNET_TRANSPORT_ps2s (n->state));
2430 GNUNET_break (0);
2431 return GNUNET_SYSERR;
2432 }
2433 return GNUNET_OK;
2434}
2435
2436
2437/**
2438 * Check if the given @a address is the same that we are already
2439 * using for the respective neighbour. If so, update the bandwidth
2440 * assignment and possibly the session and return #GNUNET_OK.
2441 * If the new address is different from what the neighbour is
2442 * using right now, return #GNUNET_NO.
2443 *
2444 * @param address address of the other peer,
2445 * @param session session to use or NULL if transport should initiate a session
2446 * @param bandwidth_in inbound quota to be used when connection is up,
2447 * 0 to disconnect from peer
2448 * @param bandwidth_out outbound quota to be used when connection is up,
2449 * 0 to disconnect from peer
2450 * @return #GNUNET_OK if we were able to just update the bandwidth and session,
2451 * #GNUNET_NO if more extensive changes are required (address changed)
2452 */
2453static int
2454try_run_fast_ats_update (const struct GNUNET_HELLO_Address *address,
2455 struct GNUNET_ATS_Session *session,
2456 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
2457 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
2458{
2459 struct NeighbourMapEntry *n;
2460
2461 n = lookup_neighbour (&address->peer);
2462 if ((NULL == n) ||
2463 (NULL == n->primary_address.address) ||
2464 (0 != GNUNET_HELLO_address_cmp (address,
2465 n->primary_address.address)))
2466 return GNUNET_NO;
2467 /* We are not really switching addresses, but merely adjusting
2468 session and/or bandwidth, can do fast ATS update! */
2469 if (session != n->primary_address.session)
2470 {
2471 /* switch to a different session, but keeping same address; could
2472 happen if there is a 2nd inbound connection */
2473 n->primary_address.session = session;
2474 GNUNET_assert (GNUNET_YES ==
2475 GST_ats_is_known (n->primary_address.address,
2476 n->primary_address.session));
2477 }
2478 if (n->primary_address.bandwidth_in.value__ != bandwidth_in.value__)
2479 {
2480 n->primary_address.bandwidth_in = bandwidth_in;
2481 if (GNUNET_YES !=
2482 set_incoming_quota (n,
2483 bandwidth_in))
2484 return GNUNET_NO;
2485 }
2486 if (n->primary_address.bandwidth_out.value__ != bandwidth_out.value__)
2487 {
2488 n->primary_address.bandwidth_out = bandwidth_out;
2489 send_outbound_quota_to_clients (n);
2490 }
2491 return GNUNET_OK;
2492}
2493
2494
2495/**
2496 * We've been asked to switch addresses, and just now got the result
2497 * from the blacklist check to see if this is allowed.
2498 *
2499 * @param cls the `struct BlacklistCheckSwitchContext` with
2500 * the information about the future address
2501 * @param peer the peer we may switch addresses on
2502 * @param address address associated with the request
2503 * @param session session associated with the request
2504 * @param result #GNUNET_OK if the connection is allowed,
2505 * #GNUNET_NO if not,
2506 * #GNUNET_SYSERR if operation was aborted
2507 */
2508static void
2509switch_address_bl_check_cont (void *cls,
2510 const struct GNUNET_PeerIdentity *peer,
2511 const struct GNUNET_HELLO_Address *address,
2512 struct GNUNET_ATS_Session *session,
2513 int result)
2514{
2515 struct BlacklistCheckSwitchContext *blc_ctx = cls;
2516 struct GNUNET_TRANSPORT_PluginFunctions *papi;
2517 struct NeighbourMapEntry *n;
2518
2519 if (GNUNET_SYSERR == result)
2520 goto cleanup;
2521
2522 papi = GST_plugins_find (address->transport_name);
2523 if (NULL == papi)
2524 {
2525 /* This can happen during shutdown. */
2526 goto cleanup;
2527 }
2528
2529 if (GNUNET_NO == result)
2530 {
2531 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2532 "Blacklist denied to switch to suggested address `%s' session %p for peer `%s'\n",
2533 GST_plugins_a2s (address),
2534 session,
2535 GNUNET_i2s (peer));
2536 GNUNET_STATISTICS_update (GST_stats,
2537 "# ATS suggestions ignored (blacklist denied)",
2538 1,
2539 GNUNET_NO);
2540 if (NULL != session)
2541 papi->disconnect_session (papi->cls,
2542 session);
2543 if (GNUNET_YES !=
2544 GNUNET_HELLO_address_check_option (address,
2545 GNUNET_HELLO_ADDRESS_INFO_INBOUND))
2546 GST_ats_block_address (address,
2547 NULL);
2548 goto cleanup;
2549 }
2550
2551
2552 if (NULL == session)
2553 {
2554 /* need to create a session, ATS only gave us an address */
2555 session = papi->get_session (papi->cls,
2556 address);
2557 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2558 "Obtained new session for peer `%s' and address '%s': %p\n",
2559 GNUNET_i2s (&address->peer),
2560 GST_plugins_a2s (address),
2561 session);
2562 if (NULL != session)
2563 GST_ats_new_session (address,
2564 session);
2565 }
2566 if (NULL == session)
2567 {
2568 /* session creation failed, bad!, fail! */
2569 GNUNET_STATISTICS_update (GST_stats,
2570 "# ATS suggestions ignored (failed to create session)",
2571 1,
2572 GNUNET_NO);
2573 /* No session could be obtained, remove blacklist check and clean up */
2574 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2575 "Failed to obtain new session for peer `%s' and address '%s'\n",
2576 GNUNET_i2s (&address->peer),
2577 GST_plugins_a2s (address));
2578 GST_ats_block_address (address,
2579 session);
2580 goto cleanup;
2581 }
2582
2583 /* We did this check already before going into blacklist, but
2584 it is theoretically possible that the situation changed in
2585 the meantime, hence we check again here */
2586 if (GNUNET_OK ==
2587 try_run_fast_ats_update (address,
2588 session,
2589 blc_ctx->bandwidth_in,
2590 blc_ctx->bandwidth_out))
2591 goto cleanup; /* was just a minor update, we're done */
2592
2593 /* check if we also need to setup the neighbour entry */
2594 if (NULL == (n = lookup_neighbour (peer)))
2595 {
2596 n = setup_neighbour (peer);
2597 if (NULL == n)
2598 {
2599 /* not sure how this can happen... */
2600 GNUNET_break (0);
2601 goto cleanup;
2602 }
2603 n->state = GNUNET_TRANSPORT_PS_INIT_ATS;
2604 }
2605
2606 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2607 "Peer `%s' switches to address `%s'\n",
2608 GNUNET_i2s (&address->peer),
2609 GST_plugins_a2s (address));
2610
2611 switch (n->state)
2612 {
2613 case GNUNET_TRANSPORT_PS_NOT_CONNECTED:
2614 GNUNET_break (0);
2615 GST_ats_block_address (address,
2616 session);
2617 free_neighbour (n);
2618 return;
2619
2620 case GNUNET_TRANSPORT_PS_INIT_ATS:
2621 /* We requested an address and ATS suggests one:
2622 * set primary address and send SYN message*/
2623 set_primary_address (n,
2624 address,
2625 session,
2626 blc_ctx->bandwidth_in,
2627 blc_ctx->bandwidth_out);
2628 if (ACK_SEND_SYN_ACK == n->ack_state)
2629 {
2630 /* Send pending SYN_ACK message */
2631 n->ack_state = ACK_SEND_ACK;
2632 send_syn_ack_message (&n->primary_address,
2633 n->connect_ack_timestamp);
2634 }
2635 set_state_and_timeout (n,
2636 GNUNET_TRANSPORT_PS_SYN_SENT,
2637 GNUNET_TIME_relative_to_absolute (
2638 SETUP_CONNECTION_TIMEOUT));
2639 send_syn (&n->primary_address);
2640 break;
2641
2642 case GNUNET_TRANSPORT_PS_SYN_SENT:
2643 /* ATS suggested a new address while waiting for an SYN_ACK:
2644 * Switch and send new SYN */
2645 /* ATS suggests a different address, switch again */
2646 set_primary_address (n,
2647 address,
2648 session,
2649 blc_ctx->bandwidth_in,
2650 blc_ctx->bandwidth_out);
2651 if (ACK_SEND_SYN_ACK == n->ack_state)
2652 {
2653 /* Send pending SYN_ACK message */
2654 n->ack_state = ACK_SEND_ACK;
2655 send_syn_ack_message (&n->primary_address,
2656 n->connect_ack_timestamp);
2657 }
2658 set_state_and_timeout (n,
2659 GNUNET_TRANSPORT_PS_SYN_SENT,
2660 GNUNET_TIME_relative_to_absolute (
2661 SETUP_CONNECTION_TIMEOUT));
2662 send_syn (&n->primary_address);
2663 break;
2664
2665 case GNUNET_TRANSPORT_PS_SYN_RECV_ATS:
2666 /* We requested an address and ATS suggests one:
2667 * set primary address and send SYN_ACK message*/
2668 set_primary_address (n,
2669 address,
2670 session,
2671 blc_ctx->bandwidth_in,
2672 blc_ctx->bandwidth_out);
2673 /* Send an ACK message as a response to the SYN msg */
2674 set_state_and_timeout (n,
2675 GNUNET_TRANSPORT_PS_SYN_RECV_ACK,
2676 GNUNET_TIME_relative_to_absolute (
2677 SETUP_CONNECTION_TIMEOUT));
2678 send_syn_ack_message (&n->primary_address,
2679 n->connect_ack_timestamp);
2680 if ((ACK_SEND_SYN_ACK == n->ack_state) ||
2681 (ACK_UNDEFINED == n->ack_state))
2682 n->ack_state = ACK_SEND_ACK;
2683 break;
2684
2685 case GNUNET_TRANSPORT_PS_SYN_RECV_ACK:
2686 /* ATS asks us to switch while we were trying to connect; switch to new
2687 address and check blacklist again */
2688 if ((ACK_SEND_SYN_ACK == n->ack_state))
2689 {
2690 n->ack_state = ACK_SEND_ACK;
2691 send_syn_ack_message (&n->primary_address,
2692 n->connect_ack_timestamp);
2693 }
2694 set_primary_address (n,
2695 address,
2696 session,
2697 blc_ctx->bandwidth_in,
2698 blc_ctx->bandwidth_out);
2699 set_state_and_timeout (n,
2700 GNUNET_TRANSPORT_PS_SYN_RECV_ACK,
2701 GNUNET_TIME_relative_to_absolute (
2702 SETUP_CONNECTION_TIMEOUT));
2703 break;
2704
2705 case GNUNET_TRANSPORT_PS_CONNECTED:
2706 GNUNET_assert (NULL != n->primary_address.address);
2707 GNUNET_assert (NULL != n->primary_address.session);
2708 GNUNET_break (n->primary_address.session != session);
2709 /* ATS asks us to switch a life connection; see if we can get
2710 a SYN_ACK on it before we actually do this! */
2711 set_alternative_address (n,
2712 address,
2713 session,
2714 blc_ctx->bandwidth_in,
2715 blc_ctx->bandwidth_out);
2716 set_state_and_timeout (n,
2717 GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT,
2718 GNUNET_TIME_relative_to_absolute (
2719 SETUP_CONNECTION_TIMEOUT));
2720 GNUNET_STATISTICS_update (GST_stats,
2721 gettext_noop ("# Attempts to switch addresses"),
2722 1,
2723 GNUNET_NO);
2724 send_syn (&n->alternative_address);
2725 break;
2726
2727 case GNUNET_TRANSPORT_PS_RECONNECT_ATS:
2728 set_primary_address (n,
2729 address,
2730 session,
2731 blc_ctx->bandwidth_in,
2732 blc_ctx->bandwidth_out);
2733 if (ACK_SEND_SYN_ACK == n->ack_state)
2734 {
2735 /* Send pending SYN_ACK message */
2736 n->ack_state = ACK_SEND_ACK;
2737 send_syn_ack_message (&n->primary_address,
2738 n->connect_ack_timestamp);
2739 }
2740 set_state_and_timeout (n,
2741 GNUNET_TRANSPORT_PS_RECONNECT_SENT,
2742 GNUNET_TIME_relative_to_absolute (
2743 FAST_RECONNECT_TIMEOUT));
2744 send_syn (&n->primary_address);
2745 break;
2746
2747 case GNUNET_TRANSPORT_PS_RECONNECT_SENT:
2748 /* ATS asks us to switch while we were trying to reconnect; switch to new
2749 address and send SYN again */
2750 set_primary_address (n,
2751 address,
2752 session,
2753 blc_ctx->bandwidth_in,
2754 blc_ctx->bandwidth_out);
2755 set_state_and_timeout (n,
2756 GNUNET_TRANSPORT_PS_RECONNECT_SENT,
2757 GNUNET_TIME_relative_to_absolute (
2758 FAST_RECONNECT_TIMEOUT));
2759 send_syn (&n->primary_address);
2760 break;
2761
2762 case GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT:
2763 if ((0 == GNUNET_HELLO_address_cmp (n->primary_address.address,
2764 address)) &&
2765 (n->primary_address.session == session))
2766 {
2767 /* ATS switches back to still-active session */
2768 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2769 "ATS double-switched, cleaning up alternative address\n");
2770 free_address (&n->alternative_address);
2771 set_state_and_timeout (n,
2772 GNUNET_TRANSPORT_PS_CONNECTED,
2773 n->timeout);
2774 break;
2775 }
2776 /* ATS asks us to switch a life connection, send */
2777 set_alternative_address (n,
2778 address,
2779 session,
2780 blc_ctx->bandwidth_in,
2781 blc_ctx->bandwidth_out);
2782 set_state_and_timeout (n,
2783 GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT,
2784 GNUNET_TIME_relative_to_absolute (
2785 SETUP_CONNECTION_TIMEOUT));
2786 send_syn (&n->alternative_address);
2787 break;
2788
2789 case GNUNET_TRANSPORT_PS_DISCONNECT:
2790 /* not going to switch addresses while disconnecting */
2791 GNUNET_STATISTICS_update (GST_stats,
2792 "# ATS suggestion ignored (disconnecting)",
2793 1,
2794 GNUNET_NO);
2795 return;
2796
2797 case GNUNET_TRANSPORT_PS_DISCONNECT_FINISHED:
2798 GNUNET_assert (0);
2799 break;
2800
2801 default:
2802 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2803 "Unhandled state `%s'\n",
2804 GNUNET_TRANSPORT_ps2s (n->state));
2805 GNUNET_break (0);
2806 break;
2807 }
2808cleanup:
2809 GNUNET_CONTAINER_DLL_remove (pending_bc_head,
2810 pending_bc_tail,
2811 blc_ctx);
2812 GNUNET_free (blc_ctx);
2813}
2814
2815
2816/**
2817 * For the given peer, switch to this address.
2818 *
2819 * Before accepting this addresses and actively using it, a blacklist check
2820 * is performed.
2821 *
2822 * If any check fails or the suggestion can somehow not be followed, we
2823 * MUST call #GST_ats_block_address() to tell ATS that the suggestion
2824 * could not be satisfied and force ATS to do something else.
2825 *
2826 * @param address address of the other peer,
2827 * @param session session to use or NULL if transport should initiate a session
2828 * @param bandwidth_in inbound quota to be used when connection is up,
2829 * 0 to disconnect from peer
2830 * @param bandwidth_out outbound quota to be used when connection is up,
2831 * 0 to disconnect from peer
2832 */
2833void
2834GST_neighbours_switch_to_address (const struct GNUNET_HELLO_Address *address,
2835 struct GNUNET_ATS_Session *session,
2836 struct GNUNET_BANDWIDTH_Value32NBO
2837 bandwidth_in,
2838 struct GNUNET_BANDWIDTH_Value32NBO
2839 bandwidth_out)
2840{
2841 struct GST_BlacklistCheck *blc;
2842 struct BlacklistCheckSwitchContext *blc_ctx;
2843
2844 GNUNET_assert (NULL != address->transport_name);
2845 if (GNUNET_OK ==
2846 try_run_fast_ats_update (address,
2847 session,
2848 bandwidth_in,
2849 bandwidth_out))
2850 return;
2851
2852 /* Check if plugin is available */
2853 if (NULL == (GST_plugins_find (address->transport_name)))
2854 {
2855 /* we don't have the plugin for this address */
2856 GNUNET_break (0);
2857 GST_ats_block_address (address,
2858 session);
2859 return;
2860 }
2861 if ((NULL == session) &&
2862 (GNUNET_HELLO_address_check_option (address,
2863 GNUNET_HELLO_ADDRESS_INFO_INBOUND)))
2864 {
2865 /* This is a inbound address and we do not have a session to use! */
2866 GNUNET_break (0);
2867 GST_ats_block_address (address,
2868 session);
2869 return;
2870 }
2871
2872 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2873 "ATS suggests address '%s' for peer `%s' at %u/%u speed\n",
2874 GST_plugins_a2s (address),
2875 GNUNET_i2s (&address->peer),
2876 (unsigned int) ntohl (bandwidth_in.value__),
2877 (unsigned int) ntohl (bandwidth_out.value__));
2878
2879 /* Perform blacklist check */
2880 blc_ctx = GNUNET_new (struct BlacklistCheckSwitchContext);
2881 blc_ctx->bandwidth_in = bandwidth_in;
2882 blc_ctx->bandwidth_out = bandwidth_out;
2883 GNUNET_CONTAINER_DLL_insert (pending_bc_head,
2884 pending_bc_tail,
2885 blc_ctx);
2886 if (NULL != (blc = GST_blacklist_test_allowed (&address->peer,
2887 address->transport_name,
2888 &switch_address_bl_check_cont,
2889 blc_ctx,
2890 address,
2891 session)))
2892 {
2893 blc_ctx->blc = blc;
2894 }
2895}
2896
2897
2898/**
2899 * Function called to send network utilization data to ATS for
2900 * each active connection.
2901 *
2902 * @param cls NULL
2903 * @param key peer we send utilization data for
2904 * @param value the `struct NeighbourMapEntry *` with data to send
2905 * @return #GNUNET_OK (continue to iterate)
2906 */
2907static int
2908send_utilization_data (void *cls,
2909 const struct GNUNET_PeerIdentity *key,
2910 void *value)
2911{
2912 struct NeighbourMapEntry *n = value;
2913 uint32_t bps_in;
2914 uint32_t bps_out;
2915 struct GNUNET_TIME_Relative delta;
2916
2917 (void) cls;
2918 if ((GNUNET_YES != test_connected (n)) ||
2919 (NULL == n->primary_address.address))
2920 return GNUNET_OK;
2921 delta = GNUNET_TIME_absolute_get_difference (n->last_util_transmission,
2922 GNUNET_TIME_absolute_get ());
2923 bps_in = 0;
2924 if ((0 != n->util_total_bytes_recv) && (0 != delta.rel_value_us))
2925 bps_in = (1000LL * 1000LL * n->util_total_bytes_recv)
2926 / (delta.rel_value_us);
2927 bps_out = 0;
2928 if ((0 != n->util_total_bytes_sent) && (0 != delta.rel_value_us))
2929 bps_out = (1000LL * 1000LL * n->util_total_bytes_sent) / delta.rel_value_us;
2930
2931 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2932 "`%s' total: received %u Bytes/s, sent %u Bytes/s\n",
2933 GNUNET_i2s (key),
2934 bps_in,
2935 bps_out);
2936 GST_ats_update_utilization (n->primary_address.address,
2937 bps_in,
2938 bps_out);
2939 n->util_total_bytes_recv = 0;
2940 n->util_total_bytes_sent = 0;
2941 n->last_util_transmission = GNUNET_TIME_absolute_get ();
2942 return GNUNET_OK;
2943}
2944
2945
2946/**
2947 * Task transmitting utilization in a regular interval
2948 *
2949 * @param cls the `struct NeighbourMapEntry` for which we are running
2950 */
2951static void
2952utilization_transmission (void *cls)
2953{
2954 (void) cls;
2955 util_transmission_tk = NULL;
2956 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
2957 &send_utilization_data,
2958 NULL);
2959 util_transmission_tk
2960 = GNUNET_SCHEDULER_add_delayed (UTIL_TRANSMISSION_INTERVAL,
2961 &utilization_transmission,
2962 NULL);
2963}
2964
2965
2966/**
2967 * Track information about data we received from the
2968 * given address (used to notify ATS about our utilization
2969 * of allocated resources).
2970 *
2971 * @param address the address we got data from
2972 * @param message the message we received (really only the size is used)
2973 */
2974void
2975GST_neighbours_notify_data_recv (const struct GNUNET_HELLO_Address *address,
2976 const struct GNUNET_MessageHeader *message)
2977{
2978 struct NeighbourMapEntry *n;
2979
2980 n = lookup_neighbour (&address->peer);
2981 if (NULL == n)
2982 return;
2983 n->util_total_bytes_recv += ntohs (message->size);
2984}
2985
2986
2987/**
2988 * Track information about data we transmitted using the given @a
2989 * address and @a session (used to notify ATS about our utilization of
2990 * allocated resources).
2991 *
2992 * @param address the address we transmitted data to
2993 * @param session session we used to transmit data
2994 * @param message the message we sent (really only the size is used)
2995 */
2996void
2997GST_neighbours_notify_data_sent (const struct GNUNET_HELLO_Address *address,
2998 struct GNUNET_ATS_Session *session,
2999 size_t size)
3000{
3001 struct NeighbourMapEntry *n;
3002
3003 n = lookup_neighbour (&address->peer);
3004 if (NULL == n)
3005 return;
3006 if (n->primary_address.session != session)
3007 return;
3008 n->util_total_bytes_sent += size;
3009}
3010
3011
3012static void
3013master_task (void *cls)
3014{
3015 struct NeighbourMapEntry *n = cls;
3016 struct GNUNET_TIME_Relative delay;
3017
3018 n->task = NULL;
3019 delay = GNUNET_TIME_absolute_get_remaining (n->timeout);
3020 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3021 "Master task runs for neighbour `%s' in state %s with timeout in %s\n",
3022 GNUNET_i2s (&n->id),
3023 GNUNET_TRANSPORT_ps2s (n->state),
3024 GNUNET_STRINGS_relative_time_to_string (delay,
3025 GNUNET_YES));
3026 switch (n->state)
3027 {
3028 case GNUNET_TRANSPORT_PS_NOT_CONNECTED:
3029 /* invalid state for master task, clean up */
3030 GNUNET_break (0);
3031 free_neighbour (n);
3032 return;
3033
3034 case GNUNET_TRANSPORT_PS_INIT_ATS:
3035 if (0 == delay.rel_value_us)
3036 {
3037 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3038 "Connection to `%s' timed out waiting for ATS to provide address\n",
3039 GNUNET_i2s (&n->id));
3040 free_neighbour (n);
3041 return;
3042 }
3043 break;
3044
3045 case GNUNET_TRANSPORT_PS_SYN_SENT:
3046 if (0 == delay.rel_value_us)
3047 {
3048 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3049 "Connection to `%s' timed out waiting for other peer to send SYN_ACK\n",
3050 GNUNET_i2s (&n->id));
3051 /* Remove address and request and additional one */
3052 unset_primary_address (n);
3053 set_state_and_timeout (n,
3054 GNUNET_TRANSPORT_PS_INIT_ATS,
3055 GNUNET_TIME_relative_to_absolute (
3056 ATS_RESPONSE_TIMEOUT));
3057 return;
3058 }
3059 break;
3060
3061 case GNUNET_TRANSPORT_PS_SYN_RECV_ATS:
3062 if (0 == delay.rel_value_us)
3063 {
3064 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3065 "Connection to `%s' timed out waiting ATS to provide address to use for SYN_ACK\n",
3066 GNUNET_i2s (&n->id));
3067 free_neighbour (n);
3068 return;
3069 }
3070 break;
3071
3072 case GNUNET_TRANSPORT_PS_SYN_RECV_ACK:
3073 if (0 == delay.rel_value_us)
3074 {
3075 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3076 "Connection to `%s' timed out waiting for other peer to send ACK\n",
3077 GNUNET_i2s (&n->id));
3078 disconnect_neighbour (n);
3079 return;
3080 }
3081 break;
3082
3083 case GNUNET_TRANSPORT_PS_CONNECTED:
3084 if (0 == delay.rel_value_us)
3085 {
3086 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3087 "Connection to `%s' timed out, missing KEEPALIVE_RESPONSEs\n",
3088 GNUNET_i2s (&n->id));
3089 disconnect_neighbour (n);
3090 return;
3091 }
3092 try_transmission_to_peer (n);
3093 send_keepalive (n);
3094 break;
3095
3096 case GNUNET_TRANSPORT_PS_RECONNECT_ATS:
3097 if (0 == delay.rel_value_us)
3098 {
3099 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3100 "Connection to `%s' timed out, waiting for ATS replacement address\n",
3101 GNUNET_i2s (&n->id));
3102 disconnect_neighbour (n);
3103 return;
3104 }
3105 break;
3106
3107 case GNUNET_TRANSPORT_PS_RECONNECT_SENT:
3108 if (0 == delay.rel_value_us)
3109 {
3110 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3111 "Connection to `%s' timed out, waiting for other peer to SYN_ACK replacement address\n",
3112 GNUNET_i2s (&n->id));
3113 disconnect_neighbour (n);
3114 return;
3115 }
3116 break;
3117
3118 case GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT:
3119 if (0 == delay.rel_value_us)
3120 {
3121 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3122 "Switch failed, cleaning up alternative address\n");
3123 free_address (&n->alternative_address);
3124 set_state_and_timeout (n,
3125 GNUNET_TRANSPORT_PS_CONNECTED,
3126 GNUNET_TIME_relative_to_absolute (
3127 SETUP_CONNECTION_TIMEOUT));
3128 }
3129 try_transmission_to_peer (n);
3130 send_keepalive (n);
3131 break;
3132
3133 case GNUNET_TRANSPORT_PS_DISCONNECT:
3134 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3135 "Cleaning up connection to `%s' after sending DISCONNECT\n",
3136 GNUNET_i2s (&n->id));
3137 free_neighbour (n);
3138 return;
3139
3140 case GNUNET_TRANSPORT_PS_DISCONNECT_FINISHED:
3141 /* how did we get here!? */
3142 GNUNET_assert (0);
3143 break;
3144
3145 default:
3146 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3147 "Unhandled state `%s'\n",
3148 GNUNET_TRANSPORT_ps2s (n->state));
3149 GNUNET_break (0);
3150 break;
3151 }
3152 delay = GNUNET_TIME_absolute_get_remaining (n->timeout);
3153 if ((GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT == n->state) ||
3154 (GNUNET_TRANSPORT_PS_CONNECTED == n->state))
3155 {
3156 /* if we are *now* in one of the two states, we're sending
3157 keep alive messages, so we need to consider the keepalive
3158 delay, not just the connection timeout */
3159 delay = GNUNET_TIME_relative_min (GNUNET_TIME_absolute_get_remaining (
3160 n->keep_alive_time),
3161 delay);
3162 }
3163 if (NULL == n->task)
3164 n->task = GNUNET_SCHEDULER_add_delayed (delay,
3165 &master_task,
3166 n);
3167}
3168
3169
3170/**
3171 * Send a ACK message to the neighbour to confirm that we
3172 * got its SYN_ACK.
3173 *
3174 * @param n neighbour to send the ACK to
3175 */
3176static void
3177send_session_ack_message (struct NeighbourMapEntry *n)
3178{
3179 struct GNUNET_MessageHeader msg;
3180
3181 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3182 "Sending ACK message to peer `%s'\n",
3183 GNUNET_i2s (&n->id));
3184
3185 msg.size = htons (sizeof(struct GNUNET_MessageHeader));
3186 msg.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_ACK);
3187 (void) send_with_session (n,
3188 &msg,
3189 sizeof(struct GNUNET_MessageHeader),
3190 UINT32_MAX,
3191 GNUNET_TIME_UNIT_FOREVER_REL,
3192 GNUNET_NO,
3193 NULL, NULL);
3194}
3195
3196
3197/**
3198 * We received a 'SESSION_SYN_ACK' message from the other peer.
3199 * Consider switching to it.
3200 *
3201 * @param message possibly a `struct GNUNET_ATS_SessionConnectMessage` (check format)
3202 * @param peer identity of the peer to switch the address for
3203 * @param address address of the other peer, NULL if other peer
3204 * connected to us
3205 * @param session session to use (or NULL)
3206 * @return #GNUNET_OK if the message was fine, #GNUNET_SYSERR on serious error
3207 */
3208int
3209GST_neighbours_handle_session_syn_ack (const struct
3210 GNUNET_MessageHeader *message,
3211 const struct
3212 GNUNET_HELLO_Address *address,
3213 struct GNUNET_ATS_Session *session)
3214{
3215 const struct TransportSynMessage *scm;
3216 struct GNUNET_TIME_Absolute ts;
3217 struct NeighbourMapEntry *n;
3218
3219 (void) session;
3220 if (ntohs (message->size) != sizeof(struct TransportSynMessage))
3221 {
3222 GNUNET_break_op (0);
3223 return GNUNET_SYSERR;
3224 }
3225 GNUNET_STATISTICS_update (GST_stats,
3226 gettext_noop
3227 ("# SYN_ACK messages received"),
3228 1, GNUNET_NO);
3229 scm = (const struct TransportSynMessage *) message;
3230 GNUNET_break_op (ntohl (scm->reserved) == 0);
3231 if (NULL == (n = lookup_neighbour (&address->peer)))
3232 {
3233 GNUNET_STATISTICS_update (GST_stats,
3234 gettext_noop
3235 ("# unexpected SYN_ACK messages (no peer)"),
3236 1, GNUNET_NO);
3237 return GNUNET_SYSERR;
3238 }
3239 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3240 "Received SYN_ACK message from peer `%s' in state %s/%s\n",
3241 GNUNET_i2s (&address->peer),
3242 GNUNET_TRANSPORT_ps2s (n->state),
3243 print_ack_state (n->ack_state));
3244 ts = GNUNET_TIME_absolute_ntoh (scm->timestamp);
3245 switch (n->state)
3246 {
3247 case GNUNET_TRANSPORT_PS_NOT_CONNECTED:
3248 GNUNET_break (0);
3249 free_neighbour (n);
3250 return GNUNET_SYSERR;
3251
3252 case GNUNET_TRANSPORT_PS_INIT_ATS:
3253 GNUNET_STATISTICS_update (GST_stats,
3254 gettext_noop (
3255 "# unexpected SYN_ACK messages (not ready)"),
3256 1,
3257 GNUNET_NO);
3258 break;
3259
3260 case GNUNET_TRANSPORT_PS_SYN_SENT:
3261 if (ts.abs_value_us != n->primary_address.connect_timestamp.abs_value_us)
3262 {
3263 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3264 "SYN_ACK ignored as the timestamp does not match our SYN request\n");
3265 return GNUNET_OK;
3266 }
3267 set_state_and_timeout (n,
3268 GNUNET_TRANSPORT_PS_CONNECTED,
3269 GNUNET_TIME_relative_to_absolute (
3270 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT));
3271 set_primary_address (n,
3272 n->primary_address.address,
3273 n->primary_address.session,
3274 n->primary_address.bandwidth_in,
3275 n->primary_address.bandwidth_out);
3276 send_session_ack_message (n);
3277 break;
3278
3279 case GNUNET_TRANSPORT_PS_SYN_RECV_ATS:
3280 case GNUNET_TRANSPORT_PS_SYN_RECV_ACK:
3281 GNUNET_STATISTICS_update (GST_stats,
3282 gettext_noop (
3283 "# unexpected SYN_ACK messages (not ready)"),
3284 1,
3285 GNUNET_NO);
3286 break;
3287
3288 case GNUNET_TRANSPORT_PS_CONNECTED:
3289 /* duplicate SYN_ACK, let's answer by duplicate ACK just in case */
3290 send_session_ack_message (n);
3291 break;
3292
3293 case GNUNET_TRANSPORT_PS_RECONNECT_ATS:
3294 /* we didn't expect any SYN_ACK, as we are waiting for ATS
3295 to give us a new address... */
3296 GNUNET_STATISTICS_update (GST_stats,
3297 gettext_noop (
3298 "# unexpected SYN_ACK messages (waiting on ATS)"),
3299 1,
3300 GNUNET_NO);
3301 break;
3302
3303 case GNUNET_TRANSPORT_PS_RECONNECT_SENT:
3304 /* Reconnecting with new address address worked; go back to connected! */
3305 set_state_and_timeout (n,
3306 GNUNET_TRANSPORT_PS_CONNECTED,
3307 GNUNET_TIME_relative_to_absolute (
3308 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT));
3309 send_session_ack_message (n);
3310 break;
3311
3312 case GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT:
3313 /* new address worked; adopt it and go back to connected! */
3314 set_state_and_timeout (n,
3315 GNUNET_TRANSPORT_PS_CONNECTED,
3316 GNUNET_TIME_relative_to_absolute (
3317 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT));
3318 GNUNET_break (GNUNET_NO == n->alternative_address.ats_active);
3319
3320 /* Set primary addresses */
3321 set_primary_address (n,
3322 n->alternative_address.address,
3323 n->alternative_address.session,
3324 n->alternative_address.bandwidth_in,
3325 n->alternative_address.bandwidth_out);
3326 GNUNET_STATISTICS_update (GST_stats,
3327 gettext_noop (
3328 "# Successful attempts to switch addresses"),
3329 1,
3330 GNUNET_NO);
3331
3332 GNUNET_HELLO_address_free (n->alternative_address.address);
3333 memset (&n->alternative_address,
3334 0,
3335 sizeof(n->alternative_address));
3336 send_session_ack_message (n);
3337 break;
3338
3339 case GNUNET_TRANSPORT_PS_DISCONNECT:
3340 GNUNET_STATISTICS_update (GST_stats,
3341 gettext_noop
3342 ("# unexpected SYN_ACK messages (disconnecting)"),
3343 1, GNUNET_NO);
3344 return GNUNET_SYSERR;
3345
3346 case GNUNET_TRANSPORT_PS_DISCONNECT_FINISHED:
3347 GNUNET_assert (0);
3348 break;
3349
3350 default:
3351 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3352 "Unhandled state `%s'\n",
3353 GNUNET_TRANSPORT_ps2s (n->state));
3354 GNUNET_break (0);
3355 return GNUNET_SYSERR;
3356 }
3357 return GNUNET_OK;
3358}
3359
3360
3361/**
3362 * A session was terminated. Take note; if needed, try to get
3363 * an alternative address from ATS.
3364 *
3365 * @param peer identity of the peer where the session died
3366 * @param session session that is gone
3367 * @return #GNUNET_YES if this was a session used, #GNUNET_NO if
3368 * this session was not in use
3369 */
3370int
3371GST_neighbours_session_terminated (const struct GNUNET_PeerIdentity *peer,
3372 struct GNUNET_ATS_Session *session)
3373{
3374 struct NeighbourMapEntry *n;
3375
3376 if (NULL == (n = lookup_neighbour (peer)))
3377 return GNUNET_NO; /* can't affect us */
3378 if (session != n->primary_address.session)
3379 {
3380 /* Free alternative address */
3381 if (session == n->alternative_address.session)
3382 {
3383 if (GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT == n->state)
3384 set_state_and_timeout (n,
3385 GNUNET_TRANSPORT_PS_CONNECTED,
3386 n->timeout);
3387 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3388 "Session died, cleaning up alternative address\n");
3389 free_address (&n->alternative_address);
3390 }
3391 return GNUNET_NO; /* doesn't affect us further */
3392 }
3393
3394 n->expect_latency_response = GNUNET_NO;
3395 /* The session for neighbour's primary address died */
3396 switch (n->state)
3397 {
3398 case GNUNET_TRANSPORT_PS_NOT_CONNECTED:
3399 GNUNET_break (0);
3400 free_neighbour (n);
3401 return GNUNET_YES;
3402
3403 case GNUNET_TRANSPORT_PS_INIT_ATS:
3404 GNUNET_break (0);
3405 free_neighbour (n);
3406 return GNUNET_YES;
3407
3408 case GNUNET_TRANSPORT_PS_SYN_SENT:
3409 /* The session used to send the SYN terminated:
3410 * this implies a connect error*/
3411 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3412 "Failed to send SYN in CONNECT_SENT with `%s' %p: session terminated\n",
3413 GST_plugins_a2s (n->primary_address.address),
3414 n->primary_address.session);
3415
3416 /* Destroy the address since it cannot be used */
3417 unset_primary_address (n);
3418 set_state_and_timeout (n,
3419 GNUNET_TRANSPORT_PS_INIT_ATS,
3420 GNUNET_TIME_relative_to_absolute (
3421 ATS_RESPONSE_TIMEOUT));
3422 break;
3423
3424 case GNUNET_TRANSPORT_PS_SYN_RECV_ATS:
3425 case GNUNET_TRANSPORT_PS_SYN_RECV_ACK:
3426 /* error on inbound session; free neighbour entirely */
3427 free_neighbour (n);
3428 return GNUNET_YES;
3429
3430 case GNUNET_TRANSPORT_PS_CONNECTED:
3431 /* Our primary connection died, try a fast reconnect */
3432 unset_primary_address (n);
3433 set_state_and_timeout (n,
3434 GNUNET_TRANSPORT_PS_RECONNECT_ATS,
3435 GNUNET_TIME_relative_to_absolute (
3436 ATS_RESPONSE_TIMEOUT));
3437 break;
3438
3439 case GNUNET_TRANSPORT_PS_RECONNECT_ATS:
3440 /* we don't have an address, how can it go down? */
3441 GNUNET_break (0);
3442 break;
3443
3444 case GNUNET_TRANSPORT_PS_RECONNECT_SENT:
3445 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3446 "Failed to send SYN in RECONNECT_SENT with `%s' %p: session terminated\n",
3447 GST_plugins_a2s (n->primary_address.address),
3448 n->primary_address.session);
3449 /* Destroy the address since it cannot be used */
3450 unset_primary_address (n);
3451 set_state_and_timeout (n,
3452 GNUNET_TRANSPORT_PS_RECONNECT_ATS,
3453 GNUNET_TIME_relative_to_absolute (
3454 ATS_RESPONSE_TIMEOUT));
3455 break;
3456
3457 case GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT:
3458 /* primary went down while we were waiting for SYN_ACK on secondary;
3459 secondary as primary */
3460
3461 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3462 "Connection `%s' %p to peer `%s' was terminated while switching, "
3463 "switching to alternative address `%s' %p\n",
3464 GST_plugins_a2s (n->primary_address.address),
3465 n->primary_address.session,
3466 GNUNET_i2s (peer),
3467 GST_plugins_a2s (n->alternative_address.address),
3468 n->alternative_address.session);
3469
3470 /* Destroy the inbound address since it cannot be used */
3471 free_address (&n->primary_address);
3472 n->primary_address = n->alternative_address;
3473 GNUNET_assert (GNUNET_YES ==
3474 GST_ats_is_known (n->primary_address.address,
3475 n->primary_address.session));
3476 memset (&n->alternative_address,
3477 0,
3478 sizeof(struct NeighbourAddress));
3479 set_state_and_timeout (n,
3480 GNUNET_TRANSPORT_PS_RECONNECT_SENT,
3481 GNUNET_TIME_relative_to_absolute (
3482 FAST_RECONNECT_TIMEOUT));
3483 break;
3484
3485 case GNUNET_TRANSPORT_PS_DISCONNECT:
3486 unset_primary_address (n);
3487 break;
3488
3489 case GNUNET_TRANSPORT_PS_DISCONNECT_FINISHED:
3490 /* neighbour was freed and plugins told to terminate session */
3491 return GNUNET_NO;
3492
3493 default:
3494 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3495 "Unhandled state `%s'\n",
3496 GNUNET_TRANSPORT_ps2s (n->state));
3497 GNUNET_break (0);
3498 break;
3499 }
3500 if (NULL != n->task)
3501 GNUNET_SCHEDULER_cancel (n->task);
3502 n->task = GNUNET_SCHEDULER_add_now (&master_task, n);
3503 return GNUNET_YES;
3504}
3505
3506
3507/**
3508 * We received a 'ACK' message from the other peer.
3509 * If we sent a 'SYN_ACK' last, this means we are now
3510 * connected. Otherwise, do nothing.
3511 *
3512 * @param message possibly a 'struct GNUNET_ATS_SessionConnectMessage' (check format)
3513 * @param address address of the other peer
3514 * @param session session to use (or NULL)
3515 * @return #GNUNET_OK if the message was fine, #GNUNET_SYSERR on serious error
3516 */
3517int
3518GST_neighbours_handle_session_ack (const struct GNUNET_MessageHeader *message,
3519 const struct GNUNET_HELLO_Address *address,
3520 struct GNUNET_ATS_Session *session)
3521{
3522 struct NeighbourMapEntry *n;
3523
3524 (void) session;
3525 if (ntohs (message->size) != sizeof(struct GNUNET_MessageHeader))
3526 {
3527 GNUNET_break_op (0);
3528 return GNUNET_SYSERR;
3529 }
3530 GNUNET_STATISTICS_update (GST_stats,
3531 gettext_noop ("# ACK messages received"),
3532 1,
3533 GNUNET_NO);
3534 if (NULL == (n = lookup_neighbour (&address->peer)))
3535 {
3536 GNUNET_break_op (0);
3537 return GNUNET_SYSERR;
3538 }
3539 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3540 "Received ACK for peer `%s' in state %s/%s\n",
3541 GNUNET_i2s (&address->peer),
3542 GNUNET_TRANSPORT_ps2s (n->state),
3543 print_ack_state (n->ack_state));
3544
3545 /* Check if we are in a plausible state for having sent
3546 a SYN_ACK. If not, return, otherwise break.
3547
3548 The remote peers sends a ACK as a response for a SYN_ACK
3549 message.
3550
3551 We expect a ACK:
3552 - If a remote peer has sent a SYN, we responded with a SYN_ACK and
3553 now wait for the ACK to finally be connected
3554 - If we sent a SYN_ACK to this peer before */if (((GNUNET_TRANSPORT_PS_SYN_RECV_ACK != n->state) &&
3555 (ACK_SEND_ACK != n->ack_state)) ||
3556 (NULL == n->primary_address.address))
3557 {
3558 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3559 "Received unexpected ACK message from peer `%s' in state %s/%s\n",
3560 GNUNET_i2s (&address->peer),
3561 GNUNET_TRANSPORT_ps2s (n->state),
3562 print_ack_state (n->ack_state));
3563
3564 GNUNET_STATISTICS_update (GST_stats,
3565 gettext_noop ("# unexpected ACK messages"),
3566 1,
3567 GNUNET_NO);
3568 return GNUNET_OK;
3569 }
3570 if (GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT == n->state)
3571 {
3572 /* We tried to switch addresses while being connect. We explicitly wait
3573 * for a SYN_ACK before going to GNUNET_TRANSPORT_PS_CONNECTED,
3574 * so we do not want to set the address as in use! */
3575 return GNUNET_OK;
3576 }
3577 set_state_and_timeout (n,
3578 GNUNET_TRANSPORT_PS_CONNECTED,
3579 GNUNET_TIME_relative_to_absolute (
3580 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT));
3581
3582 if (NULL == n->primary_address.address)
3583 {
3584 /* See issue #3693.
3585 * We are in state = PSY_SYN_RECV_ACK or ack_state = ACK_SEND_ACK, which
3586 * really means we did try (and succeed) to send a SYN and are waiting for
3587 * an ACK.
3588 * That suggests that the primary_address used to be non-NULL, but maybe it
3589 * got reset to NULL without the state being changed appropriately?
3590 */GNUNET_break (0);
3591 return GNUNET_OK;
3592 }
3593
3594 /* Reset backoff for primary address */
3595 GST_ats_block_reset (n->primary_address.address,
3596 n->primary_address.session);
3597 return GNUNET_OK;
3598}
3599
3600
3601/**
3602 * Test if we're connected to the given peer.
3603 *
3604 * @param target peer to test
3605 * @return #GNUNET_YES if we are connected, #GNUNET_NO if not
3606 */
3607int
3608GST_neighbours_test_connected (const struct GNUNET_PeerIdentity *target)
3609{
3610 return test_connected (lookup_neighbour (target));
3611}
3612
3613
3614/**
3615 * Task to asynchronously run #free_neighbour().
3616 *
3617 * @param cls the `struct NeighbourMapEntry` to free
3618 */
3619static void
3620delayed_disconnect (void *cls)
3621{
3622 struct NeighbourMapEntry *n = cls;
3623
3624 n->delayed_disconnect_task = NULL;
3625 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3626 "Disconnecting by request from peer %s\n",
3627 GNUNET_i2s (&n->id));
3628 free_neighbour (n);
3629}
3630
3631
3632void
3633GST_neighbours_handle_quota_message (const struct GNUNET_PeerIdentity *peer,
3634 const struct GNUNET_MessageHeader *msg)
3635{
3636 struct NeighbourMapEntry *n;
3637 const struct GNUNET_ATS_SessionQuotaMessage *sqm;
3638 struct GNUNET_BANDWIDTH_Value32NBO last;
3639
3640 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3641 "Received QUOTA message from peer `%s'\n",
3642 GNUNET_i2s (peer));
3643 if (ntohs (msg->size) != sizeof(struct GNUNET_ATS_SessionQuotaMessage))
3644 {
3645 GNUNET_break_op (0);
3646 GNUNET_STATISTICS_update (GST_stats,
3647 gettext_noop (
3648 "# quota messages ignored (malformed)"),
3649 1,
3650 GNUNET_NO);
3651 return;
3652 }
3653 GNUNET_STATISTICS_update (GST_stats,
3654 gettext_noop
3655 ("# QUOTA messages received"),
3656 1, GNUNET_NO);
3657 sqm = (const struct GNUNET_ATS_SessionQuotaMessage *) msg;
3658 if (NULL == (n = lookup_neighbour (peer)))
3659 {
3660 /* gone already */
3661 return;
3662 }
3663 last = GNUNET_BANDWIDTH_value_max (GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
3664 GNUNET_BANDWIDTH_value_init (ntohl (
3665 sqm->quota)));
3666 if (last.value__ != n->neighbour_receive_quota.value__)
3667 {
3668 n->neighbour_receive_quota = last;
3669 send_outbound_quota_to_clients (n);
3670 }
3671}
3672
3673
3674/**
3675 * We received a disconnect message from the given peer,
3676 * validate and process.
3677 *
3678 * @param peer sender of the message
3679 * @param msg the disconnect message
3680 */
3681void
3682GST_neighbours_handle_disconnect_message (const struct
3683 GNUNET_PeerIdentity *peer,
3684 const struct
3685 GNUNET_MessageHeader *msg)
3686{
3687 struct NeighbourMapEntry *n;
3688 const struct GNUNET_ATS_SessionDisconnectMessage *sdm;
3689
3690 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3691 "Received DISCONNECT message from peer `%s'\n",
3692 GNUNET_i2s (peer));
3693 if (ntohs (msg->size) != sizeof(struct GNUNET_ATS_SessionDisconnectMessage))
3694 {
3695 GNUNET_break_op (0);
3696 GNUNET_STATISTICS_update (GST_stats,
3697 gettext_noop
3698 ("# disconnect messages ignored (malformed)"),
3699 1,
3700 GNUNET_NO);
3701 return;
3702 }
3703 GNUNET_STATISTICS_update (GST_stats,
3704 gettext_noop
3705 ("# DISCONNECT messages received"),
3706 1, GNUNET_NO);
3707 sdm = (const struct GNUNET_ATS_SessionDisconnectMessage *) msg;
3708 if (NULL == (n = lookup_neighbour (peer)))
3709 {
3710 /* gone already */
3711 return;
3712 }
3713 if (GNUNET_TIME_absolute_ntoh (sdm->timestamp).abs_value_us <=
3714 n->connect_ack_timestamp.abs_value_us)
3715 {
3716 GNUNET_STATISTICS_update (GST_stats,
3717 gettext_noop (
3718 "# disconnect messages ignored (timestamp)"),
3719 1,
3720 GNUNET_NO);
3721 return;
3722 }
3723 if (0 != memcmp (peer,
3724 &sdm->public_key,
3725 sizeof(struct GNUNET_PeerIdentity)))
3726 {
3727 GNUNET_break_op (0);
3728 return;
3729 }
3730 if (ntohl (sdm->purpose.size) !=
3731 sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose)
3732 + sizeof(struct GNUNET_CRYPTO_EddsaPublicKey)
3733 + sizeof(struct GNUNET_TIME_AbsoluteNBO))
3734 {
3735 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3736 "DISCONNECT message from peer `%s' has invalid size\n",
3737 GNUNET_i2s (peer));
3738 GNUNET_break_op (0);
3739 return;
3740 }
3741 if (GNUNET_OK !=
3742 GNUNET_CRYPTO_eddsa_verify_ (
3743 GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT,
3744 &sdm->purpose,
3745 &sdm->signature,
3746 &sdm->public_key))
3747 {
3748 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3749 "DISCONNECT message from peer `%s' cannot be verified \n",
3750 GNUNET_i2s (peer));
3751 GNUNET_break_op (0);
3752 return;
3753 }
3754 if (NULL == n->delayed_disconnect_task)
3755 {
3756 n->delayed_disconnect_task = GNUNET_SCHEDULER_add_now (&delayed_disconnect,
3757 n);
3758 }
3759}
3760
3761
3762/**
3763 * Closure for the #neighbours_iterate() function.
3764 */
3765struct IteratorContext
3766{
3767 /**
3768 * Function to call on each connected neighbour.
3769 */
3770 GST_NeighbourIterator cb;
3771
3772 /**
3773 * Closure for @e cb.
3774 */
3775 void *cb_cls;
3776};
3777
3778
3779/**
3780 * Call the callback from the closure for each neighbour.
3781 *
3782 * @param cls the `struct IteratorContext`
3783 * @param key the hash of the public key of the neighbour
3784 * @param value the `struct NeighbourMapEntry`
3785 * @return #GNUNET_OK (continue to iterate)
3786 */
3787static int
3788neighbours_iterate (void *cls,
3789 const struct GNUNET_PeerIdentity *key,
3790 void *value)
3791{
3792 struct IteratorContext *ic = cls;
3793 struct NeighbourMapEntry *n = value;
3794 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in;
3795 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out;
3796
3797 (void) key;
3798 if (NULL != n->primary_address.address)
3799 {
3800 bandwidth_in = n->primary_address.bandwidth_in;
3801 bandwidth_out = n->primary_address.bandwidth_out;
3802 }
3803 else
3804 {
3805 bandwidth_in = GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT;
3806 bandwidth_out = GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT;
3807 }
3808 ic->cb (ic->cb_cls,
3809 &n->id,
3810 n->primary_address.address,
3811 n->state,
3812 n->timeout,
3813 bandwidth_in, bandwidth_out);
3814 return GNUNET_OK;
3815}
3816
3817
3818/**
3819 * Iterate over all connected neighbours.
3820 *
3821 * @param cb function to call
3822 * @param cb_cls closure for @a cb
3823 */
3824void
3825GST_neighbours_iterate (GST_NeighbourIterator cb,
3826 void *cb_cls)
3827{
3828 struct IteratorContext ic;
3829
3830 if (NULL == neighbours)
3831 return; /* can happen during shutdown */
3832 ic.cb = cb;
3833 ic.cb_cls = cb_cls;
3834 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
3835 &neighbours_iterate,
3836 &ic);
3837}
3838
3839
3840/**
3841 * If we have an active connection to the given target, it must be shutdown.
3842 *
3843 * @param target peer to disconnect from
3844 */
3845void
3846GST_neighbours_force_disconnect (const struct GNUNET_PeerIdentity *target)
3847{
3848 struct NeighbourMapEntry *n;
3849
3850 if (NULL == (n = lookup_neighbour (target)))
3851 return; /* not active */
3852 if (GNUNET_YES == test_connected (n))
3853 GNUNET_STATISTICS_update (GST_stats,
3854 gettext_noop (
3855 "# disconnected from peer upon explicit request"),
3856 1,
3857 GNUNET_NO);
3858 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3859 "Forced disconnect from peer %s\n",
3860 GNUNET_i2s (target));
3861 disconnect_neighbour (n);
3862}
3863
3864
3865/**
3866 * Obtain current address information for the given neighbour.
3867 *
3868 * @param peer
3869 * @return address currently used
3870 */
3871const struct GNUNET_HELLO_Address *
3872GST_neighbour_get_current_address (const struct GNUNET_PeerIdentity *peer)
3873{
3874 struct NeighbourMapEntry *n;
3875
3876 n = lookup_neighbour (peer);
3877 if (NULL == n)
3878 return NULL;
3879 return n->primary_address.address;
3880}
3881
3882
3883/**
3884 * Initialize the neighbours subsystem.
3885 *
3886 * @param max_fds maximum number of fds to use
3887 */
3888void
3889GST_neighbours_start (unsigned int max_fds)
3890{
3891 (void) max_fds;
3892 neighbours = GNUNET_CONTAINER_multipeermap_create (NEIGHBOUR_TABLE_SIZE,
3893 GNUNET_NO);
3894 util_transmission_tk = GNUNET_SCHEDULER_add_delayed (
3895 UTIL_TRANSMISSION_INTERVAL,
3896 &utilization_transmission,
3897 NULL);
3898}
3899
3900
3901/**
3902 * Disconnect from the given neighbour.
3903 *
3904 * @param cls unused
3905 * @param key hash of neighbour's public key (not used)
3906 * @param value the `struct NeighbourMapEntry` of the neighbour
3907 * @return #GNUNET_OK (continue to iterate)
3908 */
3909static int
3910disconnect_all_neighbours (void *cls,
3911 const struct GNUNET_PeerIdentity *key,
3912 void *value)
3913{
3914 struct NeighbourMapEntry *n = value;
3915
3916 (void) cls;
3917 (void) key;
3918 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3919 "Disconnecting peer `%4s' during shutdown\n",
3920 GNUNET_i2s (&n->id));
3921 free_neighbour (n);
3922 return GNUNET_OK;
3923}
3924
3925
3926/**
3927 * Cleanup the neighbours subsystem.
3928 */
3929void
3930GST_neighbours_stop ()
3931{
3932 if (NULL == neighbours)
3933 return;
3934 if (NULL != util_transmission_tk)
3935 {
3936 GNUNET_SCHEDULER_cancel (util_transmission_tk);
3937 util_transmission_tk = NULL;
3938 }
3939 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
3940 &disconnect_all_neighbours,
3941 NULL);
3942 GNUNET_CONTAINER_multipeermap_destroy (neighbours);
3943 neighbours = NULL;
3944}
3945
3946
3947/* end of file gnunet-service-transport_neighbours.c */
diff --git a/src/transport/gnunet-service-transport_neighbours.h b/src/transport/gnunet-service-transport_neighbours.h
deleted file mode 100644
index 7ce911aa1..000000000
--- a/src/transport/gnunet-service-transport_neighbours.h
+++ /dev/null
@@ -1,321 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010-2015 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/gnunet-service-transport_neighbours.h
23 * @brief neighbour management API
24 * @author Christian Grothoff
25 */
26#ifndef GNUNET_SERVICE_TRANSPORT_NEIGHBOURS_H
27#define GNUNET_SERVICE_TRANSPORT_NEIGHBOURS_H
28
29#include "gnunet_statistics_service.h"
30#include "gnunet_transport_service.h"
31#include "gnunet_transport_plugin.h"
32#include "gnunet-service-transport.h"
33#include "transport.h"
34#include "gnunet_util_lib.h"
35
36
37/**
38 * Initialize the neighbours subsystem.
39 *
40 * @param max_fds maximum number of fds to use
41 */
42void
43GST_neighbours_start (unsigned int max_fds);
44
45
46/**
47 * Cleanup the neighbours subsystem.
48 */
49void
50GST_neighbours_stop (void);
51
52
53/**
54 * Test if we're connected to the given peer.
55 *
56 * @param target peer to test
57 * @return #GNUNET_YES if we are connected, #GNUNET_NO if not
58 */
59int
60GST_neighbours_test_connected (const struct GNUNET_PeerIdentity *target);
61
62
63/**
64 * Function called after the transmission is done.
65 *
66 * @param cls closure
67 * @param success #GNUNET_OK on success, #GNUNET_NO on failure, #GNUNET_SYSERR if we're not connected
68 * @param bytes_payload how much payload was transmitted
69 * @param bytes_on_wire how many bytes were used on the wire
70 */
71typedef void
72(*GST_NeighbourSendContinuation) (void *cls,
73 int success,
74 size_t bytes_payload,
75 size_t bytes_on_wire);
76
77
78/**
79 * Transmit a message to the given target using the active connection.
80 *
81 * @param target destination
82 * @param msg message to send
83 * @param msg_size number of bytes in @a msg
84 * @param timeout when to fail with timeout
85 * @param cont function to call when done
86 * @param cont_cls closure for @a cont
87 */
88void
89GST_neighbours_send (const struct GNUNET_PeerIdentity *target,
90 const void *msg,
91 size_t msg_size,
92 struct GNUNET_TIME_Relative timeout,
93 GST_NeighbourSendContinuation cont, void *cont_cls);
94
95
96/**
97 * We have received a message from the given sender.
98 * How long should we delay before receiving more?
99 * (Also used to keep the peer marked as live).
100 *
101 * @param sender sender of the message
102 * @param size size of the message
103 * @param do_forward set to #GNUNET_YES if the message should be forwarded to clients
104 * #GNUNET_NO if the neighbour is not connected or violates the quota
105 * @return how long to wait before reading more from this sender
106 */
107struct GNUNET_TIME_Relative
108GST_neighbours_calculate_receive_delay (const struct
109 GNUNET_PeerIdentity *sender,
110 ssize_t size,
111 int *do_forward);
112
113
114/**
115 * Keep the connection to the given neighbour alive longer,
116 * we received a KEEPALIVE (or equivalent); send a response.
117 *
118 * @param neighbour neighbour to keep alive (by sending keep alive response)
119 * @param m the keep alive message containing the nonce to respond to
120 */
121void
122GST_neighbours_keepalive (const struct GNUNET_PeerIdentity *neighbour,
123 const struct GNUNET_MessageHeader *m);
124
125
126/**
127 * We received a KEEP_ALIVE_RESPONSE message and use this to calculate
128 * latency to this peer. Pass the updated information (existing ats
129 * plus calculated latency) to ATS.
130 *
131 * @param neighbour neighbour to keep alive
132 * @param m the message containing the keep alive response
133 */
134void
135GST_neighbours_keepalive_response (const struct GNUNET_PeerIdentity *neighbour,
136 const struct GNUNET_MessageHeader *m);
137
138
139/**
140 * If we have an active connection to the given target, it must be shutdown.
141 *
142 * @param target peer to disconnect from
143 */
144void
145GST_neighbours_force_disconnect (const struct GNUNET_PeerIdentity *target);
146
147
148/**
149 * Function called for each neighbour.
150 *
151 * @param cls closure
152 * @param peer identity of the neighbour
153 * @param address the address of the neighbour
154 * @param state current state the peer is in
155 * @param state_timeout timeout for this state
156 * @param bandwidth_in inbound quota in NBO
157 * @param bandwidth_out outbound quota in NBO
158 */
159typedef void
160(*GST_NeighbourIterator) (void *cls,
161 const struct GNUNET_PeerIdentity *peer,
162 const struct GNUNET_HELLO_Address *address,
163 enum GNUNET_TRANSPORT_PeerState state,
164 struct GNUNET_TIME_Absolute state_timeout,
165 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
166 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out);
167
168
169/**
170 * Iterate over all connected neighbours.
171 *
172 * @param cb function to call
173 * @param cb_cls closure for @a cb
174 */
175void
176GST_neighbours_iterate (GST_NeighbourIterator cb, void *cb_cls);
177
178
179/**
180 * A session was terminated. Take note.
181 *
182 * @param peer identity of the peer where the session died
183 * @param session session that is gone
184 * @return #GNUNET_YES if this was a session used, #GNUNET_NO if
185 * this session was not in use
186 */
187int
188GST_neighbours_session_terminated (const struct GNUNET_PeerIdentity *peer,
189 struct GNUNET_ATS_Session *session);
190
191
192/**
193 * Track information about data we received from the
194 * given address (used to notify ATS about our utilization
195 * of allocated resources).
196 *
197 * @param address the address we got data from
198 * @param message the message we received (really only the size is used)
199 */
200void
201GST_neighbours_notify_data_recv (const struct GNUNET_HELLO_Address *address,
202 const struct GNUNET_MessageHeader *message);
203
204
205/**
206 * Track information about data we transmitted using the given @a
207 * address and @a session (used to notify ATS about our utilization of
208 * allocated resources).
209 *
210 * @param address the address we transmitted data to
211 * @param session session we used to transmit data
212 * @param message the message we sent (really only the size is used)
213 */
214void
215GST_neighbours_notify_data_sent (const struct GNUNET_HELLO_Address *address,
216 struct GNUNET_ATS_Session *session,
217 size_t size);
218
219
220/**
221 * For an existing neighbour record, set the active connection to
222 * use the given address.
223 *
224 * @param address address of the other peer to start using
225 * @param session session to use (or NULL)
226 * @param bandwidth_in inbound quota to be used when connection is up
227 * @param bandwidth_out outbound quota to be used when connection is up
228 */
229void
230GST_neighbours_switch_to_address (const struct GNUNET_HELLO_Address *address,
231 struct GNUNET_ATS_Session *session,
232 struct GNUNET_BANDWIDTH_Value32NBO
233 bandwidth_in,
234 struct GNUNET_BANDWIDTH_Value32NBO
235 bandwidth_out);
236
237
238/**
239 * We received a 'SESSION_CONNECT' message from the other peer.
240 * Consider switching to it.
241 *
242 * @param message possibly a 'struct GNUNET_ATS_SessionConnectMessage' (check format)
243 * @param peer identity of the peer to switch the address for
244 * @return #GNUNET_OK if the message was fine, #GNUNET_SYSERR on serious error
245 */
246int
247GST_neighbours_handle_session_syn (const struct GNUNET_MessageHeader *message,
248 const struct GNUNET_PeerIdentity *peer);
249
250
251/**
252 * We received a 'SESSION_CONNECT_ACK' message from the other peer.
253 * Consider switching to it.
254 *
255 * @param message possibly a `struct GNUNET_ATS_SessionConnectMessage` (check format)
256 * @param address address of the other peer
257 * @param session session to use (or NULL)
258 * @return #GNUNET_OK if the message was fine, #GNUNET_SYSERR on serious error
259 */
260int
261GST_neighbours_handle_session_syn_ack (const struct
262 GNUNET_MessageHeader *message,
263 const struct
264 GNUNET_HELLO_Address *address,
265 struct GNUNET_ATS_Session *session);
266
267
268/**
269 * We received a 'SESSION_ACK' message from the other peer.
270 * If we sent a 'CONNECT_ACK' last, this means we are now
271 * connected. Otherwise, do nothing.
272 *
273 * @param message possibly a 'struct GNUNET_ATS_SessionConnectMessage' (check format)
274 * @param address address of the other peer
275 * @param session session to use (or NULL)
276 * @return #GNUNET_OK if the message was fine, #GNUNET_SYSERR on serious error
277 */
278int
279GST_neighbours_handle_session_ack (const struct GNUNET_MessageHeader *message,
280 const struct GNUNET_HELLO_Address *address,
281 struct GNUNET_ATS_Session *session);
282
283
284/**
285 * Obtain current address information for the given neighbour.
286 *
287 * @param peer
288 * @return address currently used
289 */
290const struct GNUNET_HELLO_Address *
291GST_neighbour_get_current_address (const struct GNUNET_PeerIdentity *peer);
292
293
294/**
295 * We received a quota message from the given peer,
296 * validate and process.
297 *
298 * @param peer sender of the message
299 * @param msg the quota message
300 */
301void
302GST_neighbours_handle_quota_message (const struct GNUNET_PeerIdentity *peer,
303 const struct GNUNET_MessageHeader *msg);
304
305
306/**
307 * We received a disconnect message from the given peer,
308 * validate and process.
309 *
310 * @param peer sender of the message
311 * @param msg the disconnect message
312 */
313void
314GST_neighbours_handle_disconnect_message (const struct
315 GNUNET_PeerIdentity *peer,
316 const struct
317 GNUNET_MessageHeader *msg);
318
319
320#endif
321/* end of file gnunet-service-transport_neighbours.h */
diff --git a/src/transport/gnunet-service-transport_plugins.c b/src/transport/gnunet-service-transport_plugins.c
deleted file mode 100644
index 218ef80ab..000000000
--- a/src/transport/gnunet-service-transport_plugins.c
+++ /dev/null
@@ -1,437 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010-2014 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/gnunet-service-transport_plugins.c
23 * @brief plugin management
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet-service-transport.h"
28#include "gnunet-service-transport_hello.h"
29#include "gnunet-service-transport_ats.h"
30#include "gnunet-service-transport_plugins.h"
31
32/**
33 * Entry in doubly-linked list of all of our plugins.
34 */
35struct TransportPlugin
36{
37 /**
38 * This is a doubly-linked list.
39 */
40 struct TransportPlugin *next;
41
42 /**
43 * This is a doubly-linked list.
44 */
45 struct TransportPlugin *prev;
46
47 /**
48 * API of the transport as returned by the plugin's
49 * initialization function.
50 */
51 struct GNUNET_TRANSPORT_PluginFunctions *api;
52
53 /**
54 * Short name for the plugin (e.g. "tcp").
55 */
56 char *short_name;
57
58 /**
59 * Name of the library (e.g. "gnunet_plugin_transport_tcp").
60 */
61 char *lib_name;
62
63 /**
64 * Environment this transport service is using
65 * for this plugin.
66 */
67 struct GNUNET_TRANSPORT_PluginEnvironment env;
68};
69
70/**
71 * Head of DLL of all loaded plugins.
72 */
73static struct TransportPlugin *plugins_head;
74
75/**
76 * Head of DLL of all loaded plugins.
77 */
78static struct TransportPlugin *plugins_tail;
79
80
81/**
82 * Function that will be called to update metrics for an address
83 *
84 * @param cls closure
85 * @param address address to update metrics for
86 * @param distance new distance
87 */
88static void
89plugin_env_update_distance (void *cls,
90 const struct GNUNET_HELLO_Address *address,
91 uint32_t distance)
92{
93 GST_ats_update_distance (address,
94 distance);
95}
96
97
98/**
99 * Function that will be called to figure if an address is an loopback,
100 * LAN, WAN etc. address
101 *
102 * @param cls closure
103 * @param addr binary address
104 * @param addrlen length of the @a addr
105 * @return type of the network @a addr belongs to
106 */
107static enum GNUNET_NetworkType
108plugin_env_address_to_type (void *cls,
109 const struct sockaddr *addr,
110 size_t addrlen)
111{
112 if (NULL == GST_is)
113 {
114 GNUNET_break (0);
115 return GNUNET_NT_UNSPECIFIED;
116 }
117 return GNUNET_NT_scanner_get_type (GST_is,
118 addr,
119 addrlen);
120}
121
122
123void
124GST_plugins_load (GNUNET_TRANSPORT_PluginReceiveCallback recv_cb,
125 GNUNET_TRANSPORT_AddressNotification address_cb,
126 GNUNET_TRANSPORT_SessionStart session_start_cb,
127 GNUNET_TRANSPORT_SessionEnd session_end_cb)
128{
129 struct TransportPlugin *plug;
130 struct TransportPlugin *next;
131 unsigned long long tneigh;
132 char *libname;
133 char *plugs;
134 char *pos;
135 int fail;
136
137 if (GNUNET_OK !=
138 GNUNET_CONFIGURATION_get_value_number (GST_cfg,
139 "TRANSPORT",
140 "NEIGHBOUR_LIMIT",
141 &tneigh))
142 {
143 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
144 _ ("Transport service is lacking NEIGHBOUR_LIMIT option.\n"));
145 return;
146 }
147 if (GNUNET_OK !=
148 GNUNET_CONFIGURATION_get_value_string (GST_cfg,
149 "TRANSPORT",
150 "PLUGINS",
151 &plugs))
152 return;
153 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
154 _ ("Starting transport plugins `%s'\n"),
155 plugs);
156 for (pos = strtok (plugs, " "); pos != NULL; pos = strtok (NULL, " "))
157 {
158 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
159 _ ("Loading `%s' transport plugin\n"),
160 pos);
161 GNUNET_asprintf (&libname,
162 "libgnunet_plugin_transport_%s",
163 pos);
164 plug = GNUNET_new (struct TransportPlugin);
165 plug->short_name = GNUNET_strdup (pos);
166 plug->lib_name = libname;
167 plug->env.cfg = GST_cfg;
168 plug->env.my_identity = &GST_my_identity;
169 plug->env.get_our_hello = &GST_hello_get;
170 plug->env.cls = plug->short_name;
171 plug->env.receive = recv_cb;
172 plug->env.notify_address = address_cb;
173 plug->env.session_start = session_start_cb;
174 plug->env.session_end = session_end_cb;
175 plug->env.get_address_type = &plugin_env_address_to_type;
176 plug->env.update_address_distance = &plugin_env_update_distance;
177 plug->env.max_connections = tneigh;
178 plug->env.stats = GST_stats;
179 GNUNET_CONTAINER_DLL_insert (plugins_head,
180 plugins_tail,
181 plug);
182 }
183 GNUNET_free (plugs);
184 next = plugins_head;
185 while (NULL != next)
186 {
187 plug = next;
188 next = plug->next;
189 plug->api = GNUNET_PLUGIN_load (plug->lib_name,
190 &plug->env);
191 if (NULL == plug->api)
192 {
193 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
194 _ ("Failed to load transport plugin for `%s'\n"),
195 plug->lib_name);
196 GNUNET_CONTAINER_DLL_remove (plugins_head,
197 plugins_tail,
198 plug);
199 GNUNET_free (plug->short_name);
200 GNUNET_free (plug->lib_name);
201 GNUNET_free (plug);
202 continue;
203 }
204 fail = GNUNET_NO;
205 if (NULL == plug->api->address_pretty_printer)
206 {
207 fail = GNUNET_YES;
208 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
209 _ ("Missing function `%s' in transport plugin for `%s'\n"),
210 "address_pretty_printer",
211 plug->lib_name);
212 }
213 if (NULL == plug->api->address_to_string)
214 {
215 fail = GNUNET_YES;
216 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
217 _ ("Missing function `%s' in transport plugin for `%s'\n"),
218 "address_to_string",
219 plug->lib_name);
220 }
221 if (NULL == plug->api->string_to_address)
222 {
223 fail = GNUNET_YES;
224 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
225 _ ("Missing function `%s' in transport plugin for `%s'\n"),
226 "string_to_address",
227 plug->lib_name);
228 }
229 if (NULL == plug->api->check_address)
230 {
231 fail = GNUNET_YES;
232 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
233 _ ("Missing function `%s' in transport plugin for `%s'\n"),
234 "check_address",
235 plug->lib_name);
236 }
237 if (NULL == plug->api->get_session)
238 {
239 fail = GNUNET_YES;
240 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
241 _ ("Missing function `%s' in transport plugin for `%s'\n"),
242 "get_session",
243 plug->lib_name);
244 }
245 if (NULL == plug->api->get_network)
246 {
247 fail = GNUNET_YES;
248 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
249 _ ("Missing function `%s' in transport plugin for `%s'\n"),
250 "get_network",
251 plug->lib_name);
252 }
253 if (NULL == plug->api->send)
254 {
255 fail = GNUNET_YES;
256 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
257 _ ("Missing function `%s' in transport plugin for `%s'\n"),
258 "send",
259 plug->lib_name);
260 }
261 if (NULL == plug->api->disconnect_peer)
262 {
263 fail = GNUNET_YES;
264 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
265 _ ("Missing function `%s' in transport plugin for `%s'\n"),
266 "disconnect_peer",
267 plug->lib_name);
268 }
269 if (NULL == plug->api->disconnect_session)
270 {
271 fail = GNUNET_YES;
272 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
273 _ ("Missing function `%s' in transport plugin for `%s'\n"),
274 "disconnect_session",
275 plug->lib_name);
276 }
277 if (NULL == plug->api->query_keepalive_factor)
278 {
279 fail = GNUNET_YES;
280 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
281 _ ("Missing function `%s' in transport plugin for `%s'\n"),
282 "query_keepalive_factor",
283 plug->lib_name);
284 }
285 if (NULL == plug->api->update_session_timeout)
286 {
287 fail = GNUNET_YES;
288 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
289 _ ("Missing function `%s' in transport plugin for `%s'\n"),
290 "update_session_timeout",
291 plug->lib_name);
292 }
293 if (GNUNET_YES == fail)
294 {
295 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
296 _ ("Did not load plugin `%s' due to missing functions\n"),
297 plug->lib_name);
298 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
299 GNUNET_CONTAINER_DLL_remove (plugins_head,
300 plugins_tail,
301 plug);
302 GNUNET_free (plug->short_name);
303 GNUNET_free (plug->lib_name);
304 GNUNET_free (plug);
305 }
306 }
307}
308
309
310/**
311 * Unload all plugins
312 */
313void
314GST_plugins_unload ()
315{
316 struct TransportPlugin *plug;
317
318 while (NULL != (plug = plugins_head))
319 {
320 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
321 GNUNET_free (plug->lib_name);
322 GNUNET_free (plug->short_name);
323 GNUNET_CONTAINER_DLL_remove (plugins_head, plugins_tail, plug);
324 GNUNET_free (plug);
325 }
326}
327
328
329/**
330 * Obtain the plugin API based on a plugin name.
331 *
332 * @param name name of the plugin
333 * @return the plugin's API, NULL if the plugin is not loaded
334 */
335struct GNUNET_TRANSPORT_PluginFunctions *
336GST_plugins_find (const char *name)
337{
338 struct TransportPlugin *pos;
339
340 for (pos = plugins_head; NULL != pos; pos = pos->next)
341 if (0 == strcmp (name, pos->short_name))
342 break;
343 if (NULL == pos)
344 return NULL;
345 return pos->api;
346}
347
348
349/**
350 * Obtain the plugin API based on a the stripped plugin name after the underscore.
351 *
352 * Example: GST_plugins_printer_find (http_client) will return all plugins
353 * starting with the prefix "http":
354 * http_client or server if loaded
355 *
356 * @param name name of the plugin
357 * @return the plugin's API, NULL if the plugin is not loaded
358 */
359struct GNUNET_TRANSPORT_PluginFunctions *
360GST_plugins_printer_find (const char *name)
361{
362 struct TransportPlugin *pos;
363 char *stripped = GNUNET_strdup (name);
364 char *sep = strchr (stripped, '_');
365
366 if (NULL != sep)
367 sep[0] = '\0';
368 for (pos = plugins_head; NULL != pos; pos = pos->next)
369 if (pos->short_name == strstr (pos->short_name, stripped))
370 break;
371 GNUNET_free (stripped);
372 if (NULL == pos)
373 return NULL;
374 return pos->api;
375}
376
377
378/**
379 * Convert a given address to a human-readable format. Note that the
380 * return value will be overwritten on the next call to this function.
381 *
382 * @param address the address to convert
383 * @return statically allocated (!) human-readable address
384 */
385const char *
386GST_plugins_a2s (const struct GNUNET_HELLO_Address *address)
387{
388 struct GNUNET_TRANSPORT_PluginFunctions *api;
389 static char unable_to_show[1024];
390 static const char *s;
391
392 if (NULL == address)
393 return "<NULL>";
394 if (0 == address->address_length)
395 return TRANSPORT_SESSION_INBOUND_STRING; /* Addresse with length 0 are inbound, address->address itself may be NULL */
396 api = GST_plugins_printer_find (address->transport_name);
397 if (NULL == api)
398 {
399 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
400 "Failed to find transport plugin `%s'\n",
401 address->transport_name);
402 return "<plugin unknown>";
403 }
404 if (0 == address->address_length)
405 {
406 GNUNET_snprintf (unable_to_show,
407 sizeof(unable_to_show),
408 "<unable to stringify %u-byte long address of %s transport>",
409 (unsigned int) address->address_length,
410 address->transport_name);
411 return unable_to_show;
412 }
413 return(NULL != (s = api->address_to_string (NULL,
414 address->address,
415 address->address_length))
416 ? s
417 : "<invalid>");
418}
419
420
421void
422GST_plugins_monitor_subscribe (GNUNET_TRANSPORT_SessionInfoCallback cb,
423 void *cb_cls)
424{
425 struct TransportPlugin *pos;
426
427 for (pos = plugins_head; NULL != pos; pos = pos->next)
428 if (NULL == pos->api->setup_monitor)
429 GNUNET_break (0);
430 else
431 pos->api->setup_monitor (pos->api->cls,
432 cb,
433 cb_cls);
434}
435
436
437/* end of file gnunet-service-transport_plugins.c */
diff --git a/src/transport/gnunet-service-transport_plugins.h b/src/transport/gnunet-service-transport_plugins.h
deleted file mode 100644
index fdd819fc5..000000000
--- a/src/transport/gnunet-service-transport_plugins.h
+++ /dev/null
@@ -1,107 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010,2011 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/gnunet-service-transport_plugins.h
23 * @brief plugin management API
24 * @author Christian Grothoff
25 */
26#ifndef GNUNET_SERVICE_TRANSPORT_PLUGINS_H
27#define GNUNET_SERVICE_TRANSPORT_PLUGINS_H
28
29#include "gnunet_statistics_service.h"
30#include "gnunet_transport_service.h"
31#include "gnunet_transport_plugin.h"
32#include "gnunet_util_lib.h"
33#include "gnunet_hello_lib.h"
34
35
36/**
37 * Load and initialize all plugins. The respective functions will be
38 * invoked by the plugins when the respective events happen. The
39 * closure will be set to a 'const char*' containing the name of the
40 * plugin that caused the call.
41 *
42 * @param recv_cb function to call when data is received
43 * @param address_cb function to call when our public addresses changed
44 * @param session_start_cb function to call when a session was created
45 * @param session_end_cb function to call when a session was terminated
46 */
47void
48GST_plugins_load (GNUNET_TRANSPORT_PluginReceiveCallback recv_cb,
49 GNUNET_TRANSPORT_AddressNotification address_cb,
50 GNUNET_TRANSPORT_SessionStart session_start_cb,
51 GNUNET_TRANSPORT_SessionEnd session_end_cb);
52
53/**
54 * Unload all plugins
55 */
56void
57GST_plugins_unload (void);
58
59
60/**
61 * Obtain the plugin API based on a plugin name.
62 *
63 * @param name name of the plugin
64 * @return the plugin's API, NULL if the plugin is not loaded
65 */
66struct GNUNET_TRANSPORT_PluginFunctions *
67GST_plugins_find (const char *name);
68
69
70/**
71 * Obtain the plugin API based on a the stripped plugin name after the underscore.
72 *
73 * Example: GST_plugins_printer_find (http_client) will return all plugins
74 * starting with the prefix "http":
75 * http_client or server if loaded
76 *
77 * @param name name of the plugin
78 * @return the plugin's API, NULL if the plugin is not loaded
79 */
80struct GNUNET_TRANSPORT_PluginFunctions *
81GST_plugins_printer_find (const char *name);
82
83
84/**
85 * Convert a given address to a human-readable format. Note that the
86 * return value will be overwritten on the next call to this function.
87 *
88 * @param address address to convert
89 * @return statically allocated (!) human-readable address
90 */
91const char *
92GST_plugins_a2s (const struct GNUNET_HELLO_Address *address);
93
94
95/**
96 * Register callback with all plugins to monitor their status.
97 *
98 * @param cb callback to register, NULL to unsubscribe
99 * @param cb_cls closure for @a cb
100 */
101void
102GST_plugins_monitor_subscribe (GNUNET_TRANSPORT_SessionInfoCallback cb,
103 void *cb_cls);
104
105
106#endif
107/* end of file gnunet-service-transport_plugins.h */
diff --git a/src/transport/gnunet-service-transport_validation.c b/src/transport/gnunet-service-transport_validation.c
deleted file mode 100644
index 86161bd85..000000000
--- a/src/transport/gnunet-service-transport_validation.c
+++ /dev/null
@@ -1,1819 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010-2015 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/gnunet-service-transport_validation.c
23 * @brief address validation subsystem
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet-service-transport_ats.h"
28#include "gnunet-service-transport_hello.h"
29#include "gnunet-service-transport_neighbours.h"
30#include "gnunet-service-transport_plugins.h"
31#include "gnunet-service-transport_validation.h"
32#include "gnunet-service-transport.h"
33#include "gnunet_hello_lib.h"
34#include "gnunet_ats_service.h"
35#include "gnunet_peerinfo_service.h"
36#include "gnunet_signatures.h"
37
38/**
39 * Current state of a validation process.
40 *
41 * FIXME: what state is used to indicate that a validation
42 * was successful? If that is clarified/determined, "UGH" in
43 * ~gnunetpeerinfogtk.c:1103 should be resolved.
44 */
45enum GNUNET_TRANSPORT_ValidationState
46{
47 /**
48 * Undefined state
49 *
50 * Used for final callback indicating operation done
51 */
52 GNUNET_TRANSPORT_VS_NONE,
53
54 /**
55 * Fresh validation entry
56 *
57 * Entry was just created, no validation process was executed
58 */
59 GNUNET_TRANSPORT_VS_NEW,
60
61 /**
62 * Updated validation entry
63 *
64 * This is an update for an existing validation entry
65 */
66 GNUNET_TRANSPORT_VS_UPDATE,
67
68 /**
69 * Timeout for validation entry
70 *
71 * A timeout occurred during the validation process
72 */
73 GNUNET_TRANSPORT_VS_TIMEOUT,
74
75 /**
76 * Validation entry is removed
77 *
78 * The validation entry is getting removed due to a failed validation
79 */
80 GNUNET_TRANSPORT_VS_REMOVE
81};
82
83
84/**
85 * How long is a PONG signature valid? We'll recycle a signature until
86 * 1/4 of this time is remaining. PONGs should expire so that if our
87 * external addresses change an adversary cannot replay them indefinitely.
88 * OTOH, we don't want to spend too much time generating PONG signatures,
89 * so they must have some lifetime to reduce our CPU usage.
90 */
91#define PONG_SIGNATURE_LIFETIME GNUNET_TIME_relative_multiply ( \
92 GNUNET_TIME_UNIT_HOURS, 1)
93
94/**
95 * After how long do we expire an address in a HELLO that we just
96 * validated? This value is also used for our own addresses when we
97 * create a HELLO.
98 */
99#define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply ( \
100 GNUNET_TIME_UNIT_HOURS, 12)
101
102/**
103 * How often do we allow PINGing an address that we have not yet
104 * validated? This also determines how long we track an address that
105 * we cannot validate (because after this time we can destroy the
106 * validation record).
107 */
108#define UNVALIDATED_PING_KEEPALIVE GNUNET_TIME_relative_multiply ( \
109 GNUNET_TIME_UNIT_MINUTES, 5)
110
111/**
112 * How often do we PING an address that we have successfully validated
113 * in the past but are not actively using? Should be (significantly)
114 * smaller than HELLO_ADDRESS_EXPIRATION.
115 */
116#define VALIDATED_PING_FREQUENCY GNUNET_TIME_relative_multiply ( \
117 GNUNET_TIME_UNIT_MINUTES, 15)
118
119/**
120 * How often do we PING an address that we are currently using?
121 */
122#define CONNECTED_PING_FREQUENCY GNUNET_TIME_relative_multiply ( \
123 GNUNET_TIME_UNIT_MINUTES, 2)
124
125/**
126 * How much delay is acceptable for sending the PING or PONG?
127 */
128#define ACCEPTABLE_PING_DELAY GNUNET_TIME_relative_multiply ( \
129 GNUNET_TIME_UNIT_SECONDS, 1)
130
131/**
132 * Size of the validation map hashmap.
133 */
134#define VALIDATION_MAP_SIZE 256
135
136/**
137 * Priority to use for PINGs
138 */
139#define PING_PRIORITY 2
140
141/**
142 * Priority to use for PONGs
143 */
144#define PONG_PRIORITY 4
145
146
147GNUNET_NETWORK_STRUCT_BEGIN
148
149/**
150 * Message used to ask a peer to validate receipt (to check an address
151 * from a HELLO). Followed by the address we are trying to validate,
152 * or an empty address if we are just sending a PING to confirm that a
153 * connection which the receiver (of the PING) initiated is still valid.
154 */
155struct TransportPingMessage
156{
157 /**
158 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_PING
159 */
160 struct GNUNET_MessageHeader header;
161
162 /**
163 * Challenge code (to ensure fresh reply).
164 */
165 uint32_t challenge GNUNET_PACKED;
166
167 /**
168 * Who is the intended recipient?
169 */
170 struct GNUNET_PeerIdentity target;
171};
172
173
174/**
175 * Message used to validate a HELLO. The challenge is included in the
176 * confirmation to make matching of replies to requests possible. The
177 * signature signs our public key, an expiration time and our address.<p>
178 *
179 * This message is followed by our transport address that the PING tried
180 * to confirm (if we liked it). The address can be empty (zero bytes)
181 * if the PING had not address either (and we received the request via
182 * a connection that we initiated).
183 */
184struct TransportPongMessage
185{
186 /**
187 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
188 */
189 struct GNUNET_MessageHeader header;
190
191 /**
192 * Challenge code from PING (showing freshness). Not part of what
193 * is signed so that we can re-use signatures.
194 */
195 uint32_t challenge GNUNET_PACKED;
196
197 /**
198 * Signature.
199 */
200 struct GNUNET_CRYPTO_EddsaSignature signature;
201
202 /**
203 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN to confirm that this is a
204 * plausible address for the signing peer.
205 */
206 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
207
208 /**
209 * When does this signature expire?
210 */
211 struct GNUNET_TIME_AbsoluteNBO expiration;
212
213 /**
214 * Size of address appended to this message (part of what is
215 * being signed, hence not redundant).
216 */
217 uint32_t addrlen GNUNET_PACKED;
218};
219GNUNET_NETWORK_STRUCT_END
220
221/**
222 * Information about an address under validation
223 */
224struct ValidationEntry
225{
226 /**
227 * The address.
228 */
229 struct GNUNET_HELLO_Address *address;
230
231 /**
232 * Handle to the blacklist check (if we're currently in it).
233 */
234 struct GST_BlacklistCheck *bc;
235
236 /**
237 * Cached PONG signature
238 */
239 struct GNUNET_CRYPTO_EddsaSignature pong_sig_cache;
240
241 /**
242 * ID of task that will clean up this entry if nothing happens.
243 */
244 struct GNUNET_SCHEDULER_Task *timeout_task;
245
246 /**
247 * ID of task that will trigger address revalidation.
248 */
249 struct GNUNET_SCHEDULER_Task *revalidation_task;
250
251 /**
252 * At what time did we send the latest validation request (PING)?
253 */
254 struct GNUNET_TIME_Absolute send_time;
255
256 /**
257 * At what time do we send the next validation request (PING)?
258 */
259 struct GNUNET_TIME_Absolute next_validation;
260
261 /**
262 * Until when is this address valid?
263 * ZERO if it is not currently considered valid.
264 */
265 struct GNUNET_TIME_Absolute valid_until;
266
267 /**
268 * Until when is the cached PONG signature valid?
269 * ZERO if it is not currently considered valid.
270 */
271 struct GNUNET_TIME_Absolute pong_sig_valid_until;
272
273 /**
274 * How long until we can try to validate this address again?
275 * FOREVER if the address is for an unsupported plugin (from PEERINFO)
276 * ZERO if the address is considered valid (no validation needed)
277 * otherwise a time in the future if we're currently denying re-validation
278 */
279 struct GNUNET_TIME_Absolute revalidation_block;
280
281 /**
282 * Last observed latency for this address (round-trip), delay between
283 * last PING sent and PONG received; FOREVER if we never got a PONG.
284 */
285 struct GNUNET_TIME_Relative latency;
286
287 /**
288 * Current state of this validation entry
289 */
290 enum GNUNET_TRANSPORT_ValidationState state;
291
292 /**
293 * Challenge number we used.
294 */
295 uint32_t challenge;
296
297 /**
298 * When passing the address in #add_valid_peer_address(), did we
299 * copy the address to the HELLO yet?
300 */
301 int copied;
302
303 /**
304 * Are we currently using this address for a connection?
305 */
306 int in_use;
307
308 /**
309 * Are we expecting a PONG message for this validation entry?
310 */
311 int expecting_pong;
312
313 /**
314 * Is this address known to ATS as valid right now?
315 */
316 int known_to_ats;
317
318 /**
319 * Which network type does our address belong to?
320 */
321 enum GNUNET_NetworkType network;
322};
323
324
325/**
326 * Map of PeerIdentities to 'struct ValidationEntry*'s (addresses
327 * of the given peer that we are currently validating, have validated
328 * or are blocked from re-validation for a while).
329 */
330static struct GNUNET_CONTAINER_MultiPeerMap *validation_map;
331
332/**
333 * Context for peerinfo iteration.
334 */
335static struct GNUNET_PEERINFO_NotifyContext *pnc;
336
337/**
338 * Minimum delay between to validations
339 */
340static struct GNUNET_TIME_Relative validation_delay;
341
342/**
343 * Number of validations running; any PING that was not yet
344 * matched by a PONG and for which we have not yet hit the
345 * timeout is considered a running 'validation'.
346 */
347static unsigned int validations_running;
348
349/**
350 * Validition fast start threshold
351 */
352static unsigned int validations_fast_start_threshold;
353
354/**
355 * When is next validation allowed
356 */
357static struct GNUNET_TIME_Absolute validation_next;
358
359
360/**
361 * Context for the validation entry match function.
362 */
363struct ValidationEntryMatchContext
364{
365 /**
366 * Where to store the result?
367 */
368 struct ValidationEntry *ve;
369
370 /**
371 * Address we're interested in.
372 */
373 const struct GNUNET_HELLO_Address *address;
374};
375
376
377/**
378 * Provide an update on the `validation_map` map size to statistics.
379 * This function should be called whenever the `validation_map`
380 * is changed.
381 */
382static void
383publish_ve_stat_update ()
384{
385 GNUNET_STATISTICS_set (GST_stats,
386 gettext_noop ("# Addresses in validation map"),
387 GNUNET_CONTAINER_multipeermap_size (validation_map),
388 GNUNET_NO);
389}
390
391
392/**
393 * Iterate over validation entries until a matching one is found.
394 *
395 * @param cls the `struct ValidationEntryMatchContext *`
396 * @param key peer identity (unused)
397 * @param value a `struct ValidationEntry *` to match
398 * @return #GNUNET_YES if the entry does not match,
399 * #GNUNET_NO if the entry does match
400 */
401static int
402validation_entry_match (void *cls,
403 const struct GNUNET_PeerIdentity *key,
404 void *value)
405{
406 struct ValidationEntryMatchContext *vemc = cls;
407 struct ValidationEntry *ve = value;
408
409 if (0 == GNUNET_HELLO_address_cmp (ve->address,
410 vemc->address))
411 {
412 vemc->ve = ve;
413 return GNUNET_NO;
414 }
415 return GNUNET_YES;
416}
417
418
419/**
420 * A validation entry changed. Update the state and notify
421 * monitors.
422 *
423 * @param ve validation entry that changed
424 * @param state new state
425 */
426static void
427validation_entry_changed (struct ValidationEntry *ve,
428 enum GNUNET_TRANSPORT_ValidationState state)
429{
430 ve->state = state;
431}
432
433
434/**
435 * Iterate over validation entries and free them.
436 *
437 * @param cls (unused)
438 * @param key peer identity (unused)
439 * @param value a `struct ValidationEntry *` to clean up
440 * @return #GNUNET_YES (continue to iterate)
441 */
442static int
443cleanup_validation_entry (void *cls,
444 const struct GNUNET_PeerIdentity *key,
445 void *value)
446{
447 struct ValidationEntry *ve = value;
448
449 ve->next_validation = GNUNET_TIME_UNIT_ZERO_ABS;
450 ve->valid_until = GNUNET_TIME_UNIT_ZERO_ABS;
451
452 /* Notify about deleted entry */
453 validation_entry_changed (ve,
454 GNUNET_TRANSPORT_VS_REMOVE);
455
456 if (NULL != ve->bc)
457 {
458 GST_blacklist_test_cancel (ve->bc);
459 ve->bc = NULL;
460 }
461 GNUNET_break (GNUNET_OK ==
462 GNUNET_CONTAINER_multipeermap_remove (validation_map,
463 &ve->address->peer,
464 ve));
465 publish_ve_stat_update ();
466 if (GNUNET_YES == ve->known_to_ats)
467 {
468 GST_ats_expire_address (ve->address);
469 GNUNET_assert (GNUNET_NO ==
470 GST_ats_is_known_no_session (ve->address));
471 ve->known_to_ats = GNUNET_NO;
472 }
473 GNUNET_HELLO_address_free (ve->address);
474 if (NULL != ve->timeout_task)
475 {
476 GNUNET_SCHEDULER_cancel (ve->timeout_task);
477 ve->timeout_task = NULL;
478 }
479 if (NULL != ve->revalidation_task)
480 {
481 GNUNET_SCHEDULER_cancel (ve->revalidation_task);
482 ve->revalidation_task = NULL;
483 }
484 if ((GNUNET_YES == ve->expecting_pong) &&
485 (validations_running > 0))
486 {
487 validations_running--;
488 GNUNET_STATISTICS_set (GST_stats,
489 gettext_noop ("# validations running"),
490 validations_running,
491 GNUNET_NO);
492 }
493 GNUNET_free (ve);
494 return GNUNET_OK;
495}
496
497
498/**
499 * Address validation cleanup task. Assesses if the record is no
500 * longer valid and then possibly triggers its removal.
501 *
502 * @param cls the `struct ValidationEntry`
503 */
504static void
505timeout_hello_validation (void *cls)
506{
507 struct ValidationEntry *ve = cls;
508 struct GNUNET_TIME_Absolute max;
509 struct GNUNET_TIME_Relative left;
510
511 ve->timeout_task = NULL;
512 /* For valid addresses, we want to wait until the expire;
513 for addresses under PING validation, we want to wait
514 until we give up on the PING */
515 max = GNUNET_TIME_absolute_max (ve->valid_until,
516 ve->revalidation_block);
517 left = GNUNET_TIME_absolute_get_remaining (max);
518 if (left.rel_value_us > 0)
519 {
520 /* We should wait a bit longer. This happens when
521 address lifetimes are extended due to successful
522 validations. */
523 ve->timeout_task =
524 GNUNET_SCHEDULER_add_delayed (left,
525 &timeout_hello_validation,
526 ve);
527 return;
528 }
529 GNUNET_STATISTICS_update (GST_stats,
530 gettext_noop (
531 "# address records discarded (timeout)"),
532 1,
533 GNUNET_NO);
534 cleanup_validation_entry (NULL,
535 &ve->address->peer,
536 ve);
537}
538
539
540/**
541 * Function called with the result from blacklisting.
542 * Send a PING to the other peer if a communication is allowed.
543 *
544 * @param cls our `struct ValidationEntry`
545 * @param pid identity of the other peer
546 * @param address_null address associated with the request, always NULL
547 * @param session_null session associated with the request, always NULL
548 * @param result #GNUNET_OK if the connection is allowed,
549 * #GNUNET_NO if not,
550 * #GNUNET_SYSERR if operation was aborted
551 */
552static void
553transmit_ping_if_allowed (void *cls,
554 const struct GNUNET_PeerIdentity *pid,
555 const struct GNUNET_HELLO_Address *address_null,
556 struct GNUNET_ATS_Session *session_null,
557 int result)
558{
559 struct ValidationEntry *ve = cls;
560 struct TransportPingMessage ping;
561 struct GNUNET_TRANSPORT_PluginFunctions *papi;
562 struct GNUNET_TIME_Absolute next;
563 const struct GNUNET_MessageHeader *hello;
564 ssize_t ret;
565 size_t tsize;
566 size_t slen;
567 uint16_t hsize;
568 struct GNUNET_ATS_Session *session;
569
570 ve->bc = NULL;
571 if (GNUNET_OK != result)
572 {
573 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
574 "Blacklist denies sending PING to `%s' `%s' `%s'\n",
575 GNUNET_i2s (pid),
576 GST_plugins_a2s (ve->address),
577 ve->address->transport_name);
578 GNUNET_STATISTICS_update (GST_stats,
579 gettext_noop (
580 "# address records discarded (blacklist)"),
581 1,
582 GNUNET_NO);
583 cleanup_validation_entry (NULL,
584 pid,
585 ve);
586 return;
587 }
588 hello = GST_hello_get ();
589 GNUNET_assert (NULL != hello);
590 slen = strlen (ve->address->transport_name) + 1;
591 hsize = ntohs (hello->size);
592 tsize = sizeof(struct TransportPingMessage)
593 + ve->address->address_length + slen + hsize;
594
595 ping.header.size =
596 htons (sizeof(struct TransportPingMessage)
597 + ve->address->address_length + slen);
598 ping.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
599 ping.challenge = htonl (ve->challenge);
600 ping.target = *pid;
601
602 if (tsize >= GNUNET_MAX_MESSAGE_SIZE)
603 {
604 GNUNET_break (0);
605 hsize = 0;
606 tsize =
607 sizeof(struct TransportPingMessage) + ve->address->address_length
608 + slen + hsize;
609 }
610 {
611 char message_buf[tsize] GNUNET_ALIGN;
612
613 GNUNET_memcpy (message_buf,
614 hello,
615 hsize);
616 GNUNET_memcpy (&message_buf[hsize],
617 &ping,
618 sizeof(struct TransportPingMessage));
619 GNUNET_memcpy (&message_buf[sizeof(struct TransportPingMessage) + hsize],
620 ve->address->transport_name,
621 slen);
622 GNUNET_memcpy (&message_buf[sizeof(struct TransportPingMessage) + slen
623 + hsize],
624 ve->address->address,
625 ve->address->address_length);
626 papi = GST_plugins_find (ve->address->transport_name);
627 GNUNET_assert (NULL != papi);
628 session = papi->get_session (papi->cls,
629 ve->address);
630 if (NULL == session)
631 {
632 /* Could not get a valid session */
633 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
634 "Failed to get session to send PING to `%s' at `%s'\n",
635 GNUNET_i2s (pid),
636 GST_plugins_a2s (ve->address));
637 return;
638 }
639
640 ret = papi->send (papi->cls, session,
641 message_buf, tsize,
642 PING_PRIORITY,
643 ACCEPTABLE_PING_DELAY,
644 NULL, NULL);
645 if (-1 == ret)
646 {
647 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
648 "Failed to send PING to `%s' at `%s'\n",
649 GNUNET_i2s (pid),
650 GST_plugins_a2s (ve->address));
651 return;
652 }
653 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
654 "Transmitted plain PING to `%s' `%s' `%s'\n",
655 GNUNET_i2s (pid),
656 GST_plugins_a2s (ve->address),
657 ve->address->transport_name);
658 ve->network = papi->get_network (papi->cls,
659 session);
660 GNUNET_break (GNUNET_NT_UNSPECIFIED != ve->network);
661 GST_neighbours_notify_data_sent (ve->address,
662 session,
663 tsize);
664 next = GNUNET_TIME_relative_to_absolute (validation_delay);
665 validation_next = GNUNET_TIME_absolute_max (next,
666 validation_next);
667 ve->send_time = GNUNET_TIME_absolute_get ();
668 GNUNET_STATISTICS_update (GST_stats,
669 gettext_noop (
670 "# PINGs for address validation sent"),
671 1,
672 GNUNET_NO);
673 ve->expecting_pong = GNUNET_YES;
674 validations_running++;
675 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
676 "Validation started, %u validation processes running\n",
677 validations_running);
678 GNUNET_STATISTICS_set (GST_stats,
679 gettext_noop ("# validations running"),
680 validations_running,
681 GNUNET_NO);
682 /* Notify about PING sent */
683 validation_entry_changed (ve,
684 GNUNET_TRANSPORT_VS_UPDATE);
685 }
686}
687
688
689/**
690 * Do address validation again to keep address valid.
691 *
692 * @param cls the `struct ValidationEntry`
693 */
694static void
695revalidate_address (void *cls)
696{
697 struct ValidationEntry *ve = cls;
698 struct GNUNET_TIME_Relative canonical_delay;
699 struct GNUNET_TIME_Relative delay;
700 struct GNUNET_TIME_Relative blocked_for;
701 struct GST_BlacklistCheck *bc;
702 uint32_t rdelay;
703
704 ve->revalidation_task = NULL;
705 delay = GNUNET_TIME_absolute_get_remaining (ve->revalidation_block);
706 /* Considering current connectivity situation, what is the maximum
707 block period permitted? */
708 if (GNUNET_YES == ve->in_use)
709 canonical_delay = CONNECTED_PING_FREQUENCY;
710 else if (GNUNET_TIME_absolute_get_remaining (ve->valid_until).rel_value_us >
711 0)
712 canonical_delay = VALIDATED_PING_FREQUENCY;
713 else
714 canonical_delay = UNVALIDATED_PING_KEEPALIVE;
715 /* Use delay that is MIN of original delay and possibly adjusted
716 new maximum delay (which may be lower); the real delay
717 is originally randomized between "canonical_delay" and "2 * canonical_delay",
718 so continue to permit that window for the operation. */
719 delay = GNUNET_TIME_relative_min (delay,
720 GNUNET_TIME_relative_multiply (
721 canonical_delay,
722 2));
723 ve->revalidation_block = GNUNET_TIME_relative_to_absolute (delay);
724 if (delay.rel_value_us > 0)
725 {
726 /* should wait a bit longer */
727 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
728 "Waiting for %s longer before (re)validating address `%s'\n",
729 GNUNET_STRINGS_relative_time_to_string (delay,
730 GNUNET_YES),
731 GST_plugins_a2s (ve->address));
732 ve->revalidation_task =
733 GNUNET_SCHEDULER_add_delayed (delay,
734 &revalidate_address, ve);
735 ve->next_validation = GNUNET_TIME_relative_to_absolute (delay);
736 return;
737 }
738 /* check if globally we have too many active validations at a
739 too high rate, if so, delay ours */
740 blocked_for = GNUNET_TIME_absolute_get_remaining (validation_next);
741 if ((validations_running > validations_fast_start_threshold) &&
742 (blocked_for.rel_value_us > 0))
743 {
744 /* Validations are blocked, have to wait for blocked_for time */
745 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
746 "Validations blocked for another %s, delaying validating address `%s'\n",
747 GNUNET_STRINGS_relative_time_to_string (blocked_for,
748 GNUNET_YES),
749 GST_plugins_a2s (ve->address));
750 GNUNET_STATISTICS_update (GST_stats,
751 gettext_noop (
752 "# validations delayed by global throttle"),
753 1,
754 GNUNET_NO);
755 ve->revalidation_task =
756 GNUNET_SCHEDULER_add_delayed (blocked_for,
757 &revalidate_address,
758 ve);
759 ve->next_validation = GNUNET_TIME_relative_to_absolute (blocked_for);
760 return;
761 }
762
763 /* We are good to go; remember to not go again for `canonical_delay` time;
764 add up to `canonical_delay` to randomize start time */
765 ve->revalidation_block = GNUNET_TIME_relative_to_absolute (canonical_delay);
766 /* schedule next PINGing with some extra random delay to avoid synchronous re-validations */
767 rdelay =
768 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
769 canonical_delay.rel_value_us);
770
771 delay = GNUNET_TIME_relative_add (canonical_delay,
772 GNUNET_TIME_relative_multiply
773 (GNUNET_TIME_UNIT_MICROSECONDS,
774 rdelay));
775
776 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
777 "Validating now, next scheduled for %s, now validating address `%s'\n",
778 GNUNET_STRINGS_relative_time_to_string (blocked_for,
779 GNUNET_YES),
780 GST_plugins_a2s (ve->address));
781 ve->revalidation_task =
782 GNUNET_SCHEDULER_add_delayed (delay,
783 &revalidate_address,
784 ve);
785 ve->next_validation = GNUNET_TIME_relative_to_absolute (delay);
786
787 /* start PINGing by checking blacklist */
788 GNUNET_STATISTICS_update (GST_stats,
789 gettext_noop ("# address revalidations started"), 1,
790 GNUNET_NO);
791 if (NULL != ve->bc)
792 {
793 GST_blacklist_test_cancel (ve->bc);
794 ve->bc = NULL;
795 }
796 bc = GST_blacklist_test_allowed (&ve->address->peer,
797 ve->address->transport_name,
798 &transmit_ping_if_allowed,
799 ve,
800 NULL,
801 NULL);
802 if (NULL != bc)
803 {
804 /* If transmit_ping_if_allowed was already called it may have freed ve,
805 * so only set ve->bc if it has not been called.
806 */
807 ve->bc = bc;
808 }
809}
810
811
812/**
813 * Find a ValidationEntry entry for the given neighbour that matches
814 * the given address and transport. If none exists, create one (but
815 * without starting any validation).
816 *
817 * @param address address to find
818 * @return validation entry matching the given specifications, NULL
819 * if we don't have an existing entry and no public key was given
820 */
821static struct ValidationEntry *
822find_validation_entry (const struct GNUNET_HELLO_Address *address)
823{
824 struct ValidationEntryMatchContext vemc;
825 struct ValidationEntry *ve;
826
827 vemc.ve = NULL;
828 vemc.address = address;
829 GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
830 &address->peer,
831 &validation_entry_match, &vemc);
832 if (NULL != (ve = vemc.ve))
833 return ve;
834 GNUNET_assert (GNUNET_NO ==
835 GST_ats_is_known_no_session (address));
836 ve = GNUNET_new (struct ValidationEntry);
837 ve->in_use = GNUNET_SYSERR; /* not defined */
838 ve->address = GNUNET_HELLO_address_copy (address);
839 ve->pong_sig_valid_until = GNUNET_TIME_UNIT_ZERO_ABS;
840 memset (&ve->pong_sig_cache,
841 '\0',
842 sizeof(struct GNUNET_CRYPTO_EddsaSignature));
843 ve->latency = GNUNET_TIME_UNIT_FOREVER_REL;
844 ve->challenge =
845 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX);
846 ve->timeout_task =
847 GNUNET_SCHEDULER_add_delayed (UNVALIDATED_PING_KEEPALIVE,
848 &timeout_hello_validation,
849 ve);
850 GNUNET_CONTAINER_multipeermap_put (validation_map,
851 &address->peer,
852 ve,
853 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
854 publish_ve_stat_update ();
855 validation_entry_changed (ve,
856 GNUNET_TRANSPORT_VS_NEW);
857 return ve;
858}
859
860
861/**
862 * Iterator which adds the given address to the set of validated
863 * addresses.
864 *
865 * @param cls original HELLO message
866 * @param address the address
867 * @param expiration expiration time
868 * @return #GNUNET_OK (keep the address), could return
869 * #GNUNET_NO (delete address, but this is ignored);
870 * #GNUNET_SYSERR would abort iteration (but we always iterate all)
871 */
872static int
873add_valid_address (void *cls,
874 const struct GNUNET_HELLO_Address *address,
875 struct GNUNET_TIME_Absolute expiration)
876{
877 const struct GNUNET_HELLO_Message *hello = cls;
878 struct ValidationEntry *ve;
879 struct GNUNET_PeerIdentity pid;
880 struct GNUNET_ATS_Properties prop;
881 struct GNUNET_TRANSPORT_PluginFunctions *papi;
882
883 if (0 == GNUNET_TIME_absolute_get_remaining (expiration).rel_value_us)
884 return GNUNET_OK; /* expired */
885 if (GNUNET_OK != GNUNET_HELLO_get_id (hello, &pid))
886 {
887 GNUNET_break (0);
888 return GNUNET_OK; /* invalid HELLO !? */
889 }
890 if (NULL == (papi = GST_plugins_find (address->transport_name)))
891 {
892 /* might have been valid in the past, but we don't have that
893 plugin loaded right now */
894 return GNUNET_OK;
895 }
896 if (NULL ==
897 papi->address_to_string (papi->cls,
898 address->address,
899 address->address_length))
900 {
901 /* Why do we try to add an ill-formed address? */
902 GNUNET_break (0);
903 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
904 "Address with %u bytes for plugin %s and peer %s is malformed\n",
905 (unsigned int) address->address_length,
906 address->transport_name,
907 GNUNET_i2s (&pid));
908 return GNUNET_OK;
909 }
910
911 ve = find_validation_entry (address);
912 ve->network = papi->get_network_for_address (papi->cls,
913 address);
914 GNUNET_break (GNUNET_NT_UNSPECIFIED != ve->network);
915 ve->valid_until = GNUNET_TIME_absolute_max (ve->valid_until,
916 expiration);
917 if (NULL == ve->revalidation_task)
918 {
919 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
920 "Starting revalidations for valid address `%s'\n",
921 GST_plugins_a2s (ve->address));
922 ve->next_validation = GNUNET_TIME_absolute_get ();
923 ve->revalidation_task = GNUNET_SCHEDULER_add_now (&revalidate_address, ve);
924 }
925 validation_entry_changed (ve,
926 GNUNET_TRANSPORT_VS_UPDATE);
927 memset (&prop, 0, sizeof(prop));
928 prop.scope = ve->network;
929 prop.delay = GNUNET_TIME_relative_divide (ve->latency, 2);
930 if (GNUNET_YES != ve->known_to_ats)
931 {
932 ve->known_to_ats = GNUNET_YES;
933 GST_ats_add_address (address, &prop);
934 GNUNET_assert (GNUNET_YES ==
935 GST_ats_is_known_no_session (ve->address));
936 }
937 return GNUNET_OK;
938}
939
940
941/**
942 * Function called for any HELLO known to PEERINFO.
943 *
944 * @param cls unused (NULL)
945 * @param peer id of the peer, NULL for last call (during iteration,
946 * as we are monitoring, this should never happen)
947 * @param hello hello message for the peer (can be NULL)
948 * @param err_msg error message
949 */
950static void
951process_peerinfo_hello (void *cls,
952 const struct GNUNET_PeerIdentity *peer,
953 const struct GNUNET_HELLO_Message *hello,
954 const char *err_msg)
955{
956 GNUNET_assert (NULL != peer);
957 if (NULL == hello)
958 return;
959 if (0 == memcmp (&GST_my_identity,
960 peer,
961 sizeof(struct GNUNET_PeerIdentity)))
962 {
963 /* Peerinfo returned own identity, skip validation */
964 return;
965 }
966 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
967 "Handling HELLO for peer `%s'\n",
968 GNUNET_i2s (peer));
969 GNUNET_assert (NULL ==
970 GNUNET_HELLO_iterate_addresses (hello, GNUNET_NO,
971 &add_valid_address,
972 (void *) hello));
973}
974
975
976/**
977 * Start the validation subsystem.
978 *
979 * @param max_fds maximum number of fds to use
980 */
981void
982GST_validation_start (unsigned int max_fds)
983{
984 /**
985 * Initialization for validation throttling
986 *
987 * We have a maximum number max_fds of connections we can use for validation
988 * We monitor the number of validations in parallel and start to throttle it
989 * when doing to many validations in parallel:
990 * if (running validations < (max_fds / 2))
991 * - "fast start": run validation immediately
992 * - have delay of (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value_us) / (max_fds / 2)
993 * (300 sec / ~150 == ~2 sec.) between two validations
994 */validation_next = GNUNET_TIME_absolute_get ();
995 validation_delay.rel_value_us =
996 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value_us) / (max_fds / 2);
997 validations_fast_start_threshold = (max_fds / 2);
998 validations_running = 0;
999 GNUNET_STATISTICS_set (GST_stats,
1000 gettext_noop ("# validations running"),
1001 validations_running,
1002 GNUNET_NO);
1003 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1004 "Validation uses a fast start threshold of %u connections and a delay of %s\n",
1005 validations_fast_start_threshold,
1006 GNUNET_STRINGS_relative_time_to_string (validation_delay,
1007 GNUNET_YES));
1008 validation_map = GNUNET_CONTAINER_multipeermap_create (VALIDATION_MAP_SIZE,
1009 GNUNET_NO);
1010 pnc = GNUNET_PEERINFO_notify (GST_cfg, GNUNET_YES,
1011 &process_peerinfo_hello, NULL);
1012}
1013
1014
1015/**
1016 * Stop the validation subsystem.
1017 */
1018void
1019GST_validation_stop ()
1020{
1021 GNUNET_CONTAINER_multipeermap_iterate (validation_map,
1022 &cleanup_validation_entry,
1023 NULL);
1024 GNUNET_CONTAINER_multipeermap_destroy (validation_map);
1025 validation_map = NULL;
1026 GNUNET_PEERINFO_notify_cancel (pnc);
1027}
1028
1029
1030/**
1031 * Send the given PONG to the given address.
1032 *
1033 * @param cls the PONG message
1034 * @param valid_until is ZERO if we never validated the address,
1035 * otherwise a time up to when we consider it (or was) valid
1036 * @param validation_block is FOREVER if the address is for an unsupported plugin (from PEERINFO)
1037 * is ZERO if the address is considered valid (no validation needed)
1038 * otherwise a time in the future if we're currently denying re-validation
1039 * @param address target address
1040 */
1041static void
1042multicast_pong (void *cls,
1043 struct GNUNET_TIME_Absolute valid_until,
1044 struct GNUNET_TIME_Absolute validation_block,
1045 const struct GNUNET_HELLO_Address *address)
1046{
1047 struct TransportPongMessage *pong = cls;
1048 struct GNUNET_TRANSPORT_PluginFunctions *papi;
1049 struct GNUNET_ATS_Session *session;
1050
1051 papi = GST_plugins_find (address->transport_name);
1052 if (NULL == papi)
1053 {
1054 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1055 "Plugin %s not supported, cannot send PONG\n",
1056 address->transport_name);
1057 return;
1058 }
1059 GNUNET_assert (NULL != papi->send);
1060 GNUNET_assert (NULL != papi->get_session);
1061 session = papi->get_session (papi->cls, address);
1062 if (NULL == session)
1063 {
1064 GNUNET_break (0);
1065 return;
1066 }
1067 GST_ats_new_session (address, session);
1068 papi->send (papi->cls, session,
1069 (const char *) pong,
1070 ntohs (pong->header.size),
1071 PONG_PRIORITY,
1072 ACCEPTABLE_PING_DELAY,
1073 NULL, NULL);
1074 GST_neighbours_notify_data_sent (address,
1075 session,
1076 pong->header.size);
1077}
1078
1079
1080/**
1081 * We've received a PING. If appropriate, generate a PONG.
1082 *
1083 * @param sender peer sending the PING
1084 * @param hdr the PING
1085 * @param sender_address the sender address as we got it
1086 * @param session session we got the PING from
1087 * @return #GNUNET_OK if the message was fine, #GNUNET_SYSERR on serious error
1088 */
1089int
1090GST_validation_handle_ping (const struct GNUNET_PeerIdentity *sender,
1091 const struct GNUNET_MessageHeader *hdr,
1092 const struct GNUNET_HELLO_Address *sender_address,
1093 struct GNUNET_ATS_Session *session)
1094{
1095 const struct TransportPingMessage *ping;
1096 struct TransportPongMessage *pong;
1097 struct GNUNET_TRANSPORT_PluginFunctions *papi;
1098 struct GNUNET_CRYPTO_EddsaSignature *sig_cache;
1099 struct GNUNET_TIME_Absolute *sig_cache_exp;
1100 const char *addr;
1101 const char *addrend;
1102 char *plugin_name;
1103 char *pos;
1104 size_t len_address;
1105 size_t len_plugin;
1106 ssize_t ret;
1107 struct GNUNET_HELLO_Address address;
1108
1109 if (0 ==
1110 memcmp (&GST_my_identity,
1111 sender,
1112 sizeof(struct GNUNET_PeerIdentity)))
1113 return GNUNET_OK; /* our own, ignore! */
1114 if (ntohs (hdr->size) < sizeof(struct TransportPingMessage))
1115 {
1116 GNUNET_break_op (0);
1117 return GNUNET_SYSERR;
1118 }
1119 ping = (const struct TransportPingMessage *) hdr;
1120 if (0 !=
1121 memcmp (&ping->target,
1122 &GST_my_identity,
1123 sizeof(struct GNUNET_PeerIdentity)))
1124 {
1125 GNUNET_STATISTICS_update (GST_stats,
1126 gettext_noop
1127 ("# PING message for different peer received"),
1128 1,
1129 GNUNET_NO);
1130 return GNUNET_SYSERR;
1131 }
1132 GNUNET_STATISTICS_update (GST_stats,
1133 gettext_noop ("# PING messages received"), 1,
1134 GNUNET_NO);
1135 addr = (const char *) &ping[1];
1136 len_address = ntohs (hdr->size) - sizeof(struct TransportPingMessage);
1137 /* peer wants to confirm that this is one of our addresses, this is what is
1138 * used for address validation */
1139
1140 sig_cache = NULL;
1141 sig_cache_exp = NULL;
1142 papi = NULL;
1143 if (len_address > 0)
1144 {
1145 addrend = memchr (addr, '\0', len_address);
1146 if (NULL == addrend)
1147 {
1148 GNUNET_break_op (0);
1149 return GNUNET_SYSERR;
1150 }
1151 addrend++;
1152 len_plugin = strlen (addr) + 1;
1153 len_address -= len_plugin;
1154 address.local_info = GNUNET_HELLO_ADDRESS_INFO_NONE;
1155 address.address = addrend;
1156 address.address_length = len_address;
1157 address.transport_name = addr;
1158 address.peer = GST_my_identity;
1159
1160 if (NULL == address.transport_name)
1161 {
1162 GNUNET_break (0);
1163 }
1164
1165 if (0 != strstr (address.transport_name, "_client"))
1166 {
1167 plugin_name = GNUNET_strdup (address.transport_name);
1168 pos = strstr (plugin_name, "_client");
1169 GNUNET_assert (NULL != pos);
1170 GNUNET_snprintf (pos, strlen ("_server") + 1, "%s", "_server");
1171 }
1172 else
1173 plugin_name = GNUNET_strdup (address.transport_name);
1174
1175 if (NULL == (papi = GST_plugins_find (plugin_name)))
1176 {
1177 /* we don't have the plugin for this address */
1178 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1179 _ (
1180 "Plugin `%s' not available, cannot confirm having this address\n"),
1181 plugin_name);
1182 GNUNET_free (plugin_name);
1183 return GNUNET_SYSERR;
1184 }
1185 GNUNET_free (plugin_name);
1186 if (GNUNET_OK !=
1187 papi->check_address (papi->cls,
1188 addrend,
1189 len_address))
1190 {
1191 GNUNET_STATISTICS_update (GST_stats,
1192 gettext_noop
1193 ("# failed address checks during validation"),
1194 1,
1195 GNUNET_NO);
1196 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1197 _ (
1198 "Address `%s' is not one of my addresses, not confirming PING\n"),
1199 GST_plugins_a2s (&address));
1200 return GNUNET_SYSERR;
1201 }
1202 else
1203 {
1204 GNUNET_STATISTICS_update (GST_stats,
1205 gettext_noop
1206 (
1207 "# successful address checks during validation"),
1208 1,
1209 GNUNET_NO);
1210 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1211 "Address `%s' is one of my addresses, confirming PING\n",
1212 GST_plugins_a2s (&address));
1213 }
1214
1215 if (GNUNET_YES !=
1216 GST_hello_test_address (&address,
1217 &sig_cache,
1218 &sig_cache_exp))
1219 {
1220 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1221 _ (
1222 "Not confirming PING from peer `%s' with address `%s' since I cannot confirm having this address.\n"),
1223 GNUNET_i2s (sender),
1224 GST_plugins_a2s (&address));
1225 return GNUNET_SYSERR;
1226 }
1227 }
1228 else
1229 {
1230 addrend = NULL; /* make gcc happy */
1231 len_plugin = 0;
1232 static struct GNUNET_CRYPTO_EddsaSignature no_address_signature;
1233 static struct GNUNET_TIME_Absolute no_address_signature_expiration;
1234
1235 sig_cache = &no_address_signature;
1236 sig_cache_exp = &no_address_signature_expiration;
1237 }
1238
1239 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1240 "I am `%s', sending PONG to peer `%s'\n",
1241 GNUNET_i2s_full (&GST_my_identity),
1242 GNUNET_i2s (sender));
1243
1244 /* message with structure:
1245 * [TransportPongMessage][Transport name][Address] */
1246
1247 pong = GNUNET_malloc (sizeof(struct TransportPongMessage) + len_address
1248 + len_plugin);
1249 pong->header.size =
1250 htons (sizeof(struct TransportPongMessage) + len_address + len_plugin);
1251 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
1252 pong->purpose.size =
1253 htonl (sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose)
1254 + sizeof(uint32_t) + sizeof(struct GNUNET_TIME_AbsoluteNBO)
1255 + len_address + len_plugin);
1256 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN);
1257 GNUNET_memcpy (&pong->challenge, &ping->challenge, sizeof(ping->challenge));
1258 pong->addrlen = htonl (len_address + len_plugin);
1259 GNUNET_memcpy (&pong[1], addr, len_plugin); /* Copy transport plugin */
1260 if (len_address > 0)
1261 {
1262 GNUNET_assert (NULL != addrend);
1263 GNUNET_memcpy (&((char *) &pong[1])[len_plugin], addrend, len_address);
1264 }
1265 if (GNUNET_TIME_absolute_get_remaining (*sig_cache_exp).rel_value_us <
1266 PONG_SIGNATURE_LIFETIME.rel_value_us / 4)
1267 {
1268 /* create / update cached sig */
1269 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1270 "Creating PONG signature to indicate ownership.\n");
1271 *sig_cache_exp = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
1272 pong->expiration = GNUNET_TIME_absolute_hton (*sig_cache_exp);
1273 if (GNUNET_OK !=
1274 GNUNET_CRYPTO_eddsa_sign_ (&GST_my_private_key,
1275 &pong->purpose,
1276 sig_cache))
1277 {
1278 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1279 _ ("Failed to create PONG signature for peer `%s'\n"),
1280 GNUNET_i2s (sender));
1281 }
1282 }
1283 else
1284 {
1285 pong->expiration = GNUNET_TIME_absolute_hton (*sig_cache_exp);
1286 }
1287 pong->signature = *sig_cache;
1288
1289 GNUNET_assert (NULL != sender_address);
1290
1291 /* first see if the session we got this PING from can be used to transmit
1292 * a response reliably */
1293 if (NULL == papi)
1294 {
1295 ret = -1;
1296 }
1297 else
1298 {
1299 GNUNET_assert (NULL != papi->send);
1300 GNUNET_assert (NULL != papi->get_session);
1301 if (NULL == session)
1302 {
1303 session = papi->get_session (papi->cls, sender_address);
1304 }
1305 if (NULL == session)
1306 {
1307 GNUNET_break (0);
1308 ret = -1;
1309 }
1310 else
1311 {
1312 ret = papi->send (papi->cls, session,
1313 (const char *) pong,
1314 ntohs (pong->header.size),
1315 PONG_PRIORITY, ACCEPTABLE_PING_DELAY,
1316 NULL, NULL);
1317 if (-1 != ret)
1318 GST_neighbours_notify_data_sent (sender_address,
1319 session,
1320 pong->header.size);
1321 }
1322 }
1323 if (-1 != ret)
1324 {
1325 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1326 "Transmitted PONG to `%s' via reliable mechanism\n",
1327 GNUNET_i2s (sender));
1328 /* done! */
1329 GNUNET_STATISTICS_update (GST_stats,
1330 gettext_noop
1331 ("# PONGs unicast via reliable transport"), 1,
1332 GNUNET_NO);
1333 GNUNET_free (pong);
1334 return GNUNET_OK;
1335 }
1336
1337 /* no reliable method found, try transmission via all known addresses */
1338 GNUNET_STATISTICS_update (GST_stats,
1339 gettext_noop
1340 ("# PONGs multicast to all available addresses"),
1341 1,
1342 GNUNET_NO);
1343 GST_validation_get_addresses (sender,
1344 &multicast_pong, pong);
1345 GNUNET_free (pong);
1346 return GNUNET_OK;
1347}
1348
1349
1350/**
1351 * Validate an individual address.
1352 *
1353 * @param address address we should try to validate
1354 */
1355void
1356GST_validation_handle_address (const struct GNUNET_HELLO_Address *address)
1357{
1358 struct GNUNET_TRANSPORT_PluginFunctions *papi;
1359 struct ValidationEntry *ve;
1360
1361 papi = GST_plugins_find (address->transport_name);
1362 if (NULL == papi)
1363 {
1364 /* This plugin is currently unavailable ... ignore */
1365 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1366 "No plugin available for %s\n",
1367 address->transport_name);
1368 return;
1369 }
1370 ve = find_validation_entry (address);
1371 if (NULL == ve->revalidation_task)
1372 {
1373 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1374 "Validation process started for fresh address `%s' of %s\n",
1375 GST_plugins_a2s (ve->address),
1376 GNUNET_i2s (&ve->address->peer));
1377 ve->revalidation_task = GNUNET_SCHEDULER_add_now (&revalidate_address, ve);
1378 }
1379 else
1380 {
1381 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1382 "Validation already running for address `%s' of %s\n",
1383 GST_plugins_a2s (ve->address),
1384 GNUNET_i2s (&ve->address->peer));
1385 }
1386}
1387
1388
1389/**
1390 * Iterator callback to go over all addresses and try to validate them
1391 * (unless blocked or already validated).
1392 *
1393 * @param cls NULL
1394 * @param address the address
1395 * @param expiration expiration time
1396 * @return #GNUNET_OK (keep the address)
1397 */
1398static int
1399validate_address_iterator (void *cls,
1400 const struct GNUNET_HELLO_Address *address,
1401 struct GNUNET_TIME_Absolute expiration)
1402{
1403 if (0 == GNUNET_TIME_absolute_get_remaining (expiration).rel_value_us)
1404 {
1405 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1406 "Skipping expired address from HELLO\n");
1407 return GNUNET_OK; /* expired */
1408 }
1409 GST_validation_handle_address (address);
1410 return GNUNET_OK;
1411}
1412
1413
1414/**
1415 * Add the validated peer address to the HELLO.
1416 *
1417 * @param cls the `struct ValidationEntry *` with the validated address
1418 * @param max space in @a buf
1419 * @param buf where to add the address
1420 * @return number of bytes written, #GNUNET_SYSERR to signal the
1421 * end of the iteration.
1422 */
1423static ssize_t
1424add_valid_peer_address (void *cls,
1425 size_t max,
1426 void *buf)
1427{
1428 struct ValidationEntry *ve = cls;
1429
1430 if (GNUNET_YES == ve->copied)
1431 return GNUNET_SYSERR; /* Done */
1432 ve->copied = GNUNET_YES;
1433 return GNUNET_HELLO_add_address (ve->address,
1434 ve->valid_until,
1435 buf,
1436 max);
1437}
1438
1439
1440/**
1441 * We've received a PONG. Check if it matches a pending PING and
1442 * mark the respective address as confirmed.
1443 *
1444 * @param sender peer sending the PONG
1445 * @param hdr the PONG
1446 * @return #GNUNET_OK if the message was fine, #GNUNET_SYSERR on serious error
1447 */
1448int
1449GST_validation_handle_pong (const struct GNUNET_PeerIdentity *sender,
1450 const struct GNUNET_MessageHeader *hdr)
1451{
1452 const struct TransportPongMessage *pong;
1453 struct ValidationEntry *ve;
1454 const char *tname;
1455 const char *addr;
1456 size_t addrlen;
1457 size_t slen;
1458 size_t size;
1459 struct GNUNET_HELLO_Message *hello;
1460 struct GNUNET_HELLO_Address address;
1461 int sig_res;
1462 int do_verify;
1463
1464 if (0 ==
1465 memcmp (&GST_my_identity,
1466 sender,
1467 sizeof(struct GNUNET_PeerIdentity)))
1468 return GNUNET_OK; /* our own, ignore! */
1469
1470 if (ntohs (hdr->size) < sizeof(struct TransportPongMessage))
1471 {
1472 GNUNET_break_op (0);
1473 return GNUNET_SYSERR;
1474 }
1475 GNUNET_STATISTICS_update (GST_stats,
1476 gettext_noop ("# PONG messages received"), 1,
1477 GNUNET_NO);
1478
1479 /* message with structure:
1480 * [TransportPongMessage][Transport name][Address] */
1481
1482 pong = (const struct TransportPongMessage *) hdr;
1483 tname = (const char *) &pong[1];
1484 size = ntohs (hdr->size) - sizeof(struct TransportPongMessage);
1485 addr = memchr (tname, '\0', size);
1486 if (NULL == addr)
1487 {
1488 GNUNET_break_op (0);
1489 return GNUNET_SYSERR;
1490 }
1491 addr++;
1492 slen = strlen (tname) + 1;
1493 addrlen = size - slen;
1494
1495 if (NULL == GST_plugins_find (tname))
1496 {
1497 /* we got the PONG, but the transport plugin specified in it
1498 is not supported by this peer, so this cannot be a good
1499 PONG for us. */
1500 GNUNET_break_op (0);
1501 return GNUNET_OK;
1502 }
1503
1504 address.peer = *sender;
1505 address.address = addr;
1506 address.address_length = addrlen;
1507 address.transport_name = tname;
1508 address.local_info = GNUNET_HELLO_ADDRESS_INFO_NONE;
1509 ve = find_validation_entry (&address);
1510 if ((NULL == ve) || (GNUNET_NO == ve->expecting_pong))
1511 {
1512 GNUNET_STATISTICS_update (GST_stats,
1513 gettext_noop
1514 (
1515 "# PONGs dropped, no matching pending validation"),
1516 1, GNUNET_NO);
1517 return GNUNET_OK;
1518 }
1519 /* now check that PONG is well-formed */
1520 if (0 != memcmp (&ve->address->peer,
1521 sender,
1522 sizeof(struct GNUNET_PeerIdentity)))
1523 {
1524 GNUNET_break_op (0);
1525 return GNUNET_SYSERR;
1526 }
1527 if (0 ==
1528 GNUNET_TIME_absolute_get_remaining
1529 (GNUNET_TIME_absolute_ntoh (pong->expiration)).rel_value_us)
1530 {
1531 GNUNET_STATISTICS_update (GST_stats,
1532 gettext_noop
1533 ("# PONGs dropped, signature expired"), 1,
1534 GNUNET_NO);
1535 return GNUNET_SYSERR;
1536 }
1537
1538 sig_res = GNUNET_SYSERR;
1539 do_verify = GNUNET_YES;
1540 if (0 != GNUNET_TIME_absolute_get_remaining (
1541 ve->pong_sig_valid_until).rel_value_us)
1542 {
1543 /* We have a cached and valid signature for this peer,
1544 * try to compare instead of verify */
1545 if (0 == memcmp (&ve->pong_sig_cache,
1546 &pong->signature,
1547 sizeof(struct GNUNET_CRYPTO_EddsaSignature)))
1548 {
1549 /* signatures are identical, we can skip verification */
1550 sig_res = GNUNET_OK;
1551 do_verify = GNUNET_NO;
1552 }
1553 else
1554 {
1555 sig_res = GNUNET_SYSERR;
1556 /* signatures do not match, we have to verify */
1557 }
1558 }
1559
1560 if (GNUNET_YES == do_verify)
1561 {
1562 /* Do expensive verification */
1563 sig_res = GNUNET_CRYPTO_eddsa_verify_ (
1564 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
1565 &pong->purpose,
1566 &pong->signature,
1567 &ve->address->peer.public_key);
1568 if (sig_res == GNUNET_SYSERR)
1569 {
1570 GNUNET_break_op (0);
1571 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1572 "Failed to verify: invalid signature on address `%s':%s from peer `%s'\n",
1573 tname,
1574 GST_plugins_a2s (ve->address),
1575 GNUNET_i2s (sender));
1576 }
1577 }
1578 if (sig_res == GNUNET_SYSERR)
1579 {
1580 GNUNET_break_op (0);
1581 return GNUNET_SYSERR;
1582 }
1583
1584 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1585 "Validation process successful for peer `%s' with plugin `%s' address `%s'\n",
1586 GNUNET_i2s (sender),
1587 tname,
1588 GST_plugins_a2s (ve->address));
1589 GNUNET_STATISTICS_update (GST_stats,
1590 gettext_noop ("# validations succeeded"),
1591 1,
1592 GNUNET_NO);
1593 /* validity achieved, remember it! */
1594 ve->expecting_pong = GNUNET_NO;
1595 ve->valid_until = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1596 ve->pong_sig_cache = pong->signature;
1597 ve->pong_sig_valid_until = GNUNET_TIME_absolute_ntoh (pong->expiration);
1598 ve->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
1599 {
1600 if (GNUNET_YES == ve->known_to_ats)
1601 {
1602 GNUNET_assert (GNUNET_YES ==
1603 GST_ats_is_known_no_session (ve->address));
1604 GST_ats_update_delay (ve->address,
1605 GNUNET_TIME_relative_divide (ve->latency, 2));
1606 }
1607 else
1608 {
1609 struct GNUNET_ATS_Properties prop;
1610
1611 memset (&prop, 0, sizeof(prop));
1612 GNUNET_break (GNUNET_NT_UNSPECIFIED != ve->network);
1613 prop.scope = ve->network;
1614 prop.delay = GNUNET_TIME_relative_divide (ve->latency, 2);
1615 GNUNET_assert (GNUNET_NO ==
1616 GST_ats_is_known_no_session (ve->address));
1617 ve->known_to_ats = GNUNET_YES;
1618 GST_ats_add_address (ve->address, &prop);
1619 GNUNET_assert (GNUNET_YES ==
1620 GST_ats_is_known_no_session (ve->address));
1621 }
1622 }
1623 if (validations_running > 0)
1624 {
1625 validations_running--;
1626 GNUNET_STATISTICS_set (GST_stats,
1627 gettext_noop ("# validations running"),
1628 validations_running,
1629 GNUNET_NO);
1630 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1631 "Validation finished, %u validation processes running\n",
1632 validations_running);
1633 }
1634 else
1635 {
1636 GNUNET_break (0);
1637 }
1638
1639 /* Notify about new validity */
1640 validation_entry_changed (ve,
1641 GNUNET_TRANSPORT_VS_UPDATE);
1642
1643 /* build HELLO to store in PEERINFO */
1644 GNUNET_STATISTICS_update (GST_stats,
1645 gettext_noop ("# HELLOs given to peerinfo"),
1646 1,
1647 GNUNET_NO);
1648 ve->copied = GNUNET_NO;
1649 hello = GNUNET_HELLO_create (&ve->address->peer.public_key,
1650 &add_valid_peer_address,
1651 ve,
1652 GNUNET_NO);
1653 GNUNET_break (NULL !=
1654 GNUNET_PEERINFO_add_peer (GST_peerinfo,
1655 hello,
1656 NULL,
1657 NULL));
1658 GNUNET_free (hello);
1659 return GNUNET_OK;
1660}
1661
1662
1663/**
1664 * We've received a HELLO, check which addresses are new and trigger
1665 * validation.
1666 *
1667 * @param hello the HELLO we received
1668 * @return #GNUNET_OK if the message was fine, #GNUNET_SYSERR on serious error
1669 */
1670int
1671GST_validation_handle_hello (const struct GNUNET_MessageHeader *hello)
1672{
1673 const struct GNUNET_HELLO_Message *hm =
1674 (const struct GNUNET_HELLO_Message *) hello;
1675 struct GNUNET_PeerIdentity pid;
1676 int friend;
1677
1678 friend = GNUNET_HELLO_is_friend_only (hm);
1679 if (((GNUNET_YES != friend) &&
1680 (GNUNET_NO != friend)) ||
1681 (GNUNET_OK != GNUNET_HELLO_get_id (hm, &pid)))
1682 {
1683 /* malformed HELLO */
1684 GNUNET_break_op (0);
1685 return GNUNET_SYSERR;
1686 }
1687 if (0 ==
1688 memcmp (&GST_my_identity,
1689 &pid,
1690 sizeof(struct GNUNET_PeerIdentity)))
1691 {
1692 /* got our own HELLO, how boring */
1693 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1694 "Validation received our own HELLO (%s), ignoring\n",
1695 GNUNET_i2s (&pid));
1696 return GNUNET_OK;
1697 }
1698 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1699 "Validation received HELLO message for peer `%s' with size %u, checking for new addresses\n",
1700 GNUNET_i2s (&pid),
1701 ntohs (hello->size));
1702 GNUNET_assert (NULL ==
1703 GNUNET_HELLO_iterate_addresses (hm,
1704 GNUNET_NO,
1705 &validate_address_iterator,
1706 NULL));
1707 return GNUNET_OK;
1708}
1709
1710
1711/**
1712 * Closure for #iterate_addresses().
1713 */
1714struct IteratorContext
1715{
1716 /**
1717 * Function to call on each address.
1718 */
1719 GST_ValidationAddressCallback cb;
1720
1721 /**
1722 * Closure for @e cb.
1723 */
1724 void *cb_cls;
1725};
1726
1727
1728/**
1729 * Call the callback in the closure for each validation entry.
1730 *
1731 * @param cls the `struct IteratorContext`
1732 * @param key the peer's identity
1733 * @param value the `struct ValidationEntry`
1734 * @return #GNUNET_OK (continue to iterate)
1735 */
1736static int
1737iterate_addresses (void *cls,
1738 const struct GNUNET_PeerIdentity *key,
1739 void *value)
1740{
1741 struct IteratorContext *ic = cls;
1742 struct ValidationEntry *ve = value;
1743
1744 ic->cb (ic->cb_cls,
1745 ve->valid_until,
1746 ve->revalidation_block,
1747 ve->address);
1748 return GNUNET_OK;
1749}
1750
1751
1752/**
1753 * Call the given function for each address for the given target.
1754 * Can either give a snapshot (synchronous API) or be continuous.
1755 *
1756 * @param target peer information is requested for
1757 * @param cb function to call; will not be called after this function returns
1758 * @param cb_cls closure for @a cb
1759 */
1760void
1761GST_validation_get_addresses (const struct GNUNET_PeerIdentity *target,
1762 GST_ValidationAddressCallback cb,
1763 void *cb_cls)
1764{
1765 struct IteratorContext ic;
1766
1767 ic.cb = cb;
1768 ic.cb_cls = cb_cls;
1769 GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
1770 target,
1771 &iterate_addresses, &ic);
1772}
1773
1774
1775/**
1776 * Update if we are using an address for a connection actively right now.
1777 * Based on this, the validation module will measure latency for the
1778 * address more or less often.
1779 *
1780 * @param address the address that we are now using (or not)
1781 * @param in_use #GNUNET_YES if we are now using the address for a connection,
1782 * #GNUNET_NO if we are no longer using the address for a connection
1783 */
1784void
1785GST_validation_set_address_use (const struct GNUNET_HELLO_Address *address,
1786 int in_use)
1787{
1788 struct ValidationEntry *ve;
1789
1790 if (GNUNET_HELLO_address_check_option (address,
1791 GNUNET_HELLO_ADDRESS_INFO_INBOUND))
1792 return; /* ignore inbound for validation */
1793 if (NULL == GST_plugins_find (address->transport_name))
1794 {
1795 /* How can we use an address for which we don't have the plugin? */
1796 GNUNET_break (0);
1797 return;
1798 }
1799 ve = find_validation_entry (address);
1800 if (NULL == ve)
1801 {
1802 GNUNET_break (0);
1803 return;
1804 }
1805 if (in_use == ve->in_use)
1806 return;
1807 ve->in_use = in_use;
1808 if (GNUNET_YES == in_use)
1809 {
1810 /* from now on, higher frequency, so reschedule now */
1811 if (NULL != ve->revalidation_task)
1812 GNUNET_SCHEDULER_cancel (ve->revalidation_task);
1813 ve->revalidation_task = GNUNET_SCHEDULER_add_now (&revalidate_address,
1814 ve);
1815 }
1816}
1817
1818
1819/* end of file gnunet-service-transport_validation.c */
diff --git a/src/transport/gnunet-service-transport_validation.h b/src/transport/gnunet-service-transport_validation.h
deleted file mode 100644
index 2a0428869..000000000
--- a/src/transport/gnunet-service-transport_validation.h
+++ /dev/null
@@ -1,146 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010,2011 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/gnunet-service-transport_validation.h
23 * @brief address validation API
24 * @author Christian Grothoff
25 */
26#ifndef GNUNET_SERVICE_TRANSPORT_VALIDATION_H
27#define GNUNET_SERVICE_TRANSPORT_VALIDATION_H
28
29#include "gnunet_statistics_service.h"
30#include "gnunet_transport_plugin.h"
31#include "gnunet_util_lib.h"
32#include "gnunet_hello_lib.h"
33
34/**
35 * Start the validation subsystem.
36 *
37 * @param max_fds maximum number of fds to use
38 */
39void
40GST_validation_start (unsigned int max_fds);
41
42
43/**
44 * Stop the validation subsystem.
45 */
46void
47GST_validation_stop (void);
48
49
50/**
51 * Update if we are using an address for a connection actively right now.
52 * Based on this, the validation module will measure latency for the
53 * address more or less often.
54 *
55 * @param address the address that we are now using (or not)
56 * @param in_use #GNUNET_YES if we are now using the address for a connection,
57 * #GNUNET_NO if we are no longer using the address for a connection
58 */
59void
60GST_validation_set_address_use (const struct GNUNET_HELLO_Address *address,
61 int in_use);
62
63
64/**
65 * We've received a PING. If appropriate, generate a PONG.
66 *
67 * @param sender peer sending the PING
68 * @param hdr the PING
69 * @param sender_address address of the sender, NULL if we did not initiate
70 * @param session session we got the PING from
71 * @return #GNUNET_OK if the message was fine, #GNUNET_SYSERR on serious error
72 */
73int
74GST_validation_handle_ping (const struct GNUNET_PeerIdentity *sender,
75 const struct GNUNET_MessageHeader *hdr,
76 const struct GNUNET_HELLO_Address *sender_address,
77 struct GNUNET_ATS_Session *session);
78
79
80/**
81 * We've received a PONG. Check if it matches a pending PING and
82 * mark the respective address as confirmed.
83 *
84 * @param sender peer sending the PONG
85 * @param hdr the PONG
86 * @return #GNUNET_OK if the message was fine, #GNUNET_SYSERR on serious error
87 */
88int
89GST_validation_handle_pong (const struct GNUNET_PeerIdentity *sender,
90 const struct GNUNET_MessageHeader *hdr);
91
92
93/**
94 * We've received a HELLO, check which addresses are new and trigger
95 * validation.
96 *
97 * @param hello the HELLO we received
98 * @return #GNUNET_OK if the message was fine, #GNUNET_SYSERR on serious error
99 */
100int
101GST_validation_handle_hello (const struct GNUNET_MessageHeader *hello);
102
103
104/**
105 * Validate an individual address.
106 *
107 * @param address address we should try to validate
108 */
109void
110GST_validation_handle_address (const struct GNUNET_HELLO_Address *address);
111
112
113/**
114 * Function called for each address (or address status change) that
115 * the validation module is aware of (for the given target).
116 *
117 * @param cls closure
118 * @param public_key public key for the peer, never NULL
119 * @param valid_until is ZERO if we never validated the address,
120 * otherwise a time up to when we consider it (or was) valid
121 * @param validation_block is FOREVER if the address is for an unsupported plugin (from PEERINFO)
122 * is ZERO if the address is considered valid (no validation needed)
123 * otherwise a time in the future if we're currently denying re-validation
124 * @param address the address
125 */
126typedef void
127(*GST_ValidationAddressCallback) (void *cls,
128 struct GNUNET_TIME_Absolute valid_until,
129 struct GNUNET_TIME_Absolute validation_block,
130 const struct GNUNET_HELLO_Address *address);
131
132
133/**
134 * Call the given function for each address for the given target.
135 *
136 * @param target peer information is requested for
137 * @param cb function to call; will not be called after this function returns
138 * @param cb_cls closure for @a cb
139 */
140void
141GST_validation_get_addresses (const struct GNUNET_PeerIdentity *target,
142 GST_ValidationAddressCallback cb, void *cb_cls);
143
144
145#endif
146/* end of file gnunet-service-transport_validation.h */
diff --git a/src/transport/gnunet-transport-wlan-receiver.c b/src/transport/gnunet-transport-wlan-receiver.c
deleted file mode 100644
index 7f34a957f..000000000
--- a/src/transport/gnunet-transport-wlan-receiver.c
+++ /dev/null
@@ -1,114 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2012 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/gnunet-transport-wlan-receiver.c
23 * @brief program to send via WLAN as much as possible (to test physical/theoretical throughput)
24 * @author David Brodski
25 */
26#include "platform.h"
27#include "gnunet_protocols.h"
28#include "plugin_transport_wlan.h"
29
30int
31main (int argc, char *argv[])
32{
33 char msg_buf[65536];
34 unsigned long long count;
35 double bytes_per_s;
36 time_t start;
37 time_t akt;
38 ssize_t ret;
39 pid_t pid;
40 int commpipe[2]; /* This holds the fd for the input & output of the pipe */
41
42 if (2 != argc)
43 {
44 fprintf (stderr,
45 "This program must be started with the interface name as argument.\n");
46 fprintf (stderr,
47 "Usage: %s interface-name\n"
48 "e.g. %s mon0\n",
49 argv[0],
50 argv[0]);
51 return 1;
52 }
53
54 /* Setup communication pipeline first */
55 if (pipe (commpipe))
56 {
57 fprintf (stderr, "Failed to create pipe: %s\n", strerror (errno));
58 exit (1);
59 }
60
61 /* Attempt to fork and check for errors */
62 if ((pid = fork ()) == -1)
63 {
64 fprintf (stderr, "Failed to fork: %s\n", strerror (errno));
65 exit (1);
66 }
67
68 if (pid)
69 {
70 /* A positive (non-negative) PID indicates the parent process */
71 if (0 != close (commpipe[1])) /* Close unused side of pipe (in side) */
72 fprintf (stderr, "Failed to close fd: %s\n", strerror (errno));
73 start = time (NULL);
74 count = 0;
75 while (1)
76 {
77 ret = read (commpipe[0], msg_buf, sizeof(msg_buf));
78 if (0 > ret)
79 {
80 fprintf (stderr, "read failed: %s\n", strerror (errno));
81 break;
82 }
83 count += ret;
84 akt = time (NULL);
85 if (akt - start > 30)
86 {
87 bytes_per_s = count / (akt - start);
88 bytes_per_s /= 1024;
89 printf ("recv %f kb/s\n", bytes_per_s);
90 start = akt;
91 count = 0;
92 }
93 }
94 }
95 else
96 {
97 /* A zero PID indicates that this is the child process */
98 (void) close (1);
99 if (-1 ==
100 dup2 (commpipe[1], 1)) /* Replace stdin with the in side of the pipe */
101 fprintf (stderr, "dup2 failed: %s\n", strerror (errno));
102 (void) close (commpipe[0]); /* Close unused side of pipe (in side) */
103 /* Replace the child fork with a new process */
104 if (execlp ("gnunet-helper-transport-wlan",
105 "gnunet-helper-transport-wlan",
106 argv[1],
107 NULL) == -1)
108 {
109 fprintf (stderr, "Could not start gnunet-helper-transport-wlan!");
110 _exit (1);
111 }
112 }
113 return 0;
114}
diff --git a/src/transport/gnunet-transport-wlan-sender.c b/src/transport/gnunet-transport-wlan-sender.c
deleted file mode 100644
index 5256ec7be..000000000
--- a/src/transport/gnunet-transport-wlan-sender.c
+++ /dev/null
@@ -1,251 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2011 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/gnunet-transport-wlan-sender.c
23 * @brief program to send via WLAN as much as possible (to test physical/theoretical throughput)
24 * @author David Brodski
25 */
26#include "platform.h"
27#include "plugin_transport_wlan.h"
28#include "gnunet_protocols.h"
29
30#define WLAN_MTU 1500
31
32/**
33 * LLC fields for better compatibility
34 */
35#define WLAN_LLC_DSAP_FIELD 0x1f
36#define WLAN_LLC_SSAP_FIELD 0x1f
37
38#define IEEE80211_ADDR_LEN 6 /* size of 802.11 address */
39
40#define IEEE80211_FC0_VERSION_MASK 0x03
41#define IEEE80211_FC0_VERSION_SHIFT 0
42#define IEEE80211_FC0_VERSION_0 0x00
43#define IEEE80211_FC0_TYPE_MASK 0x0c
44#define IEEE80211_FC0_TYPE_SHIFT 2
45#define IEEE80211_FC0_TYPE_MGT 0x00
46#define IEEE80211_FC0_TYPE_CTL 0x04
47#define IEEE80211_FC0_TYPE_DATA 0x08
48
49
50/**
51 * function to fill the radiotap header
52 * @param header pointer to the radiotap header
53 * @param size total message size
54 * @return GNUNET_YES at success
55 */
56static int
57getRadiotapHeader (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *header,
58 uint16_t size)
59{
60 header->header.size = htons (size);
61 header->header.type = htons (GNUNET_MESSAGE_TYPE_WLAN_DATA_TO_HELPER);
62 header->rate = 255;
63 header->tx_power = 0;
64 header->antenna = 0;
65 return GNUNET_YES;
66}
67
68
69/**
70 * function to generate the wlan hardware header for one packet
71 * @param Header address to write the header to
72 * @param to_mac_addr pointer to the address of the recipient
73 * @param mac pointer to the mac address to send from (normally overwritten over by helper)
74 * @param size size of the whole packet, needed to calculate the time to send the packet
75 * @return GNUNET_YES if there was no error
76 */
77static int
78getWlanHeader (struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *Header,
79 const struct GNUNET_TRANSPORT_WLAN_MacAddress *to_mac_addr,
80 const struct GNUNET_TRANSPORT_WLAN_MacAddress *mac,
81 unsigned int size)
82{
83 const int rate = 11000000;
84
85 Header->frame_control = htons (IEEE80211_FC0_TYPE_DATA);
86 Header->addr3 = mac_bssid_gnunet;
87 Header->addr2 = *mac;
88 Header->addr1 = *to_mac_addr;
89 Header->duration = GNUNET_htole16 ((size * 1000000) / rate + 290);
90 Header->llc[0] = WLAN_LLC_DSAP_FIELD;
91 Header->llc[1] = WLAN_LLC_SSAP_FIELD;
92 Header->llc[2] = 0; // FIXME
93 Header->llc[3] = 0; // FIXME
94 return GNUNET_YES;
95}
96
97
98int
99main (int argc, char *argv[])
100{
101 char msg_buf[WLAN_MTU];
102 struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *radiotap;
103 unsigned int temp[6];
104 struct GNUNET_TRANSPORT_WLAN_MacAddress inmac;
105 struct GNUNET_TRANSPORT_WLAN_MacAddress outmac;
106 struct GNUNET_TRANSPORT_WLAN_HelperControlMessage hcm;
107 unsigned long long count;
108 double bytes_per_s;
109 time_t start;
110 time_t akt;
111 int i;
112 ssize_t ret;
113 pid_t pid;
114 int commpipe[2]; /* This holds the fd for the input & output of the pipe */
115 int macpipe[2]; /* This holds the fd for the input & output of the pipe */
116
117 if (4 != argc)
118 {
119 fprintf (
120 stderr,
121 "This program must be started with the interface and the targets and source mac as argument.\n");
122 fprintf (stderr,
123 "Usage: interface-name mac-DST mac-SRC\n"
124 "e.g. mon0 11-22-33-44-55-66 12-34-56-78-90-ab\n");
125 return 1;
126 }
127 if (6 != sscanf (argv[2],
128 "%x-%x-%x-%x-%x-%x",
129 &temp[0],
130 &temp[1],
131 &temp[2],
132 &temp[3],
133 &temp[4],
134 &temp[5]))
135 {
136 fprintf (stderr,
137 "Usage: interface-name mac-DST mac-SRC\n"
138 "e.g. mon0 11-22-33-44-55-66 12-34-56-78-90-ab\n");
139 return 1;
140 }
141 for (i = 0; i < 6; i++)
142 outmac.mac[i] = temp[i];
143 if (6 != sscanf (argv[3],
144 "%x-%x-%x-%x-%x-%x",
145 &temp[0],
146 &temp[1],
147 &temp[2],
148 &temp[3],
149 &temp[4],
150 &temp[5]))
151 {
152 fprintf (stderr,
153 "Usage: interface-name mac-DST mac-SRC\n"
154 "e.g. mon0 11-22-33-44-55-66 12-34-56-78-90-ab\n");
155 return 1;
156 }
157 for (i = 0; i < 6; i++)
158 inmac.mac[i] = temp[i];
159
160
161 /* Setup communication pipeline first */
162 if (pipe (commpipe))
163 {
164 fprintf (stderr, "Failed to create pipe: %s\n", strerror (errno));
165 exit (1);
166 }
167 if (pipe (macpipe))
168 {
169 fprintf (stderr, "Failed to create pipe: %s\n", strerror (errno));
170 exit (1);
171 }
172
173 /* Attempt to fork and check for errors */
174 if ((pid = fork ()) == -1)
175 {
176 fprintf (stderr, "Failed to fork: %s\n", strerror (errno));
177 exit (1);
178 }
179 memset (msg_buf, 0x42, sizeof(msg_buf));
180 if (pid)
181 {
182 /* A positive (non-negative) PID indicates the parent process */
183 if (0 != close (commpipe[0])) /* Close unused side of pipe (in side) */
184 fprintf (stderr, "Failed to close fd: %s\n", strerror (errno));
185 setvbuf (stdout,
186 (char *) NULL,
187 _IONBF,
188 0); /* Set non-buffered output on stdout */
189
190 if (0 != close (macpipe[1]))
191 fprintf (stderr, "Failed to close fd: %s\n", strerror (errno));
192 if (sizeof(hcm) != read (macpipe[0], &hcm, sizeof(hcm)))
193 fprintf (stderr, "Failed to read hcm...\n");
194 fprintf (stderr,
195 "Got MAC %.2X:%.2X:%.2X:%.2X:%.2X:%.2X\n",
196 hcm.mac.mac[0],
197 hcm.mac.mac[1],
198 hcm.mac.mac[2],
199 hcm.mac.mac[3],
200 hcm.mac.mac[4],
201 hcm.mac.mac[5]);
202 radiotap = (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *) msg_buf;
203 getRadiotapHeader (radiotap, WLAN_MTU);
204 getWlanHeader (&radiotap->frame, &outmac, &inmac, WLAN_MTU);
205 start = time (NULL);
206 count = 0;
207 while (1)
208 {
209 ret = write (commpipe[1], msg_buf, WLAN_MTU);
210 if (0 > ret)
211 {
212 fprintf (stderr, "write failed: %s\n", strerror (errno));
213 break;
214 }
215 count += ret;
216 akt = time (NULL);
217 if (akt - start > 30)
218 {
219 bytes_per_s = count / (akt - start);
220 bytes_per_s /= 1024;
221 printf ("send %f kbytes/s\n", bytes_per_s);
222 start = akt;
223 count = 0;
224 }
225 }
226 }
227 else
228 {
229 /* A zero PID indicates that this is the child process */
230 (void) close (0);
231 (void) close (1);
232 if (-1 ==
233 dup2 (commpipe[0], 0)) /* Replace stdin with the in side of the pipe */
234 fprintf (stderr, "dup2 failed: %s\n", strerror (errno));
235 if (-1 ==
236 dup2 (macpipe[1], 1)) /* Replace stdout with the out side of the pipe */
237 fprintf (stderr, "dup2 failed: %s\n", strerror (errno));
238 (void) close (commpipe[1]); /* Close unused side of pipe (out side) */
239 (void) close (macpipe[0]); /* Close unused side of pipe (in side) */
240 /* Replace the child fork with a new process */
241 if (execlp ("gnunet-helper-transport-wlan",
242 "gnunet-helper-transport-wlan",
243 argv[1],
244 NULL) == -1)
245 {
246 fprintf (stderr, "Could not start gnunet-helper-transport-wlan!");
247 _exit (1);
248 }
249 }
250 return 0;
251}
diff --git a/src/transport/perf_http_peer1.conf b/src/transport/perf_http_peer1.conf
deleted file mode 100644
index e97e16289..000000000
--- a/src/transport/perf_http_peer1.conf
+++ /dev/null
@@ -1,37 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
4
5[transport]
6PLUGINS = http_client
7
8[nat]
9# Disable IPv6 support
10DISABLEV6 = YES
11# Do we use addresses from localhost address ranges? (::1, 127.0.0.0/8)
12RETURN_LOCAL_ADDRESSES = NO
13
14[hostlist]
15OPTIONS = -b
16SERVERS = http://localhost:9080/
17
18[ats]
19# Network specific inbound/outbound quotas
20UNSPECIFIED_QUOTA_IN = unlimited
21UNSPECIFIED_QUOTA_OUT = unlimited
22# LOOPBACK
23LOOPBACK_QUOTA_IN = unlimited
24LOOPBACK_QUOTA_OUT = unlimited
25# LAN
26LAN_QUOTA_IN = unlimited
27LAN_QUOTA_OUT = unlimited
28# WAN
29WAN_QUOTA_IN = unlimited
30WAN_QUOTA_OUT = unlimited
31# WLAN
32WLAN_QUOTA_IN = unlimited
33WLAN_QUOTA_OUT = unlimited
34# BLUETOOTH
35BLUETOOTH_QUOTA_IN = unlimited
36BLUETOOTH_QUOTA_OUT = unlimited
37# ATS options
diff --git a/src/transport/perf_http_peer2.conf b/src/transport/perf_http_peer2.conf
deleted file mode 100644
index a1c83bde5..000000000
--- a/src/transport/perf_http_peer2.conf
+++ /dev/null
@@ -1,40 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
4
5[transport]
6PLUGINS = http_server
7
8[nat]
9# Disable IPv6 support
10DISABLEV6 = YES
11# Do we use addresses from localhost address ranges? (::1, 127.0.0.0/8)
12RETURN_LOCAL_ADDRESSES = NO
13
14[hostlist]
15HTTPPORT = 9080
16OPTIONS = -p
17BINDTOIPV4 = YES
18BINDTOIP = 127.0.0.1
19
20[ats]
21# Network specific inbound/outbound quotas
22UNSPECIFIED_QUOTA_IN = unlimited
23UNSPECIFIED_QUOTA_OUT = unlimited
24# LOOPBACK
25LOOPBACK_QUOTA_IN = unlimited
26LOOPBACK_QUOTA_OUT = unlimited
27# LAN
28LAN_QUOTA_IN = unlimited
29LAN_QUOTA_OUT = unlimited
30# WAN
31WAN_QUOTA_IN = unlimited
32WAN_QUOTA_OUT = unlimited
33# WLAN
34WLAN_QUOTA_IN = unlimited
35WLAN_QUOTA_OUT = unlimited
36# BLUETOOTH
37BLUETOOTH_QUOTA_IN = unlimited
38BLUETOOTH_QUOTA_OUT = unlimited
39# ATS options
40
diff --git a/src/transport/perf_https_peer1.conf b/src/transport/perf_https_peer1.conf
deleted file mode 100644
index e943671c2..000000000
--- a/src/transport/perf_https_peer1.conf
+++ /dev/null
@@ -1,37 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
4
5[transport]
6PLUGINS = https_client
7
8[nat]
9# Disable IPv6 support
10DISABLEV6 = YES
11# Do we use addresses from localhost address ranges? (::1, 127.0.0.0/8)
12RETURN_LOCAL_ADDRESSES = NO
13
14[hostlist]
15OPTIONS = -b
16SERVERS = http://localhost:9080/
17
18[ats]
19# Network specific inbound/outbound quotas
20UNSPECIFIED_QUOTA_IN = unlimited
21UNSPECIFIED_QUOTA_OUT = unlimited
22# LOOPBACK
23LOOPBACK_QUOTA_IN = unlimited
24LOOPBACK_QUOTA_OUT = unlimited
25# LAN
26LAN_QUOTA_IN = unlimited
27LAN_QUOTA_OUT = unlimited
28# WAN
29WAN_QUOTA_IN = unlimited
30WAN_QUOTA_OUT = unlimited
31# WLAN
32WLAN_QUOTA_IN = unlimited
33WLAN_QUOTA_OUT = unlimited
34# BLUETOOTH
35BLUETOOTH_QUOTA_IN = unlimited
36BLUETOOTH_QUOTA_OUT = unlimited
37# ATS options
diff --git a/src/transport/perf_https_peer2.conf b/src/transport/perf_https_peer2.conf
deleted file mode 100644
index 6e30f9e60..000000000
--- a/src/transport/perf_https_peer2.conf
+++ /dev/null
@@ -1,40 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
4
5[transport]
6PLUGINS = https_server
7
8[nat]
9# Disable IPv6 support
10DISABLEV6 = YES
11# Do we use addresses from localhost address ranges? (::1, 127.0.0.0/8)
12RETURN_LOCAL_ADDRESSES = NO
13
14[hostlist]
15HTTPPORT = 9080
16OPTIONS = -p
17BINDTOIPV4 = YES
18BINDTOIP = 127.0.0.1
19
20[ats]
21# Network specific inbound/outbound quotas
22UNSPECIFIED_QUOTA_IN = unlimited
23UNSPECIFIED_QUOTA_OUT = unlimited
24# LOOPBACK
25LOOPBACK_QUOTA_IN = unlimited
26LOOPBACK_QUOTA_OUT = unlimited
27# LAN
28LAN_QUOTA_IN = unlimited
29LAN_QUOTA_OUT = unlimited
30# WAN
31WAN_QUOTA_IN = unlimited
32WAN_QUOTA_OUT = unlimited
33# WLAN
34WLAN_QUOTA_IN = unlimited
35WLAN_QUOTA_OUT = unlimited
36# BLUETOOTH
37BLUETOOTH_QUOTA_IN = unlimited
38BLUETOOTH_QUOTA_OUT = unlimited
39# ATS options
40
diff --git a/src/transport/perf_tcp_peer1.conf b/src/transport/perf_tcp_peer1.conf
deleted file mode 100644
index e56c47ada..000000000
--- a/src/transport/perf_tcp_peer1.conf
+++ /dev/null
@@ -1,31 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
4
5[transport]
6PLUGINS = tcp
7
8[hostlist]
9OPTIONS = -b
10SERVERS = http://localhost:9080/
11
12[ats]
13# Network specific inbound/outbound quotas
14UNSPECIFIED_QUOTA_IN = unlimited
15UNSPECIFIED_QUOTA_OUT = unlimited
16# LOOPBACK
17LOOPBACK_QUOTA_IN = unlimited
18LOOPBACK_QUOTA_OUT = unlimited
19# LAN
20LAN_QUOTA_IN = unlimited
21LAN_QUOTA_OUT = unlimited
22# WAN
23WAN_QUOTA_IN = unlimited
24WAN_QUOTA_OUT = unlimited
25# WLAN
26WLAN_QUOTA_IN = unlimited
27WLAN_QUOTA_OUT = unlimited
28# BLUETOOTH
29BLUETOOTH_QUOTA_IN = unlimited
30BLUETOOTH_QUOTA_OUT = unlimited
31# ATS options
diff --git a/src/transport/perf_tcp_peer2.conf b/src/transport/perf_tcp_peer2.conf
deleted file mode 100644
index 3264161f5..000000000
--- a/src/transport/perf_tcp_peer2.conf
+++ /dev/null
@@ -1,34 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
4
5[transport]
6PLUGINS = tcp
7
8[hostlist]
9HTTPPORT = 9080
10OPTIONS = -p
11BINDTOIPV4 = YES
12BINDTOIP = 127.0.0.1
13
14[ats]
15# Network specific inbound/outbound quotas
16UNSPECIFIED_QUOTA_IN = unlimited
17UNSPECIFIED_QUOTA_OUT = unlimited
18# LOOPBACK
19LOOPBACK_QUOTA_IN = unlimited
20LOOPBACK_QUOTA_OUT = unlimited
21# LAN
22LAN_QUOTA_IN = unlimited
23LAN_QUOTA_OUT = unlimited
24# WAN
25WAN_QUOTA_IN = unlimited
26WAN_QUOTA_OUT = unlimited
27# WLAN
28WLAN_QUOTA_IN = unlimited
29WLAN_QUOTA_OUT = unlimited
30# BLUETOOTH
31BLUETOOTH_QUOTA_IN = unlimited
32BLUETOOTH_QUOTA_OUT = unlimited
33# ATS options
34
diff --git a/src/transport/perf_udp_peer1.conf b/src/transport/perf_udp_peer1.conf
deleted file mode 100644
index 68bf43908..000000000
--- a/src/transport/perf_udp_peer1.conf
+++ /dev/null
@@ -1,43 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
4
5[transport]
6PLUGINS = udp
7
8[transport-udp]
9BROADCAST = NO
10BROADCAST_RECEIVE = NO
11BROADCAST_INTERVAL = 30 s
12MAX_BPS = 1000000000
13
14[nat]
15# Disable IPv6 support
16DISABLEV6 = YES
17# Do we use addresses from localhost address ranges? (::1, 127.0.0.0/8)
18RETURN_LOCAL_ADDRESSES = NO
19
20[hostlist]
21OPTIONS = -b
22SERVERS = http://localhost:9080/
23
24[ats]
25# Network specific inbound/outbound quotas
26UNSPECIFIED_QUOTA_IN = unlimited
27UNSPECIFIED_QUOTA_OUT = unlimited
28# LOOPBACK
29LOOPBACK_QUOTA_IN = unlimited
30LOOPBACK_QUOTA_OUT = unlimited
31# LAN
32LAN_QUOTA_IN = unlimited
33LAN_QUOTA_OUT = unlimited
34# WAN
35WAN_QUOTA_IN = unlimited
36WAN_QUOTA_OUT = unlimited
37# WLAN
38WLAN_QUOTA_IN = unlimited
39WLAN_QUOTA_OUT = unlimited
40# BLUETOOTH
41BLUETOOTH_QUOTA_IN = unlimited
42BLUETOOTH_QUOTA_OUT = unlimited
43# ATS options
diff --git a/src/transport/perf_udp_peer2.conf b/src/transport/perf_udp_peer2.conf
deleted file mode 100644
index efed935f8..000000000
--- a/src/transport/perf_udp_peer2.conf
+++ /dev/null
@@ -1,48 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
4
5[transport]
6PLUGINS = udp
7
8
9[transport-udp]
10# Use PORT = 0 to autodetect a port available
11BROADCAST = NO
12BROADCAST_RECEIVE = NO
13BROADCAST_INTERVAL = 30 s
14MAX_BPS = 1000000000
15
16[nat]
17# Disable IPv6 support
18DISABLEV6 = YES
19# Do we use addresses from localhost address ranges? (::1, 127.0.0.0/8)
20RETURN_LOCAL_ADDRESSES = NO
21
22[hostlist]
23HTTPPORT = 9080
24OPTIONS = -p
25BINDTOIPV4 = YES
26BINDTOIP = 127.0.0.1
27
28[ats]
29# Network specific inbound/outbound quotas
30UNSPECIFIED_QUOTA_IN = unlimited
31UNSPECIFIED_QUOTA_OUT = unlimited
32# LOOPBACK
33LOOPBACK_QUOTA_IN = unlimited
34LOOPBACK_QUOTA_OUT = unlimited
35# LAN
36LAN_QUOTA_IN = unlimited
37LAN_QUOTA_OUT = unlimited
38# WAN
39WAN_QUOTA_IN = unlimited
40WAN_QUOTA_OUT = unlimited
41# WLAN
42WLAN_QUOTA_IN = unlimited
43WLAN_QUOTA_OUT = unlimited
44# BLUETOOTH
45BLUETOOTH_QUOTA_IN = unlimited
46BLUETOOTH_QUOTA_OUT = unlimited
47# ATS options
48
diff --git a/src/transport/perf_unix_peer1.conf b/src/transport/perf_unix_peer1.conf
deleted file mode 100644
index 06cd63fc6..000000000
--- a/src/transport/perf_unix_peer1.conf
+++ /dev/null
@@ -1,52 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
4
5[transport]
6PORT = 12001
7UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
8PLUGINS = unix
9
10[transport-unix]
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-unix.sock
12
13[arm]
14PORT = 12005
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
16
17[statistics]
18PORT = 12004
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
20
21[resolver]
22PORT = 12003
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
24
25[peerinfo]
26PORT = 12002
27UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
28
29[hostlist]
30OPTIONS = -b
31SERVERS = http://localhost:9080/
32
33[ats]
34# Network specific inbound/outbound quotas
35UNSPECIFIED_QUOTA_IN = unlimited
36UNSPECIFIED_QUOTA_OUT = unlimited
37# LOOPBACK
38LOOPBACK_QUOTA_IN = unlimited
39LOOPBACK_QUOTA_OUT = unlimited
40# LAN
41LAN_QUOTA_IN = unlimited
42LAN_QUOTA_OUT = unlimited
43# WAN
44WAN_QUOTA_IN = unlimited
45WAN_QUOTA_OUT = unlimited
46# WLAN
47WLAN_QUOTA_IN = unlimited
48WLAN_QUOTA_OUT = unlimited
49# BLUETOOTH
50BLUETOOTH_QUOTA_IN = unlimited
51BLUETOOTH_QUOTA_OUT = unlimited
52# ATS options
diff --git a/src/transport/perf_unix_peer2.conf b/src/transport/perf_unix_peer2.conf
deleted file mode 100644
index feadb6fec..000000000
--- a/src/transport/perf_unix_peer2.conf
+++ /dev/null
@@ -1,56 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
4
5[transport]
6PORT = 12010
7PLUGINS = unix
8UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
9
10
11[transport-unix]
12UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-unix.sock
13
14[arm]
15PORT = 12014
16UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
17
18[statistics]
19PORT = 12013
20UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
21
22[resolver]
23PORT = 12012
24UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
25
26[peerinfo]
27PORT = 12011
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
29
30[hostlist]
31HTTPPORT = 9080
32OPTIONS = -p
33BINDTOIPV4 = YES
34BINDTOIP = 127.0.0.1
35
36[ats]
37# Network specific inbound/outbound quotas
38UNSPECIFIED_QUOTA_IN = unlimited
39UNSPECIFIED_QUOTA_OUT = unlimited
40# LOOPBACK
41LOOPBACK_QUOTA_IN = unlimited
42LOOPBACK_QUOTA_OUT = unlimited
43# LAN
44LAN_QUOTA_IN = unlimited
45LAN_QUOTA_OUT = unlimited
46# WAN
47WAN_QUOTA_IN = unlimited
48WAN_QUOTA_OUT = unlimited
49# WLAN
50WLAN_QUOTA_IN = unlimited
51WLAN_QUOTA_OUT = unlimited
52# BLUETOOTH
53BLUETOOTH_QUOTA_IN = unlimited
54BLUETOOTH_QUOTA_OUT = unlimited
55# ATS options
56
diff --git a/src/transport/plugin_transport_http.h b/src/transport/plugin_transport_http.h
deleted file mode 100644
index a3b59513e..000000000
--- a/src/transport/plugin_transport_http.h
+++ /dev/null
@@ -1,579 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/plugin_transport_http.h
23 * @brief http transport service plugin
24 * @author Matthias Wachs
25 */
26#ifndef PLUGIN_TRANSPORT_HTTP_H
27#define PLUGIN_TRANSPORT_HTTP_H
28
29#include "platform.h"
30#include "gnunet_common.h"
31#include "gnunet_constants.h"
32#include "gnunet_protocols.h"
33#include "gnunet_connection_lib.h"
34#include "gnunet_service_lib.h"
35#include "gnunet_statistics_service.h"
36#include "gnunet_transport_service.h"
37#include "gnunet_resolver_service.h"
38#include "gnunet_server_lib.h"
39#include "gnunet_container_lib.h"
40#include "gnunet_transport_plugin.h"
41#include "gnunet_os_lib.h"
42#include "gnunet_nat_lib.h"
43#include "microhttpd.h"
44/* Just included for the right curl.h */
45#include "gnunet_curl_lib.h"
46
47
48#define DEBUG_HTTP GNUNET_EXTRA_LOGGING
49#define VERBOSE_SERVER GNUNET_EXTRA_LOGGING
50#define VERBOSE_CLIENT GNUNET_EXTRA_LOGGING
51#define VERBOSE_CURL GNUNET_NO
52
53#if BUILD_HTTPS
54#define LIBGNUNET_PLUGIN_TRANSPORT_INIT libgnunet_plugin_transport_https_init
55#define LIBGNUNET_PLUGIN_TRANSPORT_DONE libgnunet_plugin_transport_https_done
56#else
57#define LIBGNUNET_PLUGIN_TRANSPORT_INIT libgnunet_plugin_transport_http_init
58#define LIBGNUNET_PLUGIN_TRANSPORT_DONE libgnunet_plugin_transport_http_done
59#endif
60
61#define INBOUND GNUNET_YES
62#define OUTBOUND GNUNET_NO
63
64
65#define HTTP_NOT_VALIDATED_TIMEOUT GNUNET_TIME_relative_multiply ( \
66 GNUNET_TIME_UNIT_SECONDS, 15)
67
68/**
69 * Encapsulation of all of the state of the plugin.
70 */
71struct Plugin
72{
73 /**
74 * Our environment.
75 */
76 struct GNUNET_TRANSPORT_PluginEnvironment *env;
77
78 /**
79 * Head of linked list of open sessions.
80 */
81 struct GNUNET_ATS_Session *head;
82
83 /**
84 * Tail of linked list of open sessions.
85 */
86 struct GNUNET_ATS_Session *tail;
87
88 /**
89 * NAT handle & address management
90 */
91 struct GNUNET_NAT_Handle *nat;
92
93 /**
94 * Our own IPv4 addresses DLL head
95 */
96 struct HttpAddressWrapper *addr_head;
97
98 /**
99 * Our own IPv4 addresses DLL tail
100 */
101 struct HttpAddressWrapper *addr_tail;
102
103 /**
104 * External hostname the plugin can be connected to, can be different to
105 * the host's FQDN, used e.g. for reverse proxying
106 */
107 char *external_hostname;
108
109 /**
110 * External hostname the plugin can be connected to, can be different to
111 * the host's FQDN, used e.g. for reverse proxying
112 */
113 struct HttpAddress *ext_addr;
114
115 /**
116 * External address length
117 */
118 size_t ext_addr_len;
119
120 /**
121 * Task calling transport service about external address
122 */
123 struct GNUNET_SCHEDULER_Task *notify_ext_task;
124
125 /**
126 * Plugin name.
127 * Equals configuration section: transport-http, transport-https
128 */
129 char *name;
130
131 /**
132 * Plugin protocol
133 * http, https
134 */
135 char *protocol;
136
137 /**
138 * Use IPv4? #GNUNET_YES or #GNUNET_NO
139 */
140 int ipv4;
141
142 /**
143 * Use IPv6? #GNUNET_YES or #GNUNET_NO
144 */
145 int ipv6;
146
147 /**
148 * Does plugin just use outbound connections and not accept inbound?
149 */
150 int client_only;
151
152 /**
153 * Port used
154 */
155 uint16_t port;
156
157 /**
158 * Maximum number of sockets the plugin can use
159 * Each http inbound /outbound connections are two connections
160 */
161 int max_connections;
162
163 /**
164 * Number of outbound sessions
165 */
166 unsigned int outbound_sessions;
167
168 /**
169 * Number of inbound sessions
170 */
171 unsigned int inbound_sessions;
172
173 /**
174 * libCurl TLS crypto init string, can be set to enhance performance
175 *
176 * Example:
177 *
178 * Use RC4-128 instead of AES:
179 * NONE:+VERS-TLS1.0:+ARCFOUR-128:+SHA1:+RSA:+COMP-NULL
180 */
181 char *crypto_init;
182
183 /**
184 * TLS key
185 */
186 char *key;
187
188 /**
189 * TLS certificate
190 */
191 char *cert;
192
193 /**
194 * Current number of establishes connections
195 */
196 int cur_connections;
197
198 /**
199 * Last used unique HTTP connection tag
200 */
201 uint32_t last_tag;
202
203 /**
204 * MHD IPv4 daemon
205 */
206 struct MHD_Daemon *server_v4;
207
208 /**
209 * MHD IPv4 task
210 */
211 struct GNUNET_SCHEDULER_Task *server_v4_task;
212
213 /**
214 * The IPv4 server is scheduled to run asap
215 */
216 int server_v4_immediately;
217
218 /**
219 * MHD IPv6 daemon
220 */
221 struct MHD_Daemon *server_v6;
222
223 /**
224 * MHD IPv4 task
225 */
226 struct GNUNET_SCHEDULER_Task *server_v6_task;
227
228 /**
229 * The IPv6 server is scheduled to run asap
230 */
231 int server_v6_immediately;
232
233 /**
234 * IPv4 server socket to bind to
235 */
236 struct sockaddr_in *server_addr_v4;
237
238 /**
239 * IPv6 server socket to bind to
240 */
241 struct sockaddr_in6 *server_addr_v6;
242
243 /**
244 * Head of server semi connections
245 * A full session consists of 2 semi-connections: send and receive
246 * If not both directions are established the server keeps this sessions here
247 */
248 struct GNUNET_ATS_Session *server_semi_head;
249
250 /**
251 * Tail of server semi connections
252 * A full session consists of 2 semi-connections: send and receive
253 * If not both directions are established the server keeps this sessions here
254 */
255 struct GNUNET_ATS_Session *server_semi_tail;
256
257 /**
258 * cURL Multihandle
259 */
260 CURLM *client_mh;
261
262 /**
263 * curl perform task
264 */
265 struct GNUNET_SCHEDULER_Task *client_perform_task;
266};
267
268GNUNET_NETWORK_STRUCT_BEGIN
269
270/**
271 * HTTP addresses including a full URI
272 */
273struct HttpAddress
274{
275 /**
276 * Length of the address following in NBO
277 */
278 uint32_t addr_len GNUNET_PACKED;
279
280 /**
281 * Address following
282 */
283 void *addr GNUNET_PACKED;
284};
285
286/**
287 * IPv4 addresses
288 */
289struct IPv4HttpAddress
290{
291 /**
292 * IPv4 address, in network byte order.
293 */
294 uint32_t ipv4_addr GNUNET_PACKED;
295
296 /**
297 * Port number, in network byte order.
298 */
299 uint16_t u4_port GNUNET_PACKED;
300};
301
302/**
303 * IPv4 addresses
304 */
305struct IPv6HttpAddress
306{
307 /**
308 * IPv6 address.
309 */
310 struct in6_addr ipv6_addr GNUNET_PACKED;
311
312 /**
313 * Port number, in network byte order.
314 */
315 uint16_t u6_port GNUNET_PACKED;
316};
317GNUNET_NETWORK_STRUCT_END
318
319
320struct ServerRequest
321{
322 /**
323 * _RECV or _SEND
324 */
325 int direction;
326
327 /**
328 * Should this connection get disconnected? #GNUNET_YES / #GNUNET_NO
329 */
330 int disconnect;
331
332 /**
333 * The session this server connection belongs to
334 */
335 struct GNUNET_ATS_Session *session;
336
337 /**
338 * The MHD connection
339 */
340 struct MHD_Connection *mhd_conn;
341};
342
343
344/**
345 * Session handle for connections.
346 */
347struct GNUNET_ATS_Session
348{
349 /**
350 * To whom are we talking to
351 */
352 struct GNUNET_PeerIdentity target;
353
354 /**
355 * Stored in a linked list.
356 */
357 struct GNUNET_ATS_Session *next;
358
359 /**
360 * Stored in a linked list.
361 */
362 struct GNUNET_ATS_Session *prev;
363
364 /**
365 * Pointer to the global plugin struct.
366 */
367 struct Plugin *plugin;
368
369 /**
370 * Address
371 */
372 void *addr;
373
374 /**
375 * Address length
376 */
377 size_t addrlen;
378
379 /**
380 * ATS network type in NBO
381 */
382 uint32_t ats_address_network_type;
383
384 /**
385 * next pointer for double linked list
386 */
387 struct HTTP_Message *msg_head;
388
389 /**
390 * previous pointer for double linked list
391 */
392 struct HTTP_Message *msg_tail;
393
394 /**
395 * Message stream tokenizer for incoming data
396 */
397 struct GNUNET_SERVER_MessageStreamTokenizer *msg_tk;
398
399 /**
400 * Absolute time when to receive data again
401 * Used for receive throttling
402 */
403 struct GNUNET_TIME_Absolute next_receive;
404
405 /**
406 * Inbound or outbound connection
407 * Outbound: #GNUNET_NO (client is used to send and receive)
408 * Inbound : #GNUNET_YES (server is used to send and receive)
409 */
410 int inbound;
411
412 /**
413 * Unique HTTP/S connection tag for this connection
414 */
415 uint32_t tag;
416
417 /**
418 * Client send handle
419 */
420 void *client_put;
421
422 /**
423 * Client receive handle
424 */
425 void *client_get;
426
427 /**
428 * Task to wake up client receive handle when receiving is allowed again
429 */
430 struct GNUNET_SCHEDULER_Task *recv_wakeup_task;
431
432 /**
433 * Session timeout task
434 */
435 struct GNUNET_SCHEDULER_Task *timeout_task;
436
437 /**
438 * Is client send handle paused since there are no data to send?
439 * #GNUNET_YES or #GNUNET_NO
440 */
441 int client_put_paused;
442
443 /**
444 * Client send handle
445 */
446 struct ServerRequest *server_recv;
447
448 /**
449 * Client send handle
450 */
451 struct ServerRequest *server_send;
452};
453
454
455/**
456 * Message to send using http
457 */
458struct HTTP_Message
459{
460 /**
461 * next pointer for double linked list
462 */
463 struct HTTP_Message *next;
464
465 /**
466 * previous pointer for double linked list
467 */
468 struct HTTP_Message *prev;
469
470 /**
471 * buffer containing data to send
472 */
473 char *buf;
474
475 /**
476 * amount of data already sent
477 */
478 size_t pos;
479
480 /**
481 * buffer length
482 */
483 size_t size;
484
485 /**
486 * Continuation function to call once the transmission buffer
487 * has again space available. NULL if there is no
488 * continuation to call.
489 */
490 GNUNET_TRANSPORT_TransmitContinuation transmit_cont;
491
492 /**
493 * Closure for @e transmit_cont.
494 */
495 void *transmit_cont_cls;
496};
497
498
499struct GNUNET_ATS_Session *
500create_session (struct Plugin *plugin,
501 const struct GNUNET_PeerIdentity *target,
502 const void *addr,
503 size_t addrlen);
504
505
506int
507exist_session (struct Plugin *plugin,
508 struct GNUNET_ATS_Session *s);
509
510
511void
512delete_session (struct GNUNET_ATS_Session *s);
513
514
515int
516exist_session (struct Plugin *plugin,
517 struct GNUNET_ATS_Session *s);
518
519
520struct GNUNET_TIME_Relative
521http_plugin_receive (void *cls,
522 const struct GNUNET_PeerIdentity *peer,
523 const struct GNUNET_MessageHeader *message,
524 struct GNUNET_ATS_Session *session,
525 const char *sender_address,
526 uint16_t sender_address_len);
527
528
529const char *
530http_plugin_address_to_string (void *cls,
531 const void *addr,
532 size_t addrlen);
533
534
535int
536client_disconnect (struct GNUNET_ATS_Session *s);
537
538
539int
540client_connect (struct GNUNET_ATS_Session *s);
541
542
543int
544client_send (struct GNUNET_ATS_Session *s, struct HTTP_Message *msg);
545
546
547int
548client_start (struct Plugin *plugin);
549
550
551void
552client_stop (struct Plugin *plugin);
553
554
555int
556server_disconnect (struct GNUNET_ATS_Session *s);
557
558
559int
560server_send (struct GNUNET_ATS_Session *s, struct HTTP_Message *msg);
561
562
563int
564server_start (struct Plugin *plugin);
565
566
567void
568server_stop (struct Plugin *plugin);
569
570
571void
572notify_session_end (void *cls,
573 const struct GNUNET_PeerIdentity *peer,
574 struct GNUNET_ATS_Session *s);
575
576
577/*#ifndef PLUGIN_TRANSPORT_HTTP_H*/
578#endif
579/* end of plugin_transport_http.h */
diff --git a/src/transport/plugin_transport_http_client.c b/src/transport/plugin_transport_http_client.c
deleted file mode 100644
index 82468992b..000000000
--- a/src/transport/plugin_transport_http_client.c
+++ /dev/null
@@ -1,2523 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2002-2014 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/plugin_transport_http_client.c
23 * @brief HTTP/S client transport plugin
24 * @author Matthias Wachs
25 * @author Christian Grothoff
26 */
27
28#if BUILD_HTTPS
29#define PLUGIN_NAME "https_client"
30#define HTTP_STAT_STR_CONNECTIONS "# HTTPS client connections"
31#define LIBGNUNET_PLUGIN_TRANSPORT_INIT \
32 libgnunet_plugin_transport_https_client_init
33#define LIBGNUNET_PLUGIN_TRANSPORT_DONE \
34 libgnunet_plugin_transport_https_client_done
35#else
36#define PLUGIN_NAME "http_client"
37#define HTTP_STAT_STR_CONNECTIONS "# HTTP client connections"
38#define LIBGNUNET_PLUGIN_TRANSPORT_INIT \
39 libgnunet_plugin_transport_http_client_init
40#define LIBGNUNET_PLUGIN_TRANSPORT_DONE \
41 libgnunet_plugin_transport_http_client_done
42#endif
43
44#define VERBOSE_CURL GNUNET_NO
45
46#define PUT_DISCONNECT_TIMEOUT GNUNET_TIME_relative_multiply ( \
47 GNUNET_TIME_UNIT_SECONDS, 1)
48
49#define ENABLE_PUT GNUNET_YES
50#define ENABLE_GET GNUNET_YES
51
52#include "platform.h"
53#include "gnunet_util_lib.h"
54#include "gnunet_protocols.h"
55#include "gnunet_transport_plugin.h"
56#include "plugin_transport_http_common.h"
57/* Just included for the right curl.h */
58#include "gnunet_curl_lib.h"
59
60
61#define LOG(kind, ...) GNUNET_log_from (kind, PLUGIN_NAME, __VA_ARGS__)
62
63/**
64 * Encapsulation of all of the state of the plugin.
65 */
66struct HTTP_Client_Plugin;
67
68/**
69 * State of a HTTP PUT request
70 */
71enum HTTP_PUT_REQUEST_STATE
72{
73 /**
74 * Just created, not yet connected
75 */
76 H_NOT_CONNECTED,
77
78 /**
79 * Connected
80 */
81 H_CONNECTED,
82
83 /**
84 * Paused, nothing to send
85 */
86 H_PAUSED,
87
88 /**
89 * Temporary disconnect in progress due to inactivity
90 */
91 H_TMP_DISCONNECTING,
92
93 /**
94 * Send request while temporary disconnect, reconnect
95 */
96 H_TMP_RECONNECT_REQUIRED,
97
98 /**
99 * Temporarily disconnected
100 */
101 H_TMP_DISCONNECTED,
102
103 /**
104 * Disconnected
105 */
106 H_DISCONNECTED
107};
108
109/**
110 * Message to send using http
111 */
112struct HTTP_Message
113{
114 /**
115 * next pointer for double linked list
116 */
117 struct HTTP_Message *next;
118
119 /**
120 * previous pointer for double linked list
121 */
122 struct HTTP_Message *prev;
123
124 /**
125 * buffer containing data to send
126 */
127 char *buf;
128
129 /**
130 * Continuation function to call once the transmission buffer
131 * has again space available. NULL if there is no
132 * continuation to call.
133 */
134 GNUNET_TRANSPORT_TransmitContinuation transmit_cont;
135
136 /**
137 * Closure for @e transmit_cont.
138 */
139 void *transmit_cont_cls;
140
141 /**
142 * amount of data already sent
143 */
144 size_t pos;
145
146 /**
147 * buffer length
148 */
149 size_t size;
150};
151
152
153/**
154 * Session handle for HTTP(S) connections.
155 */
156struct GNUNET_ATS_Session;
157
158
159/**
160 * A request handle
161 *
162 */
163struct RequestHandle
164{
165 /**
166 * Current state of this request
167 */
168 enum HTTP_PUT_REQUEST_STATE state;
169
170 /**
171 * The curl easy handle
172 */
173 CURL *easyhandle;
174
175 /**
176 * The related session
177 */
178 struct GNUNET_ATS_Session *s;
179};
180
181
182/**
183 * Session handle for connections.
184 */
185struct GNUNET_ATS_Session
186{
187 /**
188 * The URL to connect to
189 */
190 char *url;
191
192 /**
193 * Address
194 */
195 struct GNUNET_HELLO_Address *address;
196
197 /**
198 * Pointer to the global plugin struct.
199 */
200 struct HTTP_Client_Plugin *plugin;
201
202 /**
203 * Handle for the HTTP PUT request.
204 */
205 struct RequestHandle put;
206
207 /**
208 * Handle for the HTTP GET request.
209 */
210 struct RequestHandle get;
211
212 /**
213 * next pointer for double linked list
214 */
215 struct HTTP_Message *msg_head;
216
217 /**
218 * previous pointer for double linked list
219 */
220 struct HTTP_Message *msg_tail;
221
222 /**
223 * Message stream tokenizer for incoming data
224 */
225 struct GNUNET_MessageStreamTokenizer *msg_tk;
226
227 /**
228 * Session timeout task
229 */
230 struct GNUNET_SCHEDULER_Task *put_disconnect_task;
231
232 /**
233 * Session timeout task
234 */
235 struct GNUNET_SCHEDULER_Task *timeout_task;
236
237 /**
238 * Task to wake up client receive handle when receiving is allowed again
239 */
240 struct GNUNET_SCHEDULER_Task *recv_wakeup_task;
241
242 /**
243 * Absolute time when to receive data again.
244 * Used for receive throttling.
245 */
246 struct GNUNET_TIME_Absolute next_receive;
247
248 /**
249 * When does this session time out.
250 */
251 struct GNUNET_TIME_Absolute timeout;
252
253 /**
254 * Number of bytes waiting for transmission to this peer.
255 */
256 unsigned long long bytes_in_queue;
257
258 /**
259 * Outbound overhead due to HTTP connection
260 * Add to next message of this session when calling callback
261 */
262 size_t overhead;
263
264 /**
265 * Number of messages waiting for transmission to this peer.
266 */
267 unsigned int msgs_in_queue;
268
269 /**
270 * ATS network type.
271 */
272 enum GNUNET_NetworkType scope;
273};
274
275
276/**
277 * Encapsulation of all of the state of the plugin.
278 */
279struct HTTP_Client_Plugin
280{
281 /**
282 * Our environment.
283 */
284 struct GNUNET_TRANSPORT_PluginEnvironment *env;
285
286 /**
287 * Open sessions.
288 */
289 struct GNUNET_CONTAINER_MultiPeerMap *sessions;
290
291 /**
292 * Function to call about session status changes.
293 */
294 GNUNET_TRANSPORT_SessionInfoCallback sic;
295
296 /**
297 * Closure for @e sic.
298 */
299 void *sic_cls;
300
301 /**
302 * Plugin name
303 */
304 char *name;
305
306 /**
307 * Protocol
308 */
309 char *protocol;
310
311 /**
312 * Proxy configuration: hostname or ip of the proxy server
313 */
314 char *proxy_hostname;
315
316 /**
317 * Username for the proxy server
318 */
319 char *proxy_username;
320
321 /**
322 * Password for the proxy server
323 */
324 char *proxy_password;
325
326 /**
327 * cURL Multihandle
328 */
329 CURLM *curl_multi_handle;
330
331 /**
332 * curl perform task
333 */
334 struct GNUNET_SCHEDULER_Task *client_perform_task;
335
336 /**
337 * Type of proxy server:
338 *
339 * Valid values as supported by curl:
340 * CURLPROXY_HTTP, CURLPROXY_HTTP_1_0 CURLPROXY_SOCKS4, CURLPROXY_SOCKS5,
341 * CURLPROXY_SOCKS4A, CURLPROXY_SOCKS5_HOSTNAME
342 */
343 curl_proxytype proxytype;
344
345 /**
346 * Use proxy tunneling:
347 * Tunnel all operations through a given HTTP instead of have the proxy
348 * evaluate the HTTP request
349 *
350 * Default: #GNUNET_NO, #GNUNET_YES experimental
351 */
352 int proxy_use_httpproxytunnel;
353
354 /**
355 * My options to be included in the address
356 */
357 uint32_t options;
358
359 /**
360 * Maximum number of sockets the plugin can use
361 * Each http connections are two requests
362 */
363 unsigned int max_requests;
364
365 /**
366 * Current number of sockets the plugin can use
367 * Each http connections are two requests
368 */
369 unsigned int cur_requests;
370
371 /**
372 * Last used unique HTTP connection tag
373 */
374 uint32_t last_tag;
375
376 /**
377 * use IPv6
378 */
379 uint16_t use_ipv6;
380
381 /**
382 * use IPv4
383 */
384 uint16_t use_ipv4;
385
386 /**
387 * Should we emulate an XHR client for testing?
388 */
389 int emulate_xhr;
390};
391
392
393/**
394 * Disconnect a session
395 *
396 * @param cls the `struct HTTP_Client_Plugin *`
397 * @param s session
398 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
399 */
400static int
401http_client_plugin_session_disconnect (void *cls, struct GNUNET_ATS_Session *s);
402
403
404/**
405 * If a session monitor is attached, notify it about the new
406 * session state.
407 *
408 * @param plugin our plugin
409 * @param session session that changed state
410 * @param state new state of the session
411 */
412static void
413notify_session_monitor (struct HTTP_Client_Plugin *plugin,
414 struct GNUNET_ATS_Session *session,
415 enum GNUNET_TRANSPORT_SessionState state)
416{
417 struct GNUNET_TRANSPORT_SessionInfo info;
418
419 if (NULL == plugin->sic)
420 return;
421 memset (&info, 0, sizeof(info));
422 info.state = state;
423 info.is_inbound = GNUNET_NO;
424 info.num_msg_pending = session->msgs_in_queue;
425 info.num_bytes_pending = session->bytes_in_queue;
426 info.receive_delay = session->next_receive;
427 info.session_timeout = session->timeout;
428 info.address = session->address;
429 plugin->sic (plugin->sic_cls,
430 session,
431 &info);
432}
433
434
435/**
436 * Delete session @a s.
437 *
438 * @param s the session to delete
439 */
440static void
441client_delete_session (struct GNUNET_ATS_Session *s)
442{
443 struct HTTP_Client_Plugin *plugin = s->plugin;
444 struct HTTP_Message *pos;
445 struct HTTP_Message *next;
446 CURLMcode mret;
447
448 if (NULL != s->timeout_task)
449 {
450 GNUNET_SCHEDULER_cancel (s->timeout_task);
451 s->timeout_task = NULL;
452 s->timeout = GNUNET_TIME_UNIT_ZERO_ABS;
453 }
454 if (NULL != s->put_disconnect_task)
455 {
456 GNUNET_SCHEDULER_cancel (s->put_disconnect_task);
457 s->put_disconnect_task = NULL;
458 }
459 if (NULL != s->recv_wakeup_task)
460 {
461 GNUNET_SCHEDULER_cancel (s->recv_wakeup_task);
462 s->recv_wakeup_task = NULL;
463 }
464 GNUNET_assert (GNUNET_OK ==
465 GNUNET_CONTAINER_multipeermap_remove (plugin->sessions,
466 &s->address->peer,
467 s));
468 if (NULL != s->put.easyhandle)
469 {
470 LOG (GNUNET_ERROR_TYPE_DEBUG,
471 "Session %p/request %p: disconnecting PUT request to peer `%s'\n",
472 s,
473 s->put.easyhandle,
474 GNUNET_i2s (&s->address->peer));
475
476 /* remove curl handle from multi handle */
477 mret = curl_multi_remove_handle (plugin->curl_multi_handle,
478 s->put.easyhandle);
479 GNUNET_break (CURLM_OK == mret);
480 curl_easy_cleanup (s->put.easyhandle);
481 GNUNET_assert (plugin->cur_requests > 0);
482 plugin->cur_requests--;
483 s->put.easyhandle = NULL;
484 }
485 if (NULL != s->get.easyhandle)
486 {
487 LOG (GNUNET_ERROR_TYPE_DEBUG,
488 "Session %p/request %p: disconnecting GET request to peer `%s'\n",
489 s, s->get.easyhandle,
490 GNUNET_i2s (&s->address->peer));
491 /* remove curl handle from multi handle */
492 mret = curl_multi_remove_handle (plugin->curl_multi_handle,
493 s->get.easyhandle);
494 GNUNET_break (CURLM_OK == mret);
495 curl_easy_cleanup (s->get.easyhandle);
496 GNUNET_assert (plugin->cur_requests > 0);
497 plugin->cur_requests--;
498 s->get.easyhandle = NULL;
499 }
500
501 GNUNET_STATISTICS_set (plugin->env->stats,
502 HTTP_STAT_STR_CONNECTIONS,
503 plugin->cur_requests,
504 GNUNET_NO);
505 next = s->msg_head;
506 while (NULL != (pos = next))
507 {
508 next = pos->next;
509 GNUNET_CONTAINER_DLL_remove (s->msg_head,
510 s->msg_tail,
511 pos);
512 GNUNET_assert (0 < s->msgs_in_queue);
513 s->msgs_in_queue--;
514 GNUNET_assert (pos->size <= s->bytes_in_queue);
515 s->bytes_in_queue -= pos->size;
516 if (NULL != pos->transmit_cont)
517 pos->transmit_cont (pos->transmit_cont_cls,
518 &s->address->peer,
519 GNUNET_SYSERR,
520 pos->size,
521 pos->pos + s->overhead);
522 s->overhead = 0;
523 GNUNET_free (pos);
524 }
525 GNUNET_assert (0 == s->msgs_in_queue);
526 GNUNET_assert (0 == s->bytes_in_queue);
527 notify_session_monitor (plugin,
528 s,
529 GNUNET_TRANSPORT_SS_DONE);
530 if (NULL != s->msg_tk)
531 {
532 GNUNET_MST_destroy (s->msg_tk);
533 s->msg_tk = NULL;
534 }
535 GNUNET_HELLO_address_free (s->address);
536 GNUNET_free (s->url);
537 GNUNET_free (s);
538}
539
540
541/**
542 * Increment session timeout due to activity for session @a s.
543 *
544 * @param s the session
545 */
546static void
547client_reschedule_session_timeout (struct GNUNET_ATS_Session *s)
548{
549 GNUNET_assert (NULL != s->timeout_task);
550 s->timeout = GNUNET_TIME_relative_to_absolute (
551 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
552}
553
554
555/**
556 * Task performing curl operations
557 *
558 * @param cls plugin as closure
559 */
560static void
561client_run (void *cls);
562
563
564/**
565 * Function setting up file descriptors and scheduling task to run
566 *
567 * @param plugin the plugin as closure
568 * @param now schedule task in 1ms, regardless of what curl may say
569 * @return #GNUNET_SYSERR for hard failure, #GNUNET_OK for ok
570 */
571static int
572client_schedule (struct HTTP_Client_Plugin *plugin,
573 int now)
574{
575 fd_set rs;
576 fd_set ws;
577 fd_set es;
578 int max;
579 struct GNUNET_NETWORK_FDSet *grs;
580 struct GNUNET_NETWORK_FDSet *gws;
581 long to;
582 CURLMcode mret;
583 struct GNUNET_TIME_Relative timeout;
584
585 /* Cancel previous scheduled task */
586 if (plugin->client_perform_task != NULL)
587 {
588 GNUNET_SCHEDULER_cancel (plugin->client_perform_task);
589 plugin->client_perform_task = NULL;
590 }
591 max = -1;
592 FD_ZERO (&rs);
593 FD_ZERO (&ws);
594 FD_ZERO (&es);
595 mret = curl_multi_fdset (plugin->curl_multi_handle, &rs, &ws, &es, &max);
596 if (mret != CURLM_OK)
597 {
598 LOG (GNUNET_ERROR_TYPE_ERROR,
599 _ ("%s failed at %s:%d: `%s'\n"),
600 "curl_multi_fdset",
601 __FILE__,
602 __LINE__,
603 curl_multi_strerror (mret));
604 return GNUNET_SYSERR;
605 }
606 mret = curl_multi_timeout (plugin->curl_multi_handle, &to);
607 if (-1 == to)
608 timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1);
609 else
610 timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, to);
611 if (now == GNUNET_YES)
612 timeout = GNUNET_TIME_UNIT_MILLISECONDS;
613
614 if (CURLM_OK != mret)
615 {
616 LOG (GNUNET_ERROR_TYPE_ERROR,
617 _ ("%s failed at %s:%d: `%s'\n"),
618 "curl_multi_timeout", __FILE__, __LINE__,
619 curl_multi_strerror (mret));
620 return GNUNET_SYSERR;
621 }
622
623 grs = GNUNET_NETWORK_fdset_create ();
624 gws = GNUNET_NETWORK_fdset_create ();
625 GNUNET_NETWORK_fdset_copy_native (grs, &rs, max + 1);
626 GNUNET_NETWORK_fdset_copy_native (gws, &ws, max + 1);
627
628 /* Schedule task to run when select is ready to read or write */
629 plugin->client_perform_task =
630 GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
631 timeout, grs, gws,
632 &client_run, plugin);
633 GNUNET_NETWORK_fdset_destroy (gws);
634 GNUNET_NETWORK_fdset_destroy (grs);
635 return GNUNET_OK;
636}
637
638
639#if VERBOSE_CURL
640/**
641 * Logging function
642 *
643 * @param curl the curl easy handle
644 * @param type message type
645 * @param data data to log, NOT a 0-terminated string
646 * @param size data length
647 * @param cls the closure
648 * @return always 0
649 */
650static int
651client_log (CURL *curl,
652 curl_infotype type,
653 const char *data,
654 size_t size,
655 void *cls)
656{
657 struct RequestHandle *ch = cls;
658 const char *ttype = "UNSPECIFIED";
659 char text[size + 2];
660
661 if (! ((CURLINFO_TEXT == type) ||
662 (CURLINFO_HEADER_IN == type) ||
663 (CURLINFO_HEADER_OUT == type)))
664 return 0;
665 switch (type)
666 {
667 case CURLINFO_TEXT:
668 ttype = "TEXT";
669 break;
670
671 case CURLINFO_HEADER_IN:
672 ttype = "HEADER_IN";
673 break;
674
675 case CURLINFO_HEADER_OUT:
676 ttype = "HEADER_OUT";
677 /* Overhead*/
678 GNUNET_assert (NULL != ch);
679 GNUNET_assert (NULL != ch->easyhandle);
680 GNUNET_assert (NULL != ch->s);
681 ch->s->overhead += size;
682 break;
683
684 default:
685 ttype = "UNSPECIFIED";
686 break;
687 }
688 GNUNET_memcpy (text, data, size);
689 if (text[size - 1] == '\n')
690 {
691 text[size] = '\0';
692 }
693 else
694 {
695 text[size] = '\n';
696 text[size + 1] = '\0';
697 }
698 LOG (GNUNET_ERROR_TYPE_DEBUG,
699 "Request %p %s: %s",
700 ch->easyhandle,
701 ttype,
702 text);
703 return 0;
704}
705
706
707#endif
708
709/**
710 * Connect GET request
711 *
712 * @param s the session to connect
713 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
714 */
715static int
716client_connect_get (struct GNUNET_ATS_Session *s);
717
718
719/**
720 * Connect a HTTP put request
721 *
722 * @param s the session to connect
723 * @return #GNUNET_SYSERR for hard failure, #GNUNET_OK for success
724 */
725static int
726client_connect_put (struct GNUNET_ATS_Session *s);
727
728
729/**
730 * Function that can be used by the transport service to transmit
731 * a message using the plugin. Note that in the case of a
732 * peer disconnecting, the continuation MUST be called
733 * prior to the disconnect notification itself. This function
734 * will be called with this peer's HELLO message to initiate
735 * a fresh connection to another peer.
736 *
737 * @param cls closure
738 * @param s which session must be used
739 * @param msgbuf the message to transmit
740 * @param msgbuf_size number of bytes in @a msgbuf
741 * @param priority how important is the message (most plugins will
742 * ignore message priority and just FIFO)
743 * @param to how long to wait at most for the transmission (does not
744 * require plugins to discard the message after the timeout,
745 * just advisory for the desired delay; most plugins will ignore
746 * this as well)
747 * @param cont continuation to call once the message has
748 * been transmitted (or if the transport is ready
749 * for the next transmission call; or if the
750 * peer disconnected...); can be NULL
751 * @param cont_cls closure for @a cont
752 * @return number of bytes used (on the physical network, with overheads);
753 * -1 on hard errors (i.e. address invalid); 0 is a legal value
754 * and does NOT mean that the message was not transmitted (DV)
755 */
756static ssize_t
757http_client_plugin_send (void *cls,
758 struct GNUNET_ATS_Session *s,
759 const char *msgbuf,
760 size_t msgbuf_size,
761 unsigned int priority,
762 struct GNUNET_TIME_Relative to,
763 GNUNET_TRANSPORT_TransmitContinuation cont,
764 void *cont_cls)
765{
766 struct HTTP_Client_Plugin *plugin = cls;
767 struct HTTP_Message *msg;
768 char *stat_txt;
769
770 LOG (GNUNET_ERROR_TYPE_DEBUG,
771 "Session %p/request %p: Sending message with %lu to peer `%s' \n",
772 s,
773 s->put.easyhandle,
774 (unsigned long) msgbuf_size,
775 GNUNET_i2s (&s->address->peer));
776
777 /* create new message and schedule */
778 msg = GNUNET_malloc (sizeof(struct HTTP_Message) + msgbuf_size);
779 msg->size = msgbuf_size;
780 msg->buf = (char *) &msg[1];
781 msg->transmit_cont = cont;
782 msg->transmit_cont_cls = cont_cls;
783 GNUNET_memcpy (msg->buf,
784 msgbuf,
785 msgbuf_size);
786 GNUNET_CONTAINER_DLL_insert_tail (s->msg_head,
787 s->msg_tail,
788 msg);
789 s->msgs_in_queue++;
790 s->bytes_in_queue += msg->size;
791
792 GNUNET_asprintf (&stat_txt,
793 "# bytes currently in %s_client buffers",
794 plugin->protocol);
795 GNUNET_STATISTICS_update (plugin->env->stats,
796 stat_txt, msgbuf_size, GNUNET_NO);
797 GNUNET_free (stat_txt);
798 notify_session_monitor (plugin,
799 s,
800 GNUNET_TRANSPORT_SS_UPDATE);
801 if (H_TMP_DISCONNECTING == s->put.state)
802 {
803 /* PUT request is currently getting disconnected */
804 s->put.state = H_TMP_RECONNECT_REQUIRED;
805 LOG (GNUNET_ERROR_TYPE_DEBUG,
806 "Session %p/request %p: currently disconnecting, reconnecting immediately\n",
807 s,
808 s->put.easyhandle);
809 return msgbuf_size;
810 }
811 if (H_PAUSED == s->put.state)
812 {
813 /* PUT request was paused, unpause */
814 GNUNET_assert (s->put_disconnect_task != NULL);
815 GNUNET_SCHEDULER_cancel (s->put_disconnect_task);
816 s->put_disconnect_task = NULL;
817 LOG (GNUNET_ERROR_TYPE_DEBUG,
818 "Session %p/request %p: unpausing request\n",
819 s, s->put.easyhandle);
820 s->put.state = H_CONNECTED;
821 if (NULL != s->put.easyhandle)
822 curl_easy_pause (s->put.easyhandle, CURLPAUSE_CONT);
823 }
824 else if (H_TMP_DISCONNECTED == s->put.state)
825 {
826 /* PUT request was disconnected, reconnect */
827 LOG (GNUNET_ERROR_TYPE_DEBUG, "Session %p: Reconnecting PUT request\n", s);
828 GNUNET_break (NULL == s->put.easyhandle);
829 if (GNUNET_SYSERR == client_connect_put (s))
830 {
831 /* Could not reconnect */
832 http_client_plugin_session_disconnect (plugin, s);
833 return GNUNET_SYSERR;
834 }
835 }
836 client_schedule (s->plugin, GNUNET_YES);
837 return msgbuf_size;
838}
839
840
841/**
842 * Disconnect a session
843 *
844 * @param cls the `struct HTTP_Client_Plugin *`
845 * @param s session
846 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
847 */
848static int
849http_client_plugin_session_disconnect (void *cls,
850 struct GNUNET_ATS_Session *s)
851{
852 struct HTTP_Client_Plugin *plugin = cls;
853
854 LOG (GNUNET_ERROR_TYPE_DEBUG,
855 "Session %p: notifying transport about ending session\n",
856 s);
857 plugin->env->session_end (plugin->env->cls,
858 s->address,
859 s);
860 client_delete_session (s);
861
862 /* Re-schedule since handles have changed */
863 if (NULL != plugin->client_perform_task)
864 {
865 GNUNET_SCHEDULER_cancel (plugin->client_perform_task);
866 plugin->client_perform_task = NULL;
867 }
868 client_schedule (plugin, GNUNET_YES);
869
870 return GNUNET_OK;
871}
872
873
874/**
875 * Function that is called to get the keepalive factor.
876 * #GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT is divided by this number to
877 * calculate the interval between keepalive packets.
878 *
879 * @param cls closure with the `struct Plugin`
880 * @return keepalive factor
881 */
882static unsigned int
883http_client_query_keepalive_factor (void *cls)
884{
885 return 3;
886}
887
888
889/**
890 * Callback to destroys all sessions on exit.
891 *
892 * @param cls the `struct HTTP_Client_Plugin *`
893 * @param peer identity of the peer
894 * @param value the `struct GNUNET_ATS_Session *`
895 * @return #GNUNET_OK (continue iterating)
896 */
897static int
898destroy_session_cb (void *cls,
899 const struct GNUNET_PeerIdentity *peer,
900 void *value)
901{
902 struct HTTP_Client_Plugin *plugin = cls;
903 struct GNUNET_ATS_Session *session = value;
904
905 http_client_plugin_session_disconnect (plugin, session);
906 return GNUNET_OK;
907}
908
909
910/**
911 * Function that can be used to force the plugin to disconnect
912 * from the given peer and cancel all previous transmissions
913 * (and their continuationc).
914 *
915 * @param cls closure
916 * @param target peer from which to disconnect
917 */
918static void
919http_client_plugin_peer_disconnect (void *cls,
920 const struct GNUNET_PeerIdentity *target)
921{
922 struct HTTP_Client_Plugin *plugin = cls;
923
924 LOG (GNUNET_ERROR_TYPE_DEBUG,
925 "Transport tells me to disconnect `%s'\n",
926 GNUNET_i2s (target));
927 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessions,
928 target,
929 &destroy_session_cb,
930 plugin);
931}
932
933
934/**
935 * Closure for #session_lookup_client_by_address().
936 */
937struct GNUNET_ATS_SessionClientCtx
938{
939 /**
940 * Address we are looking for.
941 */
942 const struct GNUNET_HELLO_Address *address;
943
944 /**
945 * Session that was found.
946 */
947 struct GNUNET_ATS_Session *ret;
948};
949
950
951/**
952 * Locate the seession object for a given address.
953 *
954 * @param cls the `struct GNUNET_ATS_SessionClientCtx *`
955 * @param key peer identity
956 * @param value the `struct GNUNET_ATS_Session` to check
957 * @return #GNUNET_NO if found, #GNUNET_OK if not
958 */
959static int
960session_lookup_client_by_address (void *cls,
961 const struct GNUNET_PeerIdentity *key,
962 void *value)
963{
964 struct GNUNET_ATS_SessionClientCtx *sc_ctx = cls;
965 struct GNUNET_ATS_Session *s = value;
966
967 if (0 == GNUNET_HELLO_address_cmp (sc_ctx->address,
968 s->address))
969 {
970 sc_ctx->ret = s;
971 return GNUNET_NO;
972 }
973 return GNUNET_YES;
974}
975
976
977/**
978 * Check if a sessions exists for an specific address
979 *
980 * @param plugin the plugin
981 * @param address the address
982 * @return the session or NULL
983 */
984static struct GNUNET_ATS_Session *
985client_lookup_session (struct HTTP_Client_Plugin *plugin,
986 const struct GNUNET_HELLO_Address *address)
987{
988 struct GNUNET_ATS_SessionClientCtx sc_ctx;
989
990 sc_ctx.address = address;
991 sc_ctx.ret = NULL;
992 GNUNET_CONTAINER_multipeermap_iterate (plugin->sessions,
993 &session_lookup_client_by_address,
994 &sc_ctx);
995 return sc_ctx.ret;
996}
997
998
999/**
1000 * When we have nothing to transmit, we pause the HTTP PUT
1001 * after a while (so that gnurl stops asking). This task
1002 * is the delayed task that actually disconnects the PUT.
1003 *
1004 * @param cls the `struct GNUNET_ATS_Session *` with the put
1005 */
1006static void
1007client_put_disconnect (void *cls)
1008{
1009 struct GNUNET_ATS_Session *s = cls;
1010
1011 s->put_disconnect_task = NULL;
1012 LOG (GNUNET_ERROR_TYPE_DEBUG,
1013 "Session %p/request %p: will be disconnected due to no activity\n",
1014 s, s->put.easyhandle);
1015 s->put.state = H_TMP_DISCONNECTING;
1016 if (NULL != s->put.easyhandle)
1017 curl_easy_pause (s->put.easyhandle,
1018 CURLPAUSE_CONT);
1019 client_schedule (s->plugin, GNUNET_YES);
1020}
1021
1022
1023/**
1024 * Callback method used with libcurl
1025 * Method is called when libcurl needs to read data during sending
1026 *
1027 * @param stream pointer where to write data
1028 * @param size size of an individual element
1029 * @param nmemb count of elements that can be written to the buffer
1030 * @param cls our `struct GNUNET_ATS_Session`
1031 * @return bytes written to stream, returning 0 will terminate request!
1032 */
1033static size_t
1034client_send_cb (void *stream,
1035 size_t size,
1036 size_t nmemb,
1037 void *cls)
1038{
1039 struct GNUNET_ATS_Session *s = cls;
1040 struct HTTP_Client_Plugin *plugin = s->plugin;
1041 struct HTTP_Message *msg = s->msg_head;
1042 size_t len;
1043 char *stat_txt;
1044
1045 if (H_TMP_DISCONNECTING == s->put.state)
1046 {
1047 LOG (GNUNET_ERROR_TYPE_DEBUG,
1048 "Session %p/request %p: disconnect due to inactivity\n",
1049 s, s->put.easyhandle);
1050 return 0;
1051 }
1052
1053 if (NULL == msg)
1054 {
1055 if (GNUNET_YES == plugin->emulate_xhr)
1056 {
1057 LOG (GNUNET_ERROR_TYPE_DEBUG,
1058 "Session %p/request %p: PUT request finished\n",
1059 s,
1060 s->put.easyhandle);
1061 s->put.state = H_TMP_DISCONNECTING;
1062 return 0;
1063 }
1064
1065 /* We have nothing to send, so pause PUT request */
1066 LOG (GNUNET_ERROR_TYPE_DEBUG,
1067 "Session %p/request %p: nothing to send, suspending\n",
1068 s,
1069 s->put.easyhandle);
1070 s->put_disconnect_task
1071 = GNUNET_SCHEDULER_add_delayed (PUT_DISCONNECT_TIMEOUT,
1072 &client_put_disconnect,
1073 s);
1074 s->put.state = H_PAUSED;
1075 return CURL_READFUNC_PAUSE;
1076 }
1077 /* data to send */
1078 GNUNET_assert (msg->pos < msg->size);
1079 /* calculate how much fits in buffer */
1080 len = GNUNET_MIN (msg->size - msg->pos,
1081 size * nmemb);
1082 GNUNET_memcpy (stream,
1083 &msg->buf[msg->pos],
1084 len);
1085 msg->pos += len;
1086 if (msg->pos == msg->size)
1087 {
1088 LOG (GNUNET_ERROR_TYPE_DEBUG,
1089 "Session %p/request %p: sent message with %lu bytes sent, removing message from queue\n",
1090 s,
1091 s->put.easyhandle,
1092 (unsigned long) msg->size);
1093 /* Calling transmit continuation */
1094 GNUNET_CONTAINER_DLL_remove (s->msg_head,
1095 s->msg_tail,
1096 msg);
1097 GNUNET_assert (0 < s->msgs_in_queue);
1098 s->msgs_in_queue--;
1099 GNUNET_assert (msg->size <= s->bytes_in_queue);
1100 s->bytes_in_queue -= msg->size;
1101 if (NULL != msg->transmit_cont)
1102 msg->transmit_cont (msg->transmit_cont_cls,
1103 &s->address->peer,
1104 GNUNET_OK,
1105 msg->size,
1106 msg->size + s->overhead);
1107 s->overhead = 0;
1108 GNUNET_free (msg);
1109 }
1110 notify_session_monitor (plugin,
1111 s,
1112 GNUNET_TRANSPORT_SS_UPDATE);
1113 GNUNET_asprintf (&stat_txt,
1114 "# bytes currently in %s_client buffers",
1115 plugin->protocol);
1116 GNUNET_STATISTICS_update (plugin->env->stats,
1117 stat_txt,
1118 -len,
1119 GNUNET_NO);
1120 GNUNET_free (stat_txt);
1121 GNUNET_asprintf (&stat_txt,
1122 "# bytes transmitted via %s_client",
1123 plugin->protocol);
1124 GNUNET_STATISTICS_update (plugin->env->stats,
1125 stat_txt,
1126 len,
1127 GNUNET_NO);
1128 GNUNET_free (stat_txt);
1129 return len;
1130}
1131
1132
1133/**
1134 * Wake up a curl handle which was suspended
1135 *
1136 * @param cls the session
1137 */
1138static void
1139client_wake_up (void *cls)
1140{
1141 struct GNUNET_ATS_Session *s = cls;
1142
1143 s->recv_wakeup_task = NULL;
1144 LOG (GNUNET_ERROR_TYPE_DEBUG,
1145 "Session %p/request %p: Waking up GET handle\n",
1146 s, s->get.easyhandle);
1147 if (H_PAUSED == s->put.state)
1148 {
1149 /* PUT request was paused, unpause */
1150 GNUNET_assert (s->put_disconnect_task != NULL);
1151 GNUNET_SCHEDULER_cancel (s->put_disconnect_task);
1152 s->put_disconnect_task = NULL;
1153 s->put.state = H_CONNECTED;
1154 if (NULL != s->put.easyhandle)
1155 curl_easy_pause (s->put.easyhandle, CURLPAUSE_CONT);
1156 }
1157 if (NULL != s->get.easyhandle)
1158 curl_easy_pause (s->get.easyhandle, CURLPAUSE_CONT);
1159}
1160
1161
1162/**
1163 * Callback for message stream tokenizer
1164 *
1165 * @param cls the session
1166 * @param message the message received
1167 * @return always #GNUNET_OK
1168 */
1169static int
1170client_receive_mst_cb (void *cls,
1171 const struct GNUNET_MessageHeader *message)
1172{
1173 struct GNUNET_ATS_Session *s = cls;
1174 struct HTTP_Client_Plugin *plugin;
1175 struct GNUNET_TIME_Relative delay;
1176 char *stat_txt;
1177
1178 plugin = s->plugin;
1179 delay = s->plugin->env->receive (plugin->env->cls,
1180 s->address,
1181 s,
1182 message);
1183 GNUNET_asprintf (&stat_txt,
1184 "# bytes received via %s_client",
1185 plugin->protocol);
1186 GNUNET_STATISTICS_update (plugin->env->stats,
1187 stat_txt,
1188 ntohs (message->size),
1189 GNUNET_NO);
1190 GNUNET_free (stat_txt);
1191
1192 s->next_receive = GNUNET_TIME_relative_to_absolute (delay);
1193 if (GNUNET_TIME_absolute_get ().abs_value_us < s->next_receive.abs_value_us)
1194 {
1195 LOG (GNUNET_ERROR_TYPE_DEBUG,
1196 "Client: peer `%s' address `%s' next read delayed for %s\n",
1197 GNUNET_i2s (&s->address->peer),
1198 http_common_plugin_address_to_string (s->plugin->protocol,
1199 s->address->address,
1200 s->address->address_length),
1201 GNUNET_STRINGS_relative_time_to_string (delay,
1202 GNUNET_YES));
1203 }
1204 client_reschedule_session_timeout (s);
1205 return GNUNET_OK;
1206}
1207
1208
1209/**
1210 * Callback method used with libcurl when data for a PUT request are
1211 * received. We do not expect data here, so we just discard it.
1212 *
1213 * @param stream pointer where to write data
1214 * @param size size of an individual element
1215 * @param nmemb count of elements that can be written to the buffer
1216 * @param cls destination pointer, passed to the libcurl handle
1217 * @return bytes read from stream
1218 */
1219static size_t
1220client_receive_put (void *stream,
1221 size_t size,
1222 size_t nmemb,
1223 void *cls)
1224{
1225 return size * nmemb;
1226}
1227
1228
1229/**
1230 * Callback method used with libcurl when data for a GET request are
1231 * received. Forward to MST
1232 *
1233 * @param stream pointer where to write data
1234 * @param size size of an individual element
1235 * @param nmemb count of elements that can be written to the buffer
1236 * @param cls destination pointer, passed to the libcurl handle
1237 * @return bytes read from stream
1238 */
1239static size_t
1240client_receive (void *stream,
1241 size_t size,
1242 size_t nmemb,
1243 void *cls)
1244{
1245 struct GNUNET_ATS_Session *s = cls;
1246 struct GNUNET_TIME_Absolute now;
1247 size_t len = size * nmemb;
1248
1249 LOG (GNUNET_ERROR_TYPE_DEBUG,
1250 "Session %p / request %p: Received %lu bytes from peer `%s'\n",
1251 s,
1252 s->get.easyhandle,
1253 (unsigned long) len,
1254 GNUNET_i2s (&s->address->peer));
1255 now = GNUNET_TIME_absolute_get ();
1256 if (now.abs_value_us < s->next_receive.abs_value_us)
1257 {
1258 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1259 struct GNUNET_TIME_Relative delta
1260 = GNUNET_TIME_absolute_get_difference (now, s->next_receive);
1261
1262 LOG (GNUNET_ERROR_TYPE_DEBUG,
1263 "Session %p / request %p: No inbound bandwidth available! Next read was delayed for %s\n",
1264 s,
1265 s->get.easyhandle,
1266 GNUNET_STRINGS_relative_time_to_string (delta,
1267 GNUNET_YES));
1268 if (s->recv_wakeup_task != NULL)
1269 {
1270 GNUNET_SCHEDULER_cancel (s->recv_wakeup_task);
1271 s->recv_wakeup_task = NULL;
1272 }
1273 s->recv_wakeup_task
1274 = GNUNET_SCHEDULER_add_delayed (delta,
1275 &client_wake_up,
1276 s);
1277 return CURL_WRITEFUNC_PAUSE;
1278 }
1279 if (NULL == s->msg_tk)
1280 s->msg_tk = GNUNET_MST_create (&client_receive_mst_cb,
1281 s);
1282 GNUNET_MST_from_buffer (s->msg_tk,
1283 stream,
1284 len,
1285 GNUNET_NO,
1286 GNUNET_NO);
1287 return len;
1288}
1289
1290
1291static void
1292client_run (void *cls)
1293{
1294 struct HTTP_Client_Plugin *plugin = cls;
1295 int running;
1296 long http_statuscode;
1297 CURLMcode mret;
1298 CURLMsg *msg;
1299 int put_request; /* GNUNET_YES if easy handle is put, GNUNET_NO for get */
1300 int msgs_left;
1301
1302 plugin->client_perform_task = NULL;
1303 /* While data are available or timeouts occurred */
1304 do
1305 {
1306 running = 0;
1307 /* Perform operations for all handles */
1308 mret = curl_multi_perform (plugin->curl_multi_handle, &running);
1309
1310 /* Get additional information for all handles */
1311 while (NULL != (msg = curl_multi_info_read (plugin->curl_multi_handle,
1312 &msgs_left)))
1313 {
1314 CURL *easy_h = msg->easy_handle;
1315 struct GNUNET_ATS_Session *s = NULL;
1316 char *d = NULL; /* curl requires 'd' to be a 'char *' */
1317
1318 GNUNET_assert (NULL != easy_h);
1319
1320 /* Obtain session from easy handle */
1321 GNUNET_assert (CURLE_OK == curl_easy_getinfo (easy_h, CURLINFO_PRIVATE,
1322 &d));
1323 s = (struct GNUNET_ATS_Session *) d;
1324 GNUNET_assert (NULL != s);
1325
1326 if (msg->msg != CURLMSG_DONE)
1327 continue; /* This should not happen */
1328
1329 /* Get HTTP response code */
1330 GNUNET_break (CURLE_OK == curl_easy_getinfo (easy_h,
1331 CURLINFO_RESPONSE_CODE,
1332 &http_statuscode));
1333
1334 if (easy_h == s->put.easyhandle)
1335 put_request = GNUNET_YES;
1336 else
1337 put_request = GNUNET_NO;
1338
1339 /* Log status of terminated request */
1340 if ((0 != msg->data.result) || (http_statuscode != 200))
1341 LOG (GNUNET_ERROR_TYPE_DEBUG,
1342 "Session %p/request %p: %s request to `%s' ended with status %li reason %i: `%s'\n",
1343 s, msg->easy_handle,
1344 (GNUNET_YES == put_request) ? "PUT" : "GET",
1345 GNUNET_i2s (&s->address->peer),
1346 http_statuscode,
1347 msg->data.result,
1348 curl_easy_strerror (msg->data.result));
1349 else
1350 LOG (GNUNET_ERROR_TYPE_DEBUG,
1351 "Session %p/request %p: %s request to `%s' ended normal\n",
1352 s, msg->easy_handle,
1353 (GNUNET_YES == put_request) ? "PUT" : "GET",
1354 GNUNET_i2s (&s->address->peer));
1355
1356 /* Remove easy handle from multi handle */
1357 curl_multi_remove_handle (plugin->curl_multi_handle, easy_h);
1358
1359 /* Clean up easy handle */
1360 curl_easy_cleanup (easy_h);
1361
1362 /* Remove information */
1363 GNUNET_assert (plugin->cur_requests > 0);
1364 plugin->cur_requests--;
1365 LOG (GNUNET_ERROR_TYPE_INFO,
1366 "%s request to %s done, number of requests decreased to %u\n",
1367 (GNUNET_YES == put_request) ? "PUT" : "GET",
1368 s->url,
1369 plugin->cur_requests);
1370
1371 if (GNUNET_YES == put_request)
1372 {
1373 /* Clean up a PUT request */
1374 s->put.easyhandle = NULL;
1375 s->put.s = NULL;
1376
1377 switch (s->put.state)
1378 {
1379 case H_NOT_CONNECTED:
1380 case H_DISCONNECTED:
1381 case H_TMP_DISCONNECTED:
1382 /* This must not happen */
1383 GNUNET_break (0);
1384 break;
1385
1386 case H_TMP_RECONNECT_REQUIRED:
1387 /* Transport called send while disconnect in progress, reconnect */
1388 if (GNUNET_SYSERR == client_connect_put (s))
1389 {
1390 /* Reconnect failed, disconnect session */
1391 http_client_plugin_session_disconnect (plugin, s);
1392 }
1393 break;
1394
1395 case H_TMP_DISCONNECTING:
1396 /* PUT gets temporarily disconnected */
1397 s->put.state = H_TMP_DISCONNECTED;
1398 break;
1399
1400 case H_PAUSED:
1401 case H_CONNECTED:
1402 /* PUT gets permanently disconnected */
1403 s->put.state = H_DISCONNECTED;
1404 http_client_plugin_session_disconnect (plugin, s);
1405 break;
1406
1407 default:
1408 GNUNET_break (0);
1409 break;
1410 }
1411 }
1412 else if (GNUNET_NO == put_request)
1413 {
1414 /* Clean up a GET request */
1415 s->get.easyhandle = NULL;
1416 s->get.s = NULL;
1417
1418 /* If we are emulating an XHR client we need to make another GET
1419 * request.
1420 */
1421 if (GNUNET_YES == plugin->emulate_xhr)
1422 {
1423 if (GNUNET_SYSERR == client_connect_get (s))
1424 http_client_plugin_session_disconnect (plugin, s);
1425 }
1426 else
1427 {
1428 /* GET request was terminated, so disconnect session */
1429 http_client_plugin_session_disconnect (plugin, s);
1430 }
1431 }
1432 else
1433 GNUNET_break (0); /* Must not happen */
1434
1435 GNUNET_STATISTICS_set (plugin->env->stats,
1436 HTTP_STAT_STR_CONNECTIONS,
1437 plugin->cur_requests,
1438 GNUNET_NO);
1439 }
1440 }
1441 while (mret == CURLM_CALL_MULTI_PERFORM);
1442 client_schedule (plugin, GNUNET_NO);
1443}
1444
1445
1446#ifdef TCP_STEALTH
1447/**
1448 * Open TCP socket with TCP STEALTH enabled.
1449 *
1450 * @param clientp our `struct GNUNET_ATS_Session *`
1451 * @param purpose why does curl want to open a socket
1452 * @param address what kind of socket does curl want to have opened?
1453 * @return opened socket
1454 */
1455static curl_socket_t
1456open_tcp_stealth_socket_cb (void *clientp,
1457 curlsocktype purpose,
1458 struct curl_sockaddr *address)
1459{
1460 struct GNUNET_ATS_Session *s = clientp;
1461 int ret;
1462
1463 switch (purpose)
1464 {
1465 case CURLSOCKTYPE_IPCXN:
1466 ret = socket (address->family,
1467 address->socktype,
1468 address->protocol);
1469 if (-1 == ret)
1470 return CURL_SOCKET_BAD;
1471 if (((SOCK_STREAM != address->socktype) ||
1472 ((0 != address->protocol) &&
1473 (IPPROTO_TCP != address->protocol))))
1474 return (curl_socket_t) ret;
1475 if ((0 != setsockopt (ret,
1476 IPPROTO_TCP,
1477 TCP_STEALTH,
1478 &s->address->peer,
1479 sizeof(struct GNUNET_PeerIdentity))))
1480 {
1481 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1482 _ ("TCP_STEALTH not supported on this platform.\n"));
1483 (void) close (ret);
1484 return CURL_SOCKET_BAD;
1485 }
1486 return (curl_socket_t) ret;
1487
1488 case CURLSOCKTYPE_ACCEPT:
1489 GNUNET_break (0);
1490 return CURL_SOCKET_BAD;
1491 break;
1492
1493 case CURLSOCKTYPE_LAST:
1494 GNUNET_break (0);
1495 return CURL_SOCKET_BAD;
1496
1497 default:
1498 GNUNET_break (0);
1499 return CURL_SOCKET_BAD;
1500 }
1501}
1502
1503
1504#endif
1505
1506
1507/**
1508 * Connect GET request for a session
1509 *
1510 * @param s the session to connect
1511 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
1512 */
1513static int
1514client_connect_get (struct GNUNET_ATS_Session *s)
1515{
1516 CURLMcode mret;
1517 struct HttpAddress *ha;
1518 uint32_t options;
1519
1520 ha = (struct HttpAddress *) s->address->address;
1521 options = ntohl (ha->options);
1522 /* create get request */
1523 s->get.easyhandle = curl_easy_init ();
1524 s->get.s = s;
1525 if (0 != (options & HTTP_OPTIONS_TCP_STEALTH))
1526 {
1527#ifdef TCP_STEALTH
1528 curl_easy_setopt (s->get.easyhandle,
1529 CURLOPT_OPENSOCKETFUNCTION,
1530 &open_tcp_stealth_socket_cb);
1531 curl_easy_setopt (s->get.easyhandle,
1532 CURLOPT_OPENSOCKETDATA,
1533 s);
1534#else
1535 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1536 "Cannot connect, TCP STEALTH needed and not supported by kernel.\n");
1537 curl_easy_cleanup (s->get.easyhandle);
1538 s->get.easyhandle = NULL;
1539 s->get.s = NULL;
1540 return GNUNET_SYSERR;
1541#endif
1542 }
1543
1544#if VERBOSE_CURL
1545 curl_easy_setopt (s->get.easyhandle,
1546 CURLOPT_VERBOSE,
1547 1L);
1548 curl_easy_setopt (s->get.easyhandle,
1549 CURLOPT_DEBUGFUNCTION,
1550 &client_log);
1551 curl_easy_setopt (s->get.easyhandle,
1552 CURLOPT_DEBUGDATA,
1553 &s->get);
1554#endif
1555#if BUILD_HTTPS
1556 curl_easy_setopt (s->get.easyhandle, CURLOPT_SSLVERSION,
1557 CURL_SSLVERSION_TLSv1);
1558 {
1559 if (HTTP_OPTIONS_VERIFY_CERTIFICATE ==
1560 (options & HTTP_OPTIONS_VERIFY_CERTIFICATE))
1561 {
1562 curl_easy_setopt (s->get.easyhandle,
1563 CURLOPT_SSL_VERIFYPEER, 1L);
1564 curl_easy_setopt (s->get.easyhandle,
1565 CURLOPT_SSL_VERIFYHOST,
1566 2L);
1567 }
1568 else
1569 {
1570 curl_easy_setopt (s->get.easyhandle,
1571 CURLOPT_SSL_VERIFYPEER,
1572 0L);
1573 curl_easy_setopt (s->get.easyhandle,
1574 CURLOPT_SSL_VERIFYHOST,
1575 0L);
1576 }
1577 }
1578 curl_easy_setopt (s->get.easyhandle,
1579 CURLOPT_PROTOCOLS,
1580 CURLPROTO_HTTPS);
1581 curl_easy_setopt (s->get.easyhandle,
1582 CURLOPT_REDIR_PROTOCOLS,
1583 CURLPROTO_HTTPS);
1584#else
1585 curl_easy_setopt (s->get.easyhandle,
1586 CURLOPT_PROTOCOLS,
1587 CURLPROTO_HTTP);
1588 curl_easy_setopt (s->get.easyhandle,
1589 CURLOPT_REDIR_PROTOCOLS,
1590 CURLPROTO_HTTP);
1591#endif
1592
1593 if (NULL != s->plugin->proxy_hostname)
1594 {
1595 curl_easy_setopt (s->get.easyhandle,
1596 CURLOPT_PROXY,
1597 s->plugin->proxy_hostname);
1598 curl_easy_setopt (s->get.easyhandle,
1599 CURLOPT_PROXYTYPE,
1600 s->plugin->proxytype);
1601 if (NULL != s->plugin->proxy_username)
1602 curl_easy_setopt (s->get.easyhandle,
1603 CURLOPT_PROXYUSERNAME,
1604 s->plugin->proxy_username);
1605 if (NULL != s->plugin->proxy_password)
1606 curl_easy_setopt (s->get.easyhandle,
1607 CURLOPT_PROXYPASSWORD,
1608 s->plugin->proxy_password);
1609 if (GNUNET_YES == s->plugin->proxy_use_httpproxytunnel)
1610 curl_easy_setopt (s->get.easyhandle,
1611 CURLOPT_HTTPPROXYTUNNEL,
1612 s->plugin->proxy_use_httpproxytunnel);
1613 }
1614
1615 if (GNUNET_YES == s->plugin->emulate_xhr)
1616 {
1617 char *url;
1618
1619 GNUNET_asprintf (&url,
1620 "%s,1",
1621 s->url);
1622 curl_easy_setopt (s->get.easyhandle,
1623 CURLOPT_URL,
1624 url);
1625 GNUNET_free (url);
1626 }
1627 else
1628 {
1629 curl_easy_setopt (s->get.easyhandle,
1630 CURLOPT_URL,
1631 s->url);
1632 }
1633 curl_easy_setopt (s->get.easyhandle,
1634 CURLOPT_READFUNCTION,
1635 &client_send_cb);
1636 curl_easy_setopt (s->get.easyhandle,
1637 CURLOPT_READDATA,
1638 s);
1639 curl_easy_setopt (s->get.easyhandle,
1640 CURLOPT_WRITEFUNCTION,
1641 &client_receive);
1642 curl_easy_setopt (s->get.easyhandle,
1643 CURLOPT_WRITEDATA,
1644 s);
1645 /* No timeout by default, timeout done with session timeout */
1646 curl_easy_setopt (s->get.easyhandle,
1647 CURLOPT_TIMEOUT,
1648 0L);
1649 curl_easy_setopt (s->get.easyhandle,
1650 CURLOPT_PRIVATE, s);
1651 curl_easy_setopt (s->get.easyhandle,
1652 CURLOPT_CONNECTTIMEOUT_MS,
1653 (long) (HTTP_CLIENT_NOT_VALIDATED_TIMEOUT.rel_value_us
1654 / 1000LL));
1655 curl_easy_setopt (s->get.easyhandle, CURLOPT_BUFFERSIZE,
1656 2 * GNUNET_MAX_MESSAGE_SIZE);
1657#if CURL_TCP_NODELAY
1658 curl_easy_setopt (ps->recv_endpoint,
1659 CURLOPT_TCP_NODELAY,
1660 1L);
1661#endif
1662 curl_easy_setopt (s->get.easyhandle,
1663 CURLOPT_FOLLOWLOCATION,
1664 0L);
1665
1666 mret = curl_multi_add_handle (s->plugin->curl_multi_handle,
1667 s->get.easyhandle);
1668 if (CURLM_OK != mret)
1669 {
1670 LOG (GNUNET_ERROR_TYPE_ERROR,
1671 "Session %p : Failed to add GET handle to multihandle: `%s'\n",
1672 s,
1673 curl_multi_strerror (mret));
1674 curl_easy_cleanup (s->get.easyhandle);
1675 s->get.easyhandle = NULL;
1676 s->get.s = NULL;
1677 GNUNET_break (0);
1678 return GNUNET_SYSERR;
1679 }
1680 s->plugin->cur_requests++;
1681 LOG (GNUNET_ERROR_TYPE_INFO,
1682 "GET request `%s' established, number of requests increased to %u\n",
1683 s->url,
1684 s->plugin->cur_requests);
1685 return GNUNET_OK;
1686}
1687
1688
1689static int
1690client_connect_put (struct GNUNET_ATS_Session *s)
1691{
1692 CURLMcode mret;
1693 struct HttpAddress *ha;
1694 uint32_t options;
1695
1696 ha = (struct HttpAddress *) s->address->address;
1697 options = ntohl (ha->options);
1698 /* create put request */
1699 LOG (GNUNET_ERROR_TYPE_DEBUG,
1700 "Session %p: Init PUT handle\n",
1701 s);
1702 s->put.easyhandle = curl_easy_init ();
1703 s->put.s = s;
1704#if VERBOSE_CURL
1705 curl_easy_setopt (s->put.easyhandle,
1706 CURLOPT_VERBOSE,
1707 1L);
1708 curl_easy_setopt (s->put.easyhandle,
1709 CURLOPT_DEBUGFUNCTION,
1710 &client_log);
1711 curl_easy_setopt (s->put.easyhandle,
1712 CURLOPT_DEBUGDATA,
1713 &s->put);
1714#endif
1715 if (0 != (options & HTTP_OPTIONS_TCP_STEALTH))
1716 {
1717#ifdef TCP_STEALTH
1718 curl_easy_setopt (s->put.easyhandle,
1719 CURLOPT_OPENSOCKETFUNCTION,
1720 &open_tcp_stealth_socket_cb);
1721 curl_easy_setopt (s->put.easyhandle,
1722 CURLOPT_OPENSOCKETDATA,
1723 s);
1724#else
1725 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1726 "Cannot connect, TCP STEALTH needed and not supported by kernel.\n");
1727 curl_easy_cleanup (s->put.easyhandle);
1728 s->put.easyhandle = NULL;
1729 s->put.s = NULL;
1730 s->put.state = H_DISCONNECTED;
1731 return GNUNET_SYSERR;
1732#endif
1733 }
1734#if BUILD_HTTPS
1735 curl_easy_setopt (s->put.easyhandle,
1736 CURLOPT_SSLVERSION,
1737 CURL_SSLVERSION_TLSv1);
1738 {
1739 struct HttpAddress *ha;
1740 ha = (struct HttpAddress *) s->address->address;
1741
1742 if (HTTP_OPTIONS_VERIFY_CERTIFICATE ==
1743 (ntohl (ha->options) & HTTP_OPTIONS_VERIFY_CERTIFICATE))
1744 {
1745 curl_easy_setopt (s->put.easyhandle,
1746 CURLOPT_SSL_VERIFYPEER,
1747 1L);
1748 curl_easy_setopt (s->put.easyhandle,
1749 CURLOPT_SSL_VERIFYHOST,
1750 2L);
1751 }
1752 else
1753 {
1754 curl_easy_setopt (s->put.easyhandle,
1755 CURLOPT_SSL_VERIFYPEER,
1756 0L);
1757 curl_easy_setopt (s->put.easyhandle,
1758 CURLOPT_SSL_VERIFYHOST,
1759 0L);
1760 }
1761 }
1762 curl_easy_setopt (s->put.easyhandle,
1763 CURLOPT_PROTOCOLS,
1764 CURLPROTO_HTTPS);
1765 curl_easy_setopt (s->put.easyhandle,
1766 CURLOPT_REDIR_PROTOCOLS,
1767 CURLPROTO_HTTPS);
1768#else
1769 curl_easy_setopt (s->put.easyhandle,
1770 CURLOPT_PROTOCOLS,
1771 CURLPROTO_HTTP);
1772 curl_easy_setopt (s->put.easyhandle,
1773 CURLOPT_REDIR_PROTOCOLS,
1774 CURLPROTO_HTTP);
1775#endif
1776 if (NULL != s->plugin->proxy_hostname)
1777 {
1778 curl_easy_setopt (s->put.easyhandle,
1779 CURLOPT_PROXY,
1780 s->plugin->proxy_hostname);
1781 curl_easy_setopt (s->put.easyhandle,
1782 CURLOPT_PROXYTYPE,
1783 s->plugin->proxytype);
1784 if (NULL != s->plugin->proxy_username)
1785 curl_easy_setopt (s->put.easyhandle,
1786 CURLOPT_PROXYUSERNAME,
1787 s->plugin->proxy_username);
1788 if (NULL != s->plugin->proxy_password)
1789 curl_easy_setopt (s->put.easyhandle,
1790 CURLOPT_PROXYPASSWORD,
1791 s->plugin->proxy_password);
1792 if (GNUNET_YES == s->plugin->proxy_use_httpproxytunnel)
1793 curl_easy_setopt (s->put.easyhandle,
1794 CURLOPT_HTTPPROXYTUNNEL,
1795 s->plugin->proxy_use_httpproxytunnel);
1796 }
1797
1798 curl_easy_setopt (s->put.easyhandle,
1799 CURLOPT_URL,
1800 s->url);
1801 curl_easy_setopt (s->put.easyhandle,
1802 CURLOPT_UPLOAD,
1803 1L);
1804 curl_easy_setopt (s->put.easyhandle,
1805 CURLOPT_READFUNCTION,
1806 &client_send_cb);
1807 curl_easy_setopt (s->put.easyhandle,
1808 CURLOPT_READDATA,
1809 s);
1810 curl_easy_setopt (s->put.easyhandle,
1811 CURLOPT_WRITEFUNCTION,
1812 &client_receive_put);
1813 curl_easy_setopt (s->put.easyhandle,
1814 CURLOPT_WRITEDATA,
1815 s);
1816 /* No timeout by default, timeout done with session timeout */
1817 curl_easy_setopt (s->put.easyhandle,
1818 CURLOPT_TIMEOUT,
1819 0L);
1820 curl_easy_setopt (s->put.easyhandle,
1821 CURLOPT_PRIVATE,
1822 s);
1823 curl_easy_setopt (s->put.easyhandle,
1824 CURLOPT_CONNECTTIMEOUT_MS,
1825 (long) (HTTP_CLIENT_NOT_VALIDATED_TIMEOUT.rel_value_us
1826 / 1000LL));
1827 curl_easy_setopt (s->put.easyhandle, CURLOPT_BUFFERSIZE,
1828 2 * GNUNET_MAX_MESSAGE_SIZE);
1829#if CURL_TCP_NODELAY
1830 curl_easy_setopt (s->put.easyhandle, CURLOPT_TCP_NODELAY, 1);
1831#endif
1832 mret = curl_multi_add_handle (s->plugin->curl_multi_handle,
1833 s->put.easyhandle);
1834 if (CURLM_OK != mret)
1835 {
1836 LOG (GNUNET_ERROR_TYPE_ERROR,
1837 "Session %p : Failed to add PUT handle to multihandle: `%s'\n",
1838 s, curl_multi_strerror (mret));
1839 curl_easy_cleanup (s->put.easyhandle);
1840 s->put.easyhandle = NULL;
1841 s->put.s = NULL;
1842 s->put.state = H_DISCONNECTED;
1843 return GNUNET_SYSERR;
1844 }
1845 s->put.state = H_CONNECTED;
1846 s->plugin->cur_requests++;
1847
1848 LOG (GNUNET_ERROR_TYPE_INFO,
1849 "PUT request `%s' established, number of requests increased to %u\n",
1850 s->url, s->plugin->cur_requests);
1851
1852 return GNUNET_OK;
1853}
1854
1855
1856/**
1857 * Connect both PUT and GET request for a session
1858 *
1859 * @param s the session to connect
1860 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
1861 */
1862static int
1863client_connect (struct GNUNET_ATS_Session *s)
1864{
1865 struct HTTP_Client_Plugin *plugin = s->plugin;
1866 int res = GNUNET_OK;
1867
1868 /* create url */
1869 if (NULL ==
1870 http_common_plugin_address_to_string (plugin->protocol,
1871 s->address->address,
1872 s->address->address_length))
1873 {
1874 LOG (GNUNET_ERROR_TYPE_DEBUG,
1875 "Invalid address peer `%s'\n",
1876 GNUNET_i2s (&s->address->peer));
1877 return GNUNET_SYSERR;
1878 }
1879
1880 GNUNET_asprintf (&s->url,
1881 "%s/%s;%u",
1882 http_common_plugin_address_to_url (NULL,
1883 s->address->address,
1884 s->address->address_length),
1885 GNUNET_i2s_full (plugin->env->my_identity),
1886 plugin->last_tag);
1887
1888 plugin->last_tag++;
1889 LOG (GNUNET_ERROR_TYPE_DEBUG,
1890 "Initiating outbound session peer `%s' using address `%s'\n",
1891 GNUNET_i2s (&s->address->peer), s->url);
1892
1893 if (GNUNET_SYSERR == client_connect_get (s))
1894 return GNUNET_SYSERR;
1895 /* If we are emulating an XHR client then delay sending a PUT request until
1896 * there is something to send.
1897 */
1898 if (GNUNET_YES == plugin->emulate_xhr)
1899 {
1900 s->put.state = H_TMP_DISCONNECTED;
1901 }
1902 else if (GNUNET_SYSERR == client_connect_put (s))
1903 return GNUNET_SYSERR;
1904
1905 LOG (GNUNET_ERROR_TYPE_DEBUG,
1906 "Session %p: connected with GET %p and PUT %p\n",
1907 s, s->get.easyhandle,
1908 s->put.easyhandle);
1909 /* Perform connect */
1910 GNUNET_STATISTICS_set (plugin->env->stats,
1911 HTTP_STAT_STR_CONNECTIONS,
1912 plugin->cur_requests,
1913 GNUNET_NO);
1914 /* Re-schedule since handles have changed */
1915 if (NULL != plugin->client_perform_task)
1916 {
1917 GNUNET_SCHEDULER_cancel (plugin->client_perform_task);
1918 plugin->client_perform_task = NULL;
1919 }
1920
1921 /* Schedule task to run immediately */
1922 plugin->client_perform_task = GNUNET_SCHEDULER_add_now (client_run,
1923 plugin);
1924 return res;
1925}
1926
1927
1928/**
1929 * Function obtain the network type for a session
1930 *
1931 * @param cls closure (`struct Plugin*`)
1932 * @param session the session
1933 * @return the network type
1934 */
1935static enum GNUNET_NetworkType
1936http_client_plugin_get_network (void *cls,
1937 struct GNUNET_ATS_Session *session)
1938{
1939 return session->scope;
1940}
1941
1942
1943/**
1944 * Function obtain the network type for an address.
1945 *
1946 * @param cls closure (`struct Plugin *`)
1947 * @param address the address
1948 * @return the network type
1949 */
1950static enum GNUNET_NetworkType
1951http_client_plugin_get_network_for_address (void *cls,
1952 const struct
1953 GNUNET_HELLO_Address *address)
1954{
1955 struct HTTP_Client_Plugin *plugin = cls;
1956
1957 return http_common_get_network_for_address (plugin->env,
1958 address);
1959}
1960
1961
1962/**
1963 * Session was idle, so disconnect it
1964 *
1965 * @param cls the `struct GNUNET_ATS_Session` of the idle session
1966 */
1967static void
1968client_session_timeout (void *cls)
1969{
1970 struct GNUNET_ATS_Session *s = cls;
1971 struct GNUNET_TIME_Relative left;
1972
1973 s->timeout_task = NULL;
1974 left = GNUNET_TIME_absolute_get_remaining (s->timeout);
1975 if (0 != left.rel_value_us)
1976 {
1977 /* not actually our turn yet, but let's at least update
1978 the monitor, it may think we're about to die ... */
1979 notify_session_monitor (s->plugin,
1980 s,
1981 GNUNET_TRANSPORT_SS_UPDATE);
1982 s->timeout_task = GNUNET_SCHEDULER_add_delayed (left,
1983 &client_session_timeout,
1984 s);
1985 return;
1986 }
1987 LOG (TIMEOUT_LOG,
1988 "Session %p was idle for %s, disconnecting\n",
1989 s,
1990 GNUNET_STRINGS_relative_time_to_string (HTTP_CLIENT_SESSION_TIMEOUT,
1991 GNUNET_YES));
1992 GNUNET_assert (GNUNET_OK ==
1993 http_client_plugin_session_disconnect (s->plugin,
1994 s));
1995}
1996
1997
1998/**
1999 * Creates a new outbound session the transport service will use to
2000 * send data to the peer
2001 *
2002 * @param cls the plugin
2003 * @param address the address
2004 * @return the session or NULL of max connections exceeded
2005 */
2006static struct GNUNET_ATS_Session *
2007http_client_plugin_get_session (void *cls,
2008 const struct GNUNET_HELLO_Address *address)
2009{
2010 struct HTTP_Client_Plugin *plugin = cls;
2011 struct GNUNET_ATS_Session *s;
2012 struct sockaddr *sa;
2013 enum GNUNET_NetworkType net_type;
2014 size_t salen = 0;
2015 int res;
2016
2017 GNUNET_assert (NULL != address->address);
2018
2019 /* find existing session */
2020 s = client_lookup_session (plugin, address);
2021 if (NULL != s)
2022 return s;
2023
2024 /* create a new session */
2025 if (plugin->max_requests <= plugin->cur_requests)
2026 {
2027 LOG (GNUNET_ERROR_TYPE_WARNING,
2028 "Maximum number of requests (%u) reached: "
2029 "cannot connect to peer `%s'\n",
2030 plugin->max_requests,
2031 GNUNET_i2s (&address->peer));
2032 return NULL;
2033 }
2034
2035 /* Determine network location */
2036 net_type = GNUNET_NT_UNSPECIFIED;
2037 sa = http_common_socket_from_address (address->address,
2038 address->address_length,
2039 &res);
2040 if (GNUNET_SYSERR == res)
2041 return NULL;
2042 if (GNUNET_YES == res)
2043 {
2044 GNUNET_assert (NULL != sa);
2045 if (AF_INET == sa->sa_family)
2046 {
2047 salen = sizeof(struct sockaddr_in);
2048 }
2049 else if (AF_INET6 == sa->sa_family)
2050 {
2051 salen = sizeof(struct sockaddr_in6);
2052 }
2053 net_type = plugin->env->get_address_type (plugin->env->cls, sa, salen);
2054 GNUNET_free (sa);
2055 }
2056 else if (GNUNET_NO == res)
2057 {
2058 /* Cannot convert to sockaddr -> is external hostname */
2059 net_type = GNUNET_NT_WAN;
2060 }
2061 if (GNUNET_NT_UNSPECIFIED == net_type)
2062 {
2063 GNUNET_break (0);
2064 return NULL;
2065 }
2066
2067 s = GNUNET_new (struct GNUNET_ATS_Session);
2068 s->plugin = plugin;
2069 s->address = GNUNET_HELLO_address_copy (address);
2070 s->scope = net_type;
2071
2072 s->put.state = H_NOT_CONNECTED;
2073 s->timeout = GNUNET_TIME_relative_to_absolute (HTTP_CLIENT_SESSION_TIMEOUT);
2074 s->timeout_task = GNUNET_SCHEDULER_add_delayed (HTTP_CLIENT_SESSION_TIMEOUT,
2075 &client_session_timeout,
2076 s);
2077 LOG (GNUNET_ERROR_TYPE_DEBUG,
2078 "Created new session %p for `%s' address `%s''\n",
2079 s,
2080 http_common_plugin_address_to_string (plugin->protocol,
2081 s->address->address,
2082 s->address->address_length),
2083 GNUNET_i2s (&s->address->peer));
2084
2085 /* add new session */
2086 (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessions,
2087 &s->address->peer,
2088 s,
2089 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2090 /* initiate new connection */
2091 if (GNUNET_SYSERR == client_connect (s))
2092 {
2093 LOG (GNUNET_ERROR_TYPE_ERROR,
2094 "Cannot connect to peer `%s' address `%s''\n",
2095 http_common_plugin_address_to_string (plugin->protocol,
2096 s->address->address,
2097 s->address->address_length),
2098 GNUNET_i2s (&s->address->peer));
2099 client_delete_session (s);
2100 return NULL;
2101 }
2102 notify_session_monitor (plugin,
2103 s,
2104 GNUNET_TRANSPORT_SS_INIT);
2105 notify_session_monitor (plugin,
2106 s,
2107 GNUNET_TRANSPORT_SS_UP); /* or handshake? */
2108 return s;
2109}
2110
2111
2112/**
2113 * Setup http_client plugin
2114 *
2115 * @param plugin the plugin handle
2116 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
2117 */
2118static int
2119client_start (struct HTTP_Client_Plugin *plugin)
2120{
2121 curl_global_init (CURL_GLOBAL_ALL);
2122 plugin->curl_multi_handle = curl_multi_init ();
2123
2124 if (NULL == plugin->curl_multi_handle)
2125 {
2126 LOG (GNUNET_ERROR_TYPE_ERROR,
2127 _ (
2128 "Could not initialize curl multi handle, failed to start %s plugin!\n"),
2129 plugin->name);
2130 return GNUNET_SYSERR;
2131 }
2132 return GNUNET_OK;
2133}
2134
2135
2136/**
2137 * Another peer has suggested an address for this
2138 * peer and transport plugin. Check that this could be a valid
2139 * address. If so, consider adding it to the list
2140 * of addresses.
2141 *
2142 * @param cls closure with the `struct Plugin`
2143 * @param addr pointer to the address
2144 * @param addrlen length of @a addr
2145 * @return #GNUNET_OK if this is a plausible address for this peer
2146 * and transport; always returns #GNUNET_NO (this is the client!)
2147 */
2148static int
2149http_client_plugin_address_suggested (void *cls,
2150 const void *addr,
2151 size_t addrlen)
2152{
2153 /* A HTTP/S client does not have any valid address so:*/
2154 return GNUNET_NO;
2155}
2156
2157
2158/**
2159 * Exit point from the plugin.
2160 *
2161 * @param cls api as closure
2162 * @return NULL
2163 */
2164void *
2165LIBGNUNET_PLUGIN_TRANSPORT_DONE (void *cls)
2166{
2167 struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
2168 struct HTTP_Client_Plugin *plugin = api->cls;
2169
2170 if (NULL == api->cls)
2171 {
2172 /* Stub shutdown */
2173 GNUNET_free (api);
2174 return NULL;
2175 }
2176 LOG (GNUNET_ERROR_TYPE_DEBUG,
2177 _ ("Shutting down plugin `%s'\n"),
2178 plugin->name);
2179 GNUNET_CONTAINER_multipeermap_iterate (plugin->sessions,
2180 &destroy_session_cb,
2181 plugin);
2182 if (NULL != plugin->client_perform_task)
2183 {
2184 GNUNET_SCHEDULER_cancel (plugin->client_perform_task);
2185 plugin->client_perform_task = NULL;
2186 }
2187 if (NULL != plugin->curl_multi_handle)
2188 {
2189 curl_multi_cleanup (plugin->curl_multi_handle);
2190 plugin->curl_multi_handle = NULL;
2191 }
2192 curl_global_cleanup ();
2193 LOG (GNUNET_ERROR_TYPE_DEBUG,
2194 _ ("Shutdown for plugin `%s' complete\n"),
2195 plugin->name);
2196 GNUNET_CONTAINER_multipeermap_destroy (plugin->sessions);
2197 GNUNET_free (plugin->proxy_hostname);
2198 GNUNET_free (plugin->proxy_username);
2199 GNUNET_free (plugin->proxy_password);
2200 GNUNET_free (plugin);
2201 GNUNET_free (api);
2202 return NULL;
2203}
2204
2205
2206/**
2207 * Configure plugin
2208 *
2209 * @param plugin the plugin handle
2210 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
2211 */
2212static int
2213client_configure_plugin (struct HTTP_Client_Plugin *plugin)
2214{
2215 unsigned long long max_requests;
2216 char *proxy_type;
2217
2218 /* Optional parameters */
2219 if (GNUNET_OK !=
2220 GNUNET_CONFIGURATION_get_value_number (plugin->env->cfg,
2221 plugin->name,
2222 "MAX_CONNECTIONS",
2223 &max_requests))
2224 max_requests = 128;
2225 plugin->max_requests = max_requests;
2226
2227 LOG (GNUNET_ERROR_TYPE_DEBUG,
2228 _ ("Maximum number of requests is %u\n"),
2229 plugin->max_requests);
2230
2231 /* Read proxy configuration */
2232 if (GNUNET_OK ==
2233 GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg,
2234 plugin->name,
2235 "PROXY",
2236 &plugin->proxy_hostname))
2237 {
2238 LOG (GNUNET_ERROR_TYPE_DEBUG,
2239 "Found proxy host: `%s'\n",
2240 plugin->proxy_hostname);
2241 /* proxy username */
2242 if (GNUNET_OK ==
2243 GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg,
2244 plugin->name,
2245 "PROXY_USERNAME",
2246 &plugin->proxy_username))
2247 {
2248 LOG (GNUNET_ERROR_TYPE_DEBUG,
2249 "Found proxy username name: `%s'\n",
2250 plugin->proxy_username);
2251 }
2252
2253 /* proxy password */
2254 if (GNUNET_OK ==
2255 GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg,
2256 plugin->name,
2257 "PROXY_PASSWORD",
2258 &plugin->proxy_password))
2259 {
2260 LOG (GNUNET_ERROR_TYPE_DEBUG,
2261 "Found proxy password name: `%s'\n",
2262 plugin->proxy_password);
2263 }
2264
2265 /* proxy type */
2266 if (GNUNET_OK ==
2267 GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg,
2268 plugin->name,
2269 "PROXY_TYPE",
2270 &proxy_type))
2271 {
2272 GNUNET_STRINGS_utf8_toupper (proxy_type, proxy_type);
2273
2274 if (0 == strcmp (proxy_type, "HTTP"))
2275 plugin->proxytype = CURLPROXY_HTTP;
2276 else if (0 == strcmp (proxy_type, "SOCKS4"))
2277 plugin->proxytype = CURLPROXY_SOCKS4;
2278 else if (0 == strcmp (proxy_type, "SOCKS5"))
2279 plugin->proxytype = CURLPROXY_SOCKS5;
2280 else if (0 == strcmp (proxy_type, "SOCKS4A"))
2281 plugin->proxytype = CURLPROXY_SOCKS4A;
2282 else if (0 == strcmp (proxy_type, "SOCKS5_HOSTNAME "))
2283 plugin->proxytype = CURLPROXY_SOCKS5_HOSTNAME;
2284 else
2285 {
2286 LOG (GNUNET_ERROR_TYPE_ERROR,
2287 _ (
2288 "Invalid proxy type: `%s', disabling proxy! Check configuration!\n"),
2289 proxy_type);
2290
2291 GNUNET_free (proxy_type);
2292 GNUNET_free (plugin->proxy_hostname);
2293 plugin->proxy_hostname = NULL;
2294 GNUNET_free (plugin->proxy_username);
2295 plugin->proxy_username = NULL;
2296 GNUNET_free (plugin->proxy_password);
2297 plugin->proxy_password = NULL;
2298
2299 return GNUNET_SYSERR;
2300 }
2301
2302 LOG (GNUNET_ERROR_TYPE_DEBUG,
2303 "Found proxy type: `%s'\n",
2304 proxy_type);
2305 }
2306
2307 /* proxy http tunneling */
2308 plugin->proxy_use_httpproxytunnel
2309 = GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg,
2310 plugin->name,
2311 "PROXY_HTTP_TUNNELING");
2312 if (GNUNET_SYSERR == plugin->proxy_use_httpproxytunnel)
2313 plugin->proxy_use_httpproxytunnel = GNUNET_NO;
2314
2315 GNUNET_free (proxy_type);
2316 }
2317
2318 /* Should we emulate an XHR client for testing? */
2319 plugin->emulate_xhr
2320 = GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg,
2321 plugin->name,
2322 "EMULATE_XHR");
2323 return GNUNET_OK;
2324}
2325
2326
2327/**
2328 * Function to convert an address to a human-readable string.
2329 *
2330 * @param cls closure
2331 * @param addr address to convert
2332 * @param addrlen address length
2333 * @return res string if conversion was successful, NULL otherwise
2334 */
2335static const char *
2336http_client_plugin_address_to_string (void *cls,
2337 const void *addr,
2338 size_t addrlen)
2339{
2340 return http_common_plugin_address_to_string (PLUGIN_NAME,
2341 addr,
2342 addrlen);
2343}
2344
2345
2346/**
2347 * Function that will be called whenever the transport service wants to
2348 * notify the plugin that a session is still active and in use and
2349 * therefore the session timeout for this session has to be updated
2350 *
2351 * @param cls closure
2352 * @param peer which peer was the session for
2353 * @param session which session is being updated
2354 */
2355static void
2356http_client_plugin_update_session_timeout (void *cls,
2357 const struct
2358 GNUNET_PeerIdentity *peer,
2359 struct GNUNET_ATS_Session *session)
2360{
2361 client_reschedule_session_timeout (session);
2362}
2363
2364
2365/**
2366 * Function that will be called whenever the transport service wants to
2367 * notify the plugin that the inbound quota changed and that the plugin
2368 * should update it's delay for the next receive value
2369 *
2370 * @param cls closure
2371 * @param peer which peer was the session for
2372 * @param s which session is being updated
2373 * @param delay new delay to use for receiving
2374 */
2375static void
2376http_client_plugin_update_inbound_delay (void *cls,
2377 const struct GNUNET_PeerIdentity *peer,
2378 struct GNUNET_ATS_Session *s,
2379 struct GNUNET_TIME_Relative delay)
2380{
2381 s->next_receive = GNUNET_TIME_relative_to_absolute (delay);
2382 LOG (GNUNET_ERROR_TYPE_DEBUG,
2383 "New inbound delay %s\n",
2384 GNUNET_STRINGS_relative_time_to_string (delay,
2385 GNUNET_NO));
2386 if (s->recv_wakeup_task != NULL)
2387 {
2388 GNUNET_SCHEDULER_cancel (s->recv_wakeup_task);
2389 s->recv_wakeup_task
2390 = GNUNET_SCHEDULER_add_delayed (delay,
2391 &client_wake_up,
2392 s);
2393 }
2394}
2395
2396
2397/**
2398 * Return information about the given session to the
2399 * monitor callback.
2400 *
2401 * @param cls the `struct Plugin` with the monitor callback (`sic`)
2402 * @param peer peer we send information about
2403 * @param value our `struct GNUNET_ATS_Session` to send information about
2404 * @return #GNUNET_OK (continue to iterate)
2405 */
2406static int
2407send_session_info_iter (void *cls,
2408 const struct GNUNET_PeerIdentity *peer,
2409 void *value)
2410{
2411 struct HTTP_Client_Plugin *plugin = cls;
2412 struct GNUNET_ATS_Session *session = value;
2413
2414 notify_session_monitor (plugin,
2415 session,
2416 GNUNET_TRANSPORT_SS_INIT);
2417 notify_session_monitor (plugin,
2418 session,
2419 GNUNET_TRANSPORT_SS_UP); /* FIXME: or handshake? */
2420 return GNUNET_OK;
2421}
2422
2423
2424/**
2425 * Begin monitoring sessions of a plugin. There can only
2426 * be one active monitor per plugin (i.e. if there are
2427 * multiple monitors, the transport service needs to
2428 * multiplex the generated events over all of them).
2429 *
2430 * @param cls closure of the plugin
2431 * @param sic callback to invoke, NULL to disable monitor;
2432 * plugin will being by iterating over all active
2433 * sessions immediately and then enter monitor mode
2434 * @param sic_cls closure for @a sic
2435 */
2436static void
2437http_client_plugin_setup_monitor (void *cls,
2438 GNUNET_TRANSPORT_SessionInfoCallback sic,
2439 void *sic_cls)
2440{
2441 struct HTTP_Client_Plugin *plugin = cls;
2442
2443 plugin->sic = sic;
2444 plugin->sic_cls = sic_cls;
2445 if (NULL != sic)
2446 {
2447 GNUNET_CONTAINER_multipeermap_iterate (plugin->sessions,
2448 &send_session_info_iter,
2449 plugin);
2450 /* signal end of first iteration */
2451 sic (sic_cls, NULL, NULL);
2452 }
2453}
2454
2455
2456/**
2457 * Entry point for the plugin.
2458 */
2459void *
2460LIBGNUNET_PLUGIN_TRANSPORT_INIT (void *cls)
2461{
2462 struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
2463 struct GNUNET_TRANSPORT_PluginFunctions *api;
2464 struct HTTP_Client_Plugin *plugin;
2465
2466 if (NULL == env->receive)
2467 {
2468 /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully
2469 initialize the plugin or the API */
2470 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
2471 api->cls = NULL;
2472 api->address_to_string = &http_client_plugin_address_to_string;
2473 api->string_to_address = &http_common_plugin_string_to_address;
2474 api->address_pretty_printer = &http_common_plugin_address_pretty_printer;
2475 return api;
2476 }
2477
2478 plugin = GNUNET_new (struct HTTP_Client_Plugin);
2479 plugin->env = env;
2480 plugin->sessions = GNUNET_CONTAINER_multipeermap_create (128,
2481 GNUNET_YES);
2482 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
2483 api->cls = plugin;
2484 api->send = &http_client_plugin_send;
2485 api->disconnect_session = &http_client_plugin_session_disconnect;
2486 api->query_keepalive_factor = &http_client_query_keepalive_factor;
2487 api->disconnect_peer = &http_client_plugin_peer_disconnect;
2488 api->check_address = &http_client_plugin_address_suggested;
2489 api->get_session = &http_client_plugin_get_session;
2490 api->address_to_string = &http_client_plugin_address_to_string;
2491 api->string_to_address = &http_common_plugin_string_to_address;
2492 api->address_pretty_printer = &http_common_plugin_address_pretty_printer;
2493 api->get_network = &http_client_plugin_get_network;
2494 api->get_network_for_address = &http_client_plugin_get_network_for_address;
2495 api->update_session_timeout = &http_client_plugin_update_session_timeout;
2496 api->update_inbound_delay = &http_client_plugin_update_inbound_delay;
2497 api->setup_monitor = &http_client_plugin_setup_monitor;
2498#if BUILD_HTTPS
2499 plugin->name = "transport-https_client";
2500 plugin->protocol = "https";
2501#else
2502 plugin->name = "transport-http_client";
2503 plugin->protocol = "http";
2504#endif
2505 plugin->last_tag = 1;
2506
2507 if (GNUNET_SYSERR == client_configure_plugin (plugin))
2508 {
2509 LIBGNUNET_PLUGIN_TRANSPORT_DONE (api);
2510 return NULL;
2511 }
2512
2513 /* Start client */
2514 if (GNUNET_SYSERR == client_start (plugin))
2515 {
2516 LIBGNUNET_PLUGIN_TRANSPORT_DONE (api);
2517 return NULL;
2518 }
2519 return api;
2520}
2521
2522
2523/* end of plugin_transport_http_client.c */
diff --git a/src/transport/plugin_transport_http_common.c b/src/transport/plugin_transport_http_common.c
deleted file mode 100644
index a033985e1..000000000
--- a/src/transport/plugin_transport_http_common.c
+++ /dev/null
@@ -1,903 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2002-2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/plugin_transport_http_common.c
23 * @brief functionality shared between http(s)client plugins
24 * @author Matthias Wachs
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_transport_plugin.h"
29#include "plugin_transport_http_common.h"
30#include "gnunet_resolver_service.h"
31
32static void
33http_clean_splitted (struct SplittedHTTPAddress *spa)
34{
35 if (NULL != spa)
36 {
37 GNUNET_free (spa->protocol);
38 GNUNET_free (spa->host);
39 GNUNET_free (spa->path);
40 GNUNET_free (spa);
41 }
42}
43
44
45struct SplittedHTTPAddress *
46http_split_address (const char *addr)
47{
48 struct SplittedHTTPAddress *sp;
49 char *src = GNUNET_strdup (addr);
50 char *protocol_start = NULL;
51 char *host_start = NULL;
52 char *v6_end = NULL;
53 char *port_start = NULL;
54 char *path_start = NULL;
55
56 protocol_start = src;
57
58 sp = GNUNET_new (struct SplittedHTTPAddress);
59 /* Address string consists of protocol://host[:port]path*/
60
61 host_start = strstr (src, "://");
62 if (NULL == host_start)
63 {
64 GNUNET_free (src);
65 GNUNET_free (sp);
66 return NULL;
67 }
68 host_start[0] = '\0';
69 sp->protocol = GNUNET_strdup (protocol_start);
70
71 host_start += strlen ("://");
72 if (strlen (host_start) == 0)
73 {
74 GNUNET_free (src);
75 GNUNET_free (sp->protocol);
76 GNUNET_free (sp);
77 return NULL;
78 }
79
80 /* Find path start */
81 path_start = strchr (host_start, '/');
82 if (NULL != path_start)
83 {
84 sp->path = GNUNET_strdup (path_start);
85 path_start[0] = '\0';
86 }
87 else
88 sp->path = GNUNET_strdup ("");
89
90 if (strlen (host_start) < 1)
91 {
92 GNUNET_free (src);
93 GNUNET_free (sp->protocol);
94 GNUNET_free (sp->path);
95 GNUNET_free (sp);
96 return NULL;
97 }
98
99 if (NULL != (port_start = strrchr (host_start, ':')))
100 {
101 /* *We COULD have a port, but also an IPv6 address! */
102 if (NULL != (v6_end = strchr (host_start, ']')))
103 {
104 if (v6_end < port_start)
105 {
106 /* IPv6 address + port */
107 port_start[0] = '\0';
108 port_start++;
109 sp->port = atoi (port_start);
110 if ((0 == sp->port) || (65535 < sp->port))
111 {
112 GNUNET_free (src);
113 GNUNET_free (sp->protocol);
114 GNUNET_free (sp->path);
115 GNUNET_free (sp);
116 return NULL;
117 }
118 }
119 else
120 {
121 /* IPv6 address + no port */
122 if (0 == strcmp (sp->protocol, "https"))
123 sp->port = HTTPS_DEFAULT_PORT;
124 else if (0 == strcmp (sp->protocol, "http"))
125 sp->port = HTTP_DEFAULT_PORT;
126 }
127 }
128 else
129 {
130 /* No IPv6 address */
131 port_start[0] = '\0';
132 port_start++;
133 sp->port = atoi (port_start);
134 if ((0 == sp->port) || (65535 < sp->port))
135 {
136 GNUNET_free (src);
137 GNUNET_free (sp->protocol);
138 GNUNET_free (sp->path);
139 GNUNET_free (sp);
140 return NULL;
141 }
142 }
143 }
144 else
145 {
146 /* No ':' as port separator, default port for protocol */
147 if (0 == strcmp (sp->protocol, "https"))
148 sp->port = HTTPS_DEFAULT_PORT;
149 else if (0 == strcmp (sp->protocol, "http"))
150 sp->port = HTTP_DEFAULT_PORT;
151 else
152 {
153 GNUNET_break (0);
154 GNUNET_free (src);
155 GNUNET_free (sp->protocol);
156 GNUNET_free (sp->path);
157 GNUNET_free (sp);
158 return NULL;
159 }
160 }
161 if (strlen (host_start) > 0)
162 sp->host = GNUNET_strdup (host_start);
163 else
164 {
165 GNUNET_break (0);
166 GNUNET_free (src);
167 GNUNET_free (sp->protocol);
168 GNUNET_free (sp->path);
169 GNUNET_free (sp);
170 return NULL;
171 }
172 GNUNET_free (src);
173 return sp;
174}
175
176
177/**
178 * Closure for #append_port().
179 */
180struct PrettyPrinterContext
181{
182 /**
183 * DLL
184 */
185 struct PrettyPrinterContext *next;
186
187 /**
188 * DLL
189 */
190 struct PrettyPrinterContext *prev;
191
192 /**
193 * Resolver handle
194 */
195 struct GNUNET_RESOLVER_RequestHandle *resolver_handle;
196
197 /**
198 * Function to call with the result.
199 */
200 GNUNET_TRANSPORT_AddressStringCallback asc;
201
202 /**
203 * Clsoure for @e asc.
204 */
205 void *asc_cls;
206
207 /**
208 * Timeout task
209 */
210 struct GNUNET_SCHEDULER_Task *timeout_task;
211
212 /**
213 * Split Address
214 */
215 struct SplittedHTTPAddress *saddr;
216
217 /**
218 * Plugin String
219 */
220 char *plugin;
221
222 /**
223 * Was conversion successful
224 */
225 int success;
226
227 /**
228 * Address options
229 */
230 uint32_t options;
231};
232
233/**
234 * Head of PPC list
235 */
236static struct PrettyPrinterContext *dll_ppc_head;
237
238/**
239 * Tail of PPC list
240 */
241static struct PrettyPrinterContext *dll_ppc_tail;
242
243/**
244 * Function called for a quick conversion of the binary address to
245 * a numeric address. Note that the caller must not free the
246 * address and that the next call to this function is allowed
247 * to override the address again.
248 *
249 * @param plugin the name of the plugin
250 * @param saddr the split http address
251 * @param options address options
252 * @param dnsresult dns name to include in address
253 * @return string representing the same address or NULL on error
254 */
255static const char *
256http_common_plugin_dnsresult_to_address (const char *plugin,
257 const struct
258 SplittedHTTPAddress *saddr,
259 uint32_t options,
260 const char *dnsresult)
261{
262 static char rbuf[1024];
263 char *res;
264
265 GNUNET_asprintf (&res, "%s.%u.%s://%s:%u%s", plugin, options, saddr->protocol,
266 dnsresult, saddr->port, saddr->path);
267 if (strlen (res) + 1 < 500)
268 {
269 GNUNET_memcpy (rbuf, res, strlen (res) + 1);
270 GNUNET_free (res);
271 return rbuf;
272 }
273 GNUNET_break (0);
274 GNUNET_free (res);
275 return NULL;
276}
277
278
279static void
280http_common_dns_reverse_lookup_cb (void *cls, const char *hostname)
281{
282 struct PrettyPrinterContext *ppc = cls;
283
284 if (NULL != hostname)
285 {
286 ppc->asc (ppc->asc_cls,
287 http_common_plugin_dnsresult_to_address (ppc->plugin, ppc->saddr,
288 ppc->options,
289 hostname), GNUNET_OK);
290 ppc->success = GNUNET_YES;
291 }
292 else
293 {
294 ppc->asc (ppc->asc_cls, NULL,
295 (GNUNET_NO == ppc->success) ? GNUNET_SYSERR : GNUNET_OK);
296
297 GNUNET_CONTAINER_DLL_remove (dll_ppc_head, dll_ppc_tail, ppc);
298 http_clean_splitted (ppc->saddr);
299 GNUNET_free (ppc->plugin);
300 GNUNET_free (ppc);
301 }
302}
303
304
305static int
306http_common_dns_reverse_lookup (const struct sockaddr *sockaddr,
307 socklen_t sockaddr_len,
308 const char *type,
309 struct SplittedHTTPAddress *saddr,
310 uint32_t options,
311 struct GNUNET_TIME_Relative timeout,
312 GNUNET_TRANSPORT_AddressStringCallback asc,
313 void *asc_cls)
314{
315 struct PrettyPrinterContext *ppc;
316
317 ppc = GNUNET_new (struct PrettyPrinterContext);
318 ppc->saddr = saddr;
319 ppc->asc = asc;
320 ppc->asc_cls = asc_cls;
321 ppc->plugin = GNUNET_strdup (type);
322 ppc->options = options;
323 ppc->resolver_handle = GNUNET_RESOLVER_hostname_get (sockaddr,
324 sockaddr_len,
325 GNUNET_YES,
326 timeout,
327 &
328 http_common_dns_reverse_lookup_cb,
329 ppc);
330 if (NULL == ppc->resolver_handle)
331 {
332 GNUNET_free (ppc->plugin);
333 GNUNET_free (ppc);
334 return GNUNET_SYSERR;
335 }
336 GNUNET_CONTAINER_DLL_insert (dll_ppc_head,
337 dll_ppc_tail,
338 ppc);
339 return GNUNET_OK;
340}
341
342
343static void
344http_common_dns_ip_lookup_cb (void *cls,
345 const struct sockaddr *addr,
346 socklen_t addrlen)
347{
348 struct PrettyPrinterContext *ppc = cls;
349
350 if (NULL != addr)
351 {
352 ppc->asc (ppc->asc_cls,
353 http_common_plugin_dnsresult_to_address (ppc->plugin, ppc->saddr,
354 ppc->options,
355 GNUNET_a2s (addr,
356 addrlen)),
357 GNUNET_OK);
358 ppc->success = GNUNET_YES;
359 ppc->asc (ppc->asc_cls, GNUNET_a2s (addr, addrlen), GNUNET_OK);
360 }
361 else
362 {
363 ppc->asc (ppc->asc_cls, NULL,
364 (GNUNET_NO == ppc->success) ? GNUNET_SYSERR : GNUNET_OK);
365
366 GNUNET_CONTAINER_DLL_remove (dll_ppc_head, dll_ppc_tail, ppc);
367 GNUNET_free (ppc->plugin);
368 http_clean_splitted (ppc->saddr);
369 GNUNET_free (ppc);
370 }
371}
372
373
374static int
375http_common_dns_ip_lookup (const char *name,
376 const char *type,
377 struct SplittedHTTPAddress *saddr,
378 uint32_t options,
379 struct GNUNET_TIME_Relative timeout,
380 GNUNET_TRANSPORT_AddressStringCallback asc,
381 void *asc_cls)
382{
383 struct PrettyPrinterContext *ppc;
384
385 ppc = GNUNET_new (struct PrettyPrinterContext);
386 ppc->success = GNUNET_NO;
387 ppc->saddr = saddr;
388 ppc->asc = asc;
389 ppc->asc_cls = asc_cls;
390 ppc->plugin = GNUNET_strdup (type);
391 ppc->options = options;
392 ppc->resolver_handle = GNUNET_RESOLVER_ip_get (name,
393 AF_UNSPEC,
394 timeout,
395 &http_common_dns_ip_lookup_cb,
396 ppc);
397 if (NULL == ppc->resolver_handle)
398 {
399 GNUNET_free (ppc->plugin);
400 GNUNET_free (ppc);
401 return GNUNET_SYSERR;
402 }
403 GNUNET_CONTAINER_DLL_insert (dll_ppc_head,
404 dll_ppc_tail,
405 ppc);
406 return GNUNET_OK;
407}
408
409
410void
411http_common_plugin_address_pretty_printer (void *cls, const char *type,
412 const void *addr,
413 size_t addrlen,
414 int numeric,
415 struct GNUNET_TIME_Relative timeout,
416 GNUNET_TRANSPORT_AddressStringCallback
417 asc,
418 void *asc_cls)
419{
420 const struct HttpAddress *address = addr;
421 struct SplittedHTTPAddress *saddr;
422 struct sockaddr *sock_addr;
423 const char *ret;
424 char *addr_str;
425 int res;
426 int have_ip;
427
428 saddr = NULL;
429 sock_addr = NULL;
430 if ((addrlen < sizeof(struct HttpAddress)) ||
431 (addrlen != http_common_address_get_size (address)))
432 {
433 GNUNET_break (0);
434 goto handle_error;
435 }
436
437 addr_str = (char *) &address[1];
438 if (addr_str[ntohl (address->urlen) - 1] != '\0')
439 {
440 GNUNET_break (0);
441 goto handle_error;
442 }
443
444 saddr = http_split_address (addr_str);
445 if (NULL == saddr)
446 {
447 GNUNET_break (0);
448 goto handle_error;
449 }
450
451 sock_addr = http_common_socket_from_address (addr, addrlen, &res);
452 if (GNUNET_SYSERR == res)
453 {
454 /* Malformed address */
455 GNUNET_break (0);
456 goto handle_error;
457 }
458 else if (GNUNET_NO == res)
459 {
460 /* Could not convert to IP */
461 have_ip = GNUNET_NO;
462 }
463 else if (GNUNET_YES == res)
464 {
465 /* Converted to IP */
466 have_ip = GNUNET_YES;
467 }
468 else
469 {
470 /* Must not happen */
471 GNUNET_break (0);
472 goto handle_error;
473 }
474
475 if ((GNUNET_YES == numeric) &&
476 (GNUNET_YES == have_ip))
477 {
478 /* No lookup required */
479 ret = http_common_plugin_address_to_string (type, address, addrlen);
480 asc (asc_cls, ret, (NULL == ret) ? GNUNET_SYSERR : GNUNET_OK);
481 asc (asc_cls, NULL, GNUNET_OK);
482 http_clean_splitted (saddr);
483 GNUNET_free (sock_addr);
484 return;
485 }
486 if ((GNUNET_YES == numeric) &&
487 (GNUNET_NO == have_ip))
488 {
489 /* Forward lookup */
490 if (GNUNET_SYSERR ==
491 http_common_dns_ip_lookup (saddr->host, type, saddr,
492 address->options, timeout,
493 asc, asc_cls))
494 {
495 GNUNET_break (0);
496 goto handle_error;
497 }
498 /* Wait for resolver callback */
499 GNUNET_free (sock_addr);
500 return;
501 }
502 if ((GNUNET_NO == numeric) &&
503 (GNUNET_YES == have_ip))
504 {
505 /* Reverse lookup */
506 if (GNUNET_SYSERR ==
507 http_common_dns_reverse_lookup (sock_addr,
508 (AF_INET == sock_addr->sa_family)
509 ? sizeof(struct sockaddr_in)
510 : sizeof(struct sockaddr_in6),
511 type,
512 saddr,
513 address->options, timeout,
514 asc, asc_cls))
515 {
516 GNUNET_break (0);
517 goto handle_error;
518 }
519 /* Wait for resolver callback */
520 GNUNET_free (sock_addr);
521 return;
522 }
523 if ((GNUNET_NO == numeric) &&
524 (GNUNET_NO == have_ip))
525 {
526 /* No lookup required */
527 ret = http_common_plugin_address_to_string (type, address, addrlen);
528 asc (asc_cls, ret, (NULL == ret) ? GNUNET_SYSERR : GNUNET_OK);
529 asc (asc_cls, NULL, GNUNET_OK);
530 GNUNET_free (sock_addr);
531 http_clean_splitted (saddr);
532 return;
533 }
534 /* Error (argument supplied not GNUNET_YES or GNUNET_NO) */
535 GNUNET_break (0);
536 goto handle_error;
537
538handle_error:
539 /* Report error */
540 asc (asc_cls, NULL, GNUNET_SYSERR);
541 asc (asc_cls, NULL, GNUNET_OK);
542 GNUNET_free (sock_addr);
543 if (NULL != saddr)
544 http_clean_splitted (saddr);
545}
546
547
548/**
549 * FIXME.
550 */
551const char *
552http_common_plugin_address_to_url (void *cls,
553 const void *addr,
554 size_t addrlen)
555{
556 static char rbuf[1024];
557 const struct HttpAddress *address = addr;
558 const char *addr_str;
559
560 if (NULL == addr)
561 {
562 GNUNET_break (0);
563 return NULL;
564 }
565 if (0 == addrlen)
566 {
567 GNUNET_break (0);
568 return NULL;
569 }
570 if (addrlen != http_common_address_get_size (address))
571 {
572 GNUNET_break (0);
573 return NULL;
574 }
575 addr_str = (char *) &address[1];
576 if (addr_str[ntohl (address->urlen) - 1] != '\0')
577 return NULL;
578
579 GNUNET_memcpy (rbuf,
580 &address[1],
581 ntohl (address->urlen));
582 return rbuf;
583}
584
585
586const char *
587http_common_plugin_address_to_string (const char *plugin,
588 const void *addr,
589 size_t addrlen)
590{
591 static char rbuf[1024];
592 const struct HttpAddress *address = addr;
593 const char *addr_str;
594 char *res;
595
596 GNUNET_assert (NULL != plugin);
597 if (NULL == addr)
598 return NULL;
599 if (0 == addrlen)
600 return NULL;
601 if (addrlen != http_common_address_get_size (address))
602 return NULL;
603 addr_str = (char *) &address[1];
604 if (addr_str[ntohl (address->urlen) - 1] != '\0')
605 return NULL;
606 GNUNET_asprintf (&res, "%s.%u.%s", plugin, ntohl (address->options),
607 (char*) &address[1]);
608 if (strlen (res) + 1 < 500)
609 {
610 GNUNET_memcpy (rbuf, res, strlen (res) + 1);
611 GNUNET_free (res);
612 return rbuf;
613 }
614 GNUNET_break (0);
615 GNUNET_free (res);
616 return NULL;
617}
618
619
620int
621http_common_plugin_string_to_address (void *cls,
622 const char *addr,
623 uint16_t addrlen,
624 void **buf,
625 size_t *added)
626{
627 struct HttpAddress *a;
628 char *address;
629 char *plugin;
630 char *optionstr;
631 size_t urlen;
632 uint32_t options;
633
634 /* Format protocol.options.address:port */
635 address = NULL;
636 plugin = NULL;
637 optionstr = NULL;
638 if ((NULL == addr) || (addrlen == 0))
639 {
640 GNUNET_break (0);
641 return GNUNET_SYSERR;
642 }
643 if ('\0' != addr[addrlen - 1])
644 {
645 GNUNET_break (0);
646 return GNUNET_SYSERR;
647 }
648 if (strlen (addr) != addrlen - 1)
649 {
650 GNUNET_break (0);
651 return GNUNET_SYSERR;
652 }
653 plugin = GNUNET_strdup (addr);
654 optionstr = strchr (plugin, '.');
655 if (NULL == optionstr)
656 {
657 GNUNET_break (0);
658 GNUNET_free (plugin);
659 return GNUNET_SYSERR;
660 }
661 optionstr[0] = '\0';
662 optionstr++;
663 options = atol (optionstr); /* 0 on conversion error, that's ok */
664 address = strchr (optionstr, '.');
665 if (NULL == address)
666 {
667 GNUNET_break (0);
668 GNUNET_free (plugin);
669 return GNUNET_SYSERR;
670 }
671 address[0] = '\0';
672 address++;
673 urlen = strlen (address) + 1;
674
675 a = GNUNET_malloc (sizeof(struct HttpAddress) + urlen);
676 a->options = htonl (options);
677 a->urlen = htonl (urlen);
678 GNUNET_memcpy (&a[1], address, urlen);
679
680 (*buf) = a;
681 (*added) = sizeof(struct HttpAddress) + urlen;
682 GNUNET_free (plugin);
683 return GNUNET_OK;
684}
685
686
687struct HttpAddress *
688http_common_address_from_socket (const char *protocol,
689 const struct sockaddr *addr,
690 socklen_t addrlen)
691{
692 struct HttpAddress *address = NULL;
693 char *res;
694 size_t len;
695
696 GNUNET_asprintf (&res,
697 "%s://%s",
698 protocol,
699 GNUNET_a2s (addr,
700 addrlen));
701 len = strlen (res) + 1;
702 address = GNUNET_malloc (sizeof(struct HttpAddress) + len);
703 address->options = htonl (HTTP_OPTIONS_NONE);
704 address->urlen = htonl (len);
705 GNUNET_memcpy (&address[1], res, len);
706 GNUNET_free (res);
707 return address;
708}
709
710
711/**
712 * Create a socketaddr from a HTTP address
713 *
714 * @param addr a `sockaddr *` address
715 * @param addrlen length of the @a addr
716 * @param res the result:
717 * #GNUNET_SYSERR, invalid input,
718 * #GNUNET_YES: could convert to ip,
719 * #GNUNET_NO: valid input but could not convert to ip (hostname?)
720 * @return the string
721 */
722struct sockaddr *
723http_common_socket_from_address (const void *addr,
724 size_t addrlen,
725 int *res)
726{
727 const struct HttpAddress *ha;
728 struct SplittedHTTPAddress *spa;
729 struct sockaddr_storage *s;
730 char *to_conv;
731 size_t urlen;
732
733 (*res) = GNUNET_SYSERR;
734 ha = (const struct HttpAddress *) addr;
735 if (NULL == addr)
736 {
737 GNUNET_break (0);
738 return NULL;
739 }
740 if (0 == addrlen)
741 {
742 GNUNET_break (0);
743 return NULL;
744 }
745 if (addrlen < sizeof(struct HttpAddress))
746 {
747 GNUNET_break (0);
748 return NULL;
749 }
750 urlen = ntohl (ha->urlen);
751 if (sizeof(struct HttpAddress) + urlen != addrlen)
752 {
753 /* This is a legacy addresses */
754 return NULL;
755 }
756 if (addrlen < sizeof(struct HttpAddress) + urlen)
757 {
758 /* This is a legacy addresses */
759 return NULL;
760 }
761 if (((char *) addr)[addrlen - 1] != '\0')
762 {
763 GNUNET_break (0);
764 return NULL;
765 }
766 spa = http_split_address ((const char *) &ha[1]);
767 if (NULL == spa)
768 {
769 (*res) = GNUNET_SYSERR;
770 return NULL;
771 }
772
773 s = GNUNET_new (struct sockaddr_storage);
774 GNUNET_asprintf (&to_conv, "%s:%u", spa->host, spa->port);
775 if (GNUNET_SYSERR
776 == GNUNET_STRINGS_to_address_ip (to_conv, strlen (to_conv), s))
777 {
778 /* could be a hostname */
779 GNUNET_free (s);
780 (*res) = GNUNET_NO;
781 s = NULL;
782 }
783 else if ((AF_INET != s->ss_family) && (AF_INET6 != s->ss_family))
784 {
785 GNUNET_free (s);
786 (*res) = GNUNET_SYSERR;
787 s = NULL;
788 }
789 else
790 {
791 (*res) = GNUNET_YES;
792 }
793 http_clean_splitted (spa);
794 GNUNET_free (to_conv);
795 return (struct sockaddr *) s;
796}
797
798
799/**
800 * Get the length of an address
801 *
802 * @param addr address
803 * @return the size
804 */
805size_t
806http_common_address_get_size (const struct HttpAddress *addr)
807{
808 return sizeof(struct HttpAddress) + ntohl (addr->urlen);
809}
810
811
812/**
813 * Compare addr1 to addr2
814 *
815 * @param addr1 address1
816 * @param addrlen1 address 1 length
817 * @param addr2 address2
818 * @param addrlen2 address 2 length
819 * @return #GNUNET_YES if equal, #GNUNET_NO if not, #GNUNET_SYSERR on error
820 */
821size_t
822http_common_cmp_addresses (const void *addr1,
823 size_t addrlen1,
824 const void *addr2,
825 size_t addrlen2)
826{
827 const char *a1 = addr1;
828 const char *a2 = addr2;
829 const struct HttpAddress *ha1;
830 const struct HttpAddress *ha2;
831
832 ha1 = (const struct HttpAddress *) a1;
833 ha2 = (const struct HttpAddress *) a2;
834
835 if (NULL == a1)
836 return GNUNET_SYSERR;
837 if (0 == addrlen1)
838 return GNUNET_SYSERR;
839 if (a1[addrlen1 - 1] != '\0')
840 return GNUNET_SYSERR;
841
842 if (NULL == a2)
843 return GNUNET_SYSERR;
844 if (0 == addrlen2)
845 return GNUNET_SYSERR;
846 if (a2[addrlen2 - 1] != '\0')
847 return GNUNET_SYSERR;
848
849 if (addrlen1 != addrlen2)
850 return GNUNET_NO;
851 if (ha1->urlen != ha2->urlen)
852 return GNUNET_NO;
853
854 if (0 == strcmp ((const char *) &ha1[1], (const char *) &ha2[1]))
855 return GNUNET_YES;
856 return GNUNET_NO;
857}
858
859
860/**
861 * Function obtain the network type for an address.
862 *
863 * @param env the environment
864 * @param address the address
865 * @return the network type
866 */
867enum GNUNET_NetworkType
868http_common_get_network_for_address (struct
869 GNUNET_TRANSPORT_PluginEnvironment *env,
870 const struct GNUNET_HELLO_Address *address)
871{
872 struct sockaddr *sa;
873 enum GNUNET_NetworkType net_type;
874 size_t salen = 0;
875 int res;
876
877 net_type = GNUNET_NT_UNSPECIFIED;
878 sa = http_common_socket_from_address (address->address,
879 address->address_length,
880 &res);
881 if (GNUNET_SYSERR == res)
882 return net_type;
883 if (GNUNET_YES == res)
884 {
885 GNUNET_assert (NULL != sa);
886 if (AF_INET == sa->sa_family)
887 {
888 salen = sizeof(struct sockaddr_in);
889 }
890 else if (AF_INET6 == sa->sa_family)
891 {
892 salen = sizeof(struct sockaddr_in6);
893 }
894 net_type = env->get_address_type (env->cls,
895 sa,
896 salen);
897 GNUNET_free (sa);
898 }
899 return net_type;
900}
901
902
903/* end of plugin_transport_http_common.c */
diff --git a/src/transport/plugin_transport_http_common.h b/src/transport/plugin_transport_http_common.h
deleted file mode 100644
index 7a532249d..000000000
--- a/src/transport/plugin_transport_http_common.h
+++ /dev/null
@@ -1,272 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2002-2014 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport/plugin_transport_http_common.c
22 * @brief functionality shared by http client and server transport service plugin
23 * @author Matthias Wachs
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_common.h"
28#include "gnunet_transport_plugin.h"
29
30/**
31 * Timeout values for testing
32 */
33#define TESTING GNUNET_NO
34
35#if TESTING
36#define HTTP_SERVER_NOT_VALIDATED_TIMEOUT GNUNET_TIME_relative_multiply ( \
37 GNUNET_TIME_UNIT_SECONDS, 3)
38#define HTTP_CLIENT_NOT_VALIDATED_TIMEOUT GNUNET_TIME_relative_multiply ( \
39 GNUNET_TIME_UNIT_SECONDS, 3)
40#define HTTP_CLIENT_SESSION_TIMEOUT GNUNET_TIME_relative_multiply ( \
41 GNUNET_TIME_UNIT_SECONDS, 7)
42#define SERVER_SESSION_TIMEOUT GNUNET_TIME_relative_multiply ( \
43 GNUNET_TIME_UNIT_SECONDS, 7)
44#define TIMEOUT_LOG GNUNET_ERROR_TYPE_DEBUG
45
46#else
47
48#if BUILD_HTTPS
49#define PROTOCOL "https"
50#else
51#define PROTOCOL "http"
52#endif
53
54#define HTTP_SERVER_NOT_VALIDATED_TIMEOUT GNUNET_TIME_relative_multiply ( \
55 GNUNET_TIME_UNIT_SECONDS, 15)
56#define HTTP_CLIENT_NOT_VALIDATED_TIMEOUT GNUNET_TIME_relative_multiply ( \
57 GNUNET_TIME_UNIT_SECONDS, 15)
58#define HTTP_CLIENT_SESSION_TIMEOUT GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT
59#define HTTP_SERVER_SESSION_TIMEOUT GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT
60#define TIMEOUT_LOG GNUNET_ERROR_TYPE_DEBUG
61
62#endif
63
64#define HTTP_DEFAULT_PORT 80
65#define HTTPS_DEFAULT_PORT 443
66
67/**
68 * Bits in the `options` field of HTTP addresses.
69 */
70enum HttpAddressOptions
71{
72 /**
73 * No bits set.
74 */
75 HTTP_OPTIONS_NONE = 0,
76
77 /**
78 * Verify X509 server certificate, it should be valid.
79 * (if this bit is not set, it is probably just self-
80 * signed and not expected to be verified).
81 */
82 HTTP_OPTIONS_VERIFY_CERTIFICATE = 1,
83
84 /**
85 * Enable TCP Stealth-style port knocking.
86 */
87 HTTP_OPTIONS_TCP_STEALTH = 2
88};
89
90
91GNUNET_NETWORK_STRUCT_BEGIN
92
93/**
94 * HttpAddress
95 */
96struct HttpAddress
97{
98 /**
99 * Address options
100 * see `enum HttpAddressOptions`
101 */
102 uint32_t options GNUNET_PACKED;
103
104 /**
105 * Length of URL located after struct
106 */
107 uint32_t urlen GNUNET_PACKED;
108};
109
110GNUNET_NETWORK_STRUCT_END
111
112/**
113 * Representation of HTTP URL split into its components.
114 */
115struct SplittedHTTPAddress
116{
117 char *protocol;
118 char *host;
119 char *path;
120 int port;
121};
122
123
124/**
125 * Split an HTTP address into protocol, hostname, port
126 * and path components.
127 */
128struct SplittedHTTPAddress *
129http_split_address (const char *addr);
130
131
132/**
133 * Convert the transports address to a nice, human-readable
134 * format.
135 *
136 * @param cls closure
137 * @param type name of the transport that generated the address
138 * @param addr one of the addresses of the host, NULL for the last address
139 * the specific address format depends on the transport
140 * @param addrlen length of @a addr
141 * @param numeric should (IP) addresses be displayed in numeric form?
142 * @param timeout after how long should we give up?
143 * @param asc function to call on each string
144 * @param asc_cls closure for @a asc
145 */
146void
147http_common_plugin_address_pretty_printer (void *cls,
148 const char *type,
149 const void *addr,
150 size_t addrlen,
151 int numeric,
152 struct GNUNET_TIME_Relative timeout,
153 GNUNET_TRANSPORT_AddressStringCallback
154 asc,
155 void *asc_cls);
156
157
158/**
159 * Function called for a quick conversion of the binary address to
160 * a numeric address. Note that the caller must not free the
161 * address and that the next call to this function is allowed
162 * to override the address again.
163 *
164 * @param plugin name of the plugin
165 * @param addr binary address
166 * @param addrlen length of @a addr
167 * @return string representing the same address
168 */
169const char *
170http_common_plugin_address_to_string (const char *plugin,
171 const void *addr,
172 size_t addrlen);
173
174
175/**
176 * Function called to convert a string address to
177 * a binary address.
178 *
179 * @param cls closure (`struct Plugin*`)
180 * @param addr string address
181 * @param addrlen length of @a addr
182 * @param buf location to store the buffer
183 * If the function returns #GNUNET_SYSERR, its contents are undefined.
184 * @param added length of created address
185 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
186 */
187int
188http_common_plugin_string_to_address (void *cls,
189 const char *addr,
190 uint16_t addrlen,
191 void **buf,
192 size_t *added);
193
194
195/**
196 * Create a HTTP address from a socketaddr
197 *
198 * @param protocol protocol
199 * @param addr `sockaddr *` address
200 * @param addrlen length of the @a addr
201 * @return A pointer to a `struct HttpAddress` derived from @a addr
202 */
203struct HttpAddress *
204http_common_address_from_socket (const char *protocol,
205 const struct sockaddr *addr,
206 socklen_t addrlen);
207
208
209/**
210 * Create a socketaddr from a HTTP address
211 *
212 * @param addr a `sockaddr *` address
213 * @param addrlen length of the @a addr
214 * @param res the result:
215 * #GNUNET_SYSERR, invalid input,
216 * #GNUNET_YES: could convert to ip,
217 * #GNUNET_NO: valid input but could not convert to ip (hostname?)
218 * @return the string
219 */
220struct sockaddr *
221http_common_socket_from_address (const void *addr,
222 size_t addrlen,
223 int *res);
224
225
226const char *
227http_common_plugin_address_to_url (void *cls,
228 const void *addr,
229 size_t addrlen);
230
231
232/**
233 * Get the length of an address
234 *
235 * @param addr address
236 * @return the size
237 */
238size_t
239http_common_address_get_size (const struct HttpAddress *addr);
240
241
242/**
243 * Compare addr1 to addr2
244 *
245 * @param addr1 address1
246 * @param addrlen1 length of @a address1
247 * @param addr2 address2
248 * @param addrlen2 length of @a address2
249 * @return #GNUNET_YES if equal, #GNUNET_NO else
250 */
251size_t
252http_common_cmp_addresses (const void *addr1,
253 size_t addrlen1,
254 const void *addr2,
255 size_t addrlen2);
256
257
258/**
259 * Function obtain the network type for an address.
260 *
261 * @param env the environment
262 * @param address the address
263 * @return the network type
264 */
265enum GNUNET_NetworkType
266http_common_get_network_for_address (struct
267 GNUNET_TRANSPORT_PluginEnvironment *env,
268 const struct
269 GNUNET_HELLO_Address *address);
270
271
272/* end of plugin_transport_http_common.h */
diff --git a/src/transport/plugin_transport_http_server.c b/src/transport/plugin_transport_http_server.c
deleted file mode 100644
index 3ad2356b0..000000000
--- a/src/transport/plugin_transport_http_server.c
+++ /dev/null
@@ -1,3603 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2002-2014, 2017 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/plugin_transport_http_server.c
23 * @brief HTTP/S server transport plugin
24 * @author Matthias Wachs
25 * @author David Barksdale
26 * @author Christian Grothoff
27 */
28#include "platform.h"
29#include "gnunet_util_lib.h"
30#include "gnunet_statistics_service.h"
31#include "gnunet_transport_plugin.h"
32#include "gnunet_nat_service.h"
33#include "plugin_transport_http_common.h"
34#include <microhttpd.h>
35#include <regex.h>
36#include "gnunet_mhd_compat.h"
37
38#if BUILD_HTTPS
39#define PLUGIN_NAME "https_server"
40#define LIBGNUNET_PLUGIN_TRANSPORT_INIT \
41 libgnunet_plugin_transport_https_server_init
42#define LIBGNUNET_PLUGIN_TRANSPORT_DONE \
43 libgnunet_plugin_transport_https_server_done
44#else
45#define PLUGIN_NAME "http_server"
46#define LIBGNUNET_PLUGIN_TRANSPORT_INIT \
47 libgnunet_plugin_transport_http_server_init
48#define LIBGNUNET_PLUGIN_TRANSPORT_DONE \
49 libgnunet_plugin_transport_http_server_done
50#endif
51
52#define HTTP_ERROR_RESPONSE \
53 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\"><HTML><HEAD><TITLE>404 Not Found</TITLE></HEAD><BODY><H1>Not Found</H1>The requested URL was not found on this server.<P><HR><ADDRESS></ADDRESS></BODY></HTML>"
54#define _RECEIVE 0
55#define _SEND 1
56
57
58#define LOG(kind, ...) GNUNET_log_from (kind, "transport-" PLUGIN_NAME, \
59 __VA_ARGS__)
60
61
62/**
63 * Information we keep with MHD for an HTTP request.
64 */
65struct ServerRequest
66{
67 /**
68 * The session this server request belongs to
69 * Can be NULL, when session was disconnected and freed
70 */
71 struct GNUNET_ATS_Session *session;
72
73 /**
74 * The MHD connection
75 */
76 struct MHD_Connection *mhd_conn;
77
78 /**
79 * The MHD daemon
80 */
81 struct MHD_Daemon *mhd_daemon;
82
83 /**
84 * Options requested by peer
85 */
86 uint32_t options;
87#define OPTION_LONG_POLL 1 /* GET request wants long-poll semantics */
88
89 /**
90 * _RECV or _SEND
91 */
92 int direction;
93
94 /**
95 * For PUT requests: Is this the first or last callback with size 0
96 * For GET requests: Have we sent a message
97 */
98 int connected;
99
100 /**
101 * Currently suspended
102 */
103 bool suspended;
104};
105
106
107/**
108 * Wrapper to manage addresses
109 */
110struct HttpAddressWrapper
111{
112 /**
113 * Linked list next
114 */
115 struct HttpAddressWrapper *next;
116
117 /**
118 * Linked list previous
119 */
120 struct HttpAddressWrapper *prev;
121
122 /**
123 * An address we are using.
124 */
125 struct HttpAddress *address;
126
127 /**
128 * Length of the address.
129 */
130 size_t addrlen;
131};
132
133
134/**
135 * Message to send using http
136 */
137struct HTTP_Message
138{
139 /**
140 * next pointer for double linked list
141 */
142 struct HTTP_Message *next;
143
144 /**
145 * previous pointer for double linked list
146 */
147 struct HTTP_Message *prev;
148
149 /**
150 * buffer containing data to send
151 */
152 char *buf;
153
154 /**
155 * amount of data already sent
156 */
157 size_t pos;
158
159 /**
160 * buffer length
161 */
162 size_t size;
163
164 /**
165 * HTTP/S specific overhead
166 */
167 size_t overhead;
168
169 /**
170 * Continuation function to call once the transmission buffer
171 * has again space available. NULL if there is no
172 * continuation to call.
173 */
174 GNUNET_TRANSPORT_TransmitContinuation transmit_cont;
175
176 /**
177 * Closure for transmit_cont.
178 */
179 void *transmit_cont_cls;
180};
181
182
183/**
184 * Session handle for connections.
185 */
186struct GNUNET_ATS_Session
187{
188 /**
189 * To whom are we talking to (set to our identity
190 * if we are still waiting for the welcome message)
191 */
192 struct GNUNET_PeerIdentity target;
193
194 /**
195 * Pointer to the global plugin struct.
196 */
197 struct HTTP_Server_Plugin *plugin;
198
199 /**
200 * next pointer for double linked list
201 */
202 struct HTTP_Message *msg_head;
203
204 /**
205 * previous pointer for double linked list
206 */
207 struct HTTP_Message *msg_tail;
208
209 /**
210 * Message stream tokenizer for incoming data
211 */
212 struct GNUNET_MessageStreamTokenizer *msg_tk;
213
214 /**
215 * Client recv handle
216 */
217 struct ServerRequest *server_recv;
218
219 /**
220 * Client send handle
221 */
222 struct ServerRequest *server_send;
223
224 /**
225 * Address
226 */
227 struct GNUNET_HELLO_Address *address;
228
229 /**
230 * Absolute time when to receive data again
231 * Used for receive throttling
232 */
233 struct GNUNET_TIME_Absolute next_receive;
234
235 /**
236 * Absolute time when this connection will time out.
237 */
238 struct GNUNET_TIME_Absolute timeout;
239
240 /**
241 * Session timeout task
242 */
243 struct GNUNET_SCHEDULER_Task *timeout_task;
244
245 /**
246 * Task to resume MHD handling when receiving is allowed again
247 */
248 struct GNUNET_SCHEDULER_Task *recv_wakeup_task;
249
250 /**
251 * Number of bytes waiting for transmission to this peer.
252 */
253 unsigned long long bytes_in_queue;
254
255 /**
256 * Number of messages waiting for transmission to this peer.
257 */
258 unsigned int msgs_in_queue;
259
260 /**
261 * Unique HTTP/S connection tag for this connection
262 */
263 uint32_t tag;
264
265 /**
266 * ATS network type.
267 */
268 enum GNUNET_NetworkType scope;
269
270 /**
271 * #GNUNET_YES if this session is known to the service.
272 */
273 int known_to_service;
274};
275
276
277/**
278 * Encapsulation of all of the state of the plugin.
279 */
280struct HTTP_Server_Plugin
281{
282 /**
283 * Our environment.
284 */
285 struct GNUNET_TRANSPORT_PluginEnvironment *env;
286
287 /**
288 * Hash map of open sessions.
289 */
290 struct GNUNET_CONTAINER_MultiPeerMap *sessions;
291
292 /**
293 * Function to call about session status changes.
294 */
295 GNUNET_TRANSPORT_SessionInfoCallback sic;
296
297 /**
298 * Closure for @e sic.
299 */
300 void *sic_cls;
301
302 /**
303 * Plugin name
304 */
305 char *name;
306
307 /**
308 * Protocol
309 */
310 char *protocol;
311
312 /**
313 * External address
314 */
315 char *external_hostname;
316
317 /**
318 * External hostname the plugin can be connected to, can be different to
319 * the host's FQDN, used e.g. for reverse proxying
320 */
321 struct GNUNET_HELLO_Address *ext_addr;
322
323 /**
324 * NAT handle & address management
325 */
326 struct GNUNET_NAT_Handle *nat;
327
328 /**
329 * IPv4 addresses DLL head
330 */
331 struct HttpAddressWrapper *addr_head;
332
333 /**
334 * IPv4 addresses DLL tail
335 */
336 struct HttpAddressWrapper *addr_tail;
337
338 /**
339 * IPv4 server socket to bind to
340 */
341 struct sockaddr_in *server_addr_v4;
342
343 /**
344 * IPv6 server socket to bind to
345 */
346 struct sockaddr_in6 *server_addr_v6;
347
348 /**
349 * MHD IPv4 daemon
350 */
351 struct MHD_Daemon *server_v4;
352
353 /**
354 * MHD IPv4 daemon
355 */
356 struct MHD_Daemon *server_v6;
357
358#if BUILD_HTTPS
359 /**
360 * Crypto related
361 *
362 * Example:
363 *
364 * Use RC4-128 instead of AES:
365 * NONE:+VERS-TLS1.0:+ARCFOUR-128:+SHA1:+RSA:+COMP-NULL
366 *
367 */
368 char *crypto_init;
369
370 /**
371 * TLS key
372 */
373 char *key;
374
375 /**
376 * TLS certificate
377 */
378 char *cert;
379#endif
380
381 /**
382 * MHD IPv4 task
383 */
384 struct GNUNET_SCHEDULER_Task *server_v4_task;
385
386 /**
387 * MHD IPv6 task
388 */
389 struct GNUNET_SCHEDULER_Task *server_v6_task;
390
391 /**
392 * Task calling transport service about external address
393 */
394 struct GNUNET_SCHEDULER_Task *notify_ext_task;
395
396 /**
397 * Notify transport only about external address
398 */
399 unsigned int external_only;
400
401 /**
402 * The IPv4 server is scheduled to run asap
403 */
404 int server_v4_immediately;
405
406 /**
407 * The IPv6 server is scheduled to run asap
408 */
409 int server_v6_immediately;
410
411 /**
412 * Verify external address
413 */
414 int verify_external_hostname;
415
416 /**
417 * Maximum number of sockets the plugin can use
418 * Each http request /request connections are two connections
419 */
420 unsigned int max_request;
421
422 /**
423 * Current number of sockets the plugin can use
424 * Each http connection are two requests
425 */
426 unsigned int cur_request;
427
428 /**
429 * Did we immediately end the session in disconnect_cb
430 */
431 int in_shutdown;
432
433 /**
434 * Length of peer id
435 */
436 int peer_id_length;
437
438 /**
439 * My options to be included in the address
440 */
441 uint32_t options;
442
443 /**
444 * use IPv6
445 */
446 uint16_t use_ipv6;
447
448 /**
449 * use IPv4
450 */
451 uint16_t use_ipv4;
452
453 /**
454 * Port used
455 */
456 uint16_t port;
457
458 /**
459 * Regex for parsing URLs. FIXME: this seems overkill.
460 */
461 regex_t url_regex;
462};
463
464
465/**
466 * If a session monitor is attached, notify it about the new
467 * session state.
468 *
469 * @param plugin our plugin
470 * @param session session that changed state
471 * @param state new state of the session
472 */
473static void
474notify_session_monitor (struct HTTP_Server_Plugin *plugin,
475 struct GNUNET_ATS_Session *session,
476 enum GNUNET_TRANSPORT_SessionState state)
477{
478 struct GNUNET_TRANSPORT_SessionInfo info;
479
480 if (NULL == plugin->sic)
481 return;
482 memset (&info, 0, sizeof(info));
483 info.state = state;
484 info.is_inbound = GNUNET_YES;
485 info.num_msg_pending = session->msgs_in_queue;
486 info.num_bytes_pending = session->bytes_in_queue;
487 info.receive_delay = session->next_receive;
488 info.session_timeout = session->timeout;
489 info.address = session->address;
490 plugin->sic (plugin->sic_cls,
491 session,
492 &info);
493}
494
495
496/**
497 * Wake up an MHD connection which was suspended
498 *
499 * @param cls the session
500 */
501static void
502server_wake_up (void *cls)
503{
504 struct GNUNET_ATS_Session *s = cls;
505
506 s->recv_wakeup_task = NULL;
507 LOG (GNUNET_ERROR_TYPE_DEBUG,
508 "Session %p: Waking up PUT handle\n",
509 s);
510 GNUNET_assert (s->server_recv->suspended);
511 MHD_resume_connection (s->server_recv->mhd_conn);
512 s->server_recv->suspended = false;
513}
514
515
516/**
517 * Reschedule the execution of both IPv4 and IPv6 server.
518 *
519 * @param plugin the plugin
520 * @param server which server to schedule v4 or v6?
521 * @param now #GNUNET_YES to schedule execution immediately, #GNUNET_NO to wait
522 * until timeout
523 */
524static void
525server_reschedule (struct HTTP_Server_Plugin *plugin,
526 struct MHD_Daemon *server,
527 int now);
528
529
530/**
531 * Deletes the session. Must not be used afterwards.
532 *
533 * @param s the session to delete
534 */
535static void
536server_delete_session (struct GNUNET_ATS_Session *s)
537{
538 struct HTTP_Server_Plugin *plugin = s->plugin;
539 struct HTTP_Message *msg;
540
541 if (NULL != s->timeout_task)
542 {
543 GNUNET_SCHEDULER_cancel (s->timeout_task);
544 s->timeout_task = NULL;
545 s->timeout = GNUNET_TIME_UNIT_ZERO_ABS;
546 }
547 if (NULL != s->recv_wakeup_task)
548 {
549 GNUNET_SCHEDULER_cancel (s->recv_wakeup_task);
550 s->recv_wakeup_task = NULL;
551 if (NULL != s->server_recv)
552 {
553 GNUNET_assert (s->server_recv->suspended);
554 s->server_recv->suspended = false;
555 MHD_resume_connection (s->server_recv->mhd_conn);
556 }
557 }
558 GNUNET_assert (GNUNET_OK ==
559 GNUNET_CONTAINER_multipeermap_remove (plugin->sessions,
560 &s->target,
561 s));
562 while (NULL != (msg = s->msg_head))
563 {
564 GNUNET_CONTAINER_DLL_remove (s->msg_head,
565 s->msg_tail,
566 msg);
567 if (NULL != msg->transmit_cont)
568 msg->transmit_cont (msg->transmit_cont_cls,
569 &s->target,
570 GNUNET_SYSERR,
571 msg->size,
572 msg->pos + msg->overhead);
573 GNUNET_assert (s->msgs_in_queue > 0);
574 s->msgs_in_queue--;
575 GNUNET_assert (s->bytes_in_queue >= msg->size);
576 s->bytes_in_queue -= msg->size;
577 GNUNET_free (msg);
578 }
579
580 GNUNET_assert (0 == s->msgs_in_queue);
581 GNUNET_assert (0 == s->bytes_in_queue);
582
583 if (NULL != s->server_send)
584 {
585 LOG (GNUNET_ERROR_TYPE_DEBUG,
586 "Server: %p / %p Terminating inbound PUT session to peer `%s'\n",
587 s, s->server_send,
588 GNUNET_i2s (&s->target));
589 s->server_send->session = NULL;
590 MHD_set_connection_option (s->server_send->mhd_conn,
591 MHD_CONNECTION_OPTION_TIMEOUT,
592 1 /* 0 = no timeout, so this is MIN */);
593 if (s->server_send->suspended)
594 {
595 s->server_send->suspended = false;
596 MHD_resume_connection (s->server_send->mhd_conn);
597 }
598 server_reschedule (plugin,
599 s->server_send->mhd_daemon,
600 GNUNET_YES);
601 }
602
603 if (NULL != s->server_recv)
604 {
605 LOG (GNUNET_ERROR_TYPE_DEBUG,
606 "Server: %p / %p Terminating inbound GET session to peer `%s'\n",
607 s, s->server_recv, GNUNET_i2s (&s->target));
608 s->server_recv->session = NULL;
609 MHD_set_connection_option (s->server_recv->mhd_conn,
610 MHD_CONNECTION_OPTION_TIMEOUT,
611 1 /* 0 = no timeout, so this is MIN */);
612 server_reschedule (plugin,
613 s->server_recv->mhd_daemon,
614 GNUNET_YES);
615 }
616 notify_session_monitor (plugin,
617 s,
618 GNUNET_TRANSPORT_SS_DONE);
619 if (GNUNET_YES == s->known_to_service)
620 {
621 plugin->env->session_end (plugin->env->cls,
622 s->address,
623 s);
624 s->known_to_service = GNUNET_NO;
625 }
626 if (NULL != s->msg_tk)
627 {
628 GNUNET_MST_destroy (s->msg_tk);
629 s->msg_tk = NULL;
630 }
631 GNUNET_HELLO_address_free (s->address);
632 LOG (GNUNET_ERROR_TYPE_DEBUG,
633 "Session %p destroyed\n",
634 s);
635 GNUNET_free (s);
636}
637
638
639/**
640 * Disconnect session @a s by telling MHD to close the
641 * connections (reducing timeout, etc.).
642 *
643 * @param cls closure with the `struct HTTP_Server_Plugin`
644 * @param s the session
645 * @return #GNUNET_OK on success
646 */
647static int
648http_server_plugin_disconnect_session (void *cls,
649 struct GNUNET_ATS_Session *s)
650{
651 server_delete_session (s);
652 return GNUNET_OK;
653}
654
655
656/**
657 * Session was idle, so disconnect it
658 *
659 * @param cls the session
660 */
661static void
662server_session_timeout (void *cls)
663{
664 struct GNUNET_ATS_Session *s = cls;
665 struct GNUNET_TIME_Relative left;
666
667 s->timeout_task = NULL;
668 left = GNUNET_TIME_absolute_get_remaining (s->timeout);
669 if (0 != left.rel_value_us)
670 {
671 /* not actually our turn yet, but let's at least update
672 the monitor, it may think we're about to die ... */
673 notify_session_monitor (s->plugin,
674 s,
675 GNUNET_TRANSPORT_SS_UP);
676 s->timeout_task = GNUNET_SCHEDULER_add_delayed (left,
677 &server_session_timeout,
678 s);
679 return;
680 }
681 GNUNET_log (TIMEOUT_LOG,
682 "Session %p was idle for %s, disconnecting\n",
683 s,
684 GNUNET_STRINGS_relative_time_to_string (
685 HTTP_SERVER_SESSION_TIMEOUT,
686 GNUNET_YES));
687 server_delete_session (s);
688}
689
690
691/**
692 * Increment session timeout due to activity session @a s
693 *
694 * @param s the session
695 */
696static void
697server_reschedule_session_timeout (struct GNUNET_ATS_Session *s)
698{
699 GNUNET_assert (NULL != s->timeout_task);
700 s->timeout = GNUNET_TIME_relative_to_absolute (
701 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
702}
703
704
705/**
706 * Function that can be used by the transport service to transmit
707 * a message using the plugin. Note that in the case of a
708 * peer disconnecting, the continuation MUST be called
709 * prior to the disconnect notification itself. This function
710 * will be called with this peer's HELLO message to initiate
711 * a fresh connection to another peer.
712 *
713 * @param cls closure
714 * @param session which session must be used
715 * @param msgbuf the message to transmit
716 * @param msgbuf_size number of bytes in @a msgbuf
717 * @param priority how important is the message (most plugins will
718 * ignore message priority and just FIFO)
719 * @param to how long to wait at most for the transmission (does not
720 * require plugins to discard the message after the timeout,
721 * just advisory for the desired delay; most plugins will ignore
722 * this as well)
723 * @param cont continuation to call once the message has
724 * been transmitted (or if the transport is ready
725 * for the next transmission call; or if the
726 * peer disconnected...); can be NULL
727 * @param cont_cls closure for @a cont
728 * @return number of bytes used (on the physical network, with overheads);
729 * -1 on hard errors (i.e. address invalid); 0 is a legal value
730 * and does NOT mean that the message was not transmitted (DV)
731 */
732static ssize_t
733http_server_plugin_send (void *cls,
734 struct GNUNET_ATS_Session *session,
735 const char *msgbuf,
736 size_t msgbuf_size,
737 unsigned int priority,
738 struct GNUNET_TIME_Relative to,
739 GNUNET_TRANSPORT_TransmitContinuation cont,
740 void *cont_cls)
741{
742 struct HTTP_Server_Plugin *plugin = cls;
743 struct HTTP_Message *msg;
744 ssize_t bytes_sent = 0;
745 char *stat_txt;
746
747 LOG (GNUNET_ERROR_TYPE_DEBUG,
748 "Session %p/request %p: Sending message with %lu to peer `%s'\n",
749 session,
750 session->server_send,
751 (unsigned long) msgbuf_size,
752 GNUNET_i2s (&session->target));
753
754 /* create new message and schedule */
755 bytes_sent = sizeof(struct HTTP_Message) + msgbuf_size;
756 msg = GNUNET_malloc (bytes_sent);
757 msg->next = NULL;
758 msg->size = msgbuf_size;
759 msg->pos = 0;
760 msg->buf = (char *) &msg[1];
761 msg->transmit_cont = cont;
762 msg->transmit_cont_cls = cont_cls;
763 GNUNET_memcpy (msg->buf,
764 msgbuf,
765 msgbuf_size);
766 GNUNET_CONTAINER_DLL_insert_tail (session->msg_head,
767 session->msg_tail,
768 msg);
769 session->msgs_in_queue++;
770 session->bytes_in_queue += msg->size;
771 notify_session_monitor (plugin,
772 session,
773 GNUNET_TRANSPORT_SS_UP);
774 GNUNET_asprintf (&stat_txt,
775 "# bytes currently in %s_server buffers",
776 plugin->protocol);
777 GNUNET_STATISTICS_update (plugin->env->stats,
778 stat_txt, msgbuf_size, GNUNET_NO);
779 GNUNET_free (stat_txt);
780
781 if (NULL != session->server_send)
782 {
783 if (session->server_send->suspended)
784 {
785 MHD_resume_connection (session->server_send->mhd_conn);
786 session->server_send->suspended = false;
787 }
788 server_reschedule (session->plugin,
789 session->server_send->mhd_daemon,
790 GNUNET_YES);
791 }
792 return bytes_sent;
793}
794
795
796/**
797 * Terminate session during shutdown.
798 *
799 * @param cls the `struct HTTP_Server_Plugin *`
800 * @param peer for which this is a session
801 * @param value the `struct GNUNET_ATS_Session` to clean up
802 * @return #GNUNET_OK (continue to iterate)
803 */
804static int
805destroy_session_shutdown_cb (void *cls,
806 const struct GNUNET_PeerIdentity *peer,
807 void *value)
808{
809 struct GNUNET_ATS_Session *s = value;
810 struct ServerRequest *sc_send;
811 struct ServerRequest *sc_recv;
812
813 sc_send = s->server_send;
814 sc_recv = s->server_recv;
815 server_delete_session (s);
816 if (NULL != sc_send)
817 sc_send->session = NULL;
818 if (NULL != sc_recv)
819 sc_recv->session = NULL;
820
821 return GNUNET_OK;
822}
823
824
825/**
826 * Terminate session.
827 *
828 * @param cls the `struct HTTP_Server_Plugin *`
829 * @param peer for which this is a session
830 * @param value the `struct GNUNET_ATS_Session` to clean up
831 * @return #GNUNET_OK (continue to iterate)
832 */
833static int
834destroy_session_cb (void *cls,
835 const struct GNUNET_PeerIdentity *peer,
836 void *value)
837{
838 struct GNUNET_ATS_Session *s = value;
839
840 server_delete_session (s);
841 return GNUNET_OK;
842}
843
844
845/**
846 * Function that can be used to force the plugin to disconnect
847 * from the given peer and cancel all previous transmissions
848 * (and their continuationc).
849 *
850 * @param cls closure
851 * @param target peer from which to disconnect
852 */
853static void
854http_server_plugin_disconnect_peer (void *cls,
855 const struct GNUNET_PeerIdentity *target)
856{
857 struct HTTP_Server_Plugin *plugin = cls;
858
859 LOG (GNUNET_ERROR_TYPE_DEBUG,
860 "Transport tells me to disconnect `%s'\n",
861 GNUNET_i2s (target));
862 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessions,
863 target,
864 &destroy_session_cb,
865 plugin);
866}
867
868
869/**
870 * Another peer has suggested an address for this
871 * peer and transport plugin. Check that this could be a valid
872 * address. If so, consider adding it to the list
873 * of addresses.
874 *
875 * @param cls closure
876 * @param addr pointer to the address
877 * @param addrlen length of @a addr
878 * @return #GNUNET_OK if this is a plausible address for this peer
879 * and transport
880 */
881static int
882http_server_plugin_address_suggested (void *cls,
883 const void *addr,
884 size_t addrlen)
885{
886 struct HTTP_Server_Plugin *plugin = cls;
887 struct HttpAddressWrapper *next;
888 struct HttpAddressWrapper *pos;
889 const struct HttpAddress *haddr = addr;
890
891 if ((NULL != plugin->ext_addr) &&
892 (GNUNET_YES == (http_common_cmp_addresses (addr, addrlen,
893 plugin->ext_addr->address,
894 plugin->ext_addr->
895 address_length))) )
896 {
897 /* Checking HTTP_OPTIONS_VERIFY_CERTIFICATE option for external hostname */
898 if ((ntohl (haddr->options) & HTTP_OPTIONS_VERIFY_CERTIFICATE) !=
899 (plugin->options & HTTP_OPTIONS_VERIFY_CERTIFICATE))
900 return GNUNET_NO; /* VERIFY option not set as required! */
901 return GNUNET_OK;
902 }
903 next = plugin->addr_head;
904 while (NULL != (pos = next))
905 {
906 next = pos->next;
907 if (GNUNET_YES == (http_common_cmp_addresses (addr,
908 addrlen,
909 pos->address,
910 pos->addrlen)))
911 return GNUNET_OK;
912 }
913 return GNUNET_NO;
914}
915
916
917/**
918 * Creates a new outbound session the transport
919 * service will use to send data to the peer.
920 *
921 * Since HTTP/S server cannot create sessions, always returns NULL.
922 *
923 * @param cls the plugin
924 * @param address the address
925 * @return always NULL
926 */
927static struct GNUNET_ATS_Session *
928http_server_plugin_get_session (void *cls,
929 const struct GNUNET_HELLO_Address *address)
930{
931 return NULL;
932}
933
934
935/**
936 * Call MHD IPv4 to process pending requests and then go back
937 * and schedule the next run.
938 *
939 * @param cls plugin as closure
940 */
941static void
942server_v4_run (void *cls)
943{
944 struct HTTP_Server_Plugin *plugin = cls;
945
946 plugin->server_v4_task = NULL;
947 plugin->server_v4_immediately = GNUNET_NO;
948 GNUNET_assert (MHD_YES == MHD_run (plugin->server_v4));
949 server_reschedule (plugin, plugin->server_v4, GNUNET_NO);
950}
951
952
953/**
954 * Call MHD IPv6 to process pending requests and then go back
955 * and schedule the next run.
956 *
957 * @param cls plugin as closure
958 */
959static void
960server_v6_run (void *cls)
961{
962 struct HTTP_Server_Plugin *plugin = cls;
963
964 plugin->server_v6_task = NULL;
965 plugin->server_v6_immediately = GNUNET_NO;
966 GNUNET_assert (MHD_YES == MHD_run (plugin->server_v6));
967 server_reschedule (plugin, plugin->server_v6, GNUNET_NO);
968}
969
970
971/**
972 * Function that queries MHD's select sets and
973 * starts the task waiting for them.
974 *
975 * @param plugin plugin
976 * @param daemon_handle the MHD daemon handle
977 * @param now schedule now
978 * @return gnunet task identifier
979 */
980static struct GNUNET_SCHEDULER_Task *
981server_schedule (struct HTTP_Server_Plugin *plugin,
982 struct MHD_Daemon *daemon_handle,
983 int now)
984{
985 struct GNUNET_SCHEDULER_Task *ret;
986 fd_set rs;
987 fd_set ws;
988 fd_set es;
989 struct GNUNET_NETWORK_FDSet *wrs;
990 struct GNUNET_NETWORK_FDSet *wws;
991 int max;
992 MHD_UNSIGNED_LONG_LONG timeout;
993 static unsigned long long last_timeout = 0;
994 int haveto;
995 struct GNUNET_TIME_Relative tv;
996
997 if (GNUNET_YES == plugin->in_shutdown)
998 return NULL;
999
1000 ret = NULL;
1001 FD_ZERO (&rs);
1002 FD_ZERO (&ws);
1003 FD_ZERO (&es);
1004 wrs = GNUNET_NETWORK_fdset_create ();
1005 wws = GNUNET_NETWORK_fdset_create ();
1006 max = -1;
1007 GNUNET_assert (MHD_YES ==
1008 MHD_get_fdset (daemon_handle,
1009 &rs,
1010 &ws,
1011 &es,
1012 &max));
1013 haveto = MHD_get_timeout (daemon_handle, &timeout);
1014 if (haveto == MHD_YES)
1015 {
1016 if (timeout != last_timeout)
1017 {
1018 LOG (GNUNET_ERROR_TYPE_DEBUG,
1019 "SELECT Timeout changed from %llu to %llu (ms)\n",
1020 last_timeout, timeout);
1021 last_timeout = timeout;
1022 }
1023 if (timeout <= GNUNET_TIME_UNIT_SECONDS.rel_value_us / 1000LL)
1024 tv.rel_value_us = (uint64_t) timeout * 1000LL;
1025 else
1026 tv = GNUNET_TIME_UNIT_SECONDS;
1027 }
1028 else
1029 tv = GNUNET_TIME_UNIT_SECONDS;
1030 /* Force immediate run, since we have outbound data to send */
1031 if (now == GNUNET_YES)
1032 tv = GNUNET_TIME_UNIT_MILLISECONDS;
1033 GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1);
1034 GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1);
1035
1036 if (daemon_handle == plugin->server_v4)
1037 {
1038 if (plugin->server_v4_task != NULL)
1039 {
1040 GNUNET_SCHEDULER_cancel (plugin->server_v4_task);
1041 plugin->server_v4_task = NULL;
1042 }
1043#if 0
1044 LOG (GNUNET_ERROR_TYPE_DEBUG,
1045 "Scheduling IPv4 server task in %llu ms\n",
1046 tv);
1047#endif
1048 ret =
1049 GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1050 tv, wrs, wws,
1051 &server_v4_run, plugin);
1052 }
1053 if (daemon_handle == plugin->server_v6)
1054 {
1055 if (plugin->server_v6_task != NULL)
1056 {
1057 GNUNET_SCHEDULER_cancel (plugin->server_v6_task);
1058 plugin->server_v6_task = NULL;
1059 }
1060#if 0
1061 LOG (GNUNET_ERROR_TYPE_DEBUG,
1062 "Scheduling IPv6 server task in %llu ms\n", tv);
1063#endif
1064 ret =
1065 GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1066 tv, wrs, wws,
1067 &server_v6_run, plugin);
1068 }
1069 GNUNET_NETWORK_fdset_destroy (wrs);
1070 GNUNET_NETWORK_fdset_destroy (wws);
1071 return ret;
1072}
1073
1074
1075/**
1076 * Reschedule the execution of both IPv4 and IPv6 server
1077 *
1078 * @param plugin the plugin
1079 * @param server which server to schedule v4 or v6?
1080 * @param now #GNUNET_YES to schedule execution immediately, #GNUNET_NO to wait
1081 * until timeout
1082 */
1083static void
1084server_reschedule (struct HTTP_Server_Plugin *plugin,
1085 struct MHD_Daemon *server,
1086 int now)
1087{
1088 if ((server == plugin->server_v4) && (plugin->server_v4 != NULL))
1089 {
1090 if (GNUNET_YES == plugin->server_v4_immediately)
1091 return; /* No rescheduling, server will run asap */
1092
1093 if (GNUNET_YES == now)
1094 plugin->server_v4_immediately = GNUNET_YES;
1095
1096 if (plugin->server_v4_task != NULL)
1097 {
1098 GNUNET_SCHEDULER_cancel (plugin->server_v4_task);
1099 plugin->server_v4_task = NULL;
1100 }
1101 plugin->server_v4_task = server_schedule (plugin, plugin->server_v4, now);
1102 }
1103
1104 if ((server == plugin->server_v6) && (plugin->server_v6 != NULL))
1105 {
1106 if (GNUNET_YES == plugin->server_v6_immediately)
1107 return; /* No rescheduling, server will run asap */
1108
1109 if (GNUNET_YES == now)
1110 plugin->server_v6_immediately = GNUNET_YES;
1111
1112 if (plugin->server_v6_task != NULL)
1113 {
1114 GNUNET_SCHEDULER_cancel (plugin->server_v6_task);
1115 plugin->server_v6_task = NULL;
1116 }
1117 plugin->server_v6_task = server_schedule (plugin, plugin->server_v6, now);
1118 }
1119}
1120
1121
1122/**
1123 * Function that is called to get the keepalive factor.
1124 * GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT is divided by this number to
1125 * calculate the interval between keepalive packets.
1126 *
1127 * @param cls closure with the `struct HTTP_Server_Plugin`
1128 * @return keepalive factor
1129 */
1130static unsigned int
1131http_server_query_keepalive_factor (void *cls)
1132{
1133 return 3;
1134}
1135
1136
1137/**
1138 * Function that will be called whenever the transport service wants to
1139 * notify the plugin that a session is still active and in use and
1140 * therefore the session timeout for this session has to be updated
1141 *
1142 * @param cls closure
1143 * @param peer which peer was the session for
1144 * @param session which session is being updated
1145 */
1146static void
1147http_server_plugin_update_session_timeout (void *cls,
1148 const struct
1149 GNUNET_PeerIdentity *peer,
1150 struct GNUNET_ATS_Session *session)
1151{
1152 server_reschedule_session_timeout (session);
1153}
1154
1155
1156/**
1157 * Tell MHD that the connection should timeout after @a to seconds.
1158 *
1159 * @param plugin our plugin
1160 * @param s session for which the timeout changes
1161 * @param to timeout in seconds
1162 */
1163static void
1164server_mhd_connection_timeout (struct HTTP_Server_Plugin *plugin,
1165 struct GNUNET_ATS_Session *s,
1166 unsigned int to)
1167{
1168 /* Setting timeouts for other connections */
1169 if (NULL != s->server_recv)
1170 {
1171 LOG (GNUNET_ERROR_TYPE_DEBUG,
1172 "Setting timeout for %p to %u sec.\n",
1173 s->server_recv, to);
1174 MHD_set_connection_option (s->server_recv->mhd_conn,
1175 MHD_CONNECTION_OPTION_TIMEOUT,
1176 to);
1177 server_reschedule (plugin, s->server_recv->mhd_daemon, GNUNET_NO);
1178 }
1179 if (NULL != s->server_send)
1180 {
1181 LOG (GNUNET_ERROR_TYPE_DEBUG,
1182 "Setting timeout for %p to %u sec.\n",
1183 s->server_send, to);
1184 MHD_set_connection_option (s->server_send->mhd_conn,
1185 MHD_CONNECTION_OPTION_TIMEOUT,
1186 to);
1187 server_reschedule (plugin, s->server_send->mhd_daemon, GNUNET_NO);
1188 }
1189}
1190
1191
1192/**
1193 * Parse incoming URL for tag and target
1194 *
1195 * @param plugin plugin
1196 * @param url incoming url
1197 * @param target where to store the target
1198 * @param tag where to store the tag
1199 * @param options where to store the options
1200 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1201 */
1202static int
1203server_parse_url (struct HTTP_Server_Plugin *plugin,
1204 const char *url,
1205 struct GNUNET_PeerIdentity *target,
1206 uint32_t *tag,
1207 uint32_t *options)
1208{
1209 regmatch_t matches[4];
1210 const char *tag_start;
1211 const char *target_start;
1212 char *tag_end;
1213 char *options_end;
1214 size_t hash_length;
1215 unsigned long int rc;
1216
1217 /* URL parsing */
1218#define URL_REGEX \
1219 ("^.*/([0-9A-Z]+);([0-9]+)(,[0-9]+)?$")
1220
1221 if (NULL == url)
1222 {
1223 GNUNET_break (0);
1224 return GNUNET_SYSERR;
1225 }
1226
1227 if (regexec (&plugin->url_regex, url, 4, matches, 0))
1228 {
1229 LOG (GNUNET_ERROR_TYPE_DEBUG,
1230 "URL `%s' did not match regex\n", url);
1231 return GNUNET_SYSERR;
1232 }
1233
1234 target_start = &url[matches[1].rm_so];
1235 tag_start = &url[matches[2].rm_so];
1236
1237 /* convert tag */
1238 rc = strtoul (tag_start, &tag_end, 10);
1239 if (&url[matches[2].rm_eo] != tag_end)
1240 {
1241 LOG (GNUNET_ERROR_TYPE_DEBUG,
1242 "URL tag did not line up with submatch\n");
1243 return GNUNET_SYSERR;
1244 }
1245 if (rc == 0)
1246 {
1247 LOG (GNUNET_ERROR_TYPE_DEBUG,
1248 "URL tag is zero\n");
1249 return GNUNET_SYSERR;
1250 }
1251 if ((rc == ULONG_MAX) && (ERANGE == errno))
1252 {
1253 LOG (GNUNET_ERROR_TYPE_DEBUG,
1254 "URL tag > ULONG_MAX\n");
1255 return GNUNET_SYSERR;
1256 }
1257 if (rc > UINT32_MAX)
1258 {
1259 LOG (GNUNET_ERROR_TYPE_DEBUG,
1260 "URL tag > UINT32_MAX\n");
1261 return GNUNET_SYSERR;
1262 }
1263 (*tag) = (uint32_t) rc;
1264 LOG (GNUNET_ERROR_TYPE_DEBUG,
1265 "Found tag `%u' in url\n",
1266 *tag);
1267
1268 /* convert peer id */
1269 hash_length = matches[1].rm_eo - matches[1].rm_so;
1270 if (hash_length != plugin->peer_id_length)
1271 {
1272 LOG (GNUNET_ERROR_TYPE_DEBUG,
1273 "URL target is %lu bytes, expecting %u\n",
1274 (unsigned long) hash_length, plugin->peer_id_length);
1275 return GNUNET_SYSERR;
1276 }
1277 if (GNUNET_OK !=
1278 GNUNET_CRYPTO_eddsa_public_key_from_string (target_start,
1279 hash_length,
1280 &target->public_key))
1281 {
1282 LOG (GNUNET_ERROR_TYPE_DEBUG,
1283 "URL target conversion failed\n");
1284 return GNUNET_SYSERR;
1285 }
1286 LOG (GNUNET_ERROR_TYPE_DEBUG,
1287 "Found target `%s' in URL\n",
1288 GNUNET_i2s_full (target));
1289
1290 /* convert options */
1291 if (-1 == matches[3].rm_so)
1292 {
1293 *options = 0;
1294 }
1295 else
1296 {
1297 rc = strtoul (&url[matches[3].rm_so + 1], &options_end, 10);
1298 if (&url[matches[3].rm_eo] != options_end)
1299 {
1300 LOG (GNUNET_ERROR_TYPE_DEBUG,
1301 "URL options did not line up with submatch\n");
1302 return GNUNET_SYSERR;
1303 }
1304 if ((rc == ULONG_MAX) && (ERANGE == errno))
1305 {
1306 LOG (GNUNET_ERROR_TYPE_DEBUG,
1307 "URL options > ULONG_MAX\n");
1308 return GNUNET_SYSERR;
1309 }
1310 if (rc > UINT32_MAX)
1311 {
1312 LOG (GNUNET_ERROR_TYPE_DEBUG,
1313 "URL options > UINT32_MAX\n");
1314 return GNUNET_SYSERR;
1315 }
1316 (*options) = (uint32_t) rc;
1317 LOG (GNUNET_ERROR_TYPE_DEBUG,
1318 "Found options `%u' in url\n",
1319 *options);
1320 }
1321 return GNUNET_OK;
1322}
1323
1324
1325/**
1326 * Closure for #session_tag_it().
1327 */
1328struct GNUNET_ATS_SessionTagContext
1329{
1330 /**
1331 * Set to session matching the tag.
1332 */
1333 struct GNUNET_ATS_Session *res;
1334
1335 /**
1336 * Tag we are looking for.
1337 */
1338 uint32_t tag;
1339};
1340
1341
1342/**
1343 * Find a session with a matching tag.
1344 *
1345 * @param cls the `struct GNUNET_ATS_SessionTagContext *`
1346 * @param key peer identity (unused)
1347 * @param value the `struct GNUNET_ATS_Session *`
1348 * @return #GNUNET_NO if we found the session, #GNUNET_OK if not
1349 */
1350static int
1351session_tag_it (void *cls,
1352 const struct GNUNET_PeerIdentity *key,
1353 void *value)
1354{
1355 struct GNUNET_ATS_SessionTagContext *stc = cls;
1356 struct GNUNET_ATS_Session *s = value;
1357
1358 if (s->tag == stc->tag)
1359 {
1360 stc->res = s;
1361 return GNUNET_NO;
1362 }
1363 return GNUNET_YES;
1364}
1365
1366
1367/**
1368 * Lookup a mhd connection and create one if none is found
1369 *
1370 * @param plugin the plugin handle
1371 * @param mhd_connection the incoming mhd_connection
1372 * @param url incoming requested URL
1373 * @param method PUT or GET
1374 * @return the server connecetion
1375 */
1376static struct ServerRequest *
1377server_lookup_connection (struct HTTP_Server_Plugin *plugin,
1378 struct MHD_Connection *mhd_connection,
1379 const char *url,
1380 const char *method)
1381{
1382 struct GNUNET_ATS_Session *s = NULL;
1383 struct ServerRequest *sc = NULL;
1384 const union MHD_ConnectionInfo *conn_info;
1385 struct HttpAddress *addr;
1386 struct GNUNET_PeerIdentity target;
1387 size_t addr_len;
1388 struct GNUNET_ATS_SessionTagContext stc;
1389 uint32_t options;
1390 int direction = GNUNET_SYSERR;
1391 unsigned int to;
1392 enum GNUNET_NetworkType scope;
1393
1394 conn_info = MHD_get_connection_info (mhd_connection,
1395 MHD_CONNECTION_INFO_CLIENT_ADDRESS);
1396 if ((conn_info->client_addr->sa_family != AF_INET) &&
1397 (conn_info->client_addr->sa_family != AF_INET6))
1398 return NULL;
1399 LOG (GNUNET_ERROR_TYPE_DEBUG,
1400 "New %s request from %s\n",
1401 method,
1402 url);
1403 stc.tag = 0;
1404 options = 0; /* make gcc happy */
1405 if (GNUNET_SYSERR ==
1406 server_parse_url (plugin, url, &target, &stc.tag, &options))
1407 {
1408 LOG (GNUNET_ERROR_TYPE_DEBUG,
1409 "Invalid url %s\n", url);
1410 return NULL;
1411 }
1412 if (0 == strcmp (MHD_HTTP_METHOD_PUT, method))
1413 direction = _RECEIVE;
1414 else if (0 == strcmp (MHD_HTTP_METHOD_GET, method))
1415 direction = _SEND;
1416 else
1417 {
1418 LOG (GNUNET_ERROR_TYPE_DEBUG,
1419 "Invalid method %s for request from %s\n",
1420 method, url);
1421 return NULL;
1422 }
1423
1424 plugin->cur_request++;
1425 LOG (GNUNET_ERROR_TYPE_DEBUG,
1426 "New %s request from %s with tag %u (%u of %u)\n",
1427 method,
1428 GNUNET_i2s (&target),
1429 stc.tag,
1430 plugin->cur_request, plugin->max_request);
1431 /* find existing session */
1432 stc.res = NULL;
1433 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessions,
1434 &target,
1435 &session_tag_it,
1436 &stc);
1437 if (NULL == (s = stc.res))
1438 {
1439 /* create new session */
1440 addr = NULL;
1441 switch (conn_info->client_addr->sa_family)
1442 {
1443 case (AF_INET):
1444 addr = http_common_address_from_socket (plugin->protocol,
1445 conn_info->client_addr,
1446 sizeof(struct sockaddr_in));
1447 addr_len = http_common_address_get_size (addr);
1448 scope = plugin->env->get_address_type (plugin->env->cls,
1449 conn_info->client_addr,
1450 sizeof(struct sockaddr_in));
1451 break;
1452
1453 case (AF_INET6):
1454 addr = http_common_address_from_socket (plugin->protocol,
1455 conn_info->client_addr,
1456 sizeof(struct sockaddr_in6));
1457 addr_len = http_common_address_get_size (addr);
1458 scope = plugin->env->get_address_type (plugin->env->cls,
1459 conn_info->client_addr,
1460 sizeof(struct sockaddr_in6));
1461 break;
1462
1463 default:
1464 /* external host name */
1465 return NULL;
1466 }
1467 s = GNUNET_new (struct GNUNET_ATS_Session);
1468 s->target = target;
1469 s->plugin = plugin;
1470 s->scope = scope;
1471 s->address = GNUNET_HELLO_address_allocate (&s->target,
1472 PLUGIN_NAME,
1473 addr,
1474 addr_len,
1475 GNUNET_HELLO_ADDRESS_INFO_INBOUND);
1476 s->next_receive = GNUNET_TIME_UNIT_ZERO_ABS;
1477 s->tag = stc.tag;
1478 s->timeout = GNUNET_TIME_relative_to_absolute (HTTP_SERVER_SESSION_TIMEOUT);
1479 s->timeout_task = GNUNET_SCHEDULER_add_delayed (HTTP_SERVER_SESSION_TIMEOUT,
1480 &server_session_timeout,
1481 s);
1482 (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessions,
1483 &s->target,
1484 s,
1485 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1486 notify_session_monitor (plugin,
1487 s,
1488 GNUNET_TRANSPORT_SS_INIT);
1489 notify_session_monitor (plugin,
1490 s,
1491 GNUNET_TRANSPORT_SS_HANDSHAKE);
1492 LOG (GNUNET_ERROR_TYPE_DEBUG,
1493 "Creating new session %p for peer `%s' connecting from `%s'\n",
1494 s, GNUNET_i2s (&target),
1495 http_common_plugin_address_to_string (plugin->protocol,
1496 addr,
1497 addr_len));
1498 GNUNET_free (addr);
1499 }
1500
1501 if ((_RECEIVE == direction) &&
1502 (NULL != s->server_recv))
1503 {
1504 LOG (GNUNET_ERROR_TYPE_DEBUG,
1505 "Duplicate PUT request from `%s' tag %u, dismissing new request\n",
1506 GNUNET_i2s (&target),
1507 stc.tag);
1508 return NULL;
1509 }
1510 if ((_SEND == direction) && (NULL != s->server_send))
1511 {
1512 LOG (GNUNET_ERROR_TYPE_DEBUG,
1513 "Duplicate GET request from `%s' tag %u, dismissing new request\n",
1514 GNUNET_i2s (&target),
1515 stc.tag);
1516 return NULL;
1517 }
1518 sc = GNUNET_new (struct ServerRequest);
1519 if (conn_info->client_addr->sa_family == AF_INET)
1520 sc->mhd_daemon = plugin->server_v4;
1521 if (conn_info->client_addr->sa_family == AF_INET6)
1522 sc->mhd_daemon = plugin->server_v6;
1523 sc->mhd_conn = mhd_connection;
1524 sc->direction = direction;
1525 sc->connected = GNUNET_NO;
1526 sc->session = s;
1527 sc->options = options;
1528 if (direction == _SEND)
1529 {
1530 s->server_send = sc;
1531 }
1532 if (direction == _RECEIVE)
1533 {
1534 s->server_recv = sc;
1535 }
1536
1537 if ((GNUNET_NO == s->known_to_service) &&
1538 (NULL != s->server_send) &&
1539 (NULL != s->server_recv))
1540 {
1541 s->known_to_service = GNUNET_YES;
1542 notify_session_monitor (plugin,
1543 s,
1544 GNUNET_TRANSPORT_SS_UP);
1545 plugin->env->session_start (plugin->env->cls,
1546 s->address,
1547 s,
1548 s->scope);
1549 }
1550
1551 to = (HTTP_SERVER_SESSION_TIMEOUT.rel_value_us / 1000LL / 1000LL);
1552 server_mhd_connection_timeout (plugin, s, to);
1553 return sc;
1554}
1555
1556
1557/**
1558 * Callback called by MHD when it needs data to send
1559 *
1560 * @param cls current session
1561 * @param pos position in buffer
1562 * @param buf the buffer to write data to
1563 * @param max max number of bytes available in @a buf
1564 * @return bytes written to @a buf
1565 */
1566static ssize_t
1567server_send_callback (void *cls,
1568 uint64_t pos,
1569 char *buf,
1570 size_t max)
1571{
1572 struct ServerRequest *sc = cls;
1573 struct GNUNET_ATS_Session *s = sc->session;
1574 ssize_t bytes_read = 0;
1575 struct HTTP_Message *msg;
1576 char *stat_txt;
1577
1578 if (NULL == s)
1579 {
1580 /* session is disconnecting */
1581 return 0;
1582 }
1583
1584 sc = s->server_send;
1585 if (NULL == sc)
1586 return 0;
1587 msg = s->msg_head;
1588 if (NULL != msg)
1589 {
1590 /* sending */
1591 bytes_read = GNUNET_MIN (msg->size - msg->pos,
1592 max);
1593 GNUNET_memcpy (buf, &msg->buf[msg->pos], bytes_read);
1594 msg->pos += bytes_read;
1595
1596 /* removing message */
1597 if (msg->pos == msg->size)
1598 {
1599 GNUNET_CONTAINER_DLL_remove (s->msg_head,
1600 s->msg_tail,
1601 msg);
1602 if (NULL != msg->transmit_cont)
1603 msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_OK,
1604 msg->size, msg->size + msg->overhead);
1605 GNUNET_assert (s->msgs_in_queue > 0);
1606 s->msgs_in_queue--;
1607 GNUNET_assert (s->bytes_in_queue >= msg->size);
1608 s->bytes_in_queue -= msg->size;
1609 GNUNET_free (msg);
1610 notify_session_monitor (s->plugin,
1611 s,
1612 GNUNET_TRANSPORT_SS_UPDATE);
1613 }
1614 }
1615 if (0 < bytes_read)
1616 {
1617 sc->connected = GNUNET_YES;
1618 LOG (GNUNET_ERROR_TYPE_DEBUG,
1619 "Sent %lu bytes to peer `%s' with session %p \n",
1620 (unsigned long) bytes_read,
1621 GNUNET_i2s (&s->target),
1622 s);
1623 GNUNET_asprintf (&stat_txt,
1624 "# bytes currently in %s_server buffers",
1625 s->plugin->protocol);
1626 GNUNET_STATISTICS_update (s->plugin->env->stats,
1627 stat_txt,
1628 -bytes_read,
1629 GNUNET_NO);
1630 GNUNET_free (stat_txt);
1631 GNUNET_asprintf (&stat_txt,
1632 "# bytes transmitted via %s_server",
1633 s->plugin->protocol);
1634 GNUNET_STATISTICS_update (s->plugin->env->stats,
1635 stat_txt, bytes_read, GNUNET_NO);
1636 GNUNET_free (stat_txt);
1637 }
1638 else if ((sc->options & OPTION_LONG_POLL) && sc->connected)
1639 {
1640 LOG (GNUNET_ERROR_TYPE_DEBUG,
1641 "Completing GET response to peer `%s' with session %p\n",
1642 GNUNET_i2s (&s->target),
1643 s);
1644 return MHD_CONTENT_READER_END_OF_STREAM;
1645 }
1646 else
1647 {
1648 MHD_suspend_connection (s->server_send->mhd_conn);
1649 s->server_send->suspended = true;
1650 return 0;
1651 }
1652 return bytes_read;
1653}
1654
1655
1656/**
1657 * Callback called by MessageStreamTokenizer when a message has arrived
1658 *
1659 * @param cls current session as closure
1660 * @param message the message to be forwarded to transport service
1661 * @return #GNUNET_OK (all OK)
1662 */
1663static int
1664server_receive_mst_cb (void *cls,
1665 const struct GNUNET_MessageHeader *message)
1666{
1667 struct GNUNET_ATS_Session *s = cls;
1668 struct HTTP_Server_Plugin *plugin = s->plugin;
1669 struct GNUNET_TIME_Relative delay;
1670 char *stat_txt;
1671
1672 if (GNUNET_NO == s->known_to_service)
1673 {
1674 s->known_to_service = GNUNET_YES;
1675 plugin->env->session_start (plugin->env->cls,
1676 s->address,
1677 s,
1678 s->scope);
1679 notify_session_monitor (plugin,
1680 s,
1681 GNUNET_TRANSPORT_SS_UP);
1682 }
1683 delay = plugin->env->receive (plugin->env->cls,
1684 s->address,
1685 s,
1686 message);
1687 GNUNET_asprintf (&stat_txt,
1688 "# bytes received via %s_server",
1689 plugin->protocol);
1690 GNUNET_STATISTICS_update (plugin->env->stats,
1691 stat_txt,
1692 ntohs (message->size),
1693 GNUNET_NO);
1694 GNUNET_free (stat_txt);
1695 s->next_receive = GNUNET_TIME_relative_to_absolute (delay);
1696 if (delay.rel_value_us > 0)
1697 {
1698 LOG (GNUNET_ERROR_TYPE_DEBUG,
1699 "Peer `%s' address `%s' next read delayed for %s\n",
1700 GNUNET_i2s (&s->target),
1701 http_common_plugin_address_to_string (plugin->protocol,
1702 s->address->address,
1703 s->address->address_length),
1704 GNUNET_STRINGS_relative_time_to_string (delay,
1705 GNUNET_YES));
1706 }
1707 server_reschedule_session_timeout (s);
1708 return GNUNET_OK;
1709}
1710
1711
1712/**
1713 * Add headers to a request indicating that we allow Cross-Origin Resource
1714 * Sharing.
1715 *
1716 * @param response response object to modify
1717 */
1718static void
1719add_cors_headers (struct MHD_Response *response)
1720{
1721 MHD_add_response_header (response,
1722 "Access-Control-Allow-Origin",
1723 "*");
1724 MHD_add_response_header (response,
1725 "Access-Control-Allow-Methods",
1726 "GET, PUT, OPTIONS");
1727 MHD_add_response_header (response,
1728 "Access-Control-Max-Age",
1729 "86400");
1730}
1731
1732
1733/**
1734 * MHD callback for a new incoming connection
1735 *
1736 * @param cls the plugin handle
1737 * @param mhd_connection the mhd connection
1738 * @param url the requested URL
1739 * @param method GET or PUT
1740 * @param version HTTP version
1741 * @param upload_data upload data
1742 * @param upload_data_size size of @a upload_data
1743 * @param httpSessionCache the session cache to remember the connection
1744 * @return #MHD_YES if connection is accepted, #MHD_NO on reject
1745 */
1746static MHD_RESULT
1747server_access_cb (void *cls,
1748 struct MHD_Connection *mhd_connection,
1749 const char *url,
1750 const char *method,
1751 const char *version,
1752 const char *upload_data,
1753 size_t *upload_data_size,
1754 void **httpSessionCache)
1755{
1756 struct HTTP_Server_Plugin *plugin = cls;
1757 struct ServerRequest *sc = *httpSessionCache;
1758 struct GNUNET_ATS_Session *s;
1759 struct MHD_Response *response;
1760 MHD_RESULT res = MHD_YES;
1761
1762 LOG (GNUNET_ERROR_TYPE_DEBUG,
1763 _ (
1764 "Access from connection %p (%u of %u) for `%s' `%s' url `%s' with upload data size %lu\n"),
1765 sc,
1766 plugin->cur_request,
1767 plugin->max_request,
1768 method,
1769 version,
1770 url,
1771 (unsigned long) (*upload_data_size));
1772 if (NULL == sc)
1773 {
1774 /* CORS pre-flight request */
1775 if (0 == strcmp (MHD_HTTP_METHOD_OPTIONS, method))
1776 {
1777 response = MHD_create_response_from_buffer (0, NULL,
1778 MHD_RESPMEM_PERSISTENT);
1779 add_cors_headers (response);
1780 res = MHD_queue_response (mhd_connection, MHD_HTTP_OK, response);
1781 MHD_destroy_response (response);
1782 return res;
1783 }
1784 /* new connection */
1785 sc = server_lookup_connection (plugin, mhd_connection, url, method);
1786 if (NULL != sc)
1787 {
1788 /* attach to new / existing session */
1789 (*httpSessionCache) = sc;
1790 }
1791 else
1792 {
1793 /* existing session already has matching connection, refuse */
1794 response = MHD_create_response_from_buffer (strlen (HTTP_ERROR_RESPONSE),
1795 HTTP_ERROR_RESPONSE,
1796 MHD_RESPMEM_PERSISTENT);
1797 MHD_add_response_header (response,
1798 MHD_HTTP_HEADER_CONTENT_TYPE,
1799 "text/html");
1800 add_cors_headers (response);
1801 res = MHD_queue_response (mhd_connection, MHD_HTTP_NOT_FOUND, response);
1802 MHD_destroy_response (response);
1803 return res;
1804 }
1805 }
1806 /* 'old' connection */
1807 if (NULL == (s = sc->session))
1808 {
1809 /* Session was already disconnected;
1810 sent HTTP/1.1: 200 OK as response */
1811 response = MHD_create_response_from_buffer (strlen ("Thank you!"),
1812 "Thank you!",
1813 MHD_RESPMEM_PERSISTENT);
1814 add_cors_headers (response);
1815 MHD_queue_response (mhd_connection, MHD_HTTP_OK, response);
1816 MHD_destroy_response (response);
1817 return MHD_YES;
1818 }
1819
1820 if (sc->direction == _SEND)
1821 {
1822 response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN, 32 * 1024,
1823 &server_send_callback, sc,
1824 NULL);
1825 add_cors_headers (response);
1826 MHD_queue_response (mhd_connection, MHD_HTTP_OK, response);
1827 MHD_destroy_response (response);
1828 return MHD_YES;
1829 }
1830 if (sc->direction == _RECEIVE)
1831 {
1832 if ((*upload_data_size == 0) && (sc->connected == GNUNET_NO))
1833 {
1834 /* (*upload_data_size == 0) first callback when header are passed */
1835 LOG (GNUNET_ERROR_TYPE_DEBUG,
1836 "Session %p / Connection %p: Peer `%s' PUT on address `%s' connected\n",
1837 s, sc,
1838 GNUNET_i2s (&s->target),
1839 http_common_plugin_address_to_string (plugin->protocol,
1840 s->address->address,
1841 s->address->address_length));
1842 sc->connected = GNUNET_YES;
1843 return MHD_YES;
1844 }
1845 else if ((*upload_data_size == 0) && (sc->connected == GNUNET_YES))
1846 {
1847 /* (*upload_data_size == 0) when upload is complete */
1848 LOG (GNUNET_ERROR_TYPE_DEBUG,
1849 "Session %p / Connection %p: Peer `%s' PUT on address `%s' finished upload\n",
1850 s, sc,
1851 GNUNET_i2s (&s->target),
1852 http_common_plugin_address_to_string (plugin->protocol,
1853 s->address->address,
1854 s->address->address_length));
1855 sc->connected = GNUNET_NO;
1856 /* Sent HTTP/1.1: 200 OK as PUT Response\ */
1857 response = MHD_create_response_from_buffer (strlen ("Thank you!"),
1858 "Thank you!",
1859 MHD_RESPMEM_PERSISTENT);
1860 add_cors_headers (response);
1861 MHD_queue_response (mhd_connection, MHD_HTTP_OK, response);
1862 MHD_destroy_response (response);
1863 return MHD_YES;
1864 }
1865 else if ((*upload_data_size > 0) && (sc->connected == GNUNET_YES))
1866 {
1867 struct GNUNET_TIME_Relative delay;
1868
1869 /* (*upload_data_size > 0) for every segment received */
1870 LOG (GNUNET_ERROR_TYPE_DEBUG,
1871 "Session %p / Connection %p: Peer `%s' PUT on address `%s' received %lu bytes\n",
1872 s, sc,
1873 GNUNET_i2s (&s->target),
1874 http_common_plugin_address_to_string (plugin->protocol,
1875 s->address->address,
1876 s->address->address_length),
1877 (unsigned long) *upload_data_size);
1878 delay = GNUNET_TIME_absolute_get_remaining (s->next_receive);
1879 if (0 == delay.rel_value_us)
1880 {
1881 LOG (GNUNET_ERROR_TYPE_DEBUG,
1882 "PUT with %lu bytes forwarded to MST\n",
1883 (unsigned long) *upload_data_size);
1884 if (s->msg_tk == NULL)
1885 {
1886 s->msg_tk = GNUNET_MST_create (&server_receive_mst_cb,
1887 s);
1888 }
1889 GNUNET_MST_from_buffer (s->msg_tk,
1890 upload_data,
1891 *upload_data_size,
1892 GNUNET_NO, GNUNET_NO);
1893 server_mhd_connection_timeout (plugin, s,
1894 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.
1895 rel_value_us / 1000LL
1896 / 1000LL);
1897 (*upload_data_size) = 0;
1898 }
1899 else
1900 {
1901 /* delay processing */
1902 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1903 "Session %p / Connection %p: no inbound bandwidth available! Next read was delayed by %s\n",
1904 s,
1905 sc,
1906 GNUNET_STRINGS_relative_time_to_string (delay,
1907 GNUNET_YES));
1908 GNUNET_assert (s->server_recv->mhd_conn == mhd_connection);
1909 MHD_suspend_connection (s->server_recv->mhd_conn);
1910 s->server_recv->suspended = true;
1911 if (NULL == s->recv_wakeup_task)
1912 s->recv_wakeup_task
1913 = GNUNET_SCHEDULER_add_delayed (delay,
1914 &server_wake_up,
1915 s);
1916 }
1917 return MHD_YES;
1918 }
1919 else
1920 {
1921 GNUNET_break (0);
1922 return MHD_NO;
1923 }
1924 }
1925 return res;
1926}
1927
1928
1929/**
1930 * Callback from MHD when a connection disconnects
1931 *
1932 * @param cls closure with the `struct HTTP_Server_Plugin *`
1933 * @param connection the disconnected MHD connection
1934 * @param httpSessionCache the pointer to distinguish
1935 */
1936static void
1937server_disconnect_cb (void *cls,
1938 struct MHD_Connection *connection,
1939 void **httpSessionCache)
1940{
1941 struct HTTP_Server_Plugin *plugin = cls;
1942 struct ServerRequest *sc = *httpSessionCache;
1943
1944 LOG (GNUNET_ERROR_TYPE_DEBUG,
1945 "Disconnect for connection %p\n",
1946 sc);
1947 if (NULL == sc)
1948 {
1949 /* CORS pre-flight request finished */
1950 return;
1951 }
1952
1953 if (NULL != sc->session)
1954 {
1955 if (sc->direction == _SEND)
1956 {
1957 LOG (GNUNET_ERROR_TYPE_DEBUG,
1958 "Peer `%s' connection %p, GET on address `%s' disconnected\n",
1959 GNUNET_i2s (&sc->session->target),
1960 sc->session->server_send,
1961 http_common_plugin_address_to_string (plugin->protocol,
1962 sc->session->address->address,
1963 sc->session->address->
1964 address_length));
1965
1966 sc->session->server_send = NULL;
1967 }
1968 else if (sc->direction == _RECEIVE)
1969 {
1970 LOG (GNUNET_ERROR_TYPE_DEBUG,
1971 "Peer `%s' connection %p PUT on address `%s' disconnected\n",
1972 GNUNET_i2s (&sc->session->target),
1973 sc->session->server_recv,
1974 http_common_plugin_address_to_string (plugin->protocol,
1975 sc->session->address->address,
1976 sc->session->address->
1977 address_length));
1978 sc->session->server_recv = NULL;
1979 if (NULL != sc->session->msg_tk)
1980 {
1981 GNUNET_MST_destroy (sc->session->msg_tk);
1982 sc->session->msg_tk = NULL;
1983 }
1984 }
1985 }
1986 GNUNET_free (sc);
1987 plugin->cur_request--;
1988}
1989
1990
1991/**
1992 * Callback from MHD when a connection starts/stops
1993 *
1994 * @param cls closure with the `struct HTTP_Server_Plugin *`
1995 * @param connection connection handle
1996 * @param socket_context socket-specific pointer
1997 * @param toe reason for connection notification
1998 * @see #MHD_OPTION_NOTIFY_CONNECTION
1999 */
2000static void
2001server_connection_cb (void *cls,
2002 struct MHD_Connection *connection,
2003 void **socket_context,
2004 enum MHD_ConnectionNotificationCode toe)
2005{
2006 struct HTTP_Server_Plugin *plugin = cls;
2007 const union MHD_ConnectionInfo *info;
2008
2009 if (MHD_CONNECTION_NOTIFY_STARTED == toe)
2010 return;
2011
2012 /* Reschedule to remove closed socket from our select set */
2013 info = MHD_get_connection_info (connection,
2014 MHD_CONNECTION_INFO_DAEMON);
2015 GNUNET_assert (NULL != info);
2016 server_reschedule (plugin,
2017 info->daemon,
2018 GNUNET_YES);
2019}
2020
2021
2022/**
2023 * Check if incoming connection is accepted.
2024 *
2025 * @param cls plugin as closure
2026 * @param addr address of incoming connection
2027 * @param addr_len number of bytes in @a addr
2028 * @return #MHD_YES if connection is accepted, #MHD_NO if connection is rejected
2029 */
2030static MHD_RESULT
2031server_accept_cb (void *cls,
2032 const struct sockaddr *addr,
2033 socklen_t addr_len)
2034{
2035 struct HTTP_Server_Plugin *plugin = cls;
2036
2037 if (plugin->cur_request <= plugin->max_request)
2038 {
2039 LOG (GNUNET_ERROR_TYPE_DEBUG,
2040 _ ("Accepting connection (%u of %u) from `%s'\n"),
2041 plugin->cur_request, plugin->max_request,
2042 GNUNET_a2s (addr, addr_len));
2043 return MHD_YES;
2044 }
2045 else
2046 {
2047 LOG (GNUNET_ERROR_TYPE_WARNING,
2048 _ (
2049 "Server reached maximum number connections (%u), rejecting new connection\n"),
2050 plugin->max_request);
2051 return MHD_NO;
2052 }
2053}
2054
2055
2056/**
2057 * Log function called by MHD.
2058 *
2059 * @param arg NULL
2060 * @param fmt format string
2061 * @param ap arguments for the format string (va_start() and va_end()
2062 * will be called by MHD)
2063 */
2064static void
2065server_log (void *arg,
2066 const char *fmt,
2067 va_list ap)
2068{
2069 char text[1024];
2070
2071 vsnprintf (text,
2072 sizeof(text),
2073 fmt,
2074 ap);
2075 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2076 "Server: %s\n",
2077 text);
2078}
2079
2080
2081#if BUILD_HTTPS
2082/**
2083 * Load ssl certificate from file
2084 *
2085 * @param file filename
2086 * @return content of the file
2087 */
2088static char *
2089server_load_file (const char *file)
2090{
2091 struct GNUNET_DISK_FileHandle *gn_file;
2092 uint64_t fsize;
2093 char *text = NULL;
2094
2095 if (GNUNET_OK != GNUNET_DISK_file_size (file,
2096 &fsize, GNUNET_NO, GNUNET_YES))
2097 return NULL;
2098 text = GNUNET_malloc (fsize + 1);
2099 gn_file =
2100 GNUNET_DISK_file_open (file, GNUNET_DISK_OPEN_READ,
2101 GNUNET_DISK_PERM_USER_READ);
2102 if (NULL == gn_file)
2103 {
2104 GNUNET_free (text);
2105 return NULL;
2106 }
2107 if (GNUNET_SYSERR == GNUNET_DISK_file_read (gn_file, text, fsize))
2108 {
2109 GNUNET_free (text);
2110 GNUNET_DISK_file_close (gn_file);
2111 return NULL;
2112 }
2113 text[fsize] = '\0';
2114 GNUNET_DISK_file_close (gn_file);
2115 return text;
2116}
2117
2118
2119#endif
2120
2121
2122#if BUILD_HTTPS
2123/**
2124 * Load ssl certificate
2125 *
2126 * @param plugin the plugin
2127 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
2128 */
2129static int
2130server_load_certificate (struct HTTP_Server_Plugin *plugin)
2131{
2132 int res = GNUNET_OK;
2133 char *key_file;
2134 char *cert_file;
2135
2136
2137 if (GNUNET_OK !=
2138 GNUNET_CONFIGURATION_get_value_filename (plugin->env->cfg,
2139 plugin->name,
2140 "KEY_FILE", &key_file))
2141 {
2142 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
2143 plugin->name, "CERT_FILE");
2144 return GNUNET_SYSERR;
2145 }
2146 if (GNUNET_OK !=
2147 GNUNET_CONFIGURATION_get_value_filename (plugin->env->cfg,
2148 plugin->name,
2149 "CERT_FILE", &cert_file))
2150 {
2151 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
2152 plugin->name, "CERT_FILE");
2153 GNUNET_free (key_file);
2154 return GNUNET_SYSERR;
2155 }
2156 /* Get crypto init string from config. If not present, use
2157 * default values */
2158 if (GNUNET_OK ==
2159 GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg,
2160 plugin->name,
2161 "CRYPTO_INIT",
2162 &plugin->crypto_init))
2163 LOG (GNUNET_ERROR_TYPE_DEBUG,
2164 "Using crypto init string `%s'\n",
2165 plugin->crypto_init);
2166 else
2167 LOG (GNUNET_ERROR_TYPE_DEBUG,
2168 "Using default crypto init string \n");
2169
2170 /* read key & certificates from file */
2171 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2172 "Trying to loading TLS certificate from key-file `%s' cert-file`%s'\n",
2173 key_file, cert_file);
2174
2175 plugin->key = server_load_file (key_file);
2176 plugin->cert = server_load_file (cert_file);
2177
2178 if ((plugin->key == NULL) || (plugin->cert == NULL))
2179 {
2180 struct GNUNET_OS_Process *cert_creation;
2181
2182 GNUNET_free (plugin->key);
2183 plugin->key = NULL;
2184 GNUNET_free (plugin->cert);
2185 plugin->cert = NULL;
2186
2187 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2188 "No usable TLS certificate found, creating certificate\n");
2189 errno = 0;
2190 cert_creation =
2191 GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
2192 NULL, NULL, NULL,
2193 "gnunet-transport-certificate-creation",
2194 "gnunet-transport-certificate-creation",
2195 key_file,
2196 cert_file,
2197 NULL);
2198 if (NULL == cert_creation)
2199 {
2200 LOG (GNUNET_ERROR_TYPE_ERROR,
2201 _ (
2202 "Could not create a new TLS certificate, program `gnunet-transport-certificate-creation' could not be started!\n"));
2203 GNUNET_free (key_file);
2204 GNUNET_free (cert_file);
2205
2206 GNUNET_free (plugin->key);
2207 plugin->key = NULL;
2208 GNUNET_free (plugin->cert);
2209 plugin->cert = NULL;
2210 GNUNET_free (plugin->crypto_init);
2211 plugin->crypto_init = NULL;
2212
2213 return GNUNET_SYSERR;
2214 }
2215 GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (cert_creation));
2216 GNUNET_OS_process_destroy (cert_creation);
2217
2218 plugin->key = server_load_file (key_file);
2219 plugin->cert = server_load_file (cert_file);
2220 }
2221
2222 if ((plugin->key == NULL) || (plugin->cert == NULL))
2223 {
2224 LOG (GNUNET_ERROR_TYPE_ERROR,
2225 _ (
2226 "No usable TLS certificate found and creating one at `%s/%s' failed!\n"),
2227 key_file, cert_file);
2228 GNUNET_free (key_file);
2229 GNUNET_free (cert_file);
2230
2231 GNUNET_free (plugin->key);
2232 plugin->key = NULL;
2233 GNUNET_free (plugin->cert);
2234 plugin->cert = NULL;
2235 GNUNET_free (plugin->crypto_init);
2236 plugin->crypto_init = NULL;
2237
2238 return GNUNET_SYSERR;
2239 }
2240 GNUNET_free (key_file);
2241 GNUNET_free (cert_file);
2242 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2243 "TLS certificate loaded\n");
2244 return res;
2245}
2246
2247
2248#endif
2249
2250
2251/**
2252 * Invoke `MHD_start_daemon` with the various options we need to
2253 * setup the HTTP server with the given listen address.
2254 *
2255 * @param plugin our plugin
2256 * @param addr listen address to use
2257 * @param v6 MHD_NO_FLAG or MHD_USE_IPv6, depending on context
2258 * @return NULL on error
2259 */
2260static struct MHD_Daemon *
2261run_mhd_start_daemon (struct HTTP_Server_Plugin *plugin,
2262 const struct sockaddr_in *addr,
2263 int v6)
2264{
2265 struct MHD_Daemon *server;
2266 unsigned int timeout;
2267
2268#if MHD_VERSION >= 0x00090E00
2269 timeout = HTTP_SERVER_NOT_VALIDATED_TIMEOUT.rel_value_us / 1000LL / 1000LL;
2270 LOG (GNUNET_ERROR_TYPE_DEBUG,
2271 "MHD can set timeout per connection! Default time out %u sec.\n",
2272 timeout);
2273#else
2274 timeout = HTTP_SERVER_SESSION_TIMEOUT.rel_value_us / 1000LL / 1000LL;
2275 LOG (GNUNET_ERROR_TYPE_WARNING,
2276 "MHD cannot set timeout per connection! Default time out %u sec.\n",
2277 timeout);
2278#endif
2279 server = MHD_start_daemon (
2280#if VERBOSE_SERVER
2281 MHD_USE_DEBUG |
2282#endif
2283#if BUILD_HTTPS
2284 MHD_USE_SSL |
2285#endif
2286 MHD_USE_SUSPEND_RESUME
2287 | v6,
2288 plugin->port,
2289 &server_accept_cb, plugin,
2290 &server_access_cb, plugin,
2291 MHD_OPTION_SOCK_ADDR,
2292 addr,
2293 MHD_OPTION_CONNECTION_LIMIT,
2294 (unsigned int) plugin->max_request,
2295#if BUILD_HTTPS
2296 MHD_OPTION_HTTPS_PRIORITIES,
2297 plugin->crypto_init,
2298 MHD_OPTION_HTTPS_MEM_KEY,
2299 plugin->key,
2300 MHD_OPTION_HTTPS_MEM_CERT,
2301 plugin->cert,
2302#endif
2303 MHD_OPTION_CONNECTION_TIMEOUT,
2304 timeout,
2305 MHD_OPTION_CONNECTION_MEMORY_LIMIT,
2306 (size_t) (2
2307 * GNUNET_MAX_MESSAGE_SIZE),
2308 MHD_OPTION_NOTIFY_COMPLETED,
2309 &server_disconnect_cb, plugin,
2310 MHD_OPTION_NOTIFY_CONNECTION,
2311 &server_connection_cb, plugin,
2312 MHD_OPTION_EXTERNAL_LOGGER,
2313 &server_log, NULL,
2314 MHD_OPTION_END);
2315#ifdef TCP_STEALTH
2316 if ((NULL != server) &&
2317 (0 != (plugin->options & HTTP_OPTIONS_TCP_STEALTH)))
2318 {
2319 const union MHD_DaemonInfo *di;
2320
2321 di = MHD_get_daemon_info (server,
2322 MHD_DAEMON_INFO_LISTEN_FD,
2323 NULL);
2324 if ((0 != setsockopt ((int) di->listen_fd,
2325 IPPROTO_TCP,
2326 TCP_STEALTH,
2327 plugin->env->my_identity,
2328 sizeof(struct GNUNET_PeerIdentity))))
2329 {
2330 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2331 _ ("TCP_STEALTH not supported on this platform.\n"));
2332 MHD_stop_daemon (server);
2333 server = NULL;
2334 }
2335 }
2336#endif
2337 return server;
2338}
2339
2340
2341/**
2342 * Start the HTTP server
2343 *
2344 * @param plugin the plugin handle
2345 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
2346 */
2347static int
2348server_start (struct HTTP_Server_Plugin *plugin)
2349{
2350 const char *msg;
2351
2352 GNUNET_assert (NULL != plugin);
2353#if BUILD_HTTPS
2354 if (GNUNET_SYSERR == server_load_certificate (plugin))
2355 {
2356 LOG (GNUNET_ERROR_TYPE_ERROR,
2357 _ (
2358 "Could not load or create server certificate! Loading plugin failed!\n"));
2359 return GNUNET_SYSERR;
2360 }
2361#endif
2362
2363
2364 plugin->server_v4 = NULL;
2365 if (GNUNET_YES == plugin->use_ipv4)
2366 {
2367 plugin->server_v4
2368 = run_mhd_start_daemon (plugin,
2369 (const struct
2370 sockaddr_in *) plugin->server_addr_v4,
2371 MHD_NO_FLAG);
2372
2373 if (NULL == plugin->server_v4)
2374 {
2375 LOG (GNUNET_ERROR_TYPE_ERROR,
2376 "Failed to start %s IPv4 server component on port %u\n",
2377 plugin->name,
2378 plugin->port);
2379 }
2380 else
2381 server_reschedule (plugin,
2382 plugin->server_v4,
2383 GNUNET_NO);
2384 }
2385
2386
2387 plugin->server_v6 = NULL;
2388 if (GNUNET_YES == plugin->use_ipv6)
2389 {
2390 plugin->server_v6
2391 = run_mhd_start_daemon (plugin,
2392 (const struct
2393 sockaddr_in *) plugin->server_addr_v6,
2394 MHD_USE_IPv6);
2395 if (NULL == plugin->server_v6)
2396 {
2397 LOG (GNUNET_ERROR_TYPE_ERROR,
2398 "Failed to start %s IPv6 server component on port %u\n",
2399 plugin->name,
2400 plugin->port);
2401 }
2402 else
2403 {
2404 server_reschedule (plugin,
2405 plugin->server_v6,
2406 GNUNET_NO);
2407 }
2408 }
2409 msg = "No";
2410 if ((NULL == plugin->server_v6) &&
2411 (NULL == plugin->server_v4))
2412 {
2413 LOG (GNUNET_ERROR_TYPE_ERROR,
2414 "%s %s server component started on port %u\n",
2415 msg,
2416 plugin->name,
2417 plugin->port);
2418 return GNUNET_SYSERR;
2419 }
2420 if ((NULL != plugin->server_v6) &&
2421 (NULL != plugin->server_v4))
2422 msg = "IPv4 and IPv6";
2423 else if (NULL != plugin->server_v6)
2424 msg = "IPv6";
2425 else if (NULL != plugin->server_v4)
2426 msg = "IPv4";
2427 LOG (GNUNET_ERROR_TYPE_DEBUG,
2428 "%s %s server component started on port %u\n",
2429 msg,
2430 plugin->name,
2431 plugin->port);
2432 return GNUNET_OK;
2433}
2434
2435
2436/**
2437 * Add an address to the server's set of addresses and notify transport
2438 *
2439 * @param cls the plugin handle
2440 * @param add_remove #GNUNET_YES on add, #GNUNET_NO on remove
2441 * @param addr the address
2442 * @param addrlen address length
2443 */
2444static void
2445server_add_address (void *cls,
2446 int add_remove,
2447 const struct sockaddr *addr,
2448 socklen_t addrlen)
2449{
2450 struct HTTP_Server_Plugin *plugin = cls;
2451 struct GNUNET_HELLO_Address *address;
2452 struct HttpAddressWrapper *w = NULL;
2453
2454 w = GNUNET_new (struct HttpAddressWrapper);
2455 w->address = http_common_address_from_socket (plugin->protocol,
2456 addr,
2457 addrlen);
2458 if (NULL == w->address)
2459 {
2460 GNUNET_free (w);
2461 return;
2462 }
2463 w->addrlen = http_common_address_get_size (w->address);
2464
2465 GNUNET_CONTAINER_DLL_insert (plugin->addr_head,
2466 plugin->addr_tail,
2467 w);
2468 LOG (GNUNET_ERROR_TYPE_DEBUG,
2469 "Notifying transport to add address `%s'\n",
2470 http_common_plugin_address_to_string (plugin->protocol,
2471 w->address,
2472 w->addrlen));
2473 /* modify our published address list */
2474#if BUILD_HTTPS
2475 address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
2476 "https_client", w->address,
2477 w->addrlen,
2478 GNUNET_HELLO_ADDRESS_INFO_NONE);
2479#else
2480 address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
2481 "http_client", w->address,
2482 w->addrlen,
2483 GNUNET_HELLO_ADDRESS_INFO_NONE);
2484#endif
2485
2486 plugin->env->notify_address (plugin->env->cls,
2487 add_remove,
2488 address);
2489 GNUNET_HELLO_address_free (address);
2490}
2491
2492
2493/**
2494 * Remove an address from the server's set of addresses and notify transport
2495 *
2496 * @param cls the plugin handle
2497 * @param add_remove #GNUNET_YES on add, #GNUNET_NO on remove
2498 * @param addr the address
2499 * @param addrlen address length
2500 */
2501static void
2502server_remove_address (void *cls,
2503 int add_remove,
2504 const struct sockaddr *addr,
2505 socklen_t addrlen)
2506{
2507 struct HTTP_Server_Plugin *plugin = cls;
2508 struct GNUNET_HELLO_Address *address;
2509 struct HttpAddressWrapper *w = plugin->addr_head;
2510 size_t saddr_len;
2511 void *saddr;
2512
2513 saddr = http_common_address_from_socket (plugin->protocol,
2514 addr,
2515 addrlen);
2516 if (NULL == saddr)
2517 return;
2518 saddr_len = http_common_address_get_size (saddr);
2519
2520 while (NULL != w)
2521 {
2522 if (GNUNET_YES ==
2523 http_common_cmp_addresses (w->address,
2524 w->addrlen,
2525 saddr,
2526 saddr_len))
2527 break;
2528 w = w->next;
2529 }
2530 GNUNET_free (saddr);
2531
2532 if (NULL == w)
2533 return;
2534
2535 LOG (GNUNET_ERROR_TYPE_DEBUG,
2536 "Notifying transport to remove address `%s'\n",
2537 http_common_plugin_address_to_string (plugin->protocol,
2538 w->address,
2539 w->addrlen));
2540 GNUNET_CONTAINER_DLL_remove (plugin->addr_head,
2541 plugin->addr_tail,
2542 w);
2543 /* modify our published address list */
2544#if BUILD_HTTPS
2545 address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
2546 "https_client", w->address,
2547 w->addrlen,
2548 GNUNET_HELLO_ADDRESS_INFO_NONE);
2549#else
2550 address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
2551 "http_client", w->address,
2552 w->addrlen,
2553 GNUNET_HELLO_ADDRESS_INFO_NONE);
2554#endif
2555 plugin->env->notify_address (plugin->env->cls, add_remove, address);
2556 GNUNET_HELLO_address_free (address);
2557 GNUNET_free (w->address);
2558 GNUNET_free (w);
2559}
2560
2561
2562/**
2563 * Our external IP address/port mapping has changed.
2564 *
2565 * @param cls closure, the 'struct LocalAddrList'
2566 * @param[in,out] app_ctx location where the app can store stuff
2567 * on add and retrieve it on remove
2568 * @param add_remove #GNUNET_YES to mean the new public IP address, #GNUNET_NO to mean
2569 * the previous (now invalid) one
2570 * @param ac address class the address belongs to
2571 * @param addr either the previous or the new public IP address
2572 * @param addrlen actual length of the address
2573 */
2574static void
2575server_nat_port_map_callback (void *cls,
2576 void **app_ctx,
2577 int add_remove,
2578 enum GNUNET_NAT_AddressClass ac,
2579 const struct sockaddr *addr,
2580 socklen_t addrlen)
2581{
2582 struct HTTP_Server_Plugin *plugin = cls;
2583
2584 (void) app_ctx;
2585 LOG (GNUNET_ERROR_TYPE_DEBUG,
2586 "NAT called to %s address `%s'\n",
2587 (add_remove == GNUNET_NO) ? "remove" : "add",
2588 GNUNET_a2s (addr, addrlen));
2589
2590 if (AF_INET == addr->sa_family)
2591 {
2592 struct sockaddr_in *s4 = (struct sockaddr_in *) addr;
2593
2594 if (GNUNET_NO == plugin->use_ipv4)
2595 return;
2596
2597 if ((NULL != plugin->server_addr_v4) &&
2598 (0 != memcmp (&plugin->server_addr_v4->sin_addr,
2599 &s4->sin_addr,
2600 sizeof(struct in_addr))))
2601 {
2602 LOG (GNUNET_ERROR_TYPE_DEBUG,
2603 "Skipping address `%s' (not bindto address)\n",
2604 GNUNET_a2s (addr, addrlen));
2605 return;
2606 }
2607 }
2608
2609 if (AF_INET6 == addr->sa_family)
2610 {
2611 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) addr;
2612 if (GNUNET_NO == plugin->use_ipv6)
2613 return;
2614
2615 if ((NULL != plugin->server_addr_v6) &&
2616 (0 != memcmp (&plugin->server_addr_v6->sin6_addr,
2617 &s6->sin6_addr, sizeof(struct in6_addr))))
2618 {
2619 LOG (GNUNET_ERROR_TYPE_DEBUG,
2620 "Skipping address `%s' (not bindto address)\n",
2621 GNUNET_a2s (addr, addrlen));
2622 return;
2623 }
2624 }
2625
2626 switch (add_remove)
2627 {
2628 case GNUNET_YES:
2629 server_add_address (cls, add_remove, addr, addrlen);
2630 break;
2631
2632 case GNUNET_NO:
2633 server_remove_address (cls, add_remove, addr, addrlen);
2634 break;
2635 }
2636}
2637
2638
2639/**
2640 * Get valid server addresses
2641 *
2642 * @param plugin the plugin handle
2643 * @param service_name the servicename
2644 * @param cfg configuration handle
2645 * @param addrs addresses
2646 * @param addr_lens address length
2647 * @return number of addresses
2648 */
2649static int
2650server_get_addresses (struct HTTP_Server_Plugin *plugin,
2651 const char *service_name,
2652 const struct GNUNET_CONFIGURATION_Handle *cfg,
2653 struct sockaddr ***addrs,
2654 socklen_t **addr_lens)
2655{
2656 int disablev6;
2657 unsigned long long port;
2658 struct addrinfo hints;
2659 struct addrinfo *res;
2660 struct addrinfo *pos;
2661 struct addrinfo *next;
2662 unsigned int i;
2663 int resi;
2664 int ret;
2665 struct sockaddr **saddrs;
2666 socklen_t *saddrlens;
2667 char *hostname;
2668
2669 *addrs = NULL;
2670 *addr_lens = NULL;
2671
2672 disablev6 = ! plugin->use_ipv6;
2673
2674 port = 0;
2675 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT"))
2676 {
2677 GNUNET_break (GNUNET_OK ==
2678 GNUNET_CONFIGURATION_get_value_number (cfg, service_name,
2679 "PORT", &port));
2680 if (port > 65535)
2681 {
2682 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2683 _ (
2684 "Require valid port number for service in configuration!\n"));
2685 return GNUNET_SYSERR;
2686 }
2687 }
2688 if (0 == port)
2689 {
2690 LOG (GNUNET_ERROR_TYPE_INFO,
2691 "Starting in listen only mode\n");
2692 return -1; /* listen only */
2693 }
2694
2695
2696 if (GNUNET_CONFIGURATION_have_value (cfg, service_name,
2697 "BINDTO"))
2698 {
2699 GNUNET_break (GNUNET_OK ==
2700 GNUNET_CONFIGURATION_get_value_string (cfg, service_name,
2701 "BINDTO", &hostname));
2702 }
2703 else
2704 hostname = NULL;
2705
2706 if (NULL != hostname)
2707 {
2708 LOG (GNUNET_ERROR_TYPE_DEBUG,
2709 "Resolving `%s' since that is where `%s' will bind to.\n",
2710 hostname, service_name);
2711 memset (&hints, 0, sizeof(struct addrinfo));
2712 if (disablev6)
2713 hints.ai_family = AF_INET;
2714 if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
2715 (NULL == res))
2716 {
2717 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2718 _ ("Failed to resolve `%s': %s\n"),
2719 hostname,
2720 gai_strerror (ret));
2721 GNUNET_free (hostname);
2722 return GNUNET_SYSERR;
2723 }
2724 next = res;
2725 i = 0;
2726 while (NULL != (pos = next))
2727 {
2728 next = pos->ai_next;
2729 if ((disablev6) && (pos->ai_family == AF_INET6))
2730 continue;
2731 i++;
2732 }
2733 if (0 == i)
2734 {
2735 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2736 _ ("Failed to find %saddress for `%s'.\n"),
2737 disablev6 ? "IPv4 " : "", hostname);
2738 freeaddrinfo (res);
2739 GNUNET_free (hostname);
2740 return GNUNET_SYSERR;
2741 }
2742 resi = i;
2743 saddrs = GNUNET_malloc ((resi + 1) * sizeof(struct sockaddr *));
2744 saddrlens = GNUNET_malloc ((resi + 1) * sizeof(socklen_t));
2745 i = 0;
2746 next = res;
2747 while (NULL != (pos = next))
2748 {
2749 next = pos->ai_next;
2750 if ((disablev6) && (pos->ai_family == AF_INET6))
2751 continue;
2752 if ((pos->ai_protocol != IPPROTO_TCP) && (0 != pos->ai_protocol))
2753 continue; /* not TCP */
2754 if ((pos->ai_socktype != SOCK_STREAM) && (0 != pos->ai_socktype))
2755 continue; /* huh? */
2756 LOG (GNUNET_ERROR_TYPE_DEBUG,
2757 "Service will bind to `%s'\n",
2758 GNUNET_a2s (pos->ai_addr,
2759 pos->ai_addrlen));
2760 if (pos->ai_family == AF_INET)
2761 {
2762 GNUNET_assert (pos->ai_addrlen == sizeof(struct sockaddr_in));
2763 saddrlens[i] = pos->ai_addrlen;
2764 saddrs[i] = GNUNET_malloc (saddrlens[i]);
2765 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
2766 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
2767 }
2768 else
2769 {
2770 GNUNET_assert (pos->ai_family == AF_INET6);
2771 GNUNET_assert (pos->ai_addrlen == sizeof(struct sockaddr_in6));
2772 saddrlens[i] = pos->ai_addrlen;
2773 saddrs[i] = GNUNET_malloc (saddrlens[i]);
2774 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
2775 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
2776 }
2777 i++;
2778 }
2779 GNUNET_free (hostname);
2780 freeaddrinfo (res);
2781 resi = i;
2782 }
2783 else
2784 {
2785 /* will bind against everything, just set port */
2786 if (disablev6)
2787 {
2788 /* V4-only */
2789 resi = 1;
2790 i = 0;
2791 saddrs = GNUNET_malloc ((resi + 1) * sizeof(struct sockaddr *));
2792 saddrlens = GNUNET_malloc ((resi + 1) * sizeof(socklen_t));
2793
2794 saddrlens[i] = sizeof(struct sockaddr_in);
2795 saddrs[i] = GNUNET_malloc (saddrlens[i]);
2796#if HAVE_SOCKADDR_IN_SIN_LEN
2797 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
2798#endif
2799 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
2800 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
2801 }
2802 else
2803 {
2804 /* dual stack */
2805 resi = 2;
2806 saddrs = GNUNET_malloc ((resi + 1) * sizeof(struct sockaddr *));
2807 saddrlens = GNUNET_malloc ((resi + 1) * sizeof(socklen_t));
2808 i = 0;
2809 saddrlens[i] = sizeof(struct sockaddr_in6);
2810 saddrs[i] = GNUNET_malloc (saddrlens[i]);
2811#if HAVE_SOCKADDR_IN_SIN_LEN
2812 ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
2813#endif
2814 ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
2815 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
2816 i++;
2817 saddrlens[i] = sizeof(struct sockaddr_in);
2818 saddrs[i] = GNUNET_malloc (saddrlens[i]);
2819#if HAVE_SOCKADDR_IN_SIN_LEN
2820 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
2821#endif
2822 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
2823 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
2824 }
2825 }
2826 *addrs = saddrs;
2827 *addr_lens = saddrlens;
2828 return resi;
2829}
2830
2831
2832/**
2833 * Ask NAT for addresses
2834 *
2835 * @param plugin the plugin handle
2836 */
2837static void
2838server_start_report_addresses (struct HTTP_Server_Plugin *plugin)
2839{
2840 int res = GNUNET_OK;
2841 struct sockaddr **addrs;
2842 socklen_t *addrlens;
2843
2844 res = server_get_addresses (plugin,
2845 plugin->name,
2846 plugin->env->cfg,
2847 &addrs, &addrlens);
2848 LOG (GNUNET_ERROR_TYPE_DEBUG,
2849 _ ("Found %u addresses to report to NAT service\n"),
2850 res);
2851
2852 if (GNUNET_SYSERR == res)
2853 {
2854 plugin->nat = NULL;
2855 return;
2856 }
2857
2858 plugin->nat
2859 = GNUNET_NAT_register (plugin->env->cfg,
2860 plugin->name,
2861 IPPROTO_TCP,
2862 (unsigned int) res,
2863 (const struct sockaddr **) addrs,
2864 addrlens,
2865 &server_nat_port_map_callback,
2866 NULL,
2867 plugin);
2868 while (res > 0)
2869 {
2870 res--;
2871 GNUNET_assert (NULL != addrs[res]);
2872 GNUNET_free (addrs[res]);
2873 }
2874 GNUNET_free (addrs);
2875 GNUNET_free (addrlens);
2876}
2877
2878
2879/**
2880 * Stop NAT for addresses
2881 *
2882 * @param plugin the plugin handle
2883 */
2884static void
2885server_stop_report_addresses (struct HTTP_Server_Plugin *plugin)
2886{
2887 struct HttpAddressWrapper *w;
2888
2889 /* Stop NAT handle */
2890 if (NULL != plugin->nat)
2891 {
2892 GNUNET_NAT_unregister (plugin->nat);
2893 plugin->nat = NULL;
2894 }
2895 /* Clean up addresses */
2896 while (NULL != plugin->addr_head)
2897 {
2898 w = plugin->addr_head;
2899 GNUNET_CONTAINER_DLL_remove (plugin->addr_head,
2900 plugin->addr_tail,
2901 w);
2902 GNUNET_free (w->address);
2903 GNUNET_free (w);
2904 }
2905}
2906
2907
2908/**
2909 * Check if IPv6 supported on this system
2910 *
2911 * @param plugin the plugin handle
2912 * @return #GNUNET_YES on success, else #GNUNET_NO
2913 */
2914static int
2915server_check_ipv6_support (struct HTTP_Server_Plugin *plugin)
2916{
2917 struct GNUNET_NETWORK_Handle *desc = NULL;
2918 int res = GNUNET_NO;
2919
2920 /* Probe IPv6 support */
2921 desc = GNUNET_NETWORK_socket_create (PF_INET6,
2922 SOCK_STREAM,
2923 0);
2924 if (NULL == desc)
2925 {
2926 if ((errno == ENOBUFS) ||
2927 (errno == ENOMEM) ||
2928 (errno == ENFILE) ||
2929 (errno == EACCES))
2930 {
2931 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
2932 "socket");
2933 }
2934 LOG (GNUNET_ERROR_TYPE_WARNING,
2935 _ ("Disabling IPv6 since it is not supported on this system!\n"));
2936 res = GNUNET_NO;
2937 }
2938 else
2939 {
2940 GNUNET_break (GNUNET_OK ==
2941 GNUNET_NETWORK_socket_close (desc));
2942 desc = NULL;
2943 res = GNUNET_YES;
2944 }
2945 LOG (GNUNET_ERROR_TYPE_DEBUG,
2946 "Testing IPv6 on this system: %s\n",
2947 (res == GNUNET_YES) ? "successful" : "failed");
2948 return res;
2949}
2950
2951
2952/**
2953 * Notify server about our external hostname
2954 *
2955 * @param cls plugin
2956 */
2957static void
2958server_notify_external_hostname (void *cls)
2959{
2960 struct HTTP_Server_Plugin *plugin = cls;
2961 struct HttpAddress *ext_addr;
2962 size_t ext_addr_len;
2963 unsigned int urlen;
2964 char *url;
2965
2966 plugin->notify_ext_task = NULL;
2967 GNUNET_asprintf (&url,
2968 "%s://%s",
2969 plugin->protocol,
2970 plugin->external_hostname);
2971 urlen = strlen (url) + 1;
2972 ext_addr = GNUNET_malloc (sizeof(struct HttpAddress) + urlen);
2973 ext_addr->options = htonl (plugin->options);
2974 ext_addr->urlen = htonl (urlen);
2975 ext_addr_len = sizeof(struct HttpAddress) + urlen;
2976 GNUNET_memcpy (&ext_addr[1], url, urlen);
2977 GNUNET_free (url);
2978
2979 LOG (GNUNET_ERROR_TYPE_DEBUG,
2980 "Notifying transport about external hostname address `%s'\n",
2981 plugin->external_hostname);
2982
2983#if BUILD_HTTPS
2984 if (GNUNET_YES == plugin->verify_external_hostname)
2985 LOG (GNUNET_ERROR_TYPE_INFO,
2986 "Enabling SSL verification for external hostname address `%s'\n",
2987 plugin->external_hostname);
2988 plugin->ext_addr
2989 = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
2990 "https_client",
2991 ext_addr,
2992 ext_addr_len,
2993 GNUNET_HELLO_ADDRESS_INFO_NONE);
2994 plugin->env->notify_address (plugin->env->cls,
2995 GNUNET_YES,
2996 plugin->ext_addr);
2997 GNUNET_free (ext_addr);
2998#else
2999 plugin->ext_addr
3000 = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
3001 "http_client",
3002 ext_addr,
3003 ext_addr_len,
3004 GNUNET_HELLO_ADDRESS_INFO_NONE);
3005 plugin->env->notify_address (plugin->env->cls,
3006 GNUNET_YES,
3007 plugin->ext_addr);
3008 GNUNET_free (ext_addr);
3009#endif
3010}
3011
3012
3013/**
3014 * Configure the plugin
3015 *
3016 * @param plugin plugin handle
3017 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
3018 */
3019static int
3020server_configure_plugin (struct HTTP_Server_Plugin *plugin)
3021{
3022 unsigned long long port;
3023 unsigned long long max_connections;
3024 char *bind4_address = NULL;
3025 char *bind6_address = NULL;
3026 char *eh_tmp = NULL;
3027 int external_hostname_use_port;
3028
3029 /* Use IPv4? */
3030 if (GNUNET_CONFIGURATION_have_value
3031 (plugin->env->cfg, plugin->name, "USE_IPv4"))
3032 {
3033 plugin->use_ipv4 =
3034 GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg,
3035 plugin->name,
3036 "USE_IPv4");
3037 }
3038 else
3039 plugin->use_ipv4 = GNUNET_YES;
3040 LOG (GNUNET_ERROR_TYPE_DEBUG,
3041 _ ("IPv4 support is %s\n"),
3042 (plugin->use_ipv4 == GNUNET_YES) ? "enabled" : "disabled");
3043
3044 /* Use IPv6? */
3045 if (GNUNET_CONFIGURATION_have_value
3046 (plugin->env->cfg, plugin->name, "USE_IPv6"))
3047 {
3048 plugin->use_ipv6 =
3049 GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg,
3050 plugin->name,
3051 "USE_IPv6");
3052 }
3053 else
3054 plugin->use_ipv6 = GNUNET_YES;
3055 LOG (GNUNET_ERROR_TYPE_DEBUG,
3056 _ ("IPv6 support is %s\n"),
3057 (plugin->use_ipv6 == GNUNET_YES) ? "enabled" : "disabled");
3058
3059 if ((plugin->use_ipv4 == GNUNET_NO) && (plugin->use_ipv6 == GNUNET_NO))
3060 {
3061 LOG (GNUNET_ERROR_TYPE_ERROR,
3062 _ ("Neither IPv4 nor IPv6 are enabled! Fix in configuration\n"));
3063 return GNUNET_SYSERR;
3064 }
3065
3066 /* Reading port number from config file */
3067 if ((GNUNET_OK !=
3068 GNUNET_CONFIGURATION_get_value_number (plugin->env->cfg,
3069 plugin->name,
3070 "PORT", &port)) || (port > 65535))
3071 {
3072 LOG (GNUNET_ERROR_TYPE_ERROR,
3073 _ ("Port is required! Fix in configuration\n"));
3074 return GNUNET_SYSERR;
3075 }
3076 plugin->port = port;
3077
3078 LOG (GNUNET_ERROR_TYPE_INFO,
3079 _ ("Using port %u\n"), plugin->port);
3080
3081 if ((plugin->use_ipv4 == GNUNET_YES) &&
3082 (GNUNET_YES ==
3083 GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg,
3084 plugin->name,
3085 "BINDTO",
3086 &bind4_address)))
3087 {
3088 LOG (GNUNET_ERROR_TYPE_DEBUG,
3089 "Binding %s plugin to specific IPv4 address: `%s'\n",
3090 plugin->protocol,
3091 bind4_address);
3092 plugin->server_addr_v4 = GNUNET_new (struct sockaddr_in);
3093 if (1 != inet_pton (AF_INET,
3094 bind4_address,
3095 &plugin->server_addr_v4->sin_addr))
3096 {
3097 LOG (GNUNET_ERROR_TYPE_ERROR,
3098 _ ("Specific IPv4 address `%s' in configuration file is invalid!\n"),
3099 bind4_address);
3100 GNUNET_free (bind4_address);
3101 GNUNET_free (plugin->server_addr_v4);
3102 plugin->server_addr_v4 = NULL;
3103 return GNUNET_SYSERR;
3104 }
3105 else
3106 {
3107 LOG (GNUNET_ERROR_TYPE_DEBUG,
3108 "Binding to IPv4 address %s\n",
3109 bind4_address);
3110 plugin->server_addr_v4->sin_family = AF_INET;
3111 plugin->server_addr_v4->sin_port = htons (plugin->port);
3112 }
3113 GNUNET_free (bind4_address);
3114 }
3115
3116 if ((plugin->use_ipv6 == GNUNET_YES) &&
3117 (GNUNET_YES ==
3118 GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg,
3119 plugin->name,
3120 "BINDTO6",
3121 &bind6_address)))
3122 {
3123 LOG (GNUNET_ERROR_TYPE_DEBUG,
3124 "Binding %s plugin to specific IPv6 address: `%s'\n",
3125 plugin->protocol, bind6_address);
3126 plugin->server_addr_v6 = GNUNET_new (struct sockaddr_in6);
3127 if (1 !=
3128 inet_pton (AF_INET6,
3129 bind6_address,
3130 &plugin->server_addr_v6->sin6_addr))
3131 {
3132 LOG (GNUNET_ERROR_TYPE_ERROR,
3133 _ ("Specific IPv6 address `%s' in configuration file is invalid!\n"),
3134 bind6_address);
3135 GNUNET_free (bind6_address);
3136 GNUNET_free (plugin->server_addr_v6);
3137 plugin->server_addr_v6 = NULL;
3138 return GNUNET_SYSERR;
3139 }
3140 else
3141 {
3142 LOG (GNUNET_ERROR_TYPE_DEBUG,
3143 "Binding to IPv6 address %s\n",
3144 bind6_address);
3145 plugin->server_addr_v6->sin6_family = AF_INET6;
3146 plugin->server_addr_v6->sin6_port = htons (plugin->port);
3147 }
3148 GNUNET_free (bind6_address);
3149 }
3150
3151 plugin->verify_external_hostname = GNUNET_NO;
3152#if BUILD_HTTPS
3153 plugin->verify_external_hostname
3154 = GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg,
3155 plugin->name,
3156 "VERIFY_EXTERNAL_HOSTNAME");
3157 if (GNUNET_SYSERR == plugin->verify_external_hostname)
3158 plugin->verify_external_hostname = GNUNET_NO;
3159 if (GNUNET_YES == plugin->verify_external_hostname)
3160 plugin->options |= HTTP_OPTIONS_VERIFY_CERTIFICATE;
3161#endif
3162 external_hostname_use_port
3163 = GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg,
3164 plugin->name,
3165 "EXTERNAL_HOSTNAME_USE_PORT");
3166 if (GNUNET_SYSERR == external_hostname_use_port)
3167 external_hostname_use_port = GNUNET_NO;
3168
3169
3170 if (GNUNET_YES ==
3171 GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg,
3172 plugin->name,
3173 "EXTERNAL_HOSTNAME",
3174 &eh_tmp))
3175 {
3176 char *tmp;
3177 char *pos = NULL;
3178 char *pos_url = NULL;
3179
3180 if (NULL != strstr (eh_tmp, "://"))
3181 tmp = &strstr (eh_tmp, "://")[3];
3182 else
3183 tmp = eh_tmp;
3184
3185 if (GNUNET_YES == external_hostname_use_port)
3186 {
3187 if ((strlen (tmp) > 1) && (NULL != (pos = strchr (tmp, '/'))))
3188 {
3189 pos_url = pos + 1;
3190 pos[0] = '\0';
3191 GNUNET_asprintf (&plugin->external_hostname,
3192 "%s:%u/%s",
3193 tmp,
3194 (uint16_t) port,
3195 pos_url);
3196 }
3197 else
3198 GNUNET_asprintf (&plugin->external_hostname,
3199 "%s:%u",
3200 tmp,
3201 (uint16_t) port);
3202 }
3203 else
3204 plugin->external_hostname = GNUNET_strdup (tmp);
3205 GNUNET_free (eh_tmp);
3206
3207 LOG (GNUNET_ERROR_TYPE_INFO,
3208 _ ("Using external hostname `%s'\n"),
3209 plugin->external_hostname);
3210 plugin->notify_ext_task = GNUNET_SCHEDULER_add_now (
3211 &server_notify_external_hostname,
3212 plugin);
3213
3214 /* Use only configured external hostname */
3215 if (GNUNET_CONFIGURATION_have_value
3216 (plugin->env->cfg,
3217 plugin->name,
3218 "EXTERNAL_HOSTNAME_ONLY"))
3219 {
3220 plugin->external_only =
3221 GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg,
3222 plugin->name,
3223 "EXTERNAL_HOSTNAME_ONLY");
3224 }
3225 else
3226 plugin->external_only = GNUNET_NO;
3227
3228 if (GNUNET_YES == plugin->external_only)
3229 LOG (GNUNET_ERROR_TYPE_DEBUG,
3230 _ ("Notifying transport only about hostname `%s'\n"),
3231 plugin->external_hostname);
3232 }
3233 else
3234 LOG (GNUNET_ERROR_TYPE_DEBUG,
3235 "No external hostname configured\n");
3236
3237 /* Optional parameters */
3238 if (GNUNET_OK !=
3239 GNUNET_CONFIGURATION_get_value_number (plugin->env->cfg,
3240 plugin->name,
3241 "MAX_CONNECTIONS",
3242 &max_connections))
3243 max_connections = 128;
3244 plugin->max_request = max_connections;
3245
3246 LOG (GNUNET_ERROR_TYPE_DEBUG,
3247 _ ("Maximum number of connections is %u\n"),
3248 plugin->max_request);
3249
3250 plugin->peer_id_length = strlen (GNUNET_i2s_full (plugin->env->my_identity));
3251
3252 return GNUNET_OK;
3253}
3254
3255
3256/**
3257 * Exit point from the plugin.
3258 *
3259 * @param cls api
3260 * @return NULL
3261 */
3262void *
3263LIBGNUNET_PLUGIN_TRANSPORT_DONE (void *cls)
3264{
3265 struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
3266 struct HTTP_Server_Plugin *plugin = api->cls;
3267
3268 if (NULL == api->cls)
3269 {
3270 /* Free for stub mode */
3271 GNUNET_free (api);
3272 return NULL;
3273 }
3274 plugin->in_shutdown = GNUNET_YES;
3275 LOG (GNUNET_ERROR_TYPE_INFO,
3276 _ ("Shutting down plugin `%s'\n"),
3277 plugin->name);
3278
3279 if (NULL != plugin->notify_ext_task)
3280 {
3281 GNUNET_SCHEDULER_cancel (plugin->notify_ext_task);
3282 plugin->notify_ext_task = NULL;
3283 }
3284
3285 if (NULL != plugin->ext_addr)
3286 {
3287 LOG (GNUNET_ERROR_TYPE_DEBUG,
3288 "Notifying transport to remove address `%s'\n",
3289 http_common_plugin_address_to_string (plugin->protocol,
3290 plugin->ext_addr->address,
3291 plugin->ext_addr->address_length));
3292#if BUILD_HTTPS
3293 plugin->env->notify_address (plugin->env->cls,
3294 GNUNET_NO,
3295 plugin->ext_addr);
3296#else
3297 plugin->env->notify_address (plugin->env->cls,
3298 GNUNET_NO,
3299 plugin->ext_addr);
3300#endif
3301 GNUNET_HELLO_address_free (plugin->ext_addr);
3302 plugin->ext_addr = NULL;
3303 }
3304
3305 /* Stop to report addresses to transport service */
3306 server_stop_report_addresses (plugin);
3307 if (NULL != plugin->server_v4_task)
3308 {
3309 GNUNET_SCHEDULER_cancel (plugin->server_v4_task);
3310 plugin->server_v4_task = NULL;
3311 }
3312
3313 if (NULL != plugin->server_v6_task)
3314 {
3315 GNUNET_SCHEDULER_cancel (plugin->server_v6_task);
3316 plugin->server_v6_task = NULL;
3317 }
3318#if BUILD_HTTPS
3319 GNUNET_free (plugin->crypto_init);
3320 GNUNET_free (plugin->cert);
3321 GNUNET_free (plugin->key);
3322#endif
3323 GNUNET_CONTAINER_multipeermap_iterate (plugin->sessions,
3324 &destroy_session_shutdown_cb,
3325 plugin);
3326 GNUNET_CONTAINER_multipeermap_destroy (plugin->sessions);
3327 plugin->sessions = NULL;
3328 if (NULL != plugin->server_v4)
3329 {
3330 MHD_stop_daemon (plugin->server_v4);
3331 plugin->server_v4 = NULL;
3332 }
3333 if (NULL != plugin->server_v6)
3334 {
3335 MHD_stop_daemon (plugin->server_v6);
3336 plugin->server_v6 = NULL;
3337 }
3338 /* Clean up */
3339 GNUNET_free (plugin->external_hostname);
3340 GNUNET_free (plugin->ext_addr);
3341 GNUNET_free (plugin->server_addr_v4);
3342 GNUNET_free (plugin->server_addr_v6);
3343 regfree (&plugin->url_regex);
3344
3345 LOG (GNUNET_ERROR_TYPE_DEBUG,
3346 _ ("Shutdown for plugin `%s' complete\n"),
3347 plugin->name);
3348
3349 GNUNET_free (plugin);
3350 GNUNET_free (api);
3351 return NULL;
3352}
3353
3354
3355/**
3356 * Function called for a quick conversion of the binary address to
3357 * a numeric address. Note that the caller must not free the
3358 * address and that the next call to this function is allowed
3359 * to override the address again.
3360 *
3361 * @param cls unused
3362 * @param addr binary address
3363 * @param addrlen length of the address
3364 * @return string representing the same address
3365 */
3366static const char *
3367http_server_plugin_address_to_string (void *cls,
3368 const void *addr,
3369 size_t addrlen)
3370{
3371 return http_common_plugin_address_to_string (PLUGIN_NAME,
3372 addr,
3373 addrlen);
3374}
3375
3376
3377/**
3378 * Function obtain the network type for a session
3379 *
3380 * @param cls closure (`struct HTTP_Server_Plugin *`)
3381 * @param session the session
3382 * @return the network type in HBO or #GNUNET_SYSERR
3383 */
3384static enum GNUNET_NetworkType
3385http_server_plugin_get_network (void *cls,
3386 struct GNUNET_ATS_Session *session)
3387{
3388 return session->scope;
3389}
3390
3391
3392/**
3393 * Function obtain the network type for an address.
3394 *
3395 * @param cls closure (`struct Plugin *`)
3396 * @param address the address
3397 * @return the network type
3398 */
3399static enum GNUNET_NetworkType
3400http_server_plugin_get_network_for_address (void *cls,
3401 const struct
3402 GNUNET_HELLO_Address *address)
3403{
3404 struct HTTP_Server_Plugin *plugin = cls;
3405
3406 return http_common_get_network_for_address (plugin->env,
3407 address);
3408}
3409
3410
3411/**
3412 * Function that will be called whenever the transport service wants to
3413 * notify the plugin that the inbound quota changed and that the plugin
3414 * should update it's delay for the next receive value
3415 *
3416 * @param cls closure
3417 * @param peer which peer was the session for
3418 * @param session which session is being updated
3419 * @param delay new delay to use for receiving
3420 */
3421static void
3422http_server_plugin_update_inbound_delay (void *cls,
3423 const struct GNUNET_PeerIdentity *peer,
3424 struct GNUNET_ATS_Session *session,
3425 struct GNUNET_TIME_Relative delay)
3426{
3427 session->next_receive = GNUNET_TIME_relative_to_absolute (delay);
3428 LOG (GNUNET_ERROR_TYPE_DEBUG,
3429 "New inbound delay %s\n",
3430 GNUNET_STRINGS_relative_time_to_string (delay,
3431 GNUNET_NO));
3432 if (NULL != session->recv_wakeup_task)
3433 {
3434 GNUNET_SCHEDULER_cancel (session->recv_wakeup_task);
3435 session->recv_wakeup_task
3436 = GNUNET_SCHEDULER_add_delayed (delay,
3437 &server_wake_up,
3438 session);
3439 }
3440}
3441
3442
3443/**
3444 * Return information about the given session to the
3445 * monitor callback.
3446 *
3447 * @param cls the `struct Plugin` with the monitor callback (`sic`)
3448 * @param peer peer we send information about
3449 * @param value our `struct GNUNET_ATS_Session` to send information about
3450 * @return #GNUNET_OK (continue to iterate)
3451 */
3452static int
3453send_session_info_iter (void *cls,
3454 const struct GNUNET_PeerIdentity *peer,
3455 void *value)
3456{
3457 struct HTTP_Server_Plugin *plugin = cls;
3458 struct GNUNET_ATS_Session *session = value;
3459
3460 notify_session_monitor (plugin,
3461 session,
3462 GNUNET_TRANSPORT_SS_INIT);
3463 return GNUNET_OK;
3464}
3465
3466
3467/**
3468 * Begin monitoring sessions of a plugin. There can only
3469 * be one active monitor per plugin (i.e. if there are
3470 * multiple monitors, the transport service needs to
3471 * multiplex the generated events over all of them).
3472 *
3473 * @param cls closure of the plugin
3474 * @param sic callback to invoke, NULL to disable monitor;
3475 * plugin will being by iterating over all active
3476 * sessions immediately and then enter monitor mode
3477 * @param sic_cls closure for @a sic
3478 */
3479static void
3480http_server_plugin_setup_monitor (void *cls,
3481 GNUNET_TRANSPORT_SessionInfoCallback sic,
3482 void *sic_cls)
3483{
3484 struct HTTP_Server_Plugin *plugin = cls;
3485
3486 plugin->sic = sic;
3487 plugin->sic_cls = sic_cls;
3488 if (NULL != sic)
3489 {
3490 GNUNET_CONTAINER_multipeermap_iterate (plugin->sessions,
3491 &send_session_info_iter,
3492 plugin);
3493 /* signal end of first iteration */
3494 sic (sic_cls, NULL, NULL);
3495 }
3496}
3497
3498
3499/**
3500 * Entry point for the plugin.
3501 *
3502 * @param cls env
3503 * @return api
3504 */
3505void *
3506LIBGNUNET_PLUGIN_TRANSPORT_INIT (void *cls)
3507{
3508 struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
3509 struct GNUNET_TRANSPORT_PluginFunctions *api;
3510 struct HTTP_Server_Plugin *plugin;
3511
3512 if (NULL == env->receive)
3513 {
3514 /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully
3515 initialize the plugin or the API */
3516 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
3517 api->cls = NULL;
3518 api->address_to_string = &http_server_plugin_address_to_string;
3519 api->string_to_address = &http_common_plugin_string_to_address;
3520 api->address_pretty_printer = &http_common_plugin_address_pretty_printer;
3521 return api;
3522 }
3523 plugin = GNUNET_new (struct HTTP_Server_Plugin);
3524 plugin->env = env;
3525 plugin->sessions = GNUNET_CONTAINER_multipeermap_create (128,
3526 GNUNET_YES);
3527
3528 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
3529 api->cls = plugin;
3530 api->send = &http_server_plugin_send;
3531 api->disconnect_peer = &http_server_plugin_disconnect_peer;
3532 api->disconnect_session = &http_server_plugin_disconnect_session;
3533 api->query_keepalive_factor = &http_server_query_keepalive_factor;
3534 api->check_address = &http_server_plugin_address_suggested;
3535 api->get_session = &http_server_plugin_get_session;
3536
3537 api->address_to_string = &http_server_plugin_address_to_string;
3538 api->string_to_address = &http_common_plugin_string_to_address;
3539 api->address_pretty_printer = &http_common_plugin_address_pretty_printer;
3540 api->get_network = &http_server_plugin_get_network;
3541 api->get_network_for_address = &http_server_plugin_get_network_for_address;
3542 api->update_session_timeout = &http_server_plugin_update_session_timeout;
3543 api->update_inbound_delay = &http_server_plugin_update_inbound_delay;
3544 api->setup_monitor = &http_server_plugin_setup_monitor;
3545#if BUILD_HTTPS
3546 plugin->name = "transport-https_server";
3547 plugin->protocol = "https";
3548#else
3549 plugin->name = "transport-http_server";
3550 plugin->protocol = "http";
3551#endif
3552
3553 if (GNUNET_YES ==
3554 GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
3555 plugin->name,
3556 "TCP_STEALTH"))
3557 {
3558#ifdef TCP_STEALTH
3559 plugin->options |= HTTP_OPTIONS_TCP_STEALTH;
3560#else
3561 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3562 _ ("TCP_STEALTH not supported on this platform.\n"));
3563 LIBGNUNET_PLUGIN_TRANSPORT_DONE (api);
3564 return NULL;
3565#endif
3566 }
3567
3568 /* Compile URL regex */
3569 if (regcomp (&plugin->url_regex,
3570 URL_REGEX,
3571 REG_EXTENDED))
3572 {
3573 LOG (GNUNET_ERROR_TYPE_ERROR,
3574 _ ("Unable to compile URL regex\n"));
3575 LIBGNUNET_PLUGIN_TRANSPORT_DONE (api);
3576 return NULL;
3577 }
3578
3579 /* Configure plugin */
3580 if (GNUNET_SYSERR == server_configure_plugin (plugin))
3581 {
3582 LIBGNUNET_PLUGIN_TRANSPORT_DONE (api);
3583 return NULL;
3584 }
3585
3586 /* Check IPv6 support */
3587 if (GNUNET_YES == plugin->use_ipv6)
3588 plugin->use_ipv6 = server_check_ipv6_support (plugin);
3589
3590 /* Report addresses to transport service */
3591 if (GNUNET_NO == plugin->external_only)
3592 server_start_report_addresses (plugin);
3593
3594 if (GNUNET_SYSERR == server_start (plugin))
3595 {
3596 LIBGNUNET_PLUGIN_TRANSPORT_DONE (api);
3597 return NULL;
3598 }
3599 return api;
3600}
3601
3602
3603/* end of plugin_transport_http_server.c */
diff --git a/src/transport/plugin_transport_smtp.c b/src/transport/plugin_transport_smtp.c
deleted file mode 100644
index f3db4fc5a..000000000
--- a/src/transport/plugin_transport_smtp.c
+++ /dev/null
@@ -1,750 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2003-2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/plugin_transport_smtp.c
23 * @brief Implementation of the SMTP transport service
24 * @author Christian Grothoff
25 * @author Renaldo Ferreira
26 */
27
28#include "platform.h"
29#include "gnunet_util.h"
30#include "gnunet_constants.h"
31#include "gnunet_protocols.h"
32#include "gnunet_transport.h"
33#include "gnunet_stats_service.h"
34#include <libesmtp.h>
35#include <signal.h>
36
37
38/**
39 * The default maximum size of each outbound SMTP message.
40 */
41#define SMTP_MESSAGE_SIZE 65528
42
43#define DEBUG_SMTP GNUNET_EXTRA_LOGGING
44
45#define FILTER_STRING_SIZE 64
46
47/* how long can a line in base64 encoded
48 mime text be? (in characters, excluding "\n") */
49#define MAX_CHAR_PER_LINE 76
50
51#define EBUF_LEN 128
52
53/**
54 * Host-Address in a SMTP network.
55 */
56typedef struct
57{
58 /**
59 * Filter line that every sender must include in the E-mails such
60 * that the receiver can effectively filter out the GNUnet traffic
61 * from the E-mail.
62 */
63 char filter[FILTER_STRING_SIZE];
64
65 /**
66 * Claimed E-mail address of the sender.
67 * Format is "foo@bar.com" with null termination, padded to be
68 * of a multiple of 8 bytes long.
69 */
70 char senderAddress[0];
71} EmailAddress;
72
73GNUNET_NETWORK_STRUCT_BEGIN
74
75/**
76 * Encapsulation of a GNUnet message in the SMTP mail body (before
77 * base64 encoding).
78 */
79typedef struct
80{
81 GNUNET_MessageHeader header;
82
83 /**
84 * What is the identity of the sender (GNUNET_hash of public key)
85 */
86 GNUNET_PeerIdentity sender;
87} SMTPMessage;
88GNUNET_NETWORK_STRUCT_END
89
90/* *********** globals ************* */
91
92/**
93 * apis (our advertised API and the core api )
94 */
95static GNUNET_CoreAPIForTransport *core_api;
96
97static struct GNUNET_GE_Context *ectx;
98
99/**
100 * Thread that listens for inbound messages
101 */
102static struct GNUNET_ThreadHandle *dispatchThread;
103
104/**
105 * Flag to indicate that server has been shut down.
106 */
107static int smtp_shutdown = GNUNET_YES;
108
109/**
110 * Set to the SMTP server hostname (and port) for outgoing messages.
111 */
112static char *smtp_server_name;
113
114static char *pipename;
115
116/**
117 * Lock for uses of libesmtp (not thread-safe).
118 */
119static struct GNUNET_Mutex *lock;
120
121/**
122 * Old handler for SIGPIPE (kept to be able to restore).
123 */
124static struct sigaction old_handler;
125
126static char *email;
127
128static GNUNET_TransportAPI smtpAPI;
129
130static GNUNET_Stats_ServiceAPI *stats;
131
132static int stat_bytesReceived;
133
134static int stat_bytesSent;
135
136static int stat_bytesDropped;
137
138/**
139 * How many e-mails are we allowed to send per hour?
140 */
141static unsigned long long rate_limit;
142
143static GNUNET_CronTime last_transmission;
144
145
146/* ********************* the real stuff ******************* */
147
148#define strAUTOncmp(a, b) strncmp (a, b, strlen (b))
149
150/**
151 * Listen to the pipe, decode messages and send to core.
152 */
153static void *
154listenAndDistribute (void *unused)
155{
156 char *line;
157 unsigned int linesize;
158 SMTPMessage *mp;
159 FILE *fdes;
160 char *retl;
161 char *out;
162 unsigned int size;
163 GNUNET_TransportPacket *coreMP;
164 int fd;
165 unsigned int pos;
166
167 linesize = ((GNUNET_MAX_BUFFER_SIZE * 4 / 3) + 8) * (MAX_CHAR_PER_LINE + 2)
168 / MAX_CHAR_PER_LINE; /* maximum size of a line supported */
169 line = GNUNET_malloc (linesize + 2); /* 2 bytes for off-by-one errors, just to be safe... */
170
171#define READLINE(l, limit) \
172 do { retl = fgets (l, (limit), fdes); \
173 if ((retl == NULL) || (smtp_shutdown == GNUNET_YES)) { \
174 goto END; \
175 } \
176 if (core_api->load_monitor != NULL) \
177 GNUNET_network_monitor_notify_transmission (core_api->load_monitor, \
178 GNUNET_ND_DOWNLOAD, \
179 strlen (retl)); \
180 } while (0)
181
182
183 while (smtp_shutdown == GNUNET_NO)
184 {
185 fd = OPEN (pipename, O_RDONLY | O_ASYNC);
186 if (fd == -1)
187 {
188 if (smtp_shutdown == GNUNET_NO)
189 GNUNET_thread_sleep (5 * GNUNET_CRON_SECONDS);
190 continue;
191 }
192 fdes = fdopen (fd, "r");
193 while (smtp_shutdown == GNUNET_NO)
194 {
195 /* skip until end of header */
196 do
197 {
198 READLINE (line, linesize);
199 }
200 while ((line[0] != '\r') && (line[0] != '\n')); /* expect newline */
201 READLINE (line, linesize); /* read base64 encoded message; decode, process */
202 pos = 0;
203 while (1)
204 {
205 pos = strlen (line) - 1; /* ignore new line */
206 READLINE (&line[pos], linesize - pos); /* read base64 encoded message; decode, process */
207 if ((line[pos] == '\r') || (line[pos] == '\n'))
208 break; /* empty line => end of message! */
209 }
210 size = GNUNET_STRINGS_base64_decode (line, pos, &out);
211 if (size < sizeof(SMTPMessage))
212 {
213 GNUNET_GE_BREAK (ectx, 0);
214 GNUNET_free (out);
215 goto END;
216 }
217
218 mp = (SMTPMessage *) &out[size - sizeof(SMTPMessage)];
219 if (ntohs (mp->header.size) != size)
220 {
221 GNUNET_GE_LOG (ectx,
222 GNUNET_GE_WARNING | GNUNET_GE_BULK | GNUNET_GE_USER,
223 _ ("Received malformed message via %s. Ignored.\n"),
224 "SMTP");
225#if DEBUG_SMTP
226 GNUNET_GE_LOG (ectx,
227 GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER,
228 "Size returned by base64=%d, in the msg=%d.\n", size,
229 ntohl (mp->size));
230#endif
231 GNUNET_free (out);
232 goto END;
233 }
234 if (stats != NULL)
235 stats->change (stat_bytesReceived, size);
236 coreMP = GNUNET_new (GNUNET_TransportPacket);
237 coreMP->msg = out;
238 coreMP->size = size - sizeof(SMTPMessage);
239 coreMP->tsession = NULL;
240 coreMP->sender = mp->sender;
241#if DEBUG_SMTP
242 GNUNET_GE_LOG (ectx, GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER,
243 "SMTP message passed to the core.\n");
244#endif
245
246 core_api->receive (coreMP);
247 }
248END:
249#if DEBUG_SMTP
250 GNUNET_GE_LOG (ectx, GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER,
251 "SMTP message processed.\n");
252#endif
253 if (fdes != NULL)
254 fclose (fdes);
255 }
256 GNUNET_free (line);
257 return NULL;
258}
259
260
261/* *************** API implementation *************** */
262
263/**
264 * Verify that a hello-Message is correct (a node is reachable at that
265 * address). Since the reply will be asynchronous, a method must be
266 * called on success.
267 *
268 * @param hello the hello message to verify
269 * (the signature/crc have been verified before)
270 * @return GNUNET_OK on success, GNUNET_SYSERR on error
271 */
272static int
273api_verify_hello (const GNUNET_MessageHello *hello)
274{
275 const EmailAddress *maddr;
276
277 maddr = (const EmailAddress *) &hello[1];
278 if ((ntohs (hello->header.size) !=
279 sizeof(GNUNET_MessageHello) + ntohs (hello->senderAddressSize)) ||
280 (maddr->senderAddress
281 [ntohs (hello->senderAddressSize) - 1 - FILTER_STRING_SIZE] != '\0'))
282 {
283 GNUNET_GE_BREAK (ectx, 0);
284 return GNUNET_SYSERR; /* obviously invalid */
285 }
286 if (NULL == strstr (maddr->filter, ": "))
287 return GNUNET_SYSERR;
288 return GNUNET_OK;
289}
290
291
292/**
293 * Create a hello-Message for the current node. The hello is created
294 * without signature and without a timestamp. The GNUnet core will
295 * GNUNET_RSA_sign the message and add an expiration time.
296 *
297 * @return hello on success, NULL on error
298 */
299static GNUNET_MessageHello *
300api_create_hello ()
301{
302 GNUNET_MessageHello *msg;
303 char *filter;
304 EmailAddress *haddr;
305 int i;
306
307 GNUNET_GC_get_configuration_value_string (core_api->cfg, "SMTP", "FILTER",
308 "X-mailer: GNUnet", &filter);
309 if (NULL == strstr (filter, ": "))
310 {
311 GNUNET_GE_LOG (ectx, GNUNET_GE_WARNING | GNUNET_GE_BULK | GNUNET_GE_USER,
312 _ ("SMTP filter string to invalid, lacks ': '\n"));
313 GNUNET_free (filter);
314 return NULL;
315 }
316
317 if (strlen (filter) > FILTER_STRING_SIZE)
318 {
319 filter[FILTER_STRING_SIZE] = '\0';
320 GNUNET_GE_LOG (ectx, GNUNET_GE_WARNING | GNUNET_GE_BULK | GNUNET_GE_USER,
321 _ ("SMTP filter string to long, capped to `%s'\n"), filter);
322 }
323 i = (strlen (email) + 8) & (~7); /* make multiple of 8 */
324 msg =
325 GNUNET_malloc (sizeof(GNUNET_MessageHello) + sizeof(EmailAddress) + i);
326 memset (msg, 0, sizeof(GNUNET_MessageHello) + sizeof(EmailAddress) + i);
327 haddr = (EmailAddress *) &msg[1];
328 memset (&haddr->filter[0], 0, FILTER_STRING_SIZE);
329 strcpy (&haddr->filter[0], filter);
330 GNUNET_memcpy (&haddr->senderAddress[0], email, strlen (email) + 1);
331 msg->senderAddressSize = htons (strlen (email) + 1 + sizeof(EmailAddress));
332 msg->protocol = htons (GNUNET_TRANSPORT_PROTOCOL_NUMBER_SMTP);
333 msg->MTU = htonl (smtpAPI.mtu);
334 msg->header.size = htons (GNUNET_sizeof_hello (msg));
335 if (api_verify_hello (msg) == GNUNET_SYSERR)
336 GNUNET_GE_ASSERT (ectx, 0);
337 GNUNET_free (filter);
338 return msg;
339}
340
341
342struct GetMessageClosure
343{
344 unsigned int esize;
345 unsigned int pos;
346 char *ebody;
347};
348
349static const char *
350get_message (void **buf, int *len, void *cls)
351{
352 struct GetMessageClosure *gmc = cls;
353
354 *buf = NULL;
355 if (len == NULL)
356 {
357 gmc->pos = 0;
358 return NULL;
359 }
360 if (gmc->pos == gmc->esize)
361 return NULL; /* done */
362 *len = gmc->esize;
363 gmc->pos = gmc->esize;
364 return gmc->ebody;
365}
366
367
368/**
369 * Send a message to the specified remote node.
370 *
371 * @param tsession the GNUNET_MessageHello identifying the remote node
372 * @param msg what to send
373 * @param size the size of the message
374 * @param important is this message important enough to override typical limits?
375 * @return GNUNET_SYSERR on error, GNUNET_OK on success
376 */
377static int
378api_send (GNUNET_TSession *tsession, const void *msg, const unsigned int size,
379 int important)
380{
381 const GNUNET_MessageHello *hello;
382 const EmailAddress *haddr;
383 char *m;
384 char *filter;
385 char *fvalue;
386 SMTPMessage *mp;
387 struct GetMessageClosure gm_cls;
388 smtp_session_t session;
389 smtp_message_t message;
390 smtp_recipient_t recipient;
391
392#define EBUF_LEN 128
393 char ebuf[EBUF_LEN];
394 GNUNET_CronTime now;
395
396 if (smtp_shutdown == GNUNET_YES)
397 return GNUNET_SYSERR;
398 if ((size == 0) || (size > smtpAPI.mtu))
399 {
400 GNUNET_GE_BREAK (ectx, 0);
401 return GNUNET_SYSERR;
402 }
403 now = GNUNET_get_time ();
404 if ((important != GNUNET_YES) &&
405 ( ((now - last_transmission) * rate_limit) < GNUNET_CRON_HOURS) )
406 return GNUNET_NO; /* rate too high */
407 last_transmission = now;
408
409 hello = (const GNUNET_MessageHello *) tsession->internal;
410 if (hello == NULL)
411 return GNUNET_SYSERR;
412 GNUNET_mutex_lock (lock);
413 session = smtp_create_session ();
414 if (session == NULL)
415 {
416 GNUNET_GE_LOG (ectx,
417 GNUNET_GE_ERROR | GNUNET_GE_ADMIN | GNUNET_GE_USER
418 | GNUNET_GE_IMMEDIATE, _ ("SMTP: `%s' failed: %s.\n"),
419 "smtp_create_session", smtp_strerror (smtp_errno (), ebuf,
420 EBUF_LEN));
421 GNUNET_mutex_unlock (lock);
422 return GNUNET_SYSERR;
423 }
424 if (0 == smtp_set_server (session, smtp_server_name))
425 {
426 GNUNET_GE_LOG (ectx,
427 GNUNET_GE_ERROR | GNUNET_GE_ADMIN | GNUNET_GE_USER
428 | GNUNET_GE_IMMEDIATE, _ ("SMTP: `%s' failed: %s.\n"),
429 "smtp_set_server", smtp_strerror (smtp_errno (), ebuf,
430 EBUF_LEN));
431 smtp_destroy_session (session);
432 GNUNET_mutex_unlock (lock);
433 return GNUNET_SYSERR;
434 }
435 haddr = (const EmailAddress *) &hello[1];
436 message = smtp_add_message (session);
437 if (message == NULL)
438 {
439 GNUNET_GE_LOG (ectx,
440 GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER
441 | GNUNET_GE_BULK, _ ("SMTP: `%s' failed: %s.\n"),
442 "smtp_add_message", smtp_strerror (smtp_errno (), ebuf,
443 EBUF_LEN));
444 smtp_destroy_session (session);
445 GNUNET_mutex_unlock (lock);
446 return GNUNET_SYSERR;
447 }
448 smtp_set_header (message, "To", NULL, haddr->senderAddress);
449 smtp_set_header (message, "From", NULL, email);
450
451 filter = GNUNET_strdup (haddr->filter);
452 fvalue = strstr (filter, ": ");
453 GNUNET_GE_ASSERT (NULL, NULL != fvalue);
454 fvalue[0] = '\0';
455 fvalue += 2;
456 if (0 == smtp_set_header (message, filter, fvalue))
457 {
458 GNUNET_GE_LOG (ectx,
459 GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER
460 | GNUNET_GE_BULK, _ ("SMTP: `%s' failed: %s.\n"),
461 "smtp_set_header", smtp_strerror (smtp_errno (), ebuf,
462 EBUF_LEN));
463 smtp_destroy_session (session);
464 GNUNET_mutex_unlock (lock);
465 GNUNET_free (filter);
466 return GNUNET_SYSERR;
467 }
468 GNUNET_free (filter);
469 m = GNUNET_malloc (size + sizeof(SMTPMessage));
470 GNUNET_memcpy (m, msg, size);
471 mp = (SMTPMessage *) &m[size];
472 mp->header.size = htons (size + sizeof(SMTPMessage));
473 mp->header.type = htons (0);
474 mp->sender = *core_api->my_identity;
475 gm_cls.ebody = NULL;
476 gm_cls.pos = 0;
477 gm_cls.esize = GNUNET_STRINGS_base64_encode (m, size + sizeof(SMTPMessage),
478 &gm_cls.ebody);
479 GNUNET_free (m);
480 if (0 == smtp_size_set_estimate (message, gm_cls.esize))
481 {
482 GNUNET_GE_LOG (ectx,
483 GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER
484 | GNUNET_GE_BULK, _ ("SMTP: `%s' failed: %s.\n"),
485 "smtp_size_set_estimate", smtp_strerror (smtp_errno (), ebuf,
486 EBUF_LEN));
487 }
488 if (0 == smtp_set_messagecb (message, &get_message, &gm_cls))
489 {
490 GNUNET_GE_LOG (ectx,
491 GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER
492 | GNUNET_GE_BULK, _ ("SMTP: `%s' failed: %s.\n"),
493 "smtp_set_messagecb", smtp_strerror (smtp_errno (), ebuf,
494 EBUF_LEN));
495 smtp_destroy_session (session);
496 GNUNET_mutex_unlock (lock);
497 GNUNET_free (gm_cls.ebody);
498 return GNUNET_SYSERR;
499 }
500 recipient = smtp_add_recipient (message, haddr->senderAddress);
501 if (recipient == NULL)
502 {
503 GNUNET_GE_LOG (ectx,
504 GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER
505 | GNUNET_GE_BULK, _ ("SMTP: `%s' failed: %s.\n"),
506 "smtp_add_recipient", smtp_strerror (smtp_errno (), ebuf,
507 EBUF_LEN));
508 smtp_destroy_session (session);
509 GNUNET_mutex_unlock (lock);
510 return GNUNET_SYSERR;
511 }
512 if (0 == smtp_start_session (session))
513 {
514 GNUNET_GE_LOG (ectx,
515 GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER
516 | GNUNET_GE_BULK, _ ("SMTP: `%s' failed: %s.\n"),
517 "smtp_start_session", smtp_strerror (smtp_errno (), ebuf,
518 EBUF_LEN));
519 smtp_destroy_session (session);
520 GNUNET_mutex_unlock (lock);
521 GNUNET_free (gm_cls.ebody);
522 return GNUNET_SYSERR;
523 }
524 if (stats != NULL)
525 stats->change (stat_bytesSent, size);
526 if (core_api->load_monitor != NULL)
527 GNUNET_network_monitor_notify_transmission (core_api->load_monitor,
528 GNUNET_ND_UPLOAD, gm_cls.esize);
529 smtp_message_reset_status (message); /* this is needed to plug a 28-byte/message memory leak in libesmtp */
530 smtp_destroy_session (session);
531 GNUNET_mutex_unlock (lock);
532 GNUNET_free (gm_cls.ebody);
533 return GNUNET_OK;
534}
535
536
537/**
538 * Establish a connection to a remote node.
539 * @param hello the hello-Message for the target node
540 * @param tsessionPtr the session handle that is to be set
541 * @param may_reuse can we re-use an existing connection?
542 * @return GNUNET_OK on success, GNUNET_SYSERR if the operation failed
543 */
544static int
545api_connect (const GNUNET_MessageHello *hello, GNUNET_TSession **tsessionPtr,
546 int may_reuse)
547{
548 GNUNET_TSession *tsession;
549
550 tsession = GNUNET_new (GNUNET_TSession);
551 tsession->internal = GNUNET_malloc (GNUNET_sizeof_hello (hello));
552 tsession->peer = hello->senderIdentity;
553 GNUNET_memcpy (tsession->internal, hello, GNUNET_sizeof_hello (hello));
554 tsession->ttype = smtpAPI.protocol_number;
555 (*tsessionPtr) = tsession;
556 return GNUNET_OK;
557}
558
559
560/**
561 * Disconnect from a remote node.
562 *
563 * @param tsession the session that is closed
564 * @return GNUNET_OK on success, GNUNET_SYSERR if the operation failed
565 */
566static int
567api_disconnect (GNUNET_TSession *tsession)
568{
569 if (tsession != NULL)
570 {
571 if (tsession->internal != NULL)
572 GNUNET_free (tsession->internal);
573 GNUNET_free (tsession);
574 }
575 return GNUNET_OK;
576}
577
578
579/**
580 * Start the server process to receive inbound traffic.
581 * @return GNUNET_OK on success, GNUNET_SYSERR if the operation failed
582 */
583static int
584api_start_transport_server ()
585{
586 smtp_shutdown = GNUNET_NO;
587 /* initialize SMTP network */
588 dispatchThread = GNUNET_thread_create (&listenAndDistribute, NULL, 1024 * 4);
589 if (dispatchThread == NULL)
590 {
591 GNUNET_GE_DIE_STRERROR (ectx,
592 GNUNET_GE_ADMIN | GNUNET_GE_BULK | GNUNET_GE_FATAL,
593 "pthread_create");
594 return GNUNET_SYSERR;
595 }
596 return GNUNET_OK;
597}
598
599
600/**
601 * Shutdown the server process (stop receiving inbound traffic). Maybe
602 * restarted later!
603 */
604static int
605api_stop_transport_server ()
606{
607 void *unused;
608
609 smtp_shutdown = GNUNET_YES;
610 GNUNET_thread_stop_sleep (dispatchThread);
611 GNUNET_thread_join (dispatchThread, &unused);
612 return GNUNET_OK;
613}
614
615
616/**
617 * Convert SMTP hello to an IP address (always fails).
618 */
619static int
620api_hello_to_address (const GNUNET_MessageHello *hello, void **sa,
621 unsigned int *sa_len)
622{
623 return GNUNET_SYSERR;
624}
625
626
627/**
628 * Always fails.
629 */
630static int
631api_associate (GNUNET_TSession *tsession)
632{
633 return GNUNET_SYSERR; /* SMTP connections can never be associated */
634}
635
636
637/**
638 * Always succeeds (for now; we should look at adding
639 * frequency limits to SMTP in the future!).
640 */
641static int
642api_test_would_try (GNUNET_TSession *tsession, unsigned int size,
643 int important)
644{
645 return GNUNET_OK; /* we always try... */
646}
647
648
649/**
650 * The exported method. Makes the core api available via a global and
651 * returns the smtp transport API.
652 */
653GNUNET_TransportAPI *
654inittransport_smtp (struct GNUNET_CoreAPIForTransport *core)
655{
656 unsigned long long mtu;
657 struct sigaction sa;
658
659 core_api = core;
660 ectx = core->ectx;
661 if (! GNUNET_GC_have_configuration_value (core_api->cfg, "SMTP", "EMAIL"))
662 {
663 GNUNET_GE_LOG (ectx, GNUNET_GE_ERROR | GNUNET_GE_BULK | GNUNET_GE_USER,
664 _
665 (
666 "No email-address specified, can not start SMTP transport.\n"));
667 return NULL;
668 }
669 GNUNET_GC_get_configuration_value_number (core_api->cfg, "SMTP", "MTU", 1200,
670 SMTP_MESSAGE_SIZE,
671 SMTP_MESSAGE_SIZE, &mtu);
672 GNUNET_GC_get_configuration_value_number (core_api->cfg, "SMTP", "RATELIMIT",
673 0, 0, 1024 * 1024, &rate_limit);
674 stats = core_api->service_request ("stats");
675 if (stats != NULL)
676 {
677 stat_bytesReceived =
678 stats->create (gettext_noop ("# bytes received via SMTP"));
679 stat_bytesSent = stats->create (gettext_noop ("# bytes sent via SMTP"));
680 stat_bytesDropped =
681 stats->create (gettext_noop ("# bytes dropped by SMTP (outgoing)"));
682 }
683 GNUNET_GC_get_configuration_value_filename (core_api->cfg, "SMTP", "PIPE",
684 &pipename);
685 unlink (pipename);
686 if (0 != mkfifo (pipename, S_IWUSR | S_IRUSR | S_IWGRP | S_IWOTH))
687 {
688 GNUNET_GE_LOG_STRERROR (ectx,
689 GNUNET_GE_ADMIN | GNUNET_GE_BULK | GNUNET_GE_FATAL,
690 "mkfifo");
691 GNUNET_free (pipename);
692 core_api->service_release (stats);
693 stats = NULL;
694 return NULL;
695 }
696 /* we need to allow the mailer program to send us messages;
697 * easiest done by giving it write permissions (see Mantis #1142) */
698 if (0 != chmod (pipename, S_IWUSR | S_IRUSR | S_IWGRP | S_IWOTH))
699 GNUNET_GE_LOG_STRERROR (ectx,
700 GNUNET_GE_ADMIN | GNUNET_GE_BULK
701 | GNUNET_GE_WARNING, "chmod");
702 GNUNET_GC_get_configuration_value_string (core_api->cfg, "SMTP", "EMAIL",
703 NULL,
704 &email);
705 lock = GNUNET_mutex_create (GNUNET_NO);
706 GNUNET_GC_get_configuration_value_string (core_api->cfg, "SMTP", "SERVER",
707 "localhost:25", &smtp_server_name);
708 sa.sa_handler = SIG_IGN;
709 sigemptyset (&sa.sa_mask);
710 sa.sa_flags = 0;
711 sigaction (SIGPIPE, &sa, &old_handler);
712
713 smtpAPI.protocol_number = GNUNET_TRANSPORT_PROTOCOL_NUMBER_SMTP;
714 smtpAPI.mtu = mtu - sizeof(SMTPMessage);
715 smtpAPI.cost = 50;
716 smtpAPI.hello_verify = &api_verify_hello;
717 smtpAPI.hello_create = &api_create_hello;
718 smtpAPI.connect = &api_connect;
719 smtpAPI.send = &api_send;
720 smtpAPI.associate = &api_associate;
721 smtpAPI.disconnect = &api_disconnect;
722 smtpAPI.server_start = &api_start_transport_server;
723 smtpAPI.server_stop = &api_stop_transport_server;
724 smtpAPI.hello_to_address = &api_hello_to_address;
725 smtpAPI.send_now_test = &api_test_would_try;
726 return &smtpAPI;
727}
728
729
730void
731donetransport_smtp ()
732{
733 sigaction (SIGPIPE, &old_handler, NULL);
734 GNUNET_free (smtp_server_name);
735 if (stats != NULL)
736 {
737 core_api->service_release (stats);
738 stats = NULL;
739 }
740 GNUNET_mutex_destroy (lock);
741 lock = NULL;
742 unlink (pipename);
743 GNUNET_free (pipename);
744 pipename = NULL;
745 GNUNET_free (email);
746 email = NULL;
747}
748
749
750/* end of smtp.c */
diff --git a/src/transport/plugin_transport_tcp.c b/src/transport/plugin_transport_tcp.c
deleted file mode 100644
index e359185b6..000000000
--- a/src/transport/plugin_transport_tcp.c
+++ /dev/null
@@ -1,3967 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2002--2015 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport/plugin_transport_tcp.c
22 * @brief Implementation of the TCP transport service
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "gnunet_hello_lib.h"
27#include "gnunet_constants.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_nat_service.h"
30#include "gnunet_protocols.h"
31#include "gnunet_resolver_service.h"
32#include "gnunet_signatures.h"
33#include "gnunet_statistics_service.h"
34#include "gnunet_transport_service.h"
35#include "gnunet_transport_plugin.h"
36#include "transport.h"
37
38#define LOG(kind, ...) GNUNET_log_from (kind, "transport-tcp", __VA_ARGS__)
39
40#define PLUGIN_NAME "tcp"
41
42/**
43 * How long until we give up on establishing an NAT connection?
44 * Must be > 4 RTT
45 */
46#define NAT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
47
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 * Function called to notify a client about the connection begin ready
91 * to queue more data. @a buf will be NULL and @a size zero if the
92 * connection was closed for writing in the meantime.
93 *
94 * @param cls closure
95 * @param size number of bytes available in @a buf
96 * @param buf where the callee should write the message
97 * @return number of bytes written to @a buf
98 */
99typedef size_t (*GNUNET_CONNECTION_TransmitReadyNotify) (void *cls,
100 size_t size,
101 void *buf);
102
103/**
104 * Credentials for UNIX domain sockets.
105 */
106struct GNUNET_CONNECTION_Credentials
107{
108 /**
109 * UID of the other end of the connection.
110 */
111 uid_t uid;
112
113 /**
114 * GID of the other end of the connection.
115 */
116 gid_t gid;
117};
118
119
120/**
121 * Functions with this signature are called whenever a client
122 * is disconnected on the network level.
123 *
124 * @param cls closure
125 * @param client identification of the client; NULL
126 * for the last call when the server is destroyed
127 */
128typedef void (*GNUNET_SERVER_DisconnectCallback) (
129 void *cls,
130 struct GNUNET_SERVER_Client *client);
131
132
133/**
134 * Functions with this signature are called whenever a client
135 * is connected on the network level.
136 *
137 * @param cls closure
138 * @param client identification of the client
139 */
140typedef void (*GNUNET_SERVER_ConnectCallback) (
141 void *cls,
142 struct GNUNET_SERVER_Client *client);
143
144
145/**
146 * Function to call for access control checks.
147 *
148 * @param cls closure
149 * @param ucred credentials, if available, otherwise NULL
150 * @param addr address
151 * @param addrlen length of address
152 * @return GNUNET_YES to allow, GNUNET_NO to deny, GNUNET_SYSERR
153 * for unknown address family (will be denied).
154 */
155typedef int (*GNUNET_CONNECTION_AccessCheck) (
156 void *cls,
157 const struct GNUNET_CONNECTION_Credentials *ucred,
158 const struct sockaddr *addr,
159 socklen_t addrlen);
160
161/**
162 * Callback function for data received from the network. Note that
163 * both "available" and "err" would be 0 if the read simply timed out.
164 *
165 * @param cls closure
166 * @param buf pointer to received data
167 * @param available number of bytes available in "buf",
168 * possibly 0 (on errors)
169 * @param addr address of the sender
170 * @param addrlen size of addr
171 * @param errCode value of errno (on errors receiving)
172 */
173typedef void (*GNUNET_CONNECTION_Receiver) (void *cls,
174 const void *buf,
175 size_t available,
176 const struct sockaddr *addr,
177 socklen_t addrlen,
178 int errCode);
179
180
181/**
182 * Close the connection and free associated resources. There must
183 * not be any pending requests for reading or writing to the
184 * connection at this time.
185 *
186 * @param connection connection to destroy
187 */
188void
189GNUNET_CONNECTION_destroy (struct GNUNET_CONNECTION_Handle *connection);
190
191
192/**
193 * Signature of a function to create a custom tokenizer.
194 *
195 * @param cls closure from #GNUNET_SERVER_set_callbacks
196 * @param client handle to client the tokenzier will be used for
197 * @return handle to custom tokenizer ('mst')
198 */
199typedef void *(*GNUNET_SERVER_MstCreateCallback) (
200 void *cls,
201 struct GNUNET_SERVER_Client *client);
202
203
204/**
205 * Signature of a function to destroy a custom tokenizer.
206 *
207 * @param cls closure from #GNUNET_SERVER_set_callbacks
208 * @param mst custom tokenizer handle
209 */
210typedef void (*GNUNET_SERVER_MstDestroyCallback) (void *cls, void *mst);
211
212/**
213 * Signature of a function to receive data for a custom tokenizer.
214 *
215 * @param cls closure from #GNUNET_SERVER_set_callbacks
216 * @param mst custom tokenizer handle
217 * @param client_identity ID of client for which this is a buffer,
218 * can be NULL (will be passed back to 'cb')
219 * @param buf input data to add
220 * @param size number of bytes in @a buf
221 * @param purge should any excess bytes in the buffer be discarded
222 * (i.e. for packet-based services like UDP)
223 * @param one_shot only call callback once, keep rest of message in buffer
224 * @return #GNUNET_OK if we are done processing (need more data)
225 * #GNUNET_NO if one_shot was set and we have another message ready
226 * #GNUNET_SYSERR if the data stream is corrupt
227 */
228typedef int (*GNUNET_SERVER_MstReceiveCallback) (
229 void *cls,
230 void *mst,
231 struct GNUNET_SERVER_Client *client,
232 const char *buf,
233 size_t size,
234 int purge,
235 int one_shot);
236/**
237 * Functions with this signature are called whenever a message is
238 * received.
239 *
240 * @param cls closure
241 * @param client identification of the client
242 * @param message the actual message
243 */
244typedef void (*GNUNET_SERVER_MessageCallback) (
245 void *cls,
246 struct GNUNET_SERVER_Client *client,
247 const struct GNUNET_MessageHeader *message);
248
249/**
250 * Message handler. Each struct specifies how to handle on particular
251 * type of message received.
252 */
253struct GNUNET_SERVER_MessageHandler
254{
255 /**
256 * Function to call for messages of "type".
257 */
258 GNUNET_SERVER_MessageCallback callback;
259
260 /**
261 * Closure argument for @e callback.
262 */
263 void *callback_cls;
264
265 /**
266 * Type of the message this handler covers.
267 */
268 uint16_t type;
269
270 /**
271 * Expected size of messages of this type. Use 0 for
272 * variable-size. If non-zero, messages of the given
273 * type will be discarded (and the connection closed)
274 * if they do not have the right size.
275 */
276 uint16_t expected_size;
277};
278
279
280/**
281 * Options for the service (bitmask).
282 */
283enum LEGACY_SERVICE_Options
284{
285 /**
286 * Use defaults. Terminates all client connections and the listen
287 * sockets immediately upon receiving the shutdown signal.
288 */
289 LEGACY_SERVICE_OPTION_NONE = 0,
290
291 /**
292 * Do not trigger server shutdown on signal at all; instead, allow
293 * for the user to terminate the server explicitly when needed
294 * by calling #LEGACY_SERVICE_shutdown().
295 */
296 LEGACY_SERVICE_OPTION_MANUAL_SHUTDOWN = 1,
297
298 /**
299 * Trigger a SOFT server shutdown on signals, allowing active
300 * non-monitor clients to complete their transactions.
301 */
302 LEGACY_SERVICE_OPTION_SOFT_SHUTDOWN = 2
303};
304
305
306/**
307 * Ask the server to disconnect from the given client. This is the
308 * same as passing #GNUNET_SYSERR to #GNUNET_SERVER_receive_done,
309 * except that it allows dropping of a client even when not handling a
310 * message from that client.
311 *
312 * @param client the client to disconnect from
313 */
314void
315GNUNET_SERVER_client_disconnect (struct GNUNET_SERVER_Client *client);
316
317/**
318 * Return user context associated with the given client.
319 * Note: you should probably use the macro (call without the underscore).
320 *
321 * @param client client to query
322 * @param size number of bytes in user context struct (for verification only)
323 * @return pointer to user context
324 */
325void *
326GNUNET_SERVER_client_get_user_context_ (struct GNUNET_SERVER_Client *client,
327 size_t size);
328
329
330/**
331 * Functions with this signature are called whenever a
332 * complete message is received by the tokenizer.
333 *
334 * Do not call #GNUNET_SERVER_mst_destroy from within
335 * the scope of this callback.
336 *
337 * @param cls closure
338 * @param client identification of the client
339 * @param message the actual message
340 * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing
341 */
342typedef int (*GNUNET_SERVER_MessageTokenizerCallback) (
343 void *cls,
344 void *client,
345 const struct GNUNET_MessageHeader *message);
346
347
348/**
349 * Create a message stream tokenizer.
350 *
351 * @param cb function to call on completed messages
352 * @param cb_cls closure for @a cb
353 * @return handle to tokenizer
354 */
355struct GNUNET_SERVER_MessageStreamTokenizer *
356GNUNET_SERVER_mst_create (GNUNET_SERVER_MessageTokenizerCallback cb,
357 void *cb_cls);
358
359/**
360 * Add incoming data to the receive buffer and call the
361 * callback for all complete messages.
362 *
363 * @param mst tokenizer to use
364 * @param client_identity ID of client for which this is a buffer,
365 * can be NULL (will be passed back to 'cb')
366 * @param buf input data to add
367 * @param size number of bytes in @a buf
368 * @param purge should any excess bytes in the buffer be discarded
369 * (i.e. for packet-based services like UDP)
370 * @param one_shot only call callback once, keep rest of message in buffer
371 * @return #GNUNET_OK if we are done processing (need more data)
372 * #GNUNET_NO if one_shot was set and we have another message ready
373 * #GNUNET_SYSERR if the data stream is corrupt
374 */
375int
376GNUNET_SERVER_mst_receive (struct GNUNET_SERVER_MessageStreamTokenizer *mst,
377 void *client_identity,
378 const char *buf,
379 size_t size,
380 int purge,
381 int one_shot);
382
383
384/**
385 * Destroys a tokenizer.
386 *
387 * @param mst tokenizer to destroy
388 */
389void
390GNUNET_SERVER_mst_destroy (struct GNUNET_SERVER_MessageStreamTokenizer *mst);
391
392
393/**
394 * Set user context to be associated with the given client.
395 * Note: you should probably use the macro (call without the underscore).
396 *
397 * @param client client to query
398 * @param ptr pointer to user context
399 * @param size number of bytes in user context struct (for verification only)
400 */
401void
402GNUNET_SERVER_client_set_user_context_ (struct GNUNET_SERVER_Client *client,
403 void *ptr,
404 size_t size);
405
406/**
407 * Return user context associated with the given client.
408 *
409 * @param client client to query
410 * @param type expected return type (i.e. 'struct Foo')
411 * @return pointer to user context of type 'type *'.
412 */
413#define GNUNET_SERVER_client_get_user_context(client, type) \
414 (type *) GNUNET_SERVER_client_get_user_context_ (client, sizeof(type))
415
416/**
417 * Set user context to be associated with the given client.
418 *
419 * @param client client to query
420 * @param value pointer to user context
421 */
422#define GNUNET_SERVER_client_set_user_context(client, value) \
423 GNUNET_SERVER_client_set_user_context_ (client, value, sizeof(*value))
424
425
426/**
427 * Notify us when the server has enough space to transmit
428 * a message of the given size to the given client.
429 *
430 * @param client client to transmit message to
431 * @param size requested amount of buffer space
432 * @param timeout after how long should we give up (and call
433 * notify with buf NULL and size 0)?
434 * @param callback function to call when space is available
435 * @param callback_cls closure for @a callback
436 * @return non-NULL if the notify callback was queued; can be used
437 * to cancel the request using
438 * #GNUNET_SERVER_notify_transmit_ready_cancel.
439 * NULL if we are already going to notify someone else (busy)
440 */
441struct GNUNET_SERVER_TransmitHandle *
442GNUNET_SERVER_notify_transmit_ready (
443 struct GNUNET_SERVER_Client *client,
444 size_t size,
445 struct GNUNET_TIME_Relative timeout,
446 GNUNET_CONNECTION_TransmitReadyNotify callback,
447 void *callback_cls);
448
449/**
450 * Abort transmission request.
451 *
452 * @param th request to abort
453 */
454void
455GNUNET_SERVER_notify_transmit_ready_cancel (
456 struct GNUNET_SERVER_TransmitHandle *th);
457
458
459/**
460 * Notify the server that the given client handle should
461 * be kept (keeps the connection up if possible, increments
462 * the internal reference counter).
463 *
464 * @param client the client to keep
465 */
466void
467GNUNET_SERVER_client_keep (struct GNUNET_SERVER_Client *client);
468
469
470/**
471 * Notify the server that the given client handle is no
472 * longer required. Decrements the reference counter. If
473 * that counter reaches zero an inactive connection maybe
474 * closed.
475 *
476 * @param client the client to drop
477 */
478void
479GNUNET_SERVER_client_drop (struct GNUNET_SERVER_Client *client);
480
481
482/**
483 * Function called by the service's run
484 * method to run service-specific setup code.
485 *
486 * @param cls closure
487 * @param server the initialized server
488 * @param cfg configuration to use
489 */
490typedef void (*LEGACY_SERVICE_Main) (
491 void *cls,
492 struct GNUNET_SERVER_Handle *server,
493 const struct GNUNET_CONFIGURATION_Handle *cfg);
494
495
496/**
497 * Suspend accepting connections from the listen socket temporarily.
498 * Resume activity using #GNUNET_SERVER_resume.
499 *
500 * @param server server to stop accepting connections.
501 */
502void
503GNUNET_SERVER_suspend (struct GNUNET_SERVER_Handle *server);
504
505/**
506 * Notify us when the server has enough space to transmit
507 * a message of the given size to the given client.
508 *
509 * @param client client to transmit message to
510 * @param size requested amount of buffer space
511 * @param timeout after how long should we give up (and call
512 * notify with buf NULL and size 0)?
513 * @param callback function to call when space is available
514 * @param callback_cls closure for @a callback
515 * @return non-NULL if the notify callback was queued; can be used
516 * to cancel the request using
517 * #GNUNET_SERVER_notify_transmit_ready_cancel.
518 * NULL if we are already going to notify someone else (busy)
519 */
520struct GNUNET_SERVER_TransmitHandle *
521GNUNET_SERVER_notify_transmit_ready (
522 struct GNUNET_SERVER_Client *client,
523 size_t size,
524 struct GNUNET_TIME_Relative timeout,
525 GNUNET_CONNECTION_TransmitReadyNotify callback,
526 void *callback_cls);
527
528
529/**
530 * Add a TCP socket-based connection to the set of handles managed by
531 * this server. Use this function for outgoing (P2P) connections that
532 * we initiated (and where this server should process incoming
533 * messages).
534 *
535 * @param server the server to use
536 * @param connection the connection to manage (client must
537 * stop using this connection from now on)
538 * @return the client handle
539 */
540struct GNUNET_SERVER_Client *
541GNUNET_SERVER_connect_socket (struct GNUNET_SERVER_Handle *server,
542 struct GNUNET_CONNECTION_Handle *connection);
543
544
545/**
546 * Resume accepting connections from the listen socket.
547 *
548 * @param server server to resume accepting connections.
549 */
550void
551GNUNET_SERVER_resume (struct GNUNET_SERVER_Handle *server);
552
553/**
554 * Free resources held by this server.
555 *
556 * @param server server to destroy
557 */
558void
559GNUNET_SERVER_destroy (struct GNUNET_SERVER_Handle *server);
560
561
562#include "tcp_connection_legacy.c"
563#include "tcp_server_mst_legacy.c"
564#include "tcp_server_legacy.c"
565#include "tcp_service_legacy.c"
566
567GNUNET_NETWORK_STRUCT_BEGIN
568
569/**
570 * Initial handshake message for a session.
571 */
572struct WelcomeMessage
573{
574 /**
575 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME.
576 */
577 struct GNUNET_MessageHeader header;
578
579 /**
580 * Identity of the node connecting (TCP client)
581 */
582 struct GNUNET_PeerIdentity clientIdentity;
583};
584
585/**
586 * Basically a WELCOME message, but with the purpose
587 * of giving the waiting peer a client handle to use
588 */
589struct TCP_NAT_ProbeMessage
590{
591 /**
592 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE.
593 */
594 struct GNUNET_MessageHeader header;
595
596 /**
597 * Identity of the sender of the message.
598 */
599 struct GNUNET_PeerIdentity clientIdentity;
600};
601GNUNET_NETWORK_STRUCT_END
602
603/**
604 * Context for sending a NAT probe via TCP.
605 */
606struct TCPProbeContext
607{
608 /**
609 * Active probes are kept in a DLL.
610 */
611 struct TCPProbeContext *next;
612
613 /**
614 * Active probes are kept in a DLL.
615 */
616 struct TCPProbeContext *prev;
617
618 /**
619 * Probe connection.
620 */
621 struct GNUNET_CONNECTION_Handle *sock;
622
623 /**
624 * Message to be sent.
625 */
626 struct TCP_NAT_ProbeMessage message;
627
628 /**
629 * Handle to the transmission.
630 */
631 struct GNUNET_CONNECTION_TransmitHandle *transmit_handle;
632
633 /**
634 * Transport plugin handle.
635 */
636 struct Plugin *plugin;
637};
638
639/**
640 * Bits in the `options` field of TCP addresses.
641 */
642enum TcpAddressOptions
643{
644 /**
645 * No bits set.
646 */
647 TCP_OPTIONS_NONE = 0,
648
649 /**
650 * See #HTTP_OPTIONS_VERIFY_CERTIFICATE.
651 */
652 TCP_OPTIONS_RESERVED = 1,
653
654 /**
655 * Enable TCP Stealth-style port knocking.
656 */
657 TCP_OPTIONS_TCP_STEALTH = 2
658};
659
660GNUNET_NETWORK_STRUCT_BEGIN
661
662/**
663 * Network format for IPv4 addresses.
664 */
665struct IPv4TcpAddress
666{
667 /**
668 * Optional options and flags for this address,
669 * see `enum TcpAddressOptions`
670 */
671 uint32_t options GNUNET_PACKED;
672
673 /**
674 * IPv4 address, in network byte order.
675 */
676 uint32_t ipv4_addr GNUNET_PACKED;
677
678 /**
679 * Port number, in network byte order.
680 */
681 uint16_t t4_port GNUNET_PACKED;
682};
683
684/**
685 * Network format for IPv6 addresses.
686 */
687struct IPv6TcpAddress
688{
689 /**
690 * Optional flags for this address
691 * see `enum TcpAddressOptions`
692 */
693 uint32_t options GNUNET_PACKED;
694
695 /**
696 * IPv6 address.
697 */
698 struct in6_addr ipv6_addr GNUNET_PACKED;
699
700 /**
701 * Port number, in network byte order.
702 */
703 uint16_t t6_port GNUNET_PACKED;
704};
705GNUNET_NETWORK_STRUCT_END
706
707/**
708 * Encapsulation of all of the state of the plugin.
709 */
710struct Plugin;
711
712/**
713 * Information kept for each message that is yet to
714 * be transmitted.
715 */
716struct PendingMessage
717{
718 /**
719 * This is a doubly-linked list.
720 */
721 struct PendingMessage *next;
722
723 /**
724 * This is a doubly-linked list.
725 */
726 struct PendingMessage *prev;
727
728 /**
729 * The pending message
730 */
731 const char *msg;
732
733 /**
734 * Continuation function to call once the message
735 * has been sent. Can be NULL if there is no
736 * continuation to call.
737 */
738 GNUNET_TRANSPORT_TransmitContinuation transmit_cont;
739
740 /**
741 * Closure for @e transmit_cont.
742 */
743 void *transmit_cont_cls;
744
745 /**
746 * Timeout value for the pending message.
747 */
748 struct GNUNET_TIME_Absolute timeout;
749
750 /**
751 * So that the gnunet-service-transport can group messages together,
752 * these pending messages need to accept a message buffer and size
753 * instead of just a `struct GNUNET_MessageHeader`.
754 */
755 size_t message_size;
756};
757
758/**
759 * Session handle for TCP connections.
760 */
761struct GNUNET_ATS_Session
762{
763 /**
764 * To whom are we talking to (set to our identity
765 * if we are still waiting for the welcome message)
766 */
767 struct GNUNET_PeerIdentity target;
768
769 /**
770 * Pointer to the global plugin struct.
771 */
772 struct Plugin *plugin;
773
774 /**
775 * The client (used to identify this connection)
776 */
777 struct GNUNET_SERVER_Client *client;
778
779 /**
780 * Task cleaning up a NAT client connection establishment attempt;
781 */
782 struct GNUNET_SCHEDULER_Task *nat_connection_timeout;
783
784 /**
785 * Messages currently pending for transmission
786 * to this peer, if any.
787 */
788 struct PendingMessage *pending_messages_head;
789
790 /**
791 * Messages currently pending for transmission
792 * to this peer, if any.
793 */
794 struct PendingMessage *pending_messages_tail;
795
796 /**
797 * Handle for pending transmission request.
798 */
799 struct GNUNET_SERVER_TransmitHandle *transmit_handle;
800
801 /**
802 * Address of the other peer.
803 */
804 struct GNUNET_HELLO_Address *address;
805
806 /**
807 * ID of task used to delay receiving more to throttle sender.
808 */
809 struct GNUNET_SCHEDULER_Task *receive_delay_task;
810
811 /**
812 * Session timeout task
813 */
814 struct GNUNET_SCHEDULER_Task *timeout_task;
815
816 /**
817 * When will this session time out?
818 */
819 struct GNUNET_TIME_Absolute timeout;
820
821 /**
822 * When will we continue to read from the socket?
823 * (used to enforce inbound quota).
824 */
825 struct GNUNET_TIME_Absolute receive_delay;
826
827 /**
828 * Last activity on this connection. Used to select preferred
829 * connection.
830 */
831 struct GNUNET_TIME_Absolute last_activity;
832
833 /**
834 * Number of bytes waiting for transmission to this peer.
835 */
836 unsigned long long bytes_in_queue;
837
838 /**
839 * Number of messages waiting for transmission to this peer.
840 */
841 unsigned int msgs_in_queue;
842
843 /**
844 * Network type of the address.
845 */
846 enum GNUNET_NetworkType scope;
847
848 /**
849 * Are we still expecting the welcome message? (#GNUNET_YES/#GNUNET_NO)
850 */
851 int expecting_welcome;
852
853 /**
854 * Was this session created using NAT traversal?
855 */
856 int is_nat;
857};
858
859
860/**
861 * Context for address to string conversion, closure
862 * for #append_port().
863 */
864struct PrettyPrinterContext
865{
866 /**
867 * DLL
868 */
869 struct PrettyPrinterContext *next;
870
871 /**
872 * DLL
873 */
874 struct PrettyPrinterContext *prev;
875
876 /**
877 * Our plugin.
878 */
879 struct Plugin *plugin;
880
881 /**
882 * Timeout task
883 */
884 struct GNUNET_SCHEDULER_Task *timeout_task;
885
886 /**
887 * Resolver handle
888 */
889 struct GNUNET_RESOLVER_RequestHandle *resolver_handle;
890
891 /**
892 * Function to call with the result.
893 */
894 GNUNET_TRANSPORT_AddressStringCallback asc;
895
896 /**
897 * Clsoure for @e asc.
898 */
899 void *asc_cls;
900
901 /**
902 * IPv6 address
903 */
904 int ipv6;
905
906 /**
907 * Options
908 */
909 uint32_t options;
910
911 /**
912 * Port to add after the IP address.
913 */
914 uint16_t port;
915};
916
917
918/**
919 * Encapsulation of all of the state of the plugin.
920 */
921struct Plugin
922{
923 /**
924 * Our environment.
925 */
926 struct GNUNET_TRANSPORT_PluginEnvironment *env;
927
928 /**
929 * The listen socket.
930 */
931 struct GNUNET_CONNECTION_Handle *lsock;
932
933 /**
934 * Our handle to the NAT module.
935 */
936 struct GNUNET_NAT_Handle *nat;
937
938 /**
939 * Map from peer identities to sessions for the given peer.
940 */
941 struct GNUNET_CONTAINER_MultiPeerMap *sessionmap;
942
943 /**
944 * Handle to the network service.
945 */
946 struct LEGACY_SERVICE_Context *service;
947
948 /**
949 * Handle to the server for this service.
950 */
951 struct GNUNET_SERVER_Handle *server;
952
953 /**
954 * Copy of the handler array where the closures are
955 * set to this struct's instance.
956 */
957 struct GNUNET_SERVER_MessageHandler *handlers;
958
959 /**
960 * Map of peers we have tried to contact behind a NAT
961 */
962 struct GNUNET_CONTAINER_MultiPeerMap *nat_wait_conns;
963
964 /**
965 * List of active TCP probes.
966 */
967 struct TCPProbeContext *probe_head;
968
969 /**
970 * List of active TCP probes.
971 */
972 struct TCPProbeContext *probe_tail;
973
974 /**
975 * Function to call about session status changes.
976 */
977 GNUNET_TRANSPORT_SessionInfoCallback sic;
978
979 /**
980 * Closure for @e sic.
981 */
982 void *sic_cls;
983
984 /**
985 * ID of task used to update our addresses when one expires.
986 */
987 struct GNUNET_SCHEDULER_Task *address_update_task;
988
989 /**
990 * Running pretty printers: head
991 */
992 struct PrettyPrinterContext *ppc_dll_head;
993
994 /**
995 * Running pretty printers: tail
996 */
997 struct PrettyPrinterContext *ppc_dll_tail;
998
999 /**
1000 * Welcome message used by this peer.
1001 */
1002 struct WelcomeMessage my_welcome;
1003
1004 /**
1005 * How many more TCP sessions are we allowed to open right now?
1006 */
1007 unsigned long long max_connections;
1008
1009 /**
1010 * How many more TCP sessions do we have right now?
1011 */
1012 unsigned long long cur_connections;
1013
1014 /**
1015 * Address options
1016 */
1017 uint32_t myoptions;
1018
1019 /**
1020 * Port that we are actually listening on.
1021 */
1022 uint16_t open_port;
1023
1024 /**
1025 * Port that the user said we would have visible to the
1026 * rest of the world.
1027 */
1028 uint16_t adv_port;
1029};
1030
1031
1032/**
1033 * Get the list of addresses that a server for the given service
1034 * should bind to.
1035 *
1036 * @param service_name name of the service
1037 * @param cfg configuration (which specifies the addresses)
1038 * @param addrs set (call by reference) to an array of pointers to the
1039 * addresses the server should bind to and listen on; the
1040 * array will be NULL-terminated (on success)
1041 * @param addr_lens set (call by reference) to an array of the lengths
1042 * of the respective `struct sockaddr` struct in the @a addrs
1043 * array (on success)
1044 * @return number of addresses found on success,
1045 * #GNUNET_SYSERR if the configuration
1046 * did not specify reasonable finding information or
1047 * if it specified a hostname that could not be resolved;
1048 * #GNUNET_NO if the number of addresses configured is
1049 * zero (in this case, `*addrs` and `*addr_lens` will be
1050 * set to NULL).
1051 */
1052static int
1053get_server_addresses (const char *service_name,
1054 const struct GNUNET_CONFIGURATION_Handle *cfg,
1055 struct sockaddr ***addrs,
1056 socklen_t **addr_lens)
1057{
1058 int disablev6;
1059 struct GNUNET_NETWORK_Handle *desc;
1060 unsigned long long port;
1061 char *unixpath;
1062 struct addrinfo hints;
1063 struct addrinfo *res;
1064 struct addrinfo *pos;
1065 struct addrinfo *next;
1066 unsigned int i;
1067 int resi;
1068 int ret;
1069 int abstract;
1070 struct sockaddr **saddrs;
1071 socklen_t *saddrlens;
1072 char *hostname;
1073
1074 *addrs = NULL;
1075 *addr_lens = NULL;
1076 desc = NULL;
1077 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "DISABLEV6"))
1078 {
1079 if (GNUNET_SYSERR ==
1080 (disablev6 = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1081 service_name,
1082 "DISABLEV6")))
1083 return GNUNET_SYSERR;
1084 }
1085 else
1086 disablev6 = GNUNET_NO;
1087
1088 if (! disablev6)
1089 {
1090 /* probe IPv6 support */
1091 desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
1092 if (NULL == desc)
1093 {
1094 if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
1095 (EACCES == errno))
1096 {
1097 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
1098 return GNUNET_SYSERR;
1099 }
1100 LOG (GNUNET_ERROR_TYPE_INFO,
1101 _ (
1102 "Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"),
1103 service_name,
1104 strerror (errno));
1105 disablev6 = GNUNET_YES;
1106 }
1107 else
1108 {
1109 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
1110 desc = NULL;
1111 }
1112 }
1113
1114 port = 0;
1115 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT"))
1116 {
1117 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg,
1118 service_name,
1119 "PORT",
1120 &port))
1121 {
1122 LOG (GNUNET_ERROR_TYPE_ERROR,
1123 _ ("Require valid port number for service `%s' in configuration!\n"),
1124 service_name);
1125 }
1126 if (port > 65535)
1127 {
1128 LOG (GNUNET_ERROR_TYPE_ERROR,
1129 _ ("Require valid port number for service `%s' in configuration!\n"),
1130 service_name);
1131 return GNUNET_SYSERR;
1132 }
1133 }
1134
1135 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "BINDTO"))
1136 {
1137 GNUNET_break (GNUNET_OK ==
1138 GNUNET_CONFIGURATION_get_value_string (cfg,
1139 service_name,
1140 "BINDTO",
1141 &hostname));
1142 }
1143 else
1144 hostname = NULL;
1145
1146 unixpath = NULL;
1147 abstract = GNUNET_NO;
1148#ifdef AF_UNIX
1149 if ((GNUNET_YES ==
1150 GNUNET_CONFIGURATION_have_value (cfg, service_name, "UNIXPATH")) &&
1151 (GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (cfg,
1152 service_name,
1153 "UNIXPATH",
1154 &unixpath)) &&
1155 (0 < strlen (unixpath)))
1156 {
1157 /* probe UNIX support */
1158 struct sockaddr_un s_un;
1159
1160 if (strlen (unixpath) >= sizeof(s_un.sun_path))
1161 {
1162 LOG (GNUNET_ERROR_TYPE_WARNING,
1163 _ ("UNIXPATH `%s' too long, maximum length is %llu\n"),
1164 unixpath,
1165 (unsigned long long) sizeof(s_un.sun_path));
1166 unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
1167 LOG (GNUNET_ERROR_TYPE_INFO, _ ("Using `%s' instead\n"), unixpath);
1168 }
1169#ifdef __linux__
1170 abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1171 "TESTING",
1172 "USE_ABSTRACT_SOCKETS");
1173 if (GNUNET_SYSERR == abstract)
1174 abstract = GNUNET_NO;
1175#endif
1176 if ((GNUNET_YES != abstract) &&
1177 (GNUNET_OK != GNUNET_DISK_directory_create_for_file (unixpath)))
1178 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "mkdir", unixpath);
1179 }
1180 if (NULL != unixpath)
1181 {
1182 desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
1183 if (NULL == desc)
1184 {
1185 if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
1186 (EACCES == errno))
1187 {
1188 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
1189 GNUNET_free (hostname);
1190 GNUNET_free (unixpath);
1191 return GNUNET_SYSERR;
1192 }
1193 LOG (GNUNET_ERROR_TYPE_INFO,
1194 _ (
1195 "Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"),
1196 service_name,
1197 strerror (errno));
1198 GNUNET_free (unixpath);
1199 unixpath = NULL;
1200 }
1201 else
1202 {
1203 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
1204 desc = NULL;
1205 }
1206 }
1207#endif
1208
1209 if ((0 == port) && (NULL == unixpath))
1210 {
1211 LOG (GNUNET_ERROR_TYPE_ERROR,
1212 _ (
1213 "Have neither PORT nor UNIXPATH for service `%s', but one is required\n"),
1214 service_name);
1215 GNUNET_free (hostname);
1216 return GNUNET_SYSERR;
1217 }
1218 if (0 == port)
1219 {
1220 saddrs = GNUNET_malloc (2 * sizeof(struct sockaddr *));
1221 saddrlens = GNUNET_malloc (2 * sizeof(socklen_t));
1222 add_unixpath (saddrs, saddrlens, unixpath, abstract);
1223 GNUNET_free (unixpath);
1224 GNUNET_free (hostname);
1225 *addrs = saddrs;
1226 *addr_lens = saddrlens;
1227 return 1;
1228 }
1229
1230 if (NULL != hostname)
1231 {
1232 LOG (GNUNET_ERROR_TYPE_DEBUG,
1233 "Resolving `%s' since that is where `%s' will bind to.\n",
1234 hostname,
1235 service_name);
1236 memset (&hints, 0, sizeof(struct addrinfo));
1237 if (disablev6)
1238 hints.ai_family = AF_INET;
1239 hints.ai_protocol = IPPROTO_TCP;
1240 if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
1241 (NULL == res))
1242 {
1243 LOG (GNUNET_ERROR_TYPE_ERROR,
1244 _ ("Failed to resolve `%s': %s\n"),
1245 hostname,
1246 gai_strerror (ret));
1247 GNUNET_free (hostname);
1248 GNUNET_free (unixpath);
1249 return GNUNET_SYSERR;
1250 }
1251 next = res;
1252 i = 0;
1253 while (NULL != (pos = next))
1254 {
1255 next = pos->ai_next;
1256 if ((disablev6) && (pos->ai_family == AF_INET6))
1257 continue;
1258 i++;
1259 }
1260 if (0 == i)
1261 {
1262 LOG (GNUNET_ERROR_TYPE_ERROR,
1263 _ ("Failed to find %saddress for `%s'.\n"),
1264 disablev6 ? "IPv4 " : "",
1265 hostname);
1266 freeaddrinfo (res);
1267 GNUNET_free (hostname);
1268 GNUNET_free (unixpath);
1269 return GNUNET_SYSERR;
1270 }
1271 resi = i;
1272 if (NULL != unixpath)
1273 resi++;
1274 saddrs = GNUNET_malloc ((resi + 1) * sizeof(struct sockaddr *));
1275 saddrlens = GNUNET_malloc ((resi + 1) * sizeof(socklen_t));
1276 i = 0;
1277 if (NULL != unixpath)
1278 {
1279 add_unixpath (saddrs, saddrlens, unixpath, abstract);
1280 i++;
1281 }
1282 next = res;
1283 while (NULL != (pos = next))
1284 {
1285 next = pos->ai_next;
1286 if ((disablev6) && (AF_INET6 == pos->ai_family))
1287 continue;
1288 if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol))
1289 continue; /* not TCP */
1290 if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype))
1291 continue; /* huh? */
1292 LOG (GNUNET_ERROR_TYPE_DEBUG,
1293 "Service `%s' will bind to `%s'\n",
1294 service_name,
1295 GNUNET_a2s (pos->ai_addr, pos->ai_addrlen));
1296 if (AF_INET == pos->ai_family)
1297 {
1298 GNUNET_assert (sizeof(struct sockaddr_in) == pos->ai_addrlen);
1299 saddrlens[i] = pos->ai_addrlen;
1300 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1301 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
1302 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1303 }
1304 else
1305 {
1306 GNUNET_assert (AF_INET6 == pos->ai_family);
1307 GNUNET_assert (sizeof(struct sockaddr_in6) == pos->ai_addrlen);
1308 saddrlens[i] = pos->ai_addrlen;
1309 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1310 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
1311 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
1312 }
1313 i++;
1314 }
1315 GNUNET_free (hostname);
1316 freeaddrinfo (res);
1317 resi = i;
1318 }
1319 else
1320 {
1321 /* will bind against everything, just set port */
1322 if (disablev6)
1323 {
1324 /* V4-only */
1325 resi = 1;
1326 if (NULL != unixpath)
1327 resi++;
1328 i = 0;
1329 saddrs = GNUNET_malloc ((resi + 1) * sizeof(struct sockaddr *));
1330 saddrlens = GNUNET_malloc ((resi + 1) * sizeof(socklen_t));
1331 if (NULL != unixpath)
1332 {
1333 add_unixpath (saddrs, saddrlens, unixpath, abstract);
1334 i++;
1335 }
1336 saddrlens[i] = sizeof(struct sockaddr_in);
1337 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1338#if HAVE_SOCKADDR_IN_SIN_LEN
1339 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
1340#endif
1341 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
1342 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1343 }
1344 else
1345 {
1346 /* dual stack */
1347 resi = 2;
1348 if (NULL != unixpath)
1349 resi++;
1350 saddrs = GNUNET_malloc ((resi + 1) * sizeof(struct sockaddr *));
1351 saddrlens = GNUNET_malloc ((resi + 1) * sizeof(socklen_t));
1352 i = 0;
1353 if (NULL != unixpath)
1354 {
1355 add_unixpath (saddrs, saddrlens, unixpath, abstract);
1356 i++;
1357 }
1358 saddrlens[i] = sizeof(struct sockaddr_in6);
1359 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1360#if HAVE_SOCKADDR_IN_SIN_LEN
1361 ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
1362#endif
1363 ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
1364 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
1365 i++;
1366 saddrlens[i] = sizeof(struct sockaddr_in);
1367 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1368#if HAVE_SOCKADDR_IN_SIN_LEN
1369 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
1370#endif
1371 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
1372 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1373 }
1374 }
1375 GNUNET_free (unixpath);
1376 *addrs = saddrs;
1377 *addr_lens = saddrlens;
1378 return resi;
1379}
1380
1381
1382/* end ancient copy-and-paste */
1383
1384
1385/**
1386 * If a session monitor is attached, notify it about the new
1387 * session state.
1388 *
1389 * @param plugin our plugin
1390 * @param session session that changed state
1391 * @param state new state of the session
1392 */
1393static void
1394notify_session_monitor (struct Plugin *plugin,
1395 struct GNUNET_ATS_Session *session,
1396 enum GNUNET_TRANSPORT_SessionState state)
1397{
1398 struct GNUNET_TRANSPORT_SessionInfo info;
1399
1400 if (NULL == plugin->sic)
1401 return;
1402 memset (&info, 0, sizeof(info));
1403 info.state = state;
1404 info.is_inbound =
1405 GNUNET_HELLO_address_check_option (session->address,
1406 GNUNET_HELLO_ADDRESS_INFO_INBOUND);
1407 info.num_msg_pending = session->msgs_in_queue;
1408 info.num_bytes_pending = session->bytes_in_queue;
1409 if (NULL != session->receive_delay_task)
1410 info.receive_delay = session->receive_delay;
1411 info.session_timeout = session->timeout;
1412 info.address = session->address;
1413 plugin->sic (plugin->sic_cls, session, &info);
1414}
1415
1416
1417/**
1418 * Our external IP address/port mapping has changed.
1419 *
1420 * @param cls closure, the `struct Plugin`
1421 * @param[in,out] app_ctx location where the app can store stuff
1422 * on add and retrieve it on remove
1423 * @param add_remove #GNUNET_YES to mean the new public IP address, #GNUNET_NO to mean
1424 * the previous (now invalid) one
1425 * @param ac address class the address belongs to
1426 * @param addr either the previous or the new public IP address
1427 * @param addrlen actual length of @a addr
1428 */
1429static void
1430tcp_nat_port_map_callback (void *cls,
1431 void **app_ctx,
1432 int add_remove,
1433 enum GNUNET_NAT_AddressClass ac,
1434 const struct sockaddr *addr,
1435 socklen_t addrlen)
1436{
1437 struct Plugin *plugin = cls;
1438 struct GNUNET_HELLO_Address *address;
1439 struct IPv4TcpAddress t4;
1440 struct IPv6TcpAddress t6;
1441 void *arg;
1442 size_t args;
1443
1444 (void) app_ctx;
1445 LOG (GNUNET_ERROR_TYPE_INFO,
1446 "NAT notification to %s address `%s'\n",
1447 (GNUNET_YES == add_remove) ? "add" : "remove",
1448 GNUNET_a2s (addr, addrlen));
1449 /* convert 'addr' to our internal format */
1450 switch (addr->sa_family)
1451 {
1452 case AF_INET:
1453 GNUNET_assert (addrlen == sizeof(struct sockaddr_in));
1454 memset (&t4, 0, sizeof(t4));
1455 t4.options = htonl (plugin->myoptions);
1456 t4.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
1457 t4.t4_port = ((struct sockaddr_in *) addr)->sin_port;
1458 arg = &t4;
1459 args = sizeof(t4);
1460 break;
1461
1462 case AF_INET6:
1463 if (IN6_IS_ADDR_LINKLOCAL (&((struct sockaddr_in6 *) addr)->sin6_addr))
1464 {
1465 /* skip link local, we don't allow them in
1466 #tcp_plugin_check_address() */
1467 return;
1468 }
1469 GNUNET_assert (addrlen == sizeof(struct sockaddr_in6));
1470 memset (&t6, 0, sizeof(t6));
1471 GNUNET_memcpy (&t6.ipv6_addr,
1472 &((struct sockaddr_in6 *) addr)->sin6_addr,
1473 sizeof(struct in6_addr));
1474 t6.options = htonl (plugin->myoptions);
1475 t6.t6_port = ((struct sockaddr_in6 *) addr)->sin6_port;
1476 arg = &t6;
1477 args = sizeof(t6);
1478 break;
1479
1480 default:
1481 GNUNET_break (0);
1482 return;
1483 }
1484 /* modify our published address list */
1485 GNUNET_assert ((args == sizeof(struct IPv4TcpAddress)) ||
1486 (args == sizeof(struct IPv6TcpAddress)));
1487 /* TODO: use 'ac' here in the future... */
1488 address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
1489 PLUGIN_NAME,
1490 arg,
1491 args,
1492 GNUNET_HELLO_ADDRESS_INFO_NONE);
1493 plugin->env->notify_address (plugin->env->cls, add_remove, address);
1494 GNUNET_HELLO_address_free (address);
1495}
1496
1497
1498/**
1499 * Function called for a quick conversion of the binary address to
1500 * a numeric address. Note that the caller must not free the
1501 * address and that the next call to this function is allowed
1502 * to override the address again.
1503 *
1504 * @param cls closure (`struct Plugin*`)
1505 * @param addr binary address
1506 * @param addrlen length of @a addr
1507 * @return string representing the same address
1508 */
1509static const char *
1510tcp_plugin_address_to_string (void *cls, const void *addr, size_t addrlen)
1511{
1512 static char rbuf[INET6_ADDRSTRLEN + 16];
1513 char buf[INET6_ADDRSTRLEN];
1514 const void *sb;
1515 struct in_addr a4;
1516 struct in6_addr a6;
1517 const struct IPv4TcpAddress *t4;
1518 const struct IPv6TcpAddress *t6;
1519 int af;
1520 uint16_t port;
1521 uint32_t options;
1522
1523 switch (addrlen)
1524 {
1525 case sizeof(struct IPv6TcpAddress):
1526 t6 = addr;
1527 af = AF_INET6;
1528 port = ntohs (t6->t6_port);
1529 options = ntohl (t6->options);
1530 GNUNET_memcpy (&a6, &t6->ipv6_addr, sizeof(a6));
1531 sb = &a6;
1532 break;
1533
1534 case sizeof(struct IPv4TcpAddress):
1535 t4 = addr;
1536 af = AF_INET;
1537 port = ntohs (t4->t4_port);
1538 options = ntohl (t4->options);
1539 GNUNET_memcpy (&a4, &t4->ipv4_addr, sizeof(a4));
1540 sb = &a4;
1541 break;
1542
1543 default:
1544 LOG (GNUNET_ERROR_TYPE_WARNING,
1545 _ ("Unexpected address length: %u bytes\n"),
1546 (unsigned int) addrlen);
1547 return NULL;
1548 }
1549 if (NULL == inet_ntop (af, sb, buf, INET6_ADDRSTRLEN))
1550 {
1551 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "inet_ntop");
1552 return NULL;
1553 }
1554 GNUNET_snprintf (rbuf,
1555 sizeof(rbuf),
1556 (af == AF_INET6) ? "%s.%u.[%s]:%u" : "%s.%u.%s:%u",
1557 PLUGIN_NAME,
1558 options,
1559 buf,
1560 port);
1561 return rbuf;
1562}
1563
1564
1565/**
1566 * Function called to convert a string address to
1567 * a binary address.
1568 *
1569 * @param cls closure (`struct Plugin*`)
1570 * @param addr string address
1571 * @param addrlen length of the address
1572 * @param buf location to store the buffer
1573 * @param added location to store the number of bytes in the buffer.
1574 * If the function returns #GNUNET_SYSERR, its contents are undefined.
1575 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
1576 */
1577static int
1578tcp_plugin_string_to_address (void *cls,
1579 const char *addr,
1580 uint16_t addrlen,
1581 void **buf,
1582 size_t *added)
1583{
1584 struct sockaddr_storage socket_address;
1585 char *address;
1586 char *plugin;
1587 char *optionstr;
1588 uint32_t options;
1589
1590 /* Format tcp.options.address:port */
1591 address = NULL;
1592 plugin = NULL;
1593 optionstr = NULL;
1594 if ((NULL == addr) || (0 == addrlen))
1595 {
1596 GNUNET_break (0);
1597 return GNUNET_SYSERR;
1598 }
1599 if ('\0' != addr[addrlen - 1])
1600 {
1601 GNUNET_break (0);
1602 return GNUNET_SYSERR;
1603 }
1604 if (strlen (addr) != addrlen - 1)
1605 {
1606 GNUNET_break (0);
1607 return GNUNET_SYSERR;
1608 }
1609 plugin = GNUNET_strdup (addr);
1610 optionstr = strchr (plugin, '.');
1611 if (NULL == optionstr)
1612 {
1613 GNUNET_break (0);
1614 GNUNET_free (plugin);
1615 return GNUNET_SYSERR;
1616 }
1617 optionstr[0] = '\0';
1618 optionstr++;
1619 options = atol (optionstr);
1620 address = strchr (optionstr, '.');
1621 if (NULL == address)
1622 {
1623 GNUNET_break (0);
1624 GNUNET_free (plugin);
1625 return GNUNET_SYSERR;
1626 }
1627 address[0] = '\0';
1628 address++;
1629
1630 if (GNUNET_OK !=
1631 GNUNET_STRINGS_to_address_ip (address, strlen (address), &socket_address))
1632 {
1633 GNUNET_break (0);
1634 GNUNET_free (plugin);
1635 return GNUNET_SYSERR;
1636 }
1637
1638 GNUNET_free (plugin);
1639 switch (socket_address.ss_family)
1640 {
1641 case AF_INET: {
1642 struct IPv4TcpAddress *t4;
1643 struct sockaddr_in *in4 = (struct sockaddr_in *) &socket_address;
1644 t4 = GNUNET_new (struct IPv4TcpAddress);
1645 t4->options = htonl (options);
1646 t4->ipv4_addr = in4->sin_addr.s_addr;
1647 t4->t4_port = in4->sin_port;
1648 *buf = t4;
1649 *added = sizeof(struct IPv4TcpAddress);
1650 return GNUNET_OK;
1651 }
1652
1653 case AF_INET6: {
1654 struct IPv6TcpAddress *t6;
1655 struct sockaddr_in6 *in6 = (struct sockaddr_in6 *) &socket_address;
1656 t6 = GNUNET_new (struct IPv6TcpAddress);
1657 t6->options = htonl (options);
1658 t6->ipv6_addr = in6->sin6_addr;
1659 t6->t6_port = in6->sin6_port;
1660 *buf = t6;
1661 *added = sizeof(struct IPv6TcpAddress);
1662 return GNUNET_OK;
1663 }
1664
1665 default:
1666 return GNUNET_SYSERR;
1667 }
1668}
1669
1670
1671/**
1672 * Find the session handle for the given client.
1673 * Currently uses both the hashmap and the client
1674 * context, as the client context is new and the
1675 * logic still needs to be tested.
1676 *
1677 * @param plugin the plugin
1678 * @param client which client to find the session handle for
1679 * @return NULL if no matching session exists
1680 */
1681static struct GNUNET_ATS_Session *
1682lookup_session_by_client (struct Plugin *plugin,
1683 struct GNUNET_SERVER_Client *client)
1684{
1685 return GNUNET_SERVER_client_get_user_context (client,
1686 struct GNUNET_ATS_Session);
1687}
1688
1689
1690/**
1691 * Functions with this signature are called whenever we need
1692 * to close a session due to a disconnect or failure to
1693 * establish a connection.
1694 *
1695 * @param cls the `struct Plugin`
1696 * @param session session to close down
1697 * @return #GNUNET_OK on success
1698 */
1699static int
1700tcp_plugin_disconnect_session (void *cls, struct GNUNET_ATS_Session *session)
1701{
1702 struct Plugin *plugin = cls;
1703 struct PendingMessage *pm;
1704
1705 LOG (GNUNET_ERROR_TYPE_DEBUG,
1706 "Disconnecting session of peer `%s' address `%s'\n",
1707 GNUNET_i2s (&session->target),
1708 tcp_plugin_address_to_string (session->plugin,
1709 session->address->address,
1710 session->address->address_length));
1711
1712 if (NULL != session->timeout_task)
1713 {
1714 GNUNET_SCHEDULER_cancel (session->timeout_task);
1715 session->timeout_task = NULL;
1716 session->timeout = GNUNET_TIME_UNIT_ZERO_ABS;
1717 }
1718
1719 if (GNUNET_YES == GNUNET_CONTAINER_multipeermap_remove (plugin->sessionmap,
1720 &session->target,
1721 session))
1722 {
1723 GNUNET_STATISTICS_update (session->plugin->env->stats,
1724 gettext_noop ("# TCP sessions active"),
1725 -1,
1726 GNUNET_NO);
1727 }
1728 else
1729 {
1730 GNUNET_assert (GNUNET_YES ==
1731 GNUNET_CONTAINER_multipeermap_remove (plugin->nat_wait_conns,
1732 &session->target,
1733 session));
1734 }
1735 if (NULL != session->client)
1736 GNUNET_SERVER_client_set_user_context (session->client, NULL);
1737
1738 /* clean up state */
1739 if (NULL != session->transmit_handle)
1740 {
1741 GNUNET_SERVER_notify_transmit_ready_cancel (session->transmit_handle);
1742 session->transmit_handle = NULL;
1743 }
1744 session->plugin->env->session_end (session->plugin->env->cls,
1745 session->address,
1746 session);
1747
1748 if (NULL != session->nat_connection_timeout)
1749 {
1750 GNUNET_SCHEDULER_cancel (session->nat_connection_timeout);
1751 session->nat_connection_timeout = NULL;
1752 }
1753
1754 while (NULL != (pm = session->pending_messages_head))
1755 {
1756 LOG (GNUNET_ERROR_TYPE_DEBUG,
1757 (NULL != pm->transmit_cont)
1758 ? "Could not deliver message to `%s' at %s.\n"
1759 : "Could not deliver message to `%s' at %s, notifying.\n",
1760 GNUNET_i2s (&session->target),
1761 tcp_plugin_address_to_string (session->plugin,
1762 session->address->address,
1763 session->address->address_length));
1764 GNUNET_STATISTICS_update (session->plugin->env->stats,
1765 gettext_noop ("# bytes currently in TCP buffers"),
1766 -(int64_t) pm->message_size,
1767 GNUNET_NO);
1768 GNUNET_STATISTICS_update (session->plugin->env->stats,
1769 gettext_noop (
1770 "# bytes discarded by TCP (disconnect)"),
1771 pm->message_size,
1772 GNUNET_NO);
1773 GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
1774 session->pending_messages_tail,
1775 pm);
1776 GNUNET_assert (0 < session->msgs_in_queue);
1777 session->msgs_in_queue--;
1778 GNUNET_assert (pm->message_size <= session->bytes_in_queue);
1779 session->bytes_in_queue -= pm->message_size;
1780 if (NULL != pm->transmit_cont)
1781 pm->transmit_cont (pm->transmit_cont_cls,
1782 &session->target,
1783 GNUNET_SYSERR,
1784 pm->message_size,
1785 0);
1786 GNUNET_free (pm);
1787 }
1788 GNUNET_assert (0 == session->msgs_in_queue);
1789 GNUNET_assert (0 == session->bytes_in_queue);
1790 notify_session_monitor (session->plugin, session, GNUNET_TRANSPORT_SS_DONE);
1791
1792 if (NULL != session->receive_delay_task)
1793 {
1794 GNUNET_SCHEDULER_cancel (session->receive_delay_task);
1795 session->receive_delay_task = NULL;
1796 }
1797 if (NULL != session->client)
1798 {
1799 GNUNET_SERVER_client_disconnect (session->client);
1800 session->client = NULL;
1801 }
1802 GNUNET_HELLO_address_free (session->address);
1803 GNUNET_assert (NULL == session->transmit_handle);
1804 GNUNET_free (session);
1805 return GNUNET_OK;
1806}
1807
1808
1809/**
1810 * Function that is called to get the keepalive factor.
1811 * #GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT is divided by this number to
1812 * calculate the interval between keepalive packets.
1813 *
1814 * @param cls closure with the `struct Plugin`
1815 * @return keepalive factor
1816 */
1817static unsigned int
1818tcp_plugin_query_keepalive_factor (void *cls)
1819{
1820 return 3;
1821}
1822
1823
1824/**
1825 * Session was idle for too long, so disconnect it
1826 *
1827 * @param cls the `struct GNUNET_ATS_Session` of the idle session
1828 */
1829static void
1830session_timeout (void *cls)
1831{
1832 struct GNUNET_ATS_Session *s = cls;
1833 struct GNUNET_TIME_Relative left;
1834
1835 s->timeout_task = NULL;
1836 left = GNUNET_TIME_absolute_get_remaining (s->timeout);
1837 if (0 != left.rel_value_us)
1838 {
1839 /* not actually our turn yet, but let's at least update
1840 the monitor, it may think we're about to die ... */
1841 notify_session_monitor (s->plugin, s, GNUNET_TRANSPORT_SS_UPDATE);
1842 s->timeout_task = GNUNET_SCHEDULER_add_delayed (left, &session_timeout, s);
1843 return;
1844 }
1845 LOG (GNUNET_ERROR_TYPE_DEBUG,
1846 "Session %p was idle for %s, disconnecting\n",
1847 s,
1848 GNUNET_STRINGS_relative_time_to_string (
1849 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1850 GNUNET_YES));
1851 /* call session destroy function */
1852 tcp_plugin_disconnect_session (s->plugin, s);
1853}
1854
1855
1856/**
1857 * Increment session timeout due to activity.
1858 *
1859 * @param s session to increment timeout for
1860 */
1861static void
1862reschedule_session_timeout (struct GNUNET_ATS_Session *s)
1863{
1864 GNUNET_assert (NULL != s->timeout_task);
1865 s->timeout =
1866 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1867}
1868
1869
1870/**
1871 * Create a new session. Also queues a welcome message.
1872 *
1873 * @param plugin the plugin
1874 * @param address the address to create the session for
1875 * @param scope network scope the address is from
1876 * @param client client to use, reference counter must have already been increased
1877 * @param is_nat this a NAT session, we should wait for a client to
1878 * connect to us from an address, then assign that to
1879 * the session
1880 * @return new session object
1881 */
1882static struct GNUNET_ATS_Session *
1883create_session (struct Plugin *plugin,
1884 const struct GNUNET_HELLO_Address *address,
1885 enum GNUNET_NetworkType scope,
1886 struct GNUNET_SERVER_Client *client,
1887 int is_nat)
1888{
1889 struct GNUNET_ATS_Session *session;
1890 struct PendingMessage *pm;
1891
1892 if (GNUNET_YES != is_nat)
1893 GNUNET_assert (NULL != client);
1894 else
1895 GNUNET_assert (NULL == client);
1896
1897 LOG (GNUNET_ERROR_TYPE_DEBUG,
1898 "Creating new session for peer `%s' at address %s\n",
1899 GNUNET_i2s (&address->peer),
1900 tcp_plugin_address_to_string (plugin,
1901 address->address,
1902 address->address_length));
1903 session = GNUNET_new (struct GNUNET_ATS_Session);
1904 session->last_activity = GNUNET_TIME_absolute_get ();
1905 session->plugin = plugin;
1906 session->is_nat = is_nat;
1907 if (NULL != client)
1908 {
1909 session->client = client;
1910 GNUNET_SERVER_client_set_user_context (client, session);
1911 }
1912 session->address = GNUNET_HELLO_address_copy (address);
1913 session->target = address->peer;
1914 session->expecting_welcome = GNUNET_YES;
1915 session->scope = scope;
1916 pm = GNUNET_malloc (sizeof(struct PendingMessage)
1917 + sizeof(struct WelcomeMessage));
1918 pm->msg = (const char *) &pm[1];
1919 pm->message_size = sizeof(struct WelcomeMessage);
1920 GNUNET_memcpy (&pm[1], &plugin->my_welcome, sizeof(struct WelcomeMessage));
1921 pm->timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
1922 GNUNET_STATISTICS_update (plugin->env->stats,
1923 gettext_noop ("# bytes currently in TCP buffers"),
1924 pm->message_size,
1925 GNUNET_NO);
1926 GNUNET_CONTAINER_DLL_insert (session->pending_messages_head,
1927 session->pending_messages_tail,
1928 pm);
1929 session->msgs_in_queue++;
1930 session->bytes_in_queue += pm->message_size;
1931 session->timeout =
1932 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1933 session->timeout_task =
1934 GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1935 &session_timeout,
1936 session);
1937 notify_session_monitor (session->plugin, session, GNUNET_TRANSPORT_SS_INIT);
1938 if (GNUNET_YES != is_nat)
1939 {
1940 GNUNET_STATISTICS_update (plugin->env->stats,
1941 gettext_noop ("# TCP sessions active"),
1942 1,
1943 GNUNET_NO);
1944 notify_session_monitor (session->plugin, session, GNUNET_TRANSPORT_SS_UP);
1945 }
1946 else
1947 {
1948 notify_session_monitor (session->plugin,
1949 session,
1950 GNUNET_TRANSPORT_SS_HANDSHAKE);
1951 }
1952 return session;
1953}
1954
1955
1956/**
1957 * If we have pending messages, ask the server to
1958 * transmit them (schedule the respective tasks, etc.)
1959 *
1960 * @param session for which session should we do this
1961 */
1962static void
1963process_pending_messages (struct GNUNET_ATS_Session *session);
1964
1965
1966/**
1967 * Function called to notify a client about the socket
1968 * being ready to queue more data. "buf" will be
1969 * NULL and "size" zero if the socket was closed for
1970 * writing in the meantime.
1971 *
1972 * @param cls closure
1973 * @param size number of bytes available in @a buf
1974 * @param buf where the callee should write the message
1975 * @return number of bytes written to @a buf
1976 */
1977static size_t
1978do_transmit (void *cls, size_t size, void *buf)
1979{
1980 struct GNUNET_ATS_Session *session = cls;
1981 struct GNUNET_PeerIdentity pid;
1982 struct Plugin *plugin;
1983 struct PendingMessage *pos;
1984 struct PendingMessage *hd;
1985 struct PendingMessage *tl;
1986 struct GNUNET_TIME_Absolute now;
1987 char *cbuf;
1988 size_t ret;
1989
1990 session->transmit_handle = NULL;
1991 plugin = session->plugin;
1992 if (NULL == buf)
1993 {
1994 LOG (GNUNET_ERROR_TYPE_DEBUG,
1995 "Timeout trying to transmit to peer `%s', discarding message queue.\n",
1996 GNUNET_i2s (&session->target));
1997 /* timeout; cancel all messages that have already expired */
1998 hd = NULL;
1999 tl = NULL;
2000 ret = 0;
2001 now = GNUNET_TIME_absolute_get ();
2002 while ((NULL != (pos = session->pending_messages_head)) &&
2003 (pos->timeout.abs_value_us <= now.abs_value_us))
2004 {
2005 GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
2006 session->pending_messages_tail,
2007 pos);
2008 GNUNET_assert (0 < session->msgs_in_queue);
2009 session->msgs_in_queue--;
2010 GNUNET_assert (pos->message_size <= session->bytes_in_queue);
2011 session->bytes_in_queue -= pos->message_size;
2012 LOG (GNUNET_ERROR_TYPE_DEBUG,
2013 "Failed to transmit %lu byte message to `%s'.\n",
2014 (unsigned long) pos->message_size,
2015 GNUNET_i2s (&session->target));
2016 ret += pos->message_size;
2017 GNUNET_CONTAINER_DLL_insert_after (hd, tl, tl, pos);
2018 }
2019 /* do this call before callbacks (so that if callbacks destroy
2020 * session, they have a chance to cancel actions done by this
2021 * call) */
2022 process_pending_messages (session);
2023 pid = session->target;
2024 /* no do callbacks and do not use session again since
2025 * the callbacks may abort the session */
2026 while (NULL != (pos = hd))
2027 {
2028 GNUNET_CONTAINER_DLL_remove (hd, tl, pos);
2029 if (NULL != pos->transmit_cont)
2030 pos->transmit_cont (pos->transmit_cont_cls,
2031 &pid,
2032 GNUNET_SYSERR,
2033 pos->message_size,
2034 0);
2035 GNUNET_free (pos);
2036 }
2037 GNUNET_STATISTICS_update (plugin->env->stats,
2038 gettext_noop ("# bytes currently in TCP buffers"),
2039 -(int64_t) ret,
2040 GNUNET_NO);
2041 GNUNET_STATISTICS_update (plugin->env->stats,
2042 gettext_noop (
2043 "# bytes discarded by TCP (timeout)"),
2044 ret,
2045 GNUNET_NO);
2046 if (0 < ret)
2047 notify_session_monitor (session->plugin,
2048 session,
2049 GNUNET_TRANSPORT_SS_UPDATE);
2050 return 0;
2051 }
2052 /* copy all pending messages that would fit */
2053 ret = 0;
2054 cbuf = buf;
2055 hd = NULL;
2056 tl = NULL;
2057 while (NULL != (pos = session->pending_messages_head))
2058 {
2059 if (ret + pos->message_size > size)
2060 break;
2061 GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
2062 session->pending_messages_tail,
2063 pos);
2064 GNUNET_assert (0 < session->msgs_in_queue);
2065 session->msgs_in_queue--;
2066 GNUNET_assert (pos->message_size <= session->bytes_in_queue);
2067 session->bytes_in_queue -= pos->message_size;
2068 GNUNET_assert (size >= pos->message_size);
2069 LOG (GNUNET_ERROR_TYPE_DEBUG,
2070 "Transmitting message of type %u size %lu to peer %s at %s\n",
2071 ntohs (((struct GNUNET_MessageHeader *) pos->msg)->type),
2072 (unsigned long) pos->message_size,
2073 GNUNET_i2s (&session->target),
2074 tcp_plugin_address_to_string (session->plugin,
2075 session->address->address,
2076 session->address->address_length));
2077 /* FIXME: this GNUNET_memcpy can be up to 7% of our total runtime */
2078 GNUNET_memcpy (cbuf, pos->msg, pos->message_size);
2079 cbuf += pos->message_size;
2080 ret += pos->message_size;
2081 size -= pos->message_size;
2082 GNUNET_CONTAINER_DLL_insert_tail (hd, tl, pos);
2083 }
2084 notify_session_monitor (session->plugin, session, GNUNET_TRANSPORT_SS_UPDATE);
2085 /* schedule 'continuation' before callbacks so that callbacks that
2086 * cancel everything don't cause us to use a session that no longer
2087 * exists... */
2088 process_pending_messages (session);
2089 session->last_activity = GNUNET_TIME_absolute_get ();
2090 pid = session->target;
2091 /* we'll now call callbacks that may cancel the session; hence
2092 * we should not use 'session' after this point */
2093 while (NULL != (pos = hd))
2094 {
2095 GNUNET_CONTAINER_DLL_remove (hd, tl, pos);
2096 if (NULL != pos->transmit_cont)
2097 pos->transmit_cont (pos->transmit_cont_cls,
2098 &pid,
2099 GNUNET_OK,
2100 pos->message_size,
2101 pos->message_size); /* FIXME: include TCP overhead */
2102 GNUNET_free (pos);
2103 }
2104 GNUNET_assert (NULL == hd);
2105 GNUNET_assert (NULL == tl);
2106 GNUNET_STATISTICS_update (plugin->env->stats,
2107 gettext_noop ("# bytes currently in TCP buffers"),
2108 -(int64_t) ret,
2109 GNUNET_NO);
2110 GNUNET_STATISTICS_update (plugin->env->stats,
2111 gettext_noop ("# bytes transmitted via TCP"),
2112 ret,
2113 GNUNET_NO);
2114 return ret;
2115}
2116
2117
2118/**
2119 * If we have pending messages, ask the server to
2120 * transmit them (schedule the respective tasks, etc.)
2121 *
2122 * @param session for which session should we do this
2123 */
2124static void
2125process_pending_messages (struct GNUNET_ATS_Session *session)
2126{
2127 struct PendingMessage *pm;
2128
2129 GNUNET_assert (NULL != session->client);
2130 if (NULL != session->transmit_handle)
2131 return;
2132 if (NULL == (pm = session->pending_messages_head))
2133 return;
2134
2135 session->transmit_handle =
2136 GNUNET_SERVER_notify_transmit_ready (session->client,
2137 pm->message_size,
2138 GNUNET_TIME_absolute_get_remaining (
2139 pm->timeout),
2140 &do_transmit,
2141 session);
2142}
2143
2144
2145/**
2146 * Function that can be used by the transport service to transmit
2147 * a message using the plugin. Note that in the case of a
2148 * peer disconnecting, the continuation MUST be called
2149 * prior to the disconnect notification itself. This function
2150 * will be called with this peer's HELLO message to initiate
2151 * a fresh connection to another peer.
2152 *
2153 * @param cls closure
2154 * @param session which session must be used
2155 * @param msgbuf the message to transmit
2156 * @param msgbuf_size number of bytes in @a msgbuf
2157 * @param priority how important is the message (most plugins will
2158 * ignore message priority and just FIFO)
2159 * @param to how long to wait at most for the transmission (does not
2160 * require plugins to discard the message after the timeout,
2161 * just advisory for the desired delay; most plugins will ignore
2162 * this as well)
2163 * @param cont continuation to call once the message has
2164 * been transmitted (or if the transport is ready
2165 * for the next transmission call; or if the
2166 * peer disconnected...); can be NULL
2167 * @param cont_cls closure for @a cont
2168 * @return number of bytes used (on the physical network, with overheads);
2169 * -1 on hard errors (i.e. address invalid); 0 is a legal value
2170 * and does NOT mean that the message was not transmitted (DV)
2171 */
2172static ssize_t
2173tcp_plugin_send (void *cls,
2174 struct GNUNET_ATS_Session *session,
2175 const char *msgbuf,
2176 size_t msgbuf_size,
2177 unsigned int priority,
2178 struct GNUNET_TIME_Relative to,
2179 GNUNET_TRANSPORT_TransmitContinuation cont,
2180 void *cont_cls)
2181{
2182 struct Plugin *plugin = cls;
2183 struct PendingMessage *pm;
2184
2185 /* create new message entry */
2186 pm = GNUNET_malloc (sizeof(struct PendingMessage) + msgbuf_size);
2187 pm->msg = (const char *) &pm[1];
2188 GNUNET_memcpy (&pm[1], msgbuf, msgbuf_size);
2189 pm->message_size = msgbuf_size;
2190 pm->timeout = GNUNET_TIME_relative_to_absolute (to);
2191 pm->transmit_cont = cont;
2192 pm->transmit_cont_cls = cont_cls;
2193
2194 LOG (GNUNET_ERROR_TYPE_DEBUG,
2195 "Asked to transmit %lu bytes to `%s', added message to list.\n",
2196 (unsigned long) msgbuf_size,
2197 GNUNET_i2s (&session->target));
2198
2199 if (GNUNET_YES ==
2200 GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessionmap,
2201 &session->target,
2202 session))
2203 {
2204 GNUNET_assert (NULL != session->client);
2205 GNUNET_SERVER_client_set_timeout (session->client,
2206 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2207 GNUNET_STATISTICS_update (plugin->env->stats,
2208 gettext_noop ("# bytes currently in TCP buffers"),
2209 msgbuf_size,
2210 GNUNET_NO);
2211
2212 /* append pm to pending_messages list */
2213 GNUNET_CONTAINER_DLL_insert_tail (session->pending_messages_head,
2214 session->pending_messages_tail,
2215 pm);
2216 notify_session_monitor (session->plugin,
2217 session,
2218 GNUNET_TRANSPORT_SS_UPDATE);
2219 session->msgs_in_queue++;
2220 session->bytes_in_queue += pm->message_size;
2221 process_pending_messages (session);
2222 return msgbuf_size;
2223 }
2224 if (GNUNET_YES ==
2225 GNUNET_CONTAINER_multipeermap_contains_value (plugin->nat_wait_conns,
2226 &session->target,
2227 session))
2228 {
2229 LOG (GNUNET_ERROR_TYPE_DEBUG,
2230 "This NAT WAIT session for peer `%s' is not yet ready!\n",
2231 GNUNET_i2s (&session->target));
2232 GNUNET_STATISTICS_update (plugin->env->stats,
2233 gettext_noop ("# bytes currently in TCP buffers"),
2234 msgbuf_size,
2235 GNUNET_NO);
2236 /* append pm to pending_messages list */
2237 GNUNET_CONTAINER_DLL_insert_tail (session->pending_messages_head,
2238 session->pending_messages_tail,
2239 pm);
2240 session->msgs_in_queue++;
2241 session->bytes_in_queue += pm->message_size;
2242 notify_session_monitor (session->plugin,
2243 session,
2244 GNUNET_TRANSPORT_SS_HANDSHAKE);
2245 return msgbuf_size;
2246 }
2247 LOG (GNUNET_ERROR_TYPE_ERROR, "Invalid session %p\n", session);
2248 if (NULL != cont)
2249 cont (cont_cls, &session->target, GNUNET_SYSERR, pm->message_size, 0);
2250 GNUNET_break (0);
2251 GNUNET_free (pm);
2252 return GNUNET_SYSERR; /* session does not exist here */
2253}
2254
2255
2256/**
2257 * Closure for #session_lookup_it().
2258 */
2259struct GNUNET_ATS_SessionItCtx
2260{
2261 /**
2262 * Address we are looking for.
2263 */
2264 const struct GNUNET_HELLO_Address *address;
2265
2266 /**
2267 * Where to store the session (if we found it).
2268 */
2269 struct GNUNET_ATS_Session *result;
2270};
2271
2272
2273/**
2274 * Look for a session by address.
2275 *
2276 * @param cls the `struct GNUNET_ATS_SessionItCtx`
2277 * @param key unused
2278 * @param value a `struct GNUNET_ATS_Session`
2279 * @return #GNUNET_YES to continue looking, #GNUNET_NO if we found the session
2280 */
2281static int
2282session_lookup_it (void *cls,
2283 const struct GNUNET_PeerIdentity *key,
2284 void *value)
2285{
2286 struct GNUNET_ATS_SessionItCtx *si_ctx = cls;
2287 struct GNUNET_ATS_Session *session = value;
2288
2289 if (0 != GNUNET_HELLO_address_cmp (si_ctx->address, session->address))
2290 return GNUNET_YES;
2291 si_ctx->result = session;
2292 return GNUNET_NO;
2293}
2294
2295
2296/**
2297 * Task cleaning up a NAT connection attempt after timeout
2298 *
2299 * @param cls the `struct GNUNET_ATS_Session`
2300 */
2301static void
2302nat_connect_timeout (void *cls)
2303{
2304 struct GNUNET_ATS_Session *session = cls;
2305
2306 session->nat_connection_timeout = NULL;
2307 LOG (GNUNET_ERROR_TYPE_DEBUG,
2308 "NAT WAIT connection to `%4s' at `%s' could not be established, removing session\n",
2309 GNUNET_i2s (&session->target),
2310 tcp_plugin_address_to_string (session->plugin,
2311 session->address->address,
2312 session->address->address_length));
2313 tcp_plugin_disconnect_session (session->plugin, session);
2314}
2315
2316
2317/**
2318 * Function that will be called whenever the transport service wants to
2319 * notify the plugin that a session is still active and in use and
2320 * therefore the session timeout for this session has to be updated
2321 *
2322 * @param cls closure
2323 * @param peer which peer was the session for
2324 * @param session which session is being updated
2325 */
2326static void
2327tcp_plugin_update_session_timeout (void *cls,
2328 const struct GNUNET_PeerIdentity *peer,
2329 struct GNUNET_ATS_Session *session)
2330{
2331 reschedule_session_timeout (session);
2332}
2333
2334
2335/**
2336 * Task to signal the server that we can continue
2337 * receiving from the TCP client now.
2338 *
2339 * @param cls the `struct GNUNET_ATS_Session *`
2340 */
2341static void
2342delayed_done (void *cls)
2343{
2344 struct GNUNET_ATS_Session *session = cls;
2345
2346 session->receive_delay_task = NULL;
2347 reschedule_session_timeout (session);
2348 GNUNET_SERVER_receive_done (session->client, GNUNET_OK);
2349}
2350
2351
2352/**
2353 * Function that will be called whenever the transport service wants to
2354 * notify the plugin that the inbound quota changed and that the plugin
2355 * should update it's delay for the next receive value
2356 *
2357 * @param cls closure
2358 * @param peer which peer was the session for
2359 * @param session which session is being updated
2360 * @param delay new delay to use for receiving
2361 */
2362static void
2363tcp_plugin_update_inbound_delay (void *cls,
2364 const struct GNUNET_PeerIdentity *peer,
2365 struct GNUNET_ATS_Session *session,
2366 struct GNUNET_TIME_Relative delay)
2367{
2368 if (NULL == session->receive_delay_task)
2369 return;
2370 LOG (GNUNET_ERROR_TYPE_DEBUG,
2371 "New inbound delay %s\n",
2372 GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_NO));
2373 session->receive_delay = GNUNET_TIME_relative_to_absolute (delay);
2374 GNUNET_SCHEDULER_cancel (session->receive_delay_task);
2375 session->receive_delay_task =
2376 GNUNET_SCHEDULER_add_delayed (delay, &delayed_done, session);
2377}
2378
2379
2380/**
2381 * Create a new session to transmit data to the target
2382 * This session will used to send data to this peer and the plugin will
2383 * notify us by calling the env->session_end function
2384 *
2385 * @param cls closure
2386 * @param address the address to use
2387 * @return the session if the address is valid, NULL otherwise
2388 */
2389static struct GNUNET_ATS_Session *
2390tcp_plugin_get_session (void *cls, const struct GNUNET_HELLO_Address *address)
2391{
2392 struct Plugin *plugin = cls;
2393 struct GNUNET_ATS_Session *session = NULL;
2394 int af;
2395 const void *sb;
2396 size_t sbs;
2397 struct GNUNET_CONNECTION_Handle *sa;
2398 struct sockaddr_in a4;
2399 struct sockaddr_in6 a6;
2400 const struct IPv4TcpAddress *t4;
2401 const struct IPv6TcpAddress *t6;
2402 unsigned int options;
2403 enum GNUNET_NetworkType net_type;
2404 unsigned int is_natd = GNUNET_NO;
2405 size_t addrlen;
2406
2407#ifdef TCP_STEALTH
2408 struct GNUNET_NETWORK_Handle *s;
2409#endif
2410
2411 addrlen = address->address_length;
2412 LOG (GNUNET_ERROR_TYPE_DEBUG,
2413 "Trying to get session for `%s' address of peer `%s'\n",
2414 tcp_plugin_address_to_string (plugin,
2415 address->address,
2416 address->address_length),
2417 GNUNET_i2s (&address->peer));
2418
2419 if (GNUNET_HELLO_address_check_option (address,
2420 GNUNET_HELLO_ADDRESS_INFO_INBOUND))
2421 {
2422 GNUNET_break (0);
2423 return NULL;
2424 }
2425
2426 /* look for existing session */
2427 if (GNUNET_YES == GNUNET_CONTAINER_multipeermap_contains (plugin->sessionmap,
2428 &address->peer))
2429 {
2430 struct GNUNET_ATS_SessionItCtx si_ctx;
2431
2432 si_ctx.address = address;
2433 si_ctx.result = NULL;
2434 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessionmap,
2435 &address->peer,
2436 &session_lookup_it,
2437 &si_ctx);
2438 if (NULL != si_ctx.result)
2439 {
2440 session = si_ctx.result;
2441 LOG (GNUNET_ERROR_TYPE_DEBUG,
2442 "Found existing session for `%s' address `%s'\n",
2443 GNUNET_i2s (&address->peer),
2444 tcp_plugin_address_to_string (plugin,
2445 address->address,
2446 address->address_length));
2447 return session;
2448 }
2449 /* This is a bit of a hack, limiting TCP to never allow more than
2450 one TCP connection to any given peer at the same time.
2451 Without this, peers sometimes disagree about which of the TCP
2452 connections they should use, causing one side to believe that
2453 they transmit successfully, while the other receives nothing. */return NULL; /* Refuse to have more than one TCP connection per
2454 peer pair at the same time. */
2455 }
2456
2457 if (addrlen == sizeof(struct IPv6TcpAddress))
2458 {
2459 GNUNET_assert (NULL != address->address); /* make static analysis happy */
2460 t6 = address->address;
2461 options = t6->options;
2462 af = AF_INET6;
2463 memset (&a6, 0, sizeof(a6));
2464#if HAVE_SOCKADDR_IN_SIN_LEN
2465 a6.sin6_len = sizeof(a6);
2466#endif
2467 a6.sin6_family = AF_INET6;
2468 a6.sin6_port = t6->t6_port;
2469 if (t6->t6_port == 0)
2470 is_natd = GNUNET_YES;
2471 GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr));
2472 sb = &a6;
2473 sbs = sizeof(a6);
2474 }
2475 else if (addrlen == sizeof(struct IPv4TcpAddress))
2476 {
2477 GNUNET_assert (NULL != address->address); /* make static analysis happy */
2478 t4 = address->address;
2479 options = t4->options;
2480 af = AF_INET;
2481 memset (&a4, 0, sizeof(a4));
2482#if HAVE_SOCKADDR_IN_SIN_LEN
2483 a4.sin_len = sizeof(a4);
2484#endif
2485 a4.sin_family = AF_INET;
2486 a4.sin_port = t4->t4_port;
2487 if (t4->t4_port == 0)
2488 is_natd = GNUNET_YES;
2489 a4.sin_addr.s_addr = t4->ipv4_addr;
2490 sb = &a4;
2491 sbs = sizeof(a4);
2492 }
2493 else
2494 {
2495 GNUNET_STATISTICS_update (
2496 plugin->env->stats,
2497 gettext_noop ("# requests to create session with invalid address"),
2498 1,
2499 GNUNET_NO);
2500 return NULL;
2501 }
2502
2503 net_type = plugin->env->get_address_type (plugin->env->cls, sb, sbs);
2504 GNUNET_break (net_type != GNUNET_NT_UNSPECIFIED);
2505
2506 if ((is_natd == GNUNET_YES) && (addrlen == sizeof(struct IPv6TcpAddress)))
2507 {
2508 /* NAT client only works with IPv4 addresses */
2509 return NULL;
2510 }
2511
2512 if (plugin->cur_connections >= plugin->max_connections)
2513 {
2514 /* saturated */
2515 return NULL;
2516 }
2517
2518 if ((is_natd == GNUNET_YES) &&
2519 (GNUNET_YES ==
2520 GNUNET_CONTAINER_multipeermap_contains (plugin->nat_wait_conns,
2521 &address->peer)))
2522 {
2523 /* Only do one NAT punch attempt per peer identity */
2524 return NULL;
2525 }
2526
2527 if ((is_natd == GNUNET_YES) && (NULL != plugin->nat) &&
2528 (GNUNET_NO ==
2529 GNUNET_CONTAINER_multipeermap_contains (plugin->nat_wait_conns,
2530 &address->peer)))
2531 {
2532 struct sockaddr_in local_sa;
2533
2534 LOG (GNUNET_ERROR_TYPE_DEBUG,
2535 "Found valid IPv4 NAT address (creating session)!\n");
2536 session = create_session (plugin, address, net_type, NULL, GNUNET_YES);
2537 session->nat_connection_timeout =
2538 GNUNET_SCHEDULER_add_delayed (NAT_TIMEOUT, &nat_connect_timeout, session);
2539 GNUNET_assert (GNUNET_OK ==
2540 GNUNET_CONTAINER_multipeermap_put (
2541 plugin->nat_wait_conns,
2542 &session->target,
2543 session,
2544 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2545
2546 LOG (GNUNET_ERROR_TYPE_DEBUG,
2547 "Created NAT WAIT connection to `%s' at `%s'\n",
2548 GNUNET_i2s (&session->target),
2549 GNUNET_a2s (sb, sbs));
2550 memset (&local_sa, 0, sizeof(local_sa));
2551 local_sa.sin_family = AF_INET;
2552 local_sa.sin_port = htons (plugin->open_port);
2553 /* We leave sin_address at 0, let the kernel figure it out,
2554 even if our bind() is more specific. (May want to reconsider
2555 later.) */
2556 if (GNUNET_OK == GNUNET_NAT_request_reversal (plugin->nat, &local_sa, &a4))
2557 return session;
2558 LOG (GNUNET_ERROR_TYPE_DEBUG,
2559 "Running NAT client for `%s' at `%s' failed\n",
2560 GNUNET_i2s (&session->target),
2561 GNUNET_a2s (sb, sbs));
2562 tcp_plugin_disconnect_session (plugin, session);
2563 return NULL;
2564 }
2565
2566 /* create new outbound session */
2567 if (0 != (options & TCP_OPTIONS_TCP_STEALTH))
2568 {
2569#ifdef TCP_STEALTH
2570 s = GNUNET_NETWORK_socket_create (af, SOCK_STREAM, 0);
2571 if (NULL == s)
2572 {
2573 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
2574 "socket");
2575 sa = NULL;
2576 }
2577 else
2578 {
2579 if ((GNUNET_OK !=
2580 GNUNET_NETWORK_socket_setsockopt (s,
2581 IPPROTO_TCP,
2582 TCP_STEALTH,
2583 &session->target,
2584 sizeof(
2585 struct GNUNET_PeerIdentity))) ||
2586 (GNUNET_OK !=
2587 GNUNET_NETWORK_socket_setsockopt (s,
2588 IPPROTO_TCP,
2589 TCP_STEALTH_INTEGRITY,
2590 &plugin->my_welcome,
2591 sizeof(struct WelcomeMessage))))
2592 {
2593 /* TCP STEALTH not supported by kernel */
2594 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (s));
2595 sa = NULL;
2596 }
2597 else
2598 {
2599 sa = GNUNET_CONNECTION_connect_socket (s, sb, sbs);
2600 }
2601 }
2602#else
2603 sa = NULL;
2604#endif
2605 }
2606 else
2607 {
2608 sa = GNUNET_CONNECTION_create_from_sockaddr (af, sb, sbs);
2609 }
2610 if (NULL == sa)
2611 {
2612 LOG (GNUNET_ERROR_TYPE_DEBUG,
2613 "Failed to create connection to `%s' at `%s'\n",
2614 GNUNET_i2s (&address->peer),
2615 GNUNET_a2s (sb, sbs));
2616 return NULL;
2617 }
2618 LOG (GNUNET_ERROR_TYPE_DEBUG,
2619 "Asked to transmit to `%s', creating fresh session using address `%s'.\n",
2620 GNUNET_i2s (&address->peer),
2621 GNUNET_a2s (sb, sbs));
2622
2623 session = create_session (plugin,
2624 address,
2625 net_type,
2626 GNUNET_SERVER_connect_socket (plugin->server, sa),
2627 GNUNET_NO);
2628 (void) GNUNET_CONTAINER_multipeermap_put (
2629 plugin->sessionmap,
2630 &session->target,
2631 session,
2632 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2633 /* Send TCP Welcome */
2634 process_pending_messages (session);
2635
2636 return session;
2637}
2638
2639
2640/**
2641 * We have been asked to destroy all connections to a particular peer.
2642 * This function is called on each applicable session and must tear it
2643 * down.
2644 *
2645 * @param cls the `struct Plugin *`
2646 * @param key the peer which the session belongs to (unused)
2647 * @param value the `struct GNUNET_ATS_Session`
2648 * @return #GNUNET_YES (continue to iterate)
2649 */
2650static int
2651session_disconnect_it (void *cls,
2652 const struct GNUNET_PeerIdentity *key,
2653 void *value)
2654{
2655 struct Plugin *plugin = cls;
2656 struct GNUNET_ATS_Session *session = value;
2657
2658 GNUNET_STATISTICS_update (session->plugin->env->stats,
2659 gettext_noop (
2660 "# transport-service disconnect requests for TCP"),
2661 1,
2662 GNUNET_NO);
2663 tcp_plugin_disconnect_session (plugin, session);
2664 return GNUNET_YES;
2665}
2666
2667
2668/**
2669 * Function that can be called to force a disconnect from the
2670 * specified neighbour. This should also cancel all previously
2671 * scheduled transmissions. Obviously the transmission may have been
2672 * partially completed already, which is OK. The plugin is supposed
2673 * to close the connection (if applicable) and no longer call the
2674 * transmit continuation(s).
2675 *
2676 * Finally, plugin MUST NOT call the services's receive function to
2677 * notify the service that the connection to the specified target was
2678 * closed after a getting this call.
2679 *
2680 * @param cls closure
2681 * @param target peer for which the last transmission is
2682 * to be cancelled
2683 */
2684static void
2685tcp_plugin_disconnect (void *cls, const struct GNUNET_PeerIdentity *target)
2686{
2687 struct Plugin *plugin = cls;
2688
2689 LOG (GNUNET_ERROR_TYPE_DEBUG,
2690 "Disconnecting peer `%s'\n",
2691 GNUNET_i2s (target));
2692 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessionmap,
2693 target,
2694 &session_disconnect_it,
2695 plugin);
2696 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->nat_wait_conns,
2697 target,
2698 &session_disconnect_it,
2699 plugin);
2700}
2701
2702
2703/**
2704 * We are processing an address pretty printing request and finished
2705 * the IP resolution (if applicable). Append our port and forward the
2706 * result. If called with @a hostname NULL, we are done and should
2707 * clean up the pretty printer (otherwise, there might be multiple
2708 * hostnames for the IP address and we might receive more).
2709 *
2710 * @param cls the `struct PrettyPrinterContext *`
2711 * @param hostname hostname part of the address
2712 */
2713static void
2714append_port (void *cls, const char *hostname)
2715{
2716 struct PrettyPrinterContext *ppc = cls;
2717 struct Plugin *plugin = ppc->plugin;
2718 char *ret;
2719
2720 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2721 "append_port called with hostname `%s'\n",
2722 hostname);
2723 if (NULL == hostname)
2724 {
2725 /* Final call, done */
2726 ppc->resolver_handle = NULL;
2727 GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head,
2728 plugin->ppc_dll_tail,
2729 ppc);
2730 ppc->asc (ppc->asc_cls, NULL, GNUNET_OK);
2731 GNUNET_free (ppc);
2732 return;
2733 }
2734 if (GNUNET_YES == ppc->ipv6)
2735 GNUNET_asprintf (&ret,
2736 "%s.%u.[%s]:%d",
2737 PLUGIN_NAME,
2738 ppc->options,
2739 hostname,
2740 ppc->port);
2741 else
2742 GNUNET_asprintf (&ret,
2743 "%s.%u.%s:%d",
2744 PLUGIN_NAME,
2745 ppc->options,
2746 hostname,
2747 ppc->port);
2748 ppc->asc (ppc->asc_cls, ret, GNUNET_OK);
2749 GNUNET_free (ret);
2750}
2751
2752
2753/**
2754 * Convert the transports address to a nice, human-readable format.
2755 *
2756 * @param cls closure with the `struct Plugin`
2757 * @param type name of the transport that generated the address
2758 * @param addr one of the addresses of the host, NULL for the last address
2759 * the specific address format depends on the transport
2760 * @param addrlen length of the @a addr
2761 * @param numeric should (IP) addresses be displayed in numeric form?
2762 * @param timeout after how long should we give up?
2763 * @param asc function to call on each string
2764 * @param asc_cls closure for @a asc
2765 */
2766static void
2767tcp_plugin_address_pretty_printer (void *cls,
2768 const char *type,
2769 const void *addr,
2770 size_t addrlen,
2771 int numeric,
2772 struct GNUNET_TIME_Relative timeout,
2773 GNUNET_TRANSPORT_AddressStringCallback asc,
2774 void *asc_cls)
2775{
2776 struct Plugin *plugin = cls;
2777 struct PrettyPrinterContext *ppc;
2778 const void *sb;
2779 size_t sbs;
2780 struct sockaddr_in a4;
2781 struct sockaddr_in6 a6;
2782 const struct IPv4TcpAddress *t4;
2783 const struct IPv6TcpAddress *t6;
2784 uint16_t port;
2785 uint32_t options;
2786
2787 if (sizeof(struct IPv6TcpAddress) == addrlen)
2788 {
2789 t6 = addr;
2790 memset (&a6, 0, sizeof(a6));
2791 a6.sin6_family = AF_INET6;
2792 a6.sin6_port = t6->t6_port;
2793 GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr));
2794 port = ntohs (t6->t6_port);
2795 options = ntohl (t6->options);
2796 sb = &a6;
2797 sbs = sizeof(a6);
2798 }
2799 else if (sizeof(struct IPv4TcpAddress) == addrlen)
2800 {
2801 t4 = addr;
2802 memset (&a4, 0, sizeof(a4));
2803 a4.sin_family = AF_INET;
2804 a4.sin_port = t4->t4_port;
2805 a4.sin_addr.s_addr = t4->ipv4_addr;
2806 port = ntohs (t4->t4_port);
2807 options = ntohl (t4->options);
2808 sb = &a4;
2809 sbs = sizeof(a4);
2810 }
2811 else
2812 {
2813 /* invalid address */
2814 LOG (GNUNET_ERROR_TYPE_WARNING,
2815 _ ("Unexpected address length: %u bytes\n"),
2816 (unsigned int) addrlen);
2817 asc (asc_cls, NULL, GNUNET_SYSERR);
2818 asc (asc_cls, NULL, GNUNET_OK);
2819 return;
2820 }
2821 ppc = GNUNET_new (struct PrettyPrinterContext);
2822 ppc->plugin = plugin;
2823 if (addrlen == sizeof(struct IPv6TcpAddress))
2824 ppc->ipv6 = GNUNET_YES;
2825 else
2826 ppc->ipv6 = GNUNET_NO;
2827 ppc->asc = asc;
2828 ppc->asc_cls = asc_cls;
2829 ppc->port = port;
2830 ppc->options = options;
2831 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting DNS reverse lookup\n");
2832 ppc->resolver_handle = GNUNET_RESOLVER_hostname_get (sb,
2833 sbs,
2834 ! numeric,
2835 timeout,
2836 &append_port,
2837 ppc);
2838 if (NULL == ppc->resolver_handle)
2839 {
2840 GNUNET_break (0);
2841 GNUNET_free (ppc);
2842 return;
2843 }
2844 GNUNET_CONTAINER_DLL_insert (plugin->ppc_dll_head, plugin->ppc_dll_tail, ppc);
2845}
2846
2847
2848/**
2849 * Function that will be called to check if a binary address for this
2850 * plugin is well-formed and corresponds to an address for THIS peer
2851 * (as per our configuration). Naturally, if absolutely necessary,
2852 * plugins can be a bit conservative in their answer, but in general
2853 * plugins should make sure that the address does not redirect
2854 * traffic to a 3rd party that might try to man-in-the-middle our
2855 * traffic.
2856 *
2857 * @param cls closure, our `struct Plugin *`
2858 * @param addr pointer to the address
2859 * @param addrlen length of @a addr
2860 * @return #GNUNET_OK if this is a plausible address for this peer
2861 * and transport, #GNUNET_SYSERR if not
2862 */
2863static int
2864tcp_plugin_check_address (void *cls, const void *addr, size_t addrlen)
2865{
2866 struct Plugin *plugin = cls;
2867 const struct IPv4TcpAddress *v4;
2868 const struct IPv6TcpAddress *v6;
2869
2870 if ((addrlen != sizeof(struct IPv4TcpAddress)) &&
2871 (addrlen != sizeof(struct IPv6TcpAddress)))
2872 {
2873 GNUNET_break_op (0);
2874 return GNUNET_SYSERR;
2875 }
2876
2877 if (addrlen == sizeof(struct IPv4TcpAddress))
2878 {
2879 struct sockaddr_in s4;
2880
2881 v4 = (const struct IPv4TcpAddress *) addr;
2882 if (0 != memcmp (&v4->options, &plugin->myoptions, sizeof(uint32_t)))
2883 {
2884 GNUNET_break (0);
2885 return GNUNET_SYSERR;
2886 }
2887 memset (&s4, 0, sizeof(s4));
2888 s4.sin_family = AF_INET;
2889#if HAVE_SOCKADDR_IN_SIN_LEN
2890 s4.sin_len = sizeof(s4);
2891#endif
2892 s4.sin_port = v4->t4_port;
2893 s4.sin_addr.s_addr = v4->ipv4_addr;
2894
2895 if (GNUNET_OK !=
2896 GNUNET_NAT_test_address (plugin->nat, &s4, sizeof(struct sockaddr_in)))
2897 return GNUNET_SYSERR;
2898 }
2899 else
2900 {
2901 struct sockaddr_in6 s6;
2902
2903 v6 = (const struct IPv6TcpAddress *) addr;
2904 if (IN6_IS_ADDR_LINKLOCAL (&v6->ipv6_addr))
2905 {
2906 GNUNET_break_op (0);
2907 return GNUNET_SYSERR;
2908 }
2909 if (0 != memcmp (&v6->options, &plugin->myoptions, sizeof(uint32_t)))
2910 {
2911 GNUNET_break (0);
2912 return GNUNET_SYSERR;
2913 }
2914 memset (&s6, 0, sizeof(s6));
2915 s6.sin6_family = AF_INET6;
2916#if HAVE_SOCKADDR_IN_SIN_LEN
2917 s6.sin6_len = sizeof(s6);
2918#endif
2919 s6.sin6_port = v6->t6_port;
2920 s6.sin6_addr = v6->ipv6_addr;
2921
2922 if (GNUNET_OK != GNUNET_NAT_test_address (plugin->nat,
2923 &s6,
2924 sizeof(struct sockaddr_in6)))
2925 return GNUNET_SYSERR;
2926 }
2927 return GNUNET_OK;
2928}
2929
2930
2931/**
2932 * We've received a nat probe from this peer via TCP. Finish
2933 * creating the client session and resume sending of queued
2934 * messages.
2935 *
2936 * @param cls closure
2937 * @param client identification of the client
2938 * @param message the actual message
2939 */
2940static void
2941handle_tcp_nat_probe (void *cls,
2942 struct GNUNET_SERVER_Client *client,
2943 const struct GNUNET_MessageHeader *message)
2944{
2945 struct Plugin *plugin = cls;
2946 struct GNUNET_ATS_Session *session;
2947 const struct TCP_NAT_ProbeMessage *tcp_nat_probe;
2948 size_t alen;
2949 void *vaddr;
2950 struct IPv4TcpAddress *t4;
2951 struct IPv6TcpAddress *t6;
2952 const struct sockaddr_in *s4;
2953 const struct sockaddr_in6 *s6;
2954
2955 LOG (GNUNET_ERROR_TYPE_DEBUG, "Received NAT probe\n");
2956 /* We have received a TCP NAT probe, meaning we (hopefully) initiated
2957 * a connection to this peer by running gnunet-nat-client. This peer
2958 * received the punch message and now wants us to use the new connection
2959 * as the default for that peer. Do so and then send a WELCOME message
2960 * so we can really be connected!
2961 */if (ntohs (message->size) != sizeof(struct TCP_NAT_ProbeMessage))
2962 {
2963 GNUNET_break_op (0);
2964 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2965 return;
2966 }
2967
2968 tcp_nat_probe = (const struct TCP_NAT_ProbeMessage *) message;
2969 if (0 == memcmp (&tcp_nat_probe->clientIdentity,
2970 plugin->env->my_identity,
2971 sizeof(struct GNUNET_PeerIdentity)))
2972 {
2973 /* refuse connections from ourselves */
2974 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2975 return;
2976 }
2977
2978 session = GNUNET_CONTAINER_multipeermap_get (plugin->nat_wait_conns,
2979 &tcp_nat_probe->clientIdentity);
2980 if (NULL == session)
2981 {
2982 LOG (GNUNET_ERROR_TYPE_DEBUG, "Did NOT find session for NAT probe!\n");
2983 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2984 return;
2985 }
2986 LOG (GNUNET_ERROR_TYPE_DEBUG, "Found session for NAT probe!\n");
2987
2988 if (NULL != session->nat_connection_timeout)
2989 {
2990 GNUNET_SCHEDULER_cancel (session->nat_connection_timeout);
2991 session->nat_connection_timeout = NULL;
2992 }
2993
2994 if (GNUNET_OK != GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
2995 {
2996 GNUNET_break (0);
2997 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2998 tcp_plugin_disconnect_session (plugin, session);
2999 return;
3000 }
3001 GNUNET_assert (
3002 GNUNET_YES ==
3003 GNUNET_CONTAINER_multipeermap_remove (plugin->nat_wait_conns,
3004 &tcp_nat_probe->clientIdentity,
3005 session));
3006 GNUNET_SERVER_client_set_user_context (client, session);
3007 (void) GNUNET_CONTAINER_multipeermap_put (
3008 plugin->sessionmap,
3009 &session->target,
3010 session,
3011 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3012 session->last_activity = GNUNET_TIME_absolute_get ();
3013 LOG (GNUNET_ERROR_TYPE_DEBUG,
3014 "Found address `%s' for incoming connection\n",
3015 GNUNET_a2s (vaddr, alen));
3016 switch (((const struct sockaddr *) vaddr)->sa_family)
3017 {
3018 case AF_INET:
3019 s4 = vaddr;
3020 t4 = GNUNET_new (struct IPv4TcpAddress);
3021 t4->options = htonl (TCP_OPTIONS_NONE);
3022 t4->t4_port = s4->sin_port;
3023 t4->ipv4_addr = s4->sin_addr.s_addr;
3024 session->address =
3025 GNUNET_HELLO_address_allocate (&tcp_nat_probe->clientIdentity,
3026 PLUGIN_NAME,
3027 &t4,
3028 sizeof(struct IPv4TcpAddress),
3029 GNUNET_HELLO_ADDRESS_INFO_NONE);
3030 break;
3031
3032 case AF_INET6:
3033 s6 = vaddr;
3034 t6 = GNUNET_new (struct IPv6TcpAddress);
3035 t6->options = htonl (TCP_OPTIONS_NONE);
3036 t6->t6_port = s6->sin6_port;
3037 GNUNET_memcpy (&t6->ipv6_addr, &s6->sin6_addr, sizeof(struct in6_addr));
3038 session->address =
3039 GNUNET_HELLO_address_allocate (&tcp_nat_probe->clientIdentity,
3040 PLUGIN_NAME,
3041 &t6,
3042 sizeof(struct IPv6TcpAddress),
3043 GNUNET_HELLO_ADDRESS_INFO_NONE);
3044 break;
3045
3046 default:
3047 GNUNET_break_op (0);
3048 LOG (GNUNET_ERROR_TYPE_DEBUG, "Bad address for incoming connection!\n");
3049 GNUNET_free (vaddr);
3050 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3051 tcp_plugin_disconnect_session (plugin, session);
3052 return;
3053 }
3054 GNUNET_free (vaddr);
3055 GNUNET_break (NULL == session->client);
3056 session->client = client;
3057 GNUNET_STATISTICS_update (plugin->env->stats,
3058 gettext_noop ("# TCP sessions active"),
3059 1,
3060 GNUNET_NO);
3061 process_pending_messages (session);
3062 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3063}
3064
3065
3066/**
3067 * We've received a welcome from this peer via TCP. Possibly create a
3068 * fresh client record and send back our welcome.
3069 *
3070 * @param cls closure
3071 * @param client identification of the client
3072 * @param message the actual message
3073 */
3074static void
3075handle_tcp_welcome (void *cls,
3076 struct GNUNET_SERVER_Client *client,
3077 const struct GNUNET_MessageHeader *message)
3078{
3079 struct Plugin *plugin = cls;
3080 const struct WelcomeMessage *wm = (const struct WelcomeMessage *) message;
3081 struct GNUNET_HELLO_Address *address;
3082 struct GNUNET_ATS_Session *session;
3083 size_t alen;
3084 void *vaddr;
3085 struct IPv4TcpAddress t4;
3086 struct IPv6TcpAddress t6;
3087 const struct sockaddr_in *s4;
3088 const struct sockaddr_in6 *s6;
3089
3090 if (0 == memcmp (&wm->clientIdentity,
3091 plugin->env->my_identity,
3092 sizeof(struct GNUNET_PeerIdentity)))
3093 {
3094 /* refuse connections from ourselves */
3095 if (GNUNET_OK == GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
3096 {
3097 LOG (GNUNET_ERROR_TYPE_INFO,
3098 "Received WELCOME message from my own identity `%s' on address `%s'\n",
3099 GNUNET_i2s (&wm->clientIdentity),
3100 GNUNET_a2s (vaddr, alen));
3101 GNUNET_free (vaddr);
3102 }
3103 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3104 return;
3105 }
3106
3107 if (GNUNET_OK == GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
3108 {
3109 LOG (GNUNET_ERROR_TYPE_DEBUG,
3110 "Received WELCOME message from `%s' on address `%s'\n",
3111 GNUNET_i2s (&wm->clientIdentity),
3112 GNUNET_a2s (vaddr, alen));
3113 GNUNET_free (vaddr);
3114 }
3115 GNUNET_STATISTICS_update (plugin->env->stats,
3116 gettext_noop ("# TCP WELCOME messages received"),
3117 1,
3118 GNUNET_NO);
3119 session = lookup_session_by_client (plugin, client);
3120 if (NULL != session)
3121 {
3122 if (GNUNET_OK == GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
3123 {
3124 LOG (GNUNET_ERROR_TYPE_DEBUG,
3125 "Found existing session %p for peer `%s'\n",
3126 session,
3127 GNUNET_a2s (vaddr, alen));
3128 GNUNET_free (vaddr);
3129 }
3130 }
3131 else
3132 {
3133 if (GNUNET_OK == GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
3134 {
3135 if (alen == sizeof(struct sockaddr_in))
3136 {
3137 s4 = vaddr;
3138 memset (&t4, '\0', sizeof(t4));
3139 t4.options = htonl (TCP_OPTIONS_NONE);
3140 t4.t4_port = s4->sin_port;
3141 t4.ipv4_addr = s4->sin_addr.s_addr;
3142 address =
3143 GNUNET_HELLO_address_allocate (&wm->clientIdentity,
3144 PLUGIN_NAME,
3145 &t4,
3146 sizeof(t4),
3147 GNUNET_HELLO_ADDRESS_INFO_INBOUND);
3148 }
3149 else if (alen == sizeof(struct sockaddr_in6))
3150 {
3151 s6 = vaddr;
3152 memset (&t6, '\0', sizeof(t6));
3153 t6.options = htonl (TCP_OPTIONS_NONE);
3154 t6.t6_port = s6->sin6_port;
3155 GNUNET_memcpy (&t6.ipv6_addr, &s6->sin6_addr, sizeof(struct in6_addr));
3156 address =
3157 GNUNET_HELLO_address_allocate (&wm->clientIdentity,
3158 PLUGIN_NAME,
3159 &t6,
3160 sizeof(t6),
3161 GNUNET_HELLO_ADDRESS_INFO_INBOUND);
3162 }
3163 else
3164 {
3165 GNUNET_break (0);
3166 GNUNET_free (vaddr);
3167 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3168 return;
3169 }
3170 session = create_session (plugin,
3171 address,
3172 plugin->env->get_address_type (plugin->env->cls,
3173 vaddr,
3174 alen),
3175 client,
3176 GNUNET_NO);
3177 GNUNET_break (GNUNET_NT_UNSPECIFIED != session->scope);
3178 GNUNET_HELLO_address_free (address);
3179 LOG (GNUNET_ERROR_TYPE_DEBUG,
3180 "Creating new%s session %p for peer `%s' client %p\n",
3181 GNUNET_HELLO_address_check_option (session->address,
3182 GNUNET_HELLO_ADDRESS_INFO_INBOUND)
3183 ? " inbound"
3184 : "",
3185 session,
3186 tcp_plugin_address_to_string (plugin,
3187 session->address->address,
3188 session->address->address_length),
3189 client);
3190 GNUNET_free (vaddr);
3191 (void) GNUNET_CONTAINER_multipeermap_put (
3192 plugin->sessionmap,
3193 &session->target,
3194 session,
3195 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3196 /* Notify transport and ATS about new session */
3197 plugin->env->session_start (plugin->env->cls,
3198 session->address,
3199 session,
3200 session->scope);
3201 }
3202 else
3203 {
3204 LOG (GNUNET_ERROR_TYPE_DEBUG,
3205 "Did not obtain TCP socket address for incoming connection\n");
3206 GNUNET_break (0);
3207 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3208 return;
3209 }
3210 }
3211
3212 if (GNUNET_YES != session->expecting_welcome)
3213 {
3214 GNUNET_break_op (0);
3215 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3216 return;
3217 }
3218 session->last_activity = GNUNET_TIME_absolute_get ();
3219 session->expecting_welcome = GNUNET_NO;
3220
3221 process_pending_messages (session);
3222 GNUNET_SERVER_client_set_timeout (client,
3223 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3224 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3225}
3226
3227
3228/**
3229 * We've received data for this peer via TCP. Unbox,
3230 * compute latency and forward.
3231 *
3232 * @param cls closure
3233 * @param client identification of the client
3234 * @param message the actual message
3235 */
3236static void
3237handle_tcp_data (void *cls,
3238 struct GNUNET_SERVER_Client *client,
3239 const struct GNUNET_MessageHeader *message)
3240{
3241 struct Plugin *plugin = cls;
3242 struct GNUNET_ATS_Session *session;
3243 struct GNUNET_TIME_Relative delay;
3244 uint16_t type;
3245
3246 type = ntohs (message->type);
3247 if ((GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME == type) ||
3248 (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE == type))
3249 {
3250 /* We don't want to propagate WELCOME and NAT Probe messages up! */
3251 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3252 return;
3253 }
3254 session = lookup_session_by_client (plugin, client);
3255 if (NULL == session)
3256 {
3257 /* No inbound session found */
3258 void *vaddr = NULL;
3259 size_t alen;
3260
3261 GNUNET_assert (GNUNET_OK ==
3262 GNUNET_SERVER_client_get_address (client, &vaddr, &alen));
3263 LOG (GNUNET_ERROR_TYPE_ERROR,
3264 "Received unexpected %u bytes of type %u from `%s'\n",
3265 (unsigned int) ntohs (message->size),
3266 (unsigned int) ntohs (message->type),
3267 GNUNET_a2s (vaddr, alen));
3268 GNUNET_break_op (0);
3269 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3270 GNUNET_free (vaddr);
3271 return;
3272 }
3273 if (GNUNET_YES == session->expecting_welcome)
3274 {
3275 /* Session is expecting WELCOME message */
3276 void *vaddr = NULL;
3277 size_t alen;
3278
3279 GNUNET_SERVER_client_get_address (client, &vaddr, &alen);
3280 LOG (GNUNET_ERROR_TYPE_ERROR,
3281 "Received unexpected %u bytes of type %u from `%s'\n",
3282 (unsigned int) ntohs (message->size),
3283 (unsigned int) ntohs (message->type),
3284 GNUNET_a2s (vaddr, alen));
3285 GNUNET_break_op (0);
3286 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3287 GNUNET_free (vaddr);
3288 return;
3289 }
3290
3291 session->last_activity = GNUNET_TIME_absolute_get ();
3292 {
3293 void *vaddr = NULL;
3294 size_t alen;
3295
3296 GNUNET_SERVER_client_get_address (client, &vaddr, &alen);
3297 LOG (GNUNET_ERROR_TYPE_DEBUG,
3298 "Passing %u bytes of type %u from `%s' at %s to transport service.\n",
3299 (unsigned int) ntohs (message->size),
3300 (unsigned int) ntohs (message->type),
3301 GNUNET_i2s (&session->target),
3302 GNUNET_a2s (vaddr, alen));
3303 GNUNET_free (vaddr);
3304 }
3305
3306 GNUNET_STATISTICS_update (plugin->env->stats,
3307 gettext_noop ("# bytes received via TCP"),
3308 ntohs (message->size),
3309 GNUNET_NO);
3310
3311 GNUNET_assert (
3312 GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessionmap,
3313 &session->target,
3314 session));
3315 delay =
3316 plugin->env->receive (plugin->env->cls, session->address, session, message);
3317 reschedule_session_timeout (session);
3318 if (0 == delay.rel_value_us)
3319 {
3320 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3321 }
3322 else
3323 {
3324 LOG (GNUNET_ERROR_TYPE_DEBUG,
3325 "Throttling receiving from `%s' for %s\n",
3326 GNUNET_i2s (&session->target),
3327 GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
3328 GNUNET_SERVER_disable_receive_done_warning (client);
3329 GNUNET_assert (NULL == session->receive_delay_task);
3330 session->receive_delay_task =
3331 GNUNET_SCHEDULER_add_delayed (delay, &delayed_done, session);
3332 }
3333}
3334
3335
3336/**
3337 * Function called whenever a peer is connected on the "SERVER" level.
3338 * Increments number of active connections and suspends server if we
3339 * have reached the limit.
3340 *
3341 * @param cls closure
3342 * @param client identification of the client
3343 */
3344static void
3345connect_notify (void *cls, struct GNUNET_SERVER_Client *client)
3346{
3347 struct Plugin *plugin = cls;
3348
3349 if (NULL == client)
3350 return;
3351 plugin->cur_connections++;
3352 GNUNET_STATISTICS_set (plugin->env->stats,
3353 gettext_noop ("# TCP server connections active"),
3354 plugin->cur_connections,
3355 GNUNET_NO);
3356 GNUNET_STATISTICS_update (plugin->env->stats,
3357 gettext_noop ("# TCP server connect events"),
3358 1,
3359 GNUNET_NO);
3360 if (plugin->cur_connections != plugin->max_connections)
3361 return;
3362 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3363 _ ("TCP connection limit reached, suspending server\n"));
3364 GNUNET_STATISTICS_update (plugin->env->stats,
3365 gettext_noop ("# TCP service suspended"),
3366 1,
3367 GNUNET_NO);
3368 GNUNET_SERVER_suspend (
3369 plugin->server); /* Maximum number of connections rechead */
3370}
3371
3372
3373/**
3374 * Function called whenever a peer is disconnected on the "SERVER"
3375 * level. Cleans up the connection, decrements number of active
3376 * connections and if applicable resumes listening.
3377 *
3378 * @param cls closure
3379 * @param client identification of the client
3380 */
3381static void
3382disconnect_notify (void *cls, struct GNUNET_SERVER_Client *client)
3383{
3384 struct Plugin *plugin = cls;
3385 struct GNUNET_ATS_Session *session;
3386
3387 if (NULL == client)
3388 return;
3389 GNUNET_assert (plugin->cur_connections >= 1);
3390 plugin->cur_connections--;
3391 session = lookup_session_by_client (plugin, client);
3392 if (NULL == session)
3393 return; /* unknown, nothing to do */
3394 LOG (GNUNET_ERROR_TYPE_DEBUG,
3395 "Destroying session of `%s' with %s due to network-level disconnect.\n",
3396 GNUNET_i2s (&session->target),
3397 tcp_plugin_address_to_string (session->plugin,
3398 session->address->address,
3399 session->address->address_length));
3400
3401 if (plugin->cur_connections == plugin->max_connections)
3402 {
3403 GNUNET_STATISTICS_update (session->plugin->env->stats,
3404 gettext_noop ("# TCP service resumed"),
3405 1,
3406 GNUNET_NO);
3407 GNUNET_SERVER_resume (plugin->server); /* Resume server */
3408 }
3409 GNUNET_STATISTICS_set (plugin->env->stats,
3410 gettext_noop ("# TCP server connections active"),
3411 plugin->cur_connections,
3412 GNUNET_NO);
3413 GNUNET_STATISTICS_update (session->plugin->env->stats,
3414 gettext_noop (
3415 "# network-level TCP disconnect events"),
3416 1,
3417 GNUNET_NO);
3418 tcp_plugin_disconnect_session (plugin, session);
3419}
3420
3421
3422/**
3423 * We can now send a probe message, copy into buffer to really send.
3424 *
3425 * @param cls closure, a `struct TCPProbeContext`
3426 * @param size max size to copy
3427 * @param buf buffer to copy message to
3428 * @return number of bytes copied into @a buf
3429 */
3430static size_t
3431notify_send_probe (void *cls, size_t size, void *buf)
3432{
3433 struct TCPProbeContext *tcp_probe_ctx = cls;
3434 struct Plugin *plugin = tcp_probe_ctx->plugin;
3435 size_t ret;
3436
3437 tcp_probe_ctx->transmit_handle = NULL;
3438 GNUNET_CONTAINER_DLL_remove (plugin->probe_head,
3439 plugin->probe_tail,
3440 tcp_probe_ctx);
3441 if (NULL == buf)
3442 {
3443 GNUNET_CONNECTION_destroy (tcp_probe_ctx->sock);
3444 GNUNET_free (tcp_probe_ctx);
3445 return 0;
3446 }
3447 GNUNET_assert (size >= sizeof(tcp_probe_ctx->message));
3448 GNUNET_memcpy (buf, &tcp_probe_ctx->message, sizeof(tcp_probe_ctx->message));
3449 GNUNET_SERVER_connect_socket (tcp_probe_ctx->plugin->server,
3450 tcp_probe_ctx->sock);
3451 ret = sizeof(tcp_probe_ctx->message);
3452 GNUNET_free (tcp_probe_ctx);
3453 return ret;
3454}
3455
3456
3457/**
3458 * Function called by the NAT subsystem suggesting another peer wants
3459 * to connect to us via connection reversal. Try to connect back to the
3460 * given IP.
3461 *
3462 * @param cls closure
3463 * @param addr address to try
3464 * @param addrlen number of bytes in @a addr
3465 */
3466static void
3467try_connection_reversal (void *cls,
3468 const struct sockaddr *addr,
3469 socklen_t addrlen)
3470{
3471 struct Plugin *plugin = cls;
3472 struct GNUNET_CONNECTION_Handle *sock;
3473 struct TCPProbeContext *tcp_probe_ctx;
3474
3475 /**
3476 * We have received an ICMP response, ostensibly from a peer
3477 * that wants to connect to us! Send a message to establish a connection.
3478 */
3479 sock = GNUNET_CONNECTION_create_from_sockaddr (AF_INET, addr, addrlen);
3480 if (NULL == sock)
3481 {
3482 /* failed for some odd reason (out of sockets?); ignore attempt */
3483 return;
3484 }
3485
3486 tcp_probe_ctx = GNUNET_new (struct TCPProbeContext);
3487 tcp_probe_ctx->message.header.size =
3488 htons (sizeof(struct TCP_NAT_ProbeMessage));
3489 tcp_probe_ctx->message.header.type =
3490 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE);
3491 tcp_probe_ctx->message.clientIdentity = *plugin->env->my_identity;
3492 tcp_probe_ctx->plugin = plugin;
3493 tcp_probe_ctx->sock = sock;
3494 GNUNET_CONTAINER_DLL_insert (plugin->probe_head,
3495 plugin->probe_tail,
3496 tcp_probe_ctx);
3497 tcp_probe_ctx->transmit_handle =
3498 GNUNET_CONNECTION_notify_transmit_ready (sock,
3499 ntohs (tcp_probe_ctx->message
3500 .header.size),
3501 GNUNET_TIME_UNIT_FOREVER_REL,
3502 &notify_send_probe,
3503 tcp_probe_ctx);
3504}
3505
3506
3507/**
3508 * Function obtain the network type for a session
3509 *
3510 * @param cls closure (`struct Plugin *`)
3511 * @param session the session
3512 * @return the network type in HBO or #GNUNET_SYSERR
3513 */
3514static enum GNUNET_NetworkType
3515tcp_plugin_get_network (void *cls, struct GNUNET_ATS_Session *session)
3516{
3517 return session->scope;
3518}
3519
3520
3521/**
3522 * Function obtain the network type for an address.
3523 *
3524 * @param cls closure (`struct Plugin *`)
3525 * @param address the address
3526 * @return the network type
3527 */
3528static enum GNUNET_NetworkType
3529tcp_plugin_get_network_for_address (void *cls,
3530 const struct GNUNET_HELLO_Address *address)
3531{
3532 struct Plugin *plugin = cls;
3533 size_t addrlen;
3534 struct sockaddr_in a4;
3535 struct sockaddr_in6 a6;
3536 const struct IPv4TcpAddress *t4;
3537 const struct IPv6TcpAddress *t6;
3538 const void *sb;
3539 size_t sbs;
3540
3541 addrlen = address->address_length;
3542 if (addrlen == sizeof(struct IPv6TcpAddress))
3543 {
3544 GNUNET_assert (NULL != address->address); /* make static analysis happy */
3545 t6 = address->address;
3546 memset (&a6, 0, sizeof(a6));
3547#if HAVE_SOCKADDR_IN_SIN_LEN
3548 a6.sin6_len = sizeof(a6);
3549#endif
3550 a6.sin6_family = AF_INET6;
3551 a6.sin6_port = t6->t6_port;
3552 GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr));
3553 sb = &a6;
3554 sbs = sizeof(a6);
3555 }
3556 else if (addrlen == sizeof(struct IPv4TcpAddress))
3557 {
3558 GNUNET_assert (NULL != address->address); /* make static analysis happy */
3559 t4 = address->address;
3560 memset (&a4, 0, sizeof(a4));
3561#if HAVE_SOCKADDR_IN_SIN_LEN
3562 a4.sin_len = sizeof(a4);
3563#endif
3564 a4.sin_family = AF_INET;
3565 a4.sin_port = t4->t4_port;
3566 a4.sin_addr.s_addr = t4->ipv4_addr;
3567 sb = &a4;
3568 sbs = sizeof(a4);
3569 }
3570 else
3571 {
3572 GNUNET_break (0);
3573 return GNUNET_NT_UNSPECIFIED;
3574 }
3575 return plugin->env->get_address_type (plugin->env->cls, sb, sbs);
3576}
3577
3578
3579/**
3580 * Return information about the given session to the
3581 * monitor callback.
3582 *
3583 * @param cls the `struct Plugin` with the monitor callback (`sic`)
3584 * @param peer peer we send information about
3585 * @param value our `struct GNUNET_ATS_Session` to send information about
3586 * @return #GNUNET_OK (continue to iterate)
3587 */
3588static int
3589send_session_info_iter (void *cls,
3590 const struct GNUNET_PeerIdentity *peer,
3591 void *value)
3592{
3593 struct Plugin *plugin = cls;
3594 struct GNUNET_ATS_Session *session = value;
3595
3596 notify_session_monitor (plugin, session, GNUNET_TRANSPORT_SS_INIT);
3597 /* FIXME: cannot tell if this is up or not from current
3598 session state... */
3599 notify_session_monitor (plugin, session, GNUNET_TRANSPORT_SS_UP);
3600 return GNUNET_OK;
3601}
3602
3603
3604/**
3605 * Begin monitoring sessions of a plugin. There can only
3606 * be one active monitor per plugin (i.e. if there are
3607 * multiple monitors, the transport service needs to
3608 * multiplex the generated events over all of them).
3609 *
3610 * @param cls closure of the plugin
3611 * @param sic callback to invoke, NULL to disable monitor;
3612 * plugin will being by iterating over all active
3613 * sessions immediately and then enter monitor mode
3614 * @param sic_cls closure for @a sic
3615 */
3616static void
3617tcp_plugin_setup_monitor (void *cls,
3618 GNUNET_TRANSPORT_SessionInfoCallback sic,
3619 void *sic_cls)
3620{
3621 struct Plugin *plugin = cls;
3622
3623 plugin->sic = sic;
3624 plugin->sic_cls = sic_cls;
3625 if (NULL != sic)
3626 {
3627 GNUNET_CONTAINER_multipeermap_iterate (plugin->sessionmap,
3628 &send_session_info_iter,
3629 plugin);
3630 /* signal end of first iteration */
3631 sic (sic_cls, NULL, NULL);
3632 }
3633}
3634
3635
3636/**
3637 * Entry point for the plugin.
3638 *
3639 * @param cls closure, the `struct GNUNET_TRANSPORT_PluginEnvironment *`
3640 * @return the `struct GNUNET_TRANSPORT_PluginFunctions *` or NULL on error
3641 */
3642void *
3643libgnunet_plugin_transport_tcp_init (void *cls)
3644{
3645 static const struct GNUNET_SERVER_MessageHandler my_handlers[] =
3646 { { &handle_tcp_welcome,
3647 NULL,
3648 GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME,
3649 sizeof(struct WelcomeMessage) },
3650 { &handle_tcp_nat_probe,
3651 NULL,
3652 GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE,
3653 sizeof(struct TCP_NAT_ProbeMessage) },
3654 { &handle_tcp_data, NULL, GNUNET_MESSAGE_TYPE_ALL, 0 },
3655 { NULL, NULL, 0, 0 } };
3656 struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
3657 struct GNUNET_TRANSPORT_PluginFunctions *api;
3658 struct Plugin *plugin;
3659 struct LEGACY_SERVICE_Context *service;
3660 unsigned long long aport;
3661 unsigned long long bport;
3662 unsigned long long max_connections;
3663 unsigned int i;
3664 struct GNUNET_TIME_Relative idle_timeout;
3665
3666#ifdef TCP_STEALTH
3667 struct GNUNET_NETWORK_Handle *const *lsocks;
3668#endif
3669 int ret;
3670 int ret_s;
3671 struct sockaddr **addrs;
3672 socklen_t *addrlens;
3673
3674 if (NULL == env->receive)
3675 {
3676 /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully
3677 initialize the plugin or the API */
3678 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
3679 api->cls = NULL;
3680 api->address_pretty_printer = &tcp_plugin_address_pretty_printer;
3681 api->address_to_string = &tcp_plugin_address_to_string;
3682 api->string_to_address = &tcp_plugin_string_to_address;
3683 return api;
3684 }
3685
3686 GNUNET_assert (NULL != env->cfg);
3687 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (env->cfg,
3688 "transport-tcp",
3689 "MAX_CONNECTIONS",
3690 &max_connections))
3691 max_connections = 128;
3692
3693 aport = 0;
3694 if ((GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (env->cfg,
3695 "transport-tcp",
3696 "PORT",
3697 &bport)) ||
3698 (bport > 65535) ||
3699 ((GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (env->cfg,
3700 "transport-tcp",
3701 "ADVERTISED-PORT",
3702 &aport)) &&
3703 (aport > 65535)))
3704 {
3705 LOG (GNUNET_ERROR_TYPE_ERROR,
3706 _ ("Require valid port number for service `%s' in configuration!\n"),
3707 "transport-tcp");
3708 return NULL;
3709 }
3710 if (0 == aport)
3711 aport = bport;
3712 if (0 == bport)
3713 aport = 0;
3714 if (0 != bport)
3715 {
3716 service = LEGACY_SERVICE_start ("transport-tcp",
3717 env->cfg,
3718 LEGACY_SERVICE_OPTION_NONE);
3719 if (NULL == service)
3720 {
3721 LOG (GNUNET_ERROR_TYPE_WARNING, _ ("Failed to start service.\n"));
3722 return NULL;
3723 }
3724 }
3725 else
3726 service = NULL;
3727
3728 api = NULL;
3729 plugin = GNUNET_new (struct Plugin);
3730 plugin->sessionmap =
3731 GNUNET_CONTAINER_multipeermap_create (max_connections, GNUNET_YES);
3732 plugin->max_connections = max_connections;
3733 plugin->open_port = bport;
3734 plugin->adv_port = aport;
3735 plugin->env = env;
3736 plugin->my_welcome.header.size = htons (sizeof(struct WelcomeMessage));
3737 plugin->my_welcome.header.type =
3738 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME);
3739 plugin->my_welcome.clientIdentity = *plugin->env->my_identity;
3740
3741 if ((NULL != service) &&
3742 (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
3743 "transport-tcp",
3744 "TCP_STEALTH")))
3745 {
3746#ifdef TCP_STEALTH
3747 plugin->myoptions |= TCP_OPTIONS_TCP_STEALTH;
3748 lsocks = LEGACY_SERVICE_get_listen_sockets (service);
3749 if (NULL != lsocks)
3750 {
3751 uint32_t len = sizeof(struct WelcomeMessage);
3752
3753 for (i = 0; NULL != lsocks[i]; i++)
3754 {
3755 if (
3756 (GNUNET_OK !=
3757 GNUNET_NETWORK_socket_setsockopt (lsocks[i],
3758 IPPROTO_TCP,
3759 TCP_STEALTH,
3760 env->my_identity,
3761 sizeof(
3762 struct GNUNET_PeerIdentity))) ||
3763 (GNUNET_OK !=
3764 GNUNET_NETWORK_socket_setsockopt (lsocks[i],
3765 IPPROTO_TCP,
3766 TCP_STEALTH_INTEGRITY_LEN,
3767 &len,
3768 sizeof(len))))
3769 {
3770 /* TCP STEALTH not supported by kernel */
3771 GNUNET_assert (0 == i);
3772 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3773 _ ("TCP_STEALTH not supported on this platform.\n"));
3774 goto die;
3775 }
3776 }
3777 }
3778#else
3779 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3780 _ ("TCP_STEALTH not supported on this platform.\n"));
3781 goto die;
3782#endif
3783 }
3784
3785 if ((NULL != service) &&
3786 (GNUNET_SYSERR !=
3787 (ret_s =
3788 get_server_addresses ("transport-tcp", env->cfg, &addrs, &addrlens))))
3789 {
3790 for (ret = ret_s - 1; ret >= 0; ret--)
3791 LOG (GNUNET_ERROR_TYPE_INFO,
3792 "Binding to address `%s'\n",
3793 GNUNET_a2s (addrs[ret], addrlens[ret]));
3794 plugin->nat = GNUNET_NAT_register (env->cfg,
3795 "transport-tcp",
3796 IPPROTO_TCP,
3797 (unsigned int) ret_s,
3798 (const struct sockaddr **) addrs,
3799 addrlens,
3800 &tcp_nat_port_map_callback,
3801 &try_connection_reversal,
3802 plugin);
3803 for (ret = ret_s - 1; ret >= 0; ret--)
3804 GNUNET_free (addrs[ret]);
3805 GNUNET_free (addrs);
3806 GNUNET_free (addrlens);
3807 }
3808 else
3809 {
3810 plugin->nat = GNUNET_NAT_register (plugin->env->cfg,
3811 "transport-tcp",
3812 IPPROTO_TCP,
3813 0,
3814 NULL,
3815 NULL,
3816 NULL,
3817 &try_connection_reversal,
3818 plugin);
3819 }
3820 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
3821 api->cls = plugin;
3822 api->send = &tcp_plugin_send;
3823 api->get_session = &tcp_plugin_get_session;
3824 api->disconnect_session = &tcp_plugin_disconnect_session;
3825 api->query_keepalive_factor = &tcp_plugin_query_keepalive_factor;
3826 api->disconnect_peer = &tcp_plugin_disconnect;
3827 api->address_pretty_printer = &tcp_plugin_address_pretty_printer;
3828 api->check_address = &tcp_plugin_check_address;
3829 api->address_to_string = &tcp_plugin_address_to_string;
3830 api->string_to_address = &tcp_plugin_string_to_address;
3831 api->get_network = &tcp_plugin_get_network;
3832 api->get_network_for_address = &tcp_plugin_get_network_for_address;
3833 api->update_session_timeout = &tcp_plugin_update_session_timeout;
3834 api->update_inbound_delay = &tcp_plugin_update_inbound_delay;
3835 api->setup_monitor = &tcp_plugin_setup_monitor;
3836 plugin->service = service;
3837 if (NULL != service)
3838 {
3839 plugin->server = LEGACY_SERVICE_get_server (service);
3840 }
3841 else
3842 {
3843 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (env->cfg,
3844 "transport-tcp",
3845 "TIMEOUT",
3846 &idle_timeout))
3847 {
3848 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
3849 "transport-tcp",
3850 "TIMEOUT");
3851 goto die;
3852 }
3853 plugin->server = GNUNET_SERVER_create_with_sockets (NULL,
3854 plugin,
3855 NULL,
3856 idle_timeout,
3857 GNUNET_YES);
3858 }
3859 plugin->handlers = GNUNET_malloc (sizeof(my_handlers));
3860 GNUNET_memcpy (plugin->handlers, my_handlers, sizeof(my_handlers));
3861 for (i = 0;
3862 i < sizeof(my_handlers) / sizeof(struct GNUNET_SERVER_MessageHandler);
3863 i++)
3864 plugin->handlers[i].callback_cls = plugin;
3865
3866 GNUNET_SERVER_add_handlers (plugin->server, plugin->handlers);
3867 GNUNET_SERVER_connect_notify (plugin->server, &connect_notify, plugin);
3868 GNUNET_SERVER_disconnect_notify (plugin->server, &disconnect_notify, plugin);
3869 plugin->nat_wait_conns =
3870 GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
3871 if (0 != bport)
3872 LOG (GNUNET_ERROR_TYPE_INFO,
3873 _ ("TCP transport listening on port %llu\n"),
3874 bport);
3875 else
3876 LOG (GNUNET_ERROR_TYPE_INFO,
3877 _ ("TCP transport not listening on any port (client only)\n"));
3878 if ((aport != bport) && (0 != bport))
3879 LOG (GNUNET_ERROR_TYPE_INFO,
3880 _ ("TCP transport advertises itself as being on port %llu\n"),
3881 aport);
3882 /* Initially set connections to 0 */
3883 GNUNET_STATISTICS_set (plugin->env->stats,
3884 gettext_noop ("# TCP sessions active"),
3885 0,
3886 GNUNET_NO);
3887 return api;
3888
3889die:
3890 if (NULL != plugin->nat)
3891 GNUNET_NAT_unregister (plugin->nat);
3892 GNUNET_CONTAINER_multipeermap_destroy (plugin->sessionmap);
3893 if (NULL != service)
3894 LEGACY_SERVICE_stop (service);
3895 GNUNET_free (plugin);
3896 GNUNET_free (api);
3897 return NULL;
3898}
3899
3900
3901/**
3902 * Exit point from the plugin.
3903 *
3904 * @param cls the `struct GNUNET_TRANSPORT_PluginFunctions`
3905 * @return NULL
3906 */
3907void *
3908libgnunet_plugin_transport_tcp_done (void *cls)
3909{
3910 struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
3911 struct Plugin *plugin = api->cls;
3912 struct TCPProbeContext *tcp_probe;
3913 struct PrettyPrinterContext *cur;
3914 struct PrettyPrinterContext *next;
3915
3916 if (NULL == plugin)
3917 {
3918 GNUNET_free (api);
3919 return NULL;
3920 }
3921 LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down TCP plugin\n");
3922
3923 /* Removing leftover sessions */
3924 GNUNET_CONTAINER_multipeermap_iterate (plugin->sessionmap,
3925 &session_disconnect_it,
3926 plugin);
3927 /* Removing leftover NAT sessions */
3928 GNUNET_CONTAINER_multipeermap_iterate (plugin->nat_wait_conns,
3929 &session_disconnect_it,
3930 plugin);
3931
3932 for (cur = plugin->ppc_dll_head; NULL != cur; cur = next)
3933 {
3934 next = cur->next;
3935 GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head,
3936 plugin->ppc_dll_tail,
3937 cur);
3938 GNUNET_RESOLVER_request_cancel (cur->resolver_handle);
3939 cur->asc (cur->asc_cls, NULL, GNUNET_OK);
3940 GNUNET_free (cur);
3941 }
3942
3943 if (NULL != plugin->service)
3944 LEGACY_SERVICE_stop (plugin->service);
3945 else
3946 GNUNET_SERVER_destroy (plugin->server);
3947 GNUNET_free (plugin->handlers);
3948 if (NULL != plugin->nat)
3949 GNUNET_NAT_unregister (plugin->nat);
3950 while (NULL != (tcp_probe = plugin->probe_head))
3951 {
3952 GNUNET_CONTAINER_DLL_remove (plugin->probe_head,
3953 plugin->probe_tail,
3954 tcp_probe);
3955 GNUNET_CONNECTION_destroy (tcp_probe->sock);
3956 GNUNET_free (tcp_probe);
3957 }
3958 GNUNET_CONTAINER_multipeermap_destroy (plugin->nat_wait_conns);
3959 GNUNET_CONTAINER_multipeermap_destroy (plugin->sessionmap);
3960 GNUNET_break (0 == plugin->cur_connections);
3961 GNUNET_free (plugin);
3962 GNUNET_free (api);
3963 return NULL;
3964}
3965
3966
3967/* end of plugin_transport_tcp.c */
diff --git a/src/transport/plugin_transport_template.c b/src/transport/plugin_transport_template.c
deleted file mode 100644
index c39c72178..000000000
--- a/src/transport/plugin_transport_template.c
+++ /dev/null
@@ -1,565 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2002-2014 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/plugin_transport_template.c
23 * @brief template for a new transport service
24 * @author Christian Grothoff
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_protocols.h"
30#include "gnunet_statistics_service.h"
31#include "gnunet_transport_service.h"
32#include "gnunet_transport_plugin.h"
33
34#define LOG(kind, ...) GNUNET_log_from (kind, "transport-template", __VA_ARGS__)
35
36/**
37 * After how long do we expire an address that we
38 * learned from another peer if it is not reconfirmed
39 * by anyone?
40 */
41#define LEARNED_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply ( \
42 GNUNET_TIME_UNIT_HOURS, 6)
43
44#define PLUGIN_NAME "template"
45
46/**
47 * Encapsulation of all of the state of the plugin.
48 */
49struct Plugin;
50
51
52/**
53 * Session handle for connections.
54 */
55struct GNUNET_ATS_Session
56{
57 /**
58 * To whom are we talking to (set to our identity
59 * if we are still waiting for the welcome message)
60 */
61 struct GNUNET_PeerIdentity sender;
62
63 /**
64 * Stored in a linked list (or a peer map, or ...)
65 */
66 struct GNUNET_ATS_Session *next;
67
68 /**
69 * Pointer to the global plugin struct.
70 */
71 struct Plugin *plugin;
72
73 /**
74 * The client (used to identify this connection)
75 */
76 /* void *client; */
77
78 /**
79 * Continuation function to call once the transmission buffer
80 * has again space available. NULL if there is no
81 * continuation to call.
82 */
83 GNUNET_TRANSPORT_TransmitContinuation transmit_cont;
84
85 /**
86 * Closure for @e transmit_cont.
87 */
88 void *transmit_cont_cls;
89
90 /**
91 * At what time did we reset @e last_received last?
92 */
93 struct GNUNET_TIME_Absolute last_quota_update;
94
95 /**
96 * How many bytes have we received since the @e last_quota_update
97 * timestamp?
98 */
99 uint64_t last_received;
100
101 /**
102 * Number of bytes per ms that this peer is allowed
103 * to send to us.
104 */
105 uint32_t quota;
106};
107
108GNUNET_NETWORK_STRUCT_BEGIN
109
110struct TemplateAddress
111{
112 /**
113 * Address options in NBO
114 */
115 uint32_t options GNUNET_PACKED;
116
117 /* Add address here */
118};
119
120GNUNET_NETWORK_STRUCT_END
121
122/**
123 * Encapsulation of all of the state of the plugin.
124 */
125struct Plugin
126{
127 /**
128 * Our environment.
129 */
130 struct GNUNET_TRANSPORT_PluginEnvironment *env;
131
132 /**
133 * List of open sessions (or peer map, or...)
134 */
135 struct GNUNET_ATS_Session *sessions;
136
137 /**
138 * Function to call about session status changes.
139 */
140 GNUNET_TRANSPORT_SessionInfoCallback sic;
141
142 /**
143 * Closure for @e sic.
144 */
145 void *sic_cls;
146
147 /**
148 * Options in HBO to be used with addresses
149 */
150};
151
152
153#if 0
154/**
155 * If a session monitor is attached, notify it about the new
156 * session state.
157 *
158 * @param plugin our plugin
159 * @param session session that changed state
160 * @param state new state of the session
161 */
162static void
163notify_session_monitor (struct Plugin *plugin,
164 struct GNUNET_ATS_Session *session,
165 enum GNUNET_TRANSPORT_SessionState state)
166{
167 struct GNUNET_TRANSPORT_SessionInfo info;
168
169 if (NULL == plugin->sic)
170 return;
171 memset (&info, 0, sizeof(info));
172 info.state = state;
173 info.is_inbound = GNUNET_SYSERR; /* FIXME */
174 // info.num_msg_pending =
175 // info.num_bytes_pending =
176 // info.receive_delay =
177 // info.session_timeout = session->timeout;
178 // info.address = session->address;
179 plugin->sic (plugin->sic_cls,
180 session,
181 &info);
182}
183
184
185#endif
186
187
188/**
189 * Function that can be used by the transport service to transmit
190 * a message using the plugin. Note that in the case of a
191 * peer disconnecting, the continuation MUST be called
192 * prior to the disconnect notification itself. This function
193 * will be called with this peer's HELLO message to initiate
194 * a fresh connection to another peer.
195 *
196 * @param cls closure
197 * @param session which session must be used
198 * @param msgbuf the message to transmit
199 * @param msgbuf_size number of bytes in @a msgbuf
200 * @param priority how important is the message (most plugins will
201 * ignore message priority and just FIFO)
202 * @param to how long to wait at most for the transmission (does not
203 * require plugins to discard the message after the timeout,
204 * just advisory for the desired delay; most plugins will ignore
205 * this as well)
206 * @param cont continuation to call once the message has
207 * been transmitted (or if the transport is ready
208 * for the next transmission call; or if the
209 * peer disconnected...); can be NULL
210 * @param cont_cls closure for @a cont
211 * @return number of bytes used (on the physical network, with overheads);
212 * -1 on hard errors (i.e. address invalid); 0 is a legal value
213 * and does NOT mean that the message was not transmitted (DV)
214 */
215static ssize_t
216template_plugin_send (void *cls,
217 struct GNUNET_ATS_Session *session,
218 const char *msgbuf,
219 size_t msgbuf_size,
220 unsigned int priority,
221 struct GNUNET_TIME_Relative to,
222 GNUNET_TRANSPORT_TransmitContinuation cont,
223 void *cont_cls)
224{
225 /* struct Plugin *plugin = cls; */
226 ssize_t bytes_sent = 0;
227
228 return bytes_sent;
229}
230
231
232/**
233 * Function that can be used to force the plugin to disconnect
234 * from the given peer and cancel all previous transmissions
235 * (and their continuationc).
236 *
237 * @param cls closure
238 * @param target peer from which to disconnect
239 */
240static void
241template_plugin_disconnect_peer (void *cls,
242 const struct GNUNET_PeerIdentity *target)
243{
244 // struct Plugin *plugin = cls;
245 // FIXME
246}
247
248
249/**
250 * Function that can be used to force the plugin to disconnect
251 * from the given peer and cancel all previous transmissions
252 * (and their continuationc).
253 *
254 * @param cls closure
255 * @param session session from which to disconnect
256 * @return #GNUNET_OK on success
257 */
258static int
259template_plugin_disconnect_session (void *cls,
260 struct GNUNET_ATS_Session *session)
261{
262 // struct Plugin *plugin = cls;
263 // FIXME
264 return GNUNET_SYSERR;
265}
266
267
268/**
269 * Function that is called to get the keepalive factor.
270 * GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT is divided by this number to
271 * calculate the interval between keepalive packets.
272 *
273 * @param cls closure with the `struct Plugin`
274 * @return keepalive factor
275 */
276static unsigned int
277template_plugin_query_keepalive_factor (void *cls)
278{
279 return 3;
280}
281
282
283/**
284 * Function obtain the network type for a session
285 *
286 * @param cls closure ('struct Plugin*')
287 * @param session the session
288 * @return the network type in HBO or #GNUNET_SYSERR
289 */
290static enum GNUNET_NetworkType
291template_plugin_get_network (void *cls,
292 struct GNUNET_ATS_Session *session)
293{
294 GNUNET_assert (NULL != session);
295 return GNUNET_NT_UNSPECIFIED; /* Change to correct network type */
296}
297
298
299/**
300 * Function obtain the network type for an address.
301 *
302 * @param cls closure (`struct Plugin *`)
303 * @param address the address
304 * @return the network type
305 */
306static enum GNUNET_NetworkType
307template_plugin_get_network_for_address (void *cls,
308 const struct
309 GNUNET_HELLO_Address *address)
310{
311 return GNUNET_NT_WAN; /* FOR NOW */
312}
313
314
315/**
316 * Convert the transports address to a nice, human-readable
317 * format.
318 *
319 * @param cls closure
320 * @param type name of the transport that generated the address
321 * @param addr one of the addresses of the host, NULL for the last address
322 * the specific address format depends on the transport
323 * @param addrlen length of the address
324 * @param numeric should (IP) addresses be displayed in numeric form?
325 * @param timeout after how long should we give up?
326 * @param asc function to call on each string
327 * @param asc_cls closure for @a asc
328 */
329static void
330template_plugin_address_pretty_printer (void *cls, const char *type,
331 const void *addr, size_t addrlen,
332 int numeric,
333 struct GNUNET_TIME_Relative timeout,
334 GNUNET_TRANSPORT_AddressStringCallback
335 asc, void *asc_cls)
336{
337 asc (asc_cls, "converted address", GNUNET_OK); /* return address */
338 asc (asc_cls, NULL, GNUNET_OK); /* done */
339}
340
341
342/**
343 * Another peer has suggested an address for this
344 * peer and transport plugin. Check that this could be a valid
345 * address. If so, consider adding it to the list
346 * of addresses.
347 *
348 * @param cls closure
349 * @param addr pointer to the address
350 * @param addrlen length of addr
351 * @return #GNUNET_OK if this is a plausible address for this peer
352 * and transport
353 */
354static int
355template_plugin_address_suggested (void *cls, const void *addr, size_t addrlen)
356{
357 /* struct Plugin *plugin = cls; */
358
359 /* check if the address is belonging to the plugin*/
360 return GNUNET_OK;
361}
362
363
364/**
365 * Function called for a quick conversion of the binary address to
366 * a numeric address. Note that the caller must not free the
367 * address and that the next call to this function is allowed
368 * to override the address again.
369 *
370 * @param cls closure
371 * @param addr binary address
372 * @param addrlen length of the address
373 * @return string representing the same address
374 */
375static const char *
376template_plugin_address_to_string (void *cls, const void *addr, size_t addrlen)
377{
378 /*
379 * Print address in format template.options.address
380 */
381
382 if (0 == addrlen)
383 {
384 return TRANSPORT_SESSION_INBOUND_STRING;
385 }
386
387 GNUNET_break (0);
388 return NULL;
389}
390
391
392/**
393 * Function called to convert a string address to
394 * a binary address.
395 *
396 * @param cls closure ('struct Plugin*')
397 * @param addr string address
398 * @param addrlen length of the @a addr
399 * @param buf location to store the buffer
400 * @param added location to store the number of bytes in the buffer.
401 * If the function returns #GNUNET_SYSERR, its contents are undefined.
402 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
403 */
404static int
405template_plugin_string_to_address (void *cls,
406 const char *addr,
407 uint16_t addrlen,
408 void **buf, size_t *added)
409{
410 /*
411 * Parse string in format template.options.address
412 */
413 GNUNET_break (0);
414 return GNUNET_SYSERR;
415}
416
417
418/**
419 * Create a new session to transmit data to the target
420 * This session will used to send data to this peer and the plugin will
421 * notify us by calling the env->session_end function
422 *
423 * @param cls closure
424 * @param address pointer to the GNUNET_HELLO_Address
425 * @return the session if the address is valid, NULL otherwise
426 */
427static struct GNUNET_ATS_Session *
428template_plugin_get_session (void *cls,
429 const struct GNUNET_HELLO_Address *address)
430{
431 GNUNET_break (0);
432 return NULL;
433}
434
435
436static void
437template_plugin_update_session_timeout (void *cls,
438 const struct GNUNET_PeerIdentity *peer,
439 struct GNUNET_ATS_Session *session)
440{
441}
442
443
444#if 0
445/**
446 * Return information about the given session to the
447 * monitor callback.
448 *
449 * @param cls the `struct Plugin` with the monitor callback (`sic`)
450 * @param peer peer we send information about
451 * @param value our `struct GNUNET_ATS_Session` to send information about
452 * @return #GNUNET_OK (continue to iterate)
453 */
454static int
455send_session_info_iter (void *cls,
456 const struct GNUNET_PeerIdentity *peer,
457 void *value)
458{
459 struct Plugin *plugin = cls;
460 struct GNUNET_ATS_Session *session = value;
461
462 notify_session_monitor (plugin,
463 session,
464 GNUNET_TRANSPORT_SS_UP);
465 return GNUNET_OK;
466}
467
468
469#endif
470
471
472/**
473 * Begin monitoring sessions of a plugin. There can only
474 * be one active monitor per plugin (i.e. if there are
475 * multiple monitors, the transport service needs to
476 * multiplex the generated events over all of them).
477 *
478 * @param cls closure of the plugin
479 * @param sic callback to invoke, NULL to disable monitor;
480 * plugin will being by iterating over all active
481 * sessions immediately and then enter monitor mode
482 * @param sic_cls closure for @a sic
483 */
484static void
485template_plugin_setup_monitor (void *cls,
486 GNUNET_TRANSPORT_SessionInfoCallback sic,
487 void *sic_cls)
488{
489 struct Plugin *plugin = cls;
490
491 plugin->sic = sic;
492 plugin->sic_cls = sic_cls;
493 if (NULL != sic)
494 {
495#if 0
496 GNUNET_CONTAINER_multipeermap_iterate (NULL /* FIXME */,
497 &send_session_info_iter,
498 plugin);
499#endif
500 /* signal end of first iteration */
501 sic (sic_cls, NULL, NULL);
502 }
503}
504
505
506/**
507 * Entry point for the plugin.
508 */
509void *
510libgnunet_plugin_transport_template_init (void *cls)
511{
512 struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
513 struct GNUNET_TRANSPORT_PluginFunctions *api;
514 struct Plugin *plugin;
515
516 if (NULL == env->receive)
517 {
518 /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully
519 initialize the plugin or the API */
520 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
521 api->cls = NULL;
522 api->address_to_string = &template_plugin_address_to_string;
523 api->string_to_address = &template_plugin_string_to_address;
524 api->address_pretty_printer = &template_plugin_address_pretty_printer;
525 return api;
526 }
527
528 plugin = GNUNET_new (struct Plugin);
529 plugin->env = env;
530 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
531 api->cls = plugin;
532 api->send = &template_plugin_send;
533 api->disconnect_peer = &template_plugin_disconnect_peer;
534 api->disconnect_session = &template_plugin_disconnect_session;
535 api->query_keepalive_factor = &template_plugin_query_keepalive_factor;
536 api->address_pretty_printer = &template_plugin_address_pretty_printer;
537 api->check_address = &template_plugin_address_suggested;
538 api->address_to_string = &template_plugin_address_to_string;
539 api->string_to_address = &template_plugin_string_to_address;
540 api->get_session = &template_plugin_get_session;
541 api->get_network = &template_plugin_get_network;
542 api->get_network_for_address = &template_plugin_get_network_for_address;
543 api->update_session_timeout = &template_plugin_update_session_timeout;
544 api->setup_monitor = &template_plugin_setup_monitor;
545 LOG (GNUNET_ERROR_TYPE_INFO, "Template plugin successfully loaded\n");
546 return api;
547}
548
549
550/**
551 * Exit point from the plugin.
552 */
553void *
554libgnunet_plugin_transport_template_done (void *cls)
555{
556 struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
557 struct Plugin *plugin = api->cls;
558
559 GNUNET_free (plugin);
560 GNUNET_free (api);
561 return NULL;
562}
563
564
565/* end of plugin_transport_template.c */
diff --git a/src/transport/plugin_transport_udp.c b/src/transport/plugin_transport_udp.c
deleted file mode 100644
index 0d3ca449d..000000000
--- a/src/transport/plugin_transport_udp.c
+++ /dev/null
@@ -1,3897 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2010-2017 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/plugin_transport_udp.c
23 * @brief Implementation of the UDP transport protocol
24 * @author Christian Grothoff
25 * @author Nathan Evans
26 * @author Matthias Wachs
27 */
28#include "platform.h"
29#include "plugin_transport_udp.h"
30#include "gnunet_hello_lib.h"
31#include "gnunet_util_lib.h"
32#include "gnunet_fragmentation_lib.h"
33#include "gnunet_nat_service.h"
34#include "gnunet_protocols.h"
35#include "gnunet_resolver_service.h"
36#include "gnunet_signatures.h"
37#include "gnunet_constants.h"
38#include "gnunet_statistics_service.h"
39#include "gnunet_transport_service.h"
40#include "gnunet_transport_plugin.h"
41#include "transport.h"
42
43#define LOG(kind, ...) GNUNET_log_from (kind, "transport-udp", __VA_ARGS__)
44
45/**
46 * After how much inactivity should a UDP session time out?
47 */
48#define UDP_SESSION_TIME_OUT \
49 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
50
51/**
52 * Number of messages we can defragment in parallel. We only really
53 * defragment 1 message at a time, but if messages get re-ordered, we
54 * may want to keep knowledge about the previous message to avoid
55 * discarding the current message in favor of a single fragment of a
56 * previous message. 3 should be good since we don't expect massive
57 * message reorderings with UDP.
58 */
59#define UDP_MAX_MESSAGES_IN_DEFRAG 3
60
61/**
62 * We keep a defragmentation queue per sender address. How many
63 * sender addresses do we support at the same time? Memory consumption
64 * is roughly a factor of 32k * #UDP_MAX_MESSAGES_IN_DEFRAG times this
65 * value. (So 128 corresponds to 12 MB and should suffice for
66 * connecting to roughly 128 peers via UDP).
67 */
68#define UDP_MAX_SENDER_ADDRESSES_WITH_DEFRAG 128
69
70
71/**
72 * UDP Message-Packet header (after defragmentation).
73 */
74struct UDPMessage
75{
76 /**
77 * Message header.
78 */
79 struct GNUNET_MessageHeader header;
80
81 /**
82 * Always zero for now.
83 */
84 uint32_t reserved;
85
86 /**
87 * What is the identity of the sender
88 */
89 struct GNUNET_PeerIdentity sender;
90};
91
92
93/**
94 * Closure for #append_port().
95 */
96struct PrettyPrinterContext
97{
98 /**
99 * DLL
100 */
101 struct PrettyPrinterContext *next;
102
103 /**
104 * DLL
105 */
106 struct PrettyPrinterContext *prev;
107
108 /**
109 * Our plugin.
110 */
111 struct Plugin *plugin;
112
113 /**
114 * Resolver handle
115 */
116 struct GNUNET_RESOLVER_RequestHandle *resolver_handle;
117
118 /**
119 * Function to call with the result.
120 */
121 GNUNET_TRANSPORT_AddressStringCallback asc;
122
123 /**
124 * Clsoure for @e asc.
125 */
126 void *asc_cls;
127
128 /**
129 * Timeout task
130 */
131 struct GNUNET_SCHEDULER_Task *timeout_task;
132
133 /**
134 * Is this an IPv6 address?
135 */
136 int ipv6;
137
138 /**
139 * Options
140 */
141 uint32_t options;
142
143 /**
144 * Port to add after the IP address.
145 */
146 uint16_t port;
147};
148
149
150/**
151 * Session with another peer.
152 */
153struct GNUNET_ATS_Session
154{
155 /**
156 * Which peer is this session for?
157 */
158 struct GNUNET_PeerIdentity target;
159
160 /**
161 * Tokenizer for inbound messages.
162 */
163 struct GNUNET_MessageStreamTokenizer *mst;
164
165 /**
166 * Plugin this session belongs to.
167 */
168 struct Plugin *plugin;
169
170 /**
171 * Context for dealing with fragments.
172 */
173 struct UDP_FragmentationContext *frag_ctx;
174
175 /**
176 * Desired delay for next sending we send to other peer
177 */
178 struct GNUNET_TIME_Relative flow_delay_for_other_peer;
179
180 /**
181 * Desired delay for transmissions we received from other peer.
182 * This is for full messages, the value needs to be adjusted for
183 * fragmented messages.
184 */
185 struct GNUNET_TIME_Relative flow_delay_from_other_peer;
186
187 /**
188 * Session timeout task
189 */
190 struct GNUNET_SCHEDULER_Task *timeout_task;
191
192 /**
193 * When does this session time out?
194 */
195 struct GNUNET_TIME_Absolute timeout;
196
197 /**
198 * What time did we last transmit?
199 */
200 struct GNUNET_TIME_Absolute last_transmit_time;
201
202 /**
203 * expected delay for ACKs
204 */
205 struct GNUNET_TIME_Relative last_expected_ack_delay;
206
207 /**
208 * desired delay between UDP messages
209 */
210 struct GNUNET_TIME_Relative last_expected_msg_delay;
211
212 /**
213 * Our own address.
214 */
215 struct GNUNET_HELLO_Address *address;
216
217 /**
218 * Number of bytes waiting for transmission to this peer.
219 */
220 unsigned long long bytes_in_queue;
221
222 /**
223 * Number of messages waiting for transmission to this peer.
224 */
225 unsigned int msgs_in_queue;
226
227 /**
228 * Reference counter to indicate that this session is
229 * currently being used and must not be destroyed;
230 * setting @e in_destroy will destroy it as soon as
231 * possible.
232 */
233 unsigned int rc;
234
235 /**
236 * Network type of the address.
237 */
238 enum GNUNET_NetworkType scope;
239
240 /**
241 * Is this session about to be destroyed (sometimes we cannot
242 * destroy a session immediately as below us on the stack
243 * there might be code that still uses it; in this case,
244 * @e rc is non-zero).
245 */
246 int in_destroy;
247};
248
249
250/**
251 * Data structure to track defragmentation contexts based
252 * on the source of the UDP traffic.
253 */
254struct DefragContext
255{
256 /**
257 * Defragmentation context.
258 */
259 struct GNUNET_DEFRAGMENT_Context *defrag;
260
261 /**
262 * Reference to master plugin struct.
263 */
264 struct Plugin *plugin;
265
266 /**
267 * Node in the defrag heap.
268 */
269 struct GNUNET_CONTAINER_HeapNode *hnode;
270
271 /**
272 * Source address this receive context is for (allocated at the
273 * end of the struct).
274 */
275 const union UdpAddress *udp_addr;
276
277 /**
278 * Who's message(s) are we defragmenting here?
279 * Only initialized once we succeeded and
280 * @e have_sender is set.
281 */
282 struct GNUNET_PeerIdentity sender;
283
284 /**
285 * Length of @e udp_addr.
286 */
287 size_t udp_addr_len;
288
289 /**
290 * Network type the address belongs to.
291 */
292 enum GNUNET_NetworkType network_type;
293
294 /**
295 * Has the @e sender field been initialized yet?
296 */
297 int have_sender;
298};
299
300
301/**
302 * Context to send fragmented messages
303 */
304struct UDP_FragmentationContext
305{
306 /**
307 * Next in linked list
308 */
309 struct UDP_FragmentationContext *next;
310
311 /**
312 * Previous in linked list
313 */
314 struct UDP_FragmentationContext *prev;
315
316 /**
317 * The plugin
318 */
319 struct Plugin *plugin;
320
321 /**
322 * Handle for fragmentation.
323 */
324 struct GNUNET_FRAGMENT_Context *frag;
325
326 /**
327 * The session this fragmentation context belongs to
328 */
329 struct GNUNET_ATS_Session *session;
330
331 /**
332 * Function to call upon completion of the transmission.
333 */
334 GNUNET_TRANSPORT_TransmitContinuation cont;
335
336 /**
337 * Closure for @e cont.
338 */
339 void *cont_cls;
340
341 /**
342 * Start time.
343 */
344 struct GNUNET_TIME_Absolute start_time;
345
346 /**
347 * Transmission time for the next fragment. Incremented by
348 * the @e flow_delay_from_other_peer for each fragment when
349 * we setup the fragments.
350 */
351 struct GNUNET_TIME_Absolute next_frag_time;
352
353 /**
354 * Desired delay for transmissions we received from other peer.
355 * Adjusted to be per fragment (UDP_MTU), even though on the
356 * wire it was for "full messages".
357 */
358 struct GNUNET_TIME_Relative flow_delay_from_other_peer;
359
360 /**
361 * Message timeout
362 */
363 struct GNUNET_TIME_Absolute timeout;
364
365 /**
366 * Payload size of original unfragmented message
367 */
368 size_t payload_size;
369
370 /**
371 * Bytes used to send all fragments on wire including UDP overhead
372 */
373 size_t on_wire_size;
374};
375
376
377/**
378 * Function called when a message is removed from the
379 * transmission queue.
380 *
381 * @param cls closure
382 * @param udpw message wrapper finished
383 * @param result #GNUNET_OK on success (message was sent)
384 * #GNUNET_SYSERR if the target disconnected
385 * or we had a timeout or other trouble sending
386 */
387typedef void (*QueueContinuation) (void *cls,
388 struct UDP_MessageWrapper *udpw,
389 int result);
390
391
392/**
393 * Information we track for each message in the queue.
394 */
395struct UDP_MessageWrapper
396{
397 /**
398 * Session this message belongs to
399 */
400 struct GNUNET_ATS_Session *session;
401
402 /**
403 * DLL of messages, previous element
404 */
405 struct UDP_MessageWrapper *prev;
406
407 /**
408 * DLL of messages, next element
409 */
410 struct UDP_MessageWrapper *next;
411
412 /**
413 * Message with @e msg_size bytes including UDP-specific overhead.
414 */
415 char *msg_buf;
416
417 /**
418 * Function to call once the message wrapper is being removed
419 * from the queue (with success or failure).
420 */
421 QueueContinuation qc;
422
423 /**
424 * Closure for @e qc.
425 */
426 void *qc_cls;
427
428 /**
429 * External continuation to call upon completion of the
430 * transmission, NULL if this queue entry is not for a
431 * message from the application.
432 */
433 GNUNET_TRANSPORT_TransmitContinuation cont;
434
435 /**
436 * Closure for @e cont.
437 */
438 void *cont_cls;
439
440 /**
441 * Fragmentation context.
442 * frag_ctx == NULL if transport <= MTU
443 * frag_ctx != NULL if transport > MTU
444 */
445 struct UDP_FragmentationContext *frag_ctx;
446
447 /**
448 * Message enqueue time.
449 */
450 struct GNUNET_TIME_Absolute start_time;
451
452 /**
453 * Desired transmission time for this message, based on the
454 * flow limiting information we got from the other peer.
455 */
456 struct GNUNET_TIME_Absolute transmission_time;
457
458 /**
459 * Message timeout.
460 */
461 struct GNUNET_TIME_Absolute timeout;
462
463 /**
464 * Size of UDP message to send, including UDP-specific overhead.
465 */
466 size_t msg_size;
467
468 /**
469 * Payload size of original message.
470 */
471 size_t payload_size;
472};
473
474
475GNUNET_NETWORK_STRUCT_BEGIN
476
477/**
478 * UDP ACK Message-Packet header.
479 */
480struct UDP_ACK_Message
481{
482 /**
483 * Message header.
484 */
485 struct GNUNET_MessageHeader header;
486
487 /**
488 * Desired delay for flow control, in us (in NBO).
489 * A value of UINT32_MAX indicates that the other
490 * peer wants us to disconnect.
491 */
492 uint32_t delay GNUNET_PACKED;
493
494 /**
495 * What is the identity of the sender
496 */
497 struct GNUNET_PeerIdentity sender;
498};
499
500GNUNET_NETWORK_STRUCT_END
501
502
503/* ************************* Monitoring *********** */
504
505
506/**
507 * If a session monitor is attached, notify it about the new
508 * session state.
509 *
510 * @param plugin our plugin
511 * @param session session that changed state
512 * @param state new state of the session
513 */
514static void
515notify_session_monitor (struct Plugin *plugin,
516 struct GNUNET_ATS_Session *session,
517 enum GNUNET_TRANSPORT_SessionState state)
518{
519 struct GNUNET_TRANSPORT_SessionInfo info;
520
521 if (NULL == plugin->sic)
522 return;
523 if (GNUNET_YES == session->in_destroy)
524 return; /* already destroyed, just RC>0 left-over actions */
525 memset (&info, 0, sizeof(info));
526 info.state = state;
527 info.is_inbound = GNUNET_SYSERR; /* hard to say */
528 info.num_msg_pending = session->msgs_in_queue;
529 info.num_bytes_pending = session->bytes_in_queue;
530 /* info.receive_delay remains zero as this is not supported by UDP
531 (cannot selectively not receive from 'some' peer while continuing
532 to receive from others) */
533 info.session_timeout = session->timeout;
534 info.address = session->address;
535 plugin->sic (plugin->sic_cls, session, &info);
536}
537
538
539/**
540 * Return information about the given session to the monitor callback.
541 *
542 * @param cls the `struct Plugin` with the monitor callback (`sic`)
543 * @param peer peer we send information about
544 * @param value our `struct GNUNET_ATS_Session` to send information about
545 * @return #GNUNET_OK (continue to iterate)
546 */
547static int
548send_session_info_iter (void *cls,
549 const struct GNUNET_PeerIdentity *peer,
550 void *value)
551{
552 struct Plugin *plugin = cls;
553 struct GNUNET_ATS_Session *session = value;
554
555 notify_session_monitor (plugin, session, GNUNET_TRANSPORT_SS_INIT);
556 notify_session_monitor (plugin, session, GNUNET_TRANSPORT_SS_UP);
557 return GNUNET_OK;
558}
559
560
561/**
562 * Begin monitoring sessions of a plugin. There can only
563 * be one active monitor per plugin (i.e. if there are
564 * multiple monitors, the transport service needs to
565 * multiplex the generated events over all of them).
566 *
567 * @param cls closure of the plugin
568 * @param sic callback to invoke, NULL to disable monitor;
569 * plugin will being by iterating over all active
570 * sessions immediately and then enter monitor mode
571 * @param sic_cls closure for @a sic
572 */
573static void
574udp_plugin_setup_monitor (void *cls,
575 GNUNET_TRANSPORT_SessionInfoCallback sic,
576 void *sic_cls)
577{
578 struct Plugin *plugin = cls;
579
580 plugin->sic = sic;
581 plugin->sic_cls = sic_cls;
582 if (NULL != sic)
583 {
584 GNUNET_CONTAINER_multipeermap_iterate (plugin->sessions,
585 &send_session_info_iter,
586 plugin);
587 /* signal end of first iteration */
588 sic (sic_cls, NULL, NULL);
589 }
590}
591
592
593/* ****************** Little Helpers ****************** */
594
595
596/**
597 * Function to free last resources associated with a session.
598 *
599 * @param s session to free
600 */
601static void
602free_session (struct GNUNET_ATS_Session *s)
603{
604 if (NULL != s->address)
605 {
606 GNUNET_HELLO_address_free (s->address);
607 s->address = NULL;
608 }
609 if (NULL != s->frag_ctx)
610 {
611 GNUNET_FRAGMENT_context_destroy (s->frag_ctx->frag, NULL, NULL);
612 GNUNET_free (s->frag_ctx);
613 s->frag_ctx = NULL;
614 }
615 if (NULL != s->mst)
616 {
617 GNUNET_MST_destroy (s->mst);
618 s->mst = NULL;
619 }
620 GNUNET_free (s);
621}
622
623
624/**
625 * Function that is called to get the keepalive factor.
626 * #GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT is divided by this number to
627 * calculate the interval between keepalive packets.
628 *
629 * @param cls closure with the `struct Plugin`
630 * @return keepalive factor
631 */
632static unsigned int
633udp_query_keepalive_factor (void *cls)
634{
635 return 15;
636}
637
638
639/**
640 * Function obtain the network type for a session
641 *
642 * @param cls closure (`struct Plugin *`)
643 * @param session the session
644 * @return the network type
645 */
646static enum GNUNET_NetworkType
647udp_plugin_get_network (void *cls, struct GNUNET_ATS_Session *session)
648{
649 return session->scope;
650}
651
652
653/**
654 * Function obtain the network type for an address.
655 *
656 * @param cls closure (`struct Plugin *`)
657 * @param address the address
658 * @return the network type
659 */
660static enum GNUNET_NetworkType
661udp_plugin_get_network_for_address (void *cls,
662 const struct GNUNET_HELLO_Address *address)
663{
664 struct Plugin *plugin = cls;
665 size_t addrlen;
666 struct sockaddr_in a4;
667 struct sockaddr_in6 a6;
668 const struct IPv4UdpAddress *u4;
669 const struct IPv6UdpAddress *u6;
670 const void *sb;
671 size_t sbs;
672
673 addrlen = address->address_length;
674 if (addrlen == sizeof(struct IPv6UdpAddress))
675 {
676 GNUNET_assert (NULL != address->address); /* make static analysis happy */
677 u6 = address->address;
678 memset (&a6, 0, sizeof(a6));
679#if HAVE_SOCKADDR_IN_SIN_LEN
680 a6.sin6_len = sizeof(a6);
681#endif
682 a6.sin6_family = AF_INET6;
683 a6.sin6_port = u6->u6_port;
684 GNUNET_memcpy (&a6.sin6_addr, &u6->ipv6_addr, sizeof(struct in6_addr));
685 sb = &a6;
686 sbs = sizeof(a6);
687 }
688 else if (addrlen == sizeof(struct IPv4UdpAddress))
689 {
690 GNUNET_assert (NULL != address->address); /* make static analysis happy */
691 u4 = address->address;
692 memset (&a4, 0, sizeof(a4));
693#if HAVE_SOCKADDR_IN_SIN_LEN
694 a4.sin_len = sizeof(a4);
695#endif
696 a4.sin_family = AF_INET;
697 a4.sin_port = u4->u4_port;
698 a4.sin_addr.s_addr = u4->ipv4_addr;
699 sb = &a4;
700 sbs = sizeof(a4);
701 }
702 else
703 {
704 GNUNET_break (0);
705 return GNUNET_NT_UNSPECIFIED;
706 }
707 return plugin->env->get_address_type (plugin->env->cls, sb, sbs);
708}
709
710
711/* ******************* Event loop ******************** */
712
713/**
714 * We have been notified that our readset has something to read. We don't
715 * know which socket needs to be read, so we have to check each one
716 * Then reschedule this function to be called again once more is available.
717 *
718 * @param cls the plugin handle
719 */
720static void
721udp_plugin_select_v4 (void *cls);
722
723
724/**
725 * We have been notified that our readset has something to read. We don't
726 * know which socket needs to be read, so we have to check each one
727 * Then reschedule this function to be called again once more is available.
728 *
729 * @param cls the plugin handle
730 */
731static void
732udp_plugin_select_v6 (void *cls);
733
734
735/**
736 * (re)schedule IPv4-select tasks for this plugin.
737 *
738 * @param plugin plugin to reschedule
739 */
740static void
741schedule_select_v4 (struct Plugin *plugin)
742{
743 struct GNUNET_TIME_Relative min_delay;
744 struct GNUNET_TIME_Relative delay;
745 struct UDP_MessageWrapper *udpw;
746 struct UDP_MessageWrapper *min_udpw;
747
748 if ((GNUNET_YES == plugin->enable_ipv4) && (NULL != plugin->sockv4))
749 {
750 /* Find a message ready to send:
751 * Flow delay from other peer is expired or not set (0) */
752 min_delay = GNUNET_TIME_UNIT_FOREVER_REL;
753 min_udpw = NULL;
754 for (udpw = plugin->ipv4_queue_head; NULL != udpw; udpw = udpw->next)
755 {
756 delay = GNUNET_TIME_absolute_get_remaining (udpw->transmission_time);
757 if (delay.rel_value_us < min_delay.rel_value_us)
758 {
759 min_delay = delay;
760 min_udpw = udpw;
761 }
762 }
763 if (NULL != plugin->select_task_v4)
764 GNUNET_SCHEDULER_cancel (plugin->select_task_v4);
765 if (NULL != min_udpw)
766 {
767 if (min_delay.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
768 {
769 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
770 "Calculated flow delay for UDPv4 at %s for %s\n",
771 GNUNET_STRINGS_relative_time_to_string (min_delay,
772 GNUNET_YES),
773 GNUNET_i2s (&min_udpw->session->target));
774 }
775 else
776 {
777 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
778 "Calculated flow delay for UDPv4 at %s for %s\n",
779 GNUNET_STRINGS_relative_time_to_string (min_delay,
780 GNUNET_YES),
781 GNUNET_i2s (&min_udpw->session->target));
782 }
783 }
784 plugin->select_task_v4 =
785 GNUNET_SCHEDULER_add_read_net (min_delay,
786 plugin->sockv4,
787 &udp_plugin_select_v4,
788 plugin);
789 }
790}
791
792
793/**
794 * (re)schedule IPv6-select tasks for this plugin.
795 *
796 * @param plugin plugin to reschedule
797 */
798static void
799schedule_select_v6 (struct Plugin *plugin)
800{
801 struct GNUNET_TIME_Relative min_delay;
802 struct GNUNET_TIME_Relative delay;
803 struct UDP_MessageWrapper *udpw;
804 struct UDP_MessageWrapper *min_udpw;
805
806 if ((GNUNET_YES == plugin->enable_ipv6) && (NULL != plugin->sockv6))
807 {
808 min_delay = GNUNET_TIME_UNIT_FOREVER_REL;
809 min_udpw = NULL;
810 for (udpw = plugin->ipv6_queue_head; NULL != udpw; udpw = udpw->next)
811 {
812 delay = GNUNET_TIME_absolute_get_remaining (udpw->transmission_time);
813 if (delay.rel_value_us < min_delay.rel_value_us)
814 {
815 min_delay = delay;
816 min_udpw = udpw;
817 }
818 }
819 if (NULL != plugin->select_task_v6)
820 GNUNET_SCHEDULER_cancel (plugin->select_task_v6);
821 if (NULL != min_udpw)
822 {
823 if (min_delay.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
824 {
825 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
826 "Calculated flow delay for UDPv6 at %s for %s\n",
827 GNUNET_STRINGS_relative_time_to_string (min_delay,
828 GNUNET_YES),
829 GNUNET_i2s (&min_udpw->session->target));
830 }
831 else
832 {
833 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
834 "Calculated flow delay for UDPv6 at %s for %s\n",
835 GNUNET_STRINGS_relative_time_to_string (min_delay,
836 GNUNET_YES),
837 GNUNET_i2s (&min_udpw->session->target));
838 }
839 }
840 plugin->select_task_v6 =
841 GNUNET_SCHEDULER_add_read_net (min_delay,
842 plugin->sockv6,
843 &udp_plugin_select_v6,
844 plugin);
845 }
846}
847
848
849/* ******************* Address to string and back ***************** */
850
851
852/**
853 * Function called for a quick conversion of the binary address to
854 * a numeric address. Note that the caller must not free the
855 * address and that the next call to this function is allowed
856 * to override the address again.
857 *
858 * @param cls closure
859 * @param addr binary address (a `union UdpAddress`)
860 * @param addrlen length of the @a addr
861 * @return string representing the same address
862 */
863const char *
864udp_address_to_string (void *cls, const void *addr, size_t addrlen)
865{
866 static char rbuf[INET6_ADDRSTRLEN + 10];
867 char buf[INET6_ADDRSTRLEN];
868 const void *sb;
869 struct in_addr a4;
870 struct in6_addr a6;
871 const struct IPv4UdpAddress *t4;
872 const struct IPv6UdpAddress *t6;
873 int af;
874 uint16_t port;
875 uint32_t options;
876
877 if (NULL == addr)
878 {
879 GNUNET_break_op (0);
880 return NULL;
881 }
882
883 if (addrlen == sizeof(struct IPv6UdpAddress))
884 {
885 t6 = addr;
886 af = AF_INET6;
887 options = ntohl (t6->options);
888 port = ntohs (t6->u6_port);
889 a6 = t6->ipv6_addr;
890 sb = &a6;
891 }
892 else if (addrlen == sizeof(struct IPv4UdpAddress))
893 {
894 t4 = addr;
895 af = AF_INET;
896 options = ntohl (t4->options);
897 port = ntohs (t4->u4_port);
898 a4.s_addr = t4->ipv4_addr;
899 sb = &a4;
900 }
901 else
902 {
903 GNUNET_break_op (0);
904 return NULL;
905 }
906 inet_ntop (af, sb, buf, INET6_ADDRSTRLEN);
907 GNUNET_snprintf (rbuf,
908 sizeof(rbuf),
909 (af == AF_INET6) ? "%s.%u.[%s]:%u" : "%s.%u.%s:%u",
910 PLUGIN_NAME,
911 options,
912 buf,
913 port);
914 return rbuf;
915}
916
917
918/**
919 * Function called to convert a string address to a binary address.
920 *
921 * @param cls closure (`struct Plugin *`)
922 * @param addr string address
923 * @param addrlen length of the address
924 * @param buf location to store the buffer
925 * @param added location to store the number of bytes in the buffer.
926 * If the function returns #GNUNET_SYSERR, its contents are undefined.
927 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
928 */
929static int
930udp_string_to_address (void *cls,
931 const char *addr,
932 uint16_t addrlen,
933 void **buf,
934 size_t *added)
935{
936 struct sockaddr_storage socket_address;
937 char *address;
938 char *plugin;
939 char *optionstr;
940 uint32_t options;
941
942 /* Format tcp.options.address:port */
943 address = NULL;
944 plugin = NULL;
945 optionstr = NULL;
946
947 if ((NULL == addr) || (0 == addrlen))
948 {
949 GNUNET_break (0);
950 return GNUNET_SYSERR;
951 }
952 if ('\0' != addr[addrlen - 1])
953 {
954 GNUNET_break (0);
955 return GNUNET_SYSERR;
956 }
957 if (strlen (addr) != addrlen - 1)
958 {
959 GNUNET_break (0);
960 return GNUNET_SYSERR;
961 }
962 plugin = GNUNET_strdup (addr);
963 optionstr = strchr (plugin, '.');
964 if (NULL == optionstr)
965 {
966 GNUNET_break (0);
967 GNUNET_free (plugin);
968 return GNUNET_SYSERR;
969 }
970 optionstr[0] = '\0';
971 optionstr++;
972 options = atol (optionstr);
973 address = strchr (optionstr, '.');
974 if (NULL == address)
975 {
976 GNUNET_break (0);
977 GNUNET_free (plugin);
978 return GNUNET_SYSERR;
979 }
980 address[0] = '\0';
981 address++;
982
983 if (GNUNET_OK !=
984 GNUNET_STRINGS_to_address_ip (address, strlen (address), &socket_address))
985 {
986 GNUNET_break (0);
987 GNUNET_free (plugin);
988 return GNUNET_SYSERR;
989 }
990 GNUNET_free (plugin);
991
992 switch (socket_address.ss_family)
993 {
994 case AF_INET: {
995 struct IPv4UdpAddress *u4;
996 const struct sockaddr_in *in4 =
997 (const struct sockaddr_in *) &socket_address;
998
999 u4 = GNUNET_new (struct IPv4UdpAddress);
1000 u4->options = htonl (options);
1001 u4->ipv4_addr = in4->sin_addr.s_addr;
1002 u4->u4_port = in4->sin_port;
1003 *buf = u4;
1004 *added = sizeof(struct IPv4UdpAddress);
1005 return GNUNET_OK;
1006 }
1007
1008 case AF_INET6: {
1009 struct IPv6UdpAddress *u6;
1010 const struct sockaddr_in6 *in6 =
1011 (const struct sockaddr_in6 *) &socket_address;
1012
1013 u6 = GNUNET_new (struct IPv6UdpAddress);
1014 u6->options = htonl (options);
1015 u6->ipv6_addr = in6->sin6_addr;
1016 u6->u6_port = in6->sin6_port;
1017 *buf = u6;
1018 *added = sizeof(struct IPv6UdpAddress);
1019 return GNUNET_OK;
1020 }
1021
1022 default:
1023 GNUNET_break (0);
1024 return GNUNET_SYSERR;
1025 }
1026}
1027
1028
1029/**
1030 * Append our port and forward the result.
1031 *
1032 * @param cls a `struct PrettyPrinterContext *`
1033 * @param hostname result from DNS resolver
1034 */
1035static void
1036append_port (void *cls, const char *hostname)
1037{
1038 struct PrettyPrinterContext *ppc = cls;
1039 struct Plugin *plugin = ppc->plugin;
1040 char *ret;
1041
1042 if (NULL == hostname)
1043 {
1044 /* Final call, done */
1045 GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head,
1046 plugin->ppc_dll_tail,
1047 ppc);
1048 ppc->resolver_handle = NULL;
1049 ppc->asc (ppc->asc_cls, NULL, GNUNET_OK);
1050 GNUNET_free (ppc);
1051 return;
1052 }
1053 if (GNUNET_YES == ppc->ipv6)
1054 GNUNET_asprintf (&ret,
1055 "%s.%u.[%s]:%d",
1056 PLUGIN_NAME,
1057 ppc->options,
1058 hostname,
1059 ppc->port);
1060 else
1061 GNUNET_asprintf (&ret,
1062 "%s.%u.%s:%d",
1063 PLUGIN_NAME,
1064 ppc->options,
1065 hostname,
1066 ppc->port);
1067 ppc->asc (ppc->asc_cls, ret, GNUNET_OK);
1068 GNUNET_free (ret);
1069}
1070
1071
1072/**
1073 * Convert the transports address to a nice, human-readable format.
1074 *
1075 * @param cls closure with the `struct Plugin *`
1076 * @param type name of the transport that generated the address
1077 * @param addr one of the addresses of the host, NULL for the last address
1078 * the specific address format depends on the transport;
1079 * a `union UdpAddress`
1080 * @param addrlen length of the address
1081 * @param numeric should (IP) addresses be displayed in numeric form?
1082 * @param timeout after how long should we give up?
1083 * @param asc function to call on each string
1084 * @param asc_cls closure for @a asc
1085 */
1086static void
1087udp_plugin_address_pretty_printer (void *cls,
1088 const char *type,
1089 const void *addr,
1090 size_t addrlen,
1091 int numeric,
1092 struct GNUNET_TIME_Relative timeout,
1093 GNUNET_TRANSPORT_AddressStringCallback asc,
1094 void *asc_cls)
1095{
1096 struct Plugin *plugin = cls;
1097 struct PrettyPrinterContext *ppc;
1098 const struct sockaddr *sb;
1099 size_t sbs;
1100 struct sockaddr_in a4;
1101 struct sockaddr_in6 a6;
1102 const struct IPv4UdpAddress *u4;
1103 const struct IPv6UdpAddress *u6;
1104 uint16_t port;
1105 uint32_t options;
1106
1107 if (addrlen == sizeof(struct IPv6UdpAddress))
1108 {
1109 u6 = addr;
1110 memset (&a6, 0, sizeof(a6));
1111 a6.sin6_family = AF_INET6;
1112#if HAVE_SOCKADDR_IN_SIN_LEN
1113 a6.sin6_len = sizeof(a6);
1114#endif
1115 a6.sin6_port = u6->u6_port;
1116 a6.sin6_addr = u6->ipv6_addr;
1117 port = ntohs (u6->u6_port);
1118 options = ntohl (u6->options);
1119 sb = (const struct sockaddr *) &a6;
1120 sbs = sizeof(a6);
1121 }
1122 else if (addrlen == sizeof(struct IPv4UdpAddress))
1123 {
1124 u4 = addr;
1125 memset (&a4, 0, sizeof(a4));
1126 a4.sin_family = AF_INET;
1127#if HAVE_SOCKADDR_IN_SIN_LEN
1128 a4.sin_len = sizeof(a4);
1129#endif
1130 a4.sin_port = u4->u4_port;
1131 a4.sin_addr.s_addr = u4->ipv4_addr;
1132 port = ntohs (u4->u4_port);
1133 options = ntohl (u4->options);
1134 sb = (const struct sockaddr *) &a4;
1135 sbs = sizeof(a4);
1136 }
1137 else
1138 {
1139 /* invalid address */
1140 GNUNET_break_op (0);
1141 asc (asc_cls, NULL, GNUNET_SYSERR);
1142 asc (asc_cls, NULL, GNUNET_OK);
1143 return;
1144 }
1145 ppc = GNUNET_new (struct PrettyPrinterContext);
1146 ppc->plugin = plugin;
1147 ppc->asc = asc;
1148 ppc->asc_cls = asc_cls;
1149 ppc->port = port;
1150 ppc->options = options;
1151 if (addrlen == sizeof(struct IPv6UdpAddress))
1152 ppc->ipv6 = GNUNET_YES;
1153 else
1154 ppc->ipv6 = GNUNET_NO;
1155 GNUNET_CONTAINER_DLL_insert (plugin->ppc_dll_head, plugin->ppc_dll_tail, ppc);
1156 ppc->resolver_handle = GNUNET_RESOLVER_hostname_get (sb,
1157 sbs,
1158 ! numeric,
1159 timeout,
1160 &append_port,
1161 ppc);
1162}
1163
1164
1165/**
1166 * Check if the given port is plausible (must be either our listen
1167 * port or our advertised port). If it is neither, we return
1168 * #GNUNET_SYSERR.
1169 *
1170 * @param plugin global variables
1171 * @param in_port port number to check
1172 * @return #GNUNET_OK if port is either our open or advertised port
1173 */
1174static int
1175check_port (const struct Plugin *plugin, uint16_t in_port)
1176{
1177 if ((plugin->port == in_port) || (plugin->aport == in_port))
1178 return GNUNET_OK;
1179 return GNUNET_SYSERR;
1180}
1181
1182
1183/**
1184 * Function that will be called to check if a binary address for this
1185 * plugin is well-formed and corresponds to an address for THIS peer
1186 * (as per our configuration). Naturally, if absolutely necessary,
1187 * plugins can be a bit conservative in their answer, but in general
1188 * plugins should make sure that the address does not redirect
1189 * traffic to a 3rd party that might try to man-in-the-middle our
1190 * traffic.
1191 *
1192 * @param cls closure, should be our handle to the Plugin
1193 * @param addr pointer to a `union UdpAddress`
1194 * @param addrlen length of @a addr
1195 * @return #GNUNET_OK if this is a plausible address for this peer
1196 * and transport, #GNUNET_SYSERR if not
1197 */
1198static int
1199udp_plugin_check_address (void *cls, const void *addr, size_t addrlen)
1200{
1201 struct Plugin *plugin = cls;
1202 const struct IPv4UdpAddress *v4;
1203 const struct IPv6UdpAddress *v6;
1204
1205 if (sizeof(struct IPv4UdpAddress) == addrlen)
1206 {
1207 struct sockaddr_in s4;
1208
1209 v4 = (const struct IPv4UdpAddress *) addr;
1210 if (GNUNET_OK != check_port (plugin, ntohs (v4->u4_port)))
1211 return GNUNET_SYSERR;
1212 memset (&s4, 0, sizeof(s4));
1213 s4.sin_family = AF_INET;
1214#if HAVE_SOCKADDR_IN_SIN_LEN
1215 s4.sin_len = sizeof(s4);
1216#endif
1217 s4.sin_port = v4->u4_port;
1218 s4.sin_addr.s_addr = v4->ipv4_addr;
1219
1220 if (GNUNET_OK !=
1221 GNUNET_NAT_test_address (plugin->nat, &s4, sizeof(struct sockaddr_in)))
1222 return GNUNET_SYSERR;
1223 }
1224 else if (sizeof(struct IPv6UdpAddress) == addrlen)
1225 {
1226 struct sockaddr_in6 s6;
1227
1228 v6 = (const struct IPv6UdpAddress *) addr;
1229 if (IN6_IS_ADDR_LINKLOCAL (&v6->ipv6_addr))
1230 return GNUNET_OK; /* plausible, if unlikely... */
1231 memset (&s6, 0, sizeof(s6));
1232 s6.sin6_family = AF_INET6;
1233#if HAVE_SOCKADDR_IN_SIN_LEN
1234 s6.sin6_len = sizeof(s6);
1235#endif
1236 s6.sin6_port = v6->u6_port;
1237 s6.sin6_addr = v6->ipv6_addr;
1238
1239 if (GNUNET_OK != GNUNET_NAT_test_address (plugin->nat,
1240 &s6,
1241 sizeof(struct sockaddr_in6)))
1242 return GNUNET_SYSERR;
1243 }
1244 else
1245 {
1246 GNUNET_break_op (0);
1247 return GNUNET_SYSERR;
1248 }
1249 return GNUNET_OK;
1250}
1251
1252
1253/**
1254 * Our external IP address/port mapping has changed.
1255 *
1256 * @param cls closure, the `struct Plugin`
1257 * @param[in,out] app_ctx location where the app can store stuff
1258 * on add and retrieve it on remove
1259 * @param add_remove #GNUNET_YES to mean the new public IP address,
1260 * #GNUNET_NO to mean the previous (now invalid) one
1261 * @param ac address class the address belongs to
1262 * @param addr either the previous or the new public IP address
1263 * @param addrlen actual length of the @a addr
1264 */
1265static void
1266udp_nat_port_map_callback (void *cls,
1267 void **app_ctx,
1268 int add_remove,
1269 enum GNUNET_NAT_AddressClass ac,
1270 const struct sockaddr *addr,
1271 socklen_t addrlen)
1272{
1273 struct Plugin *plugin = cls;
1274 struct GNUNET_HELLO_Address *address;
1275 struct IPv4UdpAddress u4;
1276 struct IPv6UdpAddress u6;
1277 void *arg;
1278 size_t args;
1279
1280 (void) app_ctx;
1281 LOG (GNUNET_ERROR_TYPE_DEBUG,
1282 (GNUNET_YES == add_remove) ? "NAT notification to add address `%s'\n"
1283 : "NAT notification to remove address `%s'\n",
1284 GNUNET_a2s (addr, addrlen));
1285 /* convert 'address' to our internal format */
1286 switch (addr->sa_family)
1287 {
1288 case AF_INET: {
1289 const struct sockaddr_in *i4;
1290
1291 GNUNET_assert (sizeof(struct sockaddr_in) == addrlen);
1292 i4 = (const struct sockaddr_in *) addr;
1293 if (0 == ntohs (i4->sin_port))
1294 return; /* Port = 0 means unmapped, ignore these for UDP. */
1295 memset (&u4, 0, sizeof(u4));
1296 u4.options = htonl (plugin->myoptions);
1297 u4.ipv4_addr = i4->sin_addr.s_addr;
1298 u4.u4_port = i4->sin_port;
1299 arg = &u4;
1300 args = sizeof(struct IPv4UdpAddress);
1301 break;
1302 }
1303
1304 case AF_INET6: {
1305 const struct sockaddr_in6 *i6;
1306
1307 GNUNET_assert (sizeof(struct sockaddr_in6) == addrlen);
1308 i6 = (const struct sockaddr_in6 *) addr;
1309 if (0 == ntohs (i6->sin6_port))
1310 return; /* Port = 0 means unmapped, ignore these for UDP. */
1311 memset (&u6, 0, sizeof(u6));
1312 u6.options = htonl (plugin->myoptions);
1313 u6.ipv6_addr = i6->sin6_addr;
1314 u6.u6_port = i6->sin6_port;
1315 arg = &u6;
1316 args = sizeof(struct IPv6UdpAddress);
1317 break;
1318 }
1319
1320 default:
1321 GNUNET_break (0);
1322 return;
1323 }
1324 /* modify our published address list */
1325 /* TODO: use 'ac' here in the future... */
1326 address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
1327 PLUGIN_NAME,
1328 arg,
1329 args,
1330 GNUNET_HELLO_ADDRESS_INFO_NONE);
1331 plugin->env->notify_address (plugin->env->cls, add_remove, address);
1332 GNUNET_HELLO_address_free (address);
1333}
1334
1335
1336/* ********************* Finding sessions ******************* */
1337
1338
1339/**
1340 * Closure for #session_cmp_it().
1341 */
1342struct GNUNET_ATS_SessionCompareContext
1343{
1344 /**
1345 * Set to session matching the address.
1346 */
1347 struct GNUNET_ATS_Session *res;
1348
1349 /**
1350 * Address we are looking for.
1351 */
1352 const struct GNUNET_HELLO_Address *address;
1353};
1354
1355
1356/**
1357 * Find a session with a matching address.
1358 *
1359 * @param cls the `struct GNUNET_ATS_SessionCompareContext *`
1360 * @param key peer identity (unused)
1361 * @param value the `struct GNUNET_ATS_Session *`
1362 * @return #GNUNET_NO if we found the session, #GNUNET_OK if not
1363 */
1364static int
1365session_cmp_it (void *cls, const struct GNUNET_PeerIdentity *key, void *value)
1366{
1367 struct GNUNET_ATS_SessionCompareContext *cctx = cls;
1368 struct GNUNET_ATS_Session *s = value;
1369
1370 if (0 == GNUNET_HELLO_address_cmp (s->address, cctx->address))
1371 {
1372 GNUNET_assert (GNUNET_NO == s->in_destroy);
1373 cctx->res = s;
1374 return GNUNET_NO;
1375 }
1376 return GNUNET_OK;
1377}
1378
1379
1380/**
1381 * Locate an existing session the transport service is using to
1382 * send data to another peer. Performs some basic sanity checks
1383 * on the address and then tries to locate a matching session.
1384 *
1385 * @param cls the plugin
1386 * @param address the address we should locate the session by
1387 * @return the session if it exists, or NULL if it is not found
1388 */
1389static struct GNUNET_ATS_Session *
1390udp_plugin_lookup_session (void *cls,
1391 const struct GNUNET_HELLO_Address *address)
1392{
1393 struct Plugin *plugin = cls;
1394 const struct IPv6UdpAddress *udp_a6;
1395 const struct IPv4UdpAddress *udp_a4;
1396 struct GNUNET_ATS_SessionCompareContext cctx;
1397
1398 if (NULL == address->address)
1399 {
1400 GNUNET_break (0);
1401 return NULL;
1402 }
1403 if (sizeof(struct IPv4UdpAddress) == address->address_length)
1404 {
1405 if (NULL == plugin->sockv4)
1406 return NULL;
1407 udp_a4 = (const struct IPv4UdpAddress *) address->address;
1408 if (0 == udp_a4->u4_port)
1409 {
1410 GNUNET_break (0);
1411 return NULL;
1412 }
1413 }
1414 else if (sizeof(struct IPv6UdpAddress) == address->address_length)
1415 {
1416 if (NULL == plugin->sockv6)
1417 return NULL;
1418 udp_a6 = (const struct IPv6UdpAddress *) address->address;
1419 if (0 == udp_a6->u6_port)
1420 {
1421 GNUNET_break (0);
1422 return NULL;
1423 }
1424 }
1425 else
1426 {
1427 GNUNET_break (0);
1428 return NULL;
1429 }
1430
1431 /* check if session already exists */
1432 cctx.address = address;
1433 cctx.res = NULL;
1434 LOG (GNUNET_ERROR_TYPE_DEBUG,
1435 "Looking for existing session for peer `%s' with address `%s'\n",
1436 GNUNET_i2s (&address->peer),
1437 udp_address_to_string (plugin,
1438 address->address,
1439 address->address_length));
1440 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessions,
1441 &address->peer,
1442 &session_cmp_it,
1443 &cctx);
1444 if (NULL == cctx.res)
1445 return NULL;
1446 LOG (GNUNET_ERROR_TYPE_DEBUG, "Found existing session %p\n", cctx.res);
1447 return cctx.res;
1448}
1449
1450
1451/* ********************** Timeout ****************** */
1452
1453
1454/**
1455 * Increment session timeout due to activity.
1456 *
1457 * @param s session to reschedule timeout activity for
1458 */
1459static void
1460reschedule_session_timeout (struct GNUNET_ATS_Session *s)
1461{
1462 if (GNUNET_YES == s->in_destroy)
1463 return;
1464 GNUNET_assert (NULL != s->timeout_task);
1465 s->timeout = GNUNET_TIME_relative_to_absolute (UDP_SESSION_TIME_OUT);
1466}
1467
1468
1469/**
1470 * Function that will be called whenever the transport service wants to
1471 * notify the plugin that a session is still active and in use and
1472 * therefore the session timeout for this session has to be updated
1473 *
1474 * @param cls closure with the `struct Plugin`
1475 * @param peer which peer was the session for
1476 * @param session which session is being updated
1477 */
1478static void
1479udp_plugin_update_session_timeout (void *cls,
1480 const struct GNUNET_PeerIdentity *peer,
1481 struct GNUNET_ATS_Session *session)
1482{
1483 struct Plugin *plugin = cls;
1484
1485 if (GNUNET_YES !=
1486 GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessions,
1487 peer,
1488 session))
1489 {
1490 GNUNET_break (0);
1491 return;
1492 }
1493 /* Reschedule session timeout */
1494 reschedule_session_timeout (session);
1495}
1496
1497
1498/* ************************* Sending ************************ */
1499
1500
1501/**
1502 * Remove the given message from the transmission queue and
1503 * update all applicable statistics.
1504 *
1505 * @param plugin the UDP plugin
1506 * @param udpw message wrapper to dequeue
1507 */
1508static void
1509dequeue (struct Plugin *plugin, struct UDP_MessageWrapper *udpw)
1510{
1511 struct GNUNET_ATS_Session *session = udpw->session;
1512
1513 if (plugin->bytes_in_buffer < udpw->msg_size)
1514 {
1515 GNUNET_break (0);
1516 }
1517 else
1518 {
1519 GNUNET_STATISTICS_update (plugin->env->stats,
1520 "# UDP, total bytes in send buffers",
1521 -(long long) udpw->msg_size,
1522 GNUNET_NO);
1523 plugin->bytes_in_buffer -= udpw->msg_size;
1524 }
1525 GNUNET_STATISTICS_update (plugin->env->stats,
1526 "# UDP, total messages in send buffers",
1527 -1,
1528 GNUNET_NO);
1529 if (sizeof(struct IPv4UdpAddress) == udpw->session->address->address_length)
1530 {
1531 GNUNET_CONTAINER_DLL_remove (plugin->ipv4_queue_head,
1532 plugin->ipv4_queue_tail,
1533 udpw);
1534 }
1535 else if (sizeof(struct IPv6UdpAddress) ==
1536 udpw->session->address->address_length)
1537 {
1538 GNUNET_CONTAINER_DLL_remove (plugin->ipv6_queue_head,
1539 plugin->ipv6_queue_tail,
1540 udpw);
1541 }
1542 else
1543 {
1544 GNUNET_break (0);
1545 return;
1546 }
1547 GNUNET_assert (session->msgs_in_queue > 0);
1548 session->msgs_in_queue--;
1549 GNUNET_assert (session->bytes_in_queue >= udpw->msg_size);
1550 session->bytes_in_queue -= udpw->msg_size;
1551}
1552
1553
1554/**
1555 * Enqueue a message for transmission and update statistics.
1556 *
1557 * @param plugin the UDP plugin
1558 * @param udpw message wrapper to queue
1559 */
1560static void
1561enqueue (struct Plugin *plugin, struct UDP_MessageWrapper *udpw)
1562{
1563 struct GNUNET_ATS_Session *session = udpw->session;
1564
1565 if (GNUNET_YES == session->in_destroy)
1566 {
1567 GNUNET_break (0);
1568 GNUNET_free (udpw);
1569 return;
1570 }
1571 if (plugin->bytes_in_buffer > INT64_MAX - udpw->msg_size)
1572 {
1573 GNUNET_break (0);
1574 }
1575 else
1576 {
1577 GNUNET_STATISTICS_update (plugin->env->stats,
1578 "# UDP, total bytes in send buffers",
1579 udpw->msg_size,
1580 GNUNET_NO);
1581 plugin->bytes_in_buffer += udpw->msg_size;
1582 }
1583 GNUNET_STATISTICS_update (plugin->env->stats,
1584 "# UDP, total messages in send buffers",
1585 1,
1586 GNUNET_NO);
1587 if (sizeof(struct IPv4UdpAddress) == udpw->session->address->address_length)
1588 {
1589 GNUNET_CONTAINER_DLL_insert (plugin->ipv4_queue_head,
1590 plugin->ipv4_queue_tail,
1591 udpw);
1592 }
1593 else if (sizeof(struct IPv6UdpAddress) ==
1594 udpw->session->address->address_length)
1595 {
1596 GNUNET_CONTAINER_DLL_insert (plugin->ipv6_queue_head,
1597 plugin->ipv6_queue_tail,
1598 udpw);
1599 }
1600 else
1601 {
1602 GNUNET_break (0);
1603 udpw->cont (udpw->cont_cls,
1604 &session->target,
1605 GNUNET_SYSERR,
1606 udpw->msg_size,
1607 0);
1608 GNUNET_free (udpw);
1609 return;
1610 }
1611 session->msgs_in_queue++;
1612 session->bytes_in_queue += udpw->msg_size;
1613}
1614
1615
1616/**
1617 * We have completed our (attempt) to transmit a message that had to
1618 * be fragmented -- either because we got an ACK saying that all
1619 * fragments were received, or because of timeout / disconnect. Clean
1620 * up our state.
1621 *
1622 * @param frag_ctx fragmentation context to clean up
1623 * @param result #GNUNET_OK if we succeeded (got ACK),
1624 * #GNUNET_SYSERR if the transmission failed
1625 */
1626static void
1627fragmented_message_done (struct UDP_FragmentationContext *frag_ctx, int result)
1628{
1629 struct Plugin *plugin = frag_ctx->plugin;
1630 struct GNUNET_ATS_Session *s = frag_ctx->session;
1631 struct UDP_MessageWrapper *udpw;
1632 struct UDP_MessageWrapper *tmp;
1633 size_t overhead;
1634 struct GNUNET_TIME_Relative delay;
1635
1636 LOG (GNUNET_ERROR_TYPE_DEBUG,
1637 "%p: Fragmented message removed with result %s\n",
1638 frag_ctx,
1639 (result == GNUNET_SYSERR) ? "FAIL" : "SUCCESS");
1640 /* Call continuation for fragmented message */
1641 if (frag_ctx->on_wire_size >= frag_ctx->payload_size)
1642 overhead = frag_ctx->on_wire_size - frag_ctx->payload_size;
1643 else
1644 overhead = frag_ctx->on_wire_size;
1645 delay = GNUNET_TIME_absolute_get_duration (frag_ctx->start_time);
1646 if (delay.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
1647 {
1648 LOG (GNUNET_ERROR_TYPE_WARNING,
1649 "Fragmented message acknowledged after %s (expected at %s)\n",
1650 GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES),
1651 GNUNET_STRINGS_absolute_time_to_string (frag_ctx->next_frag_time));
1652 }
1653 else
1654 {
1655 LOG (GNUNET_ERROR_TYPE_DEBUG,
1656 "Fragmented message acknowledged after %s (expected at %s)\n",
1657 GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES),
1658 GNUNET_STRINGS_absolute_time_to_string (frag_ctx->next_frag_time));
1659 }
1660
1661 if (NULL != frag_ctx->cont)
1662 frag_ctx->cont (frag_ctx->cont_cls,
1663 &s->target,
1664 result,
1665 s->frag_ctx->payload_size,
1666 frag_ctx->on_wire_size);
1667 GNUNET_STATISTICS_update (plugin->env->stats,
1668 "# UDP, fragmented messages active",
1669 -1,
1670 GNUNET_NO);
1671
1672 if (GNUNET_OK == result)
1673 {
1674 GNUNET_STATISTICS_update (plugin->env->stats,
1675 "# UDP, fragmented msgs, messages, sent, success",
1676 1,
1677 GNUNET_NO);
1678 GNUNET_STATISTICS_update (plugin->env->stats,
1679 "# UDP, fragmented msgs, bytes payload, sent, success",
1680 s->frag_ctx->payload_size,
1681 GNUNET_NO);
1682 GNUNET_STATISTICS_update (
1683 plugin->env->stats,
1684 "# UDP, fragmented msgs, bytes overhead, sent, success",
1685 overhead,
1686 GNUNET_NO);
1687 GNUNET_STATISTICS_update (plugin->env->stats,
1688 "# UDP, total, bytes overhead, sent",
1689 overhead,
1690 GNUNET_NO);
1691 GNUNET_STATISTICS_update (plugin->env->stats,
1692 "# UDP, total, bytes payload, sent",
1693 s->frag_ctx->payload_size,
1694 GNUNET_NO);
1695 }
1696 else
1697 {
1698 GNUNET_STATISTICS_update (plugin->env->stats,
1699 "# UDP, fragmented msgs, messages, sent, failure",
1700 1,
1701 GNUNET_NO);
1702 GNUNET_STATISTICS_update (plugin->env->stats,
1703 "# UDP, fragmented msgs, bytes payload, sent, failure",
1704 s->frag_ctx->payload_size,
1705 GNUNET_NO);
1706 GNUNET_STATISTICS_update (plugin->env->stats,
1707 "# UDP, fragmented msgs, bytes payload, sent, failure",
1708 overhead,
1709 GNUNET_NO);
1710 GNUNET_STATISTICS_update (plugin->env->stats,
1711 "# UDP, fragmented msgs, bytes payload, sent, failure",
1712 overhead,
1713 GNUNET_NO);
1714 }
1715
1716 /* Remove remaining fragments from queue, no need to transmit those
1717 any longer. */
1718 if (s->address->address_length == sizeof(struct IPv6UdpAddress))
1719 {
1720 udpw = plugin->ipv6_queue_head;
1721 while (NULL != udpw)
1722 {
1723 tmp = udpw->next;
1724 if ((udpw->frag_ctx != NULL) && (udpw->frag_ctx == frag_ctx))
1725 {
1726 dequeue (plugin, udpw);
1727 GNUNET_free (udpw);
1728 }
1729 udpw = tmp;
1730 }
1731 }
1732 if (s->address->address_length == sizeof(struct IPv4UdpAddress))
1733 {
1734 udpw = plugin->ipv4_queue_head;
1735 while (NULL != udpw)
1736 {
1737 tmp = udpw->next;
1738 if ((NULL != udpw->frag_ctx) && (udpw->frag_ctx == frag_ctx))
1739 {
1740 dequeue (plugin, udpw);
1741 GNUNET_free (udpw);
1742 }
1743 udpw = tmp;
1744 }
1745 }
1746 notify_session_monitor (s->plugin, s, GNUNET_TRANSPORT_SS_UPDATE);
1747 GNUNET_FRAGMENT_context_destroy (frag_ctx->frag,
1748 &s->last_expected_msg_delay,
1749 &s->last_expected_ack_delay);
1750 s->frag_ctx = NULL;
1751 GNUNET_free (frag_ctx);
1752}
1753
1754
1755/**
1756 * We are finished with a fragment in the message queue.
1757 * Notify the continuation and update statistics.
1758 *
1759 * @param cls the `struct Plugin *`
1760 * @param udpw the queue entry
1761 * @param result #GNUNET_OK on success, #GNUNET_SYSERR on failure
1762 */
1763static void
1764qc_fragment_sent (void *cls, struct UDP_MessageWrapper *udpw, int result)
1765{
1766 struct Plugin *plugin = cls;
1767
1768 GNUNET_assert (NULL != udpw->frag_ctx);
1769 if (GNUNET_OK == result)
1770 {
1771 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1772 "Fragment of message with %u bytes transmitted to %s\n",
1773 (unsigned int) udpw->payload_size,
1774 GNUNET_i2s (&udpw->session->target));
1775 GNUNET_FRAGMENT_context_transmission_done (udpw->frag_ctx->frag);
1776 GNUNET_STATISTICS_update (plugin->env->stats,
1777 "# UDP, fragmented msgs, fragments, sent, success",
1778 1,
1779 GNUNET_NO);
1780 GNUNET_STATISTICS_update (
1781 plugin->env->stats,
1782 "# UDP, fragmented msgs, fragments bytes, sent, success",
1783 udpw->msg_size,
1784 GNUNET_NO);
1785 }
1786 else
1787 {
1788 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1789 "Failed to transmit fragment of message with %u bytes to %s\n",
1790 (unsigned int) udpw->payload_size,
1791 GNUNET_i2s (&udpw->session->target));
1792 fragmented_message_done (udpw->frag_ctx, GNUNET_SYSERR);
1793 GNUNET_STATISTICS_update (plugin->env->stats,
1794 "# UDP, fragmented msgs, fragments, sent, failure",
1795 1,
1796 GNUNET_NO);
1797 GNUNET_STATISTICS_update (
1798 plugin->env->stats,
1799 "# UDP, fragmented msgs, fragments bytes, sent, failure",
1800 udpw->msg_size,
1801 GNUNET_NO);
1802 }
1803}
1804
1805
1806/**
1807 * Function that is called with messages created by the fragmentation
1808 * module. In the case of the `proc` callback of the
1809 * #GNUNET_FRAGMENT_context_create() function, this function must
1810 * eventually call #GNUNET_FRAGMENT_context_transmission_done().
1811 *
1812 * @param cls closure, the `struct UDP_FragmentationContext`
1813 * @param msg the message that was created
1814 */
1815static void
1816enqueue_fragment (void *cls, const struct GNUNET_MessageHeader *msg)
1817{
1818 struct UDP_FragmentationContext *frag_ctx = cls;
1819 struct Plugin *plugin = frag_ctx->plugin;
1820 struct UDP_MessageWrapper *udpw;
1821 struct GNUNET_ATS_Session *session = frag_ctx->session;
1822 size_t msg_len = ntohs (msg->size);
1823
1824 LOG (GNUNET_ERROR_TYPE_DEBUG, "Enqueuing fragment with %lu bytes\n",
1825 (unsigned long) msg_len);
1826 udpw = GNUNET_malloc (sizeof(struct UDP_MessageWrapper) + msg_len);
1827 udpw->session = session;
1828 udpw->msg_buf = (char *) &udpw[1];
1829 udpw->msg_size = msg_len;
1830 udpw->payload_size = msg_len; /* FIXME: minus fragment overhead */
1831 udpw->timeout = frag_ctx->timeout;
1832 udpw->start_time = frag_ctx->start_time;
1833 udpw->transmission_time = frag_ctx->next_frag_time;
1834 frag_ctx->next_frag_time =
1835 GNUNET_TIME_absolute_add (frag_ctx->next_frag_time,
1836 frag_ctx->flow_delay_from_other_peer);
1837 udpw->frag_ctx = frag_ctx;
1838 udpw->qc = &qc_fragment_sent;
1839 udpw->qc_cls = plugin;
1840 GNUNET_memcpy (udpw->msg_buf, msg, msg_len);
1841 enqueue (plugin, udpw);
1842 if (session->address->address_length == sizeof(struct IPv4UdpAddress))
1843 schedule_select_v4 (plugin);
1844 else
1845 schedule_select_v6 (plugin);
1846}
1847
1848
1849/**
1850 * We are finished with a message from the message queue.
1851 * Notify the continuation and update statistics.
1852 *
1853 * @param cls the `struct Plugin *`
1854 * @param udpw the queue entry
1855 * @param result #GNUNET_OK on success, #GNUNET_SYSERR on failure
1856 */
1857static void
1858qc_message_sent (void *cls, struct UDP_MessageWrapper *udpw, int result)
1859{
1860 struct Plugin *plugin = cls;
1861 size_t overhead;
1862 struct GNUNET_TIME_Relative delay;
1863
1864 if (udpw->msg_size >= udpw->payload_size)
1865 overhead = udpw->msg_size - udpw->payload_size;
1866 else
1867 overhead = udpw->msg_size;
1868
1869 if (NULL != udpw->cont)
1870 {
1871 delay = GNUNET_TIME_absolute_get_duration (udpw->start_time);
1872 if (delay.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
1873 {
1874 LOG (GNUNET_ERROR_TYPE_WARNING,
1875 "Message sent via UDP with delay of %s\n",
1876 GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
1877 }
1878 else
1879 {
1880 LOG (GNUNET_ERROR_TYPE_DEBUG,
1881 "Message sent via UDP with delay of %s\n",
1882 GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
1883 }
1884 udpw->cont (udpw->cont_cls,
1885 &udpw->session->target,
1886 result,
1887 udpw->payload_size,
1888 overhead);
1889 }
1890 if (GNUNET_OK == result)
1891 {
1892 GNUNET_STATISTICS_update (plugin->env->stats,
1893 "# UDP, unfragmented msgs, messages, sent, success",
1894 1,
1895 GNUNET_NO);
1896 GNUNET_STATISTICS_update (
1897 plugin->env->stats,
1898 "# UDP, unfragmented msgs, bytes payload, sent, success",
1899 udpw->payload_size,
1900 GNUNET_NO);
1901 GNUNET_STATISTICS_update (
1902 plugin->env->stats,
1903 "# UDP, unfragmented msgs, bytes overhead, sent, success",
1904 overhead,
1905 GNUNET_NO);
1906 GNUNET_STATISTICS_update (plugin->env->stats,
1907 "# UDP, total, bytes overhead, sent",
1908 overhead,
1909 GNUNET_NO);
1910 GNUNET_STATISTICS_update (plugin->env->stats,
1911 "# UDP, total, bytes payload, sent",
1912 udpw->payload_size,
1913 GNUNET_NO);
1914 }
1915 else
1916 {
1917 GNUNET_STATISTICS_update (plugin->env->stats,
1918 "# UDP, unfragmented msgs, messages, sent, failure",
1919 1,
1920 GNUNET_NO);
1921 GNUNET_STATISTICS_update (
1922 plugin->env->stats,
1923 "# UDP, unfragmented msgs, bytes payload, sent, failure",
1924 udpw->payload_size,
1925 GNUNET_NO);
1926 GNUNET_STATISTICS_update (
1927 plugin->env->stats,
1928 "# UDP, unfragmented msgs, bytes overhead, sent, failure",
1929 overhead,
1930 GNUNET_NO);
1931 }
1932}
1933
1934
1935/**
1936 * Function that can be used by the transport service to transmit a
1937 * message using the plugin. Note that in the case of a peer
1938 * disconnecting, the continuation MUST be called prior to the
1939 * disconnect notification itself. This function will be called with
1940 * this peer's HELLO message to initiate a fresh connection to another
1941 * peer.
1942 *
1943 * @param cls closure
1944 * @param s which session must be used
1945 * @param msgbuf the message to transmit
1946 * @param msgbuf_size number of bytes in @a msgbuf
1947 * @param priority how important is the message (most plugins will
1948 * ignore message priority and just FIFO)
1949 * @param to how long to wait at most for the transmission (does not
1950 * require plugins to discard the message after the timeout,
1951 * just advisory for the desired delay; most plugins will ignore
1952 * this as well)
1953 * @param cont continuation to call once the message has
1954 * been transmitted (or if the transport is ready
1955 * for the next transmission call; or if the
1956 * peer disconnected...); can be NULL
1957 * @param cont_cls closure for @a cont
1958 * @return number of bytes used (on the physical network, with overheads);
1959 * -1 on hard errors (i.e. address invalid); 0 is a legal value
1960 * and does NOT mean that the message was not transmitted (DV)
1961 */
1962static ssize_t
1963udp_plugin_send (void *cls,
1964 struct GNUNET_ATS_Session *s,
1965 const char *msgbuf,
1966 size_t msgbuf_size,
1967 unsigned int priority,
1968 struct GNUNET_TIME_Relative to,
1969 GNUNET_TRANSPORT_TransmitContinuation cont,
1970 void *cont_cls)
1971{
1972 struct Plugin *plugin = cls;
1973 size_t udpmlen = msgbuf_size + sizeof(struct UDPMessage);
1974 struct UDP_FragmentationContext *frag_ctx;
1975 struct UDP_MessageWrapper *udpw;
1976 struct UDPMessage *udp;
1977 char mbuf[udpmlen] GNUNET_ALIGN;
1978 struct GNUNET_TIME_Relative latency;
1979
1980 if ((sizeof(struct IPv6UdpAddress) == s->address->address_length) &&
1981 (NULL == plugin->sockv6))
1982 return GNUNET_SYSERR;
1983 if ((sizeof(struct IPv4UdpAddress) == s->address->address_length) &&
1984 (NULL == plugin->sockv4))
1985 return GNUNET_SYSERR;
1986 if (udpmlen >= GNUNET_MAX_MESSAGE_SIZE)
1987 {
1988 GNUNET_break (0);
1989 return GNUNET_SYSERR;
1990 }
1991 if (GNUNET_YES !=
1992 GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessions,
1993 &s->target,
1994 s))
1995 {
1996 GNUNET_break (0);
1997 return GNUNET_SYSERR;
1998 }
1999 LOG (GNUNET_ERROR_TYPE_DEBUG,
2000 "UDP transmits %lu-byte message to `%s' using address `%s'\n",
2001 (unsigned long) udpmlen,
2002 GNUNET_i2s (&s->target),
2003 udp_address_to_string (plugin,
2004 s->address->address,
2005 s->address->address_length));
2006
2007 udp = (struct UDPMessage *) mbuf;
2008 udp->header.size = htons (udpmlen);
2009 udp->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_MESSAGE);
2010 udp->reserved = htonl (0);
2011 udp->sender = *plugin->env->my_identity;
2012
2013 /* We do not update the session time out here! Otherwise this
2014 * session will not timeout since we send keep alive before session
2015 * can timeout.
2016 *
2017 * For UDP we update session timeout only on receive, this will
2018 * cover keep alives, since remote peer will reply with keep alive
2019 * responses!
2020 */if (udpmlen <= UDP_MTU)
2021 {
2022 /* unfragmented message */
2023 udpw = GNUNET_malloc (sizeof(struct UDP_MessageWrapper) + udpmlen);
2024 udpw->session = s;
2025 udpw->msg_buf = (char *) &udpw[1];
2026 udpw->msg_size = udpmlen; /* message size with UDP overhead */
2027 udpw->payload_size = msgbuf_size; /* message size without UDP overhead */
2028 udpw->start_time = GNUNET_TIME_absolute_get ();
2029 udpw->timeout = GNUNET_TIME_relative_to_absolute (to);
2030 udpw->transmission_time = s->last_transmit_time;
2031 s->last_transmit_time =
2032 GNUNET_TIME_absolute_add (s->last_transmit_time,
2033 s->flow_delay_from_other_peer);
2034 udpw->cont = cont;
2035 udpw->cont_cls = cont_cls;
2036 udpw->frag_ctx = NULL;
2037 udpw->qc = &qc_message_sent;
2038 udpw->qc_cls = plugin;
2039 GNUNET_memcpy (udpw->msg_buf, udp, sizeof(struct UDPMessage));
2040 GNUNET_memcpy (&udpw->msg_buf[sizeof(struct UDPMessage)],
2041 msgbuf,
2042 msgbuf_size);
2043 enqueue (plugin, udpw);
2044 GNUNET_STATISTICS_update (plugin->env->stats,
2045 "# UDP, unfragmented messages queued total",
2046 1,
2047 GNUNET_NO);
2048 GNUNET_STATISTICS_update (plugin->env->stats,
2049 "# UDP, unfragmented bytes payload queued total",
2050 msgbuf_size,
2051 GNUNET_NO);
2052 if (s->address->address_length == sizeof(struct IPv4UdpAddress))
2053 schedule_select_v4 (plugin);
2054 else
2055 schedule_select_v6 (plugin);
2056 }
2057 else
2058 {
2059 /* fragmented message */
2060 if (NULL != s->frag_ctx)
2061 return GNUNET_SYSERR;
2062 GNUNET_memcpy (&udp[1], msgbuf, msgbuf_size);
2063 frag_ctx = GNUNET_new (struct UDP_FragmentationContext);
2064 frag_ctx->plugin = plugin;
2065 frag_ctx->session = s;
2066 frag_ctx->cont = cont;
2067 frag_ctx->cont_cls = cont_cls;
2068 frag_ctx->start_time = GNUNET_TIME_absolute_get ();
2069 frag_ctx->next_frag_time = s->last_transmit_time;
2070 frag_ctx->flow_delay_from_other_peer =
2071 GNUNET_TIME_relative_divide (s->flow_delay_from_other_peer,
2072 1 + (msgbuf_size / UDP_MTU));
2073 frag_ctx->timeout = GNUNET_TIME_relative_to_absolute (to);
2074 frag_ctx->payload_size =
2075 msgbuf_size; /* unfragmented message size without UDP overhead */
2076 frag_ctx->on_wire_size = 0; /* bytes with UDP and fragmentation overhead */
2077 frag_ctx->frag = GNUNET_FRAGMENT_context_create (plugin->env->stats,
2078 UDP_MTU,
2079 &plugin->tracker,
2080 s->last_expected_msg_delay,
2081 s->last_expected_ack_delay,
2082 &udp->header,
2083 &enqueue_fragment,
2084 frag_ctx);
2085 s->frag_ctx = frag_ctx;
2086 s->last_transmit_time = frag_ctx->next_frag_time;
2087 latency = GNUNET_TIME_absolute_get_remaining (s->last_transmit_time);
2088 if (latency.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
2089 LOG (GNUNET_ERROR_TYPE_WARNING,
2090 "Enqueued fragments will take %s for transmission to %s (queue size: %u)\n",
2091 GNUNET_STRINGS_relative_time_to_string (latency, GNUNET_YES),
2092 GNUNET_i2s (&s->target),
2093 (unsigned int) s->msgs_in_queue);
2094 else
2095 LOG (GNUNET_ERROR_TYPE_DEBUG,
2096 "Enqueued fragments will take %s for transmission to %s (queue size: %u)\n",
2097 GNUNET_STRINGS_relative_time_to_string (latency, GNUNET_YES),
2098 GNUNET_i2s (&s->target),
2099 (unsigned int) s->msgs_in_queue);
2100
2101 GNUNET_STATISTICS_update (plugin->env->stats,
2102 "# UDP, fragmented messages active",
2103 1,
2104 GNUNET_NO);
2105 GNUNET_STATISTICS_update (plugin->env->stats,
2106 "# UDP, fragmented messages, total",
2107 1,
2108 GNUNET_NO);
2109 GNUNET_STATISTICS_update (plugin->env->stats,
2110 "# UDP, fragmented bytes (payload)",
2111 frag_ctx->payload_size,
2112 GNUNET_NO);
2113 }
2114 notify_session_monitor (s->plugin, s, GNUNET_TRANSPORT_SS_UPDATE);
2115 return udpmlen;
2116}
2117
2118
2119/* ********************** Receiving ********************** */
2120
2121
2122/**
2123 * Closure for #find_receive_context().
2124 */
2125struct FindReceiveContext
2126{
2127 /**
2128 * Where to store the result.
2129 */
2130 struct DefragContext *rc;
2131
2132 /**
2133 * Session associated with this context.
2134 */
2135 struct GNUNET_ATS_Session *session;
2136
2137 /**
2138 * Address to find.
2139 */
2140 const union UdpAddress *udp_addr;
2141
2142 /**
2143 * Number of bytes in @e udp_addr.
2144 */
2145 size_t udp_addr_len;
2146};
2147
2148
2149/**
2150 * Scan the heap for a receive context with the given address.
2151 *
2152 * @param cls the `struct FindReceiveContext`
2153 * @param node internal node of the heap
2154 * @param element value stored at the node (a `struct ReceiveContext`)
2155 * @param cost cost associated with the node
2156 * @return #GNUNET_YES if we should continue to iterate,
2157 * #GNUNET_NO if not.
2158 */
2159static int
2160find_receive_context (void *cls,
2161 struct GNUNET_CONTAINER_HeapNode *node,
2162 void *element,
2163 GNUNET_CONTAINER_HeapCostType cost)
2164{
2165 struct FindReceiveContext *frc = cls;
2166 struct DefragContext *e = element;
2167
2168 if ((frc->udp_addr_len == e->udp_addr_len) &&
2169 (0 == memcmp (frc->udp_addr, e->udp_addr, frc->udp_addr_len)))
2170 {
2171 frc->rc = e;
2172 return GNUNET_NO;
2173 }
2174 return GNUNET_YES;
2175}
2176
2177
2178/**
2179 * Functions with this signature are called whenever we need to close
2180 * a session due to a disconnect or failure to establish a connection.
2181 *
2182 * @param cls closure with the `struct Plugin`
2183 * @param s session to close down
2184 * @return #GNUNET_OK on success
2185 */
2186static int
2187udp_disconnect_session (void *cls, struct GNUNET_ATS_Session *s)
2188{
2189 struct Plugin *plugin = cls;
2190 struct UDP_MessageWrapper *udpw;
2191 struct UDP_MessageWrapper *next;
2192 struct FindReceiveContext frc;
2193
2194 GNUNET_assert (GNUNET_YES != s->in_destroy);
2195 LOG (GNUNET_ERROR_TYPE_DEBUG,
2196 "Session %p to peer `%s' at address %s ended\n",
2197 s,
2198 GNUNET_i2s (&s->target),
2199 udp_address_to_string (plugin,
2200 s->address->address,
2201 s->address->address_length));
2202 if (NULL != s->timeout_task)
2203 {
2204 GNUNET_SCHEDULER_cancel (s->timeout_task);
2205 s->timeout_task = NULL;
2206 }
2207 if (NULL != s->frag_ctx)
2208 {
2209 /* Remove fragmented message due to disconnect */
2210 fragmented_message_done (s->frag_ctx, GNUNET_SYSERR);
2211 }
2212 GNUNET_assert (
2213 GNUNET_YES ==
2214 GNUNET_CONTAINER_multipeermap_remove (plugin->sessions, &s->target, s));
2215 frc.rc = NULL;
2216 frc.udp_addr = s->address->address;
2217 frc.udp_addr_len = s->address->address_length;
2218 /* Lookup existing receive context for this address */
2219 if (NULL != plugin->defrag_ctxs)
2220 {
2221 GNUNET_CONTAINER_heap_iterate (plugin->defrag_ctxs,
2222 &find_receive_context,
2223 &frc);
2224 if (NULL != frc.rc)
2225 {
2226 struct DefragContext *d_ctx = frc.rc;
2227
2228 GNUNET_CONTAINER_heap_remove_node (d_ctx->hnode);
2229 GNUNET_DEFRAGMENT_context_destroy (d_ctx->defrag);
2230 GNUNET_free (d_ctx);
2231 }
2232 }
2233 s->in_destroy = GNUNET_YES;
2234 next = plugin->ipv4_queue_head;
2235 while (NULL != (udpw = next))
2236 {
2237 next = udpw->next;
2238 if (udpw->session == s)
2239 {
2240 dequeue (plugin, udpw);
2241 udpw->qc (udpw->qc_cls, udpw, GNUNET_SYSERR);
2242 GNUNET_free (udpw);
2243 }
2244 }
2245 next = plugin->ipv6_queue_head;
2246 while (NULL != (udpw = next))
2247 {
2248 next = udpw->next;
2249 if (udpw->session == s)
2250 {
2251 dequeue (plugin, udpw);
2252 udpw->qc (udpw->qc_cls, udpw, GNUNET_SYSERR);
2253 GNUNET_free (udpw);
2254 }
2255 }
2256 if ((NULL != s->frag_ctx) && (NULL != s->frag_ctx->cont))
2257 {
2258 /* The 'frag_ctx' itself will be freed in #free_session() a bit
2259 later, as it might be in use right now */
2260 LOG (GNUNET_ERROR_TYPE_DEBUG,
2261 "Calling continuation for fragemented message to `%s' with result SYSERR\n",
2262 GNUNET_i2s (&s->target));
2263 s->frag_ctx->cont (s->frag_ctx->cont_cls,
2264 &s->target,
2265 GNUNET_SYSERR,
2266 s->frag_ctx->payload_size,
2267 s->frag_ctx->on_wire_size);
2268 }
2269 notify_session_monitor (s->plugin, s, GNUNET_TRANSPORT_SS_DONE);
2270 plugin->env->session_end (plugin->env->cls, s->address, s);
2271 GNUNET_STATISTICS_set (plugin->env->stats,
2272 "# UDP sessions active",
2273 GNUNET_CONTAINER_multipeermap_size (plugin->sessions),
2274 GNUNET_NO);
2275 if (0 == s->rc)
2276 free_session (s);
2277 return GNUNET_OK;
2278}
2279
2280
2281/**
2282 * Handle a #GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_ACK message.
2283 *
2284 * @param plugin the UDP plugin
2285 * @param msg the (presumed) UDP ACK message
2286 * @param udp_addr sender address
2287 * @param udp_addr_len number of bytes in @a udp_addr
2288 */
2289static void
2290read_process_ack (struct Plugin *plugin,
2291 const struct GNUNET_MessageHeader *msg,
2292 const union UdpAddress *udp_addr,
2293 socklen_t udp_addr_len)
2294{
2295 const struct GNUNET_MessageHeader *ack;
2296 const struct UDP_ACK_Message *udp_ack;
2297 struct GNUNET_HELLO_Address *address;
2298 struct GNUNET_ATS_Session *s;
2299 struct GNUNET_TIME_Relative flow_delay;
2300
2301 /* check message format */
2302 if (ntohs (msg->size) <
2303 sizeof(struct UDP_ACK_Message) + sizeof(struct GNUNET_MessageHeader))
2304 {
2305 GNUNET_break_op (0);
2306 return;
2307 }
2308 udp_ack = (const struct UDP_ACK_Message *) msg;
2309 ack = (const struct GNUNET_MessageHeader *) &udp_ack[1];
2310 if (ntohs (ack->size) != ntohs (msg->size) - sizeof(struct UDP_ACK_Message))
2311 {
2312 GNUNET_break_op (0);
2313 return;
2314 }
2315
2316 /* Locate session */
2317 address = GNUNET_HELLO_address_allocate (&udp_ack->sender,
2318 PLUGIN_NAME,
2319 udp_addr,
2320 udp_addr_len,
2321 GNUNET_HELLO_ADDRESS_INFO_NONE);
2322 s = udp_plugin_lookup_session (plugin, address);
2323 if (NULL == s)
2324 {
2325 LOG (GNUNET_ERROR_TYPE_WARNING,
2326 "UDP session of address %s for ACK not found\n",
2327 udp_address_to_string (plugin,
2328 address->address,
2329 address->address_length));
2330 GNUNET_HELLO_address_free (address);
2331 return;
2332 }
2333 if (NULL == s->frag_ctx)
2334 {
2335 LOG (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2336 "Fragmentation context of address %s for ACK (%s) not found\n",
2337 udp_address_to_string (plugin,
2338 address->address,
2339 address->address_length),
2340 GNUNET_FRAGMENT_print_ack (ack));
2341 GNUNET_HELLO_address_free (address);
2342 return;
2343 }
2344 GNUNET_HELLO_address_free (address);
2345
2346 /* evaluate flow delay: how long should we wait between messages? */
2347 if (UINT32_MAX == ntohl (udp_ack->delay))
2348 {
2349 /* Other peer asked for us to terminate the session */
2350 LOG (GNUNET_ERROR_TYPE_INFO,
2351 "Asked to disconnect UDP session of %s\n",
2352 GNUNET_i2s (&udp_ack->sender));
2353 udp_disconnect_session (plugin, s);
2354 return;
2355 }
2356 flow_delay.rel_value_us = (uint64_t) ntohl (udp_ack->delay);
2357 if (flow_delay.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
2358 LOG (GNUNET_ERROR_TYPE_WARNING,
2359 "We received a sending delay of %s for %s\n",
2360 GNUNET_STRINGS_relative_time_to_string (flow_delay, GNUNET_YES),
2361 GNUNET_i2s (&udp_ack->sender));
2362 else
2363 LOG (GNUNET_ERROR_TYPE_DEBUG,
2364 "We received a sending delay of %s for %s\n",
2365 GNUNET_STRINGS_relative_time_to_string (flow_delay, GNUNET_YES),
2366 GNUNET_i2s (&udp_ack->sender));
2367 /* Flow delay is for the reassembled packet, however, our delay
2368 is per packet, so we need to adjust: */
2369 s->flow_delay_from_other_peer = flow_delay;
2370
2371 /* Handle ACK */
2372 if (GNUNET_OK != GNUNET_FRAGMENT_process_ack (s->frag_ctx->frag, ack))
2373 {
2374 LOG (GNUNET_ERROR_TYPE_DEBUG,
2375 "UDP processes %u-byte acknowledgement from `%s' at `%s'\n",
2376 (unsigned int) ntohs (msg->size),
2377 GNUNET_i2s (&udp_ack->sender),
2378 udp_address_to_string (plugin, udp_addr, udp_addr_len));
2379 /* Expect more ACKs to arrive */
2380 return;
2381 }
2382
2383 /* Remove fragmented message after successful sending */
2384 LOG (GNUNET_ERROR_TYPE_DEBUG,
2385 "Message from %s at %s full ACK'ed\n",
2386 GNUNET_i2s (&udp_ack->sender),
2387 udp_address_to_string (plugin, udp_addr, udp_addr_len));
2388 fragmented_message_done (s->frag_ctx, GNUNET_OK);
2389}
2390
2391
2392/**
2393 * Message tokenizer has broken up an incoming message. Pass it on
2394 * to the service.
2395 *
2396 * @param cls the `struct GNUNET_ATS_Session *`
2397 * @param hdr the actual message
2398 * @return #GNUNET_OK (always)
2399 */
2400static int
2401process_inbound_tokenized_messages (void *cls,
2402 const struct GNUNET_MessageHeader *hdr)
2403{
2404 struct GNUNET_ATS_Session *session = cls;
2405 struct Plugin *plugin = session->plugin;
2406
2407 if (GNUNET_YES == session->in_destroy)
2408 return GNUNET_OK;
2409 reschedule_session_timeout (session);
2410 session->flow_delay_for_other_peer =
2411 plugin->env->receive (plugin->env->cls, session->address, session, hdr);
2412 return GNUNET_OK;
2413}
2414
2415
2416/**
2417 * Destroy a session, plugin is being unloaded.
2418 *
2419 * @param cls the `struct Plugin`
2420 * @param key hash of public key of target peer
2421 * @param value a `struct PeerSession *` to clean up
2422 * @return #GNUNET_OK (continue to iterate)
2423 */
2424static int
2425disconnect_and_free_it (void *cls,
2426 const struct GNUNET_PeerIdentity *key,
2427 void *value)
2428{
2429 struct Plugin *plugin = cls;
2430
2431 udp_disconnect_session (plugin, value);
2432 return GNUNET_OK;
2433}
2434
2435
2436/**
2437 * Disconnect from a remote node. Clean up session if we have one for
2438 * this peer.
2439 *
2440 * @param cls closure for this call (should be handle to Plugin)
2441 * @param target the peeridentity of the peer to disconnect
2442 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the operation failed
2443 */
2444static void
2445udp_disconnect (void *cls, const struct GNUNET_PeerIdentity *target)
2446{
2447 struct Plugin *plugin = cls;
2448
2449 LOG (GNUNET_ERROR_TYPE_DEBUG,
2450 "Disconnecting from peer `%s'\n",
2451 GNUNET_i2s (target));
2452 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessions,
2453 target,
2454 &disconnect_and_free_it,
2455 plugin);
2456}
2457
2458
2459/**
2460 * Session was idle, so disconnect it.
2461 *
2462 * @param cls the `struct GNUNET_ATS_Session` to time out
2463 */
2464static void
2465session_timeout (void *cls)
2466{
2467 struct GNUNET_ATS_Session *s = cls;
2468 struct Plugin *plugin = s->plugin;
2469 struct GNUNET_TIME_Relative left;
2470
2471 s->timeout_task = NULL;
2472 left = GNUNET_TIME_absolute_get_remaining (s->timeout);
2473 if (left.rel_value_us > 0)
2474 {
2475 /* not actually our turn yet, but let's at least update
2476 the monitor, it may think we're about to die ... */
2477 notify_session_monitor (s->plugin, s, GNUNET_TRANSPORT_SS_UPDATE);
2478 s->timeout_task = GNUNET_SCHEDULER_add_delayed (left, &session_timeout, s);
2479 return;
2480 }
2481 LOG (GNUNET_ERROR_TYPE_DEBUG,
2482 "Session %p was idle for %s, disconnecting\n",
2483 s,
2484 GNUNET_STRINGS_relative_time_to_string (UDP_SESSION_TIME_OUT,
2485 GNUNET_YES));
2486 /* call session destroy function */
2487 udp_disconnect_session (plugin, s);
2488}
2489
2490
2491/**
2492 * Allocate a new session for the given endpoint address.
2493 * Note that this function does not inform the service
2494 * of the new session, this is the responsibility of the
2495 * caller (if needed).
2496 *
2497 * @param cls the `struct Plugin`
2498 * @param address address of the other peer to use
2499 * @param network_type network type the address belongs to
2500 * @return NULL on error, otherwise session handle
2501 */
2502static struct GNUNET_ATS_Session *
2503udp_plugin_create_session (void *cls,
2504 const struct GNUNET_HELLO_Address *address,
2505 enum GNUNET_NetworkType network_type)
2506{
2507 struct Plugin *plugin = cls;
2508 struct GNUNET_ATS_Session *s;
2509
2510 s = GNUNET_new (struct GNUNET_ATS_Session);
2511 s->mst = GNUNET_MST_create (&process_inbound_tokenized_messages, s);
2512 s->plugin = plugin;
2513 s->address = GNUNET_HELLO_address_copy (address);
2514 s->target = address->peer;
2515 s->last_transmit_time = GNUNET_TIME_absolute_get ();
2516 s->last_expected_ack_delay =
2517 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 250);
2518 s->last_expected_msg_delay = GNUNET_TIME_UNIT_MILLISECONDS;
2519 s->flow_delay_from_other_peer = GNUNET_TIME_UNIT_ZERO;
2520 s->flow_delay_for_other_peer = GNUNET_TIME_UNIT_ZERO;
2521 s->timeout = GNUNET_TIME_relative_to_absolute (UDP_SESSION_TIME_OUT);
2522 s->timeout_task =
2523 GNUNET_SCHEDULER_add_delayed (UDP_SESSION_TIME_OUT, &session_timeout, s);
2524 s->scope = network_type;
2525
2526 LOG (GNUNET_ERROR_TYPE_DEBUG,
2527 "Creating new session %p for peer `%s' address `%s'\n",
2528 s,
2529 GNUNET_i2s (&address->peer),
2530 udp_address_to_string (plugin,
2531 address->address,
2532 address->address_length));
2533 GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multipeermap_put (
2534 plugin->sessions,
2535 &s->target,
2536 s,
2537 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
2538 GNUNET_STATISTICS_set (plugin->env->stats,
2539 "# UDP sessions active",
2540 GNUNET_CONTAINER_multipeermap_size (plugin->sessions),
2541 GNUNET_NO);
2542 notify_session_monitor (plugin, s, GNUNET_TRANSPORT_SS_INIT);
2543 return s;
2544}
2545
2546
2547/**
2548 * Creates a new outbound session the transport service will use to
2549 * send data to the peer.
2550 *
2551 * @param cls the `struct Plugin *`
2552 * @param address the address
2553 * @return the session or NULL of max connections exceeded
2554 */
2555static struct GNUNET_ATS_Session *
2556udp_plugin_get_session (void *cls, const struct GNUNET_HELLO_Address *address)
2557{
2558 struct Plugin *plugin = cls;
2559 struct GNUNET_ATS_Session *s;
2560 enum GNUNET_NetworkType network_type = GNUNET_NT_UNSPECIFIED;
2561 const struct IPv4UdpAddress *udp_v4;
2562 const struct IPv6UdpAddress *udp_v6;
2563
2564 if (NULL == address)
2565 {
2566 GNUNET_break (0);
2567 return NULL;
2568 }
2569 if ((address->address_length != sizeof(struct IPv4UdpAddress)) &&
2570 (address->address_length != sizeof(struct IPv6UdpAddress)))
2571 {
2572 GNUNET_break_op (0);
2573 return NULL;
2574 }
2575 if (NULL != (s = udp_plugin_lookup_session (cls, address)))
2576 return s;
2577
2578 /* need to create new session */
2579 if (sizeof(struct IPv4UdpAddress) == address->address_length)
2580 {
2581 struct sockaddr_in v4;
2582
2583 udp_v4 = (const struct IPv4UdpAddress *) address->address;
2584 memset (&v4, '\0', sizeof(v4));
2585 v4.sin_family = AF_INET;
2586#if HAVE_SOCKADDR_IN_SIN_LEN
2587 v4.sin_len = sizeof(struct sockaddr_in);
2588#endif
2589 v4.sin_port = udp_v4->u4_port;
2590 v4.sin_addr.s_addr = udp_v4->ipv4_addr;
2591 network_type = plugin->env->get_address_type (plugin->env->cls,
2592 (const struct sockaddr *) &v4,
2593 sizeof(v4));
2594 }
2595 if (sizeof(struct IPv6UdpAddress) == address->address_length)
2596 {
2597 struct sockaddr_in6 v6;
2598
2599 udp_v6 = (const struct IPv6UdpAddress *) address->address;
2600 memset (&v6, '\0', sizeof(v6));
2601 v6.sin6_family = AF_INET6;
2602#if HAVE_SOCKADDR_IN_SIN_LEN
2603 v6.sin6_len = sizeof(struct sockaddr_in6);
2604#endif
2605 v6.sin6_port = udp_v6->u6_port;
2606 v6.sin6_addr = udp_v6->ipv6_addr;
2607 network_type = plugin->env->get_address_type (plugin->env->cls,
2608 (const struct sockaddr *) &v6,
2609 sizeof(v6));
2610 }
2611 GNUNET_break (GNUNET_NT_UNSPECIFIED != network_type);
2612 return udp_plugin_create_session (cls, address, network_type);
2613}
2614
2615
2616/**
2617 * We've received a UDP Message. Process it (pass contents to main service).
2618 *
2619 * @param plugin plugin context
2620 * @param msg the message
2621 * @param udp_addr sender address
2622 * @param udp_addr_len number of bytes in @a udp_addr
2623 * @param network_type network type the address belongs to
2624 */
2625static void
2626process_udp_message (struct Plugin *plugin,
2627 const struct UDPMessage *msg,
2628 const union UdpAddress *udp_addr,
2629 size_t udp_addr_len,
2630 enum GNUNET_NetworkType network_type)
2631{
2632 struct GNUNET_ATS_Session *s;
2633 struct GNUNET_HELLO_Address *address;
2634
2635 GNUNET_break (GNUNET_NT_UNSPECIFIED != network_type);
2636 if (0 != ntohl (msg->reserved))
2637 {
2638 GNUNET_break_op (0);
2639 return;
2640 }
2641 if (ntohs (msg->header.size) <
2642 sizeof(struct GNUNET_MessageHeader) + sizeof(struct UDPMessage))
2643 {
2644 GNUNET_break_op (0);
2645 return;
2646 }
2647
2648 address = GNUNET_HELLO_address_allocate (&msg->sender,
2649 PLUGIN_NAME,
2650 udp_addr,
2651 udp_addr_len,
2652 GNUNET_HELLO_ADDRESS_INFO_NONE);
2653 if (NULL == (s = udp_plugin_lookup_session (plugin, address)))
2654 {
2655 s = udp_plugin_create_session (plugin, address, network_type);
2656 plugin->env->session_start (plugin->env->cls, address, s, s->scope);
2657 notify_session_monitor (plugin, s, GNUNET_TRANSPORT_SS_UP);
2658 }
2659 GNUNET_free (address);
2660
2661 s->rc++;
2662 GNUNET_MST_from_buffer (s->mst,
2663 (const char *) &msg[1],
2664 ntohs (msg->header.size) - sizeof(struct UDPMessage),
2665 GNUNET_YES,
2666 GNUNET_NO);
2667 s->rc--;
2668 if ((0 == s->rc) && (GNUNET_YES == s->in_destroy))
2669 free_session (s);
2670}
2671
2672
2673/**
2674 * Process a defragmented message.
2675 *
2676 * @param cls the `struct DefragContext *`
2677 * @param msg the message
2678 */
2679static void
2680fragment_msg_proc (void *cls, const struct GNUNET_MessageHeader *msg)
2681{
2682 struct DefragContext *dc = cls;
2683 const struct UDPMessage *um;
2684
2685 if (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_MESSAGE)
2686 {
2687 GNUNET_break_op (0);
2688 return;
2689 }
2690 if (ntohs (msg->size) < sizeof(struct UDPMessage))
2691 {
2692 GNUNET_break_op (0);
2693 return;
2694 }
2695 um = (const struct UDPMessage *) msg;
2696 dc->sender = um->sender;
2697 dc->have_sender = GNUNET_YES;
2698 process_udp_message (dc->plugin,
2699 um,
2700 dc->udp_addr,
2701 dc->udp_addr_len,
2702 dc->network_type);
2703}
2704
2705
2706/**
2707 * We finished sending an acknowledgement. Update
2708 * statistics.
2709 *
2710 * @param cls the `struct Plugin`
2711 * @param udpw message queue entry of the ACK
2712 * @param result #GNUNET_OK if the transmission worked,
2713 * #GNUNET_SYSERR if we failed to send the ACK
2714 */
2715static void
2716ack_message_sent (void *cls, struct UDP_MessageWrapper *udpw, int result)
2717{
2718 struct Plugin *plugin = cls;
2719
2720 if (GNUNET_OK == result)
2721 {
2722 GNUNET_STATISTICS_update (plugin->env->stats,
2723 "# UDP, ACK messages sent",
2724 1,
2725 GNUNET_NO);
2726 }
2727 else
2728 {
2729 GNUNET_STATISTICS_update (plugin->env->stats,
2730 "# UDP, ACK transmissions failed",
2731 1,
2732 GNUNET_NO);
2733 }
2734}
2735
2736
2737/**
2738 * Transmit an acknowledgement.
2739 *
2740 * @param cls the `struct DefragContext *`
2741 * @param id message ID (unused)
2742 * @param msg ack to transmit
2743 */
2744static void
2745ack_proc (void *cls, uint32_t id, const struct GNUNET_MessageHeader *msg)
2746{
2747 struct DefragContext *rc = cls;
2748 struct Plugin *plugin = rc->plugin;
2749 size_t msize = sizeof(struct UDP_ACK_Message) + ntohs (msg->size);
2750 struct UDP_ACK_Message *udp_ack;
2751 uint32_t delay;
2752 struct UDP_MessageWrapper *udpw;
2753 struct GNUNET_ATS_Session *s;
2754 struct GNUNET_HELLO_Address *address;
2755
2756 if (GNUNET_NO == rc->have_sender)
2757 {
2758 /* tried to defragment but never succeeded, hence will not ACK */
2759 /* This can happen if we just lost msgs */
2760 GNUNET_STATISTICS_update (plugin->env->stats,
2761 "# UDP, fragments discarded without ACK",
2762 1,
2763 GNUNET_NO);
2764 return;
2765 }
2766 address = GNUNET_HELLO_address_allocate (&rc->sender,
2767 PLUGIN_NAME,
2768 rc->udp_addr,
2769 rc->udp_addr_len,
2770 GNUNET_HELLO_ADDRESS_INFO_NONE);
2771 s = udp_plugin_lookup_session (plugin, address);
2772 GNUNET_HELLO_address_free (address);
2773 if (NULL == s)
2774 {
2775 LOG (GNUNET_ERROR_TYPE_ERROR,
2776 "Trying to transmit ACK to peer `%s' but no session found!\n",
2777 udp_address_to_string (plugin, rc->udp_addr, rc->udp_addr_len));
2778 GNUNET_CONTAINER_heap_remove_node (rc->hnode);
2779 GNUNET_DEFRAGMENT_context_destroy (rc->defrag);
2780 GNUNET_free (rc);
2781 GNUNET_STATISTICS_update (plugin->env->stats,
2782 "# UDP, ACK transmissions failed",
2783 1,
2784 GNUNET_NO);
2785 return;
2786 }
2787 if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us ==
2788 s->flow_delay_for_other_peer.rel_value_us)
2789 delay = UINT32_MAX;
2790 else if (s->flow_delay_for_other_peer.rel_value_us < UINT32_MAX)
2791 delay = s->flow_delay_for_other_peer.rel_value_us;
2792 else
2793 delay = UINT32_MAX - 1; /* largest value we can communicate */
2794 LOG (GNUNET_ERROR_TYPE_DEBUG,
2795 "Sending ACK to `%s' including delay of %s\n",
2796 udp_address_to_string (plugin, rc->udp_addr, rc->udp_addr_len),
2797 GNUNET_STRINGS_relative_time_to_string (s->flow_delay_for_other_peer,
2798 GNUNET_YES));
2799 udpw = GNUNET_malloc (sizeof(struct UDP_MessageWrapper) + msize);
2800 udpw->msg_size = msize;
2801 udpw->payload_size = 0;
2802 udpw->session = s;
2803 udpw->start_time = GNUNET_TIME_absolute_get ();
2804 udpw->timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
2805 udpw->msg_buf = (char *) &udpw[1];
2806 udpw->qc = &ack_message_sent;
2807 udpw->qc_cls = plugin;
2808 udp_ack = (struct UDP_ACK_Message *) udpw->msg_buf;
2809 udp_ack->header.size = htons ((uint16_t) msize);
2810 udp_ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_ACK);
2811 udp_ack->delay = htonl (delay);
2812 udp_ack->sender = *plugin->env->my_identity;
2813 GNUNET_memcpy (&udp_ack[1], msg, ntohs (msg->size));
2814 enqueue (plugin, udpw);
2815 notify_session_monitor (plugin, s, GNUNET_TRANSPORT_SS_UPDATE);
2816 if (s->address->address_length == sizeof(struct IPv4UdpAddress))
2817 schedule_select_v4 (plugin);
2818 else
2819 schedule_select_v6 (plugin);
2820}
2821
2822
2823/**
2824 * We received a fragment, process it.
2825 *
2826 * @param plugin our plugin
2827 * @param msg a message of type #GNUNET_MESSAGE_TYPE_FRAGMENT
2828 * @param udp_addr sender address
2829 * @param udp_addr_len number of bytes in @a udp_addr
2830 * @param network_type network type the address belongs to
2831 */
2832static void
2833read_process_fragment (struct Plugin *plugin,
2834 const struct GNUNET_MessageHeader *msg,
2835 const union UdpAddress *udp_addr,
2836 size_t udp_addr_len,
2837 enum GNUNET_NetworkType network_type)
2838{
2839 struct DefragContext *d_ctx;
2840 struct GNUNET_TIME_Absolute now;
2841 struct FindReceiveContext frc;
2842
2843 frc.rc = NULL;
2844 frc.udp_addr = udp_addr;
2845 frc.udp_addr_len = udp_addr_len;
2846
2847 /* Lookup existing receive context for this address */
2848 GNUNET_CONTAINER_heap_iterate (plugin->defrag_ctxs,
2849 &find_receive_context,
2850 &frc);
2851 now = GNUNET_TIME_absolute_get ();
2852 d_ctx = frc.rc;
2853
2854 if (NULL == d_ctx)
2855 {
2856 /* Create a new defragmentation context */
2857 d_ctx = GNUNET_malloc (sizeof(struct DefragContext) + udp_addr_len);
2858 GNUNET_memcpy (&d_ctx[1], udp_addr, udp_addr_len);
2859 d_ctx->udp_addr = (const union UdpAddress *) &d_ctx[1];
2860 d_ctx->udp_addr_len = udp_addr_len;
2861 d_ctx->network_type = network_type;
2862 d_ctx->plugin = plugin;
2863 d_ctx->defrag =
2864 GNUNET_DEFRAGMENT_context_create (plugin->env->stats,
2865 UDP_MTU,
2866 UDP_MAX_MESSAGES_IN_DEFRAG,
2867 d_ctx,
2868 &fragment_msg_proc,
2869 &ack_proc);
2870 d_ctx->hnode = GNUNET_CONTAINER_heap_insert (plugin->defrag_ctxs,
2871 d_ctx,
2872 (GNUNET_CONTAINER_HeapCostType)
2873 now.abs_value_us);
2874 LOG (GNUNET_ERROR_TYPE_DEBUG,
2875 "Created new defragmentation context for %u-byte fragment from `%s'\n",
2876 (unsigned int) ntohs (msg->size),
2877 udp_address_to_string (plugin, udp_addr, udp_addr_len));
2878 }
2879 else
2880 {
2881 LOG (GNUNET_ERROR_TYPE_DEBUG,
2882 "Found existing defragmentation context for %u-byte fragment from `%s'\n",
2883 (unsigned int) ntohs (msg->size),
2884 udp_address_to_string (plugin, udp_addr, udp_addr_len));
2885 }
2886
2887 if (GNUNET_OK == GNUNET_DEFRAGMENT_process_fragment (d_ctx->defrag, msg))
2888 {
2889 /* keep this 'rc' from expiring */
2890 GNUNET_CONTAINER_heap_update_cost (d_ctx->hnode,
2891 (GNUNET_CONTAINER_HeapCostType)
2892 now.abs_value_us);
2893 }
2894 if (GNUNET_CONTAINER_heap_get_size (plugin->defrag_ctxs) >
2895 UDP_MAX_SENDER_ADDRESSES_WITH_DEFRAG)
2896 {
2897 /* remove 'rc' that was inactive the longest */
2898 d_ctx = GNUNET_CONTAINER_heap_remove_root (plugin->defrag_ctxs);
2899 GNUNET_assert (NULL != d_ctx);
2900 GNUNET_DEFRAGMENT_context_destroy (d_ctx->defrag);
2901 GNUNET_free (d_ctx);
2902 GNUNET_STATISTICS_update (plugin->env->stats,
2903 "# UDP, Defragmentations aborted",
2904 1,
2905 GNUNET_NO);
2906 }
2907}
2908
2909
2910/**
2911 * Read and process a message from the given socket.
2912 *
2913 * @param plugin the overall plugin
2914 * @param rsock socket to read from
2915 */
2916static void
2917udp_select_read (struct Plugin *plugin, struct GNUNET_NETWORK_Handle *rsock)
2918{
2919 socklen_t fromlen;
2920 struct sockaddr_storage addr;
2921 char buf[65536] GNUNET_ALIGN;
2922 ssize_t size;
2923 const struct GNUNET_MessageHeader *msg;
2924 struct IPv4UdpAddress v4;
2925 struct IPv6UdpAddress v6;
2926 const struct sockaddr *sa;
2927 const struct sockaddr_in *sa4;
2928 const struct sockaddr_in6 *sa6;
2929 const union UdpAddress *int_addr;
2930 size_t int_addr_len;
2931 enum GNUNET_NetworkType network_type;
2932
2933 fromlen = sizeof(addr);
2934 memset (&addr, 0, sizeof(addr));
2935 size = GNUNET_NETWORK_socket_recvfrom (rsock,
2936 buf,
2937 sizeof(buf),
2938 (struct sockaddr *) &addr,
2939 &fromlen);
2940 sa = (const struct sockaddr *) &addr;
2941
2942 if (-1 == size)
2943 {
2944 LOG (GNUNET_ERROR_TYPE_DEBUG,
2945 "UDP failed to receive data: %s\n",
2946 strerror (errno));
2947 /* Connection failure or something. Not a protocol violation. */
2948 return;
2949 }
2950
2951 /* Check if this is a STUN packet */
2952 if (GNUNET_NO !=
2953 GNUNET_NAT_stun_handle_packet (plugin->nat,
2954 (const struct sockaddr *) &addr,
2955 fromlen,
2956 buf,
2957 size))
2958 return; /* was STUN, do not process further */
2959
2960 if (size < sizeof(struct GNUNET_MessageHeader))
2961 {
2962 LOG (GNUNET_ERROR_TYPE_WARNING,
2963 "UDP got %u bytes from %s, which is not enough for a GNUnet message header\n",
2964 (unsigned int) size,
2965 GNUNET_a2s (sa, fromlen));
2966 /* _MAY_ be a connection failure (got partial message) */
2967 /* But it _MAY_ also be that the other side uses non-GNUnet protocol. */
2968 GNUNET_break_op (0);
2969 return;
2970 }
2971
2972 msg = (const struct GNUNET_MessageHeader *) buf;
2973 LOG (GNUNET_ERROR_TYPE_DEBUG,
2974 "UDP received %u-byte message from `%s' type %u\n",
2975 (unsigned int) size,
2976 GNUNET_a2s (sa, fromlen),
2977 ntohs (msg->type));
2978 if (size != ntohs (msg->size))
2979 {
2980 LOG (GNUNET_ERROR_TYPE_WARNING,
2981 "UDP malformed message (size %u) header from %s\n",
2982 (unsigned int) size,
2983 GNUNET_a2s (sa, fromlen));
2984 GNUNET_break_op (0);
2985 return;
2986 }
2987 GNUNET_STATISTICS_update (plugin->env->stats,
2988 "# UDP, total bytes received",
2989 size,
2990 GNUNET_NO);
2991 network_type = plugin->env->get_address_type (plugin->env->cls, sa, fromlen);
2992 switch (sa->sa_family)
2993 {
2994 case AF_INET:
2995 sa4 = (const struct sockaddr_in *) &addr;
2996 v4.options = 0;
2997 v4.ipv4_addr = sa4->sin_addr.s_addr;
2998 v4.u4_port = sa4->sin_port;
2999 int_addr = (union UdpAddress *) &v4;
3000 int_addr_len = sizeof(v4);
3001 break;
3002
3003 case AF_INET6:
3004 sa6 = (const struct sockaddr_in6 *) &addr;
3005 v6.options = 0;
3006 v6.ipv6_addr = sa6->sin6_addr;
3007 v6.u6_port = sa6->sin6_port;
3008 int_addr = (union UdpAddress *) &v6;
3009 int_addr_len = sizeof(v6);
3010 break;
3011
3012 default:
3013 GNUNET_break (0);
3014 return;
3015 }
3016
3017 switch (ntohs (msg->type))
3018 {
3019 case GNUNET_MESSAGE_TYPE_TRANSPORT_BROADCAST_BEACON:
3020 if (GNUNET_YES == plugin->enable_broadcasting_receiving)
3021 udp_broadcast_receive (plugin,
3022 buf,
3023 size,
3024 int_addr,
3025 int_addr_len,
3026 network_type);
3027 return;
3028
3029 case GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_MESSAGE:
3030 if (ntohs (msg->size) < sizeof(struct UDPMessage))
3031 {
3032 GNUNET_break_op (0);
3033 return;
3034 }
3035 process_udp_message (plugin,
3036 (const struct UDPMessage *) msg,
3037 int_addr,
3038 int_addr_len,
3039 network_type);
3040 return;
3041
3042 case GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_ACK:
3043 read_process_ack (plugin, msg, int_addr, int_addr_len);
3044 return;
3045
3046 case GNUNET_MESSAGE_TYPE_FRAGMENT:
3047 read_process_fragment (plugin, msg, int_addr, int_addr_len, network_type);
3048 return;
3049
3050 default:
3051 GNUNET_break_op (0);
3052 return;
3053 }
3054}
3055
3056
3057/**
3058 * Removes messages from the transmission queue that have
3059 * timed out, and then selects a message that should be
3060 * transmitted next.
3061 *
3062 * @param plugin the UDP plugin
3063 * @param sock which socket should we process the queue for (v4 or v6)
3064 * @return message selected for transmission, or NULL for none
3065 */
3066static struct UDP_MessageWrapper *
3067remove_timeout_messages_and_select (struct Plugin *plugin,
3068 struct GNUNET_NETWORK_Handle *sock)
3069{
3070 struct UDP_MessageWrapper *udpw;
3071 struct GNUNET_TIME_Relative remaining;
3072 struct GNUNET_ATS_Session *session;
3073 int removed;
3074
3075 removed = GNUNET_NO;
3076 udpw = (sock == plugin->sockv4) ? plugin->ipv4_queue_head
3077 : plugin->ipv6_queue_head;
3078 while (NULL != udpw)
3079 {
3080 session = udpw->session;
3081 /* Find messages with timeout */
3082 remaining = GNUNET_TIME_absolute_get_remaining (udpw->timeout);
3083 if (GNUNET_TIME_UNIT_ZERO.rel_value_us == remaining.rel_value_us)
3084 {
3085 /* Message timed out */
3086 removed = GNUNET_YES;
3087 dequeue (plugin, udpw);
3088 udpw->qc (udpw->qc_cls, udpw, GNUNET_SYSERR);
3089 GNUNET_free (udpw);
3090
3091 if (sock == plugin->sockv4)
3092 {
3093 udpw = plugin->ipv4_queue_head;
3094 }
3095 else if (sock == plugin->sockv6)
3096 {
3097 udpw = plugin->ipv6_queue_head;
3098 }
3099 else
3100 {
3101 GNUNET_break (0); /* should never happen */
3102 udpw = NULL;
3103 }
3104 GNUNET_STATISTICS_update (plugin->env->stats,
3105 "# messages discarded due to timeout",
3106 1,
3107 GNUNET_NO);
3108 }
3109 else
3110 {
3111 /* Message did not time out, check transmission time */
3112 remaining = GNUNET_TIME_absolute_get_remaining (udpw->transmission_time);
3113 if (0 == remaining.rel_value_us)
3114 {
3115 /* this message is not delayed */
3116 LOG (GNUNET_ERROR_TYPE_DEBUG,
3117 "Message for peer `%s' (%lu bytes) is not delayed \n",
3118 GNUNET_i2s (&udpw->session->target),
3119 (unsigned long) udpw->payload_size);
3120 break; /* Found message to send, break */
3121 }
3122 else
3123 {
3124 /* Message is delayed, try next */
3125 LOG (GNUNET_ERROR_TYPE_DEBUG,
3126 "Message for peer `%s' (%lu bytes) is delayed for %s\n",
3127 GNUNET_i2s (&udpw->session->target),
3128 (unsigned long) udpw->payload_size,
3129 GNUNET_STRINGS_relative_time_to_string (remaining, GNUNET_YES));
3130 udpw = udpw->next;
3131 }
3132 }
3133 }
3134 if (GNUNET_YES == removed)
3135 notify_session_monitor (session->plugin,
3136 session,
3137 GNUNET_TRANSPORT_SS_UPDATE);
3138 return udpw;
3139}
3140
3141
3142/**
3143 * We failed to transmit a message via UDP. Generate
3144 * a descriptive error message.
3145 *
3146 * @param plugin our plugin
3147 * @param sa target address we were trying to reach
3148 * @param slen number of bytes in @a sa
3149 * @param error the errno value returned from the sendto() call
3150 */
3151static void
3152analyze_send_error (struct Plugin *plugin,
3153 const struct sockaddr *sa,
3154 socklen_t slen,
3155 int error)
3156{
3157 enum GNUNET_NetworkType type;
3158
3159 type = plugin->env->get_address_type (plugin->env->cls, sa, slen);
3160 if (((GNUNET_NT_LAN == type) || (GNUNET_NT_WAN == type)) &&
3161 ((ENETUNREACH == errno) || (ENETDOWN == errno)))
3162 {
3163 if (slen == sizeof(struct sockaddr_in))
3164 {
3165 /* IPv4: "Network unreachable" or "Network down"
3166 *
3167 * This indicates we do not have connectivity
3168 */
3169 LOG (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
3170 _ ("UDP could not transmit message to `%s': "
3171 "Network seems down, please check your network configuration\n"),
3172 GNUNET_a2s (sa, slen));
3173 }
3174 if (slen == sizeof(struct sockaddr_in6))
3175 {
3176 /* IPv6: "Network unreachable" or "Network down"
3177 *
3178 * This indicates that this system is IPv6 enabled, but does not
3179 * have a valid global IPv6 address assigned or we do not have
3180 * connectivity
3181 */LOG (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
3182 _ (
3183 "UDP could not transmit IPv6 message! "
3184 "Please check your network configuration and disable IPv6 if your "
3185 "connection does not have a global IPv6 address\n"));
3186 }
3187 }
3188 else
3189 {
3190 LOG (GNUNET_ERROR_TYPE_WARNING,
3191 "UDP could not transmit message to `%s': `%s'\n",
3192 GNUNET_a2s (sa, slen),
3193 strerror (error));
3194 }
3195}
3196
3197
3198/**
3199 * It is time to try to transmit a UDP message. Select one
3200 * and send.
3201 *
3202 * @param plugin the plugin
3203 * @param sock which socket (v4/v6) to send on
3204 */
3205static void
3206udp_select_send (struct Plugin *plugin, struct GNUNET_NETWORK_Handle *sock)
3207{
3208 ssize_t sent;
3209 socklen_t slen;
3210 const struct sockaddr *a;
3211 const struct IPv4UdpAddress *u4;
3212 struct sockaddr_in a4;
3213 const struct IPv6UdpAddress *u6;
3214 struct sockaddr_in6 a6;
3215 struct UDP_MessageWrapper *udpw;
3216
3217 /* Find message(s) to send */
3218 while (NULL != (udpw = remove_timeout_messages_and_select (plugin, sock)))
3219 {
3220 if (sizeof(struct IPv4UdpAddress) ==
3221 udpw->session->address->address_length)
3222 {
3223 u4 = udpw->session->address->address;
3224 memset (&a4, 0, sizeof(a4));
3225 a4.sin_family = AF_INET;
3226#if HAVE_SOCKADDR_IN_SIN_LEN
3227 a4.sin_len = sizeof(a4);
3228#endif
3229 a4.sin_port = u4->u4_port;
3230 a4.sin_addr.s_addr = u4->ipv4_addr;
3231 a = (const struct sockaddr *) &a4;
3232 slen = sizeof(a4);
3233 }
3234 else if (sizeof(struct IPv6UdpAddress) ==
3235 udpw->session->address->address_length)
3236 {
3237 u6 = udpw->session->address->address;
3238 memset (&a6, 0, sizeof(a6));
3239 a6.sin6_family = AF_INET6;
3240#if HAVE_SOCKADDR_IN_SIN_LEN
3241 a6.sin6_len = sizeof(a6);
3242#endif
3243 a6.sin6_port = u6->u6_port;
3244 a6.sin6_addr = u6->ipv6_addr;
3245 a = (const struct sockaddr *) &a6;
3246 slen = sizeof(a6);
3247 }
3248 else
3249 {
3250 GNUNET_break (0);
3251 dequeue (plugin, udpw);
3252 udpw->qc (udpw->qc_cls, udpw, GNUNET_SYSERR);
3253 notify_session_monitor (plugin,
3254 udpw->session,
3255 GNUNET_TRANSPORT_SS_UPDATE);
3256 GNUNET_free (udpw);
3257 continue;
3258 }
3259 sent = GNUNET_NETWORK_socket_sendto (sock,
3260 udpw->msg_buf,
3261 udpw->msg_size,
3262 a,
3263 slen);
3264 udpw->session->last_transmit_time =
3265 GNUNET_TIME_absolute_max (GNUNET_TIME_absolute_get (),
3266 udpw->session->last_transmit_time);
3267 dequeue (plugin, udpw);
3268 if (GNUNET_SYSERR == sent)
3269 {
3270 /* Failure */
3271 analyze_send_error (plugin, a, slen, errno);
3272 udpw->qc (udpw->qc_cls, udpw, GNUNET_SYSERR);
3273 GNUNET_STATISTICS_update (plugin->env->stats,
3274 "# UDP, total, bytes, sent, failure",
3275 sent,
3276 GNUNET_NO);
3277 GNUNET_STATISTICS_update (plugin->env->stats,
3278 "# UDP, total, messages, sent, failure",
3279 1,
3280 GNUNET_NO);
3281 }
3282 else
3283 {
3284 /* Success */
3285 LOG (GNUNET_ERROR_TYPE_DEBUG,
3286 "UDP transmitted %u-byte message to `%s' `%s' (%d: %s)\n",
3287 (unsigned int) (udpw->msg_size),
3288 GNUNET_i2s (&udpw->session->target),
3289 GNUNET_a2s (a, slen),
3290 (int) sent,
3291 (sent < 0) ? strerror (errno) : "ok");
3292 GNUNET_STATISTICS_update (plugin->env->stats,
3293 "# UDP, total, bytes, sent, success",
3294 sent,
3295 GNUNET_NO);
3296 GNUNET_STATISTICS_update (plugin->env->stats,
3297 "# UDP, total, messages, sent, success",
3298 1,
3299 GNUNET_NO);
3300 if (NULL != udpw->frag_ctx)
3301 udpw->frag_ctx->on_wire_size += udpw->msg_size;
3302 udpw->qc (udpw->qc_cls, udpw, GNUNET_OK);
3303 }
3304 notify_session_monitor (plugin, udpw->session, GNUNET_TRANSPORT_SS_UPDATE);
3305 GNUNET_free (udpw);
3306 }
3307}
3308
3309
3310/* ***************** Event loop (part 2) *************** */
3311
3312
3313/**
3314 * We have been notified that our readset has something to read. We don't
3315 * know which socket needs to be read, so we have to check each one
3316 * Then reschedule this function to be called again once more is available.
3317 *
3318 * @param cls the plugin handle
3319 */
3320static void
3321udp_plugin_select_v4 (void *cls)
3322{
3323 struct Plugin *plugin = cls;
3324 const struct GNUNET_SCHEDULER_TaskContext *tc;
3325
3326 plugin->select_task_v4 = NULL;
3327 if (NULL == plugin->sockv4)
3328 return;
3329 tc = GNUNET_SCHEDULER_get_task_context ();
3330 if ((0 != (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY)) &&
3331 (GNUNET_NETWORK_fdset_isset (tc->read_ready, plugin->sockv4)))
3332 udp_select_read (plugin, plugin->sockv4);
3333 udp_select_send (plugin, plugin->sockv4);
3334 schedule_select_v4 (plugin);
3335}
3336
3337
3338/**
3339 * We have been notified that our readset has something to read. We don't
3340 * know which socket needs to be read, so we have to check each one
3341 * Then reschedule this function to be called again once more is available.
3342 *
3343 * @param cls the plugin handle
3344 */
3345static void
3346udp_plugin_select_v6 (void *cls)
3347{
3348 struct Plugin *plugin = cls;
3349 const struct GNUNET_SCHEDULER_TaskContext *tc;
3350
3351 plugin->select_task_v6 = NULL;
3352 if (NULL == plugin->sockv6)
3353 return;
3354 tc = GNUNET_SCHEDULER_get_task_context ();
3355 if ((0 != (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY)) &&
3356 (GNUNET_NETWORK_fdset_isset (tc->read_ready, plugin->sockv6)))
3357 udp_select_read (plugin, plugin->sockv6);
3358
3359 udp_select_send (plugin, plugin->sockv6);
3360 schedule_select_v6 (plugin);
3361}
3362
3363
3364/* ******************* Initialization *************** */
3365
3366
3367/**
3368 * Setup the UDP sockets (for IPv4 and IPv6) for the plugin.
3369 *
3370 * @param plugin the plugin to initialize
3371 * @param bind_v6 IPv6 address to bind to (can be NULL, for 'any')
3372 * @param bind_v4 IPv4 address to bind to (can be NULL, for 'any')
3373 * @return number of sockets that were successfully bound
3374 */
3375static unsigned int
3376setup_sockets (struct Plugin *plugin,
3377 const struct sockaddr_in6 *bind_v6,
3378 const struct sockaddr_in *bind_v4)
3379{
3380 int tries;
3381 unsigned int sockets_created = 0;
3382 struct sockaddr_in6 server_addrv6;
3383 struct sockaddr_in server_addrv4;
3384 const struct sockaddr *server_addr;
3385 const struct sockaddr *addrs[2];
3386 socklen_t addrlens[2];
3387 socklen_t addrlen;
3388 int eno;
3389
3390 /* Create IPv6 socket */
3391 eno = EINVAL;
3392 if (GNUNET_YES == plugin->enable_ipv6)
3393 {
3394 plugin->sockv6 = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_DGRAM, 0);
3395 if (NULL == plugin->sockv6)
3396 {
3397 LOG (GNUNET_ERROR_TYPE_INFO,
3398 _ ("Disabling IPv6 since it is not supported on this system!\n"));
3399 plugin->enable_ipv6 = GNUNET_NO;
3400 }
3401 else
3402 {
3403 memset (&server_addrv6, 0, sizeof(struct sockaddr_in6));
3404#if HAVE_SOCKADDR_IN_SIN_LEN
3405 server_addrv6.sin6_len = sizeof(struct sockaddr_in6);
3406#endif
3407 server_addrv6.sin6_family = AF_INET6;
3408 if (NULL != bind_v6)
3409 server_addrv6.sin6_addr = bind_v6->sin6_addr;
3410 else
3411 server_addrv6.sin6_addr = in6addr_any;
3412
3413 if (0 == plugin->port) /* autodetect */
3414 server_addrv6.sin6_port = htons (
3415 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG, 33537)
3416 + 32000);
3417 else
3418 server_addrv6.sin6_port = htons (plugin->port);
3419 addrlen = sizeof(struct sockaddr_in6);
3420 server_addr = (const struct sockaddr *) &server_addrv6;
3421
3422 tries = 0;
3423 while (tries < 10)
3424 {
3425 LOG (GNUNET_ERROR_TYPE_DEBUG,
3426 "Binding to IPv6 `%s'\n",
3427 GNUNET_a2s (server_addr, addrlen));
3428 /* binding */
3429 if (GNUNET_OK ==
3430 GNUNET_NETWORK_socket_bind (plugin->sockv6, server_addr, addrlen))
3431 break;
3432 eno = errno;
3433 if (0 != plugin->port)
3434 {
3435 tries = 10; /* fail immediately */
3436 break; /* bind failed on specific port */
3437 }
3438 /* autodetect */
3439 server_addrv6.sin6_port = htons (
3440 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG, 33537)
3441 + 32000);
3442 tries++;
3443 }
3444 if (tries >= 10)
3445 {
3446 GNUNET_NETWORK_socket_close (plugin->sockv6);
3447 plugin->enable_ipv6 = GNUNET_NO;
3448 plugin->sockv6 = NULL;
3449 }
3450 else
3451 {
3452 plugin->port = ntohs (server_addrv6.sin6_port);
3453 }
3454 if (NULL != plugin->sockv6)
3455 {
3456 LOG (GNUNET_ERROR_TYPE_DEBUG,
3457 "IPv6 UDP socket created listinging at %s\n",
3458 GNUNET_a2s (server_addr, addrlen));
3459 addrs[sockets_created] = server_addr;
3460 addrlens[sockets_created] = addrlen;
3461 sockets_created++;
3462 }
3463 else
3464 {
3465 LOG (GNUNET_ERROR_TYPE_WARNING,
3466 _ ("Failed to bind UDP socket to %s: %s\n"),
3467 GNUNET_a2s (server_addr, addrlen),
3468 strerror (eno));
3469 }
3470 }
3471 }
3472
3473 /* Create IPv4 socket */
3474 eno = EINVAL;
3475 plugin->sockv4 = GNUNET_NETWORK_socket_create (PF_INET, SOCK_DGRAM, 0);
3476 if (NULL == plugin->sockv4)
3477 {
3478 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "socket");
3479 LOG (GNUNET_ERROR_TYPE_INFO,
3480 _ ("Disabling IPv4 since it is not supported on this system!\n"));
3481 plugin->enable_ipv4 = GNUNET_NO;
3482 }
3483 else
3484 {
3485 memset (&server_addrv4, 0, sizeof(struct sockaddr_in));
3486#if HAVE_SOCKADDR_IN_SIN_LEN
3487 server_addrv4.sin_len = sizeof(struct sockaddr_in);
3488#endif
3489 server_addrv4.sin_family = AF_INET;
3490 if (NULL != bind_v4)
3491 server_addrv4.sin_addr = bind_v4->sin_addr;
3492 else
3493 server_addrv4.sin_addr.s_addr = INADDR_ANY;
3494
3495 if (0 == plugin->port)
3496 /* autodetect */
3497 server_addrv4.sin_port = htons (
3498 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG, 33537) + 32000);
3499 else
3500 server_addrv4.sin_port = htons (plugin->port);
3501
3502 addrlen = sizeof(struct sockaddr_in);
3503 server_addr = (const struct sockaddr *) &server_addrv4;
3504
3505 tries = 0;
3506 while (tries < 10)
3507 {
3508 LOG (GNUNET_ERROR_TYPE_DEBUG,
3509 "Binding to IPv4 `%s'\n",
3510 GNUNET_a2s (server_addr, addrlen));
3511
3512 /* binding */
3513 if (GNUNET_OK ==
3514 GNUNET_NETWORK_socket_bind (plugin->sockv4, server_addr, addrlen))
3515 break;
3516 eno = errno;
3517 if (0 != plugin->port)
3518 {
3519 tries = 10; /* fail */
3520 break; /* bind failed on specific port */
3521 }
3522
3523 /* autodetect */
3524 server_addrv4.sin_port = htons (
3525 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG, 33537) + 32000);
3526 tries++;
3527 }
3528 if (tries >= 10)
3529 {
3530 GNUNET_NETWORK_socket_close (plugin->sockv4);
3531 plugin->enable_ipv4 = GNUNET_NO;
3532 plugin->sockv4 = NULL;
3533 }
3534 else
3535 {
3536 plugin->port = ntohs (server_addrv4.sin_port);
3537 }
3538
3539 if (NULL != plugin->sockv4)
3540 {
3541 LOG (GNUNET_ERROR_TYPE_DEBUG,
3542 "IPv4 socket created on port %s\n",
3543 GNUNET_a2s (server_addr, addrlen));
3544 addrs[sockets_created] = server_addr;
3545 addrlens[sockets_created] = addrlen;
3546 sockets_created++;
3547 }
3548 else
3549 {
3550 LOG (GNUNET_ERROR_TYPE_ERROR,
3551 _ ("Failed to bind UDP socket to %s: %s\n"),
3552 GNUNET_a2s (server_addr, addrlen),
3553 strerror (eno));
3554 }
3555 }
3556
3557 if (0 == sockets_created)
3558 {
3559 LOG (GNUNET_ERROR_TYPE_WARNING, _ ("Failed to open UDP sockets\n"));
3560 return 0; /* No sockets created, return */
3561 }
3562 schedule_select_v4 (plugin);
3563 schedule_select_v6 (plugin);
3564 plugin->nat = GNUNET_NAT_register (plugin->env->cfg,
3565 "transport-udp",
3566 IPPROTO_UDP,
3567 sockets_created,
3568 addrs,
3569 addrlens,
3570 &udp_nat_port_map_callback,
3571 NULL,
3572 plugin);
3573 return sockets_created;
3574}
3575
3576
3577/**
3578 * The exported method. Makes the core api available via a global and
3579 * returns the udp transport API.
3580 *
3581 * @param cls our `struct GNUNET_TRANSPORT_PluginEnvironment`
3582 * @return our `struct GNUNET_TRANSPORT_PluginFunctions`
3583 */
3584void *
3585libgnunet_plugin_transport_udp_init (void *cls)
3586{
3587 struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
3588 struct GNUNET_TRANSPORT_PluginFunctions *api;
3589 struct Plugin *p;
3590 unsigned long long port;
3591 unsigned long long aport;
3592 unsigned long long udp_max_bps;
3593 int enable_v6;
3594 int enable_broadcasting;
3595 int enable_broadcasting_recv;
3596 char *bind4_address;
3597 char *bind6_address;
3598 struct GNUNET_TIME_Relative interval;
3599 struct sockaddr_in server_addrv4;
3600 struct sockaddr_in6 server_addrv6;
3601 unsigned int res;
3602 int have_bind4;
3603 int have_bind6;
3604
3605 if (NULL == env->receive)
3606 {
3607 /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully
3608 initialize the plugin or the API */
3609 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
3610 api->cls = NULL;
3611 api->address_pretty_printer = &udp_plugin_address_pretty_printer;
3612 api->address_to_string = &udp_address_to_string;
3613 api->string_to_address = &udp_string_to_address;
3614 return api;
3615 }
3616
3617 /* Get port number: port == 0 : autodetect a port,
3618 * > 0 : use this port, not given : 2086 default */
3619 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (env->cfg,
3620 "transport-udp",
3621 "PORT",
3622 &port))
3623 port = 2086;
3624 if (port > 65535)
3625 {
3626 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
3627 "transport-udp",
3628 "PORT",
3629 _ ("must be in [0,65535]"));
3630 return NULL;
3631 }
3632 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (env->cfg,
3633 "transport-udp",
3634 "ADVERTISED_PORT",
3635 &aport))
3636 aport = port;
3637 if (aport > 65535)
3638 {
3639 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
3640 "transport-udp",
3641 "ADVERTISED_PORT",
3642 _ ("must be in [0,65535]"));
3643 return NULL;
3644 }
3645
3646 if (GNUNET_YES ==
3647 GNUNET_CONFIGURATION_get_value_yesno (env->cfg, "nat", "DISABLEV6"))
3648 enable_v6 = GNUNET_NO;
3649 else
3650 enable_v6 = GNUNET_YES;
3651
3652 have_bind4 = GNUNET_NO;
3653 memset (&server_addrv4, 0, sizeof(server_addrv4));
3654 if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (env->cfg,
3655 "transport-udp",
3656 "BINDTO",
3657 &bind4_address))
3658 {
3659 LOG (GNUNET_ERROR_TYPE_DEBUG,
3660 "Binding UDP plugin to specific address: `%s'\n",
3661 bind4_address);
3662 if (1 != inet_pton (AF_INET, bind4_address, &server_addrv4.sin_addr))
3663 {
3664 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
3665 "transport-udp",
3666 "BINDTO",
3667 _ ("must be valid IPv4 address"));
3668 GNUNET_free (bind4_address);
3669 return NULL;
3670 }
3671 have_bind4 = GNUNET_YES;
3672 }
3673 GNUNET_free (bind4_address);
3674 have_bind6 = GNUNET_NO;
3675 memset (&server_addrv6, 0, sizeof(server_addrv6));
3676 if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (env->cfg,
3677 "transport-udp",
3678 "BINDTO6",
3679 &bind6_address))
3680 {
3681 LOG (GNUNET_ERROR_TYPE_DEBUG,
3682 "Binding udp plugin to specific address: `%s'\n",
3683 bind6_address);
3684 if (1 != inet_pton (AF_INET6, bind6_address, &server_addrv6.sin6_addr))
3685 {
3686 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
3687 "transport-udp",
3688 "BINDTO6",
3689 _ ("must be valid IPv6 address"));
3690 GNUNET_free (bind6_address);
3691 return NULL;
3692 }
3693 have_bind6 = GNUNET_YES;
3694 }
3695 GNUNET_free (bind6_address);
3696
3697 enable_broadcasting = GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
3698 "transport-udp",
3699 "BROADCAST");
3700 if (enable_broadcasting == GNUNET_SYSERR)
3701 enable_broadcasting = GNUNET_NO;
3702
3703 enable_broadcasting_recv =
3704 GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
3705 "transport-udp",
3706 "BROADCAST_RECEIVE");
3707 if (enable_broadcasting_recv == GNUNET_SYSERR)
3708 enable_broadcasting_recv = GNUNET_YES;
3709
3710 if (GNUNET_SYSERR ==
3711 GNUNET_CONFIGURATION_get_value_time (env->cfg,
3712 "transport-udp",
3713 "BROADCAST_INTERVAL",
3714 &interval))
3715 {
3716 interval = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10);
3717 }
3718 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (env->cfg,
3719 "transport-udp",
3720 "MAX_BPS",
3721 &udp_max_bps))
3722 {
3723 /* 50 MB/s == infinity for practical purposes */
3724 udp_max_bps = 1024 * 1024 * 50;
3725 }
3726
3727 p = GNUNET_new (struct Plugin);
3728 p->port = port;
3729 p->aport = aport;
3730 p->broadcast_interval = interval;
3731 p->enable_ipv6 = enable_v6;
3732 p->enable_ipv4 = GNUNET_YES; /* default */
3733 p->enable_broadcasting = enable_broadcasting;
3734 p->enable_broadcasting_receiving = enable_broadcasting_recv;
3735 p->env = env;
3736 p->sessions = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_NO);
3737 p->defrag_ctxs =
3738 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3739 GNUNET_BANDWIDTH_tracker_init (&p->tracker,
3740 NULL,
3741 NULL,
3742 GNUNET_BANDWIDTH_value_init (
3743 (uint32_t) udp_max_bps),
3744 30);
3745 res = setup_sockets (p,
3746 (GNUNET_YES == have_bind6) ? &server_addrv6 : NULL,
3747 (GNUNET_YES == have_bind4) ? &server_addrv4 : NULL);
3748 if ((0 == res) || ((NULL == p->sockv4) && (NULL == p->sockv6)))
3749 {
3750 LOG (GNUNET_ERROR_TYPE_ERROR, _ ("Failed to create UDP network sockets\n"));
3751 GNUNET_CONTAINER_multipeermap_destroy (p->sessions);
3752 GNUNET_CONTAINER_heap_destroy (p->defrag_ctxs);
3753 if (NULL != p->nat)
3754 GNUNET_NAT_unregister (p->nat);
3755 GNUNET_free (p);
3756 return NULL;
3757 }
3758
3759 /* Setup broadcasting and receiving beacons */
3760 setup_broadcast (p, &server_addrv6, &server_addrv4);
3761
3762 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
3763 api->cls = p;
3764 api->disconnect_session = &udp_disconnect_session;
3765 api->query_keepalive_factor = &udp_query_keepalive_factor;
3766 api->disconnect_peer = &udp_disconnect;
3767 api->address_pretty_printer = &udp_plugin_address_pretty_printer;
3768 api->address_to_string = &udp_address_to_string;
3769 api->string_to_address = &udp_string_to_address;
3770 api->check_address = &udp_plugin_check_address;
3771 api->get_session = &udp_plugin_get_session;
3772 api->send = &udp_plugin_send;
3773 api->get_network = &udp_plugin_get_network;
3774 api->get_network_for_address = &udp_plugin_get_network_for_address;
3775 api->update_session_timeout = &udp_plugin_update_session_timeout;
3776 api->setup_monitor = &udp_plugin_setup_monitor;
3777 return api;
3778}
3779
3780
3781/**
3782 * Function called on each entry in the defragmentation heap to
3783 * clean it up.
3784 *
3785 * @param cls NULL
3786 * @param node node in the heap (to be removed)
3787 * @param element a `struct DefragContext` to be cleaned up
3788 * @param cost unused
3789 * @return #GNUNET_YES
3790 */
3791static int
3792heap_cleanup_iterator (void *cls,
3793 struct GNUNET_CONTAINER_HeapNode *node,
3794 void *element,
3795 GNUNET_CONTAINER_HeapCostType cost)
3796{
3797 struct DefragContext *d_ctx = element;
3798
3799 GNUNET_CONTAINER_heap_remove_node (node);
3800 GNUNET_DEFRAGMENT_context_destroy (d_ctx->defrag);
3801 GNUNET_free (d_ctx);
3802 return GNUNET_YES;
3803}
3804
3805
3806/**
3807 * The exported method. Makes the core api available via a global and
3808 * returns the udp transport API.
3809 *
3810 * @param cls our `struct GNUNET_TRANSPORT_PluginEnvironment`
3811 * @return NULL
3812 */
3813void *
3814libgnunet_plugin_transport_udp_done (void *cls)
3815{
3816 struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
3817 struct Plugin *plugin = api->cls;
3818 struct PrettyPrinterContext *cur;
3819 struct UDP_MessageWrapper *udpw;
3820
3821 if (NULL == plugin)
3822 {
3823 GNUNET_free (api);
3824 return NULL;
3825 }
3826 stop_broadcast (plugin);
3827 if (NULL != plugin->select_task_v4)
3828 {
3829 GNUNET_SCHEDULER_cancel (plugin->select_task_v4);
3830 plugin->select_task_v4 = NULL;
3831 }
3832 if (NULL != plugin->select_task_v6)
3833 {
3834 GNUNET_SCHEDULER_cancel (plugin->select_task_v6);
3835 plugin->select_task_v6 = NULL;
3836 }
3837 if (NULL != plugin->sockv4)
3838 {
3839 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (plugin->sockv4));
3840 plugin->sockv4 = NULL;
3841 }
3842 if (NULL != plugin->sockv6)
3843 {
3844 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (plugin->sockv6));
3845 plugin->sockv6 = NULL;
3846 }
3847 if (NULL != plugin->nat)
3848 {
3849 GNUNET_NAT_unregister (plugin->nat);
3850 plugin->nat = NULL;
3851 }
3852 if (NULL != plugin->defrag_ctxs)
3853 {
3854 GNUNET_CONTAINER_heap_iterate (plugin->defrag_ctxs,
3855 &heap_cleanup_iterator,
3856 NULL);
3857 GNUNET_CONTAINER_heap_destroy (plugin->defrag_ctxs);
3858 plugin->defrag_ctxs = NULL;
3859 }
3860 while (NULL != (udpw = plugin->ipv4_queue_head))
3861 {
3862 dequeue (plugin, udpw);
3863 udpw->qc (udpw->qc_cls, udpw, GNUNET_SYSERR);
3864 GNUNET_free (udpw);
3865 }
3866 while (NULL != (udpw = plugin->ipv6_queue_head))
3867 {
3868 dequeue (plugin, udpw);
3869 udpw->qc (udpw->qc_cls, udpw, GNUNET_SYSERR);
3870 GNUNET_free (udpw);
3871 }
3872 GNUNET_CONTAINER_multipeermap_iterate (plugin->sessions,
3873 &disconnect_and_free_it,
3874 plugin);
3875 GNUNET_CONTAINER_multipeermap_destroy (plugin->sessions);
3876
3877 while (NULL != (cur = plugin->ppc_dll_head))
3878 {
3879 GNUNET_break (0);
3880 GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head,
3881 plugin->ppc_dll_tail,
3882 cur);
3883 GNUNET_RESOLVER_request_cancel (cur->resolver_handle);
3884 if (NULL != cur->timeout_task)
3885 {
3886 GNUNET_SCHEDULER_cancel (cur->timeout_task);
3887 cur->timeout_task = NULL;
3888 }
3889 GNUNET_free (cur);
3890 }
3891 GNUNET_free (plugin);
3892 GNUNET_free (api);
3893 return NULL;
3894}
3895
3896
3897/* end of plugin_transport_udp.c */
diff --git a/src/transport/plugin_transport_udp.h b/src/transport/plugin_transport_udp.h
deleted file mode 100644
index 7192da885..000000000
--- a/src/transport/plugin_transport_udp.h
+++ /dev/null
@@ -1,355 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2010-2014 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/plugin_transport_udp.h
23 * @brief Implementation of the UDP transport protocol
24 * @author Christian Grothoff
25 * @author Nathan Evans
26 * @author Matthias Wachs
27 */
28#ifndef PLUGIN_TRANSPORT_UDP_H
29#define PLUGIN_TRANSPORT_UDP_H
30
31#include "platform.h"
32#include "gnunet_hello_lib.h"
33#include "gnunet_util_lib.h"
34#include "gnunet_fragmentation_lib.h"
35#include "gnunet_protocols.h"
36#include "gnunet_resolver_service.h"
37#include "gnunet_signatures.h"
38#include "gnunet_constants.h"
39#include "gnunet_statistics_service.h"
40#include "gnunet_transport_service.h"
41#include "gnunet_transport_plugin.h"
42#include "transport.h"
43
44#define LOG(kind, ...) GNUNET_log_from (kind, "transport-udp", __VA_ARGS__)
45
46#define PLUGIN_NAME "udp"
47
48#define DEBUG_UDP GNUNET_NO
49
50#define DEBUG_UDP_BROADCASTING GNUNET_NO
51
52/**
53 * MTU for fragmentation subsystem. Should be conservative since
54 * all communicating peers MUST work with this MTU.
55 */
56#define UDP_MTU 1400
57
58
59GNUNET_NETWORK_STRUCT_BEGIN
60/**
61 * Network format for IPv4 addresses.
62 */
63struct IPv4UdpAddress
64{
65 /**
66 * Optional options and flags for this address
67 */
68 uint32_t options GNUNET_PACKED;
69
70 /**
71 * IPv4 address, in network byte order.
72 */
73 uint32_t ipv4_addr GNUNET_PACKED;
74
75 /**
76 * Port number, in network byte order.
77 */
78 uint16_t u4_port GNUNET_PACKED;
79};
80
81
82/**
83 * Network format for IPv6 addresses.
84 */
85struct IPv6UdpAddress
86{
87 /**
88 * Optional options and flags for this address
89 */
90 uint32_t options GNUNET_PACKED;
91
92 /**
93 * IPv6 address.
94 */
95 struct in6_addr ipv6_addr GNUNET_PACKED;
96
97 /**
98 * Port number, in network byte order.
99 */
100 uint16_t u6_port GNUNET_PACKED;
101};
102GNUNET_NETWORK_STRUCT_END
103
104/**
105 * Either an IPv4 or IPv6 UDP address. Note that without a "length",
106 * one cannot tell which one of the two types this address represents.
107 */
108union UdpAddress
109{
110 /**
111 * IPv4 case.
112 */
113 struct IPv4UdpAddress v4;
114
115 /**
116 * IPv6 case.
117 */
118 struct IPv6UdpAddress v6;
119};
120
121
122/**
123 * Information we track for each message in the queue.
124 */
125struct UDP_MessageWrapper;
126
127
128/**
129 * Closure for #append_port().
130 */
131struct PrettyPrinterContext;
132
133
134/**
135 * Encapsulation of all of the state of the plugin.
136 */
137struct Plugin
138{
139 /**
140 * Our environment.
141 */
142 struct GNUNET_TRANSPORT_PluginEnvironment *env;
143
144 /**
145 * Session of peers with whom we are currently connected,
146 * map of peer identity to `struct GNUNET_ATS_Session *`.
147 */
148 struct GNUNET_CONTAINER_MultiPeerMap *sessions;
149
150 /**
151 * Heap with all of our defragmentation activities.
152 */
153 struct GNUNET_CONTAINER_Heap *defrag_ctxs;
154
155 /**
156 * ID of select task for IPv4
157 */
158 struct GNUNET_SCHEDULER_Task *select_task_v4;
159
160 /**
161 * ID of select task for IPv6
162 */
163 struct GNUNET_SCHEDULER_Task *select_task_v6;
164
165 /**
166 * Bandwidth tracker to limit global UDP traffic.
167 */
168 struct GNUNET_BANDWIDTH_Tracker tracker;
169
170 /**
171 * Address we were told to bind to exclusively (IPv4).
172 */
173 char *bind4_address;
174
175 /**
176 * Address we were told to bind to exclusively (IPv6).
177 */
178 char *bind6_address;
179
180 /**
181 * Handle to NAT traversal support.
182 */
183 struct GNUNET_NAT_Handle *nat;
184
185 /**
186 * Handle to NAT traversal support.
187 */
188 struct GNUNET_NAT_STUN_Handle *stun;
189
190 /**
191 * The read socket for IPv4
192 */
193 struct GNUNET_NETWORK_Handle *sockv4;
194
195 /**
196 * The read socket for IPv6
197 */
198 struct GNUNET_NETWORK_Handle *sockv6;
199
200 /**
201 * Head of DLL of broadcast addresses
202 */
203 struct BroadcastAddress *broadcast_tail;
204
205 /**
206 * Tail of DLL of broadcast addresses
207 */
208 struct BroadcastAddress *broadcast_head;
209
210 /**
211 * Head of messages in IPv4 queue.
212 */
213 struct UDP_MessageWrapper *ipv4_queue_head;
214
215 /**
216 * Tail of messages in IPv4 queue.
217 */
218 struct UDP_MessageWrapper *ipv4_queue_tail;
219
220 /**
221 * Head of messages in IPv6 queue.
222 */
223 struct UDP_MessageWrapper *ipv6_queue_head;
224
225 /**
226 * Tail of messages in IPv6 queue.
227 */
228 struct UDP_MessageWrapper *ipv6_queue_tail;
229
230 /**
231 * Running pretty printers: head
232 */
233 struct PrettyPrinterContext *ppc_dll_head;
234
235 /**
236 * Running pretty printers: tail
237 */
238 struct PrettyPrinterContext *ppc_dll_tail;
239
240 /**
241 * Function to call about session status changes.
242 */
243 GNUNET_TRANSPORT_SessionInfoCallback sic;
244
245 /**
246 * Closure for @e sic.
247 */
248 void *sic_cls;
249
250 /**
251 * IPv6 multicast address
252 */
253 struct sockaddr_in6 ipv6_multicast_address;
254
255 /**
256 * Broadcast interval
257 */
258 struct GNUNET_TIME_Relative broadcast_interval;
259
260 /**
261 * Bytes currently in buffer
262 */
263 int64_t bytes_in_buffer;
264
265 /**
266 * Address options
267 */
268 uint32_t myoptions;
269
270 /**
271 * Is IPv6 enabled: #GNUNET_YES or #GNUNET_NO
272 */
273 int enable_ipv6;
274
275 /**
276 * Is IPv4 enabled: #GNUNET_YES or #GNUNET_NO
277 */
278 int enable_ipv4;
279
280 /**
281 * Is broadcasting enabled: #GNUNET_YES or #GNUNET_NO
282 */
283 int enable_broadcasting;
284
285 /**
286 * Is receiving broadcasts enabled: #GNUNET_YES or #GNUNET_NO
287 */
288 int enable_broadcasting_receiving;
289
290 /**
291 * Port we broadcasting on.
292 */
293 uint16_t broadcast_port;
294
295 /**
296 * Port we listen on.
297 */
298 uint16_t port;
299
300 /**
301 * Port we advertise on.
302 */
303 uint16_t aport;
304};
305
306
307/**
308 * Function called for a quick conversion of the binary address to
309 * a numeric address. Note that the caller must not free the
310 * address and that the next call to this function is allowed
311 * to override the address again.
312 *
313 * @param cls closure
314 * @param addr binary address (a `union UdpAddress`)
315 * @param addrlen length of the @a addr
316 * @return string representing the same address
317 */
318const char *
319udp_address_to_string (void *cls,
320 const void *addr,
321 size_t addrlen);
322
323
324/**
325 * We received a broadcast message. Process it and all subsequent
326 * messages in the same packet.
327 *
328 * @param plugin the UDP plugin
329 * @param buf the buffer with the message(s)
330 * @param size number of bytes in @a buf
331 * @param udp_addr address of the sender
332 * @param udp_addr_len number of bytes in @a udp_addr
333 * @param network_type network type of the sender's address
334 */
335void
336udp_broadcast_receive (struct Plugin *plugin,
337 const char *buf,
338 ssize_t size,
339 const union UdpAddress *udp_addr,
340 size_t udp_addr_len,
341 enum GNUNET_NetworkType network_type);
342
343
344void
345setup_broadcast (struct Plugin *plugin,
346 struct sockaddr_in6 *server_addrv6,
347 struct sockaddr_in *server_addrv4);
348
349
350void
351stop_broadcast (struct Plugin *plugin);
352
353/*#ifndef PLUGIN_TRANSPORT_UDP_H*/
354#endif
355/* end of plugin_transport_udp.h */
diff --git a/src/transport/plugin_transport_udp_broadcasting.c b/src/transport/plugin_transport_udp_broadcasting.c
deleted file mode 100644
index a65f5bd2f..000000000
--- a/src/transport/plugin_transport_udp_broadcasting.c
+++ /dev/null
@@ -1,647 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2010, 2011 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/plugin_transport_udp_broadcasting.c
23 * @brief Neighbour discovery with UDP
24 * @author Christian Grothoff
25 * @author Matthias Wachs
26 */
27#include "platform.h"
28#include "plugin_transport_udp.h"
29#include "gnunet_hello_lib.h"
30#include "gnunet_util_lib.h"
31#include "gnunet_fragmentation_lib.h"
32#include "gnunet_protocols.h"
33#include "gnunet_resolver_service.h"
34#include "gnunet_signatures.h"
35#include "gnunet_constants.h"
36#include "gnunet_statistics_service.h"
37#include "gnunet_transport_service.h"
38#include "gnunet_transport_plugin.h"
39#include "transport.h"
40
41#define LOG(kind, ...) GNUNET_log_from (kind, "transport-udp", __VA_ARGS__)
42
43/* *********** Cryogenic ********** */
44#ifdef __linux__
45#include <sys/stat.h>
46#include <fcntl.h>
47
48#include <sys/ioctl.h>
49#include <sys/select.h>
50#include <sys/time.h>
51
52#define PM_MAGIC 'k'
53#define PM_SET_DELAY_AND_TIMEOUT _IOW (PM_MAGIC, 1, struct pm_times)
54
55struct pm_times
56{
57 unsigned long delay_msecs;
58 unsigned long timeout_msecs;
59};
60#endif
61/************************************/
62
63
64struct UDP_Beacon_Message
65{
66 /**
67 * Message header.
68 */
69 struct GNUNET_MessageHeader header;
70
71 /**
72 * What is the identity of the sender
73 */
74 struct GNUNET_PeerIdentity sender;
75};
76
77
78struct BroadcastAddress
79{
80 struct BroadcastAddress *next;
81
82 struct BroadcastAddress *prev;
83
84 /**
85 * ID of select broadcast task
86 */
87 struct GNUNET_SCHEDULER_Task *broadcast_task;
88
89 struct Plugin *plugin;
90
91 struct sockaddr *addr;
92
93 socklen_t addrlen;
94
95#ifdef __linux__
96 /**
97 * Cryogenic handle.
98 */
99 struct GNUNET_DISK_FileHandle *cryogenic_fd;
100
101 /**
102 * Time out for cryogenic.
103 */
104 struct pm_times cryogenic_times;
105#endif
106};
107
108
109/**
110 * Client-specific context for #broadcast_mst_cb().
111 */
112struct MstContext
113{
114 struct Plugin *plugin;
115
116 const union UdpAddress *udp_addr;
117
118 size_t udp_addr_len;
119
120 /**
121 * ATS network type.
122 */
123 enum GNUNET_NetworkType ats_address_network_type;
124};
125
126
127/**
128 * Parse broadcast message received.
129 *
130 * @param cls the `struct Plugin`
131 * @param client the `struct MstContext` with sender address
132 * @param message the message we received
133 * @return #GNUNET_OK (always)
134 */
135static int
136broadcast_mst_cb (void *cls,
137 const struct GNUNET_MessageHeader *message)
138{
139 struct MstContext *mc = cls;
140 struct Plugin *plugin = mc->plugin;
141 struct GNUNET_HELLO_Address *address;
142 const struct GNUNET_MessageHeader *hello;
143 const struct UDP_Beacon_Message *msg;
144
145 msg = (const struct UDP_Beacon_Message *) message;
146
147 if (GNUNET_MESSAGE_TYPE_TRANSPORT_BROADCAST_BEACON !=
148 ntohs (msg->header.type))
149 return GNUNET_OK;
150 LOG (GNUNET_ERROR_TYPE_DEBUG,
151 "Received beacon with %u bytes from peer `%s' via address `%s'\n",
152 ntohs (msg->header.size),
153 GNUNET_i2s (&msg->sender),
154 udp_address_to_string (NULL,
155 mc->udp_addr,
156 mc->udp_addr_len));
157 hello = (struct GNUNET_MessageHeader *) &msg[1];
158 address = GNUNET_HELLO_address_allocate (&msg->sender,
159 PLUGIN_NAME,
160 mc->udp_addr,
161 mc->udp_addr_len,
162 GNUNET_HELLO_ADDRESS_INFO_NONE);
163 plugin->env->receive (plugin->env->cls,
164 address,
165 NULL,
166 hello);
167 GNUNET_HELLO_address_free (address);
168 GNUNET_STATISTICS_update (plugin->env->stats,
169 _ ("# Multicast HELLO beacons received via UDP"),
170 1, GNUNET_NO);
171 return GNUNET_OK;
172}
173
174
175/**
176 * We received a broadcast message. Process it and all subsequent
177 * messages in the same packet.
178 *
179 * @param plugin the UDP plugin
180 * @param buf the buffer with the message(s)
181 * @param size number of bytes in @a buf
182 * @param udp_addr address of the sender
183 * @param udp_addr_len number of bytes in @a udp_addr
184 * @param network_type network type of the sender's address
185 */
186void
187udp_broadcast_receive (struct Plugin *plugin,
188 const char *buf,
189 ssize_t size,
190 const union UdpAddress *udp_addr,
191 size_t udp_addr_len,
192 enum GNUNET_NetworkType network_type)
193{
194 struct GNUNET_MessageStreamTokenizer *broadcast_mst;
195 struct MstContext mc;
196
197 broadcast_mst = GNUNET_MST_create (&broadcast_mst_cb,
198 &mc);
199 mc.plugin = plugin;
200 mc.udp_addr = udp_addr;
201 mc.udp_addr_len = udp_addr_len;
202 mc.ats_address_network_type = network_type;
203 GNUNET_MST_from_buffer (broadcast_mst,
204 buf, size,
205 GNUNET_NO,
206 GNUNET_NO);
207 GNUNET_MST_destroy (broadcast_mst);
208}
209
210
211static unsigned int
212prepare_beacon (struct Plugin *plugin,
213 struct UDP_Beacon_Message *msg)
214{
215 uint16_t hello_size;
216 uint16_t msg_size;
217
218 const struct GNUNET_MessageHeader *hello;
219
220 hello = plugin->env->get_our_hello ();
221 if (NULL == hello)
222 return 0;
223 hello_size = GNUNET_HELLO_size ((struct GNUNET_HELLO_Message *) hello);
224 msg_size = hello_size + sizeof(struct UDP_Beacon_Message);
225
226 if ((hello_size < (sizeof(struct GNUNET_MessageHeader))) ||
227 (msg_size > (UDP_MTU)))
228 return 0;
229
230 msg->sender = *(plugin->env->my_identity);
231 msg->header.size = htons (msg_size);
232 msg->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BROADCAST_BEACON);
233 GNUNET_memcpy (&msg[1], hello, hello_size);
234 return msg_size;
235}
236
237
238static void
239udp_ipv4_broadcast_send (void *cls)
240{
241 struct BroadcastAddress *baddr = cls;
242 struct Plugin *plugin = baddr->plugin;
243 int sent;
244 uint16_t msg_size;
245 char buf[65536] GNUNET_ALIGN;
246
247 baddr->broadcast_task = NULL;
248
249 msg_size = prepare_beacon (plugin, (struct UDP_Beacon_Message *) &buf);
250 if (0 != msg_size)
251 {
252 struct sockaddr_in *addr = (struct sockaddr_in *) baddr->addr;
253
254 addr->sin_port = htons (plugin->port);
255 sent = GNUNET_NETWORK_socket_sendto (plugin->sockv4, &buf, msg_size,
256 (const struct sockaddr *) addr,
257 baddr->addrlen);
258 if (sent == GNUNET_SYSERR)
259 {
260 if ((ENETUNREACH == errno) || (ENETDOWN == errno))
261 {
262 /* "Network unreachable" or "Network down"
263 *
264 * This indicates that we just do not have network connectivity
265 */
266 GNUNET_log (GNUNET_ERROR_TYPE_BULK | GNUNET_ERROR_TYPE_WARNING,
267 "Network connectivity is down, cannot send beacon!\n");
268 }
269 else
270 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sendto");
271 }
272 else
273 {
274 LOG (GNUNET_ERROR_TYPE_DEBUG,
275 "Sent HELLO beacon broadcast with %i bytes to address %s\n", sent,
276 GNUNET_a2s (baddr->addr, baddr->addrlen));
277 }
278 }
279
280#ifdef __linux__
281 /*
282 * Cryogenic
283 */
284 if (NULL != baddr->cryogenic_fd)
285 {
286 baddr->cryogenic_times.delay_msecs =
287 (plugin->broadcast_interval.rel_value_us / 1000.0) * 0.5;
288 baddr->cryogenic_times.timeout_msecs =
289 (plugin->broadcast_interval.rel_value_us / 1000.0) * 1.5;
290
291 if (ioctl (baddr->cryogenic_fd->fd,
292 PM_SET_DELAY_AND_TIMEOUT,
293 &baddr->cryogenic_times) < 0)
294 {
295 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "ioctl");
296 baddr->broadcast_task =
297 GNUNET_SCHEDULER_add_delayed (plugin->broadcast_interval,
298 &udp_ipv4_broadcast_send, baddr);
299 }
300 else
301 GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL,
302 baddr->cryogenic_fd,
303 &udp_ipv4_broadcast_send,
304 baddr);
305 }
306 else
307#endif
308 baddr->broadcast_task =
309 GNUNET_SCHEDULER_add_delayed (plugin->broadcast_interval,
310 &udp_ipv4_broadcast_send, baddr);
311}
312
313
314static void
315udp_ipv6_broadcast_send (void *cls)
316{
317 struct BroadcastAddress *baddr = cls;
318 struct Plugin *plugin = baddr->plugin;
319 ssize_t sent;
320 uint16_t msg_size;
321 char buf[65536] GNUNET_ALIGN;
322 const struct sockaddr_in6 *s6 = (const struct sockaddr_in6 *) baddr->addr;
323
324 baddr->broadcast_task = NULL;
325
326 msg_size = prepare_beacon (plugin, (struct UDP_Beacon_Message *) &buf);
327 /* Note: unclear if this actually works to limit the multicast to
328 the specified interface as we're not (necessarily) using a
329 link-local multicast group and the kernel suggests that the
330 scope ID is only respected for link-local addresses; however,
331 if the scope ID is ignored, the kernel should just multicast
332 on ALL interfaces, which is merely slightly less efficient;
333 in that case, we might want to revert to only doing this
334 once, and not per interface (hard to test...) */plugin->ipv6_multicast_address.sin6_scope_id = s6->sin6_scope_id;
335 sent = GNUNET_NETWORK_socket_sendto (plugin->sockv6, &buf, msg_size,
336 (const struct sockaddr *)
337 &plugin->ipv6_multicast_address,
338 sizeof(struct sockaddr_in6));
339 plugin->ipv6_multicast_address.sin6_scope_id = 0;
340 if (sent == GNUNET_SYSERR)
341 {
342 if ((ENETUNREACH == errno) || (ENETDOWN == errno))
343 {
344 /* "Network unreachable" or "Network down"
345 *
346 * This indicates that this system is IPv6 enabled, but does not
347 * have a valid global IPv6 address assigned
348 */GNUNET_log (GNUNET_ERROR_TYPE_BULK | GNUNET_ERROR_TYPE_WARNING,
349 "Network connectivity is down, cannot send beacon!\n");
350 }
351 else
352 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sendto");
353 }
354 else
355 {
356 LOG (GNUNET_ERROR_TYPE_DEBUG,
357 "Sending IPv6 HELLO beacon broadcast with %d bytes to address %s\n",
358 (int) sent,
359 GNUNET_a2s ((const struct sockaddr *) &plugin->ipv6_multicast_address,
360 sizeof(struct sockaddr_in6)));
361 }
362#ifdef __linux__
363 /*
364 * Cryogenic
365 */
366 if (NULL != baddr->cryogenic_fd)
367 {
368 baddr->cryogenic_times.delay_msecs =
369 (plugin->broadcast_interval.rel_value_us / 1000.0) * 0.5;
370 baddr->cryogenic_times.timeout_msecs =
371 (plugin->broadcast_interval.rel_value_us / 1000.0) * 1.5;
372
373 if (ioctl (baddr->cryogenic_fd->fd,
374 PM_SET_DELAY_AND_TIMEOUT,
375 &baddr->cryogenic_times) < 0)
376 {
377 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "ioctl");
378 baddr->broadcast_task =
379 GNUNET_SCHEDULER_add_delayed (plugin->broadcast_interval,
380 &udp_ipv6_broadcast_send, baddr);
381 }
382 else
383 GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL,
384 baddr->cryogenic_fd,
385 &udp_ipv6_broadcast_send,
386 baddr);
387 }
388 else
389#endif
390 baddr->broadcast_task =
391 GNUNET_SCHEDULER_add_delayed (plugin->broadcast_interval,
392 &udp_ipv6_broadcast_send, baddr);
393}
394
395
396/**
397 * Callback function invoked for each interface found.
398 *
399 * @param cls closure with the `struct Plugin`
400 * @param name name of the interface (can be NULL for unknown)
401 * @param isDefault is this presumably the default interface
402 * @param addr address of this interface (can be NULL for unknown or unassigned)
403 * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned)
404 * @param netmask the network mask (can be NULL for unknown or unassigned)
405 * @param addrlen length of the address
406 * @return #GNUNET_OK to continue iteration, #GNUNET_SYSERR to abort
407 */
408static int
409iface_proc (void *cls,
410 const char *name,
411 int isDefault,
412 const struct sockaddr *addr,
413 const struct sockaddr *broadcast_addr,
414 const struct sockaddr *netmask, socklen_t addrlen)
415{
416 struct Plugin *plugin = cls;
417 struct BroadcastAddress *ba;
418 enum GNUNET_NetworkType network;
419
420 if (NULL == addr)
421 return GNUNET_OK;
422 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
423 "address %s for interface %s %p\n ",
424 GNUNET_a2s (addr, addrlen), name, addr);
425 if (NULL == broadcast_addr)
426 return GNUNET_OK;
427 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
428 "broadcast address %s for interface %s %p\n ",
429 GNUNET_a2s (broadcast_addr, addrlen), name, broadcast_addr);
430 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "netmask %s for interface %s %p\n ",
431 GNUNET_a2s (netmask, addrlen), name, netmask);
432
433 network = plugin->env->get_address_type (plugin->env->cls, broadcast_addr,
434 addrlen);
435 if (GNUNET_NT_LOOPBACK == network)
436 {
437 /* Broadcasting on loopback does not make sense */
438 return GNUNET_YES;
439 }
440
441 ba = GNUNET_new (struct BroadcastAddress);
442 ba->plugin = plugin;
443 ba->addr = GNUNET_malloc (addrlen);
444 GNUNET_memcpy (ba->addr, broadcast_addr, addrlen);
445 ba->addrlen = addrlen;
446
447 if ((GNUNET_YES == plugin->enable_ipv4) &&
448 (NULL != plugin->sockv4) &&
449 (addrlen == sizeof(struct sockaddr_in)))
450 {
451#ifdef __linux__
452 /*
453 * setup Cryogenic FD for ipv4 broadcasting
454 */
455 char *filename;
456
457 GNUNET_asprintf (&filename,
458 "/dev/cryogenic/%s",
459 name);
460 if (0 == access (name, R_OK))
461 {
462 ba->cryogenic_fd =
463 GNUNET_DISK_file_open (filename,
464 GNUNET_DISK_OPEN_WRITE,
465 GNUNET_DISK_PERM_NONE);
466 }
467 GNUNET_free (filename);
468#endif
469 ba->broadcast_task =
470 GNUNET_SCHEDULER_add_now (&udp_ipv4_broadcast_send, ba);
471 }
472 if ((GNUNET_YES == plugin->enable_ipv6) &&
473 (NULL != plugin->sockv6) &&
474 (addrlen == sizeof(struct sockaddr_in6)))
475 {
476 /* Create IPv6 multicast request */
477 struct ipv6_mreq multicastRequest;
478 const struct sockaddr_in6 *s6 = (const struct
479 sockaddr_in6 *) broadcast_addr;
480
481 multicastRequest.ipv6mr_multiaddr =
482 plugin->ipv6_multicast_address.sin6_addr;
483 /* http://tools.ietf.org/html/rfc2553#section-5.2:
484 *
485 * IPV6_JOIN_GROUP
486 *
487 * Join a multicast group on a specified local interface. If the
488 * interface index is specified as 0, the kernel chooses the local
489 * interface. For example, some kernels look up the multicast
490 * group in the normal IPv6 routing table and using the resulting
491 * interface; we do this for each interface, so no need to use
492 * zero (anymore...).
493 */multicastRequest.ipv6mr_interface = s6->sin6_scope_id;
494
495 /* Join the multicast group */
496 if (GNUNET_OK !=
497 GNUNET_NETWORK_socket_setsockopt
498 (plugin->sockv6, IPPROTO_IPV6, IPV6_JOIN_GROUP,
499 &multicastRequest, sizeof(multicastRequest)))
500 {
501 LOG (GNUNET_ERROR_TYPE_WARNING,
502 "Failed to join IPv6 multicast group: IPv6 broadcasting not running\n");
503 }
504 else
505 {
506#ifdef __linux__
507 /*
508 * setup Cryogenic FD for ipv6 broadcasting
509 */
510 char *filename;
511
512 GNUNET_asprintf (&filename,
513 "/dev/cryogenic/%s",
514 name);
515 if (0 == access (name, R_OK))
516 {
517 ba->cryogenic_fd =
518 GNUNET_DISK_file_open (filename,
519 GNUNET_DISK_OPEN_WRITE,
520 GNUNET_DISK_PERM_NONE);
521 }
522 GNUNET_free (filename);
523#endif
524 ba->broadcast_task =
525 GNUNET_SCHEDULER_add_now (&udp_ipv6_broadcast_send, ba);
526 }
527 }
528 GNUNET_CONTAINER_DLL_insert (plugin->broadcast_head,
529 plugin->broadcast_tail, ba);
530 return GNUNET_OK;
531}
532
533
534/**
535 * Setup broadcasting subsystem.
536 *
537 * @param plugin
538 * @param server_addrv6
539 * @param server_addrv4
540 */
541void
542setup_broadcast (struct Plugin *plugin,
543 struct sockaddr_in6 *server_addrv6,
544 struct sockaddr_in *server_addrv4)
545{
546 if (GNUNET_YES ==
547 GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg,
548 "topology",
549 "FRIENDS-ONLY"))
550 {
551 LOG (GNUNET_ERROR_TYPE_WARNING,
552 _ (
553 "Disabling HELLO broadcasting due to friend-to-friend only configuration!\n"));
554 return;
555 }
556
557 if (GNUNET_YES != plugin->enable_broadcasting)
558 return; /* We do not send, just receive */
559
560 /* create IPv4 broadcast socket */
561 if ((GNUNET_YES == plugin->enable_ipv4) && (NULL != plugin->sockv4))
562 {
563 static int yes = 1;
564
565 if (GNUNET_NETWORK_socket_setsockopt
566 (plugin->sockv4, SOL_SOCKET, SO_BROADCAST, &yes,
567 sizeof(int)) != GNUNET_OK)
568 {
569 LOG (GNUNET_ERROR_TYPE_WARNING,
570 _ (
571 "Failed to set IPv4 broadcast option for broadcast socket on port %d\n"),
572 ntohs (server_addrv4->sin_port));
573 }
574 }
575 /* create IPv6 multicast socket */
576 if ((GNUNET_YES == plugin->enable_ipv6) && (plugin->sockv6 != NULL))
577 {
578 memset (&plugin->ipv6_multicast_address, 0, sizeof(struct sockaddr_in6));
579 GNUNET_assert (1 ==
580 inet_pton (AF_INET6, "FF05::13B",
581 &plugin->ipv6_multicast_address.sin6_addr));
582 plugin->ipv6_multicast_address.sin6_family = AF_INET6;
583 plugin->ipv6_multicast_address.sin6_port = htons (plugin->port);
584 }
585 GNUNET_OS_network_interfaces_list (&iface_proc, plugin);
586}
587
588
589/**
590 * Stop broadcasting subsystem.
591 *
592 * @param plugin
593 */
594void
595stop_broadcast (struct Plugin *plugin)
596{
597 if (GNUNET_YES == plugin->enable_broadcasting)
598 {
599 /* Disable broadcasting */
600 while (plugin->broadcast_head != NULL)
601 {
602 struct BroadcastAddress *p = plugin->broadcast_head;
603
604 if (p->broadcast_task != NULL)
605 {
606 GNUNET_SCHEDULER_cancel (p->broadcast_task);
607 p->broadcast_task = NULL;
608 }
609 if ((GNUNET_YES == plugin->enable_ipv6) &&
610 (NULL != plugin->sockv6) &&
611 (p->addrlen == sizeof(struct sockaddr_in6)))
612 {
613 /* Create IPv6 multicast request */
614 struct ipv6_mreq multicastRequest;
615 const struct sockaddr_in6 *s6 = (const struct sockaddr_in6 *) p->addr;
616
617 multicastRequest.ipv6mr_multiaddr =
618 plugin->ipv6_multicast_address.sin6_addr;
619 multicastRequest.ipv6mr_interface = s6->sin6_scope_id;
620
621 /* Leave the multicast group */
622 if (GNUNET_OK ==
623 GNUNET_NETWORK_socket_setsockopt
624 (plugin->sockv6, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
625 &multicastRequest, sizeof(multicastRequest)))
626 {
627 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "setsockopt");
628 }
629 else
630 {
631 LOG (GNUNET_ERROR_TYPE_DEBUG, "IPv6 multicasting stopped\n");
632 }
633 }
634
635#ifdef __linux__
636 GNUNET_DISK_file_close (p->cryogenic_fd);
637#endif
638 GNUNET_CONTAINER_DLL_remove (plugin->broadcast_head,
639 plugin->broadcast_tail, p);
640 GNUNET_free (p->addr);
641 GNUNET_free (p);
642 }
643 }
644}
645
646
647/* end of plugin_transport_udp_broadcasting.c */
diff --git a/src/transport/plugin_transport_unix.c b/src/transport/plugin_transport_unix.c
deleted file mode 100644
index 269949a99..000000000
--- a/src/transport/plugin_transport_unix.c
+++ /dev/null
@@ -1,1890 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2010-2014 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/plugin_transport_unix.c
23 * @brief Transport plugin using unix domain sockets (!)
24 * Clearly, can only be used locally on Unix/Linux hosts...
25 * ONLY INTENDED FOR TESTING!!!
26 * @author Christian Grothoff
27 * @author Nathan Evans
28 */
29#include "platform.h"
30#include "gnunet_util_lib.h"
31#include "gnunet_hello_lib.h"
32#include "gnunet_protocols.h"
33#include "gnunet_statistics_service.h"
34#include "gnunet_transport_service.h"
35#include "gnunet_transport_plugin.h"
36#include "transport.h"
37
38
39/**
40 * Return code we give on 'send' if we failed to send right now
41 * but it makes sense to retry later. (Note: we might want to
42 * move this to the plugin API!?).
43 */
44#define RETRY 0
45
46/**
47 * Name of the plugin.
48 */
49#define PLUGIN_NAME "unix"
50
51/**
52 * Options for UNIX Domain addresses.
53 */
54enum UNIX_ADDRESS_OPTIONS
55{
56 /**
57 * No special options.
58 */
59 UNIX_OPTIONS_NONE = 0,
60
61 /**
62 * Linux abstract domain sockets should be used.
63 */
64 UNIX_OPTIONS_USE_ABSTRACT_SOCKETS = 1
65};
66
67
68/**
69 * How long until we give up on transmitting the welcome message?
70 */
71#define HOSTNAME_RESOLVE_TIMEOUT \
72 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
73
74#define LOG(kind, ...) GNUNET_log_from (kind, "transport-unix", __VA_ARGS__)
75
76
77GNUNET_NETWORK_STRUCT_BEGIN
78
79/**
80 * Binary format for an UNIX Domain Socket address in GNUnet.
81 */
82struct UnixAddress
83{
84 /**
85 * Options to use for the address, in NBO
86 */
87 uint32_t options GNUNET_PACKED;
88
89 /**
90 * Length of the address (path length), in NBO
91 */
92 uint32_t addrlen GNUNET_PACKED;
93
94 /* followed by actual path */
95};
96
97
98/**
99 * UNIX Message-Packet header.
100 */
101struct UNIXMessage
102{
103 /**
104 * Message header.
105 */
106 struct GNUNET_MessageHeader header;
107
108 /**
109 * What is the identity of the sender (GNUNET_hash of public key)
110 */
111 struct GNUNET_PeerIdentity sender;
112};
113
114GNUNET_NETWORK_STRUCT_END
115
116
117/**
118 * Information we track for a message awaiting transmission.
119 */
120struct UNIXMessageWrapper
121{
122 /**
123 * We keep messages in a doubly linked list.
124 */
125 struct UNIXMessageWrapper *next;
126
127 /**
128 * We keep messages in a doubly linked list.
129 */
130 struct UNIXMessageWrapper *prev;
131
132 /**
133 * The actual payload (allocated separately right now).
134 */
135 struct UNIXMessage *msg;
136
137 /**
138 * Session this message belongs to.
139 */
140 struct GNUNET_ATS_Session *session;
141
142 /**
143 * Function to call upon transmission.
144 */
145 GNUNET_TRANSPORT_TransmitContinuation cont;
146
147 /**
148 * Closure for @e cont.
149 */
150 void *cont_cls;
151
152 /**
153 * Timeout for this message.
154 */
155 struct GNUNET_TIME_Absolute timeout;
156
157 /**
158 * Number of bytes in @e msg.
159 */
160 size_t msgsize;
161
162 /**
163 * Number of bytes of payload encapsulated in @e msg.
164 */
165 size_t payload;
166
167 /**
168 * Priority of the message (ignored, just dragged along in UNIX).
169 */
170 unsigned int priority;
171};
172
173
174/**
175 * Handle for a session.
176 */
177struct GNUNET_ATS_Session
178{
179 /**
180 * Sessions with pending messages (!) are kept in a DLL.
181 */
182 struct GNUNET_ATS_Session *next;
183
184 /**
185 * Sessions with pending messages (!) are kept in a DLL.
186 */
187 struct GNUNET_ATS_Session *prev;
188
189 /**
190 * To whom are we talking to (set to our identity
191 * if we are still waiting for the welcome message).
192 *
193 * FIXME: information duplicated with 'peer' in address!
194 */
195 struct GNUNET_PeerIdentity target;
196
197 /**
198 * Pointer to the global plugin struct.
199 */
200 struct Plugin *plugin;
201
202 /**
203 * Address of the other peer.
204 */
205 struct GNUNET_HELLO_Address *address;
206
207 /**
208 * Number of bytes we currently have in our write queue.
209 */
210 unsigned long long bytes_in_queue;
211
212 /**
213 * Timeout for this session.
214 */
215 struct GNUNET_TIME_Absolute timeout;
216
217 /**
218 * Session timeout task.
219 */
220 struct GNUNET_SCHEDULER_Task *timeout_task;
221
222 /**
223 * Number of messages we currently have in our write queue.
224 */
225 unsigned int msgs_in_queue;
226};
227
228
229/**
230 * Encapsulation of all of the state of the plugin.
231 */
232struct Plugin;
233
234
235/**
236 * Information we keep for each of our listen sockets.
237 */
238struct UNIX_Sock_Info
239{
240 /**
241 * The network handle
242 */
243 struct GNUNET_NETWORK_Handle *desc;
244};
245
246
247/**
248 * Encapsulation of all of the state of the plugin.
249 */
250struct Plugin
251{
252 /**
253 * ID of task used to update our addresses when one expires.
254 */
255 struct GNUNET_SCHEDULER_Task *address_update_task;
256
257 /**
258 * ID of read task
259 */
260 struct GNUNET_SCHEDULER_Task *read_task;
261
262 /**
263 * ID of write task
264 */
265 struct GNUNET_SCHEDULER_Task *write_task;
266
267 /**
268 * Number of bytes we currently have in our write queues.
269 */
270 unsigned long long bytes_in_queue;
271
272 /**
273 * Our environment.
274 */
275 struct GNUNET_TRANSPORT_PluginEnvironment *env;
276
277 /**
278 * Sessions (map from peer identity to `struct GNUNET_ATS_Session`)
279 */
280 struct GNUNET_CONTAINER_MultiPeerMap *session_map;
281
282 /**
283 * Head of queue of messages to transmit.
284 */
285 struct UNIXMessageWrapper *msg_head;
286
287 /**
288 * Tail of queue of messages to transmit.
289 */
290 struct UNIXMessageWrapper *msg_tail;
291
292 /**
293 * Path of our unix domain socket (/tmp/unix-plugin)
294 */
295 char *unix_socket_path;
296
297 /**
298 * Function to call about session status changes.
299 */
300 GNUNET_TRANSPORT_SessionInfoCallback sic;
301
302 /**
303 * Closure for @e sic.
304 */
305 void *sic_cls;
306
307 /**
308 * socket that we transmit all data with
309 */
310 struct UNIX_Sock_Info unix_sock;
311
312 /**
313 * Address options in HBO
314 */
315 uint32_t myoptions;
316
317 /**
318 * Are we using an abstract UNIX domain socket?
319 */
320 int is_abstract;
321};
322
323
324/**
325 * If a session monitor is attached, notify it about the new
326 * session state.
327 *
328 * @param plugin our plugin
329 * @param session session that changed state
330 * @param state new state of the session
331 */
332static void
333notify_session_monitor (struct Plugin *plugin,
334 struct GNUNET_ATS_Session *session,
335 enum GNUNET_TRANSPORT_SessionState state)
336{
337 struct GNUNET_TRANSPORT_SessionInfo info;
338
339 if (NULL == plugin->sic)
340 return;
341 memset (&info, 0, sizeof(info));
342 info.state = state;
343 info.is_inbound = GNUNET_SYSERR; /* hard to say */
344 info.num_msg_pending = session->msgs_in_queue;
345 info.num_bytes_pending = session->bytes_in_queue;
346 /* info.receive_delay remains zero as this is not supported by UNIX
347 (cannot selectively not receive from 'some' peer while continuing
348 to receive from others) */
349 info.session_timeout = session->timeout;
350 info.address = session->address;
351 plugin->sic (plugin->sic_cls, session, &info);
352}
353
354
355/**
356 * Function called for a quick conversion of the binary address to
357 * a numeric address. Note that the caller must not free the
358 * address and that the next call to this function is allowed
359 * to override the address again.
360 *
361 * @param cls closure
362 * @param addr binary address
363 * @param addrlen length of the @a addr
364 * @return string representing the same address
365 */
366static const char *
367unix_plugin_address_to_string (void *cls, const void *addr, size_t addrlen)
368{
369 static char rbuf[1024];
370 struct UnixAddress *ua = (struct UnixAddress *) addr;
371 char *addrstr;
372 size_t addr_str_len;
373 unsigned int off;
374
375 if ((NULL == addr) || (sizeof(struct UnixAddress) > addrlen))
376 {
377 GNUNET_break (0);
378 return NULL;
379 }
380 addrstr = (char *) &ua[1];
381 addr_str_len = ntohl (ua->addrlen);
382
383 if (addr_str_len != addrlen - sizeof(struct UnixAddress))
384 {
385 GNUNET_break (0);
386 return NULL;
387 }
388 if ('\0' != addrstr[addr_str_len - 1])
389 {
390 GNUNET_break (0);
391 return NULL;
392 }
393 if (strlen (addrstr) + 1 != addr_str_len)
394 {
395 GNUNET_break (0);
396 return NULL;
397 }
398
399 off = 0;
400 if ('\0' == addrstr[0])
401 off++;
402 memset (rbuf, 0, sizeof(rbuf));
403 GNUNET_snprintf (rbuf,
404 sizeof(rbuf) - 1,
405 "%s.%u.%s%.*s",
406 PLUGIN_NAME,
407 ntohl (ua->options),
408 (off == 1) ? "@" : "",
409 (int) (addr_str_len - off),
410 &addrstr[off]);
411 return rbuf;
412}
413
414
415/**
416 * Functions with this signature are called whenever we need
417 * to close a session due to a disconnect or failure to
418 * establish a connection.
419 *
420 * @param cls closure with the `struct Plugin *`
421 * @param session session to close down
422 * @return #GNUNET_OK on success
423 */
424static int
425unix_plugin_session_disconnect (void *cls, struct GNUNET_ATS_Session *session)
426{
427 struct Plugin *plugin = cls;
428 struct UNIXMessageWrapper *msgw;
429 struct UNIXMessageWrapper *next;
430
431 LOG (GNUNET_ERROR_TYPE_DEBUG,
432 "Disconnecting session for peer `%s' `%s'\n",
433 GNUNET_i2s (&session->target),
434 unix_plugin_address_to_string (NULL,
435 session->address->address,
436 session->address->address_length));
437 plugin->env->session_end (plugin->env->cls, session->address, session);
438 next = plugin->msg_head;
439 while (NULL != next)
440 {
441 msgw = next;
442 next = msgw->next;
443 if (msgw->session != session)
444 continue;
445 GNUNET_CONTAINER_DLL_remove (plugin->msg_head, plugin->msg_tail, msgw);
446 session->msgs_in_queue--;
447 GNUNET_assert (session->bytes_in_queue >= msgw->msgsize);
448 session->bytes_in_queue -= msgw->msgsize;
449 GNUNET_assert (plugin->bytes_in_queue >= msgw->msgsize);
450 plugin->bytes_in_queue -= msgw->msgsize;
451 if (NULL != msgw->cont)
452 msgw->cont (msgw->cont_cls,
453 &msgw->session->target,
454 GNUNET_SYSERR,
455 msgw->payload,
456 0);
457 GNUNET_free (msgw->msg);
458 GNUNET_free (msgw);
459 }
460 GNUNET_assert (GNUNET_YES ==
461 GNUNET_CONTAINER_multipeermap_remove (plugin->session_map,
462 &session->target,
463 session));
464 GNUNET_STATISTICS_set (plugin->env->stats,
465 "# UNIX sessions active",
466 GNUNET_CONTAINER_multipeermap_size (
467 plugin->session_map),
468 GNUNET_NO);
469 if (NULL != session->timeout_task)
470 {
471 GNUNET_SCHEDULER_cancel (session->timeout_task);
472 session->timeout_task = NULL;
473 session->timeout = GNUNET_TIME_UNIT_ZERO_ABS;
474 }
475 notify_session_monitor (plugin, session, GNUNET_TRANSPORT_SS_DONE);
476 GNUNET_HELLO_address_free (session->address);
477 GNUNET_break (0 == session->bytes_in_queue);
478 GNUNET_break (0 == session->msgs_in_queue);
479 GNUNET_free (session);
480 return GNUNET_OK;
481}
482
483
484/**
485 * Session was idle for too long, so disconnect it
486 *
487 * @param cls the `struct GNUNET_ATS_Session *` to disconnect
488 */
489static void
490session_timeout (void *cls)
491{
492 struct GNUNET_ATS_Session *session = cls;
493 struct GNUNET_TIME_Relative left;
494
495 session->timeout_task = NULL;
496 left = GNUNET_TIME_absolute_get_remaining (session->timeout);
497 if (0 != left.rel_value_us)
498 {
499 /* not actually our turn yet, but let's at least update
500 the monitor, it may think we're about to die ... */
501 notify_session_monitor (session->plugin,
502 session,
503 GNUNET_TRANSPORT_SS_UPDATE);
504 session->timeout_task =
505 GNUNET_SCHEDULER_add_delayed (left, &session_timeout, session);
506 return;
507 }
508 LOG (GNUNET_ERROR_TYPE_DEBUG,
509 "Session %p was idle for %s, disconnecting\n",
510 session,
511 GNUNET_STRINGS_relative_time_to_string (
512 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
513 GNUNET_YES));
514 unix_plugin_session_disconnect (session->plugin, session);
515}
516
517
518/**
519 * Increment session timeout due to activity. We do not immediately
520 * notify the monitor here as that might generate excessive
521 * signalling.
522 *
523 * @param session session for which the timeout should be rescheduled
524 */
525static void
526reschedule_session_timeout (struct GNUNET_ATS_Session *session)
527{
528 GNUNET_assert (NULL != session->timeout_task);
529 session->timeout =
530 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
531}
532
533
534/**
535 * Convert unix path to a `struct sockaddr_un *`
536 *
537 * @param unixpath path to convert
538 * @param[out] sock_len set to the length of the address
539 * @return converted unix path
540 */
541static struct sockaddr_un *
542unix_address_to_sockaddr (const char *unixpath, socklen_t *sock_len)
543{
544 struct sockaddr_un *un;
545 size_t slen;
546
547 GNUNET_assert (0 < strlen (unixpath)); /* sanity check */
548 un = GNUNET_new (struct sockaddr_un);
549 un->sun_family = AF_UNIX;
550 slen = strlen (unixpath);
551 if (slen >= sizeof(un->sun_path))
552 slen = sizeof(un->sun_path) - 1;
553 GNUNET_memcpy (un->sun_path, unixpath, slen);
554 un->sun_path[slen] = '\0';
555 slen = sizeof(struct sockaddr_un);
556#if HAVE_SOCKADDR_UN_SUN_LEN
557 un->sun_len = (u_char) slen;
558#endif
559 (*sock_len) = slen;
560 return un;
561}
562
563
564/**
565 * Closure to #lookup_session_it().
566 */
567struct LookupCtx
568{
569 /**
570 * Location to store the session, if found.
571 */
572 struct GNUNET_ATS_Session *res;
573
574 /**
575 * Address we are looking for.
576 */
577 const struct GNUNET_HELLO_Address *address;
578};
579
580
581/**
582 * Function called to find a session by address.
583 *
584 * @param cls the `struct LookupCtx *`
585 * @param key peer we are looking for (unused)
586 * @param value a session
587 * @return #GNUNET_YES if not found (continue looking), #GNUNET_NO on success
588 */
589static int
590lookup_session_it (void *cls,
591 const struct GNUNET_PeerIdentity *key,
592 void *value)
593{
594 struct LookupCtx *lctx = cls;
595 struct GNUNET_ATS_Session *session = value;
596
597 if (0 == GNUNET_HELLO_address_cmp (lctx->address, session->address))
598 {
599 lctx->res = session;
600 return GNUNET_NO;
601 }
602 return GNUNET_YES;
603}
604
605
606/**
607 * Find an existing session by address.
608 *
609 * @param plugin the plugin
610 * @param address the address to find
611 * @return NULL if session was not found
612 */
613static struct GNUNET_ATS_Session *
614lookup_session (struct Plugin *plugin,
615 const struct GNUNET_HELLO_Address *address)
616{
617 struct LookupCtx lctx;
618
619 lctx.address = address;
620 lctx.res = NULL;
621 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->session_map,
622 &address->peer,
623 &lookup_session_it,
624 &lctx);
625 return lctx.res;
626}
627
628
629/**
630 * Function that is called to get the keepalive factor.
631 * #GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT is divided by this number to
632 * calculate the interval between keepalive packets.
633 *
634 * @param cls closure with the `struct Plugin`
635 * @return keepalive factor
636 */
637static unsigned int
638unix_plugin_query_keepalive_factor (void *cls)
639{
640 return 3;
641}
642
643
644/**
645 * Actually send out the message, assume we've got the address and
646 * send_handle squared away!
647 *
648 * @param cls closure
649 * @param send_handle which handle to send message on
650 * @param target who should receive this message (ignored by UNIX)
651 * @param msgbuf one or more GNUNET_MessageHeader(s) strung together
652 * @param msgbuf_size the size of the @a msgbuf to send
653 * @param priority how important is the message (ignored by UNIX)
654 * @param timeout when should we time out (give up) if we can not transmit?
655 * @param addr the addr to send the message to, needs to be a sockaddr for us
656 * @param addrlen the len of @a addr
657 * @param payload bytes payload to send
658 * @param cont continuation to call once the message has
659 * been transmitted (or if the transport is ready
660 * for the next transmission call; or if the
661 * peer disconnected...)
662 * @param cont_cls closure for @a cont
663 * @return on success the number of bytes written, RETRY for retry, -1 on errors
664 */
665static ssize_t
666unix_real_send (void *cls,
667 struct GNUNET_NETWORK_Handle *send_handle,
668 const struct GNUNET_PeerIdentity *target,
669 const char *msgbuf,
670 size_t msgbuf_size,
671 unsigned int priority,
672 struct GNUNET_TIME_Absolute timeout,
673 const struct UnixAddress *addr,
674 size_t addrlen,
675 size_t payload,
676 GNUNET_TRANSPORT_TransmitContinuation cont,
677 void *cont_cls)
678{
679 struct Plugin *plugin = cls;
680 ssize_t sent;
681 struct sockaddr_un *un;
682 socklen_t un_len;
683 const char *unixpath;
684
685 if (NULL == send_handle)
686 {
687 GNUNET_break (0); /* We do not have a send handle */
688 return GNUNET_SYSERR;
689 }
690 if ((NULL == addr) || (0 == addrlen))
691 {
692 GNUNET_break (0); /* Can never send if we don't have an address */
693 return GNUNET_SYSERR;
694 }
695
696 /* Prepare address */
697 unixpath = (const char *) &addr[1];
698 if (NULL == (un = unix_address_to_sockaddr (unixpath, &un_len)))
699 {
700 GNUNET_break (0);
701 return -1;
702 }
703
704 if ((GNUNET_YES == plugin->is_abstract) &&
705 (0 != (UNIX_OPTIONS_USE_ABSTRACT_SOCKETS & ntohl (addr->options))))
706 {
707 un->sun_path[0] = '\0';
708 }
709resend:
710 /* Send the data */
711 sent = GNUNET_NETWORK_socket_sendto (send_handle,
712 msgbuf,
713 msgbuf_size,
714 (const struct sockaddr *) un,
715 un_len);
716 if (GNUNET_SYSERR == sent)
717 {
718 if ((EAGAIN == errno) || (ENOBUFS == errno))
719 {
720 GNUNET_free (un);
721 return RETRY; /* We have to retry later */
722 }
723 if (EMSGSIZE == errno)
724 {
725 socklen_t size = 0;
726 socklen_t len = sizeof(size);
727
728 GNUNET_NETWORK_socket_getsockopt ((struct GNUNET_NETWORK_Handle *)
729 send_handle,
730 SOL_SOCKET,
731 SO_SNDBUF,
732 &size,
733 &len);
734 if (size < msgbuf_size)
735 {
736 LOG (GNUNET_ERROR_TYPE_DEBUG,
737 "Trying to increase socket buffer size from %u to %u for message size %u\n",
738 (unsigned int) size,
739 (unsigned int) ((msgbuf_size / 1000) + 2) * 1000,
740 (unsigned int) msgbuf_size);
741 size = ((msgbuf_size / 1000) + 2) * 1000;
742 if (GNUNET_OK ==
743 GNUNET_NETWORK_socket_setsockopt ((struct GNUNET_NETWORK_Handle *)
744 send_handle,
745 SOL_SOCKET,
746 SO_SNDBUF,
747 &size,
748 sizeof(size)))
749 goto resend; /* Increased buffer size, retry sending */
750 else
751 {
752 /* Could not increase buffer size: error, no retry */
753 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "setsockopt");
754 GNUNET_free (un);
755 return GNUNET_SYSERR;
756 }
757 }
758 else
759 {
760 /* Buffer is bigger than message: error, no retry
761 * This should never happen!*/
762 GNUNET_break (0);
763 GNUNET_free (un);
764 return GNUNET_SYSERR;
765 }
766 }
767 }
768
769 LOG (GNUNET_ERROR_TYPE_DEBUG,
770 "UNIX transmitted %u-byte message to %s (%d: %s)\n",
771 (unsigned int) msgbuf_size,
772 GNUNET_a2s ((const struct sockaddr *) un, un_len),
773 (int) sent,
774 (sent < 0) ? strerror (errno) : "ok");
775 GNUNET_free (un);
776 return sent;
777}
778
779
780/**
781 * Function obtain the network type for a session
782 *
783 * @param cls closure ('struct Plugin*')
784 * @param session the session
785 * @return the network type in HBO or #GNUNET_SYSERR
786 */
787static enum GNUNET_NetworkType
788unix_plugin_get_network (void *cls, struct GNUNET_ATS_Session *session)
789{
790 GNUNET_assert (NULL != session);
791 return GNUNET_NT_LOOPBACK;
792}
793
794
795/**
796 * Function obtain the network type for a session
797 *
798 * @param cls closure (`struct Plugin *`)
799 * @param address the address
800 * @return the network type
801 */
802static enum GNUNET_NetworkType
803unix_plugin_get_network_for_address (void *cls,
804 const struct GNUNET_HELLO_Address *address)
805{
806 return GNUNET_NT_LOOPBACK;
807}
808
809
810/**
811 * Creates a new outbound session the transport service will use to send data to the
812 * peer
813 *
814 * @param cls the plugin
815 * @param address the address
816 * @return the session or NULL of max connections exceeded
817 */
818static struct GNUNET_ATS_Session *
819unix_plugin_get_session (void *cls, const struct GNUNET_HELLO_Address *address)
820{
821 struct Plugin *plugin = cls;
822 struct GNUNET_ATS_Session *session;
823 struct UnixAddress *ua;
824 char *addrstr;
825 uint32_t addr_str_len;
826 uint32_t addr_option;
827
828 ua = (struct UnixAddress *) address->address;
829 if ((NULL == address->address) || (0 == address->address_length) ||
830 (sizeof(struct UnixAddress) > address->address_length))
831 {
832 GNUNET_break (0);
833 return NULL;
834 }
835 addrstr = (char *) &ua[1];
836 addr_str_len = ntohl (ua->addrlen);
837 addr_option = ntohl (ua->options);
838
839 if ((0 != (UNIX_OPTIONS_USE_ABSTRACT_SOCKETS & addr_option)) &&
840 (GNUNET_NO == plugin->is_abstract))
841 {
842 return NULL;
843 }
844
845 if (addr_str_len != address->address_length - sizeof(struct UnixAddress))
846 {
847 return NULL; /* This can be a legacy address */
848 }
849
850 if ('\0' != addrstr[addr_str_len - 1])
851 {
852 GNUNET_break (0);
853 return NULL;
854 }
855 if (strlen (addrstr) + 1 != addr_str_len)
856 {
857 GNUNET_break (0);
858 return NULL;
859 }
860
861 /* Check if a session for this address already exists */
862 if (NULL != (session = lookup_session (plugin, address)))
863 {
864 LOG (GNUNET_ERROR_TYPE_DEBUG,
865 "Found existing session %p for address `%s'\n",
866 session,
867 unix_plugin_address_to_string (NULL,
868 address->address,
869 address->address_length));
870 return session;
871 }
872
873 /* create a new session */
874 session = GNUNET_new (struct GNUNET_ATS_Session);
875 session->target = address->peer;
876 session->address = GNUNET_HELLO_address_copy (address);
877 session->plugin = plugin;
878 session->timeout =
879 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
880 session->timeout_task =
881 GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
882 &session_timeout,
883 session);
884 LOG (GNUNET_ERROR_TYPE_DEBUG,
885 "Creating a new session %p for address `%s'\n",
886 session,
887 unix_plugin_address_to_string (NULL,
888 address->address,
889 address->address_length));
890 (void) GNUNET_CONTAINER_multipeermap_put (
891 plugin->session_map,
892 &address->peer,
893 session,
894 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
895 GNUNET_STATISTICS_set (plugin->env->stats,
896 "# UNIX sessions active",
897 GNUNET_CONTAINER_multipeermap_size (
898 plugin->session_map),
899 GNUNET_NO);
900 notify_session_monitor (plugin, session, GNUNET_TRANSPORT_SS_INIT);
901 notify_session_monitor (plugin, session, GNUNET_TRANSPORT_SS_UP);
902 return session;
903}
904
905
906/**
907 * Function that will be called whenever the transport service wants
908 * to notify the plugin that a session is still active and in use and
909 * therefore the session timeout for this session has to be updated
910 *
911 * @param cls closure with the `struct Plugin *`
912 * @param peer which peer was the session for
913 * @param session which session is being updated
914 */
915static void
916unix_plugin_update_session_timeout (void *cls,
917 const struct GNUNET_PeerIdentity *peer,
918 struct GNUNET_ATS_Session *session)
919{
920 struct Plugin *plugin = cls;
921
922 if (GNUNET_OK !=
923 GNUNET_CONTAINER_multipeermap_contains_value (plugin->session_map,
924 &session->target,
925 session))
926 {
927 GNUNET_break (0);
928 return;
929 }
930 reschedule_session_timeout (session);
931}
932
933
934/**
935 * Demultiplexer for UNIX messages
936 *
937 * @param plugin the main plugin for this transport
938 * @param sender from which peer the message was received
939 * @param currhdr pointer to the header of the message
940 * @param ua address to look for
941 * @param ua_len length of the address @a ua
942 */
943static void
944unix_demultiplexer (struct Plugin *plugin,
945 struct GNUNET_PeerIdentity *sender,
946 const struct GNUNET_MessageHeader *currhdr,
947 const struct UnixAddress *ua,
948 size_t ua_len)
949{
950 struct GNUNET_ATS_Session *session;
951 struct GNUNET_HELLO_Address *address;
952
953 GNUNET_assert (ua_len >= sizeof(struct UnixAddress));
954 LOG (GNUNET_ERROR_TYPE_DEBUG,
955 "Received message from %s\n",
956 unix_plugin_address_to_string (NULL, ua, ua_len));
957 GNUNET_STATISTICS_update (plugin->env->stats,
958 "# bytes received via UNIX",
959 ntohs (currhdr->size),
960 GNUNET_NO);
961
962 /* Look for existing session */
963 address = GNUNET_HELLO_address_allocate (
964 sender,
965 PLUGIN_NAME,
966 ua,
967 ua_len,
968 GNUNET_HELLO_ADDRESS_INFO_NONE); /* UNIX does not have "inbound" sessions */
969 session = lookup_session (plugin, address);
970 if (NULL == session)
971 {
972 session = unix_plugin_get_session (plugin, address);
973 /* Notify transport and ATS about new inbound session */
974 plugin->env->session_start (NULL,
975 session->address,
976 session,
977 GNUNET_NT_LOOPBACK);
978 }
979 else
980 {
981 reschedule_session_timeout (session);
982 }
983 GNUNET_HELLO_address_free (address);
984 plugin->env->receive (plugin->env->cls, session->address, session, currhdr);
985}
986
987
988/**
989 * Read from UNIX domain socket (it is ready).
990 *
991 * @param plugin the plugin
992 */
993static void
994unix_plugin_do_read (struct Plugin *plugin)
995{
996 char buf[65536] GNUNET_ALIGN;
997 struct UnixAddress *ua;
998 struct UNIXMessage *msg;
999 struct GNUNET_PeerIdentity sender;
1000 struct sockaddr_un un;
1001 socklen_t addrlen;
1002 ssize_t ret;
1003 int offset;
1004 int tsize;
1005 int is_abstract;
1006 char *msgbuf;
1007 const struct GNUNET_MessageHeader *currhdr;
1008 uint16_t csize;
1009 size_t ua_len;
1010
1011 addrlen = sizeof(un);
1012 memset (&un, 0, sizeof(un));
1013 ret = GNUNET_NETWORK_socket_recvfrom (plugin->unix_sock.desc,
1014 buf,
1015 sizeof(buf),
1016 (struct sockaddr *) &un,
1017 &addrlen);
1018 if ((GNUNET_SYSERR == ret) && ((errno == EAGAIN) || (errno == ENOBUFS)))
1019 return;
1020 if (GNUNET_SYSERR == ret)
1021 {
1022 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "recvfrom");
1023 return;
1024 }
1025 else
1026 {
1027 LOG (GNUNET_ERROR_TYPE_DEBUG,
1028 "Read %d bytes from socket %s\n",
1029 (int) ret,
1030 un.sun_path);
1031 }
1032
1033 GNUNET_assert (AF_UNIX == (un.sun_family));
1034 is_abstract = GNUNET_NO;
1035 if ('\0' == un.sun_path[0])
1036 {
1037 un.sun_path[0] = '@';
1038 is_abstract = GNUNET_YES;
1039 }
1040
1041 ua_len = sizeof(struct UnixAddress) + strlen (un.sun_path) + 1;
1042 ua = GNUNET_malloc (ua_len);
1043 ua->addrlen = htonl (strlen (&un.sun_path[0]) + 1);
1044 GNUNET_memcpy (&ua[1], &un.sun_path[0], strlen (un.sun_path) + 1);
1045 if (is_abstract)
1046 ua->options = htonl (UNIX_OPTIONS_USE_ABSTRACT_SOCKETS);
1047 else
1048 ua->options = htonl (UNIX_OPTIONS_NONE);
1049
1050 msg = (struct UNIXMessage *) buf;
1051 csize = ntohs (msg->header.size);
1052 if ((csize < sizeof(struct UNIXMessage)) || (csize > ret))
1053 {
1054 GNUNET_break_op (0);
1055 GNUNET_free (ua);
1056 return;
1057 }
1058 msgbuf = (char *) &msg[1];
1059 GNUNET_memcpy (&sender, &msg->sender, sizeof(struct GNUNET_PeerIdentity));
1060 offset = 0;
1061 tsize = csize - sizeof(struct UNIXMessage);
1062 while (offset + sizeof(struct GNUNET_MessageHeader) <= tsize)
1063 {
1064 currhdr = (struct GNUNET_MessageHeader *) &msgbuf[offset];
1065 csize = ntohs (currhdr->size);
1066 if ((csize < sizeof(struct GNUNET_MessageHeader)) ||
1067 (csize > tsize - offset))
1068 {
1069 GNUNET_break_op (0);
1070 break;
1071 }
1072 unix_demultiplexer (plugin, &sender, currhdr, ua, ua_len);
1073 offset += csize;
1074 }
1075 GNUNET_free (ua);
1076}
1077
1078
1079/**
1080 * Write to UNIX domain socket (it is ready).
1081 *
1082 * @param plugin handle to the plugin
1083 */
1084static void
1085unix_plugin_do_write (struct Plugin *plugin)
1086{
1087 ssize_t sent = 0;
1088 struct UNIXMessageWrapper *msgw;
1089 struct GNUNET_ATS_Session *session;
1090 int did_delete;
1091
1092 session = NULL;
1093 did_delete = GNUNET_NO;
1094 while (NULL != (msgw = plugin->msg_head))
1095 {
1096 if (GNUNET_TIME_absolute_get_remaining (msgw->timeout).rel_value_us > 0)
1097 break; /* Message is ready for sending */
1098 /* Message has a timeout */
1099 did_delete = GNUNET_YES;
1100 LOG (GNUNET_ERROR_TYPE_DEBUG,
1101 "Timeout for message with %u bytes \n",
1102 (unsigned int) msgw->msgsize);
1103 GNUNET_CONTAINER_DLL_remove (plugin->msg_head, plugin->msg_tail, msgw);
1104 session = msgw->session;
1105 session->msgs_in_queue--;
1106 GNUNET_assert (session->bytes_in_queue >= msgw->msgsize);
1107 session->bytes_in_queue -= msgw->msgsize;
1108 GNUNET_assert (plugin->bytes_in_queue >= msgw->msgsize);
1109 plugin->bytes_in_queue -= msgw->msgsize;
1110 GNUNET_STATISTICS_set (plugin->env->stats,
1111 "# bytes currently in UNIX buffers",
1112 plugin->bytes_in_queue,
1113 GNUNET_NO);
1114 GNUNET_STATISTICS_update (plugin->env->stats,
1115 "# UNIX bytes discarded",
1116 msgw->msgsize,
1117 GNUNET_NO);
1118 if (NULL != msgw->cont)
1119 msgw->cont (msgw->cont_cls,
1120 &msgw->session->target,
1121 GNUNET_SYSERR,
1122 msgw->payload,
1123 0);
1124 GNUNET_free (msgw->msg);
1125 GNUNET_free (msgw);
1126 }
1127 if (NULL == msgw)
1128 {
1129 if (GNUNET_YES == did_delete)
1130 notify_session_monitor (plugin, session, GNUNET_TRANSPORT_SS_UPDATE);
1131 return; /* Nothing to send at the moment */
1132 }
1133 session = msgw->session;
1134 sent = unix_real_send (plugin,
1135 plugin->unix_sock.desc,
1136 &session->target,
1137 (const char *) msgw->msg,
1138 msgw->msgsize,
1139 msgw->priority,
1140 msgw->timeout,
1141 msgw->session->address->address,
1142 msgw->session->address->address_length,
1143 msgw->payload,
1144 msgw->cont,
1145 msgw->cont_cls);
1146 if (RETRY == sent)
1147 {
1148 GNUNET_STATISTICS_update (plugin->env->stats,
1149 "# UNIX retry attempts",
1150 1,
1151 GNUNET_NO);
1152 notify_session_monitor (plugin, session, GNUNET_TRANSPORT_SS_UPDATE);
1153 return;
1154 }
1155 GNUNET_CONTAINER_DLL_remove (plugin->msg_head, plugin->msg_tail, msgw);
1156 session->msgs_in_queue--;
1157 GNUNET_assert (session->bytes_in_queue >= msgw->msgsize);
1158 session->bytes_in_queue -= msgw->msgsize;
1159 GNUNET_assert (plugin->bytes_in_queue >= msgw->msgsize);
1160 plugin->bytes_in_queue -= msgw->msgsize;
1161 GNUNET_STATISTICS_set (plugin->env->stats,
1162 "# bytes currently in UNIX buffers",
1163 plugin->bytes_in_queue,
1164 GNUNET_NO);
1165 notify_session_monitor (plugin, session, GNUNET_TRANSPORT_SS_UPDATE);
1166 if (GNUNET_SYSERR == sent)
1167 {
1168 /* failed and no retry */
1169 if (NULL != msgw->cont)
1170 msgw->cont (msgw->cont_cls,
1171 &msgw->session->target,
1172 GNUNET_SYSERR,
1173 msgw->payload,
1174 0);
1175 GNUNET_STATISTICS_update (plugin->env->stats,
1176 "# UNIX bytes discarded",
1177 msgw->msgsize,
1178 GNUNET_NO);
1179 GNUNET_free (msgw->msg);
1180 GNUNET_free (msgw);
1181 return;
1182 }
1183 /* successfully sent bytes */
1184 GNUNET_break (sent > 0);
1185 GNUNET_STATISTICS_update (plugin->env->stats,
1186 "# bytes transmitted via UNIX",
1187 msgw->msgsize,
1188 GNUNET_NO);
1189 if (NULL != msgw->cont)
1190 msgw->cont (msgw->cont_cls,
1191 &msgw->session->target,
1192 GNUNET_OK,
1193 msgw->payload,
1194 msgw->msgsize);
1195 GNUNET_free (msgw->msg);
1196 GNUNET_free (msgw);
1197}
1198
1199
1200/**
1201 * We have been notified that our socket has something to read.
1202 * Then reschedule this function to be called again once more is available.
1203 *
1204 * @param cls the plugin handle
1205 */
1206static void
1207unix_plugin_select_read (void *cls)
1208{
1209 struct Plugin *plugin = cls;
1210 const struct GNUNET_SCHEDULER_TaskContext *tc;
1211
1212 plugin->read_task = NULL;
1213 tc = GNUNET_SCHEDULER_get_task_context ();
1214 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY))
1215 unix_plugin_do_read (plugin);
1216 plugin->read_task =
1217 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
1218 plugin->unix_sock.desc,
1219 &unix_plugin_select_read,
1220 plugin);
1221}
1222
1223
1224/**
1225 * We have been notified that our socket is ready to write.
1226 * Then reschedule this function to be called again once more is available.
1227 *
1228 * @param cls the plugin handle
1229 */
1230static void
1231unix_plugin_select_write (void *cls)
1232{
1233 struct Plugin *plugin = cls;
1234 const struct GNUNET_SCHEDULER_TaskContext *tc;
1235
1236 plugin->write_task = NULL;
1237 tc = GNUNET_SCHEDULER_get_task_context ();
1238 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY))
1239 unix_plugin_do_write (plugin);
1240 if (NULL == plugin->msg_head)
1241 return; /* write queue empty */
1242 plugin->write_task =
1243 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
1244 plugin->unix_sock.desc,
1245 &unix_plugin_select_write,
1246 plugin);
1247}
1248
1249
1250/**
1251 * Function that can be used by the transport service to transmit
1252 * a message using the plugin. Note that in the case of a
1253 * peer disconnecting, the continuation MUST be called
1254 * prior to the disconnect notification itself. This function
1255 * will be called with this peer's HELLO message to initiate
1256 * a fresh connection to another peer.
1257 *
1258 * @param cls closure
1259 * @param session which session must be used
1260 * @param msgbuf the message to transmit
1261 * @param msgbuf_size number of bytes in @a msgbuf
1262 * @param priority how important is the message (most plugins will
1263 * ignore message priority and just FIFO)
1264 * @param to how long to wait at most for the transmission (does not
1265 * require plugins to discard the message after the timeout,
1266 * just advisory for the desired delay; most plugins will ignore
1267 * this as well)
1268 * @param cont continuation to call once the message has
1269 * been transmitted (or if the transport is ready
1270 * for the next transmission call; or if the
1271 * peer disconnected...); can be NULL
1272 * @param cont_cls closure for @a cont
1273 * @return number of bytes used (on the physical network, with overheads);
1274 * -1 on hard errors (i.e. address invalid); 0 is a legal value
1275 * and does NOT mean that the message was not transmitted (DV)
1276 */
1277static ssize_t
1278unix_plugin_send (void *cls,
1279 struct GNUNET_ATS_Session *session,
1280 const char *msgbuf,
1281 size_t msgbuf_size,
1282 unsigned int priority,
1283 struct GNUNET_TIME_Relative to,
1284 GNUNET_TRANSPORT_TransmitContinuation cont,
1285 void *cont_cls)
1286{
1287 struct Plugin *plugin = cls;
1288 struct UNIXMessageWrapper *wrapper;
1289 struct UNIXMessage *message;
1290 int ssize;
1291
1292 if (GNUNET_OK !=
1293 GNUNET_CONTAINER_multipeermap_contains_value (plugin->session_map,
1294 &session->target,
1295 session))
1296 {
1297 LOG (GNUNET_ERROR_TYPE_ERROR,
1298 "Invalid session for peer `%s' `%s'\n",
1299 GNUNET_i2s (&session->target),
1300 unix_plugin_address_to_string (NULL,
1301 session->address->address,
1302 session->address->address_length));
1303 GNUNET_break (0);
1304 return GNUNET_SYSERR;
1305 }
1306 LOG (GNUNET_ERROR_TYPE_DEBUG,
1307 "Sending %lu bytes with session for peer `%s' `%s'\n",
1308 (unsigned long) msgbuf_size,
1309 GNUNET_i2s (&session->target),
1310 unix_plugin_address_to_string (NULL,
1311 session->address->address,
1312 session->address->address_length));
1313 ssize = sizeof(struct UNIXMessage) + msgbuf_size;
1314 message = GNUNET_malloc (sizeof(struct UNIXMessage) + msgbuf_size);
1315 message->header.size = htons (ssize);
1316 message->header.type = htons (0);
1317 GNUNET_memcpy (&message->sender,
1318 plugin->env->my_identity,
1319 sizeof(struct GNUNET_PeerIdentity));
1320 GNUNET_memcpy (&message[1], msgbuf, msgbuf_size);
1321 wrapper = GNUNET_new (struct UNIXMessageWrapper);
1322 wrapper->msg = message;
1323 wrapper->msgsize = ssize;
1324 wrapper->payload = msgbuf_size;
1325 wrapper->priority = priority;
1326 wrapper->timeout = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), to);
1327 wrapper->cont = cont;
1328 wrapper->cont_cls = cont_cls;
1329 wrapper->session = session;
1330 GNUNET_CONTAINER_DLL_insert_tail (plugin->msg_head,
1331 plugin->msg_tail,
1332 wrapper);
1333 plugin->bytes_in_queue += ssize;
1334 session->bytes_in_queue += ssize;
1335 session->msgs_in_queue++;
1336 GNUNET_STATISTICS_set (plugin->env->stats,
1337 "# bytes currently in UNIX buffers",
1338 plugin->bytes_in_queue,
1339 GNUNET_NO);
1340 notify_session_monitor (plugin, session, GNUNET_TRANSPORT_SS_UPDATE);
1341 if (NULL == plugin->write_task)
1342 plugin->write_task =
1343 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
1344 plugin->unix_sock.desc,
1345 &unix_plugin_select_write,
1346 plugin);
1347 return ssize;
1348}
1349
1350
1351/**
1352 * Create a slew of UNIX sockets. If possible, use IPv6 and IPv4.
1353 *
1354 * @param cls closure for server start, should be a `struct Plugin *`
1355 * @return number of sockets created or #GNUNET_SYSERR on error
1356 */
1357static int
1358unix_transport_server_start (void *cls)
1359{
1360 struct Plugin *plugin = cls;
1361 struct sockaddr_un *un;
1362 socklen_t un_len;
1363
1364 un = unix_address_to_sockaddr (plugin->unix_socket_path, &un_len);
1365 if (GNUNET_YES == plugin->is_abstract)
1366 {
1367 plugin->unix_socket_path[0] = '@';
1368 un->sun_path[0] = '\0';
1369 }
1370 plugin->unix_sock.desc =
1371 GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_DGRAM, 0);
1372 if (NULL == plugin->unix_sock.desc)
1373 {
1374 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
1375 GNUNET_free (un);
1376 return GNUNET_SYSERR;
1377 }
1378 if ('\0' != un->sun_path[0])
1379 {
1380 if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (un->sun_path))
1381 {
1382 LOG (GNUNET_ERROR_TYPE_ERROR,
1383 _ ("Cannot create path to `%s'\n"),
1384 un->sun_path);
1385 GNUNET_NETWORK_socket_close (plugin->unix_sock.desc);
1386 plugin->unix_sock.desc = NULL;
1387 GNUNET_free (un);
1388 return GNUNET_SYSERR;
1389 }
1390 }
1391 if (GNUNET_OK != GNUNET_NETWORK_socket_bind (plugin->unix_sock.desc,
1392 (const struct sockaddr *) un,
1393 un_len))
1394 {
1395 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
1396 LOG (GNUNET_ERROR_TYPE_ERROR, _ ("Cannot bind to `%s'\n"), un->sun_path);
1397 GNUNET_NETWORK_socket_close (plugin->unix_sock.desc);
1398 plugin->unix_sock.desc = NULL;
1399 GNUNET_free (un);
1400 return GNUNET_SYSERR;
1401 }
1402 LOG (GNUNET_ERROR_TYPE_DEBUG, "Bound to `%s'\n", plugin->unix_socket_path);
1403 plugin->read_task =
1404 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
1405 plugin->unix_sock.desc,
1406 &unix_plugin_select_read,
1407 plugin);
1408 GNUNET_free (un);
1409 return 1;
1410}
1411
1412
1413/**
1414 * Function that will be called to check if a binary address for this
1415 * plugin is well-formed and corresponds to an address for THIS peer
1416 * (as per our configuration). Naturally, if absolutely necessary,
1417 * plugins can be a bit conservative in their answer, but in general
1418 * plugins should make sure that the address does not redirect
1419 * traffic to a 3rd party that might try to man-in-the-middle our
1420 * traffic.
1421 *
1422 * @param cls closure, should be our handle to the Plugin
1423 * @param addr pointer to the address
1424 * @param addrlen length of @a addr
1425 * @return #GNUNET_OK if this is a plausible address for this peer
1426 * and transport, #GNUNET_SYSERR if not
1427 *
1428 */
1429static int
1430unix_plugin_check_address (void *cls, const void *addr, size_t addrlen)
1431{
1432 struct Plugin *plugin = cls;
1433 const struct UnixAddress *ua = addr;
1434 char *addrstr;
1435 size_t addr_str_len;
1436
1437 if ((NULL == addr) || (0 == addrlen) ||
1438 (sizeof(struct UnixAddress) > addrlen))
1439 {
1440 GNUNET_break (0);
1441 return GNUNET_SYSERR;
1442 }
1443 addrstr = (char *) &ua[1];
1444 addr_str_len = ntohl (ua->addrlen);
1445 if ('\0' != addrstr[addr_str_len - 1])
1446 {
1447 GNUNET_break (0);
1448 return GNUNET_SYSERR;
1449 }
1450 if (strlen (addrstr) + 1 != addr_str_len)
1451 {
1452 GNUNET_break (0);
1453 return GNUNET_SYSERR;
1454 }
1455
1456 if (0 == strcmp (plugin->unix_socket_path, addrstr))
1457 return GNUNET_OK;
1458 return GNUNET_SYSERR;
1459}
1460
1461
1462/**
1463 * Convert the transports address to a nice, human-readable
1464 * format.
1465 *
1466 * @param cls closure
1467 * @param type name of the transport that generated the address
1468 * @param addr one of the addresses of the host, NULL for the last address
1469 * the specific address format depends on the transport
1470 * @param addrlen length of the @a addr
1471 * @param numeric should (IP) addresses be displayed in numeric form?
1472 * @param timeout after how long should we give up?
1473 * @param asc function to call on each string
1474 * @param asc_cls closure for @a asc
1475 */
1476static void
1477unix_plugin_address_pretty_printer (void *cls,
1478 const char *type,
1479 const void *addr,
1480 size_t addrlen,
1481 int numeric,
1482 struct GNUNET_TIME_Relative timeout,
1483 GNUNET_TRANSPORT_AddressStringCallback asc,
1484 void *asc_cls)
1485{
1486 const char *ret;
1487
1488 if ((NULL != addr) && (addrlen > 0))
1489 ret = unix_plugin_address_to_string (NULL, addr, addrlen);
1490 else
1491 ret = NULL;
1492 asc (asc_cls, ret, (NULL == ret) ? GNUNET_SYSERR : GNUNET_OK);
1493 asc (asc_cls, NULL, GNUNET_OK);
1494}
1495
1496
1497/**
1498 * Function called to convert a string address to
1499 * a binary address.
1500 *
1501 * @param cls closure (`struct Plugin *`)
1502 * @param addr string address
1503 * @param addrlen length of the @a addr (strlen(addr) + '\0')
1504 * @param buf location to store the buffer
1505 * If the function returns #GNUNET_SYSERR, its contents are undefined.
1506 * @param added length of created address
1507 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
1508 */
1509static int
1510unix_plugin_string_to_address (void *cls,
1511 const char *addr,
1512 uint16_t addrlen,
1513 void **buf,
1514 size_t *added)
1515{
1516 struct UnixAddress *ua;
1517 char *address;
1518 char *plugin;
1519 char *optionstr;
1520 uint32_t options;
1521 size_t ua_size;
1522
1523 /* Format unix.options.address */
1524 address = NULL;
1525 plugin = NULL;
1526 optionstr = NULL;
1527
1528 if ((NULL == addr) || (addrlen == 0))
1529 {
1530 GNUNET_break (0);
1531 return GNUNET_SYSERR;
1532 }
1533 if ('\0' != addr[addrlen - 1])
1534 {
1535 GNUNET_break (0);
1536 return GNUNET_SYSERR;
1537 }
1538 if (strlen (addr) != addrlen - 1)
1539 {
1540 GNUNET_break (0);
1541 return GNUNET_SYSERR;
1542 }
1543 plugin = GNUNET_strdup (addr);
1544 optionstr = strchr (plugin, '.');
1545 if (NULL == optionstr)
1546 {
1547 GNUNET_break (0);
1548 GNUNET_free (plugin);
1549 return GNUNET_SYSERR;
1550 }
1551 optionstr[0] = '\0';
1552 optionstr++;
1553 options = atol (optionstr);
1554 address = strchr (optionstr, '.');
1555 if (NULL == address)
1556 {
1557 GNUNET_break (0);
1558 GNUNET_free (plugin);
1559 return GNUNET_SYSERR;
1560 }
1561 address[0] = '\0';
1562 address++;
1563 if (0 != strcmp (plugin, PLUGIN_NAME))
1564 {
1565 GNUNET_break (0);
1566 GNUNET_free (plugin);
1567 return GNUNET_SYSERR;
1568 }
1569
1570 ua_size = sizeof(struct UnixAddress) + strlen (address) + 1;
1571 ua = GNUNET_malloc (ua_size);
1572 ua->options = htonl (options);
1573 ua->addrlen = htonl (strlen (address) + 1);
1574 GNUNET_memcpy (&ua[1], address, strlen (address) + 1);
1575 GNUNET_free (plugin);
1576
1577 (*buf) = ua;
1578 (*added) = ua_size;
1579 return GNUNET_OK;
1580}
1581
1582
1583/**
1584 * Notify transport service about address
1585 *
1586 * @param cls the plugin
1587 */
1588static void
1589address_notification (void *cls)
1590{
1591 struct Plugin *plugin = cls;
1592 struct GNUNET_HELLO_Address *address;
1593 size_t len;
1594 struct UnixAddress *ua;
1595 char *unix_path;
1596
1597 len = sizeof(struct UnixAddress) + strlen (plugin->unix_socket_path) + 1;
1598 ua = GNUNET_malloc (len);
1599 ua->options = htonl (plugin->myoptions);
1600 ua->addrlen = htonl (strlen (plugin->unix_socket_path) + 1);
1601 unix_path = (char *) &ua[1];
1602 GNUNET_memcpy (unix_path,
1603 plugin->unix_socket_path,
1604 strlen (plugin->unix_socket_path) + 1);
1605
1606 plugin->address_update_task = NULL;
1607 address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
1608 PLUGIN_NAME,
1609 ua,
1610 len,
1611 GNUNET_HELLO_ADDRESS_INFO_NONE);
1612 plugin->env->notify_address (plugin->env->cls, GNUNET_YES, address);
1613 GNUNET_free (ua);
1614 GNUNET_free (address);
1615}
1616
1617
1618/**
1619 * Function called on sessions to disconnect
1620 *
1621 * @param cls the plugin
1622 * @param key peer identity (unused)
1623 * @param value the `struct GNUNET_ATS_Session *` to disconnect
1624 * @return #GNUNET_YES (always, continue to iterate)
1625 */
1626static int
1627get_session_delete_it (void *cls,
1628 const struct GNUNET_PeerIdentity *key,
1629 void *value)
1630{
1631 struct Plugin *plugin = cls;
1632 struct GNUNET_ATS_Session *session = value;
1633
1634 unix_plugin_session_disconnect (plugin, session);
1635 return GNUNET_YES;
1636}
1637
1638
1639/**
1640 * Disconnect from a remote node. Clean up session if we have one for this peer
1641 *
1642 * @param cls closure for this call (should be handle to Plugin)
1643 * @param target the peeridentity of the peer to disconnect
1644 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the operation failed
1645 */
1646static void
1647unix_plugin_peer_disconnect (void *cls,
1648 const struct GNUNET_PeerIdentity *target)
1649{
1650 struct Plugin *plugin = cls;
1651
1652 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->session_map,
1653 target,
1654 &get_session_delete_it,
1655 plugin);
1656}
1657
1658
1659/**
1660 * Return information about the given session to the
1661 * monitor callback.
1662 *
1663 * @param cls the `struct Plugin` with the monitor callback (`sic`)
1664 * @param peer peer we send information about
1665 * @param value our `struct GNUNET_ATS_Session` to send information about
1666 * @return #GNUNET_OK (continue to iterate)
1667 */
1668static int
1669send_session_info_iter (void *cls,
1670 const struct GNUNET_PeerIdentity *peer,
1671 void *value)
1672{
1673 struct Plugin *plugin = cls;
1674 struct GNUNET_ATS_Session *session = value;
1675
1676 notify_session_monitor (plugin, session, GNUNET_TRANSPORT_SS_INIT);
1677 notify_session_monitor (plugin, session, GNUNET_TRANSPORT_SS_UP);
1678 return GNUNET_OK;
1679}
1680
1681
1682/**
1683 * Begin monitoring sessions of a plugin. There can only
1684 * be one active monitor per plugin (i.e. if there are
1685 * multiple monitors, the transport service needs to
1686 * multiplex the generated events over all of them).
1687 *
1688 * @param cls closure of the plugin
1689 * @param sic callback to invoke, NULL to disable monitor;
1690 * plugin will being by iterating over all active
1691 * sessions immediately and then enter monitor mode
1692 * @param sic_cls closure for @a sic
1693 */
1694static void
1695unix_plugin_setup_monitor (void *cls,
1696 GNUNET_TRANSPORT_SessionInfoCallback sic,
1697 void *sic_cls)
1698{
1699 struct Plugin *plugin = cls;
1700
1701 plugin->sic = sic;
1702 plugin->sic_cls = sic_cls;
1703 if (NULL != sic)
1704 {
1705 GNUNET_CONTAINER_multipeermap_iterate (plugin->session_map,
1706 &send_session_info_iter,
1707 plugin);
1708 /* signal end of first iteration */
1709 sic (sic_cls, NULL, NULL);
1710 }
1711}
1712
1713
1714/**
1715 * The exported method. Initializes the plugin and returns a
1716 * struct with the callbacks.
1717 *
1718 * @param cls the plugin's execution environment
1719 * @return NULL on error, plugin functions otherwise
1720 */
1721void *
1722libgnunet_plugin_transport_unix_init (void *cls)
1723{
1724 struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
1725 struct GNUNET_TRANSPORT_PluginFunctions *api;
1726 struct Plugin *plugin;
1727 int sockets_created;
1728
1729 if (NULL == env->receive)
1730 {
1731 /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully
1732 initialize the plugin or the API */
1733 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
1734 api->cls = NULL;
1735 api->address_pretty_printer = &unix_plugin_address_pretty_printer;
1736 api->address_to_string = &unix_plugin_address_to_string;
1737 api->string_to_address = &unix_plugin_string_to_address;
1738 return api;
1739 }
1740
1741 plugin = GNUNET_new (struct Plugin);
1742 if (GNUNET_OK !=
1743 GNUNET_CONFIGURATION_get_value_filename (env->cfg,
1744 "transport-unix",
1745 "UNIXPATH",
1746 &plugin->unix_socket_path))
1747 {
1748 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
1749 "transport-unix",
1750 "UNIXPATH");
1751 GNUNET_free (plugin);
1752 return NULL;
1753 }
1754
1755 plugin->env = env;
1756
1757 /* Initialize my flags */
1758#ifdef __linux__
1759 plugin->is_abstract =
1760 GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg,
1761 "testing",
1762 "USE_ABSTRACT_SOCKETS");
1763#endif
1764 plugin->myoptions = UNIX_OPTIONS_NONE;
1765 if (GNUNET_YES == plugin->is_abstract)
1766 plugin->myoptions = UNIX_OPTIONS_USE_ABSTRACT_SOCKETS;
1767
1768 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
1769 api->cls = plugin;
1770 api->get_session = &unix_plugin_get_session;
1771 api->send = &unix_plugin_send;
1772 api->disconnect_peer = &unix_plugin_peer_disconnect;
1773 api->disconnect_session = &unix_plugin_session_disconnect;
1774 api->query_keepalive_factor = &unix_plugin_query_keepalive_factor;
1775 api->address_pretty_printer = &unix_plugin_address_pretty_printer;
1776 api->address_to_string = &unix_plugin_address_to_string;
1777 api->check_address = &unix_plugin_check_address;
1778 api->string_to_address = &unix_plugin_string_to_address;
1779 api->get_network = &unix_plugin_get_network;
1780 api->get_network_for_address = &unix_plugin_get_network_for_address;
1781 api->update_session_timeout = &unix_plugin_update_session_timeout;
1782 api->setup_monitor = &unix_plugin_setup_monitor;
1783 sockets_created = unix_transport_server_start (plugin);
1784 if ((0 == sockets_created) || (GNUNET_SYSERR == sockets_created))
1785 {
1786 LOG (GNUNET_ERROR_TYPE_WARNING, _ ("Failed to open UNIX listen socket\n"));
1787 GNUNET_free (api);
1788 GNUNET_free (plugin->unix_socket_path);
1789 GNUNET_free (plugin);
1790 return NULL;
1791 }
1792 plugin->session_map = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO);
1793 plugin->address_update_task =
1794 GNUNET_SCHEDULER_add_now (&address_notification, plugin);
1795 return api;
1796}
1797
1798
1799/**
1800 * Shutdown the plugin.
1801 *
1802 * @param cls the plugin API returned from the initialization function
1803 * @return NULL (always)
1804 */
1805void *
1806libgnunet_plugin_transport_unix_done (void *cls)
1807{
1808 struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
1809 struct Plugin *plugin = api->cls;
1810 struct GNUNET_HELLO_Address *address;
1811 struct UNIXMessageWrapper *msgw;
1812 struct UnixAddress *ua;
1813 size_t len;
1814 struct GNUNET_ATS_Session *session;
1815
1816 if (NULL == plugin)
1817 {
1818 GNUNET_free (api);
1819 return NULL;
1820 }
1821 len = sizeof(struct UnixAddress) + strlen (plugin->unix_socket_path) + 1;
1822 ua = GNUNET_malloc (len);
1823 ua->options = htonl (plugin->myoptions);
1824 ua->addrlen = htonl (strlen (plugin->unix_socket_path) + 1);
1825 GNUNET_memcpy (&ua[1],
1826 plugin->unix_socket_path,
1827 strlen (plugin->unix_socket_path) + 1);
1828 address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
1829 PLUGIN_NAME,
1830 ua,
1831 len,
1832 GNUNET_HELLO_ADDRESS_INFO_NONE);
1833 plugin->env->notify_address (plugin->env->cls, GNUNET_NO, address);
1834
1835 GNUNET_free (address);
1836 GNUNET_free (ua);
1837
1838 while (NULL != (msgw = plugin->msg_head))
1839 {
1840 GNUNET_CONTAINER_DLL_remove (plugin->msg_head, plugin->msg_tail, msgw);
1841 session = msgw->session;
1842 session->msgs_in_queue--;
1843 GNUNET_assert (session->bytes_in_queue >= msgw->msgsize);
1844 session->bytes_in_queue -= msgw->msgsize;
1845 GNUNET_assert (plugin->bytes_in_queue >= msgw->msgsize);
1846 plugin->bytes_in_queue -= msgw->msgsize;
1847 if (NULL != msgw->cont)
1848 msgw->cont (msgw->cont_cls,
1849 &msgw->session->target,
1850 GNUNET_SYSERR,
1851 msgw->payload,
1852 0);
1853 GNUNET_free (msgw->msg);
1854 GNUNET_free (msgw);
1855 }
1856
1857 if (NULL != plugin->read_task)
1858 {
1859 GNUNET_SCHEDULER_cancel (plugin->read_task);
1860 plugin->read_task = NULL;
1861 }
1862 if (NULL != plugin->write_task)
1863 {
1864 GNUNET_SCHEDULER_cancel (plugin->write_task);
1865 plugin->write_task = NULL;
1866 }
1867 if (NULL != plugin->address_update_task)
1868 {
1869 GNUNET_SCHEDULER_cancel (plugin->address_update_task);
1870 plugin->address_update_task = NULL;
1871 }
1872 if (NULL != plugin->unix_sock.desc)
1873 {
1874 GNUNET_break (GNUNET_OK ==
1875 GNUNET_NETWORK_socket_close (plugin->unix_sock.desc));
1876 plugin->unix_sock.desc = NULL;
1877 }
1878 GNUNET_CONTAINER_multipeermap_iterate (plugin->session_map,
1879 &get_session_delete_it,
1880 plugin);
1881 GNUNET_CONTAINER_multipeermap_destroy (plugin->session_map);
1882 GNUNET_break (0 == plugin->bytes_in_queue);
1883 GNUNET_free (plugin->unix_socket_path);
1884 GNUNET_free (plugin);
1885 GNUNET_free (api);
1886 return NULL;
1887}
1888
1889
1890/* end of plugin_transport_unix.c */
diff --git a/src/transport/plugin_transport_wlan.c b/src/transport/plugin_transport_wlan.c
deleted file mode 100644
index 3ac106859..000000000
--- a/src/transport/plugin_transport_wlan.c
+++ /dev/null
@@ -1,2405 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2010-2014 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/plugin_transport_wlan.c
23 * @brief transport plugin for wlan and/or bluetooth
24 * @author David Brodski
25 * @author Christian Grothoff
26 *
27 * BUILD_WLAN or BUILD_BLUETOOTH must be defined such that the respective
28 * variant of this code is compiled.
29 */
30#include "platform.h"
31#include "gnunet_util_lib.h"
32#include "gnunet_hello_lib.h"
33#include "gnunet_protocols.h"
34#include "gnunet_statistics_service.h"
35#include "gnunet_transport_service.h"
36#include "gnunet_transport_plugin.h"
37#include "plugin_transport_wlan.h"
38#include "gnunet_fragmentation_lib.h"
39#include "gnunet_constants.h"
40
41
42#if BUILD_WLAN
43/* begin case wlan */
44#define PLUGIN_NAME "wlan"
45#define CONFIG_NAME "transport-wlan"
46#define HELPER_NAME "gnunet-helper-transport-wlan"
47#define DUMMY_HELPER_NAME "gnunet-helper-transport-wlan-dummy"
48#define LIBGNUNET_PLUGIN_TRANSPORT_INIT libgnunet_plugin_transport_wlan_init
49#define LIBGNUNET_PLUGIN_TRANSPORT_DONE libgnunet_plugin_transport_wlan_done
50#define LOG(kind, ...) GNUNET_log_from (kind, "transport-wlan", __VA_ARGS__)
51
52
53/**
54 * time out of a mac endpoint
55 */
56#define MACENDPOINT_TIMEOUT GNUNET_TIME_relative_multiply ( \
57 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, 2)
58
59/**
60 * We reduce the frequence of HELLO beacons in relation to
61 * the number of MAC addresses currently visible to us.
62 * This is the multiplication factor.
63 */
64#define HELLO_BEACON_SCALING_FACTOR GNUNET_TIME_relative_multiply ( \
65 GNUNET_TIME_UNIT_SECONDS, 2)
66
67
68/* end case wlan */
69#elif BUILD_BLUETOOTH
70/* begin case bluetooth */
71
72#define PLUGIN_NAME "bluetooth"
73#define CONFIG_NAME "transport-bluetooth"
74#define HELPER_NAME "gnunet-helper-transport-bluetooth"
75/* yes, this is correct, we use the same dummy driver as 'wlan' */
76#define DUMMY_HELPER_NAME "gnunet-helper-transport-wlan-dummy"
77#define LIBGNUNET_PLUGIN_TRANSPORT_INIT \
78 libgnunet_plugin_transport_bluetooth_init
79#define LIBGNUNET_PLUGIN_TRANSPORT_DONE \
80 libgnunet_plugin_transport_bluetooth_done
81#define LOG(kind, ...) GNUNET_log_from (kind, "transport-bluetooth", \
82 __VA_ARGS__)
83
84/**
85 * time out of a mac endpoint
86 */
87#define MACENDPOINT_TIMEOUT GNUNET_TIME_relative_multiply ( \
88 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, 60)
89
90
91/**
92 * We reduce the frequence of HELLO beacons in relation to
93 * the number of MAC addresses currently visible to us.
94 * This is the multiplication factor.
95 */
96#define HELLO_BEACON_SCALING_FACTOR GNUNET_TIME_relative_multiply ( \
97 GNUNET_TIME_UNIT_SECONDS, 60)
98
99/* end case bluetooth */
100#else
101#error need to build wlan or bluetooth
102#endif
103
104
105/**
106 * Functions with this signature are called whenever a
107 * complete message is received by the tokenizer.
108 *
109 * Do not call #GNUNET_SERVER_mst_destroy from within
110 * the scope of this callback.
111 *
112 * @param cls closure
113 * @param client identification of the client
114 * @param message the actual message
115 * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing
116 */
117typedef int
118(*GNUNET_SERVER_MessageTokenizerCallback) (void *cls,
119 void *client,
120 const struct
121 GNUNET_MessageHeader *message);
122
123
124/* Include legacy message stream tokenizer that was removed from util (for now) */
125#include "tcp_server_mst_legacy.c"
126
127
128/**
129 * Max size of packet (that we give to the WLAN driver for transmission)
130 */
131#define WLAN_MTU 1430
132
133
134/**
135 * Which network scope do we belong to?
136 */
137#if BUILD_WLAN
138static const enum GNUNET_NetworkType scope = GNUNET_NT_WLAN;
139#else
140static const enum GNUNET_NetworkType scope = GNUNET_NT_BT;
141#endif
142
143
144/**
145 * Maximum number of messages in defragmentation queue per MAC
146 */
147#define MESSAGES_IN_DEFRAG_QUEUE_PER_MAC 2
148
149/**
150 * Link layer control fields for better compatibility
151 * (i.e. GNUnet over WLAN is not IP-over-WLAN).
152 */
153#define WLAN_LLC_DSAP_FIELD 0x1f
154#define WLAN_LLC_SSAP_FIELD 0x1f
155
156
157GNUNET_NETWORK_STRUCT_BEGIN
158/**
159 * Header for messages which need fragmentation. This is the format of
160 * a message we obtain AFTER defragmentation. We then need to check
161 * the CRC and then tokenize the payload and pass it to the
162 * 'receive' callback.
163 */
164struct WlanHeader
165{
166 /**
167 * Message type is #GNUNET_MESSAGE_TYPE_WLAN_DATA.
168 */
169 struct GNUNET_MessageHeader header;
170
171 /**
172 * CRC32 checksum (only over the payload), in NBO.
173 */
174 uint32_t crc GNUNET_PACKED;
175
176 /**
177 * Sender of the message.
178 */
179 struct GNUNET_PeerIdentity sender;
180
181 /**
182 * Target of the message.
183 */
184 struct GNUNET_PeerIdentity target;
185
186 /* followed by payload, possibly including
187 multiple messages! */
188};
189
190
191/**
192 * Address format for WLAN.
193 */
194struct WlanAddress
195{
196 /**
197 * Options set for the WLAN, in NBO.
198 */
199 uint32_t options GNUNET_PACKED;
200
201 /**
202 * WLAN addresses using MACs.
203 */
204 struct GNUNET_TRANSPORT_WLAN_MacAddress mac;
205};
206
207
208GNUNET_NETWORK_STRUCT_END
209
210
211/**
212 * Information kept for each message that is yet to be fragmented and
213 * transmitted.
214 */
215struct PendingMessage
216{
217 /**
218 * next entry in the DLL
219 */
220 struct PendingMessage *next;
221
222 /**
223 * previous entry in the DLL
224 */
225 struct PendingMessage *prev;
226
227 /**
228 * The pending message
229 */
230 struct WlanHeader *msg;
231
232 /**
233 * Continuation function to call once the message
234 * has been sent. Can be NULL if there is no
235 * continuation to call.
236 */
237 GNUNET_TRANSPORT_TransmitContinuation transmit_cont;
238
239 /**
240 * Cls for @e transmit_cont
241 */
242 void *transmit_cont_cls;
243
244 /**
245 * Timeout task (for this message).
246 */
247 struct GNUNET_SCHEDULER_Task *timeout_task;
248};
249
250
251/**
252 * Session handle for connections with other peers.
253 */
254struct GNUNET_ATS_Session
255{
256 /**
257 * To whom are we talking to (set to our identity
258 * if we are still waiting for the welcome message)
259 */
260 struct GNUNET_PeerIdentity target;
261
262 /**
263 * We keep all sessions in a DLL at their respective
264 * `struct MACEndpoint *`.
265 */
266 struct GNUNET_ATS_Session *next;
267
268 /**
269 * We keep all sessions in a DLL at their respective
270 * `struct MACEndpoint *`.
271 */
272 struct GNUNET_ATS_Session *prev;
273
274 /**
275 * MAC endpoint with the address of this peer.
276 */
277 struct MacEndpoint *mac;
278
279 /**
280 * Address associated with this session and MAC endpoint
281 */
282 struct GNUNET_HELLO_Address *address;
283
284 /**
285 * When should this session time out?
286 */
287 struct GNUNET_TIME_Absolute timeout;
288
289 /**
290 * Timeout task (for the session).
291 */
292 struct GNUNET_SCHEDULER_Task *timeout_task;
293};
294
295
296/**
297 * Struct for messages that are being fragmented in a MAC's transmission queue.
298 */
299struct FragmentMessage
300{
301 /**
302 * This is a doubly-linked list.
303 */
304 struct FragmentMessage *next;
305
306 /**
307 * This is a doubly-linked list.
308 */
309 struct FragmentMessage *prev;
310
311 /**
312 * MAC endpoint this message belongs to
313 */
314 struct MacEndpoint *macendpoint;
315
316 /**
317 * Fragmentation context
318 */
319 struct GNUNET_FRAGMENT_Context *fragcontext;
320
321 /**
322 * Transmission handle to helper (to cancel if the frag context
323 * is destroyed early for some reason).
324 */
325 struct GNUNET_HELPER_SendHandle *sh;
326
327 /**
328 * Intended recipient.
329 */
330 struct GNUNET_PeerIdentity target;
331
332 /**
333 * Timeout value for the message.
334 */
335 struct GNUNET_TIME_Absolute timeout;
336
337 /**
338 * Timeout task.
339 */
340 struct GNUNET_SCHEDULER_Task *timeout_task;
341
342 /**
343 * Continuation to call when we're done with this message.
344 */
345 GNUNET_TRANSPORT_TransmitContinuation cont;
346
347 /**
348 * Message we need to fragment and transmit, NULL after the
349 * @e fragmentcontext has been created.
350 */
351 struct GNUNET_MessageHeader *msg;
352
353 /**
354 * Closure for @e cont
355 */
356 void *cont_cls;
357
358 /**
359 * Size of original message
360 */
361 size_t size_payload;
362
363 /**
364 * Number of bytes used to transmit message
365 */
366 size_t size_on_wire;
367};
368
369
370/**
371 * Struct to represent one network card connection
372 */
373struct MacEndpoint
374{
375 /**
376 * We keep all MACs in a DLL in the plugin.
377 */
378 struct MacEndpoint *next;
379
380 /**
381 * We keep all MACs in a DLL in the plugin.
382 */
383 struct MacEndpoint *prev;
384
385 /**
386 * Pointer to the global plugin struct.
387 */
388 struct Plugin *plugin;
389
390 /**
391 * Head of sessions that use this MAC.
392 */
393 struct GNUNET_ATS_Session *sessions_head;
394
395 /**
396 * Tail of sessions that use this MAC.
397 */
398 struct GNUNET_ATS_Session *sessions_tail;
399
400 /**
401 * Head of messages we are currently sending to this MAC.
402 */
403 struct FragmentMessage *sending_messages_head;
404
405 /**
406 * Tail of messages we are currently sending to this MAC.
407 */
408 struct FragmentMessage *sending_messages_tail;
409
410 /**
411 * Defrag context for this MAC
412 */
413 struct GNUNET_DEFRAGMENT_Context *defrag;
414
415 /**
416 * When should this endpoint time out?
417 */
418 struct GNUNET_TIME_Absolute timeout;
419
420 /**
421 * Timeout task.
422 */
423 struct GNUNET_SCHEDULER_Task *timeout_task;
424
425 /**
426 * count of messages in the fragment out queue for this mac endpoint
427 */
428 unsigned int fragment_messages_out_count;
429
430 /**
431 * peer MAC address
432 */
433 struct WlanAddress wlan_addr;
434
435 /**
436 * Message delay for fragmentation context
437 */
438 struct GNUNET_TIME_Relative msg_delay;
439
440 /**
441 * ACK delay for fragmentation context
442 */
443 struct GNUNET_TIME_Relative ack_delay;
444
445 /**
446 * Desired transmission power for this MAC
447 */
448 uint16_t tx_power;
449
450 /**
451 * Desired transmission rate for this MAC
452 */
453 uint8_t rate;
454
455 /**
456 * Antenna we should use for this MAC
457 */
458 uint8_t antenna;
459};
460
461
462/**
463 * Encapsulation of all of the state of the plugin.
464 */
465struct Plugin
466{
467 /**
468 * Our environment.
469 */
470 struct GNUNET_TRANSPORT_PluginEnvironment *env;
471
472 /**
473 * Handle to helper process for privileged operations.
474 */
475 struct GNUNET_HELPER_Handle *suid_helper;
476
477 /**
478 * Function to call about session status changes.
479 */
480 GNUNET_TRANSPORT_SessionInfoCallback sic;
481
482 /**
483 * Closure for @e sic.
484 */
485 void *sic_cls;
486
487 /**
488 * ARGV-vector for the helper (all helpers take only the binary
489 * name, one actual argument, plus the NULL terminator for 'argv').
490 */
491 char *helper_argv[3];
492
493 /**
494 * The interface of the wlan card given to us by the user.
495 */
496 char *wlan_interface;
497
498 /**
499 * Tokenizer for demultiplexing of data packets resulting from
500 * defragmentation.
501 */
502 struct GNUNET_SERVER_MessageStreamTokenizer *fragment_data_tokenizer;
503
504 /**
505 * Tokenizer for demultiplexing of data packets received from the suid helper
506 */
507 struct GNUNET_SERVER_MessageStreamTokenizer *helper_payload_tokenizer;
508
509 /**
510 * Tokenizer for demultiplexing of data packets that follow the WLAN Header
511 */
512 struct GNUNET_SERVER_MessageStreamTokenizer *wlan_header_payload_tokenizer;
513
514 /**
515 * Head of list of open connections.
516 */
517 struct MacEndpoint *mac_head;
518
519 /**
520 * Tail of list of open connections.
521 */
522 struct MacEndpoint *mac_tail;
523
524 /**
525 * Task that periodically sends a HELLO beacon via the helper.
526 */
527 struct GNUNET_SCHEDULER_Task *beacon_task;
528
529 /**
530 * Tracker for bandwidth limit
531 */
532 struct GNUNET_BANDWIDTH_Tracker tracker;
533
534 /**
535 * The mac_address of the wlan card given to us by the helper.
536 */
537 struct GNUNET_TRANSPORT_WLAN_MacAddress mac_address;
538
539 /**
540 * Have we received a control message with our MAC address yet?
541 */
542 int have_mac;
543
544 /**
545 * Number of connections
546 */
547 unsigned int mac_count;
548
549 /**
550 * Options for addresses
551 */
552 uint32_t options;
553};
554
555
556/**
557 * Information associated with a message. Can contain
558 * the session or the MAC endpoint associated with the
559 * message (or both).
560 */
561struct MacAndSession
562{
563 /**
564 * NULL if the identity of the other peer is not known.
565 */
566 struct GNUNET_ATS_Session *session;
567
568 /**
569 * MAC address of the other peer, NULL if not known.
570 */
571 struct MacEndpoint *endpoint;
572};
573
574
575/**
576 * Print MAC addresses nicely.
577 *
578 * @param mac the mac address
579 * @return string to a static buffer with
580 * the human-readable mac, will be overwritten during the next call to
581 * this function
582 */
583static const char *
584mac_to_string (const struct GNUNET_TRANSPORT_WLAN_MacAddress *mac)
585{
586 static char macstr[20];
587
588 GNUNET_snprintf (macstr,
589 sizeof(macstr),
590 "%.2X:%.2X:%.2X:%.2X:%.2X:%.2X",
591 mac->mac[0], mac->mac[1],
592 mac->mac[2], mac->mac[3],
593 mac->mac[4], mac->mac[5]);
594 return macstr;
595}
596
597
598/**
599 * Function called for a quick conversion of the binary address to
600 * a numeric address. Note that the caller must not free the
601 * address and that the next call to this function is allowed
602 * to override the address again.
603 *
604 * @param cls closure
605 * @param addr binary address
606 * @param addrlen length of the address
607 * @return string representing the same address
608 */
609static const char *
610wlan_plugin_address_to_string (void *cls,
611 const void *addr,
612 size_t addrlen)
613{
614 const struct GNUNET_TRANSPORT_WLAN_MacAddress *mac;
615 static char macstr[36];
616
617 if (sizeof(struct WlanAddress) != addrlen)
618 {
619 GNUNET_break (0);
620 return NULL;
621 }
622 mac = &((struct WlanAddress *) addr)->mac;
623 GNUNET_snprintf (macstr,
624 sizeof(macstr),
625 "%s.%u.%s",
626 PLUGIN_NAME,
627 ntohl (((struct WlanAddress *) addr)->options),
628 mac_to_string (mac));
629 return macstr;
630}
631
632
633/**
634 * If a session monitor is attached, notify it about the new
635 * session state.
636 *
637 * @param plugin our plugin
638 * @param session session that changed state
639 * @param state new state of the session
640 */
641static void
642notify_session_monitor (struct Plugin *plugin,
643 struct GNUNET_ATS_Session *session,
644 enum GNUNET_TRANSPORT_SessionState state)
645{
646 struct GNUNET_TRANSPORT_SessionInfo info;
647
648 if (NULL == plugin->sic)
649 return;
650 memset (&info, 0, sizeof(info));
651 info.state = state;
652 info.is_inbound = GNUNET_SYSERR; /* hard to say */
653 info.num_msg_pending = 0; /* we queue per MAC, not per peer */
654 info.num_bytes_pending = 0; /* we queue per MAC, not per peer */
655 info.receive_delay = GNUNET_TIME_UNIT_ZERO_ABS; /* not supported by WLAN */
656 info.session_timeout = session->timeout;
657 info.address = session->address;
658 plugin->sic (plugin->sic_cls,
659 session,
660 &info);
661}
662
663
664/**
665 * Fill the radiotap header
666 *
667 * @param endpoint pointer to the endpoint, can be NULL
668 * @param header pointer to the radiotap header
669 * @param size total message size
670 */
671static void
672get_radiotap_header (struct MacEndpoint *endpoint,
673 struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *header,
674 uint16_t size)
675{
676 header->header.type = ntohs (GNUNET_MESSAGE_TYPE_WLAN_DATA_TO_HELPER);
677 header->header.size = ntohs (size);
678 if (NULL != endpoint)
679 {
680 header->rate = endpoint->rate;
681 header->tx_power = endpoint->tx_power;
682 header->antenna = endpoint->antenna;
683 }
684 else
685 {
686 header->rate = 255;
687 header->tx_power = 0;
688 header->antenna = 0;
689 }
690}
691
692
693/**
694 * Generate the WLAN hardware header for one packet
695 *
696 * @param plugin the plugin handle
697 * @param header address to write the header to
698 * @param to_mac_addr address of the recipient
699 * @param size size of the whole packet, needed to calculate the time to send the packet
700 */
701static void
702get_wlan_header (struct Plugin *plugin,
703 struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *header,
704 const struct GNUNET_TRANSPORT_WLAN_MacAddress *to_mac_addr,
705 unsigned int size)
706{
707 const int rate = 11000000;
708
709 header->frame_control = htons (IEEE80211_FC0_TYPE_DATA);
710 header->addr1 = *to_mac_addr;
711 header->addr2 = plugin->mac_address;
712 header->addr3 = mac_bssid_gnunet;
713 header->duration = GNUNET_htole16 ((size * 1000000) / rate + 290);
714 header->sequence_control = 0; // FIXME?
715 header->llc[0] = WLAN_LLC_DSAP_FIELD;
716 header->llc[1] = WLAN_LLC_SSAP_FIELD;
717 header->llc[2] = 0; // FIXME?
718 header->llc[3] = 0; // FIXME?
719}
720
721
722/**
723 * Send an ACK for a fragment we received.
724 *
725 * @param cls the `struct MacEndpoint *` the ACK must be sent to
726 * @param msg_id id of the message
727 * @param hdr pointer to the hdr where the ack is stored
728 */
729static void
730send_ack (void *cls,
731 uint32_t msg_id,
732 const struct GNUNET_MessageHeader *hdr)
733{
734 struct MacEndpoint *endpoint = cls;
735 struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage*radio_header;
736 uint16_t msize = ntohs (hdr->size);
737 size_t size = sizeof(struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage)
738 + msize;
739 char buf[size];
740
741 if (NULL == endpoint)
742 {
743 GNUNET_break (0);
744 return;
745 }
746 if (size >= GNUNET_MAX_MESSAGE_SIZE)
747 {
748 GNUNET_break (0);
749 return;
750 }
751 LOG (GNUNET_ERROR_TYPE_DEBUG,
752 "Sending ACK to %s\n",
753 mac_to_string (&endpoint->wlan_addr.mac));
754 radio_header = (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *) buf;
755 get_radiotap_header (endpoint, radio_header, size);
756 get_wlan_header (endpoint->plugin,
757 &radio_header->frame,
758 &endpoint->wlan_addr.mac,
759 sizeof(endpoint->wlan_addr.mac));
760 GNUNET_memcpy (&radio_header[1], hdr, msize);
761 if (NULL !=
762 GNUNET_HELPER_send (endpoint->plugin->suid_helper,
763 &radio_header->header,
764 GNUNET_NO /* dropping ACKs is bad */,
765 NULL, NULL))
766 GNUNET_STATISTICS_update (endpoint->plugin->env->stats,
767 _ ("# ACKs sent"),
768 1, GNUNET_NO);
769}
770
771
772/**
773 * Handles the data after all fragments are put together
774 *
775 * @param cls macendpoint this messages belongs to
776 * @param hdr pointer to the data
777 */
778static void
779wlan_data_message_handler (void *cls,
780 const struct GNUNET_MessageHeader *hdr)
781{
782 struct MacEndpoint *endpoint = cls;
783 struct Plugin *plugin = endpoint->plugin;
784 struct MacAndSession mas;
785
786 GNUNET_STATISTICS_update (plugin->env->stats,
787 _ ("# Messages defragmented"),
788 1,
789 GNUNET_NO);
790 mas.session = NULL;
791 mas.endpoint = endpoint;
792 (void) GNUNET_SERVER_mst_receive (plugin->fragment_data_tokenizer,
793 &mas,
794 (const char *) hdr,
795 ntohs (hdr->size),
796 GNUNET_YES, GNUNET_NO);
797}
798
799
800/**
801 * Free a session
802 *
803 * @param cls our `struct Plugin`.
804 * @param session the session free
805 */
806static int
807wlan_plugin_disconnect_session (void *cls,
808 struct GNUNET_ATS_Session *session)
809{
810 struct MacEndpoint *endpoint = session->mac;
811 struct Plugin *plugin = endpoint->plugin;
812
813 plugin->env->session_end (plugin->env->cls,
814 session->address,
815 session);
816 notify_session_monitor (plugin,
817 session,
818 GNUNET_TRANSPORT_SS_DONE);
819 GNUNET_CONTAINER_DLL_remove (endpoint->sessions_head,
820 endpoint->sessions_tail,
821 session);
822 if (session->timeout_task != NULL)
823 {
824 GNUNET_SCHEDULER_cancel (session->timeout_task);
825 session->timeout_task = NULL;
826 }
827 GNUNET_STATISTICS_update (plugin->env->stats,
828 _ ("# Sessions allocated"),
829 -1,
830 GNUNET_NO);
831 GNUNET_HELLO_address_free (session->address);
832 GNUNET_free (session);
833 return GNUNET_OK;
834}
835
836
837/**
838 * Function that is called to get the keepalive factor.
839 * #GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT is divided by this number to
840 * calculate the interval between keepalive packets.
841 *
842 * @param cls closure with the `struct Plugin`
843 * @return keepalive factor
844 */
845static unsigned int
846wlan_plugin_query_keepalive_factor (void *cls)
847{
848 return 3;
849}
850
851
852/**
853 * A session is timing out. Clean up.
854 *
855 * @param cls pointer to the Session
856 */
857static void
858session_timeout (void *cls)
859{
860 struct GNUNET_ATS_Session *session = cls;
861 struct GNUNET_TIME_Relative left;
862
863 session->timeout_task = NULL;
864 left = GNUNET_TIME_absolute_get_remaining (session->timeout);
865 if (0 != left.rel_value_us)
866 {
867 session->timeout_task =
868 GNUNET_SCHEDULER_add_delayed (left,
869 &session_timeout,
870 session);
871 return;
872 }
873 wlan_plugin_disconnect_session (session->mac->plugin,
874 session);
875}
876
877
878/**
879 * Lookup a new session
880 *
881 * @param endpoint pointer to the mac endpoint of the peer
882 * @param peer peer identity to use for this session
883 * @return returns the session or NULL
884 */
885static struct GNUNET_ATS_Session *
886lookup_session (struct MacEndpoint *endpoint,
887 const struct GNUNET_PeerIdentity *peer)
888{
889 struct GNUNET_ATS_Session *session;
890
891 for (session = endpoint->sessions_head; NULL != session; session =
892 session->next)
893 if (0 == memcmp (peer, &session->target, sizeof(struct
894 GNUNET_PeerIdentity)))
895 return session;
896 return NULL;
897}
898
899
900/**
901 * Create a new session
902 *
903 * @param endpoint pointer to the mac endpoint of the peer
904 * @param peer peer identity to use for this session
905 * @return returns the session or NULL
906 */
907static struct GNUNET_ATS_Session *
908create_session (struct MacEndpoint *endpoint,
909 const struct GNUNET_PeerIdentity *peer)
910{
911 struct GNUNET_ATS_Session *session;
912
913 GNUNET_STATISTICS_update (endpoint->plugin->env->stats,
914 _ ("# Sessions allocated"),
915 1,
916 GNUNET_NO);
917 session = GNUNET_new (struct GNUNET_ATS_Session);
918 GNUNET_CONTAINER_DLL_insert_tail (endpoint->sessions_head,
919 endpoint->sessions_tail,
920 session);
921 session->address = GNUNET_HELLO_address_allocate (peer,
922 PLUGIN_NAME,
923 &endpoint->wlan_addr,
924 sizeof(endpoint->wlan_addr),
925 GNUNET_HELLO_ADDRESS_INFO_NONE);
926 session->mac = endpoint;
927 session->target = *peer;
928 session->timeout = GNUNET_TIME_relative_to_absolute (
929 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
930 session->timeout_task =
931 GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
932 &session_timeout,
933 session);
934 notify_session_monitor (endpoint->plugin,
935 session,
936 GNUNET_TRANSPORT_SS_INIT);
937 notify_session_monitor (endpoint->plugin,
938 session,
939 GNUNET_TRANSPORT_SS_UP);
940 LOG (GNUNET_ERROR_TYPE_DEBUG,
941 "Created new session %p for peer `%s' with endpoint %s\n",
942 session,
943 GNUNET_i2s (peer),
944 mac_to_string (&endpoint->wlan_addr.mac));
945
946 return session;
947}
948
949
950/**
951 * Look up a session for a peer and create a new session if none is found
952 *
953 * @param endpoint pointer to the mac endpoint of the peer
954 * @param peer peer identity to use for this session
955 * @return returns the session
956 */
957static struct GNUNET_ATS_Session *
958get_session (struct MacEndpoint *endpoint,
959 const struct GNUNET_PeerIdentity *peer)
960{
961 struct GNUNET_ATS_Session *session;
962
963 if (NULL != (session = lookup_session (endpoint, peer)))
964 return session;
965 return create_session (endpoint, peer);
966}
967
968
969/**
970 * Function called once we have successfully given the fragment
971 * message to the SUID helper process and we are thus ready for
972 * the next fragment.
973 *
974 * @param cls the `struct FragmentMessage *`
975 * @param result result of the operation (#GNUNET_OK on success,
976 * #GNUNET_NO if the helper died, #GNUNET_SYSERR
977 * if the helper was stopped)
978 */
979static void
980fragment_transmission_done (void *cls,
981 int result)
982{
983 struct FragmentMessage *fm = cls;
984
985 fm->sh = NULL;
986 GNUNET_FRAGMENT_context_transmission_done (fm->fragcontext);
987}
988
989
990/**
991 * Transmit a fragment of a message.
992 *
993 * @param cls `struct FragmentMessage *` this fragment message belongs to
994 * @param hdr pointer to the start of the fragment message
995 */
996static void
997transmit_fragment (void *cls,
998 const struct GNUNET_MessageHeader *hdr)
999{
1000 struct FragmentMessage *fm = cls;
1001 struct MacEndpoint *endpoint = fm->macendpoint;
1002 size_t size;
1003 uint16_t msize;
1004
1005 if (NULL == endpoint)
1006 {
1007 GNUNET_break (0);
1008 return;
1009 }
1010 msize = ntohs (hdr->size);
1011 size = sizeof(struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage) + msize;
1012 {
1013 char buf[size];
1014 struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *radio_header;
1015
1016 radio_header = (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *) buf;
1017 get_radiotap_header (endpoint, radio_header, size);
1018 LOG (GNUNET_ERROR_TYPE_DEBUG,
1019 "Sending %u bytes of data to MAC `%s'\n",
1020 (unsigned int) msize,
1021 mac_to_string (&endpoint->wlan_addr.mac));
1022
1023 get_wlan_header (endpoint->plugin,
1024 &radio_header->frame,
1025 &endpoint->wlan_addr.mac,
1026 sizeof(endpoint->wlan_addr.mac));
1027 GNUNET_memcpy (&radio_header[1], hdr, msize);
1028 GNUNET_assert (NULL == fm->sh);
1029 fm->sh = GNUNET_HELPER_send (endpoint->plugin->suid_helper,
1030 &radio_header->header,
1031 GNUNET_NO,
1032 &fragment_transmission_done, fm);
1033 fm->size_on_wire += size;
1034 if (NULL != fm->sh)
1035 {
1036 GNUNET_STATISTICS_update (endpoint->plugin->env->stats,
1037 _ ("# message fragments sent"),
1038 1,
1039 GNUNET_NO);
1040 }
1041 else
1042 {
1043 GNUNET_FRAGMENT_context_transmission_done (fm->fragcontext);
1044 }
1045 GNUNET_STATISTICS_update (endpoint->plugin->env->stats,
1046 "# bytes currently in buffers",
1047 -msize, GNUNET_NO);
1048 GNUNET_STATISTICS_update (endpoint->plugin->env->stats,
1049 "# bytes transmitted",
1050 msize, GNUNET_NO);
1051 }
1052}
1053
1054
1055/**
1056 * Frees the space of a message in the fragment queue (send queue)
1057 *
1058 * @param fm message to free
1059 */
1060static void
1061free_fragment_message (struct FragmentMessage *fm)
1062{
1063 struct MacEndpoint *endpoint = fm->macendpoint;
1064
1065 GNUNET_STATISTICS_update (endpoint->plugin->env->stats,
1066 _ ("# messages pending (with fragmentation)"),
1067 -1, GNUNET_NO);
1068 GNUNET_CONTAINER_DLL_remove (endpoint->sending_messages_head,
1069 endpoint->sending_messages_tail,
1070 fm);
1071 if (NULL != fm->sh)
1072 {
1073 GNUNET_HELPER_send_cancel (fm->sh);
1074 fm->sh = NULL;
1075 }
1076 if (NULL != fm->msg)
1077 {
1078 GNUNET_free (fm->msg);
1079 fm->msg = NULL;
1080 }
1081 if (NULL != fm->fragcontext)
1082 {
1083 GNUNET_FRAGMENT_context_destroy (fm->fragcontext,
1084 &endpoint->msg_delay,
1085 &endpoint->ack_delay);
1086 fm->fragcontext = NULL;
1087 }
1088 if (NULL != fm->timeout_task)
1089 {
1090 GNUNET_SCHEDULER_cancel (fm->timeout_task);
1091 fm->timeout_task = NULL;
1092 }
1093 GNUNET_free (fm);
1094}
1095
1096
1097/**
1098 * A FragmentMessage has timed out. Remove it.
1099 *
1100 * @param cls pointer to the 'struct FragmentMessage'
1101 */
1102static void
1103fragmentmessage_timeout (void *cls)
1104{
1105 struct FragmentMessage *fm = cls;
1106
1107 fm->timeout_task = NULL;
1108 if (NULL != fm->cont)
1109 {
1110 fm->cont (fm->cont_cls,
1111 &fm->target,
1112 GNUNET_SYSERR,
1113 fm->size_payload,
1114 fm->size_on_wire);
1115 fm->cont = NULL;
1116 }
1117 free_fragment_message (fm);
1118}
1119
1120
1121/**
1122 * Transmit a message to the given destination with fragmentation.
1123 *
1124 * @param endpoint desired destination
1125 * @param timeout how long can the message wait?
1126 * @param target peer that should receive the message
1127 * @param msg message to transmit
1128 * @param payload_size bytes of payload
1129 * @param cont continuation to call once the message has
1130 * been transmitted (or if the transport is ready
1131 * for the next transmission call; or if the
1132 * peer disconnected...); can be NULL
1133 * @param cont_cls closure for @a cont
1134 */
1135static void
1136send_with_fragmentation (struct MacEndpoint *endpoint,
1137 struct GNUNET_TIME_Relative timeout,
1138 const struct GNUNET_PeerIdentity *target,
1139 const struct GNUNET_MessageHeader *msg,
1140 size_t payload_size,
1141 GNUNET_TRANSPORT_TransmitContinuation cont,
1142 void *cont_cls)
1143
1144{
1145 struct FragmentMessage *fm;
1146 struct Plugin *plugin;
1147
1148 plugin = endpoint->plugin;
1149 fm = GNUNET_new (struct FragmentMessage);
1150 fm->macendpoint = endpoint;
1151 fm->target = *target;
1152 fm->size_payload = payload_size;
1153 fm->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1154 fm->cont = cont;
1155 fm->cont_cls = cont_cls;
1156 /* 1 MBit/s typical data rate, 1430 byte fragments => ~100 ms per message */
1157 fm->timeout_task =
1158 GNUNET_SCHEDULER_add_delayed (timeout,
1159 &fragmentmessage_timeout,
1160 fm);
1161 if (GNUNET_YES == plugin->have_mac)
1162 {
1163 fm->fragcontext =
1164 GNUNET_FRAGMENT_context_create (plugin->env->stats,
1165 WLAN_MTU,
1166 &plugin->tracker,
1167 fm->macendpoint->msg_delay,
1168 fm->macendpoint->ack_delay,
1169 msg,
1170 &transmit_fragment, fm);
1171 }
1172 else
1173 {
1174 fm->msg = GNUNET_copy_message (msg);
1175 }
1176 GNUNET_CONTAINER_DLL_insert_tail (endpoint->sending_messages_head,
1177 endpoint->sending_messages_tail,
1178 fm);
1179}
1180
1181
1182/**
1183 * Free a MAC endpoint.
1184 *
1185 * @param endpoint pointer to the MacEndpoint to free
1186 */
1187static void
1188free_macendpoint (struct MacEndpoint *endpoint)
1189{
1190 struct Plugin *plugin = endpoint->plugin;
1191 struct FragmentMessage *fm;
1192 struct GNUNET_ATS_Session *session;
1193
1194 GNUNET_STATISTICS_update (plugin->env->stats,
1195 _ ("# MAC endpoints allocated"),
1196 -1,
1197 GNUNET_NO);
1198 while (NULL != (session = endpoint->sessions_head))
1199 wlan_plugin_disconnect_session (plugin,
1200 session);
1201 while (NULL != (fm = endpoint->sending_messages_head))
1202 free_fragment_message (fm);
1203 GNUNET_CONTAINER_DLL_remove (plugin->mac_head,
1204 plugin->mac_tail,
1205 endpoint);
1206
1207 if (NULL != endpoint->defrag)
1208 {
1209 GNUNET_DEFRAGMENT_context_destroy (endpoint->defrag);
1210 endpoint->defrag = NULL;
1211 }
1212
1213 plugin->mac_count--;
1214 if (NULL != endpoint->timeout_task)
1215 {
1216 GNUNET_SCHEDULER_cancel (endpoint->timeout_task);
1217 endpoint->timeout_task = NULL;
1218 }
1219 GNUNET_free (endpoint);
1220}
1221
1222
1223/**
1224 * A MAC endpoint is timing out. Clean up.
1225 *
1226 * @param cls pointer to the `struct MacEndpoint *`
1227 */
1228static void
1229macendpoint_timeout (void *cls)
1230{
1231 struct MacEndpoint *endpoint = cls;
1232 struct GNUNET_TIME_Relative timeout;
1233
1234 endpoint->timeout_task = NULL;
1235 timeout = GNUNET_TIME_absolute_get_remaining (endpoint->timeout);
1236 if (0 == timeout.rel_value_us)
1237 {
1238 free_macendpoint (endpoint);
1239 return;
1240 }
1241 endpoint->timeout_task =
1242 GNUNET_SCHEDULER_add_delayed (timeout,
1243 &macendpoint_timeout,
1244 endpoint);
1245}
1246
1247
1248/**
1249 * Find (or create) a MacEndpoint with a specific MAC address
1250 *
1251 * @param plugin pointer to the plugin struct
1252 * @param mac the MAC address of the endpoint
1253 * @return handle to our data structure for this MAC
1254 */
1255static struct MacEndpoint *
1256create_macendpoint (struct Plugin *plugin,
1257 struct WlanAddress *mac)
1258{
1259 struct MacEndpoint *pos;
1260
1261 for (pos = plugin->mac_head; NULL != pos; pos = pos->next)
1262 if (0 == memcmp (mac, &pos->wlan_addr, sizeof(pos->wlan_addr)))
1263 return pos;
1264 pos = GNUNET_new (struct MacEndpoint);
1265 pos->wlan_addr = (*mac);
1266 pos->plugin = plugin;
1267 pos->defrag =
1268 GNUNET_DEFRAGMENT_context_create (plugin->env->stats,
1269 WLAN_MTU,
1270 MESSAGES_IN_DEFRAG_QUEUE_PER_MAC,
1271 pos,
1272 &wlan_data_message_handler,
1273 &send_ack);
1274
1275 pos->msg_delay = GNUNET_TIME_UNIT_MILLISECONDS;
1276 pos->ack_delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
1277 100);
1278 pos->timeout = GNUNET_TIME_relative_to_absolute (MACENDPOINT_TIMEOUT);
1279 pos->timeout_task =
1280 GNUNET_SCHEDULER_add_delayed (MACENDPOINT_TIMEOUT, &macendpoint_timeout,
1281 pos);
1282 GNUNET_CONTAINER_DLL_insert (plugin->mac_head,
1283 plugin->mac_tail,
1284 pos);
1285 plugin->mac_count++;
1286 GNUNET_STATISTICS_update (plugin->env->stats,
1287 _ ("# MAC endpoints allocated"),
1288 1, GNUNET_NO);
1289 LOG (GNUNET_ERROR_TYPE_DEBUG,
1290 "New MAC endpoint `%s'\n",
1291 wlan_plugin_address_to_string (NULL,
1292 &pos->wlan_addr,
1293 sizeof(struct WlanAddress)));
1294 return pos;
1295}
1296
1297
1298/**
1299 * Function obtain the network type for a session
1300 *
1301 * @param cls closure (`struct Plugin*`)
1302 * @param session the session
1303 * @return the network type in HBO or #GNUNET_SYSERR
1304 */
1305static enum GNUNET_NetworkType
1306wlan_plugin_get_network (void *cls,
1307 struct GNUNET_ATS_Session *session)
1308{
1309#if BUILD_WLAN
1310 return GNUNET_NT_WLAN;
1311#else
1312 return GNUNET_NT_BT;
1313#endif
1314}
1315
1316
1317/**
1318 * Function obtain the network type for an address.
1319 *
1320 * @param cls closure (`struct Plugin *`)
1321 * @param address the address
1322 * @return the network type
1323 */
1324static enum GNUNET_NetworkType
1325wlan_plugin_get_network_for_address (void *cls,
1326 const struct GNUNET_HELLO_Address *address)
1327{
1328#if BUILD_WLAN
1329 return GNUNET_NT_WLAN;
1330#else
1331 return GNUNET_NT_BT;
1332#endif
1333}
1334
1335
1336/**
1337 * Creates a new outbound session the transport service will use to
1338 * send data to the peer
1339 *
1340 * @param cls the `struct Plugin *`
1341 * @param address the address
1342 * @return the session or NULL of max connections exceeded
1343 */
1344static struct GNUNET_ATS_Session *
1345wlan_plugin_get_session (void *cls,
1346 const struct GNUNET_HELLO_Address *address)
1347{
1348 struct Plugin *plugin = cls;
1349 struct MacEndpoint *endpoint;
1350
1351 if (NULL == address)
1352 return NULL;
1353 if (sizeof(struct WlanAddress) != address->address_length)
1354 {
1355 GNUNET_break (0);
1356 return NULL;
1357 }
1358 LOG (GNUNET_ERROR_TYPE_DEBUG,
1359 "Service asked to create session for peer `%s' with MAC `%s'\n",
1360 GNUNET_i2s (&address->peer),
1361 wlan_plugin_address_to_string (NULL,
1362 address->address,
1363 address->address_length));
1364 endpoint = create_macendpoint (plugin,
1365 (struct WlanAddress *) address->address);
1366 return get_session (endpoint, &address->peer);
1367}
1368
1369
1370/**
1371 * Function that can be used to force the plugin to disconnect
1372 * from the given peer and cancel all previous transmissions
1373 * (and their continuation).
1374 *
1375 * @param cls closure
1376 * @param target peer from which to disconnect
1377 */
1378static void
1379wlan_plugin_disconnect_peer (void *cls,
1380 const struct GNUNET_PeerIdentity *target)
1381{
1382 struct Plugin *plugin = cls;
1383 struct GNUNET_ATS_Session *session;
1384 struct MacEndpoint *endpoint;
1385
1386 for (endpoint = plugin->mac_head; NULL != endpoint; endpoint = endpoint->next)
1387 for (session = endpoint->sessions_head; NULL != session; session =
1388 session->next)
1389 if (0 == memcmp (target, &session->target,
1390 sizeof(struct GNUNET_PeerIdentity)))
1391 {
1392 wlan_plugin_disconnect_session (plugin, session);
1393 break; /* inner-loop only (in case peer has another MAC as well!) */
1394 }
1395}
1396
1397
1398/**
1399 * Function that can be used by the transport service to transmit
1400 * a message using the plugin. Note that in the case of a
1401 * peer disconnecting, the continuation MUST be called
1402 * prior to the disconnect notification itself. This function
1403 * will be called with this peer's HELLO message to initiate
1404 * a fresh connection to another peer.
1405 *
1406 * @param cls closure
1407 * @param session which session must be used
1408 * @param msgbuf the message to transmit
1409 * @param msgbuf_size number of bytes in @a msgbuf
1410 * @param priority how important is the message (most plugins will
1411 * ignore message priority and just FIFO)
1412 * @param to how long to wait at most for the transmission (does not
1413 * require plugins to discard the message after the timeout,
1414 * just advisory for the desired delay; most plugins will ignore
1415 * this as well)
1416 * @param cont continuation to call once the message has
1417 * been transmitted (or if the transport is ready
1418 * for the next transmission call; or if the
1419 * peer disconnected...); can be NULL
1420 * @param cont_cls closure for @a cont
1421 * @return number of bytes used (on the physical network, with overheads);
1422 * -1 on hard errors (i.e. address invalid); 0 is a legal value
1423 * and does NOT mean that the message was not transmitted (DV)
1424 */
1425static ssize_t
1426wlan_plugin_send (void *cls,
1427 struct GNUNET_ATS_Session *session,
1428 const char *msgbuf, size_t msgbuf_size,
1429 unsigned int priority,
1430 struct GNUNET_TIME_Relative to,
1431 GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls)
1432{
1433 struct Plugin *plugin = cls;
1434 struct WlanHeader *wlanheader;
1435 size_t size = msgbuf_size + sizeof(struct WlanHeader);
1436 char buf[size] GNUNET_ALIGN;
1437
1438 LOG (GNUNET_ERROR_TYPE_DEBUG,
1439 "Transmitting %llu bytes of payload to peer `%s' (starting with %u byte message of type %u)\n",
1440 (unsigned long long) msgbuf_size,
1441 GNUNET_i2s (&session->target),
1442 (unsigned int) ntohs (((struct GNUNET_MessageHeader*) msgbuf)->size),
1443 (unsigned int) ntohs (((struct GNUNET_MessageHeader*) msgbuf)->type));
1444 wlanheader = (struct WlanHeader *) buf;
1445 wlanheader->header.size = htons (msgbuf_size + sizeof(struct WlanHeader));
1446 wlanheader->header.type = htons (GNUNET_MESSAGE_TYPE_WLAN_DATA);
1447 wlanheader->sender = *plugin->env->my_identity;
1448 wlanheader->target = session->target;
1449 wlanheader->crc = htonl (GNUNET_CRYPTO_crc32_n (msgbuf, msgbuf_size));
1450 GNUNET_memcpy (&wlanheader[1],
1451 msgbuf,
1452 msgbuf_size);
1453 GNUNET_STATISTICS_update (plugin->env->stats,
1454 "# bytes currently in buffers",
1455 msgbuf_size,
1456 GNUNET_NO);
1457 send_with_fragmentation (session->mac,
1458 to,
1459 &session->target,
1460 &wlanheader->header,
1461 msgbuf_size,
1462 cont, cont_cls);
1463 return size;
1464}
1465
1466
1467/**
1468 * We have received data from the WLAN via some session. Process depending
1469 * on the message type (HELLO, DATA, FRAGMENTATION or FRAGMENTATION-ACK).
1470 *
1471 * @param cls pointer to the plugin
1472 * @param client pointer to the session this message belongs to
1473 * @param hdr start of the message
1474 */
1475static int
1476process_data (void *cls,
1477 void *client,
1478 const struct GNUNET_MessageHeader *hdr)
1479{
1480 struct Plugin *plugin = cls;
1481 struct GNUNET_HELLO_Address *address;
1482 struct MacAndSession *mas = client;
1483 struct FragmentMessage *fm;
1484 struct GNUNET_PeerIdentity tmpsource;
1485 const struct WlanHeader *wlanheader;
1486 int ret;
1487 uint16_t msize;
1488
1489 msize = ntohs (hdr->size);
1490
1491 GNUNET_STATISTICS_update (plugin->env->stats,
1492 "# bytes received",
1493 msize, GNUNET_NO);
1494
1495 switch (ntohs (hdr->type))
1496 {
1497 case GNUNET_MESSAGE_TYPE_HELLO:
1498
1499 if (GNUNET_OK !=
1500 GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *) hdr,
1501 &tmpsource))
1502 {
1503 GNUNET_break_op (0);
1504 break;
1505 }
1506 if (NULL == mas->endpoint)
1507 {
1508 GNUNET_break (0);
1509 break;
1510 }
1511
1512 LOG (GNUNET_ERROR_TYPE_DEBUG,
1513 "Processing %u bytes of HELLO from peer `%s' at MAC %s\n",
1514 (unsigned int) msize,
1515 GNUNET_i2s (&tmpsource),
1516 wlan_plugin_address_to_string (NULL,
1517 &mas->endpoint->wlan_addr,
1518 sizeof(mas->endpoint->wlan_addr)));
1519
1520 GNUNET_STATISTICS_update (plugin->env->stats,
1521 _ ("# HELLO messages received"), 1,
1522 GNUNET_NO);
1523 address = GNUNET_HELLO_address_allocate (&tmpsource,
1524 PLUGIN_NAME,
1525 &mas->endpoint->wlan_addr,
1526 sizeof(mas->endpoint->wlan_addr),
1527 GNUNET_HELLO_ADDRESS_INFO_NONE);
1528 mas->session = lookup_session (mas->endpoint,
1529 &tmpsource);
1530 if (NULL == mas->session)
1531 {
1532 mas->session = create_session (mas->endpoint,
1533 &tmpsource);
1534 plugin->env->session_start (plugin->env->cls,
1535 address,
1536 mas->session,
1537 scope);
1538 }
1539 plugin->env->receive (plugin->env->cls,
1540 address,
1541 mas->session,
1542 hdr);
1543 GNUNET_HELLO_address_free (address);
1544 break;
1545
1546 case GNUNET_MESSAGE_TYPE_FRAGMENT:
1547 if (NULL == mas->endpoint)
1548 {
1549 GNUNET_break (0);
1550 break;
1551 }
1552 LOG (GNUNET_ERROR_TYPE_DEBUG,
1553 "Processing %u bytes of FRAGMENT from MAC %s\n",
1554 (unsigned int) msize,
1555 wlan_plugin_address_to_string (NULL,
1556 &mas->endpoint->wlan_addr,
1557 sizeof(mas->endpoint->wlan_addr)));
1558 GNUNET_STATISTICS_update (plugin->env->stats,
1559 _ ("# fragments received"),
1560 1,
1561 GNUNET_NO);
1562 (void) GNUNET_DEFRAGMENT_process_fragment (mas->endpoint->defrag,
1563 hdr);
1564 break;
1565
1566 case GNUNET_MESSAGE_TYPE_FRAGMENT_ACK:
1567 if (NULL == mas->endpoint)
1568 {
1569 GNUNET_break (0);
1570 break;
1571 }
1572 GNUNET_STATISTICS_update (plugin->env->stats,
1573 _ ("# ACKs received"),
1574 1, GNUNET_NO);
1575 for (fm = mas->endpoint->sending_messages_head; NULL != fm; fm = fm->next)
1576 {
1577 ret = GNUNET_FRAGMENT_process_ack (fm->fragcontext, hdr);
1578 if (GNUNET_OK == ret)
1579 {
1580 LOG (GNUNET_ERROR_TYPE_DEBUG,
1581 "Got last ACK, finished message transmission to `%s' (%p)\n",
1582 wlan_plugin_address_to_string (NULL,
1583 &mas->endpoint->wlan_addr,
1584 sizeof(mas->endpoint->wlan_addr)),
1585 fm);
1586 mas->endpoint->timeout = GNUNET_TIME_relative_to_absolute (
1587 MACENDPOINT_TIMEOUT);
1588 if (NULL != fm->cont)
1589 {
1590 fm->cont (fm->cont_cls,
1591 &fm->target,
1592 GNUNET_OK,
1593 fm->size_payload,
1594 fm->size_on_wire);
1595 fm->cont = NULL;
1596 }
1597 free_fragment_message (fm);
1598 break;
1599 }
1600 if (GNUNET_NO == ret)
1601 {
1602 LOG (GNUNET_ERROR_TYPE_DEBUG,
1603 "Got an ACK, message transmission to `%s' not yet finished\n",
1604 wlan_plugin_address_to_string (NULL,
1605 &mas->endpoint->wlan_addr,
1606 sizeof(mas->endpoint->wlan_addr)));
1607 break;
1608 }
1609 }
1610 if (NULL == fm)
1611 LOG (GNUNET_ERROR_TYPE_DEBUG,
1612 "ACK not matched against any active fragmentation with MAC `%s'\n",
1613 wlan_plugin_address_to_string (NULL,
1614 &mas->endpoint->wlan_addr,
1615 sizeof(mas->endpoint->wlan_addr)));
1616 break;
1617
1618 case GNUNET_MESSAGE_TYPE_WLAN_DATA:
1619 if (NULL == mas->endpoint)
1620 {
1621 GNUNET_break (0);
1622 break;
1623 }
1624 if (msize < sizeof(struct WlanHeader))
1625 {
1626 GNUNET_break (0);
1627 break;
1628 }
1629 wlanheader = (const struct WlanHeader *) hdr;
1630 if (0 != memcmp (&wlanheader->target,
1631 plugin->env->my_identity,
1632 sizeof(struct GNUNET_PeerIdentity)))
1633 {
1634 LOG (GNUNET_ERROR_TYPE_DEBUG,
1635 "Data for `%s', not for me, ignoring\n",
1636 GNUNET_i2s (&wlanheader->target));
1637 break;
1638 }
1639 if (ntohl (wlanheader->crc) !=
1640 GNUNET_CRYPTO_crc32_n (&wlanheader[1],
1641 msize - sizeof(struct WlanHeader)))
1642 {
1643 GNUNET_STATISTICS_update (plugin->env->stats,
1644 _ (
1645 "# DATA messages discarded due to CRC32 error"),
1646 1,
1647 GNUNET_NO);
1648 break;
1649 }
1650 mas->session = lookup_session (mas->endpoint,
1651 &wlanheader->sender);
1652 if (NULL == mas->session)
1653 {
1654 mas->session = create_session (mas->endpoint,
1655 &wlanheader->sender);
1656 address = GNUNET_HELLO_address_allocate (&wlanheader->sender,
1657 PLUGIN_NAME,
1658 &mas->endpoint->wlan_addr,
1659 sizeof(struct WlanAddress),
1660 GNUNET_HELLO_ADDRESS_INFO_NONE);
1661 plugin->env->session_start (plugin->env->cls,
1662 address,
1663 mas->session,
1664 scope);
1665 LOG (GNUNET_ERROR_TYPE_DEBUG,
1666 "Notifying transport about peer `%s''s new session %p \n",
1667 GNUNET_i2s (&wlanheader->sender),
1668 mas->session);
1669 GNUNET_HELLO_address_free (address);
1670 }
1671 LOG (GNUNET_ERROR_TYPE_DEBUG,
1672 "Processing %u bytes of DATA from peer `%s'\n",
1673 (unsigned int) msize,
1674 GNUNET_i2s (&wlanheader->sender));
1675 mas->session->timeout = GNUNET_TIME_relative_to_absolute (
1676 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1677 (void) GNUNET_SERVER_mst_receive (plugin->wlan_header_payload_tokenizer,
1678 mas,
1679 (const char *) &wlanheader[1],
1680 msize - sizeof(struct WlanHeader),
1681 GNUNET_YES,
1682 GNUNET_NO);
1683 break;
1684
1685 default:
1686 if (NULL == mas->endpoint)
1687 {
1688 GNUNET_break (0);
1689 break;
1690 }
1691 if (NULL == mas->session)
1692 {
1693 GNUNET_break (0);
1694 break;
1695 }
1696 LOG (GNUNET_ERROR_TYPE_DEBUG,
1697 "Received packet with %u bytes of type %u from peer %s\n",
1698 (unsigned int) msize,
1699 (unsigned int) ntohs (hdr->type),
1700 GNUNET_i2s (&mas->session->target));
1701 plugin->env->receive (plugin->env->cls,
1702 mas->session->address,
1703 mas->session,
1704 hdr);
1705 break;
1706 }
1707 return GNUNET_OK;
1708}
1709
1710
1711/**
1712 * Task to (periodically) send a HELLO beacon
1713 *
1714 * @param cls pointer to the plugin struct
1715 */
1716static void
1717send_hello_beacon (void *cls)
1718{
1719 struct Plugin *plugin = cls;
1720 uint16_t size;
1721 uint16_t hello_size;
1722 struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *radioHeader;
1723 const struct GNUNET_MessageHeader *hello;
1724
1725 hello = plugin->env->get_our_hello ();
1726 if (NULL != hello)
1727 {
1728 hello_size = GNUNET_HELLO_size ((struct GNUNET_HELLO_Message *) hello);
1729 GNUNET_assert (sizeof(struct WlanHeader) + hello_size <= WLAN_MTU);
1730 size = sizeof(struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage)
1731 + hello_size;
1732 {
1733 char buf[size] GNUNET_ALIGN;
1734
1735 LOG (GNUNET_ERROR_TYPE_DEBUG,
1736 "Sending %u byte HELLO beacon\n",
1737 (unsigned int) size);
1738 radioHeader = (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage*) buf;
1739 get_radiotap_header (NULL, radioHeader, size);
1740 LOG (GNUNET_ERROR_TYPE_DEBUG,
1741 "Broadcasting %u bytes of data to MAC `%s'\n",
1742 (unsigned int) size,
1743 mac_to_string (&bc_all_mac));
1744 get_wlan_header (plugin, &radioHeader->frame, &bc_all_mac, size);
1745 GNUNET_memcpy (&radioHeader[1], hello, hello_size);
1746 if (NULL !=
1747 GNUNET_HELPER_send (plugin->suid_helper,
1748 &radioHeader->header,
1749 GNUNET_YES /* can drop */,
1750 NULL, NULL))
1751 GNUNET_STATISTICS_update (plugin->env->stats,
1752 _ ("# HELLO beacons sent"),
1753 1, GNUNET_NO);
1754 }
1755 }
1756 plugin->beacon_task =
1757 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
1758 (HELLO_BEACON_SCALING_FACTOR,
1759 plugin->mac_count + 1),
1760 &send_hello_beacon,
1761 plugin);
1762}
1763
1764
1765/**
1766 * Function used for to process the data from the suid process
1767 *
1768 * @param cls the plugin handle
1769 * @param hdr header of the GNUNET_MessageHeader
1770 */
1771static int
1772handle_helper_message (void *cls,
1773 const struct GNUNET_MessageHeader *hdr)
1774{
1775 struct Plugin *plugin = cls;
1776 struct GNUNET_HELLO_Address *my_address;
1777 const struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage *rxinfo;
1778 const struct GNUNET_TRANSPORT_WLAN_HelperControlMessage *cm;
1779 struct WlanAddress wa;
1780 struct MacAndSession mas;
1781 uint16_t msize;
1782 struct FragmentMessage *fm;
1783 struct MacEndpoint *endpoint;
1784
1785 msize = ntohs (hdr->size);
1786 switch (ntohs (hdr->type))
1787 {
1788 case GNUNET_MESSAGE_TYPE_WLAN_HELPER_CONTROL:
1789 if (msize != sizeof(struct GNUNET_TRANSPORT_WLAN_HelperControlMessage))
1790 {
1791 GNUNET_break (0);
1792 break;
1793 }
1794 cm = (const struct GNUNET_TRANSPORT_WLAN_HelperControlMessage *) hdr;
1795 if (GNUNET_YES == plugin->have_mac)
1796 {
1797 if (0 == memcmp (&plugin->mac_address,
1798 &cm->mac,
1799 sizeof(struct GNUNET_TRANSPORT_WLAN_MacAddress)))
1800 break; /* no change */
1801 /* remove old address */
1802 memset (&wa, 0, sizeof(struct WlanAddress));
1803 wa.mac = plugin->mac_address;
1804 wa.options = htonl (plugin->options);
1805 my_address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
1806 PLUGIN_NAME,
1807 &wa, sizeof(wa),
1808 GNUNET_HELLO_ADDRESS_INFO_NONE);
1809 plugin->env->notify_address (plugin->env->cls,
1810 GNUNET_NO,
1811 my_address);
1812 GNUNET_HELLO_address_free (my_address);
1813 plugin->mac_address = cm->mac;
1814 }
1815 else
1816 {
1817 plugin->mac_address = cm->mac;
1818 plugin->have_mac = GNUNET_YES;
1819 for (endpoint = plugin->mac_head; NULL != endpoint; endpoint =
1820 endpoint->next)
1821 {
1822 for (fm = endpoint->sending_messages_head; NULL != fm; fm = fm->next)
1823 {
1824 if (NULL != fm->fragcontext)
1825 {
1826 GNUNET_break (0); /* should not happen */
1827 continue;
1828 }
1829 fm->fragcontext =
1830 GNUNET_FRAGMENT_context_create (plugin->env->stats,
1831 WLAN_MTU,
1832 &plugin->tracker,
1833 fm->macendpoint->msg_delay,
1834 fm->macendpoint->ack_delay,
1835 fm->msg,
1836 &transmit_fragment, fm);
1837 GNUNET_free (fm->msg);
1838 fm->msg = NULL;
1839 }
1840 }
1841 GNUNET_break (NULL == plugin->beacon_task);
1842 plugin->beacon_task = GNUNET_SCHEDULER_add_now (&send_hello_beacon,
1843 plugin);
1844 }
1845
1846 memset (&wa, 0, sizeof(struct WlanAddress));
1847 wa.mac = plugin->mac_address;
1848 wa.options = htonl (plugin->options);
1849 my_address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
1850 PLUGIN_NAME,
1851 &wa, sizeof(wa),
1852 GNUNET_HELLO_ADDRESS_INFO_NONE);
1853
1854 LOG (GNUNET_ERROR_TYPE_DEBUG,
1855 "Received WLAN_HELPER_CONTROL message with MAC address `%s' for peer `%s'\n",
1856 mac_to_string (&cm->mac),
1857 GNUNET_i2s (plugin->env->my_identity));
1858 plugin->env->notify_address (plugin->env->cls,
1859 GNUNET_YES,
1860 my_address);
1861 GNUNET_HELLO_address_free (my_address);
1862 break;
1863
1864 case GNUNET_MESSAGE_TYPE_WLAN_DATA_FROM_HELPER:
1865 LOG (GNUNET_ERROR_TYPE_DEBUG,
1866 "Got data message from helper with %u bytes\n",
1867 msize);
1868 GNUNET_STATISTICS_update (plugin->env->stats,
1869 _ ("# DATA messages received"), 1,
1870 GNUNET_NO);
1871 if (msize < sizeof(struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage))
1872 {
1873 LOG (GNUNET_ERROR_TYPE_DEBUG,
1874 "Size of packet is too small (%llu bytes < %llu)\n",
1875 (unsigned long long) msize,
1876 (unsigned long long) sizeof(struct
1877 GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage));
1878 break;
1879 }
1880 rxinfo = (const struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage *) hdr;
1881
1882 /* check if message is actually for us */
1883 if (0 != memcmp (&rxinfo->frame.addr3, &mac_bssid_gnunet,
1884 sizeof(struct GNUNET_TRANSPORT_WLAN_MacAddress)))
1885 {
1886 /* Not the GNUnet BSSID */
1887 break;
1888 }
1889 if ((0 != memcmp (&rxinfo->frame.addr1, &bc_all_mac,
1890 sizeof(struct GNUNET_TRANSPORT_WLAN_MacAddress))) &&
1891 (0 != memcmp (&rxinfo->frame.addr1, &plugin->mac_address,
1892 sizeof(struct GNUNET_TRANSPORT_WLAN_MacAddress))))
1893 {
1894 /* Neither broadcast nor specifically for us */
1895 break;
1896 }
1897 if (0 == memcmp (&rxinfo->frame.addr2, &plugin->mac_address,
1898 sizeof(struct GNUNET_TRANSPORT_WLAN_MacAddress)))
1899 {
1900 /* packet is FROM us, thus not FOR us */
1901 break;
1902 }
1903
1904 GNUNET_STATISTICS_update (plugin->env->stats,
1905 _ ("# DATA messages processed"),
1906 1, GNUNET_NO);
1907 LOG (GNUNET_ERROR_TYPE_DEBUG,
1908 "Receiving %u bytes of data from MAC `%s'\n",
1909 (unsigned int) (msize - sizeof(struct
1910 GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage)),
1911 mac_to_string (&rxinfo->frame.addr2));
1912 LOG (GNUNET_ERROR_TYPE_DEBUG,
1913 "Receiving %u bytes of data to MAC `%s'\n",
1914 (unsigned int) (msize - sizeof(struct
1915 GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage)),
1916 mac_to_string (&rxinfo->frame.addr1));
1917 LOG (GNUNET_ERROR_TYPE_DEBUG,
1918 "Receiving %u bytes of data with BSSID MAC `%s'\n",
1919 (unsigned int) (msize - sizeof(struct
1920 GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage)),
1921 mac_to_string (&rxinfo->frame.addr3));
1922 wa.mac = rxinfo->frame.addr2;
1923 wa.options = htonl (0);
1924 mas.endpoint = create_macendpoint (plugin, &wa);
1925 mas.session = NULL;
1926 (void) GNUNET_SERVER_mst_receive (plugin->helper_payload_tokenizer,
1927 &mas,
1928 (const char *) &rxinfo[1],
1929 msize - sizeof(struct
1930 GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage),
1931 GNUNET_YES, GNUNET_NO);
1932 break;
1933
1934 default:
1935 GNUNET_break (0);
1936 LOG (GNUNET_ERROR_TYPE_ERROR,
1937 "Unexpected message of type %u (%u bytes)",
1938 ntohs (hdr->type),
1939 ntohs (hdr->size));
1940 break;
1941 }
1942 return GNUNET_OK;
1943}
1944
1945
1946/**
1947 * Another peer has suggested an address for this
1948 * peer and transport plugin. Check that this could be a valid
1949 * address. If so, consider adding it to the list
1950 * of addresses.
1951 *
1952 * @param cls closure
1953 * @param addr pointer to the address
1954 * @param addrlen length of @a addr
1955 * @return #GNUNET_OK if this is a plausible address for this peer
1956 * and transport
1957 */
1958static int
1959wlan_plugin_address_suggested (void *cls,
1960 const void *addr,
1961 size_t addrlen)
1962{
1963 struct Plugin *plugin = cls;
1964 struct WlanAddress *wa = (struct WlanAddress *) addr;
1965
1966 if (addrlen != sizeof(struct WlanAddress))
1967 {
1968 GNUNET_break_op (0);
1969 return GNUNET_SYSERR;
1970 }
1971 if (GNUNET_YES != plugin->have_mac)
1972 {
1973 LOG (GNUNET_ERROR_TYPE_DEBUG,
1974 "Rejecting MAC `%s': I don't know my MAC!\n",
1975 mac_to_string (addr));
1976 return GNUNET_NO; /* don't know my MAC */
1977 }
1978 if (0 != memcmp (&wa->mac,
1979 &plugin->mac_address,
1980 sizeof(wa->mac)))
1981 {
1982 LOG (GNUNET_ERROR_TYPE_DEBUG,
1983 "Rejecting MAC `%s': not my MAC!\n",
1984 mac_to_string (addr));
1985 return GNUNET_NO; /* not my MAC */
1986 }
1987 return GNUNET_OK;
1988}
1989
1990
1991/**
1992 * Convert the transports address to a nice, human-readable format.
1993 *
1994 * @param cls closure
1995 * @param type name of the transport that generated the address
1996 * @param addr one of the addresses of the host, NULL for the last address
1997 * the specific address format depends on the transport
1998 * @param addrlen length of the address
1999 * @param numeric should (IP) addresses be displayed in numeric form?
2000 * @param timeout after how long should we give up?
2001 * @param asc function to call on each string
2002 * @param asc_cls closure for @a asc
2003 */
2004static void
2005wlan_plugin_address_pretty_printer (void *cls,
2006 const char *type,
2007 const void *addr,
2008 size_t addrlen,
2009 int numeric,
2010 struct GNUNET_TIME_Relative timeout,
2011 GNUNET_TRANSPORT_AddressStringCallback asc,
2012 void *asc_cls)
2013{
2014 const char *ret;
2015
2016 if (sizeof(struct WlanAddress) == addrlen)
2017 ret = wlan_plugin_address_to_string (NULL,
2018 addr,
2019 addrlen);
2020 else
2021 ret = NULL;
2022 asc (asc_cls,
2023 ret,
2024 (NULL == ret) ? GNUNET_SYSERR : GNUNET_OK);
2025 asc (asc_cls, NULL, GNUNET_OK);
2026}
2027
2028
2029/**
2030 * Exit point from the plugin.
2031 *
2032 * @param cls pointer to the api struct
2033 */
2034void *
2035LIBGNUNET_PLUGIN_TRANSPORT_DONE (void *cls)
2036{
2037 struct WlanAddress wa;
2038 struct GNUNET_HELLO_Address *address;
2039 struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
2040 struct Plugin *plugin = api->cls;
2041 struct MacEndpoint *endpoint;
2042 struct MacEndpoint *endpoint_next;
2043
2044 if (NULL == plugin)
2045 {
2046 GNUNET_free (api);
2047 return NULL;
2048 }
2049 if (GNUNET_YES == plugin->have_mac)
2050 {
2051 memset (&wa, 0, sizeof(wa));
2052 wa.options = htonl (plugin->options);
2053 wa.mac = plugin->mac_address;
2054 address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
2055 PLUGIN_NAME,
2056 &wa, sizeof(struct WlanAddress),
2057 GNUNET_HELLO_ADDRESS_INFO_NONE);
2058
2059 plugin->env->notify_address (plugin->env->cls,
2060 GNUNET_NO,
2061 address);
2062 plugin->have_mac = GNUNET_NO;
2063 GNUNET_HELLO_address_free (address);
2064 }
2065
2066 if (NULL != plugin->beacon_task)
2067 {
2068 GNUNET_SCHEDULER_cancel (plugin->beacon_task);
2069 plugin->beacon_task = NULL;
2070 }
2071 if (NULL != plugin->suid_helper)
2072 {
2073 GNUNET_HELPER_stop (plugin->suid_helper,
2074 GNUNET_NO);
2075 plugin->suid_helper = NULL;
2076 }
2077 endpoint_next = plugin->mac_head;
2078 while (NULL != (endpoint = endpoint_next))
2079 {
2080 endpoint_next = endpoint->next;
2081 free_macendpoint (endpoint);
2082 }
2083 if (NULL != plugin->fragment_data_tokenizer)
2084 {
2085 GNUNET_SERVER_mst_destroy (plugin->fragment_data_tokenizer);
2086 plugin->fragment_data_tokenizer = NULL;
2087 }
2088 if (NULL != plugin->wlan_header_payload_tokenizer)
2089 {
2090 GNUNET_SERVER_mst_destroy (plugin->wlan_header_payload_tokenizer);
2091 plugin->wlan_header_payload_tokenizer = NULL;
2092 }
2093 if (NULL != plugin->helper_payload_tokenizer)
2094 {
2095 GNUNET_SERVER_mst_destroy (plugin->helper_payload_tokenizer);
2096 plugin->helper_payload_tokenizer = NULL;
2097 }
2098 GNUNET_free (plugin->wlan_interface);
2099 GNUNET_free (plugin);
2100 GNUNET_free (api);
2101 return NULL;
2102}
2103
2104
2105/**
2106 * Function called to convert a string address to
2107 * a binary address.
2108 *
2109 * @param cls closure (`struct Plugin *`)
2110 * @param addr string address
2111 * @param addrlen length of the address
2112 * @param buf location to store the buffer
2113 * @param added location to store the number of bytes in the buffer.
2114 * If the function returns #GNUNET_SYSERR, its contents are undefined.
2115 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
2116 */
2117static int
2118wlan_plugin_string_to_address (void *cls,
2119 const char *addr,
2120 uint16_t addrlen,
2121 void **buf,
2122 size_t *added)
2123{
2124 struct WlanAddress *wa;
2125 unsigned int a[6];
2126 unsigned int i;
2127 char plugin[5];
2128 uint32_t options;
2129
2130 if ((NULL == addr) || (0 == addrlen))
2131 {
2132 GNUNET_break (0);
2133 return GNUNET_SYSERR;
2134 }
2135 if ('\0' != addr[addrlen - 1])
2136 {
2137 GNUNET_break (0);
2138 return GNUNET_SYSERR;
2139 }
2140 if (strlen (addr) != addrlen - 1)
2141 {
2142 GNUNET_break (0);
2143 return GNUNET_SYSERR;
2144 }
2145
2146 if (8 != sscanf (addr,
2147 "%4s.%u.%X:%X:%X:%X:%X:%X",
2148 plugin, &options,
2149 &a[0], &a[1], &a[2],
2150 &a[3], &a[4], &a[5]))
2151 {
2152 GNUNET_break (0);
2153 return GNUNET_SYSERR;
2154 }
2155 wa = GNUNET_new (struct WlanAddress);
2156 for (i = 0; i < 6; i++)
2157 wa->mac.mac[i] = a[i];
2158 wa->options = htonl (0);
2159 *buf = wa;
2160 *added = sizeof(struct WlanAddress);
2161 return GNUNET_OK;
2162}
2163
2164
2165/**
2166 * Begin monitoring sessions of a plugin. There can only
2167 * be one active monitor per plugin (i.e. if there are
2168 * multiple monitors, the transport service needs to
2169 * multiplex the generated events over all of them).
2170 *
2171 * @param cls closure of the plugin
2172 * @param sic callback to invoke, NULL to disable monitor;
2173 * plugin will being by iterating over all active
2174 * sessions immediately and then enter monitor mode
2175 * @param sic_cls closure for @a sic
2176 */
2177static void
2178wlan_plugin_setup_monitor (void *cls,
2179 GNUNET_TRANSPORT_SessionInfoCallback sic,
2180 void *sic_cls)
2181{
2182 struct Plugin *plugin = cls;
2183 struct MacEndpoint *mac;
2184 struct GNUNET_ATS_Session *session;
2185
2186 plugin->sic = sic;
2187 plugin->sic_cls = sic_cls;
2188 if (NULL != sic)
2189 {
2190 for (mac = plugin->mac_head; NULL != mac; mac = mac->next)
2191 for (session = mac->sessions_head; NULL != session; session =
2192 session->next)
2193 {
2194 notify_session_monitor (plugin,
2195 session,
2196 GNUNET_TRANSPORT_SS_INIT);
2197 notify_session_monitor (plugin,
2198 session,
2199 GNUNET_TRANSPORT_SS_UP);
2200 }
2201 sic (sic_cls, NULL, NULL);
2202 }
2203}
2204
2205
2206/**
2207 * Function that will be called whenever the transport service wants to
2208 * notify the plugin that a session is still active and in use and
2209 * therefore the session timeout for this session has to be updated
2210 *
2211 * @param cls closure
2212 * @param peer which peer was the session for
2213 * @param session which session is being updated
2214 */
2215static void
2216wlan_plugin_update_session_timeout (void *cls,
2217 const struct GNUNET_PeerIdentity *peer,
2218 struct GNUNET_ATS_Session *session)
2219{
2220 GNUNET_assert (NULL != session->timeout_task);
2221 session->timeout = GNUNET_TIME_relative_to_absolute (
2222 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2223}
2224
2225
2226/**
2227 * Function that will be called whenever the transport service wants to
2228 * notify the plugin that the inbound quota changed and that the plugin
2229 * should update it's delay for the next receive value
2230 *
2231 * @param cls closure
2232 * @param peer which peer was the session for
2233 * @param session which session is being updated
2234 * @param delay new delay to use for receiving
2235 */
2236static void
2237wlan_plugin_update_inbound_delay (void *cls,
2238 const struct GNUNET_PeerIdentity *peer,
2239 struct GNUNET_ATS_Session *session,
2240 struct GNUNET_TIME_Relative delay)
2241{
2242 /* does nothing, as inbound delay is not supported by WLAN */
2243}
2244
2245
2246/**
2247 * Entry point for the plugin.
2248 *
2249 * @param cls closure, the `struct GNUNET_TRANSPORT_PluginEnvironment *`
2250 * @return the `struct GNUNET_TRANSPORT_PluginFunctions *` or NULL on error
2251 */
2252void *
2253LIBGNUNET_PLUGIN_TRANSPORT_INIT (void *cls)
2254{
2255 struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
2256 struct GNUNET_TRANSPORT_PluginFunctions *api;
2257 struct Plugin *plugin;
2258 char *wlan_interface;
2259 unsigned long long testmode;
2260 char *binary;
2261
2262 /* check for 'special' mode */
2263 if (NULL == env->receive)
2264 {
2265 /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully
2266 initialize the plugin or the API */
2267 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
2268 api->cls = NULL;
2269 api->address_pretty_printer = &wlan_plugin_address_pretty_printer;
2270 api->address_to_string = &wlan_plugin_address_to_string;
2271 api->string_to_address = &wlan_plugin_string_to_address;
2272 return api;
2273 }
2274
2275 testmode = 0;
2276 /* check configuration */
2277 if ((GNUNET_YES ==
2278 GNUNET_CONFIGURATION_have_value (env->cfg,
2279 CONFIG_NAME,
2280 "TESTMODE")) &&
2281 ((GNUNET_SYSERR ==
2282 GNUNET_CONFIGURATION_get_value_number (env->cfg,
2283 CONFIG_NAME,
2284 "TESTMODE",
2285 &testmode)) ||
2286 (testmode > 2)))
2287 {
2288 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
2289 CONFIG_NAME,
2290 "TESTMODE");
2291 return NULL;
2292 }
2293 binary = GNUNET_OS_get_libexec_binary_path (HELPER_NAME);
2294 if ((0 == testmode) &&
2295 (GNUNET_YES !=
2296 GNUNET_OS_check_helper_binary (binary,
2297 GNUNET_YES,
2298 NULL)))
2299 {
2300 LOG (GNUNET_ERROR_TYPE_ERROR,
2301 _ ("Helper binary `%s' not SUID, cannot run WLAN transport\n"),
2302 HELPER_NAME);
2303 GNUNET_free (binary);
2304 return NULL;
2305 }
2306 GNUNET_free (binary);
2307 if (GNUNET_YES !=
2308 GNUNET_CONFIGURATION_get_value_string (env->cfg,
2309 CONFIG_NAME,
2310 "INTERFACE",
2311 &wlan_interface))
2312 {
2313 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
2314 CONFIG_NAME,
2315 "INTERFACE");
2316 return NULL;
2317 }
2318
2319 plugin = GNUNET_new (struct Plugin);
2320 plugin->wlan_interface = wlan_interface;
2321 plugin->env = env;
2322 GNUNET_STATISTICS_set (plugin->env->stats,
2323 _ ("# sessions allocated"),
2324 0, GNUNET_NO);
2325 GNUNET_STATISTICS_set (plugin->env->stats,
2326 _ ("# MAC endpoints allocated"),
2327 0, 0);
2328 GNUNET_BANDWIDTH_tracker_init (&plugin->tracker, NULL, NULL,
2329 GNUNET_BANDWIDTH_value_init (100 * 1024
2330 * 1024 / 8),
2331 100);
2332 plugin->fragment_data_tokenizer = GNUNET_SERVER_mst_create (&process_data,
2333 plugin);
2334 plugin->wlan_header_payload_tokenizer = GNUNET_SERVER_mst_create (
2335 &process_data,
2336 plugin);
2337 plugin->helper_payload_tokenizer = GNUNET_SERVER_mst_create (&process_data,
2338 plugin);
2339
2340 plugin->options = 0;
2341
2342 /* some compilers do not like switch on 'long long'... */
2343 switch ((unsigned int) testmode)
2344 {
2345 case 0: /* normal */
2346 plugin->helper_argv[0] = (char *) HELPER_NAME;
2347 plugin->helper_argv[1] = wlan_interface;
2348 plugin->helper_argv[2] = NULL;
2349 plugin->suid_helper = GNUNET_HELPER_start (GNUNET_NO,
2350 HELPER_NAME,
2351 plugin->helper_argv,
2352 &handle_helper_message,
2353 NULL,
2354 plugin);
2355 break;
2356
2357 case 1: /* testmode, peer 1 */
2358 plugin->helper_argv[0] = (char *) DUMMY_HELPER_NAME;
2359 plugin->helper_argv[1] = (char *) "1";
2360 plugin->helper_argv[2] = NULL;
2361 plugin->suid_helper = GNUNET_HELPER_start (GNUNET_NO,
2362 DUMMY_HELPER_NAME,
2363 plugin->helper_argv,
2364 &handle_helper_message,
2365 NULL,
2366 plugin);
2367 break;
2368
2369 case 2: /* testmode, peer 2 */
2370 plugin->helper_argv[0] = (char *) DUMMY_HELPER_NAME;
2371 plugin->helper_argv[1] = (char *) "2";
2372 plugin->helper_argv[2] = NULL;
2373 plugin->suid_helper = GNUNET_HELPER_start (GNUNET_NO,
2374 DUMMY_HELPER_NAME,
2375 plugin->helper_argv,
2376 &handle_helper_message,
2377 NULL,
2378 plugin);
2379 break;
2380
2381 default:
2382 GNUNET_assert (0);
2383 }
2384
2385 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
2386 api->cls = plugin;
2387 api->send = &wlan_plugin_send;
2388 api->get_session = &wlan_plugin_get_session;
2389 api->disconnect_peer = &wlan_plugin_disconnect_peer;
2390 api->disconnect_session = &wlan_plugin_disconnect_session;
2391 api->query_keepalive_factor = &wlan_plugin_query_keepalive_factor;
2392 api->address_pretty_printer = &wlan_plugin_address_pretty_printer;
2393 api->check_address = &wlan_plugin_address_suggested;
2394 api->address_to_string = &wlan_plugin_address_to_string;
2395 api->string_to_address = &wlan_plugin_string_to_address;
2396 api->get_network = &wlan_plugin_get_network;
2397 api->get_network_for_address = &wlan_plugin_get_network_for_address;
2398 api->update_session_timeout = &wlan_plugin_update_session_timeout;
2399 api->update_inbound_delay = &wlan_plugin_update_inbound_delay;
2400 api->setup_monitor = &wlan_plugin_setup_monitor;
2401 return api;
2402}
2403
2404
2405/* end of plugin_transport_wlan.c */
diff --git a/src/transport/plugin_transport_wlan.h b/src/transport/plugin_transport_wlan.h
deleted file mode 100644
index 6cb11f648..000000000
--- a/src/transport/plugin_transport_wlan.h
+++ /dev/null
@@ -1,276 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2010, 2011 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/plugin_transport_wlan.h
23 * @brief header for transport plugin and the helper for wlan
24 * @author David Brodski
25 */
26#ifndef PLUGIN_TRANSPORT_WLAN
27#define PLUGIN_TRANSPORT_WLAN
28
29#include "gnunet_util_lib.h"
30#include "gnunet_common.h"
31
32/**
33 * Number fo bytes in a mac address.
34 */
35#define MAC_ADDR_SIZE 6
36
37/**
38 * Value for "Management" in the 'frame_control' field of the
39 * struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame.
40 */
41#define IEEE80211_FC0_TYPE_MGT 0x00
42
43/**
44 * Value for "Control" in the 'frame_control' field of the
45 * struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame.
46 */
47#define IEEE80211_FC0_TYPE_CTL 0x04
48
49/**
50 * Value for DATA in the 'frame_control' field of the
51 * struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame.
52 */
53#define IEEE80211_FC0_TYPE_DATA 0x08
54
55
56GNUNET_NETWORK_STRUCT_BEGIN
57
58/**
59 * A MAC Address.
60 */
61struct GNUNET_TRANSPORT_WLAN_MacAddress
62{
63 uint8_t mac[MAC_ADDR_SIZE];
64};
65
66/**
67 * Format of a WLAN Control Message.
68 */
69struct GNUNET_TRANSPORT_WLAN_HelperControlMessage
70{
71 /**
72 * Message header. Type is
73 * GNUNET_MESSAGE_TYPE_WLAN_HELPER_CONTROL
74 */
75 struct GNUNET_MessageHeader hdr;
76
77 /**
78 * MAC Address of the local WLAN interface.
79 */
80 struct GNUNET_TRANSPORT_WLAN_MacAddress mac;
81};
82
83/**
84 * generic definitions for IEEE 802.3 frames
85 */
86struct GNUNET_TRANSPORT_WLAN_Ieee8023Frame
87{
88 /**
89 * Address 1: destination address in ad-hoc mode or AP, BSSID if station,
90 */
91 struct GNUNET_TRANSPORT_WLAN_MacAddress dst;
92
93 /**
94 * Address 2: source address if in ad-hoc-mode or station, BSSID if AP
95 */
96 struct GNUNET_TRANSPORT_WLAN_MacAddress src;
97
98 /**
99 * Packet type ID.
100 */
101 uint16_t type;
102};
103
104
105/**
106 * generic definitions for IEEE 802.11 frames
107 */
108struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame
109{
110 /**
111 * 802.11 Frame Control field. A bitmask. The overall field is a
112 * 16-bit mask of the respective fields. The lowest two bits should
113 * be 0, then comes the "type" (2 bits, see IEEE80211_FC0_TYPE_*
114 * constants), followed by 4-bit subtype (all zeros for ad-hoc),
115 * followed by various flags (to DS, from DS, more frag, retry,
116 * power management, more data, WEP, strict), all of which we also
117 * keep at zero.
118 */
119 uint16_t frame_control GNUNET_PACKED;
120
121 /**
122 * Microseconds to reserve link (duration), 0 by default
123 */
124 uint16_t duration GNUNET_PACKED;
125
126 /**
127 * Address 1: destination address in ad-hoc mode or AP, BSSID if station,
128 */
129 struct GNUNET_TRANSPORT_WLAN_MacAddress addr1;
130
131 /**
132 * Address 2: source address if in ad-hoc-mode or station, BSSID if AP
133 */
134 struct GNUNET_TRANSPORT_WLAN_MacAddress addr2;
135
136 /**
137 * Address 3: BSSID in ad-hoc mode, Destination if station, source if AP
138 */
139 struct GNUNET_TRANSPORT_WLAN_MacAddress addr3;
140
141 /**
142 * 802.11 sequence control field; contains fragment number an sequence
143 * number (we set this to all zeros).
144 */
145 uint16_t sequence_control GNUNET_PACKED;
146
147 /**
148 * Link layer control (LLC). Set to a GNUnet-specific value.
149 */
150 u_int8_t llc[4];
151
152 /* payload */
153} GNUNET_PACKED;
154
155
156/**
157 * Message from the plugin to the WLAN helper: send the given message with the
158 * given connection parameters.
159 */
160struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage
161{
162 /**
163 * Type is 'GNUNET_MESSAGE_TYPE_WLAN_DATA_TO_HELPER'.
164 */
165 struct GNUNET_MessageHeader header;
166
167 /**
168 * wlan send rate
169 */
170 uint8_t rate;
171
172 /**
173 * Antenna; the first antenna is 0.
174 */
175 uint8_t antenna;
176
177 /**
178 * Transmit power expressed as unitless distance from max power set at factory calibration.
179 * 0 is max power. Monotonically nondecreasing with lower power levels.
180 */
181 uint16_t tx_power GNUNET_PACKED;
182
183 /**
184 * IEEE Frame to transmit (the sender MAC address will be overwritten by the helper as it does not
185 * trust the plugin to set it correctly).
186 */
187 struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame frame;
188
189 /* actual payload follows */
190};
191
192
193/**
194 * Message from the WLAN helper to the plugin: we have received the given message with the
195 * given performance characteristics.
196 */
197/**
198 * struct to represent infos gathered form the radiotap fields, see RadiotapHeader for more Infos
199 */
200struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage
201{
202 /**
203 * Type is 'GNUNET_MESSAGE_TYPE_WLAN_DATA_FROM_HELPER'.
204 */
205 struct GNUNET_MessageHeader header;
206
207 /**
208 * Information about which of the fields below are actually valid.
209 * 0 for none. FIXME: not properly initialized so far (always zero).
210 */
211 uint32_t ri_present GNUNET_PACKED;
212
213 /**
214 * IEEE80211_RADIOTAP_TSFT, 0 if unknown.
215 */
216 uint64_t ri_mactime GNUNET_PACKED;
217
218 /**
219 * from radiotap
220 * either IEEE80211_RADIOTAP_DBM_ANTSIGNAL
221 * or IEEE80211_RADIOTAP_DB_ANTSIGNAL, 0 if unknown.
222 */
223 int32_t ri_power GNUNET_PACKED;
224
225 /**
226 * either IEEE80211_RADIOTAP_DBM_ANTNOISE
227 * or IEEE80211_RADIOTAP_DB_ANTNOISE, 0 if unknown.
228 */
229 int32_t ri_noise GNUNET_PACKED;
230
231 /**
232 * IEEE80211_RADIOTAP_CHANNEL, 0 if unknown.
233 */
234 uint32_t ri_channel GNUNET_PACKED;
235
236 /**
237 * Frequency we use. 0 if unknown.
238 */
239 uint32_t ri_freq GNUNET_PACKED;
240
241 /**
242 * IEEE80211_RADIOTAP_RATE * 50000, 0 if unknown.
243 */
244 uint32_t ri_rate GNUNET_PACKED;
245
246 /**
247 * IEEE80211_RADIOTAP_ANTENNA, 0 if unknown.
248 */
249 uint32_t ri_antenna GNUNET_PACKED;
250
251 /**
252 * IEEE Frame.
253 */
254 struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame frame;
255
256 /* followed by payload */
257};
258
259GNUNET_NETWORK_STRUCT_END
260
261/**
262 * GNUnet bssid
263 */
264static const struct GNUNET_TRANSPORT_WLAN_MacAddress mac_bssid_gnunet = {
265 { 0x13, 0x22, 0x33, 0x44, 0x55, 0x66 }
266};
267
268
269/**
270 * Broadcast MAC
271 */
272static const struct GNUNET_TRANSPORT_WLAN_MacAddress bc_all_mac = {
273 { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }
274};
275
276#endif
diff --git a/src/transport/tcp_connection_legacy.c b/src/transport/tcp_connection_legacy.c
deleted file mode 100644
index 551e79055..000000000
--- a/src/transport/tcp_connection_legacy.c
+++ /dev/null
@@ -1,1597 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file util/connection.c
23 * @brief TCP connection management
24 * @author Christian Grothoff
25 *
26 * This code is rather complex. Only modify it if you
27 * 1) Have a NEW testcase showing that the new code
28 * is needed and correct
29 * 2) All EXISTING testcases pass with the new code
30 * These rules should apply in general, but for this
31 * module they are VERY, VERY important.
32 */
33#include "platform.h"
34#include "gnunet_util_lib.h"
35#include "gnunet_resolver_service.h"
36
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 \
45 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
46
47
48#define LOG_STRERROR(kind, syscall) \
49 GNUNET_log_from_strerror (kind, "util-connection", syscall)
50
51
52/**
53 * Transmission handle. There can only be one for each connection.
54 */
55struct GNUNET_CONNECTION_TransmitHandle
56{
57 /**
58 * Function to call if the send buffer has notify_size
59 * bytes available.
60 */
61 GNUNET_CONNECTION_TransmitReadyNotify notify_ready;
62
63 /**
64 * Closure for notify_ready.
65 */
66 void *notify_ready_cls;
67
68 /**
69 * Our connection handle.
70 */
71 struct GNUNET_CONNECTION_Handle *connection;
72
73 /**
74 * Timeout for receiving (in absolute time).
75 */
76 struct GNUNET_TIME_Absolute transmit_timeout;
77
78 /**
79 * Task called on timeout.
80 */
81 struct GNUNET_SCHEDULER_Task *timeout_task;
82
83 /**
84 * At what number of bytes available in the
85 * write buffer should the notify method be called?
86 */
87 size_t notify_size;
88};
89
90
91/**
92 * During connect, we try multiple possible IP addresses
93 * to find out which one might work.
94 */
95struct AddressProbe
96{
97 /**
98 * This is a linked list.
99 */
100 struct AddressProbe *next;
101
102 /**
103 * This is a doubly-linked list.
104 */
105 struct AddressProbe *prev;
106
107 /**
108 * The address; do not free (allocated at the end of this struct).
109 */
110 const struct sockaddr *addr;
111
112 /**
113 * Underlying OS's socket.
114 */
115 struct GNUNET_NETWORK_Handle *sock;
116
117 /**
118 * Connection for which we are probing.
119 */
120 struct GNUNET_CONNECTION_Handle *connection;
121
122 /**
123 * Length of addr.
124 */
125 socklen_t addrlen;
126
127 /**
128 * Task waiting for the connection to finish connecting.
129 */
130 struct GNUNET_SCHEDULER_Task *task;
131};
132
133
134/**
135 * @brief handle for a network connection
136 */
137struct GNUNET_CONNECTION_Handle
138{
139 /**
140 * Configuration to use.
141 */
142 const struct GNUNET_CONFIGURATION_Handle *cfg;
143
144 /**
145 * Linked list of sockets we are currently trying out
146 * (during connect).
147 */
148 struct AddressProbe *ap_head;
149
150 /**
151 * Linked list of sockets we are currently trying out
152 * (during connect).
153 */
154 struct AddressProbe *ap_tail;
155
156 /**
157 * Network address of the other end-point, may be NULL.
158 */
159 struct sockaddr *addr;
160
161 /**
162 * Pointer to the hostname if connection was
163 * created using DNS lookup, otherwise NULL.
164 */
165 char *hostname;
166
167 /**
168 * Underlying OS's socket, set to NULL after fatal errors.
169 */
170 struct GNUNET_NETWORK_Handle *sock;
171
172 /**
173 * Function to call on data received, NULL if no receive is pending.
174 */
175 GNUNET_CONNECTION_Receiver receiver;
176
177 /**
178 * Closure for @e receiver.
179 */
180 void *receiver_cls;
181
182 /**
183 * Pointer to our write buffer.
184 */
185 char *write_buffer;
186
187 /**
188 * Current size of our @e write_buffer.
189 */
190 size_t write_buffer_size;
191
192 /**
193 * Current write-offset in @e write_buffer (where
194 * would we write next).
195 */
196 size_t write_buffer_off;
197
198 /**
199 * Current read-offset in @e write_buffer (how many
200 * bytes have already been sent).
201 */
202 size_t write_buffer_pos;
203
204 /**
205 * Length of @e addr.
206 */
207 socklen_t addrlen;
208
209 /**
210 * Read task that we may need to wait for.
211 */
212 struct GNUNET_SCHEDULER_Task *read_task;
213
214 /**
215 * Write task that we may need to wait for.
216 */
217 struct GNUNET_SCHEDULER_Task *write_task;
218
219 /**
220 * Handle to a pending DNS lookup request.
221 */
222 struct GNUNET_RESOLVER_RequestHandle *dns_active;
223
224 /**
225 * The handle we return for #GNUNET_CONNECTION_notify_transmit_ready().
226 */
227 struct GNUNET_CONNECTION_TransmitHandle nth;
228
229 /**
230 * Timeout for receiving (in absolute time).
231 */
232 struct GNUNET_TIME_Absolute receive_timeout;
233
234 /**
235 * Maximum number of bytes to read (for receiving).
236 */
237 size_t max;
238
239 /**
240 * Port to connect to.
241 */
242 uint16_t port;
243
244 /**
245 * When shutdown, do not ever actually close the socket, but
246 * free resources. Only should ever be set if using program
247 * termination as a signal (because only then will the leaked
248 * socket be freed!)
249 */
250 int8_t persist;
251
252 /**
253 * Usually 0. Set to 1 if this handle is in use, and should
254 * #GNUNET_CONNECTION_destroy() be called right now, the action needs
255 * to be deferred by setting it to -1.
256 */
257 int8_t destroy_later;
258
259 /**
260 * Handle to subsequent connection after proxy handshake completes,
261 */
262 struct GNUNET_CONNECTION_Handle *proxy_handshake;
263};
264
265
266/**
267 * Set the persist option on this connection handle. Indicates
268 * that the underlying socket or fd should never really be closed.
269 * Used for indicating process death.
270 *
271 * @param connection the connection to set persistent
272 */
273void
274GNUNET_CONNECTION_persist_ (struct GNUNET_CONNECTION_Handle *connection)
275{
276 connection->persist = GNUNET_YES;
277}
278
279
280/**
281 * Disable the "CORK" feature for communication with the given connection,
282 * forcing the OS to immediately flush the buffer on transmission
283 * instead of potentially buffering multiple messages. Essentially
284 * reduces the OS send buffers to zero.
285 * Used to make sure that the last messages sent through the connection
286 * reach the other side before the process is terminated.
287 *
288 * @param connection the connection to make flushing and blocking
289 * @return #GNUNET_OK on success
290 */
291int
292GNUNET_CONNECTION_disable_corking (struct GNUNET_CONNECTION_Handle *connection)
293{
294 return GNUNET_NETWORK_socket_disable_corking (connection->sock);
295}
296
297
298/**
299 * Create a connection handle by boxing an existing OS socket. The OS
300 * socket should henceforth be no longer used directly.
301 * #GNUNET_connection_destroy() will close it.
302 *
303 * @param osSocket existing socket to box
304 * @return the boxed connection handle
305 */
306struct GNUNET_CONNECTION_Handle *
307GNUNET_CONNECTION_create_from_existing (struct GNUNET_NETWORK_Handle *osSocket)
308{
309 struct GNUNET_CONNECTION_Handle *connection;
310
311 connection = GNUNET_new (struct GNUNET_CONNECTION_Handle);
312 connection->write_buffer_size = GNUNET_MIN_MESSAGE_SIZE;
313 connection->write_buffer = GNUNET_malloc (connection->write_buffer_size);
314 connection->sock = osSocket;
315 return connection;
316}
317
318
319/**
320 * Create a connection handle by accepting on a listen socket. This
321 * function may block if the listen socket has no connection ready.
322 *
323 * @param access_cb function to use to check if access is allowed
324 * @param access_cb_cls closure for @a access_cb
325 * @param lsock listen socket
326 * @return the connection handle, NULL on error
327 */
328struct GNUNET_CONNECTION_Handle *
329GNUNET_CONNECTION_create_from_accept (GNUNET_CONNECTION_AccessCheck access_cb,
330 void *access_cb_cls,
331 struct GNUNET_NETWORK_Handle *lsock)
332{
333 struct GNUNET_CONNECTION_Handle *connection;
334 char addr[128];
335 socklen_t addrlen;
336 struct GNUNET_NETWORK_Handle *sock;
337 int aret;
338 struct sockaddr_in *v4;
339 struct sockaddr_in6 *v6;
340 struct sockaddr *sa;
341 void *uaddr;
342
343#ifdef SO_PEERCRED
344 struct ucred uc;
345 socklen_t olen;
346#endif
347 struct GNUNET_CONNECTION_Credentials *gcp;
348#if HAVE_GETPEEREID || defined(SO_PEERCRED) || HAVE_GETPEERUCRED
349 struct GNUNET_CONNECTION_Credentials gc;
350
351 gc.uid = 0;
352 gc.gid = 0;
353#endif
354
355 addrlen = sizeof(addr);
356 sock =
357 GNUNET_NETWORK_socket_accept (lsock, (struct sockaddr *) &addr, &addrlen);
358 if (NULL == sock)
359 {
360 if (EAGAIN != errno)
361 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "accept");
362 return NULL;
363 }
364 if ((addrlen > sizeof(addr)) || (addrlen < sizeof(sa_family_t)))
365 {
366 GNUNET_break (0);
367 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
368 return NULL;
369 }
370
371 sa = (struct sockaddr *) addr;
372 v6 = (struct sockaddr_in6 *) addr;
373 if ((AF_INET6 == sa->sa_family) && (IN6_IS_ADDR_V4MAPPED (&v6->sin6_addr)))
374 {
375 /* convert to V4 address */
376 v4 = GNUNET_new (struct sockaddr_in);
377 memset (v4, 0, sizeof(struct sockaddr_in));
378 v4->sin_family = AF_INET;
379#if HAVE_SOCKADDR_IN_SIN_LEN
380 v4->sin_len = (u_char) sizeof(struct sockaddr_in);
381#endif
382 GNUNET_memcpy (&v4->sin_addr,
383 &((char *) &v6->sin6_addr)[sizeof(struct in6_addr)
384 - sizeof(struct in_addr)],
385 sizeof(struct in_addr));
386 v4->sin_port = v6->sin6_port;
387 uaddr = v4;
388 addrlen = sizeof(struct sockaddr_in);
389 }
390 else
391 {
392 uaddr = GNUNET_malloc (addrlen);
393 GNUNET_memcpy (uaddr, addr, addrlen);
394 }
395 gcp = NULL;
396 if (AF_UNIX == sa->sa_family)
397 {
398#if HAVE_GETPEEREID
399 /* most BSDs */
400 if (0 == getpeereid (GNUNET_NETWORK_get_fd (sock), &gc.uid, &gc.gid))
401 gcp = &gc;
402#else
403#ifdef SO_PEERCRED
404 /* largely traditional GNU/Linux */
405 olen = sizeof(uc);
406 if ((0 == getsockopt (GNUNET_NETWORK_get_fd (sock),
407 SOL_SOCKET,
408 SO_PEERCRED,
409 &uc,
410 &olen)) &&
411 (olen == sizeof(uc)))
412 {
413 gc.uid = uc.uid;
414 gc.gid = uc.gid;
415 gcp = &gc;
416 }
417#else
418#if HAVE_GETPEERUCRED
419 /* this is for Solaris 10 */
420 ucred_t *uc;
421
422 uc = NULL;
423 if (0 == getpeerucred (GNUNET_NETWORK_get_fd (sock), &uc))
424 {
425 gc.uid = ucred_geteuid (uc);
426 gc.gid = ucred_getegid (uc);
427 gcp = &gc;
428 }
429 ucred_free (uc);
430#endif
431#endif
432#endif
433 }
434
435 if ((NULL != access_cb) &&
436 (GNUNET_YES != (aret = access_cb (access_cb_cls, gcp, uaddr, addrlen))))
437 {
438 if (GNUNET_NO == aret)
439 LOG (GNUNET_ERROR_TYPE_INFO,
440 _ ("Access denied to `%s'\n"),
441 GNUNET_a2s (uaddr, addrlen));
442 GNUNET_break (GNUNET_OK ==
443 GNUNET_NETWORK_socket_shutdown (sock, SHUT_RDWR));
444 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
445 GNUNET_free (uaddr);
446 return NULL;
447 }
448 connection = GNUNET_new (struct GNUNET_CONNECTION_Handle);
449 connection->write_buffer_size = GNUNET_MIN_MESSAGE_SIZE;
450 connection->write_buffer = GNUNET_malloc (connection->write_buffer_size);
451 connection->addr = uaddr;
452 connection->addrlen = addrlen;
453 connection->sock = sock;
454 LOG (GNUNET_ERROR_TYPE_INFO,
455 _ ("Accepting connection from `%s': %p\n"),
456 GNUNET_a2s (uaddr, addrlen),
457 connection);
458 return connection;
459}
460
461
462/**
463 * Obtain the network address of the other party.
464 *
465 * @param connection the client to get the address for
466 * @param addr where to store the address
467 * @param addrlen where to store the length of the @a addr
468 * @return #GNUNET_OK on success
469 */
470int
471GNUNET_CONNECTION_get_address (struct GNUNET_CONNECTION_Handle *connection,
472 void **addr,
473 size_t *addrlen)
474{
475 if ((NULL == connection->addr) || (0 == connection->addrlen))
476 return GNUNET_NO;
477 *addr = GNUNET_malloc (connection->addrlen);
478 GNUNET_memcpy (*addr, connection->addr, connection->addrlen);
479 *addrlen = connection->addrlen;
480 return GNUNET_OK;
481}
482
483
484/**
485 * Tell the receiver callback that we had an IO error.
486 *
487 * @param connection connection to signal error
488 * @param errcode error code to send
489 */
490static void
491signal_receive_error (struct GNUNET_CONNECTION_Handle *connection, int errcode)
492{
493 GNUNET_CONNECTION_Receiver receiver;
494
495 LOG (GNUNET_ERROR_TYPE_DEBUG,
496 "Receive encounters error (%s), connection closed (%p)\n",
497 strerror (errcode),
498 connection);
499 GNUNET_assert (NULL != (receiver = connection->receiver));
500 connection->receiver = NULL;
501 receiver (connection->receiver_cls,
502 NULL,
503 0,
504 connection->addr,
505 connection->addrlen,
506 errcode);
507}
508
509
510/**
511 * Tell the receiver callback that a timeout was reached.
512 *
513 * @param connection connection to signal for
514 */
515static void
516signal_receive_timeout (struct GNUNET_CONNECTION_Handle *connection)
517{
518 GNUNET_CONNECTION_Receiver receiver;
519
520 LOG (GNUNET_ERROR_TYPE_DEBUG,
521 "Connection signals timeout to receiver (%p)!\n",
522 connection);
523 GNUNET_assert (NULL != (receiver = connection->receiver));
524 connection->receiver = NULL;
525 receiver (connection->receiver_cls, NULL, 0, NULL, 0, 0);
526}
527
528
529/**
530 * We failed to transmit data to the service, signal the error.
531 *
532 * @param connection handle that had trouble
533 * @param ecode error code (errno)
534 */
535static void
536signal_transmit_error (struct GNUNET_CONNECTION_Handle *connection, int ecode)
537{
538 GNUNET_CONNECTION_TransmitReadyNotify notify;
539
540 LOG (GNUNET_ERROR_TYPE_DEBUG,
541 "Transmission encountered error (%s), connection closed (%p)\n",
542 strerror (ecode),
543 connection);
544 if (NULL != connection->sock)
545 {
546 (void) GNUNET_NETWORK_socket_shutdown (connection->sock, SHUT_RDWR);
547 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (connection->sock));
548 connection->sock = NULL;
549 GNUNET_assert (NULL == connection->write_task);
550 }
551 if (NULL != connection->read_task)
552 {
553 /* send errors trigger read errors... */
554 GNUNET_SCHEDULER_cancel (connection->read_task);
555 connection->read_task = NULL;
556 signal_receive_timeout (connection);
557 return;
558 }
559 if (NULL == connection->nth.notify_ready)
560 return; /* nobody to tell about it */
561 notify = connection->nth.notify_ready;
562 connection->nth.notify_ready = NULL;
563 notify (connection->nth.notify_ready_cls, 0, NULL);
564}
565
566
567/**
568 * We've failed for good to establish a connection (timeout or
569 * no more addresses to try).
570 *
571 * @param connection the connection we tried to establish
572 */
573static void
574connect_fail_continuation (struct GNUNET_CONNECTION_Handle *connection)
575{
576 LOG (GNUNET_ERROR_TYPE_INFO,
577 "Failed to establish TCP connection to `%s:%u', no further addresses to try.\n",
578 connection->hostname,
579 connection->port);
580 GNUNET_break (NULL == connection->ap_head);
581 GNUNET_break (NULL == connection->ap_tail);
582 GNUNET_break (GNUNET_NO == connection->dns_active);
583 GNUNET_break (NULL == connection->sock);
584 GNUNET_assert (NULL == connection->write_task);
585 GNUNET_assert (NULL == connection->proxy_handshake);
586
587 /* signal errors for jobs that used to wait on the connection */
588 connection->destroy_later = 1;
589 if (NULL != connection->receiver)
590 signal_receive_error (connection, ECONNREFUSED);
591 if (NULL != connection->nth.notify_ready)
592 {
593 GNUNET_assert (NULL != connection->nth.timeout_task);
594 GNUNET_SCHEDULER_cancel (connection->nth.timeout_task);
595 connection->nth.timeout_task = NULL;
596 signal_transmit_error (connection, ECONNREFUSED);
597 }
598 if (-1 == connection->destroy_later)
599 {
600 /* do it now */
601 connection->destroy_later = 0;
602 GNUNET_CONNECTION_destroy (connection);
603 return;
604 }
605 connection->destroy_later = 0;
606}
607
608
609/**
610 * We are ready to transmit (or got a timeout).
611 *
612 * @param cls our connection handle
613 */
614static void
615transmit_ready (void *cls);
616
617
618/**
619 * This function is called once we either timeout or have data ready
620 * to read.
621 *
622 * @param cls connection to read from
623 */
624static void
625receive_ready (void *cls);
626
627
628/**
629 * We've succeeded in establishing a connection.
630 *
631 * @param connection the connection we tried to establish
632 */
633static void
634connect_success_continuation (struct GNUNET_CONNECTION_Handle *connection)
635{
636 LOG (GNUNET_ERROR_TYPE_DEBUG,
637 "Connection to `%s' succeeded! (%p)\n",
638 GNUNET_a2s (connection->addr, connection->addrlen),
639 connection);
640 /* trigger jobs that waited for the connection */
641 if (NULL != connection->receiver)
642 {
643 LOG (GNUNET_ERROR_TYPE_DEBUG,
644 "Connection succeeded, starting with receiving data (%p)\n",
645 connection);
646 GNUNET_assert (NULL == connection->read_task);
647 connection->read_task =
648 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_absolute_get_remaining (
649 connection->receive_timeout),
650 connection->sock,
651 &receive_ready,
652 connection);
653 }
654 if (NULL != connection->nth.notify_ready)
655 {
656 LOG (GNUNET_ERROR_TYPE_DEBUG,
657 "Connection succeeded, starting with sending data (%p)\n",
658 connection);
659 GNUNET_assert (connection->nth.timeout_task != NULL);
660 GNUNET_SCHEDULER_cancel (connection->nth.timeout_task);
661 connection->nth.timeout_task = NULL;
662 GNUNET_assert (connection->write_task == NULL);
663 connection->write_task =
664 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_absolute_get_remaining (
665 connection->nth.transmit_timeout),
666 connection->sock,
667 &transmit_ready,
668 connection);
669 }
670}
671
672
673/**
674 * Scheduler let us know that we're either ready to write on the
675 * socket OR connect timed out. Do the right thing.
676 *
677 * @param cls the `struct AddressProbe *` with the address that we are probing
678 */
679static void
680connect_probe_continuation (void *cls)
681{
682 struct AddressProbe *ap = cls;
683 struct GNUNET_CONNECTION_Handle *connection = ap->connection;
684 const struct GNUNET_SCHEDULER_TaskContext *tc;
685 struct AddressProbe *pos;
686 int error;
687 socklen_t len;
688
689 GNUNET_assert (NULL != ap->sock);
690 GNUNET_CONTAINER_DLL_remove (connection->ap_head, connection->ap_tail, ap);
691 len = sizeof(error);
692 errno = 0;
693 error = 0;
694 tc = GNUNET_SCHEDULER_get_task_context ();
695 if ((0 == (tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) ||
696 (GNUNET_OK != GNUNET_NETWORK_socket_getsockopt (ap->sock,
697 SOL_SOCKET,
698 SO_ERROR,
699 &error,
700 &len)) ||
701 (0 != error))
702 {
703 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (ap->sock));
704 GNUNET_free (ap);
705 if ((NULL == connection->ap_head) &&
706 (GNUNET_NO == connection->dns_active) &&
707 (NULL == connection->proxy_handshake))
708 connect_fail_continuation (connection);
709 return;
710 }
711 GNUNET_assert (NULL == connection->sock);
712 connection->sock = ap->sock;
713 GNUNET_assert (NULL == connection->addr);
714 connection->addr = GNUNET_malloc (ap->addrlen);
715 GNUNET_memcpy (connection->addr, ap->addr, ap->addrlen);
716 connection->addrlen = ap->addrlen;
717 GNUNET_free (ap);
718 /* cancel all other attempts */
719 while (NULL != (pos = connection->ap_head))
720 {
721 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (pos->sock));
722 GNUNET_SCHEDULER_cancel (pos->task);
723 GNUNET_CONTAINER_DLL_remove (connection->ap_head, connection->ap_tail, pos);
724 GNUNET_free (pos);
725 }
726 connect_success_continuation (connection);
727}
728
729
730/**
731 * Try to establish a connection given the specified address.
732 * This function is called by the resolver once we have a DNS reply.
733 *
734 * @param cls our `struct GNUNET_CONNECTION_Handle *`
735 * @param addr address to try, NULL for "last call"
736 * @param addrlen length of @a addr
737 */
738static void
739try_connect_using_address (void *cls,
740 const struct sockaddr *addr,
741 socklen_t addrlen)
742{
743 struct GNUNET_CONNECTION_Handle *connection = cls;
744 struct AddressProbe *ap;
745 struct GNUNET_TIME_Relative delay;
746
747 if (NULL == addr)
748 {
749 connection->dns_active = NULL;
750 if ((NULL == connection->ap_head) && (NULL == connection->sock) &&
751 (NULL == connection->proxy_handshake))
752 connect_fail_continuation (connection);
753 return;
754 }
755 if (NULL != connection->sock)
756 return; /* already connected */
757 GNUNET_assert (NULL == connection->addr);
758 /* try to connect */
759 LOG (GNUNET_ERROR_TYPE_DEBUG,
760 "Trying to connect using address `%s:%u/%s:%u'\n",
761 connection->hostname,
762 connection->port,
763 GNUNET_a2s (addr, addrlen),
764 connection->port);
765 ap = GNUNET_malloc (sizeof(struct AddressProbe) + addrlen);
766 ap->addr = (const struct sockaddr *) &ap[1];
767 GNUNET_memcpy (&ap[1], addr, addrlen);
768 ap->addrlen = addrlen;
769 ap->connection = connection;
770
771 switch (ap->addr->sa_family)
772 {
773 case AF_INET:
774 ((struct sockaddr_in *) ap->addr)->sin_port = htons (connection->port);
775 break;
776
777 case AF_INET6:
778 ((struct sockaddr_in6 *) ap->addr)->sin6_port = htons (connection->port);
779 break;
780
781 default:
782 GNUNET_break (0);
783 GNUNET_free (ap);
784 return; /* not supported by us */
785 }
786 ap->sock = GNUNET_NETWORK_socket_create (ap->addr->sa_family, SOCK_STREAM, 0);
787 if (NULL == ap->sock)
788 {
789 GNUNET_free (ap);
790 return; /* not supported by OS */
791 }
792 LOG (GNUNET_ERROR_TYPE_INFO,
793 "Trying to connect to `%s' (%p)\n",
794 GNUNET_a2s (ap->addr, ap->addrlen),
795 connection);
796 if ((GNUNET_OK !=
797 GNUNET_NETWORK_socket_connect (ap->sock, ap->addr, ap->addrlen)) &&
798 (EINPROGRESS != errno))
799 {
800 /* maybe refused / unsupported address, try next */
801 LOG_STRERROR (GNUNET_ERROR_TYPE_INFO, "connect");
802 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (ap->sock));
803 GNUNET_free (ap);
804 return;
805 }
806 GNUNET_CONTAINER_DLL_insert (connection->ap_head, connection->ap_tail, ap);
807 delay = CONNECT_RETRY_TIMEOUT;
808 if (NULL != connection->nth.notify_ready)
809 delay = GNUNET_TIME_relative_min (delay,
810 GNUNET_TIME_absolute_get_remaining (
811 connection->nth.transmit_timeout));
812 if (NULL != connection->receiver)
813 delay = GNUNET_TIME_relative_min (delay,
814 GNUNET_TIME_absolute_get_remaining (
815 connection->receive_timeout));
816 ap->task = GNUNET_SCHEDULER_add_write_net (delay,
817 ap->sock,
818 &connect_probe_continuation,
819 ap);
820}
821
822
823/**
824 * Create a connection handle by (asynchronously) connecting to a host.
825 * This function returns immediately, even if the connection has not
826 * yet been established. This function only creates TCP connections.
827 *
828 * @param cfg configuration to use
829 * @param hostname name of the host to connect to
830 * @param port port to connect to
831 * @return the connection handle
832 */
833struct GNUNET_CONNECTION_Handle *
834GNUNET_CONNECTION_create_from_connect (
835 const struct GNUNET_CONFIGURATION_Handle *cfg,
836 const char *hostname,
837 uint16_t port)
838{
839 struct GNUNET_CONNECTION_Handle *connection;
840
841 GNUNET_assert (0 < strlen (hostname)); /* sanity check */
842 connection = GNUNET_new (struct GNUNET_CONNECTION_Handle);
843 connection->cfg = cfg;
844 connection->write_buffer_size = GNUNET_MIN_MESSAGE_SIZE;
845 connection->write_buffer = GNUNET_malloc (connection->write_buffer_size);
846 connection->port = port;
847 connection->hostname = GNUNET_strdup (hostname);
848 connection->dns_active = GNUNET_RESOLVER_ip_get (connection->hostname,
849 AF_UNSPEC,
850 CONNECT_RETRY_TIMEOUT,
851 &try_connect_using_address,
852 connection);
853 return connection;
854}
855
856
857/**
858 * Create a connection handle by connecting to a UNIX domain service.
859 * This function returns immediately, even if the connection has not
860 * yet been established. This function only creates UNIX connections.
861 *
862 * @param cfg configuration to use
863 * @param unixpath path to connect to
864 * @return the connection handle, NULL on systems without UNIX support
865 */
866struct GNUNET_CONNECTION_Handle *
867GNUNET_CONNECTION_create_from_connect_to_unixpath (
868 const struct GNUNET_CONFIGURATION_Handle *cfg,
869 const char *unixpath)
870{
871#ifdef AF_UNIX
872 struct GNUNET_CONNECTION_Handle *connection;
873 struct sockaddr_un *un;
874
875 GNUNET_assert (0 < strlen (unixpath)); /* sanity check */
876 un = GNUNET_new (struct sockaddr_un);
877 un->sun_family = AF_UNIX;
878 GNUNET_strlcpy (un->sun_path, unixpath, sizeof(un->sun_path));
879#ifdef __linux__
880 {
881 int abstract;
882
883 abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg,
884 "TESTING",
885 "USE_ABSTRACT_SOCKETS");
886 if (GNUNET_YES == abstract)
887 un->sun_path[0] = '\0';
888 }
889#endif
890#if HAVE_SOCKADDR_UN_SUN_LEN
891 un->sun_len = (u_char) sizeof(struct sockaddr_un);
892#endif
893 connection = GNUNET_new (struct GNUNET_CONNECTION_Handle);
894 connection->cfg = cfg;
895 connection->write_buffer_size = GNUNET_MIN_MESSAGE_SIZE;
896 connection->write_buffer = GNUNET_malloc (connection->write_buffer_size);
897 connection->port = 0;
898 connection->hostname = NULL;
899 connection->addr = (struct sockaddr *) un;
900 connection->addrlen = sizeof(struct sockaddr_un);
901 connection->sock = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
902 if (NULL == connection->sock)
903 {
904 GNUNET_free (connection->addr);
905 GNUNET_free (connection->write_buffer);
906 GNUNET_free (connection);
907 return NULL;
908 }
909 if ((GNUNET_OK != GNUNET_NETWORK_socket_connect (connection->sock,
910 connection->addr,
911 connection->addrlen)) &&
912 (EINPROGRESS != errno))
913 {
914 /* Just return; we expect everything to work eventually so don't fail HARD */
915 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (connection->sock));
916 connection->sock = NULL;
917 return connection;
918 }
919 connect_success_continuation (connection);
920 return connection;
921#else
922 return NULL;
923#endif
924}
925
926
927/**
928 * Create a connection handle by (asynchronously) connecting to a host.
929 * This function returns immediately, even if the connection has not
930 * yet been established. This function only creates TCP connections.
931 *
932 * @param s socket to connect
933 * @param serv_addr server address
934 * @param addrlen length of @a serv_addr
935 * @return the connection handle
936 */
937struct GNUNET_CONNECTION_Handle *
938GNUNET_CONNECTION_connect_socket (struct GNUNET_NETWORK_Handle *s,
939 const struct sockaddr *serv_addr,
940 socklen_t addrlen)
941{
942 struct GNUNET_CONNECTION_Handle *connection;
943
944 if ((GNUNET_OK != GNUNET_NETWORK_socket_connect (s, serv_addr, addrlen)) &&
945 (EINPROGRESS != errno))
946 {
947 /* maybe refused / unsupported address, try next */
948 LOG_STRERROR (GNUNET_ERROR_TYPE_DEBUG, "connect");
949 LOG (GNUNET_ERROR_TYPE_DEBUG,
950 "Attempt to connect to `%s' failed\n",
951 GNUNET_a2s (serv_addr, addrlen));
952 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (s));
953 return NULL;
954 }
955 connection = GNUNET_CONNECTION_create_from_existing (s);
956 connection->addr = GNUNET_malloc (addrlen);
957 GNUNET_memcpy (connection->addr, serv_addr, addrlen);
958 connection->addrlen = addrlen;
959 LOG (GNUNET_ERROR_TYPE_INFO,
960 "Trying to connect to `%s' (%p)\n",
961 GNUNET_a2s (serv_addr, addrlen),
962 connection);
963 return connection;
964}
965
966
967/**
968 * Create a connection handle by creating a socket and
969 * (asynchronously) connecting to a host. This function returns
970 * immediately, even if the connection has not yet been established.
971 * This function only creates TCP connections.
972 *
973 * @param af_family address family to use
974 * @param serv_addr server address
975 * @param addrlen length of @a serv_addr
976 * @return the connection handle
977 */
978struct GNUNET_CONNECTION_Handle *
979GNUNET_CONNECTION_create_from_sockaddr (int af_family,
980 const struct sockaddr *serv_addr,
981 socklen_t addrlen)
982{
983 struct GNUNET_NETWORK_Handle *s;
984
985 s = GNUNET_NETWORK_socket_create (af_family, SOCK_STREAM, 0);
986 if (NULL == s)
987 {
988 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, "socket");
989 return NULL;
990 }
991 return GNUNET_CONNECTION_connect_socket (s, serv_addr, addrlen);
992}
993
994
995/**
996 * Check if connection is valid (no fatal errors have happened so far).
997 * Note that a connection that is still trying to connect is considered
998 * valid.
999 *
1000 * @param connection connection to check
1001 * @return #GNUNET_YES if valid, #GNUNET_NO otherwise
1002 */
1003int
1004GNUNET_CONNECTION_check (struct GNUNET_CONNECTION_Handle *connection)
1005{
1006 if ((NULL != connection->ap_head) || (NULL != connection->dns_active) ||
1007 (NULL != connection->proxy_handshake))
1008 return GNUNET_YES; /* still trying to connect */
1009 if ((0 != connection->destroy_later) || (NULL == connection->sock))
1010 return GNUNET_NO;
1011 return GNUNET_YES;
1012}
1013
1014
1015/**
1016 * Close the connection and free associated resources. There must
1017 * not be any pending requests for reading or writing to the
1018 * connection at this time.
1019 *
1020 * @param connection connection to destroy
1021 */
1022void
1023GNUNET_CONNECTION_destroy (struct GNUNET_CONNECTION_Handle *connection)
1024{
1025 struct AddressProbe *pos;
1026
1027 if (0 != connection->destroy_later)
1028 {
1029 connection->destroy_later = -1;
1030 return;
1031 }
1032 LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down connection (%p)\n", connection);
1033 GNUNET_assert (NULL == connection->nth.notify_ready);
1034 GNUNET_assert (NULL == connection->receiver);
1035 if (NULL != connection->write_task)
1036 {
1037 GNUNET_SCHEDULER_cancel (connection->write_task);
1038 connection->write_task = NULL;
1039 connection->write_buffer_off = 0;
1040 }
1041 if (NULL != connection->read_task)
1042 {
1043 GNUNET_SCHEDULER_cancel (connection->read_task);
1044 connection->read_task = NULL;
1045 }
1046 if (NULL != connection->nth.timeout_task)
1047 {
1048 GNUNET_SCHEDULER_cancel (connection->nth.timeout_task);
1049 connection->nth.timeout_task = NULL;
1050 }
1051 connection->nth.notify_ready = NULL;
1052 if (NULL != connection->dns_active)
1053 {
1054 GNUNET_RESOLVER_request_cancel (connection->dns_active);
1055 connection->dns_active = NULL;
1056 }
1057 if (NULL != connection->proxy_handshake)
1058 {
1059 /* GNUNET_CONNECTION_destroy (connection->proxy_handshake); */
1060 connection->proxy_handshake->destroy_later = -1;
1061 connection->proxy_handshake = NULL; /* Not leaked ??? */
1062 }
1063 while (NULL != (pos = connection->ap_head))
1064 {
1065 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (pos->sock));
1066 GNUNET_SCHEDULER_cancel (pos->task);
1067 GNUNET_CONTAINER_DLL_remove (connection->ap_head, connection->ap_tail, pos);
1068 GNUNET_free (pos);
1069 }
1070 if ((NULL != connection->sock) && (GNUNET_YES != connection->persist))
1071 {
1072 if ((GNUNET_OK !=
1073 GNUNET_NETWORK_socket_shutdown (connection->sock, SHUT_RDWR)) &&
1074 (ENOTCONN != errno) && (ECONNRESET != errno))
1075 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "shutdown");
1076 }
1077 if (NULL != connection->sock)
1078 {
1079 if (GNUNET_YES != connection->persist)
1080 {
1081 GNUNET_break (GNUNET_OK ==
1082 GNUNET_NETWORK_socket_close (connection->sock));
1083 }
1084 else
1085 {
1086 GNUNET_NETWORK_socket_free_memory_only_ (
1087 connection->sock); /* at least no memory leak (we deliberately
1088 * leak the socket in this special case) ... */
1089 }
1090 }
1091 GNUNET_free (connection->addr);
1092 GNUNET_free (connection->hostname);
1093 GNUNET_free (connection->write_buffer);
1094 GNUNET_free (connection);
1095}
1096
1097
1098/**
1099 * This function is called once we either timeout
1100 * or have data ready to read.
1101 *
1102 * @param cls connection to read from
1103 */
1104static void
1105receive_ready (void *cls)
1106{
1107 struct GNUNET_CONNECTION_Handle *connection = cls;
1108 const struct GNUNET_SCHEDULER_TaskContext *tc;
1109 char buffer[connection->max];
1110 ssize_t ret;
1111 GNUNET_CONNECTION_Receiver receiver;
1112
1113 connection->read_task = NULL;
1114 tc = GNUNET_SCHEDULER_get_task_context ();
1115 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT))
1116 {
1117 LOG (GNUNET_ERROR_TYPE_DEBUG,
1118 "Receive from `%s' encounters error: timeout (%s, %p)\n",
1119 GNUNET_a2s (connection->addr, connection->addrlen),
1120 GNUNET_STRINGS_relative_time_to_string (
1121 GNUNET_TIME_absolute_get_duration (
1122 connection->receive_timeout),
1123 GNUNET_YES),
1124 connection);
1125 signal_receive_timeout (connection);
1126 return;
1127 }
1128 if (NULL == connection->sock)
1129 {
1130 /* connect failed for good */
1131 signal_receive_error (connection, ECONNREFUSED);
1132 return;
1133 }
1134 GNUNET_assert (GNUNET_NETWORK_fdset_isset (tc->read_ready, connection->sock));
1135RETRY:
1136 ret = GNUNET_NETWORK_socket_recv (connection->sock, buffer, connection->max);
1137 if (-1 == ret)
1138 {
1139 if (EINTR == errno)
1140 goto RETRY;
1141 signal_receive_error (connection, errno);
1142 return;
1143 }
1144 LOG (GNUNET_ERROR_TYPE_DEBUG,
1145 "receive_ready read %lu/%lu bytes from `%s' (%p)!\n",
1146 (unsigned long) ret,
1147 (unsigned long) connection->max,
1148 GNUNET_a2s (connection->addr, connection->addrlen),
1149 connection);
1150 GNUNET_assert (NULL != (receiver = connection->receiver));
1151 connection->receiver = NULL;
1152 receiver (connection->receiver_cls,
1153 buffer,
1154 ret,
1155 connection->addr,
1156 connection->addrlen,
1157 0);
1158}
1159
1160
1161/**
1162 * Receive data from the given connection. Note that this function
1163 * will call @a receiver asynchronously using the scheduler. It will
1164 * "immediately" return. Note that there MUST only be one active
1165 * receive call per connection at any given point in time (so do not
1166 * call receive again until the receiver callback has been invoked).
1167 *
1168 * @param connection connection handle
1169 * @param max maximum number of bytes to read
1170 * @param timeout maximum amount of time to wait
1171 * @param receiver function to call with received data
1172 * @param receiver_cls closure for @a receiver
1173 * @return #GNUNET_SYSERR if @a connection died (receiver was
1174 * called with error)
1175 */
1176int
1177GNUNET_CONNECTION_receive (struct GNUNET_CONNECTION_Handle *connection,
1178 size_t max,
1179 struct GNUNET_TIME_Relative timeout,
1180 GNUNET_CONNECTION_Receiver receiver,
1181 void *receiver_cls)
1182{
1183 GNUNET_assert ((NULL == connection->read_task) &&
1184 (NULL == connection->receiver));
1185 GNUNET_assert (NULL != receiver);
1186 connection->receiver = receiver;
1187 connection->receiver_cls = receiver_cls;
1188 connection->receive_timeout = GNUNET_TIME_relative_to_absolute (timeout);
1189 connection->max = max;
1190 if (NULL != connection->sock)
1191 {
1192 connection->read_task =
1193 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_absolute_get_remaining (
1194 connection->receive_timeout),
1195 connection->sock,
1196 &receive_ready,
1197 connection);
1198 return GNUNET_OK;
1199 }
1200 if ((NULL == connection->dns_active) && (NULL == connection->ap_head) &&
1201 (NULL == connection->proxy_handshake))
1202 {
1203 connection->receiver = NULL;
1204 receiver (receiver_cls, NULL, 0, NULL, 0, ETIMEDOUT);
1205 return GNUNET_SYSERR;
1206 }
1207 return GNUNET_OK;
1208}
1209
1210
1211/**
1212 * Cancel receive job on the given connection. Note that the
1213 * receiver callback must not have been called yet in order
1214 * for the cancellation to be valid.
1215 *
1216 * @param connection connection handle
1217 * @return closure of the original receiver callback closure
1218 */
1219void *
1220GNUNET_CONNECTION_receive_cancel (struct GNUNET_CONNECTION_Handle *connection)
1221{
1222 if (NULL != connection->read_task)
1223 {
1224 GNUNET_assert (connection ==
1225 GNUNET_SCHEDULER_cancel (connection->read_task));
1226 connection->read_task = NULL;
1227 }
1228 connection->receiver = NULL;
1229 return connection->receiver_cls;
1230}
1231
1232
1233/**
1234 * Try to call the transmit notify method (check if we do
1235 * have enough space available first)!
1236 *
1237 * @param connection connection for which we should do this processing
1238 * @return #GNUNET_YES if we were able to call notify
1239 */
1240static int
1241process_notify (struct GNUNET_CONNECTION_Handle *connection)
1242{
1243 size_t used;
1244 size_t avail;
1245 size_t size;
1246 GNUNET_CONNECTION_TransmitReadyNotify notify;
1247
1248 LOG (GNUNET_ERROR_TYPE_DEBUG, "process_notify is running\n");
1249 GNUNET_assert (NULL == connection->write_task);
1250 if (NULL == (notify = connection->nth.notify_ready))
1251 {
1252 LOG (GNUNET_ERROR_TYPE_DEBUG, "No one to notify\n");
1253 return GNUNET_NO;
1254 }
1255 used = connection->write_buffer_off - connection->write_buffer_pos;
1256 avail = connection->write_buffer_size - used;
1257 size = connection->nth.notify_size;
1258 if (size > avail)
1259 {
1260 LOG (GNUNET_ERROR_TYPE_DEBUG, "Not enough buffer\n");
1261 return GNUNET_NO;
1262 }
1263 connection->nth.notify_ready = NULL;
1264 if (connection->write_buffer_size - connection->write_buffer_off < size)
1265 {
1266 /* need to compact */
1267 memmove (connection->write_buffer,
1268 &connection->write_buffer[connection->write_buffer_pos],
1269 used);
1270 connection->write_buffer_off -= connection->write_buffer_pos;
1271 connection->write_buffer_pos = 0;
1272 }
1273 avail = connection->write_buffer_size - connection->write_buffer_off;
1274 GNUNET_assert (avail >= size);
1275 size = notify (connection->nth.notify_ready_cls,
1276 avail,
1277 &connection->write_buffer[connection->write_buffer_off]);
1278 GNUNET_assert (size <= avail);
1279 if (0 != size)
1280 connection->write_buffer_off += size;
1281 return GNUNET_YES;
1282}
1283
1284
1285/**
1286 * Task invoked by the scheduler when a call to transmit
1287 * is timing out (we never got enough buffer space to call
1288 * the callback function before the specified timeout
1289 * expired).
1290 *
1291 * This task notifies the client about the timeout.
1292 *
1293 * @param cls the `struct GNUNET_CONNECTION_Handle`
1294 */
1295static void
1296transmit_timeout (void *cls)
1297{
1298 struct GNUNET_CONNECTION_Handle *connection = cls;
1299 GNUNET_CONNECTION_TransmitReadyNotify notify;
1300
1301 connection->nth.timeout_task = NULL;
1302 LOG (GNUNET_ERROR_TYPE_DEBUG,
1303 "Transmit to `%s:%u/%s' fails, time out reached (%p).\n",
1304 connection->hostname,
1305 connection->port,
1306 GNUNET_a2s (connection->addr, connection->addrlen),
1307 connection);
1308 notify = connection->nth.notify_ready;
1309 GNUNET_assert (NULL != notify);
1310 connection->nth.notify_ready = NULL;
1311 notify (connection->nth.notify_ready_cls, 0, NULL);
1312}
1313
1314
1315/**
1316 * Task invoked by the scheduler when we failed to connect
1317 * at the time of being asked to transmit.
1318 *
1319 * This task notifies the client about the error.
1320 *
1321 * @param cls the `struct GNUNET_CONNECTION_Handle`
1322 */
1323static void
1324connect_error (void *cls)
1325{
1326 struct GNUNET_CONNECTION_Handle *connection = cls;
1327 GNUNET_CONNECTION_TransmitReadyNotify notify;
1328
1329 LOG (GNUNET_ERROR_TYPE_DEBUG,
1330 "Transmission request of size %lu fails (%s/%u), connection failed (%p).\n",
1331 (unsigned long) connection->nth.notify_size,
1332 connection->hostname,
1333 connection->port,
1334 connection);
1335 connection->write_task = NULL;
1336 notify = connection->nth.notify_ready;
1337 connection->nth.notify_ready = NULL;
1338 notify (connection->nth.notify_ready_cls, 0, NULL);
1339}
1340
1341
1342/**
1343 * We are ready to transmit (or got a timeout).
1344 *
1345 * @param cls our connection handle
1346 */
1347static void
1348transmit_ready (void *cls)
1349{
1350 struct GNUNET_CONNECTION_Handle *connection = cls;
1351 GNUNET_CONNECTION_TransmitReadyNotify notify;
1352 const struct GNUNET_SCHEDULER_TaskContext *tc;
1353 ssize_t ret;
1354 size_t have;
1355
1356 LOG (GNUNET_ERROR_TYPE_DEBUG, "transmit_ready running (%p).\n", connection);
1357 GNUNET_assert (NULL != connection->write_task);
1358 connection->write_task = NULL;
1359 GNUNET_assert (NULL == connection->nth.timeout_task);
1360 tc = GNUNET_SCHEDULER_get_task_context ();
1361 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT))
1362 {
1363 LOG (GNUNET_ERROR_TYPE_DEBUG,
1364 "Transmit to `%s' fails, time out reached (%p).\n",
1365 GNUNET_a2s (connection->addr, connection->addrlen),
1366 connection);
1367 notify = connection->nth.notify_ready;
1368 GNUNET_assert (NULL != notify);
1369 connection->nth.notify_ready = NULL;
1370 notify (connection->nth.notify_ready_cls, 0, NULL);
1371 return;
1372 }
1373 GNUNET_assert (NULL != connection->sock);
1374 if (NULL == tc->write_ready)
1375 {
1376 /* special circumstances (in particular, PREREQ_DONE after
1377 * connect): not yet ready to write, but no "fatal" error either.
1378 * Hence retry. */
1379 goto SCHEDULE_WRITE;
1380 }
1381 if (! GNUNET_NETWORK_fdset_isset (tc->write_ready, connection->sock))
1382 {
1383 GNUNET_assert (NULL == connection->write_task);
1384 /* special circumstances (in particular, shutdown): not yet ready
1385 * to write, but no "fatal" error either. Hence retry. */
1386 goto SCHEDULE_WRITE;
1387 }
1388 GNUNET_assert (connection->write_buffer_off >= connection->write_buffer_pos);
1389 if ((NULL != connection->nth.notify_ready) &&
1390 (connection->write_buffer_size < connection->nth.notify_size))
1391 {
1392 connection->write_buffer =
1393 GNUNET_realloc (connection->write_buffer, connection->nth.notify_size);
1394 connection->write_buffer_size = connection->nth.notify_size;
1395 }
1396 process_notify (connection);
1397 have = connection->write_buffer_off - connection->write_buffer_pos;
1398 if (0 == have)
1399 {
1400 /* no data ready for writing, terminate write loop */
1401 return;
1402 }
1403 GNUNET_assert (have <= connection->write_buffer_size);
1404 GNUNET_assert (have + connection->write_buffer_pos <=
1405 connection->write_buffer_size);
1406 GNUNET_assert (connection->write_buffer_pos <= connection->write_buffer_size);
1407RETRY:
1408 ret =
1409 GNUNET_NETWORK_socket_send (connection->sock,
1410 &connection
1411 ->write_buffer[connection->write_buffer_pos],
1412 have);
1413 if (-1 == ret)
1414 {
1415 if (EINTR == errno)
1416 goto RETRY;
1417 if (NULL != connection->write_task)
1418 {
1419 GNUNET_SCHEDULER_cancel (connection->write_task);
1420 connection->write_task = NULL;
1421 }
1422 signal_transmit_error (connection, errno);
1423 return;
1424 }
1425 LOG (GNUNET_ERROR_TYPE_DEBUG,
1426 "Connection transmitted %lu/%lu bytes to `%s' (%p)\n",
1427 (unsigned long) ret,
1428 (unsigned long) have,
1429 GNUNET_a2s (connection->addr, connection->addrlen),
1430 connection);
1431 connection->write_buffer_pos += ret;
1432 if (connection->write_buffer_pos == connection->write_buffer_off)
1433 {
1434 /* transmitted all pending data */
1435 connection->write_buffer_pos = 0;
1436 connection->write_buffer_off = 0;
1437 }
1438 if ((0 == connection->write_buffer_off) &&
1439 (NULL == connection->nth.notify_ready))
1440 return; /* all data sent! */
1441 /* not done writing, schedule more */
1442SCHEDULE_WRITE:
1443 LOG (GNUNET_ERROR_TYPE_DEBUG,
1444 "Re-scheduling transmit_ready (more to do) (%p).\n",
1445 connection);
1446 have = connection->write_buffer_off - connection->write_buffer_pos;
1447 GNUNET_assert ((NULL != connection->nth.notify_ready) || (have > 0));
1448 if (NULL == connection->write_task)
1449 connection->write_task =
1450 GNUNET_SCHEDULER_add_write_net ((connection->nth.notify_ready == NULL)
1451 ? GNUNET_TIME_UNIT_FOREVER_REL
1452 : GNUNET_TIME_absolute_get_remaining (
1453 connection->nth.transmit_timeout),
1454 connection->sock,
1455 &transmit_ready,
1456 connection);
1457}
1458
1459
1460/**
1461 * Ask the connection to call us once the specified number of bytes
1462 * are free in the transmission buffer. Will never call the @a notify
1463 * callback in this task, but always first go into the scheduler.
1464 *
1465 * @param connection connection
1466 * @param size number of bytes to send
1467 * @param timeout after how long should we give up (and call
1468 * @a notify with buf NULL and size 0)?
1469 * @param notify function to call
1470 * @param notify_cls closure for @a notify
1471 * @return non-NULL if the notify callback was queued,
1472 * NULL if we are already going to notify someone else (busy)
1473 */
1474struct GNUNET_CONNECTION_TransmitHandle *
1475GNUNET_CONNECTION_notify_transmit_ready (
1476 struct GNUNET_CONNECTION_Handle *connection,
1477 size_t size,
1478 struct GNUNET_TIME_Relative timeout,
1479 GNUNET_CONNECTION_TransmitReadyNotify notify,
1480 void *notify_cls)
1481{
1482 if (NULL != connection->nth.notify_ready)
1483 {
1484 GNUNET_assert (0);
1485 return NULL;
1486 }
1487 GNUNET_assert (NULL != notify);
1488 GNUNET_assert (size < GNUNET_MAX_MESSAGE_SIZE);
1489 GNUNET_assert (connection->write_buffer_off <= connection->write_buffer_size);
1490 GNUNET_assert (connection->write_buffer_pos <= connection->write_buffer_size);
1491 GNUNET_assert (connection->write_buffer_pos <= connection->write_buffer_off);
1492 connection->nth.notify_ready = notify;
1493 connection->nth.notify_ready_cls = notify_cls;
1494 connection->nth.connection = connection;
1495 connection->nth.notify_size = size;
1496 connection->nth.transmit_timeout = GNUNET_TIME_relative_to_absolute (timeout);
1497 GNUNET_assert (NULL == connection->nth.timeout_task);
1498 if ((NULL == connection->sock) && (NULL == connection->ap_head) &&
1499 (NULL == connection->dns_active) && (NULL == connection->proxy_handshake))
1500 {
1501 if (NULL != connection->write_task)
1502 GNUNET_SCHEDULER_cancel (connection->write_task);
1503 connection->write_task =
1504 GNUNET_SCHEDULER_add_now (&connect_error, connection);
1505 return &connection->nth;
1506 }
1507 if (NULL != connection->write_task)
1508 return &connection->nth; /* previous transmission still in progress */
1509 if (NULL != connection->sock)
1510 {
1511 /* connected, try to transmit now */
1512 LOG (GNUNET_ERROR_TYPE_DEBUG,
1513 "Scheduling transmission (%p).\n",
1514 connection);
1515 connection->write_task =
1516 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_absolute_get_remaining (
1517 connection->nth.transmit_timeout),
1518 connection->sock,
1519 &transmit_ready,
1520 connection);
1521 return &connection->nth;
1522 }
1523 /* not yet connected, wait for connection */
1524 LOG (GNUNET_ERROR_TYPE_DEBUG,
1525 "Need to wait to schedule transmission for connection, adding timeout task (%p).\n",
1526 connection);
1527 connection->nth.timeout_task =
1528 GNUNET_SCHEDULER_add_delayed (timeout, &transmit_timeout, connection);
1529 return &connection->nth;
1530}
1531
1532
1533/**
1534 * Cancel the specified transmission-ready notification.
1535 *
1536 * @param th notification to cancel
1537 */
1538void
1539GNUNET_CONNECTION_notify_transmit_ready_cancel (
1540 struct GNUNET_CONNECTION_TransmitHandle *th)
1541{
1542 GNUNET_assert (NULL != th->notify_ready);
1543 th->notify_ready = NULL;
1544 if (NULL != th->timeout_task)
1545 {
1546 GNUNET_SCHEDULER_cancel (th->timeout_task);
1547 th->timeout_task = NULL;
1548 }
1549 if (NULL != th->connection->write_task)
1550 {
1551 GNUNET_SCHEDULER_cancel (th->connection->write_task);
1552 th->connection->write_task = NULL;
1553 }
1554}
1555
1556
1557/**
1558 * Create a connection to be proxied using a given connection.
1559 *
1560 * @param cph connection to proxy server
1561 * @return connection to be proxied
1562 */
1563struct GNUNET_CONNECTION_Handle *
1564GNUNET_CONNECTION_create_proxied_from_handshake (
1565 struct GNUNET_CONNECTION_Handle *cph)
1566{
1567 struct GNUNET_CONNECTION_Handle *proxied =
1568 GNUNET_CONNECTION_create_from_existing (NULL);
1569
1570 proxied->proxy_handshake = cph;
1571 return proxied;
1572}
1573
1574
1575/**
1576 * Activate proxied connection and destroy initial proxy handshake connection.
1577 * There must not be any pending requests for reading or writing to the
1578 * proxy hadshake connection at this time.
1579 *
1580 * @param proxied connection connection to proxy server
1581 */
1582void
1583GNUNET_CONNECTION_acivate_proxied (struct GNUNET_CONNECTION_Handle *proxied)
1584{
1585 struct GNUNET_CONNECTION_Handle *cph = proxied->proxy_handshake;
1586
1587 GNUNET_assert (NULL != cph);
1588 GNUNET_assert (NULL == proxied->sock);
1589 GNUNET_assert (NULL != cph->sock);
1590 proxied->sock = cph->sock;
1591 cph->sock = NULL;
1592 GNUNET_CONNECTION_destroy (cph);
1593 connect_success_continuation (proxied);
1594}
1595
1596
1597/* end of connection.c */
diff --git a/src/transport/tcp_server_legacy.c b/src/transport/tcp_server_legacy.c
deleted file mode 100644
index bb572c843..000000000
--- a/src/transport/tcp_server_legacy.c
+++ /dev/null
@@ -1,1728 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file util/server.c
23 * @brief library for building GNUnet network servers
24 * @author Christian Grothoff
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_protocols.h"
30
31#define LOG_STRERROR_FILE(kind, syscall, \
32 filename) GNUNET_log_from_strerror_file (kind, \
33 "util-server", \
34 syscall, \
35 filename)
36
37
38/**
39 * List of arrays of message handlers.
40 */
41struct HandlerList
42{
43 /**
44 * This is a linked list.
45 */
46 struct HandlerList *next;
47
48 /**
49 * NULL-terminated array of handlers.
50 */
51 const struct GNUNET_SERVER_MessageHandler *handlers;
52};
53
54
55/**
56 * List of arrays of message handlers.
57 */
58struct NotifyList
59{
60 /**
61 * This is a doubly linked list.
62 */
63 struct NotifyList *next;
64
65 /**
66 * This is a doubly linked list.
67 */
68 struct NotifyList *prev;
69
70 /**
71 * Function to call.
72 */
73 GNUNET_SERVER_DisconnectCallback callback;
74
75 /**
76 * Closure for callback.
77 */
78 void *callback_cls;
79};
80
81
82/**
83 * @brief handle for a server
84 */
85struct GNUNET_SERVER_Handle
86{
87 /**
88 * List of handlers for incoming messages.
89 */
90 struct HandlerList *handlers;
91
92 /**
93 * Head of list of our current clients.
94 */
95 struct GNUNET_SERVER_Client *clients_head;
96
97 /**
98 * Head of list of our current clients.
99 */
100 struct GNUNET_SERVER_Client *clients_tail;
101
102 /**
103 * Head of linked list of functions to call on disconnects by clients.
104 */
105 struct NotifyList *disconnect_notify_list_head;
106
107 /**
108 * Tail of linked list of functions to call on disconnects by clients.
109 */
110 struct NotifyList *disconnect_notify_list_tail;
111
112 /**
113 * Head of linked list of functions to call on connects by clients.
114 */
115 struct NotifyList *connect_notify_list_head;
116
117 /**
118 * Tail of linked list of functions to call on connects by clients.
119 */
120 struct NotifyList *connect_notify_list_tail;
121
122 /**
123 * Function to call for access control.
124 */
125 GNUNET_CONNECTION_AccessCheck access_cb;
126
127 /**
128 * Closure for @e access_cb.
129 */
130 void *access_cb_cls;
131
132 /**
133 * NULL-terminated array of sockets used to listen for new
134 * connections.
135 */
136 struct GNUNET_NETWORK_Handle **listen_sockets;
137
138 /**
139 * After how long should an idle connection time
140 * out (on write).
141 */
142 struct GNUNET_TIME_Relative idle_timeout;
143
144 /**
145 * Task scheduled to do the listening.
146 */
147 struct GNUNET_SCHEDULER_Task *listen_task;
148
149 /**
150 * Alternative function to create a MST instance.
151 */
152 GNUNET_SERVER_MstCreateCallback mst_create;
153
154 /**
155 * Alternative function to destroy a MST instance.
156 */
157 GNUNET_SERVER_MstDestroyCallback mst_destroy;
158
159 /**
160 * Alternative function to give data to a MST instance.
161 */
162 GNUNET_SERVER_MstReceiveCallback mst_receive;
163
164 /**
165 * Closure for 'mst_'-callbacks.
166 */
167 void *mst_cls;
168
169 /**
170 * Do we ignore messages of types that we do not understand or do we
171 * require that a handler is found (and if not kill the connection)?
172 */
173 int require_found;
174
175 /**
176 * Set to #GNUNET_YES once we are in 'soft' shutdown where we wait for
177 * all non-monitor clients to disconnect before we call
178 * #GNUNET_SERVER_destroy. See test_monitor_clients(). Set to
179 * #GNUNET_SYSERR once the final destroy task has been scheduled
180 * (we cannot run it in the same task).
181 */
182 int in_soft_shutdown;
183};
184
185
186/**
187 * Handle server returns for aborting transmission to a client.
188 */
189struct GNUNET_SERVER_TransmitHandle
190{
191 /**
192 * Function to call to get the message.
193 */
194 GNUNET_CONNECTION_TransmitReadyNotify callback;
195
196 /**
197 * Closure for @e callback
198 */
199 void *callback_cls;
200
201 /**
202 * Active connection transmission handle.
203 */
204 struct GNUNET_CONNECTION_TransmitHandle *cth;
205};
206
207
208/**
209 * @brief handle for a client of the server
210 */
211struct GNUNET_SERVER_Client
212{
213 /**
214 * This is a doubly linked list.
215 */
216 struct GNUNET_SERVER_Client *next;
217
218 /**
219 * This is a doubly linked list.
220 */
221 struct GNUNET_SERVER_Client *prev;
222
223 /**
224 * Processing of incoming data.
225 */
226 void *mst;
227
228 /**
229 * Server that this client belongs to.
230 */
231 struct GNUNET_SERVER_Handle *server;
232
233 /**
234 * Client closure for callbacks.
235 */
236 struct GNUNET_CONNECTION_Handle *connection;
237
238 /**
239 * User context value, manipulated using
240 * 'GNUNET_SERVER_client_{get/set}_user_context' functions.
241 */
242 void *user_context;
243
244 /**
245 * ID of task used to restart processing.
246 */
247 struct GNUNET_SCHEDULER_Task *restart_task;
248
249 /**
250 * Task that warns about missing calls to #GNUNET_SERVER_receive_done.
251 */
252 struct GNUNET_SCHEDULER_Task *warn_task;
253
254 /**
255 * Time when the warn task was started.
256 */
257 struct GNUNET_TIME_Absolute warn_start;
258
259 /**
260 * Last activity on this socket (used to time it out
261 * if reference_count == 0).
262 */
263 struct GNUNET_TIME_Absolute last_activity;
264
265 /**
266 * Transmission handle we return for this client from
267 * #GNUNET_SERVER_notify_transmit_ready.
268 */
269 struct GNUNET_SERVER_TransmitHandle th;
270
271 /**
272 * After how long should an idle connection time
273 * out (on write).
274 */
275 struct GNUNET_TIME_Relative idle_timeout;
276
277 /**
278 * Number of external entities with a reference to
279 * this client object.
280 */
281 unsigned int reference_count;
282
283 /**
284 * Was processing if incoming messages suspended while
285 * we were still processing data already received?
286 * This is a counter saying how often processing was
287 * suspended (once per handler invoked).
288 */
289 unsigned int suspended;
290
291 /**
292 * Last size given when user context was initialized; used for
293 * sanity check.
294 */
295 size_t user_context_size;
296
297 /**
298 * Are we currently in the "process_client_buffer" function (and
299 * will hence restart the receive job on exit if suspended == 0 once
300 * we are done?). If this is set, then "receive_done" will
301 * essentially only decrement suspended; if this is not set, then
302 * "receive_done" may need to restart the receive process (either
303 * from the side-buffer or via select/recv).
304 */
305 int in_process_client_buffer;
306
307 /**
308 * We're about to close down this client.
309 */
310 int shutdown_now;
311
312 /**
313 * Are we currently trying to receive? (#GNUNET_YES if we are,
314 * #GNUNET_NO if we are not, #GNUNET_SYSERR if data is already
315 * available in MST).
316 */
317 int receive_pending;
318
319 /**
320 * Persist the file handle for this client no matter what happens,
321 * force the OS to close once the process actually dies. Should only
322 * be used in special cases!
323 */
324 int persist;
325
326 /**
327 * Is this client a 'monitor' client that should not be counted
328 * when deciding on destroying the server during soft shutdown?
329 * (see also #GNUNET_SERVICE_start)
330 */
331 int is_monitor;
332
333 /**
334 * Type of last message processed (for warn_no_receive_done).
335 */
336 uint16_t warn_type;
337};
338
339
340/**
341 * Return user context associated with the given client.
342 * Note: you should probably use the macro (call without the underscore).
343 *
344 * @param client client to query
345 * @param size number of bytes in user context struct (for verification only)
346 * @return pointer to user context
347 */
348void *
349GNUNET_SERVER_client_get_user_context_ (struct GNUNET_SERVER_Client *client,
350 size_t size)
351{
352 if ((0 == client->user_context_size) &&
353 (NULL == client->user_context))
354 return NULL; /* never set */
355 GNUNET_assert (size == client->user_context_size);
356 return client->user_context;
357}
358
359
360/**
361 * Set user context to be associated with the given client.
362 * Note: you should probably use the macro (call without the underscore).
363 *
364 * @param client client to query
365 * @param ptr pointer to user context
366 * @param size number of bytes in user context struct (for verification only)
367 */
368void
369GNUNET_SERVER_client_set_user_context_ (struct GNUNET_SERVER_Client *client,
370 void *ptr,
371 size_t size)
372{
373 if (NULL == ptr)
374 {
375 client->user_context_size = 0;
376 client->user_context = ptr;
377 return;
378 }
379 client->user_context_size = size;
380 client->user_context = ptr;
381}
382
383
384/**
385 * Scheduler says our listen socket is ready. Process it!
386 *
387 * @param cls handle to our server for which we are processing the listen
388 * socket
389 */
390static void
391process_listen_socket (void *cls)
392{
393 struct GNUNET_SERVER_Handle *server = cls;
394 const struct GNUNET_SCHEDULER_TaskContext *tc;
395 struct GNUNET_CONNECTION_Handle *sock;
396 unsigned int i;
397
398 server->listen_task = NULL;
399 tc = GNUNET_SCHEDULER_get_task_context ();
400 for (i = 0; NULL != server->listen_sockets[i]; i++)
401 {
402 if (GNUNET_NETWORK_fdset_isset (tc->read_ready,
403 server->listen_sockets[i]))
404 {
405 sock =
406 GNUNET_CONNECTION_create_from_accept (server->access_cb,
407 server->access_cb_cls,
408 server->listen_sockets[i]);
409 if (NULL != sock)
410 {
411 LOG (GNUNET_ERROR_TYPE_DEBUG,
412 "Server accepted incoming connection.\n");
413 (void) GNUNET_SERVER_connect_socket (server,
414 sock);
415 }
416 }
417 }
418 /* listen for more! */
419 GNUNET_SERVER_resume (server);
420}
421
422
423/**
424 * Create and initialize a listen socket for the server.
425 *
426 * @param server_addr address to listen on
427 * @param socklen length of @a server_addr
428 * @return NULL on error, otherwise the listen socket
429 */
430static struct GNUNET_NETWORK_Handle *
431open_listen_socket (const struct sockaddr *server_addr,
432 socklen_t socklen)
433{
434 struct GNUNET_NETWORK_Handle *sock;
435 uint16_t port;
436 int eno;
437
438 switch (server_addr->sa_family)
439 {
440 case AF_INET:
441 port = ntohs (((const struct sockaddr_in *) server_addr)->sin_port);
442 break;
443
444 case AF_INET6:
445 port = ntohs (((const struct sockaddr_in6 *) server_addr)->sin6_port);
446 break;
447
448 case AF_UNIX:
449 port = 0;
450 break;
451
452 default:
453 GNUNET_break (0);
454 port = 0;
455 break;
456 }
457 sock = GNUNET_NETWORK_socket_create (server_addr->sa_family, SOCK_STREAM, 0);
458 if (NULL == sock)
459 {
460 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
461 errno = 0;
462 return NULL;
463 }
464 /* bind the socket */
465 if (GNUNET_OK != GNUNET_NETWORK_socket_bind (sock, server_addr, socklen))
466 {
467 eno = errno;
468 if (EADDRINUSE != errno)
469 {
470 /* we don't log 'EADDRINUSE' here since an IPv4 bind may
471 * fail if we already took the port on IPv6; if both IPv4 and
472 * IPv6 binds fail, then our caller will log using the
473 * errno preserved in 'eno' */
474 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
475 "bind");
476 if (0 != port)
477 LOG (GNUNET_ERROR_TYPE_ERROR,
478 _ ("`%s' failed for port %d (%s).\n"),
479 "bind",
480 port,
481 (AF_INET == server_addr->sa_family) ? "IPv4" : "IPv6");
482 eno = 0;
483 }
484 else
485 {
486 if (0 != port)
487 LOG (GNUNET_ERROR_TYPE_WARNING,
488 _ ("`%s' failed for port %d (%s): address already in use\n"),
489 "bind", port,
490 (AF_INET == server_addr->sa_family) ? "IPv4" : "IPv6");
491 else if (AF_UNIX == server_addr->sa_family)
492 {
493 LOG (GNUNET_ERROR_TYPE_WARNING,
494 _ ("`%s' failed for `%s': address already in use\n"),
495 "bind",
496 GNUNET_a2s (server_addr, socklen));
497 }
498 }
499 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
500 errno = eno;
501 return NULL;
502 }
503 if (GNUNET_OK != GNUNET_NETWORK_socket_listen (sock, 5))
504 {
505 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
506 "listen");
507 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
508 errno = 0;
509 return NULL;
510 }
511 if (0 != port)
512 LOG (GNUNET_ERROR_TYPE_DEBUG,
513 "Server starts to listen on port %u.\n",
514 port);
515 return sock;
516}
517
518
519/**
520 * Create a new server.
521 *
522 * @param access_cb function for access control
523 * @param access_cb_cls closure for @a access_cb
524 * @param lsocks NULL-terminated array of listen sockets
525 * @param idle_timeout after how long should we timeout idle connections?
526 * @param require_found if #GNUNET_YES, connections sending messages of unknown type
527 * will be closed
528 * @return handle for the new server, NULL on error
529 * (typically, "port" already in use)
530 */
531struct GNUNET_SERVER_Handle *
532GNUNET_SERVER_create_with_sockets (GNUNET_CONNECTION_AccessCheck access_cb,
533 void *access_cb_cls,
534 struct GNUNET_NETWORK_Handle **lsocks,
535 struct GNUNET_TIME_Relative idle_timeout,
536 int require_found)
537{
538 struct GNUNET_SERVER_Handle *server;
539
540 server = GNUNET_new (struct GNUNET_SERVER_Handle);
541 server->idle_timeout = idle_timeout;
542 server->listen_sockets = lsocks;
543 server->access_cb = access_cb;
544 server->access_cb_cls = access_cb_cls;
545 server->require_found = require_found;
546 if (NULL != lsocks)
547 GNUNET_SERVER_resume (server);
548 return server;
549}
550
551
552/**
553 * Create a new server.
554 *
555 * @param access_cb function for access control
556 * @param access_cb_cls closure for @a access_cb
557 * @param server_addr address to listen on (including port), NULL terminated array
558 * @param socklen length of server_addr
559 * @param idle_timeout after how long should we timeout idle connections?
560 * @param require_found if YES, connections sending messages of unknown type
561 * will be closed
562 * @return handle for the new server, NULL on error
563 * (typically, "port" already in use)
564 */
565struct GNUNET_SERVER_Handle *
566GNUNET_SERVER_create (GNUNET_CONNECTION_AccessCheck access_cb,
567 void *access_cb_cls,
568 struct sockaddr *const *server_addr,
569 const socklen_t *socklen,
570 struct GNUNET_TIME_Relative idle_timeout,
571 int require_found)
572{
573 struct GNUNET_NETWORK_Handle **lsocks;
574 unsigned int i;
575 unsigned int j;
576 unsigned int k;
577 int seen;
578
579 i = 0;
580 while (NULL != server_addr[i])
581 i++;
582 if (i > 0)
583 {
584 lsocks = GNUNET_malloc (sizeof(struct GNUNET_NETWORK_Handle *) * (i + 1));
585 i = 0;
586 j = 0;
587 while (NULL != server_addr[i])
588 {
589 seen = 0;
590 for (k = 0; k < i; k++)
591 if ((socklen[k] == socklen[i]) &&
592 (0 == memcmp (server_addr[k], server_addr[i], socklen[i])))
593 {
594 seen = 1;
595 break;
596 }
597 if (0 != seen)
598 {
599 /* duplicate address, skip */
600 i++;
601 continue;
602 }
603 lsocks[j] = open_listen_socket (server_addr[i], socklen[i]);
604 if (NULL != lsocks[j])
605 j++;
606 i++;
607 }
608 if (0 == j)
609 {
610 if (0 != errno)
611 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "bind");
612 GNUNET_free (lsocks);
613 lsocks = NULL;
614 }
615 }
616 else
617 {
618 lsocks = NULL;
619 }
620 return GNUNET_SERVER_create_with_sockets (access_cb,
621 access_cb_cls,
622 lsocks,
623 idle_timeout,
624 require_found);
625}
626
627
628/**
629 * Set the 'monitor' flag on this client. Clients which have been
630 * marked as 'monitors' won't prevent the server from shutting down
631 * once '#GNUNET_SERVER_stop_listening()' has been invoked. The idea is
632 * that for "normal" clients we likely want to allow them to process
633 * their requests; however, monitor-clients are likely to 'never'
634 * disconnect during shutdown and thus will not be considered when
635 * determining if the server should continue to exist after
636 * #GNUNET_SERVER_destroy() has been called.
637 *
638 * @param client the client to set the 'monitor' flag on
639 */
640void
641GNUNET_SERVER_client_mark_monitor (struct GNUNET_SERVER_Client *client)
642{
643 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
644 "Marking client as monitor!\n");
645 client->is_monitor = GNUNET_YES;
646}
647
648
649/**
650 * Helper function for #test_monitor_clients() to trigger
651 * #GNUNET_SERVER_destroy() after the stack has unwound.
652 *
653 * @param cls the `struct GNUNET_SERVER_Handle *` to destroy
654 */
655static void
656do_destroy (void *cls)
657{
658 struct GNUNET_SERVER_Handle *server = cls;
659
660 GNUNET_SERVER_destroy (server);
661}
662
663
664/**
665 * Check if only 'monitor' clients are left. If so, destroy the
666 * server completely.
667 *
668 * @param server server to test for full shutdown
669 */
670static void
671test_monitor_clients (struct GNUNET_SERVER_Handle *server)
672{
673 struct GNUNET_SERVER_Client *client;
674
675 if (GNUNET_YES != server->in_soft_shutdown)
676 return;
677 for (client = server->clients_head; NULL != client; client = client->next)
678 if (GNUNET_NO == client->is_monitor)
679 return;
680 /* not done yet */
681 server->in_soft_shutdown = GNUNET_SYSERR;
682 (void) GNUNET_SCHEDULER_add_now (&do_destroy, server);
683}
684
685
686/**
687 * Suspend accepting connections from the listen socket temporarily.
688 *
689 * @param server server to stop accepting connections.
690 */
691void
692GNUNET_SERVER_suspend (struct GNUNET_SERVER_Handle *server)
693{
694 if (NULL != server->listen_task)
695 {
696 GNUNET_SCHEDULER_cancel (server->listen_task);
697 server->listen_task = NULL;
698 }
699}
700
701
702void
703GNUNET_SERVER_resume (struct GNUNET_SERVER_Handle *server)
704{
705 struct GNUNET_NETWORK_FDSet *r;
706 unsigned int i;
707
708 if (NULL == server->listen_sockets)
709 return;
710 if (NULL == server->listen_sockets[0])
711 return; /* nothing to do, no listen sockets! */
712 if (NULL == server->listen_sockets[1])
713 {
714 /* simplified method: no fd set needed; this is then much simpler
715 and much more efficient */
716 server->listen_task =
717 GNUNET_SCHEDULER_add_read_net_with_priority (GNUNET_TIME_UNIT_FOREVER_REL,
718 GNUNET_SCHEDULER_PRIORITY_HIGH,
719 server->listen_sockets[0],
720 &process_listen_socket,
721 server);
722 return;
723 }
724 r = GNUNET_NETWORK_fdset_create ();
725 i = 0;
726 while (NULL != server->listen_sockets[i])
727 GNUNET_NETWORK_fdset_set (r, server->listen_sockets[i++]);
728 server->listen_task =
729 GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH,
730 GNUNET_TIME_UNIT_FOREVER_REL, r, NULL,
731 &process_listen_socket, server);
732 GNUNET_NETWORK_fdset_destroy (r);
733}
734
735
736/**
737 * Stop the listen socket and get ready to shutdown the server
738 * once only 'monitor' clients are left.
739 *
740 * @param server server to stop listening on
741 */
742void
743GNUNET_SERVER_stop_listening (struct GNUNET_SERVER_Handle *server)
744{
745 unsigned int i;
746
747 LOG (GNUNET_ERROR_TYPE_DEBUG,
748 "Server in soft shutdown\n");
749 if (NULL != server->listen_task)
750 {
751 GNUNET_SCHEDULER_cancel (server->listen_task);
752 server->listen_task = NULL;
753 }
754 if (NULL != server->listen_sockets)
755 {
756 i = 0;
757 while (NULL != server->listen_sockets[i])
758 GNUNET_break (GNUNET_OK ==
759 GNUNET_NETWORK_socket_close (server->listen_sockets[i++]));
760 GNUNET_free (server->listen_sockets);
761 server->listen_sockets = NULL;
762 }
763 if (GNUNET_NO == server->in_soft_shutdown)
764 server->in_soft_shutdown = GNUNET_YES;
765 test_monitor_clients (server);
766}
767
768
769/**
770 * Free resources held by this server.
771 *
772 * @param server server to destroy
773 */
774void
775GNUNET_SERVER_destroy (struct GNUNET_SERVER_Handle *server)
776{
777 struct HandlerList *hpos;
778 struct NotifyList *npos;
779 unsigned int i;
780
781 LOG (GNUNET_ERROR_TYPE_DEBUG,
782 "Server shutting down.\n");
783 if (NULL != server->listen_task)
784 {
785 GNUNET_SCHEDULER_cancel (server->listen_task);
786 server->listen_task = NULL;
787 }
788 if (NULL != server->listen_sockets)
789 {
790 i = 0;
791 while (NULL != server->listen_sockets[i])
792 GNUNET_break (GNUNET_OK ==
793 GNUNET_NETWORK_socket_close (server->listen_sockets[i++]));
794 GNUNET_free (server->listen_sockets);
795 server->listen_sockets = NULL;
796 }
797 while (NULL != server->clients_head)
798 GNUNET_SERVER_client_disconnect (server->clients_head);
799 while (NULL != (hpos = server->handlers))
800 {
801 server->handlers = hpos->next;
802 GNUNET_free (hpos);
803 }
804 while (NULL != (npos = server->disconnect_notify_list_head))
805 {
806 npos->callback (npos->callback_cls,
807 NULL);
808 GNUNET_CONTAINER_DLL_remove (server->disconnect_notify_list_head,
809 server->disconnect_notify_list_tail,
810 npos);
811 GNUNET_free (npos);
812 }
813 while (NULL != (npos = server->connect_notify_list_head))
814 {
815 npos->callback (npos->callback_cls,
816 NULL);
817 GNUNET_CONTAINER_DLL_remove (server->connect_notify_list_head,
818 server->connect_notify_list_tail,
819 npos);
820 GNUNET_free (npos);
821 }
822 GNUNET_free (server);
823}
824
825
826/**
827 * Add additional handlers to an existing server.
828 *
829 * @param server the server to add handlers to
830 * @param handlers array of message handlers for
831 * incoming messages; the last entry must
832 * have "NULL" for the "callback"; multiple
833 * entries for the same type are allowed,
834 * they will be called in order of occurrence.
835 * These handlers can be removed later;
836 * the handlers array must exist until removed
837 * (or server is destroyed).
838 */
839void
840GNUNET_SERVER_add_handlers (struct GNUNET_SERVER_Handle *server,
841 const struct GNUNET_SERVER_MessageHandler *handlers)
842{
843 struct HandlerList *p;
844
845 p = GNUNET_new (struct HandlerList);
846 p->handlers = handlers;
847 p->next = server->handlers;
848 server->handlers = p;
849}
850
851
852/**
853 * Change functions used by the server to tokenize the message stream.
854 * (very rarely used).
855 *
856 * @param server server to modify
857 * @param create new tokenizer initialization function
858 * @param destroy new tokenizer destruction function
859 * @param receive new tokenizer receive function
860 * @param cls closure for @a create, @a receive, @a destroy
861 */
862void
863GNUNET_SERVER_set_callbacks (struct GNUNET_SERVER_Handle *server,
864 GNUNET_SERVER_MstCreateCallback create,
865 GNUNET_SERVER_MstDestroyCallback destroy,
866 GNUNET_SERVER_MstReceiveCallback receive,
867 void *cls)
868{
869 server->mst_create = create;
870 server->mst_destroy = destroy;
871 server->mst_receive = receive;
872 server->mst_cls = cls;
873}
874
875
876/**
877 * Task run to warn about missing calls to #GNUNET_SERVER_receive_done.
878 *
879 * @param cls our `struct GNUNET_SERVER_Client *` to process more requests from
880 */
881static void
882warn_no_receive_done (void *cls)
883{
884 struct GNUNET_SERVER_Client *client = cls;
885
886 GNUNET_break (0 != client->warn_type); /* type should never be 0 here, as we don't use 0 */
887 client->warn_task =
888 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
889 &warn_no_receive_done, client);
890 LOG (GNUNET_ERROR_TYPE_WARNING,
891 _ (
892 "Processing code for message of type %u did not call `GNUNET_SERVER_receive_done' after %s\n"),
893 (unsigned int) client->warn_type,
894 GNUNET_STRINGS_relative_time_to_string (
895 GNUNET_TIME_absolute_get_duration (client->warn_start),
896 GNUNET_YES));
897}
898
899
900/**
901 * Disable the warning the server issues if a message is not acknowledged
902 * in a timely fashion. Use this call if a client is intentionally delayed
903 * for a while. Only applies to the current message.
904 *
905 * @param client client for which to disable the warning
906 */
907void
908GNUNET_SERVER_disable_receive_done_warning (struct GNUNET_SERVER_Client *client)
909{
910 if (NULL != client->warn_task)
911 {
912 GNUNET_SCHEDULER_cancel (client->warn_task);
913 client->warn_task = NULL;
914 }
915}
916
917
918/**
919 * Inject a message into the server, pretend it came
920 * from the specified client. Delivery of the message
921 * will happen instantly (if a handler is installed;
922 * otherwise the call does nothing).
923 *
924 * @param server the server receiving the message
925 * @param sender the "pretended" sender of the message
926 * can be NULL!
927 * @param message message to transmit
928 * @return #GNUNET_OK if the message was OK and the
929 * connection can stay open
930 * #GNUNET_SYSERR if the connection to the
931 * client should be shut down
932 */
933int
934GNUNET_SERVER_inject (struct GNUNET_SERVER_Handle *server,
935 struct GNUNET_SERVER_Client *sender,
936 const struct GNUNET_MessageHeader *message)
937{
938 struct HandlerList *pos;
939 const struct GNUNET_SERVER_MessageHandler *mh;
940 unsigned int i;
941 uint16_t type;
942 uint16_t size;
943 int found;
944
945 type = ntohs (message->type);
946 size = ntohs (message->size);
947 LOG (GNUNET_ERROR_TYPE_INFO,
948 "Received message of type %u and size %u from client\n",
949 type, size);
950 found = GNUNET_NO;
951 for (pos = server->handlers; NULL != pos; pos = pos->next)
952 {
953 i = 0;
954 while (pos->handlers[i].callback != NULL)
955 {
956 mh = &pos->handlers[i];
957 if ((mh->type == type) || (mh->type == GNUNET_MESSAGE_TYPE_ALL))
958 {
959 if ((0 != mh->expected_size) && (mh->expected_size != size))
960 {
961#if GNUNET8_NETWORK_IS_DEAD
962 LOG (GNUNET_ERROR_TYPE_WARNING,
963 "Expected %u bytes for message of type %u, got %u\n",
964 mh->expected_size, mh->type, size);
965 GNUNET_break_op (0);
966#else
967 LOG (GNUNET_ERROR_TYPE_DEBUG,
968 "Expected %u bytes for message of type %u, got %u\n",
969 mh->expected_size, mh->type, size);
970#endif
971 return GNUNET_SYSERR;
972 }
973 if (NULL != sender)
974 {
975 if ((0 == sender->suspended) &&
976 (NULL == sender->warn_task))
977 {
978 GNUNET_break (0 != type); /* type should never be 0 here, as we don't use 0 */
979 sender->warn_start = GNUNET_TIME_absolute_get ();
980 sender->warn_task =
981 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
982 &warn_no_receive_done,
983 sender);
984 sender->warn_type = type;
985 }
986 sender->suspended++;
987 }
988 mh->callback (mh->callback_cls, sender, message);
989 found = GNUNET_YES;
990 }
991 i++;
992 }
993 }
994 if (GNUNET_NO == found)
995 {
996 LOG (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
997 "Received message of unknown type %d\n", type);
998 if (GNUNET_YES == server->require_found)
999 return GNUNET_SYSERR;
1000 }
1001 return GNUNET_OK;
1002}
1003
1004
1005/**
1006 * We are receiving an incoming message. Process it.
1007 *
1008 * @param cls our closure (handle for the client)
1009 * @param buf buffer with data received from network
1010 * @param available number of bytes available in buf
1011 * @param addr address of the sender
1012 * @param addrlen length of @a addr
1013 * @param errCode code indicating errors receiving, 0 for success
1014 */
1015static void
1016process_incoming (void *cls,
1017 const void *buf,
1018 size_t available,
1019 const struct sockaddr *addr,
1020 socklen_t addrlen,
1021 int errCode);
1022
1023
1024/**
1025 * Process messages from the client's message tokenizer until either
1026 * the tokenizer is empty (and then schedule receiving more), or
1027 * until some handler is not immediately done (then wait for restart_processing)
1028 * or shutdown.
1029 *
1030 * @param client the client to process, RC must have already been increased
1031 * using #GNUNET_SERVER_client_keep and will be decreased by one in this
1032 * function
1033 * @param ret #GNUNET_NO to start processing from the buffer,
1034 * #GNUNET_OK if the mst buffer is drained and we should instantly go back to receiving
1035 * #GNUNET_SYSERR if we should instantly abort due to error in a previous step
1036 */
1037static void
1038process_mst (struct GNUNET_SERVER_Client *client,
1039 int ret)
1040{
1041 while ((GNUNET_SYSERR != ret) && (NULL != client->server) &&
1042 (GNUNET_YES != client->shutdown_now) && (0 == client->suspended))
1043 {
1044 if (GNUNET_OK == ret)
1045 {
1046 LOG (GNUNET_ERROR_TYPE_DEBUG,
1047 "Server re-enters receive loop, timeout: %s.\n",
1048 GNUNET_STRINGS_relative_time_to_string (client->idle_timeout,
1049 GNUNET_YES));
1050 client->receive_pending = GNUNET_YES;
1051 if (GNUNET_OK !=
1052 GNUNET_CONNECTION_receive (client->connection,
1053 GNUNET_MAX_MESSAGE_SIZE - 1,
1054 client->idle_timeout,
1055 &process_incoming,
1056 client))
1057 return;
1058 break;
1059 }
1060 LOG (GNUNET_ERROR_TYPE_DEBUG,
1061 "Server processes additional messages instantly.\n");
1062 if (NULL != client->server->mst_receive)
1063 ret =
1064 client->server->mst_receive (client->server->mst_cls, client->mst,
1065 client, NULL, 0, GNUNET_NO, GNUNET_YES);
1066 else
1067 ret =
1068 GNUNET_SERVER_mst_receive (client->mst, client, NULL, 0, GNUNET_NO,
1069 GNUNET_YES);
1070 }
1071 LOG (GNUNET_ERROR_TYPE_DEBUG,
1072 "Server leaves instant processing loop: ret = %d, server = %p, shutdown = %d, suspended = %u\n",
1073 ret, client->server,
1074 client->shutdown_now,
1075 client->suspended);
1076 if (GNUNET_NO == ret)
1077 {
1078 LOG (GNUNET_ERROR_TYPE_DEBUG,
1079 "Server has more data pending but is suspended.\n");
1080 client->receive_pending = GNUNET_SYSERR; /* data pending */
1081 }
1082 if ((GNUNET_SYSERR == ret) ||
1083 (GNUNET_YES == client->shutdown_now))
1084 GNUNET_SERVER_client_disconnect (client);
1085}
1086
1087
1088/**
1089 * We are receiving an incoming message. Process it.
1090 *
1091 * @param cls our closure (handle for the client)
1092 * @param buf buffer with data received from network
1093 * @param available number of bytes available in buf
1094 * @param addr address of the sender
1095 * @param addrlen length of @a addr
1096 * @param errCode code indicating errors receiving, 0 for success
1097 */
1098static void
1099process_incoming (void *cls,
1100 const void *buf,
1101 size_t available,
1102 const struct sockaddr *addr,
1103 socklen_t addrlen,
1104 int errCode)
1105{
1106 struct GNUNET_SERVER_Client *client = cls;
1107 struct GNUNET_SERVER_Handle *server = client->server;
1108 struct GNUNET_TIME_Absolute end;
1109 struct GNUNET_TIME_Absolute now;
1110 int ret;
1111
1112 GNUNET_assert (GNUNET_YES == client->receive_pending);
1113 client->receive_pending = GNUNET_NO;
1114 now = GNUNET_TIME_absolute_get ();
1115 end = GNUNET_TIME_absolute_add (client->last_activity,
1116 client->idle_timeout);
1117
1118 if ((NULL == buf) &&
1119 (0 == available) &&
1120 (NULL == addr) &&
1121 (0 == errCode) &&
1122 (GNUNET_YES != client->shutdown_now) &&
1123 (NULL != server) &&
1124 (GNUNET_YES == GNUNET_CONNECTION_check (client->connection)) &&
1125 (end.abs_value_us > now.abs_value_us))
1126 {
1127 /* wait longer, timeout changed (i.e. due to us sending) */
1128 LOG (GNUNET_ERROR_TYPE_DEBUG,
1129 "Receive time out, but no disconnect due to sending (%p)\n",
1130 client);
1131 client->receive_pending = GNUNET_YES;
1132 GNUNET_CONNECTION_receive (client->connection,
1133 GNUNET_MAX_MESSAGE_SIZE - 1,
1134 GNUNET_TIME_absolute_get_remaining (end),
1135 &process_incoming,
1136 client);
1137 return;
1138 }
1139 if ((NULL == buf) ||
1140 (0 == available) ||
1141 (0 != errCode) ||
1142 (NULL == server) ||
1143 (GNUNET_YES == client->shutdown_now) ||
1144 (GNUNET_YES != GNUNET_CONNECTION_check (client->connection)))
1145 {
1146 /* other side closed connection, error connecting, etc. */
1147 LOG (GNUNET_ERROR_TYPE_DEBUG,
1148 "Failed to connect or other side closed connection (%p)\n",
1149 client);
1150 GNUNET_SERVER_client_disconnect (client);
1151 return;
1152 }
1153 LOG (GNUNET_ERROR_TYPE_DEBUG,
1154 "Server receives %u bytes from `%s'.\n",
1155 (unsigned int) available,
1156 GNUNET_a2s (addr, addrlen));
1157 GNUNET_SERVER_client_keep (client);
1158 client->last_activity = now;
1159
1160 if (NULL != server->mst_receive)
1161 {
1162 ret = client->server->mst_receive (client->server->mst_cls,
1163 client->mst,
1164 client,
1165 buf,
1166 available,
1167 GNUNET_NO,
1168 GNUNET_YES);
1169 }
1170 else if (NULL != client->mst)
1171 {
1172 ret =
1173 GNUNET_SERVER_mst_receive (client->mst,
1174 client,
1175 buf,
1176 available,
1177 GNUNET_NO,
1178 GNUNET_YES);
1179 }
1180 else
1181 {
1182 GNUNET_break (0);
1183 return;
1184 }
1185 process_mst (client,
1186 ret);
1187 GNUNET_SERVER_client_drop (client);
1188}
1189
1190
1191/**
1192 * Task run to start again receiving from the network
1193 * and process requests.
1194 *
1195 * @param cls our `struct GNUNET_SERVER_Client *` to process more requests from
1196 */
1197static void
1198restart_processing (void *cls)
1199{
1200 struct GNUNET_SERVER_Client *client = cls;
1201
1202 GNUNET_assert (GNUNET_YES != client->shutdown_now);
1203 client->restart_task = NULL;
1204 if (GNUNET_NO == client->receive_pending)
1205 {
1206 LOG (GNUNET_ERROR_TYPE_DEBUG, "Server begins to read again from client.\n");
1207 client->receive_pending = GNUNET_YES;
1208 GNUNET_CONNECTION_receive (client->connection,
1209 GNUNET_MAX_MESSAGE_SIZE - 1,
1210 client->idle_timeout,
1211 &process_incoming,
1212 client);
1213 return;
1214 }
1215 LOG (GNUNET_ERROR_TYPE_DEBUG,
1216 "Server continues processing messages still in the buffer.\n");
1217 GNUNET_SERVER_client_keep (client);
1218 client->receive_pending = GNUNET_NO;
1219 process_mst (client,
1220 GNUNET_NO);
1221 GNUNET_SERVER_client_drop (client);
1222}
1223
1224
1225/**
1226 * This function is called whenever our inbound message tokenizer has
1227 * received a complete message.
1228 *
1229 * @param cls closure (struct GNUNET_SERVER_Handle)
1230 * @param client identification of the client (`struct GNUNET_SERVER_Client *`)
1231 * @param message the actual message
1232 *
1233 * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing
1234 */
1235static int
1236client_message_tokenizer_callback (void *cls,
1237 void *client,
1238 const struct GNUNET_MessageHeader *message)
1239{
1240 struct GNUNET_SERVER_Handle *server = cls;
1241 struct GNUNET_SERVER_Client *sender = client;
1242 int ret;
1243
1244 LOG (GNUNET_ERROR_TYPE_DEBUG,
1245 "Tokenizer gives server message of type %u and size %u from client\n",
1246 ntohs (message->type), ntohs (message->size));
1247 sender->in_process_client_buffer = GNUNET_YES;
1248 ret = GNUNET_SERVER_inject (server, sender, message);
1249 sender->in_process_client_buffer = GNUNET_NO;
1250 if ((GNUNET_OK != ret) || (GNUNET_YES == sender->shutdown_now))
1251 {
1252 GNUNET_SERVER_client_disconnect (sender);
1253 return GNUNET_SYSERR;
1254 }
1255 return GNUNET_OK;
1256}
1257
1258
1259/**
1260 * Add a TCP socket-based connection to the set of handles managed by
1261 * this server. Use this function for outgoing (P2P) connections that
1262 * we initiated (and where this server should process incoming
1263 * messages).
1264 *
1265 * @param server the server to use
1266 * @param connection the connection to manage (client must
1267 * stop using this connection from now on)
1268 * @return the client handle
1269 */
1270struct GNUNET_SERVER_Client *
1271GNUNET_SERVER_connect_socket (struct GNUNET_SERVER_Handle *server,
1272 struct GNUNET_CONNECTION_Handle *connection)
1273{
1274 struct GNUNET_SERVER_Client *client;
1275 struct NotifyList *n;
1276
1277 client = GNUNET_new (struct GNUNET_SERVER_Client);
1278 client->connection = connection;
1279 client->server = server;
1280 client->last_activity = GNUNET_TIME_absolute_get ();
1281 client->idle_timeout = server->idle_timeout;
1282 GNUNET_CONTAINER_DLL_insert (server->clients_head,
1283 server->clients_tail,
1284 client);
1285 if (NULL != server->mst_create)
1286 client->mst =
1287 server->mst_create (server->mst_cls, client);
1288 else
1289 client->mst =
1290 GNUNET_SERVER_mst_create (&client_message_tokenizer_callback,
1291 server);
1292 GNUNET_assert (NULL != client->mst);
1293 for (n = server->connect_notify_list_head; NULL != n; n = n->next)
1294 n->callback (n->callback_cls, client);
1295 client->receive_pending = GNUNET_YES;
1296 if (GNUNET_SYSERR ==
1297 GNUNET_CONNECTION_receive (client->connection,
1298 GNUNET_MAX_MESSAGE_SIZE - 1,
1299 client->idle_timeout,
1300 &process_incoming,
1301 client))
1302 return NULL;
1303 return client;
1304}
1305
1306
1307/**
1308 * Change the timeout for a particular client. Decreasing the timeout
1309 * may not go into effect immediately (only after the previous timeout
1310 * times out or activity happens on the socket).
1311 *
1312 * @param client the client to update
1313 * @param timeout new timeout for activities on the socket
1314 */
1315void
1316GNUNET_SERVER_client_set_timeout (struct GNUNET_SERVER_Client *client,
1317 struct GNUNET_TIME_Relative timeout)
1318{
1319 client->idle_timeout = timeout;
1320}
1321
1322
1323/**
1324 * Notify the server that the given client handle should
1325 * be kept (keeps the connection up if possible, increments
1326 * the internal reference counter).
1327 *
1328 * @param client the client to keep
1329 */
1330void
1331GNUNET_SERVER_client_keep (struct GNUNET_SERVER_Client *client)
1332{
1333 client->reference_count++;
1334}
1335
1336
1337/**
1338 * Notify the server that the given client handle is no
1339 * longer required. Decrements the reference counter. If
1340 * that counter reaches zero an inactive connection maybe
1341 * closed.
1342 *
1343 * @param client the client to drop
1344 */
1345void
1346GNUNET_SERVER_client_drop (struct GNUNET_SERVER_Client *client)
1347{
1348 GNUNET_assert (client->reference_count > 0);
1349 client->reference_count--;
1350 if ((GNUNET_YES == client->shutdown_now) && (0 == client->reference_count))
1351 GNUNET_SERVER_client_disconnect (client);
1352}
1353
1354
1355/**
1356 * Obtain the network address of the other party.
1357 *
1358 * @param client the client to get the address for
1359 * @param addr where to store the address
1360 * @param addrlen where to store the length of the @a addr
1361 * @return #GNUNET_OK on success
1362 */
1363int
1364GNUNET_SERVER_client_get_address (struct GNUNET_SERVER_Client *client,
1365 void **addr, size_t *addrlen)
1366{
1367 return GNUNET_CONNECTION_get_address (client->connection, addr, addrlen);
1368}
1369
1370
1371/**
1372 * Ask the server to notify us whenever a client disconnects.
1373 * This function is called whenever the actual network connection
1374 * is closed; the reference count may be zero or larger than zero
1375 * at this point.
1376 *
1377 * @param server the server manageing the clients
1378 * @param callback function to call on disconnect
1379 * @param callback_cls closure for @a callback
1380 */
1381void
1382GNUNET_SERVER_disconnect_notify (struct GNUNET_SERVER_Handle *server,
1383 GNUNET_SERVER_DisconnectCallback callback,
1384 void *callback_cls)
1385{
1386 struct NotifyList *n;
1387
1388 n = GNUNET_new (struct NotifyList);
1389 n->callback = callback;
1390 n->callback_cls = callback_cls;
1391 GNUNET_CONTAINER_DLL_insert (server->disconnect_notify_list_head,
1392 server->disconnect_notify_list_tail,
1393 n);
1394}
1395
1396
1397/**
1398 * Ask the server to notify us whenever a client connects.
1399 * This function is called whenever the actual network connection
1400 * is opened. If the server is destroyed before this
1401 * notification is explicitly cancelled, the 'callback' will
1402 * once be called with a 'client' argument of NULL to indicate
1403 * that the server itself is now gone (and that the callback
1404 * won't be called anymore and also can no longer be cancelled).
1405 *
1406 * @param server the server manageing the clients
1407 * @param callback function to call on sconnect
1408 * @param callback_cls closure for @a callback
1409 */
1410void
1411GNUNET_SERVER_connect_notify (struct GNUNET_SERVER_Handle *server,
1412 GNUNET_SERVER_ConnectCallback callback,
1413 void *callback_cls)
1414{
1415 struct NotifyList *n;
1416 struct GNUNET_SERVER_Client *client;
1417
1418 n = GNUNET_new (struct NotifyList);
1419 n->callback = callback;
1420 n->callback_cls = callback_cls;
1421 GNUNET_CONTAINER_DLL_insert (server->connect_notify_list_head,
1422 server->connect_notify_list_tail,
1423 n);
1424 for (client = server->clients_head; NULL != client; client = client->next)
1425 callback (callback_cls, client);
1426}
1427
1428
1429/**
1430 * Ask the server to stop notifying us whenever a client connects.
1431 *
1432 * @param server the server manageing the clients
1433 * @param callback function to call on connect
1434 * @param callback_cls closure for @a callback
1435 */
1436void
1437GNUNET_SERVER_disconnect_notify_cancel (struct GNUNET_SERVER_Handle *server,
1438 GNUNET_SERVER_DisconnectCallback
1439 callback,
1440 void *callback_cls)
1441{
1442 struct NotifyList *pos;
1443
1444 for (pos = server->disconnect_notify_list_head; NULL != pos; pos = pos->next)
1445 if ((pos->callback == callback) && (pos->callback_cls == callback_cls))
1446 break;
1447 if (NULL == pos)
1448 {
1449 GNUNET_break (0);
1450 return;
1451 }
1452 GNUNET_CONTAINER_DLL_remove (server->disconnect_notify_list_head,
1453 server->disconnect_notify_list_tail,
1454 pos);
1455 GNUNET_free (pos);
1456}
1457
1458
1459/**
1460 * Ask the server to stop notifying us whenever a client disconnects.
1461 *
1462 * @param server the server manageing the clients
1463 * @param callback function to call on disconnect
1464 * @param callback_cls closure for @a callback
1465 */
1466void
1467GNUNET_SERVER_connect_notify_cancel (struct GNUNET_SERVER_Handle *server,
1468 GNUNET_SERVER_ConnectCallback callback,
1469 void *callback_cls)
1470{
1471 struct NotifyList *pos;
1472
1473 for (pos = server->connect_notify_list_head; NULL != pos; pos = pos->next)
1474 if ((pos->callback == callback) && (pos->callback_cls == callback_cls))
1475 break;
1476 if (NULL == pos)
1477 {
1478 GNUNET_break (0);
1479 return;
1480 }
1481 GNUNET_CONTAINER_DLL_remove (server->connect_notify_list_head,
1482 server->connect_notify_list_tail,
1483 pos);
1484 GNUNET_free (pos);
1485}
1486
1487
1488/**
1489 * Ask the server to disconnect from the given client.
1490 * This is the same as returning #GNUNET_SYSERR from a message
1491 * handler, except that it allows dropping of a client even
1492 * when not handling a message from that client.
1493 *
1494 * @param client the client to disconnect from
1495 */
1496void
1497GNUNET_SERVER_client_disconnect (struct GNUNET_SERVER_Client *client)
1498{
1499 struct GNUNET_SERVER_Handle *server = client->server;
1500 struct NotifyList *n;
1501
1502 LOG (GNUNET_ERROR_TYPE_DEBUG,
1503 "Client is being disconnected from the server.\n");
1504 if (NULL != client->restart_task)
1505 {
1506 GNUNET_SCHEDULER_cancel (client->restart_task);
1507 client->restart_task = NULL;
1508 }
1509 if (NULL != client->warn_task)
1510 {
1511 GNUNET_SCHEDULER_cancel (client->warn_task);
1512 client->warn_task = NULL;
1513 }
1514 if (GNUNET_YES == client->receive_pending)
1515 {
1516 GNUNET_CONNECTION_receive_cancel (client->connection);
1517 client->receive_pending = GNUNET_NO;
1518 }
1519 client->shutdown_now = GNUNET_YES;
1520 client->reference_count++; /* make sure nobody else clean up client... */
1521 if ((NULL != client->mst) &&
1522 (NULL != server))
1523 {
1524 GNUNET_CONTAINER_DLL_remove (server->clients_head,
1525 server->clients_tail,
1526 client);
1527 if (NULL != server->mst_destroy)
1528 server->mst_destroy (server->mst_cls,
1529 client->mst);
1530 else
1531 GNUNET_SERVER_mst_destroy (client->mst);
1532 client->mst = NULL;
1533 for (n = server->disconnect_notify_list_head; NULL != n; n = n->next)
1534 n->callback (n->callback_cls,
1535 client);
1536 }
1537 client->reference_count--;
1538 if (client->reference_count > 0)
1539 {
1540 LOG (GNUNET_ERROR_TYPE_DEBUG,
1541 "RC of %p still positive, not destroying everything.\n",
1542 client);
1543 client->server = NULL;
1544 return;
1545 }
1546 if (GNUNET_YES == client->in_process_client_buffer)
1547 {
1548 LOG (GNUNET_ERROR_TYPE_DEBUG,
1549 "Still processing inputs of %p, not destroying everything.\n",
1550 client);
1551 return;
1552 }
1553 LOG (GNUNET_ERROR_TYPE_DEBUG,
1554 "RC of %p now zero, destroying everything.\n",
1555 client);
1556 if (GNUNET_YES == client->persist)
1557 GNUNET_CONNECTION_persist_ (client->connection);
1558 if (NULL != client->th.cth)
1559 GNUNET_SERVER_notify_transmit_ready_cancel (&client->th);
1560 GNUNET_CONNECTION_destroy (client->connection);
1561 /* need to cancel again, as it might have been re-added
1562 in the meantime (i.e. during callbacks) */
1563 if (NULL != client->warn_task)
1564 {
1565 GNUNET_SCHEDULER_cancel (client->warn_task);
1566 client->warn_task = NULL;
1567 }
1568 if (GNUNET_YES == client->receive_pending)
1569 {
1570 GNUNET_CONNECTION_receive_cancel (client->connection);
1571 client->receive_pending = GNUNET_NO;
1572 }
1573 GNUNET_free (client);
1574 /* we might be in soft-shutdown, test if we're done */
1575 if (NULL != server)
1576 test_monitor_clients (server);
1577}
1578
1579
1580/**
1581 * Disable the "CORK" feature for communication with the given client,
1582 * forcing the OS to immediately flush the buffer on transmission
1583 * instead of potentially buffering multiple messages.
1584 *
1585 * @param client handle to the client
1586 * @return #GNUNET_OK on success
1587 */
1588int
1589GNUNET_SERVER_client_disable_corking (struct GNUNET_SERVER_Client *client)
1590{
1591 return GNUNET_CONNECTION_disable_corking (client->connection);
1592}
1593
1594
1595/**
1596 * Wrapper for transmission notification that calls the original
1597 * callback and update the last activity time for our connection.
1598 *
1599 * @param cls the `struct GNUNET_SERVER_Client *`
1600 * @param size number of bytes we can transmit
1601 * @param buf where to copy the message
1602 * @return number of bytes actually transmitted
1603 */
1604static size_t
1605transmit_ready_callback_wrapper (void *cls, size_t size, void *buf)
1606{
1607 struct GNUNET_SERVER_Client *client = cls;
1608 GNUNET_CONNECTION_TransmitReadyNotify callback;
1609
1610 client->th.cth = NULL;
1611 callback = client->th.callback;
1612 client->th.callback = NULL;
1613 client->last_activity = GNUNET_TIME_absolute_get ();
1614 return callback (client->th.callback_cls, size, buf);
1615}
1616
1617
1618struct GNUNET_SERVER_TransmitHandle *
1619GNUNET_SERVER_notify_transmit_ready (struct GNUNET_SERVER_Client *client,
1620 size_t size,
1621 struct GNUNET_TIME_Relative timeout,
1622 GNUNET_CONNECTION_TransmitReadyNotify
1623 callback,
1624 void *callback_cls)
1625{
1626 if (NULL != client->th.callback)
1627 return NULL;
1628 client->th.callback_cls = callback_cls;
1629 client->th.callback = callback;
1630 client->th.cth = GNUNET_CONNECTION_notify_transmit_ready (client->connection,
1631 size,
1632 timeout,
1633 &
1634 transmit_ready_callback_wrapper,
1635 client);
1636 return &client->th;
1637}
1638
1639
1640/**
1641 * Abort transmission request.
1642 *
1643 * @param th request to abort
1644 */
1645void
1646GNUNET_SERVER_notify_transmit_ready_cancel (struct
1647 GNUNET_SERVER_TransmitHandle *th)
1648{
1649 GNUNET_CONNECTION_notify_transmit_ready_cancel (th->cth);
1650 th->cth = NULL;
1651 th->callback = NULL;
1652}
1653
1654
1655/**
1656 * Set the persistent flag on this client, used to setup client connection
1657 * to only be killed when the service it's connected to is actually dead.
1658 *
1659 * @param client the client to set the persistent flag on
1660 */
1661void
1662GNUNET_SERVER_client_persist_ (struct GNUNET_SERVER_Client *client)
1663{
1664 client->persist = GNUNET_YES;
1665}
1666
1667
1668/**
1669 * Resume receiving from this client, we are done processing the
1670 * current request. This function must be called from within each
1671 * GNUNET_SERVER_MessageCallback (or its respective continuations).
1672 *
1673 * @param client client we were processing a message of
1674 * @param success #GNUNET_OK to keep the connection open and
1675 * continue to receive
1676 * #GNUNET_NO to close the connection (normal behavior)
1677 * #GNUNET_SYSERR to close the connection (signal
1678 * serious error)
1679 */
1680void
1681GNUNET_SERVER_receive_done (struct GNUNET_SERVER_Client *client,
1682 int success)
1683{
1684 if (NULL == client)
1685 return;
1686 GNUNET_assert (client->suspended > 0);
1687 client->suspended--;
1688 if (GNUNET_OK != success)
1689 {
1690 LOG (GNUNET_ERROR_TYPE_DEBUG,
1691 "GNUNET_SERVER_receive_done called with failure indication\n");
1692 if ((client->reference_count > 0) || (client->suspended > 0))
1693 client->shutdown_now = GNUNET_YES;
1694 else
1695 GNUNET_SERVER_client_disconnect (client);
1696 return;
1697 }
1698 if (client->suspended > 0)
1699 {
1700 LOG (GNUNET_ERROR_TYPE_DEBUG,
1701 "GNUNET_SERVER_receive_done called, but more clients pending\n");
1702 return;
1703 }
1704 if (NULL != client->warn_task)
1705 {
1706 GNUNET_SCHEDULER_cancel (client->warn_task);
1707 client->warn_task = NULL;
1708 }
1709 if (GNUNET_YES == client->in_process_client_buffer)
1710 {
1711 LOG (GNUNET_ERROR_TYPE_DEBUG,
1712 "GNUNET_SERVER_receive_done called while still in processing loop\n");
1713 return;
1714 }
1715 if ((NULL == client->server) || (GNUNET_YES == client->shutdown_now))
1716 {
1717 GNUNET_SERVER_client_disconnect (client);
1718 return;
1719 }
1720 LOG (GNUNET_ERROR_TYPE_DEBUG,
1721 "GNUNET_SERVER_receive_done causes restart in reading from the socket\n");
1722 GNUNET_assert (NULL == client->restart_task);
1723 client->restart_task = GNUNET_SCHEDULER_add_now (&restart_processing,
1724 client);
1725}
1726
1727
1728/* end of server.c */
diff --git a/src/transport/tcp_server_mst_legacy.c b/src/transport/tcp_server_mst_legacy.c
deleted file mode 100644
index bed6874c9..000000000
--- a/src/transport/tcp_server_mst_legacy.c
+++ /dev/null
@@ -1,307 +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 it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file util/server_mst.c
23 * @brief convenience functions for handling inbound message buffers
24 * @author Christian Grothoff
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29
30
31#if HAVE_UNALIGNED_64_ACCESS
32#define ALIGN_FACTOR 4
33#else
34#define ALIGN_FACTOR 8
35#endif
36
37
38/**
39 * Handle to a message stream tokenizer.
40 */
41struct GNUNET_SERVER_MessageStreamTokenizer
42{
43 /**
44 * Function to call on completed messages.
45 */
46 GNUNET_SERVER_MessageTokenizerCallback cb;
47
48 /**
49 * Closure for @e cb.
50 */
51 void *cb_cls;
52
53 /**
54 * Size of the buffer (starting at @e hdr).
55 */
56 size_t curr_buf;
57
58 /**
59 * How many bytes in buffer have we already processed?
60 */
61 size_t off;
62
63 /**
64 * How many bytes in buffer are valid right now?
65 */
66 size_t pos;
67
68 /**
69 * Beginning of the buffer. Typed like this to force alignment.
70 */
71 struct GNUNET_MessageHeader *hdr;
72};
73
74
75/**
76 * Create a message stream tokenizer.
77 *
78 * @param cb function to call on completed messages
79 * @param cb_cls closure for @a cb
80 * @return handle to tokenizer
81 */
82struct GNUNET_SERVER_MessageStreamTokenizer *
83GNUNET_SERVER_mst_create (GNUNET_SERVER_MessageTokenizerCallback cb,
84 void *cb_cls)
85{
86 struct GNUNET_SERVER_MessageStreamTokenizer *ret;
87
88 ret = GNUNET_new (struct GNUNET_SERVER_MessageStreamTokenizer);
89 ret->hdr = GNUNET_malloc (GNUNET_MIN_MESSAGE_SIZE);
90 ret->curr_buf = GNUNET_MIN_MESSAGE_SIZE;
91 ret->cb = cb;
92 ret->cb_cls = cb_cls;
93 return ret;
94}
95
96
97/**
98 * Add incoming data to the receive buffer and call the
99 * callback for all complete messages.
100 *
101 * @param mst tokenizer to use
102 * @param client_identity ID of client for which this is a buffer
103 * @param buf input data to add
104 * @param size number of bytes in @a buf
105 * @param purge should any excess bytes in the buffer be discarded
106 * (i.e. for packet-based services like UDP)
107 * @param one_shot only call callback once, keep rest of message in buffer
108 * @return #GNUNET_OK if we are done processing (need more data)
109 * #GNUNET_NO if @a one_shot was set and we have another message ready
110 * #GNUNET_SYSERR if the data stream is corrupt
111 */
112int
113GNUNET_SERVER_mst_receive (struct GNUNET_SERVER_MessageStreamTokenizer *mst,
114 void *client_identity,
115 const char *buf, size_t size,
116 int purge, int one_shot)
117{
118 const struct GNUNET_MessageHeader *hdr;
119 size_t delta;
120 uint16_t want;
121 char *ibuf;
122 int need_align;
123 unsigned long offset;
124 int ret;
125
126 GNUNET_assert (mst->off <= mst->pos);
127 GNUNET_assert (mst->pos <= mst->curr_buf);
128 LOG (GNUNET_ERROR_TYPE_DEBUG,
129 "Server-mst receives %u bytes with %u bytes already in private buffer\n",
130 (unsigned int) size, (unsigned int) (mst->pos - mst->off));
131 ret = GNUNET_OK;
132 ibuf = (char *) mst->hdr;
133 while (mst->pos > 0)
134 {
135do_align:
136 GNUNET_assert (mst->pos >= mst->off);
137 if ((mst->curr_buf - mst->off < sizeof(struct GNUNET_MessageHeader)) ||
138 (0 != (mst->off % ALIGN_FACTOR)))
139 {
140 /* need to align or need more space */
141 mst->pos -= mst->off;
142 memmove (ibuf, &ibuf[mst->off], mst->pos);
143 mst->off = 0;
144 }
145 if (mst->pos - mst->off < sizeof(struct GNUNET_MessageHeader))
146 {
147 delta =
148 GNUNET_MIN (sizeof(struct GNUNET_MessageHeader)
149 - (mst->pos - mst->off), size);
150 GNUNET_memcpy (&ibuf[mst->pos], buf, delta);
151 mst->pos += delta;
152 buf += delta;
153 size -= delta;
154 }
155 if (mst->pos - mst->off < sizeof(struct GNUNET_MessageHeader))
156 {
157 if (purge)
158 {
159 mst->off = 0;
160 mst->pos = 0;
161 }
162 return GNUNET_OK;
163 }
164 hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off];
165 want = ntohs (hdr->size);
166 if (want < sizeof(struct GNUNET_MessageHeader))
167 {
168 GNUNET_break_op (0);
169 return GNUNET_SYSERR;
170 }
171 if ((mst->curr_buf - mst->off < want) &&
172 (mst->off > 0))
173 {
174 /* can get more space by moving */
175 mst->pos -= mst->off;
176 memmove (ibuf, &ibuf[mst->off], mst->pos);
177 mst->off = 0;
178 }
179 if (mst->curr_buf < want)
180 {
181 /* need to get more space by growing buffer */
182 GNUNET_assert (0 == mst->off);
183 mst->hdr = GNUNET_realloc (mst->hdr, want);
184 ibuf = (char *) mst->hdr;
185 mst->curr_buf = want;
186 }
187 hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off];
188 if (mst->pos - mst->off < want)
189 {
190 delta = GNUNET_MIN (want - (mst->pos - mst->off), size);
191 GNUNET_assert (mst->pos + delta <= mst->curr_buf);
192 GNUNET_memcpy (&ibuf[mst->pos], buf, delta);
193 mst->pos += delta;
194 buf += delta;
195 size -= delta;
196 }
197 if (mst->pos - mst->off < want)
198 {
199 if (purge)
200 {
201 mst->off = 0;
202 mst->pos = 0;
203 }
204 return GNUNET_OK;
205 }
206 if (one_shot == GNUNET_SYSERR)
207 {
208 /* cannot call callback again, but return value saying that
209 * we have another full message in the buffer */
210 ret = GNUNET_NO;
211 goto copy;
212 }
213 if (one_shot == GNUNET_YES)
214 one_shot = GNUNET_SYSERR;
215 mst->off += want;
216 if (GNUNET_SYSERR == mst->cb (mst->cb_cls, client_identity, hdr))
217 return GNUNET_SYSERR;
218 if (mst->off == mst->pos)
219 {
220 /* reset to beginning of buffer, it's free right now! */
221 mst->off = 0;
222 mst->pos = 0;
223 }
224 }
225 GNUNET_assert (0 == mst->pos);
226 while (size > 0)
227 {
228 LOG (GNUNET_ERROR_TYPE_DEBUG,
229 "Server-mst has %u bytes left in inbound buffer\n",
230 (unsigned int) size);
231 if (size < sizeof(struct GNUNET_MessageHeader))
232 break;
233 offset = (unsigned long) buf;
234 need_align = (0 != (offset % ALIGN_FACTOR)) ? GNUNET_YES : GNUNET_NO;
235 if (GNUNET_NO == need_align)
236 {
237 /* can try to do zero-copy and process directly from original buffer */
238 hdr = (const struct GNUNET_MessageHeader *) buf;
239 want = ntohs (hdr->size);
240 if (want < sizeof(struct GNUNET_MessageHeader))
241 {
242 GNUNET_break_op (0);
243 mst->off = 0;
244 return GNUNET_SYSERR;
245 }
246 if (size < want)
247 break; /* or not: buffer incomplete, so copy to private buffer... */
248 if (one_shot == GNUNET_SYSERR)
249 {
250 /* cannot call callback again, but return value saying that
251 * we have another full message in the buffer */
252 ret = GNUNET_NO;
253 goto copy;
254 }
255 if (one_shot == GNUNET_YES)
256 one_shot = GNUNET_SYSERR;
257 if (GNUNET_SYSERR == mst->cb (mst->cb_cls, client_identity, hdr))
258 return GNUNET_SYSERR;
259 buf += want;
260 size -= want;
261 }
262 else
263 {
264 /* need to copy to private buffer to align;
265 * yes, we go a bit more spaghetti than usual here */
266 goto do_align;
267 }
268 }
269copy:
270 if ((size > 0) && (! purge))
271 {
272 if (size + mst->pos > mst->curr_buf)
273 {
274 mst->hdr = GNUNET_realloc (mst->hdr, size + mst->pos);
275 ibuf = (char *) mst->hdr;
276 mst->curr_buf = size + mst->pos;
277 }
278 GNUNET_assert (size + mst->pos <= mst->curr_buf);
279 GNUNET_memcpy (&ibuf[mst->pos], buf, size);
280 mst->pos += size;
281 }
282 if (purge)
283 {
284 mst->off = 0;
285 mst->pos = 0;
286 }
287 LOG (GNUNET_ERROR_TYPE_DEBUG,
288 "Server-mst leaves %u bytes in private buffer\n",
289 (unsigned int) (mst->pos - mst->off));
290 return ret;
291}
292
293
294/**
295 * Destroys a tokenizer.
296 *
297 * @param mst tokenizer to destroy
298 */
299void
300GNUNET_SERVER_mst_destroy (struct GNUNET_SERVER_MessageStreamTokenizer *mst)
301{
302 GNUNET_free (mst->hdr);
303 GNUNET_free (mst);
304}
305
306
307/* end of server_mst.c */
diff --git a/src/transport/tcp_service_legacy.c b/src/transport/tcp_service_legacy.c
deleted file mode 100644
index 65b090187..000000000
--- a/src/transport/tcp_service_legacy.c
+++ /dev/null
@@ -1,1646 +0,0 @@
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 it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file 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_MALLINFO2
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/* ****************** message handlers ****************** */
231
232/**
233 * Send a 'TEST' message back to the client.
234 *
235 * @param cls the 'struct GNUNET_SERVER_Client' to send TEST to
236 * @param size number of bytes available in 'buf'
237 * @param buf where to copy the message
238 * @return number of bytes written to 'buf'
239 */
240static size_t
241write_test (void *cls, size_t size, void *buf)
242{
243 struct GNUNET_SERVER_Client *client = cls;
244 struct GNUNET_MessageHeader *msg;
245
246 if (size < sizeof(struct GNUNET_MessageHeader))
247 {
248 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
249 return 0; /* client disconnected */
250 }
251 msg = (struct GNUNET_MessageHeader *) buf;
252 msg->type = htons (GNUNET_MESSAGE_TYPE_TEST);
253 msg->size = htons (sizeof(struct GNUNET_MessageHeader));
254 GNUNET_SERVER_receive_done (client, GNUNET_OK);
255 return sizeof(struct GNUNET_MessageHeader);
256}
257
258
259/**
260 * Handler for TEST message.
261 *
262 * @param cls closure (refers to service)
263 * @param client identification of the client
264 * @param message the actual message
265 */
266static void
267handle_test (void *cls,
268 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,
277 client))
278 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
279}
280
281
282/**
283 * Default handlers for all services. Will be copied and the
284 * "callback_cls" fields will be replaced with the specific service
285 * struct.
286 */
287static const struct GNUNET_SERVER_MessageHandler defhandlers[] =
288{ { &handle_test,
289 NULL,
290 GNUNET_MESSAGE_TYPE_TEST,
291 sizeof(struct GNUNET_MessageHeader) },
292 { NULL, NULL, 0, 0 } };
293
294
295/* ****************** service core routines ************** */
296
297
298/**
299 * Check if access to the service is allowed from the given address.
300 *
301 * @param cls closure
302 * @param uc credentials, if available, otherwise NULL
303 * @param addr address
304 * @param addrlen length of address
305 * @return #GNUNET_YES to allow, #GNUNET_NO to deny, #GNUNET_SYSERR
306 * for unknown address family (will be denied).
307 */
308static int
309check_access (void *cls,
310 const struct GNUNET_CONNECTION_Credentials *uc,
311 const struct sockaddr *addr,
312 socklen_t addrlen)
313{
314 struct LEGACY_SERVICE_Context *sctx = cls;
315 const struct sockaddr_in *i4;
316 const struct sockaddr_in6 *i6;
317 int ret;
318
319 switch (addr->sa_family)
320 {
321 case AF_INET:
322 GNUNET_assert (addrlen == sizeof(struct sockaddr_in));
323 i4 = (const struct sockaddr_in *) addr;
324 ret = ((NULL == sctx->v4_allowed) ||
325 (check_ipv4_listed (sctx->v4_allowed, &i4->sin_addr))) &&
326 ((NULL == sctx->v4_denied) ||
327 (! check_ipv4_listed (sctx->v4_denied, &i4->sin_addr)));
328 break;
329
330 case AF_INET6:
331 GNUNET_assert (addrlen == sizeof(struct sockaddr_in6));
332 i6 = (const struct sockaddr_in6 *) addr;
333 ret = ((NULL == sctx->v6_allowed) ||
334 (check_ipv6_listed (sctx->v6_allowed, &i6->sin6_addr))) &&
335 ((NULL == sctx->v6_denied) ||
336 (! check_ipv6_listed (sctx->v6_denied, &i6->sin6_addr)));
337 break;
338
339 case AF_UNIX:
340 ret = GNUNET_OK; /* controlled using file-system ACL now */
341 break;
342
343 default:
344 LOG (GNUNET_ERROR_TYPE_WARNING,
345 _ ("Unknown address family %d\n"),
346 addr->sa_family);
347 return GNUNET_SYSERR;
348 }
349 if (GNUNET_OK != ret)
350 {
351 LOG (GNUNET_ERROR_TYPE_WARNING,
352 _ ("Access from `%s' denied to service `%s'\n"),
353 GNUNET_a2s (addr, addrlen),
354 sctx->service_name);
355 }
356 return ret;
357}
358
359
360/**
361 * Get the name of the file where we will
362 * write the PID of the service.
363 *
364 * @param sctx service context
365 * @return name of the file for the process ID
366 */
367static char *
368get_pid_file_name (struct LEGACY_SERVICE_Context *sctx)
369{
370 char *pif;
371
372 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (sctx->cfg,
373 sctx->service_name,
374 "PIDFILE",
375 &pif))
376 return NULL;
377 return pif;
378}
379
380
381/**
382 * Parse an IPv4 access control list.
383 *
384 * @param ret location where to write the ACL (set)
385 * @param sctx service context to use to get the configuration
386 * @param option name of the ACL option to parse
387 * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including
388 * no ACL configured)
389 */
390static int
391process_acl4 (struct GNUNET_STRINGS_IPv4NetworkPolicy **ret,
392 struct LEGACY_SERVICE_Context *sctx,
393 const char *option)
394{
395 char *opt;
396
397 if (! GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, option))
398 {
399 *ret = NULL;
400 return GNUNET_OK;
401 }
402 GNUNET_break (GNUNET_OK ==
403 GNUNET_CONFIGURATION_get_value_string (sctx->cfg,
404 sctx->service_name,
405 option,
406 &opt));
407 if (NULL == (*ret = GNUNET_STRINGS_parse_ipv4_policy (opt)))
408 {
409 LOG (GNUNET_ERROR_TYPE_WARNING,
410 _ ("Could not parse IPv4 network specification `%s' for `%s:%s'\n"),
411 opt,
412 sctx->service_name,
413 option);
414 GNUNET_free (opt);
415 return GNUNET_SYSERR;
416 }
417 GNUNET_free (opt);
418 return GNUNET_OK;
419}
420
421
422/**
423 * Parse an IPv6 access control list.
424 *
425 * @param ret location where to write the ACL (set)
426 * @param sctx service context to use to get the configuration
427 * @param option name of the ACL option to parse
428 * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including
429 * no ACL configured)
430 */
431static int
432process_acl6 (struct GNUNET_STRINGS_IPv6NetworkPolicy **ret,
433 struct LEGACY_SERVICE_Context *sctx,
434 const char *option)
435{
436 char *opt;
437
438 if (! GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, option))
439 {
440 *ret = NULL;
441 return GNUNET_OK;
442 }
443 GNUNET_break (GNUNET_OK ==
444 GNUNET_CONFIGURATION_get_value_string (sctx->cfg,
445 sctx->service_name,
446 option,
447 &opt));
448 if (NULL == (*ret = GNUNET_STRINGS_parse_ipv6_policy (opt)))
449 {
450 LOG (GNUNET_ERROR_TYPE_WARNING,
451 _ ("Could not parse IPv6 network specification `%s' for `%s:%s'\n"),
452 opt,
453 sctx->service_name,
454 option);
455 GNUNET_free (opt);
456 return GNUNET_SYSERR;
457 }
458 GNUNET_free (opt);
459 return GNUNET_OK;
460}
461
462
463/**
464 * Add the given UNIX domain path as an address to the
465 * list (as the first entry).
466 *
467 * @param saddrs array to update
468 * @param saddrlens where to store the address length
469 * @param unixpath path to add
470 * @param abstract #GNUNET_YES to add an abstract UNIX domain socket. This
471 * parameter is ignore on systems other than LINUX
472 */
473static void
474add_unixpath (struct sockaddr **saddrs,
475 socklen_t *saddrlens,
476 const char *unixpath,
477 int abstract)
478{
479#ifdef AF_UNIX
480 struct sockaddr_un *un;
481
482 un = GNUNET_new (struct sockaddr_un);
483 un->sun_family = AF_UNIX;
484 GNUNET_strlcpy (un->sun_path, unixpath, sizeof(un->sun_path));
485#ifdef __linux__
486 if (GNUNET_YES == abstract)
487 un->sun_path[0] = '\0';
488#endif
489#if HAVE_SOCKADDR_UN_SUN_LEN
490 un->sun_len = (u_char) sizeof(struct sockaddr_un);
491#endif
492 *saddrs = (struct sockaddr *) un;
493 *saddrlens = sizeof(struct sockaddr_un);
494#else
495 /* this function should never be called
496 * unless AF_UNIX is defined! */
497 GNUNET_assert (0);
498#endif
499}
500
501
502/**
503 * Get the list of addresses that a server for the given service
504 * should bind to.
505 *
506 * @param service_name name of the service
507 * @param cfg configuration (which specifies the addresses)
508 * @param addrs set (call by reference) to an array of pointers to the
509 * addresses the server should bind to and listen on; the
510 * array will be NULL-terminated (on success)
511 * @param addr_lens set (call by reference) to an array of the lengths
512 * of the respective `struct sockaddr` struct in the @a addrs
513 * array (on success)
514 * @return number of addresses found on success,
515 * #GNUNET_SYSERR if the configuration
516 * did not specify reasonable finding information or
517 * if it specified a hostname that could not be resolved;
518 * #GNUNET_NO if the number of addresses configured is
519 * zero (in this case, `*addrs` and `*addr_lens` will be
520 * set to NULL).
521 */
522int
523LEGACY_SERVICE_get_server_addresses (
524 const char *service_name,
525 const struct GNUNET_CONFIGURATION_Handle *cfg,
526 struct sockaddr ***addrs,
527 socklen_t **addr_lens)
528{
529 int disablev6;
530 struct GNUNET_NETWORK_Handle *desc;
531 unsigned long long port;
532 char *unixpath;
533 struct addrinfo hints;
534 struct addrinfo *res;
535 struct addrinfo *pos;
536 struct addrinfo *next;
537 unsigned int i;
538 int resi;
539 int ret;
540 int abstract;
541 struct sockaddr **saddrs;
542 socklen_t *saddrlens;
543 char *hostname;
544
545 *addrs = NULL;
546 *addr_lens = NULL;
547 desc = NULL;
548 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "DISABLEV6"))
549 {
550 if (GNUNET_SYSERR ==
551 (disablev6 = GNUNET_CONFIGURATION_get_value_yesno (cfg,
552 service_name,
553 "DISABLEV6")))
554 return GNUNET_SYSERR;
555 }
556 else
557 disablev6 = GNUNET_NO;
558
559 if (! disablev6)
560 {
561 /* probe IPv6 support */
562 desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
563 if (NULL == desc)
564 {
565 if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
566 (EACCES == errno))
567 {
568 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
569 return GNUNET_SYSERR;
570 }
571 LOG (GNUNET_ERROR_TYPE_INFO,
572 _ (
573 "Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"),
574 service_name,
575 strerror (errno));
576 disablev6 = GNUNET_YES;
577 }
578 else
579 {
580 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
581 desc = NULL;
582 }
583 }
584
585 port = 0;
586 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT"))
587 {
588 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg,
589 service_name,
590 "PORT",
591 &port))
592 {
593 LOG (GNUNET_ERROR_TYPE_ERROR,
594 _ ("Require valid port number for service `%s' in configuration!\n"),
595 service_name);
596 }
597 if (port > 65535)
598 {
599 LOG (GNUNET_ERROR_TYPE_ERROR,
600 _ ("Require valid port number for service `%s' in configuration!\n"),
601 service_name);
602 return GNUNET_SYSERR;
603 }
604 }
605
606 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "BINDTO"))
607 {
608 GNUNET_break (GNUNET_OK ==
609 GNUNET_CONFIGURATION_get_value_string (cfg,
610 service_name,
611 "BINDTO",
612 &hostname));
613 }
614 else
615 hostname = NULL;
616
617 unixpath = NULL;
618 abstract = GNUNET_NO;
619#ifdef AF_UNIX
620 if ((GNUNET_YES ==
621 GNUNET_CONFIGURATION_have_value (cfg, service_name, "UNIXPATH")) &&
622 (GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (cfg,
623 service_name,
624 "UNIXPATH",
625 &unixpath)) &&
626 (0 < strlen (unixpath)))
627 {
628 /* probe UNIX support */
629 struct sockaddr_un s_un;
630
631 if (strlen (unixpath) >= sizeof(s_un.sun_path))
632 {
633 LOG (GNUNET_ERROR_TYPE_WARNING,
634 _ ("UNIXPATH `%s' too long, maximum length is %llu\n"),
635 unixpath,
636 (unsigned long long) sizeof(s_un.sun_path));
637 unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
638 LOG (GNUNET_ERROR_TYPE_INFO, _ ("Using `%s' instead\n"), unixpath);
639 }
640#ifdef __linux__
641 abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg,
642 "TESTING",
643 "USE_ABSTRACT_SOCKETS");
644 if (GNUNET_SYSERR == abstract)
645 abstract = GNUNET_NO;
646#endif
647 if ((GNUNET_YES != abstract) &&
648 (GNUNET_OK != GNUNET_DISK_directory_create_for_file (unixpath)))
649 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "mkdir", unixpath);
650 }
651 if (NULL != unixpath)
652 {
653 desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
654 if (NULL == desc)
655 {
656 if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
657 (EACCES == errno))
658 {
659 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
660 GNUNET_free (hostname);
661 GNUNET_free (unixpath);
662 return GNUNET_SYSERR;
663 }
664 LOG (GNUNET_ERROR_TYPE_INFO,
665 _ (
666 "Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"),
667 service_name,
668 strerror (errno));
669 GNUNET_free (unixpath);
670 unixpath = NULL;
671 }
672 else
673 {
674 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
675 desc = NULL;
676 }
677 }
678#endif
679
680 if ((0 == port) && (NULL == unixpath))
681 {
682 LOG (GNUNET_ERROR_TYPE_ERROR,
683 _ (
684 "Have neither PORT nor UNIXPATH for service `%s', but one is required\n"),
685 service_name);
686 GNUNET_free (hostname);
687 return GNUNET_SYSERR;
688 }
689 if (0 == port)
690 {
691 saddrs = GNUNET_malloc (2 * sizeof(struct sockaddr *));
692 saddrlens = GNUNET_malloc (2 * sizeof(socklen_t));
693 add_unixpath (saddrs, saddrlens, unixpath, abstract);
694 GNUNET_free (unixpath);
695 GNUNET_free (hostname);
696 *addrs = saddrs;
697 *addr_lens = saddrlens;
698 return 1;
699 }
700
701 if (NULL != hostname)
702 {
703 LOG (GNUNET_ERROR_TYPE_DEBUG,
704 "Resolving `%s' since that is where `%s' will bind to.\n",
705 hostname,
706 service_name);
707 memset (&hints, 0, sizeof(struct addrinfo));
708 if (disablev6)
709 hints.ai_family = AF_INET;
710 hints.ai_protocol = IPPROTO_TCP;
711 if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
712 (NULL == res))
713 {
714 LOG (GNUNET_ERROR_TYPE_ERROR,
715 _ ("Failed to resolve `%s': %s\n"),
716 hostname,
717 gai_strerror (ret));
718 GNUNET_free (hostname);
719 GNUNET_free (unixpath);
720 return GNUNET_SYSERR;
721 }
722 next = res;
723 i = 0;
724 while (NULL != (pos = next))
725 {
726 next = pos->ai_next;
727 if ((disablev6) && (pos->ai_family == AF_INET6))
728 continue;
729 i++;
730 }
731 if (0 == i)
732 {
733 LOG (GNUNET_ERROR_TYPE_ERROR,
734 _ ("Failed to find %saddress for `%s'.\n"),
735 disablev6 ? "IPv4 " : "",
736 hostname);
737 freeaddrinfo (res);
738 GNUNET_free (hostname);
739 GNUNET_free (unixpath);
740 return GNUNET_SYSERR;
741 }
742 resi = i;
743 if (NULL != unixpath)
744 resi++;
745 saddrs = GNUNET_malloc ((resi + 1) * sizeof(struct sockaddr *));
746 saddrlens = GNUNET_malloc ((resi + 1) * sizeof(socklen_t));
747 i = 0;
748 if (NULL != unixpath)
749 {
750 add_unixpath (saddrs, saddrlens, unixpath, abstract);
751 i++;
752 }
753 next = res;
754 while (NULL != (pos = next))
755 {
756 next = pos->ai_next;
757 if ((disablev6) && (AF_INET6 == pos->ai_family))
758 continue;
759 if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol))
760 continue; /* not TCP */
761 if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype))
762 continue; /* huh? */
763 LOG (GNUNET_ERROR_TYPE_DEBUG,
764 "Service `%s' will bind to `%s'\n",
765 service_name,
766 GNUNET_a2s (pos->ai_addr, pos->ai_addrlen));
767 if (AF_INET == pos->ai_family)
768 {
769 GNUNET_assert (sizeof(struct sockaddr_in) == pos->ai_addrlen);
770 saddrlens[i] = pos->ai_addrlen;
771 saddrs[i] = GNUNET_malloc (saddrlens[i]);
772 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
773 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
774 }
775 else
776 {
777 GNUNET_assert (AF_INET6 == pos->ai_family);
778 GNUNET_assert (sizeof(struct sockaddr_in6) == pos->ai_addrlen);
779 saddrlens[i] = pos->ai_addrlen;
780 saddrs[i] = GNUNET_malloc (saddrlens[i]);
781 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
782 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
783 }
784 i++;
785 }
786 GNUNET_free (hostname);
787 freeaddrinfo (res);
788 resi = i;
789 }
790 else
791 {
792 /* will bind against everything, just set port */
793 if (disablev6)
794 {
795 /* V4-only */
796 resi = 1;
797 if (NULL != unixpath)
798 resi++;
799 i = 0;
800 saddrs = GNUNET_malloc ((resi + 1) * sizeof(struct sockaddr *));
801 saddrlens = GNUNET_malloc ((resi + 1) * sizeof(socklen_t));
802 if (NULL != unixpath)
803 {
804 add_unixpath (saddrs, saddrlens, unixpath, abstract);
805 i++;
806 }
807 saddrlens[i] = sizeof(struct sockaddr_in);
808 saddrs[i] = GNUNET_malloc (saddrlens[i]);
809#if HAVE_SOCKADDR_IN_SIN_LEN
810 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
811#endif
812 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
813 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
814 }
815 else
816 {
817 /* dual stack */
818 resi = 2;
819 if (NULL != unixpath)
820 resi++;
821 saddrs = GNUNET_malloc ((resi + 1) * sizeof(struct sockaddr *));
822 saddrlens = GNUNET_malloc ((resi + 1) * sizeof(socklen_t));
823 i = 0;
824 if (NULL != unixpath)
825 {
826 add_unixpath (saddrs, saddrlens, unixpath, abstract);
827 i++;
828 }
829 saddrlens[i] = sizeof(struct sockaddr_in6);
830 saddrs[i] = GNUNET_malloc (saddrlens[i]);
831#if HAVE_SOCKADDR_IN_SIN_LEN
832 ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
833#endif
834 ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
835 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
836 i++;
837 saddrlens[i] = sizeof(struct sockaddr_in);
838 saddrs[i] = GNUNET_malloc (saddrlens[i]);
839#if HAVE_SOCKADDR_IN_SIN_LEN
840 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
841#endif
842 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
843 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
844 }
845 }
846 GNUNET_free (unixpath);
847 *addrs = saddrs;
848 *addr_lens = saddrlens;
849 return resi;
850}
851
852
853/**
854 * Setup addr, addrlen, idle_timeout
855 * based on configuration!
856 *
857 * Configuration may specify:
858 * - PORT (where to bind to for TCP)
859 * - UNIXPATH (where to bind to for UNIX domain sockets)
860 * - TIMEOUT (after how many ms does an inactive service timeout);
861 * - DISABLEV6 (disable support for IPv6, otherwise we use dual-stack)
862 * - BINDTO (hostname or IP address to bind to, otherwise we take everything)
863 * - ACCEPT_FROM (only allow connections from specified IPv4 subnets)
864 * - ACCEPT_FROM6 (only allow connections from specified IPv6 subnets)
865 * - REJECT_FROM (disallow allow connections from specified IPv4 subnets)
866 * - REJECT_FROM6 (disallow allow connections from specified IPv6 subnets)
867 *
868 * @param sctx service context to initialize
869 * @return #GNUNET_OK if configuration succeeded
870 */
871static int
872setup_service (struct LEGACY_SERVICE_Context *sctx)
873{
874 struct GNUNET_TIME_Relative idleout;
875 int tolerant;
876 const char *nfds;
877 unsigned int cnt;
878 int flags;
879
880 if (GNUNET_CONFIGURATION_have_value (sctx->cfg,
881 sctx->service_name,
882 "TIMEOUT"))
883 {
884 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (sctx->cfg,
885 sctx->service_name,
886 "TIMEOUT",
887 &idleout))
888 {
889 LOG (GNUNET_ERROR_TYPE_ERROR,
890 _ ("Specified value for `%s' of service `%s' is invalid\n"),
891 "TIMEOUT",
892 sctx->service_name);
893 return GNUNET_SYSERR;
894 }
895 sctx->timeout = idleout;
896 }
897 else
898 sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
899
900 if (GNUNET_CONFIGURATION_have_value (sctx->cfg,
901 sctx->service_name,
902 "TOLERANT"))
903 {
904 if (GNUNET_SYSERR ==
905 (tolerant = GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg,
906 sctx->service_name,
907 "TOLERANT")))
908 {
909 LOG (GNUNET_ERROR_TYPE_ERROR,
910 _ ("Specified value for `%s' of service `%s' is invalid\n"),
911 "TOLERANT",
912 sctx->service_name);
913 return GNUNET_SYSERR;
914 }
915 }
916 else
917 tolerant = GNUNET_NO;
918
919 errno = 0;
920 if ((NULL != (nfds = getenv ("LISTEN_FDS"))) &&
921 (1 == sscanf (nfds, "%u", &cnt)) && (cnt > 0) && (cnt < FD_SETSIZE) &&
922 (cnt + 4 < FD_SETSIZE))
923 {
924 sctx->lsocks =
925 GNUNET_malloc (sizeof(struct GNUNET_NETWORK_Handle *) * (cnt + 1));
926 while (0 < cnt--)
927 {
928 flags = fcntl (3 + cnt, F_GETFD);
929 if ((flags < 0) || (0 != (flags & FD_CLOEXEC)) ||
930 (NULL ==
931 (sctx->lsocks[cnt] = GNUNET_NETWORK_socket_box_native (3 + cnt))))
932 {
933 LOG (GNUNET_ERROR_TYPE_ERROR,
934 _ (
935 "Could not access pre-bound socket %u, will try to bind myself\n"),
936 (unsigned int) 3 + cnt);
937 cnt++;
938 while (sctx->lsocks[cnt] != NULL)
939 GNUNET_break (0 == GNUNET_NETWORK_socket_close (sctx->lsocks[cnt++]));
940 GNUNET_free (sctx->lsocks);
941 sctx->lsocks = NULL;
942 break;
943 }
944 }
945 unsetenv ("LISTEN_FDS");
946 }
947
948 if ((NULL == sctx->lsocks) &&
949 (GNUNET_SYSERR == LEGACY_SERVICE_get_server_addresses (sctx->service_name,
950 sctx->cfg,
951 &sctx->addrs,
952 &sctx->addrlens)))
953 return GNUNET_SYSERR;
954 sctx->require_found = tolerant ? GNUNET_NO : GNUNET_YES;
955 sctx->match_uid = GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg,
956 sctx->service_name,
957 "UNIX_MATCH_UID");
958 sctx->match_gid = GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg,
959 sctx->service_name,
960 "UNIX_MATCH_GID");
961 process_acl4 (&sctx->v4_denied, sctx, "REJECT_FROM");
962 process_acl4 (&sctx->v4_allowed, sctx, "ACCEPT_FROM");
963 process_acl6 (&sctx->v6_denied, sctx, "REJECT_FROM6");
964 process_acl6 (&sctx->v6_allowed, sctx, "ACCEPT_FROM6");
965
966 return GNUNET_OK;
967}
968
969
970/**
971 * Get the name of the user that'll be used
972 * to provide the service.
973 *
974 * @param sctx service context
975 * @return value of the 'USERNAME' option
976 */
977static char *
978get_user_name (struct LEGACY_SERVICE_Context *sctx)
979{
980 char *un;
981
982 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (sctx->cfg,
983 sctx->service_name,
984 "USERNAME",
985 &un))
986 return NULL;
987 return un;
988}
989
990
991/**
992 * Write PID file.
993 *
994 * @param sctx service context
995 * @param pid PID to write (should be equal to 'getpid()'
996 * @return #GNUNET_OK on success (including no work to be done)
997 */
998static int
999write_pid_file (struct LEGACY_SERVICE_Context *sctx, pid_t pid)
1000{
1001 FILE *pidfd;
1002 char *pif;
1003 char *user;
1004 char *rdir;
1005 int len;
1006
1007 if (NULL == (pif = get_pid_file_name (sctx)))
1008 return GNUNET_OK; /* no file desired */
1009 user = get_user_name (sctx);
1010 rdir = GNUNET_strdup (pif);
1011 len = strlen (rdir);
1012 while ((len > 0) && (rdir[len] != DIR_SEPARATOR))
1013 len--;
1014 rdir[len] = '\0';
1015 if (0 != access (rdir, F_OK))
1016 {
1017 /* we get to create a directory -- and claim it
1018 * as ours! */
1019 (void) GNUNET_DISK_directory_create (rdir);
1020 if ((NULL != user) && (0 < strlen (user)))
1021 GNUNET_DISK_file_change_owner (rdir, user);
1022 }
1023 if (0 != access (rdir, W_OK | X_OK))
1024 {
1025 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "access", rdir);
1026 GNUNET_free (rdir);
1027 GNUNET_free (user);
1028 GNUNET_free (pif);
1029 return GNUNET_SYSERR;
1030 }
1031 GNUNET_free (rdir);
1032 pidfd = fopen (pif, "w");
1033 if (NULL == pidfd)
1034 {
1035 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "fopen", pif);
1036 GNUNET_free (pif);
1037 GNUNET_free (user);
1038 return GNUNET_SYSERR;
1039 }
1040 if (0 > fprintf (pidfd, "%u", pid))
1041 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fprintf", pif);
1042 GNUNET_break (0 == fclose (pidfd));
1043 if ((NULL != user) && (0 < strlen (user)))
1044 GNUNET_DISK_file_change_owner (pif, user);
1045 GNUNET_free (user);
1046 GNUNET_free (pif);
1047 return GNUNET_OK;
1048}
1049
1050
1051/**
1052 * Task run during shutdown. Stops the server/service.
1053 *
1054 * @param cls the `struct LEGACY_SERVICE_Context`
1055 */
1056static void
1057shutdown_task (void *cls)
1058{
1059 struct LEGACY_SERVICE_Context *service = cls;
1060 struct GNUNET_SERVER_Handle *server = service->server;
1061
1062 service->shutdown_task = NULL;
1063 if (0 != (service->options & LEGACY_SERVICE_OPTION_SOFT_SHUTDOWN))
1064 GNUNET_SERVER_stop_listening (server);
1065 else
1066 GNUNET_SERVER_destroy (server);
1067}
1068
1069
1070/**
1071 * Initial task for the service.
1072 *
1073 * @param cls service context
1074 */
1075static void
1076service_task (void *cls)
1077{
1078 struct LEGACY_SERVICE_Context *sctx = cls;
1079 unsigned int i;
1080
1081 GNUNET_RESOLVER_connect (sctx->cfg);
1082 if (NULL != sctx->lsocks)
1083 sctx->server = GNUNET_SERVER_create_with_sockets (&check_access,
1084 sctx,
1085 sctx->lsocks,
1086 sctx->timeout,
1087 sctx->require_found);
1088 else
1089 sctx->server = GNUNET_SERVER_create (&check_access,
1090 sctx,
1091 sctx->addrs,
1092 sctx->addrlens,
1093 sctx->timeout,
1094 sctx->require_found);
1095 if (NULL == sctx->server)
1096 {
1097 if (NULL != sctx->addrs)
1098 for (i = 0; NULL != sctx->addrs[i]; i++)
1099 LOG (GNUNET_ERROR_TYPE_INFO,
1100 _ ("Failed to start `%s' at `%s'\n"),
1101 sctx->service_name,
1102 GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i]));
1103 sctx->ret = GNUNET_SYSERR;
1104 return;
1105 }
1106
1107 if (NULL != sctx->addrs)
1108 for (i = 0; NULL != sctx->addrs[i]; i++)
1109 if ((AF_UNIX == sctx->addrs[i]->sa_family) &&
1110 ('\0' != ((const struct sockaddr_un *) sctx->addrs[i])->sun_path[0]))
1111 GNUNET_DISK_fix_permissions (((const struct sockaddr_un *)
1112 sctx->addrs[i])
1113 ->sun_path,
1114 sctx->match_uid,
1115 sctx->match_gid);
1116
1117 if (0 == (sctx->options & LEGACY_SERVICE_OPTION_MANUAL_SHUTDOWN))
1118 {
1119 /* install a task that will kill the server
1120 * process if the scheduler ever gets a shutdown signal */
1121 sctx->shutdown_task = GNUNET_SCHEDULER_add_shutdown (&shutdown_task, sctx);
1122 }
1123 sctx->my_handlers = GNUNET_malloc (sizeof(defhandlers));
1124 GNUNET_memcpy (sctx->my_handlers, defhandlers, sizeof(defhandlers));
1125 i = 0;
1126 while (NULL != sctx->my_handlers[i].callback)
1127 sctx->my_handlers[i++].callback_cls = sctx;
1128 GNUNET_SERVER_add_handlers (sctx->server, sctx->my_handlers);
1129 if (-1 != sctx->ready_confirm_fd)
1130 {
1131 GNUNET_break (1 == write (sctx->ready_confirm_fd, ".", 1));
1132 GNUNET_break (0 == close (sctx->ready_confirm_fd));
1133 sctx->ready_confirm_fd = -1;
1134 write_pid_file (sctx, getpid ());
1135 }
1136 if (NULL != sctx->addrs)
1137 {
1138 i = 0;
1139 while (NULL != sctx->addrs[i])
1140 {
1141 LOG (GNUNET_ERROR_TYPE_INFO,
1142 _ ("Service `%s' runs at %s\n"),
1143 sctx->service_name,
1144 GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i]));
1145 i++;
1146 }
1147 }
1148 sctx->task (sctx->task_cls, sctx->server, sctx->cfg);
1149}
1150
1151
1152/**
1153 * Detach from terminal.
1154 *
1155 * @param sctx service context
1156 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1157 */
1158static int
1159detach_terminal (struct LEGACY_SERVICE_Context *sctx)
1160{
1161 pid_t pid;
1162 int nullfd;
1163 int filedes[2];
1164
1165 if (0 != pipe (filedes))
1166 {
1167 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "pipe");
1168 return GNUNET_SYSERR;
1169 }
1170 pid = fork ();
1171 if (pid < 0)
1172 {
1173 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fork");
1174 return GNUNET_SYSERR;
1175 }
1176 if (0 != pid)
1177 {
1178 /* Parent */
1179 char c;
1180
1181 GNUNET_break (0 == close (filedes[1]));
1182 c = 'X';
1183 if (1 != read (filedes[0], &c, sizeof(char)))
1184 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "read");
1185 fflush (stdout);
1186 switch (c)
1187 {
1188 case '.':
1189 exit (0);
1190
1191 case 'I':
1192 LOG (GNUNET_ERROR_TYPE_INFO,
1193 _ ("Service process failed to initialize\n"));
1194 break;
1195
1196 case 'S':
1197 LOG (GNUNET_ERROR_TYPE_INFO,
1198 _ ("Service process could not initialize server function\n"));
1199 break;
1200
1201 case 'X':
1202 LOG (GNUNET_ERROR_TYPE_INFO,
1203 _ ("Service process failed to report status\n"));
1204 break;
1205 }
1206 exit (1); /* child reported error */
1207 }
1208 GNUNET_break (0 == close (0));
1209 GNUNET_break (0 == close (1));
1210 GNUNET_break (0 == close (filedes[0]));
1211 nullfd = open ("/dev/null", O_RDWR | O_APPEND);
1212 if (nullfd < 0)
1213 return GNUNET_SYSERR;
1214 /* set stdin/stdout to /dev/null */
1215 if ((dup2 (nullfd, 0) < 0) || (dup2 (nullfd, 1) < 0))
1216 {
1217 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2");
1218 (void) close (nullfd);
1219 return GNUNET_SYSERR;
1220 }
1221 (void) close (nullfd);
1222 /* Detach from controlling terminal */
1223 pid = setsid ();
1224 if (-1 == pid)
1225 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "setsid");
1226 sctx->ready_confirm_fd = filedes[1];
1227
1228 return GNUNET_OK;
1229}
1230
1231
1232/**
1233 * Set user ID.
1234 *
1235 * @param sctx service context
1236 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1237 */
1238static int
1239set_user_id (struct LEGACY_SERVICE_Context *sctx)
1240{
1241 char *user;
1242
1243 if (NULL == (user = get_user_name (sctx)))
1244 return GNUNET_OK; /* keep */
1245
1246 struct passwd *pws;
1247
1248 errno = 0;
1249 pws = getpwnam (user);
1250 if (NULL == pws)
1251 {
1252 LOG (GNUNET_ERROR_TYPE_ERROR,
1253 _ ("Cannot obtain information about user `%s': %s\n"),
1254 user,
1255 errno == 0 ? _ ("No such user") : strerror (errno));
1256 GNUNET_free (user);
1257 return GNUNET_SYSERR;
1258 }
1259 if ((0 != setgid (pws->pw_gid)) || (0 != setegid (pws->pw_gid)) ||
1260#if HAVE_INITGROUPS
1261 (0 != initgroups (user, pws->pw_gid)) ||
1262#endif
1263 (0 != setuid (pws->pw_uid)) || (0 != seteuid (pws->pw_uid)))
1264 {
1265 if ((0 != setregid (pws->pw_gid, pws->pw_gid)) ||
1266 (0 != setreuid (pws->pw_uid, pws->pw_uid)))
1267 {
1268 LOG (GNUNET_ERROR_TYPE_ERROR,
1269 _ ("Cannot change user/group to `%s': %s\n"),
1270 user,
1271 strerror (errno));
1272 GNUNET_free (user);
1273 return GNUNET_SYSERR;
1274 }
1275 }
1276
1277 GNUNET_free (user);
1278 return GNUNET_OK;
1279}
1280
1281
1282/**
1283 * Delete the PID file that was created by our parent.
1284 *
1285 * @param sctx service context
1286 */
1287static void
1288pid_file_delete (struct LEGACY_SERVICE_Context *sctx)
1289{
1290 char *pif = get_pid_file_name (sctx);
1291
1292 if (NULL == pif)
1293 return; /* no PID file */
1294 if (0 != unlink (pif))
1295 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", pif);
1296 GNUNET_free (pif);
1297}
1298
1299
1300/**
1301 * Run a standard GNUnet service startup sequence (initialize loggers
1302 * and configuration, parse options).
1303 *
1304 * @param argc number of command line arguments
1305 * @param argv command line arguments
1306 * @param service_name our service name
1307 * @param options service options
1308 * @param task main task of the service
1309 * @param task_cls closure for @a task
1310 * @return #GNUNET_SYSERR on error, #GNUNET_OK
1311 * if we shutdown nicely
1312 */
1313int
1314LEGACY_SERVICE_run (int argc,
1315 char *const *argv,
1316 const char *service_name,
1317 enum LEGACY_SERVICE_Options options,
1318 LEGACY_SERVICE_Main task,
1319 void *task_cls)
1320{
1321#define HANDLE_ERROR \
1322 do \
1323 { \
1324 GNUNET_break (0); \
1325 goto shutdown; \
1326 } while (0)
1327
1328 int err;
1329 int ret;
1330 char *cfg_fn;
1331 char *opt_cfg_fn;
1332 char *loglev;
1333 char *logfile;
1334 int do_daemonize;
1335 unsigned int i;
1336 unsigned long long skew_offset;
1337 unsigned long long skew_variance;
1338 long long clock_offset;
1339 struct LEGACY_SERVICE_Context sctx;
1340 struct GNUNET_CONFIGURATION_Handle *cfg;
1341 const char *xdg;
1342
1343 struct GNUNET_GETOPT_CommandLineOption service_options[] =
1344 { GNUNET_GETOPT_option_cfgfile (&opt_cfg_fn),
1345 GNUNET_GETOPT_option_flag ('d',
1346 "daemonize",
1347 gettext_noop (
1348 "do daemonize (detach from terminal)"),
1349 &do_daemonize),
1350 GNUNET_GETOPT_option_help (NULL),
1351 GNUNET_GETOPT_option_loglevel (&loglev),
1352 GNUNET_GETOPT_option_logfile (&logfile),
1353 GNUNET_GETOPT_option_version (PACKAGE_VERSION " " VCS_VERSION),
1354 GNUNET_GETOPT_OPTION_END };
1355 err = 1;
1356 do_daemonize = 0;
1357 logfile = NULL;
1358 loglev = NULL;
1359 opt_cfg_fn = NULL;
1360 xdg = getenv ("XDG_CONFIG_HOME");
1361 if (NULL != xdg)
1362 GNUNET_asprintf (&cfg_fn,
1363 "%s%s%s",
1364 xdg,
1365 DIR_SEPARATOR_STR,
1366 GNUNET_OS_project_data_get ()->config_file);
1367 else
1368 cfg_fn = GNUNET_strdup (GNUNET_OS_project_data_get ()->user_config_file);
1369 memset (&sctx, 0, sizeof(sctx));
1370 sctx.options = options;
1371 sctx.ready_confirm_fd = -1;
1372 sctx.ret = GNUNET_OK;
1373 sctx.timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1374 sctx.task = task;
1375 sctx.task_cls = task_cls;
1376 sctx.service_name = service_name;
1377 sctx.cfg = cfg = GNUNET_CONFIGURATION_create ();
1378
1379 /* setup subsystems */
1380 ret = GNUNET_GETOPT_run (service_name, service_options, argc, argv);
1381 if (GNUNET_SYSERR == ret)
1382 goto shutdown;
1383 if (GNUNET_NO == ret)
1384 {
1385 err = 0;
1386 goto shutdown;
1387 }
1388 if (GNUNET_OK != GNUNET_log_setup (service_name, loglev, logfile))
1389 HANDLE_ERROR;
1390 if (NULL == opt_cfg_fn)
1391 opt_cfg_fn = GNUNET_strdup (cfg_fn);
1392 if (GNUNET_YES == GNUNET_DISK_file_test (opt_cfg_fn))
1393 {
1394 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, opt_cfg_fn))
1395 {
1396 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1397 _ ("Malformed configuration file `%s', exit ...\n"),
1398 opt_cfg_fn);
1399 goto shutdown;
1400 }
1401 }
1402 else
1403 {
1404 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, NULL))
1405 {
1406 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1407 _ ("Malformed configuration, exit ...\n"));
1408 goto shutdown;
1409 }
1410 if (0 != strcmp (opt_cfg_fn, cfg_fn))
1411 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1412 _ ("Could not access configuration file `%s'\n"),
1413 opt_cfg_fn);
1414 }
1415 if (GNUNET_OK != setup_service (&sctx))
1416 goto shutdown;
1417 if ((1 == do_daemonize) && (GNUNET_OK != detach_terminal (&sctx)))
1418 HANDLE_ERROR;
1419 if (GNUNET_OK != set_user_id (&sctx))
1420 goto shutdown;
1421 LOG (GNUNET_ERROR_TYPE_DEBUG,
1422 "Service `%s' runs with configuration from `%s'\n",
1423 service_name,
1424 opt_cfg_fn);
1425 if ((GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (sctx.cfg,
1426 "TESTING",
1427 "SKEW_OFFSET",
1428 &skew_offset)) &&
1429 (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (sctx.cfg,
1430 "TESTING",
1431 "SKEW_VARIANCE",
1432 &skew_variance)))
1433 {
1434 clock_offset = skew_offset - skew_variance;
1435 GNUNET_TIME_set_offset (clock_offset);
1436 LOG (GNUNET_ERROR_TYPE_DEBUG, "Skewing clock by %lld ms\n", clock_offset);
1437 }
1438 /* actually run service */
1439 err = 0;
1440 GNUNET_SCHEDULER_run (&service_task, &sctx);
1441 /* shutdown */
1442 if ((1 == do_daemonize) && (NULL != sctx.server))
1443 pid_file_delete (&sctx);
1444 GNUNET_free (sctx.my_handlers);
1445
1446shutdown:
1447 if (-1 != sctx.ready_confirm_fd)
1448 {
1449 if (1 != write (sctx.ready_confirm_fd, err ? "I" : "S", 1))
1450 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "write");
1451 GNUNET_break (0 == close (sctx.ready_confirm_fd));
1452 }
1453#if HAVE_MALLINFO2
1454 {
1455 char *counter;
1456
1457 if ((GNUNET_YES == GNUNET_CONFIGURATION_have_value (sctx.cfg,
1458 service_name,
1459 "GAUGER_HEAP")) &&
1460 (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (sctx.cfg,
1461 service_name,
1462 "GAUGER_HEAP",
1463 &counter)))
1464 {
1465 struct mallinfo2 mi;
1466
1467 mi = mallinfo2 ();
1468 GAUGER (service_name, counter, mi.usmblks, "blocks");
1469 GNUNET_free (counter);
1470 }
1471 }
1472#endif
1473 GNUNET_CONFIGURATION_destroy (cfg);
1474 i = 0;
1475 if (NULL != sctx.addrs)
1476 while (NULL != sctx.addrs[i])
1477 GNUNET_free_nz (sctx.addrs[i++]);
1478 GNUNET_free (sctx.addrs);
1479 GNUNET_free (sctx.addrlens);
1480 GNUNET_free (logfile);
1481 GNUNET_free (loglev);
1482 GNUNET_free (cfg_fn);
1483 GNUNET_free (opt_cfg_fn);
1484 GNUNET_free (sctx.v4_denied);
1485 GNUNET_free (sctx.v6_denied);
1486 GNUNET_free (sctx.v4_allowed);
1487 GNUNET_free (sctx.v6_allowed);
1488
1489 return err ? GNUNET_SYSERR : sctx.ret;
1490}
1491
1492
1493/**
1494 * Run a service startup sequence within an existing
1495 * initialized system.
1496 *
1497 * @param service_name our service name
1498 * @param cfg configuration to use
1499 * @param options service options
1500 * @return NULL on error, service handle
1501 */
1502struct LEGACY_SERVICE_Context *
1503LEGACY_SERVICE_start (const char *service_name,
1504 const struct GNUNET_CONFIGURATION_Handle *cfg,
1505 enum LEGACY_SERVICE_Options options)
1506{
1507 int i;
1508 struct LEGACY_SERVICE_Context *sctx;
1509
1510 sctx = GNUNET_new (struct LEGACY_SERVICE_Context);
1511 sctx->ready_confirm_fd = -1; /* no daemonizing */
1512 sctx->ret = GNUNET_OK;
1513 sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1514 sctx->service_name = service_name;
1515 sctx->cfg = cfg;
1516 sctx->options = options;
1517
1518 /* setup subsystems */
1519 if (GNUNET_OK != setup_service (sctx))
1520 {
1521 LEGACY_SERVICE_stop (sctx);
1522 return NULL;
1523 }
1524 if (NULL != sctx->lsocks)
1525 sctx->server = GNUNET_SERVER_create_with_sockets (&check_access,
1526 sctx,
1527 sctx->lsocks,
1528 sctx->timeout,
1529 sctx->require_found);
1530 else
1531 sctx->server = GNUNET_SERVER_create (&check_access,
1532 sctx,
1533 sctx->addrs,
1534 sctx->addrlens,
1535 sctx->timeout,
1536 sctx->require_found);
1537
1538 if (NULL == sctx->server)
1539 {
1540 LEGACY_SERVICE_stop (sctx);
1541 return NULL;
1542 }
1543
1544 if (NULL != sctx->addrs)
1545 for (i = 0; NULL != sctx->addrs[i]; i++)
1546 if ((AF_UNIX == sctx->addrs[i]->sa_family) &&
1547 ('\0' != ((const struct sockaddr_un *) sctx->addrs[i])->sun_path[0]))
1548 GNUNET_DISK_fix_permissions (((const struct sockaddr_un *)
1549 sctx->addrs[i])
1550 ->sun_path,
1551 sctx->match_uid,
1552 sctx->match_gid);
1553
1554 sctx->my_handlers = GNUNET_malloc (sizeof(defhandlers));
1555 GNUNET_memcpy (sctx->my_handlers, defhandlers, sizeof(defhandlers));
1556 i = 0;
1557 while ((sctx->my_handlers[i].callback != NULL))
1558 sctx->my_handlers[i++].callback_cls = sctx;
1559 GNUNET_SERVER_add_handlers (sctx->server, sctx->my_handlers);
1560 return sctx;
1561}
1562
1563
1564/**
1565 * Obtain the server used by a service. Note that the server must NOT
1566 * be destroyed by the caller.
1567 *
1568 * @param ctx the service context returned from the start function
1569 * @return handle to the server for this service, NULL if there is none
1570 */
1571struct GNUNET_SERVER_Handle *
1572LEGACY_SERVICE_get_server (struct LEGACY_SERVICE_Context *ctx)
1573{
1574 return ctx->server;
1575}
1576
1577
1578/**
1579 * Get the NULL-terminated array of listen sockets for this service.
1580 *
1581 * @param ctx service context to query
1582 * @return NULL if there are no listen sockets, otherwise NULL-terminated
1583 * array of listen sockets.
1584 */
1585struct GNUNET_NETWORK_Handle *const *
1586LEGACY_SERVICE_get_listen_sockets (struct LEGACY_SERVICE_Context *ctx)
1587{
1588 return ctx->lsocks;
1589}
1590
1591
1592/**
1593 * Stop a service that was started with "LEGACY_SERVICE_start".
1594 *
1595 * @param sctx the service context returned from the start function
1596 */
1597void
1598LEGACY_SERVICE_stop (struct LEGACY_SERVICE_Context *sctx)
1599{
1600 unsigned int i;
1601
1602#if HAVE_MALLINFO2
1603 {
1604 char *counter;
1605
1606 if ((GNUNET_YES == GNUNET_CONFIGURATION_have_value (sctx->cfg,
1607 sctx->service_name,
1608 "GAUGER_HEAP")) &&
1609 (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (sctx->cfg,
1610 sctx->service_name,
1611 "GAUGER_HEAP",
1612 &counter)))
1613 {
1614 struct mallinfo2 mi;
1615
1616 mi = mallinfo2 ();
1617 GAUGER (sctx->service_name, counter, mi.usmblks, "blocks");
1618 GNUNET_free (counter);
1619 }
1620 }
1621#endif
1622 if (NULL != sctx->shutdown_task)
1623 {
1624 GNUNET_SCHEDULER_cancel (sctx->shutdown_task);
1625 sctx->shutdown_task = NULL;
1626 }
1627 if (NULL != sctx->server)
1628 GNUNET_SERVER_destroy (sctx->server);
1629 GNUNET_free (sctx->my_handlers);
1630 if (NULL != sctx->addrs)
1631 {
1632 i = 0;
1633 while (NULL != sctx->addrs[i])
1634 GNUNET_free_nz (sctx->addrs[i++]);
1635 GNUNET_free (sctx->addrs);
1636 }
1637 GNUNET_free (sctx->addrlens);
1638 GNUNET_free (sctx->v4_denied);
1639 GNUNET_free (sctx->v6_denied);
1640 GNUNET_free (sctx->v4_allowed);
1641 GNUNET_free (sctx->v6_allowed);
1642 GNUNET_free (sctx);
1643}
1644
1645
1646/* end of service.c */
diff --git a/src/transport/test_http_common.c b/src/transport/test_http_common.c
deleted file mode 100644
index fe6e4faa3..000000000
--- a/src/transport/test_http_common.c
+++ /dev/null
@@ -1,266 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport/test_http_common.c
22 * @brief base test case for common http functionality
23 */
24#include "platform.h"
25#include "gnunet_transport_service.h"
26#include "transport-testing.h"
27#include "plugin_transport_http_common.h"
28
29
30static void
31clean (struct SplittedHTTPAddress *addr)
32{
33 if (NULL == addr)
34 return;
35 GNUNET_free (addr->host);
36 GNUNET_free (addr->path);
37 GNUNET_free (addr->protocol);
38 GNUNET_free (addr);
39}
40
41
42static int
43check (struct SplittedHTTPAddress *addr,
44 const char *protocol,
45 const char *host,
46 int port,
47 const char *path)
48{
49 if (NULL == addr)
50 return GNUNET_NO;
51 if (((NULL == addr->protocol) && (NULL != protocol)) ||
52 ((NULL != addr->protocol) && (NULL == protocol)))
53 {
54 GNUNET_break (0);
55 return GNUNET_NO;
56 }
57 else if ((NULL != addr->protocol) && (NULL != protocol))
58 {
59 if (0 != strcmp (addr->protocol, protocol))
60 {
61 GNUNET_break (0);
62 return GNUNET_NO;
63 }
64 }
65
66 if (((NULL == addr->host) && (NULL != host)) ||
67 ((NULL != addr->host) && (NULL == host)))
68 {
69 GNUNET_break (0);
70 return GNUNET_NO;
71 }
72 else if ((NULL != addr->host) && (NULL != host))
73 {
74 if (0 != strcmp (addr->host, host))
75 {
76 GNUNET_break (0);
77 return GNUNET_NO;
78 }
79 }
80
81 if (((NULL == addr->path) && (NULL != path)) ||
82 ((NULL != addr->path) && (NULL == path)))
83 {
84 GNUNET_break (0);
85 return GNUNET_NO;
86 }
87 else if ((NULL != addr->path) && (NULL != path))
88 {
89 if (0 != strcmp (addr->path, path))
90 {
91 GNUNET_break (0);
92 return GNUNET_NO;
93 }
94 }
95
96 if ((addr->port != port))
97 {
98 GNUNET_break (0);
99 return GNUNET_NO;
100 }
101 return GNUNET_OK;
102}
103
104
105static int
106check_pass (const char *src,
107 const char *protocol,
108 const char *host,
109 int port,
110 const char *path)
111{
112 struct SplittedHTTPAddress *spa;
113
114 spa = http_split_address (src);
115 if (NULL == spa)
116 {
117 GNUNET_break (0);
118 return GNUNET_SYSERR;
119 }
120 if (GNUNET_OK != check (spa, protocol, host, port, path))
121 {
122 clean (spa);
123 GNUNET_break (0);
124 return GNUNET_SYSERR;
125 }
126 clean (spa);
127 return GNUNET_OK;
128}
129
130
131static int
132check_fail (const char *src)
133{
134 struct SplittedHTTPAddress *spa;
135
136 spa = http_split_address (src);
137 if (NULL != spa)
138 {
139 GNUNET_break (0);
140 clean (spa);
141 return GNUNET_SYSERR;
142 }
143 return GNUNET_OK;
144}
145
146
147static void
148test_pass_hostname ()
149{
150 check_pass ("http://test.local", "http", "test.local", HTTP_DEFAULT_PORT, "");
151 check_pass ("http://test.local/", "http", "test.local", HTTP_DEFAULT_PORT,
152 "/");
153 check_pass ("http://test.local/path", "http", "test.local", HTTP_DEFAULT_PORT,
154 "/path");
155 check_pass ("http://test.local/path/", "http", "test.local",
156 HTTP_DEFAULT_PORT, "/path/");
157 check_pass ("http://test.local/path/more", "http", "test.local",
158 HTTP_DEFAULT_PORT, "/path/more");
159 check_pass ("http://test.local:81", "http", "test.local", 81, "");
160 check_pass ("http://test.local:81/", "http", "test.local", 81, "/");
161 check_pass ("http://test.local:81/path", "http", "test.local", 81, "/path");
162 check_pass ("http://test.local:81/path/", "http", "test.local", 81, "/path/");
163 check_pass ("http://test.local:81/path/more", "http", "test.local", 81,
164 "/path/more");
165}
166
167
168static void
169test_pass_ipv4 ()
170{
171 check_pass ("http://127.0.0.1", "http", "127.0.0.1", HTTP_DEFAULT_PORT, "");
172 check_pass ("http://127.0.0.1/", "http", "127.0.0.1", HTTP_DEFAULT_PORT, "/");
173 check_pass ("http://127.0.0.1/path", "http", "127.0.0.1", HTTP_DEFAULT_PORT,
174 "/path");
175 check_pass ("http://127.0.0.1/path/", "http", "127.0.0.1", HTTP_DEFAULT_PORT,
176 "/path/");
177 check_pass ("http://127.0.0.1:81", "http", "127.0.0.1", 81, "");
178 check_pass ("http://127.0.0.1:81/", "http", "127.0.0.1", 81, "/");
179 check_pass ("http://127.0.0.1:81/path", "http", "127.0.0.1", 81, "/path");
180 check_pass ("http://127.0.0.1:81/path/", "http", "127.0.0.1", 81, "/path/");
181 check_pass ("http://127.0.0.1:81/path/more", "http", "127.0.0.1", 81,
182 "/path/more");
183}
184
185
186static void
187test_fail_ipv6 ()
188{
189 check_pass ("http://[::1]", "http", "[::1]", HTTP_DEFAULT_PORT, "");
190 check_pass ("http://[::1]/", "http", "[::1]", HTTP_DEFAULT_PORT, "/");
191 check_pass ("http://[::1]/path", "http", "[::1]", HTTP_DEFAULT_PORT, "/path");
192 check_pass ("http://[::1]/path/", "http", "[::1]", HTTP_DEFAULT_PORT,
193 "/path/");
194 check_pass ("http://[::1]:81", "http", "[::1]", 81, "");
195 check_pass ("http://[::1]:81/", "http", "[::1]", 81, "/");
196 check_pass ("http://[::1]:81/path", "http", "[::1]", 81, "/path");
197 check_pass ("http://[::1]:81/path/", "http", "[::1]", 81, "/path/");
198 check_pass ("http://[::1]:81/path/more", "http", "[::1]", 81, "/path/more");
199}
200
201
202static void
203test_fail ()
204{
205 if (GNUNET_SYSERR == check_fail (""))
206 GNUNET_break (0);
207 if (GNUNET_SYSERR == check_fail ("http"))
208 GNUNET_break (0);
209 if (GNUNET_SYSERR == check_fail ("://"))
210 GNUNET_break (0);
211 if (GNUNET_SYSERR == check_fail ("http://"))
212 GNUNET_break (0);
213 if (GNUNET_SYSERR == check_fail ("//localhost"))
214 GNUNET_break (0);
215 if (GNUNET_SYSERR == check_fail ("//:80"))
216 GNUNET_break (0);
217 if (GNUNET_SYSERR == check_fail ("//:80/"))
218 GNUNET_break (0);
219 if (GNUNET_SYSERR == check_fail ("//:80:"))
220 GNUNET_break (0);
221 if (GNUNET_SYSERR == check_fail ("http://localhost:a/"))
222 GNUNET_break (0);
223 if (GNUNET_SYSERR == check_fail ("http://127.0.0.1:a/"))
224 GNUNET_break (0);
225}
226
227
228int
229main (int argc, char *argv[])
230{
231 int ret = 0;
232 struct SplittedHTTPAddress *spa;
233
234 GNUNET_log_setup ("test", "DEBUG", NULL);
235 spa = http_split_address ("");
236 if (NULL != spa)
237 {
238 clean (spa);
239 spa = NULL;
240 GNUNET_break (0);
241 }
242
243 spa = http_split_address ("http://");
244 if (NULL != spa)
245 {
246 clean (spa);
247 GNUNET_break (0);
248 }
249
250 spa = http_split_address ("://");
251 if (NULL != spa)
252 {
253 clean (spa);
254 GNUNET_break (0);
255 }
256
257 test_pass_hostname ();
258 test_pass_ipv4 ();
259 test_fail_ipv6 ();
260 test_fail ();
261
262 return ret;
263}
264
265
266/* end of test_http_common.c */
diff --git a/src/transport/test_plugin_transport.c b/src/transport/test_plugin_transport.c
deleted file mode 100644
index 04687d845..000000000
--- a/src/transport/test_plugin_transport.c
+++ /dev/null
@@ -1,797 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2018 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport/test_plugin_transport.c
22 * @brief testcase for transport_api.c
23 * @author Sailor Siraj
24 * @author Christian Grothoff
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_hello_lib.h"
30#include "gnunet_peerinfo_service.h"
31#include "gnunet_statistics_service.h"
32#include "gnunet_protocols.h"
33#include "gnunet_transport_plugin.h"
34#include "transport.h"
35
36/**
37 * How long until we give up on transmitting the message?
38 */
39#define WAIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
40#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
41
42#define HOSTKEY_FILE "test_plugin_hostkey.ecc"
43
44/**
45 * Our public key.
46 */
47static struct GNUNET_PeerIdentity my_identity;
48
49/**
50 * Our private key.
51 */
52static struct GNUNET_CRYPTO_EddsaPrivateKey my_private_key;
53
54/**
55 * Our configuration.
56 */
57const struct GNUNET_CONFIGURATION_Handle *cfg;
58
59/**
60 * Our configuration.
61 */
62struct GNUNET_STATISTICS_Handle *stats;
63
64/**
65 * Our HELLO
66 */
67struct GNUNET_HELLO_Message *hello;
68
69/**
70 * Number of neighbours we'd like to have.
71 */
72static uint32_t max_connect_per_transport;
73
74/**
75 * Environment for this plugin.
76 */
77struct GNUNET_TRANSPORT_PluginEnvironment env;
78
79/**
80 * handle for the api provided by this plugin
81 */
82struct GNUNET_TRANSPORT_PluginFunctions *api;
83
84/**
85 * Helper handler
86 */
87struct GNUNET_HELPER_Handle *suid_helper;
88
89/**
90 * Timeout task
91 */
92static struct GNUNET_SCHEDULER_Task *timeout_endbadly;
93
94/**
95 * Timeout task
96 */
97static struct GNUNET_SCHEDULER_Task *timeout_wait;
98
99/**
100 * Library name
101 */
102static char *libname;
103
104/**
105 * Plugin addresses head
106 */
107struct AddressWrapper *head;
108
109/**
110 * Plugin addresses tail
111 */
112struct AddressWrapper *tail;
113
114unsigned int addresses_reported;
115
116unsigned int pretty_printers_running;
117
118/**
119 * Did the test pass or fail?
120 */
121static int ok;
122
123struct AddressWrapper
124{
125 struct AddressWrapper *next;
126
127 struct AddressWrapper *prev;
128
129 struct GNUNET_HELLO_Address *address;
130
131 char *addrstring;
132
133 struct GNUNET_SCHEDULER_Task *test_task;
134};
135
136
137static void
138end ()
139{
140 struct AddressWrapper *w;
141 int c = 0;
142
143 ok = 0;
144
145 if (NULL != timeout_endbadly)
146 {
147 GNUNET_SCHEDULER_cancel (timeout_endbadly);
148 timeout_endbadly = NULL;
149 }
150 if (NULL != api)
151 GNUNET_PLUGIN_unload (libname, api);
152
153 while (NULL != head)
154 {
155 w = head;
156 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
157 "Plugin did not remove address `%s'\n",
158 w->addrstring);
159 GNUNET_CONTAINER_DLL_remove (head, tail, w);
160 c++;
161 GNUNET_HELLO_address_free (w->address);
162 GNUNET_free (w->addrstring);
163 GNUNET_free (w);
164 }
165 if (c > 0)
166 {
167 GNUNET_break (0);
168 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
169 "Plugin did not remove %u addresses \n",
170 c);
171 ok = 1;
172 }
173
174 GNUNET_free (libname);
175 libname = NULL;
176 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
177 stats = NULL;
178
179 if (NULL != suid_helper)
180 {
181 GNUNET_HELPER_stop (suid_helper, GNUNET_NO);
182 suid_helper = NULL;
183 }
184}
185
186
187static void
188end_badly (void *cls)
189{
190 struct AddressWrapper *w;
191 int c = 0;
192
193 timeout_endbadly = NULL;
194 if (NULL != timeout_wait)
195 {
196 GNUNET_SCHEDULER_cancel (timeout_wait);
197 timeout_wait = NULL;
198 }
199
200 if (pretty_printers_running > 0)
201 {
202 timeout_endbadly = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
203 &end_badly, &ok);
204 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
205 "Have pending calls to pretty_printer ... deferring shutdown\n");
206 return;
207 }
208
209 if (NULL != cls)
210 {
211 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
212 "Test took too long to execute, timeout .... \n");
213 }
214
215 if (NULL != libname)
216 {
217 if (NULL != api)
218 GNUNET_PLUGIN_unload (libname, api);
219 GNUNET_free (libname);
220 libname = NULL;
221 }
222
223 while (NULL != head)
224 {
225 w = head;
226 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Plugin did not remove address `%s'\n",
227 w->addrstring);
228 GNUNET_CONTAINER_DLL_remove (head, tail, w);
229 c++;
230 GNUNET_HELLO_address_free (w->address);
231 if (NULL != w->test_task)
232 GNUNET_SCHEDULER_cancel (w->test_task);
233 GNUNET_free (w->addrstring);
234 GNUNET_free (w);
235 }
236 if (c > 0)
237 {
238 GNUNET_break (0);
239 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Plugin did not remove %u addresses\n",
240 c);
241 }
242
243 if (NULL != stats)
244 {
245 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
246 stats = NULL;
247 }
248
249 if (NULL != suid_helper)
250 {
251 GNUNET_HELPER_stop (suid_helper, GNUNET_NO);
252 suid_helper = NULL;
253 }
254
255 ok = 1;
256}
257
258
259static void
260wait_end (void *cls)
261{
262 timeout_wait = NULL;
263 if (0 == addresses_reported)
264 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
265 "Plugin did not report any addresses, could not check address conversion functions\n");
266 end ();
267}
268
269
270static void
271end_badly_now ()
272{
273 if (NULL != timeout_wait)
274 {
275 GNUNET_SCHEDULER_cancel (timeout_wait);
276 timeout_wait = NULL;
277 }
278 if (NULL != timeout_endbadly)
279 {
280 GNUNET_SCHEDULER_cancel (timeout_endbadly);
281 timeout_endbadly = NULL;
282 }
283 timeout_endbadly = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
284}
285
286
287static struct GNUNET_TIME_Relative
288env_receive (void *cls,
289 const struct GNUNET_HELLO_Address *address,
290 struct GNUNET_ATS_Session *session,
291 const struct GNUNET_MessageHeader *message)
292{
293 /* do nothing */
294 return GNUNET_TIME_relative_get_zero_ ();
295}
296
297
298static int got_reply;
299
300
301/**
302 * Take the given address and append it to the set of results sent back to
303 * the client.
304 *
305 * @param cls closure
306 * @param address the address to print
307 * @param res result code
308 */
309static void
310address_pretty_printer_cb (void *cls, const char *address, int res)
311{
312 if (NULL != address)
313 {
314 got_reply = GNUNET_YES;
315 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Pretty address : `%s'\n", address);
316 pretty_printers_running--;
317 }
318 else
319 {
320 if (GNUNET_NO == got_reply)
321 {
322 pretty_printers_running--;
323 GNUNET_break (0);
324 end_badly_now ();
325 }
326 }
327}
328
329
330static void
331test_addr_string (void *cls)
332{
333 struct AddressWrapper *w = cls;
334 void *s2a;
335 size_t s2a_len;
336
337 w->test_task = NULL;
338
339 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
340 "Testing: address_to_string \n");
341 w->addrstring = GNUNET_strdup (api->address_to_string (api,
342 w->address->address,
343 w->address->
344 address_length));
345 if (NULL == w->addrstring)
346 {
347 GNUNET_break (0);
348 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
349 "Plugin cannot convert address to string!\n");
350 end_badly_now ();
351 return;
352 }
353 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
354 "Plugin added address `%s'\n",
355 w->addrstring);
356 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
357 "Testing address_to_string: OK\n");
358 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
359 "Testing: string_to_address \n");
360 s2a = NULL;
361 s2a_len = 0;
362 if ((GNUNET_OK !=
363 api->string_to_address (api, w->addrstring,
364 strlen (w->addrstring) + 1,
365 &s2a, &s2a_len)) ||
366 (NULL == s2a))
367 {
368 GNUNET_break (0);
369 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
370 "Plugin cannot convert string to address!\n");
371 end_badly_now ();
372 return;
373 }
374
375 /*
376 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
377 "Plugin creates `%s' %u\n",api->address_to_string (api, s2a, s2a_len), s2a_len);
378
379 int c1;
380 for (c1 = 0; c1 < s2a_len; c1++ )
381 fprintf (stderr, "%u == %u\n", ((char *) s2a)[c1], ((char *) w->addr)[c1]);
382 */if (s2a_len != w->address->address_length)
383 {
384 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
385 "Plugin creates different address length when converting address->string->address: %u != %u\n",
386 (unsigned int) w->address->address_length,
387 (unsigned int) s2a_len);
388 }
389 else if (0 != memcmp (s2a, w->address->address, s2a_len))
390 {
391 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
392 "Plugin creates different address length when converting back and forth %i!\n",
393 memcmp (s2a,
394 w->address->address,
395 s2a_len));
396 }
397 else
398 {
399 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
400 "Testing string_to_address: OK\n");
401 }
402 GNUNET_free (s2a);
403
404 pretty_printers_running++;
405 api->address_pretty_printer (api->cls,
406 w->address->transport_name,
407 w->address->address,
408 w->address->address_length,
409 GNUNET_YES,
410 GNUNET_TIME_UNIT_MINUTES,
411 &address_pretty_printer_cb, w);
412
413 if (GNUNET_OK !=
414 api->check_address (api->cls,
415 w->address->address,
416 w->address->address_length))
417 {
418 GNUNET_break (0);
419 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
420 "Plugin refuses added address!\n");
421 end_badly_now ();
422 return;
423 }
424 if (NULL != timeout_wait)
425 {
426 GNUNET_SCHEDULER_cancel (timeout_wait);
427 timeout_wait = NULL;
428 }
429 timeout_wait = GNUNET_SCHEDULER_add_delayed (WAIT, &wait_end, NULL);
430}
431
432
433static void
434env_notify_address (void *cls,
435 int add_remove,
436 const struct GNUNET_HELLO_Address *address)
437{
438 struct AddressWrapper *w;
439 struct AddressWrapper *wtmp;
440
441 if (GNUNET_YES == add_remove)
442 {
443 addresses_reported++;
444 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
445 "Adding address of length %u\n",
446 (unsigned int) address->address_length);
447
448 for (wtmp = head; NULL != wtmp; wtmp = wtmp->next)
449 {
450 if ((address->address_length == wtmp->address->address_length) &&
451 (0 == memcmp (address->address, wtmp->address->address,
452 address->address_length)))
453 {
454 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
455 "Duplicate address notification .... \n");
456 return;
457 }
458 }
459
460 w = GNUNET_new (struct AddressWrapper);
461 w->address = GNUNET_HELLO_address_copy (address);
462 GNUNET_CONTAINER_DLL_insert (head, tail, w);
463 got_reply = GNUNET_NO;
464 w->test_task = GNUNET_SCHEDULER_add_now (&test_addr_string,
465 w);
466 return;
467 }
468
469 if (GNUNET_NO == add_remove)
470 {
471 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
472 "Removing address of length %u\n",
473 (unsigned int) address->address_length);
474 w = head;
475 while (NULL != w)
476 {
477 if ((address->address_length == w->address->address_length) &&
478 (0 == memcmp (w->address->address, address->address,
479 address->address_length)))
480 {
481 break;
482 }
483 w = w->next;
484 }
485
486 if (w == NULL)
487 {
488 GNUNET_break (0);
489 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
490 "Plugin removes address never added!\n");
491 end_badly_now ();
492 return;
493 }
494
495 GNUNET_CONTAINER_DLL_remove (head, tail, w);
496 GNUNET_HELLO_address_free (w->address);
497 GNUNET_free (w->addrstring);
498 GNUNET_free (w);
499 return;
500 }
501 GNUNET_break (0);
502 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
503 "Invalid operation: %u\n",
504 add_remove);
505 end_badly_now ();
506}
507
508
509static enum GNUNET_NetworkType
510env_get_address_type (void *cls,
511 const struct sockaddr *addr,
512 size_t addrlen)
513{
514 return GNUNET_NT_LOOPBACK;
515}
516
517
518static const struct GNUNET_MessageHeader *
519env_get_our_hello ()
520{
521 return (const struct GNUNET_MessageHeader *) hello;
522}
523
524
525static void
526env_session_end (void *cls,
527 const struct GNUNET_HELLO_Address *address,
528 struct GNUNET_ATS_Session *session)
529{
530}
531
532
533static void
534env_update_distance (void *cls,
535 const struct GNUNET_HELLO_Address *address,
536 uint32_t distance)
537{
538}
539
540
541static void
542setup_plugin_environment ()
543{
544 env.cfg = cfg;
545 env.cls = &env;
546 env.my_identity = &my_identity;
547 env.max_connections = max_connect_per_transport;
548 env.stats = stats;
549 env.receive = &env_receive;
550 env.notify_address = &env_notify_address;
551 env.get_address_type = &env_get_address_type;
552 env.update_address_distance = &env_update_distance;
553 env.get_our_hello = &env_get_our_hello;
554 env.session_end = &env_session_end;
555}
556
557
558static int
559handle_helper_message (void *cls,
560 const struct GNUNET_MessageHeader *hdr)
561{
562 return GNUNET_OK;
563}
564
565
566/**
567 * Runs the test.
568 *
569 * @param cls closure
570 * @param c configuration to use
571 */
572static void
573run (void *cls,
574 char *const *args,
575 const char *cfgfile,
576 const struct GNUNET_CONFIGURATION_Handle *c)
577{
578 char *const *argv = cls;
579 unsigned long long tneigh;
580 char *keyfile;
581 char *plugin;
582 char *sep;
583
584 timeout_endbadly = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
585 &end_badly,
586 &ok);
587 cfg = c;
588 /* parse configuration */
589 if ((GNUNET_OK !=
590 GNUNET_CONFIGURATION_get_value_number (c,
591 "TRANSPORT",
592 "NEIGHBOUR_LIMIT",
593 &tneigh)) ||
594 (GNUNET_OK !=
595 GNUNET_CONFIGURATION_get_value_filename (c,
596 "PEER",
597 "PRIVATE_KEY",
598 &keyfile)))
599 {
600 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
601 "Transport service is lacking key configuration settings. Exiting.\n");
602 return;
603 }
604
605 if (NULL == (stats = GNUNET_STATISTICS_create ("transport",
606 cfg)))
607 {
608 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
609 "Could not create statistics. Exiting.\n");
610 GNUNET_free (keyfile);
611 end_badly_now ();
612 return;
613 }
614
615 if (GNUNET_OK != GNUNET_DISK_file_test (HOSTKEY_FILE))
616 {
617 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
618 "Hostkey `%s' missing. Exiting.\n",
619 HOSTKEY_FILE);
620 GNUNET_free (keyfile);
621 end_badly_now ();
622 return;
623 }
624
625 if (GNUNET_OK !=
626 GNUNET_DISK_directory_create_for_file (keyfile))
627 {
628 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
629 "Could not create a directory for hostkey `%s'. Exiting.\n",
630 keyfile);
631 GNUNET_free (keyfile);
632 end_badly_now ();
633 return;
634 }
635
636 if (GNUNET_OK !=
637 GNUNET_DISK_file_copy (HOSTKEY_FILE,
638 keyfile))
639 {
640 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
641 "Could not copy hostkey `%s' to destination `%s'. Exiting.\n",
642 HOSTKEY_FILE,
643 keyfile);
644 GNUNET_free (keyfile);
645 end_badly_now ();
646 return;
647 }
648
649 max_connect_per_transport = (uint32_t) tneigh;
650 if (GNUNET_SYSERR ==
651 GNUNET_CRYPTO_eddsa_key_from_file (keyfile,
652 GNUNET_YES,
653 &my_private_key))
654 {
655 GNUNET_free (keyfile);
656 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
657 "Could not access hostkey. Exiting.\n");
658 end_badly_now ();
659 return;
660 }
661 GNUNET_free (keyfile);
662 GNUNET_CRYPTO_eddsa_key_get_public (&my_private_key,
663 &my_identity.public_key);
664
665 hello = GNUNET_HELLO_create (&my_identity.public_key, NULL, NULL, GNUNET_NO);
666
667 /* load plugins... */
668 setup_plugin_environment ();
669
670 GNUNET_assert (strlen (argv[0]) > strlen ("test_plugin_"));
671 plugin = strstr (argv[0], "test_plugin_");
672 sep = strrchr (argv[0], '.');
673 if (NULL == plugin)
674 {
675 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Not a valid test name\n");
676 end_badly_now ();
677 return;
678 }
679 plugin += strlen ("test_plugin_");
680 if (NULL != sep)
681 sep[0] = '\0';
682
683 /* Hack for WLAN: start a second helper */
684 if (0 == strcmp (plugin, "wlan"))
685 {
686 char *helper_argv[3];
687 helper_argv[0] = (char *) "gnunet-helper-transport-wlan-dummy";
688 helper_argv[1] = (char *) "2";
689 helper_argv[2] = NULL;
690 suid_helper = GNUNET_HELPER_start (GNUNET_NO,
691 "gnunet-helper-transport-wlan-dummy",
692 helper_argv,
693 &handle_helper_message, NULL, NULL);
694 }
695
696 /* Loading plugin */
697 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Loading transport plugin %s\n", plugin);
698 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", plugin);
699 api = GNUNET_PLUGIN_load (libname, &env);
700 if (NULL == api)
701 {
702 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
703 "Failed to load transport plugin for %s\n", plugin);
704 end_badly_now ();
705 return;
706 }
707
708 timeout_wait = GNUNET_SCHEDULER_add_delayed (WAIT, &wait_end, NULL);
709
710 /* Check if all functions are implemented */
711 if (NULL == api->address_pretty_printer)
712 {
713 GNUNET_break (0);
714 end_badly_now ();
715 return;
716 }
717 if (NULL == api->address_to_string)
718 {
719 GNUNET_break (0);
720 end_badly_now ();
721 return;
722 }
723 GNUNET_assert (NULL != api->check_address);
724 if (NULL == api->check_address)
725 {
726 GNUNET_break (0);
727 end_badly_now ();
728 return;
729 }
730 GNUNET_assert (NULL != api->disconnect_peer);
731 if (NULL == api->disconnect_peer)
732 {
733 GNUNET_break (0);
734 end_badly_now ();
735 return;
736 }
737 GNUNET_assert (NULL != api->get_session);
738 if (NULL == api->get_session)
739 {
740 GNUNET_break (0);
741 end_badly_now ();
742 return;
743 }
744 if (NULL == api->address_pretty_printer)
745 {
746 GNUNET_break (0);
747 end_badly_now ();
748 return;
749 }
750 if (NULL == api->string_to_address)
751 {
752 GNUNET_break (0);
753 end_badly_now ();
754 return;
755 }
756}
757
758
759/**
760 * The main function for the test
761 *
762 * @param argc number of arguments from the command line
763 * @param argv command line arguments
764 * @return 0 ok, 1 on error
765 */
766int
767main (int argc,
768 char *const *argv)
769{
770 static struct GNUNET_GETOPT_CommandLineOption options[] = {
771 GNUNET_GETOPT_OPTION_END
772 };
773 int ret;
774 char *const argv_prog[] = {
775 "test_plugin_transport",
776 "-c",
777 "test_plugin_transport_data.conf",
778 NULL
779 };
780
781 GNUNET_log_setup ("test-plugin-transport",
782 "WARNING",
783 NULL);
784 GNUNET_DISK_purge_cfg_dir ("test_plugin_transport_data.conf",
785 "GNUNET_TEST_HOME");
786 ok = 1; /* set to fail */
787 ret =
788 (GNUNET_OK
789 == GNUNET_PROGRAM_run (3, argv_prog, "test-plugin-transport",
790 "testcase", options, &run, (void *) argv)) ? ok : 1;
791 GNUNET_DISK_purge_cfg_dir ("test_plugin_transport_data.conf",
792 "GNUNET_TEST_HOME");
793 return ret;
794}
795
796
797/* end of test_plugin_transport.c */
diff --git a/src/transport/test_plugin_transport_data.conf b/src/transport/test_plugin_transport_data.conf
deleted file mode 100644
index b667a4854..000000000
--- a/src/transport/test_plugin_transport_data.conf
+++ /dev/null
@@ -1,47 +0,0 @@
1@INLINE@ test_transport_defaults.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunetd-plugin-transport/
4
5[transport-tcp]
6PORT = 52400
7
8[transport-udp]
9PORT = 52401
10
11[transport-wlan]
12INTERFACE = mon0
13TESTMODE = 1
14
15[transport-bluetooth]
16INTERFACE = hci0
17TESTMODE = 1
18
19[transport-http_server]
20PORT = 52402
21
22[transport-https_server]
23PORT = 52403
24
25[arm]
26PORT = 52360
27UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-arm.sock
28
29[statistics]
30PORT = 52361
31UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-statistics.sock
32
33[resolver]
34PORT = 52362
35UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-resolver.sock
36
37[peerinfo]
38PORT = 52363
39UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-peerinfo.sock
40
41[transport]
42PORT = 52364
43UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-transport.sock
44
45[nat]
46RETURN_LOCAL_ADDRESSES = YES
47DISABLEV6 = NO
diff --git a/src/transport/test_plugin_transport_data_udp.conf b/src/transport/test_plugin_transport_data_udp.conf
deleted file mode 100644
index 8b1378917..000000000
--- a/src/transport/test_plugin_transport_data_udp.conf
+++ /dev/null
@@ -1 +0,0 @@
1
diff --git a/src/transport/test_quota_compliance.c b/src/transport/test_quota_compliance.c
deleted file mode 100644
index c3c46db37..000000000
--- a/src/transport/test_quota_compliance.c
+++ /dev/null
@@ -1,321 +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 it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport/test_quota_compliance.c
22 * @brief base test case for transport implementations
23 *
24 * This test case tests quota compliance both on transport level
25 */
26#include "platform.h"
27#include "gnunet_transport_service.h"
28#include "gnunet_ats_service.h"
29#include "gauger.h"
30#include "transport-testing.h"
31
32/**
33 * Testcase timeout
34 */
35#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 480)
36
37#define DURATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 80)
38
39
40static struct GNUNET_SCHEDULER_Task *measure_task;
41
42static char *gen_cfgs[2];
43
44static unsigned long long quota_in[] = { 10000, 10000 };
45
46static unsigned long long quota_out[] = { 10000, 10000 };
47
48static struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
49
50
51/**
52 * Note that this value must not significantly exceed
53 * 'MAX_PENDING' in 'gnunet-service-transport.c', otherwise
54 * messages may be dropped even for a reliable transport.
55 */
56#define TOTAL_MSGS (1024 * 32)
57
58static unsigned long long total_bytes_recv;
59
60static struct GNUNET_TIME_Absolute start_time;
61
62
63static void
64report ()
65{
66 unsigned long long delta;
67 unsigned long long datarate;
68
69 delta = GNUNET_TIME_absolute_get_duration (start_time).rel_value_us;
70 if (0 == delta)
71 delta = 1;
72 datarate = (total_bytes_recv * 1000 * 1000) / delta;
73
74 fprintf (stderr,
75 "Throughput was %llu b/s\n",
76 datarate);
77 ccc->global_ret = GNUNET_OK;
78 if (datarate > 1.5 * quota_in[1])
79 {
80 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
81 "Datarate of %llu b/s significantly higher than allowed inbound quota of %llu b/s\n",
82 datarate,
83 quota_in[1]);
84 ccc->global_ret = GNUNET_SYSERR;
85 }
86 if (datarate > 1.5 * quota_out[0])
87 {
88 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
89 "Datarate of %llu b/s significantly higher than allowed outbound quota of %llu b/s\n",
90 datarate,
91 quota_out[0]);
92 ccc->global_ret = GNUNET_SYSERR;
93 }
94 if (GNUNET_OK == ccc->global_ret)
95 {
96 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
97 "Datarate of %llu b/s complied to allowed outbound quota of %llu b/s and inbound quota of %llu b/s\n",
98 datarate,
99 quota_out[0],
100 quota_in[1]);
101 }
102}
103
104
105static void
106custom_shutdown (void *cls)
107{
108 if (NULL != measure_task)
109 {
110 GNUNET_SCHEDULER_cancel (measure_task);
111 measure_task = NULL;
112 }
113 report ();
114}
115
116
117static size_t
118get_size (unsigned int iter)
119{
120 size_t ret;
121
122 ret = (iter * iter * iter) % 60000;
123 ret += sizeof(struct GNUNET_TRANSPORT_TESTING_TestMessage);
124 return ret;
125}
126
127
128static void
129notify_receive (void *cls,
130 struct GNUNET_TRANSPORT_TESTING_PeerContext *receiver,
131 const struct GNUNET_PeerIdentity *sender,
132 const struct GNUNET_TRANSPORT_TESTING_TestMessage *hdr)
133{
134 if (GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE != ntohs (hdr->header.type))
135 return;
136 total_bytes_recv += ntohs (hdr->header.size);
137
138 {
139 char *ps = GNUNET_strdup (GNUNET_i2s (&receiver->id));
140
141 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
142 "Peer %u (`%s') got message %u of size %u from peer (`%s')\n",
143 receiver->no,
144 ps,
145 ntohl (hdr->num),
146 ntohs (hdr->header.size),
147 GNUNET_i2s (sender));
148 GNUNET_free (ps);
149 }
150}
151
152
153static void
154measure (void *cls)
155{
156 static int counter;
157
158 measure_task = NULL;
159 counter++;
160 if ((DURATION.rel_value_us / 1000 / 1000LL) < counter)
161 {
162 fprintf (stderr, "%s", ".\n");
163 GNUNET_SCHEDULER_shutdown ();
164 return;
165 }
166 fprintf (stderr, "%s", ".");
167 measure_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
168 &measure,
169 NULL);
170}
171
172
173static void
174start_task (void *cls)
175{
176 static struct GNUNET_TRANSPORT_TESTING_SendClosure sc = {
177 .num_messages = TOTAL_MSGS,
178 .get_size_cb = &get_size
179 };
180
181 sc.ccc = ccc;
182 measure_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
183 &measure,
184 NULL);
185 start_time = GNUNET_TIME_absolute_get ();
186 GNUNET_SCHEDULER_add_now (&GNUNET_TRANSPORT_TESTING_simple_send,
187 &sc);
188}
189
190
191static char *
192generate_config (const char *cfg_file,
193 unsigned long long quota_in,
194 unsigned long long quota_out)
195{
196 char *in_name;
197 char *out_name;
198 char *fname = NULL;
199 struct GNUNET_CONFIGURATION_Handle *cfg = GNUNET_CONFIGURATION_create ();
200
201 GNUNET_assert (GNUNET_OK ==
202 GNUNET_CONFIGURATION_load (cfg,
203 cfg_file));
204 GNUNET_asprintf (&fname,
205 "q_in_%llu_q_out_%llu_%s",
206 quota_in,
207 quota_out,
208 cfg_file);
209 GNUNET_CONFIGURATION_set_value_string (cfg,
210 "PATHS",
211 "DEFAULTCONFIG",
212 fname);
213 for (int c = 0; c < GNUNET_NT_COUNT; c++)
214 {
215 GNUNET_asprintf (&in_name,
216 "%s_QUOTA_IN",
217 GNUNET_NT_to_string (c));
218 GNUNET_asprintf (&out_name,
219 "%s_QUOTA_OUT",
220 GNUNET_NT_to_string (c));
221 GNUNET_CONFIGURATION_set_value_number (cfg,
222 "ats",
223 in_name,
224 quota_in);
225 GNUNET_CONFIGURATION_set_value_number (cfg,
226 "ats",
227 out_name,
228 quota_out);
229 GNUNET_free (in_name);
230 GNUNET_free (out_name);
231 }
232 GNUNET_assert (GNUNET_OK ==
233 GNUNET_CONFIGURATION_write (cfg,
234 fname));
235 GNUNET_CONFIGURATION_destroy (cfg);
236 return fname;
237}
238
239
240static int
241check (void *cls,
242 struct GNUNET_TRANSPORT_TESTING_Handle *tth_,
243 const char *test_plugin_,
244 const char *test_name_,
245 unsigned int num_peers,
246 char *cfg_files[])
247{
248 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext my_ccc = {
249 .connect_continuation = &start_task,
250 .config_file = "test_quota_compliance_data.conf",
251 .rec = &notify_receive,
252 .nc = &GNUNET_TRANSPORT_TESTING_log_connect,
253 .nd = &GNUNET_TRANSPORT_TESTING_log_disconnect,
254 .shutdown_task = &custom_shutdown,
255 .timeout = TIMEOUT
256 };
257
258 ccc = &my_ccc;
259
260 if (NULL != strstr (test_name_,
261 "asymmetric"))
262 {
263 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
264 "Running asymmetric test with sending peer unlimited, receiving peer (in/out): %llu/%llu b/s \n",
265 quota_in[1],
266 quota_out[1]);
267 quota_out[0] = 1024 * 1024 * 1024;
268 quota_in[0] = 1024 * 1024 * 1024;
269 }
270 else
271 {
272 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
273 "Running symmetric test with (in/out) %llu/%llu b/s \n",
274 quota_in[1],
275 quota_out[1]);
276 }
277 for (unsigned int i = 0; i < 2; i++)
278 {
279 gen_cfgs[i] = generate_config (cfg_files[i],
280 quota_in[i],
281 quota_out[i]);
282 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
283 "Generated config file `%s'\n",
284 gen_cfgs[i]);
285 }
286
287 return GNUNET_TRANSPORT_TESTING_connect_check (&my_ccc,
288 tth_,
289 test_plugin_,
290 test_name_,
291 num_peers,
292 gen_cfgs);
293}
294
295
296int
297main (int argc,
298 char *argv[])
299{
300 if (GNUNET_OK !=
301 GNUNET_TRANSPORT_TESTING_main (2,
302 &check,
303 NULL))
304 {
305 GNUNET_break (0);
306 return 1;
307 }
308 for (unsigned int i = 0; i < 2; i++)
309 {
310 if ((NULL != gen_cfgs[i]) &&
311 (GNUNET_YES == GNUNET_DISK_file_test (gen_cfgs[i])))
312 {
313 GNUNET_DISK_directory_remove (gen_cfgs[i]);
314 GNUNET_free (gen_cfgs[i]);
315 }
316 }
317 return 0;
318}
319
320
321/* end of test_quota_compliance.c */
diff --git a/src/transport/test_quota_compliance_bluetooth_asymmetric_peer1.conf b/src/transport/test_quota_compliance_bluetooth_asymmetric_peer1.conf
deleted file mode 100644
index 86bdf6db4..000000000
--- a/src/transport/test_quota_compliance_bluetooth_asymmetric_peer1.conf
+++ /dev/null
@@ -1,12 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-bluetooth-p1/
4
5[transport-bluetooth]
6INTERFACE = hci0
7TESTMODE = 1
8
9[transport]
10PLUGINS = bluetooth
11
12
diff --git a/src/transport/test_quota_compliance_bluetooth_asymmetric_peer2.conf b/src/transport/test_quota_compliance_bluetooth_asymmetric_peer2.conf
deleted file mode 100644
index 086688e73..000000000
--- a/src/transport/test_quota_compliance_bluetooth_asymmetric_peer2.conf
+++ /dev/null
@@ -1,11 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-bluetooth-p2/
4
5[transport-bluetooth]
6INTERFACE = hci1
7TESTMODE = 2
8
9[transport]
10PLUGINS = bluetooth
11
diff --git a/src/transport/test_quota_compliance_bluetooth_peer1.conf b/src/transport/test_quota_compliance_bluetooth_peer1.conf
deleted file mode 100644
index 3f86ee940..000000000
--- a/src/transport/test_quota_compliance_bluetooth_peer1.conf
+++ /dev/null
@@ -1,30 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-bluetooth-p1/
4
5[transport-bluetooth]
6INTERFACE = hci0
7TESTMODE = 1
8
9[arm]
10PORT = 12164
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
12
13[statistics]
14PORT = 12163
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
16
17[resolver]
18PORT = 12162
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
20
21[peerinfo]
22PORT = 12161
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
24
25[transport]
26PORT = 12160
27PLUGINS = bluetooth
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
29
30
diff --git a/src/transport/test_quota_compliance_bluetooth_peer2.conf b/src/transport/test_quota_compliance_bluetooth_peer2.conf
deleted file mode 100644
index 5fc178395..000000000
--- a/src/transport/test_quota_compliance_bluetooth_peer2.conf
+++ /dev/null
@@ -1,29 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-bluetooth-p2/
4
5[transport-bluetooth]
6INTERFACE = hci1
7TESTMODE = 2
8
9[arm]
10PORT = 12174
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
12
13[statistics]
14PORT = 12173
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
16
17[resolver]
18PORT = 12172
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
20
21[peerinfo]
22PORT = 12171
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
24
25[transport]
26PORT = 12170
27PLUGINS = bluetooth
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
29
diff --git a/src/transport/test_quota_compliance_data.conf b/src/transport/test_quota_compliance_data.conf
deleted file mode 100644
index 1bc607770..000000000
--- a/src/transport/test_quota_compliance_data.conf
+++ /dev/null
@@ -1,24 +0,0 @@
1@INLINE@ test_transport_defaults.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunetd-plugin-transport/
4
5[transport-tcp]
6PORT = 52368
7TIMEOUT = 5 s
8
9[arm]
10PORT = 52366
11
12[statistics]
13PORT = 52367
14
15[resolver]
16PORT = 52364
17
18[peerinfo]
19PORT = 52369
20
21[transport]
22PORT = 52365
23
24
diff --git a/src/transport/test_quota_compliance_http_asymmetric_peer1.conf b/src/transport/test_quota_compliance_http_asymmetric_peer1.conf
deleted file mode 100644
index b2ff1913f..000000000
--- a/src/transport/test_quota_compliance_http_asymmetric_peer1.conf
+++ /dev/null
@@ -1,28 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test_quota_compliance_peer1
4
5[transport-http_client]
6
7[arm]
8PORT = 54015
9UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_http_arm_peer1.sock
10
11[statistics]
12PORT = 54014
13UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_http_statistics_peer1.sock
14
15[resolver]
16PORT = 54013
17UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_http_resolver_peer1.sock
18
19[peerinfo]
20PORT = 54012
21UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_http_peerinfo_peer1.sock
22
23[transport]
24PORT = 54011
25PLUGINS = http_client
26UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_http_transport_peer1.sock
27
28
diff --git a/src/transport/test_quota_compliance_http_asymmetric_peer2.conf b/src/transport/test_quota_compliance_http_asymmetric_peer2.conf
deleted file mode 100644
index 3408d9f2e..000000000
--- a/src/transport/test_quota_compliance_http_asymmetric_peer2.conf
+++ /dev/null
@@ -1,32 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test_quota_compliance_peer2
4
5[transport-http_server]
6PORT = 53010
7USE_IPv6 = NO
8BINDTO = 127.0.0.1
9
10
11[arm]
12PORT = 53015
13UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_http_arm_peer2.sock
14
15[statistics]
16PORT = 53014
17UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_http_statistics_peer2.sock
18
19[resolver]
20PORT = 53013
21UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_http_resolver_peer2.sock
22
23[peerinfo]
24PORT = 53012
25UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_http_peerinfo_peer2.sock
26
27[transport]
28PORT = 53011
29PLUGINS = http_server
30UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_http_transport_peer2.sock
31
32
diff --git a/src/transport/test_quota_compliance_http_peer1.conf b/src/transport/test_quota_compliance_http_peer1.conf
deleted file mode 100644
index b2ff1913f..000000000
--- a/src/transport/test_quota_compliance_http_peer1.conf
+++ /dev/null
@@ -1,28 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test_quota_compliance_peer1
4
5[transport-http_client]
6
7[arm]
8PORT = 54015
9UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_http_arm_peer1.sock
10
11[statistics]
12PORT = 54014
13UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_http_statistics_peer1.sock
14
15[resolver]
16PORT = 54013
17UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_http_resolver_peer1.sock
18
19[peerinfo]
20PORT = 54012
21UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_http_peerinfo_peer1.sock
22
23[transport]
24PORT = 54011
25PLUGINS = http_client
26UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_http_transport_peer1.sock
27
28
diff --git a/src/transport/test_quota_compliance_http_peer2.conf b/src/transport/test_quota_compliance_http_peer2.conf
deleted file mode 100644
index 3408d9f2e..000000000
--- a/src/transport/test_quota_compliance_http_peer2.conf
+++ /dev/null
@@ -1,32 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test_quota_compliance_peer2
4
5[transport-http_server]
6PORT = 53010
7USE_IPv6 = NO
8BINDTO = 127.0.0.1
9
10
11[arm]
12PORT = 53015
13UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_http_arm_peer2.sock
14
15[statistics]
16PORT = 53014
17UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_http_statistics_peer2.sock
18
19[resolver]
20PORT = 53013
21UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_http_resolver_peer2.sock
22
23[peerinfo]
24PORT = 53012
25UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_http_peerinfo_peer2.sock
26
27[transport]
28PORT = 53011
29PLUGINS = http_server
30UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_http_transport_peer2.sock
31
32
diff --git a/src/transport/test_quota_compliance_https_asymmetric_peer1.conf b/src/transport/test_quota_compliance_https_asymmetric_peer1.conf
deleted file mode 100644
index 94aa534ef..000000000
--- a/src/transport/test_quota_compliance_https_asymmetric_peer1.conf
+++ /dev/null
@@ -1,28 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test_quota_compliance_peer1/
4
5[transport-https_client]
6
7[arm]
8PORT = 54006
9UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_https_arm_peer1.sock
10
11[statistics]
12PORT = 54005
13UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_https_statistics_peer1.sock
14
15[resolver]
16PORT = 54004
17UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_https_resolver_peer1.sock
18
19[peerinfo]
20PORT = 54003
21UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_https_peerinfo_peer1.sock
22
23[transport]
24PORT = 54002
25PLUGINS = https_client
26UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_https_transport_peer1.sock
27
28
diff --git a/src/transport/test_quota_compliance_https_asymmetric_peer2.conf b/src/transport/test_quota_compliance_https_asymmetric_peer2.conf
deleted file mode 100644
index 8fb8861cd..000000000
--- a/src/transport/test_quota_compliance_https_asymmetric_peer2.conf
+++ /dev/null
@@ -1,31 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test_quota_compliance_peer2
4
5[transport-https_server]
6PORT = 53001
7KEY_FILE = https_key_quota_p2.key
8CERT_FILE = https_cert_qutoa_p2.crt
9
10[arm]
11PORT = 53006
12UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_https_arm_peer2.sock
13
14[statistics]
15PORT = 53005
16UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_https_statistics_peer2.sock
17
18[resolver]
19PORT = 53004
20UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_https_resolver_peer2.sock
21
22[peerinfo]
23PORT = 53003
24UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_https_peerinfo_peer2.sock
25
26[transport]
27PORT = 53002
28PLUGINS = https_server
29UNIXPATH = $GNUNET_RUNTIME_DIR/https_transport_peer2.sock
30
31
diff --git a/src/transport/test_quota_compliance_https_peer1.conf b/src/transport/test_quota_compliance_https_peer1.conf
deleted file mode 100644
index 94aa534ef..000000000
--- a/src/transport/test_quota_compliance_https_peer1.conf
+++ /dev/null
@@ -1,28 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test_quota_compliance_peer1/
4
5[transport-https_client]
6
7[arm]
8PORT = 54006
9UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_https_arm_peer1.sock
10
11[statistics]
12PORT = 54005
13UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_https_statistics_peer1.sock
14
15[resolver]
16PORT = 54004
17UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_https_resolver_peer1.sock
18
19[peerinfo]
20PORT = 54003
21UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_https_peerinfo_peer1.sock
22
23[transport]
24PORT = 54002
25PLUGINS = https_client
26UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_https_transport_peer1.sock
27
28
diff --git a/src/transport/test_quota_compliance_https_peer2.conf b/src/transport/test_quota_compliance_https_peer2.conf
deleted file mode 100644
index 8fb8861cd..000000000
--- a/src/transport/test_quota_compliance_https_peer2.conf
+++ /dev/null
@@ -1,31 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test_quota_compliance_peer2
4
5[transport-https_server]
6PORT = 53001
7KEY_FILE = https_key_quota_p2.key
8CERT_FILE = https_cert_qutoa_p2.crt
9
10[arm]
11PORT = 53006
12UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_https_arm_peer2.sock
13
14[statistics]
15PORT = 53005
16UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_https_statistics_peer2.sock
17
18[resolver]
19PORT = 53004
20UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_https_resolver_peer2.sock
21
22[peerinfo]
23PORT = 53003
24UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_https_peerinfo_peer2.sock
25
26[transport]
27PORT = 53002
28PLUGINS = https_server
29UNIXPATH = $GNUNET_RUNTIME_DIR/https_transport_peer2.sock
30
31
diff --git a/src/transport/test_quota_compliance_tcp_asymmetric_peer1.conf b/src/transport/test_quota_compliance_tcp_asymmetric_peer1.conf
deleted file mode 100644
index 0e0cbff24..000000000
--- a/src/transport/test_quota_compliance_tcp_asymmetric_peer1.conf
+++ /dev/null
@@ -1,32 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/quota-tcp-p1/
4
5[transport-tcp]
6PORT = 54094
7
8[transport-udp]
9PORT = 54094
10
11[arm]
12PORT = 54087
13UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_tcp_arm_peer1.sock
14
15[statistics]
16PORT = 54088
17UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_tcp_statistics_peer1.sock
18
19[resolver]
20PORT = 54089
21UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_tcp_resolver_peer1.sock
22
23[peerinfo]
24PORT = 54090
25UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_tcp_peerinfo_peer1.sock
26
27[transport]
28PORT = 54091
29PLUGINS = tcp
30UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_tcp_transport_peer1.sock
31
32
diff --git a/src/transport/test_quota_compliance_tcp_asymmetric_peer2.conf b/src/transport/test_quota_compliance_tcp_asymmetric_peer2.conf
deleted file mode 100644
index e9757b080..000000000
--- a/src/transport/test_quota_compliance_tcp_asymmetric_peer2.conf
+++ /dev/null
@@ -1,29 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/quota-tcp-p2/
4
5[transport-tcp]
6PORT = 12015
7TIMEOUT = 5 s
8
9[arm]
10PORT = 12014
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
12
13[statistics]
14PORT = 12013
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
16
17[resolver]
18PORT = 12012
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
20
21[peerinfo]
22PORT = 12011
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
24
25[transport]
26PORT = 12010
27PLUGINS = tcp
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
29
diff --git a/src/transport/test_quota_compliance_tcp_peer1.conf b/src/transport/test_quota_compliance_tcp_peer1.conf
deleted file mode 100644
index 0e0cbff24..000000000
--- a/src/transport/test_quota_compliance_tcp_peer1.conf
+++ /dev/null
@@ -1,32 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/quota-tcp-p1/
4
5[transport-tcp]
6PORT = 54094
7
8[transport-udp]
9PORT = 54094
10
11[arm]
12PORT = 54087
13UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_tcp_arm_peer1.sock
14
15[statistics]
16PORT = 54088
17UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_tcp_statistics_peer1.sock
18
19[resolver]
20PORT = 54089
21UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_tcp_resolver_peer1.sock
22
23[peerinfo]
24PORT = 54090
25UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_tcp_peerinfo_peer1.sock
26
27[transport]
28PORT = 54091
29PLUGINS = tcp
30UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_tcp_transport_peer1.sock
31
32
diff --git a/src/transport/test_quota_compliance_tcp_peer2.conf b/src/transport/test_quota_compliance_tcp_peer2.conf
deleted file mode 100644
index a7b2cf90b..000000000
--- a/src/transport/test_quota_compliance_tcp_peer2.conf
+++ /dev/null
@@ -1,29 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
4
5[transport-tcp]
6PORT = 12015
7TIMEOUT = 5 s
8
9[arm]
10PORT = 12014
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
12
13[statistics]
14PORT = 12013
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
16
17[resolver]
18PORT = 12012
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
20
21[peerinfo]
22PORT = 12011
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
24
25[transport]
26PORT = 12010
27PLUGINS = tcp
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
29
diff --git a/src/transport/test_quota_compliance_udp_peer1.conf b/src/transport/test_quota_compliance_udp_peer1.conf
deleted file mode 100644
index bba75c168..000000000
--- a/src/transport/test_quota_compliance_udp_peer1.conf
+++ /dev/null
@@ -1,29 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test_quota_compliance_peer1/
4
5[transport-udp]
6PORT = 54368
7MAX_BPS = 50000000
8
9[arm]
10PORT = 54087
11UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_udp_arm_peer1.sock
12
13[statistics]
14PORT = 54088
15UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_udp_statistics_peer1.sock
16
17[resolver]
18PORT = 54089
19UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_udp_resolver_peer1.sock
20
21[peerinfo]
22PORT = 54090
23UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_udp_peerinfo_peer1.sock
24
25[transport]
26PORT = 54091
27PLUGINS = udp
28UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_udp_transport_peer1.sock
29
diff --git a/src/transport/test_quota_compliance_udp_peer2.conf b/src/transport/test_quota_compliance_udp_peer2.conf
deleted file mode 100644
index 1cb04038c..000000000
--- a/src/transport/test_quota_compliance_udp_peer2.conf
+++ /dev/null
@@ -1,30 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test_quota_compliance_peer2
4
5[transport-udp]
6PORT = 53368
7MAX_BPS = 50000000
8
9[arm]
10PORT = 53087
11UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_udp_arm_peer2.sock
12
13[statistics]
14PORT = 53088
15UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_udp_statistics_peer2.sock
16
17[resolver]
18PORT = 53089
19UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_udp_resolver_peer2.sock
20
21[peerinfo]
22PORT = 53090
23UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_udp_peerinfo_peer2.sock
24
25[transport]
26PORT = 53091
27PLUGINS = udp
28UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_udp_transport_peer2.sock
29
30
diff --git a/src/transport/test_quota_compliance_unix_asymmetric_peer1.conf b/src/transport/test_quota_compliance_unix_asymmetric_peer1.conf
deleted file mode 100644
index a8ee6d77a..000000000
--- a/src/transport/test_quota_compliance_unix_asymmetric_peer1.conf
+++ /dev/null
@@ -1,28 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test_quota_compliance_peer1/
4
5[arm]
6PORT = 54087
7UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_unix_arm_peer1.sock
8
9[statistics]
10PORT = 54088
11UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_unix_statistics_peer1.sock
12
13[resolver]
14PORT = 54089
15UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_unix_resolver_peer1.sock
16
17[peerinfo]
18PORT = 54090
19UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_unix_peerinfo_peer1.sock
20
21[transport]
22PORT = 54091
23PLUGINS = unix
24UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_unix_transport_peer1.sock
25
26[transport-unix]
27PORT = 54092
28
diff --git a/src/transport/test_quota_compliance_unix_asymmetric_peer2.conf b/src/transport/test_quota_compliance_unix_asymmetric_peer2.conf
deleted file mode 100644
index 6edbcac9f..000000000
--- a/src/transport/test_quota_compliance_unix_asymmetric_peer2.conf
+++ /dev/null
@@ -1,28 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test_quota_compliance_peer2
4
5[arm]
6PORT = 53087
7UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_unix_arm_peer2.sock
8
9[statistics]
10PORT = 53088
11UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_unix_statistics_peer2.sock
12
13[resolver]
14PORT = 53089
15UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_unix_resolver_peer2.sock
16
17[peerinfo]
18PORT = 53090
19UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_unix_peerinfo_peer2.sock
20
21[transport]
22PORT = 53091
23PLUGINS = unix
24UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_unix_transport_peer2.sock
25
26[transport-unix]
27PORT = 53368
28
diff --git a/src/transport/test_quota_compliance_unix_peer1.conf b/src/transport/test_quota_compliance_unix_peer1.conf
deleted file mode 100644
index 59c8d6d9e..000000000
--- a/src/transport/test_quota_compliance_unix_peer1.conf
+++ /dev/null
@@ -1,27 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test_quota_compliance_peer1/
4
5[transport-unix]
6PORT = 12120
7
8[arm]
9PORT = 54087
10UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_unix_arm_peer1.sock
11
12[statistics]
13PORT = 54088
14UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_unix_statistics_peer1.sock
15
16[resolver]
17PORT = 54089
18UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_unix_resolver_peer1.sock
19
20[peerinfo]
21PORT = 54090
22UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_unix_peerinfo_peer1.sock
23
24[transport]
25PORT = 54091
26PLUGINS = unix
27UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_unix_transport_peer1.sock
diff --git a/src/transport/test_quota_compliance_unix_peer2.conf b/src/transport/test_quota_compliance_unix_peer2.conf
deleted file mode 100644
index 8c2f9989e..000000000
--- a/src/transport/test_quota_compliance_unix_peer2.conf
+++ /dev/null
@@ -1,31 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test_quota_compliance_peer2
4
5[transport-unix]
6PORT = 12136
7
8[arm]
9PORT = 53087
10UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_unix_arm_peer2.sock
11
12[statistics]
13PORT = 53088
14UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_unix_statistics_peer2.sock
15
16[resolver]
17PORT = 53089
18UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_unix_resolver_peer2.sock
19
20[peerinfo]
21PORT = 53090
22UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_unix_peerinfo_peer2.sock
23
24[transport]
25PORT = 53091
26PLUGINS = unix
27UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_unix_transport_peer2.sock
28
29[transport-unix]
30PORT = 53368
31
diff --git a/src/transport/test_quota_compliance_wlan_asymmetric_peer1.conf b/src/transport/test_quota_compliance_wlan_asymmetric_peer1.conf
deleted file mode 100644
index 78e280b68..000000000
--- a/src/transport/test_quota_compliance_wlan_asymmetric_peer1.conf
+++ /dev/null
@@ -1,29 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-wlan-p1/
4
5[transport-wlan]
6TESTMODE = 1
7
8[arm]
9PORT = 12164
10UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
11
12[statistics]
13PORT = 12163
14UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
15
16[resolver]
17PORT = 12162
18UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
19
20[peerinfo]
21PORT = 12161
22UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
23
24[transport]
25PORT = 12160
26PLUGINS = wlan
27UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
28
29
diff --git a/src/transport/test_quota_compliance_wlan_asymmetric_peer2.conf b/src/transport/test_quota_compliance_wlan_asymmetric_peer2.conf
deleted file mode 100644
index e97ab3f38..000000000
--- a/src/transport/test_quota_compliance_wlan_asymmetric_peer2.conf
+++ /dev/null
@@ -1,29 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-wlan-p2/
4
5[transport-wlan]
6INTERFACE = mon1
7TESTMODE = 2
8
9[arm]
10PORT = 12174
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
12
13[statistics]
14PORT = 12173
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
16
17[resolver]
18PORT = 12172
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
20
21[peerinfo]
22PORT = 12171
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
24
25[transport]
26PORT = 12170
27PLUGINS = wlan
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
29
diff --git a/src/transport/test_quota_compliance_wlan_peer1.conf b/src/transport/test_quota_compliance_wlan_peer1.conf
deleted file mode 100644
index 78e280b68..000000000
--- a/src/transport/test_quota_compliance_wlan_peer1.conf
+++ /dev/null
@@ -1,29 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-wlan-p1/
4
5[transport-wlan]
6TESTMODE = 1
7
8[arm]
9PORT = 12164
10UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
11
12[statistics]
13PORT = 12163
14UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
15
16[resolver]
17PORT = 12162
18UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
19
20[peerinfo]
21PORT = 12161
22UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
23
24[transport]
25PORT = 12160
26PLUGINS = wlan
27UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
28
29
diff --git a/src/transport/test_quota_compliance_wlan_peer2.conf b/src/transport/test_quota_compliance_wlan_peer2.conf
deleted file mode 100644
index e97ab3f38..000000000
--- a/src/transport/test_quota_compliance_wlan_peer2.conf
+++ /dev/null
@@ -1,29 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-wlan-p2/
4
5[transport-wlan]
6INTERFACE = mon1
7TESTMODE = 2
8
9[arm]
10PORT = 12174
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
12
13[statistics]
14PORT = 12173
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
16
17[resolver]
18PORT = 12172
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
20
21[peerinfo]
22PORT = 12171
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
24
25[transport]
26PORT = 12170
27PLUGINS = wlan
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
29
diff --git a/src/transport/test_transport_address_switch_http_peer1.conf b/src/transport/test_transport_address_switch_http_peer1.conf
deleted file mode 100644
index b48c5f47f..000000000
--- a/src/transport/test_transport_address_switch_http_peer1.conf
+++ /dev/null
@@ -1,26 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
4
5[ats]
6UNSPECIFIED_QUOTA_IN = 8 KiB
7UNSPECIFIED_QUOTA_OUT = 8 KiB
8# LOOPBACK
9LOOPBACK_QUOTA_IN = 8 KiB
10LOOPBACK_QUOTA_OUT = 8 KiB
11# LAN
12LAN_QUOTA_IN = 8 KiB
13LAN_QUOTA_OUT = 8 KiB
14# WAN
15WAN_QUOTA_IN = 8 KiB
16WAN_QUOTA_OUT = 8 KiB
17# WLAN
18WLAN_QUOTA_IN = 8 KiB
19WLAN_QUOTA_OUT = 8 KiB
20# BLUETOOTH
21BLUETOOTH_QUOTA_IN = 8 KiB
22BLUETOOTH_QUOTA_OUT = 8 KiB
23
24[transport]
25PLUGINS = http_server http_client
26
diff --git a/src/transport/test_transport_address_switch_http_peer2.conf b/src/transport/test_transport_address_switch_http_peer2.conf
deleted file mode 100644
index be8fb506c..000000000
--- a/src/transport/test_transport_address_switch_http_peer2.conf
+++ /dev/null
@@ -1,26 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
4
5[ats]
6UNSPECIFIED_QUOTA_IN = 8 KiB
7UNSPECIFIED_QUOTA_OUT = 8 KiB
8# LOOPBACK
9LOOPBACK_QUOTA_IN = 8 KiB
10LOOPBACK_QUOTA_OUT = 8 KiB
11# LAN
12LAN_QUOTA_IN = 8 KiB
13LAN_QUOTA_OUT = 8 KiB
14# WAN
15WAN_QUOTA_IN = 8 KiB
16WAN_QUOTA_OUT = 8 KiB
17# WLAN
18WLAN_QUOTA_IN = 8 KiB
19WLAN_QUOTA_OUT = 8 KiB
20# BLUETOOTH
21BLUETOOTH_QUOTA_IN = 8 KiB
22BLUETOOTH_QUOTA_OUT = 8 KiB
23
24[transport]
25PLUGINS = http_client http_server
26
diff --git a/src/transport/test_transport_address_switch_https_peer1.conf b/src/transport/test_transport_address_switch_https_peer1.conf
deleted file mode 100644
index 1f9210130..000000000
--- a/src/transport/test_transport_address_switch_https_peer1.conf
+++ /dev/null
@@ -1,44 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
4
5[ats]
6UNSPECIFIED_QUOTA_IN = 8 KiB
7UNSPECIFIED_QUOTA_OUT = 8 KiB
8# LOOPBACK
9LOOPBACK_QUOTA_IN = 8 KiB
10LOOPBACK_QUOTA_OUT = 8 KiB
11# LAN
12LAN_QUOTA_IN = 8 KiB
13LAN_QUOTA_OUT = 8 KiB
14# WAN
15WAN_QUOTA_IN = 8 KiB
16WAN_QUOTA_OUT = 8 KiB
17# WLAN
18WLAN_QUOTA_IN = 8 KiB
19WLAN_QUOTA_OUT = 8 KiB
20# BLUETOOTH
21BLUETOOTH_QUOTA_IN = 8 KiB
22BLUETOOTH_QUOTA_OUT = 8 KiB
23
24[arm]
25PORT = 12005
26UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
27
28[statistics]
29PORT = 12004
30UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
31
32[resolver]
33PORT = 12003
34UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
35
36[peerinfo]
37PORT = 12002
38UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
39
40[transport]
41PORT = 12001
42UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
43PLUGINS = https_client https_server
44
diff --git a/src/transport/test_transport_address_switch_https_peer2.conf b/src/transport/test_transport_address_switch_https_peer2.conf
deleted file mode 100644
index c58839868..000000000
--- a/src/transport/test_transport_address_switch_https_peer2.conf
+++ /dev/null
@@ -1,44 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
4
5[ats]
6UNSPECIFIED_QUOTA_IN = 8 KiB
7UNSPECIFIED_QUOTA_OUT = 8 KiB
8# LOOPBACK
9LOOPBACK_QUOTA_IN = 8 KiB
10LOOPBACK_QUOTA_OUT = 8 KiB
11# LAN
12LAN_QUOTA_IN = 8 KiB
13LAN_QUOTA_OUT = 8 KiB
14# WAN
15WAN_QUOTA_IN = 8 KiB
16WAN_QUOTA_OUT = 8 KiB
17# WLAN
18WLAN_QUOTA_IN = 8 KiB
19WLAN_QUOTA_OUT = 8 KiB
20# BLUETOOTH
21BLUETOOTH_QUOTA_IN = 8 KiB
22BLUETOOTH_QUOTA_OUT = 8 KiB
23
24[arm]
25PORT = 12014
26UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
27
28[statistics]
29PORT = 12013
30UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
31
32[resolver]
33PORT = 12012
34UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
35
36[peerinfo]
37PORT = 12011
38UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
39
40[transport]
41PORT = 12010
42PLUGINS = https_client https_server
43UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
44
diff --git a/src/transport/test_transport_api_blacklisting.c b/src/transport/test_transport_api_blacklisting.c
deleted file mode 100644
index 2ba88a863..000000000
--- a/src/transport/test_transport_api_blacklisting.c
+++ /dev/null
@@ -1,206 +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 it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/test_transport_api_blacklisting.c
23 * @brief test for the blacklisting API
24 * @author Matthias Wachs
25 * @author Christian Grothoff
26 */
27#include "platform.h"
28#include "gnunet_transport_service.h"
29#include "transport-testing.h"
30
31#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
32
33static struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
34
35static int connected;
36
37static int blacklist_request_p1;
38
39static int blacklist_request_p2;
40
41static struct GNUNET_TRANSPORT_Blacklist *blacklist_p1;
42
43static struct GNUNET_TRANSPORT_Blacklist *blacklist_p2;
44
45static struct GNUNET_SCHEDULER_Task *shutdown_task;
46
47
48static void
49end (void *cls)
50{
51 shutdown_task = NULL;
52 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
53 "Stopping\n");
54 if ((GNUNET_YES == blacklist_request_p1) &&
55 (GNUNET_YES == blacklist_request_p2) &&
56 (GNUNET_NO == connected))
57 {
58 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
59 "Peers were never connected, success\n");
60 ccc->global_ret = GNUNET_OK;
61 }
62 else
63 {
64 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
65 "Peers were not connected, fail\n");
66 ccc->global_ret = GNUNET_SYSERR;
67 }
68 GNUNET_SCHEDULER_shutdown ();
69}
70
71
72static void
73custom_shutdown (void *cls)
74{
75 if (NULL != shutdown_task)
76 {
77 GNUNET_SCHEDULER_cancel (shutdown_task);
78 shutdown_task = NULL;
79 }
80 if (NULL != blacklist_p1)
81 {
82 GNUNET_TRANSPORT_blacklist_cancel (blacklist_p1);
83 blacklist_p1 = NULL;
84 }
85 if (NULL != blacklist_p2)
86 {
87 GNUNET_TRANSPORT_blacklist_cancel (blacklist_p2);
88 blacklist_p2 = NULL;
89 }
90}
91
92
93static void
94notify_receive (void *cls,
95 struct GNUNET_TRANSPORT_TESTING_PeerContext *receiver,
96 const struct GNUNET_PeerIdentity *sender,
97 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
98{
99 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
100 "Unexpectedly even received the message despite blacklist\n");
101 connected = GNUNET_YES;
102 GNUNET_SCHEDULER_cancel (shutdown_task);
103 end (NULL);
104}
105
106
107static void
108notify_connect (void *cls,
109 struct GNUNET_TRANSPORT_TESTING_PeerContext *me,
110 const struct GNUNET_PeerIdentity *other)
111{
112 GNUNET_TRANSPORT_TESTING_log_connect (cls,
113 me,
114 other);
115 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
116 "Peers connected despite blacklist!\n");
117 connected = GNUNET_YES; /* this test now failed */
118 GNUNET_SCHEDULER_cancel (shutdown_task);
119 end (NULL);
120}
121
122
123static int
124blacklist_cb (void *cls,
125 const struct GNUNET_PeerIdentity *pid)
126{
127 struct GNUNET_TRANSPORT_TESTING_PeerContext *p = cls;
128 int res = GNUNET_SYSERR;
129
130 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
131 "Peer %u: Blacklist request for peer `%s'\n",
132 p->no,
133 GNUNET_i2s (pid));
134
135 if (p == ccc->p[0])
136 {
137 blacklist_request_p1 = GNUNET_YES;
138 res = GNUNET_OK;
139 }
140 if (p == ccc->p[1])
141 {
142 blacklist_request_p2 = GNUNET_YES;
143 res = GNUNET_SYSERR;
144 }
145
146 if ((GNUNET_YES == blacklist_request_p2) &&
147 (GNUNET_YES == blacklist_request_p1) &&
148 (NULL == shutdown_task))
149 {
150 shutdown_task
151 = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (
152 GNUNET_TIME_UNIT_SECONDS, 3),
153 &end,
154 NULL);
155 }
156 return res;
157}
158
159
160static void
161start_blacklist (void *cls)
162{
163 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
164 "Starting blacklists\n");
165 blacklist_p1 = GNUNET_TRANSPORT_blacklist (ccc->p[0]->cfg,
166 &blacklist_cb,
167 ccc->p[0]);
168 GNUNET_assert (NULL != blacklist_p1);
169 blacklist_p2 = GNUNET_TRANSPORT_blacklist (ccc->p[1]->cfg,
170 &blacklist_cb,
171 ccc->p[1]);
172 GNUNET_assert (NULL != blacklist_p2);
173}
174
175
176int
177main (int argc,
178 char *argv[])
179{
180 struct GNUNET_TRANSPORT_TESTING_SendClosure sc = {
181 .num_messages = 1
182 };
183 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext my_ccc = {
184 .pre_connect_task = &start_blacklist,
185 .connect_continuation = &GNUNET_TRANSPORT_TESTING_simple_send,
186 .connect_continuation_cls = &sc,
187 .config_file = "test_transport_api_data.conf",
188 .rec = &notify_receive,
189 .nc = &notify_connect,
190 .nd = &GNUNET_TRANSPORT_TESTING_log_disconnect,
191 .shutdown_task = &custom_shutdown,
192 .timeout = TIMEOUT,
193 .bi_directional = GNUNET_YES
194 };
195
196 ccc = &my_ccc;
197 if (GNUNET_OK !=
198 GNUNET_TRANSPORT_TESTING_main (2,
199 &GNUNET_TRANSPORT_TESTING_connect_check,
200 ccc))
201 return 1;
202 return 0;
203}
204
205
206/* end of transport_api_blacklisting.c */
diff --git a/src/transport/test_transport_api_blacklisting_tcp_peer1.conf b/src/transport/test_transport_api_blacklisting_tcp_peer1.conf
deleted file mode 100644
index eabd6b701..000000000
--- a/src/transport/test_transport_api_blacklisting_tcp_peer1.conf
+++ /dev/null
@@ -1,9 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
4
5[transport]
6PLUGINS = tcp
7
8#[transport]
9#PREFIX = valgrind
diff --git a/src/transport/test_transport_api_blacklisting_tcp_peer2.conf b/src/transport/test_transport_api_blacklisting_tcp_peer2.conf
deleted file mode 100644
index 58ce0777f..000000000
--- a/src/transport/test_transport_api_blacklisting_tcp_peer2.conf
+++ /dev/null
@@ -1,9 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
4
5[transport]
6PLUGINS = tcp
7
8#[transport]
9#PREFIX = valgrind
diff --git a/src/transport/test_transport_api_bluetooth_peer1.conf b/src/transport/test_transport_api_bluetooth_peer1.conf
deleted file mode 100644
index b1209e44b..000000000
--- a/src/transport/test_transport_api_bluetooth_peer1.conf
+++ /dev/null
@@ -1,10 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-bluetooth-p1/
4
5[transport-bluetooth]
6INTERFACE = hci0
7TESTMODE = 1
8
9[transport]
10PLUGINS = bluetooth
diff --git a/src/transport/test_transport_api_bluetooth_peer2.conf b/src/transport/test_transport_api_bluetooth_peer2.conf
deleted file mode 100644
index 371a5d3b0..000000000
--- a/src/transport/test_transport_api_bluetooth_peer2.conf
+++ /dev/null
@@ -1,10 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-bluetooth-p2/
4
5[transport-bluetooth]
6INTERFACE = hci1
7TESTMODE = 2
8
9[transport]
10PLUGINS = bluetooth
diff --git a/src/transport/test_transport_api_disconnect.c b/src/transport/test_transport_api_disconnect.c
deleted file mode 100644
index c469f28bc..000000000
--- a/src/transport/test_transport_api_disconnect.c
+++ /dev/null
@@ -1,134 +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 it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport/test_transport_api_disconnect.c
22 * @brief base test case for transport implementations
23 *
24 * This test case tests disconnect notifications in peer shutdown.
25 * Starts two peers, has them connect, sends a message in between,
26 * stops one peer, expects the others to send a disconnect notification.
27 */
28#include "platform.h"
29#include "gnunet_transport_service.h"
30#include "transport-testing.h"
31
32/**
33 * How long until we give up on transmitting the message?
34 */
35#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120)
36
37
38static struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
39
40static int shutdown_;
41
42
43static void
44notify_disconnect (void *cls,
45 struct GNUNET_TRANSPORT_TESTING_PeerContext *me,
46 const struct GNUNET_PeerIdentity *other)
47{
48 if (me != ccc->p[0])
49 return;
50 GNUNET_TRANSPORT_TESTING_log_disconnect (cls,
51 me,
52 other);
53 if (GNUNET_YES == shutdown_)
54 {
55 ccc->global_ret = GNUNET_OK;
56 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
57 "Test good, shutting down...\n");
58 GNUNET_SCHEDULER_shutdown ();
59 }
60}
61
62
63static void
64stop_peer (void *cls)
65{
66 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
67 "Shutting down peer %u (`%s')\n",
68 ccc->p[1]->no,
69 GNUNET_i2s (&ccc->p[1]->id));
70 shutdown_ = GNUNET_YES;
71 GNUNET_TRANSPORT_TESTING_stop_peer (ccc->p[1]);
72 ccc->p[1] = NULL;
73}
74
75
76static void
77notify_receive (void *cls,
78 struct GNUNET_TRANSPORT_TESTING_PeerContext *receiver,
79 const struct GNUNET_PeerIdentity *sender,
80 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
81{
82 {
83 char *ps = GNUNET_strdup (GNUNET_i2s (&receiver->id));
84
85 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
86 "Peer %u (`%s') received message of type %d and size %u size from peer %s!\n",
87 receiver->no,
88 ps,
89 ntohs (message->header.type),
90 ntohs (message->header.size),
91 GNUNET_i2s (sender));
92 GNUNET_free (ps);
93 }
94 if ((GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE == ntohs (message->header.type)) &&
95 (sizeof(struct GNUNET_TRANSPORT_TESTING_TestMessage) == ntohs (
96 message->header.size)))
97 {
98 GNUNET_SCHEDULER_add_now (&stop_peer,
99 NULL);
100 return;
101 }
102}
103
104
105int
106main (int argc,
107 char *argv[])
108{
109 struct GNUNET_TRANSPORT_TESTING_SendClosure sc = {
110 .num_messages = 1
111 };
112 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext my_ccc = {
113 .connect_continuation = &GNUNET_TRANSPORT_TESTING_simple_send,
114 .connect_continuation_cls = &sc,
115 .config_file = "test_transport_api_data.conf",
116 .rec = &notify_receive,
117 .nc = &GNUNET_TRANSPORT_TESTING_log_connect,
118 .nd = &notify_disconnect,
119 .timeout = TIMEOUT,
120 .global_ret = GNUNET_SYSERR
121 };
122
123 ccc = &my_ccc;
124 sc.ccc = ccc;
125 if (GNUNET_OK !=
126 GNUNET_TRANSPORT_TESTING_main (2,
127 &GNUNET_TRANSPORT_TESTING_connect_check,
128 ccc))
129 return 1;
130 return 0;
131}
132
133
134/* end of test_transport_api_disconnect.c */
diff --git a/src/transport/test_transport_api_disconnect_tcp_peer1.conf b/src/transport/test_transport_api_disconnect_tcp_peer1.conf
deleted file mode 100644
index 8530ba310..000000000
--- a/src/transport/test_transport_api_disconnect_tcp_peer1.conf
+++ /dev/null
@@ -1,7 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
4
5[transport]
6PLUGINS = tcp
7
diff --git a/src/transport/test_transport_api_disconnect_tcp_peer2.conf b/src/transport/test_transport_api_disconnect_tcp_peer2.conf
deleted file mode 100644
index ce9c2f885..000000000
--- a/src/transport/test_transport_api_disconnect_tcp_peer2.conf
+++ /dev/null
@@ -1,8 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
4
5[transport]
6PLUGINS = tcp
7
8
diff --git a/src/transport/test_transport_api_http_peer1.conf b/src/transport/test_transport_api_http_peer1.conf
deleted file mode 100644
index 2a622ae02..000000000
--- a/src/transport/test_transport_api_http_peer1.conf
+++ /dev/null
@@ -1,6 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-http-p1/
4
5[transport]
6PLUGINS = http_client
diff --git a/src/transport/test_transport_api_http_peer2.conf b/src/transport/test_transport_api_http_peer2.conf
deleted file mode 100644
index aca41804b..000000000
--- a/src/transport/test_transport_api_http_peer2.conf
+++ /dev/null
@@ -1,6 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-http-p2/
4
5[transport]
6PLUGINS = http_server
diff --git a/src/transport/test_transport_api_http_reverse_peer1.conf b/src/transport/test_transport_api_http_reverse_peer1.conf
deleted file mode 100644
index 67640d7bb..000000000
--- a/src/transport/test_transport_api_http_reverse_peer1.conf
+++ /dev/null
@@ -1,11 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-http-p1/
4
5[transport]
6PLUGINS = http_client
7
8[ats]
9WAN_QUOTA_IN = unlimited
10WAN_QUOTA_OUT = unlimited
11
diff --git a/src/transport/test_transport_api_http_reverse_peer2.conf b/src/transport/test_transport_api_http_reverse_peer2.conf
deleted file mode 100644
index 0e7a2ea05..000000000
--- a/src/transport/test_transport_api_http_reverse_peer2.conf
+++ /dev/null
@@ -1,12 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-http-p2/
4
5[transport-http_server]
6PORT = 8080
7EXTERNAL_HOSTNAME = fulcrum.net.in.tum.de/gnunet
8EXTERNAL_HOSTNAME_ONLY = YES
9
10[transport]
11PLUGINS = http_server
12
diff --git a/src/transport/test_transport_api_https_peer1.conf b/src/transport/test_transport_api_https_peer1.conf
deleted file mode 100644
index 55d119259..000000000
--- a/src/transport/test_transport_api_https_peer1.conf
+++ /dev/null
@@ -1,26 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-https-p1/
4
5[arm]
6PORT = 12105
7
8[statistics]
9PORT = 12104
10UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
11
12[resolver]
13PORT = 12103
14UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
15
16[peerinfo]
17PORT = 12102
18UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
19
20[transport]
21PORT = 12101
22PLUGINS = https_client
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
24#PREFIX = valgrind
25
26
diff --git a/src/transport/test_transport_api_https_peer2.conf b/src/transport/test_transport_api_https_peer2.conf
deleted file mode 100644
index 3b1d55b0a..000000000
--- a/src/transport/test_transport_api_https_peer2.conf
+++ /dev/null
@@ -1,32 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-https-p2/
4
5[transport-https_server]
6EXTERNAL_HOSTNAME = localhost
7EXTERNAL_HOSTNAME_ONLY = yes
8EXTERNAL_HOSTNAME_USE_PORT = YES
9
10[arm]
11PORT = 12115
12UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
13
14[statistics]
15PORT = 12114
16UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
17
18[resolver]
19PORT = 12113
20UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
21
22[peerinfo]
23PORT = 12112
24UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
25
26[transport]
27PORT = 12111
28PLUGINS = https_server
29UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
30#PREFIX = valgrind
31
32
diff --git a/src/transport/test_transport_api_limited_sockets.c b/src/transport/test_transport_api_limited_sockets.c
deleted file mode 100644
index 0e47800e8..000000000
--- a/src/transport/test_transport_api_limited_sockets.c
+++ /dev/null
@@ -1,132 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport/test_transport_api_limited_sockets.c
22 * @brief base test case for transport implementations
23 *
24 * This test case serves as a base for tcp, udp, and udp-nat
25 * transport test cases. Based on the executable being run
26 * the correct test case will be performed. Conservation of
27 * C code apparently.
28 */
29#include "platform.h"
30#include "gnunet_transport_service.h"
31#include "transport-testing.h"
32
33/**
34 * How long until we give up on transmitting the message?
35 */
36#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300)
37
38#define MAX_FILES 50
39
40
41#if HAVE_SETRLIMIT
42
43static struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
44
45
46static void
47notify_receive (void *cls,
48 struct GNUNET_TRANSPORT_TESTING_PeerContext *receiver,
49 const struct GNUNET_PeerIdentity *sender,
50 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
51{
52 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
53 "Received message of type %d from peer %s!\n",
54 ntohs (message->header.type),
55 GNUNET_i2s (sender));
56 if ((GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE ==
57 ntohs (message->header.type)) &&
58 (sizeof(struct GNUNET_TRANSPORT_TESTING_TestMessage) ==
59 ntohs (message->header.size)))
60 {
61 ccc->global_ret = GNUNET_OK;
62 }
63 else
64 {
65 GNUNET_break (0);
66 }
67 GNUNET_SCHEDULER_shutdown ();
68}
69
70
71int
72main (int argc, char *argv[])
73{
74 struct GNUNET_TRANSPORT_TESTING_SendClosure sc = {
75 .num_messages = 1
76 };
77 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext my_ccc = {
78 .connect_continuation = &GNUNET_TRANSPORT_TESTING_simple_send,
79 .connect_continuation_cls = &sc,
80 .config_file = "test_transport_api_data.conf",
81 .rec = &notify_receive,
82 .nc = &GNUNET_TRANSPORT_TESTING_log_connect,
83 .nd = &GNUNET_TRANSPORT_TESTING_log_disconnect,
84 .timeout = TIMEOUT,
85 .global_ret = GNUNET_SYSERR
86 };
87 struct rlimit r_file_old;
88 struct rlimit r_file_new;
89 int res;
90
91 sc.ccc = &my_ccc;
92 res = getrlimit (RLIMIT_NOFILE,
93 &r_file_old);
94 r_file_new.rlim_cur = MAX_FILES;
95 r_file_new.rlim_max = r_file_old.rlim_max;
96 res = setrlimit (RLIMIT_NOFILE,
97 &r_file_new);
98 if (0 != res)
99 {
100 fprintf (stderr,
101 "Setting limit failed: %s\n",
102 strerror (errno));
103 return 77;
104 }
105
106 ccc = &my_ccc;
107 ccc->global_ret = GNUNET_SYSERR;
108 if (GNUNET_OK !=
109 GNUNET_TRANSPORT_TESTING_main (2,
110 &GNUNET_TRANSPORT_TESTING_connect_check,
111 ccc))
112 return 1;
113 return 0;
114}
115
116
117#else
118/* cannot setrlimit */
119
120
121int
122main (int argc, char *argv[])
123{
124 fprintf (stderr,
125 "Cannot run test on this system\n");
126 return 77;
127}
128
129
130#endif
131
132/* end of test_transport_api_limited_sockets.c */
diff --git a/src/transport/test_transport_api_limited_sockets_tcp_peer1.conf b/src/transport/test_transport_api_limited_sockets_tcp_peer1.conf
deleted file mode 100644
index e0ad5f847..000000000
--- a/src/transport/test_transport_api_limited_sockets_tcp_peer1.conf
+++ /dev/null
@@ -1,7 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2@INLINE@ ../../contrib/conf/gnunet/no_autostart_above_core.conf
3[PATHS]
4GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
5
6[transport]
7PLUGINS = tcp
diff --git a/src/transport/test_transport_api_limited_sockets_tcp_peer2.conf b/src/transport/test_transport_api_limited_sockets_tcp_peer2.conf
deleted file mode 100644
index bb466abba..000000000
--- a/src/transport/test_transport_api_limited_sockets_tcp_peer2.conf
+++ /dev/null
@@ -1,8 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2@INLINE@ ../../contrib/conf/gnunet/no_autostart_above_core.conf
3
4[PATHS]
5GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
6
7[transport]
8PLUGINS = tcp
diff --git a/src/transport/test_transport_api_manipulation_cfg.c b/src/transport/test_transport_api_manipulation_cfg.c
deleted file mode 100644
index 73c81114e..000000000
--- a/src/transport/test_transport_api_manipulation_cfg.c
+++ /dev/null
@@ -1,186 +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 it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport/test_transport_api_manipulation_cfg.c
22 * @brief base test case for transport traffic manipulation implementation
23 * based on cfg
24 *
25 * Peer 1 has inbound and outbound delay of 100ms
26 * Peer 2 has no inbound and outbound delay
27 *
28 * We send a request from P1 to P2 and expect delay of >= TEST_DELAY us
29 * Then we send response from P2 to P1 and expect delay of >= TEST_DELAY us
30 */
31#include "platform.h"
32#include "gnunet_transport_service.h"
33#include "transport-testing.h"
34
35/**
36 * How long until we give up on transmitting the message?
37 */
38#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120)
39
40
41#define TEST_MESSAGE_SIZE 2600
42
43#define TEST_RESPONSE_MESSAGE_TYPE
44
45/**
46 * Test delay, in microseconds.
47 */
48#define TEST_DELAY 100 * 1000LL
49
50
51static struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
52
53static struct GNUNET_TIME_Absolute start_request;
54
55static struct GNUNET_TIME_Absolute start_response;
56
57
58static void
59sendtask_response_task (void *cls)
60{
61 int ret;
62
63 start_response = GNUNET_TIME_absolute_get ();
64 ret = GNUNET_TRANSPORT_TESTING_send (ccc->p[1],
65 ccc->p[0],
66 GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE2,
67 TEST_MESSAGE_SIZE,
68 1,
69 NULL,
70 NULL);
71 if (GNUNET_NO == ret)
72 {
73 GNUNET_break (0);
74 GNUNET_SCHEDULER_shutdown ();
75 return;
76 }
77 GNUNET_assert (GNUNET_SYSERR != ret);
78}
79
80
81static void
82notify_receive (void *cls,
83 struct GNUNET_TRANSPORT_TESTING_PeerContext *receiver,
84 const struct GNUNET_PeerIdentity *sender,
85 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
86{
87 struct GNUNET_TIME_Relative duration;
88
89 {
90 char *ps = GNUNET_strdup (GNUNET_i2s (&receiver->id));
91
92 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
93 "Peer %u (`%s') received message of type %d and size %u size from peer %s)!\n",
94 receiver->no,
95 ps,
96 ntohs (message->header.type),
97 ntohs (message->header.size),
98 GNUNET_i2s (sender));
99 GNUNET_free (ps);
100 }
101
102 switch (ntohs (message->header.type))
103 {
104 case GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE:
105 duration = GNUNET_TIME_absolute_get_difference (start_request,
106 GNUNET_TIME_absolute_get ());
107 if (duration.rel_value_us >= TEST_DELAY)
108 {
109 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
110 "Request message was delayed for %s\n",
111 GNUNET_STRINGS_relative_time_to_string (duration,
112 GNUNET_YES));
113 }
114 else
115 {
116 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
117 "Request message was delayed for unexpected duration %s\n",
118 GNUNET_STRINGS_relative_time_to_string (duration,
119 GNUNET_YES));
120 ccc->global_ret = GNUNET_SYSERR;
121 GNUNET_SCHEDULER_shutdown ();
122 }
123 /* Send response */
124 GNUNET_SCHEDULER_add_now (&sendtask_response_task,
125 NULL);
126 return;
127
128 case GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE2:
129 duration = GNUNET_TIME_absolute_get_difference (start_response,
130 GNUNET_TIME_absolute_get ());
131 if (duration.rel_value_us >= TEST_DELAY)
132 {
133 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
134 "Response message was delayed for %s\n",
135 GNUNET_STRINGS_relative_time_to_string (duration,
136 GNUNET_YES));
137 ccc->global_ret = GNUNET_OK;
138 }
139 else
140 {
141 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
142 "Response message was delayed for unexpected duration %s\n",
143 GNUNET_STRINGS_relative_time_to_string (duration,
144 GNUNET_YES));
145 ccc->global_ret = GNUNET_SYSERR;
146 }
147 GNUNET_SCHEDULER_shutdown ();
148 break;
149
150 default:
151 GNUNET_break (0);
152 break;
153 }
154}
155
156
157int
158main (int argc,
159 char *argv[])
160{
161 struct GNUNET_TRANSPORT_TESTING_SendClosure sc = {
162 .num_messages = 1
163 };
164 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext my_ccc = {
165 .connect_continuation = &GNUNET_TRANSPORT_TESTING_large_send,
166 .connect_continuation_cls = &sc,
167 .config_file = "test_transport_api_data.conf",
168 .rec = &notify_receive,
169 .nc = &GNUNET_TRANSPORT_TESTING_log_connect,
170 .nd = &GNUNET_TRANSPORT_TESTING_log_disconnect,
171 .timeout = TIMEOUT
172 };
173
174 ccc = &my_ccc;
175 sc.ccc = ccc;
176 start_request = GNUNET_TIME_absolute_get ();
177 if (GNUNET_OK !=
178 GNUNET_TRANSPORT_TESTING_main (2,
179 &GNUNET_TRANSPORT_TESTING_connect_check,
180 ccc))
181 return 1;
182 return 0;
183}
184
185
186/* end of test_transport_api_manipulation_cfg.c */
diff --git a/src/transport/test_transport_api_manipulation_cfg_peer1.conf b/src/transport/test_transport_api_manipulation_cfg_peer1.conf
deleted file mode 100644
index 77cdce2e2..000000000
--- a/src/transport/test_transport_api_manipulation_cfg_peer1.conf
+++ /dev/null
@@ -1,8 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
4
5[transport]
6PLUGINS = tcp
7MANIPULATE_DELAY_IN = 100 ms
8MANIPULATE_DELAY_OUT = 100 ms
diff --git a/src/transport/test_transport_api_manipulation_cfg_peer2.conf b/src/transport/test_transport_api_manipulation_cfg_peer2.conf
deleted file mode 100644
index 9cbaaddef..000000000
--- a/src/transport/test_transport_api_manipulation_cfg_peer2.conf
+++ /dev/null
@@ -1,8 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
4
5[transport]
6PLUGINS = tcp
7#MANIPULATE_DELAY_IN = 0 ms
8#MANIPULATE_DELAY_OUT = 0 ms
diff --git a/src/transport/test_transport_api_manipulation_recv_tcp.c b/src/transport/test_transport_api_manipulation_recv_tcp.c
deleted file mode 100644
index 207c4416f..000000000
--- a/src/transport/test_transport_api_manipulation_recv_tcp.c
+++ /dev/null
@@ -1,203 +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 it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport/test_transport_api_manipulation_recv_tcp.c
22 * @brief base test case for transport traffic manipulation implementation
23 *
24 * This test case will setup 2 peers and connect them, the first message
25 * will be sent without manipulation, then a receive delay of 1 second will
26 * be configured and 2 more message will be sent. Time will be measured
27 *
28 * In addition the distance on receiver side will be manipulated to be 10
29 */
30#include "platform.h"
31#include "gnunet_transport_service.h"
32#include "transport-testing.h"
33
34/**
35 * How long until we give up on transmitting the message?
36 */
37#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120)
38
39
40static struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
41
42static int messages_recv;
43
44static struct GNUNET_TIME_Absolute start_normal;
45
46static struct GNUNET_TIME_Relative dur_normal;
47
48static struct GNUNET_TIME_Absolute start_delayed;
49
50static struct GNUNET_TIME_Relative dur_delayed;
51
52
53static void
54do_free (void *cls)
55{
56 struct GNUNET_TRANSPORT_TESTING_SendClosure *sc = cls;
57
58 GNUNET_free (sc);
59}
60
61
62static void
63delayed_transmit (void *cls)
64{
65 struct GNUNET_TRANSPORT_TESTING_SendClosure *sc = cls;
66
67 start_delayed = GNUNET_TIME_absolute_get ();
68 GNUNET_TRANSPORT_TESTING_large_send (sc);
69}
70
71
72static void
73sendtask (void *cls)
74{
75 struct GNUNET_TRANSPORT_TESTING_SendClosure *sc;
76 struct GNUNET_ATS_Properties prop;
77 struct GNUNET_TIME_Relative delay;
78
79 sc = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_SendClosure);
80 sc->num_messages = 1;
81 sc->ccc = ccc;
82 sc->cont = &do_free;
83 sc->cont_cls = sc;
84 if (0 == messages_recv)
85 {
86 start_normal = GNUNET_TIME_absolute_get ();
87 }
88 if (0 < messages_recv)
89 {
90 memset (&prop,
91 0,
92 sizeof(prop));
93 delay = GNUNET_TIME_UNIT_SECONDS;
94 GNUNET_TRANSPORT_manipulation_set (ccc->p[1]->tmh,
95 &ccc->p[0]->id,
96 &prop,
97 delay,
98 GNUNET_TIME_UNIT_ZERO);
99 /* wait 1s to allow manipulation to go into effect */
100 if (1 == messages_recv)
101 {
102 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
103 &delayed_transmit,
104 sc);
105 return;
106 }
107 }
108 GNUNET_TRANSPORT_TESTING_large_send (sc);
109}
110
111
112static void
113notify_receive (void *cls,
114 struct GNUNET_TRANSPORT_TESTING_PeerContext *receiver,
115 const struct GNUNET_PeerIdentity *sender,
116 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
117{
118 {
119 char *ps = GNUNET_strdup (GNUNET_i2s (&receiver->id));
120
121 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
122 "Peer %u (`%s') received message of type %d and size %u size from peer %s)!\n",
123 receiver->no,
124 ps,
125 ntohs (message->header.type),
126 ntohs (message->header.size),
127 GNUNET_i2s (sender));
128 GNUNET_free (ps);
129 }
130 if ((GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE != ntohs (message->header.type)) ||
131 (GNUNET_TRANSPORT_TESTING_LARGE_MESSAGE_SIZE != ntohs (
132 message->header.size)))
133 {
134 GNUNET_break (0);
135 ccc->global_ret = GNUNET_SYSERR;
136 GNUNET_SCHEDULER_shutdown ();
137 return;
138 }
139
140 if (messages_recv <= 2)
141 {
142 /* Received non-delayed message */
143 dur_normal = GNUNET_TIME_absolute_get_duration (start_normal);
144 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
145 "Received non-delayed message %u after %s\n",
146 messages_recv,
147 GNUNET_STRINGS_relative_time_to_string (dur_normal,
148 GNUNET_YES));
149 GNUNET_SCHEDULER_add_now (&sendtask,
150 NULL);
151 messages_recv++;
152 return;
153 }
154 /* Received manipulated message */
155 dur_delayed = GNUNET_TIME_absolute_get_duration (start_delayed);
156 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
157 "Received delayed message %u after %s\n",
158 messages_recv,
159 GNUNET_STRINGS_relative_time_to_string (dur_delayed,
160 GNUNET_YES));
161 if (dur_delayed.rel_value_us < GNUNET_TIME_UNIT_SECONDS.rel_value_us)
162 {
163 GNUNET_break (0);
164 ccc->global_ret = GNUNET_SYSERR;
165 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
166 "Delayed message was not delayed correctly: took only %s\n",
167 GNUNET_STRINGS_relative_time_to_string (dur_delayed,
168 GNUNET_YES));
169 }
170 else
171 {
172 ccc->global_ret = GNUNET_OK;
173 }
174 /* shutdown */
175 GNUNET_SCHEDULER_shutdown ();
176}
177
178
179int
180main (int argc,
181 char *argv[])
182{
183 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext my_ccc = {
184 .connect_continuation = &sendtask,
185 .config_file = "test_transport_api_data.conf",
186 .rec = &notify_receive,
187 .nc = &GNUNET_TRANSPORT_TESTING_log_connect,
188 .nd = &GNUNET_TRANSPORT_TESTING_log_disconnect,
189 .timeout = TIMEOUT,
190 .global_ret = GNUNET_NO
191 };
192
193 ccc = &my_ccc;
194 if (GNUNET_OK !=
195 GNUNET_TRANSPORT_TESTING_main (2,
196 &GNUNET_TRANSPORT_TESTING_connect_check,
197 ccc))
198 return 1;
199 return 0;
200}
201
202
203/* end of test_transport_api_manipulation_recv_tcp.c */
diff --git a/src/transport/test_transport_api_manipulation_recv_tcp_peer1.conf b/src/transport/test_transport_api_manipulation_recv_tcp_peer1.conf
deleted file mode 100644
index 9150c7faf..000000000
--- a/src/transport/test_transport_api_manipulation_recv_tcp_peer1.conf
+++ /dev/null
@@ -1,29 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
4
5[transport-tcp]
6PORT = 12000
7TIMEOUT = 5 s
8
9[arm]
10PORT = 12005
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
12
13[statistics]
14PORT = 12004
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
16
17[resolver]
18PORT = 12003
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
20
21[peerinfo]
22PORT = 12002
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
24
25[transport]
26PORT = 12001
27UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
28PLUGINS = tcp
29
diff --git a/src/transport/test_transport_api_manipulation_recv_tcp_peer2.conf b/src/transport/test_transport_api_manipulation_recv_tcp_peer2.conf
deleted file mode 100644
index a7b2cf90b..000000000
--- a/src/transport/test_transport_api_manipulation_recv_tcp_peer2.conf
+++ /dev/null
@@ -1,29 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
4
5[transport-tcp]
6PORT = 12015
7TIMEOUT = 5 s
8
9[arm]
10PORT = 12014
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
12
13[statistics]
14PORT = 12013
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
16
17[resolver]
18PORT = 12012
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
20
21[peerinfo]
22PORT = 12011
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
24
25[transport]
26PORT = 12010
27PLUGINS = tcp
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
29
diff --git a/src/transport/test_transport_api_manipulation_send_tcp.c b/src/transport/test_transport_api_manipulation_send_tcp.c
deleted file mode 100644
index ea735cfc6..000000000
--- a/src/transport/test_transport_api_manipulation_send_tcp.c
+++ /dev/null
@@ -1,199 +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 it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport/test_transport_api_manipulation_send_tcp.c
22 * @brief base test case for transport traffic manipulation implementation
23 *
24 * This test case will setup 2 peers and connect them, the first message
25 * will be sent without manipulation, then a send delay of 1 second will
26 * be configured and 1 more message will be sent. Time will be measured.
27 *
28 * In addition the distance on receiver side will be manipulated to be 10
29 */
30#include "platform.h"
31#include "gnunet_transport_service.h"
32#include "transport-testing.h"
33
34/**
35 * How long until we give up on transmitting the message?
36 */
37#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
38
39static struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
40
41static int messages_recv;
42
43static struct GNUNET_TIME_Absolute start_normal;
44
45static struct GNUNET_TIME_Relative dur_normal;
46
47static struct GNUNET_TIME_Absolute start_delayed;
48
49static struct GNUNET_TIME_Relative dur_delayed;
50
51
52static void
53do_free (void *cls)
54{
55 struct GNUNET_TRANSPORT_TESTING_SendClosure *sc = cls;
56
57 GNUNET_free (sc);
58}
59
60
61static void
62delayed_transmit (void *cls)
63{
64 struct GNUNET_TRANSPORT_TESTING_SendClosure *sc = cls;
65
66 start_delayed = GNUNET_TIME_absolute_get ();
67 GNUNET_TRANSPORT_TESTING_large_send (sc);
68}
69
70
71static void
72sendtask (void *cls)
73{
74 struct GNUNET_TRANSPORT_TESTING_SendClosure *sc;
75 struct GNUNET_TIME_Relative delay;
76 struct GNUNET_ATS_Properties prop;
77
78 sc = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_SendClosure);
79 sc->num_messages = 1;
80 sc->ccc = ccc;
81 sc->cont = &do_free;
82 sc->cont_cls = sc;
83 if (0 == messages_recv)
84 {
85 start_normal = GNUNET_TIME_absolute_get ();
86 }
87 if (1 == messages_recv)
88 {
89 memset (&prop,
90 0,
91 sizeof(prop));
92 delay = GNUNET_TIME_UNIT_SECONDS;
93 GNUNET_TRANSPORT_manipulation_set (ccc->p[0]->tmh,
94 &ccc->p[1]->id,
95 &prop,
96 GNUNET_TIME_UNIT_ZERO,
97 delay);
98 /* wait 1s to allow manipulation to go into effect */
99 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
100 &delayed_transmit,
101 sc);
102 return;
103 }
104 GNUNET_TRANSPORT_TESTING_large_send (sc);
105}
106
107
108static void
109notify_receive (void *cls,
110 struct GNUNET_TRANSPORT_TESTING_PeerContext *receiver,
111 const struct GNUNET_PeerIdentity *sender,
112 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
113{
114 {
115 char *ps = GNUNET_strdup (GNUNET_i2s (&receiver->id));
116
117 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
118 "Peer %u (`%s') received message of type %d and size %u size from peer %s)!\n",
119 receiver->no,
120 ps,
121 ntohs (message->header.type),
122 ntohs (message->header.size),
123 GNUNET_i2s (sender));
124 GNUNET_free (ps);
125 }
126
127 if ((GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE != ntohs (message->header.type)) ||
128 (GNUNET_TRANSPORT_TESTING_LARGE_MESSAGE_SIZE != ntohs (
129 message->header.size)))
130 {
131 GNUNET_break (0);
132 ccc->global_ret = GNUNET_SYSERR;
133 GNUNET_SCHEDULER_shutdown ();
134 return;
135 }
136
137 if (0 == messages_recv)
138 {
139 /* Received non-delayed message */
140 dur_normal = GNUNET_TIME_absolute_get_duration (start_normal);
141 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
142 "Received non-delayed message %u after %s\n",
143 messages_recv,
144 GNUNET_STRINGS_relative_time_to_string (dur_normal,
145 GNUNET_YES));
146 GNUNET_SCHEDULER_add_now (&sendtask,
147 NULL);
148 messages_recv++;
149 return;
150 }
151 /* Received manipulated message */
152 dur_delayed = GNUNET_TIME_absolute_get_duration (start_delayed);
153 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
154 "Received delayed message %u after %s\n",
155 messages_recv,
156 GNUNET_STRINGS_relative_time_to_string (dur_delayed,
157 GNUNET_YES));
158 if (dur_delayed.rel_value_us < GNUNET_TIME_UNIT_SECONDS.rel_value_us)
159 {
160 GNUNET_break (0);
161 ccc->global_ret = GNUNET_SYSERR;
162 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
163 "Delayed message was not delayed correctly: took only %s\n",
164 GNUNET_STRINGS_relative_time_to_string (dur_delayed,
165 GNUNET_YES));
166 }
167 else
168 {
169 ccc->global_ret = GNUNET_OK;
170 }
171 GNUNET_SCHEDULER_shutdown ();
172}
173
174
175int
176main (int argc,
177 char *argv[])
178{
179 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext my_ccc = {
180 .connect_continuation = &sendtask,
181 .config_file = "test_transport_api_data.conf",
182 .rec = &notify_receive,
183 .nc = &GNUNET_TRANSPORT_TESTING_log_connect,
184 .nd = &GNUNET_TRANSPORT_TESTING_log_disconnect,
185 .timeout = TIMEOUT,
186 .global_ret = GNUNET_NO
187 };
188
189 ccc = &my_ccc;
190 if (GNUNET_OK !=
191 GNUNET_TRANSPORT_TESTING_main (2,
192 &GNUNET_TRANSPORT_TESTING_connect_check,
193 ccc))
194 return 1;
195 return 0;
196}
197
198
199/* end of test_transport_api_manipulation_send_tcp.c */
diff --git a/src/transport/test_transport_api_manipulation_send_tcp_peer1.conf b/src/transport/test_transport_api_manipulation_send_tcp_peer1.conf
deleted file mode 100644
index 9150c7faf..000000000
--- a/src/transport/test_transport_api_manipulation_send_tcp_peer1.conf
+++ /dev/null
@@ -1,29 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
4
5[transport-tcp]
6PORT = 12000
7TIMEOUT = 5 s
8
9[arm]
10PORT = 12005
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
12
13[statistics]
14PORT = 12004
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
16
17[resolver]
18PORT = 12003
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
20
21[peerinfo]
22PORT = 12002
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
24
25[transport]
26PORT = 12001
27UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
28PLUGINS = tcp
29
diff --git a/src/transport/test_transport_api_manipulation_send_tcp_peer2.conf b/src/transport/test_transport_api_manipulation_send_tcp_peer2.conf
deleted file mode 100644
index a7b2cf90b..000000000
--- a/src/transport/test_transport_api_manipulation_send_tcp_peer2.conf
+++ /dev/null
@@ -1,29 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
4
5[transport-tcp]
6PORT = 12015
7TIMEOUT = 5 s
8
9[arm]
10PORT = 12014
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
12
13[statistics]
14PORT = 12013
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
16
17[resolver]
18PORT = 12012
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
20
21[peerinfo]
22PORT = 12011
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
24
25[transport]
26PORT = 12010
27PLUGINS = tcp
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
29
diff --git a/src/transport/test_transport_api_reliability.c b/src/transport/test_transport_api_reliability.c
deleted file mode 100644
index 508fed4f5..000000000
--- a/src/transport/test_transport_api_reliability.c
+++ /dev/null
@@ -1,321 +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 it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport/test_transport_api_reliability.c
22 * @brief base test case for transport implementations
23 *
24 * This test case serves ensures that messages are reliably sent between peers
25 *
26 * This test sends TOTAL_MSGS with message type MTYPE from peer 1 to peer 2
27 * and ensures that all message were received.
28 */
29#include "platform.h"
30#include "gnunet_transport_service.h"
31#include "gauger.h"
32#include "transport-testing.h"
33
34/**
35 * Allow making the problem "bigger".
36 */
37#define FACTOR 1
38
39/**
40 * Total number of messages to send
41 *
42 * Note that this value must not significantly exceed
43 * 'MAX_PENDING' in 'gnunet-service-transport_clients.c', otherwise
44 * messages may be dropped even for a reliable transport.
45 */
46#define TOTAL_MSGS (1024 * 3 * FACTOR)
47
48/**
49 * Testcase timeout
50 */
51#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 450 \
52 * FACTOR)
53
54/**
55 * If we are in an "xhdr" test, the factor by which we divide
56 * #TOTAL_MSGS for a more sane test duration.
57 */
58static unsigned int xhdr = 1;
59
60static struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
61
62/**
63 * Total amount of bytes sent
64 */
65static unsigned long long total_bytes;
66
67/**
68 * Time of start
69 */
70static struct GNUNET_TIME_Absolute start_time;
71
72/**
73 * No. of last message received
74 */
75static unsigned int msg_recv;
76
77/**
78 * Bitmap storing which messages were received
79 */
80static char bitmap[TOTAL_MSGS / 8];
81
82
83/**
84 * Get the desired message size for message number @a iter.
85 */
86static size_t
87get_size (unsigned int iter)
88{
89 size_t ret;
90
91 ret = (iter * iter * iter);
92#ifndef __linux__
93 /* FreeBSD/OSX etc. Unix DGRAMs do not work
94 * with large messages */
95 if (0 == strcmp ("unix", ccc->test_plugin))
96 return sizeof(struct GNUNET_TRANSPORT_TESTING_TestMessage) + (ret % 1024);
97#endif
98 return sizeof(struct GNUNET_TRANSPORT_TESTING_TestMessage) + (ret % 60000);
99}
100
101
102/**
103 * Implementation of the callback for obtaining the
104 * size of messages for transmission. Counts the total
105 * number of bytes sent as a side-effect.
106 *
107 * @param cnt_down count down from `TOTAL_MSGS - 1`
108 * @return message size of the message
109 */
110static size_t
111get_size_cnt (unsigned int cnt_down)
112{
113 size_t ret = get_size (TOTAL_MSGS / xhdr - 1 - cnt_down);
114
115 total_bytes += ret;
116 return ret;
117}
118
119
120/**
121 * Sets a bit active in the bitmap.
122 *
123 * @param bitIdx which bit to set
124 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
125 */
126static int
127set_bit (unsigned int bitIdx)
128{
129 size_t arraySlot;
130 unsigned int targetBit;
131
132 if (bitIdx >= sizeof(bitmap) * 8)
133 {
134 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
135 "tried to set bit %u of %u(!?!?)\n",
136 bitIdx,
137 (unsigned int) sizeof(bitmap) * 8);
138 return GNUNET_SYSERR;
139 }
140 arraySlot = bitIdx / 8;
141 targetBit = (1L << (bitIdx % 8));
142 bitmap[arraySlot] |= targetBit;
143 return GNUNET_OK;
144}
145
146
147/**
148 * Obtain a bit from bitmap.
149 * @param map the bitmap
150 * @param bit index from bitmap
151 *
152 * @return Bit @a bit from @a map
153 */
154static int
155get_bit (const char *map,
156 unsigned int bit)
157{
158 if (bit > TOTAL_MSGS)
159 {
160 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
161 "get bit %u of %u(!?!?)\n",
162 bit,
163 (unsigned int) sizeof(bitmap) * 8);
164 return 0;
165 }
166 return ((map)[bit >> 3] & (1 << (bit & 7))) > 0;
167}
168
169
170static void
171custom_shutdown (void *cls)
172{
173 unsigned long long delta;
174 unsigned long long rate;
175 int ok;
176
177 /* Calculate statistics */
178 delta = GNUNET_TIME_absolute_get_duration (start_time).rel_value_us;
179 if (0 == delta)
180 delta = 1;
181 rate = (1000LL * 1000ll * total_bytes) / (1024 * delta);
182 fprintf (stderr,
183 "\nThroughput was %llu KiBytes/s\n",
184 rate);
185 {
186 char *value_name;
187
188 GNUNET_asprintf (&value_name,
189 "unreliable_%s",
190 ccc->test_plugin);
191 GAUGER ("TRANSPORT",
192 value_name,
193 (int) rate,
194 "kb/s");
195 GNUNET_free (value_name);
196 }
197
198 ok = 0;
199 for (unsigned int i = 0; i < TOTAL_MSGS / xhdr; i++)
200 {
201 if (get_bit (bitmap, i) == 0)
202 {
203 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
204 "Did not receive message %d\n",
205 i);
206 ok = -1;
207 }
208 }
209 if (0 != ok)
210 ccc->global_ret = GNUNET_SYSERR; /* fail: messages missing! */
211}
212
213
214static void
215notify_receive (void *cls,
216 struct GNUNET_TRANSPORT_TESTING_PeerContext *receiver,
217 const struct GNUNET_PeerIdentity *sender,
218 const struct GNUNET_TRANSPORT_TESTING_TestMessage *hdr)
219{
220 static int n;
221 unsigned int s;
222 char cbuf[GNUNET_MAX_MESSAGE_SIZE - 1];
223
224 if (GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE != ntohs (hdr->header.type))
225 return;
226 msg_recv = ntohl (hdr->num);
227 s = get_size (ntohl (hdr->num));
228
229 if (ntohs (hdr->header.size) != s)
230 {
231 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
232 "Expected message %u of size %u, got %u bytes of message %u\n",
233 (uint32_t) ntohl (hdr->num),
234 s,
235 ntohs (hdr->header.size),
236 (uint32_t) ntohl (hdr->num));
237 ccc->global_ret = GNUNET_SYSERR;
238 GNUNET_SCHEDULER_shutdown ();
239 return;
240 }
241
242 memset (cbuf,
243 ntohl (hdr->num),
244 s - sizeof(struct GNUNET_TRANSPORT_TESTING_TestMessage));
245 if (0 !=
246 memcmp (cbuf,
247 &hdr[1],
248 s - sizeof(struct GNUNET_TRANSPORT_TESTING_TestMessage)))
249 {
250 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
251 "Expected message %u with bits %u, but body did not match\n",
252 (uint32_t) ntohl (hdr->num),
253 (unsigned char) ntohl (hdr->num));
254 ccc->global_ret = GNUNET_SYSERR;
255 GNUNET_SCHEDULER_shutdown ();
256 return;
257 }
258#if VERBOSE
259 if (0 == ntohl (hdr->num) % 5)
260 {
261 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
262 "Got message %u of size %u\n",
263 (uint32_t) ntohl (hdr->num),
264 ntohs (hdr->header.size));
265 }
266#endif
267 n++;
268 if (GNUNET_SYSERR == set_bit (ntohl (hdr->num)))
269 {
270 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
271 "Message id %u is bigger than maxmimum number of messages %u expected\n",
272 (uint32_t) ntohl (hdr->num),
273 TOTAL_MSGS / xhdr);
274 }
275 if (0 == (n % (TOTAL_MSGS / xhdr / 100)))
276 {
277 fprintf (stderr, "%s", ".");
278 }
279 if (n == TOTAL_MSGS / xhdr)
280 {
281 /* end testcase with success */
282 ccc->global_ret = GNUNET_OK;
283 GNUNET_SCHEDULER_shutdown ();
284 }
285}
286
287
288int
289main (int argc, char *argv[])
290{
291 if (0 == strstr (argv[0], "xhdr"))
292 xhdr = 30;
293 struct GNUNET_TRANSPORT_TESTING_SendClosure sc = {
294 .num_messages = TOTAL_MSGS / xhdr,
295 .get_size_cb = &get_size_cnt
296 };
297 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext my_ccc = {
298 .connect_continuation = &GNUNET_TRANSPORT_TESTING_simple_send,
299 .connect_continuation_cls = &sc,
300 .config_file = "test_transport_api_data.conf",
301 .rec = &notify_receive,
302 .nc = &GNUNET_TRANSPORT_TESTING_log_connect,
303 .nd = &GNUNET_TRANSPORT_TESTING_log_disconnect,
304 .shutdown_task = &custom_shutdown,
305 .timeout = TIMEOUT,
306 .global_ret = GNUNET_SYSERR
307 };
308
309 ccc = &my_ccc;
310 sc.ccc = ccc;
311 start_time = GNUNET_TIME_absolute_get ();
312 if (GNUNET_OK !=
313 GNUNET_TRANSPORT_TESTING_main (2,
314 &GNUNET_TRANSPORT_TESTING_connect_check,
315 ccc))
316 return 1;
317 return 0;
318}
319
320
321/* end of test_transport_api_reliability.c */
diff --git a/src/transport/test_transport_api_reliability_bluetooth_peer1.conf b/src/transport/test_transport_api_reliability_bluetooth_peer1.conf
deleted file mode 100644
index 738255235..000000000
--- a/src/transport/test_transport_api_reliability_bluetooth_peer1.conf
+++ /dev/null
@@ -1,33 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-bluetooth-p1/
4
5[transport-bluetooth]
6INTERFACE = hci0
7TESTMODE = 1
8
9[arm]
10PORT = 12164
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
12
13[statistics]
14PORT = 12163
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
16
17[resolver]
18PORT = 12162
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
20
21[peerinfo]
22PORT = 12161
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
24
25[transport]
26PORT = 12160
27PLUGINS = bluetooth
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
29
30
31[ats]
32BLUETOOTH_QUOTA_IN = unlimited
33BLUETOOTH_QUOTA_OUT = unlimited
diff --git a/src/transport/test_transport_api_reliability_bluetooth_peer2.conf b/src/transport/test_transport_api_reliability_bluetooth_peer2.conf
deleted file mode 100644
index 9c68b5fbc..000000000
--- a/src/transport/test_transport_api_reliability_bluetooth_peer2.conf
+++ /dev/null
@@ -1,32 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-bluetooth-p2/
4
5[transport-bluetooth]
6INTERFACE = hci1
7TESTMODE = 2
8
9[arm]
10PORT = 12174
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
12
13[statistics]
14PORT = 12173
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
16
17[resolver]
18PORT = 12172
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
20
21[peerinfo]
22PORT = 12171
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
24
25[transport]
26PORT = 12170
27PLUGINS = bluetooth
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
29
30[ats]
31BLUETOOTH_QUOTA_IN = unlimited
32BLUETOOTH_QUOTA_OUT = unlimited
diff --git a/src/transport/test_transport_api_reliability_http_peer1.conf b/src/transport/test_transport_api_reliability_http_peer1.conf
deleted file mode 100644
index a1e5c96ac..000000000
--- a/src/transport/test_transport_api_reliability_http_peer1.conf
+++ /dev/null
@@ -1,33 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-http-p1/
4
5[transport-http_client]
6
7[transport-tcp]
8TIMEOUT = 5 s
9
10[transport-http]
11PORT = 12180
12
13[arm]
14PORT = 12185
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
16
17[statistics]
18PORT = 12184
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
20
21[resolver]
22PORT = 12183
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
24
25[peerinfo]
26PORT = 12182
27UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
28
29[transport]
30PORT = 12181
31PLUGINS = http_client
32UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
33
diff --git a/src/transport/test_transport_api_reliability_http_peer2.conf b/src/transport/test_transport_api_reliability_http_peer2.conf
deleted file mode 100644
index 25a554f94..000000000
--- a/src/transport/test_transport_api_reliability_http_peer2.conf
+++ /dev/null
@@ -1,30 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-http-p2/
4
5[transport-http_server]
6PORT = 12090
7USE_IPv6 = NO
8BINDTO = 127.0.0.1
9
10[arm]
11PORT = 12195
12UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
13
14[statistics]
15PORT = 12194
16UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
17
18[resolver]
19PORT = 12193
20UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
21
22[peerinfo]
23PORT = 12192
24UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
25
26[transport]
27PORT = 12191
28PLUGINS = http_server
29UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
30
diff --git a/src/transport/test_transport_api_reliability_http_xhr_peer1.conf b/src/transport/test_transport_api_reliability_http_xhr_peer1.conf
deleted file mode 100644
index ba4101ebe..000000000
--- a/src/transport/test_transport_api_reliability_http_xhr_peer1.conf
+++ /dev/null
@@ -1,34 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-http-p1/
4
5[transport-http_client]
6EMULATE_XHR = YES
7
8[transport-tcp]
9TIMEOUT = 5 s
10
11[transport-http]
12PORT = 12180
13
14[arm]
15PORT = 12185
16UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
17
18[statistics]
19PORT = 12184
20UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
21
22[resolver]
23PORT = 12183
24UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
25
26[peerinfo]
27PORT = 12182
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
29
30[transport]
31PORT = 12181
32PLUGINS = http_client
33UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
34
diff --git a/src/transport/test_transport_api_reliability_http_xhr_peer2.conf b/src/transport/test_transport_api_reliability_http_xhr_peer2.conf
deleted file mode 100644
index 25a554f94..000000000
--- a/src/transport/test_transport_api_reliability_http_xhr_peer2.conf
+++ /dev/null
@@ -1,30 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-http-p2/
4
5[transport-http_server]
6PORT = 12090
7USE_IPv6 = NO
8BINDTO = 127.0.0.1
9
10[arm]
11PORT = 12195
12UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
13
14[statistics]
15PORT = 12194
16UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
17
18[resolver]
19PORT = 12193
20UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
21
22[peerinfo]
23PORT = 12192
24UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
25
26[transport]
27PORT = 12191
28PLUGINS = http_server
29UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
30
diff --git a/src/transport/test_transport_api_reliability_https_peer1.conf b/src/transport/test_transport_api_reliability_https_peer1.conf
deleted file mode 100644
index 1b51da130..000000000
--- a/src/transport/test_transport_api_reliability_https_peer1.conf
+++ /dev/null
@@ -1,27 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-https-p1/
4
5[transport-https_client]
6
7[arm]
8PORT = 12305
9UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
10
11[statistics]
12PORT = 12304
13UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
14
15[resolver]
16PORT = 12303
17UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
18
19[peerinfo]
20PORT = 12302
21UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
22
23[transport]
24PORT = 12301
25PLUGINS = https_client
26UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
27
diff --git a/src/transport/test_transport_api_reliability_https_peer2.conf b/src/transport/test_transport_api_reliability_https_peer2.conf
deleted file mode 100644
index 3dfb87a6d..000000000
--- a/src/transport/test_transport_api_reliability_https_peer2.conf
+++ /dev/null
@@ -1,31 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-https-p2/
4
5[transport-https_server]
6PORT = 12310
7KEY_FILE = $GNUNET_TEST_HOME/https_key_p2.key
8CERT_FILE = $GNUNET_TEST_HOME/https_cert_p2.crt
9
10[arm]
11PORT = 12315
12UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
13
14[statistics]
15PORT = 12314
16UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
17
18[resolver]
19PORT = 12313
20UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
21
22[peerinfo]
23PORT = 12312
24UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
25
26[transport]
27PORT = 12311
28PLUGINS = https_server
29UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
30
31
diff --git a/src/transport/test_transport_api_reliability_https_xhr_peer1.conf b/src/transport/test_transport_api_reliability_https_xhr_peer1.conf
deleted file mode 100644
index 5d042f2f9..000000000
--- a/src/transport/test_transport_api_reliability_https_xhr_peer1.conf
+++ /dev/null
@@ -1,28 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-https-p1/
4
5[transport-https_client]
6EMULATE_XHR = YES
7
8[arm]
9PORT = 12305
10UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
11
12[statistics]
13PORT = 12304
14UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
15
16[resolver]
17PORT = 12303
18UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
19
20[peerinfo]
21PORT = 12302
22UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
23
24[transport]
25PORT = 12301
26PLUGINS = https_client
27UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
28
diff --git a/src/transport/test_transport_api_reliability_https_xhr_peer2.conf b/src/transport/test_transport_api_reliability_https_xhr_peer2.conf
deleted file mode 100644
index 3dfb87a6d..000000000
--- a/src/transport/test_transport_api_reliability_https_xhr_peer2.conf
+++ /dev/null
@@ -1,31 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-https-p2/
4
5[transport-https_server]
6PORT = 12310
7KEY_FILE = $GNUNET_TEST_HOME/https_key_p2.key
8CERT_FILE = $GNUNET_TEST_HOME/https_cert_p2.crt
9
10[arm]
11PORT = 12315
12UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
13
14[statistics]
15PORT = 12314
16UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
17
18[resolver]
19PORT = 12313
20UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
21
22[peerinfo]
23PORT = 12312
24UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
25
26[transport]
27PORT = 12311
28PLUGINS = https_server
29UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
30
31
diff --git a/src/transport/test_transport_api_reliability_tcp_nat_peer1.conf b/src/transport/test_transport_api_reliability_tcp_nat_peer1.conf
deleted file mode 100644
index 6a2029b09..000000000
--- a/src/transport/test_transport_api_reliability_tcp_nat_peer1.conf
+++ /dev/null
@@ -1,35 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-reliability-tcp-nat-p1/
4
5[nat]
6BEHIND_NAT = YES
7ENABLE_NAT_SERVER = YES
8DISABLEV6 = YES
9
10[transport-tcp]
11PORT = 0
12TIMEOUT = 5 s
13
14[arm]
15PORT = 51204
16UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
17
18[statistics]
19PORT = 12023
20UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
21
22[resolver]
23PORT = 12022
24UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
25
26[peerinfo]
27PORT = 12021
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
29
30[transport]
31PORT = 29542
32PLUGINS = tcp
33UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
34
35
diff --git a/src/transport/test_transport_api_reliability_tcp_nat_peer2.conf b/src/transport/test_transport_api_reliability_tcp_nat_peer2.conf
deleted file mode 100644
index 2de9026f5..000000000
--- a/src/transport/test_transport_api_reliability_tcp_nat_peer2.conf
+++ /dev/null
@@ -1,34 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-reliability-tcp-nat-p2/
4
5[nat]
6DISABLEV6 = YES
7ENABLE_NAT_CLIENT = YES
8
9[transport-tcp]
10PORT = 12030
11TIMEOUT = 5 s
12
13[arm]
14PORT = 12034
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
16
17[statistics]
18PORT = 12033
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
20
21[resolver]
22PORT = 12032
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
24
25[peerinfo]
26PORT = 12031
27UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
28
29[transport]
30PORT = 45923
31PLUGINS = tcp
32UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
33
34
diff --git a/src/transport/test_transport_api_reliability_tcp_peer1.conf b/src/transport/test_transport_api_reliability_tcp_peer1.conf
deleted file mode 100644
index 305605d63..000000000
--- a/src/transport/test_transport_api_reliability_tcp_peer1.conf
+++ /dev/null
@@ -1,29 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
4
5[transport-tcp]
6PORT = 12000
7TIMEOUT = 5 s
8
9[arm]
10PORT = 12005
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
12
13[statistics]
14PORT = 12004
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
16
17[resolver]
18PORT = 12003
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
20
21[peerinfo]
22PORT = 12002
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
24
25[transport]
26PORT = 12001
27PLUGINS = tcp
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
29
diff --git a/src/transport/test_transport_api_reliability_tcp_peer2.conf b/src/transport/test_transport_api_reliability_tcp_peer2.conf
deleted file mode 100644
index 43bb4ae37..000000000
--- a/src/transport/test_transport_api_reliability_tcp_peer2.conf
+++ /dev/null
@@ -1,28 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
4
5[transport-tcp]
6PORT = 12015
7TIMEOUT = 5 s
8
9[arm]
10PORT = 12014
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
12
13[statistics]
14PORT = 12013
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
16
17[resolver]
18PORT = 12012
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
20
21[peerinfo]
22PORT = 12011
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
24
25[transport]
26PORT = 12010
27PLUGINS = tcp
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
diff --git a/src/transport/test_transport_api_reliability_udp_peer1.conf b/src/transport/test_transport_api_reliability_udp_peer1.conf
deleted file mode 100644
index 141fb0840..000000000
--- a/src/transport/test_transport_api_reliability_udp_peer1.conf
+++ /dev/null
@@ -1,29 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-udp-p1/
4
5[transport-udp]
6PORT = 12040
7# Override 1MB/s default limit.
8MAX_BPS = 500000000
9
10[arm]
11PORT = 12045
12UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
13
14[statistics]
15PORT = 12044
16UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
17
18[resolver]
19PORT = 12043
20UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
21
22[peerinfo]
23PORT = 12042
24UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
25
26[transport]
27PORT = 12041
28PLUGINS = udp
29UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
diff --git a/src/transport/test_transport_api_reliability_udp_peer2.conf b/src/transport/test_transport_api_reliability_udp_peer2.conf
deleted file mode 100644
index 7523db854..000000000
--- a/src/transport/test_transport_api_reliability_udp_peer2.conf
+++ /dev/null
@@ -1,29 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-udp-p2/
4
5[transport-udp]
6PORT = 12050
7# Override 1MB/s default limit.
8MAX_BPS = 500000000
9
10[arm]
11PORT = 12055
12UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
13
14[statistics]
15PORT = 12054
16UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
17
18[resolver]
19PORT = 12053
20UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
21
22[peerinfo]
23PORT = 12052
24UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
25
26[transport]
27PORT = 12051
28PLUGINS = udp
29UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
diff --git a/src/transport/test_transport_api_reliability_unix_peer1.conf b/src/transport/test_transport_api_reliability_unix_peer1.conf
deleted file mode 100644
index e253aad8c..000000000
--- a/src/transport/test_transport_api_reliability_unix_peer1.conf
+++ /dev/null
@@ -1,28 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-unix-p1/
4
5[arm]
6PORT = 12125
7UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
8
9[statistics]
10PORT = 12124
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
12
13[resolver]
14PORT = 12123
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
16
17[peerinfo]
18PORT = 12122
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
20
21[transport]
22PORT = 12121
23PLUGINS = unix
24UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
25
26[transport-unix]
27PORT = 12120
28
diff --git a/src/transport/test_transport_api_reliability_unix_peer2.conf b/src/transport/test_transport_api_reliability_unix_peer2.conf
deleted file mode 100644
index e0df47c07..000000000
--- a/src/transport/test_transport_api_reliability_unix_peer2.conf
+++ /dev/null
@@ -1,28 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-unix-p2/
4
5[arm]
6PORT = 12135
7UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
8
9[statistics]
10PORT = 12134
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
12
13[resolver]
14PORT = 12133
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
16
17[peerinfo]
18PORT = 12132
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
20
21[transport]
22PORT = 12131
23PLUGINS = unix
24UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
25
26[transport-unix]
27PORT = 12131
28
diff --git a/src/transport/test_transport_api_reliability_wlan_peer1.conf b/src/transport/test_transport_api_reliability_wlan_peer1.conf
deleted file mode 100644
index 19eb21456..000000000
--- a/src/transport/test_transport_api_reliability_wlan_peer1.conf
+++ /dev/null
@@ -1,31 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-wlan-p1/
4
5[transport-wlan]
6TESTMODE = 1
7
8[arm]
9PORT = 12164
10UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
11
12[statistics]
13PORT = 12163
14UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
15
16[resolver]
17PORT = 12162
18UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
19
20[peerinfo]
21PORT = 12161
22UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
23
24[transport]
25PORT = 12160
26PLUGINS = wlan
27UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
28
29[ats]
30WLAN_QUOTA_IN = unlimited
31WLAN_QUOTA_OUT = unlimited \ No newline at end of file
diff --git a/src/transport/test_transport_api_reliability_wlan_peer2.conf b/src/transport/test_transport_api_reliability_wlan_peer2.conf
deleted file mode 100644
index d5c269b43..000000000
--- a/src/transport/test_transport_api_reliability_wlan_peer2.conf
+++ /dev/null
@@ -1,32 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-wlan-p2/
4
5[transport-wlan]
6INTERFACE = mon1
7TESTMODE = 2
8
9[arm]
10PORT = 12174
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
12
13[statistics]
14PORT = 12173
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
16
17[resolver]
18PORT = 12172
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
20
21[peerinfo]
22PORT = 12171
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
24
25[transport]
26PORT = 12170
27PLUGINS = wlan
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
29
30[ats]
31WLAN_QUOTA_IN = unlimited
32WLAN_QUOTA_OUT = unlimited
diff --git a/src/transport/test_transport_api_restart_1peer_peer1.conf b/src/transport/test_transport_api_restart_1peer_peer1.conf
deleted file mode 100644
index eabd6b701..000000000
--- a/src/transport/test_transport_api_restart_1peer_peer1.conf
+++ /dev/null
@@ -1,9 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
4
5[transport]
6PLUGINS = tcp
7
8#[transport]
9#PREFIX = valgrind
diff --git a/src/transport/test_transport_api_restart_1peer_peer2.conf b/src/transport/test_transport_api_restart_1peer_peer2.conf
deleted file mode 100644
index 58ce0777f..000000000
--- a/src/transport/test_transport_api_restart_1peer_peer2.conf
+++ /dev/null
@@ -1,9 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
4
5[transport]
6PLUGINS = tcp
7
8#[transport]
9#PREFIX = valgrind
diff --git a/src/transport/test_transport_api_restart_2peers_peer1.conf b/src/transport/test_transport_api_restart_2peers_peer1.conf
deleted file mode 100644
index eabd6b701..000000000
--- a/src/transport/test_transport_api_restart_2peers_peer1.conf
+++ /dev/null
@@ -1,9 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
4
5[transport]
6PLUGINS = tcp
7
8#[transport]
9#PREFIX = valgrind
diff --git a/src/transport/test_transport_api_restart_2peers_peer2.conf b/src/transport/test_transport_api_restart_2peers_peer2.conf
deleted file mode 100644
index 58ce0777f..000000000
--- a/src/transport/test_transport_api_restart_2peers_peer2.conf
+++ /dev/null
@@ -1,9 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
4
5[transport]
6PLUGINS = tcp
7
8#[transport]
9#PREFIX = valgrind
diff --git a/src/transport/test_transport_api_restart_reconnect.c b/src/transport/test_transport_api_restart_reconnect.c
deleted file mode 100644
index d58c1de54..000000000
--- a/src/transport/test_transport_api_restart_reconnect.c
+++ /dev/null
@@ -1,217 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010, 2015, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport/test_transport_api_restart_reconnect.c
22 * @brief base test case for transport implementations
23 *
24 * This test case starts 2 peers, connects and exchanges a message.
25 * Then, 1 or 2 peers are restarted and it is tested if peers reconnect.
26 * How many peers are restarted is determined by the name of the binary.
27 */
28#include "platform.h"
29#include "gnunet_transport_service.h"
30#include "transport-testing.h"
31
32/**
33 * How long until we give up on transmitting the message?
34 */
35#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
36
37
38static struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
39
40static struct GNUNET_ATS_ConnectivitySuggestHandle *ats_sh;
41
42static int p1_connected;
43
44static int p2_connected;
45
46static int restarted;
47
48
49static void
50custom_shutdown (void *cls)
51{
52 if (NULL != ats_sh)
53 {
54 GNUNET_ATS_connectivity_suggest_cancel (ats_sh);
55 ats_sh = NULL;
56 }
57}
58
59
60static void
61restart_cb (void *cls)
62{
63 static unsigned int c;
64 struct GNUNET_TRANSPORT_TESTING_PeerContext *p = cls;
65
66 c++;
67 if ((2 != c) &&
68 (NULL != strstr (ccc->test_name,
69 "2peers")))
70 return;
71 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
72 "Restarted peer %u (`%s'), issuing reconnect\n",
73 p->no,
74 GNUNET_i2s (&p->id));
75 ats_sh = GNUNET_ATS_connectivity_suggest (p->ats,
76 &ccc->p[1]->id,
77 1);
78}
79
80
81static void
82restart (struct GNUNET_TRANSPORT_TESTING_PeerContext *p)
83{
84 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
85 "Restarting peer %u (`%s')\n",
86 p->no,
87 GNUNET_i2s (&p->id));
88 GNUNET_assert (GNUNET_OK ==
89 GNUNET_TRANSPORT_TESTING_restart_peer (p,
90 &restart_cb,
91 p));
92}
93
94
95static void
96notify_receive (void *cls,
97 struct GNUNET_TRANSPORT_TESTING_PeerContext *receiver,
98 const struct GNUNET_PeerIdentity *sender,
99 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
100{
101 {
102 char *ps = GNUNET_strdup (GNUNET_i2s (&receiver->id));
103
104 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
105 "Peer %u (`%s') received message of type %d and size %u size from peer %s!\n",
106 receiver->no,
107 ps,
108 ntohs (message->header.type),
109 ntohs (message->header.size),
110 GNUNET_i2s (sender));
111 GNUNET_free (ps);
112 }
113 if ((GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE == ntohs (message->header.type)) &&
114 (sizeof(struct GNUNET_TRANSPORT_TESTING_TestMessage) == ntohs (
115 message->header.size)))
116 {
117 if (GNUNET_NO == restarted)
118 {
119 restarted = GNUNET_YES;
120 fprintf (stderr, "TN: %s\n", ccc->test_name);
121 restart (ccc->p[0]);
122 if (NULL != strstr (ccc->test_name,
123 "2peers"))
124 restart (ccc->p[1]);
125 return;
126 }
127 else
128 {
129 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
130 "Restarted peers connected and message was sent, stopping test...\n");
131 ccc->global_ret = GNUNET_OK;
132 GNUNET_SCHEDULER_shutdown ();
133 }
134 }
135 else
136 {
137 GNUNET_break (0);
138 ccc->global_ret = GNUNET_SYSERR;
139 GNUNET_SCHEDULER_shutdown ();
140 }
141}
142
143
144static void
145notify_connect (void *cls,
146 struct GNUNET_TRANSPORT_TESTING_PeerContext *me,
147 const struct GNUNET_PeerIdentity *other)
148{
149 static struct GNUNET_TRANSPORT_TESTING_SendClosure sc = {
150 .num_messages = 1
151 };
152
153 sc.ccc = ccc;
154 GNUNET_TRANSPORT_TESTING_log_connect (cls,
155 me,
156 other);
157 if (me == ccc->p[0])
158 p1_connected = GNUNET_YES;
159 if (me == ccc->p[1])
160 p2_connected = GNUNET_YES;
161
162 if ((GNUNET_YES == restarted) &&
163 (GNUNET_YES == p1_connected) &&
164 (GNUNET_YES == p2_connected))
165 {
166 /* Peer was restarted and we received 3 connect messages (2 from first connect, 1 from reconnect) */
167 GNUNET_SCHEDULER_add_now (&GNUNET_TRANSPORT_TESTING_simple_send,
168 &sc);
169 }
170}
171
172
173static void
174notify_disconnect (void *cls,
175 struct GNUNET_TRANSPORT_TESTING_PeerContext *me,
176 const struct GNUNET_PeerIdentity *other)
177{
178 GNUNET_TRANSPORT_TESTING_log_disconnect (cls,
179 me,
180 other);
181 if (me == ccc->p[0])
182 p1_connected = GNUNET_NO;
183 if (me == ccc->p[1])
184 p2_connected = GNUNET_NO;
185}
186
187
188int
189main (int argc,
190 char *argv[])
191{
192 struct GNUNET_TRANSPORT_TESTING_SendClosure sc = {
193 .num_messages = 1
194 };
195 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext my_ccc = {
196 .connect_continuation = &GNUNET_TRANSPORT_TESTING_simple_send,
197 .connect_continuation_cls = &sc,
198 .config_file = "test_transport_api_data.conf",
199 .rec = &notify_receive,
200 .nc = &notify_connect,
201 .nd = &notify_disconnect,
202 .shutdown_task = &custom_shutdown,
203 .timeout = TIMEOUT
204 };
205
206 ccc = &my_ccc;
207 sc.ccc = ccc;
208 if (GNUNET_OK !=
209 GNUNET_TRANSPORT_TESTING_main (2,
210 &GNUNET_TRANSPORT_TESTING_connect_check,
211 ccc))
212 return 1;
213 return 0;
214}
215
216
217/* end of test_transport_api_restart_1peer.c */
diff --git a/src/transport/test_transport_api_slow_ats_peer1.conf b/src/transport/test_transport_api_slow_ats_peer1.conf
deleted file mode 100644
index a96f5e263..000000000
--- a/src/transport/test_transport_api_slow_ats_peer1.conf
+++ /dev/null
@@ -1,7 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-slow-ats-p1/
4
5[transport]
6PLUGINS = tcp
7
diff --git a/src/transport/test_transport_api_slow_ats_peer2.conf b/src/transport/test_transport_api_slow_ats_peer2.conf
deleted file mode 100644
index 3a6ed05d3..000000000
--- a/src/transport/test_transport_api_slow_ats_peer2.conf
+++ /dev/null
@@ -1,9 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-slow-ats-p2/
4
5[transport]
6PLUGINS = tcp
7
8[ats]
9PREFIX = ./test_delay -t 10 --
diff --git a/src/transport/test_transport_api_timeout.c b/src/transport/test_transport_api_timeout.c
deleted file mode 100644
index 9f8d3bb2b..000000000
--- a/src/transport/test_transport_api_timeout.c
+++ /dev/null
@@ -1,164 +0,0 @@
1/*
2 This file is part of GNUnet.x
3 Copyright (C) 2009, 2010, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport/test_transport_api_timeout.c
22 * @brief test case for transport plugin implementations complying timeout
23 * settings
24 *
25 *
26 * This test case serves ensures that no peer disconnect events occurs
27 * while plugins are idle
28 */
29
30#include "platform.h"
31#include "gnunet_transport_service.h"
32#include "transport-testing.h"
33
34/**
35 * How long until we give up on transmitting the message?
36 */
37#define WAIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
38
39#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 90)
40
41#define MTYPE 12345
42
43static struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
44
45static struct GNUNET_TIME_Relative time_running;
46
47static struct GNUNET_SCHEDULER_Task *timer_task;
48
49static int shutdown_flag;
50
51static unsigned int disconnects;
52
53
54static void
55custom_shutdown (void *cls)
56{
57 if (NULL != timer_task)
58 {
59 GNUNET_SCHEDULER_cancel (timer_task);
60 timer_task = NULL;
61 }
62 if (0 == disconnects)
63 {
64 ccc->global_ret = GNUNET_OK;
65 }
66 else
67 {
68 ccc->global_ret = -GNUNET_SYSERR;
69 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
70 "Fail! Had %u disconnects while waiting %s\n",
71 disconnects,
72 GNUNET_STRINGS_relative_time_to_string (WAIT,
73 GNUNET_YES));
74 }
75}
76
77
78static void
79notify_receive (void *cls,
80 struct GNUNET_TRANSPORT_TESTING_PeerContext *receiver,
81 const struct GNUNET_PeerIdentity *sender,
82 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
83{
84 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
85 "Received message of type %d from peer %s!\n",
86 ntohs (message->header.type),
87 GNUNET_i2s (sender));
88}
89
90
91static void
92notify_disconnect (void *cls,
93 struct GNUNET_TRANSPORT_TESTING_PeerContext *me,
94 const struct GNUNET_PeerIdentity *other)
95{
96 GNUNET_TRANSPORT_TESTING_log_disconnect (cls,
97 me,
98 other);
99 if (shutdown_flag != GNUNET_YES)
100 {
101 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
102 "FAIL! Peer `%s' disconnected during waiting period!\n",
103 GNUNET_i2s (other));
104 disconnects++;
105 }
106}
107
108
109static void
110timer (void *cls)
111{
112 static unsigned int percentage;
113
114 timer_task = NULL;
115 percentage += 10;
116 time_running = GNUNET_TIME_relative_add (time_running,
117 GNUNET_TIME_relative_divide (WAIT,
118 10));
119
120 if (time_running.rel_value_us ==
121 GNUNET_TIME_relative_max (time_running, WAIT).rel_value_us)
122 {
123 fprintf (stderr, "%s", "100%%\n");
124 shutdown_flag = GNUNET_YES;
125 GNUNET_SCHEDULER_shutdown ();
126 }
127 else
128 {
129 fprintf (stderr,
130 "%u%%..",
131 percentage);
132 timer_task =
133 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide (WAIT, 10),
134 &timer,
135 NULL);
136 }
137}
138
139
140int
141main (int argc,
142 char *argv[])
143{
144 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext my_ccc = {
145 .connect_continuation = &timer,
146 .config_file = "test_transport_api_data.conf",
147 .rec = &notify_receive,
148 .nc = &GNUNET_TRANSPORT_TESTING_log_connect,
149 .nd = &notify_disconnect,
150 .shutdown_task = &custom_shutdown,
151 .timeout = TIMEOUT
152 };
153
154 ccc = &my_ccc;
155 if (GNUNET_OK !=
156 GNUNET_TRANSPORT_TESTING_main (2,
157 &GNUNET_TRANSPORT_TESTING_connect_check,
158 ccc))
159 return 1;
160 return 0;
161}
162
163
164/* end of test_transport_api_timeout.c*/
diff --git a/src/transport/test_transport_api_timeout_bluetooth_peer1.conf b/src/transport/test_transport_api_timeout_bluetooth_peer1.conf
deleted file mode 100644
index dcc159e45..000000000
--- a/src/transport/test_transport_api_timeout_bluetooth_peer1.conf
+++ /dev/null
@@ -1,35 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-bluetooth-p1/
4
5[transport-bluetooth]
6INTERFACE = hci0
7TESTMODE = 1
8
9[arm]
10PORT = 12164
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
12
13[statistics]
14PORT = 12163
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
16
17[resolver]
18PORT = 12162
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
20
21[peerinfo]
22PORT = 12161
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
24
25[transport]
26PORT = 12160
27PLUGINS = bluetooth
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
29#PREFIX = xterm -T transport2 -e gdb --command=cmd --args
30#PREFIX = valgrind --leak-check=full --show-reachable=yes --main-stacksize=104857600
31#PREFIX = valgrind --leak-check=full --show-reachable=yes
32#PREFIX = valgrind --leak-check=full
33#PREFIX = valgrind --tool=massif
34#PREFIX = gdbserver :2345
35
diff --git a/src/transport/test_transport_api_timeout_bluetooth_peer2.conf b/src/transport/test_transport_api_timeout_bluetooth_peer2.conf
deleted file mode 100644
index 5cd550d0e..000000000
--- a/src/transport/test_transport_api_timeout_bluetooth_peer2.conf
+++ /dev/null
@@ -1,34 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-bluetooth-p2/
4
5[transport-bluetooth]
6INTERFACE = hci1
7TESTMODE = 2
8
9[arm]
10PORT = 12174
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
12
13[statistics]
14PORT = 12173
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
16
17[resolver]
18PORT = 12172
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
20
21[peerinfo]
22PORT = 12171
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
24
25[transport]
26PORT = 12170
27PLUGINS = bluetooth
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
29#PREFIX = xterm -T transport2 -e gdb --command=cmd --args
30#PREFIX = valgrind --leak-check=full --show-reachable=yes --main-stacksize=104857600
31#PREFIX = valgrind --leak-check=full --show-reachable=yes
32#PREFIX = valgrind --leak-check=full
33#PREFIX = valgrind --tool=massif
34#PREFIX = gdbserver :2345
diff --git a/src/transport/test_transport_api_timeout_http_peer1.conf b/src/transport/test_transport_api_timeout_http_peer1.conf
deleted file mode 100644
index d7bc59ea3..000000000
--- a/src/transport/test_transport_api_timeout_http_peer1.conf
+++ /dev/null
@@ -1,28 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-http-p1/
4
5[arm]
6PORT = 12085
7UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
8
9[statistics]
10PORT = 12084
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
12
13[resolver]
14PORT = 12083
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
16
17[peerinfo]
18PORT = 12082
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
20
21[transport]
22PORT = 12081
23PLUGINS = http_client
24#BINARY = .libs/gnunet-service-transport
25UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
26#PREFIX = valgrind --leak-check=full
27#PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args
28
diff --git a/src/transport/test_transport_api_timeout_http_peer2.conf b/src/transport/test_transport_api_timeout_http_peer2.conf
deleted file mode 100644
index 453c6d0c5..000000000
--- a/src/transport/test_transport_api_timeout_http_peer2.conf
+++ /dev/null
@@ -1,31 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-http-p2/
4
5[transport-http_server]
6PORT = 12090
7USE_IPv6 = NO
8BINDTO = 127.0.0.1
9
10
11[arm]
12PORT = 12095
13UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
14
15[statistics]
16PORT = 12094
17UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
18
19[resolver]
20PORT = 12093
21UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
22
23[peerinfo]
24PORT = 12092
25UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
26
27[transport]
28PORT = 12091
29PLUGINS = http_server
30UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
31#PREFIX = valgrind --leak-check=full
diff --git a/src/transport/test_transport_api_timeout_https_peer1.conf b/src/transport/test_transport_api_timeout_https_peer1.conf
deleted file mode 100644
index c4f96814c..000000000
--- a/src/transport/test_transport_api_timeout_https_peer1.conf
+++ /dev/null
@@ -1,25 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-https-p1/
4
5[arm]
6PORT = 12105
7
8[statistics]
9PORT = 12104
10UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
11
12[resolver]
13PORT = 12103
14UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
15
16[peerinfo]
17PORT = 12102
18UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
19
20[transport]
21PORT = 12101
22PLUGINS = https_client
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
24
25
diff --git a/src/transport/test_transport_api_timeout_https_peer2.conf b/src/transport/test_transport_api_timeout_https_peer2.conf
deleted file mode 100644
index bfdf0caec..000000000
--- a/src/transport/test_transport_api_timeout_https_peer2.conf
+++ /dev/null
@@ -1,31 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-https-p2/
4
5[transport-https_server]
6PORT = 12110
7KEY_FILE = $GNUNET_TEST_HOME/https_key_p2.key
8CERT_FILE = $GNUNET_TEST_HOME/https_cert_p2.crt
9
10[arm]
11PORT = 12115
12UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
13
14[statistics]
15PORT = 12114
16UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
17
18[resolver]
19PORT = 12113
20UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
21
22[peerinfo]
23PORT = 12112
24UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
25
26[transport]
27PORT = 12111
28PLUGINS = https_server
29UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
30
31
diff --git a/src/transport/test_transport_api_timeout_tcp_peer1.conf b/src/transport/test_transport_api_timeout_tcp_peer1.conf
deleted file mode 100644
index 389250bec..000000000
--- a/src/transport/test_transport_api_timeout_tcp_peer1.conf
+++ /dev/null
@@ -1,30 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
4
5[transport-tcp]
6PORT = 12000
7TIMEOUT = 5 s
8
9[arm]
10PORT = 12005
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
12
13[statistics]
14PORT = 12004
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
16
17[resolver]
18PORT = 12003
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
20
21[peerinfo]
22PORT = 12002
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
24
25[transport]
26PORT = 12001
27PLUGINS = tcp
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
29
30
diff --git a/src/transport/test_transport_api_timeout_tcp_peer2.conf b/src/transport/test_transport_api_timeout_tcp_peer2.conf
deleted file mode 100644
index 225b8fac2..000000000
--- a/src/transport/test_transport_api_timeout_tcp_peer2.conf
+++ /dev/null
@@ -1,32 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
4
5[nat]
6ALLOW_NAT = NO
7
8[transport-tcp]
9PORT = 12100
10
11[arm]
12PORT = 12014
13UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
14
15[statistics]
16PORT = 12013
17UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
18
19[resolver]
20PORT = 12012
21UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
22
23[peerinfo]
24PORT = 12011
25UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
26
27[transport]
28PORT = 12010
29PLUGINS = tcp
30UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
31
32
diff --git a/src/transport/test_transport_api_timeout_udp_peer1.conf b/src/transport/test_transport_api_timeout_udp_peer1.conf
deleted file mode 100644
index e28e3a2e0..000000000
--- a/src/transport/test_transport_api_timeout_udp_peer1.conf
+++ /dev/null
@@ -1,33 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-udp-p1/
4
5[transport-udp]
6PORT = 12040
7BROADCAST = NO
8BROADCAST_INTERVAL = 30000
9MAX_BPS = 50000000
10
11[arm]
12PORT = 12045
13UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
14
15[statistics]
16PORT = 12044
17UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
18
19[resolver]
20PORT = 12043
21UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
22
23[peerinfo]
24PORT = 12042
25UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
26
27[transport]
28#PREFIX = valgrind --leak-check=full
29PORT = 12041
30PLUGINS = udp
31UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
32
33
diff --git a/src/transport/test_transport_api_timeout_udp_peer2.conf b/src/transport/test_transport_api_timeout_udp_peer2.conf
deleted file mode 100644
index 434ef4853..000000000
--- a/src/transport/test_transport_api_timeout_udp_peer2.conf
+++ /dev/null
@@ -1,31 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-udp-p2/
4
5[transport-udp]
6PORT = 12050
7BROADCAST = NO
8MAX_BPS = 50000000
9
10[arm]
11PORT = 12055
12UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
13
14[statistics]
15PORT = 12054
16UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
17
18[resolver]
19PORT = 12053
20UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
21
22[peerinfo]
23PORT = 12052
24UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
25
26[transport]
27PORT = 12051
28PLUGINS = udp
29UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
30
31
diff --git a/src/transport/test_transport_api_timeout_unix_peer1.conf b/src/transport/test_transport_api_timeout_unix_peer1.conf
deleted file mode 100644
index e253aad8c..000000000
--- a/src/transport/test_transport_api_timeout_unix_peer1.conf
+++ /dev/null
@@ -1,28 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-unix-p1/
4
5[arm]
6PORT = 12125
7UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
8
9[statistics]
10PORT = 12124
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
12
13[resolver]
14PORT = 12123
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
16
17[peerinfo]
18PORT = 12122
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
20
21[transport]
22PORT = 12121
23PLUGINS = unix
24UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
25
26[transport-unix]
27PORT = 12120
28
diff --git a/src/transport/test_transport_api_timeout_unix_peer2.conf b/src/transport/test_transport_api_timeout_unix_peer2.conf
deleted file mode 100644
index bd3fccbb3..000000000
--- a/src/transport/test_transport_api_timeout_unix_peer2.conf
+++ /dev/null
@@ -1,28 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-unix-p2/
4
5[arm]
6PORT = 12135
7UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
8
9[statistics]
10PORT = 12134
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
12
13[resolver]
14PORT = 12133
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
16
17[peerinfo]
18PORT = 12132
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
20
21[transport]
22PORT = 12131
23PLUGINS = unix
24UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
25
26[transport-unix]
27PORT = 12136
28
diff --git a/src/transport/test_transport_api_timeout_wlan_peer1.conf b/src/transport/test_transport_api_timeout_wlan_peer1.conf
deleted file mode 100644
index 68716d287..000000000
--- a/src/transport/test_transport_api_timeout_wlan_peer1.conf
+++ /dev/null
@@ -1,35 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-wlan-p1/
4
5[transport-wlan]
6INTERFACE = mon0
7TESTMODE = 1
8
9[arm]
10PORT = 12164
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
12
13[statistics]
14PORT = 12163
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
16
17[resolver]
18PORT = 12162
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
20
21[peerinfo]
22PORT = 12161
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
24
25[transport]
26PORT = 12160
27PLUGINS = wlan
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
29#PREFIX = xterm -T transport2 -e gdb --command=cmd --args
30#PREFIX = valgrind --leak-check=full --show-reachable=yes --main-stacksize=104857600
31#PREFIX = valgrind --leak-check=full --show-reachable=yes
32#PREFIX = valgrind --leak-check=full
33#PREFIX = valgrind --tool=massif
34#PREFIX = gdbserver :2345
35
diff --git a/src/transport/test_transport_api_timeout_wlan_peer2.conf b/src/transport/test_transport_api_timeout_wlan_peer2.conf
deleted file mode 100644
index 98bbc6e2b..000000000
--- a/src/transport/test_transport_api_timeout_wlan_peer2.conf
+++ /dev/null
@@ -1,34 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-wlan-p2/
4
5[transport-wlan]
6INTERFACE = mon1
7TESTMODE = 2
8
9[arm]
10PORT = 12174
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
12
13[statistics]
14PORT = 12173
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
16
17[resolver]
18PORT = 12172
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
20
21[peerinfo]
22PORT = 12171
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
24
25[transport]
26PORT = 12170
27PLUGINS = wlan
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
29#PREFIX = xterm -T transport2 -e gdb --command=cmd --args
30#PREFIX = valgrind --leak-check=full --show-reachable=yes --main-stacksize=104857600
31#PREFIX = valgrind --leak-check=full --show-reachable=yes
32#PREFIX = valgrind --leak-check=full
33#PREFIX = valgrind --tool=massif
34#PREFIX = gdbserver :2345
diff --git a/src/transport/test_transport_api_unix_abstract_peer1.conf b/src/transport/test_transport_api_unix_abstract_peer1.conf
deleted file mode 100644
index 103a483b4..000000000
--- a/src/transport/test_transport_api_unix_abstract_peer1.conf
+++ /dev/null
@@ -1,31 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-unix-p1/
4
5[arm]
6PORT = 12125
7UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
8
9[statistics]
10PORT = 12124
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
12
13[resolver]
14PORT = 12123
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
16
17[peerinfo]
18PORT = 12122
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
20
21[transport]
22PORT = 12121
23PLUGINS = unix
24UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
25
26[transport-unix]
27PORT = 12120
28
29[testing]
30USE_ABSTRACT_SOCKETS = YES
31
diff --git a/src/transport/test_transport_api_unix_abstract_peer2.conf b/src/transport/test_transport_api_unix_abstract_peer2.conf
deleted file mode 100644
index c3a5525d9..000000000
--- a/src/transport/test_transport_api_unix_abstract_peer2.conf
+++ /dev/null
@@ -1,31 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-unix-p2/
4
5[arm]
6PORT = 12135
7UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
8
9[statistics]
10PORT = 12134
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
12
13[resolver]
14PORT = 12133
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
16
17[peerinfo]
18PORT = 12132
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
20
21[transport]
22PORT = 12131
23PLUGINS = unix
24UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
25
26[transport-unix]
27PORT = 12136
28
29[testing]
30USE_ABSTRACT_SOCKETS = YES
31
diff --git a/src/transport/test_transport_api_unreliability_bluetooth_peer1.conf b/src/transport/test_transport_api_unreliability_bluetooth_peer1.conf
deleted file mode 100644
index 3f86ee940..000000000
--- a/src/transport/test_transport_api_unreliability_bluetooth_peer1.conf
+++ /dev/null
@@ -1,30 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-bluetooth-p1/
4
5[transport-bluetooth]
6INTERFACE = hci0
7TESTMODE = 1
8
9[arm]
10PORT = 12164
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
12
13[statistics]
14PORT = 12163
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
16
17[resolver]
18PORT = 12162
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
20
21[peerinfo]
22PORT = 12161
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
24
25[transport]
26PORT = 12160
27PLUGINS = bluetooth
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
29
30
diff --git a/src/transport/test_transport_api_unreliability_bluetooth_peer2.conf b/src/transport/test_transport_api_unreliability_bluetooth_peer2.conf
deleted file mode 100644
index 5fc178395..000000000
--- a/src/transport/test_transport_api_unreliability_bluetooth_peer2.conf
+++ /dev/null
@@ -1,29 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-bluetooth-p2/
4
5[transport-bluetooth]
6INTERFACE = hci1
7TESTMODE = 2
8
9[arm]
10PORT = 12174
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
12
13[statistics]
14PORT = 12173
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
16
17[resolver]
18PORT = 12172
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
20
21[peerinfo]
22PORT = 12171
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
24
25[transport]
26PORT = 12170
27PLUGINS = bluetooth
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
29
diff --git a/src/transport/test_transport_api_unreliability_constant_udp_peer1.conf b/src/transport/test_transport_api_unreliability_constant_udp_peer1.conf
deleted file mode 100644
index 9f63c0ced..000000000
--- a/src/transport/test_transport_api_unreliability_constant_udp_peer1.conf
+++ /dev/null
@@ -1,30 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-udp-p1/
4
5[transport-udp]
6PORT = 12040
7MAX_BPS = 1073741824
8
9[arm]
10PORT = 12045
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
12
13[statistics]
14PORT = 12044
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
16
17[resolver]
18PORT = 12043
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
20
21[peerinfo]
22PORT = 12042
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
24
25[transport]
26PORT = 12041
27PLUGINS = udp
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
29
30
diff --git a/src/transport/test_transport_api_unreliability_constant_udp_peer2.conf b/src/transport/test_transport_api_unreliability_constant_udp_peer2.conf
deleted file mode 100644
index cdf3d7bb4..000000000
--- a/src/transport/test_transport_api_unreliability_constant_udp_peer2.conf
+++ /dev/null
@@ -1,30 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-udp-p2/
4
5[transport-udp]
6PORT = 12050
7MAX_BPS = 1073741824
8
9[arm]
10PORT = 12055
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
12
13[statistics]
14PORT = 12054
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
16
17[resolver]
18PORT = 12053
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
20
21[peerinfo]
22PORT = 12052
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
24
25[transport]
26PORT = 12051
27PLUGINS = udp
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
29
30
diff --git a/src/transport/test_transport_api_unreliability_wlan_peer1.conf b/src/transport/test_transport_api_unreliability_wlan_peer1.conf
deleted file mode 100644
index 78e280b68..000000000
--- a/src/transport/test_transport_api_unreliability_wlan_peer1.conf
+++ /dev/null
@@ -1,29 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-wlan-p1/
4
5[transport-wlan]
6TESTMODE = 1
7
8[arm]
9PORT = 12164
10UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
11
12[statistics]
13PORT = 12163
14UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
15
16[resolver]
17PORT = 12162
18UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
19
20[peerinfo]
21PORT = 12161
22UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
23
24[transport]
25PORT = 12160
26PLUGINS = wlan
27UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
28
29
diff --git a/src/transport/test_transport_api_unreliability_wlan_peer2.conf b/src/transport/test_transport_api_unreliability_wlan_peer2.conf
deleted file mode 100644
index e97ab3f38..000000000
--- a/src/transport/test_transport_api_unreliability_wlan_peer2.conf
+++ /dev/null
@@ -1,29 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-wlan-p2/
4
5[transport-wlan]
6INTERFACE = mon1
7TESTMODE = 2
8
9[arm]
10PORT = 12174
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
12
13[statistics]
14PORT = 12173
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
16
17[resolver]
18PORT = 12172
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
20
21[peerinfo]
22PORT = 12171
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
24
25[transport]
26PORT = 12170
27PLUGINS = wlan
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
29
diff --git a/src/transport/test_transport_api_wlan_peer1.conf b/src/transport/test_transport_api_wlan_peer1.conf
deleted file mode 100644
index 68716d287..000000000
--- a/src/transport/test_transport_api_wlan_peer1.conf
+++ /dev/null
@@ -1,35 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-wlan-p1/
4
5[transport-wlan]
6INTERFACE = mon0
7TESTMODE = 1
8
9[arm]
10PORT = 12164
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
12
13[statistics]
14PORT = 12163
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
16
17[resolver]
18PORT = 12162
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
20
21[peerinfo]
22PORT = 12161
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
24
25[transport]
26PORT = 12160
27PLUGINS = wlan
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
29#PREFIX = xterm -T transport2 -e gdb --command=cmd --args
30#PREFIX = valgrind --leak-check=full --show-reachable=yes --main-stacksize=104857600
31#PREFIX = valgrind --leak-check=full --show-reachable=yes
32#PREFIX = valgrind --leak-check=full
33#PREFIX = valgrind --tool=massif
34#PREFIX = gdbserver :2345
35
diff --git a/src/transport/test_transport_api_wlan_peer2.conf b/src/transport/test_transport_api_wlan_peer2.conf
deleted file mode 100644
index 98bbc6e2b..000000000
--- a/src/transport/test_transport_api_wlan_peer2.conf
+++ /dev/null
@@ -1,34 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-wlan-p2/
4
5[transport-wlan]
6INTERFACE = mon1
7TESTMODE = 2
8
9[arm]
10PORT = 12174
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
12
13[statistics]
14PORT = 12173
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
16
17[resolver]
18PORT = 12172
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
20
21[peerinfo]
22PORT = 12171
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
24
25[transport]
26PORT = 12170
27PLUGINS = wlan
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
29#PREFIX = xterm -T transport2 -e gdb --command=cmd --args
30#PREFIX = valgrind --leak-check=full --show-reachable=yes --main-stacksize=104857600
31#PREFIX = valgrind --leak-check=full --show-reachable=yes
32#PREFIX = valgrind --leak-check=full
33#PREFIX = valgrind --tool=massif
34#PREFIX = gdbserver :2345
diff --git a/src/transport/test_transport_blacklisting.c b/src/transport/test_transport_blacklisting.c
deleted file mode 100644
index 204935dcb..000000000
--- a/src/transport/test_transport_blacklisting.c
+++ /dev/null
@@ -1,582 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010, 2011 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/transport_api_blacklisting.c
23 * @brief test for the blacklisting with blacklistings defined in cfg
24 *
25 * this file contains multiple tests:
26 *
27 * test_transport_blacklisting_no_bl:
28 * no blacklisting entries
29 * peers are expected to connect
30 * test_transport_blacklisting_outbound_bl_full:
31 * both peers contain bl entries for full peer
32 * test is expected to not connect
33 * test_transport_blacklisting_outbound_bl_plugin:
34 * both peers contain bl entries for plugin
35 * test is expected to not connect
36 * test_transport_blacklisting_inbound_bl_plugin:
37 * peer 1 contains no bl entries
38 * peer 2 contain bl entries for full peer
39 * test is expected to not connect
40 * test_transport_blacklisting_inbound_bl_full:
41 * peer 1 contains no bl entries
42 * peer 2 contain bl entries for plugin
43 * test is expected to not connect
44 * test_transport_blacklisting_multiple_plugins:
45 * both peers contain bl entries for plugin
46 * test is expected to connect with not bl'ed plugin
47 *
48 * @author Matthias Wachs
49 *
50 */
51#include "platform.h"
52#include "gnunet_transport_service.h"
53#include "transport-testing.h"
54
55char *test_name;
56
57struct GNUNET_TRANSPORT_TESTING_PeerContext *p1;
58
59struct GNUNET_TRANSPORT_TESTING_PeerContext *p2;
60
61static struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
62
63struct GNUNET_TRANSPORT_TESTING_Handle *tth;
64
65/**
66 * How long until we give up on transmitting the message?
67 */
68#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 20)
69
70#define CONNECT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, \
71 10)
72
73static int stage;
74static int ok;
75static int connected;
76
77static struct GNUNET_SCHEDULER_Task *die_task;
78
79static struct GNUNET_SCHEDULER_Task *timeout_task;
80
81static struct GNUNET_SCHEDULER_Task *stage_task;
82
83#if VERBOSE
84#define OKPP do { ok++; fprintf (stderr, "Now at stage %u at %s:%u\n", ok, \
85 __FILE__, __LINE__); } while (0)
86#else
87#define OKPP do { ok++; } while (0)
88#endif
89
90
91static void
92run_stage (void *cls);
93
94
95static void
96end (void *cls)
97{
98 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping\n");
99
100 if (die_task != NULL)
101 {
102 GNUNET_SCHEDULER_cancel (die_task);
103 die_task = NULL;
104 }
105
106 if (timeout_task != NULL)
107 {
108 GNUNET_SCHEDULER_cancel (timeout_task);
109 timeout_task = NULL;
110 }
111
112 if (stage_task != NULL)
113 {
114 GNUNET_SCHEDULER_cancel (stage_task);
115 stage_task = NULL;
116 }
117
118 if (cc != NULL)
119 {
120 GNUNET_TRANSPORT_TESTING_connect_peers_cancel (cc);
121 cc = NULL;
122 }
123
124 if (p1 != NULL)
125 {
126 GNUNET_TRANSPORT_TESTING_stop_peer (p1);
127 p1 = NULL;
128 }
129 if (p2 != NULL)
130 {
131 GNUNET_TRANSPORT_TESTING_stop_peer (p2);
132 p2 = NULL;
133 }
134}
135
136
137static void
138end_badly (void *cls)
139{
140 die_task = NULL;
141
142 if (timeout_task != NULL)
143 {
144 GNUNET_SCHEDULER_cancel (timeout_task);
145 timeout_task = NULL;
146 }
147
148 if (stage_task != NULL)
149 {
150 GNUNET_SCHEDULER_cancel (stage_task);
151 stage_task = NULL;
152 }
153
154 if (cc != NULL)
155 {
156 GNUNET_TRANSPORT_TESTING_connect_peers_cancel (cc);
157 cc = NULL;
158 }
159 if (p1 != NULL)
160 GNUNET_TRANSPORT_TESTING_stop_peer (p1);
161 if (p2 != NULL)
162 GNUNET_TRANSPORT_TESTING_stop_peer (p2);
163
164 ok = GNUNET_SYSERR;
165}
166
167
168static void
169testing_connect_cb (void *cls)
170{
171 cc = NULL;
172 char *p1_c = GNUNET_strdup (GNUNET_i2s (&p1->id));
173
174 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Peers connected: %u (%s) <-> %u (%s)\n",
175 p1->no, p1_c, p2->no, GNUNET_i2s (&p2->id));
176 GNUNET_free (p1_c);
177 connected = GNUNET_YES;
178 stage_task = GNUNET_SCHEDULER_add_now (&run_stage, NULL);
179}
180
181
182static void
183connect_timeout (void *cls)
184{
185 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
186 "Peers not connected, next stage\n");
187 timeout_task = NULL;
188 stage_task = GNUNET_SCHEDULER_add_now (&run_stage,
189 NULL);
190}
191
192
193static int started;
194
195
196static void
197start_cb (void *cls)
198{
199 struct GNUNET_TRANSPORT_TESTING_PeerContext *p = cls;
200
201 started++;
202 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
203 "Peer %u (`%s') started\n",
204 p->no,
205 GNUNET_i2s_full (&p->id));
206
207 if (started != 2)
208 return;
209
210 char *sender_c = GNUNET_strdup (GNUNET_i2s (&p1->id));
211
212 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
213 "Test tries to connect peer %u (`%s') -> peer %u (`%s')\n",
214 p1->no,
215 sender_c,
216 p2->no,
217 GNUNET_i2s (&p2->id));
218 GNUNET_free (sender_c);
219
220 cc = GNUNET_TRANSPORT_TESTING_connect_peers (p1,
221 p2,
222 &testing_connect_cb,
223 NULL);
224}
225
226
227static int
228check_blacklist_config (const char *cfg_file,
229 struct GNUNET_PeerIdentity *peer,
230 struct GNUNET_PeerIdentity *bl_peer)
231{
232 struct GNUNET_CONFIGURATION_Handle *cfg;
233 char *section;
234 char *peer_str;
235
236 cfg = GNUNET_CONFIGURATION_create ();
237 if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, cfg_file))
238 {
239 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not load configuration `%s'\n",
240 cfg_file);
241 GNUNET_CONFIGURATION_destroy (cfg);
242 return GNUNET_SYSERR;
243 }
244
245 peer_str = GNUNET_strdup (GNUNET_i2s_full (peer));
246 GNUNET_asprintf (&section, "transport-blacklist-%s", peer_str);
247
248 if (GNUNET_NO == GNUNET_CONFIGURATION_have_value (cfg, section,
249 GNUNET_i2s_full (bl_peer)))
250 {
251 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
252 "Configuration `%s' does not have blacklisting section for peer `%s' blacklisting `%s'\n",
253 cfg_file, peer_str, GNUNET_i2s_full (bl_peer));
254 GNUNET_CONFIGURATION_destroy (cfg);
255 GNUNET_free (section);
256 GNUNET_free (peer_str);
257 return GNUNET_SYSERR;
258 }
259
260 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
261 "Configuration `%s' does have blacklisting section for peer `%s' blacklisting `%s'\n",
262 cfg_file, peer_str, GNUNET_i2s_full (bl_peer));
263
264 GNUNET_CONFIGURATION_destroy (cfg);
265 GNUNET_free (section);
266 GNUNET_free (peer_str);
267 return GNUNET_OK;
268}
269
270
271static void
272run_stage (void *cls)
273{
274 stage_task = NULL;
275 if (NULL != die_task)
276 GNUNET_SCHEDULER_cancel (die_task);
277 die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL);
278 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Running stage %u\n", stage);
279
280 if (0 == stage)
281 {
282 started = GNUNET_NO;
283 connected = GNUNET_NO;
284 if (0 == strcmp (test_name, "test_transport_blacklisting_no_bl"))
285 {
286 /* Try to connect peers successfully */
287 p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth,
288 "test_transport_blacklisting_cfg_peer1.conf",
289 1,
290 NULL,
291 NULL,
292 NULL,
293 NULL,
294 &start_cb,
295 NULL);
296
297 p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth,
298 "test_transport_blacklisting_cfg_peer2.conf",
299 2,
300 NULL,
301 NULL,
302 NULL,
303 NULL,
304 &start_cb,
305 NULL);
306 }
307 else if (0 == strcmp (test_name,
308 "test_transport_blacklisting_outbound_bl_full"))
309 {
310 const char *cfg_p1 =
311 "test_transport_blacklisting_cfg_blp_peer1_full.conf";
312 const char *cfg_p2 =
313 "test_transport_blacklisting_cfg_blp_peer2_full.conf";
314
315 p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth,
316 cfg_p1,
317 1, NULL, NULL, NULL,
318 NULL,
319 &start_cb, NULL);
320 p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth,
321 cfg_p2, 2,
322 NULL, NULL, NULL,
323 NULL,
324 &start_cb, NULL);
325
326 /* check if configuration contain correct blacklist entries */
327 if ((GNUNET_SYSERR ==
328 check_blacklist_config (cfg_p1, &p1->id, &p2->id)) ||
329 (GNUNET_SYSERR ==
330 check_blacklist_config (cfg_p2, &p2->id, &p1->id)))
331 {
332 GNUNET_TRANSPORT_TESTING_stop_peer (p1);
333 p1 = NULL;
334 GNUNET_TRANSPORT_TESTING_stop_peer (p2);
335 p2 = NULL;
336 ok = 1;
337 GNUNET_SCHEDULER_add_now (&end, NULL);
338 }
339 }
340 else if (0
341 == strcmp (test_name,
342 "test_transport_blacklisting_outbound_bl_plugin"))
343 {
344 const char *cfg_p1 =
345 "test_transport_blacklisting_cfg_blp_peer1_plugin.conf";
346 const char *cfg_p2 =
347 "test_transport_blacklisting_cfg_blp_peer2_plugin.conf";
348
349 p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth,
350 cfg_p1,
351 1,
352 NULL,
353 NULL,
354 NULL,
355 NULL,
356 &start_cb,
357 NULL);
358
359 p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth,
360 cfg_p2, 2,
361 NULL,
362 NULL,
363 NULL,
364 NULL,
365 &start_cb,
366 NULL);
367
368 /* check if configuration contain correct blacklist entries */
369 if ((GNUNET_SYSERR ==
370 check_blacklist_config (cfg_p1, &p1->id, &p2->id)) ||
371 (GNUNET_SYSERR ==
372 check_blacklist_config (cfg_p2, &p2->id, &p1->id)))
373 {
374 GNUNET_TRANSPORT_TESTING_stop_peer (p1);
375 p1 = NULL;
376 GNUNET_TRANSPORT_TESTING_stop_peer (p2);
377 p2 = NULL;
378 ok = 1;
379 GNUNET_SCHEDULER_add_now (&end, NULL);
380 }
381 }
382 else if (0 == strcmp (test_name,
383 "test_transport_blacklisting_inbound_bl_full"))
384 {
385 const char *cfg_p1 = "test_transport_blacklisting_cfg_peer1.conf";
386 const char *cfg_p2 =
387 "test_transport_blacklisting_cfg_blp_peer2_full.conf";
388
389 p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth,
390 cfg_p1, 1,
391 NULL,
392 NULL, NULL, NULL,
393 &start_cb, NULL);
394
395 p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth,
396 cfg_p2, 2,
397 NULL,
398 NULL, NULL, NULL,
399 &start_cb, NULL);
400
401 /* check if configuration contain correct blacklist entries */
402 if ((GNUNET_SYSERR ==
403 check_blacklist_config (cfg_p2, &p2->id, &p1->id)))
404 {
405 GNUNET_TRANSPORT_TESTING_stop_peer (p1);
406 p1 = NULL;
407 GNUNET_TRANSPORT_TESTING_stop_peer (p2);
408 p2 = NULL;
409 ok = 1;
410 GNUNET_SCHEDULER_add_now (&end, NULL);
411 }
412 }
413 else if (0 == strcmp (test_name,
414 "test_transport_blacklisting_inbound_bl_plugin"))
415 {
416 const char *cfg_p1 = "test_transport_blacklisting_cfg_peer1.conf";
417 const char *cfg_p2 =
418 "test_transport_blacklisting_cfg_blp_peer2_plugin.conf";
419
420 p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth,
421 cfg_p1, 1,
422 NULL,
423 NULL, NULL, NULL,
424 &start_cb, NULL);
425
426 p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth,
427 cfg_p2, 2,
428 NULL,
429 NULL, NULL,
430 NULL,
431 &start_cb, NULL);
432
433 /* check if configuration contain correct blacklist entries */
434 if ((GNUNET_SYSERR ==
435 check_blacklist_config (cfg_p2, &p2->id, &p1->id)))
436 {
437 GNUNET_TRANSPORT_TESTING_stop_peer (p1);
438 p1 = NULL;
439 GNUNET_TRANSPORT_TESTING_stop_peer (p2);
440 p2 = NULL;
441 ok = 1;
442 GNUNET_SCHEDULER_add_now (&end, NULL);
443 }
444 }
445 else if (0 == strcmp (test_name,
446 "test_transport_blacklisting_multiple_plugins"))
447 {
448 const char *cfg_p1 =
449 "test_transport_blacklisting_cfg_blp_peer1_multiple_plugins.conf";
450 const char *cfg_p2 =
451 "test_transport_blacklisting_cfg_blp_peer2_multiple_plugins.conf";
452
453 p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth,
454 cfg_p1, 1,
455 NULL,
456 NULL, NULL, NULL,
457 &start_cb, NULL);
458
459 p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth,
460 cfg_p2, 2,
461 NULL,
462 NULL, NULL, NULL,
463 &start_cb, NULL);
464
465 /* check if configuration contain correct blacklist entries */
466 if ((GNUNET_SYSERR ==
467 check_blacklist_config (cfg_p1, &p1->id, &p2->id)) ||
468 (GNUNET_SYSERR ==
469 check_blacklist_config (cfg_p2, &p2->id, &p1->id)))
470 {
471 GNUNET_TRANSPORT_TESTING_stop_peer (p1);
472 p1 = NULL;
473 GNUNET_TRANSPORT_TESTING_stop_peer (p2);
474 p2 = NULL;
475 ok = 1;
476 GNUNET_SCHEDULER_add_now (&end, NULL);
477 }
478 }
479 else
480 {
481 GNUNET_break (0);
482 GNUNET_SCHEDULER_add_now (&end, NULL);
483 }
484
485 if ((NULL == p1) || (NULL == p2))
486 {
487 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to start peers\n");
488 ok = 1;
489 GNUNET_SCHEDULER_add_now (&end, NULL);
490 }
491
492 timeout_task = GNUNET_SCHEDULER_add_delayed (CONNECT_TIMEOUT,
493 &connect_timeout,
494 NULL);
495 stage++;
496 return;
497 }
498
499 if (cc != NULL)
500 {
501 GNUNET_TRANSPORT_TESTING_connect_peers_cancel (cc);
502 cc = NULL;
503 }
504
505 if (p1 != NULL)
506 {
507 GNUNET_TRANSPORT_TESTING_stop_peer (p1);
508 p1 = NULL;
509 }
510 if (p2 != NULL)
511 {
512 GNUNET_TRANSPORT_TESTING_stop_peer (p2);
513 p2 = NULL;
514 }
515
516 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Done in stage %u: Peers %s and %s!\n",
517 stage, (GNUNET_NO == started) ? "NOT STARTED" : "STARTED",
518 (GNUNET_YES == connected) ? "CONNECTED" : "NOT CONNECTED");
519
520 if ((0 == strcmp (test_name, "test_transport_blacklisting_no_bl"))
521 || (0 == strcmp (test_name,
522 "test_transport_blacklisting_multiple_plugins")))
523 {
524 if ((GNUNET_NO != started) && (GNUNET_YES == connected))
525 ok = 0;
526 else
527 {
528 GNUNET_break (0);
529 ok = 1;
530 }
531 }
532 else
533 {
534 if ((GNUNET_NO != started) && (GNUNET_YES != connected))
535 ok = 0;
536 else
537 {
538 ok = 1;
539 }
540 }
541 GNUNET_SCHEDULER_add_now (&end, NULL);
542}
543
544
545static void
546run (void *cls, char *const *args, const char *cfgfile,
547 const struct GNUNET_CONFIGURATION_Handle *cfg)
548{
549 connected = GNUNET_NO;
550 stage = 0;
551 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Running test `%s'!\n", test_name);
552 stage_task = GNUNET_SCHEDULER_add_now (&run_stage, NULL);
553}
554
555
556int
557main (int argc, char *argv0[])
558{
559 ok = 1;
560
561 test_name = GNUNET_TRANSPORT_TESTING_get_test_name (argv0[0]);
562
563 GNUNET_log_setup ("test-transport-api-blacklisting", "WARNING", NULL);
564
565 static char *const argv[] =
566 { "date", "-c", "test_transport_api_data.conf", NULL };
567 static struct GNUNET_GETOPT_CommandLineOption options[] =
568 { GNUNET_GETOPT_OPTION_END };
569
570 tth = GNUNET_TRANSPORT_TESTING_init ();
571
572 GNUNET_PROGRAM_run ((sizeof(argv) / sizeof(char *)) - 1, argv,
573 "test-transport-api-blacklisting", "nohelp", options,
574 &run, NULL);
575
576 GNUNET_TRANSPORT_TESTING_done (tth);
577
578 return ok;
579}
580
581
582/* end of transport_api_blacklisting.c */
diff --git a/src/transport/test_transport_blacklisting_cfg_blp_peer1_full.conf b/src/transport/test_transport_blacklisting_cfg_blp_peer1_full.conf
deleted file mode 100644
index 19bff8fcc..000000000
--- a/src/transport/test_transport_blacklisting_cfg_blp_peer1_full.conf
+++ /dev/null
@@ -1,16 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
4
5[transport-tcp]
6PORT = 12000
7TIMEOUT = 5 s
8
9[transport]
10PLUGINS = tcp
11
12#Peer 1: 4TTC9WBSVP9RJT6DVEZ7E0TDW7TQXC11NR1EMR2F8ARS87WZ2730
13#Peer 2: F7B5NX6KCPG8SAKYSGV0E94Y5NXR9JE3HCGQ5YGH1H04WFQWMWT0
14
15[transport-blacklist-4TTC9WBSVP9RJT6DVEZ7E0TDW7TQXC11NR1EMR2F8ARS87WZ2730]
16F7B5NX6KCPG8SAKYSGV0E94Y5NXR9JE3HCGQ5YGH1H04WFQWMWT0 =
diff --git a/src/transport/test_transport_blacklisting_cfg_blp_peer1_multiple_plugins.conf b/src/transport/test_transport_blacklisting_cfg_blp_peer1_multiple_plugins.conf
deleted file mode 100644
index 79bc90469..000000000
--- a/src/transport/test_transport_blacklisting_cfg_blp_peer1_multiple_plugins.conf
+++ /dev/null
@@ -1,13 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
4
5[transport]
6PLUGINS = tcp unix
7
8#Peer 1: 4TTC9WBSVP9RJT6DVEZ7E0TDW7TQXC11NR1EMR2F8ARS87WZ2730
9#Peer 2: F7B5NX6KCPG8SAKYSGV0E94Y5NXR9JE3HCGQ5YGH1H04WFQWMWT0
10
11[transport-blacklist-4TTC9WBSVP9RJT6DVEZ7E0TDW7TQXC11NR1EMR2F8ARS87WZ2730]
12F7B5NX6KCPG8SAKYSGV0E94Y5NXR9JE3HCGQ5YGH1H04WFQWMWT0 = tcp
13
diff --git a/src/transport/test_transport_blacklisting_cfg_blp_peer1_plugin.conf b/src/transport/test_transport_blacklisting_cfg_blp_peer1_plugin.conf
deleted file mode 100644
index b328dd5cf..000000000
--- a/src/transport/test_transport_blacklisting_cfg_blp_peer1_plugin.conf
+++ /dev/null
@@ -1,13 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
4
5[transport]
6PLUGINS = tcp
7
8#Peer 1: 4TTC9WBSVP9RJT6DVEZ7E0TDW7TQXC11NR1EMR2F8ARS87WZ2730
9#Peer 2: F7B5NX6KCPG8SAKYSGV0E94Y5NXR9JE3HCGQ5YGH1H04WFQWMWT0
10
11[transport-blacklist-4TTC9WBSVP9RJT6DVEZ7E0TDW7TQXC11NR1EMR2F8ARS87WZ2730]
12F7B5NX6KCPG8SAKYSGV0E94Y5NXR9JE3HCGQ5YGH1H04WFQWMWT0 = tcp
13
diff --git a/src/transport/test_transport_blacklisting_cfg_blp_peer2_full.conf b/src/transport/test_transport_blacklisting_cfg_blp_peer2_full.conf
deleted file mode 100644
index 862209d2c..000000000
--- a/src/transport/test_transport_blacklisting_cfg_blp_peer2_full.conf
+++ /dev/null
@@ -1,12 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
4
5[transport]
6PLUGINS = tcp
7
8#Peer 1: 4TTC9WBSVP9RJT6DVEZ7E0TDW7TQXC11NR1EMR2F8ARS87WZ2730
9#Peer 2: F7B5NX6KCPG8SAKYSGV0E94Y5NXR9JE3HCGQ5YGH1H04WFQWMWT0
10
11[transport-blacklist-F7B5NX6KCPG8SAKYSGV0E94Y5NXR9JE3HCGQ5YGH1H04WFQWMWT0]
124TTC9WBSVP9RJT6DVEZ7E0TDW7TQXC11NR1EMR2F8ARS87WZ2730 =
diff --git a/src/transport/test_transport_blacklisting_cfg_blp_peer2_multiple_plugins.conf b/src/transport/test_transport_blacklisting_cfg_blp_peer2_multiple_plugins.conf
deleted file mode 100644
index 3134f9d81..000000000
--- a/src/transport/test_transport_blacklisting_cfg_blp_peer2_multiple_plugins.conf
+++ /dev/null
@@ -1,12 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
4
5[transport]
6PLUGINS = tcp unix
7
8#Peer 1: 4TTC9WBSVP9RJT6DVEZ7E0TDW7TQXC11NR1EMR2F8ARS87WZ2730
9#Peer 2: F7B5NX6KCPG8SAKYSGV0E94Y5NXR9JE3HCGQ5YGH1H04WFQWMWT0
10
11[transport-blacklist-F7B5NX6KCPG8SAKYSGV0E94Y5NXR9JE3HCGQ5YGH1H04WFQWMWT0]
124TTC9WBSVP9RJT6DVEZ7E0TDW7TQXC11NR1EMR2F8ARS87WZ2730 = tcp
diff --git a/src/transport/test_transport_blacklisting_cfg_blp_peer2_plugin.conf b/src/transport/test_transport_blacklisting_cfg_blp_peer2_plugin.conf
deleted file mode 100644
index dd582125d..000000000
--- a/src/transport/test_transport_blacklisting_cfg_blp_peer2_plugin.conf
+++ /dev/null
@@ -1,12 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
4
5[transport]
6PLUGINS = tcp
7
8#Peer 1: 4TTC9WBSVP9RJT6DVEZ7E0TDW7TQXC11NR1EMR2F8ARS87WZ2730
9#Peer 2: F7B5NX6KCPG8SAKYSGV0E94Y5NXR9JE3HCGQ5YGH1H04WFQWMWT0
10
11[transport-blacklist-F7B5NX6KCPG8SAKYSGV0E94Y5NXR9JE3HCGQ5YGH1H04WFQWMWT0]
124TTC9WBSVP9RJT6DVEZ7E0TDW7TQXC11NR1EMR2F8ARS87WZ2730 = tcp
diff --git a/src/transport/test_transport_blacklisting_cfg_peer1.conf b/src/transport/test_transport_blacklisting_cfg_peer1.conf
deleted file mode 100644
index 9150c7faf..000000000
--- a/src/transport/test_transport_blacklisting_cfg_peer1.conf
+++ /dev/null
@@ -1,29 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
4
5[transport-tcp]
6PORT = 12000
7TIMEOUT = 5 s
8
9[arm]
10PORT = 12005
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
12
13[statistics]
14PORT = 12004
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
16
17[resolver]
18PORT = 12003
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
20
21[peerinfo]
22PORT = 12002
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
24
25[transport]
26PORT = 12001
27UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
28PLUGINS = tcp
29
diff --git a/src/transport/test_transport_blacklisting_cfg_peer2.conf b/src/transport/test_transport_blacklisting_cfg_peer2.conf
deleted file mode 100644
index 43bb4ae37..000000000
--- a/src/transport/test_transport_blacklisting_cfg_peer2.conf
+++ /dev/null
@@ -1,28 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
4
5[transport-tcp]
6PORT = 12015
7TIMEOUT = 5 s
8
9[arm]
10PORT = 12014
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
12
13[statistics]
14PORT = 12013
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
16
17[resolver]
18PORT = 12012
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
20
21[peerinfo]
22PORT = 12011
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
24
25[transport]
26PORT = 12010
27PLUGINS = tcp
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
diff --git a/src/transport/test_transport_testing_restart.c b/src/transport/test_transport_testing_restart.c
deleted file mode 100644
index f537af5fc..000000000
--- a/src/transport/test_transport_testing_restart.c
+++ /dev/null
@@ -1,163 +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 it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport/test_transport_testing_restart.c
22 * @brief test case for transport testing library:
23 * start the peer, get the HELLO message, restart and stop the peer
24 */
25#include "platform.h"
26#include "gnunet_transport_service.h"
27#include "transport-testing.h"
28
29#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
30
31
32static struct GNUNET_SCHEDULER_Task *timeout_task;
33
34static struct GNUNET_TRANSPORT_TESTING_PeerContext *p;
35
36static struct GNUNET_TRANSPORT_TESTING_Handle *tth;
37
38static int ret;
39
40
41static void
42end ()
43{
44 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
45 "Stopping peers\n");
46 if (NULL != timeout_task)
47 GNUNET_SCHEDULER_cancel (timeout_task);
48 if (NULL != p)
49 GNUNET_TRANSPORT_TESTING_stop_peer (p);
50 if (NULL != tth)
51 GNUNET_TRANSPORT_TESTING_done (tth);
52}
53
54
55static void
56end_badly ()
57{
58 timeout_task = NULL;
59 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
60 "Timeout!\n");
61 end ();
62 ret = GNUNET_SYSERR;
63}
64
65
66static void
67restart_cb (void *cls)
68{
69 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
70 "Peer %u (`%s') successfully restarted\n",
71 p->no,
72 GNUNET_i2s (&p->id));
73 ret = 0;
74 GNUNET_SCHEDULER_add_now (&end,
75 NULL);
76}
77
78
79static void
80restart_task ()
81{
82 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
83 "Peer %u (`%s') restarting\n",
84 p->no,
85 GNUNET_i2s (&p->id));
86 GNUNET_TRANSPORT_TESTING_restart_peer (p,
87 &restart_cb,
88 p);
89}
90
91
92static void
93start_cb (void *cls)
94{
95 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
96 "Peer %u (`%s') successfully started\n",
97 p->no,
98 GNUNET_i2s (&p->id));
99 GNUNET_SCHEDULER_add_now (&restart_task,
100 NULL);
101}
102
103
104static void
105run (void *cls,
106 char *const *args,
107 const char *cfgfile,
108 const struct GNUNET_CONFIGURATION_Handle *cfg)
109{
110 ret = 1;
111 tth = GNUNET_TRANSPORT_TESTING_init ();
112 GNUNET_assert (NULL != tth);
113
114 timeout_task
115 = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
116 &end_badly,
117 NULL);
118 p = GNUNET_TRANSPORT_TESTING_start_peer (tth,
119 cfgfile,
120 1,
121 NULL, /* receive cb */
122 NULL, /* connect cb */
123 NULL, /* disconnect cb */
124 NULL, /* nc/nd closure */
125 start_cb, /* startup cb */
126 NULL); /* closure */
127 if (NULL == p)
128 {
129 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
130 "Failed to start peer\n");
131 end ();
132 ret = 1;
133 }
134}
135
136
137int
138main (int argc,
139 char *argv[])
140{
141 char *const argv_1[] = { "test_transport_testing_restart",
142 "-c",
143 "test_transport_api_data.conf",
144 NULL };
145 struct GNUNET_GETOPT_CommandLineOption options[] = {
146 GNUNET_GETOPT_OPTION_END
147 };
148
149 GNUNET_log_setup ("test_transport_testing_restart",
150 "WARNING",
151 NULL);
152 GNUNET_PROGRAM_run ((sizeof(argv_1) / sizeof(char *)) - 1,
153 argv_1,
154 "test_transport_testing_restart",
155 "nohelp",
156 options,
157 &run,
158 NULL);
159 return ret;
160}
161
162
163/* end of test_transport_testing_restart.c */
diff --git a/src/transport/transport-testing-filenames.c b/src/transport/transport-testing-filenames.c
deleted file mode 100644
index ee7b0aacf..000000000
--- a/src/transport/transport-testing-filenames.c
+++ /dev/null
@@ -1,175 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2006, 2009, 2015, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport-testing-filenames.c
22 * @brief convenience string manipulation functions for tests
23 * @author Matthias Wachs
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "transport-testing.h"
28
29
30/**
31 * Removes all directory separators from absolute filename
32 *
33 * @param file the absolute file name, e.g. as found in argv[0]
34 * @return extracted file name, has to be freed by caller
35 */
36static char *
37extract_filename (const char *file)
38{
39 char *pch = GNUNET_strdup (file);
40 char *backup = pch;
41 char *filename = NULL;
42 char *res;
43
44 if (NULL != strstr (pch, "/"))
45 {
46 pch = strtok (pch, "/");
47 while (pch != NULL)
48 {
49 pch = strtok (NULL, "/");
50 if (pch != NULL)
51 {
52 filename = pch;
53 }
54 }
55 }
56 else
57 filename = pch;
58
59 res = GNUNET_strdup (filename);
60 GNUNET_free (backup);
61 return res;
62}
63
64
65char *
66GNUNET_TRANSPORT_TESTING_get_test_name (const char *file)
67{
68 char *backup = extract_filename (file);
69 char *filename = backup;
70 char *dotexe;
71 char *ret;
72
73 if (NULL == filename)
74 return NULL;
75
76 /* remove "lt-" */
77 filename = strstr (filename, "test");
78 if (NULL == filename)
79 {
80 GNUNET_free (backup);
81 return NULL;
82 }
83
84 /* remove ".exe" */
85 if (NULL != (dotexe = strstr (filename, ".exe")))
86 dotexe[0] = '\0';
87 ret = GNUNET_strdup (filename);
88 GNUNET_free (backup);
89 return ret;
90}
91
92
93char *
94GNUNET_TRANSPORT_TESTING_get_test_source_name (const char *file)
95{
96 char *src = extract_filename (file);
97 char *split;
98
99 split = strstr (src, ".");
100 if (NULL != split)
101 split[0] = '\0';
102 return src;
103}
104
105
106char *
107GNUNET_TRANSPORT_TESTING_get_test_plugin_name (const char *file,
108 const char *test)
109{
110 char *filename;
111 char *dotexe;
112 char *e = extract_filename (file);
113 char *t = extract_filename (test);
114 char *ret;
115
116 if (NULL == e)
117 goto fail;
118 /* remove "lt-" */
119 filename = strstr (e, "tes");
120 if (NULL == filename)
121 goto fail;
122 /* remove ".exe" */
123 if (NULL != (dotexe = strstr (filename, ".exe")))
124 dotexe[0] = '\0';
125
126 /* find last _ */
127 filename = strstr (filename, t);
128 if (NULL == filename)
129 goto fail;
130 /* copy plugin */
131 filename += strlen (t);
132 if ('\0' != *filename)
133 filename++;
134 ret = GNUNET_strdup (filename);
135 goto suc;
136fail:
137 ret = NULL;
138suc:
139 GNUNET_free (t);
140 GNUNET_free (e);
141 return ret;
142}
143
144
145char *
146GNUNET_TRANSPORT_TESTING_get_config_name (const char *file,
147 int count)
148{
149 char *filename = extract_filename (file);
150 char *backup = filename;
151 char *dotexe;
152 char *ret;
153
154 if (NULL == filename)
155 return NULL;
156 /* remove "lt-" */
157 filename = strstr (filename, "test");
158 if (NULL == filename)
159 goto fail;
160 /* remove ".exe" */
161 if (NULL != (dotexe = strstr (filename, ".exe")))
162 dotexe[0] = '\0';
163 GNUNET_asprintf (&ret,
164 "%s_peer%u.conf",
165 filename,
166 count);
167 GNUNET_free (backup);
168 return ret;
169fail:
170 GNUNET_free (backup);
171 return NULL;
172}
173
174
175/* end of transport-testing-filenames.c */
diff --git a/src/transport/transport-testing-loggers.c b/src/transport/transport-testing-loggers.c
deleted file mode 100644
index 21ed0592a..000000000
--- a/src/transport/transport-testing-loggers.c
+++ /dev/null
@@ -1,81 +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 it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport-testing-loggers.c
22 * @brief convenience functions for logging common events in tests
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "transport-testing.h"
27
28
29/**
30 * Log a connect event.
31 *
32 * @param cls NULL
33 * @param me peer that had the event
34 * @param other peer that connected.
35 */
36void
37GNUNET_TRANSPORT_TESTING_log_connect (void *cls,
38 struct
39 GNUNET_TRANSPORT_TESTING_PeerContext *me,
40 const struct GNUNET_PeerIdentity *other)
41{
42 char *ps;
43
44 ps = GNUNET_strdup (GNUNET_i2s (&me->id));
45 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
46 "Peer %s connected to %u (%s)!\n",
47 GNUNET_i2s (other),
48 me->no,
49 ps);
50 GNUNET_free (ps);
51}
52
53
54/**
55 * Log a disconnect event.
56 *
57 * @param cls NULL
58 * @param me peer that had the event
59 * @param other peer that disconnected.
60 */
61void
62GNUNET_TRANSPORT_TESTING_log_disconnect (void *cls,
63 struct
64 GNUNET_TRANSPORT_TESTING_PeerContext *
65 me,
66 const struct
67 GNUNET_PeerIdentity *other)
68{
69 char *ps;
70
71 ps = GNUNET_strdup (GNUNET_i2s (&me->id));
72 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
73 "Peer `%s' disconnected from %u (%s)!\n",
74 GNUNET_i2s (other),
75 me->no,
76 ps);
77 GNUNET_free (ps);
78}
79
80
81/* end of transport-testing-loggers.c */
diff --git a/src/transport/transport-testing-main.c b/src/transport/transport-testing-main.c
deleted file mode 100644
index 63b91713c..000000000
--- a/src/transport/transport-testing-main.c
+++ /dev/null
@@ -1,614 +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 it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport-testing-main.c
22 * @brief convenience main function for tests
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "transport-testing.h"
27
28
29/**
30 * Closure for #connect_cb.
31 */
32struct GNUNET_TRANSPORT_TESTING_ConnectRequestList
33{
34 /**
35 * Stored in a DLL.
36 */
37 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *next;
38
39 /**
40 * Stored in a DLL.
41 */
42 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *prev;
43
44 /**
45 * Overall context we are in.
46 */
47 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
48
49 /**
50 * Connect request this is about.
51 */
52 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cr;
53
54 /**
55 * Peer being connected.
56 */
57 struct GNUNET_TRANSPORT_TESTING_PeerContext *p1;
58
59 /**
60 * Peer being connected.
61 */
62 struct GNUNET_TRANSPORT_TESTING_PeerContext *p2;
63};
64
65
66/**
67 * Shutdown function for the test. Stops all peers.
68 *
69 * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *`
70 */
71static void
72do_shutdown (void *cls)
73{
74 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = cls;
75 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *crl;
76
77 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
78 "Testcase shutting down\n");
79 if (NULL != ccc->shutdown_task)
80 ccc->shutdown_task (ccc->shutdown_task_cls);
81 if (NULL != ccc->timeout_task)
82 {
83 GNUNET_SCHEDULER_cancel (ccc->timeout_task);
84 ccc->timeout_task = NULL;
85 }
86 if (NULL != ccc->connect_task)
87 {
88 GNUNET_SCHEDULER_cancel (ccc->connect_task);
89 ccc->connect_task = NULL;
90 }
91 while (NULL != (crl = ccc->crl_head))
92 {
93 GNUNET_CONTAINER_DLL_remove (ccc->crl_head,
94 ccc->crl_tail,
95 crl);
96 GNUNET_TRANSPORT_TESTING_connect_peers_cancel (crl->cr);
97 GNUNET_free (crl);
98 }
99 for (unsigned int i = 0; i < ccc->num_peers; i++)
100 {
101 if (NULL != ccc->p[i])
102 {
103 GNUNET_TRANSPORT_TESTING_stop_peer (ccc->p[i]);
104 ccc->p[i] = NULL;
105 }
106 }
107}
108
109
110/**
111 * Testcase hit timeout, shut it down with error.
112 *
113 * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *`
114 */
115static void
116do_timeout (void *cls)
117{
118 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = cls;
119
120 ccc->timeout_task = NULL;
121 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
122 "Testcase timed out\n");
123 ccc->global_ret = GNUNET_SYSERR;
124 GNUNET_SCHEDULER_shutdown ();
125}
126
127
128/**
129 * Internal data structure. Closure for
130 * #connect_cb, #disconnect_cb, #my_nc and #start_cb.
131 * Allows us to identify which peer this is about.
132 */
133struct GNUNET_TRANSPORT_TESTING_InternalPeerContext
134{
135 /**
136 * Overall context of the callback.
137 */
138 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
139
140 /**
141 * Offset of the peer this is about.
142 */
143 unsigned int off;
144};
145
146
147/**
148 * Information tracked per connected peer.
149 */
150struct ConnectPairInfo
151{
152 /**
153 * Peer this is about.
154 */
155 const struct GNUNET_PeerIdentity *sender;
156
157 /**
158 * Information about the receiving peer.
159 */
160 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi;
161};
162
163
164/**
165 * Function called when we connected two peers. Once we have gotten
166 * to the clique, launch test-specific logic.
167 *
168 * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *`
169 */
170static void
171connect_cb (void *cls)
172{
173 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *crl = cls;
174 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = crl->ccc;
175
176 GNUNET_CONTAINER_DLL_remove (ccc->crl_head,
177 ccc->crl_tail,
178 crl);
179 {
180 char *p1_c = GNUNET_strdup (GNUNET_i2s (&crl->p1->id));
181
182 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
183 "Peers connected: %u (%s) <-> %u (%s)\n",
184 crl->p1->no,
185 p1_c,
186 crl->p2->no,
187 GNUNET_i2s (&crl->p2->id));
188 GNUNET_free (p1_c);
189 GNUNET_free (crl);
190 }
191 if (NULL == ccc->crl_head)
192 {
193 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
194 "All connections UP, launching custom test logic.\n");
195 GNUNET_SCHEDULER_add_now (ccc->connect_continuation,
196 ccc->connect_continuation_cls);
197 }
198}
199
200
201/**
202 * Find peer by peer ID.
203 *
204 * @param ccc context to search
205 * @param peer peer to look for
206 * @return NULL if @a peer was not found
207 */
208struct GNUNET_TRANSPORT_TESTING_PeerContext *
209GNUNET_TRANSPORT_TESTING_find_peer (struct
210 GNUNET_TRANSPORT_TESTING_ConnectCheckContext
211 *ccc,
212 const struct GNUNET_PeerIdentity *peer)
213{
214 for (unsigned int i = 0; i < ccc->num_peers; i++)
215 if ((NULL != ccc->p[i]) &&
216 (0 == memcmp (peer,
217 &ccc->p[i]->id,
218 sizeof(*peer))))
219 return ccc->p[i];
220 return NULL;
221}
222
223
224/**
225 * Wrapper around peers connecting. Calls client's nc function.
226 *
227 * @param cls our `struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *`
228 * @param peer peer we got connected to
229 * @param mq message queue for transmissions to @a peer
230 * @return closure for message handlers
231 */
232static void *
233my_nc (void *cls,
234 const struct GNUNET_PeerIdentity *peer,
235 struct GNUNET_MQ_Handle *mq)
236{
237 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi = cls;
238 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = ipi->ccc;
239 struct ConnectPairInfo *cpi;
240
241 if (NULL != ccc->nc)
242 ccc->nc (ccc->cls,
243 ccc->p[ipi->off],
244 peer);
245 cpi = GNUNET_new (struct ConnectPairInfo);
246 cpi->ipi = ipi;
247 cpi->sender = peer; /* valid until disconnect */
248 return cpi;
249}
250
251
252/**
253 * Wrapper around peers disconnecting. Calls client's nd function.
254 *
255 * @param cls our `struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *`
256 * @param peer peer we got disconnected from
257 * @param custom_cls return value from @a my_nc
258 */
259static void
260my_nd (void *cls,
261 const struct GNUNET_PeerIdentity *peer,
262 void *custom_cls)
263{
264 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi = cls;
265 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = ipi->ccc;
266 struct ConnectPairInfo *cpi = custom_cls;
267
268 if (NULL != ccc->nd)
269 ccc->nd (ccc->cls,
270 ccc->p[ipi->off],
271 peer);
272 GNUNET_free (cpi);
273}
274
275
276/**
277 * Wrapper around receiving data. Calls client's rec function.
278 *
279 * @param cls our `struct ConnectPairInfo *`
280 * @param message message we received
281 * @return #GNUNET_OK (all messages are fine)
282 */
283static int
284check_test (void *cls,
285 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
286{
287 return GNUNET_OK;
288}
289
290
291/**
292 * Wrapper around receiving data. Calls client's rec function.
293 *
294 * @param cls our `struct ConnectPairInfo *`
295 * @param message message we received
296 */
297static void
298handle_test (void *cls,
299 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
300{
301 struct ConnectPairInfo *cpi = cls;
302 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi = cpi->ipi;
303 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = ipi->ccc;
304
305 if (NULL != ccc->rec)
306 ccc->rec (ccc->cls,
307 ccc->p[ipi->off],
308 cpi->sender,
309 message);
310}
311
312
313/**
314 * Wrapper around receiving data. Calls client's rec function.
315 *
316 * @param cls our `struct ConnectPairInfo *`
317 * @param message message we received
318 * @return #GNUNET_OK (all messages are fine)
319 */
320static int
321check_test2 (void *cls,
322 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
323{
324 return GNUNET_OK;
325}
326
327
328/**
329 * Wrapper around receiving data. Calls client's rec function.
330 *
331 * @param cls our `struct ConnectPairInfo *`
332 * @param message message we received
333 */
334static void
335handle_test2 (void *cls,
336 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
337{
338 struct ConnectPairInfo *cpi = cls;
339 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi = cpi->ipi;
340 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = ipi->ccc;
341
342 if (NULL != ccc->rec)
343 ccc->rec (ccc->cls,
344 ccc->p[ipi->off],
345 cpi->sender,
346 message);
347}
348
349
350/**
351 * Connect the peers as a clique.
352 *
353 * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext`
354 */
355static void
356do_connect (void *cls)
357{
358 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = cls;
359
360 ccc->connect_task = NULL;
361 for (unsigned int i = 0; i < ccc->num_peers; i++)
362 for (unsigned int j = (ccc->bi_directional ? 0 : i + 1); j < ccc->num_peers;
363 j++)
364 {
365 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *crl;
366
367 if (i == j)
368 continue;
369 crl = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_ConnectRequestList);
370 GNUNET_CONTAINER_DLL_insert (ccc->crl_head,
371 ccc->crl_tail,
372 crl);
373 crl->ccc = ccc;
374 crl->p1 = ccc->p[i];
375 crl->p2 = ccc->p[j];
376 {
377 char *sender_c = GNUNET_strdup (GNUNET_i2s (&ccc->p[0]->id));
378
379 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
380 "Test tries to connect peer %u (`%s') -> peer %u (`%s')\n",
381 ccc->p[0]->no,
382 sender_c,
383 ccc->p[1]->no,
384 GNUNET_i2s (&ccc->p[1]->id));
385 GNUNET_free (sender_c);
386 }
387 crl->cr = GNUNET_TRANSPORT_TESTING_connect_peers (ccc->p[i],
388 ccc->p[j],
389 &connect_cb,
390 crl);
391 }
392}
393
394
395/**
396 * Function called once we have successfully launched a peer.
397 * Once all peers have been launched, we connect all of them
398 * in a clique.
399 *
400 * @param cls our `struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *`
401 */
402static void
403start_cb (void *cls)
404{
405 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi = cls;
406 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = ipi->ccc;
407 struct GNUNET_TRANSPORT_TESTING_PeerContext *p = ccc->p[ipi->off];
408
409 ccc->started++;
410 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
411 "Peer %u (`%s') started\n",
412 p->no,
413 GNUNET_i2s (&p->id));
414 if (ccc->started != ccc->num_peers)
415 return;
416 if (NULL != ccc->pre_connect_task)
417 {
418 /* Run the custom per-connect job, then give it a second to
419 go into effect before we continue connecting peers. */
420 ccc->pre_connect_task (ccc->pre_connect_task_cls);
421 ccc->connect_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
422 &do_connect,
423 ccc);
424 }
425 else
426 {
427 do_connect (ccc);
428 }
429}
430
431
432/**
433 * Function run from #GNUNET_TRANSPORT_TESTING_connect_check
434 * once the scheduler is up. Should launch the peers and
435 * then in the continuations try to connect them.
436 *
437 * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *`
438 * @param args ignored
439 * @param cfgfile ignored
440 * @param cfg configuration
441 */
442static void
443connect_check_run (void *cls,
444 char *const *args,
445 const char *cfgfile,
446 const struct GNUNET_CONFIGURATION_Handle *cfg)
447{
448 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = cls;
449 int ok;
450
451 ccc->cfg = cfg;
452 ccc->timeout_task = GNUNET_SCHEDULER_add_delayed (ccc->timeout,
453 &do_timeout,
454 ccc);
455 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
456 ccc);
457 ok = GNUNET_OK;
458 for (unsigned int i = 0; i < ccc->num_peers; i++)
459 {
460 struct GNUNET_MQ_MessageHandler handlers[] = {
461 GNUNET_MQ_hd_var_size (test,
462 GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE,
463 struct GNUNET_TRANSPORT_TESTING_TestMessage,
464 NULL),
465 GNUNET_MQ_hd_var_size (test2,
466 GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE2,
467 struct GNUNET_TRANSPORT_TESTING_TestMessage,
468 NULL),
469 GNUNET_MQ_handler_end ()
470 };
471 ccc->p[i] = GNUNET_TRANSPORT_TESTING_start_peer (ccc->tth,
472 ccc->cfg_files[i],
473 i + 1,
474 handlers,
475 &my_nc,
476 &my_nd,
477 &ccc->ip[i],
478 &start_cb,
479 &ccc->ip[i]);
480 if (NULL == ccc->p[i])
481 ok = GNUNET_SYSERR;
482 }
483 if (GNUNET_OK != ok)
484 {
485 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
486 "Fail! Could not start peers!\n");
487 GNUNET_SCHEDULER_shutdown ();
488 }
489}
490
491
492/**
493 * Common implementation of the #GNUNET_TRANSPORT_TESTING_CheckCallback.
494 * Starts and connects the two peers, then invokes the
495 * `connect_continuation` from @a cls. Sets up a timeout to
496 * abort the test, and a shutdown handler to clean up properly
497 * on exit.
498 *
499 * @param cls closure of type `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext`
500 * @param tth_ initialized testing handle
501 * @param test_plugin_ name of the plugin
502 * @param test_name_ name of the test
503 * @param num_peers number of entries in the @a cfg_file array
504 * @param cfg_files array of names of configuration files for the peers
505 * @return #GNUNET_SYSERR on error
506 */
507int
508GNUNET_TRANSPORT_TESTING_connect_check (void *cls,
509 struct GNUNET_TRANSPORT_TESTING_Handle *
510 tth_,
511 const char *test_plugin_,
512 const char *test_name_,
513 unsigned int num_peers,
514 char *cfg_files[])
515{
516 static struct GNUNET_GETOPT_CommandLineOption options[] = {
517 GNUNET_GETOPT_OPTION_END
518 };
519 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = cls;
520 struct GNUNET_TRANSPORT_TESTING_PeerContext *p[num_peers];
521 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext ip[num_peers];
522 char *argv[] = {
523 (char *) test_name_,
524 "-c",
525 (char *) ccc->config_file,
526 NULL
527 };
528
529 ccc->num_peers = num_peers;
530 ccc->cfg_files = cfg_files;
531 ccc->test_plugin = test_plugin_;
532 ccc->test_name = test_name_;
533 ccc->tth = tth_;
534 ccc->global_ret = GNUNET_OK;
535 ccc->p = p;
536 ccc->ip = ip;
537 for (unsigned int i = 0; i < num_peers; i++)
538 {
539 ip[i].off = i;
540 ip[i].ccc = ccc;
541 }
542 if (GNUNET_OK !=
543 GNUNET_PROGRAM_run ((sizeof(argv) / sizeof(char *)) - 1,
544 argv,
545 test_name_,
546 "nohelp",
547 options,
548 &connect_check_run,
549 ccc))
550 return GNUNET_SYSERR;
551 return ccc->global_ret;
552}
553
554
555/**
556 * Setup testcase. Calls @a check with the data the test needs.
557 *
558 * @param argv0 binary name (argv[0])
559 * @param filename source file name (__FILE__)
560 * @param num_peers number of peers to start
561 * @param check main function to run
562 * @param check_cls closure for @a check
563 * @return #GNUNET_OK on success
564 */
565int
566GNUNET_TRANSPORT_TESTING_main_ (const char *argv0,
567 const char *filename,
568 unsigned int num_peers,
569 GNUNET_TRANSPORT_TESTING_CheckCallback check,
570 void *check_cls)
571{
572 struct GNUNET_TRANSPORT_TESTING_Handle *tth;
573 char *test_name;
574 char *test_source;
575 char *test_plugin;
576 char *cfg_names[num_peers];
577 int ret;
578
579 ret = GNUNET_OK;
580 test_name = GNUNET_TRANSPORT_TESTING_get_test_name (argv0);
581 GNUNET_log_setup (test_name,
582 "WARNING",
583 NULL);
584 test_source = GNUNET_TRANSPORT_TESTING_get_test_source_name (filename);
585 test_plugin = GNUNET_TRANSPORT_TESTING_get_test_plugin_name (argv0,
586 test_source);
587 for (unsigned int i = 0; i < num_peers; i++)
588 cfg_names[i] = GNUNET_TRANSPORT_TESTING_get_config_name (argv0,
589 i + 1);
590 tth = GNUNET_TRANSPORT_TESTING_init ();
591 if (NULL == tth)
592 {
593 ret = GNUNET_SYSERR;
594 }
595 else
596 {
597 ret = check (check_cls,
598 tth,
599 test_plugin,
600 test_name,
601 num_peers,
602 cfg_names);
603 GNUNET_TRANSPORT_TESTING_done (tth);
604 }
605 for (unsigned int i = 0; i < num_peers; i++)
606 GNUNET_free (cfg_names[i]);
607 GNUNET_free (test_source);
608 GNUNET_free (test_plugin);
609 GNUNET_free (test_name);
610 return ret;
611}
612
613
614/* end of transport-testing-main.c */
diff --git a/src/transport/transport-testing-send.c b/src/transport/transport-testing-send.c
deleted file mode 100644
index 9b017c563..000000000
--- a/src/transport/transport-testing-send.c
+++ /dev/null
@@ -1,241 +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 it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport-testing-send.c
22 * @brief convenience transmission function for tests
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "transport-testing.h"
27
28/**
29 * Acceptable transmission delay.
30 */
31#define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply ( \
32 GNUNET_TIME_UNIT_SECONDS, 30)
33
34
35/**
36 * Return @a cx in @a cls.
37 */
38static void
39find_cr (void *cls,
40 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
41{
42 struct GNUNET_TRANSPORT_TESTING_ConnectRequest **cr = cls;
43
44 if (GNUNET_NO == cx->connected)
45 return;
46 *cr = cx;
47}
48
49
50/**
51 * Send a test message of type @a mtype and size @a msize from
52 * peer @a sender to peer @a receiver. The peers should be
53 * connected when this function is called.
54 *
55 * @param sender the sending peer
56 * @param receiver the receiving peer
57 * @param mtype message type to use
58 * @param msize size of the message, at least `sizeof (struct GNUNET_TRANSPORT_TESTING_TestMessage)`
59 * @param num unique message number
60 * @param cont continuation to call after transmission
61 * @param cont_cls closure for @a cont
62 * @return #GNUNET_OK if message was queued,
63 * #GNUNET_NO if peers are not connected
64 * #GNUNET_SYSERR if @a msize is illegal
65 */
66int
67GNUNET_TRANSPORT_TESTING_send (struct
68 GNUNET_TRANSPORT_TESTING_PeerContext *sender,
69 struct GNUNET_TRANSPORT_TESTING_PeerContext *
70 receiver,
71 uint16_t mtype,
72 uint16_t msize,
73 uint32_t num,
74 GNUNET_SCHEDULER_TaskCallback cont,
75 void *cont_cls)
76{
77 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cr;
78 struct GNUNET_MQ_Envelope *env;
79 struct GNUNET_TRANSPORT_TESTING_TestMessage *test;
80
81 if (msize < sizeof(struct GNUNET_TRANSPORT_TESTING_TestMessage))
82 {
83 GNUNET_break (0);
84 return GNUNET_SYSERR;
85 }
86 cr = NULL;
87 GNUNET_TRANSPORT_TESTING_find_connecting_context (sender,
88 receiver,
89 &find_cr,
90 &cr);
91 if (NULL == cr)
92 GNUNET_TRANSPORT_TESTING_find_connecting_context (receiver,
93 sender,
94 &find_cr,
95 &cr);
96 if (NULL == cr)
97 {
98 GNUNET_break (0);
99 return GNUNET_NO;
100 }
101 if (NULL == cr->mq)
102 {
103 GNUNET_break (0);
104 return GNUNET_NO;
105 }
106 {
107 char *receiver_s = GNUNET_strdup (GNUNET_i2s (&receiver->id));
108
109 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
110 "Sending message from peer %u (`%s') -> peer %u (`%s') !\n",
111 sender->no,
112 GNUNET_i2s (&sender->id),
113 receiver->no,
114 receiver_s);
115 GNUNET_free (receiver_s);
116 }
117 env = GNUNET_MQ_msg_extra (test,
118 msize - sizeof(*test),
119 mtype);
120 test->num = htonl (num);
121 memset (&test[1],
122 num,
123 msize - sizeof(*test));
124 GNUNET_MQ_notify_sent (env,
125 cont,
126 cont_cls);
127 GNUNET_MQ_send (cr->mq,
128 env);
129 return GNUNET_OK;
130}
131
132
133/**
134 * Task that sends a test message from the
135 * first peer to the second peer.
136 *
137 * @param ccc context which should contain at least two peers, the
138 * first two of which should be currently connected
139 * @param size desired message size
140 * @param cont continuation to call after transmission
141 * @param cont_cls closure for @a cont
142 */
143static void
144do_send (struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc,
145 uint16_t size,
146 GNUNET_SCHEDULER_TaskCallback cont,
147 void *cont_cls)
148{
149 int ret;
150
151 ccc->global_ret = GNUNET_SYSERR;
152 ret = GNUNET_TRANSPORT_TESTING_send (ccc->p[0],
153 ccc->p[1],
154 GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE,
155 size,
156 ccc->send_num_gen++,
157 cont,
158 cont_cls);
159 GNUNET_assert (GNUNET_SYSERR != ret);
160 if (GNUNET_NO == ret)
161 {
162 GNUNET_break (0);
163 ccc->global_ret = GNUNET_SYSERR;
164 GNUNET_SCHEDULER_shutdown ();
165 }
166}
167
168
169/**
170 * Task that sends a minimalistic test message from the
171 * first peer to the second peer.
172 *
173 * @param cls the `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext`
174 * which should contain at least two peers, the first two
175 * of which should be currently connected
176 */
177void
178GNUNET_TRANSPORT_TESTING_simple_send (void *cls)
179{
180 struct GNUNET_TRANSPORT_TESTING_SendClosure *sc = cls;
181 int done;
182 size_t msize;
183
184 if (0 < sc->num_messages)
185 {
186 sc->num_messages--;
187 done = (0 == sc->num_messages);
188 }
189 else
190 {
191 done = 0; /* infinite loop */
192 }
193 msize = sizeof(struct GNUNET_TRANSPORT_TESTING_TestMessage);
194 if (NULL != sc->get_size_cb)
195 msize = sc->get_size_cb (sc->num_messages);
196 /* if this was the last message, call the continuation,
197 otherwise call this function again */
198 do_send (sc->ccc,
199 msize,
200 done ? sc->cont : &GNUNET_TRANSPORT_TESTING_simple_send,
201 done ? sc->cont_cls : sc);
202}
203
204
205/**
206 * Task that sends a large test message from the
207 * first peer to the second peer.
208 *
209 * @param cls the `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext`
210 * which should contain at least two peers, the first two
211 * of which should be currently connected
212 */
213void
214GNUNET_TRANSPORT_TESTING_large_send (void *cls)
215{
216 struct GNUNET_TRANSPORT_TESTING_SendClosure *sc = cls;
217 int done;
218 size_t msize;
219
220 if (0 < sc->num_messages)
221 {
222 sc->num_messages--;
223 done = (0 == sc->num_messages);
224 }
225 else
226 {
227 done = 0; /* infinite loop */
228 }
229 msize = 2600;
230 if (NULL != sc->get_size_cb)
231 msize = sc->get_size_cb (sc->num_messages);
232 /* if this was the last message, call the continuation,
233 otherwise call this function again */
234 do_send (sc->ccc,
235 msize,
236 done ? sc->cont : &GNUNET_TRANSPORT_TESTING_large_send,
237 done ? sc->cont_cls : sc);
238}
239
240
241/* end of transport-testing-send.c */
diff --git a/src/transport/transport-testing.c b/src/transport/transport-testing.c
deleted file mode 100644
index baced62e3..000000000
--- a/src/transport/transport-testing.c
+++ /dev/null
@@ -1,932 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2006, 2009, 2015, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport-testing.c
22 * @brief testing lib for transport service
23 * @author Matthias Wachs
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "transport-testing.h"
28
29
30#define LOG(kind, ...) GNUNET_log_from (kind, "transport-testing", __VA_ARGS__)
31
32
33static struct GNUNET_TRANSPORT_TESTING_PeerContext *
34find_peer_context (struct GNUNET_TRANSPORT_TESTING_Handle *tth,
35 const struct GNUNET_PeerIdentity *peer)
36{
37 struct GNUNET_TRANSPORT_TESTING_PeerContext *t;
38
39 for (t = tth->p_head; NULL != t; t = t->next)
40 if (0 == memcmp (&t->id,
41 peer,
42 sizeof(struct GNUNET_PeerIdentity)))
43 return t;
44 return NULL;
45}
46
47
48/**
49 * Find any connecting context matching the given pair of peers.
50 *
51 * @param p1 first peer
52 * @param p2 second peer
53 * @param cb function to call
54 * @param cb_cls closure for @a cb
55 */
56void
57GNUNET_TRANSPORT_TESTING_find_connecting_context (struct
58 GNUNET_TRANSPORT_TESTING_PeerContext
59 *p1,
60 struct
61 GNUNET_TRANSPORT_TESTING_PeerContext
62 *p2,
63 GNUNET_TRANSPORT_TESTING_ConnectContextCallback
64 cb,
65 void *cb_cls)
66{
67 struct GNUNET_TRANSPORT_TESTING_Handle *tth = p1->tth;
68 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
69 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ccn;
70
71 for (cc = tth->cc_head; NULL != cc; cc = ccn)
72 {
73 ccn = cc->next;
74 if ((cc->p1 == p1) &&
75 (cc->p2 == p2))
76 cb (cb_cls,
77 cc);
78 }
79}
80
81
82static void
83set_p1c (void *cls,
84 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
85{
86 int *found = cls;
87
88 if (NULL != found)
89 *found = GNUNET_YES;
90 cx->p1_c = GNUNET_YES;
91}
92
93
94static void
95set_mq (void *cls,
96 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
97{
98 struct GNUNET_MQ_Handle *mq = cls;
99
100 cx->mq = mq;
101}
102
103
104static void
105set_p2c (void *cls,
106 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
107{
108 int *found = cls;
109
110 if (NULL != found)
111 *found = GNUNET_YES;
112 cx->p2_c = GNUNET_YES;
113}
114
115
116static void
117clear_p1c (void *cls,
118 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
119{
120 int *found = cls;
121
122 if (NULL != found)
123 *found = GNUNET_YES;
124 cx->p1_c = GNUNET_NO;
125}
126
127
128static void
129clear_p2c (void *cls,
130 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
131{
132 int *found = cls;
133
134 if (NULL != found)
135 *found = GNUNET_YES;
136 cx->p2_c = GNUNET_NO;
137}
138
139
140static void *
141notify_connect (void *cls,
142 const struct GNUNET_PeerIdentity *peer,
143 struct GNUNET_MQ_Handle *mq)
144{
145 struct GNUNET_TRANSPORT_TESTING_PeerContext *p = cls;
146 struct GNUNET_TRANSPORT_TESTING_Handle *tth = p->tth;
147 char *p2_s;
148 struct GNUNET_TRANSPORT_TESTING_PeerContext *p2;
149 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
150 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ccn;
151 int found;
152 void *ret;
153
154 p2 = find_peer_context (p->tth,
155 peer);
156 if (NULL != p->nc)
157 ret = p->nc (p->cb_cls,
158 peer,
159 mq);
160 else
161 ret = NULL;
162
163 if (NULL != p2)
164 GNUNET_asprintf (&p2_s,
165 "%u (`%s')",
166 p2->no,
167 GNUNET_i2s (&p2->id));
168 else
169 GNUNET_asprintf (&p2_s,
170 "`%s'",
171 GNUNET_i2s (peer));
172 LOG (GNUNET_ERROR_TYPE_DEBUG,
173 "Peers %s connected to peer %u (`%s')\n",
174 p2_s,
175 p->no,
176 GNUNET_i2s (&p->id));
177 GNUNET_free (p2_s);
178 /* update flags in connecting contexts */
179 found = GNUNET_NO;
180 GNUNET_TRANSPORT_TESTING_find_connecting_context (p,
181 p2,
182 &set_p1c,
183 &found);
184 if (GNUNET_NO == found)
185 {
186 cc = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_ConnectRequest);
187 cc->p1 = p;
188 cc->p2 = p2;
189 cc->p1_c = GNUNET_YES;
190 GNUNET_CONTAINER_DLL_insert (tth->cc_head,
191 tth->cc_tail,
192 cc);
193 }
194 found = GNUNET_NO;
195 GNUNET_TRANSPORT_TESTING_find_connecting_context (p2,
196 p,
197 &set_p2c,
198 &found);
199 if (GNUNET_NO == found)
200 {
201 cc = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_ConnectRequest);
202 cc->p1 = p2;
203 cc->p2 = p;
204 cc->p1_c = GNUNET_YES;
205 GNUNET_CONTAINER_DLL_insert (tth->cc_head,
206 tth->cc_tail,
207 cc);
208 }
209 GNUNET_TRANSPORT_TESTING_find_connecting_context (p,
210 p2,
211 &set_mq,
212 mq);
213 /* update set connected flag for all requests */
214 for (cc = tth->cc_head; NULL != cc; cc = cc->next)
215 {
216 if (GNUNET_YES == cc->connected)
217 continue;
218 if ((GNUNET_YES == cc->p1_c) &&
219 (GNUNET_YES == cc->p2_c))
220 {
221 cc->connected = GNUNET_YES;
222 /* stop trying to connect */
223 if (NULL != cc->tct)
224 {
225 GNUNET_SCHEDULER_cancel (cc->tct);
226 cc->tct = NULL;
227 }
228 if (NULL != cc->oh)
229 {
230 GNUNET_TRANSPORT_offer_hello_cancel (cc->oh);
231 cc->oh = NULL;
232 }
233 if (NULL != cc->ats_sh)
234 {
235 GNUNET_ATS_connectivity_suggest_cancel (cc->ats_sh);
236 cc->ats_sh = NULL;
237 }
238 }
239 }
240 /* then notify application */
241 for (cc = tth->cc_head; NULL != cc; cc = ccn)
242 {
243 ccn = cc->next;
244 if ((GNUNET_YES == cc->connected) &&
245 (NULL != cc->cb))
246 {
247 cc->cb (cc->cb_cls);
248 cc->cb = NULL; /* only notify once! */
249 }
250 }
251 return ret;
252}
253
254
255/**
256 * Offer the current HELLO of P2 to P1.
257 *
258 * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectRequest`
259 */
260static void
261offer_hello (void *cls);
262
263
264static void
265notify_disconnect (void *cls,
266 const struct GNUNET_PeerIdentity *peer,
267 void *handler_cls)
268{
269 struct GNUNET_TRANSPORT_TESTING_PeerContext *p = cls;
270 struct GNUNET_TRANSPORT_TESTING_Handle *tth = p->tth;
271 char *p2_s;
272 /* Find PeerContext */
273 int no = 0;
274 struct GNUNET_TRANSPORT_TESTING_PeerContext *p2 = NULL;
275 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
276
277 p2 = find_peer_context (p->tth,
278 peer);
279 no = p->no;
280 if (NULL != p2)
281 GNUNET_asprintf (&p2_s,
282 "%u (`%s')",
283 p2->no,
284 GNUNET_i2s (&p2->id));
285 else
286 GNUNET_asprintf (&p2_s,
287 "`%s'",
288 GNUNET_i2s (peer));
289 LOG (GNUNET_ERROR_TYPE_DEBUG,
290 "Peers %s disconnected from peer %u (`%s')\n",
291 p2_s,
292 no,
293 GNUNET_i2s (&p->id));
294 GNUNET_free (p2_s);
295 /* notify about disconnect */
296 if (NULL != p->nd)
297 p->nd (p->cb_cls,
298 peer,
299 handler_cls);
300 if (NULL == p2)
301 return;
302 /* clear MQ, it is now invalid */
303 GNUNET_TRANSPORT_TESTING_find_connecting_context (p,
304 p2,
305 &set_mq,
306 NULL);
307 /* update set connected flags for all requests */
308 GNUNET_TRANSPORT_TESTING_find_connecting_context (p,
309 p2,
310 &clear_p1c,
311 NULL);
312 GNUNET_TRANSPORT_TESTING_find_connecting_context (p2,
313 p,
314 &clear_p2c,
315 NULL);
316 /* resume connectivity requests as necessary */
317 for (cc = tth->cc_head; NULL != cc; cc = cc->next)
318 {
319 if (GNUNET_NO == cc->connected)
320 continue;
321 if ((GNUNET_YES != cc->p1_c) ||
322 (GNUNET_YES != cc->p2_c))
323 {
324 cc->connected = GNUNET_NO;
325 /* start trying to connect */
326 if ((NULL == cc->tct) &&
327 (NULL == cc->oh))
328 cc->tct = GNUNET_SCHEDULER_add_now (&offer_hello,
329 cc);
330 if (NULL == cc->ats_sh)
331 cc->ats_sh = GNUNET_ATS_connectivity_suggest (cc->p1->ats,
332 &p2->id,
333 1);
334 }
335 }
336}
337
338
339static void
340get_hello (void *cb_cls,
341 const struct GNUNET_MessageHeader *message)
342{
343 struct GNUNET_TRANSPORT_TESTING_PeerContext *p = cb_cls;
344 struct GNUNET_PeerIdentity hello_id;
345
346 GNUNET_assert (GNUNET_OK ==
347 GNUNET_HELLO_get_id ((const struct
348 GNUNET_HELLO_Message *) message,
349 &hello_id));
350 GNUNET_assert (0 == memcmp (&hello_id,
351 &p->id,
352 sizeof(hello_id)));
353 GNUNET_free (p->hello);
354 p->hello = (struct GNUNET_HELLO_Message *) GNUNET_copy_message (message);
355
356 if (NULL != p->start_cb)
357 {
358 LOG (GNUNET_ERROR_TYPE_DEBUG,
359 "Peer %u (`%s') successfully started\n",
360 p->no,
361 GNUNET_i2s (&p->id));
362 p->start_cb (p->start_cb_cls);
363 p->start_cb = NULL;
364 }
365}
366
367
368/**
369 * Start a peer with the given configuration
370 * @param tth the testing handle
371 * @param cfgname configuration file
372 * @param peer_id a unique number to identify the peer
373 * @param handlers functions for receiving messages
374 * @param nc connect callback
375 * @param nd disconnect callback
376 * @param cb_cls closure for callback
377 * @param start_cb start callback
378 * @param start_cb_cls closure for callback
379 * @return the peer context
380 */
381struct GNUNET_TRANSPORT_TESTING_PeerContext *
382GNUNET_TRANSPORT_TESTING_start_peer (struct
383 GNUNET_TRANSPORT_TESTING_Handle *tth,
384 const char *cfgname,
385 int peer_id,
386 const struct
387 GNUNET_MQ_MessageHandler *handlers,
388 GNUNET_TRANSPORT_NotifyConnect nc,
389 GNUNET_TRANSPORT_NotifyDisconnect nd,
390 void *cb_cls,
391 GNUNET_SCHEDULER_TaskCallback start_cb,
392 void *start_cb_cls)
393{
394 char *emsg = NULL;
395 struct GNUNET_TRANSPORT_TESTING_PeerContext *p;
396 struct GNUNET_PeerIdentity dummy;
397 unsigned int i;
398
399 if (GNUNET_NO == GNUNET_DISK_file_test (cfgname))
400 {
401 LOG (GNUNET_ERROR_TYPE_ERROR,
402 "File not found: `%s'\n",
403 cfgname);
404 return NULL;
405 }
406
407 p = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_PeerContext);
408 p->tth = tth;
409 p->nc = nc;
410 p->nd = nd;
411 if (NULL != handlers)
412 {
413 for (i = 0; NULL != handlers[i].cb; i++)
414 ;
415 p->handlers = GNUNET_new_array (i + 1,
416 struct GNUNET_MQ_MessageHandler);
417 GNUNET_memcpy (p->handlers,
418 handlers,
419 i * sizeof(struct GNUNET_MQ_MessageHandler));
420 }
421 if (NULL != cb_cls)
422 p->cb_cls = cb_cls;
423 else
424 p->cb_cls = p;
425 p->start_cb = start_cb;
426 if (NULL != start_cb_cls)
427 p->start_cb_cls = start_cb_cls;
428 else
429 p->start_cb_cls = p;
430 GNUNET_CONTAINER_DLL_insert (tth->p_head,
431 tth->p_tail,
432 p);
433
434 /* Create configuration and call testing lib to modify it */
435 p->cfg = GNUNET_CONFIGURATION_create ();
436 GNUNET_assert (GNUNET_OK ==
437 GNUNET_CONFIGURATION_load (p->cfg, cfgname));
438 if (GNUNET_SYSERR ==
439 GNUNET_TESTING_configuration_create (tth->tl_system,
440 p->cfg))
441 {
442 LOG (GNUNET_ERROR_TYPE_ERROR,
443 "Testing library failed to create unique configuration based on `%s'\n",
444 cfgname);
445 GNUNET_CONFIGURATION_destroy (p->cfg);
446 GNUNET_free (p);
447 return NULL;
448 }
449
450 p->no = peer_id;
451 /* Configure peer with configuration */
452 p->peer = GNUNET_TESTING_peer_configure (tth->tl_system,
453 p->cfg,
454 p->no,
455 NULL,
456 &emsg);
457 if (NULL == p->peer)
458 {
459 LOG (GNUNET_ERROR_TYPE_ERROR,
460 "Testing library failed to create unique configuration based on `%s': `%s'\n",
461 cfgname,
462 emsg);
463 GNUNET_TRANSPORT_TESTING_stop_peer (p);
464 GNUNET_free (emsg);
465 return NULL;
466 }
467
468 if (GNUNET_OK != GNUNET_TESTING_peer_start (p->peer))
469 {
470 LOG (GNUNET_ERROR_TYPE_ERROR,
471 "Testing library failed to create unique configuration based on `%s'\n",
472 cfgname);
473 GNUNET_TRANSPORT_TESTING_stop_peer (p);
474 return NULL;
475 }
476
477 memset (&dummy,
478 '\0',
479 sizeof(dummy));
480 GNUNET_TESTING_peer_get_identity (p->peer,
481 &p->id);
482 if (0 == memcmp (&dummy,
483 &p->id,
484 sizeof(struct GNUNET_PeerIdentity)))
485 {
486 LOG (GNUNET_ERROR_TYPE_ERROR,
487 "Testing library failed to obtain peer identity for peer %u\n",
488 p->no);
489 GNUNET_TRANSPORT_TESTING_stop_peer (p);
490 return NULL;
491 }
492 LOG (GNUNET_ERROR_TYPE_DEBUG,
493 "Peer %u configured with identity `%s'\n",
494 p->no,
495 GNUNET_i2s_full (&p->id));
496 p->tmh = GNUNET_TRANSPORT_manipulation_connect (p->cfg);
497 p->th = GNUNET_TRANSPORT_core_connect (p->cfg,
498 NULL,
499 handlers,
500 p,
501 &notify_connect,
502 &notify_disconnect,
503 NULL);
504 if ((NULL == p->th) ||
505 (NULL == p->tmh))
506 {
507 LOG (GNUNET_ERROR_TYPE_ERROR,
508 "Failed to connect to transport service for peer `%s': `%s'\n",
509 cfgname,
510 emsg);
511 GNUNET_TRANSPORT_TESTING_stop_peer (p);
512 GNUNET_free (emsg);
513 return NULL;
514 }
515 p->ats = GNUNET_ATS_connectivity_init (p->cfg);
516 if (NULL == p->ats)
517 {
518 LOG (GNUNET_ERROR_TYPE_ERROR,
519 "Failed to connect to ATS service for peer `%s': `%s'\n",
520 cfgname,
521 emsg);
522 GNUNET_TRANSPORT_TESTING_stop_peer (p);
523 GNUNET_free (emsg);
524 return NULL;
525 }
526 p->ghh = GNUNET_TRANSPORT_hello_get (p->cfg,
527 GNUNET_TRANSPORT_AC_ANY,
528 &get_hello,
529 p);
530 GNUNET_assert (NULL != p->ghh);
531 return p;
532}
533
534
535/**
536 * Stops and restarts the given peer, sleeping (!) for 5s in between.
537 *
538 * @param p the peer
539 * @param restart_cb callback to call when restarted
540 * @param restart_cb_cls callback closure
541 * @return #GNUNET_OK in success otherwise #GNUNET_SYSERR
542 */
543int
544GNUNET_TRANSPORT_TESTING_restart_peer (struct
545 GNUNET_TRANSPORT_TESTING_PeerContext *p,
546 GNUNET_SCHEDULER_TaskCallback restart_cb,
547 void *restart_cb_cls)
548{
549 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
550 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ccn;
551
552 /* shutdown */
553 LOG (GNUNET_ERROR_TYPE_DEBUG,
554 "Stopping peer %u (`%s')\n",
555 p->no,
556 GNUNET_i2s (&p->id));
557 if (NULL != p->ghh)
558 {
559 GNUNET_TRANSPORT_hello_get_cancel (p->ghh);
560 p->ghh = NULL;
561 }
562 if (NULL != p->th)
563 {
564 GNUNET_TRANSPORT_core_disconnect (p->th);
565 p->th = NULL;
566 }
567 if (NULL != p->tmh)
568 {
569 GNUNET_TRANSPORT_manipulation_disconnect (p->tmh);
570 p->tmh = NULL;
571 }
572 for (cc = p->tth->cc_head; NULL != cc; cc = ccn)
573 {
574 ccn = cc->next;
575 if ((cc->p1 == p) ||
576 (cc->p2 == p))
577 GNUNET_TRANSPORT_TESTING_connect_peers_cancel (cc);
578 }
579 if (NULL != p->ats)
580 {
581 GNUNET_ATS_connectivity_done (p->ats);
582 p->ats = NULL;
583 }
584 if (GNUNET_SYSERR ==
585 GNUNET_TESTING_peer_stop (p->peer))
586 {
587 LOG (GNUNET_ERROR_TYPE_ERROR,
588 "Failed to stop peer %u (`%s')\n",
589 p->no,
590 GNUNET_i2s (&p->id));
591 return GNUNET_SYSERR;
592 }
593
594 sleep (5); // YUCK!
595
596 LOG (GNUNET_ERROR_TYPE_DEBUG,
597 "Restarting peer %u (`%s')\n",
598 p->no,
599 GNUNET_i2s (&p->id));
600 /* restart */
601 if (GNUNET_SYSERR == GNUNET_TESTING_peer_start (p->peer))
602 {
603 LOG (GNUNET_ERROR_TYPE_ERROR,
604 "Failed to restart peer %u (`%s')\n",
605 p->no,
606 GNUNET_i2s (&p->id));
607 return GNUNET_SYSERR;
608 }
609
610 GNUNET_assert (NULL == p->start_cb);
611 p->start_cb = restart_cb;
612 p->start_cb_cls = restart_cb_cls;
613
614 p->th = GNUNET_TRANSPORT_core_connect (p->cfg,
615 NULL,
616 p->handlers,
617 p,
618 &notify_connect,
619 &notify_disconnect,
620 NULL);
621 GNUNET_assert (NULL != p->th);
622 p->ats = GNUNET_ATS_connectivity_init (p->cfg);
623 p->ghh = GNUNET_TRANSPORT_hello_get (p->cfg,
624 GNUNET_TRANSPORT_AC_ANY,
625 &get_hello,
626 p);
627 GNUNET_assert (NULL != p->ghh);
628 return GNUNET_OK;
629}
630
631
632/**
633 * Shutdown the given peer
634 *
635 * @param p the peer
636 */
637void
638GNUNET_TRANSPORT_TESTING_stop_peer (struct
639 GNUNET_TRANSPORT_TESTING_PeerContext *p)
640{
641 struct GNUNET_TRANSPORT_TESTING_Handle *tth = p->tth;
642 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
643 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ccn;
644
645 for (cc = tth->cc_head; NULL != cc; cc = ccn)
646 {
647 ccn = cc->next;
648 if ((cc->p1 == p) ||
649 (cc->p2 == p))
650 GNUNET_TRANSPORT_TESTING_connect_peers_cancel (cc);
651 }
652 if (NULL != p->ghh)
653 {
654 GNUNET_TRANSPORT_hello_get_cancel (p->ghh);
655 p->ghh = NULL;
656 }
657 if (NULL != p->tmh)
658 {
659 GNUNET_TRANSPORT_manipulation_disconnect (p->tmh);
660 p->tmh = NULL;
661 }
662 if (NULL != p->th)
663 {
664 GNUNET_TRANSPORT_core_disconnect (p->th);
665 p->th = NULL;
666 }
667 if (NULL != p->peer)
668 {
669 if (GNUNET_OK !=
670 GNUNET_TESTING_peer_stop (p->peer))
671 {
672 LOG (GNUNET_ERROR_TYPE_DEBUG,
673 "Testing lib failed to stop peer %u (`%s')\n",
674 p->no,
675 GNUNET_i2s (&p->id));
676 }
677 GNUNET_TESTING_peer_destroy (p->peer);
678 p->peer = NULL;
679 }
680 if (NULL != p->ats)
681 {
682 GNUNET_ATS_connectivity_done (p->ats);
683 p->ats = NULL;
684 }
685 if (NULL != p->hello)
686 {
687 GNUNET_free (p->hello);
688 p->hello = NULL;
689 }
690 if (NULL != p->cfg)
691 {
692 GNUNET_CONFIGURATION_destroy (p->cfg);
693 p->cfg = NULL;
694 }
695 if (NULL != p->handlers)
696 {
697 GNUNET_free (p->handlers);
698 p->handlers = NULL;
699 }
700 GNUNET_CONTAINER_DLL_remove (tth->p_head,
701 tth->p_tail,
702 p);
703 LOG (GNUNET_ERROR_TYPE_DEBUG,
704 "Peer %u (`%s') stopped\n",
705 p->no,
706 GNUNET_i2s (&p->id));
707 GNUNET_free (p);
708}
709
710
711/**
712 * Function called after the HELLO was passed to the
713 * transport service.
714 */
715static void
716hello_offered (void *cls)
717{
718 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc = cls;
719
720 cc->oh = NULL;
721 cc->tct = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
722 &offer_hello,
723 cc);
724}
725
726
727/**
728 * Offer the current HELLO of P2 to P1.
729 *
730 * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectRequest`
731 */
732static void
733offer_hello (void *cls)
734{
735 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc = cls;
736 struct GNUNET_TRANSPORT_TESTING_PeerContext *p1 = cc->p1;
737 struct GNUNET_TRANSPORT_TESTING_PeerContext *p2 = cc->p2;
738
739 cc->tct = NULL;
740 {
741 char *p2_s = GNUNET_strdup (GNUNET_i2s (&p2->id));
742
743 LOG (GNUNET_ERROR_TYPE_DEBUG,
744 "Asking peer %u (`%s') to connect peer %u (`%s'), providing HELLO with %u bytes\n",
745 p1->no,
746 GNUNET_i2s (&p1->id),
747 p2->no,
748 p2_s,
749 GNUNET_HELLO_size (cc->p2->hello));
750 GNUNET_free (p2_s);
751 }
752
753 if (NULL != cc->oh)
754 GNUNET_TRANSPORT_offer_hello_cancel (cc->oh);
755 cc->oh =
756 GNUNET_TRANSPORT_offer_hello (cc->p1->cfg,
757 (const struct
758 GNUNET_MessageHeader *) cc->p2->hello,
759 &hello_offered,
760 cc);
761}
762
763
764/**
765 * Initiate a connection from p1 to p2 by offering p1 p2's HELLO message
766 *
767 * Remarks: start_peer's notify_connect callback can be called before.
768 *
769 * @param tth transport testing handle
770 * @param p1 peer 1
771 * @param p2 peer 2
772 * @param cb the callback to call when both peers notified that they are connected
773 * @param cls callback cls
774 * @return a connect request handle
775 */
776struct GNUNET_TRANSPORT_TESTING_ConnectRequest *
777GNUNET_TRANSPORT_TESTING_connect_peers (struct
778 GNUNET_TRANSPORT_TESTING_PeerContext *p1,
779 struct
780 GNUNET_TRANSPORT_TESTING_PeerContext *p2,
781 GNUNET_SCHEDULER_TaskCallback cb,
782 void *cls)
783{
784 struct GNUNET_TRANSPORT_TESTING_Handle *tth = p1->tth;
785 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
786 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ccn;
787
788 ccn = NULL;
789 for (cc = tth->cc_head; NULL != cc; cc = cc->next)
790 {
791 if ((cc->p1 == p1) &&
792 (cc->p2 == p2))
793 {
794 ccn = cc;
795 break;
796 }
797 }
798
799 cc = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_ConnectRequest);
800 cc->p1 = p1;
801 cc->p2 = p2;
802 cc->cb = cb;
803 if (NULL != cls)
804 cc->cb_cls = cls;
805 else
806 cc->cb_cls = cc;
807 if (NULL != ccn)
808 {
809 cc->p1_c = ccn->p1_c;
810 cc->p2_c = ccn->p2_c;
811 cc->connected = ccn->connected;
812 }
813 GNUNET_CONTAINER_DLL_insert (tth->cc_head,
814 tth->cc_tail,
815 cc);
816 cc->tct = GNUNET_SCHEDULER_add_now (&offer_hello,
817 cc);
818 cc->ats_sh = GNUNET_ATS_connectivity_suggest (cc->p1->ats,
819 &p2->id,
820 1);
821 LOG (GNUNET_ERROR_TYPE_DEBUG,
822 "New connect request %p\n",
823 cc);
824 return cc;
825}
826
827
828/**
829 * Cancel the request to connect two peers
830 * Tou MUST cancel the request if you stop the peers before the peers connected successfully
831 *
832 * @param tth transport testing handle
833 * @param cc a connect request handle
834 */
835void
836GNUNET_TRANSPORT_TESTING_connect_peers_cancel (struct
837 GNUNET_TRANSPORT_TESTING_ConnectRequest
838 *cc)
839{
840 struct GNUNET_TRANSPORT_TESTING_Handle *tth = cc->p1->tth;
841
842 LOG (GNUNET_ERROR_TYPE_DEBUG,
843 "Canceling connect request!\n");
844 if (NULL != cc->tct)
845 {
846 GNUNET_SCHEDULER_cancel (cc->tct);
847 cc->tct = NULL;
848 }
849 if (NULL != cc->oh)
850 {
851 GNUNET_TRANSPORT_offer_hello_cancel (cc->oh);
852 cc->oh = NULL;
853 }
854 if (NULL != cc->ats_sh)
855 {
856 GNUNET_ATS_connectivity_suggest_cancel (cc->ats_sh);
857 cc->ats_sh = NULL;
858 }
859 GNUNET_CONTAINER_DLL_remove (tth->cc_head,
860 tth->cc_tail,
861 cc);
862 GNUNET_free (cc);
863}
864
865
866/**
867 * Clean up the transport testing
868 *
869 * @param tth transport testing handle
870 */
871void
872GNUNET_TRANSPORT_TESTING_done (struct GNUNET_TRANSPORT_TESTING_Handle *tth)
873{
874 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
875 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ct;
876 struct GNUNET_TRANSPORT_TESTING_PeerContext *p;
877 struct GNUNET_TRANSPORT_TESTING_PeerContext *t;
878
879 if (NULL == tth)
880 return;
881 cc = tth->cc_head;
882 while (NULL != cc)
883 {
884 ct = cc->next;
885 LOG (GNUNET_ERROR_TYPE_ERROR,
886 "Developer forgot to cancel connect request!\n");
887 GNUNET_TRANSPORT_TESTING_connect_peers_cancel (cc);
888 cc = ct;
889 }
890 p = tth->p_head;
891 while (NULL != p)
892 {
893 t = p->next;
894 LOG (GNUNET_ERROR_TYPE_ERROR,
895 "Developer forgot to stop peer!\n");
896 GNUNET_TRANSPORT_TESTING_stop_peer (p);
897 p = t;
898 }
899 GNUNET_TESTING_system_destroy (tth->tl_system,
900 GNUNET_YES);
901
902 GNUNET_free (tth);
903}
904
905
906/**
907 * Initialize the transport testing
908 *
909 * @return transport testing handle
910 */
911struct GNUNET_TRANSPORT_TESTING_Handle *
912GNUNET_TRANSPORT_TESTING_init ()
913{
914 struct GNUNET_TRANSPORT_TESTING_Handle *tth;
915
916 tth = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_Handle);
917 tth->tl_system = GNUNET_TESTING_system_create ("transport-testing",
918 NULL,
919 NULL,
920 NULL);
921 if (NULL == tth->tl_system)
922 {
923 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
924 "Failed to initialize testing library!\n");
925 GNUNET_free (tth);
926 return NULL;
927 }
928 return tth;
929}
930
931
932/* end of transport-testing.c */
diff --git a/src/transport/transport-testing.h b/src/transport/transport-testing.h
deleted file mode 100644
index c548e59c1..000000000
--- a/src/transport/transport-testing.h
+++ /dev/null
@@ -1,914 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2006, 2009, 2015, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport-testing.h
23 * @brief testing lib for transport service
24 * @author Matthias Wachs
25 * @author Christian Grothoff
26 */
27#ifndef TRANSPORT_TESTING_H
28#define TRANSPORT_TESTING_H
29#include "platform.h"
30#include "gnunet_util_lib.h"
31#include "gnunet_hello_lib.h"
32#include "gnunet_transport_service.h"
33#include "gnunet_transport_hello_service.h"
34#include "gnunet_transport_manipulation_service.h"
35#include "gnunet_testing_lib.h"
36
37
38/* ************* Basic functions for starting/stopping/connecting *********** */
39
40/**
41 * Context for a single peer
42 */
43struct GNUNET_TRANSPORT_TESTING_PeerContext;
44
45/**
46 * Definition for a transport testing handle
47 */
48struct GNUNET_TRANSPORT_TESTING_Handle;
49
50
51/**
52 * Context for a single peer
53 */
54struct GNUNET_TRANSPORT_TESTING_PeerContext
55{
56 /**
57 * Next element in the DLL
58 */
59 struct GNUNET_TRANSPORT_TESTING_PeerContext *next;
60
61 /**
62 * Previous element in the DLL
63 */
64 struct GNUNET_TRANSPORT_TESTING_PeerContext *prev;
65
66 /**
67 * Transport testing handle this peer belongs to
68 */
69 struct GNUNET_TRANSPORT_TESTING_Handle *tth;
70
71 /**
72 * Peer's configuration
73 */
74 struct GNUNET_CONFIGURATION_Handle *cfg;
75
76 /**
77 * Peer's transport service handle
78 */
79 struct GNUNET_TRANSPORT_CoreHandle *th;
80
81 /**
82 * Peer's transport service manipulation handle
83 */
84 struct GNUNET_TRANSPORT_ManipulationHandle *tmh;
85
86 /**
87 * Peer's ATS handle.
88 */
89 struct GNUNET_ATS_ConnectivityHandle *ats;
90
91 /**
92 * Peer's transport get hello handle to retrieve peer's HELLO message
93 */
94 struct GNUNET_TRANSPORT_HelloGetHandle *ghh;
95
96 /**
97 * Peer's testing handle
98 */
99 struct GNUNET_TESTING_Peer *peer;
100
101 /**
102 * Peer identity
103 */
104 struct GNUNET_PeerIdentity id;
105
106 /**
107 * Handle for the peer's ARM process
108 */
109 struct GNUNET_OS_Process *arm_proc;
110
111 /**
112 * Receive callback
113 */
114 struct GNUNET_MQ_MessageHandler *handlers;
115
116 /**
117 * Notify connect callback
118 */
119 GNUNET_TRANSPORT_NotifyConnect nc;
120
121 /**
122 * Notify disconnect callback
123 */
124 GNUNET_TRANSPORT_NotifyDisconnect nd;
125
126 /**
127 * Startup completed callback
128 */
129 GNUNET_SCHEDULER_TaskCallback start_cb;
130
131 /**
132 * Peers HELLO Message
133 */
134 struct GNUNET_HELLO_Message *hello;
135
136 /**
137 * Closure for the @a nc and @a nd callbacks
138 */
139 void *cb_cls;
140
141 /**
142 * Closure for @e start_cb.
143 */
144 void *start_cb_cls;
145
146 /**
147 * An unique number to identify the peer
148 */
149 unsigned int no;
150};
151
152
153/**
154 * Handle for a request to connect two peers.
155 */
156struct GNUNET_TRANSPORT_TESTING_ConnectRequest
157{
158 /**
159 * Kept in a DLL.
160 */
161 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *next;
162
163 /**
164 * Kept in a DLL.
165 */
166 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *prev;
167
168 /**
169 * Peer we want to connect.
170 */
171 struct GNUNET_TRANSPORT_TESTING_PeerContext *p1;
172
173 /**
174 * Peer we want to connect.
175 */
176 struct GNUNET_TRANSPORT_TESTING_PeerContext *p2;
177
178 /**
179 * Task by which we accomplish the connection.
180 */
181 struct GNUNET_SCHEDULER_Task *tct;
182
183 /**
184 * Handle by which we ask ATS to facilitate the connection.
185 */
186 struct GNUNET_ATS_ConnectivitySuggestHandle *ats_sh;
187
188 /**
189 * Handle by which we inform the peer about the HELLO of
190 * the other peer.
191 */
192 struct GNUNET_TRANSPORT_OfferHelloHandle *oh;
193
194 /**
195 * Function to call upon completion.
196 */
197 GNUNET_SCHEDULER_TaskCallback cb;
198
199 /**
200 * Closure for @e cb.
201 */
202 void *cb_cls;
203
204 /**
205 * Message queue for sending from @a p1 to @a p2.
206 */
207 struct GNUNET_MQ_Handle *mq;
208
209 /**
210 * Set if peer1 says the connection is up to peer2.
211 */
212 int p1_c;
213
214 /**
215 * Set if peer2 says the connection is up to peer1.
216 */
217 int p2_c;
218
219 /**
220 * #GNUNET_YES if both @e p1_c and @e p2_c are #GNUNET_YES.
221 */
222 int connected;
223};
224
225
226/**
227 * Handle for a test run.
228 */
229struct GNUNET_TRANSPORT_TESTING_Handle
230{
231 /**
232 * Testing library system handle
233 */
234 struct GNUNET_TESTING_System *tl_system;
235
236 /**
237 * head DLL of connect contexts
238 */
239 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc_head;
240
241 /**
242 * head DLL of connect contexts
243 */
244 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc_tail;
245
246 /**
247 * head DLL of peers
248 */
249 struct GNUNET_TRANSPORT_TESTING_PeerContext *p_head;
250
251 /**
252 * tail DLL of peers
253 */
254 struct GNUNET_TRANSPORT_TESTING_PeerContext *p_tail;
255};
256
257
258/**
259 * Initialize the transport testing
260 *
261 * @return transport testing handle
262 */
263struct GNUNET_TRANSPORT_TESTING_Handle *
264GNUNET_TRANSPORT_TESTING_init (void);
265
266
267/**
268 * Clean up the transport testing
269 *
270 * @param tth transport testing handle
271 */
272void
273GNUNET_TRANSPORT_TESTING_done (struct GNUNET_TRANSPORT_TESTING_Handle *tth);
274
275
276/**
277 * Start a peer with the given configuration
278 *
279 * @param tth the testing handle
280 * @param cfgname configuration file
281 * @param peer_id the peer_id
282 * @param handlers functions for receiving messages
283 * @param nc connect callback
284 * @param nd disconnect callback
285 * @param cb_cls closure for @a nc and @a nd callback
286 * @param start_cb start callback
287 * @param start_cb_cls closure for @a start_cb
288 * @return the peer context
289 */
290struct GNUNET_TRANSPORT_TESTING_PeerContext *
291GNUNET_TRANSPORT_TESTING_start_peer (
292 struct GNUNET_TRANSPORT_TESTING_Handle *tth,
293 const char *cfgname,
294 int peer_id,
295 const struct GNUNET_MQ_MessageHandler *handlers,
296 GNUNET_TRANSPORT_NotifyConnect nc,
297 GNUNET_TRANSPORT_NotifyDisconnect nd,
298 void *cb_cls,
299 GNUNET_SCHEDULER_TaskCallback start_cb,
300 void *start_cb_cls);
301
302
303/**
304 * Shutdown the given peer
305 *
306 * @param p the peer
307 */
308void
309GNUNET_TRANSPORT_TESTING_stop_peer (
310 struct GNUNET_TRANSPORT_TESTING_PeerContext *pc);
311
312
313/**
314 * Stops and restarts the given peer, sleeping (!) for 5s in between.
315 *
316 * @param p the peer
317 * @param restart_cb restart callback
318 * @param restart_cb_cls callback closure
319 * @return #GNUNET_OK in success otherwise #GNUNET_SYSERR
320 */
321int
322GNUNET_TRANSPORT_TESTING_restart_peer (
323 struct GNUNET_TRANSPORT_TESTING_PeerContext *p,
324 GNUNET_SCHEDULER_TaskCallback restart_cb,
325 void *restart_cb_cls);
326
327
328/**
329 * Connect the given peers and call the callback when both peers
330 * report the inbound connection. Remarks: start_peer's notify_connect
331 * callback can be called before.
332 *
333 * @param p1 peer 1
334 * @param p2 peer 2
335 * @param cb the callback to call when both peers notified that they are
336 * connected
337 * @param cls callback cls
338 * @return a connect request handle
339 */
340struct GNUNET_TRANSPORT_TESTING_ConnectRequest *
341GNUNET_TRANSPORT_TESTING_connect_peers (
342 struct GNUNET_TRANSPORT_TESTING_PeerContext *p1,
343 struct GNUNET_TRANSPORT_TESTING_PeerContext *p2,
344 GNUNET_SCHEDULER_TaskCallback cb,
345 void *cls);
346
347
348/**
349 * Cancel the request to connect two peers. You MUST cancel the
350 * request if you stop the peers before the peers connected
351 * successfully.
352 *
353 * @param cc a connect request handle
354 */
355void
356GNUNET_TRANSPORT_TESTING_connect_peers_cancel (
357 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc);
358
359
360/**
361 * Function called on matching connect requests.
362 *
363 * @param cls closure
364 * @param cc request matching the query
365 */
366typedef void (*GNUNET_TRANSPORT_TESTING_ConnectContextCallback) (
367 void *cls,
368 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc);
369
370
371/**
372 * Find any connecting context matching the given pair of peers.
373 *
374 * @param p1 first peer
375 * @param p2 second peer
376 * @param cb function to call
377 * @param cb_cls closure for @a cb
378 */
379void
380GNUNET_TRANSPORT_TESTING_find_connecting_context (
381 struct GNUNET_TRANSPORT_TESTING_PeerContext *p1,
382 struct GNUNET_TRANSPORT_TESTING_PeerContext *p2,
383 GNUNET_TRANSPORT_TESTING_ConnectContextCallback cb,
384 void *cb_cls);
385
386
387/* ********************** high-level process functions *************** */
388
389
390/**
391 * Function called once the peers have been launched and
392 * connected by #GNUNET_TRANSPORT_TESTING_connect_check().
393 *
394 * @param cls closure
395 * @param num_peers size of the @a p array
396 * @param p the peers that were launched
397 */
398typedef void (*GNUNET_TRANSPORT_TESTING_ConnectContinuation) (
399 void *cls,
400 unsigned int num_peers,
401 struct GNUNET_TRANSPORT_TESTING_PeerContext *p[]);
402
403
404/**
405 * Internal data structure.
406 */
407struct GNUNET_TRANSPORT_TESTING_ConnectRequestList;
408
409/**
410 * Internal data structure.
411 */
412struct GNUNET_TRANSPORT_TESTING_InternalPeerContext;
413
414
415GNUNET_NETWORK_STRUCT_BEGIN
416struct GNUNET_TRANSPORT_TESTING_TestMessage
417{
418 /**
419 * Type is (usually) #GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE.
420 */
421 struct GNUNET_MessageHeader header;
422
423 /**
424 * Monotonically increasing counter throughout the test.
425 */
426 uint32_t num GNUNET_PACKED;
427};
428GNUNET_NETWORK_STRUCT_END
429
430
431/**
432 * Function called by the transport for each received message.
433 *
434 * @param cls closure
435 * @param receiver receiver of the message
436 * @param sender sender of the message
437 * @param message the message
438 */
439typedef void (*GNUNET_TRANSPORT_TESTING_ReceiveCallback) (
440 void *cls,
441 struct GNUNET_TRANSPORT_TESTING_PeerContext *receiver,
442 const struct GNUNET_PeerIdentity *sender,
443 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message);
444
445
446/**
447 * Function called to notify transport users that another
448 * peer connected to us.
449 *
450 * @param cls closure
451 * @param me peer experiencing the event
452 * @param other peer that connected to @a me
453 */
454typedef void (*GNUNET_TRANSPORT_TESTING_NotifyConnect) (
455 void *cls,
456 struct GNUNET_TRANSPORT_TESTING_PeerContext *me,
457 const struct GNUNET_PeerIdentity *other);
458
459
460/**
461 * Function called to notify transport users that another
462 * peer disconnected from us.
463 *
464 * @param cls closure
465 * @param me peer experiencing the event
466 * @param other peer that disconnected from @a me
467 */
468typedef void (*GNUNET_TRANSPORT_TESTING_NotifyDisconnect) (
469 void *cls,
470 struct GNUNET_TRANSPORT_TESTING_PeerContext *me,
471 const struct GNUNET_PeerIdentity *other);
472
473
474/**
475 * Closure that must be passed to
476 * #GNUNET_TRANSPORT_TESTING_connect_check.
477 */
478struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext
479{
480 /**
481 * How should we continue after the connect?
482 */
483 GNUNET_SCHEDULER_TaskCallback connect_continuation;
484
485 /**
486 * Closure for @e connect_continuation.
487 */
488 void *connect_continuation_cls;
489
490 /**
491 * Which configuration file should we pass to the
492 * #GNUNET_PROGRAM_run() of the testcase?
493 */
494 const char *config_file;
495
496 /**
497 * Receiver argument to give for peers we start.
498 */
499 GNUNET_TRANSPORT_TESTING_ReceiveCallback rec;
500
501 /**
502 * Notify connect argument to give for peers we start.
503 */
504 GNUNET_TRANSPORT_TESTING_NotifyConnect nc;
505
506 /**
507 * Notify disconnect argument to give for peers we start.
508 */
509 GNUNET_TRANSPORT_TESTING_NotifyDisconnect nd;
510
511 /**
512 * Closure for @e rec, @e nc and @e nd.
513 */
514 void *cls;
515
516 /**
517 * Custom task to run on shutdown.
518 */
519 GNUNET_SCHEDULER_TaskCallback shutdown_task;
520
521 /**
522 * Closure for @e shutdown_task.
523 */
524 void *shutdown_task_cls;
525
526 /**
527 * Custom task to run after peers were started but before we try to
528 * connect them. If this function is set, we wait ONE second after
529 * running this function until we continue with connecting the
530 * peers.
531 */
532 GNUNET_SCHEDULER_TaskCallback pre_connect_task;
533
534 /**
535 * Closure for @e shutdown_task.
536 */
537 void *pre_connect_task_cls;
538
539 /**
540 * When should the testcase time out?
541 */
542 struct GNUNET_TIME_Relative timeout;
543
544 /**
545 * Should we try to create connections in both directions?
546 */
547 int bi_directional;
548
549 /* ******* fields set by #GNUNET_TRANSPORT_TESTING_connect_check **** */
550
551 /**
552 * Number of peers involved in the test.
553 */
554 unsigned int num_peers;
555
556 /**
557 * Configuration files we have, array with @e num_peers entries.
558 */
559 char **cfg_files;
560
561 /**
562 * Array with @e num_peers entries.
563 */
564 struct GNUNET_TRANSPORT_TESTING_PeerContext **p;
565
566 /**
567 * Name of the plugin.
568 */
569 const char *test_plugin;
570
571 /**
572 * Name of the testcase.
573 */
574 const char *test_name;
575
576 /**
577 * Configuration object for the testcase.
578 */
579 const struct GNUNET_CONFIGURATION_Handle *cfg;
580
581 /**
582 * Main testing handle.
583 */
584 struct GNUNET_TRANSPORT_TESTING_Handle *tth;
585
586 /**
587 * Result from the main function, set to #GNUNET_OK on success.
588 * Clients should set to #GNUNET_SYSERR to indicate test failure.
589 */
590 int global_ret;
591
592 /**
593 * Generator for the `num` field in test messages. Incremented each
594 * time #GNUNET_TRANSPORT_TESTING_simple_send or
595 * #GNUNET_TRANSPORT_TESTING_large_send are used to transmit a
596 * message.
597 */
598 uint32_t send_num_gen;
599
600 /* ******* internal state, clients should not mess with this **** */
601
602 /**
603 * Task run on timeout.
604 */
605 struct GNUNET_SCHEDULER_Task *timeout_task;
606
607 /**
608 * Task run to connect peers.
609 */
610 struct GNUNET_SCHEDULER_Task *connect_task;
611
612 /**
613 * Number of peers that have been started.
614 */
615 unsigned int started;
616
617 /**
618 * DLL of active connect requests.
619 */
620 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *crl_head;
621
622 /**
623 * DLL of active connect requests.
624 */
625 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *crl_tail;
626
627 /**
628 * Array with @e num_peers entries.
629 */
630 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ip;
631};
632
633
634/**
635 * Find peer by peer ID.
636 *
637 * @param ccc context to search
638 * @param peer peer to look for
639 * @return NULL if @a peer was not found
640 */
641struct GNUNET_TRANSPORT_TESTING_PeerContext *
642GNUNET_TRANSPORT_TESTING_find_peer (
643 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc,
644 const struct GNUNET_PeerIdentity *peer);
645
646
647/**
648 * Common implementation of the #GNUNET_TRANSPORT_TESTING_CheckCallback.
649 * Starts and connects the two peers, then invokes the
650 * `connect_continuation` from @a cls. Sets up a timeout to
651 * abort the test, and a shutdown handler to clean up properly
652 * on exit.
653 *
654 * @param cls closure of type `struct
655 * GNUNET_TRANSPORT_TESTING_ConnectCheckContext`
656 * @param tth_ initialized testing handle
657 * @param test_plugin_ name of the plugin
658 * @param test_name_ name of the test
659 * @param num_peers number of entries in the @a cfg_file array
660 * @param cfg_files array of names of configuration files for the peers
661 * @return #GNUNET_SYSERR on error
662 */
663int
664GNUNET_TRANSPORT_TESTING_connect_check (
665 void *cls,
666 struct GNUNET_TRANSPORT_TESTING_Handle *tth_,
667 const char *test_plugin_,
668 const char *test_name_,
669 unsigned int num_peers,
670 char *cfg_files[]);
671
672
673/**
674 * Main function of a testcase. Called with the initial setup data
675 * for the test as derived from the source name and the binary name.
676 *
677 * @param cls closure
678 * @param tth_ initialized testing handle
679 * @param test_plugin_ name of the plugin
680 * @param test_name_ name of the test
681 * @param num_peers number of entries in the @a cfg_file array
682 * @param cfg_files array of names of configuration files for the peers
683 * @return #GNUNET_SYSERR on error
684 */
685typedef int (*GNUNET_TRANSPORT_TESTING_CheckCallback) (
686 void *cls,
687 struct GNUNET_TRANSPORT_TESTING_Handle *tth_,
688 const char *test_plugin_,
689 const char *test_name_,
690 unsigned int num_peers,
691 char *cfg_files[]);
692
693
694/**
695 * Setup testcase. Calls @a check with the data the test needs.
696 *
697 * @param argv0 binary name (argv[0])
698 * @param filename source file name (__FILE__)
699 * @param num_peers number of peers to start
700 * @param check main function to run
701 * @param check_cls closure for @a check
702 * @return #GNUNET_OK on success
703 */
704int
705GNUNET_TRANSPORT_TESTING_main_ (const char *argv0,
706 const char *filename,
707 unsigned int num_peers,
708 GNUNET_TRANSPORT_TESTING_CheckCallback check,
709 void *check_cls);
710
711
712/**
713 * Setup testcase. Calls @a check with the data the test needs.
714 *
715 * @param num_peers number of peers to start
716 * @param check main function to run
717 * @param check_cls closure for @a check
718 * @return #GNUNET_OK on success
719 */
720#define GNUNET_TRANSPORT_TESTING_main(num_peers, check, check_cls) \
721 GNUNET_TRANSPORT_TESTING_main_ (argv[0], \
722 __FILE__, \
723 num_peers, \
724 check, \
725 check_cls)
726
727/* ***************** Convenience functions for sending ********* */
728
729/**
730 * Send a test message of type @a mtype and size @a msize from
731 * peer @a sender to peer @a receiver. The peers should be
732 * connected when this function is called.
733 *
734 * @param sender the sending peer
735 * @param receiver the receiving peer
736 * @param mtype message type to use
737 * @param msize size of the message, at least `sizeof (struct
738 * GNUNET_TRANSPORT_TESTING_TestMessage)`
739 * @param num unique message number
740 * @param cont continuation to call after transmission
741 * @param cont_cls closure for @a cont
742 * @return #GNUNET_OK if message was queued,
743 * #GNUNET_NO if peers are not connected
744 * #GNUNET_SYSERR if @a msize is illegal
745 */
746int
747GNUNET_TRANSPORT_TESTING_send (
748 struct GNUNET_TRANSPORT_TESTING_PeerContext *sender,
749 struct GNUNET_TRANSPORT_TESTING_PeerContext *receiver,
750 uint16_t mtype,
751 uint16_t msize,
752 uint32_t num,
753 GNUNET_SCHEDULER_TaskCallback cont,
754 void *cont_cls);
755
756
757/**
758 * Message type used by #GNUNET_TRANSPORT_TESTING_simple_send().
759 */
760#define GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE 12345
761
762/**
763 * Alternative message type for tests.
764 */
765#define GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE2 12346
766
767
768/**
769 * Type of the closure argument to pass to
770 * #GNUNET_TRANSPORT_TESTING_simple_send() and
771 * #GNUNET_TRANSPORT_TESTING_large_send().
772 */
773struct GNUNET_TRANSPORT_TESTING_SendClosure
774{
775 /**
776 * Context for the transmission.
777 */
778 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
779
780 /**
781 * Function that returns the desired message size. Overrides
782 * the message size, can be NULL in which case the message
783 * size is the default.
784 */
785 size_t (*get_size_cb) (unsigned int n);
786
787 /**
788 * Number of messages to be transmitted in a loop.
789 * Use zero for "forever" (until external shutdown).
790 */
791 unsigned int num_messages;
792
793 /**
794 * Function to call after all transmissions, can be NULL.
795 */
796 GNUNET_SCHEDULER_TaskCallback cont;
797
798 /**
799 * Closure for @e cont.
800 */
801 void *cont_cls;
802};
803
804
805/**
806 * Task that sends a minimalistic test message from the
807 * first peer to the second peer.
808 *
809 * @param cls the `struct GNUNET_TRANSPORT_TESTING_SendClosure`
810 * which should contain at least two peers, the first two
811 * of which should be currently connected
812 */
813void
814GNUNET_TRANSPORT_TESTING_simple_send (void *cls);
815
816/**
817 * Size of a message sent with
818 * #GNUNET_TRANSPORT_TESTING_large_send(). Big enough
819 * to usually force defragmentation.
820 */
821#define GNUNET_TRANSPORT_TESTING_LARGE_MESSAGE_SIZE 2600
822
823/**
824 * Task that sends a large test message from the
825 * first peer to the second peer.
826 *
827 * @param cls the `struct GNUNET_TRANSPORT_TESTING_SendClosure`
828 * which should contain at least two peers, the first two
829 * of which should be currently connected
830 */
831void
832GNUNET_TRANSPORT_TESTING_large_send (void *cls);
833
834
835/* ********************** log-only convenience functions ************* */
836
837
838/**
839 * Log a connect event.
840 *
841 * @param cls NULL
842 * @param me peer that had the event
843 * @param other peer that connected.
844 */
845void
846GNUNET_TRANSPORT_TESTING_log_connect (
847 void *cls,
848 struct GNUNET_TRANSPORT_TESTING_PeerContext *me,
849 const struct GNUNET_PeerIdentity *other);
850
851
852/**
853 * Log a disconnect event.
854 *
855 * @param cls NULL
856 * @param me peer that had the event
857 * @param other peer that disconnected.
858 */
859void
860GNUNET_TRANSPORT_TESTING_log_disconnect (
861 void *cls,
862 struct GNUNET_TRANSPORT_TESTING_PeerContext *me,
863 const struct GNUNET_PeerIdentity *other);
864
865
866/* ********************** low-level filename functions *************** */
867
868
869/**
870 * Extracts the test filename from an absolute file name and removes
871 * the extension.
872 *
873 * @param file absolute file name
874 * @return resulting test name
875 */
876char *
877GNUNET_TRANSPORT_TESTING_get_test_name (const char *file);
878
879
880/**
881 * This function takes the filename (e.g. argv[0), removes a "lt-"-prefix and
882 * if existing ".exe"-prefix and adds the peer-number
883 *
884 * @param file filename of the test, e.g. argv[0]
885 * @param count peer number
886 * @return configuration name to use
887 */
888char *
889GNUNET_TRANSPORT_TESTING_get_config_name (const char *file, int count);
890
891
892/**
893 * Extracts the plugin anme from an absolute file name and the test name
894 * @param file absolute file name
895 * @param test test name
896 * @return the plugin name
897 */
898char *
899GNUNET_TRANSPORT_TESTING_get_test_plugin_name (const char *executable,
900 const char *testname);
901
902
903/**
904 * Extracts the filename from an absolute file name and removes the
905 * extension
906 *
907 * @param file absolute file name
908 * @return the source name
909 */
910char *
911GNUNET_TRANSPORT_TESTING_get_test_source_name (const char *file);
912
913#endif
914/* end of transport_testing.h */
diff --git a/src/transport/transport-testing2.c b/src/transport/transport-testing2.c
index ec27ac8ba..11bb6c7d1 100644
--- a/src/transport/transport-testing2.c
+++ b/src/transport/transport-testing2.c
@@ -225,10 +225,10 @@ notify_connect (void *cls,
225 GNUNET_SCHEDULER_cancel (cc->tct); 225 GNUNET_SCHEDULER_cancel (cc->tct);
226 cc->tct = NULL; 226 cc->tct = NULL;
227 } 227 }
228 if (NULL != cc->ats_sh) 228 if (NULL != cc->ah_sh)
229 { 229 {
230 GNUNET_ATS_connectivity_suggest_cancel (cc->ats_sh); 230 GNUNET_TRANSPORT_application_suggest_cancel (cc->ah_sh);
231 cc->ats_sh = NULL; 231 cc->ah_sh = NULL;
232 } 232 }
233 } 233 }
234 } 234 }
@@ -268,6 +268,7 @@ notify_disconnect (void *cls,
268 int no = 0; 268 int no = 0;
269 struct GNUNET_TRANSPORT_TESTING_PeerContext *p2 = NULL; 269 struct GNUNET_TRANSPORT_TESTING_PeerContext *p2 = NULL;
270 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc; 270 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
271 struct GNUNET_BANDWIDTH_Value32NBO bw;
271 272
272 p2 = find_peer_context (p->tth, 273 p2 = find_peer_context (p->tth,
273 peer); 274 peer);
@@ -321,10 +322,11 @@ notify_disconnect (void *cls,
321 if (NULL == cc->tct) 322 if (NULL == cc->tct)
322 cc->tct = GNUNET_SCHEDULER_add_now (&offer_hello, 323 cc->tct = GNUNET_SCHEDULER_add_now (&offer_hello,
323 cc); 324 cc);
324 if (NULL == cc->ats_sh) 325 if (NULL == cc->ah_sh)
325 cc->ats_sh = GNUNET_ATS_connectivity_suggest (cc->p1->ats, 326 cc->ah_sh = GNUNET_TRANSPORT_application_suggest (cc->p1->ah,
326 &p2->id, 327 &p2->id,
327 1); 328 GNUNET_MQ_PRIO_BEST_EFFORT,
329 bw);
328 } 330 }
329 } 331 }
330} 332}
@@ -512,11 +514,11 @@ GNUNET_TRANSPORT_TESTING_start_peer (struct
512 GNUNET_free (emsg); 514 GNUNET_free (emsg);
513 return NULL; 515 return NULL;
514 } 516 }
515 p->ats = GNUNET_ATS_connectivity_init (p->cfg); 517 p->ah = GNUNET_TRANSPORT_application_init (p->cfg);
516 if (NULL == p->ats) 518 if (NULL == p->ah)
517 { 519 {
518 LOG (GNUNET_ERROR_TYPE_ERROR, 520 LOG (GNUNET_ERROR_TYPE_ERROR,
519 "Failed to connect to ATS service for peer `%s': `%s'\n", 521 "Failed to connect to TNG service for peer `%s': `%s'\n",
520 cfgname, 522 cfgname,
521 emsg); 523 emsg);
522 GNUNET_TRANSPORT_TESTING_stop_peer (p); 524 GNUNET_TRANSPORT_TESTING_stop_peer (p);
@@ -525,9 +527,6 @@ GNUNET_TRANSPORT_TESTING_start_peer (struct
525 } 527 }
526 p->ph = GNUNET_PEERSTORE_connect (p->cfg); 528 p->ph = GNUNET_PEERSTORE_connect (p->cfg);
527 // FIXME Error handling 529 // FIXME Error handling
528 p->ah = GNUNET_TRANSPORT_application_init (p->cfg);
529 GNUNET_assert (NULL != p->ah);
530 // FIXME Error handling
531 p->rh_task = GNUNET_SCHEDULER_add_now (retrieve_hello, p); 530 p->rh_task = GNUNET_SCHEDULER_add_now (retrieve_hello, p);
532 531
533 return p; 532 return p;
@@ -565,10 +564,10 @@ GNUNET_TRANSPORT_TESTING_restart_peer (struct
565 (cc->p2 == p)) 564 (cc->p2 == p))
566 GNUNET_TRANSPORT_TESTING_connect_peers_cancel (cc); 565 GNUNET_TRANSPORT_TESTING_connect_peers_cancel (cc);
567 } 566 }
568 if (NULL != p->ats) 567 if (NULL != p->ah)
569 { 568 {
570 GNUNET_ATS_connectivity_done (p->ats); 569 GNUNET_TRANSPORT_application_done (p->ah);
571 p->ats = NULL; 570 p->ah = NULL;
572 } 571 }
573 if (GNUNET_SYSERR == 572 if (GNUNET_SYSERR ==
574 GNUNET_TESTING_peer_stop (p->peer)) 573 GNUNET_TESTING_peer_stop (p->peer))
@@ -607,7 +606,7 @@ GNUNET_TRANSPORT_TESTING_restart_peer (struct
607 &notify_connect, 606 &notify_connect,
608 &notify_disconnect); 607 &notify_disconnect);
609 GNUNET_assert (NULL != p->th); 608 GNUNET_assert (NULL != p->th);
610 p->ats = GNUNET_ATS_connectivity_init (p->cfg); 609 p->ah = GNUNET_TRANSPORT_application_init (p->cfg);
611 p->pic = GNUNET_PEERSTORE_iterate (p->ph, 610 p->pic = GNUNET_PEERSTORE_iterate (p->ph,
612 "transport", 611 "transport",
613 &p->id, 612 &p->id,
@@ -654,11 +653,6 @@ GNUNET_TRANSPORT_TESTING_stop_peer (struct
654 GNUNET_TRANSPORT_core_disconnect (p->th); 653 GNUNET_TRANSPORT_core_disconnect (p->th);
655 p->th = NULL; 654 p->th = NULL;
656 } 655 }
657 if (NULL != p->ats)
658 {
659 GNUNET_ATS_connectivity_done (p->ats);
660 p->ats = NULL;
661 }
662 if (NULL != p->ah) 656 if (NULL != p->ah)
663 { 657 {
664 GNUNET_TRANSPORT_application_done (p->ah); 658 GNUNET_TRANSPORT_application_done (p->ah);
@@ -794,6 +788,7 @@ GNUNET_TRANSPORT_TESTING_connect_peers (struct
794 struct GNUNET_TRANSPORT_TESTING_Handle *tth = p1->tth; 788 struct GNUNET_TRANSPORT_TESTING_Handle *tth = p1->tth;
795 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc; 789 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
796 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ccn; 790 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ccn;
791 struct GNUNET_BANDWIDTH_Value32NBO bw;
797 792
798 ccn = NULL; 793 ccn = NULL;
799 for (cc = tth->cc_head; NULL != cc; cc = cc->next) 794 for (cc = tth->cc_head; NULL != cc; cc = cc->next)
@@ -825,9 +820,10 @@ GNUNET_TRANSPORT_TESTING_connect_peers (struct
825 cc); 820 cc);
826 cc->tct = GNUNET_SCHEDULER_add_now (&offer_hello, 821 cc->tct = GNUNET_SCHEDULER_add_now (&offer_hello,
827 cc); 822 cc);
828 cc->ats_sh = GNUNET_ATS_connectivity_suggest (cc->p1->ats, 823 cc->ah_sh = GNUNET_TRANSPORT_application_suggest (cc->p1->ah,
829 &p2->id, 824 &p2->id,
830 1); 825 GNUNET_MQ_PRIO_BEST_EFFORT,
826 bw);
831 LOG (GNUNET_ERROR_TYPE_DEBUG, 827 LOG (GNUNET_ERROR_TYPE_DEBUG,
832 "New connect request %p\n", 828 "New connect request %p\n",
833 cc); 829 cc);
@@ -849,10 +845,10 @@ GNUNET_TRANSPORT_TESTING_connect_peers_cancel (struct
849 GNUNET_SCHEDULER_cancel (cc->tct); 845 GNUNET_SCHEDULER_cancel (cc->tct);
850 cc->tct = NULL; 846 cc->tct = NULL;
851 } 847 }
852 if (NULL != cc->ats_sh) 848 if (NULL != cc->ah_sh)
853 { 849 {
854 GNUNET_ATS_connectivity_suggest_cancel (cc->ats_sh); 850 GNUNET_TRANSPORT_application_suggest_cancel (cc->ah_sh);
855 cc->ats_sh = NULL; 851 cc->ah_sh = NULL;
856 } 852 }
857 GNUNET_CONTAINER_DLL_remove (tth->cc_head, 853 GNUNET_CONTAINER_DLL_remove (tth->cc_head,
858 tth->cc_tail, 854 tth->cc_tail,
diff --git a/src/transport/transport-testing2.h b/src/transport/transport-testing2.h
index b9e492219..bfd9f3d33 100644
--- a/src/transport/transport-testing2.h
+++ b/src/transport/transport-testing2.h
@@ -85,11 +85,6 @@ struct GNUNET_TRANSPORT_TESTING_PeerContext
85 struct GNUNET_TRANSPORT_CoreHandle *th; 85 struct GNUNET_TRANSPORT_CoreHandle *th;
86 86
87 /** 87 /**
88 * Peer's ATS handle.
89 */
90 struct GNUNET_ATS_ConnectivityHandle *ats;
91
92 /**
93 * Peer's PEERSTORE Handle 88 * Peer's PEERSTORE Handle
94 */ 89 */
95 struct GNUNET_PEERSTORE_Handle *ph; 90 struct GNUNET_PEERSTORE_Handle *ph;
@@ -197,9 +192,9 @@ struct GNUNET_TRANSPORT_TESTING_ConnectRequest
197 struct GNUNET_SCHEDULER_Task *tct; 192 struct GNUNET_SCHEDULER_Task *tct;
198 193
199 /** 194 /**
200 * Handle by which we ask ATS to facilitate the connection. 195 * Handle by which we ask TNG to facilitate the connection.
201 */ 196 */
202 struct GNUNET_ATS_ConnectivitySuggestHandle *ats_sh; 197 struct GNUNET_TRANSPORT_ApplicationSuggestHandle *ah_sh;
203 198
204 /** 199 /**
205 * Function to call upon completion. 200 * Function to call upon completion.
@@ -447,7 +442,7 @@ struct GNUNET_TRANSPORT_TESTING_PerformanceTestMessage
447 * Time this message was send via transport api. 442 * Time this message was send via transport api.
448 */ 443 */
449 struct GNUNET_TIME_AbsoluteNBO time_send; 444 struct GNUNET_TIME_AbsoluteNBO time_send;
450 445
451 /** 446 /**
452 * Monotonically increasing counter throughout the test. 447 * Monotonically increasing counter throughout the test.
453 */ 448 */
diff --git a/src/transport/transport_api_address_to_string.c b/src/transport/transport_api_address_to_string.c
deleted file mode 100644
index 5b234f802..000000000
--- a/src/transport/transport_api_address_to_string.c
+++ /dev/null
@@ -1,264 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-2014, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport/transport_api_address_to_string.c
22 * @author Christian Grothoff
23 * @brief enable clients to convert addresses to human readable strings
24 */
25#include "platform.h"
26#include "gnunet_util_lib.h"
27#include "gnunet_arm_service.h"
28#include "gnunet_hello_lib.h"
29#include "gnunet_protocols.h"
30#include "gnunet_transport_service.h"
31#include "transport.h"
32
33/**
34 * Context for the address lookup.
35 */
36struct GNUNET_TRANSPORT_AddressToStringContext
37{
38 /**
39 * Function to call with the human-readable address.
40 */
41 GNUNET_TRANSPORT_AddressToStringCallback cb;
42
43 /**
44 * Closure for @e cb.
45 */
46 void *cb_cls;
47
48 /**
49 * Connection to the service.
50 */
51 struct GNUNET_MQ_Handle *mq;
52};
53
54
55/**
56 * Function called with responses from the service.
57 *
58 * @param cls our `struct GNUNET_TRANSPORT_AddressToStringContext *`
59 * @param atsm message with the human-readable address
60 * @return #GNUNET_OK if message is well-formed
61 */
62static int
63check_reply (void *cls,
64 const struct AddressToStringResultMessage *atsm)
65{
66 uint16_t size = ntohs (atsm->header.size) - sizeof(*atsm);
67 const char *address;
68 int result;
69 uint32_t addr_len;
70
71 result = (int) ntohl (atsm->res);
72 addr_len = ntohl (atsm->addr_len);
73 if (GNUNET_SYSERR == result)
74 return GNUNET_OK;
75 if (0 == size)
76 {
77 if (GNUNET_OK != result)
78 {
79 GNUNET_break (0);
80 return GNUNET_SYSERR;
81 }
82 return GNUNET_OK;
83 }
84 address = (const char *) &atsm[1];
85 if ((addr_len > size) ||
86 (address[addr_len - 1] != '\0'))
87 {
88 /* invalid reply */
89 GNUNET_break (0);
90 return GNUNET_SYSERR;
91 }
92 return GNUNET_OK;
93}
94
95
96/**
97 * Function called with responses from the service.
98 *
99 * @param cls our `struct GNUNET_TRANSPORT_AddressToStringContext *`
100 * @param atsm message with the human-readable address
101 */
102static void
103handle_reply (void *cls,
104 const struct AddressToStringResultMessage *atsm)
105{
106 struct GNUNET_TRANSPORT_AddressToStringContext *alucb = cls;
107 uint16_t size = ntohs (atsm->header.size) - sizeof(*atsm);
108 const char *address;
109 int result;
110
111 result = (int) ntohl (atsm->res);
112 if (GNUNET_SYSERR == result)
113 {
114 /* expect more replies; as this is not the last
115 call, we must pass the empty string for the address */
116 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
117 "Address resolution failed\n");
118 alucb->cb (alucb->cb_cls,
119 "",
120 GNUNET_NO);
121 return;
122 }
123 if (0 == size)
124 {
125 /* we are done (successfully, without communication errors) */
126 alucb->cb (alucb->cb_cls,
127 NULL,
128 GNUNET_OK);
129 GNUNET_TRANSPORT_address_to_string_cancel (alucb);
130 return;
131 }
132 address = (const char *) &atsm[1];
133 /* return normal reply to caller, also expect more replies */
134 alucb->cb (alucb->cb_cls,
135 address,
136 GNUNET_OK);
137}
138
139
140/**
141 * Generic error handler, called with the appropriate
142 * error code and the same closure specified at the creation of
143 * the message queue.
144 * Not every message queue implementation supports an error handler.
145 *
146 * @param cls the `struct GNUNET_TRANSPORT_AddressToStringContext *`
147 * @param error error code
148 */
149static void
150mq_error_handler (void *cls,
151 enum GNUNET_MQ_Error error)
152{
153 struct GNUNET_TRANSPORT_AddressToStringContext *alucb = cls;
154
155 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
156 "Disconnected from transport, address resolution failed\n");
157 alucb->cb (alucb->cb_cls,
158 NULL,
159 GNUNET_SYSERR);
160 GNUNET_TRANSPORT_address_to_string_cancel (alucb);
161}
162
163
164/**
165 * Convert a binary address into a human readable address.
166 *
167 * @param cfg configuration to use
168 * @param address address to convert (binary format)
169 * @param numeric should (IP) addresses be displayed in numeric form
170 * (otherwise do reverse DNS lookup)
171 * @param timeout how long is the lookup allowed to take at most
172 * @param aluc function to call with the results
173 * @param aluc_cls closure for @a aluc
174 * @return handle to cancel the operation, NULL on error
175 */
176struct GNUNET_TRANSPORT_AddressToStringContext *
177GNUNET_TRANSPORT_address_to_string (const struct
178 GNUNET_CONFIGURATION_Handle *cfg,
179 const struct GNUNET_HELLO_Address *address,
180 int numeric,
181 struct GNUNET_TIME_Relative timeout,
182 GNUNET_TRANSPORT_AddressToStringCallback
183 aluc,
184 void *aluc_cls)
185{
186 struct GNUNET_TRANSPORT_AddressToStringContext *alc
187 = GNUNET_new (struct GNUNET_TRANSPORT_AddressToStringContext);
188 struct GNUNET_MQ_MessageHandler handlers[] = {
189 GNUNET_MQ_hd_var_size (reply,
190 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY,
191 struct AddressToStringResultMessage,
192 alc),
193 GNUNET_MQ_handler_end ()
194 };
195 size_t alen;
196 size_t slen;
197 struct AddressLookupMessage *msg;
198 struct GNUNET_MQ_Envelope *env;
199 char *addrbuf;
200
201 alen = address->address_length;
202 slen = strlen (address->transport_name) + 1;
203 if ((alen + slen >= GNUNET_MAX_MESSAGE_SIZE
204 - sizeof(struct AddressLookupMessage)) ||
205 (alen >= GNUNET_MAX_MESSAGE_SIZE) ||
206 (slen >= GNUNET_MAX_MESSAGE_SIZE))
207 {
208 GNUNET_break (0);
209 GNUNET_free (alc);
210 return NULL;
211 }
212 alc->cb = aluc;
213 alc->cb_cls = aluc_cls;
214 alc->mq = GNUNET_CLIENT_connect (cfg,
215 "transport",
216 handlers,
217 &mq_error_handler,
218 alc);
219 if (NULL == alc->mq)
220 {
221 GNUNET_break (0);
222 GNUNET_free (alc);
223 return NULL;
224 }
225 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
226 "Client tries to resolve for peer `%s' address plugin %s len %u\n",
227 GNUNET_i2s (&address->peer),
228 address->transport_name,
229 (unsigned int) address->address_length);
230 env = GNUNET_MQ_msg_extra (msg,
231 alen + slen,
232 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING);
233 msg->numeric_only = htons ((int16_t) numeric);
234 msg->addrlen = htons ((uint16_t) alen);
235 msg->timeout = GNUNET_TIME_relative_hton (timeout);
236 addrbuf = (char *) &msg[1];
237 GNUNET_memcpy (addrbuf,
238 address->address,
239 alen);
240 GNUNET_memcpy (&addrbuf[alen],
241 address->transport_name,
242 slen);
243 GNUNET_MQ_send (alc->mq,
244 env);
245 return alc;
246}
247
248
249/**
250 * Cancel request for address conversion.
251 *
252 * @param alc the context handle
253 */
254void
255GNUNET_TRANSPORT_address_to_string_cancel (struct
256 GNUNET_TRANSPORT_AddressToStringContext
257 *alc)
258{
259 GNUNET_MQ_destroy (alc->mq);
260 GNUNET_free (alc);
261}
262
263
264/* end of transport_api_address_to_string.c */
diff --git a/src/transport/transport_api_blacklist.c b/src/transport/transport_api_blacklist.c
deleted file mode 100644
index b195a7fc7..000000000
--- a/src/transport/transport_api_blacklist.c
+++ /dev/null
@@ -1,197 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010-2014, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/transport_api_blacklist.c
23 * @brief library to access the blacklisting functions of the transport service
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_arm_service.h"
29#include "gnunet_hello_lib.h"
30#include "gnunet_protocols.h"
31#include "gnunet_transport_service.h"
32#include "transport.h"
33
34/**
35 * Handle for blacklisting requests.
36 */
37struct GNUNET_TRANSPORT_Blacklist
38{
39 /**
40 * Connection to transport service.
41 */
42 struct GNUNET_MQ_Handle *mq;
43
44 /**
45 * Configuration to use.
46 */
47 const struct GNUNET_CONFIGURATION_Handle *cfg;
48
49 /**
50 * Function to call for determining if a peer is allowed
51 * to communicate with us.
52 */
53 GNUNET_TRANSPORT_BlacklistCallback cb;
54
55 /**
56 * Closure for @e cb.
57 */
58 void *cb_cls;
59};
60
61
62/**
63 * Establish blacklist connection to transport service.
64 *
65 * @param br overall handle
66 */
67static void
68reconnect (struct GNUNET_TRANSPORT_Blacklist *br);
69
70
71/**
72 * Handle blacklist queries.
73 *
74 * @param cls our overall handle
75 * @param bm query
76 */
77static void
78handle_query (void *cls,
79 const struct BlacklistMessage *bm)
80{
81 struct GNUNET_TRANSPORT_Blacklist *br = cls;
82 struct GNUNET_MQ_Envelope *env;
83 struct BlacklistMessage *res;
84
85 GNUNET_break (0 == ntohl (bm->is_allowed));
86 env = GNUNET_MQ_msg (res,
87 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY);
88 res->is_allowed = htonl (br->cb (br->cb_cls,
89 &bm->peer));
90 res->peer = bm->peer;
91 GNUNET_MQ_send (br->mq,
92 env);
93}
94
95
96/**
97 * Generic error handler, called with the appropriate error code and
98 * the same closure specified at the creation of the message queue.
99 * Not every message queue implementation supports an error handler.
100 *
101 * @param cls closure with the `struct GNUNET_TRANSPORT_Blacklist *`
102 * @param error error code
103 */
104static void
105mq_error_handler (void *cls,
106 enum GNUNET_MQ_Error error)
107{
108 struct GNUNET_TRANSPORT_Blacklist *br = cls;
109
110 reconnect (br);
111}
112
113
114/**
115 * Establish blacklist connection to transport service.
116 *
117 * @param br overall handle
118 */
119static void
120reconnect (struct GNUNET_TRANSPORT_Blacklist *br)
121{
122 struct GNUNET_MQ_MessageHandler handlers[] = {
123 GNUNET_MQ_hd_fixed_size (query,
124 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY,
125 struct BlacklistMessage,
126 br),
127 GNUNET_MQ_handler_end ()
128 };
129 struct GNUNET_MQ_Envelope *env;
130 struct GNUNET_MessageHeader *req;
131
132 if (NULL != br->mq)
133 GNUNET_MQ_destroy (br->mq);
134 br->mq = GNUNET_CLIENT_connect (br->cfg,
135 "transport",
136 handlers,
137 &mq_error_handler,
138 br);
139 if (NULL == br->mq)
140 return;
141 env = GNUNET_MQ_msg (req,
142 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT);
143 GNUNET_MQ_send (br->mq,
144 env);
145}
146
147
148/**
149 * Install a blacklist callback. The service will be queried for all
150 * existing connections as well as any fresh connections to check if
151 * they are permitted. If the blacklisting callback is unregistered,
152 * all hosts that were denied in the past will automatically be
153 * whitelisted again. Cancelling the blacklist handle is also the
154 * only way to re-enable connections from peers that were previously
155 * blacklisted.
156 *
157 * @param cfg configuration to use
158 * @param cb callback to invoke to check if connections are allowed
159 * @param cb_cls closure for @a cb
160 * @return NULL on error, otherwise handle for cancellation
161 */
162struct GNUNET_TRANSPORT_Blacklist *
163GNUNET_TRANSPORT_blacklist (const struct GNUNET_CONFIGURATION_Handle *cfg,
164 GNUNET_TRANSPORT_BlacklistCallback cb,
165 void *cb_cls)
166{
167 struct GNUNET_TRANSPORT_Blacklist *br;
168
169 br = GNUNET_new (struct GNUNET_TRANSPORT_Blacklist);
170 br->cfg = cfg;
171 br->cb = cb;
172 br->cb_cls = cb_cls;
173 reconnect (br);
174 if (NULL == br->mq)
175 {
176 GNUNET_free (br);
177 return NULL;
178 }
179 return br;
180}
181
182
183/**
184 * Abort the blacklist. Note that this function is the only way for
185 * removing a peer from the blacklist.
186 *
187 * @param br handle of the request that is to be cancelled
188 */
189void
190GNUNET_TRANSPORT_blacklist_cancel (struct GNUNET_TRANSPORT_Blacklist *br)
191{
192 GNUNET_MQ_destroy (br->mq);
193 GNUNET_free (br);
194}
195
196
197/* end of transport_api_blacklist.c */
diff --git a/src/transport/transport_api_core.c b/src/transport/transport_api_core.c
deleted file mode 100644
index 12612de09..000000000
--- a/src/transport/transport_api_core.c
+++ /dev/null
@@ -1,968 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-2013, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/transport_api_core.c
23 * @brief library to access the transport service for message exchange
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_constants.h"
29#include "gnunet_arm_service.h"
30#include "gnunet_hello_lib.h"
31#include "gnunet_protocols.h"
32#include "gnunet_transport_service.h"
33#include "transport.h"
34
35#define LOG(kind, ...) GNUNET_log_from (kind, "transport-api-core", __VA_ARGS__)
36
37/**
38 * If we could not send any payload to a peer for this amount of
39 * time, we print a warning.
40 */
41#define UNREADY_WARN_TIME GNUNET_TIME_UNIT_MINUTES
42
43/**
44 * How large to start with for the hashmap of neighbours.
45 */
46#define STARTING_NEIGHBOURS_SIZE 16
47
48
49/**
50 * Entry in hash table of all of our current (connected) neighbours.
51 */
52struct Neighbour
53{
54 /**
55 * Overall transport handle.
56 */
57 struct GNUNET_TRANSPORT_CoreHandle *h;
58
59 /**
60 * Active message queue for the peer.
61 */
62 struct GNUNET_MQ_Handle *mq;
63
64 /**
65 * Envelope with the message we are currently transmitting (or NULL).
66 */
67 struct GNUNET_MQ_Envelope *env;
68
69 /**
70 * Closure for @e mq handlers.
71 */
72 void *handlers_cls;
73
74 /**
75 * Identity of this neighbour.
76 */
77 struct GNUNET_PeerIdentity id;
78
79 /**
80 * Outbound bandwidh tracker.
81 */
82 struct GNUNET_BANDWIDTH_Tracker out_tracker;
83
84 /**
85 * Entry in our readiness heap (which is sorted by @e next_ready
86 * value). NULL if there is no pending transmission request for
87 * this neighbour or if we're waiting for @e is_ready to become
88 * true AFTER the @e out_tracker suggested that this peer's quota
89 * has been satisfied (so once @e is_ready goes to #GNUNET_YES,
90 * we should immediately go back into the heap).
91 */
92 struct GNUNET_CONTAINER_HeapNode *hn;
93
94 /**
95 * Task to trigger MQ when we have enough bandwidth for the
96 * next transmission.
97 */
98 struct GNUNET_SCHEDULER_Task *timeout_task;
99
100 /**
101 * Sending consumed more bytes on wire than payload was announced
102 * This overhead is added to the delay of next sending operation
103 */
104 unsigned long long traffic_overhead;
105
106 /**
107 * Is this peer currently ready to receive a message?
108 */
109 int is_ready;
110
111 /**
112 * Size of the message in @e env.
113 */
114 uint16_t env_size;
115};
116
117
118/**
119 * Handle for the transport service (includes all of the
120 * state for the transport service).
121 */
122struct GNUNET_TRANSPORT_CoreHandle
123{
124 /**
125 * Closure for the callbacks.
126 */
127 void *cls;
128
129 /**
130 * Functions to call for received data (template for
131 * new message queues).
132 */
133 struct GNUNET_MQ_MessageHandler *handlers;
134
135 /**
136 * function to call on connect events
137 */
138 GNUNET_TRANSPORT_NotifyConnect nc_cb;
139
140 /**
141 * function to call on disconnect events
142 */
143 GNUNET_TRANSPORT_NotifyDisconnect nd_cb;
144
145 /**
146 * function to call on excess bandwidth events
147 */
148 GNUNET_TRANSPORT_NotifyExcessBandwidth neb_cb;
149
150 /**
151 * My client connection to the transport service.
152 */
153 struct GNUNET_MQ_Handle *mq;
154
155 /**
156 * My configuration.
157 */
158 const struct GNUNET_CONFIGURATION_Handle *cfg;
159
160 /**
161 * Hash map of the current connected neighbours of this peer.
162 * Maps peer identities to `struct Neighbour` entries.
163 */
164 struct GNUNET_CONTAINER_MultiPeerMap *neighbours;
165
166 /**
167 * Peer identity as assumed by this process, or all zeros.
168 */
169 struct GNUNET_PeerIdentity self;
170
171 /**
172 * ID of the task trying to reconnect to the service.
173 */
174 struct GNUNET_SCHEDULER_Task *reconnect_task;
175
176 /**
177 * Delay until we try to reconnect.
178 */
179 struct GNUNET_TIME_Relative reconnect_delay;
180
181 /**
182 * Internal counter to check how many more receive OK messages this
183 * CORE service is allowed to send in total. Just to detect easy
184 * cases of protocol violations by the CORE implementation.
185 * NOTE: we may want to make this stronger by counting per peer
186 * instead of globally.
187 */
188 unsigned int rom_pending;
189
190 /**
191 * Should we check that @e self matches what the service thinks?
192 * (if #GNUNET_NO, then @e self is all zeros!).
193 */
194 int check_self;
195};
196
197
198/**
199 * Function that will schedule the job that will try
200 * to connect us again to the client.
201 *
202 * @param h transport service to reconnect
203 */
204static void
205disconnect_and_schedule_reconnect (struct GNUNET_TRANSPORT_CoreHandle *h);
206
207
208/**
209 * Get the neighbour list entry for the given peer
210 *
211 * @param h our context
212 * @param peer peer to look up
213 * @return NULL if no such peer entry exists
214 */
215static struct Neighbour *
216neighbour_find (struct GNUNET_TRANSPORT_CoreHandle *h,
217 const struct GNUNET_PeerIdentity *peer)
218{
219 return GNUNET_CONTAINER_multipeermap_get (h->neighbours, peer);
220}
221
222
223/**
224 * Function called by the bandwidth tracker if we have excess
225 * bandwidth.
226 *
227 * @param cls the `struct Neighbour` that has excess bandwidth
228 */
229static void
230notify_excess_cb (void *cls)
231{
232 struct Neighbour *n = cls;
233 struct GNUNET_TRANSPORT_CoreHandle *h = n->h;
234
235 LOG (GNUNET_ERROR_TYPE_DEBUG,
236 "Notifying CORE that more bandwidth is available for %s\n",
237 GNUNET_i2s (&n->id));
238
239 if (NULL != h->neb_cb)
240 h->neb_cb (h->cls, &n->id, n->handlers_cls);
241}
242
243
244/**
245 * Iterator over hash map entries, for deleting state of a neighbour.
246 *
247 * @param cls the `struct GNUNET_TRANSPORT_CoreHandle *`
248 * @param key peer identity
249 * @param value value in the hash map, the neighbour entry to delete
250 * @return #GNUNET_YES if we should continue to
251 * iterate,
252 * #GNUNET_NO if not.
253 */
254static int
255neighbour_delete (void *cls, const struct GNUNET_PeerIdentity *key, void *value)
256{
257 struct GNUNET_TRANSPORT_CoreHandle *handle = cls;
258 struct Neighbour *n = value;
259
260 LOG (GNUNET_ERROR_TYPE_DEBUG,
261 "Dropping entry for neighbour `%s'.\n",
262 GNUNET_i2s (key));
263 GNUNET_BANDWIDTH_tracker_notification_stop (&n->out_tracker);
264 if (NULL != handle->nd_cb)
265 handle->nd_cb (handle->cls, &n->id, n->handlers_cls);
266 if (NULL != n->timeout_task)
267 {
268 GNUNET_SCHEDULER_cancel (n->timeout_task);
269 n->timeout_task = NULL;
270 }
271 if (NULL != n->env)
272 {
273 GNUNET_MQ_send_cancel (n->env);
274 n->env = NULL;
275 }
276 GNUNET_MQ_destroy (n->mq);
277 GNUNET_assert (NULL == n->mq);
278 GNUNET_assert (
279 GNUNET_YES ==
280 GNUNET_CONTAINER_multipeermap_remove (handle->neighbours, key, n));
281 GNUNET_free (n);
282 return GNUNET_YES;
283}
284
285
286/**
287 * Generic error handler, called with the appropriate
288 * error code and the same closure specified at the creation of
289 * the message queue.
290 * Not every message queue implementation supports an error handler.
291 *
292 * @param cls closure with the `struct GNUNET_TRANSPORT_CoreHandle *`
293 * @param error error code
294 */
295static void
296mq_error_handler (void *cls, enum GNUNET_MQ_Error error)
297{
298 struct GNUNET_TRANSPORT_CoreHandle *h = cls;
299
300 LOG (GNUNET_ERROR_TYPE_ERROR,
301 "Error receiving from transport service (%d), disconnecting temporarily.\n",
302 error);
303 disconnect_and_schedule_reconnect (h);
304}
305
306
307/**
308 * Function we use for checking incoming HELLO messages.
309 *
310 * @param cls closure, a `struct GNUNET_TRANSPORT_CoreHandle *`
311 * @param msg message received
312 * @return #GNUNET_OK if message is well-formed
313 */
314static int
315check_hello (void *cls, const struct GNUNET_MessageHeader *msg)
316{
317 struct GNUNET_PeerIdentity me;
318
319 if (GNUNET_OK !=
320 GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *) msg, &me))
321 {
322 GNUNET_break (0);
323 return GNUNET_SYSERR;
324 }
325 return GNUNET_OK;
326}
327
328
329/**
330 * Function we use for handling incoming HELLO messages.
331 *
332 * @param cls closure, a `struct GNUNET_TRANSPORT_CoreHandle *`
333 * @param msg message received
334 */
335static void
336handle_hello (void *cls, const struct GNUNET_MessageHeader *msg)
337{
338 /* we do not care => FIXME: signal in options to NEVER send HELLOs! */
339}
340
341
342/**
343 * A message from the handler's message queue to a neighbour was
344 * transmitted. Now trigger (possibly delayed) notification of the
345 * neighbour's message queue that we are done and thus ready for
346 * the next message.
347 *
348 * @param cls the `struct Neighbour` where the message was sent
349 */
350static void
351notify_send_done_fin (void *cls)
352{
353 struct Neighbour *n = cls;
354
355 n->timeout_task = NULL;
356 n->is_ready = GNUNET_YES;
357 GNUNET_MQ_impl_send_continue (n->mq);
358}
359
360
361/**
362 * A message from the handler's message queue to a neighbour was
363 * transmitted. Now trigger (possibly delayed) notification of the
364 * neighbour's message queue that we are done and thus ready for
365 * the next message.
366 *
367 * @param cls the `struct Neighbour` where the message was sent
368 */
369static void
370notify_send_done (void *cls)
371{
372 struct Neighbour *n = cls;
373 struct GNUNET_TIME_Relative delay;
374
375 n->timeout_task = NULL;
376 if (NULL != n->env)
377 {
378 GNUNET_BANDWIDTH_tracker_consume (&n->out_tracker,
379 n->env_size + n->traffic_overhead);
380 n->env = NULL;
381 n->traffic_overhead = 0;
382 }
383 delay = GNUNET_BANDWIDTH_tracker_get_delay (&n->out_tracker, 128);
384 if (0 == delay.rel_value_us)
385 {
386 n->is_ready = GNUNET_YES;
387 GNUNET_MQ_impl_send_continue (n->mq);
388 return;
389 }
390 GNUNET_MQ_impl_send_in_flight (n->mq);
391 /* cannot send even a small message without violating
392 quota, wait a before allowing MQ to send next message */
393 n->timeout_task =
394 GNUNET_SCHEDULER_add_delayed (delay, &notify_send_done_fin, n);
395}
396
397
398/**
399 * Implement sending functionality of a message queue.
400 * Called one message at a time. Should send the @a msg
401 * to the transport service and then notify the queue
402 * once we are ready for the next one.
403 *
404 * @param mq the message queue
405 * @param msg the message to send
406 * @param impl_state state of the implementation
407 */
408static void
409mq_send_impl (struct GNUNET_MQ_Handle *mq,
410 const struct GNUNET_MessageHeader *msg,
411 void *impl_state)
412{
413 struct Neighbour *n = impl_state;
414 struct GNUNET_TRANSPORT_CoreHandle *h = n->h;
415 struct OutboundMessage *obm;
416 uint16_t msize;
417
418 GNUNET_assert (GNUNET_YES == n->is_ready);
419 msize = ntohs (msg->size);
420 if (msize >= GNUNET_MAX_MESSAGE_SIZE - sizeof(*obm))
421 {
422 GNUNET_break (0);
423 GNUNET_MQ_impl_send_continue (mq);
424 return;
425 }
426 GNUNET_assert (NULL == n->env);
427 n->env =
428 GNUNET_MQ_msg_nested_mh (obm, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, msg);
429 {
430 struct GNUNET_MQ_Envelope *env;
431
432 env = GNUNET_MQ_get_current_envelope (mq);
433 obm->priority = htonl ((uint32_t) GNUNET_MQ_env_get_options (env));
434 }
435 obm->timeout = GNUNET_TIME_relative_hton (
436 GNUNET_TIME_UNIT_MINUTES); /* FIXME: to be removed */
437 obm->peer = n->id;
438 GNUNET_assert (NULL == n->timeout_task);
439 n->is_ready = GNUNET_NO;
440 n->env_size = ntohs (msg->size);
441 GNUNET_MQ_notify_sent (n->env, &notify_send_done, n);
442 GNUNET_MQ_send (h->mq, n->env);
443 LOG (GNUNET_ERROR_TYPE_DEBUG,
444 "Queued message of type %u for neighbour `%s'.\n",
445 ntohs (msg->type),
446 GNUNET_i2s (&n->id));
447}
448
449
450/**
451 * Handle destruction of a message queue. Implementations must not
452 * free @a mq, but should take care of @a impl_state.
453 *
454 * @param mq the message queue to destroy
455 * @param impl_state state of the implementation
456 */
457static void
458mq_destroy_impl (struct GNUNET_MQ_Handle *mq, void *impl_state)
459{
460 struct Neighbour *n = impl_state;
461
462 GNUNET_assert (mq == n->mq);
463 n->mq = NULL;
464}
465
466
467/**
468 * Implementation function that cancels the currently sent message.
469 * Should basically undo whatever #mq_send_impl() did.
470 *
471 * @param mq message queue
472 * @param impl_state state specific to the implementation
473 */
474static void
475mq_cancel_impl (struct GNUNET_MQ_Handle *mq, void *impl_state)
476{
477 struct Neighbour *n = impl_state;
478
479 GNUNET_assert (GNUNET_NO == n->is_ready);
480 if (NULL != n->env)
481 {
482 GNUNET_MQ_send_cancel (n->env);
483 n->env = NULL;
484 }
485
486 n->is_ready = GNUNET_YES;
487}
488
489
490/**
491 * We had an error processing a message we forwarded from a peer to
492 * the CORE service. We should just complain about it but otherwise
493 * continue processing.
494 *
495 * @param cls closure
496 * @param error error code
497 */
498static void
499peer_mq_error_handler (void *cls, enum GNUNET_MQ_Error error)
500{
501 /* struct Neighbour *n = cls; */
502
503 GNUNET_break_op (0);
504}
505
506
507/**
508 * The outbound quota has changed in a way that may require
509 * us to reset the timeout. Update the timeout.
510 *
511 * @param cls the `struct Neighbour` for which the timeout changed
512 */
513static void
514outbound_bw_tracker_update (void *cls)
515{
516 struct Neighbour *n = cls;
517 struct GNUNET_TIME_Relative delay;
518
519 if (NULL == n->timeout_task)
520 return;
521 delay = GNUNET_BANDWIDTH_tracker_get_delay (&n->out_tracker, 128);
522 GNUNET_SCHEDULER_cancel (n->timeout_task);
523 n->timeout_task = GNUNET_SCHEDULER_add_delayed (delay, &notify_send_done, n);
524}
525
526
527/**
528 * Function we use for handling incoming connect messages.
529 *
530 * @param cls closure, a `struct GNUNET_TRANSPORT_Handle *`
531 * @param cim message received
532 */
533static void
534handle_connect (void *cls, const struct ConnectInfoMessage *cim)
535{
536 struct GNUNET_TRANSPORT_CoreHandle *h = cls;
537 struct Neighbour *n;
538
539 LOG (GNUNET_ERROR_TYPE_DEBUG,
540 "Receiving CONNECT message for `%s' with quota %u\n",
541 GNUNET_i2s (&cim->id),
542 ntohl (cim->quota_out.value__));
543 n = neighbour_find (h, &cim->id);
544 if (NULL != n)
545 {
546 GNUNET_break (0); /* FIXME: this assertion seems to fail sometimes!? */
547 disconnect_and_schedule_reconnect (h);
548 return;
549 }
550 n = GNUNET_new (struct Neighbour);
551 n->id = cim->id;
552 n->h = h;
553 n->is_ready = GNUNET_YES;
554 n->traffic_overhead = 0;
555 GNUNET_BANDWIDTH_tracker_init2 (&n->out_tracker,
556 &outbound_bw_tracker_update,
557 n,
558 GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
559 MAX_BANDWIDTH_CARRY_S,
560 &notify_excess_cb,
561 n);
562 GNUNET_assert (GNUNET_OK ==
563 GNUNET_CONTAINER_multipeermap_put (
564 h->neighbours,
565 &n->id,
566 n,
567 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
568
569 GNUNET_BANDWIDTH_tracker_update_quota (&n->out_tracker, cim->quota_out);
570 n->mq = GNUNET_MQ_queue_for_callbacks (&mq_send_impl,
571 &mq_destroy_impl,
572 &mq_cancel_impl,
573 n,
574 h->handlers,
575 &peer_mq_error_handler,
576 n);
577 if (NULL != h->nc_cb)
578 {
579 n->handlers_cls = h->nc_cb (h->cls, &n->id, n->mq);
580 GNUNET_MQ_set_handlers_closure (n->mq, n->handlers_cls);
581 }
582}
583
584
585/**
586 * Function we use for handling incoming disconnect messages.
587 *
588 * @param cls closure, a `struct GNUNET_TRANSPORT_CoreHandle *`
589 * @param dim message received
590 */
591static void
592handle_disconnect (void *cls, const struct DisconnectInfoMessage *dim)
593{
594 struct GNUNET_TRANSPORT_CoreHandle *h = cls;
595 struct Neighbour *n;
596
597 GNUNET_break (ntohl (dim->reserved) == 0);
598 LOG (GNUNET_ERROR_TYPE_DEBUG,
599 "Receiving DISCONNECT message for `%s'.\n",
600 GNUNET_i2s (&dim->peer));
601 n = neighbour_find (h, &dim->peer);
602 if (NULL == n)
603 {
604 GNUNET_break (0);
605 disconnect_and_schedule_reconnect (h);
606 return;
607 }
608 GNUNET_assert (GNUNET_YES == neighbour_delete (h, &dim->peer, n));
609}
610
611
612/**
613 * Function we use for handling incoming send-ok messages.
614 *
615 * @param cls closure, a `struct GNUNET_TRANSPORT_CoreHandle *`
616 * @param okm message received
617 */
618static void
619handle_send_ok (void *cls, const struct SendOkMessage *okm)
620{
621 struct GNUNET_TRANSPORT_CoreHandle *h = cls;
622 struct Neighbour *n;
623 uint32_t bytes_msg;
624 uint32_t bytes_physical;
625 uint16_t success = ntohs (okm->success);
626
627 bytes_msg = ntohs (okm->bytes_msg);
628 bytes_physical = ntohl (okm->bytes_physical);
629 LOG (GNUNET_ERROR_TYPE_DEBUG,
630 "Receiving SEND_OK message, transmission to %s %s.\n",
631 GNUNET_i2s (&okm->peer),
632 success == GNUNET_OK ? "succeeded" : "failed");
633 n = neighbour_find (h, &okm->peer);
634 if (NULL == n)
635 {
636 /* We should never get a 'SEND_OK' for a peer that we are not
637 connected to */
638 GNUNET_break (0);
639 disconnect_and_schedule_reconnect (h);
640 return;
641 }
642 if (bytes_physical > bytes_msg)
643 {
644 LOG (GNUNET_ERROR_TYPE_DEBUG,
645 "Overhead for %u byte message was %u\n",
646 bytes_msg,
647 bytes_physical - bytes_msg);
648 n->traffic_overhead += bytes_physical - bytes_msg;
649 }
650}
651
652
653/**
654 * Function we use for checking incoming "inbound" messages.
655 *
656 * @param cls closure, a `struct GNUNET_TRANSPORT_CoreHandle *`
657 * @param im message received
658 */
659static int
660check_recv (void *cls, const struct InboundMessage *im)
661{
662 const struct GNUNET_MessageHeader *imm;
663 uint16_t size;
664
665 size = ntohs (im->header.size) - sizeof(*im);
666 if (size < sizeof(struct GNUNET_MessageHeader))
667 {
668 GNUNET_break (0);
669 return GNUNET_SYSERR;
670 }
671 imm = (const struct GNUNET_MessageHeader *) &im[1];
672 if (ntohs (imm->size) != size)
673 {
674 GNUNET_break (0);
675 return GNUNET_SYSERR;
676 }
677 return GNUNET_OK;
678}
679
680
681/**
682 * Function we use for handling incoming messages.
683 *
684 * @param cls closure, a `struct GNUNET_TRANSPORT_CoreHandle *`
685 * @param im message received
686 */
687static void
688handle_recv (void *cls, const struct InboundMessage *im)
689{
690 struct GNUNET_TRANSPORT_CoreHandle *h = cls;
691 const struct GNUNET_MessageHeader *imm =
692 (const struct GNUNET_MessageHeader *) &im[1];
693 struct Neighbour *n;
694
695 LOG (GNUNET_ERROR_TYPE_DEBUG,
696 "Received message of type %u with %u bytes from `%s'.\n",
697 (unsigned int) ntohs (imm->type),
698 (unsigned int) ntohs (imm->size),
699 GNUNET_i2s (&im->peer));
700 n = neighbour_find (h, &im->peer);
701 if (NULL == n)
702 {
703 GNUNET_break (0);
704 disconnect_and_schedule_reconnect (h);
705 return;
706 }
707 h->rom_pending++;
708 GNUNET_MQ_inject_message (n->mq, imm);
709}
710
711
712/**
713 * Function we use for handling incoming set quota messages.
714 *
715 * @param cls closure, a `struct GNUNET_TRANSPORT_CoreHandle *`
716 * @param qm message received
717 */
718static void
719handle_set_quota (void *cls, const struct QuotaSetMessage *qm)
720{
721 struct GNUNET_TRANSPORT_CoreHandle *h = cls;
722 struct Neighbour *n;
723
724 LOG (GNUNET_ERROR_TYPE_DEBUG,
725 "Receiving SET_QUOTA message for `%s' with quota %u\n",
726 GNUNET_i2s (&qm->peer),
727 ntohl (qm->quota.value__));
728 n = neighbour_find (h, &qm->peer);
729 if (NULL == n)
730 {
731 GNUNET_break (
732 0); /* FIXME: julius reports this assertion fails sometimes? */
733 disconnect_and_schedule_reconnect (h);
734 return;
735 }
736 GNUNET_BANDWIDTH_tracker_update_quota (&n->out_tracker, qm->quota);
737}
738
739
740/**
741 * Try again to connect to transport service.
742 *
743 * @param cls the handle to the transport service
744 */
745static void
746reconnect (void *cls)
747{
748 struct GNUNET_TRANSPORT_CoreHandle *h = cls;
749 struct GNUNET_MQ_MessageHandler handlers[] =
750 { GNUNET_MQ_hd_var_size (hello,
751 GNUNET_MESSAGE_TYPE_HELLO,
752 struct GNUNET_MessageHeader,
753 h),
754 GNUNET_MQ_hd_fixed_size (connect,
755 GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT,
756 struct ConnectInfoMessage,
757 h),
758 GNUNET_MQ_hd_fixed_size (disconnect,
759 GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT,
760 struct DisconnectInfoMessage,
761 h),
762 GNUNET_MQ_hd_fixed_size (send_ok,
763 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK,
764 struct SendOkMessage,
765 h),
766 GNUNET_MQ_hd_var_size (recv,
767 GNUNET_MESSAGE_TYPE_TRANSPORT_RECV,
768 struct InboundMessage,
769 h),
770 GNUNET_MQ_hd_fixed_size (set_quota,
771 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA,
772 struct QuotaSetMessage,
773 h),
774 GNUNET_MQ_handler_end () };
775 struct GNUNET_MQ_Envelope *env;
776 struct StartMessage *s;
777 uint32_t options;
778
779 h->reconnect_task = NULL;
780 LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to transport service.\n");
781 GNUNET_assert (NULL == h->mq);
782 h->mq =
783 GNUNET_CLIENT_connect (h->cfg, "transport", handlers, &mq_error_handler, h);
784 if (NULL == h->mq)
785 return;
786 env = GNUNET_MQ_msg (s, GNUNET_MESSAGE_TYPE_TRANSPORT_START);
787 options = 0;
788 if (h->check_self)
789 options |= 1;
790 if (NULL != h->handlers)
791 options |= 2;
792 s->options = htonl (options);
793 s->self = h->self;
794 GNUNET_MQ_send (h->mq, env);
795}
796
797
798/**
799 * Function that will schedule the job that will try
800 * to connect us again to the client.
801 *
802 * @param h transport service to reconnect
803 */
804static void
805disconnect_and_schedule_reconnect (struct GNUNET_TRANSPORT_CoreHandle *h)
806{
807 GNUNET_assert (NULL == h->reconnect_task);
808 /* Forget about all neighbours that we used to be connected to */
809 GNUNET_CONTAINER_multipeermap_iterate (h->neighbours, &neighbour_delete, h);
810 if (NULL != h->mq)
811 {
812 GNUNET_MQ_destroy (h->mq);
813 h->mq = NULL;
814 }
815 LOG (GNUNET_ERROR_TYPE_DEBUG,
816 "Scheduling task to reconnect to transport service in %s.\n",
817 GNUNET_STRINGS_relative_time_to_string (h->reconnect_delay, GNUNET_YES));
818 h->reconnect_task =
819 GNUNET_SCHEDULER_add_delayed (h->reconnect_delay, &reconnect, h);
820 h->reconnect_delay = GNUNET_TIME_STD_BACKOFF (h->reconnect_delay);
821}
822
823
824/**
825 * Checks if a given peer is connected to us and get the message queue.
826 *
827 * @param handle connection to transport service
828 * @param peer the peer to check
829 * @return NULL if disconnected, otherwise message queue for @a peer
830 */
831struct GNUNET_MQ_Handle *
832GNUNET_TRANSPORT_core_get_mq (struct GNUNET_TRANSPORT_CoreHandle *handle,
833 const struct GNUNET_PeerIdentity *peer)
834{
835 struct Neighbour *n;
836
837 n = neighbour_find (handle, peer);
838 if (NULL == n)
839 return NULL;
840 return n->mq;
841}
842
843
844/**
845 * Connect to the transport service. Note that the connection may
846 * complete (or fail) asynchronously.
847 *
848 * @param cfg configuration to use
849 * @param self our own identity (API should check that it matches
850 * the identity found by transport), or NULL (no check)
851 * @param cls closure for the callbacks
852 * @param rec receive function to call
853 * @param nc function to call on connect events
854 * @param nd function to call on disconnect events
855 * @param neb function to call if we have excess bandwidth to a peer
856 * @return NULL on error
857 */
858struct GNUNET_TRANSPORT_CoreHandle *
859GNUNET_TRANSPORT_core_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
860 const struct GNUNET_PeerIdentity *self,
861 const struct GNUNET_MQ_MessageHandler *handlers,
862 void *cls,
863 GNUNET_TRANSPORT_NotifyConnect nc,
864 GNUNET_TRANSPORT_NotifyDisconnect nd,
865 GNUNET_TRANSPORT_NotifyExcessBandwidth neb)
866{
867 struct GNUNET_TRANSPORT_CoreHandle *h;
868 unsigned int i;
869
870 h = GNUNET_new (struct GNUNET_TRANSPORT_CoreHandle);
871 if (NULL != self)
872 {
873 h->self = *self;
874 h->check_self = GNUNET_YES;
875 }
876 h->cfg = cfg;
877 h->cls = cls;
878 h->nc_cb = nc;
879 h->nd_cb = nd;
880 h->neb_cb = neb;
881 h->reconnect_delay = GNUNET_TIME_UNIT_ZERO;
882 if (NULL != handlers)
883 {
884 for (i = 0; NULL != handlers[i].cb; i++)
885 ;
886 h->handlers = GNUNET_new_array (i + 1, struct GNUNET_MQ_MessageHandler);
887 GNUNET_memcpy (h->handlers,
888 handlers,
889 i * sizeof(struct GNUNET_MQ_MessageHandler));
890 }
891 LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to transport service\n");
892 reconnect (h);
893 if (NULL == h->mq)
894 {
895 GNUNET_free (h->handlers);
896 GNUNET_free (h);
897 return NULL;
898 }
899 h->neighbours =
900 GNUNET_CONTAINER_multipeermap_create (STARTING_NEIGHBOURS_SIZE, GNUNET_YES);
901 return h;
902}
903
904
905/**
906 * Disconnect from the transport service.
907 *
908 * @param handle handle to the service as returned from
909 * #GNUNET_TRANSPORT_core_connect()
910 */
911void
912GNUNET_TRANSPORT_core_disconnect (struct GNUNET_TRANSPORT_CoreHandle *handle)
913{
914 LOG (GNUNET_ERROR_TYPE_DEBUG, "Transport disconnect called!\n");
915 /* this disconnects all neighbours... */
916 if (NULL == handle->reconnect_task)
917 disconnect_and_schedule_reconnect (handle);
918 /* and now we stop trying to connect again... */
919 if (NULL != handle->reconnect_task)
920 {
921 GNUNET_SCHEDULER_cancel (handle->reconnect_task);
922 handle->reconnect_task = NULL;
923 }
924 GNUNET_CONTAINER_multipeermap_destroy (handle->neighbours);
925 handle->neighbours = NULL;
926 GNUNET_free (handle->handlers);
927 handle->handlers = NULL;
928 GNUNET_free (handle);
929}
930
931
932/**
933 * Notification from the CORE service to the TRANSPORT service
934 * that the CORE service has finished processing a message from
935 * TRANSPORT (via the @code{handlers} of #GNUNET_TRANSPORT_core_connect())
936 * and that it is thus now OK for TRANSPORT to send more messages
937 * for @a pid.
938 *
939 * Used to provide flow control, this is our equivalent to
940 * #GNUNET_SERVICE_client_continue() of an ordinary service.
941 *
942 * Note that due to the use of a window, TRANSPORT may send multiple
943 * messages destined for the same peer even without an intermediate
944 * call to this function. However, CORE must still call this function
945 * once per message received, as otherwise eventually the window will
946 * be full and TRANSPORT will stop providing messages to CORE for @a
947 * pid.
948 *
949 * @param ch core handle
950 * @param pid which peer was the message from that was fully processed by CORE
951 */
952void
953GNUNET_TRANSPORT_core_receive_continue (struct GNUNET_TRANSPORT_CoreHandle *ch,
954 const struct GNUNET_PeerIdentity *pid)
955{
956 struct RecvOkMessage *rom;
957 struct GNUNET_MQ_Envelope *env;
958
959 GNUNET_assert (ch->rom_pending > 0);
960 ch->rom_pending--;
961 env = GNUNET_MQ_msg (rom, GNUNET_MESSAGE_TYPE_TRANSPORT_RECV_OK);
962 rom->increase_window_delta = htonl (1);
963 rom->peer = *pid;
964 GNUNET_MQ_send (ch->mq, env);
965}
966
967
968/* end of transport_api_core.c */
diff --git a/src/transport/transport_api_hello_get.c b/src/transport/transport_api_hello_get.c
deleted file mode 100644
index f8bcc5f07..000000000
--- a/src/transport/transport_api_hello_get.c
+++ /dev/null
@@ -1,274 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-2013, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/transport_api_hello_get.c
23 * @brief library to obtain our HELLO from our transport service
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_constants.h"
29#include "gnunet_arm_service.h"
30#include "gnunet_hello_lib.h"
31#include "gnunet_protocols.h"
32#include "gnunet_transport_hello_service.h"
33#include "transport.h"
34
35
36/**
37 * Functions to call with this peer's HELLO.
38 */
39struct GNUNET_TRANSPORT_HelloGetHandle
40{
41 /**
42 * Our configuration.
43 */
44 const struct GNUNET_CONFIGURATION_Handle *cfg;
45
46 /**
47 * Transport handle.
48 */
49 struct GNUNET_MQ_Handle *mq;
50
51 /**
52 * Callback to call once we got our HELLO.
53 */
54 GNUNET_TRANSPORT_HelloUpdateCallback rec;
55
56 /**
57 * Closure for @e rec.
58 */
59 void *rec_cls;
60
61 /**
62 * Task for calling the HelloUpdateCallback when we already have a HELLO
63 */
64 struct GNUNET_SCHEDULER_Task *notify_task;
65
66 /**
67 * ID of the task trying to reconnect to the service.
68 */
69 struct GNUNET_SCHEDULER_Task *reconnect_task;
70
71 /**
72 * Delay until we try to reconnect.
73 */
74 struct GNUNET_TIME_Relative reconnect_delay;
75
76 /**
77 * Type of HELLOs client cares about.
78 */
79 enum GNUNET_TRANSPORT_AddressClass ac;
80};
81
82
83/**
84 * Function we use for checking incoming HELLO messages.
85 *
86 * @param cls closure, a `struct GNUNET_TRANSPORT_Handle *`
87 * @param msg message received
88 * @return #GNUNET_OK if message is well-formed
89 */
90static int
91check_hello (void *cls,
92 const struct GNUNET_MessageHeader *msg)
93{
94 struct GNUNET_PeerIdentity me;
95
96 if (GNUNET_OK !=
97 GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *) msg,
98 &me))
99 {
100 GNUNET_break (0);
101 return GNUNET_SYSERR;
102 }
103 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
104 "Receiving (my own) HELLO message (%u bytes), I am `%s'.\n",
105 (unsigned int) ntohs (msg->size),
106 GNUNET_i2s (&me));
107 return GNUNET_OK;
108}
109
110
111/**
112 * Function we use for handling incoming HELLO messages.
113 *
114 * @param cls closure, a `struct GNUNET_TRANSPORT_HelloGetHandle *`
115 * @param msg message received
116 */
117static void
118handle_hello (void *cls,
119 const struct GNUNET_MessageHeader *msg)
120{
121 struct GNUNET_TRANSPORT_HelloGetHandle *ghh = cls;
122
123 ghh->rec (ghh->rec_cls,
124 msg);
125}
126
127
128/**
129 * Function that will schedule the job that will try
130 * to connect us again to the client.
131 *
132 * @param ghh transport service to reconnect
133 */
134static void
135schedule_reconnect (struct GNUNET_TRANSPORT_HelloGetHandle *ghh);
136
137
138/**
139 * Generic error handler, called with the appropriate
140 * error code and the same closure specified at the creation of
141 * the message queue.
142 * Not every message queue implementation supports an error handler.
143 *
144 * @param cls closure with the `struct GNUNET_TRANSPORT_Handle *`
145 * @param error error code
146 */
147static void
148mq_error_handler (void *cls,
149 enum GNUNET_MQ_Error error)
150{
151 struct GNUNET_TRANSPORT_HelloGetHandle *ghh = cls;
152
153 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
154 "Error receiving from transport service, disconnecting temporarily.\n");
155 GNUNET_MQ_destroy (ghh->mq);
156 ghh->mq = NULL;
157 schedule_reconnect (ghh);
158}
159
160
161/**
162 * Try again to connect to transport service.
163 *
164 * @param cls the handle to the transport service
165 */
166static void
167reconnect (void *cls)
168{
169 struct GNUNET_TRANSPORT_HelloGetHandle *ghh = cls;
170 struct GNUNET_MQ_MessageHandler handlers[] = {
171 GNUNET_MQ_hd_var_size (hello,
172 GNUNET_MESSAGE_TYPE_HELLO,
173 struct GNUNET_MessageHeader,
174 ghh),
175 GNUNET_MQ_handler_end ()
176 };
177 struct GNUNET_MQ_Envelope *env;
178 struct StartMessage *s;
179
180 ghh->reconnect_task = NULL;
181 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
182 "Connecting to transport service.\n");
183 GNUNET_assert (NULL == ghh->mq);
184 ghh->mq = GNUNET_CLIENT_connect (ghh->cfg,
185 "transport",
186 handlers,
187 &mq_error_handler,
188 ghh);
189 if (NULL == ghh->mq)
190 return;
191 env = GNUNET_MQ_msg (s,
192 GNUNET_MESSAGE_TYPE_TRANSPORT_START);
193 s->options = htonl (0);
194 GNUNET_MQ_send (ghh->mq,
195 env);
196}
197
198
199/**
200 * Function that will schedule the job that will try
201 * to connect us again to the client.
202 *
203 * @param ghh transport service to reconnect
204 */
205static void
206schedule_reconnect (struct GNUNET_TRANSPORT_HelloGetHandle *ghh)
207{
208 ghh->reconnect_task =
209 GNUNET_SCHEDULER_add_delayed (ghh->reconnect_delay,
210 &reconnect,
211 ghh);
212 ghh->reconnect_delay = GNUNET_TIME_STD_BACKOFF (ghh->reconnect_delay);
213}
214
215
216/**
217 * Obtain the HELLO message for this peer. The callback given in this function
218 * is never called synchronously.
219 *
220 * @param cfg configuration
221 * @param ac which network type should the addresses from the HELLO belong to?
222 * @param rec function to call with the HELLO, sender will be our peer
223 * identity; message and sender will be NULL on timeout
224 * (handshake with transport service pending/failed).
225 * cost estimate will be 0.
226 * @param rec_cls closure for @a rec
227 * @return handle to cancel the operation
228 */
229struct GNUNET_TRANSPORT_HelloGetHandle *
230GNUNET_TRANSPORT_hello_get (const struct GNUNET_CONFIGURATION_Handle *cfg,
231 enum GNUNET_TRANSPORT_AddressClass ac,
232 GNUNET_TRANSPORT_HelloUpdateCallback rec,
233 void *rec_cls)
234{
235 struct GNUNET_TRANSPORT_HelloGetHandle *ghh;
236
237 ghh = GNUNET_new (struct GNUNET_TRANSPORT_HelloGetHandle);
238 ghh->rec = rec;
239 ghh->rec_cls = rec_cls;
240 ghh->cfg = cfg;
241 ghh->ac = ac;
242 reconnect (ghh);
243 if (NULL == ghh->mq)
244 {
245 GNUNET_free (ghh);
246 return NULL;
247 }
248 return ghh;
249}
250
251
252/**
253 * Stop receiving updates about changes to our HELLO message.
254 *
255 * @param ghh handle to cancel
256 */
257void
258GNUNET_TRANSPORT_hello_get_cancel (struct GNUNET_TRANSPORT_HelloGetHandle *ghh)
259{
260 if (NULL != ghh->reconnect_task)
261 {
262 GNUNET_SCHEDULER_cancel (ghh->reconnect_task);
263 ghh->reconnect_task = NULL;
264 }
265 if (NULL != ghh->mq)
266 {
267 GNUNET_MQ_destroy (ghh->mq);
268 ghh->mq = NULL;
269 }
270 GNUNET_free (ghh);
271}
272
273
274/* end of transport_api_hello_get.c */
diff --git a/src/transport/transport_api_manipulation.c b/src/transport/transport_api_manipulation.c
deleted file mode 100644
index 4f4ccc4a0..000000000
--- a/src/transport/transport_api_manipulation.c
+++ /dev/null
@@ -1,249 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-2013, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/transport_api_manipulation.c
23 * @brief library to access the low-level P2P IO service
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_constants.h"
29#include "gnunet_arm_service.h"
30#include "gnunet_hello_lib.h"
31#include "gnunet_protocols.h"
32#include "gnunet_transport_service.h"
33#include "transport.h"
34
35#define LOG(kind, ...) GNUNET_log_from (kind, "transport-api", __VA_ARGS__)
36
37
38/**
39 * Handle for the transport service (includes all of the
40 * state for the transport service).
41 */
42struct GNUNET_TRANSPORT_ManipulationHandle
43{
44 /**
45 * My client connection to the transport service.
46 */
47 struct GNUNET_MQ_Handle *mq;
48
49 /**
50 * My configuration.
51 */
52 const struct GNUNET_CONFIGURATION_Handle *cfg;
53
54 /**
55 * ID of the task trying to reconnect to the service.
56 */
57 struct GNUNET_SCHEDULER_Task *reconnect_task;
58
59 /**
60 * Delay until we try to reconnect.
61 */
62 struct GNUNET_TIME_Relative reconnect_delay;
63
64 /**
65 * Reconnect in progress
66 */
67 int reconnecting;
68};
69
70
71/**
72 * Function that will schedule the job that will try
73 * to connect us again to the client.
74 *
75 * @param h transport service to reconnect
76 */
77static void
78disconnect_and_schedule_reconnect (struct
79 GNUNET_TRANSPORT_ManipulationHandle *h);
80
81
82/**
83 * Generic error handler, called with the appropriate
84 * error code and the same closure specified at the creation of
85 * the message queue.
86 * Not every message queue implementation supports an error handler.
87 *
88 * @param cls closure with the `struct GNUNET_TRANSPORT_ManipulationHandle *`
89 * @param error error code
90 */
91static void
92mq_error_handler (void *cls,
93 enum GNUNET_MQ_Error error)
94{
95 struct GNUNET_TRANSPORT_ManipulationHandle *h = cls;
96
97 LOG (GNUNET_ERROR_TYPE_DEBUG,
98 "Error receiving from transport service, disconnecting temporarily.\n");
99 h->reconnecting = GNUNET_YES;
100 disconnect_and_schedule_reconnect (h);
101}
102
103
104/**
105 * Try again to connect to transport service.
106 *
107 * @param cls the handle to the transport service
108 */
109static void
110reconnect (void *cls)
111{
112 struct GNUNET_TRANSPORT_ManipulationHandle *h = cls;
113 struct GNUNET_MQ_MessageHandler handlers[] = {
114 GNUNET_MQ_handler_end ()
115 };
116 struct GNUNET_MQ_Envelope *env;
117 struct StartMessage *s;
118
119 h->reconnect_task = NULL;
120 LOG (GNUNET_ERROR_TYPE_DEBUG,
121 "Connecting to transport service.\n");
122 GNUNET_assert (NULL == h->mq);
123 h->reconnecting = GNUNET_NO;
124 h->mq = GNUNET_CLIENT_connect (h->cfg,
125 "transport",
126 handlers,
127 &mq_error_handler,
128 h);
129 if (NULL == h->mq)
130 return;
131 env = GNUNET_MQ_msg (s,
132 GNUNET_MESSAGE_TYPE_TRANSPORT_START);
133 GNUNET_MQ_send (h->mq,
134 env);
135}
136
137
138/**
139 * Function that will schedule the job that will try
140 * to connect us again to the client.
141 *
142 * @param h transport service to reconnect
143 */
144static void
145disconnect_and_schedule_reconnect (struct
146 GNUNET_TRANSPORT_ManipulationHandle *h)
147{
148 GNUNET_assert (NULL == h->reconnect_task);
149 if (NULL != h->mq)
150 {
151 GNUNET_MQ_destroy (h->mq);
152 h->mq = NULL;
153 }
154 h->reconnect_task =
155 GNUNET_SCHEDULER_add_delayed (h->reconnect_delay,
156 &reconnect,
157 h);
158 h->reconnect_delay = GNUNET_TIME_STD_BACKOFF (h->reconnect_delay);
159}
160
161
162/**
163 * Set transport metrics for a peer and a direction.
164 *
165 * @param handle transport handle
166 * @param peer the peer to set the metric for
167 * @param prop the performance metrics to set
168 * @param delay_in inbound delay to introduce
169 * @param delay_out outbound delay to introduce
170 *
171 * Note: Delay restrictions in receiving direction will be enforced
172 * with one message delay.
173 */
174void
175GNUNET_TRANSPORT_manipulation_set (struct
176 GNUNET_TRANSPORT_ManipulationHandle *handle,
177 const struct GNUNET_PeerIdentity *peer,
178 const struct GNUNET_ATS_Properties *prop,
179 struct GNUNET_TIME_Relative delay_in,
180 struct GNUNET_TIME_Relative delay_out)
181{
182 struct GNUNET_MQ_Envelope *env;
183 struct TrafficMetricMessage *msg;
184
185 if (NULL == handle->mq)
186 return;
187 env = GNUNET_MQ_msg (msg,
188 GNUNET_MESSAGE_TYPE_TRANSPORT_TRAFFIC_METRIC);
189 msg->reserved = htonl (0);
190 msg->peer = *peer;
191 GNUNET_ATS_properties_hton (&msg->properties,
192 prop);
193 msg->delay_in = GNUNET_TIME_relative_hton (delay_in);
194 msg->delay_out = GNUNET_TIME_relative_hton (delay_out);
195 GNUNET_MQ_send (handle->mq,
196 env);
197}
198
199
200/**
201 * Connect to the transport service. Note that the connection may
202 * complete (or fail) asynchronously.
203 *
204 * @param cfg configuration to use
205 * @return NULL on error
206 */
207struct GNUNET_TRANSPORT_ManipulationHandle *
208GNUNET_TRANSPORT_manipulation_connect (const struct
209 GNUNET_CONFIGURATION_Handle *cfg)
210{
211 struct GNUNET_TRANSPORT_ManipulationHandle *h;
212
213 h = GNUNET_new (struct GNUNET_TRANSPORT_ManipulationHandle);
214 h->cfg = cfg;
215 LOG (GNUNET_ERROR_TYPE_DEBUG,
216 "Connecting to transport service.\n");
217 reconnect (h);
218 if (NULL == h->mq)
219 {
220 GNUNET_free (h);
221 return NULL;
222 }
223 return h;
224}
225
226
227/**
228 * Disconnect from the transport service.
229 *
230 * @param handle handle to the service as returned from #GNUNET_TRANSPORT_manipulation_connect()
231 */
232void
233GNUNET_TRANSPORT_manipulation_disconnect (struct
234 GNUNET_TRANSPORT_ManipulationHandle *
235 handle)
236{
237 if (NULL == handle->reconnect_task)
238 disconnect_and_schedule_reconnect (handle);
239 /* and now we stop trying to connect again... */
240 if (NULL != handle->reconnect_task)
241 {
242 GNUNET_SCHEDULER_cancel (handle->reconnect_task);
243 handle->reconnect_task = NULL;
244 }
245 GNUNET_free (handle);
246}
247
248
249/* end of transport_api_manipulation.c */
diff --git a/src/transport/transport_api_monitor_peers.c b/src/transport/transport_api_monitor_peers.c
deleted file mode 100644
index ef1dc6087..000000000
--- a/src/transport/transport_api_monitor_peers.c
+++ /dev/null
@@ -1,443 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-2014, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/transport_api_monitor_peers.c
23 * @brief montoring api for transport peer status
24 *
25 * This api provides the ability to query the transport service about
26 * the connection status of a specific or all peers.
27 *
28 * Calls back with information about peer(s) including address used, state and
29 * state timeout for peer requests.
30 */
31#include "platform.h"
32#include "gnunet_util_lib.h"
33#include "gnunet_arm_service.h"
34#include "gnunet_hello_lib.h"
35#include "gnunet_protocols.h"
36#include "gnunet_transport_service.h"
37#include "transport.h"
38
39/**
40 * Context for iterating validation entries.
41 */
42struct GNUNET_TRANSPORT_PeerMonitoringContext
43{
44 /**
45 * Function to call with the binary address.
46 */
47 GNUNET_TRANSPORT_PeerIterateCallback cb;
48
49 /**
50 * Closure for @e cb.
51 */
52 void *cb_cls;
53
54 /**
55 * Connection to the service.
56 */
57 struct GNUNET_MQ_Handle *mq;
58
59 /**
60 * Configuration we use.
61 */
62 const struct GNUNET_CONFIGURATION_Handle *cfg;
63
64 /**
65 * Backoff for reconnect.
66 */
67 struct GNUNET_TIME_Relative backoff;
68
69 /**
70 * Task ID for reconnect.
71 */
72 struct GNUNET_SCHEDULER_Task *reconnect_task;
73
74 /**
75 * Identity of the peer to monitor.
76 */
77 struct GNUNET_PeerIdentity peer;
78
79 /**
80 * Was this a one-shot request?
81 */
82 int one_shot;
83};
84
85
86/**
87 * Check if a state is defined as connected
88 *
89 * @param state the state value
90 * @return #GNUNET_YES or #GNUNET_NO
91 */
92int
93GNUNET_TRANSPORT_is_connected (enum GNUNET_TRANSPORT_PeerState state)
94{
95 switch (state)
96 {
97 case GNUNET_TRANSPORT_PS_NOT_CONNECTED:
98 case GNUNET_TRANSPORT_PS_INIT_ATS:
99 case GNUNET_TRANSPORT_PS_SYN_SENT:
100 case GNUNET_TRANSPORT_PS_SYN_RECV_ATS:
101 case GNUNET_TRANSPORT_PS_SYN_RECV_ACK:
102 return GNUNET_NO;
103
104 case GNUNET_TRANSPORT_PS_CONNECTED:
105 case GNUNET_TRANSPORT_PS_RECONNECT_ATS:
106 case GNUNET_TRANSPORT_PS_RECONNECT_SENT:
107 case GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT:
108 return GNUNET_YES;
109
110 case GNUNET_TRANSPORT_PS_DISCONNECT:
111 case GNUNET_TRANSPORT_PS_DISCONNECT_FINISHED:
112 return GNUNET_NO;
113
114 default:
115 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
116 "Unhandled state `%s'\n",
117 GNUNET_TRANSPORT_ps2s (state));
118 GNUNET_break (0);
119 break;
120 }
121 return GNUNET_SYSERR;
122}
123
124
125/**
126 * Convert peer state to human-readable string.
127 *
128 * @param state the state value
129 * @return corresponding string
130 */
131const char *
132GNUNET_TRANSPORT_ps2s (enum GNUNET_TRANSPORT_PeerState state)
133{
134 switch (state)
135 {
136 case GNUNET_TRANSPORT_PS_NOT_CONNECTED:
137 return "S_NOT_CONNECTED";
138
139 case GNUNET_TRANSPORT_PS_INIT_ATS:
140 return "S_INIT_ATS";
141
142 case GNUNET_TRANSPORT_PS_SYN_SENT:
143 return "S_SYN_SENT";
144
145 case GNUNET_TRANSPORT_PS_SYN_RECV_ATS:
146 return "S_SYN_RECV_ATS";
147
148 case GNUNET_TRANSPORT_PS_SYN_RECV_ACK:
149 return "S_SYN_RECV_ACK";
150
151 case GNUNET_TRANSPORT_PS_CONNECTED:
152 return "S_CONNECTED";
153
154 case GNUNET_TRANSPORT_PS_RECONNECT_ATS:
155 return "S_RECONNECT_ATS";
156
157 case GNUNET_TRANSPORT_PS_RECONNECT_SENT:
158 return "S_RECONNECT_SENT";
159
160 case GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT:
161 return "S_SWITCH_SYN_SENT";
162
163 case GNUNET_TRANSPORT_PS_DISCONNECT:
164 return "S_DISCONNECT";
165
166 case GNUNET_TRANSPORT_PS_DISCONNECT_FINISHED:
167 return "S_DISCONNECT_FINISHED";
168
169 default:
170 GNUNET_break (0);
171 return "UNDEFINED";
172 }
173}
174
175
176/**
177 * Task run to re-establish the connection.
178 *
179 * @param cls our `struct GNUNET_TRANSPORT_PeerMonitoringContext *`
180 */
181static void
182do_peer_connect (void *cls);
183
184
185/**
186 * Cut the existing connection and reconnect.
187 *
188 * @param pal_ctx our context
189 */
190static void
191reconnect_peer_ctx (struct GNUNET_TRANSPORT_PeerMonitoringContext *pal_ctx)
192{
193 GNUNET_assert (GNUNET_NO == pal_ctx->one_shot);
194 GNUNET_MQ_destroy (pal_ctx->mq);
195 pal_ctx->mq = NULL;
196 pal_ctx->cb (pal_ctx->cb_cls,
197 NULL,
198 NULL,
199 GNUNET_TRANSPORT_PS_NOT_CONNECTED,
200 GNUNET_TIME_UNIT_ZERO_ABS);
201 pal_ctx->backoff = GNUNET_TIME_STD_BACKOFF (pal_ctx->backoff);
202 pal_ctx->reconnect_task = GNUNET_SCHEDULER_add_delayed (pal_ctx->backoff,
203 &do_peer_connect,
204 pal_ctx);
205}
206
207
208/**
209 * Function called with responses from the service.
210 *
211 * @param cls our `struct GNUNET_TRANSPORT_PeerMonitoringContext *`
212 * @param msg message from service
213 */
214static void
215handle_response_end (void *cls,
216 const struct GNUNET_MessageHeader *msg)
217{
218 struct GNUNET_TRANSPORT_PeerMonitoringContext *pal_ctx = cls;
219
220 if (pal_ctx->one_shot)
221 {
222 /* iteration finished */
223 pal_ctx->cb (pal_ctx->cb_cls,
224 NULL,
225 NULL,
226 GNUNET_TRANSPORT_PS_NOT_CONNECTED,
227 GNUNET_TIME_UNIT_ZERO_ABS);
228 GNUNET_TRANSPORT_monitor_peers_cancel (pal_ctx);
229 return;
230 }
231 /* not quite what we expected, reconnect */
232 GNUNET_break (0);
233 reconnect_peer_ctx (pal_ctx);
234}
235
236
237/**
238 * Function called to check responses from the service.
239 *
240 * @param cls our `struct GNUNET_TRANSPORT_PeerMonitoringContext *`
241 * @param pir_msg message with the human-readable address
242 * @return #GNUNET_OK if @a pir_msg is well-formed
243 */
244static int
245check_response (void *cls,
246 const struct PeerIterateResponseMessage *pir_msg)
247{
248 uint16_t size = ntohs (pir_msg->header.size) - sizeof(*pir_msg);
249 size_t alen = ntohl (pir_msg->addrlen);
250 size_t tlen = ntohl (pir_msg->pluginlen);
251 const char *addr;
252 const char *transport_name;
253
254 if (size != tlen + alen)
255 {
256 GNUNET_break (0);
257 return GNUNET_SYSERR;
258 }
259 if ((0 == tlen) && (0 == alen))
260 return GNUNET_OK;
261 if (0 == tlen)
262 {
263 GNUNET_break (0); /* This must not happen: address without plugin */
264 return GNUNET_SYSERR;
265 }
266 addr = (const char *) &pir_msg[1];
267 transport_name = &addr[alen];
268 if (transport_name[tlen - 1] != '\0')
269 {
270 GNUNET_break (0);
271 return GNUNET_SYSERR;
272 }
273 return GNUNET_OK;
274}
275
276
277/**
278 * Function called with responses from the service.
279 *
280 * @param cls our `struct GNUNET_TRANSPORT_PeerMonitoringContext *`
281 * @param msg message with the human-readable address
282 */
283static void
284handle_response (void *cls,
285 const struct PeerIterateResponseMessage *pir_msg)
286{
287 struct GNUNET_TRANSPORT_PeerMonitoringContext *pal_ctx = cls;
288 struct GNUNET_HELLO_Address *address;
289 size_t alen = ntohl (pir_msg->addrlen);
290 size_t tlen = ntohl (pir_msg->pluginlen);
291 const char *addr;
292 const char *transport_name;
293
294 if ((0 == tlen) &&
295 (0 == alen))
296 {
297 /* No address available */
298 pal_ctx->cb (pal_ctx->cb_cls,
299 &pir_msg->peer,
300 NULL,
301 ntohl (pir_msg->state),
302 GNUNET_TIME_absolute_ntoh (pir_msg->state_timeout));
303 return;
304 }
305 addr = (const char *) &pir_msg[1];
306 transport_name = &addr[alen];
307
308 /* notify client */
309 address = GNUNET_HELLO_address_allocate (&pir_msg->peer,
310 transport_name,
311 addr,
312 alen,
313 ntohl (pir_msg->local_address_info));
314 pal_ctx->cb (pal_ctx->cb_cls,
315 &pir_msg->peer,
316 address,
317 ntohl (pir_msg->state),
318 GNUNET_TIME_absolute_ntoh (pir_msg->state_timeout));
319 GNUNET_HELLO_address_free (address);
320}
321
322
323/**
324 * Generic error handler, called with the appropriate error code and
325 * the same closure specified at the creation of the message queue.
326 * Not every message queue implementation supports an error handler.
327 *
328 * @param cls closure with the `struct GNUNET_TRANSPORT_PeerMonitoringContext *`
329 * @param error error code
330 */
331static void
332mq_error_handler (void *cls,
333 enum GNUNET_MQ_Error error)
334{
335 struct GNUNET_TRANSPORT_PeerMonitoringContext *pal_ctx = cls;
336
337 if (pal_ctx->one_shot)
338 {
339 /* Disconnect */
340 pal_ctx->cb (pal_ctx->cb_cls,
341 NULL,
342 NULL,
343 GNUNET_TRANSPORT_PS_NOT_CONNECTED,
344 GNUNET_TIME_UNIT_ZERO_ABS);
345 GNUNET_TRANSPORT_monitor_peers_cancel (pal_ctx);
346 return;
347 }
348 reconnect_peer_ctx (pal_ctx);
349}
350
351
352/**
353 * Task run to re-establish the connection.
354 *
355 * @param cls our `struct GNUNET_TRANSPORT_PeerMonitoringContext *`
356 */
357static void
358do_peer_connect (void *cls)
359{
360 struct GNUNET_TRANSPORT_PeerMonitoringContext *pal_ctx = cls;
361 struct GNUNET_MQ_MessageHandler handlers[] = {
362 GNUNET_MQ_hd_var_size (response,
363 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_RESPONSE,
364 struct PeerIterateResponseMessage,
365 pal_ctx),
366 GNUNET_MQ_hd_fixed_size (response_end,
367 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_RESPONSE_END,
368 struct GNUNET_MessageHeader,
369 pal_ctx),
370 GNUNET_MQ_handler_end ()
371 };
372 struct PeerMonitorMessage *msg;
373 struct GNUNET_MQ_Envelope *env;
374
375 pal_ctx->reconnect_task = NULL;
376 pal_ctx->mq = GNUNET_CLIENT_connect (pal_ctx->cfg,
377 "transport",
378 handlers,
379 &mq_error_handler,
380 pal_ctx);
381 if (NULL == pal_ctx->mq)
382 return;
383 env = GNUNET_MQ_msg (msg,
384 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_REQUEST);
385 msg->one_shot = htonl (pal_ctx->one_shot);
386 msg->peer = pal_ctx->peer;
387 GNUNET_MQ_send (pal_ctx->mq,
388 env);
389}
390
391
392struct GNUNET_TRANSPORT_PeerMonitoringContext *
393GNUNET_TRANSPORT_monitor_peers (const struct GNUNET_CONFIGURATION_Handle *cfg,
394 const struct GNUNET_PeerIdentity *peer,
395 int one_shot,
396 GNUNET_TRANSPORT_PeerIterateCallback
397 peer_callback,
398 void *peer_callback_cls)
399{
400 struct GNUNET_TRANSPORT_PeerMonitoringContext *pal_ctx
401 = GNUNET_new (struct GNUNET_TRANSPORT_PeerMonitoringContext);
402
403 pal_ctx->cb = peer_callback;
404 pal_ctx->cb_cls = peer_callback_cls;
405 pal_ctx->cfg = cfg;
406 if (NULL != peer)
407 pal_ctx->peer = *peer;
408 pal_ctx->one_shot = one_shot;
409 do_peer_connect (pal_ctx);
410 if (NULL == pal_ctx->mq)
411 {
412 GNUNET_free (pal_ctx);
413 return NULL;
414 }
415 return pal_ctx;
416}
417
418
419/**
420 * Cancel request to monitor peers
421 *
422 * @param pic handle for the request to cancel
423 */
424void
425GNUNET_TRANSPORT_monitor_peers_cancel (struct
426 GNUNET_TRANSPORT_PeerMonitoringContext *
427 pic)
428{
429 if (NULL != pic->mq)
430 {
431 GNUNET_MQ_destroy (pic->mq);
432 pic->mq = NULL;
433 }
434 if (NULL != pic->reconnect_task)
435 {
436 GNUNET_SCHEDULER_cancel (pic->reconnect_task);
437 pic->reconnect_task = NULL;
438 }
439 GNUNET_free (pic);
440}
441
442
443/* end of transport_api_monitor_peers.c */
diff --git a/src/transport/transport_api_monitor_plugins.c b/src/transport/transport_api_monitor_plugins.c
deleted file mode 100644
index 43a11442b..000000000
--- a/src/transport/transport_api_monitor_plugins.c
+++ /dev/null
@@ -1,463 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2014, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/transport_api_monitor_plugins.c
23 * @brief montoring api for transport plugin session status
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_arm_service.h"
29#include "gnunet_hello_lib.h"
30#include "gnunet_protocols.h"
31#include "gnunet_transport_service.h"
32#include "transport.h"
33
34
35/**
36 * Handle for a plugin session state monitor.
37 */
38struct GNUNET_TRANSPORT_PluginMonitor
39{
40 /**
41 * Connection to the service.
42 */
43 struct GNUNET_MQ_Handle *mq;
44
45 /**
46 * Our configuration.
47 */
48 const struct GNUNET_CONFIGURATION_Handle *cfg;
49
50 /**
51 * Callback to call.
52 */
53 GNUNET_TRANSPORT_SessionMonitorCallback cb;
54
55 /**
56 * Closure for @e cb
57 */
58 void *cb_cls;
59
60 /**
61 * Map of session_ids (reduced to 32-bits) to
62 * `struct GNUNET_TRANSPORT_PluginSession` objects.
63 */
64 struct GNUNET_CONTAINER_MultiHashMap32 *sessions;
65
66 /**
67 * Backoff for reconnect.
68 */
69 struct GNUNET_TIME_Relative backoff;
70
71 /**
72 * Task ID for reconnect.
73 */
74 struct GNUNET_SCHEDULER_Task *reconnect_task;
75};
76
77
78/**
79 * Abstract representation of a plugin's session.
80 * Corresponds to the `struct GNUNET_ATS_Session` within the TRANSPORT service.
81 */
82struct GNUNET_TRANSPORT_PluginSession
83{
84 /**
85 * Unique session identifier.
86 */
87 uint64_t session_id;
88
89 /**
90 * Location for the client to store "data".
91 */
92 void *client_ctx;
93};
94
95
96/**
97 * Task run to re-establish the connection.
98 *
99 * @param cls our `struct GNUNET_TRANSPORT_PluginMonitor *`
100 */
101static void
102do_plugin_connect (void *cls);
103
104
105/**
106 * Free the session entry and notify the callback about its demise.
107 *
108 * @param cls our `struct GNUNET_TRANSPORT_PluginMonitor`
109 * @param key key of the session in the map
110 * @param value the session to free
111 * @return #GNUNET_OK (continue to iterate)
112 */
113static int
114free_entry (void *cls,
115 uint32_t key,
116 void *value)
117{
118 struct GNUNET_TRANSPORT_PluginMonitor *pm = cls;
119 struct GNUNET_TRANSPORT_PluginSession *ps = value;
120
121 pm->cb (pm->cb_cls,
122 ps,
123 &ps->client_ctx,
124 NULL);
125 GNUNET_break (GNUNET_YES ==
126 GNUNET_CONTAINER_multihashmap32_remove (pm->sessions,
127 key,
128 ps));
129 GNUNET_break (NULL == ps->client_ctx);
130 GNUNET_free (ps);
131 return GNUNET_OK;
132}
133
134
135/**
136 * Cut the existing connection and reconnect.
137 *
138 * @param pm our context
139 */
140static void
141reconnect_plugin_ctx (struct GNUNET_TRANSPORT_PluginMonitor *pm)
142{
143 GNUNET_MQ_destroy (pm->mq);
144 pm->mq = NULL;
145 GNUNET_CONTAINER_multihashmap32_iterate (pm->sessions,
146 &free_entry,
147 pm);
148 pm->backoff = GNUNET_TIME_STD_BACKOFF (pm->backoff);
149 pm->reconnect_task = GNUNET_SCHEDULER_add_delayed (pm->backoff,
150 &do_plugin_connect,
151 pm);
152}
153
154
155/**
156 * Convert 64-bit session ID to 32-bit index for hash map.
157 *
158 * @param id 64-bit session ID
159 * @return 32-bit hash map index
160 */
161static uint32_t
162wrap_id (uint64_t id)
163{
164 return ((uint32_t) id) ^ ((uint32_t) (id >> 32));
165}
166
167
168/**
169 * Context for #locate_by_id().
170 */
171struct SearchContext
172{
173 /**
174 * Result.
175 */
176 struct GNUNET_TRANSPORT_PluginSession *ps;
177
178 /**
179 * ID to locate.
180 */
181 uint64_t session_id;
182};
183
184
185/**
186 * Locate a session entry.
187 *
188 * @param cls our `struct SearchContext`
189 * @param key key of the session in the map
190 * @param value a session
191 * @return #GNUNET_OK (continue to iterate), or #GNUNET_SYSERR (match found)
192 */
193static int
194locate_by_id (void *cls,
195 uint32_t key,
196 void *value)
197{
198 struct SearchContext *sc = cls;
199 struct GNUNET_TRANSPORT_PluginSession *ps = value;
200
201 if (sc->session_id == ps->session_id)
202 {
203 sc->ps = ps;
204 return GNUNET_SYSERR;
205 }
206 return GNUNET_OK;
207}
208
209
210/**
211 * Function called with responses from the service.
212 *
213 * @param cls our `struct GNUNET_TRANSPORT_PluginMonitor *`
214 * @param tpmm message with event data
215 * @return #GNUNET_Ok if message is well-formed
216 */
217static int
218check_event (void *cls,
219 const struct TransportPluginMonitorMessage *tpmm)
220{
221 const char *pname;
222 size_t pname_len;
223 size_t paddr_len;
224
225 pname = (const char *) &tpmm[1];
226 pname_len = ntohs (tpmm->plugin_name_len);
227 paddr_len = ntohs (tpmm->plugin_address_len);
228 if ((pname_len
229 + paddr_len
230 + sizeof(struct TransportPluginMonitorMessage) != ntohs (
231 tpmm->header.size)) ||
232 ((0 != pname_len) &&
233 ('\0' != pname[pname_len - 1])))
234 {
235 GNUNET_break (0);
236 return GNUNET_SYSERR;
237 }
238 return GNUNET_OK;
239}
240
241
242/**
243 * Function called with responses from the service.
244 *
245 * @param cls our `struct GNUNET_TRANSPORT_PluginMonitor *`
246 * @param tpmm message with event data
247 */
248static void
249handle_event (void *cls,
250 const struct TransportPluginMonitorMessage *tpmm)
251{
252 struct GNUNET_TRANSPORT_PluginMonitor *pm = cls;
253 struct GNUNET_TRANSPORT_PluginSession *ps;
254 const char *pname;
255 const void *paddr;
256 enum GNUNET_TRANSPORT_SessionState ss;
257 size_t pname_len;
258 size_t paddr_len;
259 struct GNUNET_TRANSPORT_SessionInfo info;
260 struct GNUNET_HELLO_Address addr;
261 struct SearchContext rv;
262
263 pname = (const char *) &tpmm[1];
264 pname_len = ntohs (tpmm->plugin_name_len);
265 paddr_len = ntohs (tpmm->plugin_address_len);
266 paddr = &pname[pname_len];
267 ps = NULL;
268 ss = (enum GNUNET_TRANSPORT_SessionState) ntohs (tpmm->session_state);
269 if (GNUNET_TRANSPORT_SS_INIT == ss)
270 {
271 ps = GNUNET_new (struct GNUNET_TRANSPORT_PluginSession);
272 ps->session_id = tpmm->session_id;
273 (void) GNUNET_CONTAINER_multihashmap32_put (pm->sessions,
274 wrap_id (tpmm->session_id),
275 ps,
276 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
277 }
278 else
279 {
280 rv.session_id = tpmm->session_id;
281 rv.ps = NULL;
282 (void) GNUNET_CONTAINER_multihashmap32_get_multiple (pm->sessions,
283 wrap_id (
284 tpmm->session_id),
285 &locate_by_id,
286 &rv);
287 ps = rv.ps;
288 if (NULL == ps)
289 {
290 GNUNET_break (0);
291 reconnect_plugin_ctx (pm);
292 return;
293 }
294 }
295 info.state = ss;
296 info.is_inbound = (int16_t) ntohs (tpmm->is_inbound);
297 info.num_msg_pending = ntohl (tpmm->msgs_pending);
298 info.num_bytes_pending = ntohl (tpmm->bytes_pending);
299 info.receive_delay = GNUNET_TIME_absolute_ntoh (tpmm->delay);
300 info.session_timeout = GNUNET_TIME_absolute_ntoh (tpmm->timeout);
301 info.address = &addr;
302 addr.peer = tpmm->peer;
303 addr.address = (0 == paddr_len) ? NULL : paddr;
304 addr.address_length = paddr_len;
305 addr.transport_name = (0 == pname_len) ? NULL : pname;
306 addr.local_info = GNUNET_HELLO_ADDRESS_INFO_NONE;
307 pm->cb (pm->cb_cls,
308 ps,
309 &ps->client_ctx,
310 &info);
311
312 if (GNUNET_TRANSPORT_SS_DONE == ss)
313 {
314 GNUNET_break (NULL == ps->client_ctx);
315 GNUNET_assert (GNUNET_YES ==
316 GNUNET_CONTAINER_multihashmap32_remove (pm->sessions,
317 wrap_id (
318 tpmm->session_id),
319 ps));
320 GNUNET_free (ps);
321 }
322}
323
324
325/**
326 * Function called with sync responses from the service.
327 *
328 * @param cls our `struct GNUNET_TRANSPORT_PluginMonitor *`
329 * @param msg message from the service
330 */
331static void
332handle_sync (void *cls,
333 const struct GNUNET_MessageHeader *msg)
334{
335 struct GNUNET_TRANSPORT_PluginMonitor *pm = cls;
336
337 /* we are in sync, notify callback */
338 pm->cb (pm->cb_cls,
339 NULL,
340 NULL,
341 NULL);
342}
343
344
345/**
346 * Generic error handler, called with the appropriate
347 * error code and the same closure specified at the creation of
348 * the message queue.
349 * Not every message queue implementation supports an error handler.
350 *
351 * @param cls closure with the `struct GNUNET_NSE_Handle *`
352 * @param error error code
353 */
354static void
355mq_error_handler (void *cls,
356 enum GNUNET_MQ_Error error)
357{
358 struct GNUNET_TRANSPORT_PluginMonitor *pm = cls;
359
360 reconnect_plugin_ctx (pm);
361}
362
363
364/**
365 * Task run to re-establish the connection.
366 *
367 * @param cls our `struct GNUNET_TRANSPORT_PluginMonitor *`
368 */
369static void
370do_plugin_connect (void *cls)
371{
372 struct GNUNET_TRANSPORT_PluginMonitor *pm = cls;
373 struct GNUNET_MQ_MessageHandler handlers[] = {
374 GNUNET_MQ_hd_var_size (event,
375 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PLUGIN_EVENT,
376 struct TransportPluginMonitorMessage,
377 pm),
378 GNUNET_MQ_hd_fixed_size (sync,
379 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PLUGIN_SYNC,
380 struct GNUNET_MessageHeader,
381 pm),
382 GNUNET_MQ_handler_end ()
383 };
384 struct GNUNET_MessageHeader *msg;
385 struct GNUNET_MQ_Envelope *env;
386
387 pm->reconnect_task = NULL;
388 pm->mq = GNUNET_CLIENT_connect (pm->cfg,
389 "transport",
390 handlers,
391 &mq_error_handler,
392 pm);
393 if (NULL == pm->mq)
394 return;
395 env = GNUNET_MQ_msg (msg,
396 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PLUGIN_START);
397 GNUNET_MQ_send (pm->mq,
398 env);
399}
400
401
402/**
403 * Install a plugin session state monitor callback. The callback
404 * will be notified whenever the session changes.
405 *
406 * @param cfg configuration to use
407 * @param cb callback to invoke on events
408 * @param cb_cls closure for @a cb
409 * @return NULL on error, otherwise handle for cancellation
410 */
411struct GNUNET_TRANSPORT_PluginMonitor *
412GNUNET_TRANSPORT_monitor_plugins (const struct GNUNET_CONFIGURATION_Handle *cfg,
413 GNUNET_TRANSPORT_SessionMonitorCallback cb,
414 void *cb_cls)
415{
416 struct GNUNET_TRANSPORT_PluginMonitor *pm;
417
418 pm = GNUNET_new (struct GNUNET_TRANSPORT_PluginMonitor);
419 pm->cb = cb;
420 pm->cb_cls = cb_cls;
421 pm->cfg = cfg;
422 do_plugin_connect (pm);
423 if (NULL == pm->mq)
424 {
425 GNUNET_free (pm);
426 return NULL;
427 }
428 pm->sessions = GNUNET_CONTAINER_multihashmap32_create (128);
429 return pm;
430}
431
432
433/**
434 * Cancel monitoring the plugin session state. The callback will
435 * be called once for each session that is up with the information
436 * #GNUNET_TRANSPORT_SS_FINI (even though the session may stay up;
437 * this is just to enable client-side cleanup).
438 *
439 * @param pm handle of the request that is to be cancelled
440 */
441void
442GNUNET_TRANSPORT_monitor_plugins_cancel (struct
443 GNUNET_TRANSPORT_PluginMonitor *pm)
444{
445 if (NULL != pm->mq)
446 {
447 GNUNET_MQ_destroy (pm->mq);
448 pm->mq = NULL;
449 }
450 if (NULL != pm->reconnect_task)
451 {
452 GNUNET_SCHEDULER_cancel (pm->reconnect_task);
453 pm->reconnect_task = NULL;
454 }
455 GNUNET_CONTAINER_multihashmap32_iterate (pm->sessions,
456 &free_entry,
457 pm);
458 GNUNET_CONTAINER_multihashmap32_destroy (pm->sessions);
459 GNUNET_free (pm);
460}
461
462
463/* end of transport_api_monitor_plugins.c */
diff --git a/src/transport/transport_api_offer_hello.c b/src/transport/transport_api_offer_hello.c
deleted file mode 100644
index 1b611aa6b..000000000
--- a/src/transport/transport_api_offer_hello.c
+++ /dev/null
@@ -1,137 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-2013, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/transport_api_offer_hello.c
23 * @brief library to offer HELLOs to transport service
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_hello_lib.h"
29#include "gnunet_protocols.h"
30#include "gnunet_transport_service.h"
31
32
33/**
34 * Entry in linked list for all offer-HELLO requests.
35 */
36struct GNUNET_TRANSPORT_OfferHelloHandle
37{
38 /**
39 * Transport service handle we use for transmission.
40 */
41 struct GNUNET_MQ_Handle *mq;
42
43 /**
44 * Function to call once we are done.
45 */
46 GNUNET_SCHEDULER_TaskCallback cont;
47
48 /**
49 * Closure for @e cont
50 */
51 void *cls;
52};
53
54
55/**
56 * Done sending HELLO message to the service, notify application.
57 *
58 * @param cls the handle for the operation
59 */
60static void
61finished_hello (void *cls)
62{
63 struct GNUNET_TRANSPORT_OfferHelloHandle *ohh = cls;
64
65 if (NULL != ohh->cont)
66 ohh->cont (ohh->cls);
67 GNUNET_TRANSPORT_offer_hello_cancel (ohh);
68}
69
70
71/**
72 * Offer the transport service the HELLO of another peer. Note that
73 * the transport service may just ignore this message if the HELLO is
74 * malformed or useless due to our local configuration.
75 *
76 * @param cfg configuration
77 * @param hello the hello message
78 * @param cont continuation to call when HELLO has been sent,
79 * tc reason #GNUNET_SCHEDULER_REASON_TIMEOUT for fail
80 * tc reasong #GNUNET_SCHEDULER_REASON_READ_READY for success
81 * @param cont_cls closure for @a cont
82 * @return a `struct GNUNET_TRANSPORT_OfferHelloHandle` handle or NULL on failure,
83 * in case of failure @a cont will not be called
84 *
85 */
86struct GNUNET_TRANSPORT_OfferHelloHandle *
87GNUNET_TRANSPORT_offer_hello (const struct GNUNET_CONFIGURATION_Handle *cfg,
88 const struct GNUNET_MessageHeader *hello,
89 GNUNET_SCHEDULER_TaskCallback cont,
90 void *cont_cls)
91{
92 struct GNUNET_TRANSPORT_OfferHelloHandle *ohh
93 = GNUNET_new (struct GNUNET_TRANSPORT_OfferHelloHandle);
94 struct GNUNET_MQ_Envelope *env;
95 struct GNUNET_PeerIdentity peer;
96
97 if (GNUNET_OK !=
98 GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *) hello,
99 &peer))
100 {
101 GNUNET_break (0);
102 GNUNET_free (ohh);
103 return NULL;
104 }
105 ohh->mq = GNUNET_CLIENT_connect (cfg,
106 "transport",
107 NULL,
108 NULL,
109 ohh);
110 if (NULL == ohh->mq)
111 {
112 GNUNET_free (ohh);
113 return NULL;
114 }
115 ohh->cont = cont;
116 ohh->cls = cont_cls;
117 GNUNET_break (ntohs (hello->type) == GNUNET_MESSAGE_TYPE_HELLO);
118 env = GNUNET_MQ_msg_copy (hello);
119 GNUNET_MQ_notify_sent (env,
120 &finished_hello,
121 ohh);
122 GNUNET_MQ_send (ohh->mq,
123 env);
124 return ohh;
125}
126
127
128void
129GNUNET_TRANSPORT_offer_hello_cancel (struct
130 GNUNET_TRANSPORT_OfferHelloHandle *ohh)
131{
132 GNUNET_MQ_destroy (ohh->mq);
133 GNUNET_free (ohh);
134}
135
136
137/* end of transport_api_offer_hello.c */
diff --git a/src/util/container_multihashmap32.c b/src/util/container_multihashmap32.c
index 698e08e3a..3b4c92426 100644
--- a/src/util/container_multihashmap32.c
+++ b/src/util/container_multihashmap32.c
@@ -26,7 +26,6 @@
26 */ 26 */
27 27
28 28
29#include "gnunet_common.h"
30#include "platform.h" 29#include "platform.h"
31#include "gnunet_util_lib.h" 30#include "gnunet_util_lib.h"
32 31