aboutsummaryrefslogtreecommitdiff
path: root/src/transport
diff options
context:
space:
mode:
Diffstat (limited to 'src/transport')
-rw-r--r--src/transport/.gitignore93
-rw-r--r--src/transport/Makefile.am1653
-rw-r--r--src/transport/NOTES46
-rwxr-xr-xsrc/transport/benchmark.sh13
-rw-r--r--src/transport/communicator-unix.conf2
-rw-r--r--src/transport/communicator.h138
-rw-r--r--src/transport/gnunet-communicator-tcp.c3686
-rw-r--r--src/transport/gnunet-communicator-udp.c3953
-rw-r--r--src/transport/gnunet-communicator-unix.c1167
-rw-r--r--src/transport/gnunet-helper-transport-bluetooth.c2285
-rw-r--r--src/transport/gnunet-helper-transport-wlan-dummy.c520
-rw-r--r--src/transport/gnunet-helper-transport-wlan.c2184
-rw-r--r--src/transport/gnunet-service-tng.c11149
-rw-r--r--src/transport/gnunet-service-transport.c2783
-rw-r--r--src/transport/gnunet-service-transport.h234
-rw-r--r--src/transport/gnunet-service-transport_ats.c920
-rw-r--r--src/transport/gnunet-service-transport_ats.h204
-rw-r--r--src/transport/gnunet-service-transport_hello.c368
-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.c3971
-rw-r--r--src/transport/gnunet-service-transport_neighbours.h321
-rw-r--r--src/transport/gnunet-service-transport_plugins.c456
-rw-r--r--src/transport/gnunet-service-transport_plugins.h111
-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-certificate-creation.in158
-rw-r--r--src/transport/gnunet-transport-profiler.c625
-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/gnunet-transport.c1437
-rw-r--r--src/transport/ieee80211_radiotap.h276
-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.c2529
-rw-r--r--src/transport/plugin_transport_http_common.c948
-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.c2404
-rw-r--r--src/transport/plugin_transport_wlan.h276
-rwxr-xr-xsrc/transport/profile_transport.sh18
-rw-r--r--src/transport/tcp_connection_legacy.c1597
-rw-r--r--src/transport/tcp_server_legacy.c1748
-rw-r--r--src/transport/tcp_server_mst_legacy.c307
-rw-r--r--src/transport/tcp_service_legacy.c1646
-rw-r--r--src/transport/template_cfg_peer1.conf50
-rw-r--r--src/transport/template_cfg_peer2.conf58
-rw-r--r--src/transport/test_communicator_basic.c1203
-rw-r--r--src/transport/test_communicator_tcp_basic_peer1.conf48
-rw-r--r--src/transport/test_communicator_tcp_basic_peer2.conf44
-rw-r--r--src/transport/test_communicator_tcp_bidirect_peer1.conf48
-rw-r--r--src/transport/test_communicator_tcp_bidirect_peer2.conf44
-rw-r--r--src/transport/test_communicator_tcp_rekey_peer1.conf45
-rw-r--r--src/transport/test_communicator_tcp_rekey_peer2.conf45
-rw-r--r--src/transport/test_communicator_udp_backchannel_peer1.conf48
-rw-r--r--src/transport/test_communicator_udp_backchannel_peer2.conf48
-rw-r--r--src/transport/test_communicator_udp_basic_peer1.conf38
-rw-r--r--src/transport/test_communicator_udp_basic_peer2.conf39
-rw-r--r--src/transport/test_communicator_udp_rekey_peer1.conf51
-rw-r--r--src/transport/test_communicator_udp_rekey_peer2.conf51
-rw-r--r--src/transport/test_communicator_unix_basic_peer1.conf43
-rw-r--r--src/transport/test_communicator_unix_basic_peer2.conf43
-rwxr-xr-xsrc/transport/test_delay19
-rw-r--r--src/transport/test_http_common.c266
-rw-r--r--src/transport/test_plugin_hostkeybin915 -> 0 bytes
-rw-r--r--src/transport/test_plugin_hostkey.ecc1
-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.c433
-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_address_switch_tcp_peer1.conf48
-rw-r--r--src/transport/test_transport_address_switch_tcp_peer2.conf48
-rw-r--r--src/transport/test_transport_address_switch_udp_peer1.conf48
-rw-r--r--src/transport/test_transport_address_switch_udp_peer2.conf48
-rw-r--r--src/transport/test_transport_api.c126
-rw-r--r--src/transport/test_transport_api2.c126
-rw-r--r--src/transport/test_transport_api2_tcp_node1.conf32
-rw-r--r--src/transport/test_transport_api2_tcp_node2.conf22
-rw-r--r--src/transport/test_transport_api2_tcp_peer1.conf23
-rw-r--r--src/transport/test_transport_api2_tcp_peer2.conf22
-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_data.conf9
-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_monitor_peers.c226
-rw-r--r--src/transport/test_transport_api_monitor_peers_peer1.conf4
-rw-r--r--src/transport/test_transport_api_monitor_peers_peer2.conf5
-rw-r--r--src/transport/test_transport_api_monitor_validation_peer1.conf6
-rw-r--r--src/transport/test_transport_api_monitor_validation_peer2.conf7
-rw-r--r--src/transport/test_transport_api_multi_peer1.conf7
-rw-r--r--src/transport/test_transport_api_multi_peer2.conf9
-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_tcp_nat_peer1.conf34
-rw-r--r--src/transport/test_transport_api_tcp_nat_peer2.conf32
-rw-r--r--src/transport/test_transport_api_tcp_peer1.conf9
-rw-r--r--src/transport/test_transport_api_tcp_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_udp_nat_peer1.conf34
-rw-r--r--src/transport/test_transport_api_udp_nat_peer2.conf32
-rw-r--r--src/transport/test_transport_api_udp_peer1.conf17
-rw-r--r--src/transport/test_transport_api_udp_peer2.conf15
-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_unix_peer1.conf10
-rw-r--r--src/transport/test_transport_api_unix_peer2.conf7
-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_defaults.conf20
-rw-r--r--src/transport/test_transport_distance_vector_circle_topo.conf12
-rw-r--r--src/transport/test_transport_distance_vector_topo.conf8
-rw-r--r--src/transport/test_transport_plugin_cmd_simple_send.c369
-rw-r--r--src/transport/test_transport_plugin_cmd_simple_send_broadcast.c398
-rw-r--r--src/transport/test_transport_plugin_cmd_simple_send_dv.c427
-rw-r--r--src/transport/test_transport_plugin_cmd_udp_backchannel.c356
-rwxr-xr-xsrc/transport/test_transport_simple_send.sh11
-rwxr-xr-xsrc/transport/test_transport_simple_send_broadcast.sh11
-rw-r--r--src/transport/test_transport_simple_send_broadcast_topo.conf4
-rwxr-xr-xsrc/transport/test_transport_simple_send_dv.sh11
-rwxr-xr-xsrc/transport/test_transport_simple_send_dv_circle.sh11
-rwxr-xr-xsrc/transport/test_transport_simple_send_string.sh21
-rw-r--r--src/transport/test_transport_simple_send_topo.conf6
-rw-r--r--src/transport/test_transport_start_with_config.c122
-rw-r--r--src/transport/test_transport_test_transport_address_switch_tcp_peer1.conf29
-rw-r--r--src/transport/test_transport_test_transport_address_switch_tcp_peer2.conf29
-rw-r--r--src/transport/test_transport_testing_restart.c163
-rw-r--r--src/transport/test_transport_testing_startstop.c138
-rwxr-xr-xsrc/transport/test_transport_udp_backchannel.sh14
-rw-r--r--src/transport/test_transport_udp_backchannel_topo.conf7
-rw-r--r--src/transport/transport-testing-cmds.h347
-rw-r--r--src/transport/transport-testing-communicator.c1227
-rw-r--r--src/transport/transport-testing-communicator.h360
-rw-r--r--src/transport/transport-testing-filenames.c202
-rw-r--r--src/transport/transport-testing-filenames2.c202
-rw-r--r--src/transport/transport-testing-loggers.c80
-rw-r--r--src/transport/transport-testing-loggers2.c80
-rw-r--r--src/transport/transport-testing-main.c613
-rw-r--r--src/transport/transport-testing-main2.c613
-rw-r--r--src/transport/transport-testing-send.c240
-rw-r--r--src/transport/transport-testing-send2.c240
-rw-r--r--src/transport/transport-testing.c931
-rw-r--r--src/transport/transport-testing.h914
-rw-r--r--src/transport/transport-testing2.c961
-rw-r--r--src/transport/transport-testing2.h924
-rw-r--r--src/transport/transport.conf.in237
-rw-r--r--src/transport/transport.h1241
-rw-r--r--src/transport/transport_api2_application.c397
-rw-r--r--src/transport/transport_api2_communication.c1165
-rw-r--r--src/transport/transport_api2_core.c804
-rw-r--r--src/transport/transport_api2_monitor.c292
-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_cmd_backchannel_check.c602
-rw-r--r--src/transport/transport_api_cmd_connecting_peers.c265
-rw-r--r--src/transport/transport_api_cmd_send_simple.c212
-rw-r--r--src/transport/transport_api_cmd_start_peer.c491
-rw-r--r--src/transport/transport_api_cmd_stop_peer.c156
-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.c469
-rw-r--r--src/transport/transport_api_monitor_plugins.c463
-rw-r--r--src/transport/transport_api_offer_hello.c142
-rw-r--r--src/transport/transport_api_traits.c32
291 files changed, 0 insertions, 99249 deletions
diff --git a/src/transport/.gitignore b/src/transport/.gitignore
deleted file mode 100644
index 5a82a787b..000000000
--- a/src/transport/.gitignore
+++ /dev/null
@@ -1,93 +0,0 @@
1gnunet-transport-wlan-sender
2gnunet-helper-transport-bluetooth
3gnunet-helper-transport-wlan
4gnunet-helper-transport-wlan-dummy
5gnunet-service-transport
6gnunet-transport
7gnunet-transport-certificate-creation
8gnunet-transport-profiler
9gnunet-transport-wlan-receiver
10https_cert_qutoa_p2.crt
11https_key_quota_p2.key
12test_http_common
13test_plugin_bluetooth
14test_plugin_http_client
15test_plugin_http_server
16test_plugin_https_client
17test_plugin_https_server
18test_plugin_tcp
19test_plugin_udp
20test_plugin_unix
21test_plugin_wlan
22test_quota_compliance_bluetooth
23test_quota_compliance_bluetooth_asymmetric
24test_quota_compliance_http
25test_quota_compliance_http_asymmetric
26test_quota_compliance_https
27test_quota_compliance_https_asymmetric
28test_quota_compliance_tcp
29test_quota_compliance_tcp_asymmetric
30test_quota_compliance_udp
31test_quota_compliance_unix
32test_quota_compliance_unix_asymmetric
33test_quota_compliance_wlan
34test_quota_compliance_wlan_asymmetric
35test_transport_address_switch_http
36test_transport_address_switch_https
37test_transport_address_switch_tcp
38test_transport_address_switch_udp
39test_transport_api_blacklisting_tcp
40test_transport_api_bluetooth
41test_transport_api_disconnect_tcp
42test_transport_api_http
43test_transport_api_http_reverse
44test_transport_api_https
45test_transport_api_limited_sockets_tcp
46test_transport_api_manipulation_cfg
47test_transport_api_manipulation_recv_tcp
48test_transport_api_manipulation_send_tcp
49test_transport_api_monitor_peers
50test_transport_api_multi
51test_transport_api_reliability_bluetooth
52test_transport_api_reliability_http
53test_transport_api_reliability_http_xhr
54test_transport_api_reliability_https
55test_transport_api_reliability_https_xhr
56test_transport_api_reliability_tcp
57test_transport_api_reliability_tcp_nat
58test_transport_api_reliability_udp
59test_transport_api_reliability_unix
60test_transport_api_reliability_wlan
61test_transport_api_restart_1peer
62test_transport_api_restart_2peers
63test_transport_api_slow_ats
64test_transport_api_tcp
65test_transport_api_tcp_nat
66test_transport_api_timeout_bluetooth
67test_transport_api_timeout_http
68test_transport_api_timeout_https
69test_transport_api_timeout_tcp
70test_transport_api_timeout_udp
71test_transport_api_timeout_unix
72test_transport_api_timeout_wlan
73test_transport_api_udp
74test_transport_api_udp_nat
75test_transport_api_unix
76test_transport_api_unix_abstract
77test_transport_api_wlan
78test_transport_blacklisting_inbound_bl_full
79test_transport_blacklisting_inbound_bl_plugin
80test_transport_blacklisting_multiple_plugins
81test_transport_blacklisting_no_bl
82test_transport_blacklisting_outbound_bl_full
83test_transport_blacklisting_outbound_bl_plugin
84test_transport_testing_restart
85test_transport_testing_startstop
86gnunet-communicator-unix
87gnunet-service-tng
88gnunet-communicator-tcp
89gnunet-communicator-udp
90test_communicator_unix
91test_communicator_basic_unix
92test_transport_start_with_config
93test_transport_api2_tcp
diff --git a/src/transport/Makefile.am b/src/transport/Makefile.am
deleted file mode 100644
index a4971ff2c..000000000
--- a/src/transport/Makefile.am
+++ /dev/null
@@ -1,1653 +0,0 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include -I$(top_builddir)/src/include
3
4plugindir = $(libdir)/gnunet
5
6pkgcfgdir= $(pkgdatadir)/config.d/
7
8libexecdir= $(pkglibdir)/libexec/
9
10pkgcfg_DATA = \
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
42if USE_COVERAGE
43 AM_CFLAGS = --coverage -O0
44endif
45
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 = \
91 test_transport_start_with_config \
92 gnunet-transport-profiler \
93 gnunet-communicator-udp \
94 $(WLAN_BIN_SENDER) \
95 $(WLAN_BIN_RECEIVER)
96
97TESTING_LIBS = \
98 libgnunettransporttesting.la \
99 libgnunettransporttesting2.la
100
101lib_LTLIBRARIES = \
102 libgnunettransport.la \
103 libgnunettransportapplication.la \
104 libgnunettransportcore.la \
105 libgnunettransportcommunicator.la \
106 libgnunettransportmonitor.la \
107 $(TESTING_LIBS)
108
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 = \
127 transport_api_traits.c \
128 transport_api_cmd_connecting_peers.c \
129 transport_api_cmd_backchannel_check.c \
130 transport_api_cmd_start_peer.c \
131 transport_api_cmd_stop_peer.c \
132 transport_api_cmd_send_simple.c \
133 transport-testing2.c transport-testing2.h \
134 transport-testing-cmds.h \
135 transport-testing-filenames2.c \
136 transport-testing-loggers2.c \
137 transport-testing-main2.c \
138 transport-testing-send2.c \
139 transport-testing-communicator.c transport-testing-communicator.h
140libgnunettransporttesting2_la_LIBADD = \
141 libgnunettransportapplication.la \
142 libgnunettransportcore.la \
143 $(top_builddir)/src/arm/libgnunetarm.la \
144 $(top_builddir)/src/testing/libgnunettesting.la \
145 $(top_builddir)/src/ats/libgnunetats.la \
146 $(top_builddir)/src/hello/libgnunethello.la \
147 $(top_builddir)/src/peerstore/libgnunetpeerstore.la \
148 $(top_builddir)/src/util/libgnunetutil.la
149libgnunettransporttesting2_la_LDFLAGS = \
150 $(GN_LIBINTL) \
151 $(GN_LIB_LDFLAGS) \
152 -version-info 0:0:0
153
154libgnunettransport_la_SOURCES = \
155 transport.h \
156 transport_api_address_to_string.c \
157 transport_api_blacklist.c \
158 transport_api_core.c \
159 transport_api_hello_get.c \
160 transport_api_manipulation.c \
161 transport_api_monitor_peers.c \
162 transport_api_monitor_plugins.c \
163 transport_api_offer_hello.c
164
165libgnunettransport_la_LIBADD = \
166 $(top_builddir)/src/hello/libgnunethello.la \
167 $(top_builddir)/src/ats/libgnunetats.la \
168 $(top_builddir)/src/util/libgnunetutil.la \
169 $(GN_LIBINTL)
170libgnunettransport_la_LDFLAGS = \
171 $(GN_LIB_LDFLAGS) \
172 -version-info 4:0:2
173
174libgnunettransportapplication_la_SOURCES = \
175 transport_api2_application.c
176libgnunettransportapplication_la_LIBADD = \
177 $(top_builddir)/src/util/libgnunetutil.la \
178 $(LTLIBINTL)
179libgnunettransportapplication_la_LDFLAGS = \
180 $(GN_LIB_LDFLAGS) \
181 -version-info 0:0:0
182
183
184libgnunettransportcore_la_SOURCES = \
185 transport_api2_core.c
186libgnunettransportcore_la_LIBADD = \
187 $(top_builddir)/src/util/libgnunetutil.la \
188 $(GN_LIBINTL)
189libgnunettransportcore_la_LDFLAGS = \
190 $(GN_LIB_LDFLAGS) \
191 -version-info 0:0:0
192
193libgnunettransportcommunicator_la_SOURCES = \
194 transport_api2_communication.c
195libgnunettransportcommunicator_la_LIBADD = \
196 $(top_builddir)/src/util/libgnunetutil.la \
197 $(GN_LIBINTL)
198libgnunettransportcommunicator_la_LDFLAGS = \
199 $(GN_LIB_LDFLAGS) \
200 -version-info 0:0:0
201
202
203libgnunettransportmonitor_la_SOURCES = \
204 transport_api2_monitor.c
205libgnunettransportmonitor_la_LIBADD = \
206 $(top_builddir)/src/util/libgnunetutil.la \
207 $(GN_LIBINTL)
208libgnunettransportmonitor_la_LDFLAGS = \
209 $(GN_LIB_LDFLAGS) \
210 -version-info 0:0:0
211
212
213libexec_PROGRAMS = \
214 $(WLAN_BIN) \
215 $(WLAN_BIN_DUMMY) \
216 $(BT_BIN) \
217 gnunet-service-transport \
218 gnunet-service-tng \
219 gnunet-communicator-unix \
220 gnunet-communicator-udp \
221 gnunet-communicator-tcp
222
223
224
225bin_PROGRAMS = \
226 gnunet-transport
227
228bin_SCRIPTS = \
229 gnunet-transport-certificate-creation
230
231# See: https://www.gnu.org/software/automake/manual/html_node/Scripts.html#Scripts
232do_subst = sed -e 's,[@]pkgdatadir[@],$(pkgdatadir),g'
233
234
235gnunet-transport-certificate-creation: gnunet-transport-certificate-creation.in Makefile
236 $(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)/gnunet-transport-certificate-creation.in > gnunet-transport-certificate-creation
237 @chmod +x gnunet-transport-certificate-creation
238
239
240
241
242gnunet_communicator_unix_SOURCES = \
243 gnunet-communicator-unix.c
244gnunet_communicator_unix_LDADD = \
245 libgnunettransportcommunicator.la \
246 $(top_builddir)/src/statistics/libgnunetstatistics.la \
247 $(top_builddir)/src/util/libgnunetutil.la
248
249gnunet_communicator_tcp_SOURCES = \
250 gnunet-communicator-tcp.c
251gnunet_communicator_tcp_LDADD = \
252 libgnunettransportcommunicator.la \
253 $(top_builddir)/src/peerstore/libgnunetpeerstore.la \
254 $(top_builddir)/src/nat/libgnunetnatnew.la \
255 $(top_builddir)/src/nt/libgnunetnt.la \
256 $(top_builddir)/src/statistics/libgnunetstatistics.la \
257 $(top_builddir)/src/util/libgnunetutil.la \
258 $(LIBGCRYPT_LIBS)
259
260gnunet_communicator_udp_SOURCES = \
261 gnunet-communicator-udp.c
262gnunet_communicator_udp_LDADD = \
263 libgnunettransportapplication.la \
264 libgnunettransportcommunicator.la \
265 $(top_builddir)/src/nat/libgnunetnatnew.la \
266 $(top_builddir)/src/nt/libgnunetnt.la \
267 $(top_builddir)/src/statistics/libgnunetstatistics.la \
268 $(top_builddir)/src/util/libgnunetutil.la \
269 $(LIBGCRYPT_LIBS)
270
271
272gnunet_helper_transport_wlan_SOURCES = \
273 gnunet-helper-transport-wlan.c
274
275gnunet_helper_transport_wlan_dummy_SOURCES = \
276 gnunet-helper-transport-wlan-dummy.c
277gnunet_helper_transport_wlan_dummy_LDADD = \
278 $(top_builddir)/src/util/libgnunetutil.la
279
280gnunet_transport_wlan_sender_SOURCES = \
281 gnunet-transport-wlan-sender.c
282gnunet_transport_wlan_sender_LDADD = \
283 $(top_builddir)/src/util/libgnunetutil.la
284
285gnunet_transport_wlan_receiver_SOURCES = \
286 gnunet-transport-wlan-receiver.c
287gnunet_transport_wlan_receiver_LDADD = \
288 $(top_builddir)/src/util/libgnunetutil.la
289
290gnunet_helper_transport_bluetooth_SOURCES = \
291 gnunet-helper-transport-bluetooth.c
292
293gnunet_helper_transport_bluetooth_LDFLAGS = -lbluetooth
294
295
296gnunet_transport_profiler_SOURCES = \
297 gnunet-transport-profiler.c
298gnunet_transport_profiler_LDADD = \
299 libgnunettransport.la \
300 $(top_builddir)/src/hello/libgnunethello.la \
301 $(top_builddir)/src/ats/libgnunetats.la \
302 $(top_builddir)/src/util/libgnunetutil.la \
303 $(GN_LIBINTL)
304
305gnunet_transport_SOURCES = \
306 gnunet-transport.c
307gnunet_transport_LDADD = \
308 libgnunettransport.la \
309 $(top_builddir)/src/hello/libgnunethello.la \
310 $(top_builddir)/src/util/libgnunetutil.la \
311 $(GN_LIBINTL)
312
313gnunet_service_transport_SOURCES = \
314 gnunet-service-transport.c gnunet-service-transport.h \
315 gnunet-service-transport_ats.h gnunet-service-transport_ats.c \
316 gnunet-service-transport_hello.h gnunet-service-transport_hello.c \
317 gnunet-service-transport_neighbours.h gnunet-service-transport_neighbours.c \
318 gnunet-service-transport_plugins.h gnunet-service-transport_plugins.c \
319 gnunet-service-transport_validation.h gnunet-service-transport_validation.c \
320 gnunet-service-transport_manipulation.h gnunet-service-transport_manipulation.c
321# Note that while gnunet-service-transport does not use libgnunetnat
322# directly, we must link against it as GNUNET_NAT_mini_map_stop will
323# leave a 'dangling' task to process_unmap_output which will cause
324# a crash on unloading of a plugin unless the service links against
325# that library as well.
326gnunet_service_transport_LDADD = \
327 libgnunettransport.la \
328 $(top_builddir)/src/ats/libgnunetats.la \
329 $(top_builddir)/src/hello/libgnunethello.la \
330 $(top_builddir)/src/nt/libgnunetnt.la \
331 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
332 $(top_builddir)/src/statistics/libgnunetstatistics.la \
333 $(top_builddir)/src/util/libgnunetutil.la \
334 $(GN_GLPK) \
335 $(GN_LIBINTL)
336gnunet_service_transport_CFLAGS = \
337 $(AM_CFLAGS)
338# -DANALYZE
339
340
341gnunet_service_tng_SOURCES = \
342 gnunet-service-tng.c
343gnunet_service_tng_LDADD = \
344 $(top_builddir)/src/peerstore/libgnunetpeerstore.la \
345 $(top_builddir)/src/hello/libgnunethello.la \
346 $(top_builddir)/src/statistics/libgnunetstatistics.la \
347 $(top_builddir)/src/util/libgnunetutil.la \
348 $(LIBGCRYPT_LIBS) \
349 $(GN_LIBINTL)
350
351plugin_LTLIBRARIES = \
352 libgnunet_plugin_transport_tcp.la \
353 $(UNIX_PLUGIN_LA) \
354 $(HTTP_CLIENT_PLUGIN_LA) \
355 $(HTTPS_CLIENT_PLUGIN_LA) \
356 $(HTTP_SERVER_PLUGIN_LA) \
357 $(HTTPS_SERVER_PLUGIN_LA) \
358 $(WLAN_PLUGIN_LA) \
359 $(BT_PLUGIN_LA) \
360 libgnunet_test_transport_plugin_cmd_simple_send.la \
361 libgnunet_test_transport_plugin_cmd_simple_send_broadcast.la \
362 libgnunet_test_transport_plugin_cmd_simple_send_dv.la \
363 libgnunet_test_transport_plugin_cmd_udp_backchannel.la
364
365libgnunet_test_transport_plugin_cmd_udp_backchannel_la_SOURCES = \
366 test_transport_plugin_cmd_udp_backchannel.c
367libgnunet_test_transport_plugin_cmd_udp_backchannel_la_LIBADD = \
368 libgnunettransporttesting2.la \
369 libgnunettransportapplication.la \
370 libgnunettransportcore.la \
371 $(top_builddir)/src/testing/libgnunettesting.la \
372 $(top_builddir)/src/peerstore/libgnunetpeerstore.la \
373 $(top_builddir)/src/statistics/libgnunetstatistics.la \
374 $(top_builddir)/src/hello/libgnunethello.la \
375 $(top_builddir)/src/ats/libgnunetats.la \
376 $(top_builddir)/src/arm/libgnunetarm.la \
377 $(top_builddir)/src/util/libgnunetutil.la \
378 $(LTLIBINTL)
379libgnunet_test_transport_plugin_cmd_udp_backchannel_la_LDFLAGS = \
380 $(GN_PLUGIN_LDFLAGS)
381
382libgnunet_test_transport_plugin_cmd_simple_send_la_SOURCES = \
383 test_transport_plugin_cmd_simple_send.c
384libgnunet_test_transport_plugin_cmd_simple_send_la_LIBADD = \
385 libgnunettransporttesting2.la \
386 libgnunettransportapplication.la \
387 libgnunettransportcore.la \
388 $(top_builddir)/src/testing/libgnunettesting.la \
389 $(top_builddir)/src/peerstore/libgnunetpeerstore.la \
390 $(top_builddir)/src/statistics/libgnunetstatistics.la \
391 $(top_builddir)/src/hello/libgnunethello.la \
392 $(top_builddir)/src/ats/libgnunetats.la \
393 $(top_builddir)/src/arm/libgnunetarm.la \
394 $(top_builddir)/src/util/libgnunetutil.la \
395 $(LTLIBINTL)
396libgnunet_test_transport_plugin_cmd_simple_send_la_LDFLAGS = \
397 $(GN_PLUGIN_LDFLAGS)
398
399libgnunet_test_transport_plugin_cmd_simple_send_broadcast_la_SOURCES = \
400 test_transport_plugin_cmd_simple_send_broadcast.c
401libgnunet_test_transport_plugin_cmd_simple_send_broadcast_la_LIBADD = \
402 libgnunettransporttesting2.la \
403 libgnunettransportapplication.la \
404 libgnunettransportcore.la \
405 $(top_builddir)/src/testing/libgnunettesting.la \
406 $(top_builddir)/src/peerstore/libgnunetpeerstore.la \
407 $(top_builddir)/src/statistics/libgnunetstatistics.la \
408 $(top_builddir)/src/hello/libgnunethello.la \
409 $(top_builddir)/src/ats/libgnunetats.la \
410 $(top_builddir)/src/arm/libgnunetarm.la \
411 $(top_builddir)/src/util/libgnunetutil.la \
412 $(LTLIBINTL)
413libgnunet_test_transport_plugin_cmd_simple_send_broadcast_la_LDFLAGS = \
414 $(GN_PLUGIN_LDFLAGS)
415
416libgnunet_test_transport_plugin_cmd_simple_send_dv_la_SOURCES = \
417 test_transport_plugin_cmd_simple_send_dv.c
418libgnunet_test_transport_plugin_cmd_simple_send_dv_la_LIBADD = \
419 libgnunettransporttesting2.la \
420 libgnunettransportapplication.la \
421 libgnunettransportcore.la \
422 $(top_builddir)/src/testing/libgnunettesting.la \
423 $(top_builddir)/src/peerstore/libgnunetpeerstore.la \
424 $(top_builddir)/src/statistics/libgnunetstatistics.la \
425 $(top_builddir)/src/hello/libgnunethello.la \
426 $(top_builddir)/src/ats/libgnunetats.la \
427 $(top_builddir)/src/arm/libgnunetarm.la \
428 $(top_builddir)/src/util/libgnunetutil.la \
429 $(LTLIBINTL)
430libgnunet_test_transport_plugin_cmd_simple_send_dv_la_LDFLAGS = \
431 $(GN_PLUGIN_LDFLAGS)
432
433if HAVE_EXPERIMENTAL
434plugin_LTLIBRARIES += \
435 libgnunet_plugin_transport_udp.la
436endif
437
438# Note: real plugins of course need to be added
439# to the plugin_LTLIBRARIES above
440noinst_LTLIBRARIES = \
441 libgnunet_plugin_transport_template.la
442
443libgnunet_plugin_transport_tcp_la_SOURCES = \
444 plugin_transport_tcp.c
445libgnunet_plugin_transport_tcp_la_LIBADD = \
446 $(top_builddir)/src/hello/libgnunethello.la \
447 $(top_builddir)/src/statistics/libgnunetstatistics.la \
448 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
449 $(top_builddir)/src/nat/libgnunetnatnew.la \
450 $(top_builddir)/src/util/libgnunetutil.la \
451 $(LTLIBINTL)
452libgnunet_plugin_transport_tcp_la_LDFLAGS = \
453 $(GN_PLUGIN_LDFLAGS)
454
455libgnunet_plugin_transport_template_la_SOURCES = \
456 plugin_transport_template.c
457libgnunet_plugin_transport_template_la_LIBADD = \
458 $(top_builddir)/src/util/libgnunetutil.la \
459 $(LTLIBINTL)
460libgnunet_plugin_transport_template_la_LDFLAGS = \
461 $(GN_PLUGIN_LDFLAGS)
462
463libgnunet_plugin_transport_wlan_la_SOURCES = \
464 plugin_transport_wlan.c plugin_transport_wlan.h
465libgnunet_plugin_transport_wlan_la_LIBADD = \
466 $(top_builddir)/src/hello/libgnunethello.la \
467 $(top_builddir)/src/statistics/libgnunetstatistics.la \
468 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
469 $(top_builddir)/src/fragmentation/libgnunetfragmentation.la \
470 $(top_builddir)/src/util/libgnunetutil.la
471libgnunet_plugin_transport_wlan_la_LDFLAGS = \
472 $(GN_PLUGIN_LDFLAGS)
473libgnunet_plugin_transport_wlan_la_CFLAGS = \
474 $(AM_CFLAGS) -DBUILD_WLAN
475
476libgnunet_plugin_transport_bluetooth_la_SOURCES = \
477 plugin_transport_wlan.c plugin_transport_wlan.h
478libgnunet_plugin_transport_bluetooth_la_LIBADD = \
479 $(top_builddir)/src/hello/libgnunethello.la \
480 $(top_builddir)/src/statistics/libgnunetstatistics.la \
481 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
482 $(top_builddir)/src/fragmentation/libgnunetfragmentation.la \
483 $(top_builddir)/src/util/libgnunetutil.la
484libgnunet_plugin_transport_bluetooth_la_LDFLAGS = \
485 $(GN_PLUGIN_LDFLAGS)
486libgnunet_plugin_transport_bluetooth_la_CFLAGS = \
487 $(AM_CFLAGS) -DBUILD_BLUETOOTH
488
489if HAVE_EXPERIMENTAL
490libgnunet_plugin_transport_udp_la_SOURCES = \
491 plugin_transport_udp.c plugin_transport_udp.h \
492 plugin_transport_udp_broadcasting.c
493libgnunet_plugin_transport_udp_la_LIBADD = \
494 $(top_builddir)/src/hello/libgnunethello.la \
495 $(top_builddir)/src/fragmentation/libgnunetfragmentation.la \
496 $(top_builddir)/src/statistics/libgnunetstatistics.la \
497 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
498 $(top_builddir)/src/nat/libgnunetnatnew.la \
499 $(top_builddir)/src/util/libgnunetutil.la \
500 $(LTLIBINTL)
501libgnunet_plugin_transport_udp_la_LDFLAGS = \
502 $(GN_PLUGIN_LDFLAGS)
503endif
504
505libgnunet_plugin_transport_unix_la_SOURCES = \
506 plugin_transport_unix.c
507libgnunet_plugin_transport_unix_la_LIBADD = \
508 $(top_builddir)/src/hello/libgnunethello.la \
509 $(top_builddir)/src/statistics/libgnunetstatistics.la \
510 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
511 $(top_builddir)/src/util/libgnunetutil.la \
512 $(LTLIBINTL)
513libgnunet_plugin_transport_unix_la_LDFLAGS = \
514 $(GN_PLUGIN_LDFLAGS)
515
516
517libgnunet_plugin_transport_http_client_la_SOURCES = \
518 plugin_transport_http_client.c plugin_transport_http_common.c plugin_transport_http_common.h
519libgnunet_plugin_transport_http_client_la_LIBADD = \
520 $(top_builddir)/src/hello/libgnunethello.la \
521 $(top_builddir)/src/statistics/libgnunetstatistics.la \
522 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
523 @LIBCURL@ \
524 $(top_builddir)/src/util/libgnunetutil.la
525libgnunet_plugin_transport_http_client_la_LDFLAGS = \
526 $(GN_LIBINTL) \
527 $(GN_PLUGIN_LDFLAGS)
528libgnunet_plugin_transport_http_client_la_CFLAGS = \
529 @LIBCURL_CPPFLAGS@ $(AM_CFLAGS)
530
531
532libgnunet_plugin_transport_http_server_la_SOURCES = \
533 plugin_transport_http_server.c plugin_transport_http_common.c
534libgnunet_plugin_transport_http_server_la_LIBADD = \
535 $(MHD_LIBS) \
536 $(top_builddir)/src/hello/libgnunethello.la \
537 $(top_builddir)/src/statistics/libgnunetstatistics.la \
538 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
539 $(top_builddir)/src/nat/libgnunetnatnew.la \
540 $(top_builddir)/src/util/libgnunetutil.la
541libgnunet_plugin_transport_http_server_la_LDFLAGS = \
542 $(GN_LIBINTL) \
543 $(GN_PLUGIN_LDFLAGS)
544libgnunet_plugin_transport_http_server_la_CFLAGS = \
545 $(MHD_CFLAGS) $(AM_CFLAGS)
546
547libgnunet_plugin_transport_https_client_la_SOURCES = \
548 plugin_transport_http_client.c plugin_transport_http_common.c
549libgnunet_plugin_transport_https_client_la_LIBADD = \
550 $(top_builddir)/src/hello/libgnunethello.la \
551 $(top_builddir)/src/statistics/libgnunetstatistics.la \
552 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
553 @LIBCURL@ \
554 $(top_builddir)/src/util/libgnunetutil.la
555libgnunet_plugin_transport_https_client_la_LDFLAGS = \
556 $(GN_LIBINTL) \
557 $(GN_PLUGIN_LDFLAGS)
558libgnunet_plugin_transport_https_client_la_CFLAGS = \
559 @LIBCURL_CPPFLAGS@ $(AM_CFLAGS) -DBUILD_HTTPS
560
561
562libgnunet_plugin_transport_https_server_la_SOURCES = \
563 plugin_transport_http_server.c plugin_transport_http_common.c
564libgnunet_plugin_transport_https_server_la_LIBADD = \
565 $(MHD_LIBS) \
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/nat/libgnunetnatnew.la \
570 $(top_builddir)/src/util/libgnunetutil.la
571libgnunet_plugin_transport_https_server_la_LDFLAGS = \
572 $(GN_LIBINTL) \
573 $(GN_PLUGIN_LDFLAGS)
574libgnunet_plugin_transport_https_server_la_CFLAGS = \
575 $(MHD_CFLAGS) $(AM_CFLAGS) -DBUILD_HTTPS
576
577check_PROGRAMS = \
578 test_transport_address_switch_tcp \
579 test_transport_testing_startstop \
580 test_transport_testing_restart \
581 test_plugin_tcp \
582 $(UNIX_TEST) \
583 $(WLAN_PLUGIN_TEST) \
584 $(BT_PLUGIN_TEST) \
585 test_http_common \
586 $(HTTP_CLIENT_PLUGIN_TEST) \
587 $(HTTPS_CLIENT_PLUGIN_TEST) \
588 $(HTTP_SERVER_PLUGIN_TEST) \
589 $(HTTPS_SERVER_PLUGIN_TEST) \
590 test_transport_api_blacklisting_tcp \
591 test_transport_api_disconnect_tcp \
592 test_transport_api_tcp \
593 test_transport_api2_tcp \
594 test_transport_api_restart_1peer \
595 test_transport_api_restart_2peers \
596 test_transport_api_timeout_tcp \
597 test_transport_api_limited_sockets_tcp \
598 test_transport_api_tcp_nat \
599 $(UNIX_PLUGIN_TEST) \
600 $(UNIX_PLUGIN_TIMEOUT_TEST) \
601 $(UNIX_API_ABSTRACT_TEST) \
602 $(HTTP_API_TEST) \
603 $(HTTP_REVERSE_API_TEST) \
604 $(HTTP_API_TIMEOUT_TEST) \
605 $(HTTP_SWITCH) \
606 $(HTTPS_API_TEST) \
607 $(HTTPS_API_TIMEOUT_TEST) \
608 $(HTTPS_SWITCH) \
609 $(WLAN_API_TEST) \
610 $(WLAN_TIMEOUT_TEST) \
611 $(BT_API_TEST) \
612 $(BT_TIMEOUT_TEST) \
613 test_transport_api_multi \
614 test_transport_api_monitor_peers \
615 test_transport_blacklisting_no_bl \
616 test_transport_blacklisting_outbound_bl_full \
617 test_transport_blacklisting_outbound_bl_plugin \
618 test_transport_blacklisting_inbound_bl_plugin \
619 test_transport_blacklisting_inbound_bl_full \
620 test_transport_blacklisting_multiple_plugins \
621 test_transport_api_manipulation_send_tcp \
622 test_transport_api_manipulation_recv_tcp \
623 test_transport_api_manipulation_cfg \
624 test_transport_api_reliability_tcp \
625 test_transport_api_reliability_tcp_nat \
626 $(UNIX_REL_TEST) \
627 $(HTTP_REL_TEST) \
628 $(HTTPS_REL_TEST) \
629 $(WLAN_REL_TEST) \
630 $(WLAN_UREL_TEST) \
631 $(BT_REL_TEST) \
632 $(BT_UREL_TEST) \
633 test_quota_compliance_tcp \
634 test_quota_compliance_tcp_asymmetric \
635 $(UNIX_QUOTA_TEST) \
636 $(HTTP_QUOTA_TEST) \
637 $(HTTPS_QUOTA_TEST) \
638 $(WLAN_QUOTA_TEST) \
639 $(BT_QUOTA_TEST)
640if HAVE_GETOPT_BINARY
641check_PROGRAMS += \
642test_transport_api_slow_ats
643endif
644if HAVE_EXPERIMENTAL
645check_PROGRAMS += \
646 test_transport_address_switch_udp \
647 test_plugin_udp \
648 test_transport_api_udp \
649 test_transport_api_timeout_udp \
650 test_transport_api_udp_nat \
651 test_transport_api_reliability_udp \
652 test_quota_compliance_udp \
653 test_communicator_basic-unix \
654 test_communicator_basic-tcp \
655 test_communicator_basic-udp \
656 test_communicator_rekey-tcp \
657 test_communicator_rekey-udp \
658 test_communicator_backchannel-udp \
659 test_communicator_bidirect-tcp
660endif
661
662if ENABLE_TEST_RUN
663AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
664TESTS = \
665 test_transport_address_switch_tcp \
666 $(HTTP_SWITCH) \
667 $(HTTPS_SWITCH) \
668 test_transport_testing_startstop \
669 test_transport_testing_restart \
670 test_plugin_tcp \
671 $(UNIX_TEST) \
672 $(WLAN_PLUGIN_TEST) \
673 $(BT_PLUGIN_TEST) \
674 test_transport_api_blacklisting_tcp \
675 test_transport_api_disconnect_tcp \
676 test_transport_api_tcp \
677 test_transport_api_restart_1peer \
678 test_transport_api_restart_2peers \
679 test_transport_api_limited_sockets_tcp \
680 test_transport_api_tcp_nat \
681 $(UNIX_PLUGIN_TEST) \
682 $(UNIX_API_ABSTRACT_TEST) \
683 $(HTTP_API_TEST) \
684 $(HTTPS_API_TEST) \
685 $(WLAN_API_TEST) \
686 $(BT_API_TEST) \
687 test_transport_api_multi \
688 test_transport_api_monitor_peers \
689 test_transport_blacklisting_no_bl \
690 test_transport_blacklisting_outbound_bl_full \
691 test_transport_blacklisting_outbound_bl_plugin \
692 test_transport_blacklisting_inbound_bl_plugin \
693 test_transport_blacklisting_inbound_bl_full \
694 test_transport_blacklisting_multiple_plugins \
695 test_transport_api_manipulation_send_tcp \
696 test_transport_api_manipulation_recv_tcp \
697 test_transport_api_manipulation_cfg \
698 test_transport_api_reliability_tcp \
699 test_transport_api_reliability_tcp_nat \
700 $(UNIX_REL_TEST) \
701 $(HTTP_REL_TEST) \
702 $(HTTPS_REL_TEST) \
703 $(WLAN_REL_TEST) \
704 $(WLAN_UREL_TEST) \
705 $(BT_REL_TEST) \
706 $(BT_UREL_TEST) \
707 test_quota_compliance_tcp \
708 test_quota_compliance_tcp_asymmetric \
709 $(UNIX_QUOTA_TEST) \
710 $(HTTP_QUOTA_TEST) \
711 $(HTTPS_QUOTA_TEST) \
712 test_transport_api_timeout_tcp \
713 $(UNIX_PLUGIN_TIMEOUT_TEST) \
714 $(HTTP_API_TIMEOUT_TEST) \
715 $(HTTPS_API_TIMEOUT_TEST) \
716 $(WLAN_TIMEOUT_TEST) \
717 $(BT_TIMEOUT_TEST) \
718 $(check_SCRIPTS)
719if HAVE_GETOPT_BINARY
720TESTS += \
721test_transport_api_slow_ats
722endif
723if HAVE_EXPERIMENTAL
724TESTS += \
725 test_transport_address_switch_udp \
726 test_plugin_udp \
727 test_transport_api_udp \
728 test_transport_api_timeout_udp \
729 test_transport_api_udp_nat \
730 test_transport_api_reliability_udp \
731 test_quota_compliance_udp \
732 test_communicator_basic-unix \
733 test_communicator_basic-tcp \
734 test_communicator_basic-udp \
735 test_communicator_rekey-tcp \
736 test_communicator_rekey-udp \
737 test_communicator_backchannel-udp \
738 test_communicator_bidirect-tcp
739endif
740endif
741
742# Only test TNG if we run experimental
743if HAVE_EXPERIMENTAL
744check_SCRIPTS= \
745 test_transport_simple_send_string.sh \
746 test_transport_simple_send.sh \
747 test_transport_simple_send_broadcast.sh \
748 test_transport_udp_backchannel.sh \
749 test_transport_simple_send_dv_circle.sh
750 # test_transport_simple_send_dv_inverse.sh
751endif
752
753test_transport_start_with_config_SOURCES = \
754 test_transport_start_with_config.c
755test_transport_start_with_config_LDADD = \
756 $(top_builddir)/src/testing/libgnunettesting.la \
757 $(top_builddir)/src/util/libgnunetutil.la \
758 $(top_builddir)/src/hello/libgnunethello.la \
759 libgnunettransportcore.la \
760 libgnunettransporttesting2.la
761
762test_transport_testing_startstop_SOURCES = \
763 test_transport_testing_startstop.c
764test_transport_testing_startstop_LDADD = \
765 $(top_builddir)/src/util/libgnunetutil.la \
766 libgnunettransport.la \
767 $(top_builddir)/src/hello/libgnunethello.la \
768 libgnunettransporttesting.la
769
770test_transport_testing_restart_SOURCES = \
771 test_transport_testing_restart.c
772test_transport_testing_restart_LDADD = \
773 $(top_builddir)/src/util/libgnunetutil.la \
774 libgnunettransport.la \
775 $(top_builddir)/src/hello/libgnunethello.la \
776 libgnunettransporttesting.la
777
778test_transport_api_blacklisting_tcp_SOURCES = \
779 test_transport_api_blacklisting.c
780test_transport_api_blacklisting_tcp_LDADD = \
781 libgnunettransport.la \
782 $(top_builddir)/src/hello/libgnunethello.la \
783 $(top_builddir)/src/statistics/libgnunetstatistics.la \
784 $(top_builddir)/src/util/libgnunetutil.la \
785 libgnunettransporttesting.la
786
787test_transport_blacklisting_no_bl_SOURCES = \
788 test_transport_blacklisting.c
789test_transport_blacklisting_no_bl_LDADD = \
790 libgnunettransport.la \
791 $(top_builddir)/src/hello/libgnunethello.la \
792 $(top_builddir)/src/statistics/libgnunetstatistics.la \
793 $(top_builddir)/src/util/libgnunetutil.la \
794 libgnunettransporttesting.la
795
796test_transport_blacklisting_outbound_bl_full_SOURCES = \
797 test_transport_blacklisting.c
798test_transport_blacklisting_outbound_bl_full_LDADD = \
799 libgnunettransport.la \
800 $(top_builddir)/src/hello/libgnunethello.la \
801 $(top_builddir)/src/statistics/libgnunetstatistics.la \
802 $(top_builddir)/src/util/libgnunetutil.la \
803 libgnunettransporttesting.la
804
805test_transport_blacklisting_outbound_bl_plugin_SOURCES = \
806 test_transport_blacklisting.c
807test_transport_blacklisting_outbound_bl_plugin_LDADD = \
808 libgnunettransport.la \
809 $(top_builddir)/src/hello/libgnunethello.la \
810 $(top_builddir)/src/statistics/libgnunetstatistics.la \
811 $(top_builddir)/src/util/libgnunetutil.la \
812 libgnunettransporttesting.la
813
814test_transport_blacklisting_inbound_bl_full_SOURCES = \
815 test_transport_blacklisting.c
816test_transport_blacklisting_inbound_bl_full_LDADD = \
817 libgnunettransport.la \
818 $(top_builddir)/src/hello/libgnunethello.la \
819 $(top_builddir)/src/statistics/libgnunetstatistics.la \
820 $(top_builddir)/src/util/libgnunetutil.la \
821 libgnunettransporttesting.la
822
823test_transport_blacklisting_inbound_bl_plugin_SOURCES = \
824 test_transport_blacklisting.c
825test_transport_blacklisting_inbound_bl_plugin_LDADD = \
826 libgnunettransport.la \
827 $(top_builddir)/src/hello/libgnunethello.la \
828 $(top_builddir)/src/statistics/libgnunetstatistics.la \
829 $(top_builddir)/src/util/libgnunetutil.la \
830 libgnunettransporttesting.la
831
832test_transport_blacklisting_multiple_plugins_SOURCES = \
833 test_transport_blacklisting.c
834test_transport_blacklisting_multiple_plugins_LDADD = \
835 libgnunettransport.la \
836 $(top_builddir)/src/hello/libgnunethello.la \
837 $(top_builddir)/src/statistics/libgnunetstatistics.la \
838 $(top_builddir)/src/util/libgnunetutil.la \
839 libgnunettransporttesting.la
840
841
842test_transport_api_disconnect_tcp_SOURCES = \
843 test_transport_api_disconnect.c
844test_transport_api_disconnect_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_plugin_tcp_SOURCES = \
852 test_plugin_transport.c
853test_plugin_tcp_LDADD = \
854 libgnunettransport.la \
855 $(top_builddir)/src/statistics/libgnunetstatistics.la \
856 $(top_builddir)/src/hello/libgnunethello.la \
857 $(top_builddir)/src/util/libgnunetutil.la \
858 libgnunettransporttesting.la
859
860if HAVE_EXPERIMENTAL
861test_plugin_udp_SOURCES = \
862 test_plugin_transport.c
863test_plugin_udp_LDADD = \
864 libgnunettransport.la \
865 $(top_builddir)/src/statistics/libgnunetstatistics.la \
866 $(top_builddir)/src/hello/libgnunethello.la \
867 $(top_builddir)/src/util/libgnunetutil.la \
868 libgnunettransporttesting.la
869endif
870
871if HAVE_EXPERIMENTAL
872test_communicator_basic_unix_SOURCES = \
873 test_communicator_basic.c
874test_communicator_basic_unix_LDADD = \
875 libgnunettransporttesting2.la \
876 $(top_builddir)/src/testing/libgnunettesting.la \
877 $(top_builddir)/src/util/libgnunetutil.la \
878 $(top_builddir)/src/statistics/libgnunetstatistics.la
879
880test_communicator_basic_tcp_SOURCES = \
881 test_communicator_basic.c
882test_communicator_basic_tcp_LDADD = \
883 libgnunettransporttesting2.la \
884 $(top_builddir)/src/testing/libgnunettesting.la \
885 $(top_builddir)/src/util/libgnunetutil.la \
886 $(top_builddir)/src/statistics/libgnunetstatistics.la
887
888test_communicator_basic_udp_SOURCES = \
889 test_communicator_basic.c
890test_communicator_basic_udp_LDADD = \
891 libgnunettransporttesting2.la \
892 $(top_builddir)/src/testing/libgnunettesting.la \
893 $(top_builddir)/src/util/libgnunetutil.la \
894 $(top_builddir)/src/statistics/libgnunetstatistics.la
895
896test_communicator_rekey_tcp_SOURCES = \
897 test_communicator_basic.c
898test_communicator_rekey_tcp_LDADD = \
899 libgnunettransporttesting2.la \
900 $(top_builddir)/src/testing/libgnunettesting.la \
901 $(top_builddir)/src/util/libgnunetutil.la \
902 $(top_builddir)/src/statistics/libgnunetstatistics.la
903
904test_communicator_rekey_udp_SOURCES = \
905 test_communicator_basic.c
906test_communicator_rekey_udp_LDADD = \
907 libgnunettransporttesting2.la \
908 $(top_builddir)/src/testing/libgnunettesting.la \
909 $(top_builddir)/src/util/libgnunetutil.la \
910 $(top_builddir)/src/statistics/libgnunetstatistics.la
911
912test_communicator_backchannel_udp_SOURCES = \
913 test_communicator_basic.c
914test_communicator_backchannel_udp_LDADD = \
915 libgnunettransporttesting2.la \
916 $(top_builddir)/src/testing/libgnunettesting.la \
917 $(top_builddir)/src/util/libgnunetutil.la \
918 $(top_builddir)/src/statistics/libgnunetstatistics.la
919
920test_communicator_bidirect_tcp_SOURCES = \
921 test_communicator_basic.c
922test_communicator_bidirect_tcp_LDADD = \
923 libgnunettransporttesting2.la \
924 $(top_builddir)/src/testing/libgnunettesting.la \
925 $(top_builddir)/src/util/libgnunetutil.la \
926 $(top_builddir)/src/statistics/libgnunetstatistics.la
927endif
928
929test_plugin_unix_SOURCES = \
930 test_plugin_transport.c
931test_plugin_unix_LDADD = \
932 libgnunettransport.la \
933 $(top_builddir)/src/statistics/libgnunetstatistics.la \
934 $(top_builddir)/src/hello/libgnunethello.la \
935 $(top_builddir)/src/util/libgnunetutil.la \
936 libgnunettransporttesting.la
937
938test_plugin_wlan_SOURCES = \
939 test_plugin_transport.c
940test_plugin_wlan_LDADD = \
941 libgnunettransport.la \
942 $(top_builddir)/src/statistics/libgnunetstatistics.la \
943 $(top_builddir)/src/hello/libgnunethello.la \
944 $(top_builddir)/src/util/libgnunetutil.la \
945 libgnunettransporttesting.la
946
947test_plugin_bluetooth_SOURCES = \
948 test_plugin_transport.c
949test_plugin_bluetooth_LDADD = \
950 libgnunettransport.la \
951 $(top_builddir)/src/statistics/libgnunetstatistics.la \
952 $(top_builddir)/src/hello/libgnunethello.la \
953 $(top_builddir)/src/util/libgnunetutil.la \
954 libgnunettransporttesting.la
955
956test_http_common_SOURCES = \
957 test_http_common.c plugin_transport_http_common.c
958test_http_common_LDADD = \
959 libgnunettransport.la \
960 $(top_builddir)/src/statistics/libgnunetstatistics.la \
961 $(top_builddir)/src/hello/libgnunethello.la \
962 $(top_builddir)/src/util/libgnunetutil.la \
963 libgnunettransporttesting.la
964
965test_plugin_http_server_SOURCES = \
966 test_plugin_transport.c
967test_plugin_http_server_LDADD = \
968 libgnunettransport.la \
969 $(top_builddir)/src/statistics/libgnunetstatistics.la \
970 $(top_builddir)/src/hello/libgnunethello.la \
971 $(top_builddir)/src/util/libgnunetutil.la \
972 libgnunettransporttesting.la
973
974test_plugin_https_server_SOURCES = \
975 test_plugin_transport.c
976test_plugin_https_server_LDADD = \
977 libgnunettransport.la \
978 $(top_builddir)/src/statistics/libgnunetstatistics.la \
979 $(top_builddir)/src/hello/libgnunethello.la \
980 $(top_builddir)/src/util/libgnunetutil.la \
981 libgnunettransporttesting.la
982
983test_plugin_http_client_SOURCES = \
984 test_plugin_transport.c
985test_plugin_http_client_LDADD = \
986 libgnunettransport.la \
987 $(top_builddir)/src/statistics/libgnunetstatistics.la \
988 $(top_builddir)/src/hello/libgnunethello.la \
989 $(top_builddir)/src/util/libgnunetutil.la \
990 libgnunettransporttesting.la
991
992test_plugin_https_client_SOURCES = \
993 test_plugin_transport.c
994test_plugin_https_client_LDADD = \
995 libgnunettransport.la \
996 $(top_builddir)/src/statistics/libgnunetstatistics.la \
997 $(top_builddir)/src/hello/libgnunethello.la \
998 $(top_builddir)/src/util/libgnunetutil.la \
999 libgnunettransporttesting.la
1000
1001test_transport_api_tcp_SOURCES = \
1002 test_transport_api.c
1003test_transport_api_tcp_LDADD = \
1004 libgnunettransport.la \
1005 $(top_builddir)/src/hello/libgnunethello.la \
1006 $(top_builddir)/src/util/libgnunetutil.la \
1007 libgnunettransporttesting.la
1008
1009test_transport_api2_tcp_SOURCES = \
1010 test_transport_api2.c
1011test_transport_api2_tcp_LDADD = \
1012 $(top_builddir)/src/hello/libgnunethello.la \
1013 $(top_builddir)/src/util/libgnunetutil.la \
1014 libgnunettransporttesting2.la
1015
1016test_transport_api_restart_1peer_SOURCES = \
1017 test_transport_api_restart_reconnect.c
1018test_transport_api_restart_1peer_LDADD = \
1019 libgnunettransport.la \
1020 $(top_builddir)/src/hello/libgnunethello.la \
1021 $(top_builddir)/src/ats/libgnunetats.la \
1022 $(top_builddir)/src/statistics/libgnunetstatistics.la \
1023 $(top_builddir)/src/util/libgnunetutil.la \
1024 libgnunettransporttesting.la
1025
1026test_transport_api_restart_2peers_SOURCES = \
1027 test_transport_api_restart_reconnect.c
1028test_transport_api_restart_2peers_LDADD = \
1029 libgnunettransport.la \
1030 $(top_builddir)/src/hello/libgnunethello.la \
1031 $(top_builddir)/src/ats/libgnunetats.la \
1032$(top_builddir)/src/statistics/libgnunetstatistics.la \
1033 $(top_builddir)/src/util/libgnunetutil.la \
1034 libgnunettransporttesting.la
1035
1036test_transport_api_limited_sockets_tcp_SOURCES = \
1037 test_transport_api_limited_sockets.c
1038test_transport_api_limited_sockets_tcp_LDADD = \
1039 libgnunettransport.la \
1040 $(top_builddir)/src/hello/libgnunethello.la \
1041 $(top_builddir)/src/util/libgnunetutil.la \
1042 libgnunettransporttesting.la
1043
1044test_transport_api_tcp_nat_SOURCES = \
1045 test_transport_api.c
1046test_transport_api_tcp_nat_LDADD = \
1047 libgnunettransport.la \
1048 $(top_builddir)/src/hello/libgnunethello.la \
1049 $(top_builddir)/src/util/libgnunetutil.la \
1050 libgnunettransporttesting.la
1051
1052test_transport_api_manipulation_send_tcp_SOURCES = \
1053 test_transport_api_manipulation_send_tcp.c
1054test_transport_api_manipulation_send_tcp_LDADD = \
1055 libgnunettransport.la \
1056 $(top_builddir)/src/hello/libgnunethello.la \
1057 $(top_builddir)/src/util/libgnunetutil.la \
1058 libgnunettransporttesting.la
1059
1060test_transport_api_manipulation_recv_tcp_SOURCES = \
1061 test_transport_api_manipulation_recv_tcp.c
1062test_transport_api_manipulation_recv_tcp_LDADD = \
1063 libgnunettransport.la \
1064 $(top_builddir)/src/hello/libgnunethello.la \
1065 $(top_builddir)/src/util/libgnunetutil.la \
1066 libgnunettransporttesting.la
1067
1068test_transport_api_manipulation_cfg_SOURCES = \
1069 test_transport_api_manipulation_cfg.c
1070test_transport_api_manipulation_cfg_LDADD = \
1071 libgnunettransport.la \
1072 $(top_builddir)/src/hello/libgnunethello.la \
1073 $(top_builddir)/src/util/libgnunetutil.la \
1074 libgnunettransporttesting.la
1075
1076test_transport_api_reliability_tcp_SOURCES = \
1077 test_transport_api_reliability.c
1078test_transport_api_reliability_tcp_LDADD = \
1079 libgnunettransport.la \
1080 $(top_builddir)/src/hello/libgnunethello.la \
1081 $(top_builddir)/src/util/libgnunetutil.la \
1082 libgnunettransporttesting.la
1083
1084test_transport_api_timeout_tcp_SOURCES = \
1085 test_transport_api_timeout.c
1086test_transport_api_timeout_tcp_LDADD = \
1087 libgnunettransport.la \
1088 $(top_builddir)/src/hello/libgnunethello.la \
1089 $(top_builddir)/src/util/libgnunetutil.la \
1090 libgnunettransporttesting.la
1091
1092test_transport_api_timeout_unix_SOURCES = \
1093 test_transport_api_timeout.c
1094test_transport_api_timeout_unix_LDADD = \
1095 libgnunettransport.la \
1096 $(top_builddir)/src/hello/libgnunethello.la \
1097 $(top_builddir)/src/util/libgnunetutil.la \
1098 libgnunettransporttesting.la
1099
1100test_transport_api_timeout_wlan_SOURCES = \
1101 test_transport_api_timeout.c
1102test_transport_api_timeout_wlan_LDADD = \
1103 libgnunettransport.la \
1104 $(top_builddir)/src/hello/libgnunethello.la \
1105 $(top_builddir)/src/util/libgnunetutil.la \
1106 libgnunettransporttesting.la
1107
1108test_transport_api_timeout_bluetooth_SOURCES = \
1109 test_transport_api_timeout.c
1110test_transport_api_timeout_bluetooth_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_reliability_tcp_nat_SOURCES = \
1117 test_transport_api_reliability.c
1118test_transport_api_reliability_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_reliability_bluetooth_SOURCES = \
1125 test_transport_api_reliability.c
1126test_transport_api_reliability_bluetooth_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_reliability_wlan_SOURCES = \
1133 test_transport_api_reliability.c
1134test_transport_api_reliability_wlan_LDADD = \
1135 libgnunettransport.la \
1136 $(top_builddir)/src/hello/libgnunethello.la \
1137 $(top_builddir)/src/util/libgnunetutil.la \
1138 libgnunettransporttesting.la
1139
1140if HAVE_EXPERIMENTAL
1141test_transport_api_udp_SOURCES = \
1142 test_transport_api.c
1143test_transport_api_udp_LDADD = \
1144 libgnunettransport.la \
1145 $(top_builddir)/src/hello/libgnunethello.la \
1146 $(top_builddir)/src/util/libgnunetutil.la \
1147 libgnunettransporttesting.la
1148
1149test_transport_api_timeout_udp_SOURCES = \
1150 test_transport_api_timeout.c
1151test_transport_api_timeout_udp_LDADD = \
1152 libgnunettransport.la \
1153 $(top_builddir)/src/hello/libgnunethello.la \
1154 $(top_builddir)/src/util/libgnunetutil.la \
1155 libgnunettransporttesting.la
1156
1157test_transport_api_udp_nat_SOURCES = \
1158 test_transport_api.c
1159test_transport_api_udp_nat_LDADD = \
1160 libgnunettransport.la \
1161 $(top_builddir)/src/hello/libgnunethello.la \
1162 $(top_builddir)/src/util/libgnunetutil.la \
1163 libgnunettransporttesting.la
1164endif
1165
1166test_transport_api_unix_SOURCES = \
1167 test_transport_api.c
1168test_transport_api_unix_LDADD = \
1169 libgnunettransport.la \
1170 $(top_builddir)/src/hello/libgnunethello.la \
1171 $(top_builddir)/src/util/libgnunetutil.la \
1172 libgnunettransporttesting.la
1173
1174test_transport_api_unix_abstract_SOURCES = \
1175 test_transport_api.c
1176test_transport_api_unix_abstract_LDADD = \
1177 libgnunettransport.la \
1178 $(top_builddir)/src/hello/libgnunethello.la \
1179 $(top_builddir)/src/util/libgnunetutil.la \
1180 libgnunettransporttesting.la
1181
1182# HTTP tests
1183test_transport_api_http_SOURCES = \
1184 test_transport_api.c
1185test_transport_api_http_LDADD = \
1186 libgnunettransport.la \
1187 $(top_builddir)/src/hello/libgnunethello.la \
1188 $(top_builddir)/src/util/libgnunetutil.la \
1189 libgnunettransporttesting.la
1190
1191test_transport_api_http_reverse_SOURCES = \
1192 test_transport_api.c
1193test_transport_api_http_reverse_LDADD = \
1194 libgnunettransport.la \
1195 $(top_builddir)/src/hello/libgnunethello.la \
1196 $(top_builddir)/src/util/libgnunetutil.la \
1197 libgnunettransporttesting.la
1198
1199test_transport_api_timeout_http_SOURCES = \
1200 test_transport_api_timeout.c
1201test_transport_api_timeout_http_LDADD = \
1202 libgnunettransport.la \
1203 $(top_builddir)/src/hello/libgnunethello.la \
1204 $(top_builddir)/src/util/libgnunetutil.la \
1205 libgnunettransporttesting.la
1206
1207test_transport_api_reliability_http_SOURCES = \
1208 test_transport_api_reliability.c
1209test_transport_api_reliability_http_LDADD = \
1210 libgnunettransport.la \
1211 $(top_builddir)/src/hello/libgnunethello.la \
1212 $(top_builddir)/src/util/libgnunetutil.la \
1213 libgnunettransporttesting.la
1214
1215test_transport_api_reliability_http_xhr_SOURCES = \
1216 test_transport_api_reliability.c
1217test_transport_api_reliability_http_xhr_LDADD = \
1218 libgnunettransport.la \
1219 $(top_builddir)/src/hello/libgnunethello.la \
1220 $(top_builddir)/src/util/libgnunetutil.la \
1221 libgnunettransporttesting.la
1222
1223test_quota_compliance_http_SOURCES = \
1224 test_quota_compliance.c
1225test_quota_compliance_http_LDADD = \
1226 libgnunettransport.la \
1227 $(top_builddir)/src/hello/libgnunethello.la \
1228 $(top_builddir)/src/ats/libgnunetats.la \
1229 $(top_builddir)/src/nt/libgnunetnt.la \
1230 $(top_builddir)/src/util/libgnunetutil.la \
1231 libgnunettransporttesting.la
1232
1233test_quota_compliance_http_asymmetric_SOURCES = \
1234 test_quota_compliance.c
1235test_quota_compliance_http_asymmetric_LDADD = \
1236 libgnunettransport.la \
1237 $(top_builddir)/src/hello/libgnunethello.la \
1238 $(top_builddir)/src/ats/libgnunetats.la \
1239 $(top_builddir)/src/nt/libgnunetnt.la \
1240 $(top_builddir)/src/util/libgnunetutil.la \
1241 libgnunettransporttesting.la
1242
1243test_quota_compliance_https_SOURCES = \
1244 test_quota_compliance.c
1245test_quota_compliance_https_LDADD = \
1246 libgnunettransport.la \
1247 $(top_builddir)/src/hello/libgnunethello.la \
1248 $(top_builddir)/src/ats/libgnunetats.la \
1249 $(top_builddir)/src/nt/libgnunetnt.la \
1250 $(top_builddir)/src/util/libgnunetutil.la \
1251 libgnunettransporttesting.la
1252
1253test_quota_compliance_https_asymmetric_SOURCES = \
1254 test_quota_compliance.c
1255test_quota_compliance_https_asymmetric_LDADD = \
1256 libgnunettransport.la \
1257 $(top_builddir)/src/hello/libgnunethello.la \
1258 $(top_builddir)/src/ats/libgnunetats.la \
1259 $(top_builddir)/src/nt/libgnunetnt.la \
1260 $(top_builddir)/src/util/libgnunetutil.la \
1261 libgnunettransporttesting.la
1262
1263# HTTPS tests
1264test_transport_api_https_SOURCES = \
1265 test_transport_api.c
1266test_transport_api_https_LDADD = \
1267 libgnunettransport.la \
1268 $(top_builddir)/src/hello/libgnunethello.la \
1269 $(top_builddir)/src/util/libgnunetutil.la \
1270 libgnunettransporttesting.la
1271
1272test_transport_api_timeout_https_SOURCES = \
1273 test_transport_api_timeout.c
1274test_transport_api_timeout_https_LDADD = \
1275 libgnunettransport.la \
1276 $(top_builddir)/src/hello/libgnunethello.la \
1277 $(top_builddir)/src/util/libgnunetutil.la \
1278 libgnunettransporttesting.la
1279
1280
1281test_transport_api_reliability_https_SOURCES = \
1282 test_transport_api_reliability.c
1283test_transport_api_reliability_https_LDADD = \
1284 libgnunettransport.la \
1285 $(top_builddir)/src/hello/libgnunethello.la \
1286 $(top_builddir)/src/util/libgnunetutil.la \
1287 libgnunettransporttesting.la
1288
1289test_transport_api_reliability_https_xhr_SOURCES = \
1290 test_transport_api_reliability.c
1291test_transport_api_reliability_https_xhr_LDADD = \
1292 libgnunettransport.la \
1293 $(top_builddir)/src/hello/libgnunethello.la \
1294 $(top_builddir)/src/util/libgnunetutil.la \
1295 libgnunettransporttesting.la
1296
1297test_transport_api_reliability_unix_SOURCES = \
1298 test_transport_api_reliability.c
1299test_transport_api_reliability_unix_LDADD = \
1300 libgnunettransport.la \
1301 $(top_builddir)/src/hello/libgnunethello.la \
1302 $(top_builddir)/src/util/libgnunetutil.la \
1303 libgnunettransporttesting.la
1304
1305if HAVE_EXPERIMENTAL
1306test_transport_api_reliability_udp_SOURCES = \
1307 test_transport_api_reliability.c
1308test_transport_api_reliability_udp_LDADD = \
1309 libgnunettransport.la \
1310 $(top_builddir)/src/hello/libgnunethello.la \
1311 $(top_builddir)/src/util/libgnunetutil.la \
1312 libgnunettransporttesting.la
1313endif
1314
1315if LINUX
1316test_transport_api_wlan_SOURCES = \
1317 test_transport_api.c
1318test_transport_api_wlan_LDADD = \
1319 libgnunettransport.la \
1320 $(top_builddir)/src/hello/libgnunethello.la \
1321 $(top_builddir)/src/util/libgnunetutil.la \
1322 libgnunettransporttesting.la
1323endif
1324
1325if LINUX
1326if HAVE_LIBBLUETOOTH
1327test_transport_api_bluetooth_SOURCES = \
1328 test_transport_api.c
1329test_transport_api_bluetooth_LDADD = \
1330 libgnunettransport.la \
1331 $(top_builddir)/src/hello/libgnunethello.la \
1332 $(top_builddir)/src/util/libgnunetutil.la \
1333 libgnunettransporttesting.la
1334endif
1335endif
1336
1337test_transport_address_switch_tcp_SOURCES = \
1338 test_transport_address_switch.c
1339test_transport_address_switch_tcp_LDADD = \
1340 libgnunettransport.la \
1341 $(top_builddir)/src/hello/libgnunethello.la \
1342 $(top_builddir)/src/statistics/libgnunetstatistics.la \
1343 $(top_builddir)/src/util/libgnunetutil.la \
1344 libgnunettransporttesting.la
1345
1346if HAVE_EXPERIMENTAL
1347test_transport_address_switch_udp_SOURCES = \
1348 test_transport_address_switch.c
1349test_transport_address_switch_udp_LDADD = \
1350 libgnunettransport.la \
1351 $(top_builddir)/src/hello/libgnunethello.la \
1352 $(top_builddir)/src/statistics/libgnunetstatistics.la \
1353 $(top_builddir)/src/util/libgnunetutil.la \
1354 libgnunettransporttesting.la
1355endif
1356
1357 test_transport_address_switch_http_SOURCES = \
1358 test_transport_address_switch.c
1359test_transport_address_switch_http_LDADD = \
1360 libgnunettransport.la \
1361 $(top_builddir)/src/hello/libgnunethello.la \
1362 $(top_builddir)/src/statistics/libgnunetstatistics.la \
1363 $(top_builddir)/src/util/libgnunetutil.la \
1364 libgnunettransporttesting.la
1365
1366 test_transport_address_switch_https_SOURCES = \
1367 test_transport_address_switch.c
1368test_transport_address_switch_https_LDADD = \
1369 libgnunettransport.la \
1370 $(top_builddir)/src/hello/libgnunethello.la \
1371 $(top_builddir)/src/statistics/libgnunetstatistics.la \
1372 $(top_builddir)/src/util/libgnunetutil.la \
1373 libgnunettransporttesting.la
1374
1375test_quota_compliance_tcp_SOURCES = \
1376 test_quota_compliance.c
1377test_quota_compliance_tcp_LDADD = \
1378 libgnunettransport.la \
1379 $(top_builddir)/src/hello/libgnunethello.la \
1380 $(top_builddir)/src/ats/libgnunetats.la \
1381 $(top_builddir)/src/nt/libgnunetnt.la \
1382 $(top_builddir)/src/util/libgnunetutil.la \
1383 libgnunettransporttesting.la
1384
1385test_quota_compliance_tcp_asymmetric_SOURCES = \
1386 test_quota_compliance.c
1387test_quota_compliance_tcp_asymmetric_LDADD = \
1388 libgnunettransport.la \
1389 $(top_builddir)/src/hello/libgnunethello.la \
1390 $(top_builddir)/src/nt/libgnunetnt.la \
1391 $(top_builddir)/src/ats/libgnunetats.la \
1392 $(top_builddir)/src/util/libgnunetutil.la \
1393 libgnunettransporttesting.la
1394
1395if HAVE_EXPERIMENTAL
1396test_quota_compliance_udp_SOURCES = \
1397 test_quota_compliance.c
1398test_quota_compliance_udp_LDADD = \
1399 libgnunettransport.la \
1400 $(top_builddir)/src/hello/libgnunethello.la \
1401 $(top_builddir)/src/ats/libgnunetats.la \
1402 $(top_builddir)/src/nt/libgnunetnt.la \
1403 $(top_builddir)/src/util/libgnunetutil.la \
1404 libgnunettransporttesting.la
1405endif
1406
1407test_quota_compliance_unix_SOURCES = \
1408 test_quota_compliance.c
1409test_quota_compliance_unix_LDADD = \
1410 libgnunettransport.la \
1411 $(top_builddir)/src/hello/libgnunethello.la \
1412 $(top_builddir)/src/ats/libgnunetats.la \
1413 $(top_builddir)/src/nt/libgnunetnt.la \
1414 $(top_builddir)/src/util/libgnunetutil.la \
1415 libgnunettransporttesting.la
1416
1417test_quota_compliance_unix_asymmetric_SOURCES = \
1418 test_quota_compliance.c
1419test_quota_compliance_unix_asymmetric_LDADD = \
1420 libgnunettransport.la \
1421 $(top_builddir)/src/hello/libgnunethello.la \
1422 $(top_builddir)/src/ats/libgnunetats.la \
1423 $(top_builddir)/src/nt/libgnunetnt.la \
1424 $(top_builddir)/src/util/libgnunetutil.la \
1425 libgnunettransporttesting.la
1426
1427test_quota_compliance_wlan_SOURCES = \
1428 test_quota_compliance.c
1429test_quota_compliance_wlan_LDADD = \
1430 libgnunettransport.la \
1431 $(top_builddir)/src/hello/libgnunethello.la \
1432 $(top_builddir)/src/ats/libgnunetats.la \
1433 $(top_builddir)/src/nt/libgnunetnt.la \
1434 $(top_builddir)/src/util/libgnunetutil.la \
1435 libgnunettransporttesting.la
1436
1437test_quota_compliance_wlan_asymmetric_SOURCES = \
1438 test_quota_compliance.c
1439test_quota_compliance_wlan_asymmetric_LDADD = \
1440 libgnunettransport.la \
1441 $(top_builddir)/src/hello/libgnunethello.la \
1442 $(top_builddir)/src/ats/libgnunetats.la \
1443 $(top_builddir)/src/nt/libgnunetnt.la \
1444 $(top_builddir)/src/util/libgnunetutil.la \
1445 libgnunettransporttesting.la
1446
1447test_quota_compliance_bluetooth_SOURCES = \
1448 test_quota_compliance.c
1449test_quota_compliance_bluetooth_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_bluetooth_asymmetric_SOURCES = \
1458 test_quota_compliance.c
1459test_quota_compliance_bluetooth_asymmetric_LDADD = \
1460 libgnunettransport.la \
1461 $(top_builddir)/src/hello/libgnunethello.la \
1462 $(top_builddir)/src/ats/libgnunetats.la \
1463 $(top_builddir)/src/nt/libgnunetnt.la \
1464 $(top_builddir)/src/util/libgnunetutil.la \
1465 libgnunettransporttesting.la
1466
1467test_transport_api_multi_SOURCES = \
1468 test_transport_api.c
1469test_transport_api_multi_LDADD = \
1470 libgnunettransport.la \
1471 $(top_builddir)/src/hello/libgnunethello.la \
1472 $(top_builddir)/src/util/libgnunetutil.la \
1473 libgnunettransporttesting.la
1474
1475test_transport_api_monitor_peers_SOURCES = \
1476 test_transport_api_monitor_peers.c
1477test_transport_api_monitor_peers_LDADD = \
1478 libgnunettransport.la \
1479 $(top_builddir)/src/hello/libgnunethello.la \
1480 $(top_builddir)/src/util/libgnunetutil.la \
1481 libgnunettransporttesting.la
1482
1483test_transport_api_slow_ats_SOURCES = \
1484 test_transport_api.c
1485test_transport_api_slow_ats_LDADD = \
1486 libgnunettransport.la \
1487 $(top_builddir)/src/hello/libgnunethello.la \
1488 $(top_builddir)/src/util/libgnunetutil.la \
1489 libgnunettransporttesting.la
1490
1491
1492EXTRA_DIST = \
1493test_transport_simple_send_string.sh \
1494test_transport_simple_send.sh \
1495test_transport_simple_send_broadcast.sh \
1496test_transport_udp_backchannel.sh \
1497test_transport_simple_send_dv_circle.sh \
1498gnunet-transport-certificate-creation.in \
1499communicator-unix.conf \
1500test_plugin_hostkey \
1501test_plugin_hostkey.ecc \
1502test_delay \
1503template_cfg_peer1.conf\
1504template_cfg_peer2.conf\
1505test_plugin_transport_data.conf\
1506test_plugin_transport_data_udp.conf\
1507test_quota_compliance_data.conf\
1508test_quota_compliance_http_peer1.conf\
1509test_quota_compliance_http_peer2.conf\
1510test_quota_compliance_https_peer1.conf\
1511test_quota_compliance_https_peer2.conf\
1512test_quota_compliance_tcp_peer1.conf\
1513test_quota_compliance_tcp_peer2.conf\
1514test_quota_compliance_udp_peer1.conf\
1515test_quota_compliance_udp_peer2.conf\
1516test_quota_compliance_unix_peer1.conf\
1517test_quota_compliance_unix_peer2.conf\
1518test_quota_compliance_wlan_peer1.conf\
1519test_quota_compliance_wlan_peer2.conf\
1520test_quota_compliance_bluetooth_peer1.conf\
1521test_quota_compliance_bluetooth_peer2.conf\
1522test_quota_compliance_http_asymmetric_peer1.conf\
1523test_quota_compliance_http_asymmetric_peer2.conf\
1524test_quota_compliance_https_asymmetric_peer1.conf\
1525test_quota_compliance_https_asymmetric_peer2.conf\
1526test_quota_compliance_tcp_asymmetric_peer1.conf\
1527test_quota_compliance_tcp_asymmetric_peer2.conf\
1528test_quota_compliance_unix_asymmetric_peer1.conf\
1529test_quota_compliance_unix_asymmetric_peer2.conf\
1530test_quota_compliance_wlan_asymmetric_peer1.conf\
1531test_quota_compliance_wlan_asymmetric_peer2.conf\
1532test_quota_compliance_bluetooth_asymmetric_peer1.conf\
1533test_quota_compliance_bluetooth_asymmetric_peer2.conf\
1534test_transport_api_data.conf\
1535test_transport_api_blacklisting_tcp_peer1.conf \
1536test_transport_api_blacklisting_tcp_peer2.conf \
1537test_transport_api_http_peer1.conf\
1538test_transport_api_http_peer2.conf\
1539test_transport_api_https_peer1.conf\
1540test_transport_api_https_peer2.conf\
1541test_transport_api_limited_sockets_tcp_peer1.conf\
1542test_transport_api_limited_sockets_tcp_peer2.conf\
1543test_transport_api_timeout_tcp_peer1.conf\
1544test_transport_api_timeout_tcp_peer2.conf\
1545test_transport_api_multi_peer1.conf\
1546test_transport_api_multi_peer2.conf\
1547test_transport_api_restart_1peer_peer1.conf\
1548test_transport_api_restart_1peer_peer2.conf\
1549test_transport_api_reliability_http_peer1.conf\
1550test_transport_api_reliability_http_peer2.conf\
1551test_transport_api_reliability_https_peer1.conf\
1552test_transport_api_reliability_https_peer2.conf\
1553test_transport_api_reliability_tcp_nat_peer1.conf\
1554test_transport_api_reliability_tcp_nat_peer2.conf\
1555test_transport_api_reliability_tcp_peer1.conf\
1556test_transport_api_reliability_tcp_peer2.conf\
1557test_transport_api_reliability_wlan_peer1.conf\
1558test_transport_api_reliability_wlan_peer2.conf\
1559test_transport_api_reliability_bluetooth_peer1.conf\
1560test_transport_api_reliability_bluetooth_peer2.conf\
1561test_transport_api_manipulation_send_tcp_peer1.conf\
1562test_transport_api_manipulation_send_tcp_peer2.conf\
1563test_transport_api_manipulation_recv_tcp_peer1.conf\
1564test_transport_api_manipulation_recv_tcp_peer2.conf\
1565test_transport_api_manipulation_cfg_peer1.conf\
1566test_transport_api_manipulation_cfg_peer2.conf\
1567test_transport_api_restart_1peer_peer1.conf\
1568test_transport_api_restart_1peer_peer2.conf\
1569test_transport_api_restart_2peers_peer1.conf\
1570test_transport_api_restart_2peers_peer2.conf\
1571test_transport_api_tcp_nat_peer1.conf\
1572test_transport_api_tcp_nat_peer2.conf\
1573test_transport_api_tcp_peer1.conf\
1574test_transport_api_tcp_peer2.conf\
1575test_transport_api2_tcp_peer1.conf\
1576test_transport_api2_tcp_peer2.conf\
1577test_transport_api_udp_nat_peer1.conf\
1578test_transport_api_udp_nat_peer2.conf\
1579test_transport_api_udp_peer1.conf\
1580test_transport_api_udp_peer2.conf\
1581test_transport_api_timeout_udp_peer1.conf\
1582test_transport_api_timeout_udp_peer2.conf\
1583test_transport_api_unix_peer1.conf\
1584test_transport_api_unix_peer2.conf\
1585test_transport_api_unix_abstract_peer1.conf \
1586test_transport_api_unix_abstract_peer2.conf \
1587test_transport_api_timeout_unix_peer1.conf\
1588test_transport_api_timeout_unix_peer2.conf\
1589test_transport_api_timeout_wlan_peer1.conf \
1590test_transport_api_timeout_wlan_peer2.conf \
1591test_transport_api_timeout_bluetooth_peer1.conf\
1592test_transport_api_timeout_bluetooth_peer2.conf\
1593test_transport_api_reliability_udp_peer1.conf\
1594test_transport_api_reliability_udp_peer2.conf\
1595test_transport_api_reliability_http_xhr_peer1.conf\
1596test_transport_api_reliability_http_xhr_peer2.conf\
1597test_transport_api_reliability_https_xhr_peer1.conf\
1598test_transport_api_reliability_https_xhr_peer2.conf\
1599test_transport_api_reliability_unix_peer1.conf\
1600test_transport_api_reliability_unix_peer2.conf\
1601test_transport_api_reliability_wlan_peer1.conf\
1602test_transport_api_reliability_wlan_peer2.conf\
1603test_transport_api_unreliability_wlan_peer1.conf\
1604test_transport_api_unreliability_wlan_peer2.conf\
1605test_transport_api_reliability_bluetooth_peer1.conf\
1606test_transport_api_reliability_bluetooth_peer2.conf\
1607test_transport_api_wlan_peer1.conf\
1608test_transport_api_wlan_peer2.conf\
1609test_transport_api_bluetooth_peer1.conf\
1610test_transport_api_bluetooth_peer2.conf\
1611test_transport_api_monitor_peers_peer1.conf\
1612test_transport_api_monitor_peers_peer2.conf\
1613test_transport_api_monitor_validation_peer1.conf\
1614test_transport_api_monitor_validation_peer2.conf\
1615test_transport_defaults.conf\
1616test_transport_api_disconnect_tcp_peer1.conf\
1617test_transport_api_disconnect_tcp_peer2.conf\
1618test_transport_api_timeout_http_peer1.conf\
1619test_transport_api_timeout_http_peer2.conf\
1620test_transport_api_timeout_https_peer1.conf\
1621test_transport_api_timeout_https_peer2.conf\
1622test_transport_blacklisting_cfg_peer1.conf \
1623test_transport_blacklisting_cfg_peer2.conf \
1624test_transport_blacklisting_cfg_blp_peer1_full.conf\
1625test_transport_blacklisting_cfg_blp_peer1_plugin.conf \
1626test_transport_blacklisting_cfg_blp_peer2_full.conf\
1627test_transport_blacklisting_cfg_blp_peer2_plugin.conf \
1628test_transport_blacklisting_cfg_blp_peer1_multiple_plugins.conf \
1629test_transport_blacklisting_cfg_blp_peer2_multiple_plugins.conf \
1630test_transport_api_http_reverse_peer1.conf \
1631test_transport_api_http_reverse_peer2.conf \
1632perf_tcp_peer1.conf \
1633perf_tcp_peer2.conf \
1634test_transport_api_slow_ats_peer1.conf \
1635test_transport_api_slow_ats_peer2.conf \
1636 tcp_connection_legacy.c \
1637 tcp_server_mst_legacy.c \
1638 tcp_server_legacy.c \
1639 tcp_service_legacy.c \
1640test_communicator_unix_basic_peer1.conf \
1641test_communicator_unix_basic_peer2.conf \
1642test_communicator_tcp_basic_peer1.conf \
1643test_communicator_tcp_basic_peer2.conf \
1644test_communicator_udp_basic_peer1.conf \
1645test_communicator_udp_basic_peer2.conf \
1646test_communicator_tcp_rekey_peer1.conf \
1647test_communicator_tcp_rekey_peer2.conf \
1648test_communicator_udp_rekey_peer1.conf \
1649test_communicator_udp_rekey_peer2.conf \
1650test_communicator_udp_backchannel_peer1.conf \
1651test_communicator_udp_backchannel_peer2.conf \
1652test_communicator_tcp_bidirect_peer1.conf \
1653test_communicator_tcp_bidirect_peer2.conf
diff --git a/src/transport/NOTES b/src/transport/NOTES
deleted file mode 100644
index 41404e1f9..000000000
--- a/src/transport/NOTES
+++ /dev/null
@@ -1,46 +0,0 @@
1KEY DESIGN CHOICES:
2 - who decides which connections to keep/create?
3 => higher level session/key management!
4 - who enforces things like F2F topology, etc?
5 => higher level session/key management!
6 - who tracks all known HELLOs & validates?
7 => We validate, PEERINFO tracks!
8 - who advertises our HELLO?
9 => us! (need background job; previously: advertising)
10 - who advertises other peers HELLOs?
11 => higher level (core?)
12 - who does bootstrapping?
13 => bootstrap service (external!)
14 - who enforces inbound bandwidth limits?
15 => transport-service and plugins! (previously: core);
16 either by limiting reads (TCP) or discarding packets
17 (transport-service)
18 - who enforces outbound bandwidth limits?
19 => transport_api!
20 - who decides outbound bandwidth limits?
21 => other peer, via core (need authenticated limits!)
22 - who decides inbound bandwidth limits?
23 => core / apps above core (need trust info)
24 - cost function for transports is latency estimate in ms
25 => plugin provides latency data, transport-service
26 selects plugin(s) for transmission
27 - who is responsible for fragmentation?
28 => plugins! (may use common shared library)
29 - should we require UDP to be reliable?
30 => NO. There are other places that may (rarely)
31 use messages that we can not fix
32 - how do we access the 50% of service that we need for TCP/UDP
33 from service.c without code replication or getting 50%
34 that we do not want (i.e. shutdown, pid-file-writing, etc.)
35 => use GNUNET_SERVICE_start/stop functions!
36 - At what level do we manage timeouts?
37 => At the plugin (TCP connections),
38 transport-service (neighbours) and
39 core (sessions) level!
40 => All plugins have to disconnect before service-level
41 disconnect occurs
42 => We can have a plugin-connection die, but the session
43 survives!
44 => We can have a session die (no further authenticated
45 communication) even if the plugin thinks it is still
46 up!
diff --git a/src/transport/benchmark.sh b/src/transport/benchmark.sh
deleted file mode 100755
index a29e6ec2d..000000000
--- a/src/transport/benchmark.sh
+++ /dev/null
@@ -1,13 +0,0 @@
1#!/bin/sh
2
3for i in $(seq 1 0)
4do
5 echo RUN $i
6 ./test_transport_api_reliability_http
7done
8
9for i in $(seq 1 100)
10do
11 echo RUN $i
12 ./test_transport_api_reliability_https
13done
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/communicator.h b/src/transport/communicator.h
deleted file mode 100644
index 5ef43597d..000000000
--- a/src/transport/communicator.h
+++ /dev/null
@@ -1,138 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-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/communicator.h
23 * @brief common internal definitions for communicator services
24 * @author Christian Grothoff
25 */
26#ifndef COMMUNICATOR_H
27#define COMMUNICAOTR_H
28
29#include "gnunet_util_lib.h"
30#include "gnunet_protocols.h"
31
32GNUNET_NETWORK_STRUCT_BEGIN
33
34/**
35 * Message used to tell a communicator about a successful
36 * key exchange.
37 *
38 * Note that this style of KX acknowledgement typically only applies
39 * for communicators where the underlying network protocol is
40 * unidirectional and/or lacks cryptography. Furthermore, this is
41 * just the recommended "generic" style, communicators are always free
42 * to implement original designs that better fit their requirements.
43 */
44struct GNUNET_TRANSPORT_CommunicatorGenericKXConfirmation
45{
46 /**
47 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_KX_CONFIRMATION
48 */
49 struct GNUNET_MessageHeader header;
50
51 /**
52 * Timestamp from the original sender which identifies the original KX.
53 */
54 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
55
56 /**
57 * How long does the receiver of the KX believe that the address
58 * on which the KX was received will continue to be valid.
59 */
60 struct GNUNET_TIME_RelativeNBO validity;
61
62 /**
63 * Hash of the shared secret. Specific hash function may depend on
64 * the communicator's protocol details.
65 */
66 struct GNUNET_HashCode token;
67};
68
69
70/**
71 * Message used to tell a communicator about the receiver's
72 * flow control limits and to acknowledge receipt of certain
73 * messages.
74 *
75 * Note that a sender MAY choose to violate the flow-control
76 * limits provided in this message by a receiver, which may
77 * result in messages being lost (after all, transport is an
78 * unreliable channel). So if the sender violates these
79 * constraints, it should expect that the receive will simply
80 * discard the (partially) received "old" messages.
81 *
82 * This way, if a sender or receiver crashes, there is no protocol
83 * violation.
84 *
85 * Note that this style of flow control typically only applies
86 * for communicators where the underlying network protocol does
87 * not already implement flow control. Furthermore, this is
88 * just the recommended "generic" style, communicators are always
89 * free to implement original designs that better fit their
90 * requirements.
91 */
92struct GNUNET_TRANSPORT_CommunicatorGenericFCLimits
93{
94 /**
95 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_FC_LIMITS
96 */
97 struct GNUNET_MessageHeader header;
98
99 /**
100 * Maximum number of messages beyond the acknowledged message
101 * number that can still be transmitted concurrently without
102 * further acknowledgements.
103 */
104 uint32_t msg_window_size;
105
106 /**
107 * Up to which message number were all messages received.
108 */
109 uint64_t msg_cummulative_ack;
110
111 /**
112 * Maximum number of payload bytes beyond the acknowledged
113 * number of bytes can still be transmitted without further
114 * acknowledgements.
115 */
116 uint64_t bytes_window_size;
117
118 /**
119 * Cumulative acknowledgement for number of bytes received.
120 */
121 uint64_t bytes_cummulative_ack;
122
123 /**
124 * Followed by a variable-size bitfield for messages received
125 * beyond @e msg_cummulative_ack. Index at offset 0 must thus
126 * be zero, otherwise @e msg_cummulative_ack should be
127 * increased. Note that this field can be overall of 0 bytes.
128 * The variable-size bitfield must be a multiple of 64 bits
129 * long.
130 */
131 /* uint64_t msg_selective_ack_field[]; */
132};
133
134
135GNUNET_NETWORK_STRUCT_END
136
137/* end of communicator.h */
138#endif
diff --git a/src/transport/gnunet-communicator-tcp.c b/src/transport/gnunet-communicator-tcp.c
deleted file mode 100644
index 6d7a151ec..000000000
--- a/src/transport/gnunet-communicator-tcp.c
+++ /dev/null
@@ -1,3686 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2010-2014, 2018, 2019 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-communicator-tcp.c
23 * @brief Transport plugin using TCP.
24 * @author Christian Grothoff
25 *
26 * TODO:
27 * - support NAT connection reversal method (#5529)
28 * - support other TCP-specific NAT traversal methods (#5531)
29 */
30#include "platform.h"
31#include "gnunet_util_lib.h"
32#include "gnunet_core_service.h"
33#include "gnunet_peerstore_service.h"
34#include "gnunet_protocols.h"
35#include "gnunet_signatures.h"
36#include "gnunet_constants.h"
37#include "gnunet_nt_lib.h"
38#include "gnunet_nat_service.h"
39#include "gnunet_statistics_service.h"
40#include "gnunet_transport_communication_service.h"
41#include "gnunet_resolver_service.h"
42
43/**
44 * How long do we believe our addresses to remain up (before
45 * the other peer should revalidate).
46 */
47#define ADDRESS_VALIDITY_PERIOD \
48 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
49
50/**
51 * How many messages do we keep at most in the queue to the
52 * transport service before we start to drop (default,
53 * can be changed via the configuration file).
54 * Should be _below_ the level of the communicator API, as
55 * otherwise we may read messages just to have them dropped
56 * by the communicator API.
57 */
58#define DEFAULT_MAX_QUEUE_LENGTH 8
59
60/**
61 * Size of our IO buffers for ciphertext data. Must be at
62 * least UINT_MAX + sizeof (struct TCPBox).
63 */
64#define BUF_SIZE (2 * 64 * 1024 + sizeof(struct TCPBox))
65
66/**
67 * How often do we rekey based on time (at least)
68 */
69#define DEFAULT_REKEY_INTERVAL GNUNET_TIME_UNIT_DAYS
70
71/**
72 * How long do we wait until we must have received the initial KX?
73 */
74#define PROTO_QUEUE_TIMEOUT GNUNET_TIME_UNIT_MINUTES
75
76/**
77 * How often do we rekey based on number of bytes transmitted?
78 * (additionally randomized).
79 */
80#define REKEY_MAX_BYTES (1024LLU * 1024 * 1024 * 4LLU)
81
82/**
83 * Size of the initial key exchange message sent first in both
84 * directions.
85 */
86#define INITIAL_KX_SIZE \
87 (sizeof(struct GNUNET_CRYPTO_EcdhePublicKey) \
88 + sizeof(struct TCPConfirmation))
89
90/**
91 * Size of the initial core key exchange messages.
92 */
93#define INITIAL_CORE_KX_SIZE \
94 (sizeof(struct EphemeralKeyMessage) \
95 + sizeof(struct PingMessage) \
96 + sizeof(struct PongMessage))
97
98/**
99 * Address prefix used by the communicator.
100 */
101#define COMMUNICATOR_ADDRESS_PREFIX "tcp"
102
103/**
104 * Configuration section used by the communicator.
105 */
106#define COMMUNICATOR_CONFIG_SECTION "communicator-tcp"
107
108GNUNET_NETWORK_STRUCT_BEGIN
109
110
111/**
112 * Signature we use to verify that the ephemeral key was really chosen by
113 * the specified sender.
114 */
115struct TcpHandshakeSignature
116{
117 /**
118 * Purpose must be #GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_TCP_HANDSHAKE
119 */
120 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
121
122 /**
123 * Identity of the inititor of the TCP connection (TCP client).
124 */
125 struct GNUNET_PeerIdentity sender;
126
127 /**
128 * Presumed identity of the target of the TCP connection (TCP server)
129 */
130 struct GNUNET_PeerIdentity receiver;
131
132 /**
133 * Ephemeral key used by the @e sender.
134 */
135 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral;
136
137 /**
138 * Monotonic time of @e sender, to possibly help detect replay attacks
139 * (if receiver persists times by sender).
140 */
141 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
142
143 /**
144 * Challenge value used to protect against replay attack, if there is no stored monotonic time value.
145 */
146 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
147};
148
149/**
150 * Signature we use to verify that the ack from the receiver of the ephemeral key was really send by
151 * the specified sender.
152 */
153struct TcpHandshakeAckSignature
154{
155 /**
156 * Purpose must be #GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_TCP_HANDSHAKE_ACK
157 */
158 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
159
160 /**
161 * Identity of the inititor of the TCP connection (TCP client).
162 */
163 struct GNUNET_PeerIdentity sender;
164
165 /**
166 * Presumed identity of the target of the TCP connection (TCP server)
167 */
168 struct GNUNET_PeerIdentity receiver;
169
170 /**
171 * Monotonic time of @e sender, to possibly help detect replay attacks
172 * (if receiver persists times by sender).
173 */
174 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
175
176 /**
177 * Challenge value used to protect against replay attack, if there is no stored monotonic time value.
178 */
179 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
180};
181
182/**
183 * Encrypted continuation of TCP initial handshake.
184 */
185struct TCPConfirmation
186{
187 /**
188 * Sender's identity
189 */
190 struct GNUNET_PeerIdentity sender;
191
192 /**
193 * Sender's signature of type #GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_TCP_HANDSHAKE
194 */
195 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
196
197 /**
198 * Monotonic time of @e sender, to possibly help detect replay attacks
199 * (if receiver persists times by sender).
200 */
201 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
202
203 /**
204 * Challenge value used to protect against replay attack, if there is no stored monotonic time value.
205 */
206 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
207
208};
209
210/**
211 * Ack for the encrypted continuation of TCP initial handshake.
212 */
213struct TCPConfirmationAck
214{
215
216
217 /**
218 * Type is #GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_CONFIRMATION_ACK.
219 */
220 struct GNUNET_MessageHeader header;
221
222 /**
223 * Sender's identity
224 */
225 struct GNUNET_PeerIdentity sender;
226
227 /**
228 * Sender's signature of type #GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_TCP_HANDSHAKE_ACK
229 */
230 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
231
232 /**
233 * Monotonic time of @e sender, to possibly help detect replay attacks
234 * (if receiver persists times by sender).
235 */
236 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
237
238 /**
239 * Challenge value used to protect against replay attack, if there is no stored monotonic time value.
240 */
241 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
242
243};
244
245/**
246 * TCP message box. Always sent encrypted!
247 */
248struct TCPBox
249{
250 /**
251 * Type is #GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_BOX. Warning: the
252 * header size EXCLUDES the size of the `struct TCPBox`. We usually
253 * never do this, but here the payload may truly be 64k *after* the
254 * TCPBox (as we have no MTU)!!
255 */
256 struct GNUNET_MessageHeader header;
257
258 /**
259 * HMAC for the following encrypted message. Yes, we MUST use
260 * mac-then-encrypt here, as we want to hide the message sizes on
261 * the wire (zero plaintext design!). Using CTR mode, padding oracle
262 * attacks do not apply. Besides, due to the use of ephemeral keys
263 * (hopefully with effective replay protection from monotonic time!)
264 * the attacker is limited in using the oracle.
265 */
266 struct GNUNET_ShortHashCode hmac;
267
268 /* followed by as may bytes of payload as indicated in @e header,
269 excluding the TCPBox itself! */
270};
271
272
273/**
274 * TCP rekey message box. Always sent encrypted! Data after
275 * this message will use the new key.
276 */
277struct TCPRekey
278{
279 /**
280 * Type is #GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_REKEY.
281 */
282 struct GNUNET_MessageHeader header;
283
284 /**
285 * HMAC for the following encrypted message. Yes, we MUST use
286 * mac-then-encrypt here, as we want to hide the message sizes on
287 * the wire (zero plaintext design!). Using CTR mode padding oracle
288 * attacks do not apply. Besides, due to the use of ephemeral keys
289 * (hopefully with effective replay protection from monotonic time!)
290 * the attacker is limited in using the oracle.
291 */
292 struct GNUNET_ShortHashCode hmac;
293
294 /**
295 * New ephemeral key.
296 */
297 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral;
298
299 /**
300 * Sender's signature of type #GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_TCP_REKEY
301 */
302 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
303
304 /**
305 * Monotonic time of @e sender, to possibly help detect replay attacks
306 * (if receiver persists times by sender).
307 */
308 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
309};
310
311/**
312 * Signature we use to verify that the ephemeral key was really chosen by
313 * the specified sender.
314 */
315struct TcpRekeySignature
316{
317 /**
318 * Purpose must be #GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_TCP_REKEY
319 */
320 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
321
322 /**
323 * Identity of the inititor of the TCP connection (TCP client).
324 */
325 struct GNUNET_PeerIdentity sender;
326
327 /**
328 * Presumed identity of the target of the TCP connection (TCP server)
329 */
330 struct GNUNET_PeerIdentity receiver;
331
332 /**
333 * Ephemeral key used by the @e sender.
334 */
335 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral;
336
337 /**
338 * Monotonic time of @e sender, to possibly help detect replay attacks
339 * (if receiver persists times by sender).
340 */
341 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
342};
343
344/**
345 * TCP finish. Sender asks for the connection to be closed.
346 * Needed/useful in case we drop RST/FIN packets on the GNUnet
347 * port due to the possibility of malicious RST/FIN injection.
348 */
349struct TCPFinish
350{
351 /**
352 * Type is #GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_FINISH.
353 */
354 struct GNUNET_MessageHeader header;
355
356 /**
357 * HMAC for the following encrypted message. Yes, we MUST use
358 * mac-then-encrypt here, as we want to hide the message sizes on
359 * the wire (zero plaintext design!). Using CTR mode padding oracle
360 * attacks do not apply. Besides, due to the use of ephemeral keys
361 * (hopefully with effective replay protection from monotonic time!)
362 * the attacker is limited in using the oracle.
363 */
364 struct GNUNET_ShortHashCode hmac;
365};
366
367
368GNUNET_NETWORK_STRUCT_END
369
370/**
371 * Struct to use as closure.
372 */
373struct ListenTask
374{
375 /**
376 * ID of listen task
377 */
378 struct GNUNET_SCHEDULER_Task *listen_task;
379
380 /**
381 * Listen socket.
382 */
383 struct GNUNET_NETWORK_Handle *listen_sock;
384};
385
386/**
387 * Handle for a queue.
388 */
389struct Queue
390{
391 /**
392 * To whom are we talking to.
393 */
394 struct GNUNET_PeerIdentity target;
395
396 /**
397 * Listen socket.
398 */
399 struct GNUNET_NETWORK_Handle *listen_sock;
400
401 /**
402 * socket that we transmit all data with on this queue
403 */
404 struct GNUNET_NETWORK_Handle *sock;
405
406 /**
407 * cipher for decryption of incoming data.
408 */
409 gcry_cipher_hd_t in_cipher;
410
411 /**
412 * cipher for encryption of outgoing data.
413 */
414 gcry_cipher_hd_t out_cipher;
415
416 /**
417 * Shared secret for HMAC verification on incoming data.
418 */
419 struct GNUNET_HashCode in_hmac;
420
421 /**
422 * Shared secret for HMAC generation on outgoing data, ratcheted after
423 * each operation.
424 */
425 struct GNUNET_HashCode out_hmac;
426
427 /**
428 * Our ephemeral key. Stored here temporarily during rekeying / key
429 * generation.
430 */
431 struct GNUNET_CRYPTO_EcdhePrivateKey ephemeral;
432
433 /**
434 * ID of read task for this connection.
435 */
436 struct GNUNET_SCHEDULER_Task *read_task;
437
438 /**
439 * ID of write task for this connection.
440 */
441 struct GNUNET_SCHEDULER_Task *write_task;
442
443 /**
444 * Address of the other peer.
445 */
446 struct sockaddr *address;
447
448 /**
449 * How many more bytes may we sent with the current @e out_cipher
450 * before we should rekey?
451 */
452 uint64_t rekey_left_bytes;
453
454 /**
455 * Until what time may we sent with the current @e out_cipher
456 * before we should rekey?
457 */
458 struct GNUNET_TIME_Absolute rekey_time;
459
460 /**
461 * Length of the address.
462 */
463 socklen_t address_len;
464
465 /**
466 * Message queue we are providing for the #ch.
467 */
468 struct GNUNET_MQ_Handle *mq;
469
470 /**
471 * handle for this queue with the #ch.
472 */
473 struct GNUNET_TRANSPORT_QueueHandle *qh;
474
475 /**
476 * Number of bytes we currently have in our write queue.
477 */
478 unsigned long long bytes_in_queue;
479
480 /**
481 * Buffer for reading ciphertext from network into.
482 */
483 char cread_buf[BUF_SIZE];
484
485 /**
486 * buffer for writing ciphertext to network.
487 */
488 char cwrite_buf[BUF_SIZE];
489
490 /**
491 * Plaintext buffer for decrypted plaintext.
492 */
493 char pread_buf[UINT16_MAX + 1 + sizeof(struct TCPBox)];
494
495 /**
496 * Plaintext buffer for messages to be encrypted.
497 */
498 char pwrite_buf[UINT16_MAX + 1 + sizeof(struct TCPBox)];
499
500 /**
501 * At which offset in the ciphertext read buffer should we
502 * append more ciphertext for transmission next?
503 */
504 size_t cread_off;
505
506 /**
507 * At which offset in the ciphertext write buffer should we
508 * append more ciphertext from reading next?
509 */
510 size_t cwrite_off;
511
512 /**
513 * At which offset in the plaintext input buffer should we
514 * append more plaintext from decryption next?
515 */
516 size_t pread_off;
517
518 /**
519 * At which offset in the plaintext output buffer should we
520 * append more plaintext for encryption next?
521 */
522 size_t pwrite_off;
523
524 /**
525 * Timeout for this queue.
526 */
527 struct GNUNET_TIME_Absolute timeout;
528
529 /**
530 * How may messages did we pass from this queue to CORE for which we
531 * have yet to receive an acknoweldgement that CORE is done with
532 * them? If "large" (or even just non-zero), we should throttle
533 * reading to provide flow control. See also #DEFAULT_MAX_QUEUE_LENGTH
534 * and #max_queue_length.
535 */
536 unsigned int backpressure;
537
538 /**
539 * Which network type does this queue use?
540 */
541 enum GNUNET_NetworkType nt;
542
543 /**
544 * The connection status of this queue.
545 */
546 enum GNUNET_TRANSPORT_ConnectionStatus cs;
547
548 /**
549 * Is MQ awaiting a #GNUNET_MQ_impl_send_continue() call?
550 */
551 int mq_awaits_continue;
552
553 /**
554 * Did we enqueue a finish message and are closing down the queue?
555 */
556 int finishing;
557
558 /**
559 * Did we technically destroy this queue, but kept the allocation
560 * around because of @e backpressure not being zero yet? Used
561 * simply to delay the final #GNUNET_free() operation until
562 * #core_read_finished_cb() has been called.
563 */
564 int destroyed;
565
566 /**
567 * #GNUNET_YES if we just rekeyed and must thus possibly
568 * re-decrypt ciphertext.
569 */
570 int rekeyed;
571
572 /**
573 * Monotonic time value for rekey message.
574 */
575 struct GNUNET_TIME_AbsoluteNBO rekey_monotonic_time;
576
577 /**
578 * Monotonic time value for handshake message.
579 */
580 struct GNUNET_TIME_AbsoluteNBO handshake_monotonic_time;
581
582 /**
583 * Monotonic time value for handshake ack message.
584 */
585 struct GNUNET_TIME_AbsoluteNBO handshake_ack_monotonic_time;
586
587 /**
588 * Challenge value used to protect against replay attack, if there is no stored monotonic time value.
589 */
590 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
591
592 /**
593 * Challenge value received. In case of inbound connection we have to remember the value, because we send the challenge back later after we received the GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_CONFIRMATION_ACK.
594 */
595 struct GNUNET_CRYPTO_ChallengeNonceP challenge_received;
596
597 /**
598 * Iteration Context for retrieving the monotonic time send with key for rekeying.
599 */
600 struct GNUNET_PEERSTORE_IterateContext *rekey_monotime_get;
601
602 /**
603 * Iteration Context for retrieving the monotonic time send with the handshake.
604 */
605 struct GNUNET_PEERSTORE_IterateContext *handshake_monotime_get;
606
607 /**
608 * Iteration Context for retrieving the monotonic time send with the handshake ack.
609 */
610 struct GNUNET_PEERSTORE_IterateContext *handshake_ack_monotime_get;
611
612 /**
613 * Store Context for retrieving the monotonic time send with key for rekeying.
614 */
615 struct GNUNET_PEERSTORE_StoreContext *rekey_monotime_sc;
616
617 /**
618 * Store Context for retrieving the monotonic time send with the handshake.
619 */
620 struct GNUNET_PEERSTORE_StoreContext *handshake_monotime_sc;
621
622 /**
623 * Store Context for retrieving the monotonic time send with the handshake ack.
624 */
625 struct GNUNET_PEERSTORE_StoreContext *handshake_ack_monotime_sc;
626};
627
628
629/**
630 * Handle for an incoming connection where we do not yet have enough
631 * information to setup a full queue.
632 */
633struct ProtoQueue
634{
635 /**
636 * Kept in a DLL.
637 */
638 struct ProtoQueue *next;
639
640 /**
641 * Kept in a DLL.
642 */
643 struct ProtoQueue *prev;
644
645 /**
646 * Listen socket.
647 */
648 struct GNUNET_NETWORK_Handle *listen_sock;
649
650 /**
651 * socket that we transmit all data with on this queue
652 */
653 struct GNUNET_NETWORK_Handle *sock;
654
655 /**
656 * ID of read task for this connection.
657 */
658 struct GNUNET_SCHEDULER_Task *read_task;
659
660 /**
661 * Address of the other peer.
662 */
663 struct sockaddr *address;
664
665 /**
666 * Length of the address.
667 */
668 socklen_t address_len;
669
670 /**
671 * Timeout for this protoqueue.
672 */
673 struct GNUNET_TIME_Absolute timeout;
674
675 /**
676 * Buffer for reading all the information we need to upgrade from
677 * protoqueue to queue.
678 */
679 char ibuf[INITIAL_KX_SIZE];
680
681 /**
682 * Current offset for reading into @e ibuf.
683 */
684 size_t ibuf_off;
685};
686
687/**
688 * In case of port only configuration we like to bind to ipv4 and ipv6 addresses.
689 */
690struct PortOnlyIpv4Ipv6
691{
692 /**
693 * Ipv4 address we like to bind to.
694 */
695 struct sockaddr *addr_ipv4;
696
697 /**
698 * Length of ipv4 address.
699 */
700 socklen_t addr_len_ipv4;
701
702 /**
703 * Ipv6 address we like to bind to.
704 */
705 struct sockaddr *addr_ipv6;
706
707 /**
708 * Length of ipv6 address.
709 */
710 socklen_t addr_len_ipv6;
711
712};
713
714/**
715 * DLL to store the addresses we like to register at NAT service.
716 */
717struct Addresses
718{
719 /**
720 * Kept in a DLL.
721 */
722 struct Addresses *next;
723
724 /**
725 * Kept in a DLL.
726 */
727 struct Addresses *prev;
728
729 /**
730 * Address we like to register at NAT service.
731 */
732 struct sockaddr *addr;
733
734 /**
735 * Length of address we like to register at NAT service.
736 */
737 socklen_t addr_len;
738
739};
740
741
742/**
743 * Maximum queue length before we stop reading towards the transport service.
744 */
745static unsigned long long max_queue_length;
746
747/**
748 * For logging statistics.
749 */
750static struct GNUNET_STATISTICS_Handle *stats;
751
752/**
753 * Our environment.
754 */
755static struct GNUNET_TRANSPORT_CommunicatorHandle *ch;
756
757/**
758 * Queues (map from peer identity to `struct Queue`)
759 */
760static struct GNUNET_CONTAINER_MultiPeerMap *queue_map;
761
762/**
763 * ListenTasks (map from socket to `struct ListenTask`)
764 */
765static struct GNUNET_CONTAINER_MultiHashMap *lt_map;
766
767/**
768 * Our public key.
769 */
770static struct GNUNET_PeerIdentity my_identity;
771
772/**
773 * The rekey interval
774 */
775static struct GNUNET_TIME_Relative rekey_interval;
776
777/**
778 * Our private key.
779 */
780static struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
781
782/**
783 * Our configuration.
784 */
785static const struct GNUNET_CONFIGURATION_Handle *cfg;
786
787/**
788 * Network scanner to determine network types.
789 */
790static struct GNUNET_NT_InterfaceScanner *is;
791
792/**
793 * Connection to NAT service.
794 */
795static struct GNUNET_NAT_Handle *nat;
796
797/**
798 * Protoqueues DLL head.
799 */
800static struct ProtoQueue *proto_head;
801
802/**
803 * Protoqueues DLL tail.
804 */
805static struct ProtoQueue *proto_tail;
806
807/**
808 * Handle for DNS lookup of bindto address
809 */
810struct GNUNET_RESOLVER_RequestHandle *resolve_request_handle;
811
812/**
813 * Head of DLL with addresses we like to register at NAT servcie.
814 */
815struct Addresses *addrs_head;
816
817/**
818 * Head of DLL with addresses we like to register at NAT servcie.
819 */
820struct Addresses *addrs_tail;
821
822/**
823 * Head of DLL with ListenTasks.
824 */
825struct ListenTask *lts_head;
826
827/**
828 * Head of DLL with ListenTask.
829 */
830struct ListenTask *lts_tail;
831
832/**
833 * Number of addresses in the DLL for register at NAT service.
834 */
835int addrs_lens;
836
837/**
838 * Size of data received without KX challenge played back.
839 */
840// TODO remove?
841size_t unverified_size;
842
843/**
844 * Database for peer's HELLOs.
845 */
846static struct GNUNET_PEERSTORE_Handle *peerstore;
847
848/**
849 * A flag indicating we are already doing a shutdown.
850 */
851int shutdown_running = GNUNET_NO;
852
853/**
854 * The port the communicator should be assigned to.
855 */
856unsigned int bind_port;
857
858/**
859 * We have been notified that our listen socket has something to
860 * read. Do the read and reschedule this function to be called again
861 * once more is available.
862 *
863 * @param cls NULL
864 */
865static void
866listen_cb (void *cls);
867
868/**
869 * Functions with this signature are called whenever we need
870 * to close a queue due to a disconnect or failure to
871 * establish a connection.
872 *
873 * @param queue queue to close down
874 */
875static void
876queue_destroy (struct Queue *queue)
877{
878 struct ListenTask *lt = NULL;
879 struct GNUNET_HashCode h_sock;
880 int sockfd;
881
882 if (NULL != queue->listen_sock)
883 {
884 sockfd = GNUNET_NETWORK_get_fd (queue->listen_sock);
885 GNUNET_CRYPTO_hash (&sockfd,
886 sizeof(int),
887 &h_sock);
888
889 lt = GNUNET_CONTAINER_multihashmap_get (lt_map, &h_sock);
890 }
891
892 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
893 "Disconnecting queue for peer `%s'\n",
894 GNUNET_i2s (&queue->target));
895 if (NULL != queue->rekey_monotime_sc)
896 {
897 GNUNET_PEERSTORE_store_cancel (queue->rekey_monotime_sc);
898 queue->rekey_monotime_sc = NULL;
899 }
900 if (NULL != queue->handshake_monotime_sc)
901 {
902 GNUNET_PEERSTORE_store_cancel (queue->handshake_monotime_sc);
903 queue->handshake_monotime_sc = NULL;
904 }
905 if (NULL != queue->handshake_ack_monotime_sc)
906 {
907 GNUNET_PEERSTORE_store_cancel (queue->handshake_ack_monotime_sc);
908 queue->handshake_ack_monotime_sc = NULL;
909 }
910 if (NULL != queue->rekey_monotime_get)
911 {
912 GNUNET_PEERSTORE_iterate_cancel (queue->rekey_monotime_get);
913 queue->rekey_monotime_get = NULL;
914 }
915 if (NULL != queue->handshake_monotime_get)
916 {
917 GNUNET_PEERSTORE_iterate_cancel (queue->handshake_monotime_get);
918 queue->handshake_monotime_get = NULL;
919 }
920 if (NULL != queue->handshake_ack_monotime_get)
921 {
922 GNUNET_PEERSTORE_iterate_cancel (queue->handshake_ack_monotime_get);
923 queue->handshake_ack_monotime_get = NULL;
924 }
925 if (NULL != queue->qh)
926 {
927 GNUNET_TRANSPORT_communicator_mq_del (queue->qh);
928 queue->qh = NULL;
929 }
930 GNUNET_assert (
931 GNUNET_YES ==
932 GNUNET_CONTAINER_multipeermap_remove (queue_map, &queue->target, queue));
933 GNUNET_STATISTICS_set (stats,
934 "# queues active",
935 GNUNET_CONTAINER_multipeermap_size (queue_map),
936 GNUNET_NO);
937 if (NULL != queue->read_task)
938 {
939 GNUNET_SCHEDULER_cancel (queue->read_task);
940 queue->read_task = NULL;
941 }
942 if (NULL != queue->write_task)
943 {
944 GNUNET_SCHEDULER_cancel (queue->write_task);
945 queue->write_task = NULL;
946 }
947 if (GNUNET_SYSERR == GNUNET_NETWORK_socket_close (queue->sock))
948 {
949 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
950 "closing socket failed\n");
951 }
952 gcry_cipher_close (queue->in_cipher);
953 gcry_cipher_close (queue->out_cipher);
954 GNUNET_free (queue->address);
955 if (0 != queue->backpressure)
956 queue->destroyed = GNUNET_YES;
957 else
958 GNUNET_free (queue);
959
960 if (NULL == lt)
961 return;
962
963 if ((! shutdown_running) && (NULL == lt->listen_task))
964 {
965 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
966 "add read net listen\n");
967 lt->listen_task = GNUNET_SCHEDULER_add_read_net (
968 GNUNET_TIME_UNIT_FOREVER_REL,
969 lt->listen_sock,
970 &listen_cb,
971 lt);
972 }
973 else
974 GNUNET_free (lt);
975}
976
977
978/**
979 * Compute @a mac over @a buf, and ratched the @a hmac_secret.
980 *
981 * @param[in,out] hmac_secret secret for HMAC calculation
982 * @param buf buffer to MAC
983 * @param buf_size number of bytes in @a buf
984 * @param smac[out] where to write the HMAC
985 */
986static void
987calculate_hmac (struct GNUNET_HashCode *hmac_secret,
988 const void *buf,
989 size_t buf_size,
990 struct GNUNET_ShortHashCode *smac)
991{
992 struct GNUNET_HashCode mac;
993
994 GNUNET_CRYPTO_hmac_raw (hmac_secret,
995 sizeof(struct GNUNET_HashCode),
996 buf,
997 buf_size,
998 &mac);
999 /* truncate to `struct GNUNET_ShortHashCode` */
1000 memcpy (smac, &mac, sizeof(struct GNUNET_ShortHashCode));
1001 /* ratchet hmac key */
1002 GNUNET_CRYPTO_hash (hmac_secret,
1003 sizeof(struct GNUNET_HashCode),
1004 hmac_secret);
1005}
1006
1007
1008/**
1009 * Append a 'finish' message to the outgoing transmission. Once the
1010 * finish has been transmitted, destroy the queue.
1011 *
1012 * @param queue queue to shut down nicely
1013 */
1014static void
1015queue_finish (struct Queue *queue)
1016{
1017 struct TCPFinish fin;
1018
1019 memset (&fin, 0, sizeof(fin));
1020 fin.header.size = htons (sizeof(fin));
1021 fin.header.type = htons (GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_FINISH);
1022 calculate_hmac (&queue->out_hmac, &fin, sizeof(fin), &fin.hmac);
1023 /* if there is any message left in pwrite_buf, we
1024 overwrite it (possibly dropping the last message
1025 from CORE hard here) */
1026 memcpy (queue->pwrite_buf, &fin, sizeof(fin));
1027 queue->pwrite_off = sizeof(fin);
1028 /* This flag will ensure that #queue_write() no longer
1029 notifies CORE about the possibility of sending
1030 more data, and that #queue_write() will call
1031 #queue_destroy() once the @c fin was fully written. */
1032 queue->finishing = GNUNET_YES;
1033}
1034
1035
1036/**
1037 * Increment queue timeout due to activity. We do not immediately
1038 * notify the monitor here as that might generate excessive
1039 * signalling.
1040 *
1041 * @param queue queue for which the timeout should be rescheduled
1042 */
1043static void
1044reschedule_queue_timeout (struct Queue *queue)
1045{
1046 queue->timeout =
1047 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1048}
1049
1050
1051/**
1052 * Queue read task. If we hit the timeout, disconnect it
1053 *
1054 * @param cls the `struct Queue *` to disconnect
1055 */
1056static void
1057queue_read (void *cls);
1058
1059
1060/**
1061 * Core tells us it is done processing a message that transport
1062 * received on a queue with status @a success.
1063 *
1064 * @param cls a `struct Queue *` where the message originally came from
1065 * @param success #GNUNET_OK on success
1066 */
1067static void
1068core_read_finished_cb (void *cls, int success)
1069{
1070 struct Queue *queue = cls;
1071 if (GNUNET_OK != success)
1072 GNUNET_STATISTICS_update (stats,
1073 "# messages lost in communicator API towards CORE",
1074 1,
1075 GNUNET_NO);
1076 if (NULL == queue)
1077 return;
1078
1079 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1080 "backpressure %u\n",
1081 queue->backpressure);
1082
1083 queue->backpressure--;
1084 /* handle deferred queue destruction */
1085 if ((queue->destroyed) && (0 == queue->backpressure))
1086 {
1087 GNUNET_free (queue);
1088 return;
1089 }
1090 else if (GNUNET_YES != queue->destroyed)
1091 {
1092 reschedule_queue_timeout (queue);
1093 /* possibly unchoke reading, now that CORE made progress */
1094 if (NULL == queue->read_task)
1095 queue->read_task =
1096 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_absolute_get_remaining (
1097 queue->timeout),
1098 queue->sock,
1099 &queue_read,
1100 queue);
1101 }
1102}
1103
1104
1105/**
1106 * We received @a plaintext_len bytes of @a plaintext on @a queue.
1107 * Pass it on to CORE. If transmission is actually happening,
1108 * increase backpressure counter.
1109 *
1110 * @param queue the queue that received the plaintext
1111 * @param plaintext the plaintext that was received
1112 * @param plaintext_len number of bytes of plaintext received
1113 */
1114static void
1115pass_plaintext_to_core (struct Queue *queue,
1116 const void *plaintext,
1117 size_t plaintext_len)
1118{
1119 const struct GNUNET_MessageHeader *hdr = plaintext;
1120 int ret;
1121
1122 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1123 "pass message from %s to core\n",
1124 GNUNET_i2s (&queue->target));
1125
1126 if (ntohs (hdr->size) != plaintext_len)
1127 {
1128 /* NOTE: If we ever allow multiple CORE messages in one
1129 BOX, this will have to change! */
1130 GNUNET_break (0);
1131 return;
1132 }
1133 ret = GNUNET_TRANSPORT_communicator_receive (ch,
1134 &queue->target,
1135 hdr,
1136 ADDRESS_VALIDITY_PERIOD,
1137 &core_read_finished_cb,
1138 queue);
1139 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1140 "passed to core\n");
1141 if (GNUNET_OK == ret)
1142 queue->backpressure++;
1143 GNUNET_break (GNUNET_NO != ret); /* backpressure not working!? */
1144 if (GNUNET_SYSERR == ret)
1145 GNUNET_STATISTICS_update (stats,
1146 "# bytes lost due to CORE not running",
1147 plaintext_len,
1148 GNUNET_NO);
1149}
1150
1151
1152/**
1153 * Setup @a cipher based on shared secret @a dh and decrypting
1154 * peer @a pid.
1155 *
1156 * @param dh shared secret
1157 * @param pid decrypting peer's identity
1158 * @param cipher[out] cipher to initialize
1159 * @param hmac_key[out] HMAC key to initialize
1160 */
1161static void
1162setup_cipher (const struct GNUNET_HashCode *dh,
1163 const struct GNUNET_PeerIdentity *pid,
1164 gcry_cipher_hd_t *cipher,
1165 struct GNUNET_HashCode *hmac_key)
1166{
1167 char key[256 / 8];
1168 char ctr[128 / 8];
1169
1170 GNUNET_assert (0 == gcry_cipher_open (cipher,
1171 GCRY_CIPHER_AES256 /* low level: go for speed */,
1172 GCRY_CIPHER_MODE_CTR,
1173 0 /* flags */));
1174 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_kdf (key,
1175 sizeof(key),
1176 "TCP-key",
1177 strlen ("TCP-key"),
1178 dh,
1179 sizeof(*dh),
1180 pid,
1181 sizeof(*pid),
1182 NULL,
1183 0));
1184 GNUNET_assert (0 == gcry_cipher_setkey (*cipher, key, sizeof(key)));
1185 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_kdf (ctr,
1186 sizeof(ctr),
1187 "TCP-ctr",
1188 strlen ("TCP-ctr"),
1189 dh,
1190 sizeof(*dh),
1191 pid,
1192 sizeof(*pid),
1193 NULL,
1194 0));
1195 gcry_cipher_setctr (*cipher, ctr, sizeof(ctr));
1196 GNUNET_assert (GNUNET_YES ==
1197 GNUNET_CRYPTO_kdf (hmac_key,
1198 sizeof(struct GNUNET_HashCode),
1199 "TCP-hmac",
1200 strlen ("TCP-hmac"),
1201 dh,
1202 sizeof(*dh),
1203 pid,
1204 sizeof(*pid),
1205 NULL,
1206 0));
1207}
1208
1209
1210/**
1211 * Callback called when peerstore store operation for rekey monotime value is finished.
1212 * @param cls Queue context the store operation was executed.
1213 * @param success Store operation was successful (GNUNET_OK) or not.
1214 */
1215static void
1216rekey_monotime_store_cb (void *cls, int success)
1217{
1218 struct Queue *queue = cls;
1219 if (GNUNET_OK != success)
1220 {
1221 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1222 "Failed to store rekey monotonic time in PEERSTORE!\n");
1223 }
1224 queue->rekey_monotime_sc = NULL;
1225}
1226
1227
1228/**
1229 * Callback called by peerstore when records for GNUNET_PEERSTORE_TRANSPORT_TCP_COMMUNICATOR_REKEY
1230 * where found.
1231 * @param cls Queue context the store operation was executed.
1232 * @param record The record found or NULL if there is no record left.
1233 * @param emsg Message from peerstore.
1234 */
1235static void
1236rekey_monotime_cb (void *cls,
1237 const struct GNUNET_PEERSTORE_Record *record,
1238 const char *emsg)
1239{
1240 struct Queue *queue = cls;
1241 struct GNUNET_TIME_AbsoluteNBO *mtbe;
1242 struct GNUNET_TIME_Absolute mt;
1243 const struct GNUNET_PeerIdentity *pid;
1244 struct GNUNET_TIME_AbsoluteNBO *rekey_monotonic_time;
1245
1246 (void) emsg;
1247
1248 rekey_monotonic_time = &queue->rekey_monotonic_time;
1249 pid = &queue->target;
1250 if (NULL == record)
1251 {
1252 queue->rekey_monotime_get = NULL;
1253 return;
1254 }
1255 if (sizeof(*mtbe) != record->value_size)
1256 {
1257 GNUNET_break (0);
1258 return;
1259 }
1260 mtbe = record->value;
1261 mt = GNUNET_TIME_absolute_ntoh (*mtbe);
1262 if (mt.abs_value_us > GNUNET_TIME_absolute_ntoh (
1263 queue->rekey_monotonic_time).abs_value_us)
1264 {
1265 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1266 "Queue from %s dropped, rekey monotime in the past\n",
1267 GNUNET_i2s (&queue->target));
1268 GNUNET_break (0);
1269 queue_finish (queue);
1270 return;
1271 }
1272 queue->rekey_monotime_sc = GNUNET_PEERSTORE_store (peerstore,
1273 "transport_tcp_communicator",
1274 pid,
1275 GNUNET_PEERSTORE_TRANSPORT_TCP_COMMUNICATOR_REKEY,
1276 rekey_monotonic_time,
1277 sizeof(*
1278 rekey_monotonic_time),
1279 GNUNET_TIME_UNIT_FOREVER_ABS,
1280 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
1281 &rekey_monotime_store_cb,
1282 queue);
1283}
1284
1285
1286/**
1287 * Setup cipher of @a queue for decryption.
1288 *
1289 * @param ephemeral ephemeral key we received from the other peer
1290 * @param queue[in,out] queue to initialize decryption cipher for
1291 */
1292static void
1293setup_in_cipher (const struct GNUNET_CRYPTO_EcdhePublicKey *ephemeral,
1294 struct Queue *queue)
1295{
1296 struct GNUNET_HashCode dh;
1297
1298 GNUNET_CRYPTO_eddsa_ecdh (my_private_key, ephemeral, &dh);
1299 setup_cipher (&dh, &my_identity, &queue->in_cipher, &queue->in_hmac);
1300}
1301
1302
1303/**
1304 * Handle @a rekey message on @a queue. The message was already
1305 * HMAC'ed, but we should additionally still check the signature.
1306 * Then we need to stop the old cipher and start afresh.
1307 *
1308 * @param queue the queue @a rekey was received on
1309 * @param rekey the rekey message
1310 */
1311static void
1312do_rekey (struct Queue *queue, const struct TCPRekey *rekey)
1313{
1314 struct TcpRekeySignature thp;
1315
1316 thp.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_TCP_REKEY);
1317 thp.purpose.size = htonl (sizeof(thp));
1318 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1319 "do_rekey size %u\n",
1320 thp.purpose.size);
1321 thp.sender = queue->target;
1322 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1323 "sender %s\n",
1324 GNUNET_p2s (&thp.sender.public_key));
1325 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1326 "sender %s\n",
1327 GNUNET_p2s (&queue->target.public_key));
1328 thp.receiver = my_identity;
1329 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1330 "receiver %s\n",
1331 GNUNET_p2s (&thp.receiver.public_key));
1332 thp.ephemeral = rekey->ephemeral;
1333 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1334 "ephemeral %s\n",
1335 GNUNET_e2s (&thp.ephemeral));
1336 thp.monotonic_time = rekey->monotonic_time;
1337 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1338 "time %s\n",
1339 GNUNET_STRINGS_absolute_time_to_string (
1340 GNUNET_TIME_absolute_ntoh (thp.monotonic_time)));
1341 GNUNET_assert (ntohl ((&thp)->purpose.size) == sizeof (*(&thp)));
1342 if (GNUNET_OK !=
1343 GNUNET_CRYPTO_eddsa_verify (
1344 GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_TCP_REKEY,
1345 &thp,
1346 &rekey->sender_sig,
1347 &queue->target.public_key))
1348 {
1349 GNUNET_break (0);
1350 queue_finish (queue);
1351 return;
1352 }
1353 queue->rekey_monotonic_time = rekey->monotonic_time;
1354 queue->rekey_monotime_get = GNUNET_PEERSTORE_iterate (peerstore,
1355 "transport_tcp_communicator",
1356 &queue->target,
1357 GNUNET_PEERSTORE_TRANSPORT_TCP_COMMUNICATOR_REKEY,
1358 &rekey_monotime_cb,
1359 queue);
1360 gcry_cipher_close (queue->in_cipher);
1361 queue->rekeyed = GNUNET_YES;
1362 setup_in_cipher (&rekey->ephemeral, queue);
1363}
1364
1365
1366/**
1367 * Callback called when peerstore store operation for handshake ack monotime value is finished.
1368 * @param cls Queue context the store operation was executed.
1369 * @param success Store operation was successful (GNUNET_OK) or not.
1370 */
1371static void
1372handshake_ack_monotime_store_cb (void *cls, int success)
1373{
1374 struct Queue *queue = cls;
1375
1376 if (GNUNET_OK != success)
1377 {
1378 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1379 "Failed to store handshake ack monotonic time in PEERSTORE!\n");
1380 }
1381 queue->handshake_ack_monotime_sc = NULL;
1382}
1383
1384
1385/**
1386 * Callback called by peerstore when records for GNUNET_PEERSTORE_TRANSPORT_TCP_COMMUNICATOR_HANDSHAKE_ACK
1387 * where found.
1388 * @param cls Queue context the store operation was executed.
1389 * @param record The record found or NULL if there is no record left.
1390 * @param emsg Message from peerstore.
1391 */
1392static void
1393handshake_ack_monotime_cb (void *cls,
1394 const struct GNUNET_PEERSTORE_Record *record,
1395 const char *emsg)
1396{
1397 struct Queue *queue = cls;
1398 struct GNUNET_TIME_AbsoluteNBO *mtbe;
1399 struct GNUNET_TIME_Absolute mt;
1400 const struct GNUNET_PeerIdentity *pid;
1401 struct GNUNET_TIME_AbsoluteNBO *handshake_ack_monotonic_time;
1402
1403 (void) emsg;
1404
1405 handshake_ack_monotonic_time = &queue->handshake_ack_monotonic_time;
1406 pid = &queue->target;
1407 if (NULL == record)
1408 {
1409 queue->handshake_ack_monotime_get = NULL;
1410 return;
1411 }
1412 if (sizeof(*mtbe) != record->value_size)
1413 {
1414 GNUNET_break (0);
1415 return;
1416 }
1417 mtbe = record->value;
1418 mt = GNUNET_TIME_absolute_ntoh (*mtbe);
1419 if (mt.abs_value_us > GNUNET_TIME_absolute_ntoh (
1420 queue->handshake_ack_monotonic_time).abs_value_us)
1421 {
1422 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1423 "Queue from %s dropped, handshake ack monotime in the past\n",
1424 GNUNET_i2s (&queue->target));
1425 GNUNET_break (0);
1426 queue_finish (queue);
1427 return;
1428 }
1429 queue->handshake_ack_monotime_sc =
1430 GNUNET_PEERSTORE_store (peerstore,
1431 "transport_tcp_communicator",
1432 pid,
1433 GNUNET_PEERSTORE_TRANSPORT_TCP_COMMUNICATOR_HANDSHAKE_ACK,
1434 handshake_ack_monotonic_time,
1435 sizeof(*handshake_ack_monotonic_time),
1436 GNUNET_TIME_UNIT_FOREVER_ABS,
1437 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
1438 &
1439 handshake_ack_monotime_store_cb,
1440 queue);
1441}
1442
1443
1444/**
1445 * Sending challenge with TcpConfirmationAck back to sender of ephemeral key.
1446 *
1447 * @param tc The TCPConfirmation originally send.
1448 * @param queue The queue context.
1449 */
1450static void
1451send_challenge (struct GNUNET_CRYPTO_ChallengeNonceP challenge, struct
1452 Queue *queue)
1453{
1454 struct TCPConfirmationAck tca;
1455 struct TcpHandshakeAckSignature thas;
1456
1457 GNUNET_log_from_nocheck (GNUNET_ERROR_TYPE_DEBUG,
1458 "transport",
1459 "sending challenge\n");
1460
1461 tca.header.type = ntohs (
1462 GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_CONFIRMATION_ACK);
1463 tca.header.size = ntohs (sizeof(tca));
1464 tca.challenge = challenge;
1465 tca.sender = my_identity;
1466 tca.monotonic_time =
1467 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (cfg));
1468 thas.purpose.purpose = htonl (
1469 GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_TCP_HANDSHAKE_ACK);
1470 thas.purpose.size = htonl (sizeof(thas));
1471 thas.sender = my_identity;
1472 thas.receiver = queue->target;
1473 thas.monotonic_time = tca.monotonic_time;
1474 thas.challenge = tca.challenge;
1475 GNUNET_CRYPTO_eddsa_sign (my_private_key,
1476 &thas,
1477 &tca.sender_sig);
1478 GNUNET_assert (0 ==
1479 gcry_cipher_encrypt (queue->out_cipher,
1480 &queue->cwrite_buf[queue->cwrite_off],
1481 sizeof(tca),
1482 &tca,
1483 sizeof(tca)));
1484 queue->cwrite_off += sizeof(tca);
1485 GNUNET_log_from_nocheck (GNUNET_ERROR_TYPE_DEBUG,
1486 "transport",
1487 "sending challenge done\n");
1488}
1489
1490
1491/**
1492 * Setup cipher for outgoing data stream based on target and
1493 * our ephemeral private key.
1494 *
1495 * @param queue queue to setup outgoing (encryption) cipher for
1496 */
1497static void
1498setup_out_cipher (struct Queue *queue)
1499{
1500 struct GNUNET_HashCode dh;
1501
1502 GNUNET_CRYPTO_ecdh_eddsa (&queue->ephemeral, &queue->target.public_key, &dh);
1503 /* we don't need the private key anymore, drop it! */
1504 memset (&queue->ephemeral, 0, sizeof(queue->ephemeral));
1505 setup_cipher (&dh, &queue->target, &queue->out_cipher, &queue->out_hmac);
1506 queue->rekey_time = GNUNET_TIME_relative_to_absolute (rekey_interval);
1507 queue->rekey_left_bytes =
1508 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, REKEY_MAX_BYTES);
1509}
1510
1511
1512/**
1513 * Inject a `struct TCPRekey` message into the queue's plaintext
1514 * buffer.
1515 *
1516 * @param queue queue to perform rekeying on
1517 */
1518static void
1519inject_rekey (struct Queue *queue)
1520{
1521 struct TCPRekey rekey;
1522 struct TcpRekeySignature thp;
1523
1524 GNUNET_assert (0 == queue->pwrite_off);
1525 memset (&rekey, 0, sizeof(rekey));
1526 GNUNET_CRYPTO_ecdhe_key_create (&queue->ephemeral);
1527 rekey.header.type = ntohs (GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_REKEY);
1528 rekey.header.size = ntohs (sizeof(rekey));
1529 GNUNET_CRYPTO_ecdhe_key_get_public (&queue->ephemeral, &rekey.ephemeral);
1530 rekey.monotonic_time =
1531 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (cfg));
1532 thp.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_TCP_REKEY);
1533 thp.purpose.size = htonl (sizeof(thp));
1534 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1535 "inject_rekey size %u\n",
1536 thp.purpose.size);
1537 thp.sender = my_identity;
1538 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1539 "sender %s\n",
1540 GNUNET_p2s (&thp.sender.public_key));
1541 thp.receiver = queue->target;
1542 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1543 "receiver %s\n",
1544 GNUNET_p2s (&thp.receiver.public_key));
1545 thp.ephemeral = rekey.ephemeral;
1546 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1547 "ephemeral %s\n",
1548 GNUNET_e2s (&thp.ephemeral));
1549 thp.monotonic_time = rekey.monotonic_time;
1550 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1551 "time %s\n",
1552 GNUNET_STRINGS_absolute_time_to_string (
1553 GNUNET_TIME_absolute_ntoh (thp.monotonic_time)));
1554 GNUNET_CRYPTO_eddsa_sign (my_private_key,
1555 &thp,
1556 &rekey.sender_sig);
1557 calculate_hmac (&queue->out_hmac, &rekey, sizeof(rekey), &rekey.hmac);
1558 /* Encrypt rekey message with 'old' cipher */
1559 GNUNET_assert (0 ==
1560 gcry_cipher_encrypt (queue->out_cipher,
1561 &queue->cwrite_buf[queue->cwrite_off],
1562 sizeof(rekey),
1563 &rekey,
1564 sizeof(rekey)));
1565 queue->cwrite_off += sizeof(rekey);
1566 /* Setup new cipher for successive messages */
1567 gcry_cipher_close (queue->out_cipher);
1568 setup_out_cipher (queue);
1569}
1570
1571
1572/**
1573 * We have been notified that our socket is ready to write.
1574 * Then reschedule this function to be called again once more is available.
1575 *
1576 * @param cls a `struct Queue`
1577 */
1578static void
1579queue_write (void *cls)
1580{
1581 struct Queue *queue = cls;
1582 ssize_t sent;
1583 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "In queue write\n");
1584 queue->write_task = NULL;
1585 if (0 != queue->cwrite_off)
1586 {
1587 sent = GNUNET_NETWORK_socket_send (queue->sock,
1588 queue->cwrite_buf,
1589 queue->cwrite_off);
1590 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1591 "Sent %lu bytes to TCP queue\n", sent);
1592 if ((-1 == sent) && (EAGAIN != errno) && (EINTR != errno))
1593 {
1594 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "send");
1595 queue_destroy (queue);
1596 return;
1597 }
1598 if (sent > 0)
1599 {
1600 size_t usent = (size_t) sent;
1601 queue->cwrite_off -= usent;
1602 memmove (queue->cwrite_buf,
1603 &queue->cwrite_buf[usent],
1604 queue->cwrite_off);
1605 reschedule_queue_timeout (queue);
1606 }
1607 }
1608 /* can we encrypt more? (always encrypt full messages, needed
1609 such that #mq_cancel() can work!) */
1610 if ((0 < queue->rekey_left_bytes) &&
1611 (queue->pwrite_off > 0) &&
1612 (queue->cwrite_off + queue->pwrite_off <= BUF_SIZE))
1613 {
1614 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1615 "Encrypting %lu bytes\n", queue->pwrite_off);
1616 GNUNET_assert (0 ==
1617 gcry_cipher_encrypt (queue->out_cipher,
1618 &queue->cwrite_buf[queue->cwrite_off],
1619 queue->pwrite_off,
1620 queue->pwrite_buf,
1621 queue->pwrite_off));
1622 if (queue->rekey_left_bytes > queue->pwrite_off)
1623 queue->rekey_left_bytes -= queue->pwrite_off;
1624 else
1625 queue->rekey_left_bytes = 0;
1626 queue->cwrite_off += queue->pwrite_off;
1627 queue->pwrite_off = 0;
1628 }
1629 // if ((-1 != unverified_size)&& ((0 == queue->pwrite_off) &&
1630 if (((0 == queue->pwrite_off) &&
1631 ((0 == queue->rekey_left_bytes) ||
1632 (0 ==
1633 GNUNET_TIME_absolute_get_remaining (
1634 queue->rekey_time).rel_value_us))))
1635 {
1636 inject_rekey (queue);
1637 }
1638 if ((0 == queue->pwrite_off) && (! queue->finishing) &&
1639 (GNUNET_YES == queue->mq_awaits_continue))
1640 {
1641 queue->mq_awaits_continue = GNUNET_NO;
1642 GNUNET_MQ_impl_send_continue (queue->mq);
1643 }
1644 /* did we just finish writing 'finish'? */
1645 if ((0 == queue->cwrite_off) && (GNUNET_YES == queue->finishing))
1646 {
1647 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1648 "Finishing queue\n");
1649 queue_destroy (queue);
1650 return;
1651 }
1652 /* do we care to write more? */
1653 if ((0 < queue->cwrite_off) || (0 < queue->pwrite_off))
1654 queue->write_task =
1655 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
1656 queue->sock,
1657 &queue_write,
1658 queue);
1659}
1660
1661
1662/**
1663 * Test if we have received a full message in plaintext.
1664 * If so, handle it.
1665 *
1666 * @param queue queue to process inbound plaintext for
1667 * @return number of bytes of plaintext handled, 0 for none
1668 */
1669static size_t
1670try_handle_plaintext (struct Queue *queue)
1671{
1672 const struct GNUNET_MessageHeader *hdr =
1673 (const struct GNUNET_MessageHeader *) queue->pread_buf;
1674 const struct TCPConfirmationAck *tca = (const struct
1675 TCPConfirmationAck *) queue->pread_buf;
1676 const struct TCPBox *box = (const struct TCPBox *) queue->pread_buf;
1677 const struct TCPRekey *rekey = (const struct TCPRekey *) queue->pread_buf;
1678 const struct TCPFinish *fin = (const struct TCPFinish *) queue->pread_buf;
1679 struct TCPRekey rekeyz;
1680 struct TCPFinish finz;
1681 struct GNUNET_ShortHashCode tmac;
1682 uint16_t type;
1683 size_t size = 0; /* make compiler happy */
1684 struct TcpHandshakeAckSignature thas;
1685 const struct GNUNET_CRYPTO_ChallengeNonceP challenge = queue->challenge;
1686
1687 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1688 "try handle plaintext!\n");
1689
1690 if ((sizeof(*hdr) > queue->pread_off))
1691 {
1692 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1693 "Handling plaintext, not even a header!\n");
1694 return 0; /* not even a header */
1695 }
1696
1697 if ((-1 != unverified_size) && (unverified_size > INITIAL_CORE_KX_SIZE))
1698 {
1699 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1700 "Already received data of size %lu bigger than KX size %lu!\n",
1701 unverified_size,
1702 INITIAL_CORE_KX_SIZE);
1703 GNUNET_break_op (0);
1704 queue_finish (queue);
1705 return 0;
1706 }
1707
1708 type = ntohs (hdr->type);
1709 switch (type)
1710 {
1711 case GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_CONFIRMATION_ACK:
1712 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1713 "start processing ack\n");
1714 if (sizeof(*tca) > queue->pread_off)
1715 {
1716 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1717 "Handling plaintext size of tca greater than pread offset.\n");
1718 return 0;
1719 }
1720 if (ntohs (hdr->size) != sizeof(*tca))
1721 {
1722 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1723 "Handling plaintext size does not match message type.\n");
1724 GNUNET_break_op (0);
1725 queue_finish (queue);
1726 return 0;
1727 }
1728
1729 thas.purpose.purpose = htonl (
1730 GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_TCP_HANDSHAKE_ACK);
1731 thas.purpose.size = htonl (sizeof(thas));
1732 thas.sender = tca->sender;
1733 thas.receiver = my_identity;
1734 thas.monotonic_time = tca->monotonic_time;
1735 thas.challenge = tca->challenge;
1736
1737 if (GNUNET_SYSERR == GNUNET_CRYPTO_eddsa_verify (
1738 GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_TCP_HANDSHAKE_ACK,
1739 &thas,
1740 &tca->sender_sig,
1741 &tca->sender.public_key))
1742 {
1743 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1744 "Verification of signature failed!\n");
1745 GNUNET_break (0);
1746 queue_finish (queue);
1747 return 0;
1748 }
1749 if (0 != GNUNET_memcmp (&tca->challenge, &challenge))
1750 {
1751 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1752 "Challenge in TCPConfirmationAck not correct!\n");
1753 GNUNET_break (0);
1754 queue_finish (queue);
1755 return 0;
1756 }
1757
1758 queue->handshake_ack_monotime_get = GNUNET_PEERSTORE_iterate (peerstore,
1759 "transport_tcp_communicator",
1760 &queue->target,
1761 GNUNET_PEERSTORE_TRANSPORT_TCP_COMMUNICATOR_HANDSHAKE_ACK,
1762 &
1763 handshake_ack_monotime_cb,
1764 queue);
1765
1766 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1767 "Handling plaintext, ack processed!\n");
1768
1769 if (GNUNET_TRANSPORT_CS_INBOUND == queue->cs)
1770 {
1771 send_challenge (queue->challenge_received, queue);
1772 queue->write_task =
1773 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
1774 queue->sock,
1775 &queue_write,
1776 queue);
1777 }
1778
1779 unverified_size = -1;
1780
1781 char *foreign_addr;
1782
1783 switch (queue->address->sa_family)
1784 {
1785 case AF_INET:
1786 GNUNET_asprintf (&foreign_addr,
1787 "%s-%s",
1788 COMMUNICATOR_ADDRESS_PREFIX,
1789 GNUNET_a2s (queue->address, queue->address_len));
1790 break;
1791
1792 case AF_INET6:
1793 GNUNET_asprintf (&foreign_addr,
1794 "%s-%s",
1795 COMMUNICATOR_ADDRESS_PREFIX,
1796 GNUNET_a2s (queue->address, queue->address_len));
1797 break;
1798
1799 default:
1800 GNUNET_assert (0);
1801 }
1802
1803 queue->qh = GNUNET_TRANSPORT_communicator_mq_add (ch,
1804 &queue->target,
1805 foreign_addr,
1806 UINT16_MAX, /* no MTU */
1807 GNUNET_TRANSPORT_QUEUE_LENGTH_UNLIMITED,
1808 0, /* Priority */
1809 queue->nt,
1810 queue->cs,
1811 queue->mq);
1812
1813 GNUNET_free (foreign_addr);
1814
1815 size = ntohs (hdr->size);
1816 break;
1817 case GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_BOX:
1818 /* Special case: header size excludes box itself! */
1819 if (ntohs (hdr->size) + sizeof(struct TCPBox) > queue->pread_off)
1820 return 0;
1821 calculate_hmac (&queue->in_hmac, &box[1], ntohs (hdr->size), &tmac);
1822 if (0 != memcmp (&tmac, &box->hmac, sizeof(tmac)))
1823 {
1824 GNUNET_break_op (0);
1825 queue_finish (queue);
1826 return 0;
1827 }
1828 pass_plaintext_to_core (queue, (const void *) &box[1], ntohs (hdr->size));
1829 size = ntohs (hdr->size) + sizeof(*box);
1830 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1831 "Handling plaintext, box processed!\n");
1832 break;
1833
1834 case GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_REKEY:
1835 if (sizeof(*rekey) > queue->pread_off)
1836 return 0;
1837 if (ntohs (hdr->size) != sizeof(*rekey))
1838 {
1839 GNUNET_break_op (0);
1840 queue_finish (queue);
1841 return 0;
1842 }
1843 rekeyz = *rekey;
1844 memset (&rekeyz.hmac, 0, sizeof(rekeyz.hmac));
1845 calculate_hmac (&queue->in_hmac, &rekeyz, sizeof(rekeyz), &tmac);
1846 if (0 != memcmp (&tmac, &rekey->hmac, sizeof(tmac)))
1847 {
1848 GNUNET_break_op (0);
1849 queue_finish (queue);
1850 return 0;
1851 }
1852 do_rekey (queue, rekey);
1853 size = ntohs (hdr->size);
1854 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1855 "Handling plaintext, rekey processed!\n");
1856 break;
1857
1858 case GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_FINISH:
1859 if (sizeof(*fin) > queue->pread_off)
1860 return 0;
1861 if (ntohs (hdr->size) != sizeof(*fin))
1862 {
1863 GNUNET_break_op (0);
1864 queue_finish (queue);
1865 return 0;
1866 }
1867 finz = *fin;
1868 memset (&finz.hmac, 0, sizeof(finz.hmac));
1869 calculate_hmac (&queue->in_hmac, &rekeyz, sizeof(rekeyz), &tmac);
1870 if (0 != memcmp (&tmac, &fin->hmac, sizeof(tmac)))
1871 {
1872 GNUNET_break_op (0);
1873 queue_finish (queue);
1874 return 0;
1875 }
1876 /* handle FINISH by destroying queue */
1877 queue_destroy (queue);
1878 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1879 "Handling plaintext, finish processed!\n");
1880 break;
1881
1882 default:
1883 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1884 "Handling plaintext, nothing processed!\n");
1885 GNUNET_break_op (0);
1886 queue_finish (queue);
1887 return 0;
1888 }
1889 GNUNET_assert (0 != size);
1890 if (-1 != unverified_size)
1891 unverified_size += size;
1892 return size;
1893}
1894
1895
1896/**
1897 * Queue read task. If we hit the timeout, disconnect it
1898 *
1899 * @param cls the `struct Queue *` to disconnect
1900 */
1901static void
1902queue_read (void *cls)
1903{
1904 struct Queue *queue = cls;
1905 struct GNUNET_TIME_Relative left;
1906 ssize_t rcvd;
1907
1908 queue->read_task = NULL;
1909 rcvd = GNUNET_NETWORK_socket_recv (queue->sock,
1910 &queue->cread_buf[queue->cread_off],
1911 BUF_SIZE - queue->cread_off);
1912 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1913 "Received %lu bytes from TCP queue\n", rcvd);
1914 GNUNET_log_from_nocheck (GNUNET_ERROR_TYPE_DEBUG,
1915 "transport",
1916 "Received %lu bytes from TCP queue\n", rcvd);
1917 if (-1 == rcvd)
1918 {
1919 if ((EAGAIN != errno) && (EINTR != errno))
1920 {
1921 GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "recv");
1922 queue_finish (queue);
1923 return;
1924 }
1925 /* try again */
1926 left = GNUNET_TIME_absolute_get_remaining (queue->timeout);
1927 queue->read_task =
1928 GNUNET_SCHEDULER_add_read_net (left, queue->sock, &queue_read, queue);
1929 return;
1930 }
1931 if (0 != rcvd)
1932 reschedule_queue_timeout (queue);
1933 queue->cread_off += rcvd;
1934 while ((queue->pread_off < sizeof(queue->pread_buf)) &&
1935 (queue->cread_off > 0))
1936 {
1937 size_t max = GNUNET_MIN (sizeof(queue->pread_buf) - queue->pread_off,
1938 queue->cread_off);
1939 size_t done;
1940 size_t total;
1941 size_t old_pread_off = queue->pread_off;
1942
1943 GNUNET_assert (0 ==
1944 gcry_cipher_decrypt (queue->in_cipher,
1945 &queue->pread_buf[queue->pread_off],
1946 max,
1947 queue->cread_buf,
1948 max));
1949 queue->pread_off += max;
1950 total = 0;
1951 while (0 != (done = try_handle_plaintext (queue)))
1952 {
1953 /* 'done' bytes of plaintext were used, shift buffer */
1954 GNUNET_assert (done <= queue->pread_off);
1955 /* NOTE: this memmove() could possibly sometimes be
1956 avoided if we pass 'total' into try_handle_plaintext()
1957 and use it at an offset into the buffer there! */
1958 memmove (queue->pread_buf,
1959 &queue->pread_buf[done],
1960 queue->pread_off - done);
1961 queue->pread_off -= done;
1962 total += done;
1963 /* The last plaintext was a rekey, abort for now */
1964 if (GNUNET_YES == queue->rekeyed)
1965 break;
1966 }
1967 /* when we encounter a rekey message, the decryption above uses the
1968 wrong key for everything after the rekey; in that case, we have
1969 to re-do the decryption at 'total' instead of at 'max'.
1970 However, we have to take into account that the plaintext buffer may have
1971 already contained data and not jumped too far ahead in the ciphertext.
1972 If there is no rekey and the last message is incomplete (max > total),
1973 it is safe to keep the decryption so we shift by 'max' */
1974 if (GNUNET_YES == queue->rekeyed)
1975 {
1976 max = total - old_pread_off;
1977 queue->rekeyed = GNUNET_NO;
1978 queue->pread_off = 0;
1979 }
1980 memmove (queue->cread_buf, &queue->cread_buf[max], queue->cread_off - max);
1981 queue->cread_off -= max;
1982 }
1983 if (BUF_SIZE == queue->cread_off)
1984 return; /* buffer full, suspend reading */
1985 left = GNUNET_TIME_absolute_get_remaining (queue->timeout);
1986 if (0 != left.rel_value_us)
1987 {
1988 if (max_queue_length > queue->backpressure)
1989 {
1990 /* continue reading */
1991 left = GNUNET_TIME_absolute_get_remaining (queue->timeout);
1992 queue->read_task =
1993 GNUNET_SCHEDULER_add_read_net (left, queue->sock, &queue_read, queue);
1994 }
1995 return;
1996 }
1997 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1998 "Queue %p was idle for %s, disconnecting\n",
1999 queue,
2000 GNUNET_STRINGS_relative_time_to_string (
2001 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2002 GNUNET_YES));
2003 queue_finish (queue);
2004}
2005
2006
2007/**
2008 * Convert a `struct sockaddr_in6 to a `struct sockaddr *`
2009 *
2010 * @param[out] sock_len set to the length of the address.
2011 * @param v6 The sockaddr_in6 to be converted.
2012 * @return The struct sockaddr *.
2013 */
2014static struct sockaddr *
2015tcp_address_to_sockaddr_numeric_v6 (socklen_t *sock_len,
2016 struct sockaddr_in6 v6,
2017 unsigned int port)
2018{
2019 struct sockaddr *in;
2020
2021 v6.sin6_family = AF_INET6;
2022 v6.sin6_port = htons ((uint16_t) port);
2023#if HAVE_SOCKADDR_IN_SIN_LEN
2024 v6.sin6_len = sizeof(sizeof(struct sockaddr_in6));
2025#endif
2026 v6.sin6_flowinfo = 0;
2027 v6.sin6_scope_id = 0;
2028 in = GNUNET_memdup (&v6, sizeof(v6));
2029 *sock_len = sizeof(struct sockaddr_in6);
2030
2031 return in;
2032}
2033
2034
2035/**
2036 * Convert a `struct sockaddr_in4 to a `struct sockaddr *`
2037 *
2038 * @param[out] sock_len set to the length of the address.
2039 * @param v4 The sockaddr_in4 to be converted.
2040 * @return The struct sockaddr *.
2041 */
2042static struct sockaddr *
2043tcp_address_to_sockaddr_numeric_v4 (socklen_t *sock_len,
2044 struct sockaddr_in v4,
2045 unsigned int port)
2046{
2047 struct sockaddr *in;
2048
2049 v4.sin_family = AF_INET;
2050 v4.sin_port = htons ((uint16_t) port);
2051#if HAVE_SOCKADDR_IN_SIN_LEN
2052 v4.sin_len = sizeof(struct sockaddr_in);
2053#endif
2054 in = GNUNET_memdup (&v4, sizeof(v4));
2055 *sock_len = sizeof(struct sockaddr_in);
2056 return in;
2057}
2058
2059
2060/**
2061 * Convert TCP bind specification to a `struct PortOnlyIpv4Ipv6 *`
2062 *
2063 * @param bindto bind specification to convert.
2064 * @return The converted bindto specification.
2065 */
2066static struct PortOnlyIpv4Ipv6 *
2067tcp_address_to_sockaddr_port_only (const char *bindto, unsigned int *port)
2068{
2069 struct PortOnlyIpv4Ipv6 *po;
2070 struct sockaddr_in *i4;
2071 struct sockaddr_in6 *i6;
2072 socklen_t sock_len_ipv4;
2073 socklen_t sock_len_ipv6;
2074
2075 /* interpreting value as just a PORT number */
2076 if (*port > UINT16_MAX)
2077 {
2078 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2079 "BINDTO specification `%s' invalid: value too large for port\n",
2080 bindto);
2081 return NULL;
2082 }
2083
2084 po = GNUNET_new (struct PortOnlyIpv4Ipv6);
2085
2086 if ((GNUNET_NO == GNUNET_NETWORK_test_pf (PF_INET6)) ||
2087 (GNUNET_YES ==
2088 GNUNET_CONFIGURATION_get_value_yesno (cfg,
2089 COMMUNICATOR_CONFIG_SECTION,
2090 "DISABLE_V6")))
2091 {
2092 i4 = GNUNET_malloc (sizeof(struct sockaddr_in));
2093 po->addr_ipv4 = tcp_address_to_sockaddr_numeric_v4 (&sock_len_ipv4, *i4,
2094 *port);
2095 po->addr_len_ipv4 = sock_len_ipv4;
2096 }
2097 else
2098 {
2099
2100 i4 = GNUNET_malloc (sizeof(struct sockaddr_in));
2101 po->addr_ipv4 = tcp_address_to_sockaddr_numeric_v4 (&sock_len_ipv4, *i4,
2102 *port);
2103 po->addr_len_ipv4 = sock_len_ipv4;
2104
2105 i6 = GNUNET_malloc (sizeof(struct sockaddr_in6));
2106 po->addr_ipv6 = tcp_address_to_sockaddr_numeric_v6 (&sock_len_ipv6, *i6,
2107 *port);
2108
2109 po->addr_len_ipv6 = sock_len_ipv6;
2110
2111 GNUNET_free (i6);
2112 }
2113
2114 GNUNET_free (i4);
2115
2116 return po;
2117}
2118
2119
2120/**
2121 * This Method extracts the address part of the BINDTO string.
2122 *
2123 * @param bindto String we extract the address part from.
2124 * @return The extracted address string.
2125 */
2126static char *
2127extract_address (const char *bindto)
2128{
2129 char *addr;
2130 char *start;
2131 char *token;
2132 char *cp;
2133 char *rest = NULL;
2134 char *res;
2135
2136 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2137 "extract address with bindto %s\n",
2138 bindto);
2139
2140 if (NULL == bindto)
2141 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2142 "bindto is NULL\n");
2143
2144 cp = GNUNET_strdup (bindto);
2145
2146 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2147 "extract address 2\n");
2148
2149 start = cp;
2150 if (('[' == *cp) && (']' == cp[strlen (cp) - 1]))
2151 {
2152 start++; /* skip over '['*/
2153 cp[strlen (cp) - 1] = '\0'; /* eat ']'*/
2154 addr = GNUNET_strdup (start);
2155 }
2156 else
2157 {
2158 token = strtok_r (cp, "]", &rest);
2159 if (strlen (bindto) == strlen (token))
2160 {
2161 token = strtok_r (cp, ":", &rest);
2162 addr = GNUNET_strdup (token);
2163 }
2164 else
2165 {
2166 token++;
2167 res = GNUNET_strdup (token);
2168 addr = GNUNET_strdup (res);
2169 }
2170 }
2171
2172 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2173 "tcp address: %s\n",
2174 addr);
2175 GNUNET_free (cp);
2176 return addr;
2177}
2178
2179
2180/**
2181 * This Method extracts the port part of the BINDTO string.
2182 *
2183 * @param addr_and_port String we extract the port from.
2184 * @return The extracted port as unsigned int.
2185 */
2186static unsigned int
2187extract_port (const char *addr_and_port)
2188{
2189 unsigned int port;
2190 char dummy[2];
2191 char *token;
2192 char *addr;
2193 char *colon;
2194 char *cp;
2195 char *rest = NULL;
2196
2197 if (NULL != addr_and_port)
2198 {
2199 cp = GNUNET_strdup (addr_and_port);
2200 token = strtok_r (cp, "]", &rest);
2201 if (strlen (addr_and_port) == strlen (token))
2202 {
2203 colon = strrchr (cp, ':');
2204 if (NULL == colon)
2205 {
2206 GNUNET_free (cp);
2207 return 0;
2208 }
2209 addr = colon;
2210 addr++;
2211 }
2212 else
2213 {
2214 token = strtok_r (NULL, "]", &rest);
2215 if (NULL == token)
2216 {
2217 GNUNET_free (cp);
2218 return 0;
2219 }
2220 else
2221 {
2222 addr = token;
2223 addr++;
2224 }
2225 }
2226
2227
2228 if (1 == sscanf (addr, "%u%1s", &port, dummy))
2229 {
2230 /* interpreting value as just a PORT number */
2231 if (port > UINT16_MAX)
2232 {
2233 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2234 "Port `%u' invalid: value too large for port\n",
2235 port);
2236 GNUNET_free (cp);
2237 return 0;
2238 }
2239 }
2240 else
2241 {
2242 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2243 "BINDTO specification invalid: last ':' not followed by number\n");
2244 GNUNET_free (cp);
2245 return 0;
2246 }
2247 GNUNET_free (cp);
2248 }
2249 else
2250 {
2251 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2252 "return 0\n");
2253 /* interpret missing port as 0, aka pick any free one */
2254 port = 0;
2255 }
2256
2257 return port;
2258}
2259
2260
2261/**
2262 * Convert TCP bind specification to a `struct sockaddr *`
2263 *
2264 * @param bindto bind specification to convert
2265 * @param[out] sock_len set to the length of the address
2266 * @return converted bindto specification
2267 */
2268static struct sockaddr *
2269tcp_address_to_sockaddr (const char *bindto, socklen_t *sock_len)
2270{
2271 struct sockaddr *in;
2272 unsigned int port;
2273 struct sockaddr_in v4;
2274 struct sockaddr_in6 v6;
2275 char *start;
2276
2277 start = extract_address (bindto);
2278 // FIXME: check NULL == start
2279 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2280 "start %s\n",
2281 start);
2282
2283 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2284 "!bindto %s\n",
2285 bindto);
2286
2287
2288 if (1 == inet_pton (AF_INET, start, &v4.sin_addr))
2289 {
2290 // colon = strrchr (cp, ':');
2291 port = extract_port (bindto);
2292
2293 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2294 "port %u\n",
2295 port);
2296
2297 in = tcp_address_to_sockaddr_numeric_v4 (sock_len, v4, port);
2298 }
2299 else if (1 == inet_pton (AF_INET6, start, &v6.sin6_addr))
2300 {
2301 // colon = strrchr (cp, ':');
2302 port = extract_port (bindto);
2303 in = tcp_address_to_sockaddr_numeric_v6 (sock_len, v6, port);
2304 }
2305 else
2306 {
2307 GNUNET_assert (0);
2308 }
2309
2310 GNUNET_free (start);
2311 return in;
2312}
2313
2314
2315/**
2316 * Signature of functions implementing the sending functionality of a
2317 * message queue.
2318 *
2319 * @param mq the message queue
2320 * @param msg the message to send
2321 * @param impl_state our `struct Queue`
2322 */
2323static void
2324mq_send (struct GNUNET_MQ_Handle *mq,
2325 const struct GNUNET_MessageHeader *msg,
2326 void *impl_state)
2327{
2328 struct Queue *queue = impl_state;
2329 uint16_t msize = ntohs (msg->size);
2330 struct TCPBox box;
2331 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2332 "In MQ send. Queue finishing: %s; write task running: %s\n",
2333 (GNUNET_YES == queue->finishing) ? "yes" : "no",
2334 (NULL == queue->write_task) ? "yes" : "no");
2335 GNUNET_assert (mq == queue->mq);
2336 queue->mq_awaits_continue = GNUNET_YES;
2337 if (GNUNET_YES == queue->finishing)
2338 return; /* this queue is dying, drop msg */
2339 GNUNET_assert (0 == queue->pwrite_off);
2340 box.header.type = htons (GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_BOX);
2341 box.header.size = htons (msize);
2342 calculate_hmac (&queue->out_hmac, msg, msize, &box.hmac);
2343 memcpy (&queue->pwrite_buf[queue->pwrite_off], &box, sizeof(box));
2344 queue->pwrite_off += sizeof(box);
2345 memcpy (&queue->pwrite_buf[queue->pwrite_off], msg, msize);
2346 queue->pwrite_off += msize;
2347 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2348 "%lu bytes of plaintext to send\n", queue->pwrite_off);
2349 GNUNET_assert (NULL != queue->sock);
2350 if (NULL == queue->write_task)
2351 queue->write_task =
2352 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
2353 queue->sock,
2354 &queue_write,
2355 queue);
2356}
2357
2358
2359/**
2360 * Signature of functions implementing the destruction of a message
2361 * queue. Implementations must not free @a mq, but should take care
2362 * of @a impl_state.
2363 *
2364 * @param mq the message queue to destroy
2365 * @param impl_state our `struct Queue`
2366 */
2367static void
2368mq_destroy (struct GNUNET_MQ_Handle *mq, void *impl_state)
2369{
2370 struct Queue *queue = impl_state;
2371
2372 if (mq == queue->mq)
2373 {
2374 queue->mq = NULL;
2375 queue_finish (queue);
2376 }
2377}
2378
2379
2380/**
2381 * Implementation function that cancels the currently sent message.
2382 *
2383 * @param mq message queue
2384 * @param impl_state our `struct Queue`
2385 */
2386static void
2387mq_cancel (struct GNUNET_MQ_Handle *mq, void *impl_state)
2388{
2389 struct Queue *queue = impl_state;
2390
2391 GNUNET_assert (0 != queue->pwrite_off);
2392 queue->pwrite_off = 0;
2393}
2394
2395
2396/**
2397 * Generic error handler, called with the appropriate
2398 * error code and the same closure specified at the creation of
2399 * the message queue.
2400 * Not every message queue implementation supports an error handler.
2401 *
2402 * @param cls our `struct Queue`
2403 * @param error error code
2404 */
2405static void
2406mq_error (void *cls, enum GNUNET_MQ_Error error)
2407{
2408 struct Queue *queue = cls;
2409
2410 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2411 "MQ error in queue to %s: %d\n",
2412 GNUNET_i2s (&queue->target),
2413 (int) error);
2414 queue_finish (queue);
2415}
2416
2417
2418/**
2419 * Add the given @a queue to our internal data structure. Setup the
2420 * MQ processing and inform transport that the queue is ready. Must
2421 * be called after the KX for outgoing messages has been bootstrapped.
2422 *
2423 * @param queue queue to boot
2424 */
2425static void
2426boot_queue (struct Queue *queue)
2427{
2428 queue->nt =
2429 GNUNET_NT_scanner_get_type (is, queue->address, queue->address_len);
2430 (void) GNUNET_CONTAINER_multipeermap_put (
2431 queue_map,
2432 &queue->target,
2433 queue,
2434 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2435 GNUNET_STATISTICS_set (stats,
2436 "# queues active",
2437 GNUNET_CONTAINER_multipeermap_size (queue_map),
2438 GNUNET_NO);
2439 queue->timeout =
2440 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2441 queue->mq = GNUNET_MQ_queue_for_callbacks (&mq_send,
2442 &mq_destroy,
2443 &mq_cancel,
2444 queue,
2445 NULL,
2446 &mq_error,
2447 queue);
2448}
2449
2450
2451/**
2452 * Generate and transmit our ephemeral key and the signature for
2453 * the initial KX with the other peer. Must be called first, before
2454 * any other bytes are ever written to the output buffer. Note that
2455 * our cipher must already be initialized when calling this function.
2456 * Helper function for #start_initial_kx_out().
2457 *
2458 * @param queue queue to do KX for
2459 * @param epub our public key for the KX
2460 */
2461static void
2462transmit_kx (struct Queue *queue,
2463 const struct GNUNET_CRYPTO_EcdhePublicKey *epub)
2464{
2465 struct TcpHandshakeSignature ths;
2466 struct TCPConfirmation tc;
2467
2468 memcpy (queue->cwrite_buf, epub, sizeof(*epub));
2469 queue->cwrite_off = sizeof(*epub);
2470 /* compute 'tc' and append in encrypted format to cwrite_buf */
2471 tc.sender = my_identity;
2472 tc.monotonic_time =
2473 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (cfg));
2474 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
2475 &tc.challenge,
2476 sizeof(tc.challenge));
2477 ths.purpose.purpose = htonl (
2478 GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_TCP_HANDSHAKE);
2479 ths.purpose.size = htonl (sizeof(ths));
2480 ths.sender = my_identity;
2481 ths.receiver = queue->target;
2482 ths.ephemeral = *epub;
2483 ths.monotonic_time = tc.monotonic_time;
2484 ths.challenge = tc.challenge;
2485 GNUNET_CRYPTO_eddsa_sign (my_private_key,
2486 &ths,
2487 &tc.sender_sig);
2488 GNUNET_assert (0 ==
2489 gcry_cipher_encrypt (queue->out_cipher,
2490 &queue->cwrite_buf[queue->cwrite_off],
2491 sizeof(tc),
2492 &tc,
2493 sizeof(tc)));
2494 queue->challenge = tc.challenge;
2495 queue->cwrite_off += sizeof(tc);
2496
2497 GNUNET_log_from_nocheck (GNUNET_ERROR_TYPE_DEBUG,
2498 "transport",
2499 "handshake written\n");
2500}
2501
2502
2503/**
2504 * Initialize our key material for outgoing transmissions and
2505 * inform the other peer about it. Must be called first before
2506 * any data is sent.
2507 *
2508 * @param queue the queue to setup
2509 */
2510static void
2511start_initial_kx_out (struct Queue *queue)
2512{
2513 struct GNUNET_CRYPTO_EcdhePublicKey epub;
2514
2515 GNUNET_CRYPTO_ecdhe_key_create (&queue->ephemeral);
2516 GNUNET_CRYPTO_ecdhe_key_get_public (&queue->ephemeral, &epub);
2517 setup_out_cipher (queue);
2518 transmit_kx (queue, &epub);
2519}
2520
2521
2522/**
2523 * Callback called when peerstore store operation for handshake monotime is finished.
2524 * @param cls Queue context the store operation was executed.
2525 * @param success Store operation was successful (GNUNET_OK) or not.
2526 */
2527static void
2528handshake_monotime_store_cb (void *cls, int success)
2529{
2530 struct Queue *queue = cls;
2531 if (GNUNET_OK != success)
2532 {
2533 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2534 "Failed to store handshake monotonic time in PEERSTORE!\n");
2535 }
2536 queue->handshake_monotime_sc = NULL;
2537}
2538
2539
2540/**
2541 * Callback called by peerstore when records for GNUNET_PEERSTORE_TRANSPORT_TCP_COMMUNICATOR_HANDSHAKE
2542 * where found.
2543 * @param cls Queue context the store operation was executed.
2544 * @param record The record found or NULL if there is no record left.
2545 * @param emsg Message from peerstore.
2546 */
2547static void
2548handshake_monotime_cb (void *cls,
2549 const struct GNUNET_PEERSTORE_Record *record,
2550 const char *emsg)
2551{
2552 struct Queue *queue = cls;
2553 struct GNUNET_TIME_AbsoluteNBO *mtbe;
2554 struct GNUNET_TIME_Absolute mt;
2555 const struct GNUNET_PeerIdentity *pid;
2556 struct GNUNET_TIME_AbsoluteNBO *handshake_monotonic_time;
2557
2558 (void) emsg;
2559
2560 handshake_monotonic_time = &queue->handshake_monotonic_time;
2561 pid = &queue->target;
2562 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2563 "tcp handshake with us %s\n",
2564 GNUNET_i2s (&my_identity));
2565 if (NULL == record)
2566 {
2567 queue->handshake_monotime_get = NULL;
2568 return;
2569 }
2570 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2571 "tcp handshake from peer %s\n",
2572 GNUNET_i2s (pid));
2573 if (sizeof(*mtbe) != record->value_size)
2574 {
2575 GNUNET_break (0);
2576 return;
2577 }
2578 mtbe = record->value;
2579 mt = GNUNET_TIME_absolute_ntoh (*mtbe);
2580 if (mt.abs_value_us > GNUNET_TIME_absolute_ntoh (
2581 queue->handshake_monotonic_time).abs_value_us)
2582 {
2583 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2584 "Queue from %s dropped, handshake monotime in the past\n",
2585 GNUNET_i2s (&queue->target));
2586 GNUNET_break (0);
2587 queue_finish (queue);
2588 return;
2589 }
2590 queue->handshake_monotime_sc = GNUNET_PEERSTORE_store (peerstore,
2591 "transport_tcp_communicator",
2592 pid,
2593 GNUNET_PEERSTORE_TRANSPORT_TCP_COMMUNICATOR_HANDSHAKE,
2594 handshake_monotonic_time,
2595 sizeof(*
2596 handshake_monotonic_time),
2597 GNUNET_TIME_UNIT_FOREVER_ABS,
2598 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
2599 &
2600 handshake_monotime_store_cb,
2601 queue);
2602}
2603
2604
2605/**
2606 * We have received the first bytes from the other side on a @a queue.
2607 * Decrypt the @a tc contained in @a ibuf and check the signature.
2608 * Note that #setup_in_cipher() must have already been called.
2609 *
2610 * @param queue queue to decrypt initial bytes from other peer for
2611 * @param tc[out] where to store the result
2612 * @param ibuf incoming data, of size
2613 * `INITIAL_KX_SIZE`
2614 * @return #GNUNET_OK if the signature was OK, #GNUNET_SYSERR if not
2615 */
2616static int
2617decrypt_and_check_tc (struct Queue *queue,
2618 struct TCPConfirmation *tc,
2619 char *ibuf)
2620{
2621 struct TcpHandshakeSignature ths;
2622 enum GNUNET_GenericReturnValue ret;
2623
2624 GNUNET_assert (
2625 0 ==
2626 gcry_cipher_decrypt (queue->in_cipher,
2627 tc,
2628 sizeof(*tc),
2629 &ibuf[sizeof(struct GNUNET_CRYPTO_EcdhePublicKey)],
2630 sizeof(*tc)));
2631 ths.purpose.purpose = htonl (
2632 GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_TCP_HANDSHAKE);
2633 ths.purpose.size = htonl (sizeof(ths));
2634 ths.sender = tc->sender;
2635 ths.receiver = my_identity;
2636 memcpy (&ths.ephemeral, ibuf, sizeof(struct GNUNET_CRYPTO_EcdhePublicKey));
2637 ths.monotonic_time = tc->monotonic_time;
2638 ths.challenge = tc->challenge;
2639 ret = GNUNET_CRYPTO_eddsa_verify (
2640 GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_TCP_HANDSHAKE,
2641 &ths,
2642 &tc->sender_sig,
2643 &tc->sender.public_key);
2644 if (GNUNET_YES == ret)
2645 queue->handshake_monotime_get =
2646 GNUNET_PEERSTORE_iterate (peerstore,
2647 "transport_tcp_communicator",
2648 &queue->target,
2649 GNUNET_PEERSTORE_TRANSPORT_TCP_COMMUNICATOR_HANDSHAKE,
2650 &handshake_monotime_cb,
2651 queue);
2652 return ret;
2653}
2654
2655
2656/**
2657 * Closes socket and frees memory associated with @a pq.
2658 *
2659 * @param pq proto queue to free
2660 */
2661static void
2662free_proto_queue (struct ProtoQueue *pq)
2663{
2664 if (NULL != pq->listen_sock)
2665 {
2666 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (pq->listen_sock));
2667 pq->listen_sock = NULL;
2668 }
2669 GNUNET_NETWORK_socket_close (pq->sock);
2670 GNUNET_free (pq->address);
2671 GNUNET_CONTAINER_DLL_remove (proto_head, proto_tail, pq);
2672 GNUNET_free (pq);
2673}
2674
2675
2676/**
2677 * Read from the socket of the proto queue until we have enough data
2678 * to upgrade to full queue.
2679 *
2680 * @param cls a `struct ProtoQueue`
2681 */
2682static void
2683proto_read_kx (void *cls)
2684{
2685 struct ProtoQueue *pq = cls;
2686 ssize_t rcvd;
2687 struct GNUNET_TIME_Relative left;
2688 struct Queue *queue;
2689 struct TCPConfirmation tc;
2690
2691 pq->read_task = NULL;
2692 left = GNUNET_TIME_absolute_get_remaining (pq->timeout);
2693 if (0 == left.rel_value_us)
2694 {
2695 free_proto_queue (pq);
2696 return;
2697 }
2698 rcvd = GNUNET_NETWORK_socket_recv (pq->sock,
2699 &pq->ibuf[pq->ibuf_off],
2700 sizeof(pq->ibuf) - pq->ibuf_off);
2701 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2702 "Received %lu bytes for KX\n", rcvd);
2703 GNUNET_log_from_nocheck (GNUNET_ERROR_TYPE_DEBUG,
2704 "transport",
2705 "Received %lu bytes for KX\n", rcvd);
2706 if (-1 == rcvd)
2707 {
2708 if ((EAGAIN != errno) && (EINTR != errno))
2709 {
2710 GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "recv");
2711 free_proto_queue (pq);
2712 return;
2713 }
2714 /* try again */
2715 pq->read_task =
2716 GNUNET_SCHEDULER_add_read_net (left, pq->sock, &proto_read_kx, pq);
2717 return;
2718 }
2719 pq->ibuf_off += rcvd;
2720 if (pq->ibuf_off > sizeof(pq->ibuf))
2721 {
2722 /* read more */
2723 pq->read_task =
2724 GNUNET_SCHEDULER_add_read_net (left, pq->sock, &proto_read_kx, pq);
2725 return;
2726 }
2727 /* we got all the data, let's find out who we are talking to! */
2728 queue = GNUNET_new (struct Queue);
2729 setup_in_cipher ((const struct GNUNET_CRYPTO_EcdhePublicKey *) pq->ibuf,
2730 queue);
2731 if (GNUNET_OK != decrypt_and_check_tc (queue, &tc, pq->ibuf))
2732 {
2733 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2734 "Invalid TCP KX received from %s\n",
2735 GNUNET_a2s (pq->address, pq->address_len));
2736 gcry_cipher_close (queue->in_cipher);
2737 GNUNET_free (queue);
2738 free_proto_queue (pq);
2739 return;
2740 }
2741 queue->address = pq->address; /* steals reference */
2742 queue->address_len = pq->address_len;
2743 queue->target = tc.sender;
2744 queue->listen_sock = pq->listen_sock;
2745 queue->sock = pq->sock;
2746
2747 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2748 "created queue with target %s\n",
2749 GNUNET_i2s (&queue->target));
2750
2751 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2752 "start kx proto\n");
2753
2754 start_initial_kx_out (queue);
2755 queue->cs = GNUNET_TRANSPORT_CS_INBOUND;
2756 boot_queue (queue);
2757 queue->read_task =
2758 GNUNET_SCHEDULER_add_read_net (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2759 queue->sock,
2760 &queue_read,
2761 queue);
2762 queue->write_task =
2763 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
2764 queue->sock,
2765 &queue_write,
2766 queue);
2767 // TODO To early! Move it somewhere else.
2768 // send_challenge (tc.challenge, queue);
2769 queue->challenge_received = tc.challenge;
2770
2771 GNUNET_CONTAINER_DLL_remove (proto_head, proto_tail, pq);
2772 GNUNET_free (pq);
2773}
2774
2775
2776/**
2777 * We have been notified that our listen socket has something to
2778 * read. Do the read and reschedule this function to be called again
2779 * once more is available.
2780 *
2781 * @param cls ListenTask with listening socket and task
2782 */
2783static void
2784listen_cb (void *cls)
2785{
2786 struct sockaddr_storage in;
2787 socklen_t addrlen;
2788 struct GNUNET_NETWORK_Handle *sock;
2789 struct ProtoQueue *pq;
2790 struct ListenTask *lt;
2791
2792 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2793 "listen_cb\n");
2794
2795 lt = cls;
2796
2797 lt->listen_task = NULL;
2798 GNUNET_assert (NULL != lt->listen_sock);
2799 addrlen = sizeof(in);
2800 memset (&in, 0, sizeof(in));
2801 sock = GNUNET_NETWORK_socket_accept (lt->listen_sock,
2802 (struct sockaddr*) &in,
2803 &addrlen);
2804 if ((NULL == sock) && ((EMFILE == errno) || (ENFILE == errno)))
2805 return; /* system limit reached, wait until connection goes down */
2806 lt->listen_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
2807 lt->listen_sock,
2808 &listen_cb,
2809 lt);
2810 if ((NULL == sock) && ((EAGAIN == errno) || (ENOBUFS == errno)))
2811 return;
2812 if (NULL == sock)
2813 {
2814 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "accept");
2815 return;
2816 }
2817 pq = GNUNET_new (struct ProtoQueue);
2818 pq->address_len = addrlen;
2819 pq->address = GNUNET_memdup (&in, addrlen);
2820 pq->timeout = GNUNET_TIME_relative_to_absolute (PROTO_QUEUE_TIMEOUT);
2821 pq->sock = sock;
2822 pq->read_task = GNUNET_SCHEDULER_add_read_net (PROTO_QUEUE_TIMEOUT,
2823 pq->sock,
2824 &proto_read_kx,
2825 pq);
2826 GNUNET_CONTAINER_DLL_insert (proto_head, proto_tail, pq);
2827}
2828
2829
2830/**
2831 * Read from the socket of the queue until we have enough data
2832 * to initialize the decryption logic and can switch to regular
2833 * reading.
2834 *
2835 * @param cls a `struct Queue`
2836 */
2837static void
2838queue_read_kx (void *cls)
2839{
2840 struct Queue *queue = cls;
2841 ssize_t rcvd;
2842 struct GNUNET_TIME_Relative left;
2843 struct TCPConfirmation tc;
2844
2845 queue->read_task = NULL;
2846 left = GNUNET_TIME_absolute_get_remaining (queue->timeout);
2847 if (0 == left.rel_value_us)
2848 {
2849 queue_destroy (queue);
2850 return;
2851 }
2852 rcvd = GNUNET_NETWORK_socket_recv (queue->sock,
2853 &queue->cread_buf[queue->cread_off],
2854 BUF_SIZE - queue->cread_off);
2855 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2856 "Received %lu bytes for KX\n",
2857 rcvd);
2858 GNUNET_log_from_nocheck (GNUNET_ERROR_TYPE_DEBUG,
2859 "transport",
2860 "Received %lu bytes for KX\n",
2861 rcvd);
2862 if (-1 == rcvd)
2863 {
2864 if ((EAGAIN != errno) && (EINTR != errno))
2865 {
2866 GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "recv");
2867 queue_destroy (queue);
2868 return;
2869 }
2870 queue->read_task =
2871 GNUNET_SCHEDULER_add_read_net (left, queue->sock, &queue_read_kx, queue);
2872 return;
2873 }
2874 queue->cread_off += rcvd;
2875 if (queue->cread_off < INITIAL_KX_SIZE)
2876 {
2877 /* read more */
2878 queue->read_task =
2879 GNUNET_SCHEDULER_add_read_net (left, queue->sock, &queue_read_kx, queue);
2880 return;
2881 }
2882 /* we got all the data, let's find out who we are talking to! */
2883 setup_in_cipher ((const struct GNUNET_CRYPTO_EcdhePublicKey *)
2884 queue->cread_buf,
2885 queue);
2886 if (GNUNET_OK != decrypt_and_check_tc (queue, &tc, queue->cread_buf))
2887 {
2888 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2889 "Invalid TCP KX received from %s\n",
2890 GNUNET_a2s (queue->address, queue->address_len));
2891 queue_destroy (queue);
2892 return;
2893 }
2894 if (0 !=
2895 memcmp (&tc.sender, &queue->target, sizeof(struct GNUNET_PeerIdentity)))
2896 {
2897 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2898 "Invalid sender in TCP KX received from %s\n",
2899 GNUNET_a2s (queue->address, queue->address_len));
2900 queue_destroy (queue);
2901 return;
2902 }
2903 send_challenge (tc.challenge, queue);
2904 queue->write_task =
2905 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
2906 queue->sock,
2907 &queue_write,
2908 queue);
2909
2910 /* update queue timeout */
2911 reschedule_queue_timeout (queue);
2912 /* prepare to continue with regular read task immediately */
2913 memmove (queue->cread_buf,
2914 &queue->cread_buf[INITIAL_KX_SIZE],
2915 queue->cread_off - (INITIAL_KX_SIZE));
2916 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2917 "cread_off is %lu bytes before adjusting\n",
2918 queue->cread_off);
2919 queue->cread_off -= INITIAL_KX_SIZE;
2920 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2921 "cread_off set to %lu bytes\n",
2922 queue->cread_off);
2923 queue->read_task = GNUNET_SCHEDULER_add_now (&queue_read, queue);
2924}
2925
2926
2927/**
2928 * Function called by the transport service to initialize a
2929 * message queue given address information about another peer.
2930 * If and when the communication channel is established, the
2931 * communicator must call #GNUNET_TRANSPORT_communicator_mq_add()
2932 * to notify the service that the channel is now up. It is
2933 * the responsibility of the communicator to manage sane
2934 * retries and timeouts for any @a peer/@a address combination
2935 * provided by the transport service. Timeouts and retries
2936 * do not need to be signalled to the transport service.
2937 *
2938 * @param cls closure
2939 * @param peer identity of the other peer
2940 * @param address where to send the message, human-readable
2941 * communicator-specific format, 0-terminated, UTF-8
2942 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the provided address is
2943 * invalid
2944 */
2945static int
2946mq_init (void *cls, const struct GNUNET_PeerIdentity *peer, const char *address)
2947{
2948 struct Queue *queue;
2949 const char *path;
2950 struct sockaddr *in;
2951 socklen_t in_len = 0;
2952 struct GNUNET_NETWORK_Handle *sock;
2953
2954 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2955 "Connecting to %s\n", address);
2956 GNUNET_log_from_nocheck (GNUNET_ERROR_TYPE_DEBUG,
2957 "transport",
2958 "Connecting to %s\n", address);
2959 if (0 != strncmp (address,
2960 COMMUNICATOR_ADDRESS_PREFIX "-",
2961 strlen (COMMUNICATOR_ADDRESS_PREFIX "-")))
2962 {
2963 GNUNET_break_op (0);
2964 return GNUNET_SYSERR;
2965 }
2966 path = &address[strlen (COMMUNICATOR_ADDRESS_PREFIX "-")];
2967 in = tcp_address_to_sockaddr (path, &in_len);
2968
2969 if (NULL == in)
2970 {
2971 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2972 "Failed to setup TCP socket address\n");
2973 return GNUNET_SYSERR;
2974 }
2975
2976 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2977 "in %s\n",
2978 GNUNET_a2s (in, in_len));
2979
2980 sock = GNUNET_NETWORK_socket_create (in->sa_family, SOCK_STREAM, IPPROTO_TCP);
2981 if (NULL == sock)
2982 {
2983 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2984 "socket(%d) failed: %s",
2985 in->sa_family,
2986 strerror (errno));
2987 GNUNET_free (in);
2988 return GNUNET_SYSERR;
2989 }
2990 if ((GNUNET_OK != GNUNET_NETWORK_socket_connect (sock, in, in_len)) &&
2991 (errno != EINPROGRESS))
2992 {
2993 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2994 "connect to `%s' failed: %s",
2995 address,
2996 strerror (errno));
2997 GNUNET_NETWORK_socket_close (sock);
2998 GNUNET_free (in);
2999 return GNUNET_SYSERR;
3000 }
3001
3002 queue = GNUNET_new (struct Queue);
3003 queue->target = *peer;
3004 queue->address = in;
3005 queue->address_len = in_len;
3006 queue->sock = sock;
3007 queue->cs = GNUNET_TRANSPORT_CS_OUTBOUND;
3008 boot_queue (queue);
3009 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3010 "booted queue with target %s\n",
3011 GNUNET_i2s (&queue->target));
3012 // queue->mq_awaits_continue = GNUNET_YES;
3013 queue->read_task =
3014 GNUNET_SCHEDULER_add_read_net (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
3015 queue->sock,
3016 &queue_read_kx,
3017 queue);
3018
3019
3020 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3021 "start kx mq_init\n");
3022
3023 start_initial_kx_out (queue);
3024 queue->write_task =
3025 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
3026 queue->sock,
3027 &queue_write,
3028 queue);
3029 return GNUNET_OK;
3030}
3031
3032
3033/**
3034 * Iterator over all ListenTasks to clean up.
3035 *
3036 * @param cls NULL
3037 * @param key unused
3038 * @param value the ListenTask to cancel.
3039 * @return #GNUNET_OK to continue to iterate
3040 */
3041static int
3042get_lt_delete_it (void *cls,
3043 const struct GNUNET_HashCode *key,
3044 void *value)
3045{
3046 struct ListenTask *lt = value;
3047
3048 (void) cls;
3049 (void) key;
3050 if (NULL != lt->listen_task)
3051 {
3052 GNUNET_SCHEDULER_cancel (lt->listen_task);
3053 lt->listen_task = NULL;
3054 }
3055 if (NULL != lt->listen_sock)
3056 {
3057 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (lt->listen_sock));
3058 lt->listen_sock = NULL;
3059 }
3060 return GNUNET_OK;
3061}
3062
3063
3064/**
3065 * Iterator over all message queues to clean up.
3066 *
3067 * @param cls NULL
3068 * @param target unused
3069 * @param value the queue to destroy
3070 * @return #GNUNET_OK to continue to iterate
3071 */
3072static int
3073get_queue_delete_it (void *cls,
3074 const struct GNUNET_PeerIdentity *target,
3075 void *value)
3076{
3077 struct Queue *queue = value;
3078
3079 (void) cls;
3080 (void) target;
3081 queue_destroy (queue);
3082 return GNUNET_OK;
3083}
3084
3085
3086/**
3087 * Shutdown the UNIX communicator.
3088 *
3089 * @param cls NULL (always)
3090 */
3091static void
3092do_shutdown (void *cls)
3093{
3094 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3095 "Shutdown %s!\n",
3096 shutdown_running ? "running" : "not running");
3097
3098 if (GNUNET_YES == shutdown_running)
3099 return;
3100 else
3101 shutdown_running = GNUNET_YES;
3102
3103 while (NULL != proto_head)
3104 free_proto_queue (proto_head);
3105 if (NULL != nat)
3106 {
3107 GNUNET_NAT_unregister (nat);
3108 nat = NULL;
3109 }
3110 GNUNET_CONTAINER_multihashmap_iterate (lt_map, &get_lt_delete_it, NULL);
3111 GNUNET_CONTAINER_multipeermap_iterate (queue_map, &get_queue_delete_it, NULL);
3112 GNUNET_CONTAINER_multipeermap_destroy (queue_map);
3113 if (NULL != ch)
3114 {
3115 GNUNET_TRANSPORT_communicator_address_remove_all (ch);
3116 GNUNET_TRANSPORT_communicator_disconnect (ch);
3117 ch = NULL;
3118 }
3119 if (NULL != stats)
3120 {
3121 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
3122 stats = NULL;
3123 }
3124 if (NULL != my_private_key)
3125 {
3126 GNUNET_free (my_private_key);
3127 my_private_key = NULL;
3128 }
3129 if (NULL != is)
3130 {
3131 GNUNET_NT_scanner_done (is);
3132 is = NULL;
3133 }
3134 if (NULL != peerstore)
3135 {
3136 GNUNET_PEERSTORE_disconnect (peerstore, GNUNET_NO);
3137 peerstore = NULL;
3138 }
3139 if (NULL != resolve_request_handle)
3140 {
3141 GNUNET_RESOLVER_request_cancel (resolve_request_handle);
3142 resolve_request_handle = NULL;
3143 }
3144 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3145 "Shutdown done!\n");
3146}
3147
3148
3149/**
3150 * Function called when the transport service has received an
3151 * acknowledgement for this communicator (!) via a different return
3152 * path.
3153 *
3154 * Not applicable for TCP.
3155 *
3156 * @param cls closure
3157 * @param sender which peer sent the notification
3158 * @param msg payload
3159 */
3160static void
3161enc_notify_cb (void *cls,
3162 const struct GNUNET_PeerIdentity *sender,
3163 const struct GNUNET_MessageHeader *msg)
3164{
3165 (void) cls;
3166 (void) sender;
3167 (void) msg;
3168 GNUNET_break_op (0);
3169}
3170
3171
3172/**
3173 * Signature of the callback passed to #GNUNET_NAT_register() for
3174 * a function to call whenever our set of 'valid' addresses changes.
3175 *
3176 * @param cls closure
3177 * @param app_ctx[in,out] location where the app can store stuff
3178 * on add and retrieve it on remove
3179 * @param add_remove #GNUNET_YES to add a new public IP address,
3180 * #GNUNET_NO to remove a previous (now invalid) one
3181 * @param ac address class the address belongs to
3182 * @param addr either the previous or the new public IP address
3183 * @param addrlen actual length of the @a addr
3184 */
3185static void
3186nat_address_cb (void *cls,
3187 void **app_ctx,
3188 int add_remove,
3189 enum GNUNET_NAT_AddressClass ac,
3190 const struct sockaddr *addr,
3191 socklen_t addrlen)
3192{
3193 char *my_addr;
3194 struct GNUNET_TRANSPORT_AddressIdentifier *ai;
3195
3196 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3197 "nat address cb %s %s\n",
3198 add_remove ? "add" : "remove",
3199 GNUNET_a2s (addr, addrlen));
3200
3201 if (GNUNET_YES == add_remove)
3202 {
3203 enum GNUNET_NetworkType nt;
3204
3205 GNUNET_asprintf (&my_addr,
3206 "%s-%s",
3207 COMMUNICATOR_ADDRESS_PREFIX,
3208 GNUNET_a2s (addr, addrlen));
3209 nt = GNUNET_NT_scanner_get_type (is, addr, addrlen);
3210 ai =
3211 GNUNET_TRANSPORT_communicator_address_add (ch,
3212 my_addr,
3213 nt,
3214 GNUNET_TIME_UNIT_FOREVER_REL);
3215 GNUNET_free (my_addr);
3216 *app_ctx = ai;
3217 }
3218 else
3219 {
3220 ai = *app_ctx;
3221 GNUNET_TRANSPORT_communicator_address_remove (ai);
3222 *app_ctx = NULL;
3223 }
3224}
3225
3226
3227/**
3228 * This method adds addresses to the DLL, that are later register at the NAT service.
3229 */
3230static void
3231add_addr (struct sockaddr *in, socklen_t in_len)
3232{
3233
3234 struct Addresses *saddrs;
3235
3236 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3237 "add address %s\n",
3238 GNUNET_a2s (in, in_len));
3239
3240 saddrs = GNUNET_new (struct Addresses);
3241 saddrs->addr = in;
3242 saddrs->addr_len = in_len;
3243 GNUNET_CONTAINER_DLL_insert (addrs_head, addrs_tail, saddrs);
3244
3245 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3246 "after add address %s\n",
3247 GNUNET_a2s (in, in_len));
3248
3249 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3250 "add address %s\n",
3251 GNUNET_a2s (saddrs->addr, saddrs->addr_len));
3252
3253 addrs_lens++;
3254}
3255
3256
3257/**
3258 * This method launch network interactions for each address we like to bind to.
3259 *
3260 * @param addr The address we will listen to.
3261 * @param in_len The length of the address we will listen to.
3262 * @return GNUNET_SYSERR in case of error. GNUNET_OK in case we are successfully listen to the address.
3263 */
3264static int
3265init_socket (struct sockaddr *addr,
3266 socklen_t in_len)
3267{
3268 struct sockaddr_storage in_sto;
3269 socklen_t sto_len;
3270 struct GNUNET_NETWORK_Handle *listen_sock;
3271 struct ListenTask *lt;
3272 int sockfd;
3273 struct GNUNET_HashCode h_sock;
3274
3275 if (NULL == addr)
3276 {
3277 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3278 "Address is NULL.\n");
3279 return GNUNET_SYSERR;
3280 }
3281
3282 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3283 "address %s\n",
3284 GNUNET_a2s (addr, in_len));
3285
3286 listen_sock =
3287 GNUNET_NETWORK_socket_create (addr->sa_family, SOCK_STREAM, IPPROTO_TCP);
3288 if (NULL == listen_sock)
3289 {
3290 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
3291 return GNUNET_SYSERR;
3292 }
3293
3294 if (GNUNET_OK != GNUNET_NETWORK_socket_bind (listen_sock, addr, in_len))
3295 {
3296 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
3297 GNUNET_NETWORK_socket_close (listen_sock);
3298 listen_sock = NULL;
3299 return GNUNET_SYSERR;
3300 }
3301
3302 if (GNUNET_OK !=
3303 GNUNET_NETWORK_socket_listen (listen_sock,
3304 5))
3305 {
3306 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
3307 "listen");
3308 GNUNET_NETWORK_socket_close (listen_sock);
3309 listen_sock = NULL;
3310 return GNUNET_SYSERR;
3311 }
3312
3313 /* We might have bound to port 0, allowing the OS to figure it out;
3314 thus, get the real IN-address from the socket */
3315 sto_len = sizeof(in_sto);
3316
3317 if (0 != getsockname (GNUNET_NETWORK_get_fd (listen_sock),
3318 (struct sockaddr *) &in_sto,
3319 &sto_len))
3320 {
3321 memcpy (&in_sto, addr, in_len);
3322 sto_len = in_len;
3323 }
3324
3325 // addr = (struct sockaddr *) &in_sto;
3326 in_len = sto_len;
3327 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3328 "Bound to `%s'\n",
3329 GNUNET_a2s ((const struct sockaddr *) &in_sto, sto_len));
3330 stats = GNUNET_STATISTICS_create ("C-TCP", cfg);
3331
3332 if (NULL == is)
3333 is = GNUNET_NT_scanner_init ();
3334
3335 if (NULL == my_private_key)
3336 my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg);
3337 if (NULL == my_private_key)
3338 {
3339 GNUNET_log (
3340 GNUNET_ERROR_TYPE_ERROR,
3341 _ (
3342 "Transport service is lacking key configuration settings. Exiting.\n"));
3343 if (NULL != resolve_request_handle)
3344 GNUNET_RESOLVER_request_cancel (resolve_request_handle);
3345 GNUNET_SCHEDULER_shutdown ();
3346 return GNUNET_SYSERR;
3347 }
3348 GNUNET_CRYPTO_eddsa_key_get_public (my_private_key, &my_identity.public_key);
3349 /* start listening */
3350
3351 lt = GNUNET_new (struct ListenTask);
3352 lt->listen_sock = listen_sock;
3353
3354 lt->listen_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
3355 listen_sock,
3356 &listen_cb,
3357 lt);
3358
3359 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3360 "creating hash\n");
3361 sockfd = GNUNET_NETWORK_get_fd (lt->listen_sock);
3362 GNUNET_CRYPTO_hash (&sockfd,
3363 sizeof(int),
3364 &h_sock);
3365
3366 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3367 "creating map\n");
3368 if (NULL == lt_map)
3369 lt_map = GNUNET_CONTAINER_multihashmap_create (2, GNUNET_NO);
3370
3371 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3372 "creating map entry\n");
3373 GNUNET_assert (GNUNET_OK ==
3374 GNUNET_CONTAINER_multihashmap_put (lt_map,
3375 &h_sock,
3376 lt,
3377 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
3378
3379 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3380 "map entry created\n");
3381
3382 if (NULL == queue_map)
3383 queue_map = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO);
3384
3385 if (NULL == ch)
3386 ch = GNUNET_TRANSPORT_communicator_connect (cfg,
3387 COMMUNICATOR_CONFIG_SECTION,
3388 COMMUNICATOR_ADDRESS_PREFIX,
3389 GNUNET_TRANSPORT_CC_RELIABLE,
3390 &mq_init,
3391 NULL,
3392 &enc_notify_cb,
3393 NULL);
3394
3395 if (NULL == ch)
3396 {
3397 GNUNET_break (0);
3398 if (NULL != resolve_request_handle)
3399 GNUNET_RESOLVER_request_cancel (resolve_request_handle);
3400 GNUNET_SCHEDULER_shutdown ();
3401 return GNUNET_SYSERR;
3402 }
3403
3404 add_addr (addr, in_len);
3405 return GNUNET_OK;
3406
3407}
3408
3409
3410/**
3411 * This method reads from the DLL addrs_head to register them at the NAT service.
3412 */
3413static void
3414nat_register ()
3415{
3416 struct sockaddr **saddrs;
3417 socklen_t *saddr_lens;
3418 int i;
3419 size_t len;
3420
3421 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3422 "starting nat register!\n");
3423 len = 0;
3424 i = 0;
3425 saddrs = GNUNET_malloc ((addrs_lens) * sizeof(struct sockaddr *));
3426 saddr_lens = GNUNET_malloc ((addrs_lens) * sizeof(socklen_t));
3427 for (struct Addresses *pos = addrs_head; NULL != pos; pos = pos->next)
3428 {
3429 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3430 "registering address %s\n",
3431 GNUNET_a2s (addrs_head->addr, addrs_head->addr_len));
3432
3433 saddr_lens[i] = addrs_head->addr_len;
3434 len += saddr_lens[i];
3435 saddrs[i] = GNUNET_memdup (addrs_head->addr, saddr_lens[i]);
3436 i++;
3437 }
3438
3439 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3440 "registering addresses %lu %lu %lu %lu\n",
3441 (addrs_lens) * sizeof(struct sockaddr *),
3442 (addrs_lens) * sizeof(socklen_t),
3443 len,
3444 sizeof(COMMUNICATOR_CONFIG_SECTION));
3445 nat = GNUNET_NAT_register (cfg,
3446 COMMUNICATOR_CONFIG_SECTION,
3447 IPPROTO_TCP,
3448 addrs_lens,
3449 (const struct sockaddr **) saddrs,
3450 saddr_lens,
3451 &nat_address_cb,
3452 NULL /* FIXME: support reversal: #5529 */,
3453 NULL /* closure */);
3454 for (i = addrs_lens - 1; i >= 0; i--)
3455 GNUNET_free (saddrs[i]);
3456 GNUNET_free (saddrs);
3457 GNUNET_free (saddr_lens);
3458
3459 if (NULL == nat)
3460 {
3461 GNUNET_break (0);
3462 if (NULL != resolve_request_handle)
3463 GNUNET_RESOLVER_request_cancel (resolve_request_handle);
3464 GNUNET_SCHEDULER_shutdown ();
3465 }
3466}
3467
3468
3469/**
3470 * This method is the callback called by the resolver API, and wraps method init_socket.
3471 *
3472 * @param cls The port we will bind to.
3473 * @param addr The address we will bind to.
3474 * @param in_len The length of the address we will bind to.
3475 */
3476static void
3477init_socket_resolv (void *cls,
3478 const struct sockaddr *addr,
3479 socklen_t in_len)
3480{
3481 struct sockaddr_in *v4;
3482 struct sockaddr_in6 *v6;
3483 struct sockaddr *in;
3484
3485 (void) cls;
3486 if (NULL != addr)
3487 {
3488 if (AF_INET == addr->sa_family)
3489 {
3490 v4 = (struct sockaddr_in *) addr;
3491 in = tcp_address_to_sockaddr_numeric_v4 (&in_len, *v4, bind_port);// _global);
3492 }
3493 else if (AF_INET6 == addr->sa_family)
3494 {
3495 v6 = (struct sockaddr_in6 *) addr;
3496 in = tcp_address_to_sockaddr_numeric_v6 (&in_len, *v6, bind_port);// _global);
3497 }
3498 else
3499 {
3500 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3501 "Address family %u not suitable (not AF_INET %u nor AF_INET6 %u \n",
3502 addr->sa_family,
3503 AF_INET,
3504 AF_INET6);
3505 return;
3506 }
3507 init_socket (in, in_len);
3508 }
3509 else
3510 {
3511 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3512 "Address is NULL. This might be an error or the resolver finished resolving.\n");
3513 if (NULL == addrs_head)
3514 {
3515 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3516 "Resolver finished resolving, but we do not listen to an address!.\n");
3517 return;
3518 }
3519 nat_register ();
3520 }
3521}
3522
3523
3524/**
3525 * Setup communicator and launch network interactions.
3526 *
3527 * @param cls NULL (always)
3528 * @param args remaining command-line arguments
3529 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
3530 * @param c configuration
3531 */
3532static void
3533run (void *cls,
3534 char *const *args,
3535 const char *cfgfile,
3536 const struct GNUNET_CONFIGURATION_Handle *c)
3537{
3538 char *bindto;
3539 struct sockaddr *in;
3540 socklen_t in_len;
3541 struct sockaddr_in v4;
3542 struct sockaddr_in6 v6;
3543 char *start;
3544 unsigned int port;
3545 char dummy[2];
3546 char *rest = NULL;
3547 struct PortOnlyIpv4Ipv6 *po;
3548 socklen_t addr_len_ipv4;
3549 socklen_t addr_len_ipv6;
3550
3551 (void) cls;
3552 cfg = c;
3553 if (GNUNET_OK !=
3554 GNUNET_CONFIGURATION_get_value_string (cfg,
3555 COMMUNICATOR_CONFIG_SECTION,
3556 "BINDTO",
3557 &bindto))
3558 {
3559 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
3560 COMMUNICATOR_CONFIG_SECTION,
3561 "BINDTO");
3562 return;
3563 }
3564 if (GNUNET_OK !=
3565 GNUNET_CONFIGURATION_get_value_number (cfg,
3566 COMMUNICATOR_CONFIG_SECTION,
3567 "MAX_QUEUE_LENGTH",
3568 &max_queue_length))
3569 max_queue_length = DEFAULT_MAX_QUEUE_LENGTH;
3570 if (GNUNET_OK !=
3571 GNUNET_CONFIGURATION_get_value_time (cfg,
3572 COMMUNICATOR_CONFIG_SECTION,
3573 "REKEY_INTERVAL",
3574 &rekey_interval))
3575 rekey_interval = DEFAULT_REKEY_INTERVAL;
3576
3577 peerstore = GNUNET_PEERSTORE_connect (cfg);
3578 if (NULL == peerstore)
3579 {
3580 GNUNET_free (bindto);
3581 GNUNET_break (0);
3582 GNUNET_SCHEDULER_shutdown ();
3583 return;
3584 }
3585
3586 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
3587
3588 if (1 == sscanf (bindto, "%u%1s", &bind_port, dummy))
3589 {
3590 po = tcp_address_to_sockaddr_port_only (bindto, &bind_port);
3591 addr_len_ipv4 = po->addr_len_ipv4;
3592 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3593 "address po %s\n",
3594 GNUNET_a2s (po->addr_ipv4, addr_len_ipv4));
3595 if (NULL != po->addr_ipv4)
3596 {
3597 init_socket (po->addr_ipv4, addr_len_ipv4);
3598 }
3599 if (NULL != po->addr_ipv6)
3600 {
3601 addr_len_ipv6 = po->addr_len_ipv6;
3602 init_socket (po->addr_ipv6, addr_len_ipv6);
3603 }
3604 GNUNET_free (po);
3605 nat_register ();
3606 GNUNET_free (bindto);
3607 return;
3608 }
3609
3610 start = extract_address (bindto);
3611 // FIXME: check for NULL == start...
3612 if (1 == inet_pton (AF_INET, start, &v4.sin_addr))
3613 {
3614 bind_port = extract_port (bindto);
3615
3616 in = tcp_address_to_sockaddr_numeric_v4 (&in_len, v4, bind_port);
3617 init_socket (in, in_len);
3618 nat_register ();
3619 GNUNET_free (start);
3620 GNUNET_free (bindto);
3621 return;
3622 }
3623
3624 if (1 == inet_pton (AF_INET6, start, &v6.sin6_addr))
3625 {
3626 bind_port = extract_port (bindto);
3627 in = tcp_address_to_sockaddr_numeric_v6 (&in_len, v6, bind_port);
3628 init_socket (in, in_len);
3629 nat_register ();
3630 GNUNET_free (start);
3631 GNUNET_free (bindto);
3632 return;
3633 }
3634
3635 bind_port = extract_port (bindto);
3636 resolve_request_handle = GNUNET_RESOLVER_ip_get (strtok_r (bindto,
3637 ":",
3638 &rest),
3639 AF_UNSPEC,
3640 GNUNET_TIME_UNIT_MINUTES,
3641 &init_socket_resolv,
3642 &port);
3643 GNUNET_free (bindto);
3644 GNUNET_free (start);
3645}
3646
3647
3648/**
3649 * The main function for the UNIX communicator.
3650 *
3651 * @param argc number of arguments from the command line
3652 * @param argv command line arguments
3653 * @return 0 ok, 1 on error
3654 */
3655int
3656main (int argc, char *const *argv)
3657{
3658 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
3659 GNUNET_GETOPT_OPTION_END
3660 };
3661 int ret;
3662
3663 GNUNET_log_from_nocheck (GNUNET_ERROR_TYPE_DEBUG,
3664 "transport",
3665 "Starting tcp communicator\n");
3666 if (GNUNET_OK !=
3667 GNUNET_STRINGS_get_utf8_args (argc, argv,
3668 &argc, &argv))
3669 return 2;
3670
3671 ret = (GNUNET_OK ==
3672 GNUNET_PROGRAM_run (argc,
3673 argv,
3674 "gnunet-communicator-tcp",
3675 _ ("GNUnet TCP communicator"),
3676 options,
3677 &run,
3678 NULL))
3679 ? 0
3680 : 1;
3681 GNUNET_free_nz ((void *) argv);
3682 return ret;
3683}
3684
3685
3686/* end of gnunet-communicator-tcp.c */
diff --git a/src/transport/gnunet-communicator-udp.c b/src/transport/gnunet-communicator-udp.c
deleted file mode 100644
index 70848ff79..000000000
--- a/src/transport/gnunet-communicator-udp.c
+++ /dev/null
@@ -1,3953 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2010-2014, 2018, 2019 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-communicator-udp.c
23 * @brief Transport plugin using UDP.
24 * @author Christian Grothoff
25 *
26 * TODO:
27 * - consider imposing transmission limits in the absence
28 * of ACKs; or: maybe this should be done at TNG service level?
29 * (at least the receiver might want to enforce limits on
30 * KX/DH operations per sender in here) (#5552)
31 * - overall, we should look more into flow control support
32 * (either in backchannel, or general solution in TNG service)
33 * - handle addresses discovered from broadcasts (#5551)
34 * (think: what was the story again on address validation?
35 * where is the API for that!?!)
36 * - support DNS names in BINDTO option (#5528)
37 * - support NAT connection reversal method (#5529)
38 * - support other UDP-specific NAT traversal methods (#)
39 */
40#include "platform.h"
41#include "gnunet_util_lib.h"
42#include "gnunet_protocols.h"
43#include "gnunet_signatures.h"
44#include "gnunet_constants.h"
45#include "gnunet_nt_lib.h"
46#include "gnunet_nat_service.h"
47#include "gnunet_statistics_service.h"
48#include "gnunet_transport_application_service.h"
49#include "gnunet_transport_communication_service.h"
50
51/**
52 * How often do we rekey based on time (at least)
53 */
54#define DEFAULT_REKEY_TIME_INTERVAL GNUNET_TIME_UNIT_DAYS
55
56/**
57 * How long do we wait until we must have received the initial KX?
58 */
59#define PROTO_QUEUE_TIMEOUT GNUNET_TIME_UNIT_MINUTES
60
61/**
62 * How often do we broadcast our presence on the LAN?
63 */
64#define BROADCAST_FREQUENCY GNUNET_TIME_UNIT_MINUTES
65
66/**
67 * How often do we scan for changes to our network interfaces?
68 */
69#define INTERFACE_SCAN_FREQUENCY \
70 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
71
72/**
73 * How long do we believe our addresses to remain up (before
74 * the other peer should revalidate).
75 */
76#define ADDRESS_VALIDITY_PERIOD GNUNET_TIME_UNIT_HOURS
77
78#define WORKING_QUEUE_INTERVALL \
79 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MICROSECONDS,1)
80
81/**
82 * AES key size.
83 */
84#define AES_KEY_SIZE (256 / 8)
85
86/**
87 * AES (GCM) IV size.
88 */
89#define AES_IV_SIZE (96 / 8)
90
91/**
92 * Size of the GCM tag.
93 */
94#define GCM_TAG_SIZE (128 / 8)
95
96#define GENERATE_AT_ONCE 2
97
98/**
99 * If we fall below this number of available KCNs,
100 * we generate additional ACKs until we reach
101 * #KCN_TARGET.
102 * Should be large enough that we don't generate ACKs all
103 * the time and still have enough time for the ACK to
104 * arrive before the sender runs out. So really this
105 * should ideally be based on the RTT.
106 */
107#define KCN_THRESHOLD 92
108
109/**
110 * How many KCNs do we keep around *after* we hit
111 * the #KCN_THRESHOLD? Should be larger than
112 * #KCN_THRESHOLD so we do not generate just one
113 * ACK at the time.
114 */
115#define KCN_TARGET 128
116
117/**
118 * What is the maximum delta between KCN sequence numbers
119 * that we allow. Used to expire 'ancient' KCNs that likely
120 * were dropped by the network. Must be larger than
121 * KCN_TARGET (otherwise we generate new KCNs all the time),
122 * but not too large (otherwise packet loss may cause
123 * sender to fall back to KX needlessly when sender runs
124 * out of ACK'ed KCNs due to losses).
125 */
126#define MAX_SQN_DELTA 160
127
128/**
129 * How many shared master secrets do we keep around
130 * at most per sender? Should be large enough so
131 * that we generally have a chance of sending an ACK
132 * before the sender already rotated out the master
133 * secret. Generally values around #KCN_TARGET make
134 * sense. Might make sense to adapt to RTT if we had
135 * a good measurement...
136 */
137#define MAX_SECRETS 128000
138
139/**
140 * Default value for how often we do rekey based on number of bytes transmitted?
141 * (additionally randomized).
142 */
143#define DEFAULT_REKEY_MAX_BYTES (1024LLU * 1024 * 1024 * 4LLU)
144
145/**
146 * Address prefix used by the communicator.
147 */
148
149#define COMMUNICATOR_ADDRESS_PREFIX "udp"
150
151/**
152 * Configuration section used by the communicator.
153 */
154#define COMMUNICATOR_CONFIG_SECTION "communicator-udp"
155
156GNUNET_NETWORK_STRUCT_BEGIN
157
158
159/**
160 * Signature we use to verify that the ephemeral key was really chosen by
161 * the specified sender. If possible, the receiver should respond with
162 * a `struct UDPAck` (possibly via backchannel).
163 */
164struct UdpHandshakeSignature
165{
166 /**
167 * Purpose must be #GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_UDP_HANDSHAKE
168 */
169 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
170
171 /**
172 * Identity of the inititor of the UDP connection (UDP client).
173 */
174 struct GNUNET_PeerIdentity sender;
175
176 /**
177 * Presumed identity of the target of the UDP connection (UDP server)
178 */
179 struct GNUNET_PeerIdentity receiver;
180
181 /**
182 * Ephemeral key used by the @e sender.
183 */
184 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral;
185
186 /**
187 * Monotonic time of @e sender, to possibly help detect replay attacks
188 * (if receiver persists times by sender).
189 */
190 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
191};
192
193
194/**
195 * "Plaintext" header at beginning of KX message. Followed
196 * by encrypted `struct UDPConfirmation`.
197 */
198struct InitialKX
199{
200 /**
201 * Ephemeral key for KX.
202 */
203 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral;
204
205 /**
206 * HMAC for the following encrypted message, using GCM. HMAC uses
207 * key derived from the handshake with sequence number zero.
208 */
209 char gcm_tag[GCM_TAG_SIZE];
210
211 /**
212 * A flag indicating, if the sender is doing rekeying.
213 */
214 int rekeying;
215};
216
217
218/**
219 * Encrypted continuation of UDP initial handshake, followed
220 * by message header with payload.
221 */
222struct UDPConfirmation
223{
224 /**
225 * Sender's identity
226 */
227 struct GNUNET_PeerIdentity sender;
228
229 /**
230 * Sender's signature of type #GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_UDP_HANDSHAKE
231 */
232 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
233
234 /**
235 * Monotonic time of @e sender, to possibly help detect replay attacks
236 * (if receiver persists times by sender).
237 */
238 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
239
240 /* followed by messages */
241
242 /* padding may follow actual messages */
243};
244
245
246/**
247 * UDP key acknowledgement. May be sent via backchannel. Allows the
248 * sender to use `struct UDPBox` with the acknowledge key henceforth.
249 */
250struct UDPAck
251{
252 /**
253 * Type is #GNUNET_MESSAGE_TYPE_COMMUNICATOR_UDP_ACK.
254 */
255 struct GNUNET_MessageHeader header;
256
257 /**
258 * Sequence acknowledgement limit. Specifies current maximum sequence
259 * number supported by receiver.
260 */
261 uint32_t sequence_max GNUNET_PACKED;
262
263 /**
264 * Sequence acknowledgement limit. Specifies current maximum sequence
265 * number supported by receiver.
266 */
267 uint32_t acks_available GNUNET_PACKED;
268
269 /**
270 * CMAC of the base key being acknowledged.
271 */
272 struct GNUNET_HashCode cmac;
273};
274
275
276/**
277 * Signature we use to verify that the broadcast was really made by
278 * the peer that claims to have made it. Basically, affirms that the
279 * peer is really using this IP address (albeit possibly not in _our_
280 * LAN). Makes it difficult for peers in the LAN to claim to
281 * be just any global peer -- an attacker must have at least
282 * shared a LAN with the peer they're pretending to be here.
283 */
284struct UdpBroadcastSignature
285{
286 /**
287 * Purpose must be #GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_UDP_BROADCAST
288 */
289 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
290
291 /**
292 * Identity of the inititor of the UDP broadcast.
293 */
294 struct GNUNET_PeerIdentity sender;
295
296 /**
297 * Hash of the sender's UDP address.
298 */
299 struct GNUNET_HashCode h_address;
300};
301
302
303/**
304 * Broadcast by peer in LAN announcing its presence. Unusual in that
305 * we don't pad these to full MTU, as we cannot prevent being
306 * recognized in LAN as GNUnet peers if this feature is enabled
307 * anyway. Also, the entire message is in cleartext.
308 */
309struct UDPBroadcast
310{
311 /**
312 * Sender's peer identity.
313 */
314 struct GNUNET_PeerIdentity sender;
315
316 /**
317 * Sender's signature of type
318 * #GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_UDP_BROADCAST
319 */
320 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
321};
322
323
324/**
325 * UDP message box. Always sent encrypted, only allowed after
326 * the receiver sent a `struct UDPAck` for the base key!
327 */
328struct UDPBox
329{
330 /**
331 * Key and IV identification code. KDF applied to an acknowledged
332 * base key and a sequence number. Sequence numbers must be used
333 * monotonically increasing up to the maximum specified in
334 * `struct UDPAck`. Without further `struct UDPAck`s, the sender
335 * must fall back to sending handshakes!
336 */
337 struct GNUNET_ShortHashCode kid;
338
339 /**
340 * 128-bit authentication tag for the following encrypted message,
341 * from GCM. MAC starts at the @e body_start that follows and
342 * extends until the end of the UDP payload. If the @e hmac is
343 * wrong, the receiver should check if the message might be a
344 * `struct UdpHandshakeSignature`.
345 */
346 char gcm_tag[GCM_TAG_SIZE];
347
348 /**
349 * A flag indicating, if the sender is doing rekeying.
350 */
351 int rekeying;
352};
353
354/**
355 * UDP message box. Always sent encrypted, only allowed after
356 * the receiver sent a `struct UDPAck` for the base key!
357 */
358struct UDPRekey
359{
360 /**
361 * Key and IV identification code. KDF applied to an acknowledged
362 * base key and a sequence number. Sequence numbers must be used
363 * monotonically increasing up to the maximum specified in
364 * `struct UDPAck`. Without further `struct UDPAck`s, the sender
365 * must fall back to sending handshakes!
366 */
367 struct GNUNET_ShortHashCode kid;
368
369 /**
370 * 128-bit authentication tag for the following encrypted message,
371 * from GCM. MAC starts at the @e body_start that follows and
372 * extends until the end of the UDP payload. If the @e hmac is
373 * wrong, the receiver should check if the message might be a
374 * `struct UdpHandshakeSignature`.
375 */
376 char gcm_tag[GCM_TAG_SIZE];
377
378 /**
379 * Sender's identity
380 */
381 struct GNUNET_PeerIdentity sender;
382};
383
384GNUNET_NETWORK_STRUCT_END
385
386/**
387 * Shared secret we generated for a particular sender or receiver.
388 */
389struct SharedSecret;
390
391
392/**
393 * Pre-generated "kid" code (key and IV identification code) to
394 * quickly derive master key for a `struct UDPBox`.
395 */
396struct KeyCacheEntry
397{
398 /**
399 * Kept in a DLL.
400 */
401 struct KeyCacheEntry *next;
402
403 /**
404 * Kept in a DLL.
405 */
406 struct KeyCacheEntry *prev;
407
408 /**
409 * Key and IV identification code. KDF applied to an acknowledged
410 * base key and a sequence number. Sequence numbers must be used
411 * monotonically increasing up to the maximum specified in
412 * `struct UDPAck`. Without further `struct UDPAck`s, the sender
413 * must fall back to sending handshakes!
414 */
415 struct GNUNET_ShortHashCode kid;
416
417 /**
418 * Corresponding shared secret.
419 */
420 struct SharedSecret *ss;
421
422 /**
423 * Sequence number used to derive this entry from master key.
424 */
425 uint32_t sequence_number;
426};
427
428
429/**
430 * Information we track per sender address we have recently been
431 * in contact with (decryption from sender).
432 */
433struct SenderAddress;
434
435/**
436 * Information we track per receiving address we have recently been
437 * in contact with (encryption to receiver).
438 */
439struct ReceiverAddress;
440
441/**
442 * Shared secret we generated for a particular sender or receiver.
443 */
444struct SharedSecret
445{
446 /**
447 * Kept in a DLL.
448 */
449 struct SharedSecret *next;
450
451 /**
452 * Kept in a DLL.
453 */
454 struct SharedSecret *prev;
455
456 /**
457 * Kept in a DLL, sorted by sequence number. Only if we are decrypting.
458 */
459 struct KeyCacheEntry *kce_head;
460
461 /**
462 * Kept in a DLL, sorted by sequence number. Only if we are decrypting.
463 */
464 struct KeyCacheEntry *kce_tail;
465
466 /**
467 * Sender we use this shared secret with, or NULL.
468 */
469 struct SenderAddress *sender;
470
471 /**
472 * Receiver we use this shared secret with, or NULL.
473 */
474 struct ReceiverAddress *receiver;
475
476 /**
477 * Master shared secret.
478 */
479 struct GNUNET_HashCode master;
480
481 /**
482 * CMAC is used to identify @e master in ACKs.
483 */
484 struct GNUNET_HashCode cmac;
485
486 /**
487 * Up to which sequence number did we use this @e master already?
488 * (for encrypting only)
489 */
490 uint32_t sequence_used;
491
492 /**
493 * Up to which sequence number did the other peer allow us to use
494 * this key, or up to which number did we allow the other peer to
495 * use this key?
496 */
497 uint32_t sequence_allowed;
498
499 /**
500 * Number of active KCN entries.
501 */
502 unsigned int active_kce_count;
503};
504
505
506/**
507 * Information we track per sender address we have recently been
508 * in contact with (we decrypt messages from the sender).
509 */
510struct SenderAddress
511{
512 /**
513 * Shared secret we use with @e target for rekeying.
514 */
515 struct SharedSecret *ss_rekey;
516
517 /**
518 * Flag indicating sender is initiated rekeying for this receiver.
519 */
520 int rekeying;
521
522 /**
523 * To whom are we talking to.
524 */
525 struct GNUNET_PeerIdentity target;
526
527 /**
528 * Entry in sender expiration heap.
529 */
530 struct GNUNET_CONTAINER_HeapNode *hn;
531
532 /**
533 * Shared secrets we used with @e target, first used is head.
534 */
535 struct SharedSecret *ss_head;
536
537 /**
538 * Shared secrets we used with @e target, last used is tail.
539 */
540 struct SharedSecret *ss_tail;
541
542 /**
543 * Address of the other peer.
544 */
545 struct sockaddr *address;
546
547 /**
548 * Length of the address.
549 */
550 socklen_t address_len;
551
552 /**
553 * Timeout for this sender.
554 */
555 struct GNUNET_TIME_Absolute timeout;
556
557 /**
558 * Length of the DLL at @a ss_head.
559 */
560 unsigned int num_secrets;
561
562 /**
563 * Number of BOX keys from ACKs we have currently
564 * available for this sender.
565 */
566 unsigned int acks_available;
567
568 /**
569 * Which network type does this queue use?
570 */
571 enum GNUNET_NetworkType nt;
572
573 /**
574 * sender_destroy already called on sender.
575 */
576 int sender_destroy_called;
577
578
579 /**
580 * ID of kce working queue task
581 */
582 struct GNUNET_SCHEDULER_Task *kce_task;
583
584 /**
585 * ID of kce rekey working queue task
586 */
587 struct GNUNET_SCHEDULER_Task *kce_task_rekey;
588
589 /**
590 * Is the kce_task finished?
591 */
592 int kce_task_finished;
593};
594
595
596/**
597 * Information we track per receiving address we have recently been
598 * in contact with (encryption to receiver).
599 */
600struct ReceiverAddress
601{
602
603 /**
604 * Shared secret we use with @e target for rekeying.
605 */
606 struct SharedSecret *ss_rekey;
607
608 /**
609 * Acks available when we started rekeying.
610 */
611 unsigned int rekey_acks_available;
612
613 /**
614 * Send bytes for this receiver address.
615 */
616 uint64_t rekey_send_bytes;
617
618 /**
619 * Timeout for this receiver address.
620 */
621 struct GNUNET_TIME_Absolute rekey_timeout;
622
623 /**
624 * Flag indicating sender is initiated rekeying for this receiver.
625 */
626 int rekeying;
627
628 /**
629 * Number of kce we retain for sending the rekeying shared secret.
630 */
631 int number_rekeying_kce;
632
633 /**
634 * To whom are we talking to.
635 */
636 struct GNUNET_PeerIdentity target;
637
638 /**
639 * Shared secrets we received from @e target, first used is head.
640 */
641 struct SharedSecret *ss_head;
642
643 /**
644 * Shared secrets we received with @e target, last used is tail.
645 */
646 struct SharedSecret *ss_tail;
647
648 /**
649 * Address of the receiver in the human-readable format
650 * with the #COMMUNICATOR_ADDRESS_PREFIX.
651 */
652 char *foreign_addr;
653
654 /**
655 * Address of the other peer.
656 */
657 struct sockaddr *address;
658
659 /**
660 * Length of the address.
661 */
662 socklen_t address_len;
663
664 /**
665 * Entry in sender expiration heap.
666 */
667 struct GNUNET_CONTAINER_HeapNode *hn;
668
669 /**
670 * KX message queue we are providing for the #ch.
671 */
672 struct GNUNET_MQ_Handle *kx_mq;
673
674 /**
675 * Default message queue we are providing for the #ch.
676 */
677 struct GNUNET_MQ_Handle *d_mq;
678
679 /**
680 * handle for KX queue with the #ch.
681 */
682 struct GNUNET_TRANSPORT_QueueHandle *kx_qh;
683
684 /**
685 * handle for default queue with the #ch.
686 */
687 struct GNUNET_TRANSPORT_QueueHandle *d_qh;
688
689 /**
690 * Timeout for this receiver address.
691 */
692 struct GNUNET_TIME_Absolute timeout;
693
694 /**
695 * MTU we allowed transport for this receiver's KX queue.
696 */
697 size_t kx_mtu;
698
699 /**
700 * MTU we allowed transport for this receiver's default queue.
701 */
702 size_t d_mtu;
703
704 /**
705 * Length of the DLL at @a ss_head.
706 */
707 unsigned int num_secrets;
708
709 /**
710 * Number of BOX keys from ACKs we have currently
711 * available for this receiver.
712 */
713 unsigned int acks_available;
714
715 /**
716 * Which network type does this queue use?
717 */
718 enum GNUNET_NetworkType nt;
719
720 /**
721 * receiver_destroy already called on receiver.
722 */
723 int receiver_destroy_called;
724};
725
726/**
727 * Interface we broadcast our presence on.
728 */
729struct BroadcastInterface
730{
731 /**
732 * Kept in a DLL.
733 */
734 struct BroadcastInterface *next;
735
736 /**
737 * Kept in a DLL.
738 */
739 struct BroadcastInterface *prev;
740
741 /**
742 * Task for this broadcast interface.
743 */
744 struct GNUNET_SCHEDULER_Task *broadcast_task;
745
746 /**
747 * Sender's address of the interface.
748 */
749 struct sockaddr *sa;
750
751 /**
752 * Broadcast address to use on the interface.
753 */
754 struct sockaddr *ba;
755
756 /**
757 * Message we broadcast on this interface.
758 */
759 struct UDPBroadcast bcm;
760
761 /**
762 * If this is an IPv6 interface, this is the request
763 * we use to join/leave the group.
764 */
765 struct ipv6_mreq mcreq;
766
767 /**
768 * Number of bytes in @e sa.
769 */
770 socklen_t salen;
771
772 /**
773 * Was this interface found in the last #iface_proc() scan?
774 */
775 int found;
776};
777
778/**
779 * The rekey interval
780 */
781static struct GNUNET_TIME_Relative rekey_interval;
782
783/**
784 * How often we do rekey based on number of bytes transmitted
785 */
786static unsigned long long rekey_max_bytes;
787/**
788 * Shared secret we finished the last kce working queue for.
789 */
790struct SharedSecret *ss_finished;
791
792/**
793 * Cache of pre-generated key IDs.
794 */
795static struct GNUNET_CONTAINER_MultiShortmap *key_cache;
796
797/**
798 * ID of read task
799 */
800static struct GNUNET_SCHEDULER_Task *read_task;
801
802/**
803 * ID of timeout task
804 */
805static struct GNUNET_SCHEDULER_Task *timeout_task;
806
807/**
808 * ID of master broadcast task
809 */
810static struct GNUNET_SCHEDULER_Task *broadcast_task;
811
812/**
813 * For logging statistics.
814 */
815static struct GNUNET_STATISTICS_Handle *stats;
816
817/**
818 * Our environment.
819 */
820static struct GNUNET_TRANSPORT_CommunicatorHandle *ch;
821
822/**
823 * Receivers (map from peer identity to `struct ReceiverAddress`)
824 */
825static struct GNUNET_CONTAINER_MultiPeerMap *receivers;
826
827/**
828 * Senders (map from peer identity to `struct SenderAddress`)
829 */
830static struct GNUNET_CONTAINER_MultiPeerMap *senders;
831
832/**
833 * Expiration heap for senders (contains `struct SenderAddress`)
834 */
835static struct GNUNET_CONTAINER_Heap *senders_heap;
836
837/**
838 * Expiration heap for receivers (contains `struct ReceiverAddress`)
839 */
840static struct GNUNET_CONTAINER_Heap *receivers_heap;
841
842/**
843 * Broadcast interface tasks. Kept in a DLL.
844 */
845static struct BroadcastInterface *bi_head;
846
847/**
848 * Broadcast interface tasks. Kept in a DLL.
849 */
850static struct BroadcastInterface *bi_tail;
851
852/**
853 * Our socket.
854 */
855static struct GNUNET_NETWORK_Handle *udp_sock;
856
857/**
858 * #GNUNET_YES if #udp_sock supports IPv6.
859 */
860static int have_v6_socket;
861
862/**
863 * Our public key.
864 */
865static struct GNUNET_PeerIdentity my_identity;
866
867/**
868 * Our private key.
869 */
870static struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
871
872/**
873 * Our configuration.
874 */
875static const struct GNUNET_CONFIGURATION_Handle *cfg;
876
877/**
878 * Our handle to report addresses for validation to TRANSPORT.
879 */
880static struct GNUNET_TRANSPORT_ApplicationHandle *ah;
881
882/**
883 * Network scanner to determine network types.
884 */
885static struct GNUNET_NT_InterfaceScanner *is;
886
887/**
888 * Connection to NAT service.
889 */
890static struct GNUNET_NAT_Handle *nat;
891
892/**
893 * Port number to which we are actually bound.
894 */
895static uint16_t my_port;
896
897
898/**
899 * An interface went away, stop broadcasting on it.
900 *
901 * @param bi entity to close down
902 */
903static void
904bi_destroy (struct BroadcastInterface *bi)
905{
906 if (AF_INET6 == bi->sa->sa_family)
907 {
908 /* Leave the multicast group */
909 if (GNUNET_OK != GNUNET_NETWORK_socket_setsockopt (udp_sock,
910 IPPROTO_IPV6,
911 IPV6_LEAVE_GROUP,
912 &bi->mcreq,
913 sizeof(bi->mcreq)))
914 {
915 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "setsockopt");
916 }
917 }
918 GNUNET_CONTAINER_DLL_remove (bi_head, bi_tail, bi);
919 GNUNET_SCHEDULER_cancel (bi->broadcast_task);
920 GNUNET_free (bi->sa);
921 GNUNET_free (bi->ba);
922 GNUNET_free (bi);
923}
924
925
926/**
927 * Destroys a receiving state due to timeout or shutdown.
928 *
929 * @param receiver entity to close down
930 */
931static void
932receiver_destroy (struct ReceiverAddress *receiver)
933{
934
935 receiver->receiver_destroy_called = GNUNET_YES;
936
937 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
938 "Disconnecting receiver for peer `%s'\n",
939 GNUNET_i2s (&receiver->target));
940 /*if (NULL != (mq = receiver->kx_mq))
941 {
942 receiver->kx_mq = NULL;
943 GNUNET_MQ_destroy (mq);
944 }*/
945 if (NULL != receiver->kx_qh)
946 {
947 GNUNET_TRANSPORT_communicator_mq_del (receiver->kx_qh);
948 receiver->kx_qh = NULL;
949 receiver->kx_mq = NULL;
950 }
951 /*if (NULL != (mq = receiver->d_mq))
952 {
953 receiver->d_mq = NULL;
954 GNUNET_MQ_destroy (mq);
955 }*/
956 if (NULL != receiver->d_qh)
957 {
958 GNUNET_TRANSPORT_communicator_mq_del (receiver->d_qh);
959 receiver->d_qh = NULL;
960 }
961 GNUNET_assert (GNUNET_YES ==
962 GNUNET_CONTAINER_multipeermap_remove (receivers,
963 &receiver->target,
964 receiver));
965 GNUNET_assert (receiver == GNUNET_CONTAINER_heap_remove_node (receiver->hn));
966 GNUNET_STATISTICS_set (stats,
967 "# receivers active",
968 GNUNET_CONTAINER_multipeermap_size (receivers),
969 GNUNET_NO);
970 GNUNET_free (receiver->address);
971 GNUNET_free (receiver->foreign_addr);
972 GNUNET_free (receiver);
973}
974
975
976/**
977 * Free memory used by key cache entry.
978 *
979 * @param kce the key cache entry
980 */
981static void
982kce_destroy (struct KeyCacheEntry *kce)
983{
984 struct SharedSecret *ss = kce->ss;
985
986 ss->active_kce_count--;
987 ss->sender->acks_available--;
988 GNUNET_CONTAINER_DLL_remove (ss->kce_head, ss->kce_tail, kce);
989 GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multishortmap_remove (key_cache,
990 &kce->kid,
991 kce));
992 GNUNET_free (kce);
993}
994
995
996/**
997 * Compute @a kid.
998 *
999 * @param msec master secret for HMAC calculation
1000 * @param serial number for the @a smac calculation
1001 * @param kid[out] where to write the key ID
1002 */
1003static void
1004get_kid (const struct GNUNET_HashCode *msec,
1005 uint32_t serial,
1006 struct GNUNET_ShortHashCode *kid)
1007{
1008 uint32_t sid = htonl (serial);
1009
1010 GNUNET_CRYPTO_hkdf (kid,
1011 sizeof(*kid),
1012 GCRY_MD_SHA512,
1013 GCRY_MD_SHA256,
1014 &sid,
1015 sizeof(sid),
1016 msec,
1017 sizeof(*msec),
1018 "UDP-KID",
1019 strlen ("UDP-KID"),
1020 NULL,
1021 0);
1022}
1023
1024
1025/**
1026 * Setup key cache entry for sequence number @a seq and shared secret @a ss.
1027 *
1028 * @param ss shared secret
1029 * @param seq sequence number for the key cache entry
1030 */
1031static void
1032kce_generate (struct SharedSecret *ss, uint32_t seq)
1033{
1034 struct KeyCacheEntry *kce;
1035
1036 GNUNET_assert (0 < seq);
1037 kce = GNUNET_new (struct KeyCacheEntry);
1038 kce->ss = ss;
1039 kce->sequence_number = seq;
1040 get_kid (&ss->master, seq, &kce->kid);
1041 GNUNET_CONTAINER_DLL_insert (ss->kce_head, ss->kce_tail, kce);
1042 ss->active_kce_count++;
1043 ss->sender->acks_available++;
1044 (void) GNUNET_CONTAINER_multishortmap_put (
1045 key_cache,
1046 &kce->kid,
1047 kce,
1048 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1049 GNUNET_STATISTICS_set (stats,
1050 "# KIDs active",
1051 GNUNET_CONTAINER_multishortmap_size (key_cache),
1052 GNUNET_NO);
1053}
1054
1055
1056/**
1057 * Destroy @a ss and associated key cache entries.
1058 *
1059 * @param ss shared secret to destroy
1060 * @param withoutKce If GNUNET_YES shared secrets with kce will not be destroyed.
1061 */
1062static int
1063secret_destroy (struct SharedSecret *ss, int withoutKce)
1064{
1065 struct SenderAddress *sender;
1066 struct ReceiverAddress *receiver;
1067 struct KeyCacheEntry *kce;
1068
1069 if (withoutKce && (ss->sequence_allowed > 0))
1070 return GNUNET_NO;
1071
1072 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1073 "secret %s destroy %u %u\n",
1074 GNUNET_h2s (&ss->master),
1075 withoutKce,
1076 ss->sequence_allowed);
1077 if (NULL != (sender = ss->sender))
1078 {
1079 GNUNET_CONTAINER_DLL_remove (sender->ss_head, sender->ss_tail, ss);
1080 sender->num_secrets--;
1081 }
1082 if (NULL != (receiver = ss->receiver))
1083 {
1084 GNUNET_CONTAINER_DLL_remove (receiver->ss_head, receiver->ss_tail, ss);
1085 receiver->num_secrets--;
1086 // Uncomment this for alternativ 1 of backchannel functionality
1087 receiver->acks_available -= (ss->sequence_allowed - ss->sequence_used);
1088 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1089 "%u receiver->acks_available 3\n",
1090 receiver->acks_available);
1091 // Until here for alternativ 1
1092 }
1093 while (NULL != (kce = ss->kce_head))
1094 kce_destroy (kce);
1095 GNUNET_STATISTICS_update (stats, "# Secrets active", -1, GNUNET_NO);
1096 GNUNET_STATISTICS_set (stats,
1097 "# KIDs active",
1098 GNUNET_CONTAINER_multishortmap_size (key_cache),
1099 GNUNET_NO);
1100 GNUNET_free (ss);
1101 return GNUNET_YES;
1102}
1103
1104
1105/**
1106 * Functions with this signature are called whenever we need
1107 * to close a sender's state due to timeout.
1108 *
1109 * @param sender entity to close down
1110 */
1111static void
1112sender_destroy (struct SenderAddress *sender)
1113{
1114 sender->sender_destroy_called = GNUNET_YES;
1115 GNUNET_assert (
1116 GNUNET_YES ==
1117 GNUNET_CONTAINER_multipeermap_remove (senders, &sender->target, sender));
1118 GNUNET_assert (sender == GNUNET_CONTAINER_heap_remove_node (sender->hn));
1119 GNUNET_STATISTICS_set (stats,
1120 "# senders active",
1121 GNUNET_CONTAINER_multipeermap_size (senders),
1122 GNUNET_NO);
1123 GNUNET_free (sender->address);
1124 GNUNET_free (sender);
1125}
1126
1127
1128/**
1129 * Compute @a key and @a iv.
1130 *
1131 * @param msec master secret for calculation
1132 * @param serial number for the @a smac calculation
1133 * @param key[out] where to write the decryption key
1134 * @param iv[out] where to write the IV
1135 */
1136static void
1137get_iv_key (const struct GNUNET_HashCode *msec,
1138 uint32_t serial,
1139 char key[AES_KEY_SIZE],
1140 char iv[AES_IV_SIZE])
1141{
1142 uint32_t sid = htonl (serial);
1143 char res[AES_KEY_SIZE + AES_IV_SIZE];
1144
1145 GNUNET_CRYPTO_hkdf (res,
1146 sizeof(res),
1147 GCRY_MD_SHA512,
1148 GCRY_MD_SHA256,
1149 &sid,
1150 sizeof(sid),
1151 msec,
1152 sizeof(*msec),
1153 "UDP-IV-KEY",
1154 strlen ("UDP-IV-KEY"),
1155 NULL,
1156 0);
1157 memcpy (key, res, AES_KEY_SIZE);
1158 memcpy (iv, &res[AES_KEY_SIZE], AES_IV_SIZE);
1159}
1160
1161
1162/**
1163 * Increment sender timeout due to activity.
1164 *
1165 * @param sender address for which the timeout should be rescheduled
1166 */
1167static void
1168reschedule_sender_timeout (struct SenderAddress *sender)
1169{
1170 sender->timeout =
1171 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1172 GNUNET_CONTAINER_heap_update_cost (sender->hn, sender->timeout.abs_value_us);
1173}
1174
1175
1176/**
1177 * Increment receiver timeout due to activity.
1178 *
1179 * @param receiver address for which the timeout should be rescheduled
1180 */
1181static void
1182reschedule_receiver_timeout (struct ReceiverAddress *receiver)
1183{
1184 receiver->timeout =
1185 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1186 GNUNET_CONTAINER_heap_update_cost (receiver->hn,
1187 receiver->timeout.abs_value_us);
1188}
1189
1190
1191/**
1192 * Task run to check #receiver_heap and #sender_heap for timeouts.
1193 *
1194 * @param cls unused, NULL
1195 */
1196static void
1197check_timeouts (void *cls)
1198{
1199 struct GNUNET_TIME_Relative st;
1200 struct GNUNET_TIME_Relative rt;
1201 struct GNUNET_TIME_Relative delay;
1202 struct ReceiverAddress *receiver;
1203 struct SenderAddress *sender;
1204
1205 (void) cls;
1206 timeout_task = NULL;
1207 rt = GNUNET_TIME_UNIT_FOREVER_REL;
1208 while (NULL != (receiver = GNUNET_CONTAINER_heap_peek (receivers_heap)))
1209 {
1210 /* if (GNUNET_YES != receiver->receiver_destroy_called) */
1211 /* { */
1212 rt = GNUNET_TIME_absolute_get_remaining (receiver->timeout);
1213 if (0 != rt.rel_value_us)
1214 break;
1215 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1216 "Receiver timed out\n");
1217 receiver_destroy (receiver);
1218 // }
1219 }
1220 st = GNUNET_TIME_UNIT_FOREVER_REL;
1221 while (NULL != (sender = GNUNET_CONTAINER_heap_peek (senders_heap)))
1222 {
1223 if (GNUNET_YES != sender->sender_destroy_called)
1224 {
1225 st = GNUNET_TIME_absolute_get_remaining (sender->timeout);
1226 if (0 != st.rel_value_us)
1227 break;
1228 sender_destroy (sender);
1229 }
1230 }
1231 delay = GNUNET_TIME_relative_min (rt, st);
1232 if (delay.rel_value_us < GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
1233 timeout_task = GNUNET_SCHEDULER_add_delayed (delay, &check_timeouts, NULL);
1234}
1235
1236
1237/**
1238 * Calculate cmac from master in @a ss.
1239 *
1240 * @param ss[in,out] data structure to complete
1241 */
1242static void
1243calculate_cmac (struct SharedSecret *ss)
1244{
1245 GNUNET_CRYPTO_hkdf (&ss->cmac,
1246 sizeof(ss->cmac),
1247 GCRY_MD_SHA512,
1248 GCRY_MD_SHA256,
1249 "CMAC",
1250 strlen ("CMAC"),
1251 &ss->master,
1252 sizeof(ss->master),
1253 "UDP-CMAC",
1254 strlen ("UDP-CMAC"),
1255 NULL,
1256 0);
1257}
1258
1259
1260/**
1261 * We received @a plaintext_len bytes of @a plaintext from a @a sender.
1262 * Pass it on to CORE.
1263 *
1264 * @param queue the queue that received the plaintext
1265 * @param plaintext the plaintext that was received
1266 * @param plaintext_len number of bytes of plaintext received
1267 */
1268static void
1269pass_plaintext_to_core (struct SenderAddress *sender,
1270 const void *plaintext,
1271 size_t plaintext_len)
1272{
1273 const struct GNUNET_MessageHeader *hdr = plaintext;
1274 const char *pos = plaintext;
1275
1276 while (ntohs (hdr->size) <= plaintext_len)
1277 {
1278 GNUNET_STATISTICS_update (stats,
1279 "# bytes given to core",
1280 ntohs (hdr->size),
1281 GNUNET_NO);
1282 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1283 "Giving %u bytes to TNG\n", ntohs (hdr->size));
1284 GNUNET_assert (GNUNET_SYSERR !=
1285 GNUNET_TRANSPORT_communicator_receive (ch,
1286 &sender->target,
1287 hdr,
1288 ADDRESS_VALIDITY_PERIOD,
1289 NULL /* no flow control possible */
1290 ,
1291 NULL));
1292 /* move on to next message, if any */
1293 plaintext_len -= ntohs (hdr->size);
1294 if (plaintext_len < sizeof(*hdr))
1295 break;
1296 pos += ntohs (hdr->size);
1297 hdr = (const struct GNUNET_MessageHeader *) pos;
1298 // TODO for now..., we do not actually sen >1msg or have a way of telling
1299 // if we are done
1300 break;
1301 }
1302 GNUNET_STATISTICS_update (stats,
1303 "# bytes padding discarded",
1304 plaintext_len,
1305 GNUNET_NO);
1306}
1307
1308
1309/**
1310 * Setup @a cipher based on shared secret @a msec and
1311 * serial number @a serial.
1312 *
1313 * @param msec master shared secret
1314 * @param serial serial number of cipher to set up
1315 * @param cipher[out] cipher to initialize
1316 */
1317static void
1318setup_cipher (const struct GNUNET_HashCode *msec,
1319 uint32_t serial,
1320 gcry_cipher_hd_t *cipher)
1321{
1322 char key[AES_KEY_SIZE];
1323 char iv[AES_IV_SIZE];
1324 int rc;
1325
1326 GNUNET_assert (0 ==
1327 gcry_cipher_open (cipher,
1328 GCRY_CIPHER_AES256 /* low level: go for speed */,
1329 GCRY_CIPHER_MODE_GCM,
1330 0 /* flags */));
1331 get_iv_key (msec, serial, key, iv);
1332 rc = gcry_cipher_setkey (*cipher, key, sizeof(key));
1333 GNUNET_assert ((0 == rc) || ((char) rc == GPG_ERR_WEAK_KEY));
1334 rc = gcry_cipher_setiv (*cipher, iv, sizeof(iv));
1335 GNUNET_assert ((0 == rc) || ((char) rc == GPG_ERR_WEAK_KEY));
1336}
1337
1338
1339/**
1340 * Try to decrypt @a buf using shared secret @a ss and key/iv
1341 * derived using @a serial.
1342 *
1343 * @param ss shared secret
1344 * @param tag GCM authentication tag
1345 * @param serial serial number to use
1346 * @param in_buf input buffer to decrypt
1347 * @param in_buf_size number of bytes in @a in_buf and available in @a out_buf
1348 * @param out_buf where to write the result
1349 * @return #GNUNET_OK on success
1350 */
1351static int
1352try_decrypt (const struct SharedSecret *ss,
1353 const char tag[GCM_TAG_SIZE],
1354 uint32_t serial,
1355 const char *in_buf,
1356 size_t in_buf_size,
1357 char *out_buf)
1358{
1359 gcry_cipher_hd_t cipher;
1360
1361 setup_cipher (&ss->master, serial, &cipher);
1362 GNUNET_assert (
1363 0 ==
1364 gcry_cipher_decrypt (cipher, out_buf, in_buf_size, in_buf, in_buf_size));
1365 if (0 != gcry_cipher_checktag (cipher, tag, GCM_TAG_SIZE))
1366 {
1367 gcry_cipher_close (cipher);
1368 GNUNET_STATISTICS_update (stats,
1369 "# AEAD authentication failures",
1370 1,
1371 GNUNET_NO);
1372 return GNUNET_SYSERR;
1373 }
1374 gcry_cipher_close (cipher);
1375 return GNUNET_OK;
1376}
1377
1378
1379/**
1380 * Setup shared secret for decryption.
1381 *
1382 * @param ephemeral ephemeral key we received from the other peer
1383 * @return new shared secret
1384 */
1385static struct SharedSecret *
1386setup_shared_secret_dec (const struct GNUNET_CRYPTO_EcdhePublicKey *ephemeral)
1387{
1388 struct SharedSecret *ss;
1389
1390 ss = GNUNET_new (struct SharedSecret);
1391 GNUNET_CRYPTO_eddsa_ecdh (my_private_key, ephemeral, &ss->master);
1392 return ss;
1393}
1394
1395
1396/**
1397 * Setup shared secret for encryption.
1398 *
1399 * @param ephemeral ephemeral key we are sending to the other peer
1400 * @param receiver[in,out] queue to initialize encryption key for
1401 * @return new shared secret
1402 */
1403static struct SharedSecret *
1404setup_shared_secret_enc (const struct GNUNET_CRYPTO_EcdhePrivateKey *ephemeral,
1405 struct ReceiverAddress *receiver, int add_to_receiver)
1406{
1407 struct SharedSecret *ss;
1408
1409 ss = GNUNET_new (struct SharedSecret);
1410 GNUNET_CRYPTO_ecdh_eddsa (ephemeral,
1411 &receiver->target.public_key,
1412 &ss->master);
1413 calculate_cmac (ss);
1414 ss->receiver = receiver;
1415 GNUNET_CONTAINER_DLL_insert (receiver->ss_head, receiver->ss_tail, ss);
1416 receiver->num_secrets++;
1417 GNUNET_STATISTICS_update (stats, "# Secrets active", 1, GNUNET_NO);
1418 return ss;
1419}
1420
1421
1422/**
1423 * Setup the MQ for the @a receiver. If a queue exists,
1424 * the existing one is destroyed. Then the MTU is
1425 * recalculated and a fresh queue is initialized.
1426 *
1427 * @param receiver receiver to setup MQ for
1428 */
1429static void
1430setup_receiver_mq (struct ReceiverAddress *receiver);
1431
1432/**
1433 * Destroying all secrets. Depending on parameter we keep those secrets having a kce.
1434 *
1435 * @param ss The secret we will not destroy.
1436 * @param withoutKce If GNUNET_YES shared secrets with kce will not be destroyed.
1437 */
1438static void
1439destroy_all_secrets (struct SharedSecret *ss, int withoutKce)
1440{
1441 struct SenderAddress *sender;
1442 struct ReceiverAddress *receiver;
1443 struct SharedSecret *ss_to_destroy;
1444 struct SharedSecret *ss_start;
1445 struct SharedSecret *pos;
1446 int at_least_one_destroyed = GNUNET_NO;
1447
1448 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1449 "Starting destroy all withoutKce: %u.\n",
1450 withoutKce);
1451
1452 if (NULL != (sender = ss->sender))
1453 {
1454 ss_start = sender->ss_head;
1455 }
1456 else if (NULL != (receiver = ss->receiver))
1457 {
1458 ss_start = receiver->ss_head;
1459 }
1460 else
1461 {
1462 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1463 "Shared secret has no sender or receiver!\n");
1464 return;
1465 }
1466
1467 pos = ss_start;
1468 while (NULL != pos)
1469 {
1470 ss_to_destroy = pos;
1471 pos = pos->next;
1472
1473 if (ss != ss_to_destroy)
1474 at_least_one_destroyed = secret_destroy (ss_to_destroy, withoutKce);
1475 }
1476
1477 if ((ss != ss_start) && ! at_least_one_destroyed)
1478 {
1479 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1480 "Really destroying all.\n");
1481 destroy_all_secrets (ss_start, GNUNET_NO);
1482 }
1483
1484 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1485 "Finished destroy all.\n");
1486}
1487
1488
1489static void
1490add_acks (struct SharedSecret *ss, int acks_to_add)
1491{
1492
1493 struct ReceiverAddress *receiver = ss->receiver;
1494
1495 GNUNET_assert (NULL != ss);
1496 GNUNET_assert (NULL != receiver);
1497
1498 if (NULL == receiver->d_qh)
1499 {
1500 receiver->d_qh =
1501 GNUNET_TRANSPORT_communicator_mq_add (ch,
1502 &receiver->target,
1503 receiver->foreign_addr,
1504 receiver->d_mtu,
1505 acks_to_add,
1506 1, /* Priority */
1507 receiver->nt,
1508 GNUNET_TRANSPORT_CS_OUTBOUND,
1509 receiver->d_mq);
1510 }
1511 else
1512 {
1513 GNUNET_TRANSPORT_communicator_mq_update (ch,
1514 receiver->d_qh,
1515 acks_to_add,
1516 1);
1517 }
1518
1519 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1520 "Tell transport we have %u more acks!\n",
1521 acks_to_add);
1522 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1523 "%u kce for rekeying.\n",
1524 receiver->number_rekeying_kce);
1525
1526 // Until here for alternativ 1
1527
1528 /* move ss to head to avoid discarding it anytime soon! */
1529
1530 GNUNET_CONTAINER_DLL_remove (receiver->ss_head, receiver->ss_tail, ss);
1531 GNUNET_CONTAINER_DLL_insert (receiver->ss_head, receiver->ss_tail, ss);
1532 destroy_all_secrets (ss, GNUNET_YES);
1533}
1534
1535
1536static uint32_t
1537reset_rekey_kces (struct ReceiverAddress *receiver,
1538 uint32_t acks_to_add)
1539{
1540 int needed_for_rekeying;
1541
1542 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1543 "%u kce for rekeying and %u acks_to_add\n",
1544 receiver->number_rekeying_kce,
1545 acks_to_add);
1546
1547 needed_for_rekeying = (3 - receiver->number_rekeying_kce);
1548 if (acks_to_add <= needed_for_rekeying)
1549 {
1550 receiver->number_rekeying_kce += acks_to_add;
1551 acks_to_add = 0;
1552 }
1553 else
1554 {
1555 acks_to_add -= (3 - receiver->number_rekeying_kce);
1556 receiver->number_rekeying_kce = 3;
1557 }
1558
1559 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1560 "%u kce for rekeying and %u acks_to_add\n",
1561 receiver->number_rekeying_kce,
1562 acks_to_add);
1563 return acks_to_add;
1564}
1565
1566
1567static void
1568add_acks_rekey (struct ReceiverAddress *receiver)
1569{
1570 uint32_t acks_to_add = receiver->ss_rekey->sequence_allowed;
1571
1572 if (receiver->number_rekeying_kce < 3)
1573 acks_to_add = reset_rekey_kces (receiver, acks_to_add);
1574 receiver->acks_available = receiver->ss_rekey->sequence_allowed;
1575 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1576 "%u receiver->acks_available 4\n",
1577 receiver->acks_available);
1578 /* add_acks (receiver->ss_rekey, acks_to_add - 3); */
1579 if (0 != acks_to_add)
1580 {
1581 add_acks (receiver->ss_rekey, acks_to_add);
1582 }
1583 receiver->ss_rekey = NULL;
1584 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1585 "# rekeying successful\n");
1586 GNUNET_STATISTICS_update (stats,
1587 "# rekeying successful",
1588 1,
1589 GNUNET_NO);
1590}
1591
1592
1593/**
1594 * We received an ACK for @a pid. Check if it is for
1595 * the receiver in @a value and if so, handle it and
1596 * return #GNUNET_NO. Otherwise, return #GNUNET_YES.
1597 *
1598 * @param cls a `const struct UDPAck`
1599 * @param pid peer the ACK is from
1600 * @param value a `struct ReceiverAddress`
1601 * @return #GNUNET_YES to continue to iterate
1602 */
1603static int
1604handle_ack (void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
1605{
1606 const struct UDPAck *ack = cls;
1607 struct ReceiverAddress *receiver = value;
1608 uint32_t acks_to_add;
1609 uint32_t allowed;
1610 // int needed_for_rekeying;
1611
1612 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1613 "in handle ack with cmac %s\n",
1614 GNUNET_h2s (&ack->cmac));
1615
1616 if (NULL != receiver->ss_rekey)
1617 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1618 "We have rekey secret with cmac %s \n",
1619 GNUNET_h2s (&receiver->ss_rekey->cmac));
1620
1621 if ((NULL != receiver->ss_rekey) && (0 == memcmp (&ack->cmac,
1622 &receiver->ss_rekey->cmac,
1623 sizeof(struct
1624 GNUNET_HashCode))) )
1625 {
1626 allowed = ntohl (ack->sequence_max);
1627
1628 if (allowed > receiver->ss_rekey->sequence_allowed)
1629 {
1630 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1631 "%u > %u (%u %u) for rekey secrect %s\n", allowed,
1632 receiver->ss_rekey->sequence_allowed,
1633 receiver->acks_available,
1634 ack->acks_available,
1635 GNUNET_h2s (&receiver->ss_rekey->master));
1636
1637 receiver->ss_rekey->sequence_allowed = allowed;
1638
1639 if (GNUNET_NO == receiver->rekeying)
1640 add_acks_rekey (receiver);
1641
1642 return GNUNET_NO;
1643 }
1644 }
1645
1646 (void) pid;
1647 for (struct SharedSecret *ss = receiver->ss_head; NULL != ss; ss = ss->next)
1648 {
1649 if (0 == memcmp (&ack->cmac, &ss->cmac, sizeof(struct GNUNET_HashCode)))
1650 {
1651
1652 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1653 "Found matching mac\n");
1654
1655 allowed = ntohl (ack->sequence_max);
1656
1657 if (allowed > ss->sequence_allowed)
1658 {
1659 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1660 "%u > %u (%u %u) for secrect %s\n", allowed,
1661 ss->sequence_allowed,
1662 receiver->acks_available,
1663 ack->acks_available,
1664 GNUNET_h2s (&ss->master));
1665 // Uncomment this for alternativ 1 of backchannel functionality
1666 acks_to_add = (allowed - ss->sequence_allowed);
1667 if ((GNUNET_NO == receiver->rekeying) &&
1668 (receiver->number_rekeying_kce < 3) )
1669 acks_to_add = reset_rekey_kces (receiver, acks_to_add);
1670 /* if ((GNUNET_NO == receiver->rekeying) && */
1671 /* (receiver->number_rekeying_kce < */
1672 /* 3) ) */
1673 /* { */
1674 /* needed_for_rekeying = (3 - receiver->number_rekeying_kce); */
1675 /* if (acks_to_add <= needed_for_rekeying) */
1676 /* { */
1677 /* receiver->number_rekeying_kce += acks_to_add; */
1678 /* acks_to_add = 0; */
1679 /* } */
1680 /* else */
1681 /* { */
1682 /* acks_to_add -= (3 - receiver->number_rekeying_kce); */
1683 /* receiver->number_rekeying_kce = 3; */
1684 /* } */
1685 /* } */
1686 /* GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, */
1687 /* "%u kce for rekeying\n", */
1688 /* receiver->number_rekeying_kce); */
1689
1690 if ((0 != acks_to_add) && (GNUNET_NO == receiver->rekeying))
1691 {
1692 receiver->acks_available += (allowed - ss->sequence_allowed);
1693 ss->sequence_allowed = allowed;
1694 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1695 "%u receiver->acks_available 5\n",
1696 receiver->acks_available);
1697 add_acks (ss, acks_to_add);
1698 }
1699 }
1700 return GNUNET_NO;
1701 }
1702 }
1703 return GNUNET_YES;
1704}
1705
1706
1707/**
1708 * Test if we have received a valid message in plaintext.
1709 * If so, handle it.
1710 *
1711 * @param sender peer to process inbound plaintext for
1712 * @param buf buffer we received
1713 * @param buf_size number of bytes in @a buf
1714 */
1715static void
1716try_handle_plaintext (struct SenderAddress *sender,
1717 const void *buf,
1718 size_t buf_size)
1719{
1720 const struct GNUNET_MessageHeader *hdr =
1721 (const struct GNUNET_MessageHeader *) buf;
1722 const struct UDPAck *ack = (const struct UDPAck *) buf;
1723 uint16_t type;
1724
1725 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1726 "try_handle_plaintext of size %u (%u %u) and type %u\n",
1727 buf_size,
1728 ntohs (hdr->size),
1729 sizeof(*hdr),
1730 ntohs (hdr->type));
1731 if (sizeof(*hdr) > buf_size)
1732 return; /* not even a header */
1733 if (ntohs (hdr->size) > buf_size)
1734 return; /* not even a header */
1735 type = ntohs (hdr->type);
1736 switch (type)
1737 {
1738 case GNUNET_MESSAGE_TYPE_COMMUNICATOR_UDP_ACK:
1739 /* lookup master secret by 'cmac', then update sequence_max */
1740 GNUNET_CONTAINER_multipeermap_get_multiple (receivers,
1741 &sender->target,
1742 &handle_ack,
1743 (void *) ack);
1744 /* There could be more messages after the ACK, handle those as well */
1745 buf += ntohs (hdr->size);
1746 buf_size -= ntohs (hdr->size);
1747 pass_plaintext_to_core (sender, buf, buf_size);
1748 break;
1749
1750 case GNUNET_MESSAGE_TYPE_COMMUNICATOR_UDP_PAD:
1751 /* skip padding */
1752 break;
1753
1754 default:
1755 pass_plaintext_to_core (sender, buf, buf_size);
1756 }
1757}
1758
1759
1760static void
1761kce_generate_cb (void *cls)
1762{
1763 struct SharedSecret *ss = cls;
1764
1765 ss->sender->kce_task = NULL;
1766
1767 if (((GNUNET_NO == ss->sender->rekeying) && (ss->sender->acks_available <
1768 KCN_TARGET) ) ||
1769 ((ss->sender->ss_rekey == ss) && (GNUNET_YES == ss->sender->rekeying) &&
1770 (ss->sender->acks_available < KCN_TARGET)))
1771 {
1772
1773 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1774 "Precomputing keys for master %s\n",
1775 GNUNET_h2s (&(ss->master)));
1776
1777 for (int i = 0; i < GENERATE_AT_ONCE; i++)
1778 kce_generate (ss, ++ss->sequence_allowed);
1779
1780 if (KCN_TARGET > ss->sender->acks_available)
1781 {
1782 ss->sender->kce_task = GNUNET_SCHEDULER_add_delayed (
1783 WORKING_QUEUE_INTERVALL,
1784 kce_generate_cb,
1785 ss);
1786 }
1787 else
1788 {
1789 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1790 "We have enough keys.\n");
1791 ss_finished = ss;
1792 ss->sender->kce_task_finished = GNUNET_YES;
1793 }
1794 }
1795
1796
1797
1798}
1799
1800
1801static void
1802kce_generate_rekey_cb (void *cls)
1803{
1804 struct SharedSecret *ss = cls;
1805
1806 ss->sender->kce_task_rekey = NULL;
1807
1808 if (NULL == ss->sender->kce_task)
1809 {
1810
1811 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1812 "Precomputing keys for rekey master %s\n",
1813 GNUNET_h2s (&(ss->master)));
1814
1815 for (int i = 0; i < GENERATE_AT_ONCE; i++)
1816 kce_generate (ss, ++ss->sequence_allowed);
1817
1818 ss->sender->kce_task = GNUNET_SCHEDULER_add_delayed (
1819 WORKING_QUEUE_INTERVALL,
1820 kce_generate_cb,
1821 ss);
1822 ss->sender->kce_task_rekey = NULL;
1823 }
1824 else
1825 {
1826 ss->sender->kce_task_rekey = GNUNET_SCHEDULER_add_delayed (
1827 WORKING_QUEUE_INTERVALL,
1828 kce_generate_rekey_cb,
1829 ss);
1830 }
1831}
1832
1833
1834/**
1835 * We established a shared secret with a sender. We should try to send
1836 * the sender an `struct UDPAck` at the next opportunity to allow the
1837 * sender to use @a ss longer (assuming we did not yet already
1838 * recently).
1839 *
1840 * @param ss shared secret to generate ACKs for
1841 * @param initial The SharedSecret came with initial KX.
1842 */
1843static void
1844consider_ss_ack (struct SharedSecret *ss, int initial)
1845{
1846 struct GNUNET_SCHEDULER_Task *kce_task_rekey;
1847 struct GNUNET_SCHEDULER_Task *kce_task;
1848 int kce_task_finished;
1849
1850 kce_task_rekey = ss->sender->kce_task_rekey;
1851 kce_task_finished = ss->sender->kce_task_finished;
1852 kce_task = ss->sender->kce_task;
1853
1854 GNUNET_assert (NULL != ss->sender);
1855 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1856 "Considering SS UDPAck %s\n",
1857 GNUNET_i2s_full (&ss->sender->target));
1858
1859 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1860 "We have %u acks available.\n",
1861 ss->sender->acks_available);
1862 /* drop ancient KeyCacheEntries */
1863 while ((NULL != ss->kce_head) &&
1864 (MAX_SQN_DELTA <
1865 ss->kce_head->sequence_number - ss->kce_tail->sequence_number))
1866 kce_destroy (ss->kce_tail);
1867
1868
1869 if (GNUNET_NO == initial)
1870 kce_generate (ss, ++ss->sequence_allowed);
1871
1872 /*if (0 == ss->sender->acks_available)
1873 {
1874 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1875 "Generating keys\n");
1876 while (ss->active_kce_count < KCN_TARGET)
1877 kce_generate (ss, ++ss->sequence_allowed);
1878 }*/
1879
1880 if (NULL != kce_task)
1881 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1882 "kce_task is not NULL\n");
1883 if (kce_task_finished)
1884 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1885 "kce_task_finished: GNUNET_YES\n");
1886 if (initial)
1887 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1888 "initial: GNUNET_YES\n");
1889
1890 if ( kce_task_finished || (GNUNET_NO == initial))
1891 {
1892 struct UDPAck ack;
1893 struct SharedSecret *ss_tell;
1894
1895 if (GNUNET_NO != initial)
1896 ss_tell = ss_finished;
1897 else
1898 ss_tell = ss;
1899
1900 ack.header.type = htons (GNUNET_MESSAGE_TYPE_COMMUNICATOR_UDP_ACK);
1901 ack.header.size = htons (sizeof(ack));
1902 ack.sequence_max = htonl (ss_tell->sequence_allowed);
1903 ack.acks_available = ss->sender->acks_available;
1904 ack.cmac = ss_tell->cmac;
1905 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1906 "Notifying transport of UDPAck %s with initial %u and master %s\n",
1907 GNUNET_i2s_full (&ss_tell->sender->target),
1908 initial,
1909 GNUNET_h2s (&(ss_tell->master)));
1910 GNUNET_TRANSPORT_communicator_notify (ch,
1911 &ss_tell->sender->target,
1912 COMMUNICATOR_ADDRESS_PREFIX,
1913 &ack.header);
1914 if (GNUNET_NO != initial)
1915 {
1916 destroy_all_secrets (ss, GNUNET_YES);
1917 ss->sender->kce_task_finished = GNUNET_NO;
1918 }
1919 }
1920 else if ((NULL == kce_task) && ((KCN_THRESHOLD >
1921 ss->sender->acks_available) ||
1922 (GNUNET_YES == ss->sender->rekeying) ||
1923 (ss->sender->num_secrets > MAX_SECRETS) ))
1924 {
1925
1926 // kce_generate (ss, ++ss->sequence_allowed);
1927 // kce_generate (ss, ++ss->sequence_allowed);
1928 // TODO This task must be per sender!
1929 kce_task = GNUNET_SCHEDULER_add_delayed (WORKING_QUEUE_INTERVALL,
1930 kce_generate_cb,
1931 ss);
1932 kce_task_finished = GNUNET_NO;
1933
1934 }
1935 else if ((NULL == kce_task_rekey) && (GNUNET_YES ==
1936 ss->sender->rekeying) )
1937 {
1938 kce_task_rekey = GNUNET_SCHEDULER_add_delayed (WORKING_QUEUE_INTERVALL,
1939 kce_generate_rekey_cb,
1940 ss);
1941 }
1942}
1943
1944
1945/**
1946 * We received a @a box with matching @a kce. Decrypt and process it.
1947 *
1948 * @param box the data we received
1949 * @param box_len number of bytes in @a box
1950 * @param kce key index to decrypt @a box
1951 */
1952static void
1953decrypt_box (const struct UDPBox *box,
1954 size_t box_len,
1955 struct KeyCacheEntry *kce)
1956{
1957 struct SharedSecret *ss = kce->ss;
1958 char out_buf[box_len - sizeof(*box)];
1959
1960 GNUNET_assert (NULL != ss->sender);
1961 if (GNUNET_OK != try_decrypt (ss,
1962 box->gcm_tag,
1963 kce->sequence_number,
1964 (const char *) &box[1],
1965 sizeof(out_buf),
1966 out_buf))
1967 {
1968 GNUNET_STATISTICS_update (stats,
1969 "# Decryption failures with valid KCE",
1970 1,
1971 GNUNET_NO);
1972 kce_destroy (kce);
1973 return;
1974 }
1975 kce_destroy (kce);
1976 GNUNET_STATISTICS_update (stats,
1977 "# bytes decrypted with BOX",
1978 sizeof(out_buf),
1979 GNUNET_NO);
1980 GNUNET_STATISTICS_update (stats,
1981 "# messages decrypted with BOX",
1982 1,
1983 GNUNET_NO);
1984 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1985 "decrypted UDPBox with kid %s\n",
1986 GNUNET_sh2s (&box->kid));
1987 try_handle_plaintext (ss->sender, out_buf, sizeof(out_buf));
1988 if ((GNUNET_NO == box->rekeying) && (GNUNET_YES == ss->sender->rekeying))
1989 {
1990 ss->sender->rekeying = GNUNET_NO;
1991 ss->sender->ss_rekey = NULL;
1992 // destroy_all_secrets (ss, GNUNET_NO);
1993 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1994 "Receiver stopped rekeying.\n");
1995 }
1996 else if (GNUNET_NO == box->rekeying)
1997 consider_ss_ack (ss, GNUNET_NO);
1998 else
1999 {
2000 ss->sender->rekeying = GNUNET_YES;
2001 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2002 "Got Box: Receiver doing rekeying.\n");
2003 }
2004}
2005
2006
2007/**
2008 * We received a @a rekey with matching @a kce. Decrypt and process it.
2009 *
2010 * @param rekey the data we received
2011 * @param rekey_len number of bytes in @a rekey
2012 * @param kce key index to decrypt @a rekey
2013 */
2014static void
2015decrypt_rekey (const struct UDPRekey *rekey,
2016 size_t rekey_len,
2017 struct KeyCacheEntry *kce,
2018 struct SenderAddress *sender)
2019{
2020 struct SharedSecret *ss = kce->ss;
2021 struct SharedSecret *ss_rekey;
2022 char out_buf[rekey_len - sizeof(*rekey)];
2023 struct GNUNET_HashCode *master;
2024
2025
2026 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2027 "decrypt_rekey.\n");
2028
2029 GNUNET_assert (NULL != ss->sender);
2030 if (GNUNET_OK != try_decrypt (ss,
2031 rekey->gcm_tag,
2032 kce->sequence_number,
2033 (const char *) &rekey[1],
2034 sizeof(out_buf),
2035 out_buf))
2036 {
2037 GNUNET_STATISTICS_update (stats,
2038 "# Decryption failures with valid KCE",
2039 1,
2040 GNUNET_NO);
2041 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2042 "Decryption with kid %s failed\n",
2043 GNUNET_sh2s (&rekey->kid));
2044 kce_destroy (kce);
2045 return;
2046 }
2047 kce_destroy (kce);
2048 GNUNET_STATISTICS_update (stats,
2049 "# bytes decrypted with Rekey",
2050 sizeof(out_buf),
2051 GNUNET_NO);
2052 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2053 "decrypted UDPRekey with kid %s\n",
2054 GNUNET_sh2s (&rekey->kid));
2055 /*cmac = (struct GNUNET_HashCode *) out_buf;
2056 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2057 "Received secret with cmac %s \n",
2058 GNUNET_h2s (&cmac));*/
2059 // ss_rekey = (struct SharedSecret *) out_buf;
2060 master = (struct GNUNET_HashCode *) out_buf;
2061 ss_rekey = GNUNET_new (struct SharedSecret);
2062 ss_rekey->master = *master;
2063 calculate_cmac (ss_rekey);
2064 ss_rekey->sender = sender;
2065 // ss_rekey->sequence_used = 0;
2066 // ss_rekey->sequence_allowed = 0;
2067 /* ss_rekey->active_kce_count = 0; */
2068 /* ss_rekey->prev = NULL; */
2069 /* ss_rekey->next = NULL; */
2070 /* GNUNET_assert (ss_rekey->prev == NULL && sender->ss_head != ss_rekey); */
2071 /* GNUNET_assert (ss_rekey->next == NULL && sender->ss_tail != ss_rekey); */
2072 GNUNET_CONTAINER_DLL_insert (sender->ss_head, sender->ss_tail, ss_rekey);
2073 sender->ss_rekey = ss_rekey;
2074 sender->num_secrets++;
2075 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2076 "Received secret with cmac %s\n",
2077 GNUNET_h2s (&(ss_rekey->cmac)));
2078 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2079 "Received secret with master %s.\n",
2080 GNUNET_h2s (&(ss_rekey->master)));
2081 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2082 "We have %u sequence_allowed.\n",
2083 ss_rekey->sequence_allowed);
2084 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2085 "We have a sender %p\n",
2086 ss_rekey->sender);
2087 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2088 "We have %u acks available.\n",
2089 ss_rekey->sender->acks_available);
2090 consider_ss_ack (ss_rekey, GNUNET_YES);
2091
2092}
2093
2094
2095/**
2096 * Closure for #find_sender_by_address()
2097 */
2098struct SearchContext
2099{
2100 /**
2101 * Address we are looking for.
2102 */
2103 const struct sockaddr *address;
2104
2105 /**
2106 * Number of bytes in @e address.
2107 */
2108 socklen_t address_len;
2109
2110 /**
2111 * Return value to set if we found a match.
2112 */
2113 struct SenderAddress *sender;
2114};
2115
2116
2117/**
2118 * Find existing `struct SenderAddress` by matching addresses.
2119 *
2120 * @param cls a `struct SearchContext`
2121 * @param key ignored, must match already
2122 * @param value a `struct SenderAddress`
2123 * @return #GNUNET_YES if not found (continue to search), #GNUNET_NO if found
2124 */
2125static int
2126find_sender_by_address (void *cls,
2127 const struct GNUNET_PeerIdentity *key,
2128 void *value)
2129{
2130 struct SearchContext *sc = cls;
2131 struct SenderAddress *sender = value;
2132
2133 if ((sender->address_len == sc->address_len) &&
2134 (0 == memcmp (sender->address, sc->address, sender->address_len)))
2135 {
2136 sc->sender = sender;
2137 return GNUNET_NO; /* stop iterating! */
2138 }
2139 return GNUNET_YES;
2140}
2141
2142
2143/**
2144 * Create sender address for @a target. Note that we
2145 * might already have one, so a fresh one is only allocated
2146 * if one does not yet exist for @a address.
2147 *
2148 * @param target peer to generate address for
2149 * @param address target address
2150 * @param address_len number of bytes in @a address
2151 * @return data structure to keep track of key material for
2152 * decrypting data from @a target
2153 */
2154static struct SenderAddress *
2155setup_sender (const struct GNUNET_PeerIdentity *target,
2156 const struct sockaddr *address,
2157 socklen_t address_len)
2158{
2159 struct SenderAddress *sender;
2160 struct SearchContext sc = { .address = address,
2161 .address_len = address_len,
2162 .sender = NULL };
2163
2164 GNUNET_CONTAINER_multipeermap_get_multiple (senders,
2165 target,
2166 &find_sender_by_address,
2167 &sc);
2168 if (NULL != sc.sender)
2169 {
2170 reschedule_sender_timeout (sc.sender);
2171 return sc.sender;
2172 }
2173 sender = GNUNET_new (struct SenderAddress);
2174 sender->target = *target;
2175 sender->address = GNUNET_memdup (address, address_len);
2176 sender->address_len = address_len;
2177 (void) GNUNET_CONTAINER_multipeermap_put (
2178 senders,
2179 &sender->target,
2180 sender,
2181 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2182 GNUNET_STATISTICS_set (stats,
2183 "# senders active",
2184 GNUNET_CONTAINER_multipeermap_size (receivers),
2185 GNUNET_NO);
2186 sender->timeout =
2187 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2188 sender->hn = GNUNET_CONTAINER_heap_insert (senders_heap,
2189 sender,
2190 sender->timeout.abs_value_us);
2191 sender->nt = GNUNET_NT_scanner_get_type (is, address, address_len);
2192 if (NULL == timeout_task)
2193 timeout_task = GNUNET_SCHEDULER_add_now (&check_timeouts, NULL);
2194 return sender;
2195}
2196
2197
2198/**
2199 * Check signature from @a uc against @a ephemeral.
2200 *
2201 * @param ephermal key that is signed
2202 * @param uc signature of claimant
2203 * @return #GNUNET_OK if signature is valid
2204 */
2205static int
2206verify_confirmation (const struct GNUNET_CRYPTO_EcdhePublicKey *ephemeral,
2207 const struct UDPConfirmation *uc)
2208{
2209 struct UdpHandshakeSignature uhs;
2210
2211 uhs.purpose.purpose = htonl (
2212 GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_UDP_HANDSHAKE);
2213 uhs.purpose.size = htonl (sizeof(uhs));
2214 uhs.sender = uc->sender;
2215 uhs.receiver = my_identity;
2216 uhs.ephemeral = *ephemeral;
2217 uhs.monotonic_time = uc->monotonic_time;
2218 return GNUNET_CRYPTO_eddsa_verify (
2219 GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_UDP_HANDSHAKE,
2220 &uhs,
2221 &uc->sender_sig,
2222 &uc->sender.public_key);
2223}
2224
2225
2226/**
2227 * Converts @a address to the address string format used by this
2228 * communicator in HELLOs.
2229 *
2230 * @param address the address to convert, must be AF_INET or AF_INET6.
2231 * @param address_len number of bytes in @a address
2232 * @return string representation of @a address
2233 */
2234static char *
2235sockaddr_to_udpaddr_string (const struct sockaddr *address,
2236 socklen_t address_len)
2237{
2238 char *ret;
2239
2240 switch (address->sa_family)
2241 {
2242 case AF_INET:
2243 GNUNET_asprintf (&ret,
2244 "%s-%s",
2245 COMMUNICATOR_ADDRESS_PREFIX,
2246 GNUNET_a2s (address, address_len));
2247 break;
2248
2249 case AF_INET6:
2250 GNUNET_asprintf (&ret,
2251 "%s-%s",
2252 COMMUNICATOR_ADDRESS_PREFIX,
2253 GNUNET_a2s (address, address_len));
2254 break;
2255
2256 default:
2257 GNUNET_assert (0);
2258 }
2259 return ret;
2260}
2261
2262
2263/**
2264 * Socket read task.
2265 *
2266 * @param cls NULL
2267 */
2268static void
2269sock_read (void *cls)
2270{
2271 struct sockaddr_storage sa;
2272 struct sockaddr_in *addr_verify;
2273 socklen_t salen = sizeof(sa);
2274 char buf[UINT16_MAX];
2275 ssize_t rcvd;
2276
2277 (void) cls;
2278 read_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
2279 udp_sock,
2280 &sock_read,
2281 NULL);
2282 rcvd = GNUNET_NETWORK_socket_recvfrom (udp_sock,
2283 buf,
2284 sizeof(buf),
2285 (struct sockaddr *) &sa,
2286 &salen);
2287 if (-1 == rcvd)
2288 {
2289 GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "recv");
2290 return;
2291 }
2292 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2293 "Read %lu bytes\n", rcvd);
2294
2295 if (rcvd > sizeof(struct UDPRekey))
2296 {
2297 const struct UDPRekey *rekey;
2298 const struct UDPBox *box;
2299 struct KeyCacheEntry *kce;
2300 struct SenderAddress *sender;
2301 int do_decrypt = GNUNET_NO;
2302
2303 rekey = (const struct UDPRekey *) buf;
2304 box = (const struct UDPBox *) buf;
2305 kce = GNUNET_CONTAINER_multishortmap_get (key_cache, &rekey->kid);
2306
2307 if ((GNUNET_YES == box->rekeying) || (GNUNET_NO == box->rekeying))
2308 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2309 "UDPRekey has rekeying %u\n",
2310 box->rekeying);
2311 else
2312 do_decrypt = GNUNET_YES;
2313
2314 if ((GNUNET_YES == do_decrypt) && (NULL != kce) && (GNUNET_YES ==
2315 kce->ss->sender->
2316 rekeying))
2317 {
2318 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2319 "UDPRekey with kid %s\n",
2320 GNUNET_sh2s (&rekey->kid));
2321 sender = setup_sender (&rekey->sender, (const struct sockaddr *) &sa,
2322 salen);
2323
2324 if (NULL != sender->ss_rekey)
2325 return;
2326
2327 decrypt_rekey (rekey, (size_t) rcvd, kce, sender);
2328 return;
2329 }
2330 }
2331
2332 /* first, see if it is a UDPBox */
2333 if (rcvd > sizeof(struct UDPBox))
2334 {
2335 const struct UDPBox *box;
2336 struct KeyCacheEntry *kce;
2337
2338 box = (const struct UDPBox *) buf;
2339 kce = GNUNET_CONTAINER_multishortmap_get (key_cache, &box->kid);
2340 if (NULL != kce)
2341 {
2342 decrypt_box (box, (size_t) rcvd, kce);
2343 return;
2344 }
2345 }
2346
2347 /* next, check if it is a broadcast */
2348 if (sizeof(struct UDPBroadcast) == rcvd)
2349 {
2350 const struct UDPBroadcast *ub;
2351 struct UdpBroadcastSignature uhs;
2352 struct GNUNET_PeerIdentity sender;
2353
2354 addr_verify = GNUNET_memdup (&sa, salen);
2355 addr_verify->sin_port = 0;
2356 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2357 "received UDPBroadcast from %s\n",
2358 GNUNET_a2s ((const struct sockaddr *) addr_verify, salen));
2359 ub = (const struct UDPBroadcast *) buf;
2360 uhs.purpose.purpose = htonl (
2361 GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_UDP_BROADCAST);
2362 uhs.purpose.size = htonl (sizeof(uhs));
2363 uhs.sender = ub->sender;
2364 sender = ub->sender;
2365 if (0 == memcmp (&sender, &my_identity, sizeof (struct
2366 GNUNET_PeerIdentity)))
2367 {
2368 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2369 "Received our own broadcast\n");
2370 return;
2371 }
2372 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2373 "checking UDPBroadcastSignature for %s\n",
2374 GNUNET_i2s (&sender));
2375 GNUNET_CRYPTO_hash ((struct sockaddr *) addr_verify, salen, &uhs.h_address);
2376 if (GNUNET_OK ==
2377 GNUNET_CRYPTO_eddsa_verify (
2378 GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_UDP_BROADCAST,
2379 &uhs,
2380 &ub->sender_sig,
2381 &ub->sender.public_key))
2382 {
2383 char *addr_s;
2384 enum GNUNET_NetworkType nt;
2385
2386 addr_s =
2387 sockaddr_to_udpaddr_string ((const struct sockaddr *) &sa, salen);
2388 GNUNET_STATISTICS_update (stats, "# broadcasts received", 1, GNUNET_NO);
2389 /* use our own mechanism to determine network type */
2390 nt =
2391 GNUNET_NT_scanner_get_type (is, (const struct sockaddr *) &sa, salen);
2392 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2393 "validating address %s received from UDPBroadcast\n",
2394 GNUNET_i2s (&sender));
2395 GNUNET_TRANSPORT_application_validate (ah, &sender, nt, addr_s);
2396 GNUNET_free (addr_s);
2397 return;
2398 }
2399 else
2400 {
2401 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2402 "VerifyingPeer %s is verifying UDPBroadcast\n",
2403 GNUNET_i2s (&my_identity));
2404 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2405 "Verifying UDPBroadcast from %s failed\n",
2406 GNUNET_i2s (&ub->sender));
2407 }
2408 GNUNET_free (addr_verify);
2409 /* continue with KX, mostly for statistics... */
2410 }
2411
2412
2413 /* finally, test if it is a KX */
2414 if (rcvd < sizeof(struct UDPConfirmation) + sizeof(struct InitialKX))
2415 {
2416 GNUNET_STATISTICS_update (stats,
2417 "# messages dropped (no kid, too small for KX)",
2418 1,
2419 GNUNET_NO);
2420 return;
2421 }
2422 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2423 "Got KX\n");
2424 {
2425 const struct InitialKX *kx;
2426 struct SharedSecret *ss;
2427 char pbuf[rcvd - sizeof(struct InitialKX)];
2428 const struct UDPConfirmation *uc;
2429 struct SenderAddress *sender;
2430
2431 kx = (const struct InitialKX *) buf;
2432 ss = setup_shared_secret_dec (&kx->ephemeral);
2433 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2434 "Before DEC\n");
2435
2436 if (GNUNET_OK != try_decrypt (ss,
2437 kx->gcm_tag,
2438 0,
2439 &buf[sizeof(*kx)],
2440 sizeof(pbuf),
2441 pbuf))
2442 {
2443 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2444 "Unable to decrypt tag, dropping...\n");
2445 GNUNET_free (ss);
2446 GNUNET_STATISTICS_update (
2447 stats,
2448 "# messages dropped (no kid, AEAD decryption failed)",
2449 1,
2450 GNUNET_NO);
2451 return;
2452 }
2453 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2454 "Before VERIFY\n");
2455
2456 uc = (const struct UDPConfirmation *) pbuf;
2457 if (GNUNET_OK != verify_confirmation (&kx->ephemeral, uc))
2458 {
2459 GNUNET_break_op (0);
2460 GNUNET_free (ss);
2461 GNUNET_STATISTICS_update (stats,
2462 "# messages dropped (sender signature invalid)",
2463 1,
2464 GNUNET_NO);
2465 return;
2466 }
2467 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2468 "Before SETUP_SENDER\n");
2469
2470 calculate_cmac (ss);
2471 sender = setup_sender (&uc->sender, (const struct sockaddr *) &sa, salen);
2472 ss->sender = sender;
2473 GNUNET_CONTAINER_DLL_insert (sender->ss_head, sender->ss_tail, ss);
2474 sender->num_secrets++;
2475 GNUNET_STATISTICS_update (stats, "# Secrets active", 1, GNUNET_NO);
2476 GNUNET_STATISTICS_update (stats,
2477 "# messages decrypted without BOX",
2478 1,
2479 GNUNET_NO);
2480 try_handle_plaintext (sender, &uc[1], sizeof(pbuf) - sizeof(*uc));
2481 if ((GNUNET_NO == kx->rekeying) && (GNUNET_YES == ss->sender->rekeying))
2482 {
2483 ss->sender->rekeying = GNUNET_NO;
2484 sender->ss_rekey = NULL;
2485 // destroy_all_secrets (ss, GNUNET_NO);
2486 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2487 "Receiver stopped rekeying.\n");
2488 }
2489 else if (GNUNET_NO == kx->rekeying)
2490 consider_ss_ack (ss, GNUNET_YES);
2491 else
2492 {
2493 ss->sender->rekeying = GNUNET_YES;
2494 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2495 "Got KX: Receiver doing rekeying.\n");
2496 }
2497 /*if (sender->num_secrets > MAX_SECRETS)
2498 secret_destroy (sender->ss_tail);*/
2499 }
2500}
2501
2502
2503/**
2504 * Convert UDP bind specification to a `struct sockaddr *`
2505 *
2506 * @param bindto bind specification to convert
2507 * @param[out] sock_len set to the length of the address
2508 * @return converted bindto specification
2509 */
2510static struct sockaddr *
2511udp_address_to_sockaddr (const char *bindto, socklen_t *sock_len)
2512{
2513 struct sockaddr *in;
2514 unsigned int port;
2515 char dummy[2];
2516 char *colon;
2517 char *cp;
2518
2519 if (1 == sscanf (bindto, "%u%1s", &port, dummy))
2520 {
2521 /* interpreting value as just a PORT number */
2522 if (port > UINT16_MAX)
2523 {
2524 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2525 "BINDTO specification `%s' invalid: value too large for port\n",
2526 bindto);
2527 return NULL;
2528 }
2529 if ((GNUNET_NO == GNUNET_NETWORK_test_pf (PF_INET6)) ||
2530 (GNUNET_YES ==
2531 GNUNET_CONFIGURATION_get_value_yesno (cfg,
2532 COMMUNICATOR_CONFIG_SECTION,
2533 "DISABLE_V6")))
2534 {
2535 struct sockaddr_in *i4;
2536
2537 i4 = GNUNET_malloc (sizeof(struct sockaddr_in));
2538 i4->sin_family = AF_INET;
2539 i4->sin_port = htons ((uint16_t) port);
2540 *sock_len = sizeof(struct sockaddr_in);
2541 in = (struct sockaddr *) i4;
2542 }
2543 else
2544 {
2545 struct sockaddr_in6 *i6;
2546
2547 i6 = GNUNET_malloc (sizeof(struct sockaddr_in6));
2548 i6->sin6_family = AF_INET6;
2549 i6->sin6_port = htons ((uint16_t) port);
2550 *sock_len = sizeof(struct sockaddr_in6);
2551 in = (struct sockaddr *) i6;
2552 }
2553 return in;
2554 }
2555 cp = GNUNET_strdup (bindto);
2556 colon = strrchr (cp, ':');
2557 if (NULL != colon)
2558 {
2559 /* interpret value after colon as port */
2560 *colon = '\0';
2561 colon++;
2562 if (1 == sscanf (colon, "%u%1s", &port, dummy))
2563 {
2564 /* interpreting value as just a PORT number */
2565 if (port > UINT16_MAX)
2566 {
2567 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2568 "BINDTO specification `%s' invalid: value too large for port\n",
2569 bindto);
2570 GNUNET_free (cp);
2571 return NULL;
2572 }
2573 }
2574 else
2575 {
2576 GNUNET_log (
2577 GNUNET_ERROR_TYPE_ERROR,
2578 "BINDTO specification `%s' invalid: last ':' not followed by number\n",
2579 bindto);
2580 GNUNET_free (cp);
2581 return NULL;
2582 }
2583 }
2584 else
2585 {
2586 /* interpret missing port as 0, aka pick any free one */
2587 port = 0;
2588 }
2589 {
2590 /* try IPv4 */
2591 struct sockaddr_in v4;
2592 if (1 == inet_pton (AF_INET, cp, &v4.sin_addr))
2593 {
2594 v4.sin_family = AF_INET;
2595 v4.sin_port = htons ((uint16_t) port);
2596#if HAVE_SOCKADDR_IN_SIN_LEN
2597 v4.sin_len = sizeof(struct sockaddr_in);
2598#endif
2599 in = GNUNET_memdup (&v4, sizeof(struct sockaddr_in));
2600 *sock_len = sizeof(struct sockaddr_in);
2601 GNUNET_free (cp);
2602 return in;
2603 }
2604 }
2605 {
2606 /* try IPv6 */
2607 struct sockaddr_in6 v6;
2608 const char *start;
2609
2610 start = cp;
2611 if (('[' == *cp) && (']' == cp[strlen (cp) - 1]))
2612 {
2613 start++; /* skip over '[' */
2614 cp[strlen (cp) - 1] = '\0'; /* eat ']' */
2615 }
2616 if (1 == inet_pton (AF_INET6, start, &v6.sin6_addr))
2617 {
2618 v6.sin6_family = AF_INET6;
2619 v6.sin6_port = htons ((uint16_t) port);
2620#if HAVE_SOCKADDR_IN_SIN_LEN
2621 v6.sin6_len = sizeof(sizeof(struct sockaddr_in6));
2622#endif
2623 in = GNUNET_memdup (&v6, sizeof(v6));
2624 *sock_len = sizeof(v6);
2625 GNUNET_free (cp);
2626 return in;
2627 }
2628 }
2629 /* #5528 FIXME (feature!): maybe also try getnameinfo()? */
2630 GNUNET_free (cp);
2631 return NULL;
2632}
2633
2634
2635/**
2636 * Pad @a dgram by @a pad_size using @a out_cipher.
2637 *
2638 * @param out_cipher cipher to use
2639 * @param dgram datagram to pad
2640 * @param pad_size number of bytes of padding to append
2641 */
2642static void
2643do_pad (gcry_cipher_hd_t out_cipher, char *dgram, size_t pad_size)
2644{
2645 char pad[pad_size];
2646
2647 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, pad, sizeof(pad));
2648 if (sizeof(pad) > sizeof(struct GNUNET_MessageHeader))
2649 {
2650 struct GNUNET_MessageHeader hdr =
2651 { .size = htons (sizeof(pad)),
2652 .type = htons (GNUNET_MESSAGE_TYPE_COMMUNICATOR_UDP_PAD) };
2653
2654 memcpy (pad, &hdr, sizeof(hdr));
2655 }
2656 GNUNET_assert (
2657 0 ==
2658 gcry_cipher_encrypt (out_cipher, dgram, sizeof(pad), pad, sizeof(pad)));
2659}
2660
2661
2662/**
2663 * Signature of functions implementing the sending functionality of a
2664 * message queue.
2665 *
2666 * @param mq the message queue
2667 * @param msg the message to send
2668 * @param impl_state our `struct ReceiverAddress`
2669 */
2670static void
2671mq_send_kx (struct GNUNET_MQ_Handle *mq,
2672 const struct GNUNET_MessageHeader *msg,
2673 void *impl_state)
2674{
2675 struct ReceiverAddress *receiver = impl_state;
2676 uint16_t msize = ntohs (msg->size);
2677 struct UdpHandshakeSignature uhs;
2678 struct UDPConfirmation uc;
2679 struct InitialKX kx;
2680 struct GNUNET_CRYPTO_EcdhePrivateKey epriv;
2681 char dgram[receiver->kx_mtu + sizeof(uc) + sizeof(kx)];
2682 size_t dpos;
2683 gcry_cipher_hd_t out_cipher;
2684 struct SharedSecret *ss;
2685
2686 GNUNET_assert (mq == receiver->kx_mq);
2687 if (msize > receiver->kx_mtu)
2688 {
2689 GNUNET_break (0);
2690 if (GNUNET_YES != receiver->receiver_destroy_called)
2691 receiver_destroy (receiver);
2692 return;
2693 }
2694 reschedule_receiver_timeout (receiver);
2695
2696 /* setup key material */
2697 GNUNET_CRYPTO_ecdhe_key_create (&epriv);
2698
2699 ss = setup_shared_secret_enc (&epriv, receiver, GNUNET_YES);
2700
2701 if (receiver->num_secrets > MAX_SECRETS)
2702 {
2703 destroy_all_secrets (ss, GNUNET_YES);
2704 }
2705
2706 setup_cipher (&ss->master, 0, &out_cipher);
2707 /* compute 'uc' */
2708 uc.sender = my_identity;
2709 uc.monotonic_time =
2710 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (cfg));
2711 uhs.purpose.purpose = htonl (
2712 GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_UDP_HANDSHAKE);
2713 uhs.purpose.size = htonl (sizeof(uhs));
2714 uhs.sender = my_identity;
2715 uhs.receiver = receiver->target;
2716 GNUNET_CRYPTO_ecdhe_key_get_public (&epriv, &uhs.ephemeral);
2717 uhs.monotonic_time = uc.monotonic_time;
2718 GNUNET_CRYPTO_eddsa_sign (my_private_key,
2719 &uhs,
2720 &uc.sender_sig);
2721 /* Leave space for kx */
2722 dpos = sizeof(kx);
2723 /* Append encrypted uc to dgram */
2724 GNUNET_assert (0 == gcry_cipher_encrypt (out_cipher,
2725 &dgram[dpos],
2726 sizeof(uc),
2727 &uc,
2728 sizeof(uc)));
2729 dpos += sizeof(uc);
2730 /* Append encrypted payload to dgram */
2731 GNUNET_assert (
2732 0 == gcry_cipher_encrypt (out_cipher, &dgram[dpos], msize, msg, msize));
2733 dpos += msize;
2734 do_pad (out_cipher, &dgram[dpos], sizeof(dgram) - dpos);
2735 /* Datagram starts with kx */
2736 kx.ephemeral = uhs.ephemeral;
2737 GNUNET_assert (
2738 0 == gcry_cipher_gettag (out_cipher, kx.gcm_tag, sizeof(kx.gcm_tag)));
2739 gcry_cipher_close (out_cipher);
2740 if (GNUNET_NO == receiver->rekeying)
2741 kx.rekeying = GNUNET_NO;
2742 else
2743 kx.rekeying = GNUNET_YES;
2744 memcpy (dgram, &kx, sizeof(kx));
2745 if (-1 == GNUNET_NETWORK_socket_sendto (udp_sock,
2746 dgram,
2747 sizeof(dgram),
2748 receiver->address,
2749 receiver->address_len))
2750 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "send");
2751 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2752 "Sending KX with payload size %u to %s\n",
2753 msize,
2754 GNUNET_a2s (receiver->address,
2755 receiver->address_len));
2756 GNUNET_MQ_impl_send_continue (mq);
2757}
2758
2759
2760static void
2761check_for_rekeying (struct ReceiverAddress *receiver, struct UDPBox *box)
2762{
2763
2764 struct GNUNET_TIME_Relative rt;
2765
2766 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2767 "Timeout is %llu\n.",
2768 (unsigned long long) receiver->rekey_timeout.abs_value_us);
2769
2770 if (0 == receiver->rekey_timeout.abs_value_us)
2771 {
2772 receiver->rekey_timeout = GNUNET_TIME_relative_to_absolute (
2773 rekey_interval);
2774 }
2775 else
2776 {
2777 rt = GNUNET_TIME_absolute_get_remaining (receiver->rekey_timeout);
2778 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2779 "Relative time is %llu and timeout is %llu\n.",
2780 (unsigned long long) rt.rel_value_us,
2781 (unsigned long long) receiver->rekey_timeout.abs_value_us);
2782
2783 if ((0 == rt.rel_value_us) || (receiver->rekey_send_bytes >
2784 rekey_max_bytes) )
2785 {
2786 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2787 "Bytes send %llu greater than %llu max bytes\n.",
2788 (unsigned long long) receiver->rekey_send_bytes,
2789 rekey_max_bytes);
2790 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2791 "Relative time is %llu and timeout is %llu\n.",
2792 (unsigned long long) rt.rel_value_us,
2793 (unsigned long long) receiver->rekey_timeout.abs_value_us);
2794
2795 receiver->rekey_timeout.abs_value_us = 0;
2796 receiver->rekey_send_bytes = 0;
2797 receiver->ss_rekey = NULL;
2798 // destroy_all_secrets (ss, GNUNET_NO);
2799 receiver->rekeying = GNUNET_YES;
2800 receiver->rekey_acks_available = receiver->acks_available;
2801 box->rekeying = GNUNET_YES;
2802 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2803 "Sender started rekeying.\n");
2804 if (GNUNET_YES == box->rekeying)
2805 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2806 "Sending rekeying with kid %s\n",
2807 GNUNET_sh2s (&box->kid));
2808 }
2809 }
2810}
2811
2812
2813static void
2814send_UDPRekey (struct ReceiverAddress *receiver, struct SharedSecret *ss)
2815{
2816 uint8_t is_ss_rekey_sequence_allowed_zero = GNUNET_NO;
2817 uint8_t is_acks_available_below = GNUNET_NO;
2818 uint8_t send_rekey = GNUNET_NO;
2819 uint16_t not_below;
2820 struct GNUNET_CRYPTO_EcdhePrivateKey epriv;
2821 struct UDPRekey *rekey;
2822 size_t dpos;
2823
2824 char rekey_dgram[sizeof(struct UDPRekey) + receiver->d_mtu];
2825
2826 if (NULL != receiver->ss_rekey)
2827 {
2828 not_below = (receiver->rekey_acks_available
2829 - (receiver->rekey_acks_available % 3)) / 3;
2830 is_ss_rekey_sequence_allowed_zero = (0 ==
2831 receiver->ss_rekey->sequence_allowed);
2832 is_acks_available_below = (receiver->acks_available >= not_below);
2833 send_rekey = (0 == (receiver->acks_available - not_below) % not_below) &&
2834 is_acks_available_below && is_ss_rekey_sequence_allowed_zero;
2835 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2836 "send_rekey: %u, %u, %u\n",
2837 send_rekey,
2838 receiver->rekey_acks_available,
2839 receiver->acks_available);
2840 }
2841 else if (NULL == receiver->ss_rekey)
2842 {
2843 /* setup key material */
2844 GNUNET_CRYPTO_ecdhe_key_create (&epriv);
2845 receiver->ss_rekey = setup_shared_secret_enc (&epriv, receiver,
2846 GNUNET_NO);
2847 receiver->ss_rekey->sequence_allowed = 0;
2848 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2849 "Setup secret with cmac %s\n",
2850 GNUNET_h2s (&(receiver->ss_rekey->cmac)));
2851 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2852 "Setup secret with master %s.\n",
2853 GNUNET_h2s (&(receiver->ss_rekey->master)));
2854 }
2855
2856 if (send_rekey)
2857 {
2858 GNUNET_assert (0 != receiver->number_rekeying_kce);
2859 gcry_cipher_hd_t rekey_out_cipher;
2860
2861 while (NULL != ss && ss->sequence_used >= ss->sequence_allowed)
2862 {
2863 ss = ss->prev;
2864 }
2865
2866 if (NULL != ss)
2867 {
2868 rekey = (struct UDPRekey *) rekey_dgram;
2869 rekey->sender = my_identity;
2870 ss->sequence_used++;
2871 get_kid (&ss->master, ss->sequence_used, &rekey->kid);
2872 receiver->number_rekeying_kce--;
2873 setup_cipher (&ss->master, ss->sequence_used, &rekey_out_cipher);
2874 /* Append encrypted payload to dgram */
2875 dpos = sizeof(struct UDPRekey);
2876
2877 GNUNET_assert (
2878 0 == gcry_cipher_encrypt (rekey_out_cipher, &rekey_dgram[dpos],
2879 sizeof(receiver->ss_rekey->master),
2880 &(receiver->ss_rekey->master),
2881 sizeof(receiver->ss_rekey->master)));
2882 dpos += sizeof(receiver->ss_rekey->master);
2883 /* GNUNET_assert ( */
2884 /* 0 == gcry_cipher_encrypt (rekey_out_cipher, &rekey_dgram[dpos], */
2885 /* /\*sizeof(receiver->ss_rekey->cmac), */
2886 /* &(receiver->ss_rekey->cmac), */
2887 /* sizeof(receiver->ss_rekey->cmac))); */
2888 /* dpos += sizeof(receiver->ss_rekey->cmac);*\/ */
2889 /* sizeof(receiver->ss_rekey), */
2890 /* receiver->ss_rekey, */
2891 /* sizeof(receiver->ss_rekey))); */
2892 /* dpos += sizeof(receiver->ss_rekey); */
2893 do_pad (rekey_out_cipher, &rekey_dgram[dpos], sizeof(rekey_dgram)
2894 - dpos);
2895 GNUNET_assert (0 == gcry_cipher_gettag (rekey_out_cipher,
2896 rekey->gcm_tag,
2897 sizeof(rekey->gcm_tag)));
2898 gcry_cipher_close (rekey_out_cipher);
2899
2900 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2901 "Sending rekey with kid %s and master %s\n",
2902 GNUNET_sh2s (&rekey->kid),
2903 GNUNET_h2s (&(receiver->ss_rekey->master)));
2904 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2905 "Sending rekey with cmac %s\n",
2906 GNUNET_h2s (&(receiver->ss_rekey->cmac)));
2907 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2908 "%u rekey kces left.\n",
2909 receiver->number_rekeying_kce);
2910
2911 if (-1 == GNUNET_NETWORK_socket_sendto (udp_sock,
2912 rekey_dgram,
2913 sizeof(rekey_dgram),
2914 receiver->address,
2915 receiver->address_len))
2916 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "send");
2917
2918 receiver->acks_available--;
2919 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2920 "%u receiver->acks_available 1\n",
2921 receiver->acks_available);
2922 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2923 "Sending UDPRekey to %s\n", GNUNET_a2s (receiver->address,
2924 receiver->
2925 address_len));
2926 }
2927 }
2928}
2929
2930
2931/**
2932 * Signature of functions implementing the sending functionality of a
2933 * message queue.
2934 *
2935 * @param mq the message queue
2936 * @param msg the message to send
2937 * @param impl_state our `struct ReceiverAddress`
2938 */
2939static void
2940mq_send_d (struct GNUNET_MQ_Handle *mq,
2941 const struct GNUNET_MessageHeader *msg,
2942 void *impl_state)
2943{
2944 struct ReceiverAddress *receiver = impl_state;
2945 uint16_t msize = ntohs (msg->size);
2946
2947 GNUNET_assert (mq == receiver->d_mq);
2948 if ((msize > receiver->d_mtu) ||
2949 (0 == receiver->acks_available))
2950 {
2951 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2952 "msize: %u, mtu: %lu, acks: %u\n",
2953 msize,
2954 receiver->d_mtu,
2955 receiver->acks_available);
2956
2957 GNUNET_break (0);
2958 if (GNUNET_YES != receiver->receiver_destroy_called)
2959 receiver_destroy (receiver);
2960 return;
2961 }
2962 reschedule_receiver_timeout (receiver);
2963
2964 /* begin "BOX" encryption method, scan for ACKs from tail! */
2965 for (struct SharedSecret *ss = receiver->ss_tail; NULL != ss; ss = ss->prev)
2966 {
2967 if (0 < ss->sequence_used)
2968 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2969 "Trying to send UDPBox with shared secrect %s sequence_used %u and ss->sequence_allowed %u\n",
2970 GNUNET_h2s (&ss->master),
2971 ss->sequence_used,
2972 ss->sequence_allowed);
2973 // Uncomment this for alternativ 1 of backchannel functionality
2974 if (ss->sequence_used >= ss->sequence_allowed)
2975 // Until here for alternativ 1
2976 // Uncomment this for alternativ 2 of backchannel functionality
2977 // if (0 == ss->sequence_allowed)
2978 // Until here for alternativ 2
2979 {
2980 continue;
2981 }
2982 char dgram[sizeof(struct UDPBox) + receiver->d_mtu];
2983 struct UDPBox *box;
2984 gcry_cipher_hd_t out_cipher;
2985 size_t dpos;
2986
2987 box = (struct UDPBox *) dgram;
2988 ss->sequence_used++;
2989 get_kid (&ss->master, ss->sequence_used, &box->kid);
2990 setup_cipher (&ss->master, ss->sequence_used, &out_cipher);
2991 /* Append encrypted payload to dgram */
2992 dpos = sizeof(struct UDPBox);
2993 GNUNET_assert (
2994 0 == gcry_cipher_encrypt (out_cipher, &dgram[dpos], msize, msg, msize));
2995 dpos += msize;
2996 do_pad (out_cipher, &dgram[dpos], sizeof(dgram) - dpos);
2997 GNUNET_assert (0 == gcry_cipher_gettag (out_cipher,
2998 box->gcm_tag,
2999 sizeof(box->gcm_tag)));
3000 gcry_cipher_close (out_cipher);
3001
3002 receiver->rekey_send_bytes += sizeof(struct UDPBox) + receiver->d_mtu;
3003
3004 if (GNUNET_NO == receiver->rekeying)
3005 box->rekeying = GNUNET_NO;
3006 else
3007 box->rekeying = GNUNET_YES;
3008
3009 if (-1 == GNUNET_NETWORK_socket_sendto (udp_sock,
3010 dgram,
3011 sizeof(dgram),
3012 receiver->address,
3013 receiver->address_len))
3014 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "send");
3015 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3016 "Sending UDPBox with payload size %u, %u acks left\n",
3017 msize,
3018 receiver->acks_available);
3019 GNUNET_MQ_impl_send_continue (mq);
3020 receiver->acks_available--;
3021 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3022 "%u receiver->acks_available 2\n",
3023 receiver->acks_available);
3024 check_for_rekeying (receiver, box);
3025 if (0 == receiver->acks_available - receiver->number_rekeying_kce)
3026 {
3027 /* We have no more ACKs */
3028 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3029 "No more acks\n");
3030 if (GNUNET_YES == receiver->rekeying)
3031 {
3032 receiver->rekeying = GNUNET_NO;
3033 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3034 "Sender stopped rekeying\n");
3035
3036 if ((NULL != receiver->ss_rekey) && (0 <
3037 receiver->ss_rekey->
3038 sequence_allowed) )
3039 add_acks_rekey (receiver);
3040 }
3041 }
3042 else if ((GNUNET_YES == receiver->rekeying) )
3043 {
3044 send_UDPRekey (receiver, ss);
3045 }
3046
3047 return;
3048 }
3049}
3050
3051
3052/**
3053 * Signature of functions implementing the destruction of a message
3054 * queue. Implementations must not free @a mq, but should take care
3055 * of @a impl_state.
3056 *
3057 * @param mq the message queue to destroy
3058 * @param impl_state our `struct ReceiverAddress`
3059 */
3060static void
3061mq_destroy_d (struct GNUNET_MQ_Handle *mq, void *impl_state)
3062{
3063 struct ReceiverAddress *receiver = impl_state;
3064 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3065 "Default MQ destroyed\n");
3066 if (mq == receiver->d_mq)
3067 {
3068 receiver->d_mq = NULL;
3069 if (GNUNET_YES != receiver->receiver_destroy_called)
3070 receiver_destroy (receiver);
3071 }
3072}
3073
3074
3075/**
3076 * Signature of functions implementing the destruction of a message
3077 * queue. Implementations must not free @a mq, but should take care
3078 * of @a impl_state.
3079 *
3080 * @param mq the message queue to destroy
3081 * @param impl_state our `struct ReceiverAddress`
3082 */
3083static void
3084mq_destroy_kx (struct GNUNET_MQ_Handle *mq, void *impl_state)
3085{
3086 struct ReceiverAddress *receiver = impl_state;
3087 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3088 "KX MQ destroyed\n");
3089 if (mq == receiver->kx_mq)
3090 {
3091 receiver->kx_mq = NULL;
3092 if (GNUNET_YES != receiver->receiver_destroy_called)
3093 receiver_destroy (receiver);
3094 }
3095}
3096
3097
3098/**
3099 * Implementation function that cancels the currently sent message.
3100 *
3101 * @param mq message queue
3102 * @param impl_state our `struct RecvierAddress`
3103 */
3104static void
3105mq_cancel (struct GNUNET_MQ_Handle *mq, void *impl_state)
3106{
3107 /* Cancellation is impossible with UDP; bail */
3108 GNUNET_assert (0);
3109}
3110
3111
3112/**
3113 * Generic error handler, called with the appropriate
3114 * error code and the same closure specified at the creation of
3115 * the message queue.
3116 * Not every message queue implementation supports an error handler.
3117 *
3118 * @param cls our `struct ReceiverAddress`
3119 * @param error error code
3120 */
3121static void
3122mq_error (void *cls, enum GNUNET_MQ_Error error)
3123{
3124 struct ReceiverAddress *receiver = cls;
3125
3126 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3127 "MQ error in queue to %s: %d\n",
3128 GNUNET_i2s (&receiver->target),
3129 (int) error);
3130 receiver_destroy (receiver);
3131}
3132
3133
3134/**
3135 * Setup the MQ for the @a receiver. If a queue exists,
3136 * the existing one is destroyed. Then the MTU is
3137 * recalculated and a fresh queue is initialized.
3138 *
3139 * @param receiver receiver to setup MQ for
3140 */
3141static void
3142setup_receiver_mq (struct ReceiverAddress *receiver)
3143{
3144 size_t base_mtu;
3145
3146 /*if (NULL != receiver->kx_qh)
3147 {
3148 GNUNET_TRANSPORT_communicator_mq_del (receiver->kx_qh);
3149 receiver->kx_qh = NULL;
3150 }
3151 if (NULL != receiver->d_qh)
3152 {
3153 GNUNET_TRANSPORT_communicator_mq_del (receiver->d_qh);
3154 receiver->d_qh = NULL;
3155 }*/
3156 // GNUNET_assert (NULL == receiver->mq);
3157 switch (receiver->address->sa_family)
3158 {
3159 case AF_INET:
3160 base_mtu = 1480 /* Ethernet MTU, 1500 - Ethernet header - VLAN tag */
3161 - sizeof(struct GNUNET_TUN_IPv4Header) /* 20 */
3162 - sizeof(struct GNUNET_TUN_UdpHeader) /* 8 */;
3163 break;
3164
3165 case AF_INET6:
3166 base_mtu = 1280 /* Minimum MTU required by IPv6 */
3167 - sizeof(struct GNUNET_TUN_IPv6Header) /* 40 */
3168 - sizeof(struct GNUNET_TUN_UdpHeader) /* 8 */;
3169 break;
3170
3171 default:
3172 GNUNET_assert (0);
3173 break;
3174 }
3175 /* MTU based on full KX messages */
3176 receiver->kx_mtu = base_mtu - sizeof(struct InitialKX) /* 48 */
3177 - sizeof(struct UDPConfirmation); /* 104 */
3178 /* MTU based on BOXed messages */
3179 receiver->d_mtu = base_mtu - sizeof(struct UDPBox);
3180
3181 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3182 "Setting up MQs and QHs\n");
3183 /* => Effective MTU for CORE will range from 1080 (IPv6 + KX) to
3184 1404 (IPv4 + Box) bytes, depending on circumstances... */
3185 if (NULL == receiver->kx_mq)
3186 receiver->kx_mq = GNUNET_MQ_queue_for_callbacks (&mq_send_kx,
3187 &mq_destroy_kx,
3188 &mq_cancel,
3189 receiver,
3190 NULL,
3191 &mq_error,
3192 receiver);
3193 if (NULL == receiver->d_mq)
3194 receiver->d_mq = GNUNET_MQ_queue_for_callbacks (&mq_send_d,
3195 &mq_destroy_d,
3196 &mq_cancel,
3197 receiver,
3198 NULL,
3199 &mq_error,
3200 receiver);
3201
3202 receiver->kx_qh =
3203 GNUNET_TRANSPORT_communicator_mq_add (ch,
3204 &receiver->target,
3205 receiver->foreign_addr,
3206 receiver->kx_mtu,
3207 GNUNET_TRANSPORT_QUEUE_LENGTH_UNLIMITED,
3208 0, /* Priority */
3209 receiver->nt,
3210 GNUNET_TRANSPORT_CS_OUTBOUND,
3211 receiver->kx_mq);
3212}
3213
3214
3215/**
3216 * Function called by the transport service to initialize a
3217 * message queue given address information about another peer.
3218 * If and when the communication channel is established, the
3219 * communicator must call #GNUNET_TRANSPORT_communicator_mq_add()
3220 * to notify the service that the channel is now up. It is
3221 * the responsibility of the communicator to manage sane
3222 * retries and timeouts for any @a peer/@a address combination
3223 * provided by the transport service. Timeouts and retries
3224 * do not need to be signalled to the transport service.
3225 *
3226 * @param cls closure
3227 * @param peer identity of the other peer
3228 * @param address where to send the message, human-readable
3229 * communicator-specific format, 0-terminated, UTF-8
3230 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the provided address is
3231 * invalid
3232 */
3233static int
3234mq_init (void *cls, const struct GNUNET_PeerIdentity *peer, const char *address)
3235{
3236 struct ReceiverAddress *receiver;
3237 const char *path;
3238 struct sockaddr *in;
3239 socklen_t in_len;
3240
3241 if (0 != strncmp (address,
3242 COMMUNICATOR_ADDRESS_PREFIX "-",
3243 strlen (COMMUNICATOR_ADDRESS_PREFIX "-")))
3244 {
3245 GNUNET_break_op (0);
3246 return GNUNET_SYSERR;
3247 }
3248 path = &address[strlen (COMMUNICATOR_ADDRESS_PREFIX "-")];
3249 in = udp_address_to_sockaddr (path, &in_len);
3250
3251 receiver = GNUNET_new (struct ReceiverAddress);
3252 receiver->address = in;
3253 receiver->address_len = in_len;
3254 receiver->target = *peer;
3255 receiver->nt = GNUNET_NT_scanner_get_type (is, in, in_len);
3256 (void) GNUNET_CONTAINER_multipeermap_put (
3257 receivers,
3258 &receiver->target,
3259 receiver,
3260 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3261 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3262 "Added %s to receivers\n",
3263 GNUNET_i2s_full (&receiver->target));
3264 receiver->timeout =
3265 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3266 receiver->hn = GNUNET_CONTAINER_heap_insert (receivers_heap,
3267 receiver,
3268 receiver->timeout.abs_value_us);
3269 GNUNET_STATISTICS_set (stats,
3270 "# receivers active",
3271 GNUNET_CONTAINER_multipeermap_size (receivers),
3272 GNUNET_NO);
3273 receiver->foreign_addr =
3274 sockaddr_to_udpaddr_string (receiver->address, receiver->address_len);
3275 setup_receiver_mq (receiver);
3276 if (NULL == timeout_task)
3277 timeout_task = GNUNET_SCHEDULER_add_now (&check_timeouts, NULL);
3278 return GNUNET_OK;
3279}
3280
3281
3282/**
3283 * Iterator over all receivers to clean up.
3284 *
3285 * @param cls NULL
3286 * @param target unused
3287 * @param value the queue to destroy
3288 * @return #GNUNET_OK to continue to iterate
3289 */
3290static int
3291get_receiver_delete_it (void *cls,
3292 const struct GNUNET_PeerIdentity *target,
3293 void *value)
3294{
3295 struct ReceiverAddress *receiver = value;
3296
3297 (void) cls;
3298 (void) target;
3299 receiver_destroy (receiver);
3300 return GNUNET_OK;
3301}
3302
3303
3304/**
3305 * Iterator over all senders to clean up.
3306 *
3307 * @param cls NULL
3308 * @param target unused
3309 * @param value the queue to destroy
3310 * @return #GNUNET_OK to continue to iterate
3311 */
3312static int
3313get_sender_delete_it (void *cls,
3314 const struct GNUNET_PeerIdentity *target,
3315 void *value)
3316{
3317 struct SenderAddress *sender = value;
3318
3319 (void) cls;
3320 (void) target;
3321
3322 if (NULL != sender->kce_task_rekey)
3323 {
3324 GNUNET_SCHEDULER_cancel (sender->kce_task_rekey);
3325 sender->kce_task_rekey = NULL;
3326 }
3327 if (NULL != sender->kce_task)
3328 {
3329 GNUNET_SCHEDULER_cancel (sender->kce_task);
3330 sender->kce_task = NULL;
3331 }
3332
3333 sender_destroy (sender);
3334 return GNUNET_OK;
3335}
3336
3337
3338/**
3339 * Shutdown the UNIX communicator.
3340 *
3341 * @param cls NULL (always)
3342 */
3343static void
3344do_shutdown (void *cls)
3345{
3346 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3347 "do_shutdown\n");
3348 if (NULL != nat)
3349 {
3350 GNUNET_NAT_unregister (nat);
3351 nat = NULL;
3352 }
3353 while (NULL != bi_head)
3354 bi_destroy (bi_head);
3355 if (NULL != broadcast_task)
3356 {
3357 GNUNET_SCHEDULER_cancel (broadcast_task);
3358 broadcast_task = NULL;
3359 }
3360 if (NULL != timeout_task)
3361 {
3362 GNUNET_SCHEDULER_cancel (timeout_task);
3363 timeout_task = NULL;
3364 }
3365 if (NULL != read_task)
3366 {
3367 GNUNET_SCHEDULER_cancel (read_task);
3368 read_task = NULL;
3369 }
3370 if (NULL != udp_sock)
3371 {
3372 GNUNET_break (GNUNET_OK ==
3373 GNUNET_NETWORK_socket_close (udp_sock));
3374 udp_sock = NULL;
3375 }
3376 GNUNET_CONTAINER_multipeermap_iterate (receivers,
3377 &get_receiver_delete_it,
3378 NULL);
3379 GNUNET_CONTAINER_multipeermap_destroy (receivers);
3380 GNUNET_CONTAINER_multipeermap_iterate (senders,
3381 &get_sender_delete_it,
3382 NULL);
3383 GNUNET_CONTAINER_multipeermap_destroy (senders);
3384 GNUNET_CONTAINER_multishortmap_destroy (key_cache);
3385 GNUNET_CONTAINER_heap_destroy (senders_heap);
3386 GNUNET_CONTAINER_heap_destroy (receivers_heap);
3387 if (NULL != timeout_task)
3388 {
3389 GNUNET_SCHEDULER_cancel (timeout_task);
3390 timeout_task = NULL;
3391 }
3392 if (NULL != ch)
3393 {
3394 GNUNET_TRANSPORT_communicator_disconnect (ch);
3395 ch = NULL;
3396 }
3397 if (NULL != ah)
3398 {
3399 GNUNET_TRANSPORT_application_done (ah);
3400 ah = NULL;
3401 }
3402 if (NULL != stats)
3403 {
3404 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
3405 stats = NULL;
3406 }
3407 if (NULL != my_private_key)
3408 {
3409 GNUNET_free (my_private_key);
3410 my_private_key = NULL;
3411 }
3412 if (NULL != is)
3413 {
3414 GNUNET_NT_scanner_done (is);
3415 is = NULL;
3416 }
3417 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3418 "do_shutdown finished\n");
3419}
3420
3421
3422/**
3423 * Function called when the transport service has received a
3424 * backchannel message for this communicator (!) via a different return
3425 * path. Should be an acknowledgement.
3426 *
3427 * @param cls closure, NULL
3428 * @param sender which peer sent the notification
3429 * @param msg payload
3430 */
3431static void
3432enc_notify_cb (void *cls,
3433 const struct GNUNET_PeerIdentity *sender,
3434 const struct GNUNET_MessageHeader *msg)
3435{
3436 const struct UDPAck *ack;
3437
3438 (void) cls;
3439 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3440 "Storing UDPAck received from backchannel from %s\n",
3441 GNUNET_i2s_full (sender));
3442 if ((ntohs (msg->type) != GNUNET_MESSAGE_TYPE_COMMUNICATOR_UDP_ACK) ||
3443 (ntohs (msg->size) != sizeof(struct UDPAck)))
3444 {
3445 GNUNET_break_op (0);
3446 return;
3447 }
3448 ack = (const struct UDPAck *) msg;
3449 GNUNET_CONTAINER_multipeermap_get_multiple (receivers,
3450 sender,
3451 &handle_ack,
3452 (void *) ack);
3453}
3454
3455
3456/**
3457 * Signature of the callback passed to #GNUNET_NAT_register() for
3458 * a function to call whenever our set of 'valid' addresses changes.
3459 *
3460 * @param cls closure
3461 * @param app_ctx[in,out] location where the app can store stuff
3462 * on add and retrieve it on remove
3463 * @param add_remove #GNUNET_YES to add a new public IP address,
3464 * #GNUNET_NO to remove a previous (now invalid) one
3465 * @param ac address class the address belongs to
3466 * @param addr either the previous or the new public IP address
3467 * @param addrlen actual length of the @a addr
3468 */
3469static void
3470nat_address_cb (void *cls,
3471 void **app_ctx,
3472 int add_remove,
3473 enum GNUNET_NAT_AddressClass ac,
3474 const struct sockaddr *addr,
3475 socklen_t addrlen)
3476{
3477 char *my_addr;
3478 struct GNUNET_TRANSPORT_AddressIdentifier *ai;
3479
3480 if (GNUNET_YES == add_remove)
3481 {
3482 enum GNUNET_NetworkType nt;
3483
3484 GNUNET_asprintf (&my_addr,
3485 "%s-%s",
3486 COMMUNICATOR_ADDRESS_PREFIX,
3487 GNUNET_a2s (addr, addrlen));
3488 nt = GNUNET_NT_scanner_get_type (is, addr, addrlen);
3489 ai =
3490 GNUNET_TRANSPORT_communicator_address_add (ch,
3491 my_addr,
3492 nt,
3493 GNUNET_TIME_UNIT_FOREVER_REL);
3494 GNUNET_free (my_addr);
3495 *app_ctx = ai;
3496 }
3497 else
3498 {
3499 ai = *app_ctx;
3500 GNUNET_TRANSPORT_communicator_address_remove (ai);
3501 *app_ctx = NULL;
3502 }
3503}
3504
3505
3506/**
3507 * Broadcast our presence on one of our interfaces.
3508 *
3509 * @param cls a `struct BroadcastInterface`
3510 */
3511static void
3512ifc_broadcast (void *cls)
3513{
3514 struct BroadcastInterface *bi = cls;
3515 struct GNUNET_TIME_Relative delay;
3516
3517 delay = BROADCAST_FREQUENCY;
3518 delay.rel_value_us =
3519 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, delay.rel_value_us);
3520 bi->broadcast_task =
3521 GNUNET_SCHEDULER_add_delayed (delay, &ifc_broadcast, bi);
3522
3523 switch (bi->sa->sa_family)
3524 {
3525 case AF_INET: {
3526 static int yes = 1;
3527 static int no = 0;
3528 ssize_t sent;
3529
3530 if (GNUNET_OK !=
3531 GNUNET_NETWORK_socket_setsockopt (udp_sock,
3532 SOL_SOCKET,
3533 SO_BROADCAST,
3534 &yes,
3535 sizeof(int)))
3536 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
3537 "setsockopt");
3538 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3539 "creating UDPBroadcast from %s\n",
3540 GNUNET_i2s (&(bi->bcm.sender)));
3541 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3542 "sending UDPBroadcast to add %s\n",
3543 GNUNET_a2s (bi->ba, bi->salen));
3544 sent = GNUNET_NETWORK_socket_sendto (udp_sock,
3545 &bi->bcm,
3546 sizeof(bi->bcm),
3547 bi->ba,
3548 bi->salen);
3549 if (-1 == sent)
3550 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
3551 "sendto");
3552 if (GNUNET_OK != GNUNET_NETWORK_socket_setsockopt (udp_sock,
3553 SOL_SOCKET,
3554 SO_BROADCAST,
3555 &no,
3556 sizeof(int)))
3557 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
3558 "setsockopt");
3559 break;
3560 }
3561
3562 case AF_INET6: {
3563 ssize_t sent;
3564 struct sockaddr_in6 dst;
3565
3566 dst.sin6_family = AF_INET6;
3567 dst.sin6_port = htons (my_port);
3568 dst.sin6_addr = bi->mcreq.ipv6mr_multiaddr;
3569 dst.sin6_scope_id = ((struct sockaddr_in6 *) bi->ba)->sin6_scope_id;
3570
3571 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3572 "sending UDPBroadcast\n");
3573 sent = GNUNET_NETWORK_socket_sendto (udp_sock,
3574 &bi->bcm,
3575 sizeof(bi->bcm),
3576 (const struct sockaddr *) &dst,
3577 sizeof(dst));
3578 if (-1 == sent)
3579 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "sendto");
3580 break;
3581 }
3582
3583 default:
3584 GNUNET_break (0);
3585 break;
3586 }
3587}
3588
3589
3590/**
3591 * Callback function invoked for each interface found.
3592 * Activates/deactivates broadcast interfaces.
3593 *
3594 * @param cls NULL
3595 * @param name name of the interface (can be NULL for unknown)
3596 * @param isDefault is this presumably the default interface
3597 * @param addr address of this interface (can be NULL for unknown or unassigned)
3598 * @param broadcast_addr the broadcast address (can be NULL for unknown or
3599 * unassigned)
3600 * @param netmask the network mask (can be NULL for unknown or unassigned)
3601 * @param addrlen length of the address
3602 * @return #GNUNET_OK to continue iteration, #GNUNET_SYSERR to abort
3603 */
3604static int
3605iface_proc (void *cls,
3606 const char *name,
3607 int isDefault,
3608 const struct sockaddr *addr,
3609 const struct sockaddr *broadcast_addr,
3610 const struct sockaddr *netmask,
3611 socklen_t addrlen)
3612{
3613 struct BroadcastInterface *bi;
3614 enum GNUNET_NetworkType network;
3615 struct UdpBroadcastSignature ubs;
3616
3617 (void) cls;
3618 (void) netmask;
3619 if (NULL == addr)
3620 return GNUNET_YES; /* need to know our address! */
3621 network = GNUNET_NT_scanner_get_type (is, addr, addrlen);
3622 if (GNUNET_NT_LOOPBACK == network)
3623 {
3624 /* Broadcasting on loopback does not make sense */
3625 return GNUNET_YES;
3626 }
3627 for (bi = bi_head; NULL != bi; bi = bi->next)
3628 {
3629 if ((bi->salen == addrlen) && (0 == memcmp (addr, bi->sa, addrlen)))
3630 {
3631 bi->found = GNUNET_YES;
3632 return GNUNET_OK;
3633 }
3634 }
3635
3636 if ((AF_INET6 == addr->sa_family) && (NULL == broadcast_addr))
3637 return GNUNET_OK; /* broadcast_addr is required for IPv6! */
3638 if ((AF_INET6 == addr->sa_family) && (GNUNET_YES != have_v6_socket))
3639 return GNUNET_OK; /* not using IPv6 */
3640
3641 bi = GNUNET_new (struct BroadcastInterface);
3642 bi->sa = GNUNET_memdup (addr,
3643 addrlen);
3644 if ( (NULL != broadcast_addr) &&
3645 (addrlen == sizeof (struct sockaddr_in)) )
3646 {
3647 struct sockaddr_in *ba;
3648
3649 ba = GNUNET_memdup (broadcast_addr,
3650 addrlen);
3651 ba->sin_port = htons (2086); /* always GNUnet port, ignore configuration! */
3652 bi->ba = (struct sockaddr *) ba;
3653 }
3654 bi->salen = addrlen;
3655 bi->found = GNUNET_YES;
3656 bi->bcm.sender = my_identity;
3657 ubs.purpose.purpose = htonl (
3658 GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_UDP_BROADCAST);
3659 ubs.purpose.size = htonl (sizeof(ubs));
3660 ubs.sender = my_identity;
3661 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3662 "creating UDPBroadcastSignature for %s\n",
3663 GNUNET_a2s (addr, addrlen));
3664 GNUNET_CRYPTO_hash (addr, addrlen, &ubs.h_address);
3665 GNUNET_CRYPTO_eddsa_sign (my_private_key,
3666 &ubs,
3667 &bi->bcm.sender_sig);
3668 if (NULL != bi->ba)
3669 {
3670 bi->broadcast_task = GNUNET_SCHEDULER_add_now (&ifc_broadcast, bi);
3671 GNUNET_CONTAINER_DLL_insert (bi_head, bi_tail, bi);
3672 }
3673 if ((AF_INET6 == addr->sa_family) && (NULL != broadcast_addr))
3674 {
3675 /* Create IPv6 multicast request */
3676 const struct sockaddr_in6 *s6 =
3677 (const struct sockaddr_in6 *) broadcast_addr;
3678
3679 GNUNET_assert (
3680 1 == inet_pton (AF_INET6, "FF05::13B", &bi->mcreq.ipv6mr_multiaddr));
3681
3682 /* http://tools.ietf.org/html/rfc2553#section-5.2:
3683 *
3684 * IPV6_JOIN_GROUP
3685 *
3686 * Join a multicast group on a specified local interface. If the
3687 * interface index is specified as 0, the kernel chooses the local
3688 * interface. For example, some kernels look up the multicast
3689 * group in the normal IPv6 routing table and using the resulting
3690 * interface; we do this for each interface, so no need to use
3691 * zero (anymore...).
3692 */bi->mcreq.ipv6mr_interface = s6->sin6_scope_id;
3693
3694 /* Join the multicast group */
3695 if (GNUNET_OK != GNUNET_NETWORK_socket_setsockopt (udp_sock,
3696 IPPROTO_IPV6,
3697 IPV6_JOIN_GROUP,
3698 &bi->mcreq,
3699 sizeof(bi->mcreq)))
3700 {
3701 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "setsockopt");
3702 }
3703 }
3704 return GNUNET_OK;
3705}
3706
3707
3708/**
3709 * Scan interfaces to broadcast our presence on the LAN.
3710 *
3711 * @param cls NULL, unused
3712 */
3713static void
3714do_broadcast (void *cls)
3715{
3716 struct BroadcastInterface *bin;
3717
3718 (void) cls;
3719 for (struct BroadcastInterface *bi = bi_head; NULL != bi; bi = bi->next)
3720 bi->found = GNUNET_NO;
3721 GNUNET_OS_network_interfaces_list (&iface_proc, NULL);
3722 for (struct BroadcastInterface *bi = bi_head; NULL != bi; bi = bin)
3723 {
3724 bin = bi->next;
3725 if (GNUNET_NO == bi->found)
3726 bi_destroy (bi);
3727 }
3728 broadcast_task = GNUNET_SCHEDULER_add_delayed (INTERFACE_SCAN_FREQUENCY,
3729 &do_broadcast,
3730 NULL);
3731}
3732
3733
3734/**
3735 * Setup communicator and launch network interactions.
3736 *
3737 * @param cls NULL (always)
3738 * @param args remaining command-line arguments
3739 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
3740 * @param c configuration
3741 */
3742static void
3743run (void *cls,
3744 char *const *args,
3745 const char *cfgfile,
3746 const struct GNUNET_CONFIGURATION_Handle *c)
3747{
3748 char *bindto;
3749 struct sockaddr *in;
3750 socklen_t in_len;
3751 struct sockaddr_storage in_sto;
3752 socklen_t sto_len;
3753
3754 (void) cls;
3755 cfg = c;
3756 if (GNUNET_OK !=
3757 GNUNET_CONFIGURATION_get_value_string (cfg,
3758 COMMUNICATOR_CONFIG_SECTION,
3759 "BINDTO",
3760 &bindto))
3761 {
3762 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
3763 COMMUNICATOR_CONFIG_SECTION,
3764 "BINDTO");
3765 return;
3766 }
3767
3768 if (GNUNET_OK !=
3769 GNUNET_CONFIGURATION_get_value_time (cfg,
3770 COMMUNICATOR_CONFIG_SECTION,
3771 "REKEY_INTERVAL",
3772 &rekey_interval))
3773 rekey_interval = DEFAULT_REKEY_TIME_INTERVAL;
3774
3775 if (GNUNET_OK !=
3776 GNUNET_CONFIGURATION_get_value_size (cfg,
3777 COMMUNICATOR_CONFIG_SECTION,
3778 "REKEY_MAX_BYTES",
3779 &rekey_max_bytes))
3780 rekey_max_bytes = DEFAULT_REKEY_MAX_BYTES;
3781
3782 in = udp_address_to_sockaddr (bindto, &in_len);
3783 if (NULL == in)
3784 {
3785 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3786 "Failed to setup UDP socket address with path `%s'\n",
3787 bindto);
3788 GNUNET_free (bindto);
3789 return;
3790 }
3791 udp_sock =
3792 GNUNET_NETWORK_socket_create (in->sa_family,
3793 SOCK_DGRAM,
3794 IPPROTO_UDP);
3795 if (NULL == udp_sock)
3796 {
3797 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
3798 GNUNET_free (in);
3799 GNUNET_free (bindto);
3800 return;
3801 }
3802 if (AF_INET6 == in->sa_family)
3803 have_v6_socket = GNUNET_YES;
3804 if (GNUNET_OK !=
3805 GNUNET_NETWORK_socket_bind (udp_sock,
3806 in,
3807 in_len))
3808 {
3809 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
3810 "bind",
3811 bindto);
3812 GNUNET_NETWORK_socket_close (udp_sock);
3813 udp_sock = NULL;
3814 GNUNET_free (in);
3815 GNUNET_free (bindto);
3816 return;
3817 }
3818
3819 /* We might have bound to port 0, allowing the OS to figure it out;
3820 thus, get the real IN-address from the socket */
3821 sto_len = sizeof(in_sto);
3822 if (0 != getsockname (GNUNET_NETWORK_get_fd (udp_sock),
3823 (struct sockaddr *) &in_sto,
3824 &sto_len))
3825 {
3826 memcpy (&in_sto, in, in_len);
3827 sto_len = in_len;
3828 }
3829 GNUNET_free (in);
3830 GNUNET_free (bindto);
3831 in = (struct sockaddr *) &in_sto;
3832 in_len = sto_len;
3833 GNUNET_log_from_nocheck (GNUNET_ERROR_TYPE_DEBUG,
3834 "transport",
3835 "Bound to `%s'\n",
3836 GNUNET_a2s ((const struct sockaddr *) &in_sto,
3837 sto_len));
3838 switch (in->sa_family)
3839 {
3840 case AF_INET:
3841 my_port = ntohs (((struct sockaddr_in *) in)->sin_port);
3842 break;
3843
3844 case AF_INET6:
3845 my_port = ntohs (((struct sockaddr_in6 *) in)->sin6_port);
3846 break;
3847
3848 default:
3849 GNUNET_break (0);
3850 my_port = 0;
3851 }
3852 stats = GNUNET_STATISTICS_create ("C-UDP", cfg);
3853 senders = GNUNET_CONTAINER_multipeermap_create (32, GNUNET_YES);
3854 receivers = GNUNET_CONTAINER_multipeermap_create (32, GNUNET_YES);
3855 senders_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3856 receivers_heap =
3857 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3858 key_cache = GNUNET_CONTAINER_multishortmap_create (1024, GNUNET_YES);
3859 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
3860 is = GNUNET_NT_scanner_init ();
3861 my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg);
3862 if (NULL == my_private_key)
3863 {
3864 GNUNET_log (
3865 GNUNET_ERROR_TYPE_ERROR,
3866 _ (
3867 "Transport service is lacking key configuration settings. Exiting.\n"));
3868 GNUNET_SCHEDULER_shutdown ();
3869 return;
3870 }
3871 GNUNET_CRYPTO_eddsa_key_get_public (my_private_key, &my_identity.public_key);
3872 /* start reading */
3873 read_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
3874 udp_sock,
3875 &sock_read,
3876 NULL);
3877 ch = GNUNET_TRANSPORT_communicator_connect (cfg,
3878 COMMUNICATOR_CONFIG_SECTION,
3879 COMMUNICATOR_ADDRESS_PREFIX,
3880 GNUNET_TRANSPORT_CC_UNRELIABLE,
3881 &mq_init,
3882 NULL,
3883 &enc_notify_cb,
3884 NULL);
3885 if (NULL == ch)
3886 {
3887 GNUNET_break (0);
3888 GNUNET_SCHEDULER_shutdown ();
3889 return;
3890 }
3891 ah = GNUNET_TRANSPORT_application_init (cfg);
3892 if (NULL == ah)
3893 {
3894 GNUNET_break (0);
3895 GNUNET_SCHEDULER_shutdown ();
3896 return;
3897 }
3898 /* start broadcasting */
3899 if (GNUNET_YES !=
3900 GNUNET_CONFIGURATION_get_value_yesno (cfg,
3901 COMMUNICATOR_CONFIG_SECTION,
3902 "DISABLE_BROADCAST"))
3903 {
3904 broadcast_task = GNUNET_SCHEDULER_add_now (&do_broadcast, NULL);
3905 }
3906 nat = GNUNET_NAT_register (cfg,
3907 COMMUNICATOR_CONFIG_SECTION,
3908 IPPROTO_UDP,
3909 1 /* one address */,
3910 (const struct sockaddr **) &in,
3911 &in_len,
3912 &nat_address_cb,
3913 NULL /* FIXME: support reversal: #5529 */,
3914 NULL /* closure */);
3915}
3916
3917
3918/**
3919 * The main function for the UNIX communicator.
3920 *
3921 * @param argc number of arguments from the command line
3922 * @param argv command line arguments
3923 * @return 0 ok, 1 on error
3924 */
3925int
3926main (int argc, char *const *argv)
3927{
3928 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
3929 GNUNET_GETOPT_OPTION_END
3930 };
3931 int ret;
3932
3933 GNUNET_log_from_nocheck (GNUNET_ERROR_TYPE_DEBUG,
3934 "transport",
3935 "Starting udp communicator\n");
3936 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
3937 return 2;
3938
3939 ret = (GNUNET_OK == GNUNET_PROGRAM_run (argc,
3940 argv,
3941 "gnunet-communicator-udp",
3942 _ ("GNUnet UDP communicator"),
3943 options,
3944 &run,
3945 NULL))
3946 ? 0
3947 : 1;
3948 GNUNET_free_nz ((void *) argv);
3949 return ret;
3950}
3951
3952
3953/* end of gnunet-communicator-udp.c */
diff --git a/src/transport/gnunet-communicator-unix.c b/src/transport/gnunet-communicator-unix.c
deleted file mode 100644
index d7e18f87a..000000000
--- a/src/transport/gnunet-communicator-unix.c
+++ /dev/null
@@ -1,1167 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2010-2014, 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/**
22 * @file transport/gnunet-communicator-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_protocols.h"
32#include "gnunet_constants.h"
33#include "gnunet_nt_lib.h"
34#include "gnunet_statistics_service.h"
35#include "gnunet_transport_communication_service.h"
36
37/**
38 * How many messages do we keep at most in the queue to the
39 * transport service before we start to drop (default,
40 * can be changed via the configuration file).
41 * Should be _below_ the level of the communicator API, as
42 * otherwise we may read messages just to have them dropped
43 * by the communicator API.
44 */
45#define DEFAULT_MAX_QUEUE_LENGTH 8000
46
47/**
48 * Address prefix used by the communicator.
49 */
50#define COMMUNICATOR_ADDRESS_PREFIX "unix"
51
52/**
53 * Configuration section used by the communicator.
54 */
55#define COMMUNICATOR_CONFIG_SECTION "communicator-unix"
56
57/**
58 * Our MTU.
59 */
60#ifndef DARWIN
61#define UNIX_MTU UINT16_MAX
62#else
63#define UNIX_MTU 2048
64#endif
65
66GNUNET_NETWORK_STRUCT_BEGIN
67
68/**
69 * UNIX Message-Packet header.
70 */
71struct UNIXMessage
72{
73 /**
74 * Message header.
75 */
76 struct GNUNET_MessageHeader header;
77
78 /**
79 * What is the identity of the sender (GNUNET_hash of public key)
80 */
81 struct GNUNET_PeerIdentity sender;
82};
83
84GNUNET_NETWORK_STRUCT_END
85
86
87/**
88 * Handle for a queue.
89 */
90struct Queue
91{
92 /**
93 * Queues with pending messages (!) are kept in a DLL.
94 */
95 struct Queue *next;
96
97 /**
98 * Queues with pending messages (!) are kept in a DLL.
99 */
100 struct Queue *prev;
101
102 /**
103 * To whom are we talking to.
104 */
105 struct GNUNET_PeerIdentity target;
106
107 /**
108 * Address of the other peer.
109 */
110 struct sockaddr_un *address;
111
112 /**
113 * Length of the address.
114 */
115 socklen_t address_len;
116
117 /**
118 * Message currently scheduled for transmission, non-NULL if and only
119 * if this queue is in the #queue_head DLL.
120 */
121 struct UNIXMessage *msg;
122
123 /**
124 * Message queue we are providing for the #ch.
125 */
126 struct GNUNET_MQ_Handle *mq;
127
128 /**
129 * handle for this queue with the #ch.
130 */
131 struct GNUNET_TRANSPORT_QueueHandle *qh;
132
133 /**
134 * Number of bytes we currently have in our write queue.
135 */
136 unsigned long long bytes_in_queue;
137
138 /**
139 * Timeout for this queue.
140 */
141 struct GNUNET_TIME_Absolute timeout;
142
143 /**
144 * Queue timeout task.
145 */
146 struct GNUNET_SCHEDULER_Task *timeout_task;
147};
148
149/**
150 * My Peer Identity
151 */
152static struct GNUNET_PeerIdentity my_identity;
153
154/**
155 * ID of read task
156 */
157static struct GNUNET_SCHEDULER_Task *read_task;
158
159/**
160 * ID of write task
161 */
162static struct GNUNET_SCHEDULER_Task *write_task;
163
164/**
165 * Number of messages we currently have in our queues towards the transport service.
166 */
167static unsigned long long delivering_messages;
168
169/**
170 * Maximum queue length before we stop reading towards the transport service.
171 */
172static unsigned long long max_queue_length;
173
174/**
175 * For logging statistics.
176 */
177static struct GNUNET_STATISTICS_Handle *stats;
178
179/**
180 * Our environment.
181 */
182static struct GNUNET_TRANSPORT_CommunicatorHandle *ch;
183
184/**
185 * Queues (map from peer identity to `struct Queue`)
186 */
187static struct GNUNET_CONTAINER_MultiPeerMap *queue_map;
188
189/**
190 * Head of queue of messages to transmit.
191 */
192static struct Queue *queue_head;
193
194/**
195 * Tail of queue of messages to transmit.
196 */
197static struct Queue *queue_tail;
198
199/**
200 * socket that we transmit all data with
201 */
202static struct GNUNET_NETWORK_Handle *unix_sock;
203
204/**
205 * Handle to the operation that publishes our address.
206 */
207static struct GNUNET_TRANSPORT_AddressIdentifier *ai;
208
209
210/**
211 * Functions with this signature are called whenever we need
212 * to close a queue due to a disconnect or failure to
213 * establish a connection.
214 *
215 * @param queue queue to close down
216 */
217static void
218queue_destroy (struct Queue *queue)
219{
220 struct GNUNET_MQ_Handle *mq;
221
222 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
223 "Disconnecting queue for peer `%s'\n",
224 GNUNET_i2s (&queue->target));
225 if (0 != queue->bytes_in_queue)
226 {
227 GNUNET_CONTAINER_DLL_remove (queue_head, queue_tail, queue);
228 queue->bytes_in_queue = 0;
229 }
230 if (NULL != (mq = queue->mq))
231 {
232 queue->mq = NULL;
233 GNUNET_MQ_destroy (mq);
234 }
235 GNUNET_assert (
236 GNUNET_YES ==
237 GNUNET_CONTAINER_multipeermap_remove (queue_map, &queue->target, queue));
238 GNUNET_STATISTICS_set (stats,
239 "# queues active",
240 GNUNET_CONTAINER_multipeermap_size (queue_map),
241 GNUNET_NO);
242 if (NULL != queue->timeout_task)
243 {
244 GNUNET_SCHEDULER_cancel (queue->timeout_task);
245 queue->timeout_task = NULL;
246 }
247 GNUNET_free (queue->address);
248 GNUNET_free (queue);
249}
250
251
252/**
253 * Queue was idle for too long, so disconnect it
254 *
255 * @param cls the `struct Queue *` to disconnect
256 */
257static void
258queue_timeout (void *cls)
259{
260 struct Queue *queue = cls;
261 struct GNUNET_TIME_Relative left;
262
263 queue->timeout_task = NULL;
264 left = GNUNET_TIME_absolute_get_remaining (queue->timeout);
265 if (0 != left.rel_value_us)
266 {
267 /* not actually our turn yet, but let's at least update
268 the monitor, it may think we're about to die ... */
269 queue->timeout_task =
270 GNUNET_SCHEDULER_add_delayed (left, &queue_timeout, queue);
271 return;
272 }
273 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
274 "Queue %p was idle for %s, disconnecting\n",
275 queue,
276 GNUNET_STRINGS_relative_time_to_string (
277 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
278 GNUNET_YES));
279 queue_destroy (queue);
280}
281
282
283/**
284 * Increment queue timeout due to activity. We do not immediately
285 * notify the monitor here as that might generate excessive
286 * signalling.
287 *
288 * @param queue queue for which the timeout should be rescheduled
289 */
290static void
291reschedule_queue_timeout (struct Queue *queue)
292{
293 GNUNET_assert (NULL != queue->timeout_task);
294 queue->timeout =
295 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
296}
297
298
299/**
300 * Convert unix path to a `struct sockaddr_un *`
301 *
302 * @param unixpath path to convert
303 * @param[out] sock_len set to the length of the address
304 * @param is_abstract is this an abstract @a unixpath
305 * @return converted unix path
306 */
307static struct sockaddr_un *
308unix_address_to_sockaddr (const char *unixpath, socklen_t *sock_len)
309{
310 struct sockaddr_un *un;
311 size_t slen;
312
313 GNUNET_assert (0 < strlen (unixpath)); /* sanity check */
314 un = GNUNET_new (struct sockaddr_un);
315 un->sun_family = AF_UNIX;
316 slen = strlen (unixpath);
317 if (slen >= sizeof(un->sun_path))
318 slen = sizeof(un->sun_path) - 1;
319 GNUNET_memcpy (un->sun_path, unixpath, slen);
320 un->sun_path[slen] = '\0';
321 slen = sizeof(struct sockaddr_un);
322#if HAVE_SOCKADDR_UN_SUN_LEN
323 un->sun_len = (u_char) slen;
324#endif
325 (*sock_len) = slen;
326 if ('@' == un->sun_path[0])
327 un->sun_path[0] = '\0';
328 return un;
329}
330
331
332/**
333 * Closure to #lookup_queue_it().
334 */
335struct LookupCtx
336{
337 /**
338 * Location to store the queue, if found.
339 */
340 struct Queue *res;
341
342 /**
343 * Address we are looking for.
344 */
345 const struct sockaddr_un *un;
346
347 /**
348 * Number of bytes in @a un
349 */
350 socklen_t un_len;
351};
352
353
354/**
355 * Function called to find a queue by address.
356 *
357 * @param cls the `struct LookupCtx *`
358 * @param key peer we are looking for (unused)
359 * @param value a queue
360 * @return #GNUNET_YES if not found (continue looking), #GNUNET_NO on success
361 */
362static int
363lookup_queue_it (void *cls, const struct GNUNET_PeerIdentity *key, void *value)
364{
365 struct LookupCtx *lctx = cls;
366 struct Queue *queue = value;
367
368 if ((queue->address_len == lctx->un_len) &&
369 (0 == memcmp (lctx->un, queue->address, queue->address_len)))
370 {
371 lctx->res = queue;
372 return GNUNET_NO;
373 }
374 return GNUNET_YES;
375}
376
377
378/**
379 * Find an existing queue by address.
380 *
381 * @param plugin the plugin
382 * @param address the address to find
383 * @return NULL if queue was not found
384 */
385static struct Queue *
386lookup_queue (const struct GNUNET_PeerIdentity *peer,
387 const struct sockaddr_un *un,
388 socklen_t un_len)
389{
390 struct LookupCtx lctx;
391
392 lctx.un = un;
393 lctx.un_len = un_len;
394 lctx.res = NULL;
395 GNUNET_CONTAINER_multipeermap_get_multiple (queue_map,
396 peer,
397 &lookup_queue_it,
398 &lctx);
399 return lctx.res;
400}
401
402
403/**
404 * We have been notified that our socket is ready to write.
405 * Then reschedule this function to be called again once more is available.
406 *
407 * @param cls NULL
408 */
409static void
410select_write_cb (void *cls)
411{
412 struct Queue *queue = queue_tail;
413 const struct GNUNET_MessageHeader *msg = &queue->msg->header;
414 size_t msg_size = ntohs (msg->size);
415 ssize_t sent;
416
417 /* take queue of the ready list */
418 write_task = NULL;
419resend:
420 /* Send the data */
421 sent = GNUNET_NETWORK_socket_sendto (unix_sock,
422 msg,
423 msg_size,
424 (const struct sockaddr *) queue->address,
425 queue->address_len);
426 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
427 "UNIX transmitted message to %s (%d/%u: %s)\n",
428 GNUNET_i2s (&queue->target),
429 (int) sent,
430 (unsigned int) msg_size,
431 (sent < 0) ? strerror (errno) : "ok");
432 if (-1 != sent)
433 {
434 GNUNET_CONTAINER_DLL_remove (queue_head, queue_tail, queue);
435 if (NULL != queue_head)
436 write_task = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
437 unix_sock,
438 &select_write_cb,
439 NULL);
440
441 /* send 'msg' */
442 GNUNET_free (queue->msg);
443 queue->msg = NULL;
444 GNUNET_MQ_impl_send_continue (queue->mq);
445 GNUNET_STATISTICS_update (stats,
446 "# bytes sent",
447 (long long) sent,
448 GNUNET_NO);
449 reschedule_queue_timeout (queue);
450 return; /* all good */
451 }
452 GNUNET_STATISTICS_update (stats,
453 "# network transmission failures",
454 1,
455 GNUNET_NO);
456 write_task = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
457 unix_sock,
458 &select_write_cb,
459 NULL);
460 switch (errno)
461 {
462 case EAGAIN:
463 case ENOBUFS:
464 /* We should retry later... */
465 GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "send");
466 return;
467
468 case EMSGSIZE: {
469 socklen_t size = 0;
470 socklen_t len = sizeof(size);
471
472 GNUNET_NETWORK_socket_getsockopt (unix_sock,
473 SOL_SOCKET,
474 SO_SNDBUF,
475 &size,
476 &len);
477 if (size > ntohs (msg->size))
478 {
479 /* Buffer is bigger than message: error, no retry
480 * This should never happen!*/
481 GNUNET_break (0);
482 return;
483 }
484 GNUNET_log (
485 GNUNET_ERROR_TYPE_WARNING,
486 "Trying to increase socket buffer size from %u to %u for message size %u\n",
487 (unsigned int) size,
488 (unsigned int) ((msg_size / 1000) + 2) * 1000,
489 (unsigned int) msg_size);
490 size = ((msg_size / 1000) + 2) * 1000;
491 if (GNUNET_OK == GNUNET_NETWORK_socket_setsockopt (unix_sock,
492 SOL_SOCKET,
493 SO_SNDBUF,
494 &size,
495 sizeof(size)))
496 goto resend; /* Increased buffer size, retry sending */
497 /* Ok, then just try very modest increase */
498 size = msg_size;
499 if (GNUNET_OK == GNUNET_NETWORK_socket_setsockopt (unix_sock,
500 SOL_SOCKET,
501 SO_SNDBUF,
502 &size,
503 sizeof(size)))
504 goto resend; /* Increased buffer size, retry sending */
505 /* Could not increase buffer size: error, no retry */
506 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "setsockopt");
507 return;
508 }
509
510 default:
511 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "send");
512 return;
513 }
514}
515
516
517/**
518 * Signature of functions implementing the sending functionality of a
519 * message queue.
520 *
521 * @param mq the message queue
522 * @param msg the message to send
523 * @param impl_state our `struct Queue`
524 */
525static void
526mq_send (struct GNUNET_MQ_Handle *mq,
527 const struct GNUNET_MessageHeader *msg,
528 void *impl_state)
529{
530 struct Queue *queue = impl_state;
531 size_t msize = ntohs (msg->size);
532
533 GNUNET_assert (mq == queue->mq);
534 GNUNET_assert (NULL == queue->msg);
535 // Convert to UNIXMessage
536 queue->msg = GNUNET_malloc (msize + sizeof (struct UNIXMessage));
537 queue->msg->header.size = htons (msize + sizeof (struct UNIXMessage));
538 queue->msg->sender = my_identity;
539 memcpy (&queue->msg[1], msg, msize);
540 GNUNET_CONTAINER_DLL_insert (queue_head, queue_tail, queue);
541 GNUNET_assert (NULL != unix_sock);
542 if (NULL == write_task)
543 write_task = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
544 unix_sock,
545 &select_write_cb,
546 NULL);
547}
548
549
550/**
551 * Signature of functions implementing the destruction of a message
552 * queue. Implementations must not free @a mq, but should take care
553 * of @a impl_state.
554 *
555 * @param mq the message queue to destroy
556 * @param impl_state our `struct Queue`
557 */
558static void
559mq_destroy (struct GNUNET_MQ_Handle *mq, void *impl_state)
560{
561 struct Queue *queue = impl_state;
562
563 if (mq == queue->mq)
564 {
565 queue->mq = NULL;
566 queue_destroy (queue);
567 }
568}
569
570
571/**
572 * Implementation function that cancels the currently sent message.
573 *
574 * @param mq message queue
575 * @param impl_state our `struct Queue`
576 */
577static void
578mq_cancel (struct GNUNET_MQ_Handle *mq, void *impl_state)
579{
580 struct Queue *queue = impl_state;
581
582 GNUNET_assert (NULL != queue->msg);
583 queue->msg = NULL;
584 GNUNET_CONTAINER_DLL_remove (queue_head, queue_tail, queue);
585 GNUNET_assert (NULL != write_task);
586 if (NULL == queue_head)
587 {
588 GNUNET_SCHEDULER_cancel (write_task);
589 write_task = NULL;
590 }
591}
592
593
594/**
595 * Generic error handler, called with the appropriate
596 * error code and the same closure specified at the creation of
597 * the message queue.
598 * Not every message queue implementation supports an error handler.
599 *
600 * @param cls our `struct Queue`
601 * @param error error code
602 */
603static void
604mq_error (void *cls, enum GNUNET_MQ_Error error)
605{
606 struct Queue *queue = cls;
607
608 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
609 "UNIX MQ error in queue to %s: %d\n",
610 GNUNET_i2s (&queue->target),
611 (int) error);
612 queue_destroy (queue);
613}
614
615
616/**
617 * Creates a new outbound queue the transport service will use to send
618 * data to another peer.
619 *
620 * @param peer the target peer
621 * @param cs inbound or outbound queue
622 * @param un the address
623 * @param un_len number of bytes in @a un
624 * @return the queue or NULL of max connections exceeded
625 */
626static struct Queue *
627setup_queue (const struct GNUNET_PeerIdentity *target,
628 enum GNUNET_TRANSPORT_ConnectionStatus cs,
629 const struct sockaddr_un *un,
630 socklen_t un_len)
631{
632 struct Queue *queue;
633
634 queue = GNUNET_new (struct Queue);
635 queue->target = *target;
636 queue->address = GNUNET_memdup (un, un_len);
637 queue->address_len = un_len;
638 (void) GNUNET_CONTAINER_multipeermap_put (
639 queue_map,
640 &queue->target,
641 queue,
642 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
643 GNUNET_STATISTICS_set (stats,
644 "# queues active",
645 GNUNET_CONTAINER_multipeermap_size (queue_map),
646 GNUNET_NO);
647 queue->timeout =
648 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
649 queue->timeout_task =
650 GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
651 &queue_timeout,
652 queue);
653 queue->mq = GNUNET_MQ_queue_for_callbacks (&mq_send,
654 &mq_destroy,
655 &mq_cancel,
656 queue,
657 NULL,
658 &mq_error,
659 queue);
660 {
661 char *foreign_addr;
662
663 if ('\0' == un->sun_path[0])
664 GNUNET_asprintf (&foreign_addr,
665 "%s-@%s",
666 COMMUNICATOR_ADDRESS_PREFIX,
667 &un->sun_path[1]);
668 else
669 GNUNET_asprintf (&foreign_addr,
670 "%s-%s",
671 COMMUNICATOR_ADDRESS_PREFIX,
672 un->sun_path);
673 queue->qh = GNUNET_TRANSPORT_communicator_mq_add (ch,
674 &queue->target,
675 foreign_addr,
676 UNIX_MTU - sizeof (struct
677 UNIXMessage),
678 GNUNET_TRANSPORT_QUEUE_LENGTH_UNLIMITED,
679 0,
680 GNUNET_NT_LOOPBACK,
681 cs,
682 queue->mq);
683 GNUNET_free (foreign_addr);
684 }
685 return queue;
686}
687
688
689/**
690 * We have been notified that our socket has something to read. Do the
691 * read and reschedule this function to be called again once more is
692 * available.
693 *
694 * @param cls NULL
695 */
696static void
697select_read_cb (void *cls);
698
699
700/**
701 * Function called when message was successfully passed to
702 * transport service. Continue read activity.
703 *
704 * @param cls NULL
705 * @param success #GNUNET_OK on success
706 */
707static void
708receive_complete_cb (void *cls, int success)
709{
710 (void) cls;
711 delivering_messages--;
712 if (GNUNET_OK != success)
713 GNUNET_STATISTICS_update (stats,
714 "# transport transmission failures",
715 1,
716 GNUNET_NO);
717 if ((NULL == read_task) && (delivering_messages < max_queue_length) &&
718 (NULL != unix_sock))
719 read_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
720 unix_sock,
721 &select_read_cb,
722 NULL);
723}
724
725
726/**
727 * We have been notified that our socket has something to read. Do the
728 * read and reschedule this function to be called again once more is
729 * available.
730 *
731 * @param cls NULL
732 */
733static void
734select_read_cb (void *cls)
735{
736 char buf[65536] GNUNET_ALIGN;
737 struct Queue *queue;
738 const struct UNIXMessage *msg;
739 struct sockaddr_un un;
740 socklen_t addrlen;
741 ssize_t ret;
742 uint16_t msize;
743
744 GNUNET_assert (NULL != unix_sock);
745 read_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
746 unix_sock,
747 &select_read_cb,
748 NULL);
749 addrlen = sizeof(un);
750 memset (&un, 0, sizeof(un));
751 ret = GNUNET_NETWORK_socket_recvfrom (unix_sock,
752 buf,
753 sizeof(buf),
754 (struct sockaddr *) &un,
755 &addrlen);
756 if ((-1 == ret) && ((EAGAIN == errno) || (ENOBUFS == errno)))
757 return;
758 if (-1 == ret)
759 {
760 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "recvfrom");
761 return;
762 }
763 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
764 "Read %d bytes from socket %s\n",
765 (int) ret,
766 un.sun_path);
767 GNUNET_assert (AF_UNIX == (un.sun_family));
768 msg = (struct UNIXMessage *) buf;
769 msize = ntohs (msg->header.size);
770 if ((msize < sizeof(struct UNIXMessage)) || (msize > ret))
771 {
772 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
773 "Wrong message size: %d bytes\n",
774 msize);
775 GNUNET_break_op (0);
776 return;
777 }
778 queue = lookup_queue (&msg->sender, &un, addrlen);
779 if (NULL == queue)
780 queue =
781 setup_queue (&msg->sender, GNUNET_TRANSPORT_CS_INBOUND, &un, addrlen);
782 else
783 reschedule_queue_timeout (queue);
784 if (NULL == queue)
785 {
786 GNUNET_log (
787 GNUNET_ERROR_TYPE_ERROR,
788 _ (
789 "Maximum number of UNIX connections exceeded, dropping incoming message\n"));
790 return;
791 }
792
793 {
794 uint16_t tsize = msize - sizeof(struct UNIXMessage);
795
796 const struct GNUNET_MessageHeader *currhdr;
797 struct GNUNET_MessageHeader al_hdr;
798
799 currhdr = (const struct GNUNET_MessageHeader *) &msg[1];
800 /* ensure aligned access */
801 memcpy (&al_hdr, currhdr, sizeof(al_hdr));
802 if ((tsize < sizeof(struct GNUNET_MessageHeader)) ||
803 (tsize != ntohs (al_hdr.size)))
804 {
805 GNUNET_break_op (0);
806 return;
807 }
808 ret = GNUNET_TRANSPORT_communicator_receive (ch,
809 &msg->sender,
810 currhdr,
811 GNUNET_TIME_UNIT_FOREVER_REL,
812 &receive_complete_cb,
813 NULL);
814 if (GNUNET_SYSERR == ret)
815 {
816 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
817 "Transport not up!\n");
818 return; /* transport not up */
819 }
820 if (GNUNET_NO == ret)
821 {
822 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
823 "Error sending message to transport\n");
824 return;
825 }
826 delivering_messages++;
827 }
828 if (delivering_messages >= max_queue_length)
829 {
830 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
831 "Back pressure %llu\n", delivering_messages);
832
833 /* we should try to apply 'back pressure' */
834 GNUNET_SCHEDULER_cancel (read_task);
835 read_task = NULL;
836 }
837}
838
839
840/**
841 * Function called by the transport service to initialize a
842 * message queue given address information about another peer.
843 * If and when the communication channel is established, the
844 * communicator must call #GNUNET_TRANSPORT_communicator_mq_add()
845 * to notify the service that the channel is now up. It is
846 * the responsibility of the communicator to manage sane
847 * retries and timeouts for any @a peer/@a address combination
848 * provided by the transport service. Timeouts and retries
849 * do not need to be signalled to the transport service.
850 *
851 * @param cls closure
852 * @param peer identity of the other peer
853 * @param address where to send the message, human-readable
854 * communicator-specific format, 0-terminated, UTF-8
855 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the provided address is invalid
856 */
857static int
858mq_init (void *cls, const struct GNUNET_PeerIdentity *peer, const char *address)
859{
860 struct Queue *queue;
861 const char *path;
862 struct sockaddr_un *un;
863 socklen_t un_len;
864
865 (void) cls;
866 if (0 != strncmp (address,
867 COMMUNICATOR_ADDRESS_PREFIX "-",
868 strlen (COMMUNICATOR_ADDRESS_PREFIX "-")))
869 {
870 GNUNET_break_op (0);
871 return GNUNET_SYSERR;
872 }
873 path = &address[strlen (COMMUNICATOR_ADDRESS_PREFIX "-")];
874 un = unix_address_to_sockaddr (path, &un_len);
875 queue = lookup_queue (peer, un, un_len);
876 if (NULL != queue)
877 {
878 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
879 "Address `%s' for %s ignored, queue exists\n",
880 path,
881 GNUNET_i2s (peer));
882 GNUNET_free (un);
883 return GNUNET_OK;
884 }
885 queue = setup_queue (peer, GNUNET_TRANSPORT_CS_OUTBOUND, un, un_len);
886 GNUNET_free (un);
887 if (NULL == queue)
888 {
889 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
890 "Failed to setup queue to %s at `%s'\n",
891 GNUNET_i2s (peer),
892 path);
893 return GNUNET_NO;
894 }
895 return GNUNET_OK;
896}
897
898
899/**
900 * Iterator over all message queues to clean up.
901 *
902 * @param cls NULL
903 * @param target unused
904 * @param value the queue to destroy
905 * @return #GNUNET_OK to continue to iterate
906 */
907static int
908get_queue_delete_it (void *cls,
909 const struct GNUNET_PeerIdentity *target,
910 void *value)
911{
912 struct Queue *queue = value;
913
914 (void) cls;
915 (void) target;
916 queue_destroy (queue);
917 return GNUNET_OK;
918}
919
920
921/**
922 * Shutdown the UNIX communicator.
923 *
924 * @param cls NULL (always)
925 */
926static void
927do_shutdown (void *cls)
928{
929 if (NULL != read_task)
930 {
931 GNUNET_SCHEDULER_cancel (read_task);
932 read_task = NULL;
933 }
934 if (NULL != write_task)
935 {
936 GNUNET_SCHEDULER_cancel (write_task);
937 write_task = NULL;
938 }
939 if (NULL != unix_sock)
940 {
941 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (unix_sock));
942 unix_sock = NULL;
943 }
944 GNUNET_CONTAINER_multipeermap_iterate (queue_map, &get_queue_delete_it, NULL);
945 GNUNET_CONTAINER_multipeermap_destroy (queue_map);
946 if (NULL != ai)
947 {
948 GNUNET_TRANSPORT_communicator_address_remove (ai);
949 ai = NULL;
950 }
951 if (NULL != ch)
952 {
953 GNUNET_TRANSPORT_communicator_disconnect (ch);
954 ch = NULL;
955 }
956 if (NULL != stats)
957 {
958 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
959 stats = NULL;
960 }
961}
962
963
964/**
965 * Function called when the transport service has received an
966 * acknowledgement for this communicator (!) via a different return
967 * path.
968 *
969 * Not applicable for UNIX.
970 *
971 * @param cls closure
972 * @param sender which peer sent the notification
973 * @param msg payload
974 */
975static void
976enc_notify_cb (void *cls,
977 const struct GNUNET_PeerIdentity *sender,
978 const struct GNUNET_MessageHeader *msg)
979{
980 (void) cls;
981 (void) sender;
982 (void) msg;
983 GNUNET_break_op (0);
984}
985
986
987/**
988 * Setup communicator and launch network interactions.
989 *
990 * @param cls NULL (always)
991 * @param args remaining command-line arguments
992 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
993 * @param cfg configuration
994 */
995static void
996run (void *cls,
997 char *const *args,
998 const char *cfgfile,
999 const struct GNUNET_CONFIGURATION_Handle *cfg)
1000{
1001 char *unix_socket_path;
1002 struct sockaddr_un *un;
1003 socklen_t un_len;
1004 char *my_addr;
1005 struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
1006
1007 (void) cls;
1008 delivering_messages = 0;
1009
1010 my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg);
1011 if (NULL == my_private_key)
1012 {
1013 GNUNET_log (
1014 GNUNET_ERROR_TYPE_ERROR,
1015 _ (
1016 "UNIX communicator is lacking key configuration settings. Exiting.\n"));
1017 GNUNET_SCHEDULER_shutdown ();
1018 return;
1019 }
1020 GNUNET_CRYPTO_eddsa_key_get_public (my_private_key, &my_identity.public_key);
1021
1022 if (GNUNET_OK !=
1023 GNUNET_CONFIGURATION_get_value_filename (cfg,
1024 COMMUNICATOR_CONFIG_SECTION,
1025 "UNIXPATH",
1026 &unix_socket_path))
1027 {
1028 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
1029 COMMUNICATOR_CONFIG_SECTION,
1030 "UNIXPATH");
1031 return;
1032 }
1033 if (GNUNET_OK !=
1034 GNUNET_CONFIGURATION_get_value_number (cfg,
1035 COMMUNICATOR_CONFIG_SECTION,
1036 "MAX_QUEUE_LENGTH",
1037 &max_queue_length))
1038 max_queue_length = DEFAULT_MAX_QUEUE_LENGTH;
1039
1040 un = unix_address_to_sockaddr (unix_socket_path, &un_len);
1041 if (NULL == un)
1042 {
1043 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1044 "Failed to setup UNIX domain socket address with path `%s'\n",
1045 unix_socket_path);
1046 GNUNET_free (unix_socket_path);
1047 return;
1048 }
1049 unix_sock = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_DGRAM, 0);
1050 if (NULL == unix_sock)
1051 {
1052 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
1053 GNUNET_free (un);
1054 GNUNET_free (unix_socket_path);
1055 return;
1056 }
1057 if (('\0' != un->sun_path[0]) &&
1058 (GNUNET_OK != GNUNET_DISK_directory_create_for_file (un->sun_path)))
1059 {
1060 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1061 _ ("Cannot create path to `%s'\n"),
1062 un->sun_path);
1063 GNUNET_NETWORK_socket_close (unix_sock);
1064 unix_sock = NULL;
1065 GNUNET_free (un);
1066 GNUNET_free (unix_socket_path);
1067 return;
1068 }
1069 if (GNUNET_OK != GNUNET_NETWORK_socket_bind (unix_sock,
1070 (const struct sockaddr *) un,
1071 un_len))
1072 {
1073 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "bind", un->sun_path);
1074 GNUNET_NETWORK_socket_close (unix_sock);
1075 unix_sock = NULL;
1076 GNUNET_free (un);
1077 GNUNET_free (unix_socket_path);
1078 return;
1079 }
1080 GNUNET_free (un);
1081 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Bound to `%s'\n", unix_socket_path);
1082 stats = GNUNET_STATISTICS_create ("C-UNIX", cfg);
1083 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
1084 read_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
1085 unix_sock,
1086 &select_read_cb,
1087 NULL);
1088 queue_map = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO);
1089 ch = GNUNET_TRANSPORT_communicator_connect (cfg,
1090 COMMUNICATOR_CONFIG_SECTION,
1091 COMMUNICATOR_ADDRESS_PREFIX,
1092 GNUNET_TRANSPORT_CC_RELIABLE,
1093 &mq_init,
1094 NULL,
1095 &enc_notify_cb,
1096 NULL);
1097 if (NULL == ch)
1098 {
1099 GNUNET_break (0);
1100 GNUNET_SCHEDULER_shutdown ();
1101 GNUNET_free (unix_socket_path);
1102 return;
1103 }
1104 GNUNET_asprintf (&my_addr,
1105 "%s-%s",
1106 COMMUNICATOR_ADDRESS_PREFIX,
1107 unix_socket_path);
1108 GNUNET_free (unix_socket_path);
1109 ai = GNUNET_TRANSPORT_communicator_address_add (ch,
1110 my_addr,
1111 GNUNET_NT_LOOPBACK,
1112 GNUNET_TIME_UNIT_FOREVER_REL);
1113 GNUNET_free (my_addr);
1114}
1115
1116
1117/**
1118 * The main function for the UNIX communicator.
1119 *
1120 * @param argc number of arguments from the command line
1121 * @param argv command line arguments
1122 * @return 0 ok, 1 on error
1123 */
1124int
1125main (int argc, char *const *argv)
1126{
1127 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
1128 GNUNET_GETOPT_OPTION_END
1129 };
1130 int ret;
1131
1132 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
1133 return 2;
1134
1135 ret = (GNUNET_OK ==
1136 GNUNET_PROGRAM_run (argc,
1137 argv,
1138 "gnunet-communicator-unix",
1139 _ ("GNUnet UNIX domain socket communicator"),
1140 options,
1141 &run,
1142 NULL))
1143 ? 0
1144 : 1;
1145 GNUNET_free_nz ((void *) argv);
1146 return ret;
1147}
1148
1149
1150#if defined(__linux__) && defined(__GLIBC__)
1151#include <malloc.h>
1152
1153/**
1154 * MINIMIZE heap size (way below 128k) since this process doesn't need much.
1155 */
1156void __attribute__ ((constructor))
1157GNUNET_ARM_memory_init ()
1158{
1159 mallopt (M_TRIM_THRESHOLD, 4 * 1024);
1160 mallopt (M_TOP_PAD, 1 * 1024);
1161 malloc_trim (0);
1162}
1163
1164
1165#endif
1166
1167/* end of gnunet-communicator-unix.c */
diff --git a/src/transport/gnunet-helper-transport-bluetooth.c b/src/transport/gnunet-helper-transport-bluetooth.c
deleted file mode 100644
index 019f3914f..000000000
--- a/src/transport/gnunet-helper-transport-bluetooth.c
+++ /dev/null
@@ -1,2285 +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 "gnunet_config.h"
23
24#include <bluetooth/bluetooth.h>
25#include <bluetooth/hci.h>
26#include <bluetooth/hci_lib.h>
27#include <bluetooth/rfcomm.h>
28#include <bluetooth/sdp.h>
29#include <bluetooth/sdp_lib.h>
30#include <errno.h>
31#include <linux/if.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <sys/ioctl.h>
35#include <sys/param.h>
36#include <sys/socket.h>
37#include <sys/stat.h>
38#include <sys/types.h>
39#include <unistd.h>
40
41#include "plugin_transport_wlan.h"
42#include "gnunet_protocols.h"
43
44
45/**
46 * Maximum number of ports assignable for RFCOMMM protocol.
47 */
48#define MAX_PORTS 30
49
50/**
51 * Maximum size of a message allowed in either direction
52 * (used for our receive and sent buffers).
53 */
54#define MAXLINE 4096
55
56
57/**
58 * Maximum number of loops without inquiring for new devices.
59 */
60#define MAX_LOOPS 5
61
62/**
63 * In bluez library, the maximum name length of a device is 8
64 */
65#define BLUEZ_DEVNAME_SIZE 8
66
67/**
68 * struct for storing the information of the hardware. There is only
69 * one of these.
70 */
71struct HardwareInfos
72{
73 /**
74 * Name of the interface, not necessarily 0-terminated (!).
75 */
76 char iface[IFNAMSIZ];
77
78 /**
79 * file descriptor for the rfcomm socket
80 */
81 int fd_rfcomm;
82
83 /**
84 * MAC address of our own bluetooth interface.
85 */
86 struct GNUNET_TRANSPORT_WLAN_MacAddress pl_mac;
87
88 /**
89 * SDP session
90 */
91 sdp_session_t *session;
92};
93
94/**
95 * IO buffer used for buffering data in transit (to wireless or to stdout).
96 */
97struct SendBuffer
98{
99 /**
100 * How many bytes of data are stored in 'buf' for transmission right now?
101 * Data always starts at offset 0 and extends to 'size'.
102 */
103 size_t size;
104
105 /**
106 * How many bytes that were stored in 'buf' did we already write to the
107 * destination? Always smaller than 'size'.
108 */
109 size_t pos;
110
111 /**
112 * Buffered data; twice the maximum allowed message size as we add some
113 * headers.
114 */
115 char buf[MAXLINE * 2];
116};
117
118#ifdef __linux__
119/**
120 * Devices buffer used to keep a list with all the discoverable devices in
121 * order to send them HELLO messages one by one when it receive a broadcast message.
122 */
123struct BroadcastMessages
124{
125 /* List with the discoverable devices' addresses */
126 bdaddr_t devices[MAX_PORTS];
127
128 /* List with the open sockets */
129 int fds[MAX_PORTS];
130
131
132 /* The number of the devices */
133 int size;
134
135 /* The current position */
136 int pos;
137
138 /* The device id */
139 int dev_id;
140};
141
142/**
143 * Address used to identify the broadcast messages.
144 */
145static struct GNUNET_TRANSPORT_WLAN_MacAddress broadcast_address = { { 255, 255,
146 255, 255,
147 255,
148 255 } };
149
150/**
151 * Buffer with the discoverable devices.
152 */
153static struct BroadcastMessages neighbours;
154
155static int searching_devices_count = 0;
156#endif
157
158/**
159 * Buffer for data read from stdin to be transmitted to the bluetooth device
160 */
161static struct SendBuffer write_pout;
162
163/**
164 * Buffer for data read from the bluetooth device to be transmitted to stdout.
165 */
166static struct SendBuffer write_std;
167
168
169/* ****** this are the same functions as the ones used in gnunet-helper-transport-wlan.c ****** */
170
171/**
172 * To what multiple do we align messages? 8 byte should suffice for everyone
173 * for now.
174 */
175#define ALIGN_FACTOR 8
176
177/**
178 * Smallest supported message.
179 */
180#define MIN_BUFFER_SIZE sizeof(struct GNUNET_MessageHeader)
181
182
183/**
184 * Functions with this signature are called whenever a
185 * complete message is received by the tokenizer.
186 *
187 * @param cls closure
188 * @param message the actual message
189 */
190typedef void (*MessageTokenizerCallback) (void *cls,
191 const struct
192 GNUNET_MessageHeader *
193 message);
194
195/**
196 * Handle to a message stream tokenizer.
197 */
198struct MessageStreamTokenizer
199{
200 /**
201 * Function to call on completed messages.
202 */
203 MessageTokenizerCallback cb;
204
205 /**
206 * Closure for cb.
207 */
208 void *cb_cls;
209
210 /**
211 * Size of the buffer (starting at 'hdr').
212 */
213 size_t curr_buf;
214
215 /**
216 * How many bytes in buffer have we already processed?
217 */
218 size_t off;
219
220 /**
221 * How many bytes in buffer are valid right now?
222 */
223 size_t pos;
224
225 /**
226 * Beginning of the buffer. Typed like this to force alignment.
227 */
228 struct GNUNET_MessageHeader *hdr;
229};
230
231
232/**
233 * Create a message stream tokenizer.
234 *
235 * @param cb function to call on completed messages
236 * @param cb_cls closure for cb
237 * @return handle to tokenizer
238 */
239static struct MessageStreamTokenizer *
240mst_create (MessageTokenizerCallback cb,
241 void *cb_cls)
242{
243 struct MessageStreamTokenizer *ret;
244
245 ret = malloc (sizeof(struct MessageStreamTokenizer));
246 if (NULL == ret)
247 {
248 fprintf (stderr, "Failed to allocate buffer for tokenizer\n");
249 exit (1);
250 }
251 ret->hdr = malloc (MIN_BUFFER_SIZE);
252 if (NULL == ret->hdr)
253 {
254 fprintf (stderr, "Failed to allocate buffer for alignment\n");
255 exit (1);
256 }
257 ret->curr_buf = MIN_BUFFER_SIZE;
258 ret->cb = cb;
259 ret->cb_cls = cb_cls;
260 ret->pos = 0;
261
262 return ret;
263}
264
265
266/**
267 * Add incoming data to the receive buffer and call the
268 * callback for all complete messages.
269 *
270 * @param mst tokenizer to use
271 * @param buf input data to add
272 * @param size number of bytes in buf
273 * @return GNUNET_OK if we are done processing (need more data)
274 * GNUNET_SYSERR if the data stream is corrupt
275 */
276static int
277mst_receive (struct MessageStreamTokenizer *mst,
278 const char *buf, size_t size)
279{
280 const struct GNUNET_MessageHeader *hdr;
281 size_t delta;
282 uint16_t want;
283 char *ibuf;
284 int need_align;
285 unsigned long offset;
286 int ret;
287
288 ret = GNUNET_OK;
289 ibuf = (char *) mst->hdr;
290 while (mst->pos > 0)
291 {
292do_align:
293 if (mst->pos < mst->off)
294 {
295 // fprintf (stderr, "We processed too many bytes!\n");
296 return GNUNET_SYSERR;
297 }
298 if ((mst->curr_buf - mst->off < sizeof(struct GNUNET_MessageHeader)) ||
299 (0 != (mst->off % ALIGN_FACTOR)))
300 {
301 /* need to align or need more space */
302 mst->pos -= mst->off;
303 memmove (ibuf, &ibuf[mst->off], mst->pos);
304 mst->off = 0;
305 }
306 if (mst->pos - mst->off < sizeof(struct GNUNET_MessageHeader))
307 {
308 delta =
309 GNUNET_MIN (sizeof(struct GNUNET_MessageHeader)
310 - (mst->pos - mst->off), size);
311 GNUNET_memcpy (&ibuf[mst->pos], buf, delta);
312 mst->pos += delta;
313 buf += delta;
314 size -= delta;
315 }
316 if (mst->pos - mst->off < sizeof(struct GNUNET_MessageHeader))
317 {
318 // FIXME should I reset ??
319 // mst->off = 0;
320 // mst->pos = 0;
321 return GNUNET_OK;
322 }
323 hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off];
324 want = ntohs (hdr->size);
325 if (want < sizeof(struct GNUNET_MessageHeader))
326 {
327 fprintf (stderr,
328 "Received invalid message from stdin\n");
329 return GNUNET_SYSERR;
330 }
331 if ((mst->curr_buf - mst->off < want) &&
332 (mst->off > 0))
333 {
334 /* need more space */
335 mst->pos -= mst->off;
336 memmove (ibuf, &ibuf[mst->off], mst->pos);
337 mst->off = 0;
338 }
339 if (want > mst->curr_buf)
340 {
341 if (mst->off != 0)
342 {
343 fprintf (stderr, "Error! We should proceeded 0 bytes\n");
344 return GNUNET_SYSERR;
345 }
346 mst->hdr = realloc (mst->hdr, want);
347 if (NULL == mst->hdr)
348 {
349 fprintf (stderr, "Failed to allocate buffer for alignment\n");
350 exit (1);
351 }
352 ibuf = (char *) mst->hdr;
353 mst->curr_buf = want;
354 }
355 hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off];
356 if (mst->pos - mst->off < want)
357 {
358 delta = GNUNET_MIN (want - (mst->pos - mst->off), size);
359 if (mst->pos + delta > mst->curr_buf)
360 {
361 fprintf (stderr, "The size of the buffer will be exceeded!\n");
362 return GNUNET_SYSERR;
363 }
364 GNUNET_memcpy (&ibuf[mst->pos], buf, delta);
365 mst->pos += delta;
366 buf += delta;
367 size -= delta;
368 }
369 if (mst->pos - mst->off < want)
370 {
371 // FIXME should I use this?
372 // mst->off = 0;
373 // mst->pos = 0;
374 return GNUNET_OK;
375 }
376 mst->cb (mst->cb_cls, hdr);
377 mst->off += want;
378 if (mst->off == mst->pos)
379 {
380 /* reset to beginning of buffer, it's free right now! */
381 mst->off = 0;
382 mst->pos = 0;
383 }
384 }
385 if (0 != mst->pos)
386 {
387 fprintf (stderr,
388 "There should some valid bytes in the buffer on this stage\n");
389 return GNUNET_SYSERR;
390 }
391 while (size > 0)
392 {
393 if (size < sizeof(struct GNUNET_MessageHeader))
394 break;
395 offset = (unsigned long) buf;
396 need_align = (0 != offset % ALIGN_FACTOR) ? GNUNET_YES : GNUNET_NO;
397 if (GNUNET_NO == need_align)
398 {
399 /* can try to do zero-copy and process directly from original buffer */
400 hdr = (const struct GNUNET_MessageHeader *) buf;
401 want = ntohs (hdr->size);
402 if (want < sizeof(struct GNUNET_MessageHeader))
403 {
404 fprintf (stderr,
405 "Received invalid message from stdin\n");
406 // exit (1);
407 mst->off = 0;
408 return GNUNET_SYSERR;
409 }
410 if (size < want)
411 break; /* or not, buffer incomplete, so copy to private buffer... */
412 mst->cb (mst->cb_cls, hdr);
413 buf += want;
414 size -= want;
415 }
416 else
417 {
418 /* need to copy to private buffer to align;
419 * yes, we go a bit more spaghetti than usual here */
420 goto do_align;
421 }
422 }
423 if (size > 0)
424 {
425 if (size + mst->pos > mst->curr_buf)
426 {
427 mst->hdr = realloc (mst->hdr, size + mst->pos);
428 if (NULL == mst->hdr)
429 {
430 fprintf (stderr, "Failed to allocate buffer for alignment\n");
431 exit (1);
432 }
433 ibuf = (char *) mst->hdr;
434 mst->curr_buf = size + mst->pos;
435 }
436 if (mst->pos + size > mst->curr_buf)
437 {
438 fprintf (stderr,
439 "Assertion failed\n");
440 exit (1);
441 }
442 GNUNET_memcpy (&ibuf[mst->pos], buf, size);
443 mst->pos += size;
444 }
445 return ret;
446}
447
448
449/**
450 * Destroys a tokenizer.
451 *
452 * @param mst tokenizer to destroy
453 */
454static void
455mst_destroy (struct MessageStreamTokenizer *mst)
456{
457 free (mst->hdr);
458 free (mst);
459}
460
461
462/**
463 * Calculate crc32, the start of the calculation
464 *
465 * @param buf buffer to calc the crc
466 * @param len len of the buffer
467 * @return crc sum
468 */
469static unsigned long
470calc_crc_osdep (const unsigned char *buf, size_t len)
471{
472 static const unsigned long int crc_tbl_osdep[256] = {
473 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
474 0xE963A535, 0x9E6495A3,
475 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD,
476 0xE7B82D07, 0x90BF1D91,
477 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB,
478 0xF4D4B551, 0x83D385C7,
479 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
480 0xFA0F3D63, 0x8D080DF5,
481 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447,
482 0xD20D85FD, 0xA50AB56B,
483 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75,
484 0xDCD60DCF, 0xABD13D59,
485 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
486 0xCFBA9599, 0xB8BDA50F,
487 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11,
488 0xC1611DAB, 0xB6662D3D,
489 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F,
490 0x9FBFE4A5, 0xE8B8D433,
491 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
492 0x91646C97, 0xE6635C01,
493 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B,
494 0x8208F4C1, 0xF50FC457,
495 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49,
496 0x8CD37CF3, 0xFBD44C65,
497 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
498 0xA4D1C46D, 0xD3D6F4FB,
499 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5,
500 0xAA0A4C5F, 0xDD0D7CC9,
501 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3,
502 0xB966D409, 0xCE61E49F,
503 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
504 0xB7BD5C3B, 0xC0BA6CAD,
505 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF,
506 0x04DB2615, 0x73DC1683,
507 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D,
508 0x0A00AE27, 0x7D079EB1,
509 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
510 0x196C3671, 0x6E6B06E7,
511 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9,
512 0x17B7BE43, 0x60B08ED5,
513 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767,
514 0x3FB506DD, 0x48B2364B,
515 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
516 0x316E8EEF, 0x4669BE79,
517 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703,
518 0x220216B9, 0x5505262F,
519 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31,
520 0x2CD99E8B, 0x5BDEAE1D,
521 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
522 0x72076785, 0x05005713,
523 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D,
524 0x7CDCEFB7, 0x0BDBDF21,
525 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B,
526 0x6FB077E1, 0x18B74777,
527 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
528 0x616BFFD3, 0x166CCF45,
529 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7,
530 0x4969474D, 0x3E6E77DB,
531 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5,
532 0x47B2CF7F, 0x30B5FFE9,
533 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
534 0x54DE5729, 0x23D967BF,
535 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1,
536 0x5A05DF1B, 0x2D02EF8D
537 };
538
539 unsigned long crc = 0xFFFFFFFF;
540
541 for (; len > 0; len--, buf++)
542 crc = crc_tbl_osdep[(crc ^ *buf) & 0xFF] ^ (crc >> 8);
543 return(~crc);
544}
545
546
547/**
548 * Calculate and check crc of the bluetooth packet
549 *
550 * @param buf buffer of the packet, with len + 4 bytes of data,
551 * the last 4 bytes being the checksum
552 * @param len length of the payload in data
553 * @return 0 on success (checksum matches), 1 on error
554 */
555static int
556check_crc_buf_osdep (const unsigned char *buf, size_t len)
557{
558 unsigned long crc;
559
560 crc = calc_crc_osdep (buf, len);
561 buf += len;
562 if ((((crc) & 0xFF) == buf[0]) && (((crc >> 8) & 0xFF) == buf[1]) &&
563 ( ((crc >> 16) & 0xFF) == buf[2]) && ( ((crc >> 24) & 0xFF) == buf[3]) )
564 return 0;
565 return 1;
566}
567
568
569/* ************** end of clone ***************** */
570#ifdef __linux__
571/**
572 * Function for assigning a port number
573 *
574 * @param socket the socket used to bind
575 * @param addr pointer to the rfcomm address
576 * @return 0 on success
577 */
578static int
579bind_socket (int socket, struct sockaddr_rc *addr)
580{
581 int port, status;
582
583 /* Bind every possible port (from 0 to 30) and stop when binding doesn't fail */
584 // FIXME : it should start from port 1, but on my computer it doesn't work :)
585 for (port = 3; port <= 30; port++)
586 {
587 addr->rc_channel = port;
588 status = bind (socket, (struct sockaddr *) addr, sizeof(struct
589 sockaddr_rc));
590 if (status == 0)
591 return 0;
592 }
593
594 return -1;
595}
596
597
598#endif
599
600/**
601 * Function used for creating the service record and registering it.
602 *
603 * @param dev pointer to the device struct
604 * @param rc_channel the rfcomm channel
605 * @return 0 on success
606 */
607static int
608register_service (struct HardwareInfos *dev, int rc_channel)
609{
610 /**
611 * 1. initializations
612 * 2. set the service ID, class, profile information
613 * 3. make the service record publicly browsable
614 * 4. register the RFCOMM channel
615 * 5. set the name, provider and description
616 * 6. register the service record to the local SDP server
617 * 7. cleanup
618 */uint8_t svc_uuid_int[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
619 dev->pl_mac.mac[5], dev->pl_mac.mac[4],
620 dev->pl_mac.mac[3],
621 dev->pl_mac.mac[2], dev->pl_mac.mac[1],
622 dev->pl_mac.mac[0] };
623 const char *service_dsc = "Bluetooth plugin services";
624 const char *service_prov = "GNUnet provider";
625 uuid_t root_uuid, rfcomm_uuid, svc_uuid;
626 sdp_list_t *root_list = 0, *rfcomm_list = 0, *proto_list = 0,
627 *access_proto_list = 0, *svc_list = 0;
628 sdp_record_t *record = 0;
629 sdp_data_t *channel = 0;
630
631 record = sdp_record_alloc ();
632
633 /* Set the general service ID */
634 sdp_uuid128_create (&svc_uuid, &svc_uuid_int);
635 svc_list = sdp_list_append (0, &svc_uuid);
636 sdp_set_service_classes (record, svc_list);
637 sdp_set_service_id (record, svc_uuid);
638
639 /* Make the service record publicly browsable */
640 sdp_uuid16_create (&root_uuid, PUBLIC_BROWSE_GROUP);
641 root_list = sdp_list_append (0, &root_uuid);
642 sdp_set_browse_groups (record, root_list);
643
644 /* Register the RFCOMM channel */
645 sdp_uuid16_create (&rfcomm_uuid, RFCOMM_UUID);
646 channel = sdp_data_alloc (SDP_UINT8, &rc_channel);
647 rfcomm_list = sdp_list_append (0, &rfcomm_uuid);
648 sdp_list_append (rfcomm_list, channel);
649 proto_list = sdp_list_append (0, rfcomm_list);
650
651 /* Set protocol information */
652 access_proto_list = sdp_list_append (0, proto_list);
653 sdp_set_access_protos (record, access_proto_list);
654
655 /* Set the name, provider, and description */
656 sdp_set_info_attr (record, dev->iface, service_prov, service_dsc);
657
658 /* Connect to the local SDP server */
659 dev->session = sdp_connect (BDADDR_ANY, BDADDR_LOCAL, SDP_RETRY_IF_BUSY);
660
661 if (! dev->session)
662 {
663 fprintf (stderr,
664 "Failed to connect to the SDP server on interface `%.*s': %s\n",
665 IFNAMSIZ, dev->iface, strerror (errno));
666 // FIXME exit?
667 return 1;
668 }
669
670 /* Register the service record */
671 if (sdp_record_register (dev->session, record, 0) < 0)
672 {
673 fprintf (stderr,
674 "Failed to register a service record on interface `%.*s': %s\n",
675 IFNAMSIZ, dev->iface, strerror (errno));
676 // FIXME exit?
677 return 1;
678 }
679
680 /* Cleanup */
681 sdp_data_free (channel);
682 sdp_list_free (root_list, 0);
683 sdp_list_free (rfcomm_list, 0);
684 sdp_list_free (proto_list, 0);
685 sdp_list_free (access_proto_list, 0);
686 sdp_list_free (svc_list, 0);
687 sdp_record_free (record);
688
689 return 0;
690}
691
692
693/**
694 * Function used for searching and browsing for a service. This will return the
695 * port number on which the service is running.
696 *
697 * @param dev pointer to the device struct
698 * @param dest target address
699 * @return channel
700 */
701static int
702get_channel (struct HardwareInfos *dev, bdaddr_t dest)
703{
704 /**
705 * 1. detect all nearby devices
706 * 2. for each device:
707 * 2.1. connect to the SDP server running
708 * 2.2. get a list of service records with the specific UUID
709 * 2.3. for each service record get a list of the protocol sequences and get
710 * the port number
711 */uint8_t svc_uuid_int[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
712 dest.b[5], dest.b[4], dest.b[3],
713 dest.b[2], dest.b[1], dest.b[0] };
714 sdp_session_t *session = 0;
715 sdp_list_t *search_list = 0, *attrid_list = 0, *response_list = 0, *it = 0;
716 uuid_t svc_uuid;
717 uint32_t range = 0x0000ffff;
718 int channel = -1;
719
720 /* Connect to the local SDP server */
721 session = sdp_connect (BDADDR_ANY, &dest, 0);
722 if (! session)
723 {
724 fprintf (stderr,
725 "Failed to connect to the SDP server on interface `%.*s': %s\n",
726 IFNAMSIZ, dev->iface, strerror (errno));
727 return -1;
728 }
729
730 sdp_uuid128_create (&svc_uuid, &svc_uuid_int);
731 search_list = sdp_list_append (0, &svc_uuid);
732 attrid_list = sdp_list_append (0, &range);
733
734 if (sdp_service_search_attr_req (session, search_list,
735 SDP_ATTR_REQ_RANGE, attrid_list,
736 &response_list) == 0)
737 {
738 for (it = response_list; it; it = it->next)
739 {
740 sdp_record_t *record = (sdp_record_t *) it->data;
741 sdp_list_t *proto_list = 0;
742 if (sdp_get_access_protos (record, &proto_list) == 0)
743 {
744 channel = sdp_get_proto_port (proto_list, RFCOMM_UUID);
745 sdp_list_free (proto_list, 0);
746 }
747 sdp_record_free (record);
748 }
749 }
750
751 sdp_list_free (search_list, 0);
752 sdp_list_free (attrid_list, 0);
753 sdp_list_free (response_list, 0);
754
755 sdp_close (session);
756
757 if (-1 == channel)
758 fprintf (stderr,
759 "Failed to find the listening channel for interface `%.*s': %s\n",
760 IFNAMSIZ,
761 dev->iface,
762 strerror (errno));
763
764 return channel;
765}
766
767
768/**
769 * Read from the socket and put the result into the buffer for transmission to 'stdout'.
770 *
771 * @param sock file descriptor for reading
772 * @param buf buffer to read to; first bytes will be the 'struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame',
773 * followed by the actual payload
774 * @param buf_size size of the buffer
775 * @param ri where to write radiotap_rx info
776 * @return number of bytes written to 'buf'
777 */
778static ssize_t
779read_from_the_socket (void *sock,
780 unsigned char *buf, size_t buf_size,
781 struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage *ri)
782{
783 unsigned char tmpbuf[buf_size];
784 ssize_t count;
785 count = read (*((int *) sock), tmpbuf, buf_size);
786
787 if (0 > count)
788 {
789 if (EAGAIN == errno)
790 return 0;
791
792 fprintf (stderr, "Failed to read from the HCI socket: %s\n", strerror (
793 errno));
794
795 return -1;
796 }
797
798 #ifdef __linux__
799 /* Get the channel used */
800 int len;
801 struct sockaddr_rc rc_addr = { 0 };
802
803 memset (&rc_addr, 0, sizeof(rc_addr));
804 len = sizeof(rc_addr);
805 if (0 > getsockname (*((int *) sock), (struct sockaddr *) &rc_addr,
806 (socklen_t *) &len))
807 {
808 fprintf (stderr, "getsockname() call failed : %s\n", strerror (errno));
809 return -1;
810 }
811
812 memset (ri, 0, sizeof(*ri));
813 ri->ri_channel = rc_addr.rc_channel;
814 #endif
815
816 /* Detect CRC32 at the end */
817 if (0 == check_crc_buf_osdep (tmpbuf, count - sizeof(uint32_t)))
818 {
819 count -= sizeof(uint32_t);
820 }
821
822 GNUNET_memcpy (buf, tmpbuf, count);
823
824 return count;
825}
826
827
828/**
829 * Open the bluetooth interface for reading/writing
830 *
831 * @param dev pointer to the device struct
832 * @return 0 on success, non-zero on error
833 */
834static int
835open_device (struct HardwareInfos *dev)
836{
837 int i, dev_id = -1, fd_hci;
838 struct
839 {
840 struct hci_dev_list_req list;
841 struct hci_dev_req dev[HCI_MAX_DEV];
842 } request; // used for detecting the local devices
843 struct sockaddr_rc rc_addr = { 0 }; // used for binding
844
845 /* Initialize the neighbour structure */
846 neighbours.dev_id = -1;
847 for (i = 0; i < MAX_PORTS; i++)
848 neighbours.fds[i] = -1;
849
850 /* Open a HCI socket */
851 fd_hci = socket (AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
852
853 if (fd_hci < 0)
854 {
855 fprintf (stderr,
856 "Failed to create HCI socket: %s\n",
857 strerror (errno));
858 return -1;
859 }
860
861 memset (&request, 0, sizeof(request));
862 request.list.dev_num = HCI_MAX_DEV;
863
864 if (ioctl (fd_hci, HCIGETDEVLIST, (void *) &request) < 0)
865 {
866 fprintf (stderr,
867 "ioctl(HCIGETDEVLIST) on interface `%.*s' failed: %s\n",
868 IFNAMSIZ,
869 dev->iface,
870 strerror (errno));
871 (void) close (fd_hci);
872 return 1;
873 }
874
875 /* Search for a device with dev->iface name */
876 for (i = 0; i < request.list.dev_num; i++)
877 {
878 struct hci_dev_info dev_info;
879
880 memset (&dev_info, 0, sizeof(struct hci_dev_info));
881 dev_info.dev_id = request.dev[i].dev_id;
882 strncpy (dev_info.name, dev->iface, BLUEZ_DEVNAME_SIZE);
883
884 if (ioctl (fd_hci, HCIGETDEVINFO, (void *) &dev_info))
885 {
886 fprintf (stderr,
887 "ioctl(HCIGETDEVINFO) on interface `%.*s' failed: %s\n",
888 IFNAMSIZ,
889 dev->iface,
890 strerror (errno));
891 (void) close (fd_hci);
892 return 1;
893 }
894
895 if (strncmp (dev_info.name, dev->iface, BLUEZ_DEVNAME_SIZE) == 0)
896 {
897 dev_id = dev_info.dev_id; // the device was found
898 /**
899 * Copy the MAC address to the device structure
900 */
901 GNUNET_memcpy (&dev->pl_mac, &dev_info.bdaddr, sizeof(bdaddr_t));
902
903 /* Check if the interface is up */
904 if (hci_test_bit (HCI_UP, (void *) &dev_info.flags) == 0)
905 {
906 /* Bring the interface up */
907 if (ioctl (fd_hci, HCIDEVUP, dev_info.dev_id))
908 {
909 fprintf (stderr,
910 "ioctl(HCIDEVUP) on interface `%.*s' failed: %s\n",
911 IFNAMSIZ,
912 dev->iface,
913 strerror (errno));
914 (void) close (fd_hci);
915 return 1;
916 }
917 }
918
919 /* Check if the device is discoverable */
920 if ((hci_test_bit (HCI_PSCAN, (void *) &dev_info.flags) == 0) ||
921 (hci_test_bit (HCI_ISCAN, (void *) &dev_info.flags) == 0) )
922 {
923 /* Set interface Page Scan and Inqury Scan ON */
924 struct hci_dev_req dev_req;
925
926 memset (&dev_req, 0, sizeof(dev_req));
927 dev_req.dev_id = dev_info.dev_id;
928 dev_req.dev_opt = SCAN_PAGE | SCAN_INQUIRY;
929
930 if (ioctl (fd_hci, HCISETSCAN, (unsigned long) &dev_req))
931 {
932 fprintf (stderr,
933 "ioctl(HCISETSCAN) on interface `%.*s' failed: %s\n",
934 IFNAMSIZ,
935 dev->iface,
936 strerror (errno));
937 (void) close (fd_hci);
938 return 1;
939 }
940 }
941 break;
942 }
943 }
944
945 /* Check if the interface was not found */
946 if (-1 == dev_id)
947 {
948 fprintf (stderr,
949 "The interface %s was not found\n",
950 dev->iface);
951 (void) close (fd_hci);
952 return 1;
953 }
954
955 /* Close the hci socket */
956 (void) close (fd_hci);
957
958
959 /* Bind the rfcomm socket to the interface */
960 memset (&rc_addr, 0, sizeof(rc_addr));
961 rc_addr.rc_family = AF_BLUETOOTH;
962 rc_addr.rc_bdaddr = *BDADDR_ANY;
963
964 if (bind_socket (dev->fd_rfcomm, &rc_addr) != 0)
965 {
966 fprintf (stderr,
967 "Failed to bind interface `%.*s': %s\n",
968 IFNAMSIZ,
969 dev->iface,
970 strerror (errno));
971 return 1;
972 }
973
974 /* Register a SDP service */
975 if (register_service (dev, rc_addr.rc_channel) != 0)
976 {
977 fprintf (stderr,
978 "Failed to register a service on interface `%.*s': %s\n",
979 IFNAMSIZ,
980 dev->iface, strerror (errno));
981 return 1;
982 }
983
984 /* Switch socket in listening mode */
985 if (listen (dev->fd_rfcomm, 5) == -1) // FIXME: probably we need a bigger number
986 {
987 fprintf (stderr, "Failed to listen on socket for interface `%.*s': %s\n",
988 IFNAMSIZ,
989 dev->iface, strerror (errno));
990 return 1;
991 }
992
993 return 0;
994}
995
996
997/**
998 * Set the header to sane values to make attacks more difficult
999 *
1000 * @param taIeeeHeader pointer to the header of the packet
1001 * @param dev pointer to the Hardware_Infos struct
1002 *
1003 **** copy from gnunet-helper-transport-wlan.c ****
1004 */
1005static void
1006mac_set (struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *taIeeeHeader,
1007 const struct HardwareInfos *dev)
1008{
1009 taIeeeHeader->frame_control = htons (IEEE80211_FC0_TYPE_DATA);
1010 taIeeeHeader->addr3 = mac_bssid_gnunet;
1011 taIeeeHeader->addr2 = dev->pl_mac;
1012}
1013
1014
1015#ifdef __linux__
1016/**
1017 * Test if the given interface name really corresponds to a bluetooth
1018 * device.
1019 *
1020 * @param iface name of the interface
1021 * @return 0 on success, 1 on error
1022 **** similar with the one from gnunet-helper-transport-wlan.c ****
1023 */
1024static int
1025test_bluetooth_interface (const char *iface)
1026{
1027 char strbuf[512];
1028 struct stat sbuf;
1029 int ret;
1030
1031 ret = snprintf (strbuf, sizeof(strbuf),
1032 "/sys/class/bluetooth/%s/subsystem",
1033 iface);
1034 if ((ret < 0) || (ret >= sizeof(strbuf)) || (0 != stat (strbuf, &sbuf)))
1035 {
1036 fprintf (stderr,
1037 "Did not find 802.15.1 interface `%s'. Exiting.\n",
1038 iface);
1039 exit (1);
1040 }
1041 return 0;
1042}
1043
1044
1045#endif
1046
1047/**
1048 * Test incoming packets mac for being our own.
1049 *
1050 * @param taIeeeHeader buffer of the packet
1051 * @param dev the Hardware_Infos struct
1052 * @return 0 if mac belongs to us, 1 if mac is for another target
1053 *
1054 **** same as the one from gnunet-helper-transport-wlan.c ****
1055 */
1056static int
1057mac_test (const struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *taIeeeHeader,
1058 const struct HardwareInfos *dev)
1059{
1060 static struct GNUNET_TRANSPORT_WLAN_MacAddress all_zeros;
1061
1062 if ((0 == memcmp (&taIeeeHeader->addr3, &all_zeros, MAC_ADDR_SIZE)) ||
1063 (0 == memcmp (&taIeeeHeader->addr1, &all_zeros, MAC_ADDR_SIZE)))
1064 return 0; /* some drivers set no Macs, then assume it is all for us! */
1065
1066 if (0 != memcmp (&taIeeeHeader->addr3, &mac_bssid_gnunet, MAC_ADDR_SIZE))
1067 return 1; /* not a GNUnet ad-hoc package */
1068 if ((0 == memcmp (&taIeeeHeader->addr1, &dev->pl_mac, MAC_ADDR_SIZE)) ||
1069 (0 == memcmp (&taIeeeHeader->addr1, &bc_all_mac, MAC_ADDR_SIZE)))
1070 return 0; /* for us, or broadcast */
1071 return 1; /* not for us */
1072}
1073
1074
1075/**
1076 * Process data from the stdin. Takes the message, forces the sender MAC to be correct
1077 * and puts it into our buffer for transmission to the receiver.
1078 *
1079 * @param cls pointer to the device struct ('struct HardwareInfos*')
1080 * @param hdr pointer to the start of the packet
1081 *
1082 **** same as the one from gnunet-helper-transport-wlan.c ****
1083 */
1084static void
1085stdin_send_hw (void *cls, const struct GNUNET_MessageHeader *hdr)
1086{
1087 struct HardwareInfos *dev = cls;
1088 const struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *header;
1089 struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *blueheader;
1090 size_t sendsize;
1091
1092 sendsize = ntohs (hdr->size);
1093 if ((sendsize <
1094 sizeof(struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage)) ||
1095 (GNUNET_MESSAGE_TYPE_WLAN_DATA_TO_HELPER != ntohs (hdr->type)))
1096 {
1097 fprintf (stderr, "Received malformed message\n");
1098 exit (1);
1099 }
1100 sendsize -= (sizeof(struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage)
1101 - sizeof(struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame));
1102 if (MAXLINE < sendsize)
1103 {
1104 fprintf (stderr, "Packet too big for buffer\n");
1105 exit (1);
1106 }
1107 header = (const struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *) hdr;
1108 GNUNET_memcpy (&write_pout.buf, &header->frame, sendsize);
1109 blueheader = (struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *) &write_pout.buf;
1110
1111 /* payload contains MAC address, but we don't trust it, so we'll
1112 * overwrite it with OUR MAC address to prevent mischief */
1113 mac_set (blueheader, dev);
1114 GNUNET_memcpy (&blueheader->addr1, &header->frame.addr1,
1115 sizeof(struct GNUNET_TRANSPORT_WLAN_MacAddress));
1116 write_pout.size = sendsize;
1117}
1118
1119
1120#ifdef __linux__
1121/**
1122 * Broadcast a HELLO message for peer discovery
1123 *
1124 * @param dev pointer to the device struct
1125 * @param dev pointer to the socket which was added to the set
1126 * @return 0 on success
1127 */
1128static int
1129send_broadcast (struct HardwareInfos *dev, int *sendsocket)
1130{
1131 int new_device = 0;
1132 int loops = 0;
1133
1134search_for_devices:
1135 if (((neighbours.size == neighbours.pos) && (new_device == 1)) ||
1136 (neighbours.size == 0) )
1137 {
1138inquiry_devices: // skip the conditions and force a inquiry for new devices
1139 {
1140 /**
1141 * It means that I sent HELLO messages to all the devices from the list and I should search
1142 * for new ones or that this is the first time when I do a search.
1143 */
1144 inquiry_info *devices = NULL;
1145 int i, responses, max_responses = MAX_PORTS;
1146
1147 /* sanity checks */
1148 if (neighbours.size >= MAX_PORTS)
1149 {
1150 fprintf (stderr,
1151 "%.*s reached the top limit for the discovarable devices\n",
1152 IFNAMSIZ,
1153 dev->iface);
1154 return 2;
1155 }
1156
1157 /* Get the device id */
1158 if (neighbours.dev_id == -1)
1159 {
1160 char addr[19] = { 0 }; // the device MAC address
1161
1162 ba2str ((bdaddr_t *) &dev->pl_mac, addr);
1163 neighbours.dev_id = hci_devid (addr);
1164 if (neighbours.dev_id < 0)
1165 {
1166 fprintf (stderr,
1167 "Failed to get the device id for interface %.*s : %s\n",
1168 IFNAMSIZ,
1169 dev->iface, strerror (errno));
1170 return 1;
1171 }
1172 }
1173
1174 devices = malloc (max_responses * sizeof(inquiry_info));
1175 if (devices == NULL)
1176 {
1177 fprintf (stderr,
1178 "Failed to allocate memory for inquiry info list on interface %.*s\n",
1179 IFNAMSIZ,
1180 dev->iface);
1181 return 1;
1182 }
1183
1184 responses = hci_inquiry (neighbours.dev_id, 8, max_responses, NULL,
1185 &devices, IREQ_CACHE_FLUSH);
1186 if (responses < 0)
1187 {
1188 fprintf (stderr, "Failed to inquiry on interface %.*s\n", IFNAMSIZ,
1189 dev->iface);
1190 return 1;
1191 }
1192
1193 fprintf (stderr, "LOG : Found %d devices\n", responses); // FIXME delete it after debugging stage
1194
1195 if (responses == 0)
1196 {
1197 fprintf (stderr, "LOG : No devices discoverable\n");
1198 return 1;
1199 }
1200
1201 for (i = 0; i < responses; i++)
1202 {
1203 int j;
1204 int found = 0;
1205
1206 /* sanity check */
1207 if (i >= MAX_PORTS)
1208 {
1209 fprintf (stderr,
1210 "%.*s reached the top limit for the discoverable devices (after inquiry)\n",
1211 IFNAMSIZ,
1212 dev->iface);
1213 return 2;
1214 }
1215
1216 /* Search if the address already exists on the list */
1217 for (j = 0; j < neighbours.size; j++)
1218 {
1219 if (memcmp (&(devices + i)->bdaddr, &(neighbours.devices[j]),
1220 sizeof(bdaddr_t)) == 0)
1221 {
1222 found = 1;
1223 fprintf (stderr, "LOG : the device already exists on the list\n"); // FIXME debugging message
1224 break;
1225 }
1226 }
1227
1228 if (found == 0)
1229 {
1230 char addr[19] = { 0 };
1231
1232 ba2str (&(devices + i)->bdaddr, addr);
1233 fprintf (stderr, "LOG : %s was added to the list\n", addr); // FIXME debugging message
1234 GNUNET_memcpy (&(neighbours.devices[neighbours.size++]), &(devices
1235 + i)->
1236 bdaddr, sizeof(bdaddr_t));
1237 }
1238 }
1239
1240 free (devices);
1241 }
1242 }
1243
1244 int connection_successful = 0;
1245 struct sockaddr_rc addr_rc = { 0 };
1246 int errno_copy = 0;
1247 addr_rc.rc_family = AF_BLUETOOTH;
1248
1249 /* Try to connect to a new device from the list */
1250 while (neighbours.pos < neighbours.size)
1251 {
1252 /* Check if we are already connected to this device */
1253 if (neighbours.fds[neighbours.pos] == -1)
1254 {
1255 memset (&addr_rc.rc_bdaddr, 0, sizeof(addr_rc.rc_bdaddr));
1256 GNUNET_memcpy (&addr_rc.rc_bdaddr, &(neighbours.devices[neighbours.pos]),
1257 sizeof(addr_rc.rc_bdaddr));
1258
1259 addr_rc.rc_channel = get_channel (dev, addr_rc.rc_bdaddr);
1260
1261 *sendsocket = socket (AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
1262 if ((-1 < *sendsocket) &&
1263 (0 == connect (*sendsocket,
1264 (struct sockaddr *) &addr_rc,
1265 sizeof(addr_rc))))
1266 {
1267 neighbours.fds[neighbours.pos++] = *sendsocket;
1268 connection_successful = 1;
1269 char addr[19] = { 0 };
1270 ba2str (&(neighbours.devices[neighbours.pos - 1]), addr);
1271 fprintf (stderr, "LOG : Connected to %s\n", addr);
1272 break;
1273 }
1274 else
1275 {
1276 char addr[19] = { 0 };
1277 errno_copy = errno; // Save a copy for later
1278
1279 if (-1 != *sendsocket)
1280 {
1281 (void) close (*sendsocket);
1282 *sendsocket = -1;
1283 }
1284 ba2str (&(neighbours.devices[neighbours.pos]), addr);
1285 fprintf (stderr,
1286 "LOG : Couldn't connect on device %s, error : %s\n",
1287 addr,
1288 strerror (errno));
1289 if (errno != ECONNREFUSED) // FIXME be sure that this works
1290 {
1291 fprintf (stderr, "LOG : Removes %d device from the list\n",
1292 neighbours.pos);
1293 /* Remove the device from the list */
1294 GNUNET_memcpy (&neighbours.devices[neighbours.pos],
1295 &neighbours.devices[neighbours.size - 1],
1296 sizeof(bdaddr_t));
1297 memset (&neighbours.devices[neighbours.size - 1], 0,
1298 sizeof(bdaddr_t));
1299 neighbours.fds[neighbours.pos] = neighbours.fds[neighbours.size - 1];
1300 neighbours.fds[neighbours.size - 1] = -1;
1301 neighbours.size -= 1;
1302 }
1303
1304 neighbours.pos += 1;
1305
1306 if (neighbours.pos >= neighbours.size)
1307 neighbours.pos = 0;
1308
1309 loops += 1;
1310
1311 if (loops == MAX_LOOPS) // don't get stuck trying to connect to one device
1312 return 1;
1313 }
1314 }
1315 else
1316 {
1317 fprintf (stderr, "LOG : Search for a new device\n"); // FIXME debugging message
1318 neighbours.pos += 1;
1319 }
1320 }
1321
1322 /* Cycle on the list */
1323 if (neighbours.pos == neighbours.size)
1324 {
1325 neighbours.pos = 0;
1326 searching_devices_count += 1;
1327
1328 if (searching_devices_count == MAX_LOOPS)
1329 {
1330 fprintf (stderr, "LOG : Force to inquiry for new devices\n");
1331 searching_devices_count = 0;
1332 goto inquiry_devices;
1333 }
1334 }
1335 /* If a new device wasn't found, search an old one */
1336 if (connection_successful == 0)
1337 {
1338 int loop_check = neighbours.pos;
1339 while (neighbours.fds[neighbours.pos] == -1)
1340 {
1341 if (neighbours.pos == neighbours.size)
1342 neighbours.pos = 0;
1343
1344 if (neighbours.pos == loop_check)
1345 {
1346 if (errno_copy == ECONNREFUSED)
1347 {
1348 fprintf (stderr, "LOG : No device found. Go back and search again\n"); // FIXME debugging message
1349 new_device = 1;
1350 loops += 1;
1351 goto search_for_devices;
1352 }
1353 else
1354 {
1355 return 1; // Skip the broadcast message
1356 }
1357 }
1358
1359 neighbours.pos += 1;
1360 }
1361
1362 *sendsocket = neighbours.fds[neighbours.pos++];
1363 }
1364
1365 return 0;
1366}
1367
1368
1369#endif
1370
1371/**
1372 * Main function of the helper. This code accesses a bluetooth interface
1373 * forwards traffic in both directions between the bluetooth interface and
1374 * stdin/stdout of this process. Error messages are written to stderr.
1375 *
1376 * @param argc number of arguments, must be 2
1377 * @param argv arguments only argument is the name of the interface (e.g. 'hci0')
1378 * @return 0 on success (never happens, as we don't return unless aborted), 1 on error
1379 *
1380 **** similar to gnunet-helper-transport-wlan.c ****
1381 */
1382int
1383main (int argc, char *argv[])
1384{
1385#ifdef __linux__
1386 struct HardwareInfos dev;
1387 char readbuf[MAXLINE];
1388 int maxfd;
1389 fd_set rfds;
1390 fd_set wfds;
1391 int stdin_open;
1392 struct MessageStreamTokenizer *stdin_mst;
1393 int raw_eno, i;
1394 int crt_rfds = 0, rfds_list[MAX_PORTS];
1395 int broadcast, sendsocket;
1396
1397 /* Assert privs so we can modify the firewall rules! */
1398 {
1399#ifdef HAVE_SETRESUID
1400 uid_t uid = getuid ();
1401
1402 if (0 != setresuid (uid, 0, 0))
1403 {
1404 fprintf (stderr,
1405 "Failed to setresuid to root: %s\n",
1406 strerror (errno));
1407 return 254;
1408 }
1409#else
1410 if (0 != seteuid (0))
1411 {
1412 fprintf (stderr,
1413 "Failed to seteuid back to root: %s\n", strerror (errno));
1414 return 254;
1415 }
1416#endif
1417 }
1418
1419 /* Make use of SGID capabilities on POSIX */
1420 memset (&dev, 0, sizeof(dev));
1421 dev.fd_rfcomm = socket (AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
1422 raw_eno = errno; /* remember for later */
1423
1424 /* Now that we've dropped root rights, we can do error checking */
1425 if (2 != argc)
1426 {
1427 fprintf (stderr,
1428 "You must specify the name of the interface as the first \
1429 and only argument to this program.\n");
1430 if (-1 != dev.fd_rfcomm)
1431 (void) close (dev.fd_rfcomm);
1432 return 1;
1433 }
1434
1435 if (-1 == dev.fd_rfcomm)
1436 {
1437 fprintf (stderr, "Failed to create a RFCOMM socket: %s\n", strerror (
1438 raw_eno));
1439 return 1;
1440 }
1441 if (dev.fd_rfcomm >= FD_SETSIZE)
1442 {
1443 fprintf (stderr, "File descriptor too large for select (%d > %d)\n",
1444 dev.fd_rfcomm, FD_SETSIZE);
1445 (void) close (dev.fd_rfcomm);
1446 return 1;
1447 }
1448 if (0 != test_bluetooth_interface (argv[1]))
1449 {
1450 (void) close (dev.fd_rfcomm);
1451 return 1;
1452 }
1453 strncpy (dev.iface, argv[1], IFNAMSIZ);
1454 if (0 != open_device (&dev))
1455 {
1456 (void) close (dev.fd_rfcomm);
1457 return 1;
1458 }
1459
1460 /* Drop privs */
1461 {
1462 uid_t uid = getuid ();
1463 #ifdef HAVE_SETRESUID
1464 if (0 != setresuid (uid, uid, uid))
1465 {
1466 fprintf (stderr, "Failed to setresuid: %s\n", strerror (errno));
1467 if (-1 != dev.fd_rfcomm)
1468 (void) close (dev.fd_rfcomm);
1469 return 1;
1470 }
1471 #else
1472 if (0 != (setuid (uid) | seteuid (uid)))
1473 {
1474 fprintf (stderr, "Failed to setuid: %s\n", strerror (errno));
1475 if (-1 != dev.fd_rfcomm)
1476 (void) close (dev.fd_rfcomm);
1477 return 1;
1478 }
1479 #endif
1480 }
1481
1482 /* Send MAC address of the bluetooth interface to STDOUT first */
1483 {
1484 struct GNUNET_TRANSPORT_WLAN_HelperControlMessage macmsg;
1485
1486 macmsg.hdr.size = htons (sizeof(macmsg));
1487 macmsg.hdr.type = htons (GNUNET_MESSAGE_TYPE_WLAN_HELPER_CONTROL);
1488 GNUNET_memcpy (&macmsg.mac, &dev.pl_mac, sizeof(struct
1489 GNUNET_TRANSPORT_WLAN_MacAddress));
1490 GNUNET_memcpy (write_std.buf, &macmsg, sizeof(macmsg));
1491 write_std.size = sizeof(macmsg);
1492 }
1493
1494
1495 stdin_mst = mst_create (&stdin_send_hw, &dev);
1496 stdin_open = 1;
1497
1498 /**
1499 * TODO : I should make the time out of a mac endpoint smaller and check if the rate
1500 * from get_wlan_header (plugin_transport_bluetooth.c) is correct.
1501 */
1502 while (1)
1503 {
1504 maxfd = -1;
1505 broadcast = 0;
1506 sendsocket = -1;
1507
1508 FD_ZERO (&rfds);
1509 if ((0 == write_pout.size) && (1 == stdin_open))
1510 {
1511 FD_SET (STDIN_FILENO, &rfds);
1512 maxfd = MAX (maxfd, STDIN_FILENO);
1513 }
1514 if (0 == write_std.size)
1515 {
1516 FD_SET (dev.fd_rfcomm, &rfds);
1517 maxfd = MAX (maxfd, dev.fd_rfcomm);
1518 }
1519
1520 for (i = 0; i < crt_rfds; i++) // it can receive messages from multiple devices
1521 {
1522 FD_SET (rfds_list[i], &rfds);
1523 maxfd = MAX (maxfd, rfds_list[i]);
1524 }
1525 FD_ZERO (&wfds);
1526 if (0 < write_std.size)
1527 {
1528 FD_SET (STDOUT_FILENO, &wfds);
1529 maxfd = MAX (maxfd, STDOUT_FILENO);
1530 }
1531 if (0 < write_pout.size) // it can send messages only to one device per loop
1532 {
1533 struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *frame;
1534 /* Get the destination address */
1535 frame = (struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *) write_pout.buf;
1536
1537 if (memcmp (&frame->addr1, &dev.pl_mac,
1538 sizeof(struct GNUNET_TRANSPORT_WLAN_MacAddress)) == 0)
1539 {
1540 broadcast = 1;
1541 memset (&write_pout, 0, sizeof(write_pout)); // clear the buffer
1542 }
1543 else if (memcmp (&frame->addr1, &broadcast_address,
1544 sizeof(struct GNUNET_TRANSPORT_WLAN_MacAddress)) == 0)
1545 {
1546 fprintf (stderr, "LOG : %s has a broadcast message (pos %d, size %d)\n",
1547 dev.iface, neighbours.pos, neighbours.size); // FIXME: debugging message
1548
1549 if (send_broadcast (&dev, &sendsocket) != 0) // if the searching wasn't successful don't get stuck on the select stage
1550 {
1551 broadcast = 1;
1552 memset (&write_pout, 0, sizeof(write_pout)); // remove the message
1553 fprintf (stderr,
1554 "LOG : Skipping the broadcast message (pos %d, size %d)\n",
1555 neighbours.pos, neighbours.size);
1556 }
1557 else
1558 {
1559 FD_SET (sendsocket, &wfds);
1560 maxfd = MAX (maxfd, sendsocket);
1561 }
1562 }
1563 else
1564 {
1565 int found = 0;
1566 int pos = 0;
1567 /* Search if the address already exists on the list */
1568 for (i = 0; i < neighbours.size; i++)
1569 {
1570 if (memcmp (&frame->addr1, &(neighbours.devices[i]),
1571 sizeof(bdaddr_t)) == 0)
1572 {
1573 pos = i;
1574 if (neighbours.fds[i] != -1)
1575 {
1576 found = 1; // save the position where it was found
1577 FD_SET (neighbours.fds[i], &wfds);
1578 maxfd = MAX (maxfd, neighbours.fds[i]);
1579 sendsocket = neighbours.fds[i];
1580 fprintf (stderr, "LOG: the address was found in the list\n");
1581 break;
1582 }
1583 }
1584 }
1585 if (found == 0)
1586 {
1587 int status;
1588 struct sockaddr_rc addr = { 0 };
1589
1590 fprintf (stderr,
1591 "LOG : %s has a new message for %.2X:%.2X:%.2X:%.2X:%.2X:%.2X which isn't on the broadcast list\n",
1592 dev.iface,
1593 frame->addr1.mac[5], frame->addr1.mac[4],
1594 frame->addr1.mac[3],
1595 frame->addr1.mac[2], frame->addr1.mac[1],
1596 frame->addr1.mac[0]); // FIXME: debugging message
1597
1598 sendsocket = socket (AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
1599
1600 if (sendsocket < 0)
1601 {
1602 fprintf (stderr,
1603 "Failed to create a RFCOMM socket (sending stage): %s\n",
1604 strerror (errno));
1605 return -1;
1606 }
1607
1608 GNUNET_memcpy (&addr.rc_bdaddr, &frame->addr1, sizeof(bdaddr_t));
1609 addr.rc_family = AF_BLUETOOTH;
1610 addr.rc_channel = get_channel (&dev, addr.rc_bdaddr);
1611
1612 int tries = 0;
1613connect_retry:
1614 status = connect (sendsocket, (struct sockaddr *) &addr,
1615 sizeof(addr));
1616 if ((0 != status) && (errno != EAGAIN) )
1617 {
1618 if ((errno == ECONNREFUSED) && (tries < 2) )
1619 {
1620 fprintf (stderr, "LOG : %.*s failed to connect. Trying again!\n",
1621 IFNAMSIZ, dev.iface);
1622 tries++;
1623 goto connect_retry;
1624 }
1625 else if (errno == EBADF)
1626 {
1627 fprintf (stderr, "LOG : %s failed to connect : %s. Skip it!\n",
1628 dev.iface, strerror (errno));
1629 memset (&write_pout, 0, sizeof(write_pout));
1630 broadcast = 1;
1631 }
1632 else
1633 {
1634 fprintf (stderr,
1635 "LOG : %s failed to connect : %s. Try again later!\n",
1636 dev.iface,
1637 strerror (errno));
1638 memset (&write_pout, 0, sizeof(write_pout));
1639 broadcast = 1;
1640 }
1641 }
1642 else
1643 {
1644 FD_SET (sendsocket, &wfds);
1645 maxfd = MAX (maxfd, sendsocket);
1646 fprintf (stderr, "LOG : Connection successful\n");
1647 if (pos != 0) // save the socket
1648 {
1649 neighbours.fds[pos] = sendsocket;
1650 }
1651 else
1652 {
1653 /* Add the new device to the discovered devices list */
1654 if (neighbours.size < MAX_PORTS)
1655 {
1656 neighbours.fds[neighbours.size] = sendsocket;
1657 GNUNET_memcpy (&(neighbours.devices[neighbours.size++]),
1658 &addr.rc_bdaddr, sizeof(bdaddr_t));
1659 }
1660 else
1661 {
1662 fprintf (stderr,
1663 "The top limit for the discovarable devices' list was reached\n");
1664 }
1665 }
1666 }
1667 }
1668 }
1669 }
1670
1671 if (broadcast == 0)
1672 {
1673 /* Select a fd which is ready for action :) */
1674 {
1675 int retval = select (maxfd + 1, &rfds, &wfds, NULL, NULL);
1676 if ((-1 == retval) && (EINTR == errno))
1677 continue;
1678 if ((0 > retval) && (errno != EBADF) ) // we handle BADF errors later
1679 {
1680 fprintf (stderr, "select failed: %s\n", strerror (errno));
1681 break;
1682 }
1683 }
1684 if (FD_ISSET (STDOUT_FILENO, &wfds))
1685 {
1686 ssize_t ret =
1687 write (STDOUT_FILENO, write_std.buf + write_std.pos,
1688 write_std.size - write_std.pos);
1689 if (0 > ret)
1690 {
1691 fprintf (stderr, "Failed to write to STDOUT: %s\n", strerror (errno));
1692 break;
1693 }
1694 write_std.pos += ret;
1695 if (write_std.pos == write_std.size)
1696 {
1697 write_std.pos = 0;
1698 write_std.size = 0;
1699 }
1700 fprintf (stderr, "LOG : %s sends a message to STDOUT\n", dev.iface); // FIXME: debugging message
1701 }
1702 if (-1 != sendsocket)
1703 {
1704 if (FD_ISSET (sendsocket, &wfds))
1705 {
1706 ssize_t ret = write (sendsocket,
1707 write_pout.buf + write_std.pos,
1708 write_pout.size - write_pout.pos);
1709 if (0 > ret) // FIXME should I first check the error type?
1710 {
1711 fprintf (stderr,
1712 "Failed to write to bluetooth device: %s. Closing the socket!\n",
1713 strerror (errno));
1714 for (i = 0; i < neighbours.size; i++)
1715 {
1716 if (neighbours.fds[i] == sendsocket)
1717 {
1718 (void) close (sendsocket);
1719 neighbours.fds[i] = -1;
1720 break;
1721 }
1722 }
1723 /* Remove the message */
1724 memset (&write_pout.buf + write_std.pos, 0, (write_pout.size
1725 - write_pout.pos));
1726 write_pout.pos = 0;
1727 write_pout.size = 0;
1728 }
1729 else
1730 {
1731 write_pout.pos += ret;
1732 if ((write_pout.pos != write_pout.size) && (0 != ret))
1733 {
1734 /* We should not get partial sends with packet-oriented devices... */
1735 fprintf (stderr, "Write error, partial send: %u/%u\n",
1736 (unsigned int) write_pout.pos,
1737 (unsigned int) write_pout.size);
1738 break;
1739 }
1740
1741 if (write_pout.pos == write_pout.size)
1742 {
1743 write_pout.pos = 0;
1744 write_pout.size = 0;
1745 }
1746 fprintf (stderr, "LOG : %s sends a message to a DEVICE\n",
1747 dev.iface); // FIXME: debugging message
1748 }
1749 }
1750 }
1751 for (i = 0; i <= maxfd; i++)
1752 {
1753 if (FD_ISSET (i, &rfds))
1754 {
1755 if (i == STDIN_FILENO)
1756 {
1757 ssize_t ret =
1758 read (i, readbuf, sizeof(readbuf));
1759 if (0 > ret)
1760 {
1761 fprintf (stderr,
1762 "Read error from STDIN: %s\n",
1763 strerror (errno));
1764 break;
1765 }
1766 if (0 == ret)
1767 {
1768 /* stop reading... */
1769 stdin_open = 0;
1770 }
1771 else
1772 {
1773 mst_receive (stdin_mst, readbuf, ret);
1774 fprintf (stderr, "LOG : %s receives a message from STDIN\n",
1775 dev.iface); // FIXME: debugging message
1776 }
1777 }
1778 else if (i == dev.fd_rfcomm)
1779 {
1780 int readsocket;
1781 struct sockaddr_rc addr = { 0 };
1782 unsigned int opt = sizeof(addr);
1783
1784 readsocket = accept (dev.fd_rfcomm, (struct sockaddr *) &addr,
1785 &opt);
1786 fprintf (stderr, "LOG : %s accepts a message\n", dev.iface); // FIXME: debugging message
1787 if (readsocket == -1)
1788 {
1789 fprintf (stderr,
1790 "Failed to accept a connection on interface: %.*s\n",
1791 IFNAMSIZ,
1792 strerror (errno));
1793 break;
1794 }
1795 else
1796 {
1797 FD_SET (readsocket, &rfds);
1798 maxfd = MAX (maxfd, readsocket);
1799
1800 if (crt_rfds < MAX_PORTS)
1801 rfds_list[crt_rfds++] = readsocket;
1802 else
1803 {
1804 fprintf (stderr,
1805 "The limit for the read file descriptors list was \
1806 reached\n");
1807 break;
1808 }
1809 }
1810 }
1811 else
1812 {
1813 struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage *rrm;
1814 ssize_t ret;
1815 fprintf (stderr, "LOG : %s reads something from the socket\n",
1816 dev.iface); // FIXME : debugging message
1817 rrm = (struct
1818 GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage *) write_std.buf;
1819 ret =
1820 read_from_the_socket ((void *) &i, (unsigned char *) &rrm->frame,
1821 sizeof(write_std.buf)
1822 - sizeof(struct
1823 GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage)
1824 + sizeof(struct
1825 GNUNET_TRANSPORT_WLAN_Ieee80211Frame),
1826 rrm);
1827 if (0 >= ret)
1828 {
1829 int j;
1830 FD_CLR (i, &rfds);
1831 close (i);
1832 /* Remove the socket from the list */
1833 for (j = 0; j < crt_rfds; j++)
1834 {
1835 if (rfds_list[j] == i)
1836 {
1837 rfds_list[j] ^= rfds_list[crt_rfds - 1];
1838 rfds_list[crt_rfds - 1] ^= rfds_list[j];
1839 rfds_list[j] ^= rfds_list[crt_rfds - 1];
1840 crt_rfds -= 1;
1841 break;
1842 }
1843 }
1844
1845 fprintf (stderr, "Read error from raw socket: %s\n", strerror (
1846 errno));
1847 break;
1848 }
1849 if ((0 < ret) && (0 == mac_test (&rrm->frame, &dev)))
1850 {
1851 write_std.size = ret
1852 + sizeof(struct
1853 GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage)
1854 - sizeof(struct
1855 GNUNET_TRANSPORT_WLAN_Ieee80211Frame);
1856 rrm->header.size = htons (write_std.size);
1857 rrm->header.type = htons (
1858 GNUNET_MESSAGE_TYPE_WLAN_DATA_FROM_HELPER);
1859 }
1860 }
1861 }
1862 }
1863 }
1864 }
1865 /* Error handling, try to clean up a bit at least */
1866 mst_destroy (stdin_mst);
1867 stdin_mst = NULL;
1868 sdp_close (dev.session);
1869 (void) close (dev.fd_rfcomm);
1870 if (-1 != sendsocket)
1871 (void) close (sendsocket);
1872
1873 for (i = 0; i < crt_rfds; i++)
1874 (void) close (rfds_list[i]);
1875
1876 for (i = 0; i < neighbours.size; i++)
1877 (void) close (neighbours.fds[i]);
1878 #else
1879 struct HardwareInfos dev;
1880 struct GNUNET_NETWORK_Handle *sendsocket;
1881 struct GNUNET_NETWORK_FDSet *rfds;
1882 struct GNUNET_NETWORK_FDSet *wfds;
1883 struct GNUNET_NETWORK_Handle *rfds_list[MAX_PORTS];
1884 char readbuf[MAXLINE] = { 0 };
1885 SOCKADDR_BTH acc_addr = { 0 };
1886 int addr_len = sizeof(SOCKADDR_BTH);
1887 int broadcast, i, stdin_open, crt_rfds = 0;
1888 HANDLE stdin_handle = GetStdHandle (STD_INPUT_HANDLE);
1889 HANDLE stdout_handle = GetStdHandle (STD_OUTPUT_HANDLE);
1890 struct MessageStreamTokenizer *stdin_mst;
1891
1892 /* check the handles */
1893 if (stdin_handle == INVALID_HANDLE_VALUE)
1894 {
1895 fprintf (stderr, "Failed to get the stdin handle\n");
1896 ExitProcess (2);
1897 }
1898
1899 if (stdout_handle == INVALID_HANDLE_VALUE)
1900 {
1901 fprintf (stderr, "Failed to get the stdout handle\n");
1902 ExitProcess (2);
1903 }
1904
1905 /* initialize windows sockets */
1906 initialize_windows_sockets ();
1907
1908 // /* test bluetooth socket family support */ --> it return false because the GNUNET_NETWORK_test_pf should also receive the type of socket (BTHPROTO_RFCOMM)
1909 // if (GNUNET_NETWORK_test_pf (AF_BTH) != GNUNET_OK)
1910 // {
1911 // fprintf (stderr, "AF_BTH family is not supported\n");
1912 // ExitProcess (2);
1913 // }
1914
1915 /* create the socket */
1916 dev.handle = GNUNET_NETWORK_socket_create (AF_BTH, SOCK_STREAM,
1917 BTHPROTO_RFCOMM);
1918 if (dev.handle == NULL)
1919 {
1920 fprintf (stderr, "Failed to create RFCOMM socket: ");
1921 print_last_error ();
1922 ExitProcess (2);
1923 }
1924
1925
1926 if (open_device (&dev) == -1)
1927 {
1928 fprintf (stderr, "Failed to open the device\n");
1929 print_last_error ();
1930 if (GNUNET_NETWORK_socket_close (dev.handle) != GNUNET_OK)
1931 {
1932 fprintf (stderr, "Failed to close the socket!\n");
1933 print_last_error ();
1934 }
1935 ExitProcess (2);
1936 }
1937
1938 if (GNUNET_OK != GNUNET_NETWORK_socket_set_blocking (dev.handle, 1))
1939 {
1940 fprintf (stderr, "Failed to change the socket mode\n");
1941 ExitProcess (2);
1942 }
1943
1944 memset (&write_std, 0, sizeof(write_std));
1945 memset (&write_pout, 0, sizeof(write_pout));
1946 stdin_open = 1;
1947
1948 rfds = GNUNET_NETWORK_fdset_create ();
1949 wfds = GNUNET_NETWORK_fdset_create ();
1950
1951 /* Send MAC address of the bluetooth interface to STDOUT first */
1952 {
1953 struct GNUNET_TRANSPORT_WLAN_HelperControlMessage macmsg;
1954
1955 macmsg.hdr.size = htons (sizeof(macmsg));
1956 macmsg.hdr.type = htons (GNUNET_MESSAGE_TYPE_WLAN_HELPER_CONTROL);
1957 GNUNET_memcpy (&macmsg.mac, &dev.pl_mac, sizeof(struct
1958 GNUNET_TRANSPORT_WLAN_MacAddress_Copy));
1959 GNUNET_memcpy (write_std.buf, &macmsg, sizeof(macmsg));
1960 write_std.size = sizeof(macmsg);
1961 }
1962
1963
1964 stdin_mst = mst_create (&stdin_send_hw, &dev);
1965 stdin_open = 1;
1966
1967 int pos = 0;
1968 int stdin_pos = -1;
1969 int stdout_pos = -1;
1970 while (1)
1971 {
1972 broadcast = 0;
1973 pos = 0;
1974 stdin_pos = -1;
1975 stdout_pos = -1;
1976 sendsocket = NULL; // FIXME ???memleaks
1977
1978 GNUNET_NETWORK_fdset_zero (rfds);
1979 if ((0 == write_pout.size) && (1 == stdin_open))
1980 {
1981 stdin_pos = pos;
1982 pos += 1;
1983 GNUNET_NETWORK_fdset_handle_set (rfds, (struct
1984 GNUNET_DISK_FileHandle*) &
1985 stdin_handle);
1986 }
1987
1988 if (0 == write_std.size)
1989 {
1990 pos += 1;
1991 GNUNET_NETWORK_fdset_set (rfds, dev.handle);
1992 }
1993
1994 for (i = 0; i < crt_rfds; i++)
1995 {
1996 pos += 1;
1997 GNUNET_NETWORK_fdset_set (rfds, rfds_list[i]);
1998 }
1999
2000 GNUNET_NETWORK_fdset_zero (wfds);
2001 if (0 < write_std.size)
2002 {
2003 stdout_pos = pos;
2004 GNUNET_NETWORK_fdset_handle_set (wfds, (struct
2005 GNUNET_DISK_FileHandle*) &
2006 stdout_handle);
2007 // printf ("%s\n", write_std.buf);
2008 // memset (write_std.buf, 0, write_std.size);
2009 // write_std.size = 0;
2010 }
2011
2012 if (0 < write_pout.size)
2013 {
2014 if (strcmp (argv[1], "ff:ff:ff:ff:ff:ff") == 0)
2015 {
2016 fprintf (stderr, "LOG: BROADCAST! Skipping the message\n");
2017 // skip the message
2018 broadcast = 1;
2019 memset (write_pout.buf, 0, write_pout.size);
2020 write_pout.size = 0;
2021 }
2022 else
2023 {
2024 SOCKADDR_BTH addr;
2025 fprintf (stderr, "LOG : has a new message for %s\n", argv[1]);
2026 sendsocket = GNUNET_NETWORK_socket_create (AF_BTH, SOCK_STREAM,
2027 BTHPROTO_RFCOMM);
2028
2029 if (sendsocket == NULL)
2030 {
2031 fprintf (stderr, "Failed to create RFCOMM socket: \n");
2032 print_last_error ();
2033 ExitProcess (2);
2034 }
2035
2036 memset (&addr, 0, sizeof(addr));
2037 // addr.addressFamily = AF_BTH;
2038 if (SOCKET_ERROR ==
2039 WSAStringToAddress (argv[1], AF_BTH, NULL, (LPSOCKADDR) &addr,
2040 &addr_len))
2041 {
2042 fprintf (stderr, "Failed to translate the address: ");
2043 print_last_error ();
2044 ExitProcess (2);
2045 }
2046 addr.port = get_channel (argv[1]);
2047 if (addr.port == -1)
2048 {
2049 fprintf (stderr,
2050 "Couldn't find the sdp service for the address: %s\n",
2051 argv[1]);
2052 memset (write_pout.buf, 0, write_pout.size);
2053 write_pout.size = 0;
2054 broadcast = 1; // skipping the select part
2055 }
2056 else
2057 {
2058 if (GNUNET_OK != GNUNET_NETWORK_socket_connect (sendsocket,
2059 (LPSOCKADDR) &addr,
2060 addr_len))
2061 {
2062 fprintf (stderr, "Failed to connect: ");
2063 print_last_error ();
2064 ExitProcess (2);
2065 }
2066
2067 if (GNUNET_OK != GNUNET_NETWORK_socket_set_blocking (sendsocket, 1))
2068 {
2069 fprintf (stderr, "Failed to change the socket mode\n");
2070 ExitProcess (2);
2071 }
2072
2073 GNUNET_NETWORK_fdset_set (wfds, sendsocket);
2074 }
2075 }
2076 }
2077
2078 if (broadcast == 0)
2079 {
2080 int retval = GNUNET_NETWORK_socket_select (rfds, wfds, NULL,
2081 GNUNET_TIME_relative_get_forever_ ());
2082 if (retval < 0)
2083 {
2084 fprintf (stderr, "Select error\n");
2085 ExitProcess (2);
2086 }
2087 // if (GNUNET_NETWORK_fdset_isset (wfds, (struct GNUNET_NETWORK_Handle*)&stdout_handle))
2088 if (retval == stdout_pos)
2089 {
2090 fprintf (stderr, "LOG : sends a message to STDOUT\n"); // FIXME: debugging message
2091 // ssize_t ret;
2092 // ret = GNUNET_NETWORK_socket_send ((struct GNUNET_NETWORK_Handle *)&stdout_handle, write_std.buf + write_std.pos, write_std.size - write_std.pos);
2093 // ret = write (STDOUT_FILENO, write_std.buf + write_std.pos, write_std.size - write_std.pos);
2094 DWORD ret;
2095 if (FALSE == WriteFile (stdout_handle, write_std.buf + write_std.pos,
2096 write_std.size - write_std.pos, &ret, NULL))
2097 {
2098 fprintf (stderr, "Failed to write to STDOUT: ");
2099 print_last_error ();
2100 break;
2101 }
2102
2103 if (ret <= 0)
2104 {
2105 fprintf (stderr, "Failed to write to STDOUT\n");
2106 ExitProcess (2);
2107 }
2108
2109 write_std.pos += ret;
2110 if (write_std.pos == write_std.size)
2111 {
2112 write_std.pos = 0;
2113 write_std.size = 0;
2114 }
2115 }
2116 if (sendsocket != NULL)
2117 {
2118 if (GNUNET_NETWORK_fdset_isset (wfds, sendsocket))
2119 {
2120 ssize_t ret;
2121 ret = GNUNET_NETWORK_socket_send (sendsocket, write_pout.buf
2122 + write_pout.pos,
2123 write_pout.size - write_pout.pos);
2124
2125 if (GNUNET_SYSERR == ret)
2126 {
2127 fprintf (stderr,
2128 "Failed to send to the socket. Closing the socket. Error: \n");
2129 print_last_error ();
2130 if (GNUNET_NETWORK_socket_close (sendsocket) != GNUNET_OK)
2131 {
2132 fprintf (stderr, "Failed to close the sendsocket!\n");
2133 print_last_error ();
2134 }
2135 ExitProcess (2);
2136 }
2137 else
2138 {
2139 write_pout.pos += ret;
2140 if ((write_pout.pos != write_pout.size) && (0 != ret))
2141 {
2142 /* we should not get partial sends with packet-oriented devices... */
2143 fprintf (stderr, "Write error, partial send: %u/%u\n",
2144 (unsigned int) write_pout.pos,
2145 (unsigned int) write_pout.size);
2146 break;
2147 }
2148
2149 if (write_pout.pos == write_pout.size)
2150 {
2151 write_pout.pos = 0;
2152 write_pout.size = 0;
2153 }
2154 fprintf (stderr, "LOG : sends a message to a DEVICE\n"); // FIXME: debugging message
2155 }
2156 }
2157 }
2158
2159 // if (GNUNET_NETWORK_fdset_isset (rfds, (struct GNUNET_NETWORK_Handle*)&stdin_handle))
2160 if (retval == stdin_pos)
2161 {
2162 // ssize_t ret;
2163 // ret = GNUNET_NETWORK_socket_recv ((struct GNUNET_NETWORK_Handle *)&stdin_handle, readbuf, sizeof (write_pout.buf));
2164 // ret = read (STDIN_FILENO, readbuf, sizeof (readbuf));
2165 DWORD ret;
2166 if (FALSE == ReadFile (stdin_handle, readbuf, sizeof(readbuf), &ret,
2167 NULL)) /* do nothing asynchronous */
2168 {
2169 fprintf (stderr, "Read error from STDIN: ");
2170 print_last_error ();
2171 break;
2172 }
2173 if (0 == ret)
2174 {
2175 /* stop reading... */
2176 stdin_open = 0;
2177 }
2178 else
2179 {
2180 mst_receive (stdin_mst, readbuf, ret);
2181 fprintf (stderr, "LOG : receives a message from STDIN\n"); // FIXME: debugging message
2182 }
2183 }
2184 else if (GNUNET_NETWORK_fdset_isset (rfds, dev.handle))
2185 {
2186 fprintf (stderr, "LOG: accepting connection\n");
2187 struct GNUNET_NETWORK_Handle *readsocket;
2188 readsocket = GNUNET_NETWORK_socket_accept (dev.handle,
2189 (LPSOCKADDR) &acc_addr,
2190 &addr_len);
2191 if (readsocket == NULL)
2192 {
2193 fprintf (stderr, "Accept error %d: ", GetLastError ());
2194 print_last_error ();
2195 ExitProcess (2);
2196 }
2197 else
2198 {
2199 if (GNUNET_OK != GNUNET_NETWORK_socket_set_blocking (readsocket, 1))
2200 {
2201 fprintf (stderr, "Failed to change the socket mode\n");
2202 ExitProcess (2);
2203 }
2204 GNUNET_NETWORK_fdset_set (rfds, readsocket);
2205
2206 if (crt_rfds < MAX_PORTS)
2207 rfds_list[crt_rfds++] = readsocket;
2208 else
2209 {
2210 fprintf (stderr,
2211 "The limit for the read file descriptors list was reached\n");
2212 break;
2213 }
2214 }
2215 }
2216 else
2217 for (i = 0; i < crt_rfds; i++)
2218 {
2219 if (GNUNET_NETWORK_fdset_isset (rfds, rfds_list[i]))
2220 {
2221 struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage *rrm;
2222 ssize_t ret;
2223 fprintf (stderr, "LOG: reading something from the socket\n"); // FIXME : debugging message
2224 rrm = (struct
2225 GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage *) write_std.buf;
2226 ret = read_from_the_socket (rfds_list[i], (unsigned
2227 char *) &rrm->frame,
2228 sizeof(write_std.buf)
2229 - sizeof(struct
2230 GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage)
2231 + sizeof(struct
2232 GNUNET_TRANSPORT_WLAN_Ieee80211Frame),
2233 rrm);
2234 if (0 >= ret)
2235 {
2236 // TODO remove the socket from the list
2237 if (GNUNET_NETWORK_socket_close (rfds_list[i]) != GNUNET_OK)
2238 {
2239 fprintf (stderr, "Failed to close the sendsocket!\n");
2240 print_last_error ();
2241 }
2242
2243 fprintf (stderr, "Read error from raw socket: ");
2244 print_last_error ();
2245 break;
2246 }
2247 if ((0 < ret) && (0 == mac_test (&rrm->frame, &dev)))
2248 {
2249 write_std.size = ret
2250 + sizeof(struct
2251 GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage)
2252 - sizeof(struct
2253 GNUNET_TRANSPORT_WLAN_Ieee80211Frame);
2254 rrm->header.size = htons (write_std.size);
2255 rrm->header.type = htons (
2256 GNUNET_MESSAGE_TYPE_WLAN_DATA_FROM_HELPER);
2257 }
2258 break;
2259 }
2260 }
2261 }
2262 }
2263
2264 mst_destroy (stdin_mst);
2265 stdin_mst = NULL;
2266
2267 if (GNUNET_NETWORK_socket_close (dev.handle) != GNUNET_OK)
2268 {
2269 fprintf (stderr, "Failed to close the socket!\n");
2270 print_last_error ();
2271 }
2272
2273 for (i = 0; i < crt_rfds; i++)
2274 {
2275 if (GNUNET_NETWORK_socket_close (rfds_list[i]) != GNUNET_OK)
2276 {
2277 fprintf (stderr, "Failed to close the socket!\n");
2278 print_last_error ();
2279 }
2280 }
2281
2282 WSACleanup ();
2283 #endif
2284 return 1; /* we never exit 'normally' */
2285}
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 72dd8b594..000000000
--- a/src/transport/gnunet-helper-transport-wlan.c
+++ /dev/null
@@ -1,2184 +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 "gnunet_config.h"
113#include <sys/socket.h>
114#include <sys/ioctl.h>
115#include <sys/types.h>
116#include <unistd.h>
117#include <sys/wait.h>
118#include <sys/time.h>
119#include <sys/stat.h>
120#include <netpacket/packet.h>
121#include <linux/if_ether.h>
122#include <linux/if.h>
123#include <linux/wireless.h>
124#include <netinet/in.h>
125#include <linux/if_tun.h>
126#include <stdio.h>
127#include <stdlib.h>
128#include <string.h>
129#include <stdarg.h>
130#include <fcntl.h>
131#include <errno.h>
132#include <dirent.h>
133#include <sys/param.h>
134#include <unistd.h>
135#include <stdint.h>
136
137#include "gnunet_protocols.h"
138#include "plugin_transport_wlan.h"
139
140/**
141 * Packet format type for the messages we receive from
142 * the kernel. This is for Ethernet 10Mbps format (no
143 * performance information included).
144 */
145#define ARPHRD_ETHER 1
146
147
148/**
149 * Packet format type for the messages we receive from
150 * the kernel. This is for plain messages (with no
151 * performance information included).
152 */
153#define ARPHRD_IEEE80211 801
154
155
156/**
157 * Packet format type for the messages we receive from
158 * the kernel. This is for the PRISM format.
159 */
160#define ARPHRD_IEEE80211_PRISM 802
161
162/**
163 * Packet format type for the messages we receive from
164 * the kernel. This is for messages with a
165 * 'struct Ieee80211RadiotapHeader' (see below).
166 */
167#define ARPHRD_IEEE80211_FULL 803
168
169
170/**
171 * Maximum size of a message allowed in either direction
172 * (used for our receive and sent buffers).
173 */
174#define MAXLINE 4096
175
176
177/* ********* structure of messages of type ARPHRD_IEEE80211_PRISM *********** */
178
179/**
180 * Device name length in PRISM frames.
181 * (In the kernel, this is "WLAN_DEVNAMELEN_MAX")
182 */
183#define PRISM_DEVICE_NAME_LENGTH 16
184
185/**
186 * Monitor Frame (indicator that we have a 'struct PrismHeader').
187 */
188#define PRISM_MSGCODE_MONITOR 0x0041
189
190/**
191 * Mac time element. In micro-seconds.
192 * Drivers appear to use a 64bit counter to hold mactime internal
193 * the then fill the prism header with the lower 32 bits
194 */
195#define PRISM_DID_MACTIME 0x2041
196
197/**
198 * Channel element
199 */
200#define PRISM_DID_CHANNEL 0x3041
201
202/**
203 * Signal element. Should be the signal strength in dbm, some people
204 * suggest that instead "100 - (strength in dbm)" is used (to make this
205 * a positive integer).
206 */
207#define PRISM_DID_SIGNAL 0x6041
208
209/**
210 * Noise element
211 */
212#define PRISM_DID_NOISE 0x7041
213
214/**
215 * Rate element, in units/multiples of 500Khz
216 */
217#define PRISM_DID_RATE 0x8041
218
219
220/**
221 * Value is set (supplied)
222 */
223#define PRISM_STATUS_OK 0
224
225/**
226 * Value not supplied.
227 */
228#define PRISM_STATUS_NO_VALUE 1
229
230
231/**
232 * Values in the 'struct PrismHeader'. All in host byte order (!).
233 */
234struct PrismValue
235{
236 /**
237 * This has a different ID for each parameter, see
238 * PRISM_DID_* constants.
239 */
240 uint32_t did;
241
242 /**
243 * See PRISM_STATUS_*-constants. Note that they are unusual: 0 = set; 1 = not set
244 */
245 uint16_t status;
246
247 /**
248 * length of data (which is always a uint32_t, but presumably this can be used
249 * to specify that fewer bytes are used (with values in 'len' from 0-4). We
250 * ignore this field.
251 */
252 uint16_t len;
253
254 /**
255 * The data value
256 */
257 uint32_t data;
258} __attribute__ ((packed));
259
260
261/**
262 * Prism header format ('struct p80211msg' in Linux). All in host byte order (!).
263 */
264struct PrismHeader
265{
266 /**
267 * We expect this to be a PRISM_MSGCODE_*.
268 */
269 uint32_t msgcode;
270
271 /**
272 * The length of the entire header.
273 */
274 uint32_t msglen;
275
276 /**
277 * Name of the device that captured the packet.
278 */
279 char devname[PRISM_DEVICE_NAME_LENGTH];
280
281 /* followed by 'struct PrismValue's. Documentation suggests that these
282 are typically the hosttime, mactime, channel, rssi, sq, signal, noise,
283 rate, istx and frmlen values, but documentation is sparse. So we
284 will use the 'did' fields to find out what we actually got. */
285} __attribute__ ((packed));
286
287
288/* ****** end of structure of messages of type ARPHRD_IEEE80211_PRISM ******* */
289
290/* ********** structure of messages of type ARPHRD_IEEE80211_FULL *********** */
291
292/**
293 * Bits in the 'it_present' bitmask from the 'struct
294 * Ieee80211RadiotapHeader'. For each value, we give the name, data
295 * type, unit and then a description below. Note that the actual size
296 * of the extension can be bigger as arguments must be padded so that
297 * args of a given length must begin at a boundary of that length.
298 * However, note that compound args are allowed (eg, 2 x uint16_t for
299 * IEEE80211_RADIOTAP_CHANNEL) so total argument length is not a
300 * reliable indicator of alignment requirement. See also
301 * 'man 9 ieee80211_radiotap'.
302 */
303enum RadiotapType
304{
305 /**
306 * IEEE80211_RADIOTAP_TSFT __le64 microseconds
307 *
308 * Value in microseconds of the MAC's 64-bit 802.11 Time
309 * Synchronization Function timer when the first bit of the
310 * MPDU arrived at the MAC. For received frames, only.
311 */
312 IEEE80211_RADIOTAP_TSFT = 0,
313
314 /**
315 * IEEE80211_RADIOTAP_FLAGS uint8_t bitmap
316 *
317 * Properties of transmitted and received frames. See flags
318 * defined below.
319 */
320 IEEE80211_RADIOTAP_FLAGS = 1,
321
322 /**
323 * IEEE80211_RADIOTAP_RATE uint8_t 500kb/s
324 *
325 * Tx/Rx data rate
326 */
327 IEEE80211_RADIOTAP_RATE = 2,
328
329 /**
330 * IEEE80211_RADIOTAP_CHANNEL 2 x __le16 MHz, bitmap
331 *
332 * Tx/Rx frequency in MHz, followed by flags (see below).
333 */
334 IEEE80211_RADIOTAP_CHANNEL = 3,
335 /**
336 * IEEE80211_RADIOTAP_FHSS __le16 see below
337 *
338 * For frequency-hopping radios, the hop set (first byte)
339 * and pattern (second byte).
340 */
341 IEEE80211_RADIOTAP_FHSS = 4,
342
343 /**
344 * IEEE80211_RADIOTAP_DBM_ANTSIGNAL s8 decibels from
345 * one milliwatt (dBm)
346 *
347 * RF signal power at the antenna, decibel difference from
348 * one milliwatt.
349 */
350 IEEE80211_RADIOTAP_DBM_ANTSIGNAL = 5,
351
352 /**
353 * IEEE80211_RADIOTAP_DBM_ANTNOISE s8 decibels from
354 * one milliwatt (dBm)
355 *
356 * RF noise power at the antenna, decibel difference from one
357 * milliwatt.
358 */
359 IEEE80211_RADIOTAP_DBM_ANTNOISE = 6,
360
361 /**
362 * IEEE80211_RADIOTAP_LOCK_QUALITY __le16 unitless
363 *
364 * Quality of Barker code lock. Unitless. Monotonically
365 * nondecreasing with "better" lock strength. Called "Signal
366 * Quality" in datasheets. (Is there a standard way to measure
367 * this?)
368 */
369 IEEE80211_RADIOTAP_LOCK_QUALITY = 7,
370
371 /**
372 * IEEE80211_RADIOTAP_TX_ATTENUATION __le16 unitless
373 *
374 * Transmit power expressed as unitless distance from max
375 * power set at factory calibration. 0 is max power.
376 * Monotonically nondecreasing with lower power levels.
377 */
378 IEEE80211_RADIOTAP_TX_ATTENUATION = 8,
379
380 /**
381 * IEEE80211_RADIOTAP_DB_TX_ATTENUATION __le16 decibels (dB)
382 *
383 * Transmit power expressed as decibel distance from max power
384 * set at factory calibration. 0 is max power. Monotonically
385 * nondecreasing with lower power levels.
386 */
387 IEEE80211_RADIOTAP_DB_TX_ATTENUATION = 9,
388
389 /**
390 * IEEE80211_RADIOTAP_DBM_TX_POWER s8 decibels from
391 * one milliwatt (dBm)
392 *
393 * Transmit power expressed as dBm (decibels from a 1 milliwatt
394 * reference). This is the absolute power level measured at
395 * the antenna port.
396 */
397 IEEE80211_RADIOTAP_DBM_TX_POWER = 10,
398
399 /**
400 * IEEE80211_RADIOTAP_ANTENNA uint8_t antenna index
401 *
402 * Unitless indication of the Rx/Tx antenna for this packet.
403 * The first antenna is antenna 0.
404 */
405 IEEE80211_RADIOTAP_ANTENNA = 11,
406
407 /**
408 * IEEE80211_RADIOTAP_DB_ANTSIGNAL uint8_t decibel (dB)
409 *
410 * RF signal power at the antenna, decibel difference from an
411 * arbitrary, fixed reference.
412 */
413 IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12,
414
415 /**
416 * IEEE80211_RADIOTAP_DB_ANTNOISE uint8_t decibel (dB)
417 *
418 * RF noise power at the antenna, decibel difference from an
419 * arbitrary, fixed reference point.
420 */
421 IEEE80211_RADIOTAP_DB_ANTNOISE = 13,
422
423 /**
424 * IEEE80211_RADIOTAP_RX_FLAGS __le16 bitmap
425 *
426 * Properties of received frames. See flags defined below.
427 */
428 IEEE80211_RADIOTAP_RX_FLAGS = 14,
429
430 /**
431 * IEEE80211_RADIOTAP_TX_FLAGS __le16 bitmap
432 *
433 * Properties of transmitted frames. See flags defined below.
434 */
435 IEEE80211_RADIOTAP_TX_FLAGS = 15,
436
437 /**
438 * IEEE80211_RADIOTAP_RTS_RETRIES uint8_t data
439 *
440 * Number of rts retries a transmitted frame used.
441 */
442 IEEE80211_RADIOTAP_RTS_RETRIES = 16,
443
444 /**
445 * IEEE80211_RADIOTAP_DATA_RETRIES uint8_t data
446 *
447 * Number of unicast retries a transmitted frame used.
448 */
449 IEEE80211_RADIOTAP_DATA_RETRIES = 17,
450
451 /**
452 * Extension bit, used to indicate that more bits are needed for
453 * the bitmask.
454 */
455 IEEE80211_RADIOTAP_EXT = 31
456};
457
458/**
459 * Bitmask indicating an extension of the bitmask is used.
460 * (Mask corresponding to IEEE80211_RADIOTAP_EXT).
461 */
462#define IEEE80211_RADIOTAP_PRESENT_EXTEND_MASK (1 << IEEE80211_RADIOTAP_EXT)
463
464
465/**
466 * Bit in IEEE80211_RADIOTAP_FLAGS (which we might get
467 * as part of a 'struct Ieee80211RadiotapHeader' extension
468 * if the IEEE80211_RADIOTAP_FLAGS bit is set in
469 * 'it_present'). The radiotap flags are an 8-bit field.
470 *
471 * Frame was sent/received during CFP (Contention Free Period)
472 */
473#define IEEE80211_RADIOTAP_F_CFP 0x01
474
475/**
476 * Bit in IEEE80211_RADIOTAP_FLAGS (which we might get
477 * as part of a 'struct Ieee80211RadiotapHeader' extension
478 * if the IEEE80211_RADIOTAP_FLAGS bit is set in
479 * 'it_present'). The radiotap flags are an 8-bit field.
480 *
481 * Frame was sent/received with short preamble
482 */
483#define IEEE80211_RADIOTAP_F_SHORTPRE 0x02
484
485/**
486 * Bit in IEEE80211_RADIOTAP_FLAGS (which we might get
487 * as part of a 'struct Ieee80211RadiotapHeader' extension
488 * if the IEEE80211_RADIOTAP_FLAGS bit is set in
489 * 'it_present'). The radiotap flags are an 8-bit field.
490 *
491 * Frame was sent/received with WEP encryption
492 */
493#define IEEE80211_RADIOTAP_F_WEP 0x04
494
495/**
496 * Bit in IEEE80211_RADIOTAP_FLAGS (which we might get
497 * as part of a 'struct Ieee80211RadiotapHeader' extension
498 * if the IEEE80211_RADIOTAP_FLAGS bit is set in
499 * 'it_present'). The radiotap flags are an 8-bit field.
500 *
501 * Frame was sent/received with fragmentation
502 */
503#define IEEE80211_RADIOTAP_F_FRAG 0x08
504
505/**
506 * Bit in IEEE80211_RADIOTAP_FLAGS (which we might get
507 * as part of a 'struct Ieee80211RadiotapHeader' extension
508 * if the IEEE80211_RADIOTAP_FLAGS bit is set in
509 * 'it_present'). The radiotap flags are an 8-bit field.
510 *
511 * Frame includes FCS (CRC at the end that needs to be removeD).
512 */
513#define IEEE80211_RADIOTAP_F_FCS 0x10
514
515/**
516 * Bit in IEEE80211_RADIOTAP_FLAGS (which we might get
517 * as part of a 'struct Ieee80211RadiotapHeader' extension
518 * if the IEEE80211_RADIOTAP_FLAGS bit is set in
519 * 'it_present'). The radiotap flags are an 8-bit field.
520 *
521 * Frame has padding between 802.11 header and payload
522 * (to 32-bit boundary)
523 */
524#define IEEE80211_RADIOTAP_F_DATAPAD 0x20
525
526
527/**
528 * For IEEE80211_RADIOTAP_RX_FLAGS:
529 * frame failed crc check
530 */
531#define IEEE80211_RADIOTAP_F_RX_BADFCS 0x0001
532
533/**
534 * For IEEE80211_RADIOTAP_TX_FLAGS ('txflags' in 'struct RadiotapTransmissionHeader'):
535 * failed due to excessive retries
536 */
537#define IEEE80211_RADIOTAP_F_TX_FAIL 0x0001
538
539/**
540 * For IEEE80211_RADIOTAP_TX_FLAGS ('txflags' in 'struct RadiotapTransmissionHeader'):
541 * used cts 'protection'
542 */
543#define IEEE80211_RADIOTAP_F_TX_CTS 0x0002
544
545/**
546 * For IEEE80211_RADIOTAP_TX_FLAGS ('txflags' in 'struct RadiotapTransmissionHeader'):
547 * used rts/cts handshake
548 */
549#define IEEE80211_RADIOTAP_F_TX_RTS 0x0004
550
551/**
552 * For IEEE80211_RADIOTAP_TX_FLAGS ('txflags' in 'struct RadiotapTransmissionHeader'):
553 * frame should not be ACKed
554 */
555#define IEEE80211_RADIOTAP_F_TX_NOACK 0x0008
556
557/**
558 * For IEEE80211_RADIOTAP_TX_FLAGS ('txflags' in 'struct RadiotapTransmissionHeader'):
559 * sequence number handled by userspace
560 */
561#define IEEE80211_RADIOTAP_F_TX_NOSEQ 0x0010
562
563
564/**
565 * Generic header for radiotap messages (receiving and sending). A
566 * bit mask (it_present) determines which specific records follow.
567 *
568 * I am trying to describe precisely what the application programmer
569 * should expect in the following, and for that reason I tell the
570 * units and origin of each measurement (where it applies), or else I
571 * use sufficiently weaselly language ("is a monotonically nondecreasing
572 * function of...") that I cannot set false expectations for lawyerly
573 * readers.
574 *
575 * The radio capture header precedes the 802.11 header.
576 * All data in the header is little endian on all platforms.
577 */
578struct Ieee80211RadiotapHeader
579{
580 /**
581 * Version 0. Only increases for drastic changes, introduction of
582 * compatible new fields does not count.
583 */
584 uint8_t it_version;
585
586 /**
587 * Padding. Set to 0.
588 */
589 uint8_t it_pad;
590
591 /**
592 * length of the whole header in bytes, including it_version,
593 * it_pad, it_len, and data fields.
594 */
595 uint16_t it_len;
596
597 /**
598 * A bitmap telling which fields are present. Set bit 31
599 * (0x80000000) to extend the bitmap by another 32 bits. Additional
600 * extensions are made by setting bit 31.
601 */
602 uint32_t it_present;
603};
604
605
606/**
607 * Format of the header we need to prepend to messages to be sent to the
608 * Kernel.
609 */
610struct RadiotapTransmissionHeader
611{
612 /**
613 * First we begin with the 'generic' header we also get when receiving
614 * messages.
615 */
616 struct Ieee80211RadiotapHeader header;
617
618 /**
619 * Transmission rate (we use 0, kernel makes up its mind anyway).
620 */
621 uint8_t rate;
622
623 /**
624 * Padding (we use 0). There is a requirement to pad args, so that
625 * args of a given length must begin at a boundary of that length.
626 * As our next argument is the 'it_len' with 2 bytes, we need 1 byte
627 * of padding.
628 */
629 uint8_t pad1;
630
631 /**
632 * Transmission flags from on the IEEE80211_RADIOTAP_F_TX_* constant family.
633 */
634 uint16_t txflags;
635};
636
637/**
638 * The above 'struct RadiotapTransmissionHeader' should have the
639 * following value for 'header.it_present' based on the presence of
640 * the 'rate' and 'txflags' in the overall struct.
641 */
642#define IEEE80211_RADIOTAP_OUR_TRANSMISSION_HEADER_MASK ((1 \
643 << \
644 IEEE80211_RADIOTAP_RATE) \
645 | (1 \
646 << \
647 IEEE80211_RADIOTAP_TX_FLAGS))
648
649
650/**
651 * struct Ieee80211RadiotapHeaderIterator - tracks walk through present radiotap arguments
652 * in the radiotap header. Used when we parse radiotap packets received from the kernel.
653 */
654struct Ieee80211RadiotapHeaderIterator
655{
656 /**
657 * pointer to the radiotap header we are walking through
658 */
659 const struct Ieee80211RadiotapHeader *rtheader;
660
661 /**
662 * pointer to current radiotap arg
663 */
664 const uint8_t *this_arg;
665
666 /**
667 * internal next argument pointer
668 */
669 const uint8_t *arg;
670
671 /**
672 * internal pointer to next present uint32_t (if IEEE80211_RADIOTAP_EXT is used).
673 */
674 const uint32_t *next_bitmap;
675
676 /**
677 * length of radiotap header in host byte ordering
678 */
679 size_t max_length;
680
681 /**
682 * internal shifter for current uint32_t bitmap, (it_present in host byte order),
683 * If bit 0 is set, the 'arg_index' argument is present.
684 */
685 uint32_t bitmap_shifter;
686
687 /**
688 * IEEE80211_RADIOTAP_... index of current arg
689 */
690 unsigned int this_arg_index;
691
692 /**
693 * internal next argument index
694 */
695 unsigned int arg_index;
696};
697
698
699/* ************** end of structure of ARPHRD_IEEE80211_FULL ************** */
700
701/* ************************** our globals ******************************* */
702
703/**
704 * struct for storing the information of the hardware. There is only
705 * one of these.
706 */
707struct HardwareInfos
708{
709 /**
710 * file descriptor for the raw socket
711 */
712 int fd_raw;
713
714 /**
715 * Which format has the header that we're getting when receiving packets?
716 * Some ARPHRD_IEEE80211_XXX-value.
717 */
718 int arptype_in;
719
720 /**
721 * Name of the interface, not necessarily 0-terminated (!).
722 */
723 char iface[IFNAMSIZ];
724
725 /**
726 * MAC address of our own WLAN interface.
727 */
728 struct GNUNET_TRANSPORT_WLAN_MacAddress pl_mac;
729};
730
731
732/**
733 * IO buffer used for buffering data in transit (to wireless or to stdout).
734 */
735struct SendBuffer
736{
737 /**
738 * How many bytes of data are stored in 'buf' for transmission right now?
739 * Data always starts at offset 0 and extends to 'size'.
740 */
741 size_t size;
742
743 /**
744 * How many bytes that were stored in 'buf' did we already write to the
745 * destination? Always smaller than 'size'.
746 */
747 size_t pos;
748
749 /**
750 * Buffered data; twice the maximum allowed message size as we add some
751 * headers.
752 */
753 char buf[MAXLINE * 2];
754};
755
756
757/**
758 * Buffer for data read from stdin to be transmitted to the wirless card.
759 */
760static struct SendBuffer write_pout;
761
762/**
763 * Buffer for data read from the wireless card to be transmitted to stdout.
764 */
765static struct SendBuffer write_std;
766
767
768/* *********** specialized version of server_mst.c begins here ********** */
769
770/**
771 * To what multiple do we align messages? 8 byte should suffice for everyone
772 * for now.
773 */
774#define ALIGN_FACTOR 8
775
776/**
777 * Smallest supported message.
778 */
779#define MIN_BUFFER_SIZE sizeof(struct GNUNET_MessageHeader)
780
781
782/**
783 * Functions with this signature are called whenever a
784 * complete message is received by the tokenizer.
785 *
786 * @param cls closure
787 * @param message the actual message
788 */
789typedef void (*MessageTokenizerCallback) (void *cls,
790 const struct
791 GNUNET_MessageHeader *
792 message);
793
794/**
795 * Handle to a message stream tokenizer.
796 */
797struct MessageStreamTokenizer
798{
799 /**
800 * Function to call on completed messages.
801 */
802 MessageTokenizerCallback cb;
803
804 /**
805 * Closure for cb.
806 */
807 void *cb_cls;
808
809 /**
810 * Size of the buffer (starting at 'hdr').
811 */
812 size_t curr_buf;
813
814 /**
815 * How many bytes in buffer have we already processed?
816 */
817 size_t off;
818
819 /**
820 * How many bytes in buffer are valid right now?
821 */
822 size_t pos;
823
824 /**
825 * Beginning of the buffer. Typed like this to force alignment.
826 */
827 struct GNUNET_MessageHeader *hdr;
828};
829
830
831/**
832 * Create a message stream tokenizer.
833 *
834 * @param cb function to call on completed messages
835 * @param cb_cls closure for cb
836 * @return handle to tokenizer
837 */
838static struct MessageStreamTokenizer *
839mst_create (MessageTokenizerCallback cb,
840 void *cb_cls)
841{
842 struct MessageStreamTokenizer *ret;
843
844 ret = malloc (sizeof(struct MessageStreamTokenizer));
845 if (NULL == ret)
846 {
847 fprintf (stderr, "Failed to allocate buffer for tokenizer\n");
848 exit (1);
849 }
850 ret->hdr = malloc (MIN_BUFFER_SIZE);
851 if (NULL == ret->hdr)
852 {
853 fprintf (stderr, "Failed to allocate buffer for alignment\n");
854 exit (1);
855 }
856 ret->curr_buf = MIN_BUFFER_SIZE;
857 ret->cb = cb;
858 ret->cb_cls = cb_cls;
859 return ret;
860}
861
862
863/**
864 * Add incoming data to the receive buffer and call the
865 * callback for all complete messages.
866 *
867 * @param mst tokenizer to use
868 * @param buf input data to add
869 * @param size number of bytes in buf
870 * @return GNUNET_OK if we are done processing (need more data)
871 * GNUNET_SYSERR if the data stream is corrupt
872 */
873static int
874mst_receive (struct MessageStreamTokenizer *mst,
875 const char *buf, size_t size)
876{
877 const struct GNUNET_MessageHeader *hdr;
878 size_t delta;
879 uint16_t want;
880 char *ibuf;
881 int need_align;
882 unsigned long offset;
883 int ret;
884
885 ret = GNUNET_OK;
886 ibuf = (char *) mst->hdr;
887 while (mst->pos > 0)
888 {
889do_align:
890 if ((mst->curr_buf - mst->off < sizeof(struct GNUNET_MessageHeader)) ||
891 (0 != (mst->off % ALIGN_FACTOR)))
892 {
893 /* need to align or need more space */
894 mst->pos -= mst->off;
895 memmove (ibuf, &ibuf[mst->off], mst->pos);
896 mst->off = 0;
897 }
898 if (mst->pos - mst->off < sizeof(struct GNUNET_MessageHeader))
899 {
900 delta =
901 GNUNET_MIN (sizeof(struct GNUNET_MessageHeader)
902 - (mst->pos - mst->off), size);
903 GNUNET_memcpy (&ibuf[mst->pos], buf, delta);
904 mst->pos += delta;
905 buf += delta;
906 size -= delta;
907 }
908 if (mst->pos - mst->off < sizeof(struct GNUNET_MessageHeader))
909 {
910 return GNUNET_OK;
911 }
912 hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off];
913 want = ntohs (hdr->size);
914 if (want < sizeof(struct GNUNET_MessageHeader))
915 {
916 fprintf (stderr,
917 "Received invalid message from stdin\n");
918 exit (1);
919 }
920 if (mst->curr_buf - mst->off < want)
921 {
922 /* need more space */
923 mst->pos -= mst->off;
924 memmove (ibuf, &ibuf[mst->off], mst->pos);
925 mst->off = 0;
926 }
927 if (want > mst->curr_buf)
928 {
929 mst->hdr = realloc (mst->hdr, want);
930 if (NULL == mst->hdr)
931 {
932 fprintf (stderr, "Failed to allocate buffer for alignment\n");
933 exit (1);
934 }
935 ibuf = (char *) mst->hdr;
936 mst->curr_buf = want;
937 }
938 hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off];
939 if (mst->pos - mst->off < want)
940 {
941 delta = GNUNET_MIN (want - (mst->pos - mst->off), size);
942 GNUNET_memcpy (&ibuf[mst->pos], buf, delta);
943 mst->pos += delta;
944 buf += delta;
945 size -= delta;
946 }
947 if (mst->pos - mst->off < want)
948 {
949 return GNUNET_OK;
950 }
951 mst->cb (mst->cb_cls, hdr);
952 mst->off += want;
953 if (mst->off == mst->pos)
954 {
955 /* reset to beginning of buffer, it's free right now! */
956 mst->off = 0;
957 mst->pos = 0;
958 }
959 }
960 while (size > 0)
961 {
962 if (size < sizeof(struct GNUNET_MessageHeader))
963 break;
964 offset = (unsigned long) buf;
965 need_align = (0 != offset % ALIGN_FACTOR) ? GNUNET_YES : GNUNET_NO;
966 if (GNUNET_NO == need_align)
967 {
968 /* can try to do zero-copy and process directly from original buffer */
969 hdr = (const struct GNUNET_MessageHeader *) buf;
970 want = ntohs (hdr->size);
971 if (want < sizeof(struct GNUNET_MessageHeader))
972 {
973 fprintf (stderr,
974 "Received invalid message from stdin\n");
975 exit (1);
976 }
977 if (size < want)
978 break; /* or not, buffer incomplete, so copy to private buffer... */
979 mst->cb (mst->cb_cls, hdr);
980 buf += want;
981 size -= want;
982 }
983 else
984 {
985 /* need to copy to private buffer to align;
986 * yes, we go a bit more spaghetti than usual here */
987 goto do_align;
988 }
989 }
990 if (size > 0)
991 {
992 if (size + mst->pos > mst->curr_buf)
993 {
994 mst->hdr = realloc (mst->hdr, size + mst->pos);
995 if (NULL == mst->hdr)
996 {
997 fprintf (stderr, "Failed to allocate buffer for alignment\n");
998 exit (1);
999 }
1000 ibuf = (char *) mst->hdr;
1001 mst->curr_buf = size + mst->pos;
1002 }
1003 if (mst->pos + size > mst->curr_buf)
1004 {
1005 fprintf (stderr,
1006 "Assertion failed\n");
1007 exit (1);
1008 }
1009 GNUNET_memcpy (&ibuf[mst->pos], buf, size);
1010 mst->pos += size;
1011 }
1012 return ret;
1013}
1014
1015
1016/**
1017 * Destroys a tokenizer.
1018 *
1019 * @param mst tokenizer to destroy
1020 */
1021static void
1022mst_destroy (struct MessageStreamTokenizer *mst)
1023{
1024 free (mst->hdr);
1025 free (mst);
1026}
1027
1028
1029/* ***************** end of server_mst.c clone ***************** **/
1030
1031
1032/* ************** code for handling of ARPHRD_IEEE80211_FULL ************** */
1033
1034/**
1035 * Radiotap header iteration
1036 *
1037 * call __ieee80211_radiotap_iterator_init() to init a semi-opaque iterator
1038 * struct Ieee80211RadiotapHeaderIterator (no need to init the struct beforehand)
1039 * then loop calling __ieee80211_radiotap_iterator_next()... it returns -1
1040 * if there are no more args in the header, or the next argument type index
1041 * that is present. The iterator's this_arg member points to the start of the
1042 * argument associated with the current argument index that is present,
1043 * which can be found in the iterator's this_arg_index member. This arg
1044 * index corresponds to the IEEE80211_RADIOTAP_... defines.
1045 *
1046 * @param iterator iterator to initialize
1047 * @param radiotap_header message to parse
1048 * @param max_length number of valid bytes in radiotap_header
1049 * @return 0 on success, -1 on error
1050 */
1051static int
1052ieee80211_radiotap_iterator_init (struct
1053 Ieee80211RadiotapHeaderIterator *iterator,
1054 const struct
1055 Ieee80211RadiotapHeader *radiotap_header,
1056 size_t max_length)
1057{
1058 if ((iterator == NULL) ||
1059 (radiotap_header == NULL))
1060 return -1;
1061
1062 /* Linux only supports version 0 radiotap format */
1063 if (0 != radiotap_header->it_version)
1064 return -1;
1065
1066 /* sanity check for allowed length and radiotap length field */
1067 if ((max_length < sizeof(struct Ieee80211RadiotapHeader)) ||
1068 (max_length < (GNUNET_le16toh (radiotap_header->it_len))))
1069 return -1;
1070
1071 memset (iterator, 0, sizeof(struct Ieee80211RadiotapHeaderIterator));
1072 iterator->rtheader = radiotap_header;
1073 iterator->max_length = GNUNET_le16toh (radiotap_header->it_len);
1074 iterator->bitmap_shifter = GNUNET_le32toh (radiotap_header->it_present);
1075 iterator->arg = ((uint8_t *) radiotap_header) + sizeof(struct
1076 Ieee80211RadiotapHeader);
1077
1078 /* find payload start allowing for extended bitmap(s) */
1079 if (0 != (iterator->bitmap_shifter & IEEE80211_RADIOTAP_PRESENT_EXTEND_MASK))
1080 {
1081 while (GNUNET_le32toh (*((uint32_t *) iterator->arg))
1082 & IEEE80211_RADIOTAP_PRESENT_EXTEND_MASK)
1083 {
1084 iterator->arg += sizeof(uint32_t);
1085 /*
1086 * check for insanity where the present bitmaps
1087 * keep claiming to extend up to or even beyond the
1088 * stated radiotap header length
1089 */if (iterator->arg - ((uint8_t *) iterator->rtheader) >
1090 iterator->max_length)
1091 return -1;
1092 }
1093 iterator->arg += sizeof(uint32_t);
1094 /*
1095 * no need to check again for blowing past stated radiotap
1096 * header length, because ieee80211_radiotap_iterator_next
1097 * checks it before it is dereferenced
1098 */}
1099 /* we are all initialized happily */
1100 return 0;
1101}
1102
1103
1104/**
1105 * Returns the next radiotap parser iterator arg.
1106 *
1107 * This function returns the next radiotap arg index (IEEE80211_RADIOTAP_...)
1108 * and sets iterator->this_arg to point to the payload for the arg. It takes
1109 * care of alignment handling and extended present fields. interator->this_arg
1110 * can be changed by the caller. The args pointed to are in little-endian
1111 * format.
1112 *
1113 * @param iterator: radiotap_iterator to move to next arg (if any)
1114 * @return next present arg index on success or -1 if no more or error
1115 */
1116static int
1117ieee80211_radiotap_iterator_next (struct
1118 Ieee80211RadiotapHeaderIterator *iterator)
1119{
1120 /*
1121 * small length lookup table for all radiotap types we heard of
1122 * starting from b0 in the bitmap, so we can walk the payload
1123 * area of the radiotap header
1124 *
1125 * There is a requirement to pad args, so that args
1126 * of a given length must begin at a boundary of that length
1127 * -- but note that compound args are allowed (eg, 2 x uint16_t
1128 * for IEEE80211_RADIOTAP_CHANNEL) so total arg length is not
1129 * a reliable indicator of alignment requirement.
1130 *
1131 * upper nybble: content alignment for arg
1132 * lower nybble: content length for arg
1133 */static const uint8_t rt_sizes[] = {
1134 [IEEE80211_RADIOTAP_TSFT] = 0x88,
1135 [IEEE80211_RADIOTAP_FLAGS] = 0x11,
1136 [IEEE80211_RADIOTAP_RATE] = 0x11,
1137 [IEEE80211_RADIOTAP_CHANNEL] = 0x24,
1138 [IEEE80211_RADIOTAP_FHSS] = 0x22,
1139 [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = 0x11,
1140 [IEEE80211_RADIOTAP_DBM_ANTNOISE] = 0x11,
1141 [IEEE80211_RADIOTAP_LOCK_QUALITY] = 0x22,
1142 [IEEE80211_RADIOTAP_TX_ATTENUATION] = 0x22,
1143 [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = 0x22,
1144 [IEEE80211_RADIOTAP_DBM_TX_POWER] = 0x11,
1145 [IEEE80211_RADIOTAP_ANTENNA] = 0x11,
1146 [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = 0x11,
1147 [IEEE80211_RADIOTAP_DB_ANTNOISE] = 0x11,
1148 [IEEE80211_RADIOTAP_TX_FLAGS] = 0x22,
1149 [IEEE80211_RADIOTAP_RX_FLAGS] = 0x22,
1150 [IEEE80211_RADIOTAP_RTS_RETRIES] = 0x11,
1151 [IEEE80211_RADIOTAP_DATA_RETRIES] = 0x11
1152 /*
1153 * add more here as they are defined in
1154 * include/net/ieee80211_radiotap.h
1155 */
1156 };
1157
1158 /*
1159 * for every radiotap entry we can at
1160 * least skip (by knowing the length)...
1161 */
1162 while (iterator->arg_index < sizeof(rt_sizes))
1163 {
1164 int hit = (0 != (iterator->bitmap_shifter & 1));
1165
1166 if (hit)
1167 {
1168 unsigned int wanted_alignment;
1169 unsigned int unalignment;
1170 /*
1171 * arg is present, account for alignment padding
1172 * 8-bit args can be at any alignment
1173 * 16-bit args must start on 16-bit boundary
1174 * 32-bit args must start on 32-bit boundary
1175 * 64-bit args must start on 64-bit boundary
1176 *
1177 * note that total arg size can differ from alignment of
1178 * elements inside arg, so we use upper nybble of length table
1179 * to base alignment on. First, 'wanted_alignment' is set to be
1180 * 1 for 8-bit, 2 for 16-bit, 4 for 32-bit and 8 for 64-bit
1181 * arguments. Then, we calculate the 'unalignment' (how many
1182 * bytes we are over by taking the difference of 'arg' and the
1183 * overall starting point modulo the desired alignment. As
1184 * desired alignments are powers of two, we can do modulo with
1185 * binary "&" (and also avoid the possibility of a division by
1186 * zero if the 'rt_sizes' table contains bogus entries).
1187 *
1188 * also note: these alignments are relative to the start of the
1189 * radiotap header. There is no guarantee that the radiotap
1190 * header itself is aligned on any kind of boundary, thus we
1191 * need to really look at the delta here.
1192 */wanted_alignment = rt_sizes[iterator->arg_index] >> 4;
1193 unalignment = (((void *) iterator->arg) - ((void *) iterator->rtheader))
1194 & (wanted_alignment - 1);
1195 if (0 != unalignment)
1196 {
1197 /* need padding (by 'wanted_alignment - unalignment') */
1198 iterator->arg_index += wanted_alignment - unalignment;
1199 }
1200
1201 /*
1202 * this is what we will return to user, but we need to
1203 * move on first so next call has something fresh to test
1204 */
1205 iterator->this_arg_index = iterator->arg_index;
1206 iterator->this_arg = iterator->arg;
1207
1208 /* internally move on the size of this arg (using lower nybble from
1209 the table) */
1210 iterator->arg += rt_sizes[iterator->arg_index] & 0x0f;
1211
1212 /*
1213 * check for insanity where we are given a bitmap that
1214 * claims to have more arg content than the length of the
1215 * radiotap section. We will normally end up equalling this
1216 * max_length on the last arg, never exceeding it.
1217 */if ((((void *) iterator->arg) - ((void *) iterator->rtheader)) >
1218 iterator->max_length)
1219 return -1;
1220 }
1221
1222 /* Now, move on to next bit / next entry */
1223 iterator->arg_index++;
1224
1225 if (0 == (iterator->arg_index % 32))
1226 {
1227 /* completed current uint32_t bitmap */
1228 if (0 != (iterator->bitmap_shifter & 1))
1229 {
1230 /* bit 31 was set, there is more; move to next uint32_t bitmap */
1231 iterator->bitmap_shifter = GNUNET_le32toh (*iterator->next_bitmap);
1232 iterator->next_bitmap++;
1233 }
1234 else
1235 {
1236 /* no more bitmaps: end (by setting arg_index to high, unsupported value) */
1237 iterator->arg_index = sizeof(rt_sizes);
1238 }
1239 }
1240 else
1241 {
1242 /* just try the next bit (while loop will move on) */
1243 iterator->bitmap_shifter >>= 1;
1244 }
1245
1246 /* if we found a valid arg earlier, return it now */
1247 if (hit)
1248 return iterator->this_arg_index;
1249 }
1250
1251 /* we don't know how to handle any more args (or there are no more),
1252 so we're done (this is not an error) */
1253 return -1;
1254}
1255
1256
1257/**
1258 * Calculate crc32, the start of the calculation
1259 *
1260 * @param buf buffer to calc the crc
1261 * @param len len of the buffer
1262 * @return crc sum
1263 */
1264static unsigned long
1265calc_crc_osdep (const unsigned char *buf, size_t len)
1266{
1267 static const unsigned long int crc_tbl_osdep[256] = {
1268 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
1269 0xE963A535, 0x9E6495A3,
1270 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD,
1271 0xE7B82D07, 0x90BF1D91,
1272 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB,
1273 0xF4D4B551, 0x83D385C7,
1274 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
1275 0xFA0F3D63, 0x8D080DF5,
1276 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447,
1277 0xD20D85FD, 0xA50AB56B,
1278 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75,
1279 0xDCD60DCF, 0xABD13D59,
1280 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
1281 0xCFBA9599, 0xB8BDA50F,
1282 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11,
1283 0xC1611DAB, 0xB6662D3D,
1284 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F,
1285 0x9FBFE4A5, 0xE8B8D433,
1286 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
1287 0x91646C97, 0xE6635C01,
1288 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B,
1289 0x8208F4C1, 0xF50FC457,
1290 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49,
1291 0x8CD37CF3, 0xFBD44C65,
1292 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
1293 0xA4D1C46D, 0xD3D6F4FB,
1294 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5,
1295 0xAA0A4C5F, 0xDD0D7CC9,
1296 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3,
1297 0xB966D409, 0xCE61E49F,
1298 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
1299 0xB7BD5C3B, 0xC0BA6CAD,
1300 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF,
1301 0x04DB2615, 0x73DC1683,
1302 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D,
1303 0x0A00AE27, 0x7D079EB1,
1304 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
1305 0x196C3671, 0x6E6B06E7,
1306 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9,
1307 0x17B7BE43, 0x60B08ED5,
1308 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767,
1309 0x3FB506DD, 0x48B2364B,
1310 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
1311 0x316E8EEF, 0x4669BE79,
1312 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703,
1313 0x220216B9, 0x5505262F,
1314 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31,
1315 0x2CD99E8B, 0x5BDEAE1D,
1316 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
1317 0x72076785, 0x05005713,
1318 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D,
1319 0x7CDCEFB7, 0x0BDBDF21,
1320 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B,
1321 0x6FB077E1, 0x18B74777,
1322 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
1323 0x616BFFD3, 0x166CCF45,
1324 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7,
1325 0x4969474D, 0x3E6E77DB,
1326 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5,
1327 0x47B2CF7F, 0x30B5FFE9,
1328 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
1329 0x54DE5729, 0x23D967BF,
1330 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1,
1331 0x5A05DF1B, 0x2D02EF8D
1332 };
1333
1334 unsigned long crc = 0xFFFFFFFF;
1335
1336 for (; len > 0; len--, buf++)
1337 crc = crc_tbl_osdep[(crc ^ *buf) & 0xFF] ^ (crc >> 8);
1338 return(~crc);
1339}
1340
1341
1342/**
1343 * Calculate and check crc of the wlan packet
1344 *
1345 * @param buf buffer of the packet, with len + 4 bytes of data,
1346 * the last 4 bytes being the checksum
1347 * @param len length of the payload in data
1348 * @return 0 on success (checksum matches), 1 on error
1349 */
1350static int
1351check_crc_buf_osdep (const unsigned char *buf, size_t len)
1352{
1353 unsigned long crc;
1354
1355 crc = calc_crc_osdep (buf, len);
1356 buf += len;
1357 if ((((crc) & 0xFF) == buf[0]) && (((crc >> 8) & 0xFF) == buf[1]) &&
1358 ( ((crc >> 16) & 0xFF) == buf[2]) && ( ((crc >> 24) & 0xFF) == buf[3]) )
1359 return 0;
1360 return 1;
1361}
1362
1363
1364/* ************end of code for handling of ARPHRD_IEEE80211_FULL ************** */
1365
1366
1367/* ************beginning of code for reading packets from kernel ************** */
1368
1369/**
1370 * Return the channel from the frequency (in Mhz)
1371 *
1372 * @param frequency of the channel
1373 * @return number of the channel
1374 */
1375static int
1376get_channel_from_frequency (int32_t frequency)
1377{
1378 if ((frequency >= 2412) && (frequency <= 2472))
1379 return (frequency - 2407) / 5;
1380 if (frequency == 2484)
1381 return 14;
1382 if ((frequency >= 5000) && (frequency <= 6100))
1383 return (frequency - 5000) / 5;
1384 return -1;
1385}
1386
1387
1388/**
1389 * Get the channel used by our WLAN interface.
1390 *
1391 * @param dev pointer to the dev struct of the card
1392 * @return channel number, -1 on error
1393 */
1394static int
1395linux_get_channel (const struct HardwareInfos *dev)
1396{
1397 struct iwreq wrq;
1398 int32_t frequency;
1399
1400 memset (&wrq, 0, sizeof(struct iwreq));
1401 strncpy (wrq.ifr_name, dev->iface, IFNAMSIZ);
1402 if (0 > ioctl (dev->fd_raw, SIOCGIWFREQ, &wrq))
1403 return -1;
1404 frequency = wrq.u.freq.m; /* 'iw_freq' defines 'm' as '__s32', so we keep it signed */
1405 if (100000000 < frequency)
1406 frequency /= 100000;
1407 else if (1000000 < frequency)
1408 frequency /= 1000;
1409 if (1000 < frequency)
1410 return get_channel_from_frequency (frequency);
1411 return frequency;
1412}
1413
1414
1415/**
1416 * Read from the raw socket (the wlan card), parse the packet and
1417 * put the result into the buffer for transmission to 'stdout'.
1418 *
1419 * @param dev pointer to the struct of the wlan card
1420 * @param buf buffer to read to; first bytes will be the 'struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame',
1421 * followed by the actual payload
1422 * @param buf_size size of the buffer
1423 * @param ri where to write radiotap_rx info
1424 * @return number of bytes written to 'buf'
1425 */
1426static ssize_t
1427linux_read (struct HardwareInfos *dev,
1428 unsigned char *buf, size_t buf_size,
1429 struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage *ri)
1430{
1431 unsigned char tmpbuf[buf_size];
1432 ssize_t caplen;
1433 size_t n;
1434 int got_signal = 0;
1435 int got_noise = 0;
1436 int got_channel = 0;
1437 int fcs_removed = 0;
1438
1439 caplen = read (dev->fd_raw, tmpbuf, buf_size);
1440 if (0 > caplen)
1441 {
1442 if (EAGAIN == errno)
1443 return 0;
1444 fprintf (stderr, "Failed to read from RAW socket: %s\n", strerror (errno));
1445 return -1;
1446 }
1447
1448 memset (ri, 0, sizeof(*ri));
1449 switch (dev->arptype_in)
1450 {
1451 case ARPHRD_IEEE80211_PRISM:
1452 {
1453 const struct PrismHeader *ph;
1454
1455 ph = (const struct PrismHeader*) tmpbuf;
1456 n = ph->msglen;
1457 if ((n < 8) || (n >= caplen))
1458 return 0; /* invalid format */
1459 if ((PRISM_MSGCODE_MONITOR == ph->msgcode) &&
1460 (n >= sizeof(struct PrismHeader)))
1461 {
1462 const char *pos;
1463 size_t left;
1464 struct PrismValue pv;
1465
1466 left = n - sizeof(struct PrismHeader);
1467 pos = (const char *) &ph[1];
1468 while (left > sizeof(struct PrismValue))
1469 {
1470 left -= sizeof(struct PrismValue);
1471 GNUNET_memcpy (&pv, pos, sizeof(struct PrismValue));
1472 pos += sizeof(struct PrismValue);
1473
1474 switch (pv.did)
1475 {
1476 case PRISM_DID_NOISE:
1477 if (PRISM_STATUS_OK == pv.status)
1478 {
1479 ri->ri_noise = pv.data;
1480 /* got_noise = 1; */
1481 }
1482 break;
1483
1484 case PRISM_DID_RATE:
1485 if (PRISM_STATUS_OK == pv.status)
1486 ri->ri_rate = pv.data * 500000;
1487 break;
1488
1489 case PRISM_DID_CHANNEL:
1490 if (PRISM_STATUS_OK == pv.status)
1491 {
1492 ri->ri_channel = pv.data;
1493 got_channel = 1;
1494 }
1495 break;
1496
1497 case PRISM_DID_MACTIME:
1498 if (PRISM_STATUS_OK == pv.status)
1499 ri->ri_mactime = pv.data;
1500 break;
1501
1502 case PRISM_DID_SIGNAL:
1503 if (PRISM_STATUS_OK == pv.status)
1504 {
1505 ri->ri_power = pv.data;
1506 /* got_signal = 1; */
1507 }
1508 break;
1509 }
1510 }
1511 }
1512 if ((n < 8) || (n >= caplen))
1513 return 0; /* invalid format */
1514 }
1515 break;
1516
1517 case ARPHRD_IEEE80211_FULL:
1518 {
1519 struct Ieee80211RadiotapHeaderIterator iterator;
1520 struct Ieee80211RadiotapHeader *rthdr;
1521
1522 memset (&iterator, 0, sizeof(iterator));
1523 rthdr = (struct Ieee80211RadiotapHeader *) tmpbuf;
1524 n = GNUNET_le16toh (rthdr->it_len);
1525 if ((n < sizeof(struct Ieee80211RadiotapHeader)) || (n >= caplen))
1526 return 0; /* invalid 'it_len' */
1527 if (0 != ieee80211_radiotap_iterator_init (&iterator, rthdr, caplen))
1528 return 0;
1529 /* go through the radiotap arguments we have been given by the driver */
1530 while (0 <= ieee80211_radiotap_iterator_next (&iterator))
1531 {
1532 switch (iterator.this_arg_index)
1533 {
1534 case IEEE80211_RADIOTAP_TSFT:
1535 ri->ri_mactime = GNUNET_le64toh (*((uint64_t *) iterator.this_arg));
1536 break;
1537
1538 case IEEE80211_RADIOTAP_DBM_ANTSIGNAL:
1539 if (! got_signal)
1540 {
1541 ri->ri_power = *((int8_t *) iterator.this_arg);
1542 got_signal = 1;
1543 }
1544 break;
1545
1546 case IEEE80211_RADIOTAP_DB_ANTSIGNAL:
1547 if (! got_signal)
1548 {
1549 ri->ri_power = *((int8_t *) iterator.this_arg);
1550 got_signal = 1;
1551 }
1552 break;
1553
1554 case IEEE80211_RADIOTAP_DBM_ANTNOISE:
1555 if (! got_noise)
1556 {
1557 ri->ri_noise = *((int8_t *) iterator.this_arg);
1558 got_noise = 1;
1559 }
1560 break;
1561
1562 case IEEE80211_RADIOTAP_DB_ANTNOISE:
1563 if (! got_noise)
1564 {
1565 ri->ri_noise = *((int8_t *) iterator.this_arg);
1566 got_noise = 1;
1567 }
1568 break;
1569
1570 case IEEE80211_RADIOTAP_ANTENNA:
1571 ri->ri_antenna = *iterator.this_arg;
1572 break;
1573
1574 case IEEE80211_RADIOTAP_CHANNEL:
1575 ri->ri_channel = *iterator.this_arg;
1576 got_channel = 1;
1577 break;
1578
1579 case IEEE80211_RADIOTAP_RATE:
1580 ri->ri_rate = (*iterator.this_arg) * 500000;
1581 break;
1582
1583 case IEEE80211_RADIOTAP_FLAGS:
1584 {
1585 uint8_t flags = *iterator.this_arg;
1586 /* is the CRC visible at the end? if so, remove */
1587 if (0 != (flags & IEEE80211_RADIOTAP_F_FCS))
1588 {
1589 fcs_removed = 1;
1590 caplen -= sizeof(uint32_t);
1591 }
1592 break;
1593 }
1594
1595 case IEEE80211_RADIOTAP_RX_FLAGS:
1596 {
1597 uint16_t flags = ntohs (*((uint16_t *) iterator.this_arg));
1598 if (0 != (flags & IEEE80211_RADIOTAP_F_RX_BADFCS))
1599 return 0;
1600 }
1601 break;
1602 } /* end of 'switch' */
1603 } /* end of the 'while' loop */
1604 }
1605 break;
1606
1607 case ARPHRD_IEEE80211:
1608 n = 0; /* no header */
1609 break;
1610
1611 case ARPHRD_ETHER:
1612 {
1613 if (sizeof(struct GNUNET_TRANSPORT_WLAN_Ieee8023Frame) > caplen)
1614 return 0; /* invalid */
1615 GNUNET_memcpy (&buf[sizeof(struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame)],
1616 tmpbuf + sizeof(struct
1617 GNUNET_TRANSPORT_WLAN_Ieee8023Frame),
1618 caplen - sizeof(struct
1619 GNUNET_TRANSPORT_WLAN_Ieee8023Frame)
1620 - 4 /* 4 byte FCS */);
1621 return caplen - sizeof(struct GNUNET_TRANSPORT_WLAN_Ieee8023Frame) - 4;
1622 }
1623
1624 default:
1625 errno = ENOTSUP; /* unsupported format */
1626 return -1;
1627 }
1628 caplen -= n;
1629 if (! got_channel)
1630 ri->ri_channel = linux_get_channel (dev);
1631
1632 /* detect CRC32 at the end, even if the flag wasn't set and remove it */
1633 if ((0 == fcs_removed) &&
1634 (0 == check_crc_buf_osdep (tmpbuf + n, caplen - sizeof(uint32_t))))
1635 {
1636 /* NOTE: this heuristic can of course fail if there happens to
1637 be a matching checksum at the end. Would be good to have
1638 some data to see how often this heuristic actually works. */
1639 caplen -= sizeof(uint32_t);
1640 }
1641 /* copy payload to target buffer */
1642 GNUNET_memcpy (buf, tmpbuf + n, caplen);
1643 return caplen;
1644}
1645
1646
1647/* ************end of code for reading packets from kernel ************** */
1648
1649/* ************other helper functions for main start here ************** */
1650
1651
1652/**
1653 * Open the wireless network interface for reading/writing.
1654 *
1655 * @param dev pointer to the device struct
1656 * @return 0 on success
1657 */
1658static int
1659open_device_raw (struct HardwareInfos *dev)
1660{
1661 struct ifreq ifr;
1662 struct iwreq wrq;
1663 struct packet_mreq mr;
1664 struct sockaddr_ll sll;
1665
1666 /* find the interface index */
1667 memset (&ifr, 0, sizeof(ifr));
1668 strncpy (ifr.ifr_name, dev->iface, IFNAMSIZ);
1669 if (-1 == ioctl (dev->fd_raw, SIOCGIFINDEX, &ifr))
1670 {
1671 fprintf (stderr, "ioctl(SIOCGIFINDEX) on interface `%.*s' failed: %s\n",
1672 IFNAMSIZ, dev->iface, strerror (errno));
1673 return 1;
1674 }
1675
1676 /* lookup the hardware type */
1677 memset (&sll, 0, sizeof(sll));
1678 sll.sll_family = AF_PACKET;
1679 sll.sll_ifindex = ifr.ifr_ifindex;
1680 sll.sll_protocol = htons (ETH_P_ALL);
1681 if (-1 == ioctl (dev->fd_raw, SIOCGIFHWADDR, &ifr))
1682 {
1683 fprintf (stderr, "ioctl(SIOCGIFHWADDR) on interface `%.*s' failed: %s\n",
1684 IFNAMSIZ, dev->iface, strerror (errno));
1685 return 1;
1686 }
1687 if (((ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211) &&
1688 (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) &&
1689 (ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211_PRISM) &&
1690 (ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211_FULL)))
1691 {
1692 fprintf (stderr,
1693 "Error: interface `%.*s' is not using a supported hardware address family (got %d)\n",
1694 IFNAMSIZ, dev->iface,
1695 ifr.ifr_hwaddr.sa_family);
1696 return 1;
1697 }
1698
1699 /* lookup iw mode */
1700 memset (&wrq, 0, sizeof(struct iwreq));
1701 strncpy (wrq.ifr_name, dev->iface, IFNAMSIZ);
1702 if (-1 == ioctl (dev->fd_raw, SIOCGIWMODE, &wrq))
1703 {
1704 /* most probably not supported (ie for rtap ipw interface) *
1705 * so just assume its correctly set... */
1706 wrq.u.mode = IW_MODE_MONITOR;
1707 }
1708
1709 if ((wrq.u.mode != IW_MODE_MONITOR) &&
1710 (wrq.u.mode != IW_MODE_ADHOC))
1711 {
1712 fprintf (stderr,
1713 "Error: interface `%.*s' is not in monitor or ad-hoc mode (got %d)\n",
1714 IFNAMSIZ, dev->iface,
1715 wrq.u.mode);
1716 return 1;
1717 }
1718
1719 /* Is interface st to up, broadcast & running ? */
1720 if ((ifr.ifr_flags | IFF_UP | IFF_BROADCAST | IFF_RUNNING) != ifr.ifr_flags)
1721 {
1722 /* Bring interface up */
1723 ifr.ifr_flags |= IFF_UP | IFF_BROADCAST | IFF_RUNNING;
1724
1725 if (-1 == ioctl (dev->fd_raw, SIOCSIFFLAGS, &ifr))
1726 {
1727 fprintf (stderr, "ioctl(SIOCSIFFLAGS) on interface `%.*s' failed: %s\n",
1728 IFNAMSIZ, dev->iface, strerror (errno));
1729 return 1;
1730 }
1731 }
1732
1733 /* bind the raw socket to the interface */
1734 if (-1 == bind (dev->fd_raw, (struct sockaddr *) &sll, sizeof(sll)))
1735 {
1736 fprintf (stderr, "Failed to bind interface `%.*s': %s\n", IFNAMSIZ,
1737 dev->iface, strerror (errno));
1738 return 1;
1739 }
1740
1741 /* lookup the hardware type */
1742 if (-1 == ioctl (dev->fd_raw, SIOCGIFHWADDR, &ifr))
1743 {
1744 fprintf (stderr, "ioctl(SIOCGIFHWADDR) on interface `%.*s' failed: %s\n",
1745 IFNAMSIZ, dev->iface, strerror (errno));
1746 return 1;
1747 }
1748
1749 GNUNET_memcpy (&dev->pl_mac, ifr.ifr_hwaddr.sa_data, MAC_ADDR_SIZE);
1750 dev->arptype_in = ifr.ifr_hwaddr.sa_family;
1751 if ((ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) &&
1752 (ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211) &&
1753 (ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211_PRISM) &&
1754 (ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211_FULL))
1755 {
1756 fprintf (stderr, "Unsupported hardware link type %d on interface `%.*s'\n",
1757 ifr.ifr_hwaddr.sa_family, IFNAMSIZ, dev->iface);
1758 return 1;
1759 }
1760
1761 /* enable promiscuous mode */
1762 memset (&mr, 0, sizeof(mr));
1763 mr.mr_ifindex = sll.sll_ifindex;
1764 mr.mr_type = PACKET_MR_PROMISC;
1765 if (0 !=
1766 setsockopt (dev->fd_raw, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mr,
1767 sizeof(mr)))
1768 {
1769 fprintf (stderr,
1770 "Failed to enable promiscuous mode on interface `%.*s'\n",
1771 IFNAMSIZ,
1772 dev->iface);
1773 return 1;
1774 }
1775 return 0;
1776}
1777
1778
1779/**
1780 * Test if the given interface name really corresponds to a wireless
1781 * device.
1782 *
1783 * @param iface name of the interface
1784 * @return 0 on success, 1 on error
1785 */
1786static int
1787test_wlan_interface (const char *iface)
1788{
1789 char strbuf[512];
1790 struct stat sbuf;
1791 int ret;
1792
1793 ret = snprintf (strbuf, sizeof(strbuf),
1794 "/sys/class/net/%s/phy80211/subsystem",
1795 iface);
1796 if ((ret < 0) || (ret >= sizeof(strbuf)) || (0 != stat (strbuf, &sbuf)))
1797 {
1798 fprintf (stderr,
1799 "Did not find 802.11 interface `%s'. Exiting.\n",
1800 iface);
1801 exit (1);
1802 }
1803 return 0;
1804}
1805
1806
1807/**
1808 * Test incoming packets mac for being our own.
1809 *
1810 * @param taIeeeHeader buffer of the packet
1811 * @param dev the Hardware_Infos struct
1812 * @return 0 if mac belongs to us, 1 if mac is for another target
1813 */
1814static int
1815mac_test (const struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *taIeeeHeader,
1816 const struct HardwareInfos *dev)
1817{
1818 static struct GNUNET_TRANSPORT_WLAN_MacAddress all_zeros;
1819
1820 if ((0 == memcmp (&taIeeeHeader->addr3, &all_zeros, MAC_ADDR_SIZE)) ||
1821 (0 == memcmp (&taIeeeHeader->addr1, &all_zeros, MAC_ADDR_SIZE)))
1822 return 0; /* some drivers set no Macs, then assume it is all for us! */
1823
1824 if (0 != memcmp (&taIeeeHeader->addr3, &mac_bssid_gnunet, MAC_ADDR_SIZE))
1825 return 1; /* not a GNUnet ad-hoc package */
1826 if ((0 == memcmp (&taIeeeHeader->addr1, &dev->pl_mac, MAC_ADDR_SIZE)) ||
1827 (0 == memcmp (&taIeeeHeader->addr1, &bc_all_mac, MAC_ADDR_SIZE)))
1828 return 0; /* for us, or broadcast */
1829 return 1; /* not for us */
1830}
1831
1832
1833/**
1834 * Set the wlan header to sane values to make attacks more difficult
1835 *
1836 * @param taIeeeHeader pointer to the header of the packet
1837 * @param dev pointer to the Hardware_Infos struct
1838 */
1839static void
1840mac_set (struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *taIeeeHeader,
1841 const struct HardwareInfos *dev)
1842{
1843 taIeeeHeader->frame_control = htons (IEEE80211_FC0_TYPE_DATA);
1844 taIeeeHeader->addr2 = dev->pl_mac;
1845 taIeeeHeader->addr3 = mac_bssid_gnunet;
1846}
1847
1848
1849/**
1850 * Process data from the stdin. Takes the message, prepends the
1851 * radiotap transmission header, forces the sender MAC to be correct
1852 * and puts it into our buffer for transmission to the kernel.
1853 *
1854 * @param cls pointer to the device struct ('struct HardwareInfos*')
1855 * @param hdr pointer to the start of the packet
1856 */
1857static void
1858stdin_send_hw (void *cls, const struct GNUNET_MessageHeader *hdr)
1859{
1860 struct HardwareInfos *dev = cls;
1861 const struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *header;
1862 struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *wlanheader;
1863 size_t sendsize;
1864 struct RadiotapTransmissionHeader rtheader;
1865 struct GNUNET_TRANSPORT_WLAN_Ieee8023Frame etheader;
1866
1867 sendsize = ntohs (hdr->size);
1868 if ((sendsize <
1869 sizeof(struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage)) ||
1870 (GNUNET_MESSAGE_TYPE_WLAN_DATA_TO_HELPER != ntohs (hdr->type)))
1871 {
1872 fprintf (stderr, "Received malformed message\n");
1873 exit (1);
1874 }
1875 sendsize -= (sizeof(struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage)
1876 - sizeof(struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame));
1877 if (MAXLINE < sendsize)
1878 {
1879 fprintf (stderr, "Packet too big for buffer\n");
1880 exit (1);
1881 }
1882 header = (const struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *) hdr;
1883 switch (dev->arptype_in)
1884 {
1885 case ARPHRD_IEEE80211_PRISM:
1886 case ARPHRD_IEEE80211_FULL:
1887 case ARPHRD_IEEE80211:
1888 rtheader.header.it_version = 0;
1889 rtheader.header.it_pad = 0;
1890 rtheader.header.it_len = GNUNET_htole16 (sizeof(rtheader));
1891 rtheader.header.it_present = GNUNET_htole16 (
1892 IEEE80211_RADIOTAP_OUR_TRANSMISSION_HEADER_MASK);
1893 rtheader.rate = header->rate;
1894 rtheader.pad1 = 0;
1895 rtheader.txflags = GNUNET_htole16 (IEEE80211_RADIOTAP_F_TX_NOACK
1896 | IEEE80211_RADIOTAP_F_TX_NOSEQ);
1897 GNUNET_memcpy (write_pout.buf, &rtheader, sizeof(rtheader));
1898 GNUNET_memcpy (&write_pout.buf[sizeof(rtheader)], &header->frame, sendsize);
1899 wlanheader = (struct
1900 GNUNET_TRANSPORT_WLAN_Ieee80211Frame *) &write_pout.buf[sizeof(
1901 rtheader)
1902 ];
1903
1904 /* payload contains MAC address, but we don't trust it, so we'll
1905 * overwrite it with OUR MAC address to prevent mischief */
1906 mac_set (wlanheader, dev);
1907 write_pout.size = sendsize + sizeof(rtheader);
1908 break;
1909
1910 case ARPHRD_ETHER:
1911 etheader.dst = header->frame.addr1;
1912 /* etheader.src = header->frame.addr2; --- untrusted input */
1913 etheader.src = dev->pl_mac;
1914 etheader.type = htons (ETH_P_IP);
1915 GNUNET_memcpy (write_pout.buf, &etheader, sizeof(etheader));
1916 GNUNET_memcpy (&write_pout.buf[sizeof(etheader)], &header[1], sendsize
1917 - sizeof(struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame));
1918 write_pout.size = sendsize - sizeof(struct
1919 GNUNET_TRANSPORT_WLAN_Ieee80211Frame)
1920 + sizeof(etheader);
1921 break;
1922
1923 default:
1924 fprintf (stderr,
1925 "Unsupported ARPTYPE!\n");
1926 break;
1927 }
1928}
1929
1930
1931/**
1932 * Main function of the helper. This code accesses a WLAN interface
1933 * in monitoring mode (layer 2) and then forwards traffic in both
1934 * directions between the WLAN interface and stdin/stdout of this
1935 * process. Error messages are written to stdout.
1936 *
1937 * @param argc number of arguments, must be 2
1938 * @param argv arguments only argument is the name of the interface (e.g. 'mon0')
1939 * @return 0 on success (never happens, as we don't return unless aborted), 1 on error
1940 */
1941int
1942main (int argc, char *argv[])
1943{
1944 struct HardwareInfos dev;
1945 char readbuf[MAXLINE];
1946 int maxfd;
1947 fd_set rfds;
1948 fd_set wfds;
1949 int stdin_open;
1950 struct MessageStreamTokenizer *stdin_mst;
1951 int raw_eno;
1952
1953 /* assert privs so we can modify the firewall rules! */
1954 {
1955#ifdef HAVE_SETRESUID
1956 uid_t uid = getuid ();
1957
1958 if (0 != setresuid (uid, 0, 0))
1959 {
1960 fprintf (stderr,
1961 "Failed to setresuid to root: %s\n",
1962 strerror (errno));
1963 return 254;
1964 }
1965#else
1966 if (0 != seteuid (0))
1967 {
1968 fprintf (stderr,
1969 "Failed to seteuid back to root: %s\n", strerror (errno));
1970 return 254;
1971 }
1972#endif
1973 }
1974
1975 /* make use of SGID capabilities on POSIX */
1976 memset (&dev, 0, sizeof(dev));
1977 dev.fd_raw = socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ALL));
1978 raw_eno = errno; /* remember for later */
1979
1980 /* now that we've dropped root rights, we can do error checking */
1981 if (2 != argc)
1982 {
1983 fprintf (stderr,
1984 "You must specify the name of the interface as the first and only argument to this program.\n");
1985 if (-1 != dev.fd_raw)
1986 (void) close (dev.fd_raw);
1987 return 1;
1988 }
1989
1990 if (-1 == dev.fd_raw)
1991 {
1992 fprintf (stderr, "Failed to create raw socket: %s\n", strerror (raw_eno));
1993 return 1;
1994 }
1995 if (dev.fd_raw >= FD_SETSIZE)
1996 {
1997 fprintf (stderr, "File descriptor too large for select (%d > %d)\n",
1998 dev.fd_raw, FD_SETSIZE);
1999 (void) close (dev.fd_raw);
2000 return 1;
2001 }
2002 if (0 != test_wlan_interface (argv[1]))
2003 {
2004 (void) close (dev.fd_raw);
2005 return 1;
2006 }
2007 memcpy (dev.iface, argv[1], IFNAMSIZ);
2008 if (0 != open_device_raw (&dev))
2009 {
2010 (void) close (dev.fd_raw);
2011 return 1;
2012 }
2013
2014 /* drop privs */
2015 {
2016 uid_t uid = getuid ();
2017#ifdef HAVE_SETRESUID
2018 if (0 != setresuid (uid, uid, uid))
2019 {
2020 fprintf (stderr, "Failed to setresuid: %s\n", strerror (errno));
2021 if (-1 != dev.fd_raw)
2022 (void) close (dev.fd_raw);
2023 return 1;
2024 }
2025#else
2026 if (0 != (setuid (uid) | seteuid (uid)))
2027 {
2028 fprintf (stderr, "Failed to setuid: %s\n", strerror (errno));
2029 if (-1 != dev.fd_raw)
2030 (void) close (dev.fd_raw);
2031 return 1;
2032 }
2033#endif
2034 }
2035
2036
2037 /* send MAC address of the WLAN interface to STDOUT first */
2038 {
2039 struct GNUNET_TRANSPORT_WLAN_HelperControlMessage macmsg;
2040
2041 macmsg.hdr.size = htons (sizeof(macmsg));
2042 macmsg.hdr.type = htons (GNUNET_MESSAGE_TYPE_WLAN_HELPER_CONTROL);
2043 GNUNET_memcpy (&macmsg.mac, &dev.pl_mac, sizeof(struct
2044 GNUNET_TRANSPORT_WLAN_MacAddress));
2045 GNUNET_memcpy (write_std.buf, &macmsg, sizeof(macmsg));
2046 write_std.size = sizeof(macmsg);
2047 }
2048
2049 stdin_mst = mst_create (&stdin_send_hw, &dev);
2050 stdin_open = 1;
2051 while (1)
2052 {
2053 maxfd = -1;
2054 FD_ZERO (&rfds);
2055 if ((0 == write_pout.size) && (1 == stdin_open))
2056 {
2057 FD_SET (STDIN_FILENO, &rfds);
2058 maxfd = MAX (maxfd, STDIN_FILENO);
2059 }
2060 if (0 == write_std.size)
2061 {
2062 FD_SET (dev.fd_raw, &rfds);
2063 maxfd = MAX (maxfd, dev.fd_raw);
2064 }
2065 FD_ZERO (&wfds);
2066 if (0 < write_std.size)
2067 {
2068 FD_SET (STDOUT_FILENO, &wfds);
2069 maxfd = MAX (maxfd, STDOUT_FILENO);
2070 }
2071 if (0 < write_pout.size)
2072 {
2073 FD_SET (dev.fd_raw, &wfds);
2074 maxfd = MAX (maxfd, dev.fd_raw);
2075 }
2076 {
2077 int retval = select (maxfd + 1, &rfds, &wfds, NULL, NULL);
2078 if ((-1 == retval) && (EINTR == errno))
2079 continue;
2080 if (0 > retval)
2081 {
2082 fprintf (stderr, "select failed: %s\n", strerror (errno));
2083 break;
2084 }
2085 }
2086 if (FD_ISSET (STDOUT_FILENO, &wfds))
2087 {
2088 ssize_t ret =
2089 write (STDOUT_FILENO, write_std.buf + write_std.pos,
2090 write_std.size - write_std.pos);
2091 if (0 > ret)
2092 {
2093 fprintf (stderr, "Failed to write to STDOUT: %s\n", strerror (errno));
2094 break;
2095 }
2096 write_std.pos += ret;
2097 if (write_std.pos == write_std.size)
2098 {
2099 write_std.pos = 0;
2100 write_std.size = 0;
2101 }
2102 }
2103 if (FD_ISSET (dev.fd_raw, &wfds))
2104 {
2105 ssize_t ret =
2106 write (dev.fd_raw, write_pout.buf + write_pout.pos,
2107 write_pout.size - write_pout.pos);
2108 if (0 > ret)
2109 {
2110 fprintf (stderr, "Failed to write to WLAN device: %s\n",
2111 strerror (errno));
2112 break;
2113 }
2114 write_pout.pos += ret;
2115 if ((write_pout.pos != write_pout.size) && (0 != ret))
2116 {
2117 /* we should not get partial sends with packet-oriented devices... */
2118 fprintf (stderr, "Write error, partial send: %u/%u\n",
2119 (unsigned int) write_pout.pos,
2120 (unsigned int) write_pout.size);
2121 break;
2122 }
2123 if (write_pout.pos == write_pout.size)
2124 {
2125 write_pout.pos = 0;
2126 write_pout.size = 0;
2127 }
2128 }
2129
2130 if (FD_ISSET (STDIN_FILENO, &rfds))
2131 {
2132 ssize_t ret =
2133 read (STDIN_FILENO, readbuf, sizeof(readbuf));
2134 if (0 > ret)
2135 {
2136 fprintf (stderr, "Read error from STDIN: %s\n", strerror (errno));
2137 break;
2138 }
2139 if (0 == ret)
2140 {
2141 /* stop reading... */
2142 stdin_open = 0;
2143 }
2144 mst_receive (stdin_mst, readbuf, ret);
2145 }
2146
2147 if (FD_ISSET (dev.fd_raw, &rfds))
2148 {
2149 struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage *rrm;
2150 ssize_t ret;
2151
2152 rrm = (struct
2153 GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage *) write_std.buf;
2154 ret =
2155 linux_read (&dev, (unsigned char *) &rrm->frame,
2156 sizeof(write_std.buf)
2157 - sizeof(struct
2158 GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage)
2159 + sizeof(struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame),
2160 rrm);
2161 if (0 > ret)
2162 {
2163 fprintf (stderr, "Read error from raw socket: %s\n", strerror (errno));
2164 break;
2165 }
2166 if ((0 < ret) && (0 == mac_test (&rrm->frame, &dev)))
2167 {
2168 write_std.size = ret
2169 + sizeof(struct
2170 GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage)
2171 - sizeof(struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame);
2172 rrm->header.size = htons (write_std.size);
2173 rrm->header.type = htons (GNUNET_MESSAGE_TYPE_WLAN_DATA_FROM_HELPER);
2174 }
2175 }
2176 }
2177 /* Error handling, try to clean up a bit at least */
2178 mst_destroy (stdin_mst);
2179 (void) close (dev.fd_raw);
2180 return 1; /* we never exit 'normally' */
2181}
2182
2183
2184/* end of gnunet-helper-transport-wlan.c */
diff --git a/src/transport/gnunet-service-tng.c b/src/transport/gnunet-service-tng.c
deleted file mode 100644
index 7efe07fda..000000000
--- a/src/transport/gnunet-service-tng.c
+++ /dev/null
@@ -1,11149 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010-2016, 2018, 2019 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-tng.c
22 * @brief main for gnunet-service-tng
23 * @author Christian Grothoff
24 *
25 * TODO:
26 * Implement next:
27 * - review retransmission logic, right now there is no smartness there!
28 * => congestion control, etc [PERFORMANCE-BASICS]
29 *
30 * Optimizations-Statistics:
31 * - Track ACK losses based on ACK-counter [ROUTING]
32 * - Need to track total bandwidth per VirtualLink and adjust how frequently
33 * we send FC messages based on bandwidth-delay-product (and relation
34 * to the window size!). See OPTIMIZE-FC-BDP.
35 * - Consider more statistics in #check_connection_quality() [FIXME-CONQ-STATISTICS]
36 * - Adapt available_fc_window_size, using larger values for high-bandwidth
37 * and high-latency links *if* we have the RAM [GOODPUT / utilization / stalls]
38 * - Set last_window_consum_limit promise properly based on
39 * latency and bandwidth of the respective connection [GOODPUT / utilization / stalls]
40 *
41 * Optimizations-DV:
42 * - When forwarding DV learn messages, if a peer is reached that
43 * has a *bidirectional* link to the origin beyond 1st hop,
44 * do NOT forward it to peers _other_ than the origin, as
45 * there is clearly a better path directly from the origin to
46 * whatever else we could reach.
47 * - When we passively learned DV (with unconfirmed freshness), we
48 * right now add the path to our list but with a zero path_valid_until
49 * time and only use it for unconfirmed routes. However, we could consider
50 * triggering an explicit validation mechanism ourselves, specifically routing
51 * a challenge-response message over the path [ROUTING]
52 * = if available, try to confirm unconfirmed DV paths when trying to establish
53 * virtual link for a `struct IncomingRequest`. (i.e. if DVH is
54 * unconfirmed, incoming requests cause us to try to validate a passively
55 * learned path (requires new message type!))
56 *
57 * Optimizations-Fragmentation:
58 * - Fragments send over a reliable channel could do without the
59 * AcknowledgementUUIDP altogether, as they won't be acked! [BANDWIDTH]
60 * (-> have 2nd type of acknowledgment message; low priority, as we
61 * do not have an MTU-limited *reliable* communicator) [FIXME-FRAG-REL-UUID]
62 * - if messages are below MTU, consider adding ACKs and other stuff
63 * to the same transmission to avoid tiny messages (requires planning at
64 * receiver, and additional MST-style demultiplex at receiver!) [PACKET COUNT]
65 *
66 * Optimizations-internals:
67 * - queue_send_msg by API design has to make a copy
68 * of the payload, and route_message on top of that requires a malloc/free.
69 * Change design to approximate "zero" copy better... [CPU]
70 * - could avoid copying body of message into each fragment and keep
71 * fragments as just pointers into the original message and only
72 * fully build fragments just before transmission (optimization, should
73 * reduce CPU and memory use) [CPU, MEMORY]
74 */
75#include "platform.h"
76#include "gnunet_util_lib.h"
77#include "gnunet_statistics_service.h"
78#include "gnunet_transport_monitor_service.h"
79#include "gnunet_peerstore_service.h"
80#include "gnunet_hello_lib.h"
81#include "gnunet_signatures.h"
82#include "transport.h"
83
84/**
85 * Maximum number of FC retransmissions for a running retransmission task.
86 */
87#define MAX_FC_RETRANSMIT_COUNT 1000
88
89/**
90 * Maximum number of messages we acknowledge together in one
91 * cumulative ACK. Larger values may save a bit of bandwidth.
92 */
93#define MAX_CUMMULATIVE_ACKS 64
94
95/**
96 * What is the 1:n chance that we send a Flow control response when
97 * receiving a flow control message that did not change anything for
98 * us? Basically, this is used in the case where both peers are stuck
99 * on flow control (no window changes), but one might continue sending
100 * flow control messages to the other peer as the first FC message
101 * when things stalled got lost, and then subsequently the other peer
102 * does *usually* not respond as nothing changed. So to ensure that
103 * eventually the FC messages stop, we do send with 1/8th probability
104 * an FC message even if nothing changed. That prevents one peer
105 * being stuck in sending (useless) FC messages "forever".
106 */
107#define FC_NO_CHANGE_REPLY_PROBABILITY 8
108
109/**
110 * What is the size we assume for a read operation in the
111 * absence of an MTU for the purpose of flow control?
112 */
113#define IN_PACKET_SIZE_WITHOUT_MTU 128
114
115/**
116 * Number of slots we keep of historic data for computation of
117 * goodput / message loss ratio.
118 */
119#define GOODPUT_AGING_SLOTS 4
120
121/**
122 * How big is the flow control window size by default;
123 * limits per-neighbour RAM utilization.
124 */
125#define DEFAULT_WINDOW_SIZE (128 * 1024)
126
127/**
128 * For how many incoming connections do we try to create a
129 * virtual link for (at the same time!). This does NOT
130 * limit the number of incoming connections, just the number
131 * for which we are actively trying to find working addresses
132 * in the absence (!) of our own applications wanting the
133 * link to go up.
134 */
135#define MAX_INCOMING_REQUEST 16
136
137/**
138 * Maximum number of peers we select for forwarding DVInit
139 * messages at the same time (excluding initiator).
140 */
141#define MAX_DV_DISCOVERY_SELECTION 16
142
143/**
144 * Window size. How many messages to the same target do we pass
145 * to CORE without a RECV_OK in between? Small values limit
146 * thoughput, large values will increase latency.
147 *
148 * FIXME-OPTIMIZE: find out what good values are experimentally,
149 * maybe set adaptively (i.e. to observed available bandwidth).
150 */
151#define RECV_WINDOW_SIZE 4
152
153/**
154 * Minimum number of hops we should forward DV learn messages
155 * even if they are NOT useful for us in hope of looping
156 * back to the initiator?
157 *
158 * FIXME: allow initiator some control here instead?
159 */
160#define MIN_DV_PATH_LENGTH_FOR_INITIATOR 3
161
162/**
163 * Maximum DV distance allowed ever.
164 */
165#define MAX_DV_HOPS_ALLOWED 16
166
167/**
168 * Maximum number of DV learning activities we may
169 * have pending at the same time.
170 */
171#define MAX_DV_LEARN_PENDING 64
172
173/**
174 * Maximum number of DV paths we keep simultaneously to the same target.
175 */
176#define MAX_DV_PATHS_TO_TARGET 3
177
178/**
179 * If a queue delays the next message by more than this number
180 * of seconds we log a warning. Note: this is for testing,
181 * the value chosen here might be too aggressively low!
182 */
183#define DELAY_WARN_THRESHOLD \
184 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
185
186/**
187 * If a DVBox could not be forwarded after this number of
188 * seconds we drop it.
189 */
190#define DV_FORWARD_TIMEOUT \
191 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
192
193/**
194 * Default value for how long we wait for reliability ack.
195 */
196#define DEFAULT_ACK_WAIT_DURATION \
197 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
198
199/**
200 * We only consider queues as "quality" connections when
201 * suppressing the generation of DV initiation messages if
202 * the latency of the queue is below this threshold.
203 */
204#define DV_QUALITY_RTT_THRESHOLD \
205 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
206
207/**
208 * How long do we consider a DV path valid if we see no
209 * further updates on it? Note: the value chosen here might be too low!
210 */
211#define DV_PATH_VALIDITY_TIMEOUT \
212 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
213
214/**
215 * How long do we cache backchannel (struct Backtalker) information
216 * after a backchannel goes inactive?
217 */
218#define BACKCHANNEL_INACTIVITY_TIMEOUT \
219 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
220
221/**
222 * How long before paths expire would we like to (re)discover DV paths? Should
223 * be below #DV_PATH_VALIDITY_TIMEOUT.
224 */
225#define DV_PATH_DISCOVERY_FREQUENCY \
226 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
227
228/**
229 * How long are ephemeral keys valid?
230 */
231#define EPHEMERAL_VALIDITY \
232 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
233
234/**
235 * How long do we keep partially reassembled messages around before giving up?
236 */
237#define REASSEMBLY_EXPIRATION \
238 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
239
240/**
241 * What is the fastest rate at which we send challenges *if* we keep learning
242 * an address (gossip, DHT, etc.)?
243 */
244#define FAST_VALIDATION_CHALLENGE_FREQ \
245 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
246
247/**
248 * What is the slowest rate at which we send challenges?
249 */
250#define MAX_VALIDATION_CHALLENGE_FREQ \
251 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_DAYS, 1)
252
253/**
254 * How long until we forget about historic accumulators and thus
255 * reset the ACK counter? Should exceed the maximum time an
256 * active connection experiences without an ACK.
257 */
258#define ACK_CUMMULATOR_TIMEOUT \
259 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
260
261/**
262 * What is the non-randomized base frequency at which we
263 * would initiate DV learn messages?
264 */
265#define DV_LEARN_BASE_FREQUENCY GNUNET_TIME_UNIT_MINUTES
266
267/**
268 * How many good connections (confirmed, bi-directional, not DV)
269 * do we need to have to suppress initiating DV learn messages?
270 */
271#define DV_LEARN_QUALITY_THRESHOLD 100
272
273/**
274 * When do we forget an invalid address for sure?
275 */
276#define MAX_ADDRESS_VALID_UNTIL \
277 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MONTHS, 1)
278
279/**
280 * How long do we consider an address valid if we just checked?
281 */
282#define ADDRESS_VALIDATION_LIFETIME \
283 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
284
285/**
286 * What is the maximum frequency at which we do address validation?
287 * A random value between 0 and this value is added when scheduling
288 * the #validation_task (both to ensure we do not validate too often,
289 * and to randomize a bit).
290 */
291#define MIN_DELAY_ADDRESS_VALIDATION GNUNET_TIME_UNIT_MILLISECONDS
292
293/**
294 * How many network RTTs before an address validation expires should we begin
295 * trying to revalidate? (Note that the RTT used here is the one that we
296 * experienced during the last validation, not necessarily the latest RTT
297 * observed).
298 */
299#define VALIDATION_RTT_BUFFER_FACTOR 3
300
301/**
302 * How many messages can we have pending for a given communicator
303 * process before we start to throttle that communicator?
304 *
305 * Used if a communicator might be CPU-bound and cannot handle the traffic.
306 */
307#define COMMUNICATOR_TOTAL_QUEUE_LIMIT 512
308
309/**
310 * How many messages can we have pending for a given queue (queue to
311 * a particular peer via a communicator) process before we start to
312 * throttle that queue?
313 */
314#define QUEUE_LENGTH_LIMIT 32
315
316
317GNUNET_NETWORK_STRUCT_BEGIN
318
319/**
320 * Unique identifier we attach to a message.
321 */
322struct MessageUUIDP
323{
324 /**
325 * Unique value, generated by incrementing the
326 * `message_uuid_ctr` of `struct Neighbour`.
327 */
328 uint64_t uuid GNUNET_PACKED;
329};
330
331
332/**
333 * Unique identifier to map an acknowledgement to a transmission.
334 */
335struct AcknowledgementUUIDP
336{
337 /**
338 * The UUID value.
339 */
340 struct GNUNET_Uuid value;
341};
342
343/**
344 * Outer layer of an encapsulated backchannel message.
345 */
346struct TransportBackchannelEncapsulationMessage
347{
348 /**
349 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION.
350 */
351 struct GNUNET_MessageHeader header;
352
353 /* Followed by *another* message header which is the message to
354 the communicator */
355
356 /* Followed by a 0-terminated name of the communicator */
357};
358
359
360/**
361 * Body by which a peer confirms that it is using an ephemeral key.
362 */
363struct EphemeralConfirmationPS
364{
365 /**
366 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
367 */
368 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
369
370 /**
371 * How long is this signature over the ephemeral key valid?
372 *
373 * Note that the receiver MUST IGNORE the absolute time, and only interpret
374 * the value as a mononic time and reject "older" values than the last one
375 * observed. This is necessary as we do not want to require synchronized
376 * clocks and may not have a bidirectional communication channel.
377 *
378 * Even with this, there is no real guarantee against replay achieved here,
379 * unless the latest timestamp is persisted. While persistence should be
380 * provided via PEERSTORE, we do not consider the mechanism reliable! Thus,
381 * communicators must protect against replay attacks when using backchannel
382 * communication!
383 */
384 struct GNUNET_TIME_AbsoluteNBO sender_monotonic_time;
385
386 /**
387 * Target's peer identity.
388 */
389 struct GNUNET_PeerIdentity target;
390
391 /**
392 * Ephemeral key setup by the sender for @e target, used
393 * to encrypt the payload.
394 */
395 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
396};
397
398
399/**
400 * Plaintext of the variable-size payload that is encrypted
401 * within a `struct TransportBackchannelEncapsulationMessage`
402 */
403struct TransportDVBoxPayloadP
404{
405 /**
406 * Sender's peer identity.
407 */
408 struct GNUNET_PeerIdentity sender;
409
410 /**
411 * Signature of the sender over an
412 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL.
413 */
414 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
415
416 /**
417 * Current monotonic time of the sending transport service. Used to
418 * detect replayed messages. Note that the receiver should remember
419 * a list of the recently seen timestamps and only reject messages
420 * if the timestamp is in the list, or the list is "full" and the
421 * timestamp is smaller than the lowest in the list.
422 *
423 * Like the @e ephemeral_validity, the list of timestamps per peer should be
424 * persisted to guard against replays after restarts.
425 */
426 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
427
428 /* Followed by a `struct GNUNET_MessageHeader` with a message
429 for the target peer */
430};
431
432
433/**
434 * Outer layer of an encapsulated unfragmented application message sent
435 * over an unreliable channel.
436 */
437struct TransportReliabilityBoxMessage
438{
439 /**
440 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX
441 */
442 struct GNUNET_MessageHeader header;
443
444 /**
445 * Number of messages still to be sent before a commulative
446 * ACK is requested. Zero if an ACK is requested immediately.
447 * In NBO. Note that the receiver may send the ACK faster
448 * if it believes that is reasonable.
449 */
450 uint32_t ack_countdown GNUNET_PACKED;
451
452 /**
453 * Unique ID of the message used for signalling receipt of
454 * messages sent over possibly unreliable channels. Should
455 * be a random.
456 */
457 struct AcknowledgementUUIDP ack_uuid;
458};
459
460
461/**
462 * Acknowledgement payload.
463 */
464struct TransportCummulativeAckPayloadP
465{
466 /**
467 * How long was the ACK delayed for generating cumulative ACKs?
468 * Used to calculate the correct network RTT by taking the receipt
469 * time of the ack minus the transmission time of the sender minus
470 * this value.
471 */
472 struct GNUNET_TIME_RelativeNBO ack_delay;
473
474 /**
475 * UUID of a message being acknowledged.
476 */
477 struct AcknowledgementUUIDP ack_uuid;
478};
479
480
481/**
482 * Confirmation that the receiver got a
483 * #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX. Note that the
484 * confirmation may be transmitted over a completely different queue,
485 * so ACKs are identified by a combination of PID of sender and
486 * message UUID, without the queue playing any role!
487 */
488struct TransportReliabilityAckMessage
489{
490 /**
491 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK
492 */
493 struct GNUNET_MessageHeader header;
494
495 /**
496 * Counter of ACKs transmitted by the sender to us. Incremented
497 * by one for each ACK, used to detect how many ACKs were lost.
498 */
499 uint32_t ack_counter GNUNET_PACKED;
500
501 /* followed by any number of `struct TransportCummulativeAckPayloadP`
502 messages providing ACKs */
503};
504
505
506/**
507 * Outer layer of an encapsulated fragmented application message.
508 */
509struct TransportFragmentBoxMessage
510{
511 /**
512 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT
513 */
514 struct GNUNET_MessageHeader header;
515
516 /**
517 * Offset of this fragment in the overall message.
518 */
519 uint16_t frag_off GNUNET_PACKED;
520
521 /**
522 * Total size of the message that is being fragmented.
523 */
524 uint16_t msg_size GNUNET_PACKED;
525
526 /**
527 * Unique ID of this fragment (and fragment transmission!). Will
528 * change even if a fragment is retransmitted to make each
529 * transmission attempt unique! If a client receives a duplicate
530 * fragment (same @e frag_off for same @a msg_uuid, it must send
531 * #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK immediately.
532 */
533 struct AcknowledgementUUIDP ack_uuid;
534
535 /**
536 * Original message ID for of the message that all the fragments
537 * belong to. Must be the same for all fragments.
538 */
539 struct MessageUUIDP msg_uuid;
540};
541
542
543/**
544 * Content signed by the initator during DV learning.
545 *
546 * The signature is required to prevent DDoS attacks. A peer sending out this
547 * message is potentially generating a lot of traffic that will go back to the
548 * initator, as peers receiving this message will try to let the initiator
549 * know that they got the message.
550 *
551 * Without this signature, an attacker could abuse this mechanism for traffic
552 * amplification, sending a lot of traffic to a peer by putting out this type
553 * of message with the victim's peer identity.
554 *
555 * Even with just a signature, traffic amplification would be possible via
556 * replay attacks. The @e monotonic_time limits such replay attacks, as every
557 * potential amplificator will check the @e monotonic_time and only respond
558 * (at most) once per message.
559 */
560struct DvInitPS
561{
562 /**
563 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
564 */
565 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
566
567 /**
568 * Time at the initiator when generating the signature.
569 *
570 * Note that the receiver MUST IGNORE the absolute time, and only interpret
571 * the value as a mononic time and reject "older" values than the last one
572 * observed. This is necessary as we do not want to require synchronized
573 * clocks and may not have a bidirectional communication channel.
574 *
575 * Even with this, there is no real guarantee against replay achieved here,
576 * unless the latest timestamp is persisted. Persistence should be
577 * provided via PEERSTORE if possible.
578 */
579 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
580
581 /**
582 * Challenge value used by the initiator to re-identify the path.
583 */
584 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
585};
586
587
588/**
589 * Content signed by each peer during DV learning.
590 *
591 * This assues the initiator of the DV learning operation that the hop from @e
592 * pred via the signing peer to @e succ actually exists. This makes it
593 * impossible for an adversary to supply the network with bogus routes.
594 *
595 * The @e challenge is included to provide replay protection for the
596 * initiator. This way, the initiator knows that the hop existed after the
597 * original @e challenge was first transmitted, providing a freshness metric.
598 *
599 * Peers other than the initiator that passively learn paths by observing
600 * these messages do NOT benefit from this. Here, an adversary may indeed
601 * replay old messages. Thus, passively learned paths should always be
602 * immediately marked as "potentially stale".
603 */
604struct DvHopPS
605{
606 /**
607 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
608 */
609 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
610
611 /**
612 * Identity of the previous peer on the path.
613 */
614 struct GNUNET_PeerIdentity pred;
615
616 /**
617 * Identity of the next peer on the path.
618 */
619 struct GNUNET_PeerIdentity succ;
620
621 /**
622 * Challenge value used by the initiator to re-identify the path.
623 */
624 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
625};
626
627
628/**
629 * An entry describing a peer on a path in a
630 * `struct TransportDVLearnMessage` message.
631 */
632struct DVPathEntryP
633{
634 /**
635 * Identity of a peer on the path.
636 */
637 struct GNUNET_PeerIdentity hop;
638
639 /**
640 * Signature of this hop over the path, of purpose
641 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
642 */
643 struct GNUNET_CRYPTO_EddsaSignature hop_sig;
644};
645
646
647/**
648 * Internal message used by transport for distance vector learning.
649 * If @e num_hops does not exceed the threshold, peers should append
650 * themselves to the peer list and flood the message (possibly only
651 * to a subset of their neighbours to limit discoverability of the
652 * network topology). To the extend that the @e bidirectional bits
653 * are set, peers may learn the inverse paths even if they did not
654 * initiate.
655 *
656 * Unless received on a bidirectional queue and @e num_hops just
657 * zero, peers that can forward to the initator should always try to
658 * forward to the initiator.
659 */
660struct TransportDVLearnMessage
661{
662 /**
663 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN
664 */
665 struct GNUNET_MessageHeader header;
666
667 /**
668 * Number of hops this messages has travelled, in NBO. Zero if
669 * sent by initiator.
670 */
671 uint16_t num_hops GNUNET_PACKED;
672
673 /**
674 * Bitmask of the last 16 hops indicating whether they are confirmed
675 * available (without DV) in both directions or not, in NBO. Used
676 * to possibly instantly learn a path in both directions. Each peer
677 * should shift this value by one to the left, and then set the
678 * lowest bit IF the current sender can be reached from it (without
679 * DV routing).
680 */
681 uint16_t bidirectional GNUNET_PACKED;
682
683 /**
684 * Peers receiving this message and delaying forwarding to other
685 * peers for any reason should increment this value by the non-network
686 * delay created by the peer.
687 */
688 struct GNUNET_TIME_RelativeNBO non_network_delay;
689
690 /**
691 * Time at the initiator when generating the signature.
692 *
693 * Note that the receiver MUST IGNORE the absolute time, and only interpret
694 * the value as a mononic time and reject "older" values than the last one
695 * observed. This is necessary as we do not want to require synchronized
696 * clocks and may not have a bidirectional communication channel.
697 *
698 * Even with this, there is no real guarantee against replay achieved here,
699 * unless the latest timestamp is persisted. Persistence should be
700 * provided via PEERSTORE if possible.
701 */
702 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
703
704 /**
705 * Signature of this hop over the path, of purpose
706 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
707 */
708 struct GNUNET_CRYPTO_EddsaSignature init_sig;
709
710 /**
711 * Identity of the peer that started this learning activity.
712 */
713 struct GNUNET_PeerIdentity initiator;
714
715 /**
716 * Challenge value used by the initiator to re-identify the path.
717 */
718 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
719
720 /* Followed by @e num_hops `struct DVPathEntryP` values,
721 excluding the initiator of the DV trace; the last entry is the
722 current sender; the current peer must not be included. */
723};
724
725
726/**
727 * Outer layer of an encapsulated message send over multiple hops.
728 * The path given only includes the identities of the subsequent
729 * peers, i.e. it will be empty if we are the receiver. Each
730 * forwarding peer should scan the list from the end, and if it can,
731 * forward to the respective peer. The list should then be shortened
732 * by all the entries up to and including that peer. Each hop should
733 * also increment @e total_hops to allow the receiver to get a precise
734 * estimate on the number of hops the message travelled. Senders must
735 * provide a learned path that thus should work, but intermediaries
736 * know of a shortcut, they are allowed to send the message via that
737 * shortcut.
738 *
739 * If a peer finds itself still on the list, it must drop the message.
740 *
741 * The payload of the box can only be decrypted and verified by the
742 * ultimate receiver. Intermediaries do not learn the sender's
743 * identity and the path the message has taken. However, the first
744 * hop does learn the sender as @e total_hops would be zero and thus
745 * the predecessor must be the origin (so this is not really useful
746 * for anonymization).
747 */
748struct TransportDVBoxMessage
749{
750 /**
751 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX
752 */
753 struct GNUNET_MessageHeader header;
754
755 /**
756 * Flag if the payload is a control message. In NBO.
757 */
758 unsigned int without_fc;
759
760 /**
761 * Number of total hops this messages travelled. In NBO.
762 * @e origin sets this to zero, to be incremented at
763 * each hop. Peers should limit the @e total_hops value
764 * they accept from other peers.
765 */
766 uint16_t total_hops GNUNET_PACKED;
767
768 /**
769 * Number of hops this messages includes. In NBO. Reduced by one
770 * or more at each hop. Peers should limit the @e num_hops value
771 * they accept from other peers.
772 */
773 uint16_t num_hops GNUNET_PACKED;
774
775 /**
776 * Ephemeral key setup by the sender for target, used to encrypt the
777 * payload. Intermediaries must not change this value.
778 */
779 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
780
781 /**
782 * We use an IV here as the @e ephemeral_key is re-used for
783 * #EPHEMERAL_VALIDITY time to avoid re-signing it all the time.
784 * Intermediaries must not change this value.
785 */
786 struct GNUNET_ShortHashCode iv;
787
788 /**
789 * HMAC over the ciphertext of the encrypted, variable-size body
790 * that follows. Verified via DH of target and @e ephemeral_key.
791 * Intermediaries must not change this value.
792 */
793 struct GNUNET_HashCode hmac;
794
795 /**
796 * Size this msg had initially. This is needed to calculate the hmac at the target.
797 * The header size can not be used for that, because the box size is getting smaller at each hop.
798 */
799 /**
800 * The length of the struct (in bytes, including the length field itself),
801 * in big-endian format.
802 */
803 uint16_t orig_size GNUNET_PACKED;
804
805 /* Followed by @e num_hops `struct GNUNET_PeerIdentity` values;
806 excluding the @e origin and the current peer, the last must be
807 the ultimate target; if @e num_hops is zero, the receiver of this
808 message is the ultimate target. */
809
810 /* Followed by encrypted, variable-size payload, which
811 must begin with a `struct TransportDVBoxPayloadP` */
812
813 /* Followed by the actual message, which itself must not be a
814 a DV_LEARN or DV_BOX message! */
815};
816
817
818/**
819 * Message send to another peer to validate that it can indeed
820 * receive messages at a particular address.
821 */
822struct TransportValidationChallengeMessage
823{
824 /**
825 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE
826 */
827 struct GNUNET_MessageHeader header;
828
829 /**
830 * Always zero.
831 */
832 uint32_t reserved GNUNET_PACKED;
833
834 /**
835 * Challenge to be signed by the receiving peer.
836 */
837 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
838
839 /**
840 * Timestamp of the sender, to be copied into the reply to allow
841 * sender to calculate RTT. Must be monotonically increasing!
842 */
843 struct GNUNET_TIME_AbsoluteNBO sender_time;
844};
845
846
847/**
848 * Message signed by a peer to confirm that it can indeed
849 * receive messages at a particular address.
850 */
851struct TransportValidationPS
852{
853 /**
854 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE
855 */
856 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
857
858 /**
859 * How long does the sender believe the address on
860 * which the challenge was received to remain valid?
861 */
862 struct GNUNET_TIME_RelativeNBO validity_duration;
863
864 /**
865 * Challenge signed by the receiving peer.
866 */
867 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
868};
869
870
871/**
872 * Message send to a peer to respond to a
873 * #GNUNET_MESSAGE_TYPE_ADDRESS_VALIDATION_CHALLENGE
874 */
875struct TransportValidationResponseMessage
876{
877 /**
878 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE
879 */
880 struct GNUNET_MessageHeader header;
881
882 /**
883 * Always zero.
884 */
885 uint32_t reserved GNUNET_PACKED;
886
887 /**
888 * The peer's signature matching the
889 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE purpose.
890 */
891 struct GNUNET_CRYPTO_EddsaSignature signature;
892
893 /**
894 * The challenge that was signed by the receiving peer.
895 */
896 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
897
898 /**
899 * Original timestamp of the sender (was @code{sender_time}),
900 * copied into the reply to allow sender to calculate RTT.
901 */
902 struct GNUNET_TIME_AbsoluteNBO origin_time;
903
904 /**
905 * How long does the sender believe this address to remain
906 * valid?
907 */
908 struct GNUNET_TIME_RelativeNBO validity_duration;
909};
910
911
912/**
913 * Message for Transport-to-Transport Flow control. Specifies the size
914 * of the flow control window, including how much we believe to have
915 * consumed (at transmission time), how much we believe to be allowed
916 * (at transmission time), and how much the other peer is allowed to
917 * send to us, and how much data we already received from the other
918 * peer.
919 */
920struct TransportFlowControlMessage
921{
922 /**
923 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL
924 */
925 struct GNUNET_MessageHeader header;
926
927 /**
928 * Sequence number of the flow control message. Incremented by one
929 * for each message. Starts at zero when a virtual link goes up.
930 * Used to detect one-sided connection drops. On wrap-around, the
931 * flow control counters will be reset as if the connection had
932 * dropped.
933 */
934 uint32_t seq GNUNET_PACKED;
935
936 /**
937 * Flow control window size in bytes, in NBO.
938 * The receiver can send this many bytes at most.
939 */
940 uint64_t inbound_window_size GNUNET_PACKED;
941
942 /**
943 * How many bytes has the sender sent that count for flow control at
944 * this time. Used to allow the receiver to estimate the packet
945 * loss rate.
946 */
947 uint64_t outbound_sent GNUNET_PACKED;
948
949 /**
950 * Latest flow control window size we learned from the other peer,
951 * in bytes, in NBO. We are limited to sending at most this many
952 * bytes to the other peer. May help the other peer detect when
953 * flow control messages were lost and should thus be retransmitted.
954 * In particular, if the delta to @e outbound_sent is too small,
955 * this signals that we are stalled.
956 */
957 uint64_t outbound_window_size GNUNET_PACKED;
958
959 /**
960 * Timestamp of the sender. Must be monotonically increasing!
961 * Used to enable receiver to ignore out-of-order packets in
962 * combination with the @e seq. Note that @e seq will go down
963 * (back to zero) whenever either side believes the connection
964 * was dropped, allowing the peers to detect that they need to
965 * reset the counters for the number of bytes sent!
966 */
967 struct GNUNET_TIME_AbsoluteNBO sender_time;
968};
969
970
971GNUNET_NETWORK_STRUCT_END
972
973
974/**
975 * What type of client is the `struct TransportClient` about?
976 */
977enum ClientType
978{
979 /**
980 * We do not know yet (client is fresh).
981 */
982 CT_NONE = 0,
983
984 /**
985 * Is the CORE service, we need to forward traffic to it.
986 */
987 CT_CORE = 1,
988
989 /**
990 * It is a monitor, forward monitor data.
991 */
992 CT_MONITOR = 2,
993
994 /**
995 * It is a communicator, use for communication.
996 */
997 CT_COMMUNICATOR = 3,
998
999 /**
1000 * "Application" telling us where to connect (i.e. TOPOLOGY, DHT or CADET).
1001 */
1002 CT_APPLICATION = 4
1003};
1004
1005
1006/**
1007 * Which transmission options are allowable for transmission?
1008 * Interpreted bit-wise!
1009 */
1010enum RouteMessageOptions
1011{
1012 /**
1013 * Only confirmed, non-DV direct neighbours.
1014 */
1015 RMO_NONE = 0,
1016
1017 /**
1018 * We are allowed to use DV routing for this @a hdr
1019 */
1020 RMO_DV_ALLOWED = 1,
1021
1022 /**
1023 * We are allowed to use unconfirmed queues or DV routes for this message
1024 */
1025 RMO_UNCONFIRMED_ALLOWED = 2,
1026
1027 /**
1028 * Reliable and unreliable, DV and non-DV are all acceptable.
1029 */
1030 RMO_ANYTHING_GOES = (RMO_DV_ALLOWED | RMO_UNCONFIRMED_ALLOWED),
1031
1032 /**
1033 * If we have multiple choices, it is OK to send this message
1034 * over multiple channels at the same time to improve loss tolerance.
1035 * (We do at most 2 transmissions.)
1036 */
1037 RMO_REDUNDANT = 4
1038};
1039
1040
1041/**
1042 * When did we launch this DV learning activity?
1043 */
1044struct LearnLaunchEntry
1045{
1046 /**
1047 * Kept (also) in a DLL sorted by launch time.
1048 */
1049 struct LearnLaunchEntry *prev;
1050
1051 /**
1052 * Kept (also) in a DLL sorted by launch time.
1053 */
1054 struct LearnLaunchEntry *next;
1055
1056 /**
1057 * Challenge that uniquely identifies this activity.
1058 */
1059 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
1060
1061 /**
1062 * When did we transmit the DV learn message (used to calculate RTT) and
1063 * determine freshness of paths learned via this operation.
1064 */
1065 struct GNUNET_TIME_Absolute launch_time;
1066};
1067
1068
1069/**
1070 * Information we keep per #GOODPUT_AGING_SLOTS about historic
1071 * (or current) transmission performance.
1072 */
1073struct TransmissionHistoryEntry
1074{
1075 /**
1076 * Number of bytes actually sent in the interval.
1077 */
1078 uint64_t bytes_sent;
1079
1080 /**
1081 * Number of bytes received and acknowledged by the other peer in
1082 * the interval.
1083 */
1084 uint64_t bytes_received;
1085};
1086
1087
1088/**
1089 * Performance data for a transmission possibility.
1090 */
1091struct PerformanceData
1092{
1093 /**
1094 * Weighted average for the RTT.
1095 */
1096 struct GNUNET_TIME_Relative aged_rtt;
1097
1098 /**
1099 * Historic performance data, using a ring buffer of#GOODPUT_AGING_SLOTS
1100 * entries.
1101 */
1102 struct TransmissionHistoryEntry the[GOODPUT_AGING_SLOTS];
1103
1104 /**
1105 * What was the last age when we wrote to @e the? Used to clear
1106 * old entries when the age advances.
1107 */
1108 unsigned int last_age;
1109};
1110
1111
1112/**
1113 * Client connected to the transport service.
1114 */
1115struct TransportClient;
1116
1117/**
1118 * A neighbour that at least one communicator is connected to.
1119 */
1120struct Neighbour;
1121
1122/**
1123 * Entry in our #dv_routes table, representing a (set of) distance
1124 * vector routes to a particular peer.
1125 */
1126struct DistanceVector;
1127
1128/**
1129 * A queue is a message queue provided by a communicator
1130 * via which we can reach a particular neighbour.
1131 */
1132struct Queue;
1133
1134/**
1135 * Message awaiting transmission. See detailed comments below.
1136 */
1137struct PendingMessage;
1138
1139/**
1140 * One possible hop towards a DV target.
1141 */
1142struct DistanceVectorHop;
1143
1144/**
1145 * A virtual link is another reachable peer that is known to CORE. It
1146 * can be either a `struct Neighbour` with at least one confirmed
1147 * `struct Queue`, or a `struct DistanceVector` with at least one
1148 * confirmed `struct DistanceVectorHop`. With a virtual link we track
1149 * data that is per neighbour that is not specific to how the
1150 * connectivity is established.
1151 */
1152struct VirtualLink;
1153
1154
1155/**
1156 * Context from #handle_incoming_msg(). Closure for many
1157 * message handlers below.
1158 */
1159struct CommunicatorMessageContext
1160{
1161 /**
1162 * Kept in a DLL of `struct VirtualLink` if waiting for CORE
1163 * flow control to unchoke.
1164 */
1165 struct CommunicatorMessageContext *next;
1166
1167 /**
1168 * Kept in a DLL of `struct VirtualLink` if waiting for CORE
1169 * flow control to unchoke.
1170 */
1171 struct CommunicatorMessageContext *prev;
1172
1173 /**
1174 * Which communicator provided us with the message.
1175 */
1176 struct TransportClient *tc;
1177
1178 /**
1179 * Additional information for flow control and about the sender.
1180 */
1181 struct GNUNET_TRANSPORT_IncomingMessage im;
1182
1183 /**
1184 * Number of hops the message has travelled (if DV-routed).
1185 * FIXME: make use of this in ACK handling!
1186 */
1187 uint16_t total_hops;
1188};
1189
1190
1191/**
1192 * Closure for #core_env_sent_cb.
1193 */
1194struct CoreSentContext
1195{
1196 /**
1197 * Kept in a DLL to clear @e vl in case @e vl is lost.
1198 */
1199 struct CoreSentContext *next;
1200
1201 /**
1202 * Kept in a DLL to clear @e vl in case @e vl is lost.
1203 */
1204 struct CoreSentContext *prev;
1205
1206 /**
1207 * Virtual link this is about.
1208 */
1209 struct VirtualLink *vl;
1210
1211 /**
1212 * How big was the message.
1213 */
1214 uint16_t size;
1215
1216 /**
1217 * By how much should we increment @e vl's
1218 * incoming_fc_window_size_used once we are done sending to CORE?
1219 * Use to ensure we do not increment twice if there is more than one
1220 * CORE client.
1221 */
1222 uint16_t isize;
1223};
1224
1225
1226/**
1227 * Information we keep for a message that we are reassembling.
1228 */
1229struct ReassemblyContext
1230{
1231 /**
1232 * Original message ID for of the message that all the fragments
1233 * belong to.
1234 */
1235 struct MessageUUIDP msg_uuid;
1236
1237 /**
1238 * Which neighbour is this context for?
1239 */
1240 struct VirtualLink *virtual_link;
1241
1242 /**
1243 * Entry in the reassembly heap (sorted by expiration).
1244 */
1245 struct GNUNET_CONTAINER_HeapNode *hn;
1246
1247 /**
1248 * Bitfield with @e msg_size bits representing the positions
1249 * where we have received fragments. When we receive a fragment,
1250 * we check the bits in @e bitfield before incrementing @e msg_missing.
1251 *
1252 * Allocated after the reassembled message.
1253 */
1254 uint8_t *bitfield;
1255
1256 /**
1257 * At what time will we give up reassembly of this message?
1258 */
1259 struct GNUNET_TIME_Absolute reassembly_timeout;
1260
1261 /**
1262 * Time we received the last fragment. @e avg_ack_delay must be
1263 * incremented by now - @e last_frag multiplied by @e num_acks.
1264 */
1265 struct GNUNET_TIME_Absolute last_frag;
1266
1267 /**
1268 * How big is the message we are reassembling in total?
1269 */
1270 uint16_t msg_size;
1271
1272 /**
1273 * How many bytes of the message are still missing? Defragmentation
1274 * is complete when @e msg_missing == 0.
1275 */
1276 uint16_t msg_missing;
1277
1278 /* Followed by @e msg_size bytes of the (partially) defragmented original
1279 * message */
1280
1281 /* Followed by @e bitfield data */
1282};
1283
1284
1285/**
1286 * A virtual link is another reachable peer that is known to CORE. It
1287 * can be either a `struct Neighbour` with at least one confirmed
1288 * `struct Queue`, or a `struct DistanceVector` with at least one
1289 * confirmed `struct DistanceVectorHop`. With a virtual link we track
1290 * data that is per neighbour that is not specific to how the
1291 * connectivity is established.
1292 */
1293struct VirtualLink
1294{
1295 /**
1296 * Identity of the peer at the other end of the link.
1297 */
1298 struct GNUNET_PeerIdentity target;
1299
1300 /**
1301 * Map with `struct ReassemblyContext` structs for fragments under
1302 * reassembly. May be NULL if we currently have no fragments from
1303 * this @e pid (lazy initialization).
1304 */
1305 struct GNUNET_CONTAINER_MultiHashMap32 *reassembly_map;
1306
1307 /**
1308 * Heap with `struct ReassemblyContext` structs for fragments under
1309 * reassembly. May be NULL if we currently have no fragments from
1310 * this @e pid (lazy initialization).
1311 */
1312 struct GNUNET_CONTAINER_Heap *reassembly_heap;
1313
1314 /**
1315 * Task to free old entries from the @e reassembly_heap and @e reassembly_map.
1316 */
1317 struct GNUNET_SCHEDULER_Task *reassembly_timeout_task;
1318
1319 /**
1320 * Communicators blocked for receiving on @e target as we are waiting
1321 * on the @e core_recv_window to increase.
1322 */
1323 struct CommunicatorMessageContext *cmc_head;
1324
1325 /**
1326 * Communicators blocked for receiving on @e target as we are waiting
1327 * on the @e core_recv_window to increase.
1328 */
1329 struct CommunicatorMessageContext *cmc_tail;
1330
1331 /**
1332 * Head of list of messages pending for this VL.
1333 */
1334 struct PendingMessage *pending_msg_head;
1335
1336 /**
1337 * Tail of list of messages pending for this VL.
1338 */
1339 struct PendingMessage *pending_msg_tail;
1340
1341 /**
1342 * Kept in a DLL to clear @e vl in case @e vl is lost.
1343 */
1344 struct CoreSentContext *csc_tail;
1345
1346 /**
1347 * Kept in a DLL to clear @e vl in case @e vl is lost.
1348 */
1349 struct CoreSentContext *csc_head;
1350
1351 /**
1352 * Task scheduled to possibly notfiy core that this peer is no
1353 * longer counting as confirmed. Runs the #core_visibility_check(),
1354 * which checks that some DV-path or a queue exists that is still
1355 * considered confirmed.
1356 */
1357 struct GNUNET_SCHEDULER_Task *visibility_task;
1358
1359 /**
1360 * Task scheduled to periodically retransmit FC messages (in
1361 * case one got lost).
1362 */
1363 struct GNUNET_SCHEDULER_Task *fc_retransmit_task;
1364
1365 /**
1366 * Number of FC retransmissions for this running task.
1367 */
1368 unsigned int fc_retransmit_count;
1369
1370 /**
1371 * Is this VirtualLink confirmed.
1372 * A unconfirmed VirtualLink might exist, if we got a FC from that target.
1373 */
1374 unsigned int confirmed;
1375
1376 /**
1377 * Neighbour used by this virtual link, NULL if @e dv is used.
1378 */
1379 struct Neighbour *n;
1380
1381 /**
1382 * Distance vector used by this virtual link, NULL if @e n is used.
1383 */
1384 struct DistanceVector *dv;
1385
1386 /**
1387 * Sender timestamp of @e n_challenge, used to generate out-of-order
1388 * challenges (as sender's timestamps must be monotonically
1389 * increasing). FIXME: where do we need this?
1390 */
1391 struct GNUNET_TIME_Absolute n_challenge_time;
1392
1393 /**
1394 * When did we last send a
1395 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL message?
1396 * Used to determine whether it is time to re-transmit the message.
1397 */
1398 struct GNUNET_TIME_Absolute last_fc_transmission;
1399
1400 /**
1401 * Sender timestamp of the last
1402 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL message we have
1403 * received. Note that we do not persist this monotonic time as we
1404 * do not really have to worry about ancient flow control window
1405 * sizes after restarts.
1406 */
1407 struct GNUNET_TIME_Absolute last_fc_timestamp;
1408
1409 /**
1410 * Expected RTT from the last FC transmission. (Zero if the last
1411 * attempt failed, but could theoretically be zero even on success.)
1412 */
1413 struct GNUNET_TIME_Relative last_fc_rtt;
1414
1415 /**
1416 * Used to generate unique UUIDs for messages that are being
1417 * fragmented.
1418 */
1419 uint64_t message_uuid_ctr;
1420
1421 /**
1422 * Memory allocated for this virtual link. Expresses how much RAM
1423 * we are willing to allocate to this virtual link. OPTIMIZE-ME:
1424 * Can be adapted to dedicate more RAM to links that need it, while
1425 * sticking to some overall RAM limit. For now, set to
1426 * #DEFAULT_WINDOW_SIZE.
1427 */
1428 uint64_t available_fc_window_size;
1429
1430 /**
1431 * Memory actually used to buffer packets on this virtual link.
1432 * Expresses how much RAM we are currently using for virtual link.
1433 * Note that once CORE is done with a packet, we decrement the value
1434 * here.
1435 */
1436 uint64_t incoming_fc_window_size_ram;
1437
1438 /**
1439 * Last flow control window size we provided to the other peer, in
1440 * bytes. We are allowing the other peer to send this
1441 * many bytes.
1442 */
1443 uint64_t incoming_fc_window_size;
1444
1445 /**
1446 * How much of the window did the other peer successfully use (and
1447 * we already passed it on to CORE)? Must be below @e
1448 * incoming_fc_window_size. We should effectively signal the
1449 * other peer that the window is this much bigger at the next
1450 * opportunity / challenge.
1451 */
1452 uint64_t incoming_fc_window_size_used;
1453
1454 /**
1455 * What is our current estimate on the message loss rate for the sender?
1456 * Based on the difference between how much the sender sent according
1457 * to the last #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL message
1458 * (@e outbound_sent field) and how much we actually received at that
1459 * time (@e incoming_fc_window_size_used). This delta is then
1460 * added onto the @e incoming_fc_window_size when determining the
1461 * @e outbound_window_size we send to the other peer. Initially zero.
1462 * May be negative if we (due to out-of-order delivery) actually received
1463 * more than the sender claims to have sent in its last FC message.
1464 */
1465 int64_t incoming_fc_window_size_loss;
1466
1467 /**
1468 * Our current flow control window size in bytes. We
1469 * are allowed to transmit this many bytes to @a n.
1470 */
1471 uint64_t outbound_fc_window_size;
1472
1473 /**
1474 * How much of our current flow control window size have we
1475 * used (in bytes). Must be below
1476 * @e outbound_fc_window_size.
1477 */
1478 uint64_t outbound_fc_window_size_used;
1479
1480 /**
1481 * What is the most recent FC window the other peer sent us
1482 * in `outbound_window_size`? This is basically the window
1483 * size value the other peer has definitively received from
1484 * us. If it matches @e incoming_fc_window_size, we should
1485 * not send a FC message to increase the FC window. However,
1486 * we may still send an FC message to notify the other peer
1487 * that we received the other peer's FC message.
1488 */
1489 uint64_t last_outbound_window_size_received;
1490
1491 /**
1492 * Generator for the sequence numbers of
1493 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL messages we send.
1494 */
1495 uint32_t fc_seq_gen;
1496
1497 /**
1498 * Last sequence number of a
1499 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL message we have
1500 * received.
1501 */
1502 uint32_t last_fc_seq;
1503
1504 /**
1505 * How many more messages can we send to CORE before we exhaust
1506 * the receive window of CORE for this peer? If this hits zero,
1507 * we must tell communicators to stop providing us more messages
1508 * for this peer. In fact, the window can go negative as we
1509 * have multiple communicators, so per communicator we can go
1510 * down by one into the negative range. Furthermore, we count
1511 * delivery per CORE client, so if we had multiple cores, that
1512 * might also cause a negative window size here (as one message
1513 * would decrement the window by one per CORE client).
1514 */
1515 int core_recv_window;
1516};
1517
1518
1519/**
1520 * Data structure kept when we are waiting for an acknowledgement.
1521 */
1522struct PendingAcknowledgement
1523{
1524 /**
1525 * If @e pm is non-NULL, this is the DLL in which this acknowledgement
1526 * is kept in relation to its pending message.
1527 */
1528 struct PendingAcknowledgement *next_pm;
1529
1530 /**
1531 * If @e pm is non-NULL, this is the DLL in which this acknowledgement
1532 * is kept in relation to its pending message.
1533 */
1534 struct PendingAcknowledgement *prev_pm;
1535
1536 /**
1537 * If @e queue is non-NULL, this is the DLL in which this acknowledgement
1538 * is kept in relation to the queue that was used to transmit the
1539 * @a pm.
1540 */
1541 struct PendingAcknowledgement *next_queue;
1542
1543 /**
1544 * If @e queue is non-NULL, this is the DLL in which this acknowledgement
1545 * is kept in relation to the queue that was used to transmit the
1546 * @a pm.
1547 */
1548 struct PendingAcknowledgement *prev_queue;
1549
1550 /**
1551 * If @e dvh is non-NULL, this is the DLL in which this acknowledgement
1552 * is kept in relation to the DVH that was used to transmit the
1553 * @a pm.
1554 */
1555 struct PendingAcknowledgement *next_dvh;
1556
1557 /**
1558 * If @e dvh is non-NULL, this is the DLL in which this acknowledgement
1559 * is kept in relation to the DVH that was used to transmit the
1560 * @a pm.
1561 */
1562 struct PendingAcknowledgement *prev_dvh;
1563
1564 /**
1565 * Pointers for the DLL of all pending acknowledgements.
1566 * This list is sorted by @e transmission time. If the list gets too
1567 * long, the oldest entries are discarded.
1568 */
1569 struct PendingAcknowledgement *next_pa;
1570
1571 /**
1572 * Pointers for the DLL of all pending acknowledgements.
1573 * This list is sorted by @e transmission time. If the list gets too
1574 * long, the oldest entries are discarded.
1575 */
1576 struct PendingAcknowledgement *prev_pa;
1577
1578 /**
1579 * Unique identifier for this transmission operation.
1580 */
1581 struct AcknowledgementUUIDP ack_uuid;
1582
1583 /**
1584 * Message that was transmitted, may be NULL if the message was ACKed
1585 * via another channel.
1586 */
1587 struct PendingMessage *pm;
1588
1589 /**
1590 * Distance vector path chosen for this transmission, NULL if transmission
1591 * was to a direct neighbour OR if the path was forgotten in the meantime.
1592 */
1593 struct DistanceVectorHop *dvh;
1594
1595 /**
1596 * Queue used for transmission, NULL if the queue has been destroyed
1597 * (which may happen before we get an acknowledgement).
1598 */
1599 struct Queue *queue;
1600
1601 /**
1602 * Time of the transmission, for RTT calculation.
1603 */
1604 struct GNUNET_TIME_Absolute transmission_time;
1605
1606 /**
1607 * Number of bytes of the original message (to calculate bandwidth).
1608 */
1609 uint16_t message_size;
1610};
1611
1612
1613/**
1614 * One possible hop towards a DV target.
1615 */
1616struct DistanceVectorHop
1617{
1618 /**
1619 * Kept in a MDLL, sorted by @e timeout.
1620 */
1621 struct DistanceVectorHop *next_dv;
1622
1623 /**
1624 * Kept in a MDLL, sorted by @e timeout.
1625 */
1626 struct DistanceVectorHop *prev_dv;
1627
1628 /**
1629 * Kept in a MDLL.
1630 */
1631 struct DistanceVectorHop *next_neighbour;
1632
1633 /**
1634 * Kept in a MDLL.
1635 */
1636 struct DistanceVectorHop *prev_neighbour;
1637
1638 /**
1639 * Head of DLL of PAs that used our @a path.
1640 */
1641 struct PendingAcknowledgement *pa_head;
1642
1643 /**
1644 * Tail of DLL of PAs that used our @a path.
1645 */
1646 struct PendingAcknowledgement *pa_tail;
1647
1648 /**
1649 * What would be the next hop to @e target?
1650 */
1651 struct Neighbour *next_hop;
1652
1653 /**
1654 * Distance vector entry this hop belongs with.
1655 */
1656 struct DistanceVector *dv;
1657
1658 /**
1659 * Array of @e distance hops to the target, excluding @e next_hop.
1660 * NULL if the entire path is us to @e next_hop to `target`. Allocated
1661 * at the end of this struct. Excludes the target itself!
1662 */
1663 const struct GNUNET_PeerIdentity *path;
1664
1665 /**
1666 * At what time do we forget about this path unless we see it again
1667 * while learning?
1668 */
1669 struct GNUNET_TIME_Absolute timeout;
1670
1671 /**
1672 * For how long is the validation of this path considered
1673 * valid?
1674 * Set to ZERO if the path is learned by snooping on DV learn messages
1675 * initiated by other peers, and to the time at which we generated the
1676 * challenge for DV learn operations this peer initiated.
1677 */
1678 struct GNUNET_TIME_Absolute path_valid_until;
1679
1680 /**
1681 * Performance data for this transmission possibility.
1682 */
1683 struct PerformanceData pd;
1684
1685 /**
1686 * Number of hops in total to the `target` (excluding @e next_hop and `target`
1687 * itself). Thus 0 still means a distance of 2 hops (to @e next_hop and then
1688 * to `target`).
1689 */
1690 unsigned int distance;
1691};
1692
1693
1694/**
1695 * Entry in our #dv_routes table, representing a (set of) distance
1696 * vector routes to a particular peer.
1697 */
1698struct DistanceVector
1699{
1700 /**
1701 * To which peer is this a route?
1702 */
1703 struct GNUNET_PeerIdentity target;
1704
1705 /**
1706 * Known paths to @e target.
1707 */
1708 struct DistanceVectorHop *dv_head;
1709
1710 /**
1711 * Known paths to @e target.
1712 */
1713 struct DistanceVectorHop *dv_tail;
1714
1715 /**
1716 * Task scheduled to purge expired paths from @e dv_head MDLL.
1717 */
1718 struct GNUNET_SCHEDULER_Task *timeout_task;
1719
1720 /**
1721 * Do we have a confirmed working queue and are thus visible to
1722 * CORE? If so, this is the virtual link, otherwise NULL.
1723 */
1724 struct VirtualLink *vl;
1725
1726 /**
1727 * Signature affirming @e ephemeral_key of type
1728 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
1729 */
1730 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
1731
1732 /**
1733 * How long is @e sender_sig valid
1734 */
1735 struct GNUNET_TIME_Absolute ephemeral_validity;
1736
1737 /**
1738 * What time was @e sender_sig created
1739 */
1740 struct GNUNET_TIME_Absolute monotime;
1741
1742 /**
1743 * Our ephemeral key.
1744 */
1745 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
1746
1747 /**
1748 * Our private ephemeral key.
1749 */
1750 struct GNUNET_CRYPTO_EcdhePrivateKey private_key;
1751};
1752
1753
1754/**
1755 * Entry identifying transmission in one of our `struct
1756 * Queue` which still awaits an ACK. This is used to
1757 * ensure we do not overwhelm a communicator and limit the number of
1758 * messages outstanding per communicator (say in case communicator is
1759 * CPU bound) and per queue (in case bandwidth allocation exceeds
1760 * what the communicator can actually provide towards a particular
1761 * peer/target).
1762 */
1763struct QueueEntry
1764{
1765 /**
1766 * Kept as a DLL.
1767 */
1768 struct QueueEntry *next;
1769
1770 /**
1771 * Kept as a DLL.
1772 */
1773 struct QueueEntry *prev;
1774
1775 /**
1776 * Queue this entry is queued with.
1777 */
1778 struct Queue *queue;
1779
1780 /**
1781 * Pending message this entry is for, or NULL for none.
1782 */
1783 struct PendingMessage *pm;
1784
1785 /**
1786 * Message ID used for this message with the queue used for transmission.
1787 */
1788 uint64_t mid;
1789};
1790
1791
1792/**
1793 * A queue is a message queue provided by a communicator
1794 * via which we can reach a particular neighbour.
1795 */
1796struct Queue
1797{
1798 /**
1799 * Kept in a MDLL.
1800 */
1801 struct Queue *next_neighbour;
1802
1803 /**
1804 * Kept in a MDLL.
1805 */
1806 struct Queue *prev_neighbour;
1807
1808 /**
1809 * Kept in a MDLL.
1810 */
1811 struct Queue *prev_client;
1812
1813 /**
1814 * Kept in a MDLL.
1815 */
1816 struct Queue *next_client;
1817
1818 /**
1819 * Head of DLL of PAs that used this queue.
1820 */
1821 struct PendingAcknowledgement *pa_head;
1822
1823 /**
1824 * Tail of DLL of PAs that used this queue.
1825 */
1826 struct PendingAcknowledgement *pa_tail;
1827
1828 /**
1829 * Head of DLL of unacked transmission requests.
1830 */
1831 struct QueueEntry *queue_head;
1832
1833 /**
1834 * End of DLL of unacked transmission requests.
1835 */
1836 struct QueueEntry *queue_tail;
1837
1838 /**
1839 * Which neighbour is this queue for?
1840 */
1841 struct Neighbour *neighbour;
1842
1843 /**
1844 * Which communicator offers this queue?
1845 */
1846 struct TransportClient *tc;
1847
1848 /**
1849 * Address served by the queue.
1850 */
1851 const char *address;
1852
1853 /**
1854 * Is this queue of unlimited length.
1855 */
1856 unsigned int unlimited_length;
1857
1858 /**
1859 * Task scheduled for the time when this queue can (likely) transmit the
1860 * next message.
1861 */
1862 struct GNUNET_SCHEDULER_Task *transmit_task;
1863
1864 /**
1865 * How long do *we* consider this @e address to be valid? In the past or
1866 * zero if we have not yet validated it. Can be updated based on
1867 * challenge-response validations (via address validation logic), or when we
1868 * receive ACKs that we can definitively map to transmissions via this
1869 * queue.
1870 */
1871 struct GNUNET_TIME_Absolute validated_until;
1872
1873 /**
1874 * Performance data for this queue.
1875 */
1876 struct PerformanceData pd;
1877
1878 /**
1879 * Message ID generator for transmissions on this queue to the
1880 * communicator.
1881 */
1882 uint64_t mid_gen;
1883
1884 /**
1885 * Unique identifier of this queue with the communicator.
1886 */
1887 uint32_t qid;
1888
1889 /**
1890 * Maximum transmission unit supported by this queue.
1891 */
1892 uint32_t mtu;
1893
1894 /**
1895 * Messages pending.
1896 */
1897 uint32_t num_msg_pending;
1898
1899 /**
1900 * Bytes pending.
1901 */
1902 uint32_t num_bytes_pending;
1903
1904 /**
1905 * Length of the DLL starting at @e queue_head.
1906 */
1907 unsigned int queue_length;
1908
1909 /**
1910 * Capacity of the queue.
1911 */
1912 uint64_t q_capacity;
1913
1914 /**
1915 * Queue priority
1916 */
1917 uint32_t priority;
1918
1919 /**
1920 * Network type offered by this queue.
1921 */
1922 enum GNUNET_NetworkType nt;
1923
1924 /**
1925 * Connection status for this queue.
1926 */
1927 enum GNUNET_TRANSPORT_ConnectionStatus cs;
1928
1929 /**
1930 * Set to #GNUNET_YES if this queue is idle waiting for some
1931 * virtual link to give it a pending message.
1932 */
1933 int idle;
1934};
1935
1936
1937/**
1938 * A neighbour that at least one communicator is connected to.
1939 */
1940struct Neighbour
1941{
1942 /**
1943 * Which peer is this about?
1944 */
1945 struct GNUNET_PeerIdentity pid;
1946
1947 /**
1948 * Head of MDLL of DV hops that have this neighbour as next hop. Must be
1949 * purged if this neighbour goes down.
1950 */
1951 struct DistanceVectorHop *dv_head;
1952
1953 /**
1954 * Tail of MDLL of DV hops that have this neighbour as next hop. Must be
1955 * purged if this neighbour goes down.
1956 */
1957 struct DistanceVectorHop *dv_tail;
1958
1959 /**
1960 * Head of DLL of queues to this peer.
1961 */
1962 struct Queue *queue_head;
1963
1964 /**
1965 * Tail of DLL of queues to this peer.
1966 */
1967 struct Queue *queue_tail;
1968
1969 /**
1970 * Handle for an operation to fetch @e last_dv_learn_monotime information from
1971 * the PEERSTORE, or NULL.
1972 */
1973 struct GNUNET_PEERSTORE_IterateContext *get;
1974
1975 /**
1976 * Handle to a PEERSTORE store operation to store this @e pid's @e
1977 * @e last_dv_learn_monotime. NULL if no PEERSTORE operation is pending.
1978 */
1979 struct GNUNET_PEERSTORE_StoreContext *sc;
1980
1981 /**
1982 * Do we have a confirmed working queue and are thus visible to
1983 * CORE? If so, this is the virtual link, otherwise NULL.
1984 */
1985 struct VirtualLink *vl;
1986
1987 /**
1988 * Latest DVLearn monotonic time seen from this peer. Initialized only
1989 * if @e dl_monotime_available is #GNUNET_YES.
1990 */
1991 struct GNUNET_TIME_Absolute last_dv_learn_monotime;
1992
1993 /**
1994 * Do we have the latest value for @e last_dv_learn_monotime from
1995 * PEERSTORE yet, or are we still waiting for a reply of PEERSTORE?
1996 */
1997 int dv_monotime_available;
1998};
1999
2000
2001/**
2002 * Another peer attempted to talk to us, we should try to establish
2003 * a connection in the other direction.
2004 */
2005struct IncomingRequest
2006{
2007 /**
2008 * Kept in a DLL.
2009 */
2010 struct IncomingRequest *next;
2011
2012 /**
2013 * Kept in a DLL.
2014 */
2015 struct IncomingRequest *prev;
2016
2017 /**
2018 * Handle for watching the peerstore for HELLOs for this peer.
2019 */
2020 struct GNUNET_PEERSTORE_WatchContext *wc;
2021
2022 /**
2023 * Which peer is this about?
2024 */
2025 struct GNUNET_PeerIdentity pid;
2026};
2027
2028
2029/**
2030 * A peer that an application (client) would like us to talk to directly.
2031 */
2032struct PeerRequest
2033{
2034 /**
2035 * Which peer is this about?
2036 */
2037 struct GNUNET_PeerIdentity pid;
2038
2039 /**
2040 * Client responsible for the request.
2041 */
2042 struct TransportClient *tc;
2043
2044 /**
2045 * Handle for watching the peerstore for HELLOs for this peer.
2046 */
2047 struct GNUNET_PEERSTORE_WatchContext *wc;
2048
2049 /**
2050 * What kind of performance preference does this @e tc have?
2051 *
2052 * TODO: use this!
2053 */
2054 enum GNUNET_MQ_PriorityPreferences pk;
2055
2056 /**
2057 * How much bandwidth would this @e tc like to see?
2058 */
2059 struct GNUNET_BANDWIDTH_Value32NBO bw;
2060};
2061
2062
2063/**
2064 * Types of different pending messages.
2065 */
2066enum PendingMessageType
2067{
2068 /**
2069 * Ordinary message received from the CORE service.
2070 */
2071 PMT_CORE = 0,
2072
2073 /**
2074 * Fragment box.
2075 */
2076 PMT_FRAGMENT_BOX = 1,
2077
2078 /**
2079 * Reliability box.
2080 */
2081 PMT_RELIABILITY_BOX = 2,
2082
2083 /**
2084 * Pending message created during #forward_dv_box().
2085 */
2086 PMT_DV_BOX = 3
2087};
2088
2089
2090/**
2091 * Transmission request that is awaiting delivery. The original
2092 * transmission requests from CORE may be too big for some queues.
2093 * In this case, a *tree* of fragments is created. At each
2094 * level of the tree, fragments are kept in a DLL ordered by which
2095 * fragment should be sent next (at the head). The tree is searched
2096 * top-down, with the original message at the root.
2097 *
2098 * To select a node for transmission, first it is checked if the
2099 * current node's message fits with the MTU. If it does not, we
2100 * either calculate the next fragment (based on @e frag_off) from the
2101 * current node, or, if all fragments have already been created,
2102 * descend to the @e head_frag. Even though the node was already
2103 * fragmented, the fragment may be too big if the fragment was
2104 * generated for a queue with a larger MTU. In this case, the node
2105 * may be fragmented again, thus creating a tree.
2106 *
2107 * When acknowledgements for fragments are received, the tree
2108 * must be pruned, removing those parts that were already
2109 * acknowledged. When fragments are sent over a reliable
2110 * channel, they can be immediately removed.
2111 *
2112 * If a message is ever fragmented, then the original "full" message
2113 * is never again transmitted (even if it fits below the MTU), and
2114 * only (remaining) fragments are sent.
2115 */
2116struct PendingMessage
2117{
2118 /**
2119 * Kept in a MDLL of messages for this @a vl.
2120 */
2121 struct PendingMessage *next_vl;
2122
2123 /**
2124 * Kept in a MDLL of messages for this @a vl.
2125 */
2126 struct PendingMessage *prev_vl;
2127
2128 /**
2129 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
2130 */
2131 struct PendingMessage *next_client;
2132
2133 /**
2134 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
2135 */
2136 struct PendingMessage *prev_client;
2137
2138 /**
2139 * Kept in a MDLL of messages from this @a cpm (if @e pmt is
2140 * #PMT_FRAGMENT_BOx)
2141 */
2142 struct PendingMessage *next_frag;
2143
2144 /**
2145 * Kept in a MDLL of messages from this @a cpm (if @e pmt is
2146 * #PMT_FRAGMENT_BOX)
2147 */
2148 struct PendingMessage *prev_frag;
2149
2150 /**
2151 * Head of DLL of PAs for this pending message.
2152 */
2153 struct PendingAcknowledgement *pa_head;
2154
2155 /**
2156 * Tail of DLL of PAs for this pending message.
2157 */
2158 struct PendingAcknowledgement *pa_tail;
2159
2160 /**
2161 * This message, reliability *or* DV-boxed. Only possibly available
2162 * if @e pmt is #PMT_CORE.
2163 */
2164 struct PendingMessage *bpm;
2165
2166 /**
2167 * Target of the request (always the ultimate destination!).
2168 */
2169 struct VirtualLink *vl;
2170
2171 /**
2172 * Set to non-NULL value if this message is currently being given to a
2173 * communicator and we are awaiting that communicator's acknowledgement.
2174 * Note that we must not retransmit a pending message while we're still
2175 * in the process of giving it to a communicator. If a pending message
2176 * is free'd while this entry is non-NULL, the @e qe reference to us
2177 * should simply be set to NULL.
2178 */
2179 struct QueueEntry *qe;
2180
2181 /**
2182 * Client that issued the transmission request, if @e pmt is #PMT_CORE.
2183 */
2184 struct TransportClient *client;
2185
2186 /**
2187 * Head of a MDLL of fragments created for this core message.
2188 */
2189 struct PendingMessage *head_frag;
2190
2191 /**
2192 * Tail of a MDLL of fragments created for this core message.
2193 */
2194 struct PendingMessage *tail_frag;
2195
2196 /**
2197 * Our parent in the fragmentation tree.
2198 */
2199 struct PendingMessage *frag_parent;
2200
2201 /**
2202 * At what time should we give up on the transmission (and no longer retry)?
2203 */
2204 struct GNUNET_TIME_Absolute timeout;
2205
2206 /**
2207 * What is the earliest time for us to retry transmission of this message?
2208 */
2209 struct GNUNET_TIME_Absolute next_attempt;
2210
2211 /**
2212 * UUID to use for this message (used for reassembly of fragments, only
2213 * initialized if @e msg_uuid_set is #GNUNET_YES).
2214 */
2215 struct MessageUUIDP msg_uuid;
2216
2217 /**
2218 * UUID we use to identify this message in our logs.
2219 * Generated by incrementing the "logging_uuid_gen".
2220 */
2221 unsigned long long logging_uuid;
2222
2223 /**
2224 * Type of the pending message.
2225 */
2226 enum PendingMessageType pmt;
2227
2228 /**
2229 * Preferences for this message.
2230 * TODO: actually use this!
2231 */
2232 enum GNUNET_MQ_PriorityPreferences prefs;
2233
2234 /**
2235 * If pmt is of type PMT_DV_BOX we store the used path here.
2236 */
2237 struct DistanceVectorHop *used_dvh;
2238
2239 /**
2240 * Size of the original message.
2241 */
2242 uint16_t bytes_msg;
2243
2244 /**
2245 * Offset at which we should generate the next fragment.
2246 */
2247 uint16_t frag_off;
2248
2249 /**
2250 * #GNUNET_YES once @e msg_uuid was initialized
2251 */
2252 int16_t msg_uuid_set;
2253
2254 /* Followed by @e bytes_msg to transmit */
2255};
2256
2257
2258/**
2259 * Acknowledgement payload.
2260 */
2261struct TransportCummulativeAckPayload
2262{
2263 /**
2264 * When did we receive the message we are ACKing? Used to calculate
2265 * the delay we introduced by cummulating ACKs.
2266 */
2267 struct GNUNET_TIME_Absolute receive_time;
2268
2269 /**
2270 * UUID of a message being acknowledged.
2271 */
2272 struct AcknowledgementUUIDP ack_uuid;
2273};
2274
2275
2276/**
2277 * Data structure in which we track acknowledgements still to
2278 * be sent to the
2279 */
2280struct AcknowledgementCummulator
2281{
2282 /**
2283 * Target peer for which we are accumulating ACKs here.
2284 */
2285 struct GNUNET_PeerIdentity target;
2286
2287 /**
2288 * ACK data being accumulated. Only @e num_acks slots are valid.
2289 */
2290 struct TransportCummulativeAckPayload ack_uuids[MAX_CUMMULATIVE_ACKS];
2291
2292 /**
2293 * Task scheduled either to transmit the cumulative ACK message,
2294 * or to clean up this data structure after extended periods of
2295 * inactivity (if @e num_acks is zero).
2296 */
2297 struct GNUNET_SCHEDULER_Task *task;
2298
2299 /**
2300 * When is @e task run (only used if @e num_acks is non-zero)?
2301 */
2302 struct GNUNET_TIME_Absolute min_transmission_time;
2303
2304 /**
2305 * Counter to produce the `ack_counter` in the `struct
2306 * TransportReliabilityAckMessage`. Allows the receiver to detect
2307 * lost ACK messages. Incremented by @e num_acks upon transmission.
2308 */
2309 uint32_t ack_counter;
2310
2311 /**
2312 * Number of entries used in @e ack_uuids. Reset to 0 upon transmission.
2313 */
2314 unsigned int num_acks;
2315};
2316
2317
2318/**
2319 * One of the addresses of this peer.
2320 */
2321struct AddressListEntry
2322{
2323 /**
2324 * Kept in a DLL.
2325 */
2326 struct AddressListEntry *next;
2327
2328 /**
2329 * Kept in a DLL.
2330 */
2331 struct AddressListEntry *prev;
2332
2333 /**
2334 * Which communicator provides this address?
2335 */
2336 struct TransportClient *tc;
2337
2338 /**
2339 * The actual address.
2340 */
2341 const char *address;
2342
2343 /**
2344 * Current context for storing this address in the peerstore.
2345 */
2346 struct GNUNET_PEERSTORE_StoreContext *sc;
2347
2348 /**
2349 * Task to periodically do @e st operation.
2350 */
2351 struct GNUNET_SCHEDULER_Task *st;
2352
2353 /**
2354 * What is a typical lifetime the communicator expects this
2355 * address to have? (Always from now.)
2356 */
2357 struct GNUNET_TIME_Relative expiration;
2358
2359 /**
2360 * Address identifier used by the communicator.
2361 */
2362 uint32_t aid;
2363
2364 /**
2365 * Network type offered by this address.
2366 */
2367 enum GNUNET_NetworkType nt;
2368};
2369
2370
2371/**
2372 * Client connected to the transport service.
2373 */
2374struct TransportClient
2375{
2376 /**
2377 * Kept in a DLL.
2378 */
2379 struct TransportClient *next;
2380
2381 /**
2382 * Kept in a DLL.
2383 */
2384 struct TransportClient *prev;
2385
2386 /**
2387 * Handle to the client.
2388 */
2389 struct GNUNET_SERVICE_Client *client;
2390
2391 /**
2392 * Message queue to the client.
2393 */
2394 struct GNUNET_MQ_Handle *mq;
2395
2396 /**
2397 * What type of client is this?
2398 */
2399 enum ClientType type;
2400
2401 union
2402 {
2403 /**
2404 * Information for @e type #CT_CORE.
2405 */
2406 struct
2407 {
2408 /**
2409 * Head of list of messages pending for this client, sorted by
2410 * transmission time ("next_attempt" + possibly internal prioritization).
2411 */
2412 struct PendingMessage *pending_msg_head;
2413
2414 /**
2415 * Tail of list of messages pending for this client.
2416 */
2417 struct PendingMessage *pending_msg_tail;
2418 } core;
2419
2420 /**
2421 * Information for @e type #CT_MONITOR.
2422 */
2423 struct
2424 {
2425 /**
2426 * Peer identity to monitor the addresses of.
2427 * Zero to monitor all neighbours. Valid if
2428 * @e type is #CT_MONITOR.
2429 */
2430 struct GNUNET_PeerIdentity peer;
2431
2432 /**
2433 * Is this a one-shot monitor?
2434 */
2435 int one_shot;
2436 } monitor;
2437
2438
2439 /**
2440 * Information for @e type #CT_COMMUNICATOR.
2441 */
2442 struct
2443 {
2444 /**
2445 * If @e type is #CT_COMMUNICATOR, this communicator
2446 * supports communicating using these addresses.
2447 */
2448 char *address_prefix;
2449
2450 /**
2451 * Head of DLL of queues offered by this communicator.
2452 */
2453 struct Queue *queue_head;
2454
2455 /**
2456 * Tail of DLL of queues offered by this communicator.
2457 */
2458 struct Queue *queue_tail;
2459
2460 /**
2461 * Head of list of the addresses of this peer offered by this
2462 * communicator.
2463 */
2464 struct AddressListEntry *addr_head;
2465
2466 /**
2467 * Tail of list of the addresses of this peer offered by this
2468 * communicator.
2469 */
2470 struct AddressListEntry *addr_tail;
2471
2472 /**
2473 * Number of queue entries in all queues to this communicator. Used
2474 * throttle sending to a communicator if we see that the communicator
2475 * is globally unable to keep up.
2476 */
2477 unsigned int total_queue_length;
2478
2479 /**
2480 * Characteristics of this communicator.
2481 */
2482 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
2483 } communicator;
2484
2485 /**
2486 * Information for @e type #CT_APPLICATION
2487 */
2488 struct
2489 {
2490 /**
2491 * Map of requests for peers the given client application would like to
2492 * see connections for. Maps from PIDs to `struct PeerRequest`.
2493 */
2494 struct GNUNET_CONTAINER_MultiPeerMap *requests;
2495 } application;
2496 } details;
2497};
2498
2499
2500/**
2501 * State we keep for validation activities. Each of these
2502 * is both in the #validation_heap and the #validation_map.
2503 */
2504struct ValidationState
2505{
2506 /**
2507 * For which peer is @a address to be validated (or possibly valid)?
2508 * Serves as key in the #validation_map.
2509 */
2510 struct GNUNET_PeerIdentity pid;
2511
2512 /**
2513 * How long did the peer claim this @e address to be valid? Capped at
2514 * minimum of #MAX_ADDRESS_VALID_UNTIL relative to the time where we last
2515 * were told about the address and the value claimed by the other peer at
2516 * that time. May be updated similarly when validation succeeds.
2517 */
2518 struct GNUNET_TIME_Absolute valid_until;
2519
2520 /**
2521 * How long do *we* consider this @e address to be valid?
2522 * In the past or zero if we have not yet validated it.
2523 */
2524 struct GNUNET_TIME_Absolute validated_until;
2525
2526 /**
2527 * When did we FIRST use the current @e challenge in a message?
2528 * Used to sanity-check @code{origin_time} in the response when
2529 * calculating the RTT. If the @code{origin_time} is not in
2530 * the expected range, the response is discarded as malicious.
2531 */
2532 struct GNUNET_TIME_Absolute first_challenge_use;
2533
2534 /**
2535 * When did we LAST use the current @e challenge in a message?
2536 * Used to sanity-check @code{origin_time} in the response when
2537 * calculating the RTT. If the @code{origin_time} is not in
2538 * the expected range, the response is discarded as malicious.
2539 */
2540 struct GNUNET_TIME_Absolute last_challenge_use;
2541
2542 /**
2543 * Next time we will send the @e challenge to the peer, if this time is past
2544 * @e valid_until, this validation state is released at this time. If the
2545 * address is valid, @e next_challenge is set to @e validated_until MINUS @e
2546 * validation_delay * #VALIDATION_RTT_BUFFER_FACTOR, such that we will try
2547 * to re-validate before the validity actually expires.
2548 */
2549 struct GNUNET_TIME_Absolute next_challenge;
2550
2551 /**
2552 * Current backoff factor we're applying for sending the @a challenge.
2553 * Reset to 0 if the @a challenge is confirmed upon validation.
2554 * Reduced to minimum of #FAST_VALIDATION_CHALLENGE_FREQ and half of the
2555 * existing value if we receive an unvalidated address again over
2556 * another channel (and thus should consider the information "fresh").
2557 * Maximum is #MAX_VALIDATION_CHALLENGE_FREQ.
2558 */
2559 struct GNUNET_TIME_Relative challenge_backoff;
2560
2561 /**
2562 * Initially set to "forever". Once @e validated_until is set, this value is
2563 * set to the RTT that tells us how long it took to receive the validation.
2564 */
2565 struct GNUNET_TIME_Relative validation_rtt;
2566
2567 /**
2568 * The challenge we sent to the peer to get it to validate the address. Note
2569 * that we rotate the challenge whenever we update @e validated_until to
2570 * avoid attacks where a peer simply replays an old challenge in the future.
2571 * (We must not rotate more often as otherwise we may discard valid answers
2572 * due to packet losses, latency and reorderings on the network).
2573 */
2574 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
2575
2576 /**
2577 * Claimed address of the peer.
2578 */
2579 char *address;
2580
2581 /**
2582 * Entry in the #validation_heap, which is sorted by @e next_challenge. The
2583 * heap is used to figure out when the next validation activity should be
2584 * run.
2585 */
2586 struct GNUNET_CONTAINER_HeapNode *hn;
2587
2588 /**
2589 * Handle to a PEERSTORE store operation for this @e address. NULL if
2590 * no PEERSTORE operation is pending.
2591 */
2592 struct GNUNET_PEERSTORE_StoreContext *sc;
2593
2594 /**
2595 * Self-imposed limit on the previous flow control window. (May be zero,
2596 * if we never used data from the previous window or are establishing the
2597 * connection for the first time).
2598 */
2599 uint32_t last_window_consum_limit;
2600
2601 /**
2602 * We are technically ready to send the challenge, but we are waiting for
2603 * the respective queue to become available for transmission.
2604 */
2605 int awaiting_queue;
2606};
2607
2608
2609/**
2610 * A Backtalker is a peer sending us backchannel messages. We use this
2611 * struct to detect monotonic time violations, cache ephemeral key
2612 * material (to avoid repeatedly checking signatures), and to synchronize
2613 * monotonic time with the PEERSTORE.
2614 */
2615struct Backtalker
2616{
2617 /**
2618 * Peer this is about.
2619 */
2620 struct GNUNET_PeerIdentity pid;
2621
2622 /**
2623 * Last (valid) monotonic time received from this sender.
2624 */
2625 struct GNUNET_TIME_Absolute monotonic_time;
2626
2627 /**
2628 * When will this entry time out?
2629 */
2630 struct GNUNET_TIME_Absolute timeout;
2631
2632 /**
2633 * Last (valid) ephemeral key received from this sender.
2634 */
2635 struct GNUNET_CRYPTO_EcdhePublicKey last_ephemeral;
2636
2637 /**
2638 * Task associated with this backtalker. Can be for timeout,
2639 * or other asynchronous operations.
2640 */
2641 struct GNUNET_SCHEDULER_Task *task;
2642
2643 /**
2644 * Communicator context waiting on this backchannel's @e get, or NULL.
2645 */
2646 struct CommunicatorMessageContext *cmc;
2647
2648 /**
2649 * Handle for an operation to fetch @e monotonic_time information from the
2650 * PEERSTORE, or NULL.
2651 */
2652 struct GNUNET_PEERSTORE_IterateContext *get;
2653
2654 /**
2655 * Handle to a PEERSTORE store operation for this @e pid's @e
2656 * monotonic_time. NULL if no PEERSTORE operation is pending.
2657 */
2658 struct GNUNET_PEERSTORE_StoreContext *sc;
2659
2660 /**
2661 * Number of bytes of the original message body that follows after this
2662 * struct.
2663 */
2664 size_t body_size;
2665};
2666
2667
2668/**
2669 * Head of linked list of all clients to this service.
2670 */
2671static struct TransportClient *clients_head;
2672
2673/**
2674 * Tail of linked list of all clients to this service.
2675 */
2676static struct TransportClient *clients_tail;
2677
2678/**
2679 * Statistics handle.
2680 */
2681static struct GNUNET_STATISTICS_Handle *GST_stats;
2682
2683/**
2684 * Configuration handle.
2685 */
2686static const struct GNUNET_CONFIGURATION_Handle *GST_cfg;
2687
2688/**
2689 * Our public key.
2690 */
2691static struct GNUNET_PeerIdentity GST_my_identity;
2692
2693/**
2694 * Our private key.
2695 */
2696static struct GNUNET_CRYPTO_EddsaPrivateKey *GST_my_private_key;
2697
2698/**
2699 * Map from PIDs to `struct Neighbour` entries. A peer is
2700 * a neighbour if we have an MQ to it from some communicator.
2701 */
2702static struct GNUNET_CONTAINER_MultiPeerMap *neighbours;
2703
2704/**
2705 * Map from PIDs to `struct Backtalker` entries. A peer is
2706 * a backtalker if it recently send us backchannel messages.
2707 */
2708static struct GNUNET_CONTAINER_MultiPeerMap *backtalkers;
2709
2710/**
2711 * Map from PIDs to `struct AcknowledgementCummulator`s.
2712 * Here we track the cumulative ACKs for transmission.
2713 */
2714static struct GNUNET_CONTAINER_MultiPeerMap *ack_cummulators;
2715
2716/**
2717 * Map of pending acknowledgements, mapping `struct AcknowledgementUUID` to
2718 * a `struct PendingAcknowledgement`.
2719 */
2720static struct GNUNET_CONTAINER_MultiUuidmap *pending_acks;
2721
2722/**
2723 * Map from PIDs to `struct DistanceVector` entries describing
2724 * known paths to the peer.
2725 */
2726static struct GNUNET_CONTAINER_MultiPeerMap *dv_routes;
2727
2728/**
2729 * Map from PIDs to `struct ValidationState` entries describing
2730 * addresses we are aware of and their validity state.
2731 */
2732static struct GNUNET_CONTAINER_MultiPeerMap *validation_map;
2733
2734/**
2735 * Map from PIDs to `struct VirtualLink` entries describing
2736 * links CORE knows to exist.
2737 */
2738static struct GNUNET_CONTAINER_MultiPeerMap *links;
2739
2740/**
2741 * Map from challenges to `struct LearnLaunchEntry` values.
2742 */
2743static struct GNUNET_CONTAINER_MultiShortmap *dvlearn_map;
2744
2745/**
2746 * Head of a DLL sorted by launch time.
2747 */
2748static struct LearnLaunchEntry *lle_head = NULL;
2749
2750/**
2751 * Tail of a DLL sorted by launch time.
2752 */
2753static struct LearnLaunchEntry *lle_tail = NULL;
2754
2755/**
2756 * MIN Heap sorted by "next_challenge" to `struct ValidationState` entries
2757 * sorting addresses we are aware of by when we should next try to (re)validate
2758 * (or expire) them.
2759 */
2760static struct GNUNET_CONTAINER_Heap *validation_heap;
2761
2762/**
2763 * Database for peer's HELLOs.
2764 */
2765static struct GNUNET_PEERSTORE_Handle *peerstore;
2766
2767/**
2768 * Task run to initiate DV learning.
2769 */
2770static struct GNUNET_SCHEDULER_Task *dvlearn_task;
2771
2772/**
2773 * Task to run address validation.
2774 */
2775static struct GNUNET_SCHEDULER_Task *validation_task;
2776
2777/**
2778 * The most recent PA we have created, head of DLL.
2779 * The length of the DLL is kept in #pa_count.
2780 */
2781static struct PendingAcknowledgement *pa_head;
2782
2783/**
2784 * The oldest PA we have created, tail of DLL.
2785 * The length of the DLL is kept in #pa_count.
2786 */
2787static struct PendingAcknowledgement *pa_tail;
2788
2789/**
2790 * List of incoming connections where we are trying
2791 * to get a connection back established. Length
2792 * kept in #ir_total.
2793 */
2794static struct IncomingRequest *ir_head;
2795
2796/**
2797 * Tail of DLL starting at #ir_head.
2798 */
2799static struct IncomingRequest *ir_tail;
2800
2801/**
2802 * Length of the DLL starting at #ir_head.
2803 */
2804static unsigned int ir_total;
2805
2806/**
2807 * Generator of `logging_uuid` in `struct PendingMessage`.
2808 */
2809static unsigned long long logging_uuid_gen;
2810
2811/**
2812 * Number of entries in the #pa_head/#pa_tail DLL. Used to
2813 * limit the size of the data structure.
2814 */
2815static unsigned int pa_count;
2816
2817/**
2818 * Monotonic time we use for HELLOs generated at this time. TODO: we
2819 * should increase this value from time to time (i.e. whenever a
2820 * `struct AddressListEntry` actually expires), but IF we do this, we
2821 * must also update *all* (remaining) addresses in the PEERSTORE at
2822 * that time! (So for now only increased when the peer is restarted,
2823 * which hopefully roughly matches whenever our addresses change.)
2824 */
2825static struct GNUNET_TIME_Absolute hello_mono_time;
2826
2827/**
2828 * Indication if we have received a shutdown signal
2829 * and are in the process of cleaning up.
2830 */
2831static int in_shutdown;
2832
2833/**
2834 * Get an offset into the transmission history buffer for `struct
2835 * PerformanceData`. Note that the caller must perform the required
2836 * modulo #GOODPUT_AGING_SLOTS operation before indexing into the
2837 * array!
2838 *
2839 * An 'age' lasts 15 minute slots.
2840 *
2841 * @return current age of the world
2842 */
2843static unsigned int
2844get_age ()
2845{
2846 struct GNUNET_TIME_Absolute now;
2847
2848 now = GNUNET_TIME_absolute_get ();
2849 return now.abs_value_us / GNUNET_TIME_UNIT_MINUTES.rel_value_us / 15;
2850}
2851
2852
2853/**
2854 * Release @a ir data structure.
2855 *
2856 * @param ir data structure to release
2857 */
2858static void
2859free_incoming_request (struct IncomingRequest *ir)
2860{
2861 GNUNET_CONTAINER_DLL_remove (ir_head, ir_tail, ir);
2862 GNUNET_assert (ir_total > 0);
2863 ir_total--;
2864 GNUNET_PEERSTORE_watch_cancel (ir->wc);
2865 ir->wc = NULL;
2866 GNUNET_free (ir);
2867}
2868
2869
2870/**
2871 * Release @a pa data structure.
2872 *
2873 * @param pa data structure to release
2874 */
2875static void
2876free_pending_acknowledgement (struct PendingAcknowledgement *pa)
2877{
2878 struct Queue *q = pa->queue;
2879 struct PendingMessage *pm = pa->pm;
2880 struct DistanceVectorHop *dvh = pa->dvh;
2881
2882 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2883 "free_pending_acknowledgement\n");
2884 if (NULL != q)
2885 {
2886 GNUNET_CONTAINER_MDLL_remove (queue, q->pa_head, q->pa_tail, pa);
2887 pa->queue = NULL;
2888 }
2889 if (NULL != pm)
2890 {
2891 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2892 "remove pa from message\n");
2893 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2894 "remove pa from message %llu\n",
2895 pm->logging_uuid);
2896 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2897 "remove pa from message %u\n",
2898 pm->pmt);
2899 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2900 "remove pa from message %s\n",
2901 GNUNET_uuid2s (&pa->ack_uuid.value));
2902 GNUNET_CONTAINER_MDLL_remove (pm, pm->pa_head, pm->pa_tail, pa);
2903 pa->pm = NULL;
2904 }
2905 if (NULL != dvh)
2906 {
2907 GNUNET_CONTAINER_MDLL_remove (dvh, dvh->pa_head, dvh->pa_tail, pa);
2908 pa->queue = NULL;
2909 }
2910 GNUNET_assert (GNUNET_YES ==
2911 GNUNET_CONTAINER_multiuuidmap_remove (pending_acks,
2912 &pa->ack_uuid.value,
2913 pa));
2914 GNUNET_free (pa);
2915}
2916
2917
2918/**
2919 * Free fragment tree below @e root, excluding @e root itself.
2920 * FIXME: this does NOT seem to have the intended semantics
2921 * based on how this is called. Seems we generally DO expect
2922 * @a root to be free'ed itself as well!
2923 *
2924 * @param root root of the tree to free
2925 */
2926static void
2927free_fragment_tree (struct PendingMessage *root)
2928{
2929 struct PendingMessage *frag;
2930
2931 while (NULL != (frag = root->head_frag))
2932 {
2933 struct PendingAcknowledgement *pa;
2934
2935 free_fragment_tree (frag);
2936 while (NULL != (pa = frag->pa_head))
2937 {
2938 GNUNET_CONTAINER_MDLL_remove (pm, frag->pa_head, frag->pa_tail, pa);
2939 pa->pm = NULL;
2940 }
2941 GNUNET_CONTAINER_MDLL_remove (frag, root->head_frag, root->tail_frag, frag);
2942 if (NULL != frag->qe)
2943 {
2944 GNUNET_assert (frag == frag->qe->pm);
2945 frag->qe->pm = NULL;
2946 GNUNET_CONTAINER_DLL_remove (frag->qe->queue->queue_head,
2947 frag->qe->queue->queue_tail,
2948 frag->qe);
2949 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2950 "Removing QueueEntry MID %llu from queue\n",
2951 frag->qe->mid);
2952 GNUNET_free (frag->qe);
2953 }
2954 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2955 "Free frag %p\n",
2956 frag);
2957 GNUNET_free (frag);
2958 }
2959}
2960
2961
2962/**
2963 * Release memory associated with @a pm and remove @a pm from associated
2964 * data structures. @a pm must be a top-level pending message and not
2965 * a fragment in the tree. The entire tree is freed (if applicable).
2966 *
2967 * @param pm the pending message to free
2968 */
2969static void
2970free_pending_message (struct PendingMessage *pm)
2971{
2972 struct TransportClient *tc = pm->client;
2973 struct VirtualLink *vl = pm->vl;
2974 struct PendingAcknowledgement *pa;
2975
2976 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2977 "Freeing pm %p\n",
2978 pm);
2979 if (NULL != tc)
2980 {
2981 GNUNET_CONTAINER_MDLL_remove (client,
2982 tc->details.core.pending_msg_head,
2983 tc->details.core.pending_msg_tail,
2984 pm);
2985 }
2986 if ((NULL != vl) && (NULL == pm->frag_parent))
2987 {
2988 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2989 "Removing pm %lu\n",
2990 pm->logging_uuid);
2991 GNUNET_CONTAINER_MDLL_remove (vl,
2992 vl->pending_msg_head,
2993 vl->pending_msg_tail,
2994 pm);
2995 }
2996 while (NULL != (pa = pm->pa_head))
2997 {
2998 if (NULL == pa)
2999 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3000 "free pending pa null\n");
3001 if (NULL == pm->pa_tail)
3002 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3003 "free pending pa_tail null\n");
3004 if (NULL == pa->prev_pa)
3005 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3006 "free pending pa prev null\n");
3007 if (NULL == pa->next_pa)
3008 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3009 "free pending pa next null\n");
3010 GNUNET_CONTAINER_MDLL_remove (pm, pm->pa_head, pm->pa_tail, pa);
3011 pa->pm = NULL;
3012 }
3013
3014 free_fragment_tree (pm);
3015 if (NULL != pm->qe)
3016 {
3017 GNUNET_assert (pm == pm->qe->pm);
3018 pm->qe->pm = NULL;
3019 GNUNET_CONTAINER_DLL_remove (pm->qe->queue->queue_head,
3020 pm->qe->queue->queue_tail,
3021 pm->qe);
3022 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3023 "Removing QueueEntry MID %llu from queue\n",
3024 pm->qe->mid);
3025 GNUNET_free (pm->qe);
3026 }
3027 if (NULL != pm->bpm)
3028 {
3029 free_fragment_tree (pm->bpm);
3030 GNUNET_free (pm->bpm);
3031 }
3032 if (NULL == pm)
3033 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3034 "free pending pm null\n");
3035 GNUNET_free (pm);
3036}
3037
3038
3039/**
3040 * Free @a rc
3041 *
3042 * @param rc data structure to free
3043 */
3044static void
3045free_reassembly_context (struct ReassemblyContext *rc)
3046{
3047 struct VirtualLink *vl = rc->virtual_link;
3048
3049 GNUNET_assert (rc == GNUNET_CONTAINER_heap_remove_node (rc->hn));
3050 GNUNET_assert (GNUNET_OK ==
3051 GNUNET_CONTAINER_multihashmap32_remove (vl->reassembly_map,
3052 rc->msg_uuid.uuid,
3053 rc));
3054 GNUNET_free (rc);
3055}
3056
3057
3058/**
3059 * Task run to clean up reassembly context of a neighbour that have expired.
3060 *
3061 * @param cls a `struct Neighbour`
3062 */
3063static void
3064reassembly_cleanup_task (void *cls)
3065{
3066 struct VirtualLink *vl = cls;
3067 struct ReassemblyContext *rc;
3068
3069 vl->reassembly_timeout_task = NULL;
3070 while (NULL != (rc = GNUNET_CONTAINER_heap_peek (vl->reassembly_heap)))
3071 {
3072 if (0 == GNUNET_TIME_absolute_get_remaining (rc->reassembly_timeout)
3073 .rel_value_us)
3074 {
3075 free_reassembly_context (rc);
3076 continue;
3077 }
3078 GNUNET_assert (NULL == vl->reassembly_timeout_task);
3079 vl->reassembly_timeout_task =
3080 GNUNET_SCHEDULER_add_at (rc->reassembly_timeout,
3081 &reassembly_cleanup_task,
3082 vl);
3083 return;
3084 }
3085}
3086
3087
3088/**
3089 * function called to #free_reassembly_context().
3090 *
3091 * @param cls NULL
3092 * @param key unused
3093 * @param value a `struct ReassemblyContext` to free
3094 * @return #GNUNET_OK (continue iteration)
3095 */
3096static int
3097free_reassembly_cb (void *cls, uint32_t key, void *value)
3098{
3099 struct ReassemblyContext *rc = value;
3100
3101 (void) cls;
3102 (void) key;
3103 free_reassembly_context (rc);
3104 return GNUNET_OK;
3105}
3106
3107
3108/**
3109 * Free virtual link.
3110 *
3111 * @param vl link data to free
3112 */
3113static void
3114free_virtual_link (struct VirtualLink *vl)
3115{
3116 struct PendingMessage *pm;
3117 struct CoreSentContext *csc;
3118
3119 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3120 "free virtual link %p\n",
3121 vl);
3122
3123 if (NULL != vl->reassembly_map)
3124 {
3125 GNUNET_CONTAINER_multihashmap32_iterate (vl->reassembly_map,
3126 &free_reassembly_cb,
3127 NULL);
3128 GNUNET_CONTAINER_multihashmap32_destroy (vl->reassembly_map);
3129 vl->reassembly_map = NULL;
3130 GNUNET_CONTAINER_heap_destroy (vl->reassembly_heap);
3131 vl->reassembly_heap = NULL;
3132 }
3133 if (NULL != vl->reassembly_timeout_task)
3134 {
3135 GNUNET_SCHEDULER_cancel (vl->reassembly_timeout_task);
3136 vl->reassembly_timeout_task = NULL;
3137 }
3138 while (NULL != (pm = vl->pending_msg_head))
3139 free_pending_message (pm);
3140 GNUNET_assert (GNUNET_YES ==
3141 GNUNET_CONTAINER_multipeermap_remove (links, &vl->target, vl));
3142 if (NULL != vl->visibility_task)
3143 {
3144 GNUNET_SCHEDULER_cancel (vl->visibility_task);
3145 vl->visibility_task = NULL;
3146 }
3147 if (NULL != vl->fc_retransmit_task)
3148 {
3149 GNUNET_SCHEDULER_cancel (vl->fc_retransmit_task);
3150 vl->fc_retransmit_task = NULL;
3151 }
3152 while (NULL != (csc = vl->csc_head))
3153 {
3154 GNUNET_CONTAINER_DLL_remove (vl->csc_head, vl->csc_tail, csc);
3155 GNUNET_assert (vl == csc->vl);
3156 csc->vl = NULL;
3157 }
3158 GNUNET_break (NULL == vl->n);
3159 GNUNET_break (NULL == vl->dv);
3160 GNUNET_free (vl);
3161}
3162
3163
3164/**
3165 * Free validation state.
3166 *
3167 * @param vs validation state to free
3168 */
3169static void
3170free_validation_state (struct ValidationState *vs)
3171{
3172 GNUNET_assert (
3173 GNUNET_YES ==
3174 GNUNET_CONTAINER_multipeermap_remove (validation_map, &vs->pid, vs));
3175 GNUNET_CONTAINER_heap_remove_node (vs->hn);
3176 vs->hn = NULL;
3177 if (NULL != vs->sc)
3178 {
3179 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3180 "store cancel\n");
3181 GNUNET_PEERSTORE_store_cancel (vs->sc);
3182 vs->sc = NULL;
3183 }
3184 GNUNET_free (vs->address);
3185 GNUNET_free (vs);
3186}
3187
3188
3189/**
3190 * Lookup neighbour for peer @a pid.
3191 *
3192 * @param pid neighbour to look for
3193 * @return NULL if we do not have this peer as a neighbour
3194 */
3195static struct Neighbour *
3196lookup_neighbour (const struct GNUNET_PeerIdentity *pid)
3197{
3198 return GNUNET_CONTAINER_multipeermap_get (neighbours, pid);
3199}
3200
3201
3202/**
3203 * Lookup virtual link for peer @a pid.
3204 *
3205 * @param pid virtual link to look for
3206 * @return NULL if we do not have this peer as a virtual link
3207 */
3208static struct VirtualLink *
3209lookup_virtual_link (const struct GNUNET_PeerIdentity *pid)
3210{
3211 return GNUNET_CONTAINER_multipeermap_get (links, pid);
3212}
3213
3214
3215/**
3216 * Details about what to notify monitors about.
3217 */
3218struct MonitorEvent
3219{
3220 /**
3221 * @deprecated To be discussed if we keep these...
3222 */
3223 struct GNUNET_TIME_Absolute last_validation;
3224 struct GNUNET_TIME_Absolute valid_until;
3225 struct GNUNET_TIME_Absolute next_validation;
3226
3227 /**
3228 * Current round-trip time estimate.
3229 */
3230 struct GNUNET_TIME_Relative rtt;
3231
3232 /**
3233 * Connection status.
3234 */
3235 enum GNUNET_TRANSPORT_ConnectionStatus cs;
3236
3237 /**
3238 * Messages pending.
3239 */
3240 uint32_t num_msg_pending;
3241
3242 /**
3243 * Bytes pending.
3244 */
3245 uint32_t num_bytes_pending;
3246};
3247
3248
3249/**
3250 * Free a @dvh. Callers MAY want to check if this was the last path to the
3251 * `target`, and if so call #free_dv_route to also free the associated DV
3252 * entry in #dv_routes (if not, the associated scheduler job should eventually
3253 * take care of it).
3254 *
3255 * @param dvh hop to free
3256 */
3257static void
3258free_distance_vector_hop (struct DistanceVectorHop *dvh)
3259{
3260 struct Neighbour *n = dvh->next_hop;
3261 struct DistanceVector *dv = dvh->dv;
3262 struct PendingAcknowledgement *pa;
3263
3264 while (NULL != (pa = dvh->pa_head))
3265 {
3266 GNUNET_CONTAINER_MDLL_remove (dvh, dvh->pa_head, dvh->pa_tail, pa);
3267 pa->dvh = NULL;
3268 }
3269 GNUNET_CONTAINER_MDLL_remove (neighbour, n->dv_head, n->dv_tail, dvh);
3270 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, dvh);
3271 GNUNET_free (dvh);
3272}
3273
3274
3275/**
3276 * Task run to check whether the hops of the @a cls still
3277 * are validated, or if we need to core about disconnection.
3278 *
3279 * @param cls a `struct VirtualLink`
3280 */
3281static void
3282check_link_down (void *cls);
3283
3284
3285/**
3286 * Send message to CORE clients that we lost a connection.
3287 *
3288 * @param pid peer the connection was for
3289 */
3290static void
3291cores_send_disconnect_info (const struct GNUNET_PeerIdentity *pid)
3292{
3293 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3294 "Informing CORE clients about disconnect from %s\n",
3295 GNUNET_i2s (pid));
3296 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
3297 {
3298 struct GNUNET_MQ_Envelope *env;
3299 struct DisconnectInfoMessage *dim;
3300
3301 if (CT_CORE != tc->type)
3302 continue;
3303 env = GNUNET_MQ_msg (dim, GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
3304 dim->peer = *pid;
3305 GNUNET_MQ_send (tc->mq, env);
3306 }
3307}
3308
3309
3310/**
3311 * Free entry in #dv_routes. First frees all hops to the target, and
3312 * if there are no entries left, frees @a dv as well.
3313 *
3314 * @param dv route to free
3315 */
3316static void
3317free_dv_route (struct DistanceVector *dv)
3318{
3319 struct DistanceVectorHop *dvh;
3320
3321 while (NULL != (dvh = dv->dv_head))
3322 free_distance_vector_hop (dvh);
3323 if (NULL == dv->dv_head)
3324 {
3325 struct VirtualLink *vl;
3326
3327 GNUNET_assert (
3328 GNUNET_YES ==
3329 GNUNET_CONTAINER_multipeermap_remove (dv_routes, &dv->target, dv));
3330 if (NULL != (vl = dv->vl))
3331 {
3332 GNUNET_assert (dv == vl->dv);
3333 vl->dv = NULL;
3334 if (NULL == vl->n)
3335 {
3336 cores_send_disconnect_info (&dv->target);
3337 free_virtual_link (vl);
3338 }
3339 else
3340 {
3341 GNUNET_SCHEDULER_cancel (vl->visibility_task);
3342 vl->visibility_task = GNUNET_SCHEDULER_add_now (&check_link_down, vl);
3343 }
3344 dv->vl = NULL;
3345 }
3346
3347 if (NULL != dv->timeout_task)
3348 {
3349 GNUNET_SCHEDULER_cancel (dv->timeout_task);
3350 dv->timeout_task = NULL;
3351 }
3352 GNUNET_free (dv);
3353 }
3354}
3355
3356
3357/**
3358 * Notify monitor @a tc about an event. That @a tc
3359 * cares about the event has already been checked.
3360 *
3361 * Send @a tc information in @a me about a @a peer's status with
3362 * respect to some @a address to all monitors that care.
3363 *
3364 * @param tc monitor to inform
3365 * @param peer peer the information is about
3366 * @param address address the information is about
3367 * @param nt network type associated with @a address
3368 * @param me detailed information to transmit
3369 */
3370static void
3371notify_monitor (struct TransportClient *tc,
3372 const struct GNUNET_PeerIdentity *peer,
3373 const char *address,
3374 enum GNUNET_NetworkType nt,
3375 const struct MonitorEvent *me)
3376{
3377 struct GNUNET_MQ_Envelope *env;
3378 struct GNUNET_TRANSPORT_MonitorData *md;
3379 size_t addr_len = strlen (address) + 1;
3380
3381 env = GNUNET_MQ_msg_extra (md,
3382 addr_len,
3383 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_DATA);
3384 md->nt = htonl ((uint32_t) nt);
3385 md->peer = *peer;
3386 md->last_validation = GNUNET_TIME_absolute_hton (me->last_validation);
3387 md->valid_until = GNUNET_TIME_absolute_hton (me->valid_until);
3388 md->next_validation = GNUNET_TIME_absolute_hton (me->next_validation);
3389 md->rtt = GNUNET_TIME_relative_hton (me->rtt);
3390 md->cs = htonl ((uint32_t) me->cs);
3391 md->num_msg_pending = htonl (me->num_msg_pending);
3392 md->num_bytes_pending = htonl (me->num_bytes_pending);
3393 memcpy (&md[1], address, addr_len);
3394 GNUNET_MQ_send (tc->mq, env);
3395}
3396
3397
3398/**
3399 * Send information in @a me about a @a peer's status with respect
3400 * to some @a address to all monitors that care.
3401 *
3402 * @param peer peer the information is about
3403 * @param address address the information is about
3404 * @param nt network type associated with @a address
3405 * @param me detailed information to transmit
3406 */
3407static void
3408notify_monitors (const struct GNUNET_PeerIdentity *peer,
3409 const char *address,
3410 enum GNUNET_NetworkType nt,
3411 const struct MonitorEvent *me)
3412{
3413 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
3414 {
3415 if (CT_MONITOR != tc->type)
3416 continue;
3417 if (tc->details.monitor.one_shot)
3418 continue;
3419 if ((GNUNET_NO == GNUNET_is_zero (&tc->details.monitor.peer)) &&
3420 (0 != GNUNET_memcmp (&tc->details.monitor.peer, peer)))
3421 continue;
3422 notify_monitor (tc, peer, address, nt, me);
3423 }
3424}
3425
3426
3427/**
3428 * Called whenever a client connects. Allocates our
3429 * data structures associated with that client.
3430 *
3431 * @param cls closure, NULL
3432 * @param client identification of the client
3433 * @param mq message queue for the client
3434 * @return our `struct TransportClient`
3435 */
3436static void *
3437client_connect_cb (void *cls,
3438 struct GNUNET_SERVICE_Client *client,
3439 struct GNUNET_MQ_Handle *mq)
3440{
3441 struct TransportClient *tc;
3442
3443 (void) cls;
3444 tc = GNUNET_new (struct TransportClient);
3445 tc->client = client;
3446 tc->mq = mq;
3447 GNUNET_CONTAINER_DLL_insert (clients_head, clients_tail, tc);
3448 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3449 "Client %p of type %u connected\n",
3450 tc,
3451 tc->type);
3452 return tc;
3453}
3454
3455
3456/**
3457 * Release memory used by @a neighbour.
3458 *
3459 * @param neighbour neighbour entry to free
3460 */
3461static void
3462free_neighbour (struct Neighbour *neighbour)
3463{
3464 struct DistanceVectorHop *dvh;
3465 struct VirtualLink *vl;
3466
3467 GNUNET_assert (NULL == neighbour->queue_head);
3468 GNUNET_assert (GNUNET_YES ==
3469 GNUNET_CONTAINER_multipeermap_remove (neighbours,
3470 &neighbour->pid,
3471 neighbour));
3472 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3473 "Freeing neighbour\n");
3474 while (NULL != (dvh = neighbour->dv_head))
3475 {
3476 struct DistanceVector *dv = dvh->dv;
3477
3478 free_distance_vector_hop (dvh);
3479 if (NULL == dv->dv_head)
3480 free_dv_route (dv);
3481 }
3482 if (NULL != neighbour->get)
3483 {
3484 GNUNET_PEERSTORE_iterate_cancel (neighbour->get);
3485 neighbour->get = NULL;
3486 }
3487 if (NULL != neighbour->sc)
3488 {
3489 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3490 "store cancel\n");
3491 GNUNET_PEERSTORE_store_cancel (neighbour->sc);
3492 neighbour->sc = NULL;
3493 }
3494 if (NULL != (vl = neighbour->vl))
3495 {
3496 GNUNET_assert (neighbour == vl->n);
3497 vl->n = NULL;
3498 if (NULL == vl->dv)
3499 {
3500 cores_send_disconnect_info (&vl->target);
3501 free_virtual_link (vl);
3502 }
3503 else
3504 {
3505 GNUNET_SCHEDULER_cancel (vl->visibility_task);
3506 vl->visibility_task = GNUNET_SCHEDULER_add_now (&check_link_down, vl);
3507 }
3508 neighbour->vl = NULL;
3509 }
3510 GNUNET_free (neighbour);
3511}
3512
3513
3514/**
3515 * Send message to CORE clients that we lost a connection.
3516 *
3517 * @param tc client to inform (must be CORE client)
3518 * @param pid peer the connection is for
3519 */
3520static void
3521core_send_connect_info (struct TransportClient *tc,
3522 const struct GNUNET_PeerIdentity *pid)
3523{
3524 struct GNUNET_MQ_Envelope *env;
3525 struct ConnectInfoMessage *cim;
3526
3527 GNUNET_assert (CT_CORE == tc->type);
3528 env = GNUNET_MQ_msg (cim, GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
3529 cim->id = *pid;
3530 GNUNET_MQ_send (tc->mq, env);
3531}
3532
3533
3534/**
3535 * Send message to CORE clients that we gained a connection
3536 *
3537 * @param pid peer the queue was for
3538 */
3539static void
3540cores_send_connect_info (const struct GNUNET_PeerIdentity *pid)
3541{
3542 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3543 "Informing CORE clients about connection to %s\n",
3544 GNUNET_i2s (pid));
3545 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
3546 {
3547 if (CT_CORE != tc->type)
3548 continue;
3549 core_send_connect_info (tc, pid);
3550 }
3551}
3552
3553
3554/**
3555 * We believe we are ready to transmit a message on a queue. Gives the
3556 * message to the communicator for transmission (updating the tracker,
3557 * and re-scheduling itself if applicable).
3558 *
3559 * @param cls the `struct Queue` to process transmissions for
3560 */
3561static void
3562transmit_on_queue (void *cls);
3563
3564
3565/**
3566 * Check if the communicator has another queue with higher prio ready for sending.
3567 */
3568static unsigned int
3569check_for_queue_with_higher_prio (struct Queue *queue, struct Queue *queue_head)
3570{
3571 for (struct Queue *s = queue_head; NULL != s;
3572 s = s->next_client)
3573 {
3574 if (s->tc->details.communicator.address_prefix !=
3575 queue->tc->details.communicator.address_prefix)
3576 {
3577 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3578 "queue address %s qid %u compare with queue: address %s qid %u\n",
3579 queue->address,
3580 queue->qid,
3581 s->address,
3582 s->qid);
3583 if ((s->priority > queue->priority) && (0 < s->q_capacity) &&
3584 (QUEUE_LENGTH_LIMIT > s->queue_length) )
3585 return GNUNET_YES;
3586 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3587 "Lower prio\n");
3588 }
3589 }
3590 return GNUNET_NO;
3591}
3592
3593
3594/**
3595 * Called whenever something changed that might effect when we
3596 * try to do the next transmission on @a queue using #transmit_on_queue().
3597 *
3598 * @param queue the queue to do scheduling for
3599 * @param p task priority to use, if @a queue is scheduled
3600 */
3601static void
3602schedule_transmit_on_queue (struct GNUNET_TIME_Relative delay,
3603 struct Queue *queue,
3604 enum GNUNET_SCHEDULER_Priority p)
3605{
3606 if (check_for_queue_with_higher_prio (queue,
3607 queue->tc->details.communicator.
3608 queue_head))
3609 return;
3610
3611 if (queue->tc->details.communicator.total_queue_length >=
3612 COMMUNICATOR_TOTAL_QUEUE_LIMIT)
3613 {
3614 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3615 "Transmission throttled due to communicator queue limit\n");
3616 GNUNET_STATISTICS_update (
3617 GST_stats,
3618 "# Transmission throttled due to communicator queue limit",
3619 1,
3620 GNUNET_NO);
3621 queue->idle = GNUNET_NO;
3622 return;
3623 }
3624 if (queue->queue_length >= QUEUE_LENGTH_LIMIT)
3625 {
3626 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3627 "Transmission throttled due to communicator queue length limit\n");
3628 GNUNET_STATISTICS_update (GST_stats,
3629 "# Transmission throttled due to queue queue limit",
3630 1,
3631 GNUNET_NO);
3632 queue->idle = GNUNET_NO;
3633 return;
3634 }
3635 if (0 == queue->q_capacity)
3636 {
3637 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3638 "Transmission throttled due to communicator message queue qid %u has capacity %lu.\n",
3639 queue->qid,
3640 queue->q_capacity);
3641 GNUNET_STATISTICS_update (GST_stats,
3642 "# Transmission throttled due to message queue capacity",
3643 1,
3644 GNUNET_NO);
3645 queue->idle = GNUNET_NO;
3646 return;
3647 }
3648 /* queue might indeed be ready, schedule it */
3649 if (NULL != queue->transmit_task)
3650 GNUNET_SCHEDULER_cancel (queue->transmit_task);
3651 queue->transmit_task =
3652 GNUNET_SCHEDULER_add_delayed_with_priority (delay, p, &transmit_on_queue,
3653 queue);
3654 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3655 "Considering transmission on queue `%s' QID %llu to %s\n",
3656 queue->address,
3657 (unsigned long long) queue->qid,
3658 GNUNET_i2s (&queue->neighbour->pid));
3659}
3660
3661
3662/**
3663 * Task run to check whether the hops of the @a cls still
3664 * are validated, or if we need to core about disconnection.
3665 *
3666 * @param cls a `struct VirtualLink`
3667 */
3668static void
3669check_link_down (void *cls)
3670{
3671 struct VirtualLink *vl = cls;
3672 struct DistanceVector *dv = vl->dv;
3673 struct Neighbour *n = vl->n;
3674 struct GNUNET_TIME_Absolute dvh_timeout;
3675 struct GNUNET_TIME_Absolute q_timeout;
3676
3677 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3678 "Checking if link is down\n");
3679 vl->visibility_task = NULL;
3680 dvh_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
3681 if (NULL != dv)
3682 {
3683 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3684 pos = pos->next_dv)
3685 dvh_timeout = GNUNET_TIME_absolute_max (dvh_timeout,
3686 pos->path_valid_until);
3687 if (0 == GNUNET_TIME_absolute_get_remaining (dvh_timeout).rel_value_us)
3688 {
3689 vl->dv->vl = NULL;
3690 vl->dv = NULL;
3691 }
3692 }
3693 q_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
3694 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
3695 q_timeout = GNUNET_TIME_absolute_max (q_timeout, q->validated_until);
3696 if (0 == GNUNET_TIME_absolute_get_remaining (q_timeout).rel_value_us)
3697 {
3698 vl->n->vl = NULL;
3699 vl->n = NULL;
3700 }
3701 if ((NULL == vl->n) && (NULL == vl->dv))
3702 {
3703 cores_send_disconnect_info (&vl->target);
3704 free_virtual_link (vl);
3705 return;
3706 }
3707 vl->visibility_task =
3708 GNUNET_SCHEDULER_add_at (GNUNET_TIME_absolute_max (q_timeout, dvh_timeout),
3709 &check_link_down,
3710 vl);
3711}
3712
3713
3714/**
3715 * Free @a queue.
3716 *
3717 * @param queue the queue to free
3718 */
3719static void
3720free_queue (struct Queue *queue)
3721{
3722 struct Neighbour *neighbour = queue->neighbour;
3723 struct TransportClient *tc = queue->tc;
3724 struct MonitorEvent me = { .cs = GNUNET_TRANSPORT_CS_DOWN,
3725 .rtt = GNUNET_TIME_UNIT_FOREVER_REL };
3726 struct QueueEntry *qe;
3727 int maxxed;
3728 struct PendingAcknowledgement *pa;
3729 struct VirtualLink *vl;
3730
3731 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3732 "Cleaning up queue %u\n", queue->qid);
3733 if (NULL != queue->transmit_task)
3734 {
3735 GNUNET_SCHEDULER_cancel (queue->transmit_task);
3736 queue->transmit_task = NULL;
3737 }
3738 while (NULL != (pa = queue->pa_head))
3739 {
3740 GNUNET_CONTAINER_MDLL_remove (queue, queue->pa_head, queue->pa_tail, pa);
3741 pa->queue = NULL;
3742 }
3743
3744 GNUNET_CONTAINER_MDLL_remove (neighbour,
3745 neighbour->queue_head,
3746 neighbour->queue_tail,
3747 queue);
3748 GNUNET_CONTAINER_MDLL_remove (client,
3749 tc->details.communicator.queue_head,
3750 tc->details.communicator.queue_tail,
3751 queue);
3752 maxxed = (COMMUNICATOR_TOTAL_QUEUE_LIMIT <=
3753 tc->details.communicator.
3754 total_queue_length);
3755 while (NULL != (qe = queue->queue_head))
3756 {
3757 GNUNET_CONTAINER_DLL_remove (queue->queue_head, queue->queue_tail, qe);
3758 queue->queue_length--;
3759 tc->details.communicator.total_queue_length--;
3760 if (NULL != qe->pm)
3761 {
3762 GNUNET_assert (qe == qe->pm->qe);
3763 qe->pm->qe = NULL;
3764 }
3765 GNUNET_free (qe);
3766 }
3767 GNUNET_assert (0 == queue->queue_length);
3768 if ((maxxed) && (COMMUNICATOR_TOTAL_QUEUE_LIMIT >
3769 tc->details.communicator.total_queue_length))
3770 {
3771 /* Communicator dropped below threshold, resume all _other_ queues */
3772 GNUNET_STATISTICS_update (
3773 GST_stats,
3774 "# Transmission throttled due to communicator queue limit",
3775 -1,
3776 GNUNET_NO);
3777 for (struct Queue *s = tc->details.communicator.queue_head; NULL != s;
3778 s = s->next_client)
3779 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
3780 s,
3781 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
3782 }
3783 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
3784 GNUNET_free (queue);
3785
3786 vl = lookup_virtual_link (&neighbour->pid);
3787 if ((NULL != vl) && (GNUNET_YES == vl->confirmed) && (neighbour == vl->n))
3788 {
3789 GNUNET_SCHEDULER_cancel (vl->visibility_task);
3790 check_link_down (vl);
3791 }
3792 if (NULL == neighbour->queue_head)
3793 {
3794 free_neighbour (neighbour);
3795 }
3796}
3797
3798
3799/**
3800 * Free @a ale
3801 *
3802 * @param ale address list entry to free
3803 */
3804static void
3805free_address_list_entry (struct AddressListEntry *ale)
3806{
3807 struct TransportClient *tc = ale->tc;
3808
3809 GNUNET_CONTAINER_DLL_remove (tc->details.communicator.addr_head,
3810 tc->details.communicator.addr_tail,
3811 ale);
3812 if (NULL != ale->sc)
3813 {
3814 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3815 "store cancel\n");
3816 GNUNET_PEERSTORE_store_cancel (ale->sc);
3817 ale->sc = NULL;
3818 }
3819 if (NULL != ale->st)
3820 {
3821 GNUNET_SCHEDULER_cancel (ale->st);
3822 ale->st = NULL;
3823 }
3824 GNUNET_free (ale);
3825}
3826
3827
3828/**
3829 * Stop the peer request in @a value.
3830 *
3831 * @param cls a `struct TransportClient` that no longer makes the request
3832 * @param pid the peer's identity
3833 * @param value a `struct PeerRequest`
3834 * @return #GNUNET_YES (always)
3835 */
3836static int
3837stop_peer_request (void *cls,
3838 const struct GNUNET_PeerIdentity *pid,
3839 void *value)
3840{
3841 struct TransportClient *tc = cls;
3842 struct PeerRequest *pr = value;
3843
3844 GNUNET_PEERSTORE_watch_cancel (pr->wc);
3845 pr->wc = NULL;
3846 GNUNET_assert (
3847 GNUNET_YES ==
3848 GNUNET_CONTAINER_multipeermap_remove (tc->details.application.requests,
3849 pid,
3850 pr));
3851 GNUNET_free (pr);
3852
3853 return GNUNET_OK;
3854}
3855
3856
3857static void
3858do_shutdown (void *cls);
3859
3860/**
3861 * Called whenever a client is disconnected. Frees our
3862 * resources associated with that client.
3863 *
3864 * @param cls closure, NULL
3865 * @param client identification of the client
3866 * @param app_ctx our `struct TransportClient`
3867 */
3868static void
3869client_disconnect_cb (void *cls,
3870 struct GNUNET_SERVICE_Client *client,
3871 void *app_ctx)
3872{
3873 struct TransportClient *tc = app_ctx;
3874
3875 (void) cls;
3876 (void) client;
3877 GNUNET_CONTAINER_DLL_remove (clients_head, clients_tail, tc);
3878 switch (tc->type)
3879 {
3880 case CT_NONE:
3881 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3882 "Unknown Client %p disconnected, cleaning up.\n",
3883 tc);
3884 break;
3885
3886 case CT_CORE: {
3887 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3888 "CORE Client %p disconnected, cleaning up.\n",
3889 tc);
3890
3891 struct PendingMessage *pm;
3892
3893 while (NULL != (pm = tc->details.core.pending_msg_head))
3894 {
3895 GNUNET_CONTAINER_MDLL_remove (client,
3896 tc->details.core.pending_msg_head,
3897 tc->details.core.pending_msg_tail,
3898 pm);
3899 pm->client = NULL;
3900 }
3901 }
3902 break;
3903
3904 case CT_MONITOR:
3905 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3906 "MONITOR Client %p disconnected, cleaning up.\n",
3907 tc);
3908
3909 break;
3910
3911 case CT_COMMUNICATOR: {
3912 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3913 "COMMUNICATOR Client %p disconnected, cleaning up.\n",
3914 tc);
3915
3916 struct Queue *q;
3917 struct AddressListEntry *ale;
3918
3919 while (NULL != (q = tc->details.communicator.queue_head))
3920 free_queue (q);
3921 while (NULL != (ale = tc->details.communicator.addr_head))
3922 free_address_list_entry (ale);
3923 GNUNET_free (tc->details.communicator.address_prefix);
3924 }
3925 break;
3926
3927 case CT_APPLICATION:
3928 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3929 "APPLICATION Client %p disconnected, cleaning up.\n",
3930 tc);
3931
3932 GNUNET_CONTAINER_multipeermap_iterate (tc->details.application.requests,
3933 &stop_peer_request,
3934 tc);
3935 GNUNET_CONTAINER_multipeermap_destroy (tc->details.application.requests);
3936 break;
3937 }
3938 GNUNET_free (tc);
3939 if ((GNUNET_YES == in_shutdown) && (NULL == clients_head))
3940 {
3941 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3942 "Our last client disconnected\n");
3943 do_shutdown (cls);
3944 }
3945}
3946
3947
3948/**
3949 * Iterator telling new CORE client about all existing
3950 * connections to peers.
3951 *
3952 * @param cls the new `struct TransportClient`
3953 * @param pid a connected peer
3954 * @param value the `struct Neighbour` with more information
3955 * @return #GNUNET_OK (continue to iterate)
3956 */
3957static int
3958notify_client_connect_info (void *cls,
3959 const struct GNUNET_PeerIdentity *pid,
3960 void *value)
3961{
3962 struct TransportClient *tc = cls;
3963
3964 (void) value;
3965 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3966 "Telling new CORE client about existing connection to %s\n",
3967 GNUNET_i2s (pid));
3968 core_send_connect_info (tc, pid);
3969 return GNUNET_OK;
3970}
3971
3972
3973/**
3974 * Initialize a "CORE" client. We got a start message from this
3975 * client, so add it to the list of clients for broadcasting of
3976 * inbound messages.
3977 *
3978 * @param cls the client
3979 * @param start the start message that was sent
3980 */
3981static void
3982handle_client_start (void *cls, const struct StartMessage *start)
3983{
3984 struct TransportClient *tc = cls;
3985 uint32_t options;
3986
3987 options = ntohl (start->options);
3988 if ((0 != (1 & options)) &&
3989 (0 != GNUNET_memcmp (&start->self, &GST_my_identity)))
3990 {
3991 /* client thinks this is a different peer, reject */
3992 GNUNET_break (0);
3993 GNUNET_SERVICE_client_drop (tc->client);
3994 return;
3995 }
3996 if (CT_NONE != tc->type)
3997 {
3998 GNUNET_break (0);
3999 GNUNET_SERVICE_client_drop (tc->client);
4000 return;
4001 }
4002 tc->type = CT_CORE;
4003 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4004 "New CORE client with PID %s registered\n",
4005 GNUNET_i2s (&start->self));
4006 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
4007 &notify_client_connect_info,
4008 tc);
4009 GNUNET_SERVICE_client_continue (tc->client);
4010}
4011
4012
4013/**
4014 * Client asked for transmission to a peer. Process the request.
4015 *
4016 * @param cls the client
4017 * @param obm the send message that was sent
4018 */
4019static int
4020check_client_send (void *cls, const struct OutboundMessage *obm)
4021{
4022 struct TransportClient *tc = cls;
4023 uint16_t size;
4024 const struct GNUNET_MessageHeader *obmm;
4025
4026 if (CT_CORE != tc->type)
4027 {
4028 GNUNET_break (0);
4029 return GNUNET_SYSERR;
4030 }
4031 size = ntohs (obm->header.size) - sizeof(struct OutboundMessage);
4032 if (size < sizeof(struct GNUNET_MessageHeader))
4033 {
4034 GNUNET_break (0);
4035 return GNUNET_SYSERR;
4036 }
4037 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
4038 if (size != ntohs (obmm->size))
4039 {
4040 GNUNET_break (0);
4041 return GNUNET_SYSERR;
4042 }
4043 return GNUNET_OK;
4044}
4045
4046
4047/**
4048 * Send a response to the @a pm that we have processed a "send"
4049 * request. Sends a confirmation to the "core" client responsible for
4050 * the original request and free's @a pm.
4051 *
4052 * @param pm handle to the original pending message
4053 */
4054static void
4055client_send_response (struct PendingMessage *pm)
4056{
4057 struct TransportClient *tc = pm->client;
4058 struct VirtualLink *vl = pm->vl;
4059
4060 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4061 "client send response\n");
4062 if (NULL != tc)
4063 {
4064 struct GNUNET_MQ_Envelope *env;
4065 struct SendOkMessage *so_msg;
4066
4067 env = GNUNET_MQ_msg (so_msg, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
4068 so_msg->peer = vl->target;
4069 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4070 "Confirming transmission of <%llu> to %s\n",
4071 pm->logging_uuid,
4072 GNUNET_i2s (&vl->target));
4073 GNUNET_MQ_send (tc->mq, env);
4074 }
4075 free_pending_message (pm);
4076}
4077
4078
4079/**
4080 * Pick @a hops_array_length random DV paths satisfying @a options
4081 *
4082 * @param dv data structure to pick paths from
4083 * @param options constraints to satisfy
4084 * @param hops_array[out] set to the result
4085 * @param hops_array_length length of the @a hops_array
4086 * @return number of entries set in @a hops_array
4087 */
4088static unsigned int
4089pick_random_dv_hops (const struct DistanceVector *dv,
4090 enum RouteMessageOptions options,
4091 struct DistanceVectorHop **hops_array,
4092 unsigned int hops_array_length)
4093{
4094 uint64_t choices[hops_array_length];
4095 uint64_t num_dv;
4096 unsigned int dv_count;
4097
4098 /* Pick random vectors, but weighted by distance, giving more weight
4099 to shorter vectors */
4100 num_dv = 0;
4101 dv_count = 0;
4102 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
4103 pos = pos->next_dv)
4104 {
4105 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
4106 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
4107 .rel_value_us == 0))
4108 continue; /* pos unconfirmed and confirmed required */
4109 num_dv += MAX_DV_HOPS_ALLOWED - pos->distance;
4110 dv_count++;
4111 }
4112 if (0 == dv_count)
4113 return 0;
4114 if (dv_count <= hops_array_length)
4115 {
4116 dv_count = 0;
4117 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
4118 pos = pos->next_dv)
4119 hops_array[dv_count++] = pos;
4120 return dv_count;
4121 }
4122 for (unsigned int i = 0; i < hops_array_length; i++)
4123 {
4124 int ok = GNUNET_NO;
4125 while (GNUNET_NO == ok)
4126 {
4127 choices[i] =
4128 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, num_dv);
4129 ok = GNUNET_YES;
4130 for (unsigned int j = 0; j < i; j++)
4131 if (choices[i] == choices[j])
4132 {
4133 ok = GNUNET_NO;
4134 break;
4135 }
4136 }
4137 }
4138 dv_count = 0;
4139 num_dv = 0;
4140 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
4141 pos = pos->next_dv)
4142 {
4143 uint32_t delta = MAX_DV_HOPS_ALLOWED - pos->distance;
4144
4145 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
4146 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
4147 .rel_value_us == 0))
4148 continue; /* pos unconfirmed and confirmed required */
4149 for (unsigned int i = 0; i < hops_array_length; i++)
4150 if ((num_dv <= choices[i]) && (num_dv + delta > choices[i]))
4151 hops_array[dv_count++] = pos;
4152 num_dv += delta;
4153 }
4154 return dv_count;
4155}
4156
4157
4158/**
4159 * Communicator started. Test message is well-formed.
4160 *
4161 * @param cls the client
4162 * @param cam the send message that was sent
4163 */
4164static int
4165check_communicator_available (
4166 void *cls,
4167 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
4168{
4169 struct TransportClient *tc = cls;
4170 uint16_t size;
4171
4172 if (CT_NONE != tc->type)
4173 {
4174 GNUNET_break (0);
4175 return GNUNET_SYSERR;
4176 }
4177 tc->type = CT_COMMUNICATOR;
4178 size = ntohs (cam->header.size) - sizeof(*cam);
4179 if (0 == size)
4180 return GNUNET_OK; /* receive-only communicator */
4181 GNUNET_MQ_check_zero_termination (cam);
4182 return GNUNET_OK;
4183}
4184
4185
4186/**
4187 * Send ACK to communicator (if requested) and free @a cmc.
4188 *
4189 * @param cmc context for which we are done handling the message
4190 */
4191static void
4192finish_cmc_handling (struct CommunicatorMessageContext *cmc)
4193{
4194 if (0 != ntohl (cmc->im.fc_on))
4195 {
4196 /* send ACK when done to communicator for flow control! */
4197 struct GNUNET_MQ_Envelope *env;
4198 struct GNUNET_TRANSPORT_IncomingMessageAck *ack;
4199
4200 env = GNUNET_MQ_msg (ack, GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG_ACK);
4201 ack->reserved = htonl (0);
4202 ack->fc_id = cmc->im.fc_id;
4203 ack->sender = cmc->im.sender;
4204 GNUNET_MQ_send (cmc->tc->mq, env);
4205 }
4206 GNUNET_SERVICE_client_continue (cmc->tc->client);
4207 GNUNET_free (cmc);
4208}
4209
4210
4211/**
4212 * Client confirms that it is done handling message(s) to a particular
4213 * peer. We may now provide more messages to CORE for this peer.
4214 *
4215 * Notifies the respective queues that more messages can now be received.
4216 *
4217 * @param cls the client
4218 * @param rom the message that was sent
4219 */
4220static void
4221handle_client_recv_ok (void *cls, const struct RecvOkMessage *rom)
4222{
4223 struct TransportClient *tc = cls;
4224 struct VirtualLink *vl;
4225 uint32_t delta;
4226 struct CommunicatorMessageContext *cmc;
4227
4228 if (CT_CORE != tc->type)
4229 {
4230 GNUNET_break (0);
4231 GNUNET_SERVICE_client_drop (tc->client);
4232 return;
4233 }
4234 vl = lookup_virtual_link (&rom->peer);
4235 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
4236 {
4237 GNUNET_STATISTICS_update (GST_stats,
4238 "# RECV_OK dropped: virtual link unknown",
4239 1,
4240 GNUNET_NO);
4241 GNUNET_SERVICE_client_continue (tc->client);
4242 return;
4243 }
4244 delta = ntohl (rom->increase_window_delta);
4245 vl->core_recv_window += delta;
4246 if (vl->core_recv_window <= 0)
4247 return;
4248 /* resume communicators */
4249 while (NULL != (cmc = vl->cmc_tail))
4250 {
4251 GNUNET_CONTAINER_DLL_remove (vl->cmc_head, vl->cmc_tail, cmc);
4252 finish_cmc_handling (cmc);
4253 }
4254}
4255
4256
4257/**
4258 * Communicator started. Process the request.
4259 *
4260 * @param cls the client
4261 * @param cam the send message that was sent
4262 */
4263static void
4264handle_communicator_available (
4265 void *cls,
4266 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
4267{
4268 struct TransportClient *tc = cls;
4269 uint16_t size;
4270
4271 size = ntohs (cam->header.size) - sizeof(*cam);
4272 if (0 == size)
4273 {
4274 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4275 "Receive-only communicator connected\n");
4276 return; /* receive-only communicator */
4277 }
4278 tc->details.communicator.address_prefix =
4279 GNUNET_strdup ((const char *) &cam[1]);
4280 tc->details.communicator.cc =
4281 (enum GNUNET_TRANSPORT_CommunicatorCharacteristics) ntohl (cam->cc);
4282 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4283 "Communicator with prefix `%s' connected\n",
4284 tc->details.communicator.address_prefix);
4285 GNUNET_SERVICE_client_continue (tc->client);
4286}
4287
4288
4289/**
4290 * Communicator requests backchannel transmission. Check the request.
4291 *
4292 * @param cls the client
4293 * @param cb the send message that was sent
4294 * @return #GNUNET_OK if message is well-formed
4295 */
4296static int
4297check_communicator_backchannel (
4298 void *cls,
4299 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
4300{
4301 const struct GNUNET_MessageHeader *inbox;
4302 const char *is;
4303 uint16_t msize;
4304 uint16_t isize;
4305
4306 (void) cls;
4307 msize = ntohs (cb->header.size) - sizeof(*cb);
4308 inbox = (const struct GNUNET_MessageHeader *) &cb[1];
4309 isize = ntohs (inbox->size);
4310 if (isize >= msize)
4311 {
4312 GNUNET_break (0);
4313 return GNUNET_SYSERR;
4314 }
4315 is = (const char *) inbox;
4316 is += isize;
4317 msize -= isize;
4318 GNUNET_assert (0 < msize);
4319 if ('\0' != is[msize - 1])
4320 {
4321 GNUNET_break (0);
4322 return GNUNET_SYSERR;
4323 }
4324 return GNUNET_OK;
4325}
4326
4327
4328/**
4329 * Ensure ephemeral keys in our @a dv are current. If no current one exists,
4330 * set it up.
4331 *
4332 * @param dv[in,out] virtual link to update ephemeral for
4333 */
4334static void
4335update_ephemeral (struct DistanceVector *dv)
4336{
4337 struct EphemeralConfirmationPS ec;
4338
4339 if (0 !=
4340 GNUNET_TIME_absolute_get_remaining (dv->ephemeral_validity).rel_value_us)
4341 return;
4342 dv->monotime = GNUNET_TIME_absolute_get_monotonic (GST_cfg);
4343 dv->ephemeral_validity =
4344 GNUNET_TIME_absolute_add (dv->monotime, EPHEMERAL_VALIDITY);
4345 GNUNET_CRYPTO_ecdhe_key_create (&dv->private_key);
4346 GNUNET_CRYPTO_ecdhe_key_get_public (&dv->private_key, &dv->ephemeral_key);
4347 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
4348 ec.target = dv->target;
4349 ec.ephemeral_key = dv->ephemeral_key;
4350 ec.sender_monotonic_time = GNUNET_TIME_absolute_hton (dv->monotime);
4351 ec.purpose.size = htonl (sizeof(ec));
4352 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
4353 &ec,
4354 &dv->sender_sig);
4355}
4356
4357
4358/**
4359 * Send the message @a payload on @a queue.
4360 *
4361 * @param queue the queue to use for transmission
4362 * @param pm pending message to update once transmission is done, may be NULL!
4363 * @param payload the payload to send (encapsulated in a
4364 * #GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG).
4365 * @param payload_size number of bytes in @a payload
4366 */
4367static void
4368queue_send_msg (struct Queue *queue,
4369 struct PendingMessage *pm,
4370 const void *payload,
4371 size_t payload_size)
4372{
4373 struct Neighbour *n = queue->neighbour;
4374 struct GNUNET_TRANSPORT_SendMessageTo *smt;
4375 struct GNUNET_MQ_Envelope *env;
4376
4377 GNUNET_log (
4378 GNUNET_ERROR_TYPE_DEBUG,
4379 "Queueing %u bytes of payload for transmission <%llu> on queue %llu to %s\n",
4380 (unsigned int) payload_size,
4381 (NULL == pm) ? 0 : pm->logging_uuid,
4382 (unsigned long long) queue->qid,
4383 GNUNET_i2s (&queue->neighbour->pid));
4384 env = GNUNET_MQ_msg_extra (smt,
4385 payload_size,
4386 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG);
4387 smt->qid = queue->qid;
4388 smt->mid = queue->mid_gen;
4389 smt->receiver = n->pid;
4390 memcpy (&smt[1], payload, payload_size);
4391 {
4392 /* Pass the env to the communicator of queue for transmission. */
4393 struct QueueEntry *qe;
4394
4395 qe = GNUNET_new (struct QueueEntry);
4396 qe->mid = queue->mid_gen++;
4397 qe->queue = queue;
4398 if (NULL != pm)
4399 {
4400 qe->pm = pm;
4401 // TODO Why do we have a retransmission. When we know, make decision if we still want this.
4402 // GNUNET_assert (NULL == pm->qe);
4403 /*if (NULL != pm->qe)
4404 {
4405 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4406 "Retransmitting message <%llu> remove pm from qe with MID: %llu \n",
4407 pm->logging_uuid,
4408 (unsigned long long) pm->qe->mid);
4409 pm->qe->pm = NULL;
4410 }*/
4411 pm->qe = qe;
4412 }
4413 GNUNET_CONTAINER_DLL_insert (queue->queue_head, queue->queue_tail, qe);
4414 GNUNET_assert (CT_COMMUNICATOR == queue->tc->type);
4415 queue->queue_length++;
4416 queue->tc->details.communicator.total_queue_length++;
4417 if (0 == queue->q_capacity)
4418 return;
4419 if (GNUNET_NO == queue->unlimited_length)
4420 queue->q_capacity--;
4421 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4422 "Queue %s with qid %u has capacity %lu\n",
4423 queue->address,
4424 queue->qid,
4425 queue->q_capacity);
4426 if (COMMUNICATOR_TOTAL_QUEUE_LIMIT ==
4427 queue->tc->details.communicator.total_queue_length)
4428 queue->idle = GNUNET_NO;
4429 if (QUEUE_LENGTH_LIMIT == queue->queue_length)
4430 queue->idle = GNUNET_NO;
4431 if (0 == queue->q_capacity)
4432 queue->idle = GNUNET_NO;
4433 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4434 "Sending message MID %llu of type %u (%u) and size %u with MQ %p\n",
4435 smt->mid,
4436 ntohs (((const struct GNUNET_MessageHeader *) payload)->type),
4437 ntohs (smt->header.size),
4438 payload_size,
4439 queue->tc->mq);
4440 GNUNET_MQ_send (queue->tc->mq, env);
4441 }
4442}
4443
4444
4445/**
4446 * Pick a queue of @a n under constraints @a options and schedule
4447 * transmission of @a hdr.
4448 *
4449 * @param n neighbour to send to
4450 * @param hdr message to send as payload
4451 * @param options whether queues must be confirmed or not,
4452 * and whether we may pick multiple (2) queues
4453 * @return expected RTT for transmission, #GNUNET_TIME_UNIT_FOREVER_REL if sending failed
4454 */
4455static struct GNUNET_TIME_Relative
4456route_via_neighbour (const struct Neighbour *n,
4457 const struct GNUNET_MessageHeader *hdr,
4458 enum RouteMessageOptions options)
4459{
4460 struct GNUNET_TIME_Absolute now;
4461 unsigned int candidates;
4462 unsigned int sel1;
4463 unsigned int sel2;
4464 struct GNUNET_TIME_Relative rtt;
4465
4466 /* Pick one or two 'random' queues from n (under constraints of options) */
4467 now = GNUNET_TIME_absolute_get ();
4468 /* FIXME-OPTIMIZE: give queues 'weights' and pick proportional to
4469 weight in the future; weight could be assigned by observed
4470 bandwidth (note: not sure if we should do this for this type
4471 of control traffic though). */
4472 candidates = 0;
4473 for (struct Queue *pos = n->queue_head; NULL != pos;
4474 pos = pos->next_neighbour)
4475 {
4476 if ((0 != (options & RMO_UNCONFIRMED_ALLOWED)) ||
4477 (pos->validated_until.abs_value_us > now.abs_value_us))
4478 candidates++;
4479 }
4480 if (0 == candidates)
4481 {
4482 /* This can happen rarely if the last confirmed queue timed
4483 out just as we were beginning to process this message. */
4484 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4485 "Could not route message of type %u to %s: no valid queue\n",
4486 ntohs (hdr->type),
4487 GNUNET_i2s (&n->pid));
4488 GNUNET_STATISTICS_update (GST_stats,
4489 "# route selection failed (all no valid queue)",
4490 1,
4491 GNUNET_NO);
4492 return GNUNET_TIME_UNIT_FOREVER_REL;
4493 }
4494
4495 rtt = GNUNET_TIME_UNIT_FOREVER_REL;
4496 sel1 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
4497 if (0 == (options & RMO_REDUNDANT))
4498 sel2 = candidates; /* picks none! */
4499 else
4500 sel2 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
4501 candidates = 0;
4502 for (struct Queue *pos = n->queue_head; NULL != pos;
4503 pos = pos->next_neighbour)
4504 {
4505 if ((0 != (options & RMO_UNCONFIRMED_ALLOWED)) ||
4506 (pos->validated_until.abs_value_us > now.abs_value_us))
4507 {
4508 if ((sel1 == candidates) || (sel2 == candidates))
4509 {
4510 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4511 "Routing message of type %u to %s using %s (#%u)\n",
4512 ntohs (hdr->type),
4513 GNUNET_i2s (&n->pid),
4514 pos->address,
4515 (sel1 == candidates) ? 1 : 2);
4516 rtt = GNUNET_TIME_relative_min (rtt, pos->pd.aged_rtt);
4517 queue_send_msg (pos, NULL, hdr, ntohs (hdr->size));
4518 }
4519 candidates++;
4520 }
4521 }
4522 return rtt;
4523}
4524
4525
4526/**
4527 * Structure of the key material used to encrypt backchannel messages.
4528 */
4529struct DVKeyState
4530{
4531 /**
4532 * State of our block cipher.
4533 */
4534 gcry_cipher_hd_t cipher;
4535
4536 /**
4537 * Actual key material.
4538 */
4539 struct
4540 {
4541 /**
4542 * Key used for HMAC calculations (via #GNUNET_CRYPTO_hmac()).
4543 */
4544 struct GNUNET_CRYPTO_AuthKey hmac_key;
4545
4546 /**
4547 * Symmetric key to use for encryption.
4548 */
4549 char aes_key[256 / 8];
4550
4551 /**
4552 * Counter value to use during setup.
4553 */
4554 char aes_ctr[128 / 8];
4555 } material;
4556};
4557
4558
4559/**
4560 * Given the key material in @a km and the initialization vector
4561 * @a iv, setup the key material for the backchannel in @a key.
4562 *
4563 * @param km raw master secret
4564 * @param iv initialization vector
4565 * @param key[out] symmetric cipher and HMAC state to generate
4566 */
4567static void
4568dv_setup_key_state_from_km (const struct GNUNET_HashCode *km,
4569 const struct GNUNET_ShortHashCode *iv,
4570 struct DVKeyState *key)
4571{
4572 /* must match #dh_key_derive_eph_pub */
4573 GNUNET_assert (GNUNET_YES ==
4574 GNUNET_CRYPTO_kdf (&key->material,
4575 sizeof(key->material),
4576 "transport-backchannel-key",
4577 strlen ("transport-backchannel-key"),
4578 km,
4579 sizeof(*km),
4580 iv,
4581 sizeof(*iv),
4582 NULL));
4583 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4584 "Deriving backchannel key based on KM %s and IV %s\n",
4585 GNUNET_h2s (km),
4586 GNUNET_sh2s (iv));
4587 GNUNET_assert (0 == gcry_cipher_open (&key->cipher,
4588 GCRY_CIPHER_AES256 /* low level: go for speed */,
4589 GCRY_CIPHER_MODE_CTR,
4590 0 /* flags */));
4591 GNUNET_assert (0 == gcry_cipher_setkey (key->cipher,
4592 &key->material.aes_key,
4593 sizeof(key->material.aes_key)));
4594 gcry_cipher_setctr (key->cipher,
4595 &key->material.aes_ctr,
4596 sizeof(key->material.aes_ctr));
4597}
4598
4599
4600/**
4601 * Derive backchannel encryption key material from @a priv_ephemeral
4602 * and @a target and @a iv.
4603 *
4604 * @param priv_ephemeral ephemeral private key to use
4605 * @param target the target peer to encrypt to
4606 * @param iv unique IV to use
4607 * @param key[out] set to the key material
4608 */
4609static void
4610dh_key_derive_eph_pid (
4611 const struct GNUNET_CRYPTO_EcdhePrivateKey *priv_ephemeral,
4612 const struct GNUNET_PeerIdentity *target,
4613 const struct GNUNET_ShortHashCode *iv,
4614 struct DVKeyState *key)
4615{
4616 struct GNUNET_HashCode km;
4617
4618 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_ecdh_eddsa (priv_ephemeral,
4619 &target->public_key,
4620 &km));
4621 dv_setup_key_state_from_km (&km, iv, key);
4622}
4623
4624
4625/**
4626 * Derive backchannel encryption key material from #GST_my_private_key
4627 * and @a pub_ephemeral and @a iv.
4628 *
4629 * @param priv_ephemeral ephemeral private key to use
4630 * @param target the target peer to encrypt to
4631 * @param iv unique IV to use
4632 * @param key[out] set to the key material
4633 */
4634static void
4635dh_key_derive_eph_pub (const struct GNUNET_CRYPTO_EcdhePublicKey *pub_ephemeral,
4636 const struct GNUNET_ShortHashCode *iv,
4637 struct DVKeyState *key)
4638{
4639 struct GNUNET_HashCode km;
4640
4641 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_eddsa_ecdh (GST_my_private_key,
4642 pub_ephemeral,
4643 &km));
4644 dv_setup_key_state_from_km (&km, iv, key);
4645}
4646
4647
4648/**
4649 * Do HMAC calculation for backchannel messages over @a data using key
4650 * material from @a key.
4651 *
4652 * @param key key material (from DH)
4653 * @param hmac[out] set to the HMAC
4654 * @param data data to perform HMAC calculation over
4655 * @param data_size number of bytes in @a data
4656 */
4657static void
4658dv_hmac (const struct DVKeyState *key,
4659 struct GNUNET_HashCode *hmac,
4660 const void *data,
4661 size_t data_size)
4662{
4663 GNUNET_CRYPTO_hmac (&key->material.hmac_key, data, data_size, hmac);
4664}
4665
4666
4667/**
4668 * Perform backchannel encryption using symmetric secret in @a key
4669 * to encrypt data from @a in to @a dst.
4670 *
4671 * @param key[in,out] key material to use
4672 * @param dst where to write the result
4673 * @param in input data to encrypt (plaintext)
4674 * @param in_size number of bytes of input in @a in and available at @a dst
4675 */
4676static void
4677dv_encrypt (struct DVKeyState *key, const void *in, void *dst, size_t in_size)
4678{
4679 GNUNET_assert (0 ==
4680 gcry_cipher_encrypt (key->cipher, dst, in_size, in, in_size));
4681}
4682
4683
4684/**
4685 * Perform backchannel encryption using symmetric secret in @a key
4686 * to encrypt data from @a in to @a dst.
4687 *
4688 * @param key[in,out] key material to use
4689 * @param ciph cipher text to decrypt
4690 * @param out[out] output data to generate (plaintext)
4691 * @param out_size number of bytes of input in @a ciph and available in @a out
4692 */
4693static void
4694dv_decrypt (struct DVKeyState *key,
4695 void *out,
4696 const void *ciph,
4697 size_t out_size)
4698{
4699 GNUNET_assert (
4700 0 == gcry_cipher_decrypt (key->cipher, out, out_size, ciph, out_size));
4701}
4702
4703
4704/**
4705 * Clean up key material in @a key.
4706 *
4707 * @param key key material to clean up (memory must not be free'd!)
4708 */
4709static void
4710dv_key_clean (struct DVKeyState *key)
4711{
4712 gcry_cipher_close (key->cipher);
4713 GNUNET_CRYPTO_zero_keys (&key->material, sizeof(key->material));
4714}
4715
4716
4717/**
4718 * Function to call to further operate on the now DV encapsulated
4719 * message @a hdr, forwarding it via @a next_hop under respect of
4720 * @a options.
4721 *
4722 * @param cls closure
4723 * @param next_hop next hop of the DV path
4724 * @param hdr encapsulated message, technically a `struct TransportDFBoxMessage`
4725 * @param options options of the original message
4726 */
4727typedef void (*DVMessageHandler) (void *cls,
4728 struct Neighbour *next_hop,
4729 const struct GNUNET_MessageHeader *hdr,
4730 enum RouteMessageOptions options);
4731
4732/**
4733 * Pick a path of @a dv under constraints @a options and schedule
4734 * transmission of @a hdr.
4735 *
4736 * @param target neighbour to ultimately send to
4737 * @param num_dvhs length of the @a dvhs array
4738 * @param dvhs array of hops to send the message to
4739 * @param hdr message to send as payload
4740 * @param use function to call with the encapsulated message
4741 * @param use_cls closure for @a use
4742 * @param options whether path must be confirmed or not, to be passed to @a use
4743 * @param shall this TransportDVBoxMessage be forwarded without flow control.
4744 * @return expected RTT for transmission, #GNUNET_TIME_UNIT_FOREVER_REL if sending failed
4745 */
4746static struct GNUNET_TIME_Relative
4747encapsulate_for_dv (struct DistanceVector *dv,
4748 unsigned int num_dvhs,
4749 struct DistanceVectorHop **dvhs,
4750 const struct GNUNET_MessageHeader *hdr,
4751 DVMessageHandler use,
4752 void *use_cls,
4753 enum RouteMessageOptions options,
4754 enum GNUNET_GenericReturnValue without_fc)
4755{
4756 struct TransportDVBoxMessage box_hdr;
4757 struct TransportDVBoxPayloadP payload_hdr;
4758 uint16_t enc_body_size = ntohs (hdr->size);
4759 char enc[sizeof(struct TransportDVBoxPayloadP) + enc_body_size] GNUNET_ALIGN;
4760 struct TransportDVBoxPayloadP *enc_payload_hdr =
4761 (struct TransportDVBoxPayloadP *) enc;
4762 struct DVKeyState *key;
4763 struct GNUNET_TIME_Relative rtt;
4764
4765 key = GNUNET_new (struct DVKeyState);
4766 /* Encrypt payload */
4767 box_hdr.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX);
4768 box_hdr.total_hops = htons (0);
4769 box_hdr.without_fc = htons (without_fc);
4770 update_ephemeral (dv);
4771 box_hdr.ephemeral_key = dv->ephemeral_key;
4772 payload_hdr.sender_sig = dv->sender_sig;
4773
4774 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
4775 &box_hdr.iv,
4776 sizeof(box_hdr.iv));
4777 dh_key_derive_eph_pid (&dv->private_key, &dv->target, &box_hdr.iv, key);
4778 payload_hdr.sender = GST_my_identity;
4779 payload_hdr.monotonic_time = GNUNET_TIME_absolute_hton (dv->monotime);
4780 dv_encrypt (key, &payload_hdr, enc_payload_hdr, sizeof(payload_hdr));
4781 dv_encrypt (key,
4782 hdr,
4783 &enc[sizeof(struct TransportDVBoxPayloadP)],
4784 enc_body_size);
4785 dv_hmac (key, &box_hdr.hmac, enc, sizeof(enc));
4786 dv_key_clean (key);
4787 rtt = GNUNET_TIME_UNIT_FOREVER_REL;
4788 /* For each selected path, take the pre-computed header and body
4789 and add the path in the middle of the message; then send it. */
4790 for (unsigned int i = 0; i < num_dvhs; i++)
4791 {
4792 struct DistanceVectorHop *dvh = dvhs[i];
4793 unsigned int num_hops = dvh->distance + 1;
4794 char buf[sizeof(struct TransportDVBoxMessage)
4795 + sizeof(struct GNUNET_PeerIdentity) * num_hops
4796 + sizeof(struct TransportDVBoxPayloadP)
4797 + enc_body_size] GNUNET_ALIGN;
4798 struct GNUNET_PeerIdentity *dhops;
4799
4800 box_hdr.header.size = htons (sizeof(buf));
4801 box_hdr.orig_size = htons (sizeof(buf));
4802 box_hdr.num_hops = htons (num_hops);
4803 memcpy (buf, &box_hdr, sizeof(box_hdr));
4804 dhops = (struct GNUNET_PeerIdentity *) &buf[sizeof(box_hdr)];
4805 memcpy (dhops,
4806 dvh->path,
4807 dvh->distance * sizeof(struct GNUNET_PeerIdentity));
4808 dhops[dvh->distance] = dv->target;
4809 if (GNUNET_EXTRA_LOGGING > 0)
4810 {
4811 char *path;
4812
4813 path = GNUNET_strdup (GNUNET_i2s (&GST_my_identity));
4814 for (unsigned int j = 0; j < num_hops; j++)
4815 {
4816 char *tmp;
4817
4818 GNUNET_asprintf (&tmp, "%s-%s", path, GNUNET_i2s (&dhops[j]));
4819 GNUNET_free (path);
4820 path = tmp;
4821 }
4822 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4823 "Routing message of type %u to %s using DV (#%u/%u) via %s\n",
4824 ntohs (hdr->type),
4825 GNUNET_i2s (&dv->target),
4826 i + 1,
4827 num_dvhs,
4828 path);
4829 GNUNET_free (path);
4830 }
4831 rtt = GNUNET_TIME_relative_min (rtt, dvh->pd.aged_rtt);
4832 memcpy (&dhops[num_hops], enc, sizeof(enc));
4833 use (use_cls,
4834 dvh->next_hop,
4835 (const struct GNUNET_MessageHeader *) buf,
4836 options);
4837 GNUNET_free (key);
4838 }
4839 return rtt;
4840}
4841
4842
4843/**
4844 * Wrapper around #route_via_neighbour() that matches the
4845 * #DVMessageHandler structure.
4846 *
4847 * @param cls unused
4848 * @param next_hop where to send next
4849 * @param hdr header of the message to send
4850 * @param options message options for queue selection
4851 */
4852static void
4853send_dv_to_neighbour (void *cls,
4854 struct Neighbour *next_hop,
4855 const struct GNUNET_MessageHeader *hdr,
4856 enum RouteMessageOptions options)
4857{
4858 (void) cls;
4859 (void) route_via_neighbour (next_hop, hdr, RMO_UNCONFIRMED_ALLOWED);
4860}
4861
4862
4863/**
4864 * We need to transmit @a hdr to @a target. If necessary, this may
4865 * involve DV routing. This function routes without applying flow
4866 * control or congestion control and should only be used for control
4867 * traffic.
4868 *
4869 * @param target peer to receive @a hdr
4870 * @param hdr header of the message to route and #GNUNET_free()
4871 * @param options which transmission channels are allowed
4872 * @return expected RTT for transmission, #GNUNET_TIME_UNIT_FOREVER_REL if sending failed
4873 */
4874static struct GNUNET_TIME_Relative
4875route_control_message_without_fc (struct VirtualLink *vl,
4876// route_control_message_without_fc (const struct GNUNET_PeerIdentity *target,
4877 const struct GNUNET_MessageHeader *hdr,
4878 enum RouteMessageOptions options)
4879{
4880 // struct VirtualLink *vl;
4881 struct Neighbour *n;
4882 struct DistanceVector *dv;
4883 struct GNUNET_TIME_Relative rtt1;
4884 struct GNUNET_TIME_Relative rtt2;
4885 const struct GNUNET_PeerIdentity *target = &vl->target;
4886
4887 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4888 "Trying to route message of type %u to %s without fc\n",
4889 ntohs (hdr->type),
4890 GNUNET_i2s (target));
4891
4892 // TODO Do this elsewhere. vl should be given as parameter to method.
4893 // vl = lookup_virtual_link (target);
4894 GNUNET_assert (NULL != vl && GNUNET_YES == vl->confirmed);
4895 if (NULL == vl)
4896 return GNUNET_TIME_UNIT_FOREVER_REL;
4897 n = vl->n;
4898 dv = (0 != (options & RMO_DV_ALLOWED)) ? vl->dv : NULL;
4899 if (0 == (options & RMO_UNCONFIRMED_ALLOWED))
4900 {
4901 /* if confirmed is required, and we do not have anything
4902 confirmed, drop respective options */
4903 if (NULL == n)
4904 n = lookup_neighbour (target);
4905 if ((NULL == dv) && (0 != (options & RMO_DV_ALLOWED)))
4906 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, target);
4907 }
4908 if ((NULL == n) && (NULL == dv))
4909 {
4910 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4911 "Cannot route message of type %u to %s: no route\n",
4912 ntohs (hdr->type),
4913 GNUNET_i2s (target));
4914 GNUNET_STATISTICS_update (GST_stats,
4915 "# Messages dropped in routing: no acceptable method",
4916 1,
4917 GNUNET_NO);
4918 return GNUNET_TIME_UNIT_FOREVER_REL;
4919 }
4920 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4921 "Routing message of type %u to %s with options %X\n",
4922 ntohs (hdr->type),
4923 GNUNET_i2s (target),
4924 (unsigned int) options);
4925 /* If both dv and n are possible and we must choose:
4926 flip a coin for the choice between the two; for now 50/50 */
4927 if ((NULL != n) && (NULL != dv) && (0 == (options & RMO_REDUNDANT)))
4928 {
4929 if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 2))
4930 n = NULL;
4931 else
4932 dv = NULL;
4933 }
4934 if ((NULL != n) && (NULL != dv))
4935 options &= ~RMO_REDUNDANT; /* We will do one DV and one direct, that's
4936 enough for redundancy, so clear the flag. */
4937 rtt1 = GNUNET_TIME_UNIT_FOREVER_REL;
4938 rtt2 = GNUNET_TIME_UNIT_FOREVER_REL;
4939 if (NULL != n)
4940 {
4941 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4942 "Try to route message of type %u to %s without fc via neighbour\n",
4943 ntohs (hdr->type),
4944 GNUNET_i2s (target));
4945 rtt1 = route_via_neighbour (n, hdr, options);
4946 }
4947 if (NULL != dv)
4948 {
4949 struct DistanceVectorHop *hops[2];
4950 unsigned int res;
4951
4952 res = pick_random_dv_hops (dv,
4953 options,
4954 hops,
4955 (0 == (options & RMO_REDUNDANT)) ? 1 : 2);
4956 if (0 == res)
4957 {
4958 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4959 "Failed to route message, could not determine DV path\n");
4960 return rtt1;
4961 }
4962 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4963 "encapsulate_for_dv 1\n");
4964 rtt2 = encapsulate_for_dv (dv,
4965 res,
4966 hops,
4967 hdr,
4968 &send_dv_to_neighbour,
4969 NULL,
4970 options & (~RMO_REDUNDANT),
4971 GNUNET_YES);
4972 }
4973 return GNUNET_TIME_relative_min (rtt1, rtt2);
4974}
4975
4976
4977static void
4978consider_sending_fc (void *cls);
4979
4980/**
4981 * Something changed on the virtual link with respect to flow
4982 * control. Consider retransmitting the FC window size.
4983 *
4984 * @param cls a `struct VirtualLink` to work with
4985 */
4986static void
4987task_consider_sending_fc (void *cls)
4988{
4989 struct VirtualLink *vl = cls;
4990 vl->fc_retransmit_task = NULL;
4991 consider_sending_fc (cls);
4992}
4993
4994
4995/**
4996 * Something changed on the virtual link with respect to flow
4997 * control. Consider retransmitting the FC window size.
4998 *
4999 * @param cls a `struct VirtualLink` to work with
5000 */
5001static void
5002consider_sending_fc (void *cls)
5003{
5004 struct VirtualLink *vl = cls;
5005 struct GNUNET_TIME_Absolute monotime;
5006 struct TransportFlowControlMessage fc;
5007 struct GNUNET_TIME_Relative duration;
5008 struct GNUNET_TIME_Relative rtt;
5009
5010 duration = GNUNET_TIME_absolute_get_duration (vl->last_fc_transmission);
5011 /* OPTIMIZE-FC-BDP: decide sane criteria on when to do this, instead of doing
5012 it always! */
5013 /* For example, we should probably ONLY do this if a bit more than
5014 an RTT has passed, or if the window changed "significantly" since
5015 then. See vl->last_fc_rtt! NOTE: to do this properly, we also
5016 need an estimate for the bandwidth-delay-product for the entire
5017 VL, as that determines "significantly". We have the delay, but
5018 the bandwidth statistics need to be added for the VL!*/(void) duration;
5019
5020 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5021 "Sending FC seq %u to %s with new window %llu\n",
5022 (unsigned int) vl->fc_seq_gen,
5023 GNUNET_i2s (&vl->target),
5024 (unsigned long long) vl->incoming_fc_window_size);
5025 monotime = GNUNET_TIME_absolute_get_monotonic (GST_cfg);
5026 vl->last_fc_transmission = monotime;
5027 fc.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL);
5028 fc.header.size = htons (sizeof(fc));
5029 fc.seq = htonl (vl->fc_seq_gen++);
5030 fc.inbound_window_size = GNUNET_htonll (vl->incoming_fc_window_size);
5031 fc.outbound_sent = GNUNET_htonll (vl->outbound_fc_window_size_used);
5032 fc.outbound_window_size = GNUNET_htonll (vl->outbound_fc_window_size);
5033 fc.sender_time = GNUNET_TIME_absolute_hton (monotime);
5034 rtt = route_control_message_without_fc (vl, &fc.header, RMO_DV_ALLOWED);
5035 if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us == rtt.rel_value_us)
5036 {
5037 rtt = GNUNET_TIME_UNIT_SECONDS;
5038 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5039 "FC retransmission to %s failed, will retry in %s\n",
5040 GNUNET_i2s (&vl->target),
5041 GNUNET_STRINGS_relative_time_to_string (rtt, GNUNET_YES));
5042 vl->last_fc_rtt = GNUNET_TIME_UNIT_ZERO;
5043 }
5044 else
5045 {
5046 /* OPTIMIZE-FC-BDP: rtt is not ideal, we can do better! */
5047 vl->last_fc_rtt = rtt;
5048 }
5049 if (NULL != vl->fc_retransmit_task)
5050 GNUNET_SCHEDULER_cancel (vl->fc_retransmit_task);
5051 if (MAX_FC_RETRANSMIT_COUNT == vl->fc_retransmit_count)
5052 {
5053 rtt = GNUNET_TIME_UNIT_MINUTES;
5054 vl->fc_retransmit_count = 0;
5055 }
5056 vl->fc_retransmit_task =
5057 GNUNET_SCHEDULER_add_delayed (rtt, &task_consider_sending_fc, vl);
5058 vl->fc_retransmit_count++;
5059}
5060
5061
5062/**
5063 * There is a message at the head of the pending messages for @a vl
5064 * which may be ready for transmission. Check if a queue is ready to
5065 * take it.
5066 *
5067 * This function must (1) check for flow control to ensure that we can
5068 * right now send to @a vl, (2) check that the pending message in the
5069 * queue is actually eligible, (3) determine if any applicable queue
5070 * (direct neighbour or DVH path) is ready to accept messages, and
5071 * (4) prioritize based on the preferences associated with the
5072 * pending message.
5073 *
5074 * So yeah, easy.
5075 *
5076 * @param vl virtual link where we should check for transmission
5077 */
5078static void
5079check_vl_transmission (struct VirtualLink *vl)
5080{
5081 struct Neighbour *n = vl->n;
5082 struct DistanceVector *dv = vl->dv;
5083 struct GNUNET_TIME_Absolute now;
5084 struct VirtualLink *vl_next_hop;
5085 int elig;
5086
5087 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5088 "check_vl_transmission to target %s\n",
5089 GNUNET_i2s (&vl->target));
5090 /* Check that we have an eligible pending message!
5091 (cheaper than having #transmit_on_queue() find out!) */
5092 elig = GNUNET_NO;
5093 for (struct PendingMessage *pm = vl->pending_msg_head; NULL != pm;
5094 pm = pm->next_vl)
5095 {
5096 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5097 "check_vl_transmission loop\n");
5098 if (NULL != pm->qe)
5099 continue; /* not eligible, is in a queue! */
5100 if (pm->bytes_msg + vl->outbound_fc_window_size_used >
5101 vl->outbound_fc_window_size)
5102 {
5103 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5104 "Stalled message %lu transmission on VL %s due to flow control: %llu < %llu\n",
5105 pm->logging_uuid,
5106 GNUNET_i2s (&vl->target),
5107 (unsigned long long) vl->outbound_fc_window_size,
5108 (unsigned long long) (pm->bytes_msg
5109 + vl->outbound_fc_window_size_used));
5110 consider_sending_fc (vl);
5111 return; /* We have a message, but flow control says "nope" */
5112 }
5113 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5114 "Target window on VL %s not stalled. Scheduling transmission on queue\n",
5115 GNUNET_i2s (&vl->target));
5116 /* Notify queues at direct neighbours that we are interested */
5117 now = GNUNET_TIME_absolute_get ();
5118 if (NULL != n)
5119 {
5120 for (struct Queue *queue = n->queue_head; NULL != queue;
5121 queue = queue->next_neighbour)
5122 {
5123 if ((GNUNET_YES == queue->idle) &&
5124 (queue->validated_until.abs_value_us > now.abs_value_us))
5125 {
5126 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5127 "Direct neighbour %s not stalled\n",
5128 GNUNET_i2s (&n->pid));
5129 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
5130 queue,
5131 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
5132 elig = GNUNET_YES;
5133 }
5134 else
5135 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5136 "Neighbour Queue QID: %u (%u) busy or invalid\n",
5137 queue->qid,
5138 queue->idle);
5139 }
5140 }
5141 /* Notify queues via DV that we are interested */
5142 if (NULL != dv)
5143 {
5144 /* Do DV with lower scheduler priority, which effectively means that
5145 IF a neighbour exists and is available, we prefer it. */
5146 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
5147 pos = pos->next_dv)
5148 {
5149 struct Neighbour *nh = pos->next_hop;
5150
5151
5152 if (pos->path_valid_until.abs_value_us <= now.abs_value_us)
5153 continue; /* skip this one: path not validated */
5154 else
5155 {
5156 vl_next_hop = lookup_virtual_link (&nh->pid);
5157 if (pm->bytes_msg + vl_next_hop->outbound_fc_window_size_used >
5158 vl_next_hop->outbound_fc_window_size)
5159 {
5160 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5161 "Stalled message %lu transmission on next hop %s due to flow control: %llu < %llu\n",
5162 pm->logging_uuid,
5163 GNUNET_i2s (&vl_next_hop->target),
5164 (unsigned long
5165 long) vl_next_hop->outbound_fc_window_size,
5166 (unsigned long long) (pm->bytes_msg
5167 + vl_next_hop->
5168 outbound_fc_window_size_used));
5169 consider_sending_fc (vl_next_hop);
5170 continue; /* We have a message, but flow control says "nope" for the first hop of this path */
5171 }
5172 for (struct Queue *queue = nh->queue_head; NULL != queue;
5173 queue = queue->next_neighbour)
5174 if ((GNUNET_YES == queue->idle) &&
5175 (queue->validated_until.abs_value_us > now.abs_value_us))
5176 {
5177 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5178 "Next hop neighbour %s not stalled\n",
5179 GNUNET_i2s (&nh->pid));
5180 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
5181 queue,
5182 GNUNET_SCHEDULER_PRIORITY_BACKGROUND);
5183 elig = GNUNET_YES;
5184 }
5185 else
5186 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5187 "DV Queue QID: %u (%u) busy or invalid\n",
5188 queue->qid,
5189 queue->idle);
5190 }
5191 }
5192 }
5193 if (GNUNET_YES == elig)
5194 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5195 "Eligible message %lu of size %llu to %s: %llu/%llu\n",
5196 pm->logging_uuid,
5197 pm->bytes_msg,
5198 GNUNET_i2s (&vl->target),
5199 (unsigned long long) vl->outbound_fc_window_size,
5200 (unsigned long long) (pm->bytes_msg
5201 + vl->outbound_fc_window_size_used));
5202 break;
5203 }
5204}
5205
5206
5207/**
5208 * Client asked for transmission to a peer. Process the request.
5209 *
5210 * @param cls the client
5211 * @param obm the send message that was sent
5212 */
5213static void
5214handle_client_send (void *cls, const struct OutboundMessage *obm)
5215{
5216 struct TransportClient *tc = cls;
5217 struct PendingMessage *pm;
5218 const struct GNUNET_MessageHeader *obmm;
5219 uint32_t bytes_msg;
5220 struct VirtualLink *vl;
5221 enum GNUNET_MQ_PriorityPreferences pp;
5222
5223 GNUNET_assert (CT_CORE == tc->type);
5224 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
5225 bytes_msg = ntohs (obmm->size);
5226 pp = (enum GNUNET_MQ_PriorityPreferences) ntohl (obm->priority);
5227 vl = lookup_virtual_link (&obm->peer);
5228 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
5229 {
5230 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5231 "Don't have %s as a neighbour (anymore).\n",
5232 GNUNET_i2s (&obm->peer));
5233 /* Failure: don't have this peer as a neighbour (anymore).
5234 Might have gone down asynchronously, so this is NOT
5235 a protocol violation by CORE. Still count the event,
5236 as this should be rare. */
5237 GNUNET_SERVICE_client_continue (tc->client);
5238 GNUNET_STATISTICS_update (GST_stats,
5239 "# messages dropped (neighbour unknown)",
5240 1,
5241 GNUNET_NO);
5242 return;
5243 }
5244
5245 pm = GNUNET_malloc (sizeof(struct PendingMessage) + bytes_msg);
5246 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5247 "1 created pm %p storing vl %p\n",
5248 pm,
5249 vl);
5250 pm->logging_uuid = logging_uuid_gen++;
5251 pm->prefs = pp;
5252 pm->client = tc;
5253 pm->vl = vl;
5254 pm->bytes_msg = bytes_msg;
5255 memcpy (&pm[1], obmm, bytes_msg);
5256 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5257 "Sending %u bytes as <%llu> to %s\n",
5258 bytes_msg,
5259 pm->logging_uuid,
5260 GNUNET_i2s (&obm->peer));
5261 GNUNET_CONTAINER_MDLL_insert (client,
5262 tc->details.core.pending_msg_head,
5263 tc->details.core.pending_msg_tail,
5264 pm);
5265 GNUNET_CONTAINER_MDLL_insert (vl,
5266 vl->pending_msg_head,
5267 vl->pending_msg_tail,
5268 pm);
5269 check_vl_transmission (vl);
5270 GNUNET_SERVICE_client_continue (tc->client);
5271}
5272
5273
5274/**
5275 * Communicator requests backchannel transmission. Process the request.
5276 * Just repacks it into our `struct TransportBackchannelEncapsulationMessage *`
5277 * (which for now has exactly the same format, only a different message type)
5278 * and passes it on for routing.
5279 *
5280 * @param cls the client
5281 * @param cb the send message that was sent
5282 */
5283static void
5284handle_communicator_backchannel (
5285 void *cls,
5286 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
5287{
5288 struct Neighbour *n;
5289 struct VirtualLink *vl;
5290 struct TransportClient *tc = cls;
5291 const struct GNUNET_MessageHeader *inbox =
5292 (const struct GNUNET_MessageHeader *) &cb[1];
5293 uint16_t isize = ntohs (inbox->size);
5294 const char *is = ((const char *) &cb[1]) + isize;
5295 size_t slen = strlen (is) + 1;
5296 char
5297 mbuf[slen + isize
5298 + sizeof(struct
5299 TransportBackchannelEncapsulationMessage)] GNUNET_ALIGN;
5300 struct TransportBackchannelEncapsulationMessage *be =
5301 (struct TransportBackchannelEncapsulationMessage *) mbuf;
5302
5303 /* 0-termination of 'is' was checked already in
5304 #check_communicator_backchannel() */
5305 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5306 "Preparing backchannel transmission to %s:%s of type %u and size %u\n",
5307 GNUNET_i2s (&cb->pid),
5308 is,
5309 ntohs (inbox->type),
5310 ntohs (inbox->size));
5311 /* encapsulate and encrypt message */
5312 be->header.type =
5313 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION);
5314 be->header.size = htons (sizeof(mbuf));
5315 memcpy (&be[1], inbox, isize);
5316 memcpy (&mbuf[sizeof(struct TransportBackchannelEncapsulationMessage)
5317 + isize],
5318 is,
5319 strlen (is) + 1);
5320 // route_control_message_without_fc (&cb->pid, &be->header, RMO_DV_ALLOWED);
5321 vl = lookup_virtual_link (&cb->pid);
5322 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
5323 {
5324 route_control_message_without_fc (vl, &be->header, RMO_DV_ALLOWED);
5325 }
5326 else
5327 {
5328 /* Use route via neighbour */
5329 n = lookup_neighbour (&cb->pid);
5330 if (NULL != n)
5331 route_via_neighbour (
5332 n,
5333 &be->header,
5334 RMO_NONE);
5335 }
5336 GNUNET_SERVICE_client_continue (tc->client);
5337}
5338
5339
5340/**
5341 * Address of our peer added. Test message is well-formed.
5342 *
5343 * @param cls the client
5344 * @param aam the send message that was sent
5345 * @return #GNUNET_OK if message is well-formed
5346 */
5347static int
5348check_add_address (void *cls,
5349 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
5350{
5351 struct TransportClient *tc = cls;
5352
5353 if (CT_COMMUNICATOR != tc->type)
5354 {
5355 GNUNET_break (0);
5356 return GNUNET_SYSERR;
5357 }
5358 GNUNET_MQ_check_zero_termination (aam);
5359 return GNUNET_OK;
5360}
5361
5362
5363/**
5364 * Ask peerstore to store our address.
5365 *
5366 * @param cls an `struct AddressListEntry *`
5367 */
5368static void
5369store_pi (void *cls);
5370
5371
5372/**
5373 * Function called when peerstore is done storing our address.
5374 *
5375 * @param cls a `struct AddressListEntry`
5376 * @param success #GNUNET_YES if peerstore was successful
5377 */
5378static void
5379peerstore_store_own_cb (void *cls, int success)
5380{
5381 struct AddressListEntry *ale = cls;
5382
5383 ale->sc = NULL;
5384 if (GNUNET_YES != success)
5385 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5386 "Failed to store our own address `%s' in peerstore!\n",
5387 ale->address);
5388 else
5389 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5390 "Successfully stored our own address `%s' in peerstore!\n",
5391 ale->address);
5392 /* refresh period is 1/4 of expiration time, that should be plenty
5393 without being excessive. */
5394 ale->st =
5395 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide (ale->expiration,
5396 4ULL),
5397 &store_pi,
5398 ale);
5399}
5400
5401
5402/**
5403 * Ask peerstore to store our address.
5404 *
5405 * @param cls an `struct AddressListEntry *`
5406 */
5407static void
5408store_pi (void *cls)
5409{
5410 struct AddressListEntry *ale = cls;
5411 void *addr;
5412 size_t addr_len;
5413 struct GNUNET_TIME_Absolute expiration;
5414
5415 ale->st = NULL;
5416 expiration = GNUNET_TIME_relative_to_absolute (ale->expiration);
5417 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5418 "Storing our address `%s' in peerstore until %s!\n",
5419 ale->address,
5420 GNUNET_STRINGS_absolute_time_to_string (expiration));
5421 GNUNET_HELLO_sign_address (ale->address,
5422 ale->nt,
5423 hello_mono_time,
5424 GST_my_private_key,
5425 &addr,
5426 &addr_len);
5427 ale->sc = GNUNET_PEERSTORE_store (peerstore,
5428 "transport",
5429 &GST_my_identity,
5430 GNUNET_PEERSTORE_TRANSPORT_HELLO_KEY,
5431 addr,
5432 addr_len,
5433 expiration,
5434 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
5435 &peerstore_store_own_cb,
5436 ale);
5437 GNUNET_free (addr);
5438 if (NULL == ale->sc)
5439 {
5440 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5441 "Failed to store our address `%s' with peerstore\n",
5442 ale->address);
5443 ale->st =
5444 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &store_pi, ale);
5445 }
5446}
5447
5448
5449/**
5450 * Address of our peer added. Process the request.
5451 *
5452 * @param cls the client
5453 * @param aam the send message that was sent
5454 */
5455static void
5456handle_add_address (void *cls,
5457 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
5458{
5459 struct TransportClient *tc = cls;
5460 struct AddressListEntry *ale;
5461 size_t slen;
5462
5463 /* 0-termination of &aam[1] was checked in #check_add_address */
5464 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5465 "Communicator added address `%s'!\n",
5466 (const char *) &aam[1]);
5467 slen = ntohs (aam->header.size) - sizeof(*aam);
5468 ale = GNUNET_malloc (sizeof(struct AddressListEntry) + slen);
5469 ale->tc = tc;
5470 ale->address = (const char *) &ale[1];
5471 ale->expiration = GNUNET_TIME_relative_ntoh (aam->expiration);
5472 ale->aid = aam->aid;
5473 ale->nt = (enum GNUNET_NetworkType) ntohl (aam->nt);
5474 memcpy (&ale[1], &aam[1], slen);
5475 GNUNET_CONTAINER_DLL_insert (tc->details.communicator.addr_head,
5476 tc->details.communicator.addr_tail,
5477 ale);
5478 ale->st = GNUNET_SCHEDULER_add_now (&store_pi, ale);
5479 GNUNET_SERVICE_client_continue (tc->client);
5480}
5481
5482
5483/**
5484 * Address of our peer deleted. Process the request.
5485 *
5486 * @param cls the client
5487 * @param dam the send message that was sent
5488 */
5489static void
5490handle_del_address (void *cls,
5491 const struct GNUNET_TRANSPORT_DelAddressMessage *dam)
5492{
5493 struct TransportClient *tc = cls;
5494 struct AddressListEntry *alen;
5495
5496 if (CT_COMMUNICATOR != tc->type)
5497 {
5498 GNUNET_break (0);
5499 GNUNET_SERVICE_client_drop (tc->client);
5500 return;
5501 }
5502 for (struct AddressListEntry *ale = tc->details.communicator.addr_head;
5503 NULL != ale;
5504 ale = alen)
5505 {
5506 alen = ale->next;
5507 if (dam->aid != ale->aid)
5508 continue;
5509 GNUNET_assert (ale->tc == tc);
5510 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5511 "Communicator deleted address `%s'!\n",
5512 ale->address);
5513 free_address_list_entry (ale);
5514 GNUNET_SERVICE_client_continue (tc->client);
5515 return;
5516 }
5517 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5518 "Communicator removed address we did not even have.\n");
5519 GNUNET_SERVICE_client_continue (tc->client);
5520 // GNUNET_SERVICE_client_drop (tc->client);
5521}
5522
5523
5524/**
5525 * Given an inbound message @a msg from a communicator @a cmc,
5526 * demultiplex it based on the type calling the right handler.
5527 *
5528 * @param cmc context for demultiplexing
5529 * @param msg message to demultiplex
5530 */
5531static void
5532demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
5533 const struct GNUNET_MessageHeader *msg);
5534
5535
5536/**
5537 * Function called when we are done giving a message of a certain
5538 * size to CORE and should thus decrement the number of bytes of
5539 * RAM reserved for that peer's MQ.
5540 *
5541 * @param cls a `struct CoreSentContext`
5542 */
5543static void
5544core_env_sent_cb (void *cls)
5545{
5546 struct CoreSentContext *ctx = cls;
5547 struct VirtualLink *vl = ctx->vl;
5548
5549 if (NULL == vl)
5550 {
5551 /* lost the link in the meantime, ignore */
5552 GNUNET_free (ctx);
5553 return;
5554 }
5555 GNUNET_CONTAINER_DLL_remove (vl->csc_head, vl->csc_tail, ctx);
5556 GNUNET_assert (vl->incoming_fc_window_size_ram >= ctx->size);
5557 vl->incoming_fc_window_size_ram -= ctx->size;
5558 vl->incoming_fc_window_size_used += ctx->isize;
5559 consider_sending_fc (vl);
5560 GNUNET_free (ctx);
5561}
5562
5563
5564/**
5565 * Communicator gave us an unencapsulated message to pass as-is to
5566 * CORE. Process the request.
5567 *
5568 * @param cls a `struct CommunicatorMessageContext` (must call
5569 * #finish_cmc_handling() when done)
5570 * @param mh the message that was received
5571 */
5572static void
5573handle_raw_message (void *cls, const struct GNUNET_MessageHeader *mh)
5574{
5575 struct CommunicatorMessageContext *cmc = cls;
5576 struct VirtualLink *vl;
5577 uint16_t size = ntohs (mh->size);
5578 int have_core;
5579
5580 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5581 "Handling raw message of type %u with %u bytes\n",
5582 (unsigned int) ntohs (mh->type),
5583 (unsigned int) ntohs (mh->size));
5584
5585 if ((size > UINT16_MAX - sizeof(struct InboundMessage)) ||
5586 (size < sizeof(struct GNUNET_MessageHeader)))
5587 {
5588 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
5589
5590 GNUNET_break (0);
5591 finish_cmc_handling (cmc);
5592 GNUNET_SERVICE_client_drop (client);
5593 return;
5594 }
5595 vl = lookup_virtual_link (&cmc->im.sender);
5596 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
5597 {
5598 /* FIXME: sender is giving us messages for CORE but we don't have
5599 the link up yet! I *suspect* this can happen right now (i.e.
5600 sender has verified us, but we didn't verify sender), but if
5601 we pass this on, CORE would be confused (link down, messages
5602 arrive). We should investigate more if this happens often,
5603 or in a persistent manner, and possibly do "something" about
5604 it. Thus logging as error for now. */
5605 GNUNET_break_op (0);
5606 GNUNET_STATISTICS_update (GST_stats,
5607 "# CORE messages dropped (virtual link still down)",
5608 1,
5609 GNUNET_NO);
5610
5611 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5612 "CORE messages of type %u with %u bytes dropped (virtual link still down)\n",
5613 (unsigned int) ntohs (mh->type),
5614 (unsigned int) ntohs (mh->size));
5615 finish_cmc_handling (cmc);
5616 return;
5617 }
5618 if (vl->incoming_fc_window_size_ram > UINT_MAX - size)
5619 {
5620 GNUNET_STATISTICS_update (GST_stats,
5621 "# CORE messages dropped (FC arithmetic overflow)",
5622 1,
5623 GNUNET_NO);
5624 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5625 "CORE messages of type %u with %u bytes dropped (FC arithmetic overflow)\n",
5626 (unsigned int) ntohs (mh->type),
5627 (unsigned int) ntohs (mh->size));
5628 finish_cmc_handling (cmc);
5629 return;
5630 }
5631 if (vl->incoming_fc_window_size_ram + size > vl->available_fc_window_size)
5632 {
5633 GNUNET_STATISTICS_update (GST_stats,
5634 "# CORE messages dropped (FC window overflow)",
5635 1,
5636 GNUNET_NO);
5637 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5638 "CORE messages of type %u with %u bytes dropped (FC window overflow)\n",
5639 (unsigned int) ntohs (mh->type),
5640 (unsigned int) ntohs (mh->size));
5641 finish_cmc_handling (cmc);
5642 return;
5643 }
5644
5645 /* Forward to all CORE clients */
5646 have_core = GNUNET_NO;
5647 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
5648 {
5649 struct GNUNET_MQ_Envelope *env;
5650 struct InboundMessage *im;
5651 struct CoreSentContext *ctx;
5652
5653 if (CT_CORE != tc->type)
5654 continue;
5655 vl->incoming_fc_window_size_ram += size;
5656 env = GNUNET_MQ_msg_extra (im, size, GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
5657 ctx = GNUNET_new (struct CoreSentContext);
5658 ctx->vl = vl;
5659 ctx->size = size;
5660 ctx->isize = (GNUNET_NO == have_core) ? size : 0;
5661 have_core = GNUNET_YES;
5662 GNUNET_CONTAINER_DLL_insert (vl->csc_head, vl->csc_tail, ctx);
5663 GNUNET_MQ_notify_sent (env, &core_env_sent_cb, ctx);
5664 im->peer = cmc->im.sender;
5665 memcpy (&im[1], mh, size);
5666 GNUNET_MQ_send (tc->mq, env);
5667 vl->core_recv_window--;
5668 }
5669 if (GNUNET_NO == have_core)
5670 {
5671 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5672 "Dropped message to CORE: no CORE client connected!\n");
5673 /* Nevertheless, count window as used, as it is from the
5674 perspective of the other peer! */
5675 vl->incoming_fc_window_size_used += size;
5676 /* TODO-M1 */
5677 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5678 "Dropped message of type %u with %u bytes to CORE: no CORE client connected!\n",
5679 (unsigned int) ntohs (mh->type),
5680 (unsigned int) ntohs (mh->size));
5681 finish_cmc_handling (cmc);
5682 return;
5683 }
5684 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5685 "Delivered message from %s of type %u to CORE\n",
5686 GNUNET_i2s (&cmc->im.sender),
5687 ntohs (mh->type));
5688 if (vl->core_recv_window > 0)
5689 {
5690 finish_cmc_handling (cmc);
5691 return;
5692 }
5693 /* Wait with calling #finish_cmc_handling(cmc) until the message
5694 was processed by CORE MQs (for CORE flow control)! */
5695 GNUNET_CONTAINER_DLL_insert (vl->cmc_head, vl->cmc_tail, cmc);
5696}
5697
5698
5699/**
5700 * Communicator gave us a fragment box. Check the message.
5701 *
5702 * @param cls a `struct CommunicatorMessageContext`
5703 * @param fb the send message that was sent
5704 * @return #GNUNET_YES if message is well-formed
5705 */
5706static int
5707check_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
5708{
5709 uint16_t size = ntohs (fb->header.size);
5710 uint16_t bsize = size - sizeof(*fb);
5711
5712 (void) cls;
5713 if (0 == bsize)
5714 {
5715 GNUNET_break_op (0);
5716 return GNUNET_SYSERR;
5717 }
5718 if (bsize + ntohs (fb->frag_off) > ntohs (fb->msg_size))
5719 {
5720 GNUNET_break_op (0);
5721 return GNUNET_SYSERR;
5722 }
5723 if (ntohs (fb->frag_off) >= ntohs (fb->msg_size))
5724 {
5725 GNUNET_break_op (0);
5726 return GNUNET_SYSERR;
5727 }
5728 return GNUNET_YES;
5729}
5730
5731
5732/**
5733 * Clean up an idle cumulative acknowledgement data structure.
5734 *
5735 * @param cls a `struct AcknowledgementCummulator *`
5736 */
5737static void
5738destroy_ack_cummulator (void *cls)
5739{
5740 struct AcknowledgementCummulator *ac = cls;
5741
5742 ac->task = NULL;
5743 GNUNET_assert (0 == ac->num_acks);
5744 GNUNET_assert (
5745 GNUNET_YES ==
5746 GNUNET_CONTAINER_multipeermap_remove (ack_cummulators, &ac->target, ac));
5747 GNUNET_free (ac);
5748}
5749
5750
5751/**
5752 * Do the transmission of a cumulative acknowledgement now.
5753 *
5754 * @param cls a `struct AcknowledgementCummulator *`
5755 */
5756static void
5757transmit_cummulative_ack_cb (void *cls)
5758{
5759 struct Neighbour *n;
5760 struct VirtualLink *vl;
5761 struct AcknowledgementCummulator *ac = cls;
5762 char buf[sizeof(struct TransportReliabilityAckMessage)
5763 + ac->num_acks
5764 * sizeof(struct TransportCummulativeAckPayloadP)] GNUNET_ALIGN;
5765 struct TransportReliabilityAckMessage *ack =
5766 (struct TransportReliabilityAckMessage *) buf;
5767 struct TransportCummulativeAckPayloadP *ap;
5768
5769 ac->task = NULL;
5770 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5771 "Sending ACK with %u components to %s\n",
5772 ac->num_acks,
5773 GNUNET_i2s (&ac->target));
5774 GNUNET_assert (0 < ac->num_acks);
5775 ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK);
5776 ack->header.size =
5777 htons (sizeof(*ack)
5778 + ac->num_acks * sizeof(struct TransportCummulativeAckPayloadP));
5779 ack->ack_counter = htonl (ac->ack_counter += ac->num_acks);
5780 ap = (struct TransportCummulativeAckPayloadP *) &ack[1];
5781 for (unsigned int i = 0; i < ac->num_acks; i++)
5782 {
5783 ap[i].ack_uuid = ac->ack_uuids[i].ack_uuid;
5784 ap[i].ack_delay = GNUNET_TIME_relative_hton (
5785 GNUNET_TIME_absolute_get_duration (ac->ack_uuids[i].receive_time));
5786 }
5787 /*route_control_message_without_fc (
5788 &ac->target,
5789 &ack->header,
5790 RMO_DV_ALLOWED);*/
5791 vl = lookup_virtual_link (&ac->target);
5792 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
5793 {
5794 route_control_message_without_fc (
5795 vl,
5796 &ack->header,
5797 RMO_DV_ALLOWED);
5798 }
5799 else
5800 {
5801 /* Use route via neighbour */
5802 n = lookup_neighbour (&ac->target);
5803 if (NULL != n)
5804 route_via_neighbour (
5805 n,
5806 &ack->header,
5807 RMO_NONE);
5808 }
5809 ac->num_acks = 0;
5810 ac->task = GNUNET_SCHEDULER_add_delayed (ACK_CUMMULATOR_TIMEOUT,
5811 &destroy_ack_cummulator,
5812 ac);
5813}
5814
5815
5816/**
5817 * Transmit an acknowledgement for @a ack_uuid to @a pid delaying
5818 * transmission by at most @a ack_delay.
5819 *
5820 * @param pid target peer
5821 * @param ack_uuid UUID to ack
5822 * @param max_delay how long can the ACK wait
5823 */
5824static void
5825cummulative_ack (const struct GNUNET_PeerIdentity *pid,
5826 const struct AcknowledgementUUIDP *ack_uuid,
5827 struct GNUNET_TIME_Absolute max_delay)
5828{
5829 struct AcknowledgementCummulator *ac;
5830
5831 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5832 "Scheduling ACK %s for transmission to %s\n",
5833 GNUNET_uuid2s (&ack_uuid->value),
5834 GNUNET_i2s (pid));
5835 ac = GNUNET_CONTAINER_multipeermap_get (ack_cummulators, pid);
5836 if (NULL == ac)
5837 {
5838 ac = GNUNET_new (struct AcknowledgementCummulator);
5839 ac->target = *pid;
5840 ac->min_transmission_time = max_delay;
5841 GNUNET_assert (GNUNET_YES ==
5842 GNUNET_CONTAINER_multipeermap_put (
5843 ack_cummulators,
5844 &ac->target,
5845 ac,
5846 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
5847 }
5848 else
5849 {
5850 if (MAX_CUMMULATIVE_ACKS == ac->num_acks)
5851 {
5852 /* must run immediately, ack buffer full! */
5853 transmit_cummulative_ack_cb (ac);
5854 }
5855 GNUNET_SCHEDULER_cancel (ac->task);
5856 ac->min_transmission_time =
5857 GNUNET_TIME_absolute_min (ac->min_transmission_time, max_delay);
5858 }
5859 GNUNET_assert (ac->num_acks < MAX_CUMMULATIVE_ACKS);
5860 ac->ack_uuids[ac->num_acks].receive_time = GNUNET_TIME_absolute_get ();
5861 ac->ack_uuids[ac->num_acks].ack_uuid = *ack_uuid;
5862 ac->num_acks++;
5863 ac->task = GNUNET_SCHEDULER_add_at (ac->min_transmission_time,
5864 &transmit_cummulative_ack_cb,
5865 ac);
5866}
5867
5868
5869/**
5870 * Closure for #find_by_message_uuid.
5871 */
5872struct FindByMessageUuidContext
5873{
5874 /**
5875 * UUID to look for.
5876 */
5877 struct MessageUUIDP message_uuid;
5878
5879 /**
5880 * Set to the reassembly context if found.
5881 */
5882 struct ReassemblyContext *rc;
5883};
5884
5885
5886/**
5887 * Iterator called to find a reassembly context by the message UUID in the
5888 * multihashmap32.
5889 *
5890 * @param cls a `struct FindByMessageUuidContext`
5891 * @param key a key (unused)
5892 * @param value a `struct ReassemblyContext`
5893 * @return #GNUNET_YES if not found, #GNUNET_NO if found
5894 */
5895static int
5896find_by_message_uuid (void *cls, uint32_t key, void *value)
5897{
5898 struct FindByMessageUuidContext *fc = cls;
5899 struct ReassemblyContext *rc = value;
5900
5901 (void) key;
5902 if (0 == GNUNET_memcmp (&fc->message_uuid, &rc->msg_uuid))
5903 {
5904 fc->rc = rc;
5905 return GNUNET_NO;
5906 }
5907 return GNUNET_YES;
5908}
5909
5910
5911/**
5912 * Communicator gave us a fragment. Process the request.
5913 *
5914 * @param cls a `struct CommunicatorMessageContext` (must call
5915 * #finish_cmc_handling() when done)
5916 * @param fb the message that was received
5917 */
5918static void
5919handle_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
5920{
5921 struct CommunicatorMessageContext *cmc = cls;
5922 struct VirtualLink *vl;
5923 struct ReassemblyContext *rc;
5924 const struct GNUNET_MessageHeader *msg;
5925 uint16_t msize;
5926 uint16_t fsize;
5927 uint16_t frag_off;
5928 char *target;
5929 struct GNUNET_TIME_Relative cdelay;
5930 struct FindByMessageUuidContext fc;
5931
5932 vl = lookup_virtual_link (&cmc->im.sender);
5933 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
5934 {
5935 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
5936
5937 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5938 "No virtual link for %s to handle fragment\n",
5939 GNUNET_i2s (&cmc->im.sender));
5940 GNUNET_break (0);
5941 finish_cmc_handling (cmc);
5942 GNUNET_SERVICE_client_drop (client);
5943 return;
5944 }
5945 if (NULL == vl->reassembly_map)
5946 {
5947 vl->reassembly_map = GNUNET_CONTAINER_multihashmap32_create (8);
5948 vl->reassembly_heap =
5949 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
5950 vl->reassembly_timeout_task =
5951 GNUNET_SCHEDULER_add_delayed (REASSEMBLY_EXPIRATION,
5952 &reassembly_cleanup_task,
5953 vl);
5954 }
5955 msize = ntohs (fb->msg_size);
5956 fc.message_uuid = fb->msg_uuid;
5957 fc.rc = NULL;
5958 (void) GNUNET_CONTAINER_multihashmap32_get_multiple (vl->reassembly_map,
5959 fb->msg_uuid.uuid,
5960 &find_by_message_uuid,
5961 &fc);
5962 fsize = ntohs (fb->header.size) - sizeof(*fb);
5963 if (NULL == (rc = fc.rc))
5964 {
5965 rc = GNUNET_malloc (sizeof(*rc) + msize /* reassembly payload buffer */
5966 + (msize + 7) / 8 * sizeof(uint8_t) /* bitfield */);
5967 rc->msg_uuid = fb->msg_uuid;
5968 rc->virtual_link = vl;
5969 rc->msg_size = msize;
5970 rc->reassembly_timeout =
5971 GNUNET_TIME_relative_to_absolute (REASSEMBLY_EXPIRATION);
5972 rc->last_frag = GNUNET_TIME_absolute_get ();
5973 rc->hn = GNUNET_CONTAINER_heap_insert (vl->reassembly_heap,
5974 rc,
5975 rc->reassembly_timeout.abs_value_us);
5976 GNUNET_assert (GNUNET_OK ==
5977 GNUNET_CONTAINER_multihashmap32_put (
5978 vl->reassembly_map,
5979 rc->msg_uuid.uuid,
5980 rc,
5981 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
5982 target = (char *) &rc[1];
5983 rc->bitfield = (uint8_t *) (target + rc->msg_size);
5984 if (fsize != rc->msg_size)
5985 rc->msg_missing = rc->msg_size;
5986 else
5987 rc->msg_missing = 0;
5988 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5989 "Received fragment with size %u at offset %u/%u %u bytes missing from %s for NEW message %u\n",
5990 fsize,
5991 ntohs (fb->frag_off),
5992 msize,
5993 rc->msg_missing,
5994 GNUNET_i2s (&cmc->im.sender),
5995 (unsigned int) fb->msg_uuid.uuid);
5996 }
5997 else
5998 {
5999 target = (char *) &rc[1];
6000 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6001 "Received fragment at offset %u/%u from %s for message %u\n",
6002 ntohs (fb->frag_off),
6003 msize,
6004 GNUNET_i2s (&cmc->im.sender),
6005 (unsigned int) fb->msg_uuid.uuid);
6006 }
6007 if (msize != rc->msg_size)
6008 {
6009 GNUNET_break (0);
6010 finish_cmc_handling (cmc);
6011 return;
6012 }
6013
6014 /* reassemble */
6015 if (0 == fsize)
6016 {
6017 GNUNET_break (0);
6018 finish_cmc_handling (cmc);
6019 return;
6020 }
6021 frag_off = ntohs (fb->frag_off);
6022 if (frag_off + fsize > msize)
6023 {
6024 /* Fragment (plus fragment size) exceeds message size! */
6025 GNUNET_break_op (0);
6026 finish_cmc_handling (cmc);
6027 return;
6028 }
6029 memcpy (&target[frag_off], &fb[1], fsize);
6030 /* update bitfield and msg_missing */
6031 for (unsigned int i = frag_off; i < frag_off + fsize; i++)
6032 {
6033 if (0 == (rc->bitfield[i / 8] & (1 << (i % 8))))
6034 {
6035 rc->bitfield[i / 8] |= (1 << (i % 8));
6036 rc->msg_missing--;
6037 }
6038 }
6039
6040 /* Compute cumulative ACK */
6041 cdelay = GNUNET_TIME_absolute_get_duration (rc->last_frag);
6042 cdelay = GNUNET_TIME_relative_multiply (cdelay, rc->msg_missing / fsize);
6043 if (0 == rc->msg_missing)
6044 cdelay = GNUNET_TIME_UNIT_ZERO;
6045 cummulative_ack (&cmc->im.sender,
6046 &fb->ack_uuid,
6047 GNUNET_TIME_relative_to_absolute (cdelay));
6048 rc->last_frag = GNUNET_TIME_absolute_get ();
6049 /* is reassembly complete? */
6050 if (0 != rc->msg_missing)
6051 {
6052 finish_cmc_handling (cmc);
6053 return;
6054 }
6055 /* reassembly is complete, verify result */
6056 msg = (const struct GNUNET_MessageHeader *) &rc[1];
6057 if (ntohs (msg->size) != rc->msg_size)
6058 {
6059 GNUNET_break (0);
6060 free_reassembly_context (rc);
6061 finish_cmc_handling (cmc);
6062 return;
6063 }
6064 /* successful reassembly */
6065 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6066 "Fragment reassembly complete for message %u\n",
6067 (unsigned int) fb->msg_uuid.uuid);
6068 /* FIXME: check that the resulting msg is NOT a
6069 DV Box or Reliability Box, as that is NOT allowed! */
6070 demultiplex_with_cmc (cmc, msg);
6071 /* FIXME-OPTIMIZE: really free here? Might be bad if fragments are still
6072 en-route and we forget that we finished this reassembly immediately!
6073 -> keep around until timeout?
6074 -> shorten timeout based on ACK? */
6075 free_reassembly_context (rc);
6076}
6077
6078
6079/**
6080 * Communicator gave us a reliability box. Check the message.
6081 *
6082 * @param cls a `struct CommunicatorMessageContext`
6083 * @param rb the send message that was sent
6084 * @return #GNUNET_YES if message is well-formed
6085 */
6086static int
6087check_reliability_box (void *cls,
6088 const struct TransportReliabilityBoxMessage *rb)
6089{
6090 (void) cls;
6091 const struct GNUNET_MessageHeader *inbox = (const struct
6092 GNUNET_MessageHeader *) &rb[1];
6093
6094 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6095 "check_send_msg with size %u: inner msg type %u and size %u (%u %u)\n",
6096 ntohs (rb->header.size),
6097 ntohs (inbox->type),
6098 ntohs (inbox->size),
6099 sizeof (struct TransportReliabilityBoxMessage),
6100 sizeof (struct GNUNET_MessageHeader));
6101 GNUNET_MQ_check_boxed_message (rb);
6102 return GNUNET_YES;
6103}
6104
6105
6106/**
6107 * Communicator gave us a reliability box. Process the request.
6108 *
6109 * @param cls a `struct CommunicatorMessageContext` (must call
6110 * #finish_cmc_handling() when done)
6111 * @param rb the message that was received
6112 */
6113static void
6114handle_reliability_box (void *cls,
6115 const struct TransportReliabilityBoxMessage *rb)
6116{
6117 struct CommunicatorMessageContext *cmc = cls;
6118 const struct GNUNET_MessageHeader *inbox =
6119 (const struct GNUNET_MessageHeader *) &rb[1];
6120 struct GNUNET_TIME_Relative rtt;
6121
6122 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6123 "Received reliability box from %s with UUID %s of type %u\n",
6124 GNUNET_i2s (&cmc->im.sender),
6125 GNUNET_uuid2s (&rb->ack_uuid.value),
6126 (unsigned int) ntohs (inbox->type));
6127 rtt = GNUNET_TIME_UNIT_SECONDS; /* FIXME: should base this on "RTT", but we
6128 do not really have an RTT for the
6129 * incoming* queue (should we have
6130 the sender add it to the rb message?) */
6131 cummulative_ack (
6132 &cmc->im.sender,
6133 &rb->ack_uuid,
6134 (0 == ntohl (rb->ack_countdown))
6135 ? GNUNET_TIME_UNIT_ZERO_ABS
6136 : GNUNET_TIME_relative_to_absolute (
6137 GNUNET_TIME_relative_divide (rtt, 8 /* FIXME: magic constant */)));
6138 /* continue with inner message */
6139 /* FIXME: check that inbox is NOT a DV Box, fragment or another
6140 reliability box (not allowed!) */
6141 demultiplex_with_cmc (cmc, inbox);
6142}
6143
6144
6145/**
6146 * Check if we have advanced to another age since the last time. If
6147 * so, purge ancient statistics (more than GOODPUT_AGING_SLOTS before
6148 * the current age)
6149 *
6150 * @param pd[in,out] data to update
6151 * @param age current age
6152 */
6153static void
6154update_pd_age (struct PerformanceData *pd, unsigned int age)
6155{
6156 unsigned int sage;
6157
6158 if (age == pd->last_age)
6159 return; /* nothing to do */
6160 sage = GNUNET_MAX (pd->last_age, age - 2 * GOODPUT_AGING_SLOTS);
6161 for (unsigned int i = sage; i <= age - GOODPUT_AGING_SLOTS; i++)
6162 {
6163 struct TransmissionHistoryEntry *the = &pd->the[i % GOODPUT_AGING_SLOTS];
6164
6165 the->bytes_sent = 0;
6166 the->bytes_received = 0;
6167 }
6168 pd->last_age = age;
6169}
6170
6171
6172/**
6173 * Update @a pd based on the latest @a rtt and the number of bytes
6174 * that were confirmed to be successfully transmitted.
6175 *
6176 * @param pd[in,out] data to update
6177 * @param rtt latest round-trip time
6178 * @param bytes_transmitted_ok number of bytes receiver confirmed as received
6179 */
6180static void
6181update_performance_data (struct PerformanceData *pd,
6182 struct GNUNET_TIME_Relative rtt,
6183 uint16_t bytes_transmitted_ok)
6184{
6185 uint64_t nval = rtt.rel_value_us;
6186 uint64_t oval = pd->aged_rtt.rel_value_us;
6187 unsigned int age = get_age ();
6188 struct TransmissionHistoryEntry *the = &pd->the[age % GOODPUT_AGING_SLOTS];
6189
6190 if (oval == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
6191 pd->aged_rtt = rtt;
6192 else
6193 pd->aged_rtt.rel_value_us = (nval + 7 * oval) / 8;
6194 update_pd_age (pd, age);
6195 the->bytes_received += bytes_transmitted_ok;
6196}
6197
6198
6199/**
6200 * We have successfully transmitted data via @a q, update metrics.
6201 *
6202 * @param q queue to update
6203 * @param rtt round trip time observed
6204 * @param bytes_transmitted_ok number of bytes successfully transmitted
6205 */
6206static void
6207update_queue_performance (struct Queue *q,
6208 struct GNUNET_TIME_Relative rtt,
6209 uint16_t bytes_transmitted_ok)
6210{
6211 update_performance_data (&q->pd, rtt, bytes_transmitted_ok);
6212}
6213
6214
6215/**
6216 * We have successfully transmitted data via @a dvh, update metrics.
6217 *
6218 * @param dvh distance vector path data to update
6219 * @param rtt round trip time observed
6220 * @param bytes_transmitted_ok number of bytes successfully transmitted
6221 */
6222static void
6223update_dvh_performance (struct DistanceVectorHop *dvh,
6224 struct GNUNET_TIME_Relative rtt,
6225 uint16_t bytes_transmitted_ok)
6226{
6227 update_performance_data (&dvh->pd, rtt, bytes_transmitted_ok);
6228}
6229
6230
6231/**
6232 * We have completed transmission of @a pm, remove it from
6233 * the transmission queues (and if it is a fragment, continue
6234 * up the tree as necessary).
6235 *
6236 * @param pm pending message that was transmitted
6237 */
6238static void
6239completed_pending_message (struct PendingMessage *pm)
6240{
6241 struct PendingMessage *pos;
6242
6243 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6244 "Complete transmission of message %llu %u\n",
6245 pm->logging_uuid,
6246 pm->pmt);
6247 switch (pm->pmt)
6248 {
6249 case PMT_CORE:
6250 case PMT_RELIABILITY_BOX:
6251 /* Full message sent, we are done */
6252 client_send_response (pm);
6253 return;
6254
6255 case PMT_FRAGMENT_BOX:
6256 /* Fragment sent over reliable channel */
6257 pos = pm->frag_parent;
6258 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, pm);
6259 free_pending_message (pm);
6260 /* check if subtree is done */
6261 while ((NULL == pos->head_frag) && (pos->frag_off == pos->bytes_msg) &&
6262 (NULL != pos->frag_parent))
6263 {
6264 pm = pos;
6265 pos = pm->frag_parent;
6266 if ((NULL == pos) && (PMT_DV_BOX == pm->pmt))
6267 {
6268 client_send_response (pm);
6269 return;
6270 }
6271 else if (PMT_DV_BOX == pm->pmt)
6272 {
6273 client_send_response (pos);
6274 return;
6275 }
6276 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, pm);
6277 free_pending_message (pm);
6278 }
6279
6280 /* Was this the last applicable fragment? */
6281 if ((NULL == pos->head_frag) && (NULL == pos->frag_parent) &&
6282 (pos->frag_off == pos->bytes_msg))
6283 client_send_response (pos);
6284 return;
6285
6286 case PMT_DV_BOX:
6287 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6288 "Completed transmission of message %llu (DV Box)\n",
6289 pm->logging_uuid);
6290 if (NULL != pm->frag_parent)
6291 {
6292 if (NULL != pm->bpm)
6293 {
6294 GNUNET_free (pm->bpm);
6295 }
6296 client_send_response (pm->frag_parent);
6297 }
6298 else
6299 client_send_response (pm);
6300 return;
6301 }
6302}
6303
6304
6305/**
6306 * The @a pa was acknowledged, process the acknowledgement.
6307 *
6308 * @param pa the pending acknowledgement that was satisfied
6309 * @param ack_delay artificial delay from cumulative acks created by the
6310 * other peer
6311 */
6312static void
6313handle_acknowledged (struct PendingAcknowledgement *pa,
6314 struct GNUNET_TIME_Relative ack_delay)
6315{
6316 struct GNUNET_TIME_Relative delay;
6317
6318 delay = GNUNET_TIME_absolute_get_duration (pa->transmission_time);
6319 if (delay.rel_value_us > ack_delay.rel_value_us)
6320 delay = GNUNET_TIME_UNIT_ZERO;
6321 else
6322 delay = GNUNET_TIME_relative_subtract (delay, ack_delay);
6323 if (NULL != pa->queue)
6324 update_queue_performance (pa->queue, delay, pa->message_size);
6325 if (NULL != pa->dvh)
6326 update_dvh_performance (pa->dvh, delay, pa->message_size);
6327 if (NULL != pa->pm)
6328 completed_pending_message (pa->pm);
6329 free_pending_acknowledgement (pa);
6330}
6331
6332
6333/**
6334 * Communicator gave us a reliability ack. Check it is well-formed.
6335 *
6336 * @param cls a `struct CommunicatorMessageContext` (unused)
6337 * @param ra the message that was received
6338 * @return #GNUNET_Ok if @a ra is well-formed
6339 */
6340static int
6341check_reliability_ack (void *cls,
6342 const struct TransportReliabilityAckMessage *ra)
6343{
6344 unsigned int n_acks;
6345
6346 (void) cls;
6347 n_acks = (ntohs (ra->header.size) - sizeof(*ra))
6348 / sizeof(struct TransportCummulativeAckPayloadP);
6349 if (0 == n_acks)
6350 {
6351 GNUNET_break_op (0);
6352 return GNUNET_SYSERR;
6353 }
6354 if ((ntohs (ra->header.size) - sizeof(*ra)) !=
6355 n_acks * sizeof(struct TransportCummulativeAckPayloadP))
6356 {
6357 GNUNET_break_op (0);
6358 return GNUNET_SYSERR;
6359 }
6360 return GNUNET_OK;
6361}
6362
6363
6364/**
6365 * Communicator gave us a reliability ack. Process the request.
6366 *
6367 * @param cls a `struct CommunicatorMessageContext` (must call
6368 * #finish_cmc_handling() when done)
6369 * @param ra the message that was received
6370 */
6371static void
6372handle_reliability_ack (void *cls,
6373 const struct TransportReliabilityAckMessage *ra)
6374{
6375 struct CommunicatorMessageContext *cmc = cls;
6376 const struct TransportCummulativeAckPayloadP *ack;
6377 unsigned int n_acks;
6378 uint32_t ack_counter;
6379
6380 n_acks = (ntohs (ra->header.size) - sizeof(*ra))
6381 / sizeof(struct TransportCummulativeAckPayloadP);
6382 ack = (const struct TransportCummulativeAckPayloadP *) &ra[1];
6383 for (unsigned int i = 0; i < n_acks; i++)
6384 {
6385 struct PendingAcknowledgement *pa =
6386 GNUNET_CONTAINER_multiuuidmap_get (pending_acks, &ack[i].ack_uuid.value);
6387 if (NULL == pa)
6388 {
6389 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6390 "Received ACK from %s with UUID %s which is unknown to us!\n",
6391 GNUNET_i2s (&cmc->im.sender),
6392 GNUNET_uuid2s (&ack[i].ack_uuid.value));
6393 GNUNET_STATISTICS_update (
6394 GST_stats,
6395 "# FRAGMENT_ACKS dropped, no matching pending message",
6396 1,
6397 GNUNET_NO);
6398 continue;
6399 }
6400 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6401 "Received ACK from %s with UUID %s\n",
6402 GNUNET_i2s (&cmc->im.sender),
6403 GNUNET_uuid2s (&ack[i].ack_uuid.value));
6404 handle_acknowledged (pa, GNUNET_TIME_relative_ntoh (ack[i].ack_delay));
6405 }
6406
6407 ack_counter = htonl (ra->ack_counter);
6408 (void) ack_counter; /* silence compiler warning for now */
6409 // FIXME-OPTIMIZE: track ACK losses based on ack_counter somewhere!
6410 // (DV and/or Neighbour?)
6411 finish_cmc_handling (cmc);
6412}
6413
6414
6415/**
6416 * Communicator gave us a backchannel encapsulation. Check the message.
6417 *
6418 * @param cls a `struct CommunicatorMessageContext`
6419 * @param be the send message that was sent
6420 * @return #GNUNET_YES if message is well-formed
6421 */
6422static int
6423check_backchannel_encapsulation (
6424 void *cls,
6425 const struct TransportBackchannelEncapsulationMessage *be)
6426{
6427 uint16_t size = ntohs (be->header.size) - sizeof(*be);
6428 const struct GNUNET_MessageHeader *inbox =
6429 (const struct GNUNET_MessageHeader *) &be[1];
6430 const char *is;
6431 uint16_t isize;
6432
6433 (void) cls;
6434 if (ntohs (inbox->size) >= size)
6435 {
6436 GNUNET_break_op (0);
6437 return GNUNET_SYSERR;
6438 }
6439 isize = ntohs (inbox->size);
6440 is = ((const char *) inbox) + isize;
6441 size -= isize;
6442 if ('\0' != is[size - 1])
6443 {
6444 GNUNET_break_op (0);
6445 return GNUNET_SYSERR;
6446 }
6447 return GNUNET_YES;
6448}
6449
6450
6451/**
6452 * Communicator gave us a backchannel encapsulation. Process the request.
6453 * (We are the destination of the backchannel here.)
6454 *
6455 * @param cls a `struct CommunicatorMessageContext` (must call
6456 * #finish_cmc_handling() when done)
6457 * @param be the message that was received
6458 */
6459static void
6460handle_backchannel_encapsulation (
6461 void *cls,
6462 const struct TransportBackchannelEncapsulationMessage *be)
6463{
6464 struct CommunicatorMessageContext *cmc = cls;
6465 struct GNUNET_TRANSPORT_CommunicatorBackchannelIncoming *cbi;
6466 struct GNUNET_MQ_Envelope *env;
6467 struct TransportClient *tc;
6468 const struct GNUNET_MessageHeader *inbox =
6469 (const struct GNUNET_MessageHeader *) &be[1];
6470 uint16_t isize = ntohs (inbox->size);
6471 const char *target_communicator = ((const char *) inbox) + isize;
6472 char *sender;
6473 char *self;
6474
6475 GNUNET_asprintf (&sender,
6476 "%s",
6477 GNUNET_i2s (&cmc->im.sender));
6478 GNUNET_asprintf (&self,
6479 "%s",
6480 GNUNET_i2s (&GST_my_identity));
6481
6482 /* Find client providing this communicator */
6483 for (tc = clients_head; NULL != tc; tc = tc->next)
6484 if ((CT_COMMUNICATOR == tc->type) &&
6485 (0 ==
6486 strcmp (tc->details.communicator.address_prefix, target_communicator)))
6487 break;
6488 if (NULL == tc)
6489 {
6490 char *stastr;
6491
6492 GNUNET_asprintf (
6493 &stastr,
6494 "# Backchannel message dropped: target communicator `%s' unknown",
6495 target_communicator);
6496 GNUNET_STATISTICS_update (GST_stats, stastr, 1, GNUNET_NO);
6497 GNUNET_free (stastr);
6498 finish_cmc_handling (cmc);
6499 return;
6500 }
6501 /* Finally, deliver backchannel message to communicator */
6502 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6503 "Delivering backchannel message from %s to %s of type %u to %s\n",
6504 sender,
6505 self,
6506 ntohs (inbox->type),
6507 target_communicator);
6508 env = GNUNET_MQ_msg_extra (
6509 cbi,
6510 isize,
6511 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL_INCOMING);
6512 cbi->pid = cmc->im.sender;
6513 memcpy (&cbi[1], inbox, isize);
6514 GNUNET_MQ_send (tc->mq, env);
6515 finish_cmc_handling (cmc);
6516}
6517
6518
6519/**
6520 * Task called when we should check if any of the DV paths
6521 * we have learned to a target are due for garbage collection.
6522 *
6523 * Collects stale paths, and possibly frees the entire DV
6524 * entry if no paths are left. Otherwise re-schedules itself.
6525 *
6526 * @param cls a `struct DistanceVector`
6527 */
6528static void
6529path_cleanup_cb (void *cls)
6530{
6531 struct DistanceVector *dv = cls;
6532 struct DistanceVectorHop *pos;
6533
6534 dv->timeout_task = NULL;
6535 while (NULL != (pos = dv->dv_head))
6536 {
6537 GNUNET_assert (dv == pos->dv);
6538 if (GNUNET_TIME_absolute_get_remaining (pos->timeout).rel_value_us > 0)
6539 break;
6540 free_distance_vector_hop (pos);
6541 }
6542 if (NULL == pos)
6543 {
6544 free_dv_route (dv);
6545 return;
6546 }
6547 dv->timeout_task =
6548 GNUNET_SCHEDULER_add_at (pos->timeout, &path_cleanup_cb, dv);
6549}
6550
6551
6552/**
6553 * The @a hop is a validated path to the respective target
6554 * peer and we should tell core about it -- and schedule
6555 * a job to revoke the state.
6556 *
6557 * @param hop a path to some peer that is the reason for activation
6558 */
6559static void
6560activate_core_visible_dv_path (struct DistanceVectorHop *hop)
6561{
6562 struct DistanceVector *dv = hop->dv;
6563 struct VirtualLink *vl;
6564
6565 vl = lookup_virtual_link (&dv->target);
6566 if (NULL == vl)
6567 {
6568
6569 vl = GNUNET_new (struct VirtualLink);
6570 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6571 "Creating new virtual link %p to %s using DV!\n",
6572 vl,
6573 GNUNET_i2s (&dv->target));
6574 vl->confirmed = GNUNET_YES;
6575 vl->message_uuid_ctr =
6576 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
6577 vl->target = dv->target;
6578 vl->core_recv_window = RECV_WINDOW_SIZE;
6579 vl->available_fc_window_size = DEFAULT_WINDOW_SIZE;
6580 vl->incoming_fc_window_size = DEFAULT_WINDOW_SIZE;
6581 GNUNET_break (GNUNET_YES ==
6582 GNUNET_CONTAINER_multipeermap_put (
6583 links,
6584 &vl->target,
6585 vl,
6586 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
6587 vl->dv = dv;
6588 dv->vl = vl;
6589 vl->visibility_task =
6590 GNUNET_SCHEDULER_add_at (hop->path_valid_until, &check_link_down, vl);
6591 consider_sending_fc (vl);
6592 /* We lacked a confirmed connection to the target
6593 before, so tell CORE about it (finally!) */
6594 cores_send_connect_info (&dv->target);
6595 }
6596 else
6597 {
6598 /* Link was already up, remember dv is also now available and we are done */
6599 vl->dv = dv;
6600 dv->vl = vl;
6601 if (GNUNET_NO == vl->confirmed)
6602 {
6603 vl->confirmed = GNUNET_YES;
6604 vl->visibility_task =
6605 GNUNET_SCHEDULER_add_at (hop->path_valid_until, &check_link_down, vl);
6606 consider_sending_fc (vl);
6607 /* We lacked a confirmed connection to the target
6608 before, so tell CORE about it (finally!) */
6609 cores_send_connect_info (&dv->target);
6610 }
6611 else
6612 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6613 "Virtual link to %s could now also use DV!\n",
6614 GNUNET_i2s (&dv->target));
6615 }
6616}
6617
6618
6619/**
6620 * We have learned a @a path through the network to some other peer, add it to
6621 * our DV data structure (returning #GNUNET_YES on success).
6622 *
6623 * We do not add paths if we have a sufficient number of shorter
6624 * paths to this target already (returning #GNUNET_NO).
6625 *
6626 * We also do not add problematic paths, like those where we lack the first
6627 * hop in our neighbour list (i.e. due to a topology change) or where some
6628 * non-first hop is in our neighbour list (returning #GNUNET_SYSERR).
6629 *
6630 * @param path the path we learned, path[0] should be us,
6631 * and then path contains a valid path from us to
6632 * `path[path_len-1]` path[1] should be a direct neighbour (we should check!)
6633 * @param path_len number of entries on the @a path, at least three!
6634 * @param network_latency how long does the message take from us to
6635 * `path[path_len-1]`? set to "forever" if unknown
6636 * @param path_valid_until how long is this path considered validated? Maybe
6637 * be zero.
6638 * @return #GNUNET_YES on success,
6639 * #GNUNET_NO if we have better path(s) to the target
6640 * #GNUNET_SYSERR if the path is useless and/or invalid
6641 * (i.e. path[1] not a direct neighbour
6642 * or path[i+1] is a direct neighbour for i>0)
6643 */
6644static int
6645learn_dv_path (const struct GNUNET_PeerIdentity *path,
6646 unsigned int path_len,
6647 struct GNUNET_TIME_Relative network_latency,
6648 struct GNUNET_TIME_Absolute path_valid_until)
6649{
6650 struct DistanceVectorHop *hop;
6651 struct DistanceVector *dv;
6652 struct Neighbour *next_hop;
6653 unsigned int shorter_distance;
6654
6655 if (path_len < 3)
6656 {
6657 /* what a boring path! not allowed! */
6658 GNUNET_break (0);
6659 return GNUNET_SYSERR;
6660 }
6661 GNUNET_assert (0 == GNUNET_memcmp (&GST_my_identity, &path[0]));
6662 next_hop = lookup_neighbour (&path[1]);
6663 if (NULL == next_hop)
6664 {
6665 /* next hop must be a neighbour, otherwise this whole thing is useless! */
6666 GNUNET_break (0);
6667 return GNUNET_SYSERR;
6668 }
6669 for (unsigned int i = 2; i < path_len; i++)
6670 if (NULL != lookup_neighbour (&path[i]))
6671 {
6672 /* Useless path: we have a direct connection to some hop
6673 in the middle of the path, so this one is not even
6674 terribly useful for redundancy */
6675 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6676 "Path of %u hops useless: directly link to hop %u (%s)\n",
6677 path_len,
6678 i,
6679 GNUNET_i2s (&path[i]));
6680 GNUNET_STATISTICS_update (GST_stats,
6681 "# Useless DV path ignored: hop is neighbour",
6682 1,
6683 GNUNET_NO);
6684 return GNUNET_SYSERR;
6685 }
6686 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &path[path_len - 1]);
6687 if (NULL == dv)
6688 {
6689 dv = GNUNET_new (struct DistanceVector);
6690 dv->target = path[path_len - 1];
6691 dv->timeout_task = GNUNET_SCHEDULER_add_delayed (DV_PATH_VALIDITY_TIMEOUT,
6692 &path_cleanup_cb,
6693 dv);
6694 GNUNET_assert (GNUNET_OK ==
6695 GNUNET_CONTAINER_multipeermap_put (
6696 dv_routes,
6697 &dv->target,
6698 dv,
6699 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
6700 }
6701 /* Check if we have this path already! */
6702 shorter_distance = 0;
6703 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
6704 pos = pos->next_dv)
6705 {
6706 if (pos->distance < path_len - 3)
6707 shorter_distance++;
6708 /* Note that the distances in 'pos' excludes us (path[0]),
6709 the next_hop (path[1]) and the target so we need to subtract three
6710 and check next_hop explicitly */
6711 if ((pos->distance == path_len - 3) && (pos->next_hop == next_hop))
6712 {
6713 int match = GNUNET_YES;
6714
6715 for (unsigned int i = 0; i < pos->distance; i++)
6716 {
6717 if (0 != GNUNET_memcmp (&pos->path[i], &path[i + 2]))
6718 {
6719 match = GNUNET_NO;
6720 break;
6721 }
6722 }
6723 if (GNUNET_YES == match)
6724 {
6725 struct GNUNET_TIME_Relative last_timeout;
6726
6727 /* Re-discovered known path, update timeout */
6728 GNUNET_STATISTICS_update (GST_stats,
6729 "# Known DV path refreshed",
6730 1,
6731 GNUNET_NO);
6732 last_timeout = GNUNET_TIME_absolute_get_remaining (pos->timeout);
6733 pos->timeout =
6734 GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
6735 pos->path_valid_until =
6736 GNUNET_TIME_absolute_max (pos->path_valid_until, path_valid_until);
6737 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, pos);
6738 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, pos);
6739 if (0 <
6740 GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us)
6741 activate_core_visible_dv_path (pos);
6742 if (last_timeout.rel_value_us <
6743 GNUNET_TIME_relative_subtract (DV_PATH_VALIDITY_TIMEOUT,
6744 DV_PATH_DISCOVERY_FREQUENCY)
6745 .rel_value_us)
6746 {
6747 /* Some peer send DV learn messages too often, we are learning
6748 the same path faster than it would be useful; do not forward! */
6749 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6750 "Rediscovered path too quickly, not forwarding further\n");
6751 return GNUNET_NO;
6752 }
6753 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6754 "Refreshed known path to %s valid until %s, forwarding further\n",
6755 GNUNET_i2s (&dv->target),
6756 GNUNET_STRINGS_absolute_time_to_string (
6757 pos->path_valid_until));
6758 return GNUNET_YES;
6759 }
6760 }
6761 }
6762 /* Count how many shorter paths we have (incl. direct
6763 neighbours) before simply giving up on this one! */
6764 if (shorter_distance >= MAX_DV_PATHS_TO_TARGET)
6765 {
6766 /* We have a shorter path already! */
6767 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6768 "Have many shorter DV paths %s, not forwarding further\n",
6769 GNUNET_i2s (&dv->target));
6770 return GNUNET_NO;
6771 }
6772 /* create new DV path entry */
6773 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6774 "Discovered new DV path to %s valid until %s\n",
6775 GNUNET_i2s (&dv->target),
6776 GNUNET_STRINGS_absolute_time_to_string (path_valid_until));
6777 hop = GNUNET_malloc (sizeof(struct DistanceVectorHop)
6778 + sizeof(struct GNUNET_PeerIdentity) * (path_len - 3));
6779 hop->next_hop = next_hop;
6780 hop->dv = dv;
6781 hop->path = (const struct GNUNET_PeerIdentity *) &hop[1];
6782 memcpy (&hop[1],
6783 &path[2],
6784 sizeof(struct GNUNET_PeerIdentity) * (path_len - 3));
6785 hop->timeout = GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
6786 hop->path_valid_until = path_valid_until;
6787 hop->distance = path_len - 3;
6788 hop->pd.aged_rtt = network_latency;
6789 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, hop);
6790 GNUNET_CONTAINER_MDLL_insert (neighbour,
6791 next_hop->dv_head,
6792 next_hop->dv_tail,
6793 hop);
6794 if (0 < GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us)
6795 activate_core_visible_dv_path (hop);
6796 return GNUNET_YES;
6797}
6798
6799
6800/**
6801 * Communicator gave us a DV learn message. Check the message.
6802 *
6803 * @param cls a `struct CommunicatorMessageContext`
6804 * @param dvl the send message that was sent
6805 * @return #GNUNET_YES if message is well-formed
6806 */
6807static int
6808check_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
6809{
6810 uint16_t size = ntohs (dvl->header.size);
6811 uint16_t num_hops = ntohs (dvl->num_hops);
6812 const struct DVPathEntryP *hops = (const struct DVPathEntryP *) &dvl[1];
6813
6814 (void) cls;
6815 if (size != sizeof(*dvl) + num_hops * sizeof(struct DVPathEntryP))
6816 {
6817 GNUNET_break_op (0);
6818 return GNUNET_SYSERR;
6819 }
6820 if (num_hops > MAX_DV_HOPS_ALLOWED)
6821 {
6822 GNUNET_break_op (0);
6823 return GNUNET_SYSERR;
6824 }
6825 for (unsigned int i = 0; i < num_hops; i++)
6826 {
6827 if (0 == GNUNET_memcmp (&dvl->initiator, &hops[i].hop))
6828 {
6829 GNUNET_break_op (0);
6830 return GNUNET_SYSERR;
6831 }
6832 if (0 == GNUNET_memcmp (&GST_my_identity, &hops[i].hop))
6833 {
6834 GNUNET_break_op (0);
6835 return GNUNET_SYSERR;
6836 }
6837 }
6838 return GNUNET_YES;
6839}
6840
6841
6842/**
6843 * Build and forward a DV learn message to @a next_hop.
6844 *
6845 * @param next_hop peer to send the message to
6846 * @param msg message received
6847 * @param bi_history bitmask specifying hops on path that were bidirectional
6848 * @param nhops length of the @a hops array
6849 * @param hops path the message traversed so far
6850 * @param in_time when did we receive the message, used to calculate network
6851 * delay
6852 */
6853static void
6854forward_dv_learn (const struct GNUNET_PeerIdentity *next_hop,
6855 const struct TransportDVLearnMessage *msg,
6856 uint16_t bi_history,
6857 uint16_t nhops,
6858 const struct DVPathEntryP *hops,
6859 struct GNUNET_TIME_Absolute in_time)
6860{
6861 struct Neighbour *n;
6862 struct VirtualLink *vl;
6863 struct DVPathEntryP *dhops;
6864 char buf[sizeof(struct TransportDVLearnMessage)
6865 + (nhops + 1) * sizeof(struct DVPathEntryP)] GNUNET_ALIGN;
6866 struct TransportDVLearnMessage *fwd = (struct TransportDVLearnMessage *) buf;
6867 struct GNUNET_TIME_Relative nnd;
6868
6869 /* compute message for forwarding */
6870 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6871 "Forwarding DV learn message originating from %s to %s\n",
6872 GNUNET_i2s (&msg->initiator),
6873 GNUNET_i2s2 (next_hop));
6874 GNUNET_assert (nhops < MAX_DV_HOPS_ALLOWED);
6875 fwd->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
6876 fwd->header.size = htons (sizeof(struct TransportDVLearnMessage)
6877 + (nhops + 1) * sizeof(struct DVPathEntryP));
6878 fwd->num_hops = htons (nhops + 1);
6879 fwd->bidirectional = htons (bi_history);
6880 nnd = GNUNET_TIME_relative_add (GNUNET_TIME_absolute_get_duration (in_time),
6881 GNUNET_TIME_relative_ntoh (
6882 msg->non_network_delay));
6883 fwd->non_network_delay = GNUNET_TIME_relative_hton (nnd);
6884 fwd->init_sig = msg->init_sig;
6885 fwd->initiator = msg->initiator;
6886 fwd->challenge = msg->challenge;
6887 fwd->monotonic_time = msg->monotonic_time;
6888 dhops = (struct DVPathEntryP *) &fwd[1];
6889 GNUNET_memcpy (dhops, hops, sizeof(struct DVPathEntryP) * nhops);
6890 dhops[nhops].hop = GST_my_identity;
6891 {
6892 struct DvHopPS dhp = {
6893 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
6894 .purpose.size = htonl (sizeof(dhp)),
6895 .pred = (0 == nhops) ? msg->initiator : dhops[nhops - 1].hop,
6896 .succ = *next_hop,
6897 .challenge = msg->challenge
6898 };
6899 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
6900 &dhp,
6901 &dhops[nhops].hop_sig);
6902 }
6903 /*route_control_message_without_fc (next_hop,
6904 &fwd->header,
6905 RMO_UNCONFIRMED_ALLOWED);*/
6906 vl = lookup_virtual_link (next_hop);
6907 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
6908 {
6909 route_control_message_without_fc (vl,
6910 &fwd->header,
6911 RMO_UNCONFIRMED_ALLOWED);
6912 }
6913 else
6914 {
6915 /* Use route via neighbour */
6916 n = lookup_neighbour (next_hop);
6917 if (NULL != n)
6918 route_via_neighbour (
6919 n,
6920 &fwd->header,
6921 RMO_UNCONFIRMED_ALLOWED);
6922 }
6923}
6924
6925
6926/**
6927 * Check signature of type #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
6928 *
6929 * @param sender_monotonic_time monotonic time of the initiator
6930 * @param init the signer
6931 * @param challenge the challenge that was signed
6932 * @param init_sig signature presumably by @a init
6933 * @return #GNUNET_OK if the signature is valid
6934 */
6935static int
6936validate_dv_initiator_signature (
6937 struct GNUNET_TIME_AbsoluteNBO sender_monotonic_time,
6938 const struct GNUNET_PeerIdentity *init,
6939 const struct GNUNET_CRYPTO_ChallengeNonceP *challenge,
6940 const struct GNUNET_CRYPTO_EddsaSignature *init_sig)
6941{
6942 struct DvInitPS ip = { .purpose.purpose = htonl (
6943 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
6944 .purpose.size = htonl (sizeof(ip)),
6945 .monotonic_time = sender_monotonic_time,
6946 .challenge = *challenge };
6947
6948 if (
6949 GNUNET_OK !=
6950 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR,
6951 &ip,
6952 init_sig,
6953 &init->public_key))
6954 {
6955 GNUNET_break_op (0);
6956 return GNUNET_SYSERR;
6957 }
6958 return GNUNET_OK;
6959}
6960
6961
6962/**
6963 * Closure for #dv_neighbour_selection and #dv_neighbour_transmission.
6964 */
6965struct NeighbourSelectionContext
6966{
6967 /**
6968 * Original message we received.
6969 */
6970 const struct TransportDVLearnMessage *dvl;
6971
6972 /**
6973 * The hops taken.
6974 */
6975 const struct DVPathEntryP *hops;
6976
6977 /**
6978 * Time we received the message.
6979 */
6980 struct GNUNET_TIME_Absolute in_time;
6981
6982 /**
6983 * Offsets of the selected peers.
6984 */
6985 uint32_t selections[MAX_DV_DISCOVERY_SELECTION];
6986
6987 /**
6988 * Number of peers eligible for selection.
6989 */
6990 unsigned int num_eligible;
6991
6992 /**
6993 * Number of peers that were selected for forwarding.
6994 */
6995 unsigned int num_selections;
6996
6997 /**
6998 * Number of hops in @e hops
6999 */
7000 uint16_t nhops;
7001
7002 /**
7003 * Bitmap of bidirectional connections encountered.
7004 */
7005 uint16_t bi_history;
7006};
7007
7008
7009/**
7010 * Function called for each neighbour during #handle_dv_learn.
7011 *
7012 * @param cls a `struct NeighbourSelectionContext *`
7013 * @param pid identity of the peer
7014 * @param value a `struct Neighbour`
7015 * @return #GNUNET_YES (always)
7016 */
7017static int
7018dv_neighbour_selection (void *cls,
7019 const struct GNUNET_PeerIdentity *pid,
7020 void *value)
7021{
7022 struct NeighbourSelectionContext *nsc = cls;
7023
7024 (void) value;
7025 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
7026 return GNUNET_YES; /* skip initiator */
7027 for (unsigned int i = 0; i < nsc->nhops; i++)
7028 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
7029 return GNUNET_YES;
7030 /* skip peers on path */
7031 nsc->num_eligible++;
7032 return GNUNET_YES;
7033}
7034
7035
7036/**
7037 * Function called for each neighbour during #handle_dv_learn.
7038 * We call #forward_dv_learn() on the neighbour(s) selected
7039 * during #dv_neighbour_selection().
7040 *
7041 * @param cls a `struct NeighbourSelectionContext *`
7042 * @param pid identity of the peer
7043 * @param value a `struct Neighbour`
7044 * @return #GNUNET_YES (always)
7045 */
7046static int
7047dv_neighbour_transmission (void *cls,
7048 const struct GNUNET_PeerIdentity *pid,
7049 void *value)
7050{
7051 struct NeighbourSelectionContext *nsc = cls;
7052
7053 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7054 "transmission %s\n",
7055 GNUNET_i2s (pid));
7056 (void) value;
7057 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
7058 return GNUNET_YES; /* skip initiator */
7059 for (unsigned int i = 0; i < nsc->nhops; i++)
7060 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
7061 return GNUNET_YES;
7062 /* skip peers on path */
7063 for (unsigned int i = 0; i < nsc->num_selections; i++)
7064 {
7065 if (nsc->selections[i] == nsc->num_eligible)
7066 {
7067 forward_dv_learn (pid,
7068 nsc->dvl,
7069 nsc->bi_history,
7070 nsc->nhops,
7071 nsc->hops,
7072 nsc->in_time);
7073 break;
7074 }
7075 }
7076 nsc->num_eligible++;
7077 return GNUNET_YES;
7078}
7079
7080
7081/**
7082 * Computes the number of neighbours we should forward a DVInit
7083 * message to given that it has so far taken @a hops_taken hops
7084 * though the network and that the number of neighbours we have
7085 * in total is @a neighbour_count, out of which @a eligible_count
7086 * are not yet on the path.
7087 *
7088 * NOTE: technically we might want to include NSE in the formula to
7089 * get a better grip on the overall network size. However, for now
7090 * using NSE here would create a dependency issue in the build system.
7091 * => Left for later, hardcoded to 50 for now.
7092 *
7093 * The goal of the fomula is that we want to reach a total of LOG(NSE)
7094 * peers via DV (`target_total`). We want the reach to be spread out
7095 * over various distances to the origin, with a bias towards shorter
7096 * distances.
7097 *
7098 * We make the strong assumption that the network topology looks
7099 * "similar" at other hops, in particular the @a neighbour_count
7100 * should be comparable at other hops.
7101 *
7102 * If the local neighbourhood is densely connected, we expect that @a
7103 * eligible_count is close to @a neighbour_count minus @a hops_taken
7104 * as a lot of the path is already known. In that case, we should
7105 * forward to few(er) peers to try to find a path out of the
7106 * neighbourhood. OTOH, if @a eligible_count is close to @a
7107 * neighbour_count, we should forward to many peers as we are either
7108 * still close to the origin (i.e. @a hops_taken is small) or because
7109 * we managed to get beyond a local cluster. We express this as
7110 * the `boost_factor` using the square of the fraction of eligible
7111 * neighbours (so if only 50% are eligible, we boost by 1/4, but if
7112 * 99% are eligible, the 'boost' will be almost 1).
7113 *
7114 * Second, the more hops we have taken, the larger the problem of an
7115 * exponential traffic explosion gets. So we take the `target_total`,
7116 * and compute our degree such that at each distance d 2^{-d} peers
7117 * are selected (corrected by the `boost_factor`).
7118 *
7119 * @param hops_taken number of hops DVInit has travelled so far
7120 * @param neighbour_count number of neighbours we have in total
7121 * @param eligible_count number of neighbours we could in
7122 * theory forward to
7123 */
7124static unsigned int
7125calculate_fork_degree (unsigned int hops_taken,
7126 unsigned int neighbour_count,
7127 unsigned int eligible_count)
7128{
7129 double target_total = 50.0; /* FIXME: use LOG(NSE)? */
7130 double eligible_ratio =
7131 ((double) eligible_count) / ((double) neighbour_count);
7132 double boost_factor = eligible_ratio * eligible_ratio;
7133 unsigned int rnd;
7134 double left;
7135
7136 if (hops_taken >= 64)
7137 {
7138 GNUNET_break (0);
7139 return 0; /* precaution given bitshift below */
7140 }
7141 for (unsigned int i = 1; i < hops_taken; i++)
7142 {
7143 /* For each hop, subtract the expected number of targets
7144 reached at distance d (so what remains divided by 2^d) */
7145 target_total -= (target_total * boost_factor / (1LLU << i));
7146 }
7147 rnd =
7148 (unsigned int) floor (target_total * boost_factor / (1LLU << hops_taken));
7149 /* round up or down probabilistically depending on how close we were
7150 when floor()ing to rnd */
7151 left = target_total - (double) rnd;
7152 if (UINT32_MAX * left >
7153 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX))
7154 rnd++; /* round up */
7155 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7156 "Forwarding DV learn message of %u hops %u(/%u/%u) times\n",
7157 hops_taken,
7158 rnd,
7159 eligible_count,
7160 neighbour_count);
7161 return rnd;
7162}
7163
7164
7165/**
7166 * Function called when peerstore is done storing a DV monotonic time.
7167 *
7168 * @param cls a `struct Neighbour`
7169 * @param success #GNUNET_YES if peerstore was successful
7170 */
7171static void
7172neighbour_store_dvmono_cb (void *cls, int success)
7173{
7174 struct Neighbour *n = cls;
7175
7176 n->sc = NULL;
7177 if (GNUNET_YES != success)
7178 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
7179 "Failed to store other peer's monotonic time in peerstore!\n");
7180}
7181
7182
7183/**
7184 * Communicator gave us a DV learn message. Process the request.
7185 *
7186 * @param cls a `struct CommunicatorMessageContext` (must call
7187 * #finish_cmc_handling() when done)
7188 * @param dvl the message that was received
7189 */
7190static void
7191handle_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
7192{
7193 struct CommunicatorMessageContext *cmc = cls;
7194 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
7195 int bi_hop;
7196 uint16_t nhops;
7197 uint16_t bi_history;
7198 const struct DVPathEntryP *hops;
7199 int do_fwd;
7200 int did_initiator;
7201 struct GNUNET_TIME_Absolute in_time;
7202 struct Neighbour *n;
7203
7204 nhops = ntohs (dvl->num_hops); /* 0 = sender is initiator */
7205 bi_history = ntohs (dvl->bidirectional);
7206 hops = (const struct DVPathEntryP *) &dvl[1];
7207 if (0 == nhops)
7208 {
7209 /* sanity check */
7210 if (0 != GNUNET_memcmp (&dvl->initiator, &cmc->im.sender))
7211 {
7212 GNUNET_break (0);
7213 finish_cmc_handling (cmc);
7214 return;
7215 }
7216 }
7217 else
7218 {
7219 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7220 "handle dv learn message last hop %s\n",
7221 GNUNET_i2s (&hops[nhops - 1].hop));
7222 /* sanity check */
7223 if (0 != GNUNET_memcmp (&hops[nhops - 1].hop, &cmc->im.sender))
7224 {
7225 GNUNET_break (0);
7226 finish_cmc_handling (cmc);
7227 return;
7228 }
7229 }
7230
7231 GNUNET_assert (CT_COMMUNICATOR == cmc->tc->type);
7232 cc = cmc->tc->details.communicator.cc;
7233 bi_hop = (GNUNET_TRANSPORT_CC_RELIABLE ==
7234 cc); // FIXME: add bi-directional flag to cc?
7235 in_time = GNUNET_TIME_absolute_get ();
7236
7237 /* continue communicator here, everything else can happen asynchronous! */
7238 finish_cmc_handling (cmc);
7239
7240 n = lookup_neighbour (&dvl->initiator);
7241 if (NULL != n)
7242 {
7243 if ((n->dv_monotime_available == GNUNET_YES) &&
7244 (GNUNET_TIME_absolute_ntoh (dvl->monotonic_time).abs_value_us <
7245 n->last_dv_learn_monotime.abs_value_us))
7246 {
7247 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7248 "DV learn from %s discarded due to time travel",
7249 GNUNET_i2s (&dvl->initiator));
7250 GNUNET_STATISTICS_update (GST_stats,
7251 "# DV learn discarded due to time travel",
7252 1,
7253 GNUNET_NO);
7254 return;
7255 }
7256 if (GNUNET_OK != validate_dv_initiator_signature (dvl->monotonic_time,
7257 &dvl->initiator,
7258 &dvl->challenge,
7259 &dvl->init_sig))
7260 {
7261 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7262 "DV learn signature from %s invalid\n",
7263 GNUNET_i2s (&dvl->initiator));
7264 GNUNET_break_op (0);
7265 return;
7266 }
7267 n->last_dv_learn_monotime = GNUNET_TIME_absolute_ntoh (dvl->monotonic_time);
7268 if (GNUNET_YES == n->dv_monotime_available)
7269 {
7270 if (NULL != n->sc)
7271 {
7272 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7273 "store cancel\n");
7274 GNUNET_PEERSTORE_store_cancel (n->sc);
7275 }
7276 n->sc =
7277 GNUNET_PEERSTORE_store (peerstore,
7278 "transport",
7279 &dvl->initiator,
7280 GNUNET_PEERSTORE_TRANSPORT_DVLEARN_MONOTIME,
7281 &dvl->monotonic_time,
7282 sizeof(dvl->monotonic_time),
7283 GNUNET_TIME_UNIT_FOREVER_ABS,
7284 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
7285 &neighbour_store_dvmono_cb,
7286 n);
7287 }
7288 }
7289 /* OPTIMIZE-FIXME: asynchronously (!) verify signatures!,
7290 If signature verification load too high, implement random drop strategy */
7291 for (unsigned int i = 0; i < nhops; i++)
7292 {
7293 struct DvHopPS dhp = { .purpose.purpose =
7294 htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
7295 .purpose.size = htonl (sizeof(dhp)),
7296 .pred = (0 == i) ? dvl->initiator : hops[i - 1].hop,
7297 .succ = (nhops == i + 1) ? GST_my_identity
7298 : hops[i + 1].hop,
7299 .challenge = dvl->challenge };
7300
7301 if (GNUNET_OK !=
7302 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP,
7303 &dhp,
7304 &hops[i].hop_sig,
7305 &hops[i].hop.public_key))
7306 {
7307 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7308 "DV learn from %s signature of hop %u invalid\n",
7309 GNUNET_i2s (&dvl->initiator),
7310 i);
7311 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7312 "signature of hop %s invalid\n",
7313 GNUNET_i2s (&hops[i].hop));
7314 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7315 "pred %s\n",
7316 GNUNET_i2s (&dhp.pred));
7317 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7318 "succ %s\n",
7319 GNUNET_i2s (&dhp.succ));
7320 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7321 "hash %s\n",
7322 GNUNET_sh2s (&dhp.challenge.value));
7323 GNUNET_break_op (0);
7324 return;
7325 }
7326 }
7327 if (GNUNET_EXTRA_LOGGING > 0)
7328 {
7329 char *path;
7330
7331 path = GNUNET_strdup (GNUNET_i2s (&dvl->initiator));
7332 for (unsigned int i = 0; i < nhops; i++)
7333 {
7334 char *tmp;
7335
7336 GNUNET_asprintf (&tmp,
7337 "%s%s%s",
7338 path,
7339 (bi_history & (1 << (nhops - i))) ? "<->" : "-->",
7340 GNUNET_i2s (&hops[i].hop));
7341 GNUNET_free (path);
7342 path = tmp;
7343 }
7344 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7345 "Received DVInit via %s%s%s\n",
7346 path,
7347 bi_hop ? "<->" : "-->",
7348 GNUNET_i2s (&GST_my_identity));
7349 GNUNET_free (path);
7350 }
7351 do_fwd = GNUNET_YES;
7352 if (0 == GNUNET_memcmp (&GST_my_identity, &dvl->initiator))
7353 {
7354 struct GNUNET_PeerIdentity path[nhops + 1];
7355 struct GNUNET_TIME_Relative host_latency_sum;
7356 struct GNUNET_TIME_Relative latency;
7357 struct GNUNET_TIME_Relative network_latency;
7358 struct GNUNET_TIME_Absolute now;
7359
7360 /* We initiated this, learn the forward path! */
7361 path[0] = GST_my_identity;
7362 path[1] = hops[0].hop;
7363 host_latency_sum = GNUNET_TIME_relative_ntoh (dvl->non_network_delay);
7364
7365 // Need also something to lookup initiation time
7366 // to compute RTT! -> add RTT argument here?
7367 now = GNUNET_TIME_absolute_get ();
7368 latency = GNUNET_TIME_absolute_get_duration (GNUNET_TIME_absolute_ntoh (
7369 dvl->monotonic_time));
7370 GNUNET_assert (latency.rel_value_us >= host_latency_sum.rel_value_us);
7371 // latency = GNUNET_TIME_UNIT_FOREVER_REL; // FIXME: initialize properly
7372 // (based on dvl->challenge, we can identify time of origin!)
7373
7374 network_latency = GNUNET_TIME_relative_subtract (latency, host_latency_sum);
7375 /* assumption: latency on all links is the same */
7376 network_latency = GNUNET_TIME_relative_divide (network_latency, nhops);
7377
7378 for (unsigned int i = 2; i <= nhops; i++)
7379 {
7380 struct GNUNET_TIME_Relative ilat;
7381
7382 /* assumption: linear latency increase per hop */
7383 ilat = GNUNET_TIME_relative_multiply (network_latency, i);
7384 path[i] = hops[i - 1].hop;
7385 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7386 "Learned path with %u hops to %s with latency %s\n",
7387 i,
7388 GNUNET_i2s (&path[i]),
7389 GNUNET_STRINGS_relative_time_to_string (ilat, GNUNET_YES));
7390 learn_dv_path (path,
7391 i + 1,
7392 ilat,
7393 GNUNET_TIME_relative_to_absolute (
7394 ADDRESS_VALIDATION_LIFETIME));
7395 }
7396 /* as we initiated, do not forward again (would be circular!) */
7397 do_fwd = GNUNET_NO;
7398 return;
7399 }
7400 if (bi_hop)
7401 {
7402 /* last hop was bi-directional, we could learn something here! */
7403 struct GNUNET_PeerIdentity path[nhops + 2];
7404
7405 path[0] = GST_my_identity;
7406 path[1] = hops[nhops - 1].hop; /* direct neighbour == predecessor! */
7407 for (unsigned int i = 0; i < nhops; i++)
7408 {
7409 int iret;
7410
7411 if (0 == (bi_history & (1 << i)))
7412 break; /* i-th hop not bi-directional, stop learning! */
7413 if (i == nhops - 1)
7414 {
7415 path[i + 2] = dvl->initiator;
7416 }
7417 else
7418 {
7419 path[i + 2] = hops[nhops - i - 2].hop;
7420 }
7421
7422 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7423 "Learned inverse path with %u hops to %s\n",
7424 i + 2,
7425 GNUNET_i2s (&path[i + 2]));
7426 iret = learn_dv_path (path,
7427 i + 3,
7428 GNUNET_TIME_UNIT_FOREVER_REL,
7429 GNUNET_TIME_UNIT_ZERO_ABS);
7430 if (GNUNET_SYSERR == iret)
7431 {
7432 /* path invalid or too long to be interesting for US, thus should also
7433 not be interesting to our neighbours, cut path when forwarding to
7434 'i' hops, except of course for the one that goes back to the
7435 initiator */
7436 GNUNET_STATISTICS_update (GST_stats,
7437 "# DV learn not forwarded due invalidity of path",
7438 1,
7439 GNUNET_NO);
7440 do_fwd = GNUNET_NO;
7441 break;
7442 }
7443 if ((GNUNET_NO == iret) && (nhops == i + 1))
7444 {
7445 /* we have better paths, and this is the longest target,
7446 so there cannot be anything interesting later */
7447 GNUNET_STATISTICS_update (GST_stats,
7448 "# DV learn not forwarded, got better paths",
7449 1,
7450 GNUNET_NO);
7451 do_fwd = GNUNET_NO;
7452 break;
7453 }
7454 }
7455 }
7456 if (MAX_DV_HOPS_ALLOWED == nhops)
7457 {
7458 /* At limit, we're out of here! */
7459 return;
7460 }
7461
7462 /* Forward to initiator, if path non-trivial and possible */
7463 bi_history = (bi_history << 1) | (bi_hop ? 1 : 0);
7464 did_initiator = GNUNET_NO;
7465 if ((1 <= nhops) &&
7466 (GNUNET_YES ==
7467 GNUNET_CONTAINER_multipeermap_contains (neighbours, &dvl->initiator)))
7468 {
7469 /* send back to origin! */
7470 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7471 "Sending DVL back to initiator %s\n",
7472 GNUNET_i2s (&dvl->initiator));
7473 forward_dv_learn (&dvl->initiator, dvl, bi_history, nhops, hops, in_time);
7474 did_initiator = GNUNET_YES;
7475 }
7476 /* We forward under two conditions: either we still learned something
7477 ourselves (do_fwd), or the path was darn short and thus the initiator is
7478 likely to still be very interested in this (and we did NOT already
7479 send it back to the initiator) */
7480 if ((do_fwd) || ((nhops < MIN_DV_PATH_LENGTH_FOR_INITIATOR) &&
7481 (GNUNET_NO == did_initiator)))
7482 {
7483 /* Pick random neighbours that are not yet on the path */
7484 struct NeighbourSelectionContext nsc;
7485 unsigned int n_cnt;
7486
7487 n_cnt = GNUNET_CONTAINER_multipeermap_size (neighbours);
7488 nsc.nhops = nhops;
7489 nsc.dvl = dvl;
7490 nsc.bi_history = bi_history;
7491 nsc.hops = hops;
7492 nsc.in_time = in_time;
7493 nsc.num_eligible = 0;
7494 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
7495 &dv_neighbour_selection,
7496 &nsc);
7497 if (0 == nsc.num_eligible)
7498 return; /* done here, cannot forward to anyone else */
7499 nsc.num_selections = calculate_fork_degree (nhops, n_cnt, nsc.num_eligible);
7500 nsc.num_selections =
7501 GNUNET_MIN (MAX_DV_DISCOVERY_SELECTION, nsc.num_selections);
7502 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7503 "Forwarding DVL to %u other peers\n",
7504 nsc.num_selections);
7505 for (unsigned int i = 0; i < nsc.num_selections; i++)
7506 nsc.selections[i] =
7507 (nsc.num_selections == n_cnt)
7508 ? i /* all were selected, avoid collisions by chance */
7509 : GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, n_cnt);
7510 nsc.num_eligible = 0;
7511 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
7512 &dv_neighbour_transmission,
7513 &nsc);
7514 }
7515}
7516
7517
7518/**
7519 * Communicator gave us a DV box. Check the message.
7520 *
7521 * @param cls a `struct CommunicatorMessageContext`
7522 * @param dvb the send message that was sent
7523 * @return #GNUNET_YES if message is well-formed
7524 */
7525static int
7526check_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
7527{
7528 uint16_t size = ntohs (dvb->header.size);
7529 uint16_t num_hops = ntohs (dvb->num_hops);
7530 const struct GNUNET_PeerIdentity *hops =
7531 (const struct GNUNET_PeerIdentity *) &dvb[1];
7532
7533 (void) cls;
7534 if (size < sizeof(*dvb) + num_hops * sizeof(struct GNUNET_PeerIdentity)
7535 + sizeof(struct GNUNET_MessageHeader))
7536 {
7537 GNUNET_break_op (0);
7538 return GNUNET_SYSERR;
7539 }
7540 /* This peer must not be on the path */
7541 for (unsigned int i = 0; i < num_hops; i++)
7542 if (0 == GNUNET_memcmp (&hops[i], &GST_my_identity))
7543 {
7544 GNUNET_break_op (0);
7545 return GNUNET_SYSERR;
7546 }
7547 return GNUNET_YES;
7548}
7549
7550
7551/**
7552 * Create a DV Box message and queue it for transmission to
7553 * @ea next_hop.
7554 *
7555 * @param next_hop peer to receive the message next
7556 * @param total_hops how many hops did the message take so far
7557 * @param num_hops length of the @a hops array
7558 * @param origin origin of the message
7559 * @param hops next peer(s) to the destination, including destination
7560 * @param payload payload of the box
7561 * @param payload_size number of bytes in @a payload
7562 */
7563static void
7564forward_dv_box (struct Neighbour *next_hop,
7565 struct TransportDVBoxMessage *hdr,
7566 uint16_t total_hops,
7567 uint16_t num_hops,
7568 const struct GNUNET_PeerIdentity *hops,
7569 const void *enc_payload,
7570 uint16_t enc_payload_size)
7571{
7572 struct VirtualLink *vl = next_hop->vl;
7573 struct PendingMessage *pm;
7574 size_t msg_size = sizeof(struct TransportDVBoxMessage)
7575 + num_hops * sizeof(struct GNUNET_PeerIdentity)
7576 + enc_payload_size;
7577 char *buf;
7578 char msg_buf[msg_size] GNUNET_ALIGN;
7579 struct GNUNET_PeerIdentity *dhops;
7580
7581 hdr->num_hops = htons (num_hops);
7582 hdr->total_hops = htons (total_hops);
7583 hdr->header.size = htons (msg_size);
7584 memcpy (msg_buf, hdr, sizeof(*hdr));
7585 dhops = (struct GNUNET_PeerIdentity *) &msg_buf[sizeof(struct
7586 TransportDVBoxMessage)];
7587 memcpy (dhops, hops, num_hops * sizeof(struct GNUNET_PeerIdentity));
7588 memcpy (&dhops[num_hops], enc_payload, enc_payload_size);
7589
7590 if (GNUNET_YES == ntohs (hdr->without_fc))
7591 {
7592 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7593 "Forwarding control message (payload size %u) in DV Box to next hop %s (%u/%u) \n",
7594 enc_payload_size,
7595 GNUNET_i2s (&next_hop->pid),
7596 (unsigned int) num_hops,
7597 (unsigned int) total_hops);
7598 route_via_neighbour (next_hop, (const struct
7599 GNUNET_MessageHeader *) msg_buf,
7600 RMO_ANYTHING_GOES);
7601 }
7602 else if (NULL != vl)
7603 {
7604 pm = GNUNET_malloc (sizeof(struct PendingMessage) + msg_size);
7605 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7606 "2 created pm %p storing vl %p \n",
7607 pm,
7608 vl);
7609 pm->pmt = PMT_DV_BOX;
7610 pm->vl = vl;
7611 pm->timeout = GNUNET_TIME_relative_to_absolute (DV_FORWARD_TIMEOUT);
7612 pm->logging_uuid = logging_uuid_gen++;
7613 pm->prefs = GNUNET_MQ_PRIO_BACKGROUND;
7614 pm->bytes_msg = msg_size;
7615 buf = (char *) &pm[1];
7616 memcpy (buf, msg_buf, msg_size);
7617 GNUNET_CONTAINER_MDLL_insert (vl,
7618 vl->pending_msg_head,
7619 vl->pending_msg_tail,
7620 pm);
7621 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7622 "Created pending message %llu for DV Box with next hop %s (%u/%u)\n",
7623 pm->logging_uuid,
7624 GNUNET_i2s (&next_hop->pid),
7625 (unsigned int) num_hops,
7626 (unsigned int) total_hops);
7627 check_vl_transmission (vl);
7628 }
7629 else
7630 {
7631 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7632 "The virtual link is not ready for forwarding a DV Box with payload.\n");
7633 // FIXME The DV Box was send before the validation response. Shall we send a validation request for DV paths?
7634 }
7635}
7636
7637
7638/**
7639 * Free data structures associated with @a b.
7640 *
7641 * @param b data structure to release
7642 */
7643static void
7644free_backtalker (struct Backtalker *b)
7645{
7646 if (NULL != b->get)
7647 {
7648 GNUNET_PEERSTORE_iterate_cancel (b->get);
7649 b->get = NULL;
7650 GNUNET_assert (NULL != b->cmc);
7651 finish_cmc_handling (b->cmc);
7652 b->cmc = NULL;
7653 }
7654 if (NULL != b->task)
7655 {
7656 GNUNET_SCHEDULER_cancel (b->task);
7657 b->task = NULL;
7658 }
7659 if (NULL != b->sc)
7660 {
7661 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7662 "store cancel\n");
7663 GNUNET_PEERSTORE_store_cancel (b->sc);
7664 b->sc = NULL;
7665 }
7666 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7667 "Removing backtalker for %s\n",
7668 GNUNET_i2s (&b->pid));
7669 GNUNET_assert (
7670 GNUNET_YES ==
7671 GNUNET_CONTAINER_multipeermap_remove (backtalkers, &b->pid, b));
7672 GNUNET_free (b);
7673}
7674
7675
7676/**
7677 * Callback to free backtalker records.
7678 *
7679 * @param cls NULL
7680 * @param pid unused
7681 * @param value a `struct Backtalker`
7682 * @return #GNUNET_OK (always)
7683 */
7684static int
7685free_backtalker_cb (void *cls,
7686 const struct GNUNET_PeerIdentity *pid,
7687 void *value)
7688{
7689 struct Backtalker *b = value;
7690
7691 (void) cls;
7692 (void) pid;
7693 free_backtalker (b);
7694 return GNUNET_OK;
7695}
7696
7697
7698/**
7699 * Function called when it is time to clean up a backtalker.
7700 *
7701 * @param cls a `struct Backtalker`
7702 */
7703static void
7704backtalker_timeout_cb (void *cls)
7705{
7706 struct Backtalker *b = cls;
7707
7708 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7709 "backtalker timeout.\n");
7710 b->task = NULL;
7711 if (0 != GNUNET_TIME_absolute_get_remaining (b->timeout).rel_value_us)
7712 {
7713 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
7714 return;
7715 }
7716 GNUNET_assert (NULL == b->sc);
7717 free_backtalker (b);
7718}
7719
7720
7721/**
7722 * Function called with the monotonic time of a backtalker
7723 * by PEERSTORE. Updates the time and continues processing.
7724 *
7725 * @param cls a `struct Backtalker`
7726 * @param record the information found, NULL for the last call
7727 * @param emsg error message
7728 */
7729static void
7730backtalker_monotime_cb (void *cls,
7731 const struct GNUNET_PEERSTORE_Record *record,
7732 const char *emsg)
7733{
7734 struct Backtalker *b = cls;
7735 struct GNUNET_TIME_AbsoluteNBO *mtbe;
7736 struct GNUNET_TIME_Absolute mt;
7737
7738 (void) emsg;
7739 if (NULL == record)
7740 {
7741 /* we're done with #backtalker_monotime_cb() invocations,
7742 continue normal processing */
7743 b->get = NULL;
7744 GNUNET_assert (NULL != b->cmc);
7745 if (0 != b->body_size)
7746 demultiplex_with_cmc (b->cmc,
7747 (const struct GNUNET_MessageHeader *) &b[1]);
7748 else
7749 finish_cmc_handling (b->cmc);
7750 b->cmc = NULL;
7751 return;
7752 }
7753 if (sizeof(*mtbe) != record->value_size)
7754 {
7755 GNUNET_break (0);
7756 return;
7757 }
7758 mtbe = record->value;
7759 mt = GNUNET_TIME_absolute_ntoh (*mtbe);
7760 if (mt.abs_value_us > b->monotonic_time.abs_value_us)
7761 {
7762 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7763 "Backtalker message from %s dropped, monotime in the past\n",
7764 GNUNET_i2s (&b->pid));
7765 GNUNET_STATISTICS_update (
7766 GST_stats,
7767 "# Backchannel messages dropped: monotonic time not increasing",
7768 1,
7769 GNUNET_NO);
7770 b->monotonic_time = mt;
7771 /* Setting body_size to 0 prevents call to #forward_backchannel_payload()
7772 */
7773 b->body_size = 0;
7774 return;
7775 }
7776}
7777
7778
7779/**
7780 * Function called by PEERSTORE when the store operation of
7781 * a backtalker's monotonic time is complete.
7782 *
7783 * @param cls the `struct Backtalker`
7784 * @param success #GNUNET_OK on success
7785 */
7786static void
7787backtalker_monotime_store_cb (void *cls, int success)
7788{
7789 struct Backtalker *b = cls;
7790
7791 if (GNUNET_OK != success)
7792 {
7793 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
7794 "Failed to store backtalker's monotonic time in PEERSTORE!\n");
7795 }
7796 b->sc = NULL;
7797 if (NULL != b->task)
7798 {
7799 GNUNET_SCHEDULER_cancel (b->task);
7800 b->task = NULL;
7801 }
7802 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
7803}
7804
7805
7806/**
7807 * The backtalker @a b monotonic time changed. Update PEERSTORE.
7808 *
7809 * @param b a backtalker with updated monotonic time
7810 */
7811static void
7812update_backtalker_monotime (struct Backtalker *b)
7813{
7814 struct GNUNET_TIME_AbsoluteNBO mtbe;
7815
7816 if (NULL != b->sc)
7817 {
7818 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7819 "store cancel before store with sc %p\n",
7820 b->sc);
7821 /*GNUNET_PEERSTORE_store_cancel (b->sc);
7822 b->sc = NULL;*/
7823 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7824 "store cancel before store with sc %p is null\n",
7825 b->sc);
7826 }
7827 else
7828 {
7829 GNUNET_SCHEDULER_cancel (b->task);
7830 b->task = NULL;
7831 }
7832 mtbe = GNUNET_TIME_absolute_hton (b->monotonic_time);
7833 b->sc =
7834 GNUNET_PEERSTORE_store (peerstore,
7835 "transport",
7836 &b->pid,
7837 GNUNET_PEERSTORE_TRANSPORT_BACKCHANNEL_MONOTIME,
7838 &mtbe,
7839 sizeof(mtbe),
7840 GNUNET_TIME_UNIT_FOREVER_ABS,
7841 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
7842 &backtalker_monotime_store_cb,
7843 b);
7844}
7845
7846
7847/**
7848 * Communicator gave us a DV box. Process the request.
7849 *
7850 * @param cls a `struct CommunicatorMessageContext` (must call
7851 * #finish_cmc_handling() when done)
7852 * @param dvb the message that was received
7853 */
7854static void
7855handle_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
7856{
7857 struct CommunicatorMessageContext *cmc = cls;
7858 uint16_t size = ntohs (dvb->header.size) - sizeof(*dvb);
7859 uint16_t num_hops = ntohs (dvb->num_hops);
7860 const struct GNUNET_PeerIdentity *hops =
7861 (const struct GNUNET_PeerIdentity *) &dvb[1];
7862 const char *enc_payload = (const char *) &hops[num_hops];
7863 uint16_t enc_payload_size =
7864 size - (num_hops * sizeof(struct GNUNET_PeerIdentity));
7865 char enc[enc_payload_size];
7866 struct DVKeyState *key;
7867 struct GNUNET_HashCode hmac;
7868 const char *hdr;
7869 size_t hdr_len;
7870
7871 key = GNUNET_new (struct DVKeyState);
7872
7873 if (GNUNET_EXTRA_LOGGING > 0)
7874 {
7875 char *path;
7876
7877 path = GNUNET_strdup (GNUNET_i2s (&GST_my_identity));
7878 for (unsigned int i = 0; i < num_hops; i++)
7879 {
7880 char *tmp;
7881
7882 GNUNET_asprintf (&tmp, "%s->%s", path, GNUNET_i2s (&hops[i]));
7883 GNUNET_free (path);
7884 path = tmp;
7885 }
7886 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7887 "Received DVBox with remaining path %s\n",
7888 path);
7889 GNUNET_free (path);
7890 }
7891
7892 if (num_hops > 0)
7893 {
7894 /* We're trying from the end of the hops array, as we may be
7895 able to find a shortcut unknown to the origin that way */
7896 for (int i = num_hops - 1; i >= 0; i--)
7897 {
7898 struct Neighbour *n;
7899
7900 if (0 == GNUNET_memcmp (&hops[i], &GST_my_identity))
7901 {
7902 GNUNET_break_op (0);
7903 finish_cmc_handling (cmc);
7904 return;
7905 }
7906 n = lookup_neighbour (&hops[i]);
7907 if (NULL == n)
7908 continue;
7909 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7910 "Skipping %u/%u hops ahead while routing DV Box\n",
7911 i,
7912 num_hops);
7913
7914 forward_dv_box (n,
7915 (struct TransportDVBoxMessage *) dvb,
7916 ntohs (dvb->total_hops) + 1,
7917 num_hops - i - 1, /* number of hops left */
7918 &hops[i + 1], /* remaining hops */
7919 enc_payload,
7920 enc_payload_size);
7921 GNUNET_STATISTICS_update (GST_stats,
7922 "# DV hops skipped routing boxes",
7923 i,
7924 GNUNET_NO);
7925 GNUNET_STATISTICS_update (GST_stats,
7926 "# DV boxes routed (total)",
7927 1,
7928 GNUNET_NO);
7929 finish_cmc_handling (cmc);
7930 return;
7931 }
7932 /* Woopsie, next hop not in neighbours, drop! */
7933 GNUNET_STATISTICS_update (GST_stats,
7934 "# DV Boxes dropped: next hop unknown",
7935 1,
7936 GNUNET_NO);
7937 finish_cmc_handling (cmc);
7938 return;
7939 }
7940 /* We are the target. Unbox and handle message. */
7941 GNUNET_STATISTICS_update (GST_stats,
7942 "# DV boxes opened (ultimate target)",
7943 1,
7944 GNUNET_NO);
7945 cmc->total_hops = ntohs (dvb->total_hops);
7946
7947 dh_key_derive_eph_pub (&dvb->ephemeral_key, &dvb->iv, key);
7948 hdr = (const char *) &dvb[1];
7949 hdr_len = ntohs (dvb->orig_size) - sizeof(*dvb) - sizeof(struct
7950 GNUNET_PeerIdentity)
7951 * ntohs (dvb->total_hops);
7952
7953 dv_hmac (key, &hmac, hdr, hdr_len);
7954 if (0 != GNUNET_memcmp (&hmac, &dvb->hmac))
7955 {
7956 /* HMAC mismatch, discard! */
7957 GNUNET_break_op (0);
7958 finish_cmc_handling (cmc);
7959 return;
7960 }
7961 /* begin actual decryption */
7962 {
7963 struct Backtalker *b;
7964 struct GNUNET_TIME_Absolute monotime;
7965 struct TransportDVBoxPayloadP ppay;
7966 char body[hdr_len - sizeof(ppay)] GNUNET_ALIGN;
7967 const struct GNUNET_MessageHeader *mh =
7968 (const struct GNUNET_MessageHeader *) body;
7969
7970 GNUNET_assert (hdr_len >=
7971 sizeof(ppay) + sizeof(struct GNUNET_MessageHeader));
7972 dv_decrypt (key, &ppay, hdr, sizeof(ppay));
7973 dv_decrypt (key, &body, &hdr[sizeof(ppay)], hdr_len - sizeof(ppay));
7974 dv_key_clean (key);
7975 if (ntohs (mh->size) != sizeof(body))
7976 {
7977 GNUNET_break_op (0);
7978 finish_cmc_handling (cmc);
7979 return;
7980 }
7981 /* need to prevent box-in-a-box (and DV_LEARN) so check inbox type! */
7982 switch (ntohs (mh->type))
7983 {
7984 case GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX:
7985 GNUNET_break_op (0);
7986 finish_cmc_handling (cmc);
7987 return;
7988
7989 case GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN:
7990 GNUNET_break_op (0);
7991 finish_cmc_handling (cmc);
7992 return;
7993
7994 default:
7995 /* permitted, continue */
7996 break;
7997 }
7998 monotime = GNUNET_TIME_absolute_ntoh (ppay.monotonic_time);
7999 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8000 "Decrypted backtalk from %s\n",
8001 GNUNET_i2s (&ppay.sender));
8002 b = GNUNET_CONTAINER_multipeermap_get (backtalkers, &ppay.sender);
8003 if ((NULL != b) && (monotime.abs_value_us < b->monotonic_time.abs_value_us))
8004 {
8005 GNUNET_STATISTICS_update (
8006 GST_stats,
8007 "# Backchannel messages dropped: monotonic time not increasing",
8008 1,
8009 GNUNET_NO);
8010 finish_cmc_handling (cmc);
8011 return;
8012 }
8013 if ((NULL == b) ||
8014 (0 != GNUNET_memcmp (&b->last_ephemeral, &dvb->ephemeral_key)))
8015 {
8016 /* Check signature */
8017 struct EphemeralConfirmationPS ec;
8018
8019 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
8020 ec.target = GST_my_identity;
8021 ec.ephemeral_key = dvb->ephemeral_key;
8022 ec.purpose.size = htonl (sizeof(ec));
8023 ec.sender_monotonic_time = ppay.monotonic_time;
8024 if (
8025 GNUNET_OK !=
8026 GNUNET_CRYPTO_eddsa_verify (
8027 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL,
8028 &ec,
8029 &ppay.sender_sig,
8030 &ppay.sender.public_key))
8031 {
8032 /* Signature invalid, discard! */
8033 GNUNET_break_op (0);
8034 finish_cmc_handling (cmc);
8035 return;
8036 }
8037 }
8038 /* Update sender, we now know the real origin! */
8039 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8040 "DVBox received for me from %s via %s\n",
8041 GNUNET_i2s2 (&ppay.sender),
8042 GNUNET_i2s (&cmc->im.sender));
8043 cmc->im.sender = ppay.sender;
8044
8045 if (NULL != b)
8046 {
8047 /* update key cache and mono time */
8048 b->last_ephemeral = dvb->ephemeral_key;
8049 b->monotonic_time = monotime;
8050 update_backtalker_monotime (b);
8051 b->timeout =
8052 GNUNET_TIME_relative_to_absolute (BACKCHANNEL_INACTIVITY_TIMEOUT);
8053
8054 demultiplex_with_cmc (cmc, mh);
8055 return;
8056 }
8057 /* setup data structure to cache signature AND check
8058 monotonic time with PEERSTORE before forwarding backchannel payload */
8059 b = GNUNET_malloc (sizeof(struct Backtalker) + sizeof(body));
8060 b->pid = ppay.sender;
8061 b->body_size = sizeof(body);
8062 memcpy (&b[1], body, sizeof(body));
8063 GNUNET_assert (GNUNET_YES ==
8064 GNUNET_CONTAINER_multipeermap_put (
8065 backtalkers,
8066 &b->pid,
8067 b,
8068 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8069 b->monotonic_time = monotime; /* NOTE: to be checked still! */
8070 b->cmc = cmc;
8071 b->timeout =
8072 GNUNET_TIME_relative_to_absolute (BACKCHANNEL_INACTIVITY_TIMEOUT);
8073 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
8074 b->get =
8075 GNUNET_PEERSTORE_iterate (peerstore,
8076 "transport",
8077 &b->pid,
8078 GNUNET_PEERSTORE_TRANSPORT_BACKCHANNEL_MONOTIME,
8079 &backtalker_monotime_cb,
8080 b);
8081 } /* end actual decryption */
8082}
8083
8084
8085/**
8086 * Client notified us about transmission from a peer. Process the request.
8087 *
8088 * @param cls a `struct TransportClient` which sent us the message
8089 * @param obm the send message that was sent
8090 * @return #GNUNET_YES if message is well-formed
8091 */
8092static int
8093check_incoming_msg (void *cls,
8094 const struct GNUNET_TRANSPORT_IncomingMessage *im)
8095{
8096 struct TransportClient *tc = cls;
8097
8098 if (CT_COMMUNICATOR != tc->type)
8099 {
8100 GNUNET_break (0);
8101 return GNUNET_SYSERR;
8102 }
8103 GNUNET_MQ_check_boxed_message (im);
8104 return GNUNET_OK;
8105}
8106
8107
8108/**
8109 * Closure for #check_known_address.
8110 */
8111struct CheckKnownAddressContext
8112{
8113 /**
8114 * Set to the address we are looking for.
8115 */
8116 const char *address;
8117
8118 /**
8119 * Set to a matching validation state, if one was found.
8120 */
8121 struct ValidationState *vs;
8122};
8123
8124
8125/**
8126 * Test if the validation state in @a value matches the
8127 * address from @a cls.
8128 *
8129 * @param cls a `struct CheckKnownAddressContext`
8130 * @param pid unused (must match though)
8131 * @param value a `struct ValidationState`
8132 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
8133 */
8134static int
8135check_known_address (void *cls,
8136 const struct GNUNET_PeerIdentity *pid,
8137 void *value)
8138{
8139 struct CheckKnownAddressContext *ckac = cls;
8140 struct ValidationState *vs = value;
8141
8142 (void) pid;
8143 if (0 != strcmp (vs->address, ckac->address))
8144 return GNUNET_OK;
8145 ckac->vs = vs;
8146 return GNUNET_NO;
8147}
8148
8149
8150/**
8151 * Task run periodically to validate some address based on #validation_heap.
8152 *
8153 * @param cls NULL
8154 */
8155static void
8156validation_start_cb (void *cls);
8157
8158
8159/**
8160 * Set the time for next_challenge of @a vs to @a new_time.
8161 * Updates the heap and if necessary reschedules the job.
8162 *
8163 * @param vs validation state to update
8164 * @param new_time new time for revalidation
8165 */
8166static void
8167update_next_challenge_time (struct ValidationState *vs,
8168 struct GNUNET_TIME_Absolute new_time)
8169{
8170 struct GNUNET_TIME_Relative delta;
8171
8172 if (new_time.abs_value_us == vs->next_challenge.abs_value_us)
8173 return; /* be lazy */
8174 vs->next_challenge = new_time;
8175 if (NULL == vs->hn)
8176 vs->hn =
8177 GNUNET_CONTAINER_heap_insert (validation_heap, vs, new_time.abs_value_us);
8178 else
8179 GNUNET_CONTAINER_heap_update_cost (vs->hn, new_time.abs_value_us);
8180 if ((vs != GNUNET_CONTAINER_heap_peek (validation_heap)) &&
8181 (NULL != validation_task))
8182 return;
8183 if (NULL != validation_task)
8184 GNUNET_SCHEDULER_cancel (validation_task);
8185 /* randomize a bit */
8186 delta.rel_value_us =
8187 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
8188 MIN_DELAY_ADDRESS_VALIDATION.rel_value_us);
8189 new_time = GNUNET_TIME_absolute_add (new_time, delta);
8190 validation_task =
8191 GNUNET_SCHEDULER_add_at (new_time, &validation_start_cb, NULL);
8192}
8193
8194
8195/**
8196 * Start address validation.
8197 *
8198 * @param pid peer the @a address is for
8199 * @param address an address to reach @a pid (presumably)
8200 */
8201static void
8202start_address_validation (const struct GNUNET_PeerIdentity *pid,
8203 const char *address)
8204{
8205 struct GNUNET_TIME_Absolute now;
8206 struct ValidationState *vs;
8207 struct CheckKnownAddressContext ckac = { .address = address, .vs = NULL };
8208
8209 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
8210 pid,
8211 &check_known_address,
8212 &ckac);
8213 if (NULL != (vs = ckac.vs))
8214 {
8215 /* if 'vs' is not currently valid, we need to speed up retrying the
8216 * validation */
8217 if (vs->validated_until.abs_value_us < vs->next_challenge.abs_value_us)
8218 {
8219 /* reduce backoff as we got a fresh advertisement */
8220 vs->challenge_backoff =
8221 GNUNET_TIME_relative_min (FAST_VALIDATION_CHALLENGE_FREQ,
8222 GNUNET_TIME_relative_divide (
8223 vs->challenge_backoff,
8224 2));
8225 update_next_challenge_time (vs,
8226 GNUNET_TIME_relative_to_absolute (
8227 vs->challenge_backoff));
8228 }
8229 return;
8230 }
8231 now = GNUNET_TIME_absolute_get ();
8232 vs = GNUNET_new (struct ValidationState);
8233 vs->pid = *pid;
8234 vs->valid_until =
8235 GNUNET_TIME_relative_to_absolute (ADDRESS_VALIDATION_LIFETIME);
8236 vs->first_challenge_use = now;
8237 vs->validation_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
8238 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
8239 &vs->challenge,
8240 sizeof(vs->challenge));
8241 vs->address = GNUNET_strdup (address);
8242 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8243 "Starting address validation `%s' of peer %s using challenge %s\n",
8244 address,
8245 GNUNET_i2s (pid),
8246 GNUNET_sh2s (&vs->challenge.value));
8247 GNUNET_assert (GNUNET_YES ==
8248 GNUNET_CONTAINER_multipeermap_put (
8249 validation_map,
8250 &vs->pid,
8251 vs,
8252 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
8253 update_next_challenge_time (vs, now);
8254}
8255
8256
8257/**
8258 * Function called by PEERSTORE for each matching record.
8259 *
8260 * @param cls closure, a `struct IncomingRequest`
8261 * @param record peerstore record information
8262 * @param emsg error message, or NULL if no errors
8263 */
8264static void
8265handle_hello_for_incoming (void *cls,
8266 const struct GNUNET_PEERSTORE_Record *record,
8267 const char *emsg)
8268{
8269 struct IncomingRequest *ir = cls;
8270 const char *val;
8271
8272 if (NULL != emsg)
8273 {
8274 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
8275 "Got failure from PEERSTORE: %s\n",
8276 emsg);
8277 return;
8278 }
8279 val = record->value;
8280 if ((0 == record->value_size) || ('\0' != val[record->value_size - 1]))
8281 {
8282 GNUNET_break (0);
8283 return;
8284 }
8285 start_address_validation (&ir->pid, (const char *) record->value);
8286}
8287
8288
8289/**
8290 * Communicator gave us a transport address validation challenge. Process the
8291 * request.
8292 *
8293 * @param cls a `struct CommunicatorMessageContext` (must call
8294 * #finish_cmc_handling() when done)
8295 * @param tvc the message that was received
8296 */
8297static void
8298handle_validation_challenge (
8299 void *cls,
8300 const struct TransportValidationChallengeMessage *tvc)
8301{
8302 struct CommunicatorMessageContext *cmc = cls;
8303 struct TransportValidationResponseMessage tvr;
8304 struct VirtualLink *vl;
8305 struct GNUNET_TIME_RelativeNBO validity_duration;
8306 struct IncomingRequest *ir;
8307 struct Neighbour *n;
8308 struct GNUNET_PeerIdentity sender;
8309
8310 /* DV-routed messages are not allowed for validation challenges */
8311 if (cmc->total_hops > 0)
8312 {
8313 GNUNET_break_op (0);
8314 finish_cmc_handling (cmc);
8315 return;
8316 }
8317 validity_duration = cmc->im.expected_address_validity;
8318 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8319 "Received address validation challenge %s\n",
8320 GNUNET_sh2s (&tvc->challenge.value));
8321 /* If we have a virtual link, we use this mechanism to signal the
8322 size of the flow control window, and to allow the sender
8323 to ask for increases. If for us the virtual link is still down,
8324 we will always give a window size of zero. */
8325 tvr.header.type =
8326 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE);
8327 tvr.header.size = htons (sizeof(tvr));
8328 tvr.reserved = htonl (0);
8329 tvr.challenge = tvc->challenge;
8330 tvr.origin_time = tvc->sender_time;
8331 tvr.validity_duration = validity_duration;
8332 {
8333 /* create signature */
8334 struct TransportValidationPS tvp = {
8335 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
8336 .purpose.size = htonl (sizeof(tvp)),
8337 .validity_duration = validity_duration,
8338 .challenge = tvc->challenge
8339 };
8340
8341 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
8342 &tvp,
8343 &tvr.signature);
8344 }
8345 sender = cmc->im.sender;
8346 vl = lookup_virtual_link (&sender);
8347 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
8348 {
8349 // route_control_message_without_fc (&cmc->im.sender,
8350 route_control_message_without_fc (vl,
8351 &tvr.header,
8352 RMO_ANYTHING_GOES | RMO_REDUNDANT);
8353 }
8354 else
8355 {
8356 /* Use route via neighbour */
8357 n = lookup_neighbour (&sender);
8358 if (NULL != n)
8359 route_via_neighbour (n, &tvr.header,
8360 RMO_ANYTHING_GOES | RMO_REDUNDANT
8361 | RMO_UNCONFIRMED_ALLOWED);
8362 }
8363
8364 finish_cmc_handling (cmc);
8365 if (NULL != vl)
8366 return;
8367
8368 /* For us, the link is still down, but we need bi-directional
8369 connections (for flow-control and for this to be useful for
8370 CORE), so we must try to bring the link up! */
8371
8372 /* (1) Check existing queues, if any, we may be lucky! */
8373 n = lookup_neighbour (&sender);
8374 if (NULL != n)
8375 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
8376 start_address_validation (&sender, q->address);
8377 /* (2) Also try to see if we have addresses in PEERSTORE for this peer
8378 we could use */
8379 for (ir = ir_head; NULL != ir; ir = ir->next)
8380 if (0 == GNUNET_memcmp (&ir->pid, &sender))
8381 return;
8382 /* we are already trying */
8383 ir = GNUNET_new (struct IncomingRequest);
8384 ir->pid = sender;
8385 GNUNET_CONTAINER_DLL_insert (ir_head, ir_tail, ir);
8386 ir->wc = GNUNET_PEERSTORE_watch (peerstore,
8387 "transport",
8388 &ir->pid,
8389 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
8390 &handle_hello_for_incoming,
8391 ir);
8392 ir_total++;
8393 /* Bound attempts we do in parallel here, might otherwise get excessive */
8394 while (ir_total > MAX_INCOMING_REQUEST)
8395 free_incoming_request (ir_head);
8396}
8397
8398
8399/**
8400 * Closure for #check_known_challenge.
8401 */
8402struct CheckKnownChallengeContext
8403{
8404 /**
8405 * Set to the challenge we are looking for.
8406 */
8407 const struct GNUNET_CRYPTO_ChallengeNonceP *challenge;
8408
8409 /**
8410 * Set to a matching validation state, if one was found.
8411 */
8412 struct ValidationState *vs;
8413};
8414
8415
8416/**
8417 * Test if the validation state in @a value matches the
8418 * challenge from @a cls.
8419 *
8420 * @param cls a `struct CheckKnownChallengeContext`
8421 * @param pid unused (must match though)
8422 * @param value a `struct ValidationState`
8423 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
8424 */
8425static int
8426check_known_challenge (void *cls,
8427 const struct GNUNET_PeerIdentity *pid,
8428 void *value)
8429{
8430 struct CheckKnownChallengeContext *ckac = cls;
8431 struct ValidationState *vs = value;
8432
8433 (void) pid;
8434 if (0 != GNUNET_memcmp (&vs->challenge, ckac->challenge))
8435 return GNUNET_OK;
8436 ckac->vs = vs;
8437 return GNUNET_NO;
8438}
8439
8440
8441/**
8442 * Function called when peerstore is done storing a
8443 * validated address.
8444 *
8445 * @param cls a `struct ValidationState`
8446 * @param success #GNUNET_YES on success
8447 */
8448static void
8449peerstore_store_validation_cb (void *cls, int success)
8450{
8451 struct ValidationState *vs = cls;
8452
8453 vs->sc = NULL;
8454 if (GNUNET_YES == success)
8455 return;
8456 GNUNET_STATISTICS_update (GST_stats,
8457 "# Peerstore failed to store foreign address",
8458 1,
8459 GNUNET_NO);
8460}
8461
8462
8463/**
8464 * Find the queue matching @a pid and @a address.
8465 *
8466 * @param pid peer the queue must go to
8467 * @param address address the queue must use
8468 * @return NULL if no such queue exists
8469 */
8470static struct Queue *
8471find_queue (const struct GNUNET_PeerIdentity *pid, const char *address)
8472{
8473 struct Neighbour *n;
8474
8475 n = lookup_neighbour (pid);
8476 if (NULL == n)
8477 return NULL;
8478 for (struct Queue *pos = n->queue_head; NULL != pos;
8479 pos = pos->next_neighbour)
8480 {
8481 if (0 == strcmp (pos->address, address))
8482 return pos;
8483 }
8484 return NULL;
8485}
8486
8487
8488/**
8489 * Communicator gave us a transport address validation response. Process the
8490 * request.
8491 *
8492 * @param cls a `struct CommunicatorMessageContext` (must call
8493 * #finish_cmc_handling() when done)
8494 * @param tvr the message that was received
8495 */
8496static void
8497handle_validation_response (
8498 void *cls,
8499 const struct TransportValidationResponseMessage *tvr)
8500{
8501 struct CommunicatorMessageContext *cmc = cls;
8502 struct ValidationState *vs;
8503 struct CheckKnownChallengeContext ckac = { .challenge = &tvr->challenge,
8504 .vs = NULL };
8505 struct GNUNET_TIME_Absolute origin_time;
8506 struct Queue *q;
8507 struct Neighbour *n;
8508 struct VirtualLink *vl;
8509
8510 /* check this is one of our challenges */
8511 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
8512 &cmc->im.sender,
8513 &check_known_challenge,
8514 &ckac);
8515 if (NULL == (vs = ckac.vs))
8516 {
8517 /* This can happen simply if we 'forgot' the challenge by now,
8518 i.e. because we received the validation response twice */
8519 GNUNET_STATISTICS_update (GST_stats,
8520 "# Validations dropped, challenge unknown",
8521 1,
8522 GNUNET_NO);
8523 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8524 "Validation response %s dropped, challenge unknown\n",
8525 GNUNET_sh2s (&tvr->challenge.value));
8526 finish_cmc_handling (cmc);
8527 return;
8528 }
8529
8530 /* sanity check on origin time */
8531 origin_time = GNUNET_TIME_absolute_ntoh (tvr->origin_time);
8532 if ((origin_time.abs_value_us < vs->first_challenge_use.abs_value_us) ||
8533 (origin_time.abs_value_us > vs->last_challenge_use.abs_value_us))
8534 {
8535 GNUNET_break_op (0);
8536 finish_cmc_handling (cmc);
8537 return;
8538 }
8539
8540 {
8541 /* check signature */
8542 struct TransportValidationPS tvp = {
8543 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
8544 .purpose.size = htonl (sizeof(tvp)),
8545 .validity_duration = tvr->validity_duration,
8546 .challenge = tvr->challenge
8547 };
8548
8549 if (
8550 GNUNET_OK !=
8551 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE,
8552 &tvp,
8553 &tvr->signature,
8554 &cmc->im.sender.public_key))
8555 {
8556 GNUNET_break_op (0);
8557 finish_cmc_handling (cmc);
8558 return;
8559 }
8560 }
8561
8562 /* validity is capped by our willingness to keep track of the
8563 validation entry and the maximum the other peer allows */
8564 vs->valid_until = GNUNET_TIME_relative_to_absolute (
8565 GNUNET_TIME_relative_min (GNUNET_TIME_relative_ntoh (
8566 tvr->validity_duration),
8567 MAX_ADDRESS_VALID_UNTIL));
8568 vs->validated_until =
8569 GNUNET_TIME_absolute_min (vs->valid_until,
8570 GNUNET_TIME_relative_to_absolute (
8571 ADDRESS_VALIDATION_LIFETIME));
8572 vs->validation_rtt = GNUNET_TIME_absolute_get_duration (origin_time);
8573 vs->challenge_backoff = GNUNET_TIME_UNIT_ZERO;
8574 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
8575 &vs->challenge,
8576 sizeof(vs->challenge));
8577 vs->first_challenge_use = GNUNET_TIME_absolute_subtract (
8578 vs->validated_until,
8579 GNUNET_TIME_relative_multiply (vs->validation_rtt,
8580 VALIDATION_RTT_BUFFER_FACTOR));
8581 vs->last_challenge_use =
8582 GNUNET_TIME_UNIT_ZERO_ABS; /* challenge was not yet used */
8583 update_next_challenge_time (vs, vs->first_challenge_use);
8584 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8585 "Validation response %s accepted, address valid until %s\n",
8586 GNUNET_sh2s (&tvr->challenge.value),
8587 GNUNET_STRINGS_absolute_time_to_string (vs->valid_until));
8588 vs->sc = GNUNET_PEERSTORE_store (peerstore,
8589 "transport",
8590 &cmc->im.sender,
8591 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
8592 vs->address,
8593 strlen (vs->address) + 1,
8594 vs->valid_until,
8595 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
8596 &peerstore_store_validation_cb,
8597 vs);
8598 finish_cmc_handling (cmc);
8599
8600 /* Finally, we now possibly have a confirmed (!) working queue,
8601 update queue status (if queue still is around) */
8602 q = find_queue (&vs->pid, vs->address);
8603 if (NULL == q)
8604 {
8605 GNUNET_STATISTICS_update (GST_stats,
8606 "# Queues lost at time of successful validation",
8607 1,
8608 GNUNET_NO);
8609 return;
8610 }
8611 q->validated_until = vs->validated_until;
8612 q->pd.aged_rtt = vs->validation_rtt;
8613 n = q->neighbour;
8614 vl = lookup_virtual_link (&vs->pid);
8615 if (NULL == vl)
8616 {
8617 vl = GNUNET_new (struct VirtualLink);
8618 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8619 "Creating new virtual link %p to %s using direct neighbour!\n",
8620 vl,
8621 GNUNET_i2s (&vs->pid));
8622 vl->confirmed = GNUNET_YES;
8623 vl->message_uuid_ctr =
8624 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
8625 vl->target = n->pid;
8626 vl->core_recv_window = RECV_WINDOW_SIZE;
8627 vl->available_fc_window_size = DEFAULT_WINDOW_SIZE;
8628 vl->incoming_fc_window_size = DEFAULT_WINDOW_SIZE;
8629 GNUNET_break (GNUNET_YES ==
8630 GNUNET_CONTAINER_multipeermap_put (
8631 links,
8632 &vl->target,
8633 vl,
8634 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8635 vl->n = n;
8636 n->vl = vl;
8637 q->idle = GNUNET_YES;
8638 vl->visibility_task =
8639 GNUNET_SCHEDULER_add_at (q->validated_until, &check_link_down, vl);
8640 consider_sending_fc (vl);
8641 /* We lacked a confirmed connection to the target
8642 before, so tell CORE about it (finally!) */
8643 cores_send_connect_info (&n->pid);
8644 }
8645 else
8646 {
8647 /* Link was already up, remember n is also now available and we are done */
8648 if (NULL == vl->n)
8649 {
8650 vl->n = n;
8651 n->vl = vl;
8652 if (GNUNET_YES == vl->confirmed)
8653 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8654 "Virtual link to %s could now also direct neighbour!\n",
8655 GNUNET_i2s (&vs->pid));
8656 }
8657 else
8658 {
8659 GNUNET_assert (n == vl->n);
8660 }
8661 if (GNUNET_NO == vl->confirmed)
8662 {
8663 vl->confirmed = GNUNET_YES;
8664 q->idle = GNUNET_YES;
8665 vl->visibility_task =
8666 GNUNET_SCHEDULER_add_at (q->validated_until, &check_link_down, vl);
8667 consider_sending_fc (vl);
8668 /* We lacked a confirmed connection to the target
8669 before, so tell CORE about it (finally!) */
8670 cores_send_connect_info (&n->pid);
8671 }
8672 }
8673}
8674
8675
8676/**
8677 * Incoming meessage. Process the request.
8678 *
8679 * @param im the send message that was received
8680 */
8681static void
8682handle_incoming_msg (void *cls,
8683 const struct GNUNET_TRANSPORT_IncomingMessage *im)
8684{
8685 struct TransportClient *tc = cls;
8686 struct CommunicatorMessageContext *cmc =
8687 GNUNET_new (struct CommunicatorMessageContext);
8688
8689 cmc->tc = tc;
8690 cmc->im = *im;
8691 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8692 "Received message with size %u via communicator from peer %s\n",
8693 &im->header.size,
8694 GNUNET_i2s (&im->sender));
8695 demultiplex_with_cmc (cmc, (const struct GNUNET_MessageHeader *) &im[1]);
8696}
8697
8698
8699/**
8700 * Communicator gave us a transport address validation response. Process the
8701 * request.
8702 *
8703 * @param cls a `struct CommunicatorMessageContext` (must call
8704 * #finish_cmc_handling() when done)
8705 * @param fc the message that was received
8706 */
8707static void
8708handle_flow_control (void *cls, const struct TransportFlowControlMessage *fc)
8709{
8710 struct CommunicatorMessageContext *cmc = cls;
8711 struct VirtualLink *vl;
8712 uint32_t seq;
8713 struct GNUNET_TIME_Absolute st;
8714 uint64_t os;
8715 uint64_t wnd;
8716 uint32_t random;
8717
8718 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8719 "Received FC from %s\n", GNUNET_i2s (&cmc->im.sender));
8720 vl = lookup_virtual_link (&cmc->im.sender);
8721 if (NULL == vl)
8722 {
8723 vl = GNUNET_new (struct VirtualLink);
8724 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8725 "No virtual link for %p FC creating new unconfirmed virtual link to %s!\n",
8726 vl,
8727 GNUNET_i2s (&cmc->im.sender));
8728 vl->confirmed = GNUNET_NO;
8729 vl->message_uuid_ctr =
8730 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
8731 vl->target = cmc->im.sender;
8732 vl->core_recv_window = RECV_WINDOW_SIZE;
8733 vl->available_fc_window_size = DEFAULT_WINDOW_SIZE;
8734 vl->incoming_fc_window_size = DEFAULT_WINDOW_SIZE;
8735 GNUNET_break (GNUNET_YES ==
8736 GNUNET_CONTAINER_multipeermap_put (
8737 links,
8738 &vl->target,
8739 vl,
8740 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8741 }
8742 st = GNUNET_TIME_absolute_ntoh (fc->sender_time);
8743 if (st.abs_value_us < vl->last_fc_timestamp.abs_value_us)
8744 {
8745 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8746 "FC dropped: Message out of order\n");
8747 /* out of order, drop */
8748 GNUNET_STATISTICS_update (GST_stats,
8749 "# FC dropped: message out of order",
8750 1,
8751 GNUNET_NO);
8752 finish_cmc_handling (cmc);
8753 return;
8754 }
8755 seq = ntohl (fc->seq);
8756 if (seq < vl->last_fc_seq)
8757 {
8758 /* Wrap-around/reset of other peer; start all counters from zero */
8759 vl->outbound_fc_window_size_used = 0;
8760 }
8761 vl->last_fc_seq = seq;
8762 vl->last_fc_timestamp = st;
8763 vl->outbound_fc_window_size = GNUNET_ntohll (fc->inbound_window_size);
8764 os = GNUNET_ntohll (fc->outbound_sent);
8765 vl->incoming_fc_window_size_loss =
8766 (int64_t) (os - vl->incoming_fc_window_size_used);
8767 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8768 "Received FC from %s, seq %u, new window %llu (loss at %lld)\n",
8769 GNUNET_i2s (&vl->target),
8770 (unsigned int) seq,
8771 (unsigned long long) vl->outbound_fc_window_size,
8772 (long long) vl->incoming_fc_window_size_loss);
8773 wnd = GNUNET_ntohll (fc->outbound_window_size);
8774 random = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
8775 UINT32_MAX);
8776 if ((GNUNET_YES == vl->confirmed) && ((wnd < vl->incoming_fc_window_size) ||
8777 (vl->last_outbound_window_size_received
8778 != wnd) ||
8779 (0 == random
8780 % FC_NO_CHANGE_REPLY_PROBABILITY)))
8781 {
8782 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8783 "Consider re-sending our FC message, as clearly the other peer's idea of the window is not up-to-date (%llu vs %llu) or %llu last received differs, or random reply %lu\n",
8784 (unsigned long long) wnd,
8785 (unsigned long long) vl->incoming_fc_window_size,
8786 (unsigned long long) vl->last_outbound_window_size_received,
8787 random % FC_NO_CHANGE_REPLY_PROBABILITY);
8788 consider_sending_fc (vl);
8789 }
8790 if ((wnd == vl->incoming_fc_window_size) &&
8791 (vl->last_outbound_window_size_received == wnd) &&
8792 (NULL != vl->fc_retransmit_task))
8793 {
8794 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8795 "Stopping FC retransmission to %s: peer is current at window %llu\n",
8796 GNUNET_i2s (&vl->target),
8797 (unsigned long long) wnd);
8798 GNUNET_SCHEDULER_cancel (vl->fc_retransmit_task);
8799 vl->fc_retransmit_task = NULL;
8800 vl->fc_retransmit_count = 0;
8801 }
8802 vl->last_outbound_window_size_received = wnd;
8803 /* FC window likely increased, check transmission possibilities! */
8804 check_vl_transmission (vl);
8805 finish_cmc_handling (cmc);
8806}
8807
8808
8809/**
8810 * Given an inbound message @a msg from a communicator @a cmc,
8811 * demultiplex it based on the type calling the right handler.
8812 *
8813 * @param cmc context for demultiplexing
8814 * @param msg message to demultiplex
8815 */
8816static void
8817demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
8818 const struct GNUNET_MessageHeader *msg)
8819{
8820 struct GNUNET_MQ_MessageHandler handlers[] =
8821 { GNUNET_MQ_hd_var_size (fragment_box,
8822 GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT,
8823 struct TransportFragmentBoxMessage,
8824 cmc),
8825 GNUNET_MQ_hd_var_size (reliability_box,
8826 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX,
8827 struct TransportReliabilityBoxMessage,
8828 cmc),
8829 GNUNET_MQ_hd_var_size (reliability_ack,
8830 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK,
8831 struct TransportReliabilityAckMessage,
8832 cmc),
8833 GNUNET_MQ_hd_var_size (backchannel_encapsulation,
8834 GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION,
8835 struct TransportBackchannelEncapsulationMessage,
8836 cmc),
8837 GNUNET_MQ_hd_var_size (dv_learn,
8838 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN,
8839 struct TransportDVLearnMessage,
8840 cmc),
8841 GNUNET_MQ_hd_var_size (dv_box,
8842 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX,
8843 struct TransportDVBoxMessage,
8844 cmc),
8845 GNUNET_MQ_hd_fixed_size (
8846 validation_challenge,
8847 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE,
8848 struct TransportValidationChallengeMessage,
8849 cmc),
8850 GNUNET_MQ_hd_fixed_size (flow_control,
8851 GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL,
8852 struct TransportFlowControlMessage,
8853 cmc),
8854 GNUNET_MQ_hd_fixed_size (
8855 validation_response,
8856 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE,
8857 struct TransportValidationResponseMessage,
8858 cmc),
8859 GNUNET_MQ_handler_end () };
8860 int ret;
8861
8862 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8863 "Handling message of type %u with %u bytes\n",
8864 (unsigned int) ntohs (msg->type),
8865 (unsigned int) ntohs (msg->size));
8866 ret = GNUNET_MQ_handle_message (handlers, msg);
8867 if (GNUNET_SYSERR == ret)
8868 {
8869 GNUNET_break (0);
8870 GNUNET_SERVICE_client_drop (cmc->tc->client);
8871 GNUNET_free (cmc);
8872 return;
8873 }
8874 if (GNUNET_NO == ret)
8875 {
8876 /* unencapsulated 'raw' message */
8877 handle_raw_message (cmc, msg);
8878 }
8879}
8880
8881
8882/**
8883 * New queue became available. Check message.
8884 *
8885 * @param cls the client
8886 * @param aqm the send message that was sent
8887 */
8888static int
8889check_add_queue_message (void *cls,
8890 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
8891{
8892 struct TransportClient *tc = cls;
8893
8894 if (CT_COMMUNICATOR != tc->type)
8895 {
8896 GNUNET_break (0);
8897 return GNUNET_SYSERR;
8898 }
8899 GNUNET_MQ_check_zero_termination (aqm);
8900 return GNUNET_OK;
8901}
8902
8903
8904/**
8905 * If necessary, generates the UUID for a @a pm
8906 *
8907 * @param pm pending message to generate UUID for.
8908 */
8909static void
8910set_pending_message_uuid (struct PendingMessage *pm)
8911{
8912 if (pm->msg_uuid_set)
8913 return;
8914 pm->msg_uuid.uuid = pm->vl->message_uuid_ctr++;
8915 pm->msg_uuid_set = GNUNET_YES;
8916}
8917
8918
8919/**
8920 * Setup data structure waiting for acknowledgements.
8921 *
8922 * @param queue queue the @a pm will be sent over
8923 * @param dvh path the message will take, may be NULL
8924 * @param pm the pending message for transmission
8925 * @return corresponding fresh pending acknowledgement
8926 */
8927static struct PendingAcknowledgement *
8928prepare_pending_acknowledgement (struct Queue *queue,
8929 struct DistanceVectorHop *dvh,
8930 struct PendingMessage *pm)
8931{
8932 struct PendingAcknowledgement *pa;
8933
8934 pa = GNUNET_new (struct PendingAcknowledgement);
8935 pa->queue = queue;
8936 pa->dvh = dvh;
8937 pa->pm = pm;
8938 do
8939 {
8940 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
8941 &pa->ack_uuid,
8942 sizeof(pa->ack_uuid));
8943 }
8944 while (GNUNET_YES != GNUNET_CONTAINER_multiuuidmap_put (
8945 pending_acks,
8946 &pa->ack_uuid.value,
8947 pa,
8948 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8949 GNUNET_CONTAINER_MDLL_insert (queue, queue->pa_head, queue->pa_tail, pa);
8950 GNUNET_CONTAINER_MDLL_insert (pm, pm->pa_head, pm->pa_tail, pa);
8951 if (NULL != dvh)
8952 GNUNET_CONTAINER_MDLL_insert (dvh, dvh->pa_head, dvh->pa_tail, pa);
8953 pa->transmission_time = GNUNET_TIME_absolute_get ();
8954 pa->message_size = pm->bytes_msg;
8955 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8956 "Waiting for ACKnowledgment `%s' for <%llu>\n",
8957 GNUNET_uuid2s (&pa->ack_uuid.value),
8958 pm->logging_uuid);
8959 return pa;
8960}
8961
8962
8963/**
8964 * Fragment the given @a pm to the given @a mtu. Adds
8965 * additional fragments to the neighbour as well. If the
8966 * @a mtu is too small, generates and error for the @a pm
8967 * and returns NULL.
8968 *
8969 * @param queue which queue to fragment for
8970 * @param dvh path the message will take, or NULL
8971 * @param pm pending message to fragment for transmission
8972 * @return new message to transmit
8973 */
8974static struct PendingMessage *
8975fragment_message (struct Queue *queue,
8976 struct DistanceVectorHop *dvh,
8977 struct PendingMessage *pm)
8978{
8979 struct PendingAcknowledgement *pa;
8980 struct PendingMessage *ff;
8981 uint16_t mtu;
8982
8983 mtu = (UINT16_MAX == queue->mtu)
8984 ? UINT16_MAX - sizeof(struct GNUNET_TRANSPORT_SendMessageTo)
8985 : queue->mtu;
8986 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8987 "Fragmenting message <%llu> with size %u to %s for MTU %u\n",
8988 pm->logging_uuid,
8989 pm->bytes_msg,
8990 GNUNET_i2s (&pm->vl->target),
8991 (unsigned int) mtu);
8992 set_pending_message_uuid (pm);
8993 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8994 "Fragmenting message %llu <%llu> with size %u to %s for MTU %u\n",
8995 (unsigned long long) pm->msg_uuid.uuid,
8996 pm->logging_uuid,
8997 pm->bytes_msg,
8998 GNUNET_i2s (&pm->vl->target),
8999 (unsigned int) mtu);
9000
9001 /* This invariant is established in #handle_add_queue_message() */
9002 GNUNET_assert (mtu > sizeof(struct TransportFragmentBoxMessage));
9003
9004 /* select fragment for transmission, descending the tree if it has
9005 been expanded until we are at a leaf or at a fragment that is small
9006 enough
9007 */
9008 ff = pm;
9009 while (((ff->bytes_msg > mtu) || (pm == ff)) &&
9010 (ff->frag_off == ff->bytes_msg) && (NULL != ff->head_frag))
9011 {
9012 ff = ff->head_frag; /* descent into fragmented fragments */
9013 }
9014
9015 if (((ff->bytes_msg > mtu) || (pm == ff)) && (ff->frag_off < ff->bytes_msg))
9016 {
9017 /* Did not yet calculate all fragments, calculate next fragment */
9018 struct PendingMessage *frag;
9019 struct TransportFragmentBoxMessage tfb;
9020 const char *orig;
9021 char *msg;
9022 uint16_t fragmax;
9023 uint16_t fragsize;
9024 uint16_t msize;
9025 uint16_t xoff = 0;
9026
9027 orig = (const char *) &ff[1];
9028 msize = ff->bytes_msg;
9029 if (pm != ff)
9030 {
9031 const struct TransportFragmentBoxMessage *tfbo;
9032
9033 tfbo = (const struct TransportFragmentBoxMessage *) orig;
9034 orig += sizeof(struct TransportFragmentBoxMessage);
9035 msize -= sizeof(struct TransportFragmentBoxMessage);
9036 xoff = ntohs (tfbo->frag_off);
9037 }
9038 fragmax = mtu - sizeof(struct TransportFragmentBoxMessage);
9039 fragsize = GNUNET_MIN (msize - ff->frag_off, fragmax);
9040 frag =
9041 GNUNET_malloc (sizeof(struct PendingMessage)
9042 + sizeof(struct TransportFragmentBoxMessage) + fragsize);
9043 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9044 "3 created pm %p from pm %p storing vl %p from pm %p\n",
9045 frag,
9046 ff,
9047 pm->vl,
9048 pm);
9049 frag->logging_uuid = logging_uuid_gen++;
9050 frag->vl = pm->vl;
9051 frag->frag_parent = ff;
9052 frag->timeout = pm->timeout;
9053 frag->bytes_msg = sizeof(struct TransportFragmentBoxMessage) + fragsize;
9054 frag->pmt = PMT_FRAGMENT_BOX;
9055 msg = (char *) &frag[1];
9056 tfb.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT);
9057 tfb.header.size =
9058 htons (sizeof(struct TransportFragmentBoxMessage) + fragsize);
9059 pa = prepare_pending_acknowledgement (queue, dvh, frag);
9060 tfb.ack_uuid = pa->ack_uuid;
9061 tfb.msg_uuid = pm->msg_uuid;
9062 tfb.frag_off = htons (ff->frag_off + xoff);
9063 tfb.msg_size = htons (pm->bytes_msg);
9064 memcpy (msg, &tfb, sizeof(tfb));
9065 memcpy (&msg[sizeof(tfb)], &orig[ff->frag_off], fragsize);
9066 GNUNET_CONTAINER_MDLL_insert (frag, ff->head_frag,
9067 ff->tail_frag, frag);
9068 ff->frag_off += fragsize;
9069 ff = frag;
9070 }
9071
9072 /* Move head to the tail and return it */
9073 GNUNET_CONTAINER_MDLL_remove (frag,
9074 ff->frag_parent->head_frag,
9075 ff->frag_parent->tail_frag,
9076 ff);
9077 GNUNET_CONTAINER_MDLL_insert_tail (frag,
9078 ff->frag_parent->head_frag,
9079 ff->frag_parent->tail_frag,
9080 ff);
9081
9082 return ff;
9083}
9084
9085
9086/**
9087 * Reliability-box the given @a pm. On error (can there be any), NULL
9088 * may be returned, otherwise the "replacement" for @a pm (which
9089 * should then be added to the respective neighbour's queue instead of
9090 * @a pm). If the @a pm is already fragmented or reliability boxed,
9091 * or itself an ACK, this function simply returns @a pm.
9092 *
9093 * @param queue which queue to prepare transmission for
9094 * @param dvh path the message will take, or NULL
9095 * @param pm pending message to box for transmission over unreliabile queue
9096 * @return new message to transmit
9097 */
9098static struct PendingMessage *
9099reliability_box_message (struct Queue *queue,
9100 struct DistanceVectorHop *dvh,
9101 struct PendingMessage *pm)
9102{
9103 struct TransportReliabilityBoxMessage rbox;
9104 struct PendingAcknowledgement *pa;
9105 struct PendingMessage *bpm;
9106 char *msg;
9107
9108 if ((PMT_CORE != pm->pmt) && (PMT_DV_BOX != pm->pmt))
9109 return pm; /* already fragmented or reliability boxed, or control message:
9110 do nothing */
9111 if (NULL != pm->bpm)
9112 return pm->bpm; /* already computed earlier: do nothing */
9113 // TODO I guess we do not need this assertion. We might have a DLL with
9114 // fragments, because the MTU changed, and we do not need to fragment anymore.
9115 // But we should keep the fragments until message was completed, because
9116 // the MTU might change again.
9117 // GNUNET_assert (NULL == pm->head_frag);
9118 if (pm->bytes_msg + sizeof(rbox) > UINT16_MAX)
9119 {
9120 /* failed hard */
9121 GNUNET_break (0);
9122 client_send_response (pm);
9123 return NULL;
9124 }
9125
9126 pa = prepare_pending_acknowledgement (queue, dvh, pm);
9127
9128 bpm = GNUNET_malloc (sizeof(struct PendingMessage) + sizeof(rbox)
9129 + pm->bytes_msg);
9130 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9131 "4 created pm %p storing vl %p from pm %p\n",
9132 bpm,
9133 pm->vl,
9134 pm);
9135 bpm->logging_uuid = logging_uuid_gen++;
9136 bpm->vl = pm->vl;
9137 bpm->frag_parent = pm;
9138 // Why was this needed?
9139 // GNUNET_CONTAINER_MDLL_insert (frag, pm->head_frag, pm->tail_frag, bpm);
9140 bpm->timeout = pm->timeout;
9141 bpm->pmt = PMT_RELIABILITY_BOX;
9142 bpm->bytes_msg = pm->bytes_msg + sizeof(rbox);
9143 set_pending_message_uuid (bpm);
9144 rbox.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX);
9145 rbox.header.size = htons (sizeof(rbox) + pm->bytes_msg);
9146 rbox.ack_countdown = htonl (0); // FIXME: implement ACK countdown support
9147
9148 rbox.ack_uuid = pa->ack_uuid;
9149 msg = (char *) &bpm[1];
9150 memcpy (msg, &rbox, sizeof(rbox));
9151 memcpy (&msg[sizeof(rbox)], &pm[1], pm->bytes_msg);
9152 pm->bpm = bpm;
9153 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9154 "Preparing reliability box for message <%llu> of size %lu (%lu) to %s on queue %s\n",
9155 pm->logging_uuid,
9156 pm->bytes_msg,
9157 ntohs (((const struct GNUNET_MessageHeader *) &pm[1])->size),
9158 GNUNET_i2s (&pm->vl->target),
9159 queue->address);
9160 return bpm;
9161}
9162
9163
9164static void
9165reorder_root_pm (struct PendingMessage *pm,
9166 struct GNUNET_TIME_Absolute next_attempt)
9167{
9168 struct VirtualLink *vl = pm->vl;
9169 struct PendingMessage *pos;
9170
9171 /* re-insert sort in neighbour list */
9172 GNUNET_CONTAINER_MDLL_remove (vl,
9173 vl->pending_msg_head,
9174 vl->pending_msg_tail,
9175 pm);
9176 pos = vl->pending_msg_tail;
9177 while ((NULL != pos) &&
9178 (next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
9179 pos = pos->prev_vl;
9180 GNUNET_CONTAINER_MDLL_insert_after (vl,
9181 vl->pending_msg_head,
9182 vl->pending_msg_tail,
9183 pos,
9184 pm);
9185}
9186
9187
9188/**
9189 * Change the value of the `next_attempt` field of @a pm
9190 * to @a next_attempt and re-order @a pm in the transmission
9191 * list as required by the new timestamp.
9192 *
9193 * @param pm a pending message to update
9194 * @param next_attempt timestamp to use
9195 */
9196static void
9197update_pm_next_attempt (struct PendingMessage *pm,
9198 struct GNUNET_TIME_Absolute next_attempt)
9199{
9200 struct VirtualLink *vl = pm->vl;
9201
9202 // TODO Do we really need a next_attempt value for PendingMessage other than the root Pending Message?
9203 pm->next_attempt = next_attempt;
9204 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9205 "Next attempt for message <%llu> set to %s\n",
9206 pm->logging_uuid,
9207 GNUNET_STRINGS_absolute_time_to_string (next_attempt));
9208
9209 if (NULL == pm->frag_parent)
9210 {
9211 reorder_root_pm (pm, next_attempt);
9212 }
9213 else if ((PMT_RELIABILITY_BOX == pm->pmt) || (PMT_DV_BOX == pm->pmt))
9214 {
9215 struct PendingMessage *root = pm->frag_parent;
9216
9217 while (NULL != root->frag_parent)
9218 root = root->frag_parent;
9219 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9220 "Next attempt for root message <%llu> set to %s\n",
9221 root->logging_uuid);
9222 root->next_attempt = next_attempt;
9223 reorder_root_pm (root, next_attempt);
9224 }
9225 else
9226 {
9227 /* re-insert sort in fragment list */
9228 struct PendingMessage *fp = pm->frag_parent;
9229 struct PendingMessage *pos;
9230
9231 GNUNET_CONTAINER_MDLL_remove (frag, fp->head_frag, fp->tail_frag, pm);
9232 pos = fp->tail_frag;
9233 while ((NULL != pos) &&
9234 (next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
9235 pos = pos->prev_frag;
9236 GNUNET_CONTAINER_MDLL_insert_after (frag,
9237 fp->head_frag,
9238 fp->tail_frag,
9239 pos,
9240 pm);
9241 if (NULL == pos)
9242 {
9243 pos = fp;
9244 // Get the root pm
9245 while (NULL != pos->frag_parent)
9246 pos = pos->frag_parent;
9247 pos->next_attempt = next_attempt;
9248 reorder_root_pm (pos, next_attempt);
9249 }
9250 }
9251}
9252
9253
9254/**
9255 * Context for #select_best_pending_from_link().
9256 */
9257struct PendingMessageScoreContext
9258{
9259 /**
9260 * Set to the best message that was found, NULL for none.
9261 */
9262 struct PendingMessage *best;
9263
9264 /**
9265 * DVH that @e best should take, or NULL for direct transmission.
9266 */
9267 struct DistanceVectorHop *dvh;
9268
9269 /**
9270 * What is the estimated total overhead for this message?
9271 */
9272 size_t real_overhead;
9273
9274 /**
9275 * Number of pending messages we seriously considered this time.
9276 */
9277 unsigned int consideration_counter;
9278
9279 /**
9280 * Did we have to fragment?
9281 */
9282 int frag;
9283
9284 /**
9285 * Did we have to reliability box?
9286 */
9287 int relb;
9288
9289 /**
9290 * There are pending messages, but it was to early to send one of them.
9291 */
9292 int to_early;
9293
9294 /**
9295 * When will we try to transmit the message again for which it was to early to retry.
9296 */
9297 struct GNUNET_TIME_Relative to_early_retry_delay;
9298};
9299
9300
9301/**
9302 * Select the best pending message from @a vl for transmission
9303 * via @a queue.
9304 *
9305 * @param sc[in,out] best message so far (NULL for none), plus scoring data
9306 * @param queue the queue that will be used for transmission
9307 * @param vl the virtual link providing the messages
9308 * @param dvh path we are currently considering, or NULL for none
9309 * @param overhead number of bytes of overhead to be expected
9310 * from DV encapsulation (0 for without DV)
9311 */
9312static void
9313select_best_pending_from_link (struct PendingMessageScoreContext *sc,
9314 struct Queue *queue,
9315 struct VirtualLink *vl,
9316 struct DistanceVectorHop *dvh,
9317 size_t overhead)
9318{
9319 struct GNUNET_TIME_Absolute now;
9320
9321 now = GNUNET_TIME_absolute_get ();
9322 for (struct PendingMessage *pos = vl->pending_msg_head; NULL != pos;
9323 pos = pos->next_vl)
9324 {
9325 size_t real_overhead = overhead;
9326 int frag;
9327 int relb;
9328
9329 if ((NULL != dvh) && (PMT_DV_BOX == pos->pmt))
9330 {
9331 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9332 "DV messages must not be DV-routed to next hop!\n");
9333 continue; /* DV messages must not be DV-routed to next hop! */
9334 }
9335 if (pos->next_attempt.abs_value_us > now.abs_value_us)
9336 {
9337 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9338 "too early for all messages, they are sorted by next_attempt\n");
9339 sc->to_early = GNUNET_YES;
9340 sc->to_early_retry_delay = GNUNET_TIME_absolute_get_remaining (
9341 pos->next_attempt);
9342
9343 break; /* too early for all messages, they are sorted by next_attempt */
9344 }
9345 sc->to_early = GNUNET_NO;
9346 if (NULL != pos->qe)
9347 {
9348 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9349 "not eligible\n");
9350 continue; /* not eligible */
9351 }
9352 sc->consideration_counter++;
9353 /* determine if we have to fragment, if so add fragmentation
9354 overhead! */
9355 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9356 "check %u for sc->best\n",
9357 pos->logging_uuid);
9358 frag = GNUNET_NO;
9359 if (((0 != queue->mtu) &&
9360 (pos->bytes_msg + real_overhead > queue->mtu)) ||
9361 (pos->bytes_msg > UINT16_MAX - sizeof(struct
9362 GNUNET_TRANSPORT_SendMessageTo))
9363 ||
9364 (NULL != pos->head_frag /* fragments already exist, should
9365 respect that even if MTU is UINT16_MAX for
9366 this queue */))
9367 {
9368 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9369 "fragment msg with size %u, realoverhead is %u\n",
9370 pos->bytes_msg,
9371 real_overhead);
9372 frag = GNUNET_YES;
9373 if (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc)
9374 {
9375 /* FIXME-FRAG-REL-UUID: we could use an optimized, shorter fragmentation
9376 header without the ACK UUID when using a *reliable* channel! */
9377 }
9378 real_overhead = overhead + sizeof(struct TransportFragmentBoxMessage);
9379 }
9380 /* determine if we have to reliability-box, if so add reliability box
9381 overhead */
9382 relb = GNUNET_NO;
9383 if ((GNUNET_NO == frag) &&
9384 (0 == (pos->prefs & GNUNET_MQ_PREF_UNRELIABLE)) &&
9385 (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc))
9386 {
9387 real_overhead += sizeof(struct TransportReliabilityBoxMessage);
9388
9389 if ((0 != queue->mtu) && (pos->bytes_msg + real_overhead > queue->mtu))
9390 {
9391 frag = GNUNET_YES;
9392 real_overhead = overhead + sizeof(struct TransportFragmentBoxMessage);
9393 }
9394 else
9395 {
9396 relb = GNUNET_YES;
9397 }
9398 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9399 "Create reliability box of msg with size %u, realoverhead is %u %u %u %u\n",
9400 pos->bytes_msg,
9401 real_overhead,
9402 queue->mtu,
9403 frag,
9404 relb);
9405 }
9406
9407 /* Finally, compare to existing 'best' in sc to see if this 'pos' pending
9408 message would beat it! */
9409 if (NULL != sc->best)
9410 {
9411 /* CHECK if pos fits queue BETTER (=smaller) than pm, if not: continue;
9412 OPTIMIZE-ME: This is a heuristic, which so far has NOT been
9413 experimentally validated. There may be some huge potential for
9414 improvement here. Also, we right now only compare how well the
9415 given message fits _this_ queue, and do not consider how well other
9416 queues might suit the message. Taking other queues into consideration
9417 may further improve the result, but could also be expensive
9418 in terms of CPU time. */
9419 long long sc_score = sc->frag * 40 + sc->relb * 20 + sc->real_overhead;
9420 long long pm_score = frag * 40 + relb * 20 + real_overhead;
9421 long long time_delta =
9422 (sc->best->next_attempt.abs_value_us - pos->next_attempt.abs_value_us)
9423 / 1000LL;
9424
9425 /* "time_delta" considers which message has been 'ready' for transmission
9426 for longer, if a message has a preference for low latency, increase
9427 the weight of the time_delta by 10x if it is favorable for that message */
9428 if ((0 != (pos->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
9429 (0 != (sc->best->prefs & GNUNET_MQ_PREF_LOW_LATENCY)))
9430 time_delta *= 10; /* increase weight (always, both are low latency) */
9431 else if ((0 != (pos->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
9432 (time_delta > 0))
9433 time_delta *= 10; /* increase weight, favors 'pos', which is low latency */
9434 else if ((0 != (sc->best->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
9435 (time_delta < 0))
9436 time_delta *= 10; /* increase weight, favors 'sc->best', which is low latency */
9437 if (0 != queue->mtu)
9438 {
9439 /* Grant bonus if we are below MTU, larger bonus the closer we will
9440 be to the MTU */
9441 if (queue->mtu > sc->real_overhead + sc->best->bytes_msg)
9442 sc_score -= queue->mtu - (sc->real_overhead + sc->best->bytes_msg);
9443 if (queue->mtu > real_overhead + pos->bytes_msg)
9444 pm_score -= queue->mtu - (real_overhead + pos->bytes_msg);
9445 }
9446 if (sc_score + time_delta > pm_score)
9447 {
9448 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9449 "sc_score of %u larger, keep sc->best %u\n",
9450 pos->logging_uuid,
9451 sc->best->logging_uuid);
9452 continue; /* sc_score larger, keep sc->best */
9453 }
9454 }
9455 sc->best = pos;
9456 sc->dvh = dvh;
9457 sc->frag = frag;
9458 sc->relb = relb;
9459 sc->real_overhead = real_overhead;
9460 }
9461}
9462
9463
9464/**
9465 * Function to call to further operate on the now DV encapsulated
9466 * message @a hdr, forwarding it via @a next_hop under respect of
9467 * @a options.
9468 *
9469 * @param cls a `struct PendingMessageScoreContext`
9470 * @param next_hop next hop of the DV path
9471 * @param hdr encapsulated message, technically a `struct TransportDVBoxMessage`
9472 * @param options options of the original message
9473 */
9474static void
9475extract_box_cb (void *cls,
9476 struct Neighbour *next_hop,
9477 const struct GNUNET_MessageHeader *hdr,
9478 enum RouteMessageOptions options)
9479{
9480 struct PendingMessageScoreContext *sc = cls;
9481 struct PendingMessage *pm = sc->best;
9482 struct PendingMessage *bpm;
9483 uint16_t bsize = ntohs (hdr->size);
9484
9485 GNUNET_assert (NULL == pm->bpm);
9486 bpm = GNUNET_malloc (sizeof(struct PendingMessage) + bsize);
9487 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9488 "5 created pm %p storing vl %p from pm %p\n",
9489 bpm,
9490 pm->vl,
9491 pm);
9492 bpm->logging_uuid = logging_uuid_gen++;
9493 bpm->pmt = PMT_DV_BOX;
9494 bpm->vl = pm->vl;
9495 bpm->timeout = pm->timeout;
9496 bpm->bytes_msg = bsize;
9497 bpm->frag_parent = pm;
9498 set_pending_message_uuid (bpm);
9499 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9500 "Creating DV Box %llu for original message %llu (next hop is %s)\n",
9501 bpm->logging_uuid,
9502 pm->logging_uuid,
9503 GNUNET_i2s (&next_hop->pid));
9504 memcpy (&bpm[1], hdr, bsize);
9505 pm->bpm = bpm;
9506}
9507
9508
9509/**
9510 * We believe we are ready to transmit a `struct PendingMessage` on a
9511 * queue, the big question is which one! We need to see if there is
9512 * one pending that is allowed by flow control and congestion control
9513 * and (ideally) matches our queue's performance profile.
9514 *
9515 * If such a message is found, we give the message to the communicator
9516 * for transmission (updating the tracker, and re-scheduling ourselves
9517 * if applicable).
9518 *
9519 * If no such message is found, the queue's `idle` field must be set
9520 * to #GNUNET_YES.
9521 *
9522 * @param cls the `struct Queue` to process transmissions for
9523 */
9524static void
9525transmit_on_queue (void *cls)
9526{
9527 struct Queue *queue = cls;
9528 struct Neighbour *n = queue->neighbour;
9529 struct PendingMessageScoreContext sc;
9530 struct PendingMessage *pm;
9531
9532 queue->transmit_task = NULL;
9533 if (NULL == n->vl)
9534 {
9535 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9536 "Virtual link `%s' is down, cannot have PM for queue `%s'\n",
9537 GNUNET_i2s (&n->pid),
9538 queue->address);
9539 queue->idle = GNUNET_YES;
9540 return;
9541 }
9542 memset (&sc, 0, sizeof(sc));
9543 select_best_pending_from_link (&sc, queue, n->vl, NULL, 0);
9544 if (NULL == sc.best)
9545 {
9546 /* Also look at DVH that have the n as first hop! */
9547 for (struct DistanceVectorHop *dvh = n->dv_head; NULL != dvh;
9548 dvh = dvh->next_neighbour)
9549 {
9550 select_best_pending_from_link (&sc,
9551 queue,
9552 dvh->dv->vl,
9553 dvh,
9554 sizeof(struct GNUNET_PeerIdentity)
9555 * (1 + dvh->distance)
9556 + sizeof(struct TransportDVBoxMessage)
9557 + sizeof(struct TransportDVBoxPayloadP));
9558 }
9559 }
9560 if (NULL == sc.best)
9561 {
9562 /* no message pending, nothing to do here! */
9563 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9564 "No pending messages, queue `%s' to %s now idle\n",
9565 queue->address,
9566 GNUNET_i2s (&n->pid));
9567 if (GNUNET_YES == sc.to_early)
9568 schedule_transmit_on_queue (sc.to_early_retry_delay,
9569 queue,
9570 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
9571 queue->idle = GNUNET_YES;
9572 return;
9573 }
9574 /* There is a message pending, we are certainly not idle */
9575 queue->idle = GNUNET_NO;
9576
9577 /* Given selection in `sc`, do transmission */
9578 pm = sc.best;
9579 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9580 "Selected message <%llu>\n",
9581 pm->logging_uuid);
9582 if (NULL != sc.dvh)
9583 {
9584 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9585 "Is this %u a DV box?\n",
9586 pm->pmt);
9587 GNUNET_assert (PMT_DV_BOX != pm->pmt);
9588 if ((NULL != sc.best->bpm) && (sc.best->bpm->used_dvh != sc.dvh))
9589 {
9590 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9591 "Discard old box, because we have a new DV path.\n");
9592 free_pending_message (sc.best->bpm);
9593 sc.best->bpm = NULL;
9594 }
9595
9596 if (NULL == sc.best->bpm)
9597 {
9598 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9599 "encapsulate_for_dv 2\n");
9600 encapsulate_for_dv (sc.dvh->dv,
9601 1,
9602 &sc.dvh,
9603 (const struct GNUNET_MessageHeader *) &sc.best[1],
9604 &extract_box_cb,
9605 &sc,
9606 RMO_NONE,
9607 GNUNET_NO);
9608 GNUNET_assert (NULL != sc.best->bpm);
9609 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9610 "%u %u %u %u %u\n",
9611 sizeof(struct GNUNET_PeerIdentity),
9612 sizeof(struct TransportDVBoxMessage),
9613 sizeof(struct TransportDVBoxPayloadP),
9614 sizeof(struct TransportFragmentBoxMessage),
9615 ((const struct GNUNET_MessageHeader *) &sc.best[1])->size);
9616 sc.best->bpm->used_dvh = sc.dvh;
9617 }
9618 pm = sc.best->bpm;
9619 }
9620 if (GNUNET_YES == sc.frag)
9621 {
9622 pm = fragment_message (queue, sc.dvh, pm);
9623 if (NULL == pm)
9624 {
9625 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9626 "Fragmentation failed queue %s to %s for <%llu>, trying again\n",
9627 queue->address,
9628 GNUNET_i2s (&n->pid),
9629 sc.best->logging_uuid);
9630 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
9631 queue,
9632 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
9633 return;
9634 }
9635 }
9636 else if (GNUNET_YES == sc.relb)
9637 {
9638 pm = reliability_box_message (queue, sc.dvh, pm);
9639 if (NULL == pm)
9640 {
9641 /* Reliability boxing failed, try next message... */
9642 GNUNET_log (
9643 GNUNET_ERROR_TYPE_DEBUG,
9644 "Reliability boxing failed queue %s to %s for <%llu>, trying again\n",
9645 queue->address,
9646 GNUNET_i2s (&n->pid),
9647 sc.best->logging_uuid);
9648 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
9649 queue,
9650 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
9651 return;
9652 }
9653 }
9654
9655 /* Pass 'pm' for transission to the communicator */
9656 GNUNET_log (
9657 GNUNET_ERROR_TYPE_DEBUG,
9658 "Passing message <%llu> to queue %s for peer %s (considered %u others)\n",
9659 pm->logging_uuid,
9660 queue->address,
9661 GNUNET_i2s (&n->pid),
9662 sc.consideration_counter);
9663
9664 /* Flow control: increment amount of traffic sent; if we are routing
9665 via DV (and thus the ultimate target of the pending message is for
9666 a different virtual link than the one of the queue), then we need
9667 to use up not only the window of the direct link but also the
9668 flow control window for the DV link! */
9669 pm->vl->outbound_fc_window_size_used += pm->bytes_msg;
9670
9671 if (pm->vl != queue->neighbour->vl)
9672 {
9673 /* If the virtual link of the queue differs, this better be distance
9674 vector routing! */
9675 GNUNET_assert (NULL != sc.dvh);
9676 /* If we do distance vector routing, we better not do this for a
9677 message that was itself DV-routed */
9678 GNUNET_assert (PMT_DV_BOX != sc.best->pmt);
9679 /* We use the size of the unboxed message here, to avoid counting
9680 the DV-Box header which is eaten up on the way by intermediaries */
9681 queue->neighbour->vl->outbound_fc_window_size_used += sc.best->bytes_msg;
9682 }
9683 else
9684 {
9685 GNUNET_assert (NULL == sc.dvh);
9686 }
9687
9688 queue_send_msg (queue, pm, &pm[1], pm->bytes_msg);
9689
9690 /* Check if this transmission somehow conclusively finished handing 'pm'
9691 even without any explicit ACKs */
9692 if ((PMT_CORE == pm->pmt) ||
9693 (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc))
9694 {
9695 completed_pending_message (pm);
9696 }
9697 else
9698 {
9699 struct GNUNET_TIME_Relative wait_duration;
9700
9701 /* Message not finished, waiting for acknowledgement.
9702 Update time by which we might retransmit 's' based on queue
9703 characteristics (i.e. RTT); it takes one RTT for the message to
9704 arrive and the ACK to come back in the best case; but the other
9705 side is allowed to delay ACKs by 2 RTTs, so we use 4 RTT before
9706 retransmitting.
9707
9708 OPTIMIZE: Note that in the future this heuristic should likely
9709 be improved further (measure RTT stability, consider message
9710 urgency and size when delaying ACKs, etc.) */
9711
9712 if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us !=
9713 queue->pd.aged_rtt.rel_value_us)
9714 wait_duration = queue->pd.aged_rtt;
9715 else
9716 wait_duration = DEFAULT_ACK_WAIT_DURATION;
9717 struct GNUNET_TIME_Absolute next = GNUNET_TIME_relative_to_absolute (
9718 GNUNET_TIME_relative_multiply (
9719 wait_duration, 4));
9720 struct GNUNET_TIME_Relative plus = GNUNET_TIME_relative_multiply (
9721 wait_duration, 4);
9722 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9723 "Waiting %s (%llu) for ACK until %llu\n",
9724 GNUNET_STRINGS_relative_time_to_string (
9725 GNUNET_TIME_relative_multiply (
9726 queue->pd.aged_rtt, 4), GNUNET_NO),
9727 plus,
9728 next);
9729 update_pm_next_attempt (pm,
9730 GNUNET_TIME_relative_to_absolute (
9731 GNUNET_TIME_relative_multiply (wait_duration,
9732 4)));
9733 }
9734 /* finally, re-schedule queue transmission task itself */
9735 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
9736 queue,
9737 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
9738}
9739
9740
9741/**
9742 * Queue to a peer went down. Process the request.
9743 *
9744 * @param cls the client
9745 * @param dqm the send message that was sent
9746 */
9747static void
9748handle_del_queue_message (void *cls,
9749 const struct GNUNET_TRANSPORT_DelQueueMessage *dqm)
9750{
9751 struct TransportClient *tc = cls;
9752
9753 if (CT_COMMUNICATOR != tc->type)
9754 {
9755 GNUNET_break (0);
9756 GNUNET_SERVICE_client_drop (tc->client);
9757 return;
9758 }
9759 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
9760 queue = queue->next_client)
9761 {
9762 struct Neighbour *neighbour = queue->neighbour;
9763
9764 if ((dqm->qid != queue->qid) ||
9765 (0 != GNUNET_memcmp (&dqm->receiver, &neighbour->pid)))
9766 continue;
9767 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9768 "Dropped queue %s to peer %s\n",
9769 queue->address,
9770 GNUNET_i2s (&neighbour->pid));
9771 free_queue (queue);
9772 GNUNET_SERVICE_client_continue (tc->client);
9773 return;
9774 }
9775 GNUNET_break (0);
9776 GNUNET_SERVICE_client_drop (tc->client);
9777}
9778
9779
9780/**
9781 * Message was transmitted. Process the request.
9782 *
9783 * @param cls the client
9784 * @param sma the send message that was sent
9785 */
9786static void
9787handle_send_message_ack (void *cls,
9788 const struct GNUNET_TRANSPORT_SendMessageToAck *sma)
9789{
9790 struct TransportClient *tc = cls;
9791 struct QueueEntry *qe;
9792 struct PendingMessage *pm;
9793
9794 if (CT_COMMUNICATOR != tc->type)
9795 {
9796 GNUNET_break (0);
9797 GNUNET_SERVICE_client_drop (tc->client);
9798 return;
9799 }
9800
9801 /* find our queue entry matching the ACK */
9802 qe = NULL;
9803 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9804 "Looking for queue for PID %s\n",
9805 GNUNET_i2s (&sma->receiver));
9806 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
9807 queue = queue->next_client)
9808 {
9809 if (0 != GNUNET_memcmp (&queue->neighbour->pid, &sma->receiver))
9810 continue;
9811 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9812 "Found PID %s\n",
9813 GNUNET_i2s (&queue->neighbour->pid));
9814
9815
9816 for (struct QueueEntry *qep = queue->queue_head; NULL != qep;
9817 qep = qep->next)
9818 {
9819 if (qep->mid != sma->mid)
9820 continue;
9821 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9822 "QueueEntry MID: %llu on queue QID: %llu, Ack MID: %llu\n",
9823 (unsigned long long) qep->mid,
9824 (unsigned long long) queue->qid,
9825 (unsigned long long) sma->mid);
9826 qe = qep;
9827 if ((NULL != qe->pm) && (qe->pm->qe != qe))
9828 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9829 "For pending message %llu we had retransmissions.\n",
9830 qe->pm->logging_uuid);
9831 break;
9832 }
9833 }
9834 if (NULL == qe)
9835 {
9836 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9837 "No QueueEntry found for Ack MID %llu\n",
9838 (unsigned long long) sma->mid);
9839 // TODO I guess this can happen, if the Ack from the peer comes before the Ack from the queue.
9840 /* this should never happen */
9841 /*GNUNET_break (0);
9842 GNUNET_SERVICE_client_drop (tc->client);*/
9843 GNUNET_SERVICE_client_continue (tc->client);
9844 return;
9845 }
9846 GNUNET_CONTAINER_DLL_remove (qe->queue->queue_head,
9847 qe->queue->queue_tail,
9848 qe);
9849 qe->queue->queue_length--;
9850 tc->details.communicator.total_queue_length--;
9851 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9852 "Received ACK on queue %s to peer %s (new length: %u/%u)\n",
9853 qe->queue->address,
9854 GNUNET_i2s (&qe->queue->neighbour->pid),
9855 qe->queue->queue_length,
9856 tc->details.communicator.total_queue_length);
9857 GNUNET_SERVICE_client_continue (tc->client);
9858
9859 /* if applicable, resume transmissions that waited on ACK */
9860 if (COMMUNICATOR_TOTAL_QUEUE_LIMIT - 1 ==
9861 tc->details.communicator.total_queue_length)
9862 {
9863 /* Communicator dropped below threshold, resume all queues
9864 incident with this client! */
9865 GNUNET_STATISTICS_update (
9866 GST_stats,
9867 "# Transmission throttled due to communicator queue limit",
9868 -1,
9869 GNUNET_NO);
9870 for (struct Queue *queue = tc->details.communicator.queue_head;
9871 NULL != queue;
9872 queue = queue->next_client)
9873 {
9874 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
9875 queue,
9876 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
9877 }
9878 }
9879 else if (QUEUE_LENGTH_LIMIT - 1 == qe->queue->queue_length)
9880 {
9881 /* queue dropped below threshold; only resume this one queue */
9882 GNUNET_STATISTICS_update (GST_stats,
9883 "# Transmission throttled due to queue queue limit",
9884 -1,
9885 GNUNET_NO);
9886 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
9887 qe->queue,
9888 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
9889 }
9890 else if (1 == qe->queue->q_capacity)
9891 {
9892 // TODO I guess this will never happen, because the communicator triggers this by updating its queue length itself.
9893 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9894 "Transmission rescheduled due to communicator message queue with qid %u has capacity %lu.\n",
9895 qe->queue->qid,
9896 qe->queue->q_capacity);
9897 /* message queue has capacity; only resume this one queue */
9898 /* queue dropped below threshold; only resume this one queue */
9899 GNUNET_STATISTICS_update (GST_stats,
9900 "# Transmission throttled due to message queue capacity",
9901 -1,
9902 GNUNET_NO);
9903 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
9904 qe->queue,
9905 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
9906 }
9907
9908 if (NULL != (pm = qe->pm))
9909 {
9910 struct VirtualLink *vl;
9911
9912 // GNUNET_assert (qe == pm->qe);
9913 pm->qe = NULL;
9914 /* If waiting for this communicator may have blocked transmission
9915 of pm on other queues for this neighbour, force schedule
9916 transmit on queue for queues of the neighbour */
9917 if (NULL == pm->frag_parent)
9918 {
9919 vl = pm->vl;
9920 if ((NULL != vl) &&
9921 (NULL != vl->pending_msg_head) &&
9922 (vl->pending_msg_head == pm))
9923 check_vl_transmission (vl);
9924 }
9925 }
9926 GNUNET_free (qe);
9927}
9928
9929
9930/**
9931 * Iterator telling new MONITOR client about all existing
9932 * queues to peers.
9933 *
9934 * @param cls the new `struct TransportClient`
9935 * @param pid a connected peer
9936 * @param value the `struct Neighbour` with more information
9937 * @return #GNUNET_OK (continue to iterate)
9938 */
9939static int
9940notify_client_queues (void *cls,
9941 const struct GNUNET_PeerIdentity *pid,
9942 void *value)
9943{
9944 struct TransportClient *tc = cls;
9945 struct Neighbour *neighbour = value;
9946
9947 GNUNET_assert (CT_MONITOR == tc->type);
9948 for (struct Queue *q = neighbour->queue_head; NULL != q;
9949 q = q->next_neighbour)
9950 {
9951 struct MonitorEvent me = { .rtt = q->pd.aged_rtt,
9952 .cs = q->cs,
9953 .num_msg_pending = q->num_msg_pending,
9954 .num_bytes_pending = q->num_bytes_pending };
9955
9956 notify_monitor (tc, pid, q->address, q->nt, &me);
9957 }
9958 return GNUNET_OK;
9959}
9960
9961
9962/**
9963 * Initialize a monitor client.
9964 *
9965 * @param cls the client
9966 * @param start the start message that was sent
9967 */
9968static void
9969handle_monitor_start (void *cls,
9970 const struct GNUNET_TRANSPORT_MonitorStart *start)
9971{
9972 struct TransportClient *tc = cls;
9973
9974 if (CT_NONE != tc->type)
9975 {
9976 GNUNET_break (0);
9977 GNUNET_SERVICE_client_drop (tc->client);
9978 return;
9979 }
9980 tc->type = CT_MONITOR;
9981 tc->details.monitor.peer = start->peer;
9982 tc->details.monitor.one_shot = ntohl (start->one_shot);
9983 GNUNET_CONTAINER_multipeermap_iterate (neighbours, &notify_client_queues, tc);
9984 GNUNET_SERVICE_client_mark_monitor (tc->client);
9985 GNUNET_SERVICE_client_continue (tc->client);
9986}
9987
9988
9989/**
9990 * Find transport client providing communication service
9991 * for the protocol @a prefix.
9992 *
9993 * @param prefix communicator name
9994 * @return NULL if no such transport client is available
9995 */
9996static struct TransportClient *
9997lookup_communicator (const char *prefix)
9998{
9999 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
10000 {
10001 if (CT_COMMUNICATOR != tc->type)
10002 continue;
10003 if (0 == strcmp (prefix, tc->details.communicator.address_prefix))
10004 return tc;
10005 }
10006 GNUNET_log (
10007 GNUNET_ERROR_TYPE_WARNING,
10008 "Somone suggested use of communicator for `%s', but we do not have such a communicator!\n",
10009 prefix);
10010 return NULL;
10011}
10012
10013
10014/**
10015 * Signature of a function called with a communicator @a address of a peer
10016 * @a pid that an application wants us to connect to.
10017 *
10018 * @param pid target peer
10019 * @param address the address to try
10020 */
10021static void
10022suggest_to_connect (const struct GNUNET_PeerIdentity *pid, const char *address)
10023{
10024 static uint32_t idgen;
10025 struct TransportClient *tc;
10026 char *prefix;
10027 struct GNUNET_TRANSPORT_CreateQueue *cqm;
10028 struct GNUNET_MQ_Envelope *env;
10029 size_t alen;
10030
10031 prefix = GNUNET_HELLO_address_to_prefix (address);
10032 if (NULL == prefix)
10033 {
10034 GNUNET_break (0); /* We got an invalid address!? */
10035 return;
10036 }
10037 tc = lookup_communicator (prefix);
10038 if (NULL == tc)
10039 {
10040 GNUNET_STATISTICS_update (GST_stats,
10041 "# Suggestions ignored due to missing communicator",
10042 1,
10043 GNUNET_NO);
10044 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
10045 "Cannot connect to %s at `%s', no matching communicator present\n",
10046 GNUNET_i2s (pid),
10047 address);
10048 GNUNET_free (prefix);
10049 return;
10050 }
10051 /* forward suggestion for queue creation to communicator */
10052 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10053 "Request #%u for `%s' communicator to create queue to `%s'\n",
10054 (unsigned int) idgen,
10055 prefix,
10056 address);
10057 GNUNET_free (prefix);
10058 alen = strlen (address) + 1;
10059 env =
10060 GNUNET_MQ_msg_extra (cqm, alen, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE);
10061 cqm->request_id = htonl (idgen++);
10062 cqm->receiver = *pid;
10063 memcpy (&cqm[1], address, alen);
10064 GNUNET_MQ_send (tc->mq, env);
10065}
10066
10067
10068/**
10069 * The queue @a q (which matches the peer and address in @a vs) is
10070 * ready for queueing. We should now queue the validation request.
10071 *
10072 * @param q queue to send on
10073 * @param vs state to derive validation challenge from
10074 */
10075static void
10076validation_transmit_on_queue (struct Queue *q, struct ValidationState *vs)
10077{
10078 struct TransportValidationChallengeMessage tvc;
10079
10080 vs->last_challenge_use = GNUNET_TIME_absolute_get_monotonic (GST_cfg);
10081 tvc.header.type =
10082 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE);
10083 tvc.header.size = htons (sizeof(tvc));
10084 tvc.reserved = htonl (0);
10085 tvc.challenge = vs->challenge;
10086 tvc.sender_time = GNUNET_TIME_absolute_hton (vs->last_challenge_use);
10087 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
10088 "Sending address validation challenge %s to %s\n",
10089 GNUNET_sh2s (&tvc.challenge.value),
10090 GNUNET_i2s (&q->neighbour->pid));
10091 queue_send_msg (q, NULL, &tvc, sizeof(tvc));
10092}
10093
10094
10095/**
10096 * Task run periodically to validate some address based on #validation_heap.
10097 *
10098 * @param cls NULL
10099 */
10100static void
10101validation_start_cb (void *cls)
10102{
10103 struct ValidationState *vs;
10104 struct Queue *q;
10105
10106 (void) cls;
10107 validation_task = NULL;
10108 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
10109 /* drop validations past their expiration */
10110 while (
10111 (NULL != vs) &&
10112 (0 == GNUNET_TIME_absolute_get_remaining (vs->valid_until).rel_value_us))
10113 {
10114 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10115 "Validation response %s cleaned up\n",
10116 GNUNET_sh2s (&vs->challenge.value));
10117 free_validation_state (vs);
10118 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
10119 }
10120 if (NULL == vs)
10121 {
10122 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
10123 "Address validation task not scheduled anymore, nothing to do\n");
10124 return; /* woopsie, no more addresses known, should only
10125 happen if we're really a lonely peer */
10126 }
10127 q = find_queue (&vs->pid, vs->address);
10128 if (NULL == q)
10129 {
10130 vs->awaiting_queue = GNUNET_YES;
10131 suggest_to_connect (&vs->pid, vs->address);
10132 }
10133 else
10134 validation_transmit_on_queue (q, vs);
10135 /* Finally, reschedule next attempt */
10136 vs->challenge_backoff =
10137 GNUNET_TIME_randomized_backoff (vs->challenge_backoff,
10138 MAX_VALIDATION_CHALLENGE_FREQ);
10139 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10140 "Address validation task will run again in %s\n",
10141 GNUNET_STRINGS_relative_time_to_string (vs->challenge_backoff,
10142 GNUNET_YES));
10143 update_next_challenge_time (vs,
10144 GNUNET_TIME_relative_to_absolute (
10145 vs->challenge_backoff));
10146}
10147
10148
10149/**
10150 * Closure for #check_connection_quality.
10151 */
10152struct QueueQualityContext
10153{
10154 /**
10155 * Set to the @e k'th queue encountered.
10156 */
10157 struct Queue *q;
10158
10159 /**
10160 * Set to the number of quality queues encountered.
10161 */
10162 unsigned int quality_count;
10163
10164 /**
10165 * Set to the total number of queues encountered.
10166 */
10167 unsigned int num_queues;
10168
10169 /**
10170 * Decremented for each queue, for selection of the
10171 * k-th queue in @e q.
10172 */
10173 unsigned int k;
10174};
10175
10176
10177/**
10178 * Check whether any queue to the given neighbour is
10179 * of a good "quality" and if so, increment the counter.
10180 * Also counts the total number of queues, and returns
10181 * the k-th queue found.
10182 *
10183 * @param cls a `struct QueueQualityContext *` with counters
10184 * @param pid peer this is about
10185 * @param value a `struct Neighbour`
10186 * @return #GNUNET_OK (continue to iterate)
10187 */
10188static int
10189check_connection_quality (void *cls,
10190 const struct GNUNET_PeerIdentity *pid,
10191 void *value)
10192{
10193 struct QueueQualityContext *ctx = cls;
10194 struct Neighbour *n = value;
10195 int do_inc;
10196
10197 (void) pid;
10198 do_inc = GNUNET_NO;
10199 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
10200 {
10201 ctx->num_queues++;
10202 if (0 == ctx->k--)
10203 ctx->q = q;
10204 /* FIXME-CONQ-STATISTICS: in the future, add reliability / goodput
10205 statistics and consider those as well here? */
10206 if (q->pd.aged_rtt.rel_value_us < DV_QUALITY_RTT_THRESHOLD.rel_value_us)
10207 do_inc = GNUNET_YES;
10208 }
10209 if (GNUNET_YES == do_inc)
10210 ctx->quality_count++;
10211 return GNUNET_OK;
10212}
10213
10214
10215/**
10216 * Task run when we CONSIDER initiating a DV learn
10217 * process. We first check that sending out a message is
10218 * even possible (queues exist), then that it is desirable
10219 * (if not, reschedule the task for later), and finally
10220 * we may then begin the job. If there are too many
10221 * entries in the #dvlearn_map, we purge the oldest entry
10222 * using #lle_tail.
10223 *
10224 * @param cls NULL
10225 */
10226static void
10227start_dv_learn (void *cls)
10228{
10229 struct LearnLaunchEntry *lle;
10230 struct QueueQualityContext qqc;
10231 struct TransportDVLearnMessage dvl;
10232
10233 (void) cls;
10234 dvlearn_task = NULL;
10235 if (0 == GNUNET_CONTAINER_multipeermap_size (neighbours))
10236 return; /* lost all connectivity, cannot do learning */
10237 qqc.quality_count = 0;
10238 qqc.num_queues = 0;
10239 qqc.k = GNUNET_CONTAINER_multipeermap_size (neighbours);
10240 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
10241 &check_connection_quality,
10242 &qqc);
10243 if (qqc.quality_count > DV_LEARN_QUALITY_THRESHOLD)
10244 {
10245 struct GNUNET_TIME_Relative delay;
10246 unsigned int factor;
10247
10248 /* scale our retries by how far we are above the threshold */
10249 factor = qqc.quality_count / DV_LEARN_QUALITY_THRESHOLD;
10250 delay = GNUNET_TIME_relative_multiply (DV_LEARN_BASE_FREQUENCY, factor);
10251 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10252 "At connection quality %u, will launch DV learn in %s\n",
10253 qqc.quality_count,
10254 GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
10255 dvlearn_task = GNUNET_SCHEDULER_add_delayed (delay, &start_dv_learn, NULL);
10256 return;
10257 }
10258 /* remove old entries in #dvlearn_map if it has grown too big */
10259 while (MAX_DV_LEARN_PENDING <=
10260 GNUNET_CONTAINER_multishortmap_size (dvlearn_map))
10261 {
10262 lle = lle_tail;
10263 GNUNET_assert (GNUNET_YES ==
10264 GNUNET_CONTAINER_multishortmap_remove (dvlearn_map,
10265 &lle->challenge.value,
10266 lle));
10267 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
10268 GNUNET_free (lle);
10269 }
10270 /* setup data structure for learning */
10271 lle = GNUNET_new (struct LearnLaunchEntry);
10272 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
10273 &lle->challenge,
10274 sizeof(lle->challenge));
10275 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10276 "Starting launch DV learn with challenge %s\n",
10277 GNUNET_sh2s (&lle->challenge.value));
10278 GNUNET_CONTAINER_DLL_insert (lle_head, lle_tail, lle);
10279 GNUNET_break (GNUNET_YES ==
10280 GNUNET_CONTAINER_multishortmap_put (
10281 dvlearn_map,
10282 &lle->challenge.value,
10283 lle,
10284 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
10285 dvl.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
10286 dvl.header.size = htons (sizeof(dvl));
10287 dvl.num_hops = htons (0);
10288 dvl.bidirectional = htons (0);
10289 dvl.non_network_delay = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO);
10290 dvl.monotonic_time =
10291 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (GST_cfg));
10292 {
10293 struct DvInitPS dvip = {
10294 .purpose.purpose = htonl (
10295 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
10296 .purpose.size = htonl (sizeof(dvip)),
10297 .monotonic_time = dvl.monotonic_time,
10298 .challenge = lle->challenge
10299 };
10300
10301 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
10302 &dvip,
10303 &dvl.init_sig);
10304 }
10305 dvl.initiator = GST_my_identity;
10306 dvl.challenge = lle->challenge;
10307
10308 qqc.quality_count = 0;
10309 qqc.k = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, qqc.num_queues);
10310 qqc.num_queues = 0;
10311 qqc.q = NULL;
10312 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
10313 &check_connection_quality,
10314 &qqc);
10315 GNUNET_assert (NULL != qqc.q);
10316
10317 /* Do this as close to transmission time as possible! */
10318 lle->launch_time = GNUNET_TIME_absolute_get ();
10319
10320 queue_send_msg (qqc.q, NULL, &dvl, sizeof(dvl));
10321 /* reschedule this job, randomizing the time it runs (but no
10322 actual backoff!) */
10323 dvlearn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_randomize (
10324 DV_LEARN_BASE_FREQUENCY),
10325 &start_dv_learn,
10326 NULL);
10327}
10328
10329
10330/**
10331 * A new queue has been created, check if any address validation
10332 * requests have been waiting for it.
10333 *
10334 * @param cls a `struct Queue`
10335 * @param pid peer concerned (unused)
10336 * @param value a `struct ValidationState`
10337 * @return #GNUNET_NO if a match was found and we can stop looking
10338 */
10339static int
10340check_validation_request_pending (void *cls,
10341 const struct GNUNET_PeerIdentity *pid,
10342 void *value)
10343{
10344 struct Queue *q = cls;
10345 struct ValidationState *vs = value;
10346
10347 (void) pid;
10348 if ((GNUNET_YES == vs->awaiting_queue) &&
10349 (0 == strcmp (vs->address, q->address)))
10350 {
10351 vs->awaiting_queue = GNUNET_NO;
10352 validation_transmit_on_queue (q, vs);
10353 return GNUNET_NO;
10354 }
10355 return GNUNET_OK;
10356}
10357
10358
10359/**
10360 * Function called with the monotonic time of a DV initiator
10361 * by PEERSTORE. Updates the time.
10362 *
10363 * @param cls a `struct Neighbour`
10364 * @param record the information found, NULL for the last call
10365 * @param emsg error message
10366 */
10367static void
10368neighbour_dv_monotime_cb (void *cls,
10369 const struct GNUNET_PEERSTORE_Record *record,
10370 const char *emsg)
10371{
10372 struct Neighbour *n = cls;
10373 struct GNUNET_TIME_AbsoluteNBO *mtbe;
10374
10375 (void) emsg;
10376 if (NULL == record)
10377 {
10378 /* we're done with #neighbour_dv_monotime_cb() invocations,
10379 continue normal processing */
10380 n->get = NULL;
10381 n->dv_monotime_available = GNUNET_YES;
10382 return;
10383 }
10384 if (sizeof(*mtbe) != record->value_size)
10385 {
10386 GNUNET_break (0);
10387 return;
10388 }
10389 mtbe = record->value;
10390 n->last_dv_learn_monotime =
10391 GNUNET_TIME_absolute_max (n->last_dv_learn_monotime,
10392 GNUNET_TIME_absolute_ntoh (*mtbe));
10393}
10394
10395
10396/**
10397 * New queue became available. Process the request.
10398 *
10399 * @param cls the client
10400 * @param aqm the send message that was sent
10401 */
10402static void
10403handle_add_queue_message (void *cls,
10404 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
10405{
10406 struct TransportClient *tc = cls;
10407 struct Queue *queue;
10408 struct Neighbour *neighbour;
10409 const char *addr;
10410 uint16_t addr_len;
10411
10412 if (ntohl (aqm->mtu) <= sizeof(struct TransportFragmentBoxMessage))
10413 {
10414 /* MTU so small as to be useless for transmissions,
10415 required for #fragment_message()! */
10416 GNUNET_break_op (0);
10417 GNUNET_SERVICE_client_drop (tc->client);
10418 return;
10419 }
10420 /* This may simply be a queue update */
10421 for (queue = tc->details.communicator.queue_head;
10422 NULL != queue;
10423 queue = queue->next_client)
10424 {
10425 if (queue->qid != aqm->qid)
10426 continue;
10427 break;
10428 }
10429
10430 if (NULL != queue)
10431 {
10432 neighbour = queue->neighbour;
10433 }
10434 else
10435 {
10436 neighbour = lookup_neighbour (&aqm->receiver);
10437 if (NULL == neighbour)
10438 {
10439 neighbour = GNUNET_new (struct Neighbour);
10440 neighbour->pid = aqm->receiver;
10441 GNUNET_assert (GNUNET_OK ==
10442 GNUNET_CONTAINER_multipeermap_put (
10443 neighbours,
10444 &neighbour->pid,
10445 neighbour,
10446 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
10447 neighbour->get =
10448 GNUNET_PEERSTORE_iterate (peerstore,
10449 "transport",
10450 &neighbour->pid,
10451 GNUNET_PEERSTORE_TRANSPORT_DVLEARN_MONOTIME,
10452 &neighbour_dv_monotime_cb,
10453 neighbour);
10454 }
10455 addr_len = ntohs (aqm->header.size) - sizeof(*aqm);
10456 addr = (const char *) &aqm[1];
10457 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10458 "New queue %s to %s available with QID %llu and q_len %lu and mtu %u\n",
10459 addr,
10460 GNUNET_i2s (&aqm->receiver),
10461 (unsigned long long) aqm->qid,
10462 GNUNET_ntohll (aqm->q_len),
10463 ntohl (aqm->mtu));
10464 queue = GNUNET_malloc (sizeof(struct Queue) + addr_len);
10465 queue->tc = tc;
10466 queue->address = (const char *) &queue[1];
10467 queue->pd.aged_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
10468 queue->qid = aqm->qid;
10469 queue->neighbour = neighbour;
10470 if (GNUNET_TRANSPORT_QUEUE_LENGTH_UNLIMITED == GNUNET_ntohll (aqm->q_len))
10471 queue->unlimited_length = GNUNET_YES;
10472 queue->q_capacity = GNUNET_ntohll (aqm->q_len);
10473 memcpy (&queue[1], addr, addr_len);
10474 /* notify monitors about new queue */
10475 {
10476 struct MonitorEvent me = { .rtt = queue->pd.aged_rtt, .cs = queue->cs };
10477
10478 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
10479 }
10480 GNUNET_CONTAINER_MDLL_insert (neighbour,
10481 neighbour->queue_head,
10482 neighbour->queue_tail,
10483 queue);
10484 GNUNET_CONTAINER_MDLL_insert (client,
10485 tc->details.communicator.queue_head,
10486 tc->details.communicator.queue_tail,
10487 queue);
10488
10489 }
10490 queue->mtu = ntohl (aqm->mtu);
10491 queue->nt = (enum GNUNET_NetworkType) ntohl (aqm->nt);
10492 queue->cs = (enum GNUNET_TRANSPORT_ConnectionStatus) ntohl (aqm->cs);
10493 queue->idle = GNUNET_YES;
10494 /* check if valdiations are waiting for the queue */
10495 (void)
10496 GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
10497 &aqm->receiver,
10498 &check_validation_request_pending,
10499 queue);
10500 /* look for traffic for this queue */
10501 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
10502 queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
10503 /* might be our first queue, try launching DV learning */
10504 if (NULL == dvlearn_task)
10505 dvlearn_task = GNUNET_SCHEDULER_add_now (&start_dv_learn, NULL);
10506 GNUNET_SERVICE_client_continue (tc->client);
10507}
10508
10509
10510/**
10511 * @brief Handle updates to queues.
10512 *
10513 * @param cls the transport client.
10514 * @param msg Message struct.
10515 */
10516static void
10517handle_update_queue_message (void *cls,
10518 const struct
10519 GNUNET_TRANSPORT_UpdateQueueMessage *msg)
10520{
10521 struct TransportClient *tc = cls;
10522 struct Queue *target_queue = NULL;
10523
10524 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10525 "Received queue update message for %u with q_len %llu and mtu %u\n",
10526 msg->qid,
10527 (unsigned long long) GNUNET_ntohll (msg->q_len),
10528 ntohl (msg->mtu));
10529 for (target_queue = tc->details.communicator.queue_head;
10530 NULL != target_queue;
10531 target_queue = target_queue->next_client)
10532 {
10533 if (msg->qid == target_queue->qid)
10534 break;
10535 }
10536 if (NULL == target_queue)
10537 {
10538 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
10539 "Queue to update no longer exists! Discarding update.\n");
10540 return;
10541 }
10542
10543 target_queue->nt = msg->nt;
10544 target_queue->mtu = ntohl (msg->mtu);
10545 target_queue->cs = msg->cs;
10546 target_queue->priority = ntohl (msg->priority);
10547 /* The update message indicates how many messages
10548 * the queue should be able to handle.
10549 */
10550 if (GNUNET_TRANSPORT_QUEUE_LENGTH_UNLIMITED == GNUNET_ntohll (msg->q_len))
10551 target_queue->unlimited_length = GNUNET_YES;
10552 else
10553 target_queue->unlimited_length = GNUNET_NO;
10554 target_queue->q_capacity = GNUNET_ntohll (msg->q_len);
10555 if (0 < target_queue->q_capacity)
10556 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
10557 target_queue,
10558 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
10559 GNUNET_SERVICE_client_continue (tc->client);
10560}
10561
10562
10563/**
10564 * Communicator tells us that our request to create a queue "worked", that
10565 * is setting up the queue is now in process.
10566 *
10567 * @param cls the `struct TransportClient`
10568 * @param cqr confirmation message
10569 */
10570static void
10571handle_queue_create_ok (void *cls,
10572 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
10573{
10574 struct TransportClient *tc = cls;
10575
10576 if (CT_COMMUNICATOR != tc->type)
10577 {
10578 GNUNET_break (0);
10579 GNUNET_SERVICE_client_drop (tc->client);
10580 return;
10581 }
10582 GNUNET_STATISTICS_update (GST_stats,
10583 "# Suggestions succeeded at communicator",
10584 1,
10585 GNUNET_NO);
10586 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10587 "Request #%u for communicator to create queue succeeded\n",
10588 (unsigned int) ntohs (cqr->request_id));
10589 GNUNET_SERVICE_client_continue (tc->client);
10590}
10591
10592
10593/**
10594 * Communicator tells us that our request to create a queue failed. This
10595 * usually indicates that the provided address is simply invalid or that the
10596 * communicator's resources are exhausted.
10597 *
10598 * @param cls the `struct TransportClient`
10599 * @param cqr failure message
10600 */
10601static void
10602handle_queue_create_fail (
10603 void *cls,
10604 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
10605{
10606 struct TransportClient *tc = cls;
10607
10608 if (CT_COMMUNICATOR != tc->type)
10609 {
10610 GNUNET_break (0);
10611 GNUNET_SERVICE_client_drop (tc->client);
10612 return;
10613 }
10614 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10615 "Request #%u for communicator to create queue failed\n",
10616 (unsigned int) ntohs (cqr->request_id));
10617 GNUNET_STATISTICS_update (GST_stats,
10618 "# Suggestions failed in queue creation at communicator",
10619 1,
10620 GNUNET_NO);
10621 GNUNET_SERVICE_client_continue (tc->client);
10622}
10623
10624
10625/**
10626 * We have received a `struct ExpressPreferenceMessage` from an application
10627 * client.
10628 *
10629 * @param cls handle to the client
10630 * @param msg the start message
10631 */
10632static void
10633handle_suggest_cancel (void *cls, const struct ExpressPreferenceMessage *msg)
10634{
10635 struct TransportClient *tc = cls;
10636 struct PeerRequest *pr;
10637
10638 if (CT_APPLICATION != tc->type)
10639 {
10640 GNUNET_break (0);
10641 GNUNET_SERVICE_client_drop (tc->client);
10642 return;
10643 }
10644 pr = GNUNET_CONTAINER_multipeermap_get (tc->details.application.requests,
10645 &msg->peer);
10646 if (NULL == pr)
10647 {
10648 GNUNET_break (0);
10649 GNUNET_SERVICE_client_drop (tc->client);
10650 return;
10651 }
10652 (void) stop_peer_request (tc, &pr->pid, pr);
10653 GNUNET_SERVICE_client_continue (tc->client);
10654}
10655
10656
10657/**
10658 * Function called by PEERSTORE for each matching record.
10659 *
10660 * @param cls closure, a `struct PeerRequest`
10661 * @param record peerstore record information
10662 * @param emsg error message, or NULL if no errors
10663 */
10664static void
10665handle_hello_for_client (void *cls,
10666 const struct GNUNET_PEERSTORE_Record *record,
10667 const char *emsg)
10668{
10669 struct PeerRequest *pr = cls;
10670 const char *val;
10671
10672 if (NULL != emsg)
10673 {
10674 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
10675 "Got failure from PEERSTORE: %s\n",
10676 emsg);
10677 return;
10678 }
10679 val = record->value;
10680 if ((0 == record->value_size) || ('\0' != val[record->value_size - 1]))
10681 {
10682 GNUNET_break (0);
10683 return;
10684 }
10685 start_address_validation (&pr->pid, (const char *) record->value);
10686}
10687
10688
10689/**
10690 * We have received a `struct ExpressPreferenceMessage` from an application
10691 * client.
10692 *
10693 * @param cls handle to the client
10694 * @param msg the start message
10695 */
10696static void
10697handle_suggest (void *cls, const struct ExpressPreferenceMessage *msg)
10698{
10699 struct TransportClient *tc = cls;
10700 struct PeerRequest *pr;
10701
10702 if (CT_NONE == tc->type)
10703 {
10704 tc->type = CT_APPLICATION;
10705 tc->details.application.requests =
10706 GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
10707 }
10708 if (CT_APPLICATION != tc->type)
10709 {
10710 GNUNET_break (0);
10711 GNUNET_SERVICE_client_drop (tc->client);
10712 return;
10713 }
10714 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10715 "Client suggested we talk to %s with preference %d at rate %u\n",
10716 GNUNET_i2s (&msg->peer),
10717 (int) ntohl (msg->pk),
10718 (int) ntohl (msg->bw.value__));
10719 pr = GNUNET_new (struct PeerRequest);
10720 pr->tc = tc;
10721 pr->pid = msg->peer;
10722 pr->bw = msg->bw;
10723 pr->pk = (enum GNUNET_MQ_PriorityPreferences) ntohl (msg->pk);
10724 if (GNUNET_YES != GNUNET_CONTAINER_multipeermap_put (
10725 tc->details.application.requests,
10726 &pr->pid,
10727 pr,
10728 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
10729 {
10730 GNUNET_break (0);
10731 GNUNET_free (pr);
10732 GNUNET_SERVICE_client_drop (tc->client);
10733 return;
10734 }
10735 pr->wc = GNUNET_PEERSTORE_watch (peerstore,
10736 "transport",
10737 &pr->pid,
10738 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
10739 &handle_hello_for_client,
10740 pr);
10741 GNUNET_SERVICE_client_continue (tc->client);
10742}
10743
10744
10745/**
10746 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION
10747 * messages.
10748 *
10749 * @param cls a `struct TransportClient *`
10750 * @param m message to verify
10751 * @return #GNUNET_OK on success
10752 */
10753static int
10754check_request_hello_validation (void *cls,
10755 const struct RequestHelloValidationMessage *m)
10756{
10757 (void) cls;
10758 GNUNET_MQ_check_zero_termination (m);
10759 return GNUNET_OK;
10760}
10761
10762
10763/**
10764 * A client encountered an address of another peer. Consider validating it,
10765 * and if validation succeeds, persist it to PEERSTORE.
10766 *
10767 * @param cls a `struct TransportClient *`
10768 * @param m message to verify
10769 */
10770static void
10771handle_request_hello_validation (void *cls,
10772 const struct RequestHelloValidationMessage *m)
10773{
10774 struct TransportClient *tc = cls;
10775
10776 start_address_validation (&m->peer, (const char *) &m[1]);
10777 GNUNET_SERVICE_client_continue (tc->client);
10778}
10779
10780
10781/**
10782 * Free neighbour entry.
10783 *
10784 * @param cls NULL
10785 * @param pid unused
10786 * @param value a `struct Neighbour`
10787 * @return #GNUNET_OK (always)
10788 */
10789static int
10790free_neighbour_cb (void *cls,
10791 const struct GNUNET_PeerIdentity *pid,
10792 void *value)
10793{
10794 struct Neighbour *neighbour = value;
10795
10796 (void) cls;
10797 (void) pid;
10798 GNUNET_break (0); // should this ever happen?
10799 free_neighbour (neighbour);
10800
10801 return GNUNET_OK;
10802}
10803
10804
10805/**
10806 * Free DV route entry.
10807 *
10808 * @param cls NULL
10809 * @param pid unused
10810 * @param value a `struct DistanceVector`
10811 * @return #GNUNET_OK (always)
10812 */
10813static int
10814free_dv_routes_cb (void *cls,
10815 const struct GNUNET_PeerIdentity *pid,
10816 void *value)
10817{
10818 struct DistanceVector *dv = value;
10819
10820 (void) cls;
10821 (void) pid;
10822 free_dv_route (dv);
10823
10824 return GNUNET_OK;
10825}
10826
10827
10828/**
10829 * Free validation state.
10830 *
10831 * @param cls NULL
10832 * @param pid unused
10833 * @param value a `struct ValidationState`
10834 * @return #GNUNET_OK (always)
10835 */
10836static int
10837free_validation_state_cb (void *cls,
10838 const struct GNUNET_PeerIdentity *pid,
10839 void *value)
10840{
10841 struct ValidationState *vs = value;
10842
10843 (void) cls;
10844 (void) pid;
10845 free_validation_state (vs);
10846 return GNUNET_OK;
10847}
10848
10849
10850/**
10851 * Free pending acknowledgement.
10852 *
10853 * @param cls NULL
10854 * @param key unused
10855 * @param value a `struct PendingAcknowledgement`
10856 * @return #GNUNET_OK (always)
10857 */
10858static int
10859free_pending_ack_cb (void *cls, const struct GNUNET_Uuid *key, void *value)
10860{
10861 struct PendingAcknowledgement *pa = value;
10862
10863 (void) cls;
10864 (void) key;
10865 free_pending_acknowledgement (pa);
10866 return GNUNET_OK;
10867}
10868
10869
10870/**
10871 * Free acknowledgement cummulator.
10872 *
10873 * @param cls NULL
10874 * @param pid unused
10875 * @param value a `struct AcknowledgementCummulator`
10876 * @return #GNUNET_OK (always)
10877 */
10878static int
10879free_ack_cummulator_cb (void *cls,
10880 const struct GNUNET_PeerIdentity *pid,
10881 void *value)
10882{
10883 struct AcknowledgementCummulator *ac = value;
10884
10885 (void) cls;
10886 (void) pid;
10887 GNUNET_SCHEDULER_cancel (ac->task);
10888 GNUNET_free (ac);
10889 return GNUNET_OK;
10890}
10891
10892
10893/**
10894 * Function called when the service shuts down. Unloads our plugins
10895 * and cancels pending validations.
10896 *
10897 * @param cls closure, unused
10898 */
10899static void
10900do_shutdown (void *cls)
10901{
10902 struct LearnLaunchEntry *lle;
10903
10904 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10905 "shutdown logic\n");
10906 (void) cls;
10907 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
10908 &free_neighbour_cb, NULL);
10909 if (NULL != validation_task)
10910 {
10911 GNUNET_SCHEDULER_cancel (validation_task);
10912 validation_task = NULL;
10913 }
10914 if (NULL != dvlearn_task)
10915 {
10916 GNUNET_SCHEDULER_cancel (dvlearn_task);
10917 dvlearn_task = NULL;
10918 }
10919 if (NULL != GST_stats)
10920 {
10921 GNUNET_STATISTICS_destroy (GST_stats, GNUNET_NO);
10922 GST_stats = NULL;
10923 }
10924 if (NULL != GST_my_private_key)
10925 {
10926 GNUNET_free (GST_my_private_key);
10927 GST_my_private_key = NULL;
10928 }
10929 GNUNET_CONTAINER_multipeermap_iterate (ack_cummulators,
10930 &free_ack_cummulator_cb,
10931 NULL);
10932 GNUNET_CONTAINER_multipeermap_destroy (ack_cummulators);
10933 ack_cummulators = NULL;
10934 GNUNET_CONTAINER_multiuuidmap_iterate (pending_acks,
10935 &free_pending_ack_cb,
10936 NULL);
10937 GNUNET_CONTAINER_multiuuidmap_destroy (pending_acks);
10938 pending_acks = NULL;
10939 GNUNET_break (0 == GNUNET_CONTAINER_multipeermap_size (neighbours));
10940 GNUNET_CONTAINER_multipeermap_destroy (neighbours);
10941 neighbours = NULL;
10942 GNUNET_break (0 == GNUNET_CONTAINER_multipeermap_size (links));
10943 GNUNET_CONTAINER_multipeermap_destroy (links);
10944 links = NULL;
10945 GNUNET_CONTAINER_multipeermap_iterate (backtalkers,
10946 &free_backtalker_cb,
10947 NULL);
10948 GNUNET_CONTAINER_multipeermap_destroy (backtalkers);
10949 backtalkers = NULL;
10950 GNUNET_CONTAINER_multipeermap_iterate (validation_map,
10951 &free_validation_state_cb,
10952 NULL);
10953 GNUNET_CONTAINER_multipeermap_destroy (validation_map);
10954 validation_map = NULL;
10955 while (NULL != ir_head)
10956 free_incoming_request (ir_head);
10957 GNUNET_assert (0 == ir_total);
10958 while (NULL != (lle = lle_head))
10959 {
10960 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
10961 GNUNET_free (lle);
10962 }
10963 if (NULL != peerstore)
10964 {
10965 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10966 "Disconnecting from PEERSTORE service\n");
10967 GNUNET_PEERSTORE_disconnect (peerstore, GNUNET_NO);
10968 peerstore = NULL;
10969 }
10970 GNUNET_CONTAINER_multishortmap_destroy (dvlearn_map);
10971 dvlearn_map = NULL;
10972 GNUNET_CONTAINER_heap_destroy (validation_heap);
10973 validation_heap = NULL;
10974 GNUNET_CONTAINER_multipeermap_iterate (dv_routes, &free_dv_routes_cb, NULL);
10975 GNUNET_CONTAINER_multipeermap_destroy (dv_routes);
10976 dv_routes = NULL;
10977 GNUNET_SCHEDULER_shutdown ();
10978}
10979
10980
10981static void
10982shutdown_task (void *cls)
10983{
10984 in_shutdown = GNUNET_YES;
10985
10986 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10987 "Shutdown task executed\n");
10988 if (NULL != clients_head)
10989 {
10990 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
10991 {
10992 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
10993 "client still connected: %u\n",
10994 tc->type);
10995 }
10996 }
10997 else
10998 do_shutdown (cls);
10999
11000}
11001
11002
11003/**
11004 * Initiate transport service.
11005 *
11006 * @param cls closure
11007 * @param c configuration to use
11008 * @param service the initialized service
11009 */
11010static void
11011run (void *cls,
11012 const struct GNUNET_CONFIGURATION_Handle *c,
11013 struct GNUNET_SERVICE_Handle *service)
11014{
11015 (void) cls;
11016 (void) service;
11017 /* setup globals */
11018 hello_mono_time = GNUNET_TIME_absolute_get_monotonic (c);
11019 in_shutdown = GNUNET_NO;
11020 GST_cfg = c;
11021 backtalkers = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
11022 pending_acks = GNUNET_CONTAINER_multiuuidmap_create (32768, GNUNET_YES);
11023 ack_cummulators = GNUNET_CONTAINER_multipeermap_create (256, GNUNET_YES);
11024 neighbours = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
11025 links = GNUNET_CONTAINER_multipeermap_create (512, GNUNET_YES);
11026 dv_routes = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
11027 dvlearn_map = GNUNET_CONTAINER_multishortmap_create (2 * MAX_DV_LEARN_PENDING,
11028 GNUNET_YES);
11029 validation_map = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
11030 validation_heap =
11031 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
11032 GST_my_private_key =
11033 GNUNET_CRYPTO_eddsa_key_create_from_configuration (GST_cfg);
11034 if (NULL == GST_my_private_key)
11035 {
11036 GNUNET_log (
11037 GNUNET_ERROR_TYPE_ERROR,
11038 _ (
11039 "Transport service is lacking key configuration settings. Exiting.\n"));
11040 GNUNET_SCHEDULER_shutdown ();
11041 return;
11042 }
11043 GNUNET_CRYPTO_eddsa_key_get_public (GST_my_private_key,
11044 &GST_my_identity.public_key);
11045 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
11046 "My identity is `%s'\n",
11047 GNUNET_i2s_full (&GST_my_identity));
11048 GST_stats = GNUNET_STATISTICS_create ("transport", GST_cfg);
11049 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
11050 peerstore = GNUNET_PEERSTORE_connect (GST_cfg);
11051 if (NULL == peerstore)
11052 {
11053 GNUNET_break (0);
11054 GNUNET_SCHEDULER_shutdown ();
11055 return;
11056 }
11057}
11058
11059
11060/**
11061 * Define "main" method using service macro.
11062 */
11063GNUNET_SERVICE_MAIN (
11064 "transport",
11065 GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN,
11066 &run,
11067 &client_connect_cb,
11068 &client_disconnect_cb,
11069 NULL,
11070 /* communication with applications */
11071 GNUNET_MQ_hd_fixed_size (suggest,
11072 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST,
11073 struct ExpressPreferenceMessage,
11074 NULL),
11075 GNUNET_MQ_hd_fixed_size (suggest_cancel,
11076 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST_CANCEL,
11077 struct ExpressPreferenceMessage,
11078 NULL),
11079 GNUNET_MQ_hd_var_size (request_hello_validation,
11080 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION,
11081 struct RequestHelloValidationMessage,
11082 NULL),
11083 /* communication with core */
11084 GNUNET_MQ_hd_fixed_size (client_start,
11085 GNUNET_MESSAGE_TYPE_TRANSPORT_START,
11086 struct StartMessage,
11087 NULL),
11088 GNUNET_MQ_hd_var_size (client_send,
11089 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND,
11090 struct OutboundMessage,
11091 NULL),
11092 GNUNET_MQ_hd_fixed_size (client_recv_ok,
11093 GNUNET_MESSAGE_TYPE_TRANSPORT_RECV_OK,
11094 struct RecvOkMessage,
11095 NULL),
11096 /* communication with communicators */
11097 GNUNET_MQ_hd_var_size (communicator_available,
11098 GNUNET_MESSAGE_TYPE_TRANSPORT_NEW_COMMUNICATOR,
11099 struct GNUNET_TRANSPORT_CommunicatorAvailableMessage,
11100 NULL),
11101 GNUNET_MQ_hd_var_size (communicator_backchannel,
11102 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL,
11103 struct GNUNET_TRANSPORT_CommunicatorBackchannel,
11104 NULL),
11105 GNUNET_MQ_hd_var_size (add_address,
11106 GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS,
11107 struct GNUNET_TRANSPORT_AddAddressMessage,
11108 NULL),
11109 GNUNET_MQ_hd_fixed_size (del_address,
11110 GNUNET_MESSAGE_TYPE_TRANSPORT_DEL_ADDRESS,
11111 struct GNUNET_TRANSPORT_DelAddressMessage,
11112 NULL),
11113 GNUNET_MQ_hd_var_size (incoming_msg,
11114 GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG,
11115 struct GNUNET_TRANSPORT_IncomingMessage,
11116 NULL),
11117 GNUNET_MQ_hd_fixed_size (queue_create_ok,
11118 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_OK,
11119 struct GNUNET_TRANSPORT_CreateQueueResponse,
11120 NULL),
11121 GNUNET_MQ_hd_fixed_size (queue_create_fail,
11122 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL,
11123 struct GNUNET_TRANSPORT_CreateQueueResponse,
11124 NULL),
11125 GNUNET_MQ_hd_var_size (add_queue_message,
11126 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP,
11127 struct GNUNET_TRANSPORT_AddQueueMessage,
11128 NULL),
11129 GNUNET_MQ_hd_fixed_size (update_queue_message,
11130 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_UPDATE,
11131 struct GNUNET_TRANSPORT_UpdateQueueMessage,
11132 NULL),
11133 GNUNET_MQ_hd_fixed_size (del_queue_message,
11134 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN,
11135 struct GNUNET_TRANSPORT_DelQueueMessage,
11136 NULL),
11137 GNUNET_MQ_hd_fixed_size (send_message_ack,
11138 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG_ACK,
11139 struct GNUNET_TRANSPORT_SendMessageToAck,
11140 NULL),
11141 /* communication with monitors */
11142 GNUNET_MQ_hd_fixed_size (monitor_start,
11143 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_START,
11144 struct GNUNET_TRANSPORT_MonitorStart,
11145 NULL),
11146 GNUNET_MQ_handler_end ());
11147
11148
11149/* end of file gnunet-service-transport.c */
diff --git a/src/transport/gnunet-service-transport.c b/src/transport/gnunet-service-transport.c
deleted file mode 100644
index 345a0d949..000000000
--- a/src/transport/gnunet-service-transport.c
+++ /dev/null
@@ -1,2783 +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 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
2489/**
2490 * Cancel a blacklist check.
2491 *
2492 * @param bc check to cancel
2493 */
2494void
2495GST_blacklist_test_cancel (struct GST_BlacklistCheck *bc)
2496{
2497 GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
2498 if (NULL != bc->bl_pos)
2499 {
2500 if ((CT_BLACKLIST == bc->bl_pos->type) &&
2501 (bc->bl_pos->details.blacklist.bc == bc))
2502 {
2503 /* we're at the head of the queue, remove us! */
2504 bc->bl_pos->details.blacklist.bc = NULL;
2505 }
2506 }
2507 if (NULL != bc->task)
2508 {
2509 GNUNET_SCHEDULER_cancel (bc->task);
2510 bc->task = NULL;
2511 }
2512 GNUNET_free (bc->address);
2513 GNUNET_free (bc);
2514}
2515
2516
2517/**
2518 * Function to iterate over options in the blacklisting section for a peer.
2519 *
2520 * @param cls closure
2521 * @param section name of the section
2522 * @param option name of the option
2523 * @param value value of the option
2524 */
2525static void
2526blacklist_cfg_iter (void *cls,
2527 const char *section,
2528 const char *option,
2529 const char *value)
2530{
2531 unsigned int *res = cls;
2532 struct GNUNET_PeerIdentity peer;
2533 char *plugs;
2534 char *pos;
2535
2536 if (GNUNET_OK !=
2537 GNUNET_CRYPTO_eddsa_public_key_from_string (option,
2538 strlen (option),
2539 &peer.public_key))
2540 return;
2541
2542 if ((NULL == value) || (0 == strcmp (value, "")))
2543 {
2544 /* Blacklist whole peer */
2545 GST_blacklist_add_peer (&peer, NULL);
2546 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2547 _ ("Adding blacklisting entry for peer `%s'\n"),
2548 GNUNET_i2s (&peer));
2549 }
2550 else
2551 {
2552 plugs = GNUNET_strdup (value);
2553 for (pos = strtok (plugs, " "); pos != NULL; pos = strtok (NULL, " "))
2554 {
2555 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2556 _ ("Adding blacklisting entry for peer `%s':`%s'\n"),
2557 GNUNET_i2s (&peer),
2558 pos);
2559 GST_blacklist_add_peer (&peer, pos);
2560 }
2561 GNUNET_free (plugs);
2562 }
2563 (*res)++;
2564}
2565
2566
2567/**
2568 * Read blacklist configuration
2569 *
2570 * @param cfg the configuration handle
2571 * @param my_id my peer identity
2572 */
2573static void
2574read_blacklist_configuration (const struct GNUNET_CONFIGURATION_Handle *cfg,
2575 const struct GNUNET_PeerIdentity *my_id)
2576{
2577 char cfg_sect[512];
2578 unsigned int res = 0;
2579
2580 GNUNET_snprintf (cfg_sect,
2581 sizeof(cfg_sect),
2582 "transport-blacklist-%s",
2583 GNUNET_i2s_full (my_id));
2584 GNUNET_CONFIGURATION_iterate_section_values (cfg,
2585 cfg_sect,
2586 &blacklist_cfg_iter,
2587 &res);
2588 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2589 "Loaded %u blacklisting entries from configuration\n",
2590 res);
2591}
2592
2593
2594/**
2595 * Initiate transport service.
2596 *
2597 * @param cls closure
2598 * @param c configuration to use
2599 * @param service the initialized service
2600 */
2601static void
2602run (void *cls,
2603 const struct GNUNET_CONFIGURATION_Handle *c,
2604 struct GNUNET_SERVICE_Handle *service)
2605{
2606 char *keyfile;
2607 long long unsigned int max_fd_cfg;
2608 int max_fd_rlimit;
2609 int max_fd;
2610 int friend_only;
2611
2612 /* setup globals */
2613 GST_cfg = c;
2614 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (c,
2615 "PEER",
2616 "PRIVATE_KEY",
2617 &keyfile))
2618 {
2619 GNUNET_log (
2620 GNUNET_ERROR_TYPE_ERROR,
2621 _ (
2622 "Transport service is lacking key configuration settings. Exiting.\n"));
2623 GNUNET_SCHEDULER_shutdown ();
2624 return;
2625 }
2626 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (c,
2627 "transport",
2628 "HELLO_EXPIRATION",
2629 &hello_expiration))
2630 {
2631 hello_expiration = GNUNET_CONSTANTS_HELLO_ADDRESS_EXPIRATION;
2632 }
2633 if (GNUNET_SYSERR ==
2634 GNUNET_CRYPTO_eddsa_key_from_file (keyfile,
2635 GNUNET_YES,
2636 &GST_my_private_key))
2637 {
2638 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2639 "Failed to setup peer's private key\n");
2640 GNUNET_SCHEDULER_shutdown ();
2641 GNUNET_free (keyfile);
2642 return;
2643 }
2644 GNUNET_free (keyfile);
2645 GST_stats = GNUNET_STATISTICS_create ("transport", GST_cfg);
2646 GST_peerinfo = GNUNET_PEERINFO_connect (GST_cfg);
2647 GNUNET_CRYPTO_eddsa_key_get_public (&GST_my_private_key,
2648 &GST_my_identity.public_key);
2649 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2650 "My identity is `%s'\n",
2651 GNUNET_i2s_full (&GST_my_identity));
2652
2653 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
2654 if (NULL == GST_peerinfo)
2655 {
2656 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2657 _ ("Could not access PEERINFO service. Exiting.\n"));
2658 GNUNET_SCHEDULER_shutdown ();
2659 return;
2660 }
2661
2662 max_fd_rlimit = 0;
2663#if HAVE_GETRLIMIT
2664 {
2665 struct rlimit r_file;
2666
2667 if (0 == getrlimit (RLIMIT_NOFILE, &r_file))
2668 {
2669 max_fd_rlimit = r_file.rlim_cur;
2670 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2671 "Maximum number of open files was: %u/%u\n",
2672 (unsigned int) r_file.rlim_cur,
2673 (unsigned int) r_file.rlim_max);
2674 }
2675 max_fd_rlimit =
2676 (9 * max_fd_rlimit) / 10; /* Keep 10% for rest of transport */
2677 }
2678#endif
2679 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (GST_cfg,
2680 "transport",
2681 "MAX_FD",
2682 &max_fd_cfg))
2683 max_fd_cfg = max_fd_rlimit;
2684
2685 if (max_fd_cfg > max_fd_rlimit)
2686 max_fd = max_fd_cfg;
2687 else
2688 max_fd = max_fd_rlimit;
2689 if (max_fd < DEFAULT_MAX_FDS)
2690 max_fd = DEFAULT_MAX_FDS;
2691
2692 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2693 "Limiting number of sockets to %u: validation %u, neighbors: %u\n",
2694 max_fd,
2695 (max_fd / 3),
2696 (max_fd / 3) * 2);
2697
2698 friend_only =
2699 GNUNET_CONFIGURATION_get_value_yesno (GST_cfg, "topology", "FRIENDS-ONLY");
2700 if (GNUNET_SYSERR == friend_only)
2701 friend_only = GNUNET_NO; /* According to topology defaults */
2702 /* start subsystems */
2703 /* Disable DSTJ peer */
2704 {
2705 struct GNUNET_PeerIdentity dstj;
2706 const char *ds = "DSTJBRRKZ8TBW3FGK6B0M5QXWT9WYNZ45H5MCV4HY7ST64Q8T9F0";
2707
2708 GNUNET_assert (
2709 GNUNET_OK ==
2710 GNUNET_CRYPTO_eddsa_public_key_from_string (ds,
2711 strlen (ds),
2712 &dstj.public_key));
2713 GST_blacklist_add_peer (&dstj, NULL);
2714 }
2715 read_blacklist_configuration (GST_cfg, &GST_my_identity);
2716 GST_is = GNUNET_NT_scanner_init ();
2717 GST_ats_connect = GNUNET_ATS_connectivity_init (GST_cfg);
2718 GST_ats =
2719 GNUNET_ATS_scheduling_init (GST_cfg, &ats_request_address_change, NULL);
2720 GST_ats_init ();
2721 GST_manipulation_init ();
2722 GST_plugins_load (&GST_manipulation_recv,
2723 &plugin_env_address_change_notification,
2724 &plugin_env_session_start,
2725 &plugin_env_session_end);
2726 GST_hello_start (friend_only, &process_hello_update, NULL);
2727 GST_neighbours_start ((max_fd / 3) * 2);
2728 active_stccs = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_YES);
2729 plugin_nc = GNUNET_notification_context_create (0);
2730 GST_validation_start ((max_fd / 3));
2731}
2732
2733
2734/**
2735 * Define "main" method using service macro.
2736 */
2737GNUNET_SERVICE_MAIN (
2738 "transport",
2739 GNUNET_SERVICE_OPTION_NONE,
2740 &run,
2741 &client_connect_cb,
2742 &client_disconnect_cb,
2743 NULL,
2744 GNUNET_MQ_hd_fixed_size (client_start,
2745 GNUNET_MESSAGE_TYPE_TRANSPORT_START,
2746 struct StartMessage,
2747 NULL),
2748 GNUNET_MQ_hd_var_size (client_hello,
2749 GNUNET_MESSAGE_TYPE_HELLO,
2750 struct GNUNET_MessageHeader,
2751 NULL),
2752 GNUNET_MQ_hd_var_size (client_send,
2753 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND,
2754 struct OutboundMessage,
2755 NULL),
2756 GNUNET_MQ_hd_var_size (client_address_to_string,
2757 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING,
2758 struct AddressLookupMessage,
2759 NULL),
2760 GNUNET_MQ_hd_fixed_size (client_monitor_peers,
2761 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_REQUEST,
2762 struct PeerMonitorMessage,
2763 NULL),
2764 GNUNET_MQ_hd_fixed_size (client_blacklist_init,
2765 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT,
2766 struct GNUNET_MessageHeader,
2767 NULL),
2768 GNUNET_MQ_hd_fixed_size (client_blacklist_reply,
2769 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY,
2770 struct BlacklistMessage,
2771 NULL),
2772 GNUNET_MQ_hd_fixed_size (client_set_metric,
2773 GNUNET_MESSAGE_TYPE_TRANSPORT_TRAFFIC_METRIC,
2774 struct TrafficMetricMessage,
2775 NULL),
2776 GNUNET_MQ_hd_fixed_size (client_monitor_plugins,
2777 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PLUGIN_START,
2778 struct GNUNET_MessageHeader,
2779 NULL),
2780 GNUNET_MQ_handler_end ());
2781
2782
2783/* end of file gnunet-service-transport.c */
diff --git a/src/transport/gnunet-service-transport.h b/src/transport/gnunet-service-transport.h
deleted file mode 100644
index ea9e71e4b..000000000
--- a/src/transport/gnunet-service-transport.h
+++ /dev/null
@@ -1,234 +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.h
23 * @brief globals
24 * @author Christian Grothoff
25 */
26#ifndef GNUNET_SERVICE_TRANSPORT_H
27#define GNUNET_SERVICE_TRANSPORT_H
28
29#include "gnunet_util_lib.h"
30#include "gnunet_statistics_service.h"
31#include "gnunet_ats_service.h"
32#include "gnunet_transport_service.h"
33
34#define VERBOSE_VALIDATION GNUNET_YES
35
36/**
37 * Statistics handle.
38 */
39extern struct GNUNET_STATISTICS_Handle *GST_stats;
40
41/**
42 * Configuration handle.
43 */
44extern const struct GNUNET_CONFIGURATION_Handle *GST_cfg;
45
46/**
47 * Configuration handle.
48 */
49extern struct GNUNET_PeerIdentity GST_my_identity;
50
51/**
52 * Handle to peerinfo service.
53 */
54extern struct GNUNET_PEERINFO_Handle *GST_peerinfo;
55
56/**
57 * Our private key.
58 */
59extern struct GNUNET_CRYPTO_EddsaPrivateKey GST_my_private_key;
60
61/**
62 * ATS handle.
63 */
64extern struct GNUNET_ATS_SchedulingHandle *GST_ats;
65
66/**
67 * ATS connectivity handle.
68 */
69extern struct GNUNET_ATS_ConnectivityHandle *GST_ats_connect;
70
71/**
72 * Interface scanner determines our LAN address range(s).
73 */
74extern struct GNUNET_NT_InterfaceScanner *GST_is;
75
76
77/**
78 * Function to call when a peer's address has changed
79 *
80 * @param cls closure
81 * @param peer peer this update is about,
82 * @param address address, NULL for disconnect notification
83 */
84typedef void
85(*GNUNET_TRANSPORT_NeighbourChangeCallback) (void *cls,
86 const struct
87 GNUNET_PeerIdentity *peer,
88 const struct
89 GNUNET_HELLO_Address *address,
90 enum GNUNET_TRANSPORT_PeerState
91 state,
92 struct GNUNET_TIME_Absolute
93 state_timeout,
94 struct GNUNET_BANDWIDTH_Value32NBO
95 bandwidth_in,
96 struct GNUNET_BANDWIDTH_Value32NBO
97 bandwidth_out);
98
99
100/**
101 * Continuation called from a blacklist test.
102 *
103 * @param cls closure
104 * @param peer identity of peer that was tested
105 * @param address address associated with the request
106 * @param session session associated with the request
107 * @param result #GNUNET_OK if the connection is allowed,
108 * #GNUNET_NO if not,
109 * #GNUNET_SYSERR if operation was aborted
110 */
111typedef void
112(*GST_BlacklistTestContinuation) (void *cls,
113 const struct GNUNET_PeerIdentity *peer,
114 const struct GNUNET_HELLO_Address *address,
115 struct GNUNET_ATS_Session *session,
116 int result);
117
118
119/**
120 * Add the given peer to the blacklist (for the given transport).
121 *
122 * @param peer peer to blacklist
123 * @param transport_name transport to blacklist for this peer, NULL for all
124 */
125void
126GST_blacklist_add_peer (const struct GNUNET_PeerIdentity *peer,
127 const char *transport_name);
128
129
130/**
131 * Handle to an active blacklist check.
132 */
133struct GST_BlacklistCheck;
134
135
136/**
137 * Test if a peer/transport combination is blacklisted.
138 *
139 * @param peer the identity of the peer to test
140 * @param transport_name name of the transport to test, never NULL
141 * @param cont function to call with result
142 * @param cont_cls closure for @a cont
143 * @param address address to pass back to @a cont, can be NULL
144 * @param session session to pass back to @a cont, can be NULL
145 * @return handle to the blacklist check, NULL if the decision
146 * was made instantly and @a cont was already called
147 */
148struct GST_BlacklistCheck *
149GST_blacklist_test_allowed (const struct GNUNET_PeerIdentity *peer,
150 const char *transport_name,
151 GST_BlacklistTestContinuation cont,
152 void *cont_cls,
153 const struct GNUNET_HELLO_Address *address,
154 struct GNUNET_ATS_Session *session);
155
156
157/**
158 * Abort blacklist if @a address and @a session match.
159 *
160 * @param address address used to abort matching checks
161 * @param session session used to abort matching checks
162 */
163void
164GST_blacklist_abort_matching (const struct GNUNET_HELLO_Address *address,
165 struct GNUNET_ATS_Session *session);
166
167/**
168 * Cancel a blacklist check.
169 *
170 * @param bc check to cancel
171 */
172void
173GST_blacklist_test_cancel (struct GST_BlacklistCheck *bc);
174
175
176/**
177 * Function called by the transport for each received message.
178 *
179 * @param cls closure, const char* with the name of the plugin we received the message from
180 * @param address address and (claimed) identity of the other peer
181 * @param session identifier used for this session (NULL for plugins
182 * that do not offer bi-directional communication to the sender
183 * using the same "connection")
184 * @param message the message, NULL if we only care about
185 * learning about the delay until we should receive again
186 * @return how long the plugin should wait until receiving more data
187 * (plugins that do not support this, can ignore the return value)
188 */
189struct GNUNET_TIME_Relative
190GST_receive_callback (void *cls,
191 const struct GNUNET_HELLO_Address *address,
192 struct GNUNET_ATS_Session *session,
193 const struct GNUNET_MessageHeader *message);
194
195/**
196 * Broadcast the given message to all of our clients.
197 *
198 * @param msg message to broadcast
199 * @param may_drop #GNUNET_YES if the message can be dropped / is payload
200 */
201void
202GST_clients_broadcast (const struct GNUNET_MessageHeader *msg,
203 int may_drop);
204
205
206/**
207 * Broadcast the new active address to all clients monitoring the peer.
208 *
209 * @param peer peer this update is about (never NULL)
210 * @param address address, NULL on disconnect
211 * @param state the current state of the peer
212 * @param state_timeout the time out for the state
213 */
214void
215GST_clients_broadcast_peer_notification (const struct GNUNET_PeerIdentity *peer,
216 const struct
217 GNUNET_HELLO_Address *address,
218 enum GNUNET_TRANSPORT_PeerState state,
219 struct GNUNET_TIME_Absolute
220 state_timeout);
221
222
223/**
224 * Notify all clients about a disconnect, and cancel
225 * pending SEND_OK messages for this peer.
226 *
227 * @param peer peer that disconnected
228 */
229void
230GST_clients_broadcast_disconnect (const struct GNUNET_PeerIdentity *peer);
231
232
233#endif
234/* end of file gnunet-service-transport_plugins.h */
diff --git a/src/transport/gnunet-service-transport_ats.c b/src/transport/gnunet-service-transport_ats.c
deleted file mode 100644
index 130311e15..000000000
--- a/src/transport/gnunet-service-transport_ats.c
+++ /dev/null
@@ -1,920 +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
480/**
481 * Notify ATS about the new address including the network this address is
482 * located in. The address must NOT be inbound and must be new to ATS.
483 *
484 * @param address the address
485 * @param prop performance information
486 */
487void
488GST_ats_add_address (const struct GNUNET_HELLO_Address *address,
489 const struct GNUNET_ATS_Properties *prop)
490{
491 struct GNUNET_ATS_AddressRecord *ar;
492 struct AddressInfo *ai;
493
494 if (0 ==
495 memcmp (&GST_my_identity,
496 &address->peer,
497 sizeof(struct GNUNET_PeerIdentity)))
498 return; /* our own, ignore! */
499 /* validadte address */
500 if (NULL == address->transport_name)
501 {
502 GNUNET_break (0);
503 return;
504 }
505 GNUNET_assert (GNUNET_YES !=
506 GNUNET_HELLO_address_check_option (address,
507 GNUNET_HELLO_ADDRESS_INFO_INBOUND));
508 ai = find_ai_no_session (address);
509 GNUNET_assert (NULL == ai);
510 GNUNET_break (GNUNET_NT_UNSPECIFIED != prop->scope);
511
512 /* address seems sane, let's tell ATS */
513 LOG (GNUNET_ERROR_TYPE_INFO,
514 "Notifying ATS about peer %s's new address `%s'\n",
515 GNUNET_i2s (&address->peer),
516 GST_plugins_a2s (address));
517 ar = GNUNET_ATS_address_add (GST_ats,
518 address,
519 NULL,
520 prop);
521 GNUNET_assert (NULL != ar);
522 ai = GNUNET_new (struct AddressInfo);
523 ai->address = GNUNET_HELLO_address_copy (address);
524 ai->ar = ar;
525 ai->properties = *prop;
526 (void) GNUNET_CONTAINER_multipeermap_put (p2a,
527 &ai->address->peer,
528 ai,
529 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
530 publish_p2a_stat_update ();
531}
532
533
534/**
535 * Notify ATS about a new @a session now existing for the given
536 * @a address. Essentially, an outbound @a address was used
537 * to establish a @a session. It is safe to call this function
538 * repeatedly for the same @a address and @a session pair.
539 *
540 * @param address the address
541 * @param session the session
542 */
543void
544GST_ats_new_session (const struct GNUNET_HELLO_Address *address,
545 struct GNUNET_ATS_Session *session)
546{
547 struct AddressInfo *ai;
548
549 if (0 ==
550 memcmp (&GST_my_identity,
551 &address->peer,
552 sizeof(struct GNUNET_PeerIdentity)))
553 return; /* our own, ignore! */
554 ai = find_ai (address, NULL);
555 if (NULL == ai)
556 {
557 /* We may simply already be aware of the session, even if some
558 other part of the code could not tell if it just created a new
559 session or just got one recycled from the plugin; hence, we may
560 be called with "new" session even for an "old" session; in that
561 case, check that this is the case, but just ignore it. */GNUNET_assert (NULL != (find_ai (address, session)));
562 return;
563 }
564 GNUNET_assert (NULL == ai->session);
565 ai->session = session;
566 LOG (GNUNET_ERROR_TYPE_DEBUG,
567 "Telling ATS about new session for peer %s\n",
568 GNUNET_i2s (&address->peer));
569 /* Note that the address might currently be blocked; we only
570 tell ATS about the session if the address is currently not
571 blocked; otherwise, ATS will be told about the session on
572 unblock. */
573 if (NULL != ai->ar)
574 GNUNET_ATS_address_add_session (ai->ar,
575 session);
576 else
577 GNUNET_assert (NULL != ai->unblock_task);
578}
579
580
581/**
582 * Release memory used by the given address data.
583 *
584 * @param ai the `struct AddressInfo`
585 */
586static void
587destroy_ai (struct AddressInfo *ai)
588{
589 GNUNET_assert (NULL == ai->session);
590 if (NULL != ai->unblock_task)
591 {
592 GNUNET_SCHEDULER_cancel (ai->unblock_task);
593 ai->unblock_task = NULL;
594 num_blocked--;
595 }
596 GNUNET_assert (GNUNET_YES ==
597 GNUNET_CONTAINER_multipeermap_remove (p2a,
598 &ai->address->peer,
599 ai));
600 LOG (GNUNET_ERROR_TYPE_DEBUG,
601 "Telling ATS to destroy address from peer %s\n",
602 GNUNET_i2s (&ai->address->peer));
603 if (NULL != ai->ar)
604 {
605 GNUNET_ATS_address_destroy (ai->ar);
606 ai->ar = NULL;
607 }
608 publish_p2a_stat_update ();
609 GNUNET_HELLO_address_free (ai->address);
610 GNUNET_free (ai);
611}
612
613
614/**
615 * Notify ATS that the @a session (but not the @a address) of
616 * a given @a address is no longer relevant. (The @a session
617 * went down.) This function may be called even if for the
618 * respective outbound address #GST_ats_new_session() was
619 * never called and thus the pair is unknown to ATS. In this
620 * case, the call is simply ignored.
621 *
622 * @param address the address
623 * @param session the session
624 */
625void
626GST_ats_del_session (const struct GNUNET_HELLO_Address *address,
627 struct GNUNET_ATS_Session *session)
628{
629 struct AddressInfo *ai;
630
631 if (0 ==
632 memcmp (&GST_my_identity,
633 &address->peer,
634 sizeof(struct GNUNET_PeerIdentity)))
635 return; /* our own, ignore! */
636 if (NULL == session)
637 {
638 GNUNET_break (0);
639 return;
640 }
641 ai = find_ai (address,
642 session);
643 if (NULL == ai)
644 {
645 /* We sometimes create sessions just for sending a PING,
646 and if those are destroyed they were never known to
647 ATS which means we end up here (however, in this
648 case, the address must be an outbound address). */
649 GNUNET_break (GNUNET_YES !=
650 GNUNET_HELLO_address_check_option (address,
651 GNUNET_HELLO_ADDRESS_INFO_INBOUND));
652 return;
653 }
654 GNUNET_assert (session == ai->session);
655 ai->session = NULL;
656 LOG (GNUNET_ERROR_TYPE_DEBUG,
657 "Telling ATS to destroy session %p from peer %s\n",
658 session,
659 GNUNET_i2s (&address->peer));
660 if (GNUNET_YES == ai->expired)
661 {
662 /* last reason to keep this 'ai' around is now gone, the
663 session is dead as well, clean up */
664 if (NULL != ai->ar)
665 {
666 /* Address expired but not blocked, and thus 'ar' was still
667 live because of the session; deleting just the session
668 will do for an inbound session, but for an outbound we
669 then also need to destroy the address with ATS. */
670 if (GNUNET_NO ==
671 GNUNET_ATS_address_del_session (ai->ar,
672 session))
673 {
674 GNUNET_ATS_address_destroy (ai->ar);
675 }
676 /* "ar" has been freed, regardless how the branch
677 above played out: it was either freed in
678 #GNUNET_ATS_address_del_session() because it was
679 incoming, or explicitly in
680 #GNUNET_ATS_address_del_session(). */ai->ar = NULL;
681 }
682 destroy_ai (ai);
683 return;
684 }
685
686 if (NULL == ai->ar)
687 {
688 /* If ATS doesn't know about the address/session, this means
689 this address was blocked. */
690 if (GNUNET_YES ==
691 GNUNET_HELLO_address_check_option (address,
692 GNUNET_HELLO_ADDRESS_INFO_INBOUND))
693 {
694 /* This was a blocked inbound session, which now lost the
695 session. But inbound addresses are by themselves useless,
696 so we must forget about the address as well. */
697 destroy_ai (ai);
698 return;
699 }
700 /* Otherwise, we are done as we have set `ai->session` to NULL
701 already and ATS will simply not be told about the session when
702 the connection is unblocked and the outbound address becomes
703 available again. . */
704 return;
705 }
706
707 /* This is the "simple" case where ATS knows about the session and
708 the address is neither blocked nor expired. Delete the session,
709 and if it was inbound, free the address as well. */
710 if (GNUNET_YES ==
711 GNUNET_ATS_address_del_session (ai->ar,
712 session))
713 {
714 /* This was an inbound address, the session is now gone, so we
715 need to also forget about the address itself. */
716 ai->ar = NULL;
717 destroy_ai (ai);
718 }
719}
720
721
722/**
723 * Notify ATS about DV @a distance change to an @a address.
724 * Does nothing if the @a address is not known to us.
725 *
726 * @param address the address
727 * @param distance new distance value
728 */
729void
730GST_ats_update_distance (const struct GNUNET_HELLO_Address *address,
731 uint32_t distance)
732{
733 struct AddressInfo *ai;
734
735 ai = find_ai_no_session (address);
736 if (NULL == ai)
737 {
738 /* We do not know about this address, do nothing. */
739 return;
740 }
741 LOG (GNUNET_ERROR_TYPE_DEBUG,
742 "Updated distance for peer `%s' to %u\n",
743 GNUNET_i2s (&address->peer),
744 distance);
745 ai->properties.distance = distance;
746 /* Give manipulation its chance to change metrics */
747 GST_manipulation_manipulate_metrics (address,
748 ai->session,
749 &ai->properties);
750 /* Address may be blocked, only give ATS if address is
751 currently active. */
752 if (NULL != ai->ar)
753 GNUNET_ATS_address_update (ai->ar,
754 &ai->properties);
755}
756
757
758/**
759 * Notify ATS about @a delay changes to properties of an @a address.
760 * Does nothing if the @a address is not known to us.
761 *
762 * @param address the address
763 * @param delay new delay value
764 */
765void
766GST_ats_update_delay (const struct GNUNET_HELLO_Address *address,
767 struct GNUNET_TIME_Relative delay)
768{
769 struct AddressInfo *ai;
770
771 ai = find_ai_no_session (address);
772 if (NULL == ai)
773 {
774 /* We do not know about this address, do nothing. */
775 return;
776 }
777 LOG (GNUNET_ERROR_TYPE_DEBUG,
778 "Updated latency for peer `%s' to %s\n",
779 GNUNET_i2s (&address->peer),
780 GNUNET_STRINGS_relative_time_to_string (delay,
781 GNUNET_YES));
782 ai->properties.delay = delay;
783 /* Give manipulation its chance to change metrics */
784 GST_manipulation_manipulate_metrics (address,
785 ai->session,
786 &ai->properties);
787 /* Address may be blocked, only give ATS if address is
788 currently active. */
789 if (NULL != ai->ar)
790 GNUNET_ATS_address_update (ai->ar,
791 &ai->properties);
792}
793
794
795/**
796 * Notify ATS about utilization changes to an @a address.
797 * Does nothing if the @a address is not known to us.
798 *
799 * @param address our information about the address
800 * @param bps_in new utilization inbound
801 * @param bps_out new utilization outbound
802 */
803void
804GST_ats_update_utilization (const struct GNUNET_HELLO_Address *address,
805 uint32_t bps_in,
806 uint32_t bps_out)
807{
808 struct AddressInfo *ai;
809
810 ai = find_ai_no_session (address);
811 if (NULL == ai)
812 {
813 /* We do not know about this address, do nothing. */
814 return;
815 }
816 LOG (GNUNET_ERROR_TYPE_DEBUG,
817 "Updating utilization for peer `%s' address %s: %u/%u\n",
818 GNUNET_i2s (&address->peer),
819 GST_plugins_a2s (address),
820 (unsigned int) bps_in,
821 (unsigned int) bps_out);
822 ai->properties.utilization_in = bps_in;
823 ai->properties.utilization_out = bps_out;
824 /* Give manipulation its chance to change metrics */
825 GST_manipulation_manipulate_metrics (address,
826 ai->session,
827 &ai->properties);
828 /* Address may be blocked, only give ATS if address is
829 currently active. */
830 if (NULL != ai->ar)
831 GNUNET_ATS_address_update (ai->ar,
832 &ai->properties);
833}
834
835
836/**
837 * Notify ATS that the address has expired and thus cannot
838 * be used any longer. This function must only be called
839 * if the corresponding session is already gone.
840 *
841 * @param address the address
842 */
843void
844GST_ats_expire_address (const struct GNUNET_HELLO_Address *address)
845{
846 struct AddressInfo *ai;
847
848 if (0 ==
849 memcmp (&GST_my_identity,
850 &address->peer,
851 sizeof(struct GNUNET_PeerIdentity)))
852 return; /* our own, ignore! */
853 LOG (GNUNET_ERROR_TYPE_DEBUG,
854 "Address %s of peer %s expired\n",
855 GST_plugins_a2s (address),
856 GNUNET_i2s (&address->peer));
857 ai = find_ai_no_session (address);
858 if (NULL == ai)
859 {
860 GNUNET_assert (0);
861 return;
862 }
863 if (NULL != ai->session)
864 {
865 /* Got an active session, just remember the expiration
866 and act upon it when the session goes down. */
867 ai->expired = GNUNET_YES;
868 return;
869 }
870 /* Address expired, no session, free resources */
871 destroy_ai (ai);
872}
873
874
875/**
876 * Initialize ATS subsystem.
877 */
878void
879GST_ats_init ()
880{
881 p2a = GNUNET_CONTAINER_multipeermap_create (4, GNUNET_YES);
882}
883
884
885/**
886 * Release memory used by the given address data.
887 *
888 * @param cls NULL
889 * @param key which peer is this about
890 * @param value the `struct AddressInfo`
891 * @return #GNUNET_OK (continue to iterate)
892 */
893static int
894destroy_ai_cb (void *cls,
895 const struct GNUNET_PeerIdentity *key,
896 void *value)
897{
898 struct AddressInfo *ai = value;
899
900 destroy_ai (ai);
901 return GNUNET_OK;
902}
903
904
905/**
906 * Shutdown ATS subsystem.
907 */
908void
909GST_ats_done ()
910{
911 GNUNET_CONTAINER_multipeermap_iterate (p2a,
912 &destroy_ai_cb,
913 NULL);
914 publish_p2a_stat_update ();
915 GNUNET_CONTAINER_multipeermap_destroy (p2a);
916 p2a = NULL;
917}
918
919
920/* 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 d536714ec..000000000
--- a/src/transport/gnunet-service-transport_ats.h
+++ /dev/null
@@ -1,204 +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 this 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 session the session
158 * @param delay new delay value
159 */
160void
161GST_ats_update_delay (const struct GNUNET_HELLO_Address *address,
162 struct GNUNET_TIME_Relative delay);
163
164
165/**
166 * Notify ATS about DV @a distance change to an @a address.
167 * Does nothing if the @a address is not known to us.
168 *
169 * @param address the address
170 * @param distance new distance value
171 */
172void
173GST_ats_update_distance (const struct GNUNET_HELLO_Address *address,
174 uint32_t distance);
175
176
177/**
178 * Notify ATS that the @a session (but not the @a address) of
179 * a given @a address is no longer relevant. (The @a session
180 * went down.) This function may be called even if for the
181 * respective outbound address #GST_ats_new_session() was
182 * never called and thus the pair is unknown to ATS. In this
183 * case, the call is simply ignored.
184 *
185 * @param address the address
186 * @param session the session
187 */
188void
189GST_ats_del_session (const struct GNUNET_HELLO_Address *address,
190 struct GNUNET_ATS_Session *session);
191
192
193/**
194 * Notify ATS that the address has expired and thus cannot
195 * be used any longer. This function must only be called
196 * if the corresponding session is already gone.
197 *
198 * @param address the address
199 */
200void
201GST_ats_expire_address (const struct GNUNET_HELLO_Address *address);
202
203
204#endif
diff --git a/src/transport/gnunet-service-transport_hello.c b/src/transport/gnunet-service-transport_hello.c
deleted file mode 100644
index 472c77c27..000000000
--- a/src/transport/gnunet-service-transport_hello.c
+++ /dev/null
@@ -1,368 +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
337/**
338 * Test if a particular address is one of ours.
339 *
340 * @param address address to test
341 * @param sig location where to cache PONG signatures for this address [set]
342 * @param sig_expiration how long until the current 'sig' expires?
343 * (ZERO if sig was never created) [set]
344 * @return #GNUNET_YES if this is one of our addresses,
345 * #GNUNET_NO if not
346 */
347int
348GST_hello_test_address (const struct GNUNET_HELLO_Address *address,
349 struct GNUNET_CRYPTO_EddsaSignature **sig,
350 struct GNUNET_TIME_Absolute **sig_expiration)
351{
352 struct OwnAddressList *al;
353
354 for (al = oal_head; al != NULL; al = al->next)
355 if (0 == GNUNET_HELLO_address_cmp (address,
356 al->address))
357 {
358 *sig = &al->pong_signature;
359 *sig_expiration = &al->pong_sig_expires;
360 return GNUNET_YES;
361 }
362 *sig = NULL;
363 *sig_expiration = NULL;
364 return GNUNET_NO;
365}
366
367
368/* 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 04d1774c0..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 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 prop[IN|OUT] 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 ca1b4d1da..000000000
--- a/src/transport/gnunet-service-transport_neighbours.c
+++ /dev/null
@@ -1,3971 +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
1771/**
1772 * Transmit a message to the given target using the active connection.
1773 *
1774 * @param target destination
1775 * @param msg message to send
1776 * @param msg_size number of bytes in msg
1777 * @param timeout when to fail with timeout
1778 * @param cont function to call when done
1779 * @param cont_cls closure for @a cont
1780 */
1781void
1782GST_neighbours_send (const struct GNUNET_PeerIdentity *target,
1783 const void *msg,
1784 size_t msg_size,
1785 struct GNUNET_TIME_Relative timeout,
1786 GST_NeighbourSendContinuation cont,
1787 void *cont_cls)
1788{
1789 struct NeighbourMapEntry *n;
1790 struct MessageQueue *mq;
1791
1792 /* All ove these cases should never happen; they are all API violations.
1793 But we check anyway, just to be sure. */
1794 if (NULL == (n = lookup_neighbour (target)))
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 if (GNUNET_YES != test_connected (n))
1805 {
1806 GNUNET_break (0);
1807 if (NULL != cont)
1808 cont (cont_cls,
1809 GNUNET_SYSERR,
1810 msg_size,
1811 0);
1812 return;
1813 }
1814 bytes_in_send_queue += msg_size;
1815 GNUNET_STATISTICS_set (GST_stats,
1816 gettext_noop
1817 ("# bytes in message queue for other peers"),
1818 bytes_in_send_queue, GNUNET_NO);
1819 mq = GNUNET_malloc (sizeof(struct MessageQueue) + msg_size);
1820 mq->cont = cont;
1821 mq->cont_cls = cont_cls;
1822 GNUNET_memcpy (&mq[1], msg, msg_size);
1823 mq->message_buf = (const char *) &mq[1];
1824 mq->message_buf_size = msg_size;
1825 mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1826
1827 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1828 "Enqueueing %u bytes to send to peer %s\n",
1829 (unsigned int) msg_size,
1830 GNUNET_i2s (target));
1831 GNUNET_CONTAINER_DLL_insert_tail (n->messages_head,
1832 n->messages_tail,
1833 mq);
1834 if (NULL != n->task)
1835 GNUNET_SCHEDULER_cancel (n->task);
1836 n->task = GNUNET_SCHEDULER_add_now (&master_task, n);
1837}
1838
1839
1840/**
1841 * Continuation called from our attempt to transmitted our
1842 * #GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_SYN to the specified @a
1843 * target. Continue processing based on the @a result. Specifically,
1844 * if we failed to transmit, discard the address we used.
1845 *
1846 * @param cls NULL
1847 * @param target which peer received the transmission
1848 * @param result #GNUNET_OK if sending worked
1849 * @param size_payload how many bytes of payload were sent (ignored)
1850 * @param size_on_wire how much bandwidth was consumed on the wire (ignored)
1851 */
1852static void
1853send_session_syn_cont (void *cls,
1854 const struct GNUNET_PeerIdentity *target,
1855 int result,
1856 size_t size_payload,
1857 size_t size_on_wire)
1858{
1859 struct NeighbourMapEntry *n;
1860
1861 (void) cls;
1862 (void) size_payload;
1863 (void) size_on_wire;
1864 n = lookup_neighbour (target);
1865 if (NULL == n)
1866 {
1867 /* SYN continuation was called after neighbor was freed,
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
1873 if ((GNUNET_TRANSPORT_PS_SYN_SENT != n->state) &&
1874 (GNUNET_TRANSPORT_PS_RECONNECT_SENT != n->state) &&
1875 (GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT != n->state))
1876 {
1877 /* SYN continuation was called after neighbor changed state,
1878 * for example due to a time out for the state or the session
1879 * used was already terminated: nothing to do here... */
1880 return;
1881 }
1882 if (GNUNET_OK == result)
1883 return;
1884
1885 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1886 _ ("Failed to send SYN message to peer `%s'\n"),
1887 GNUNET_i2s (target));
1888 switch (n->state)
1889 {
1890 case GNUNET_TRANSPORT_PS_SYN_SENT:
1891 /* Remove address and request an additional one */
1892 unset_primary_address (n);
1893 set_state_and_timeout (n,
1894 GNUNET_TRANSPORT_PS_INIT_ATS,
1895 GNUNET_TIME_relative_to_absolute (
1896 FAST_RECONNECT_TIMEOUT));
1897 break;
1898
1899 case GNUNET_TRANSPORT_PS_RECONNECT_SENT:
1900 /* Remove address and request an additional one */
1901 unset_primary_address (n);
1902 set_state_and_timeout (n,
1903 GNUNET_TRANSPORT_PS_RECONNECT_ATS,
1904 GNUNET_TIME_relative_to_absolute (
1905 ATS_RESPONSE_TIMEOUT));
1906 break;
1907
1908 case GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT:
1909 /* Remove address and request and go back to primary address */
1910 GNUNET_STATISTICS_update (GST_stats,
1911 gettext_noop (
1912 "# Failed attempts to switch addresses (failed to send SYN CONT)"),
1913 1,
1914 GNUNET_NO);
1915 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1916 "Switch failed, cleaning up alternative address\n");
1917 free_address (&n->alternative_address);
1918 set_state_and_timeout (n,
1919 GNUNET_TRANSPORT_PS_CONNECTED,
1920 GNUNET_TIME_relative_to_absolute (
1921 ATS_RESPONSE_TIMEOUT));
1922 break;
1923
1924 default:
1925 disconnect_neighbour (n);
1926 break;
1927 }
1928}
1929
1930
1931/**
1932 * Send a SYN message via the given address.
1933 *
1934 * @param na address to use
1935 */
1936static void
1937send_syn (struct NeighbourAddress *na)
1938{
1939 struct GNUNET_TRANSPORT_PluginFunctions *papi;
1940 struct TransportSynMessage connect_msg;
1941 struct NeighbourMapEntry *n;
1942
1943 GNUNET_assert (NULL != na->session);
1944 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1945 "Sending SYN message to peer `%s' at %s\n",
1946 GNUNET_i2s (&na->address->peer),
1947 GST_plugins_a2s (na->address));
1948
1949 papi = GST_plugins_find (na->address->transport_name);
1950 GNUNET_assert (NULL != papi);
1951 GNUNET_STATISTICS_update (GST_stats,
1952 gettext_noop
1953 ("# SYN messages sent"),
1954 1, GNUNET_NO);
1955 na->connect_timestamp = GNUNET_TIME_absolute_get ();
1956 connect_msg.header.size = htons (sizeof(struct TransportSynMessage));
1957 connect_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_SYN);
1958 connect_msg.reserved = htonl (0);
1959 connect_msg.timestamp = GNUNET_TIME_absolute_hton (na->connect_timestamp);
1960 if (-1 ==
1961 papi->send (papi->cls,
1962 na->session,
1963 (const char *) &connect_msg,
1964 sizeof(struct TransportSynMessage),
1965 UINT_MAX,
1966 SETUP_CONNECTION_TIMEOUT,
1967 &send_session_syn_cont, NULL))
1968 {
1969 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1970 _ ("Failed to transmit SYN message to %s\n"),
1971 GST_plugins_a2s (na->address));
1972 n = lookup_neighbour (&na->address->peer);
1973 if (NULL == n)
1974 {
1975 GNUNET_break (0);
1976 return;
1977 }
1978 switch (n->state)
1979 {
1980 case GNUNET_TRANSPORT_PS_SYN_SENT:
1981 /* Remove address and request and additional one */
1982 GNUNET_assert (na == &n->primary_address);
1983 unset_primary_address (n);
1984 set_state_and_timeout (n,
1985 GNUNET_TRANSPORT_PS_INIT_ATS,
1986 GNUNET_TIME_relative_to_absolute (
1987 FAST_RECONNECT_TIMEOUT));
1988 /* Hard failure to send the SYN message with this address:
1989 Destroy address and session */
1990 break;
1991
1992 case GNUNET_TRANSPORT_PS_RECONNECT_SENT:
1993 /* Remove address and request an additional one */
1994 GNUNET_assert (na == &n->primary_address);
1995 unset_primary_address (n);
1996 set_state_and_timeout (n,
1997 GNUNET_TRANSPORT_PS_RECONNECT_ATS,
1998 GNUNET_TIME_relative_to_absolute (
1999 ATS_RESPONSE_TIMEOUT));
2000 break;
2001
2002 case GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT:
2003 GNUNET_assert (na == &n->alternative_address);
2004 GNUNET_STATISTICS_update (GST_stats,
2005 gettext_noop (
2006 "# Failed attempts to switch addresses (failed to send SYN)"),
2007 1,
2008 GNUNET_NO);
2009 /* Remove address and request an additional one */
2010 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2011 "Switch failed, cleaning up alternative address\n");
2012 free_address (&n->alternative_address);
2013 set_state_and_timeout (n,
2014 GNUNET_TRANSPORT_PS_CONNECTED,
2015 GNUNET_TIME_relative_to_absolute (
2016 ATS_RESPONSE_TIMEOUT));
2017 break;
2018
2019 default:
2020 GNUNET_break (0);
2021 disconnect_neighbour (n);
2022 break;
2023 }
2024 return;
2025 }
2026 GST_neighbours_notify_data_sent (na->address,
2027 na->session,
2028 sizeof(struct TransportSynMessage));
2029}
2030
2031
2032/**
2033 * Continuation called from our attempt to transmitted our
2034 * #GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_SYN_ACK to the specified @a
2035 * target. Continue processing based on the @a result. Specifically,
2036 * if we failed to transmit, discard the address we used.
2037 *
2038 * @param cls NULL
2039 * @param target which peer received the transmission
2040 * @param result #GNUNET_OK if sending worked
2041 * @param size_payload how many bytes of payload were sent (ignored)
2042 * @param size_on_wire how much bandwidth was consumed on the wire (ignored)
2043 */
2044static void
2045send_session_syn_ack_cont (void *cls,
2046 const struct GNUNET_PeerIdentity *target,
2047 int result,
2048 size_t size_payload,
2049 size_t size_on_wire)
2050{
2051 struct NeighbourMapEntry *n;
2052
2053 (void) cls;
2054 (void) size_payload;
2055 (void) size_on_wire;
2056 n = lookup_neighbour (target);
2057 if (NULL == n)
2058 {
2059 /* SYN_ACK continuation was called after neighbor was freed,
2060 * for example due to a time out for the state or the session
2061 * used was already terminated: nothing to do here... */
2062 return;
2063 }
2064
2065 if (GNUNET_TRANSPORT_PS_SYN_RECV_ACK != n->state)
2066 {
2067 /* SYN_ACK continuation was called after neighbor changed state,
2068 * for example due to a time out for the state or the session
2069 * used was already terminated: nothing to do here... */
2070 return;
2071 }
2072 if (GNUNET_OK == result)
2073 return;
2074
2075 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2076 _ (
2077 "Failed to send SYN_ACK message to peer `%s' using address `%s'\n"),
2078 GNUNET_i2s (target),
2079 GST_plugins_a2s (n->primary_address.address));
2080
2081 /* Remove address and request and additional one */
2082 /* FIXME: what if the neighbour's primary address
2083 changed in the meantime? Might want to instead
2084 pass "something" around in closure to be sure. */
2085 unset_primary_address (n);
2086 n->ack_state = ACK_SEND_SYN_ACK;
2087 set_state_and_timeout (n,
2088 GNUNET_TRANSPORT_PS_SYN_RECV_ATS,
2089 GNUNET_TIME_relative_to_absolute (
2090 ATS_RESPONSE_TIMEOUT));
2091}
2092
2093
2094/**
2095 * Send a SYN_ACK message via the given address.
2096 *
2097 * @param na address and session to use
2098 * @param timestamp timestamp to use for the ACK message
2099 * @return #GNUNET_SYSERR if sending immediately failed, #GNUNET_OK otherwise
2100 */
2101static void
2102send_syn_ack_message (struct NeighbourAddress *na,
2103 struct GNUNET_TIME_Absolute timestamp)
2104{
2105 const struct GNUNET_HELLO_Address *address = na->address;
2106 struct GNUNET_ATS_Session *session = na->session;
2107 struct GNUNET_TRANSPORT_PluginFunctions *papi;
2108 struct TransportSynMessage connect_msg;
2109 struct NeighbourMapEntry *n;
2110
2111 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2112 "Sending SYN_ACK to peer `%s'\n",
2113 GNUNET_i2s (&address->peer));
2114
2115 if (NULL == (papi = GST_plugins_find (address->transport_name)))
2116 {
2117 GNUNET_break (0);
2118 return;
2119 }
2120 if (NULL == session)
2121 session = papi->get_session (papi->cls,
2122 address);
2123 if (NULL == session)
2124 {
2125 GNUNET_break (0);
2126 return;
2127 }
2128 GST_ats_new_session (address,
2129 session);
2130 GNUNET_STATISTICS_update (GST_stats,
2131 gettext_noop
2132 ("# SYN_ACK messages sent"),
2133 1, GNUNET_NO);
2134 connect_msg.header.size = htons (sizeof(struct TransportSynMessage));
2135 connect_msg.header.type = htons (
2136 GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_SYN_ACK);
2137 connect_msg.reserved = htonl (0);
2138 connect_msg.timestamp = GNUNET_TIME_absolute_hton (timestamp);
2139
2140 if (GNUNET_SYSERR ==
2141 papi->send (papi->cls,
2142 session,
2143 (const char *) &connect_msg,
2144 sizeof(struct TransportSynMessage),
2145 UINT_MAX,
2146 GNUNET_TIME_UNIT_FOREVER_REL,
2147 &send_session_syn_ack_cont, NULL))
2148 {
2149 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2150 _ ("Failed to transmit SYN_ACK message to %s\n"),
2151 GST_plugins_a2s (address));
2152
2153 n = lookup_neighbour (&address->peer);
2154 if (NULL == n)
2155 {
2156 GNUNET_break (0);
2157 return;
2158 }
2159 /* Remove address and request and additional one */
2160 unset_primary_address (n);
2161 n->ack_state = ACK_SEND_SYN_ACK;
2162 set_state_and_timeout (n,
2163 GNUNET_TRANSPORT_PS_SYN_RECV_ATS,
2164 GNUNET_TIME_relative_to_absolute (
2165 ATS_RESPONSE_TIMEOUT));
2166 return;
2167 }
2168}
2169
2170
2171/**
2172 * Function called by the bandwidth tracker for a peer whenever
2173 * the tracker's state changed such that we need to recalculate
2174 * the delay for flow control. We calculate the latest delay
2175 * and inform the plugin (if applicable).
2176 *
2177 * @param cls the `struct NeighbourMapEntry` to update calculations for
2178 */
2179static void
2180inbound_bw_tracker_update (void *cls)
2181{
2182 struct NeighbourMapEntry *n = cls;
2183 struct GNUNET_TRANSPORT_PluginFunctions *papi;
2184 struct GNUNET_TIME_Relative delay;
2185 int do_forward;
2186
2187 if (NULL == n->primary_address.address)
2188 return; /* not active, ignore */
2189 papi = GST_plugins_find (n->primary_address.address->transport_name);
2190 GNUNET_assert (NULL != papi);
2191 if (NULL == papi->update_inbound_delay)
2192 return;
2193 delay = GST_neighbours_calculate_receive_delay (&n->id,
2194 0,
2195 &do_forward);
2196 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2197 "New inbound delay for peer `%s' is %llu ms\n",
2198 GNUNET_i2s (&n->id),
2199 (unsigned long long) delay.rel_value_us / 1000LL);
2200 if (NULL == n->primary_address.session)
2201 return;
2202 papi->update_inbound_delay (papi->cls,
2203 &n->id,
2204 n->primary_address.session,
2205 delay);
2206}
2207
2208
2209/**
2210 * Create a fresh entry in the neighbour map for the given peer
2211 *
2212 * @param peer peer to create an entry for
2213 * @return new neighbour map entry
2214 */
2215static struct NeighbourMapEntry *
2216setup_neighbour (const struct GNUNET_PeerIdentity *peer)
2217{
2218 struct NeighbourMapEntry *n;
2219
2220 if (0 ==
2221 memcmp (&GST_my_identity,
2222 peer,
2223 sizeof(struct GNUNET_PeerIdentity)))
2224 {
2225 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2226 "Cowardly refusing to consider myself my neighbour!\n");
2227 return NULL;
2228 }
2229 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2230 "Creating new neighbour entry for `%s'\n",
2231 GNUNET_i2s (peer));
2232 n = GNUNET_new (struct NeighbourMapEntry);
2233 n->id = *peer;
2234 n->ack_state = ACK_UNDEFINED;
2235 n->last_util_transmission = GNUNET_TIME_absolute_get ();
2236 n->neighbour_receive_quota = GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT;
2237 GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
2238 &inbound_bw_tracker_update,
2239 n,
2240 GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
2241 MAX_BANDWIDTH_CARRY_S);
2242 n->task = GNUNET_SCHEDULER_add_now (&master_task, n);
2243 set_state_and_timeout (n,
2244 GNUNET_TRANSPORT_PS_NOT_CONNECTED,
2245 GNUNET_TIME_UNIT_FOREVER_ABS);
2246 GNUNET_assert (GNUNET_OK ==
2247 GNUNET_CONTAINER_multipeermap_put (neighbours,
2248 &n->id,
2249 n,
2250 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2251 n->suggest_handle = GNUNET_ATS_connectivity_suggest (GST_ats_connect,
2252 peer,
2253 0);
2254
2255 return n;
2256}
2257
2258
2259/**
2260 * Entry in a DLL we use to keep track of pending blacklist checks.
2261 */
2262struct BlacklistCheckSwitchContext
2263{
2264 /**
2265 * DLL prev pointer.
2266 */
2267 struct BlacklistCheckSwitchContext *prev;
2268
2269 /**
2270 * DLL next pointer.
2271 */
2272 struct BlacklistCheckSwitchContext *next;
2273
2274 /**
2275 * Handle to the blacklist check we are performing.
2276 */
2277 struct GST_BlacklistCheck *blc;
2278
2279 /**
2280 * Inbound bandwidth that was assigned to @e address.
2281 */
2282 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in;
2283
2284 /**
2285 * Outbound bandwidth that was assigned to @e address.
2286 */
2287 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out;
2288};
2289
2290
2291/**
2292 * We received a 'SYN' message from the other peer.
2293 * Consider switching to it.
2294 *
2295 * @param message possibly a `struct TransportSynMessage` (check format)
2296 * @param peer identity of the peer to switch the address for
2297 * @return #GNUNET_OK if the message was fine, #GNUNET_SYSERR on serious error
2298 */
2299int
2300GST_neighbours_handle_session_syn (const struct GNUNET_MessageHeader *message,
2301 const struct GNUNET_PeerIdentity *peer)
2302{
2303 const struct TransportSynMessage *scm;
2304 struct NeighbourMapEntry *n;
2305 struct GNUNET_TIME_Absolute ts;
2306
2307 if (ntohs (message->size) != sizeof(struct TransportSynMessage))
2308 {
2309 GNUNET_break_op (0);
2310 return GNUNET_SYSERR;
2311 }
2312 GNUNET_STATISTICS_update (GST_stats,
2313 gettext_noop
2314 ("# SYN messages received"),
2315 1, GNUNET_NO);
2316 if (NULL == neighbours)
2317 {
2318 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2319 _ (
2320 "SYN request from peer `%s' ignored due impending shutdown\n"),
2321 GNUNET_i2s (peer));
2322 return GNUNET_OK; /* we're shutting down */
2323 }
2324 scm = (const struct TransportSynMessage *) message;
2325 GNUNET_break_op (0 == ntohl (scm->reserved));
2326 ts = GNUNET_TIME_absolute_ntoh (scm->timestamp);
2327 if (0 ==
2328 memcmp (&GST_my_identity,
2329 peer,
2330 sizeof(struct GNUNET_PeerIdentity)))
2331 {
2332 /* loopback connection-to-self, ignore */
2333 return GNUNET_SYSERR;
2334 }
2335 n = lookup_neighbour (peer);
2336 if (NULL == n)
2337 {
2338 /* This is a new neighbour and set to not connected */
2339 n = setup_neighbour (peer);
2340 GNUNET_assert (NULL != n);
2341 }
2342
2343 /* Remember this SYN message in neighbour */
2344 n->ack_state = ACK_SEND_SYN_ACK;
2345 n->connect_ack_timestamp = ts;
2346
2347 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2348 "Received SYN for peer `%s' in state %s/%s\n",
2349 GNUNET_i2s (peer),
2350 GNUNET_TRANSPORT_ps2s (n->state),
2351 print_ack_state (n->ack_state));
2352
2353 switch (n->state)
2354 {
2355 case GNUNET_TRANSPORT_PS_NOT_CONNECTED:
2356 /* Request an address from ATS to send SYN_ACK to this peer */
2357 set_state_and_timeout (n,
2358 GNUNET_TRANSPORT_PS_SYN_RECV_ATS,
2359 GNUNET_TIME_relative_to_absolute (
2360 ATS_RESPONSE_TIMEOUT));
2361 break;
2362
2363 case GNUNET_TRANSPORT_PS_INIT_ATS:
2364 /* SYN message takes priority over us asking ATS for address:
2365 * Wait for ATS to suggest an address and send SYN_ACK */
2366 set_state_and_timeout (n,
2367 GNUNET_TRANSPORT_PS_SYN_RECV_ATS,
2368 GNUNET_TIME_relative_to_absolute (
2369 ATS_RESPONSE_TIMEOUT));
2370 break;
2371
2372 case GNUNET_TRANSPORT_PS_SYN_RECV_ATS:
2373 /* We already wait for an address to send an SYN_ACK */
2374 break;
2375
2376 case GNUNET_TRANSPORT_PS_SYN_SENT:
2377 case GNUNET_TRANSPORT_PS_SYN_RECV_ACK:
2378 /* Send ACK immediately */
2379 n->ack_state = ACK_SEND_ACK;
2380 send_syn_ack_message (&n->primary_address,
2381 ts);
2382 break;
2383
2384 case GNUNET_TRANSPORT_PS_CONNECTED:
2385 /* we are already connected and can thus send the ACK immediately */
2386 GNUNET_assert (NULL != n->primary_address.address);
2387 GNUNET_assert (NULL != n->primary_address.session);
2388 n->ack_state = ACK_SEND_ACK;
2389 send_syn_ack_message (&n->primary_address,
2390 ts);
2391 break;
2392
2393 case GNUNET_TRANSPORT_PS_RECONNECT_ATS:
2394 /* We wait for ATS address suggestion */
2395 break;
2396
2397 case GNUNET_TRANSPORT_PS_RECONNECT_SENT:
2398 /* We received a SYN message while waiting for a SYN_ACK in fast
2399 * reconnect. Send SYN_ACK immediately */
2400 n->ack_state = ACK_SEND_ACK;
2401 send_syn_ack_message (&n->primary_address,
2402 n->connect_ack_timestamp);
2403 break;
2404
2405 case GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT:
2406 /* We are already connected and can thus send the ACK immediately;
2407 still, it can never hurt to have an alternative address, so also
2408 tell ATS about it */
2409 GNUNET_assert (NULL != n->primary_address.address);
2410 GNUNET_assert (NULL != n->primary_address.session);
2411 n->ack_state = ACK_SEND_ACK;
2412 send_syn_ack_message (&n->primary_address,
2413 ts);
2414 break;
2415
2416 case GNUNET_TRANSPORT_PS_DISCONNECT:
2417 /* Get rid of remains and re-try */
2418 free_neighbour (n);
2419 n = setup_neighbour (peer);
2420 GNUNET_assert (NULL != n);
2421 /* Remember the SYN time stamp for ACK message */
2422 n->ack_state = ACK_SEND_SYN_ACK;
2423 n->connect_ack_timestamp = ts;
2424 /* Request an address for the peer */
2425 set_state_and_timeout (n,
2426 GNUNET_TRANSPORT_PS_SYN_RECV_ATS,
2427 GNUNET_TIME_relative_to_absolute (
2428 ATS_RESPONSE_TIMEOUT));
2429 break;
2430
2431 case GNUNET_TRANSPORT_PS_DISCONNECT_FINISHED:
2432 /* should not be possible */
2433 GNUNET_assert (0);
2434 break;
2435
2436 default:
2437 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2438 "Unhandled state `%s'\n",
2439 GNUNET_TRANSPORT_ps2s (n->state));
2440 GNUNET_break (0);
2441 return GNUNET_SYSERR;
2442 }
2443 return GNUNET_OK;
2444}
2445
2446
2447/**
2448 * Check if the given @a address is the same that we are already
2449 * using for the respective neighbour. If so, update the bandwidth
2450 * assignment and possibly the session and return #GNUNET_OK.
2451 * If the new address is different from what the neighbour is
2452 * using right now, return #GNUNET_NO.
2453 *
2454 * @param address address of the other peer,
2455 * @param session session to use or NULL if transport should initiate a session
2456 * @param bandwidth_in inbound quota to be used when connection is up,
2457 * 0 to disconnect from peer
2458 * @param bandwidth_out outbound quota to be used when connection is up,
2459 * 0 to disconnect from peer
2460 * @return #GNUNET_OK if we were able to just update the bandwidth and session,
2461 * #GNUNET_NO if more extensive changes are required (address changed)
2462 */
2463static int
2464try_run_fast_ats_update (const struct GNUNET_HELLO_Address *address,
2465 struct GNUNET_ATS_Session *session,
2466 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
2467 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
2468{
2469 struct NeighbourMapEntry *n;
2470
2471 n = lookup_neighbour (&address->peer);
2472 if ((NULL == n) ||
2473 (NULL == n->primary_address.address) ||
2474 (0 != GNUNET_HELLO_address_cmp (address,
2475 n->primary_address.address)))
2476 return GNUNET_NO;
2477 /* We are not really switching addresses, but merely adjusting
2478 session and/or bandwidth, can do fast ATS update! */
2479 if (session != n->primary_address.session)
2480 {
2481 /* switch to a different session, but keeping same address; could
2482 happen if there is a 2nd inbound connection */
2483 n->primary_address.session = session;
2484 GNUNET_assert (GNUNET_YES ==
2485 GST_ats_is_known (n->primary_address.address,
2486 n->primary_address.session));
2487 }
2488 if (n->primary_address.bandwidth_in.value__ != bandwidth_in.value__)
2489 {
2490 n->primary_address.bandwidth_in = bandwidth_in;
2491 if (GNUNET_YES !=
2492 set_incoming_quota (n,
2493 bandwidth_in))
2494 return GNUNET_NO;
2495 }
2496 if (n->primary_address.bandwidth_out.value__ != bandwidth_out.value__)
2497 {
2498 n->primary_address.bandwidth_out = bandwidth_out;
2499 send_outbound_quota_to_clients (n);
2500 }
2501 return GNUNET_OK;
2502}
2503
2504
2505/**
2506 * We've been asked to switch addresses, and just now got the result
2507 * from the blacklist check to see if this is allowed.
2508 *
2509 * @param cls the `struct BlacklistCheckSwitchContext` with
2510 * the information about the future address
2511 * @param peer the peer we may switch addresses on
2512 * @param address address associated with the request
2513 * @param session session associated with the request
2514 * @param result #GNUNET_OK if the connection is allowed,
2515 * #GNUNET_NO if not,
2516 * #GNUNET_SYSERR if operation was aborted
2517 */
2518static void
2519switch_address_bl_check_cont (void *cls,
2520 const struct GNUNET_PeerIdentity *peer,
2521 const struct GNUNET_HELLO_Address *address,
2522 struct GNUNET_ATS_Session *session,
2523 int result)
2524{
2525 struct BlacklistCheckSwitchContext *blc_ctx = cls;
2526 struct GNUNET_TRANSPORT_PluginFunctions *papi;
2527 struct NeighbourMapEntry *n;
2528
2529 if (GNUNET_SYSERR == result)
2530 goto cleanup;
2531
2532 papi = GST_plugins_find (address->transport_name);
2533 if (NULL == papi)
2534 {
2535 /* This can happen during shutdown. */
2536 goto cleanup;
2537 }
2538
2539 if (GNUNET_NO == result)
2540 {
2541 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2542 "Blacklist denied to switch to suggested address `%s' session %p for peer `%s'\n",
2543 GST_plugins_a2s (address),
2544 session,
2545 GNUNET_i2s (peer));
2546 GNUNET_STATISTICS_update (GST_stats,
2547 "# ATS suggestions ignored (blacklist denied)",
2548 1,
2549 GNUNET_NO);
2550 if (NULL != session)
2551 papi->disconnect_session (papi->cls,
2552 session);
2553 if (GNUNET_YES !=
2554 GNUNET_HELLO_address_check_option (address,
2555 GNUNET_HELLO_ADDRESS_INFO_INBOUND))
2556 GST_ats_block_address (address,
2557 NULL);
2558 goto cleanup;
2559 }
2560
2561
2562 if (NULL == session)
2563 {
2564 /* need to create a session, ATS only gave us an address */
2565 session = papi->get_session (papi->cls,
2566 address);
2567 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2568 "Obtained new session for peer `%s' and address '%s': %p\n",
2569 GNUNET_i2s (&address->peer),
2570 GST_plugins_a2s (address),
2571 session);
2572 if (NULL != session)
2573 GST_ats_new_session (address,
2574 session);
2575 }
2576 if (NULL == session)
2577 {
2578 /* session creation failed, bad!, fail! */
2579 GNUNET_STATISTICS_update (GST_stats,
2580 "# ATS suggestions ignored (failed to create session)",
2581 1,
2582 GNUNET_NO);
2583 /* No session could be obtained, remove blacklist check and clean up */
2584 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2585 "Failed to obtain new session for peer `%s' and address '%s'\n",
2586 GNUNET_i2s (&address->peer),
2587 GST_plugins_a2s (address));
2588 GST_ats_block_address (address,
2589 session);
2590 goto cleanup;
2591 }
2592
2593 /* We did this check already before going into blacklist, but
2594 it is theoretically possible that the situation changed in
2595 the meantime, hence we check again here */
2596 if (GNUNET_OK ==
2597 try_run_fast_ats_update (address,
2598 session,
2599 blc_ctx->bandwidth_in,
2600 blc_ctx->bandwidth_out))
2601 goto cleanup; /* was just a minor update, we're done */
2602
2603 /* check if we also need to setup the neighbour entry */
2604 if (NULL == (n = lookup_neighbour (peer)))
2605 {
2606 n = setup_neighbour (peer);
2607 if (NULL == n)
2608 {
2609 /* not sure how this can happen... */
2610 GNUNET_break (0);
2611 goto cleanup;
2612 }
2613 n->state = GNUNET_TRANSPORT_PS_INIT_ATS;
2614 }
2615
2616 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2617 "Peer `%s' switches to address `%s'\n",
2618 GNUNET_i2s (&address->peer),
2619 GST_plugins_a2s (address));
2620
2621 switch (n->state)
2622 {
2623 case GNUNET_TRANSPORT_PS_NOT_CONNECTED:
2624 GNUNET_break (0);
2625 GST_ats_block_address (address,
2626 session);
2627 free_neighbour (n);
2628 return;
2629
2630 case GNUNET_TRANSPORT_PS_INIT_ATS:
2631 /* We requested an address and ATS suggests one:
2632 * set primary address and send SYN message*/
2633 set_primary_address (n,
2634 address,
2635 session,
2636 blc_ctx->bandwidth_in,
2637 blc_ctx->bandwidth_out);
2638 if (ACK_SEND_SYN_ACK == n->ack_state)
2639 {
2640 /* Send pending SYN_ACK message */
2641 n->ack_state = ACK_SEND_ACK;
2642 send_syn_ack_message (&n->primary_address,
2643 n->connect_ack_timestamp);
2644 }
2645 set_state_and_timeout (n,
2646 GNUNET_TRANSPORT_PS_SYN_SENT,
2647 GNUNET_TIME_relative_to_absolute (
2648 SETUP_CONNECTION_TIMEOUT));
2649 send_syn (&n->primary_address);
2650 break;
2651
2652 case GNUNET_TRANSPORT_PS_SYN_SENT:
2653 /* ATS suggested a new address while waiting for an SYN_ACK:
2654 * Switch and send new SYN */
2655 /* ATS suggests a different address, switch again */
2656 set_primary_address (n,
2657 address,
2658 session,
2659 blc_ctx->bandwidth_in,
2660 blc_ctx->bandwidth_out);
2661 if (ACK_SEND_SYN_ACK == n->ack_state)
2662 {
2663 /* Send pending SYN_ACK message */
2664 n->ack_state = ACK_SEND_ACK;
2665 send_syn_ack_message (&n->primary_address,
2666 n->connect_ack_timestamp);
2667 }
2668 set_state_and_timeout (n,
2669 GNUNET_TRANSPORT_PS_SYN_SENT,
2670 GNUNET_TIME_relative_to_absolute (
2671 SETUP_CONNECTION_TIMEOUT));
2672 send_syn (&n->primary_address);
2673 break;
2674
2675 case GNUNET_TRANSPORT_PS_SYN_RECV_ATS:
2676 /* We requested an address and ATS suggests one:
2677 * set primary address and send SYN_ACK message*/
2678 set_primary_address (n,
2679 address,
2680 session,
2681 blc_ctx->bandwidth_in,
2682 blc_ctx->bandwidth_out);
2683 /* Send an ACK message as a response to the SYN msg */
2684 set_state_and_timeout (n,
2685 GNUNET_TRANSPORT_PS_SYN_RECV_ACK,
2686 GNUNET_TIME_relative_to_absolute (
2687 SETUP_CONNECTION_TIMEOUT));
2688 send_syn_ack_message (&n->primary_address,
2689 n->connect_ack_timestamp);
2690 if ((ACK_SEND_SYN_ACK == n->ack_state) ||
2691 (ACK_UNDEFINED == n->ack_state))
2692 n->ack_state = ACK_SEND_ACK;
2693 break;
2694
2695 case GNUNET_TRANSPORT_PS_SYN_RECV_ACK:
2696 /* ATS asks us to switch while we were trying to connect; switch to new
2697 address and check blacklist again */
2698 if ((ACK_SEND_SYN_ACK == n->ack_state))
2699 {
2700 n->ack_state = ACK_SEND_ACK;
2701 send_syn_ack_message (&n->primary_address,
2702 n->connect_ack_timestamp);
2703 }
2704 set_primary_address (n,
2705 address,
2706 session,
2707 blc_ctx->bandwidth_in,
2708 blc_ctx->bandwidth_out);
2709 set_state_and_timeout (n,
2710 GNUNET_TRANSPORT_PS_SYN_RECV_ACK,
2711 GNUNET_TIME_relative_to_absolute (
2712 SETUP_CONNECTION_TIMEOUT));
2713 break;
2714
2715 case GNUNET_TRANSPORT_PS_CONNECTED:
2716 GNUNET_assert (NULL != n->primary_address.address);
2717 GNUNET_assert (NULL != n->primary_address.session);
2718 GNUNET_break (n->primary_address.session != session);
2719 /* ATS asks us to switch a life connection; see if we can get
2720 a SYN_ACK on it before we actually do this! */
2721 set_alternative_address (n,
2722 address,
2723 session,
2724 blc_ctx->bandwidth_in,
2725 blc_ctx->bandwidth_out);
2726 set_state_and_timeout (n,
2727 GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT,
2728 GNUNET_TIME_relative_to_absolute (
2729 SETUP_CONNECTION_TIMEOUT));
2730 GNUNET_STATISTICS_update (GST_stats,
2731 gettext_noop ("# Attempts to switch addresses"),
2732 1,
2733 GNUNET_NO);
2734 send_syn (&n->alternative_address);
2735 break;
2736
2737 case GNUNET_TRANSPORT_PS_RECONNECT_ATS:
2738 set_primary_address (n,
2739 address,
2740 session,
2741 blc_ctx->bandwidth_in,
2742 blc_ctx->bandwidth_out);
2743 if (ACK_SEND_SYN_ACK == n->ack_state)
2744 {
2745 /* Send pending SYN_ACK message */
2746 n->ack_state = ACK_SEND_ACK;
2747 send_syn_ack_message (&n->primary_address,
2748 n->connect_ack_timestamp);
2749 }
2750 set_state_and_timeout (n,
2751 GNUNET_TRANSPORT_PS_RECONNECT_SENT,
2752 GNUNET_TIME_relative_to_absolute (
2753 FAST_RECONNECT_TIMEOUT));
2754 send_syn (&n->primary_address);
2755 break;
2756
2757 case GNUNET_TRANSPORT_PS_RECONNECT_SENT:
2758 /* ATS asks us to switch while we were trying to reconnect; switch to new
2759 address and send SYN again */
2760 set_primary_address (n,
2761 address,
2762 session,
2763 blc_ctx->bandwidth_in,
2764 blc_ctx->bandwidth_out);
2765 set_state_and_timeout (n,
2766 GNUNET_TRANSPORT_PS_RECONNECT_SENT,
2767 GNUNET_TIME_relative_to_absolute (
2768 FAST_RECONNECT_TIMEOUT));
2769 send_syn (&n->primary_address);
2770 break;
2771
2772 case GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT:
2773 if ((0 == GNUNET_HELLO_address_cmp (n->primary_address.address,
2774 address)) &&
2775 (n->primary_address.session == session))
2776 {
2777 /* ATS switches back to still-active session */
2778 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2779 "ATS double-switched, cleaning up alternative address\n");
2780 free_address (&n->alternative_address);
2781 set_state_and_timeout (n,
2782 GNUNET_TRANSPORT_PS_CONNECTED,
2783 n->timeout);
2784 break;
2785 }
2786 /* ATS asks us to switch a life connection, send */
2787 set_alternative_address (n,
2788 address,
2789 session,
2790 blc_ctx->bandwidth_in,
2791 blc_ctx->bandwidth_out);
2792 set_state_and_timeout (n,
2793 GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT,
2794 GNUNET_TIME_relative_to_absolute (
2795 SETUP_CONNECTION_TIMEOUT));
2796 send_syn (&n->alternative_address);
2797 break;
2798
2799 case GNUNET_TRANSPORT_PS_DISCONNECT:
2800 /* not going to switch addresses while disconnecting */
2801 GNUNET_STATISTICS_update (GST_stats,
2802 "# ATS suggestion ignored (disconnecting)",
2803 1,
2804 GNUNET_NO);
2805 return;
2806
2807 case GNUNET_TRANSPORT_PS_DISCONNECT_FINISHED:
2808 GNUNET_assert (0);
2809 break;
2810
2811 default:
2812 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2813 "Unhandled state `%s'\n",
2814 GNUNET_TRANSPORT_ps2s (n->state));
2815 GNUNET_break (0);
2816 break;
2817 }
2818cleanup:
2819 GNUNET_CONTAINER_DLL_remove (pending_bc_head,
2820 pending_bc_tail,
2821 blc_ctx);
2822 GNUNET_free (blc_ctx);
2823}
2824
2825
2826/**
2827 * For the given peer, switch to this address.
2828 *
2829 * Before accepting this addresses and actively using it, a blacklist check
2830 * is performed.
2831 *
2832 * If any check fails or the suggestion can somehow not be followed, we
2833 * MUST call #GST_ats_block_address() to tell ATS that the suggestion
2834 * could not be satisfied and force ATS to do something else.
2835 *
2836 * @param address address of the other peer,
2837 * @param session session to use or NULL if transport should initiate a session
2838 * @param bandwidth_in inbound quota to be used when connection is up,
2839 * 0 to disconnect from peer
2840 * @param bandwidth_out outbound quota to be used when connection is up,
2841 * 0 to disconnect from peer
2842 */
2843void
2844GST_neighbours_switch_to_address (const struct GNUNET_HELLO_Address *address,
2845 struct GNUNET_ATS_Session *session,
2846 struct GNUNET_BANDWIDTH_Value32NBO
2847 bandwidth_in,
2848 struct GNUNET_BANDWIDTH_Value32NBO
2849 bandwidth_out)
2850{
2851 struct GST_BlacklistCheck *blc;
2852 struct BlacklistCheckSwitchContext *blc_ctx;
2853
2854 GNUNET_assert (NULL != address->transport_name);
2855 if (GNUNET_OK ==
2856 try_run_fast_ats_update (address,
2857 session,
2858 bandwidth_in,
2859 bandwidth_out))
2860 return;
2861
2862 /* Check if plugin is available */
2863 if (NULL == (GST_plugins_find (address->transport_name)))
2864 {
2865 /* we don't have the plugin for this address */
2866 GNUNET_break (0);
2867 GST_ats_block_address (address,
2868 session);
2869 return;
2870 }
2871 if ((NULL == session) &&
2872 (GNUNET_HELLO_address_check_option (address,
2873 GNUNET_HELLO_ADDRESS_INFO_INBOUND)))
2874 {
2875 /* This is a inbound address and we do not have a session to use! */
2876 GNUNET_break (0);
2877 GST_ats_block_address (address,
2878 session);
2879 return;
2880 }
2881
2882 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2883 "ATS suggests address '%s' for peer `%s' at %u/%u speed\n",
2884 GST_plugins_a2s (address),
2885 GNUNET_i2s (&address->peer),
2886 (unsigned int) ntohl (bandwidth_in.value__),
2887 (unsigned int) ntohl (bandwidth_out.value__));
2888
2889 /* Perform blacklist check */
2890 blc_ctx = GNUNET_new (struct BlacklistCheckSwitchContext);
2891 blc_ctx->bandwidth_in = bandwidth_in;
2892 blc_ctx->bandwidth_out = bandwidth_out;
2893 GNUNET_CONTAINER_DLL_insert (pending_bc_head,
2894 pending_bc_tail,
2895 blc_ctx);
2896 if (NULL != (blc = GST_blacklist_test_allowed (&address->peer,
2897 address->transport_name,
2898 &switch_address_bl_check_cont,
2899 blc_ctx,
2900 address,
2901 session)))
2902 {
2903 blc_ctx->blc = blc;
2904 }
2905}
2906
2907
2908/**
2909 * Function called to send network utilization data to ATS for
2910 * each active connection.
2911 *
2912 * @param cls NULL
2913 * @param key peer we send utilization data for
2914 * @param value the `struct NeighbourMapEntry *` with data to send
2915 * @return #GNUNET_OK (continue to iterate)
2916 */
2917static int
2918send_utilization_data (void *cls,
2919 const struct GNUNET_PeerIdentity *key,
2920 void *value)
2921{
2922 struct NeighbourMapEntry *n = value;
2923 uint32_t bps_in;
2924 uint32_t bps_out;
2925 struct GNUNET_TIME_Relative delta;
2926
2927 (void) cls;
2928 if ((GNUNET_YES != test_connected (n)) ||
2929 (NULL == n->primary_address.address))
2930 return GNUNET_OK;
2931 delta = GNUNET_TIME_absolute_get_difference (n->last_util_transmission,
2932 GNUNET_TIME_absolute_get ());
2933 bps_in = 0;
2934 if ((0 != n->util_total_bytes_recv) && (0 != delta.rel_value_us))
2935 bps_in = (1000LL * 1000LL * n->util_total_bytes_recv)
2936 / (delta.rel_value_us);
2937 bps_out = 0;
2938 if ((0 != n->util_total_bytes_sent) && (0 != delta.rel_value_us))
2939 bps_out = (1000LL * 1000LL * n->util_total_bytes_sent) / delta.rel_value_us;
2940
2941 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2942 "`%s' total: received %u Bytes/s, sent %u Bytes/s\n",
2943 GNUNET_i2s (key),
2944 bps_in,
2945 bps_out);
2946 GST_ats_update_utilization (n->primary_address.address,
2947 bps_in,
2948 bps_out);
2949 n->util_total_bytes_recv = 0;
2950 n->util_total_bytes_sent = 0;
2951 n->last_util_transmission = GNUNET_TIME_absolute_get ();
2952 return GNUNET_OK;
2953}
2954
2955
2956/**
2957 * Task transmitting utilization in a regular interval
2958 *
2959 * @param cls the `struct NeighbourMapEntry` for which we are running
2960 */
2961static void
2962utilization_transmission (void *cls)
2963{
2964 (void) cls;
2965 util_transmission_tk = NULL;
2966 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
2967 &send_utilization_data,
2968 NULL);
2969 util_transmission_tk
2970 = GNUNET_SCHEDULER_add_delayed (UTIL_TRANSMISSION_INTERVAL,
2971 &utilization_transmission,
2972 NULL);
2973}
2974
2975
2976/**
2977 * Track information about data we received from the
2978 * given address (used to notify ATS about our utilization
2979 * of allocated resources).
2980 *
2981 * @param address the address we got data from
2982 * @param message the message we received (really only the size is used)
2983 */
2984void
2985GST_neighbours_notify_data_recv (const struct GNUNET_HELLO_Address *address,
2986 const struct GNUNET_MessageHeader *message)
2987{
2988 struct NeighbourMapEntry *n;
2989
2990 n = lookup_neighbour (&address->peer);
2991 if (NULL == n)
2992 return;
2993 n->util_total_bytes_recv += ntohs (message->size);
2994}
2995
2996
2997/**
2998 * Track information about data we transmitted using the given @a
2999 * address and @a session (used to notify ATS about our utilization of
3000 * allocated resources).
3001 *
3002 * @param address the address we transmitted data to
3003 * @param session session we used to transmit data
3004 * @param message the message we sent (really only the size is used)
3005 */
3006void
3007GST_neighbours_notify_data_sent (const struct GNUNET_HELLO_Address *address,
3008 struct GNUNET_ATS_Session *session,
3009 size_t size)
3010{
3011 struct NeighbourMapEntry *n;
3012
3013 n = lookup_neighbour (&address->peer);
3014 if (NULL == n)
3015 return;
3016 if (n->primary_address.session != session)
3017 return;
3018 n->util_total_bytes_sent += size;
3019}
3020
3021
3022/**
3023 * Master task run for every neighbour. Performs all of the time-related
3024 * activities (keep alive, send next message, disconnect if idle, finish
3025 * clean up after disconnect).
3026 *
3027 * @param cls the 'struct NeighbourMapEntry' for which we are running
3028 */
3029static void
3030master_task (void *cls)
3031{
3032 struct NeighbourMapEntry *n = cls;
3033 struct GNUNET_TIME_Relative delay;
3034
3035 n->task = NULL;
3036 delay = GNUNET_TIME_absolute_get_remaining (n->timeout);
3037 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3038 "Master task runs for neighbour `%s' in state %s with timeout in %s\n",
3039 GNUNET_i2s (&n->id),
3040 GNUNET_TRANSPORT_ps2s (n->state),
3041 GNUNET_STRINGS_relative_time_to_string (delay,
3042 GNUNET_YES));
3043 switch (n->state)
3044 {
3045 case GNUNET_TRANSPORT_PS_NOT_CONNECTED:
3046 /* invalid state for master task, clean up */
3047 GNUNET_break (0);
3048 free_neighbour (n);
3049 return;
3050
3051 case GNUNET_TRANSPORT_PS_INIT_ATS:
3052 if (0 == delay.rel_value_us)
3053 {
3054 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3055 "Connection to `%s' timed out waiting for ATS to provide address\n",
3056 GNUNET_i2s (&n->id));
3057 free_neighbour (n);
3058 return;
3059 }
3060 break;
3061
3062 case GNUNET_TRANSPORT_PS_SYN_SENT:
3063 if (0 == delay.rel_value_us)
3064 {
3065 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3066 "Connection to `%s' timed out waiting for other peer to send SYN_ACK\n",
3067 GNUNET_i2s (&n->id));
3068 /* Remove address and request and additional one */
3069 unset_primary_address (n);
3070 set_state_and_timeout (n,
3071 GNUNET_TRANSPORT_PS_INIT_ATS,
3072 GNUNET_TIME_relative_to_absolute (
3073 ATS_RESPONSE_TIMEOUT));
3074 return;
3075 }
3076 break;
3077
3078 case GNUNET_TRANSPORT_PS_SYN_RECV_ATS:
3079 if (0 == delay.rel_value_us)
3080 {
3081 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3082 "Connection to `%s' timed out waiting ATS to provide address to use for SYN_ACK\n",
3083 GNUNET_i2s (&n->id));
3084 free_neighbour (n);
3085 return;
3086 }
3087 break;
3088
3089 case GNUNET_TRANSPORT_PS_SYN_RECV_ACK:
3090 if (0 == delay.rel_value_us)
3091 {
3092 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3093 "Connection to `%s' timed out waiting for other peer to send ACK\n",
3094 GNUNET_i2s (&n->id));
3095 disconnect_neighbour (n);
3096 return;
3097 }
3098 break;
3099
3100 case GNUNET_TRANSPORT_PS_CONNECTED:
3101 if (0 == delay.rel_value_us)
3102 {
3103 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3104 "Connection to `%s' timed out, missing KEEPALIVE_RESPONSEs\n",
3105 GNUNET_i2s (&n->id));
3106 disconnect_neighbour (n);
3107 return;
3108 }
3109 try_transmission_to_peer (n);
3110 send_keepalive (n);
3111 break;
3112
3113 case GNUNET_TRANSPORT_PS_RECONNECT_ATS:
3114 if (0 == delay.rel_value_us)
3115 {
3116 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3117 "Connection to `%s' timed out, waiting for ATS replacement address\n",
3118 GNUNET_i2s (&n->id));
3119 disconnect_neighbour (n);
3120 return;
3121 }
3122 break;
3123
3124 case GNUNET_TRANSPORT_PS_RECONNECT_SENT:
3125 if (0 == delay.rel_value_us)
3126 {
3127 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3128 "Connection to `%s' timed out, waiting for other peer to SYN_ACK replacement address\n",
3129 GNUNET_i2s (&n->id));
3130 disconnect_neighbour (n);
3131 return;
3132 }
3133 break;
3134
3135 case GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT:
3136 if (0 == delay.rel_value_us)
3137 {
3138 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3139 "Switch failed, cleaning up alternative address\n");
3140 free_address (&n->alternative_address);
3141 set_state_and_timeout (n,
3142 GNUNET_TRANSPORT_PS_CONNECTED,
3143 GNUNET_TIME_relative_to_absolute (
3144 SETUP_CONNECTION_TIMEOUT));
3145 }
3146 try_transmission_to_peer (n);
3147 send_keepalive (n);
3148 break;
3149
3150 case GNUNET_TRANSPORT_PS_DISCONNECT:
3151 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3152 "Cleaning up connection to `%s' after sending DISCONNECT\n",
3153 GNUNET_i2s (&n->id));
3154 free_neighbour (n);
3155 return;
3156
3157 case GNUNET_TRANSPORT_PS_DISCONNECT_FINISHED:
3158 /* how did we get here!? */
3159 GNUNET_assert (0);
3160 break;
3161
3162 default:
3163 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3164 "Unhandled state `%s'\n",
3165 GNUNET_TRANSPORT_ps2s (n->state));
3166 GNUNET_break (0);
3167 break;
3168 }
3169 delay = GNUNET_TIME_absolute_get_remaining (n->timeout);
3170 if ((GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT == n->state) ||
3171 (GNUNET_TRANSPORT_PS_CONNECTED == n->state))
3172 {
3173 /* if we are *now* in one of the two states, we're sending
3174 keep alive messages, so we need to consider the keepalive
3175 delay, not just the connection timeout */
3176 delay = GNUNET_TIME_relative_min (GNUNET_TIME_absolute_get_remaining (
3177 n->keep_alive_time),
3178 delay);
3179 }
3180 if (NULL == n->task)
3181 n->task = GNUNET_SCHEDULER_add_delayed (delay,
3182 &master_task,
3183 n);
3184}
3185
3186
3187/**
3188 * Send a ACK message to the neighbour to confirm that we
3189 * got its SYN_ACK.
3190 *
3191 * @param n neighbour to send the ACK to
3192 */
3193static void
3194send_session_ack_message (struct NeighbourMapEntry *n)
3195{
3196 struct GNUNET_MessageHeader msg;
3197
3198 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3199 "Sending ACK message to peer `%s'\n",
3200 GNUNET_i2s (&n->id));
3201
3202 msg.size = htons (sizeof(struct GNUNET_MessageHeader));
3203 msg.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_ACK);
3204 (void) send_with_session (n,
3205 &msg,
3206 sizeof(struct GNUNET_MessageHeader),
3207 UINT32_MAX,
3208 GNUNET_TIME_UNIT_FOREVER_REL,
3209 GNUNET_NO,
3210 NULL, NULL);
3211}
3212
3213
3214/**
3215 * We received a 'SESSION_SYN_ACK' message from the other peer.
3216 * Consider switching to it.
3217 *
3218 * @param message possibly a `struct GNUNET_ATS_SessionConnectMessage` (check format)
3219 * @param peer identity of the peer to switch the address for
3220 * @param address address of the other peer, NULL if other peer
3221 * connected to us
3222 * @param session session to use (or NULL)
3223 * @return #GNUNET_OK if the message was fine, #GNUNET_SYSERR on serious error
3224 */
3225int
3226GST_neighbours_handle_session_syn_ack (const struct
3227 GNUNET_MessageHeader *message,
3228 const struct
3229 GNUNET_HELLO_Address *address,
3230 struct GNUNET_ATS_Session *session)
3231{
3232 const struct TransportSynMessage *scm;
3233 struct GNUNET_TIME_Absolute ts;
3234 struct NeighbourMapEntry *n;
3235
3236 (void) session;
3237 if (ntohs (message->size) != sizeof(struct TransportSynMessage))
3238 {
3239 GNUNET_break_op (0);
3240 return GNUNET_SYSERR;
3241 }
3242 GNUNET_STATISTICS_update (GST_stats,
3243 gettext_noop
3244 ("# SYN_ACK messages received"),
3245 1, GNUNET_NO);
3246 scm = (const struct TransportSynMessage *) message;
3247 GNUNET_break_op (ntohl (scm->reserved) == 0);
3248 if (NULL == (n = lookup_neighbour (&address->peer)))
3249 {
3250 GNUNET_STATISTICS_update (GST_stats,
3251 gettext_noop
3252 ("# unexpected SYN_ACK messages (no peer)"),
3253 1, GNUNET_NO);
3254 return GNUNET_SYSERR;
3255 }
3256 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3257 "Received SYN_ACK message from peer `%s' in state %s/%s\n",
3258 GNUNET_i2s (&address->peer),
3259 GNUNET_TRANSPORT_ps2s (n->state),
3260 print_ack_state (n->ack_state));
3261 ts = GNUNET_TIME_absolute_ntoh (scm->timestamp);
3262 switch (n->state)
3263 {
3264 case GNUNET_TRANSPORT_PS_NOT_CONNECTED:
3265 GNUNET_break (0);
3266 free_neighbour (n);
3267 return GNUNET_SYSERR;
3268
3269 case GNUNET_TRANSPORT_PS_INIT_ATS:
3270 GNUNET_STATISTICS_update (GST_stats,
3271 gettext_noop (
3272 "# unexpected SYN_ACK messages (not ready)"),
3273 1,
3274 GNUNET_NO);
3275 break;
3276
3277 case GNUNET_TRANSPORT_PS_SYN_SENT:
3278 if (ts.abs_value_us != n->primary_address.connect_timestamp.abs_value_us)
3279 {
3280 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3281 "SYN_ACK ignored as the timestamp does not match our SYN request\n");
3282 return GNUNET_OK;
3283 }
3284 set_state_and_timeout (n,
3285 GNUNET_TRANSPORT_PS_CONNECTED,
3286 GNUNET_TIME_relative_to_absolute (
3287 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT));
3288 set_primary_address (n,
3289 n->primary_address.address,
3290 n->primary_address.session,
3291 n->primary_address.bandwidth_in,
3292 n->primary_address.bandwidth_out);
3293 send_session_ack_message (n);
3294 break;
3295
3296 case GNUNET_TRANSPORT_PS_SYN_RECV_ATS:
3297 case GNUNET_TRANSPORT_PS_SYN_RECV_ACK:
3298 GNUNET_STATISTICS_update (GST_stats,
3299 gettext_noop (
3300 "# unexpected SYN_ACK messages (not ready)"),
3301 1,
3302 GNUNET_NO);
3303 break;
3304
3305 case GNUNET_TRANSPORT_PS_CONNECTED:
3306 /* duplicate SYN_ACK, let's answer by duplicate ACK just in case */
3307 send_session_ack_message (n);
3308 break;
3309
3310 case GNUNET_TRANSPORT_PS_RECONNECT_ATS:
3311 /* we didn't expect any SYN_ACK, as we are waiting for ATS
3312 to give us a new address... */
3313 GNUNET_STATISTICS_update (GST_stats,
3314 gettext_noop (
3315 "# unexpected SYN_ACK messages (waiting on ATS)"),
3316 1,
3317 GNUNET_NO);
3318 break;
3319
3320 case GNUNET_TRANSPORT_PS_RECONNECT_SENT:
3321 /* Reconnecting with new address address worked; go back to connected! */
3322 set_state_and_timeout (n,
3323 GNUNET_TRANSPORT_PS_CONNECTED,
3324 GNUNET_TIME_relative_to_absolute (
3325 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT));
3326 send_session_ack_message (n);
3327 break;
3328
3329 case GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT:
3330 /* new address worked; adopt it and go back to connected! */
3331 set_state_and_timeout (n,
3332 GNUNET_TRANSPORT_PS_CONNECTED,
3333 GNUNET_TIME_relative_to_absolute (
3334 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT));
3335 GNUNET_break (GNUNET_NO == n->alternative_address.ats_active);
3336
3337 /* Set primary addresses */
3338 set_primary_address (n,
3339 n->alternative_address.address,
3340 n->alternative_address.session,
3341 n->alternative_address.bandwidth_in,
3342 n->alternative_address.bandwidth_out);
3343 GNUNET_STATISTICS_update (GST_stats,
3344 gettext_noop (
3345 "# Successful attempts to switch addresses"),
3346 1,
3347 GNUNET_NO);
3348
3349 GNUNET_HELLO_address_free (n->alternative_address.address);
3350 memset (&n->alternative_address,
3351 0,
3352 sizeof(n->alternative_address));
3353 send_session_ack_message (n);
3354 break;
3355
3356 case GNUNET_TRANSPORT_PS_DISCONNECT:
3357 GNUNET_STATISTICS_update (GST_stats,
3358 gettext_noop
3359 ("# unexpected SYN_ACK messages (disconnecting)"),
3360 1, GNUNET_NO);
3361 return GNUNET_SYSERR;
3362
3363 case GNUNET_TRANSPORT_PS_DISCONNECT_FINISHED:
3364 GNUNET_assert (0);
3365 break;
3366
3367 default:
3368 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3369 "Unhandled state `%s'\n",
3370 GNUNET_TRANSPORT_ps2s (n->state));
3371 GNUNET_break (0);
3372 return GNUNET_SYSERR;
3373 }
3374 return GNUNET_OK;
3375}
3376
3377
3378/**
3379 * A session was terminated. Take note; if needed, try to get
3380 * an alternative address from ATS.
3381 *
3382 * @param peer identity of the peer where the session died
3383 * @param session session that is gone
3384 * @return #GNUNET_YES if this was a session used, #GNUNET_NO if
3385 * this session was not in use
3386 */
3387int
3388GST_neighbours_session_terminated (const struct GNUNET_PeerIdentity *peer,
3389 struct GNUNET_ATS_Session *session)
3390{
3391 struct NeighbourMapEntry *n;
3392
3393 if (NULL == (n = lookup_neighbour (peer)))
3394 return GNUNET_NO; /* can't affect us */
3395 if (session != n->primary_address.session)
3396 {
3397 /* Free alternative address */
3398 if (session == n->alternative_address.session)
3399 {
3400 if (GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT == n->state)
3401 set_state_and_timeout (n,
3402 GNUNET_TRANSPORT_PS_CONNECTED,
3403 n->timeout);
3404 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3405 "Session died, cleaning up alternative address\n");
3406 free_address (&n->alternative_address);
3407 }
3408 return GNUNET_NO; /* doesn't affect us further */
3409 }
3410
3411 n->expect_latency_response = GNUNET_NO;
3412 /* The session for neighbour's primary address died */
3413 switch (n->state)
3414 {
3415 case GNUNET_TRANSPORT_PS_NOT_CONNECTED:
3416 GNUNET_break (0);
3417 free_neighbour (n);
3418 return GNUNET_YES;
3419
3420 case GNUNET_TRANSPORT_PS_INIT_ATS:
3421 GNUNET_break (0);
3422 free_neighbour (n);
3423 return GNUNET_YES;
3424
3425 case GNUNET_TRANSPORT_PS_SYN_SENT:
3426 /* The session used to send the SYN terminated:
3427 * this implies a connect error*/
3428 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3429 "Failed to send SYN in CONNECT_SENT with `%s' %p: session terminated\n",
3430 GST_plugins_a2s (n->primary_address.address),
3431 n->primary_address.session);
3432
3433 /* Destroy the address since it cannot be used */
3434 unset_primary_address (n);
3435 set_state_and_timeout (n,
3436 GNUNET_TRANSPORT_PS_INIT_ATS,
3437 GNUNET_TIME_relative_to_absolute (
3438 ATS_RESPONSE_TIMEOUT));
3439 break;
3440
3441 case GNUNET_TRANSPORT_PS_SYN_RECV_ATS:
3442 case GNUNET_TRANSPORT_PS_SYN_RECV_ACK:
3443 /* error on inbound session; free neighbour entirely */
3444 free_neighbour (n);
3445 return GNUNET_YES;
3446
3447 case GNUNET_TRANSPORT_PS_CONNECTED:
3448 /* Our primary connection died, try a fast reconnect */
3449 unset_primary_address (n);
3450 set_state_and_timeout (n,
3451 GNUNET_TRANSPORT_PS_RECONNECT_ATS,
3452 GNUNET_TIME_relative_to_absolute (
3453 ATS_RESPONSE_TIMEOUT));
3454 break;
3455
3456 case GNUNET_TRANSPORT_PS_RECONNECT_ATS:
3457 /* we don't have an address, how can it go down? */
3458 GNUNET_break (0);
3459 break;
3460
3461 case GNUNET_TRANSPORT_PS_RECONNECT_SENT:
3462 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3463 "Failed to send SYN in RECONNECT_SENT with `%s' %p: session terminated\n",
3464 GST_plugins_a2s (n->primary_address.address),
3465 n->primary_address.session);
3466 /* Destroy the address since it cannot be used */
3467 unset_primary_address (n);
3468 set_state_and_timeout (n,
3469 GNUNET_TRANSPORT_PS_RECONNECT_ATS,
3470 GNUNET_TIME_relative_to_absolute (
3471 ATS_RESPONSE_TIMEOUT));
3472 break;
3473
3474 case GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT:
3475 /* primary went down while we were waiting for SYN_ACK on secondary;
3476 secondary as primary */
3477
3478 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3479 "Connection `%s' %p to peer `%s' was terminated while switching, "
3480 "switching to alternative address `%s' %p\n",
3481 GST_plugins_a2s (n->primary_address.address),
3482 n->primary_address.session,
3483 GNUNET_i2s (peer),
3484 GST_plugins_a2s (n->alternative_address.address),
3485 n->alternative_address.session);
3486
3487 /* Destroy the inbound address since it cannot be used */
3488 free_address (&n->primary_address);
3489 n->primary_address = n->alternative_address;
3490 GNUNET_assert (GNUNET_YES ==
3491 GST_ats_is_known (n->primary_address.address,
3492 n->primary_address.session));
3493 memset (&n->alternative_address,
3494 0,
3495 sizeof(struct NeighbourAddress));
3496 set_state_and_timeout (n,
3497 GNUNET_TRANSPORT_PS_RECONNECT_SENT,
3498 GNUNET_TIME_relative_to_absolute (
3499 FAST_RECONNECT_TIMEOUT));
3500 break;
3501
3502 case GNUNET_TRANSPORT_PS_DISCONNECT:
3503 unset_primary_address (n);
3504 break;
3505
3506 case GNUNET_TRANSPORT_PS_DISCONNECT_FINISHED:
3507 /* neighbour was freed and plugins told to terminate session */
3508 return GNUNET_NO;
3509
3510 default:
3511 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3512 "Unhandled state `%s'\n",
3513 GNUNET_TRANSPORT_ps2s (n->state));
3514 GNUNET_break (0);
3515 break;
3516 }
3517 if (NULL != n->task)
3518 GNUNET_SCHEDULER_cancel (n->task);
3519 n->task = GNUNET_SCHEDULER_add_now (&master_task, n);
3520 return GNUNET_YES;
3521}
3522
3523
3524/**
3525 * We received a 'ACK' message from the other peer.
3526 * If we sent a 'SYN_ACK' last, this means we are now
3527 * connected. Otherwise, do nothing.
3528 *
3529 * @param message possibly a 'struct GNUNET_ATS_SessionConnectMessage' (check format)
3530 * @param address address of the other peer
3531 * @param session session to use (or NULL)
3532 * @return #GNUNET_OK if the message was fine, #GNUNET_SYSERR on serious error
3533 */
3534int
3535GST_neighbours_handle_session_ack (const struct GNUNET_MessageHeader *message,
3536 const struct GNUNET_HELLO_Address *address,
3537 struct GNUNET_ATS_Session *session)
3538{
3539 struct NeighbourMapEntry *n;
3540
3541 (void) session;
3542 if (ntohs (message->size) != sizeof(struct GNUNET_MessageHeader))
3543 {
3544 GNUNET_break_op (0);
3545 return GNUNET_SYSERR;
3546 }
3547 GNUNET_STATISTICS_update (GST_stats,
3548 gettext_noop ("# ACK messages received"),
3549 1,
3550 GNUNET_NO);
3551 if (NULL == (n = lookup_neighbour (&address->peer)))
3552 {
3553 GNUNET_break_op (0);
3554 return GNUNET_SYSERR;
3555 }
3556 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3557 "Received ACK for peer `%s' in state %s/%s\n",
3558 GNUNET_i2s (&address->peer),
3559 GNUNET_TRANSPORT_ps2s (n->state),
3560 print_ack_state (n->ack_state));
3561
3562 /* Check if we are in a plausible state for having sent
3563 a SYN_ACK. If not, return, otherwise break.
3564
3565 The remote peers sends a ACK as a response for a SYN_ACK
3566 message.
3567
3568 We expect a ACK:
3569 - If a remote peer has sent a SYN, we responded with a SYN_ACK and
3570 now wait for the ACK to finally be connected
3571 - If we sent a SYN_ACK to this peer before */if (((GNUNET_TRANSPORT_PS_SYN_RECV_ACK != n->state) &&
3572 (ACK_SEND_ACK != n->ack_state)) ||
3573 (NULL == n->primary_address.address))
3574 {
3575 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3576 "Received unexpected ACK message from peer `%s' in state %s/%s\n",
3577 GNUNET_i2s (&address->peer),
3578 GNUNET_TRANSPORT_ps2s (n->state),
3579 print_ack_state (n->ack_state));
3580
3581 GNUNET_STATISTICS_update (GST_stats,
3582 gettext_noop ("# unexpected ACK messages"),
3583 1,
3584 GNUNET_NO);
3585 return GNUNET_OK;
3586 }
3587 if (GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT == n->state)
3588 {
3589 /* We tried to switch addresses while being connect. We explicitly wait
3590 * for a SYN_ACK before going to GNUNET_TRANSPORT_PS_CONNECTED,
3591 * so we do not want to set the address as in use! */
3592 return GNUNET_OK;
3593 }
3594 set_state_and_timeout (n,
3595 GNUNET_TRANSPORT_PS_CONNECTED,
3596 GNUNET_TIME_relative_to_absolute (
3597 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT));
3598
3599 if (NULL == n->primary_address.address)
3600 {
3601 /* See issue #3693.
3602 * We are in state = PSY_SYN_RECV_ACK or ack_state = ACK_SEND_ACK, which
3603 * really means we did try (and succeed) to send a SYN and are waiting for
3604 * an ACK.
3605 * That suggests that the primary_address used to be non-NULL, but maybe it
3606 * got reset to NULL without the state being changed appropriately?
3607 */GNUNET_break (0);
3608 return GNUNET_OK;
3609 }
3610
3611 /* Reset backoff for primary address */
3612 GST_ats_block_reset (n->primary_address.address,
3613 n->primary_address.session);
3614 return GNUNET_OK;
3615}
3616
3617
3618/**
3619 * Test if we're connected to the given peer.
3620 *
3621 * @param target peer to test
3622 * @return #GNUNET_YES if we are connected, #GNUNET_NO if not
3623 */
3624int
3625GST_neighbours_test_connected (const struct GNUNET_PeerIdentity *target)
3626{
3627 return test_connected (lookup_neighbour (target));
3628}
3629
3630
3631/**
3632 * Task to asynchronously run #free_neighbour().
3633 *
3634 * @param cls the `struct NeighbourMapEntry` to free
3635 */
3636static void
3637delayed_disconnect (void *cls)
3638{
3639 struct NeighbourMapEntry *n = cls;
3640
3641 n->delayed_disconnect_task = NULL;
3642 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3643 "Disconnecting by request from peer %s\n",
3644 GNUNET_i2s (&n->id));
3645 free_neighbour (n);
3646}
3647
3648
3649/**
3650 * We received a quota message from the given peer,
3651 * validate and process.
3652 *
3653 * @param peer sender of the message
3654 * @param msg the quota message
3655 */
3656void
3657GST_neighbours_handle_quota_message (const struct GNUNET_PeerIdentity *peer,
3658 const struct GNUNET_MessageHeader *msg)
3659{
3660 struct NeighbourMapEntry *n;
3661 const struct GNUNET_ATS_SessionQuotaMessage *sqm;
3662 struct GNUNET_BANDWIDTH_Value32NBO last;
3663
3664 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3665 "Received QUOTA message from peer `%s'\n",
3666 GNUNET_i2s (peer));
3667 if (ntohs (msg->size) != sizeof(struct GNUNET_ATS_SessionQuotaMessage))
3668 {
3669 GNUNET_break_op (0);
3670 GNUNET_STATISTICS_update (GST_stats,
3671 gettext_noop (
3672 "# quota messages ignored (malformed)"),
3673 1,
3674 GNUNET_NO);
3675 return;
3676 }
3677 GNUNET_STATISTICS_update (GST_stats,
3678 gettext_noop
3679 ("# QUOTA messages received"),
3680 1, GNUNET_NO);
3681 sqm = (const struct GNUNET_ATS_SessionQuotaMessage *) msg;
3682 if (NULL == (n = lookup_neighbour (peer)))
3683 {
3684 /* gone already */
3685 return;
3686 }
3687 last = GNUNET_BANDWIDTH_value_max (GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
3688 GNUNET_BANDWIDTH_value_init (ntohl (
3689 sqm->quota)));
3690 if (last.value__ != n->neighbour_receive_quota.value__)
3691 {
3692 n->neighbour_receive_quota = last;
3693 send_outbound_quota_to_clients (n);
3694 }
3695}
3696
3697
3698/**
3699 * We received a disconnect message from the given peer,
3700 * validate and process.
3701 *
3702 * @param peer sender of the message
3703 * @param msg the disconnect message
3704 */
3705void
3706GST_neighbours_handle_disconnect_message (const struct
3707 GNUNET_PeerIdentity *peer,
3708 const struct
3709 GNUNET_MessageHeader *msg)
3710{
3711 struct NeighbourMapEntry *n;
3712 const struct GNUNET_ATS_SessionDisconnectMessage *sdm;
3713
3714 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3715 "Received DISCONNECT message from peer `%s'\n",
3716 GNUNET_i2s (peer));
3717 if (ntohs (msg->size) != sizeof(struct GNUNET_ATS_SessionDisconnectMessage))
3718 {
3719 GNUNET_break_op (0);
3720 GNUNET_STATISTICS_update (GST_stats,
3721 gettext_noop
3722 ("# disconnect messages ignored (malformed)"),
3723 1,
3724 GNUNET_NO);
3725 return;
3726 }
3727 GNUNET_STATISTICS_update (GST_stats,
3728 gettext_noop
3729 ("# DISCONNECT messages received"),
3730 1, GNUNET_NO);
3731 sdm = (const struct GNUNET_ATS_SessionDisconnectMessage *) msg;
3732 if (NULL == (n = lookup_neighbour (peer)))
3733 {
3734 /* gone already */
3735 return;
3736 }
3737 if (GNUNET_TIME_absolute_ntoh (sdm->timestamp).abs_value_us <=
3738 n->connect_ack_timestamp.abs_value_us)
3739 {
3740 GNUNET_STATISTICS_update (GST_stats,
3741 gettext_noop (
3742 "# disconnect messages ignored (timestamp)"),
3743 1,
3744 GNUNET_NO);
3745 return;
3746 }
3747 if (0 != memcmp (peer,
3748 &sdm->public_key,
3749 sizeof(struct GNUNET_PeerIdentity)))
3750 {
3751 GNUNET_break_op (0);
3752 return;
3753 }
3754 if (ntohl (sdm->purpose.size) !=
3755 sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose)
3756 + sizeof(struct GNUNET_CRYPTO_EddsaPublicKey)
3757 + sizeof(struct GNUNET_TIME_AbsoluteNBO))
3758 {
3759 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3760 "DISCONNECT message from peer `%s' has invalid size\n",
3761 GNUNET_i2s (peer));
3762 GNUNET_break_op (0);
3763 return;
3764 }
3765 if (GNUNET_OK !=
3766 GNUNET_CRYPTO_eddsa_verify_ (
3767 GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT,
3768 &sdm->purpose,
3769 &sdm->signature,
3770 &sdm->public_key))
3771 {
3772 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3773 "DISCONNECT message from peer `%s' cannot be verified \n",
3774 GNUNET_i2s (peer));
3775 GNUNET_break_op (0);
3776 return;
3777 }
3778 if (NULL == n->delayed_disconnect_task)
3779 {
3780 n->delayed_disconnect_task = GNUNET_SCHEDULER_add_now (&delayed_disconnect,
3781 n);
3782 }
3783}
3784
3785
3786/**
3787 * Closure for the #neighbours_iterate() function.
3788 */
3789struct IteratorContext
3790{
3791 /**
3792 * Function to call on each connected neighbour.
3793 */
3794 GST_NeighbourIterator cb;
3795
3796 /**
3797 * Closure for @e cb.
3798 */
3799 void *cb_cls;
3800};
3801
3802
3803/**
3804 * Call the callback from the closure for each neighbour.
3805 *
3806 * @param cls the `struct IteratorContext`
3807 * @param key the hash of the public key of the neighbour
3808 * @param value the `struct NeighbourMapEntry`
3809 * @return #GNUNET_OK (continue to iterate)
3810 */
3811static int
3812neighbours_iterate (void *cls,
3813 const struct GNUNET_PeerIdentity *key,
3814 void *value)
3815{
3816 struct IteratorContext *ic = cls;
3817 struct NeighbourMapEntry *n = value;
3818 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in;
3819 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out;
3820
3821 (void) key;
3822 if (NULL != n->primary_address.address)
3823 {
3824 bandwidth_in = n->primary_address.bandwidth_in;
3825 bandwidth_out = n->primary_address.bandwidth_out;
3826 }
3827 else
3828 {
3829 bandwidth_in = GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT;
3830 bandwidth_out = GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT;
3831 }
3832 ic->cb (ic->cb_cls,
3833 &n->id,
3834 n->primary_address.address,
3835 n->state,
3836 n->timeout,
3837 bandwidth_in, bandwidth_out);
3838 return GNUNET_OK;
3839}
3840
3841
3842/**
3843 * Iterate over all connected neighbours.
3844 *
3845 * @param cb function to call
3846 * @param cb_cls closure for @a cb
3847 */
3848void
3849GST_neighbours_iterate (GST_NeighbourIterator cb,
3850 void *cb_cls)
3851{
3852 struct IteratorContext ic;
3853
3854 if (NULL == neighbours)
3855 return; /* can happen during shutdown */
3856 ic.cb = cb;
3857 ic.cb_cls = cb_cls;
3858 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
3859 &neighbours_iterate,
3860 &ic);
3861}
3862
3863
3864/**
3865 * If we have an active connection to the given target, it must be shutdown.
3866 *
3867 * @param target peer to disconnect from
3868 */
3869void
3870GST_neighbours_force_disconnect (const struct GNUNET_PeerIdentity *target)
3871{
3872 struct NeighbourMapEntry *n;
3873
3874 if (NULL == (n = lookup_neighbour (target)))
3875 return; /* not active */
3876 if (GNUNET_YES == test_connected (n))
3877 GNUNET_STATISTICS_update (GST_stats,
3878 gettext_noop (
3879 "# disconnected from peer upon explicit request"),
3880 1,
3881 GNUNET_NO);
3882 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3883 "Forced disconnect from peer %s\n",
3884 GNUNET_i2s (target));
3885 disconnect_neighbour (n);
3886}
3887
3888
3889/**
3890 * Obtain current address information for the given neighbour.
3891 *
3892 * @param peer
3893 * @return address currently used
3894 */
3895const struct GNUNET_HELLO_Address *
3896GST_neighbour_get_current_address (const struct GNUNET_PeerIdentity *peer)
3897{
3898 struct NeighbourMapEntry *n;
3899
3900 n = lookup_neighbour (peer);
3901 if (NULL == n)
3902 return NULL;
3903 return n->primary_address.address;
3904}
3905
3906
3907/**
3908 * Initialize the neighbours subsystem.
3909 *
3910 * @param max_fds maximum number of fds to use
3911 */
3912void
3913GST_neighbours_start (unsigned int max_fds)
3914{
3915 (void) max_fds;
3916 neighbours = GNUNET_CONTAINER_multipeermap_create (NEIGHBOUR_TABLE_SIZE,
3917 GNUNET_NO);
3918 util_transmission_tk = GNUNET_SCHEDULER_add_delayed (
3919 UTIL_TRANSMISSION_INTERVAL,
3920 &utilization_transmission,
3921 NULL);
3922}
3923
3924
3925/**
3926 * Disconnect from the given neighbour.
3927 *
3928 * @param cls unused
3929 * @param key hash of neighbour's public key (not used)
3930 * @param value the `struct NeighbourMapEntry` of the neighbour
3931 * @return #GNUNET_OK (continue to iterate)
3932 */
3933static int
3934disconnect_all_neighbours (void *cls,
3935 const struct GNUNET_PeerIdentity *key,
3936 void *value)
3937{
3938 struct NeighbourMapEntry *n = value;
3939
3940 (void) cls;
3941 (void) key;
3942 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3943 "Disconnecting peer `%4s' during shutdown\n",
3944 GNUNET_i2s (&n->id));
3945 free_neighbour (n);
3946 return GNUNET_OK;
3947}
3948
3949
3950/**
3951 * Cleanup the neighbours subsystem.
3952 */
3953void
3954GST_neighbours_stop ()
3955{
3956 if (NULL == neighbours)
3957 return;
3958 if (NULL != util_transmission_tk)
3959 {
3960 GNUNET_SCHEDULER_cancel (util_transmission_tk);
3961 util_transmission_tk = NULL;
3962 }
3963 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
3964 &disconnect_all_neighbours,
3965 NULL);
3966 GNUNET_CONTAINER_multipeermap_destroy (neighbours);
3967 neighbours = NULL;
3968}
3969
3970
3971/* 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 13aeab4e6..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 quoat 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 c88532806..000000000
--- a/src/transport/gnunet-service-transport_plugins.c
+++ /dev/null
@@ -1,456 +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 session the session
87 * @param distance new distance
88 */
89static void
90plugin_env_update_distance (void *cls,
91 const struct GNUNET_HELLO_Address *address,
92 uint32_t distance)
93{
94 GST_ats_update_distance (address,
95 distance);
96}
97
98
99/**
100 * Function that will be called to figure if an address is an loopback,
101 * LAN, WAN etc. address
102 *
103 * @param cls closure
104 * @param addr binary address
105 * @param addrlen length of the @a addr
106 * @return type of the network @a addr belongs to
107 */
108static enum GNUNET_NetworkType
109plugin_env_address_to_type (void *cls,
110 const struct sockaddr *addr,
111 size_t addrlen)
112{
113 if (NULL == GST_is)
114 {
115 GNUNET_break (0);
116 return GNUNET_NT_UNSPECIFIED;
117 }
118 return GNUNET_NT_scanner_get_type (GST_is,
119 addr,
120 addrlen);
121}
122
123
124/**
125 * Load and initialize all plugins. The respective functions will be
126 * invoked by the plugins when the respective events happen. The
127 * closure will be set to a 'const char*' containing the name of the
128 * plugin that caused the call.
129 *
130 * @param recv_cb function to call when data is received
131 * @param address_cb function to call when our public addresses changed
132 * @param session_start_cb function to call when a session was created
133 * @param session_end_cb function to call when a session was terminated
134 * @param address_type_cb function to call when a address type is requested
135 */
136void
137GST_plugins_load (GNUNET_TRANSPORT_PluginReceiveCallback recv_cb,
138 GNUNET_TRANSPORT_AddressNotification address_cb,
139 GNUNET_TRANSPORT_SessionStart session_start_cb,
140 GNUNET_TRANSPORT_SessionEnd session_end_cb)
141{
142 struct TransportPlugin *plug;
143 struct TransportPlugin *next;
144 unsigned long long tneigh;
145 char *libname;
146 char *plugs;
147 char *pos;
148 int fail;
149
150 if (GNUNET_OK !=
151 GNUNET_CONFIGURATION_get_value_number (GST_cfg,
152 "TRANSPORT",
153 "NEIGHBOUR_LIMIT",
154 &tneigh))
155 {
156 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
157 _ ("Transport service is lacking NEIGHBOUR_LIMIT option.\n"));
158 return;
159 }
160 if (GNUNET_OK !=
161 GNUNET_CONFIGURATION_get_value_string (GST_cfg,
162 "TRANSPORT",
163 "PLUGINS",
164 &plugs))
165 return;
166 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
167 _ ("Starting transport plugins `%s'\n"),
168 plugs);
169 for (pos = strtok (plugs, " "); pos != NULL; pos = strtok (NULL, " "))
170 {
171 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
172 _ ("Loading `%s' transport plugin\n"),
173 pos);
174 GNUNET_asprintf (&libname,
175 "libgnunet_plugin_transport_%s",
176 pos);
177 plug = GNUNET_new (struct TransportPlugin);
178 plug->short_name = GNUNET_strdup (pos);
179 plug->lib_name = libname;
180 plug->env.cfg = GST_cfg;
181 plug->env.my_identity = &GST_my_identity;
182 plug->env.get_our_hello = &GST_hello_get;
183 plug->env.cls = plug->short_name;
184 plug->env.receive = recv_cb;
185 plug->env.notify_address = address_cb;
186 plug->env.session_start = session_start_cb;
187 plug->env.session_end = session_end_cb;
188 plug->env.get_address_type = &plugin_env_address_to_type;
189 plug->env.update_address_distance = &plugin_env_update_distance;
190 plug->env.max_connections = tneigh;
191 plug->env.stats = GST_stats;
192 GNUNET_CONTAINER_DLL_insert (plugins_head,
193 plugins_tail,
194 plug);
195 }
196 GNUNET_free (plugs);
197 next = plugins_head;
198 while (NULL != next)
199 {
200 plug = next;
201 next = plug->next;
202 plug->api = GNUNET_PLUGIN_load (plug->lib_name,
203 &plug->env);
204 if (NULL == plug->api)
205 {
206 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
207 _ ("Failed to load transport plugin for `%s'\n"),
208 plug->lib_name);
209 GNUNET_CONTAINER_DLL_remove (plugins_head,
210 plugins_tail,
211 plug);
212 GNUNET_free (plug->short_name);
213 GNUNET_free (plug->lib_name);
214 GNUNET_free (plug);
215 continue;
216 }
217 fail = GNUNET_NO;
218 if (NULL == plug->api->address_pretty_printer)
219 {
220 fail = GNUNET_YES;
221 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
222 _ ("Missing function `%s' in transport plugin for `%s'\n"),
223 "address_pretty_printer",
224 plug->lib_name);
225 }
226 if (NULL == plug->api->address_to_string)
227 {
228 fail = GNUNET_YES;
229 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
230 _ ("Missing function `%s' in transport plugin for `%s'\n"),
231 "address_to_string",
232 plug->lib_name);
233 }
234 if (NULL == plug->api->string_to_address)
235 {
236 fail = GNUNET_YES;
237 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
238 _ ("Missing function `%s' in transport plugin for `%s'\n"),
239 "string_to_address",
240 plug->lib_name);
241 }
242 if (NULL == plug->api->check_address)
243 {
244 fail = GNUNET_YES;
245 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
246 _ ("Missing function `%s' in transport plugin for `%s'\n"),
247 "check_address",
248 plug->lib_name);
249 }
250 if (NULL == plug->api->get_session)
251 {
252 fail = GNUNET_YES;
253 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
254 _ ("Missing function `%s' in transport plugin for `%s'\n"),
255 "get_session",
256 plug->lib_name);
257 }
258 if (NULL == plug->api->get_network)
259 {
260 fail = GNUNET_YES;
261 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
262 _ ("Missing function `%s' in transport plugin for `%s'\n"),
263 "get_network",
264 plug->lib_name);
265 }
266 if (NULL == plug->api->send)
267 {
268 fail = GNUNET_YES;
269 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
270 _ ("Missing function `%s' in transport plugin for `%s'\n"),
271 "send",
272 plug->lib_name);
273 }
274 if (NULL == plug->api->disconnect_peer)
275 {
276 fail = GNUNET_YES;
277 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
278 _ ("Missing function `%s' in transport plugin for `%s'\n"),
279 "disconnect_peer",
280 plug->lib_name);
281 }
282 if (NULL == plug->api->disconnect_session)
283 {
284 fail = GNUNET_YES;
285 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
286 _ ("Missing function `%s' in transport plugin for `%s'\n"),
287 "disconnect_session",
288 plug->lib_name);
289 }
290 if (NULL == plug->api->query_keepalive_factor)
291 {
292 fail = GNUNET_YES;
293 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
294 _ ("Missing function `%s' in transport plugin for `%s'\n"),
295 "query_keepalive_factor",
296 plug->lib_name);
297 }
298 if (NULL == plug->api->update_session_timeout)
299 {
300 fail = GNUNET_YES;
301 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
302 _ ("Missing function `%s' in transport plugin for `%s'\n"),
303 "update_session_timeout",
304 plug->lib_name);
305 }
306 if (GNUNET_YES == fail)
307 {
308 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
309 _ ("Did not load plugin `%s' due to missing functions\n"),
310 plug->lib_name);
311 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
312 GNUNET_CONTAINER_DLL_remove (plugins_head,
313 plugins_tail,
314 plug);
315 GNUNET_free (plug->short_name);
316 GNUNET_free (plug->lib_name);
317 GNUNET_free (plug);
318 }
319 }
320}
321
322
323/**
324 * Unload all plugins
325 */
326void
327GST_plugins_unload ()
328{
329 struct TransportPlugin *plug;
330
331 while (NULL != (plug = plugins_head))
332 {
333 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
334 GNUNET_free (plug->lib_name);
335 GNUNET_free (plug->short_name);
336 GNUNET_CONTAINER_DLL_remove (plugins_head, plugins_tail, plug);
337 GNUNET_free (plug);
338 }
339}
340
341
342/**
343 * Obtain the plugin API based on a plugin name.
344 *
345 * @param name name of the plugin
346 * @return the plugin's API, NULL if the plugin is not loaded
347 */
348struct GNUNET_TRANSPORT_PluginFunctions *
349GST_plugins_find (const char *name)
350{
351 struct TransportPlugin *pos;
352
353 for (pos = plugins_head; NULL != pos; pos = pos->next)
354 if (0 == strcmp (name, pos->short_name))
355 break;
356 if (NULL == pos)
357 return NULL;
358 return pos->api;
359}
360
361
362/**
363 * Obtain the plugin API based on a the stripped plugin name after the underscore.
364 *
365 * Example: GST_plugins_printer_find (http_client) will return all plugins
366 * starting with the prefix "http":
367 * http_client or server if loaded
368 *
369 * @param name name of the plugin
370 * @return the plugin's API, NULL if the plugin is not loaded
371 */
372struct GNUNET_TRANSPORT_PluginFunctions *
373GST_plugins_printer_find (const char *name)
374{
375 struct TransportPlugin *pos;
376 char *stripped = GNUNET_strdup (name);
377 char *sep = strchr (stripped, '_');
378
379 if (NULL != sep)
380 sep[0] = '\0';
381 for (pos = plugins_head; NULL != pos; pos = pos->next)
382 if (pos->short_name == strstr (pos->short_name, stripped))
383 break;
384 GNUNET_free (stripped);
385 if (NULL == pos)
386 return NULL;
387 return pos->api;
388}
389
390
391/**
392 * Convert a given address to a human-readable format. Note that the
393 * return value will be overwritten on the next call to this function.
394 *
395 * @param address the address to convert
396 * @return statically allocated (!) human-readable address
397 */
398const char *
399GST_plugins_a2s (const struct GNUNET_HELLO_Address *address)
400{
401 struct GNUNET_TRANSPORT_PluginFunctions *api;
402 static char unable_to_show[1024];
403 static const char *s;
404
405 if (NULL == address)
406 return "<NULL>";
407 if (0 == address->address_length)
408 return TRANSPORT_SESSION_INBOUND_STRING; /* Addresse with length 0 are inbound, address->address itself may be NULL */
409 api = GST_plugins_printer_find (address->transport_name);
410 if (NULL == api)
411 {
412 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
413 "Failed to find transport plugin `%s'\n",
414 address->transport_name);
415 return "<plugin unknown>";
416 }
417 if (0 == address->address_length)
418 {
419 GNUNET_snprintf (unable_to_show,
420 sizeof(unable_to_show),
421 "<unable to stringify %u-byte long address of %s transport>",
422 (unsigned int) address->address_length,
423 address->transport_name);
424 return unable_to_show;
425 }
426 return(NULL != (s = api->address_to_string (NULL,
427 address->address,
428 address->address_length))
429 ? s
430 : "<invalid>");
431}
432
433
434/**
435 * Register callback with all plugins to monitor their status.
436 *
437 * @param cb callback to register, NULL to unsubscribe
438 * @param cb_cls closure for @a cb
439 */
440void
441GST_plugins_monitor_subscribe (GNUNET_TRANSPORT_SessionInfoCallback cb,
442 void *cb_cls)
443{
444 struct TransportPlugin *pos;
445
446 for (pos = plugins_head; NULL != pos; pos = pos->next)
447 if (NULL == pos->api->setup_monitor)
448 GNUNET_break (0);
449 else
450 pos->api->setup_monitor (pos->api->cls,
451 cb,
452 cb_cls);
453}
454
455
456/* 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 0e69da074..000000000
--- a/src/transport/gnunet-service-transport_plugins.h
+++ /dev/null
@@ -1,111 +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 register_quota_cb function to call to register a quota callback
44 * @param unregister_quota_cb function to call to unregister a quota callback
45 * @param address_cb function to call when our public addresses changed
46 * @param session_start_cb function to call when a session was created
47 * @param session_end_cb function to call when a session was terminated
48 * @param address_type_cb function to call when a address type is requested
49 * @param metric_update_cb function to call when address metrics change
50 */
51void
52GST_plugins_load (GNUNET_TRANSPORT_PluginReceiveCallback recv_cb,
53 GNUNET_TRANSPORT_AddressNotification address_cb,
54 GNUNET_TRANSPORT_SessionStart session_start_cb,
55 GNUNET_TRANSPORT_SessionEnd session_end_cb);
56
57/**
58 * Unload all plugins
59 */
60void
61GST_plugins_unload (void);
62
63
64/**
65 * Obtain the plugin API based on a plugin name.
66 *
67 * @param name name of the plugin
68 * @return the plugin's API, NULL if the plugin is not loaded
69 */
70struct GNUNET_TRANSPORT_PluginFunctions *
71GST_plugins_find (const char *name);
72
73
74/**
75 * Obtain the plugin API based on a the stripped plugin name after the underscore.
76 *
77 * Example: GST_plugins_printer_find (http_client) will return all plugins
78 * starting with the prefix "http":
79 * http_client or server if loaded
80 *
81 * @param name name of the plugin
82 * @return the plugin's API, NULL if the plugin is not loaded
83 */
84struct GNUNET_TRANSPORT_PluginFunctions *
85GST_plugins_printer_find (const char *name);
86
87
88/**
89 * Convert a given address to a human-readable format. Note that the
90 * return value will be overwritten on the next call to this function.
91 *
92 * @param address address to convert
93 * @return statically allocated (!) human-readable address
94 */
95const char *
96GST_plugins_a2s (const struct GNUNET_HELLO_Address *address);
97
98
99/**
100 * Register callback with all plugins to monitor their status.
101 *
102 * @param cb callback to register, NULL to unsubscribe
103 * @param cb_cls closure for @a cb
104 */
105void
106GST_plugins_monitor_subscribe (GNUNET_TRANSPORT_SessionInfoCallback cb,
107 void *cb_cls);
108
109
110#endif
111/* 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-certificate-creation.in b/src/transport/gnunet-transport-certificate-creation.in
deleted file mode 100644
index 771422a7a..000000000
--- a/src/transport/gnunet-transport-certificate-creation.in
+++ /dev/null
@@ -1,158 +0,0 @@
1#!/bin/sh
2#
3# This shell script will generate an X509 certificate for
4# your gnunet-transport HTTPS
5#
6# The current version partially reuses and recycles
7# code from build.sh by NetBSD (although not entirely
8# used because it needs debugging):
9#
10# Copyright (c) 2001-2011 The NetBSD Foundation, Inc.
11# All rights reserved.
12#
13# This code is derived from software contributed to
14# The NetBSD Foundation by Todd Vierling and Luke Mewburn.
15
16# Redistribution and use in source and binary forms, with or
17# without modification, are permitted provided that the following
18# conditions are met:
19# 1. Redistributions of source code must retain the above
20# copyright notice, this list of conditions and the following
21# disclaimer.
22# 2. Redistributions in binary form must reproduce the above
23# copyright notice, this list of conditions and the following
24# disclaimer in the documentation and/or other materials
25# provided with the distribution.
26
27# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
28# CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
29# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
30# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
31# DISCLAIMED.
32# IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR
33# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
34# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
35# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
37# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38# LIABILITY, OR TORT
39# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
40# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
41# OF SUCH DAMAGE.
42
43progname=${0##*/}
44
45existence() {
46 command -v "$1" >/dev/null 2>&1
47}
48
49setdefaults()
50{
51 verbosity=0
52 runcmd=
53}
54
55statusmsg()
56{
57 ${runcmd} echo " $@"
58}
59
60infomsg()
61{
62 if [ x$verbosity = x1 ]; then
63 statusmsg "INFO: $@"
64 fi
65}
66
67warningmsg()
68{
69 statusmsg "WARNING: $@"
70}
71
72errormsg()
73{
74 statusmsg "ERROR: $@"
75}
76
77linemsg()
78{
79 statusmsg "========================================="
80}
81
82
83usage()
84{
85 if [ -n "$*" ]; then
86 echo ""
87 echo "${progname}: $*"
88 fi
89 cat <<_usage_
90
91Usage: ${progname} [-hv] [-c FILE] [...]
92
93Options:
94 -c FILE Use the configuration file FILE.
95 -h Print this help message.
96 -v Print the version and exit.
97 -V be verbose
98
99_usage_
100 exit 1
101}
102
103
104generate_cert_key()
105{
106 echo ""
107 infomsg "Generating Cert and Key"
108
109 CERTTOOL=""
110 GNUTLS_CA_TEMPLATE=@PKGDATADIRECTORY@/gnunet-gns-proxy-ca.template
111 OPENSSL=0
112 if test -x $(existence gnutls-certtool)
113 #if test -z "`gnutls-certtool --version`" > /dev/null
114 then
115 if test -z "`certtool --version | grep gnutls`" > /dev/null
116 then
117 warningmsg "'gnutls-certtool' or 'certtool' command not found. Trying openssl."
118 # if test -z "`openssl version`" > /dev/null
119 if test -x $(existence openssl)
120 then
121 OPENSSL=1
122 else
123 warningmsg "Install either gnutls certtool or openssl for certificate generation!"
124 statusmsg "Cleaning up."
125 exit 1
126 fi
127 fi
128 CERTTOOL="certtool"
129 else
130 CERTTOOL="gnutls-certtool"
131 fi
132 mkdir -p `dirname $KEYFILE`
133
134 if test 1 -eq $OPENSSL
135 then
136 openssl genrsa -out $KEYFILE 1024
137 openssl req -batch -days 365 -out $CERTFILE -new -x509 -key $KEYFILE
138 else
139 $CERTTOOL --generate-privkey --outfile $KEYFILE 2>/dev/null
140 $CERTTOOL --template $GNUTLS_CA_TEMPLATE --generate-self-signed --load-privkey $KEYFILE --outfile $CERTFILE 2>/dev/null
141 fi
142 }
143
144print_version()
145{
146 GNUNET_ARM_VERSION=`gnunet-arm -v`
147 echo $GNUNET_ARM_VERSION
148}
149
150main()
151{
152 KEYFILE=$1
153 CERTFILE=$2
154 setdefaults
155 generate_cert_key
156}
157
158main "$@"
diff --git a/src/transport/gnunet-transport-profiler.c b/src/transport/gnunet-transport-profiler.c
deleted file mode 100644
index 6e5204e28..000000000
--- a/src/transport/gnunet-transport-profiler.c
+++ /dev/null
@@ -1,625 +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 src/transport/gnunet-transport-profiler.c
23 * @brief Tool to help benchmark the transport subsystem.
24 * @author Christian Grothoff
25 * @author Nathan Evans
26 *
27 * This utility can be used to benchmark a transport mechanism for
28 * GNUnet.
29 */
30#include "platform.h"
31#include "gnunet_util_lib.h"
32#include "gnunet_protocols.h"
33#include "gnunet_ats_service.h"
34#include "gnunet_transport_service.h"
35
36
37struct Iteration
38{
39 struct Iteration *next;
40 struct Iteration *prev;
41 struct GNUNET_TIME_Absolute start;
42 struct GNUNET_TIME_Absolute end;
43
44 struct GNUNET_TIME_Relative dur;
45
46 /* Transmission rate for this iteration in KB/s */
47 float rate;
48
49 unsigned int msgs_sent;
50};
51
52
53/**
54 * Timeout for a connections
55 */
56#define CONNECT_TIMEOUT \
57 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
58
59/**
60 * Benchmarking block size in bye
61 */
62#define DEFAULT_MESSAGE_SIZE 1024
63
64/**
65 * Benchmarking message count
66 */
67#define DEFAULT_MESSAGE_COUNT 1024
68
69/**
70 * Benchmarking iteration count
71 */
72#define DEFAULT_ITERATION_COUNT 1
73
74/**
75 * Option -s.
76 */
77static int benchmark_send;
78
79/**
80 * Option -b.
81 */
82static int benchmark_receive;
83
84/**
85 * Option -n.
86 */
87static unsigned int benchmark_count;
88
89/**
90 * Option -i.
91 */
92static unsigned int benchmark_iterations;
93
94/**
95 * Option -m.
96 */
97static unsigned int benchmark_size;
98
99/**
100 * Benchmark running
101 */
102static unsigned int benchmark_running;
103
104/**
105 * Which peer should we connect to?
106 */
107static char *cpid;
108
109/**
110 * Handle to transport service.
111 */
112static struct GNUNET_TRANSPORT_CoreHandle *handle;
113
114/**
115 * Handle to ATS service.
116 */
117static struct GNUNET_ATS_ConnectivityHandle *ats;
118
119/**
120 * Configuration handle
121 */
122static struct GNUNET_CONFIGURATION_Handle *cfg;
123
124/**
125 * Try_connect handle
126 */
127static struct GNUNET_ATS_ConnectivitySuggestHandle *ats_sh;
128
129static struct Iteration *ihead;
130
131static struct Iteration *itail;
132
133/**
134 * Global return value (0 success).
135 */
136static int ret;
137
138/**
139 * Handle for transmissions.
140 */
141static struct GNUNET_MQ_Handle *mq;
142
143static struct GNUNET_TRANSPORT_Blacklist *bl_handle;
144
145/**
146 * Identity of the peer we transmit to / connect to.
147 * (equivalent to 'cpid' string).
148 */
149static struct GNUNET_PeerIdentity pid;
150
151/**
152 * Selected level of verbosity.
153 */
154static unsigned int verbosity;
155
156
157/**
158 * Task run in monitor mode when the user presses CTRL-C to abort.
159 * Stops monitoring activity.
160 *
161 * @param cls NULL
162 */
163static void
164shutdown_task (void *cls)
165{
166 struct Iteration *icur;
167 struct Iteration *inext;
168
169 unsigned int iterations;
170
171 unsigned long long avg_duration;
172 float avg_rate;
173 float stddev_rate;
174 float stddev_duration;
175
176 if (NULL != ats_sh)
177 {
178 GNUNET_ATS_connectivity_suggest_cancel (ats_sh);
179 ats_sh = NULL;
180 }
181 if (NULL != bl_handle)
182 {
183 GNUNET_TRANSPORT_blacklist_cancel (bl_handle);
184 bl_handle = NULL;
185 }
186 if (NULL != ats)
187 {
188 GNUNET_ATS_connectivity_done (ats);
189 ats = NULL;
190 }
191 if (NULL != handle)
192 {
193 GNUNET_TRANSPORT_core_disconnect (handle);
194 handle = NULL;
195 }
196
197 if (verbosity > 0)
198 fprintf (stdout, "\n");
199
200 /* Output format:
201 * All time values in ms
202 * Rate in KB/s
203 * #messages;#messagesize;#avg_dur;#avg_rate;#duration_i0;#duration_i0;... */
204
205 if (benchmark_send)
206 {
207 /* First iteration to calculate avg and stddev */
208 iterations = 0;
209 avg_duration = 0;
210 avg_rate = 0.0;
211
212 inext = ihead;
213 while (NULL != (icur = inext))
214 {
215 inext = icur->next;
216 icur->rate = ((benchmark_count * benchmark_size) / 1024)
217 / ((float) icur->dur.rel_value_us / (1000 * 1000));
218 if (verbosity > 0)
219 fprintf (stdout,
220 _ ("%llu B in %llu ms == %.2f KB/s!\n"),
221 ((long long unsigned int) benchmark_count * benchmark_size),
222 ((long long unsigned int) icur->dur.rel_value_us / 1000),
223 (float) icur->rate);
224
225 avg_duration += icur->dur.rel_value_us / (1000);
226 avg_rate += icur->rate;
227 iterations++;
228 }
229 if (0 == iterations)
230 iterations = 1; /* avoid division by zero */
231 /* Calculate average rate */
232 avg_rate /= iterations;
233 /* Calculate average duration */
234 avg_duration /= iterations;
235
236 stddev_rate = 0;
237 stddev_duration = 0;
238 inext = ihead;
239 while (NULL != (icur = inext))
240 {
241 inext = icur->next;
242 stddev_rate += ((icur->rate - avg_rate) * (icur->rate - avg_rate));
243 stddev_duration += (((icur->dur.rel_value_us / 1000) - avg_duration)
244 * ((icur->dur.rel_value_us / 1000) - avg_duration));
245 }
246 /* Calculate standard deviation rate */
247 stddev_rate = stddev_rate / iterations;
248 stddev_rate = sqrtf (stddev_rate);
249
250 /* Calculate standard deviation duration */
251 stddev_duration = stddev_duration / iterations;
252 stddev_duration = sqrtf (stddev_duration);
253
254 /* Output */
255 fprintf (stdout,
256 "%u;%u;%llu;%llu;%.2f;%.2f",
257 benchmark_count,
258 benchmark_size,
259 avg_duration,
260 (unsigned long long) stddev_duration,
261 avg_rate,
262 stddev_rate);
263
264 inext = ihead;
265 while (NULL != (icur = inext))
266 {
267 inext = icur->next;
268 GNUNET_CONTAINER_DLL_remove (ihead, itail, icur);
269
270 fprintf (stdout,
271 ";%llu;%.2f",
272 (long long unsigned int) (icur->dur.rel_value_us / 1000),
273 icur->rate);
274
275 GNUNET_free (icur);
276 }
277 }
278#if 0
279 if (benchmark_receive)
280 {
281 duration = GNUNET_TIME_absolute_get_duration (start_time);
282 fprintf (stdout,
283 "Received %llu bytes/s (%llu bytes in %s)\n",
284 1000LL * 1000LL * traffic_received / (1 + duration.rel_value_us),
285 traffic_received,
286 GNUNET_STRINGS_relative_time_to_string (duration, GNUNET_YES));
287 }
288#endif
289 fprintf (stdout, "\n");
290}
291
292
293static void
294iteration_done ();
295
296
297/**
298 * Function called to notify a client about the socket
299 * begin ready to queue more data. @a buf will be
300 * NULL and @a size zero if the socket was closed for
301 * writing in the meantime.
302 *
303 * @param cls closure
304 * @param size number of bytes available in @a buf
305 * @param buf where the callee should write the message
306 * @return number of bytes written to @a buf
307 */
308static void
309send_msg (void *cls)
310{
311 struct GNUNET_MQ_Envelope *env;
312 struct GNUNET_MessageHeader *m;
313
314 if (NULL == mq)
315 return;
316 env = GNUNET_MQ_msg_extra (m, benchmark_size, GNUNET_MESSAGE_TYPE_DUMMY);
317 memset (&m[1], 52, benchmark_size - sizeof(struct GNUNET_MessageHeader));
318
319 if (itail->msgs_sent < benchmark_count)
320 {
321 GNUNET_MQ_notify_sent (env, &send_msg, NULL);
322 }
323 else
324 {
325 iteration_done ();
326 }
327 GNUNET_MQ_send (mq, env);
328 if ((verbosity > 0) && (0 == itail->msgs_sent % 10))
329 fprintf (stdout, ".");
330}
331
332
333static void
334iteration_start ()
335{
336 struct Iteration *icur;
337
338 ret = 0;
339 if (! benchmark_send)
340 return;
341 benchmark_running = GNUNET_YES;
342 icur = GNUNET_new (struct Iteration);
343 GNUNET_CONTAINER_DLL_insert_tail (ihead, itail, icur);
344 icur->start = GNUNET_TIME_absolute_get ();
345 if (verbosity > 0)
346 fprintf (
347 stdout,
348 "\nStarting benchmark, starting to send %u messages in %u byte blocks\n",
349 benchmark_count,
350 benchmark_size);
351 send_msg (NULL);
352}
353
354
355static void
356iteration_done ()
357{
358 static int it_count = 0;
359
360 it_count++;
361 itail->dur = GNUNET_TIME_absolute_get_duration (itail->start);
362 if (it_count == benchmark_iterations)
363 {
364 benchmark_running = GNUNET_NO;
365 GNUNET_SCHEDULER_shutdown ();
366 return;
367 }
368 iteration_start ();
369}
370
371
372/**
373 * Function called to notify transport users that another
374 * peer connected to us.
375 *
376 * @param cls closure
377 * @param peer the peer that connected
378 * @param m message queue for transmissions
379 * @return NULL
380 */
381static void *
382notify_connect (void *cls,
383 const struct GNUNET_PeerIdentity *peer,
384 struct GNUNET_MQ_Handle *m)
385{
386 if (0 != memcmp (&pid, peer, sizeof(struct GNUNET_PeerIdentity)))
387 {
388 fprintf (stdout, "Connected to different peer `%s'\n", GNUNET_i2s (&pid));
389 return NULL;
390 }
391
392 if (verbosity > 0)
393 fprintf (stdout, "Successfully connected to `%s'\n", GNUNET_i2s (&pid));
394 mq = m;
395 iteration_start ();
396 return NULL;
397}
398
399
400/**
401 * Function called to notify transport users that another
402 * peer disconnected from us.
403 *
404 * @param cls closure
405 * @param peer the peer that disconnected
406 * @param internal_cls NULL
407 */
408static void
409notify_disconnect (void *cls,
410 const struct GNUNET_PeerIdentity *peer,
411 void *internal_cls)
412{
413 if (0 != memcmp (&pid, peer, sizeof(struct GNUNET_PeerIdentity)))
414 return;
415 mq = NULL;
416 if (GNUNET_YES == benchmark_running)
417 {
418 fprintf (stdout,
419 "Disconnected from peer `%s' while benchmarking\n",
420 GNUNET_i2s (&pid));
421 return;
422 }
423}
424
425
426/**
427 * Function called by the transport for each received message.
428 *
429 * @param cls closure
430 * @param message the message
431 * @return #GNUNET_OK
432 */
433static int
434check_dummy (void *cls, const struct GNUNET_MessageHeader *message)
435{
436 return GNUNET_OK; /* all messages are fine */
437}
438
439
440/**
441 * Function called by the transport for each received message.
442 *
443 * @param cls closure
444 * @param message the message
445 */
446static void
447handle_dummy (void *cls, const struct GNUNET_MessageHeader *message)
448{
449 if (! benchmark_receive)
450 return;
451 if (verbosity > 0)
452 fprintf (stdout,
453 "Received %u bytes\n",
454 (unsigned int) ntohs (message->size));
455}
456
457
458static int
459blacklist_cb (void *cls, const struct GNUNET_PeerIdentity *peer)
460{
461 if (0 != memcmp (&pid, peer, sizeof(struct GNUNET_PeerIdentity)))
462 {
463 if (verbosity > 0)
464 fprintf (stdout, "Denying connection to `%s'\n", GNUNET_i2s (peer));
465 return GNUNET_SYSERR;
466 }
467 return GNUNET_OK;
468}
469
470
471/**
472 * Main function that will be run by the scheduler.
473 *
474 * @param cls closure
475 * @param args remaining command-line arguments
476 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
477 * @param mycfg configuration
478 */
479static void
480run (void *cls,
481 char *const *args,
482 const char *cfgfile,
483 const struct GNUNET_CONFIGURATION_Handle *mycfg)
484{
485 struct GNUNET_MQ_MessageHandler handlers[] =
486 { GNUNET_MQ_hd_var_size (dummy,
487 GNUNET_MESSAGE_TYPE_DUMMY,
488 struct GNUNET_MessageHeader,
489 NULL),
490 GNUNET_MQ_handler_end () };
491
492 cfg = (struct GNUNET_CONFIGURATION_Handle *) mycfg;
493
494 ret = 1;
495 if (GNUNET_MAX_MESSAGE_SIZE <= benchmark_size)
496 {
497 fprintf (stderr, "Message size too big!\n");
498 return;
499 }
500
501 if (NULL == cpid)
502 {
503 fprintf (stderr, "No peer identity given\n");
504 return;
505 }
506 if (GNUNET_OK != GNUNET_CRYPTO_eddsa_public_key_from_string (cpid,
507 strlen (cpid),
508 &pid.public_key))
509 {
510 fprintf (stderr, "Failed to parse peer identity `%s'\n", cpid);
511 return;
512 }
513 if (1 == benchmark_send)
514 {
515 if (verbosity > 0)
516 fprintf (stderr,
517 "Trying to send %u messages with size %u to peer `%s'\n",
518 benchmark_count,
519 benchmark_size,
520 GNUNET_i2s (&pid));
521 }
522 else if (1 == benchmark_receive)
523 {
524 fprintf (stderr,
525 "Trying to receive messages from peer `%s'\n",
526 GNUNET_i2s (&pid));
527 }
528 else
529 {
530 fprintf (stderr, "No operation given\n");
531 return;
532 }
533
534 ats = GNUNET_ATS_connectivity_init (cfg);
535 if (NULL == ats)
536 {
537 fprintf (stderr, "Failed to connect to ATS service\n");
538 ret = 1;
539 return;
540 }
541
542 handle = GNUNET_TRANSPORT_core_connect (cfg,
543 NULL,
544 handlers,
545 NULL,
546 &notify_connect,
547 &notify_disconnect,
548 NULL);
549 if (NULL == handle)
550 {
551 fprintf (stderr, "Failed to connect to transport service\n");
552 GNUNET_ATS_connectivity_done (ats);
553 ats = NULL;
554 ret = 1;
555 return;
556 }
557
558 bl_handle = GNUNET_TRANSPORT_blacklist (cfg, &blacklist_cb, NULL);
559 ats_sh = GNUNET_ATS_connectivity_suggest (ats, &pid, 1);
560 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
561}
562
563
564int
565main (int argc, char *const *argv)
566{
567 int res;
568
569 benchmark_count = DEFAULT_MESSAGE_COUNT;
570 benchmark_size = DEFAULT_MESSAGE_SIZE;
571 benchmark_iterations = DEFAULT_ITERATION_COUNT;
572 benchmark_running = GNUNET_NO;
573
574 struct GNUNET_GETOPT_CommandLineOption options[] = {
575 GNUNET_GETOPT_option_flag ('s',
576 "send",
577 gettext_noop ("send data to peer"),
578 &benchmark_send),
579 GNUNET_GETOPT_option_flag ('r',
580 "receive",
581 gettext_noop ("receive data from peer"),
582 &benchmark_receive),
583 GNUNET_GETOPT_option_uint ('i',
584 "iterations",
585 NULL,
586 gettext_noop ("iterations"),
587 &benchmark_iterations),
588 GNUNET_GETOPT_option_uint ('n',
589 "number",
590 NULL,
591 gettext_noop ("number of messages to send"),
592 &benchmark_count),
593 GNUNET_GETOPT_option_uint ('m',
594 "messagesize",
595 NULL,
596 gettext_noop ("message size to use"),
597 &benchmark_size),
598 GNUNET_GETOPT_option_string ('p',
599 "peer",
600 "PEER",
601 gettext_noop ("peer identity"),
602 &cpid),
603 GNUNET_GETOPT_option_verbose (&verbosity),
604 GNUNET_GETOPT_OPTION_END
605 };
606
607 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
608 return 2;
609
610 res =
611 GNUNET_PROGRAM_run (argc,
612 argv,
613 "gnunet-transport",
614 gettext_noop ("Direct access to transport service."),
615 options,
616 &run,
617 NULL);
618 GNUNET_free_nz ((void *) argv);
619 if (GNUNET_OK == res)
620 return ret;
621 return 1;
622}
623
624
625/* end of gnunet-transport-profiler.c */
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/gnunet-transport.c b/src/transport/gnunet-transport.c
deleted file mode 100644
index b5ad43770..000000000
--- a/src/transport/gnunet-transport.c
+++ /dev/null
@@ -1,1437 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011-2014, 2016, 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 src/transport/gnunet-transport.c
23 * @brief Tool to help configure, measure and control the transport subsystem.
24 * @author Christian Grothoff
25 * @author Nathan Evans
26 */
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_resolver_service.h"
30#include "gnunet_protocols.h"
31#include "gnunet_transport_service.h"
32
33/**
34 * Timeout for a name resolution
35 */
36#define RESOLUTION_TIMEOUT \
37 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
38
39/**
40 * Timeout for an operation
41 */
42#define OP_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
43
44
45/**
46 * Context to store name resolutions for valiation
47 */
48struct ValidationResolutionContext
49{
50 /**
51 * Next in DLL
52 */
53 struct ValidationResolutionContext *next;
54
55 /**
56 * Previous in DLL
57 */
58 struct ValidationResolutionContext *prev;
59
60 /**
61 * Address to resolve
62 */
63 struct GNUNET_HELLO_Address *addrcp;
64
65 /**
66 * Time of last validation
67 */
68 struct GNUNET_TIME_Absolute last_validation;
69
70 /**
71 * Address is valid until
72 */
73 struct GNUNET_TIME_Absolute valid_until;
74
75 /**
76 * Time of next validation
77 */
78 struct GNUNET_TIME_Absolute next_validation;
79
80 /**
81 * Transport conversion handle
82 */
83 struct GNUNET_TRANSPORT_AddressToStringContext *asc;
84
85 /**
86 * plugin name
87 */
88 char *transport;
89
90 /**
91 * was the entry printed
92 */
93 int printed;
94};
95
96/**
97 * Struct to store information about peers in monitor mode
98 */
99struct MonitoredPeer
100{
101 /**
102 * State of the peer
103 */
104 enum GNUNET_TRANSPORT_PeerState state;
105
106 /**
107 * Timeout
108 */
109 struct GNUNET_TIME_Absolute state_timeout;
110
111 /**
112 * The address to convert
113 */
114 struct GNUNET_HELLO_Address *address;
115};
116
117/**
118 * Context to store name resolutions for valiation
119 */
120struct PeerResolutionContext
121{
122 /**
123 * Next in DLL
124 */
125 struct PeerResolutionContext *next;
126
127 /**
128 * Prev in DLL
129 */
130 struct PeerResolutionContext *prev;
131
132 /**
133 * address to resolve
134 */
135 struct GNUNET_HELLO_Address *addrcp;
136
137 /**
138 * transport conversiion context
139 */
140 struct GNUNET_TRANSPORT_AddressToStringContext *asc;
141
142 /**
143 * peer state
144 */
145 enum GNUNET_TRANSPORT_PeerState state;
146
147 /**
148 * state timeout
149 */
150 struct GNUNET_TIME_Absolute state_timeout;
151
152 /**
153 * transport plugin
154 */
155 char *transport;
156
157 /**
158 * was the entry printed
159 */
160 int printed;
161};
162
163
164/**
165 * Benchmarking block size in KB
166 */
167#define BLOCKSIZE 4
168
169/**
170 * Handle to transport service.
171 */
172static struct GNUNET_TRANSPORT_CoreHandle *handle;
173
174/**
175 * Configuration handle
176 */
177static struct GNUNET_CONFIGURATION_Handle *cfg;
178
179/**
180 * Blacklisting handle
181 */
182struct GNUNET_TRANSPORT_Blacklist *blacklist;
183
184/**
185 * Option -s.
186 */
187static int benchmark_send;
188
189/**
190 * Option -b.
191 */
192static int benchmark_receive;
193
194/**
195 * Option -l.
196 */
197static int benchmark_receive;
198
199/**
200 * Option -i.
201 */
202static int iterate_connections;
203
204/**
205 * Option -a.
206 */
207static int iterate_all;
208
209/**
210 * Option -c.
211 */
212static int monitor_connects;
213
214/**
215 * Option -m.
216 */
217static int monitor_connections;
218
219/**
220 * Option -P.
221 */
222static int monitor_plugins;
223
224/**
225 * Option -D.
226 */
227static int do_disconnect;
228
229/**
230 * Option -n.
231 */
232static int numeric;
233
234/**
235 * Global return value (0 success).
236 */
237static int ret;
238
239/**
240 * Current number of connections in monitor mode
241 */
242static int monitor_connect_counter;
243
244/**
245 * Number of bytes of traffic we received so far.
246 */
247static unsigned long long traffic_received;
248
249/**
250 * Number of bytes of traffic we sent so far.
251 */
252static unsigned long long traffic_sent;
253
254/**
255 * Starting time of transmitting/receiving data.
256 */
257static struct GNUNET_TIME_Absolute start_time;
258
259/**
260 * Map storing information about monitored peers
261 */
262static struct GNUNET_CONTAINER_MultiPeerMap *monitored_peers;
263
264/**
265 * Map storing information about monitored plugins's sessions.
266 */
267static struct GNUNET_CONTAINER_MultiPeerMap *monitored_plugins;
268
269/**
270 * Handle if we are monitoring peers at the transport level.
271 */
272static struct GNUNET_TRANSPORT_PeerMonitoringContext *pic;
273
274/**
275 * Handle if we are monitoring plugin session activity.
276 */
277static struct GNUNET_TRANSPORT_PluginMonitor *pm;
278
279/**
280 * Identity of the peer we transmit to / connect to.
281 * ('-p' command-line option).
282 */
283static struct GNUNET_PeerIdentity pid;
284
285/**
286 * Task for operation timeout
287 */
288static struct GNUNET_SCHEDULER_Task *op_timeout;
289
290/**
291 * Selected level of verbosity.
292 */
293static unsigned int verbosity;
294
295/**
296 * Resolver process handle.
297 */
298struct GNUNET_OS_Process *resolver;
299
300/**
301 * Number of address resolutions pending
302 */
303static unsigned int address_resolutions;
304
305/**
306 * DLL: head of validation resolution entries
307 */
308static struct ValidationResolutionContext *vc_head;
309
310/**
311 * DLL: tail of validation resolution entries
312 */
313static struct ValidationResolutionContext *vc_tail;
314
315/**
316 * DLL: head of resolution entries
317 */
318static struct PeerResolutionContext *rc_head;
319
320/**
321 * DLL: head of resolution entries
322 */
323static struct PeerResolutionContext *rc_tail;
324
325
326/**
327 * Function called to release data stored in the #monitored_peers map.
328 *
329 * @param cls unused
330 * @param key the peer identity
331 * @param value a `struct MonitoredPeer` to release
332 * @return #GNUNET_OK (continue to iterate)
333 */
334static int
335destroy_it (void *cls, const struct GNUNET_PeerIdentity *key, void *value)
336{
337 struct MonitoredPeer *m = value;
338
339 GNUNET_assert (
340 GNUNET_OK ==
341 GNUNET_CONTAINER_multipeermap_remove (monitored_peers, key, value));
342 GNUNET_free (m->address);
343 GNUNET_free (value);
344 return GNUNET_OK;
345}
346
347
348/**
349 * Task run in monitor mode when the user presses CTRL-C to abort.
350 * Stops monitoring activity.
351 *
352 * @param cls NULL
353 */
354static void
355shutdown_task (void *cls)
356{
357 struct GNUNET_TIME_Relative duration;
358 struct ValidationResolutionContext *cur;
359 struct ValidationResolutionContext *next;
360 struct PeerResolutionContext *rc;
361
362 if (NULL != op_timeout)
363 {
364 GNUNET_SCHEDULER_cancel (op_timeout);
365 op_timeout = NULL;
366 }
367 if (NULL != pic)
368 {
369 GNUNET_TRANSPORT_monitor_peers_cancel (pic);
370 pic = NULL;
371 }
372 if (NULL != pm)
373 {
374 GNUNET_TRANSPORT_monitor_plugins_cancel (pm);
375 pm = NULL;
376 }
377
378 next = vc_head;
379 for (cur = next; NULL != cur; cur = next)
380 {
381 next = cur->next;
382
383 GNUNET_TRANSPORT_address_to_string_cancel (cur->asc);
384 GNUNET_CONTAINER_DLL_remove (vc_head, vc_tail, cur);
385 GNUNET_free (cur->transport);
386 GNUNET_HELLO_address_free (cur->addrcp);
387 GNUNET_free (cur);
388 }
389 while (NULL != (rc = rc_head))
390 {
391 GNUNET_CONTAINER_DLL_remove (rc_head, rc_tail, rc);
392 GNUNET_TRANSPORT_address_to_string_cancel (rc->asc);
393 GNUNET_free (rc->transport);
394 GNUNET_free (rc->addrcp);
395 GNUNET_free (rc);
396 }
397 if (NULL != handle)
398 {
399 GNUNET_TRANSPORT_core_disconnect (handle);
400 handle = NULL;
401 }
402 if (benchmark_send)
403 {
404 duration = GNUNET_TIME_absolute_get_duration (start_time);
405 fprintf (stdout,
406 _ ("Transmitted %llu bytes/s (%llu bytes in %s)\n"),
407 1000LL * 1000LL * traffic_sent / (1 + duration.rel_value_us),
408 traffic_sent,
409 GNUNET_STRINGS_relative_time_to_string (duration, GNUNET_YES));
410 }
411 if (benchmark_receive)
412 {
413 duration = GNUNET_TIME_absolute_get_duration (start_time);
414 fprintf (stdout,
415 _ ("Received %llu bytes/s (%llu bytes in %s)\n"),
416 1000LL * 1000LL * traffic_received / (1 + duration.rel_value_us),
417 traffic_received,
418 GNUNET_STRINGS_relative_time_to_string (duration, GNUNET_YES));
419 }
420
421 if (NULL != monitored_peers)
422 {
423 GNUNET_CONTAINER_multipeermap_iterate (monitored_peers, &destroy_it, NULL);
424 GNUNET_CONTAINER_multipeermap_destroy (monitored_peers);
425 monitored_peers = NULL;
426 }
427 if (NULL != monitored_plugins)
428 {
429 GNUNET_break (0 == GNUNET_CONTAINER_multipeermap_size (monitored_plugins));
430 GNUNET_CONTAINER_multipeermap_destroy (monitored_plugins);
431 monitored_plugins = NULL;
432 }
433 if (NULL != blacklist)
434 {
435 GNUNET_TRANSPORT_blacklist_cancel (blacklist);
436 blacklist = NULL;
437 ret = 0;
438 }
439}
440
441
442/**
443 * We are done, shut down.
444 */
445static void
446operation_timeout (void *cls)
447{
448 struct PeerResolutionContext *cur;
449 struct PeerResolutionContext *next;
450
451 op_timeout = NULL;
452 if ((benchmark_send) || (benchmark_receive))
453 {
454 fprintf (stdout, _ ("Failed to connect to `%s'\n"), GNUNET_i2s_full (&pid));
455 GNUNET_SCHEDULER_shutdown ();
456 ret = 1;
457 return;
458 }
459 if (iterate_connections)
460 {
461 next = rc_head;
462 while (NULL != (cur = next))
463 {
464 next = cur->next;
465 fprintf (stdout,
466 _ ("Failed to resolve address for peer `%s'\n"),
467 GNUNET_i2s (&cur->addrcp->peer));
468
469 GNUNET_CONTAINER_DLL_remove (rc_head, rc_tail, cur);
470 GNUNET_TRANSPORT_address_to_string_cancel (cur->asc);
471 GNUNET_free (cur->transport);
472 GNUNET_free (cur->addrcp);
473 GNUNET_free (cur);
474 }
475 fprintf (stdout,
476 "%s",
477 _ ("Failed to list connections, timeout occurred\n"));
478 GNUNET_SCHEDULER_shutdown ();
479 ret = 1;
480 return;
481 }
482}
483
484
485/**
486 * Function called to notify a client about the socket
487 * begin ready to queue more data. Sends another message.
488 *
489 * @param cls closure with the message queue
490 */
491static void
492do_send (void *cls)
493{
494 struct GNUNET_MQ_Handle *mq = cls;
495 struct GNUNET_MessageHeader *m;
496 struct GNUNET_MQ_Envelope *env;
497
498 env = GNUNET_MQ_msg_extra (m, BLOCKSIZE * 1024, GNUNET_MESSAGE_TYPE_DUMMY);
499 memset (&m[1], 52, BLOCKSIZE * 1024 - sizeof(struct GNUNET_MessageHeader));
500 traffic_sent += BLOCKSIZE * 1024;
501 GNUNET_MQ_notify_sent (env, &do_send, mq);
502 if (verbosity > 0)
503 fprintf (stdout,
504 _ ("Transmitting %u bytes\n"),
505 (unsigned int) BLOCKSIZE * 1024);
506 GNUNET_MQ_send (mq, env);
507}
508
509
510/**
511 * Function called to notify transport users that another
512 * peer connected to us.
513 *
514 * @param cls closure
515 * @param peer the peer that connected
516 * @param mq message queue for sending to @a peer
517 */
518static void *
519notify_connect (void *cls,
520 const struct GNUNET_PeerIdentity *peer,
521 struct GNUNET_MQ_Handle *mq)
522{
523 if (0 != memcmp (&pid, peer, sizeof(struct GNUNET_PeerIdentity)))
524 return NULL;
525 ret = 0;
526 if (! benchmark_send)
527 return NULL;
528 if (NULL != op_timeout)
529 {
530 GNUNET_SCHEDULER_cancel (op_timeout);
531 op_timeout = NULL;
532 }
533 if (verbosity > 0)
534 fprintf (
535 stdout,
536 _ (
537 "Successfully connected to `%s', starting to send benchmark data in %u Kb blocks\n"),
538 GNUNET_i2s (peer),
539 BLOCKSIZE);
540 start_time = GNUNET_TIME_absolute_get ();
541 do_send (mq);
542 return mq;
543}
544
545
546/**
547 * Function called to notify transport users that another
548 * peer disconnected from us.
549 *
550 * @param cls closure
551 * @param peer the peer that disconnected
552 * @param internal_cls what we returned from #notify_connect()
553 */
554static void
555notify_disconnect (void *cls,
556 const struct GNUNET_PeerIdentity *peer,
557 void *internal_cls)
558{
559 if (0 != memcmp (&pid, peer, sizeof(struct GNUNET_PeerIdentity)))
560 return;
561 if (NULL == internal_cls)
562 return; /* not about target peer */
563 if (! benchmark_send)
564 return; /* not transmitting */
565 fprintf (stdout,
566 _ ("Disconnected from peer `%s' while benchmarking\n"),
567 GNUNET_i2s (&pid));
568}
569
570
571/**
572 * Function called to notify transport users that another
573 * peer connected to us.
574 *
575 * @param cls closure
576 * @param peer the peer that connected
577 * @param mq for sending messages to @a peer
578 * @return NULL
579 */
580static void *
581monitor_notify_connect (void *cls,
582 const struct GNUNET_PeerIdentity *peer,
583 struct GNUNET_MQ_Handle *mq)
584{
585 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
586 const char *now_str = GNUNET_STRINGS_absolute_time_to_string (now);
587
588 monitor_connect_counter++;
589 fprintf (stdout,
590 _ ("%24s: %-17s %4s (%u connections in total)\n"),
591 now_str,
592 _ ("Connected to"),
593 GNUNET_i2s (peer),
594 monitor_connect_counter);
595 return NULL;
596}
597
598
599/**
600 * Function called to notify transport users that another
601 * peer disconnected from us.
602 *
603 * @param cls closure
604 * @param peer the peer that disconnected
605 * @param internal_cls what we returned from #monitor_notify_connect()
606 */
607static void
608monitor_notify_disconnect (void *cls,
609 const struct GNUNET_PeerIdentity *peer,
610 void *internal_cls)
611{
612 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
613 const char *now_str = GNUNET_STRINGS_absolute_time_to_string (now);
614
615 GNUNET_assert (monitor_connect_counter > 0);
616 monitor_connect_counter--;
617
618 fprintf (stdout,
619 _ ("%24s: %-17s %4s (%u connections in total)\n"),
620 now_str,
621 _ ("Disconnected from"),
622 GNUNET_i2s (peer),
623 monitor_connect_counter);
624}
625
626
627/**
628 * Function called by the transport for each received message.
629 *
630 * @param cls closure
631 * @param message the message
632 * @return #GNUNET_OK
633 */
634static int
635check_dummy (void *cls, const struct GNUNET_MessageHeader *message)
636{
637 return GNUNET_OK; /* all messages are fine */
638}
639
640
641/**
642 * Function called by the transport for each received message.
643 *
644 * @param cls closure
645 * @param message the message
646 */
647static void
648handle_dummy (void *cls, const struct GNUNET_MessageHeader *message)
649{
650 if (! benchmark_receive)
651 return;
652 if (verbosity > 0)
653 fprintf (stdout,
654 _ ("Received %u bytes\n"),
655 (unsigned int) ntohs (message->size));
656 if (0 == traffic_received)
657 start_time = GNUNET_TIME_absolute_get ();
658 traffic_received += ntohs (message->size);
659}
660
661
662/**
663 * Convert address to a printable format.
664 *
665 * @param address the address
666 * @param numeric #GNUNET_YES to convert to numeric format, #GNUNET_NO
667 * to try to use reverse DNS
668 * @param state state the peer is in
669 * @param state_timeout when will the peer's state expire
670 */
671static void
672resolve_peer_address (const struct GNUNET_HELLO_Address *address,
673 int numeric,
674 enum GNUNET_TRANSPORT_PeerState state,
675 struct GNUNET_TIME_Absolute state_timeout);
676
677
678static void
679print_info (const struct GNUNET_PeerIdentity *id,
680 const char *transport,
681 const char *addr,
682 enum GNUNET_TRANSPORT_PeerState state,
683 struct GNUNET_TIME_Absolute state_timeout)
684{
685 if (((GNUNET_YES == iterate_connections) && (GNUNET_YES == iterate_all)) ||
686 (GNUNET_YES == monitor_connections))
687 {
688 fprintf (stdout,
689 _ ("Peer `%s': %s %s in state `%s' until %s\n"),
690 GNUNET_i2s (id),
691 (NULL == transport) ? "<none>" : transport,
692 (NULL == transport) ? "<none>" : addr,
693 GNUNET_TRANSPORT_ps2s (state),
694 GNUNET_STRINGS_absolute_time_to_string (state_timeout));
695 }
696 else if ((GNUNET_YES == iterate_connections) &&
697 (GNUNET_TRANSPORT_is_connected (state)))
698 {
699 /* Only connected peers, skip state */
700 fprintf (stdout,
701 _ ("Peer `%s': %s %s\n"),
702 GNUNET_i2s (id),
703 transport,
704 addr);
705 }
706}
707
708
709/**
710 * Function called with a textual representation of an address. This
711 * function will be called several times with different possible
712 * textual representations, and a last time with @a address being NULL
713 * to signal the end of the iteration. Note that @a address NULL
714 * always is the last call, regardless of the value in @a res.
715 *
716 * @param cls closure
717 * @param address NULL on end of iteration,
718 * otherwise 0-terminated printable UTF-8 string,
719 * in particular an empty string if @a res is #GNUNET_NO
720 * @param res result of the address to string conversion:
721 * if #GNUNET_OK: conversion successful
722 * if #GNUNET_NO: address was invalid (or not supported)
723 * if #GNUNET_SYSERR: communication error (IPC error)
724 */
725static void
726process_peer_string (void *cls, const char *address, int res)
727{
728 struct PeerResolutionContext *rc = cls;
729
730 if (NULL != address)
731 {
732 if (GNUNET_SYSERR == res)
733 {
734 fprintf (
735 stderr,
736 "Failed to convert address for peer `%s' plugin `%s' length %u to string \n",
737 GNUNET_i2s (&rc->addrcp->peer),
738 rc->addrcp->transport_name,
739 (unsigned int) rc->addrcp->address_length);
740 print_info (&rc->addrcp->peer,
741 rc->transport,
742 NULL,
743 rc->state,
744 rc->state_timeout);
745 rc->printed = GNUNET_YES;
746 return;
747 }
748 if (GNUNET_OK == res)
749 {
750 print_info (&rc->addrcp->peer,
751 rc->transport,
752 address,
753 rc->state,
754 rc->state_timeout);
755 rc->printed = GNUNET_YES;
756 return; /* Wait for done call */
757 }
758 /* GNUNET_NO == res: ignore, was simply not supported */
759 return;
760 }
761 /* NULL == address, last call, we are done */
762
763 rc->asc = NULL;
764 GNUNET_assert (address_resolutions > 0);
765 address_resolutions--;
766 if (GNUNET_NO == rc->printed)
767 {
768 if (numeric == GNUNET_NO)
769 {
770 /* Failed to resolve address, try numeric lookup
771 (note: this should not be needed, as transport
772 should fallback to numeric conversion if DNS takes
773 too long) */
774 resolve_peer_address (rc->addrcp,
775 GNUNET_YES,
776 rc->state,
777 rc->state_timeout);
778 }
779 else
780 {
781 print_info (&rc->addrcp->peer,
782 rc->transport,
783 NULL,
784 rc->state,
785 rc->state_timeout);
786 }
787 }
788 GNUNET_free (rc->transport);
789 GNUNET_free (rc->addrcp);
790 GNUNET_CONTAINER_DLL_remove (rc_head, rc_tail, rc);
791 GNUNET_free (rc);
792 if ((0 == address_resolutions) && (iterate_connections))
793 {
794 if (NULL != op_timeout)
795 {
796 GNUNET_SCHEDULER_cancel (op_timeout);
797 op_timeout = NULL;
798 }
799 ret = 0;
800 GNUNET_SCHEDULER_shutdown ();
801 }
802}
803
804
805/**
806 * Convert address to a printable format and print it
807 * together with the given state data.
808 *
809 * @param address the address
810 * @param numeric #GNUNET_YES to convert to numeric format, #GNUNET_NO
811 * to try to use reverse DNS
812 * @param state state the peer is in
813 * @param state_timeout when will the peer's state expire
814 */
815static void
816resolve_peer_address (const struct GNUNET_HELLO_Address *address,
817 int numeric,
818 enum GNUNET_TRANSPORT_PeerState state,
819 struct GNUNET_TIME_Absolute state_timeout)
820{
821 struct PeerResolutionContext *rc;
822
823 rc = GNUNET_new (struct PeerResolutionContext);
824 GNUNET_CONTAINER_DLL_insert (rc_head, rc_tail, rc);
825 address_resolutions++;
826 rc->transport = GNUNET_strdup (address->transport_name);
827 rc->addrcp = GNUNET_HELLO_address_copy (address);
828 rc->printed = GNUNET_NO;
829 rc->state = state;
830 rc->state_timeout = state_timeout;
831 /* Resolve address to string */
832 rc->asc = GNUNET_TRANSPORT_address_to_string (cfg,
833 address,
834 numeric,
835 RESOLUTION_TIMEOUT,
836 &process_peer_string,
837 rc);
838}
839
840
841/**
842 * Function called with information about a peers during a one shot iteration
843 *
844 * @param cls closure
845 * @param peer identity of the peer, NULL for final callback when operation done
846 * @param address binary address used to communicate with this peer,
847 * NULL on disconnect or when done
848 * @param state current state this peer is in
849 * @param state_timeout time out for the current state
850 */
851static void
852process_peer_iteration_cb (void *cls,
853 const struct GNUNET_PeerIdentity *peer,
854 const struct GNUNET_HELLO_Address *address,
855 enum GNUNET_TRANSPORT_PeerState state,
856 struct GNUNET_TIME_Absolute state_timeout)
857{
858 if (NULL == peer)
859 {
860 /* done */
861 pic = NULL;
862 return;
863 }
864
865 if ((GNUNET_NO == iterate_all) &&
866 (GNUNET_NO == GNUNET_TRANSPORT_is_connected (state)))
867 return; /* Display only connected peers */
868
869 if (NULL != op_timeout)
870 GNUNET_SCHEDULER_cancel (op_timeout);
871 op_timeout =
872 GNUNET_SCHEDULER_add_delayed (OP_TIMEOUT, &operation_timeout, NULL);
873
874 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
875 "Received address for peer `%s': %s\n",
876 GNUNET_i2s (peer),
877 address ? address->transport_name : "");
878
879 if (NULL != address)
880 resolve_peer_address (address, numeric, state, state_timeout);
881 else
882 print_info (peer, NULL, NULL, state, state_timeout);
883}
884
885
886/**
887 * Context for address resolution by #plugin_monitoring_cb().
888 */
889struct PluginMonitorAddress
890{
891 /**
892 * Ongoing resolution request.
893 */
894 struct GNUNET_TRANSPORT_AddressToStringContext *asc;
895
896 /**
897 * Resolved address as string.
898 */
899 char *str;
900
901 /**
902 * Last event we got and did not yet print because
903 * @e str was NULL (address not yet resolved).
904 */
905 struct GNUNET_TRANSPORT_SessionInfo si;
906};
907
908
909/**
910 * Print information about a plugin monitoring event.
911 *
912 * @param addr out internal context
913 * @param info the monitoring information
914 */
915static void
916print_plugin_event_info (struct PluginMonitorAddress *addr,
917 const struct GNUNET_TRANSPORT_SessionInfo *info)
918{
919 const char *state;
920
921 switch (info->state)
922 {
923 case GNUNET_TRANSPORT_SS_INIT:
924 state = "INIT";
925 break;
926
927 case GNUNET_TRANSPORT_SS_HANDSHAKE:
928 state = "HANDSHAKE";
929 break;
930
931 case GNUNET_TRANSPORT_SS_UP:
932 state = "UP";
933 break;
934
935 case GNUNET_TRANSPORT_SS_UPDATE:
936 state = "UPDATE";
937 break;
938
939 case GNUNET_TRANSPORT_SS_DONE:
940 state = "DONE";
941 break;
942
943 default:
944 state = "UNKNOWN";
945 break;
946 }
947 fprintf (stdout,
948 "%s: state %s timeout in %s @ %s%s\n",
949 GNUNET_i2s (&info->address->peer),
950 state,
951 GNUNET_STRINGS_relative_time_to_string (
952 GNUNET_TIME_absolute_get_remaining (info->session_timeout),
953 GNUNET_YES),
954 addr->str,
955 (info->is_inbound == GNUNET_YES) ? " (INBOUND)" : "");
956 fprintf (stdout,
957 "%s: queue has %3u messages and %6u bytes\n",
958 GNUNET_i2s (&info->address->peer),
959 info->num_msg_pending,
960 info->num_bytes_pending);
961 if (0 !=
962 GNUNET_TIME_absolute_get_remaining (info->receive_delay).rel_value_us)
963 fprintf (stdout,
964 "%s: receiving blocked until %s\n",
965 GNUNET_i2s (&info->address->peer),
966 GNUNET_STRINGS_absolute_time_to_string (info->receive_delay));
967}
968
969
970/**
971 * Function called with a textual representation of an address. This
972 * function will be called several times with different possible
973 * textual representations, and a last time with @a address being NULL
974 * to signal the end of the iteration. Note that @a address NULL
975 * always is the last call, regardless of the value in @a res.
976 *
977 * @param cls closure
978 * @param address NULL on end of iteration,
979 * otherwise 0-terminated printable UTF-8 string,
980 * in particular an empty string if @a res is #GNUNET_NO
981 * @param res result of the address to string conversion:
982 * if #GNUNET_OK: conversion successful
983 * if #GNUNET_NO: address was invalid (or not supported)
984 * if #GNUNET_SYSERR: communication error (IPC error)
985 */
986static void
987address_cb (void *cls, const char *address, int res)
988{
989 struct PluginMonitorAddress *addr = cls;
990
991 if (NULL == address)
992 {
993 addr->asc = NULL;
994 return;
995 }
996 if (NULL != addr->str)
997 return;
998 addr->str = GNUNET_strdup (address);
999 print_plugin_event_info (addr, &addr->si);
1000}
1001
1002
1003/**
1004 * Function called by the plugin with information about the
1005 * current sessions managed by the plugin (for monitoring).
1006 *
1007 * @param cls closure (NULL)
1008 * @param session session handle this information is about,
1009 * NULL to indicate that we are "in sync" (initial
1010 * iteration complete)
1011 * @param session_ctx storage location where the application
1012 * can store data; will point to NULL on #GNUNET_TRANSPORT_SS_INIT,
1013 * and must be reset to NULL on #GNUNET_TRANSPORT_SS_DONE
1014 * @param info information about the state of the session,
1015 * NULL if @a session is also NULL and we are
1016 * merely signalling that the initial iteration is over;
1017 * NULL with @a session being non-NULL if the monitor
1018 * was being cancelled while sessions were active
1019 */
1020static void
1021plugin_monitoring_cb (void *cls,
1022 struct GNUNET_TRANSPORT_PluginSession *session,
1023 void **session_ctx,
1024 const struct GNUNET_TRANSPORT_SessionInfo *info)
1025{
1026 struct PluginMonitorAddress *addr;
1027
1028 if ((NULL == info) && (NULL == session))
1029 return; /* in sync with transport service */
1030 addr = *session_ctx;
1031 if (NULL == info)
1032 {
1033 if (NULL != addr)
1034 {
1035 if (NULL != addr->asc)
1036 {
1037 GNUNET_TRANSPORT_address_to_string_cancel (addr->asc);
1038 addr->asc = NULL;
1039 }
1040 GNUNET_free (addr->str);
1041 GNUNET_free (addr);
1042 *session_ctx = NULL;
1043 }
1044 return; /* shutdown */
1045 }
1046 if (0 !=
1047 memcmp (&info->address->peer, &pid, sizeof(struct GNUNET_PeerIdentity)))
1048 return; /* filtered */
1049 if (NULL == addr)
1050 {
1051 addr = GNUNET_new (struct PluginMonitorAddress);
1052 addr->asc =
1053 GNUNET_TRANSPORT_address_to_string (cfg,
1054 info->address,
1055 numeric,
1056 GNUNET_TIME_UNIT_FOREVER_REL,
1057 &address_cb,
1058 addr);
1059 *session_ctx = addr;
1060 }
1061 if (NULL == addr->str)
1062 addr->si = *info;
1063 else
1064 print_plugin_event_info (addr, info);
1065 if (GNUNET_TRANSPORT_SS_DONE == info->state)
1066 {
1067 if (NULL != addr->asc)
1068 {
1069 GNUNET_TRANSPORT_address_to_string_cancel (addr->asc);
1070 addr->asc = NULL;
1071 }
1072 GNUNET_free (addr->str);
1073 GNUNET_free (addr);
1074 *session_ctx = NULL;
1075 }
1076}
1077
1078
1079/**
1080 * Function called with information about a peers
1081 *
1082 * @param cls closure, NULL
1083 * @param peer identity of the peer, NULL for final callback when operation done
1084 * @param address binary address used to communicate with this peer,
1085 * NULL on disconnect or when done
1086 * @param state current state this peer is in
1087 * @param state_timeout time out for the current state
1088 */
1089static void
1090process_peer_monitoring_cb (void *cls,
1091 const struct GNUNET_PeerIdentity *peer,
1092 const struct GNUNET_HELLO_Address *address,
1093 enum GNUNET_TRANSPORT_PeerState state,
1094 struct GNUNET_TIME_Absolute state_timeout)
1095{
1096 struct MonitoredPeer *m;
1097
1098 if (NULL == peer)
1099 {
1100 fprintf (stdout,
1101 "%s",
1102 _ (
1103 "Monitor disconnected from transport service. Reconnecting.\n"));
1104 return;
1105 }
1106
1107 if (NULL != op_timeout)
1108 GNUNET_SCHEDULER_cancel (op_timeout);
1109 op_timeout =
1110 GNUNET_SCHEDULER_add_delayed (OP_TIMEOUT, &operation_timeout, NULL);
1111
1112 if (NULL == (m = GNUNET_CONTAINER_multipeermap_get (monitored_peers, peer)))
1113 {
1114 m = GNUNET_new (struct MonitoredPeer);
1115 GNUNET_CONTAINER_multipeermap_put (
1116 monitored_peers,
1117 peer,
1118 m,
1119 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1120 }
1121 else
1122 {
1123 if ((m->state == state) &&
1124 (m->state_timeout.abs_value_us == state_timeout.abs_value_us) &&
1125 (NULL == address) && (NULL == m->address))
1126 {
1127 return; /* No real change */
1128 }
1129 if ((m->state == state) && (NULL != address) && (NULL != m->address) &&
1130 (0 == GNUNET_HELLO_address_cmp (m->address, address)))
1131 return; /* No real change */
1132 }
1133
1134 if (NULL != m->address)
1135 {
1136 GNUNET_free (m->address);
1137 m->address = NULL;
1138 }
1139 if (NULL != address)
1140 m->address = GNUNET_HELLO_address_copy (address);
1141 m->state = state;
1142 m->state_timeout = state_timeout;
1143
1144 if (NULL != address)
1145 resolve_peer_address (m->address, numeric, m->state, m->state_timeout);
1146 else
1147 print_info (peer, NULL, NULL, m->state, m->state_timeout);
1148}
1149
1150
1151/**
1152 * Function called with the transport service checking if we
1153 * want to blacklist a peer. Return #GNUNET_SYSERR for the
1154 * peer that we should disconnect from.
1155 *
1156 * @param cls NULL
1157 * @param cpid peer to check blacklisting for
1158 * @return #GNUNET_OK if the connection is allowed, #GNUNET_SYSERR if not
1159 */
1160static int
1161blacklist_cb (void *cls, const struct GNUNET_PeerIdentity *cpid)
1162{
1163 if (0 == memcmp (cpid, &pid, sizeof(struct GNUNET_PeerIdentity)))
1164 return GNUNET_SYSERR;
1165 return GNUNET_OK;
1166}
1167
1168
1169/**
1170 * Main function that will be run by the scheduler.
1171 *
1172 * @param cls closure
1173 * @param args remaining command-line arguments
1174 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1175 * @param mycfg configuration
1176 */
1177static void
1178run (void *cls,
1179 char *const *args,
1180 const char *cfgfile,
1181 const struct GNUNET_CONFIGURATION_Handle *mycfg)
1182{
1183 static struct GNUNET_PeerIdentity zero_pid;
1184 int counter = 0;
1185
1186 ret = 1;
1187
1188 cfg = (struct GNUNET_CONFIGURATION_Handle *) mycfg;
1189
1190 counter = benchmark_send + benchmark_receive + iterate_connections
1191 + monitor_connections + monitor_connects + do_disconnect
1192 + monitor_plugins;
1193
1194 if (1 < counter)
1195 {
1196 fprintf (
1197 stderr,
1198 _ (
1199 "Multiple operations given. Please choose only one operation: %s, %s, %s, %s, %s, %s %s\n"),
1200 "disconnect",
1201 "benchmark send",
1202 "benchmark receive",
1203 "information",
1204 "monitor",
1205 "events",
1206 "plugins");
1207 return;
1208 }
1209 if (0 == counter)
1210 {
1211 fprintf (
1212 stderr,
1213 _ (
1214 "No operation given. Please choose one operation: %s, %s, %s, %s, %s, %s, %s\n"),
1215 "disconnect",
1216 "benchmark send",
1217 "benchmark receive",
1218 "information",
1219 "monitor",
1220 "events",
1221 "plugins");
1222 return;
1223 }
1224
1225 if (do_disconnect) /* -D: Disconnect from peer */
1226 {
1227 if (0 == memcmp (&zero_pid, &pid, sizeof(pid)))
1228 {
1229 fprintf (stderr,
1230 _ ("Option `%s' makes no sense without option `%s'.\n"),
1231 "-D",
1232 "-p");
1233 ret = 1;
1234 return;
1235 }
1236 blacklist = GNUNET_TRANSPORT_blacklist (cfg, &blacklist_cb, NULL);
1237 if (NULL == blacklist)
1238 {
1239 fprintf (stderr,
1240 "%s",
1241 _ (
1242 "Failed to connect to transport service for disconnection\n"));
1243 ret = 1;
1244 return;
1245 }
1246 fprintf (stdout,
1247 "%s",
1248 _ ("Blacklisting request in place, stop with CTRL-C\n"));
1249 }
1250 else if (benchmark_send) /* -s: Benchmark sending */
1251 {
1252 if (0 == memcmp (&zero_pid, &pid, sizeof(pid)))
1253 {
1254 fprintf (stderr,
1255 _ ("Option `%s' makes no sense without option `%s'.\n"),
1256 "-s",
1257 "-p");
1258 ret = 1;
1259 return;
1260 }
1261 handle = GNUNET_TRANSPORT_core_connect (cfg,
1262 NULL,
1263 NULL,
1264 NULL,
1265 &notify_connect,
1266 &notify_disconnect,
1267 NULL);
1268 if (NULL == handle)
1269 {
1270 fprintf (stderr, "%s", _ ("Failed to connect to transport service\n"));
1271 ret = 1;
1272 return;
1273 }
1274 start_time = GNUNET_TIME_absolute_get ();
1275 op_timeout =
1276 GNUNET_SCHEDULER_add_delayed (OP_TIMEOUT, &operation_timeout, NULL);
1277 }
1278 else if (benchmark_receive) /* -b: Benchmark receiving */
1279 {
1280 struct GNUNET_MQ_MessageHandler handlers[] =
1281 { GNUNET_MQ_hd_var_size (dummy,
1282 GNUNET_MESSAGE_TYPE_DUMMY,
1283 struct GNUNET_MessageHeader,
1284 NULL),
1285 GNUNET_MQ_handler_end () };
1286
1287 handle = GNUNET_TRANSPORT_core_connect (cfg,
1288 NULL,
1289 handlers,
1290 NULL,
1291 NULL,
1292 NULL,
1293 NULL);
1294 if (NULL == handle)
1295 {
1296 fprintf (stderr, "%s", _ ("Failed to connect to transport service\n"));
1297 ret = 1;
1298 return;
1299 }
1300 if (verbosity > 0)
1301 fprintf (stdout, "%s", _ ("Starting to receive benchmark data\n"));
1302 start_time = GNUNET_TIME_absolute_get ();
1303 }
1304 else if (iterate_connections) /* -i: List information about peers once */
1305 {
1306 pic = GNUNET_TRANSPORT_monitor_peers (cfg,
1307 &pid,
1308 GNUNET_YES,
1309 &process_peer_iteration_cb,
1310 (void *) cfg);
1311 op_timeout =
1312 GNUNET_SCHEDULER_add_delayed (OP_TIMEOUT, &operation_timeout, NULL);
1313 }
1314 else if (monitor_connections) /* -m: List information about peers continuously
1315 */
1316 {
1317 monitored_peers = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO);
1318 pic = GNUNET_TRANSPORT_monitor_peers (cfg,
1319 &pid,
1320 GNUNET_NO,
1321 &process_peer_monitoring_cb,
1322 NULL);
1323 }
1324 else if (monitor_plugins) /* -P: List information about plugins continuously
1325 */
1326 {
1327 monitored_plugins = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO);
1328 pm = GNUNET_TRANSPORT_monitor_plugins (cfg, &plugin_monitoring_cb, NULL);
1329 }
1330 else if (monitor_connects) /* -e : Monitor (dis)connect events continuously */
1331 {
1332 monitor_connect_counter = 0;
1333 handle = GNUNET_TRANSPORT_core_connect (cfg,
1334 NULL,
1335 NULL,
1336 NULL,
1337 &monitor_notify_connect,
1338 &monitor_notify_disconnect,
1339 NULL);
1340 if (NULL == handle)
1341 {
1342 fprintf (stderr, "%s", _ ("Failed to connect to transport service\n"));
1343 ret = 1;
1344 return;
1345 }
1346 ret = 0;
1347 }
1348 else
1349 {
1350 GNUNET_break (0);
1351 return;
1352 }
1353
1354 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
1355}
1356
1357
1358int
1359main (int argc, char *const *argv)
1360{
1361 int res;
1362 struct GNUNET_GETOPT_CommandLineOption options[] =
1363 { GNUNET_GETOPT_option_flag (
1364 'a',
1365 "all",
1366 gettext_noop (
1367 "print information for all peers (instead of only connected peers)"),
1368 &iterate_all),
1369 GNUNET_GETOPT_option_flag (
1370 'b',
1371 "benchmark",
1372 gettext_noop (
1373 "measure how fast we are receiving data from all peers (until CTRL-C)"),
1374 &benchmark_receive),
1375 GNUNET_GETOPT_option_flag ('D',
1376 "disconnect",
1377 gettext_noop ("disconnect from a peer"),
1378 &do_disconnect),
1379 GNUNET_GETOPT_option_flag (
1380 'i',
1381 "information",
1382 gettext_noop (
1383 "provide information about all current connections (once)"),
1384 &iterate_connections),
1385 GNUNET_GETOPT_option_flag (
1386 'm',
1387 "monitor",
1388 gettext_noop (
1389 "provide information about all current connections (continuously)"),
1390 &monitor_connections),
1391 GNUNET_GETOPT_option_flag (
1392 'e',
1393 "events",
1394 gettext_noop (
1395 "provide information about all connects and disconnect events (continuously)"),
1396 &monitor_connects),
1397 GNUNET_GETOPT_option_flag ('n',
1398 "numeric",
1399 gettext_noop ("do not resolve hostnames"),
1400 &numeric),
1401 GNUNET_GETOPT_option_base32_auto ('p',
1402 "peer",
1403 "PEER",
1404 gettext_noop ("peer identity"),
1405 &pid),
1406 GNUNET_GETOPT_option_flag ('P',
1407 "plugins",
1408 gettext_noop ("monitor plugin sessions"),
1409 &monitor_plugins),
1410 GNUNET_GETOPT_option_flag (
1411 's',
1412 "send",
1413 gettext_noop (
1414 "send data for benchmarking to the other peer (until CTRL-C)"),
1415 &benchmark_send),
1416 GNUNET_GETOPT_option_verbose (&verbosity),
1417 GNUNET_GETOPT_OPTION_END };
1418
1419 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
1420 return 2;
1421
1422 res =
1423 GNUNET_PROGRAM_run (argc,
1424 argv,
1425 "gnunet-transport",
1426 gettext_noop ("Direct access to transport service."),
1427 options,
1428 &run,
1429 NULL);
1430 GNUNET_free_nz ((void *) argv);
1431 if (GNUNET_OK == res)
1432 return ret;
1433 return 1;
1434}
1435
1436
1437/* end of gnunet-transport.c */
diff --git a/src/transport/ieee80211_radiotap.h b/src/transport/ieee80211_radiotap.h
deleted file mode 100644
index 9351da9a5..000000000
--- a/src/transport/ieee80211_radiotap.h
+++ /dev/null
@@ -1,276 +0,0 @@
1/*
2 * Copyright (c) 2003, 2004 David Young. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of David Young may not be used to endorse or promote
13 * products derived from this software without specific prior
14 * written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
19 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID
20 * YOUNG BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
22 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
27 * OF SUCH DAMAGE.
28 */
29
30/*
31 * Modifications to fit into the linux IEEE 802.11 stack,
32 * Mike Kershaw (dragorn@kismetwireless.net)
33 */
34
35#ifndef IEEE80211RADIOTAP_H
36#define IEEE80211RADIOTAP_H
37
38#include <linux/if_ether.h>
39#include <linux/kernel.h>
40// #include <asm/unaligned.h>
41
42/* Base version of the radiotap packet header data */
43#define PKTHDR_RADIOTAP_VERSION 0
44
45/* A generic radio capture format is desirable. There is one for
46 * Linux, but it is neither rigidly defined (there were not even
47 * units given for some fields) nor easily extensible.
48 *
49 * I suggest the following extensible radio capture format. It is
50 * based on a bitmap indicating which fields are present.
51 *
52 * I am trying to describe precisely what the application programmer
53 * should expect in the following, and for that reason I tell the
54 * units and origin of each measurement (where it applies), or else I
55 * use sufficiently weaselly language ("is a monotonically nondecreasing
56 * function of...") that I cannot set false expectations for lawyerly
57 * readers.
58 */
59
60/*
61 * The radio capture header precedes the 802.11 header.
62 * All data in the header is little endian on all platforms.
63 */
64struct ieee80211_radiotap_header
65{
66 u8 it_version; /* Version 0. Only increases
67 * for drastic changes,
68 * introduction of compatible
69 * new fields does not count.
70 */
71 u8 it_pad;
72 __le16 it_len; /* length of the whole
73 * header in bytes, including
74 * it_version, it_pad,
75 * it_len, and data fields.
76 */
77 __le32 it_present; /* A bitmap telling which
78 * fields are present. Set bit 31
79 * (0x80000000) to extend the
80 * bitmap by another 32 bits.
81 * Additional extensions are made
82 * by setting bit 31.
83 */
84} __packed;
85
86/* Name Data type Units
87 * ---- --------- -----
88 *
89 * IEEE80211_RADIOTAP_TSFT __le64 microseconds
90 *
91 * Value in microseconds of the MAC's 64-bit 802.11 Time
92 * Synchronization Function timer when the first bit of the
93 * MPDU arrived at the MAC. For received frames, only.
94 *
95 * IEEE80211_RADIOTAP_CHANNEL 2 x __le16 MHz, bitmap
96 *
97 * Tx/Rx frequency in MHz, followed by flags (see below).
98 *
99 * IEEE80211_RADIOTAP_FHSS __le16 see below
100 *
101 * For frequency-hopping radios, the hop set (first byte)
102 * and pattern (second byte).
103 *
104 * IEEE80211_RADIOTAP_RATE u8 500kb/s
105 *
106 * Tx/Rx data rate
107 *
108 * IEEE80211_RADIOTAP_DBM_ANTSIGNAL s8 decibels from
109 * one milliwatt (dBm)
110 *
111 * RF signal power at the antenna, decibel difference from
112 * one milliwatt.
113 *
114 * IEEE80211_RADIOTAP_DBM_ANTNOISE s8 decibels from
115 * one milliwatt (dBm)
116 *
117 * RF noise power at the antenna, decibel difference from one
118 * milliwatt.
119 *
120 * IEEE80211_RADIOTAP_DB_ANTSIGNAL u8 decibel (dB)
121 *
122 * RF signal power at the antenna, decibel difference from an
123 * arbitrary, fixed reference.
124 *
125 * IEEE80211_RADIOTAP_DB_ANTNOISE u8 decibel (dB)
126 *
127 * RF noise power at the antenna, decibel difference from an
128 * arbitrary, fixed reference point.
129 *
130 * IEEE80211_RADIOTAP_LOCK_QUALITY __le16 unitless
131 *
132 * Quality of Barker code lock. Unitless. Monotonically
133 * nondecreasing with "better" lock strength. Called "Signal
134 * Quality" in datasheets. (Is there a standard way to measure
135 * this?)
136 *
137 * IEEE80211_RADIOTAP_TX_ATTENUATION __le16 unitless
138 *
139 * Transmit power expressed as unitless distance from max
140 * power set at factory calibration. 0 is max power.
141 * Monotonically nondecreasing with lower power levels.
142 *
143 * IEEE80211_RADIOTAP_DB_TX_ATTENUATION __le16 decibels (dB)
144 *
145 * Transmit power expressed as decibel distance from max power
146 * set at factory calibration. 0 is max power. Monotonically
147 * nondecreasing with lower power levels.
148 *
149 * IEEE80211_RADIOTAP_DBM_TX_POWER s8 decibels from
150 * one milliwatt (dBm)
151 *
152 * Transmit power expressed as dBm (decibels from a 1 milliwatt
153 * reference). This is the absolute power level measured at
154 * the antenna port.
155 *
156 * IEEE80211_RADIOTAP_FLAGS u8 bitmap
157 *
158 * Properties of transmitted and received frames. See flags
159 * defined below.
160 *
161 * IEEE80211_RADIOTAP_ANTENNA u8 antenna index
162 *
163 * Unitless indication of the Rx/Tx antenna for this packet.
164 * The first antenna is antenna 0.
165 *
166 * IEEE80211_RADIOTAP_RX_FLAGS __le16 bitmap
167 *
168 * Properties of received frames. See flags defined below.
169 *
170 * IEEE80211_RADIOTAP_TX_FLAGS __le16 bitmap
171 *
172 * Properties of transmitted frames. See flags defined below.
173 *
174 * IEEE80211_RADIOTAP_RTS_RETRIES u8 data
175 *
176 * Number of rts retries a transmitted frame used.
177 *
178 * IEEE80211_RADIOTAP_DATA_RETRIES u8 data
179 *
180 * Number of unicast retries a transmitted frame used.
181 *
182 */
183enum ieee80211_radiotap_type
184{
185 IEEE80211_RADIOTAP_TSFT = 0,
186 IEEE80211_RADIOTAP_FLAGS = 1,
187 IEEE80211_RADIOTAP_RATE = 2,
188 IEEE80211_RADIOTAP_CHANNEL = 3,
189 IEEE80211_RADIOTAP_FHSS = 4,
190 IEEE80211_RADIOTAP_DBM_ANTSIGNAL = 5,
191 IEEE80211_RADIOTAP_DBM_ANTNOISE = 6,
192 IEEE80211_RADIOTAP_LOCK_QUALITY = 7,
193 IEEE80211_RADIOTAP_TX_ATTENUATION = 8,
194 IEEE80211_RADIOTAP_DB_TX_ATTENUATION = 9,
195 IEEE80211_RADIOTAP_DBM_TX_POWER = 10,
196 IEEE80211_RADIOTAP_ANTENNA = 11,
197 IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12,
198 IEEE80211_RADIOTAP_DB_ANTNOISE = 13,
199 IEEE80211_RADIOTAP_RX_FLAGS = 14,
200 IEEE80211_RADIOTAP_TX_FLAGS = 15,
201 IEEE80211_RADIOTAP_RTS_RETRIES = 16,
202 IEEE80211_RADIOTAP_DATA_RETRIES = 17,
203
204 /* valid in every it_present bitmap, even vendor namespaces */
205 IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE = 29,
206 IEEE80211_RADIOTAP_VENDOR_NAMESPACE = 30,
207 IEEE80211_RADIOTAP_EXT = 31
208};
209
210/* Channel flags. */
211#define IEEE80211_CHAN_TURBO 0x0010 /* Turbo channel */
212#define IEEE80211_CHAN_CCK 0x0020 /* CCK channel */
213#define IEEE80211_CHAN_OFDM 0x0040 /* OFDM channel */
214#define IEEE80211_CHAN_2GHZ 0x0080 /* 2 GHz spectrum channel. */
215#define IEEE80211_CHAN_5GHZ 0x0100 /* 5 GHz spectrum channel */
216#define IEEE80211_CHAN_PASSIVE 0x0200 /* Only passive scan allowed */
217#define IEEE80211_CHAN_DYN 0x0400 /* Dynamic CCK-OFDM channel */
218#define IEEE80211_CHAN_GFSK 0x0800 /* GFSK channel (FHSS PHY) */
219
220/* For IEEE80211_RADIOTAP_FLAGS */
221#define IEEE80211_RADIOTAP_F_CFP 0x01 /* sent/received
222 * during CFP
223 */
224#define IEEE80211_RADIOTAP_F_SHORTPRE 0x02 /* sent/received
225 * with short
226 * preamble
227 */
228#define IEEE80211_RADIOTAP_F_WEP 0x04 /* sent/received
229 * with WEP encryption
230 */
231#define IEEE80211_RADIOTAP_F_FRAG 0x08 /* sent/received
232 * with fragmentation
233 */
234#define IEEE80211_RADIOTAP_F_FCS 0x10 /* frame includes FCS */
235#define IEEE80211_RADIOTAP_F_DATAPAD 0x20 /* frame has padding between
236 * 802.11 header and payload
237 * (to 32-bit boundary)
238 */
239#define IEEE80211_RADIOTAP_F_BADFCS 0x40 /* bad FCS */
240
241/* For IEEE80211_RADIOTAP_RX_FLAGS */
242#define IEEE80211_RADIOTAP_F_RX_BADPLCP 0x0002 /* frame has bad PLCP */
243
244/* For IEEE80211_RADIOTAP_TX_FLAGS */
245#define IEEE80211_RADIOTAP_F_TX_FAIL 0x0001 /* failed due to excessive
246 * retries */
247#define IEEE80211_RADIOTAP_F_TX_CTS 0x0002 /* used cts 'protection' */
248#define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */
249
250/* Ugly macro to convert literal channel numbers into their mhz equivalents
251 * There are certainly some conditions that will break this (like feeding it '30')
252 * but they shouldn't arise since nothing talks on channel 30. */
253#define ieee80211chan2mhz(x) \
254 (((x) <= 14) ? \
255 (((x) == 14) ? 2484 : ((x) * 5) + 2407) : \
256 ((x) + 1000) * 5)
257
258/* helpers */
259static inline u16
260get_unaligned_le16 (const u8 *p)
261{
262 return p[0] | p[1] << 8;
263}
264
265
266static inline int
267ieee80211_get_radiotap_len (unsigned char *data)
268{
269 struct ieee80211_radiotap_header *hdr =
270 (struct ieee80211_radiotap_header *) data;
271
272 return get_unaligned_le16 ((const u8 *) &hdr->it_len);
273}
274
275
276#endif /* IEEE80211_RADIOTAP_H */
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 476a3cd52..000000000
--- a/src/transport/plugin_transport_http_client.c
+++ /dev/null
@@ -1,2529 +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 * @param tc gnunet scheduler task context
560 */
561static void
562client_run (void *cls);
563
564
565/**
566 * Function setting up file descriptors and scheduling task to run
567 *
568 * @param plugin the plugin as closure
569 * @param now schedule task in 1ms, regardless of what curl may say
570 * @return #GNUNET_SYSERR for hard failure, #GNUNET_OK for ok
571 */
572static int
573client_schedule (struct HTTP_Client_Plugin *plugin,
574 int now)
575{
576 fd_set rs;
577 fd_set ws;
578 fd_set es;
579 int max;
580 struct GNUNET_NETWORK_FDSet *grs;
581 struct GNUNET_NETWORK_FDSet *gws;
582 long to;
583 CURLMcode mret;
584 struct GNUNET_TIME_Relative timeout;
585
586 /* Cancel previous scheduled task */
587 if (plugin->client_perform_task != NULL)
588 {
589 GNUNET_SCHEDULER_cancel (plugin->client_perform_task);
590 plugin->client_perform_task = NULL;
591 }
592 max = -1;
593 FD_ZERO (&rs);
594 FD_ZERO (&ws);
595 FD_ZERO (&es);
596 mret = curl_multi_fdset (plugin->curl_multi_handle, &rs, &ws, &es, &max);
597 if (mret != CURLM_OK)
598 {
599 LOG (GNUNET_ERROR_TYPE_ERROR,
600 _ ("%s failed at %s:%d: `%s'\n"),
601 "curl_multi_fdset",
602 __FILE__,
603 __LINE__,
604 curl_multi_strerror (mret));
605 return GNUNET_SYSERR;
606 }
607 mret = curl_multi_timeout (plugin->curl_multi_handle, &to);
608 if (-1 == to)
609 timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1);
610 else
611 timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, to);
612 if (now == GNUNET_YES)
613 timeout = GNUNET_TIME_UNIT_MILLISECONDS;
614
615 if (CURLM_OK != mret)
616 {
617 LOG (GNUNET_ERROR_TYPE_ERROR,
618 _ ("%s failed at %s:%d: `%s'\n"),
619 "curl_multi_timeout", __FILE__, __LINE__,
620 curl_multi_strerror (mret));
621 return GNUNET_SYSERR;
622 }
623
624 grs = GNUNET_NETWORK_fdset_create ();
625 gws = GNUNET_NETWORK_fdset_create ();
626 GNUNET_NETWORK_fdset_copy_native (grs, &rs, max + 1);
627 GNUNET_NETWORK_fdset_copy_native (gws, &ws, max + 1);
628
629 /* Schedule task to run when select is ready to read or write */
630 plugin->client_perform_task =
631 GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
632 timeout, grs, gws,
633 &client_run, plugin);
634 GNUNET_NETWORK_fdset_destroy (gws);
635 GNUNET_NETWORK_fdset_destroy (grs);
636 return GNUNET_OK;
637}
638
639
640#if VERBOSE_CURL
641/**
642 * Logging function
643 *
644 * @param curl the curl easy handle
645 * @param type message type
646 * @param data data to log, NOT a 0-terminated string
647 * @param size data length
648 * @param cls the closure
649 * @return always 0
650 */
651static int
652client_log (CURL *curl,
653 curl_infotype type,
654 const char *data,
655 size_t size,
656 void *cls)
657{
658 struct RequestHandle *ch = cls;
659 const char *ttype = "UNSPECIFIED";
660 char text[size + 2];
661
662 if (! ((CURLINFO_TEXT == type) ||
663 (CURLINFO_HEADER_IN == type) ||
664 (CURLINFO_HEADER_OUT == type)))
665 return 0;
666 switch (type)
667 {
668 case CURLINFO_TEXT:
669 ttype = "TEXT";
670 break;
671
672 case CURLINFO_HEADER_IN:
673 ttype = "HEADER_IN";
674 break;
675
676 case CURLINFO_HEADER_OUT:
677 ttype = "HEADER_OUT";
678 /* Overhead*/
679 GNUNET_assert (NULL != ch);
680 GNUNET_assert (NULL != ch->easyhandle);
681 GNUNET_assert (NULL != ch->s);
682 ch->s->overhead += size;
683 break;
684
685 default:
686 ttype = "UNSPECIFIED";
687 break;
688 }
689 GNUNET_memcpy (text, data, size);
690 if (text[size - 1] == '\n')
691 {
692 text[size] = '\0';
693 }
694 else
695 {
696 text[size] = '\n';
697 text[size + 1] = '\0';
698 }
699 LOG (GNUNET_ERROR_TYPE_DEBUG,
700 "Request %p %s: %s",
701 ch->easyhandle,
702 ttype,
703 text);
704 return 0;
705}
706
707
708#endif
709
710/**
711 * Connect GET request
712 *
713 * @param s the session to connect
714 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
715 */
716static int
717client_connect_get (struct GNUNET_ATS_Session *s);
718
719
720/**
721 * Connect a HTTP put request
722 *
723 * @param s the session to connect
724 * @return #GNUNET_SYSERR for hard failure, #GNUNET_OK for success
725 */
726static int
727client_connect_put (struct GNUNET_ATS_Session *s);
728
729
730/**
731 * Function that can be used by the transport service to transmit
732 * a message using the plugin. Note that in the case of a
733 * peer disconnecting, the continuation MUST be called
734 * prior to the disconnect notification itself. This function
735 * will be called with this peer's HELLO message to initiate
736 * a fresh connection to another peer.
737 *
738 * @param cls closure
739 * @param s which session must be used
740 * @param msgbuf the message to transmit
741 * @param msgbuf_size number of bytes in @a msgbuf
742 * @param priority how important is the message (most plugins will
743 * ignore message priority and just FIFO)
744 * @param to how long to wait at most for the transmission (does not
745 * require plugins to discard the message after the timeout,
746 * just advisory for the desired delay; most plugins will ignore
747 * this as well)
748 * @param cont continuation to call once the message has
749 * been transmitted (or if the transport is ready
750 * for the next transmission call; or if the
751 * peer disconnected...); can be NULL
752 * @param cont_cls closure for @a cont
753 * @return number of bytes used (on the physical network, with overheads);
754 * -1 on hard errors (i.e. address invalid); 0 is a legal value
755 * and does NOT mean that the message was not transmitted (DV)
756 */
757static ssize_t
758http_client_plugin_send (void *cls,
759 struct GNUNET_ATS_Session *s,
760 const char *msgbuf,
761 size_t msgbuf_size,
762 unsigned int priority,
763 struct GNUNET_TIME_Relative to,
764 GNUNET_TRANSPORT_TransmitContinuation cont,
765 void *cont_cls)
766{
767 struct HTTP_Client_Plugin *plugin = cls;
768 struct HTTP_Message *msg;
769 char *stat_txt;
770
771 LOG (GNUNET_ERROR_TYPE_DEBUG,
772 "Session %p/request %p: Sending message with %lu to peer `%s' \n",
773 s,
774 s->put.easyhandle,
775 (unsigned long) msgbuf_size,
776 GNUNET_i2s (&s->address->peer));
777
778 /* create new message and schedule */
779 msg = GNUNET_malloc (sizeof(struct HTTP_Message) + msgbuf_size);
780 msg->size = msgbuf_size;
781 msg->buf = (char *) &msg[1];
782 msg->transmit_cont = cont;
783 msg->transmit_cont_cls = cont_cls;
784 GNUNET_memcpy (msg->buf,
785 msgbuf,
786 msgbuf_size);
787 GNUNET_CONTAINER_DLL_insert_tail (s->msg_head,
788 s->msg_tail,
789 msg);
790 s->msgs_in_queue++;
791 s->bytes_in_queue += msg->size;
792
793 GNUNET_asprintf (&stat_txt,
794 "# bytes currently in %s_client buffers",
795 plugin->protocol);
796 GNUNET_STATISTICS_update (plugin->env->stats,
797 stat_txt, msgbuf_size, GNUNET_NO);
798 GNUNET_free (stat_txt);
799 notify_session_monitor (plugin,
800 s,
801 GNUNET_TRANSPORT_SS_UPDATE);
802 if (H_TMP_DISCONNECTING == s->put.state)
803 {
804 /* PUT request is currently getting disconnected */
805 s->put.state = H_TMP_RECONNECT_REQUIRED;
806 LOG (GNUNET_ERROR_TYPE_DEBUG,
807 "Session %p/request %p: currently disconnecting, reconnecting immediately\n",
808 s,
809 s->put.easyhandle);
810 return msgbuf_size;
811 }
812 if (H_PAUSED == s->put.state)
813 {
814 /* PUT request was paused, unpause */
815 GNUNET_assert (s->put_disconnect_task != NULL);
816 GNUNET_SCHEDULER_cancel (s->put_disconnect_task);
817 s->put_disconnect_task = NULL;
818 LOG (GNUNET_ERROR_TYPE_DEBUG,
819 "Session %p/request %p: unpausing request\n",
820 s, s->put.easyhandle);
821 s->put.state = H_CONNECTED;
822 if (NULL != s->put.easyhandle)
823 curl_easy_pause (s->put.easyhandle, CURLPAUSE_CONT);
824 }
825 else if (H_TMP_DISCONNECTED == s->put.state)
826 {
827 /* PUT request was disconnected, reconnect */
828 LOG (GNUNET_ERROR_TYPE_DEBUG, "Session %p: Reconnecting PUT request\n", s);
829 GNUNET_break (NULL == s->put.easyhandle);
830 if (GNUNET_SYSERR == client_connect_put (s))
831 {
832 /* Could not reconnect */
833 http_client_plugin_session_disconnect (plugin, s);
834 return GNUNET_SYSERR;
835 }
836 }
837 client_schedule (s->plugin, GNUNET_YES);
838 return msgbuf_size;
839}
840
841
842/**
843 * Disconnect a session
844 *
845 * @param cls the `struct HTTP_Client_Plugin *`
846 * @param s session
847 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
848 */
849static int
850http_client_plugin_session_disconnect (void *cls,
851 struct GNUNET_ATS_Session *s)
852{
853 struct HTTP_Client_Plugin *plugin = cls;
854
855 LOG (GNUNET_ERROR_TYPE_DEBUG,
856 "Session %p: notifying transport about ending session\n",
857 s);
858 plugin->env->session_end (plugin->env->cls,
859 s->address,
860 s);
861 client_delete_session (s);
862
863 /* Re-schedule since handles have changed */
864 if (NULL != plugin->client_perform_task)
865 {
866 GNUNET_SCHEDULER_cancel (plugin->client_perform_task);
867 plugin->client_perform_task = NULL;
868 }
869 client_schedule (plugin, GNUNET_YES);
870
871 return GNUNET_OK;
872}
873
874
875/**
876 * Function that is called to get the keepalive factor.
877 * #GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT is divided by this number to
878 * calculate the interval between keepalive packets.
879 *
880 * @param cls closure with the `struct Plugin`
881 * @return keepalive factor
882 */
883static unsigned int
884http_client_query_keepalive_factor (void *cls)
885{
886 return 3;
887}
888
889
890/**
891 * Callback to destroys all sessions on exit.
892 *
893 * @param cls the `struct HTTP_Client_Plugin *`
894 * @param peer identity of the peer
895 * @param value the `struct GNUNET_ATS_Session *`
896 * @return #GNUNET_OK (continue iterating)
897 */
898static int
899destroy_session_cb (void *cls,
900 const struct GNUNET_PeerIdentity *peer,
901 void *value)
902{
903 struct HTTP_Client_Plugin *plugin = cls;
904 struct GNUNET_ATS_Session *session = value;
905
906 http_client_plugin_session_disconnect (plugin, session);
907 return GNUNET_OK;
908}
909
910
911/**
912 * Function that can be used to force the plugin to disconnect
913 * from the given peer and cancel all previous transmissions
914 * (and their continuationc).
915 *
916 * @param cls closure
917 * @param target peer from which to disconnect
918 */
919static void
920http_client_plugin_peer_disconnect (void *cls,
921 const struct GNUNET_PeerIdentity *target)
922{
923 struct HTTP_Client_Plugin *plugin = cls;
924
925 LOG (GNUNET_ERROR_TYPE_DEBUG,
926 "Transport tells me to disconnect `%s'\n",
927 GNUNET_i2s (target));
928 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessions,
929 target,
930 &destroy_session_cb,
931 plugin);
932}
933
934
935/**
936 * Closure for #session_lookup_client_by_address().
937 */
938struct GNUNET_ATS_SessionClientCtx
939{
940 /**
941 * Address we are looking for.
942 */
943 const struct GNUNET_HELLO_Address *address;
944
945 /**
946 * Session that was found.
947 */
948 struct GNUNET_ATS_Session *ret;
949};
950
951
952/**
953 * Locate the seession object for a given address.
954 *
955 * @param cls the `struct GNUNET_ATS_SessionClientCtx *`
956 * @param key peer identity
957 * @param value the `struct GNUNET_ATS_Session` to check
958 * @return #GNUNET_NO if found, #GNUNET_OK if not
959 */
960static int
961session_lookup_client_by_address (void *cls,
962 const struct GNUNET_PeerIdentity *key,
963 void *value)
964{
965 struct GNUNET_ATS_SessionClientCtx *sc_ctx = cls;
966 struct GNUNET_ATS_Session *s = value;
967
968 if (0 == GNUNET_HELLO_address_cmp (sc_ctx->address,
969 s->address))
970 {
971 sc_ctx->ret = s;
972 return GNUNET_NO;
973 }
974 return GNUNET_YES;
975}
976
977
978/**
979 * Check if a sessions exists for an specific address
980 *
981 * @param plugin the plugin
982 * @param address the address
983 * @return the session or NULL
984 */
985static struct GNUNET_ATS_Session *
986client_lookup_session (struct HTTP_Client_Plugin *plugin,
987 const struct GNUNET_HELLO_Address *address)
988{
989 struct GNUNET_ATS_SessionClientCtx sc_ctx;
990
991 sc_ctx.address = address;
992 sc_ctx.ret = NULL;
993 GNUNET_CONTAINER_multipeermap_iterate (plugin->sessions,
994 &session_lookup_client_by_address,
995 &sc_ctx);
996 return sc_ctx.ret;
997}
998
999
1000/**
1001 * When we have nothing to transmit, we pause the HTTP PUT
1002 * after a while (so that gnurl stops asking). This task
1003 * is the delayed task that actually disconnects the PUT.
1004 *
1005 * @param cls the `struct GNUNET_ATS_Session *` with the put
1006 */
1007static void
1008client_put_disconnect (void *cls)
1009{
1010 struct GNUNET_ATS_Session *s = cls;
1011
1012 s->put_disconnect_task = NULL;
1013 LOG (GNUNET_ERROR_TYPE_DEBUG,
1014 "Session %p/request %p: will be disconnected due to no activity\n",
1015 s, s->put.easyhandle);
1016 s->put.state = H_TMP_DISCONNECTING;
1017 if (NULL != s->put.easyhandle)
1018 curl_easy_pause (s->put.easyhandle,
1019 CURLPAUSE_CONT);
1020 client_schedule (s->plugin, GNUNET_YES);
1021}
1022
1023
1024/**
1025 * Callback method used with libcurl
1026 * Method is called when libcurl needs to read data during sending
1027 *
1028 * @param stream pointer where to write data
1029 * @param size size of an individual element
1030 * @param nmemb count of elements that can be written to the buffer
1031 * @param cls our `struct GNUNET_ATS_Session`
1032 * @return bytes written to stream, returning 0 will terminate request!
1033 */
1034static size_t
1035client_send_cb (void *stream,
1036 size_t size,
1037 size_t nmemb,
1038 void *cls)
1039{
1040 struct GNUNET_ATS_Session *s = cls;
1041 struct HTTP_Client_Plugin *plugin = s->plugin;
1042 struct HTTP_Message *msg = s->msg_head;
1043 size_t len;
1044 char *stat_txt;
1045
1046 if (H_TMP_DISCONNECTING == s->put.state)
1047 {
1048 LOG (GNUNET_ERROR_TYPE_DEBUG,
1049 "Session %p/request %p: disconnect due to inactivity\n",
1050 s, s->put.easyhandle);
1051 return 0;
1052 }
1053
1054 if (NULL == msg)
1055 {
1056 if (GNUNET_YES == plugin->emulate_xhr)
1057 {
1058 LOG (GNUNET_ERROR_TYPE_DEBUG,
1059 "Session %p/request %p: PUT request finished\n",
1060 s,
1061 s->put.easyhandle);
1062 s->put.state = H_TMP_DISCONNECTING;
1063 return 0;
1064 }
1065
1066 /* We have nothing to send, so pause PUT request */
1067 LOG (GNUNET_ERROR_TYPE_DEBUG,
1068 "Session %p/request %p: nothing to send, suspending\n",
1069 s,
1070 s->put.easyhandle);
1071 s->put_disconnect_task
1072 = GNUNET_SCHEDULER_add_delayed (PUT_DISCONNECT_TIMEOUT,
1073 &client_put_disconnect,
1074 s);
1075 s->put.state = H_PAUSED;
1076 return CURL_READFUNC_PAUSE;
1077 }
1078 /* data to send */
1079 GNUNET_assert (msg->pos < msg->size);
1080 /* calculate how much fits in buffer */
1081 len = GNUNET_MIN (msg->size - msg->pos,
1082 size * nmemb);
1083 GNUNET_memcpy (stream,
1084 &msg->buf[msg->pos],
1085 len);
1086 msg->pos += len;
1087 if (msg->pos == msg->size)
1088 {
1089 LOG (GNUNET_ERROR_TYPE_DEBUG,
1090 "Session %p/request %p: sent message with %lu bytes sent, removing message from queue\n",
1091 s,
1092 s->put.easyhandle,
1093 (unsigned long) msg->size);
1094 /* Calling transmit continuation */
1095 GNUNET_CONTAINER_DLL_remove (s->msg_head,
1096 s->msg_tail,
1097 msg);
1098 GNUNET_assert (0 < s->msgs_in_queue);
1099 s->msgs_in_queue--;
1100 GNUNET_assert (msg->size <= s->bytes_in_queue);
1101 s->bytes_in_queue -= msg->size;
1102 if (NULL != msg->transmit_cont)
1103 msg->transmit_cont (msg->transmit_cont_cls,
1104 &s->address->peer,
1105 GNUNET_OK,
1106 msg->size,
1107 msg->size + s->overhead);
1108 s->overhead = 0;
1109 GNUNET_free (msg);
1110 }
1111 notify_session_monitor (plugin,
1112 s,
1113 GNUNET_TRANSPORT_SS_UPDATE);
1114 GNUNET_asprintf (&stat_txt,
1115 "# bytes currently in %s_client buffers",
1116 plugin->protocol);
1117 GNUNET_STATISTICS_update (plugin->env->stats,
1118 stat_txt,
1119 -len,
1120 GNUNET_NO);
1121 GNUNET_free (stat_txt);
1122 GNUNET_asprintf (&stat_txt,
1123 "# bytes transmitted via %s_client",
1124 plugin->protocol);
1125 GNUNET_STATISTICS_update (plugin->env->stats,
1126 stat_txt,
1127 len,
1128 GNUNET_NO);
1129 GNUNET_free (stat_txt);
1130 return len;
1131}
1132
1133
1134/**
1135 * Wake up a curl handle which was suspended
1136 *
1137 * @param cls the session
1138 */
1139static void
1140client_wake_up (void *cls)
1141{
1142 struct GNUNET_ATS_Session *s = cls;
1143
1144 s->recv_wakeup_task = NULL;
1145 LOG (GNUNET_ERROR_TYPE_DEBUG,
1146 "Session %p/request %p: Waking up GET handle\n",
1147 s, s->get.easyhandle);
1148 if (H_PAUSED == s->put.state)
1149 {
1150 /* PUT request was paused, unpause */
1151 GNUNET_assert (s->put_disconnect_task != NULL);
1152 GNUNET_SCHEDULER_cancel (s->put_disconnect_task);
1153 s->put_disconnect_task = NULL;
1154 s->put.state = H_CONNECTED;
1155 if (NULL != s->put.easyhandle)
1156 curl_easy_pause (s->put.easyhandle, CURLPAUSE_CONT);
1157 }
1158 if (NULL != s->get.easyhandle)
1159 curl_easy_pause (s->get.easyhandle, CURLPAUSE_CONT);
1160}
1161
1162
1163/**
1164 * Callback for message stream tokenizer
1165 *
1166 * @param cls the session
1167 * @param message the message received
1168 * @return always #GNUNET_OK
1169 */
1170static int
1171client_receive_mst_cb (void *cls,
1172 const struct GNUNET_MessageHeader *message)
1173{
1174 struct GNUNET_ATS_Session *s = cls;
1175 struct HTTP_Client_Plugin *plugin;
1176 struct GNUNET_TIME_Relative delay;
1177 char *stat_txt;
1178
1179 plugin = s->plugin;
1180 delay = s->plugin->env->receive (plugin->env->cls,
1181 s->address,
1182 s,
1183 message);
1184 GNUNET_asprintf (&stat_txt,
1185 "# bytes received via %s_client",
1186 plugin->protocol);
1187 GNUNET_STATISTICS_update (plugin->env->stats,
1188 stat_txt,
1189 ntohs (message->size),
1190 GNUNET_NO);
1191 GNUNET_free (stat_txt);
1192
1193 s->next_receive = GNUNET_TIME_relative_to_absolute (delay);
1194 if (GNUNET_TIME_absolute_get ().abs_value_us < s->next_receive.abs_value_us)
1195 {
1196 LOG (GNUNET_ERROR_TYPE_DEBUG,
1197 "Client: peer `%s' address `%s' next read delayed for %s\n",
1198 GNUNET_i2s (&s->address->peer),
1199 http_common_plugin_address_to_string (s->plugin->protocol,
1200 s->address->address,
1201 s->address->address_length),
1202 GNUNET_STRINGS_relative_time_to_string (delay,
1203 GNUNET_YES));
1204 }
1205 client_reschedule_session_timeout (s);
1206 return GNUNET_OK;
1207}
1208
1209
1210/**
1211 * Callback method used with libcurl when data for a PUT request are
1212 * received. We do not expect data here, so we just discard it.
1213 *
1214 * @param stream pointer where to write data
1215 * @param size size of an individual element
1216 * @param nmemb count of elements that can be written to the buffer
1217 * @param cls destination pointer, passed to the libcurl handle
1218 * @return bytes read from stream
1219 */
1220static size_t
1221client_receive_put (void *stream,
1222 size_t size,
1223 size_t nmemb,
1224 void *cls)
1225{
1226 return size * nmemb;
1227}
1228
1229
1230/**
1231 * Callback method used with libcurl when data for a GET request are
1232 * received. Forward to MST
1233 *
1234 * @param stream pointer where to write data
1235 * @param size size of an individual element
1236 * @param nmemb count of elements that can be written to the buffer
1237 * @param cls destination pointer, passed to the libcurl handle
1238 * @return bytes read from stream
1239 */
1240static size_t
1241client_receive (void *stream,
1242 size_t size,
1243 size_t nmemb,
1244 void *cls)
1245{
1246 struct GNUNET_ATS_Session *s = cls;
1247 struct GNUNET_TIME_Absolute now;
1248 size_t len = size * nmemb;
1249
1250 LOG (GNUNET_ERROR_TYPE_DEBUG,
1251 "Session %p / request %p: Received %lu bytes from peer `%s'\n",
1252 s,
1253 s->get.easyhandle,
1254 (unsigned long) len,
1255 GNUNET_i2s (&s->address->peer));
1256 now = GNUNET_TIME_absolute_get ();
1257 if (now.abs_value_us < s->next_receive.abs_value_us)
1258 {
1259 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1260 struct GNUNET_TIME_Relative delta
1261 = GNUNET_TIME_absolute_get_difference (now, s->next_receive);
1262
1263 LOG (GNUNET_ERROR_TYPE_DEBUG,
1264 "Session %p / request %p: No inbound bandwidth available! Next read was delayed for %s\n",
1265 s,
1266 s->get.easyhandle,
1267 GNUNET_STRINGS_relative_time_to_string (delta,
1268 GNUNET_YES));
1269 if (s->recv_wakeup_task != NULL)
1270 {
1271 GNUNET_SCHEDULER_cancel (s->recv_wakeup_task);
1272 s->recv_wakeup_task = NULL;
1273 }
1274 s->recv_wakeup_task
1275 = GNUNET_SCHEDULER_add_delayed (delta,
1276 &client_wake_up,
1277 s);
1278 return CURL_WRITEFUNC_PAUSE;
1279 }
1280 if (NULL == s->msg_tk)
1281 s->msg_tk = GNUNET_MST_create (&client_receive_mst_cb,
1282 s);
1283 GNUNET_MST_from_buffer (s->msg_tk,
1284 stream,
1285 len,
1286 GNUNET_NO,
1287 GNUNET_NO);
1288 return len;
1289}
1290
1291
1292/**
1293 * Task performing curl operations
1294 *
1295 * @param cls plugin as closure
1296 */
1297static void
1298client_run (void *cls)
1299{
1300 struct HTTP_Client_Plugin *plugin = cls;
1301 int running;
1302 long http_statuscode;
1303 CURLMcode mret;
1304 CURLMsg *msg;
1305 int put_request; /* GNUNET_YES if easy handle is put, GNUNET_NO for get */
1306 int msgs_left;
1307
1308 plugin->client_perform_task = NULL;
1309 /* While data are available or timeouts occurred */
1310 do
1311 {
1312 running = 0;
1313 /* Perform operations for all handles */
1314 mret = curl_multi_perform (plugin->curl_multi_handle, &running);
1315
1316 /* Get additional information for all handles */
1317 while (NULL != (msg = curl_multi_info_read (plugin->curl_multi_handle,
1318 &msgs_left)))
1319 {
1320 CURL *easy_h = msg->easy_handle;
1321 struct GNUNET_ATS_Session *s = NULL;
1322 char *d = NULL; /* curl requires 'd' to be a 'char *' */
1323
1324 GNUNET_assert (NULL != easy_h);
1325
1326 /* Obtain session from easy handle */
1327 GNUNET_assert (CURLE_OK == curl_easy_getinfo (easy_h, CURLINFO_PRIVATE,
1328 &d));
1329 s = (struct GNUNET_ATS_Session *) d;
1330 GNUNET_assert (NULL != s);
1331
1332 if (msg->msg != CURLMSG_DONE)
1333 continue; /* This should not happen */
1334
1335 /* Get HTTP response code */
1336 GNUNET_break (CURLE_OK == curl_easy_getinfo (easy_h,
1337 CURLINFO_RESPONSE_CODE,
1338 &http_statuscode));
1339
1340 if (easy_h == s->put.easyhandle)
1341 put_request = GNUNET_YES;
1342 else
1343 put_request = GNUNET_NO;
1344
1345 /* Log status of terminated request */
1346 if ((0 != msg->data.result) || (http_statuscode != 200))
1347 LOG (GNUNET_ERROR_TYPE_DEBUG,
1348 "Session %p/request %p: %s request to `%s' ended with status %li reason %i: `%s'\n",
1349 s, msg->easy_handle,
1350 (GNUNET_YES == put_request) ? "PUT" : "GET",
1351 GNUNET_i2s (&s->address->peer),
1352 http_statuscode,
1353 msg->data.result,
1354 curl_easy_strerror (msg->data.result));
1355 else
1356 LOG (GNUNET_ERROR_TYPE_DEBUG,
1357 "Session %p/request %p: %s request to `%s' ended normal\n",
1358 s, msg->easy_handle,
1359 (GNUNET_YES == put_request) ? "PUT" : "GET",
1360 GNUNET_i2s (&s->address->peer));
1361
1362 /* Remove easy handle from multi handle */
1363 curl_multi_remove_handle (plugin->curl_multi_handle, easy_h);
1364
1365 /* Clean up easy handle */
1366 curl_easy_cleanup (easy_h);
1367
1368 /* Remove information */
1369 GNUNET_assert (plugin->cur_requests > 0);
1370 plugin->cur_requests--;
1371 LOG (GNUNET_ERROR_TYPE_INFO,
1372 "%s request to %s done, number of requests decreased to %u\n",
1373 (GNUNET_YES == put_request) ? "PUT" : "GET",
1374 s->url,
1375 plugin->cur_requests);
1376
1377 if (GNUNET_YES == put_request)
1378 {
1379 /* Clean up a PUT request */
1380 s->put.easyhandle = NULL;
1381 s->put.s = NULL;
1382
1383 switch (s->put.state)
1384 {
1385 case H_NOT_CONNECTED:
1386 case H_DISCONNECTED:
1387 case H_TMP_DISCONNECTED:
1388 /* This must not happen */
1389 GNUNET_break (0);
1390 break;
1391
1392 case H_TMP_RECONNECT_REQUIRED:
1393 /* Transport called send while disconnect in progress, reconnect */
1394 if (GNUNET_SYSERR == client_connect_put (s))
1395 {
1396 /* Reconnect failed, disconnect session */
1397 http_client_plugin_session_disconnect (plugin, s);
1398 }
1399 break;
1400
1401 case H_TMP_DISCONNECTING:
1402 /* PUT gets temporarily disconnected */
1403 s->put.state = H_TMP_DISCONNECTED;
1404 break;
1405
1406 case H_PAUSED:
1407 case H_CONNECTED:
1408 /* PUT gets permanently disconnected */
1409 s->put.state = H_DISCONNECTED;
1410 http_client_plugin_session_disconnect (plugin, s);
1411 break;
1412
1413 default:
1414 GNUNET_break (0);
1415 break;
1416 }
1417 }
1418 else if (GNUNET_NO == put_request)
1419 {
1420 /* Clean up a GET request */
1421 s->get.easyhandle = NULL;
1422 s->get.s = NULL;
1423
1424 /* If we are emulating an XHR client we need to make another GET
1425 * request.
1426 */
1427 if (GNUNET_YES == plugin->emulate_xhr)
1428 {
1429 if (GNUNET_SYSERR == client_connect_get (s))
1430 http_client_plugin_session_disconnect (plugin, s);
1431 }
1432 else
1433 {
1434 /* GET request was terminated, so disconnect session */
1435 http_client_plugin_session_disconnect (plugin, s);
1436 }
1437 }
1438 else
1439 GNUNET_break (0); /* Must not happen */
1440
1441 GNUNET_STATISTICS_set (plugin->env->stats,
1442 HTTP_STAT_STR_CONNECTIONS,
1443 plugin->cur_requests,
1444 GNUNET_NO);
1445 }
1446 }
1447 while (mret == CURLM_CALL_MULTI_PERFORM);
1448 client_schedule (plugin, GNUNET_NO);
1449}
1450
1451
1452#ifdef TCP_STEALTH
1453/**
1454 * Open TCP socket with TCP STEALTH enabled.
1455 *
1456 * @param clientp our `struct GNUNET_ATS_Session *`
1457 * @param purpose why does curl want to open a socket
1458 * @param address what kind of socket does curl want to have opened?
1459 * @return opened socket
1460 */
1461static curl_socket_t
1462open_tcp_stealth_socket_cb (void *clientp,
1463 curlsocktype purpose,
1464 struct curl_sockaddr *address)
1465{
1466 struct GNUNET_ATS_Session *s = clientp;
1467 int ret;
1468
1469 switch (purpose)
1470 {
1471 case CURLSOCKTYPE_IPCXN:
1472 ret = socket (address->family,
1473 address->socktype,
1474 address->protocol);
1475 if (-1 == ret)
1476 return CURL_SOCKET_BAD;
1477 if (((SOCK_STREAM != address->socktype) ||
1478 ((0 != address->protocol) &&
1479 (IPPROTO_TCP != address->protocol))))
1480 return (curl_socket_t) ret;
1481 if ((0 != setsockopt (ret,
1482 IPPROTO_TCP,
1483 TCP_STEALTH,
1484 &s->address->peer,
1485 sizeof(struct GNUNET_PeerIdentity))))
1486 {
1487 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1488 _ ("TCP_STEALTH not supported on this platform.\n"));
1489 (void) close (ret);
1490 return CURL_SOCKET_BAD;
1491 }
1492 return (curl_socket_t) ret;
1493
1494 case CURLSOCKTYPE_ACCEPT:
1495 GNUNET_break (0);
1496 return CURL_SOCKET_BAD;
1497 break;
1498
1499 case CURLSOCKTYPE_LAST:
1500 GNUNET_break (0);
1501 return CURL_SOCKET_BAD;
1502
1503 default:
1504 GNUNET_break (0);
1505 return CURL_SOCKET_BAD;
1506 }
1507}
1508
1509
1510#endif
1511
1512
1513/**
1514 * Connect GET request for a session
1515 *
1516 * @param s the session to connect
1517 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
1518 */
1519static int
1520client_connect_get (struct GNUNET_ATS_Session *s)
1521{
1522 CURLMcode mret;
1523 struct HttpAddress *ha;
1524 uint32_t options;
1525
1526 ha = (struct HttpAddress *) s->address->address;
1527 options = ntohl (ha->options);
1528 /* create get request */
1529 s->get.easyhandle = curl_easy_init ();
1530 s->get.s = s;
1531 if (0 != (options & HTTP_OPTIONS_TCP_STEALTH))
1532 {
1533#ifdef TCP_STEALTH
1534 curl_easy_setopt (s->get.easyhandle,
1535 CURLOPT_OPENSOCKETFUNCTION,
1536 &open_tcp_stealth_socket_cb);
1537 curl_easy_setopt (s->get.easyhandle,
1538 CURLOPT_OPENSOCKETDATA,
1539 s);
1540#else
1541 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1542 "Cannot connect, TCP STEALTH needed and not supported by kernel.\n");
1543 curl_easy_cleanup (s->get.easyhandle);
1544 s->get.easyhandle = NULL;
1545 s->get.s = NULL;
1546 return GNUNET_SYSERR;
1547#endif
1548 }
1549
1550#if VERBOSE_CURL
1551 curl_easy_setopt (s->get.easyhandle,
1552 CURLOPT_VERBOSE,
1553 1L);
1554 curl_easy_setopt (s->get.easyhandle,
1555 CURLOPT_DEBUGFUNCTION,
1556 &client_log);
1557 curl_easy_setopt (s->get.easyhandle,
1558 CURLOPT_DEBUGDATA,
1559 &s->get);
1560#endif
1561#if BUILD_HTTPS
1562 curl_easy_setopt (s->get.easyhandle, CURLOPT_SSLVERSION,
1563 CURL_SSLVERSION_TLSv1);
1564 {
1565 if (HTTP_OPTIONS_VERIFY_CERTIFICATE ==
1566 (options & HTTP_OPTIONS_VERIFY_CERTIFICATE))
1567 {
1568 curl_easy_setopt (s->get.easyhandle,
1569 CURLOPT_SSL_VERIFYPEER, 1L);
1570 curl_easy_setopt (s->get.easyhandle,
1571 CURLOPT_SSL_VERIFYHOST,
1572 2L);
1573 }
1574 else
1575 {
1576 curl_easy_setopt (s->get.easyhandle,
1577 CURLOPT_SSL_VERIFYPEER,
1578 0L);
1579 curl_easy_setopt (s->get.easyhandle,
1580 CURLOPT_SSL_VERIFYHOST,
1581 0L);
1582 }
1583 }
1584 curl_easy_setopt (s->get.easyhandle,
1585 CURLOPT_PROTOCOLS,
1586 CURLPROTO_HTTPS);
1587 curl_easy_setopt (s->get.easyhandle,
1588 CURLOPT_REDIR_PROTOCOLS,
1589 CURLPROTO_HTTPS);
1590#else
1591 curl_easy_setopt (s->get.easyhandle,
1592 CURLOPT_PROTOCOLS,
1593 CURLPROTO_HTTP);
1594 curl_easy_setopt (s->get.easyhandle,
1595 CURLOPT_REDIR_PROTOCOLS,
1596 CURLPROTO_HTTP);
1597#endif
1598
1599 if (NULL != s->plugin->proxy_hostname)
1600 {
1601 curl_easy_setopt (s->get.easyhandle,
1602 CURLOPT_PROXY,
1603 s->plugin->proxy_hostname);
1604 curl_easy_setopt (s->get.easyhandle,
1605 CURLOPT_PROXYTYPE,
1606 s->plugin->proxytype);
1607 if (NULL != s->plugin->proxy_username)
1608 curl_easy_setopt (s->get.easyhandle,
1609 CURLOPT_PROXYUSERNAME,
1610 s->plugin->proxy_username);
1611 if (NULL != s->plugin->proxy_password)
1612 curl_easy_setopt (s->get.easyhandle,
1613 CURLOPT_PROXYPASSWORD,
1614 s->plugin->proxy_password);
1615 if (GNUNET_YES == s->plugin->proxy_use_httpproxytunnel)
1616 curl_easy_setopt (s->get.easyhandle,
1617 CURLOPT_HTTPPROXYTUNNEL,
1618 s->plugin->proxy_use_httpproxytunnel);
1619 }
1620
1621 if (GNUNET_YES == s->plugin->emulate_xhr)
1622 {
1623 char *url;
1624
1625 GNUNET_asprintf (&url,
1626 "%s,1",
1627 s->url);
1628 curl_easy_setopt (s->get.easyhandle,
1629 CURLOPT_URL,
1630 url);
1631 GNUNET_free (url);
1632 }
1633 else
1634 {
1635 curl_easy_setopt (s->get.easyhandle,
1636 CURLOPT_URL,
1637 s->url);
1638 }
1639 curl_easy_setopt (s->get.easyhandle,
1640 CURLOPT_READFUNCTION,
1641 &client_send_cb);
1642 curl_easy_setopt (s->get.easyhandle,
1643 CURLOPT_READDATA,
1644 s);
1645 curl_easy_setopt (s->get.easyhandle,
1646 CURLOPT_WRITEFUNCTION,
1647 &client_receive);
1648 curl_easy_setopt (s->get.easyhandle,
1649 CURLOPT_WRITEDATA,
1650 s);
1651 /* No timeout by default, timeout done with session timeout */
1652 curl_easy_setopt (s->get.easyhandle,
1653 CURLOPT_TIMEOUT,
1654 0L);
1655 curl_easy_setopt (s->get.easyhandle,
1656 CURLOPT_PRIVATE, s);
1657 curl_easy_setopt (s->get.easyhandle,
1658 CURLOPT_CONNECTTIMEOUT_MS,
1659 (long) (HTTP_CLIENT_NOT_VALIDATED_TIMEOUT.rel_value_us
1660 / 1000LL));
1661 curl_easy_setopt (s->get.easyhandle, CURLOPT_BUFFERSIZE,
1662 2 * GNUNET_MAX_MESSAGE_SIZE);
1663#if CURL_TCP_NODELAY
1664 curl_easy_setopt (ps->recv_endpoint,
1665 CURLOPT_TCP_NODELAY,
1666 1L);
1667#endif
1668 curl_easy_setopt (s->get.easyhandle,
1669 CURLOPT_FOLLOWLOCATION,
1670 0L);
1671
1672 mret = curl_multi_add_handle (s->plugin->curl_multi_handle,
1673 s->get.easyhandle);
1674 if (CURLM_OK != mret)
1675 {
1676 LOG (GNUNET_ERROR_TYPE_ERROR,
1677 "Session %p : Failed to add GET handle to multihandle: `%s'\n",
1678 s,
1679 curl_multi_strerror (mret));
1680 curl_easy_cleanup (s->get.easyhandle);
1681 s->get.easyhandle = NULL;
1682 s->get.s = NULL;
1683 GNUNET_break (0);
1684 return GNUNET_SYSERR;
1685 }
1686 s->plugin->cur_requests++;
1687 LOG (GNUNET_ERROR_TYPE_INFO,
1688 "GET request `%s' established, number of requests increased to %u\n",
1689 s->url,
1690 s->plugin->cur_requests);
1691 return GNUNET_OK;
1692}
1693
1694
1695static int
1696client_connect_put (struct GNUNET_ATS_Session *s)
1697{
1698 CURLMcode mret;
1699 struct HttpAddress *ha;
1700 uint32_t options;
1701
1702 ha = (struct HttpAddress *) s->address->address;
1703 options = ntohl (ha->options);
1704 /* create put request */
1705 LOG (GNUNET_ERROR_TYPE_DEBUG,
1706 "Session %p: Init PUT handle\n",
1707 s);
1708 s->put.easyhandle = curl_easy_init ();
1709 s->put.s = s;
1710#if VERBOSE_CURL
1711 curl_easy_setopt (s->put.easyhandle,
1712 CURLOPT_VERBOSE,
1713 1L);
1714 curl_easy_setopt (s->put.easyhandle,
1715 CURLOPT_DEBUGFUNCTION,
1716 &client_log);
1717 curl_easy_setopt (s->put.easyhandle,
1718 CURLOPT_DEBUGDATA,
1719 &s->put);
1720#endif
1721 if (0 != (options & HTTP_OPTIONS_TCP_STEALTH))
1722 {
1723#ifdef TCP_STEALTH
1724 curl_easy_setopt (s->put.easyhandle,
1725 CURLOPT_OPENSOCKETFUNCTION,
1726 &open_tcp_stealth_socket_cb);
1727 curl_easy_setopt (s->put.easyhandle,
1728 CURLOPT_OPENSOCKETDATA,
1729 s);
1730#else
1731 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1732 "Cannot connect, TCP STEALTH needed and not supported by kernel.\n");
1733 curl_easy_cleanup (s->put.easyhandle);
1734 s->put.easyhandle = NULL;
1735 s->put.s = NULL;
1736 s->put.state = H_DISCONNECTED;
1737 return GNUNET_SYSERR;
1738#endif
1739 }
1740#if BUILD_HTTPS
1741 curl_easy_setopt (s->put.easyhandle,
1742 CURLOPT_SSLVERSION,
1743 CURL_SSLVERSION_TLSv1);
1744 {
1745 struct HttpAddress *ha;
1746 ha = (struct HttpAddress *) s->address->address;
1747
1748 if (HTTP_OPTIONS_VERIFY_CERTIFICATE ==
1749 (ntohl (ha->options) & HTTP_OPTIONS_VERIFY_CERTIFICATE))
1750 {
1751 curl_easy_setopt (s->put.easyhandle,
1752 CURLOPT_SSL_VERIFYPEER,
1753 1L);
1754 curl_easy_setopt (s->put.easyhandle,
1755 CURLOPT_SSL_VERIFYHOST,
1756 2L);
1757 }
1758 else
1759 {
1760 curl_easy_setopt (s->put.easyhandle,
1761 CURLOPT_SSL_VERIFYPEER,
1762 0L);
1763 curl_easy_setopt (s->put.easyhandle,
1764 CURLOPT_SSL_VERIFYHOST,
1765 0L);
1766 }
1767 }
1768 curl_easy_setopt (s->put.easyhandle,
1769 CURLOPT_PROTOCOLS,
1770 CURLPROTO_HTTPS);
1771 curl_easy_setopt (s->put.easyhandle,
1772 CURLOPT_REDIR_PROTOCOLS,
1773 CURLPROTO_HTTPS);
1774#else
1775 curl_easy_setopt (s->put.easyhandle,
1776 CURLOPT_PROTOCOLS,
1777 CURLPROTO_HTTP);
1778 curl_easy_setopt (s->put.easyhandle,
1779 CURLOPT_REDIR_PROTOCOLS,
1780 CURLPROTO_HTTP);
1781#endif
1782 if (NULL != s->plugin->proxy_hostname)
1783 {
1784 curl_easy_setopt (s->put.easyhandle,
1785 CURLOPT_PROXY,
1786 s->plugin->proxy_hostname);
1787 curl_easy_setopt (s->put.easyhandle,
1788 CURLOPT_PROXYTYPE,
1789 s->plugin->proxytype);
1790 if (NULL != s->plugin->proxy_username)
1791 curl_easy_setopt (s->put.easyhandle,
1792 CURLOPT_PROXYUSERNAME,
1793 s->plugin->proxy_username);
1794 if (NULL != s->plugin->proxy_password)
1795 curl_easy_setopt (s->put.easyhandle,
1796 CURLOPT_PROXYPASSWORD,
1797 s->plugin->proxy_password);
1798 if (GNUNET_YES == s->plugin->proxy_use_httpproxytunnel)
1799 curl_easy_setopt (s->put.easyhandle,
1800 CURLOPT_HTTPPROXYTUNNEL,
1801 s->plugin->proxy_use_httpproxytunnel);
1802 }
1803
1804 curl_easy_setopt (s->put.easyhandle,
1805 CURLOPT_URL,
1806 s->url);
1807 curl_easy_setopt (s->put.easyhandle,
1808 CURLOPT_UPLOAD,
1809 1L);
1810 curl_easy_setopt (s->put.easyhandle,
1811 CURLOPT_READFUNCTION,
1812 &client_send_cb);
1813 curl_easy_setopt (s->put.easyhandle,
1814 CURLOPT_READDATA,
1815 s);
1816 curl_easy_setopt (s->put.easyhandle,
1817 CURLOPT_WRITEFUNCTION,
1818 &client_receive_put);
1819 curl_easy_setopt (s->put.easyhandle,
1820 CURLOPT_WRITEDATA,
1821 s);
1822 /* No timeout by default, timeout done with session timeout */
1823 curl_easy_setopt (s->put.easyhandle,
1824 CURLOPT_TIMEOUT,
1825 0L);
1826 curl_easy_setopt (s->put.easyhandle,
1827 CURLOPT_PRIVATE,
1828 s);
1829 curl_easy_setopt (s->put.easyhandle,
1830 CURLOPT_CONNECTTIMEOUT_MS,
1831 (long) (HTTP_CLIENT_NOT_VALIDATED_TIMEOUT.rel_value_us
1832 / 1000LL));
1833 curl_easy_setopt (s->put.easyhandle, CURLOPT_BUFFERSIZE,
1834 2 * GNUNET_MAX_MESSAGE_SIZE);
1835#if CURL_TCP_NODELAY
1836 curl_easy_setopt (s->put.easyhandle, CURLOPT_TCP_NODELAY, 1);
1837#endif
1838 mret = curl_multi_add_handle (s->plugin->curl_multi_handle,
1839 s->put.easyhandle);
1840 if (CURLM_OK != mret)
1841 {
1842 LOG (GNUNET_ERROR_TYPE_ERROR,
1843 "Session %p : Failed to add PUT handle to multihandle: `%s'\n",
1844 s, curl_multi_strerror (mret));
1845 curl_easy_cleanup (s->put.easyhandle);
1846 s->put.easyhandle = NULL;
1847 s->put.s = NULL;
1848 s->put.state = H_DISCONNECTED;
1849 return GNUNET_SYSERR;
1850 }
1851 s->put.state = H_CONNECTED;
1852 s->plugin->cur_requests++;
1853
1854 LOG (GNUNET_ERROR_TYPE_INFO,
1855 "PUT request `%s' established, number of requests increased to %u\n",
1856 s->url, s->plugin->cur_requests);
1857
1858 return GNUNET_OK;
1859}
1860
1861
1862/**
1863 * Connect both PUT and GET request for a session
1864 *
1865 * @param s the session to connect
1866 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
1867 */
1868static int
1869client_connect (struct GNUNET_ATS_Session *s)
1870{
1871 struct HTTP_Client_Plugin *plugin = s->plugin;
1872 int res = GNUNET_OK;
1873
1874 /* create url */
1875 if (NULL ==
1876 http_common_plugin_address_to_string (plugin->protocol,
1877 s->address->address,
1878 s->address->address_length))
1879 {
1880 LOG (GNUNET_ERROR_TYPE_DEBUG,
1881 "Invalid address peer `%s'\n",
1882 GNUNET_i2s (&s->address->peer));
1883 return GNUNET_SYSERR;
1884 }
1885
1886 GNUNET_asprintf (&s->url,
1887 "%s/%s;%u",
1888 http_common_plugin_address_to_url (NULL,
1889 s->address->address,
1890 s->address->address_length),
1891 GNUNET_i2s_full (plugin->env->my_identity),
1892 plugin->last_tag);
1893
1894 plugin->last_tag++;
1895 LOG (GNUNET_ERROR_TYPE_DEBUG,
1896 "Initiating outbound session peer `%s' using address `%s'\n",
1897 GNUNET_i2s (&s->address->peer), s->url);
1898
1899 if (GNUNET_SYSERR == client_connect_get (s))
1900 return GNUNET_SYSERR;
1901 /* If we are emulating an XHR client then delay sending a PUT request until
1902 * there is something to send.
1903 */
1904 if (GNUNET_YES == plugin->emulate_xhr)
1905 {
1906 s->put.state = H_TMP_DISCONNECTED;
1907 }
1908 else if (GNUNET_SYSERR == client_connect_put (s))
1909 return GNUNET_SYSERR;
1910
1911 LOG (GNUNET_ERROR_TYPE_DEBUG,
1912 "Session %p: connected with GET %p and PUT %p\n",
1913 s, s->get.easyhandle,
1914 s->put.easyhandle);
1915 /* Perform connect */
1916 GNUNET_STATISTICS_set (plugin->env->stats,
1917 HTTP_STAT_STR_CONNECTIONS,
1918 plugin->cur_requests,
1919 GNUNET_NO);
1920 /* Re-schedule since handles have changed */
1921 if (NULL != plugin->client_perform_task)
1922 {
1923 GNUNET_SCHEDULER_cancel (plugin->client_perform_task);
1924 plugin->client_perform_task = NULL;
1925 }
1926
1927 /* Schedule task to run immediately */
1928 plugin->client_perform_task = GNUNET_SCHEDULER_add_now (client_run,
1929 plugin);
1930 return res;
1931}
1932
1933
1934/**
1935 * Function obtain the network type for a session
1936 *
1937 * @param cls closure (`struct Plugin*`)
1938 * @param session the session
1939 * @return the network type
1940 */
1941static enum GNUNET_NetworkType
1942http_client_plugin_get_network (void *cls,
1943 struct GNUNET_ATS_Session *session)
1944{
1945 return session->scope;
1946}
1947
1948
1949/**
1950 * Function obtain the network type for an address.
1951 *
1952 * @param cls closure (`struct Plugin *`)
1953 * @param address the address
1954 * @return the network type
1955 */
1956static enum GNUNET_NetworkType
1957http_client_plugin_get_network_for_address (void *cls,
1958 const struct
1959 GNUNET_HELLO_Address *address)
1960{
1961 struct HTTP_Client_Plugin *plugin = cls;
1962
1963 return http_common_get_network_for_address (plugin->env,
1964 address);
1965}
1966
1967
1968/**
1969 * Session was idle, so disconnect it
1970 *
1971 * @param cls the `struct GNUNET_ATS_Session` of the idle session
1972 */
1973static void
1974client_session_timeout (void *cls)
1975{
1976 struct GNUNET_ATS_Session *s = cls;
1977 struct GNUNET_TIME_Relative left;
1978
1979 s->timeout_task = NULL;
1980 left = GNUNET_TIME_absolute_get_remaining (s->timeout);
1981 if (0 != left.rel_value_us)
1982 {
1983 /* not actually our turn yet, but let's at least update
1984 the monitor, it may think we're about to die ... */
1985 notify_session_monitor (s->plugin,
1986 s,
1987 GNUNET_TRANSPORT_SS_UPDATE);
1988 s->timeout_task = GNUNET_SCHEDULER_add_delayed (left,
1989 &client_session_timeout,
1990 s);
1991 return;
1992 }
1993 LOG (TIMEOUT_LOG,
1994 "Session %p was idle for %s, disconnecting\n",
1995 s,
1996 GNUNET_STRINGS_relative_time_to_string (HTTP_CLIENT_SESSION_TIMEOUT,
1997 GNUNET_YES));
1998 GNUNET_assert (GNUNET_OK ==
1999 http_client_plugin_session_disconnect (s->plugin,
2000 s));
2001}
2002
2003
2004/**
2005 * Creates a new outbound session the transport service will use to
2006 * send data to the peer
2007 *
2008 * @param cls the plugin
2009 * @param address the address
2010 * @return the session or NULL of max connections exceeded
2011 */
2012static struct GNUNET_ATS_Session *
2013http_client_plugin_get_session (void *cls,
2014 const struct GNUNET_HELLO_Address *address)
2015{
2016 struct HTTP_Client_Plugin *plugin = cls;
2017 struct GNUNET_ATS_Session *s;
2018 struct sockaddr *sa;
2019 enum GNUNET_NetworkType net_type;
2020 size_t salen = 0;
2021 int res;
2022
2023 GNUNET_assert (NULL != address->address);
2024
2025 /* find existing session */
2026 s = client_lookup_session (plugin, address);
2027 if (NULL != s)
2028 return s;
2029
2030 /* create a new session */
2031 if (plugin->max_requests <= plugin->cur_requests)
2032 {
2033 LOG (GNUNET_ERROR_TYPE_WARNING,
2034 "Maximum number of requests (%u) reached: "
2035 "cannot connect to peer `%s'\n",
2036 plugin->max_requests,
2037 GNUNET_i2s (&address->peer));
2038 return NULL;
2039 }
2040
2041 /* Determine network location */
2042 net_type = GNUNET_NT_UNSPECIFIED;
2043 sa = http_common_socket_from_address (address->address,
2044 address->address_length,
2045 &res);
2046 if (GNUNET_SYSERR == res)
2047 return NULL;
2048 if (GNUNET_YES == res)
2049 {
2050 GNUNET_assert (NULL != sa);
2051 if (AF_INET == sa->sa_family)
2052 {
2053 salen = sizeof(struct sockaddr_in);
2054 }
2055 else if (AF_INET6 == sa->sa_family)
2056 {
2057 salen = sizeof(struct sockaddr_in6);
2058 }
2059 net_type = plugin->env->get_address_type (plugin->env->cls, sa, salen);
2060 GNUNET_free (sa);
2061 }
2062 else if (GNUNET_NO == res)
2063 {
2064 /* Cannot convert to sockaddr -> is external hostname */
2065 net_type = GNUNET_NT_WAN;
2066 }
2067 if (GNUNET_NT_UNSPECIFIED == net_type)
2068 {
2069 GNUNET_break (0);
2070 return NULL;
2071 }
2072
2073 s = GNUNET_new (struct GNUNET_ATS_Session);
2074 s->plugin = plugin;
2075 s->address = GNUNET_HELLO_address_copy (address);
2076 s->scope = net_type;
2077
2078 s->put.state = H_NOT_CONNECTED;
2079 s->timeout = GNUNET_TIME_relative_to_absolute (HTTP_CLIENT_SESSION_TIMEOUT);
2080 s->timeout_task = GNUNET_SCHEDULER_add_delayed (HTTP_CLIENT_SESSION_TIMEOUT,
2081 &client_session_timeout,
2082 s);
2083 LOG (GNUNET_ERROR_TYPE_DEBUG,
2084 "Created new session %p for `%s' address `%s''\n",
2085 s,
2086 http_common_plugin_address_to_string (plugin->protocol,
2087 s->address->address,
2088 s->address->address_length),
2089 GNUNET_i2s (&s->address->peer));
2090
2091 /* add new session */
2092 (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessions,
2093 &s->address->peer,
2094 s,
2095 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2096 /* initiate new connection */
2097 if (GNUNET_SYSERR == client_connect (s))
2098 {
2099 LOG (GNUNET_ERROR_TYPE_ERROR,
2100 "Cannot connect to peer `%s' address `%s''\n",
2101 http_common_plugin_address_to_string (plugin->protocol,
2102 s->address->address,
2103 s->address->address_length),
2104 GNUNET_i2s (&s->address->peer));
2105 client_delete_session (s);
2106 return NULL;
2107 }
2108 notify_session_monitor (plugin,
2109 s,
2110 GNUNET_TRANSPORT_SS_INIT);
2111 notify_session_monitor (plugin,
2112 s,
2113 GNUNET_TRANSPORT_SS_UP); /* or handshake? */
2114 return s;
2115}
2116
2117
2118/**
2119 * Setup http_client plugin
2120 *
2121 * @param plugin the plugin handle
2122 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
2123 */
2124static int
2125client_start (struct HTTP_Client_Plugin *plugin)
2126{
2127 curl_global_init (CURL_GLOBAL_ALL);
2128 plugin->curl_multi_handle = curl_multi_init ();
2129
2130 if (NULL == plugin->curl_multi_handle)
2131 {
2132 LOG (GNUNET_ERROR_TYPE_ERROR,
2133 _ (
2134 "Could not initialize curl multi handle, failed to start %s plugin!\n"),
2135 plugin->name);
2136 return GNUNET_SYSERR;
2137 }
2138 return GNUNET_OK;
2139}
2140
2141
2142/**
2143 * Another peer has suggested an address for this
2144 * peer and transport plugin. Check that this could be a valid
2145 * address. If so, consider adding it to the list
2146 * of addresses.
2147 *
2148 * @param cls closure with the `struct Plugin`
2149 * @param addr pointer to the address
2150 * @param addrlen length of @a addr
2151 * @return #GNUNET_OK if this is a plausible address for this peer
2152 * and transport; always returns #GNUNET_NO (this is the client!)
2153 */
2154static int
2155http_client_plugin_address_suggested (void *cls,
2156 const void *addr,
2157 size_t addrlen)
2158{
2159 /* A HTTP/S client does not have any valid address so:*/
2160 return GNUNET_NO;
2161}
2162
2163
2164/**
2165 * Exit point from the plugin.
2166 *
2167 * @param cls api as closure
2168 * @return NULL
2169 */
2170void *
2171LIBGNUNET_PLUGIN_TRANSPORT_DONE (void *cls)
2172{
2173 struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
2174 struct HTTP_Client_Plugin *plugin = api->cls;
2175
2176 if (NULL == api->cls)
2177 {
2178 /* Stub shutdown */
2179 GNUNET_free (api);
2180 return NULL;
2181 }
2182 LOG (GNUNET_ERROR_TYPE_DEBUG,
2183 _ ("Shutting down plugin `%s'\n"),
2184 plugin->name);
2185 GNUNET_CONTAINER_multipeermap_iterate (plugin->sessions,
2186 &destroy_session_cb,
2187 plugin);
2188 if (NULL != plugin->client_perform_task)
2189 {
2190 GNUNET_SCHEDULER_cancel (plugin->client_perform_task);
2191 plugin->client_perform_task = NULL;
2192 }
2193 if (NULL != plugin->curl_multi_handle)
2194 {
2195 curl_multi_cleanup (plugin->curl_multi_handle);
2196 plugin->curl_multi_handle = NULL;
2197 }
2198 curl_global_cleanup ();
2199 LOG (GNUNET_ERROR_TYPE_DEBUG,
2200 _ ("Shutdown for plugin `%s' complete\n"),
2201 plugin->name);
2202 GNUNET_CONTAINER_multipeermap_destroy (plugin->sessions);
2203 GNUNET_free (plugin->proxy_hostname);
2204 GNUNET_free (plugin->proxy_username);
2205 GNUNET_free (plugin->proxy_password);
2206 GNUNET_free (plugin);
2207 GNUNET_free (api);
2208 return NULL;
2209}
2210
2211
2212/**
2213 * Configure plugin
2214 *
2215 * @param plugin the plugin handle
2216 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
2217 */
2218static int
2219client_configure_plugin (struct HTTP_Client_Plugin *plugin)
2220{
2221 unsigned long long max_requests;
2222 char *proxy_type;
2223
2224 /* Optional parameters */
2225 if (GNUNET_OK !=
2226 GNUNET_CONFIGURATION_get_value_number (plugin->env->cfg,
2227 plugin->name,
2228 "MAX_CONNECTIONS",
2229 &max_requests))
2230 max_requests = 128;
2231 plugin->max_requests = max_requests;
2232
2233 LOG (GNUNET_ERROR_TYPE_DEBUG,
2234 _ ("Maximum number of requests is %u\n"),
2235 plugin->max_requests);
2236
2237 /* Read proxy configuration */
2238 if (GNUNET_OK ==
2239 GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg,
2240 plugin->name,
2241 "PROXY",
2242 &plugin->proxy_hostname))
2243 {
2244 LOG (GNUNET_ERROR_TYPE_DEBUG,
2245 "Found proxy host: `%s'\n",
2246 plugin->proxy_hostname);
2247 /* proxy username */
2248 if (GNUNET_OK ==
2249 GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg,
2250 plugin->name,
2251 "PROXY_USERNAME",
2252 &plugin->proxy_username))
2253 {
2254 LOG (GNUNET_ERROR_TYPE_DEBUG,
2255 "Found proxy username name: `%s'\n",
2256 plugin->proxy_username);
2257 }
2258
2259 /* proxy password */
2260 if (GNUNET_OK ==
2261 GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg,
2262 plugin->name,
2263 "PROXY_PASSWORD",
2264 &plugin->proxy_password))
2265 {
2266 LOG (GNUNET_ERROR_TYPE_DEBUG,
2267 "Found proxy password name: `%s'\n",
2268 plugin->proxy_password);
2269 }
2270
2271 /* proxy type */
2272 if (GNUNET_OK ==
2273 GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg,
2274 plugin->name,
2275 "PROXY_TYPE",
2276 &proxy_type))
2277 {
2278 GNUNET_STRINGS_utf8_toupper (proxy_type, proxy_type);
2279
2280 if (0 == strcmp (proxy_type, "HTTP"))
2281 plugin->proxytype = CURLPROXY_HTTP;
2282 else if (0 == strcmp (proxy_type, "SOCKS4"))
2283 plugin->proxytype = CURLPROXY_SOCKS4;
2284 else if (0 == strcmp (proxy_type, "SOCKS5"))
2285 plugin->proxytype = CURLPROXY_SOCKS5;
2286 else if (0 == strcmp (proxy_type, "SOCKS4A"))
2287 plugin->proxytype = CURLPROXY_SOCKS4A;
2288 else if (0 == strcmp (proxy_type, "SOCKS5_HOSTNAME "))
2289 plugin->proxytype = CURLPROXY_SOCKS5_HOSTNAME;
2290 else
2291 {
2292 LOG (GNUNET_ERROR_TYPE_ERROR,
2293 _ (
2294 "Invalid proxy type: `%s', disabling proxy! Check configuration!\n"),
2295 proxy_type);
2296
2297 GNUNET_free (proxy_type);
2298 GNUNET_free (plugin->proxy_hostname);
2299 plugin->proxy_hostname = NULL;
2300 GNUNET_free (plugin->proxy_username);
2301 plugin->proxy_username = NULL;
2302 GNUNET_free (plugin->proxy_password);
2303 plugin->proxy_password = NULL;
2304
2305 return GNUNET_SYSERR;
2306 }
2307
2308 LOG (GNUNET_ERROR_TYPE_DEBUG,
2309 "Found proxy type: `%s'\n",
2310 proxy_type);
2311 }
2312
2313 /* proxy http tunneling */
2314 plugin->proxy_use_httpproxytunnel
2315 = GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg,
2316 plugin->name,
2317 "PROXY_HTTP_TUNNELING");
2318 if (GNUNET_SYSERR == plugin->proxy_use_httpproxytunnel)
2319 plugin->proxy_use_httpproxytunnel = GNUNET_NO;
2320
2321 GNUNET_free (proxy_type);
2322 }
2323
2324 /* Should we emulate an XHR client for testing? */
2325 plugin->emulate_xhr
2326 = GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg,
2327 plugin->name,
2328 "EMULATE_XHR");
2329 return GNUNET_OK;
2330}
2331
2332
2333/**
2334 * Function to convert an address to a human-readable string.
2335 *
2336 * @param cls closure
2337 * @param addr address to convert
2338 * @param addrlen address length
2339 * @return res string if conversion was successful, NULL otherwise
2340 */
2341static const char *
2342http_client_plugin_address_to_string (void *cls,
2343 const void *addr,
2344 size_t addrlen)
2345{
2346 return http_common_plugin_address_to_string (PLUGIN_NAME,
2347 addr,
2348 addrlen);
2349}
2350
2351
2352/**
2353 * Function that will be called whenever the transport service wants to
2354 * notify the plugin that a session is still active and in use and
2355 * therefore the session timeout for this session has to be updated
2356 *
2357 * @param cls closure
2358 * @param peer which peer was the session for
2359 * @param session which session is being updated
2360 */
2361static void
2362http_client_plugin_update_session_timeout (void *cls,
2363 const struct
2364 GNUNET_PeerIdentity *peer,
2365 struct GNUNET_ATS_Session *session)
2366{
2367 client_reschedule_session_timeout (session);
2368}
2369
2370
2371/**
2372 * Function that will be called whenever the transport service wants to
2373 * notify the plugin that the inbound quota changed and that the plugin
2374 * should update it's delay for the next receive value
2375 *
2376 * @param cls closure
2377 * @param peer which peer was the session for
2378 * @param s which session is being updated
2379 * @param delay new delay to use for receiving
2380 */
2381static void
2382http_client_plugin_update_inbound_delay (void *cls,
2383 const struct GNUNET_PeerIdentity *peer,
2384 struct GNUNET_ATS_Session *s,
2385 struct GNUNET_TIME_Relative delay)
2386{
2387 s->next_receive = GNUNET_TIME_relative_to_absolute (delay);
2388 LOG (GNUNET_ERROR_TYPE_DEBUG,
2389 "New inbound delay %s\n",
2390 GNUNET_STRINGS_relative_time_to_string (delay,
2391 GNUNET_NO));
2392 if (s->recv_wakeup_task != NULL)
2393 {
2394 GNUNET_SCHEDULER_cancel (s->recv_wakeup_task);
2395 s->recv_wakeup_task
2396 = GNUNET_SCHEDULER_add_delayed (delay,
2397 &client_wake_up,
2398 s);
2399 }
2400}
2401
2402
2403/**
2404 * Return information about the given session to the
2405 * monitor callback.
2406 *
2407 * @param cls the `struct Plugin` with the monitor callback (`sic`)
2408 * @param peer peer we send information about
2409 * @param value our `struct GNUNET_ATS_Session` to send information about
2410 * @return #GNUNET_OK (continue to iterate)
2411 */
2412static int
2413send_session_info_iter (void *cls,
2414 const struct GNUNET_PeerIdentity *peer,
2415 void *value)
2416{
2417 struct HTTP_Client_Plugin *plugin = cls;
2418 struct GNUNET_ATS_Session *session = value;
2419
2420 notify_session_monitor (plugin,
2421 session,
2422 GNUNET_TRANSPORT_SS_INIT);
2423 notify_session_monitor (plugin,
2424 session,
2425 GNUNET_TRANSPORT_SS_UP); /* FIXME: or handshake? */
2426 return GNUNET_OK;
2427}
2428
2429
2430/**
2431 * Begin monitoring sessions of a plugin. There can only
2432 * be one active monitor per plugin (i.e. if there are
2433 * multiple monitors, the transport service needs to
2434 * multiplex the generated events over all of them).
2435 *
2436 * @param cls closure of the plugin
2437 * @param sic callback to invoke, NULL to disable monitor;
2438 * plugin will being by iterating over all active
2439 * sessions immediately and then enter monitor mode
2440 * @param sic_cls closure for @a sic
2441 */
2442static void
2443http_client_plugin_setup_monitor (void *cls,
2444 GNUNET_TRANSPORT_SessionInfoCallback sic,
2445 void *sic_cls)
2446{
2447 struct HTTP_Client_Plugin *plugin = cls;
2448
2449 plugin->sic = sic;
2450 plugin->sic_cls = sic_cls;
2451 if (NULL != sic)
2452 {
2453 GNUNET_CONTAINER_multipeermap_iterate (plugin->sessions,
2454 &send_session_info_iter,
2455 plugin);
2456 /* signal end of first iteration */
2457 sic (sic_cls, NULL, NULL);
2458 }
2459}
2460
2461
2462/**
2463 * Entry point for the plugin.
2464 */
2465void *
2466LIBGNUNET_PLUGIN_TRANSPORT_INIT (void *cls)
2467{
2468 struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
2469 struct GNUNET_TRANSPORT_PluginFunctions *api;
2470 struct HTTP_Client_Plugin *plugin;
2471
2472 if (NULL == env->receive)
2473 {
2474 /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully
2475 initialize the plugin or the API */
2476 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
2477 api->cls = NULL;
2478 api->address_to_string = &http_client_plugin_address_to_string;
2479 api->string_to_address = &http_common_plugin_string_to_address;
2480 api->address_pretty_printer = &http_common_plugin_address_pretty_printer;
2481 return api;
2482 }
2483
2484 plugin = GNUNET_new (struct HTTP_Client_Plugin);
2485 plugin->env = env;
2486 plugin->sessions = GNUNET_CONTAINER_multipeermap_create (128,
2487 GNUNET_YES);
2488 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
2489 api->cls = plugin;
2490 api->send = &http_client_plugin_send;
2491 api->disconnect_session = &http_client_plugin_session_disconnect;
2492 api->query_keepalive_factor = &http_client_query_keepalive_factor;
2493 api->disconnect_peer = &http_client_plugin_peer_disconnect;
2494 api->check_address = &http_client_plugin_address_suggested;
2495 api->get_session = &http_client_plugin_get_session;
2496 api->address_to_string = &http_client_plugin_address_to_string;
2497 api->string_to_address = &http_common_plugin_string_to_address;
2498 api->address_pretty_printer = &http_common_plugin_address_pretty_printer;
2499 api->get_network = &http_client_plugin_get_network;
2500 api->get_network_for_address = &http_client_plugin_get_network_for_address;
2501 api->update_session_timeout = &http_client_plugin_update_session_timeout;
2502 api->update_inbound_delay = &http_client_plugin_update_inbound_delay;
2503 api->setup_monitor = &http_client_plugin_setup_monitor;
2504#if BUILD_HTTPS
2505 plugin->name = "transport-https_client";
2506 plugin->protocol = "https";
2507#else
2508 plugin->name = "transport-http_client";
2509 plugin->protocol = "http";
2510#endif
2511 plugin->last_tag = 1;
2512
2513 if (GNUNET_SYSERR == client_configure_plugin (plugin))
2514 {
2515 LIBGNUNET_PLUGIN_TRANSPORT_DONE (api);
2516 return NULL;
2517 }
2518
2519 /* Start client */
2520 if (GNUNET_SYSERR == client_start (plugin))
2521 {
2522 LIBGNUNET_PLUGIN_TRANSPORT_DONE (api);
2523 return NULL;
2524 }
2525 return api;
2526}
2527
2528
2529/* 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 75bf8b74a..000000000
--- a/src/transport/plugin_transport_http_common.c
+++ /dev/null
@@ -1,948 +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
410/**
411 * Convert the transports address to a nice, human-readable
412 * format.
413 *
414 * @param cls closure
415 * @param type name of the transport that generated the address
416 * @param addr one of the addresses of the host, NULL for the last address
417 * the specific address format depends on the transport
418 * @param addrlen length of the @a addr
419 * @param numeric should (IP) addresses be displayed in numeric form?
420 * @param timeout after how long should we give up?
421 * @param asc function to call on each string
422 * @param asc_cls closure for @a asc
423 */
424void
425http_common_plugin_address_pretty_printer (void *cls, const char *type,
426 const void *addr,
427 size_t addrlen,
428 int numeric,
429 struct GNUNET_TIME_Relative timeout,
430 GNUNET_TRANSPORT_AddressStringCallback
431 asc,
432 void *asc_cls)
433{
434 const struct HttpAddress *address = addr;
435 struct SplittedHTTPAddress *saddr;
436 struct sockaddr *sock_addr;
437 const char *ret;
438 char *addr_str;
439 int res;
440 int have_ip;
441
442 saddr = NULL;
443 sock_addr = NULL;
444 if ((addrlen < sizeof(struct HttpAddress)) ||
445 (addrlen != http_common_address_get_size (address)))
446 {
447 GNUNET_break (0);
448 goto handle_error;
449 }
450
451 addr_str = (char *) &address[1];
452 if (addr_str[ntohl (address->urlen) - 1] != '\0')
453 {
454 GNUNET_break (0);
455 goto handle_error;
456 }
457
458 saddr = http_split_address (addr_str);
459 if (NULL == saddr)
460 {
461 GNUNET_break (0);
462 goto handle_error;
463 }
464
465 sock_addr = http_common_socket_from_address (addr, addrlen, &res);
466 if (GNUNET_SYSERR == res)
467 {
468 /* Malformed address */
469 GNUNET_break (0);
470 goto handle_error;
471 }
472 else if (GNUNET_NO == res)
473 {
474 /* Could not convert to IP */
475 have_ip = GNUNET_NO;
476 }
477 else if (GNUNET_YES == res)
478 {
479 /* Converted to IP */
480 have_ip = GNUNET_YES;
481 }
482 else
483 {
484 /* Must not happen */
485 GNUNET_break (0);
486 goto handle_error;
487 }
488
489 if ((GNUNET_YES == numeric) &&
490 (GNUNET_YES == have_ip))
491 {
492 /* No lookup required */
493 ret = http_common_plugin_address_to_string (type, address, addrlen);
494 asc (asc_cls, ret, (NULL == ret) ? GNUNET_SYSERR : GNUNET_OK);
495 asc (asc_cls, NULL, GNUNET_OK);
496 http_clean_splitted (saddr);
497 GNUNET_free (sock_addr);
498 return;
499 }
500 if ((GNUNET_YES == numeric) &&
501 (GNUNET_NO == have_ip))
502 {
503 /* Forward lookup */
504 if (GNUNET_SYSERR ==
505 http_common_dns_ip_lookup (saddr->host, type, saddr,
506 address->options, timeout,
507 asc, asc_cls))
508 {
509 GNUNET_break (0);
510 goto handle_error;
511 }
512 /* Wait for resolver callback */
513 GNUNET_free (sock_addr);
514 return;
515 }
516 if ((GNUNET_NO == numeric) &&
517 (GNUNET_YES == have_ip))
518 {
519 /* Reverse lookup */
520 if (GNUNET_SYSERR ==
521 http_common_dns_reverse_lookup (sock_addr,
522 (AF_INET == sock_addr->sa_family)
523 ? sizeof(struct sockaddr_in)
524 : sizeof(struct sockaddr_in6),
525 type,
526 saddr,
527 address->options, timeout,
528 asc, asc_cls))
529 {
530 GNUNET_break (0);
531 goto handle_error;
532 }
533 /* Wait for resolver callback */
534 GNUNET_free (sock_addr);
535 return;
536 }
537 if ((GNUNET_NO == numeric) &&
538 (GNUNET_NO == have_ip))
539 {
540 /* No lookup required */
541 ret = http_common_plugin_address_to_string (type, address, addrlen);
542 asc (asc_cls, ret, (NULL == ret) ? GNUNET_SYSERR : GNUNET_OK);
543 asc (asc_cls, NULL, GNUNET_OK);
544 GNUNET_free (sock_addr);
545 http_clean_splitted (saddr);
546 return;
547 }
548 /* Error (argument supplied not GNUNET_YES or GNUNET_NO) */
549 GNUNET_break (0);
550 goto handle_error;
551
552handle_error:
553 /* Report error */
554 asc (asc_cls, NULL, GNUNET_SYSERR);
555 asc (asc_cls, NULL, GNUNET_OK);
556 GNUNET_free (sock_addr);
557 if (NULL != saddr)
558 http_clean_splitted (saddr);
559}
560
561
562/**
563 * FIXME.
564 */
565const char *
566http_common_plugin_address_to_url (void *cls,
567 const void *addr,
568 size_t addrlen)
569{
570 static char rbuf[1024];
571 const struct HttpAddress *address = addr;
572 const char *addr_str;
573
574 if (NULL == addr)
575 {
576 GNUNET_break (0);
577 return NULL;
578 }
579 if (0 == addrlen)
580 {
581 GNUNET_break (0);
582 return NULL;
583 }
584 if (addrlen != http_common_address_get_size (address))
585 {
586 GNUNET_break (0);
587 return NULL;
588 }
589 addr_str = (char *) &address[1];
590 if (addr_str[ntohl (address->urlen) - 1] != '\0')
591 return NULL;
592
593 GNUNET_memcpy (rbuf,
594 &address[1],
595 ntohl (address->urlen));
596 return rbuf;
597}
598
599
600/**
601 * Function called for a quick conversion of the binary address to
602 * a numeric address. Note that the caller must not free the
603 * address and that the next call to this function is allowed
604 * to override the address again.
605 *
606 * @param plugin the name of the plugin
607 * @param addr binary address
608 * @param addrlen length of the address
609 * @return string representing the same address
610 */
611const char *
612http_common_plugin_address_to_string (const char *plugin,
613 const void *addr,
614 size_t addrlen)
615{
616 static char rbuf[1024];
617 const struct HttpAddress *address = addr;
618 const char *addr_str;
619 char *res;
620
621 GNUNET_assert (NULL != plugin);
622 if (NULL == addr)
623 return NULL;
624 if (0 == addrlen)
625 return NULL;
626 if (addrlen != http_common_address_get_size (address))
627 return NULL;
628 addr_str = (char *) &address[1];
629 if (addr_str[ntohl (address->urlen) - 1] != '\0')
630 return NULL;
631 GNUNET_asprintf (&res, "%s.%u.%s", plugin, ntohl (address->options),
632 (char*)&address[1]);
633 if (strlen (res) + 1 < 500)
634 {
635 GNUNET_memcpy (rbuf, res, strlen (res) + 1);
636 GNUNET_free (res);
637 return rbuf;
638 }
639 GNUNET_break (0);
640 GNUNET_free (res);
641 return NULL;
642}
643
644
645/**
646 * Function called to convert a string address to
647 * a binary address.
648 *
649 * @param cls closure ('struct Plugin*')
650 * @param addr string address
651 * @param addrlen length of the @a addr
652 * @param buf location to store the buffer
653 * If the function returns #GNUNET_SYSERR, its contents are undefined.
654 * @param added length of created address
655 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
656 */
657int
658http_common_plugin_string_to_address (void *cls,
659 const char *addr,
660 uint16_t addrlen,
661 void **buf,
662 size_t *added)
663{
664 struct HttpAddress *a;
665 char *address;
666 char *plugin;
667 char *optionstr;
668 size_t urlen;
669 uint32_t options;
670
671 /* Format protocol.options.address:port */
672 address = NULL;
673 plugin = NULL;
674 optionstr = NULL;
675 if ((NULL == addr) || (addrlen == 0))
676 {
677 GNUNET_break (0);
678 return GNUNET_SYSERR;
679 }
680 if ('\0' != addr[addrlen - 1])
681 {
682 GNUNET_break (0);
683 return GNUNET_SYSERR;
684 }
685 if (strlen (addr) != addrlen - 1)
686 {
687 GNUNET_break (0);
688 return GNUNET_SYSERR;
689 }
690 plugin = GNUNET_strdup (addr);
691 optionstr = strchr (plugin, '.');
692 if (NULL == optionstr)
693 {
694 GNUNET_break (0);
695 GNUNET_free (plugin);
696 return GNUNET_SYSERR;
697 }
698 optionstr[0] = '\0';
699 optionstr++;
700 options = atol (optionstr); /* 0 on conversion error, that's ok */
701 address = strchr (optionstr, '.');
702 if (NULL == address)
703 {
704 GNUNET_break (0);
705 GNUNET_free (plugin);
706 return GNUNET_SYSERR;
707 }
708 address[0] = '\0';
709 address++;
710 urlen = strlen (address) + 1;
711
712 a = GNUNET_malloc (sizeof(struct HttpAddress) + urlen);
713 a->options = htonl (options);
714 a->urlen = htonl (urlen);
715 GNUNET_memcpy (&a[1], address, urlen);
716
717 (*buf) = a;
718 (*added) = sizeof(struct HttpAddress) + urlen;
719 GNUNET_free (plugin);
720 return GNUNET_OK;
721}
722
723
724/**
725 * Create a HTTP address from a socketaddr
726 *
727 * @param protocol protocol
728 * @param addr sockaddr * address
729 * @param addrlen length of the address
730 * @return the HttpAddress
731 */
732struct HttpAddress *
733http_common_address_from_socket (const char *protocol,
734 const struct sockaddr *addr,
735 socklen_t addrlen)
736{
737 struct HttpAddress *address = NULL;
738 char *res;
739 size_t len;
740
741 GNUNET_asprintf (&res,
742 "%s://%s",
743 protocol,
744 GNUNET_a2s (addr,
745 addrlen));
746 len = strlen (res) + 1;
747 address = GNUNET_malloc (sizeof(struct HttpAddress) + len);
748 address->options = htonl (HTTP_OPTIONS_NONE);
749 address->urlen = htonl (len);
750 GNUNET_memcpy (&address[1], res, len);
751 GNUNET_free (res);
752 return address;
753}
754
755
756/**
757 * Create a socketaddr from a HTTP address
758 *
759 * @param addr a `sockaddr *` address
760 * @param addrlen length of the @a addr
761 * @param res the result:
762 * #GNUNET_SYSERR, invalid input,
763 * #GNUNET_YES: could convert to ip,
764 * #GNUNET_NO: valid input but could not convert to ip (hostname?)
765 * @return the string
766 */
767struct sockaddr *
768http_common_socket_from_address (const void *addr,
769 size_t addrlen,
770 int *res)
771{
772 const struct HttpAddress *ha;
773 struct SplittedHTTPAddress *spa;
774 struct sockaddr_storage *s;
775 char *to_conv;
776 size_t urlen;
777
778 (*res) = GNUNET_SYSERR;
779 ha = (const struct HttpAddress *) addr;
780 if (NULL == addr)
781 {
782 GNUNET_break (0);
783 return NULL;
784 }
785 if (0 == addrlen)
786 {
787 GNUNET_break (0);
788 return NULL;
789 }
790 if (addrlen < sizeof(struct HttpAddress))
791 {
792 GNUNET_break (0);
793 return NULL;
794 }
795 urlen = ntohl (ha->urlen);
796 if (sizeof(struct HttpAddress) + urlen != addrlen)
797 {
798 /* This is a legacy addresses */
799 return NULL;
800 }
801 if (addrlen < sizeof(struct HttpAddress) + urlen)
802 {
803 /* This is a legacy addresses */
804 return NULL;
805 }
806 if (((char *) addr)[addrlen - 1] != '\0')
807 {
808 GNUNET_break (0);
809 return NULL;
810 }
811 spa = http_split_address ((const char *) &ha[1]);
812 if (NULL == spa)
813 {
814 (*res) = GNUNET_SYSERR;
815 return NULL;
816 }
817
818 s = GNUNET_new (struct sockaddr_storage);
819 GNUNET_asprintf (&to_conv, "%s:%u", spa->host, spa->port);
820 if (GNUNET_SYSERR
821 == GNUNET_STRINGS_to_address_ip (to_conv, strlen (to_conv), s))
822 {
823 /* could be a hostname */
824 GNUNET_free (s);
825 (*res) = GNUNET_NO;
826 s = NULL;
827 }
828 else if ((AF_INET != s->ss_family) && (AF_INET6 != s->ss_family))
829 {
830 GNUNET_free (s);
831 (*res) = GNUNET_SYSERR;
832 s = NULL;
833 }
834 else
835 {
836 (*res) = GNUNET_YES;
837 }
838 http_clean_splitted (spa);
839 GNUNET_free (to_conv);
840 return (struct sockaddr *) s;
841}
842
843
844/**
845 * Get the length of an address
846 *
847 * @param addr address
848 * @return the size
849 */
850size_t
851http_common_address_get_size (const struct HttpAddress *addr)
852{
853 return sizeof(struct HttpAddress) + ntohl (addr->urlen);
854}
855
856
857/**
858 * Compare addr1 to addr2
859 *
860 * @param addr1 address1
861 * @param addrlen1 address 1 length
862 * @param addr2 address2
863 * @param addrlen2 address 2 length
864 * @return #GNUNET_YES if equal, #GNUNET_NO if not, #GNUNET_SYSERR on error
865 */
866size_t
867http_common_cmp_addresses (const void *addr1,
868 size_t addrlen1,
869 const void *addr2,
870 size_t addrlen2)
871{
872 const char *a1 = addr1;
873 const char *a2 = addr2;
874 const struct HttpAddress *ha1;
875 const struct HttpAddress *ha2;
876
877 ha1 = (const struct HttpAddress *) a1;
878 ha2 = (const struct HttpAddress *) a2;
879
880 if (NULL == a1)
881 return GNUNET_SYSERR;
882 if (0 == addrlen1)
883 return GNUNET_SYSERR;
884 if (a1[addrlen1 - 1] != '\0')
885 return GNUNET_SYSERR;
886
887 if (NULL == a2)
888 return GNUNET_SYSERR;
889 if (0 == addrlen2)
890 return GNUNET_SYSERR;
891 if (a2[addrlen2 - 1] != '\0')
892 return GNUNET_SYSERR;
893
894 if (addrlen1 != addrlen2)
895 return GNUNET_NO;
896 if (ha1->urlen != ha2->urlen)
897 return GNUNET_NO;
898
899 if (0 == strcmp ((const char *) &ha1[1], (const char *) &ha2[1]))
900 return GNUNET_YES;
901 return GNUNET_NO;
902}
903
904
905/**
906 * Function obtain the network type for an address.
907 *
908 * @param env the environment
909 * @param address the address
910 * @return the network type
911 */
912enum GNUNET_NetworkType
913http_common_get_network_for_address (struct
914 GNUNET_TRANSPORT_PluginEnvironment *env,
915 const struct GNUNET_HELLO_Address *address)
916{
917 struct sockaddr *sa;
918 enum GNUNET_NetworkType net_type;
919 size_t salen = 0;
920 int res;
921
922 net_type = GNUNET_NT_UNSPECIFIED;
923 sa = http_common_socket_from_address (address->address,
924 address->address_length,
925 &res);
926 if (GNUNET_SYSERR == res)
927 return net_type;
928 if (GNUNET_YES == res)
929 {
930 GNUNET_assert (NULL != sa);
931 if (AF_INET == sa->sa_family)
932 {
933 salen = sizeof(struct sockaddr_in);
934 }
935 else if (AF_INET6 == sa->sa_family)
936 {
937 salen = sizeof(struct sockaddr_in6);
938 }
939 net_type = env->get_address_type (env->cls,
940 sa,
941 salen);
942 GNUNET_free (sa);
943 }
944 return net_type;
945}
946
947
948/* 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 299dc0e68..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 the address
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 the address
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 the string
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 78b030e9a..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 app_ctx[in,out] 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 ac4cc672f..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 app_ctx[in,out] 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 + 12];
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 2db31caa3..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 app_ctx[in,out] 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 138fb5080..000000000
--- a/src/transport/plugin_transport_wlan.c
+++ /dev/null
@@ -1,2404 +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 GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage));
1877 break;
1878 }
1879 rxinfo = (const struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage *) hdr;
1880
1881 /* check if message is actually for us */
1882 if (0 != memcmp (&rxinfo->frame.addr3, &mac_bssid_gnunet,
1883 sizeof(struct GNUNET_TRANSPORT_WLAN_MacAddress)))
1884 {
1885 /* Not the GNUnet BSSID */
1886 break;
1887 }
1888 if ((0 != memcmp (&rxinfo->frame.addr1, &bc_all_mac,
1889 sizeof(struct GNUNET_TRANSPORT_WLAN_MacAddress))) &&
1890 (0 != memcmp (&rxinfo->frame.addr1, &plugin->mac_address,
1891 sizeof(struct GNUNET_TRANSPORT_WLAN_MacAddress))))
1892 {
1893 /* Neither broadcast nor specifically for us */
1894 break;
1895 }
1896 if (0 == memcmp (&rxinfo->frame.addr2, &plugin->mac_address,
1897 sizeof(struct GNUNET_TRANSPORT_WLAN_MacAddress)))
1898 {
1899 /* packet is FROM us, thus not FOR us */
1900 break;
1901 }
1902
1903 GNUNET_STATISTICS_update (plugin->env->stats,
1904 _ ("# DATA messages processed"),
1905 1, GNUNET_NO);
1906 LOG (GNUNET_ERROR_TYPE_DEBUG,
1907 "Receiving %u bytes of data from MAC `%s'\n",
1908 (unsigned int) (msize - sizeof(struct
1909 GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage)),
1910 mac_to_string (&rxinfo->frame.addr2));
1911 LOG (GNUNET_ERROR_TYPE_DEBUG,
1912 "Receiving %u bytes of data to MAC `%s'\n",
1913 (unsigned int) (msize - sizeof(struct
1914 GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage)),
1915 mac_to_string (&rxinfo->frame.addr1));
1916 LOG (GNUNET_ERROR_TYPE_DEBUG,
1917 "Receiving %u bytes of data with BSSID MAC `%s'\n",
1918 (unsigned int) (msize - sizeof(struct
1919 GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage)),
1920 mac_to_string (&rxinfo->frame.addr3));
1921 wa.mac = rxinfo->frame.addr2;
1922 wa.options = htonl (0);
1923 mas.endpoint = create_macendpoint (plugin, &wa);
1924 mas.session = NULL;
1925 (void) GNUNET_SERVER_mst_receive (plugin->helper_payload_tokenizer,
1926 &mas,
1927 (const char *) &rxinfo[1],
1928 msize - sizeof(struct
1929 GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage),
1930 GNUNET_YES, GNUNET_NO);
1931 break;
1932
1933 default:
1934 GNUNET_break (0);
1935 LOG (GNUNET_ERROR_TYPE_ERROR,
1936 "Unexpected message of type %u (%u bytes)",
1937 ntohs (hdr->type),
1938 ntohs (hdr->size));
1939 break;
1940 }
1941 return GNUNET_OK;
1942}
1943
1944
1945/**
1946 * Another peer has suggested an address for this
1947 * peer and transport plugin. Check that this could be a valid
1948 * address. If so, consider adding it to the list
1949 * of addresses.
1950 *
1951 * @param cls closure
1952 * @param addr pointer to the address
1953 * @param addrlen length of @a addr
1954 * @return #GNUNET_OK if this is a plausible address for this peer
1955 * and transport
1956 */
1957static int
1958wlan_plugin_address_suggested (void *cls,
1959 const void *addr,
1960 size_t addrlen)
1961{
1962 struct Plugin *plugin = cls;
1963 struct WlanAddress *wa = (struct WlanAddress *) addr;
1964
1965 if (addrlen != sizeof(struct WlanAddress))
1966 {
1967 GNUNET_break_op (0);
1968 return GNUNET_SYSERR;
1969 }
1970 if (GNUNET_YES != plugin->have_mac)
1971 {
1972 LOG (GNUNET_ERROR_TYPE_DEBUG,
1973 "Rejecting MAC `%s': I don't know my MAC!\n",
1974 mac_to_string (addr));
1975 return GNUNET_NO; /* don't know my MAC */
1976 }
1977 if (0 != memcmp (&wa->mac,
1978 &plugin->mac_address,
1979 sizeof(wa->mac)))
1980 {
1981 LOG (GNUNET_ERROR_TYPE_DEBUG,
1982 "Rejecting MAC `%s': not my MAC!\n",
1983 mac_to_string (addr));
1984 return GNUNET_NO; /* not my MAC */
1985 }
1986 return GNUNET_OK;
1987}
1988
1989
1990/**
1991 * Convert the transports address to a nice, human-readable format.
1992 *
1993 * @param cls closure
1994 * @param type name of the transport that generated the address
1995 * @param addr one of the addresses of the host, NULL for the last address
1996 * the specific address format depends on the transport
1997 * @param addrlen length of the address
1998 * @param numeric should (IP) addresses be displayed in numeric form?
1999 * @param timeout after how long should we give up?
2000 * @param asc function to call on each string
2001 * @param asc_cls closure for @a asc
2002 */
2003static void
2004wlan_plugin_address_pretty_printer (void *cls,
2005 const char *type,
2006 const void *addr,
2007 size_t addrlen,
2008 int numeric,
2009 struct GNUNET_TIME_Relative timeout,
2010 GNUNET_TRANSPORT_AddressStringCallback asc,
2011 void *asc_cls)
2012{
2013 const char *ret;
2014
2015 if (sizeof(struct WlanAddress) == addrlen)
2016 ret = wlan_plugin_address_to_string (NULL,
2017 addr,
2018 addrlen);
2019 else
2020 ret = NULL;
2021 asc (asc_cls,
2022 ret,
2023 (NULL == ret) ? GNUNET_SYSERR : GNUNET_OK);
2024 asc (asc_cls, NULL, GNUNET_OK);
2025}
2026
2027
2028/**
2029 * Exit point from the plugin.
2030 *
2031 * @param cls pointer to the api struct
2032 */
2033void *
2034LIBGNUNET_PLUGIN_TRANSPORT_DONE (void *cls)
2035{
2036 struct WlanAddress wa;
2037 struct GNUNET_HELLO_Address *address;
2038 struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
2039 struct Plugin *plugin = api->cls;
2040 struct MacEndpoint *endpoint;
2041 struct MacEndpoint *endpoint_next;
2042
2043 if (NULL == plugin)
2044 {
2045 GNUNET_free (api);
2046 return NULL;
2047 }
2048 if (GNUNET_YES == plugin->have_mac)
2049 {
2050 memset (&wa, 0, sizeof(wa));
2051 wa.options = htonl (plugin->options);
2052 wa.mac = plugin->mac_address;
2053 address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
2054 PLUGIN_NAME,
2055 &wa, sizeof(struct WlanAddress),
2056 GNUNET_HELLO_ADDRESS_INFO_NONE);
2057
2058 plugin->env->notify_address (plugin->env->cls,
2059 GNUNET_NO,
2060 address);
2061 plugin->have_mac = GNUNET_NO;
2062 GNUNET_HELLO_address_free (address);
2063 }
2064
2065 if (NULL != plugin->beacon_task)
2066 {
2067 GNUNET_SCHEDULER_cancel (plugin->beacon_task);
2068 plugin->beacon_task = NULL;
2069 }
2070 if (NULL != plugin->suid_helper)
2071 {
2072 GNUNET_HELPER_stop (plugin->suid_helper,
2073 GNUNET_NO);
2074 plugin->suid_helper = NULL;
2075 }
2076 endpoint_next = plugin->mac_head;
2077 while (NULL != (endpoint = endpoint_next))
2078 {
2079 endpoint_next = endpoint->next;
2080 free_macendpoint (endpoint);
2081 }
2082 if (NULL != plugin->fragment_data_tokenizer)
2083 {
2084 GNUNET_SERVER_mst_destroy (plugin->fragment_data_tokenizer);
2085 plugin->fragment_data_tokenizer = NULL;
2086 }
2087 if (NULL != plugin->wlan_header_payload_tokenizer)
2088 {
2089 GNUNET_SERVER_mst_destroy (plugin->wlan_header_payload_tokenizer);
2090 plugin->wlan_header_payload_tokenizer = NULL;
2091 }
2092 if (NULL != plugin->helper_payload_tokenizer)
2093 {
2094 GNUNET_SERVER_mst_destroy (plugin->helper_payload_tokenizer);
2095 plugin->helper_payload_tokenizer = NULL;
2096 }
2097 GNUNET_free (plugin->wlan_interface);
2098 GNUNET_free (plugin);
2099 GNUNET_free (api);
2100 return NULL;
2101}
2102
2103
2104/**
2105 * Function called to convert a string address to
2106 * a binary address.
2107 *
2108 * @param cls closure (`struct Plugin *`)
2109 * @param addr string address
2110 * @param addrlen length of the address
2111 * @param buf location to store the buffer
2112 * @param added location to store the number of bytes in the buffer.
2113 * If the function returns #GNUNET_SYSERR, its contents are undefined.
2114 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
2115 */
2116static int
2117wlan_plugin_string_to_address (void *cls,
2118 const char *addr,
2119 uint16_t addrlen,
2120 void **buf,
2121 size_t *added)
2122{
2123 struct WlanAddress *wa;
2124 unsigned int a[6];
2125 unsigned int i;
2126 char plugin[5];
2127 uint32_t options;
2128
2129 if ((NULL == addr) || (0 == addrlen))
2130 {
2131 GNUNET_break (0);
2132 return GNUNET_SYSERR;
2133 }
2134 if ('\0' != addr[addrlen - 1])
2135 {
2136 GNUNET_break (0);
2137 return GNUNET_SYSERR;
2138 }
2139 if (strlen (addr) != addrlen - 1)
2140 {
2141 GNUNET_break (0);
2142 return GNUNET_SYSERR;
2143 }
2144
2145 if (8 != sscanf (addr,
2146 "%4s.%u.%X:%X:%X:%X:%X:%X",
2147 plugin, &options,
2148 &a[0], &a[1], &a[2],
2149 &a[3], &a[4], &a[5]))
2150 {
2151 GNUNET_break (0);
2152 return GNUNET_SYSERR;
2153 }
2154 wa = GNUNET_new (struct WlanAddress);
2155 for (i = 0; i < 6; i++)
2156 wa->mac.mac[i] = a[i];
2157 wa->options = htonl (0);
2158 *buf = wa;
2159 *added = sizeof(struct WlanAddress);
2160 return GNUNET_OK;
2161}
2162
2163
2164/**
2165 * Begin monitoring sessions of a plugin. There can only
2166 * be one active monitor per plugin (i.e. if there are
2167 * multiple monitors, the transport service needs to
2168 * multiplex the generated events over all of them).
2169 *
2170 * @param cls closure of the plugin
2171 * @param sic callback to invoke, NULL to disable monitor;
2172 * plugin will being by iterating over all active
2173 * sessions immediately and then enter monitor mode
2174 * @param sic_cls closure for @a sic
2175 */
2176static void
2177wlan_plugin_setup_monitor (void *cls,
2178 GNUNET_TRANSPORT_SessionInfoCallback sic,
2179 void *sic_cls)
2180{
2181 struct Plugin *plugin = cls;
2182 struct MacEndpoint *mac;
2183 struct GNUNET_ATS_Session *session;
2184
2185 plugin->sic = sic;
2186 plugin->sic_cls = sic_cls;
2187 if (NULL != sic)
2188 {
2189 for (mac = plugin->mac_head; NULL != mac; mac = mac->next)
2190 for (session = mac->sessions_head; NULL != session; session =
2191 session->next)
2192 {
2193 notify_session_monitor (plugin,
2194 session,
2195 GNUNET_TRANSPORT_SS_INIT);
2196 notify_session_monitor (plugin,
2197 session,
2198 GNUNET_TRANSPORT_SS_UP);
2199 }
2200 sic (sic_cls, NULL, NULL);
2201 }
2202}
2203
2204
2205/**
2206 * Function that will be called whenever the transport service wants to
2207 * notify the plugin that a session is still active and in use and
2208 * therefore the session timeout for this session has to be updated
2209 *
2210 * @param cls closure
2211 * @param peer which peer was the session for
2212 * @param session which session is being updated
2213 */
2214static void
2215wlan_plugin_update_session_timeout (void *cls,
2216 const struct GNUNET_PeerIdentity *peer,
2217 struct GNUNET_ATS_Session *session)
2218{
2219 GNUNET_assert (NULL != session->timeout_task);
2220 session->timeout = GNUNET_TIME_relative_to_absolute (
2221 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2222}
2223
2224
2225/**
2226 * Function that will be called whenever the transport service wants to
2227 * notify the plugin that the inbound quota changed and that the plugin
2228 * should update it's delay for the next receive value
2229 *
2230 * @param cls closure
2231 * @param peer which peer was the session for
2232 * @param session which session is being updated
2233 * @param delay new delay to use for receiving
2234 */
2235static void
2236wlan_plugin_update_inbound_delay (void *cls,
2237 const struct GNUNET_PeerIdentity *peer,
2238 struct GNUNET_ATS_Session *session,
2239 struct GNUNET_TIME_Relative delay)
2240{
2241 /* does nothing, as inbound delay is not supported by WLAN */
2242}
2243
2244
2245/**
2246 * Entry point for the plugin.
2247 *
2248 * @param cls closure, the `struct GNUNET_TRANSPORT_PluginEnvironment *`
2249 * @return the `struct GNUNET_TRANSPORT_PluginFunctions *` or NULL on error
2250 */
2251void *
2252LIBGNUNET_PLUGIN_TRANSPORT_INIT (void *cls)
2253{
2254 struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
2255 struct GNUNET_TRANSPORT_PluginFunctions *api;
2256 struct Plugin *plugin;
2257 char *wlan_interface;
2258 unsigned long long testmode;
2259 char *binary;
2260
2261 /* check for 'special' mode */
2262 if (NULL == env->receive)
2263 {
2264 /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully
2265 initialize the plugin or the API */
2266 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
2267 api->cls = NULL;
2268 api->address_pretty_printer = &wlan_plugin_address_pretty_printer;
2269 api->address_to_string = &wlan_plugin_address_to_string;
2270 api->string_to_address = &wlan_plugin_string_to_address;
2271 return api;
2272 }
2273
2274 testmode = 0;
2275 /* check configuration */
2276 if ((GNUNET_YES ==
2277 GNUNET_CONFIGURATION_have_value (env->cfg,
2278 CONFIG_NAME,
2279 "TESTMODE")) &&
2280 ((GNUNET_SYSERR ==
2281 GNUNET_CONFIGURATION_get_value_number (env->cfg,
2282 CONFIG_NAME,
2283 "TESTMODE",
2284 &testmode)) ||
2285 (testmode > 2)))
2286 {
2287 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
2288 CONFIG_NAME,
2289 "TESTMODE");
2290 return NULL;
2291 }
2292 binary = GNUNET_OS_get_libexec_binary_path (HELPER_NAME);
2293 if ((0 == testmode) &&
2294 (GNUNET_YES !=
2295 GNUNET_OS_check_helper_binary (binary,
2296 GNUNET_YES,
2297 NULL)))
2298 {
2299 LOG (GNUNET_ERROR_TYPE_ERROR,
2300 _ ("Helper binary `%s' not SUID, cannot run WLAN transport\n"),
2301 HELPER_NAME);
2302 GNUNET_free (binary);
2303 return NULL;
2304 }
2305 GNUNET_free (binary);
2306 if (GNUNET_YES !=
2307 GNUNET_CONFIGURATION_get_value_string (env->cfg,
2308 CONFIG_NAME,
2309 "INTERFACE",
2310 &wlan_interface))
2311 {
2312 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
2313 CONFIG_NAME,
2314 "INTERFACE");
2315 return NULL;
2316 }
2317
2318 plugin = GNUNET_new (struct Plugin);
2319 plugin->wlan_interface = wlan_interface;
2320 plugin->env = env;
2321 GNUNET_STATISTICS_set (plugin->env->stats,
2322 _ ("# sessions allocated"),
2323 0, GNUNET_NO);
2324 GNUNET_STATISTICS_set (plugin->env->stats,
2325 _ ("# MAC endpoints allocated"),
2326 0, 0);
2327 GNUNET_BANDWIDTH_tracker_init (&plugin->tracker, NULL, NULL,
2328 GNUNET_BANDWIDTH_value_init (100 * 1024
2329 * 1024 / 8),
2330 100);
2331 plugin->fragment_data_tokenizer = GNUNET_SERVER_mst_create (&process_data,
2332 plugin);
2333 plugin->wlan_header_payload_tokenizer = GNUNET_SERVER_mst_create (
2334 &process_data,
2335 plugin);
2336 plugin->helper_payload_tokenizer = GNUNET_SERVER_mst_create (&process_data,
2337 plugin);
2338
2339 plugin->options = 0;
2340
2341 /* some compilers do not like switch on 'long long'... */
2342 switch ((unsigned int) testmode)
2343 {
2344 case 0: /* normal */
2345 plugin->helper_argv[0] = (char *) HELPER_NAME;
2346 plugin->helper_argv[1] = wlan_interface;
2347 plugin->helper_argv[2] = NULL;
2348 plugin->suid_helper = GNUNET_HELPER_start (GNUNET_NO,
2349 HELPER_NAME,
2350 plugin->helper_argv,
2351 &handle_helper_message,
2352 NULL,
2353 plugin);
2354 break;
2355
2356 case 1: /* testmode, peer 1 */
2357 plugin->helper_argv[0] = (char *) DUMMY_HELPER_NAME;
2358 plugin->helper_argv[1] = (char *) "1";
2359 plugin->helper_argv[2] = NULL;
2360 plugin->suid_helper = GNUNET_HELPER_start (GNUNET_NO,
2361 DUMMY_HELPER_NAME,
2362 plugin->helper_argv,
2363 &handle_helper_message,
2364 NULL,
2365 plugin);
2366 break;
2367
2368 case 2: /* testmode, peer 2 */
2369 plugin->helper_argv[0] = (char *) DUMMY_HELPER_NAME;
2370 plugin->helper_argv[1] = (char *) "2";
2371 plugin->helper_argv[2] = NULL;
2372 plugin->suid_helper = GNUNET_HELPER_start (GNUNET_NO,
2373 DUMMY_HELPER_NAME,
2374 plugin->helper_argv,
2375 &handle_helper_message,
2376 NULL,
2377 plugin);
2378 break;
2379
2380 default:
2381 GNUNET_assert (0);
2382 }
2383
2384 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
2385 api->cls = plugin;
2386 api->send = &wlan_plugin_send;
2387 api->get_session = &wlan_plugin_get_session;
2388 api->disconnect_peer = &wlan_plugin_disconnect_peer;
2389 api->disconnect_session = &wlan_plugin_disconnect_session;
2390 api->query_keepalive_factor = &wlan_plugin_query_keepalive_factor;
2391 api->address_pretty_printer = &wlan_plugin_address_pretty_printer;
2392 api->check_address = &wlan_plugin_address_suggested;
2393 api->address_to_string = &wlan_plugin_address_to_string;
2394 api->string_to_address = &wlan_plugin_string_to_address;
2395 api->get_network = &wlan_plugin_get_network;
2396 api->get_network_for_address = &wlan_plugin_get_network_for_address;
2397 api->update_session_timeout = &wlan_plugin_update_session_timeout;
2398 api->update_inbound_delay = &wlan_plugin_update_inbound_delay;
2399 api->setup_monitor = &wlan_plugin_setup_monitor;
2400 return api;
2401}
2402
2403
2404/* 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 d175f9377..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_crypto_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/profile_transport.sh b/src/transport/profile_transport.sh
deleted file mode 100755
index 0e6935fc7..000000000
--- a/src/transport/profile_transport.sh
+++ /dev/null
@@ -1,18 +0,0 @@
1#!/bin/sh
2
3C_ITERATIONS=5
4C_MESSAGE_DELTA=10
5C_MESSAGE_START=10
6C_MESSAGE_END=2000
7
8#for i in {$C_MESSAGE_START..$C_MESSAGE_END..$C_MESSAGE_DELTA}
9# do
10# echo "Welcome $i times"
11# done
12
13
14for $((cur=$C_MESSAGE_START; cur<=$C_MESSAGE_END; cur = cur + $C_MESSAGE_DELTA))
15{
16 ./gnunet-transport-profiler -p NSGWRTMHG2YJK9KZSTEWKJ5TK20AGRDBWHFA1ZNKKZ7T360MZ8S0 -s -c perf_https_peer1.conf -n 20240 -m $cur -i 4
17 sleep 1
18}
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 f4d48d4f6..000000000
--- a/src/transport/tcp_server_legacy.c
+++ /dev/null
@@ -1,1748 +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
702/**
703 * Resume accepting connections from the listen socket.
704 *
705 * @param server server to stop accepting connections.
706 */
707void
708GNUNET_SERVER_resume (struct GNUNET_SERVER_Handle *server)
709{
710 struct GNUNET_NETWORK_FDSet *r;
711 unsigned int i;
712
713 if (NULL == server->listen_sockets)
714 return;
715 if (NULL == server->listen_sockets[0])
716 return; /* nothing to do, no listen sockets! */
717 if (NULL == server->listen_sockets[1])
718 {
719 /* simplified method: no fd set needed; this is then much simpler
720 and much more efficient */
721 server->listen_task =
722 GNUNET_SCHEDULER_add_read_net_with_priority (GNUNET_TIME_UNIT_FOREVER_REL,
723 GNUNET_SCHEDULER_PRIORITY_HIGH,
724 server->listen_sockets[0],
725 &process_listen_socket,
726 server);
727 return;
728 }
729 r = GNUNET_NETWORK_fdset_create ();
730 i = 0;
731 while (NULL != server->listen_sockets[i])
732 GNUNET_NETWORK_fdset_set (r, server->listen_sockets[i++]);
733 server->listen_task =
734 GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH,
735 GNUNET_TIME_UNIT_FOREVER_REL, r, NULL,
736 &process_listen_socket, server);
737 GNUNET_NETWORK_fdset_destroy (r);
738}
739
740
741/**
742 * Stop the listen socket and get ready to shutdown the server
743 * once only 'monitor' clients are left.
744 *
745 * @param server server to stop listening on
746 */
747void
748GNUNET_SERVER_stop_listening (struct GNUNET_SERVER_Handle *server)
749{
750 unsigned int i;
751
752 LOG (GNUNET_ERROR_TYPE_DEBUG,
753 "Server in soft shutdown\n");
754 if (NULL != server->listen_task)
755 {
756 GNUNET_SCHEDULER_cancel (server->listen_task);
757 server->listen_task = NULL;
758 }
759 if (NULL != server->listen_sockets)
760 {
761 i = 0;
762 while (NULL != server->listen_sockets[i])
763 GNUNET_break (GNUNET_OK ==
764 GNUNET_NETWORK_socket_close (server->listen_sockets[i++]));
765 GNUNET_free (server->listen_sockets);
766 server->listen_sockets = NULL;
767 }
768 if (GNUNET_NO == server->in_soft_shutdown)
769 server->in_soft_shutdown = GNUNET_YES;
770 test_monitor_clients (server);
771}
772
773
774/**
775 * Free resources held by this server.
776 *
777 * @param server server to destroy
778 */
779void
780GNUNET_SERVER_destroy (struct GNUNET_SERVER_Handle *server)
781{
782 struct HandlerList *hpos;
783 struct NotifyList *npos;
784 unsigned int i;
785
786 LOG (GNUNET_ERROR_TYPE_DEBUG,
787 "Server shutting down.\n");
788 if (NULL != server->listen_task)
789 {
790 GNUNET_SCHEDULER_cancel (server->listen_task);
791 server->listen_task = NULL;
792 }
793 if (NULL != server->listen_sockets)
794 {
795 i = 0;
796 while (NULL != server->listen_sockets[i])
797 GNUNET_break (GNUNET_OK ==
798 GNUNET_NETWORK_socket_close (server->listen_sockets[i++]));
799 GNUNET_free (server->listen_sockets);
800 server->listen_sockets = NULL;
801 }
802 while (NULL != server->clients_head)
803 GNUNET_SERVER_client_disconnect (server->clients_head);
804 while (NULL != (hpos = server->handlers))
805 {
806 server->handlers = hpos->next;
807 GNUNET_free (hpos);
808 }
809 while (NULL != (npos = server->disconnect_notify_list_head))
810 {
811 npos->callback (npos->callback_cls,
812 NULL);
813 GNUNET_CONTAINER_DLL_remove (server->disconnect_notify_list_head,
814 server->disconnect_notify_list_tail,
815 npos);
816 GNUNET_free (npos);
817 }
818 while (NULL != (npos = server->connect_notify_list_head))
819 {
820 npos->callback (npos->callback_cls,
821 NULL);
822 GNUNET_CONTAINER_DLL_remove (server->connect_notify_list_head,
823 server->connect_notify_list_tail,
824 npos);
825 GNUNET_free (npos);
826 }
827 GNUNET_free (server);
828}
829
830
831/**
832 * Add additional handlers to an existing server.
833 *
834 * @param server the server to add handlers to
835 * @param handlers array of message handlers for
836 * incoming messages; the last entry must
837 * have "NULL" for the "callback"; multiple
838 * entries for the same type are allowed,
839 * they will be called in order of occurrence.
840 * These handlers can be removed later;
841 * the handlers array must exist until removed
842 * (or server is destroyed).
843 */
844void
845GNUNET_SERVER_add_handlers (struct GNUNET_SERVER_Handle *server,
846 const struct GNUNET_SERVER_MessageHandler *handlers)
847{
848 struct HandlerList *p;
849
850 p = GNUNET_new (struct HandlerList);
851 p->handlers = handlers;
852 p->next = server->handlers;
853 server->handlers = p;
854}
855
856
857/**
858 * Change functions used by the server to tokenize the message stream.
859 * (very rarely used).
860 *
861 * @param server server to modify
862 * @param create new tokenizer initialization function
863 * @param destroy new tokenizer destruction function
864 * @param receive new tokenizer receive function
865 * @param cls closure for @a create, @a receive, @a destroy
866 */
867void
868GNUNET_SERVER_set_callbacks (struct GNUNET_SERVER_Handle *server,
869 GNUNET_SERVER_MstCreateCallback create,
870 GNUNET_SERVER_MstDestroyCallback destroy,
871 GNUNET_SERVER_MstReceiveCallback receive,
872 void *cls)
873{
874 server->mst_create = create;
875 server->mst_destroy = destroy;
876 server->mst_receive = receive;
877 server->mst_cls = cls;
878}
879
880
881/**
882 * Task run to warn about missing calls to #GNUNET_SERVER_receive_done.
883 *
884 * @param cls our `struct GNUNET_SERVER_Client *` to process more requests from
885 */
886static void
887warn_no_receive_done (void *cls)
888{
889 struct GNUNET_SERVER_Client *client = cls;
890
891 GNUNET_break (0 != client->warn_type); /* type should never be 0 here, as we don't use 0 */
892 client->warn_task =
893 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
894 &warn_no_receive_done, client);
895 LOG (GNUNET_ERROR_TYPE_WARNING,
896 _ (
897 "Processing code for message of type %u did not call `GNUNET_SERVER_receive_done' after %s\n"),
898 (unsigned int) client->warn_type,
899 GNUNET_STRINGS_relative_time_to_string (
900 GNUNET_TIME_absolute_get_duration (client->warn_start),
901 GNUNET_YES));
902}
903
904
905/**
906 * Disable the warning the server issues if a message is not acknowledged
907 * in a timely fashion. Use this call if a client is intentionally delayed
908 * for a while. Only applies to the current message.
909 *
910 * @param client client for which to disable the warning
911 */
912void
913GNUNET_SERVER_disable_receive_done_warning (struct GNUNET_SERVER_Client *client)
914{
915 if (NULL != client->warn_task)
916 {
917 GNUNET_SCHEDULER_cancel (client->warn_task);
918 client->warn_task = NULL;
919 }
920}
921
922
923/**
924 * Inject a message into the server, pretend it came
925 * from the specified client. Delivery of the message
926 * will happen instantly (if a handler is installed;
927 * otherwise the call does nothing).
928 *
929 * @param server the server receiving the message
930 * @param sender the "pretended" sender of the message
931 * can be NULL!
932 * @param message message to transmit
933 * @return #GNUNET_OK if the message was OK and the
934 * connection can stay open
935 * #GNUNET_SYSERR if the connection to the
936 * client should be shut down
937 */
938int
939GNUNET_SERVER_inject (struct GNUNET_SERVER_Handle *server,
940 struct GNUNET_SERVER_Client *sender,
941 const struct GNUNET_MessageHeader *message)
942{
943 struct HandlerList *pos;
944 const struct GNUNET_SERVER_MessageHandler *mh;
945 unsigned int i;
946 uint16_t type;
947 uint16_t size;
948 int found;
949
950 type = ntohs (message->type);
951 size = ntohs (message->size);
952 LOG (GNUNET_ERROR_TYPE_INFO,
953 "Received message of type %u and size %u from client\n",
954 type, size);
955 found = GNUNET_NO;
956 for (pos = server->handlers; NULL != pos; pos = pos->next)
957 {
958 i = 0;
959 while (pos->handlers[i].callback != NULL)
960 {
961 mh = &pos->handlers[i];
962 if ((mh->type == type) || (mh->type == GNUNET_MESSAGE_TYPE_ALL))
963 {
964 if ((0 != mh->expected_size) && (mh->expected_size != size))
965 {
966#if GNUNET8_NETWORK_IS_DEAD
967 LOG (GNUNET_ERROR_TYPE_WARNING,
968 "Expected %u bytes for message of type %u, got %u\n",
969 mh->expected_size, mh->type, size);
970 GNUNET_break_op (0);
971#else
972 LOG (GNUNET_ERROR_TYPE_DEBUG,
973 "Expected %u bytes for message of type %u, got %u\n",
974 mh->expected_size, mh->type, size);
975#endif
976 return GNUNET_SYSERR;
977 }
978 if (NULL != sender)
979 {
980 if ((0 == sender->suspended) &&
981 (NULL == sender->warn_task))
982 {
983 GNUNET_break (0 != type); /* type should never be 0 here, as we don't use 0 */
984 sender->warn_start = GNUNET_TIME_absolute_get ();
985 sender->warn_task =
986 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
987 &warn_no_receive_done,
988 sender);
989 sender->warn_type = type;
990 }
991 sender->suspended++;
992 }
993 mh->callback (mh->callback_cls, sender, message);
994 found = GNUNET_YES;
995 }
996 i++;
997 }
998 }
999 if (GNUNET_NO == found)
1000 {
1001 LOG (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1002 "Received message of unknown type %d\n", type);
1003 if (GNUNET_YES == server->require_found)
1004 return GNUNET_SYSERR;
1005 }
1006 return GNUNET_OK;
1007}
1008
1009
1010/**
1011 * We are receiving an incoming message. Process it.
1012 *
1013 * @param cls our closure (handle for the client)
1014 * @param buf buffer with data received from network
1015 * @param available number of bytes available in buf
1016 * @param addr address of the sender
1017 * @param addrlen length of @a addr
1018 * @param errCode code indicating errors receiving, 0 for success
1019 */
1020static void
1021process_incoming (void *cls,
1022 const void *buf,
1023 size_t available,
1024 const struct sockaddr *addr,
1025 socklen_t addrlen,
1026 int errCode);
1027
1028
1029/**
1030 * Process messages from the client's message tokenizer until either
1031 * the tokenizer is empty (and then schedule receiving more), or
1032 * until some handler is not immediately done (then wait for restart_processing)
1033 * or shutdown.
1034 *
1035 * @param client the client to process, RC must have already been increased
1036 * using #GNUNET_SERVER_client_keep and will be decreased by one in this
1037 * function
1038 * @param ret #GNUNET_NO to start processing from the buffer,
1039 * #GNUNET_OK if the mst buffer is drained and we should instantly go back to receiving
1040 * #GNUNET_SYSERR if we should instantly abort due to error in a previous step
1041 */
1042static void
1043process_mst (struct GNUNET_SERVER_Client *client,
1044 int ret)
1045{
1046 while ((GNUNET_SYSERR != ret) && (NULL != client->server) &&
1047 (GNUNET_YES != client->shutdown_now) && (0 == client->suspended))
1048 {
1049 if (GNUNET_OK == ret)
1050 {
1051 LOG (GNUNET_ERROR_TYPE_DEBUG,
1052 "Server re-enters receive loop, timeout: %s.\n",
1053 GNUNET_STRINGS_relative_time_to_string (client->idle_timeout,
1054 GNUNET_YES));
1055 client->receive_pending = GNUNET_YES;
1056 if (GNUNET_OK !=
1057 GNUNET_CONNECTION_receive (client->connection,
1058 GNUNET_MAX_MESSAGE_SIZE - 1,
1059 client->idle_timeout,
1060 &process_incoming,
1061 client))
1062 return;
1063 break;
1064 }
1065 LOG (GNUNET_ERROR_TYPE_DEBUG,
1066 "Server processes additional messages instantly.\n");
1067 if (NULL != client->server->mst_receive)
1068 ret =
1069 client->server->mst_receive (client->server->mst_cls, client->mst,
1070 client, NULL, 0, GNUNET_NO, GNUNET_YES);
1071 else
1072 ret =
1073 GNUNET_SERVER_mst_receive (client->mst, client, NULL, 0, GNUNET_NO,
1074 GNUNET_YES);
1075 }
1076 LOG (GNUNET_ERROR_TYPE_DEBUG,
1077 "Server leaves instant processing loop: ret = %d, server = %p, shutdown = %d, suspended = %u\n",
1078 ret, client->server,
1079 client->shutdown_now,
1080 client->suspended);
1081 if (GNUNET_NO == ret)
1082 {
1083 LOG (GNUNET_ERROR_TYPE_DEBUG,
1084 "Server has more data pending but is suspended.\n");
1085 client->receive_pending = GNUNET_SYSERR; /* data pending */
1086 }
1087 if ((GNUNET_SYSERR == ret) ||
1088 (GNUNET_YES == client->shutdown_now))
1089 GNUNET_SERVER_client_disconnect (client);
1090}
1091
1092
1093/**
1094 * We are receiving an incoming message. Process it.
1095 *
1096 * @param cls our closure (handle for the client)
1097 * @param buf buffer with data received from network
1098 * @param available number of bytes available in buf
1099 * @param addr address of the sender
1100 * @param addrlen length of @a addr
1101 * @param errCode code indicating errors receiving, 0 for success
1102 */
1103static void
1104process_incoming (void *cls,
1105 const void *buf,
1106 size_t available,
1107 const struct sockaddr *addr,
1108 socklen_t addrlen,
1109 int errCode)
1110{
1111 struct GNUNET_SERVER_Client *client = cls;
1112 struct GNUNET_SERVER_Handle *server = client->server;
1113 struct GNUNET_TIME_Absolute end;
1114 struct GNUNET_TIME_Absolute now;
1115 int ret;
1116
1117 GNUNET_assert (GNUNET_YES == client->receive_pending);
1118 client->receive_pending = GNUNET_NO;
1119 now = GNUNET_TIME_absolute_get ();
1120 end = GNUNET_TIME_absolute_add (client->last_activity,
1121 client->idle_timeout);
1122
1123 if ((NULL == buf) &&
1124 (0 == available) &&
1125 (NULL == addr) &&
1126 (0 == errCode) &&
1127 (GNUNET_YES != client->shutdown_now) &&
1128 (NULL != server) &&
1129 (GNUNET_YES == GNUNET_CONNECTION_check (client->connection)) &&
1130 (end.abs_value_us > now.abs_value_us))
1131 {
1132 /* wait longer, timeout changed (i.e. due to us sending) */
1133 LOG (GNUNET_ERROR_TYPE_DEBUG,
1134 "Receive time out, but no disconnect due to sending (%p)\n",
1135 client);
1136 client->receive_pending = GNUNET_YES;
1137 GNUNET_CONNECTION_receive (client->connection,
1138 GNUNET_MAX_MESSAGE_SIZE - 1,
1139 GNUNET_TIME_absolute_get_remaining (end),
1140 &process_incoming,
1141 client);
1142 return;
1143 }
1144 if ((NULL == buf) ||
1145 (0 == available) ||
1146 (0 != errCode) ||
1147 (NULL == server) ||
1148 (GNUNET_YES == client->shutdown_now) ||
1149 (GNUNET_YES != GNUNET_CONNECTION_check (client->connection)))
1150 {
1151 /* other side closed connection, error connecting, etc. */
1152 LOG (GNUNET_ERROR_TYPE_DEBUG,
1153 "Failed to connect or other side closed connection (%p)\n",
1154 client);
1155 GNUNET_SERVER_client_disconnect (client);
1156 return;
1157 }
1158 LOG (GNUNET_ERROR_TYPE_DEBUG,
1159 "Server receives %u bytes from `%s'.\n",
1160 (unsigned int) available,
1161 GNUNET_a2s (addr, addrlen));
1162 GNUNET_SERVER_client_keep (client);
1163 client->last_activity = now;
1164
1165 if (NULL != server->mst_receive)
1166 {
1167 ret = client->server->mst_receive (client->server->mst_cls,
1168 client->mst,
1169 client,
1170 buf,
1171 available,
1172 GNUNET_NO,
1173 GNUNET_YES);
1174 }
1175 else if (NULL != client->mst)
1176 {
1177 ret =
1178 GNUNET_SERVER_mst_receive (client->mst,
1179 client,
1180 buf,
1181 available,
1182 GNUNET_NO,
1183 GNUNET_YES);
1184 }
1185 else
1186 {
1187 GNUNET_break (0);
1188 return;
1189 }
1190 process_mst (client,
1191 ret);
1192 GNUNET_SERVER_client_drop (client);
1193}
1194
1195
1196/**
1197 * Task run to start again receiving from the network
1198 * and process requests.
1199 *
1200 * @param cls our `struct GNUNET_SERVER_Client *` to process more requests from
1201 */
1202static void
1203restart_processing (void *cls)
1204{
1205 struct GNUNET_SERVER_Client *client = cls;
1206
1207 GNUNET_assert (GNUNET_YES != client->shutdown_now);
1208 client->restart_task = NULL;
1209 if (GNUNET_NO == client->receive_pending)
1210 {
1211 LOG (GNUNET_ERROR_TYPE_DEBUG, "Server begins to read again from client.\n");
1212 client->receive_pending = GNUNET_YES;
1213 GNUNET_CONNECTION_receive (client->connection,
1214 GNUNET_MAX_MESSAGE_SIZE - 1,
1215 client->idle_timeout,
1216 &process_incoming,
1217 client);
1218 return;
1219 }
1220 LOG (GNUNET_ERROR_TYPE_DEBUG,
1221 "Server continues processing messages still in the buffer.\n");
1222 GNUNET_SERVER_client_keep (client);
1223 client->receive_pending = GNUNET_NO;
1224 process_mst (client,
1225 GNUNET_NO);
1226 GNUNET_SERVER_client_drop (client);
1227}
1228
1229
1230/**
1231 * This function is called whenever our inbound message tokenizer has
1232 * received a complete message.
1233 *
1234 * @param cls closure (struct GNUNET_SERVER_Handle)
1235 * @param client identification of the client (`struct GNUNET_SERVER_Client *`)
1236 * @param message the actual message
1237 *
1238 * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing
1239 */
1240static int
1241client_message_tokenizer_callback (void *cls,
1242 void *client,
1243 const struct GNUNET_MessageHeader *message)
1244{
1245 struct GNUNET_SERVER_Handle *server = cls;
1246 struct GNUNET_SERVER_Client *sender = client;
1247 int ret;
1248
1249 LOG (GNUNET_ERROR_TYPE_DEBUG,
1250 "Tokenizer gives server message of type %u and size %u from client\n",
1251 ntohs (message->type), ntohs (message->size));
1252 sender->in_process_client_buffer = GNUNET_YES;
1253 ret = GNUNET_SERVER_inject (server, sender, message);
1254 sender->in_process_client_buffer = GNUNET_NO;
1255 if ((GNUNET_OK != ret) || (GNUNET_YES == sender->shutdown_now))
1256 {
1257 GNUNET_SERVER_client_disconnect (sender);
1258 return GNUNET_SYSERR;
1259 }
1260 return GNUNET_OK;
1261}
1262
1263
1264/**
1265 * Add a TCP socket-based connection to the set of handles managed by
1266 * this server. Use this function for outgoing (P2P) connections that
1267 * we initiated (and where this server should process incoming
1268 * messages).
1269 *
1270 * @param server the server to use
1271 * @param connection the connection to manage (client must
1272 * stop using this connection from now on)
1273 * @return the client handle
1274 */
1275struct GNUNET_SERVER_Client *
1276GNUNET_SERVER_connect_socket (struct GNUNET_SERVER_Handle *server,
1277 struct GNUNET_CONNECTION_Handle *connection)
1278{
1279 struct GNUNET_SERVER_Client *client;
1280 struct NotifyList *n;
1281
1282 client = GNUNET_new (struct GNUNET_SERVER_Client);
1283 client->connection = connection;
1284 client->server = server;
1285 client->last_activity = GNUNET_TIME_absolute_get ();
1286 client->idle_timeout = server->idle_timeout;
1287 GNUNET_CONTAINER_DLL_insert (server->clients_head,
1288 server->clients_tail,
1289 client);
1290 if (NULL != server->mst_create)
1291 client->mst =
1292 server->mst_create (server->mst_cls, client);
1293 else
1294 client->mst =
1295 GNUNET_SERVER_mst_create (&client_message_tokenizer_callback,
1296 server);
1297 GNUNET_assert (NULL != client->mst);
1298 for (n = server->connect_notify_list_head; NULL != n; n = n->next)
1299 n->callback (n->callback_cls, client);
1300 client->receive_pending = GNUNET_YES;
1301 if (GNUNET_SYSERR ==
1302 GNUNET_CONNECTION_receive (client->connection,
1303 GNUNET_MAX_MESSAGE_SIZE - 1,
1304 client->idle_timeout,
1305 &process_incoming,
1306 client))
1307 return NULL;
1308 return client;
1309}
1310
1311
1312/**
1313 * Change the timeout for a particular client. Decreasing the timeout
1314 * may not go into effect immediately (only after the previous timeout
1315 * times out or activity happens on the socket).
1316 *
1317 * @param client the client to update
1318 * @param timeout new timeout for activities on the socket
1319 */
1320void
1321GNUNET_SERVER_client_set_timeout (struct GNUNET_SERVER_Client *client,
1322 struct GNUNET_TIME_Relative timeout)
1323{
1324 client->idle_timeout = timeout;
1325}
1326
1327
1328/**
1329 * Notify the server that the given client handle should
1330 * be kept (keeps the connection up if possible, increments
1331 * the internal reference counter).
1332 *
1333 * @param client the client to keep
1334 */
1335void
1336GNUNET_SERVER_client_keep (struct GNUNET_SERVER_Client *client)
1337{
1338 client->reference_count++;
1339}
1340
1341
1342/**
1343 * Notify the server that the given client handle is no
1344 * longer required. Decrements the reference counter. If
1345 * that counter reaches zero an inactive connection maybe
1346 * closed.
1347 *
1348 * @param client the client to drop
1349 */
1350void
1351GNUNET_SERVER_client_drop (struct GNUNET_SERVER_Client *client)
1352{
1353 GNUNET_assert (client->reference_count > 0);
1354 client->reference_count--;
1355 if ((GNUNET_YES == client->shutdown_now) && (0 == client->reference_count))
1356 GNUNET_SERVER_client_disconnect (client);
1357}
1358
1359
1360/**
1361 * Obtain the network address of the other party.
1362 *
1363 * @param client the client to get the address for
1364 * @param addr where to store the address
1365 * @param addrlen where to store the length of the @a addr
1366 * @return #GNUNET_OK on success
1367 */
1368int
1369GNUNET_SERVER_client_get_address (struct GNUNET_SERVER_Client *client,
1370 void **addr, size_t *addrlen)
1371{
1372 return GNUNET_CONNECTION_get_address (client->connection, addr, addrlen);
1373}
1374
1375
1376/**
1377 * Ask the server to notify us whenever a client disconnects.
1378 * This function is called whenever the actual network connection
1379 * is closed; the reference count may be zero or larger than zero
1380 * at this point.
1381 *
1382 * @param server the server manageing the clients
1383 * @param callback function to call on disconnect
1384 * @param callback_cls closure for @a callback
1385 */
1386void
1387GNUNET_SERVER_disconnect_notify (struct GNUNET_SERVER_Handle *server,
1388 GNUNET_SERVER_DisconnectCallback callback,
1389 void *callback_cls)
1390{
1391 struct NotifyList *n;
1392
1393 n = GNUNET_new (struct NotifyList);
1394 n->callback = callback;
1395 n->callback_cls = callback_cls;
1396 GNUNET_CONTAINER_DLL_insert (server->disconnect_notify_list_head,
1397 server->disconnect_notify_list_tail,
1398 n);
1399}
1400
1401
1402/**
1403 * Ask the server to notify us whenever a client connects.
1404 * This function is called whenever the actual network connection
1405 * is opened. If the server is destroyed before this
1406 * notification is explicitly cancelled, the 'callback' will
1407 * once be called with a 'client' argument of NULL to indicate
1408 * that the server itself is now gone (and that the callback
1409 * won't be called anymore and also can no longer be cancelled).
1410 *
1411 * @param server the server manageing the clients
1412 * @param callback function to call on sconnect
1413 * @param callback_cls closure for @a callback
1414 */
1415void
1416GNUNET_SERVER_connect_notify (struct GNUNET_SERVER_Handle *server,
1417 GNUNET_SERVER_ConnectCallback callback,
1418 void *callback_cls)
1419{
1420 struct NotifyList *n;
1421 struct GNUNET_SERVER_Client *client;
1422
1423 n = GNUNET_new (struct NotifyList);
1424 n->callback = callback;
1425 n->callback_cls = callback_cls;
1426 GNUNET_CONTAINER_DLL_insert (server->connect_notify_list_head,
1427 server->connect_notify_list_tail,
1428 n);
1429 for (client = server->clients_head; NULL != client; client = client->next)
1430 callback (callback_cls, client);
1431}
1432
1433
1434/**
1435 * Ask the server to stop notifying us whenever a client connects.
1436 *
1437 * @param server the server manageing the clients
1438 * @param callback function to call on connect
1439 * @param callback_cls closure for @a callback
1440 */
1441void
1442GNUNET_SERVER_disconnect_notify_cancel (struct GNUNET_SERVER_Handle *server,
1443 GNUNET_SERVER_DisconnectCallback
1444 callback,
1445 void *callback_cls)
1446{
1447 struct NotifyList *pos;
1448
1449 for (pos = server->disconnect_notify_list_head; NULL != pos; pos = pos->next)
1450 if ((pos->callback == callback) && (pos->callback_cls == callback_cls))
1451 break;
1452 if (NULL == pos)
1453 {
1454 GNUNET_break (0);
1455 return;
1456 }
1457 GNUNET_CONTAINER_DLL_remove (server->disconnect_notify_list_head,
1458 server->disconnect_notify_list_tail,
1459 pos);
1460 GNUNET_free (pos);
1461}
1462
1463
1464/**
1465 * Ask the server to stop notifying us whenever a client disconnects.
1466 *
1467 * @param server the server manageing the clients
1468 * @param callback function to call on disconnect
1469 * @param callback_cls closure for @a callback
1470 */
1471void
1472GNUNET_SERVER_connect_notify_cancel (struct GNUNET_SERVER_Handle *server,
1473 GNUNET_SERVER_ConnectCallback callback,
1474 void *callback_cls)
1475{
1476 struct NotifyList *pos;
1477
1478 for (pos = server->connect_notify_list_head; NULL != pos; pos = pos->next)
1479 if ((pos->callback == callback) && (pos->callback_cls == callback_cls))
1480 break;
1481 if (NULL == pos)
1482 {
1483 GNUNET_break (0);
1484 return;
1485 }
1486 GNUNET_CONTAINER_DLL_remove (server->connect_notify_list_head,
1487 server->connect_notify_list_tail,
1488 pos);
1489 GNUNET_free (pos);
1490}
1491
1492
1493/**
1494 * Ask the server to disconnect from the given client.
1495 * This is the same as returning #GNUNET_SYSERR from a message
1496 * handler, except that it allows dropping of a client even
1497 * when not handling a message from that client.
1498 *
1499 * @param client the client to disconnect from
1500 */
1501void
1502GNUNET_SERVER_client_disconnect (struct GNUNET_SERVER_Client *client)
1503{
1504 struct GNUNET_SERVER_Handle *server = client->server;
1505 struct NotifyList *n;
1506
1507 LOG (GNUNET_ERROR_TYPE_DEBUG,
1508 "Client is being disconnected from the server.\n");
1509 if (NULL != client->restart_task)
1510 {
1511 GNUNET_SCHEDULER_cancel (client->restart_task);
1512 client->restart_task = NULL;
1513 }
1514 if (NULL != client->warn_task)
1515 {
1516 GNUNET_SCHEDULER_cancel (client->warn_task);
1517 client->warn_task = NULL;
1518 }
1519 if (GNUNET_YES == client->receive_pending)
1520 {
1521 GNUNET_CONNECTION_receive_cancel (client->connection);
1522 client->receive_pending = GNUNET_NO;
1523 }
1524 client->shutdown_now = GNUNET_YES;
1525 client->reference_count++; /* make sure nobody else clean up client... */
1526 if ((NULL != client->mst) &&
1527 (NULL != server))
1528 {
1529 GNUNET_CONTAINER_DLL_remove (server->clients_head,
1530 server->clients_tail,
1531 client);
1532 if (NULL != server->mst_destroy)
1533 server->mst_destroy (server->mst_cls,
1534 client->mst);
1535 else
1536 GNUNET_SERVER_mst_destroy (client->mst);
1537 client->mst = NULL;
1538 for (n = server->disconnect_notify_list_head; NULL != n; n = n->next)
1539 n->callback (n->callback_cls,
1540 client);
1541 }
1542 client->reference_count--;
1543 if (client->reference_count > 0)
1544 {
1545 LOG (GNUNET_ERROR_TYPE_DEBUG,
1546 "RC of %p still positive, not destroying everything.\n",
1547 client);
1548 client->server = NULL;
1549 return;
1550 }
1551 if (GNUNET_YES == client->in_process_client_buffer)
1552 {
1553 LOG (GNUNET_ERROR_TYPE_DEBUG,
1554 "Still processing inputs of %p, not destroying everything.\n",
1555 client);
1556 return;
1557 }
1558 LOG (GNUNET_ERROR_TYPE_DEBUG,
1559 "RC of %p now zero, destroying everything.\n",
1560 client);
1561 if (GNUNET_YES == client->persist)
1562 GNUNET_CONNECTION_persist_ (client->connection);
1563 if (NULL != client->th.cth)
1564 GNUNET_SERVER_notify_transmit_ready_cancel (&client->th);
1565 GNUNET_CONNECTION_destroy (client->connection);
1566 /* need to cancel again, as it might have been re-added
1567 in the meantime (i.e. during callbacks) */
1568 if (NULL != client->warn_task)
1569 {
1570 GNUNET_SCHEDULER_cancel (client->warn_task);
1571 client->warn_task = NULL;
1572 }
1573 if (GNUNET_YES == client->receive_pending)
1574 {
1575 GNUNET_CONNECTION_receive_cancel (client->connection);
1576 client->receive_pending = GNUNET_NO;
1577 }
1578 GNUNET_free (client);
1579 /* we might be in soft-shutdown, test if we're done */
1580 if (NULL != server)
1581 test_monitor_clients (server);
1582}
1583
1584
1585/**
1586 * Disable the "CORK" feature for communication with the given client,
1587 * forcing the OS to immediately flush the buffer on transmission
1588 * instead of potentially buffering multiple messages.
1589 *
1590 * @param client handle to the client
1591 * @return #GNUNET_OK on success
1592 */
1593int
1594GNUNET_SERVER_client_disable_corking (struct GNUNET_SERVER_Client *client)
1595{
1596 return GNUNET_CONNECTION_disable_corking (client->connection);
1597}
1598
1599
1600/**
1601 * Wrapper for transmission notification that calls the original
1602 * callback and update the last activity time for our connection.
1603 *
1604 * @param cls the `struct GNUNET_SERVER_Client *`
1605 * @param size number of bytes we can transmit
1606 * @param buf where to copy the message
1607 * @return number of bytes actually transmitted
1608 */
1609static size_t
1610transmit_ready_callback_wrapper (void *cls, size_t size, void *buf)
1611{
1612 struct GNUNET_SERVER_Client *client = cls;
1613 GNUNET_CONNECTION_TransmitReadyNotify callback;
1614
1615 client->th.cth = NULL;
1616 callback = client->th.callback;
1617 client->th.callback = NULL;
1618 client->last_activity = GNUNET_TIME_absolute_get ();
1619 return callback (client->th.callback_cls, size, buf);
1620}
1621
1622
1623/**
1624 * Notify us when the server has enough space to transmit
1625 * a message of the given size to the given client.
1626 *
1627 * @param client client to transmit message to
1628 * @param size requested amount of buffer space
1629 * @param timeout after how long should we give up (and call
1630 * notify with buf NULL and size 0)?
1631 * @param callback function to call when space is available
1632 * @param callback_cls closure for @a callback
1633 * @return non-NULL if the notify callback was queued; can be used
1634 * to cancel the request using
1635 * #GNUNET_SERVER_notify_transmit_ready_cancel().
1636 * NULL if we are already going to notify someone else (busy)
1637 */
1638struct GNUNET_SERVER_TransmitHandle *
1639GNUNET_SERVER_notify_transmit_ready (struct GNUNET_SERVER_Client *client,
1640 size_t size,
1641 struct GNUNET_TIME_Relative timeout,
1642 GNUNET_CONNECTION_TransmitReadyNotify
1643 callback,
1644 void *callback_cls)
1645{
1646 if (NULL != client->th.callback)
1647 return NULL;
1648 client->th.callback_cls = callback_cls;
1649 client->th.callback = callback;
1650 client->th.cth = GNUNET_CONNECTION_notify_transmit_ready (client->connection,
1651 size,
1652 timeout,
1653 &
1654 transmit_ready_callback_wrapper,
1655 client);
1656 return &client->th;
1657}
1658
1659
1660/**
1661 * Abort transmission request.
1662 *
1663 * @param th request to abort
1664 */
1665void
1666GNUNET_SERVER_notify_transmit_ready_cancel (struct
1667 GNUNET_SERVER_TransmitHandle *th)
1668{
1669 GNUNET_CONNECTION_notify_transmit_ready_cancel (th->cth);
1670 th->cth = NULL;
1671 th->callback = NULL;
1672}
1673
1674
1675/**
1676 * Set the persistent flag on this client, used to setup client connection
1677 * to only be killed when the service it's connected to is actually dead.
1678 *
1679 * @param client the client to set the persistent flag on
1680 */
1681void
1682GNUNET_SERVER_client_persist_ (struct GNUNET_SERVER_Client *client)
1683{
1684 client->persist = GNUNET_YES;
1685}
1686
1687
1688/**
1689 * Resume receiving from this client, we are done processing the
1690 * current request. This function must be called from within each
1691 * GNUNET_SERVER_MessageCallback (or its respective continuations).
1692 *
1693 * @param client client we were processing a message of
1694 * @param success #GNUNET_OK to keep the connection open and
1695 * continue to receive
1696 * #GNUNET_NO to close the connection (normal behavior)
1697 * #GNUNET_SYSERR to close the connection (signal
1698 * serious error)
1699 */
1700void
1701GNUNET_SERVER_receive_done (struct GNUNET_SERVER_Client *client,
1702 int success)
1703{
1704 if (NULL == client)
1705 return;
1706 GNUNET_assert (client->suspended > 0);
1707 client->suspended--;
1708 if (GNUNET_OK != success)
1709 {
1710 LOG (GNUNET_ERROR_TYPE_DEBUG,
1711 "GNUNET_SERVER_receive_done called with failure indication\n");
1712 if ((client->reference_count > 0) || (client->suspended > 0))
1713 client->shutdown_now = GNUNET_YES;
1714 else
1715 GNUNET_SERVER_client_disconnect (client);
1716 return;
1717 }
1718 if (client->suspended > 0)
1719 {
1720 LOG (GNUNET_ERROR_TYPE_DEBUG,
1721 "GNUNET_SERVER_receive_done called, but more clients pending\n");
1722 return;
1723 }
1724 if (NULL != client->warn_task)
1725 {
1726 GNUNET_SCHEDULER_cancel (client->warn_task);
1727 client->warn_task = NULL;
1728 }
1729 if (GNUNET_YES == client->in_process_client_buffer)
1730 {
1731 LOG (GNUNET_ERROR_TYPE_DEBUG,
1732 "GNUNET_SERVER_receive_done called while still in processing loop\n");
1733 return;
1734 }
1735 if ((NULL == client->server) || (GNUNET_YES == client->shutdown_now))
1736 {
1737 GNUNET_SERVER_client_disconnect (client);
1738 return;
1739 }
1740 LOG (GNUNET_ERROR_TYPE_DEBUG,
1741 "GNUNET_SERVER_receive_done causes restart in reading from the socket\n");
1742 GNUNET_assert (NULL == client->restart_task);
1743 client->restart_task = GNUNET_SCHEDULER_add_now (&restart_processing,
1744 client);
1745}
1746
1747
1748/* 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/template_cfg_peer1.conf b/src/transport/template_cfg_peer1.conf
deleted file mode 100644
index 5ba198450..000000000
--- a/src/transport/template_cfg_peer1.conf
+++ /dev/null
@@ -1,50 +0,0 @@
1@INLINE@ test_transport_defaults.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
4GNUNET_RUNTIME_DIR = $GNUNET_TEST_HOME/runtime/
5GNUNET_USER_RUNTIME_DIR = $GNUNET_TEST_HOME/runtime/
6
7[nat]
8RETURN_LOCAL_ADDRESSES = YES
9DISABLEV6 = NO
10
11[transport-tcp]
12PORT = 12000
13TIMEOUT = 5 s
14
15[transport-udp]
16BROADCAST = NO
17
18[transport-unix]
19PORT = 12007
20
21[arm]
22PORT = 12005
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
24
25[statistics]
26PORT = 12004
27UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
28
29[resolver]
30PORT = 12003
31UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
32
33[peerinfo]
34PORT = 12002
35UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
36USE_INCLUDED_HELLOS = NO
37
38[transport]
39#PREFIX = valgrind --leak-check=full
40PORT = 12001
41UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
42
43[ats]
44WAN_QUOTA_IN = unlimited
45WAN_QUOTA_OUT = unlimited
46PORT = 12006
47UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-ats.sock
48
49[hostlist]
50SERVERS = dummy
diff --git a/src/transport/template_cfg_peer2.conf b/src/transport/template_cfg_peer2.conf
deleted file mode 100644
index 6ac610fec..000000000
--- a/src/transport/template_cfg_peer2.conf
+++ /dev/null
@@ -1,58 +0,0 @@
1@INLINE@ test_transport_defaults.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
4GNUNET_RUNTIME_DIR = $GNUNET_TEST_HOME/runtime/
5GNUNET_USER_RUNTIME_DIR = $GNUNET_TEST_HOME/runtime/
6
7[nat]
8RETURN_LOCAL_ADDRESSES = YES
9DISABLEV6 = NO
10
11[transport-tcp]
12PORT = 12100
13TIMEOUT = 5 s
14
15[transport-udp]
16BROADCAST = NO
17
18[transport-unix]
19PORT = 12017
20
21[transport-http_server]
22PORT = 12018
23USE_IPv6 = YES
24
25[transport-https_server]
26PORT = 12019
27KEY_FILE = $GNUNET_TEST_HOME/https_key_p1.key
28CERT_FILE = $GNUNET_TEST_HOME/https_cert_p1.crt
29USE_IPv6 = YES
30
31[arm]
32PORT = 12014
33UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
34
35[statistics]
36PORT = 12013
37UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
38
39[resolver]
40PORT = 12012
41UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
42
43[peerinfo]
44PORT = 12011
45UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
46USE_INCLUDED_HELLOS = NO
47
48[transport]
49#PREFIX = valgrind --leak-check=full
50PORT = 12010
51UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
52
53[ats]
54PORT = 12016
55UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-ats.sock
56
57[hostlist]
58SERVERS = dummy
diff --git a/src/transport/test_communicator_basic.c b/src/transport/test_communicator_basic.c
deleted file mode 100644
index f43cdaaf3..000000000
--- a/src/transport/test_communicator_basic.c
+++ /dev/null
@@ -1,1203 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2019 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_communicator_basic.c
23* @brief test the communicators
24* @author Julius Bünger
25* @author Martin Schanzenbach
26*/
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "transport-testing-communicator.h"
30#include "gnunet_ats_transport_service.h"
31#include "gnunet_signatures.h"
32#include "gnunet_testing_lib.h"
33#include "transport.h"
34#include "gnunet_statistics_service.h"
35
36#include <inttypes.h>
37
38
39#define LOG(kind, ...) GNUNET_log_from (kind, \
40 "test_transport_communicator", \
41 __VA_ARGS__)
42
43#define NUM_PEERS 2
44
45static struct GNUNET_SCHEDULER_Task *to_task[NUM_PEERS];
46
47static int queue_est = GNUNET_NO;
48
49static struct GNUNET_PeerIdentity peer_id[NUM_PEERS];
50
51static char *communicator_binary;
52
53static struct
54GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_hs[NUM_PEERS];
55
56static struct GNUNET_CONFIGURATION_Handle *cfg_peers[NUM_PEERS];
57
58static struct GNUNET_STATISTICS_Handle *stats[NUM_PEERS];
59
60static char *cfg_peers_name[NUM_PEERS];
61
62static int finished[NUM_PEERS];
63
64static int ret;
65
66static int bidirect = GNUNET_NO;
67
68static size_t long_message_size;
69
70static struct GNUNET_TIME_Absolute start_short[NUM_PEERS];
71
72static struct GNUNET_TIME_Absolute start_long[NUM_PEERS];
73
74static struct GNUNET_TIME_Absolute timeout[NUM_PEERS];
75
76// static struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *my_tc;
77
78static char *communicator_name;
79
80static char *test_name;
81
82static struct GNUNET_STATISTICS_GetHandle *box_stats[NUM_PEERS];
83
84static struct GNUNET_STATISTICS_GetHandle *rekey_stats[NUM_PEERS];
85
86#define TEST_SECTION "test-setup"
87
88#define SHORT_MESSAGE_SIZE 128
89
90#define LONG_MESSAGE_SIZE 32000 /* FIXME */
91
92#define ALLOWED_PACKET_LOSS 91
93
94#define BURST_PACKETS 5000
95
96#define TOTAL_ITERATIONS 1
97
98#define PEER_A 0
99
100#define PEER_B 1
101
102static unsigned int iterations_left[NUM_PEERS];
103
104#define TIMEOUT_MULTIPLIER 1
105
106#define DELAY \
107 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MICROSECONDS,200)
108
109#define SHORT_BURST_WINDOW \
110 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,2)
111
112#define LONG_BURST_WINDOW \
113 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,2)
114
115enum TestPhase
116{
117 TP_INIT,
118 TP_BURST_SHORT,
119 TP_BURST_LONG,
120 TP_SIZE_CHECK
121};
122
123static unsigned int phase_short[NUM_PEERS];
124
125static unsigned int phase_long[NUM_PEERS];
126
127static unsigned int phase_size[NUM_PEERS];
128
129static long long unsigned int allowed_packet_loss_short;
130
131static long long unsigned int allowed_packet_loss_long;
132
133static long long unsigned int burst_packets_short;
134
135static long long unsigned int burst_packets_long;
136
137static long long unsigned int delay_long_value;
138
139static long long unsigned int delay_short_value;
140
141static struct GNUNET_TIME_Relative delay_short;
142
143static struct GNUNET_TIME_Relative delay_long;
144
145static size_t num_sent_short[NUM_PEERS];
146
147static size_t num_sent_long[NUM_PEERS];
148
149static size_t num_sent_size[NUM_PEERS];
150
151static uint32_t ack[NUM_PEERS];
152
153static enum TestPhase phase[NUM_PEERS];
154
155static size_t num_received_short[NUM_PEERS];
156
157static size_t num_received_long[NUM_PEERS];
158
159static size_t num_received_size[NUM_PEERS];
160
161static uint64_t avg_latency[NUM_PEERS];
162
163static void
164communicator_available_cb (
165 void *cls,
166 struct
167 GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h,
168 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc,
169 char *address_prefix)
170{
171 LOG (GNUNET_ERROR_TYPE_INFO,
172 "Communicator available. (cc: %u, prefix: %s)\n",
173 cc,
174 address_prefix);
175}
176
177
178static void
179open_queue (void *cls)
180{
181 const char *address = cls;
182
183 if (NULL != tc_hs[PEER_A]->c_mq)
184 {
185 queue_est = GNUNET_YES;
186 GNUNET_TRANSPORT_TESTING_transport_communicator_open_queue (tc_hs[PEER_A],
187 &peer_id[PEER_B],
188 address);
189 }
190 else
191 {
192 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
193 &open_queue,
194 (void *) address);
195 }
196}
197
198
199static void
200add_address_cb (
201 void *cls,
202 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h,
203 const char *address,
204 struct GNUNET_TIME_Relative expiration,
205 uint32_t aid,
206 enum GNUNET_NetworkType nt)
207{
208 LOG (GNUNET_ERROR_TYPE_DEBUG,
209 "New address. (addr: %s, expir: %s, ID: %" PRIu32 ", nt: %u\n",
210 address,
211 GNUNET_STRINGS_relative_time_to_string (expiration,
212 GNUNET_NO),
213 aid,
214 (int) nt);
215 // addresses[1] = GNUNET_strdup (address);
216 if ((0 == strcmp ((char*) cls, cfg_peers_name[PEER_B])) &&
217 (GNUNET_NO == queue_est))
218 {
219 open_queue ((void *) address);
220 }
221}
222
223
224/**
225 * @brief Callback that informs whether the requested queue will be
226 * established
227 *
228 * Implements #GNUNET_TRANSPORT_TESTING_QueueCreateReplyCallback.
229 *
230 * @param cls Closure - unused
231 * @param tc_h Communicator handle - unused
232 * @param will_try #GNUNET_YES if queue will be established
233 * #GNUNET_NO if queue will not be established (bogous address)
234 */
235static void
236queue_create_reply_cb (
237 void *cls,
238 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h,
239 int will_try)
240{
241 (void) cls;
242 (void) tc_h;
243 if (GNUNET_YES == will_try)
244 LOG (GNUNET_ERROR_TYPE_DEBUG,
245 "Queue will be established!\n");
246 else
247 LOG (GNUNET_ERROR_TYPE_WARNING,
248 "Queue won't be established (bougus address?)!\n");
249}
250
251
252static struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *
253handle_backchannel_cb (void *cls,
254 struct GNUNET_MessageHeader *msg,
255 struct GNUNET_PeerIdentity *pid)
256{
257 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = cls;
258
259 (void) tc_h;
260 (void) msg;
261 LOG (GNUNET_ERROR_TYPE_DEBUG, "Handling BC message...\n");
262 if (0 == memcmp (&peer_id[PEER_A], pid, sizeof (*pid)))
263 return tc_hs[PEER_A];
264 else
265 return tc_hs[PEER_B];
266}
267
268
269static char*
270make_payload (size_t payload_size)
271{
272 struct GNUNET_TIME_Absolute ts;
273 struct GNUNET_TIME_AbsoluteNBO ts_n;
274 char *payload = GNUNET_malloc (payload_size);
275
276 LOG (GNUNET_ERROR_TYPE_DEBUG,
277 "Making payload of size %lu\n", payload_size);
278 GNUNET_assert (payload_size >= 8); // So that out timestamp fits
279 ts = GNUNET_TIME_absolute_get ();
280 ts_n = GNUNET_TIME_absolute_hton (ts);
281 memset (payload, 'a', payload_size);
282 memcpy (payload, &ts_n, sizeof (struct GNUNET_TIME_AbsoluteNBO));
283 return payload;
284}
285
286static struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *
287get_tc_h (unsigned int peer_nr)
288{
289 LOG (GNUNET_ERROR_TYPE_DEBUG,
290 "Got peer %u\n",
291 peer_nr);
292
293 LOG (GNUNET_ERROR_TYPE_DEBUG,
294 "Handle %p peer 0\n",
295 tc_hs[0]);
296
297 LOG (GNUNET_ERROR_TYPE_DEBUG,
298 "Handle %p peer 1\n",
299 tc_hs[1]);
300
301 LOG (GNUNET_ERROR_TYPE_DEBUG,
302 "Handle %p get\n",
303 tc_hs[peer_nr]);
304
305 return tc_hs[peer_nr];
306}
307
308
309static unsigned int
310get_peer_nr_from_tc (struct
311 GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h)
312{
313 if (tc_h == get_tc_h (0))
314 return PEER_A;
315 else
316 return PEER_B;
317}
318
319static unsigned int
320get_peer_nr (void *cls, unsigned int get_the_other_one)
321{
322 if (0 == strcmp ((char*) cls, cfg_peers_name[0]))
323 return get_the_other_one ? PEER_B : PEER_A;
324 else
325 return get_the_other_one ? PEER_A : PEER_B;
326}
327
328static void
329process_statistics_box_done (void *cls, int success)
330{
331 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = cls;
332 unsigned int peer_nr;
333
334 peer_nr = get_peer_nr_from_tc (tc_h);
335
336 if (NULL != box_stats[peer_nr])
337 box_stats[peer_nr] = NULL;
338 if (NULL == rekey_stats[peer_nr])
339 {
340 LOG (GNUNET_ERROR_TYPE_DEBUG,
341 "Finished\n");
342 GNUNET_SCHEDULER_shutdown ();
343 }
344}
345
346
347static void
348process_statistics_rekey_done (void *cls, int success)
349{
350 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = cls;
351 unsigned int peer_nr;
352
353 peer_nr = get_peer_nr_from_tc (tc_h);
354
355 if (NULL != rekey_stats[peer_nr])
356 rekey_stats[peer_nr] = NULL;
357 if (NULL == box_stats[peer_nr])
358 {
359 LOG (GNUNET_ERROR_TYPE_DEBUG,
360 "Finished\n");
361 GNUNET_SCHEDULER_shutdown ();
362 }
363}
364
365static int
366process_statistics (void *cls,
367 const char *subsystem,
368 const char *name,
369 uint64_t value,
370 int is_persistent)
371{
372 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
373 "Statistic: Name %s and value %lu\n",
374 name,
375 value);
376 if ((0 == strcmp ("rekey", test_name)) && (0 == strcmp (
377 "# rekeying successful",
378 name)) && (0 == value))
379 {
380 ret = 2;
381 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
382 "No successful rekeying!\n");
383 GNUNET_SCHEDULER_shutdown ();
384 }
385 if ((0 == strcmp ("backchannel", test_name)) &&
386 (0 == strcmp (
387 "# messages decrypted with BOX",
388 name))
389 && (9000 > value))
390 {
391 ret = 2;
392 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
393 "Not enough BOX messages!\n");
394 GNUNET_SCHEDULER_shutdown ();
395 }
396 if ((0 == strcmp ("rekey", test_name)) &&
397 (0 == strcmp (
398 "# messages decrypted with BOX",
399 name))
400 && (6000 > value))
401 {
402 ret = 2;
403 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
404 "Not enough BOX messages!\n");
405 GNUNET_SCHEDULER_shutdown ();
406 }
407 return GNUNET_OK;
408}
409
410static void
411short_test (void *cls);
412
413static void
414short_test_cb (void *cls)
415{
416 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = cls;
417 unsigned int peer_nr;
418 char *payload;
419
420 peer_nr = get_peer_nr_from_tc (tc_h);
421
422 LOG (GNUNET_ERROR_TYPE_DEBUG,
423 "short_test_cb %u/%u for peer %u and handle %p\n",
424 (unsigned int) num_sent_short[peer_nr],
425 (unsigned int) num_received_short[peer_nr],
426 peer_nr,
427 tc_h);
428 payload = make_payload (SHORT_MESSAGE_SIZE);
429 num_sent_short[peer_nr]++;
430 GNUNET_TRANSPORT_TESTING_transport_communicator_send (tc_h,
431 (burst_packets_short ==
432 num_sent_short[peer_nr])
433 ? NULL
434 : &short_test,
435 cls,
436 payload,
437 SHORT_MESSAGE_SIZE);
438 GNUNET_free (payload);
439 timeout[peer_nr] = GNUNET_TIME_relative_to_absolute (
440 GNUNET_TIME_relative_multiply (
441 GNUNET_TIME_UNIT_SECONDS,
442 TIMEOUT_MULTIPLIER));
443}
444
445static void
446short_test (void *cls)
447{
448 GNUNET_SCHEDULER_add_delayed (delay_short,
449 &short_test_cb,
450 cls);
451}
452
453static void
454size_test (void *cls)
455{
456 unsigned int peer_nr;
457 char *payload;
458 size_t max_size = 64000;
459 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = cls;
460
461 peer_nr = get_peer_nr_from_tc (tc_h);
462 LOG (GNUNET_ERROR_TYPE_DEBUG,
463 "size_test_cb %u\n",
464 (unsigned int) num_sent_size[peer_nr]);
465 GNUNET_assert (TP_SIZE_CHECK == phase[peer_nr]);
466 if (LONG_MESSAGE_SIZE != long_message_size)
467 max_size = long_message_size;
468 if (ack[peer_nr] + 10 > max_size)
469 return; /* Leave some room for our protocol, so not 2^16 exactly */
470 ack[peer_nr] += 10;
471 payload = make_payload (ack[peer_nr]);
472 num_sent_size[peer_nr]++;
473 GNUNET_TRANSPORT_TESTING_transport_communicator_send (tc_h,
474 (ack[peer_nr] <
475 max_size)
476 ? &size_test
477 : NULL,
478 cls,
479 payload,
480 ack[peer_nr]);
481 GNUNET_free (payload);
482 timeout[peer_nr] = GNUNET_TIME_relative_to_absolute (
483 GNUNET_TIME_relative_multiply (
484 GNUNET_TIME_UNIT_SECONDS,
485 TIMEOUT_MULTIPLIER));
486}
487
488static void
489long_test (void *cls);
490
491static void
492long_test_cb (void *cls)
493{
494 unsigned int peer_nr;
495 char *payload;
496 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = cls;
497
498 peer_nr = get_peer_nr_from_tc (tc_h);
499
500 LOG (GNUNET_ERROR_TYPE_DEBUG,
501 "long_test_cb %u/%u\n",
502 (unsigned int) num_sent_long[peer_nr],
503 (unsigned int) num_received_long[peer_nr]);
504 payload = make_payload (long_message_size);
505 num_sent_long[peer_nr]++;
506 GNUNET_TRANSPORT_TESTING_transport_communicator_send (tc_h,
507 (burst_packets_long ==
508 num_sent_long[peer_nr])
509 ? NULL
510 : &long_test,
511 cls,
512 payload,
513 long_message_size);
514 GNUNET_free (payload);
515 timeout[peer_nr] = GNUNET_TIME_relative_to_absolute (
516 GNUNET_TIME_relative_multiply (
517 GNUNET_TIME_UNIT_SECONDS,
518 TIMEOUT_MULTIPLIER));
519}
520
521
522static void
523long_test (void *cls)
524{
525 GNUNET_SCHEDULER_add_delayed (delay_long,
526 &long_test_cb,
527 cls);
528}
529
530static void
531choose_phase (struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h)
532{
533 unsigned int peer_nr;
534
535 peer_nr = get_peer_nr_from_tc (tc_h);
536
537 if (GNUNET_YES == phase_short[peer_nr])
538 {
539 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
540 "Choose phase short with peer %u and Handle %p\n",
541 peer_nr,
542 tc_h);
543 phase[peer_nr] = TP_BURST_SHORT;
544 start_short[peer_nr] = GNUNET_TIME_absolute_get ();
545 short_test (tc_h);
546 }
547 else if (GNUNET_YES == phase_long[peer_nr])
548 {
549 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
550 "Choose phase long with peer %u\n",
551 peer_nr);
552 phase[peer_nr] = TP_BURST_LONG;
553 start_long[peer_nr] = GNUNET_TIME_absolute_get ();
554 long_test (tc_h);
555 }
556 else if (GNUNET_YES == phase_size[peer_nr])
557 {
558 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
559 "Choose phase size\n");
560 phase[peer_nr] = TP_SIZE_CHECK;
561 size_test (tc_h);
562 }
563 else
564 {
565 if ((0 == strcmp ("udp", communicator_name)) && ((0 == strcmp ("rekey",
566 test_name))
567 ||(0 == strcmp (
568 "backchannel",
569 test_name))) )
570 {
571 if (NULL != box_stats[peer_nr])
572 GNUNET_STATISTICS_get_cancel (box_stats[peer_nr]);
573 box_stats[peer_nr] = GNUNET_STATISTICS_get (stats[1],
574 "C-UDP",
575 "# messages decrypted with BOX",
576 process_statistics_box_done,
577 &process_statistics,
578 tc_h);
579 if (NULL != rekey_stats[peer_nr])
580 GNUNET_STATISTICS_get_cancel (rekey_stats[peer_nr]);
581 rekey_stats[peer_nr] = GNUNET_STATISTICS_get (stats[0],
582 "C-UDP",
583 "# rekeying successful",
584 process_statistics_rekey_done,
585 &process_statistics,
586 tc_h);
587 }
588 else
589 {
590 if ((GNUNET_NO == bidirect)|| (((PEER_A == peer_nr) &&
591 finished[PEER_B]) || ((PEER_B ==
592 peer_nr) &&
593 finished
594 [PEER_A])))
595 {
596 LOG (GNUNET_ERROR_TYPE_DEBUG,
597 "Finished\n");
598 GNUNET_SCHEDULER_shutdown ();
599 }
600 finished[peer_nr] = GNUNET_YES;
601 }
602 }
603}
604
605static void finish_phase_long (unsigned int peer_nr)
606{
607 static struct GNUNET_TIME_Relative duration;
608
609 duration = GNUNET_TIME_absolute_get_duration (start_long[peer_nr]);
610 LOG (GNUNET_ERROR_TYPE_MESSAGE,
611 "Long size packet test for peer %u done.\n",
612 peer_nr);
613 char *goodput = GNUNET_STRINGS_byte_size_fancy (
614 (long_message_size * num_received_long[peer_nr] * 1000 * 1000)
615 / duration.
616 rel_value_us);
617
618 LOG (GNUNET_ERROR_TYPE_MESSAGE,
619 "%lu/%lu packets in %llu us (%s/s) -- avg latency: %llu us\n",
620 (unsigned long) num_received_long[peer_nr],
621 (unsigned long) num_sent_long[peer_nr],
622 (unsigned long long) duration.rel_value_us,
623 goodput,
624 (unsigned long long) avg_latency[peer_nr]);
625 GNUNET_free (goodput);
626 ack[peer_nr] = 0;
627 // phase = TP_SIZE_CHECK;
628 // num_received = 0;
629 // num_sent_long = 0;
630 avg_latency[peer_nr] = 0;
631 // size_test (NULL);
632 phase_long[peer_nr] = GNUNET_NO;
633 choose_phase (get_tc_h (peer_nr));
634}
635
636static void
637finish_phase_short (unsigned int peer_nr)
638{
639 static struct GNUNET_TIME_Relative duration;
640
641 duration = GNUNET_TIME_absolute_get_duration (start_short[peer_nr]);
642 LOG (GNUNET_ERROR_TYPE_MESSAGE,
643 "Short size packet test for peer %u done.\n",
644 peer_nr);
645 char *goodput = GNUNET_STRINGS_byte_size_fancy (
646 (SHORT_MESSAGE_SIZE * num_received_short[peer_nr] * 1000 * 1000)
647 / duration.rel_value_us);
648 LOG (GNUNET_ERROR_TYPE_MESSAGE,
649 "%lu/%lu packets in %llu us (%s/s) -- avg latency: %llu us\n",
650 (unsigned long) num_received_short[peer_nr],
651 (unsigned long) num_sent_short[peer_nr],
652 (unsigned long long) duration.rel_value_us,
653 goodput,
654 (unsigned long long) avg_latency[peer_nr]);
655 GNUNET_free (goodput);
656 // start_long = GNUNET_TIME_absolute_get ();
657 // phase = TP_BURST_LONG;
658 // num_sent_short = 0;
659 avg_latency[peer_nr] = 0;
660 // num_received = 0;
661 phase_short[peer_nr] = GNUNET_NO;
662 choose_phase (get_tc_h (peer_nr));
663 // long_test (NULL);
664}
665
666static void
667latency_timeout (void *cls)
668{
669
670 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = cls;
671 unsigned int peer_nr;
672 size_t num_sent = 0;
673 size_t num_received = 0;
674
675 peer_nr = get_peer_nr_from_tc (tc_h);
676 to_task[peer_nr] = NULL;
677
678 switch (phase[peer_nr])
679 {
680 case TP_INIT:
681 GNUNET_assert (0);
682 break;
683 case TP_BURST_SHORT:
684 num_sent = num_sent_short[peer_nr];
685 num_received = num_received_short[peer_nr];
686 if ((num_sent_short[peer_nr] == burst_packets_short) &&
687 (num_received_short[peer_nr] >
688 burst_packets_short
689 / 100
690 *
691 allowed_packet_loss_short) )
692 {
693 finish_phase_short (peer_nr);
694 to_task[peer_nr] = GNUNET_SCHEDULER_add_at (timeout[peer_nr],
695 &latency_timeout,
696 cls);
697 return;
698 }
699 break;
700 case TP_BURST_LONG:
701 num_sent = num_sent_long[peer_nr];
702 num_received = num_received_long[peer_nr];
703 if ((num_sent_long[peer_nr] == burst_packets_long) &&
704 (num_received_long[peer_nr] >
705 burst_packets_long
706 / 100
707 *
708 allowed_packet_loss_long) )
709 {
710 finish_phase_long (peer_nr);
711 to_task[peer_nr] = GNUNET_SCHEDULER_add_at (timeout[peer_nr],
712 &latency_timeout,
713 cls);
714 return;
715 }
716 break;
717 case TP_SIZE_CHECK:
718 num_sent = num_sent_size[peer_nr];
719 num_received = num_received_size[peer_nr];
720 break;
721 }
722 if (GNUNET_TIME_absolute_get_remaining (timeout[peer_nr]).rel_value_us > 0)
723 {
724 to_task[peer_nr] = GNUNET_SCHEDULER_add_at (timeout[peer_nr],
725 &latency_timeout,
726 cls);
727 return;
728 }
729 LOG (GNUNET_ERROR_TYPE_ERROR,
730 "Latency too high. Test failed. (Phase: %d. Sent: %lu, Received: %lu)\n",
731 phase[peer_nr], num_sent, num_received);
732 ret = 2;
733 GNUNET_SCHEDULER_shutdown ();
734}
735
736/**
737 * @brief Handle opening of queue
738 *
739 * Issues sending of test data
740 *
741 * Implements #GNUNET_TRANSPORT_TESTING_AddQueueCallback
742 *
743 * @param cls Closure
744 * @param tc_h Communicator handle
745 * @param tc_queue Handle to newly opened queue
746 */
747static void
748add_queue_cb (void *cls,
749 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h,
750 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *
751 tc_queue,
752 size_t mtu)
753{
754
755 unsigned int peer_nr;
756
757 peer_nr = get_peer_nr (cls, GNUNET_NO);
758 LOG (GNUNET_ERROR_TYPE_DEBUG,
759 "Handle %p add %u %u\n",
760 tc_h,
761 peer_nr,
762 get_peer_nr_from_tc (tc_h));
763 if ((GNUNET_NO == bidirect)&&(0 != strcmp ((char*) cls, cfg_peers_name[0])))
764 {
765 LOG (GNUNET_ERROR_TYPE_DEBUG,
766 "Queue available at receiving peer\n");
767 return; // TODO?
768 }
769 else if (TP_INIT != phase[peer_nr])
770 return;
771 LOG (GNUNET_ERROR_TYPE_DEBUG,
772 "Queue established, starting test...\n");
773 if (UINT32_MAX != mtu) /* Message header overhead */
774 long_message_size = mtu - sizeof(struct GNUNET_TRANSPORT_SendMessageTo)
775 - sizeof(struct GNUNET_MessageHeader);
776 else
777 long_message_size = LONG_MESSAGE_SIZE;
778 timeout[peer_nr] = GNUNET_TIME_relative_to_absolute (
779 GNUNET_TIME_relative_multiply (
780 GNUNET_TIME_UNIT_SECONDS,
781 TIMEOUT_MULTIPLIER));
782 GNUNET_assert (NULL == to_task[peer_nr]);
783 to_task[peer_nr] = GNUNET_SCHEDULER_add_delayed (
784 GNUNET_TIME_relative_multiply (
785 GNUNET_TIME_UNIT_SECONDS,
786 TIMEOUT_MULTIPLIER),
787 &latency_timeout,
788 tc_h);
789 choose_phase (tc_h);
790}
791
792
793static void
794update_avg_latency (const char *payload, unsigned int peer_nr)
795{
796 struct GNUNET_TIME_AbsoluteNBO *ts_n;
797 struct GNUNET_TIME_Absolute ts;
798 struct GNUNET_TIME_Relative latency;
799 size_t num_received = 0;
800
801 ts_n = (struct GNUNET_TIME_AbsoluteNBO *) payload;
802 ts = GNUNET_TIME_absolute_ntoh (*ts_n);
803 latency = GNUNET_TIME_absolute_get_duration (ts);
804
805 switch (phase[peer_nr])
806 {
807 case TP_INIT:
808 GNUNET_assert (0);
809 break;
810 case TP_BURST_SHORT:
811 num_received = num_received_short[peer_nr];
812 break;
813 case TP_BURST_LONG:
814 num_received = num_received_long[peer_nr];
815 break;
816 case TP_SIZE_CHECK:
817 num_received = num_received_size[peer_nr];
818 break;
819 }
820 if (1 >= num_received)
821 avg_latency[peer_nr] = latency.rel_value_us;
822 else
823 avg_latency[peer_nr] = ((avg_latency[peer_nr] * (num_received - 1))
824 + latency.rel_value_us)
825 / num_received;
826 LOG (GNUNET_ERROR_TYPE_DEBUG,
827 "Latency of received packet by peer %u: %s with avg latency %lu\n",
828 peer_nr,
829 GNUNET_STRINGS_relative_time_to_string (latency,
830 GNUNET_YES),
831 avg_latency[peer_nr]);
832}
833
834
835
836
837static void
838load_phase_config ()
839{
840
841 phase_short[0] = GNUNET_CONFIGURATION_get_value_yesno (cfg_peers[0],
842 TEST_SECTION,
843 "PHASE_SHORT");
844 if (GNUNET_SYSERR == phase_short[0])
845 phase_short[0] = GNUNET_YES;
846
847 phase_short[1] = phase_short[0];
848
849 phase_long[0] = GNUNET_CONFIGURATION_get_value_yesno (cfg_peers[0],
850 TEST_SECTION,
851 "PHASE_LONG");
852
853 if (GNUNET_SYSERR == phase_long[0])
854 phase_long[0] = GNUNET_YES;
855
856 phase_long[1] = phase_long[0];
857
858 phase_size[0] = GNUNET_CONFIGURATION_get_value_yesno (cfg_peers[0],
859 TEST_SECTION,
860 "PHASE_SIZE");
861
862 if (GNUNET_SYSERR == phase_size[0])
863 phase_size[0] = GNUNET_YES;
864
865 phase_size[1] = phase_size[0];
866}
867
868
869
870/**
871 * @brief Handle an incoming message
872 *
873 * Implements #GNUNET_TRANSPORT_TESTING_IncomingMessageCallback
874
875 * @param cls Closure
876 * @param tc_h Handle to the receiving communicator
877 * @param msg Received message
878 */
879static void
880incoming_message_cb (
881 void *cls,
882 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h,
883 const char *payload,
884 size_t payload_len)
885{
886 unsigned int peer_nr;
887
888
889 peer_nr = get_peer_nr (cls, GNUNET_YES);
890
891 if ((GNUNET_NO == bidirect)&&(0 != strcmp ((char*) cls,
892 cfg_peers_name[NUM_PEERS - 1])))
893 {
894 LOG (GNUNET_ERROR_TYPE_WARNING,
895 "unexpected receiver...\n");
896 return;
897 }
898 /* Reset timeout */
899 timeout[peer_nr] = GNUNET_TIME_relative_to_absolute (
900 GNUNET_TIME_relative_multiply (
901 GNUNET_TIME_UNIT_SECONDS,
902 TIMEOUT_MULTIPLIER));
903 switch (phase[peer_nr])
904 {
905 case TP_INIT:
906 GNUNET_break (0);
907 break;
908 case TP_BURST_SHORT:
909 {
910 GNUNET_assert (SHORT_MESSAGE_SIZE == payload_len);
911 num_received_short[peer_nr]++;
912
913 update_avg_latency (payload, peer_nr);
914 if ((num_sent_short[peer_nr] == burst_packets_short) &&
915 (num_received_short[peer_nr] ==
916 burst_packets_short))
917 {
918 finish_phase_short (peer_nr);
919 }
920 break;
921 }
922 case TP_BURST_LONG:
923 {
924 if (long_message_size != payload_len)
925 {
926 LOG (GNUNET_ERROR_TYPE_WARNING,
927 "Ignoring packet with wrong length\n");
928 return; // Ignore
929 }
930 num_received_long[peer_nr]++;
931
932 update_avg_latency (payload, peer_nr);
933 if ((num_sent_long[peer_nr] == burst_packets_long) &&
934 (num_received_long[peer_nr] >
935 burst_packets_long))
936 {
937 finish_phase_long (peer_nr);
938 }
939 break;
940 }
941 case TP_SIZE_CHECK:
942 {
943 size_t max_size = 64000;
944
945 GNUNET_assert (TP_SIZE_CHECK == phase[peer_nr]);
946 if (LONG_MESSAGE_SIZE != long_message_size)
947 max_size = long_message_size;
948 num_received_size[peer_nr]++;
949 update_avg_latency (payload, peer_nr);
950 if ((GNUNET_YES == phase_size[peer_nr]) && (num_received_size[peer_nr] >=
951 (max_size) / 10) )
952 {
953 LOG (GNUNET_ERROR_TYPE_MESSAGE,
954 "Size packet test for peer %u done.\n",
955 peer_nr);
956 LOG (GNUNET_ERROR_TYPE_MESSAGE,
957 "%lu/%lu packets -- avg latency: %llu us\n",
958 (unsigned long) num_received_size[peer_nr],
959 (unsigned long) num_sent_size[peer_nr],
960 (unsigned long long) avg_latency[peer_nr]);
961 iterations_left[peer_nr]--;
962 phase_size[peer_nr] = GNUNET_NO;
963 if (0 != iterations_left[peer_nr])
964 {
965 // start_short = GNUNET_TIME_absolute_get ();
966 // phase = TP_BURST_SHORT;
967 num_received_size[peer_nr] = 0;
968 num_sent_size[peer_nr] = 0;
969 avg_latency[peer_nr] = 0;
970 num_sent_short[peer_nr] = 0;
971 num_sent_long[peer_nr] = 0;
972 num_received_short[peer_nr] = 0;
973 num_received_long[peer_nr] = 0;
974 // short_test (NULL);
975 if (((PEER_A == peer_nr) && finished[PEER_B]) || ((PEER_B ==
976 peer_nr) &&
977 finished[PEER_A]))
978 {
979 load_phase_config ();
980 }
981 }
982 choose_phase (get_tc_h (peer_nr));
983 }
984 break;
985 }
986 }
987}
988
989
990static void
991do_shutdown (void *cls)
992{
993 LOG (GNUNET_ERROR_TYPE_DEBUG,
994 "shutting down test.\n");
995
996 for (unsigned int i = 0; i < NUM_PEERS; i++)
997 {
998 if (NULL != box_stats[i])
999 {
1000 GNUNET_STATISTICS_get_cancel (box_stats[i]);
1001 box_stats[i] = NULL;
1002 }
1003 if (NULL != rekey_stats[i])
1004 {
1005 GNUNET_STATISTICS_get_cancel (rekey_stats[i]);
1006 rekey_stats[i] = NULL;
1007 }
1008 if (NULL != to_task[i])
1009 {
1010 GNUNET_SCHEDULER_cancel (to_task[i]);
1011 to_task[i] = NULL;
1012 }
1013 GNUNET_TRANSPORT_TESTING_transport_communicator_service_stop (tc_hs[i]);
1014 GNUNET_STATISTICS_destroy (stats[i], GNUNET_NO);
1015 }
1016}
1017
1018
1019
1020/**
1021 * @brief Main function called by the scheduler
1022 *
1023 * @param cls Closure - Handle to confiation
1024 */
1025static void
1026run (void *cls)
1027{
1028 ret = 0;
1029 // num_received = 0;
1030 // num_sent = 0;
1031 for (unsigned int i = 0; i < NUM_PEERS; i++)
1032 {
1033 tc_hs[i] = GNUNET_TRANSPORT_TESTING_transport_communicator_service_start (
1034 "transport",
1035 communicator_binary,
1036 cfg_peers_name[i],
1037 &peer_id[i],
1038 &communicator_available_cb,
1039 &add_address_cb,
1040 &queue_create_reply_cb,
1041 &add_queue_cb,
1042 &incoming_message_cb,
1043 &handle_backchannel_cb,
1044 cfg_peers_name[i]); /* cls */
1045
1046 if ((0 == strcmp ("udp", communicator_name)) && ((0 == strcmp ("rekey",
1047 test_name))||
1048 (0 == strcmp (
1049 "backchannel",
1050 test_name))) )
1051 {
1052 stats[i] = GNUNET_STATISTICS_create ("C-UDP",
1053 cfg_peers[i]);
1054 }
1055 else if ((0 == strcmp ("bidirect", test_name)))
1056 {
1057 bidirect = GNUNET_YES;
1058 }
1059 }
1060 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
1061 NULL);
1062}
1063
1064int
1065main (int argc,
1066 char *const *argv)
1067{
1068 struct GNUNET_CRYPTO_EddsaPrivateKey *private_key;
1069 char *test_mode;
1070 char *cfg_peer;
1071
1072 iterations_left[0] = TOTAL_ITERATIONS;
1073 iterations_left[1] = TOTAL_ITERATIONS;
1074 phase[0] = TP_INIT;
1075 phase[1] = TP_INIT;
1076 ret = 1;
1077 test_name = GNUNET_TESTING_get_testname_from_underscore (argv[0]);
1078 communicator_name = strchr (test_name, '-');
1079 communicator_name[0] = '\0';
1080 communicator_name++;
1081 test_mode = test_name;
1082
1083 GNUNET_asprintf (&communicator_binary,
1084 "gnunet-communicator-%s",
1085 communicator_name);
1086
1087 if (GNUNET_OK !=
1088 GNUNET_log_setup ("test_communicator_basic",
1089 "DEBUG",
1090 NULL))
1091 {
1092 fprintf (stderr, "Unable to setup log\n");
1093 GNUNET_break (0);
1094 return 2;
1095 }
1096 for (unsigned int i = 0; i < NUM_PEERS; i++)
1097 {
1098 GNUNET_asprintf ((&cfg_peer),
1099 "test_communicator_%s_%s_peer%u.conf",
1100 communicator_name, test_mode, i + 1);
1101 cfg_peers_name[i] = cfg_peer;
1102 cfg_peers[i] = GNUNET_CONFIGURATION_create ();
1103 if (GNUNET_YES ==
1104 GNUNET_DISK_file_test (cfg_peers_name[i]))
1105 {
1106 if (GNUNET_SYSERR ==
1107 GNUNET_CONFIGURATION_load (cfg_peers[i],
1108 cfg_peers_name[i]))
1109 {
1110 fprintf (stderr,
1111 "Malformed configuration file `%s', exiting ...\n",
1112 cfg_peers_name[i]);
1113 return 1;
1114 }
1115 }
1116 else
1117 {
1118 if (GNUNET_SYSERR ==
1119 GNUNET_CONFIGURATION_load (cfg_peers[i],
1120 NULL))
1121 {
1122 fprintf (stderr,
1123 "Configuration file %s does not exist, exiting ...\n",
1124 cfg_peers_name[i]);
1125 return 1;
1126 }
1127 }
1128 private_key =
1129 GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg_peers[i]);
1130 if (NULL == private_key)
1131 {
1132 LOG (GNUNET_ERROR_TYPE_ERROR,
1133 "Unable to get peer ID\n");
1134 return 1;
1135 }
1136 GNUNET_CRYPTO_eddsa_key_get_public (private_key,
1137 &peer_id[i].public_key);
1138 GNUNET_free (private_key);
1139 LOG (GNUNET_ERROR_TYPE_INFO,
1140 "Identity of peer %u is %s\n",
1141 i,
1142 GNUNET_i2s_full (&peer_id[i]));
1143 }
1144 if (GNUNET_OK !=
1145 GNUNET_CONFIGURATION_get_value_number (cfg_peers[0],
1146 TEST_SECTION,
1147 "ALLOWED_PACKET_LOSS_SHORT",
1148 &allowed_packet_loss_short))
1149 allowed_packet_loss_short = ALLOWED_PACKET_LOSS;
1150 if (GNUNET_OK !=
1151 GNUNET_CONFIGURATION_get_value_number (cfg_peers[0],
1152 TEST_SECTION,
1153 "ALLOWED_PACKET_LOSS_LONG",
1154 &allowed_packet_loss_long))
1155 allowed_packet_loss_long = ALLOWED_PACKET_LOSS;
1156 if (GNUNET_OK !=
1157 GNUNET_CONFIGURATION_get_value_number (cfg_peers[0],
1158 TEST_SECTION,
1159 "BURST_PACKETS_SHORT",
1160 &burst_packets_short))
1161 burst_packets_short = BURST_PACKETS;
1162 if (GNUNET_OK !=
1163 GNUNET_CONFIGURATION_get_value_number (cfg_peers[0],
1164 TEST_SECTION,
1165 "BURST_ÃœACKETS_LONG",
1166 &burst_packets_long))
1167 burst_packets_long = BURST_PACKETS;
1168 if (GNUNET_OK !=
1169 GNUNET_CONFIGURATION_get_value_number (cfg_peers[0],
1170 TEST_SECTION,
1171 "DELAY_SHORT",
1172 &delay_short_value))
1173 delay_short = DELAY;
1174 else
1175 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MICROSECONDS,
1176 delay_short_value);
1177 if (GNUNET_OK !=
1178 GNUNET_CONFIGURATION_get_value_number (cfg_peers[0],
1179 TEST_SECTION,
1180 "DELAY_SHORT",
1181 &delay_long_value))
1182 delay_long = DELAY;
1183 else
1184 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MICROSECONDS,
1185 delay_long_value);
1186 load_phase_config ();
1187 LOG (GNUNET_ERROR_TYPE_MESSAGE, "Starting test...\n");
1188 LOG (GNUNET_ERROR_TYPE_DEBUG,
1189 "argv[0]: %s\n",
1190 argv[0]);
1191 LOG (GNUNET_ERROR_TYPE_DEBUG,
1192 "test_name: %s\n",
1193 test_name);
1194 LOG (GNUNET_ERROR_TYPE_DEBUG,
1195 "communicator_name: %s\n",
1196 communicator_name);
1197 LOG (GNUNET_ERROR_TYPE_DEBUG,
1198 "communicator_binary: %s\n",
1199 communicator_binary);
1200 GNUNET_SCHEDULER_run (&run,
1201 NULL);
1202 return ret;
1203}
diff --git a/src/transport/test_communicator_tcp_basic_peer1.conf b/src/transport/test_communicator_tcp_basic_peer1.conf
deleted file mode 100644
index dbc227ac6..000000000
--- a/src/transport/test_communicator_tcp_basic_peer1.conf
+++ /dev/null
@@ -1,48 +0,0 @@
1@INLINE@ test_transport_defaults.conf
2
3[test-setup]
4#PHASE_LONG=NO
5#PHASE_SIZE=NO
6#BURST_PACKETS_SHORT=1
7
8[PATHS]
9GNUNET_TEST_HOME = $GNUNET_TMP/test-communicator-unix-1/
10
11[PEER]
12PRIVATE_KEY = $GNUNET_TMP/test-communicator-unix-1/private.key
13
14[transport-tcp]
15PORT = 52400
16
17[transport-udp]
18PORT = 52401
19
20[transport]
21PORT = 60000
22UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-transport_test_1.sock
23
24[nat]
25UNIXPATH = $GNUNET_TMP/test-communicator-unix-1/nat.sock
26
27[peerstore]
28UNIXPATH = $GNUNET_TMP/test-communicator-unix-1/peerstore.sock
29
30[statistics]
31PORT = 22461
32UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-statistics_test_1.sock
33
34[communicator-unix]
35UNIXPATH = $GNUNET_RUNTIME_DIR/test_gnunet-communicator-unix_1.sock
36
37[communicator-tcp]
38#PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args
39#PREFIX = valgrind --leak-check=full --track-origins=yes
40BINDTO = 60002
41DISABLE_V6 = YES
42
43[communicator-udp]
44BINDTO = 60002
45
46[resolver]
47PORT = 62089
48UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-resolver_test_1.sock
diff --git a/src/transport/test_communicator_tcp_basic_peer2.conf b/src/transport/test_communicator_tcp_basic_peer2.conf
deleted file mode 100644
index b73157f0d..000000000
--- a/src/transport/test_communicator_tcp_basic_peer2.conf
+++ /dev/null
@@ -1,44 +0,0 @@
1@INLINE@ test_transport_defaults.conf
2
3[PATHS]
4GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunetd-plugin-transport/
5
6[PEER]
7PRIVATE_KEY = $GNUNET_TMP/test-communicator-unix-2/private.key
8
9
10[transport-tcp]
11PORT = 52400
12
13[transport-udp]
14PORT = 52401
15
16[transport]
17PORT = 60001
18UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-transport_test_2.sock
19
20[nat]
21UNIXPATH = $GNUNET_TMP/test-communicator-unix-2/nat.sock
22
23[peerstore]
24UNIXPATH = $GNUNET_TMP/test-communicator-unix-2/peerstore.sock
25
26[statistics]
27PORT = 22462
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-statistics_test_2.sock
29
30[communicator-unix]
31UNIXPATH = $GNUNET_RUNTIME_DIR/test_gnunet-communicator-unix_2.sock
32
33[communicator-tcp]
34#PREFIX = xterm -geometry 100x85 -T peer2 -e gdb --args
35#PREFIX = valgrind --leak-check=full --track-origins=yes
36BINDTO = 60003
37DISABLE_V6 = YES
38
39[communicator-udp]
40BINDTO = 60003
41
42[resolver]
43PORT = 62090
44UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-resolver_test_2.sock
diff --git a/src/transport/test_communicator_tcp_bidirect_peer1.conf b/src/transport/test_communicator_tcp_bidirect_peer1.conf
deleted file mode 100644
index dbc227ac6..000000000
--- a/src/transport/test_communicator_tcp_bidirect_peer1.conf
+++ /dev/null
@@ -1,48 +0,0 @@
1@INLINE@ test_transport_defaults.conf
2
3[test-setup]
4#PHASE_LONG=NO
5#PHASE_SIZE=NO
6#BURST_PACKETS_SHORT=1
7
8[PATHS]
9GNUNET_TEST_HOME = $GNUNET_TMP/test-communicator-unix-1/
10
11[PEER]
12PRIVATE_KEY = $GNUNET_TMP/test-communicator-unix-1/private.key
13
14[transport-tcp]
15PORT = 52400
16
17[transport-udp]
18PORT = 52401
19
20[transport]
21PORT = 60000
22UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-transport_test_1.sock
23
24[nat]
25UNIXPATH = $GNUNET_TMP/test-communicator-unix-1/nat.sock
26
27[peerstore]
28UNIXPATH = $GNUNET_TMP/test-communicator-unix-1/peerstore.sock
29
30[statistics]
31PORT = 22461
32UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-statistics_test_1.sock
33
34[communicator-unix]
35UNIXPATH = $GNUNET_RUNTIME_DIR/test_gnunet-communicator-unix_1.sock
36
37[communicator-tcp]
38#PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args
39#PREFIX = valgrind --leak-check=full --track-origins=yes
40BINDTO = 60002
41DISABLE_V6 = YES
42
43[communicator-udp]
44BINDTO = 60002
45
46[resolver]
47PORT = 62089
48UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-resolver_test_1.sock
diff --git a/src/transport/test_communicator_tcp_bidirect_peer2.conf b/src/transport/test_communicator_tcp_bidirect_peer2.conf
deleted file mode 100644
index b73157f0d..000000000
--- a/src/transport/test_communicator_tcp_bidirect_peer2.conf
+++ /dev/null
@@ -1,44 +0,0 @@
1@INLINE@ test_transport_defaults.conf
2
3[PATHS]
4GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunetd-plugin-transport/
5
6[PEER]
7PRIVATE_KEY = $GNUNET_TMP/test-communicator-unix-2/private.key
8
9
10[transport-tcp]
11PORT = 52400
12
13[transport-udp]
14PORT = 52401
15
16[transport]
17PORT = 60001
18UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-transport_test_2.sock
19
20[nat]
21UNIXPATH = $GNUNET_TMP/test-communicator-unix-2/nat.sock
22
23[peerstore]
24UNIXPATH = $GNUNET_TMP/test-communicator-unix-2/peerstore.sock
25
26[statistics]
27PORT = 22462
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-statistics_test_2.sock
29
30[communicator-unix]
31UNIXPATH = $GNUNET_RUNTIME_DIR/test_gnunet-communicator-unix_2.sock
32
33[communicator-tcp]
34#PREFIX = xterm -geometry 100x85 -T peer2 -e gdb --args
35#PREFIX = valgrind --leak-check=full --track-origins=yes
36BINDTO = 60003
37DISABLE_V6 = YES
38
39[communicator-udp]
40BINDTO = 60003
41
42[resolver]
43PORT = 62090
44UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-resolver_test_2.sock
diff --git a/src/transport/test_communicator_tcp_rekey_peer1.conf b/src/transport/test_communicator_tcp_rekey_peer1.conf
deleted file mode 100644
index 82fbf353a..000000000
--- a/src/transport/test_communicator_tcp_rekey_peer1.conf
+++ /dev/null
@@ -1,45 +0,0 @@
1@INLINE@ test_transport_defaults.conf
2
3[PATHS]
4GNUNET_TEST_HOME = $GNUNET_TMP/test-communicator-unix-1/
5
6[PEER]
7PRIVATE_KEY = $GNUNET_TMP/test-communicator-unix-1/private.key
8
9[transport-tcp]
10PORT = 52400
11
12[transport-udp]
13PORT = 52401
14
15[transport]
16PORT = 60000
17UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-transport_test_1.sock
18
19[nat]
20UNIXPATH = $GNUNET_TMP/test-communicator-unix-1/nat.sock
21ENABLE_IPSCAN = YES
22
23[peerstore]
24UNIXPATH = $GNUNET_TMP/test-communicator-unix-1/peerstore.sock
25
26[statistics]
27PORT = 22461
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-statistics_test_1.sock
29
30[resolver]
31PORT = 62089
32UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-resolver_test_1.sock
33
34[communicator-unix]
35UNIXPATH = $GNUNET_RUNTIME_DIR/test_gnunet-communicator-unix_1.sock
36
37[communicator-tcp]
38#PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args
39#PREFIX = valgrind --leak-check=full --track-origins=yes
40BINDTO = 60002
41DISABLE_V6 = YES
42REKEY_INTERVAL = 100ms
43
44[communicator-udp]
45BINDTO = 60002
diff --git a/src/transport/test_communicator_tcp_rekey_peer2.conf b/src/transport/test_communicator_tcp_rekey_peer2.conf
deleted file mode 100644
index 086a996ae..000000000
--- a/src/transport/test_communicator_tcp_rekey_peer2.conf
+++ /dev/null
@@ -1,45 +0,0 @@
1@INLINE@ test_transport_defaults.conf
2
3[PATHS]
4GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunetd-plugin-transport/
5
6[PEER]
7PRIVATE_KEY = $GNUNET_TMP/test-communicator-unix-2/private.key
8
9
10[transport-tcp]
11PORT = 52400
12
13[transport-udp]
14PORT = 52401
15
16[transport]
17PORT = 60001
18UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-transport_test_2.sock
19
20[nat]
21UNIXPATH = $GNUNET_TMP/test-communicator-unix-2/nat.sock
22
23[peerstore]
24UNIXPATH = $GNUNET_TMP/test-communicator-unix-2/peerstore.sock
25
26[statistics]
27PORT = 22462
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-statistics_test_2.sock
29
30[resolver]
31PORT = 62090
32UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-resolver_test_2.sock
33
34[communicator-unix]
35UNIXPATH = $GNUNET_RUNTIME_DIR/test_gnunet-communicator-unix_2.sock
36
37[communicator-tcp]
38#PREFIX = xterm -geometry 100x85 -T peer2 -e gdb --args
39#PREFIX = valgrind --leak-check=full --track-origins=yes
40BINDTO = 60003
41DISABLE_V6 = YES
42REKEY_INTERVAL = 100ms
43
44[communicator-udp]
45BINDTO = 60003
diff --git a/src/transport/test_communicator_udp_backchannel_peer1.conf b/src/transport/test_communicator_udp_backchannel_peer1.conf
deleted file mode 100644
index 59e6d68e3..000000000
--- a/src/transport/test_communicator_udp_backchannel_peer1.conf
+++ /dev/null
@@ -1,48 +0,0 @@
1@INLINE@ test_transport_defaults.conf
2
3[PATHS]
4GNUNET_TEST_HOME = $GNUNET_TMP/test-communicator-unix-1/
5
6[PEER]
7PRIVATE_KEY = $GNUNET_TMP/test-communicator-unix-1/private.key
8
9[transport-tcp]
10PORT = 52400
11
12[transport-udp]
13PORT = 52401
14
15[transport]
16PORT = 60000
17UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-transport_test_1.sock
18
19[nat]
20UNIXPATH = $GNUNET_TMP/test-communicator-unix-1/nat.sock
21ENABLE_IPSCAN = YES
22
23[peerstore]
24UNIXPATH = $GNUNET_TMP/test-communicator-unix-1/peerstore.sock
25
26[statistics]
27PORT = 22461
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-statistics_test_1.sock
29
30[resolver]
31PORT = 62089
32UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-resolver_test_1.sock
33
34[communicator-unix]
35UNIXPATH = $GNUNET_RUNTIME_DIR/test_gnunet-communicator-unix_1.sock
36
37[communicator-tcp]
38BINDTO = 60002
39DISABLE_V6 = YES
40
41[communicator-udp]
42#PREFIX = valgrind --leak-check=full --track-origins=yes
43BINDTO = 60002
44DISABLE_V6 = YES
45MAX_QUEUE_LENGTH=5000
46
47[communicator-test]
48BACKCHANNEL_ENABLED = YES
diff --git a/src/transport/test_communicator_udp_backchannel_peer2.conf b/src/transport/test_communicator_udp_backchannel_peer2.conf
deleted file mode 100644
index 3abf7999b..000000000
--- a/src/transport/test_communicator_udp_backchannel_peer2.conf
+++ /dev/null
@@ -1,48 +0,0 @@
1@INLINE@ test_transport_defaults.conf
2
3[PATHS]
4GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunetd-plugin-transport/
5
6[PEER]
7PRIVATE_KEY = $GNUNET_TMP/test-communicator-unix-2/private.key
8
9
10[transport-tcp]
11PORT = 52400
12
13[transport-udp]
14PORT = 52401
15
16[transport]
17PORT = 60001
18UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-transport_test_2.sock
19
20[nat]
21UNIXPATH = $GNUNET_TMP/test-communicator-unix-2/nat.sock
22
23[peerstore]
24UNIXPATH = $GNUNET_TMP/test-communicator-unix-2/peerstore.sock
25
26[statistics]
27PORT = 22462
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-statistics_test_2.sock
29
30[resolver]
31PORT = 62090
32UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-resolver_test_2.sock
33
34[communicator-unix]
35UNIXPATH = $GNUNET_RUNTIME_DIR/test_gnunet-communicator-unix_2.sock
36
37[communicator-tcp]
38BINDTO = 60003
39DISABLE_V6 = YES
40
41[communicator-udp]
42#PREFIX = valgrind --leak-check=full --track-origins=yes
43BINDTO = 60003
44DISABLE_V6 = YES
45MAX_QUEUE_LENGTH=5000
46
47[communicator-test]
48BACKCHANNEL_ENABLED = YES
diff --git a/src/transport/test_communicator_udp_basic_peer1.conf b/src/transport/test_communicator_udp_basic_peer1.conf
deleted file mode 100644
index c6ff024ee..000000000
--- a/src/transport/test_communicator_udp_basic_peer1.conf
+++ /dev/null
@@ -1,38 +0,0 @@
1@INLINE@ test_transport_defaults.conf
2
3[PATHS]
4GNUNET_TEST_HOME = $GNUNET_TMP/test-communicator-unix-1/
5
6[PEER]
7PRIVATE_KEY = $GNUNET_TMP/test-communicator-unix-1/private.key
8
9[transport-tcp]
10PORT = 52400
11
12[transport-udp]
13PORT = 52401
14
15[transport]
16#PORT = 60000
17UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-transport_test_1.sock
18
19[nat]
20UNIXPATH = $GNUNET_TMP/test-communicator-unix-1/nat.sock
21ENABLE_IPSCAN = YES
22
23[peerstore]
24UNIXPATH = $GNUNET_TMP/test-communicator-unix-1/peerstore.sock
25
26[statistics]
27PORT = 22461
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-statistics_test_1.sock
29
30[resolver]
31PORT = 62089
32UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-resolver_test_1.sock
33
34[communicator-udp]
35#PREFIX = valgrind --leak-check=full --track-origins=yes
36BINDTO = 60002
37DISABLE_V6 = YES
38MAX_QUEUE_LENGTH=5000
diff --git a/src/transport/test_communicator_udp_basic_peer2.conf b/src/transport/test_communicator_udp_basic_peer2.conf
deleted file mode 100644
index b353b03e9..000000000
--- a/src/transport/test_communicator_udp_basic_peer2.conf
+++ /dev/null
@@ -1,39 +0,0 @@
1@INLINE@ test_transport_defaults.conf
2
3[PATHS]
4GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunetd-plugin-transport/
5
6[PEER]
7PRIVATE_KEY = $GNUNET_TMP/test-communicator-unix-2/private.key
8
9
10[transport-tcp]
11PORT = 52400
12
13[transport-udp]
14PORT = 52402
15
16[transport]
17#PORT = 60001
18UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-transport_test_2.sock
19
20[nat]
21UNIXPATH = $GNUNET_TMP/test-communicator-unix-2/nat.sock
22
23
24[peerstore]
25UNIXPATH = $GNUNET_TMP/test-communicator-unix-2/peerstore.sock
26
27[statistics]
28PORT = 22462
29UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-statistics_test_2.sock
30
31[resolver]
32PORT = 62090
33UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-resolver_test_2.sock
34
35[communicator-udp]
36#PREFIX = valgrind --leak-check=full --track-origins=yes
37BINDTO = 60003
38DISABLE_V6 = YES
39MAX_QUEUE_LENGTH=5000
diff --git a/src/transport/test_communicator_udp_rekey_peer1.conf b/src/transport/test_communicator_udp_rekey_peer1.conf
deleted file mode 100644
index 6bfeafe33..000000000
--- a/src/transport/test_communicator_udp_rekey_peer1.conf
+++ /dev/null
@@ -1,51 +0,0 @@
1@INLINE@ test_transport_defaults.conf
2
3[PATHS]
4GNUNET_TEST_HOME = $GNUNET_TMP/test-communicator-unix-1/
5
6[PEER]
7PRIVATE_KEY = $GNUNET_TMP/test-communicator-unix-1/private.key
8
9[transport-tcp]
10PORT = 52400
11
12[transport-udp]
13PORT = 52401
14
15[transport]
16PORT = 60000
17UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-transport_test_1.sock
18
19[nat]
20UNIXPATH = $GNUNET_TMP/test-communicator-unix-1/nat.sock
21ENABLE_IPSCAN = YES
22
23[peerstore]
24UNIXPATH = $GNUNET_TMP/test-communicator-unix-1/peerstore.sock
25
26[statistics]
27PORT = 22461
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-statistics_test_1.sock
29
30[resolver]
31PORT = 62089
32UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-resolver_test_1.sock
33
34[communicator-unix]
35UNIXPATH = $GNUNET_RUNTIME_DIR/test_gnunet-communicator-unix_1.sock
36
37[communicator-tcp]
38BINDTO = 60002
39DISABLE_V6 = YES
40REKEY_INTERVAL = 100ms
41
42[communicator-udp]
43#PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args
44#PREFIX = valgrind --leak-check=full --track-origins=yes
45BINDTO = 60002
46DISABLE_V6 = YES
47MAX_QUEUE_LENGTH=5000
48REKEY_MAX_BYTES=9MiB
49
50[communicator-test]
51BACKCHANNEL_ENABLED = YES
diff --git a/src/transport/test_communicator_udp_rekey_peer2.conf b/src/transport/test_communicator_udp_rekey_peer2.conf
deleted file mode 100644
index 474ca0c15..000000000
--- a/src/transport/test_communicator_udp_rekey_peer2.conf
+++ /dev/null
@@ -1,51 +0,0 @@
1@INLINE@ test_transport_defaults.conf
2
3[PATHS]
4GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunetd-plugin-transport/
5
6[PEER]
7PRIVATE_KEY = $GNUNET_TMP/test-communicator-unix-2/private.key
8
9
10[transport-tcp]
11PORT = 52400
12
13[transport-udp]
14PORT = 52401
15
16[transport]
17PORT = 60001
18UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-transport_test_2.sock
19
20[nat]
21UNIXPATH = $GNUNET_TMP/test-communicator-unix-2/nat.sock
22
23[peerstore]
24UNIXPATH = $GNUNET_TMP/test-communicator-unix-2/peerstore.sock
25
26[statistics]
27PORT = 22462
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-statistics_test_2.sock
29
30[resolver]
31PORT = 62090
32UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-resolver_test_2.sock
33
34[communicator-unix]
35UNIXPATH = $GNUNET_RUNTIME_DIR/test_gnunet-communicator-unix_2.sock
36
37[communicator-tcp]
38BINDTO = 60003
39DISABLE_V6 = YES
40REKEY_INTERVAL = 100ms
41
42[communicator-udp]
43#PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args
44#PREFIX = valgrind --leak-check=full --track-origins=yes
45BINDTO = 60003
46DISABLE_V6 = YES
47MAX_QUEUE_LENGTH=5000
48REKEY_MAX_BYTES=9MiB
49
50[communicator-test]
51BACKCHANNEL_ENABLED = YES
diff --git a/src/transport/test_communicator_unix_basic_peer1.conf b/src/transport/test_communicator_unix_basic_peer1.conf
deleted file mode 100644
index 13ba2d16b..000000000
--- a/src/transport/test_communicator_unix_basic_peer1.conf
+++ /dev/null
@@ -1,43 +0,0 @@
1@INLINE@ test_transport_defaults.conf
2
3[PATHS]
4GNUNET_TEST_HOME = $GNUNET_TMP/test-communicator-unix-1/
5
6[PEER]
7PRIVATE_KEY = $GNUNET_TMP/test-communicator-unix-1/private.key
8
9[transport-tcp]
10PORT = 52400
11
12[transport-udp]
13PORT = 52401
14
15[transport]
16PORT = 60000
17UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-transport_test_1.sock
18
19[nat]
20UNIXPATH = $GNUNET_TMP/communicator-unix-1/nat.sock
21ENABLE_IPSCAN = YES
22
23[peerstore]
24UNIXPATH = $GNUNET_TMP/test-communicator-unix-1/peerstore.sock
25
26[statistics]
27PORT = 22461
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-statistics_test_1.sock
29
30[resolver]
31PORT = 62089
32UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-resolver_test_1.sock
33
34[communicator-unix]
35#PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args
36#PREFIX = valgrind --leak-check=full --track-origins=yes
37UNIXPATH = $GNUNET_RUNTIME_DIR/communicator-unix-1.sock
38
39[communicator-tcp]
40BINDTO = 60002
41
42[communicator-udp]
43BINDTO = 60002
diff --git a/src/transport/test_communicator_unix_basic_peer2.conf b/src/transport/test_communicator_unix_basic_peer2.conf
deleted file mode 100644
index 727e844a7..000000000
--- a/src/transport/test_communicator_unix_basic_peer2.conf
+++ /dev/null
@@ -1,43 +0,0 @@
1@INLINE@ test_transport_defaults.conf
2
3[PATHS]
4GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunetd-plugin-transport/
5
6[PEER]
7PRIVATE_KEY = $GNUNET_TMP/test-communicator-unix-2/private.key
8
9
10[transport-tcp]
11PORT = 52400
12
13[transport-udp]
14PORT = 52401
15
16[transport]
17PORT = 60001
18UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-transport_test_2.sock
19
20[nat]
21UNIXPATH = $GNUNET_TMP/communicator-unix-2/nat.sock
22
23[peerstore]
24UNIXPATH = $GNUNET_TMP/test-communicator-unix-2/peerstore.sock
25
26[statistics]
27PORT = 22462
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-statistics_test_2.sock
29
30[resolver]
31PORT = 62090
32UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-resolver_test_2.sock
33
34[communicator-unix]
35#PREFIX = xterm -geometry 100x85 -T peer2 -e gdb --args
36#PREFIX = valgrind --leak-check=full --track-origins=yes
37UNIXPATH = $GNUNET_RUNTIME_DIR/communicator-unix-2.sock
38
39[communicator-tcp]
40BINDTO = 60003
41
42[communicator-udp]
43BINDTO = 60003
diff --git a/src/transport/test_delay b/src/transport/test_delay
deleted file mode 100755
index 5f82b65fb..000000000
--- a/src/transport/test_delay
+++ /dev/null
@@ -1,19 +0,0 @@
1#!/bin/sh
2
3TEMP=$(getopt 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
18echo "exec $@"
19exec "$@"
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_hostkey b/src/transport/test_plugin_hostkey
deleted file mode 100644
index e7b1ad012..000000000
--- a/src/transport/test_plugin_hostkey
+++ /dev/null
Binary files differ
diff --git a/src/transport/test_plugin_hostkey.ecc b/src/transport/test_plugin_hostkey.ecc
deleted file mode 100644
index 18641b798..000000000
--- a/src/transport/test_plugin_hostkey.ecc
+++ /dev/null
@@ -1 +0,0 @@
1‚”ˆÖ’ÛËy¢/HÒc ȃ§¿±;¼»f?¶@…~áJ \ No newline at end of file
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.c b/src/transport/test_transport_address_switch.c
deleted file mode 100644
index ce5117bd1..000000000
--- a/src/transport/test_transport_address_switch.c
+++ /dev/null
@@ -1,433 +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_transport_address_switch.c
22 * @brief base test case for transport implementations
23 *
24 * This test case tests if peers can successfully switch addresses when
25 * connected for plugins supporting multiple addresses by monitoring transport's
26 * statistic values.
27 *
28 * This test starts 2 peers and connects them. When connected test messages
29 * are transmitted from peer 2 to peer 1. The test monitors transport's
30 * statistics values for information about address switch attempts.
31 *
32 * The test passes with success if one of the peers could successfully switch
33 * addresses in connected state and a test message was successfully transmitted
34 * after this switch.
35 *
36 * Since it is not possible to trigger an address switch from outside,
37 * the test returns "77" (skipped) when no address switching attempt
38 * takes place. It fails if an address switch attempt fails.
39 *
40 * NOTE: The test seems largely useless right now, as we simply NEVER
41 * switch addresses under the test conditions. However, it may be a
42 * good starting point for a future test. For now, it always times
43 * out and returns "77" (skipped), so we set the timeout suitably low.
44 */
45#include "platform.h"
46#include "gnunet_transport_service.h"
47#include "gnunet_ats_service.h"
48#include "transport-testing.h"
49
50
51/**
52 * Testcase timeout (set aggressively as we know this test doesn't work right now)
53 */
54#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
55
56
57static struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
58
59static struct GNUNET_SCHEDULER_Task *measure_task;
60
61
62/**
63 * Statistics we track per peer.
64 */
65struct PeerStats
66{
67 struct GNUNET_STATISTICS_Handle *stat;
68
69 unsigned int addresses_avail;
70
71 unsigned int switch_attempts;
72
73 unsigned int switch_success;
74
75 unsigned int switch_fail;
76};
77
78static struct PeerStats stats[2];
79
80/* Amount of data transferred since last switch attempt */
81static unsigned long long bytes_sent_after_switch;
82
83static unsigned long long bytes_recv_after_switch;
84
85
86static int
87stat_start_attempt_cb (void *cls,
88 const char *subsystem,
89 const char *name,
90 uint64_t value,
91 int is_persistent)
92{
93 struct PeerStats *stat = cls;
94
95 stat->switch_attempts++;
96 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Switch attempted (%p)", stat);
97 bytes_recv_after_switch = 0;
98 bytes_sent_after_switch = 0;
99
100 return GNUNET_OK;
101}
102
103
104static int
105stat_success_attempt_cb (void *cls,
106 const char *subsystem,
107 const char *name,
108 uint64_t value,
109 int is_persistent)
110{
111 struct PeerStats *stat = cls;
112
113 stat->switch_success++;
114 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Switch succeeded (%p)", stat);
115 return GNUNET_OK;
116}
117
118
119static int
120stat_fail_attempt_cb (void *cls,
121 const char *subsystem,
122 const char *name,
123 uint64_t value,
124 int is_persistent)
125{
126 struct PeerStats *stat = cls;
127
128 if (value == 0)
129 return GNUNET_OK;
130
131 stat->switch_fail++;
132 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Switch failed (%p)", stat);
133 return GNUNET_OK;
134}
135
136
137static int
138stat_addresses_available (void *cls,
139 const char *subsystem,
140 const char *name,
141 uint64_t value,
142 int is_persistent)
143{
144 struct PeerStats *stat = cls;
145
146 stat->addresses_avail++;
147 return GNUNET_OK;
148}
149
150
151/**
152 * List of statistics entries we care about.
153 */
154static struct WatchEntry
155{
156 /**
157 * Name of the statistic we watch.
158 */
159 const char *stat_name;
160
161 /**
162 * Handler to register;
163 */
164 GNUNET_STATISTICS_Iterator stat_handler;
165} watches[] =
166{ { "# Attempts to switch addresses", &stat_start_attempt_cb },
167 { "# Successful attempts to switch addresses", &stat_success_attempt_cb },
168 { "# Failed attempts to switch addresses (failed to send CONNECT CONT)",
169 &stat_fail_attempt_cb },
170 { "# Failed attempts to switch addresses (failed to send CONNECT)",
171 &stat_fail_attempt_cb },
172 { "# Failed attempts to switch addresses (no response)",
173 &stat_fail_attempt_cb },
174 { "# transport addresses", &stat_addresses_available },
175 { NULL, NULL } };
176
177
178static void
179custom_shutdown (void *cls)
180{
181 int result;
182
183 if (NULL != measure_task)
184 {
185 GNUNET_SCHEDULER_cancel (measure_task);
186 measure_task = NULL;
187 }
188 if (0 == stats[0].switch_attempts + stats[1].switch_attempts)
189 {
190 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
191 "Test did not work, as peers didn't switch (flawed testcase)!\n");
192 ccc->global_ret = 77;
193 }
194 else
195 {
196 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
197 "Fail (timeout)! No transmission after switch! Stopping peers\n");
198 ccc->global_ret = 77; /* GNUNET_SYSERR; */
199 }
200
201 /* stop statistics */
202 for (unsigned int i = 0; i < 2; i++)
203 {
204 if (NULL != stats[i].stat)
205 {
206 for (unsigned int j = 0; NULL != watches[j].stat_name; j++)
207 GNUNET_assert (GNUNET_OK ==
208 GNUNET_STATISTICS_watch_cancel (stats[i].stat,
209 "transport",
210 watches[j].stat_name,
211 watches[j].stat_handler,
212 &stats[i]));
213 GNUNET_STATISTICS_destroy (stats[i].stat, GNUNET_NO);
214 stats[i].stat = NULL;
215 }
216 }
217
218 result = 0;
219 fprintf (stderr, "\n");
220 if (stats[0].switch_attempts > 0)
221 {
222 fprintf (
223 stderr,
224 "Peer 1 tried %u times to switch and succeeded %u times, failed %u times\n",
225 stats[0].switch_attempts,
226 stats[0].switch_success,
227 stats[0].switch_fail);
228 if (stats[0].switch_success != stats[0].switch_attempts)
229 {
230 GNUNET_break (0);
231 result++;
232 }
233 }
234 else if (stats[0].addresses_avail > 1)
235 {
236 fprintf (stderr,
237 "Peer 1 had %u addresses available, but did not try to switch\n",
238 stats[0].addresses_avail);
239 }
240 if (stats[1].switch_attempts > 0)
241 {
242 fprintf (
243 stderr,
244 "Peer 2 tried %u times to switch and succeeded %u times, failed %u times\n",
245 stats[1].switch_attempts,
246 stats[1].switch_success,
247 stats[1].switch_fail);
248 if (stats[1].switch_success != stats[1].switch_attempts)
249 {
250 GNUNET_break (0);
251 result++;
252 }
253 }
254 else if (stats[1].addresses_avail > 1)
255 {
256 fprintf (stderr,
257 "Peer 2 had %u addresses available, but did not try to switch\n",
258 stats[1].addresses_avail);
259 }
260
261 if (((stats[0].switch_attempts > 0) || (stats[1].switch_attempts > 0)) &&
262 (bytes_sent_after_switch == 0))
263 {
264 fprintf (stderr, "No data sent after switching!\n");
265 GNUNET_break (0);
266 result++;
267 }
268 if (((stats[0].switch_attempts > 0) || (stats[1].switch_attempts > 0)) &&
269 (bytes_recv_after_switch == 0))
270 {
271 fprintf (stderr, "No data received after switching!\n");
272 GNUNET_break (0);
273 result++;
274 }
275#if 0
276 /* This test is not really expected to pass right now... */
277 if (0 != result)
278 ccc->global_ret = GNUNET_SYSERR;
279#endif
280}
281
282
283static void
284notify_receive (void *cls,
285 struct GNUNET_TRANSPORT_TESTING_PeerContext *receiver,
286 const struct GNUNET_PeerIdentity *sender,
287 const struct GNUNET_TRANSPORT_TESTING_TestMessage *hdr)
288{
289 if (GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE != ntohs (hdr->header.type))
290 return;
291
292 {
293 char *ps = GNUNET_strdup (GNUNET_i2s (&receiver->id));
294
295 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
296 "Peer %u (`%s') got message %u of size %u from peer (`%s')\n",
297 receiver->no,
298 ps,
299 (uint32_t) ntohl (hdr->num),
300 ntohs (hdr->header.size),
301 GNUNET_i2s (sender));
302 GNUNET_free (ps);
303 }
304 if (((stats[0].switch_attempts >= 1) || (stats[1].switch_attempts >= 1)) &&
305 (stats[0].switch_attempts ==
306 stats[0].switch_fail + stats[0].switch_success) &&
307 (stats[1].switch_attempts ==
308 stats[1].switch_fail + stats[1].switch_success))
309 {
310 bytes_recv_after_switch += ntohs (hdr->header.size);
311 if ((bytes_sent_after_switch > 0) && (bytes_recv_after_switch > 0))
312 {
313 /* A peer switched addresses and sent and received data after the
314 * switch operations */
315 GNUNET_SCHEDULER_shutdown ();
316 }
317 }
318}
319
320
321static void
322notify_send (void *cls)
323{
324 static uint32_t cnt;
325
326 GNUNET_assert (
327 GNUNET_OK ==
328 GNUNET_TRANSPORT_TESTING_send (ccc->p[1],
329 ccc->p[0],
330 GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE,
331 GNUNET_TRANSPORT_TESTING_LARGE_MESSAGE_SIZE,
332 ++cnt,
333 &notify_send,
334 NULL));
335 if (((stats[0].switch_attempts >= 1) || (stats[1].switch_attempts >= 1)) &&
336 (stats[0].switch_attempts ==
337 stats[0].switch_fail + stats[0].switch_success) &&
338 (stats[1].switch_attempts ==
339 stats[1].switch_fail + stats[1].switch_success))
340 {
341 bytes_sent_after_switch += GNUNET_TRANSPORT_TESTING_LARGE_MESSAGE_SIZE;
342 }
343}
344
345
346static void
347progress_indicator (void *cls)
348{
349 static int counter;
350
351 measure_task = NULL;
352 counter++;
353 if ((TIMEOUT.rel_value_us / 1000 / 1000LL) < counter)
354 {
355 fprintf (stderr, "%s", ".\n");
356 }
357 else
358 {
359 fprintf (stderr, "%s", ".");
360 measure_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
361 &progress_indicator,
362 NULL);
363 }
364}
365
366
367static void
368connected_cb (void *cls)
369{
370 for (unsigned int i = 0; i < 2; i++)
371 {
372 stats[i].stat = GNUNET_STATISTICS_create ("transport", ccc->p[i]->cfg);
373 if (NULL == stats[i].stat)
374 {
375 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
376 "Fail! Could not create statistics for peers!\n");
377 ccc->global_ret = GNUNET_SYSERR;
378 GNUNET_SCHEDULER_shutdown ();
379 return;
380 }
381 for (unsigned int j = 0; NULL != watches[j].stat_name; j++)
382 {
383 GNUNET_STATISTICS_watch (stats[i].stat,
384 "transport",
385 watches[j].stat_name,
386 watches[j].stat_handler,
387 &stats[i]);
388 }
389 }
390 /* Show progress */
391 ccc->global_ret = GNUNET_OK;
392 measure_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
393 &progress_indicator,
394 NULL);
395 /* Peers are connected, start transmit test messages */
396 GNUNET_assert (
397 GNUNET_OK ==
398 GNUNET_TRANSPORT_TESTING_send (ccc->p[1],
399 ccc->p[0],
400 GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE,
401 GNUNET_TRANSPORT_TESTING_LARGE_MESSAGE_SIZE,
402 0,
403 &notify_send,
404 NULL));
405}
406
407
408int
409main (int argc, char *argv[])
410{
411 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext my_ccc =
412 { .connect_continuation = &connected_cb,
413 .config_file = "test_transport_api_data.conf",
414 .rec = &notify_receive,
415 .nc = &GNUNET_TRANSPORT_TESTING_log_connect,
416 .shutdown_task = &custom_shutdown,
417 .timeout = TIMEOUT };
418
419 ccc = &my_ccc;
420 int ret;
421
422 ret = GNUNET_TRANSPORT_TESTING_main (2,
423 &GNUNET_TRANSPORT_TESTING_connect_check,
424 ccc);
425 if (77 == ret)
426 return 77;
427 if (GNUNET_OK != ret)
428 return 1;
429 return 0;
430}
431
432
433/* end of test_transport_address_switch.c */
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_address_switch_tcp_peer1.conf b/src/transport/test_transport_address_switch_tcp_peer1.conf
deleted file mode 100644
index cfcbfe41c..000000000
--- a/src/transport/test_transport_address_switch_tcp_peer1.conf
+++ /dev/null
@@ -1,48 +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-tcp]
25PORT = 12000
26TIMEOUT = 5 s
27
28[arm]
29PORT = 12005
30UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
31
32[statistics]
33PORT = 12004
34UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
35
36[resolver]
37PORT = 12003
38UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
39
40[peerinfo]
41PORT = 12002
42UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
43
44[transport]
45PORT = 12001
46UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
47PLUGINS = tcp
48
diff --git a/src/transport/test_transport_address_switch_tcp_peer2.conf b/src/transport/test_transport_address_switch_tcp_peer2.conf
deleted file mode 100644
index bda2354b6..000000000
--- a/src/transport/test_transport_address_switch_tcp_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[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-tcp]
25PORT = 12015
26TIMEOUT = 5 s
27
28[arm]
29PORT = 12014
30UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
31
32[statistics]
33PORT = 12013
34UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
35
36[resolver]
37PORT = 12012
38UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
39
40[peerinfo]
41PORT = 12011
42UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
43
44[transport]
45PORT = 12010
46PLUGINS = tcp
47UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
48
diff --git a/src/transport/test_transport_address_switch_udp_peer1.conf b/src/transport/test_transport_address_switch_udp_peer1.conf
deleted file mode 100644
index bdc3a2253..000000000
--- a/src/transport/test_transport_address_switch_udp_peer1.conf
+++ /dev/null
@@ -1,48 +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-tcp]
25PORT = 12000
26TIMEOUT = 5 s
27
28[arm]
29PORT = 12005
30UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
31
32[statistics]
33PORT = 12004
34UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
35
36[resolver]
37PORT = 12003
38UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
39
40[peerinfo]
41PORT = 12002
42UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
43
44[transport]
45PORT = 12001
46UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
47PLUGINS = udp
48
diff --git a/src/transport/test_transport_address_switch_udp_peer2.conf b/src/transport/test_transport_address_switch_udp_peer2.conf
deleted file mode 100644
index ae6397db4..000000000
--- a/src/transport/test_transport_address_switch_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[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-tcp]
25PORT = 12015
26TIMEOUT = 5 s
27
28[arm]
29PORT = 12014
30UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
31
32[statistics]
33PORT = 12013
34UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
35
36[resolver]
37PORT = 12012
38UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
39
40[peerinfo]
41PORT = 12011
42UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
43
44[transport]
45PORT = 12010
46PLUGINS = udp
47UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
48
diff --git a/src/transport/test_transport_api.c b/src/transport/test_transport_api.c
deleted file mode 100644
index 5f5e03a9e..000000000
--- a/src/transport/test_transport_api.c
+++ /dev/null
@@ -1,126 +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.c
22 * @brief base test case for transport implementations
23 * @author Christian Grothoff
24 *
25 * This test case serves as a base for tcp, udp, and udp-nat
26 * transport test cases. Based on the executable being run
27 * the correct test case will be performed. Conservation of
28 * C code apparently.
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
41
42static void
43notify_receive (void *cls,
44 struct GNUNET_TRANSPORT_TESTING_PeerContext *receiver,
45 const struct GNUNET_PeerIdentity *sender,
46 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
47{
48 {
49 char *ps = GNUNET_strdup (GNUNET_i2s (&receiver->id));
50
51 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
52 "Peer %u (`%s') received message of type %d and size %u size from peer %s!\n",
53 receiver->no,
54 ps,
55 ntohs (message->header.type),
56 ntohs (message->header.size),
57 GNUNET_i2s (sender));
58 GNUNET_free (ps);
59 }
60
61 if ((GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE == ntohs (message->header.type)) &&
62 (GNUNET_TRANSPORT_TESTING_LARGE_MESSAGE_SIZE == ntohs (
63 message->header.size)))
64 {
65 ccc->global_ret = GNUNET_OK;
66 GNUNET_SCHEDULER_shutdown ();
67 }
68 else
69 {
70 GNUNET_break (0);
71 ccc->global_ret = GNUNET_SYSERR;
72 GNUNET_SCHEDULER_shutdown ();
73 }
74}
75
76
77/**
78 * Runs the test.
79 *
80 * @param argv the argv argument from main()
81 * @param bi_directional should we try to establish connections
82 * in both directions simultaneously?
83 */
84static int
85test (char *argv[],
86 int bi_directional)
87{
88 struct GNUNET_TRANSPORT_TESTING_SendClosure sc = {
89 .num_messages = 1
90 };
91 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext my_ccc = {
92 .connect_continuation = &GNUNET_TRANSPORT_TESTING_large_send,
93 .connect_continuation_cls = &sc,
94 .config_file = "test_transport_api_data.conf",
95 .rec = &notify_receive,
96 .nc = &GNUNET_TRANSPORT_TESTING_log_connect,
97 .nd = &GNUNET_TRANSPORT_TESTING_log_disconnect,
98 .timeout = TIMEOUT,
99 .bi_directional = bi_directional
100 };
101
102 ccc = &my_ccc;
103 sc.ccc = ccc;
104 if (GNUNET_OK !=
105 GNUNET_TRANSPORT_TESTING_main (2,
106 &GNUNET_TRANSPORT_TESTING_connect_check,
107 ccc))
108 return 1;
109 return 0;
110}
111
112
113int
114main (int argc,
115 char *argv[])
116{
117 if ((0 != test (argv,
118 GNUNET_NO)) ||
119 (0 != test (argv,
120 GNUNET_YES)))
121 return 1;
122 return 0;
123}
124
125
126/* end of test_transport_api.c */
diff --git a/src/transport/test_transport_api2.c b/src/transport/test_transport_api2.c
deleted file mode 100644
index e1606e0be..000000000
--- a/src/transport/test_transport_api2.c
+++ /dev/null
@@ -1,126 +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.c
22 * @brief base test case for transport implementations
23 * @author Christian Grothoff
24 *
25 * This test case serves as a base for tcp, udp, and udp-nat
26 * transport test cases. Based on the executable being run
27 * the correct test case will be performed. Conservation of
28 * C code apparently.
29 */
30#include "platform.h"
31//#include "gnunet_transport_service.h"
32#include "transport-testing2.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
41
42static void
43notify_receive (void *cls,
44 struct GNUNET_TRANSPORT_TESTING_PeerContext *receiver,
45 const struct GNUNET_PeerIdentity *sender,
46 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
47{
48 {
49 char *ps = GNUNET_strdup (GNUNET_i2s (&receiver->id));
50
51 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
52 "Peer %u (`%s') received message of type %d and size %u size from peer %s!\n",
53 receiver->no,
54 ps,
55 ntohs (message->header.type),
56 ntohs (message->header.size),
57 GNUNET_i2s (sender));
58 GNUNET_free (ps);
59 }
60
61 if ((GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE == ntohs (message->header.type)) &&
62 (GNUNET_TRANSPORT_TESTING_LARGE_MESSAGE_SIZE == ntohs (
63 message->header.size)))
64 {
65 ccc->global_ret = GNUNET_OK;
66 GNUNET_SCHEDULER_shutdown ();
67 }
68 else
69 {
70 GNUNET_break (0);
71 ccc->global_ret = GNUNET_SYSERR;
72 GNUNET_SCHEDULER_shutdown ();
73 }
74}
75
76
77/**
78 * Runs the test.
79 *
80 * @param argv the argv argument from main()
81 * @param bi_directional should we try to establish connections
82 * in both directions simultaneously?
83 */
84static int
85test (char *argv[],
86 int bi_directional)
87{
88 struct GNUNET_TRANSPORT_TESTING_SendClosure sc = {
89 .num_messages = 1
90 };
91 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext my_ccc = {
92 .connect_continuation = &GNUNET_TRANSPORT_TESTING_large_send,
93 .connect_continuation_cls = &sc,
94 .config_file = "test_transport_api_data.conf",
95 .rec = &notify_receive,
96 .nc = &GNUNET_TRANSPORT_TESTING_log_connect,
97 .nd = &GNUNET_TRANSPORT_TESTING_log_disconnect,
98 .timeout = TIMEOUT,
99 .bi_directional = bi_directional
100 };
101
102 ccc = &my_ccc;
103 sc.ccc = ccc;
104 if (GNUNET_OK !=
105 GNUNET_TRANSPORT_TESTING_main (2,
106 &GNUNET_TRANSPORT_TESTING_connect_check,
107 ccc))
108 return 1;
109 return 0;
110}
111
112
113int
114main (int argc,
115 char *argv[])
116{
117 if ((0 != test (argv,
118 GNUNET_NO)) ||
119 (0 != test (argv,
120 GNUNET_YES)))
121 return 1;
122 return 0;
123}
124
125
126/* end of test_transport_api.c */
diff --git a/src/transport/test_transport_api2_tcp_node1.conf b/src/transport/test_transport_api2_tcp_node1.conf
deleted file mode 100644
index b8a743a3b..000000000
--- a/src/transport/test_transport_api2_tcp_node1.conf
+++ /dev/null
@@ -1,32 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
4
5[transport]
6BINARY = gnunet-service-tng
7PLUGINS = tcp
8#PREFIX = valgrind --leak-check=full --track-origins=yes --trace-children=yes --log-file=/tmp/vg_peer1-%p
9UNIXPATH = $GNUNET_RUNTIME_DIR/tng-p1.sock
10
11[communicator-tcp]
12BINARY = gnunet-communicator-tcp
13BINDTO = 192.168.15.1:60002
14DISABLE_V6 = YES
15IMMEDIATE_START = YES
16UNIXPATH = $GNUNET_RUNTIME_DIR/tcp-comm-p1.sock
17#PREFIX = valgrind --leak-check=full --track-origins=yes --trace-children=yes --log-file=/tmp/vg_ctpeer1-%p
18#PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args
19
20[communicator-udp]
21#PREFIX = valgrind --leak-check=full --track-origins=yes --trace-children=yes --log-file=/tmp/vg_cupeer1-%p
22BINARY = gnunet-communicator-udp
23BINDTO = 192.168.15.1:60002
24DISABLE_V6 = YES
25IMMEDIATE_START = YES
26UNIXPATH = $GNUNET_RUNTIME_DIR/udp-comm-p1.sock
27
28[peerstore]
29IMMEDIATE_START = YES
30
31#[transport]
32#PREFIX = valgrind
diff --git a/src/transport/test_transport_api2_tcp_node2.conf b/src/transport/test_transport_api2_tcp_node2.conf
deleted file mode 100644
index f94368b3f..000000000
--- a/src/transport/test_transport_api2_tcp_node2.conf
+++ /dev/null
@@ -1,22 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
4
5[transport]
6BINARY = gnunet-service-tng
7#PREFIX = valgrind --log-file=/tmp/vg_peer2-%p
8UNIXPATH = $GNUNET_RUNTIME_DIR/tng-p2.sock
9
10[communicator-tcp]
11BINARY = gnunet-communicator-tcp
12BINDTO = 192.168.15.2:60003
13DISABLE_V6 = YES
14IMMEDIATE_START = YES
15#PREFIX = valgrind --log-file=/tmp/vg_comm2-%p
16UNIXPATH = $GNUNET_RUNTIME_DIR/tcp-comm-p2.sock
17
18[peerstore]
19IMMEDIATE_START = YES
20
21#[transport]
22#PREFIX = valgrind
diff --git a/src/transport/test_transport_api2_tcp_peer1.conf b/src/transport/test_transport_api2_tcp_peer1.conf
deleted file mode 100644
index 745ed6887..000000000
--- a/src/transport/test_transport_api2_tcp_peer1.conf
+++ /dev/null
@@ -1,23 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
4
5[transport]
6BINARY = gnunet-service-tng
7PLUGINS = tcp
8#PREFIX = valgrind --log-file=/tmp/vg_peer1-%p
9UNIXPATH = $GNUNET_RUNTIME_DIR/tng-p1.sock
10
11[communicator-tcp]
12BINARY = gnunet-communicator-tcp
13BINDTO = 60002
14DISABLE_V6 = YES
15IMMEDIATE_START = YES
16UNIXPATH = $GNUNET_RUNTIME_DIR/tcp-comm-p1.sock
17#PREFIX = valgrind --log-file=/tmp/vg_cpeer1-%p
18
19[peerstore]
20IMMEDIATE_START = YES
21
22#[transport]
23#PREFIX = valgrind
diff --git a/src/transport/test_transport_api2_tcp_peer2.conf b/src/transport/test_transport_api2_tcp_peer2.conf
deleted file mode 100644
index 022468bcd..000000000
--- a/src/transport/test_transport_api2_tcp_peer2.conf
+++ /dev/null
@@ -1,22 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
4
5[transport]
6BINARY = gnunet-service-tng
7#PREFIX = valgrind --log-file=/tmp/vg_peer2-%p
8UNIXPATH = $GNUNET_RUNTIME_DIR/tng-p2.sock
9
10[communicator-tcp]
11BINARY = gnunet-communicator-tcp
12BINDTO = 60003
13DISABLE_V6 = YES
14IMMEDIATE_START = YES
15#PREFIX = valgrind --log-file=/tmp/vg_comm2-%p
16UNIXPATH = $GNUNET_RUNTIME_DIR/tcp-comm-p2.sock
17
18[peerstore]
19IMMEDIATE_START = YES
20
21#[transport]
22#PREFIX = valgrind
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_data.conf b/src/transport/test_transport_api_data.conf
deleted file mode 100644
index c06235a0a..000000000
--- a/src/transport/test_transport_api_data.conf
+++ /dev/null
@@ -1,9 +0,0 @@
1@INLINE@ test_transport_defaults.conf
2[PATHS]
3
4[transport-tcp]
5PORT = 52094
6
7[transport-udp]
8PORT = 52094
9
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_monitor_peers.c b/src/transport/test_transport_api_monitor_peers.c
deleted file mode 100644
index c09e3782d..000000000
--- a/src/transport/test_transport_api_monitor_peers.c
+++ /dev/null
@@ -1,226 +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_monitor_peers.c
22 * @brief base test case for transport peer monitor API
23 */
24#include "platform.h"
25#include "gnunet_transport_service.h"
26#include "transport-testing.h"
27
28/**
29 * How long until we give up on transmitting the message?
30 */
31#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120)
32
33/**
34 * How long until we give up on transmitting the message?
35 */
36#define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply ( \
37 GNUNET_TIME_UNIT_SECONDS, 30)
38
39#define TEST_MESSAGE_SIZE 2600
40
41#define TEST_MESSAGE_TYPE 12345
42
43static struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
44
45static struct GNUNET_TRANSPORT_PeerMonitoringContext *pmc_p1;
46
47static struct GNUNET_TRANSPORT_PeerMonitoringContext *pmc_p2;
48
49static int p1_c;
50
51static int p2_c;
52
53static int p1_c_notify;
54
55static int p2_c_notify;
56
57
58static void
59custom_shutdown (void *cls)
60{
61 if (NULL != pmc_p1)
62 {
63 GNUNET_TRANSPORT_monitor_peers_cancel (pmc_p1);
64 pmc_p1 = NULL;
65 }
66 if (NULL != pmc_p2)
67 {
68 GNUNET_TRANSPORT_monitor_peers_cancel (pmc_p2);
69 pmc_p2 = NULL;
70 }
71}
72
73
74static void
75notify_receive (void *cls,
76 struct GNUNET_TRANSPORT_TESTING_PeerContext *receiver,
77 const struct GNUNET_PeerIdentity *sender,
78 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
79{
80 char *ps = GNUNET_strdup (GNUNET_i2s (&receiver->id));
81
82 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
83 "Peer %u (`%s') received message of type %d and size %u size from peer %s!\n",
84 receiver->no,
85 ps,
86 ntohs (message->header.type),
87 ntohs (message->header.size),
88 GNUNET_i2s (sender));
89 GNUNET_free (ps);
90}
91
92
93static void
94sendtask (void *cls)
95{
96 /* intentionally empty */
97}
98
99
100static void
101check_done ()
102{
103 if ((GNUNET_YES == p1_c) &&
104 (GNUNET_YES == p2_c) &&
105 p1_c_notify &&
106 p2_c_notify)
107 {
108 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
109 "Both peers state to be connected\n");
110 ccc->global_ret = GNUNET_OK;
111 GNUNET_SCHEDULER_shutdown ();
112 }
113}
114
115
116static void
117notify_connect (void *cls,
118 struct GNUNET_TRANSPORT_TESTING_PeerContext *me,
119 const struct GNUNET_PeerIdentity *other)
120{
121 GNUNET_TRANSPORT_TESTING_log_connect (cls,
122 me,
123 other);
124 if (0 == memcmp (other, &ccc->p[0]->id, sizeof(struct GNUNET_PeerIdentity)))
125 {
126 p1_c_notify = GNUNET_YES;
127 }
128 if (0 == memcmp (other, &ccc->p[1]->id, sizeof(struct GNUNET_PeerIdentity)))
129 {
130 p2_c_notify = GNUNET_YES;
131 }
132 check_done ();
133}
134
135
136static void
137monitor1_cb (void *cls,
138 const struct GNUNET_PeerIdentity *peer,
139 const struct GNUNET_HELLO_Address *address,
140 enum GNUNET_TRANSPORT_PeerState state,
141 struct GNUNET_TIME_Absolute state_timeout)
142{
143 if ((NULL == address) || (NULL == ccc->p[0]))
144 return;
145
146 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
147 "Monitor 1: %s %s %s\n",
148 GNUNET_i2s (&address->peer),
149 GNUNET_TRANSPORT_ps2s (state),
150 GNUNET_STRINGS_absolute_time_to_string (state_timeout));
151 if ((0 == memcmp (&address->peer, &ccc->p[1]->id, sizeof(ccc->p[1]->id))) &&
152 (GNUNET_YES == GNUNET_TRANSPORT_is_connected (state)) &&
153 (GNUNET_NO == p1_c))
154 {
155 p1_c = GNUNET_YES;
156 check_done ();
157 }
158}
159
160
161static void
162monitor2_cb (void *cls,
163 const struct GNUNET_PeerIdentity *peer,
164 const struct GNUNET_HELLO_Address *address,
165 enum GNUNET_TRANSPORT_PeerState state,
166 struct GNUNET_TIME_Absolute state_timeout)
167{
168 if ((NULL == address) || (NULL == ccc->p[1]))
169 return;
170
171 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
172 "Monitor 2: %s %s %s\n",
173 GNUNET_i2s (&address->peer),
174 GNUNET_TRANSPORT_ps2s (state),
175 GNUNET_STRINGS_absolute_time_to_string (state_timeout));
176 if ((0 == memcmp (&address->peer, &ccc->p[0]->id, sizeof(ccc->p[0]->id))) &&
177 (GNUNET_YES == GNUNET_TRANSPORT_is_connected (state)) &&
178 (GNUNET_NO == p2_c))
179 {
180 p2_c = GNUNET_YES;
181 check_done ();
182 }
183}
184
185
186static void
187start_monitors (void *cls)
188{
189 pmc_p1 = GNUNET_TRANSPORT_monitor_peers (ccc->p[0]->cfg,
190 NULL,
191 GNUNET_NO,
192 &monitor1_cb,
193 NULL);
194 pmc_p2 = GNUNET_TRANSPORT_monitor_peers (ccc->p[1]->cfg,
195 NULL,
196 GNUNET_NO,
197 &monitor2_cb,
198 NULL);
199}
200
201
202int
203main (int argc, char *argv[])
204{
205 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext my_ccc = {
206 .pre_connect_task = &start_monitors,
207 .connect_continuation = &sendtask,
208 .config_file = "test_transport_api_data.conf",
209 .rec = &notify_receive,
210 .nc = &notify_connect,
211 .nd = &GNUNET_TRANSPORT_TESTING_log_disconnect,
212 .shutdown_task = &custom_shutdown,
213 .timeout = TIMEOUT
214 };
215
216 ccc = &my_ccc;
217 if (GNUNET_OK !=
218 GNUNET_TRANSPORT_TESTING_main (2,
219 &GNUNET_TRANSPORT_TESTING_connect_check,
220 ccc))
221 return 1;
222 return 0;
223}
224
225
226/* end of test_transport_api_monitor_peers.c */
diff --git a/src/transport/test_transport_api_monitor_peers_peer1.conf b/src/transport/test_transport_api_monitor_peers_peer1.conf
deleted file mode 100644
index bc9eee19b..000000000
--- a/src/transport/test_transport_api_monitor_peers_peer1.conf
+++ /dev/null
@@ -1,4 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-monitoring-p1/
4
diff --git a/src/transport/test_transport_api_monitor_peers_peer2.conf b/src/transport/test_transport_api_monitor_peers_peer2.conf
deleted file mode 100644
index 5225a5a87..000000000
--- a/src/transport/test_transport_api_monitor_peers_peer2.conf
+++ /dev/null
@@ -1,5 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-monitoring-p2/
4
5
diff --git a/src/transport/test_transport_api_monitor_validation_peer1.conf b/src/transport/test_transport_api_monitor_validation_peer1.conf
deleted file mode 100644
index 02f7bc2f0..000000000
--- a/src/transport/test_transport_api_monitor_validation_peer1.conf
+++ /dev/null
@@ -1,6 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-monitoring-val-p1/
4
5[transport]
6PLUGINS=tcp
diff --git a/src/transport/test_transport_api_monitor_validation_peer2.conf b/src/transport/test_transport_api_monitor_validation_peer2.conf
deleted file mode 100644
index d4e0874f0..000000000
--- a/src/transport/test_transport_api_monitor_validation_peer2.conf
+++ /dev/null
@@ -1,7 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-monitoring-val-p2/
4
5[TRANSPORT]
6PLUGINS=tcp
7
diff --git a/src/transport/test_transport_api_multi_peer1.conf b/src/transport/test_transport_api_multi_peer1.conf
deleted file mode 100644
index b7cb98777..000000000
--- a/src/transport/test_transport_api_multi_peer1.conf
+++ /dev/null
@@ -1,7 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-multi-p1/
4
5[transport]
6PLUGINS = tcp udp
7
diff --git a/src/transport/test_transport_api_multi_peer2.conf b/src/transport/test_transport_api_multi_peer2.conf
deleted file mode 100644
index f69e0abd9..000000000
--- a/src/transport/test_transport_api_multi_peer2.conf
+++ /dev/null
@@ -1,9 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-multi-p2/
4
5[nat]
6ALLOW_NAT = NO
7
8[transport]
9PLUGINS = tcp udp
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_tcp_nat_peer1.conf b/src/transport/test_transport_api_tcp_nat_peer1.conf
deleted file mode 100644
index fb2fcecc6..000000000
--- a/src/transport/test_transport_api_tcp_nat_peer1.conf
+++ /dev/null
@@ -1,34 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-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
diff --git a/src/transport/test_transport_api_tcp_nat_peer2.conf b/src/transport/test_transport_api_tcp_nat_peer2.conf
deleted file mode 100644
index 1faefc195..000000000
--- a/src/transport/test_transport_api_tcp_nat_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-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
diff --git a/src/transport/test_transport_api_tcp_peer1.conf b/src/transport/test_transport_api_tcp_peer1.conf
deleted file mode 100644
index eabd6b701..000000000
--- a/src/transport/test_transport_api_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_tcp_peer2.conf b/src/transport/test_transport_api_tcp_peer2.conf
deleted file mode 100644
index 58ce0777f..000000000
--- a/src/transport/test_transport_api_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_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_udp_nat_peer1.conf b/src/transport/test_transport_api_udp_nat_peer1.conf
deleted file mode 100644
index 7bbcaa628..000000000
--- a/src/transport/test_transport_api_udp_nat_peer1.conf
+++ /dev/null
@@ -1,34 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-udp-nat-p1/
4
5[nat]
6BEHIND_NAT = YES
7ALLOW_NAT = NO
8ONLY_NAT_ADDRESSES = YES
9
10[transport-udp]
11PORT = 0
12
13[arm]
14PORT = 12065
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
16
17[statistics]
18PORT = 12064
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
20
21[resolver]
22PORT = 12063
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
24
25[peerinfo]
26PORT = 12062
27UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
28
29[transport]
30PORT = 12061
31PLUGINS = udp
32UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
33
34
diff --git a/src/transport/test_transport_api_udp_nat_peer2.conf b/src/transport/test_transport_api_udp_nat_peer2.conf
deleted file mode 100644
index 8bdb8c293..000000000
--- a/src/transport/test_transport_api_udp_nat_peer2.conf
+++ /dev/null
@@ -1,32 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-udp-nat-p2/
4
5[nat]
6ALLOW_NAT = YES
7
8[transport-udp]
9PORT = 12070
10
11[arm]
12PORT = 12075
13UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
14
15[statistics]
16PORT = 12074
17UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
18
19[resolver]
20PORT = 12073
21UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
22
23[peerinfo]
24PORT = 12072
25UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
26
27[transport]
28PORT = 12071
29PLUGINS = udp
30UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
31
32
diff --git a/src/transport/test_transport_api_udp_peer1.conf b/src/transport/test_transport_api_udp_peer1.conf
deleted file mode 100644
index 4684b77f2..000000000
--- a/src/transport/test_transport_api_udp_peer1.conf
+++ /dev/null
@@ -1,17 +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 = 0
7BROADCAST = NO
8MAX_BPS = 50000000
9BINDTO = 127.0.0.1
10BINDTO6 = ::1
11
12[transport]
13PORT = 12041
14PLUGINS = udp
15
16
17
diff --git a/src/transport/test_transport_api_udp_peer2.conf b/src/transport/test_transport_api_udp_peer2.conf
deleted file mode 100644
index 96706ce49..000000000
--- a/src/transport/test_transport_api_udp_peer2.conf
+++ /dev/null
@@ -1,15 +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
9BINDTO = 127.0.0.1
10BINDTO6 = ::1
11
12[transport]
13PLUGINS = udp
14
15
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_unix_peer1.conf b/src/transport/test_transport_api_unix_peer1.conf
deleted file mode 100644
index 005558bcc..000000000
--- a/src/transport/test_transport_api_unix_peer1.conf
+++ /dev/null
@@ -1,10 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-unix-p1/
4
5[transport]
6PLUGINS = unix
7
8[transport-unix]
9PORT = 12120
10
diff --git a/src/transport/test_transport_api_unix_peer2.conf b/src/transport/test_transport_api_unix_peer2.conf
deleted file mode 100644
index 840ed81c7..000000000
--- a/src/transport/test_transport_api_unix_peer2.conf
+++ /dev/null
@@ -1,7 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-unix-p2/
4
5[transport]
6PLUGINS = unix
7
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_defaults.conf b/src/transport/test_transport_defaults.conf
deleted file mode 100644
index 3aed73f0c..000000000
--- a/src/transport/test_transport_defaults.conf
+++ /dev/null
@@ -1,20 +0,0 @@
1@INLINE@ ../../contrib/conf/gnunet/no_forcestart.conf
2
3[PATHS]
4GNUNET_TEST_HOME = $GNUNET_TMP/test-tng/
5
6[transport-tcp]
7TIMEOUT = 300 s
8
9[transport]
10# PREFIX = valgrind
11
12[nat]
13DISABLEV6 = NO
14RETURN_LOCAL_ADDRESSES = YES
15BINDTO = 127.0.0.1
16INTERNAL_ADDRESS = 127.0.0.1
17EXTERNAL_ADDRESS = 127.0.0.1
18
19[transport-udp]
20BROADCAST_RECEIVE = no
diff --git a/src/transport/test_transport_distance_vector_circle_topo.conf b/src/transport/test_transport_distance_vector_circle_topo.conf
deleted file mode 100644
index 210179291..000000000
--- a/src/transport/test_transport_distance_vector_circle_topo.conf
+++ /dev/null
@@ -1,12 +0,0 @@
1M:1
2N:3
3X:0
4AC:1
5B:0
6T:libgnunet_test_transport_plugin_cmd_simple_send_dv
7R:1|{tcp_port:0}|{udp_port:1}
8R:2|{tcp_port:0}|{udp_port:1}
9R:3|{tcp_port:0}|{udp_port:1}
10P:1:1|{connect:{P:2:1:udp}}
11P:2:1|{connect:{P:3:1:udp}}
12P:3:1|{connect:{P:1:1:udp}}
diff --git a/src/transport/test_transport_distance_vector_topo.conf b/src/transport/test_transport_distance_vector_topo.conf
deleted file mode 100644
index ead3e0a0a..000000000
--- a/src/transport/test_transport_distance_vector_topo.conf
+++ /dev/null
@@ -1,8 +0,0 @@
1M:2
2N:2
3X:0
4T:libgnunet_test_transport_plugin_cmd_simple_send_dv
5R:1|{tcp_port:1}|{udp_port:0}
6R:2|{tcp_port:1}|{udp_port:0}
7P:1:1|{connect:{P:2:1:tcp}}
8P:2:1|{connect:{P:1:1:tcp}}
diff --git a/src/transport/test_transport_plugin_cmd_simple_send.c b/src/transport/test_transport_plugin_cmd_simple_send.c
deleted file mode 100644
index 154c0abca..000000000
--- a/src/transport/test_transport_plugin_cmd_simple_send.c
+++ /dev/null
@@ -1,369 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2021 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/plugin_cmd_simple_send.c
23 * @brief a plugin to provide the API for running test cases.
24 * @author t3sserakt
25 */
26#include "platform.h"
27#include "gnunet_testing_ng_lib.h"
28#include "gnunet_testing_netjail_lib.h"
29#include "gnunet_util_lib.h"
30#include "gnunet_transport_application_service.h"
31#include "transport-testing2.h"
32#include "transport-testing-cmds.h"
33
34/**
35 * Generic logging shortcut
36 */
37#define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__)
38
39#define BASE_DIR "testdir"
40
41#define TOPOLOGY_CONFIG "test_transport_simple_send_topo.conf"
42
43struct TestState
44{
45 /**
46 * Callback to write messages to the master loop.
47 *
48 */
49 TESTING_CMD_HELPER_write_cb write_message;
50
51 /**
52 * The name for a specific test environment directory.
53 *
54 */
55 char *testdir;
56
57 /**
58 * The name for the configuration file of the specific node.
59 *
60 */
61 char *cfgname;
62
63 /**
64 * The complete topology information.
65 */
66 struct GNUNET_TESTING_NetjailTopology *topology;
67};
68
69static struct GNUNET_TESTING_Command block_send;
70
71static struct GNUNET_TESTING_Command block_receive;
72
73static struct GNUNET_TESTING_Command connect_peers;
74
75static struct GNUNET_TESTING_Command local_prepared;
76
77
78/**
79 * Function called to check a message of type GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE being
80 * received.
81 *
82 */
83static int
84check_test (void *cls,
85 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
86{
87 return GNUNET_OK;
88}
89
90
91/**
92 * Function called to handle a message of type GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE
93 * being received.
94 *
95 */
96static void
97handle_test (void *cls,
98 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
99{
100 const struct GNUNET_TESTING_AsyncContext *ac;
101
102 GNUNET_TESTING_get_trait_async_context (&block_receive,
103 &ac);
104 GNUNET_assert (NULL != ac);
105 if (NULL == ac->cont)
106 GNUNET_TESTING_async_fail ((struct GNUNET_TESTING_AsyncContext *) ac);
107 else
108 GNUNET_TESTING_async_finish ((struct GNUNET_TESTING_AsyncContext *) ac);
109}
110
111
112/**
113 * Callback to set the flag indicating all peers started. Will be called via the plugin api.
114 *
115 */
116static void
117all_peers_started ()
118{
119 const struct GNUNET_TESTING_AsyncContext *ac;
120
121 GNUNET_TESTING_get_trait_async_context (&block_send,
122 &ac);
123 GNUNET_assert (NULL != ac);
124 if (NULL == ac->cont)
125 GNUNET_TESTING_async_fail ((struct GNUNET_TESTING_AsyncContext *) ac);
126 else
127 GNUNET_TESTING_async_finish ((struct GNUNET_TESTING_AsyncContext *) ac);
128}
129
130
131/**
132 * Function called with the final result of the test.
133 *
134 * @param cls the `struct MainParams`
135 * @param rv #GNUNET_OK if the test passed
136 */
137static void
138handle_result (void *cls,
139 enum GNUNET_GenericReturnValue rv)
140{
141 struct TestState *ts = cls;
142 struct GNUNET_MessageHeader *reply;
143
144 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
145 "Local test exits with status %d\n",
146 rv);
147 reply = GNUNET_TESTING_send_local_test_finished_msg (rv);
148
149 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
150 "message prepared\n");
151 ts->write_message (reply,
152 ntohs (reply->size));
153 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
154 "message send\n");
155 GNUNET_free (ts->testdir);
156 GNUNET_free (ts->cfgname);
157 GNUNET_TESTING_free_topology (ts->topology);
158 GNUNET_free (ts);
159}
160
161
162/**
163 * Callback from start peer cmd for signaling a peer got connected.
164 *
165 */
166static void *
167notify_connect (struct GNUNET_TESTING_Interpreter *is,
168 const struct GNUNET_PeerIdentity *peer)
169{
170 const struct ConnectPeersState *cps;
171 const struct GNUNET_TESTING_Command *cmd;
172
173 cmd = GNUNET_TESTING_interpreter_lookup_command (is,
174 "connect-peers");
175 GNUNET_TRANSPORT_get_trait_connect_peer_state (cmd,
176 &cps);
177 void *ret = NULL;
178
179 cps->notify_connect (is,
180 peer);
181 return ret;
182}
183
184
185/**
186 * Callback to set the flag indicating all peers are prepared to finish. Will be called via the plugin api.
187 */
188static void
189all_local_tests_prepared ()
190{
191 const struct LocalPreparedState *lfs;
192
193 GNUNET_TESTING_get_trait_local_prepared_state (&local_prepared,
194 &lfs);
195 GNUNET_assert (NULL != &lfs->ac);
196 if (NULL == lfs->ac.cont)
197 GNUNET_TESTING_async_fail ((struct GNUNET_TESTING_AsyncContext *) &lfs->ac);
198 else
199 GNUNET_TESTING_async_finish ((struct
200 GNUNET_TESTING_AsyncContext *) &lfs->ac);
201}
202
203
204/**
205 * Function to start a local test case.
206 *
207 * @param write_message Callback to send a message to the master loop.
208 * @param router_ip Global address of the network namespace.
209 * @param node_ip Local address of a node i a network namespace.
210 * @param m The number of the node in a network namespace.
211 * @param n The number of the network namespace.
212 * @param local_m The number of nodes in a network namespace.
213 */
214static void
215start_testcase (TESTING_CMD_HELPER_write_cb write_message, char *router_ip,
216 char *node_ip,
217 char *m,
218 char *n,
219 char *local_m,
220 char *topology_data,
221 unsigned int *read_file)
222{
223
224 unsigned int n_int;
225 unsigned int m_int;
226 unsigned int local_m_int;
227 unsigned int num;
228 struct TestState *ts = GNUNET_new (struct TestState);
229 struct GNUNET_TESTING_NetjailTopology *topology;
230
231 if (GNUNET_YES == *read_file)
232 {
233 LOG (GNUNET_ERROR_TYPE_DEBUG,
234 "read from file\n");
235 topology = GNUNET_TESTING_get_topo_from_file (topology_data);
236 }
237 else
238 topology = GNUNET_TESTING_get_topo_from_string (topology_data);
239
240 ts->topology = topology;
241
242 sscanf (m, "%u", &m_int);
243 sscanf (n, "%u", &n_int);
244 sscanf (local_m, "%u", &local_m_int);
245
246 if (0 == n_int)
247 num = m_int;
248 else
249 num = (n_int - 1) * local_m_int + m_int + topology->nodes_x;
250
251 block_send = GNUNET_TESTING_cmd_block_until_external_trigger (
252 "block");
253 block_receive = GNUNET_TESTING_cmd_block_until_external_trigger (
254 "block-receive");
255 connect_peers = GNUNET_TRANSPORT_cmd_connect_peers ("connect-peers",
256 "start-peer",
257 "system-create",
258 num,
259 topology,
260 0);
261 local_prepared = GNUNET_TESTING_cmd_local_test_prepared (
262 "local-test-prepared",
263 write_message);
264
265
266 GNUNET_asprintf (&ts->cfgname,
267 "test_transport_api2_tcp_node1.conf");
268
269 LOG (GNUNET_ERROR_TYPE_DEBUG,
270 "plugin cfgname: %s\n",
271 ts->cfgname);
272
273 LOG (GNUNET_ERROR_TYPE_DEBUG,
274 "node ip: %s\n",
275 node_ip);
276
277 GNUNET_asprintf (&ts->testdir,
278 "%s%s%s",
279 BASE_DIR,
280 m,
281 n);
282
283 struct GNUNET_MQ_MessageHandler handlers[] = {
284 GNUNET_MQ_hd_var_size (test,
285 GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE,
286 struct GNUNET_TRANSPORT_TESTING_TestMessage,
287 ts),
288 GNUNET_MQ_handler_end ()
289 };
290
291 struct GNUNET_TESTING_Command commands[] = {
292 GNUNET_TESTING_cmd_system_create ("system-create",
293 ts->testdir),
294 GNUNET_TRANSPORT_cmd_start_peer ("start-peer",
295 "system-create",
296 num,
297 node_ip,
298 handlers,
299 ts->cfgname,
300 notify_connect,
301 GNUNET_NO),
302 GNUNET_TESTING_cmd_send_peer_ready ("send-peer-ready",
303 write_message),
304 block_send,
305 connect_peers,
306 GNUNET_TRANSPORT_cmd_send_simple ("send-simple",
307 "start-peer",
308 "system-create",
309 num,
310 topology),
311 block_receive,
312 local_prepared,
313 GNUNET_TRANSPORT_cmd_stop_peer ("stop-peer",
314 "start-peer"),
315 GNUNET_TESTING_cmd_system_destroy ("system-destroy",
316 "system-create"),
317 GNUNET_TESTING_cmd_end ()
318 };
319
320 ts->write_message = write_message;
321
322 GNUNET_TESTING_run (commands,
323 GNUNET_TIME_UNIT_FOREVER_REL,
324 &handle_result,
325 ts);
326
327}
328
329
330/**
331 * Entry point for the plugin.
332 *
333 * @param cls NULL
334 * @return the exported block API
335 */
336void *
337libgnunet_test_transport_plugin_cmd_simple_send_init (void *cls)
338{
339 struct GNUNET_TESTING_PluginFunctions *api;
340
341 GNUNET_log_setup ("simple-send",
342 "DEBUG",
343 NULL);
344
345 api = GNUNET_new (struct GNUNET_TESTING_PluginFunctions);
346 api->start_testcase = &start_testcase;
347 api->all_peers_started = &all_peers_started;
348 api->all_local_tests_prepared = all_local_tests_prepared;
349 return api;
350}
351
352
353/**
354 * Exit point from the plugin.
355 *
356 * @param cls the return value from #libgnunet_test_transport_plugin_block_test_init
357 * @return NULL
358 */
359void *
360libgnunet_test_transport_plugin_cmd_simple_send_done (void *cls)
361{
362 struct GNUNET_TESTING_PluginFunctions *api = cls;
363
364 GNUNET_free (api);
365 return NULL;
366}
367
368
369/* end of plugin_cmd_simple_send.c */
diff --git a/src/transport/test_transport_plugin_cmd_simple_send_broadcast.c b/src/transport/test_transport_plugin_cmd_simple_send_broadcast.c
deleted file mode 100644
index 9d6844be1..000000000
--- a/src/transport/test_transport_plugin_cmd_simple_send_broadcast.c
+++ /dev/null
@@ -1,398 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2021 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/plugin_cmd_simple_send_broadcast.c
23 * @brief a plugin to provide the API for running test cases.
24 * @author t3sserakt
25 */
26#include "platform.h"
27#include "gnunet_testing_ng_lib.h"
28#include "gnunet_testing_netjail_lib.h"
29#include "gnunet_util_lib.h"
30#include "gnunet_transport_application_service.h"
31#include "transport-testing2.h"
32#include "transport-testing-cmds.h"
33
34/**
35 * Generic logging shortcut
36 */
37#define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__)
38
39#define BASE_DIR "testdir"
40
41#define TOPOLOGY_CONFIG "test_transport_simple_send_topo.conf"
42
43struct TestState
44{
45 /**
46 * Callback to write messages to the master loop.
47 *
48 */
49 TESTING_CMD_HELPER_write_cb write_message;
50
51 /**
52 * The name for a specific test environment directory.
53 *
54 */
55 char *testdir;
56
57 /**
58 * The name for the configuration file of the specific node.
59 *
60 */
61 char *cfgname;
62
63 /**
64 * The complete topology information.
65 */
66 struct GNUNET_TESTING_NetjailTopology *topology;
67};
68
69static struct GNUNET_TESTING_Command block_send;
70
71static struct GNUNET_TESTING_Command block_receive;
72
73static struct GNUNET_TESTING_Command connect_peers;
74
75static struct GNUNET_TESTING_Command local_prepared;
76
77/**
78 * Function called to check a message of type GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE being
79 * received.
80 *
81 */
82static int
83check_test (void *cls,
84 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
85{
86 return GNUNET_OK;
87}
88
89
90/**
91 * Function called to handle a message of type GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE
92 * being received.
93 *
94 */
95static void
96handle_test (void *cls,
97 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
98{
99 const struct GNUNET_TESTING_AsyncContext *ac;
100
101 GNUNET_TESTING_get_trait_async_context (&block_receive,
102 &ac);
103 GNUNET_assert (NULL != ac);
104 if ((GNUNET_NO == ac->finished) && (NULL == ac->cont))
105 GNUNET_TESTING_async_fail ((struct GNUNET_TESTING_AsyncContext *) ac);
106 else if (GNUNET_NO == ac->finished)
107 GNUNET_TESTING_async_finish ((struct GNUNET_TESTING_AsyncContext *) ac);
108}
109
110
111/**
112 * Callback to set the flag indicating all peers started. Will be called via the plugin api.
113 *
114 */
115static void
116all_peers_started ()
117{
118 const struct GNUNET_TESTING_AsyncContext *ac;
119
120 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
121 "Received message\n");
122 GNUNET_TESTING_get_trait_async_context (&block_send,
123 &ac);
124 GNUNET_assert (NULL != ac);
125 if (NULL == ac->cont)
126 GNUNET_TESTING_async_fail ((struct GNUNET_TESTING_AsyncContext *) ac);
127 else
128 GNUNET_TESTING_async_finish ((struct GNUNET_TESTING_AsyncContext *) ac);
129}
130
131
132/**
133 * Function called with the final result of the test.
134 *
135 * @param cls the `struct MainParams`
136 * @param rv #GNUNET_OK if the test passed
137 */
138static void
139handle_result (void *cls,
140 enum GNUNET_GenericReturnValue rv)
141{
142 struct TestState *ts = cls;
143 struct GNUNET_MessageHeader *reply;
144
145 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
146 "Local test exits with status %d\n",
147 rv);
148 reply = GNUNET_TESTING_send_local_test_finished_msg (rv);
149
150 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
151 "message prepared\n");
152 ts->write_message (reply,
153 ntohs (reply->size));
154 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
155 "message send\n");
156 GNUNET_free (ts->testdir);
157 GNUNET_free (ts->cfgname);
158 GNUNET_TESTING_free_topology (ts->topology);
159 GNUNET_free (ts);
160}
161
162
163/**
164 * Callback from start peer cmd for signaling a peer got connected.
165 *
166 */
167static void *
168notify_connect (struct GNUNET_TESTING_Interpreter *is,
169 const struct GNUNET_PeerIdentity *peer)
170{
171 const struct GNUNET_TESTING_AsyncContext *ac;
172 void *ret = NULL;
173 const struct GNUNET_TESTING_Command *cmd;
174 struct BlockState *bs;
175
176
177 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
178 "notify_connect\n");
179
180 GNUNET_TESTING_get_trait_async_context (&connect_peers,
181 &ac);
182
183 if (NULL != ac->is)
184 {
185 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
186 "notify_connect running\n");
187 GNUNET_assert (NULL != ac);
188 if (NULL == ac->cont)
189 GNUNET_TESTING_async_fail ((struct GNUNET_TESTING_AsyncContext *) ac);
190 else
191 GNUNET_TESTING_async_finish ((struct GNUNET_TESTING_AsyncContext *) ac);
192 }
193 else
194 {
195 cmd = GNUNET_TESTING_interpreter_lookup_future_command (is,
196 "connect-peers");
197
198 LOG (GNUNET_ERROR_TYPE_DEBUG,
199 "block state %s\n",
200 cmd->label);
201 GNUNET_TESTING_get_trait_block_state (
202 cmd,
203 (const struct BlockState **) &bs);
204
205 LOG (GNUNET_ERROR_TYPE_DEBUG,
206 "block state %u\n",
207 bs->asynchronous_finish);
208 bs->asynchronous_finish = GNUNET_YES;
209 LOG (GNUNET_ERROR_TYPE_DEBUG,
210 "block state %u\n",
211 bs->asynchronous_finish);
212 }
213
214 return ret;
215}
216
217
218/**
219 * Callback to set the flag indicating all peers are prepared to finish. Will be called via the plugin api.
220 */
221static void
222all_local_tests_prepared ()
223{
224 const struct LocalPreparedState *lfs;
225
226 GNUNET_TESTING_get_trait_local_prepared_state (&local_prepared,
227 &lfs);
228 GNUNET_assert (NULL != &lfs->ac);
229 if (NULL == lfs->ac.cont)
230 GNUNET_TESTING_async_fail ((struct GNUNET_TESTING_AsyncContext *) &lfs->ac);
231 else
232 GNUNET_TESTING_async_finish ((struct
233 GNUNET_TESTING_AsyncContext *) &lfs->ac);
234}
235
236
237/**
238 * Function to start a local test case.
239 *
240 * @param write_message Callback to send a message to the master loop.
241 * @param router_ip Global address of the network namespace.
242 * @param node_ip Local address of a node i a network namespace.
243 * @param m The number of the node in a network namespace.
244 * @param n The number of the network namespace.
245 * @param local_m The number of nodes in a network namespace.
246 */
247static void
248start_testcase (TESTING_CMD_HELPER_write_cb write_message, char *router_ip,
249 char *node_ip,
250 char *m,
251 char *n,
252 char *local_m,
253 char *topology_data,
254 unsigned int *read_file)
255{
256 unsigned int n_int;
257 unsigned int m_int;
258 unsigned int local_m_int;
259 unsigned int num;
260 struct TestState *ts = GNUNET_new (struct TestState);
261 struct GNUNET_TESTING_NetjailTopology *topology;
262
263
264
265 if (GNUNET_YES == *read_file)
266 {
267 LOG (GNUNET_ERROR_TYPE_DEBUG,
268 "read from file\n");
269 topology = GNUNET_TESTING_get_topo_from_file (topology_data);
270 }
271 else
272 topology = GNUNET_TESTING_get_topo_from_string (topology_data);
273
274 ts->topology = topology;
275
276 sscanf (m, "%u", &m_int);
277 sscanf (n, "%u", &n_int);
278 sscanf (local_m, "%u", &local_m_int);
279
280 if (0 == n_int)
281 num = m_int;
282 else
283 num = (n_int - 1) * local_m_int + m_int + topology->nodes_x;
284
285 block_send = GNUNET_TESTING_cmd_block_until_external_trigger ("block");
286 block_receive = GNUNET_TESTING_cmd_block_until_external_trigger (
287 "block-receive");
288 connect_peers = GNUNET_TESTING_cmd_block_until_external_trigger (
289 "connect-peers");
290 local_prepared = GNUNET_TESTING_cmd_local_test_prepared (
291 "local-test-prepared",
292 write_message);
293
294
295 GNUNET_asprintf (&ts->cfgname,
296 "test_transport_api2_tcp_node1.conf");
297
298 LOG (GNUNET_ERROR_TYPE_DEBUG,
299 "plugin cfgname: %s\n",
300 ts->cfgname);
301
302 LOG (GNUNET_ERROR_TYPE_DEBUG,
303 "node ip: %s\n",
304 node_ip);
305
306 GNUNET_asprintf (&ts->testdir,
307 "%s%s%s",
308 BASE_DIR,
309 m,
310 n);
311
312 struct GNUNET_MQ_MessageHandler handlers[] = {
313 GNUNET_MQ_hd_var_size (test,
314 GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE,
315 struct GNUNET_TRANSPORT_TESTING_TestMessage,
316 ts),
317 GNUNET_MQ_handler_end ()
318 };
319
320 struct GNUNET_TESTING_Command commands[] = {
321 GNUNET_TESTING_cmd_system_create ("system-create",
322 ts->testdir),
323 GNUNET_TRANSPORT_cmd_start_peer ("start-peer",
324 "system-create",
325 num,
326 node_ip,
327 handlers,
328 ts->cfgname,
329 notify_connect,
330 GNUNET_YES),
331 GNUNET_TESTING_cmd_send_peer_ready ("send-peer-ready",
332 write_message),
333 block_send,
334 connect_peers,
335 GNUNET_TRANSPORT_cmd_send_simple ("send-simple",
336 "start-peer",
337 "system-create",
338 num,
339 topology),
340 block_receive,
341 local_prepared,
342 GNUNET_TRANSPORT_cmd_stop_peer ("stop-peer",
343 "start-peer"),
344 GNUNET_TESTING_cmd_system_destroy ("system-destroy",
345 "system-create"),
346 GNUNET_TESTING_cmd_end ()
347 };
348
349 ts->write_message = write_message;
350
351 GNUNET_TESTING_run (commands,
352 GNUNET_TIME_UNIT_FOREVER_REL,
353 &handle_result,
354 ts);
355
356}
357
358
359/**
360 * Entry point for the plugin.
361 *
362 * @param cls NULL
363 * @return the exported block API
364 */
365void *
366libgnunet_test_transport_plugin_cmd_simple_send_broadcast_init (void *cls)
367{
368 struct GNUNET_TESTING_PluginFunctions *api;
369
370 GNUNET_log_setup ("simple-send",
371 "DEBUG",
372 NULL);
373
374 api = GNUNET_new (struct GNUNET_TESTING_PluginFunctions);
375 api->start_testcase = &start_testcase;
376 api->all_peers_started = &all_peers_started;
377 api->all_local_tests_prepared = all_local_tests_prepared;
378 return api;
379}
380
381
382/**
383 * Exit point from the plugin.
384 *
385 * @param cls the return value from #libgnunet_test_transport_plugin_block_test_init
386 * @return NULL
387 */
388void *
389libgnunet_test_transport_plugin_cmd_simple_send_broadcast_done (void *cls)
390{
391 struct GNUNET_TESTING_PluginFunctions *api = cls;
392
393 GNUNET_free (api);
394 return NULL;
395}
396
397
398/* end of plugin_cmd_simple_send_broadcast.c */
diff --git a/src/transport/test_transport_plugin_cmd_simple_send_dv.c b/src/transport/test_transport_plugin_cmd_simple_send_dv.c
deleted file mode 100644
index f1f168102..000000000
--- a/src/transport/test_transport_plugin_cmd_simple_send_dv.c
+++ /dev/null
@@ -1,427 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2021 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/plugin_cmd_simple_send_broadcast.c
23 * @brief a plugin to provide the API for running test cases.
24 * @author t3sserakt
25 */
26#include "platform.h"
27#include "gnunet_testing_ng_lib.h"
28#include "gnunet_testing_netjail_lib.h"
29#include "gnunet_util_lib.h"
30#include "gnunet_transport_application_service.h"
31#include "transport-testing2.h"
32#include "transport-testing-cmds.h"
33
34/**
35 * Generic logging shortcut
36 */
37#define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__)
38
39#define BASE_DIR "testdir"
40
41#define TOPOLOGY_CONFIG "test_transport_simple_send_topo.conf"
42
43struct TestState
44{
45 /**
46 * Callback to write messages to the master loop.
47 *
48 */
49 TESTING_CMD_HELPER_write_cb write_message;
50
51 /**
52 * The name for a specific test environment directory.
53 *
54 */
55 char *testdir;
56
57 /**
58 * The name for the configuration file of the specific node.
59 *
60 */
61 char *cfgname;
62
63 /**
64 * The complete topology information.
65 */
66 struct GNUNET_TESTING_NetjailTopology *topology;
67
68};
69
70/**
71 * The number of messages received.
72 */
73static unsigned int number_received;
74
75static struct GNUNET_TESTING_Command block_send;
76
77static struct GNUNET_TESTING_Command block_receive;
78
79static struct GNUNET_TESTING_Command connect_peers;
80
81static struct GNUNET_TESTING_Command local_prepared;
82
83static struct GNUNET_TESTING_Command start_peer;
84
85/**
86 * Function called to check a message of type GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE being
87 * received.
88 *
89 */
90static int
91check_test (void *cls,
92 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
93{
94 GNUNET_assert (NULL != cls);
95 return GNUNET_OK;
96}
97
98
99/**
100 * Function called to handle a message of type GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE
101 * being received.
102 *
103 */
104static void
105handle_test (void *cls,
106 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
107{
108 struct GNUNET_PeerIdentity *peer = cls;
109 const struct GNUNET_TESTING_AsyncContext *ac_block;
110 const struct GNUNET_TESTING_AsyncContext *ac_start;
111 const struct GNUNET_TESTING_Command *cmd;
112 const struct GNUNET_CONTAINER_MultiShortmap *connected_peers_map;
113 unsigned int connected;
114 struct BlockState *bs;
115 struct GNUNET_TRANSPORT_CoreHandle *ch;
116 const struct StartPeerState *sps;
117
118
119 GNUNET_TRANSPORT_get_trait_state (&start_peer,
120 &sps);
121 ch = sps->th;
122 GNUNET_TRANSPORT_get_trait_connected_peers_map (&start_peer,
123 &connected_peers_map);
124
125 if (NULL != connected_peers_map)
126 {
127 connected = GNUNET_CONTAINER_multishortmap_size (
128 connected_peers_map);
129
130 number_received++;
131 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
132 "Received %u test message(s) from %s, %u connected peer(s)\n",
133 number_received,
134 GNUNET_i2s (peer),
135 connected);
136
137 GNUNET_TESTING_get_trait_async_context (&block_receive,
138 &ac_block);
139
140 if ( connected == number_received)
141 {
142 if (NULL != ac_block->is)
143 {
144 GNUNET_assert (NULL != ac_block);
145 if (NULL == ac_block->cont)
146 GNUNET_TESTING_async_fail ((struct
147 GNUNET_TESTING_AsyncContext *) ac_block);
148 else
149 GNUNET_TESTING_async_finish ((struct
150 GNUNET_TESTING_AsyncContext *) ac_block);
151 }
152 else
153 {
154 GNUNET_TESTING_get_trait_block_state (
155 &block_receive,
156 (const struct BlockState **) &bs);
157 bs->asynchronous_finish = GNUNET_YES;
158 }
159
160 }
161 }
162 GNUNET_TRANSPORT_core_receive_continue (ch, peer);
163}
164
165
166/**
167 * Callback to set the flag indicating all peers started. Will be called via the plugin api.
168 *
169 */
170static void
171all_peers_started ()
172{
173 const struct GNUNET_TESTING_AsyncContext *ac;
174
175 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
176 "Received message\n");
177 GNUNET_TESTING_get_trait_async_context (&block_send,
178 &ac);
179 GNUNET_assert (NULL != ac);
180 if (NULL == ac->cont)
181 GNUNET_TESTING_async_fail ((struct GNUNET_TESTING_AsyncContext *) ac);
182 else
183 GNUNET_TESTING_async_finish ((struct GNUNET_TESTING_AsyncContext *) ac);
184}
185
186
187/**
188 * Function called with the final result of the test.
189 *
190 * @param cls the `struct MainParams`
191 * @param rv #GNUNET_OK if the test passed
192 */
193static void
194handle_result (void *cls,
195 enum GNUNET_GenericReturnValue rv)
196{
197 struct TestState *ts = cls;
198 struct GNUNET_MessageHeader *reply;
199
200 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
201 "Local test exits with status %d\n",
202 rv);
203 reply = GNUNET_TESTING_send_local_test_finished_msg (rv);
204
205 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
206 "message prepared\n");
207 ts->write_message (reply,
208 ntohs (reply->size));
209 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
210 "message send\n");
211 GNUNET_free (ts->testdir);
212 GNUNET_free (ts->cfgname);
213 GNUNET_TESTING_free_topology (ts->topology);
214 GNUNET_free (ts);
215}
216
217
218/**
219 * Callback from start peer cmd for signaling a peer got connected.
220 *
221 */
222static void *
223notify_connect (struct GNUNET_TESTING_Interpreter *is,
224 const struct GNUNET_PeerIdentity *peer)
225{
226 const struct ConnectPeersState *cps;
227 const struct GNUNET_TESTING_Command *cmd;
228 void *ret = NULL;
229
230 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
231 "notify_connect peer %s\n",
232 GNUNET_i2s (peer));
233 cmd = GNUNET_TESTING_interpreter_lookup_command_all (is,
234 "connect-peers");
235 GNUNET_TRANSPORT_get_trait_connect_peer_state (cmd,
236 &cps);
237 cps->notify_connect (is,
238 peer);
239
240 return ret;
241}
242
243
244/**
245 * Callback to set the flag indicating all peers are prepared to finish. Will be called via the plugin api.
246 */
247static void
248all_local_tests_prepared ()
249{
250 const struct LocalPreparedState *lfs;
251
252 GNUNET_TESTING_get_trait_local_prepared_state (&local_prepared,
253 &lfs);
254 GNUNET_assert (NULL != &lfs->ac);
255 if (NULL == lfs->ac.cont)
256 GNUNET_TESTING_async_fail ((struct GNUNET_TESTING_AsyncContext *) &lfs->ac);
257 else
258 GNUNET_TESTING_async_finish ((struct
259 GNUNET_TESTING_AsyncContext *) &lfs->ac);
260}
261
262
263/**
264 * Function to start a local test case.
265 *
266 * @param write_message Callback to send a message to the master loop.
267 * @param router_ip Global address of the network namespace.
268 * @param node_ip Local address of a node i a network namespace.
269 * @param m The number of the node in a network namespace.
270 * @param n The number of the network namespace.
271 * @param local_m The number of nodes in a network namespace.
272 */
273static void
274start_testcase (TESTING_CMD_HELPER_write_cb write_message, char *router_ip,
275 char *node_ip,
276 char *m,
277 char *n,
278 char *local_m,
279 char *topology_data,
280 unsigned int *read_file)
281{
282 unsigned int n_int;
283 unsigned int m_int;
284 unsigned int local_m_int;
285 unsigned int num;
286 struct TestState *ts = GNUNET_new (struct TestState);
287 struct GNUNET_TESTING_NetjailTopology *topology;
288 struct GNUNET_MQ_MessageHandler handlers[] = {
289 GNUNET_MQ_hd_var_size (test,
290 GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE,
291 struct GNUNET_TRANSPORT_TESTING_TestMessage,
292 ts),
293 GNUNET_MQ_handler_end ()
294 };
295
296 if (GNUNET_YES == *read_file)
297 {
298 LOG (GNUNET_ERROR_TYPE_DEBUG,
299 "read from file\n");
300 topology = GNUNET_TESTING_get_topo_from_file (topology_data);
301 }
302 else
303 topology = GNUNET_TESTING_get_topo_from_string (topology_data);
304
305 ts->topology = topology;
306
307 sscanf (m, "%u", &m_int);
308 sscanf (n, "%u", &n_int);
309 sscanf (local_m, "%u", &local_m_int);
310
311 if (0 == n_int)
312 num = m_int;
313 else
314 num = (n_int - 1) * local_m_int + m_int + topology->nodes_x;
315
316 block_send = GNUNET_TESTING_cmd_block_until_external_trigger ("block");
317 block_receive = GNUNET_TESTING_cmd_block_until_external_trigger (
318 "block-receive");
319 connect_peers = GNUNET_TRANSPORT_cmd_connect_peers (
320 "connect-peers",
321 "start-peer",
322 "system-create",
323 num,
324 topology,
325 topology->additional_connects);
326 local_prepared = GNUNET_TESTING_cmd_local_test_prepared (
327 "local-test-prepared",
328 write_message);
329
330
331 GNUNET_asprintf (&ts->cfgname,
332 "test_transport_api2_tcp_node1.conf");
333
334 LOG (GNUNET_ERROR_TYPE_DEBUG,
335 "plugin cfgname: %s\n",
336 ts->cfgname);
337
338 LOG (GNUNET_ERROR_TYPE_DEBUG,
339 "node ip: %s\n",
340 node_ip);
341
342 GNUNET_asprintf (&ts->testdir,
343 "%s%s%s",
344 BASE_DIR,
345 m,
346 n);
347
348 start_peer = GNUNET_TRANSPORT_cmd_start_peer ("start-peer",
349 "system-create",
350 num,
351 node_ip,
352 handlers,
353 ts->cfgname,
354 notify_connect,
355 GNUNET_NO);
356 struct GNUNET_TESTING_Command commands[] = {
357 GNUNET_TESTING_cmd_system_create ("system-create",
358 ts->testdir),
359 start_peer,
360 GNUNET_TESTING_cmd_send_peer_ready ("send-peer-ready",
361 write_message),
362 block_send,
363 connect_peers,
364 GNUNET_TRANSPORT_cmd_send_simple ("send-simple",
365 "start-peer",
366 "system-create",
367 num,
368 topology),
369 block_receive,
370 local_prepared,
371 GNUNET_TRANSPORT_cmd_stop_peer ("stop-peer",
372 "start-peer"),
373 GNUNET_TESTING_cmd_system_destroy ("system-destroy",
374 "system-create"),
375 GNUNET_TESTING_cmd_end ()
376 };
377
378 ts->write_message = write_message;
379
380 GNUNET_TESTING_run (commands,
381 GNUNET_TIME_UNIT_FOREVER_REL,
382 &handle_result,
383 ts);
384
385}
386
387
388/**
389 * Entry point for the plugin.
390 *
391 * @param cls NULL
392 * @return the exported block API
393 */
394void *
395libgnunet_test_transport_plugin_cmd_simple_send_dv_init (void *cls)
396{
397 struct GNUNET_TESTING_PluginFunctions *api;
398
399 GNUNET_log_setup ("simple-send",
400 "DEBUG",
401 NULL);
402
403 api = GNUNET_new (struct GNUNET_TESTING_PluginFunctions);
404 api->start_testcase = &start_testcase;
405 api->all_peers_started = &all_peers_started;
406 api->all_local_tests_prepared = all_local_tests_prepared;
407 return api;
408}
409
410
411/**
412 * Exit point from the plugin.
413 *
414 * @param cls the return value from #libgnunet_test_transport_plugin_block_test_init
415 * @return NULL
416 */
417void *
418libgnunet_test_transport_plugin_cmd_simple_send_dv_done (void *cls)
419{
420 struct GNUNET_TESTING_PluginFunctions *api = cls;
421
422 GNUNET_free (api);
423 return NULL;
424}
425
426
427/* end of plugin_cmd_simple_send_broadcast.c */
diff --git a/src/transport/test_transport_plugin_cmd_udp_backchannel.c b/src/transport/test_transport_plugin_cmd_udp_backchannel.c
deleted file mode 100644
index 537832e61..000000000
--- a/src/transport/test_transport_plugin_cmd_udp_backchannel.c
+++ /dev/null
@@ -1,356 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2021 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/plugin_cmd_simple_send.c
23 * @brief a plugin to provide the API for running test cases.
24 * @author t3sserakt
25 */
26#include "platform.h"
27#include "gnunet_testing_ng_lib.h"
28#include "gnunet_testing_netjail_lib.h"
29#include "gnunet_util_lib.h"
30#include "gnunet_transport_application_service.h"
31#include "transport-testing2.h"
32#include "transport-testing-cmds.h"
33
34/**
35 * Generic logging shortcut
36 */
37#define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__)
38
39#define BASE_DIR "testdir"
40
41#define TOPOLOGY_CONFIG "test_transport_udp_backchannel_topo.conf"
42
43struct TestState
44{
45 /**
46 * Callback to write messages to the master loop.
47 *
48 */
49 TESTING_CMD_HELPER_write_cb write_message;
50
51 /**
52 * The name for a specific test environment directory.
53 *
54 */
55 char *testdir;
56
57 /**
58 * The name for the configuration file of the specific node.
59 *
60 */
61 char *cfgname;
62
63 /**
64 * The complete topology information.
65 */
66 struct GNUNET_TESTING_NetjailTopology *topology;
67};
68
69static struct GNUNET_TESTING_Command block_send;
70
71static struct GNUNET_TESTING_Command connect_peers;
72
73static struct GNUNET_TESTING_Command local_prepared;
74
75
76/**
77 * Function called to check a message of type GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE being
78 * received.
79 *
80 */
81static int
82check_test (void *cls,
83 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
84{
85 return GNUNET_OK;
86}
87
88
89/**
90 * Function called to handle a message of type GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE
91 * being received.
92 *
93 */
94static void
95handle_test (void *cls,
96 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
97{
98 // struct GNUNET_TESTING_AsyncContext *ac;
99
100 /*GNUNET_TESTING_get_trait_async_context (&block_receive,
101 &ac);
102 if ((NULL == ac) || (NULL == ac->cont))
103 GNUNET_TESTING_async_fail (ac);
104 else
105 GNUNET_TESTING_async_finish (ac);*/
106}
107
108
109/**
110 * Callback to set the flag indicating all peers started. Will be called via the plugin api.
111 *
112 */
113static void
114all_peers_started ()
115{
116 const struct GNUNET_TESTING_AsyncContext *ac;
117
118 GNUNET_TESTING_get_trait_async_context (&block_send,
119 &ac);
120 GNUNET_assert (NULL != ac);
121 if ((NULL == ac->cont))
122 GNUNET_TESTING_async_fail ((struct GNUNET_TESTING_AsyncContext *) ac);
123 else
124 GNUNET_TESTING_async_finish ((struct GNUNET_TESTING_AsyncContext *) ac);
125}
126
127
128/**
129* Function called with the final result of the test.
130*
131* @param cls the `struct MainParams`
132* @param rv #GNUNET_OK if the test passed
133*/
134static void
135handle_result (void *cls,
136 enum GNUNET_GenericReturnValue rv)
137{
138 struct TestState *ts = cls;
139 struct GNUNET_MessageHeader *reply;
140
141 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
142 "Local test exits with status %d\n",
143 rv);
144 reply = GNUNET_TESTING_send_local_test_finished_msg (rv);
145
146 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
147 "message prepared\n");
148 ts->write_message (reply,
149 ntohs (reply->size));
150
151 GNUNET_free (ts->testdir);
152 GNUNET_free (ts->cfgname);
153 GNUNET_TESTING_free_topology (ts->topology);
154 GNUNET_free (ts);
155}
156
157
158/**
159 * Callback from start peer cmd for signaling a peer got connected.
160 *
161 */
162static void *
163notify_connect (struct GNUNET_TESTING_Interpreter *is,
164 const struct GNUNET_PeerIdentity *peer)
165{
166 const struct ConnectPeersState *cps;
167
168 GNUNET_TRANSPORT_get_trait_connect_peer_state (&connect_peers,
169 &cps);
170 void *ret = NULL;
171
172 cps->notify_connect (is,
173 peer);
174 return ret;
175}
176
177/**
178 * Callback to set the flag indicating all peers are prepared to finish. Will be called via the plugin api.
179 */
180static void
181all_local_tests_prepared ()
182{
183 const struct LocalPreparedState *lfs;
184
185 GNUNET_TESTING_get_trait_local_prepared_state (&local_prepared,
186 &lfs);
187 GNUNET_assert (NULL != &lfs->ac);
188 if (NULL == lfs->ac.cont)
189 GNUNET_TESTING_async_fail ((struct GNUNET_TESTING_AsyncContext *) &lfs->ac);
190 else
191 GNUNET_TESTING_async_finish ((struct
192 GNUNET_TESTING_AsyncContext *) &lfs->ac);
193}
194
195/**
196 * Function to start a local test case.
197 *
198 * @param write_message Callback to send a message to the master loop.
199 * @param router_ip Global address of the network namespace.
200 * @param node_ip Local address of a node i a network namespace.
201 * @param m The number of the node in a network namespace.
202 * @param n The number of the network namespace.
203 * @param local_m The number of nodes in a network namespace.
204 */
205static void
206start_testcase (TESTING_CMD_HELPER_write_cb write_message, char *router_ip,
207 char *node_ip,
208 char *m,
209 char *n,
210 char *local_m,
211 char *topology_data,
212 unsigned int *read_file)
213{
214
215 unsigned int n_int;
216 unsigned int m_int;
217 unsigned int local_m_int;
218 unsigned int num;
219 struct TestState *ts = GNUNET_new (struct TestState);
220
221 struct GNUNET_TESTING_NetjailTopology *topology;
222
223 if (GNUNET_YES == *read_file)
224 topology = GNUNET_TESTING_get_topo_from_file (topology_data);
225 else
226 topology = GNUNET_TESTING_get_topo_from_string (topology_data);
227
228 ts->topology = topology;
229
230 sscanf (m, "%u", &m_int);
231 sscanf (n, "%u", &n_int);
232 sscanf (local_m, "%u", &local_m_int);
233
234
235 if (0 == n_int)
236 num = m_int;
237 else
238 num = (n_int - 1) * local_m_int + m_int + topology->nodes_x;
239
240 block_send = GNUNET_TESTING_cmd_block_until_external_trigger (
241 "block");
242 connect_peers = GNUNET_TRANSPORT_cmd_connect_peers ("connect-peers",
243 "start-peer",
244 "system-create",
245 num,
246 topology,
247 0);
248 local_prepared = GNUNET_TESTING_cmd_local_test_prepared (
249 "local-test-prepared",
250 write_message);
251
252 GNUNET_asprintf (&ts->cfgname,
253 "test_transport_api2_tcp_node1.conf");
254
255 LOG (GNUNET_ERROR_TYPE_DEBUG,
256 "plugin cfgname: %s\n",
257 ts->cfgname);
258
259 LOG (GNUNET_ERROR_TYPE_DEBUG,
260 "node ip: %s\n",
261 node_ip);
262
263 GNUNET_asprintf (&ts->testdir,
264 "%s%s%s",
265 BASE_DIR,
266 m,
267 n);
268
269 struct GNUNET_MQ_MessageHandler handlers[] = {
270 GNUNET_MQ_hd_var_size (test,
271 GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE,
272 struct GNUNET_TRANSPORT_TESTING_TestMessage,
273 NULL),
274 GNUNET_MQ_handler_end ()
275 };
276
277 struct GNUNET_TESTING_Command commands[] = {
278 GNUNET_TESTING_cmd_system_create ("system-create",
279 ts->testdir),
280 GNUNET_TRANSPORT_cmd_start_peer ("start-peer",
281 "system-create",
282 num,
283 node_ip,
284 handlers,
285 ts->cfgname,
286 notify_connect,
287 GNUNET_NO),
288 GNUNET_TESTING_cmd_send_peer_ready ("send-peer-ready",
289 write_message),
290 block_send,
291 connect_peers,
292 GNUNET_TRANSPORT_cmd_backchannel_check ("backchannel-check",
293 "start-peer",
294 "system-create",
295 num,
296 m_int,
297 n_int,
298 topology),
299 local_prepared,
300 GNUNET_TRANSPORT_cmd_stop_peer ("stop-peer",
301 "start-peer"),
302 GNUNET_TESTING_cmd_system_destroy ("system-destroy",
303 "system-create"),
304 GNUNET_TESTING_cmd_end ()
305 };
306
307 ts->write_message = write_message;
308
309 GNUNET_TESTING_run (commands,
310 GNUNET_TIME_UNIT_FOREVER_REL,
311 &handle_result,
312 ts);
313
314}
315
316
317/**
318 * Entry point for the plugin.
319 *
320 * @param cls NULL
321 * @return the exported block API
322 */
323void *
324libgnunet_test_transport_plugin_cmd_udp_backchannel_init (void *cls)
325{
326 struct GNUNET_TESTING_PluginFunctions *api;
327
328 GNUNET_log_setup ("udp-backchannel",
329 "DEBUG",
330 NULL);
331
332 api = GNUNET_new (struct GNUNET_TESTING_PluginFunctions);
333 api->start_testcase = &start_testcase;
334 api->all_peers_started = &all_peers_started;
335 api->all_local_tests_prepared = all_local_tests_prepared;
336 return api;
337}
338
339
340/**
341 * Exit point from the plugin.
342 *
343 * @param cls the return value from #libgnunet_test_transport_plugin_block_test_init
344 * @return NULL
345 */
346void *
347libgnunet_test_transport_plugin_cmd_udp_backchannel_done (void *cls)
348{
349 struct GNUNET_TESTING_PluginFunctions *api = cls;
350
351 GNUNET_free (api);
352 return NULL;
353}
354
355
356/* end of plugin_cmd_simple_send.c */
diff --git a/src/transport/test_transport_simple_send.sh b/src/transport/test_transport_simple_send.sh
deleted file mode 100755
index 0250070be..000000000
--- a/src/transport/test_transport_simple_send.sh
+++ /dev/null
@@ -1,11 +0,0 @@
1#!/bin/bash
2if ! [ -d "/run/netns" ]; then
3 echo You have to create the directory /run/netns.
4fi
5if [ -f /proc/sys/kernel/unprivileged_userns_clone ]; then
6 if [ "$(cat /proc/sys/kernel/unprivileged_userns_clone)" != 1 ]; then
7 echo -e "Error during test setup: The kernel parameter kernel.unprivileged_userns_clone has to be set to 1! One has to execute\n\n sysctl kernel.unprivileged_userns_clone=1\n"
8 exit 78
9 fi
10fi
11exec unshare -r -nmU bash -c "mount -t tmpfs --make-rshared tmpfs /run/netns; ./test_transport_start_with_config test_transport_simple_send_topo.conf"
diff --git a/src/transport/test_transport_simple_send_broadcast.sh b/src/transport/test_transport_simple_send_broadcast.sh
deleted file mode 100755
index a4801bf70..000000000
--- a/src/transport/test_transport_simple_send_broadcast.sh
+++ /dev/null
@@ -1,11 +0,0 @@
1#!/bin/bash
2if ! [ -d "/run/netns" ]; then
3 echo You have to create the directory /run/netns.
4fi
5if [ -f /proc/sys/kernel/unprivileged_userns_clone ]; then
6 if [ "$(cat /proc/sys/kernel/unprivileged_userns_clone)" != 1 ]; then
7 echo -e "Error during test setup: The kernel parameter kernel.unprivileged_userns_clone has to be set to 1! One has to execute\n\n sysctl kernel.unprivileged_userns_clone=1\n"
8 exit 78
9 fi
10fi
11exec unshare -r -nmU bash -c "mount -t tmpfs --make-rshared tmpfs /run/netns; ./test_transport_start_with_config test_transport_simple_send_broadcast_topo.conf"
diff --git a/src/transport/test_transport_simple_send_broadcast_topo.conf b/src/transport/test_transport_simple_send_broadcast_topo.conf
deleted file mode 100644
index aa4964f81..000000000
--- a/src/transport/test_transport_simple_send_broadcast_topo.conf
+++ /dev/null
@@ -1,4 +0,0 @@
1M:2
2N:1
3X:0
4T:libgnunet_test_transport_plugin_cmd_simple_send_broadcast \ No newline at end of file
diff --git a/src/transport/test_transport_simple_send_dv.sh b/src/transport/test_transport_simple_send_dv.sh
deleted file mode 100755
index b57ee0629..000000000
--- a/src/transport/test_transport_simple_send_dv.sh
+++ /dev/null
@@ -1,11 +0,0 @@
1#!/bin/bash
2if ! [ -d "/run/netns" ]; then
3 echo You have to create the directory /run/netns.
4fi
5if [ -f /proc/sys/kernel/unprivileged_userns_clone ]; then
6 if [ "$(cat /proc/sys/kernel/unprivileged_userns_clone)" != 1 ]; then
7 echo -e "Error during test setup: The kernel parameter kernel.unprivileged_userns_clone has to be set to 1! One has to execute\n\n sysctl kernel.unprivileged_userns_clone=1\n"
8 exit 78
9 fi
10fi
11exec unshare -r -nmU bash -c "mount -t tmpfs --make-rshared tmpfs /run/netns; ./test_transport_start_with_config test_transport_distance_vector_topo.conf"
diff --git a/src/transport/test_transport_simple_send_dv_circle.sh b/src/transport/test_transport_simple_send_dv_circle.sh
deleted file mode 100755
index bd5f00abe..000000000
--- a/src/transport/test_transport_simple_send_dv_circle.sh
+++ /dev/null
@@ -1,11 +0,0 @@
1#!/bin/bash
2if ! [ -d "/run/netns" ]; then
3 echo You have to create the directory /run/netns.
4fi
5if [ -f /proc/sys/kernel/unprivileged_userns_clone ]; then
6 if [ "$(cat /proc/sys/kernel/unprivileged_userns_clone)" != 1 ]; then
7 echo -e "Error during test setup: The kernel parameter kernel.unprivileged_userns_clone has to be set to 1! One has to execute\n\n sysctl kernel.unprivileged_userns_clone=1\n"
8 exit 78
9 fi
10fi
11exec unshare -r -nmU bash -c "mount -t tmpfs --make-rshared tmpfs /run/netns; ./test_transport_start_with_config test_transport_distance_vector_circle_topo.conf"
diff --git a/src/transport/test_transport_simple_send_string.sh b/src/transport/test_transport_simple_send_string.sh
deleted file mode 100755
index 211abb494..000000000
--- a/src/transport/test_transport_simple_send_string.sh
+++ /dev/null
@@ -1,21 +0,0 @@
1#!/bin/bash
2string=$(cat << EOF
3M:2
4N:1
5X:0
6T:libgnunet_test_transport_plugin_cmd_simple_send
7P:1:1|{connect:{P:1:2:tcp}}
8P:1:2|{connect:{P:1:1:tcp}}
9EOF
10 )
11if ! [ -d "/run/netns" ]; then
12 echo You have to create the directory /run/netns.
13fi
14if [ -f /proc/sys/kernel/unprivileged_userns_clone ]; then
15 if [ "$(cat /proc/sys/kernel/unprivileged_userns_clone)" != 1 ]; then
16 echo -e "Error during test setup: The kernel parameter kernel.unprivileged_userns_clone has to be set to 1! One has to execute\n\n sysctl kernel.unprivileged_userns_clone=1\n"
17 exit 78
18 fi
19fi
20
21exec unshare -r -nmU bash -c "mount -t tmpfs --make-rshared tmpfs /run/netns; ./test_transport_start_with_config -s '$string'"
diff --git a/src/transport/test_transport_simple_send_topo.conf b/src/transport/test_transport_simple_send_topo.conf
deleted file mode 100644
index 2c16201f5..000000000
--- a/src/transport/test_transport_simple_send_topo.conf
+++ /dev/null
@@ -1,6 +0,0 @@
1M:2
2N:1
3X:0
4T:libgnunet_test_transport_plugin_cmd_simple_send
5P:1:1|{connect:{P:1:2:tcp}}
6P:1:2|{connect:{P:1:1:tcp}} \ No newline at end of file
diff --git a/src/transport/test_transport_start_with_config.c b/src/transport/test_transport_start_with_config.c
deleted file mode 100644
index 0c3271436..000000000
--- a/src/transport/test_transport_start_with_config.c
+++ /dev/null
@@ -1,122 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2021 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/test_transport_start_with_config.c
23 * @brief Generic program to start testcases in an configurable topology.
24 * @author t3sserakt
25 */
26#include "platform.h"
27#include "gnunet_testing_ng_lib.h"
28#include "gnunet_testing_netjail_lib.h"
29#include "transport-testing-cmds.h"
30#include "gnunet_util_lib.h"
31
32#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 600)
33
34
35int
36main (int argc,
37 char *const *argv)
38{
39 char *topology_data;
40 char *topology_data_script;
41 struct GNUNET_TESTING_NetjailTopology *topology;
42 unsigned int read_file = GNUNET_YES;
43 int ret;
44 char *rest = NULL;
45 char *token;
46 size_t single_line_len;
47 size_t data_len;
48
49 GNUNET_log_setup ("test-netjail",
50 "DEBUG",
51 NULL);
52
53 if (0 == strcmp ("-s", argv[1]))
54 {
55 data_len = strlen (argv[2]);
56 topology_data = GNUNET_malloc (data_len);
57 topology_data_script = GNUNET_malloc (data_len);
58 token = strtok_r (argv[2], "\n", &rest);
59 while (NULL != token)
60 {
61 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
62 "token1 %s\n",
63 token);
64 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
65 "token2 %s\n",
66 token);
67 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
68 "topology_data %s\n",
69 topology_data);
70 strcat (topology_data_script, token);
71 strcat (topology_data_script, " ");
72 strcat (topology_data, token);
73 strcat (topology_data, "\n");
74 token = strtok_r (NULL, "\n", &rest);
75 }
76 single_line_len = strlen (topology_data);
77 topology_data_script [single_line_len - 1] = '\0';
78 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
79 "read from string\n");
80 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
81 "topology_data %s\n",
82 topology_data);
83 read_file = GNUNET_NO;
84 topology = GNUNET_TESTING_get_topo_from_string (topology_data);
85 }
86 else
87 {
88 topology_data = argv[1];
89 topology_data_script = argv[1];
90 topology = GNUNET_TESTING_get_topo_from_file (topology_data);
91 }
92
93 struct GNUNET_TESTING_Command commands[] = {
94 GNUNET_TESTING_cmd_netjail_start ("netjail-start",
95 topology_data_script,
96 &read_file),
97 GNUNET_TESTING_cmd_netjail_start_testing_system ("netjail-start-testbed",
98 topology,
99 &read_file,
100 topology_data_script,
101 TIMEOUT),
102 GNUNET_TESTING_cmd_stop_testing_system ("stop-testbed",
103 "netjail-start-testbed",
104 topology),
105 GNUNET_TESTING_cmd_netjail_stop ("netjail-stop",
106 topology_data_script,
107 &read_file),
108 GNUNET_TESTING_cmd_end ()
109 };
110
111 ret = GNUNET_TESTING_main (commands,
112 TIMEOUT);
113
114 if (0 == strcmp ("-s", argv[1]))
115 {
116 GNUNET_free (topology_data_script);
117 GNUNET_free (topology_data);
118 }
119 GNUNET_TESTING_free_topology (topology);
120
121 return ret;
122}
diff --git a/src/transport/test_transport_test_transport_address_switch_tcp_peer1.conf b/src/transport/test_transport_test_transport_address_switch_tcp_peer1.conf
deleted file mode 100644
index 920e8d199..000000000
--- a/src/transport/test_transport_test_transport_address_switch_tcp_peer1.conf
+++ /dev/null
@@ -1,29 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2
3[ats]
4UNSPECIFIED_QUOTA_IN = 8 KiB
5UNSPECIFIED_QUOTA_OUT = 8 KiB
6# LOOPBACK
7LOOPBACK_QUOTA_IN = 8 KiB
8LOOPBACK_QUOTA_OUT = 8 KiB
9# LAN
10LAN_QUOTA_IN = 8 KiB
11LAN_QUOTA_OUT = 8 KiB
12# WAN
13WAN_QUOTA_IN = 8 KiB
14WAN_QUOTA_OUT = 8 KiB
15# WLAN
16WLAN_QUOTA_IN = 8 KiB
17WLAN_QUOTA_OUT = 8 KiB
18# BLUETOOTH
19BLUETOOTH_QUOTA_IN = 8 KiB
20BLUETOOTH_QUOTA_OUT = 8 KiB
21
22[PATHS]
23GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/quota-tcp-p1/
24
25[transport]
26PLUGINS = tcp
27
28
29
diff --git a/src/transport/test_transport_test_transport_address_switch_tcp_peer2.conf b/src/transport/test_transport_test_transport_address_switch_tcp_peer2.conf
deleted file mode 100644
index 6855cd00d..000000000
--- a/src/transport/test_transport_test_transport_address_switch_tcp_peer2.conf
+++ /dev/null
@@ -1,29 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2
3[ats]
4UNSPECIFIED_QUOTA_IN = 8 KiB
5UNSPECIFIED_QUOTA_OUT = 8 KiB
6# LOOPBACK
7LOOPBACK_QUOTA_IN = 8 KiB
8LOOPBACK_QUOTA_OUT = 8 KiB
9# LAN
10LAN_QUOTA_IN = 8 KiB
11LAN_QUOTA_OUT = 8 KiB
12# WAN
13WAN_QUOTA_IN = 8 KiB
14WAN_QUOTA_OUT = 8 KiB
15# WLAN
16WLAN_QUOTA_IN = 8 KiB
17WLAN_QUOTA_OUT = 8 KiB
18# BLUETOOTH
19BLUETOOTH_QUOTA_IN = 8 KiB
20BLUETOOTH_QUOTA_OUT = 8 KiB
21
22
23[PATHS]
24GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
25
26[transport]
27PLUGINS = tcp
28
29
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/test_transport_testing_startstop.c b/src/transport/test_transport_testing_startstop.c
deleted file mode 100644
index 4783c1813..000000000
--- a/src/transport/test_transport_testing_startstop.c
+++ /dev/null
@@ -1,138 +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_startstop.c
22 * @brief test case for transport testing library:
23 * start the peer, get the HELLO message 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
67start_cb (void *cls)
68{
69 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
70 "Peer %u (`%s') successfully started\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
80run (void *cls,
81 char *const *args,
82 const char *cfgfile,
83 const struct GNUNET_CONFIGURATION_Handle *cfg)
84{
85 ret = 1;
86 tth = GNUNET_TRANSPORT_TESTING_init ();
87 GNUNET_assert (NULL != tth);
88
89 timeout_task =
90 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
91 &end_badly,
92 NULL);
93
94 p = GNUNET_TRANSPORT_TESTING_start_peer (tth,
95 cfgfile,
96 1,
97 NULL, /* receive cb */
98 NULL, /* connect cb */
99 NULL, /* disconnect cb */
100 NULL, /* nc/nd closure */
101 &start_cb, /* startup cb */
102 NULL); /* closure */
103 if (NULL == p)
104 {
105 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to start peer\n");
106 if (timeout_task != NULL)
107 GNUNET_SCHEDULER_cancel (timeout_task);
108 timeout_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
109 }
110}
111
112
113int
114main (int argc, char *argv[])
115{
116 char *const argv_1[] = { "test_transport_testing",
117 "-c",
118 "test_transport_api_data.conf",
119 NULL };
120 struct GNUNET_GETOPT_CommandLineOption options[] = {
121 GNUNET_GETOPT_OPTION_END
122 };
123
124 GNUNET_log_setup ("test_transport_testing_startstop",
125 "WARNING",
126 NULL);
127 GNUNET_PROGRAM_run ((sizeof(argv_1) / sizeof(char *)) - 1,
128 argv_1,
129 "test_transport_testing_startstop", "nohelp",
130 options,
131 &run,
132 &ret);
133
134 return ret;
135}
136
137
138/* end of test_transport_testing_startstop.c */
diff --git a/src/transport/test_transport_udp_backchannel.sh b/src/transport/test_transport_udp_backchannel.sh
deleted file mode 100755
index 1a7c83385..000000000
--- a/src/transport/test_transport_udp_backchannel.sh
+++ /dev/null
@@ -1,14 +0,0 @@
1#!/bin/bash
2if [ -f "test.out" ]; then
3 rm test.out
4fi
5if ! [ -d "/run/netns" ]; then
6 echo You have to create the directory /run/netns.
7fi
8if [ -f /proc/sys/kernel/unprivileged_userns_clone ]; then
9 if [ "$(cat /proc/sys/kernel/unprivileged_userns_clone)" != 1 ]; then
10 echo -e "Error during test setup: The kernel parameter kernel.unprivileged_userns_clone has to be set to 1! One has to execute\n\n sysctl kernel.unprivileged_userns_clone=1\n"
11 exit 78
12 fi
13fi
14exec unshare -r -nmU bash -c "mount -t tmpfs --make-rshared tmpfs /run/netns; GNUNET_FORCE_LOG=';;;;DEBUG' GNUNET_FORCE_LOGFILE='test.out' ./test_transport_start_with_config test_transport_udp_backchannel_topo.conf"
diff --git a/src/transport/test_transport_udp_backchannel_topo.conf b/src/transport/test_transport_udp_backchannel_topo.conf
deleted file mode 100644
index ad35bde0a..000000000
--- a/src/transport/test_transport_udp_backchannel_topo.conf
+++ /dev/null
@@ -1,7 +0,0 @@
1M:1
2N:1
3X:1
4T:libgnunet_test_transport_plugin_cmd_udp_backchannel
5K:1|{connect:{P:1:1:tcp}}
6R:1|{tcp_port:1}|{udp_port:0}
7P:1:1|{connect:{K:1:udp}}
diff --git a/src/transport/transport-testing-cmds.h b/src/transport/transport-testing-cmds.h
deleted file mode 100644
index 5a3fb22d6..000000000
--- a/src/transport/transport-testing-cmds.h
+++ /dev/null
@@ -1,347 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2021 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport-testing.h
23 * @brief testing lib for transport service
24 * @author Matthias Wachs
25 * @author Christian Grothoff
26 */
27#ifndef TRANSPORT_TESTING_CMDS_H
28#define TRANSPORT_TESTING_CMDS_H
29#include "gnunet_testing_lib.h"
30
31
32typedef void *
33(*GNUNET_TRANSPORT_notify_connect_cb) (struct GNUNET_TESTING_Interpreter *is,
34 const struct GNUNET_PeerIdentity *peer);
35
36/**
37 * Struct to store information needed in callbacks.
38 *
39 */
40struct ConnectPeersState
41{
42 /**
43 * Context for our asynchronous completion.
44 */
45 struct GNUNET_TESTING_AsyncContext ac;
46
47 GNUNET_TRANSPORT_notify_connect_cb notify_connect;
48
49 /**
50 * The testing system of this node.
51 */
52 const struct GNUNET_TESTING_System *tl_system;
53
54 // Label of the cmd which started the test system.
55 const char *create_label;
56
57 /**
58 * Number globally identifying the node.
59 *
60 */
61 uint32_t num;
62
63 /**
64 * Label of the cmd to start a peer.
65 *
66 */
67 const char *start_peer_label;
68
69 /**
70 * The topology of the test setup.
71 */
72 struct GNUNET_TESTING_NetjailTopology *topology;
73
74 /**
75 * Connections to other peers.
76 */
77 struct GNUNET_TESTING_NodeConnection *node_connections_head;
78
79 struct GNUNET_TESTING_Interpreter *is;
80
81 /**
82 * Number of connections.
83 */
84 unsigned int con_num;
85
86 /**
87 * Number of additional connects this cmd will wait for not triggered by this cmd.
88 */
89 unsigned int additional_connects;
90
91 /**
92 * Number of connections we already have a notification for.
93 */
94 unsigned int con_num_notified;
95
96 /**
97 * Number of additional connects this cmd will wait for not triggered by this cmd we already have a notification for.
98 */
99 unsigned int additional_connects_notified;
100};
101
102struct StartPeerState
103{
104 /**
105 * Context for our asynchronous completion.
106 */
107 struct GNUNET_TESTING_AsyncContext ac;
108
109 /**
110 * The ip of a node.
111 */
112 char *node_ip;
113
114 /**
115 * Receive callback
116 */
117 struct GNUNET_MQ_MessageHandler *handlers;
118
119 const char *cfgname;
120
121 /**
122 * Peer's configuration
123 */
124 struct GNUNET_CONFIGURATION_Handle *cfg;
125
126 struct GNUNET_TESTING_Peer *peer;
127
128 /**
129 * Peer identity
130 */
131 struct GNUNET_PeerIdentity id;
132
133 /**
134 * Peer's transport service handle
135 */
136 struct GNUNET_TRANSPORT_CoreHandle *th;
137
138 /**
139 * Application handle
140 */
141 struct GNUNET_TRANSPORT_ApplicationHandle *ah;
142
143 /**
144 * Peer's PEERSTORE Handle
145 */
146 struct GNUNET_PEERSTORE_Handle *ph;
147
148 /**
149 * Hello get task
150 */
151 struct GNUNET_SCHEDULER_Task *rh_task;
152
153 /**
154 * Peer's transport get hello handle to retrieve peer's HELLO message
155 */
156 struct GNUNET_PEERSTORE_IterateContext *pic;
157
158 /**
159 * Hello
160 */
161 char *hello;
162
163 /**
164 * Hello size
165 */
166 size_t hello_size;
167
168 char *m;
169
170 char *n;
171
172 char *local_m;
173
174 const char *system_label;
175
176 /**
177 * An unique number to identify the peer
178 */
179 unsigned int no;
180
181 struct GNUNET_CONTAINER_MultiShortmap *connected_peers_map;
182
183 const struct GNUNET_TESTING_System *tl_system;
184
185 GNUNET_TRANSPORT_notify_connect_cb notify_connect;
186
187 /**
188 * Flag indicating, if udp broadcast should be switched on.
189 */
190 enum GNUNET_GenericReturnValue broadcast;
191};
192
193
194/**
195 * Create command.
196 *
197 * @param label name for command.
198 * @param system_label Label of the cmd to setup a test environment.
199 * @param m The number of the local node of the actual network namespace.
200 * @param n The number of the actual namespace.
201 * @param local_m Number of local nodes in each namespace.
202 * @param handlers Handler for messages received by this peer.
203 * @param cfgname Configuration file name for this peer.
204 * @param notify_connect Method which will be called, when a peer connects.
205 * @param broadcast Flag indicating, if broadcast should be switched on.
206 * @return command.
207 */
208struct GNUNET_TESTING_Command
209GNUNET_TRANSPORT_cmd_start_peer (const char *label,
210 const char *system_label,
211 uint32_t no,
212 char *node_ip,
213 struct GNUNET_MQ_MessageHandler *handlers,
214 const char *cfgname,
215 GNUNET_TRANSPORT_notify_connect_cb
216 notify_connect,
217 unsigned int broadcast);
218
219
220struct GNUNET_TESTING_Command
221GNUNET_TRANSPORT_cmd_stop_peer (const char *label,
222 const char *start_label);
223
224
225/**
226 * Create command
227 *
228 * @param label name for command
229 * @param start_peer_label Label of the cmd to start a peer.
230 * @param create_peer_label Label of the cmd which started the test system.
231 * @param num Number globally identifying the node.
232 * @param The topology for the test setup.
233 * @param additional_connects Number of additional connects this cmd will wait for not triggered by this cmd.
234 * @return command.
235 */
236struct GNUNET_TESTING_Command
237GNUNET_TRANSPORT_cmd_connect_peers (
238 const char *label,
239 const char *start_peer_label,
240 const char *create_label,
241 uint32_t num,
242 struct GNUNET_TESTING_NetjailTopology *topology,
243 unsigned int additional_connects);
244
245
246/**
247 * Create command.
248 *
249 * @param label name for command.
250 * @param start_peer_label Label of the cmd to start a peer.
251 * @param create_peer_label Label of the cmd which started the test system.
252 * @param num Number globally identifying the node.
253 * @param The topology for the test setup.
254 * @return command.
255 */
256struct GNUNET_TESTING_Command
257GNUNET_TRANSPORT_cmd_send_simple (const char *label,
258 const char *start_peer_label,
259 const char *create_label,
260 uint32_t num,
261 struct GNUNET_TESTING_NetjailTopology *
262 topology);
263
264
265/**
266 * Create command.
267 *
268 * @param label name for command.
269 * @param start_peer_label Label of the cmd to start a peer.
270 * @param create_label Label of the cmd to create the testing system.
271 * @param num Number globally identifying the node.
272 * @param node_n The number of the node in a network namespace.
273 * @param namespace_n The number of the network namespace.
274 * @param The topology for the test setup.
275 * @return command.
276 */
277struct GNUNET_TESTING_Command
278GNUNET_TRANSPORT_cmd_backchannel_check (const char *label,
279 const char *start_peer_label,
280 const char *create_label,
281 uint32_t num,
282 unsigned int node_n,
283 unsigned int namespace_n,
284 struct GNUNET_TESTING_NetjailTopology *
285 topology);
286
287
288/**
289 * Create headers for a trait with name @a name for
290 * statically allocated data of type @a type.
291 */
292#define GNUNET_TRANSPORT_MAKE_DECL_SIMPLE_TRAIT(name,type) \
293 enum GNUNET_GenericReturnValue \
294 GNUNET_TRANSPORT_get_trait_ ## name ( \
295 const struct GNUNET_TESTING_Command *cmd, \
296 type **ret); \
297 struct GNUNET_TESTING_Trait \
298 GNUNET_TRANSPORT_make_trait_ ## name ( \
299 type * value);
300
301
302/**
303 * Create C implementation for a trait with name @a name for statically
304 * allocated data of type @a type.
305 */
306#define GNUNET_TRANSPORT_MAKE_IMPL_SIMPLE_TRAIT(name,type) \
307 enum GNUNET_GenericReturnValue \
308 GNUNET_TRANSPORT_get_trait_ ## name ( \
309 const struct GNUNET_TESTING_Command *cmd, \
310 type **ret) \
311 { \
312 if (NULL == cmd->traits) return GNUNET_SYSERR; \
313 return cmd->traits (cmd->cls, \
314 (const void **) ret, \
315 GNUNET_S (name), \
316 0); \
317 } \
318 struct GNUNET_TESTING_Trait \
319 GNUNET_TRANSPORT_make_trait_ ## name ( \
320 type * value) \
321 { \
322 struct GNUNET_TESTING_Trait ret = { \
323 .trait_name = GNUNET_S (name), \
324 .ptr = (const void *) value \
325 }; \
326 return ret; \
327 }
328
329
330/**
331 * Call #op on all simple traits.
332 */
333#define GNUNET_TRANSPORT_SIMPLE_TRAITS(op) \
334 op (peer_id, const struct GNUNET_PeerIdentity) \
335 op (connected_peers_map, const struct GNUNET_CONTAINER_MultiShortmap) \
336 op (hello_size, const size_t) \
337 op (hello, const char) \
338 op (application_handle, const struct GNUNET_TRANSPORT_ApplicationHandle) \
339 op (connect_peer_state, const struct ConnectPeersState) \
340 op (state, const struct StartPeerState) \
341 op (broadcast, const enum GNUNET_GenericReturnValue)
342
343GNUNET_TRANSPORT_SIMPLE_TRAITS (GNUNET_TRANSPORT_MAKE_DECL_SIMPLE_TRAIT)
344
345
346#endif
347/* end of transport_testing.h */
diff --git a/src/transport/transport-testing-communicator.c b/src/transport/transport-testing-communicator.c
deleted file mode 100644
index ce4af01f2..000000000
--- a/src/transport/transport-testing-communicator.c
+++ /dev/null
@@ -1,1227 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2019 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-testing-communicator.c
23 * @brief functions related to testing-tng
24 * @author Christian Grothoff
25 * @author Julius Bünger
26 */
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_protocols.h"
30#include "gnunet_constants.h"
31#include "transport-testing-communicator.h"
32#include "gnunet_ats_transport_service.h"
33#include "gnunet_hello_lib.h"
34#include "gnunet_signatures.h"
35#include "transport.h"
36#include <inttypes.h>
37
38#define LOG(kind, ...) GNUNET_log_from (kind, "transport-testing2", __VA_ARGS__)
39
40struct MyClient
41{
42 struct MyClient *prev;
43 struct MyClient *next;
44 /**
45 * @brief Handle to the client
46 */
47 struct GNUNET_SERVICE_Client *client;
48
49 /**
50 * @brief Handle to the client
51 */
52 struct GNUNET_MQ_Handle *c_mq;
53
54 /**
55 * The TCH
56 */
57 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc;
58
59};
60
61/**
62 * @brief Queue of a communicator and some context
63 */
64struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue
65{
66 /**
67 * @brief Handle to the TransportCommunicator
68 */
69 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h;
70
71 /**
72 * @brief Envelope to a message that requests the opening of the queue.
73 *
74 * If the client already requests queue(s), but the communicator is not yet
75 * connected, we cannot send the request to open the queue. Save it until the
76 * communicator becomes available and send it then.
77 */
78 struct GNUNET_MQ_Envelope *open_queue_env;
79
80 /**
81 * @brief Peer ID of the peer on the other side of the queue
82 */
83 struct GNUNET_PeerIdentity peer_id;
84
85 /**
86 * @brief Queue ID
87 */
88 uint32_t qid;
89
90 /**
91 * @brief Current message id
92 */
93 uint64_t mid;
94
95 /**
96 * An `enum GNUNET_NetworkType` in NBO.
97 */
98 uint32_t nt;
99
100 /**
101 * Maximum transmission unit. UINT32_MAX for unlimited.
102 */
103 uint32_t mtu;
104
105 /**
106 * Queue length. UINT64_MAX for unlimited.
107 */
108 uint64_t q_len;
109
110 /**
111 * Queue prio
112 */
113 uint32_t priority;
114
115 /**
116 * An `enum GNUNET_TRANSPORT_ConnectionStatus` in NBO.
117 */
118 uint32_t cs;
119
120 /**
121 * @brief Next element inside a DLL
122 */
123 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *next;
124
125 /**
126 * @brief Previous element inside a DLL
127 */
128 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *prev;
129};
130
131
132/**
133 * @brief Handle/Context to a single transmission
134 */
135struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorTransmission
136{
137};
138
139
140/**
141 * @brief Check whether incoming msg indicating available communicator is
142 * correct
143 *
144 * @param cls Closure
145 * @param msg Message struct
146 *
147 * @return GNUNET_YES in case message is correct
148 */
149static int
150check_communicator_available (
151 void *cls,
152 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *msg)
153{
154 uint16_t size;
155
156 size = ntohs (msg->header.size) - sizeof(*msg);
157 if (0 == size)
158 return GNUNET_OK; /* receive-only communicator */
159 GNUNET_MQ_check_zero_termination (msg);
160 return GNUNET_OK;
161}
162
163
164/**
165 * @brief Handle new communicator
166 *
167 * Store characteristics of communicator, call respective client callback.
168 *
169 * @param cls Closure - communicator handle
170 * @param msg Message struct
171 */
172static void
173handle_communicator_available (
174 void *cls,
175 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *msg)
176{
177 struct MyClient *client = cls;
178 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h =
179 client->tc;
180 uint16_t size;
181 tc_h->c_mq = client->c_mq;
182
183 size = ntohs (msg->header.size) - sizeof(*msg);
184 if (0 == size)
185 {
186 GNUNET_SERVICE_client_continue (client->client);
187 return; /* receive-only communicator */
188 }
189 tc_h->c_characteristics = ntohl (msg->cc);
190 tc_h->c_addr_prefix = GNUNET_strdup ((const char *) &msg[1]);
191 if (NULL != tc_h->communicator_available_cb)
192 {
193 LOG (GNUNET_ERROR_TYPE_DEBUG, "calling communicator_available_cb()\n");
194 tc_h->communicator_available_cb (tc_h->cb_cls,
195 tc_h,
196 tc_h->c_characteristics,
197 tc_h->c_addr_prefix);
198 }
199 GNUNET_SERVICE_client_continue (client->client);
200 LOG (GNUNET_ERROR_TYPE_DEBUG, "finished communicator_available_cb()\n");
201
202}
203
204
205/**
206 * Incoming message. Test message is well-formed.
207 *
208 * @param cls the client
209 * @param msg the send message that was sent
210 * @return #GNUNET_OK if message is well-formed
211 */
212static int
213check_communicator_backchannel (void *cls,
214 const struct
215 GNUNET_TRANSPORT_CommunicatorBackchannel *msg)
216{
217 // struct TransportClient *tc = cls;
218
219 // if (CT_COMMUNICATOR != tc->type)
220 // {
221 // GNUNET_break (0);
222 // return GNUNET_SYSERR;
223 // }
224 // GNUNET_MQ_check_boxed_message (msg);
225 return GNUNET_OK;
226}
227
228
229/**
230 * @brief Receive an incoming message.
231 *
232 * Pass the message to the client.
233 *
234 * @param cls Closure - communicator handle
235 * @param msg Message
236 */
237static void
238handle_communicator_backchannel (void *cls,
239 const struct
240 GNUNET_TRANSPORT_CommunicatorBackchannel *
241 bc_msg)
242{
243 struct MyClient *client = cls;
244 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h =
245 client->tc;
246 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *other_tc_h;
247 struct GNUNET_MessageHeader *msg;
248 msg = (struct GNUNET_MessageHeader *) &bc_msg[1];
249 uint16_t isize = ntohs (msg->size);
250 const char *target_communicator = ((const char *) msg) + isize;
251 struct GNUNET_TRANSPORT_CommunicatorBackchannelIncoming *cbi;
252 struct GNUNET_MQ_Envelope *env;
253
254 LOG (GNUNET_ERROR_TYPE_DEBUG,
255 "Received backchannel message\n");
256 if (tc_h->bc_enabled != GNUNET_YES)
257 {
258 GNUNET_SERVICE_client_continue (client->client);
259 return;
260 }
261 /* Find client providing this communicator */
262 /* Finally, deliver backchannel message to communicator */
263 LOG (GNUNET_ERROR_TYPE_DEBUG,
264 "Delivering backchannel message of type %u to %s\n",
265 ntohs (msg->type),
266 target_communicator);
267 other_tc_h = tc_h->bc_cb (tc_h, msg, (struct
268 GNUNET_PeerIdentity*) &bc_msg->pid);
269 env = GNUNET_MQ_msg_extra (
270 cbi,
271 isize,
272 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL_INCOMING);
273 cbi->pid = tc_h->peer_id;
274 memcpy (&cbi[1], msg, isize);
275
276
277 GNUNET_MQ_send (other_tc_h->c_mq, env);
278 GNUNET_SERVICE_client_continue (client->client);
279}
280
281
282/**
283 * Address of our peer added. Test message is well-formed.
284 *
285 * @param cls the client
286 * @param aam the send message that was sent
287 * @return #GNUNET_OK if message is well-formed
288 */
289static int
290check_add_address (void *cls,
291 const struct GNUNET_TRANSPORT_AddAddressMessage *msg)
292{
293 // if (CT_COMMUNICATOR != tc->type)
294 // {
295 // GNUNET_break (0);
296 // return GNUNET_SYSERR;
297 // }
298 GNUNET_MQ_check_zero_termination (msg);
299 return GNUNET_OK;
300}
301
302
303/**
304 * @brief The communicator informs about an address.
305 *
306 * Store address and call client callback.
307 *
308 * @param cls Closure - communicator handle
309 * @param msg Message
310 */
311static void
312handle_add_address (void *cls,
313 const struct GNUNET_TRANSPORT_AddAddressMessage *msg)
314{
315 struct MyClient *client = cls;
316 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h =
317 client->tc;
318 uint16_t size;
319 size = ntohs (msg->header.size) - sizeof(*msg);
320 LOG (GNUNET_ERROR_TYPE_DEBUG, "received add address cb %u\n", size);
321 if (0 == size)
322 return; /* receive-only communicator */
323 LOG (GNUNET_ERROR_TYPE_DEBUG, "received add address cb %u\n", size);
324 tc_h->c_address = GNUNET_strdup ((const char *) &msg[1]);
325 if (NULL != tc_h->add_address_cb)
326 {
327 LOG (GNUNET_ERROR_TYPE_DEBUG, "calling add_address_cb()\n");
328 tc_h->add_address_cb (tc_h->cb_cls,
329 tc_h,
330 tc_h->c_address,
331 GNUNET_TIME_relative_ntoh (msg->expiration),
332 msg->aid,
333 ntohl (msg->nt));
334 }
335 GNUNET_SERVICE_client_continue (client->client);
336}
337
338
339/**
340 * Incoming message. Test message is well-formed.
341 *
342 * @param cls the client
343 * @param msg the send message that was sent
344 * @return #GNUNET_OK if message is well-formed
345 */
346static int
347check_incoming_msg (void *cls,
348 const struct GNUNET_TRANSPORT_IncomingMessage *msg)
349{
350 // struct TransportClient *tc = cls;
351
352 // if (CT_COMMUNICATOR != tc->type)
353 // {
354 // GNUNET_break (0);
355 // return GNUNET_SYSERR;
356 // }
357 GNUNET_MQ_check_boxed_message (msg);
358 return GNUNET_OK;
359}
360
361
362/**
363 * @brief Receive an incoming message.
364 *
365 * Pass the message to the client.
366 *
367 * @param cls Closure - communicator handle
368 * @param msg Message
369 */
370static void
371handle_incoming_msg (void *cls,
372 const struct GNUNET_TRANSPORT_IncomingMessage *inc_msg)
373{
374 struct MyClient *client = cls;
375 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h =
376 client->tc;
377 struct GNUNET_MessageHeader *msg;
378 msg = (struct GNUNET_MessageHeader *) &inc_msg[1];
379 size_t payload_len = ntohs (msg->size) - sizeof (struct
380 GNUNET_MessageHeader);
381 if (NULL != tc_h->incoming_msg_cb)
382 {
383 tc_h->incoming_msg_cb (tc_h->cb_cls,
384 tc_h,
385 (char*) &msg[1],
386 payload_len);
387 }
388 else
389 {
390 LOG (GNUNET_ERROR_TYPE_WARNING,
391 "Incoming message from communicator but no handler!\n");
392 }
393 if (GNUNET_YES == ntohl (inc_msg->fc_on))
394 {
395 /* send ACK when done to communicator for flow control! */
396 struct GNUNET_MQ_Envelope *env;
397 struct GNUNET_TRANSPORT_IncomingMessageAck *ack;
398
399 env = GNUNET_MQ_msg (ack, GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG_ACK);
400 GNUNET_assert (NULL != env);
401 ack->reserved = htonl (0);
402 ack->fc_id = inc_msg->fc_id;
403 ack->sender = inc_msg->sender;
404 GNUNET_MQ_send (tc_h->c_mq, env);
405 }
406
407 GNUNET_SERVICE_client_continue (client->client);
408}
409
410
411/**
412 * @brief Communicator informs that it tries to establish requested queue
413 *
414 * @param cls Closure - communicator handle
415 * @param msg Message
416 */
417static void
418handle_queue_create_ok (void *cls,
419 const struct GNUNET_TRANSPORT_CreateQueueResponse *msg)
420{
421 struct MyClient *client = cls;
422 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h =
423 client->tc;
424
425 if (NULL != tc_h->queue_create_reply_cb)
426 {
427 tc_h->queue_create_reply_cb (tc_h->cb_cls, tc_h, GNUNET_YES);
428 }
429 GNUNET_SERVICE_client_continue (client->client);
430}
431
432
433/**
434 * @brief Communicator informs that it won't try establishing requested queue.
435 *
436 * It will not do so probably because the address is bougus (see comment to
437 * #GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL)
438 *
439 * @param cls Closure - communicator handle
440 * @param msg Message
441 */
442static void
443handle_queue_create_fail (
444 void *cls,
445 const struct GNUNET_TRANSPORT_CreateQueueResponse *msg)
446{
447 struct MyClient *client = cls;
448 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h =
449 client->tc;
450
451 if (NULL != tc_h->queue_create_reply_cb)
452 {
453 tc_h->queue_create_reply_cb (tc_h->cb_cls, tc_h, GNUNET_NO);
454 }
455 GNUNET_SERVICE_client_continue (client->client);
456}
457
458
459/**
460 * New queue became available. Check message.
461 *
462 * @param cls the client
463 * @param aqm the send message that was sent
464 */
465static int
466check_add_queue_message (void *cls,
467 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
468{
469 GNUNET_MQ_check_zero_termination (aqm);
470 return GNUNET_OK;
471}
472
473
474/**
475 * @brief Handle new queue
476 *
477 * Store context and call client callback.
478 *
479 * @param cls Closure - communicator handle
480 * @param msg Message struct
481 */
482static void
483handle_add_queue_message (void *cls,
484 const struct GNUNET_TRANSPORT_AddQueueMessage *msg)
485{
486 struct MyClient *client = cls;
487 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h =
488 client->tc;
489 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *tc_queue;
490
491 LOG (GNUNET_ERROR_TYPE_DEBUG,
492 "Got queue with ID %u\n", msg->qid);
493 for (tc_queue = tc_h->queue_head; NULL != tc_queue; tc_queue = tc_queue->next)
494 {
495 if (tc_queue->qid == msg->qid)
496 break;
497 }
498 if (NULL == tc_queue)
499 {
500 tc_queue =
501 GNUNET_new (struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue);
502 tc_queue->tc_h = tc_h;
503 tc_queue->qid = msg->qid;
504 tc_queue->peer_id = msg->receiver;
505 GNUNET_CONTAINER_DLL_insert (tc_h->queue_head, tc_h->queue_tail, tc_queue);
506 }
507 GNUNET_assert (tc_queue->qid == msg->qid);
508 GNUNET_assert (0 == GNUNET_memcmp (&tc_queue->peer_id, &msg->receiver));
509 tc_queue->nt = msg->nt;
510 tc_queue->mtu = ntohl (msg->mtu);
511 tc_queue->cs = msg->cs;
512 tc_queue->priority = ntohl (msg->priority);
513 tc_queue->q_len = GNUNET_ntohll (msg->q_len);
514 if (NULL != tc_h->add_queue_cb)
515 {
516 tc_h->add_queue_cb (tc_h->cb_cls, tc_h, tc_queue, tc_queue->mtu);
517 }
518 GNUNET_SERVICE_client_continue (client->client);
519}
520
521
522/**
523 * @brief Handle new queue
524 *
525 * Store context and call client callback.
526 *
527 * @param cls Closure - communicator handle
528 * @param msg Message struct
529 */
530static void
531handle_update_queue_message (void *cls,
532 const struct
533 GNUNET_TRANSPORT_UpdateQueueMessage *msg)
534{
535 struct MyClient *client = cls;
536 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h =
537 client->tc;
538 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *tc_queue;
539
540 LOG (GNUNET_ERROR_TYPE_DEBUG,
541 "Received queue update message for %u with q_len %" PRIu64 "\n",
542 msg->qid, GNUNET_ntohll (msg->q_len));
543 tc_queue = tc_h->queue_head;
544 if (NULL != tc_queue)
545 {
546 while (tc_queue->qid != msg->qid)
547 {
548 tc_queue = tc_queue->next;
549 }
550 }
551 if (NULL == tc_queue)
552 {
553 GNUNET_SERVICE_client_continue (client->client);
554 return;
555 }
556 GNUNET_assert (tc_queue->qid == msg->qid);
557 GNUNET_assert (0 == GNUNET_memcmp (&tc_queue->peer_id, &msg->receiver));
558 tc_queue->nt = msg->nt;
559 tc_queue->mtu = ntohl (msg->mtu);
560 tc_queue->cs = msg->cs;
561 tc_queue->priority = ntohl (msg->priority);
562 // Uncomment this for alternativ 1 of backchannel functionality
563 tc_queue->q_len += GNUNET_ntohll (msg->q_len);
564 // Until here for alternativ 1
565 // Uncomment this for alternativ 2 of backchannel functionality
566 // tc_queue->q_len = GNUNET_ntohll (msg->q_len);
567 // Until here for alternativ 2
568 GNUNET_SERVICE_client_continue (client->client);
569}
570
571
572/**
573 * @brief Shut down the service
574 *
575 * @param cls Closure - Handle to the service
576 */
577static void
578shutdown_service (void *cls)
579{
580 struct GNUNET_SERVICE_Handle *h = cls;
581
582 LOG (GNUNET_ERROR_TYPE_DEBUG,
583 "Shutting down service!\n");
584
585 GNUNET_SERVICE_stop (h);
586}
587
588
589/**
590 * @brief Callback called when new Client (Communicator) connects
591 *
592 * @param cls Closure - TransporCommmunicator Handle
593 * @param client Client
594 * @param mq Messagequeue
595 *
596 * @return TransportCommunicator Handle
597 */
598static void *
599connect_cb (void *cls,
600 struct GNUNET_SERVICE_Client *client,
601 struct GNUNET_MQ_Handle *mq)
602{
603 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = cls;
604 struct MyClient *new_c;
605
606 LOG (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected to %p.\n",
607 client, tc_h);
608 new_c = GNUNET_new (struct MyClient);
609 new_c->client = client;
610 new_c->c_mq = mq;
611 new_c->tc = tc_h;
612 GNUNET_CONTAINER_DLL_insert (tc_h->client_head,
613 tc_h->client_tail,
614 new_c);
615
616 if (NULL == tc_h->queue_head)
617 return new_c;
618 /* Iterate over queues. They are yet to be opened. Request opening. */
619 for (struct
620 GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *tc_queue_iter =
621 tc_h->queue_head;
622 NULL != tc_queue_iter;
623 tc_queue_iter = tc_queue_iter->next)
624 {
625 if (NULL == tc_queue_iter->open_queue_env)
626 continue;
627 /* Send the previously created mq envelope to request the creation of the
628 * queue. */
629 GNUNET_MQ_send (tc_h->c_mq,
630 tc_queue_iter->open_queue_env);
631 tc_queue_iter->open_queue_env = NULL;
632 }
633 return new_c;
634}
635
636
637/**
638 * @brief Callback called when Client disconnects
639 *
640 * @param cls Closure - TransportCommunicator Handle
641 * @param client Client
642 * @param internal_cls TransporCommmunicator Handle
643 */
644static void
645disconnect_cb (void *cls,
646 struct GNUNET_SERVICE_Client *client,
647 void *internal_cls)
648{
649 struct MyClient *cl = cls;
650 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = cls;
651
652 for (cl = tc_h->client_head; NULL != cl; cl = cl->next)
653 {
654 if (cl->client != client)
655 continue;
656 GNUNET_CONTAINER_DLL_remove (tc_h->client_head,
657 tc_h->client_tail,
658 cl);
659 if (cl->c_mq == tc_h->c_mq)
660 tc_h->c_mq = NULL;
661 GNUNET_free (cl);
662 break;
663 }
664 LOG (GNUNET_ERROR_TYPE_DEBUG, "Client disconnected.\n");
665}
666
667
668/**
669 * Message was transmitted. Process the request.
670 *
671 * @param cls the client
672 * @param sma the send message that was sent
673 */
674static void
675handle_send_message_ack (void *cls,
676 const struct GNUNET_TRANSPORT_SendMessageToAck *sma)
677{
678 struct MyClient *client = cls;
679 GNUNET_SERVICE_client_continue (client->client);
680 // NOP
681}
682
683
684/**
685 * @brief Start the communicator part of the transport service
686 *
687 * @param communicator_available Callback to be called when a new communicator
688 * becomes available
689 * @param cfg Configuration
690 */
691static void
692transport_communicator_start (
693 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h)
694{
695 struct GNUNET_MQ_MessageHandler mh[] = {
696 GNUNET_MQ_hd_var_size (communicator_available,
697 GNUNET_MESSAGE_TYPE_TRANSPORT_NEW_COMMUNICATOR,
698 struct GNUNET_TRANSPORT_CommunicatorAvailableMessage,
699 tc_h),
700 GNUNET_MQ_hd_var_size (communicator_backchannel,
701 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL,
702 struct GNUNET_TRANSPORT_CommunicatorBackchannel,
703 tc_h),
704 GNUNET_MQ_hd_var_size (add_address,
705 GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS,
706 struct GNUNET_TRANSPORT_AddAddressMessage,
707 tc_h),
708 // GNUNET_MQ_hd_fixed_size (del_address,
709 // GNUNET_MESSAGE_TYPE_TRANSPORT_DEL_ADDRESS,
710 // struct GNUNET_TRANSPORT_DelAddressMessage,
711 // NULL),
712 GNUNET_MQ_hd_var_size (incoming_msg,
713 GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG,
714 struct GNUNET_TRANSPORT_IncomingMessage,
715 tc_h),
716 GNUNET_MQ_hd_fixed_size (queue_create_ok,
717 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_OK,
718 struct GNUNET_TRANSPORT_CreateQueueResponse,
719 tc_h),
720 GNUNET_MQ_hd_fixed_size (queue_create_fail,
721 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL,
722 struct GNUNET_TRANSPORT_CreateQueueResponse,
723 tc_h),
724 GNUNET_MQ_hd_var_size (add_queue_message,
725 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP,
726 struct GNUNET_TRANSPORT_AddQueueMessage,
727 tc_h),
728 GNUNET_MQ_hd_fixed_size (update_queue_message,
729 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_UPDATE,
730 struct GNUNET_TRANSPORT_UpdateQueueMessage,
731 tc_h),
732 // GNUNET_MQ_hd_fixed_size (del_queue_message,
733 // GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN,
734 // struct GNUNET_TRANSPORT_DelQueueMessage,
735 // NULL),
736 GNUNET_MQ_hd_fixed_size (send_message_ack,
737 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG_ACK,
738 struct GNUNET_TRANSPORT_SendMessageToAck,
739 tc_h),
740 GNUNET_MQ_handler_end ()
741 };
742
743
744 tc_h->sh = GNUNET_SERVICE_start ("transport",
745 tc_h->cfg,
746 &connect_cb,
747 &disconnect_cb,
748 tc_h,
749 mh);
750 GNUNET_assert (NULL != tc_h->sh);
751}
752
753
754/**
755 * @brief Task run at shutdown to kill communicator and clean up
756 *
757 * @param cls Closure - Process of communicator
758 */
759static void
760shutdown_process (struct GNUNET_OS_Process *proc)
761{
762 if (0 != GNUNET_OS_process_kill (proc, SIGTERM))
763 {
764 LOG (GNUNET_ERROR_TYPE_WARNING,
765 "Error shutting down process with SIGERM, trying SIGKILL\n");
766 if (0 != GNUNET_OS_process_kill (proc, SIGKILL))
767 {
768 LOG (GNUNET_ERROR_TYPE_ERROR,
769 "Error shutting down process with SIGERM and SIGKILL\n");
770 }
771 }
772 GNUNET_OS_process_destroy (proc);
773}
774
775/**
776 * @brief Task run at shutdown to kill the statistics process
777 *
778 * @param cls Closure - Process of communicator
779 */
780static void
781shutdown_statistics (void *cls)
782{
783 struct GNUNET_OS_Process *proc = cls;
784 shutdown_process (proc);
785}
786
787/**
788 * @brief Task run at shutdown to kill the peerstore process
789 *
790 * @param cls Closure - Process of communicator
791 */
792static void
793shutdown_peerstore (void *cls)
794{
795 struct GNUNET_OS_Process *proc = cls;
796 shutdown_process (proc);
797}
798
799/**
800 * @brief Task run at shutdown to kill a communicator process
801 *
802 * @param cls Closure - Process of communicator
803 */
804static void
805shutdown_communicator (void *cls)
806{
807 struct GNUNET_OS_Process *proc = cls;
808 shutdown_process (proc);
809}
810
811
812/**
813 * @brief Start the communicator
814 *
815 * @param cfgname Name of the communicator
816 */
817static void
818communicator_start (
819 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h,
820 const char *binary_name)
821{
822 char *binary;
823 char *loprefix;
824 char *section_name;
825
826 LOG (GNUNET_ERROR_TYPE_DEBUG, "communicator_start\n");
827
828 section_name = strchr (binary_name, '-');
829 section_name++;
830
831 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (tc_h->cfg,
832 section_name,
833 "PREFIX",
834 &loprefix))
835 loprefix = GNUNET_strdup ("");
836
837
838 binary = GNUNET_OS_get_libexec_binary_path (binary_name);
839 tc_h->c_proc = GNUNET_OS_start_process_s (GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
840 NULL,
841 loprefix,
842 binary,
843 binary_name,
844 "-c",
845 tc_h->cfg_filename,
846 NULL);
847 if (NULL == tc_h->c_proc)
848 {
849 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to start communicator!");
850 return;
851 }
852 LOG (GNUNET_ERROR_TYPE_INFO, "started communicator\n");
853 GNUNET_free (binary);
854}
855
856
857/**
858 * @brief Task run at shutdown to kill communicator and clean up
859 *
860 * @param cls Closure - Process of communicator
861 */
862static void
863shutdown_nat (void *cls)
864{
865 struct GNUNET_OS_Process *proc = cls;
866 shutdown_process (proc);
867}
868
869
870/**
871 * @brief Task run at shutdown to kill the resolver process
872 *
873 * @param cls Closure - Process of communicator
874 */
875static void
876shutdown_resolver (void *cls)
877{
878 struct GNUNET_OS_Process *proc = cls;
879 shutdown_process (proc);
880}
881
882
883/**
884 * @brief Start Resolver
885 *
886 */
887static void
888resolver_start (struct
889 GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h)
890{
891 char *binary;
892
893 LOG (GNUNET_ERROR_TYPE_DEBUG, "resolver_start\n");
894 binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-resolver");
895 tc_h->resolver_proc = GNUNET_OS_start_process (
896 GNUNET_OS_INHERIT_STD_OUT_AND_ERR
897 | GNUNET_OS_USE_PIPE_CONTROL,
898 NULL,
899 NULL,
900 NULL,
901 binary,
902 "gnunet-service-resolver",
903 "-c",
904 tc_h->cfg_filename,
905 NULL);
906 if (NULL == tc_h->resolver_proc)
907 {
908 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to start resolver service!");
909 return;
910 }
911 LOG (GNUNET_ERROR_TYPE_INFO, "started resolver service\n");
912 GNUNET_free (binary);
913
914}
915
916/**
917 * @brief Start Statistics
918 *
919 */
920static void
921statistics_start (
922 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h)
923{
924 char *binary;
925
926 binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-statistics");
927 tc_h->stat_proc = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
928 NULL,
929 NULL,
930 NULL,
931 binary,
932 "gnunet-service-statistics",
933 "-c",
934 tc_h->cfg_filename,
935 NULL);
936 if (NULL == tc_h->stat_proc)
937 {
938 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to start Statistics!");
939 return;
940 }
941 LOG (GNUNET_ERROR_TYPE_INFO, "started Statistics\n");
942 GNUNET_free (binary);
943}
944
945/**
946 * @brief Start Peerstore
947 *
948 */
949static void
950peerstore_start (
951 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h)
952{
953 char *binary;
954
955 binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-peerstore");
956 tc_h->ps_proc = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
957 NULL,
958 NULL,
959 NULL,
960 binary,
961 "gnunet-service-peerstore",
962 "-c",
963 tc_h->cfg_filename,
964 NULL);
965 if (NULL == tc_h->ps_proc)
966 {
967 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to start Peerstore!");
968 return;
969 }
970 LOG (GNUNET_ERROR_TYPE_INFO, "started Peerstore\n");
971 GNUNET_free (binary);
972}
973
974/**
975 * @brief Start NAT
976 *
977 */
978static void
979nat_start (
980 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h)
981{
982 char *binary;
983
984 LOG (GNUNET_ERROR_TYPE_DEBUG, "nat_start\n");
985 binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-nat");
986 tc_h->nat_proc = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_OUT_AND_ERR
987 | GNUNET_OS_USE_PIPE_CONTROL,
988 NULL,
989 NULL,
990 NULL,
991 binary,
992 "gnunet-service-nat",
993 "-c",
994 tc_h->cfg_filename,
995 NULL);
996 if (NULL == tc_h->nat_proc)
997 {
998 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to start NAT!");
999 return;
1000 }
1001 LOG (GNUNET_ERROR_TYPE_INFO, "started NAT\n");
1002 GNUNET_free (binary);
1003}
1004
1005
1006/**
1007 * @brief Start communicator part of transport service and communicator
1008 *
1009 * @param service_name Name of the service
1010 * @param cfg Configuration handle
1011 * @param communicator_available_cb Callback that is called when a new
1012 * @param add_address_cb Callback that is called when a new
1013 * communicator becomes available
1014 * @param cb_cls Closure to @a communicator_available_cb and @a
1015 *
1016 * @return Handle to the communicator duo
1017 */
1018struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *
1019GNUNET_TRANSPORT_TESTING_transport_communicator_service_start (
1020 const char *service_name,
1021 const char *binary_name,
1022 const char *cfg_filename,
1023 const struct GNUNET_PeerIdentity *peer_id,
1024 GNUNET_TRANSPORT_TESTING_CommunicatorAvailableCallback
1025 communicator_available_cb,
1026 GNUNET_TRANSPORT_TESTING_AddAddressCallback add_address_cb,
1027 GNUNET_TRANSPORT_TESTING_QueueCreateReplyCallback queue_create_reply_cb,
1028 GNUNET_TRANSPORT_TESTING_AddQueueCallback add_queue_cb,
1029 GNUNET_TRANSPORT_TESTING_IncomingMessageCallback incoming_message_cb,
1030 GNUNET_TRANSPORT_TESTING_BackchannelCallback bc_cb,
1031 void *cb_cls)
1032{
1033 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h;
1034
1035 LOG (GNUNET_ERROR_TYPE_DEBUG,
1036 "Starting new transport/communicator combo with config %s\n",
1037 cfg_filename);
1038 tc_h =
1039 GNUNET_new (struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle);
1040 tc_h->cfg_filename = GNUNET_strdup (cfg_filename);
1041 tc_h->cfg = GNUNET_CONFIGURATION_create ();
1042 if ((GNUNET_SYSERR == GNUNET_CONFIGURATION_load (tc_h->cfg, cfg_filename)))
1043 {
1044 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1045 _ ("Malformed configuration file `%s', exit ...\n"),
1046 cfg_filename);
1047 GNUNET_free (tc_h->cfg_filename);
1048 GNUNET_CONFIGURATION_destroy (tc_h->cfg);
1049 GNUNET_free (tc_h);
1050 return NULL;
1051 }
1052 tc_h->bc_enabled = GNUNET_CONFIGURATION_get_value_yesno (tc_h->cfg,
1053 "communicator-test",
1054 "BACKCHANNEL_ENABLED");
1055 tc_h->communicator_available_cb = communicator_available_cb;
1056 tc_h->add_address_cb = add_address_cb;
1057 tc_h->queue_create_reply_cb = queue_create_reply_cb;
1058 tc_h->add_queue_cb = add_queue_cb;
1059 tc_h->incoming_msg_cb = incoming_message_cb;
1060 tc_h->bc_cb = bc_cb;
1061 tc_h->peer_id = *peer_id;
1062 tc_h->cb_cls = cb_cls;
1063
1064 /* Start communicator part of service */
1065 transport_communicator_start (tc_h);
1066 /* Start NAT */
1067 nat_start (tc_h);
1068 /* Start resolver service */
1069 resolver_start (tc_h);
1070 /* Start peerstore service */
1071 peerstore_start (tc_h);
1072 /* Start statistic service */
1073 statistics_start (tc_h);
1074 /* Schedule start communicator */
1075 communicator_start (tc_h,
1076 binary_name);
1077 return tc_h;
1078}
1079
1080
1081void
1082GNUNET_TRANSPORT_TESTING_transport_communicator_service_stop (
1083 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h)
1084{
1085 shutdown_communicator (tc_h->c_proc);
1086 shutdown_service (tc_h->sh);
1087 shutdown_nat (tc_h->nat_proc);
1088 shutdown_resolver (tc_h->resolver_proc);
1089 shutdown_peerstore (tc_h->ps_proc);
1090 shutdown_statistics (tc_h->stat_proc);
1091 GNUNET_CONFIGURATION_destroy (tc_h->cfg);
1092 GNUNET_free (tc_h);
1093}
1094
1095
1096/**
1097 * @brief Instruct communicator to open a queue
1098 *
1099 * @param tc_h Handle to communicator which shall open queue
1100 * @param peer_id Towards which peer
1101 * @param address For which address
1102 */
1103void
1104GNUNET_TRANSPORT_TESTING_transport_communicator_open_queue (
1105 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h,
1106 const struct GNUNET_PeerIdentity *peer_id,
1107 const char *address)
1108{
1109 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *tc_queue;
1110 static uint32_t idgen;
1111 char *prefix;
1112 struct GNUNET_TRANSPORT_CreateQueue *msg;
1113 struct GNUNET_MQ_Envelope *env;
1114 size_t alen;
1115
1116 tc_queue =
1117 GNUNET_new (struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue);
1118 tc_queue->tc_h = tc_h;
1119 prefix = GNUNET_HELLO_address_to_prefix (address);
1120 if (NULL == prefix)
1121 {
1122 GNUNET_break (0); /* We got an invalid address!? */
1123 GNUNET_free (tc_queue);
1124 return;
1125 }
1126 GNUNET_free (prefix);
1127 alen = strlen (address) + 1;
1128 env =
1129 GNUNET_MQ_msg_extra (msg, alen, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE);
1130 msg->request_id = htonl (idgen++);
1131 tc_queue->qid = msg->request_id;
1132 msg->receiver = *peer_id;
1133 tc_queue->peer_id = *peer_id;
1134 memcpy (&msg[1], address, alen);
1135 if (NULL != tc_h->c_mq)
1136 {
1137 LOG (GNUNET_ERROR_TYPE_DEBUG,
1138 "Sending queue create immediately\n");
1139 GNUNET_MQ_send (tc_h->c_mq, env);
1140 }
1141 else
1142 {
1143 tc_queue->open_queue_env = env;
1144 }
1145 GNUNET_CONTAINER_DLL_insert (tc_h->queue_head, tc_h->queue_tail, tc_queue);
1146}
1147
1148
1149/**
1150 * @brief Instruct communicator to send data
1151 *
1152 * @param tc_queue The queue to use for sending
1153 * @param cont function to call when done sending
1154 * @param cont_cls closure for @a cont
1155 * @param payload Data to send
1156 * @param payload_size Size of the @a payload
1157 */
1158void
1159GNUNET_TRANSPORT_TESTING_transport_communicator_send
1160 (struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h,
1161 GNUNET_SCHEDULER_TaskCallback cont,
1162 void *cont_cls,
1163 const void *payload,
1164 size_t payload_size)
1165{
1166 struct GNUNET_MessageHeader *mh;
1167 struct GNUNET_TRANSPORT_SendMessageTo *msg;
1168 struct GNUNET_MQ_Envelope *env;
1169 size_t inbox_size;
1170 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *tc_queue;
1171 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *tc_queue_tmp;
1172
1173 tc_queue = NULL;
1174 for (tc_queue_tmp = tc_h->queue_head;
1175 NULL != tc_queue_tmp;
1176 tc_queue_tmp = tc_queue_tmp->next)
1177 {
1178 if (tc_queue_tmp->q_len <= 0)
1179 continue;
1180 if (NULL == tc_queue)
1181 {
1182 LOG (GNUNET_ERROR_TYPE_DEBUG,
1183 "Selecting queue with prio %u, len %" PRIu64 " and MTU %u\n",
1184 tc_queue_tmp->priority,
1185 tc_queue_tmp->q_len,
1186 tc_queue_tmp->mtu);
1187 tc_queue = tc_queue_tmp;
1188 continue;
1189 }
1190 if (tc_queue->priority < tc_queue_tmp->priority)
1191 {
1192 LOG (GNUNET_ERROR_TYPE_DEBUG,
1193 "Selecting queue with prio %u, len %" PRIu64 " and MTU %u\n",
1194 tc_queue_tmp->priority,
1195 tc_queue_tmp->q_len,
1196 tc_queue_tmp->mtu);
1197 tc_queue = tc_queue_tmp;
1198 }
1199 }
1200 GNUNET_assert (NULL != tc_queue);
1201 // Uncomment this for alternativ 1 of backchannel functionality
1202 if (tc_queue->q_len != GNUNET_TRANSPORT_QUEUE_LENGTH_UNLIMITED)
1203 tc_queue->q_len--;
1204 // Until here for alternativ 1
1205 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1206 "Sending message\n");
1207 inbox_size = sizeof (struct GNUNET_MessageHeader) + payload_size;
1208 env = GNUNET_MQ_msg_extra (msg,
1209 inbox_size,
1210 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG);
1211 GNUNET_assert (NULL != env);
1212 msg->qid = htonl (tc_queue->qid);
1213 msg->mid = tc_queue->mid++;
1214 msg->receiver = tc_queue->peer_id;
1215 mh = (struct GNUNET_MessageHeader *) &msg[1];
1216 mh->size = htons (inbox_size);
1217 mh->type = GNUNET_MESSAGE_TYPE_DUMMY;
1218 memcpy (&mh[1],
1219 payload,
1220 payload_size);
1221 if (NULL != cont)
1222 GNUNET_MQ_notify_sent (env,
1223 cont,
1224 cont_cls);
1225 GNUNET_MQ_send (tc_queue->tc_h->c_mq,
1226 env);
1227}
diff --git a/src/transport/transport-testing-communicator.h b/src/transport/transport-testing-communicator.h
deleted file mode 100644
index 1875258b4..000000000
--- a/src/transport/transport-testing-communicator.h
+++ /dev/null
@@ -1,360 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2019 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-testing-communicator.h
23 * @brief functions and structures related to testing-tng
24 * @author Christian Grothoff
25 * @author Julius Bünger
26 */
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_ats_transport_service.h"
30#include "transport.h"
31
32/**
33 * @brief Queue of a communicator and some context
34 */
35struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue;
36
37
38/**
39 * @brief Handle/Context to a single transmission
40 */
41struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorTransmission;
42
43/**
44 * @brief Function signature for callbacks that are called when new
45 * backchannel message arrived
46 *
47 * @param cls Closure
48 * @param msg Backchannel message
49 * @param pid Target peer
50 */
51typedef struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *
52(*GNUNET_TRANSPORT_TESTING_BackchannelCallback)(void *cls,
53 struct GNUNET_MessageHeader *msg,
54 struct GNUNET_PeerIdentity *pid);
55
56
57/**
58 * @brief Function signature for callbacks that are called when new
59 * communicators become available
60 *
61 * @param cls Closure
62 * @param tc_h Communicator handle
63 * @param cc Characteristics of communicator
64 * @param address_prefix Prefix of the address
65 */
66typedef void
67(*GNUNET_TRANSPORT_TESTING_CommunicatorAvailableCallback)(void *cls,
68 struct
69 GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle
70 *tc_h,
71 enum
72 GNUNET_TRANSPORT_CommunicatorCharacteristics
73 cc,
74 char *address_prefix);
75
76
77/**
78 * @brief Receive information about the address of a communicator.
79 *
80 * @param cls Closure
81 * @param tc_h Communicator handle
82 * @param address Address represented as string
83 * @param expiration Expiration
84 * @param aid Aid
85 * @param nt Network Type
86 */
87typedef void
88(*GNUNET_TRANSPORT_TESTING_AddAddressCallback)(void *cls,
89 struct
90 GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle
91 *tc_h,
92 const char *address,
93 struct GNUNET_TIME_Relative
94 expiration,
95 uint32_t aid,
96 enum GNUNET_NetworkType nt);
97
98
99/**
100 * @brief Get informed about the success of a queue request.
101 *
102 * @param cls Closure
103 * @param tc_h Communicator handle
104 * @param will_try #GNUNET_YES if communicator will try to create queue
105 */
106typedef void
107(*GNUNET_TRANSPORT_TESTING_QueueCreateReplyCallback)(void *cls,
108 struct
109 GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle
110 *tc_h,
111 int will_try);
112
113
114/**
115 * @brief Handle opening of queue
116 *
117 * @param cls Closure
118 * @param tc_h Communicator handle
119 * @param tc_queue Handle to newly opened queue
120 */
121typedef void
122(*GNUNET_TRANSPORT_TESTING_AddQueueCallback)(void *cls,
123 struct
124 GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle
125 *tc_h,
126 struct
127 GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue
128 *tc_queue,
129 size_t mtu);
130
131
132/**
133 * @brief Handle an incoming message
134 *
135 * @param cls Closure
136 * @param tc_h Handle to the receiving communicator
137 * @param msg Received message
138 */
139typedef void
140(*GNUNET_TRANSPORT_TESTING_IncomingMessageCallback)(void *cls,
141 struct
142 GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle
143 *tc_h,
144 const char*payload,
145 size_t payload_len);
146
147/**
148 * @brief Handle to a transport communicator
149 */
150struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle
151{
152 /**
153 * Clients
154 */
155 struct MyClient *client_head;
156 struct MyClient *client_tail;
157
158 /**
159 * @brief Handle to the client
160 */
161 struct GNUNET_MQ_Handle *c_mq;
162
163 /**
164 * @brief Handle to the configuration
165 */
166 struct GNUNET_CONFIGURATION_Handle *cfg;
167
168 /**
169 * @brief File name of configuration file
170 */
171 char *cfg_filename;
172
173 struct GNUNET_PeerIdentity peer_id;
174
175 /**
176 * @brief Handle to the transport service
177 */
178 struct GNUNET_SERVICE_Handle *tsh;
179
180 /**
181 * @brief Task that will be run on shutdown to stop and clean transport
182 * service
183 */
184 struct GNUNET_SCHEDULER_Task *ts_shutdown_task;
185
186
187 /**
188 * @brief Process of the communicator
189 */
190 struct GNUNET_OS_Process *c_proc;
191
192 /**
193 * NAT process
194 */
195 struct GNUNET_OS_Process *nat_proc;
196
197 /**
198 * resolver service process
199 */
200 struct GNUNET_OS_Process *resolver_proc;
201
202 /**
203 * statistics service process
204 */
205 struct GNUNET_OS_Process *stat_proc;
206
207 /**
208 * peerstore service process
209 */
210 struct GNUNET_OS_Process *ps_proc;
211
212 /**
213 * @brief Task that will be run on shutdown to stop and clean communicator
214 */
215 struct GNUNET_SCHEDULER_Task *c_shutdown_task;
216
217 /**
218 * @brief Characteristics of the communicator
219 */
220 enum GNUNET_TRANSPORT_CommunicatorCharacteristics c_characteristics;
221
222 /**
223 * @brief Specifies supported addresses
224 */
225 char *c_addr_prefix;
226
227 /**
228 * @brief Specifies supported addresses
229 */
230 char *c_address;
231
232 /**
233 * @brief Head of the DLL of queues associated with this communicator
234 */
235 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *queue_head;
236
237 /**
238 * @brief Tail of the DLL of queues associated with this communicator
239 */
240 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *queue_tail;
241
242 /* Callbacks + Closures */
243 /**
244 * @brief Callback called when a new communicator connects
245 */
246 GNUNET_TRANSPORT_TESTING_CommunicatorAvailableCallback
247 communicator_available_cb;
248
249 /**
250 * @brief Callback called when a new communicator connects
251 */
252 GNUNET_TRANSPORT_TESTING_AddAddressCallback add_address_cb;
253
254 /**
255 * @brief Callback called when a new communicator connects
256 */
257 GNUNET_TRANSPORT_TESTING_QueueCreateReplyCallback queue_create_reply_cb;
258
259 /**
260 * @brief Callback called when a new communicator connects
261 */
262 GNUNET_TRANSPORT_TESTING_AddQueueCallback add_queue_cb;
263
264 /**
265 * @brief Callback called when a new communicator connects
266 */
267 GNUNET_TRANSPORT_TESTING_IncomingMessageCallback incoming_msg_cb;
268
269 /**
270 * @brief Backchannel callback
271 */
272 GNUNET_TRANSPORT_TESTING_BackchannelCallback bc_cb;
273
274 /**
275 * Our service handle
276 */
277 struct GNUNET_SERVICE_Handle *sh;
278
279 /**
280 * @brief Closure to the callback
281 */
282 void *cb_cls;
283
284 /**
285 * Backchannel supported
286 */
287 int bc_enabled;
288};
289
290/**
291 * @brief Start communicator part of transport service and communicator
292 *
293 * @param service_name Name of the service
294 * @param cfg Configuration handle
295 * @param communicator_available Callback that is called when a new
296 * communicator becomes available
297 * @param add_address_cb Callback handling new addresses
298 * @param queue_create_reply_cb Callback handling success of queue requests
299 * @param add_queue_cb Callback handling freshly created queues
300 * @param incoming_message_cb Callback handling incoming messages
301 * @param cb_cls Closure to @p communicator_available
302 *
303 * @return Handle to the communicator duo
304 */
305struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *
306GNUNET_TRANSPORT_TESTING_transport_communicator_service_start (
307 const char *service_name,
308 const char *binary_name,
309 const char *cfg_filename,
310 const struct GNUNET_PeerIdentity *peer_id,
311 GNUNET_TRANSPORT_TESTING_CommunicatorAvailableCallback
312 communicator_available_cb,
313 GNUNET_TRANSPORT_TESTING_AddAddressCallback add_address_cb,
314 GNUNET_TRANSPORT_TESTING_QueueCreateReplyCallback queue_create_reply_cb,
315 GNUNET_TRANSPORT_TESTING_AddQueueCallback add_queue_cb,
316 GNUNET_TRANSPORT_TESTING_IncomingMessageCallback incoming_message_cb,
317 GNUNET_TRANSPORT_TESTING_BackchannelCallback bc_cb,
318 void *cb_cls);
319
320
321void
322GNUNET_TRANSPORT_TESTING_transport_communicator_service_stop (
323 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h);
324
325
326/**
327 * @brief Instruct communicator to open a queue
328 *
329 * @param tc_h Handle to communicator which shall open queue
330 * @param peer_id Towards which peer
331 * @param address For which address
332 */
333void
334GNUNET_TRANSPORT_TESTING_transport_communicator_open_queue (struct
335 GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle
336 *tc_h,
337 const struct
338 GNUNET_PeerIdentity
339 *peer_id,
340 const char *address);
341
342
343/**
344 * @brief Instruct communicator to send data
345 *
346 * @param tc_queue The queue to use for sending
347 * @param cont function to call when done sending
348 * @param cont_cls closure for @a cont
349 * @param payload Data to send
350 * @param payload_size Size of the @a payload
351 */
352void
353GNUNET_TRANSPORT_TESTING_transport_communicator_send (struct
354 GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle
355 *tc_h,
356 GNUNET_SCHEDULER_TaskCallback
357 cont,
358 void *cont_cls,
359 const void *payload,
360 size_t payload_size);
diff --git a/src/transport/transport-testing-filenames.c b/src/transport/transport-testing-filenames.c
deleted file mode 100644
index 7c136b690..000000000
--- a/src/transport/transport-testing-filenames.c
+++ /dev/null
@@ -1,202 +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 "transport-testing.h"
27
28
29/**
30 * Removes all directory separators from absolute filename
31 *
32 * @param file the absolute file name, e.g. as found in argv[0]
33 * @return extracted file name, has to be freed by caller
34 */
35static char *
36extract_filename (const char *file)
37{
38 char *pch = GNUNET_strdup (file);
39 char *backup = pch;
40 char *filename = NULL;
41 char *res;
42
43 if (NULL != strstr (pch, "/"))
44 {
45 pch = strtok (pch, "/");
46 while (pch != NULL)
47 {
48 pch = strtok (NULL, "/");
49 if (pch != NULL)
50 {
51 filename = pch;
52 }
53 }
54 }
55 else
56 filename = pch;
57
58 res = GNUNET_strdup (filename);
59 GNUNET_free (backup);
60 return res;
61}
62
63
64/**
65 * Extracts the test filename from an absolute file name and removes
66 * the extension
67 *
68 * @param file absolute file name
69 * @return the result
70 */
71char *
72GNUNET_TRANSPORT_TESTING_get_test_name (const char *file)
73{
74 char *backup = extract_filename (file);
75 char *filename = backup;
76 char *dotexe;
77 char *ret;
78
79 if (NULL == filename)
80 return NULL;
81
82 /* remove "lt-" */
83 filename = strstr (filename, "test");
84 if (NULL == filename)
85 {
86 GNUNET_free (backup);
87 return NULL;
88 }
89
90 /* remove ".exe" */
91 if (NULL != (dotexe = strstr (filename, ".exe")))
92 dotexe[0] = '\0';
93 ret = GNUNET_strdup (filename);
94 GNUNET_free (backup);
95 return ret;
96}
97
98
99/**
100 * Extracts the filename from an absolute file name and removes the extension
101 *
102 * @param file absolute file name
103 * @return the result
104 */
105char *
106GNUNET_TRANSPORT_TESTING_get_test_source_name (const char *file)
107{
108 char *src = extract_filename (file);
109 char *split;
110
111 split = strstr (src, ".");
112 if (NULL != split)
113 split[0] = '\0';
114 return src;
115}
116
117
118/**
119 * Extracts the plugin name from an absolute file name and the test name
120 *
121 * @param file absolute file name
122 * @param test test name
123 * @return the result
124 */
125char *
126GNUNET_TRANSPORT_TESTING_get_test_plugin_name (const char *file,
127 const char *test)
128{
129 char *filename;
130 char *dotexe;
131 char *e = extract_filename (file);
132 char *t = extract_filename (test);
133 char *ret;
134
135 if (NULL == e)
136 goto fail;
137 /* remove "lt-" */
138 filename = strstr (e, "tes");
139 if (NULL == filename)
140 goto fail;
141 /* remove ".exe" */
142 if (NULL != (dotexe = strstr (filename, ".exe")))
143 dotexe[0] = '\0';
144
145 /* find last _ */
146 filename = strstr (filename, t);
147 if (NULL == filename)
148 goto fail;
149 /* copy plugin */
150 filename += strlen (t);
151 if ('\0' != *filename)
152 filename++;
153 ret = GNUNET_strdup (filename);
154 goto suc;
155fail:
156 ret = NULL;
157suc:
158 GNUNET_free (t);
159 GNUNET_free (e);
160 return ret;
161}
162
163
164/**
165 * This function takes the filename (e.g. argv[0), removes a "lt-"-prefix and
166 * if existing ".exe"-prefix and adds the peer-number
167 *
168 * @param file filename of the test, e.g. argv[0]
169 * @param count peer number
170 * @return the result
171 */
172char *
173GNUNET_TRANSPORT_TESTING_get_config_name (const char *file,
174 int count)
175{
176 char *filename = extract_filename (file);
177 char *backup = filename;
178 char *dotexe;
179 char *ret;
180
181 if (NULL == filename)
182 return NULL;
183 /* remove "lt-" */
184 filename = strstr (filename, "test");
185 if (NULL == filename)
186 goto fail;
187 /* remove ".exe" */
188 if (NULL != (dotexe = strstr (filename, ".exe")))
189 dotexe[0] = '\0';
190 GNUNET_asprintf (&ret,
191 "%s_peer%u.conf",
192 filename,
193 count);
194 GNUNET_free (backup);
195 return ret;
196fail:
197 GNUNET_free (backup);
198 return NULL;
199}
200
201
202/* end of transport-testing-filenames.c */
diff --git a/src/transport/transport-testing-filenames2.c b/src/transport/transport-testing-filenames2.c
deleted file mode 100644
index 7d6fd529d..000000000
--- a/src/transport/transport-testing-filenames2.c
+++ /dev/null
@@ -1,202 +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 "transport-testing2.h"
27
28
29/**
30 * Removes all directory separators from absolute filename
31 *
32 * @param file the absolute file name, e.g. as found in argv[0]
33 * @return extracted file name, has to be freed by caller
34 */
35static char *
36extract_filename (const char *file)
37{
38 char *pch = GNUNET_strdup (file);
39 char *backup = pch;
40 char *filename = NULL;
41 char *res;
42
43 if (NULL != strstr (pch, "/"))
44 {
45 pch = strtok (pch, "/");
46 while (pch != NULL)
47 {
48 pch = strtok (NULL, "/");
49 if (pch != NULL)
50 {
51 filename = pch;
52 }
53 }
54 }
55 else
56 filename = pch;
57
58 res = GNUNET_strdup (filename);
59 GNUNET_free (backup);
60 return res;
61}
62
63
64/**
65 * Extracts the test filename from an absolute file name and removes
66 * the extension
67 *
68 * @param file absolute file name
69 * @return the result
70 */
71char *
72GNUNET_TRANSPORT_TESTING_get_test_name (const char *file)
73{
74 char *backup = extract_filename (file);
75 char *filename = backup;
76 char *dotexe;
77 char *ret;
78
79 if (NULL == filename)
80 return NULL;
81
82 /* remove "lt-" */
83 filename = strstr (filename, "test");
84 if (NULL == filename)
85 {
86 GNUNET_free (backup);
87 return NULL;
88 }
89
90 /* remove ".exe" */
91 if (NULL != (dotexe = strstr (filename, ".exe")))
92 dotexe[0] = '\0';
93 ret = GNUNET_strdup (filename);
94 GNUNET_free (backup);
95 return ret;
96}
97
98
99/**
100 * Extracts the filename from an absolute file name and removes the extension
101 *
102 * @param file absolute file name
103 * @return the result
104 */
105char *
106GNUNET_TRANSPORT_TESTING_get_test_source_name (const char *file)
107{
108 char *src = extract_filename (file);
109 char *split;
110
111 split = strstr (src, ".");
112 if (NULL != split)
113 split[0] = '\0';
114 return src;
115}
116
117
118/**
119 * Extracts the plugin name from an absolute file name and the test name
120 *
121 * @param file absolute file name
122 * @param test test name
123 * @return the result
124 */
125char *
126GNUNET_TRANSPORT_TESTING_get_test_plugin_name (const char *file,
127 const char *test)
128{
129 char *filename;
130 char *dotexe;
131 char *e = extract_filename (file);
132 char *t = extract_filename (test);
133 char *ret;
134
135 if (NULL == e)
136 goto fail;
137 /* remove "lt-" */
138 filename = strstr (e, "tes");
139 if (NULL == filename)
140 goto fail;
141 /* remove ".exe" */
142 if (NULL != (dotexe = strstr (filename, ".exe")))
143 dotexe[0] = '\0';
144
145 /* find last _ */
146 filename = strstr (filename, t);
147 if (NULL == filename)
148 goto fail;
149 /* copy plugin */
150 filename += strlen (t);
151 if ('\0' != *filename)
152 filename++;
153 ret = GNUNET_strdup (filename);
154 goto suc;
155fail:
156 ret = NULL;
157suc:
158 GNUNET_free (t);
159 GNUNET_free (e);
160 return ret;
161}
162
163
164/**
165 * This function takes the filename (e.g. argv[0), removes a "lt-"-prefix and
166 * if existing ".exe"-prefix and adds the peer-number
167 *
168 * @param file filename of the test, e.g. argv[0]
169 * @param count peer number
170 * @return the result
171 */
172char *
173GNUNET_TRANSPORT_TESTING_get_config_name (const char *file,
174 int count)
175{
176 char *filename = extract_filename (file);
177 char *backup = filename;
178 char *dotexe;
179 char *ret;
180
181 if (NULL == filename)
182 return NULL;
183 /* remove "lt-" */
184 filename = strstr (filename, "test");
185 if (NULL == filename)
186 goto fail;
187 /* remove ".exe" */
188 if (NULL != (dotexe = strstr (filename, ".exe")))
189 dotexe[0] = '\0';
190 GNUNET_asprintf (&ret,
191 "%s_peer%u.conf",
192 filename,
193 count);
194 GNUNET_free (backup);
195 return ret;
196fail:
197 GNUNET_free (backup);
198 return NULL;
199}
200
201
202/* 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 330a392c6..000000000
--- a/src/transport/transport-testing-loggers.c
+++ /dev/null
@@ -1,80 +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 "transport-testing.h"
26
27
28/**
29 * Log a connect event.
30 *
31 * @param cls NULL
32 * @param me peer that had the event
33 * @param other peer that connected.
34 */
35void
36GNUNET_TRANSPORT_TESTING_log_connect (void *cls,
37 struct
38 GNUNET_TRANSPORT_TESTING_PeerContext *me,
39 const struct GNUNET_PeerIdentity *other)
40{
41 char *ps;
42
43 ps = GNUNET_strdup (GNUNET_i2s (&me->id));
44 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
45 "Peer %s connected to %u (%s)!\n",
46 GNUNET_i2s (other),
47 me->no,
48 ps);
49 GNUNET_free (ps);
50}
51
52
53/**
54 * Log a disconnect event.
55 *
56 * @param cls NULL
57 * @param me peer that had the event
58 * @param other peer that disconnected.
59 */
60void
61GNUNET_TRANSPORT_TESTING_log_disconnect (void *cls,
62 struct
63 GNUNET_TRANSPORT_TESTING_PeerContext *
64 me,
65 const struct
66 GNUNET_PeerIdentity *other)
67{
68 char *ps;
69
70 ps = GNUNET_strdup (GNUNET_i2s (&me->id));
71 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
72 "Peer `%s' disconnected from %u (%s)!\n",
73 GNUNET_i2s (other),
74 me->no,
75 ps);
76 GNUNET_free (ps);
77}
78
79
80/* end of transport-testing-loggers.c */
diff --git a/src/transport/transport-testing-loggers2.c b/src/transport/transport-testing-loggers2.c
deleted file mode 100644
index ead4fa365..000000000
--- a/src/transport/transport-testing-loggers2.c
+++ /dev/null
@@ -1,80 +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 "transport-testing2.h"
26
27
28/**
29 * Log a connect event.
30 *
31 * @param cls NULL
32 * @param me peer that had the event
33 * @param other peer that connected.
34 */
35void
36GNUNET_TRANSPORT_TESTING_log_connect (void *cls,
37 struct
38 GNUNET_TRANSPORT_TESTING_PeerContext *me,
39 const struct GNUNET_PeerIdentity *other)
40{
41 char *ps;
42
43 ps = GNUNET_strdup (GNUNET_i2s (&me->id));
44 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
45 "Peer %s connected to %u (%s)!\n",
46 GNUNET_i2s (other),
47 me->no,
48 ps);
49 GNUNET_free (ps);
50}
51
52
53/**
54 * Log a disconnect event.
55 *
56 * @param cls NULL
57 * @param me peer that had the event
58 * @param other peer that disconnected.
59 */
60void
61GNUNET_TRANSPORT_TESTING_log_disconnect (void *cls,
62 struct
63 GNUNET_TRANSPORT_TESTING_PeerContext *
64 me,
65 const struct
66 GNUNET_PeerIdentity *other)
67{
68 char *ps;
69
70 ps = GNUNET_strdup (GNUNET_i2s (&me->id));
71 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
72 "Peer `%s' disconnected from %u (%s)!\n",
73 GNUNET_i2s (other),
74 me->no,
75 ps);
76 GNUNET_free (ps);
77}
78
79
80/* 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 20c58eeee..000000000
--- a/src/transport/transport-testing-main.c
+++ /dev/null
@@ -1,613 +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 "transport-testing.h"
26
27
28/**
29 * Closure for #connect_cb.
30 */
31struct GNUNET_TRANSPORT_TESTING_ConnectRequestList
32{
33 /**
34 * Stored in a DLL.
35 */
36 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *next;
37
38 /**
39 * Stored in a DLL.
40 */
41 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *prev;
42
43 /**
44 * Overall context we are in.
45 */
46 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
47
48 /**
49 * Connect request this is about.
50 */
51 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cr;
52
53 /**
54 * Peer being connected.
55 */
56 struct GNUNET_TRANSPORT_TESTING_PeerContext *p1;
57
58 /**
59 * Peer being connected.
60 */
61 struct GNUNET_TRANSPORT_TESTING_PeerContext *p2;
62};
63
64
65/**
66 * Shutdown function for the test. Stops all peers.
67 *
68 * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *`
69 */
70static void
71do_shutdown (void *cls)
72{
73 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = cls;
74 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *crl;
75
76 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
77 "Testcase shutting down\n");
78 if (NULL != ccc->shutdown_task)
79 ccc->shutdown_task (ccc->shutdown_task_cls);
80 if (NULL != ccc->timeout_task)
81 {
82 GNUNET_SCHEDULER_cancel (ccc->timeout_task);
83 ccc->timeout_task = NULL;
84 }
85 if (NULL != ccc->connect_task)
86 {
87 GNUNET_SCHEDULER_cancel (ccc->connect_task);
88 ccc->connect_task = NULL;
89 }
90 while (NULL != (crl = ccc->crl_head))
91 {
92 GNUNET_CONTAINER_DLL_remove (ccc->crl_head,
93 ccc->crl_tail,
94 crl);
95 GNUNET_TRANSPORT_TESTING_connect_peers_cancel (crl->cr);
96 GNUNET_free (crl);
97 }
98 for (unsigned int i = 0; i < ccc->num_peers; i++)
99 {
100 if (NULL != ccc->p[i])
101 {
102 GNUNET_TRANSPORT_TESTING_stop_peer (ccc->p[i]);
103 ccc->p[i] = NULL;
104 }
105 }
106}
107
108
109/**
110 * Testcase hit timeout, shut it down with error.
111 *
112 * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *`
113 */
114static void
115do_timeout (void *cls)
116{
117 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = cls;
118
119 ccc->timeout_task = NULL;
120 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
121 "Testcase timed out\n");
122 ccc->global_ret = GNUNET_SYSERR;
123 GNUNET_SCHEDULER_shutdown ();
124}
125
126
127/**
128 * Internal data structure. Closure for
129 * #connect_cb, #disconnect_cb, #my_nc and #start_cb.
130 * Allows us to identify which peer this is about.
131 */
132struct GNUNET_TRANSPORT_TESTING_InternalPeerContext
133{
134 /**
135 * Overall context of the callback.
136 */
137 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
138
139 /**
140 * Offset of the peer this is about.
141 */
142 unsigned int off;
143};
144
145
146/**
147 * Information tracked per connected peer.
148 */
149struct ConnectPairInfo
150{
151 /**
152 * Peer this is about.
153 */
154 const struct GNUNET_PeerIdentity *sender;
155
156 /**
157 * Information about the receiving peer.
158 */
159 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi;
160};
161
162
163/**
164 * Function called when we connected two peers. Once we have gotten
165 * to the clique, launch test-specific logic.
166 *
167 * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *`
168 */
169static void
170connect_cb (void *cls)
171{
172 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *crl = cls;
173 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = crl->ccc;
174
175 GNUNET_CONTAINER_DLL_remove (ccc->crl_head,
176 ccc->crl_tail,
177 crl);
178 {
179 char *p1_c = GNUNET_strdup (GNUNET_i2s (&crl->p1->id));
180
181 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
182 "Peers connected: %u (%s) <-> %u (%s)\n",
183 crl->p1->no,
184 p1_c,
185 crl->p2->no,
186 GNUNET_i2s (&crl->p2->id));
187 GNUNET_free (p1_c);
188 GNUNET_free (crl);
189 }
190 if (NULL == ccc->crl_head)
191 {
192 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
193 "All connections UP, launching custom test logic.\n");
194 GNUNET_SCHEDULER_add_now (ccc->connect_continuation,
195 ccc->connect_continuation_cls);
196 }
197}
198
199
200/**
201 * Find peer by peer ID.
202 *
203 * @param ccc context to search
204 * @param peer peer to look for
205 * @return NULL if @a peer was not found
206 */
207struct GNUNET_TRANSPORT_TESTING_PeerContext *
208GNUNET_TRANSPORT_TESTING_find_peer (struct
209 GNUNET_TRANSPORT_TESTING_ConnectCheckContext
210 *ccc,
211 const struct GNUNET_PeerIdentity *peer)
212{
213 for (unsigned int i = 0; i < ccc->num_peers; i++)
214 if ((NULL != ccc->p[i]) &&
215 (0 == memcmp (peer,
216 &ccc->p[i]->id,
217 sizeof(*peer))))
218 return ccc->p[i];
219 return NULL;
220}
221
222
223/**
224 * Wrapper around peers connecting. Calls client's nc function.
225 *
226 * @param cls our `struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *`
227 * @param peer peer we got connected to
228 * @param mq message queue for transmissions to @a peer
229 * @return closure for message handlers
230 */
231static void *
232my_nc (void *cls,
233 const struct GNUNET_PeerIdentity *peer,
234 struct GNUNET_MQ_Handle *mq)
235{
236 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi = cls;
237 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = ipi->ccc;
238 struct ConnectPairInfo *cpi;
239
240 if (NULL != ccc->nc)
241 ccc->nc (ccc->cls,
242 ccc->p[ipi->off],
243 peer);
244 cpi = GNUNET_new (struct ConnectPairInfo);
245 cpi->ipi = ipi;
246 cpi->sender = peer; /* valid until disconnect */
247 return cpi;
248}
249
250
251/**
252 * Wrapper around peers disconnecting. Calls client's nd function.
253 *
254 * @param cls our `struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *`
255 * @param peer peer we got disconnected from
256 * @param custom_cls return value from @my_nc
257 */
258static void
259my_nd (void *cls,
260 const struct GNUNET_PeerIdentity *peer,
261 void *custom_cls)
262{
263 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi = cls;
264 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = ipi->ccc;
265 struct ConnectPairInfo *cpi = custom_cls;
266
267 if (NULL != ccc->nd)
268 ccc->nd (ccc->cls,
269 ccc->p[ipi->off],
270 peer);
271 GNUNET_free (cpi);
272}
273
274
275/**
276 * Wrapper around receiving data. Calls client's rec function.
277 *
278 * @param cls our `struct ConnectPairInfo *`
279 * @param message message we received
280 * @return #GNUNET_OK (all messages are fine)
281 */
282static int
283check_test (void *cls,
284 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
285{
286 return GNUNET_OK;
287}
288
289
290/**
291 * Wrapper around receiving data. Calls client's rec function.
292 *
293 * @param cls our `struct ConnectPairInfo *`
294 * @param message message we received
295 */
296static void
297handle_test (void *cls,
298 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
299{
300 struct ConnectPairInfo *cpi = cls;
301 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi = cpi->ipi;
302 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = ipi->ccc;
303
304 if (NULL != ccc->rec)
305 ccc->rec (ccc->cls,
306 ccc->p[ipi->off],
307 cpi->sender,
308 message);
309}
310
311
312/**
313 * Wrapper around receiving data. Calls client's rec function.
314 *
315 * @param cls our `struct ConnectPairInfo *`
316 * @param message message we received
317 * @return #GNUNET_OK (all messages are fine)
318 */
319static int
320check_test2 (void *cls,
321 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
322{
323 return GNUNET_OK;
324}
325
326
327/**
328 * Wrapper around receiving data. Calls client's rec function.
329 *
330 * @param cls our `struct ConnectPairInfo *`
331 * @param message message we received
332 */
333static void
334handle_test2 (void *cls,
335 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
336{
337 struct ConnectPairInfo *cpi = cls;
338 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi = cpi->ipi;
339 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = ipi->ccc;
340
341 if (NULL != ccc->rec)
342 ccc->rec (ccc->cls,
343 ccc->p[ipi->off],
344 cpi->sender,
345 message);
346}
347
348
349/**
350 * Connect the peers as a clique.
351 *
352 * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext`
353 */
354static void
355do_connect (void *cls)
356{
357 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = cls;
358
359 ccc->connect_task = NULL;
360 for (unsigned int i = 0; i < ccc->num_peers; i++)
361 for (unsigned int j = (ccc->bi_directional ? 0 : i + 1); j < ccc->num_peers;
362 j++)
363 {
364 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *crl;
365
366 if (i == j)
367 continue;
368 crl = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_ConnectRequestList);
369 GNUNET_CONTAINER_DLL_insert (ccc->crl_head,
370 ccc->crl_tail,
371 crl);
372 crl->ccc = ccc;
373 crl->p1 = ccc->p[i];
374 crl->p2 = ccc->p[j];
375 {
376 char *sender_c = GNUNET_strdup (GNUNET_i2s (&ccc->p[0]->id));
377
378 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
379 "Test tries to connect peer %u (`%s') -> peer %u (`%s')\n",
380 ccc->p[0]->no,
381 sender_c,
382 ccc->p[1]->no,
383 GNUNET_i2s (&ccc->p[1]->id));
384 GNUNET_free (sender_c);
385 }
386 crl->cr = GNUNET_TRANSPORT_TESTING_connect_peers (ccc->p[i],
387 ccc->p[j],
388 &connect_cb,
389 crl);
390 }
391}
392
393
394/**
395 * Function called once we have successfully launched a peer.
396 * Once all peers have been launched, we connect all of them
397 * in a clique.
398 *
399 * @param cls our `struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *`
400 */
401static void
402start_cb (void *cls)
403{
404 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi = cls;
405 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = ipi->ccc;
406 struct GNUNET_TRANSPORT_TESTING_PeerContext *p = ccc->p[ipi->off];
407
408 ccc->started++;
409 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
410 "Peer %u (`%s') started\n",
411 p->no,
412 GNUNET_i2s (&p->id));
413 if (ccc->started != ccc->num_peers)
414 return;
415 if (NULL != ccc->pre_connect_task)
416 {
417 /* Run the custom per-connect job, then give it a second to
418 go into effect before we continue connecting peers. */
419 ccc->pre_connect_task (ccc->pre_connect_task_cls);
420 ccc->connect_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
421 &do_connect,
422 ccc);
423 }
424 else
425 {
426 do_connect (ccc);
427 }
428}
429
430
431/**
432 * Function run from #GNUNET_TRANSPORT_TESTING_connect_check
433 * once the scheduler is up. Should launch the peers and
434 * then in the continuations try to connect them.
435 *
436 * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *`
437 * @param args ignored
438 * @param cfgfile ignored
439 * @param cfg configuration
440 */
441static void
442connect_check_run (void *cls,
443 char *const *args,
444 const char *cfgfile,
445 const struct GNUNET_CONFIGURATION_Handle *cfg)
446{
447 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = cls;
448 int ok;
449
450 ccc->cfg = cfg;
451 ccc->timeout_task = GNUNET_SCHEDULER_add_delayed (ccc->timeout,
452 &do_timeout,
453 ccc);
454 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
455 ccc);
456 ok = GNUNET_OK;
457 for (unsigned int i = 0; i < ccc->num_peers; i++)
458 {
459 struct GNUNET_MQ_MessageHandler handlers[] = {
460 GNUNET_MQ_hd_var_size (test,
461 GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE,
462 struct GNUNET_TRANSPORT_TESTING_TestMessage,
463 NULL),
464 GNUNET_MQ_hd_var_size (test2,
465 GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE2,
466 struct GNUNET_TRANSPORT_TESTING_TestMessage,
467 NULL),
468 GNUNET_MQ_handler_end ()
469 };
470 ccc->p[i] = GNUNET_TRANSPORT_TESTING_start_peer (ccc->tth,
471 ccc->cfg_files[i],
472 i + 1,
473 handlers,
474 &my_nc,
475 &my_nd,
476 &ccc->ip[i],
477 &start_cb,
478 &ccc->ip[i]);
479 if (NULL == ccc->p[i])
480 ok = GNUNET_SYSERR;
481 }
482 if (GNUNET_OK != ok)
483 {
484 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
485 "Fail! Could not start peers!\n");
486 GNUNET_SCHEDULER_shutdown ();
487 }
488}
489
490
491/**
492 * Common implementation of the #GNUNET_TRANSPORT_TESTING_CheckCallback.
493 * Starts and connects the two peers, then invokes the
494 * `connect_continuation` from @a cls. Sets up a timeout to
495 * abort the test, and a shutdown handler to clean up properly
496 * on exit.
497 *
498 * @param cls closure of type `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext`
499 * @param tth_ initialized testing handle
500 * @param test_plugin_ name of the plugin
501 * @param test_name_ name of the test
502 * @param num_peers number of entries in the @a cfg_file array
503 * @param cfg_files array of names of configuration files for the peers
504 * @return #GNUNET_SYSERR on error
505 */
506int
507GNUNET_TRANSPORT_TESTING_connect_check (void *cls,
508 struct GNUNET_TRANSPORT_TESTING_Handle *
509 tth_,
510 const char *test_plugin_,
511 const char *test_name_,
512 unsigned int num_peers,
513 char *cfg_files[])
514{
515 static struct GNUNET_GETOPT_CommandLineOption options[] = {
516 GNUNET_GETOPT_OPTION_END
517 };
518 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = cls;
519 struct GNUNET_TRANSPORT_TESTING_PeerContext *p[num_peers];
520 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext ip[num_peers];
521 char *argv[] = {
522 (char *) test_name_,
523 "-c",
524 (char *) ccc->config_file,
525 NULL
526 };
527
528 ccc->num_peers = num_peers;
529 ccc->cfg_files = cfg_files;
530 ccc->test_plugin = test_plugin_;
531 ccc->test_name = test_name_;
532 ccc->tth = tth_;
533 ccc->global_ret = GNUNET_OK;
534 ccc->p = p;
535 ccc->ip = ip;
536 for (unsigned int i = 0; i < num_peers; i++)
537 {
538 ip[i].off = i;
539 ip[i].ccc = ccc;
540 }
541 if (GNUNET_OK !=
542 GNUNET_PROGRAM_run ((sizeof(argv) / sizeof(char *)) - 1,
543 argv,
544 test_name_,
545 "nohelp",
546 options,
547 &connect_check_run,
548 ccc))
549 return GNUNET_SYSERR;
550 return ccc->global_ret;
551}
552
553
554/**
555 * Setup testcase. Calls @a check with the data the test needs.
556 *
557 * @param argv0 binary name (argv[0])
558 * @param filename source file name (__FILE__)
559 * @param num_peers number of peers to start
560 * @param check main function to run
561 * @param check_cls closure for @a check
562 * @return #GNUNET_OK on success
563 */
564int
565GNUNET_TRANSPORT_TESTING_main_ (const char *argv0,
566 const char *filename,
567 unsigned int num_peers,
568 GNUNET_TRANSPORT_TESTING_CheckCallback check,
569 void *check_cls)
570{
571 struct GNUNET_TRANSPORT_TESTING_Handle *tth;
572 char *test_name;
573 char *test_source;
574 char *test_plugin;
575 char *cfg_names[num_peers];
576 int ret;
577
578 ret = GNUNET_OK;
579 test_name = GNUNET_TRANSPORT_TESTING_get_test_name (argv0);
580 GNUNET_log_setup (test_name,
581 "WARNING",
582 NULL);
583 test_source = GNUNET_TRANSPORT_TESTING_get_test_source_name (filename);
584 test_plugin = GNUNET_TRANSPORT_TESTING_get_test_plugin_name (argv0,
585 test_source);
586 for (unsigned int i = 0; i < num_peers; i++)
587 cfg_names[i] = GNUNET_TRANSPORT_TESTING_get_config_name (argv0,
588 i + 1);
589 tth = GNUNET_TRANSPORT_TESTING_init ();
590 if (NULL == tth)
591 {
592 ret = GNUNET_SYSERR;
593 }
594 else
595 {
596 ret = check (check_cls,
597 tth,
598 test_plugin,
599 test_name,
600 num_peers,
601 cfg_names);
602 GNUNET_TRANSPORT_TESTING_done (tth);
603 }
604 for (unsigned int i = 0; i < num_peers; i++)
605 GNUNET_free (cfg_names[i]);
606 GNUNET_free (test_source);
607 GNUNET_free (test_plugin);
608 GNUNET_free (test_name);
609 return ret;
610}
611
612
613/* end of transport-testing-main.c */
diff --git a/src/transport/transport-testing-main2.c b/src/transport/transport-testing-main2.c
deleted file mode 100644
index 62aa3ceb7..000000000
--- a/src/transport/transport-testing-main2.c
+++ /dev/null
@@ -1,613 +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 "transport-testing2.h"
26
27
28/**
29 * Closure for #connect_cb.
30 */
31struct GNUNET_TRANSPORT_TESTING_ConnectRequestList
32{
33 /**
34 * Stored in a DLL.
35 */
36 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *next;
37
38 /**
39 * Stored in a DLL.
40 */
41 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *prev;
42
43 /**
44 * Overall context we are in.
45 */
46 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
47
48 /**
49 * Connect request this is about.
50 */
51 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cr;
52
53 /**
54 * Peer being connected.
55 */
56 struct GNUNET_TRANSPORT_TESTING_PeerContext *p1;
57
58 /**
59 * Peer being connected.
60 */
61 struct GNUNET_TRANSPORT_TESTING_PeerContext *p2;
62};
63
64
65/**
66 * Shutdown function for the test. Stops all peers.
67 *
68 * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *`
69 */
70static void
71do_shutdown (void *cls)
72{
73 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = cls;
74 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *crl;
75
76 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
77 "Testcase shutting down\n");
78 if (NULL != ccc->shutdown_task)
79 ccc->shutdown_task (ccc->shutdown_task_cls);
80 if (NULL != ccc->timeout_task)
81 {
82 GNUNET_SCHEDULER_cancel (ccc->timeout_task);
83 ccc->timeout_task = NULL;
84 }
85 if (NULL != ccc->connect_task)
86 {
87 GNUNET_SCHEDULER_cancel (ccc->connect_task);
88 ccc->connect_task = NULL;
89 }
90 while (NULL != (crl = ccc->crl_head))
91 {
92 GNUNET_CONTAINER_DLL_remove (ccc->crl_head,
93 ccc->crl_tail,
94 crl);
95 GNUNET_TRANSPORT_TESTING_connect_peers_cancel (crl->cr);
96 GNUNET_free (crl);
97 }
98 for (unsigned int i = 0; i < ccc->num_peers; i++)
99 {
100 if (NULL != ccc->p[i])
101 {
102 GNUNET_TRANSPORT_TESTING_stop_peer (ccc->p[i]);
103 ccc->p[i] = NULL;
104 }
105 }
106}
107
108
109/**
110 * Testcase hit timeout, shut it down with error.
111 *
112 * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *`
113 */
114static void
115do_timeout (void *cls)
116{
117 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = cls;
118
119 ccc->timeout_task = NULL;
120 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
121 "Testcase timed out\n");
122 ccc->global_ret = GNUNET_SYSERR;
123 GNUNET_SCHEDULER_shutdown ();
124}
125
126
127/**
128 * Internal data structure. Closure for
129 * #connect_cb, #disconnect_cb, #my_nc and #start_cb.
130 * Allows us to identify which peer this is about.
131 */
132struct GNUNET_TRANSPORT_TESTING_InternalPeerContext
133{
134 /**
135 * Overall context of the callback.
136 */
137 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
138
139 /**
140 * Offset of the peer this is about.
141 */
142 unsigned int off;
143};
144
145
146/**
147 * Information tracked per connected peer.
148 */
149struct ConnectPairInfo
150{
151 /**
152 * Peer this is about.
153 */
154 const struct GNUNET_PeerIdentity *sender;
155
156 /**
157 * Information about the receiving peer.
158 */
159 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi;
160};
161
162
163/**
164 * Function called when we connected two peers. Once we have gotten
165 * to the clique, launch test-specific logic.
166 *
167 * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *`
168 */
169static void
170connect_cb (void *cls)
171{
172 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *crl = cls;
173 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = crl->ccc;
174
175 GNUNET_CONTAINER_DLL_remove (ccc->crl_head,
176 ccc->crl_tail,
177 crl);
178 {
179 char *p1_c = GNUNET_strdup (GNUNET_i2s (&crl->p1->id));
180
181 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
182 "Peers connected: %u (%s) <-> %u (%s)\n",
183 crl->p1->no,
184 p1_c,
185 crl->p2->no,
186 GNUNET_i2s (&crl->p2->id));
187 GNUNET_free (p1_c);
188 GNUNET_free (crl);
189 }
190 if (NULL == ccc->crl_head)
191 {
192 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
193 "All connections UP, launching custom test logic.\n");
194 GNUNET_SCHEDULER_add_now (ccc->connect_continuation,
195 ccc->connect_continuation_cls);
196 }
197}
198
199
200/**
201 * Find peer by peer ID.
202 *
203 * @param ccc context to search
204 * @param peer peer to look for
205 * @return NULL if @a peer was not found
206 */
207struct GNUNET_TRANSPORT_TESTING_PeerContext *
208GNUNET_TRANSPORT_TESTING_find_peer (struct
209 GNUNET_TRANSPORT_TESTING_ConnectCheckContext
210 *ccc,
211 const struct GNUNET_PeerIdentity *peer)
212{
213 for (unsigned int i = 0; i < ccc->num_peers; i++)
214 if ((NULL != ccc->p[i]) &&
215 (0 == memcmp (peer,
216 &ccc->p[i]->id,
217 sizeof(*peer))))
218 return ccc->p[i];
219 return NULL;
220}
221
222
223/**
224 * Wrapper around peers connecting. Calls client's nc function.
225 *
226 * @param cls our `struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *`
227 * @param peer peer we got connected to
228 * @param mq message queue for transmissions to @a peer
229 * @return closure for message handlers
230 */
231static void *
232my_nc (void *cls,
233 const struct GNUNET_PeerIdentity *peer,
234 struct GNUNET_MQ_Handle *mq)
235{
236 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi = cls;
237 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = ipi->ccc;
238 struct ConnectPairInfo *cpi;
239
240 if (NULL != ccc->nc)
241 ccc->nc (ccc->cls,
242 ccc->p[ipi->off],
243 peer);
244 cpi = GNUNET_new (struct ConnectPairInfo);
245 cpi->ipi = ipi;
246 cpi->sender = peer; /* valid until disconnect */
247 return cpi;
248}
249
250
251/**
252 * Wrapper around peers disconnecting. Calls client's nd function.
253 *
254 * @param cls our `struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *`
255 * @param peer peer we got disconnected from
256 * @param custom_cls return value from @my_nc
257 */
258static void
259my_nd (void *cls,
260 const struct GNUNET_PeerIdentity *peer,
261 void *custom_cls)
262{
263 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi = cls;
264 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = ipi->ccc;
265 struct ConnectPairInfo *cpi = custom_cls;
266
267 if (NULL != ccc->nd)
268 ccc->nd (ccc->cls,
269 ccc->p[ipi->off],
270 peer);
271 GNUNET_free (cpi);
272}
273
274
275/**
276 * Wrapper around receiving data. Calls client's rec function.
277 *
278 * @param cls our `struct ConnectPairInfo *`
279 * @param message message we received
280 * @return #GNUNET_OK (all messages are fine)
281 */
282static int
283check_test (void *cls,
284 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
285{
286 return GNUNET_OK;
287}
288
289
290/**
291 * Wrapper around receiving data. Calls client's rec function.
292 *
293 * @param cls our `struct ConnectPairInfo *`
294 * @param message message we received
295 */
296static void
297handle_test (void *cls,
298 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
299{
300 struct ConnectPairInfo *cpi = cls;
301 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi = cpi->ipi;
302 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = ipi->ccc;
303
304 if (NULL != ccc->rec)
305 ccc->rec (ccc->cls,
306 ccc->p[ipi->off],
307 cpi->sender,
308 message);
309}
310
311
312/**
313 * Wrapper around receiving data. Calls client's rec function.
314 *
315 * @param cls our `struct ConnectPairInfo *`
316 * @param message message we received
317 * @return #GNUNET_OK (all messages are fine)
318 */
319static int
320check_test2 (void *cls,
321 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
322{
323 return GNUNET_OK;
324}
325
326
327/**
328 * Wrapper around receiving data. Calls client's rec function.
329 *
330 * @param cls our `struct ConnectPairInfo *`
331 * @param message message we received
332 */
333static void
334handle_test2 (void *cls,
335 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
336{
337 struct ConnectPairInfo *cpi = cls;
338 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi = cpi->ipi;
339 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = ipi->ccc;
340
341 if (NULL != ccc->rec)
342 ccc->rec (ccc->cls,
343 ccc->p[ipi->off],
344 cpi->sender,
345 message);
346}
347
348
349/**
350 * Connect the peers as a clique.
351 *
352 * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext`
353 */
354static void
355do_connect (void *cls)
356{
357 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = cls;
358
359 ccc->connect_task = NULL;
360 for (unsigned int i = 0; i < ccc->num_peers; i++)
361 for (unsigned int j = (ccc->bi_directional ? 0 : i + 1); j < ccc->num_peers;
362 j++)
363 {
364 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *crl;
365
366 if (i == j)
367 continue;
368 crl = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_ConnectRequestList);
369 GNUNET_CONTAINER_DLL_insert (ccc->crl_head,
370 ccc->crl_tail,
371 crl);
372 crl->ccc = ccc;
373 crl->p1 = ccc->p[i];
374 crl->p2 = ccc->p[j];
375 {
376 char *sender_c = GNUNET_strdup (GNUNET_i2s (&ccc->p[0]->id));
377
378 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
379 "Test tries to connect peer %u (`%s') -> peer %u (`%s')\n",
380 ccc->p[0]->no,
381 sender_c,
382 ccc->p[1]->no,
383 GNUNET_i2s (&ccc->p[1]->id));
384 GNUNET_free (sender_c);
385 }
386 crl->cr = GNUNET_TRANSPORT_TESTING_connect_peers (ccc->p[i],
387 ccc->p[j],
388 &connect_cb,
389 crl);
390 }
391}
392
393
394/**
395 * Function called once we have successfully launched a peer.
396 * Once all peers have been launched, we connect all of them
397 * in a clique.
398 *
399 * @param cls our `struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *`
400 */
401static void
402start_cb (void *cls)
403{
404 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi = cls;
405 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = ipi->ccc;
406 struct GNUNET_TRANSPORT_TESTING_PeerContext *p = ccc->p[ipi->off];
407
408 ccc->started++;
409 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
410 "Peer %u (`%s') started\n",
411 p->no,
412 GNUNET_i2s (&p->id));
413 if (ccc->started != ccc->num_peers)
414 return;
415 if (NULL != ccc->pre_connect_task)
416 {
417 /* Run the custom per-connect job, then give it a second to
418 go into effect before we continue connecting peers. */
419 ccc->pre_connect_task (ccc->pre_connect_task_cls);
420 ccc->connect_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
421 &do_connect,
422 ccc);
423 }
424 else
425 {
426 do_connect (ccc);
427 }
428}
429
430
431/**
432 * Function run from #GNUNET_TRANSPORT_TESTING_connect_check
433 * once the scheduler is up. Should launch the peers and
434 * then in the continuations try to connect them.
435 *
436 * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *`
437 * @param args ignored
438 * @param cfgfile ignored
439 * @param cfg configuration
440 */
441static void
442connect_check_run (void *cls,
443 char *const *args,
444 const char *cfgfile,
445 const struct GNUNET_CONFIGURATION_Handle *cfg)
446{
447 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = cls;
448 int ok;
449
450 ccc->cfg = cfg;
451 ccc->timeout_task = GNUNET_SCHEDULER_add_delayed (ccc->timeout,
452 &do_timeout,
453 ccc);
454 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
455 ccc);
456 ok = GNUNET_OK;
457 for (unsigned int i = 0; i < ccc->num_peers; i++)
458 {
459 struct GNUNET_MQ_MessageHandler handlers[] = {
460 GNUNET_MQ_hd_var_size (test,
461 GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE,
462 struct GNUNET_TRANSPORT_TESTING_TestMessage,
463 NULL),
464 GNUNET_MQ_hd_var_size (test2,
465 GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE2,
466 struct GNUNET_TRANSPORT_TESTING_TestMessage,
467 NULL),
468 GNUNET_MQ_handler_end ()
469 };
470 ccc->p[i] = GNUNET_TRANSPORT_TESTING_start_peer (ccc->tth,
471 ccc->cfg_files[i],
472 i + 1,
473 handlers,
474 &my_nc,
475 &my_nd,
476 &ccc->ip[i],
477 &start_cb,
478 &ccc->ip[i]);
479 if (NULL == ccc->p[i])
480 ok = GNUNET_SYSERR;
481 }
482 if (GNUNET_OK != ok)
483 {
484 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
485 "Fail! Could not start peers!\n");
486 GNUNET_SCHEDULER_shutdown ();
487 }
488}
489
490
491/**
492 * Common implementation of the #GNUNET_TRANSPORT_TESTING_CheckCallback.
493 * Starts and connects the two peers, then invokes the
494 * `connect_continuation` from @a cls. Sets up a timeout to
495 * abort the test, and a shutdown handler to clean up properly
496 * on exit.
497 *
498 * @param cls closure of type `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext`
499 * @param tth_ initialized testing handle
500 * @param test_plugin_ name of the plugin
501 * @param test_name_ name of the test
502 * @param num_peers number of entries in the @a cfg_file array
503 * @param cfg_files array of names of configuration files for the peers
504 * @return #GNUNET_SYSERR on error
505 */
506int
507GNUNET_TRANSPORT_TESTING_connect_check (void *cls,
508 struct GNUNET_TRANSPORT_TESTING_Handle *
509 tth_,
510 const char *test_plugin_,
511 const char *test_name_,
512 unsigned int num_peers,
513 char *cfg_files[])
514{
515 static struct GNUNET_GETOPT_CommandLineOption options[] = {
516 GNUNET_GETOPT_OPTION_END
517 };
518 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = cls;
519 struct GNUNET_TRANSPORT_TESTING_PeerContext *p[num_peers];
520 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext ip[num_peers];
521 char *argv[] = {
522 (char *) test_name_,
523 "-c",
524 (char *) ccc->config_file,
525 NULL
526 };
527
528 ccc->num_peers = num_peers;
529 ccc->cfg_files = cfg_files;
530 ccc->test_plugin = test_plugin_;
531 ccc->test_name = test_name_;
532 ccc->tth = tth_;
533 ccc->global_ret = GNUNET_OK;
534 ccc->p = p;
535 ccc->ip = ip;
536 for (unsigned int i = 0; i < num_peers; i++)
537 {
538 ip[i].off = i;
539 ip[i].ccc = ccc;
540 }
541 if (GNUNET_OK !=
542 GNUNET_PROGRAM_run ((sizeof(argv) / sizeof(char *)) - 1,
543 argv,
544 test_name_,
545 "nohelp",
546 options,
547 &connect_check_run,
548 ccc))
549 return GNUNET_SYSERR;
550 return ccc->global_ret;
551}
552
553
554/**
555 * Setup testcase. Calls @a check with the data the test needs.
556 *
557 * @param argv0 binary name (argv[0])
558 * @param filename source file name (__FILE__)
559 * @param num_peers number of peers to start
560 * @param check main function to run
561 * @param check_cls closure for @a check
562 * @return #GNUNET_OK on success
563 */
564int
565GNUNET_TRANSPORT_TESTING_main_ (const char *argv0,
566 const char *filename,
567 unsigned int num_peers,
568 GNUNET_TRANSPORT_TESTING_CheckCallback check,
569 void *check_cls)
570{
571 struct GNUNET_TRANSPORT_TESTING_Handle *tth;
572 char *test_name;
573 char *test_source;
574 char *test_plugin;
575 char *cfg_names[num_peers];
576 int ret;
577
578 ret = GNUNET_OK;
579 test_name = GNUNET_TRANSPORT_TESTING_get_test_name (argv0);
580 GNUNET_log_setup (test_name,
581 "WARNING",
582 NULL);
583 test_source = GNUNET_TRANSPORT_TESTING_get_test_source_name (filename);
584 test_plugin = GNUNET_TRANSPORT_TESTING_get_test_plugin_name (argv0,
585 test_source);
586 for (unsigned int i = 0; i < num_peers; i++)
587 cfg_names[i] = GNUNET_TRANSPORT_TESTING_get_config_name (argv0,
588 i + 1);
589 tth = GNUNET_TRANSPORT_TESTING_init ();
590 if (NULL == tth)
591 {
592 ret = GNUNET_SYSERR;
593 }
594 else
595 {
596 ret = check (check_cls,
597 tth,
598 test_plugin,
599 test_name,
600 num_peers,
601 cfg_names);
602 GNUNET_TRANSPORT_TESTING_done (tth);
603 }
604 for (unsigned int i = 0; i < num_peers; i++)
605 GNUNET_free (cfg_names[i]);
606 GNUNET_free (test_source);
607 GNUNET_free (test_plugin);
608 GNUNET_free (test_name);
609 return ret;
610}
611
612
613/* 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 38018c172..000000000
--- a/src/transport/transport-testing-send.c
+++ /dev/null
@@ -1,240 +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 "transport-testing.h"
26
27/**
28 * Acceptable transmission delay.
29 */
30#define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply ( \
31 GNUNET_TIME_UNIT_SECONDS, 30)
32
33
34/**
35 * Return @a cx in @a cls.
36 */
37static void
38find_cr (void *cls,
39 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
40{
41 struct GNUNET_TRANSPORT_TESTING_ConnectRequest **cr = cls;
42
43 if (GNUNET_NO == cx->connected)
44 return;
45 *cr = cx;
46}
47
48
49/**
50 * Send a test message of type @a mtype and size @a msize from
51 * peer @a sender to peer @a receiver. The peers should be
52 * connected when this function is called.
53 *
54 * @param sender the sending peer
55 * @param receiver the receiving peer
56 * @param mtype message type to use
57 * @param msize size of the message, at least `sizeof (struct GNUNET_TRANSPORT_TESTING_TestMessage)`
58 * @param num unique message number
59 * @param cont continuation to call after transmission
60 * @param cont_cls closure for @a cont
61 * @return #GNUNET_OK if message was queued,
62 * #GNUNET_NO if peers are not connected
63 * #GNUNET_SYSERR if @a msize is illegal
64 */
65int
66GNUNET_TRANSPORT_TESTING_send (struct
67 GNUNET_TRANSPORT_TESTING_PeerContext *sender,
68 struct GNUNET_TRANSPORT_TESTING_PeerContext *
69 receiver,
70 uint16_t mtype,
71 uint16_t msize,
72 uint32_t num,
73 GNUNET_SCHEDULER_TaskCallback cont,
74 void *cont_cls)
75{
76 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cr;
77 struct GNUNET_MQ_Envelope *env;
78 struct GNUNET_TRANSPORT_TESTING_TestMessage *test;
79
80 if (msize < sizeof(struct GNUNET_TRANSPORT_TESTING_TestMessage))
81 {
82 GNUNET_break (0);
83 return GNUNET_SYSERR;
84 }
85 cr = NULL;
86 GNUNET_TRANSPORT_TESTING_find_connecting_context (sender,
87 receiver,
88 &find_cr,
89 &cr);
90 if (NULL == cr)
91 GNUNET_TRANSPORT_TESTING_find_connecting_context (receiver,
92 sender,
93 &find_cr,
94 &cr);
95 if (NULL == cr)
96 {
97 GNUNET_break (0);
98 return GNUNET_NO;
99 }
100 if (NULL == cr->mq)
101 {
102 GNUNET_break (0);
103 return GNUNET_NO;
104 }
105 {
106 char *receiver_s = GNUNET_strdup (GNUNET_i2s (&receiver->id));
107
108 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
109 "Sending message from peer %u (`%s') -> peer %u (`%s') !\n",
110 sender->no,
111 GNUNET_i2s (&sender->id),
112 receiver->no,
113 receiver_s);
114 GNUNET_free (receiver_s);
115 }
116 env = GNUNET_MQ_msg_extra (test,
117 msize - sizeof(*test),
118 mtype);
119 test->num = htonl (num);
120 memset (&test[1],
121 num,
122 msize - sizeof(*test));
123 GNUNET_MQ_notify_sent (env,
124 cont,
125 cont_cls);
126 GNUNET_MQ_send (cr->mq,
127 env);
128 return GNUNET_OK;
129}
130
131
132/**
133 * Task that sends a test message from the
134 * first peer to the second peer.
135 *
136 * @param ccc context which should contain at least two peers, the
137 * first two of which should be currently connected
138 * @param size desired message size
139 * @param cont continuation to call after transmission
140 * @param cont_cls closure for @a cont
141 */
142static void
143do_send (struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc,
144 uint16_t size,
145 GNUNET_SCHEDULER_TaskCallback cont,
146 void *cont_cls)
147{
148 int ret;
149
150 ccc->global_ret = GNUNET_SYSERR;
151 ret = GNUNET_TRANSPORT_TESTING_send (ccc->p[0],
152 ccc->p[1],
153 GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE,
154 size,
155 ccc->send_num_gen++,
156 cont,
157 cont_cls);
158 GNUNET_assert (GNUNET_SYSERR != ret);
159 if (GNUNET_NO == ret)
160 {
161 GNUNET_break (0);
162 ccc->global_ret = GNUNET_SYSERR;
163 GNUNET_SCHEDULER_shutdown ();
164 }
165}
166
167
168/**
169 * Task that sends a minimalistic test message from the
170 * first peer to the second peer.
171 *
172 * @param cls the `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext`
173 * which should contain at least two peers, the first two
174 * of which should be currently connected
175 */
176void
177GNUNET_TRANSPORT_TESTING_simple_send (void *cls)
178{
179 struct GNUNET_TRANSPORT_TESTING_SendClosure *sc = cls;
180 int done;
181 size_t msize;
182
183 if (0 < sc->num_messages)
184 {
185 sc->num_messages--;
186 done = (0 == sc->num_messages);
187 }
188 else
189 {
190 done = 0; /* infinite loop */
191 }
192 msize = sizeof(struct GNUNET_TRANSPORT_TESTING_TestMessage);
193 if (NULL != sc->get_size_cb)
194 msize = sc->get_size_cb (sc->num_messages);
195 /* if this was the last message, call the continuation,
196 otherwise call this function again */
197 do_send (sc->ccc,
198 msize,
199 done ? sc->cont : &GNUNET_TRANSPORT_TESTING_simple_send,
200 done ? sc->cont_cls : sc);
201}
202
203
204/**
205 * Task that sends a large test message from the
206 * first peer to the second peer.
207 *
208 * @param cls the `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext`
209 * which should contain at least two peers, the first two
210 * of which should be currently connected
211 */
212void
213GNUNET_TRANSPORT_TESTING_large_send (void *cls)
214{
215 struct GNUNET_TRANSPORT_TESTING_SendClosure *sc = cls;
216 int done;
217 size_t msize;
218
219 if (0 < sc->num_messages)
220 {
221 sc->num_messages--;
222 done = (0 == sc->num_messages);
223 }
224 else
225 {
226 done = 0; /* infinite loop */
227 }
228 msize = 2600;
229 if (NULL != sc->get_size_cb)
230 msize = sc->get_size_cb (sc->num_messages);
231 /* if this was the last message, call the continuation,
232 otherwise call this function again */
233 do_send (sc->ccc,
234 msize,
235 done ? sc->cont : &GNUNET_TRANSPORT_TESTING_large_send,
236 done ? sc->cont_cls : sc);
237}
238
239
240/* end of transport-testing-send.c */
diff --git a/src/transport/transport-testing-send2.c b/src/transport/transport-testing-send2.c
deleted file mode 100644
index bd2afb9b0..000000000
--- a/src/transport/transport-testing-send2.c
+++ /dev/null
@@ -1,240 +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 "transport-testing2.h"
26
27/**
28 * Acceptable transmission delay.
29 */
30#define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply ( \
31 GNUNET_TIME_UNIT_SECONDS, 30)
32
33
34/**
35 * Return @a cx in @a cls.
36 */
37static void
38find_cr (void *cls,
39 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
40{
41 struct GNUNET_TRANSPORT_TESTING_ConnectRequest **cr = cls;
42
43 if (GNUNET_NO == cx->connected)
44 return;
45 *cr = cx;
46}
47
48
49/**
50 * Send a test message of type @a mtype and size @a msize from
51 * peer @a sender to peer @a receiver. The peers should be
52 * connected when this function is called.
53 *
54 * @param sender the sending peer
55 * @param receiver the receiving peer
56 * @param mtype message type to use
57 * @param msize size of the message, at least `sizeof (struct GNUNET_TRANSPORT_TESTING_TestMessage)`
58 * @param num unique message number
59 * @param cont continuation to call after transmission
60 * @param cont_cls closure for @a cont
61 * @return #GNUNET_OK if message was queued,
62 * #GNUNET_NO if peers are not connected
63 * #GNUNET_SYSERR if @a msize is illegal
64 */
65int
66GNUNET_TRANSPORT_TESTING_send (struct
67 GNUNET_TRANSPORT_TESTING_PeerContext *sender,
68 struct GNUNET_TRANSPORT_TESTING_PeerContext *
69 receiver,
70 uint16_t mtype,
71 uint16_t msize,
72 uint32_t num,
73 GNUNET_SCHEDULER_TaskCallback cont,
74 void *cont_cls)
75{
76 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cr;
77 struct GNUNET_MQ_Envelope *env;
78 struct GNUNET_TRANSPORT_TESTING_TestMessage *test;
79
80 if (msize < sizeof(struct GNUNET_TRANSPORT_TESTING_TestMessage))
81 {
82 GNUNET_break (0);
83 return GNUNET_SYSERR;
84 }
85 cr = NULL;
86 GNUNET_TRANSPORT_TESTING_find_connecting_context (sender,
87 receiver,
88 &find_cr,
89 &cr);
90 if (NULL == cr)
91 GNUNET_TRANSPORT_TESTING_find_connecting_context (receiver,
92 sender,
93 &find_cr,
94 &cr);
95 if (NULL == cr)
96 {
97 GNUNET_break (0);
98 return GNUNET_NO;
99 }
100 if (NULL == cr->mq)
101 {
102 GNUNET_break (0);
103 return GNUNET_NO;
104 }
105 {
106 char *receiver_s = GNUNET_strdup (GNUNET_i2s (&receiver->id));
107
108 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
109 "Sending message from peer %u (`%s') -> peer %u (`%s') !\n",
110 sender->no,
111 GNUNET_i2s (&sender->id),
112 receiver->no,
113 receiver_s);
114 GNUNET_free (receiver_s);
115 }
116 env = GNUNET_MQ_msg_extra (test,
117 msize - sizeof(*test),
118 mtype);
119 test->num = htonl (num);
120 memset (&test[1],
121 num,
122 msize - sizeof(*test));
123 GNUNET_MQ_notify_sent (env,
124 cont,
125 cont_cls);
126 GNUNET_MQ_send (cr->mq,
127 env);
128 return GNUNET_OK;
129}
130
131
132/**
133 * Task that sends a test message from the
134 * first peer to the second peer.
135 *
136 * @param ccc context which should contain at least two peers, the
137 * first two of which should be currently connected
138 * @param size desired message size
139 * @param cont continuation to call after transmission
140 * @param cont_cls closure for @a cont
141 */
142static void
143do_send (struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc,
144 uint16_t size,
145 GNUNET_SCHEDULER_TaskCallback cont,
146 void *cont_cls)
147{
148 int ret;
149
150 ccc->global_ret = GNUNET_SYSERR;
151 ret = GNUNET_TRANSPORT_TESTING_send (ccc->p[0],
152 ccc->p[1],
153 GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE,
154 size,
155 ccc->send_num_gen++,
156 cont,
157 cont_cls);
158 GNUNET_assert (GNUNET_SYSERR != ret);
159 if (GNUNET_NO == ret)
160 {
161 GNUNET_break (0);
162 ccc->global_ret = GNUNET_SYSERR;
163 GNUNET_SCHEDULER_shutdown ();
164 }
165}
166
167
168/**
169 * Task that sends a minimalistic test message from the
170 * first peer to the second peer.
171 *
172 * @param cls the `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext`
173 * which should contain at least two peers, the first two
174 * of which should be currently connected
175 */
176void
177GNUNET_TRANSPORT_TESTING_simple_send (void *cls)
178{
179 struct GNUNET_TRANSPORT_TESTING_SendClosure *sc = cls;
180 int done;
181 size_t msize;
182
183 if (0 < sc->num_messages)
184 {
185 sc->num_messages--;
186 done = (0 == sc->num_messages);
187 }
188 else
189 {
190 done = 0; /* infinite loop */
191 }
192 msize = sizeof(struct GNUNET_TRANSPORT_TESTING_TestMessage);
193 if (NULL != sc->get_size_cb)
194 msize = sc->get_size_cb (sc->num_messages);
195 /* if this was the last message, call the continuation,
196 otherwise call this function again */
197 do_send (sc->ccc,
198 msize,
199 done ? sc->cont : &GNUNET_TRANSPORT_TESTING_simple_send,
200 done ? sc->cont_cls : sc);
201}
202
203
204/**
205 * Task that sends a large test message from the
206 * first peer to the second peer.
207 *
208 * @param cls the `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext`
209 * which should contain at least two peers, the first two
210 * of which should be currently connected
211 */
212void
213GNUNET_TRANSPORT_TESTING_large_send (void *cls)
214{
215 struct GNUNET_TRANSPORT_TESTING_SendClosure *sc = cls;
216 int done;
217 size_t msize;
218
219 if (0 < sc->num_messages)
220 {
221 sc->num_messages--;
222 done = (0 == sc->num_messages);
223 }
224 else
225 {
226 done = 0; /* infinite loop */
227 }
228 msize = 2600;
229 if (NULL != sc->get_size_cb)
230 msize = sc->get_size_cb (sc->num_messages);
231 /* if this was the last message, call the continuation,
232 otherwise call this function again */
233 do_send (sc->ccc,
234 msize,
235 done ? sc->cont : &GNUNET_TRANSPORT_TESTING_large_send,
236 done ? sc->cont_cls : sc);
237}
238
239
240/* 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 00c4a08dd..000000000
--- a/src/transport/transport-testing.c
+++ /dev/null
@@ -1,931 +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 "transport-testing.h"
27
28
29#define LOG(kind, ...) GNUNET_log_from (kind, "transport-testing", __VA_ARGS__)
30
31
32static struct GNUNET_TRANSPORT_TESTING_PeerContext *
33find_peer_context (struct GNUNET_TRANSPORT_TESTING_Handle *tth,
34 const struct GNUNET_PeerIdentity *peer)
35{
36 struct GNUNET_TRANSPORT_TESTING_PeerContext *t;
37
38 for (t = tth->p_head; NULL != t; t = t->next)
39 if (0 == memcmp (&t->id,
40 peer,
41 sizeof(struct GNUNET_PeerIdentity)))
42 return t;
43 return NULL;
44}
45
46
47/**
48 * Find any connecting context matching the given pair of peers.
49 *
50 * @param p1 first peer
51 * @param p2 second peer
52 * @param cb function to call
53 * @param cb_cls closure for @a cb
54 */
55void
56GNUNET_TRANSPORT_TESTING_find_connecting_context (struct
57 GNUNET_TRANSPORT_TESTING_PeerContext
58 *p1,
59 struct
60 GNUNET_TRANSPORT_TESTING_PeerContext
61 *p2,
62 GNUNET_TRANSPORT_TESTING_ConnectContextCallback
63 cb,
64 void *cb_cls)
65{
66 struct GNUNET_TRANSPORT_TESTING_Handle *tth = p1->tth;
67 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
68 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ccn;
69
70 for (cc = tth->cc_head; NULL != cc; cc = ccn)
71 {
72 ccn = cc->next;
73 if ((cc->p1 == p1) &&
74 (cc->p2 == p2))
75 cb (cb_cls,
76 cc);
77 }
78}
79
80
81static void
82set_p1c (void *cls,
83 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
84{
85 int *found = cls;
86
87 if (NULL != found)
88 *found = GNUNET_YES;
89 cx->p1_c = GNUNET_YES;
90}
91
92
93static void
94set_mq (void *cls,
95 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
96{
97 struct GNUNET_MQ_Handle *mq = cls;
98
99 cx->mq = mq;
100}
101
102
103static void
104set_p2c (void *cls,
105 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
106{
107 int *found = cls;
108
109 if (NULL != found)
110 *found = GNUNET_YES;
111 cx->p2_c = GNUNET_YES;
112}
113
114
115static void
116clear_p1c (void *cls,
117 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
118{
119 int *found = cls;
120
121 if (NULL != found)
122 *found = GNUNET_YES;
123 cx->p1_c = GNUNET_NO;
124}
125
126
127static void
128clear_p2c (void *cls,
129 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
130{
131 int *found = cls;
132
133 if (NULL != found)
134 *found = GNUNET_YES;
135 cx->p2_c = GNUNET_NO;
136}
137
138
139static void *
140notify_connect (void *cls,
141 const struct GNUNET_PeerIdentity *peer,
142 struct GNUNET_MQ_Handle *mq)
143{
144 struct GNUNET_TRANSPORT_TESTING_PeerContext *p = cls;
145 struct GNUNET_TRANSPORT_TESTING_Handle *tth = p->tth;
146 char *p2_s;
147 struct GNUNET_TRANSPORT_TESTING_PeerContext *p2;
148 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
149 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ccn;
150 int found;
151 void *ret;
152
153 p2 = find_peer_context (p->tth,
154 peer);
155 if (NULL != p->nc)
156 ret = p->nc (p->cb_cls,
157 peer,
158 mq);
159 else
160 ret = NULL;
161
162 if (NULL != p2)
163 GNUNET_asprintf (&p2_s,
164 "%u (`%s')",
165 p2->no,
166 GNUNET_i2s (&p2->id));
167 else
168 GNUNET_asprintf (&p2_s,
169 "`%s'",
170 GNUNET_i2s (peer));
171 LOG (GNUNET_ERROR_TYPE_DEBUG,
172 "Peers %s connected to peer %u (`%s')\n",
173 p2_s,
174 p->no,
175 GNUNET_i2s (&p->id));
176 GNUNET_free (p2_s);
177 /* update flags in connecting contexts */
178 found = GNUNET_NO;
179 GNUNET_TRANSPORT_TESTING_find_connecting_context (p,
180 p2,
181 &set_p1c,
182 &found);
183 if (GNUNET_NO == found)
184 {
185 cc = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_ConnectRequest);
186 cc->p1 = p;
187 cc->p2 = p2;
188 cc->p1_c = GNUNET_YES;
189 GNUNET_CONTAINER_DLL_insert (tth->cc_head,
190 tth->cc_tail,
191 cc);
192 }
193 found = GNUNET_NO;
194 GNUNET_TRANSPORT_TESTING_find_connecting_context (p2,
195 p,
196 &set_p2c,
197 &found);
198 if (GNUNET_NO == found)
199 {
200 cc = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_ConnectRequest);
201 cc->p1 = p2;
202 cc->p2 = p;
203 cc->p1_c = GNUNET_YES;
204 GNUNET_CONTAINER_DLL_insert (tth->cc_head,
205 tth->cc_tail,
206 cc);
207 }
208 GNUNET_TRANSPORT_TESTING_find_connecting_context (p,
209 p2,
210 &set_mq,
211 mq);
212 /* update set connected flag for all requests */
213 for (cc = tth->cc_head; NULL != cc; cc = cc->next)
214 {
215 if (GNUNET_YES == cc->connected)
216 continue;
217 if ((GNUNET_YES == cc->p1_c) &&
218 (GNUNET_YES == cc->p2_c))
219 {
220 cc->connected = GNUNET_YES;
221 /* stop trying to connect */
222 if (NULL != cc->tct)
223 {
224 GNUNET_SCHEDULER_cancel (cc->tct);
225 cc->tct = NULL;
226 }
227 if (NULL != cc->oh)
228 {
229 GNUNET_TRANSPORT_offer_hello_cancel (cc->oh);
230 cc->oh = NULL;
231 }
232 if (NULL != cc->ats_sh)
233 {
234 GNUNET_ATS_connectivity_suggest_cancel (cc->ats_sh);
235 cc->ats_sh = NULL;
236 }
237 }
238 }
239 /* then notify application */
240 for (cc = tth->cc_head; NULL != cc; cc = ccn)
241 {
242 ccn = cc->next;
243 if ((GNUNET_YES == cc->connected) &&
244 (NULL != cc->cb))
245 {
246 cc->cb (cc->cb_cls);
247 cc->cb = NULL; /* only notify once! */
248 }
249 }
250 return ret;
251}
252
253
254/**
255 * Offer the current HELLO of P2 to P1.
256 *
257 * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectRequest`
258 */
259static void
260offer_hello (void *cls);
261
262
263static void
264notify_disconnect (void *cls,
265 const struct GNUNET_PeerIdentity *peer,
266 void *handler_cls)
267{
268 struct GNUNET_TRANSPORT_TESTING_PeerContext *p = cls;
269 struct GNUNET_TRANSPORT_TESTING_Handle *tth = p->tth;
270 char *p2_s;
271 /* Find PeerContext */
272 int no = 0;
273 struct GNUNET_TRANSPORT_TESTING_PeerContext *p2 = NULL;
274 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
275
276 p2 = find_peer_context (p->tth,
277 peer);
278 no = p->no;
279 if (NULL != p2)
280 GNUNET_asprintf (&p2_s,
281 "%u (`%s')",
282 p2->no,
283 GNUNET_i2s (&p2->id));
284 else
285 GNUNET_asprintf (&p2_s,
286 "`%s'",
287 GNUNET_i2s (peer));
288 LOG (GNUNET_ERROR_TYPE_DEBUG,
289 "Peers %s disconnected from peer %u (`%s')\n",
290 p2_s,
291 no,
292 GNUNET_i2s (&p->id));
293 GNUNET_free (p2_s);
294 /* notify about disconnect */
295 if (NULL != p->nd)
296 p->nd (p->cb_cls,
297 peer,
298 handler_cls);
299 if (NULL == p2)
300 return;
301 /* clear MQ, it is now invalid */
302 GNUNET_TRANSPORT_TESTING_find_connecting_context (p,
303 p2,
304 &set_mq,
305 NULL);
306 /* update set connected flags for all requests */
307 GNUNET_TRANSPORT_TESTING_find_connecting_context (p,
308 p2,
309 &clear_p1c,
310 NULL);
311 GNUNET_TRANSPORT_TESTING_find_connecting_context (p2,
312 p,
313 &clear_p2c,
314 NULL);
315 /* resume connectivity requests as necessary */
316 for (cc = tth->cc_head; NULL != cc; cc = cc->next)
317 {
318 if (GNUNET_NO == cc->connected)
319 continue;
320 if ((GNUNET_YES != cc->p1_c) ||
321 (GNUNET_YES != cc->p2_c))
322 {
323 cc->connected = GNUNET_NO;
324 /* start trying to connect */
325 if ((NULL == cc->tct) &&
326 (NULL == cc->oh))
327 cc->tct = GNUNET_SCHEDULER_add_now (&offer_hello,
328 cc);
329 if (NULL == cc->ats_sh)
330 cc->ats_sh = GNUNET_ATS_connectivity_suggest (cc->p1->ats,
331 &p2->id,
332 1);
333 }
334 }
335}
336
337
338static void
339get_hello (void *cb_cls,
340 const struct GNUNET_MessageHeader *message)
341{
342 struct GNUNET_TRANSPORT_TESTING_PeerContext *p = cb_cls;
343 struct GNUNET_PeerIdentity hello_id;
344
345 GNUNET_assert (GNUNET_OK ==
346 GNUNET_HELLO_get_id ((const struct
347 GNUNET_HELLO_Message *) message,
348 &hello_id));
349 GNUNET_assert (0 == memcmp (&hello_id,
350 &p->id,
351 sizeof(hello_id)));
352 GNUNET_free (p->hello);
353 p->hello = (struct GNUNET_HELLO_Message *) GNUNET_copy_message (message);
354
355 if (NULL != p->start_cb)
356 {
357 LOG (GNUNET_ERROR_TYPE_DEBUG,
358 "Peer %u (`%s') successfully started\n",
359 p->no,
360 GNUNET_i2s (&p->id));
361 p->start_cb (p->start_cb_cls);
362 p->start_cb = NULL;
363 }
364}
365
366
367/**
368 * Start a peer with the given configuration
369 * @param tth the testing handle
370 * @param cfgname configuration file
371 * @param peer_id a unique number to identify the peer
372 * @param handlers functions for receiving messages
373 * @param nc connect callback
374 * @param nd disconnect callback
375 * @param cb_cls closure for callback
376 * @param start_cb start callback
377 * @param start_cb_cls closure for callback
378 * @return the peer context
379 */
380struct GNUNET_TRANSPORT_TESTING_PeerContext *
381GNUNET_TRANSPORT_TESTING_start_peer (struct
382 GNUNET_TRANSPORT_TESTING_Handle *tth,
383 const char *cfgname,
384 int peer_id,
385 const struct
386 GNUNET_MQ_MessageHandler *handlers,
387 GNUNET_TRANSPORT_NotifyConnect nc,
388 GNUNET_TRANSPORT_NotifyDisconnect nd,
389 void *cb_cls,
390 GNUNET_SCHEDULER_TaskCallback start_cb,
391 void *start_cb_cls)
392{
393 char *emsg = NULL;
394 struct GNUNET_TRANSPORT_TESTING_PeerContext *p;
395 struct GNUNET_PeerIdentity dummy;
396 unsigned int i;
397
398 if (GNUNET_NO == GNUNET_DISK_file_test (cfgname))
399 {
400 LOG (GNUNET_ERROR_TYPE_ERROR,
401 "File not found: `%s'\n",
402 cfgname);
403 return NULL;
404 }
405
406 p = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_PeerContext);
407 p->tth = tth;
408 p->nc = nc;
409 p->nd = nd;
410 if (NULL != handlers)
411 {
412 for (i = 0; NULL != handlers[i].cb; i++)
413 ;
414 p->handlers = GNUNET_new_array (i + 1,
415 struct GNUNET_MQ_MessageHandler);
416 GNUNET_memcpy (p->handlers,
417 handlers,
418 i * sizeof(struct GNUNET_MQ_MessageHandler));
419 }
420 if (NULL != cb_cls)
421 p->cb_cls = cb_cls;
422 else
423 p->cb_cls = p;
424 p->start_cb = start_cb;
425 if (NULL != start_cb_cls)
426 p->start_cb_cls = start_cb_cls;
427 else
428 p->start_cb_cls = p;
429 GNUNET_CONTAINER_DLL_insert (tth->p_head,
430 tth->p_tail,
431 p);
432
433 /* Create configuration and call testing lib to modify it */
434 p->cfg = GNUNET_CONFIGURATION_create ();
435 GNUNET_assert (GNUNET_OK ==
436 GNUNET_CONFIGURATION_load (p->cfg, cfgname));
437 if (GNUNET_SYSERR ==
438 GNUNET_TESTING_configuration_create (tth->tl_system,
439 p->cfg))
440 {
441 LOG (GNUNET_ERROR_TYPE_ERROR,
442 "Testing library failed to create unique configuration based on `%s'\n",
443 cfgname);
444 GNUNET_CONFIGURATION_destroy (p->cfg);
445 GNUNET_free (p);
446 return NULL;
447 }
448
449 p->no = peer_id;
450 /* Configure peer with configuration */
451 p->peer = GNUNET_TESTING_peer_configure (tth->tl_system,
452 p->cfg,
453 p->no,
454 NULL,
455 &emsg);
456 if (NULL == p->peer)
457 {
458 LOG (GNUNET_ERROR_TYPE_ERROR,
459 "Testing library failed to create unique configuration based on `%s': `%s'\n",
460 cfgname,
461 emsg);
462 GNUNET_TRANSPORT_TESTING_stop_peer (p);
463 GNUNET_free (emsg);
464 return NULL;
465 }
466
467 if (GNUNET_OK != GNUNET_TESTING_peer_start (p->peer))
468 {
469 LOG (GNUNET_ERROR_TYPE_ERROR,
470 "Testing library failed to create unique configuration based on `%s'\n",
471 cfgname);
472 GNUNET_TRANSPORT_TESTING_stop_peer (p);
473 return NULL;
474 }
475
476 memset (&dummy,
477 '\0',
478 sizeof(dummy));
479 GNUNET_TESTING_peer_get_identity (p->peer,
480 &p->id);
481 if (0 == memcmp (&dummy,
482 &p->id,
483 sizeof(struct GNUNET_PeerIdentity)))
484 {
485 LOG (GNUNET_ERROR_TYPE_ERROR,
486 "Testing library failed to obtain peer identity for peer %u\n",
487 p->no);
488 GNUNET_TRANSPORT_TESTING_stop_peer (p);
489 return NULL;
490 }
491 LOG (GNUNET_ERROR_TYPE_DEBUG,
492 "Peer %u configured with identity `%s'\n",
493 p->no,
494 GNUNET_i2s_full (&p->id));
495 p->tmh = GNUNET_TRANSPORT_manipulation_connect (p->cfg);
496 p->th = GNUNET_TRANSPORT_core_connect (p->cfg,
497 NULL,
498 handlers,
499 p,
500 &notify_connect,
501 &notify_disconnect,
502 NULL);
503 if ((NULL == p->th) ||
504 (NULL == p->tmh))
505 {
506 LOG (GNUNET_ERROR_TYPE_ERROR,
507 "Failed to connect to transport service for peer `%s': `%s'\n",
508 cfgname,
509 emsg);
510 GNUNET_TRANSPORT_TESTING_stop_peer (p);
511 GNUNET_free (emsg);
512 return NULL;
513 }
514 p->ats = GNUNET_ATS_connectivity_init (p->cfg);
515 if (NULL == p->ats)
516 {
517 LOG (GNUNET_ERROR_TYPE_ERROR,
518 "Failed to connect to ATS service for peer `%s': `%s'\n",
519 cfgname,
520 emsg);
521 GNUNET_TRANSPORT_TESTING_stop_peer (p);
522 GNUNET_free (emsg);
523 return NULL;
524 }
525 p->ghh = GNUNET_TRANSPORT_hello_get (p->cfg,
526 GNUNET_TRANSPORT_AC_ANY,
527 &get_hello,
528 p);
529 GNUNET_assert (NULL != p->ghh);
530 return p;
531}
532
533
534/**
535 * Stops and restarts the given peer, sleeping (!) for 5s in between.
536 *
537 * @param p the peer
538 * @param restart_cb callback to call when restarted
539 * @param restart_cb_cls callback closure
540 * @return #GNUNET_OK in success otherwise #GNUNET_SYSERR
541 */
542int
543GNUNET_TRANSPORT_TESTING_restart_peer (struct
544 GNUNET_TRANSPORT_TESTING_PeerContext *p,
545 GNUNET_SCHEDULER_TaskCallback restart_cb,
546 void *restart_cb_cls)
547{
548 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
549 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ccn;
550
551 /* shutdown */
552 LOG (GNUNET_ERROR_TYPE_DEBUG,
553 "Stopping peer %u (`%s')\n",
554 p->no,
555 GNUNET_i2s (&p->id));
556 if (NULL != p->ghh)
557 {
558 GNUNET_TRANSPORT_hello_get_cancel (p->ghh);
559 p->ghh = NULL;
560 }
561 if (NULL != p->th)
562 {
563 GNUNET_TRANSPORT_core_disconnect (p->th);
564 p->th = NULL;
565 }
566 if (NULL != p->tmh)
567 {
568 GNUNET_TRANSPORT_manipulation_disconnect (p->tmh);
569 p->tmh = NULL;
570 }
571 for (cc = p->tth->cc_head; NULL != cc; cc = ccn)
572 {
573 ccn = cc->next;
574 if ((cc->p1 == p) ||
575 (cc->p2 == p))
576 GNUNET_TRANSPORT_TESTING_connect_peers_cancel (cc);
577 }
578 if (NULL != p->ats)
579 {
580 GNUNET_ATS_connectivity_done (p->ats);
581 p->ats = NULL;
582 }
583 if (GNUNET_SYSERR ==
584 GNUNET_TESTING_peer_stop (p->peer))
585 {
586 LOG (GNUNET_ERROR_TYPE_ERROR,
587 "Failed to stop peer %u (`%s')\n",
588 p->no,
589 GNUNET_i2s (&p->id));
590 return GNUNET_SYSERR;
591 }
592
593 sleep (5); // YUCK!
594
595 LOG (GNUNET_ERROR_TYPE_DEBUG,
596 "Restarting peer %u (`%s')\n",
597 p->no,
598 GNUNET_i2s (&p->id));
599 /* restart */
600 if (GNUNET_SYSERR == GNUNET_TESTING_peer_start (p->peer))
601 {
602 LOG (GNUNET_ERROR_TYPE_ERROR,
603 "Failed to restart peer %u (`%s')\n",
604 p->no,
605 GNUNET_i2s (&p->id));
606 return GNUNET_SYSERR;
607 }
608
609 GNUNET_assert (NULL == p->start_cb);
610 p->start_cb = restart_cb;
611 p->start_cb_cls = restart_cb_cls;
612
613 p->th = GNUNET_TRANSPORT_core_connect (p->cfg,
614 NULL,
615 p->handlers,
616 p,
617 &notify_connect,
618 &notify_disconnect,
619 NULL);
620 GNUNET_assert (NULL != p->th);
621 p->ats = GNUNET_ATS_connectivity_init (p->cfg);
622 p->ghh = GNUNET_TRANSPORT_hello_get (p->cfg,
623 GNUNET_TRANSPORT_AC_ANY,
624 &get_hello,
625 p);
626 GNUNET_assert (NULL != p->ghh);
627 return GNUNET_OK;
628}
629
630
631/**
632 * Shutdown the given peer
633 *
634 * @param p the peer
635 */
636void
637GNUNET_TRANSPORT_TESTING_stop_peer (struct
638 GNUNET_TRANSPORT_TESTING_PeerContext *p)
639{
640 struct GNUNET_TRANSPORT_TESTING_Handle *tth = p->tth;
641 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
642 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ccn;
643
644 for (cc = tth->cc_head; NULL != cc; cc = ccn)
645 {
646 ccn = cc->next;
647 if ((cc->p1 == p) ||
648 (cc->p2 == p))
649 GNUNET_TRANSPORT_TESTING_connect_peers_cancel (cc);
650 }
651 if (NULL != p->ghh)
652 {
653 GNUNET_TRANSPORT_hello_get_cancel (p->ghh);
654 p->ghh = NULL;
655 }
656 if (NULL != p->tmh)
657 {
658 GNUNET_TRANSPORT_manipulation_disconnect (p->tmh);
659 p->tmh = NULL;
660 }
661 if (NULL != p->th)
662 {
663 GNUNET_TRANSPORT_core_disconnect (p->th);
664 p->th = NULL;
665 }
666 if (NULL != p->peer)
667 {
668 if (GNUNET_OK !=
669 GNUNET_TESTING_peer_stop (p->peer))
670 {
671 LOG (GNUNET_ERROR_TYPE_DEBUG,
672 "Testing lib failed to stop peer %u (`%s')\n",
673 p->no,
674 GNUNET_i2s (&p->id));
675 }
676 GNUNET_TESTING_peer_destroy (p->peer);
677 p->peer = NULL;
678 }
679 if (NULL != p->ats)
680 {
681 GNUNET_ATS_connectivity_done (p->ats);
682 p->ats = NULL;
683 }
684 if (NULL != p->hello)
685 {
686 GNUNET_free (p->hello);
687 p->hello = NULL;
688 }
689 if (NULL != p->cfg)
690 {
691 GNUNET_CONFIGURATION_destroy (p->cfg);
692 p->cfg = NULL;
693 }
694 if (NULL != p->handlers)
695 {
696 GNUNET_free (p->handlers);
697 p->handlers = NULL;
698 }
699 GNUNET_CONTAINER_DLL_remove (tth->p_head,
700 tth->p_tail,
701 p);
702 LOG (GNUNET_ERROR_TYPE_DEBUG,
703 "Peer %u (`%s') stopped\n",
704 p->no,
705 GNUNET_i2s (&p->id));
706 GNUNET_free (p);
707}
708
709
710/**
711 * Function called after the HELLO was passed to the
712 * transport service.
713 */
714static void
715hello_offered (void *cls)
716{
717 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc = cls;
718
719 cc->oh = NULL;
720 cc->tct = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
721 &offer_hello,
722 cc);
723}
724
725
726/**
727 * Offer the current HELLO of P2 to P1.
728 *
729 * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectRequest`
730 */
731static void
732offer_hello (void *cls)
733{
734 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc = cls;
735 struct GNUNET_TRANSPORT_TESTING_PeerContext *p1 = cc->p1;
736 struct GNUNET_TRANSPORT_TESTING_PeerContext *p2 = cc->p2;
737
738 cc->tct = NULL;
739 {
740 char *p2_s = GNUNET_strdup (GNUNET_i2s (&p2->id));
741
742 LOG (GNUNET_ERROR_TYPE_DEBUG,
743 "Asking peer %u (`%s') to connect peer %u (`%s'), providing HELLO with %u bytes\n",
744 p1->no,
745 GNUNET_i2s (&p1->id),
746 p2->no,
747 p2_s,
748 GNUNET_HELLO_size (cc->p2->hello));
749 GNUNET_free (p2_s);
750 }
751
752 if (NULL != cc->oh)
753 GNUNET_TRANSPORT_offer_hello_cancel (cc->oh);
754 cc->oh =
755 GNUNET_TRANSPORT_offer_hello (cc->p1->cfg,
756 (const struct
757 GNUNET_MessageHeader *) cc->p2->hello,
758 &hello_offered,
759 cc);
760}
761
762
763/**
764 * Initiate a connection from p1 to p2 by offering p1 p2's HELLO message
765 *
766 * Remarks: start_peer's notify_connect callback can be called before.
767 *
768 * @param tth transport testing handle
769 * @param p1 peer 1
770 * @param p2 peer 2
771 * @param cb the callback to call when both peers notified that they are connected
772 * @param cls callback cls
773 * @return a connect request handle
774 */
775struct GNUNET_TRANSPORT_TESTING_ConnectRequest *
776GNUNET_TRANSPORT_TESTING_connect_peers (struct
777 GNUNET_TRANSPORT_TESTING_PeerContext *p1,
778 struct
779 GNUNET_TRANSPORT_TESTING_PeerContext *p2,
780 GNUNET_SCHEDULER_TaskCallback cb,
781 void *cls)
782{
783 struct GNUNET_TRANSPORT_TESTING_Handle *tth = p1->tth;
784 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
785 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ccn;
786
787 ccn = NULL;
788 for (cc = tth->cc_head; NULL != cc; cc = cc->next)
789 {
790 if ((cc->p1 == p1) &&
791 (cc->p2 == p2))
792 {
793 ccn = cc;
794 break;
795 }
796 }
797
798 cc = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_ConnectRequest);
799 cc->p1 = p1;
800 cc->p2 = p2;
801 cc->cb = cb;
802 if (NULL != cls)
803 cc->cb_cls = cls;
804 else
805 cc->cb_cls = cc;
806 if (NULL != ccn)
807 {
808 cc->p1_c = ccn->p1_c;
809 cc->p2_c = ccn->p2_c;
810 cc->connected = ccn->connected;
811 }
812 GNUNET_CONTAINER_DLL_insert (tth->cc_head,
813 tth->cc_tail,
814 cc);
815 cc->tct = GNUNET_SCHEDULER_add_now (&offer_hello,
816 cc);
817 cc->ats_sh = GNUNET_ATS_connectivity_suggest (cc->p1->ats,
818 &p2->id,
819 1);
820 LOG (GNUNET_ERROR_TYPE_DEBUG,
821 "New connect request %p\n",
822 cc);
823 return cc;
824}
825
826
827/**
828 * Cancel the request to connect two peers
829 * Tou MUST cancel the request if you stop the peers before the peers connected successfully
830 *
831 * @param tth transport testing handle
832 * @param cc a connect request handle
833 */
834void
835GNUNET_TRANSPORT_TESTING_connect_peers_cancel (struct
836 GNUNET_TRANSPORT_TESTING_ConnectRequest
837 *cc)
838{
839 struct GNUNET_TRANSPORT_TESTING_Handle *tth = cc->p1->tth;
840
841 LOG (GNUNET_ERROR_TYPE_DEBUG,
842 "Canceling connect request!\n");
843 if (NULL != cc->tct)
844 {
845 GNUNET_SCHEDULER_cancel (cc->tct);
846 cc->tct = NULL;
847 }
848 if (NULL != cc->oh)
849 {
850 GNUNET_TRANSPORT_offer_hello_cancel (cc->oh);
851 cc->oh = NULL;
852 }
853 if (NULL != cc->ats_sh)
854 {
855 GNUNET_ATS_connectivity_suggest_cancel (cc->ats_sh);
856 cc->ats_sh = NULL;
857 }
858 GNUNET_CONTAINER_DLL_remove (tth->cc_head,
859 tth->cc_tail,
860 cc);
861 GNUNET_free (cc);
862}
863
864
865/**
866 * Clean up the transport testing
867 *
868 * @param tth transport testing handle
869 */
870void
871GNUNET_TRANSPORT_TESTING_done (struct GNUNET_TRANSPORT_TESTING_Handle *tth)
872{
873 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
874 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ct;
875 struct GNUNET_TRANSPORT_TESTING_PeerContext *p;
876 struct GNUNET_TRANSPORT_TESTING_PeerContext *t;
877
878 if (NULL == tth)
879 return;
880 cc = tth->cc_head;
881 while (NULL != cc)
882 {
883 ct = cc->next;
884 LOG (GNUNET_ERROR_TYPE_ERROR,
885 "Developer forgot to cancel connect request!\n");
886 GNUNET_TRANSPORT_TESTING_connect_peers_cancel (cc);
887 cc = ct;
888 }
889 p = tth->p_head;
890 while (NULL != p)
891 {
892 t = p->next;
893 LOG (GNUNET_ERROR_TYPE_ERROR,
894 "Developer forgot to stop peer!\n");
895 GNUNET_TRANSPORT_TESTING_stop_peer (p);
896 p = t;
897 }
898 GNUNET_TESTING_system_destroy (tth->tl_system,
899 GNUNET_YES);
900
901 GNUNET_free (tth);
902}
903
904
905/**
906 * Initialize the transport testing
907 *
908 * @return transport testing handle
909 */
910struct GNUNET_TRANSPORT_TESTING_Handle *
911GNUNET_TRANSPORT_TESTING_init ()
912{
913 struct GNUNET_TRANSPORT_TESTING_Handle *tth;
914
915 tth = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_Handle);
916 tth->tl_system = GNUNET_TESTING_system_create ("transport-testing",
917 NULL,
918 NULL,
919 NULL);
920 if (NULL == tth->tl_system)
921 {
922 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
923 "Failed to initialize testing library!\n");
924 GNUNET_free (tth);
925 return NULL;
926 }
927 return tth;
928}
929
930
931/* 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
deleted file mode 100644
index 6d41ec098..000000000
--- a/src/transport/transport-testing2.c
+++ /dev/null
@@ -1,961 +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 "transport-testing2.h"
27
28
29#define LOG(kind, ...) GNUNET_log_from (kind, "transport-testing", __VA_ARGS__)
30
31
32static struct GNUNET_TRANSPORT_TESTING_PeerContext *
33find_peer_context (struct GNUNET_TRANSPORT_TESTING_Handle *tth,
34 const struct GNUNET_PeerIdentity *peer)
35{
36 struct GNUNET_TRANSPORT_TESTING_PeerContext *t;
37
38 for (t = tth->p_head; NULL != t; t = t->next)
39 if (0 == memcmp (&t->id,
40 peer,
41 sizeof(struct GNUNET_PeerIdentity)))
42 return t;
43 return NULL;
44}
45
46
47/**
48 * Find any connecting context matching the given pair of peers.
49 *
50 * @param p1 first peer
51 * @param p2 second peer
52 * @param cb function to call
53 * @param cb_cls closure for @a cb
54 */
55void
56GNUNET_TRANSPORT_TESTING_find_connecting_context (struct
57 GNUNET_TRANSPORT_TESTING_PeerContext
58 *p1,
59 struct
60 GNUNET_TRANSPORT_TESTING_PeerContext
61 *p2,
62 GNUNET_TRANSPORT_TESTING_ConnectContextCallback
63 cb,
64 void *cb_cls)
65{
66 struct GNUNET_TRANSPORT_TESTING_Handle *tth = p1->tth;
67 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
68 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ccn;
69
70 for (cc = tth->cc_head; NULL != cc; cc = ccn)
71 {
72 ccn = cc->next;
73 if ((cc->p1 == p1) &&
74 (cc->p2 == p2))
75 cb (cb_cls,
76 cc);
77 }
78}
79
80
81static void
82set_p1c (void *cls,
83 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
84{
85 int *found = cls;
86
87 if (NULL != found)
88 *found = GNUNET_YES;
89 cx->p1_c = GNUNET_YES;
90}
91
92
93static void
94set_mq (void *cls,
95 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
96{
97 struct GNUNET_MQ_Handle *mq = cls;
98
99 cx->mq = mq;
100}
101
102
103static void
104set_p2c (void *cls,
105 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
106{
107 int *found = cls;
108
109 if (NULL != found)
110 *found = GNUNET_YES;
111 cx->p2_c = GNUNET_YES;
112}
113
114
115static void
116clear_p1c (void *cls,
117 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
118{
119 int *found = cls;
120
121 if (NULL != found)
122 *found = GNUNET_YES;
123 cx->p1_c = GNUNET_NO;
124}
125
126
127static void
128clear_p2c (void *cls,
129 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
130{
131 int *found = cls;
132
133 if (NULL != found)
134 *found = GNUNET_YES;
135 cx->p2_c = GNUNET_NO;
136}
137
138
139static void *
140notify_connect (void *cls,
141 const struct GNUNET_PeerIdentity *peer,
142 struct GNUNET_MQ_Handle *mq)
143{
144 struct GNUNET_TRANSPORT_TESTING_PeerContext *p = cls;
145 struct GNUNET_TRANSPORT_TESTING_Handle *tth = p->tth;
146 char *p2_s;
147 struct GNUNET_TRANSPORT_TESTING_PeerContext *p2;
148 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
149 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ccn;
150 int found;
151 void *ret;
152
153 p2 = find_peer_context (p->tth,
154 peer);
155 if (NULL != p->nc)
156 ret = p->nc (p->cb_cls,
157 peer,
158 mq);
159 else
160 ret = NULL;
161
162 if (NULL != p2)
163 GNUNET_asprintf (&p2_s,
164 "%u (`%s')",
165 p2->no,
166 GNUNET_i2s (&p2->id));
167 else
168 GNUNET_asprintf (&p2_s,
169 "`%s'",
170 GNUNET_i2s (peer));
171 LOG (GNUNET_ERROR_TYPE_DEBUG,
172 "Peers %s connected to peer %u (`%s')\n",
173 p2_s,
174 p->no,
175 GNUNET_i2s (&p->id));
176 GNUNET_free (p2_s);
177 /* update flags in connecting contexts */
178 found = GNUNET_NO;
179 GNUNET_TRANSPORT_TESTING_find_connecting_context (p,
180 p2,
181 &set_p1c,
182 &found);
183 if (GNUNET_NO == found)
184 {
185 cc = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_ConnectRequest);
186 cc->p1 = p;
187 cc->p2 = p2;
188 cc->p1_c = GNUNET_YES;
189 GNUNET_CONTAINER_DLL_insert (tth->cc_head,
190 tth->cc_tail,
191 cc);
192 }
193 found = GNUNET_NO;
194 GNUNET_TRANSPORT_TESTING_find_connecting_context (p2,
195 p,
196 &set_p2c,
197 &found);
198 if (GNUNET_NO == found)
199 {
200 cc = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_ConnectRequest);
201 cc->p1 = p2;
202 cc->p2 = p;
203 cc->p1_c = GNUNET_YES;
204 GNUNET_CONTAINER_DLL_insert (tth->cc_head,
205 tth->cc_tail,
206 cc);
207 }
208 GNUNET_TRANSPORT_TESTING_find_connecting_context (p,
209 p2,
210 &set_mq,
211 mq);
212 /* update set connected flag for all requests */
213 for (cc = tth->cc_head; NULL != cc; cc = cc->next)
214 {
215 if (GNUNET_YES == cc->connected)
216 continue;
217 if ((GNUNET_YES == cc->p1_c) &&
218 (GNUNET_YES == cc->p2_c))
219 {
220 cc->connected = GNUNET_YES;
221 /* stop trying to connect */
222 if (NULL != cc->tct)
223 {
224 GNUNET_SCHEDULER_cancel (cc->tct);
225 cc->tct = NULL;
226 }
227 if (NULL != cc->ats_sh)
228 {
229 GNUNET_ATS_connectivity_suggest_cancel (cc->ats_sh);
230 cc->ats_sh = NULL;
231 }
232 }
233 }
234 /* then notify application */
235 for (cc = tth->cc_head; NULL != cc; cc = ccn)
236 {
237 ccn = cc->next;
238 if ((GNUNET_YES == cc->connected) &&
239 (NULL != cc->cb))
240 {
241 cc->cb (cc->cb_cls);
242 cc->cb = NULL; /* only notify once! */
243 }
244 }
245 return ret;
246}
247
248
249/**
250 * Offer the current HELLO of P2 to P1.
251 *
252 * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectRequest`
253 */
254static void
255offer_hello (void *cls);
256
257
258static void
259notify_disconnect (void *cls,
260 const struct GNUNET_PeerIdentity *peer,
261 void *handler_cls)
262{
263 struct GNUNET_TRANSPORT_TESTING_PeerContext *p = cls;
264 struct GNUNET_TRANSPORT_TESTING_Handle *tth = p->tth;
265 char *p2_s;
266 /* Find PeerContext */
267 int no = 0;
268 struct GNUNET_TRANSPORT_TESTING_PeerContext *p2 = NULL;
269 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
270
271 p2 = find_peer_context (p->tth,
272 peer);
273 no = p->no;
274 if (NULL != p2)
275 GNUNET_asprintf (&p2_s,
276 "%u (`%s')",
277 p2->no,
278 GNUNET_i2s (&p2->id));
279 else
280 GNUNET_asprintf (&p2_s,
281 "`%s'",
282 GNUNET_i2s (peer));
283 LOG (GNUNET_ERROR_TYPE_DEBUG,
284 "Peers %s disconnected from peer %u (`%s')\n",
285 p2_s,
286 no,
287 GNUNET_i2s (&p->id));
288 GNUNET_free (p2_s);
289 /* notify about disconnect */
290 if (NULL != p->nd)
291 p->nd (p->cb_cls,
292 peer,
293 handler_cls);
294 if (NULL == p2)
295 return;
296 /* clear MQ, it is now invalid */
297 GNUNET_TRANSPORT_TESTING_find_connecting_context (p,
298 p2,
299 &set_mq,
300 NULL);
301 /* update set connected flags for all requests */
302 GNUNET_TRANSPORT_TESTING_find_connecting_context (p,
303 p2,
304 &clear_p1c,
305 NULL);
306 GNUNET_TRANSPORT_TESTING_find_connecting_context (p2,
307 p,
308 &clear_p2c,
309 NULL);
310 /* resume connectivity requests as necessary */
311 for (cc = tth->cc_head; NULL != cc; cc = cc->next)
312 {
313 if (GNUNET_NO == cc->connected)
314 continue;
315 if ((GNUNET_YES != cc->p1_c) ||
316 (GNUNET_YES != cc->p2_c))
317 {
318 cc->connected = GNUNET_NO;
319 /* start trying to connect */
320 if (NULL == cc->tct)
321 cc->tct = GNUNET_SCHEDULER_add_now (&offer_hello,
322 cc);
323 if (NULL == cc->ats_sh)
324 cc->ats_sh = GNUNET_ATS_connectivity_suggest (cc->p1->ats,
325 &p2->id,
326 1);
327 }
328 }
329}
330
331static void
332retrieve_hello (void *cls);
333
334static void
335hello_iter_cb (void *cb_cls,
336 const struct GNUNET_PEERSTORE_Record *record,
337 const char *emsg)
338{
339 struct GNUNET_TRANSPORT_TESTING_PeerContext *p = cb_cls;
340 if (NULL == record)
341 {
342 p->pic = NULL;
343 if (NULL != p->start_cb)
344 p->rh_task = GNUNET_SCHEDULER_add_now (retrieve_hello, p);
345 return;
346 }
347 // Check record type et al?
348 p->hello_size = record->value_size;
349 p->hello = GNUNET_malloc (p->hello_size);
350 memcpy (p->hello, record->value, p->hello_size);
351 p->hello[p->hello_size - 1] = '\0';
352
353 GNUNET_PEERSTORE_iterate_cancel (p->pic);
354 p->pic = NULL;
355 if (NULL != p->start_cb)
356 {
357 LOG (GNUNET_ERROR_TYPE_DEBUG,
358 "Peer %u (`%s') successfully started\n",
359 p->no,
360 GNUNET_i2s (&p->id));
361 p->start_cb (p->start_cb_cls);
362 p->start_cb = NULL;
363 }
364}
365
366
367static void
368retrieve_hello (void *cls)
369{
370 struct GNUNET_TRANSPORT_TESTING_PeerContext *p = cls;
371 p->rh_task = NULL;
372 p->pic = GNUNET_PEERSTORE_iterate (p->ph,
373 "transport",
374 &p->id,
375 GNUNET_PEERSTORE_TRANSPORT_HELLO_KEY,
376 hello_iter_cb,
377 p);
378
379}
380
381
382/**
383 * Start a peer with the given configuration
384 * @param tth the testing handle
385 * @param cfgname configuration file
386 * @param peer_id a unique number to identify the peer
387 * @param handlers functions for receiving messages
388 * @param nc connect callback
389 * @param nd disconnect callback
390 * @param cb_cls closure for callback
391 * @param start_cb start callback
392 * @param start_cb_cls closure for callback
393 * @return the peer context
394 */
395struct GNUNET_TRANSPORT_TESTING_PeerContext *
396GNUNET_TRANSPORT_TESTING_start_peer (struct
397 GNUNET_TRANSPORT_TESTING_Handle *tth,
398 const char *cfgname,
399 int peer_id,
400 const struct
401 GNUNET_MQ_MessageHandler *handlers,
402 GNUNET_TRANSPORT_NotifyConnect nc,
403 GNUNET_TRANSPORT_NotifyDisconnect nd,
404 void *cb_cls,
405 GNUNET_SCHEDULER_TaskCallback start_cb,
406 void *start_cb_cls)
407{
408 char *emsg = NULL;
409 struct GNUNET_TRANSPORT_TESTING_PeerContext *p;
410 struct GNUNET_PeerIdentity dummy;
411 unsigned int i;
412
413 if (GNUNET_NO == GNUNET_DISK_file_test (cfgname))
414 {
415 LOG (GNUNET_ERROR_TYPE_ERROR,
416 "File not found: `%s'\n",
417 cfgname);
418 return NULL;
419 }
420
421 p = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_PeerContext);
422 p->tth = tth;
423 p->nc = nc;
424 p->nd = nd;
425 if (NULL != handlers)
426 {
427 for (i = 0; NULL != handlers[i].cb; i++)
428 ;
429 p->handlers = GNUNET_new_array (i + 1,
430 struct GNUNET_MQ_MessageHandler);
431 GNUNET_memcpy (p->handlers,
432 handlers,
433 i * sizeof(struct GNUNET_MQ_MessageHandler));
434 }
435 if (NULL != cb_cls)
436 p->cb_cls = cb_cls;
437 else
438 p->cb_cls = p;
439 p->start_cb = start_cb;
440 if (NULL != start_cb_cls)
441 p->start_cb_cls = start_cb_cls;
442 else
443 p->start_cb_cls = p;
444 GNUNET_CONTAINER_DLL_insert (tth->p_head,
445 tth->p_tail,
446 p);
447
448 /* Create configuration and call testing lib to modify it */
449 p->cfg = GNUNET_CONFIGURATION_create ();
450 GNUNET_assert (GNUNET_OK ==
451 GNUNET_CONFIGURATION_load (p->cfg, cfgname));
452 if (GNUNET_SYSERR ==
453 GNUNET_TESTING_configuration_create (tth->tl_system,
454 p->cfg))
455 {
456 LOG (GNUNET_ERROR_TYPE_ERROR,
457 "Testing library failed to create unique configuration based on `%s'\n",
458 cfgname);
459 GNUNET_CONFIGURATION_destroy (p->cfg);
460 GNUNET_free (p);
461 return NULL;
462 }
463
464 p->no = peer_id;
465 /* Configure peer with configuration */
466 p->peer = GNUNET_TESTING_peer_configure (tth->tl_system,
467 p->cfg,
468 p->no,
469 NULL,
470 &emsg);
471 if (NULL == p->peer)
472 {
473 LOG (GNUNET_ERROR_TYPE_ERROR,
474 "Testing library failed to create unique configuration based on `%s': `%s'\n",
475 cfgname,
476 emsg);
477 GNUNET_TRANSPORT_TESTING_stop_peer (p);
478 GNUNET_free (emsg);
479 return NULL;
480 }
481
482 if (GNUNET_OK != GNUNET_TESTING_peer_start (p->peer))
483 {
484 LOG (GNUNET_ERROR_TYPE_ERROR,
485 "Testing library failed to create unique configuration based on `%s'\n",
486 cfgname);
487 GNUNET_TRANSPORT_TESTING_stop_peer (p);
488 return NULL;
489 }
490
491 memset (&dummy,
492 '\0',
493 sizeof(dummy));
494 GNUNET_TESTING_peer_get_identity (p->peer,
495 &p->id);
496 if (0 == memcmp (&dummy,
497 &p->id,
498 sizeof(struct GNUNET_PeerIdentity)))
499 {
500 LOG (GNUNET_ERROR_TYPE_ERROR,
501 "Testing library failed to obtain peer identity for peer %u\n",
502 p->no);
503 GNUNET_TRANSPORT_TESTING_stop_peer (p);
504 return NULL;
505 }
506 LOG (GNUNET_ERROR_TYPE_DEBUG,
507 "Peer %u configured with identity `%s'\n",
508 p->no,
509 GNUNET_i2s_full (&p->id));
510 p->th = GNUNET_TRANSPORT_core_connect (p->cfg,
511 NULL,
512 handlers,
513 p,
514 &notify_connect,
515 &notify_disconnect);
516 if (NULL == p->th)
517 {
518 LOG (GNUNET_ERROR_TYPE_ERROR,
519 "Failed to connect to transport 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->ats = GNUNET_ATS_connectivity_init (p->cfg);
527 if (NULL == p->ats)
528 {
529 LOG (GNUNET_ERROR_TYPE_ERROR,
530 "Failed to connect to ATS service for peer `%s': `%s'\n",
531 cfgname,
532 emsg);
533 GNUNET_TRANSPORT_TESTING_stop_peer (p);
534 GNUNET_free (emsg);
535 return NULL;
536 }
537 p->ph = GNUNET_PEERSTORE_connect (p->cfg);
538 // FIXME Error handling
539 p->ah = GNUNET_TRANSPORT_application_init (p->cfg);
540 GNUNET_assert (NULL != p->ah);
541 // FIXME Error handling
542 p->rh_task = GNUNET_SCHEDULER_add_now (retrieve_hello, p);
543
544 return p;
545}
546
547
548/**
549 * Stops and restarts the given peer, sleeping (!) for 5s in between.
550 *
551 * @param p the peer
552 * @param restart_cb callback to call when restarted
553 * @param restart_cb_cls callback closure
554 * @return #GNUNET_OK in success otherwise #GNUNET_SYSERR
555 */
556int
557GNUNET_TRANSPORT_TESTING_restart_peer (struct
558 GNUNET_TRANSPORT_TESTING_PeerContext *p,
559 GNUNET_SCHEDULER_TaskCallback restart_cb,
560 void *restart_cb_cls)
561{
562 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
563 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ccn;
564
565 /* shutdown */
566 LOG (GNUNET_ERROR_TYPE_DEBUG,
567 "Stopping peer %u (`%s')\n",
568 p->no,
569 GNUNET_i2s (&p->id));
570 if (NULL != p->pic)
571 {
572 GNUNET_PEERSTORE_iterate_cancel (p->pic);
573 p->pic = NULL;
574 }
575 if (NULL != p->th)
576 {
577 GNUNET_TRANSPORT_core_disconnect (p->th);
578 p->th = NULL;
579 }
580 for (cc = p->tth->cc_head; NULL != cc; cc = ccn)
581 {
582 ccn = cc->next;
583 if ((cc->p1 == p) ||
584 (cc->p2 == p))
585 GNUNET_TRANSPORT_TESTING_connect_peers_cancel (cc);
586 }
587 if (NULL != p->ats)
588 {
589 GNUNET_ATS_connectivity_done (p->ats);
590 p->ats = NULL;
591 }
592 if (GNUNET_SYSERR ==
593 GNUNET_TESTING_peer_stop (p->peer))
594 {
595 LOG (GNUNET_ERROR_TYPE_ERROR,
596 "Failed to stop peer %u (`%s')\n",
597 p->no,
598 GNUNET_i2s (&p->id));
599 return GNUNET_SYSERR;
600 }
601
602 sleep (5); // YUCK!
603
604 LOG (GNUNET_ERROR_TYPE_DEBUG,
605 "Restarting peer %u (`%s')\n",
606 p->no,
607 GNUNET_i2s (&p->id));
608 /* restart */
609 if (GNUNET_SYSERR == GNUNET_TESTING_peer_start (p->peer))
610 {
611 LOG (GNUNET_ERROR_TYPE_ERROR,
612 "Failed to restart peer %u (`%s')\n",
613 p->no,
614 GNUNET_i2s (&p->id));
615 return GNUNET_SYSERR;
616 }
617
618 GNUNET_assert (NULL == p->start_cb);
619 p->start_cb = restart_cb;
620 p->start_cb_cls = restart_cb_cls;
621
622 p->th = GNUNET_TRANSPORT_core_connect (p->cfg,
623 NULL,
624 p->handlers,
625 p,
626 &notify_connect,
627 &notify_disconnect);
628 GNUNET_assert (NULL != p->th);
629 p->ats = GNUNET_ATS_connectivity_init (p->cfg);
630 p->pic = GNUNET_PEERSTORE_iterate (p->ph,
631 "transport",
632 &p->id,
633 GNUNET_PEERSTORE_TRANSPORT_HELLO_KEY,
634 hello_iter_cb,
635 p);
636 GNUNET_assert (NULL != p->pic);
637 return GNUNET_OK;
638}
639
640
641/**
642 * Shutdown the given peer
643 *
644 * @param p the peer
645 */
646void
647GNUNET_TRANSPORT_TESTING_stop_peer (struct
648 GNUNET_TRANSPORT_TESTING_PeerContext *p)
649{
650 struct GNUNET_TRANSPORT_TESTING_Handle *tth = p->tth;
651 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
652 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ccn;
653 /* shutdown */
654 LOG (GNUNET_ERROR_TYPE_DEBUG,
655 "Stopping peer %u (`%s')\n",
656 p->no,
657 GNUNET_i2s (&p->id));
658
659 for (cc = tth->cc_head; NULL != cc; cc = ccn)
660 {
661 ccn = cc->next;
662 if ((cc->p1 == p) ||
663 (cc->p2 == p))
664 GNUNET_TRANSPORT_TESTING_connect_peers_cancel (cc);
665 }
666 if (NULL != p->pic)
667 {
668 GNUNET_PEERSTORE_iterate_cancel (p->pic);
669 p->pic = NULL;
670 }
671 if (NULL != p->th)
672 {
673 GNUNET_TRANSPORT_core_disconnect (p->th);
674 p->th = NULL;
675 }
676 if (NULL != p->ats)
677 {
678 GNUNET_ATS_connectivity_done (p->ats);
679 p->ats = NULL;
680 }
681 if (NULL != p->ah)
682 {
683 GNUNET_TRANSPORT_application_done (p->ah);
684 p->ah = NULL;
685 }
686 if (NULL != p->ph)
687 {
688 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
689 "Disconnecting from PEERSTORE service\n");
690 GNUNET_PEERSTORE_disconnect (p->ph, GNUNET_NO);
691 p->ph = NULL;
692 }
693
694 if (NULL != p->peer)
695 {
696 if (GNUNET_OK !=
697 GNUNET_TESTING_peer_stop (p->peer))
698 {
699 LOG (GNUNET_ERROR_TYPE_DEBUG,
700 "Testing lib failed to stop peer %u (`%s')\n",
701 p->no,
702 GNUNET_i2s (&p->id));
703 }
704 GNUNET_TESTING_peer_destroy (p->peer);
705 p->peer = NULL;
706 }
707 if (NULL != p->hello)
708 {
709 GNUNET_free (p->hello);
710 p->hello = NULL;
711 }
712 if (NULL != p->cfg)
713 {
714 GNUNET_CONFIGURATION_destroy (p->cfg);
715 p->cfg = NULL;
716 }
717 if (NULL != p->handlers)
718 {
719 GNUNET_free (p->handlers);
720 p->handlers = NULL;
721 }
722 GNUNET_CONTAINER_DLL_remove (tth->p_head,
723 tth->p_tail,
724 p);
725 LOG (GNUNET_ERROR_TYPE_DEBUG,
726 "Peer %u (`%s') stopped\n",
727 p->no,
728 GNUNET_i2s (&p->id));
729 if (NULL != p->rh_task)
730 GNUNET_SCHEDULER_cancel (p->rh_task);
731 p->rh_task = NULL;
732 GNUNET_free (p);
733}
734
735
736/**
737 * Function called after the HELLO was passed to the
738 * transport service.
739 * FIXME maybe schedule the application_validate somehow
740 */
741/*
742 static void
743 hello_offered (void *cls)
744 {
745 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc = cls;
746
747 cc->oh = NULL;
748 cc->tct = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
749 &offer_hello,
750 cc);
751 }*/
752
753
754/**
755 * Offer the current HELLO of P2 to P1.
756 *
757 * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectRequest`
758 */
759static void
760offer_hello (void *cls)
761{
762 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc = cls;
763 struct GNUNET_TRANSPORT_TESTING_PeerContext *p1 = cc->p1;
764 struct GNUNET_TRANSPORT_TESTING_PeerContext *p2 = cc->p2;
765 struct GNUNET_TIME_Absolute t;
766 enum GNUNET_NetworkType nt = 0;
767 char *addr;
768
769 cc->tct = NULL;
770 {
771 char *p2_s = GNUNET_strdup (GNUNET_i2s (&p2->id));
772
773 LOG (GNUNET_ERROR_TYPE_DEBUG,
774 "Asking peer %u (`%s') to connect peer %u (`%s'), providing HELLO with %s\n",
775 p1->no,
776 GNUNET_i2s (&p1->id),
777 p2->no,
778 p2_s,
779 p2->hello);
780 GNUNET_free (p2_s);
781 }
782
783 addr = GNUNET_HELLO_extract_address (p2->hello,
784 p2->hello_size,
785 &p2->id,
786 &nt,
787 &t);
788 GNUNET_assert (NULL != addr);
789 GNUNET_assert (NULL != p1->hello);
790 GNUNET_TRANSPORT_application_validate (p1->ah,
791 &p2->id,
792 nt,
793 addr);
794 GNUNET_free (addr);
795}
796
797
798/**
799 * Initiate a connection from p1 to p2 by offering p1 p2's HELLO message
800 *
801 * Remarks: start_peer's notify_connect callback can be called before.
802 *
803 * @param tth transport testing handle
804 * @param p1 peer 1
805 * @param p2 peer 2
806 * @param cb the callback to call when both peers notified that they are connected
807 * @param cls callback cls
808 * @return a connect request handle
809 */
810struct GNUNET_TRANSPORT_TESTING_ConnectRequest *
811GNUNET_TRANSPORT_TESTING_connect_peers (struct
812 GNUNET_TRANSPORT_TESTING_PeerContext *p1,
813 struct
814 GNUNET_TRANSPORT_TESTING_PeerContext *p2,
815 GNUNET_SCHEDULER_TaskCallback cb,
816 void *cls)
817{
818 struct GNUNET_TRANSPORT_TESTING_Handle *tth = p1->tth;
819 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
820 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ccn;
821
822 ccn = NULL;
823 for (cc = tth->cc_head; NULL != cc; cc = cc->next)
824 {
825 if ((cc->p1 == p1) &&
826 (cc->p2 == p2))
827 {
828 ccn = cc;
829 break;
830 }
831 }
832
833 cc = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_ConnectRequest);
834 cc->p1 = p1;
835 cc->p2 = p2;
836 cc->cb = cb;
837 if (NULL != cls)
838 cc->cb_cls = cls;
839 else
840 cc->cb_cls = cc;
841 if (NULL != ccn)
842 {
843 cc->p1_c = ccn->p1_c;
844 cc->p2_c = ccn->p2_c;
845 cc->connected = ccn->connected;
846 }
847 GNUNET_CONTAINER_DLL_insert (tth->cc_head,
848 tth->cc_tail,
849 cc);
850 cc->tct = GNUNET_SCHEDULER_add_now (&offer_hello,
851 cc);
852 cc->ats_sh = GNUNET_ATS_connectivity_suggest (cc->p1->ats,
853 &p2->id,
854 1);
855 LOG (GNUNET_ERROR_TYPE_DEBUG,
856 "New connect request %p\n",
857 cc);
858 return cc;
859}
860
861
862/**
863 * Cancel the request to connect two peers
864 * Tou MUST cancel the request if you stop the peers before the peers connected successfully
865 *
866 * @param tth transport testing handle
867 * @param cc a connect request handle
868 */
869void
870GNUNET_TRANSPORT_TESTING_connect_peers_cancel (struct
871 GNUNET_TRANSPORT_TESTING_ConnectRequest
872 *cc)
873{
874 struct GNUNET_TRANSPORT_TESTING_Handle *tth = cc->p1->tth;
875
876 LOG (GNUNET_ERROR_TYPE_DEBUG,
877 "Canceling connect request!\n");
878 if (NULL != cc->tct)
879 {
880 GNUNET_SCHEDULER_cancel (cc->tct);
881 cc->tct = NULL;
882 }
883 if (NULL != cc->ats_sh)
884 {
885 GNUNET_ATS_connectivity_suggest_cancel (cc->ats_sh);
886 cc->ats_sh = NULL;
887 }
888 GNUNET_CONTAINER_DLL_remove (tth->cc_head,
889 tth->cc_tail,
890 cc);
891 GNUNET_free (cc);
892}
893
894
895/**
896 * Clean up the transport testing
897 *
898 * @param tth transport testing handle
899 */
900void
901GNUNET_TRANSPORT_TESTING_done (struct GNUNET_TRANSPORT_TESTING_Handle *tth)
902{
903 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
904 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ct;
905 struct GNUNET_TRANSPORT_TESTING_PeerContext *p;
906 struct GNUNET_TRANSPORT_TESTING_PeerContext *t;
907
908 if (NULL == tth)
909 return;
910 cc = tth->cc_head;
911 while (NULL != cc)
912 {
913 ct = cc->next;
914 LOG (GNUNET_ERROR_TYPE_ERROR,
915 "Developer forgot to cancel connect request!\n");
916 GNUNET_TRANSPORT_TESTING_connect_peers_cancel (cc);
917 cc = ct;
918 }
919 p = tth->p_head;
920 while (NULL != p)
921 {
922 t = p->next;
923 LOG (GNUNET_ERROR_TYPE_ERROR,
924 "Developer forgot to stop peer!\n");
925 GNUNET_TRANSPORT_TESTING_stop_peer (p);
926 p = t;
927 }
928 GNUNET_TESTING_system_destroy (tth->tl_system,
929 GNUNET_YES);
930
931 GNUNET_free (tth);
932}
933
934
935/**
936 * Initialize the transport testing
937 *
938 * @return transport testing handle
939 */
940struct GNUNET_TRANSPORT_TESTING_Handle *
941GNUNET_TRANSPORT_TESTING_init ()
942{
943 struct GNUNET_TRANSPORT_TESTING_Handle *tth;
944
945 tth = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_Handle);
946 tth->tl_system = GNUNET_TESTING_system_create ("transport-testing",
947 NULL,
948 NULL,
949 NULL);
950 if (NULL == tth->tl_system)
951 {
952 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
953 "Failed to initialize testing library!\n");
954 GNUNET_free (tth);
955 return NULL;
956 }
957 return tth;
958}
959
960
961/* end of transport-testing.c */
diff --git a/src/transport/transport-testing2.h b/src/transport/transport-testing2.h
deleted file mode 100644
index e2167ca7e..000000000
--- a/src/transport/transport-testing2.h
+++ /dev/null
@@ -1,924 +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_peerstore_service.h"
33#include "gnunet_transport_core_service.h"
34#include "gnunet_transport_application_service.h"
35#include "gnunet_transport_manipulation_service.h"
36#include "gnunet_testing_lib.h"
37
38
39/* ************* Basic functions for starting/stopping/connecting *********** */
40
41/**
42 * Context for a single peer
43 */
44struct GNUNET_TRANSPORT_TESTING_PeerContext;
45
46/**
47 * Definition for a transport testing handle
48 */
49struct GNUNET_TRANSPORT_TESTING_Handle;
50
51
52/**
53 * Context for a single peer
54 */
55struct GNUNET_TRANSPORT_TESTING_PeerContext
56{
57 /**
58 * Next element in the DLL
59 */
60 struct GNUNET_TRANSPORT_TESTING_PeerContext *next;
61
62 /**
63 * Previous element in the DLL
64 */
65 struct GNUNET_TRANSPORT_TESTING_PeerContext *prev;
66
67 /**
68 * Transport testing handle this peer belongs to
69 */
70 struct GNUNET_TRANSPORT_TESTING_Handle *tth;
71
72 /**
73 * Application handle
74 */
75 struct GNUNET_TRANSPORT_ApplicationHandle *ah;
76
77 /**
78 * Peer's configuration
79 */
80 struct GNUNET_CONFIGURATION_Handle *cfg;
81
82 /**
83 * Peer's transport service handle
84 */
85 struct GNUNET_TRANSPORT_CoreHandle *th;
86
87 /**
88 * Peer's ATS handle.
89 */
90 struct GNUNET_ATS_ConnectivityHandle *ats;
91
92 /**
93 * Peer's PEERSTORE Handle
94 */
95 struct GNUNET_PEERSTORE_Handle *ph;
96
97 /**
98 * Peer's transport get hello handle to retrieve peer's HELLO message
99 */
100 struct GNUNET_PEERSTORE_IterateContext *pic;
101
102 /**
103 * Hello
104 */
105 char *hello;
106
107 /**
108 * Hello size
109 */
110 size_t hello_size;
111
112 /**
113 * Peer's testing handle
114 */
115 struct GNUNET_TESTING_Peer *peer;
116
117 /**
118 * Peer identity
119 */
120 struct GNUNET_PeerIdentity id;
121
122 /**
123 * Handle for the peer's ARM process
124 */
125 struct GNUNET_OS_Process *arm_proc;
126
127 /**
128 * Receive callback
129 */
130 struct GNUNET_MQ_MessageHandler *handlers;
131
132 /**
133 * Notify connect callback
134 */
135 GNUNET_TRANSPORT_NotifyConnect nc;
136
137 /**
138 * Notify disconnect callback
139 */
140 GNUNET_TRANSPORT_NotifyDisconnect nd;
141
142 /**
143 * Startup completed callback
144 */
145 GNUNET_SCHEDULER_TaskCallback start_cb;
146
147 /**
148 * Hello get task
149 */
150 struct GNUNET_SCHEDULER_Task *rh_task;
151
152 /**
153 * Closure for the @a nc and @a nd callbacks
154 */
155 void *cb_cls;
156
157 /**
158 * Closure for @e start_cb.
159 */
160 void *start_cb_cls;
161
162 /**
163 * An unique number to identify the peer
164 */
165 unsigned int no;
166};
167
168
169/**
170 * Handle for a request to connect two peers.
171 */
172struct GNUNET_TRANSPORT_TESTING_ConnectRequest
173{
174 /**
175 * Kept in a DLL.
176 */
177 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *next;
178
179 /**
180 * Kept in a DLL.
181 */
182 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *prev;
183
184 /**
185 * Peer we want to connect.
186 */
187 struct GNUNET_TRANSPORT_TESTING_PeerContext *p1;
188
189 /**
190 * Peer we want to connect.
191 */
192 struct GNUNET_TRANSPORT_TESTING_PeerContext *p2;
193
194 /**
195 * Task by which we accomplish the connection.
196 */
197 struct GNUNET_SCHEDULER_Task *tct;
198
199 /**
200 * Handle by which we ask ATS to facilitate the connection.
201 */
202 struct GNUNET_ATS_ConnectivitySuggestHandle *ats_sh;
203
204 /**
205 * Function to call upon completion.
206 */
207 GNUNET_SCHEDULER_TaskCallback cb;
208
209 /**
210 * Closure for @e cb.
211 */
212 void *cb_cls;
213
214 /**
215 * Message queue for sending from @a p1 to @a p2.
216 */
217 struct GNUNET_MQ_Handle *mq;
218
219 /**
220 * Set if peer1 says the connection is up to peer2.
221 */
222 int p1_c;
223
224 /**
225 * Set if peer2 says the connection is up to peer1.
226 */
227 int p2_c;
228
229 /**
230 * #GNUNET_YES if both @e p1_c and @e p2_c are #GNUNET_YES.
231 */
232 int connected;
233};
234
235
236/**
237 * Handle for a test run.
238 */
239struct GNUNET_TRANSPORT_TESTING_Handle
240{
241 /**
242 * Testing library system handle
243 */
244 struct GNUNET_TESTING_System *tl_system;
245
246 /**
247 * head DLL of connect contexts
248 */
249 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc_head;
250
251 /**
252 * head DLL of connect contexts
253 */
254 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc_tail;
255
256 /**
257 * head DLL of peers
258 */
259 struct GNUNET_TRANSPORT_TESTING_PeerContext *p_head;
260
261 /**
262 * tail DLL of peers
263 */
264 struct GNUNET_TRANSPORT_TESTING_PeerContext *p_tail;
265};
266
267
268/**
269 * Initialize the transport testing
270 *
271 * @return transport testing handle
272 */
273struct GNUNET_TRANSPORT_TESTING_Handle *
274GNUNET_TRANSPORT_TESTING_init (void);
275
276
277/**
278 * Clean up the transport testing
279 *
280 * @param tth transport testing handle
281 */
282void
283GNUNET_TRANSPORT_TESTING_done (struct GNUNET_TRANSPORT_TESTING_Handle *tth);
284
285
286/**
287 * Start a peer with the given configuration
288 *
289 * @param tth the testing handle
290 * @param cfgname configuration file
291 * @param peer_id the peer_id
292 * @param handlers functions for receiving messages
293 * @param nc connect callback
294 * @param nd disconnect callback
295 * @param cb_cls closure for @a nc and @a nd callback
296 * @param start_cb start callback
297 * @param start_cb_cls closure for @a start_cb
298 * @return the peer context
299 */
300struct GNUNET_TRANSPORT_TESTING_PeerContext *
301GNUNET_TRANSPORT_TESTING_start_peer (
302 struct GNUNET_TRANSPORT_TESTING_Handle *tth,
303 const char *cfgname,
304 int peer_id,
305 const struct GNUNET_MQ_MessageHandler *handlers,
306 GNUNET_TRANSPORT_NotifyConnect nc,
307 GNUNET_TRANSPORT_NotifyDisconnect nd,
308 void *cb_cls,
309 GNUNET_SCHEDULER_TaskCallback start_cb,
310 void *start_cb_cls);
311
312
313/**
314 * Shutdown the given peer
315 *
316 * @param p the peer
317 */
318void
319GNUNET_TRANSPORT_TESTING_stop_peer (
320 struct GNUNET_TRANSPORT_TESTING_PeerContext *pc);
321
322
323/**
324 * Stops and restarts the given peer, sleeping (!) for 5s in between.
325 *
326 * @param p the peer
327 * @param restart_cb restart callback
328 * @param restart_cb_cls callback closure
329 * @return #GNUNET_OK in success otherwise #GNUNET_SYSERR
330 */
331int
332GNUNET_TRANSPORT_TESTING_restart_peer (
333 struct GNUNET_TRANSPORT_TESTING_PeerContext *p,
334 GNUNET_SCHEDULER_TaskCallback restart_cb,
335 void *restart_cb_cls);
336
337
338/**
339 * Connect the given peers and call the callback when both peers
340 * report the inbound connection. Remarks: start_peer's notify_connect
341 * callback can be called before.
342 *
343 * @param p1 peer 1
344 * @param p2 peer 2
345 * @param cb the callback to call when both peers notified that they are
346 * connected
347 * @param cls callback cls
348 * @return a connect request handle
349 */
350struct GNUNET_TRANSPORT_TESTING_ConnectRequest *
351GNUNET_TRANSPORT_TESTING_connect_peers (
352 struct GNUNET_TRANSPORT_TESTING_PeerContext *p1,
353 struct GNUNET_TRANSPORT_TESTING_PeerContext *p2,
354 GNUNET_SCHEDULER_TaskCallback cb,
355 void *cls);
356
357
358/**
359 * Cancel the request to connect two peers. You MUST cancel the
360 * request if you stop the peers before the peers connected
361 * successfully.
362 *
363 * @param cc a connect request handle
364 */
365void
366GNUNET_TRANSPORT_TESTING_connect_peers_cancel (
367 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc);
368
369
370/**
371 * Function called on matching connect requests.
372 *
373 * @param cls closure
374 * @param cc request matching the query
375 */
376typedef void (*GNUNET_TRANSPORT_TESTING_ConnectContextCallback) (
377 void *cls,
378 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc);
379
380
381/**
382 * Find any connecting context matching the given pair of peers.
383 *
384 * @param p1 first peer
385 * @param p2 second peer
386 * @param cb function to call
387 * @param cb_cls closure for @a cb
388 */
389void
390GNUNET_TRANSPORT_TESTING_find_connecting_context (
391 struct GNUNET_TRANSPORT_TESTING_PeerContext *p1,
392 struct GNUNET_TRANSPORT_TESTING_PeerContext *p2,
393 GNUNET_TRANSPORT_TESTING_ConnectContextCallback cb,
394 void *cb_cls);
395
396
397/* ********************** high-level process functions *************** */
398
399
400/**
401 * Function called once the peers have been launched and
402 * connected by #GNUNET_TRANSPORT_TESTING_connect_check().
403 *
404 * @param cls closure
405 * @param num_peers size of the @a p array
406 * @param p the peers that were launched
407 */
408typedef void (*GNUNET_TRANSPORT_TESTING_ConnectContinuation) (
409 void *cls,
410 unsigned int num_peers,
411 struct GNUNET_TRANSPORT_TESTING_PeerContext *p[]);
412
413
414/**
415 * Internal data structure.
416 */
417struct GNUNET_TRANSPORT_TESTING_ConnectRequestList;
418
419/**
420 * Internal data structure.
421 */
422struct GNUNET_TRANSPORT_TESTING_InternalPeerContext;
423
424
425GNUNET_NETWORK_STRUCT_BEGIN
426struct GNUNET_TRANSPORT_TESTING_TestMessage
427{
428 /**
429 * Type is (usually) #GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE.
430 */
431 struct GNUNET_MessageHeader header;
432
433 /**
434 * Monotonically increasing counter throughout the test.
435 */
436 uint32_t num GNUNET_PACKED;
437};
438GNUNET_NETWORK_STRUCT_END
439
440
441/**
442 * Function called by the transport for each received message.
443 *
444 * @param cls closure
445 * @param receiver receiver of the message
446 * @param sender sender of the message
447 * @param message the message
448 */
449typedef void (*GNUNET_TRANSPORT_TESTING_ReceiveCallback) (
450 void *cls,
451 struct GNUNET_TRANSPORT_TESTING_PeerContext *receiver,
452 const struct GNUNET_PeerIdentity *sender,
453 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message);
454
455
456/**
457 * Function called to notify transport users that another
458 * peer connected to us.
459 *
460 * @param cls closure
461 * @param me peer experiencing the event
462 * @param other peer that connected to @a me
463 */
464typedef void (*GNUNET_TRANSPORT_TESTING_NotifyConnect) (
465 void *cls,
466 struct GNUNET_TRANSPORT_TESTING_PeerContext *me,
467 const struct GNUNET_PeerIdentity *other);
468
469
470/**
471 * Function called to notify transport users that another
472 * peer disconnected from us.
473 *
474 * @param cls closure
475 * @param me peer experiencing the event
476 * @param other peer that disconnected from @a me
477 */
478typedef void (*GNUNET_TRANSPORT_TESTING_NotifyDisconnect) (
479 void *cls,
480 struct GNUNET_TRANSPORT_TESTING_PeerContext *me,
481 const struct GNUNET_PeerIdentity *other);
482
483
484/**
485 * Closure that must be passed to
486 * #GNUNET_TRANSPORT_TESTING_connect_check.
487 */
488struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext
489{
490 /**
491 * How should we continue after the connect?
492 */
493 GNUNET_SCHEDULER_TaskCallback connect_continuation;
494
495 /**
496 * Closure for @e connect_continuation.
497 */
498 void *connect_continuation_cls;
499
500 /**
501 * Which configuration file should we pass to the
502 * #GNUNET_PROGRAM_run() of the testcase?
503 */
504 const char *config_file;
505
506 /**
507 * Receiver argument to give for peers we start.
508 */
509 GNUNET_TRANSPORT_TESTING_ReceiveCallback rec;
510
511 /**
512 * Notify connect argument to give for peers we start.
513 */
514 GNUNET_TRANSPORT_TESTING_NotifyConnect nc;
515
516 /**
517 * Notify disconnect argument to give for peers we start.
518 */
519 GNUNET_TRANSPORT_TESTING_NotifyDisconnect nd;
520
521 /**
522 * Closure for @e rec, @e nc and @e nd.
523 */
524 void *cls;
525
526 /**
527 * Custom task to run on shutdown.
528 */
529 GNUNET_SCHEDULER_TaskCallback shutdown_task;
530
531 /**
532 * Closure for @e shutdown_task.
533 */
534 void *shutdown_task_cls;
535
536 /**
537 * Custom task to run after peers were started but before we try to
538 * connect them. If this function is set, we wait ONE second after
539 * running this function until we continue with connecting the
540 * peers.
541 */
542 GNUNET_SCHEDULER_TaskCallback pre_connect_task;
543
544 /**
545 * Closure for @e shutdown_task.
546 */
547 void *pre_connect_task_cls;
548
549 /**
550 * When should the testcase time out?
551 */
552 struct GNUNET_TIME_Relative timeout;
553
554 /**
555 * Should we try to create connections in both directions?
556 */
557 int bi_directional;
558
559 /* ******* fields set by #GNUNET_TRANSPORT_TESTING_connect_check **** */
560
561 /**
562 * Number of peers involved in the test.
563 */
564 unsigned int num_peers;
565
566 /**
567 * Configuration files we have, array with @e num_peers entries.
568 */
569 char **cfg_files;
570
571 /**
572 * Array with @e num_peers entries.
573 */
574 struct GNUNET_TRANSPORT_TESTING_PeerContext **p;
575
576 /**
577 * Name of the plugin.
578 */
579 const char *test_plugin;
580
581 /**
582 * Name of the testcase.
583 */
584 const char *test_name;
585
586 /**
587 * Configuration object for the testcase.
588 */
589 const struct GNUNET_CONFIGURATION_Handle *cfg;
590
591 /**
592 * Main testing handle.
593 */
594 struct GNUNET_TRANSPORT_TESTING_Handle *tth;
595
596 /**
597 * Result from the main function, set to #GNUNET_OK on success.
598 * Clients should set to #GNUNET_SYSERR to indicate test failure.
599 */
600 int global_ret;
601
602 /**
603 * Generator for the `num` field in test messages. Incremented each
604 * time #GNUNET_TRANSPORT_TESTING_simple_send or
605 * #GNUNET_TRANSPORT_TESTING_large_send are used to transmit a
606 * message.
607 */
608 uint32_t send_num_gen;
609
610 /* ******* internal state, clients should not mess with this **** */
611
612 /**
613 * Task run on timeout.
614 */
615 struct GNUNET_SCHEDULER_Task *timeout_task;
616
617 /**
618 * Task run to connect peers.
619 */
620 struct GNUNET_SCHEDULER_Task *connect_task;
621
622 /**
623 * Number of peers that have been started.
624 */
625 unsigned int started;
626
627 /**
628 * DLL of active connect requests.
629 */
630 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *crl_head;
631
632 /**
633 * DLL of active connect requests.
634 */
635 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *crl_tail;
636
637 /**
638 * Array with @e num_peers entries.
639 */
640 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ip;
641};
642
643
644/**
645 * Find peer by peer ID.
646 *
647 * @param ccc context to search
648 * @param peer peer to look for
649 * @return NULL if @a peer was not found
650 */
651struct GNUNET_TRANSPORT_TESTING_PeerContext *
652GNUNET_TRANSPORT_TESTING_find_peer (
653 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc,
654 const struct GNUNET_PeerIdentity *peer);
655
656
657/**
658 * Common implementation of the #GNUNET_TRANSPORT_TESTING_CheckCallback.
659 * Starts and connects the two peers, then invokes the
660 * `connect_continuation` from @a cls. Sets up a timeout to
661 * abort the test, and a shutdown handler to clean up properly
662 * on exit.
663 *
664 * @param cls closure of type `struct
665 * GNUNET_TRANSPORT_TESTING_ConnectCheckContext`
666 * @param tth_ initialized testing handle
667 * @param test_plugin_ name of the plugin
668 * @param test_name_ name of the test
669 * @param num_peers number of entries in the @a cfg_file array
670 * @param cfg_files array of names of configuration files for the peers
671 * @return #GNUNET_SYSERR on error
672 */
673int
674GNUNET_TRANSPORT_TESTING_connect_check (
675 void *cls,
676 struct GNUNET_TRANSPORT_TESTING_Handle *tth_,
677 const char *test_plugin_,
678 const char *test_name_,
679 unsigned int num_peers,
680 char *cfg_files[]);
681
682
683/**
684 * Main function of a testcase. Called with the initial setup data
685 * for the test as derived from the source name and the binary name.
686 *
687 * @param cls closure
688 * @param tth_ initialized testing handle
689 * @param test_plugin_ name of the plugin
690 * @param test_name_ name of the test
691 * @param num_peers number of entries in the @a cfg_file array
692 * @param cfg_files array of names of configuration files for the peers
693 * @return #GNUNET_SYSERR on error
694 */
695typedef int (*GNUNET_TRANSPORT_TESTING_CheckCallback) (
696 void *cls,
697 struct GNUNET_TRANSPORT_TESTING_Handle *tth_,
698 const char *test_plugin_,
699 const char *test_name_,
700 unsigned int num_peers,
701 char *cfg_files[]);
702
703
704/**
705 * Setup testcase. Calls @a check with the data the test needs.
706 *
707 * @param argv0 binary name (argv[0])
708 * @param filename source file name (__FILE__)
709 * @param num_peers number of peers to start
710 * @param check main function to run
711 * @param check_cls closure for @a check
712 * @return #GNUNET_OK on success
713 */
714int
715GNUNET_TRANSPORT_TESTING_main_ (const char *argv0,
716 const char *filename,
717 unsigned int num_peers,
718 GNUNET_TRANSPORT_TESTING_CheckCallback check,
719 void *check_cls);
720
721
722/**
723 * Setup testcase. Calls @a check with the data the test needs.
724 *
725 * @param num_peers number of peers to start
726 * @param check main function to run
727 * @param check_cls closure for @a check
728 * @return #GNUNET_OK on success
729 */
730#define GNUNET_TRANSPORT_TESTING_main(num_peers, check, check_cls) \
731 GNUNET_TRANSPORT_TESTING_main_ (argv[0], \
732 __FILE__, \
733 num_peers, \
734 check, \
735 check_cls)
736
737/* ***************** Convenience functions for sending ********* */
738
739/**
740 * Send a test message of type @a mtype and size @a msize from
741 * peer @a sender to peer @a receiver. The peers should be
742 * connected when this function is called.
743 *
744 * @param sender the sending peer
745 * @param receiver the receiving peer
746 * @param mtype message type to use
747 * @param msize size of the message, at least `sizeof (struct
748 * GNUNET_TRANSPORT_TESTING_TestMessage)`
749 * @param num unique message number
750 * @param cont continuation to call after transmission
751 * @param cont_cls closure for @a cont
752 * @return #GNUNET_OK if message was queued,
753 * #GNUNET_NO if peers are not connected
754 * #GNUNET_SYSERR if @a msize is illegal
755 */
756int
757GNUNET_TRANSPORT_TESTING_send (
758 struct GNUNET_TRANSPORT_TESTING_PeerContext *sender,
759 struct GNUNET_TRANSPORT_TESTING_PeerContext *receiver,
760 uint16_t mtype,
761 uint16_t msize,
762 uint32_t num,
763 GNUNET_SCHEDULER_TaskCallback cont,
764 void *cont_cls);
765
766
767/**
768 * Message type used by #GNUNET_TRANSPORT_TESTING_simple_send().
769 */
770#define GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE 12345
771
772/**
773 * Alternative message type for tests.
774 */
775#define GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE2 12346
776
777
778/**
779 * Type of the closure argument to pass to
780 * #GNUNET_TRANSPORT_TESTING_simple_send() and
781 * #GNUNET_TRANSPORT_TESTING_large_send().
782 */
783struct GNUNET_TRANSPORT_TESTING_SendClosure
784{
785 /**
786 * Context for the transmission.
787 */
788 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
789
790 /**
791 * Function that returns the desired message size. Overrides
792 * the message size, can be NULL in which case the message
793 * size is the default.
794 */
795 size_t (*get_size_cb) (unsigned int n);
796
797 /**
798 * Number of messages to be transmitted in a loop.
799 * Use zero for "forever" (until external shutdown).
800 */
801 unsigned int num_messages;
802
803 /**
804 * Function to call after all transmissions, can be NULL.
805 */
806 GNUNET_SCHEDULER_TaskCallback cont;
807
808 /**
809 * Closure for @e cont.
810 */
811 void *cont_cls;
812};
813
814
815/**
816 * Task that sends a minimalistic test message from the
817 * first peer to the second peer.
818 *
819 * @param cls the `struct GNUNET_TRANSPORT_TESTING_SendClosure`
820 * which should contain at least two peers, the first two
821 * of which should be currently connected
822 */
823void
824GNUNET_TRANSPORT_TESTING_simple_send (void *cls);
825
826/**
827 * Size of a message sent with
828 * #GNUNET_TRANSPORT_TESTING_large_send(). Big enough
829 * to usually force defragmentation.
830 */
831#define GNUNET_TRANSPORT_TESTING_LARGE_MESSAGE_SIZE 2600
832
833/**
834 * Task that sends a large test message from the
835 * first peer to the second peer.
836 *
837 * @param cls the `struct GNUNET_TRANSPORT_TESTING_SendClosure`
838 * which should contain at least two peers, the first two
839 * of which should be currently connected
840 */
841void
842GNUNET_TRANSPORT_TESTING_large_send (void *cls);
843
844
845/* ********************** log-only convenience functions ************* */
846
847
848/**
849 * Log a connect event.
850 *
851 * @param cls NULL
852 * @param me peer that had the event
853 * @param other peer that connected.
854 */
855void
856GNUNET_TRANSPORT_TESTING_log_connect (
857 void *cls,
858 struct GNUNET_TRANSPORT_TESTING_PeerContext *me,
859 const struct GNUNET_PeerIdentity *other);
860
861
862/**
863 * Log a disconnect event.
864 *
865 * @param cls NULL
866 * @param me peer that had the event
867 * @param other peer that disconnected.
868 */
869void
870GNUNET_TRANSPORT_TESTING_log_disconnect (
871 void *cls,
872 struct GNUNET_TRANSPORT_TESTING_PeerContext *me,
873 const struct GNUNET_PeerIdentity *other);
874
875
876/* ********************** low-level filename functions *************** */
877
878
879/**
880 * Extracts the test filename from an absolute file name and removes
881 * the extension.
882 *
883 * @param file absolute file name
884 * @return resulting test name
885 */
886char *
887GNUNET_TRANSPORT_TESTING_get_test_name (const char *file);
888
889
890/**
891 * This function takes the filename (e.g. argv[0), removes a "lt-"-prefix and
892 * if existing ".exe"-prefix and adds the peer-number
893 *
894 * @param file filename of the test, e.g. argv[0]
895 * @param count peer number
896 * @return configuration name to use
897 */
898char *
899GNUNET_TRANSPORT_TESTING_get_config_name (const char *file, int count);
900
901
902/**
903 * Extracts the plugin anme from an absolute file name and the test name
904 * @param file absolute file name
905 * @param test test name
906 * @return the plugin name
907 */
908char *
909GNUNET_TRANSPORT_TESTING_get_test_plugin_name (const char *executable,
910 const char *testname);
911
912
913/**
914 * Extracts the filename from an absolute file name and removes the
915 * extension
916 *
917 * @param file absolute file name
918 * @return the source name
919 */
920char *
921GNUNET_TRANSPORT_TESTING_get_test_source_name (const char *file);
922
923#endif
924/* end of transport_testing.h */
diff --git a/src/transport/transport.conf.in b/src/transport/transport.conf.in
deleted file mode 100644
index c6b207ad7..000000000
--- a/src/transport/transport.conf.in
+++ /dev/null
@@ -1,237 +0,0 @@
1[transport]
2START_ON_DEMAND = @START_ON_DEMAND@
3@JAVAPORT@PORT = 2091
4HOSTNAME = localhost
5BINARY = gnunet-service-transport
6# PREFIX = valgrind
7
8# Maximum number of neighbours PER PLUGIN (not in total).
9NEIGHBOUR_LIMIT = 50
10ACCEPT_FROM = 127.0.0.1;
11ACCEPT_FROM6 = ::1;
12# TCP is the only transport plugin known to work "reliably"
13PLUGINS = tcp
14UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-transport.sock
15BLACKLIST_FILE = $GNUNET_CONFIG_HOME/transport/blacklist
16UNIX_MATCH_UID = NO
17UNIX_MATCH_GID = YES
18# DISABLE_SOCKET_FORWARDING = NO
19# USERNAME =
20# MAXBUF =
21# TIMEOUT =
22# DISABLEV6 =
23# BINDTO =
24# REJECT_FROM =
25# REJECT_FROM6 =
26# PREFIX = valgrind --leak-check=full
27
28# Configuration settings related to traffic manipulation for testing purposes
29# Distance
30# MANIPULATE_DISTANCE_IN = 1
31# MANIPULATE_DISTANCE_OUT = 1
32# Delay; WARNING: to large values may lead to peers not connecting!
33# MANIPULATE_DELAY_IN = 1 ms
34# MANIPULATE_DELAY_OUT = 1 ms
35
36
37[transport-unix]
38UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-transport-plugin-unix.sock
39TESTING_IGNORE_KEYS = ACCEPT_FROM;
40
41[transport-tcp]
42# Use 0 to ONLY advertise as a peer behind NAT (no port binding)
43PORT = 2086
44
45# Obsolete option, to be replaced by HOLE_EXTERNAL (soon)
46ADVERTISED_PORT = 2086
47
48# If we have a manually punched NAT, what is the external IP and port?
49# Can use DNS names for DynDNS-based detection of external IP.
50# Can use IPv6 addresses ([fefc::]:PORT).
51# Use "AUTO" for the hostname to automatically detect external IP.
52# Do not set if NAT is not manually punched.
53# HOLE_EXTERNAL = AUTO:2086
54
55TESTING_IGNORE_KEYS = ACCEPT_FROM;
56
57# Maximum number of open TCP connections allowed
58MAX_CONNECTIONS = 128
59
60TIMEOUT = 5 s
61# ACCEPT_FROM =
62# ACCEPT_FROM6 =
63# REJECT_FROM =
64# REJECT_FROM6 =
65# BINDTO =
66MAX_CONNECTIONS = 128
67
68# Enable TCP stealth?
69TCP_STEALTH = NO
70
71
72
73[transport-xt]
74# Use 0 to ONLY advertise as a peer behind NAT (no port binding)
75PORT = 2087
76
77# Obsolete option, to be replaced by HOLE_EXTERNAL (soon)
78ADVERTISED_PORT = 2087
79
80# If we have a manually punched NAT, what is the external IP and port?
81# Can use DNS names for DynDNS-based detection of external IP.
82# Can use IPv6 addresses ([fefc::]:PORT).
83# Use "AUTO" for the hostname to automatically detect external IP.
84# Do not set if NAT is not manually punched.
85# HOLE_EXTERNAL = AUTO:2087
86
87TESTING_IGNORE_KEYS = ACCEPT_FROM;
88
89# Maximum number of open TCP connections allowed
90MAX_CONNECTIONS = 128
91
92TIMEOUT = 5 s
93# ACCEPT_FROM =
94# ACCEPT_FROM6 =
95# REJECT_FROM =
96# REJECT_FROM6 =
97# BINDTO =
98MAX_CONNECTIONS = 128
99
100# Enable TCP stealth?
101TCP_STEALTH = NO
102
103
104[transport-udp]
105# Use PORT = 0 to autodetect a port available
106PORT = 2086
107BROADCAST = YES
108BROADCAST_RECEIVE = YES
109BROADCAST_INTERVAL = 30 s
110
111# This limits UDP to 1MB/s for SENDING. Higher values are advised
112# for benchmarking or well-connected systems. Note that this quota
113# applies IN ADDITION to the system-wide transport-wide WAN/LAN
114# quotas.
115MAX_BPS = 1000000
116TESTING_IGNORE_KEYS = ACCEPT_FROM;
117
118# If we have a manually punched NAT, what is the external IP and port?
119# Can use DNS names for DynDNS-based detection of external IP.
120# Can use IPv6 addresses ([fefc::]:PORT).
121# Use "AUTO" for the hostname to automatically detect external IP.
122# Do not set if NAT is not manually punched.
123# HOLE_EXTERNAL = AUTO:2086
124
125
126[transport-xu]
127# Use PORT = 0 to autodetect a port available
128PORT = 2087
129
130
131[transport-http_client]
132MAX_CONNECTIONS = 128
133TESTING_IGNORE_KEYS = ACCEPT_FROM;
134# Hostname or IP of proxy server
135# PROXY =
136
137# User name for proxy server
138# PROXY_USERNAME =
139# User password for proxy server
140# PROXY_PASSWORD =
141
142# Type of proxy server,
143# Valid values: HTTP, SOCKS4, SOCKS5, SOCKS4A, SOCKS5_HOSTNAME
144# Default: HTTP
145# PROXY_TYPE = HTTP
146
147# Enable tunneling proxy request instead of having proxy server evaluate it
148# Experimental, default: NO
149# PROXY_HTTP_TUNNELING = NO
150
151
152[transport-http_server]
153#EXTERNAL_HOSTNAME = <your hostname/path>
154PORT = 1080
155
156# Obsolete option, to be replaced by HOLE_EXTERNAL (soon)
157ADVERTISED_PORT = 1080
158
159# If we have a manually punched NAT, what is the external IP and port?
160# Can use DNS names for DynDNS-based detection of external IP.
161# Can use IPv6 addresses ([fefc::]:PORT).
162# Use "AUTO" for the hostname to automatically detect external IP.
163# Do not set if NAT is not manually punched.
164# HOLE_EXTERNAL = AUTO:1080
165
166MAX_CONNECTIONS = 128
167TESTING_IGNORE_KEYS = ACCEPT_FROM;
168
169# Enable TCP stealth?
170TCP_STEALTH = NO
171
172
173[transport-https_client]
174MAX_CONNECTIONS = 128
175TESTING_IGNORE_KEYS = ACCEPT_FROM;
176# Hostname or IP of proxy server
177# PROXY =
178
179# User name for proxy server
180# PROXY_USERNAME =
181# User password for proxy server
182# PROXY_PASSWORD =
183
184# Type of proxy server,
185# Valid values: HTTP, SOCKS4, SOCKS5, SOCKS4A, SOCKS5_HOSTNAME
186# Default: HTTP
187# PROXY_TYPE = HTTP
188
189# Enable tunneling proxy request instead of having proxy server evaluate it
190# Experimental, default: NO
191# PROXY_HTTP_TUNNELING = NO
192
193
194[transport-https_server]
195# EXTERNAL_HOSTNAME = <your hostname/path>
196# EXTERNAL_HOSTNAME_ONLY = YES
197# If you have a valid SSL certificate for your external hostname tell,
198# clients to verify it
199# VERIFY_EXTERNAL_HOSTNAME = YES
200# Does the external hostname use the same port?
201# EXTERNAL_HOSTNAME_USE_PORT = YES
202PORT = 4433
203
204# Obsolete option, to be replaced by HOLE_EXTERNAL (soon)
205ADVERTISED_PORT = 4433
206
207# If we have a manually punched NAT, what is the external IP and port?
208# Can use DNS names for DynDNS-based detection of external IP.
209# Can use IPv6 addresses ([fefc::]:PORT).
210# Use "AUTO" for the hostname to automatically detect external IP.
211# Do not set if NAT is not manually punched.
212# HOLE_EXTERNAL = AUTO:4433
213
214CRYPTO_INIT = NORMAL
215KEY_FILE = $GNUNET_DATA_HOME/transport/https.key
216CERT_FILE = $GNUNET_DATA_HOME/transport/https.cert
217MAX_CONNECTIONS = 128
218TESTING_IGNORE_KEYS = ACCEPT_FROM;
219
220# Enable TCP stealth?
221TCP_STEALTH = NO
222
223
224[transport-wlan]
225# Name of the interface in monitor mode (typically monX)
226INTERFACE = mon0
227# Real hardware, no testing
228TESTMODE = 0
229TESTING_IGNORE_KEYS = ACCEPT_FROM;
230
231
232[transport-bluetooth]
233# Name of the interface (typically hciX)
234INTERFACE = hci0
235# Real hardware, no testing
236TESTMODE = 0
237TESTING_IGNORE_KEYS = ACCEPT_FROM;
diff --git a/src/transport/transport.h b/src/transport/transport.h
deleted file mode 100644
index 8ffc87070..000000000
--- a/src/transport/transport.h
+++ /dev/null
@@ -1,1241 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-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/transport.h
23 * @brief common internal definitions for transport service
24 * @author Christian Grothoff
25 */
26#ifndef TRANSPORT_H
27#define TRANSPORT_H
28
29#include "gnunet_crypto_lib.h"
30#include "gnunet_time_lib.h"
31#include "gnunet_constants.h"
32
33#define DEBUG_TRANSPORT GNUNET_EXTRA_LOGGING
34
35
36/**
37 * For how long do we allow unused bandwidth
38 * from the past to carry over into the future? (in seconds)
39 */
40#define MAX_BANDWIDTH_CARRY_S GNUNET_CONSTANTS_MAX_BANDWIDTH_CARRY_S
41
42/**
43 * How often do we (at most) do a full quota
44 * recalculation? (in ms)
45 */
46#define MIN_QUOTA_REFRESH_TIME 2000
47
48/**
49 * What's the maximum number of sockets transport uses for validation and
50 * neighbors
51 */
52#define DEFAULT_MAX_FDS 256
53
54/**
55 * Maximum frequency for re-evaluating latencies for all transport addresses.
56 */
57#define LATENCY_EVALUATION_MAX_DELAY \
58 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
59
60/**
61 * Maximum frequency for re-evaluating latencies for connected addresses.
62 */
63#define CONNECTED_LATENCY_EVALUATION_MAX_DELAY \
64 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
65
66/**
67 * Similar to GNUNET_TRANSPORT_NotifyDisconnect but in and out quotas are
68 * included here. These values are not required outside transport_api
69 *
70 * @param cls closure
71 * @param peer the peer that connected
72 * @param bandwidth_in inbound bandwidth in NBO
73 * @param bandwidth_out outbound bandwidth in NBO
74 *
75 */
76typedef void (*NotifyConnect) (
77 void *cls,
78 const struct GNUNET_PeerIdentity *peer,
79 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
80 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out);
81
82
83GNUNET_NETWORK_STRUCT_BEGIN
84
85
86/**
87 * Message from the transport service to the library
88 * asking to check if both processes agree about this
89 * peers identity.
90 */
91struct StartMessage
92{
93 /**
94 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_START
95 */
96 struct GNUNET_MessageHeader header;
97
98 /**
99 * 0: no options
100 * 1: The @e self field should be checked
101 * 2: this client is interested in payload traffic
102 */
103 uint32_t options;
104
105 /**
106 * Identity we think we have. If it does not match, the
107 * receiver should print out an error message and disconnect.
108 */
109 struct GNUNET_PeerIdentity self;
110};
111
112
113/**
114 * Message from the transport service to the library
115 * informing about neighbors.
116 */
117struct ConnectInfoMessage
118{
119 /**
120 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT
121 */
122 struct GNUNET_MessageHeader header;
123
124#if (defined(GNUNET_TRANSPORT_COMMUNICATION_VERSION) || \
125 defined(GNUNET_TRANSPORT_CORE_VERSION))
126
127 /**
128 * Always zero, for alignment.
129 */
130 uint32_t reserved GNUNET_PACKED;
131#else
132 /**
133 * Current outbound quota for this peer
134 */
135 struct GNUNET_BANDWIDTH_Value32NBO quota_out;
136#endif
137
138 /**
139 * Identity of the new neighbour.
140 */
141 struct GNUNET_PeerIdentity id;
142};
143
144
145/**
146 * Message from the transport service to the library
147 * informing about disconnects.
148 */
149struct DisconnectInfoMessage
150{
151 /**
152 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT
153 */
154 struct GNUNET_MessageHeader header;
155
156 /**
157 * Reserved, always zero.
158 */
159 uint32_t reserved GNUNET_PACKED;
160
161 /**
162 * Who got disconnected?
163 */
164 struct GNUNET_PeerIdentity peer;
165};
166
167
168/**
169 * Message used to set a particular bandwidth quota. Sent TO the
170 * service to set an incoming quota, sent FROM the service to update
171 * an outgoing quota.
172 *
173 * NOTE: no longer used in TNG!
174 */
175struct QuotaSetMessage
176{
177 /**
178 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA
179 */
180 struct GNUNET_MessageHeader header;
181
182 /**
183 * Quota.
184 */
185 struct GNUNET_BANDWIDTH_Value32NBO quota;
186
187 /**
188 * About which peer are we talking here?
189 */
190 struct GNUNET_PeerIdentity peer;
191};
192
193
194/**
195 * Message used to notify the transport API about a message
196 * received from the network. The actual message follows.
197 */
198struct InboundMessage
199{
200 /**
201 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_RECV
202 */
203 struct GNUNET_MessageHeader header;
204
205 /**
206 * Which peer sent the message?
207 */
208 struct GNUNET_PeerIdentity peer;
209};
210
211
212/**
213 * Message used to notify the transport API that it can
214 * send another message to the transport service.
215 */
216struct SendOkMessage
217{
218 /**
219 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK
220 */
221 struct GNUNET_MessageHeader header;
222
223#if (defined(GNUNET_TRANSPORT_COMMUNICATION_VERSION) || \
224 defined(GNUNET_TRANSPORT_CORE_VERSION))
225
226 uint32_t reserved GNUNET_PACKED;
227#else
228 /**
229 * #GNUNET_OK if the transmission succeeded,
230 * #GNUNET_SYSERR if it failed (i.e. network disconnect);
231 * in either case, it is now OK for this client to
232 * send us another message for the given peer.
233 */
234 uint16_t success GNUNET_PACKED;
235
236 /**
237 * Size of message sent
238 */
239 uint16_t bytes_msg GNUNET_PACKED;
240
241 /**
242 * Size of message sent over wire.
243 * Includes plugin and protocol specific overheads.
244 */
245 uint32_t bytes_physical GNUNET_PACKED;
246#endif
247
248 /**
249 * Which peer can send more now?
250 */
251 struct GNUNET_PeerIdentity peer;
252};
253
254
255/**
256 * Message used to notify the transport API that it can
257 * send another message to the transport service.
258 * (Used to implement flow control.)
259 */
260struct RecvOkMessage
261{
262 /**
263 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_RECV_OK
264 */
265 struct GNUNET_MessageHeader header;
266
267 /**
268 * Number of messages by which to increase the window, greater or
269 * equal to one.
270 */
271 uint32_t increase_window_delta GNUNET_PACKED;
272
273 /**
274 * Which peer can CORE handle more from now?
275 */
276 struct GNUNET_PeerIdentity peer;
277};
278
279
280/**
281 * Message used to notify the transport service about a message
282 * to be transmitted to another peer. The actual message follows.
283 */
284struct OutboundMessage
285{
286 /**
287 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_SEND
288 */
289 struct GNUNET_MessageHeader header;
290
291 /**
292 * An `enum GNUNET_MQ_PriorityPreferences` in NBO.
293 */
294 uint32_t priority GNUNET_PACKED;
295
296#if ! (defined(GNUNET_TRANSPORT_COMMUNICATION_VERSION) || \
297 defined(GNUNET_TRANSPORT_CORE_VERSION))
298
299 /**
300 * Allowed delay.
301 */
302 struct GNUNET_TIME_RelativeNBO timeout;
303#endif
304
305 /**
306 * Which peer should receive the message?
307 */
308 struct GNUNET_PeerIdentity peer;
309};
310
311
312#if ! (defined(GNUNET_TRANSPORT_COMMUNICATION_VERSION) || \
313 defined(GNUNET_TRANSPORT_CORE_VERSION))
314
315
316/**
317 * Message used to notify the transport API about an address to string
318 * conversion. Message is followed by the string with the humand-readable
319 * address. For each lookup, multiple results may be returned. The
320 * last message must have a @e res of #GNUNET_OK and an @e addr_len
321 * of zero.
322 */
323struct AddressToStringResultMessage
324{
325 /**
326 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY
327 */
328 struct GNUNET_MessageHeader header;
329
330 /**
331 * #GNUNET_OK if the conversion succeeded,
332 * #GNUNET_SYSERR if it failed
333 */
334 uint32_t res GNUNET_PACKED;
335
336 /**
337 * Length of the following string, zero if @e is #GNUNET_SYSERR
338 */
339 uint32_t addr_len GNUNET_PACKED;
340};
341
342
343/**
344 * Message from the library to the transport service
345 * asking for converting a transport address to a
346 * human-readable UTF-8 string.
347 */
348struct AddressLookupMessage
349{
350 /**
351 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING
352 */
353 struct GNUNET_MessageHeader header;
354
355 /**
356 * Should the conversion use numeric IP addresses (otherwise
357 * a reverse DNS lookup is OK -- if applicable).
358 */
359 int16_t numeric_only GNUNET_PACKED;
360
361 /**
362 * Length of the (binary) address in bytes, in big-endian.
363 */
364 uint16_t addrlen GNUNET_PACKED;
365
366 /**
367 * timeout to give up (for DNS resolution timeout mostly)
368 */
369 struct GNUNET_TIME_RelativeNBO timeout;
370
371 /* followed by @e addrlen bytes of the actual address, then
372 * followed by the 0-terminated name of the transport */
373};
374
375
376/**
377 * Message from the transport service to the library containing information
378 * about a peer. Information contained are:
379 * - current address used to communicate with this peer
380 * - state
381 * - state timeout
382 *
383 * Memory layout:
384 * [AddressIterateResponseMessage][address[addrlen]][transportname[pluginlen]]
385 */
386struct ValidationIterateResponseMessage
387{
388 /**
389 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_VALIDATION_RESPONSE
390 */
391 struct GNUNET_MessageHeader header;
392
393 /**
394 * For alignment.
395 */
396 uint32_t reserved;
397
398 /**
399 * Peer identity
400 */
401 struct GNUNET_PeerIdentity peer;
402
403 /**
404 * Local info about the address
405 */
406 uint32_t local_address_info GNUNET_PACKED;
407
408 /**
409 * Address length
410 */
411 uint32_t addrlen GNUNET_PACKED;
412
413 /**
414 * Length of the plugin name
415 */
416 uint32_t pluginlen GNUNET_PACKED;
417
418 /**
419 * State
420 */
421 uint32_t state GNUNET_PACKED;
422
423 /**
424 * At what time did we successfully validate the address last.
425 * Will be NEVER if the address failed validation.
426 */
427 struct GNUNET_TIME_AbsoluteNBO last_validation;
428
429 /**
430 * Until when is the address believed to be valid.
431 * Will be ZERO if the address is not believed to be valid.
432 */
433 struct GNUNET_TIME_AbsoluteNBO valid_until;
434
435 /**
436 * When will we next try to validate the address (typically
437 * done before @e valid_until happens).
438 */
439 struct GNUNET_TIME_AbsoluteNBO next_validation;
440};
441
442
443/**
444 * Message from the library to the transport service
445 * asking for binary addresses known for a peer.
446 */
447struct ValidationMonitorMessage
448{
449 /**
450 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_VALIDATION_REQUEST
451 */
452 struct GNUNET_MessageHeader header;
453
454 /**
455 * One shot call or continuous replies?
456 */
457 uint32_t one_shot GNUNET_PACKED;
458
459 /**
460 * The identity of the peer to look up.
461 */
462 struct GNUNET_PeerIdentity peer;
463};
464
465
466/**
467 * Message from the library to the transport service
468 * asking for binary addresses known for a peer.
469 */
470struct PeerMonitorMessage
471{
472 /**
473 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_REQUEST
474 */
475 struct GNUNET_MessageHeader header;
476
477 /**
478 * One shot call or continuous replies?
479 */
480 uint32_t one_shot GNUNET_PACKED;
481
482 /**
483 * The identity of the peer to look up.
484 */
485 struct GNUNET_PeerIdentity peer;
486};
487
488
489/**
490 * Message from the library to the transport service
491 * asking for binary addresses known for a peer.
492 */
493struct TrafficMetricMessage
494{
495 /**
496 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_TRAFFIC_METRIC
497 */
498 struct GNUNET_MessageHeader header;
499
500 /**
501 * Always zero.
502 */
503 uint32_t reserved GNUNET_PACKED;
504
505 /**
506 * The identity of the peer to look up.
507 */
508 struct GNUNET_PeerIdentity peer;
509
510 /**
511 * Fake properties to generate.
512 */
513 struct GNUNET_ATS_PropertiesNBO properties;
514
515 /**
516 * Fake delay to add on inbound traffic.
517 */
518 struct GNUNET_TIME_RelativeNBO delay_in;
519
520 /**
521 * Fake delay to add on outbound traffic.
522 */
523 struct GNUNET_TIME_RelativeNBO delay_out;
524};
525
526
527/**
528 * Message from the transport service to the library containing information
529 * about a peer. Information contained are:
530 * - current address used to communicate with this peer
531 * - state
532 * - state timeout
533 *
534 * Memory layout:
535 * [AddressIterateResponseMessage][address[addrlen]][transportname[pluginlen]]
536 */
537struct PeerIterateResponseMessage
538{
539 /**
540 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_RESPONSE
541 */
542 struct GNUNET_MessageHeader header;
543
544 /**
545 * For alignment.
546 */
547 uint32_t reserved;
548
549 /**
550 * Peer identity
551 */
552 struct GNUNET_PeerIdentity peer;
553
554 /**
555 * Timeout for the state this peer is in
556 */
557 struct GNUNET_TIME_AbsoluteNBO state_timeout;
558
559 /**
560 * Local info about the address
561 */
562 uint32_t local_address_info GNUNET_PACKED;
563
564 /**
565 * State this peer is in as an `enum GNUNET_TRANSPORT_PeerState`
566 */
567 uint32_t state GNUNET_PACKED;
568
569 /**
570 * Address length
571 */
572 uint32_t addrlen GNUNET_PACKED;
573
574 /**
575 * Length of the plugin name
576 */
577 uint32_t pluginlen GNUNET_PACKED;
578};
579
580
581/**
582 * Change in blacklisting (either request or notification,
583 * depending on which direction it is going).
584 */
585struct BlacklistMessage
586{
587 /**
588 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY or
589 * #GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY.
590 */
591 struct GNUNET_MessageHeader header;
592
593 /**
594 * 0 for the query, #GNUNET_OK (allowed) or #GNUNET_SYSERR (disallowed)
595 * for the response.
596 */
597 uint32_t is_allowed GNUNET_PACKED;
598
599 /**
600 * Which peer is being blacklisted or queried?
601 */
602 struct GNUNET_PeerIdentity peer;
603};
604
605
606/**
607 * Transport-level connection status update.
608 */
609struct TransportPluginMonitorMessage
610{
611 /**
612 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PLUGIN_EVENT.
613 */
614 struct GNUNET_MessageHeader header;
615
616 /**
617 * An `enum GNUNET_TRANSPORT_SessionState` in NBO.
618 */
619 uint16_t session_state GNUNET_PACKED;
620
621 /**
622 * #GNUNET_YES if this is an inbound connection,
623 * #GNUNET_NO if this is an outbound connection,
624 * #GNUNET_SYSERR if connections of this plugin
625 * are so fundamentally bidirectional
626 * that they have no 'initiator'
627 * Value given in NBO.
628 */
629 int16_t is_inbound GNUNET_PACKED;
630
631 /**
632 * Number of messages waiting transmission.
633 */
634 uint32_t msgs_pending GNUNET_PACKED;
635
636 /**
637 * Number of bytes waiting for transmission.
638 */
639 uint32_t bytes_pending GNUNET_PACKED;
640
641 /**
642 * When will this transport plugin session time out?
643 */
644 struct GNUNET_TIME_AbsoluteNBO timeout;
645
646 /**
647 * Until how long is this plugin currently blocked from reading?
648 */
649 struct GNUNET_TIME_AbsoluteNBO delay;
650
651 /**
652 * Which peer is this connection for?
653 */
654 struct GNUNET_PeerIdentity peer;
655
656 /**
657 * Unique identifier for the session.
658 */
659 uint64_t session_id;
660
661 /**
662 * Length of the plugin name in bytes, including 0-termination.
663 */
664 uint16_t plugin_name_len GNUNET_PACKED;
665
666 /**
667 * Length of the plugin address in bytes.
668 */
669 uint16_t plugin_address_len GNUNET_PACKED;
670
671 /* followed by 0-terminated plugin name and
672 @e plugin_address_len bytes of plugin address */
673};
674
675#else
676
677/* *********************** TNG messages ***************** */
678
679/**
680 * Communicator goes online. Note which addresses it can
681 * work with.
682 */
683struct GNUNET_TRANSPORT_CommunicatorAvailableMessage
684{
685 /**
686 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_NEW_COMMUNICATOR.
687 */
688 struct GNUNET_MessageHeader header;
689
690 /**
691 * NBO encoding of `enum GNUNET_TRANSPORT_CommunicatorCharacteristics`
692 */
693 uint32_t cc;
694
695 /* Followed by the address prefix of the communicator */
696};
697
698
699/**
700 * Add address to the list.
701 */
702struct GNUNET_TRANSPORT_AddAddressMessage
703{
704 /**
705 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS.
706 */
707 struct GNUNET_MessageHeader header;
708
709 /**
710 * Address identifier (used during deletion).
711 */
712 uint32_t aid GNUNET_PACKED;
713
714 /**
715 * When does the address expire?
716 */
717 struct GNUNET_TIME_RelativeNBO expiration;
718
719 /**
720 * An `enum GNUNET_NetworkType` in NBO.
721 */
722 uint32_t nt;
723
724 /* followed by UTF-8 encoded, 0-terminated human-readable address */
725};
726
727
728/**
729 * Remove address from the list.
730 */
731struct GNUNET_TRANSPORT_DelAddressMessage
732{
733 /**
734 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_DEL_ADDRESS.
735 */
736 struct GNUNET_MessageHeader header;
737
738 /**
739 * Address identifier.
740 */
741 uint32_t aid GNUNET_PACKED;
742};
743
744
745/**
746 * Inform transport about an incoming message.
747 */
748struct GNUNET_TRANSPORT_IncomingMessage
749{
750 /**
751 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG.
752 */
753 struct GNUNET_MessageHeader header;
754
755 /**
756 * Do we use flow control or not?
757 */
758 uint32_t fc_on GNUNET_PACKED;
759
760 /**
761 * 64-bit number to identify the matching ACK.
762 */
763 uint64_t fc_id GNUNET_PACKED;
764
765 /**
766 * How long does the communicator believe the address on which
767 * the message was received to remain valid?
768 */
769 struct GNUNET_TIME_RelativeNBO expected_address_validity;
770
771 /**
772 * Sender identifier.
773 */
774 struct GNUNET_PeerIdentity sender;
775
776 /* followed by the message */
777};
778
779
780/**
781 * Transport informs us about being done with an incoming message.
782 * (only sent if fc_on was set).
783 */
784struct GNUNET_TRANSPORT_IncomingMessageAck
785{
786 /**
787 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG_ACK.
788 */
789 struct GNUNET_MessageHeader header;
790
791 /**
792 * Reserved (0)
793 */
794 uint32_t reserved GNUNET_PACKED;
795
796 /**
797 * Which message is being ACKed?
798 */
799 uint64_t fc_id GNUNET_PACKED;
800
801 /**
802 * Sender identifier of the original message.
803 */
804 struct GNUNET_PeerIdentity sender;
805};
806
807
808/**
809 * Add queue to the transport
810 */
811struct GNUNET_TRANSPORT_AddQueueMessage
812{
813 /**
814 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP.
815 */
816 struct GNUNET_MessageHeader header;
817
818 /**
819 * Queue identifier (used to identify the queue).
820 */
821 uint32_t qid GNUNET_PACKED;
822
823 /**
824 * Receiver that can be addressed via the queue.
825 */
826 struct GNUNET_PeerIdentity receiver;
827
828 /**
829 * An `enum GNUNET_NetworkType` in NBO.
830 */
831 uint32_t nt;
832
833 /**
834 * Maximum transmission unit, in NBO. UINT32_MAX for unlimited.
835 */
836 uint32_t mtu;
837
838 /**
839 * Queue length, in NBO. Defines how many messages may be
840 * send through this queue. UINT64_MAX for unlimited.
841 */
842 uint64_t q_len;
843
844 /**
845 * Priority of the queue in relation to other queues.
846 */
847 uint32_t priority;
848
849 /**
850 * An `enum GNUNET_TRANSPORT_ConnectionStatus` in NBO.
851 */
852 uint32_t cs;
853
854 /* followed by UTF-8 encoded, 0-terminated human-readable address */
855};
856
857
858/**
859 * Update queue
860 */
861struct GNUNET_TRANSPORT_UpdateQueueMessage
862{
863 /**
864 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP.
865 */
866 struct GNUNET_MessageHeader header;
867
868 /**
869 * Queue identifier (used to identify the queue).
870 */
871 uint32_t qid GNUNET_PACKED;
872
873 /**
874 * Receiver that can be addressed via the queue.
875 */
876 struct GNUNET_PeerIdentity receiver;
877
878 /**
879 * An `enum GNUNET_NetworkType` in NBO.
880 */
881 uint32_t nt;
882
883 /**
884 * Maximum transmission unit, in NBO. UINT32_MAX for unlimited.
885 */
886 uint32_t mtu;
887
888 /**
889 * Queue length, in NBO. Defines how many messages may be
890 * send through this queue. UINT64_MAX for unlimited.
891 */
892 uint64_t q_len;
893
894 /**
895 * Priority of the queue in relation to other queues.
896 */
897 uint32_t priority;
898
899 /**
900 * An `enum GNUNET_TRANSPORT_ConnectionStatus` in NBO.
901 */
902 uint32_t cs;
903};
904
905
906/**
907 * Remove queue, it is no longer available.
908 */
909struct GNUNET_TRANSPORT_DelQueueMessage
910{
911 /**
912 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN.
913 */
914 struct GNUNET_MessageHeader header;
915
916 /**
917 * Address identifier.
918 */
919 uint32_t qid GNUNET_PACKED;
920
921 /**
922 * Receiver that can be addressed via the queue.
923 */
924 struct GNUNET_PeerIdentity receiver;
925};
926
927
928/**
929 * Transport tells communicator that it wants a new queue.
930 */
931struct GNUNET_TRANSPORT_CreateQueue
932{
933 /**
934 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE.
935 */
936 struct GNUNET_MessageHeader header;
937
938 /**
939 * Unique ID for the request.
940 */
941 uint32_t request_id GNUNET_PACKED;
942
943 /**
944 * Receiver that can be addressed via the queue.
945 */
946 struct GNUNET_PeerIdentity receiver;
947
948 /* followed by UTF-8 encoded, 0-terminated human-readable address */
949};
950
951
952/**
953 * Communicator tells transport how queue creation went down.
954 */
955struct GNUNET_TRANSPORT_CreateQueueResponse
956{
957 /**
958 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_OK or
959 * #GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL.
960 */
961 struct GNUNET_MessageHeader header;
962
963 /**
964 * Unique ID for the request.
965 */
966 uint32_t request_id GNUNET_PACKED;
967};
968
969
970/**
971 * Inform communicator about transport's desire to send a message.
972 */
973struct GNUNET_TRANSPORT_SendMessageTo
974{
975 /**
976 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG.
977 */
978 struct GNUNET_MessageHeader header;
979
980 /**
981 * Which queue should we use?
982 */
983 uint32_t qid GNUNET_PACKED;
984
985 /**
986 * Message ID, used for flow control.
987 */
988 uint64_t mid GNUNET_PACKED;
989
990 /**
991 * Receiver identifier.
992 */
993 struct GNUNET_PeerIdentity receiver;
994
995 /* followed by the message */
996};
997
998
999/**
1000 * Inform transport that message was sent.
1001 */
1002struct GNUNET_TRANSPORT_SendMessageToAck
1003{
1004 /**
1005 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG_ACK.
1006 */
1007 struct GNUNET_MessageHeader header;
1008
1009 /**
1010 * Success (#GNUNET_OK), failure (#GNUNET_SYSERR).
1011 */
1012 uint32_t status GNUNET_PACKED;
1013
1014 /**
1015 * Message ID of the original message.
1016 */
1017 uint64_t mid GNUNET_PACKED;
1018
1019 /**
1020 * Receiver identifier.
1021 */
1022 struct GNUNET_PeerIdentity receiver;
1023};
1024
1025
1026/**
1027 * Message from communicator to transport service asking for
1028 * transmission of a backchannel message with the given peer @e pid
1029 * and communicator.
1030 */
1031struct GNUNET_TRANSPORT_CommunicatorBackchannel
1032{
1033 /**
1034 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL
1035 */
1036 struct GNUNET_MessageHeader header;
1037
1038 /**
1039 * Always zero, for alignment.
1040 */
1041 uint32_t reserved;
1042
1043 /**
1044 * Target peer.
1045 */
1046 struct GNUNET_PeerIdentity pid;
1047
1048 /* Followed by a `struct GNUNET_MessageHeader` with the encapsulated
1049 message to the communicator */
1050
1051 /* Followed by the 0-terminated string specifying the desired
1052 communicator at the target (@e pid) peer */
1053};
1054
1055
1056/**
1057 * Message from transport to communicator passing along a backchannel
1058 * message from the given peer @e pid.
1059 */
1060struct GNUNET_TRANSPORT_CommunicatorBackchannelIncoming
1061{
1062 /**
1063 * Type will be
1064 * #GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL_INCOMING
1065 */
1066 struct GNUNET_MessageHeader header;
1067
1068 /**
1069 * Always zero, for alignment.
1070 */
1071 uint32_t reserved;
1072
1073 /**
1074 * Origin peer.
1075 */
1076 struct GNUNET_PeerIdentity pid;
1077
1078 /* Followed by a `struct GNUNET_MessageHeader` with the encapsulated
1079 message to the communicator */
1080};
1081
1082
1083/**
1084 * Request to start monitoring.
1085 */
1086struct GNUNET_TRANSPORT_MonitorStart
1087{
1088 /**
1089 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_START.
1090 */
1091 struct GNUNET_MessageHeader header;
1092
1093 /**
1094 * #GNUNET_YES for one-shot montoring, #GNUNET_NO for continuous monitoring.
1095 */
1096 uint32_t one_shot;
1097
1098 /**
1099 * Target identifier to monitor, all zeros for "all peers".
1100 */
1101 struct GNUNET_PeerIdentity peer;
1102};
1103
1104
1105/**
1106 * Monitoring data.
1107 */
1108struct GNUNET_TRANSPORT_MonitorData
1109{
1110 /**
1111 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_DATA.
1112 */
1113 struct GNUNET_MessageHeader header;
1114
1115 /**
1116 * Network type (an `enum GNUNET_NetworkType` in NBO).
1117 */
1118 uint32_t nt GNUNET_PACKED;
1119
1120 /**
1121 * Target identifier.
1122 */
1123 struct GNUNET_PeerIdentity peer;
1124
1125 /**
1126 * @deprecated To be discussed if we keep these...
1127 */
1128 struct GNUNET_TIME_AbsoluteNBO last_validation;
1129 struct GNUNET_TIME_AbsoluteNBO valid_until;
1130 struct GNUNET_TIME_AbsoluteNBO next_validation;
1131
1132 /**
1133 * Current round-trip time estimate.
1134 */
1135 struct GNUNET_TIME_RelativeNBO rtt;
1136
1137 /**
1138 * Connection status (in NBO).
1139 */
1140 uint32_t cs GNUNET_PACKED;
1141
1142 /**
1143 * Messages pending (in NBO).
1144 */
1145 uint32_t num_msg_pending GNUNET_PACKED;
1146
1147 /**
1148 * Bytes pending (in NBO).
1149 */
1150 uint32_t num_bytes_pending GNUNET_PACKED;
1151
1152 /* Followed by 0-terminated address of the peer */
1153};
1154
1155
1156/**
1157 * Request to verify address.
1158 */
1159struct GNUNET_TRANSPORT_AddressToVerify
1160{
1161 /**
1162 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_CONSIDER_VERIFY.
1163 */
1164 struct GNUNET_MessageHeader header;
1165
1166 /**
1167 * Reserved. 0.
1168 */
1169 uint32_t reserved;
1170
1171 /**
1172 * Peer the address is from.
1173 */
1174 struct GNUNET_PeerIdentity peer;
1175
1176 /* followed by variable-size raw address */
1177};
1178
1179
1180/**
1181 * Application client to TRANSPORT service: we would like to have
1182 * address suggestions for this peer.
1183 */
1184struct ExpressPreferenceMessage
1185{
1186 /**
1187 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST or
1188 * #GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST_CANCEL to stop
1189 * suggestions.
1190 */
1191 struct GNUNET_MessageHeader header;
1192
1193 /**
1194 * What type of performance preference does the client have?
1195 * A `enum GNUNET_MQ_PreferenceKind` in NBO.
1196 */
1197 uint32_t pk GNUNET_PACKED;
1198
1199 /**
1200 * Peer to get address suggestions for.
1201 */
1202 struct GNUNET_PeerIdentity peer;
1203
1204 /**
1205 * How much bandwidth in bytes/second does the application expect?
1206 */
1207 struct GNUNET_BANDWIDTH_Value32NBO bw;
1208};
1209
1210
1211/**
1212 * We got an address of another peer, TRANSPORT service
1213 * should validate it. There is no response.
1214 */
1215struct RequestHelloValidationMessage
1216{
1217 /**
1218 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION.
1219 */
1220 struct GNUNET_MessageHeader header;
1221
1222 /**
1223 * What type of network does the other peer claim this is?
1224 * A `enum GNUNET_NetworkType` in NBO.
1225 */
1226 uint32_t nt GNUNET_PACKED;
1227
1228 /**
1229 * Peer to the address is presumably for.
1230 */
1231 struct GNUNET_PeerIdentity peer;
1232
1233 /* followed by 0-terminated address to validate */
1234};
1235
1236#endif
1237
1238GNUNET_NETWORK_STRUCT_END
1239
1240/* end of transport.h */
1241#endif
diff --git a/src/transport/transport_api2_application.c b/src/transport/transport_api2_application.c
deleted file mode 100644
index 00f5f62eb..000000000
--- a/src/transport/transport_api2_application.c
+++ /dev/null
@@ -1,397 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010--2019 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_api2_application.c
22 * @brief enable clients to ask TRANSPORT about establishing connections to peers
23 * @author Christian Grothoff
24 * @author Matthias Wachs
25 */
26#include "platform.h"
27#include "gnunet_transport_application_service.h"
28#include "gnunet_transport_core_service.h"
29#include "transport.h"
30
31
32#define LOG(kind, ...) \
33 GNUNET_log_from (kind, "transport-application-api", __VA_ARGS__)
34
35
36/**
37 * Handle for TRANSPORT address suggestion requests.
38 */
39struct GNUNET_TRANSPORT_ApplicationSuggestHandle
40{
41 /**
42 * ID of the peer for which address suggestion was requested.
43 */
44 struct GNUNET_PeerIdentity id;
45
46 /**
47 * Connecitivity handle this suggestion handle belongs to.
48 */
49 struct GNUNET_TRANSPORT_ApplicationHandle *ch;
50
51 /**
52 * What preference is being expressed?
53 */
54 enum GNUNET_MQ_PriorityPreferences pk;
55
56 /**
57 * How much bandwidth does the client expect?
58 */
59 struct GNUNET_BANDWIDTH_Value32NBO bw;
60};
61
62
63/**
64 * Handle to the TRANSPORT subsystem for application management.
65 */
66struct GNUNET_TRANSPORT_ApplicationHandle
67{
68 /**
69 * Our configuration.
70 */
71 const struct GNUNET_CONFIGURATION_Handle *cfg;
72
73 /**
74 * Map with the identities of all the peers for which we would
75 * like to have address suggestions. The key is the PID, the
76 * value is currently the `struct GNUNET_TRANSPORT_ApplicationSuggestHandle`
77 */
78 struct GNUNET_CONTAINER_MultiPeerMap *sug_requests;
79
80 /**
81 * Message queue for sending requests to the TRANSPORT service.
82 */
83 struct GNUNET_MQ_Handle *mq;
84
85 /**
86 * Task to trigger reconnect.
87 */
88 struct GNUNET_SCHEDULER_Task *task;
89
90 /**
91 * Reconnect backoff delay.
92 */
93 struct GNUNET_TIME_Relative backoff;
94};
95
96
97/**
98 * Re-establish the connection to the TRANSPORT service.
99 *
100 * @param ch handle to use to re-connect.
101 */
102static void
103reconnect (struct GNUNET_TRANSPORT_ApplicationHandle *ch);
104
105
106/**
107 * Re-establish the connection to the TRANSPORT service.
108 *
109 * @param cls handle to use to re-connect.
110 */
111static void
112reconnect_task (void *cls)
113{
114 struct GNUNET_TRANSPORT_ApplicationHandle *ch = cls;
115
116 ch->task = NULL;
117 reconnect (ch);
118}
119
120
121/**
122 * Disconnect from TRANSPORT and then reconnect.
123 *
124 * @param ch our handle
125 */
126static void
127force_reconnect (struct GNUNET_TRANSPORT_ApplicationHandle *ch)
128{
129 if (NULL != ch->mq)
130 {
131 GNUNET_MQ_destroy (ch->mq);
132 ch->mq = NULL;
133 }
134 ch->backoff = GNUNET_TIME_STD_BACKOFF (ch->backoff);
135 ch->task = GNUNET_SCHEDULER_add_delayed (ch->backoff, &reconnect_task, ch);
136}
137
138
139/**
140 * We encountered an error handling the MQ to the
141 * TRANSPORT service. Reconnect.
142 *
143 * @param cls the `struct GNUNET_TRANSPORT_ApplicationHandle`
144 * @param error details about the error
145 */
146static void
147error_handler (void *cls, enum GNUNET_MQ_Error error)
148{
149 struct GNUNET_TRANSPORT_ApplicationHandle *ch = cls;
150
151 LOG (GNUNET_ERROR_TYPE_DEBUG,
152 "TRANSPORT connection died (code %d), reconnecting\n",
153 (int) error);
154 force_reconnect (ch);
155}
156
157
158/**
159 * Transmit request for an address suggestion.
160 *
161 * @param cls the `struct GNUNET_TRANSPORT_ApplicationHandle`
162 * @param peer peer to ask for an address suggestion for
163 * @param value the `struct GNUNET_TRANSPORT_SuggestHandle`
164 * @return #GNUNET_OK (continue to iterate), #GNUNET_SYSERR on
165 * failure (message queue no longer exists)
166 */
167static int
168transmit_suggestion (void *cls,
169 const struct GNUNET_PeerIdentity *peer,
170 void *value)
171{
172 struct GNUNET_TRANSPORT_ApplicationHandle *ch = cls;
173 struct GNUNET_TRANSPORT_ApplicationSuggestHandle *sh = value;
174 struct GNUNET_MQ_Envelope *ev;
175 struct ExpressPreferenceMessage *m;
176
177 if (NULL == ch->mq)
178 return GNUNET_SYSERR;
179 ev = GNUNET_MQ_msg (m, GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST);
180 m->pk = htonl ((uint32_t) sh->pk);
181 m->bw = sh->bw;
182 m->peer = *peer;
183 GNUNET_MQ_send (ch->mq, ev);
184 return GNUNET_OK;
185}
186
187
188/**
189 * Re-establish the connection to the TRANSPORT service.
190 *
191 * @param ch handle to use to re-connect.
192 */
193static void
194reconnect (struct GNUNET_TRANSPORT_ApplicationHandle *ch)
195{
196 static const struct GNUNET_MQ_MessageHandler handlers[] = { { NULL, 0, 0 } };
197
198 GNUNET_assert (NULL == ch->mq);
199 ch->mq =
200 GNUNET_CLIENT_connect (ch->cfg, "transport", handlers, &error_handler, ch);
201 if (NULL == ch->mq)
202 {
203 force_reconnect (ch);
204 return;
205 }
206 GNUNET_CONTAINER_multipeermap_iterate (ch->sug_requests,
207 &transmit_suggestion,
208 ch);
209}
210
211
212/**
213 * Initialize the TRANSPORT application suggestion client handle.
214 *
215 * @param cfg configuration to use
216 * @return transport application handle, NULL on error
217 */
218struct GNUNET_TRANSPORT_ApplicationHandle *
219GNUNET_TRANSPORT_application_init (
220 const struct GNUNET_CONFIGURATION_Handle *cfg)
221{
222 struct GNUNET_TRANSPORT_ApplicationHandle *ch;
223
224 ch = GNUNET_new (struct GNUNET_TRANSPORT_ApplicationHandle);
225 ch->cfg = cfg;
226 ch->sug_requests = GNUNET_CONTAINER_multipeermap_create (32, GNUNET_YES);
227 reconnect (ch);
228 return ch;
229}
230
231
232/**
233 * Function called to free all `struct GNUNET_TRANSPORT_ApplicationSuggestHandle`s
234 * in the map.
235 *
236 * @param cls NULL
237 * @param key the key
238 * @param value the value to free
239 * @return #GNUNET_OK (continue to iterate)
240 */
241static int
242free_sug_handle (void *cls, const struct GNUNET_PeerIdentity *key, void *value)
243{
244 struct GNUNET_TRANSPORT_ApplicationSuggestHandle *cur = value;
245
246 GNUNET_free (cur);
247 return GNUNET_OK;
248}
249
250
251/**
252 * Client is done with TRANSPORT application management, release resources.
253 *
254 * @param ch handle to release
255 */
256void
257GNUNET_TRANSPORT_application_done (
258 struct GNUNET_TRANSPORT_ApplicationHandle *ch)
259{
260 if (NULL != ch->mq)
261 {
262 GNUNET_MQ_destroy (ch->mq);
263 ch->mq = NULL;
264 }
265 if (NULL != ch->task)
266 {
267 GNUNET_SCHEDULER_cancel (ch->task);
268 ch->task = NULL;
269 }
270 GNUNET_CONTAINER_multipeermap_iterate (ch->sug_requests,
271 &free_sug_handle,
272 NULL);
273 GNUNET_CONTAINER_multipeermap_destroy (ch->sug_requests);
274 GNUNET_free (ch);
275}
276
277
278/**
279 * An application would like TRANSPORT to connect to a peer.
280 *
281 * @param ch handle
282 * @param peer identity of the peer we need an address for
283 * @param pk what kind of application will the application require (can be
284 * #GNUNET_MQ_PRIO_BACKGROUND, we will still try to connect)
285 * @param bw desired bandwidth, can be zero (we will still try to connect)
286 * @return suggest handle, NULL if a request is already pending
287 */
288struct GNUNET_TRANSPORT_ApplicationSuggestHandle *
289GNUNET_TRANSPORT_application_suggest (
290 struct GNUNET_TRANSPORT_ApplicationHandle *ch,
291 const struct GNUNET_PeerIdentity *peer,
292 enum GNUNET_MQ_PriorityPreferences pk,
293 struct GNUNET_BANDWIDTH_Value32NBO bw)
294{
295 struct GNUNET_TRANSPORT_ApplicationSuggestHandle *s;
296
297 s = GNUNET_new (struct GNUNET_TRANSPORT_ApplicationSuggestHandle);
298 s->ch = ch;
299 s->id = *peer;
300 s->pk = pk;
301 s->bw = bw;
302 (void) GNUNET_CONTAINER_multipeermap_put (
303 ch->sug_requests,
304 &s->id,
305 s,
306 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
307 LOG (GNUNET_ERROR_TYPE_DEBUG,
308 "Requesting TRANSPORT to suggest address for `%s'\n",
309 GNUNET_i2s (peer));
310 if (NULL == ch->mq)
311 return s;
312 GNUNET_assert (GNUNET_OK == transmit_suggestion (ch, &s->id, s));
313 return s;
314}
315
316
317/**
318 * We no longer care about being connected to a peer.
319 *
320 * @param sh handle to stop
321 */
322void
323GNUNET_TRANSPORT_application_suggest_cancel (
324 struct GNUNET_TRANSPORT_ApplicationSuggestHandle *sh)
325{
326 struct GNUNET_TRANSPORT_ApplicationHandle *ch = sh->ch;
327 struct GNUNET_MQ_Envelope *ev;
328 struct ExpressPreferenceMessage *m;
329
330 LOG (GNUNET_ERROR_TYPE_DEBUG,
331 "Telling TRANSPORT we no longer care for an address for `%s'\n",
332 GNUNET_i2s (&sh->id));
333 GNUNET_assert (
334 GNUNET_OK ==
335 GNUNET_CONTAINER_multipeermap_remove (ch->sug_requests, &sh->id, sh));
336 if (NULL == ch->mq)
337 {
338 GNUNET_free (sh);
339 return;
340 }
341 ev = GNUNET_MQ_msg (m, GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST_CANCEL);
342 m->pk = htonl ((uint32_t) sh->pk);
343 m->bw = sh->bw;
344 m->peer = sh->id;
345 GNUNET_MQ_send (ch->mq, ev);
346 GNUNET_free (sh);
347}
348
349
350/**
351 * An application (or a communicator) has received a HELLO (or other address
352 * data of another peer) and wants TRANSPORT to validate that the address is
353 * correct. The result is NOT returned, in fact TRANSPORT may do nothing
354 * (i.e. if it has too many active validations or recently tried this one
355 * already). If the @a addr validates, TRANSPORT will persist the address
356 * with PEERSTORE.
357 *
358 * @param ch handle
359 * @param peer identity of the peer we have an address for
360 * @param nt network type of @a addr (as claimed by the other peer);
361 * used by TRANSPORT to avoid trying @a addr's that really cannot work
362 * due to network type mismatches
363 * @param addr address to validate
364 */
365void
366GNUNET_TRANSPORT_application_validate (
367 struct GNUNET_TRANSPORT_ApplicationHandle *ch,
368 const struct GNUNET_PeerIdentity *peer,
369 enum GNUNET_NetworkType nt,
370 const char *addr)
371{
372 struct GNUNET_MQ_Envelope *ev;
373 struct RequestHelloValidationMessage *m;
374 size_t alen;
375
376 if (NULL == ch->mq)
377 {
378 GNUNET_log (
379 GNUNET_ERROR_TYPE_WARNING,
380 "Address validation for %s:%s skipped as transport is not connected\n",
381 GNUNET_i2s (peer),
382 addr);
383 return;
384 }
385 alen = strlen (addr) + 1;
386 ev =
387 GNUNET_MQ_msg_extra (m,
388 alen,
389 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION);
390 m->peer = *peer;
391 m->nt = htonl ((uint32_t) nt);
392 memcpy (&m[1], addr, alen);
393 GNUNET_MQ_send (ch->mq, ev);
394}
395
396
397/* end of transport_api2_application.c */
diff --git a/src/transport/transport_api2_communication.c b/src/transport/transport_api2_communication.c
deleted file mode 100644
index 2a80db87b..000000000
--- a/src/transport/transport_api2_communication.c
+++ /dev/null
@@ -1,1165 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 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/**
22 * @file transport/transport_api2_communication.c
23 * @brief implementation of the gnunet_transport_communication_service.h API
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_protocols.h"
29#include "gnunet_transport_communication_service.h"
30#include "gnunet_ats_transport_service.h"
31#include "transport.h"
32
33
34/**
35 * How many messages do we keep at most in the queue to the
36 * transport service before we start to drop (default,
37 * can be changed via the configuration file).
38 */
39#define DEFAULT_MAX_QUEUE_LENGTH 16
40
41
42/**
43 * Information we track per packet to enable flow control.
44 */
45struct FlowControl
46{
47 /**
48 * Kept in a DLL.
49 */
50 struct FlowControl *next;
51
52 /**
53 * Kept in a DLL.
54 */
55 struct FlowControl *prev;
56
57 /**
58 * Function to call once the message was processed.
59 */
60 GNUNET_TRANSPORT_MessageCompletedCallback cb;
61
62 /**
63 * Closure for @e cb
64 */
65 void *cb_cls;
66
67 /**
68 * Which peer is this about?
69 */
70 struct GNUNET_PeerIdentity sender;
71
72 /**
73 * More-or-less unique ID for the message.
74 */
75 uint64_t id;
76};
77
78
79/**
80 * Information we track per message to tell the transport about
81 * success or failures.
82 */
83struct AckPending
84{
85 /**
86 * Kept in a DLL.
87 */
88 struct AckPending *next;
89
90 /**
91 * Kept in a DLL.
92 */
93 struct AckPending *prev;
94
95 /**
96 * Communicator this entry belongs to.
97 */
98 struct GNUNET_TRANSPORT_CommunicatorHandle *ch;
99
100 /**
101 * Which peer is this about?
102 */
103 struct GNUNET_PeerIdentity receiver;
104
105 /**
106 * More-or-less unique ID for the message.
107 */
108 uint64_t mid;
109};
110
111
112/**
113 * Opaque handle to the transport service for communicators.
114 */
115struct GNUNET_TRANSPORT_CommunicatorHandle
116{
117 /**
118 * Head of DLL of addresses this communicator offers to the transport service.
119 */
120 struct GNUNET_TRANSPORT_AddressIdentifier *ai_head;
121
122 /**
123 * Tail of DLL of addresses this communicator offers to the transport service.
124 */
125 struct GNUNET_TRANSPORT_AddressIdentifier *ai_tail;
126
127 /**
128 * DLL of messages awaiting flow control confirmation (ack).
129 */
130 struct FlowControl *fc_head;
131
132 /**
133 * DLL of messages awaiting flow control confirmation (ack).
134 */
135 struct FlowControl *fc_tail;
136
137 /**
138 * DLL of messages awaiting transmission confirmation (ack).
139 */
140 struct AckPending *ap_head;
141
142 /**
143 * DLL of messages awaiting transmission confirmation (ack).
144 */
145 struct AckPending *ap_tail;
146
147 /**
148 * DLL of queues we offer.
149 */
150 struct GNUNET_TRANSPORT_QueueHandle *queue_head;
151
152 /**
153 * DLL of queues we offer.
154 */
155 struct GNUNET_TRANSPORT_QueueHandle *queue_tail;
156
157 /**
158 * Our configuration.
159 */
160 const struct GNUNET_CONFIGURATION_Handle *cfg;
161
162 /**
163 * Config section to use.
164 */
165 const char *config_section;
166
167 /**
168 * Address prefix to use.
169 */
170 const char *addr_prefix;
171
172 /**
173 * Function to call when the transport service wants us to initiate
174 * a communication channel with another peer.
175 */
176 GNUNET_TRANSPORT_CommunicatorMqInit mq_init;
177
178 /**
179 * Closure for @e mq_init.
180 */
181 void *mq_init_cls;
182
183 /**
184 * Function to call when the transport service receives messages
185 * for a communicator (i.e. for NAT traversal or for non-bidirectional
186 * communicators).
187 */
188 GNUNET_TRANSPORT_CommunicatorNotify notify_cb;
189
190 /**
191 * Closure for @e notify_Cb.
192 */
193 void *notify_cb_cls;
194
195 /**
196 * Queue to talk to the transport service.
197 */
198 struct GNUNET_MQ_Handle *mq;
199
200 /**
201 * Maximum permissible queue length.
202 */
203 unsigned long long max_queue_length;
204
205 /**
206 * Flow-control identifier generator.
207 */
208 uint64_t fc_gen;
209
210 /**
211 * Internal UUID for the address used in communication with the
212 * transport service.
213 */
214 uint32_t aid_gen;
215
216 /**
217 * Queue identifier generator.
218 */
219 uint32_t queue_gen;
220
221 /**
222 * Characteristics of the communicator.
223 */
224 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
225};
226
227
228/**
229 * Handle returned to identify the internal data structure the transport
230 * API has created to manage a message queue to a particular peer.
231 */
232struct GNUNET_TRANSPORT_QueueHandle
233{
234 /**
235 * Kept in a DLL.
236 */
237 struct GNUNET_TRANSPORT_QueueHandle *next;
238
239 /**
240 * Kept in a DLL.
241 */
242 struct GNUNET_TRANSPORT_QueueHandle *prev;
243
244 /**
245 * Handle this queue belongs to.
246 */
247 struct GNUNET_TRANSPORT_CommunicatorHandle *ch;
248
249 /**
250 * Address used by the communication queue.
251 */
252 char *address;
253
254 /**
255 * The queue itself.
256 */
257 struct GNUNET_MQ_Handle *mq;
258
259 /**
260 * Which peer we can communciate with.
261 */
262 struct GNUNET_PeerIdentity peer;
263
264 /**
265 * Network type of the communication queue.
266 */
267 enum GNUNET_NetworkType nt;
268
269 /**
270 * Communication status of the queue.
271 */
272 enum GNUNET_TRANSPORT_ConnectionStatus cs;
273
274 /**
275 * ID for this queue when talking to the transport service.
276 */
277 uint32_t queue_id;
278
279 /**
280 * Maximum transmission unit for the queue.
281 */
282 uint32_t mtu;
283
284 /**
285 * Queue length.
286 */
287 uint64_t q_len;
288 /**
289 * Queue priority.
290 */
291 uint32_t priority;
292};
293
294
295/**
296 * Internal representation of an address a communicator is
297 * currently providing for the transport service.
298 */
299struct GNUNET_TRANSPORT_AddressIdentifier
300{
301 /**
302 * Kept in a DLL.
303 */
304 struct GNUNET_TRANSPORT_AddressIdentifier *next;
305
306 /**
307 * Kept in a DLL.
308 */
309 struct GNUNET_TRANSPORT_AddressIdentifier *prev;
310
311 /**
312 * Transport handle where the address was added.
313 */
314 struct GNUNET_TRANSPORT_CommunicatorHandle *ch;
315
316 /**
317 * The actual address.
318 */
319 char *address;
320
321 /**
322 * When does the address expire? (Expected lifetime of the
323 * address.)
324 */
325 struct GNUNET_TIME_Relative expiration;
326
327 /**
328 * Internal UUID for the address used in communication with the
329 * transport service.
330 */
331 uint32_t aid;
332
333 /**
334 * Network type for the address.
335 */
336 enum GNUNET_NetworkType nt;
337};
338
339
340/**
341 * (re)connect our communicator to the transport service
342 *
343 * @param ch handle to reconnect
344 */
345static void
346reconnect (struct GNUNET_TRANSPORT_CommunicatorHandle *ch);
347
348
349/**
350 * Send message to the transport service about address @a ai
351 * being now available.
352 *
353 * @param ai address to add
354 */
355static void
356send_add_address (struct GNUNET_TRANSPORT_AddressIdentifier *ai)
357{
358 struct GNUNET_MQ_Envelope *env;
359 struct GNUNET_TRANSPORT_AddAddressMessage *aam;
360
361 if (NULL == ai->ch->mq)
362 return;
363 env = GNUNET_MQ_msg_extra (aam,
364 strlen (ai->address) + 1,
365 GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS);
366 aam->expiration = GNUNET_TIME_relative_hton (ai->expiration);
367 aam->nt = htonl ((uint32_t) ai->nt);
368 memcpy (&aam[1], ai->address, strlen (ai->address) + 1);
369 GNUNET_MQ_send (ai->ch->mq, env);
370}
371
372
373/**
374 * Send message to the transport service about address @a ai
375 * being no longer available.
376 *
377 * @param ai address to delete
378 */
379static void
380send_del_address (struct GNUNET_TRANSPORT_AddressIdentifier *ai)
381{
382 struct GNUNET_MQ_Envelope *env;
383 struct GNUNET_TRANSPORT_DelAddressMessage *dam;
384
385 if (NULL == ai->ch->mq)
386 return;
387 env = GNUNET_MQ_msg (dam, GNUNET_MESSAGE_TYPE_TRANSPORT_DEL_ADDRESS);
388 dam->aid = htonl (ai->aid);
389 GNUNET_MQ_send (ai->ch->mq, env);
390}
391
392
393/**
394 * Send message to the transport service about queue @a qh
395 * being now available.
396 *
397 * @param qh queue to add
398 */
399static void
400send_add_queue (struct GNUNET_TRANSPORT_QueueHandle *qh)
401{
402 struct GNUNET_MQ_Envelope *env;
403 struct GNUNET_TRANSPORT_AddQueueMessage *aqm;
404
405 if (NULL == qh->ch->mq)
406 return;
407 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
408 "Sending `GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP` message\n");
409 env = GNUNET_MQ_msg_extra (aqm,
410 strlen (qh->address) + 1,
411 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP);
412 aqm->qid = htonl (qh->queue_id);
413 aqm->receiver = qh->peer;
414 aqm->nt = htonl ((uint32_t) qh->nt);
415 aqm->mtu = htonl (qh->mtu);
416 aqm->q_len = GNUNET_htonll (qh->q_len);
417 aqm->priority = htonl (qh->priority);
418 aqm->cs = htonl ((uint32_t) qh->cs);
419 memcpy (&aqm[1], qh->address, strlen (qh->address) + 1);
420 GNUNET_MQ_send (qh->ch->mq, env);
421}
422
423
424/**
425 * Send message to the transport service about queue @a qh
426 * updated.
427 *
428 * @param qh queue to add
429 */
430static void
431send_update_queue (struct GNUNET_TRANSPORT_QueueHandle *qh)
432{
433 struct GNUNET_MQ_Envelope *env;
434 struct GNUNET_TRANSPORT_UpdateQueueMessage *uqm;
435
436 if (NULL == qh->ch->mq)
437 return;
438 env = GNUNET_MQ_msg (uqm, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_UPDATE);
439 uqm->qid = htonl (qh->queue_id);
440 uqm->receiver = qh->peer;
441 uqm->nt = htonl ((uint32_t) qh->nt);
442 uqm->mtu = htonl (qh->mtu);
443 uqm->q_len = GNUNET_htonll (qh->q_len);
444 uqm->priority = htonl (qh->priority);
445 uqm->cs = htonl ((uint32_t) qh->cs);
446 GNUNET_MQ_send (qh->ch->mq, env);
447}
448
449
450/**
451 * Send message to the transport service about queue @a qh
452 * being no longer available.
453 *
454 * @param qh queue to delete
455 */
456static void
457send_del_queue (struct GNUNET_TRANSPORT_QueueHandle *qh)
458{
459 struct GNUNET_MQ_Envelope *env;
460 struct GNUNET_TRANSPORT_DelQueueMessage *dqm;
461
462 if (NULL == qh->ch->mq)
463 return;
464 env = GNUNET_MQ_msg (dqm, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN);
465 dqm->qid = htonl (qh->queue_id);
466 dqm->receiver = qh->peer;
467 GNUNET_MQ_send (qh->ch->mq, env);
468}
469
470
471/**
472 * Disconnect from the transport service. Purges
473 * all flow control entries as we will no longer receive
474 * the ACKs. Purges the ack pending entries as the
475 * transport will no longer expect the confirmations.
476 *
477 * @param ch service to disconnect from
478 */
479static void
480disconnect (struct GNUNET_TRANSPORT_CommunicatorHandle *ch)
481{
482 struct FlowControl *fcn;
483 struct AckPending *apn;
484
485 for (struct FlowControl *fc = ch->fc_head; NULL != fc; fc = fcn)
486 {
487 fcn = fc->next;
488 GNUNET_CONTAINER_DLL_remove (ch->fc_head, ch->fc_tail, fc);
489 fc->cb (fc->cb_cls, GNUNET_SYSERR);
490 GNUNET_free (fc);
491 }
492 for (struct AckPending *ap = ch->ap_head; NULL != ap; ap = apn)
493 {
494 apn = ap->next;
495 GNUNET_CONTAINER_DLL_remove (ch->ap_head, ch->ap_tail, ap);
496 GNUNET_free (ap);
497 }
498 if (NULL == ch->mq)
499 return;
500 GNUNET_MQ_destroy (ch->mq);
501 ch->mq = NULL;
502}
503
504
505/**
506 * Function called on MQ errors.
507 */
508static void
509error_handler (void *cls, enum GNUNET_MQ_Error error)
510{
511 struct GNUNET_TRANSPORT_CommunicatorHandle *ch = cls;
512
513 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
514 "MQ failure %d, reconnecting to transport service.\n",
515 error);
516 disconnect (ch);
517 /* TODO: maybe do this with exponential backoff/delay */
518 reconnect (ch);
519}
520
521
522/**
523 * Transport service acknowledged a message we gave it
524 * (with flow control enabled). Tell the communicator.
525 *
526 * @param cls our `struct GNUNET_TRANSPORT_CommunicatorHandle *`
527 * @param incoming_ack the ack
528 */
529static void
530handle_incoming_ack (
531 void *cls,
532 const struct GNUNET_TRANSPORT_IncomingMessageAck *incoming_ack)
533{
534 struct GNUNET_TRANSPORT_CommunicatorHandle *ch = cls;
535
536 for (struct FlowControl *fc = ch->fc_head; NULL != fc; fc = fc->next)
537 {
538 if ((fc->id == incoming_ack->fc_id) &&
539 (0 == memcmp (&fc->sender,
540 &incoming_ack->sender,
541 sizeof(struct GNUNET_PeerIdentity))))
542 {
543 GNUNET_CONTAINER_DLL_remove (ch->fc_head, ch->fc_tail, fc);
544 fc->cb (fc->cb_cls, GNUNET_OK);
545 GNUNET_free (fc);
546 return;
547 }
548 }
549 GNUNET_break (0);
550 disconnect (ch);
551 /* TODO: maybe do this with exponential backoff/delay */
552 reconnect (ch);
553}
554
555
556/**
557 * Transport service wants us to create a queue. Check if @a cq
558 * is well-formed.
559 *
560 * @param cls our `struct GNUNET_TRANSPORT_CommunicatorHandle *`
561 * @param cq the queue creation request
562 * @return #GNUNET_OK if @a smt is well-formed
563 */
564static int
565check_create_queue (void *cls, const struct GNUNET_TRANSPORT_CreateQueue *cq)
566{
567 (void) cls;
568 GNUNET_MQ_check_zero_termination (cq);
569 return GNUNET_OK;
570}
571
572
573/**
574 * Transport service wants us to create a queue. Tell the communicator.
575 *
576 * @param cls our `struct GNUNET_TRANSPORT_CommunicatorHandle *`
577 * @param cq the queue creation request
578 */
579static void
580handle_create_queue (void *cls, const struct GNUNET_TRANSPORT_CreateQueue *cq)
581{
582 struct GNUNET_TRANSPORT_CommunicatorHandle *ch = cls;
583 const char *addr = (const char *) &cq[1];
584 struct GNUNET_TRANSPORT_CreateQueueResponse *cqr;
585 struct GNUNET_MQ_Envelope *env;
586
587 if (GNUNET_OK != ch->mq_init (ch->mq_init_cls, &cq->receiver, addr))
588 {
589 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
590 "Address `%s' invalid for this communicator\n",
591 addr);
592 env = GNUNET_MQ_msg (cqr, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL);
593 }
594 else
595 {
596 env = GNUNET_MQ_msg (cqr, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_OK);
597 }
598 cqr->request_id = cq->request_id;
599 GNUNET_MQ_send (ch->mq, env);
600}
601
602
603/**
604 * Transport service wants us to send a message. Check if @a smt
605 * is well-formed.
606 *
607 * @param cls our `struct GNUNET_TRANSPORT_CommunicatorHandle *`
608 * @param smt the transmission request
609 * @return #GNUNET_OK if @a smt is well-formed
610 */
611static int
612check_send_msg (void *cls, const struct GNUNET_TRANSPORT_SendMessageTo *smt)
613{
614 (void) cls;
615 GNUNET_MQ_check_boxed_message (smt);
616 return GNUNET_OK;
617}
618
619
620/**
621 * Notify transport service about @a status of a message with
622 * @a mid sent to @a receiver.
623 *
624 * @param ch handle
625 * @param status #GNUNET_OK on success, #GNUNET_SYSERR on failure
626 * @param receiver which peer was the receiver
627 * @param mid message that the ack is about
628 */
629static void
630send_ack (struct GNUNET_TRANSPORT_CommunicatorHandle *ch,
631 int status,
632 const struct GNUNET_PeerIdentity *receiver,
633 uint64_t mid)
634{
635 struct GNUNET_MQ_Envelope *env;
636 struct GNUNET_TRANSPORT_SendMessageToAck *ack;
637
638 env = GNUNET_MQ_msg (ack, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG_ACK);
639 ack->status = htonl (status);
640 ack->mid = mid;
641 ack->receiver = *receiver;
642 GNUNET_MQ_send (ch->mq, env);
643}
644
645
646/**
647 * Message queue transmission by communicator was successful,
648 * notify transport service.
649 *
650 * @param cls an `struct AckPending *`
651 */
652static void
653send_ack_cb (void *cls)
654{
655 struct AckPending *ap = cls;
656 struct GNUNET_TRANSPORT_CommunicatorHandle *ch = ap->ch;
657
658 GNUNET_CONTAINER_DLL_remove (ch->ap_head, ch->ap_tail, ap);
659 send_ack (ch, GNUNET_OK, &ap->receiver, ap->mid);
660 GNUNET_free (ap);
661}
662
663
664/**
665 * Transport service wants us to send a message. Tell the communicator.
666 *
667 * @param cls our `struct GNUNET_TRANSPORT_CommunicatorHandle *`
668 * @param smt the transmission request
669 */
670static void
671handle_send_msg (void *cls, const struct GNUNET_TRANSPORT_SendMessageTo *smt)
672{
673 struct GNUNET_TRANSPORT_CommunicatorHandle *ch = cls;
674 const struct GNUNET_MessageHeader *mh;
675 struct GNUNET_MQ_Envelope *env;
676 struct AckPending *ap;
677 struct GNUNET_TRANSPORT_QueueHandle *qh;
678
679 for (qh = ch->queue_head; NULL != qh; qh = qh->next)
680 if ((qh->queue_id == ntohl (smt->qid)) &&
681 (0 == memcmp (&qh->peer,
682 &smt->receiver,
683 sizeof(struct GNUNET_PeerIdentity))))
684 break;
685 if (NULL == qh)
686 {
687 /* queue is already gone, tell transport this one failed */
688 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
689 "Transmission failed, queue no longer exists.\n");
690 send_ack (ch, GNUNET_NO, &smt->receiver, smt->mid);
691 return;
692 }
693 ap = GNUNET_new (struct AckPending);
694 ap->ch = ch;
695 ap->receiver = smt->receiver;
696 ap->mid = smt->mid;
697 GNUNET_CONTAINER_DLL_insert (ch->ap_head, ch->ap_tail, ap);
698 mh = (const struct GNUNET_MessageHeader *) &smt[1];
699 env = GNUNET_MQ_msg_copy (mh);
700 GNUNET_MQ_notify_sent (env, &send_ack_cb, ap);
701 GNUNET_MQ_send (qh->mq, env);
702}
703
704
705/**
706 * Transport service gives us backchannel message. Check if @a bi
707 * is well-formed.
708 *
709 * @param cls our `struct GNUNET_TRANSPORT_CommunicatorHandle *`
710 * @param bi the backchannel message
711 * @return #GNUNET_OK if @a smt is well-formed
712 */
713static int
714check_backchannel_incoming (
715 void *cls,
716 const struct GNUNET_TRANSPORT_CommunicatorBackchannelIncoming *bi)
717{
718 (void) cls;
719 GNUNET_MQ_check_boxed_message (bi);
720 return GNUNET_OK;
721}
722
723
724/**
725 * Transport service gives us backchannel message. Handle it.
726 *
727 * @param cls our `struct GNUNET_TRANSPORT_CommunicatorHandle *`
728 * @param bi the backchannel message
729 */
730static void
731handle_backchannel_incoming (
732 void *cls,
733 const struct GNUNET_TRANSPORT_CommunicatorBackchannelIncoming *bi)
734{
735 struct GNUNET_TRANSPORT_CommunicatorHandle *ch = cls;
736 if (NULL != ch->notify_cb)
737 ch->notify_cb (ch->notify_cb_cls,
738 &bi->pid,
739 (const struct GNUNET_MessageHeader *) &bi[1]);
740 else
741 GNUNET_log (
742 GNUNET_ERROR_TYPE_INFO,
743 _ ("Dropped backchanel message: handler not provided by communicator\n"));
744}
745
746
747/**
748 * (re)connect our communicator to the transport service
749 *
750 * @param ch handle to reconnect
751 */
752static void
753reconnect (struct GNUNET_TRANSPORT_CommunicatorHandle *ch)
754{
755 struct GNUNET_MQ_MessageHandler handlers[] =
756 { GNUNET_MQ_hd_fixed_size (incoming_ack,
757 GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG_ACK,
758 struct GNUNET_TRANSPORT_IncomingMessageAck,
759 ch),
760 GNUNET_MQ_hd_var_size (create_queue,
761 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE,
762 struct GNUNET_TRANSPORT_CreateQueue,
763 ch),
764 GNUNET_MQ_hd_var_size (send_msg,
765 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG,
766 struct GNUNET_TRANSPORT_SendMessageTo,
767 ch),
768 GNUNET_MQ_hd_var_size (
769 backchannel_incoming,
770 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL_INCOMING,
771 struct GNUNET_TRANSPORT_CommunicatorBackchannelIncoming,
772 ch),
773 GNUNET_MQ_handler_end () };
774 struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam;
775 struct GNUNET_MQ_Envelope *env;
776
777 ch->mq =
778 GNUNET_CLIENT_connect (ch->cfg, "transport", handlers, &error_handler, ch);
779 if (NULL == ch->mq)
780 return;
781 env = GNUNET_MQ_msg_extra (cam,
782 strlen (ch->addr_prefix) + 1,
783 GNUNET_MESSAGE_TYPE_TRANSPORT_NEW_COMMUNICATOR);
784 cam->cc = htonl ((uint32_t) ch->cc);
785 memcpy (&cam[1], ch->addr_prefix, strlen (ch->addr_prefix) + 1);
786 GNUNET_MQ_send (ch->mq, env);
787 for (struct GNUNET_TRANSPORT_AddressIdentifier *ai = ch->ai_head; NULL != ai;
788 ai = ai->next)
789 send_add_address (ai);
790 for (struct GNUNET_TRANSPORT_QueueHandle *qh = ch->queue_head; NULL != qh;
791 qh = qh->next)
792 send_add_queue (qh);
793}
794
795
796/**
797 * Connect to the transport service.
798 *
799 * @param cfg configuration to use
800 * @param config_section section of the configuration to use for options
801 * @param addr_prefix address prefix for addresses supported by this
802 * communicator, could be NULL for incoming-only communicators
803 * @param cc what characteristics does the communicator have?
804 * @param mtu maximum message size supported by communicator, 0 if
805 * sending is not supported, SIZE_MAX for no MTU
806 * @param mq_init function to call to initialize a message queue given
807 * the address of another peer, can be NULL if the
808 * communicator only supports receiving messages
809 * @param mq_init_cls closure for @a mq_init
810 * @param notify_cb function to pass backchannel messages to communicator
811 * @param notify_cb_cls closure for @a notify_cb
812 * @return NULL on error
813 */
814struct GNUNET_TRANSPORT_CommunicatorHandle *
815GNUNET_TRANSPORT_communicator_connect (
816 const struct GNUNET_CONFIGURATION_Handle *cfg,
817 const char *config_section,
818 const char *addr_prefix,
819 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc,
820 GNUNET_TRANSPORT_CommunicatorMqInit mq_init,
821 void *mq_init_cls,
822 GNUNET_TRANSPORT_CommunicatorNotify notify_cb,
823 void *notify_cb_cls)
824{
825 struct GNUNET_TRANSPORT_CommunicatorHandle *ch;
826
827 ch = GNUNET_new (struct GNUNET_TRANSPORT_CommunicatorHandle);
828 ch->cfg = cfg;
829 ch->config_section = config_section;
830 ch->addr_prefix = addr_prefix;
831 ch->mq_init = mq_init;
832 ch->mq_init_cls = mq_init_cls;
833 ch->notify_cb = notify_cb;
834 ch->notify_cb_cls = notify_cb_cls;
835 ch->cc = cc;
836 reconnect (ch);
837 if (GNUNET_OK !=
838 GNUNET_CONFIGURATION_get_value_number (cfg,
839 config_section,
840 "MAX_QUEUE_LENGTH",
841 &ch->max_queue_length))
842 ch->max_queue_length = DEFAULT_MAX_QUEUE_LENGTH;
843 if (NULL == ch->mq)
844 {
845 GNUNET_free (ch);
846 return NULL;
847 }
848 return ch;
849}
850
851
852/**
853 * Disconnect from the transport service.
854 *
855 * @param ch handle returned from connect
856 */
857void
858GNUNET_TRANSPORT_communicator_disconnect (
859 struct GNUNET_TRANSPORT_CommunicatorHandle *ch)
860{
861 disconnect (ch);
862 while (NULL != ch->ai_head)
863 {
864 GNUNET_break (0); /* communicator forgot to remove address, warn! */
865 GNUNET_TRANSPORT_communicator_address_remove (ch->ai_head);
866 }
867 GNUNET_free (ch);
868}
869
870
871/* ************************* Receiving *************************** */
872
873
874/**
875 * Notify transport service that the communicator has received
876 * a message.
877 *
878 * @param ch connection to transport service
879 * @param sender presumed sender of the message (details to be checked
880 * by higher layers)
881 * @param msg the message
882 * @param expected_addr_validity how long does the communicator believe it
883 * will continue to be able to receive messages from the same address
884 * on which it received this message?
885 * @param cb function to call once handling the message is done, NULL if
886 * flow control is not supported by this communicator
887 * @param cb_cls closure for @a cb
888 * @return #GNUNET_OK if all is well, #GNUNET_NO if the message was
889 * immediately dropped due to memory limitations (communicator
890 * should try to apply back pressure),
891 * #GNUNET_SYSERR if the message could not be delivered because
892 * the transport service is not yet up
893 */
894int
895GNUNET_TRANSPORT_communicator_receive (
896 struct GNUNET_TRANSPORT_CommunicatorHandle *ch,
897 const struct GNUNET_PeerIdentity *sender,
898 const struct GNUNET_MessageHeader *msg,
899 struct GNUNET_TIME_Relative expected_addr_validity,
900 GNUNET_TRANSPORT_MessageCompletedCallback cb,
901 void *cb_cls)
902{
903 struct GNUNET_MQ_Envelope *env;
904 struct GNUNET_TRANSPORT_IncomingMessage *im;
905 uint16_t msize;
906
907
908 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
909 "communicator receive\n");
910
911 if (NULL == ch->mq)
912 return GNUNET_SYSERR;
913 if ((NULL == cb) && (GNUNET_MQ_get_length (ch->mq) >= ch->max_queue_length))
914 {
915 GNUNET_log (
916 GNUNET_ERROR_TYPE_WARNING,
917 "Dropping message: transport is too slow, queue length %llu exceeded\n",
918 ch->max_queue_length);
919 return GNUNET_NO;
920 }
921
922 msize = ntohs (msg->size);
923 env =
924 GNUNET_MQ_msg_extra (im, msize, GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG);
925 if (NULL == env)
926 {
927 GNUNET_break (0);
928 return GNUNET_SYSERR;
929 }
930 im->expected_address_validity =
931 GNUNET_TIME_relative_hton (expected_addr_validity);
932 im->sender = *sender;
933 // FIXME: this is expensive, would be better if we would
934 // re-design the API to allow us to create the envelope first,
935 // and then have the application fill in the body so we do
936 // not have to memcpy()
937 memcpy (&im[1], msg, msize);
938 im->fc_on = htonl (GNUNET_NO);
939 if (NULL != cb)
940 {
941 struct FlowControl *fc;
942
943 im->fc_on = htonl (GNUNET_YES);
944 im->fc_id = ch->fc_gen++;
945 fc = GNUNET_new (struct FlowControl);
946 fc->sender = *sender;
947 fc->id = im->fc_id;
948 fc->cb = cb;
949 fc->cb_cls = cb_cls;
950 GNUNET_CONTAINER_DLL_insert (ch->fc_head, ch->fc_tail, fc);
951 }
952 GNUNET_MQ_send (ch->mq, env);
953 return GNUNET_OK;
954}
955
956
957/* ************************* Discovery *************************** */
958
959
960/**
961 * Notify transport service that an MQ became available due to an
962 * "inbound" connection or because the communicator discovered the
963 * presence of another peer.
964 *
965 * @param ch connection to transport service
966 * @param peer peer with which we can now communicate
967 * @param address address in human-readable format, 0-terminated, UTF-8
968 * @param mtu maximum message size supported by queue, 0 if
969 * sending is not supported, SIZE_MAX for no MTU
970 * @param q_len number of messages that can be send through this queue
971 * @param priority queue priority. Queues with highest priority should be
972 * used
973 * @param nt which network type does the @a address belong to?
974 * @param cc what characteristics does the communicator have?
975 * @param cs what is the connection status of the queue?
976 * @param mq message queue of the @a peer
977 * @return API handle identifying the new MQ
978 */
979struct GNUNET_TRANSPORT_QueueHandle *
980GNUNET_TRANSPORT_communicator_mq_add (
981 struct GNUNET_TRANSPORT_CommunicatorHandle *ch,
982 const struct GNUNET_PeerIdentity *peer,
983 const char *address,
984 uint32_t mtu,
985 uint64_t q_len,
986 uint32_t priority,
987 enum GNUNET_NetworkType nt,
988 enum GNUNET_TRANSPORT_ConnectionStatus cs,
989 struct GNUNET_MQ_Handle *mq)
990{
991 struct GNUNET_TRANSPORT_QueueHandle *qh;
992
993 // Do not notify the service if there is no intial capacity.
994 GNUNET_assert (0 < q_len);
995
996 qh = GNUNET_new (struct GNUNET_TRANSPORT_QueueHandle);
997 qh->ch = ch;
998 qh->peer = *peer;
999 qh->address = GNUNET_strdup (address);
1000 qh->nt = nt;
1001 qh->mtu = mtu;
1002 qh->q_len = q_len;
1003 qh->priority = priority;
1004 qh->cs = cs;
1005 qh->mq = mq;
1006 qh->queue_id = ch->queue_gen++;
1007 GNUNET_CONTAINER_DLL_insert (ch->queue_head, ch->queue_tail, qh);
1008 send_add_queue (qh);
1009 return qh;
1010}
1011
1012
1013/**
1014 * Notify transport service that an MQ was updated
1015 *
1016 * @param ch connection to transport service
1017 * @param qh the queue to update
1018 * @param q_len number of messages that can be send through this queue
1019 * @param priority queue priority. Queues with highest priority should be
1020 * used
1021 */
1022void
1023GNUNET_TRANSPORT_communicator_mq_update (
1024 struct GNUNET_TRANSPORT_CommunicatorHandle *ch,
1025 const struct GNUNET_TRANSPORT_QueueHandle *u_qh,
1026 uint64_t q_len,
1027 uint32_t priority)
1028{
1029 struct GNUNET_TRANSPORT_QueueHandle *qh;
1030
1031 for (qh = ch->queue_head; NULL != qh; qh = qh->next)
1032 {
1033 if (u_qh == qh)
1034 break;
1035 }
1036 GNUNET_assert (NULL != qh);
1037 qh->q_len = q_len;
1038 qh->priority = priority;
1039 send_update_queue (qh);
1040}
1041
1042
1043/**
1044 * Notify transport service that an MQ became unavailable due to a
1045 * disconnect or timeout.
1046 *
1047 * @param qh handle for the queue that must be invalidated
1048 */
1049void
1050GNUNET_TRANSPORT_communicator_mq_del (struct GNUNET_TRANSPORT_QueueHandle *qh)
1051{
1052 struct GNUNET_TRANSPORT_CommunicatorHandle *ch = qh->ch;
1053
1054 send_del_queue (qh);
1055 GNUNET_CONTAINER_DLL_remove (ch->queue_head, ch->queue_tail, qh);
1056 GNUNET_MQ_destroy (qh->mq);
1057 GNUNET_free (qh->address);
1058 GNUNET_free (qh);
1059}
1060
1061
1062/**
1063 * Notify transport service about an address that this communicator
1064 * provides for this peer.
1065 *
1066 * @param ch connection to transport service
1067 * @param address our address in human-readable format, 0-terminated, UTF-8
1068 * @param nt which network type does the address belong to?
1069 * @param expiration when does the communicator forsee this address expiring?
1070 */
1071struct GNUNET_TRANSPORT_AddressIdentifier *
1072GNUNET_TRANSPORT_communicator_address_add (
1073 struct GNUNET_TRANSPORT_CommunicatorHandle *ch,
1074 const char *address,
1075 enum GNUNET_NetworkType nt,
1076 struct GNUNET_TIME_Relative expiration)
1077{
1078 struct GNUNET_TRANSPORT_AddressIdentifier *ai;
1079
1080 ai = GNUNET_new (struct GNUNET_TRANSPORT_AddressIdentifier);
1081 ai->ch = ch;
1082 ai->address = GNUNET_strdup (address);
1083 ai->nt = nt;
1084 ai->expiration = expiration;
1085 ai->aid = ch->aid_gen++;
1086 GNUNET_CONTAINER_DLL_insert (ch->ai_head, ch->ai_tail, ai);
1087 send_add_address (ai);
1088 return ai;
1089}
1090
1091/**
1092 * Notify transport service about an address that this communicator no
1093 * longer provides for this peer.
1094 *
1095 * @param ai address that is no longer provided
1096 */
1097void
1098GNUNET_TRANSPORT_communicator_address_remove (
1099 struct GNUNET_TRANSPORT_AddressIdentifier *ai)
1100{
1101 struct GNUNET_TRANSPORT_CommunicatorHandle *ch = ai->ch;
1102
1103 send_del_address (ai);
1104 GNUNET_CONTAINER_DLL_remove (ch->ai_head, ch->ai_tail, ai);
1105 GNUNET_free (ai->address);
1106 GNUNET_free (ai);
1107}
1108
1109/**
1110 * Notify transport service that this communicator no longer provides all its addresses for this peer.
1111 *
1112 * @param ch The communicator handle.
1113 */
1114void
1115GNUNET_TRANSPORT_communicator_address_remove_all (
1116 struct GNUNET_TRANSPORT_CommunicatorHandle *ch)
1117{
1118 for (struct GNUNET_TRANSPORT_AddressIdentifier *ai = ch->ai_head; NULL != ai;
1119 ai = ai->next)
1120 GNUNET_TRANSPORT_communicator_address_remove (ai);
1121}
1122
1123
1124/* ************************* Backchannel *************************** */
1125
1126
1127/**
1128 * The communicator asks the transport service to route a message via
1129 * a different path to another communicator service at another peer.
1130 * This must only be done for special control traffic (as there is no
1131 * flow control for this API), such as acknowledgements, and generally
1132 * only be done if the communicator is uni-directional (i.e. cannot
1133 * send the message back itself).
1134 *
1135 * @param ch handle of this communicator
1136 * @param pid peer to send the message to
1137 * @param comm name of the communicator to send the message to
1138 * @param header header of the message to transmit and pass via the
1139 * notify-API to @a pid's communicator @a comm
1140 */
1141void
1142GNUNET_TRANSPORT_communicator_notify (
1143 struct GNUNET_TRANSPORT_CommunicatorHandle *ch,
1144 const struct GNUNET_PeerIdentity *pid,
1145 const char *comm,
1146 const struct GNUNET_MessageHeader *header)
1147{
1148 struct GNUNET_MQ_Envelope *env;
1149 struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb;
1150 size_t slen = strlen (comm) + 1;
1151 uint16_t mlen = ntohs (header->size);
1152
1153 GNUNET_assert (mlen + slen + sizeof(*cb) < UINT16_MAX);
1154 env =
1155 GNUNET_MQ_msg_extra (cb,
1156 slen + mlen,
1157 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL);
1158 cb->pid = *pid;
1159 memcpy (&cb[1], header, mlen);
1160 memcpy (((char *) &cb[1]) + mlen, comm, slen);
1161 GNUNET_MQ_send (ch->mq, env);
1162}
1163
1164
1165/* end of transport_api2_communication.c */
diff --git a/src/transport/transport_api2_core.c b/src/transport/transport_api2_core.c
deleted file mode 100644
index 8cd0b7c8c..000000000
--- a/src/transport/transport_api2_core.c
+++ /dev/null
@@ -1,804 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-2013, 2016, 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/**
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_core_service.h"
33#include "transport.h"
34
35#define LOG(kind, ...) GNUNET_log_from (kind, "transport-api-core", __VA_ARGS__)
36
37/**
38 * How large to start with for the hashmap of neighbours.
39 */
40#define STARTING_NEIGHBOURS_SIZE 16
41
42/**
43 * Window size. How many messages to the same target do we pass
44 * to TRANSPORT without a SEND_OK in between? Small values limit
45 * thoughput, large values will increase latency.
46 *
47 * FIXME-OPTIMIZE: find out what good values are experimentally,
48 * maybe set adaptively (i.e. to observed available bandwidth).
49 */
50#define SEND_WINDOW_SIZE 4
51
52
53/**
54 * Entry in hash table of all of our current (connected) neighbours.
55 */
56struct Neighbour
57{
58 /**
59 * Identity of this neighbour.
60 */
61 struct GNUNET_PeerIdentity id;
62
63 /**
64 * Overall transport handle.
65 */
66 struct GNUNET_TRANSPORT_CoreHandle *h;
67
68 /**
69 * Active message queue for the peer.
70 */
71 struct GNUNET_MQ_Handle *mq;
72
73 /**
74 * Envelope with the message we are currently transmitting (or NULL).
75 */
76 struct GNUNET_MQ_Envelope *env;
77
78 /**
79 * Closure for @e mq handlers.
80 */
81 void *handlers_cls;
82
83 /**
84 * How many messages can we still send to this peer before we should
85 * throttle?
86 */
87 unsigned int ready_window;
88
89 /**
90 * Used to indicate our status if @e env is non-NULL. Set to
91 * #GNUNET_YES if we did pass a message to the MQ and are waiting
92 * for the call to #notify_send_done(). Set to #GNUNET_NO if the @e
93 * ready_window is 0 and @e env is waiting for a
94 * #GNUNET_MESSAGE_TYPE_TRANSPORT_RECV_OK?
95 */
96 int16_t awaiting_done;
97
98 /**
99 * Size of the message in @e env.
100 */
101 uint16_t env_size;
102};
103
104
105/**
106 * Handle for the transport service (includes all of the
107 * state for the transport service).
108 */
109struct GNUNET_TRANSPORT_CoreHandle
110{
111 /**
112 * Closure for the callbacks.
113 */
114 void *cls;
115
116 /**
117 * Functions to call for received data (template for
118 * new message queues).
119 */
120 struct GNUNET_MQ_MessageHandler *handlers;
121
122 /**
123 * function to call on connect events
124 */
125 GNUNET_TRANSPORT_NotifyConnect nc_cb;
126
127 /**
128 * function to call on disconnect events
129 */
130 GNUNET_TRANSPORT_NotifyDisconnect nd_cb;
131
132 /**
133 * My client connection to the transport service.
134 */
135 struct GNUNET_MQ_Handle *mq;
136
137 /**
138 * My configuration.
139 */
140 const struct GNUNET_CONFIGURATION_Handle *cfg;
141
142 /**
143 * Hash map of the current connected neighbours of this peer.
144 * Maps peer identities to `struct Neighbour` entries.
145 */
146 struct GNUNET_CONTAINER_MultiPeerMap *neighbours;
147
148 /**
149 * Peer identity as assumed by this process, or all zeros.
150 */
151 struct GNUNET_PeerIdentity self;
152
153 /**
154 * ID of the task trying to reconnect to the service.
155 */
156 struct GNUNET_SCHEDULER_Task *reconnect_task;
157
158 /**
159 * Delay until we try to reconnect.
160 */
161 struct GNUNET_TIME_Relative reconnect_delay;
162
163 /**
164 * Should we check that @e self matches what the service thinks?
165 * (if #GNUNET_NO, then @e self is all zeros!).
166 */
167 int check_self;
168};
169
170
171/**
172 * Function that will schedule the job that will try
173 * to connect us again to the client.
174 *
175 * @param h transport service to reconnect
176 */
177static void
178disconnect_and_schedule_reconnect (struct GNUNET_TRANSPORT_CoreHandle *h);
179
180
181/**
182 * Get the neighbour list entry for the given peer
183 *
184 * @param h our context
185 * @param peer peer to look up
186 * @return NULL if no such peer entry exists
187 */
188static struct Neighbour *
189neighbour_find (struct GNUNET_TRANSPORT_CoreHandle *h,
190 const struct GNUNET_PeerIdentity *peer)
191{
192 return GNUNET_CONTAINER_multipeermap_get (h->neighbours, peer);
193}
194
195
196/**
197 * Iterator over hash map entries, for deleting state of a neighbour.
198 *
199 * @param cls the `struct GNUNET_TRANSPORT_CoreHandle *`
200 * @param key peer identity
201 * @param value value in the hash map, the neighbour entry to delete
202 * @return #GNUNET_YES if we should continue to
203 * iterate,
204 * #GNUNET_NO if not.
205 */
206static int
207neighbour_delete (void *cls, const struct GNUNET_PeerIdentity *key, void *value)
208{
209 struct GNUNET_TRANSPORT_CoreHandle *handle = cls;
210 struct Neighbour *n = value;
211
212 LOG (GNUNET_ERROR_TYPE_DEBUG,
213 "Dropping entry for neighbour `%s'.\n",
214 GNUNET_i2s (key));
215 if (NULL != handle->nd_cb)
216 handle->nd_cb (handle->cls, &n->id, n->handlers_cls);
217 if (NULL != n->env)
218 {
219 GNUNET_MQ_send_cancel (n->env);
220 n->env = NULL;
221 }
222 GNUNET_MQ_destroy (n->mq);
223 GNUNET_assert (NULL == n->mq);
224 GNUNET_assert (
225 GNUNET_YES ==
226 GNUNET_CONTAINER_multipeermap_remove (handle->neighbours, key, n));
227 GNUNET_free (n);
228 return GNUNET_YES;
229}
230
231
232/**
233 * Generic error handler, called with the appropriate
234 * error code and the same closure specified at the creation of
235 * the message queue.
236 * Not every message queue implementation supports an error handler.
237 *
238 * @param cls closure with the `struct GNUNET_TRANSPORT_CoreHandle *`
239 * @param error error code
240 */
241static void
242mq_error_handler (void *cls, enum GNUNET_MQ_Error error)
243{
244 struct GNUNET_TRANSPORT_CoreHandle *h = cls;
245
246 LOG (GNUNET_ERROR_TYPE_DEBUG,
247 "Error %u received from transport service, disconnecting temporarily.\n",
248 error);
249 disconnect_and_schedule_reconnect (h);
250}
251
252
253/**
254 * A message from the handler's message queue to a neighbour was
255 * transmitted. Now trigger (possibly delayed) notification of the
256 * neighbour's message queue that we are done and thus ready for
257 * the next message. Note that the MQ being ready is independent
258 * of the send window, as we may queue many messages and simply
259 * not pass them to TRANSPORT if the send window is insufficient.
260 *
261 * @param cls the `struct Neighbour` where the message was sent
262 */
263static void
264notify_send_done (void *cls)
265{
266 struct Neighbour *n = cls;
267
268 n->awaiting_done = GNUNET_NO;
269 n->env = NULL;
270 GNUNET_MQ_impl_send_continue (n->mq);
271}
272
273
274/**
275 * We have an envelope waiting for transmission at @a n, and
276 * our transmission window is positive. Perform the transmission.
277 *
278 * @param n neighbour to perform transmission for
279 */
280static void
281do_send (struct Neighbour *n)
282{
283 GNUNET_assert (0 < n->ready_window);
284 GNUNET_assert (NULL != n->env);
285 n->ready_window--;
286 n->awaiting_done = GNUNET_YES;
287 GNUNET_MQ_notify_sent (n->env, &notify_send_done, n);
288 GNUNET_MQ_send (n->h->mq, n->env);
289 LOG (GNUNET_ERROR_TYPE_DEBUG,
290 "Passed message of type %u for neighbour `%s' to TRANSPORT.\n",
291 ntohs (GNUNET_MQ_env_get_msg (n->env)->type),
292 GNUNET_i2s (&n->id));
293}
294
295
296/**
297 * Implement sending functionality of a message queue.
298 * Called one message at a time. Should send the @a msg
299 * to the transport service and then notify the queue
300 * once we are ready for the next one.
301 *
302 * @param mq the message queue
303 * @param msg the message to send
304 * @param impl_state state of the implementation
305 */
306static void
307mq_send_impl (struct GNUNET_MQ_Handle *mq,
308 const struct GNUNET_MessageHeader *msg,
309 void *impl_state)
310{
311 struct Neighbour *n = impl_state;
312 struct OutboundMessage *obm;
313 uint16_t msize;
314
315 msize = ntohs (msg->size);
316 if (msize >= GNUNET_MAX_MESSAGE_SIZE - sizeof(*obm))
317 {
318 GNUNET_break (0);
319 GNUNET_MQ_impl_send_continue (mq);
320 return;
321 }
322 LOG (GNUNET_ERROR_TYPE_DEBUG,
323 "CORE requested transmission of message of type %u to neighbour `%s'.\n",
324 ntohs (msg->type),
325 GNUNET_i2s (&n->id));
326
327 GNUNET_assert (NULL == n->env);
328 n->env =
329 GNUNET_MQ_msg_nested_mh (obm, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, msg);
330 n->env_size = ntohs (msg->size);
331 {
332 struct GNUNET_MQ_Envelope *env;
333
334 env = GNUNET_MQ_get_current_envelope (mq);
335 obm->priority = htonl ((uint32_t) GNUNET_MQ_env_get_options (env));
336 }
337 obm->peer = n->id;
338 if (0 == n->ready_window)
339 {
340 LOG (GNUNET_ERROR_TYPE_DEBUG,
341 "Flow control delays transmission to CORE until we see SEND_OK.\n");
342 return; /* can't send yet, need to wait for SEND_OK */
343 }
344 do_send (n);
345}
346
347
348/**
349 * Handle destruction of a message queue. Implementations must not
350 * free @a mq, but should take care of @a impl_state.
351 *
352 * @param mq the message queue to destroy
353 * @param impl_state state of the implementation
354 */
355static void
356mq_destroy_impl (struct GNUNET_MQ_Handle *mq, void *impl_state)
357{
358 struct Neighbour *n = impl_state;
359
360 GNUNET_assert (mq == n->mq);
361 n->mq = NULL;
362}
363
364
365/**
366 * Implementation function that cancels the currently sent message.
367 * Should basically undo whatever #mq_send_impl() did.
368 *
369 * @param mq message queue
370 * @param impl_state state specific to the implementation
371 */
372static void
373mq_cancel_impl (struct GNUNET_MQ_Handle *mq, void *impl_state)
374{
375 struct Neighbour *n = impl_state;
376
377 n->ready_window++;
378 if (GNUNET_YES == n->awaiting_done)
379 {
380 GNUNET_MQ_send_cancel (n->env);
381 n->env = NULL;
382 n->awaiting_done = GNUNET_NO;
383 }
384 else
385 {
386 GNUNET_assert (0 == n->ready_window);
387 n->env = NULL;
388 }
389}
390
391
392/**
393 * We had an error processing a message we forwarded from a peer to
394 * the CORE service. We should just complain about it but otherwise
395 * continue processing.
396 *
397 * @param cls closure
398 * @param error error code
399 */
400static void
401peer_mq_error_handler (void *cls, enum GNUNET_MQ_Error error)
402{
403 /* struct Neighbour *n = cls; */
404
405 GNUNET_break_op (0);
406}
407
408
409/**
410 * Function we use for handling incoming connect messages.
411 *
412 * @param cls closure, a `struct GNUNET_TRANSPORT_Handle *`
413 * @param cim message received
414 */
415static void
416handle_connect (void *cls, const struct ConnectInfoMessage *cim)
417{
418 struct GNUNET_TRANSPORT_CoreHandle *h = cls;
419 struct Neighbour *n;
420
421 LOG (GNUNET_ERROR_TYPE_DEBUG,
422 "Receiving CONNECT message for `%s'\n",
423 GNUNET_i2s (&cim->id));
424 n = neighbour_find (h, &cim->id);
425 if (NULL != n)
426 {
427 GNUNET_break (0);
428 disconnect_and_schedule_reconnect (h);
429 return;
430 }
431 n = GNUNET_new (struct Neighbour);
432 n->id = cim->id;
433 n->h = h;
434 n->ready_window = SEND_WINDOW_SIZE;
435 GNUNET_assert (GNUNET_OK ==
436 GNUNET_CONTAINER_multipeermap_put (
437 h->neighbours,
438 &n->id,
439 n,
440 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
441
442 n->mq = GNUNET_MQ_queue_for_callbacks (&mq_send_impl,
443 &mq_destroy_impl,
444 &mq_cancel_impl,
445 n,
446 h->handlers,
447 &peer_mq_error_handler,
448 n);
449 if (NULL != h->nc_cb)
450 {
451 n->handlers_cls = h->nc_cb (h->cls, &n->id, n->mq);
452 GNUNET_MQ_set_handlers_closure (n->mq, n->handlers_cls);
453 }
454}
455
456
457/**
458 * Function we use for handling incoming disconnect messages.
459 *
460 * @param cls closure, a `struct GNUNET_TRANSPORT_CoreHandle *`
461 * @param dim message received
462 */
463static void
464handle_disconnect (void *cls, const struct DisconnectInfoMessage *dim)
465{
466 struct GNUNET_TRANSPORT_CoreHandle *h = cls;
467 struct Neighbour *n;
468
469 GNUNET_break (ntohl (dim->reserved) == 0);
470 LOG (GNUNET_ERROR_TYPE_DEBUG,
471 "Receiving DISCONNECT message for `%s'.\n",
472 GNUNET_i2s (&dim->peer));
473 n = neighbour_find (h, &dim->peer);
474 if (NULL == n)
475 {
476 GNUNET_break (0);
477 disconnect_and_schedule_reconnect (h);
478 return;
479 }
480 GNUNET_assert (GNUNET_YES == neighbour_delete (h, &dim->peer, n));
481}
482
483
484/**
485 * Function we use for handling incoming send-ok messages.
486 *
487 * @param cls closure, a `struct GNUNET_TRANSPORT_CoreHandle *`
488 * @param okm message received
489 */
490static void
491handle_send_ok (void *cls, const struct SendOkMessage *okm)
492{
493 struct GNUNET_TRANSPORT_CoreHandle *h = cls;
494 struct Neighbour *n;
495
496 LOG (GNUNET_ERROR_TYPE_DEBUG,
497 "Receiving SEND_OK message for transmission to %s\n",
498 GNUNET_i2s (&okm->peer));
499 n = neighbour_find (h, &okm->peer);
500 if (NULL == n)
501 {
502 /* We should never get a 'SEND_OK' for a peer that we are not
503 connected to */
504 GNUNET_break (0);
505 disconnect_and_schedule_reconnect (h);
506 return;
507 }
508 n->ready_window++;
509 if ((NULL != n->env) && (1 == n->ready_window))
510 do_send (n);
511}
512
513
514/**
515 * Function we use for checking incoming "inbound" messages.
516 *
517 * @param cls closure, a `struct GNUNET_TRANSPORT_CoreHandle *`
518 * @param im message received
519 */
520static int
521check_recv (void *cls, const struct InboundMessage *im)
522{
523 const struct GNUNET_MessageHeader *imm;
524 uint16_t size;
525
526 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
527 "check_recv\n");
528 size = ntohs (im->header.size) - sizeof(*im);
529 if (size < sizeof(struct GNUNET_MessageHeader))
530 {
531 GNUNET_break (0);
532 return GNUNET_SYSERR;
533 }
534 imm = (const struct GNUNET_MessageHeader *) &im[1];
535 if (ntohs (imm->size) != size)
536 {
537 GNUNET_break (0);
538 return GNUNET_SYSERR;
539 }
540 return GNUNET_OK;
541}
542
543
544/**
545 * Function we use for handling incoming messages.
546 *
547 * @param cls closure, a `struct GNUNET_TRANSPORT_CoreHandle *`
548 * @param im message received
549 */
550static void
551handle_recv (void *cls, const struct InboundMessage *im)
552{
553 struct GNUNET_TRANSPORT_CoreHandle *h = cls;
554 const struct GNUNET_MessageHeader *imm =
555 (const struct GNUNET_MessageHeader *) &im[1];
556 struct Neighbour *n;
557
558 LOG (GNUNET_ERROR_TYPE_DEBUG,
559 "Received message of type %u with %u bytes from `%s'.\n",
560 (unsigned int) ntohs (imm->type),
561 (unsigned int) ntohs (imm->size),
562 GNUNET_i2s (&im->peer));
563 n = neighbour_find (h, &im->peer);
564 if (NULL == n)
565 {
566 GNUNET_break (0);
567 disconnect_and_schedule_reconnect (h);
568 return;
569 }
570 GNUNET_MQ_inject_message (n->mq, imm);
571}
572
573
574/**
575 * Try again to connect to transport service.
576 *
577 * @param cls the handle to the transport service
578 */
579static void
580reconnect (void *cls)
581{
582 struct GNUNET_TRANSPORT_CoreHandle *h = cls;
583 struct GNUNET_MQ_MessageHandler handlers[] =
584 { GNUNET_MQ_hd_fixed_size (connect,
585 GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT,
586 struct ConnectInfoMessage,
587 h),
588 GNUNET_MQ_hd_fixed_size (disconnect,
589 GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT,
590 struct DisconnectInfoMessage,
591 h),
592 GNUNET_MQ_hd_fixed_size (send_ok,
593 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK,
594 struct SendOkMessage,
595 h),
596 GNUNET_MQ_hd_var_size (recv,
597 GNUNET_MESSAGE_TYPE_TRANSPORT_RECV,
598 struct InboundMessage,
599 h),
600 GNUNET_MQ_handler_end () };
601 struct GNUNET_MQ_Envelope *env;
602 struct StartMessage *s;
603 uint32_t options;
604
605 h->reconnect_task = NULL;
606 LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to transport service.\n");
607 GNUNET_assert (NULL == h->mq);
608 h->mq =
609 GNUNET_CLIENT_connect (h->cfg, "transport", handlers, &mq_error_handler, h);
610 if (NULL == h->mq)
611 return;
612 env = GNUNET_MQ_msg (s, GNUNET_MESSAGE_TYPE_TRANSPORT_START);
613 options = 0;
614 if (h->check_self)
615 options |= 1;
616 if (NULL != h->handlers)
617 options |= 2;
618 s->options = htonl (options);
619 s->self = h->self;
620 GNUNET_MQ_send (h->mq, env);
621}
622
623
624/**
625 * Disconnect from the transport service.
626 *
627 * @param h transport service to reconnect
628 */
629static void
630disconnect (struct GNUNET_TRANSPORT_CoreHandle *h)
631{
632 GNUNET_CONTAINER_multipeermap_iterate (h->neighbours, &neighbour_delete, h);
633 if (NULL != h->mq)
634 {
635 GNUNET_MQ_destroy (h->mq);
636 h->mq = NULL;
637 }
638}
639
640
641/**
642 * Function that will schedule the job that will try
643 * to connect us again to the client.
644 *
645 * @param h transport service to reconnect
646 */
647static void
648disconnect_and_schedule_reconnect (struct GNUNET_TRANSPORT_CoreHandle *h)
649{
650 GNUNET_assert (NULL == h->reconnect_task);
651 disconnect (h);
652 LOG (GNUNET_ERROR_TYPE_DEBUG,
653 "Scheduling task to reconnect to transport service in %s.\n",
654 GNUNET_STRINGS_relative_time_to_string (h->reconnect_delay, GNUNET_YES));
655 h->reconnect_task =
656 GNUNET_SCHEDULER_add_delayed (h->reconnect_delay, &reconnect, h);
657 h->reconnect_delay = GNUNET_TIME_STD_BACKOFF (h->reconnect_delay);
658}
659
660
661/**
662 * Checks if a given peer is connected to us and get the message queue.
663 *
664 * @param handle connection to transport service
665 * @param peer the peer to check
666 * @return NULL if disconnected, otherwise message queue for @a peer
667 */
668struct GNUNET_MQ_Handle *
669GNUNET_TRANSPORT_core_get_mq (struct GNUNET_TRANSPORT_CoreHandle *handle,
670 const struct GNUNET_PeerIdentity *peer)
671{
672 struct Neighbour *n;
673
674 n = neighbour_find (handle, peer);
675 if (NULL == n)
676 return NULL;
677 return n->mq;
678}
679
680
681/**
682 * Notification from the CORE service to the TRANSPORT service
683 * that the CORE service has finished processing a message from
684 * TRANSPORT (via the @code{handlers} of #GNUNET_TRANSPORT_core_connect())
685 * and that it is thus now OK for TRANSPORT to send more messages
686 * for @a pid.
687 *
688 * Used to provide flow control, this is our equivalent to
689 * #GNUNET_SERVICE_client_continue() of an ordinary service.
690 *
691 * Note that due to the use of a window, TRANSPORT may send multiple
692 * messages destined for the same peer even without an intermediate
693 * call to this function. However, CORE must still call this function
694 * once per message received, as otherwise eventually the window will
695 * be full and TRANSPORT will stop providing messages to CORE for @a
696 * pid.
697 *
698 * @param ch core handle
699 * @param pid which peer was the message from that was fully processed by CORE
700 */
701void
702GNUNET_TRANSPORT_core_receive_continue (struct GNUNET_TRANSPORT_CoreHandle *ch,
703 const struct GNUNET_PeerIdentity *pid)
704{
705 struct GNUNET_MQ_Envelope *env;
706 struct RecvOkMessage *rok;
707
708 LOG (GNUNET_ERROR_TYPE_DEBUG,
709 "Message for %s finished CORE processing, sending RECV_OK.\n",
710 GNUNET_i2s (pid));
711 if (NULL == ch->mq)
712 return;
713 env = GNUNET_MQ_msg (rok, GNUNET_MESSAGE_TYPE_TRANSPORT_RECV_OK);
714 rok->increase_window_delta = htonl (1);
715 rok->peer = *pid;
716 GNUNET_MQ_send (ch->mq, env);
717}
718
719
720/**
721 * Connect to the transport service. Note that the connection may
722 * complete (or fail) asynchronously.
723 *
724 * @param cfg configuration to use
725 * @param self our own identity (API should check that it matches
726 * the identity found by transport), or NULL (no check)
727 * @param cls closure for the callbacks
728 * @param rec receive function to call
729 * @param nc function to call on connect events
730 * @param nd function to call on disconnect events
731 * @return NULL on error
732 */
733struct GNUNET_TRANSPORT_CoreHandle *
734GNUNET_TRANSPORT_core_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
735 const struct GNUNET_PeerIdentity *self,
736 const struct GNUNET_MQ_MessageHandler *handlers,
737 void *cls,
738 GNUNET_TRANSPORT_NotifyConnect nc,
739 GNUNET_TRANSPORT_NotifyDisconnect nd)
740{
741 struct GNUNET_TRANSPORT_CoreHandle *h;
742 unsigned int i;
743
744 h = GNUNET_new (struct GNUNET_TRANSPORT_CoreHandle);
745 if (NULL != self)
746 {
747 h->self = *self;
748 h->check_self = GNUNET_YES;
749 }
750 h->cfg = cfg;
751 h->cls = cls;
752 h->nc_cb = nc;
753 h->nd_cb = nd;
754 h->reconnect_delay = GNUNET_TIME_UNIT_ZERO;
755 if (NULL != handlers)
756 {
757 for (i = 0; NULL != handlers[i].cb; i++)
758 ;
759 h->handlers = GNUNET_new_array (i + 1, struct GNUNET_MQ_MessageHandler);
760 GNUNET_memcpy (h->handlers,
761 handlers,
762 i * sizeof(struct GNUNET_MQ_MessageHandler));
763 }
764 LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to transport service\n");
765 reconnect (h);
766 if (NULL == h->mq)
767 {
768 GNUNET_free (h->handlers);
769 GNUNET_free (h);
770 return NULL;
771 }
772 h->neighbours =
773 GNUNET_CONTAINER_multipeermap_create (STARTING_NEIGHBOURS_SIZE, GNUNET_YES);
774 return h;
775}
776
777
778/**
779 * Disconnect from the transport service.
780 *
781 * @param handle handle to the service as returned from
782 * #GNUNET_TRANSPORT_core_connect()
783 */
784void
785GNUNET_TRANSPORT_core_disconnect (struct GNUNET_TRANSPORT_CoreHandle *handle)
786{
787 LOG (GNUNET_ERROR_TYPE_DEBUG, "Transport disconnect called!\n");
788 /* this disconnects all neighbours... */
789 disconnect (handle);
790 /* and now we stop trying to connect again... */
791 if (NULL != handle->reconnect_task)
792 {
793 GNUNET_SCHEDULER_cancel (handle->reconnect_task);
794 handle->reconnect_task = NULL;
795 }
796 GNUNET_CONTAINER_multipeermap_destroy (handle->neighbours);
797 handle->neighbours = NULL;
798 GNUNET_free (handle->handlers);
799 handle->handlers = NULL;
800 GNUNET_free (handle);
801}
802
803
804/* end of transport_api_core.c */
diff --git a/src/transport/transport_api2_monitor.c b/src/transport/transport_api2_monitor.c
deleted file mode 100644
index 67aa1985e..000000000
--- a/src/transport/transport_api2_monitor.c
+++ /dev/null
@@ -1,292 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 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/**
22 * @file transport/transport_api2_monitor.c
23 * @brief implementation of the gnunet_transport_monitor_service.h API
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_protocols.h"
29#include "gnunet_transport_monitor_service.h"
30#include "transport.h"
31
32
33/**
34 * Opaque handle to the transport service for monitors.
35 */
36struct GNUNET_TRANSPORT_MonitorContext
37{
38 /**
39 * Our configuration.
40 */
41 const struct GNUNET_CONFIGURATION_Handle *cfg;
42
43 /**
44 * Queue to talk to the transport service.
45 */
46 struct GNUNET_MQ_Handle *mq;
47
48 /**
49 * Peer we monitor, all zeros for "all"
50 */
51 struct GNUNET_PeerIdentity peer;
52
53 /**
54 * #GNUNET_YES to return the current state and then end.
55 */
56 int one_shot;
57
58 /**
59 * Function to call with monitor data.
60 */
61 GNUNET_TRANSPORT_MonitorCallback cb;
62
63 /**
64 * Closure for @e cb.
65 */
66 void *cb_cls;
67};
68
69
70/**
71 * (re)connect our monitor to the transport service
72 *
73 * @param mc handle to reconnect
74 */
75static void
76reconnect (struct GNUNET_TRANSPORT_MonitorContext *mc);
77
78
79/**
80 * Send message to the transport service about our montoring
81 * desire.
82 *
83 * @param ai address to delete
84 */
85static void
86send_start_monitor (struct GNUNET_TRANSPORT_MonitorContext *mc)
87{
88 struct GNUNET_MQ_Envelope *env;
89 struct GNUNET_TRANSPORT_MonitorStart *smm;
90
91 if (NULL == mc->mq)
92 return;
93 env = GNUNET_MQ_msg (smm, GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_START);
94 smm->one_shot = htonl ((uint32_t) mc->one_shot);
95 smm->peer = mc->peer;
96 GNUNET_MQ_send (mc->mq, env);
97}
98
99
100/**
101 * Disconnect from the transport service.
102 *
103 * @param mc service to disconnect from
104 */
105static void
106disconnect (struct GNUNET_TRANSPORT_MonitorContext *mc)
107{
108 if (NULL == mc->mq)
109 return;
110 GNUNET_MQ_destroy (mc->mq);
111 mc->mq = NULL;
112}
113
114
115/**
116 * Function called on MQ errors. Reconnects to the service.
117 *
118 * @param cls our `struct GNUNET_TRANSPORT_MonitorContext *`
119 * @param error what error happened?
120 */
121static void
122error_handler (void *cls, enum GNUNET_MQ_Error error)
123{
124 struct GNUNET_TRANSPORT_MonitorContext *mc = cls;
125
126 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
127 "MQ failure %d, reconnecting to transport service.\n",
128 error);
129 disconnect (mc);
130 /* TODO: maybe do this with exponential backoff/delay */
131 reconnect (mc);
132}
133
134
135/**
136 * Transport service sends us information about what is going on.
137 * Check if @a md is well-formed.
138 *
139 * @param cls our `struct GNUNET_TRANSPORT_MonitorContext *`
140 * @param md the monitor data we got
141 * @return #GNUNET_OK if @a smt is well-formed
142 */
143static int
144check_monitor_data (void *cls, const struct GNUNET_TRANSPORT_MonitorData *md)
145{
146 (void) cls;
147 GNUNET_MQ_check_zero_termination (md);
148 return GNUNET_OK;
149}
150
151
152/**
153 * Transport service sends us information about what is going on.
154 *
155 * @param cls our `struct GNUNET_TRANSPORT_MonitorContext *`
156 * @param md monitor data
157 */
158static void
159handle_monitor_data (void *cls, const struct GNUNET_TRANSPORT_MonitorData *md)
160{
161 struct GNUNET_TRANSPORT_MonitorContext *mc = cls;
162 struct GNUNET_TRANSPORT_MonitorInformation mi;
163
164 mi.address = (const char *) &md[1];
165 mi.nt = (enum GNUNET_NetworkType) ntohl (md->nt);
166 mi.cs = (enum GNUNET_TRANSPORT_ConnectionStatus) ntohl (md->cs);
167 mi.num_msg_pending = ntohl (md->num_msg_pending);
168 mi.num_bytes_pending = ntohl (md->num_bytes_pending);
169 mi.last_validation = GNUNET_TIME_absolute_ntoh (md->last_validation);
170 mi.valid_until = GNUNET_TIME_absolute_ntoh (md->valid_until);
171 mi.next_validation = GNUNET_TIME_absolute_ntoh (md->next_validation);
172 mi.rtt = GNUNET_TIME_relative_ntoh (md->rtt);
173 mc->cb (mc->cb_cls, &md->peer, &mi);
174}
175
176
177/**
178 * One shot was requested, and transport service is done.
179 *
180 * @param cls our `struct GNUNET_TRANSPORT_MonitorContext *`
181 * @param me end message
182 */
183static void
184handle_monitor_end (void *cls, const struct GNUNET_MessageHeader *me)
185{
186 struct GNUNET_TRANSPORT_MonitorContext *mc = cls;
187
188 if (GNUNET_YES != mc->one_shot)
189 {
190 GNUNET_break (0);
191 disconnect (mc);
192 reconnect (mc);
193 return;
194 }
195 mc->cb (mc->cb_cls, NULL, NULL);
196 GNUNET_TRANSPORT_monitor_cancel (mc);
197}
198
199
200/**
201 * (re)connect our monitor to the transport service
202 *
203 * @param mc handle to reconnect
204 */
205static void
206reconnect (struct GNUNET_TRANSPORT_MonitorContext *mc)
207{
208 struct GNUNET_MQ_MessageHandler handlers[] =
209 { GNUNET_MQ_hd_var_size (monitor_data,
210 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_DATA,
211 struct GNUNET_TRANSPORT_MonitorData,
212 mc),
213 GNUNET_MQ_hd_fixed_size (monitor_end,
214 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_END,
215 struct GNUNET_MessageHeader,
216 mc),
217 GNUNET_MQ_handler_end () };
218
219 mc->mq =
220 GNUNET_CLIENT_connect (mc->cfg, "transport", handlers, &error_handler, mc);
221 if (NULL == mc->mq)
222 return;
223 send_start_monitor (mc);
224}
225
226
227/**
228 * Return information about a specific peer or all peers currently known to
229 * transport service once or in monitoring mode. To obtain information about
230 * a specific peer, a peer identity can be passed. To obtain information about
231 * all peers currently known to transport service, NULL can be passed as peer
232 * identity.
233 *
234 * For each peer, the callback is called with information about the address used
235 * to communicate with this peer, the state this peer is currently in and the
236 * the current timeout for this state.
237 *
238 * Upon completion, the #GNUNET_TRANSPORT_PeerIterateCallback is called one
239 * more time with `NULL`. After this, the operation must no longer be
240 * explicitly canceled.
241 *
242 * The #GNUNET_TRANSPORT_monitor_peers_cancel call MUST not be called in the
243 * the peer_callback!
244 *
245 * @param cfg configuration to use
246 * @param peer a specific peer identity to obtain information for,
247 * NULL for all peers
248 * @param one_shot #GNUNET_YES to return the current state and then end (with NULL+NULL),
249 * #GNUNET_NO to monitor peers continuously
250 * @param cb function to call with the results
251 * @param cb_cls closure for @a mc
252 */
253struct GNUNET_TRANSPORT_MonitorContext *
254GNUNET_TRANSPORT_monitor (const struct GNUNET_CONFIGURATION_Handle *cfg,
255 const struct GNUNET_PeerIdentity *peer,
256 int one_shot,
257 GNUNET_TRANSPORT_MonitorCallback cb,
258 void *cb_cls)
259{
260 struct GNUNET_TRANSPORT_MonitorContext *mc;
261
262 mc = GNUNET_new (struct GNUNET_TRANSPORT_MonitorContext);
263 mc->cfg = cfg;
264 if (NULL != peer)
265 mc->peer = *peer;
266 mc->one_shot = one_shot;
267 mc->cb = cb;
268 mc->cb_cls = cb_cls;
269 reconnect (mc);
270 if (NULL == mc->mq)
271 {
272 GNUNET_free (mc);
273 return NULL;
274 }
275 return mc;
276}
277
278
279/**
280 * Cancel request to monitor peers
281 *
282 * @param pmc handle for the request to cancel
283 */
284void
285GNUNET_TRANSPORT_monitor_cancel (struct GNUNET_TRANSPORT_MonitorContext *mc)
286{
287 disconnect (mc);
288 GNUNET_free (mc);
289}
290
291
292/* end of transport_api2_monitor.c */
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 c7de39ea8..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 msg 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 msg 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_cmd_backchannel_check.c b/src/transport/transport_api_cmd_backchannel_check.c
deleted file mode 100644
index 4ffd96210..000000000
--- a/src/transport/transport_api_cmd_backchannel_check.c
+++ /dev/null
@@ -1,602 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2021 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testing_api_cmd_backchannel_check.c
23 * @brief cmd to start a peer.
24 * @author t3sserakt
25 */
26#include "platform.h"
27#include "gnunet_common.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_testing_ng_lib.h"
30#include "gnunet_testing_netjail_lib.h"
31#include "gnunet_transport_application_service.h"
32#include "gnunet_hello_lib.h"
33#include "gnunet_transport_service.h"
34#include "transport-testing-cmds.h"
35
36/**
37 * Generic logging shortcut
38 */
39#define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__)
40
41#define UDP "udp"
42
43/**
44 * Maximum length allowed for line input.
45 */
46#define MAX_LINE_LENGTH 1024
47
48/**
49 * Struct to store information needed in callbacks.
50 *
51 */
52struct CheckState
53{
54 /**
55 * Context for our asynchronous completion.
56 */
57 struct GNUNET_TESTING_AsyncContext ac;
58
59 /**
60 * The number of the node in a network namespace.
61 */
62 unsigned int node_n;
63
64 /**
65 * The number of the network namespace.
66 */
67 unsigned int namespace_n;
68
69 /**
70 * The testing system of this node.
71 */
72 const struct GNUNET_TESTING_System *tl_system;
73
74 // Label of the cmd which started the test system.
75 const char *create_label;
76
77 /**
78 * Number globally identifying the node.
79 *
80 */
81 uint32_t num;
82
83 /**
84 * Label of the cmd to start a peer.
85 *
86 */
87 const char *start_peer_label;
88
89 /**
90 * The topology of the test setup.
91 */
92 struct GNUNET_TESTING_NetjailTopology *topology;
93
94 /**
95 * Connections to other peers.
96 */
97 struct GNUNET_TESTING_NodeConnection *node_connections_head;
98
99 /**
100 * Number of connections.
101 */
102 unsigned int con_num;
103
104 /**
105 * Number of received backchannel messages.
106 */
107 unsigned int received_backchannel_msgs;
108
109 /**
110 * Array with search strings.
111 */
112 char **search_string;
113
114 /**
115 * File handle for log file.
116 */
117 struct GNUNET_DISK_FileHandle *fh;
118
119 /**
120 * Task which handles the reading
121 */
122 struct GNUNET_SCHEDULER_Task *task;
123
124 /**
125 * Stream to read log file lines.
126 */
127 FILE *stream;
128};
129
130/**
131 *
132 * @param cls The cmd state CheckState.
133 */
134static void
135read_from_log (void *cls)
136{
137 struct CheckState *cs = cls;
138 char line[MAX_LINE_LENGTH + 1];
139 char *search_string;
140
141
142 LOG (GNUNET_ERROR_TYPE_DEBUG,
143 "read_from_log\n");
144
145 cs->fh = GNUNET_DISK_file_open ("test.out",
146 GNUNET_DISK_OPEN_READ,
147 GNUNET_DISK_PERM_USER_READ);
148
149 cs->task = NULL;
150
151 /* read message from line and handle it */
152 cs->stream = fdopen (cs->fh->fd, "r");
153 memset (line, 0, MAX_LINE_LENGTH + 1);
154
155 // fgets (line, MAX_LINE_LENGTH, cs->stream);
156 // while (NULL != line && 0 != strcmp (line, ""))// '\0' != line[0])
157 while (NULL != fgets (line, MAX_LINE_LENGTH, cs->stream))
158 {
159 /*LOG (GNUNET_ERROR_TYPE_DEBUG,
160 "cs->received_backchannel_msgs: %u\n",
161 cs->received_backchannel_msgs);*/
162 /*if (NULL == strstr (line, "line"))
163 LOG (GNUNET_ERROR_TYPE_DEBUG,
164 "line: %s",
165 line);*/
166
167
168 for (int i = 0; i < cs->con_num; i++)
169 {
170 search_string = cs->search_string[i];
171 /*LOG (GNUNET_ERROR_TYPE_DEBUG,
172 "search %u %u: %s %p\n",
173 i,
174 cs->con_num,
175 cs->search_string[i],
176 cs->search_string);
177 fprintf (stderr,
178 line);*/
179 if (NULL != strstr (line,
180 search_string))
181 // "Delivering backchannel message from 4TTC to F7B5 of type 1460 to udp"))
182 // cs->search_string[i]))
183 {
184 cs->received_backchannel_msgs++;
185 LOG (GNUNET_ERROR_TYPE_DEBUG,
186 "received_backchannel_msgs %u con_num %u\n",
187 cs->received_backchannel_msgs,
188 cs->con_num);
189 if (cs->received_backchannel_msgs == cs->con_num)
190 {
191 LOG (GNUNET_ERROR_TYPE_DEBUG,
192 "search finished %lu %lu %u\n",
193 strlen (cs->search_string[i]),
194 strlen (
195 "Delivering backchannel message from 4TTC to F7B5 of type 1460 to udp"),
196 strcmp (
197 "Delivering backchannel message from 4TTC to F7B5 of type 1460 to udp",
198 cs->search_string[i]));
199 GNUNET_TESTING_async_finish (&cs->ac);
200 fclose (cs->stream);
201 return;
202 }
203 }
204 }
205 }
206 LOG (GNUNET_ERROR_TYPE_DEBUG,
207 "read_from_log end\n");
208 fclose (cs->stream);
209 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
210 &read_from_log,
211 cs);
212 /*if (NULL == fgets (line, MAX_LINE_LENGTH, cs->stream))
213 {
214 LOG (GNUNET_ERROR_TYPE_DEBUG,
215 "read null\n");
216 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
217 &read_from_log,
218 cs);
219 return;
220 }*/
221 /*else {
222 cs->task =
223 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
224 cs->fh,
225 &read_from_log,
226 cs);
227
228
229 }*/
230}
231
232
233static enum GNUNET_GenericReturnValue
234will_the_other_node_connect_via_udp (
235 struct CheckState *cs,
236 const struct GNUNET_TESTING_NetjailNode *node)
237// struct GNUNET_TESTING_NodeConnection *connection)
238{
239 // struct GNUNET_TESTING_NetjailTopology *topology = cs->topology;
240 // unsigned int node_n = connection->node_n;
241 // unsigned int namespace_n = connection->namespace_n;
242 // struct GNUNET_HashCode hc;
243 // struct GNUNET_ShortHashCode *key = GNUNET_new (struct GNUNET_ShortHashCode);
244 // struct GNUNET_HashCode hc_namespace;
245 /*struct GNUNET_ShortHashCode *key_namespace = GNUNET_new (struct
246 GNUNET_ShortHashCode);*/
247 // struct GNUNET_TESTING_NetjailNode *node;
248 struct GNUNET_TESTING_NodeConnection *pos_connection;
249 struct GNUNET_TESTING_AddressPrefix *pos_prefix;
250 // struct GNUNET_TESTING_NetjailNamespace *namespace;
251 // struct GNUNET_CONTAINER_MultiShortmap *map;
252
253 /* if (0 == connection->namespace_n) */
254 /* { */
255 /* map = topology->map_globals; */
256 /* } */
257 /* else */
258 /* { */
259 /* GNUNET_CRYPTO_hash (&namespace_n, sizeof(namespace_n), &hc_namespace); */
260 /* memcpy (key_namespace, */
261 /* &hc_namespace, */
262 /* sizeof (*key_namespace)); */
263 /* if (GNUNET_YES == GNUNET_CONTAINER_multishortmap_contains ( */
264 /* topology->map_namespaces, */
265 /* key_namespace)) */
266 /* { */
267 /* namespace = GNUNET_CONTAINER_multishortmap_get (topology->map_namespaces, */
268 /* key_namespace); */
269 /* map = namespace->nodes; */
270 /* } */
271 /* else */
272 /* GNUNET_assert (0); */
273 /* } */
274
275 /* GNUNET_CRYPTO_hash (&node_n, sizeof(node_n), &hc); */
276 /* memcpy (key, */
277 /* &hc, */
278 /* sizeof (*key)); */
279 /* if (GNUNET_YES == GNUNET_CONTAINER_multishortmap_contains ( */
280 /* map, */
281 /* key)) */
282 /* { */
283 /* node = GNUNET_CONTAINER_multishortmap_get (cs->topology->map_globals, */
284 /* key); */
285 /* for (pos_connection = node->node_connections_head; NULL != pos_connection; */
286 /* pos_connection = pos_connection->next) */
287 /* { */
288 /* if ((node->namespace_n == pos_connection->namespace_n) && */
289 /* (node->node_n == pos_connection->node_n) ) */
290 /* { */
291 /* for (pos_prefix = pos_connection->address_prefixes_head; NULL != */
292 /* pos_prefix; */
293 /* pos_prefix = */
294 /* pos_prefix->next) */
295 /* { */
296 /* if (0 == strcmp (UDP, pos_prefix->address_prefix)) */
297 /* { */
298 /* return GNUNET_YES; */
299 /* } */
300 /* } */
301 /* } */
302 /* } */
303 /* } */
304
305 for (pos_connection = node->node_connections_head; NULL != pos_connection;
306 pos_connection = pos_connection->next)
307 {
308 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
309 "connect via udp %u %u %u %u\n",
310 node->namespace_n,
311 cs->namespace_n,
312 node->node_n,
313 cs->node_n);
314 if ((pos_connection->namespace_n == cs->namespace_n) &&
315 (pos_connection->node_n == cs->node_n) )
316 {
317 for (pos_prefix = pos_connection->address_prefixes_head; NULL !=
318 pos_prefix;
319 pos_prefix =
320 pos_prefix->next)
321 {
322 if (0 == strcmp (UDP, pos_prefix->address_prefix))
323 {
324 return GNUNET_YES;
325 }
326 }
327 }
328 }
329
330 return GNUNET_NO;
331}
332
333static void
334add_search_string (struct CheckState *cs, const struct
335 GNUNET_TESTING_NetjailNode *node)
336{
337 unsigned int num;
338 struct GNUNET_PeerIdentity *peer;
339 struct GNUNET_PeerIdentity *us;
340 char *buf;
341 char *part_one = "Delivering backchannel message from ";
342 char *part_two = " to ";
343 char *part_three = " of type 1460 to udp";
344 char *peer_id;
345 char *us_id;
346
347 if (0 == node->namespace_n)
348 num = node->node_n;
349 else
350 num = (node->namespace_n - 1) * cs->topology->nodes_m + node->node_n
351 + cs->topology->nodes_x;
352
353 // num = GNUNET_TESTING_calculate_num (pos_connection, cs->topology);
354 peer = GNUNET_TESTING_get_pub_key (num, cs->tl_system);
355 LOG (GNUNET_ERROR_TYPE_DEBUG,
356 "peer: %s num %u\n",
357 GNUNET_i2s (peer),
358 num);
359 us = GNUNET_TESTING_get_pub_key (cs->num, cs->tl_system);
360 LOG (GNUNET_ERROR_TYPE_DEBUG,
361 "us: %s cs->num %d\n",
362 GNUNET_i2s (us),
363 cs->num);
364
365 GNUNET_asprintf (&peer_id,
366 "%s",
367 GNUNET_i2s (peer));
368 GNUNET_asprintf (&us_id,
369 "%s",
370 GNUNET_i2s (us));
371
372 if (0 < GNUNET_asprintf (&buf,
373 "%s%s%s%s%s",
374 part_one,
375 us_id,
376 part_two,
377 peer_id,
378 part_three))
379 {
380 GNUNET_array_append (cs->search_string,
381 cs->con_num,
382 buf);
383 /*LOG (GNUNET_ERROR_TYPE_DEBUG,
384 "con_num: %u search: %s %p\n",
385 cs->con_num,
386 cs->search_string[cs->con_num - 1],
387 cs->search_string);*/
388 }
389 else
390 GNUNET_assert (0);
391}
392
393
394/**
395 * The run method of this cmd will connect to peers.
396 *
397 */
398static void
399backchannel_check_run (void *cls,
400 struct GNUNET_TESTING_Interpreter *is)
401{
402 struct CheckState *cs = cls;
403 // char *buf;
404 // char *part_one = "Delivering backchannel message from ";
405 // char *part_two = " of type 1460 to udp";
406 const struct GNUNET_TESTING_Command *system_cmd;
407 const struct GNUNET_TESTING_System *tl_system;
408 const struct GNUNET_TESTING_Command *peer1_cmd;
409 const struct GNUNET_TRANSPORT_ApplicationHandle *ah;
410 // struct GNUNET_PeerIdentity *peer;
411 // uint32_t num;
412 // struct GNUNET_TESTING_NodeConnection *pos_connection;
413 // unsigned int con_num = 0;
414 struct GNUNET_CONTAINER_MultiShortmapIterator *node_it;
415 struct GNUNET_CONTAINER_MultiShortmapIterator *namespace_it;
416 struct GNUNET_ShortHashCode node_key;
417 struct GNUNET_ShortHashCode namespace_key;
418 const struct GNUNET_TESTING_NetjailNode *node;
419 const struct GNUNET_TESTING_NetjailNamespace *namespace;
420
421 peer1_cmd = GNUNET_TESTING_interpreter_lookup_command (is,
422 cs->start_peer_label);
423 GNUNET_TRANSPORT_get_trait_application_handle (peer1_cmd,
424 &ah);
425
426 system_cmd = GNUNET_TESTING_interpreter_lookup_command (is,
427 cs->create_label);
428 GNUNET_TESTING_get_trait_test_system (system_cmd,
429 &tl_system);
430
431 cs->tl_system = tl_system;
432
433 cs->node_connections_head = GNUNET_TESTING_get_connections (cs->num,
434 cs->topology);
435
436 LOG (GNUNET_ERROR_TYPE_DEBUG,
437 "check run\n");
438
439
440 node_it = GNUNET_CONTAINER_multishortmap_iterator_create (
441 cs->topology->map_globals);
442
443 while (GNUNET_YES == GNUNET_CONTAINER_multishortmap_iterator_next (node_it,
444 &node_key,
445 (const
446 void**) &
447 node))
448 {
449 LOG (GNUNET_ERROR_TYPE_DEBUG,
450 "namespace_n %u node_n %u\n",
451 node->namespace_n,
452 node->node_n);
453 if (GNUNET_YES == will_the_other_node_connect_via_udp (cs, node))
454 {
455 add_search_string (cs, node);
456 }
457 }
458 namespace_it = GNUNET_CONTAINER_multishortmap_iterator_create (
459 cs->topology->map_namespaces);
460 while (GNUNET_YES == GNUNET_CONTAINER_multishortmap_iterator_next (
461 namespace_it,
462 &namespace_key,
463 (const
464 void**) &namespace))
465 {
466 LOG (GNUNET_ERROR_TYPE_DEBUG,
467 "namespace_n %u\n",
468 node->namespace_n);
469 node_it = GNUNET_CONTAINER_multishortmap_iterator_create (
470 namespace->nodes);
471 while (GNUNET_YES == GNUNET_CONTAINER_multishortmap_iterator_next (node_it,
472 &node_key,
473 (const
474 void**)
475 &node))
476 {
477 LOG (GNUNET_ERROR_TYPE_DEBUG,
478 "namespace_n %u node_n %u\n",
479 node->namespace_n,
480 node->node_n);
481 if (GNUNET_YES == will_the_other_node_connect_via_udp (cs, node))
482 {
483 add_search_string (cs, node);
484 }
485 }
486 }
487 /* for (pos_connection = cs->node_connections_head; NULL != pos_connection; */
488 /* pos_connection = pos_connection->next) */
489 /* { */
490
491 /* if (GNUNET_YES == will_the_other_node_connect_via_udp (cs, node)) */
492 /* { */
493 /* num = GNUNET_TESTING_calculate_num (pos_connection, cs->topology); */
494 /* peer = GNUNET_TESTING_get_pub_key (num, tl_system); */
495 /* LOG (GNUNET_ERROR_TYPE_DEBUG, */
496 /* "peer: %s\n", */
497 /* GNUNET_i2s (peer)); */
498
499 /* if (0 < GNUNET_asprintf (&buf, */
500 /* "%s%s%s", */
501 /* part_one, */
502 /* GNUNET_i2s (peer), */
503 /* part_two)) */
504 /* { */
505 /* GNUNET_array_append (cs->search_string, */
506 /* con_num, */
507 /* buf); */
508 /* /\*LOG (GNUNET_ERROR_TYPE_DEBUG, */
509 /* "con_num: %u search: %s %p\n", */
510 /* con_num, */
511 /* cs->search_string[con_num - 1], */
512 /* cs->search_string);*\/ */
513 /* } */
514 /* else */
515 /* GNUNET_assert (0); */
516 /* } */
517
518
519 /* } */
520 // cs->con_num = con_num;
521 if (0 != cs->con_num)
522 {
523 cs->task =
524 GNUNET_SCHEDULER_add_now (&read_from_log,
525 cs);
526 }
527 else
528 GNUNET_TESTING_async_finish (&cs->ac);
529
530}
531
532
533/**
534 * Trait function of this cmd does nothing.
535 *
536 */
537static int
538backchannel_check_traits (void *cls,
539 const void **ret,
540 const char *trait,
541 unsigned int index)
542{
543 return GNUNET_OK;
544}
545
546
547/**
548 * The cleanup function of this cmd frees resources the cmd allocated.
549 *
550 */
551static void
552backchannel_check_cleanup (void *cls)
553{
554 struct ConnectPeersState *cs = cls;
555
556 GNUNET_free (cs);
557}
558
559
560/**
561 * Create command.
562 *
563 * @param label name for command.
564 * @param start_peer_label Label of the cmd to start a peer.
565 * @param create_label Label of the cmd to create the testing system.
566 * @param num Number globally identifying the node.
567 * @param node_n The number of the node in a network namespace.
568 * @param namespace_n The number of the network namespace.
569 * @param The topology for the test setup.
570 * @return command.
571 */
572struct GNUNET_TESTING_Command
573GNUNET_TRANSPORT_cmd_backchannel_check (const char *label,
574 const char *start_peer_label,
575 const char *create_label,
576 uint32_t num,
577 unsigned int node_n,
578 unsigned int namespace_n,
579 struct GNUNET_TESTING_NetjailTopology *
580 topology)
581{
582 struct CheckState *cs;
583
584 cs = GNUNET_new (struct CheckState);
585 cs->start_peer_label = start_peer_label;
586 cs->num = num;
587 cs->create_label = create_label;
588 cs->topology = topology;
589 cs->node_n = node_n;
590 cs->namespace_n = namespace_n;
591
592 struct GNUNET_TESTING_Command cmd = {
593 .cls = cs,
594 .label = label,
595 .run = &backchannel_check_run,
596 .ac = &cs->ac,
597 .cleanup = &backchannel_check_cleanup,
598 .traits = &backchannel_check_traits
599 };
600
601 return cmd;
602}
diff --git a/src/transport/transport_api_cmd_connecting_peers.c b/src/transport/transport_api_cmd_connecting_peers.c
deleted file mode 100644
index 8aba290c3..000000000
--- a/src/transport/transport_api_cmd_connecting_peers.c
+++ /dev/null
@@ -1,265 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2021 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testing_api_cmd_start_peer.c
23 * @brief cmd to start a peer.
24 * @author t3sserakt
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_testing_ng_lib.h"
29#include "gnunet_testing_netjail_lib.h"
30#include "gnunet_transport_application_service.h"
31#include "gnunet_hello_lib.h"
32#include "gnunet_transport_service.h"
33#include "transport-testing-cmds.h"
34
35/**
36 * Generic logging shortcut
37 */
38#define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__)
39
40/**
41 * The run method of this cmd will connect to peers.
42 *
43 */
44static void
45connect_peers_run (void *cls,
46 struct GNUNET_TESTING_Interpreter *is)
47{
48 struct ConnectPeersState *cps = cls;
49 const struct GNUNET_TESTING_Command *system_cmd;
50 const struct GNUNET_TESTING_System *tl_system;
51
52
53 const struct GNUNET_TESTING_Command *peer1_cmd;
54 const struct GNUNET_TRANSPORT_ApplicationHandle *ah;
55 struct GNUNET_PeerIdentity *peer;
56 char *addr;
57 char *addr_and_port;
58 enum GNUNET_NetworkType nt = 0;
59 uint32_t num;
60 struct GNUNET_TESTING_NodeConnection *pos_connection;
61 struct GNUNET_TESTING_AddressPrefix *pos_prefix;
62 unsigned int con_num = 0;
63 const enum GNUNET_GenericReturnValue *broadcast;
64 char *port;
65
66 cps->is = is;
67 peer1_cmd = GNUNET_TESTING_interpreter_lookup_command (is,
68 cps->start_peer_label);
69 GNUNET_TRANSPORT_get_trait_application_handle (peer1_cmd,
70 &ah);
71 GNUNET_TRANSPORT_get_trait_broadcast (peer1_cmd,
72 &broadcast);
73
74 system_cmd = GNUNET_TESTING_interpreter_lookup_command (is,
75 cps->create_label);
76 GNUNET_TESTING_get_trait_test_system (system_cmd,
77 &tl_system);
78
79 cps->tl_system = tl_system;
80
81 LOG (GNUNET_ERROR_TYPE_DEBUG,
82 "cps->num: %u \n",
83 cps->num);
84
85 cps->node_connections_head = GNUNET_TESTING_get_connections (cps->num,
86 cps->topology);
87
88 for (pos_connection = cps->node_connections_head; NULL != pos_connection;
89 pos_connection = pos_connection->next)
90 {
91 con_num++;
92 num = GNUNET_TESTING_calculate_num (pos_connection, cps->topology);
93 for (pos_prefix = pos_connection->address_prefixes_head; NULL != pos_prefix;
94 pos_prefix =
95 pos_prefix->next)
96 {
97 addr = GNUNET_TESTING_get_address (pos_connection,
98 pos_prefix->address_prefix);
99 if (NULL != addr)
100 {
101 if (0 == GNUNET_memcmp (pos_prefix->address_prefix, "udp"))
102 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
103 "validating memcmp\n");
104 if (GNUNET_YES == *broadcast)
105 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
106 "validating broadcast\n");
107 if ((0 == GNUNET_memcmp (pos_prefix->address_prefix, "udp")) &&
108 (GNUNET_YES == *broadcast) )
109 GNUNET_asprintf (&addr_and_port,
110 "%s:2086",
111 addr);
112 else
113 GNUNET_asprintf (&addr_and_port,
114 "%s:60002",
115 addr);
116 peer = GNUNET_TESTING_get_pub_key (num, tl_system);
117 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
118 "validating peer number %u with identity %s and address %s %u %s\n",
119 num,
120 GNUNET_i2s (peer),
121 addr_and_port,
122 *broadcast,
123 pos_prefix->address_prefix);
124 GNUNET_TRANSPORT_application_validate ((struct
125 GNUNET_TRANSPORT_ApplicationHandle
126 *) ah,
127 peer,
128 nt,
129 addr_and_port);
130 GNUNET_free (peer);
131 GNUNET_free (addr);
132 GNUNET_free (addr_and_port);
133 }
134 }
135 }
136 cps->con_num = con_num;
137}
138
139
140/**
141 * Callback from start peer cmd for signaling a peer got connected.
142 *
143 */
144static void *
145notify_connect (struct GNUNET_TESTING_Interpreter *is,
146 const struct GNUNET_PeerIdentity *peer)
147{
148 const struct GNUNET_TESTING_Command *cmd;
149 struct ConnectPeersState *cps;
150 struct GNUNET_PeerIdentity *peer_connection;
151 struct GNUNET_TESTING_NodeConnection *pos_connection;
152 unsigned int num;
153 unsigned int con_num;
154 void *ret = NULL;
155
156 cmd = GNUNET_TESTING_interpreter_lookup_command_all (is,
157 "connect-peers");
158 cps = cmd->cls;
159 con_num = cps->con_num_notified;
160 for (pos_connection = cps->node_connections_head; NULL != pos_connection;
161 pos_connection = pos_connection->next)
162 {
163 num = GNUNET_TESTING_calculate_num (pos_connection, cps->topology);
164 peer_connection = GNUNET_TESTING_get_pub_key (num, cps->tl_system);
165 if (0 == GNUNET_memcmp (peer,
166 peer_connection))
167 cps->con_num_notified++;
168 GNUNET_free (peer_connection);
169 }
170 if (cps->con_num == con_num)
171 cps->additional_connects_notified++;
172
173 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
174 "con_num: %u add: %u num_notified: %u add_notified: %u\n",
175 cps->con_num,
176 cps->additional_connects,
177 cps->con_num_notified,
178 cps->additional_connects_notified);
179 if (cps->con_num + cps->additional_connects == cps->con_num_notified
180 + cps->additional_connects_notified)
181 {
182 GNUNET_TESTING_async_finish (&cps->ac);
183 }
184 return ret;
185}
186
187
188/**
189 * The cleanup function of this cmd frees resources the cmd allocated.
190 *
191 */
192static void
193connect_peers_cleanup (void *cls)
194{
195 struct ConnectPeersState *cps = cls;
196
197 GNUNET_free (cps);
198}
199
200
201/**
202 * This function prepares an array with traits.
203 *
204 */
205enum GNUNET_GenericReturnValue
206connect_peers_traits (void *cls,
207 const void **ret,
208 const char *trait,
209 unsigned int index)
210{
211 struct ConnectPeersState *cps = cls;
212 struct GNUNET_TESTING_Trait traits[] = {
213 GNUNET_TRANSPORT_make_trait_connect_peer_state ((const void *) cps),
214 GNUNET_TESTING_trait_end ()
215 };
216 return GNUNET_TESTING_get_trait (traits,
217 ret,
218 trait,
219 index);
220}
221
222
223/**
224 * Create command
225 *
226 * @param label name for command
227 * @param start_peer_label Label of the cmd to start a peer.
228 * @param create_peer_label Label of the cmd which started the test system.
229 * @param num Number globally identifying the node.
230 * @param The topology for the test setup.
231 * @param additional_connects Number of additional connects this cmd will wait for not triggered by this cmd.
232 * @return command.
233 */
234struct GNUNET_TESTING_Command
235GNUNET_TRANSPORT_cmd_connect_peers (const char *label,
236 const char *start_peer_label,
237 const char *create_label,
238 uint32_t num,
239 struct GNUNET_TESTING_NetjailTopology *
240 topology,
241 unsigned int additional_connects)
242{
243 struct ConnectPeersState *cps;
244
245 cps = GNUNET_new (struct ConnectPeersState);
246 cps->start_peer_label = start_peer_label;
247 cps->num = num;
248 cps->create_label = create_label;
249 cps->topology = topology;
250 cps->notify_connect = notify_connect;
251 cps->additional_connects = additional_connects;
252
253 {
254 struct GNUNET_TESTING_Command cmd = {
255 .cls = cps,
256 .label = label,
257 .run = &connect_peers_run,
258 .ac = &cps->ac,
259 .cleanup = &connect_peers_cleanup,
260 .traits = &connect_peers_traits
261 };
262
263 return cmd;
264 }
265}
diff --git a/src/transport/transport_api_cmd_send_simple.c b/src/transport/transport_api_cmd_send_simple.c
deleted file mode 100644
index ade0cc914..000000000
--- a/src/transport/transport_api_cmd_send_simple.c
+++ /dev/null
@@ -1,212 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2021 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testing_api_cmd_start_peer.c
23 * @brief cmd to start a peer.
24 * @author t3sserakt
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_testing_ng_lib.h"
29#include "gnunet_testing_netjail_lib.h"
30#include "transport-testing2.h"
31#include "transport-testing-cmds.h"
32
33/**
34 * Generic logging shortcut
35 */
36#define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__)
37
38/**
39 * Struct to hold information for callbacks.
40 *
41 */
42struct SendSimpleState
43{
44 /**
45 * Number globally identifying the node.
46 *
47 */
48 uint32_t num;
49
50 /**
51 * Label of the cmd to start a peer.
52 *
53 */
54 const char *start_peer_label;
55
56 /**
57 * Label of the cmd which started the test system.
58 *
59 */
60 const char *create_label;
61
62 /**
63 * The topology we get the connected nodes from.
64 */
65 struct GNUNET_TESTING_NetjailTopology *topology;
66};
67
68
69/**
70 * The cleanup function of this cmd frees resources the cmd allocated.
71 *
72 */
73static void
74send_simple_cleanup (void *cls)
75{
76 struct SendSimpleState *sss = cls;
77
78 GNUNET_free (sss);
79}
80
81
82static int
83send_simple_cb (void *cls,
84 const struct GNUNET_ShortHashCode *key,
85 void *value)
86{
87 struct SendSimpleState *sss = cls;
88 struct GNUNET_MQ_Handle *mq = value;
89 struct GNUNET_MQ_Envelope *env;
90 struct GNUNET_TRANSPORT_TESTING_TestMessage *test;
91
92 LOG (GNUNET_ERROR_TYPE_DEBUG,
93 "Sending simple test message\n");
94
95 env = GNUNET_MQ_msg_extra (test,
96 1000 - sizeof(*test),
97 GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE);
98 test->num = htonl (sss->num);
99 memset (&test[1],
100 sss->num,
101 1000 - sizeof(*test));
102 GNUNET_MQ_send (mq,
103 env);
104 return GNUNET_OK;
105}
106
107
108/**
109 * The run method of this cmd will send a simple message to the connected peers.
110 *
111 */
112static void
113send_simple_run (void *cls,
114 struct GNUNET_TESTING_Interpreter *is)
115{
116 struct SendSimpleState *sss = cls;
117 const struct GNUNET_CONTAINER_MultiShortmap *connected_peers_map;
118 const struct GNUNET_TESTING_Command *peer1_cmd;
119 // struct GNUNET_ShortHashCode *key = GNUNET_new (struct GNUNET_ShortHashCode);
120 struct GNUNET_HashCode hc;
121 struct GNUNET_TESTING_NodeConnection *node_connections_head;
122 struct GNUNET_PeerIdentity *peer;
123 struct GNUNET_CRYPTO_EddsaPublicKey public_key;
124 uint32_t num;
125 struct GNUNET_TESTING_NodeConnection *pos_connection;
126 const struct GNUNET_TESTING_Command *system_cmd;
127 const struct GNUNET_TESTING_System *tl_system;
128
129 peer1_cmd = GNUNET_TESTING_interpreter_lookup_command (is,
130 sss->start_peer_label);
131 GNUNET_TRANSPORT_get_trait_connected_peers_map (peer1_cmd,
132 &connected_peers_map);
133
134 system_cmd = GNUNET_TESTING_interpreter_lookup_command (is,
135 sss->create_label);
136 GNUNET_TESTING_get_trait_test_system (system_cmd,
137 &tl_system);
138
139 node_connections_head = GNUNET_TESTING_get_connections (sss->num,
140 sss->topology);
141
142 GNUNET_CONTAINER_multishortmap_iterate (
143 (struct GNUNET_CONTAINER_MultiShortmap *)
144 connected_peers_map, send_simple_cb,
145 sss);
146 /*for (int i = 0; i < 1; i++)
147 {
148 for (pos_connection = node_connections_head; NULL != pos_connection;
149 pos_connection = pos_connection->next)
150 {
151 num = GNUNET_TESTING_calculate_num (pos_connection, sss->topology);
152 peer = GNUNET_TESTING_get_pub_key (num, tl_system);
153 public_key = peer->public_key;
154 GNUNET_CRYPTO_hash (&public_key, sizeof(public_key), &hc);
155
156 memcpy (key,
157 &hc,
158 sizeof (*key));
159 mq = GNUNET_CONTAINER_multishortmap_get (connected_peers_map,
160 key);
161 env = GNUNET_MQ_msg_extra (test,
162 1000 - sizeof(*test),
163 GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE);
164 test->num = htonl (sss->num);
165 memset (&test[1],
166 sss->num,
167 1000 - sizeof(*test));
168 GNUNET_MQ_send (mq,
169 env);
170 }
171 }*/
172
173 // GNUNET_free (key);
174
175}
176
177
178/**
179 * Create command.
180 *
181 * @param label name for command.
182 * @param start_peer_label Label of the cmd to start a peer.
183 * @param start_peer_label Label of the cmd which started the test system.
184 * @param num Number globally identifying the node.
185 * @param The topology for the test setup.
186 * @return command.
187 */
188struct GNUNET_TESTING_Command
189GNUNET_TRANSPORT_cmd_send_simple (const char *label,
190 const char *start_peer_label,
191 const char *create_label,
192 uint32_t num,
193 struct GNUNET_TESTING_NetjailTopology *
194 topology)
195{
196 struct SendSimpleState *sss;
197
198 sss = GNUNET_new (struct SendSimpleState);
199 sss->num = num;
200 sss->start_peer_label = start_peer_label;
201 sss->create_label = create_label;
202 sss->topology = topology;
203
204 struct GNUNET_TESTING_Command cmd = {
205 .cls = sss,
206 .label = label,
207 .run = &send_simple_run,
208 .cleanup = &send_simple_cleanup
209 };
210
211 return cmd;
212}
diff --git a/src/transport/transport_api_cmd_start_peer.c b/src/transport/transport_api_cmd_start_peer.c
deleted file mode 100644
index 7448eff5a..000000000
--- a/src/transport/transport_api_cmd_start_peer.c
+++ /dev/null
@@ -1,491 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2021 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testing_api_cmd_start_peer.c
23 * @brief cmd to start a peer.
24 * @author t3sserakt
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_testing_ng_lib.h"
29#include "gnunet_testing_netjail_lib.h"
30#include "gnunet_peerstore_service.h"
31#include "gnunet_transport_core_service.h"
32#include "gnunet_transport_application_service.h"
33#include "transport-testing-cmds.h"
34
35/**
36 * Generic logging shortcut
37 */
38#define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__)
39
40
41static void
42retrieve_hello (void *cls);
43
44
45/**
46 * Callback delivering the hello of this peer from peerstore.
47 *
48 */
49static void
50hello_iter_cb (void *cb_cls,
51 const struct GNUNET_PEERSTORE_Record *record,
52 const char *emsg)
53{
54 struct StartPeerState *sps = cb_cls;
55 if (NULL == record)
56 {
57 sps->pic = NULL;
58 sps->rh_task = GNUNET_SCHEDULER_add_now (retrieve_hello, sps);
59 return;
60 }
61 // Check record type et al?
62 sps->hello_size = record->value_size;
63 sps->hello = GNUNET_malloc (sps->hello_size);
64 memcpy (sps->hello, record->value, sps->hello_size);
65 sps->hello[sps->hello_size - 1] = '\0';
66
67 GNUNET_PEERSTORE_iterate_cancel (sps->pic);
68 sps->pic = NULL;
69 GNUNET_TESTING_async_finish (&sps->ac);
70}
71
72
73/**
74 * Function to start the retrieval task to retrieve the hello of this peer
75 * from the peerstore.
76 *
77 */
78static void
79retrieve_hello (void *cls)
80{
81 struct StartPeerState *sps = cls;
82 sps->rh_task = NULL;
83 sps->pic = GNUNET_PEERSTORE_iterate (sps->ph,
84 "transport",
85 &sps->id,
86 GNUNET_PEERSTORE_TRANSPORT_HELLO_KEY,
87 hello_iter_cb,
88 sps);
89
90}
91
92
93/**
94 * Disconnect callback for the connection to the core service.
95 *
96 */
97static void
98notify_disconnect (void *cls,
99 const struct GNUNET_PeerIdentity *peer,
100 void *handler_cls)
101{
102 struct StartPeerState *sps = cls;
103
104 LOG (GNUNET_ERROR_TYPE_DEBUG,
105 "Peer %s disconnected from peer %u (`%s')\n",
106 GNUNET_i2s (peer),
107 sps->no,
108 GNUNET_i2s (&sps->id));
109
110}
111
112
113/**
114 * Connect callback for the connection to the core service.
115 *
116 */
117static void *
118notify_connect (void *cls,
119 const struct GNUNET_PeerIdentity *peer,
120 struct GNUNET_MQ_Handle *mq)
121{
122 struct StartPeerState *sps = cls;
123 struct GNUNET_ShortHashCode *key = GNUNET_new (struct GNUNET_ShortHashCode);
124 struct GNUNET_HashCode hc;
125 struct GNUNET_CRYPTO_EddsaPublicKey public_key = peer->public_key;
126
127 void *ret = (struct GNUNET_PeerIdentity *) peer;
128
129 LOG (GNUNET_ERROR_TYPE_DEBUG,
130 "This Peer %s \n",
131 GNUNET_i2s (&sps->id));
132 LOG (GNUNET_ERROR_TYPE_DEBUG,
133 "Peer %s connected to peer number %u\n",
134 GNUNET_i2s (peer),
135 sps->no);
136
137 GNUNET_CRYPTO_hash (&public_key, sizeof(public_key), &hc);
138
139
140 memcpy (key,
141 &hc,
142 sizeof (*key));
143 GNUNET_CONTAINER_multishortmap_put (sps->connected_peers_map,
144 key,
145 mq,
146 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
147
148 GNUNET_free (key);
149
150 sps->notify_connect (sps->ac.is,
151 peer);
152
153 return ret;
154}
155
156
157/**
158 * The run method of this cmd will start all services of a peer to test the transport service.
159 *
160 */
161static void
162start_peer_run (void *cls,
163 struct GNUNET_TESTING_Interpreter *is)
164{
165 struct StartPeerState *sps = cls;
166 char *emsg = NULL;
167 struct GNUNET_PeerIdentity dummy;
168 const struct GNUNET_TESTING_Command *system_cmd;
169 const struct GNUNET_TESTING_System *tl_system;
170 char *home;
171 char *transport_unix_path;
172 char *tcp_communicator_unix_path;
173 char *udp_communicator_unix_path;
174 char *bindto;
175 char *bindto_udp;
176
177 if (GNUNET_NO == GNUNET_DISK_file_test (sps->cfgname))
178 {
179 LOG (GNUNET_ERROR_TYPE_ERROR,
180 "File not found: `%s'\n",
181 sps->cfgname);
182 GNUNET_TESTING_interpreter_fail (is);
183 return;
184 }
185
186
187 sps->cfg = GNUNET_CONFIGURATION_create ();
188 GNUNET_assert (GNUNET_OK ==
189 GNUNET_CONFIGURATION_load (sps->cfg, sps->cfgname));
190
191 GNUNET_asprintf (&home,
192 "$GNUNET_TMP/test-transport/api-tcp-p%u",
193 sps->no);
194
195 GNUNET_asprintf (&transport_unix_path,
196 "$GNUNET_RUNTIME_DIR/tng-p%u.sock",
197 sps->no);
198
199 GNUNET_asprintf (&tcp_communicator_unix_path,
200 "$GNUNET_RUNTIME_DIR/tcp-comm-p%u.sock",
201 sps->no);
202
203 GNUNET_asprintf (&udp_communicator_unix_path,
204 "$GNUNET_RUNTIME_DIR/tcp-comm-p%u.sock",
205 sps->no);
206
207 GNUNET_asprintf (&bindto,
208 "%s:60002",
209 sps->node_ip);
210
211 GNUNET_asprintf (&bindto_udp,
212 "2086");
213
214 LOG (GNUNET_ERROR_TYPE_DEBUG,
215 "node_ip %s\n",
216 bindto);
217
218 LOG (GNUNET_ERROR_TYPE_DEBUG,
219 "bind_udp %s\n",
220 GNUNET_YES == sps->broadcast ?
221 bindto_udp : bindto);
222
223 GNUNET_CONFIGURATION_set_value_string (sps->cfg, "PATHS", "GNUNET_TEST_HOME",
224 home);
225 GNUNET_CONFIGURATION_set_value_string (sps->cfg, "transport", "UNIXPATH",
226 transport_unix_path);
227 GNUNET_CONFIGURATION_set_value_string (sps->cfg, "communicator-tcp",
228 "BINDTO",
229 bindto);
230 GNUNET_CONFIGURATION_set_value_string (sps->cfg, "communicator-udp",
231 "BINDTO",
232 GNUNET_YES == sps->broadcast ?
233 bindto_udp : bindto);
234 GNUNET_CONFIGURATION_set_value_string (sps->cfg, "communicator-tcp",
235 "UNIXPATH",
236 tcp_communicator_unix_path);
237 GNUNET_CONFIGURATION_set_value_string (sps->cfg, "communicator-udp",
238 "UNIXPATH",
239 udp_communicator_unix_path);
240
241 system_cmd = GNUNET_TESTING_interpreter_lookup_command (is,
242 sps->system_label);
243 GNUNET_TESTING_get_trait_test_system (system_cmd,
244 &tl_system);
245
246 sps->tl_system = tl_system;
247
248 LOG (GNUNET_ERROR_TYPE_DEBUG,
249 "Creating testing library with key number %u\n",
250 sps->no);
251
252 if (GNUNET_SYSERR ==
253 GNUNET_TESTING_configuration_create ((struct
254 GNUNET_TESTING_System *) tl_system,
255 sps->cfg))
256 {
257 LOG (GNUNET_ERROR_TYPE_DEBUG,
258 "Testing library failed to create unique configuration based on `%s'\n",
259 sps->cfgname);
260 GNUNET_CONFIGURATION_destroy (sps->cfg);
261 GNUNET_TESTING_interpreter_fail (is);
262 return;
263 }
264
265 sps->peer = GNUNET_TESTING_peer_configure ((struct
266 GNUNET_TESTING_System *) sps->
267 tl_system,
268 sps->cfg,
269 sps->no,
270 NULL,
271 &emsg);
272 if (NULL == sps->peer)
273 {
274 LOG (GNUNET_ERROR_TYPE_ERROR,
275 "Testing library failed to create unique configuration based on `%s': `%s' with key number %u\n",
276 sps->cfgname,
277 emsg,
278 sps->no);
279 GNUNET_free (emsg);
280 GNUNET_TESTING_interpreter_fail (is);
281 return;
282 }
283
284 if (GNUNET_OK != GNUNET_TESTING_peer_start (sps->peer))
285 {
286 LOG (GNUNET_ERROR_TYPE_ERROR,
287 "Testing library failed to create unique configuration based on `%s'\n",
288 sps->cfgname);
289 GNUNET_free (emsg);
290 GNUNET_TESTING_interpreter_fail (is);
291 return;
292 }
293
294 memset (&dummy,
295 '\0',
296 sizeof(dummy));
297
298 GNUNET_TESTING_peer_get_identity (sps->peer,
299 &sps->id);
300
301 if (0 == memcmp (&dummy,
302 &sps->id,
303 sizeof(struct GNUNET_PeerIdentity)))
304 {
305 LOG (GNUNET_ERROR_TYPE_ERROR,
306 "Testing library failed to obtain peer identity for peer %u\n",
307 sps->no);
308 GNUNET_free (emsg);
309 GNUNET_TESTING_interpreter_fail (is);
310 return;
311 }
312 LOG (GNUNET_ERROR_TYPE_DEBUG,
313 "Peer %u configured with identity `%s'\n",
314 sps->no,
315 GNUNET_i2s_full (&sps->id));
316
317 sps->th = GNUNET_TRANSPORT_core_connect (sps->cfg,
318 NULL,
319 sps->handlers,
320 sps,
321 &notify_connect,
322 &notify_disconnect);
323 if (NULL == sps->th)
324 {
325 LOG (GNUNET_ERROR_TYPE_ERROR,
326 "Failed to connect to transport service for peer `%s': `%s'\n",
327 sps->cfgname,
328 emsg);
329 GNUNET_free (emsg);
330 GNUNET_TESTING_interpreter_fail (is);
331 return;
332 }
333
334 sps->ph = GNUNET_PEERSTORE_connect (sps->cfg);
335 if (NULL == sps->th)
336 {
337 LOG (GNUNET_ERROR_TYPE_ERROR,
338 "Failed to connect to peerstore service for peer `%s': `%s'\n",
339 sps->cfgname,
340 emsg);
341 GNUNET_free (emsg);
342 GNUNET_TESTING_interpreter_fail (is);
343 return;
344 }
345
346 sps->ah = GNUNET_TRANSPORT_application_init (sps->cfg);
347 if (NULL == sps->ah)
348 {
349 LOG (GNUNET_ERROR_TYPE_ERROR,
350 "Failed to initialize the TRANSPORT application suggestion client handle for peer `%s': `%s'\n",
351 sps->cfgname,
352 emsg);
353 GNUNET_free (emsg);
354 GNUNET_TESTING_interpreter_fail (is);
355 return;
356 }
357 sps->rh_task = GNUNET_SCHEDULER_add_now (retrieve_hello, sps);
358 GNUNET_free (home);
359 GNUNET_free (transport_unix_path);
360 GNUNET_free (tcp_communicator_unix_path);
361 GNUNET_free (udp_communicator_unix_path);
362 GNUNET_free (bindto);
363 GNUNET_free (bindto_udp);
364}
365
366
367/**
368 * The cleanup function of this cmd frees resources the cmd allocated.
369 *
370 */
371static void
372start_peer_cleanup (void *cls)
373{
374 struct StartPeerState *sps = cls;
375
376 if (NULL != sps->handlers)
377 {
378 GNUNET_free (sps->handlers);
379 sps->handlers = NULL;
380 }
381 if (NULL != sps->cfg)
382 {
383 GNUNET_CONFIGURATION_destroy (sps->cfg);
384 sps->cfg = NULL;
385 }
386 GNUNET_free (sps->hello);
387 GNUNET_free (sps->connected_peers_map);
388 GNUNET_free (sps);
389}
390
391
392/**
393 * This function prepares an array with traits.
394 *
395 */
396static int
397start_peer_traits (void *cls,
398 const void **ret,
399 const char *trait,
400 unsigned int index)
401{
402 struct StartPeerState *sps = cls;
403 struct GNUNET_TRANSPORT_ApplicationHandle *ah = sps->ah;
404 struct GNUNET_PeerIdentity *id = &sps->id;
405 struct GNUNET_CONTAINER_MultiShortmap *connected_peers_map =
406 sps->connected_peers_map;
407 char *hello = sps->hello;
408 size_t hello_size = sps->hello_size;
409
410
411 struct GNUNET_TESTING_Trait traits[] = {
412 GNUNET_TRANSPORT_make_trait_application_handle ((const void *) ah),
413 GNUNET_TRANSPORT_make_trait_peer_id ((const void *) id),
414 GNUNET_TRANSPORT_make_trait_connected_peers_map ((const
415 void *)
416 connected_peers_map),
417 GNUNET_TRANSPORT_make_trait_hello ((const void *) hello),
418 GNUNET_TRANSPORT_make_trait_hello_size ((const void *) hello_size),
419 GNUNET_TRANSPORT_make_trait_state ((const void *) sps),
420 GNUNET_TRANSPORT_make_trait_broadcast ((const void *) &sps->broadcast),
421 GNUNET_TESTING_trait_end ()
422 };
423
424 return GNUNET_TESTING_get_trait (traits,
425 ret,
426 trait,
427 index);
428}
429
430
431/**
432 * Create command.
433 *
434 * @param label name for command.
435 * @param system_label Label of the cmd to setup a test environment.
436 * @param m The number of the local node of the actual network namespace.
437 * @param n The number of the actual namespace.
438 * @param local_m Number of local nodes in each namespace.
439 * @param handlers Handler for messages received by this peer.
440 * @param cfgname Configuration file name for this peer.
441 * @param notify_connect Method which will be called, when a peer connects.
442 * @param broadcast Flag indicating, if broadcast should be switched on.
443 * @return command.
444 */
445struct GNUNET_TESTING_Command
446GNUNET_TRANSPORT_cmd_start_peer (const char *label,
447 const char *system_label,
448 uint32_t no,
449 char *node_ip,
450 struct GNUNET_MQ_MessageHandler *handlers,
451 const char *cfgname,
452 GNUNET_TRANSPORT_notify_connect_cb
453 notify_connect,
454 unsigned int broadcast)
455{
456 struct StartPeerState *sps;
457 struct GNUNET_CONTAINER_MultiShortmap *connected_peers_map =
458 GNUNET_CONTAINER_multishortmap_create (1,GNUNET_NO);
459 unsigned int i;
460
461 sps = GNUNET_new (struct StartPeerState);
462 sps->no = no;
463 sps->system_label = system_label;
464 sps->connected_peers_map = connected_peers_map;
465 sps->cfgname = cfgname;
466 sps->node_ip = node_ip;
467 sps->notify_connect = notify_connect;
468 sps->broadcast = broadcast;
469
470 if (NULL != handlers)
471 {
472 for (i = 0; NULL != handlers[i].cb; i++)
473 ;
474 sps->handlers = GNUNET_new_array (i + 1,
475 struct GNUNET_MQ_MessageHandler);
476 GNUNET_memcpy (sps->handlers,
477 handlers,
478 i * sizeof(struct GNUNET_MQ_MessageHandler));
479 }
480
481 struct GNUNET_TESTING_Command cmd = {
482 .cls = sps,
483 .label = label,
484 .run = &start_peer_run,
485 .ac = &sps->ac,
486 .cleanup = &start_peer_cleanup,
487 .traits = &start_peer_traits
488 };
489
490 return cmd;
491}
diff --git a/src/transport/transport_api_cmd_stop_peer.c b/src/transport/transport_api_cmd_stop_peer.c
deleted file mode 100644
index 4ca730add..000000000
--- a/src/transport/transport_api_cmd_stop_peer.c
+++ /dev/null
@@ -1,156 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2021 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testing_api_cmd_stop_peer.c
23 * @brief cmd to stop a peer.
24 * @author t3sserakt
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_testing_ng_lib.h"
29#include "gnunet_testing_netjail_lib.h"
30#include "gnunet_peerstore_service.h"
31#include "gnunet_transport_core_service.h"
32#include "gnunet_transport_application_service.h"
33#include "transport-testing-cmds.h"
34
35/**
36 * Generic logging shortcut
37 */
38#define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__)
39
40
41/**
42 * Struct to hold information for callbacks.
43 *
44 */
45struct StopPeerState
46{
47 // Label of the cmd to start the peer.
48 const char *start_label;
49};
50
51
52/**
53 * The run method of this cmd will stop all services of a peer which were used to test the transport service.
54 *
55 */
56static void
57stop_peer_run (void *cls,
58 struct GNUNET_TESTING_Interpreter *is)
59{
60 struct StopPeerState *stop_ps = cls;
61 const struct StartPeerState *sps;
62 const struct GNUNET_TESTING_Command *start_cmd;
63
64 start_cmd = GNUNET_TESTING_interpreter_lookup_command (is,
65 stop_ps->start_label);
66 GNUNET_TRANSPORT_get_trait_state (start_cmd,
67 &sps);
68
69 if (NULL != sps->pic)
70 {
71 GNUNET_PEERSTORE_iterate_cancel (sps->pic);
72 }
73 if (NULL != sps->th)
74 {
75 GNUNET_TRANSPORT_core_disconnect (sps->th);
76 }
77 if (NULL != sps->ah)
78 {
79 GNUNET_TRANSPORT_application_done (sps->ah);
80 }
81 if (NULL != sps->ph)
82 {
83 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
84 "Disconnecting from PEERSTORE service\n");
85 GNUNET_PEERSTORE_disconnect (sps->ph, GNUNET_NO);
86 }
87 if (NULL != sps->peer)
88 {
89 if (GNUNET_OK !=
90 GNUNET_TESTING_peer_stop (sps->peer))
91 {
92 LOG (GNUNET_ERROR_TYPE_ERROR,
93 "Testing lib failed to stop peer %u (`%s')\n",
94 sps->no,
95 GNUNET_i2s (&sps->id));
96 }
97 GNUNET_TESTING_peer_destroy (sps->peer);
98 }
99 if (NULL != sps->rh_task)
100 GNUNET_SCHEDULER_cancel (sps->rh_task);
101}
102
103
104/**
105 * The cleanup function of this cmd frees resources the cmd allocated.
106 *
107 */
108static void
109stop_peer_cleanup (void *cls)
110{
111 struct StopPeerState *sps = cls;
112
113 GNUNET_free (sps);
114}
115
116
117/**
118 * Trait function of this cmd does nothing.
119 *
120 */
121static int
122stop_peer_traits (void *cls,
123 const void **ret,
124 const char *trait,
125 unsigned int index)
126{
127 return GNUNET_OK;
128}
129
130
131/**
132 * Create command.
133 *
134 * @param label name for command.
135 * @param start_label Label of the cmd to start the peer.
136 * @return command.
137 */
138struct GNUNET_TESTING_Command
139GNUNET_TRANSPORT_cmd_stop_peer (const char *label,
140 const char *start_label)
141{
142 struct StopPeerState *sps;
143
144 sps = GNUNET_new (struct StopPeerState);
145 sps->start_label = start_label;
146 {
147 struct GNUNET_TESTING_Command cmd = {
148 .cls = sps,
149 .label = label,
150 .run = &stop_peer_run,
151 .cleanup = &stop_peer_cleanup,
152 .traits = &stop_peer_traits
153 };
154 return cmd;
155 }
156}
diff --git a/src/transport/transport_api_core.c b/src/transport/transport_api_core.c
deleted file mode 100644
index 0ffaeb444..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 msg 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 2f0f07f23..000000000
--- a/src/transport/transport_api_monitor_peers.c
+++ /dev/null
@@ -1,469 +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
392/**
393 * Return information about a specific peer or all peers currently known to
394 * transport service once or in monitoring mode. To obtain information about
395 * a specific peer, a peer identity can be passed. To obtain information about
396 * all peers currently known to transport service, NULL can be passed as peer
397 * identity.
398 *
399 * For each peer, the callback is called with information about the address used
400 * to communicate with this peer, the state this peer is currently in and the
401 * the current timeout for this state.
402 *
403 * Upon completion, the 'GNUNET_TRANSPORT_PeerIterateCallback' is called one
404 * more time with 'NULL'. After this, the operation must no longer be
405 * explicitly canceled.
406 *
407 * The #GNUNET_TRANSPORT_monitor_peers_cancel call MUST not be called in the
408 * the peer_callback!
409 *
410 * @param cfg configuration to use
411 * @param peer a specific peer identity to obtain information for,
412 * NULL for all peers
413 * @param one_shot #GNUNET_YES to return the current state and then end (with NULL+NULL),
414 * #GNUNET_NO to monitor peers continuously
415 * @param peer_callback function to call with the results
416 * @param peer_callback_cls closure for @a peer_address_callback
417 */
418struct GNUNET_TRANSPORT_PeerMonitoringContext *
419GNUNET_TRANSPORT_monitor_peers (const struct GNUNET_CONFIGURATION_Handle *cfg,
420 const struct GNUNET_PeerIdentity *peer,
421 int one_shot,
422 GNUNET_TRANSPORT_PeerIterateCallback
423 peer_callback,
424 void *peer_callback_cls)
425{
426 struct GNUNET_TRANSPORT_PeerMonitoringContext *pal_ctx
427 = GNUNET_new (struct GNUNET_TRANSPORT_PeerMonitoringContext);
428
429 pal_ctx->cb = peer_callback;
430 pal_ctx->cb_cls = peer_callback_cls;
431 pal_ctx->cfg = cfg;
432 if (NULL != peer)
433 pal_ctx->peer = *peer;
434 pal_ctx->one_shot = one_shot;
435 do_peer_connect (pal_ctx);
436 if (NULL == pal_ctx->mq)
437 {
438 GNUNET_free (pal_ctx);
439 return NULL;
440 }
441 return pal_ctx;
442}
443
444
445/**
446 * Cancel request to monitor peers
447 *
448 * @param pic handle for the request to cancel
449 */
450void
451GNUNET_TRANSPORT_monitor_peers_cancel (struct
452 GNUNET_TRANSPORT_PeerMonitoringContext *
453 pic)
454{
455 if (NULL != pic->mq)
456 {
457 GNUNET_MQ_destroy (pic->mq);
458 pic->mq = NULL;
459 }
460 if (NULL != pic->reconnect_task)
461 {
462 GNUNET_SCHEDULER_cancel (pic->reconnect_task);
463 pic->reconnect_task = NULL;
464 }
465 GNUNET_free (pic);
466}
467
468
469/* 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 d8eddddaa..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 * @paramm 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 * @paramm 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 eb342f57c..000000000
--- a/src/transport/transport_api_offer_hello.c
+++ /dev/null
@@ -1,142 +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
128/**
129 * Cancel the request to transport to offer the HELLO message
130 *
131 * @param ohh the handle for the operation to cancel
132 */
133void
134GNUNET_TRANSPORT_offer_hello_cancel (struct
135 GNUNET_TRANSPORT_OfferHelloHandle *ohh)
136{
137 GNUNET_MQ_destroy (ohh->mq);
138 GNUNET_free (ohh);
139}
140
141
142/* end of transport_api_offer_hello.c */
diff --git a/src/transport/transport_api_traits.c b/src/transport/transport_api_traits.c
deleted file mode 100644
index 7e66cc3d1..000000000
--- a/src/transport/transport_api_traits.c
+++ /dev/null
@@ -1,32 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2021 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/test_transport_start_with_config.c
23 * @brief Generic program to start testcases in an configurable topology.
24 * @author t3sserakt
25 */
26#include "platform.h"
27#include "gnunet_testing_ng_lib.h"
28#include "gnunet_testing_netjail_lib.h"
29#include "transport-testing-cmds.h"
30#include "gnunet_util_lib.h"
31
32GNUNET_TRANSPORT_SIMPLE_TRAITS (GNUNET_TRANSPORT_MAKE_IMPL_SIMPLE_TRAIT)